[SCM] Packaging for the OpenArena engine branch, upstream, updated. upstream/0.8.1-7-gcc53d0e
Simon McVittie
smcv at debian.org
Sun Feb 26 22:15:44 UTC 2012
The following commit has been merged in the upstream branch:
commit cc53d0e69c3a2c14d4670f1f0727c114810aa662
Author: Simon McVittie <smcv at debian.org>
Date: Sun Feb 26 14:14:24 2012 +0000
Imported Upstream version 0.8.8
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..91fb204
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2196 @@
+#
+# ioq3 Makefile
+#
+# GNU Make required
+#
+
+COMPILE_PLATFORM=$(shell uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]')
+
+COMPILE_ARCH=$(shell uname -m | sed -e s/i.86/i386/)
+
+ifeq ($(COMPILE_PLATFORM),sunos)
+ # Solaris uname and GNU uname differ
+ COMPILE_ARCH=$(shell uname -p | sed -e s/i.86/i386/)
+endif
+ifeq ($(COMPILE_PLATFORM),darwin)
+ # Apple does some things a little differently...
+ COMPILE_ARCH=$(shell uname -p | sed -e s/i.86/i386/)
+endif
+
+ifeq ($(COMPILE_PLATFORM),mingw32)
+ ifeq ($(COMPILE_ARCH),i386)
+ COMPILE_ARCH=x86
+ endif
+endif
+
+ BUILD_STANDALONE = 1
+ BUILD_CLIENT = 0
+ BUILD_CLIENT_SMP = 0
+ BUILD_SERVER = 0
+ BUILD_GAME_SO = 1
+ BUILD_GAME_QVM = 1
+ifndef BUILD_MISSIONPACK
+ BUILD_MISSIONPACK=
+endif
+
+ifneq ($(PLATFORM),darwin)
+ BUILD_CLIENT_SMP = 0
+endif
+
+#############################################################################
+#
+# If you require a different configuration from the defaults below, create a
+# new file named "Makefile.local" in the same directory as this file and define
+# your parameters there. This allows you to change configuration without
+# causing problems with keeping up to date with the repository.
+#
+#############################################################################
+-include Makefile.local
+
+ifndef PLATFORM
+PLATFORM=$(COMPILE_PLATFORM)
+endif
+export PLATFORM
+
+ifeq ($(COMPILE_ARCH),powerpc)
+ COMPILE_ARCH=ppc
+endif
+ifeq ($(COMPILE_ARCH),powerpc64)
+ COMPILE_ARCH=ppc64
+endif
+
+ifndef ARCH
+ARCH=$(COMPILE_ARCH)
+endif
+export ARCH
+
+ifneq ($(PLATFORM),$(COMPILE_PLATFORM))
+ CROSS_COMPILING=1
+else
+ CROSS_COMPILING=0
+
+ ifneq ($(ARCH),$(COMPILE_ARCH))
+ CROSS_COMPILING=1
+ endif
+endif
+export CROSS_COMPILING
+
+ifndef COPYDIR
+COPYDIR="/usr/local/games/quake3"
+endif
+
+ifndef MOUNT_DIR
+MOUNT_DIR=code
+endif
+
+ifndef BUILD_DIR
+BUILD_DIR=build
+endif
+
+ifndef GENERATE_DEPENDENCIES
+GENERATE_DEPENDENCIES=1
+endif
+
+ifndef USE_OPENAL
+USE_OPENAL=1
+endif
+
+ifndef USE_OPENAL_DLOPEN
+ ifeq ($(PLATFORM),mingw32)
+ USE_OPENAL_DLOPEN=1
+ else
+ USE_OPENAL_DLOPEN=0
+ endif
+endif
+
+ifndef USE_CURL
+USE_CURL=1
+endif
+
+ifndef USE_CURL_DLOPEN
+ ifeq ($(PLATFORM),mingw32)
+ USE_CURL_DLOPEN=0
+ else
+ USE_CURL_DLOPEN=1
+ endif
+endif
+
+ifndef USE_CODEC_VORBIS
+USE_CODEC_VORBIS=0
+endif
+
+ifndef USE_MUMBLE
+USE_MUMBLE=1
+endif
+
+ifndef USE_VOIP
+USE_VOIP=1
+endif
+
+ifndef USE_INTERNAL_SPEEX
+USE_INTERNAL_SPEEX=1
+endif
+
+ifndef USE_LOCAL_HEADERS
+USE_LOCAL_HEADERS=1
+endif
+
+#############################################################################
+
+BD=$(BUILD_DIR)/debug-$(PLATFORM)-$(ARCH)
+BR=$(BUILD_DIR)/release-$(PLATFORM)-$(ARCH)
+CDIR=$(MOUNT_DIR)/client
+SDIR=$(MOUNT_DIR)/server
+RDIR=$(MOUNT_DIR)/renderer
+CMDIR=$(MOUNT_DIR)/qcommon
+SDLDIR=$(MOUNT_DIR)/sdl
+ASMDIR=$(MOUNT_DIR)/asm
+SYSDIR=$(MOUNT_DIR)/sys
+GDIR=$(MOUNT_DIR)/game
+CGDIR=$(MOUNT_DIR)/cgame
+BLIBDIR=$(MOUNT_DIR)/botlib
+NDIR=$(MOUNT_DIR)/null
+UIDIR=$(MOUNT_DIR)/ui
+Q3UIDIR=$(MOUNT_DIR)/q3_ui
+JPDIR=$(MOUNT_DIR)/jpeg-6b
+SPEEXDIR=$(MOUNT_DIR)/libspeex
+Q3ASMDIR=$(MOUNT_DIR)/tools/asm
+LBURGDIR=$(MOUNT_DIR)/tools/lcc/lburg
+Q3CPPDIR=$(MOUNT_DIR)/tools/lcc/cpp
+Q3LCCETCDIR=$(MOUNT_DIR)/tools/lcc/etc
+Q3LCCSRCDIR=$(MOUNT_DIR)/tools/lcc/src
+LOKISETUPDIR=misc/setup
+NSISDIR=misc/nsis
+SDLHDIR=$(MOUNT_DIR)/SDL12
+LIBSDIR=$(MOUNT_DIR)/libs
+TEMPDIR=/tmp
+
+# set PKG_CONFIG_PATH to influence this, e.g.
+# PKG_CONFIG_PATH=/opt/cross/i386-mingw32msvc/lib/pkgconfig
+ifeq ($(shell which pkg-config > /dev/null; echo $$?),0)
+ CURL_CFLAGS=$(shell pkg-config --cflags libcurl)
+ CURL_LIBS=$(shell pkg-config --libs libcurl)
+ OPENAL_CFLAGS=$(shell pkg-config --cflags openal)
+ OPENAL_LIBS=$(shell pkg-config --libs openal)
+ # FIXME: introduce CLIENT_CFLAGS
+ SDL_CFLAGS=$(shell pkg-config --cflags sdl|sed 's/-Dmain=SDL_main//')
+ SDL_LIBS=$(shell pkg-config --libs sdl)
+endif
+# Use sdl-config if all else fails
+ifeq ($(SDL_CFLAGS),)
+ ifeq ($(shell which sdl-config > /dev/null; echo $$?),0)
+ SDL_CFLAGS=$(shell sdl-config --cflags)
+ SDL_LIBS=$(shell sdl-config --libs)
+ endif
+endif
+
+# version info
+VERSION=1.36
+
+USE_SVN=
+ifeq ($(wildcard .svn),.svn)
+ SVN_REV=$(shell LANG=C svnversion .)
+ ifneq ($(SVN_REV),)
+ VERSION:=$(VERSION)_SVN$(SVN_REV)
+ USE_SVN=1
+ endif
+else
+ifeq ($(wildcard .git/svn/.metadata),.git/svn/.metadata)
+ SVN_REV=$(shell LANG=C git svn info | awk '$$1 == "Revision:" {print $$2; exit 0}')
+ ifneq ($(SVN_REV),)
+ VERSION:=$(VERSION)_SVN$(SVN_REV)
+ endif
+endif
+endif
+
+
+#############################################################################
+# SETUP AND BUILD -- LINUX
+#############################################################################
+
+## Defaults
+LIB=lib
+
+INSTALL=install
+MKDIR=mkdir
+
+ifeq ($(PLATFORM),linux)
+
+ ifeq ($(ARCH),alpha)
+ ARCH=axp
+ else
+ ifeq ($(ARCH),x86_64)
+ LIB=lib64
+ else
+ ifeq ($(ARCH),ppc64)
+ LIB=lib64
+ else
+ ifeq ($(ARCH),s390x)
+ LIB=lib64
+ endif
+ endif
+ endif
+ endif
+
+ BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
+ -pipe -DUSE_ICON $(SDL_CFLAGS)
+
+ ifeq ($(USE_OPENAL),1)
+ BASE_CFLAGS += -DUSE_OPENAL
+ ifeq ($(USE_OPENAL_DLOPEN),1)
+ BASE_CFLAGS += -DUSE_OPENAL_DLOPEN
+ endif
+ endif
+
+ ifeq ($(USE_CURL),1)
+ BASE_CFLAGS += -DUSE_CURL
+ ifeq ($(USE_CURL_DLOPEN),1)
+ BASE_CFLAGS += -DUSE_CURL_DLOPEN
+ endif
+ endif
+
+ ifeq ($(USE_CODEC_VORBIS),1)
+ BASE_CFLAGS += -DUSE_CODEC_VORBIS
+ endif
+
+ OPTIMIZE = -O3 -ffast-math -funroll-loops -fomit-frame-pointer
+
+ ifeq ($(ARCH),x86_64)
+ OPTIMIZE = -O3 -fomit-frame-pointer -ffast-math -funroll-loops \
+ -falign-loops=2 -falign-jumps=2 -falign-functions=2 \
+ -fstrength-reduce
+ # experimental x86_64 jit compiler! you need GNU as
+ HAVE_VM_COMPILED = true
+ else
+ ifeq ($(ARCH),i386)
+ OPTIMIZE = -O3 -march=i586 -fomit-frame-pointer -ffast-math \
+ -funroll-loops -falign-loops=2 -falign-jumps=2 \
+ -falign-functions=2 -fstrength-reduce
+ HAVE_VM_COMPILED=true
+ else
+ ifeq ($(ARCH),ppc)
+ BASE_CFLAGS += -maltivec
+ HAVE_VM_COMPILED=true
+ endif
+ ifeq ($(ARCH),ppc64)
+ BASE_CFLAGS += -maltivec
+ HAVE_VM_COMPILED=true
+ endif
+ ifeq ($(ARCH),sparc)
+ OPTIMIZE += -mtune=ultrasparc3 -mv8plus
+ HAVE_VM_COMPILED=true
+ endif
+ endif
+ endif
+
+ ifneq ($(HAVE_VM_COMPILED),true)
+ BASE_CFLAGS += -DNO_VM_COMPILED
+ endif
+
+ SHLIBEXT=so
+ SHLIBCFLAGS=-fPIC
+ SHLIBLDFLAGS=-shared $(LDFLAGS)
+
+ THREAD_LIBS=-lpthread
+ LIBS=-ldl -lm
+
+ CLIENT_LIBS=$(SDL_LIBS) -lGL
+
+ ifeq ($(USE_OPENAL),1)
+ ifneq ($(USE_OPENAL_DLOPEN),1)
+ CLIENT_LIBS += -lopenal
+ endif
+ endif
+
+ ifeq ($(USE_CURL),1)
+ ifneq ($(USE_CURL_DLOPEN),1)
+ CLIENT_LIBS += -lcurl
+ endif
+ endif
+
+ ifeq ($(USE_CODEC_VORBIS),1)
+ CLIENT_LIBS += -lvorbisfile -lvorbis -logg
+ endif
+
+ ifeq ($(USE_MUMBLE),1)
+ CLIENT_LIBS += -lrt
+ endif
+
+ifeq ($(USE_LOCAL_HEADERS),1)
+ BASE_CFLAGS += -I$(SDLHDIR)/include
+ endif
+
+ ifeq ($(ARCH),i386)
+ # linux32 make ...
+ BASE_CFLAGS += -m32
+ else
+ ifeq ($(ARCH),ppc64)
+ BASE_CFLAGS += -m64
+ endif
+ endif
+
+ DEBUG_CFLAGS = $(BASE_CFLAGS) -g -O0
+ RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG $(OPTIMIZE)
+
+else # ifeq Linux
+
+#############################################################################
+# SETUP AND BUILD -- MAC OS X
+#############################################################################
+
+ifeq ($(PLATFORM),darwin)
+ HAVE_VM_COMPILED=true
+ CLIENT_LIBS=
+ OPTIMIZE=
+
+ BASE_CFLAGS = -Wall -Wimplicit -Wstrict-prototypes
+
+ ifeq ($(ARCH),ppc)
+ BASE_CFLAGS += -faltivec
+ OPTIMIZE += -O3
+ endif
+ ifeq ($(ARCH),ppc64)
+ BASE_CFLAGS += -faltivec
+ endif
+ ifeq ($(ARCH),i386)
+ OPTIMIZE += -march=prescott -mfpmath=sse
+ # x86 vm will crash without -mstackrealign since MMX instructions will be
+ # used no matter what and they corrupt the frame pointer in VM calls
+ BASE_CFLAGS += -mstackrealign
+ endif
+
+ BASE_CFLAGS += -fno-strict-aliasing -DMACOS_X -fno-common -pipe
+
+ ifeq ($(USE_OPENAL),1)
+ BASE_CFLAGS += -DUSE_OPENAL
+ ifneq ($(USE_OPENAL_DLOPEN),1)
+ CLIENT_LIBS += -framework OpenAL
+ else
+ BASE_CFLAGS += -DUSE_OPENAL_DLOPEN
+ endif
+ endif
+
+ ifeq ($(USE_CURL),1)
+ BASE_CFLAGS += -DUSE_CURL
+ ifneq ($(USE_CURL_DLOPEN),1)
+ CLIENT_LIBS += -lcurl
+ else
+ BASE_CFLAGS += -DUSE_CURL_DLOPEN
+ endif
+ endif
+
+ ifeq ($(USE_CODEC_VORBIS),1)
+ BASE_CFLAGS += -DUSE_CODEC_VORBIS
+ CLIENT_LIBS += -lvorbisfile -lvorbis -logg
+ endif
+
+ BASE_CFLAGS += -D_THREAD_SAFE=1
+
+ ifeq ($(USE_LOCAL_HEADERS),1)
+ BASE_CFLAGS += -I$(SDLHDIR)/include
+ endif
+
+ # We copy sdlmain before ranlib'ing it so that subversion doesn't think
+ # the file has been modified by each build.
+ LIBSDLMAIN=$(B)/libSDLmain.a
+ LIBSDLMAINSRC=$(LIBSDIR)/macosx/libSDLmain.a
+ CLIENT_LIBS += -framework Cocoa -framework IOKit -framework OpenGL \
+ $(LIBSDIR)/macosx/libSDL-1.2.0.dylib
+
+ OPTIMIZE += -ffast-math -falign-loops=16
+
+ ifneq ($(HAVE_VM_COMPILED),true)
+ BASE_CFLAGS += -DNO_VM_COMPILED
+ endif
+
+ DEBUG_CFLAGS = $(BASE_CFLAGS) -g -O0
+
+ RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG $(OPTIMIZE)
+
+ SHLIBEXT=dylib
+ SHLIBCFLAGS=-fPIC -fno-common
+ SHLIBLDFLAGS=-dynamiclib $(LDFLAGS)
+
+ NOTSHLIBCFLAGS=-mdynamic-no-pic
+
+ TOOLS_CFLAGS += -DMACOS_X
+
+else # ifeq darwin
+
+
+#############################################################################
+# SETUP AND BUILD -- MINGW32
+#############################################################################
+
+ifeq ($(PLATFORM),mingw32)
+
+ ifndef WINDRES
+ WINDRES=windres
+ endif
+
+ ARCH=x86
+
+ BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
+ -DUSE_ICON
+
+ # In the absence of wspiapi.h, require Windows XP or later
+ ifeq ($(shell test -e $(CMDIR)/wspiapi.h; echo $$?),1)
+ BASE_CFLAGS += -DWINVER=0x501
+ endif
+
+ ifeq ($(USE_OPENAL),1)
+ BASE_CFLAGS += -DUSE_OPENAL
+ BASE_CFLAGS += $(OPENAL_CFLAGS)
+ ifeq ($(USE_OPENAL_DLOPEN),1)
+ BASE_CFLAGS += -DUSE_OPENAL_DLOPEN
+ else
+ CLIENT_LDFLAGS += $(OPENAL_LDFLAGS)
+ endif
+ endif
+
+ ifeq ($(USE_CODEC_VORBIS),1)
+ BASE_CFLAGS += -DUSE_CODEC_VORBIS
+ endif
+
+ OPTIMIZE = -O3 -march=i586 -fno-omit-frame-pointer -ffast-math \
+ -falign-loops=2 -funroll-loops -falign-jumps=2 -falign-functions=2 \
+ -fstrength-reduce
+
+ HAVE_VM_COMPILED = true
+
+ SHLIBEXT=dll
+ SHLIBCFLAGS=
+ SHLIBLDFLAGS=-shared $(LDFLAGS)
+
+ BINEXT=.exe
+
+ LIBS= -lws2_32 -lwinmm
+ CLIENT_LDFLAGS = -mwindows
+ CLIENT_LIBS = -lgdi32 -lole32 -lopengl32
+
+ ifeq ($(USE_CURL),1)
+ BASE_CFLAGS += -DUSE_CURL
+ BASE_CFLAGS += $(CURL_CFLAGS)
+ ifneq ($(USE_CURL_DLOPEN),1)
+ ifeq ($(USE_LOCAL_HEADERS),1)
+ BASE_CFLAGS += -DCURL_STATICLIB
+ CLIENT_LIBS += $(LIBSDIR)/win32/libcurl.a
+ else
+ CLIENT_LIBS += $(CURL_LIBS)
+ endif
+ endif
+ endif
+
+ ifeq ($(USE_CODEC_VORBIS),1)
+ CLIENT_LIBS += -lvorbisfile -lvorbis -logg
+ endif
+
+ ifeq ($(ARCH),x86)
+ # build 32bit
+ BASE_CFLAGS += -m32
+ endif
+
+ DEBUG_CFLAGS=$(BASE_CFLAGS) -g -O0
+ RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG $(OPTIMIZE)
+
+ # libmingw32 must be linked before libSDLmain
+ CLIENT_LIBS += -lmingw32
+ ifeq ($(USE_LOCAL_HEADERS),1)
+ BASE_CFLAGS += -I$(SDLHDIR)/include
+ CLIENT_LIBS += $(LIBSDIR)/win32/libSDLmain.a \
+ $(LIBSDIR)/win32/libSDL.dll.a
+ else
+ BASE_CFLAGS += $(SDL_CFLAGS)
+ CLIENT_LIBS += $(SDL_LIBS)
+ endif
+
+
+
+ BUILD_CLIENT_SMP = 0
+
+else # ifeq mingw32
+
+#############################################################################
+# SETUP AND BUILD -- FREEBSD
+#############################################################################
+
+ifeq ($(PLATFORM),freebsd)
+
+ ifneq (,$(findstring alpha,$(shell uname -m)))
+ ARCH=axp
+ else #default to i386
+ ARCH=i386
+ endif #alpha test
+
+
+ BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
+ -DUSE_ICON $(SDL_CFLAGS)
+
+ ifeq ($(USE_OPENAL),1)
+ BASE_CFLAGS += -DUSE_OPENAL
+ ifeq ($(USE_OPENAL_DLOPEN),1)
+ BASE_CFLAGS += -DUSE_OPENAL_DLOPEN
+ endif
+ endif
+
+ ifeq ($(USE_CODEC_VORBIS),1)
+ BASE_CFLAGS += -DUSE_CODEC_VORBIS
+ endif
+
+ ifeq ($(ARCH),axp)
+ BASE_CFLAGS += -DNO_VM_COMPILED
+ RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O3 -ffast-math -funroll-loops \
+ -fomit-frame-pointer -fexpensive-optimizations
+ else
+ ifeq ($(ARCH),i386)
+ RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O3 -mtune=pentiumpro \
+ -march=pentium -fomit-frame-pointer -pipe -ffast-math \
+ -falign-loops=2 -falign-jumps=2 -falign-functions=2 \
+ -funroll-loops -fstrength-reduce
+ HAVE_VM_COMPILED=true
+ else
+ BASE_CFLAGS += -DNO_VM_COMPILED
+ endif
+ endif
+
+ DEBUG_CFLAGS=$(BASE_CFLAGS) -g
+
+ SHLIBEXT=so
+ SHLIBCFLAGS=-fPIC
+ SHLIBLDFLAGS=-shared $(LDFLAGS)
+
+ THREAD_LIBS=-lpthread
+ # don't need -ldl (FreeBSD)
+ LIBS=-lm
+
+ CLIENT_LIBS =
+
+ CLIENT_LIBS += $(SDL_LIBS) -lGL
+
+ ifeq ($(USE_OPENAL),1)
+ ifneq ($(USE_OPENAL_DLOPEN),1)
+ CLIENT_LIBS += $(THREAD_LIBS) -lopenal
+ endif
+ endif
+
+ ifeq ($(USE_CODEC_VORBIS),1)
+ CLIENT_LIBS += -lvorbisfile -lvorbis -logg
+ endif
+
+else # ifeq freebsd
+
+#############################################################################
+# SETUP AND BUILD -- OPENBSD
+#############################################################################
+
+ifeq ($(PLATFORM),openbsd)
+
+ #default to i386, no tests done on anything else
+ ARCH=i386
+
+
+ BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
+ -DUSE_ICON $(SDL_CFLAGS)
+
+ ifeq ($(USE_OPENAL),1)
+ BASE_CFLAGS += -DUSE_OPENAL
+ ifeq ($(USE_OPENAL_DLOPEN),1)
+ BASE_CFLAGS += -DUSE_OPENAL_DLOPEN
+ endif
+ endif
+
+ ifeq ($(USE_CODEC_VORBIS),1)
+ BASE_CFLAGS += -DUSE_CODEC_VORBIS
+ endif
+
+ BASE_CFLAGS += -DNO_VM_COMPILED -I/usr/X11R6/include -I/usr/local/include
+ RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O3 \
+ -march=pentium -fomit-frame-pointer -pipe -ffast-math \
+ -falign-loops=2 -falign-jumps=2 -falign-functions=2 \
+ -funroll-loops -fstrength-reduce
+ HAVE_VM_COMPILED=false
+
+ DEBUG_CFLAGS=$(BASE_CFLAGS) -g
+
+ SHLIBEXT=so
+ SHLIBCFLAGS=-fPIC
+ SHLIBLDFLAGS=-shared $(LDFLAGS)
+
+ THREAD_LIBS=-lpthread
+ LIBS=-lm
+
+ CLIENT_LIBS =
+
+ CLIENT_LIBS += $(SDL_LIBS) -lGL
+
+ ifeq ($(USE_OPENAL),1)
+ ifneq ($(USE_OPENAL_DLOPEN),1)
+ CLIENT_LIBS += $(THREAD_LIBS) -lossaudio -lopenal
+ endif
+ endif
+
+ ifeq ($(USE_CODEC_VORBIS),1)
+ CLIENT_LIBS += -lvorbisfile -lvorbis -logg
+ endif
+
+else # ifeq openbsd
+
+#############################################################################
+# SETUP AND BUILD -- NETBSD
+#############################################################################
+
+ifeq ($(PLATFORM),netbsd)
+
+ ifeq ($(shell uname -m),i386)
+ ARCH=i386
+ endif
+
+ LIBS=-lm
+ SHLIBEXT=so
+ SHLIBCFLAGS=-fPIC
+ SHLIBLDFLAGS=-shared $(LDFLAGS)
+ THREAD_LIBS=-lpthread
+
+ BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes
+
+ ifneq ($(ARCH),i386)
+ BASE_CFLAGS += -DNO_VM_COMPILED
+ endif
+
+ DEBUG_CFLAGS=$(BASE_CFLAGS) -g
+
+ BUILD_CLIENT = 0
+ BUILD_GAME_QVM = 0
+
+else # ifeq netbsd
+
+#############################################################################
+# SETUP AND BUILD -- IRIX
+#############################################################################
+
+ifeq ($(PLATFORM),irix64)
+
+ ARCH=mips #default to MIPS
+
+ CC = c99
+ MKDIR = mkdir -p
+
+ BASE_CFLAGS=-Dstricmp=strcasecmp -Xcpluscomm -woff 1185 \
+ -I. $(SDL_CFLAGS) -I$(ROOT)/usr/include -DNO_VM_COMPILED
+ RELEASE_CFLAGS=$(BASE_CFLAGS) -O3
+ DEBUG_CFLAGS=$(BASE_CFLAGS) -g
+
+ SHLIBEXT=so
+ SHLIBCFLAGS=
+ SHLIBLDFLAGS=-shared
+
+ LIBS=-ldl -lm -lgen
+ # FIXME: The X libraries probably aren't necessary?
+ CLIENT_LIBS=-L/usr/X11/$(LIB) $(SDL_LIBS) -lGL \
+ -lX11 -lXext -lm
+
+else # ifeq IRIX
+
+#############################################################################
+# SETUP AND BUILD -- SunOS
+#############################################################################
+
+ifeq ($(PLATFORM),sunos)
+
+ CC=gcc
+ INSTALL=ginstall
+ MKDIR=gmkdir
+ COPYDIR="/usr/local/share/games/quake3"
+
+ ifneq (,$(findstring i86pc,$(shell uname -m)))
+ ARCH=i386
+ else #default to sparc
+ ARCH=sparc
+ endif
+
+ ifneq ($(ARCH),i386)
+ ifneq ($(ARCH),sparc)
+ $(error arch $(ARCH) is currently not supported)
+ endif
+ endif
+
+ BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
+ -pipe -DUSE_ICON $(SDL_CFLAGS)
+
+ OPTIMIZE = -O3 -ffast-math -funroll-loops
+
+ ifeq ($(ARCH),sparc)
+ OPTIMIZE = -O3 -ffast-math \
+ -fstrength-reduce -falign-functions=2 \
+ -mtune=ultrasparc3 -mv8plus -mno-faster-structs \
+ -funroll-loops #-mv8plus
+ HAVE_VM_COMPILED=true
+ else
+ ifeq ($(ARCH),i386)
+ OPTIMIZE = -O3 -march=i586 -fomit-frame-pointer -ffast-math \
+ -funroll-loops -falign-loops=2 -falign-jumps=2 \
+ -falign-functions=2 -fstrength-reduce
+ HAVE_VM_COMPILED=true
+ BASE_CFLAGS += -m32
+ BASE_CFLAGS += -I/usr/X11/include/NVIDIA
+ CLIENT_LDFLAGS += -L/usr/X11/lib/NVIDIA -R/usr/X11/lib/NVIDIA
+ endif
+ endif
+
+ ifneq ($(HAVE_VM_COMPILED),true)
+ BASE_CFLAGS += -DNO_VM_COMPILED
+ endif
+
+ DEBUG_CFLAGS = $(BASE_CFLAGS) -ggdb -O0
+
+ RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG $(OPTIMIZE)
+
+ SHLIBEXT=so
+ SHLIBCFLAGS=-fPIC
+ SHLIBLDFLAGS=-shared $(LDFLAGS)
+
+ THREAD_LIBS=-lpthread
+ LIBS=-lsocket -lnsl -ldl -lm
+
+ BOTCFLAGS=-O0
+
+ CLIENT_LIBS +=$(SDL_LIBS) -lGL -lX11 -lXext -liconv -lm
+
+else # ifeq sunos
+
+#############################################################################
+# SETUP AND BUILD -- GENERIC
+#############################################################################
+ BASE_CFLAGS=-DNO_VM_COMPILED
+ DEBUG_CFLAGS=$(BASE_CFLAGS) -g
+ RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O3
+
+ SHLIBEXT=so
+ SHLIBCFLAGS=-fPIC
+ SHLIBLDFLAGS=-shared
+
+endif #Linux
+endif #darwin
+endif #mingw32
+endif #FreeBSD
+endif #OpenBSD
+endif #NetBSD
+endif #IRIX
+endif #SunOS
+
+TARGETS =
+
+ifneq ($(BUILD_SERVER),0)
+ TARGETS += $(B)/ioq3ded.$(ARCH)$(BINEXT)
+endif
+
+ifneq ($(BUILD_CLIENT),0)
+ TARGETS += $(B)/ioquake3.$(ARCH)$(BINEXT)
+ ifneq ($(BUILD_CLIENT_SMP),0)
+ TARGETS += $(B)/ioquake3-smp.$(ARCH)$(BINEXT)
+ endif
+endif
+
+ifneq ($(BUILD_GAME_SO),0)
+ TARGETS += \
+ $(B)/baseq3/cgame$(ARCH).$(SHLIBEXT) \
+ $(B)/baseq3/qagame$(ARCH).$(SHLIBEXT) \
+ $(B)/baseq3/ui$(ARCH).$(SHLIBEXT)
+ ifneq ($(BUILD_MISSIONPACK),0)
+ TARGETS += \
+ $(B)/missionpack/cgame$(ARCH).$(SHLIBEXT) \
+ $(B)/missionpack/qagame$(ARCH).$(SHLIBEXT) \
+ $(B)/missionpack/ui$(ARCH).$(SHLIBEXT)
+ endif
+endif
+
+ifneq ($(BUILD_GAME_QVM),0)
+ ifneq ($(CROSS_COMPILING),1)
+ TARGETS += \
+ $(B)/baseq3/vm/cgame.qvm \
+ $(B)/baseq3/vm/qagame.qvm \
+ $(B)/baseq3/vm/ui.qvm
+ ifneq ($(BUILD_MISSIONPACK),0)
+ TARGETS += \
+ $(B)/missionpack/vm/qagame.qvm \
+ $(B)/missionpack/vm/cgame.qvm \
+ $(B)/missionpack/vm/ui.qvm
+ endif
+ endif
+endif
+
+ifeq ($(USE_MUMBLE),1)
+ BASE_CFLAGS += -DUSE_MUMBLE
+endif
+
+ifeq ($(USE_VOIP),1)
+ BASE_CFLAGS += -DUSE_VOIP
+ ifeq ($(USE_INTERNAL_SPEEX),1)
+ BASE_CFLAGS += -DFLOATING_POINT -DUSE_ALLOCA -I$(SPEEXDIR)/include
+ else
+ CLIENT_LIBS += -lspeex
+ endif
+endif
+
+ifdef DEFAULT_BASEDIR
+ BASE_CFLAGS += -DDEFAULT_BASEDIR=\\\"$(DEFAULT_BASEDIR)\\\"
+endif
+
+ifeq ($(USE_LOCAL_HEADERS),1)
+ BASE_CFLAGS += -DUSE_LOCAL_HEADERS
+endif
+
+ifeq ($(BUILD_STANDALONE),1)
+ BASE_CFLAGS += -DSTANDALONE
+endif
+
+ifeq ($(GENERATE_DEPENDENCIES),1)
+ DEPEND_CFLAGS = -MMD
+else
+ DEPEND_CFLAGS =
+endif
+
+BASE_CFLAGS += -DPRODUCT_VERSION=\\\"$(VERSION)\\\"
+
+ifeq ($(V),1)
+echo_cmd=@:
+Q=
+else
+echo_cmd=@echo
+Q=@
+endif
+
+define DO_CC
+$(echo_cmd) "CC $<"
+$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) -o $@ -c $<
+endef
+
+define DO_SMP_CC
+$(echo_cmd) "SMP_CC $<"
+$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) -DSMP -o $@ -c $<
+endef
+
+define DO_BOT_CC
+$(echo_cmd) "BOT_CC $<"
+$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) $(BOTCFLAGS) -DBOTLIB -o $@ -c $<
+endef
+
+ifeq ($(GENERATE_DEPENDENCIES),1)
+ DO_QVM_DEP=cat $(@:%.o=%.d) | sed -e 's/\.o/\.asm/g' >> $(@:%.o=%.d)
+endif
+
+define DO_SHLIB_CC
+$(echo_cmd) "SHLIB_CC $<"
+$(Q)$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+$(Q)$(DO_QVM_DEP)
+endef
+
+define DO_GAME_CC
+$(echo_cmd) "GAME_CC $<"
+$(Q)$(CC) -DQAGAME $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+$(Q)$(DO_QVM_DEP)
+endef
+
+define DO_CGAME_CC
+$(echo_cmd) "CGAME_CC $<"
+$(Q)$(CC) -DCGAME $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+$(Q)$(DO_QVM_DEP)
+endef
+
+define DO_UI_CC
+$(echo_cmd) "UI_CC $<"
+$(Q)$(CC) -DUI $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+$(Q)$(DO_QVM_DEP)
+endef
+
+define DO_SHLIB_CC_MISSIONPACK
+$(echo_cmd) "SHLIB_CC_MISSIONPACK $<"
+$(Q)$(CC) -DMISSIONPACK $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+$(Q)$(DO_QVM_DEP)
+endef
+
+define DO_GAME_CC_MISSIONPACK
+$(echo_cmd) "GAME_CC_MISSIONPACK $<"
+$(Q)$(CC) -DMISSIONPACK -DQAGAME $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+$(Q)$(DO_QVM_DEP)
+endef
+
+define DO_CGAME_CC_MISSIONPACK
+$(echo_cmd) "CGAME_CC_MISSIONPACK $<"
+$(Q)$(CC) -DMISSIONPACK -DCGAME $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+$(Q)$(DO_QVM_DEP)
+endef
+
+define DO_UI_CC_MISSIONPACK
+$(echo_cmd) "UI_CC_MISSIONPACK $<"
+$(Q)$(CC) -DMISSIONPACK -DUI $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+$(Q)$(DO_QVM_DEP)
+endef
+
+define DO_AS
+$(echo_cmd) "AS $<"
+$(Q)$(CC) $(CFLAGS) -x assembler-with-cpp -o $@ -c $<
+endef
+
+define DO_DED_CC
+$(echo_cmd) "DED_CC $<"
+$(Q)$(CC) $(NOTSHLIBCFLAGS) -DDEDICATED $(CFLAGS) -o $@ -c $<
+endef
+
+define DO_WINDRES
+$(echo_cmd) "WINDRES $<"
+$(Q)$(WINDRES) -i $< -o $@
+endef
+
+
+#############################################################################
+# MAIN TARGETS
+#############################################################################
+
+default: release
+all: debug release
+
+debug:
+ @$(MAKE) targets B=$(BD) CFLAGS="$(CFLAGS) $(DEPEND_CFLAGS) \
+ $(DEBUG_CFLAGS)" V=$(V)
+
+release:
+ @$(MAKE) targets B=$(BR) CFLAGS="$(CFLAGS) $(DEPEND_CFLAGS) \
+ $(RELEASE_CFLAGS)" V=$(V)
+
+# Create the build directories, check libraries and print out
+# an informational message, then start building
+targets: makedirs
+ @echo ""
+ @echo "Building ioquake3 in $(B):"
+ @echo " PLATFORM: $(PLATFORM)"
+ @echo " ARCH: $(ARCH)"
+ @echo " VERSION: $(VERSION)"
+ @echo " COMPILE_PLATFORM: $(COMPILE_PLATFORM)"
+ @echo " COMPILE_ARCH: $(COMPILE_ARCH)"
+ @echo " CC: $(CC)"
+ @echo ""
+ @echo " CFLAGS:"
+ - at for i in $(CFLAGS); \
+ do \
+ echo " $$i"; \
+ done
+ @echo ""
+ @echo " LDFLAGS:"
+ - at for i in $(LDFLAGS); \
+ do \
+ echo " $$i"; \
+ done
+ @echo ""
+ @echo " LIBS:"
+ - at for i in $(LIBS); \
+ do \
+ echo " $$i"; \
+ done
+ @echo ""
+ @echo " CLIENT_LIBS:"
+ - at for i in $(CLIENT_LIBS); \
+ do \
+ echo " $$i"; \
+ done
+ @echo ""
+ @echo " Output:"
+ - at for i in $(TARGETS); \
+ do \
+ echo " $$i"; \
+ done
+ @echo ""
+ifneq ($(TARGETS),)
+ @$(MAKE) $(TARGETS) V=$(V)
+endif
+
+makedirs:
+ @if [ ! -d $(BUILD_DIR) ];then $(MKDIR) $(BUILD_DIR);fi
+ @if [ ! -d $(B) ];then $(MKDIR) $(B);fi
+ @if [ ! -d $(B)/client ];then $(MKDIR) $(B)/client;fi
+ @if [ ! -d $(B)/clientsmp ];then $(MKDIR) $(B)/clientsmp;fi
+ @if [ ! -d $(B)/ded ];then $(MKDIR) $(B)/ded;fi
+ @if [ ! -d $(B)/baseq3 ];then $(MKDIR) $(B)/baseq3;fi
+ @if [ ! -d $(B)/baseq3/cgame ];then $(MKDIR) $(B)/baseq3/cgame;fi
+ @if [ ! -d $(B)/baseq3/game ];then $(MKDIR) $(B)/baseq3/game;fi
+ @if [ ! -d $(B)/baseq3/ui ];then $(MKDIR) $(B)/baseq3/ui;fi
+ @if [ ! -d $(B)/baseq3/qcommon ];then $(MKDIR) $(B)/baseq3/qcommon;fi
+ @if [ ! -d $(B)/baseq3/vm ];then $(MKDIR) $(B)/baseq3/vm;fi
+ @if [ ! -d $(B)/missionpack ];then $(MKDIR) $(B)/missionpack;fi
+ @if [ ! -d $(B)/missionpack/cgame ];then $(MKDIR) $(B)/missionpack/cgame;fi
+ @if [ ! -d $(B)/missionpack/game ];then $(MKDIR) $(B)/missionpack/game;fi
+ @if [ ! -d $(B)/missionpack/ui ];then $(MKDIR) $(B)/missionpack/ui;fi
+ @if [ ! -d $(B)/missionpack/qcommon ];then $(MKDIR) $(B)/missionpack/qcommon;fi
+ @if [ ! -d $(B)/missionpack/vm ];then $(MKDIR) $(B)/missionpack/vm;fi
+ @if [ ! -d $(B)/tools ];then $(MKDIR) $(B)/tools;fi
+ @if [ ! -d $(B)/tools/asm ];then $(MKDIR) $(B)/tools/asm;fi
+ @if [ ! -d $(B)/tools/etc ];then $(MKDIR) $(B)/tools/etc;fi
+ @if [ ! -d $(B)/tools/rcc ];then $(MKDIR) $(B)/tools/rcc;fi
+ @if [ ! -d $(B)/tools/cpp ];then $(MKDIR) $(B)/tools/cpp;fi
+ @if [ ! -d $(B)/tools/lburg ];then $(MKDIR) $(B)/tools/lburg;fi
+
+#############################################################################
+# QVM BUILD TOOLS
+#############################################################################
+
+TOOLS_OPTIMIZE = -g -O2 -Wall -fno-strict-aliasing
+TOOLS_CFLAGS = $(TOOLS_OPTIMIZE) \
+ -DTEMPDIR=\"$(TEMPDIR)\" -DSYSTEM=\"\" \
+ -I$(Q3LCCSRCDIR) \
+ -I$(LBURGDIR)
+TOOLS_LIBS =
+TOOLS_LDFLAGS =
+
+ifeq ($(GENERATE_DEPENDENCIES),1)
+ TOOLS_CFLAGS += -MMD
+endif
+
+define DO_TOOLS_CC
+$(echo_cmd) "TOOLS_CC $<"
+$(Q)$(CC) $(TOOLS_CFLAGS) -o $@ -c $<
+endef
+
+define DO_TOOLS_CC_DAGCHECK
+$(echo_cmd) "TOOLS_CC_DAGCHECK $<"
+$(Q)$(CC) $(TOOLS_CFLAGS) -Wno-unused -o $@ -c $<
+endef
+
+LBURG = $(B)/tools/lburg/lburg$(BINEXT)
+DAGCHECK_C = $(B)/tools/rcc/dagcheck.c
+Q3RCC = $(B)/tools/q3rcc$(BINEXT)
+Q3CPP = $(B)/tools/q3cpp$(BINEXT)
+Q3LCC = $(B)/tools/q3lcc$(BINEXT)
+Q3ASM = $(B)/tools/q3asm$(BINEXT)
+
+LBURGOBJ= \
+ $(B)/tools/lburg/lburg.o \
+ $(B)/tools/lburg/gram.o
+
+$(B)/tools/lburg/%.o: $(LBURGDIR)/%.c
+ $(DO_TOOLS_CC)
+
+$(LBURG): $(LBURGOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
+
+Q3RCCOBJ = \
+ $(B)/tools/rcc/alloc.o \
+ $(B)/tools/rcc/bind.o \
+ $(B)/tools/rcc/bytecode.o \
+ $(B)/tools/rcc/dag.o \
+ $(B)/tools/rcc/dagcheck.o \
+ $(B)/tools/rcc/decl.o \
+ $(B)/tools/rcc/enode.o \
+ $(B)/tools/rcc/error.o \
+ $(B)/tools/rcc/event.o \
+ $(B)/tools/rcc/expr.o \
+ $(B)/tools/rcc/gen.o \
+ $(B)/tools/rcc/init.o \
+ $(B)/tools/rcc/inits.o \
+ $(B)/tools/rcc/input.o \
+ $(B)/tools/rcc/lex.o \
+ $(B)/tools/rcc/list.o \
+ $(B)/tools/rcc/main.o \
+ $(B)/tools/rcc/null.o \
+ $(B)/tools/rcc/output.o \
+ $(B)/tools/rcc/prof.o \
+ $(B)/tools/rcc/profio.o \
+ $(B)/tools/rcc/simp.o \
+ $(B)/tools/rcc/stmt.o \
+ $(B)/tools/rcc/string.o \
+ $(B)/tools/rcc/sym.o \
+ $(B)/tools/rcc/symbolic.o \
+ $(B)/tools/rcc/trace.o \
+ $(B)/tools/rcc/tree.o \
+ $(B)/tools/rcc/types.o
+
+$(DAGCHECK_C): $(LBURG) $(Q3LCCSRCDIR)/dagcheck.md
+ $(echo_cmd) "LBURG $(Q3LCCSRCDIR)/dagcheck.md"
+ $(Q)$(LBURG) $(Q3LCCSRCDIR)/dagcheck.md $@
+
+$(B)/tools/rcc/dagcheck.o: $(DAGCHECK_C)
+ $(DO_TOOLS_CC_DAGCHECK)
+
+$(B)/tools/rcc/%.o: $(Q3LCCSRCDIR)/%.c
+ $(DO_TOOLS_CC)
+
+$(Q3RCC): $(Q3RCCOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
+
+Q3CPPOBJ = \
+ $(B)/tools/cpp/cpp.o \
+ $(B)/tools/cpp/lex.o \
+ $(B)/tools/cpp/nlist.o \
+ $(B)/tools/cpp/tokens.o \
+ $(B)/tools/cpp/macro.o \
+ $(B)/tools/cpp/eval.o \
+ $(B)/tools/cpp/include.o \
+ $(B)/tools/cpp/hideset.o \
+ $(B)/tools/cpp/getopt.o \
+ $(B)/tools/cpp/unix.o
+
+$(B)/tools/cpp/%.o: $(Q3CPPDIR)/%.c
+ $(DO_TOOLS_CC)
+
+$(Q3CPP): $(Q3CPPOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
+
+Q3LCCOBJ = \
+ $(B)/tools/etc/lcc.o \
+ $(B)/tools/etc/bytecode.o
+
+$(B)/tools/etc/%.o: $(Q3LCCETCDIR)/%.c
+ $(DO_TOOLS_CC)
+
+$(Q3LCC): $(Q3LCCOBJ) $(Q3RCC) $(Q3CPP)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $(Q3LCCOBJ) $(TOOLS_LIBS)
+
+define DO_Q3LCC
+$(echo_cmd) "Q3LCC $<"
+$(Q)$(Q3LCC) -o $@ $<
+endef
+
+define DO_CGAME_Q3LCC
+$(echo_cmd) "CGAME_Q3LCC $<"
+$(Q)$(Q3LCC) -DCGAME -o $@ $<
+endef
+
+define DO_GAME_Q3LCC
+$(echo_cmd) "GAME_Q3LCC $<"
+$(Q)$(Q3LCC) -DQAGAME -o $@ $<
+endef
+
+define DO_UI_Q3LCC
+$(echo_cmd) "UI_Q3LCC $<"
+$(Q)$(Q3LCC) -DUI -o $@ $<
+endef
+
+define DO_Q3LCC_MISSIONPACK
+$(echo_cmd) "Q3LCC_MISSIONPACK $<"
+$(Q)$(Q3LCC) -DMISSIONPACK -o $@ $<
+endef
+
+define DO_CGAME_Q3LCC_MISSIONPACK
+$(echo_cmd) "CGAME_Q3LCC_MISSIONPACK $<"
+$(Q)$(Q3LCC) -DMISSIONPACK -DCGAME -o $@ $<
+endef
+
+define DO_GAME_Q3LCC_MISSIONPACK
+$(echo_cmd) "GAME_Q3LCC_MISSIONPACK $<"
+$(Q)$(Q3LCC) -DMISSIONPACK -DQAGAME -o $@ $<
+endef
+
+define DO_UI_Q3LCC_MISSIONPACK
+$(echo_cmd) "UI_Q3LCC_MISSIONPACK $<"
+$(Q)$(Q3LCC) -DMISSIONPACK -DUI -o $@ $<
+endef
+
+
+Q3ASMOBJ = \
+ $(B)/tools/asm/q3asm.o \
+ $(B)/tools/asm/cmdlib.o
+
+$(B)/tools/asm/%.o: $(Q3ASMDIR)/%.c
+ $(DO_TOOLS_CC)
+
+$(Q3ASM): $(Q3ASMOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
+
+
+#############################################################################
+# CLIENT/SERVER
+#############################################################################
+
+Q3OBJ = \
+ $(B)/client/cl_cgame.o \
+ $(B)/client/cl_cin.o \
+ $(B)/client/cl_console.o \
+ $(B)/client/cl_input.o \
+ $(B)/client/cl_keys.o \
+ $(B)/client/cl_main.o \
+ $(B)/client/cl_net_chan.o \
+ $(B)/client/cl_parse.o \
+ $(B)/client/cl_scrn.o \
+ $(B)/client/cl_ui.o \
+ $(B)/client/cl_avi.o \
+ \
+ $(B)/client/cm_load.o \
+ $(B)/client/cm_patch.o \
+ $(B)/client/cm_polylib.o \
+ $(B)/client/cm_test.o \
+ $(B)/client/cm_trace.o \
+ \
+ $(B)/client/cmd.o \
+ $(B)/client/common.o \
+ $(B)/client/cvar.o \
+ $(B)/client/files.o \
+ $(B)/client/md4.o \
+ $(B)/client/md5.o \
+ $(B)/client/msg.o \
+ $(B)/client/net_chan.o \
+ $(B)/client/net_ip.o \
+ $(B)/client/huffman.o \
+ \
+ $(B)/client/snd_adpcm.o \
+ $(B)/client/snd_dma.o \
+ $(B)/client/snd_mem.o \
+ $(B)/client/snd_mix.o \
+ $(B)/client/snd_wavelet.o \
+ \
+ $(B)/client/snd_main.o \
+ $(B)/client/snd_codec.o \
+ $(B)/client/snd_codec_wav.o \
+ $(B)/client/snd_codec_ogg.o \
+ \
+ $(B)/client/qal.o \
+ $(B)/client/snd_openal.o \
+ \
+ $(B)/client/cl_curl.o \
+ \
+ $(B)/client/sv_bot.o \
+ $(B)/client/sv_ccmds.o \
+ $(B)/client/sv_client.o \
+ $(B)/client/sv_game.o \
+ $(B)/client/sv_init.o \
+ $(B)/client/sv_main.o \
+ $(B)/client/sv_net_chan.o \
+ $(B)/client/sv_snapshot.o \
+ $(B)/client/sv_world.o \
+ \
+ $(B)/client/q_math.o \
+ $(B)/client/q_shared.o \
+ \
+ $(B)/client/unzip.o \
+ $(B)/client/puff.o \
+ $(B)/client/vm.o \
+ $(B)/client/vm_interpreted.o \
+ \
+ $(B)/client/be_aas_bspq3.o \
+ $(B)/client/be_aas_cluster.o \
+ $(B)/client/be_aas_debug.o \
+ $(B)/client/be_aas_entity.o \
+ $(B)/client/be_aas_file.o \
+ $(B)/client/be_aas_main.o \
+ $(B)/client/be_aas_move.o \
+ $(B)/client/be_aas_optimize.o \
+ $(B)/client/be_aas_reach.o \
+ $(B)/client/be_aas_route.o \
+ $(B)/client/be_aas_routealt.o \
+ $(B)/client/be_aas_sample.o \
+ $(B)/client/be_ai_char.o \
+ $(B)/client/be_ai_chat.o \
+ $(B)/client/be_ai_gen.o \
+ $(B)/client/be_ai_goal.o \
+ $(B)/client/be_ai_move.o \
+ $(B)/client/be_ai_weap.o \
+ $(B)/client/be_ai_weight.o \
+ $(B)/client/be_ea.o \
+ $(B)/client/be_interface.o \
+ $(B)/client/l_crc.o \
+ $(B)/client/l_libvar.o \
+ $(B)/client/l_log.o \
+ $(B)/client/l_memory.o \
+ $(B)/client/l_precomp.o \
+ $(B)/client/l_script.o \
+ $(B)/client/l_struct.o \
+ \
+ $(B)/client/jcapimin.o \
+ $(B)/client/jcapistd.o \
+ $(B)/client/jccoefct.o \
+ $(B)/client/jccolor.o \
+ $(B)/client/jcdctmgr.o \
+ $(B)/client/jchuff.o \
+ $(B)/client/jcinit.o \
+ $(B)/client/jcmainct.o \
+ $(B)/client/jcmarker.o \
+ $(B)/client/jcmaster.o \
+ $(B)/client/jcomapi.o \
+ $(B)/client/jcparam.o \
+ $(B)/client/jcphuff.o \
+ $(B)/client/jcprepct.o \
+ $(B)/client/jcsample.o \
+ $(B)/client/jdapimin.o \
+ $(B)/client/jdapistd.o \
+ $(B)/client/jdatasrc.o \
+ $(B)/client/jdcoefct.o \
+ $(B)/client/jdcolor.o \
+ $(B)/client/jddctmgr.o \
+ $(B)/client/jdhuff.o \
+ $(B)/client/jdinput.o \
+ $(B)/client/jdmainct.o \
+ $(B)/client/jdmarker.o \
+ $(B)/client/jdmaster.o \
+ $(B)/client/jdpostct.o \
+ $(B)/client/jdsample.o \
+ $(B)/client/jdtrans.o \
+ $(B)/client/jerror.o \
+ $(B)/client/jfdctflt.o \
+ $(B)/client/jidctflt.o \
+ $(B)/client/jmemmgr.o \
+ $(B)/client/jmemnobs.o \
+ $(B)/client/jutils.o \
+ \
+ $(B)/client/tr_animation.o \
+ $(B)/client/tr_backend.o \
+ $(B)/client/tr_bsp.o \
+ $(B)/client/tr_cmds.o \
+ $(B)/client/tr_curve.o \
+ $(B)/client/tr_flares.o \
+ $(B)/client/tr_font.o \
+ $(B)/client/tr_image.o \
+ $(B)/client/tr_image_png.o \
+ $(B)/client/tr_image_jpg.o \
+ $(B)/client/tr_image_bmp.o \
+ $(B)/client/tr_image_tga.o \
+ $(B)/client/tr_image_pcx.o \
+ $(B)/client/tr_init.o \
+ $(B)/client/tr_light.o \
+ $(B)/client/tr_main.o \
+ $(B)/client/tr_marks.o \
+ $(B)/client/tr_mesh.o \
+ $(B)/client/tr_model.o \
+ $(B)/client/tr_noise.o \
+ $(B)/client/tr_scene.o \
+ $(B)/client/tr_shade.o \
+ $(B)/client/tr_shade_calc.o \
+ $(B)/client/tr_shader.o \
+ $(B)/client/tr_shadows.o \
+ $(B)/client/tr_sky.o \
+ $(B)/client/tr_surface.o \
+ $(B)/client/tr_world.o \
+ \
+ $(B)/client/sdl_gamma.o \
+ $(B)/client/sdl_input.o \
+ $(B)/client/sdl_snd.o \
+ \
+ $(B)/client/con_passive.o \
+ $(B)/client/con_log.o \
+ $(B)/client/sys_main.o
+
+ifeq ($(ARCH),i386)
+ Q3OBJ += \
+ $(B)/client/snd_mixa.o \
+ $(B)/client/matha.o \
+ $(B)/client/ftola.o \
+ $(B)/client/snapvectora.o
+endif
+ifeq ($(ARCH),x86)
+ Q3OBJ += \
+ $(B)/client/snd_mixa.o \
+ $(B)/client/matha.o \
+ $(B)/client/ftola.o \
+ $(B)/client/snapvectora.o
+endif
+
+ifeq ($(USE_VOIP),1)
+ifeq ($(USE_INTERNAL_SPEEX),1)
+Q3OBJ += \
+ $(B)/client/bits.o \
+ $(B)/client/buffer.o \
+ $(B)/client/cb_search.o \
+ $(B)/client/exc_10_16_table.o \
+ $(B)/client/exc_10_32_table.o \
+ $(B)/client/exc_20_32_table.o \
+ $(B)/client/exc_5_256_table.o \
+ $(B)/client/exc_5_64_table.o \
+ $(B)/client/exc_8_128_table.o \
+ $(B)/client/fftwrap.o \
+ $(B)/client/filterbank.o \
+ $(B)/client/filters.o \
+ $(B)/client/gain_table.o \
+ $(B)/client/gain_table_lbr.o \
+ $(B)/client/hexc_10_32_table.o \
+ $(B)/client/hexc_table.o \
+ $(B)/client/high_lsp_tables.o \
+ $(B)/client/jitter.o \
+ $(B)/client/kiss_fft.o \
+ $(B)/client/kiss_fftr.o \
+ $(B)/client/lpc.o \
+ $(B)/client/lsp.o \
+ $(B)/client/lsp_tables_nb.o \
+ $(B)/client/ltp.o \
+ $(B)/client/mdf.o \
+ $(B)/client/modes.o \
+ $(B)/client/modes_wb.o \
+ $(B)/client/nb_celp.o \
+ $(B)/client/preprocess.o \
+ $(B)/client/quant_lsp.o \
+ $(B)/client/resample.o \
+ $(B)/client/sb_celp.o \
+ $(B)/client/smallft.o \
+ $(B)/client/speex.o \
+ $(B)/client/speex_callbacks.o \
+ $(B)/client/speex_header.o \
+ $(B)/client/stereo.o \
+ $(B)/client/vbr.o \
+ $(B)/client/vq.o \
+ $(B)/client/window.o
+endif
+endif
+
+
+ifeq ($(HAVE_VM_COMPILED),true)
+ ifeq ($(ARCH),i386)
+ Q3OBJ += $(B)/client/vm_x86.o
+ endif
+ ifeq ($(ARCH),x86)
+ Q3OBJ += $(B)/client/vm_x86.o
+ endif
+ ifeq ($(ARCH),x86_64)
+ Q3OBJ += $(B)/client/vm_x86_64.o $(B)/client/vm_x86_64_assembler.o
+ endif
+ ifeq ($(ARCH),ppc)
+ Q3OBJ += $(B)/client/vm_powerpc.o $(B)/client/vm_powerpc_asm.o
+ endif
+ ifeq ($(ARCH),ppc64)
+ Q3OBJ += $(B)/client/vm_powerpc.o $(B)/client/vm_powerpc_asm.o
+ endif
+ ifeq ($(ARCH),sparc)
+ Q3OBJ += $(B)/client/vm_sparc.o
+ endif
+endif
+
+ifeq ($(PLATFORM),mingw32)
+ Q3OBJ += \
+ $(B)/client/win_resource.o \
+ $(B)/client/sys_win32.o
+else
+ Q3OBJ += \
+ $(B)/client/sys_unix.o
+endif
+
+ifeq ($(USE_MUMBLE),1)
+ Q3OBJ += \
+ $(B)/client/libmumblelink.o
+endif
+
+Q3POBJ += \
+ $(B)/client/sdl_glimp.o
+
+Q3POBJ_SMP += \
+ $(B)/clientsmp/sdl_glimp.o
+
+$(B)/ioquake3.$(ARCH)$(BINEXT): $(Q3OBJ) $(Q3POBJ) $(LIBSDLMAIN)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \
+ -o $@ $(Q3OBJ) $(Q3POBJ) \
+ $(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS)
+
+$(B)/ioquake3-smp.$(ARCH)$(BINEXT): $(Q3OBJ) $(Q3POBJ_SMP) $(LIBSDLMAIN)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(THREAD_LDFLAGS) \
+ -o $@ $(Q3OBJ) $(Q3POBJ_SMP) \
+ $(THREAD_LIBS) $(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS)
+
+ifneq ($(strip $(LIBSDLMAIN)),)
+ifneq ($(strip $(LIBSDLMAINSRC)),)
+$(LIBSDLMAIN) : $(LIBSDLMAINSRC)
+ cp $< $@
+ ranlib $@
+endif
+endif
+
+
+
+#############################################################################
+# DEDICATED SERVER
+#############################################################################
+
+Q3DOBJ = \
+ $(B)/ded/sv_bot.o \
+ $(B)/ded/sv_client.o \
+ $(B)/ded/sv_ccmds.o \
+ $(B)/ded/sv_game.o \
+ $(B)/ded/sv_init.o \
+ $(B)/ded/sv_main.o \
+ $(B)/ded/sv_net_chan.o \
+ $(B)/ded/sv_snapshot.o \
+ $(B)/ded/sv_world.o \
+ \
+ $(B)/ded/cm_load.o \
+ $(B)/ded/cm_patch.o \
+ $(B)/ded/cm_polylib.o \
+ $(B)/ded/cm_test.o \
+ $(B)/ded/cm_trace.o \
+ $(B)/ded/cmd.o \
+ $(B)/ded/common.o \
+ $(B)/ded/cvar.o \
+ $(B)/ded/files.o \
+ $(B)/ded/md4.o \
+ $(B)/ded/msg.o \
+ $(B)/ded/net_chan.o \
+ $(B)/ded/net_ip.o \
+ $(B)/ded/huffman.o \
+ \
+ $(B)/ded/q_math.o \
+ $(B)/ded/q_shared.o \
+ \
+ $(B)/ded/unzip.o \
+ $(B)/ded/vm.o \
+ $(B)/ded/vm_interpreted.o \
+ \
+ $(B)/ded/be_aas_bspq3.o \
+ $(B)/ded/be_aas_cluster.o \
+ $(B)/ded/be_aas_debug.o \
+ $(B)/ded/be_aas_entity.o \
+ $(B)/ded/be_aas_file.o \
+ $(B)/ded/be_aas_main.o \
+ $(B)/ded/be_aas_move.o \
+ $(B)/ded/be_aas_optimize.o \
+ $(B)/ded/be_aas_reach.o \
+ $(B)/ded/be_aas_route.o \
+ $(B)/ded/be_aas_routealt.o \
+ $(B)/ded/be_aas_sample.o \
+ $(B)/ded/be_ai_char.o \
+ $(B)/ded/be_ai_chat.o \
+ $(B)/ded/be_ai_gen.o \
+ $(B)/ded/be_ai_goal.o \
+ $(B)/ded/be_ai_move.o \
+ $(B)/ded/be_ai_weap.o \
+ $(B)/ded/be_ai_weight.o \
+ $(B)/ded/be_ea.o \
+ $(B)/ded/be_interface.o \
+ $(B)/ded/l_crc.o \
+ $(B)/ded/l_libvar.o \
+ $(B)/ded/l_log.o \
+ $(B)/ded/l_memory.o \
+ $(B)/ded/l_precomp.o \
+ $(B)/ded/l_script.o \
+ $(B)/ded/l_struct.o \
+ \
+ $(B)/ded/null_client.o \
+ $(B)/ded/null_input.o \
+ $(B)/ded/null_snddma.o \
+ \
+ $(B)/ded/con_log.o \
+ $(B)/ded/sys_main.o
+
+ifeq ($(ARCH),i386)
+ Q3DOBJ += \
+ $(B)/ded/ftola.o \
+ $(B)/ded/snapvectora.o \
+ $(B)/ded/matha.o
+endif
+ifeq ($(ARCH),x86)
+ Q3DOBJ += \
+ $(B)/ded/ftola.o \
+ $(B)/ded/snapvectora.o \
+ $(B)/ded/matha.o
+endif
+
+ifeq ($(HAVE_VM_COMPILED),true)
+ ifeq ($(ARCH),i386)
+ Q3DOBJ += $(B)/ded/vm_x86.o
+ endif
+ ifeq ($(ARCH),x86)
+ Q3DOBJ += $(B)/ded/vm_x86.o
+ endif
+ ifeq ($(ARCH),x86_64)
+ Q3DOBJ += $(B)/ded/vm_x86_64.o $(B)/ded/vm_x86_64_assembler.o
+ endif
+ ifeq ($(ARCH),ppc)
+ Q3DOBJ += $(B)/ded/vm_powerpc.o $(B)/ded/vm_powerpc_asm.o
+ endif
+ ifeq ($(ARCH),ppc64)
+ Q3DOBJ += $(B)/ded/vm_powerpc.o $(B)/ded/vm_powerpc_asm.o
+ endif
+ ifeq ($(ARCH),sparc)
+ Q3DOBJ += $(B)/ded/vm_sparc.o
+ endif
+endif
+
+ifeq ($(PLATFORM),mingw32)
+ Q3DOBJ += \
+ $(B)/ded/win_resource.o \
+ $(B)/ded/sys_win32.o \
+ $(B)/ded/con_win32.o
+else
+ Q3DOBJ += \
+ $(B)/ded/sys_unix.o \
+ $(B)/ded/con_tty.o
+endif
+
+$(B)/ioq3ded.$(ARCH)$(BINEXT): $(Q3DOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(Q3DOBJ) $(LIBS)
+
+
+
+#############################################################################
+## BASEQ3 CGAME
+#############################################################################
+
+Q3CGOBJ_ = \
+ $(B)/baseq3/cgame/cg_main.o \
+ $(B)/baseq3/game/bg_misc.o \
+ $(B)/baseq3/game/bg_lib.o \
+ $(B)/baseq3/game/bg_pmove.o \
+ $(B)/baseq3/game/bg_slidemove.o \
+ $(B)/baseq3/cgame/cg_challenges.o \
+ $(B)/baseq3/cgame/cg_consolecmds.o \
+ $(B)/baseq3/cgame/cg_draw.o \
+ $(B)/baseq3/cgame/cg_drawtools.o \
+ $(B)/baseq3/cgame/cg_effects.o \
+ $(B)/baseq3/cgame/cg_ents.o \
+ $(B)/baseq3/cgame/cg_event.o \
+ $(B)/baseq3/cgame/cg_info.o \
+ $(B)/baseq3/cgame/cg_localents.o \
+ $(B)/baseq3/cgame/cg_marks.o \
+ $(B)/baseq3/cgame/cg_players.o \
+ $(B)/baseq3/cgame/cg_playerstate.o \
+ $(B)/baseq3/cgame/cg_predict.o \
+ $(B)/baseq3/cgame/cg_scoreboard.o \
+ $(B)/baseq3/cgame/cg_servercmds.o \
+ $(B)/baseq3/cgame/cg_snapshot.o \
+ $(B)/baseq3/cgame/cg_unlagged.o \
+ $(B)/baseq3/cgame/cg_view.o \
+ $(B)/baseq3/cgame/cg_weapons.o \
+ \
+ $(B)/baseq3/qcommon/q_math.o \
+ $(B)/baseq3/qcommon/q_shared.o
+
+Q3CGOBJ = $(Q3CGOBJ_) $(B)/baseq3/cgame/cg_syscalls.o
+Q3CGVMOBJ = $(Q3CGOBJ_:%.o=%.asm)
+
+$(B)/baseq3/cgame$(ARCH).$(SHLIBEXT): $(Q3CGOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3CGOBJ)
+
+$(B)/baseq3/vm/cgame.qvm: $(Q3CGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM)
+ $(echo_cmd) "Q3ASM $@"
+ $(Q)$(Q3ASM) -o $@ $(Q3CGVMOBJ) $(CGDIR)/cg_syscalls.asm
+
+#############################################################################
+## MISSIONPACK CGAME
+#############################################################################
+
+MPCGOBJ_ = \
+ $(B)/missionpack/cgame/cg_main.o \
+ $(B)/missionpack/game/bg_misc.o \
+ $(B)/missionpack/game/bg_lib.o \
+ $(B)/missionpack/game/bg_pmove.o \
+ $(B)/missionpack/game/bg_slidemove.o \
+ $(B)/missionpack/cgame/cg_challenges.o \
+ $(B)/missionpack/cgame/cg_consolecmds.o \
+ $(B)/missionpack/cgame/cg_newdraw.o \
+ $(B)/missionpack/cgame/cg_draw.o \
+ $(B)/missionpack/cgame/cg_drawtools.o \
+ $(B)/missionpack/cgame/cg_effects.o \
+ $(B)/missionpack/cgame/cg_ents.o \
+ $(B)/missionpack/cgame/cg_event.o \
+ $(B)/missionpack/cgame/cg_info.o \
+ $(B)/missionpack/cgame/cg_localents.o \
+ $(B)/missionpack/cgame/cg_marks.o \
+ $(B)/missionpack/cgame/cg_players.o \
+ $(B)/missionpack/cgame/cg_playerstate.o \
+ $(B)/missionpack/cgame/cg_predict.o \
+ $(B)/missionpack/cgame/cg_scoreboard.o \
+ $(B)/missionpack/cgame/cg_servercmds.o \
+ $(B)/missionpack/cgame/cg_snapshot.o \
+ $(B)/missionpack/cgame/cg_unlagged.o \
+ $(B)/missionpack/cgame/cg_view.o \
+ $(B)/missionpack/cgame/cg_weapons.o \
+ $(B)/missionpack/ui/ui_shared.o \
+ \
+ $(B)/missionpack/qcommon/q_math.o \
+ $(B)/missionpack/qcommon/q_shared.o
+
+MPCGOBJ = $(MPCGOBJ_) $(B)/missionpack/cgame/cg_syscalls.o
+MPCGVMOBJ = $(MPCGOBJ_:%.o=%.asm)
+
+$(B)/missionpack/cgame$(ARCH).$(SHLIBEXT): $(MPCGOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPCGOBJ)
+
+$(B)/missionpack/vm/cgame.qvm: $(MPCGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM)
+ $(echo_cmd) "Q3ASM $@"
+ $(Q)$(Q3ASM) -o $@ $(MPCGVMOBJ) $(CGDIR)/cg_syscalls.asm
+
+
+
+#############################################################################
+## BASEQ3 GAME
+#############################################################################
+
+Q3GOBJ_ = \
+ $(B)/baseq3/game/g_main.o \
+ $(B)/baseq3/game/ai_chat.o \
+ $(B)/baseq3/game/ai_cmd.o \
+ $(B)/baseq3/game/ai_dmnet.o \
+ $(B)/baseq3/game/ai_dmq3.o \
+ $(B)/baseq3/game/ai_main.o \
+ $(B)/baseq3/game/ai_team.o \
+ $(B)/baseq3/game/ai_vcmd.o \
+ $(B)/baseq3/game/bg_misc.o \
+ $(B)/baseq3/game/bg_lib.o \
+ $(B)/baseq3/game/bg_pmove.o \
+ $(B)/baseq3/game/bg_slidemove.o \
+ $(B)/baseq3/game/g_active.o \
+ $(B)/baseq3/game/g_arenas.o \
+ $(B)/baseq3/game/g_admin.o \
+ $(B)/baseq3/game/g_bot.o \
+ $(B)/baseq3/game/g_client.o \
+ $(B)/baseq3/game/g_cmds.o \
+ $(B)/baseq3/game/g_cmds_ext.o \
+ $(B)/baseq3/game/g_combat.o \
+ $(B)/baseq3/game/g_items.o \
+ $(B)/baseq3/game/bg_alloc.o \
+ $(B)/baseq3/game/g_fileops.o \
+ $(B)/baseq3/game/g_killspree.o \
+ $(B)/baseq3/game/g_misc.o \
+ $(B)/baseq3/game/g_missile.o \
+ $(B)/baseq3/game/g_mover.o \
+ $(B)/baseq3/game/g_playerstore.o \
+ $(B)/baseq3/game/g_session.o \
+ $(B)/baseq3/game/g_spawn.o \
+ $(B)/baseq3/game/g_svcmds.o \
+ $(B)/baseq3/game/g_svcmds_ext.o \
+ $(B)/baseq3/game/g_target.o \
+ $(B)/baseq3/game/g_team.o \
+ $(B)/baseq3/game/g_trigger.o \
+ $(B)/baseq3/game/g_unlagged.o \
+ $(B)/baseq3/game/g_utils.o \
+ $(B)/baseq3/game/g_vote.o \
+ $(B)/baseq3/game/g_weapon.o \
+ \
+ $(B)/baseq3/qcommon/q_math.o \
+ $(B)/baseq3/qcommon/q_shared.o
+
+Q3GOBJ = $(Q3GOBJ_) $(B)/baseq3/game/g_syscalls.o
+Q3GVMOBJ = $(Q3GOBJ_:%.o=%.asm)
+
+$(B)/baseq3/qagame$(ARCH).$(SHLIBEXT): $(Q3GOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3GOBJ)
+
+$(B)/baseq3/vm/qagame.qvm: $(Q3GVMOBJ) $(GDIR)/g_syscalls.asm $(Q3ASM)
+ $(echo_cmd) "Q3ASM $@"
+ $(Q)$(Q3ASM) -o $@ $(Q3GVMOBJ) $(GDIR)/g_syscalls.asm
+
+#############################################################################
+## MISSIONPACK GAME
+#############################################################################
+
+MPGOBJ_ = \
+ $(B)/missionpack/game/g_main.o \
+ $(B)/missionpack/game/ai_chat.o \
+ $(B)/missionpack/game/ai_cmd.o \
+ $(B)/missionpack/game/ai_dmnet.o \
+ $(B)/missionpack/game/ai_dmq3.o \
+ $(B)/missionpack/game/ai_main.o \
+ $(B)/missionpack/game/ai_team.o \
+ $(B)/missionpack/game/ai_vcmd.o \
+ $(B)/missionpack/game/bg_misc.o \
+ $(B)/missionpack/game/bg_lib.o \
+ $(B)/missionpack/game/bg_pmove.o \
+ $(B)/missionpack/game/bg_slidemove.o \
+ $(B)/missionpack/game/g_active.o \
+ $(B)/missionpack/game/g_admin.o \
+ $(B)/missionpack/game/g_arenas.o \
+ $(B)/missionpack/game/g_bot.o \
+ $(B)/missionpack/game/g_client.o \
+ $(B)/missionpack/game/g_cmds.o \
+ $(B)/missionpack/game/g_cmds_ext.o \
+ $(B)/missionpack/game/g_combat.o \
+ $(B)/missionpack/game/g_items.o \
+ $(B)/missionpack/game/bg_alloc.o \
+ $(B)/missionpack/game/g_fileops.o \
+ $(B)/missionpack/game/g_killspree.o \
+ $(B)/missionpack/game/g_misc.o \
+ $(B)/missionpack/game/g_missile.o \
+ $(B)/missionpack/game/g_mover.o \
+ $(B)/missionpack/game/g_playerstore.o \
+ $(B)/missionpack/game/g_session.o \
+ $(B)/missionpack/game/g_spawn.o \
+ $(B)/missionpack/game/g_svcmds.o \
+ $(B)/missionpack/game/g_svcmds_ext.o \
+ $(B)/missionpack/game/g_target.o \
+ $(B)/missionpack/game/g_team.o \
+ $(B)/missionpack/game/g_trigger.o \
+ $(B)/missionpack/game/g_unlagged.o \
+ $(B)/missionpack/game/g_utils.o \
+ $(B)/missionpack/game/g_vote.o \
+ $(B)/missionpack/game/g_weapon.o \
+ \
+ $(B)/missionpack/qcommon/q_math.o \
+ $(B)/missionpack/qcommon/q_shared.o
+
+MPGOBJ = $(MPGOBJ_) $(B)/missionpack/game/g_syscalls.o
+MPGVMOBJ = $(MPGOBJ_:%.o=%.asm)
+
+$(B)/missionpack/qagame$(ARCH).$(SHLIBEXT): $(MPGOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPGOBJ)
+
+$(B)/missionpack/vm/qagame.qvm: $(MPGVMOBJ) $(GDIR)/g_syscalls.asm $(Q3ASM)
+ $(echo_cmd) "Q3ASM $@"
+ $(Q)$(Q3ASM) -o $@ $(MPGVMOBJ) $(GDIR)/g_syscalls.asm
+
+
+
+#############################################################################
+## BASEQ3 UI
+#############################################################################
+
+Q3UIOBJ_ = \
+ $(B)/baseq3/ui/ui_main.o \
+ $(B)/baseq3/game/bg_misc.o \
+ $(B)/baseq3/game/bg_lib.o \
+ $(B)/baseq3/ui/ui_addbots.o \
+ $(B)/baseq3/ui/ui_atoms.o \
+ $(B)/baseq3/ui/ui_cdkey.o \
+ $(B)/baseq3/ui/ui_challenges.o \
+ $(B)/baseq3/ui/ui_cinematics.o \
+ $(B)/baseq3/ui/ui_confirm.o \
+ $(B)/baseq3/ui/ui_connect.o \
+ $(B)/baseq3/ui/ui_controls2.o \
+ $(B)/baseq3/ui/ui_credits.o \
+ $(B)/baseq3/ui/ui_demo2.o \
+ $(B)/baseq3/ui/ui_display.o \
+ $(B)/baseq3/ui/ui_firstconnect.o \
+ $(B)/baseq3/ui/ui_gameinfo.o \
+ $(B)/baseq3/ui/ui_ingame.o \
+ $(B)/baseq3/ui/ui_loadconfig.o \
+ $(B)/baseq3/ui/ui_menu.o \
+ $(B)/baseq3/ui/ui_mfield.o \
+ $(B)/baseq3/ui/ui_mods.o \
+ $(B)/baseq3/ui/ui_network.o \
+ $(B)/baseq3/ui/ui_options.o \
+ $(B)/baseq3/ui/ui_password.o \
+ $(B)/baseq3/ui/ui_playermodel.o \
+ $(B)/baseq3/ui/ui_players.o \
+ $(B)/baseq3/ui/ui_playersettings.o \
+ $(B)/baseq3/ui/ui_preferences.o \
+ $(B)/baseq3/ui/ui_qmenu.o \
+ $(B)/baseq3/ui/ui_removebots.o \
+ $(B)/baseq3/ui/ui_saveconfig.o \
+ $(B)/baseq3/ui/ui_serverinfo.o \
+ $(B)/baseq3/ui/ui_servers2.o \
+ $(B)/baseq3/ui/ui_setup.o \
+ $(B)/baseq3/ui/ui_sound.o \
+ $(B)/baseq3/ui/ui_sparena.o \
+ $(B)/baseq3/ui/ui_specifyserver.o \
+ $(B)/baseq3/ui/ui_splevel.o \
+ $(B)/baseq3/ui/ui_sppostgame.o \
+ $(B)/baseq3/ui/ui_spskill.o \
+ $(B)/baseq3/ui/ui_startserver.o \
+ $(B)/baseq3/ui/ui_team.o \
+ $(B)/baseq3/ui/ui_teamorders.o \
+ $(B)/baseq3/ui/ui_video.o \
+ $(B)/baseq3/ui/ui_votemenu.o \
+ $(B)/baseq3/ui/ui_votemenu_fraglimit.o \
+ $(B)/baseq3/ui/ui_votemenu_timelimit.o \
+ $(B)/baseq3/ui/ui_votemenu_gametype.o \
+ $(B)/baseq3/ui/ui_votemenu_kick.o \
+ $(B)/baseq3/ui/ui_votemenu_map.o \
+ $(B)/baseq3/ui/ui_votemenu_custom.o \
+ \
+ $(B)/baseq3/qcommon/q_math.o \
+ $(B)/baseq3/qcommon/q_shared.o
+
+Q3UIOBJ = $(Q3UIOBJ_) $(B)/missionpack/ui/ui_syscalls.o
+Q3UIVMOBJ = $(Q3UIOBJ_:%.o=%.asm)
+
+$(B)/baseq3/ui$(ARCH).$(SHLIBEXT): $(Q3UIOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3UIOBJ)
+
+$(B)/baseq3/vm/ui.qvm: $(Q3UIVMOBJ) $(UIDIR)/ui_syscalls.asm $(Q3ASM)
+ $(echo_cmd) "Q3ASM $@"
+ $(Q)$(Q3ASM) -o $@ $(Q3UIVMOBJ) $(UIDIR)/ui_syscalls.asm
+
+#############################################################################
+## MISSIONPACK UI
+#############################################################################
+
+MPUIOBJ_ = \
+ $(B)/missionpack/ui/ui_main.o \
+ $(B)/missionpack/ui/ui_atoms.o \
+ $(B)/missionpack/ui/ui_gameinfo.o \
+ $(B)/missionpack/ui/ui_players.o \
+ $(B)/missionpack/ui/ui_shared.o \
+ \
+ $(B)/missionpack/ui/bg_misc.o \
+ $(B)/missionpack/ui/bg_lib.o \
+ \
+ $(B)/missionpack/qcommon/q_math.o \
+ $(B)/missionpack/qcommon/q_shared.o
+
+MPUIOBJ = $(MPUIOBJ_) $(B)/missionpack/ui/ui_syscalls.o
+MPUIVMOBJ = $(MPUIOBJ_:%.o=%.asm)
+
+$(B)/missionpack/ui$(ARCH).$(SHLIBEXT): $(MPUIOBJ)
+ $(echo_cmd) "LD $@"
+ $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPUIOBJ)
+
+$(B)/missionpack/vm/ui.qvm: $(MPUIVMOBJ) $(UIDIR)/ui_syscalls.asm $(Q3ASM)
+ $(echo_cmd) "Q3ASM $@"
+ $(Q)$(Q3ASM) -o $@ $(MPUIVMOBJ) $(UIDIR)/ui_syscalls.asm
+
+
+
+#############################################################################
+## CLIENT/SERVER RULES
+#############################################################################
+
+$(B)/client/%.o: $(ASMDIR)/%.s
+ $(DO_AS)
+
+$(B)/client/%.o: $(CDIR)/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(SDIR)/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(CMDIR)/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(BLIBDIR)/%.c
+ $(DO_BOT_CC)
+
+$(B)/client/%.o: $(JPDIR)/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(SPEEXDIR)/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(RDIR)/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(SDLDIR)/%.c
+ $(DO_CC)
+
+$(B)/clientsmp/%.o: $(SDLDIR)/%.c
+ $(DO_SMP_CC)
+
+$(B)/client/%.o: $(SYSDIR)/%.c
+ $(DO_CC)
+
+$(B)/client/%.o: $(SYSDIR)/%.rc
+ $(DO_WINDRES)
+
+
+$(B)/ded/%.o: $(ASMDIR)/%.s
+ $(DO_AS)
+
+$(B)/ded/%.o: $(SDIR)/%.c
+ $(DO_DED_CC)
+
+$(B)/ded/%.o: $(CMDIR)/%.c
+ $(DO_DED_CC)
+
+$(B)/ded/%.o: $(BLIBDIR)/%.c
+ $(DO_BOT_CC)
+
+$(B)/ded/%.o: $(SYSDIR)/%.c
+ $(DO_DED_CC)
+
+$(B)/ded/%.o: $(SYSDIR)/%.rc
+ $(DO_WINDRES)
+
+$(B)/ded/%.o: $(NDIR)/%.c
+ $(DO_DED_CC)
+
+# Extra dependencies to ensure the SVN version is incorporated
+ifeq ($(USE_SVN),1)
+ $(B)/client/cl_console.o : .svn/entries
+ $(B)/client/common.o : .svn/entries
+ $(B)/ded/common.o : .svn/entries
+endif
+
+
+#############################################################################
+## GAME MODULE RULES
+#############################################################################
+
+$(B)/baseq3/cgame/bg_%.o: $(GDIR)/bg_%.c
+ $(DO_CGAME_CC)
+
+$(B)/baseq3/cgame/%.o: $(CGDIR)/%.c
+ $(DO_CGAME_CC)
+
+$(B)/baseq3/cgame/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
+ $(DO_CGAME_Q3LCC)
+
+$(B)/baseq3/cgame/%.asm: $(CGDIR)/%.c $(Q3LCC)
+ $(DO_CGAME_Q3LCC)
+
+$(B)/missionpack/cgame/bg_%.o: $(GDIR)/bg_%.c
+ $(DO_CGAME_CC_MISSIONPACK)
+
+$(B)/missionpack/cgame/%.o: $(CGDIR)/%.c
+ $(DO_CGAME_CC_MISSIONPACK)
+
+$(B)/missionpack/cgame/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
+ $(DO_CGAME_Q3LCC_MISSIONPACK)
+
+$(B)/missionpack/cgame/%.asm: $(CGDIR)/%.c $(Q3LCC)
+ $(DO_CGAME_Q3LCC_MISSIONPACK)
+
+
+$(B)/baseq3/game/%.o: $(GDIR)/%.c
+ $(DO_GAME_CC)
+
+$(B)/baseq3/game/%.asm: $(GDIR)/%.c $(Q3LCC)
+ $(DO_GAME_Q3LCC)
+
+$(B)/missionpack/game/%.o: $(GDIR)/%.c
+ $(DO_GAME_CC_MISSIONPACK)
+
+$(B)/missionpack/game/%.asm: $(GDIR)/%.c $(Q3LCC)
+ $(DO_GAME_Q3LCC_MISSIONPACK)
+
+
+$(B)/baseq3/ui/bg_%.o: $(GDIR)/bg_%.c
+ $(DO_UI_CC)
+
+$(B)/baseq3/ui/%.o: $(Q3UIDIR)/%.c
+ $(DO_UI_CC)
+
+$(B)/baseq3/ui/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
+ $(DO_UI_Q3LCC)
+
+$(B)/baseq3/ui/%.asm: $(Q3UIDIR)/%.c $(Q3LCC)
+ $(DO_UI_Q3LCC)
+
+$(B)/missionpack/ui/bg_%.o: $(GDIR)/bg_%.c
+ $(DO_UI_CC_MISSIONPACK)
+
+$(B)/missionpack/ui/%.o: $(UIDIR)/%.c
+ $(DO_UI_CC_MISSIONPACK)
+
+$(B)/missionpack/ui/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
+ $(DO_UI_Q3LCC_MISSIONPACK)
+
+$(B)/missionpack/ui/%.asm: $(UIDIR)/%.c $(Q3LCC)
+ $(DO_UI_Q3LCC_MISSIONPACK)
+
+
+$(B)/baseq3/qcommon/%.o: $(CMDIR)/%.c
+ $(DO_SHLIB_CC)
+
+$(B)/baseq3/qcommon/%.asm: $(CMDIR)/%.c $(Q3LCC)
+ $(DO_Q3LCC)
+
+$(B)/missionpack/qcommon/%.o: $(CMDIR)/%.c
+ $(DO_SHLIB_CC_MISSIONPACK)
+
+$(B)/missionpack/qcommon/%.asm: $(CMDIR)/%.c $(Q3LCC)
+ $(DO_Q3LCC_MISSIONPACK)
+
+
+#############################################################################
+# MISC
+#############################################################################
+
+OBJ = $(Q3OBJ) $(Q3POBJ) $(Q3POBJ_SMP) $(Q3DOBJ) \
+ $(MPGOBJ) $(Q3GOBJ) $(Q3CGOBJ) $(MPCGOBJ) $(Q3UIOBJ) $(MPUIOBJ) \
+ $(MPGVMOBJ) $(Q3GVMOBJ) $(Q3CGVMOBJ) $(MPCGVMOBJ) $(Q3UIVMOBJ) $(MPUIVMOBJ)
+TOOLSOBJ = $(LBURGOBJ) $(Q3CPPOBJ) $(Q3RCCOBJ) $(Q3LCCOBJ) $(Q3ASMOBJ)
+
+
+copyfiles: release
+ @if [ ! -d $(COPYDIR)/baseq3 ]; then echo "You need to set COPYDIR to where your Quake3 data is!"; fi
+ -$(MKDIR) -p -m 0755 $(COPYDIR)/baseq3
+ -$(MKDIR) -p -m 0755 $(COPYDIR)/missionpack
+
+ifneq ($(BUILD_CLIENT),0)
+ $(INSTALL) -s -m 0755 $(BR)/ioquake3.$(ARCH)$(BINEXT) $(COPYDIR)/ioquake3.$(ARCH)$(BINEXT)
+endif
+
+# Don't copy the SMP until it's working together with SDL.
+#ifneq ($(BUILD_CLIENT_SMP),0)
+# $(INSTALL) -s -m 0755 $(BR)/ioquake3-smp.$(ARCH)$(BINEXT) $(COPYDIR)/ioquake3-smp.$(ARCH)$(BINEXT)
+#endif
+
+ifneq ($(BUILD_SERVER),0)
+ @if [ -f $(BR)/ioq3ded.$(ARCH)$(BINEXT) ]; then \
+ $(INSTALL) -s -m 0755 $(BR)/ioq3ded.$(ARCH)$(BINEXT) $(COPYDIR)/ioq3ded.$(ARCH)$(BINEXT); \
+ fi
+endif
+
+ifneq ($(BUILD_GAME_SO),0)
+ $(INSTALL) -s -m 0755 $(BR)/baseq3/cgame$(ARCH).$(SHLIBEXT) \
+ $(COPYDIR)/baseq3/.
+ $(INSTALL) -s -m 0755 $(BR)/baseq3/qagame$(ARCH).$(SHLIBEXT) \
+ $(COPYDIR)/baseq3/.
+ $(INSTALL) -s -m 0755 $(BR)/baseq3/ui$(ARCH).$(SHLIBEXT) \
+ $(COPYDIR)/baseq3/.
+ ifneq ($(BUILD_MISSIONPACK),0)
+ -$(MKDIR) -p -m 0755 $(COPYDIR)/missionpack
+ $(INSTALL) -s -m 0755 $(BR)/missionpack/cgame$(ARCH).$(SHLIBEXT) \
+ $(COPYDIR)/missionpack/.
+ $(INSTALL) -s -m 0755 $(BR)/missionpack/qagame$(ARCH).$(SHLIBEXT) \
+ $(COPYDIR)/missionpack/.
+ $(INSTALL) -s -m 0755 $(BR)/missionpack/ui$(ARCH).$(SHLIBEXT) \
+ $(COPYDIR)/missionpack/.
+ endif
+endif
+
+clean: clean-debug clean-release
+
+#We do not make installers
+#ifeq ($(PLATFORM),mingw32)
+# @$(MAKE) -C $(NSISDIR) clean
+#else
+# @$(MAKE) -C $(LOKISETUPDIR) clean
+#endif
+
+clean-debug:
+ @$(MAKE) clean2 B=$(BD)
+
+clean-release:
+ @$(MAKE) clean2 B=$(BR)
+
+clean2:
+ @echo "CLEAN $(B)"
+ @rm -f $(OBJ)
+ @rm -f $(OBJ_D_FILES)
+ @rm -f $(TARGETS)
+
+toolsclean: toolsclean-debug toolsclean-release
+
+toolsclean-debug:
+ @$(MAKE) toolsclean2 B=$(BD)
+
+toolsclean-release:
+ @$(MAKE) toolsclean2 B=$(BR)
+
+toolsclean2:
+ @echo "TOOLS_CLEAN $(B)"
+ @rm -f $(TOOLSOBJ)
+ @rm -f $(TOOLSOBJ_D_FILES)
+ @rm -f $(LBURG) $(DAGCHECK_C) $(Q3RCC) $(Q3CPP) $(Q3LCC) $(Q3ASM)
+
+distclean: clean toolsclean
+ @rm -rf $(BUILD_DIR)
+
+installer: release
+ifeq ($(PLATFORM),mingw32)
+ @$(MAKE) VERSION=$(VERSION) -C $(NSISDIR) V=$(V)
+else
+ @$(MAKE) VERSION=$(VERSION) -C $(LOKISETUPDIR) V=$(V)
+endif
+
+dist:
+ rm -rf ioquake3-$(VERSION)
+ svn export . ioquake3-$(VERSION)
+ tar --owner=root --group=root --force-local -cjf ioquake3-$(VERSION).tar.bz2 ioquake3-$(VERSION)
+ rm -rf ioquake3-$(VERSION)
+
+#############################################################################
+# DEPENDENCIES
+#############################################################################
+
+OBJ_D_FILES=$(filter %.d,$(OBJ:%.o=%.d))
+TOOLSOBJ_D_FILES=$(filter %.d,$(TOOLSOBJ:%.o=%.d))
+-include $(OBJ_D_FILES) $(TOOLSOBJ_D_FILES)
+
+.PHONY: all clean clean2 clean-debug clean-release copyfiles \
+ debug default dist distclean installer makedirs \
+ release targets \
+ toolsclean toolsclean2 toolsclean-debug toolsclean-release
diff --git a/README-0.8.8 b/README-0.8.8
new file mode 100644
index 0000000..03a8145
--- /dev/null
+++ b/README-0.8.8
@@ -0,0 +1,7 @@
+This is the GPLv2+ source for the game code of OpenArena 0.8.8
+
+Compiling should be as simple as typing "make" or double clicking the windows scripts.
+
+This is taken from the oa-0.8.8 branch of http://code.google.com/p/oax/ at revision 295.
+
+More information can likely be found at http://openarena.ws/board/
diff --git a/README-0.8.8~ b/README-0.8.8~
new file mode 100644
index 0000000..91741ca
--- /dev/null
+++ b/README-0.8.8~
@@ -0,0 +1,7 @@
+This is the GPLv2+ source for the gamecode of OpenArena 0.8.8
+
+Compiling should be as simple as typing "make" or double clicking the windows scripts.
+
+This is taken from the oa-0.8.8 branch of http://code.google.com/p/oax/ at revision 295.
+
+More information can likely be found at http://openarena.ws/board/
diff --git a/game/admin.dat b/admin.dat
similarity index 100%
rename from game/admin.dat
rename to admin.dat
diff --git a/engine/code/botlib/aasfile.h b/code/botlib/aasfile.h
similarity index 100%
rename from engine/code/botlib/aasfile.h
rename to code/botlib/aasfile.h
diff --git a/engine/code/botlib/be_aas.h b/code/botlib/be_aas.h
similarity index 100%
rename from engine/code/botlib/be_aas.h
rename to code/botlib/be_aas.h
diff --git a/engine/code/botlib/be_aas_bsp.h b/code/botlib/be_aas_bsp.h
similarity index 100%
rename from engine/code/botlib/be_aas_bsp.h
rename to code/botlib/be_aas_bsp.h
diff --git a/engine/code/botlib/be_aas_cluster.h b/code/botlib/be_aas_cluster.h
similarity index 100%
rename from engine/code/botlib/be_aas_cluster.h
rename to code/botlib/be_aas_cluster.h
diff --git a/engine/code/botlib/be_aas_debug.h b/code/botlib/be_aas_debug.h
similarity index 100%
rename from engine/code/botlib/be_aas_debug.h
rename to code/botlib/be_aas_debug.h
diff --git a/engine/code/botlib/be_aas_def.h b/code/botlib/be_aas_def.h
similarity index 100%
rename from engine/code/botlib/be_aas_def.h
rename to code/botlib/be_aas_def.h
diff --git a/engine/code/botlib/be_aas_entity.h b/code/botlib/be_aas_entity.h
similarity index 100%
rename from engine/code/botlib/be_aas_entity.h
rename to code/botlib/be_aas_entity.h
diff --git a/engine/code/botlib/be_aas_file.h b/code/botlib/be_aas_file.h
similarity index 100%
rename from engine/code/botlib/be_aas_file.h
rename to code/botlib/be_aas_file.h
diff --git a/engine/code/botlib/be_aas_funcs.h b/code/botlib/be_aas_funcs.h
similarity index 100%
rename from engine/code/botlib/be_aas_funcs.h
rename to code/botlib/be_aas_funcs.h
diff --git a/engine/code/botlib/be_aas_main.h b/code/botlib/be_aas_main.h
similarity index 100%
rename from engine/code/botlib/be_aas_main.h
rename to code/botlib/be_aas_main.h
diff --git a/engine/code/botlib/be_aas_move.h b/code/botlib/be_aas_move.h
similarity index 100%
rename from engine/code/botlib/be_aas_move.h
rename to code/botlib/be_aas_move.h
diff --git a/engine/code/botlib/be_aas_optimize.h b/code/botlib/be_aas_optimize.h
similarity index 100%
rename from engine/code/botlib/be_aas_optimize.h
rename to code/botlib/be_aas_optimize.h
diff --git a/engine/code/botlib/be_aas_reach.h b/code/botlib/be_aas_reach.h
similarity index 100%
rename from engine/code/botlib/be_aas_reach.h
rename to code/botlib/be_aas_reach.h
diff --git a/engine/code/botlib/be_aas_route.h b/code/botlib/be_aas_route.h
similarity index 100%
rename from engine/code/botlib/be_aas_route.h
rename to code/botlib/be_aas_route.h
diff --git a/engine/code/botlib/be_aas_routealt.h b/code/botlib/be_aas_routealt.h
similarity index 100%
rename from engine/code/botlib/be_aas_routealt.h
rename to code/botlib/be_aas_routealt.h
diff --git a/engine/code/botlib/be_aas_sample.h b/code/botlib/be_aas_sample.h
similarity index 100%
rename from engine/code/botlib/be_aas_sample.h
rename to code/botlib/be_aas_sample.h
diff --git a/engine/code/botlib/be_ai_char.h b/code/botlib/be_ai_char.h
similarity index 100%
rename from engine/code/botlib/be_ai_char.h
rename to code/botlib/be_ai_char.h
diff --git a/engine/code/botlib/be_ai_chat.h b/code/botlib/be_ai_chat.h
similarity index 100%
rename from engine/code/botlib/be_ai_chat.h
rename to code/botlib/be_ai_chat.h
diff --git a/engine/code/botlib/be_ai_gen.h b/code/botlib/be_ai_gen.h
similarity index 100%
rename from engine/code/botlib/be_ai_gen.h
rename to code/botlib/be_ai_gen.h
diff --git a/engine/code/botlib/be_ai_goal.h b/code/botlib/be_ai_goal.h
similarity index 100%
rename from engine/code/botlib/be_ai_goal.h
rename to code/botlib/be_ai_goal.h
diff --git a/engine/code/botlib/be_ai_move.h b/code/botlib/be_ai_move.h
similarity index 100%
rename from engine/code/botlib/be_ai_move.h
rename to code/botlib/be_ai_move.h
diff --git a/engine/code/botlib/be_ai_weap.h b/code/botlib/be_ai_weap.h
similarity index 100%
rename from engine/code/botlib/be_ai_weap.h
rename to code/botlib/be_ai_weap.h
diff --git a/engine/code/botlib/be_ai_weight.h b/code/botlib/be_ai_weight.h
similarity index 100%
rename from engine/code/botlib/be_ai_weight.h
rename to code/botlib/be_ai_weight.h
diff --git a/engine/code/botlib/be_ea.h b/code/botlib/be_ea.h
similarity index 100%
rename from engine/code/botlib/be_ea.h
rename to code/botlib/be_ea.h
diff --git a/game/code/botlib/be_interface.h b/code/botlib/be_interface.h
similarity index 100%
rename from game/code/botlib/be_interface.h
rename to code/botlib/be_interface.h
diff --git a/game/code/botlib/botlib.h b/code/botlib/botlib.h
similarity index 100%
rename from game/code/botlib/botlib.h
rename to code/botlib/botlib.h
diff --git a/engine/code/botlib/l_crc.h b/code/botlib/l_crc.h
similarity index 100%
rename from engine/code/botlib/l_crc.h
rename to code/botlib/l_crc.h
diff --git a/engine/code/botlib/l_libvar.h b/code/botlib/l_libvar.h
similarity index 100%
rename from engine/code/botlib/l_libvar.h
rename to code/botlib/l_libvar.h
diff --git a/engine/code/botlib/l_log.h b/code/botlib/l_log.h
similarity index 100%
rename from engine/code/botlib/l_log.h
rename to code/botlib/l_log.h
diff --git a/engine/code/botlib/l_memory.h b/code/botlib/l_memory.h
similarity index 100%
rename from engine/code/botlib/l_memory.h
rename to code/botlib/l_memory.h
diff --git a/engine/code/botlib/l_precomp.h b/code/botlib/l_precomp.h
similarity index 100%
rename from engine/code/botlib/l_precomp.h
rename to code/botlib/l_precomp.h
diff --git a/engine/code/botlib/l_script.h b/code/botlib/l_script.h
similarity index 100%
rename from engine/code/botlib/l_script.h
rename to code/botlib/l_script.h
diff --git a/engine/code/botlib/l_struct.h b/code/botlib/l_struct.h
similarity index 100%
rename from engine/code/botlib/l_struct.h
rename to code/botlib/l_struct.h
diff --git a/engine/code/botlib/l_utils.h b/code/botlib/l_utils.h
similarity index 100%
rename from engine/code/botlib/l_utils.h
rename to code/botlib/l_utils.h
diff --git a/engine/code/botlib/lcc.mak b/code/botlib/lcc.mak
similarity index 100%
rename from engine/code/botlib/lcc.mak
rename to code/botlib/lcc.mak
diff --git a/engine/code/botlib/linux-i386.mak b/code/botlib/linux-i386.mak
similarity index 100%
rename from engine/code/botlib/linux-i386.mak
rename to code/botlib/linux-i386.mak
diff --git a/game/code/cgame/cg_challenges.c b/code/cgame/cg_challenges.c
similarity index 100%
rename from game/code/cgame/cg_challenges.c
rename to code/cgame/cg_challenges.c
diff --git a/code/cgame/cg_consolecmds.c b/code/cgame/cg_consolecmds.c
new file mode 100644
index 0000000..5337460
--- /dev/null
+++ b/code/cgame/cg_consolecmds.c
@@ -0,0 +1,622 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_consolecmds.c -- text commands typed in at the local console, or
+// executed by a key binding
+
+#include "cg_local.h"
+#include "../ui/ui_shared.h"
+#ifdef MISSIONPACK
+extern menuDef_t *menuScoreboard;
+#endif
+
+void CG_PrintClientNumbers( void ) {
+ int i;
+
+ CG_Printf( "slot score ping name\n" );
+ CG_Printf( "---- ----- ---- ----\n" );
+
+ for(i=0;i<cg.numScores;i++) {
+ CG_Printf("%-4d",cg.scores[i].client);
+
+ CG_Printf(" %-5d",cg.scores[i].score);
+
+ CG_Printf(" %-4d",cg.scores[i].ping);
+
+ CG_Printf(" %s\n",cgs.clientinfo[cg.scores[i].client].name);
+ }
+}
+
+void CG_TargetCommand_f( void ) {
+ int targetNum;
+ char test[4];
+
+ targetNum = CG_CrosshairPlayer();
+ if (!targetNum ) {
+ return;
+ }
+
+ trap_Argv( 1, test, 4 );
+ trap_SendConsoleCommand( va( "gc %i %i", targetNum, atoi( test ) ) );
+}
+
+
+
+/*
+=================
+CG_SizeUp_f
+
+Keybinding command
+=================
+*/
+static void CG_SizeUp_f (void) {
+ trap_Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize.integer+10)));
+}
+
+
+/*
+=================
+CG_SizeDown_f
+
+Keybinding command
+=================
+*/
+static void CG_SizeDown_f (void) {
+ trap_Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize.integer-10)));
+}
+
+
+/*
+=============
+CG_Viewpos_f
+
+Debugging command to print the current position
+=============
+*/
+static void CG_Viewpos_f (void) {
+ CG_Printf ("(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0],
+ (int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2],
+ (int)cg.refdefViewAngles[YAW]);
+}
+
+
+static void CG_ScoresDown_f( void ) {
+
+#ifdef MISSIONPACK
+ CG_BuildSpectatorString();
+#endif
+ if ( cg.scoresRequestTime + 2000 < cg.time ) {
+ // the scores are more than two seconds out of data,
+ // so request new ones
+ cg.scoresRequestTime = cg.time;
+ trap_SendClientCommand( "score" );
+
+ // leave the current scores up if they were already
+ // displayed, but if this is the first hit, clear them out
+ if ( !cg.showScores ) {
+ cg.showScores = qtrue;
+ cg.numScores = 0;
+ }
+ } else {
+ // show the cached contents even if they just pressed if it
+ // is within two seconds
+ cg.showScores = qtrue;
+ }
+}
+
+static void CG_ScoresUp_f( void ) {
+ if ( cg.showScores ) {
+ cg.showScores = qfalse;
+ cg.scoreFadeTime = cg.time;
+ }
+}
+
+static void CG_AccDown_f( void ) {
+
+ if ( cg.accRequestTime + 2000 < cg.time ) {
+
+ cg.accRequestTime = cg.time;
+ trap_SendClientCommand( "acc" );
+
+ if ( !cg.showAcc ) {
+ cg.showAcc = qtrue;
+ }
+
+ } else {
+ cg.showAcc = qtrue;
+ }
+}
+
+
+static void CG_AccUp_f( void ) {
+ if ( cg.showAcc ) {
+ cg.showAcc = qfalse;
+ cg.accFadeTime = cg.time;
+ }
+}
+
+
+#ifdef MISSIONPACK
+extern menuDef_t *menuScoreboard;
+void Menu_Reset( void ); // FIXME: add to right include file
+
+static void CG_LoadHud_f( void) {
+ char buff[1024];
+ const char *hudSet;
+ memset(buff, 0, sizeof(buff));
+
+ String_Init();
+ Menu_Reset();
+
+ trap_Cvar_VariableStringBuffer("cg_hudFiles", buff, sizeof(buff));
+ hudSet = buff;
+ if (hudSet[0] == '\0') {
+ hudSet = "ui/hud.txt";
+ }
+
+ CG_LoadMenus(hudSet);
+ menuScoreboard = NULL;
+}
+
+
+static void CG_scrollScoresDown_f( void) {
+ if (menuScoreboard && cg.scoreBoardShowing) {
+ Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qtrue);
+ Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qtrue);
+ Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qtrue);
+ }
+}
+
+
+static void CG_scrollScoresUp_f( void) {
+ if (menuScoreboard && cg.scoreBoardShowing) {
+ Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qfalse);
+ Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qfalse);
+ Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qfalse);
+ }
+}
+
+
+static void CG_spWin_f( void) {
+ trap_Cvar_Set("cg_cameraOrbit", "2");
+ trap_Cvar_Set("cg_cameraOrbitDelay", "35");
+ trap_Cvar_Set("cg_thirdPerson", "1");
+ trap_Cvar_Set("cg_thirdPersonAngle", "0");
+ trap_Cvar_Set("cg_thirdPersonRange", "100");
+ CG_AddBufferedSound(cgs.media.winnerSound);
+ //trap_S_StartLocalSound(cgs.media.winnerSound, CHAN_ANNOUNCER);
+ CG_CenterPrint("YOU WIN!", SCREEN_HEIGHT * .30, 0);
+}
+
+static void CG_spLose_f( void) {
+ trap_Cvar_Set("cg_cameraOrbit", "2");
+ trap_Cvar_Set("cg_cameraOrbitDelay", "35");
+ trap_Cvar_Set("cg_thirdPerson", "1");
+ trap_Cvar_Set("cg_thirdPersonAngle", "0");
+ trap_Cvar_Set("cg_thirdPersonRange", "100");
+ CG_AddBufferedSound(cgs.media.loserSound);
+ //trap_S_StartLocalSound(cgs.media.loserSound, CHAN_ANNOUNCER);
+ CG_CenterPrint("YOU LOSE...", SCREEN_HEIGHT * .30, 0);
+}
+
+#endif
+
+static void CG_TellTarget_f( void ) {
+ int clientNum;
+ char command[128];
+ char message[128];
+
+ clientNum = CG_CrosshairPlayer();
+ if ( clientNum == -1 ) {
+ return;
+ }
+
+ trap_Args( message, 128 );
+ Com_sprintf( command, 128, "tell %i %s", clientNum, message );
+ trap_SendClientCommand( command );
+}
+
+static void CG_TellAttacker_f( void ) {
+ int clientNum;
+ char command[128];
+ char message[128];
+
+ clientNum = CG_LastAttacker();
+ if ( clientNum == -1 ) {
+ return;
+ }
+
+ trap_Args( message, 128 );
+ Com_sprintf( command, 128, "tell %i %s", clientNum, message );
+ trap_SendClientCommand( command );
+}
+
+static void CG_VoiceTellTarget_f( void ) {
+ int clientNum;
+ char command[128];
+ char message[128];
+
+ clientNum = CG_CrosshairPlayer();
+ if ( clientNum == -1 ) {
+ return;
+ }
+
+ trap_Args( message, 128 );
+ Com_sprintf( command, 128, "vtell %i %s", clientNum, message );
+ trap_SendClientCommand( command );
+}
+
+static void CG_VoiceTellAttacker_f( void ) {
+ int clientNum;
+ char command[128];
+ char message[128];
+
+ clientNum = CG_LastAttacker();
+ if ( clientNum == -1 ) {
+ return;
+ }
+
+ trap_Args( message, 128 );
+ Com_sprintf( command, 128, "vtell %i %s", clientNum, message );
+ trap_SendClientCommand( command );
+}
+
+#ifdef MISSIONPACK
+static void CG_NextTeamMember_f( void ) {
+ CG_SelectNextPlayer();
+}
+
+static void CG_PrevTeamMember_f( void ) {
+ CG_SelectPrevPlayer();
+}
+
+// ASS U ME's enumeration order as far as task specific orders, OFFENSE is zero, CAMP is last
+//
+static void CG_NextOrder_f( void ) {
+ clientInfo_t *ci = cgs.clientinfo + cg.snap->ps.clientNum;
+ if (ci) {
+ if (!ci->teamLeader && sortedTeamPlayers[cg_currentSelectedPlayer.integer] != cg.snap->ps.clientNum) {
+ return;
+ }
+ }
+ if (cgs.currentOrder < TEAMTASK_CAMP) {
+ cgs.currentOrder++;
+
+ if (cgs.currentOrder == TEAMTASK_RETRIEVE) {
+ if (!CG_OtherTeamHasFlag()) {
+ cgs.currentOrder++;
+ }
+ }
+
+ if (cgs.currentOrder == TEAMTASK_ESCORT) {
+ if (!CG_YourTeamHasFlag()) {
+ cgs.currentOrder++;
+ }
+ }
+
+ } else {
+ cgs.currentOrder = TEAMTASK_OFFENSE;
+ }
+ cgs.orderPending = qtrue;
+ cgs.orderTime = cg.time + 3000;
+}
+
+
+static void CG_ConfirmOrder_f (void ) {
+ trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_YES));
+ trap_SendConsoleCommand("+button5; wait; -button5");
+ if (cg.time < cgs.acceptOrderTime) {
+ trap_SendClientCommand(va("teamtask %d\n", cgs.acceptTask));
+ cgs.acceptOrderTime = 0;
+ }
+}
+
+static void CG_DenyOrder_f (void ) {
+ trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_NO));
+ trap_SendConsoleCommand("+button6; wait; -button6");
+ if (cg.time < cgs.acceptOrderTime) {
+ cgs.acceptOrderTime = 0;
+ }
+}
+
+static void CG_TaskOffense_f (void ) {
+ if (cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION || cgs.gametype == GT_1FCTF) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONGETFLAG));
+ } else {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONOFFENSE));
+ }
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_OFFENSE));
+}
+
+static void CG_TaskDefense_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONDEFENSE));
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_DEFENSE));
+}
+
+static void CG_TaskPatrol_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONPATROL));
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_PATROL));
+}
+
+static void CG_TaskCamp_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONCAMPING));
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_CAMP));
+}
+
+static void CG_TaskFollow_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOW));
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_FOLLOW));
+}
+
+static void CG_TaskRetrieve_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONRETURNFLAG));
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_RETRIEVE));
+}
+
+static void CG_TaskEscort_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOWCARRIER));
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_ESCORT));
+}
+
+static void CG_TaskOwnFlag_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_IHAVEFLAG));
+}
+
+static void CG_TauntKillInsult_f (void ) {
+ trap_SendConsoleCommand("cmd vsay kill_insult\n");
+}
+
+static void CG_TauntPraise_f (void ) {
+ trap_SendConsoleCommand("cmd vsay praise\n");
+}
+
+static void CG_TauntTaunt_f (void ) {
+ trap_SendConsoleCommand("cmd vtaunt\n");
+}
+
+static void CG_TauntDeathInsult_f (void ) {
+ trap_SendConsoleCommand("cmd vsay death_insult\n");
+}
+
+static void CG_TauntGauntlet_f (void ) {
+ trap_SendConsoleCommand("cmd vsay kill_guantlet\n");
+}
+
+static void CG_TaskSuicide_f (void ) {
+ int clientNum;
+ char command[128];
+
+ clientNum = CG_CrosshairPlayer();
+ if ( clientNum == -1 ) {
+ return;
+ }
+
+ Com_sprintf( command, 128, "tell %i suicide", clientNum );
+ trap_SendClientCommand( command );
+}
+
+
+
+/*
+==================
+CG_TeamMenu_f
+==================
+*/
+/*
+static void CG_TeamMenu_f( void ) {
+ if (trap_Key_GetCatcher() & KEYCATCH_CGAME) {
+ CG_EventHandling(CGAME_EVENT_NONE);
+ trap_Key_SetCatcher(0);
+ } else {
+ CG_EventHandling(CGAME_EVENT_TEAMMENU);
+ //trap_Key_SetCatcher(KEYCATCH_CGAME);
+ }
+}
+*/
+
+/*
+==================
+CG_EditHud_f
+==================
+*/
+/*
+static void CG_EditHud_f( void ) {
+ //cls.keyCatchers ^= KEYCATCH_CGAME;
+ //VM_Call (cgvm, CG_EVENT_HANDLING, (cls.keyCatchers & KEYCATCH_CGAME) ? CGAME_EVENT_EDITHUD : CGAME_EVENT_NONE);
+}
+*/
+
+#endif
+
+/*
+==================
+CG_StartOrbit_f
+==================
+*/
+
+static void CG_StartOrbit_f( void ) {
+ char var[MAX_TOKEN_CHARS];
+
+ trap_Cvar_VariableStringBuffer( "developer", var, sizeof( var ) );
+ if ( !atoi(var) ) {
+ return;
+ }
+ if (cg_cameraOrbit.value != 0) {
+ trap_Cvar_Set ("cg_cameraOrbit", "0");
+ trap_Cvar_Set("cg_thirdPerson", "0");
+ } else {
+ trap_Cvar_Set("cg_cameraOrbit", "5");
+ trap_Cvar_Set("cg_thirdPerson", "1");
+ trap_Cvar_Set("cg_thirdPersonAngle", "0");
+ trap_Cvar_Set("cg_thirdPersonRange", "100");
+ }
+}
+
+/*
+static void CG_Camera_f( void ) {
+ char name[1024];
+ trap_Argv( 1, name, sizeof(name));
+ if (trap_loadCamera(name)) {
+ cg.cameraMode = qtrue;
+ trap_startCamera(cg.time);
+ } else {
+ CG_Printf ("Unable to load camera %s\n",name);
+ }
+}
+*/
+
+
+typedef struct {
+ char *cmd;
+ void (*function)(void);
+} consoleCommand_t;
+
+static consoleCommand_t commands[] = {
+ { "testgun", CG_TestGun_f },
+ { "testmodel", CG_TestModel_f },
+ { "nextframe", CG_TestModelNextFrame_f },
+ { "prevframe", CG_TestModelPrevFrame_f },
+ { "nextskin", CG_TestModelNextSkin_f },
+ { "prevskin", CG_TestModelPrevSkin_f },
+ { "viewpos", CG_Viewpos_f },
+ { "+scores", CG_ScoresDown_f },
+ { "-scores", CG_ScoresUp_f },
+ { "+zoom", CG_ZoomDown_f },
+ { "-zoom", CG_ZoomUp_f },
+ { "sizeup", CG_SizeUp_f },
+ { "sizedown", CG_SizeDown_f },
+ { "weapnext", CG_NextWeapon_f },
+ { "weapprev", CG_PrevWeapon_f },
+ { "weapon", CG_Weapon_f },
+ { "tell_target", CG_TellTarget_f },
+ { "tell_attacker", CG_TellAttacker_f },
+ { "vtell_target", CG_VoiceTellTarget_f },
+ { "vtell_attacker", CG_VoiceTellAttacker_f },
+ { "tcmd", CG_TargetCommand_f },
+#ifdef MISSIONPACK
+ { "loadhud", CG_LoadHud_f },
+ { "nextTeamMember", CG_NextTeamMember_f },
+ { "prevTeamMember", CG_PrevTeamMember_f },
+ { "nextOrder", CG_NextOrder_f },
+ { "confirmOrder", CG_ConfirmOrder_f },
+ { "denyOrder", CG_DenyOrder_f },
+ { "taskOffense", CG_TaskOffense_f },
+ { "taskDefense", CG_TaskDefense_f },
+ { "taskPatrol", CG_TaskPatrol_f },
+ { "taskCamp", CG_TaskCamp_f },
+ { "taskFollow", CG_TaskFollow_f },
+ { "taskRetrieve", CG_TaskRetrieve_f },
+ { "taskEscort", CG_TaskEscort_f },
+ { "taskSuicide", CG_TaskSuicide_f },
+ { "taskOwnFlag", CG_TaskOwnFlag_f },
+ { "tauntKillInsult", CG_TauntKillInsult_f },
+ { "tauntPraise", CG_TauntPraise_f },
+ { "tauntTaunt", CG_TauntTaunt_f },
+ { "tauntDeathInsult", CG_TauntDeathInsult_f },
+ { "tauntGauntlet", CG_TauntGauntlet_f },
+ { "spWin", CG_spWin_f },
+ { "spLose", CG_spLose_f },
+ { "scoresDown", CG_scrollScoresDown_f },
+ { "scoresUp", CG_scrollScoresUp_f },
+#endif
+ { "startOrbit", CG_StartOrbit_f },
+// { "camera", CG_Camera_f },
+ { "loaddeferred", CG_LoadDeferredPlayers },
+ { "+acc", CG_AccDown_f },
+ { "-acc", CG_AccUp_f },
+ { "clients", CG_PrintClientNumbers }
+};
+
+
+/*
+=================
+CG_ConsoleCommand
+
+The string has been tokenized and can be retrieved with
+Cmd_Argc() / Cmd_Argv()
+=================
+*/
+qboolean CG_ConsoleCommand( void ) {
+ const char *cmd;
+ int i;
+
+ cmd = CG_Argv(0);
+
+ for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
+ if ( !Q_stricmp( cmd, commands[i].cmd ) ) {
+ commands[i].function();
+ return qtrue;
+ }
+ }
+
+ return qfalse;
+}
+
+
+/*
+=================
+CG_InitConsoleCommands
+
+Let the client system know about all of our commands
+so it can perform tab completion
+=================
+*/
+void CG_InitConsoleCommands( void ) {
+ int i;
+
+ for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
+ trap_AddCommand( commands[i].cmd );
+ }
+
+ //
+ // the game server will interpret these commands, which will be automatically
+ // forwarded to the server after they are not recognized locally
+ //
+ trap_AddCommand ("kill");
+ trap_AddCommand ("say");
+ trap_AddCommand ("say_team");
+ trap_AddCommand ("tell");
+ trap_AddCommand ("vsay");
+ trap_AddCommand ("vsay_team");
+ trap_AddCommand ("vtell");
+ trap_AddCommand ("vtaunt");
+ trap_AddCommand ("vosay");
+ trap_AddCommand ("vosay_team");
+ trap_AddCommand ("votell");
+ trap_AddCommand ("give");
+ trap_AddCommand ("god");
+ trap_AddCommand ("notarget");
+ trap_AddCommand ("noclip");
+ trap_AddCommand ("team");
+ trap_AddCommand ("follow");
+ trap_AddCommand ("levelshot");
+ trap_AddCommand ("addbot");
+ trap_AddCommand ("setviewpos");
+ trap_AddCommand ("callvote");
+ trap_AddCommand ("getmappage");
+ trap_AddCommand ("vote");
+ trap_AddCommand ("callteamvote");
+ trap_AddCommand ("teamvote");
+ trap_AddCommand ("stats");
+ trap_AddCommand ("teamtask");
+ trap_AddCommand ("loaddefered"); // spelled wrong, but not changing for demo
+}
diff --git a/code/cgame/cg_draw.c b/code/cgame/cg_draw.c
new file mode 100644
index 0000000..391e458
--- /dev/null
+++ b/code/cgame/cg_draw.c
@@ -0,0 +1,3408 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_draw.c -- draw all of the graphical elements during
+// active (after loading) gameplay
+
+#include "cg_local.h"
+
+#ifdef MISSIONPACK
+#include "../ui/ui_shared.h"
+
+// used for scoreboard
+extern displayContextDef_t cgDC;
+menuDef_t *menuScoreboard = NULL;
+#else
+int drawTeamOverlayModificationCount = -1;
+#endif
+
+int sortedTeamPlayers[TEAM_MAXOVERLAY];
+int numSortedTeamPlayers;
+
+char systemChat[256];
+char teamChat1[256];
+char teamChat2[256];
+
+#ifdef MISSIONPACK
+
+int CG_Text_Width(const char *text, float scale, int limit) {
+ int count,len;
+ float out;
+ glyphInfo_t *glyph;
+ float useScale;
+// FIXME: see ui_main.c, same problem
+// const unsigned char *s = text;
+ const char *s = text;
+ fontInfo_t *font = &cgDC.Assets.textFont;
+ if (scale <= cg_smallFont.value) {
+ font = &cgDC.Assets.smallFont;
+ } else if (scale > cg_bigFont.value) {
+ font = &cgDC.Assets.bigFont;
+ }
+ useScale = scale * font->glyphScale;
+ out = 0;
+ if (text) {
+ len = strlen(text);
+ if (limit > 0 && len > limit) {
+ len = limit;
+ }
+ count = 0;
+ while (s && *s && count < len) {
+ if ( Q_IsColorString(s) ) {
+ s += 2;
+ continue;
+ } else {
+ glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
+ out += glyph->xSkip;
+ s++;
+ count++;
+ }
+ }
+ }
+ return out * useScale;
+}
+
+int CG_Text_Height(const char *text, float scale, int limit) {
+ int len, count;
+ float max;
+ glyphInfo_t *glyph;
+ float useScale;
+// TTimo: FIXME
+// const unsigned char *s = text;
+ const char *s = text;
+ fontInfo_t *font = &cgDC.Assets.textFont;
+ if (scale <= cg_smallFont.value) {
+ font = &cgDC.Assets.smallFont;
+ } else if (scale > cg_bigFont.value) {
+ font = &cgDC.Assets.bigFont;
+ }
+ useScale = scale * font->glyphScale;
+ max = 0;
+ if (text) {
+ len = strlen(text);
+ if (limit > 0 && len > limit) {
+ len = limit;
+ }
+ count = 0;
+ while (s && *s && count < len) {
+ if ( Q_IsColorString(s) ) {
+ s += 2;
+ continue;
+ } else {
+ glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
+ if (max < glyph->height) {
+ max = glyph->height;
+ }
+ s++;
+ count++;
+ }
+ }
+ }
+ return max * useScale;
+}
+
+void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
+ float w, h;
+ w = width * scale;
+ h = height * scale;
+ CG_AdjustFrom640( &x, &y, &w, &h );
+ trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
+}
+
+void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
+ int len, count;
+ vec4_t newColor;
+ glyphInfo_t *glyph;
+ float useScale;
+ fontInfo_t *font = &cgDC.Assets.textFont;
+ if (scale <= cg_smallFont.value) {
+ font = &cgDC.Assets.smallFont;
+ } else if (scale > cg_bigFont.value) {
+ font = &cgDC.Assets.bigFont;
+ }
+ useScale = scale * font->glyphScale;
+ if (text) {
+// TTimo: FIXME
+// const unsigned char *s = text;
+ const char *s = text;
+ trap_R_SetColor( color );
+ memcpy(&newColor[0], &color[0], sizeof(vec4_t));
+ len = strlen(text);
+ if (limit > 0 && len > limit) {
+ len = limit;
+ }
+ count = 0;
+ while (s && *s && count < len) {
+ glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
+ //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
+ //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
+ if ( Q_IsColorString( s ) ) {
+ memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
+ newColor[3] = color[3];
+ trap_R_SetColor( newColor );
+ s += 2;
+ continue;
+ } else {
+ float yadj = useScale * glyph->top;
+ if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
+ int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
+ colorBlack[3] = newColor[3];
+ trap_R_SetColor( colorBlack );
+ CG_Text_PaintChar(x + ofs, y - yadj + ofs,
+ glyph->imageWidth,
+ glyph->imageHeight,
+ useScale,
+ glyph->s,
+ glyph->t,
+ glyph->s2,
+ glyph->t2,
+ glyph->glyph);
+ colorBlack[3] = 1.0;
+ trap_R_SetColor( newColor );
+ }
+ CG_Text_PaintChar(x, y - yadj,
+ glyph->imageWidth,
+ glyph->imageHeight,
+ useScale,
+ glyph->s,
+ glyph->t,
+ glyph->s2,
+ glyph->t2,
+ glyph->glyph);
+ // CG_DrawPic(x, y - yadj, scale * cgDC.Assets.textFont.glyphs[text[i]].imageWidth, scale * cgDC.Assets.textFont.glyphs[text[i]].imageHeight, cgDC.Assets.textFont.glyphs[text[i]].glyph);
+ x += (glyph->xSkip * useScale) + adjust;
+ s++;
+ count++;
+ }
+ }
+ trap_R_SetColor( NULL );
+ }
+}
+
+
+#endif
+
+/*
+==============
+CG_DrawField
+
+Draws large numbers for status bar and powerups
+==============
+*/
+#ifndef MISSIONPACK
+static void CG_DrawField (int x, int y, int width, int value) {
+ char num[16], *ptr;
+ int l;
+ int frame;
+
+ if ( width < 1 ) {
+ return;
+ }
+
+ // draw number string
+ if ( width > 5 ) {
+ width = 5;
+ }
+
+ switch ( width ) {
+ case 1:
+ value = value > 9 ? 9 : value;
+ value = value < 0 ? 0 : value;
+ break;
+ case 2:
+ value = value > 99 ? 99 : value;
+ value = value < -9 ? -9 : value;
+ break;
+ case 3:
+ value = value > 999 ? 999 : value;
+ value = value < -99 ? -99 : value;
+ break;
+ case 4:
+ value = value > 9999 ? 9999 : value;
+ value = value < -999 ? -999 : value;
+ break;
+ }
+
+ Com_sprintf (num, sizeof(num), "%i", value);
+ l = strlen(num);
+ if (l > width)
+ l = width;
+ x += 2 + CHAR_WIDTH*(width - l);
+
+ ptr = num;
+ while (*ptr && l)
+ {
+ if (*ptr == '-')
+ frame = STAT_MINUS;
+ else
+ frame = *ptr -'0';
+
+ CG_DrawPic( x,y, CHAR_WIDTH, CHAR_HEIGHT, cgs.media.numberShaders[frame] );
+ x += CHAR_WIDTH;
+ ptr++;
+ l--;
+ }
+}
+#endif // MISSIONPACK
+
+/*
+================
+CG_Draw3DModel
+
+================
+*/
+void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles ) {
+ refdef_t refdef;
+ refEntity_t ent;
+
+ if ( !cg_draw3dIcons.integer || !cg_drawIcons.integer ) {
+ return;
+ }
+
+ CG_AdjustFrom640( &x, &y, &w, &h );
+
+ memset( &refdef, 0, sizeof( refdef ) );
+
+ memset( &ent, 0, sizeof( ent ) );
+ AnglesToAxis( angles, ent.axis );
+ VectorCopy( origin, ent.origin );
+ ent.hModel = model;
+ ent.customSkin = skin;
+ ent.renderfx = RF_NOSHADOW; // no stencil shadows
+
+ refdef.rdflags = RDF_NOWORLDMODEL;
+
+ AxisClear( refdef.viewaxis );
+
+ refdef.fov_x = 30;
+ refdef.fov_y = 30;
+
+ refdef.x = x;
+ refdef.y = y;
+ refdef.width = w;
+ refdef.height = h;
+
+ refdef.time = cg.time;
+
+ trap_R_ClearScene();
+ trap_R_AddRefEntityToScene( &ent );
+ trap_R_RenderScene( &refdef );
+}
+
+/*
+================
+CG_DrawHead
+
+Used for both the status bar and the scoreboard
+================
+*/
+void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles ) {
+ clipHandle_t cm;
+ clientInfo_t *ci;
+ float len;
+ vec3_t origin;
+ vec3_t mins, maxs;
+
+ ci = &cgs.clientinfo[ clientNum ];
+
+ if ( cg_draw3dIcons.integer ) {
+ cm = ci->headModel;
+ if ( !cm ) {
+ return;
+ }
+
+ // offset the origin y and z to center the head
+ trap_R_ModelBounds( cm, mins, maxs );
+
+ origin[2] = -0.5 * ( mins[2] + maxs[2] );
+ origin[1] = 0.5 * ( mins[1] + maxs[1] );
+
+ // calculate distance so the head nearly fills the box
+ // assume heads are taller than wide
+ len = 0.7 * ( maxs[2] - mins[2] );
+ origin[0] = len / 0.268; // len / tan( fov/2 )
+
+ // allow per-model tweaking
+ VectorAdd( origin, ci->headOffset, origin );
+
+ CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, origin, headAngles );
+ } else if ( cg_drawIcons.integer ) {
+ CG_DrawPic( x, y, w, h, ci->modelIcon );
+ }
+
+ // if they are deferred, draw a cross out
+ if ( ci->deferred ) {
+ CG_DrawPic( x, y, w, h, cgs.media.deferShader );
+ }
+}
+
+/*
+================
+CG_DrawFlagModel
+
+Used for both the status bar and the scoreboard
+================
+*/
+void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D ) {
+ qhandle_t cm;
+ float len;
+ vec3_t origin, angles;
+ vec3_t mins, maxs;
+ qhandle_t handle;
+
+ if ( !force2D && cg_draw3dIcons.integer ) {
+
+ VectorClear( angles );
+
+ cm = cgs.media.redFlagModel;
+
+ // offset the origin y and z to center the flag
+ trap_R_ModelBounds( cm, mins, maxs );
+
+ origin[2] = -0.5 * ( mins[2] + maxs[2] );
+ origin[1] = 0.5 * ( mins[1] + maxs[1] );
+
+ // calculate distance so the flag nearly fills the box
+ // assume heads are taller than wide
+ len = 0.5 * ( maxs[2] - mins[2] );
+ origin[0] = len / 0.268; // len / tan( fov/2 )
+
+ angles[YAW] = 60 * sin( cg.time / 2000.0 );;
+
+ if( team == TEAM_RED ) {
+ handle = cgs.media.redFlagModel;
+ if(cgs.gametype == GT_DOUBLE_D){
+ if(cgs.redflag == TEAM_BLUE)
+ handle = cgs.media.blueFlagModel;
+ if(cgs.redflag == TEAM_FREE)
+ handle = cgs.media.neutralFlagModel;
+ if(cgs.redflag == TEAM_NONE)
+ handle = cgs.media.neutralFlagModel;
+ }
+ } else if( team == TEAM_BLUE ) {
+ handle = cgs.media.blueFlagModel;
+ if(cgs.gametype == GT_DOUBLE_D){
+ if(cgs.redflag == TEAM_BLUE)
+ handle = cgs.media.blueFlagModel;
+ if(cgs.redflag == TEAM_FREE)
+ handle = cgs.media.neutralFlagModel;
+ if(cgs.redflag == TEAM_NONE)
+ handle = cgs.media.neutralFlagModel;
+ }
+ } else if( team == TEAM_FREE ) {
+ handle = cgs.media.neutralFlagModel;
+ } else {
+ return;
+ }
+ CG_Draw3DModel( x, y, w, h, handle, 0, origin, angles );
+ } else if ( cg_drawIcons.integer ) {
+ gitem_t *item;
+
+ if( team == TEAM_RED ) {
+ item = BG_FindItemForPowerup( PW_REDFLAG );
+ } else if( team == TEAM_BLUE ) {
+ item = BG_FindItemForPowerup( PW_BLUEFLAG );
+ } else if( team == TEAM_FREE ) {
+ item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
+ } else {
+ return;
+ }
+ if (item) {
+ CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon );
+ }
+ }
+}
+
+/*
+================
+CG_DrawStatusBarHead
+
+================
+*/
+#ifndef MISSIONPACK
+
+static void CG_DrawStatusBarHead( float x ) {
+ vec3_t angles;
+ float size, stretch;
+ float frac;
+
+ VectorClear( angles );
+
+ if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) {
+ frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME;
+ size = ICON_SIZE * 1.25 * ( 1.5 - frac * 0.5 );
+
+ stretch = size - ICON_SIZE * 1.25;
+ // kick in the direction of damage
+ x -= stretch * 0.5 + cg.damageX * stretch * 0.5;
+
+ cg.headStartYaw = 180 + cg.damageX * 45;
+
+ cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
+ cg.headEndPitch = 5 * cos( crandom()*M_PI );
+
+ cg.headStartTime = cg.time;
+ cg.headEndTime = cg.time + 100 + random() * 2000;
+ } else {
+ if ( cg.time >= cg.headEndTime ) {
+ // select a new head angle
+ cg.headStartYaw = cg.headEndYaw;
+ cg.headStartPitch = cg.headEndPitch;
+ cg.headStartTime = cg.headEndTime;
+ cg.headEndTime = cg.time + 100 + random() * 2000;
+
+ cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
+ cg.headEndPitch = 5 * cos( crandom()*M_PI );
+ }
+
+ size = ICON_SIZE * 1.25;
+ }
+
+ // if the server was frozen for a while we may have a bad head start time
+ if ( cg.headStartTime > cg.time ) {
+ cg.headStartTime = cg.time;
+ }
+
+ frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime );
+ frac = frac * frac * ( 3 - 2 * frac );
+ angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac;
+ angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac;
+
+ CG_DrawHead( x, 480 - size, size, size,
+ cg.snap->ps.clientNum, angles );
+}
+#endif // MISSIONPACK
+
+/*
+================
+CG_DrawStatusBarFlag
+
+================
+*/
+#ifndef MISSIONPACK
+static void CG_DrawStatusBarFlag( float x, int team ) {
+ CG_DrawFlagModel( x, 480 - ICON_SIZE, ICON_SIZE, ICON_SIZE, team, qfalse );
+}
+#endif // MISSIONPACK
+
+/*
+================
+CG_DrawTeamBackground
+
+================
+*/
+void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team )
+{
+ vec4_t hcolor;
+
+ hcolor[3] = alpha;
+ if ( team == TEAM_RED ) {
+ hcolor[0] = 1;
+ hcolor[1] = 0;
+ hcolor[2] = 0;
+ } else if ( team == TEAM_BLUE ) {
+ hcolor[0] = 0;
+ hcolor[1] = 0;
+ hcolor[2] = 1;
+ } else {
+ return;
+ }
+ trap_R_SetColor( hcolor );
+ CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
+ trap_R_SetColor( NULL );
+}
+
+/*
+================
+CG_DrawStatusBar
+
+================
+*/
+#ifndef MISSIONPACK
+static void CG_DrawStatusBar( void ) {
+ int color;
+ centity_t *cent;
+ playerState_t *ps;
+ int value;
+ vec4_t hcolor;
+ vec3_t angles;
+ vec3_t origin;
+ qhandle_t handle;
+
+ static float colors[4][4] = {
+// { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} };
+ { 1.0f, 0.69f, 0.0f, 1.0f }, // normal
+ { 1.0f, 0.2f, 0.2f, 1.0f }, // low health
+ { 0.5f, 0.5f, 0.5f, 1.0f }, // weapon firing
+ { 1.0f, 1.0f, 1.0f, 1.0f } }; // health > 100
+
+ if ( cg_drawStatus.integer == 0 ) {
+ return;
+ }
+
+ // draw the team background
+ if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) //If not following anybody:
+ CG_DrawTeamBackground( 0, 420, 640, 60, 0.33f, cg.snap->ps.persistant[PERS_TEAM] );
+ else //Sago: If we follow find the teamcolor of the guy we follow. It might not be our own team!
+ CG_DrawTeamBackground( 0, 420, 640, 60, 0.33f, cgs.clientinfo[ cg.snap->ps.clientNum ].team );
+
+ cent = &cg_entities[cg.snap->ps.clientNum];
+ ps = &cg.snap->ps;
+
+ VectorClear( angles );
+
+ // draw any 3D icons first, so the changes back to 2D are minimized
+ if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) {
+ origin[0] = 70;
+ origin[1] = 0;
+ origin[2] = 0;
+ angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 );
+ CG_Draw3DModel( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
+ cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles );
+ }
+
+ CG_DrawStatusBarHead( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE );
+
+ if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) {
+ CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_RED );
+ } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) {
+ CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_BLUE );
+ } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) {
+ CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_FREE );
+ }
+
+ if ( ps->stats[ STAT_ARMOR ] ) {
+ origin[0] = 90;
+ origin[1] = 0;
+ origin[2] = -10;
+ angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
+ CG_Draw3DModel( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
+ cgs.media.armorModel, 0, origin, angles );
+ }
+
+ if( cgs.gametype == GT_HARVESTER ) {
+ origin[0] = 90;
+ origin[1] = 0;
+ origin[2] = -10;
+ angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
+ if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
+ handle = cgs.media.redCubeModel;
+ } else {
+ handle = cgs.media.blueCubeModel;
+ }
+ CG_Draw3DModel( 470 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, handle, 0, origin, angles );
+ }
+
+
+ //
+ // ammo
+ //
+ if ( cent->currentState.weapon ) {
+ value = ps->ammo[cent->currentState.weapon];
+ if ( value > -1 ) {
+ if ( cg.predictedPlayerState.weaponstate == WEAPON_FIRING
+ && cg.predictedPlayerState.weaponTime > 100 ) {
+ // draw as dark grey when reloading
+ color = 2; // dark grey
+ } else {
+ if ( value >= 0 ) {
+ color = 0; // green
+ } else {
+ color = 1; // red
+ }
+ }
+ trap_R_SetColor( colors[color] );
+
+ CG_DrawField (0, 432, 3, value);
+ trap_R_SetColor( NULL );
+
+ // if we didn't draw a 3D icon, draw a 2D icon for ammo
+ if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
+ qhandle_t icon;
+
+ icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon;
+ if ( icon ) {
+ CG_DrawPic( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, icon );
+ }
+ }
+ }
+ }
+
+ //
+ // health
+ //
+ value = ps->stats[STAT_HEALTH];
+ if ( value > 100 ) {
+ trap_R_SetColor( colors[3] ); // white
+ } else if (value > 25) {
+ trap_R_SetColor( colors[0] ); // green
+ } else if (value > 0) {
+ color = (cg.time >> 8) & 1; // flash
+ trap_R_SetColor( colors[color] );
+ } else {
+ trap_R_SetColor( colors[1] ); // red
+ }
+
+ // stretch the health up when taking damage
+ CG_DrawField ( 185, 432, 3, value);
+ CG_ColorForHealth( hcolor );
+ trap_R_SetColor( hcolor );
+
+
+ //
+ // armor
+ //
+ value = ps->stats[STAT_ARMOR];
+ if (value > 0 ) {
+ trap_R_SetColor( colors[0] );
+ CG_DrawField (370, 432, 3, value);
+ trap_R_SetColor( NULL );
+ // if we didn't draw a 3D icon, draw a 2D icon for armor
+ if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
+ CG_DrawPic( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, cgs.media.armorIcon );
+ }
+
+ }
+
+ //Skulls!
+ if(cgs.gametype == GT_HARVESTER)
+ {
+ value = ps->generic1;
+ if (value > 0 ) {
+ trap_R_SetColor( colors[0] );
+ CG_DrawField (470, 432, 3, value);
+ trap_R_SetColor( NULL );
+ // if we didn't draw a 3D icon, draw a 2D icon for skull
+ if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
+ if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
+ handle = cgs.media.redCubeIcon;
+ } else {
+ handle = cgs.media.blueCubeIcon;
+ }
+ CG_DrawPic( 470 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, handle );
+ }
+
+ }
+ }
+}
+#endif
+
+/*
+===========================================================================================
+
+ UPPER RIGHT CORNER
+
+===========================================================================================
+*/
+
+/*
+================
+CG_DrawAttacker
+
+================
+*/
+static float CG_DrawAttacker( float y ) {
+ int t;
+ float size;
+ vec3_t angles;
+ const char *info;
+ const char *name;
+ int clientNum;
+
+ if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
+ return y;
+ }
+
+ if ( !cg.attackerTime ) {
+ return y;
+ }
+
+ clientNum = cg.predictedPlayerState.persistant[PERS_ATTACKER];
+ if ( clientNum < 0 || clientNum >= MAX_CLIENTS || clientNum == cg.snap->ps.clientNum ) {
+ return y;
+ }
+
+ t = cg.time - cg.attackerTime;
+ if ( t > ATTACKER_HEAD_TIME ) {
+ cg.attackerTime = 0;
+ return y;
+ }
+
+ size = ICON_SIZE * 1.25;
+
+ angles[PITCH] = 0;
+ angles[YAW] = 180;
+ angles[ROLL] = 0;
+ CG_DrawHead( 640 - size, y, size, size, clientNum, angles );
+
+ info = CG_ConfigString( CS_PLAYERS + clientNum );
+ name = Info_ValueForKey( info, "n" );
+ y += size;
+ CG_DrawBigString( 640 - ( Q_PrintStrlen( name ) * BIGCHAR_WIDTH), y, name, 0.5 );
+
+ return y + BIGCHAR_HEIGHT + 2;
+}
+
+/*
+================
+CG_DrawSpeedMeter
+
+================
+*/
+static float CG_DrawSpeedMeter( float y ) {
+ char *s;
+ int w;
+ vec_t *vel;
+ int speed;
+
+ /* speed meter can get in the way of the scoreboard */
+ if ( cg.scoreBoardShowing ) {
+ return y;
+ }
+
+ vel = cg.snap->ps.velocity;
+ /* ignore vertical component of velocity */
+ speed = sqrt(vel[0] * vel[0] + vel[1] * vel[1]);
+
+ s = va( "%iu/s", speed );
+
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+
+ if (cg_drawSpeed.integer == 1) {
+ /* top left-hand corner of screen */
+ CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
+ return y + BIGCHAR_HEIGHT + 4;
+ } else {
+ /* center of screen */
+ CG_DrawBigString( 320 - w / 2, 300, s, 1.0F);
+ return y;
+ }
+}
+
+/*
+==================
+CG_DrawSnapshot
+==================
+*/
+static float CG_DrawSnapshot( float y ) {
+ char *s;
+ int w;
+
+ s = va( "time:%i snap:%i cmd:%i", cg.snap->serverTime,
+ cg.latestSnapshotNum, cgs.serverCommandSequence );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+
+ CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
+
+ return y + BIGCHAR_HEIGHT + 4;
+}
+
+/*
+==================
+CG_DrawFPS
+==================
+*/
+#define FPS_FRAMES 4
+static float CG_DrawFPS( float y ) {
+ char *s;
+ int w;
+ static int previousTimes[FPS_FRAMES];
+ static int index;
+ int i, total;
+ int fps;
+ static int previous;
+ int t, frameTime;
+
+ // don't use serverTime, because that will be drifting to
+ // correct for internet lag changes, timescales, timedemos, etc
+ t = trap_Milliseconds();
+ frameTime = t - previous;
+ previous = t;
+
+ previousTimes[index % FPS_FRAMES] = frameTime;
+ index++;
+ if ( index > FPS_FRAMES ) {
+ // average multiple frames together to smooth changes out a bit
+ total = 0;
+ for ( i = 0 ; i < FPS_FRAMES ; i++ ) {
+ total += previousTimes[i];
+ }
+ if ( !total ) {
+ total = 1;
+ }
+ fps = 1000 * FPS_FRAMES / total;
+
+ s = va( "%ifps", fps );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+
+ CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
+ }
+
+ return y + BIGCHAR_HEIGHT + 4;
+}
+
+/*
+=================
+CG_DrawTimer
+=================
+*/
+static float CG_DrawTimer( float y ) {
+ char *s;
+ int w;
+ int mins, seconds, tens;
+ int msec;
+
+ msec = cg.time - cgs.levelStartTime;
+
+ seconds = msec / 1000;
+ mins = seconds / 60;
+ seconds -= mins * 60;
+ tens = seconds / 10;
+ seconds -= tens * 10;
+
+ s = va( "%i:%i%i", mins, tens, seconds );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+
+ CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
+
+ return y + BIGCHAR_HEIGHT + 4;
+}
+
+/*
+CG_DrawDoubleDominationThings
+ *
+ *Sago: Might be relevant for debugging missionpack.
+*/
+
+/*static float CG_DrawDoubleDominationThings( float y ) {
+ char *s;
+ int w;
+ int statusA, statusB;
+ statusA = cgs.redflag;
+ statusB = cgs.blueflag;
+
+ if(statusA == TEAM_NONE) {
+ s = va("Point A not spawned");
+ } else
+ if(statusA == TEAM_FREE) {
+ s = va("Point A is not controlled");
+ } else
+ if(statusA == TEAM_RED) {
+ s = va("Point A is controlled by RED");
+ } else
+ if(statusA == TEAM_BLUE) {
+ s = va("Point A is controlled by BLUE");
+ } else
+ s = va("Point A has an error");
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallString( 635 - w, y + 2, s, 1.0F);
+ y+=SMALLCHAR_HEIGHT+4;
+
+ if(statusB == TEAM_NONE) {
+ s = va("Point B not spawned");
+ } else
+ if(statusB == TEAM_FREE) {
+ s = va("Point B is not controlled");
+ } else
+ if(statusB == TEAM_RED) {
+ s = va("Point B is controlled by RED");
+ } else
+ if(statusB == TEAM_BLUE) {
+ s = va("Point B is controlled by BLUE");
+ } else
+ s = va("Point B has an error");
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallString( 635 - w, y + 2, s, 1.0F);
+
+ if( ( ( statusB == statusA ) && ( statusA == TEAM_RED ) ) ||
+ ( ( statusB == statusA ) && ( statusA == TEAM_BLUE ) ) ) {
+ s = va("Capture in: %i",(cgs.timetaken+10*1000-cg.time)/1000+1);
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ y+=SMALLCHAR_HEIGHT+4;
+ CG_DrawSmallString( 635 - w, y + 2, s, 1.0F);
+ }
+
+ return y + SMALLCHAR_HEIGHT+4;
+}*/
+
+/*
+=================
+CG_DrawLMSmode
+=================
+*/
+
+static float CG_DrawLMSmode( float y ) {
+ char *s;
+ int w;
+
+ if(cgs.lms_mode == 0) {
+ s = va("LMS: Point/round + OT");
+ } else
+ if(cgs.lms_mode == 1) {
+ s = va("LMS: Point/round - OT");
+ } else
+ if(cgs.lms_mode == 2) {
+ s = va("LMS: Point/kill + OT");
+ } else
+ if(cgs.lms_mode == 3) {
+ s = va("LMS: Point/kill - OT");
+ } else
+ s = va("LMS: Unknown mode");
+
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallString( 635 - w, y + 2, s, 1.0F);
+
+ return y + SMALLCHAR_HEIGHT+4;
+}
+
+/*
+=================
+CG_DrawCTFoneway
+=================
+*/
+
+static float CG_DrawCTFoneway( float y ) {
+ char *s;
+ int w;
+ vec4_t color;
+
+ if(cgs.gametype != GT_CTF_ELIMINATION)
+ return y;
+
+ memcpy(color,g_color_table[ColorIndex(COLOR_WHITE)],sizeof(color));
+
+ if( (cgs.elimflags&EF_ONEWAY)==0) {
+ return y; //nothing to draw
+ } else
+ if(cgs.attackingTeam == TEAM_BLUE) {
+ memcpy(color,g_color_table[ColorIndex(COLOR_BLUE)],sizeof(color));
+ s = va("Blue team on offence");
+ } else
+ if(cgs.attackingTeam == TEAM_RED) {
+ memcpy(color,g_color_table[ColorIndex(COLOR_RED)],sizeof(color));
+ s = va("Red team on offence");
+ } else
+ s = va("Unknown team on offence");
+
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallStringColor( 635 - w, y + 2, s, color);
+
+ return y + SMALLCHAR_HEIGHT+4;
+}
+
+/*
+=================
+CG_DrawEliminationDeathMessage
+=================
+*/
+
+/*static float CG_DrawEliminationDeathMessage( float y ) {
+ char *s;
+ int w;
+
+ s = va("You are waiting for a new round");
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallString( 635 - w, y + 2, s, 1.0F);
+
+ return y + SMALLCHAR_HEIGHT+4;
+}*/
+
+/*
+=================
+CG_DrawDomStatus
+=================
+*/
+
+static float CG_DrawDomStatus( float y ) {
+ int i,w;
+ char *s;
+ vec4_t color;
+
+ for(i = 0;i < cgs.domination_points_count;i++) {
+ switch(cgs.domination_points_status[i]) {
+ case TEAM_RED:
+ memcpy(color,g_color_table[ColorIndex(COLOR_RED)],sizeof(color));
+ break;
+ case TEAM_BLUE:
+ memcpy(color,g_color_table[ColorIndex(COLOR_BLUE)],sizeof(color));
+ break;
+ default:
+ memcpy(color,g_color_table[ColorIndex(COLOR_WHITE)],sizeof(color));
+ break;
+ }
+
+ s = va("%s",cgs.domination_points_names[i]);
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallStringColor( 635 - w, y + 2, s, color);
+ y += SMALLCHAR_HEIGHT+4;
+
+ }
+
+ return y;
+}
+
+
+/*
+=================
+CG_DrawEliminationTimer
+=================
+*/
+static float CG_DrawEliminationTimer( float y ) {
+ char *s;
+ int w;
+ int mins, seconds, tens, sec;
+ int msec;
+ vec4_t color;
+ const char *st;
+ float scale;
+ int cw;
+ int rst;
+
+
+
+ rst = cgs.roundStartTime;
+
+ if(cg.time>rst && !cgs.roundtime) {
+ return y;
+ }
+
+ //default color is white
+ memcpy(color,g_color_table[ColorIndex(COLOR_WHITE)],sizeof(color));
+
+ //msec = cg.time - cgs.levelStartTime;
+ if(cg.time>rst) //We are started
+ {
+ msec = cgs.roundtime*1000 - (cg.time -rst);
+ if(msec<=30*1000-1) //<= 30 seconds
+ memcpy(color,g_color_table[ColorIndex(COLOR_YELLOW)],sizeof(color));
+ if(msec<=10*1000-1) //<= 10 seconds
+ memcpy(color,g_color_table[ColorIndex(COLOR_RED)],sizeof(color));
+ msec += 1000; //120-1 instead of 119-0
+ }
+ else
+ {
+ //Warmup
+ msec = -cg.time +rst;
+ memcpy(color,g_color_table[ColorIndex(COLOR_GREEN)],sizeof(color));
+ sec = msec/1000;
+ msec += 1000; //5-1 instead of 4-0
+/***
+Lots of stuff
+****/
+ if(cg.warmup == 0)
+ {
+ st = va( "Round in: %i", sec + 1 );
+ if ( sec != cg.warmupCount ) {
+ cg.warmupCount = sec;
+ switch ( sec ) {
+ case 0:
+ trap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER );
+ break;
+ case 1:
+ trap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER );
+ break;
+ case 2:
+ trap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER );
+ break;
+ default:
+ break;
+ }
+ }
+ scale = 0.45f;
+ switch ( cg.warmupCount ) {
+ case 0:
+ cw = 28;
+ scale = 0.54f;
+ break;
+ case 1:
+ cw = 24;
+ scale = 0.51f;
+ break;
+ case 2:
+ cw = 20;
+ scale = 0.48f;
+ break;
+ default:
+ cw = 16;
+ scale = 0.45f;
+ break;
+ }
+
+ #ifdef MISSIONPACK
+ //w = CG_Text_Width(s, scale, 0);
+ //CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, st, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
+ #else
+
+ w = CG_DrawStrlen( st );
+ CG_DrawStringExt( 320 - w * cw/2, 70, st, colorWhite,
+ qfalse, qtrue, cw, (int)(cw * 1.5), 0 );
+ #endif
+ }
+/*
+Lots of stuff
+*/
+ }
+
+ seconds = msec / 1000;
+ mins = seconds / 60;
+ seconds -= mins * 60;
+ tens = seconds / 10;
+ seconds -= tens * 10;
+
+ if(msec>=0)
+ s = va( " %i:%i%i", mins, tens, seconds );
+ else
+ s = va( " Overtime");
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+
+ CG_DrawBigStringColor( 635 - w, y + 2, s, color);
+
+ return y + BIGCHAR_HEIGHT + 4;
+}
+
+
+/*
+=================
+CG_DrawTeamOverlay
+=================
+*/
+
+static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) {
+ int x, w, h, xx;
+ int i, j, len;
+ const char *p;
+ vec4_t hcolor;
+ int pwidth, lwidth;
+ int plyrs;
+ char st[16];
+ clientInfo_t *ci;
+ gitem_t *item;
+ int ret_y, count;
+
+ if ( !cg_drawTeamOverlay.integer ) {
+ return y;
+ }
+
+ if ( cg.snap->ps.persistant[PERS_TEAM] != TEAM_RED && cg.snap->ps.persistant[PERS_TEAM] != TEAM_BLUE ) {
+ return y; // Not on any team
+ }
+
+ plyrs = 0;
+
+ // max player name width
+ pwidth = 0;
+ count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers;
+ for (i = 0; i < count; i++) {
+ ci = cgs.clientinfo + sortedTeamPlayers[i];
+ if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
+ plyrs++;
+ len = CG_DrawStrlen(ci->name);
+ if (len > pwidth)
+ pwidth = len;
+ }
+ }
+
+ if (!plyrs)
+ return y;
+
+ if (pwidth > TEAM_OVERLAY_MAXNAME_WIDTH)
+ pwidth = TEAM_OVERLAY_MAXNAME_WIDTH;
+
+ // max location name width
+ lwidth = 0;
+ for (i = 1; i < MAX_LOCATIONS; i++) {
+ p = CG_ConfigString(CS_LOCATIONS + i);
+ if (p && *p) {
+ len = CG_DrawStrlen(p);
+ if (len > lwidth)
+ lwidth = len;
+ }
+ }
+
+ if (lwidth > TEAM_OVERLAY_MAXLOCATION_WIDTH)
+ lwidth = TEAM_OVERLAY_MAXLOCATION_WIDTH;
+
+ w = (pwidth + lwidth + 4 + 7) * TINYCHAR_WIDTH;
+
+ if ( right )
+ x = 640 - w;
+ else
+ x = 0;
+
+ h = plyrs * TINYCHAR_HEIGHT;
+
+ if ( upper ) {
+ ret_y = y + h;
+ } else {
+ y -= h;
+ ret_y = y;
+ }
+
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
+ hcolor[0] = 1.0f;
+ hcolor[1] = 0.0f;
+ hcolor[2] = 0.0f;
+ hcolor[3] = 0.33f;
+ } else { // if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE )
+ hcolor[0] = 0.0f;
+ hcolor[1] = 0.0f;
+ hcolor[2] = 1.0f;
+ hcolor[3] = 0.33f;
+ }
+ trap_R_SetColor( hcolor );
+ CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
+ trap_R_SetColor( NULL );
+
+ for (i = 0; i < count; i++) {
+ ci = cgs.clientinfo + sortedTeamPlayers[i];
+ if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
+
+ hcolor[0] = hcolor[1] = hcolor[2] = hcolor[3] = 1.0;
+
+ xx = x + TINYCHAR_WIDTH;
+
+ CG_DrawStringExt( xx, y,
+ ci->name, hcolor, qfalse, qfalse,
+ TINYCHAR_WIDTH, TINYCHAR_HEIGHT, TEAM_OVERLAY_MAXNAME_WIDTH);
+
+ if (lwidth) {
+ p = CG_ConfigString(CS_LOCATIONS + ci->location);
+ if (!p || !*p)
+ p = "unknown";
+ len = CG_DrawStrlen(p);
+ if (len > lwidth)
+ len = lwidth;
+
+// xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth +
+// ((lwidth/2 - len/2) * TINYCHAR_WIDTH);
+ xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth;
+ CG_DrawStringExt( xx, y,
+ p, hcolor, qfalse, qfalse, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
+ TEAM_OVERLAY_MAXLOCATION_WIDTH);
+ }
+
+ CG_GetColorForHealth( ci->health, ci->armor, hcolor );
+
+ Com_sprintf (st, sizeof(st), "%3i %3i", ci->health, ci->armor);
+
+ xx = x + TINYCHAR_WIDTH * 3 +
+ TINYCHAR_WIDTH * pwidth + TINYCHAR_WIDTH * lwidth;
+
+ CG_DrawStringExt( xx, y,
+ st, hcolor, qfalse, qfalse,
+ TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
+
+ // draw weapon icon
+ xx += TINYCHAR_WIDTH * 3;
+
+ if ( cg_weapons[ci->curWeapon].weaponIcon ) {
+ CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
+ cg_weapons[ci->curWeapon].weaponIcon );
+ } else {
+ CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
+ cgs.media.deferShader );
+ }
+
+ // Draw powerup icons
+ if (right) {
+ xx = x;
+ } else {
+ xx = x + w - TINYCHAR_WIDTH;
+ }
+ for (j = 0; j <= PW_NUM_POWERUPS; j++) {
+ if (ci->powerups & (1 << j)) {
+
+ item = BG_FindItemForPowerup( j );
+
+ if (item) {
+ CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
+ trap_R_RegisterShader( item->icon ) );
+ if (right) {
+ xx -= TINYCHAR_WIDTH;
+ } else {
+ xx += TINYCHAR_WIDTH;
+ }
+ }
+ }
+ }
+
+ y += TINYCHAR_HEIGHT;
+ }
+ }
+
+ return ret_y;
+//#endif
+}
+
+static float CG_DrawFollowMessage( float y ) {
+ char *s;
+ int w;
+
+ if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) || ( ( cgs.elimflags & EF_NO_FREESPEC ) && (cgs.gametype == GT_ELIMINATION || cgs.gametype == GT_CTF_ELIMINATION ) ) ) {
+ return y;
+ }
+
+ s = va("USE_ITEM to stop following");
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallString( 635 - w, y + 2, s, 1.0F);
+
+ return y + SMALLCHAR_HEIGHT+4;
+}
+
+
+/*
+=====================
+CG_DrawUpperRight
+
+=====================
+*/
+static void CG_DrawUpperRight(stereoFrame_t stereoFrame)
+{
+ float y;
+
+ y = 0;
+
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1 && cg_drawTeamOverlay.integer == 1 ) {
+ y = CG_DrawTeamOverlay( y, qtrue, qtrue );
+ }
+ /*if ( cgs.gametype == GT_DOUBLE_D ) {
+ y = CG_DrawDoubleDominationThings(y);
+ }
+ else*/
+ if ( cgs.gametype == GT_LMS && cg.showScores ) {
+ y = CG_DrawLMSmode(y);
+ }
+ else
+ if ( cgs.gametype == GT_CTF_ELIMINATION ) {
+ y = CG_DrawCTFoneway(y);
+ }
+ else
+ if ( cgs.gametype == GT_DOMINATION ) {
+ y = CG_DrawDomStatus(y);
+ }
+
+ if ( cg_drawSnapshot.integer ) {
+ y = CG_DrawSnapshot( y );
+ }
+ if (cg_drawFPS.integer && (stereoFrame == STEREO_CENTER || stereoFrame == STEREO_RIGHT)) {
+ y = CG_DrawFPS( y );
+ }
+ if (cgs.gametype==GT_ELIMINATION || cgs.gametype == GT_CTF_ELIMINATION || cgs.gametype==GT_LMS) {
+ y = CG_DrawEliminationTimer( y );
+ /*if (cgs.clientinfo[ cg.clientNum ].isDead)
+ y = CG_DrawEliminationDeathMessage( y);*/
+ }
+
+ y = CG_DrawFollowMessage( y );
+
+ if ( cg_drawTimer.integer) {
+ y = CG_DrawTimer( y );
+ }
+ if ( cg_drawAttacker.integer ) {
+ y = CG_DrawAttacker( y );
+ }
+ if ( cg_drawSpeed.integer ) {
+ y = CG_DrawSpeedMeter( y );
+ }
+
+}
+
+/*
+===========================================================================================
+
+ LOWER RIGHT CORNER
+
+===========================================================================================
+*/
+
+/*
+=================
+CG_DrawScores
+
+Draw the small two score display
+=================
+*/
+#ifndef MISSIONPACK
+static float CG_DrawScores( float y ) {
+ const char *s;
+ int s1, s2, score;
+ int x, w;
+ int v;
+ vec4_t color;
+ float y1;
+ gitem_t *item;
+ int statusA,statusB;
+
+ statusA = cgs.redflag;
+ statusB = cgs.blueflag;
+
+ s1 = cgs.scores1;
+ s2 = cgs.scores2;
+
+ y -= BIGCHAR_HEIGHT + 8;
+
+ y1 = y;
+
+ // draw from the right side to left
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ x = 640;
+ color[0] = 0.0f;
+ color[1] = 0.0f;
+ color[2] = 1.0f;
+ color[3] = 0.33f;
+ s = va( "%2i", s2 );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
+ x -= w;
+ CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
+ CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
+ }
+ CG_DrawBigString( x + 4, y, s, 1.0F);
+
+ if ( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION) {
+ // Display flag status
+ item = BG_FindItemForPowerup( PW_BLUEFLAG );
+
+ if (item) {
+ y1 = y - BIGCHAR_HEIGHT - 8;
+ if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) {
+ CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.blueFlagShader[cgs.blueflag] );
+ }
+ }
+ }
+
+ if ( cgs.gametype == GT_DOUBLE_D ) {
+ // Display Domination point status
+
+ y1 = y - 32;//BIGCHAR_HEIGHT - 8;
+ if( cgs.redflag >= 0 && cgs.redflag <= 3 ) {
+ CG_DrawPic( x, y1-4, w, 32, cgs.media.ddPointSkinB[cgs.blueflag] );
+ }
+ }
+
+ color[0] = 1.0f;
+ color[1] = 0.0f;
+ color[2] = 0.0f;
+ color[3] = 0.33f;
+ s = va( "%2i", s1 );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
+ x -= w;
+ CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
+ CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
+ }
+ CG_DrawBigString( x + 4, y, s, 1.0F);
+
+ if ( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION ) {
+ // Display flag status
+ item = BG_FindItemForPowerup( PW_REDFLAG );
+
+ if (item) {
+ y1 = y - BIGCHAR_HEIGHT - 8;
+ if( cgs.redflag >= 0 && cgs.redflag <= 2 ) {
+ CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.redFlagShader[cgs.redflag] );
+ }
+ }
+ }
+
+ if ( cgs.gametype == GT_DOUBLE_D ) {
+ // Display Domination point status
+
+ y1 = y - 32;//BIGCHAR_HEIGHT - 8;
+ if( cgs.redflag >= 0 && cgs.redflag <= 3 ) {
+ CG_DrawPic( x, y1-4, w, 32, cgs.media.ddPointSkinA[cgs.redflag] );
+ }
+
+
+
+ //Time till capture:
+ if( ( ( statusB == statusA ) && ( statusA == TEAM_RED ) ) ||
+ ( ( statusB == statusA ) && ( statusA == TEAM_BLUE ) ) ) {
+ s = va("%i",(cgs.timetaken+10*1000-cg.time)/1000+1);
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ CG_DrawBigString( x + 32+8-w/2, y-28, s, 1.0F);
+ }
+ }
+
+ if ( cgs.gametype == GT_OBELISK ) {
+ s = va("^1%3i%% ^4%3i%%",cg.redObeliskHealth,cg.blueObeliskHealth);
+ CG_DrawSmallString( x, y-28, s, 1.0F);
+ }
+
+
+
+ if ( cgs.gametype >= GT_CTF && cgs.ffa_gt==0) {
+ v = cgs.capturelimit;
+ } else {
+ v = cgs.fraglimit;
+ }
+ if ( v ) {
+ s = va( "%2i", v );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
+ x -= w;
+ CG_DrawBigString( x + 4, y, s, 1.0F);
+ }
+
+ } else {
+ qboolean spectator;
+
+ x = 640;
+ score = cg.snap->ps.persistant[PERS_SCORE];
+ spectator = ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR );
+
+ // always show your score in the second box if not in first place
+ if ( s1 != score ) {
+ s2 = score;
+ }
+ if ( s2 != SCORE_NOT_PRESENT ) {
+ s = va( "%2i", s2 );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
+ x -= w;
+ if ( !spectator && score == s2 && score != s1 ) {
+ color[0] = 1.0f;
+ color[1] = 0.0f;
+ color[2] = 0.0f;
+ color[3] = 0.33f;
+ CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
+ CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
+ } else {
+ color[0] = 0.5f;
+ color[1] = 0.5f;
+ color[2] = 0.5f;
+ color[3] = 0.33f;
+ CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
+ }
+ CG_DrawBigString( x + 4, y, s, 1.0F);
+ }
+
+ // first place
+ if ( s1 != SCORE_NOT_PRESENT ) {
+ s = va( "%2i", s1 );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
+ x -= w;
+ if ( !spectator && score == s1 ) {
+ color[0] = 0.0f;
+ color[1] = 0.0f;
+ color[2] = 1.0f;
+ color[3] = 0.33f;
+ CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
+ CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
+ } else {
+ color[0] = 0.5f;
+ color[1] = 0.5f;
+ color[2] = 0.5f;
+ color[3] = 0.33f;
+ CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
+ }
+ CG_DrawBigString( x + 4, y, s, 1.0F);
+ }
+
+ if ( cgs.fraglimit ) {
+ s = va( "%2i", cgs.fraglimit );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
+ x -= w;
+ CG_DrawBigString( x + 4, y, s, 1.0F);
+ }
+
+ }
+
+ return y1 - 8;
+}
+#endif // MISSIONPACK
+
+/*
+================
+CG_DrawPowerups
+================
+*/
+#ifndef MISSIONPACK
+static float CG_DrawPowerups( float y ) {
+ int sorted[MAX_POWERUPS];
+ int sortedTime[MAX_POWERUPS];
+ int i, j, k;
+ int active;
+ playerState_t *ps;
+ int t;
+ gitem_t *item;
+ int x;
+ int color;
+ float size;
+ float f;
+ static float colors[2][4] = {
+ { 0.2f, 1.0f, 0.2f, 1.0f } ,
+ { 1.0f, 0.2f, 0.2f, 1.0f }
+ };
+
+ ps = &cg.snap->ps;
+
+ if ( ps->stats[STAT_HEALTH] <= 0 ) {
+ return y;
+ }
+
+ // sort the list by time remaining
+ active = 0;
+ for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
+ if ( !ps->powerups[ i ] ) {
+ continue;
+ }
+ t = ps->powerups[ i ] - cg.time;
+ // ZOID--don't draw if the power up has unlimited time (999 seconds)
+ // This is true of the CTF flags
+ if ( t < 0 || t > 999000) {
+ continue;
+ }
+
+ item = BG_FindItemForPowerup( i );
+ if ( item && item->giType == IT_PERSISTANT_POWERUP)
+ continue; //Don't draw persistant powerups here!
+
+ // insert into the list
+ for ( j = 0 ; j < active ; j++ ) {
+ if ( sortedTime[j] >= t ) {
+ for ( k = active - 1 ; k >= j ; k-- ) {
+ sorted[k+1] = sorted[k];
+ sortedTime[k+1] = sortedTime[k];
+ }
+ break;
+ }
+ }
+ sorted[j] = i;
+ sortedTime[j] = t;
+ active++;
+ }
+
+ // draw the icons and timers
+ x = 640 - ICON_SIZE - CHAR_WIDTH * 2;
+ for ( i = 0 ; i < active ; i++ ) {
+ item = BG_FindItemForPowerup( sorted[i] );
+
+ if (item) {
+
+ color = 1;
+
+ y -= ICON_SIZE;
+
+ trap_R_SetColor( colors[color] );
+ CG_DrawField( x, y, 2, sortedTime[ i ] / 1000 );
+
+ t = ps->powerups[ sorted[i] ];
+ if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
+ trap_R_SetColor( NULL );
+ } else {
+ vec4_t modulate;
+
+ f = (float)( t - cg.time ) / POWERUP_BLINK_TIME;
+ f -= (int)f;
+ modulate[0] = modulate[1] = modulate[2] = modulate[3] = f;
+ trap_R_SetColor( modulate );
+ }
+
+ if ( cg.powerupActive == sorted[i] &&
+ cg.time - cg.powerupTime < PULSE_TIME ) {
+ f = 1.0 - ( ( (float)cg.time - cg.powerupTime ) / PULSE_TIME );
+ size = ICON_SIZE * ( 1.0 + ( PULSE_SCALE - 1.0 ) * f );
+ } else {
+ size = ICON_SIZE;
+ }
+
+ CG_DrawPic( 640 - size, y + ICON_SIZE / 2 - size / 2,
+ size, size, trap_R_RegisterShader( item->icon ) );
+ }
+ }
+ trap_R_SetColor( NULL );
+
+ return y;
+}
+#endif // MISSIONPACK
+
+/*
+=====================
+CG_DrawLowerRight
+
+=====================
+*/
+#ifndef MISSIONPACK
+static void CG_DrawLowerRight( void ) {
+ float y;
+
+ y = 480 - ICON_SIZE;
+
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1 && cg_drawTeamOverlay.integer == 2 ) {
+ y = CG_DrawTeamOverlay( y, qtrue, qfalse );
+ }
+
+ y = CG_DrawScores( y );
+ y = CG_DrawPowerups( y );
+}
+#endif // MISSIONPACK
+
+/*
+===================
+CG_DrawPickupItem
+===================
+*/
+#ifndef MISSIONPACK
+static int CG_DrawPickupItem( int y ) {
+ int value;
+ float *fadeColor;
+
+ if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
+ return y;
+ }
+
+ y -= ICON_SIZE;
+
+ value = cg.itemPickup;
+ if ( value ) {
+ fadeColor = CG_FadeColor( cg.itemPickupTime, 3000 );
+ if ( fadeColor ) {
+ CG_RegisterItemVisuals( value );
+ trap_R_SetColor( fadeColor );
+ CG_DrawPic( 8, y, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
+ CG_DrawBigString( ICON_SIZE + 16, y + (ICON_SIZE/2 - BIGCHAR_HEIGHT/2), bg_itemlist[ value ].pickup_name, fadeColor[0] );
+ trap_R_SetColor( NULL );
+ }
+ }
+
+ return y;
+}
+#endif // MISSIONPACK
+
+/*
+=====================
+CG_DrawLowerLeft
+
+=====================
+*/
+#ifndef MISSIONPACK
+static void CG_DrawLowerLeft( void ) {
+ float y;
+
+ y = 480 - ICON_SIZE;
+
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1 && cg_drawTeamOverlay.integer == 3 ) {
+ y = CG_DrawTeamOverlay( y, qfalse, qfalse );
+ }
+
+
+ y = CG_DrawPickupItem( y );
+}
+#endif // MISSIONPACK
+
+
+//===========================================================================================
+
+/*
+=================
+CG_DrawTeamInfo
+=================
+*/
+#ifndef MISSIONPACK
+static void CG_DrawTeamInfo( void ) {
+ int w, h;
+ int i, len;
+ vec4_t hcolor;
+ int chatHeight;
+
+#define CHATLOC_Y 420 // bottom end
+#define CHATLOC_X 0
+
+ if (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT)
+ chatHeight = cg_teamChatHeight.integer;
+ else
+ chatHeight = TEAMCHAT_HEIGHT;
+ if (chatHeight <= 0)
+ return; // disabled
+
+ if (cgs.teamLastChatPos != cgs.teamChatPos) {
+ if (cg.time - cgs.teamChatMsgTimes[cgs.teamLastChatPos % chatHeight] > cg_teamChatTime.integer) {
+ cgs.teamLastChatPos++;
+ }
+
+ h = (cgs.teamChatPos - cgs.teamLastChatPos) * TINYCHAR_HEIGHT;
+
+ w = 0;
+
+ for (i = cgs.teamLastChatPos; i < cgs.teamChatPos; i++) {
+ len = CG_DrawStrlen(cgs.teamChatMsgs[i % chatHeight]);
+ if (len > w)
+ w = len;
+ }
+ w *= TINYCHAR_WIDTH;
+ w += TINYCHAR_WIDTH * 2;
+
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
+ hcolor[0] = 1.0f;
+ hcolor[1] = 0.0f;
+ hcolor[2] = 0.0f;
+ hcolor[3] = 0.33f;
+ } else if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
+ hcolor[0] = 0.0f;
+ hcolor[1] = 0.0f;
+ hcolor[2] = 1.0f;
+ hcolor[3] = 0.33f;
+ } else {
+ hcolor[0] = 0.0f;
+ hcolor[1] = 1.0f;
+ hcolor[2] = 0.0f;
+ hcolor[3] = 0.33f;
+ }
+
+ trap_R_SetColor( hcolor );
+ CG_DrawPic( CHATLOC_X, CHATLOC_Y - h, 640, h, cgs.media.teamStatusBar );
+ trap_R_SetColor( NULL );
+
+ hcolor[0] = hcolor[1] = hcolor[2] = 1.0f;
+ hcolor[3] = 1.0f;
+
+ for (i = cgs.teamChatPos - 1; i >= cgs.teamLastChatPos; i--) {
+ CG_DrawStringExt( CHATLOC_X + TINYCHAR_WIDTH,
+ CHATLOC_Y - (cgs.teamChatPos - i)*TINYCHAR_HEIGHT,
+ cgs.teamChatMsgs[i % chatHeight], hcolor, qfalse, qfalse,
+ TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
+ }
+ }
+}
+#endif // MISSIONPACK
+
+/*
+===================
+CG_DrawHoldableItem
+===================
+*/
+#ifndef MISSIONPACK
+static void CG_DrawHoldableItem( void ) {
+ int value;
+
+ value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM];
+ if ( value ) {
+ CG_RegisterItemVisuals( value );
+ CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
+ }
+
+}
+#endif // MISSIONPACK
+
+#ifndef MISSIONPACK
+/*
+===================
+CG_DrawPersistantPowerup
+===================
+*/
+#if 1 // sos001208 - DEAD // sago - ALIVE
+static void CG_DrawPersistantPowerup( void ) {
+ int value;
+
+ value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP];
+ if ( value ) {
+ CG_RegisterItemVisuals( value );
+ CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2 - ICON_SIZE, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
+ }
+}
+#endif
+#endif // MISSIONPACK
+
+
+/*
+===================
+CG_DrawReward
+===================
+*/
+static void CG_DrawReward( void ) {
+ float *color;
+ int i, count;
+ float x, y;
+ char buf[32];
+
+ if ( !cg_drawRewards.integer ) {
+ return;
+ }
+
+ color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
+ if ( !color ) {
+ if (cg.rewardStack > 0) {
+ for(i = 0; i < cg.rewardStack; i++) {
+ cg.rewardSound[i] = cg.rewardSound[i+1];
+
+ cg.rewardShader[i] = cg.rewardShader[i+1];
+ cg.rewardCount[i] = cg.rewardCount[i+1];
+ }
+ cg.rewardTime = cg.time;
+ cg.rewardStack--;
+ color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
+
+ trap_S_StartLocalSound(cg.rewardSound[0], CHAN_ANNOUNCER);
+
+ } else {
+ return;
+ }
+ }
+
+ trap_R_SetColor( color );
+
+ /*
+ count = cg.rewardCount[0]/10; // number of big rewards to draw
+
+ if (count) {
+ y = 4;
+ x = 320 - count * ICON_SIZE;
+ for ( i = 0 ; i < count ; i++ ) {
+ CG_DrawPic( x, y, (ICON_SIZE*2)-4, (ICON_SIZE*2)-4, cg.rewardShader[0] );
+ x += (ICON_SIZE*2);
+ }
+ }
+
+ count = cg.rewardCount[0] - count*10; // number of small rewards to draw
+ */
+
+ if ( cg.rewardCount[0] >= 10 ) {
+ y = 56;
+ x = 320 - ICON_SIZE/2;
+ CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
+ Com_sprintf(buf, sizeof(buf), "%d", cg.rewardCount[0]);
+ x = ( SCREEN_WIDTH - SMALLCHAR_WIDTH * CG_DrawStrlen( buf ) ) / 2;
+ CG_DrawStringExt( x, y+ICON_SIZE, buf, color, qfalse, qtrue,
+ SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
+ }
+ else {
+
+ count = cg.rewardCount[0];
+
+ y = 56;
+ x = 320 - count * ICON_SIZE/2;
+ for ( i = 0 ; i < count ; i++ ) {
+ CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
+ x += ICON_SIZE;
+ }
+ }
+ trap_R_SetColor( NULL );
+}
+
+
+/*
+===============================================================================
+
+LAGOMETER
+
+===============================================================================
+*/
+
+#define LAG_SAMPLES 128
+
+
+typedef struct {
+ int frameSamples[LAG_SAMPLES];
+ int frameCount;
+ int snapshotFlags[LAG_SAMPLES];
+ int snapshotSamples[LAG_SAMPLES];
+ int snapshotCount;
+} lagometer_t;
+
+lagometer_t lagometer;
+
+/*
+==============
+CG_AddLagometerFrameInfo
+
+Adds the current interpolate / extrapolate bar for this frame
+==============
+*/
+void CG_AddLagometerFrameInfo( void ) {
+ int offset;
+
+ offset = cg.time - cg.latestSnapshotTime;
+ lagometer.frameSamples[ lagometer.frameCount & ( LAG_SAMPLES - 1) ] = offset;
+ lagometer.frameCount++;
+}
+
+/*
+==============
+CG_AddLagometerSnapshotInfo
+
+Each time a snapshot is received, log its ping time and
+the number of snapshots that were dropped before it.
+
+Pass NULL for a dropped packet.
+==============
+*/
+void CG_AddLagometerSnapshotInfo( snapshot_t *snap ) {
+ // dropped packet
+ if ( !snap ) {
+ lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = -1;
+ lagometer.snapshotCount++;
+ return;
+ }
+
+ // add this snapshot's info
+ lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->ping;
+ lagometer.snapshotFlags[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->snapFlags;
+ lagometer.snapshotCount++;
+}
+
+/*
+==============
+CG_DrawDisconnect
+
+Should we draw something differnet for long lag vs no packets?
+==============
+*/
+static void CG_DrawDisconnect( void ) {
+ float x, y;
+ int cmdNum;
+ usercmd_t cmd;
+ const char *s;
+ int w; // bk010215 - FIXME char message[1024];
+
+ // draw the phone jack if we are completely past our buffers
+ cmdNum = trap_GetCurrentCmdNumber() - CMD_BACKUP + 1;
+ trap_GetUserCmd( cmdNum, &cmd );
+ if ( cmd.serverTime <= cg.snap->ps.commandTime
+ || cmd.serverTime > cg.time ) { // special check for map_restart // bk 0102165 - FIXME
+ return;
+ }
+
+ // also add text in center of screen
+ s = "Connection Interrupted"; // bk 010215 - FIXME
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ CG_DrawBigString( 320 - w/2, 100, s, 1.0F);
+
+ // blink the icon
+ if ( ( cg.time >> 9 ) & 1 ) {
+ return;
+ }
+
+ x = 640 - 48;
+ y = 480 - 48;
+
+ CG_DrawPic( x, y, 48, 48, trap_R_RegisterShader("gfx/2d/net.tga" ) );
+}
+
+
+#define MAX_LAGOMETER_PING 900
+#define MAX_LAGOMETER_RANGE 300
+
+/*
+==============
+CG_DrawLagometer
+==============
+*/
+static void CG_DrawLagometer( void ) {
+ int a, x, y, i;
+ float v;
+ float ax, ay, aw, ah, mid, range;
+ int color;
+ float vscale;
+
+ if ( !cg_lagometer.integer || cgs.localServer ) {
+ CG_DrawDisconnect();
+ return;
+ }
+
+ //
+ // draw the graph
+ //
+#ifdef MISSIONPACK
+ x = 640 - 48;
+ y = 480 - 144;
+#else
+ x = 640 - 48;
+ y = 480 - 48;
+#endif
+
+ trap_R_SetColor( NULL );
+ CG_DrawPic( x, y, 48, 48, cgs.media.lagometerShader );
+
+ ax = x;
+ ay = y;
+ aw = 48;
+ ah = 48;
+ CG_AdjustFrom640( &ax, &ay, &aw, &ah );
+
+ color = -1;
+ range = ah / 3;
+ mid = ay + range;
+
+ vscale = range / MAX_LAGOMETER_RANGE;
+
+ // draw the frame interpoalte / extrapolate graph
+ for ( a = 0 ; a < aw ; a++ ) {
+ i = ( lagometer.frameCount - 1 - a ) & (LAG_SAMPLES - 1);
+ v = lagometer.frameSamples[i];
+ v *= vscale;
+ if ( v > 0 ) {
+ if ( color != 1 ) {
+ color = 1;
+ trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
+ }
+ if ( v > range ) {
+ v = range;
+ }
+ trap_R_DrawStretchPic ( ax + aw - a, mid - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
+ } else if ( v < 0 ) {
+ if ( color != 2 ) {
+ color = 2;
+ trap_R_SetColor( g_color_table[ColorIndex(COLOR_BLUE)] );
+ }
+ v = -v;
+ if ( v > range ) {
+ v = range;
+ }
+ trap_R_DrawStretchPic( ax + aw - a, mid, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
+ }
+ }
+
+ // draw the snapshot latency / drop graph
+ range = ah / 2;
+ vscale = range / MAX_LAGOMETER_PING;
+
+ for ( a = 0 ; a < aw ; a++ ) {
+ i = ( lagometer.snapshotCount - 1 - a ) & (LAG_SAMPLES - 1);
+ v = lagometer.snapshotSamples[i];
+ if ( v > 0 ) {
+ if ( lagometer.snapshotFlags[i] & SNAPFLAG_RATE_DELAYED ) {
+ if ( color != 5 ) {
+ color = 5; // YELLOW for rate delay
+ trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
+ }
+ } else {
+ if ( color != 3 ) {
+ color = 3;
+ trap_R_SetColor( g_color_table[ColorIndex(COLOR_GREEN)] );
+ }
+ }
+ v = v * vscale;
+ if ( v > range ) {
+ v = range;
+ }
+ trap_R_DrawStretchPic( ax + aw - a, ay + ah - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
+ } else if ( v < 0 ) {
+ if ( color != 4 ) {
+ color = 4; // RED for dropped snapshots
+ trap_R_SetColor( g_color_table[ColorIndex(COLOR_RED)] );
+ }
+ trap_R_DrawStretchPic( ax + aw - a, ay + ah - range, 1, range, 0, 0, 0, 0, cgs.media.whiteShader );
+ }
+ }
+
+ trap_R_SetColor( NULL );
+
+ if ( cg_nopredict.integer || cg_synchronousClients.integer ) {
+ CG_DrawBigString( ax, ay, "snc", 1.0 );
+ }
+
+ CG_DrawDisconnect();
+}
+
+
+
+/*
+===============================================================================
+
+CENTER PRINTING
+
+===============================================================================
+*/
+
+
+/*
+==============
+CG_CenterPrint
+
+Called for important messages that should stay in the center of the screen
+for a few moments
+==============
+*/
+void CG_CenterPrint( const char *str, int y, int charWidth ) {
+ char *s;
+
+ Q_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) );
+
+ cg.centerPrintTime = cg.time;
+ cg.centerPrintY = y;
+ cg.centerPrintCharWidth = charWidth;
+
+ // count the number of lines for centering
+ cg.centerPrintLines = 1;
+ s = cg.centerPrint;
+ while( *s ) {
+ if (*s == '\n')
+ cg.centerPrintLines++;
+ s++;
+ }
+}
+
+
+/*
+===================
+CG_DrawCenterString
+===================
+*/
+static void CG_DrawCenterString( void ) {
+ char *start;
+ int l;
+ int x, y, w;
+#ifdef MISSIONPACK // bk010221 - unused else
+ int h;
+#endif
+ float *color;
+
+ if ( !cg.centerPrintTime ) {
+ return;
+ }
+
+ color = CG_FadeColor( cg.centerPrintTime, 1000 * cg_centertime.value );
+ if ( !color ) {
+ return;
+ }
+
+ trap_R_SetColor( color );
+
+ start = cg.centerPrint;
+
+ y = cg.centerPrintY - cg.centerPrintLines * BIGCHAR_HEIGHT / 2;
+
+ while ( 1 ) {
+ char linebuffer[1024];
+
+ for ( l = 0; l < 50; l++ ) {
+ if ( !start[l] || start[l] == '\n' ) {
+ break;
+ }
+ linebuffer[l] = start[l];
+ }
+ linebuffer[l] = 0;
+
+#ifdef MISSIONPACK
+ w = CG_Text_Width(linebuffer, 0.5, 0);
+ h = CG_Text_Height(linebuffer, 0.5, 0);
+ x = (SCREEN_WIDTH - w) / 2;
+ CG_Text_Paint(x, y + h, 0.5, color, linebuffer, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
+ y += h + 6;
+#else
+ w = cg.centerPrintCharWidth * CG_DrawStrlen( linebuffer );
+
+ x = ( SCREEN_WIDTH - w ) / 2;
+
+ CG_DrawStringExt( x, y, linebuffer, color, qfalse, qtrue,
+ cg.centerPrintCharWidth, (int)(cg.centerPrintCharWidth * 1.5), 0 );
+
+ y += cg.centerPrintCharWidth * 1.5;
+#endif
+ while ( *start && ( *start != '\n' ) ) {
+ start++;
+ }
+ if ( !*start ) {
+ break;
+ }
+ start++;
+ }
+
+ trap_R_SetColor( NULL );
+}
+
+/*
+=====================
+CG_DrawCenter1FctfString
+=====================
+*/
+static void CG_DrawCenter1FctfString( void ) {
+ #ifndef MISSIONPACK
+ int x, y, w;
+ float *color;
+ char *line;
+ int status;
+
+ if(cgs.gametype != GT_1FCTF)
+ return;
+
+ status = cgs.flagStatus;
+
+ //Sago: TODO: Find the proper defines instead of hardcoded values.
+ switch(status)
+ {
+ case 2:
+ line = va("Red has the flag!");
+ color = colorRed;
+ break;
+ case 3:
+ line = va("Blue has the flag!");
+ color = colorBlue;
+ break;
+ case 4:
+ line = va("Flag dropped!");
+ color = colorWhite;
+ break;
+ default:
+ return;
+
+ };
+ y = 100;
+
+
+ w = cg.centerPrintCharWidth * CG_DrawStrlen( line );
+
+ x = ( SCREEN_WIDTH - w ) / 2;
+
+ CG_DrawStringExt( x, y, line, color, qfalse, qtrue,
+ cg.centerPrintCharWidth, (int)(cg.centerPrintCharWidth * 1.5), 0 );
+
+
+ #endif
+}
+
+
+
+/*
+=====================
+CG_DrawCenterDDString
+=====================
+*/
+static void CG_DrawCenterDDString( void ) {
+ #ifndef MISSIONPACK
+ int x, y, w;
+ float *color;
+ char *line;
+ int statusA, statusB;
+ int sec;
+ static int lastDDSec = -100;
+
+
+ if(cgs.gametype != GT_DOUBLE_D)
+ return;
+
+ statusA = cgs.redflag;
+ statusB = cgs.blueflag;
+
+ if( ( ( statusB == statusA ) && ( statusA == TEAM_RED ) ) ||
+ ( ( statusB == statusA ) && ( statusA == TEAM_BLUE ) ) ) {
+ }
+ else
+ return; //No team is dominating
+
+ if(statusA == TEAM_BLUE) {
+ line = va("Blue scores in %i",(cgs.timetaken+10*1000-cg.time)/1000+1);
+ color = colorBlue;
+ } else if(statusA == TEAM_RED) {
+ line = va("Red scores in %i",(cgs.timetaken+10*1000-cg.time)/1000+1);
+ color = colorRed;
+ } else {
+ lastDDSec = -100;
+ return;
+ }
+
+ sec = (cgs.timetaken+10*1000-cg.time)/1000+1;
+ if(sec!=lastDDSec) {
+ //A new number is being displayed... play the sound!
+ switch ( sec ) {
+ case 1:
+ trap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER );
+ break;
+ case 2:
+ trap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER );
+ break;
+ case 3:
+ trap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER );
+ break;
+ case 10:
+ trap_S_StartLocalSound( cgs.media.doublerSound , CHAN_ANNOUNCER );
+ break;
+ default:
+ break;
+ }
+ }
+ lastDDSec = sec;
+
+ y = 100;
+
+
+ w = cg.centerPrintCharWidth * CG_DrawStrlen( line );
+
+ x = ( SCREEN_WIDTH - w ) / 2;
+
+ CG_DrawStringExt( x, y, line, color, qfalse, qtrue,
+ cg.centerPrintCharWidth, (int)(cg.centerPrintCharWidth * 1.5), 0 );
+
+ #endif
+}
+
+
+/*
+================================================================================
+
+CROSSHAIR
+
+================================================================================
+*/
+
+
+/*
+=================
+CG_DrawCrosshair
+=================
+*/
+static void CG_DrawCrosshair(void)
+{
+ float w, h;
+ qhandle_t hShader;
+ float f;
+ float x, y;
+ int ca = 0; //only to get rid of the warning(not useful)
+ int currentWeapon;
+
+ currentWeapon = cg.predictedPlayerState.weapon;
+
+ if ( !cg_drawCrosshair.integer ) {
+ return;
+ }
+
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) {
+ return;
+ }
+
+ if ( cg.renderingThirdPerson ) {
+ return;
+ }
+
+ // set color based on health
+ if ( cg_crosshairHealth.integer ) {
+ vec4_t hcolor;
+
+ CG_ColorForHealth( hcolor );
+ trap_R_SetColor( hcolor );
+ } else {
+ vec4_t color;
+ color[0]=cg_crosshairColorRed.value;
+ color[1]=cg_crosshairColorGreen.value;
+ color[2]=cg_crosshairColorBlue.value;
+ color[3]=1.0f;
+ trap_R_SetColor( color );
+ }
+
+ if( cg_differentCrosshairs.integer == 1 ){
+ switch( currentWeapon ){
+ case 1:
+ w = h = cg_ch1size.value;
+ ca = cg_ch1.integer;
+ break;
+ case 2:
+ w = h = cg_ch2size.value;
+ ca = cg_ch2.integer;
+ break;
+ case 3:
+ w = h = cg_ch3size.value;
+ ca = cg_ch3.integer;
+ break;
+ case 4:
+ w = h = cg_ch4size.value;
+ ca = cg_ch4.integer;
+ break;
+ case 5:
+ w = h = cg_ch5size.value;
+ ca = cg_ch5.integer;
+ break;
+ case 6:
+ w = h = cg_ch6size.value;
+ ca = cg_ch6.integer;
+ break;
+ case 7:
+ w = h = cg_ch7size.value;
+ ca = cg_ch7.integer;
+ break;
+ case 8:
+ w = h = cg_ch8size.value;
+ ca = cg_ch8.integer;
+ break;
+ case 9:
+ w = h = cg_ch9size.value;
+ ca = cg_ch9.integer;
+ break;
+ case 10:
+ w = h = cg_ch10size.value;
+ ca = cg_ch10.integer;
+ break;
+ case 11:
+ w = h = cg_ch11size.value;
+ ca = cg_ch11.integer;
+ break;
+ case 12:
+ w = h = cg_ch12size.value;
+ ca = cg_ch12.integer;
+ break;
+ case 13:
+ w = h = cg_ch13size.value;
+ ca = cg_ch13.integer;
+ break;
+ default:
+ w = h = cg_crosshairSize.value;
+ ca = cg_drawCrosshair.integer;
+ break;
+ }
+ }
+ else{
+ w = h = cg_crosshairSize.value;
+ ca = cg_drawCrosshair.integer;
+ }
+
+ if( cg_crosshairPulse.integer ){
+ // pulse the size of the crosshair when picking up items
+ f = cg.time - cg.itemPickupBlendTime;
+ if ( f > 0 && f < ITEM_BLOB_TIME ) {
+ f /= ITEM_BLOB_TIME;
+ w *= ( 1 + f );
+ h *= ( 1 + f );
+ }
+ }
+
+ x = cg_crosshairX.integer;
+ y = cg_crosshairY.integer;
+ CG_AdjustFrom640( &x, &y, &w, &h );
+
+ if (ca < 0) {
+ ca = 0;
+ }
+ hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ];
+
+ if(!hShader)
+ hShader = cgs.media.crosshairShader[ ca % 10 ];
+
+ trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (cg.refdef.width - w),
+ y + cg.refdef.y + 0.5 * (cg.refdef.height - h),
+ w, h, 0, 0, 1, 1, hShader );
+}
+
+/*
+=================
+CG_DrawCrosshair3D
+=================
+*/
+static void CG_DrawCrosshair3D(void)
+{
+ float w, h;
+ qhandle_t hShader;
+ float f;
+ int ca;
+
+ trace_t trace;
+ vec3_t endpos;
+ float stereoSep, zProj, maxdist, xmax;
+ char rendererinfos[128];
+ refEntity_t ent;
+
+ if ( !cg_drawCrosshair.integer ) {
+ return;
+ }
+
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) {
+ return;
+ }
+
+ if ( cg.renderingThirdPerson ) {
+ return;
+ }
+
+ w = h = cg_crosshairSize.value;
+
+ // pulse the size of the crosshair when picking up items
+ f = cg.time - cg.itemPickupBlendTime;
+ if ( f > 0 && f < ITEM_BLOB_TIME ) {
+ f /= ITEM_BLOB_TIME;
+ w *= ( 1 + f );
+ h *= ( 1 + f );
+ }
+
+ ca = cg_drawCrosshair.integer;
+ if (ca < 0) {
+ ca = 0;
+ }
+ hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ];
+
+ if(!hShader)
+ hShader = cgs.media.crosshairShader[ ca % 10 ];
+
+ // Use a different method rendering the crosshair so players don't see two of them when
+ // focusing their eyes at distant objects with high stereo separation
+ // We are going to trace to the next shootable object and place the crosshair in front of it.
+
+ // first get all the important renderer information
+ trap_Cvar_VariableStringBuffer("r_zProj", rendererinfos, sizeof(rendererinfos));
+ zProj = atof(rendererinfos);
+ trap_Cvar_VariableStringBuffer("r_stereoSeparation", rendererinfos, sizeof(rendererinfos));
+ stereoSep = zProj / atof(rendererinfos);
+
+ xmax = zProj * tan(cg.refdef.fov_x * M_PI / 360.0f);
+
+ // let the trace run through until a change in stereo separation of the crosshair becomes less than one pixel.
+ maxdist = cgs.glconfig.vidWidth * stereoSep * zProj / (2 * xmax);
+ VectorMA(cg.refdef.vieworg, maxdist, cg.refdef.viewaxis[0], endpos);
+ CG_Trace(&trace, cg.refdef.vieworg, NULL, NULL, endpos, 0, MASK_SHOT);
+
+ memset(&ent, 0, sizeof(ent));
+ ent.reType = RT_SPRITE;
+ ent.renderfx = RF_DEPTHHACK | RF_CROSSHAIR;
+
+ VectorCopy(trace.endpos, ent.origin);
+
+ // scale the crosshair so it appears the same size for all distances
+ ent.radius = w / 640 * xmax * trace.fraction * maxdist / zProj;
+ ent.customShader = hShader;
+
+ trap_R_AddRefEntityToScene(&ent);
+}
+
+
+
+/*
+=================
+CG_ScanForCrosshairEntity
+=================
+*/
+static void CG_ScanForCrosshairEntity( void ) {
+ trace_t trace;
+ vec3_t start, end;
+ int content;
+
+ VectorCopy( cg.refdef.vieworg, start );
+ VectorMA( start, 131072, cg.refdef.viewaxis[0], end );
+
+ CG_Trace( &trace, start, vec3_origin, vec3_origin, end,
+ cg.snap->ps.clientNum, CONTENTS_SOLID|CONTENTS_BODY );
+ if ( trace.entityNum >= MAX_CLIENTS ) {
+ return;
+ }
+
+ // if the player is in fog, don't show it
+ content = CG_PointContents( trace.endpos, 0 );
+ if ( content & CONTENTS_FOG ) {
+ return;
+ }
+
+ // if the player is invisible, don't show it
+ if ( cg_entities[ trace.entityNum ].currentState.powerups & ( 1 << PW_INVIS ) ) {
+ return;
+ }
+
+ // update the fade timer
+ cg.crosshairClientNum = trace.entityNum;
+ cg.crosshairClientTime = cg.time;
+}
+
+
+/*
+=====================
+CG_DrawCrosshairNames
+=====================
+*/
+static void CG_DrawCrosshairNames( void ) {
+ float *color;
+ char *name;
+ float w;
+
+ if ( !cg_drawCrosshair.integer ) {
+ return;
+ }
+ if ( !cg_drawCrosshairNames.integer ) {
+ return;
+ }
+ if ( cg.renderingThirdPerson ) {
+ return;
+ }
+
+ // scan the known entities to see if the crosshair is sighted on one
+ CG_ScanForCrosshairEntity();
+
+ // draw the name of the player being looked at
+ color = CG_FadeColor( cg.crosshairClientTime, 1000 );
+ if ( !color ) {
+ trap_R_SetColor( NULL );
+ return;
+ }
+
+ name = cgs.clientinfo[ cg.crosshairClientNum ].name;
+#ifdef MISSIONPACK
+ color[3] *= 0.5f;
+ w = CG_Text_Width(name, 0.3f, 0);
+ CG_Text_Paint( 320 - w / 2, 190, 0.3f, color, name, 0, 0, ITEM_TEXTSTYLE_SHADOWED);
+#else
+ w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH;
+ CG_DrawBigString( 320 - w / 2, 170, name, color[3] * 0.5f );
+#endif
+ trap_R_SetColor( NULL );
+}
+
+
+//==============================================================================
+
+/*
+=================
+CG_DrawSpectator
+=================
+*/
+static void CG_DrawSpectator(void) {
+ CG_DrawBigString(320 - 9 * 8, 440, "SPECTATOR", 1.0F);
+ if ( cgs.gametype == GT_TOURNAMENT ) {
+ CG_DrawBigString(320 - 15 * 8, 460, "waiting to play", 1.0F);
+ }
+ else if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ CG_DrawBigString(320 - 39 * 8, 460, "press ESC and use the JOIN menu to play", 1.0F);
+ }
+}
+
+/*
+=================
+CG_DrawVote
+=================
+*/
+static void CG_DrawVote(void) {
+ char *s;
+ int sec;
+
+ if ( !cgs.voteTime ) {
+ return;
+ }
+
+ // play a talk beep whenever it is modified
+ if ( cgs.voteModified ) {
+ cgs.voteModified = qfalse;
+ trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
+ }
+
+ sec = ( VOTE_TIME - ( cg.time - cgs.voteTime ) ) / 1000;
+ if ( sec < 0 ) {
+ sec = 0;
+ }
+#ifdef MISSIONPACK
+ s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo);
+ CG_DrawSmallString( 0, 58, s, 1.0F );
+ s = "or press ESC then click Vote";
+ CG_DrawSmallString( 0, 58 + SMALLCHAR_HEIGHT + 2, s, 1.0F );
+#else
+ s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo );
+ CG_DrawSmallString( 0, 58, s, 1.0F );
+#endif
+}
+
+/*
+=================
+CG_DrawTeamVote
+=================
+*/
+static void CG_DrawTeamVote(void) {
+ char *s;
+ int sec, cs_offset;
+
+ if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
+ cs_offset = 0;
+ else if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )
+ cs_offset = 1;
+ else
+ return;
+
+ if ( !cgs.teamVoteTime[cs_offset] ) {
+ return;
+ }
+
+ // play a talk beep whenever it is modified
+ if ( cgs.teamVoteModified[cs_offset] ) {
+ cgs.teamVoteModified[cs_offset] = qfalse;
+ trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
+ }
+
+ sec = ( VOTE_TIME - ( cg.time - cgs.teamVoteTime[cs_offset] ) ) / 1000;
+ if ( sec < 0 ) {
+ sec = 0;
+ }
+ s = va("TEAMVOTE(%i):%s yes:%i no:%i", sec, cgs.teamVoteString[cs_offset],
+ cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] );
+ CG_DrawSmallString( 0, 90, s, 1.0F );
+}
+
+
+static qboolean CG_DrawScoreboard( void ) {
+#ifdef MISSIONPACK
+ static qboolean firstTime = qtrue;
+ float fade, *fadeColor;
+
+ if (menuScoreboard) {
+ menuScoreboard->window.flags &= ~WINDOW_FORCED;
+ }
+ if (cg_paused.integer) {
+ cg.deferredPlayerLoading = 0;
+ firstTime = qtrue;
+ return qfalse;
+ }
+
+ // should never happen in Team Arena
+ if (cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
+ cg.deferredPlayerLoading = 0;
+ firstTime = qtrue;
+ return qfalse;
+ }
+
+ // don't draw scoreboard during death while warmup up
+ if ( cg.warmup && !cg.showScores ) {
+ return qfalse;
+ }
+
+ if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD || cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
+ fade = 1.0;
+ fadeColor = colorWhite;
+ } else {
+ fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
+ if ( !fadeColor ) {
+ // next time scoreboard comes up, don't print killer
+ cg.deferredPlayerLoading = 0;
+ cg.killerName[0] = 0;
+ firstTime = qtrue;
+ return qfalse;
+ }
+ fade = *fadeColor;
+ }
+
+
+ if (menuScoreboard == NULL) {
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ menuScoreboard = Menus_FindByName("teamscore_menu");
+ } else {
+ menuScoreboard = Menus_FindByName("score_menu");
+ }
+ }
+
+ if (menuScoreboard) {
+ if (firstTime) {
+ CG_SetScoreSelection(menuScoreboard);
+ firstTime = qfalse;
+ }
+ Menu_Paint(menuScoreboard, qtrue);
+ }
+
+ // load any models that have been deferred
+ if ( ++cg.deferredPlayerLoading > 10 ) {
+ CG_LoadDeferredPlayers();
+ }
+
+ return qtrue;
+#else
+ char *s;
+ int w;
+ if(cg.respawnTime && cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR && (cgs.gametype < GT_ELIMINATION || cgs.gametype > GT_LMS) ) {
+ if(cg.respawnTime>cg.time) {
+ s = va("Respawn in: %2.2f",((double)cg.respawnTime-(double)cg.time)/1000.0);
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallStringColor(320-w/2,400, s, colorYellow);
+ } else {
+ s = va("Click FIRE to respawn");
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallStringColor(320-w/2,400, "Click FIRE to respawn", colorGreen);
+ }
+ }
+ return CG_DrawOldScoreboard();
+#endif
+}
+
+#define ACCBOARD_XPOS 500
+#define ACCBOARD_YPOS 150
+#define ACCBOARD_HEIGHT 20
+#define ACCBOARD_WIDTH 75
+#define ACCITEM_SIZE 16
+
+qboolean CG_DrawAccboard( void ) {
+ int counter, i;
+
+ i = 0;
+
+ if( !cg.showAcc ){
+ return qfalse;
+ }
+ trap_R_SetColor( colorWhite );
+
+ for( counter = 0; counter < WP_NUM_WEAPONS ; counter++ ){
+ if( cg_weapons[counter+2].weaponIcon && counter != WP_PROX_LAUNCHER && counter != WP_GRAPPLING_HOOK )
+ i++;
+ }
+
+ CG_DrawTeamBackground( ACCBOARD_XPOS, ACCBOARD_YPOS, ACCBOARD_WIDTH, ACCBOARD_HEIGHT*(i + 1), 0.33f, TEAM_BLUE );
+
+ i = 0;
+
+ for( counter = 0 ; counter < WP_NUM_WEAPONS ; counter++ ){
+ if( cg_weapons[counter+2].weaponIcon && counter != WP_PROX_LAUNCHER && counter != WP_GRAPPLING_HOOK ){
+ CG_DrawPic( ACCBOARD_XPOS + 10, ACCBOARD_YPOS + 10 +i*ACCBOARD_HEIGHT, ACCITEM_SIZE, ACCITEM_SIZE, cg_weapons[counter+2].weaponIcon );
+ if( cg.accuracys[counter][0] > 0 )
+ CG_DrawSmallStringColor(ACCBOARD_XPOS + 10 + ACCITEM_SIZE + 10, ACCBOARD_YPOS + 10 +i*ACCBOARD_HEIGHT + ACCITEM_SIZE/2 - SMALLCHAR_HEIGHT/2 ,
+ va("%i%s",(int)(((float)cg.accuracys[counter][1]*100)/((float)(cg.accuracys[counter][0]))),"%"), colorWhite);
+ else
+ CG_DrawSmallStringColor(ACCBOARD_XPOS + 10 + ACCITEM_SIZE + 10, ACCBOARD_YPOS + 10 +i*ACCBOARD_HEIGHT + ACCITEM_SIZE/2 - SMALLCHAR_HEIGHT/2 , "-%", colorWhite);
+ i++;
+ }
+ }
+
+ trap_R_SetColor(NULL);
+ return qtrue;
+}
+
+
+
+/*
+=================
+CG_DrawIntermission
+=================
+*/
+static void CG_DrawIntermission( void ) {
+// int key;
+#ifdef MISSIONPACK
+ //if (cg_singlePlayer.integer) {
+ // CG_DrawCenterString();
+ // return;
+ //}
+#else
+ if ( cgs.gametype == GT_SINGLE_PLAYER ) {
+ CG_DrawCenterString();
+ return;
+ }
+#endif
+ cg.scoreFadeTime = cg.time;
+ cg.scoreBoardShowing = CG_DrawScoreboard();
+}
+
+/*
+=================
+CG_DrawFollow
+=================
+*/
+static qboolean CG_DrawFollow( void ) {
+ float x;
+ vec4_t color;
+ const char *name;
+
+ if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
+ return qfalse;
+ }
+ color[0] = 1;
+ color[1] = 1;
+ color[2] = 1;
+ color[3] = 1;
+
+
+ CG_DrawBigString( 320 - 9 * 8, 24, "following", 1.0F );
+
+ name = cgs.clientinfo[ cg.snap->ps.clientNum ].name;
+
+ x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( name ) );
+
+ CG_DrawStringExt( x, 40, name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+
+ return qtrue;
+}
+
+
+
+/*
+=================
+CG_DrawAmmoWarning
+=================
+*/
+static void CG_DrawAmmoWarning( void ) {
+ const char *s;
+ int w;
+
+ //Don't report in instant gib same with RA
+ if(cgs.nopickup)
+ return;
+
+ if ( cg_drawAmmoWarning.integer == 0 ) {
+ return;
+ }
+
+ if ( !cg.lowAmmoWarning ) {
+ return;
+ }
+
+ if ( cg.lowAmmoWarning == 2 ) {
+ s = "OUT OF AMMO";
+ } else {
+ s = "LOW AMMO WARNING";
+ }
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ CG_DrawBigString(320 - w / 2, 64, s, 1.0F);
+}
+
+
+//#ifdef MISSIONPACK
+/*
+=================
+CG_DrawProxWarning
+=================
+*/
+static void CG_DrawProxWarning( void ) {
+ char s [32];
+ int w;
+ static int proxTime;
+ static int proxCounter;
+ static int proxTick;
+
+ if( !(cg.snap->ps.eFlags & EF_TICKING ) ) {
+ proxTime = 0;
+ return;
+ }
+
+ if (proxTime == 0) {
+ proxTime = cg.time + 5000;
+ proxCounter = 5;
+ proxTick = 0;
+ }
+
+ if (cg.time > proxTime) {
+ proxTick = proxCounter--;
+ proxTime = cg.time + 1000;
+ }
+
+ if (proxTick != 0) {
+ Com_sprintf(s, sizeof(s), "INTERNAL COMBUSTION IN: %i", proxTick);
+ } else {
+ Com_sprintf(s, sizeof(s), "YOU HAVE BEEN MINED");
+ }
+
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ CG_DrawBigStringColor( 320 - w / 2, 64 + BIGCHAR_HEIGHT, s, g_color_table[ColorIndex(COLOR_RED)] );
+}
+//#endif
+
+
+/*
+=================
+CG_DrawWarmup
+=================
+*/
+static void CG_DrawWarmup( void ) {
+ int w;
+ int sec;
+ int i;
+ float scale;
+ clientInfo_t *ci1, *ci2;
+ int cw;
+ const char *s;
+
+ sec = cg.warmup;
+ if ( !sec ) {
+ return;
+ }
+
+ if ( sec < 0 ) {
+ s = "Waiting for players";
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ CG_DrawBigString(320 - w / 2, 24, s, 1.0F);
+ cg.warmupCount = 0;
+ return;
+ }
+
+ if (cgs.gametype == GT_TOURNAMENT) {
+ // find the two active players
+ ci1 = NULL;
+ ci2 = NULL;
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_FREE ) {
+ if ( !ci1 ) {
+ ci1 = &cgs.clientinfo[i];
+ } else {
+ ci2 = &cgs.clientinfo[i];
+ }
+ }
+ }
+
+ if ( ci1 && ci2 ) {
+ s = va( "%s vs %s", ci1->name, ci2->name );
+#ifdef MISSIONPACK
+ w = CG_Text_Width(s, 0.6f, 0);
+ CG_Text_Paint(320 - w / 2, 60, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
+#else
+ w = CG_DrawStrlen( s );
+ if ( w > 640 / GIANT_WIDTH ) {
+ cw = 640 / w;
+ } else {
+ cw = GIANT_WIDTH;
+ }
+ CG_DrawStringExt( 320 - w * cw/2, 20,s, colorWhite,
+ qfalse, qtrue, cw, (int)(cw * 1.5f), 0 );
+#endif
+ }
+ } else {
+ if ( cgs.gametype == GT_FFA ) {
+ s = "Free For All";
+ } else if ( cgs.gametype == GT_TEAM ) {
+ s = "Team Deathmatch";
+ } else if ( cgs.gametype == GT_CTF ) {
+ s = "Capture the Flag";
+ } else if ( cgs.gametype == GT_ELIMINATION ) {
+ s = "Elimination";
+ } else if ( cgs.gametype == GT_CTF_ELIMINATION ) {
+ s = "CTF Elimination";
+ } else if ( cgs.gametype == GT_LMS ) {
+ s = "Last Man Standing";
+ } else if ( cgs.gametype == GT_DOUBLE_D ) {
+ s = "Double Domination";
+ } else if ( cgs.gametype == GT_1FCTF ) {
+ s = "One Flag CTF";
+ } else if ( cgs.gametype == GT_OBELISK ) {
+ s = "Overload";
+ } else if ( cgs.gametype == GT_HARVESTER ) {
+ s = "Harvester";
+ } else if ( cgs.gametype == GT_DOMINATION ) {
+ s = "Domination";
+ } else {
+ s = "";
+ }
+#ifdef MISSIONPACK
+ w = CG_Text_Width(s, 0.6f, 0);
+ CG_Text_Paint(320 - w / 2, 90, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
+#else
+ w = CG_DrawStrlen( s );
+ if ( w > 640 / GIANT_WIDTH ) {
+ cw = 640 / w;
+ } else {
+ cw = GIANT_WIDTH;
+ }
+ CG_DrawStringExt( 320 - w * cw/2, 25,s, colorWhite,
+ qfalse, qtrue, cw, (int)(cw * 1.1f), 0 );
+#endif
+ }
+
+ sec = ( sec - cg.time ) / 1000;
+ if ( sec < 0 ) {
+ cg.warmup = 0;
+ sec = 0;
+ }
+ s = va( "Starts in: %i", sec + 1 );
+ if ( sec != cg.warmupCount ) {
+ cg.warmupCount = sec;
+ switch ( sec ) {
+ case 0:
+ trap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER );
+ break;
+ case 1:
+ trap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER );
+ break;
+ case 2:
+ trap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER );
+ break;
+ default:
+ break;
+ }
+ }
+ scale = 0.45f;
+ switch ( cg.warmupCount ) {
+ case 0:
+ cw = 28;
+ scale = 0.54f;
+ break;
+ case 1:
+ cw = 24;
+ scale = 0.51f;
+ break;
+ case 2:
+ cw = 20;
+ scale = 0.48f;
+ break;
+ default:
+ cw = 16;
+ scale = 0.45f;
+ break;
+ }
+
+#ifdef MISSIONPACK
+ w = CG_Text_Width(s, scale, 0);
+ CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
+#else
+ w = CG_DrawStrlen( s );
+ CG_DrawStringExt( 320 - w * cw/2, 70, s, colorWhite,
+ qfalse, qtrue, cw, (int)(cw * 1.5), 0 );
+#endif
+}
+
+//==================================================================================
+#ifdef MISSIONPACK
+/*
+=================
+CG_DrawTimedMenus
+=================
+*/
+void CG_DrawTimedMenus( void ) {
+ if (cg.voiceTime) {
+ int t = cg.time - cg.voiceTime;
+ if ( t > 2500 ) {
+ Menus_CloseByName("voiceMenu");
+ trap_Cvar_Set("cl_conXOffset", "0");
+ cg.voiceTime = 0;
+ }
+ }
+}
+#endif
+/*
+=================
+CG_Draw2D
+=================
+*/
+static void CG_Draw2D(stereoFrame_t stereoFrame)
+{
+#ifdef MISSIONPACK
+ if (cgs.orderPending && cg.time > cgs.orderTime) {
+ CG_CheckOrderPending();
+ }
+#endif
+ // if we are taking a levelshot for the menu, don't draw anything
+ if ( cg.levelShot ) {
+ return;
+ }
+
+ if ( cg_draw2D.integer == 0 ) {
+ return;
+ }
+
+ if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
+ CG_DrawIntermission();
+ return;
+ }
+
+/*
+ if (cg.cameraMode) {
+ return;
+ }
+*/
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR /*|| cg.snap->ps.pm_type == PM_SPECTATOR*/ ) {
+ CG_DrawSpectator();
+
+ if(stereoFrame == STEREO_CENTER)
+ CG_DrawCrosshair();
+
+ CG_DrawCrosshairNames();
+ } else {
+ // don't draw any status if dead or the scoreboard is being explicitly shown
+ if ( !cg.showScores && cg.snap->ps.stats[STAT_HEALTH] > 0 ) {
+
+#ifdef MISSIONPACK
+ if ( cg_drawStatus.integer ) {
+ Menu_PaintAll();
+ CG_DrawTimedMenus();
+ }
+#else
+ CG_DrawStatusBar();
+#endif
+
+ CG_DrawAmmoWarning();
+
+ CG_DrawProxWarning();
+ if(stereoFrame == STEREO_CENTER)
+ CG_DrawCrosshair();
+ CG_DrawCrosshairNames();
+ CG_DrawWeaponSelect();
+
+ #ifndef MISSIONPACK
+ CG_DrawHoldableItem();
+ CG_DrawPersistantPowerup();
+ #endif
+
+ CG_DrawReward();
+ }
+
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+#ifndef MISSIONPACK
+ CG_DrawTeamInfo();
+#endif
+ }
+ }
+
+ CG_DrawVote();
+ CG_DrawTeamVote();
+
+ CG_DrawLagometer();
+
+#ifdef MISSIONPACK
+ if (!cg_paused.integer) {
+ CG_DrawUpperRight(stereoFrame);
+ }
+#else
+ CG_DrawUpperRight(stereoFrame);
+#endif
+
+#ifndef MISSIONPACK
+ CG_DrawLowerRight();
+ CG_DrawLowerLeft();
+#endif
+
+ if ( !CG_DrawFollow() ) {
+ CG_DrawWarmup();
+ }
+
+ // don't draw center string if scoreboard is up
+ cg.scoreBoardShowing = CG_DrawScoreboard();
+ if ( !cg.scoreBoardShowing) {
+ CG_DrawCenterDDString();
+ CG_DrawCenter1FctfString();
+ CG_DrawCenterString();
+ }
+
+ cg.accBoardShowing = CG_DrawAccboard();
+}
+
+
+static void CG_DrawTourneyScoreboard( void ) {
+#ifdef MISSIONPACK
+#else
+ CG_DrawOldTourneyScoreboard();
+#endif
+}
+
+/*
+=====================
+CG_DrawActive
+
+Perform all drawing needed to completely fill the screen
+=====================
+*/
+void CG_DrawActive( stereoFrame_t stereoView ) {
+ // optionally draw the info screen instead
+ if ( !cg.snap ) {
+ CG_DrawInformation();
+ return;
+ }
+
+ // optionally draw the tournement scoreboard instead
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR &&
+ ( cg.snap->ps.pm_flags & PMF_SCOREBOARD ) ) {
+ CG_DrawTourneyScoreboard();
+ return;
+ }
+
+ // clear around the rendered view if sized down
+ CG_TileClear();
+
+ if(stereoView != STEREO_CENTER)
+ CG_DrawCrosshair3D();
+
+ // draw 3D view
+ trap_R_RenderScene( &cg.refdef );
+
+ // draw status bar and other floating elements
+ CG_Draw2D(stereoView);
+}
+
+
+
diff --git a/game/code/cgame/cg_drawtools.c b/code/cgame/cg_drawtools.c
similarity index 100%
rename from game/code/cgame/cg_drawtools.c
rename to code/cgame/cg_drawtools.c
diff --git a/code/cgame/cg_effects.c b/code/cgame/cg_effects.c
new file mode 100644
index 0000000..a63d96e
--- /dev/null
+++ b/code/cgame/cg_effects.c
@@ -0,0 +1,828 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_effects.c -- these functions generate localentities, usually as a result
+// of event processing
+
+#include "cg_local.h"
+
+
+/*
+==================
+CG_BubbleTrail
+
+Bullets shot underwater
+==================
+*/
+void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ) {
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int i;
+
+ if ( cg_noProjectileTrail.integer ) {
+ return;
+ }
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ // advance a random amount first
+ i = rand() % (int)spacing;
+ VectorMA( move, i, vec, move );
+
+ VectorScale (vec, spacing, vec);
+
+ for ( ; i < len; i += spacing ) {
+ localEntity_t *le;
+ refEntity_t *re;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = LEF_PUFF_DONT_SCALE;
+ le->leType = LE_MOVE_SCALE_FADE;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 1000 + random() * 250;
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+
+ re = &le->refEntity;
+ re->shaderTime = cg.time / 1000.0f;
+
+ re->reType = RT_SPRITE;
+ re->rotation = 0;
+ re->radius = 3;
+ re->customShader = cgs.media.waterBubbleShader;
+ re->shaderRGBA[0] = 0xff;
+ re->shaderRGBA[1] = 0xff;
+ re->shaderRGBA[2] = 0xff;
+ re->shaderRGBA[3] = 0xff;
+
+ le->color[3] = 1.0;
+
+ le->pos.trType = TR_LINEAR;
+ le->pos.trTime = cg.time;
+ VectorCopy( move, le->pos.trBase );
+ le->pos.trDelta[0] = crandom()*5;
+ le->pos.trDelta[1] = crandom()*5;
+ le->pos.trDelta[2] = crandom()*5 + 6;
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+/*
+=====================
+CG_SmokePuff
+
+Adds a smoke puff or blood trail localEntity.
+=====================
+*/
+localEntity_t *CG_SmokePuff( const vec3_t p, const vec3_t vel,
+ float radius,
+ float r, float g, float b, float a,
+ float duration,
+ int startTime,
+ int fadeInTime,
+ int leFlags,
+ qhandle_t hShader ) {
+ static int seed = 0x92;
+ localEntity_t *le;
+ refEntity_t *re;
+// int fadeInTime = startTime + duration / 2;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = leFlags;
+ le->radius = radius;
+
+ re = &le->refEntity;
+ re->rotation = Q_random( &seed ) * 360;
+ re->radius = radius;
+ re->shaderTime = startTime / 1000.0f;
+
+ le->leType = LE_MOVE_SCALE_FADE;
+ le->startTime = startTime;
+ le->fadeInTime = fadeInTime;
+ le->endTime = startTime + duration;
+ if ( fadeInTime > startTime ) {
+ le->lifeRate = 1.0 / ( le->endTime - le->fadeInTime );
+ }
+ else {
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+ }
+ le->color[0] = r;
+ le->color[1] = g;
+ le->color[2] = b;
+ le->color[3] = a;
+
+
+ le->pos.trType = TR_LINEAR_STOP;
+ le->pos.trTime = startTime;
+ VectorCopy( vel, le->pos.trDelta );
+ VectorCopy( p, le->pos.trBase );
+
+ VectorCopy( p, re->origin );
+ re->customShader = hShader;
+
+ // rage pro can't alpha fade, so use a different shader
+ if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
+ re->customShader = cgs.media.smokePuffRageProShader;
+ re->shaderRGBA[0] = 0xff;
+ re->shaderRGBA[1] = 0xff;
+ re->shaderRGBA[2] = 0xff;
+ re->shaderRGBA[3] = 0xff;
+ } else {
+ re->shaderRGBA[0] = le->color[0] * 0xff;
+ re->shaderRGBA[1] = le->color[1] * 0xff;
+ re->shaderRGBA[2] = le->color[2] * 0xff;
+ re->shaderRGBA[3] = 0xff;
+ }
+
+ re->reType = RT_SPRITE;
+ re->radius = le->radius;
+
+ return le;
+}
+
+// LEILEI same as above, but slows down.......
+localEntity_t *CG_SlowPuff( const vec3_t p, const vec3_t vel,
+ float radius,
+ float r, float g, float b, float a,
+ float duration,
+ int startTime,
+ int fadeInTime,
+ int leFlags,
+ qhandle_t hShader ) {
+ static int seed = 0x92;
+ localEntity_t *le;
+ refEntity_t *re;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = leFlags;
+ le->radius = radius;
+
+ re = &le->refEntity;
+ re->rotation = Q_random( &seed ) * 360;
+ re->radius = radius;
+ re->shaderTime = startTime / 1000.0f;
+
+ le->leType = LE_MOVE_SCALE_FADE;
+ le->startTime = startTime;
+ le->fadeInTime = fadeInTime;
+ le->endTime = startTime + duration;
+ if ( fadeInTime > startTime ) {
+ le->lifeRate = 1.0 / ( le->endTime - le->fadeInTime );
+ }
+ else {
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+ }
+ le->color[0] = r;
+ le->color[1] = g;
+ le->color[2] = b;
+ le->color[3] = a;
+
+
+ le->pos.trType = TR_LINEAR;
+ le->pos.trTime = startTime;
+ VectorCopy( vel, le->pos.trDelta );
+ VectorCopy( p, le->pos.trBase );
+
+ VectorCopy( p, re->origin );
+ re->customShader = hShader;
+
+ // rage pro can't alpha fade, so use a different shader
+ if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
+ re->customShader = cgs.media.smokePuffRageProShader;
+ re->shaderRGBA[0] = 0xff;
+ re->shaderRGBA[1] = 0xff;
+ re->shaderRGBA[2] = 0xff;
+ re->shaderRGBA[3] = 0xff;
+ } else {
+ re->shaderRGBA[0] = le->color[0] * 0xff;
+ re->shaderRGBA[1] = le->color[1] * 0xff;
+ re->shaderRGBA[2] = le->color[2] * 0xff;
+ re->shaderRGBA[3] = 0xff;
+ }
+
+ re->reType = RT_SPRITE;
+ re->radius = le->radius;
+
+ return le;
+}
+
+/*
+==================
+CG_SpawnEffect
+
+Player teleporting in or out
+==================
+*/
+void CG_SpawnEffect( vec3_t org ) {
+ localEntity_t *le;
+ refEntity_t *re;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = 0;
+ le->leType = LE_FADE_RGB;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 500;
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+
+ le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
+
+ re = &le->refEntity;
+
+ re->reType = RT_MODEL;
+ re->shaderTime = cg.time / 1000.0f;
+
+#ifndef MISSIONPACK
+ re->customShader = cgs.media.teleportEffectShader;
+#endif
+ re->hModel = cgs.media.teleportEffectModel;
+ AxisClear( re->axis );
+
+ VectorCopy( org, re->origin );
+#ifdef MISSIONPACK
+ re->origin[2] += 16;
+#else
+ re->origin[2] -= 24;
+#endif
+}
+
+/*
+===============
+CG_LightningBoltBeam
+===============
+*/
+void CG_LightningBoltBeam( vec3_t start, vec3_t end ) {
+ localEntity_t *le;
+ refEntity_t *beam;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = 0;
+ le->leType = LE_SHOWREFENTITY;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 50;
+
+ beam = &le->refEntity;
+
+ VectorCopy( start, beam->origin );
+ // this is the end point
+ VectorCopy( end, beam->oldorigin );
+
+ beam->reType = RT_LIGHTNING;
+ beam->customShader = cgs.media.lightningShader;
+}
+
+/*
+==================
+CG_KamikazeEffect
+==================
+*/
+void CG_KamikazeEffect( vec3_t org ) {
+ localEntity_t *le;
+ refEntity_t *re;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = 0;
+ le->leType = LE_KAMIKAZE;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 3000;//2250;
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+
+ le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
+
+ VectorClear(le->angles.trBase);
+
+ re = &le->refEntity;
+
+ re->reType = RT_MODEL;
+ re->shaderTime = cg.time / 1000.0f;
+
+ re->hModel = cgs.media.kamikazeEffectModel;
+
+ VectorCopy( org, re->origin );
+
+}
+
+/*
+==================
+CG_ObeliskExplode
+==================
+*/
+void CG_ObeliskExplode( vec3_t org, int entityNum ) {
+ localEntity_t *le;
+ vec3_t origin;
+
+ // create an explosion
+ VectorCopy( org, origin );
+ origin[2] += 64;
+ le = CG_MakeExplosion( origin, vec3_origin,
+ cgs.media.dishFlashModel,
+ cgs.media.rocketExplosionShader,
+ 600, qtrue );
+ le->light = 300;
+ le->lightColor[0] = 1;
+ le->lightColor[1] = 0.75;
+ le->lightColor[2] = 0.0;
+}
+
+/*
+==================
+CG_ObeliskPain
+==================
+*/
+void CG_ObeliskPain( vec3_t org ) {
+ float r;
+ sfxHandle_t sfx;
+
+ // hit sound
+ r = rand() & 3;
+ if ( r < 2 ) {
+ sfx = cgs.media.obeliskHitSound1;
+ } else if ( r == 2 ) {
+ sfx = cgs.media.obeliskHitSound2;
+ } else {
+ sfx = cgs.media.obeliskHitSound3;
+ }
+ trap_S_StartSound ( org, ENTITYNUM_NONE, CHAN_BODY, sfx );
+}
+
+
+/*
+==================
+CG_InvulnerabilityImpact
+==================
+*/
+void CG_InvulnerabilityImpact( vec3_t org, vec3_t angles ) {
+ localEntity_t *le;
+ refEntity_t *re;
+ int r;
+ sfxHandle_t sfx;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = 0;
+ le->leType = LE_INVULIMPACT;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 1000;
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+
+ le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
+
+ re = &le->refEntity;
+
+ re->reType = RT_MODEL;
+ re->shaderTime = cg.time / 1000.0f;
+
+ re->hModel = cgs.media.invulnerabilityImpactModel;
+
+ VectorCopy( org, re->origin );
+ AnglesToAxis( angles, re->axis );
+
+ r = rand() & 3;
+ if ( r < 2 ) {
+ sfx = cgs.media.invulnerabilityImpactSound1;
+ } else if ( r == 2 ) {
+ sfx = cgs.media.invulnerabilityImpactSound2;
+ } else {
+ sfx = cgs.media.invulnerabilityImpactSound3;
+ }
+ trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, sfx );
+}
+
+/*
+==================
+CG_InvulnerabilityJuiced
+==================
+*/
+void CG_InvulnerabilityJuiced( vec3_t org ) {
+ localEntity_t *le;
+ refEntity_t *re;
+ vec3_t angles;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = 0;
+ le->leType = LE_INVULJUICED;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 10000;
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+
+ le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
+
+ re = &le->refEntity;
+
+ re->reType = RT_MODEL;
+ re->shaderTime = cg.time / 1000.0f;
+
+ re->hModel = cgs.media.invulnerabilityJuicedModel;
+
+ VectorCopy( org, re->origin );
+ VectorClear(angles);
+ AnglesToAxis( angles, re->axis );
+
+ trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, cgs.media.invulnerabilityJuicedSound );
+}
+
+/*
+==================
+CG_ScorePlum
+==================
+*/
+void CG_ScorePlum( int client, vec3_t org, int score ) {
+ localEntity_t *le;
+ refEntity_t *re;
+ vec3_t angles;
+ static vec3_t lastPos;
+
+ // only visualize for the client that scored
+ if (client != cg.predictedPlayerState.clientNum || cg_scorePlum.integer == 0) {
+ return;
+ }
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = 0;
+ le->leType = LE_SCOREPLUM;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 4000;
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+
+
+ le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
+ le->radius = score;
+
+ VectorCopy( org, le->pos.trBase );
+ if (org[2] >= lastPos[2] - 20 && org[2] <= lastPos[2] + 20) {
+ le->pos.trBase[2] -= 20;
+ }
+
+ //CG_Printf( "Plum origin %i %i %i -- %i\n", (int)org[0], (int)org[1], (int)org[2], (int)Distance(org, lastPos));
+ VectorCopy(org, lastPos);
+
+
+ re = &le->refEntity;
+
+ re->reType = RT_SPRITE;
+ re->radius = 16;
+
+ VectorClear(angles);
+ AnglesToAxis( angles, re->axis );
+}
+
+
+/*
+====================
+CG_MakeExplosion
+====================
+*/
+localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
+ qhandle_t hModel, qhandle_t shader,
+ int msec, qboolean isSprite ) {
+ float ang;
+ localEntity_t *ex;
+ int offset;
+ vec3_t tmpVec, newOrigin;
+
+ if ( msec <= 0 ) {
+ CG_Error( "CG_MakeExplosion: msec = %i", msec );
+ }
+
+ // skew the time a bit so they aren't all in sync
+ offset = rand() & 63;
+
+ ex = CG_AllocLocalEntity();
+ if ( isSprite ) {
+ ex->leType = LE_SPRITE_EXPLOSION;
+
+ // randomly rotate sprite orientation
+ ex->refEntity.rotation = rand() % 360;
+ VectorScale( dir, 16, tmpVec );
+ VectorAdd( tmpVec, origin, newOrigin );
+ } else {
+ ex->leType = LE_EXPLOSION;
+ VectorCopy( origin, newOrigin );
+
+ // set axis with random rotate
+ if ( !dir ) {
+ AxisClear( ex->refEntity.axis );
+ } else {
+ ang = rand() % 360;
+ VectorCopy( dir, ex->refEntity.axis[0] );
+ RotateAroundDirection( ex->refEntity.axis, ang );
+ }
+ }
+
+ ex->startTime = cg.time - offset;
+ ex->endTime = ex->startTime + msec;
+
+ // bias the time so all shader effects start correctly
+ ex->refEntity.shaderTime = ex->startTime / 1000.0f;
+
+ ex->refEntity.hModel = hModel;
+ ex->refEntity.customShader = shader;
+
+ // set origin
+ VectorCopy( newOrigin, ex->refEntity.origin );
+ VectorCopy( newOrigin, ex->refEntity.oldorigin );
+
+ ex->color[0] = ex->color[1] = ex->color[2] = 1.0;
+
+ return ex;
+}
+
+
+/*
+=================
+CG_Bleed
+
+This is the spurt of blood when a character gets hit
+=================
+*/
+void CG_Bleed( vec3_t origin, int entityNum ) {
+ localEntity_t *ex;
+
+ if ( !cg_blood.integer ) {
+ return;
+ }
+
+ ex = CG_AllocLocalEntity();
+ ex->leType = LE_EXPLOSION;
+
+ ex->startTime = cg.time;
+ ex->endTime = ex->startTime + 500;
+
+ VectorCopy ( origin, ex->refEntity.origin);
+ ex->refEntity.reType = RT_SPRITE;
+ ex->refEntity.rotation = rand() % 360;
+ ex->refEntity.radius = 24;
+
+ ex->refEntity.customShader = cgs.media.bloodExplosionShader;
+
+ // don't show player's own blood in view
+ if ( entityNum == cg.snap->ps.clientNum ) {
+ ex->refEntity.renderfx |= RF_THIRD_PERSON;
+ }
+}
+
+
+
+/*
+==================
+CG_SpurtBlood (LEILEI)
+==================
+*/
+void CG_SpurtBlood( vec3_t origin, vec3_t velocity, int hard ) {
+ localEntity_t *blood;
+// if ( !cg_blood.integer ) { return; }
+
+
+ velocity[0] = velocity[0] * hard * crandom()*460;
+ velocity[1] = velocity[1] * hard * crandom()*460;
+ velocity[2] = velocity[2] * hard * crandom()*566 + 65;
+ blood = CG_SmokePuff( origin, velocity,
+ 21, // radius
+ 1, 1, 1, 1, // color
+ 2450, // trailTime
+ cg.time, // startTime
+ 0, // fadeInTime
+ 0, // flags
+ cgs.media.lbldShader1 );
+ // use the optimized version
+ blood->leType = LE_FALL_SCALE_FADE;
+ blood->leType = LE_GORE;
+ blood->pos.trType = TR_GRAVITY;
+ VectorCopy( velocity, blood->pos.trDelta );
+ blood->pos.trDelta[2] = 55;
+ if (crandom() < 0.5){
+ blood->leMarkType = LEMT_BURN;
+ blood->leBounceSoundType = LEBS_BLOOD;
+ }
+ // VectorCopy( velocity, blood->pos.trDelta );
+
+}
+/*
+==================
+CG_LaunchGib
+==================
+*/
+void CG_LaunchGib( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
+ localEntity_t *le;
+ refEntity_t *re;
+
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+
+ le->leType = LE_FRAGMENT;
+ le->startTime = cg.time;
+ le->endTime = le->startTime + 5000 + random() * 3000;
+
+ VectorCopy( origin, re->origin );
+ AxisCopy( axisDefault, re->axis );
+ re->hModel = hModel;
+
+ le->pos.trType = TR_GRAVITY;
+ VectorCopy( origin, le->pos.trBase );
+ VectorCopy( velocity, le->pos.trDelta );
+ le->pos.trTime = cg.time;
+
+ le->bounceFactor = 0.6f;
+
+ le->leBounceSoundType = LEBS_BLOOD;
+ le->leMarkType = LEMT_BLOOD;
+ if ( cg_leiSuperGoreyAwesome.integer ) {
+ CG_SpurtBlood( origin, velocity, 7); // LEILEI toss some extra juice
+ CG_SpurtBlood( origin, velocity, 22);
+ CG_SpurtBlood( origin, velocity, 11);
+ }
+
+}
+
+
+
+
+
+/*
+===================
+CG_GibPlayer
+
+Generated a bunch of gibs launching out from the bodies location
+===================
+*/
+#define GIB_VELOCITY 250
+#define GIB_JUMP 250
+void CG_GibPlayer( vec3_t playerOrigin ) {
+ vec3_t origin, velocity;
+
+ if ( !cg_blood.integer ) {
+ return;
+ }
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ if ( rand() & 1 ) {
+ CG_LaunchGib( origin, velocity, cgs.media.gibSkull );
+ } else {
+ CG_LaunchGib( origin, velocity, cgs.media.gibBrain );
+ }
+
+ // allow gibs to be turned off for speed
+ if ( !cg_gibs.integer ) {
+ return;
+ }
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibAbdomen );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibArm );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibChest );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibFist );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibFoot );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibForearm );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibIntestine );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
+}
+
+/*
+==================
+CG_LaunchGib
+==================
+*/
+void CG_LaunchExplode( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
+ localEntity_t *le;
+ refEntity_t *re;
+
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+
+ le->leType = LE_FRAGMENT;
+ le->startTime = cg.time;
+ le->endTime = le->startTime + 10000 + random() * 6000;
+
+ VectorCopy( origin, re->origin );
+ AxisCopy( axisDefault, re->axis );
+ re->hModel = hModel;
+
+ le->pos.trType = TR_GRAVITY;
+ VectorCopy( origin, le->pos.trBase );
+ VectorCopy( velocity, le->pos.trDelta );
+ le->pos.trTime = cg.time;
+
+ le->bounceFactor = 0.1f;
+
+ le->leBounceSoundType = LEBS_BRASS;
+ le->leMarkType = LEMT_NONE;
+}
+
+#define EXP_VELOCITY 100
+#define EXP_JUMP 150
+/*
+===================
+CG_GibPlayer
+
+Generated a bunch of gibs launching out from the bodies location
+===================
+*/
+void CG_BigExplosion( vec3_t playerOrigin ) {
+ vec3_t origin, velocity;
+
+ if ( !cg_blood.integer ) {
+ return;
+ }
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*EXP_VELOCITY;
+ velocity[1] = crandom()*EXP_VELOCITY;
+ velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
+ CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*EXP_VELOCITY;
+ velocity[1] = crandom()*EXP_VELOCITY;
+ velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
+ CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*EXP_VELOCITY*1.5;
+ velocity[1] = crandom()*EXP_VELOCITY*1.5;
+ velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
+ CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*EXP_VELOCITY*2.0;
+ velocity[1] = crandom()*EXP_VELOCITY*2.0;
+ velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
+ CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*EXP_VELOCITY*2.5;
+ velocity[1] = crandom()*EXP_VELOCITY*2.5;
+ velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
+ CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
+}
+
+
+
+
+
diff --git a/code/cgame/cg_ents.c b/code/cgame/cg_ents.c
new file mode 100644
index 0000000..a7c95c3
--- /dev/null
+++ b/code/cgame/cg_ents.c
@@ -0,0 +1,1112 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_ents.c -- present snapshot entities, happens every single frame
+
+#include "cg_local.h"
+
+
+/*
+======================
+CG_PositionEntityOnTag
+
+Modifies the entities position and axis by the given
+tag location
+======================
+*/
+void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
+ qhandle_t parentModel, char *tagName ) {
+ int i;
+ orientation_t lerped;
+
+ // lerp the tag
+ trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
+ 1.0 - parent->backlerp, tagName );
+
+ // FIXME: allow origin offsets along tag?
+ VectorCopy( parent->origin, entity->origin );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
+ }
+
+ // had to cast away the const to avoid compiler problems...
+ MatrixMultiply( lerped.axis, ((refEntity_t *)parent)->axis, entity->axis );
+ entity->backlerp = parent->backlerp;
+}
+
+
+/*
+======================
+CG_PositionRotatedEntityOnTag
+
+Modifies the entities position and axis by the given
+tag location
+======================
+*/
+void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
+ qhandle_t parentModel, char *tagName ) {
+ int i;
+ orientation_t lerped;
+ vec3_t tempAxis[3];
+
+//AxisClear( entity->axis );
+ // lerp the tag
+ trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
+ 1.0 - parent->backlerp, tagName );
+
+ // FIXME: allow origin offsets along tag?
+ VectorCopy( parent->origin, entity->origin );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
+ }
+
+ // had to cast away the const to avoid compiler problems...
+ MatrixMultiply( entity->axis, lerped.axis, tempAxis );
+ MatrixMultiply( tempAxis, ((refEntity_t *)parent)->axis, entity->axis );
+}
+
+
+
+/*
+==========================================================================
+
+FUNCTIONS CALLED EACH FRAME
+
+==========================================================================
+*/
+
+/*
+======================
+CG_SetEntitySoundPosition
+
+Also called by event processing code
+======================
+*/
+void CG_SetEntitySoundPosition( centity_t *cent ) {
+ if ( cent->currentState.solid == SOLID_BMODEL ) {
+ vec3_t origin;
+ float *v;
+
+ v = cgs.inlineModelMidpoints[ cent->currentState.modelindex ];
+ VectorAdd( cent->lerpOrigin, v, origin );
+ trap_S_UpdateEntityPosition( cent->currentState.number, origin );
+ } else {
+ trap_S_UpdateEntityPosition( cent->currentState.number, cent->lerpOrigin );
+ }
+}
+
+/*
+==================
+CG_EntityEffects
+
+Add continuous entity effects, like local entity emission and lighting
+==================
+*/
+static void CG_EntityEffects( centity_t *cent ) {
+
+ // update sound origins
+ CG_SetEntitySoundPosition( cent );
+
+ // add loop sound
+ if ( cent->currentState.loopSound ) {
+ if (cent->currentState.eType != ET_SPEAKER) {
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin,
+ cgs.gameSounds[ cent->currentState.loopSound ] );
+ } else {
+ trap_S_AddRealLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin,
+ cgs.gameSounds[ cent->currentState.loopSound ] );
+ }
+ }
+
+
+ // constant light glow
+ if(cent->currentState.constantLight)
+ {
+ int cl;
+ float i, r, g, b;
+
+ cl = cent->currentState.constantLight;
+ r = (float) (cl & 0xFF) / 255.0;
+ g = (float) ((cl >> 8) & 0xFF) / 255.0;
+ b = (float) ((cl >> 16) & 0xFF) / 255.0;
+ i = (float) ((cl >> 24) & 0xFF) * 4.0;
+ trap_R_AddLightToScene(cent->lerpOrigin, i, r, g, b);
+ }
+
+}
+
+
+/*
+==================
+CG_General
+==================
+*/
+static void CG_General( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *s1;
+
+ s1 = ¢->currentState;
+
+ // if set to invisible, skip
+ if (!s1->modelindex) {
+ return;
+ }
+
+ memset (&ent, 0, sizeof(ent));
+
+ // set frame
+
+ ent.frame = s1->frame;
+ ent.oldframe = ent.frame;
+ ent.backlerp = 0;
+
+ VectorCopy( cent->lerpOrigin, ent.origin);
+ VectorCopy( cent->lerpOrigin, ent.oldorigin);
+
+ ent.hModel = cgs.gameModels[s1->modelindex];
+
+ // player model
+ if (s1->number == cg.snap->ps.clientNum) {
+ ent.renderfx |= RF_THIRD_PERSON; // only draw from mirrors
+ }
+
+ // convert angles to axis
+ AnglesToAxis( cent->lerpAngles, ent.axis );
+
+ // add to refresh list
+ trap_R_AddRefEntityToScene (&ent);
+}
+
+/*
+==================
+CG_Speaker
+
+Speaker entities can automatically play sounds
+==================
+*/
+static void CG_Speaker( centity_t *cent ) {
+ if ( ! cent->currentState.clientNum ) { // FIXME: use something other than clientNum...
+ return; // not auto triggering
+ }
+
+ if ( cg.time < cent->miscTime ) {
+ return;
+ }
+
+ trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.gameSounds[cent->currentState.eventParm] );
+
+ // ent->s.frame = ent->wait * 10;
+ // ent->s.clientNum = ent->random * 10;
+ cent->miscTime = cg.time + cent->currentState.frame * 100 + cent->currentState.clientNum * 100 * crandom();
+}
+
+/*
+==================
+CG_Item
+==================
+*/
+static void CG_Item( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *es;
+ gitem_t *item;
+ int msec;
+ float frac;
+ float scale;
+ weaponInfo_t *wi;
+
+ es = ¢->currentState;
+ if ( es->modelindex >= bg_numItems ) {
+ CG_Error( "Bad item index %i on entity", es->modelindex );
+ }
+
+ // if set to invisible, skip
+ if ( !es->modelindex || ( es->eFlags & EF_NODRAW ) ) {
+ return;
+ }
+
+ item = &bg_itemlist[ es->modelindex ];
+ if ( cg_simpleItems.integer && item->giType != IT_TEAM ) {
+ memset( &ent, 0, sizeof( ent ) );
+ ent.reType = RT_SPRITE;
+ VectorCopy( cent->lerpOrigin, ent.origin );
+ ent.radius = 14;
+ ent.customShader = cg_items[es->modelindex].icon;
+ ent.shaderRGBA[0] = 255;
+ ent.shaderRGBA[1] = 255;
+ ent.shaderRGBA[2] = 255;
+ ent.shaderRGBA[3] = 255;
+ trap_R_AddRefEntityToScene(&ent);
+ return;
+ }
+
+ // items bob up and down continuously
+ scale = 0.005 + cent->currentState.number * 0.00001;
+ cent->lerpOrigin[2] += 4 + cos( ( cg.time + 1000 ) * scale ) * 4;
+
+ memset (&ent, 0, sizeof(ent));
+
+ // autorotate at one of two speeds
+ if ( item->giType == IT_HEALTH ) {
+ VectorCopy( cg.autoAnglesFast, cent->lerpAngles );
+ AxisCopy( cg.autoAxisFast, ent.axis );
+ } else {
+ VectorCopy( cg.autoAngles, cent->lerpAngles );
+ AxisCopy( cg.autoAxis, ent.axis );
+ }
+
+ wi = NULL;
+ // the weapons have their origin where they attatch to player
+ // models, so we need to offset them or they will rotate
+ // eccentricly
+ if ( item->giType == IT_WEAPON ) {
+ wi = &cg_weapons[item->giTag];
+ cent->lerpOrigin[0] -=
+ wi->weaponMidpoint[0] * ent.axis[0][0] +
+ wi->weaponMidpoint[1] * ent.axis[1][0] +
+ wi->weaponMidpoint[2] * ent.axis[2][0];
+ cent->lerpOrigin[1] -=
+ wi->weaponMidpoint[0] * ent.axis[0][1] +
+ wi->weaponMidpoint[1] * ent.axis[1][1] +
+ wi->weaponMidpoint[2] * ent.axis[2][1];
+ cent->lerpOrigin[2] -=
+ wi->weaponMidpoint[0] * ent.axis[0][2] +
+ wi->weaponMidpoint[1] * ent.axis[1][2] +
+ wi->weaponMidpoint[2] * ent.axis[2][2];
+
+ cent->lerpOrigin[2] += 8; // an extra height boost
+ }
+
+ ent.hModel = cg_items[es->modelindex].models[0];
+
+ VectorCopy( cent->lerpOrigin, ent.origin);
+ VectorCopy( cent->lerpOrigin, ent.oldorigin);
+
+ ent.nonNormalizedAxes = qfalse;
+
+ // if just respawned, slowly scale up
+ msec = cg.time - cent->miscTime;
+ if ( msec >= 0 && msec < ITEM_SCALEUP_TIME ) {
+ frac = (float)msec / ITEM_SCALEUP_TIME;
+ VectorScale( ent.axis[0], frac, ent.axis[0] );
+ VectorScale( ent.axis[1], frac, ent.axis[1] );
+ VectorScale( ent.axis[2], frac, ent.axis[2] );
+ ent.nonNormalizedAxes = qtrue;
+ } else {
+ frac = 1.0;
+ }
+
+ // items without glow textures need to keep a minimum light value
+ // so they are always visible
+ if ( ( item->giType == IT_WEAPON ) ||
+ ( item->giType == IT_ARMOR ) ) {
+ ent.renderfx |= RF_MINLIGHT;
+ }
+
+ // increase the size of the weapons when they are presented as items
+ if ( item->giType == IT_WEAPON ) {
+ VectorScale( ent.axis[0], 1.5, ent.axis[0] );
+ VectorScale( ent.axis[1], 1.5, ent.axis[1] );
+ VectorScale( ent.axis[2], 1.5, ent.axis[2] );
+ ent.nonNormalizedAxes = qtrue;
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.weaponHoverSound );
+ }
+
+ if ( item->giType == IT_HOLDABLE && item->giTag == HI_KAMIKAZE ) {
+ VectorScale( ent.axis[0], 2, ent.axis[0] );
+ VectorScale( ent.axis[1], 2, ent.axis[1] );
+ VectorScale( ent.axis[2], 2, ent.axis[2] );
+ ent.nonNormalizedAxes = qtrue;
+ }
+
+ // add to refresh list
+ trap_R_AddRefEntityToScene(&ent);
+
+ if ( item->giType == IT_WEAPON && wi->barrelModel ) {
+ refEntity_t barrel;
+
+ memset( &barrel, 0, sizeof( barrel ) );
+
+ barrel.hModel = wi->barrelModel;
+
+ VectorCopy( ent.lightingOrigin, barrel.lightingOrigin );
+ barrel.shadowPlane = ent.shadowPlane;
+ barrel.renderfx = ent.renderfx;
+
+ CG_PositionRotatedEntityOnTag( &barrel, &ent, wi->weaponModel, "tag_barrel" );
+
+ AxisCopy( ent.axis, barrel.axis );
+ barrel.nonNormalizedAxes = ent.nonNormalizedAxes;
+
+ trap_R_AddRefEntityToScene( &barrel );
+ }
+
+ // accompanying rings / spheres for powerups
+ if ( !cg_simpleItems.integer )
+ {
+ vec3_t spinAngles;
+
+ VectorClear( spinAngles );
+
+ if ( item->giType == IT_HEALTH || item->giType == IT_POWERUP )
+ {
+ if ( ( ent.hModel = cg_items[es->modelindex].models[1] ) != 0 )
+ {
+ if ( item->giType == IT_POWERUP )
+ {
+ ent.origin[2] += 12;
+ spinAngles[1] = ( cg.time & 1023 ) * 360 / -1024.0f;
+ }
+ AnglesToAxis( spinAngles, ent.axis );
+
+ // scale up if respawning
+ if ( frac != 1.0 ) {
+ VectorScale( ent.axis[0], frac, ent.axis[0] );
+ VectorScale( ent.axis[1], frac, ent.axis[1] );
+ VectorScale( ent.axis[2], frac, ent.axis[2] );
+ ent.nonNormalizedAxes = qtrue;
+ }
+ trap_R_AddRefEntityToScene( &ent );
+ }
+ }
+ }
+}
+
+//============================================================================
+
+/*
+===============
+CG_Missile
+===============
+*/
+static void CG_Missile( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *s1;
+ const weaponInfo_t *weapon;
+// int col;
+
+ s1 = ¢->currentState;
+ if ( s1->weapon >= WP_NUM_WEAPONS ) {
+ s1->weapon = 0;
+ }
+ weapon = &cg_weapons[s1->weapon];
+
+ // calculate the axis
+ VectorCopy( s1->angles, cent->lerpAngles);
+
+ // add trails
+ if ( weapon->missileTrailFunc )
+ {
+ weapon->missileTrailFunc( cent, weapon );
+ }
+/*
+ if ( cent->currentState.modelindex == TEAM_RED ) {
+ col = 1;
+ }
+ else if ( cent->currentState.modelindex == TEAM_BLUE ) {
+ col = 2;
+ }
+ else {
+ col = 0;
+ }
+
+ // add dynamic light
+ if ( weapon->missileDlight ) {
+ trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight,
+ weapon->missileDlightColor[col][0], weapon->missileDlightColor[col][1], weapon->missileDlightColor[col][2] );
+ }
+*/
+ // add dynamic light
+ if ( weapon->missileDlight ) {
+ trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight,
+ weapon->missileDlightColor[0], weapon->missileDlightColor[1], weapon->missileDlightColor[2] );
+ }
+
+ // add missile sound
+ if ( weapon->missileSound ) {
+ vec3_t velocity;
+
+ BG_EvaluateTrajectoryDelta( ¢->currentState.pos, cg.time, velocity );
+
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, weapon->missileSound );
+ }
+
+ // create the render entity
+ memset (&ent, 0, sizeof(ent));
+ VectorCopy( cent->lerpOrigin, ent.origin);
+ VectorCopy( cent->lerpOrigin, ent.oldorigin);
+
+ if ( cent->currentState.weapon == WP_PLASMAGUN ) {
+ ent.reType = RT_SPRITE;
+ ent.radius = 16;
+ ent.rotation = 0;
+ ent.customShader = cgs.media.plasmaBallShader;
+ trap_R_AddRefEntityToScene( &ent );
+ return;
+ }
+
+ // flicker between two skins
+ ent.skinNum = cg.clientFrame & 1;
+ ent.hModel = weapon->missileModel;
+ ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
+
+//#ifdef MISSIONPACK
+ if ( cent->currentState.weapon == WP_PROX_LAUNCHER ) {
+ if (s1->generic1 == TEAM_BLUE) {
+ ent.hModel = cgs.media.blueProxMine;
+ }
+ }
+//#endif
+
+ // convert direction of travel into axis
+ if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {
+ ent.axis[0][2] = 1;
+ }
+
+ // spin as it moves
+ if ( s1->pos.trType != TR_STATIONARY ) {
+ RotateAroundDirection( ent.axis, cg.time / 4 );
+ } else {
+//#ifdef MISSIONPACK
+ if ( s1->weapon == WP_PROX_LAUNCHER ) {
+ AnglesToAxis( cent->lerpAngles, ent.axis );
+ }
+ else
+//#endif
+ {
+ RotateAroundDirection( ent.axis, s1->time );
+ }
+ }
+
+ // add to refresh list, possibly with quad glow
+ CG_AddRefEntityWithPowerups( &ent, s1, TEAM_FREE, qtrue );
+}
+
+/*
+===============
+CG_Grapple
+
+This is called when the grapple is sitting up against the wall
+===============
+*/
+static void CG_Grapple( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *s1;
+ const weaponInfo_t *weapon;
+
+ s1 = ¢->currentState;
+ if ( s1->weapon >= WP_NUM_WEAPONS ) {
+ s1->weapon = 0;
+ }
+ weapon = &cg_weapons[s1->weapon];
+
+ // calculate the axis
+ VectorCopy( s1->angles, cent->lerpAngles);
+
+ // FIXME add grapple pull sound here..?
+ // add missile sound
+ if ( weapon->missileSound ) {
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->missileSound );
+ }
+
+
+ // Will draw cable if needed
+ CG_GrappleTrail ( cent, weapon );
+
+ // create the render entity
+ memset (&ent, 0, sizeof(ent));
+ VectorCopy( cent->lerpOrigin, ent.origin);
+ VectorCopy( cent->lerpOrigin, ent.oldorigin);
+
+ // flicker between two skins
+ ent.skinNum = cg.clientFrame & 1;
+ ent.hModel = weapon->missileModel;
+ ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
+
+ // convert direction of travel into axis
+ if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {
+ ent.axis[0][2] = 1;
+ }
+
+ trap_R_AddRefEntityToScene( &ent );
+}
+
+/*
+===============
+CG_Mover
+===============
+*/
+static void CG_Mover( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *s1;
+
+ s1 = ¢->currentState;
+
+ // create the render entity
+ memset (&ent, 0, sizeof(ent));
+ VectorCopy( cent->lerpOrigin, ent.origin);
+ VectorCopy( cent->lerpOrigin, ent.oldorigin);
+ AnglesToAxis( cent->lerpAngles, ent.axis );
+
+ ent.renderfx = RF_NOSHADOW;
+
+ // flicker between two skins (FIXME?)
+ ent.skinNum = ( cg.time >> 6 ) & 1;
+
+ // get the model, either as a bmodel or a modelindex
+ if ( s1->solid == SOLID_BMODEL ) {
+ ent.hModel = cgs.inlineDrawModel[s1->modelindex];
+ } else {
+ ent.hModel = cgs.gameModels[s1->modelindex];
+ }
+
+ // add to refresh list
+ trap_R_AddRefEntityToScene(&ent);
+
+ // add the secondary model
+ if ( s1->modelindex2 ) {
+ ent.skinNum = 0;
+ ent.hModel = cgs.gameModels[s1->modelindex2];
+ trap_R_AddRefEntityToScene(&ent);
+ }
+
+}
+
+/*
+===============
+CG_Beam
+
+Also called as an event
+===============
+*/
+void CG_Beam( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *s1;
+
+ s1 = ¢->currentState;
+
+ // create the render entity
+ memset (&ent, 0, sizeof(ent));
+ VectorCopy( s1->pos.trBase, ent.origin );
+ VectorCopy( s1->origin2, ent.oldorigin );
+ AxisClear( ent.axis );
+ ent.reType = RT_BEAM;
+
+ ent.renderfx = RF_NOSHADOW;
+
+ // add to refresh list
+ trap_R_AddRefEntityToScene(&ent);
+}
+
+
+/*
+===============
+CG_Portal
+===============
+*/
+static void CG_Portal( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *s1;
+
+ s1 = ¢->currentState;
+
+ // create the render entity
+ memset (&ent, 0, sizeof(ent));
+ VectorCopy( cent->lerpOrigin, ent.origin );
+ VectorCopy( s1->origin2, ent.oldorigin );
+ ByteToDir( s1->eventParm, ent.axis[0] );
+ PerpendicularVector( ent.axis[1], ent.axis[0] );
+
+ // negating this tends to get the directions like they want
+ // we really should have a camera roll value
+ VectorSubtract( vec3_origin, ent.axis[1], ent.axis[1] );
+
+ CrossProduct( ent.axis[0], ent.axis[1], ent.axis[2] );
+ ent.reType = RT_PORTALSURFACE;
+ ent.oldframe = s1->powerups;
+ ent.frame = s1->frame; // rotation speed
+ ent.skinNum = s1->clientNum/256.0 * 360; // roll offset
+
+ // add to refresh list
+ trap_R_AddRefEntityToScene(&ent);
+}
+
+
+/*
+=========================
+CG_AdjustPositionForMover
+
+Also called by client movement prediction code
+=========================
+*/
+void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out ) {
+ centity_t *cent;
+ vec3_t oldOrigin, origin, deltaOrigin;
+ vec3_t oldAngles, angles, deltaAngles;
+
+ if ( moverNum <= 0 || moverNum >= ENTITYNUM_MAX_NORMAL ) {
+ VectorCopy( in, out );
+ return;
+ }
+
+ cent = &cg_entities[ moverNum ];
+ if ( cent->currentState.eType != ET_MOVER ) {
+ VectorCopy( in, out );
+ return;
+ }
+
+ BG_EvaluateTrajectory( ¢->currentState.pos, fromTime, oldOrigin );
+ BG_EvaluateTrajectory( ¢->currentState.apos, fromTime, oldAngles );
+
+ BG_EvaluateTrajectory( ¢->currentState.pos, toTime, origin );
+ BG_EvaluateTrajectory( ¢->currentState.apos, toTime, angles );
+
+ VectorSubtract( origin, oldOrigin, deltaOrigin );
+ VectorSubtract( angles, oldAngles, deltaAngles );
+
+ VectorAdd( in, deltaOrigin, out );
+
+ // FIXME: origin change when on a rotating object
+}
+
+
+/*
+=============================
+CG_InterpolateEntityPosition
+=============================
+*/
+static void CG_InterpolateEntityPosition( centity_t *cent ) {
+ vec3_t current, next;
+ float f;
+
+ // it would be an internal error to find an entity that interpolates without
+ // a snapshot ahead of the current one
+ if ( cg.nextSnap == NULL ) {
+ CG_Error( "CG_InterpoateEntityPosition: cg.nextSnap == NULL" );
+ }
+
+ f = cg.frameInterpolation;
+
+ // this will linearize a sine or parabolic curve, but it is important
+ // to not extrapolate player positions if more recent data is available
+ BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, current );
+ BG_EvaluateTrajectory( ¢->nextState.pos, cg.nextSnap->serverTime, next );
+
+ cent->lerpOrigin[0] = current[0] + f * ( next[0] - current[0] );
+ cent->lerpOrigin[1] = current[1] + f * ( next[1] - current[1] );
+ cent->lerpOrigin[2] = current[2] + f * ( next[2] - current[2] );
+
+ BG_EvaluateTrajectory( ¢->currentState.apos, cg.snap->serverTime, current );
+ BG_EvaluateTrajectory( ¢->nextState.apos, cg.nextSnap->serverTime, next );
+
+ cent->lerpAngles[0] = LerpAngle( current[0], next[0], f );
+ cent->lerpAngles[1] = LerpAngle( current[1], next[1], f );
+ cent->lerpAngles[2] = LerpAngle( current[2], next[2], f );
+
+}
+
+/*
+===============
+CG_CalcEntityLerpPositions
+
+===============
+*/
+static void CG_CalcEntityLerpPositions( centity_t *cent ) {
+
+//unlagged - projectile nudge
+ // this will be set to how far forward projectiles will be extrapolated
+ int timeshift = 0;
+//unlagged - projectile nudge
+
+//unlagged - smooth clients #2
+ // this is done server-side now - cg_smoothClients is undefined
+ // players will always be TR_INTERPOLATE
+/*
+ // if this player does not want to see extrapolated players
+ if ( !cg_smoothClients.integer ) {
+ // make sure the clients use TR_INTERPOLATE
+ if ( cent->currentState.number < MAX_CLIENTS ) {
+ cent->currentState.pos.trType = TR_INTERPOLATE;
+ cent->nextState.pos.trType = TR_INTERPOLATE;
+ }
+ }
+*/
+//unlagged - smooth clients #2
+
+ if ( cent->interpolate && cent->currentState.pos.trType == TR_INTERPOLATE ) {
+ CG_InterpolateEntityPosition( cent );
+ return;
+ }
+
+ // first see if we can interpolate between two snaps for
+ // linear extrapolated clients
+ if ( cent->interpolate && cent->currentState.pos.trType == TR_LINEAR_STOP &&
+ cent->currentState.number < MAX_CLIENTS) {
+ CG_InterpolateEntityPosition( cent );
+ return;
+ }
+
+//unlagged - timenudge extrapolation
+ // interpolating failed (probably no nextSnap), so extrapolate
+ // this can also happen if the teleport bit is flipped, but that
+ // won't be noticeable
+ if ( cent->currentState.number < MAX_CLIENTS &&
+ cent->currentState.clientNum != cg.predictedPlayerState.clientNum ) {
+ cent->currentState.pos.trType = TR_LINEAR_STOP;
+ cent->currentState.pos.trTime = cg.snap->serverTime;
+ cent->currentState.pos.trDuration = 1000 / sv_fps.integer;
+ }
+//unlagged - timenudge extrapolation
+
+//unlagged - projectile nudge
+ // if it's a missile but not a grappling hook
+ if ( cent->currentState.eType == ET_MISSILE && cent->currentState.weapon != WP_GRAPPLING_HOOK ) {
+ // if it's one of ours
+ if ( cent->currentState.otherEntityNum == cg.clientNum ) {
+ // extrapolate one server frame's worth - this will correct for tiny
+ // visual inconsistencies introduced by backward-reconciling all players
+ // one server frame before running projectiles
+ timeshift = 1000 / sv_fps.integer;
+ }
+ // if it's not, and it's not a grenade launcher
+ else if ( cent->currentState.weapon != WP_GRENADE_LAUNCHER ) {
+ // extrapolate based on cg_projectileNudge
+ timeshift = cg_projectileNudge.integer + 1000 / sv_fps.integer;
+ }
+ }
+
+ // just use the current frame and evaluate as best we can
+// BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin );
+// BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles );
+ BG_EvaluateTrajectory( ¢->currentState.pos, cg.time + timeshift, cent->lerpOrigin );
+ BG_EvaluateTrajectory( ¢->currentState.apos, cg.time + timeshift, cent->lerpAngles );
+
+ // if there's a time shift
+ if ( timeshift != 0 ) {
+ trace_t tr;
+ vec3_t lastOrigin;
+
+ BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, lastOrigin );
+
+ CG_Trace( &tr, lastOrigin, vec3_origin, vec3_origin, cent->lerpOrigin, cent->currentState.number, MASK_SHOT );
+
+ // don't let the projectile go through the floor
+ if ( tr.fraction < 1.0f ) {
+ cent->lerpOrigin[0] = lastOrigin[0] + tr.fraction * ( cent->lerpOrigin[0] - lastOrigin[0] );
+ cent->lerpOrigin[1] = lastOrigin[1] + tr.fraction * ( cent->lerpOrigin[1] - lastOrigin[1] );
+ cent->lerpOrigin[2] = lastOrigin[2] + tr.fraction * ( cent->lerpOrigin[2] - lastOrigin[2] );
+ }
+ }
+//unlagged - projectile nudge
+
+ // adjust for riding a mover if it wasn't rolled into the predicted
+ // player state
+ if ( cent != &cg.predictedPlayerEntity ) {
+ CG_AdjustPositionForMover( cent->lerpOrigin, cent->currentState.groundEntityNum,
+ cg.snap->serverTime, cg.time, cent->lerpOrigin );
+ }
+}
+
+/*
+===============
+CG_TeamBase
+===============
+*/
+static void CG_TeamBase( centity_t *cent ) {
+ refEntity_t model;
+//#ifdef MISSIONPACK
+ vec3_t angles;
+ int t, h;
+ float c;
+
+ if ( cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF ) {
+//#else
+// if ( cgs.gametype == GT_CTF) {
+//#endif
+ // show the flag base
+ memset(&model, 0, sizeof(model));
+ model.reType = RT_MODEL;
+ VectorCopy( cent->lerpOrigin, model.lightingOrigin );
+ VectorCopy( cent->lerpOrigin, model.origin );
+ AnglesToAxis( cent->currentState.angles, model.axis );
+ if ( cent->currentState.modelindex == TEAM_RED ) {
+ model.hModel = cgs.media.redFlagBaseModel;
+ }
+ else if ( cent->currentState.modelindex == TEAM_BLUE ) {
+ model.hModel = cgs.media.blueFlagBaseModel;
+ }
+ else {
+ model.hModel = cgs.media.neutralFlagBaseModel;
+ }
+ trap_R_AddRefEntityToScene( &model );
+ }
+//#ifdef MISSIONPACK
+ else if ( cgs.gametype == GT_OBELISK ) {
+ // show the obelisk
+ memset(&model, 0, sizeof(model));
+ model.reType = RT_MODEL;
+ VectorCopy( cent->lerpOrigin, model.lightingOrigin );
+ VectorCopy( cent->lerpOrigin, model.origin );
+ AnglesToAxis( cent->currentState.angles, model.axis );
+
+ model.hModel = cgs.media.overloadBaseModel;
+ trap_R_AddRefEntityToScene( &model );
+ // if hit
+ if ( cent->currentState.frame == 1) {
+ // show hit model
+ // modelindex2 is the health value of the obelisk
+ c = cent->currentState.modelindex2;
+ model.shaderRGBA[0] = 0xff;
+ model.shaderRGBA[1] = c;
+ model.shaderRGBA[2] = c;
+ model.shaderRGBA[3] = 0xff;
+ //
+ model.hModel = cgs.media.overloadEnergyModel;
+ trap_R_AddRefEntityToScene( &model );
+ }
+ // if respawning
+ if ( cent->currentState.frame == 2) {
+ if ( !cent->miscTime ) {
+ cent->miscTime = cg.time;
+ }
+ t = cg.time - cent->miscTime;
+ h = (cg_obeliskRespawnDelay.integer - 5) * 1000;
+ //
+ if (t > h) {
+ c = (float) (t - h) / h;
+ if (c > 1)
+ c = 1;
+ }
+ else {
+ c = 0;
+ }
+ // show the lights
+ AnglesToAxis( cent->currentState.angles, model.axis );
+ //
+ model.shaderRGBA[0] = c * 0xff;
+ model.shaderRGBA[1] = c * 0xff;
+ model.shaderRGBA[2] = c * 0xff;
+ model.shaderRGBA[3] = c * 0xff;
+
+ model.hModel = cgs.media.overloadLightsModel;
+ trap_R_AddRefEntityToScene( &model );
+ // show the target
+ if (t > h) {
+ if ( !cent->muzzleFlashTime ) {
+ trap_S_StartSound (cent->lerpOrigin, ENTITYNUM_NONE, CHAN_BODY, cgs.media.obeliskRespawnSound);
+ cent->muzzleFlashTime = 1;
+ }
+ VectorCopy(cent->currentState.angles, angles);
+ angles[YAW] += (float) 16 * acos(1-c) * 180 / M_PI;
+ AnglesToAxis( angles, model.axis );
+
+ VectorScale( model.axis[0], c, model.axis[0]);
+ VectorScale( model.axis[1], c, model.axis[1]);
+ VectorScale( model.axis[2], c, model.axis[2]);
+
+ model.shaderRGBA[0] = 0xff;
+ model.shaderRGBA[1] = 0xff;
+ model.shaderRGBA[2] = 0xff;
+ model.shaderRGBA[3] = 0xff;
+ //
+ model.origin[2] += 56;
+ model.hModel = cgs.media.overloadTargetModel;
+ trap_R_AddRefEntityToScene( &model );
+ }
+ else {
+ //FIXME: show animated smoke
+ }
+ }
+ else {
+ cent->miscTime = 0;
+ cent->muzzleFlashTime = 0;
+ // modelindex2 is the health value of the obelisk
+ c = cent->currentState.modelindex2;
+ model.shaderRGBA[0] = 0xff;
+ model.shaderRGBA[1] = c;
+ model.shaderRGBA[2] = c;
+ model.shaderRGBA[3] = 0xff;
+ // show the lights
+ model.hModel = cgs.media.overloadLightsModel;
+ trap_R_AddRefEntityToScene( &model );
+ // show the target
+ model.origin[2] += 56;
+ model.hModel = cgs.media.overloadTargetModel;
+ trap_R_AddRefEntityToScene( &model );
+ }
+ }
+ else if ( cgs.gametype == GT_HARVESTER ) {
+ // show harvester model
+ memset(&model, 0, sizeof(model));
+ model.reType = RT_MODEL;
+ VectorCopy( cent->lerpOrigin, model.lightingOrigin );
+ VectorCopy( cent->lerpOrigin, model.origin );
+ AnglesToAxis( cent->currentState.angles, model.axis );
+
+ if ( cent->currentState.modelindex == TEAM_RED ) {
+ model.hModel = cgs.media.harvesterModel;
+ model.customSkin = cgs.media.harvesterRedSkin;
+ }
+ else if ( cent->currentState.modelindex == TEAM_BLUE ) {
+ model.hModel = cgs.media.harvesterModel;
+ model.customSkin = cgs.media.harvesterBlueSkin;
+ }
+ else {
+ model.hModel = cgs.media.harvesterNeutralModel;
+ model.customSkin = 0;
+ }
+ trap_R_AddRefEntityToScene( &model );
+ }
+//#endif
+}
+
+/*
+===============
+CG_AddCEntity
+
+===============
+*/
+static void CG_AddCEntity( centity_t *cent ) {
+ // event-only entities will have been dealt with already
+ if ( cent->currentState.eType >= ET_EVENTS ) {
+ return;
+ }
+
+ // calculate the current origin
+ CG_CalcEntityLerpPositions( cent );
+
+ // add automatic effects
+ CG_EntityEffects( cent );
+
+ switch ( cent->currentState.eType ) {
+ default:
+ CG_Error( "Bad entity type: %i\n", cent->currentState.eType );
+ break;
+ case ET_INVISIBLE:
+ case ET_PUSH_TRIGGER:
+ case ET_TELEPORT_TRIGGER:
+ break;
+ case ET_GENERAL:
+ CG_General( cent );
+ break;
+ case ET_PLAYER:
+ CG_Player( cent );
+ break;
+ case ET_ITEM:
+ CG_Item( cent );
+ break;
+ case ET_MISSILE:
+ CG_Missile( cent );
+ break;
+ case ET_MOVER:
+ CG_Mover( cent );
+ break;
+ case ET_BEAM:
+ CG_Beam( cent );
+ break;
+ case ET_PORTAL:
+ CG_Portal( cent );
+ break;
+ case ET_SPEAKER:
+ CG_Speaker( cent );
+ break;
+ case ET_GRAPPLE:
+ CG_Grapple( cent );
+ break;
+ case ET_TEAM:
+ CG_TeamBase( cent );
+ break;
+ }
+}
+
+/*
+===============
+CG_AddPacketEntities
+
+===============
+*/
+void CG_AddPacketEntities( void ) {
+ int num;
+ centity_t *cent;
+ playerState_t *ps;
+
+ // set cg.frameInterpolation
+ if ( cg.nextSnap ) {
+ int delta;
+
+ delta = (cg.nextSnap->serverTime - cg.snap->serverTime);
+ if ( delta == 0 ) {
+ cg.frameInterpolation = 0;
+ } else {
+ cg.frameInterpolation = (float)( cg.time - cg.snap->serverTime ) / delta;
+ }
+ } else {
+ cg.frameInterpolation = 0; // actually, it should never be used, because
+ // no entities should be marked as interpolating
+ }
+
+ // the auto-rotating items will all have the same axis
+ cg.autoAngles[0] = 0;
+ cg.autoAngles[1] = ( cg.time & 2047 ) * 360 / 2048.0;
+ cg.autoAngles[2] = 0;
+
+ cg.autoAnglesFast[0] = 0;
+ cg.autoAnglesFast[1] = ( cg.time & 1023 ) * 360 / 1024.0f;
+ cg.autoAnglesFast[2] = 0;
+
+ AnglesToAxis( cg.autoAngles, cg.autoAxis );
+ AnglesToAxis( cg.autoAnglesFast, cg.autoAxisFast );
+
+ // generate and add the entity from the playerstate
+ ps = &cg.predictedPlayerState;
+ BG_PlayerStateToEntityState( ps, &cg.predictedPlayerEntity.currentState, qfalse );
+ CG_AddCEntity( &cg.predictedPlayerEntity );
+
+ // lerp the non-predicted value for lightning gun origins
+ CG_CalcEntityLerpPositions( &cg_entities[ cg.snap->ps.clientNum ] );
+
+//unlagged - early transitioning
+ if ( cg.nextSnap ) {
+ // pre-add some of the entities sent over by the server
+ // we have data for them and they don't need to interpolate
+ for ( num = 0 ; num < cg.nextSnap->numEntities ; num++ ) {
+ cent = &cg_entities[ cg.nextSnap->entities[ num ].number ];
+ if ( cent->nextState.eType == ET_MISSILE || cent->nextState.eType == ET_GENERAL ) {
+ // transition it immediately and add it
+ CG_TransitionEntity( cent );
+ cent->interpolate = qtrue;
+ CG_AddCEntity( cent );
+ }
+ }
+ }
+//unlagged - early transitioning
+
+ // add each entity sent over by the server
+ for ( num = 0 ; num < cg.snap->numEntities ; num++ ) {
+ cent = &cg_entities[ cg.snap->entities[ num ].number ];
+//unlagged - early transitioning
+ if ( !cg.nextSnap || (cent->nextState.eType != ET_MISSILE && cent->nextState.eType != ET_GENERAL) ) {
+//unlagged - early transitioning
+ CG_AddCEntity( cent );
+ } //Also unlagged
+ }
+}
+
diff --git a/code/cgame/cg_event.c b/code/cgame/cg_event.c
new file mode 100644
index 0000000..8cc1113
--- /dev/null
+++ b/code/cgame/cg_event.c
@@ -0,0 +1,1374 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_event.c -- handle entity events at snapshot or playerstate transitions
+
+#include "cg_local.h"
+
+// for the voice chats
+#ifdef MISSIONPACK // bk001205
+#include "../../ui/menudef.h"
+#endif
+//==========================================================================
+
+/*
+===================
+CG_PlaceString
+
+Also called by scoreboard drawing
+===================
+*/
+const char *CG_PlaceString( int rank ) {
+ static char str[64];
+ char *s, *t;
+
+ if ( rank & RANK_TIED_FLAG ) {
+ rank &= ~RANK_TIED_FLAG;
+ t = "Tied for ";
+ } else {
+ t = "";
+ }
+
+ if ( rank == 1 ) {
+ s = S_COLOR_BLUE "1st" S_COLOR_WHITE; // draw in blue
+ } else if ( rank == 2 ) {
+ s = S_COLOR_RED "2nd" S_COLOR_WHITE; // draw in red
+ } else if ( rank == 3 ) {
+ s = S_COLOR_YELLOW "3rd" S_COLOR_WHITE; // draw in yellow
+ } else if ( rank == 11 ) {
+ s = "11th";
+ } else if ( rank == 12 ) {
+ s = "12th";
+ } else if ( rank == 13 ) {
+ s = "13th";
+ } else if ( rank % 10 == 1 ) {
+ s = va("%ist", rank);
+ } else if ( rank % 10 == 2 ) {
+ s = va("%ind", rank);
+ } else if ( rank % 10 == 3 ) {
+ s = va("%ird", rank);
+ } else {
+ s = va("%ith", rank);
+ }
+
+ Com_sprintf( str, sizeof( str ), "%s%s", t, s );
+ return str;
+}
+
+/*
+=============
+CG_Obituary
+=============
+*/
+static void CG_Obituary( entityState_t *ent ) {
+ int mod;
+ int target, attacker;
+ char *message;
+ char *message2;
+ const char *targetInfo;
+ const char *attackerInfo;
+ char targetName[32];
+ char attackerName[32];
+ gender_t gender;
+ clientInfo_t *ci;
+
+ target = ent->otherEntityNum;
+ attacker = ent->otherEntityNum2;
+ mod = ent->eventParm;
+
+ if ( target < 0 || target >= MAX_CLIENTS ) {
+ CG_Error( "CG_Obituary: target out of range" );
+ }
+ ci = &cgs.clientinfo[target];
+
+ if ( attacker < 0 || attacker >= MAX_CLIENTS ) {
+ attacker = ENTITYNUM_WORLD;
+ attackerInfo = NULL;
+ } else {
+ attackerInfo = CG_ConfigString( CS_PLAYERS + attacker );
+ }
+
+ targetInfo = CG_ConfigString( CS_PLAYERS + target );
+ if ( !targetInfo ) {
+ return;
+ }
+ Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof(targetName) - 2);
+ strcat( targetName, S_COLOR_WHITE );
+
+ message2 = "";
+
+ // check for single client messages
+
+ if(attacker != ENTITYNUM_WORLD)
+ message = NULL;
+ else
+ switch( mod ) {
+ case MOD_SUICIDE:
+ message = "suicides";
+ break;
+ case MOD_FALLING:
+ message = "cratered";
+ break;
+ case MOD_CRUSH:
+ message = "was squished";
+ break;
+ case MOD_WATER:
+ message = "sank like a rock";
+ break;
+ case MOD_SLIME:
+ message = "melted";
+ break;
+ case MOD_LAVA:
+ message = "does a back flip into the lava";
+ break;
+ case MOD_TARGET_LASER:
+ message = "saw the light";
+ break;
+ case MOD_TRIGGER_HURT:
+ message = "was in the wrong place";
+ break;
+ default:
+ message = NULL;
+ break;
+ }
+
+ if (attacker == target) {
+ gender = ci->gender;
+ switch (mod) {
+ case MOD_KAMIKAZE:
+ message = "goes out with a bang";
+ break;
+ case MOD_GRENADE_SPLASH:
+ if ( gender == GENDER_FEMALE )
+ message = "tripped on her own grenade";
+ else if ( gender == GENDER_NEUTER )
+ message = "tripped on its own grenade";
+ else
+ message = "tripped on his own grenade";
+ break;
+ case MOD_ROCKET_SPLASH:
+ if ( gender == GENDER_FEMALE )
+ message = "blew herself up";
+ else if ( gender == GENDER_NEUTER )
+ message = "blew itself up";
+ else
+ message = "blew himself up";
+ break;
+ case MOD_PLASMA_SPLASH:
+ if ( gender == GENDER_FEMALE )
+ message = "melted herself";
+ else if ( gender == GENDER_NEUTER )
+ message = "melted itself";
+ else
+ message = "melted himself";
+ break;
+ case MOD_BFG_SPLASH:
+ message = "should have used a smaller gun";
+ break;
+ case MOD_PROXIMITY_MINE:
+ if( gender == GENDER_FEMALE ) {
+ message = "found her prox mine";
+ } else if ( gender == GENDER_NEUTER ) {
+ message = "found its prox mine";
+ } else {
+ message = "found his prox mine";
+ }
+ break;
+ default:
+ if ( gender == GENDER_FEMALE )
+ message = "killed herself";
+ else if ( gender == GENDER_NEUTER )
+ message = "killed itself";
+ else
+ message = "killed himself";
+ break;
+ }
+ }
+
+ //If a suicide happens while disconnecting then we might not have a targetName
+ if (message && strlen(targetName)) {
+ CG_Printf( "%s %s.\n", targetName, message);
+ return;
+ }
+
+
+ // check for kill messages from the current clientNum
+ if ( attacker == cg.snap->ps.clientNum ) {
+ char *s;
+
+ if ( cgs.gametype < GT_TEAM ) {
+ s = va("You fragged %s\n%s place with %i", targetName,
+ CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
+ cg.snap->ps.persistant[PERS_SCORE] );
+ } else {
+ if(ent->generic1)
+ s = va("You fragged your ^1TEAMMATE^7 %s", targetName );
+ else
+ s = va("You fragged %s", targetName );
+ }
+#ifdef MISSIONPACK
+ if (!(cg_singlePlayerActive.integer && cg_cameraOrbit.integer)) {
+ CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, (int)(BIGCHAR_WIDTH * cg_fragmsgsize.value) );
+ }
+#else
+ CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, (int)(BIGCHAR_WIDTH * cg_fragmsgsize.value) );
+#endif
+
+ // print the text message as well
+ }
+
+ // check for double client messages
+ if ( !attackerInfo ) {
+ attacker = ENTITYNUM_WORLD;
+ strcpy( attackerName, "noname" );
+ } else {
+ Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof(attackerName) - 2);
+ strcat( attackerName, S_COLOR_WHITE );
+ // check for kill messages about the current clientNum
+ if ( target == cg.snap->ps.clientNum ) {
+ Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) );
+ }
+ }
+
+ if ( attacker != ENTITYNUM_WORLD ) {
+
+ if(ent->generic1) {
+ message = "was killed by ^1TEAMMATE^7";
+ }
+ else
+ switch (mod) {
+ case MOD_GRAPPLE:
+ message = "was caught by";
+ break;
+ case MOD_GAUNTLET:
+ message = "was pummeled by";
+ break;
+ case MOD_MACHINEGUN:
+ message = "was machinegunned by";
+ break;
+ case MOD_SHOTGUN:
+ message = "was gunned down by";
+ break;
+ case MOD_GRENADE:
+ message = "ate";
+ message2 = "'s grenade";
+ break;
+ case MOD_GRENADE_SPLASH:
+ message = "was shredded by";
+ message2 = "'s shrapnel";
+ break;
+ case MOD_ROCKET:
+ message = "ate";
+ message2 = "'s rocket";
+ break;
+ case MOD_ROCKET_SPLASH:
+ message = "almost dodged";
+ message2 = "'s rocket";
+ break;
+ case MOD_PLASMA:
+ message = "was melted by";
+ message2 = "'s plasmagun";
+ break;
+ case MOD_PLASMA_SPLASH:
+ message = "was melted by";
+ message2 = "'s plasmagun";
+ break;
+ case MOD_RAILGUN:
+ message = "was railed by";
+ break;
+ case MOD_LIGHTNING:
+ message = "was electrocuted by";
+ break;
+ case MOD_BFG:
+ case MOD_BFG_SPLASH:
+ message = "was blasted by";
+ message2 = "'s BFG";
+ break;
+ case MOD_NAIL:
+ message = "was nailed by";
+ break;
+ case MOD_CHAINGUN:
+ message = "got lead poisoning from";
+ message2 = "'s Chaingun";
+ break;
+ case MOD_PROXIMITY_MINE:
+ message = "was too close to";
+ message2 = "'s Prox Mine";
+ break;
+ case MOD_KAMIKAZE:
+ message = "falls to";
+ message2 = "'s Kamikaze blast";
+ break;
+ case MOD_JUICED:
+ message = "was juiced by";
+ break;
+ case MOD_TELEFRAG:
+ message = "tried to invade";
+ message2 = "'s personal space";
+ break;
+ case MOD_LAVA:
+ message = "was given a hot bath by";
+ break;
+ case MOD_SLIME:
+ message = "was given a acid bath by";
+ break;
+ case MOD_FALLING:
+ message = "was given a small push by";
+ break;
+ case MOD_TRIGGER_HURT:
+ message = "was helped on the way by";
+ break;
+ case MOD_CRUSH:
+ message = "was crushed in";
+ message2 = "'s trap";
+ break;
+ default:
+ message = "was killed by";
+ break;
+ }
+
+ if (message) {
+ CG_Printf( "%s %s %s%s\n",
+ targetName, message, attackerName, message2);
+ return;
+ }
+ }
+
+ // we don't know what it was
+ CG_Printf( "%s died.\n", targetName );
+}
+
+//==========================================================================
+
+/*
+===============
+CG_UseItem
+===============
+*/
+static void CG_UseItem( centity_t *cent ) {
+ clientInfo_t *ci;
+ int itemNum, clientNum;
+ gitem_t *item;
+ entityState_t *es;
+
+ es = ¢->currentState;
+
+ itemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0;
+ if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) {
+ itemNum = 0;
+ }
+
+ // print a message if the local player
+ if ( es->number == cg.snap->ps.clientNum ) {
+ if ( !itemNum ) {
+ CG_CenterPrint( "No item to use", SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
+ } else {
+ item = BG_FindItemForHoldable( itemNum );
+ CG_CenterPrint( va("Use %s", item->pickup_name), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
+ }
+ }
+
+ switch ( itemNum ) {
+ default:
+ case HI_NONE:
+ trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound );
+ break;
+
+ case HI_TELEPORTER:
+ break;
+
+ case HI_MEDKIT:
+ clientNum = cent->currentState.clientNum;
+ if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
+ ci = &cgs.clientinfo[ clientNum ];
+ ci->medkitUsageTime = cg.time;
+ }
+ trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.medkitSound );
+ break;
+
+//#ifdef MISSIONPACK
+ case HI_KAMIKAZE:
+ break;
+
+ case HI_PORTAL:
+ break;
+ case HI_INVULNERABILITY:
+ trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useInvulnerabilitySound );
+ break;
+//#endif
+ }
+
+}
+
+static qboolean CG_WeaponHigher(int currentWeapon, int newWeapon) {
+ char *currentScore = NULL;
+ char *newScore = NULL;
+ char weapon[5];
+ Com_sprintf(weapon,5,"/%i/",currentWeapon);
+ currentScore = strstr(cg_weaponOrder.string,weapon);
+ Com_sprintf(weapon,5,"/%i/",newWeapon);
+ newScore = strstr(cg_weaponOrder.string,weapon);
+ if(!newScore || !currentScore)
+ return qfalse;
+ if(newScore>currentScore)
+ return qtrue;
+ else
+ return qfalse;
+}
+
+/*
+================
+CG_ItemPickup
+
+A new item was picked up this frame
+================
+*/
+static void CG_ItemPickup( int itemNum ) {
+ cg.itemPickup = itemNum;
+ cg.itemPickupTime = cg.time;
+ cg.itemPickupBlendTime = cg.time;
+ // see if it should be the grabbed weapon
+ if ( bg_itemlist[itemNum].giType == IT_WEAPON ) {
+ // select it immediately
+ /* always*/
+ if ( cg_autoswitch.integer == 1 && bg_itemlist[itemNum].giTag != WP_MACHINEGUN ) {
+ cg.weaponSelectTime = cg.time;
+ cg.weaponSelect = bg_itemlist[itemNum].giTag;
+ }
+ /* if new */
+ if ( cg_autoswitch.integer == 2 && 0 == (cg.snap->ps.stats[ STAT_WEAPONS ] & (1 << bg_itemlist[itemNum].giTag) ) ) {
+ cg.weaponSelectTime = cg.time;
+ cg.weaponSelect = bg_itemlist[itemNum].giTag;
+ }
+ /* if better */
+ if ( cg_autoswitch.integer == 3 && CG_WeaponHigher(cg.weaponSelect,bg_itemlist[itemNum].giTag)) {
+ cg.weaponSelectTime = cg.time;
+ cg.weaponSelect = bg_itemlist[itemNum].giTag;
+ }
+ /* if new and better */
+ if ( cg_autoswitch.integer == 4 && 0 == (cg.snap->ps.stats[ STAT_WEAPONS ] & (1 << bg_itemlist[itemNum].giTag) )
+ && CG_WeaponHigher(cg.weaponSelect,bg_itemlist[itemNum].giTag)) {
+ cg.weaponSelectTime = cg.time;
+ cg.weaponSelect = bg_itemlist[itemNum].giTag;
+ }
+ //
+ }
+
+}
+
+/*
+================
+CG_WaterLevel
+
+Returns waterlevel for entity origin
+================
+*/
+int CG_WaterLevel(centity_t *cent) {
+ vec3_t point;
+ int contents, sample1, sample2, anim, waterlevel;
+
+ // get waterlevel, accounting for ducking
+ waterlevel = 0;
+ VectorCopy(cent->lerpOrigin, point);
+ point[2] += MINS_Z + 1;
+ anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
+
+ if (anim == LEGS_WALKCR || anim == LEGS_IDLECR) {
+ point[2] += CROUCH_VIEWHEIGHT;
+ } else {
+ point[2] += DEFAULT_VIEWHEIGHT;
+ }
+
+ contents = CG_PointContents(point, -1);
+
+ if (contents & MASK_WATER) {
+ sample2 = point[2] - MINS_Z;
+ sample1 = sample2 / 2;
+ waterlevel = 1;
+ point[2] = cent->lerpOrigin[2] + MINS_Z + sample1;
+ contents = CG_PointContents(point, -1);
+
+ if (contents & MASK_WATER) {
+ waterlevel = 2;
+ point[2] = cent->lerpOrigin[2] + MINS_Z + sample2;
+ contents = CG_PointContents(point, -1);
+
+ if (contents & MASK_WATER) {
+ waterlevel = 3;
+ }
+ }
+ }
+
+ return waterlevel;
+}
+
+/*
+================
+CG_PainEvent
+
+Also called by playerstate transition
+================
+*/
+void CG_PainEvent( centity_t *cent, int health ) {
+ char *snd;
+
+ // don't do more than two pain sounds a second
+ if ( cg.time - cent->pe.painTime < 500 ) {
+ return;
+ }
+
+ if ( health < 25 ) {
+ snd = "*pain25_1.wav";
+ } else if ( health < 50 ) {
+ snd = "*pain50_1.wav";
+ } else if ( health < 75 ) {
+ snd = "*pain75_1.wav";
+ } else {
+ snd = "*pain100_1.wav";
+ }
+ // play a gurp sound instead of a normal pain sound
+ if (CG_WaterLevel(cent) >= 1) {
+ if (rand()&1) {
+ trap_S_StartSound(NULL, cent->currentState.number, CHAN_VOICE, CG_CustomSound(cent->currentState.number, "sound/player/gurp1.wav"));
+ } else {
+ trap_S_StartSound(NULL, cent->currentState.number, CHAN_VOICE, CG_CustomSound(cent->currentState.number, "sound/player/gurp2.wav"));
+ }
+ } else {
+ trap_S_StartSound(NULL, cent->currentState.number, CHAN_VOICE, CG_CustomSound(cent->currentState.number, snd));
+ }
+ // save pain time for programitic twitch animation
+ cent->pe.painTime = cg.time;
+ cent->pe.painDirection ^= 1;
+}
+
+
+
+/*
+==============
+CG_EntityEvent
+
+An entity has an event value
+also called by CG_CheckPlayerstateEvents
+==============
+*/
+#define DEBUGNAME(x) if(cg_debugEvents.integer){CG_Printf(x"\n");}
+void CG_EntityEvent( centity_t *cent, vec3_t position ) {
+ entityState_t *es;
+ int event;
+ vec3_t dir;
+ const char *s;
+ int clientNum;
+ clientInfo_t *ci;
+
+ es = ¢->currentState;
+ event = es->event & ~EV_EVENT_BITS;
+
+ if ( cg_debugEvents.integer ) {
+ CG_Printf( "ent:%3i event:%3i ", es->number, event );
+ }
+
+ if ( !event ) {
+ DEBUGNAME("ZEROEVENT");
+ return;
+ }
+
+ clientNum = es->clientNum;
+ if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
+ clientNum = 0;
+ }
+ ci = &cgs.clientinfo[ clientNum ];
+
+ switch ( event ) {
+ //
+ // movement generated events
+ //
+ case EV_FOOTSTEP:
+ DEBUGNAME("EV_FOOTSTEP");
+ if (cg_footsteps.integer) {
+ trap_S_StartSound (NULL, es->number, CHAN_BODY,
+ cgs.media.footsteps[ ci->footsteps ][rand()&3] );
+ }
+ break;
+ case EV_FOOTSTEP_METAL:
+ DEBUGNAME("EV_FOOTSTEP_METAL");
+ if (cg_footsteps.integer) {
+ trap_S_StartSound (NULL, es->number, CHAN_BODY,
+ cgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] );
+ }
+ break;
+ case EV_FOOTSPLASH:
+ DEBUGNAME("EV_FOOTSPLASH");
+ if (cg_footsteps.integer) {
+ trap_S_StartSound (NULL, es->number, CHAN_BODY,
+ cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
+ }
+ break;
+ case EV_FOOTWADE:
+ DEBUGNAME("EV_FOOTWADE");
+ if (cg_footsteps.integer) {
+ trap_S_StartSound (NULL, es->number, CHAN_BODY,
+ cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
+ }
+ break;
+ case EV_SWIM:
+ DEBUGNAME("EV_SWIM");
+ if (cg_footsteps.integer) {
+ trap_S_StartSound (NULL, es->number, CHAN_BODY,
+ cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
+ }
+ break;
+
+
+ case EV_FALL_SHORT:
+ DEBUGNAME("EV_FALL_SHORT");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound );
+ if ( clientNum == cg.predictedPlayerState.clientNum ) {
+ // smooth landing z changes
+ cg.landChange = -8;
+ cg.landTime = cg.time;
+ }
+ break;
+ case EV_FALL_MEDIUM:
+ DEBUGNAME("EV_FALL_MEDIUM");
+ // use normal pain sound
+ trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) );
+ if ( clientNum == cg.predictedPlayerState.clientNum ) {
+ // smooth landing z changes
+ cg.landChange = -16;
+ cg.landTime = cg.time;
+ }
+ break;
+ case EV_FALL_FAR:
+ DEBUGNAME("EV_FALL_FAR");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) );
+ cent->pe.painTime = cg.time; // don't play a pain sound right after this
+ if ( clientNum == cg.predictedPlayerState.clientNum ) {
+ // smooth landing z changes
+ cg.landChange = -24;
+ cg.landTime = cg.time;
+ }
+ break;
+
+ case EV_STEP_4:
+ case EV_STEP_8:
+ case EV_STEP_12:
+ case EV_STEP_16: // smooth out step up transitions
+ DEBUGNAME("EV_STEP");
+ {
+ float oldStep;
+ int delta;
+ int step;
+
+ if ( clientNum != cg.predictedPlayerState.clientNum ) {
+ break;
+ }
+ // if we are interpolating, we don't need to smooth steps
+ if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ||
+ cg_nopredict.integer || cg_synchronousClients.integer ) {
+ break;
+ }
+ // check for stepping up before a previous step is completed
+ delta = cg.time - cg.stepTime;
+ if (delta < STEP_TIME) {
+ oldStep = cg.stepChange * (STEP_TIME - delta) / STEP_TIME;
+ } else {
+ oldStep = 0;
+ }
+
+ // add this amount
+ step = 4 * (event - EV_STEP_4 + 1 );
+ cg.stepChange = oldStep + step;
+ if ( cg.stepChange > MAX_STEP_CHANGE ) {
+ cg.stepChange = MAX_STEP_CHANGE;
+ }
+ cg.stepTime = cg.time;
+ break;
+ }
+
+ case EV_JUMP_PAD:
+ DEBUGNAME("EV_JUMP_PAD");
+// CG_Printf( "EV_JUMP_PAD w/effect #%i\n", es->eventParm );
+ {
+ localEntity_t *smoke;
+ vec3_t up = {0, 0, 1};
+
+
+ smoke = CG_SmokePuff( cent->lerpOrigin, up,
+ 32,
+ 1, 1, 1, 0.33f,
+ 1000,
+ cg.time, 0,
+ LEF_PUFF_DONT_SCALE,
+ cgs.media.smokePuffShader );
+ }
+
+ // boing sound at origin, jump sound on player
+ trap_S_StartSound ( cent->lerpOrigin, -1, CHAN_VOICE, cgs.media.jumpPadSound );
+ trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
+ break;
+
+ case EV_JUMP:
+ DEBUGNAME("EV_JUMP");
+ trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
+ break;
+ case EV_TAUNT:
+ DEBUGNAME("EV_TAUNT");
+ trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) );
+ break;
+#ifdef MISSIONPACK
+ case EV_TAUNT_YES:
+ DEBUGNAME("EV_TAUNT_YES");
+ CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_YES);
+ break;
+ case EV_TAUNT_NO:
+ DEBUGNAME("EV_TAUNT_NO");
+ CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_NO);
+ break;
+ case EV_TAUNT_FOLLOWME:
+ DEBUGNAME("EV_TAUNT_FOLLOWME");
+ CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_FOLLOWME);
+ break;
+ case EV_TAUNT_GETFLAG:
+ DEBUGNAME("EV_TAUNT_GETFLAG");
+ CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONGETFLAG);
+ break;
+ case EV_TAUNT_GUARDBASE:
+ DEBUGNAME("EV_TAUNT_GUARDBASE");
+ CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONDEFENSE);
+ break;
+ case EV_TAUNT_PATROL:
+ DEBUGNAME("EV_TAUNT_PATROL");
+ CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONPATROL);
+ break;
+#endif
+ case EV_WATER_TOUCH:
+ DEBUGNAME("EV_WATER_TOUCH");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound );
+ break;
+ case EV_WATER_LEAVE:
+ DEBUGNAME("EV_WATER_LEAVE");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );
+ break;
+ case EV_WATER_UNDER:
+ DEBUGNAME("EV_WATER_UNDER");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound );
+ break;
+ case EV_WATER_CLEAR:
+ DEBUGNAME("EV_WATER_CLEAR");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) );
+ break;
+
+ case EV_ITEM_PICKUP:
+ DEBUGNAME("EV_ITEM_PICKUP");
+ {
+ gitem_t *item;
+ int index;
+
+ index = es->eventParm; // player predicted
+
+ if ( index < 1 || index >= bg_numItems ) {
+ break;
+ }
+ item = &bg_itemlist[ index ];
+
+ // powerups and team items will have a separate global sound, this one
+ // will be played at prediction time
+ if ( item->giType == IT_POWERUP || item->giType == IT_TEAM) {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.n_healthSound );
+ } else if (item->giType == IT_PERSISTANT_POWERUP) {
+#ifdef MISSIONPACK
+ switch (item->giTag ) {
+ case PW_SCOUT:
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.scoutSound );
+ break;
+ case PW_GUARD:
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.guardSound );
+ break;
+ case PW_DOUBLER:
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.doublerSound );
+ break;
+ case PW_AMMOREGEN:
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.ammoregenSound );
+ break;
+ }
+#endif
+ } else {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );
+ }
+
+ // show icon and name on status bar
+ if ( es->number == cg.snap->ps.clientNum ) {
+ CG_ItemPickup( index );
+ }
+ }
+ break;
+
+ case EV_GLOBAL_ITEM_PICKUP:
+ DEBUGNAME("EV_GLOBAL_ITEM_PICKUP");
+ {
+ gitem_t *item;
+ int index;
+
+ index = es->eventParm; // player predicted
+
+ if ( index < 1 || index >= bg_numItems ) {
+ break;
+ }
+ item = &bg_itemlist[ index ];
+ // powerup pickups are global
+ if( item->pickup_sound ) {
+ trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );
+ }
+
+ // show icon and name on status bar
+ if ( es->number == cg.snap->ps.clientNum ) {
+ CG_ItemPickup( index );
+ }
+ }
+ break;
+
+ //
+ // weapon events
+ //
+ case EV_NOAMMO:
+ DEBUGNAME("EV_NOAMMO");
+// trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound );
+ if ( es->number == cg.snap->ps.clientNum ) {
+ CG_OutOfAmmoChange();
+ }
+ break;
+ case EV_CHANGE_WEAPON:
+ DEBUGNAME("EV_CHANGE_WEAPON");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
+ break;
+ case EV_FIRE_WEAPON:
+ DEBUGNAME("EV_FIRE_WEAPON");
+ CG_FireWeapon( cent );
+ break;
+
+ case EV_USE_ITEM0:
+ DEBUGNAME("EV_USE_ITEM0");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM1:
+ DEBUGNAME("EV_USE_ITEM1");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM2:
+ DEBUGNAME("EV_USE_ITEM2");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM3:
+ DEBUGNAME("EV_USE_ITEM3");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM4:
+ DEBUGNAME("EV_USE_ITEM4");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM5:
+ DEBUGNAME("EV_USE_ITEM5");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM6:
+ DEBUGNAME("EV_USE_ITEM6");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM7:
+ DEBUGNAME("EV_USE_ITEM7");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM8:
+ DEBUGNAME("EV_USE_ITEM8");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM9:
+ DEBUGNAME("EV_USE_ITEM9");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM10:
+ DEBUGNAME("EV_USE_ITEM10");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM11:
+ DEBUGNAME("EV_USE_ITEM11");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM12:
+ DEBUGNAME("EV_USE_ITEM12");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM13:
+ DEBUGNAME("EV_USE_ITEM13");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM14:
+ DEBUGNAME("EV_USE_ITEM14");
+ CG_UseItem( cent );
+ break;
+
+ //=================================================================
+
+ //
+ // other events
+ //
+ case EV_PLAYER_TELEPORT_IN:
+ DEBUGNAME("EV_PLAYER_TELEPORT_IN");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleInSound );
+ CG_SpawnEffect( position);
+ break;
+
+ case EV_PLAYER_TELEPORT_OUT:
+ DEBUGNAME("EV_PLAYER_TELEPORT_OUT");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleOutSound );
+ CG_SpawnEffect( position);
+ break;
+
+ case EV_ITEM_POP:
+ DEBUGNAME("EV_ITEM_POP");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
+ break;
+ case EV_ITEM_RESPAWN:
+ DEBUGNAME("EV_ITEM_RESPAWN");
+ cent->miscTime = cg.time; // scale up from this
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
+ break;
+
+ case EV_GRENADE_BOUNCE:
+ DEBUGNAME("EV_GRENADE_BOUNCE");
+ if ( rand() & 1 ) {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb1aSound );
+ } else {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb2aSound );
+ }
+ break;
+
+
+ case EV_PROXIMITY_MINE_STICK:
+ DEBUGNAME("EV_PROXIMITY_MINE_STICK");
+ if( es->eventParm & SURF_FLESH ) {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimplSound );
+ } else if( es->eventParm & SURF_METALSTEPS ) {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpmSound );
+ } else {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpdSound );
+ }
+ break;
+
+ case EV_PROXIMITY_MINE_TRIGGER:
+ DEBUGNAME("EV_PROXIMITY_MINE_TRIGGER");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbactvSound );
+ break;
+ case EV_KAMIKAZE:
+ DEBUGNAME("EV_KAMIKAZE");
+ CG_KamikazeEffect( cent->lerpOrigin );
+ break;
+ case EV_OBELISKEXPLODE:
+ DEBUGNAME("EV_OBELISKEXPLODE");
+ CG_ObeliskExplode( cent->lerpOrigin, es->eventParm );
+ break;
+ case EV_OBELISKPAIN:
+ DEBUGNAME("EV_OBELISKPAIN");
+ CG_ObeliskPain( cent->lerpOrigin );
+ break;
+ case EV_INVUL_IMPACT:
+ DEBUGNAME("EV_INVUL_IMPACT");
+ CG_InvulnerabilityImpact( cent->lerpOrigin, cent->currentState.angles );
+ break;
+ case EV_JUICED:
+ DEBUGNAME("EV_JUICED");
+ CG_InvulnerabilityJuiced( cent->lerpOrigin );
+ break;
+ case EV_LIGHTNINGBOLT:
+ DEBUGNAME("EV_LIGHTNINGBOLT");
+ CG_LightningBoltBeam(es->origin2, es->pos.trBase);
+ break;
+ case EV_SCOREPLUM:
+ DEBUGNAME("EV_SCOREPLUM");
+ CG_ScorePlum( cent->currentState.otherEntityNum, cent->lerpOrigin, cent->currentState.time );
+ break;
+
+ //
+ // missile impacts
+ //
+ case EV_MISSILE_HIT:
+ DEBUGNAME("EV_MISSILE_HIT");
+ ByteToDir( es->eventParm, dir );
+ CG_MissileHitPlayer( es->weapon, position, dir, es->otherEntityNum );
+ break;
+
+ case EV_MISSILE_MISS:
+ DEBUGNAME("EV_MISSILE_MISS");
+ ByteToDir( es->eventParm, dir );
+ CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_DEFAULT );
+ break;
+
+ case EV_MISSILE_MISS_METAL:
+ DEBUGNAME("EV_MISSILE_MISS_METAL");
+ ByteToDir( es->eventParm, dir );
+ CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_METAL );
+ break;
+
+ case EV_RAILTRAIL:
+ DEBUGNAME("EV_RAILTRAIL");
+ cent->currentState.weapon = WP_RAILGUN;
+//unlagged - attack prediction #2
+ // if the client is us, unlagged is on server-side, and we've got it client-side
+ if ( es->clientNum == cg.predictedPlayerState.clientNum &&
+ cgs.delagHitscan && (cg_delag.integer & 1 || cg_delag.integer & 16) ) {
+ // do nothing, because it was already predicted
+ //Com_Printf("Ignoring rail trail event\n");
+ }
+ else {
+ if(es->clientNum == cg.snap->ps.clientNum && !cg.renderingThirdPerson)
+ {
+ if(cg_drawGun.integer == 2)
+ VectorMA(es->origin2, 8, cg.refdef.viewaxis[1], es->origin2);
+ else if(cg_drawGun.integer == 3)
+ VectorMA(es->origin2, 4, cg.refdef.viewaxis[1], es->origin2);
+ }
+
+
+ // draw a rail trail, because it wasn't predicted
+ CG_RailTrail( ci, es->origin2, es->pos.trBase );
+
+ // if the end was on a nomark surface, don't make an explosion
+ if ( es->eventParm != 255 ) {
+ ByteToDir( es->eventParm, dir );
+ CG_MissileHitWall( es->weapon, es->clientNum, position, dir, IMPACTSOUND_DEFAULT );
+ }
+ //Com_Printf("Non-predicted rail trail\n");
+ }
+//unlagged - attack prediction #2
+ break;
+
+ case EV_BULLET_HIT_WALL:
+ DEBUGNAME("EV_BULLET_HIT_WALL");
+//unlagged - attack prediction #2
+ // if the client is us, unlagged is on server-side, and we've got it client-side
+ if ( es->clientNum == cg.predictedPlayerState.clientNum &&
+ cgs.delagHitscan && (cg_delag.integer & 1 || cg_delag.integer & 2) ) {
+ // do nothing, because it was already predicted
+ //Com_Printf("Ignoring bullet event\n");
+ }
+ else {
+ // do the bullet, because it wasn't predicted
+ ByteToDir( es->eventParm, dir );
+ CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD );
+ //Com_Printf("Non-predicted bullet\n");
+ }
+//unlagged - attack prediction #2
+ break;
+
+ case EV_BULLET_HIT_FLESH:
+ DEBUGNAME("EV_BULLET_HIT_FLESH");
+//unlagged - attack prediction #2
+ // if the client is us, unlagged is on server-side, and we've got it client-side
+ if ( es->clientNum == cg.predictedPlayerState.clientNum &&
+ cgs.delagHitscan && (cg_delag.integer & 1 || cg_delag.integer & 2) ) {
+ // do nothing, because it was already predicted
+ //Com_Printf("Ignoring bullet event\n");
+ }
+ else {
+ // do the bullet, because it wasn't predicted
+ CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );
+ //Com_Printf("Non-predicted bullet\n");
+ }
+//unlagged - attack prediction #2
+ break;
+
+ case EV_SHOTGUN:
+ DEBUGNAME("EV_SHOTGUN");
+//unlagged - attack prediction #2
+ // if the client is us, unlagged is on server-side, and we've got it client-side
+ if ( es->otherEntityNum == cg.predictedPlayerState.clientNum &&
+ cgs.delagHitscan && (cg_delag.integer & 1 || cg_delag.integer & 4) ) {
+ // do nothing, because it was already predicted
+ //Com_Printf("Ignoring shotgun event\n");
+ }
+ else {
+ // do the shotgun pattern, because it wasn't predicted
+ CG_ShotgunFire( es );
+ //Com_Printf("Non-predicted shotgun pattern\n");
+ }
+//unlagged - attack prediction #2
+ break;
+
+ case EV_GENERAL_SOUND:
+ DEBUGNAME("EV_GENERAL_SOUND");
+ if ( cgs.gameSounds[ es->eventParm ] ) {
+ trap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] );
+ } else {
+ s = CG_ConfigString( CS_SOUNDS + es->eventParm );
+ trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) );
+ }
+ break;
+
+ case EV_GLOBAL_SOUND: // play from the player's head so it never diminishes
+ DEBUGNAME("EV_GLOBAL_SOUND");
+ if ( cgs.gameSounds[ es->eventParm ] ) {
+ trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
+ } else {
+ s = CG_ConfigString( CS_SOUNDS + es->eventParm );
+ trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
+ }
+ break;
+
+ case EV_GLOBAL_TEAM_SOUND: // play from the player's head so it never diminishes
+ {
+ DEBUGNAME("EV_GLOBAL_TEAM_SOUND");
+ switch( es->eventParm ) {
+ case GTS_RED_CAPTURE: // CTF: red team captured the blue flag, 1FCTF: red team captured the neutral flag
+ if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
+ CG_AddBufferedSound( cgs.media.captureYourTeamSound );
+ else
+ CG_AddBufferedSound( cgs.media.captureOpponentSound );
+ break;
+ case GTS_BLUE_CAPTURE: // CTF: blue team captured the red flag, 1FCTF: blue team captured the neutral flag
+ if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )
+ CG_AddBufferedSound( cgs.media.captureYourTeamSound );
+ else
+ CG_AddBufferedSound( cgs.media.captureOpponentSound );
+ break;
+ case GTS_RED_RETURN: // CTF: blue flag returned, 1FCTF: never used
+ if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
+ CG_AddBufferedSound( cgs.media.returnYourTeamSound );
+ else
+ CG_AddBufferedSound( cgs.media.returnOpponentSound );
+ //
+ CG_AddBufferedSound( cgs.media.blueFlagReturnedSound );
+ break;
+ case GTS_BLUE_RETURN: // CTF red flag returned, 1FCTF: neutral flag returned
+ if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )
+ CG_AddBufferedSound( cgs.media.returnYourTeamSound );
+ else
+ CG_AddBufferedSound( cgs.media.returnOpponentSound );
+ //
+ CG_AddBufferedSound( cgs.media.redFlagReturnedSound );
+ break;
+
+ case GTS_RED_TAKEN: // CTF: red team took blue flag, 1FCTF: blue team took the neutral flag
+ // if this player picked up the flag then a sound is played in CG_CheckLocalSounds
+ if (cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
+ }
+ else {
+ if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
+//#ifdef MISSIONPACK
+ if (cgs.gametype == GT_1FCTF)
+ CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
+ else
+//#endif
+ CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
+ }
+ else if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
+//#ifdef MISSIONPACK
+ if (cgs.gametype == GT_1FCTF)
+ CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
+ else
+//#endif
+ CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
+ }
+ }
+ break;
+ case GTS_BLUE_TAKEN: // CTF: blue team took the red flag, 1FCTF red team took the neutral flag
+ // if this player picked up the flag then a sound is played in CG_CheckLocalSounds
+ if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
+ }
+ else {
+ if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
+//#ifdef MISSIONPACK
+ if (cgs.gametype == GT_1FCTF)
+ CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
+ else
+//#endif
+ CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
+ }
+ else if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
+//#ifdef MISSIONPACK
+ if (cgs.gametype == GT_1FCTF)
+ CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
+ else
+//#endif
+ CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
+ }
+ }
+ break;
+ case GTS_REDOBELISK_ATTACKED: // Overload: red obelisk is being attacked
+ if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
+ CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );
+ }
+ break;
+ case GTS_BLUEOBELISK_ATTACKED: // Overload: blue obelisk is being attacked
+ if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
+ CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );
+ }
+ break;
+
+ case GTS_REDTEAM_SCORED:
+ CG_AddBufferedSound(cgs.media.redScoredSound);
+ break;
+ case GTS_BLUETEAM_SCORED:
+ CG_AddBufferedSound(cgs.media.blueScoredSound);
+ break;
+ case GTS_REDTEAM_TOOK_LEAD:
+ CG_AddBufferedSound(cgs.media.redLeadsSound);
+ break;
+ case GTS_BLUETEAM_TOOK_LEAD:
+ CG_AddBufferedSound(cgs.media.blueLeadsSound);
+ break;
+ case GTS_TEAMS_ARE_TIED:
+ CG_AddBufferedSound( cgs.media.teamsTiedSound );
+ break;
+ case GTS_KAMIKAZE:
+ trap_S_StartLocalSound(cgs.media.kamikazeFarSound, CHAN_ANNOUNCER);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case EV_PAIN:
+ // local player sounds are triggered in CG_CheckLocalSounds,
+ // so ignore events on the player
+ DEBUGNAME("EV_PAIN");
+ if ( cent->currentState.number != cg.snap->ps.clientNum ) {
+ CG_PainEvent( cent, es->eventParm );
+ }
+ break;
+
+ case EV_DEATH1:
+ case EV_DEATH2:
+ case EV_DEATH3:
+ DEBUGNAME("EV_DEATHx");
+
+ if (CG_WaterLevel(cent) >= 1) {
+ trap_S_StartSound(NULL, es->number, CHAN_VOICE, CG_CustomSound(es->number, "*drown.wav"));
+ } else {
+ trap_S_StartSound(NULL, es->number, CHAN_VOICE, CG_CustomSound(es->number, va("*death%i.wav", event - EV_DEATH1 + 1)));
+ }
+
+ break;
+
+
+ case EV_OBITUARY:
+ DEBUGNAME("EV_OBITUARY");
+ CG_Obituary( es );
+ break;
+
+ //
+ // powerup events
+ //
+ case EV_POWERUP_QUAD:
+ DEBUGNAME("EV_POWERUP_QUAD");
+ if ( es->number == cg.snap->ps.clientNum ) {
+ cg.powerupActive = PW_QUAD;
+ cg.powerupTime = cg.time;
+ }
+ trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.quadSound );
+ break;
+ case EV_POWERUP_BATTLESUIT:
+ DEBUGNAME("EV_POWERUP_BATTLESUIT");
+ if ( es->number == cg.snap->ps.clientNum ) {
+ cg.powerupActive = PW_BATTLESUIT;
+ cg.powerupTime = cg.time;
+ }
+ trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.protectSound );
+ break;
+ case EV_POWERUP_REGEN:
+ DEBUGNAME("EV_POWERUP_REGEN");
+ if ( es->number == cg.snap->ps.clientNum ) {
+ cg.powerupActive = PW_REGEN;
+ cg.powerupTime = cg.time;
+ }
+ trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.regenSound );
+ break;
+
+ case EV_GIB_PLAYER:
+ DEBUGNAME("EV_GIB_PLAYER");
+ // don't play gib sound when using the kamikaze because it interferes
+ // with the kamikaze sound, downside is that the gib sound will also
+ // not be played when someone is gibbed while just carrying the kamikaze
+ if ( !(es->eFlags & EF_KAMIKAZE) ) {
+ trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound );
+ }
+ CG_GibPlayer( cent->lerpOrigin );
+ break;
+
+ case EV_STOPLOOPINGSOUND:
+ DEBUGNAME("EV_STOPLOOPINGSOUND");
+ trap_S_StopLoopingSound( es->number );
+ es->loopSound = 0;
+ break;
+
+ case EV_DEBUG_LINE:
+ DEBUGNAME("EV_DEBUG_LINE");
+ CG_Beam( cent );
+ break;
+
+ default:
+ DEBUGNAME("UNKNOWN");
+ CG_Error( "Unknown event: %i", event );
+ break;
+ }
+
+}
+
+
+/*
+==============
+CG_CheckEvents
+
+==============
+*/
+void CG_CheckEvents( centity_t *cent ) {
+ // check for event-only entities
+ if ( cent->currentState.eType > ET_EVENTS ) {
+ if ( cent->previousEvent ) {
+ return; // already fired
+ }
+ // if this is a player event set the entity number of the client entity number
+ if ( cent->currentState.eFlags & EF_PLAYER_EVENT ) {
+ cent->currentState.number = cent->currentState.otherEntityNum;
+ }
+
+ cent->previousEvent = 1;
+
+ cent->currentState.event = cent->currentState.eType - ET_EVENTS;
+ } else {
+ // check for events riding with another entity
+ if ( cent->currentState.event == cent->previousEvent ) {
+ return;
+ }
+ cent->previousEvent = cent->currentState.event;
+ if ( ( cent->currentState.event & ~EV_EVENT_BITS ) == 0 ) {
+ return;
+ }
+ }
+
+ // calculate the position at exactly the frame time
+ BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, cent->lerpOrigin );
+ CG_SetEntitySoundPosition( cent );
+
+ CG_EntityEvent( cent, cent->lerpOrigin );
+}
+
diff --git a/code/cgame/cg_info.c b/code/cgame/cg_info.c
new file mode 100644
index 0000000..729396c
--- /dev/null
+++ b/code/cgame/cg_info.c
@@ -0,0 +1,312 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_info.c -- display information while data is being loading
+
+#include "cg_local.h"
+
+#define MAX_LOADING_PLAYER_ICONS 16
+#define MAX_LOADING_ITEM_ICONS 26
+
+static int loadingPlayerIconCount;
+static int loadingItemIconCount;
+static qhandle_t loadingPlayerIcons[MAX_LOADING_PLAYER_ICONS];
+static qhandle_t loadingItemIcons[MAX_LOADING_ITEM_ICONS];
+
+
+/*
+===================
+CG_DrawLoadingIcons
+===================
+*/
+static void CG_DrawLoadingIcons( void ) {
+ int n;
+ int x, y;
+
+ for( n = 0; n < loadingPlayerIconCount; n++ ) {
+ x = 16 + n * 78;
+ y = 324-40;
+ CG_DrawPic( x, y, 64, 64, loadingPlayerIcons[n] );
+ }
+
+ for( n = 0; n < loadingItemIconCount; n++ ) {
+ y = 400-40;
+ if( n >= 13 ) {
+ y += 40;
+ }
+ x = 16 + n % 13 * 48;
+ CG_DrawPic( x, y, 32, 32, loadingItemIcons[n] );
+ }
+}
+
+
+/*
+======================
+CG_LoadingString
+
+======================
+*/
+void CG_LoadingString( const char *s ) {
+ Q_strncpyz( cg.infoScreenText, s, sizeof( cg.infoScreenText ) );
+
+ trap_UpdateScreen();
+}
+
+/*
+===================
+CG_LoadingItem
+===================
+*/
+void CG_LoadingItem( int itemNum ) {
+ gitem_t *item;
+
+ item = &bg_itemlist[itemNum];
+
+ if ( item->icon && loadingItemIconCount < MAX_LOADING_ITEM_ICONS ) {
+ loadingItemIcons[loadingItemIconCount++] = trap_R_RegisterShaderNoMip( item->icon );
+ }
+
+ CG_LoadingString( item->pickup_name );
+}
+
+/*
+===================
+CG_LoadingClient
+===================
+*/
+void CG_LoadingClient( int clientNum ) {
+ const char *info;
+ char *skin;
+ char personality[MAX_QPATH];
+ char model[MAX_QPATH];
+ char iconName[MAX_QPATH];
+
+ info = CG_ConfigString( CS_PLAYERS + clientNum );
+
+ if ( loadingPlayerIconCount < MAX_LOADING_PLAYER_ICONS ) {
+ Q_strncpyz( model, Info_ValueForKey( info, "model" ), sizeof( model ) );
+ skin = strrchr( model, '/' );
+ if ( skin ) {
+ *skin++ = '\0';
+ } else {
+ skin = "default";
+ }
+
+ Com_sprintf( iconName, MAX_QPATH, "models/players/%s/icon_%s.tga", model, skin );
+
+ loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
+ if ( !loadingPlayerIcons[loadingPlayerIconCount] ) {
+ Com_sprintf( iconName, MAX_QPATH, "models/players/characters/%s/icon_%s.tga", model, skin );
+ loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
+ }
+ if ( !loadingPlayerIcons[loadingPlayerIconCount] ) {
+ Com_sprintf( iconName, MAX_QPATH, "models/players/%s/icon_%s.tga", DEFAULT_MODEL, "default" );
+ loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
+ }
+ if ( loadingPlayerIcons[loadingPlayerIconCount] ) {
+ loadingPlayerIconCount++;
+ }
+ }
+
+ Q_strncpyz( personality, Info_ValueForKey( info, "n" ), sizeof(personality) );
+ Q_CleanStr( personality );
+
+ if( cgs.gametype == GT_SINGLE_PLAYER ) {
+ trap_S_RegisterSound( va( "sound/player/announce/%s.wav", personality ), qtrue );
+ }
+
+ CG_LoadingString( personality );
+}
+
+
+/*
+====================
+CG_DrawInformation
+
+Draw all the status / pacifier stuff during level loading
+====================
+*/
+void CG_DrawInformation( void ) {
+ const char *s;
+ const char *info;
+ const char *sysInfo;
+ int y;
+ int value;
+ qhandle_t levelshot;
+ qhandle_t detail;
+ char buf[1024];
+
+ info = CG_ConfigString( CS_SERVERINFO );
+ sysInfo = CG_ConfigString( CS_SYSTEMINFO );
+
+ s = Info_ValueForKey( info, "mapname" );
+ levelshot = trap_R_RegisterShaderNoMip( va( "levelshots/%s.tga", s ) );
+ if ( !levelshot ) {
+ levelshot = trap_R_RegisterShaderNoMip( "menu/art/unknownmap" );
+ }
+ trap_R_SetColor( NULL );
+ CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, levelshot );
+
+ // blend a detail texture over it
+ detail = trap_R_RegisterShader( "levelShotDetail" );
+ trap_R_DrawStretchPic( 0, 0, cgs.glconfig.vidWidth, cgs.glconfig.vidHeight, 0, 0, 2.5, 2, detail );
+
+ // draw the icons of things as they are loaded
+ CG_DrawLoadingIcons();
+
+ // the first 150 rows are reserved for the client connection
+ // screen to write into
+ if ( cg.infoScreenText[0] ) {
+ UI_DrawProportionalString( 320, 128-32, va("Loading... %s", cg.infoScreenText),
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ } else {
+ UI_DrawProportionalString( 320, 128-32, "Awaiting snapshot...",
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ }
+
+ // draw info string information
+
+ y = 180-32;
+
+ // don't print server lines if playing a local game
+ trap_Cvar_VariableStringBuffer( "sv_running", buf, sizeof( buf ) );
+ if ( !atoi( buf ) ) {
+ // server hostname
+ Q_strncpyz(buf, Info_ValueForKey( info, "sv_hostname" ), 1024);
+ Q_CleanStr(buf);
+ UI_DrawProportionalString( 320, y, buf,
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+
+ // pure server
+ s = Info_ValueForKey( sysInfo, "sv_pure" );
+ if ( s[0] == '1' ) {
+ UI_DrawProportionalString( 320, y, "Pure Server",
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+
+ // server-specific message of the day
+ s = CG_ConfigString( CS_MOTD );
+ if ( s[0] ) {
+ UI_DrawProportionalString( 320, y, s,
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+
+ // some extra space after hostname and motd
+ y += 10;
+ }
+
+ // map-specific message (long map name)
+ s = CG_ConfigString( CS_MESSAGE );
+ if ( s[0] ) {
+ UI_DrawProportionalString( 320, y, s,
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+
+ // cheats warning
+ s = Info_ValueForKey( sysInfo, "sv_cheats" );
+ if ( s[0] == '1' ) {
+ UI_DrawProportionalString( 320, y, "CHEATS ARE ENABLED",
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+
+ // game type
+ switch ( cgs.gametype ) {
+ case GT_FFA:
+ s = "Free For All";
+ break;
+ case GT_SINGLE_PLAYER:
+ s = "Single Player";
+ break;
+ case GT_TOURNAMENT:
+ s = "Tournament";
+ break;
+ case GT_TEAM:
+ s = "Team Deathmatch";
+ break;
+ case GT_CTF:
+ s = "Capture The Flag";
+ break;
+//#ifdef MISSIONPACK
+ case GT_1FCTF:
+ s = "One Flag CTF";
+ break;
+ case GT_OBELISK:
+ s = "Overload";
+ break;
+ case GT_HARVESTER:
+ s = "Harvester";
+ break;
+//#endif
+ case GT_ELIMINATION:
+ s = "Elimination";
+ break;
+ case GT_CTF_ELIMINATION:
+ s = " CTF Elimination";
+ break;
+ case GT_LMS:
+ s = "Last Man Standing";
+ break;
+ case GT_DOUBLE_D:
+ s = "Double Domination";
+ break;
+ case GT_DOMINATION:
+ s = "Domination";
+ break;
+ default:
+ s = "Unknown Gametype";
+ break;
+ }
+ UI_DrawProportionalString( 320, y, s,
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+
+ value = atoi( Info_ValueForKey( info, "timelimit" ) );
+ if ( value ) {
+ UI_DrawProportionalString( 320, y, va( "timelimit %i", value ),
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+
+ if (cgs.gametype < GT_CTF || cgs.ffa_gt>0) {
+ value = atoi( Info_ValueForKey( info, "fraglimit" ) );
+ if ( value ) {
+ UI_DrawProportionalString( 320, y, va( "fraglimit %i", value ),
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+ }
+
+ if (cgs.gametype >= GT_CTF && cgs.ffa_gt == 0) {
+ value = atoi( Info_ValueForKey( info, "capturelimit" ) );
+ if ( value ) {
+ UI_DrawProportionalString( 320, y, va( "capturelimit %i", value ),
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+ }
+}
+
diff --git a/code/cgame/cg_local.h b/code/cgame/cg_local.h
new file mode 100644
index 0000000..44f7d3b
--- /dev/null
+++ b/code/cgame/cg_local.h
@@ -0,0 +1,1898 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#include "../qcommon/q_shared.h"
+#include "../renderer/tr_types.h"
+#include "../game/bg_public.h"
+#include "cg_public.h"
+
+#include "../game/challenges.h"
+
+
+// The entire cgame module is unloaded and reloaded on each level change,
+// so there is NO persistant data between levels on the client side.
+// If you absolutely need something stored, it can either be kept
+// by the server in the server stored userinfos, or stashed in a cvar.
+
+#ifdef MISSIONPACK
+#define CG_FONT_THRESHOLD 0.1
+#endif
+
+#define POWERUP_BLINKS 5
+
+#define POWERUP_BLINK_TIME 1000
+#define FADE_TIME 200
+#define PULSE_TIME 200
+#define DAMAGE_DEFLECT_TIME 100
+#define DAMAGE_RETURN_TIME 400
+#define DAMAGE_TIME 500
+#define LAND_DEFLECT_TIME 150
+#define LAND_RETURN_TIME 300
+#define STEP_TIME 200
+#define DUCK_TIME 100
+#define PAIN_TWITCH_TIME 200
+#define WEAPON_SELECT_TIME 1400
+#define ITEM_SCALEUP_TIME 1000
+#define ZOOM_TIME 150
+#define ITEM_BLOB_TIME 200
+#define MUZZLE_FLASH_TIME 20
+#define SINK_TIME 1000 // time for fragments to sink into ground before going away
+#define ATTACKER_HEAD_TIME 10000
+#define REWARD_TIME 3000
+
+#define PULSE_SCALE 1.5 // amount to scale up the icons when activating
+
+#define MAX_STEP_CHANGE 32
+
+#define MAX_VERTS_ON_POLY 10
+#define MAX_MARK_POLYS 256
+
+#define STAT_MINUS 10 // num frame for '-' stats digit
+
+#define ICON_SIZE 48
+#define CHAR_WIDTH 32
+#define CHAR_HEIGHT 48
+#define TEXT_ICON_SPACE 4
+
+#define TEAMCHAT_WIDTH 80
+#define TEAMCHAT_HEIGHT 8
+
+// very large characters.pk
+#define GIANT_WIDTH 32
+#define GIANT_HEIGHT 48
+
+#define NUM_CROSSHAIRS 99
+
+#define TEAM_OVERLAY_MAXNAME_WIDTH 12
+#define TEAM_OVERLAY_MAXLOCATION_WIDTH 16
+
+#define DEFAULT_MODEL "sarge"
+#ifdef MISSIONPACK
+#define DEFAULT_TEAM_MODEL "sergei"
+#define DEFAULT_TEAM_HEAD "*sergei"
+#else
+#define DEFAULT_TEAM_MODEL "sarge"
+#define DEFAULT_TEAM_HEAD "sarge"
+#endif
+
+#define DEFAULT_REDTEAM_NAME "Vim supporters"
+#define DEFAULT_BLUETEAM_NAME "Emacs supporters"
+
+typedef enum {
+ FOOTSTEP_NORMAL,
+ FOOTSTEP_BOOT,
+ FOOTSTEP_FLESH,
+ FOOTSTEP_MECH,
+ FOOTSTEP_ENERGY,
+ FOOTSTEP_METAL,
+ FOOTSTEP_SPLASH,
+
+ FOOTSTEP_TOTAL
+} footstep_t;
+
+typedef enum {
+ IMPACTSOUND_DEFAULT,
+ IMPACTSOUND_METAL,
+ IMPACTSOUND_FLESH
+} impactSound_t;
+
+//=================================================
+
+// player entities need to track more information
+// than any other type of entity.
+
+// note that not every player entity is a client entity,
+// because corpses after respawn are outside the normal
+// client numbering range
+
+// when changing animation, set animationTime to frameTime + lerping time
+// The current lerp will finish out, then it will lerp to the new animation
+typedef struct {
+ int oldFrame;
+ int oldFrameTime; // time when ->oldFrame was exactly on
+
+ int frame;
+ int frameTime; // time when ->frame will be exactly on
+
+ float backlerp;
+
+ float yawAngle;
+ qboolean yawing;
+ float pitchAngle;
+ qboolean pitching;
+
+ int animationNumber; // may include ANIM_TOGGLEBIT
+ animation_t *animation;
+ int animationTime; // time when the first frame of the animation will be exact
+} lerpFrame_t;
+
+
+typedef struct {
+ lerpFrame_t legs, torso, flag;
+ int painTime;
+ int painDirection; // flip from 0 to 1
+ int lightningFiring;
+
+ // railgun trail spawning
+ vec3_t railgunImpact;
+ qboolean railgunFlash;
+
+ // machinegun spinning
+ float barrelAngle;
+ int barrelTime;
+ qboolean barrelSpinning;
+} playerEntity_t;
+
+//=================================================
+
+
+
+// centity_t have a direct corespondence with gentity_t in the game, but
+// only the entityState_t is directly communicated to the cgame
+typedef struct centity_s {
+ entityState_t currentState; // from cg.frame
+ entityState_t nextState; // from cg.nextFrame, if available
+ qboolean interpolate; // true if next is valid to interpolate to
+ qboolean currentValid; // true if cg.frame holds this entity
+
+ int muzzleFlashTime; // move to playerEntity?
+ int previousEvent;
+ int teleportFlag;
+
+ int trailTime; // so missile trails can handle dropped initial packets
+ int dustTrailTime;
+ int miscTime;
+
+ int snapShotTime; // last time this entity was found in a snapshot
+
+ playerEntity_t pe;
+
+ int errorTime; // decay the error from this time
+ vec3_t errorOrigin;
+ vec3_t errorAngles;
+
+ qboolean extrapolated; // false if origin / angles is an interpolation
+ vec3_t rawOrigin;
+ vec3_t rawAngles;
+
+ vec3_t beamEnd;
+
+ // exact interpolated position of entity on this frame
+ vec3_t lerpOrigin;
+ vec3_t lerpAngles;
+} centity_t;
+
+
+//======================================================================
+
+// local entities are created as a result of events or predicted actions,
+// and live independantly from all server transmitted entities
+
+typedef struct markPoly_s {
+ struct markPoly_s *prevMark, *nextMark;
+ int time;
+ qhandle_t markShader;
+ qboolean alphaFade; // fade alpha instead of rgb
+ float color[4];
+ poly_t poly;
+ polyVert_t verts[MAX_VERTS_ON_POLY];
+} markPoly_t;
+
+
+typedef enum {
+ LE_MARK,
+ LE_EXPLOSION,
+ LE_SPRITE_EXPLOSION,
+ LE_FRAGMENT,
+ LE_MOVE_SCALE_FADE,
+ LE_FALL_SCALE_FADE,
+ LE_FADE_RGB,
+ LE_SCALE_FADE,
+ LE_SCOREPLUM,
+ LE_KAMIKAZE,
+ LE_INVULIMPACT,
+ LE_INVULJUICED,
+ LE_SHOWREFENTITY,
+ LE_GORE
+} leType_t;
+
+typedef enum {
+ LEF_PUFF_DONT_SCALE = 0x0001, // do not scale size over time
+ LEF_TUMBLE = 0x0002, // tumble over time, used for ejecting shells
+ LEF_SOUND1 = 0x0004, // sound 1 for kamikaze
+ LEF_SOUND2 = 0x0008 // sound 2 for kamikaze
+} leFlag_t;
+
+typedef enum {
+ LEMT_NONE,
+ LEMT_BURN,
+ LEMT_BLOOD
+} leMarkType_t; // fragment local entities can leave marks on walls
+
+typedef enum {
+ LEBS_NONE,
+ LEBS_BLOOD,
+ LEBS_BRASS,
+ LEBS_SHELL
+} leBounceSoundType_t; // fragment local entities can make sounds on impacts
+
+typedef struct localEntity_s {
+ struct localEntity_s *prev, *next;
+ leType_t leType;
+ int leFlags;
+
+ int startTime;
+ int endTime;
+ int fadeInTime;
+
+ float lifeRate; // 1.0 / (endTime - startTime)
+
+ trajectory_t pos;
+ trajectory_t angles;
+
+ float bounceFactor; // 0.0 = no bounce, 1.0 = perfect
+
+ float color[4];
+
+ float radius;
+
+ float light;
+ vec3_t lightColor;
+
+ leMarkType_t leMarkType; // mark to leave on fragment impact
+ leBounceSoundType_t leBounceSoundType;
+
+ refEntity_t refEntity;
+} localEntity_t;
+
+//======================================================================
+
+
+typedef struct {
+ int client;
+ int score;
+ int ping;
+ int time;
+ int scoreFlags;
+ int powerUps;
+ int accuracy;
+ int impressiveCount;
+ int excellentCount;
+ int guantletCount;
+ int defendCount;
+ int assistCount;
+ int captures;
+ qboolean perfect;
+ int team;
+ int isDead;
+} score_t;
+
+// each client has an associated clientInfo_t
+// that contains media references necessary to present the
+// client model and other color coded effects
+// this is regenerated each time a client's configstring changes,
+// usually as a result of a userinfo (name, model, etc) change
+#define MAX_CUSTOM_SOUNDS 32
+
+typedef struct {
+ qboolean infoValid;
+
+ char name[MAX_QPATH];
+ team_t team;
+
+ int botSkill; // 0 = not bot, 1-5 = bot
+
+ vec3_t color1;
+ vec3_t color2;
+
+ int score; // updated by score servercmds
+ int location; // location index for team mode
+ int health; // you only get this info about your teammates
+ int armor;
+ int curWeapon;
+
+ int handicap;
+ int wins, losses; // in tourney mode
+
+ int teamTask; // task in teamplay (offence/defence)
+ qboolean teamLeader; // true when this is a team leader
+
+ int powerups; // so can display quad/flag status
+
+ int medkitUsageTime;
+ int invulnerabilityStartTime;
+ int invulnerabilityStopTime;
+
+ int breathPuffTime;
+
+ // when clientinfo is changed, the loading of models/skins/sounds
+ // can be deferred until you are dead, to prevent hitches in
+ // gameplay
+ char modelName[MAX_QPATH];
+ char skinName[MAX_QPATH];
+ char headModelName[MAX_QPATH];
+ char headSkinName[MAX_QPATH];
+ char redTeam[MAX_TEAMNAME];
+ char blueTeam[MAX_TEAMNAME];
+ qboolean deferred;
+
+ qboolean newAnims; // true if using the new mission pack animations
+ qboolean fixedlegs; // true if legs yaw is always the same as torso yaw
+ qboolean fixedtorso; // true if torso never changes yaw
+
+ vec3_t headOffset; // move head in icon views
+ footstep_t footsteps;
+ gender_t gender; // from model
+
+ qhandle_t legsModel;
+ qhandle_t legsSkin;
+
+ qhandle_t torsoModel;
+ qhandle_t torsoSkin;
+
+ qhandle_t headModel;
+ qhandle_t headSkin;
+
+ qhandle_t modelIcon;
+
+ animation_t animations[MAX_TOTALANIMATIONS];
+
+ sfxHandle_t sounds[MAX_CUSTOM_SOUNDS];
+
+ int isDead;
+} clientInfo_t;
+
+
+// each WP_* weapon enum has an associated weaponInfo_t
+// that contains media references necessary to present the
+// weapon and its effects
+typedef struct weaponInfo_s {
+ qboolean registered;
+ gitem_t *item;
+
+ qhandle_t handsModel; // the hands don't actually draw, they just position the weapon
+ qhandle_t weaponModel;
+ qhandle_t barrelModel;
+ qhandle_t flashModel;
+
+ vec3_t weaponMidpoint; // so it will rotate centered instead of by tag
+
+ float flashDlight;
+ vec3_t flashDlightColor;
+ sfxHandle_t flashSound[4]; // fast firing weapons randomly choose
+
+ qhandle_t weaponIcon;
+ qhandle_t ammoIcon;
+
+ qhandle_t ammoModel;
+
+ qhandle_t missileModel;
+ sfxHandle_t missileSound;
+ void (*missileTrailFunc)( centity_t *, const struct weaponInfo_s *wi );
+ float missileDlight;
+ vec3_t missileDlightColor;
+ int missileRenderfx;
+
+ void (*ejectBrassFunc)( centity_t * );
+
+ float trailRadius;
+ float wiTrailTime;
+
+ sfxHandle_t readySound;
+ sfxHandle_t firingSound;
+ qboolean loopFireSound;
+} weaponInfo_t;
+
+
+// each IT_* item has an associated itemInfo_t
+// that constains media references necessary to present the
+// item and its effects
+typedef struct {
+ qboolean registered;
+ qhandle_t models[MAX_ITEM_MODELS];
+ qhandle_t icon;
+} itemInfo_t;
+
+
+typedef struct {
+ int itemNum;
+} powerupInfo_t;
+
+
+#define MAX_SKULLTRAIL 10
+
+typedef struct {
+ vec3_t positions[MAX_SKULLTRAIL];
+ int numpositions;
+} skulltrail_t;
+
+
+#define MAX_REWARDSTACK 10
+#define MAX_SOUNDBUFFER 20
+
+//======================================================================
+
+// all cg.stepTime, cg.duckTime, cg.landTime, etc are set to cg.time when the action
+// occurs, and they will have visible effects for #define STEP_TIME or whatever msec after
+
+#define MAX_PREDICTED_EVENTS 16
+
+//unlagged - optimized prediction
+#define NUM_SAVED_STATES (CMD_BACKUP + 2)
+//unlagged - optimized prediction
+
+typedef struct {
+ int clientFrame; // incremented each frame
+
+ int clientNum;
+
+ qboolean demoPlayback;
+ qboolean levelShot; // taking a level menu screenshot
+ int deferredPlayerLoading;
+ qboolean loading; // don't defer players at initial startup
+ qboolean intermissionStarted; // don't play voice rewards, because game will end shortly
+
+ // there are only one or two snapshot_t that are relevent at a time
+ int latestSnapshotNum; // the number of snapshots the client system has received
+ int latestSnapshotTime; // the time from latestSnapshotNum, so we don't need to read the snapshot yet
+
+ snapshot_t *snap; // cg.snap->serverTime <= cg.time
+ snapshot_t *nextSnap; // cg.nextSnap->serverTime > cg.time, or NULL
+ snapshot_t activeSnapshots[2];
+
+ float frameInterpolation; // (float)( cg.time - cg.frame->serverTime ) / (cg.nextFrame->serverTime - cg.frame->serverTime)
+
+ qboolean thisFrameTeleport;
+ qboolean nextFrameTeleport;
+
+ int frametime; // cg.time - cg.oldTime
+
+ int time; // this is the time value that the client
+ // is rendering at.
+ int oldTime; // time at last frame, used for missile trails and prediction checking
+
+ int physicsTime; // either cg.snap->time or cg.nextSnap->time
+
+ int timelimitWarnings; // 5 min, 1 min, overtime
+ int fraglimitWarnings;
+
+ qboolean mapRestart; // set on a map restart to set back the weapon
+
+ qboolean renderingThirdPerson; // during deaths, chasecams, etc
+
+ // prediction state
+ qboolean hyperspace; // true if prediction has hit a trigger_teleport
+ playerState_t predictedPlayerState;
+ centity_t predictedPlayerEntity;
+ qboolean validPPS; // clear until the first call to CG_PredictPlayerState
+ int predictedErrorTime;
+ vec3_t predictedError;
+
+ int eventSequence;
+ int predictableEvents[MAX_PREDICTED_EVENTS];
+
+ float stepChange; // for stair up smoothing
+ int stepTime;
+
+ float duckChange; // for duck viewheight smoothing
+ int duckTime;
+
+ float landChange; // for landing hard
+ int landTime;
+
+ // input state sent to server
+ int weaponSelect;
+
+ // auto rotating items
+ vec3_t autoAngles;
+ vec3_t autoAxis[3];
+ vec3_t autoAnglesFast;
+ vec3_t autoAxisFast[3];
+
+ // view rendering
+ refdef_t refdef;
+ vec3_t refdefViewAngles; // will be converted to refdef.viewaxis
+
+ // zoom key
+ qboolean zoomed;
+ int zoomTime;
+ float zoomSensitivity;
+
+ // information screen text during loading
+ char infoScreenText[MAX_STRING_CHARS];
+
+ // scoreboard
+ int scoresRequestTime;
+ int numScores;
+ int selectedScore;
+ int teamScores[2];
+ score_t scores[MAX_CLIENTS];
+ qboolean showScores;
+ qboolean scoreBoardShowing;
+ int scoreFadeTime;
+
+ int accuracys[WP_NUM_WEAPONS][2];
+ int accRequestTime;
+ qboolean showAcc;
+ qboolean accBoardShowing;
+ int accFadeTime;
+
+
+ char killerName[MAX_NAME_LENGTH];
+ char spectatorList[MAX_STRING_CHARS]; // list of names
+ int spectatorLen; // length of list
+ float spectatorWidth; // width in device units
+ int spectatorTime; // next time to offset
+ int spectatorPaintX; // current paint x
+ int spectatorPaintX2; // current paint x
+ int spectatorOffset; // current offset from start
+ int spectatorPaintLen; // current offset from start
+
+ // skull trails
+ skulltrail_t skulltrails[MAX_CLIENTS];
+
+ // centerprinting
+ int centerPrintTime;
+ int centerPrintCharWidth;
+ int centerPrintY;
+ char centerPrint[1024];
+ int centerPrintLines;
+
+ // low ammo warning state
+ int lowAmmoWarning; // 1 = low, 2 = empty
+
+ // kill timers for carnage reward
+ int lastKillTime;
+
+ // crosshair client ID
+ int crosshairClientNum;
+ int crosshairClientTime;
+
+ // powerup active flashing
+ int powerupActive;
+ int powerupTime;
+
+ // attacking player
+ int attackerTime;
+ int voiceTime;
+
+ // reward medals
+ int rewardStack;
+ int rewardTime;
+ int rewardCount[MAX_REWARDSTACK];
+ qhandle_t rewardShader[MAX_REWARDSTACK];
+ qhandle_t rewardSound[MAX_REWARDSTACK];
+
+ // sound buffer mainly for announcer sounds
+ int soundBufferIn;
+ int soundBufferOut;
+ int soundTime;
+ qhandle_t soundBuffer[MAX_SOUNDBUFFER];
+
+ // for voice chat buffer
+ int voiceChatTime;
+ int voiceChatBufferIn;
+ int voiceChatBufferOut;
+
+ // warmup countdown
+ int warmup;
+ int warmupCount;
+
+ //==========================
+
+ int itemPickup;
+ int itemPickupTime;
+ int itemPickupBlendTime; // the pulse around the crosshair is timed seperately
+
+ int weaponSelectTime;
+ int weaponAnimation;
+ int weaponAnimationTime;
+
+ // blend blobs
+ float damageTime;
+ float damageX, damageY, damageValue;
+
+ // status bar head
+ float headYaw;
+ float headEndPitch;
+ float headEndYaw;
+ int headEndTime;
+ float headStartPitch;
+ float headStartYaw;
+ int headStartTime;
+
+ // view movement
+ float v_dmg_time;
+ float v_dmg_pitch;
+ float v_dmg_roll;
+
+ vec3_t kick_angles; // weapon kicks
+ vec3_t kick_origin;
+
+ // temp working variables for player view
+ float bobfracsin;
+ int bobcycle;
+ float xyspeed;
+ int nextOrbitTime;
+
+ //qboolean cameraMode; // if rendering from a loaded camera
+
+
+ // development tool
+ refEntity_t testModelEntity;
+ char testModelName[MAX_QPATH];
+ qboolean testGun;
+
+//unlagged - optimized prediction
+ int lastPredictedCommand;
+ int lastServerTime;
+ playerState_t savedPmoveStates[NUM_SAVED_STATES];
+ int stateHead, stateTail;
+//unlagged - optimized prediction
+
+ //time that the client will respawn. If 0 = the player is alive.
+ int respawnTime;
+
+ int redObeliskHealth;
+ int blueObeliskHealth;
+} cg_t;
+
+
+// all of the model, shader, and sound references that are
+// loaded at gamestate time are stored in cgMedia_t
+// Other media that can be tied to clients, weapons, or items are
+// stored in the clientInfo_t, itemInfo_t, weaponInfo_t, and powerupInfo_t
+typedef struct {
+ qhandle_t charsetShader;
+ qhandle_t charsetProp;
+ qhandle_t charsetPropGlow;
+ qhandle_t charsetPropB;
+ qhandle_t whiteShader;
+
+ qhandle_t redCubeModel;
+ qhandle_t blueCubeModel;
+ qhandle_t redCubeIcon;
+ qhandle_t blueCubeIcon;
+ qhandle_t redFlagModel;
+ qhandle_t blueFlagModel;
+ qhandle_t neutralFlagModel;
+ qhandle_t redFlagShader[3];
+ qhandle_t blueFlagShader[3];
+ qhandle_t flagShader[4];
+
+//For Double Domination:
+ //qhandle_t ddPointA;
+ //qhandle_t ddPointB;
+ qhandle_t ddPointSkinA[4]; //white,red,blue,none
+ qhandle_t ddPointSkinB[4]; //white,red,blue,none
+
+ qhandle_t flagPoleModel;
+ qhandle_t flagFlapModel;
+
+ qhandle_t redFlagFlapSkin;
+ qhandle_t blueFlagFlapSkin;
+ qhandle_t neutralFlagFlapSkin;
+
+ qhandle_t redFlagBaseModel;
+ qhandle_t blueFlagBaseModel;
+ qhandle_t neutralFlagBaseModel;
+
+ qhandle_t overloadBaseModel;
+ qhandle_t overloadTargetModel;
+ qhandle_t overloadLightsModel;
+ qhandle_t overloadEnergyModel;
+
+ qhandle_t harvesterModel;
+ qhandle_t harvesterRedSkin;
+ qhandle_t harvesterBlueSkin;
+ qhandle_t harvesterNeutralModel;
+
+ qhandle_t armorModel;
+ qhandle_t armorIcon;
+
+ qhandle_t teamStatusBar;
+
+ qhandle_t deferShader;
+
+ // gib explosions
+ qhandle_t gibAbdomen;
+ qhandle_t gibArm;
+ qhandle_t gibChest;
+ qhandle_t gibFist;
+ qhandle_t gibFoot;
+ qhandle_t gibForearm;
+ qhandle_t gibIntestine;
+ qhandle_t gibLeg;
+ qhandle_t gibSkull;
+ qhandle_t gibBrain;
+
+ qhandle_t smoke2;
+
+ qhandle_t machinegunBrassModel;
+ qhandle_t shotgunBrassModel;
+
+ qhandle_t railRingsShader;
+ qhandle_t railCoreShader;
+
+ qhandle_t lightningShader;
+
+ qhandle_t friendShader;
+
+ qhandle_t balloonShader;
+ qhandle_t connectionShader;
+
+ qhandle_t selectShader;
+ qhandle_t viewBloodShader;
+ qhandle_t tracerShader;
+ qhandle_t crosshairShader[NUM_CROSSHAIRS];
+ qhandle_t lagometerShader;
+ qhandle_t backTileShader;
+ qhandle_t noammoShader;
+
+ qhandle_t smokePuffShader;
+ qhandle_t smokePuffRageProShader;
+ qhandle_t shotgunSmokePuffShader;
+ qhandle_t plasmaBallShader;
+ qhandle_t waterBubbleShader;
+ qhandle_t bloodTrailShader;
+
+
+
+ // LEILEI shaders
+
+ qhandle_t lsmkShader1;
+ qhandle_t lsmkShader2;
+ qhandle_t lsmkShader3;
+ qhandle_t lsmkShader4;
+ qhandle_t lbumShader1;
+ qhandle_t lfblShader1;
+ qhandle_t lsplShader;
+ qhandle_t lspkShader1;
+ qhandle_t lspkShader2;
+ qhandle_t lbldShader1;
+ qhandle_t lbldShader2;
+ qhandle_t grappleShader; // leilei - grapple hook
+ qhandle_t lmarkmetal1;
+ qhandle_t lmarkmetal2;
+ qhandle_t lmarkmetal3;
+ qhandle_t lmarkmetal4;
+ qhandle_t lmarkbullet1;
+ qhandle_t lmarkbullet2;
+ qhandle_t lmarkbullet3;
+ qhandle_t lmarkbullet4;
+
+//#ifdef MISSIONPACK
+ qhandle_t nailPuffShader;
+ qhandle_t blueProxMine;
+//#endif
+
+ qhandle_t numberShaders[11];
+
+ qhandle_t shadowMarkShader;
+
+ qhandle_t botSkillShaders[5];
+
+ // wall mark shaders
+ qhandle_t wakeMarkShader;
+ qhandle_t bloodMarkShader;
+ qhandle_t bulletMarkShader;
+ qhandle_t burnMarkShader;
+ qhandle_t holeMarkShader;
+ qhandle_t energyMarkShader;
+
+ // powerup shaders
+ qhandle_t quadShader;
+ qhandle_t redQuadShader;
+ qhandle_t quadWeaponShader;
+ qhandle_t invisShader;
+ qhandle_t regenShader;
+ qhandle_t battleSuitShader;
+ qhandle_t battleWeaponShader;
+ qhandle_t hastePuffShader;
+ qhandle_t redKamikazeShader;
+ qhandle_t blueKamikazeShader;
+
+ // player overlays
+ qhandle_t neutralOverlay;
+ qhandle_t redOverlay;
+ qhandle_t blueOverlay;
+
+ // weapon effect models
+ qhandle_t bulletFlashModel;
+ qhandle_t ringFlashModel;
+ qhandle_t dishFlashModel;
+ qhandle_t lightningExplosionModel;
+
+ // weapon effect shaders
+ qhandle_t railExplosionShader;
+ qhandle_t plasmaExplosionShader;
+ qhandle_t bulletExplosionShader;
+ qhandle_t rocketExplosionShader;
+ qhandle_t grenadeExplosionShader;
+ qhandle_t bfgExplosionShader;
+ qhandle_t bloodExplosionShader;
+
+ // special effects models
+ qhandle_t teleportEffectModel;
+ qhandle_t teleportEffectShader;
+//#ifdef MISSIONPACK
+ qhandle_t kamikazeEffectModel;
+ qhandle_t kamikazeShockWave;
+ qhandle_t kamikazeHeadModel;
+ qhandle_t kamikazeHeadTrail;
+ qhandle_t guardPowerupModel;
+ qhandle_t scoutPowerupModel;
+ qhandle_t doublerPowerupModel;
+ qhandle_t ammoRegenPowerupModel;
+ qhandle_t invulnerabilityImpactModel;
+ qhandle_t invulnerabilityJuicedModel;
+ qhandle_t medkitUsageModel;
+ qhandle_t dustPuffShader;
+ qhandle_t heartShader;
+//#endif
+ qhandle_t invulnerabilityPowerupModel;
+
+ // scoreboard headers
+ qhandle_t scoreboardName;
+ qhandle_t scoreboardPing;
+ qhandle_t scoreboardScore;
+ qhandle_t scoreboardTime;
+
+ // medals shown during gameplay
+ qhandle_t medalImpressive;
+ qhandle_t medalExcellent;
+ qhandle_t medalGauntlet;
+ qhandle_t medalDefend;
+ qhandle_t medalAssist;
+ qhandle_t medalCapture;
+
+ // sounds
+ sfxHandle_t quadSound;
+ sfxHandle_t tracerSound;
+ sfxHandle_t selectSound;
+ sfxHandle_t useNothingSound;
+ sfxHandle_t wearOffSound;
+ sfxHandle_t footsteps[FOOTSTEP_TOTAL][4];
+ sfxHandle_t sfx_lghit1;
+ sfxHandle_t sfx_lghit2;
+ sfxHandle_t sfx_lghit3;
+ sfxHandle_t sfx_ric1;
+ sfxHandle_t sfx_ric2;
+ sfxHandle_t sfx_ric3;
+ sfxHandle_t sfx_railg;
+ sfxHandle_t sfx_rockexp;
+ sfxHandle_t sfx_plasmaexp;
+//#ifdef MISSIONPACK
+ sfxHandle_t sfx_proxexp;
+ sfxHandle_t sfx_nghit;
+ sfxHandle_t sfx_nghitflesh;
+ sfxHandle_t sfx_nghitmetal;
+ sfxHandle_t sfx_chghit;
+ sfxHandle_t sfx_chghitflesh;
+ sfxHandle_t sfx_chghitmetal;
+ sfxHandle_t kamikazeExplodeSound;
+ sfxHandle_t kamikazeImplodeSound;
+ sfxHandle_t kamikazeFarSound;
+ sfxHandle_t useInvulnerabilitySound;
+ sfxHandle_t invulnerabilityImpactSound1;
+ sfxHandle_t invulnerabilityImpactSound2;
+ sfxHandle_t invulnerabilityImpactSound3;
+ sfxHandle_t invulnerabilityJuicedSound;
+ sfxHandle_t obeliskHitSound1;
+ sfxHandle_t obeliskHitSound2;
+ sfxHandle_t obeliskHitSound3;
+ sfxHandle_t obeliskRespawnSound;
+ sfxHandle_t winnerSound;
+ sfxHandle_t loserSound;
+ sfxHandle_t youSuckSound;
+//#endif
+ sfxHandle_t gibSound;
+ sfxHandle_t gibBounce1Sound;
+ sfxHandle_t gibBounce2Sound;
+ sfxHandle_t gibBounce3Sound;
+ sfxHandle_t teleInSound;
+ sfxHandle_t teleOutSound;
+ sfxHandle_t noAmmoSound;
+ sfxHandle_t respawnSound;
+ sfxHandle_t talkSound;
+ sfxHandle_t landSound;
+ sfxHandle_t fallSound;
+ sfxHandle_t jumpPadSound;
+
+// LEILEI
+ sfxHandle_t lspl1Sound;
+ sfxHandle_t lspl2Sound; // Blood Splat Noises
+ sfxHandle_t lspl3Sound;
+
+ sfxHandle_t lbul1Sound;
+ sfxHandle_t lbul2Sound; // Bullet Drop Noises
+ sfxHandle_t lbul3Sound;
+
+ sfxHandle_t lshl1Sound;
+ sfxHandle_t lshl2Sound; // Shell Drop Noises
+ sfxHandle_t lshl3Sound;
+
+// LEILEI END
+
+ sfxHandle_t oneMinuteSound;
+ sfxHandle_t fiveMinuteSound;
+ sfxHandle_t suddenDeathSound;
+
+ sfxHandle_t threeFragSound;
+ sfxHandle_t twoFragSound;
+ sfxHandle_t oneFragSound;
+
+ sfxHandle_t hitSound;
+ sfxHandle_t hitSoundHighArmor;
+ sfxHandle_t hitSoundLowArmor;
+ sfxHandle_t hitTeamSound;
+ sfxHandle_t impressiveSound;
+ sfxHandle_t excellentSound;
+ sfxHandle_t deniedSound;
+ sfxHandle_t humiliationSound;
+ sfxHandle_t assistSound;
+ sfxHandle_t defendSound;
+ sfxHandle_t firstImpressiveSound;
+ sfxHandle_t firstExcellentSound;
+ sfxHandle_t firstHumiliationSound;
+
+ sfxHandle_t takenLeadSound;
+ sfxHandle_t tiedLeadSound;
+ sfxHandle_t lostLeadSound;
+
+ sfxHandle_t voteNow;
+ sfxHandle_t votePassed;
+ sfxHandle_t voteFailed;
+
+ sfxHandle_t watrInSound;
+ sfxHandle_t watrOutSound;
+ sfxHandle_t watrUnSound;
+
+ sfxHandle_t flightSound;
+ sfxHandle_t medkitSound;
+
+ sfxHandle_t weaponHoverSound;
+
+ // teamplay sounds
+ sfxHandle_t captureAwardSound;
+ sfxHandle_t redScoredSound;
+ sfxHandle_t blueScoredSound;
+ sfxHandle_t redLeadsSound;
+ sfxHandle_t blueLeadsSound;
+ sfxHandle_t teamsTiedSound;
+
+ sfxHandle_t captureYourTeamSound;
+ sfxHandle_t captureOpponentSound;
+ sfxHandle_t returnYourTeamSound;
+ sfxHandle_t returnOpponentSound;
+ sfxHandle_t takenYourTeamSound;
+ sfxHandle_t takenOpponentSound;
+
+ sfxHandle_t redFlagReturnedSound;
+ sfxHandle_t blueFlagReturnedSound;
+ sfxHandle_t neutralFlagReturnedSound;
+ sfxHandle_t enemyTookYourFlagSound;
+ sfxHandle_t enemyTookTheFlagSound;
+ sfxHandle_t yourTeamTookEnemyFlagSound;
+ sfxHandle_t yourTeamTookTheFlagSound;
+ sfxHandle_t youHaveFlagSound;
+ sfxHandle_t yourBaseIsUnderAttackSound;
+ sfxHandle_t holyShitSound;
+
+ // tournament sounds
+ sfxHandle_t count3Sound;
+ sfxHandle_t count2Sound;
+ sfxHandle_t count1Sound;
+ sfxHandle_t countFightSound;
+ sfxHandle_t countPrepareSound;
+
+#ifdef MISSIONPACK
+ // new stuff
+ qhandle_t patrolShader;
+ qhandle_t assaultShader;
+ qhandle_t campShader;
+ qhandle_t followShader;
+ qhandle_t defendShader;
+ qhandle_t teamLeaderShader;
+ qhandle_t retrieveShader;
+ qhandle_t escortShader;
+ qhandle_t deathShader;
+ qhandle_t flagShaders[3];
+ sfxHandle_t countPrepareTeamSound;
+#endif
+
+ sfxHandle_t ammoregenSound;
+ sfxHandle_t doublerSound;
+ sfxHandle_t guardSound;
+ sfxHandle_t scoutSound;
+
+ qhandle_t cursor;
+ qhandle_t selectCursor;
+ qhandle_t sizeCursor;
+
+ sfxHandle_t regenSound;
+ sfxHandle_t protectSound;
+ sfxHandle_t n_healthSound;
+ sfxHandle_t hgrenb1aSound;
+ sfxHandle_t hgrenb2aSound;
+ sfxHandle_t wstbimplSound;
+ sfxHandle_t wstbimpmSound;
+ sfxHandle_t wstbimpdSound;
+ sfxHandle_t wstbactvSound;
+
+} cgMedia_t;
+
+
+// The client game static (cgs) structure hold everything
+// loaded or calculated from the gamestate. It will NOT
+// be cleared when a tournement restart is done, allowing
+// all clients to begin playing instantly
+typedef struct {
+ gameState_t gameState; // gamestate from server
+ glconfig_t glconfig; // rendering configuration
+ float screenXScale; // derived from glconfig
+ float screenYScale;
+ float screenXBias;
+
+ int serverCommandSequence; // reliable command stream counter
+ int processedSnapshotNum;// the number of snapshots cgame has requested
+
+ qboolean localServer; // detected on startup by checking sv_running
+
+ // parsed from serverinfo
+ gametype_t gametype;
+ int dmflags;
+ int videoflags;
+ int elimflags;
+ int teamflags;
+ int fraglimit;
+ int capturelimit;
+ int timelimit;
+ int maxclients;
+ char mapname[MAX_QPATH];
+ char redTeam[MAX_QPATH];
+ char blueTeam[MAX_QPATH];
+
+ int voteTime;
+ int voteYes;
+ int voteNo;
+ qboolean voteModified; // beep whenever changed
+ char voteString[MAX_STRING_TOKENS];
+
+ int teamVoteTime[2];
+ int teamVoteYes[2];
+ int teamVoteNo[2];
+ qboolean teamVoteModified[2]; // beep whenever changed
+ char teamVoteString[2][MAX_STRING_TOKENS];
+
+ int levelStartTime;
+
+//Forced FFA
+ int ffa_gt;
+
+//Elimination
+ int roundStartTime;
+ int roundtime;
+
+//CTF Elimination
+ int attackingTeam;
+
+//Last Man Standing
+ int lms_mode;
+
+//instantgib + nexuiz style rocket arena:
+ int nopickup;
+
+//Double Domination DD
+ int timetaken;
+
+//Domination
+ int domination_points_count;
+ char domination_points_names[MAX_DOMINATION_POINTS][MAX_DOMINATION_POINTS_NAMES];
+ int domination_points_status[MAX_DOMINATION_POINTS];
+
+
+ int scores1, scores2; // from configstrings
+ int redflag, blueflag; // flag status from configstrings
+ int flagStatus;
+
+ qboolean newHud;
+
+ //
+ // locally derived information from gamestate
+ //
+ qhandle_t gameModels[MAX_MODELS];
+ sfxHandle_t gameSounds[MAX_SOUNDS];
+
+ int numInlineModels;
+ qhandle_t inlineDrawModel[MAX_MODELS];
+ vec3_t inlineModelMidpoints[MAX_MODELS];
+
+ clientInfo_t clientinfo[MAX_CLIENTS];
+
+ // teamchat width is *3 because of embedded color codes
+ char teamChatMsgs[TEAMCHAT_HEIGHT][TEAMCHAT_WIDTH*3+1];
+ int teamChatMsgTimes[TEAMCHAT_HEIGHT];
+ int teamChatPos;
+ int teamLastChatPos;
+
+ int cursorX;
+ int cursorY;
+ qboolean eventHandling;
+ qboolean mouseCaptured;
+ qboolean sizingHud;
+ void *capturedItem;
+ qhandle_t activeCursor;
+
+ // orders
+ int currentOrder;
+ qboolean orderPending;
+ int orderTime;
+ int currentVoiceClient;
+ int acceptOrderTime;
+ int acceptTask;
+ int acceptLeader;
+ char acceptVoice[MAX_NAME_LENGTH];
+
+ // media
+ cgMedia_t media;
+
+//unlagged - client options
+ // this will be set to the server's g_delagHitscan
+ int delagHitscan;
+//unlagged - client options
+//KK-OAX For storing whether or not the server has multikills enabled.
+ int altExcellent;
+} cgs_t;
+
+//==============================================================================
+
+extern cgs_t cgs;
+extern cg_t cg;
+extern centity_t cg_entities[MAX_GENTITIES];
+extern weaponInfo_t cg_weapons[MAX_WEAPONS];
+extern itemInfo_t cg_items[MAX_ITEMS];
+extern markPoly_t cg_markPolys[MAX_MARK_POLYS];
+
+extern vmCvar_t cg_centertime;
+extern vmCvar_t cg_runpitch;
+extern vmCvar_t cg_runroll;
+extern vmCvar_t cg_bobup;
+extern vmCvar_t cg_bobpitch;
+extern vmCvar_t cg_bobroll;
+extern vmCvar_t cg_swingSpeed;
+extern vmCvar_t cg_shadows;
+extern vmCvar_t cg_gibs;
+extern vmCvar_t cg_drawTimer;
+extern vmCvar_t cg_drawFPS;
+extern vmCvar_t cg_drawSnapshot;
+extern vmCvar_t cg_draw3dIcons;
+extern vmCvar_t cg_drawIcons;
+extern vmCvar_t cg_drawAmmoWarning;
+extern vmCvar_t cg_drawCrosshair;
+extern vmCvar_t cg_drawCrosshairNames;
+extern vmCvar_t cg_drawRewards;
+extern vmCvar_t cg_drawTeamOverlay;
+extern vmCvar_t cg_teamOverlayUserinfo;
+extern vmCvar_t cg_crosshairX;
+extern vmCvar_t cg_crosshairY;
+extern vmCvar_t cg_crosshairSize;
+extern vmCvar_t cg_crosshairHealth;
+extern vmCvar_t cg_drawStatus;
+extern vmCvar_t cg_draw2D;
+extern vmCvar_t cg_animSpeed;
+extern vmCvar_t cg_debugAnim;
+extern vmCvar_t cg_debugPosition;
+extern vmCvar_t cg_debugEvents;
+extern vmCvar_t cg_railTrailTime;
+extern vmCvar_t cg_errorDecay;
+extern vmCvar_t cg_nopredict;
+extern vmCvar_t cg_noPlayerAnims;
+extern vmCvar_t cg_showmiss;
+extern vmCvar_t cg_footsteps;
+extern vmCvar_t cg_addMarks;
+extern vmCvar_t cg_brassTime;
+extern vmCvar_t cg_gun_frame;
+extern vmCvar_t cg_gun_x;
+extern vmCvar_t cg_gun_y;
+extern vmCvar_t cg_gun_z;
+extern vmCvar_t cg_drawGun;
+extern vmCvar_t cg_viewsize;
+extern vmCvar_t cg_tracerChance;
+extern vmCvar_t cg_tracerWidth;
+extern vmCvar_t cg_tracerLength;
+extern vmCvar_t cg_autoswitch;
+extern vmCvar_t cg_ignore;
+extern vmCvar_t cg_simpleItems;
+extern vmCvar_t cg_fov;
+extern vmCvar_t cg_zoomFov;
+extern vmCvar_t cg_thirdPersonRange;
+extern vmCvar_t cg_thirdPersonAngle;
+extern vmCvar_t cg_thirdPerson;
+extern vmCvar_t cg_lagometer;
+extern vmCvar_t cg_drawAttacker;
+extern vmCvar_t cg_drawSpeed;
+extern vmCvar_t cg_synchronousClients;
+extern vmCvar_t cg_teamChatTime;
+extern vmCvar_t cg_teamChatHeight;
+extern vmCvar_t cg_stats;
+extern vmCvar_t cg_forceModel;
+extern vmCvar_t cg_buildScript;
+extern vmCvar_t cg_paused;
+extern vmCvar_t cg_blood;
+extern vmCvar_t cg_predictItems;
+extern vmCvar_t cg_deferPlayers;
+extern vmCvar_t cg_drawFriend;
+extern vmCvar_t cg_teamChatsOnly;
+extern vmCvar_t cg_noVoiceChats;
+extern vmCvar_t cg_noVoiceText;
+extern vmCvar_t cg_scorePlum;
+//unlagged - smooth clients #2
+// this is done server-side now
+//extern vmCvar_t cg_smoothClients;
+//unlagged - smooth clients #2
+extern vmCvar_t pmove_fixed;
+extern vmCvar_t pmove_msec;
+extern vmCvar_t pmove_float;
+//extern vmCvar_t cg_pmove_fixed;
+extern vmCvar_t cg_cameraOrbit;
+extern vmCvar_t cg_cameraOrbitDelay;
+extern vmCvar_t cg_timescaleFadeEnd;
+extern vmCvar_t cg_timescaleFadeSpeed;
+extern vmCvar_t cg_timescale;
+extern vmCvar_t cg_cameraMode;
+extern vmCvar_t cg_smallFont;
+extern vmCvar_t cg_bigFont;
+extern vmCvar_t cg_noTaunt;
+extern vmCvar_t cg_noProjectileTrail;
+extern vmCvar_t cg_oldRail;
+extern vmCvar_t cg_oldRocket;
+
+extern vmCvar_t cg_leiEnhancement; // LEILEI'S LINE!
+extern vmCvar_t cg_leiGoreNoise; // LEILEI'S LINE!
+extern vmCvar_t cg_leiBrassNoise; // LEILEI'S LINE!
+extern vmCvar_t cg_leiSuperGoreyAwesome; // LEILEI'S LINE!
+extern vmCvar_t cg_oldPlasma;
+extern vmCvar_t cg_trueLightning;
+extern vmCvar_t cg_music;
+#ifdef MISSIONPACK
+extern vmCvar_t cg_redTeamName;
+extern vmCvar_t cg_blueTeamName;
+extern vmCvar_t cg_currentSelectedPlayer;
+extern vmCvar_t cg_currentSelectedPlayerName;
+extern vmCvar_t cg_singlePlayer;
+extern vmCvar_t cg_singlePlayerActive;
+extern vmCvar_t cg_recordSPDemo;
+extern vmCvar_t cg_recordSPDemoName;
+#endif
+//Sago: Moved outside
+extern vmCvar_t cg_obeliskRespawnDelay;
+extern vmCvar_t cg_enableDust;
+extern vmCvar_t cg_enableBreath;
+
+//unlagged - client options
+extern vmCvar_t cg_delag;
+//extern vmCvar_t cg_debugDelag;
+//extern vmCvar_t cg_drawBBox;
+extern vmCvar_t cg_cmdTimeNudge;
+extern vmCvar_t sv_fps;
+extern vmCvar_t cg_projectileNudge;
+extern vmCvar_t cg_optimizePrediction;
+extern vmCvar_t cl_timeNudge;
+//extern vmCvar_t cg_latentSnaps;
+//extern vmCvar_t cg_latentCmds;
+//extern vmCvar_t cg_plOut;
+//unlagged - client options
+
+//extra CVARS elimination
+extern vmCvar_t cg_alwaysWeaponBar;
+extern vmCvar_t cg_hitsound;
+extern vmCvar_t cg_voip_teamonly;
+extern vmCvar_t cg_voteflags;
+extern vmCvar_t cg_cyclegrapple;
+extern vmCvar_t cg_vote_custom_commands;
+
+extern vmCvar_t cg_autovertex;
+
+//Cvar to adjust the size of the fragmessage
+extern vmCvar_t cg_fragmsgsize;
+
+extern vmCvar_t cg_crosshairPulse;
+extern vmCvar_t cg_differentCrosshairs;
+extern vmCvar_t cg_ch1;
+extern vmCvar_t cg_ch1size;
+extern vmCvar_t cg_ch2;
+extern vmCvar_t cg_ch2size;
+extern vmCvar_t cg_ch3;
+extern vmCvar_t cg_ch3size;
+extern vmCvar_t cg_ch4;
+extern vmCvar_t cg_ch4size;
+extern vmCvar_t cg_ch5;
+extern vmCvar_t cg_ch5size;
+extern vmCvar_t cg_ch6;
+extern vmCvar_t cg_ch6size;
+extern vmCvar_t cg_ch7;
+extern vmCvar_t cg_ch7size;
+extern vmCvar_t cg_ch8;
+extern vmCvar_t cg_ch8size;
+extern vmCvar_t cg_ch9;
+extern vmCvar_t cg_ch9size;
+extern vmCvar_t cg_ch10;
+extern vmCvar_t cg_ch10size;
+extern vmCvar_t cg_ch11;
+extern vmCvar_t cg_ch11size;
+extern vmCvar_t cg_ch12;
+extern vmCvar_t cg_ch12size;
+extern vmCvar_t cg_ch13;
+extern vmCvar_t cg_ch13size;
+
+extern vmCvar_t cg_crosshairColorRed;
+extern vmCvar_t cg_crosshairColorGreen;
+extern vmCvar_t cg_crosshairColorBlue;
+
+extern vmCvar_t cg_weaponBarStyle;
+
+extern vmCvar_t cg_weaponOrder;
+extern vmCvar_t cg_chatBeep;
+extern vmCvar_t cg_teamChatBeep;
+
+//unlagged - cg_unlagged.c
+void CG_PredictWeaponEffects( centity_t *cent );
+//void CG_AddBoundingBox( centity_t *cent );
+qboolean CG_Cvar_ClampInt( const char *name, vmCvar_t *vmCvar, int min, int max );
+//unlagged - cg_unlagged.c
+
+//
+// cg_main.c
+//
+const char *CG_ConfigString( int index );
+const char *CG_Argv( int arg );
+
+void QDECL CG_Printf( const char *msg, ... );
+void QDECL CG_Error( const char *msg, ... ) __attribute__((noreturn));
+
+void CG_StartMusic( void );
+
+void CG_UpdateCvars( void );
+
+int CG_CrosshairPlayer( void );
+int CG_LastAttacker( void );
+void CG_LoadMenus(const char *menuFile);
+void CG_KeyEvent(int key, qboolean down);
+void CG_MouseEvent(int x, int y);
+void CG_EventHandling(int type);
+void CG_RankRunFrame( void );
+void CG_SetScoreSelection(void *menu);
+//score_t *CG_GetSelectedScore( void );
+void CG_BuildSpectatorString( void );
+
+//unlagged, sagos modfication
+void SnapVectorTowards( vec3_t v, vec3_t to );
+
+void CG_FairCvars( void );
+
+//
+// cg_view.c
+//
+void CG_TestModel_f (void);
+void CG_TestGun_f (void);
+void CG_TestModelNextFrame_f (void);
+void CG_TestModelPrevFrame_f (void);
+void CG_TestModelNextSkin_f (void);
+void CG_TestModelPrevSkin_f (void);
+void CG_ZoomDown_f( void );
+void CG_ZoomUp_f( void );
+void CG_AddBufferedSound( sfxHandle_t sfx);
+
+void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
+
+
+//
+// cg_drawtools.c
+//
+void CG_AdjustFrom640( float *x, float *y, float *w, float *h );
+void CG_FillRect( float x, float y, float width, float height, const float *color );
+void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader );
+void CG_DrawString( float x, float y, const char *string,
+ float charWidth, float charHeight, const float *modulate );
+
+
+void CG_DrawStringExt( int x, int y, const char *string, const float *setColor,
+ qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars );
+void CG_DrawBigString( int x, int y, const char *s, float alpha );
+void CG_DrawBigStringColor( int x, int y, const char *s, vec4_t color );
+void CG_DrawSmallString( int x, int y, const char *s, float alpha );
+void CG_DrawSmallStringColor( int x, int y, const char *s, vec4_t color );
+
+int CG_DrawStrlen( const char *str );
+
+float *CG_FadeColor( int startMsec, int totalMsec );
+float *CG_TeamColor( int team );
+void CG_TileClear( void );
+void CG_ColorForHealth( vec4_t hcolor );
+void CG_GetColorForHealth( int health, int armor, vec4_t hcolor );
+
+void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );
+void CG_DrawRect( float x, float y, float width, float height, float size, const float *color );
+void CG_DrawSides(float x, float y, float w, float h, float size);
+void CG_DrawTopBottom(float x, float y, float w, float h, float size);
+
+
+//
+// cg_draw.c, cg_newDraw.c
+//
+extern int sortedTeamPlayers[TEAM_MAXOVERLAY];
+extern int numSortedTeamPlayers;
+extern int drawTeamOverlayModificationCount;
+extern char systemChat[256];
+extern char teamChat1[256];
+extern char teamChat2[256];
+
+void CG_AddLagometerFrameInfo( void );
+void CG_AddLagometerSnapshotInfo( snapshot_t *snap );
+void CG_CenterPrint( const char *str, int y, int charWidth );
+void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles );
+void CG_DrawActive( stereoFrame_t stereoView );
+void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D );
+void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team );
+void CG_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle);
+void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style);
+int CG_Text_Width(const char *text, float scale, int limit);
+int CG_Text_Height(const char *text, float scale, int limit);
+void CG_SelectPrevPlayer( void );
+void CG_SelectNextPlayer( void );
+float CG_GetValue(int ownerDraw);
+qboolean CG_OwnerDrawVisible(int flags);
+void CG_RunMenuScript(char **args);
+void CG_ShowResponseHead( void );
+void CG_SetPrintString(int type, const char *p);
+void CG_InitTeamChat( void );
+void CG_GetTeamColor(vec4_t *color);
+const char *CG_GetGameStatusText( void );
+const char *CG_GetKillerText( void );
+void CG_Draw3DModel(float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles);
+void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader);
+void CG_CheckOrderPending( void );
+const char *CG_GameTypeString( void );
+qboolean CG_YourTeamHasFlag( void );
+qboolean CG_OtherTeamHasFlag( void );
+qhandle_t CG_StatusHandle(int task);
+
+
+
+//
+// cg_player.c
+//
+void CG_Player( centity_t *cent );
+void CG_ResetPlayerEntity( centity_t *cent );
+void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team, qboolean isMissile );
+void CG_NewClientInfo( int clientNum );
+sfxHandle_t CG_CustomSound( int clientNum, const char *soundName );
+
+//
+// cg_predict.c
+//
+void CG_BuildSolidList( void );
+int CG_PointContents( const vec3_t point, int passEntityNum );
+void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
+ int skipNumber, int mask );
+void CG_PredictPlayerState( void );
+void CG_LoadDeferredPlayers( void );
+
+
+//
+// cg_events.c
+//
+void CG_CheckEvents( centity_t *cent );
+const char *CG_PlaceString( int rank );
+void CG_EntityEvent( centity_t *cent, vec3_t position );
+void CG_PainEvent( centity_t *cent, int health );
+
+
+//
+// cg_ents.c
+//
+void CG_SetEntitySoundPosition( centity_t *cent );
+void CG_AddPacketEntities( void );
+void CG_Beam( centity_t *cent );
+void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out );
+
+void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
+ qhandle_t parentModel, char *tagName );
+void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
+ qhandle_t parentModel, char *tagName );
+
+
+
+//
+// cg_weapons.c
+//
+void CG_NextWeapon_f( void );
+void CG_PrevWeapon_f( void );
+void CG_Weapon_f( void );
+
+void CG_RegisterWeapon( int weaponNum );
+void CG_RegisterItemVisuals( int itemNum );
+
+void CG_FireWeapon( centity_t *cent );
+void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType );
+void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum );
+void CG_ShotgunFire( entityState_t *es );
+void CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum );
+
+void CG_RailTrail( clientInfo_t *ci, vec3_t start, vec3_t end );
+void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi );
+void CG_AddViewWeapon (playerState_t *ps);
+void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team );
+void CG_DrawWeaponSelect( void );
+
+void CG_DrawWeaponBar0(int count, int bits);
+void CG_DrawWeaponBar1(int count, int bits);
+void CG_DrawWeaponBar2(int count, int bits, float *color);
+void CG_DrawWeaponBar3(int count, int bits, float *color);
+void CG_DrawWeaponBar4(int count, int bits, float *color);
+void CG_DrawWeaponBar5(int count, int bits, float *color);
+void CG_DrawWeaponBar6(int count, int bits, float *color);
+void CG_DrawWeaponBar7(int count, int bits, float *color);
+
+void CG_OutOfAmmoChange( void ); // should this be in pmove?
+
+//
+// cg_marks.c
+//
+void CG_InitMarkPolys( void );
+void CG_AddMarks( void );
+void CG_ImpactMark( qhandle_t markShader,
+ const vec3_t origin, const vec3_t dir,
+ float orientation,
+ float r, float g, float b, float a,
+ qboolean alphaFade,
+ float radius, qboolean temporary );
+void CG_LeiSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed);
+void CG_LeiSparks2 (vec3_t org, vec3_t vel, int duration, float x, float y, float speed);
+void CG_LeiPuff (vec3_t org, vec3_t vel, int duration, float x, float y, float speed, float size);
+
+
+//
+// cg_localents.c
+//
+void CG_InitLocalEntities( void );
+localEntity_t *CG_AllocLocalEntity( void );
+void CG_AddLocalEntities( void );
+
+//
+// cg_effects.c
+//
+localEntity_t *CG_SmokePuff( const vec3_t p,
+ const vec3_t vel,
+ float radius,
+ float r, float g, float b, float a,
+ float duration,
+ int startTime,
+ int fadeInTime,
+ int leFlags,
+ qhandle_t hShader );
+void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing );
+void CG_SpawnEffect( vec3_t org );
+//#ifdef MISSIONPACK
+void CG_KamikazeEffect( vec3_t org );
+void CG_ObeliskExplode( vec3_t org, int entityNum );
+void CG_ObeliskPain( vec3_t org );
+void CG_InvulnerabilityImpact( vec3_t org, vec3_t angles );
+void CG_InvulnerabilityJuiced( vec3_t org );
+void CG_LightningBoltBeam( vec3_t start, vec3_t end );
+//#endif
+void CG_ScorePlum( int client, vec3_t org, int score );
+
+void CG_GibPlayer( vec3_t playerOrigin );
+void CG_BigExplode( vec3_t playerOrigin );
+
+void CG_Bleed( vec3_t origin, int entityNum );
+
+localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
+ qhandle_t hModel, qhandle_t shader, int msec,
+ qboolean isSprite );
+
+void CG_SpurtBlood( vec3_t origin, vec3_t velocity, int hard );
+
+//
+// cg_snapshot.c
+//
+void CG_ProcessSnapshots( void );
+//unlagged - early transitioning
+void CG_TransitionEntity( centity_t *cent );
+//unlagged - early transitioning
+
+//
+// cg_info.c
+//
+void CG_LoadingString( const char *s );
+void CG_LoadingItem( int itemNum );
+void CG_LoadingClient( int clientNum );
+void CG_DrawInformation( void );
+
+//
+// cg_scoreboard.c
+//
+qboolean CG_DrawOldScoreboard( void );
+void CG_DrawOldTourneyScoreboard( void );
+
+//
+// cg_challenges.c
+//
+void challenges_init(void);
+void challenges_save(void);
+unsigned int getChallenge(int challenge);
+void addChallenge(int challenge);
+
+//
+// cg_consolecmds.c
+//
+qboolean CG_ConsoleCommand( void );
+void CG_InitConsoleCommands( void );
+
+//
+// cg_servercmds.c
+//
+void CG_ExecuteNewServerCommands( int latestSequence );
+void CG_ParseServerinfo( void );
+void CG_SetConfigValues( void );
+void CG_LoadVoiceChats( void );
+void CG_ShaderStateChanged(void);
+void CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd );
+void CG_PlayBufferedVoiceChats( void );
+
+//
+// cg_playerstate.c
+//
+void CG_Respawn( void );
+void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops );
+void CG_CheckChangedPredictableEvents( playerState_t *ps );
+
+
+//===============================================
+
+//
+// system traps
+// These functions are how the cgame communicates with the main game system
+//
+
+// print message on the local console
+void trap_Print( const char *fmt );
+
+// abort the game
+void trap_Error( const char *fmt ) __attribute__((noreturn));
+
+// milliseconds should only be used for performance tuning, never
+// for anything game related. Get time from the CG_DrawActiveFrame parameter
+int trap_Milliseconds( void );
+
+// console variable interaction
+void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
+void trap_Cvar_Update( vmCvar_t *vmCvar );
+void trap_Cvar_Set( const char *var_name, const char *value );
+void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
+
+// ServerCommand and ConsoleCommand parameter access
+int trap_Argc( void );
+void trap_Argv( int n, char *buffer, int bufferLength );
+void trap_Args( char *buffer, int bufferLength );
+
+// filesystem access
+// returns length of file
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
+void trap_FS_Read( void *buffer, int len, fileHandle_t f );
+void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
+void trap_FS_FCloseFile( fileHandle_t f );
+int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
+
+// add commands to the local console as if they were typed in
+// for map changing, etc. The command is not executed immediately,
+// but will be executed in order the next time console commands
+// are processed
+void trap_SendConsoleCommand( const char *text );
+
+// register a command name so the console can perform command completion.
+// FIXME: replace this with a normal console command "defineCommand"?
+void trap_AddCommand( const char *cmdName );
+
+// send a string to the server over the network
+void trap_SendClientCommand( const char *s );
+
+// force a screen update, only used during gamestate load
+void trap_UpdateScreen( void );
+
+// model collision
+void trap_CM_LoadMap( const char *mapname );
+int trap_CM_NumInlineModels( void );
+clipHandle_t trap_CM_InlineModel( int index ); // 0 = world, 1+ = bmodels
+clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs );
+int trap_CM_PointContents( const vec3_t p, clipHandle_t model );
+int trap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles );
+void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ const vec3_t mins, const vec3_t maxs,
+ clipHandle_t model, int brushmask );
+void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ const vec3_t mins, const vec3_t maxs,
+ clipHandle_t model, int brushmask,
+ const vec3_t origin, const vec3_t angles );
+
+// Returns the projection of a polygon onto the solid brushes in the world
+int trap_CM_MarkFragments( int numPoints, const vec3_t *points,
+ const vec3_t projection,
+ int maxPoints, vec3_t pointBuffer,
+ int maxFragments, markFragment_t *fragmentBuffer );
+
+// normal sounds will have their volume dynamically changed as their entity
+// moves and the listener moves
+void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx );
+void trap_S_StopLoopingSound(int entnum);
+
+// a local sound is always played full volume
+void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );
+void trap_S_ClearLoopingSounds( qboolean killall );
+void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
+void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
+void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin );
+
+// respatialize recalculates the volumes of sound as they should be heard by the
+// given entityNum and position
+void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
+sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ); // returns buzz if not found
+void trap_S_StartBackgroundTrack( const char *intro, const char *loop ); // empty name stops music
+void trap_S_StopBackgroundTrack( void );
+
+
+void trap_R_LoadWorldMap( const char *mapname );
+
+// all media should be registered during level startup to prevent
+// hitches during gameplay
+qhandle_t trap_R_RegisterModel( const char *name ); // returns rgb axis if not found
+qhandle_t trap_R_RegisterSkin( const char *name ); // returns all white if not found
+qhandle_t trap_R_RegisterShader( const char *name ); // returns all white if not found
+qhandle_t trap_R_RegisterShaderNoMip( const char *name ); // returns all white if not found
+
+// a scene is built up by calls to R_ClearScene and the various R_Add functions.
+// Nothing is drawn until R_RenderScene is called.
+void trap_R_ClearScene( void );
+void trap_R_AddRefEntityToScene( const refEntity_t *re );
+
+// polys are intended for simple wall marks, not really for doing
+// significant construction
+void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );
+void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int numPolys );
+void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
+int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
+void trap_R_RenderScene( const refdef_t *fd );
+void trap_R_SetColor( const float *rgba ); // NULL = 1,1,1,1
+void trap_R_DrawStretchPic( float x, float y, float w, float h,
+ float s1, float t1, float s2, float t2, qhandle_t hShader );
+void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );
+int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame,
+ float frac, const char *tagName );
+void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset );
+
+// The glconfig_t will not change during the life of a cgame.
+// If it needs to change, the entire cgame will be restarted, because
+// all the qhandle_t are then invalid.
+void trap_GetGlconfig( glconfig_t *glconfig );
+
+// the gamestate should be grabbed at startup, and whenever a
+// configstring changes
+void trap_GetGameState( gameState_t *gamestate );
+
+// cgame will poll each frame to see if a newer snapshot has arrived
+// that it is interested in. The time is returned seperately so that
+// snapshot latency can be calculated.
+void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime );
+
+// a snapshot get can fail if the snapshot (or the entties it holds) is so
+// old that it has fallen out of the client system queue
+qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot );
+
+// retrieve a text command from the server stream
+// the current snapshot will hold the number of the most recent command
+// qfalse can be returned if the client system handled the command
+// argc() / argv() can be used to examine the parameters of the command
+qboolean trap_GetServerCommand( int serverCommandNumber );
+
+// returns the most recent command number that can be passed to GetUserCmd
+// this will always be at least one higher than the number in the current
+// snapshot, and it may be quite a few higher if it is a fast computer on
+// a lagged connection
+int trap_GetCurrentCmdNumber( void );
+
+qboolean trap_GetUserCmd( int cmdNumber, usercmd_t *ucmd );
+
+// used for the weapon select and zoom
+void trap_SetUserCmdValue( int stateValue, float sensitivityScale );
+
+// aids for VM testing
+void testPrintInt( char *string, int i );
+void testPrintFloat( char *string, float f );
+
+int trap_MemoryRemaining( void );
+void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font);
+qboolean trap_Key_IsDown( int keynum );
+int trap_Key_GetCatcher( void );
+void trap_Key_SetCatcher( int catcher );
+int trap_Key_GetKey( const char *binding );
+
+
+typedef enum {
+ SYSTEM_PRINT,
+ CHAT_PRINT,
+ TEAMCHAT_PRINT
+} q3print_t; // bk001201 - warning: useless keyword or type name in empty declaration
+
+
+int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits);
+e_status trap_CIN_StopCinematic(int handle);
+e_status trap_CIN_RunCinematic (int handle);
+void trap_CIN_DrawCinematic (int handle);
+void trap_CIN_SetExtents (int handle, int x, int y, int w, int h);
+
+void trap_SnapVector( float *v );
+
+qboolean trap_loadCamera(const char *name);
+void trap_startCamera(int time);
+qboolean trap_getCameraInfo(int time, vec3_t *origin, vec3_t *angles);
+
+qboolean trap_GetEntityToken( char *buffer, int bufferSize );
+
+void CG_ClearParticles (void);
+void CG_AddParticles (void);
+void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum);
+void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent);
+void CG_AddParticleShrapnel (localEntity_t *le);
+void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent);
+void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration);
+void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed);
+void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir);
+void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha);
+void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd);
+extern qboolean initparticles;
+int CG_NewParticleArea ( int num );
+
+
+// LEILEI ENHANCEMENT
+
diff --git a/code/cgame/cg_localents.c b/code/cgame/cg_localents.c
new file mode 100644
index 0000000..e07e72b
--- /dev/null
+++ b/code/cgame/cg_localents.c
@@ -0,0 +1,1101 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+// cg_localents.c -- every frame, generate renderer commands for locally
+// processed entities, like smoke puffs, gibs, shells, etc.
+
+#include "cg_local.h"
+
+#define MAX_LOCAL_ENTITIES 512
+localEntity_t cg_localEntities[MAX_LOCAL_ENTITIES];
+localEntity_t cg_activeLocalEntities; // double linked list
+localEntity_t *cg_freeLocalEntities; // single linked list
+
+/*
+===================
+CG_InitLocalEntities
+
+This is called at startup and for tournement restarts
+===================
+*/
+void CG_InitLocalEntities( void ) {
+ int i;
+
+ memset( cg_localEntities, 0, sizeof( cg_localEntities ) );
+ cg_activeLocalEntities.next = &cg_activeLocalEntities;
+ cg_activeLocalEntities.prev = &cg_activeLocalEntities;
+ cg_freeLocalEntities = cg_localEntities;
+ for ( i = 0 ; i < MAX_LOCAL_ENTITIES - 1 ; i++ ) {
+ cg_localEntities[i].next = &cg_localEntities[i+1];
+ }
+}
+
+
+/*
+==================
+CG_FreeLocalEntity
+==================
+*/
+void CG_FreeLocalEntity( localEntity_t *le ) {
+ if ( !le->prev ) {
+ CG_Error( "CG_FreeLocalEntity: not active" );
+ }
+
+ // remove from the doubly linked active list
+ le->prev->next = le->next;
+ le->next->prev = le->prev;
+
+ // the free list is only singly linked
+ le->next = cg_freeLocalEntities;
+ cg_freeLocalEntities = le;
+}
+
+/*
+===================
+CG_AllocLocalEntity
+
+Will allways succeed, even if it requires freeing an old active entity
+===================
+*/
+localEntity_t *CG_AllocLocalEntity( void ) {
+ localEntity_t *le;
+
+ if ( !cg_freeLocalEntities ) {
+ // no free entities, so free the one at the end of the chain
+ // remove the oldest active entity
+ CG_FreeLocalEntity( cg_activeLocalEntities.prev );
+ }
+
+ le = cg_freeLocalEntities;
+ cg_freeLocalEntities = cg_freeLocalEntities->next;
+
+ memset( le, 0, sizeof( *le ) );
+
+ // link into the active list
+ le->next = cg_activeLocalEntities.next;
+ le->prev = &cg_activeLocalEntities;
+ cg_activeLocalEntities.next->prev = le;
+ cg_activeLocalEntities.next = le;
+ return le;
+}
+
+
+/*
+====================================================================================
+
+FRAGMENT PROCESSING
+
+A fragment localentity interacts with the environment in some way (hitting walls),
+or generates more localentities along a trail.
+
+====================================================================================
+*/
+
+/*
+================
+CG_BloodTrail
+
+Leave expanding blood puffs behind gibs
+================
+*/
+void CG_BloodTrail( localEntity_t *le ) {
+ int t;
+ int t2;
+ int step;
+ vec3_t newOrigin;
+ localEntity_t *blood;
+
+ step = 150;
+ t = step * ( (cg.time - cg.frametime + step ) / step );
+ t2 = step * ( cg.time / step );
+
+ for ( ; t <= t2; t += step ) {
+ BG_EvaluateTrajectory( &le->pos, t, newOrigin );
+
+ blood = CG_SmokePuff( newOrigin, vec3_origin,
+ 20, // radius
+ 1, 1, 1, 1, // color
+ 2000, // trailTime
+ t, // startTime
+ 0, // fadeInTime
+ 0, // flags
+ cgs.media.bloodTrailShader );
+ // use the optimized version
+ blood->leType = LE_FALL_SCALE_FADE;
+ // drop a total of 40 units over its lifetime
+ blood->pos.trDelta[2] = 40;
+ if ( cg_leiSuperGoreyAwesome.integer ) {
+// blood = CG_SpurtBlood( newOrigin, vec3_origin, 3); // LEILEI more gore plz
+ }
+ }
+}
+
+
+// LEILEI
+void CG_SmallBloodTrail( localEntity_t *le ) {
+ int t;
+ int t2;
+ int step;
+ vec3_t newOrigin;
+ localEntity_t *blood;
+
+ step = 61;
+ t = step * ( (cg.time - cg.frametime + step ) / step );
+ t2 = step * ( cg.time / step );
+
+ for ( ; t <= t2; t += step ) {
+ BG_EvaluateTrajectory( &le->pos, t, newOrigin );
+
+ blood = CG_SmokePuff( newOrigin, vec3_origin,
+ 3, // radius
+ 1, 1, 1, 1, // color
+ 770, // trailTime
+ t, // startTime
+ 0, // fadeInTime
+ 0, // flags
+ cgs.media.lbldShader1 );
+ // use the optimized version
+ blood->leType = LE_FALL_SCALE_FADE;
+ // drop a total of 40 units over its lifetime
+ blood->pos.trDelta[2] = 120;
+ }
+}
+
+
+
+/*
+================
+CG_FragmentBounceMark
+================
+*/
+void CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) {
+ int radius;
+
+ if ( le->leMarkType == LEMT_BLOOD ) {
+
+ radius = 16 + (rand()&31);
+ CG_ImpactMark( cgs.media.bloodMarkShader, trace->endpos, trace->plane.normal, random()*360,
+ 1,1,1,1, qtrue, radius, qfalse );
+ } else if ( le->leMarkType == LEMT_BURN ) {
+
+ radius = 8 + (rand()&15);
+ CG_ImpactMark( cgs.media.burnMarkShader, trace->endpos, trace->plane.normal, random()*360,
+ 1,1,1,1, qtrue, radius, qfalse );
+ }
+
+
+ // don't allow a fragment to make multiple marks, or they
+ // pile up while settling
+ le->leMarkType = LEMT_NONE;
+}
+
+/*
+================
+CG_FragmentBounceSound
+================
+*/
+void CG_FragmentBounceSound( localEntity_t *le, trace_t *trace ) {
+ if ( le->leBounceSoundType == LEBS_BLOOD ) {
+ // half the gibs will make splat sounds
+ if ( rand() & 1 ) {
+ int r = rand()&3;
+ sfxHandle_t s;
+
+ if ( r == 0 ) {
+ s = cgs.media.gibBounce1Sound;
+ } else if ( r == 1 ) {
+ s = cgs.media.gibBounce2Sound;
+ } else {
+ s = cgs.media.gibBounce3Sound;
+ }
+ trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );
+ }
+ } else if ( le->leBounceSoundType == LEBS_BRASS ) {
+ if ( cg_leiBrassNoise.integer ) {
+ // half the casings will make casing sounds
+ if ( rand() & 1 ) {
+ int r = rand()&3;
+ sfxHandle_t s;
+
+ if ( r == 0 ) {
+ s = cgs.media.lbul1Sound;
+ } else if ( r == 1 ) {
+ s = cgs.media.lbul2Sound;
+ } else {
+ s = cgs.media.lbul3Sound;
+ }
+ trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );
+ }
+ }
+
+ } else if ( le->leBounceSoundType == LEBS_SHELL ) {
+
+ if ( cg_leiBrassNoise.integer ) {
+
+ // half the casings will make casing sounds
+ if ( rand() & 1 ) {
+ int r = rand()&3;
+ sfxHandle_t s;
+
+ if ( r == 0 ) {
+ s = cgs.media.lshl1Sound;
+ } else if ( r == 1 ) {
+ s = cgs.media.lshl2Sound;
+ } else {
+ s = cgs.media.lshl3Sound;
+ }
+ trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );
+ }
+ }
+
+ }
+
+ // don't allow a fragment to make multiple bounce sounds,
+ // or it gets too noisy as they settle
+ le->leBounceSoundType = LEBS_NONE;
+}
+
+
+// LEILEI
+void CG_GoreMark( localEntity_t *le, trace_t *trace ) {
+ int radius;
+
+ if ( le->leMarkType == LEMT_BURN ) {
+
+ radius = 6 + (rand()&16);
+ CG_ImpactMark( cgs.media.lbldShader2, trace->endpos, trace->plane.normal, random()*360,
+ 1,1,1,1, qtrue, radius, qfalse );
+
+ }
+
+ le->leMarkType = LEMT_NONE;
+}
+
+
+/*
+================
+CG_SplatSound LEILEI
+================
+*/
+void CG_SplatSound( localEntity_t *le, trace_t *trace ) {
+ if ( le->leBounceSoundType == LEBS_BLOOD ) {
+ // half the splats will make splat sounds
+ if ( cg_leiGoreNoise.integer ) {
+ if ( rand() & 1 ) {
+ int r = rand()&3;
+ sfxHandle_t s;
+
+ if ( r == 0 ) {
+ s = cgs.media.lspl1Sound;
+ } else if ( r == 1 ) {
+ s = cgs.media.lspl2Sound;
+ } else {
+ s = cgs.media.lspl3Sound;
+ }
+ trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );
+ }
+ }
+ } else if ( le->leBounceSoundType == LEBS_BRASS ) {
+ // no GERMAN EURO CENSOR ROBOTS mode yet.
+ }
+
+ // don't allow a fragment to make multiple bounce sounds,
+ // or it gets too noisy as they settle
+ le->leBounceSoundType = LEBS_NONE;
+}
+
+
+
+/*
+================
+CG_ReflectVelocity
+================
+*/
+void CG_ReflectVelocity( localEntity_t *le, trace_t *trace ) {
+ vec3_t velocity;
+ float dot;
+ int hitTime;
+
+ // reflect the velocity on the trace plane
+ hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction;
+ BG_EvaluateTrajectoryDelta( &le->pos, hitTime, velocity );
+ dot = DotProduct( velocity, trace->plane.normal );
+ VectorMA( velocity, -2*dot, trace->plane.normal, le->pos.trDelta );
+
+ VectorScale( le->pos.trDelta, le->bounceFactor, le->pos.trDelta );
+
+ VectorCopy( trace->endpos, le->pos.trBase );
+ le->pos.trTime = cg.time;
+
+
+ // check for stop, making sure that even on low FPS systems it doesn't bobble
+ if ( trace->allsolid ||
+ ( trace->plane.normal[2] > 0 &&
+ ( le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2] ) ) ) {
+ le->pos.trType = TR_STATIONARY;
+ } else {
+
+ }
+}
+
+/*
+================
+CG_AddFragment
+================
+*/
+void CG_AddFragment( localEntity_t *le ) {
+ vec3_t newOrigin;
+ trace_t trace;
+
+ if ( le->pos.trType == TR_STATIONARY ) {
+ // sink into the ground if near the removal time
+ int t;
+ float oldZ;
+
+ t = le->endTime - cg.time;
+ if ( t < SINK_TIME ) {
+ // we must use an explicit lighting origin, otherwise the
+ // lighting would be lost as soon as the origin went
+ // into the ground
+ VectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin );
+ le->refEntity.renderfx |= RF_LIGHTING_ORIGIN;
+ oldZ = le->refEntity.origin[2];
+ le->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME );
+ trap_R_AddRefEntityToScene( &le->refEntity );
+ le->refEntity.origin[2] = oldZ;
+ } else {
+ trap_R_AddRefEntityToScene( &le->refEntity );
+ }
+
+ return;
+ }
+
+ // calculate new position
+ BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );
+
+ // trace a line from previous position to new position
+ CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
+ if ( trace.fraction == 1.0 ) {
+ // still in free fall
+ VectorCopy( newOrigin, le->refEntity.origin );
+
+ if ( le->leFlags & LEF_TUMBLE ) {
+ vec3_t angles;
+
+ BG_EvaluateTrajectory( &le->angles, cg.time, angles );
+ AnglesToAxis( angles, le->refEntity.axis );
+ }
+
+ trap_R_AddRefEntityToScene( &le->refEntity );
+
+ // add a blood trail
+ if ( le->leBounceSoundType == LEBS_BLOOD ) {
+ CG_BloodTrail( le );
+ }
+
+ return;
+ }
+
+ // if it is in a nodrop zone, remove it
+ // this keeps gibs from waiting at the bottom of pits of death
+ // and floating levels
+ if ( CG_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
+ CG_FreeLocalEntity( le );
+ return;
+ }
+
+ // leave a mark
+ CG_FragmentBounceMark( le, &trace );
+
+ // do a bouncy sound
+ CG_FragmentBounceSound( le, &trace );
+
+ // reflect the velocity on the trace plane
+ CG_ReflectVelocity( le, &trace );
+
+ trap_R_AddRefEntityToScene( &le->refEntity );
+}
+
+// LEILEI
+
+void CG_JustSplat( localEntity_t *le, trace_t *trace ) {
+ vec3_t velocity;
+ float dot;
+ int hitTime;
+
+ // reflect the velocity on the trace plane
+ hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction;
+ BG_EvaluateTrajectoryDelta( &le->pos, hitTime, velocity );
+ dot = DotProduct( velocity, trace->plane.normal );
+ VectorMA( velocity, -2*dot, trace->plane.normal, le->pos.trDelta );
+
+ VectorScale( le->pos.trDelta, le->bounceFactor, le->pos.trDelta );
+
+ VectorCopy( trace->endpos, le->pos.trBase );
+ le->pos.trTime = cg.time;
+
+
+ // check for stop, making sure that even on low FPS systems it doesn't bobble
+ if ( trace->allsolid ||
+ ( trace->plane.normal[2] > 0 &&
+ ( le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2] ) ) ) {
+ le->pos.trType = TR_STATIONARY;
+ } else {
+
+ }
+}
+
+void CG_AddGore( localEntity_t *le ) {
+ vec3_t newOrigin;
+ trace_t trace;
+
+ if ( le->pos.trType == TR_STATIONARY ) {
+ // sink into the ground if near the removal time
+ //int t;
+ //float oldZ;
+
+ CG_FreeLocalEntity( le ); // kill it
+
+ return;
+ }
+
+ // calculate new position
+ BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );
+
+ // trace a line from previous position to new position
+ CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
+ if ( trace.fraction == 1.0 ) {
+ // still in free fall
+ VectorCopy( newOrigin, le->refEntity.origin );
+
+ if ( le->leFlags & LEF_TUMBLE ) {
+ vec3_t angles;
+
+ BG_EvaluateTrajectory( &le->angles, cg.time, angles );
+ AnglesToAxis( angles, le->refEntity.axis );
+ }
+
+ trap_R_AddRefEntityToScene( &le->refEntity );
+
+ CG_SmallBloodTrail( le );
+
+ return;
+ }
+
+ // if it is in a nodrop zone, remove it
+ // this keeps gibs from waiting at the bottom of pits of death
+ // and floating levels
+ if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
+ CG_FreeLocalEntity( le );
+ return;
+ }
+
+ // leave a mark
+ CG_GoreMark( le, &trace );
+
+ // do a juicy sound
+ CG_SplatSound( le, &trace );
+
+ CG_JustSplat( le, &trace );
+
+ trap_R_AddRefEntityToScene( &le->refEntity );
+}
+
+/*
+=====================================================================
+
+TRIVIAL LOCAL ENTITIES
+
+These only do simple scaling or modulation before passing to the renderer
+=====================================================================
+*/
+
+/*
+====================
+CG_AddFadeRGB
+====================
+*/
+void CG_AddFadeRGB( localEntity_t *le ) {
+ refEntity_t *re;
+ float c;
+
+ re = &le->refEntity;
+
+ c = ( le->endTime - cg.time ) * le->lifeRate;
+ c *= 0xff;
+
+ re->shaderRGBA[0] = le->color[0] * c;
+ re->shaderRGBA[1] = le->color[1] * c;
+ re->shaderRGBA[2] = le->color[2] * c;
+ re->shaderRGBA[3] = le->color[3] * c;
+
+ trap_R_AddRefEntityToScene( re );
+}
+
+/*
+==================
+CG_AddMoveScaleFade
+==================
+*/
+static void CG_AddMoveScaleFade( localEntity_t *le ) {
+ refEntity_t *re;
+ float c;
+ vec3_t delta;
+ float len;
+
+ re = &le->refEntity;
+
+ if ( le->fadeInTime > le->startTime && cg.time < le->fadeInTime ) {
+ // fade / grow time
+ c = 1.0 - (float) ( le->fadeInTime - cg.time ) / ( le->fadeInTime - le->startTime );
+ }
+ else {
+ // fade / grow time
+ c = ( le->endTime - cg.time ) * le->lifeRate;
+ }
+
+ re->shaderRGBA[3] = 0xff * c * le->color[3];
+
+ if ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) {
+ re->radius = le->radius * ( 1.0 - c ) + 8;
+ }
+
+ BG_EvaluateTrajectory( &le->pos, cg.time, re->origin );
+
+ // if the view would be "inside" the sprite, kill the sprite
+ // so it doesn't add too much overdraw
+ VectorSubtract( re->origin, cg.refdef.vieworg, delta );
+ len = VectorLength( delta );
+ if ( len < le->radius ) {
+ CG_FreeLocalEntity( le );
+ return;
+ }
+
+ trap_R_AddRefEntityToScene( re );
+}
+
+
+/*
+===================
+CG_AddScaleFade
+
+For rocket smokes that hang in place, fade out, and are
+removed if the view passes through them.
+There are often many of these, so it needs to be simple.
+===================
+*/
+static void CG_AddScaleFade( localEntity_t *le ) {
+ refEntity_t *re;
+ float c;
+ vec3_t delta;
+ float len;
+
+ re = &le->refEntity;
+
+ // fade / grow time
+ c = ( le->endTime - cg.time ) * le->lifeRate;
+
+ re->shaderRGBA[3] = 0xff * c * le->color[3];
+ re->radius = le->radius * ( 1.0 - c ) + 8;
+
+ // if the view would be "inside" the sprite, kill the sprite
+ // so it doesn't add too much overdraw
+ VectorSubtract( re->origin, cg.refdef.vieworg, delta );
+ len = VectorLength( delta );
+ // LEILEI
+ if (!cg_leiEnhancement.integer) {
+ if ( len < le->radius ) {
+ CG_FreeLocalEntity( le );
+ return;
+ }
+ }
+ trap_R_AddRefEntityToScene( re );
+}
+
+
+/*
+=================
+CG_AddFallScaleFade
+
+This is just an optimized CG_AddMoveScaleFade
+For blood mists that drift down, fade out, and are
+removed if the view passes through them.
+There are often 100+ of these, so it needs to be simple.
+=================
+*/
+static void CG_AddFallScaleFade( localEntity_t *le ) {
+ refEntity_t *re;
+ float c;
+ vec3_t delta;
+ float len;
+
+ re = &le->refEntity;
+
+ // fade time
+ c = ( le->endTime - cg.time ) * le->lifeRate;
+
+ re->shaderRGBA[3] = 0xff * c * le->color[3];
+
+ re->origin[2] = le->pos.trBase[2] - ( 1.0 - c ) * le->pos.trDelta[2];
+
+ re->radius = le->radius * ( 1.0 - c ) + 16;
+
+ // if the view would be "inside" the sprite, kill the sprite
+ // so it doesn't add too much overdraw
+ VectorSubtract( re->origin, cg.refdef.vieworg, delta );
+ len = VectorLength( delta );
+
+ // LEILEI
+if (!cg_leiEnhancement.integer) {
+ if ( len < le->radius ) {
+ CG_FreeLocalEntity( le );
+ return;
+ }
+ }
+ trap_R_AddRefEntityToScene( re );
+}
+
+
+
+/*
+================
+CG_AddExplosion
+================
+*/
+static void CG_AddExplosion( localEntity_t *ex ) {
+ refEntity_t *ent;
+
+ ent = &ex->refEntity;
+
+ // add the entity
+ trap_R_AddRefEntityToScene(ent);
+
+ // add the dlight
+ if ( ex->light ) {
+ float light;
+
+ light = (float)( cg.time - ex->startTime ) / ( ex->endTime - ex->startTime );
+ if ( light < 0.5 ) {
+ light = 1.0;
+ } else {
+ light = 1.0 - ( light - 0.5 ) * 2;
+ }
+ light = ex->light * light;
+ trap_R_AddLightToScene(ent->origin, light, ex->lightColor[0], ex->lightColor[1], ex->lightColor[2] );
+ }
+}
+
+/*
+================
+CG_AddSpriteExplosion
+================
+*/
+static void CG_AddSpriteExplosion( localEntity_t *le ) {
+ refEntity_t re;
+ float c;
+
+ re = le->refEntity;
+
+ c = ( le->endTime - cg.time ) / ( float ) ( le->endTime - le->startTime );
+ if ( c > 1 ) {
+ c = 1.0; // can happen during connection problems
+ }
+
+ re.shaderRGBA[0] = 0xff;
+ re.shaderRGBA[1] = 0xff;
+ re.shaderRGBA[2] = 0xff;
+ re.shaderRGBA[3] = 0xff * c * 0.33;
+
+ re.reType = RT_SPRITE;
+ re.radius = 42 * ( 1.0 - c ) + 30;
+
+ trap_R_AddRefEntityToScene( &re );
+
+ // add the dlight
+ if ( le->light ) {
+ float light;
+
+ light = (float)( cg.time - le->startTime ) / ( le->endTime - le->startTime );
+ if ( light < 0.5 ) {
+ light = 1.0;
+ } else {
+ light = 1.0 - ( light - 0.5 ) * 2;
+ }
+ light = le->light * light;
+ trap_R_AddLightToScene(re.origin, light, le->lightColor[0], le->lightColor[1], le->lightColor[2] );
+ }
+}
+
+
+//#ifdef MISSIONPACK
+/*
+====================
+CG_AddKamikaze
+====================
+*/
+void CG_AddKamikaze( localEntity_t *le ) {
+ refEntity_t *re;
+ refEntity_t shockwave;
+ float c;
+ vec3_t test, axis[3];
+ int t;
+
+ re = &le->refEntity;
+
+ t = cg.time - le->startTime;
+ VectorClear( test );
+ AnglesToAxis( test, axis );
+
+ if (t > KAMI_SHOCKWAVE_STARTTIME && t < KAMI_SHOCKWAVE_ENDTIME) {
+
+ if (!(le->leFlags & LEF_SOUND1)) {
+// trap_S_StartSound (re->origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.kamikazeExplodeSound );
+ trap_S_StartLocalSound(cgs.media.kamikazeExplodeSound, CHAN_AUTO);
+ le->leFlags |= LEF_SOUND1;
+ }
+ // 1st kamikaze shockwave
+ memset(&shockwave, 0, sizeof(shockwave));
+ shockwave.hModel = cgs.media.kamikazeShockWave;
+ shockwave.reType = RT_MODEL;
+ shockwave.shaderTime = re->shaderTime;
+ VectorCopy(re->origin, shockwave.origin);
+
+ c = (float)(t - KAMI_SHOCKWAVE_STARTTIME) / (float)(KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVE_STARTTIME);
+ VectorScale( axis[0], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[0] );
+ VectorScale( axis[1], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[1] );
+ VectorScale( axis[2], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[2] );
+ shockwave.nonNormalizedAxes = qtrue;
+
+ if (t > KAMI_SHOCKWAVEFADE_STARTTIME) {
+ c = (float)(t - KAMI_SHOCKWAVEFADE_STARTTIME) / (float)(KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVEFADE_STARTTIME);
+ }
+ else {
+ c = 0;
+ }
+ c *= 0xff;
+ shockwave.shaderRGBA[0] = 0xff - c;
+ shockwave.shaderRGBA[1] = 0xff - c;
+ shockwave.shaderRGBA[2] = 0xff - c;
+ shockwave.shaderRGBA[3] = 0xff - c;
+
+ trap_R_AddRefEntityToScene( &shockwave );
+ }
+
+ if (t > KAMI_EXPLODE_STARTTIME && t < KAMI_IMPLODE_ENDTIME) {
+ // explosion and implosion
+ c = ( le->endTime - cg.time ) * le->lifeRate;
+ c *= 0xff;
+ re->shaderRGBA[0] = le->color[0] * c;
+ re->shaderRGBA[1] = le->color[1] * c;
+ re->shaderRGBA[2] = le->color[2] * c;
+ re->shaderRGBA[3] = le->color[3] * c;
+
+ if( t < KAMI_IMPLODE_STARTTIME ) {
+ c = (float)(t - KAMI_EXPLODE_STARTTIME) / (float)(KAMI_IMPLODE_STARTTIME - KAMI_EXPLODE_STARTTIME);
+ }
+ else {
+ if (!(le->leFlags & LEF_SOUND2)) {
+// trap_S_StartSound (re->origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.kamikazeImplodeSound );
+ trap_S_StartLocalSound(cgs.media.kamikazeImplodeSound, CHAN_AUTO);
+ le->leFlags |= LEF_SOUND2;
+ }
+ c = (float)(KAMI_IMPLODE_ENDTIME - t) / (float) (KAMI_IMPLODE_ENDTIME - KAMI_IMPLODE_STARTTIME);
+ }
+ VectorScale( axis[0], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[0] );
+ VectorScale( axis[1], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[1] );
+ VectorScale( axis[2], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[2] );
+ re->nonNormalizedAxes = qtrue;
+
+ trap_R_AddRefEntityToScene( re );
+ // add the dlight
+ trap_R_AddLightToScene( re->origin, c * 1000.0, 1.0, 1.0, c );
+ }
+
+ if (t > KAMI_SHOCKWAVE2_STARTTIME && t < KAMI_SHOCKWAVE2_ENDTIME) {
+ // 2nd kamikaze shockwave
+ if (le->angles.trBase[0] == 0 &&
+ le->angles.trBase[1] == 0 &&
+ le->angles.trBase[2] == 0) {
+ le->angles.trBase[0] = random() * 360;
+ le->angles.trBase[1] = random() * 360;
+ le->angles.trBase[2] = random() * 360;
+ }
+ else {
+ c = 0;
+ }
+ memset(&shockwave, 0, sizeof(shockwave));
+ shockwave.hModel = cgs.media.kamikazeShockWave;
+ shockwave.reType = RT_MODEL;
+ shockwave.shaderTime = re->shaderTime;
+ VectorCopy(re->origin, shockwave.origin);
+
+ test[0] = le->angles.trBase[0];
+ test[1] = le->angles.trBase[1];
+ test[2] = le->angles.trBase[2];
+ AnglesToAxis( test, axis );
+
+ c = (float)(t - KAMI_SHOCKWAVE2_STARTTIME) / (float)(KAMI_SHOCKWAVE2_ENDTIME - KAMI_SHOCKWAVE2_STARTTIME);
+ VectorScale( axis[0], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[0] );
+ VectorScale( axis[1], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[1] );
+ VectorScale( axis[2], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[2] );
+ shockwave.nonNormalizedAxes = qtrue;
+
+ if (t > KAMI_SHOCKWAVE2FADE_STARTTIME) {
+ c = (float)(t - KAMI_SHOCKWAVE2FADE_STARTTIME) / (float)(KAMI_SHOCKWAVE2_ENDTIME - KAMI_SHOCKWAVE2FADE_STARTTIME);
+ }
+ else {
+ c = 0;
+ }
+ c *= 0xff;
+ shockwave.shaderRGBA[0] = 0xff - c;
+ shockwave.shaderRGBA[1] = 0xff - c;
+ shockwave.shaderRGBA[2] = 0xff - c;
+ shockwave.shaderRGBA[3] = 0xff - c;
+
+ trap_R_AddRefEntityToScene( &shockwave );
+ }
+}
+
+/*
+===================
+CG_AddInvulnerabilityImpact
+===================
+*/
+void CG_AddInvulnerabilityImpact( localEntity_t *le ) {
+ trap_R_AddRefEntityToScene( &le->refEntity );
+}
+
+/*
+===================
+CG_AddInvulnerabilityJuiced
+===================
+*/
+void CG_AddInvulnerabilityJuiced( localEntity_t *le ) {
+ int t;
+
+ t = cg.time - le->startTime;
+ if ( t > 3000 ) {
+ le->refEntity.axis[0][0] = (float) 1.0 + 0.3 * (t - 3000) / 2000;
+ le->refEntity.axis[1][1] = (float) 1.0 + 0.3 * (t - 3000) / 2000;
+ le->refEntity.axis[2][2] = (float) 0.7 + 0.3 * (2000 - (t - 3000)) / 2000;
+ }
+ if ( t > 5000 ) {
+ le->endTime = 0;
+ CG_GibPlayer( le->refEntity.origin );
+ }
+ else {
+ trap_R_AddRefEntityToScene( &le->refEntity );
+ }
+}
+
+/*
+===================
+CG_AddRefEntity
+===================
+*/
+void CG_AddRefEntity( localEntity_t *le ) {
+ if (le->endTime < cg.time) {
+ CG_FreeLocalEntity( le );
+ return;
+ }
+ trap_R_AddRefEntityToScene( &le->refEntity );
+}
+
+//#endif
+/*
+===================
+CG_AddScorePlum
+===================
+*/
+#define NUMBER_SIZE 8
+
+void CG_AddScorePlum( localEntity_t *le ) {
+ refEntity_t *re;
+ vec3_t origin, delta, dir, vec, up = {0, 0, 1};
+ float c, len;
+ int i, score, digits[10], numdigits, negative;
+
+ re = &le->refEntity;
+
+ c = ( le->endTime - cg.time ) * le->lifeRate;
+
+ score = le->radius;
+ if (score < 0) {
+ re->shaderRGBA[0] = 0xff;
+ re->shaderRGBA[1] = 0x11;
+ re->shaderRGBA[2] = 0x11;
+ }
+ else {
+ re->shaderRGBA[0] = 0xff;
+ re->shaderRGBA[1] = 0xff;
+ re->shaderRGBA[2] = 0xff;
+ if (score >= 50) {
+ re->shaderRGBA[1] = 0;
+ } else if (score >= 20) {
+ re->shaderRGBA[0] = re->shaderRGBA[1] = 0;
+ } else if (score >= 10) {
+ re->shaderRGBA[2] = 0;
+ } else if (score >= 2) {
+ re->shaderRGBA[0] = re->shaderRGBA[2] = 0;
+ }
+
+ }
+ if (c < 0.25)
+ re->shaderRGBA[3] = 0xff * 4 * c;
+ else
+ re->shaderRGBA[3] = 0xff;
+
+ re->radius = NUMBER_SIZE / 2;
+
+ VectorCopy(le->pos.trBase, origin);
+ origin[2] += 110 - c * 100;
+
+ VectorSubtract(cg.refdef.vieworg, origin, dir);
+ CrossProduct(dir, up, vec);
+ VectorNormalize(vec);
+
+ VectorMA(origin, -10 + 20 * sin(c * 2 * M_PI), vec, origin);
+
+ // if the view would be "inside" the sprite, kill the sprite
+ // so it doesn't add too much overdraw
+ VectorSubtract( origin, cg.refdef.vieworg, delta );
+ len = VectorLength( delta );
+ if ( len < 20 ) {
+ CG_FreeLocalEntity( le );
+ return;
+ }
+
+ negative = qfalse;
+ if (score < 0) {
+ negative = qtrue;
+ score = -score;
+ }
+
+ for (numdigits = 0; !(numdigits && !score); numdigits++) {
+ digits[numdigits] = score % 10;
+ score = score / 10;
+ }
+
+ if (negative) {
+ digits[numdigits] = 10;
+ numdigits++;
+ }
+
+ for (i = 0; i < numdigits; i++) {
+ VectorMA(origin, (float) (((float) numdigits / 2) - i) * NUMBER_SIZE, vec, re->origin);
+ re->customShader = cgs.media.numberShaders[digits[numdigits-1-i]];
+ trap_R_AddRefEntityToScene( re );
+ }
+}
+
+
+
+
+//==============================================================================
+
+/*
+===================
+CG_AddLocalEntities
+
+===================
+*/
+void CG_AddLocalEntities( void ) {
+ localEntity_t *le, *next;
+
+ // walk the list backwards, so any new local entities generated
+ // (trails, marks, etc) will be present this frame
+ le = cg_activeLocalEntities.prev;
+ for ( ; le != &cg_activeLocalEntities ; le = next ) {
+ // grab next now, so if the local entity is freed we
+ // still have it
+ next = le->prev;
+
+ if ( cg.time >= le->endTime ) {
+ CG_FreeLocalEntity( le );
+ continue;
+ }
+ switch ( le->leType ) {
+ default:
+ CG_Error( "Bad leType: %i", le->leType );
+ break;
+
+ case LE_MARK:
+ break;
+
+ case LE_SPRITE_EXPLOSION:
+ CG_AddSpriteExplosion( le );
+ break;
+
+ case LE_EXPLOSION:
+ CG_AddExplosion( le );
+ break;
+
+ case LE_FRAGMENT: // gibs and brass
+ CG_AddFragment( le );
+ break;
+
+ case LE_MOVE_SCALE_FADE: // water bubbles
+ CG_AddMoveScaleFade( le );
+ break;
+
+ case LE_FADE_RGB: // teleporters, railtrails
+ CG_AddFadeRGB( le );
+ break;
+
+ case LE_FALL_SCALE_FADE: // gib blood trails
+ CG_AddFallScaleFade( le );
+ break;
+
+ case LE_SCALE_FADE: // rocket trails
+ CG_AddScaleFade( le );
+ break;
+
+ case LE_SCOREPLUM:
+ CG_AddScorePlum( le );
+ break;
+
+//#ifdef MISSIONPACK
+ case LE_KAMIKAZE:
+ CG_AddKamikaze( le );
+ break;
+ case LE_INVULIMPACT:
+ CG_AddInvulnerabilityImpact( le );
+ break;
+ case LE_INVULJUICED:
+ CG_AddInvulnerabilityJuiced( le );
+ break;
+ case LE_SHOWREFENTITY:
+ CG_AddRefEntity( le );
+ break;
+//#endif
+
+ case LE_GORE: // blood
+ CG_AddGore( le );
+ break;
+ }
+ }
+}
+
+
+
+
diff --git a/code/cgame/cg_main.c b/code/cgame/cg_main.c
new file mode 100644
index 0000000..a271d29
--- /dev/null
+++ b/code/cgame/cg_main.c
@@ -0,0 +1,2348 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_main.c -- initialization and primary entry point for cgame
+#include "cg_local.h"
+
+#ifdef MISSIONPACK
+#include "../ui/ui_shared.h"
+// display context for new ui stuff
+displayContextDef_t cgDC;
+#endif
+
+int forceModelModificationCount = -1;
+
+void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum );
+void CG_Shutdown( void );
+
+
+/*
+================
+vmMain
+
+This is the only way control passes into the module.
+This must be the very first function compiled into the .q3vm file
+================
+*/
+intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
+
+ switch ( command ) {
+ case CG_INIT:
+ CG_Init( arg0, arg1, arg2 );
+ return 0;
+ case CG_SHUTDOWN:
+ CG_Shutdown();
+ return 0;
+ case CG_CONSOLE_COMMAND:
+ return CG_ConsoleCommand();
+ case CG_DRAW_ACTIVE_FRAME:
+ CG_DrawActiveFrame( arg0, arg1, arg2 );
+ CG_FairCvars();
+ return 0;
+ case CG_CROSSHAIR_PLAYER:
+ return CG_CrosshairPlayer();
+ case CG_LAST_ATTACKER:
+ return CG_LastAttacker();
+ case CG_KEY_EVENT:
+ CG_KeyEvent(arg0, arg1);
+ return 0;
+ case CG_MOUSE_EVENT:
+#ifdef MISSIONPACK
+ cgDC.cursorx = cgs.cursorX;
+ cgDC.cursory = cgs.cursorY;
+#endif
+ CG_MouseEvent(arg0, arg1);
+ return 0;
+ case CG_EVENT_HANDLING:
+ CG_EventHandling(arg0);
+ return 0;
+ default:
+ CG_Error( "vmMain: unknown command %i", command );
+ break;
+ }
+ return -1;
+}
+
+
+cg_t cg;
+cgs_t cgs;
+centity_t cg_entities[MAX_GENTITIES];
+weaponInfo_t cg_weapons[MAX_WEAPONS];
+itemInfo_t cg_items[MAX_ITEMS];
+
+
+vmCvar_t cg_railTrailTime;
+vmCvar_t cg_centertime;
+vmCvar_t cg_runpitch;
+vmCvar_t cg_runroll;
+vmCvar_t cg_bobup;
+vmCvar_t cg_bobpitch;
+vmCvar_t cg_bobroll;
+vmCvar_t cg_swingSpeed;
+vmCvar_t cg_shadows;
+vmCvar_t cg_gibs;
+vmCvar_t cg_drawTimer;
+vmCvar_t cg_drawFPS;
+vmCvar_t cg_drawSnapshot;
+vmCvar_t cg_draw3dIcons;
+vmCvar_t cg_drawIcons;
+vmCvar_t cg_drawAmmoWarning;
+vmCvar_t cg_drawCrosshair;
+vmCvar_t cg_drawCrosshairNames;
+vmCvar_t cg_drawRewards;
+vmCvar_t cg_crosshairSize;
+vmCvar_t cg_crosshairX;
+vmCvar_t cg_crosshairY;
+vmCvar_t cg_crosshairHealth;
+vmCvar_t cg_draw2D;
+vmCvar_t cg_drawStatus;
+vmCvar_t cg_animSpeed;
+vmCvar_t cg_debugAnim;
+vmCvar_t cg_debugPosition;
+vmCvar_t cg_debugEvents;
+vmCvar_t cg_errorDecay;
+vmCvar_t cg_nopredict;
+vmCvar_t cg_noPlayerAnims;
+vmCvar_t cg_showmiss;
+vmCvar_t cg_footsteps;
+vmCvar_t cg_addMarks;
+vmCvar_t cg_brassTime;
+vmCvar_t cg_viewsize;
+vmCvar_t cg_drawGun;
+vmCvar_t cg_gun_frame;
+vmCvar_t cg_gun_x;
+vmCvar_t cg_gun_y;
+vmCvar_t cg_gun_z;
+vmCvar_t cg_tracerChance;
+vmCvar_t cg_tracerWidth;
+vmCvar_t cg_tracerLength;
+vmCvar_t cg_autoswitch;
+vmCvar_t cg_ignore;
+vmCvar_t cg_simpleItems;
+vmCvar_t cg_fov;
+vmCvar_t cg_zoomFov;
+vmCvar_t cg_thirdPerson;
+vmCvar_t cg_thirdPersonRange;
+vmCvar_t cg_thirdPersonAngle;
+vmCvar_t cg_lagometer;
+vmCvar_t cg_drawAttacker;
+vmCvar_t cg_drawSpeed;
+vmCvar_t cg_synchronousClients;
+vmCvar_t cg_teamChatTime;
+vmCvar_t cg_teamChatHeight;
+vmCvar_t cg_stats;
+vmCvar_t cg_buildScript;
+vmCvar_t cg_forceModel;
+vmCvar_t cg_paused;
+vmCvar_t cg_blood;
+vmCvar_t cg_predictItems;
+vmCvar_t cg_deferPlayers;
+vmCvar_t cg_drawTeamOverlay;
+vmCvar_t cg_teamOverlayUserinfo;
+vmCvar_t cg_drawFriend;
+vmCvar_t cg_teamChatsOnly;
+vmCvar_t cg_noVoiceChats;
+vmCvar_t cg_noVoiceText;
+vmCvar_t cg_hudFiles;
+vmCvar_t cg_scorePlum;
+//unlagged - smooth clients #2
+// this is done server-side now
+//vmCvar_t cg_smoothClients;
+//unlagged - smooth clients #2
+vmCvar_t pmove_fixed;
+//vmCvar_t cg_pmove_fixed;
+vmCvar_t pmove_msec;
+vmCvar_t pmove_float;
+vmCvar_t cg_pmove_msec;
+vmCvar_t cg_cameraMode;
+vmCvar_t cg_cameraOrbit;
+vmCvar_t cg_cameraOrbitDelay;
+vmCvar_t cg_timescaleFadeEnd;
+vmCvar_t cg_timescaleFadeSpeed;
+vmCvar_t cg_timescale;
+vmCvar_t cg_smallFont;
+vmCvar_t cg_bigFont;
+vmCvar_t cg_noTaunt;
+vmCvar_t cg_noProjectileTrail;
+vmCvar_t cg_oldRail;
+vmCvar_t cg_oldRocket;
+vmCvar_t cg_leiEnhancement; // ANOTHER LEILEI LINE!!!
+vmCvar_t cg_leiBrassNoise; // ANOTHER LEILEI LINE!!!
+vmCvar_t cg_leiGoreNoise; // ANOTHER LEILEI LINE!!!
+vmCvar_t cg_leiSuperGoreyAwesome; // ANOTHER LEILEI LINE!!!
+vmCvar_t cg_oldPlasma;
+vmCvar_t cg_trueLightning;
+vmCvar_t cg_music;
+vmCvar_t cg_weaponOrder;
+
+
+#ifdef MISSIONPACK
+vmCvar_t cg_redTeamName;
+vmCvar_t cg_blueTeamName;
+vmCvar_t cg_currentSelectedPlayer;
+vmCvar_t cg_currentSelectedPlayerName;
+vmCvar_t cg_singlePlayer;
+vmCvar_t cg_singlePlayerActive;
+vmCvar_t cg_recordSPDemo;
+vmCvar_t cg_recordSPDemoName;
+#endif
+vmCvar_t cg_obeliskRespawnDelay;
+vmCvar_t cg_enableDust;
+vmCvar_t cg_enableBreath;
+
+//unlagged - client options
+vmCvar_t cg_delag;
+//vmCvar_t cg_debugDelag;
+//vmCvar_t cg_drawBBox;
+vmCvar_t cg_cmdTimeNudge;
+vmCvar_t sv_fps;
+vmCvar_t cg_projectileNudge;
+vmCvar_t cg_optimizePrediction;
+vmCvar_t cl_timeNudge;
+//vmCvar_t cg_latentSnaps;
+//vmCvar_t cg_latentCmds;
+//vmCvar_t cg_plOut;
+//unlagged - client options
+
+//elimination addition
+vmCvar_t cg_alwaysWeaponBar;
+vmCvar_t cg_hitsound;
+vmCvar_t cg_voip_teamonly;
+vmCvar_t cg_voteflags;
+vmCvar_t cg_cyclegrapple;
+vmCvar_t cg_vote_custom_commands;
+
+vmCvar_t cg_autovertex;
+
+vmCvar_t cg_fragmsgsize;
+
+vmCvar_t cg_crosshairPulse;
+vmCvar_t cg_differentCrosshairs;
+vmCvar_t cg_ch1;
+vmCvar_t cg_ch1size;
+vmCvar_t cg_ch2;
+vmCvar_t cg_ch2size;
+vmCvar_t cg_ch3;
+vmCvar_t cg_ch3size;
+vmCvar_t cg_ch4;
+vmCvar_t cg_ch4size;
+vmCvar_t cg_ch5;
+vmCvar_t cg_ch5size;
+vmCvar_t cg_ch6;
+vmCvar_t cg_ch6size;
+vmCvar_t cg_ch7;
+vmCvar_t cg_ch7size;
+vmCvar_t cg_ch8;
+vmCvar_t cg_ch8size;
+vmCvar_t cg_ch9;
+vmCvar_t cg_ch9size;
+vmCvar_t cg_ch10;
+vmCvar_t cg_ch10size;
+vmCvar_t cg_ch11;
+vmCvar_t cg_ch11size;
+vmCvar_t cg_ch12;
+vmCvar_t cg_ch12size;
+vmCvar_t cg_ch13;
+vmCvar_t cg_ch13size;
+
+vmCvar_t cg_crosshairColorRed;
+vmCvar_t cg_crosshairColorGreen;
+vmCvar_t cg_crosshairColorBlue;
+
+vmCvar_t cg_weaponBarStyle;
+vmCvar_t cg_chatBeep;
+vmCvar_t cg_teamChatBeep;
+
+typedef struct {
+ vmCvar_t *vmCvar;
+ char *cvarName;
+ char *defaultString;
+ int cvarFlags;
+} cvarTable_t;
+
+static cvarTable_t cvarTable[] = { // bk001129
+ { &cg_ignore, "cg_ignore", "0", 0 }, // used for debugging
+ { &cg_autoswitch, "cg_autoswitch", "1", CVAR_ARCHIVE },
+ { &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE },
+ { &cg_zoomFov, "cg_zoomfov", "22.5", CVAR_ARCHIVE },
+ { &cg_fov, "cg_fov", "90", CVAR_ARCHIVE },
+ { &cg_viewsize, "cg_viewsize", "100", CVAR_ARCHIVE },
+ { &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE },
+ { &cg_gibs, "cg_gibs", "1", CVAR_ARCHIVE },
+ { &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE },
+ { &cg_drawStatus, "cg_drawStatus", "1", CVAR_ARCHIVE },
+ { &cg_drawTimer, "cg_drawTimer", "0", CVAR_ARCHIVE },
+ { &cg_drawFPS, "cg_drawFPS", "0", CVAR_ARCHIVE },
+ { &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE },
+ { &cg_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE },
+ { &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE },
+ { &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE },
+ { &cg_drawAttacker, "cg_drawAttacker", "1", CVAR_ARCHIVE },
+ { &cg_drawSpeed, "cg_drawSpeed", "0", CVAR_ARCHIVE },
+ { &cg_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
+ { &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
+ { &cg_drawRewards, "cg_drawRewards", "1", CVAR_ARCHIVE },
+ { &cg_crosshairSize, "cg_crosshairSize", "24", CVAR_ARCHIVE },
+ { &cg_crosshairHealth, "cg_crosshairHealth", "1", CVAR_ARCHIVE },
+ { &cg_crosshairX, "cg_crosshairX", "0", CVAR_ARCHIVE },
+ { &cg_crosshairY, "cg_crosshairY", "0", CVAR_ARCHIVE },
+ { &cg_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
+ { &cg_simpleItems, "cg_simpleItems", "0", CVAR_ARCHIVE },
+ { &cg_addMarks, "cg_marks", "1", CVAR_ARCHIVE },
+ { &cg_lagometer, "cg_lagometer", "1", CVAR_ARCHIVE },
+ { &cg_railTrailTime, "cg_railTrailTime", "600", CVAR_ARCHIVE },
+ { &cg_gun_x, "cg_gunX", "0", CVAR_CHEAT },
+ { &cg_gun_y, "cg_gunY", "0", CVAR_CHEAT },
+ { &cg_gun_z, "cg_gunZ", "0", CVAR_CHEAT },
+ { &cg_centertime, "cg_centertime", "3", CVAR_CHEAT },
+ { &cg_runpitch, "cg_runpitch", "0.002", CVAR_ARCHIVE},
+ { &cg_runroll, "cg_runroll", "0.005", CVAR_ARCHIVE },
+ { &cg_bobup , "cg_bobup", "0.005", CVAR_CHEAT },
+ { &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE },
+ { &cg_bobroll, "cg_bobroll", "0.002", CVAR_ARCHIVE },
+ { &cg_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT },
+ { &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT },
+ { &cg_debugAnim, "cg_debuganim", "0", CVAR_CHEAT },
+ { &cg_debugPosition, "cg_debugposition", "0", CVAR_CHEAT },
+ { &cg_debugEvents, "cg_debugevents", "0", CVAR_CHEAT },
+ { &cg_errorDecay, "cg_errordecay", "100", 0 },
+ { &cg_nopredict, "cg_nopredict", "0", 0 },
+ { &cg_noPlayerAnims, "cg_noplayeranims", "0", CVAR_CHEAT },
+ { &cg_showmiss, "cg_showmiss", "0", 0 },
+ { &cg_footsteps, "cg_footsteps", "1", CVAR_CHEAT },
+ { &cg_tracerChance, "cg_tracerchance", "0.4", CVAR_CHEAT },
+ { &cg_tracerWidth, "cg_tracerwidth", "1", CVAR_CHEAT },
+ { &cg_tracerLength, "cg_tracerlength", "100", CVAR_CHEAT },
+ { &cg_thirdPersonRange, "cg_thirdPersonRange", "40", CVAR_CHEAT },
+ { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", CVAR_CHEAT },
+ { &cg_thirdPerson, "cg_thirdPerson", "0", 0 },
+ { &cg_teamChatTime, "cg_teamChatTime", "3000", CVAR_ARCHIVE },
+ { &cg_teamChatHeight, "cg_teamChatHeight", "0", CVAR_ARCHIVE },
+ { &cg_forceModel, "cg_forceModel", "0", CVAR_ARCHIVE },
+ { &cg_predictItems, "cg_predictItems", "1", CVAR_ARCHIVE },
+#ifdef MISSIONPACK
+ { &cg_deferPlayers, "cg_deferPlayers", "0", CVAR_ARCHIVE },
+#else
+ { &cg_deferPlayers, "cg_deferPlayers", "1", CVAR_ARCHIVE },
+#endif
+ { &cg_drawTeamOverlay, "cg_drawTeamOverlay", "0", CVAR_ARCHIVE },
+ { &cg_teamOverlayUserinfo, "teamoverlay", "0", CVAR_ROM | CVAR_USERINFO },
+ { &cg_stats, "cg_stats", "0", 0 },
+ { &cg_drawFriend, "cg_drawFriend", "1", CVAR_ARCHIVE },
+ { &cg_teamChatsOnly, "cg_teamChatsOnly", "0", CVAR_ARCHIVE },
+ { &cg_noVoiceChats, "cg_noVoiceChats", "0", CVAR_ARCHIVE },
+ { &cg_noVoiceText, "cg_noVoiceText", "0", CVAR_ARCHIVE },
+ // the following variables are created in other parts of the system,
+ // but we also reference them here
+ { &cg_buildScript, "com_buildScript", "0", 0 }, // force loading of all possible data amd error on failures
+ { &cg_paused, "cl_paused", "0", CVAR_ROM },
+ { &cg_blood, "com_blood", "1", CVAR_ARCHIVE },
+ { &cg_alwaysWeaponBar, "cg_alwaysWeaponBar", "0", CVAR_ARCHIVE}, //Elimination
+ { &cg_hitsound, "cg_hitsound", "0", CVAR_ARCHIVE},
+ { &cg_voip_teamonly, "cg_voipTeamOnly", "1", CVAR_ARCHIVE},
+ { &cg_voteflags, "cg_voteflags", "*", CVAR_ROM},
+ { &cg_cyclegrapple, "cg_cyclegrapple", "1", CVAR_ARCHIVE},
+ { &cg_vote_custom_commands, "cg_vote_custom_commands", "", CVAR_ROM },
+ { &cg_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO }, // communicated by systeminfo
+
+ { &cg_autovertex, "cg_autovertex", "0", CVAR_ARCHIVE },
+#ifdef MISSIONPACK
+ { &cg_redTeamName, "g_redteam", DEFAULT_REDTEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO },
+ { &cg_blueTeamName, "g_blueteam", DEFAULT_BLUETEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO },
+ { &cg_currentSelectedPlayer, "cg_currentSelectedPlayer", "0", CVAR_ARCHIVE},
+ { &cg_currentSelectedPlayerName, "cg_currentSelectedPlayerName", "", CVAR_ARCHIVE},
+ { &cg_singlePlayer, "ui_singlePlayerActive", "0", CVAR_USERINFO},
+ { &cg_singlePlayerActive, "ui_singlePlayerActive", "0", CVAR_USERINFO},
+ { &cg_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE},
+ { &cg_recordSPDemoName, "ui_recordSPDemoName", "", CVAR_ARCHIVE},
+ { &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
+#endif
+ { &cg_enableDust, "g_enableDust", "0", CVAR_SERVERINFO},
+ { &cg_enableBreath, "g_enableBreath", "0", CVAR_SERVERINFO},
+ { &cg_obeliskRespawnDelay, "g_obeliskRespawnDelay", "10", CVAR_SERVERINFO},
+
+ { &cg_cameraOrbit, "cg_cameraOrbit", "0", CVAR_CHEAT},
+ { &cg_cameraOrbitDelay, "cg_cameraOrbitDelay", "50", CVAR_ARCHIVE},
+ { &cg_timescaleFadeEnd, "cg_timescaleFadeEnd", "1", 0},
+ { &cg_timescaleFadeSpeed, "cg_timescaleFadeSpeed", "0", 0},
+ { &cg_timescale, "timescale", "1", 0},
+ { &cg_scorePlum, "cg_scorePlums", "1", CVAR_USERINFO | CVAR_ARCHIVE},
+//unlagged - smooth clients #2
+// this is done server-side now
+// { &cg_smoothClients, "cg_smoothClients", "0", CVAR_USERINFO | CVAR_ARCHIVE},
+//unlagged - smooth clients #2
+ { &cg_cameraMode, "com_cameraMode", "0", CVAR_CHEAT},
+
+ { &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO},
+ { &pmove_msec, "pmove_msec", "11", CVAR_SYSTEMINFO},
+ { &pmove_float, "pmove_float", "1", CVAR_SYSTEMINFO},
+ { &cg_noTaunt, "cg_noTaunt", "0", CVAR_ARCHIVE},
+ { &cg_noProjectileTrail, "cg_noProjectileTrail", "0", CVAR_ARCHIVE},
+ { &cg_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE},
+ { &cg_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE},
+ { &cg_oldRail, "cg_oldRail", "0", CVAR_ARCHIVE},
+ { &cg_oldRocket, "cg_oldRocket", "1", CVAR_ARCHIVE},
+ { &cg_leiEnhancement, "cg_leiEnhancement", "0", CVAR_ARCHIVE}, // LEILEI default off (in case of whiner)
+ { &cg_leiGoreNoise, "cg_leiGoreNoise", "0", CVAR_ARCHIVE}, // LEILEI
+ { &cg_leiBrassNoise, "cg_leiBrassNoise", "0", CVAR_ARCHIVE}, // LEILEI
+ { &cg_leiSuperGoreyAwesome, "cg_leiSuperGoreyAwesome", "0", CVAR_ARCHIVE}, // LEILEI
+ { &cg_oldPlasma, "cg_oldPlasma", "1", CVAR_ARCHIVE},
+//unlagged - client options
+ { &cg_delag, "cg_delag", "1", CVAR_ARCHIVE | CVAR_USERINFO },
+// { &cg_debugDelag, "cg_debugDelag", "0", CVAR_USERINFO | CVAR_CHEAT },
+// { &cg_drawBBox, "cg_drawBBox", "0", CVAR_CHEAT },
+ { &cg_cmdTimeNudge, "cg_cmdTimeNudge", "0", CVAR_ARCHIVE | CVAR_USERINFO },
+ // this will be automagically copied from the server
+ { &sv_fps, "sv_fps", "20", CVAR_SYSTEMINFO },
+ { &cg_projectileNudge, "cg_projectileNudge", "0", CVAR_ARCHIVE },
+ { &cg_optimizePrediction, "cg_optimizePrediction", "1", CVAR_ARCHIVE },
+ { &cl_timeNudge, "cl_timeNudge", "0", CVAR_ARCHIVE },
+// { &cg_latentSnaps, "cg_latentSnaps", "0", CVAR_USERINFO | CVAR_CHEAT },
+// { &cg_latentCmds, "cg_latentCmds", "0", CVAR_USERINFO | CVAR_CHEAT },
+// { &cg_plOut, "cg_plOut", "0", CVAR_USERINFO | CVAR_CHEAT },
+//unlagged - client options
+ { &cg_trueLightning, "cg_trueLightning", "0.0", CVAR_ARCHIVE},
+ { &cg_music, "cg_music", "", CVAR_ARCHIVE},
+// { &cg_pmove_fixed, "cg_pmove_fixed", "0", CVAR_USERINFO | CVAR_ARCHIVE }
+
+ { &cg_fragmsgsize, "cg_fragmsgsize", "1.0", CVAR_ARCHIVE},
+ { &cg_crosshairPulse, "cg_crosshairPulse", "1", CVAR_ARCHIVE},
+
+ { &cg_differentCrosshairs, "cg_differentCrosshairs", "0", CVAR_ARCHIVE},
+ { &cg_ch1, "cg_ch1", "1", CVAR_ARCHIVE},
+ { &cg_ch1size, "cg_ch1size", "24", CVAR_ARCHIVE},
+ { &cg_ch2, "cg_ch2", "1", CVAR_ARCHIVE},
+ { &cg_ch2size, "cg_ch2size", "24", CVAR_ARCHIVE},
+ { &cg_ch3, "cg_ch3", "1", CVAR_ARCHIVE},
+ { &cg_ch3size, "cg_ch3size", "24", CVAR_ARCHIVE},
+ { &cg_ch4, "cg_ch4", "1", CVAR_ARCHIVE},
+ { &cg_ch4size, "cg_ch4size", "24", CVAR_ARCHIVE},
+ { &cg_ch5, "cg_ch5", "1", CVAR_ARCHIVE},
+ { &cg_ch5size, "cg_ch5size", "24", CVAR_ARCHIVE},
+ { &cg_ch6, "cg_ch6", "1", CVAR_ARCHIVE},
+ { &cg_ch6size, "cg_ch6size", "24", CVAR_ARCHIVE},
+ { &cg_ch7, "cg_ch7", "1", CVAR_ARCHIVE},
+ { &cg_ch7size, "cg_ch7size", "24", CVAR_ARCHIVE},
+ { &cg_ch8, "cg_ch8", "1", CVAR_ARCHIVE},
+ { &cg_ch8size, "cg_ch8size", "24", CVAR_ARCHIVE},
+ { &cg_ch9, "cg_ch9", "1", CVAR_ARCHIVE},
+ { &cg_ch9size, "cg_ch9size", "24", CVAR_ARCHIVE},
+ { &cg_ch10, "cg_ch10", "1", CVAR_ARCHIVE},
+ { &cg_ch10size, "cg_ch10size", "24", CVAR_ARCHIVE},
+ { &cg_ch11, "cg_ch11", "1", CVAR_ARCHIVE},
+ { &cg_ch11size, "cg_ch11size", "24", CVAR_ARCHIVE},
+ { &cg_ch12, "cg_ch12", "1", CVAR_ARCHIVE},
+ { &cg_ch12size, "cg_ch12size", "24", CVAR_ARCHIVE},
+ { &cg_ch13, "cg_ch13", "1", CVAR_ARCHIVE},
+ { &cg_ch13size, "cg_ch13size", "24", CVAR_ARCHIVE},
+
+ { &cg_crosshairColorRed, "cg_crosshairColorRed", "1.0", CVAR_ARCHIVE},
+ { &cg_crosshairColorGreen, "cg_crosshairColorGreen", "1.0", CVAR_ARCHIVE},
+ { &cg_crosshairColorBlue, "cg_crosshairColorBlue", "1.0", CVAR_ARCHIVE},
+
+ { &cg_weaponBarStyle, "cg_weaponBarStyle", "0", CVAR_ARCHIVE},
+ { &cg_weaponOrder,"cg_weaponOrder", "/1/2/4/3/6/7/8/9/5/", CVAR_ARCHIVE},
+ {&cg_chatBeep, "cg_chatBeep", "1", CVAR_ARCHIVE },
+ {&cg_teamChatBeep, "cg_teamChatBeep", "1", CVAR_ARCHIVE }
+};
+
+static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] );
+
+/*
+=================
+CG_RegisterCvars
+=================
+*/
+void CG_RegisterCvars( void ) {
+ int i;
+ cvarTable_t *cv;
+ char var[MAX_TOKEN_CHARS];
+
+ for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
+ trap_Cvar_Register( cv->vmCvar, cv->cvarName,
+ cv->defaultString, cv->cvarFlags );
+ }
+
+ // see if we are also running the server on this machine
+ trap_Cvar_VariableStringBuffer( "sv_running", var, sizeof( var ) );
+ cgs.localServer = atoi( var );
+
+ forceModelModificationCount = cg_forceModel.modificationCount;
+
+ trap_Cvar_Register(NULL, "model", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
+ trap_Cvar_Register(NULL, "headmodel", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
+ trap_Cvar_Register(NULL, "team_model", DEFAULT_TEAM_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
+ trap_Cvar_Register(NULL, "team_headmodel", DEFAULT_TEAM_HEAD, CVAR_USERINFO | CVAR_ARCHIVE );
+}
+
+/*
+===================
+CG_ForceModelChange
+===================
+*/
+static void CG_ForceModelChange( void ) {
+ int i;
+
+ for (i=0 ; i<MAX_CLIENTS ; i++) {
+ const char *clientInfo;
+
+ clientInfo = CG_ConfigString( CS_PLAYERS+i );
+ if ( !clientInfo[0] ) {
+ continue;
+ }
+ CG_NewClientInfo( i );
+ }
+}
+
+/*
+=================
+CG_UpdateCvars
+=================
+*/
+void CG_UpdateCvars( void ) {
+ int i;
+ cvarTable_t *cv;
+
+ for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
+//unlagged - client options
+ // clamp the value between 0 and 999
+ // negative values would suck - people could conceivably shoot other
+ // players *long* after they had left the area, on purpose
+ if ( cv->vmCvar == &cg_cmdTimeNudge ) {
+ CG_Cvar_ClampInt( cv->cvarName, cv->vmCvar, 0, 999 );
+ }
+ // cl_timenudge less than -50 or greater than 50 doesn't actually
+ // do anything more than -50 or 50 (actually the numbers are probably
+ // closer to -30 and 30, but 50 is nice and round-ish)
+ // might as well not feed the myth, eh?
+ else if ( cv->vmCvar == &cl_timeNudge ) {
+ CG_Cvar_ClampInt( cv->cvarName, cv->vmCvar, -50, 50 );
+ }
+ // don't let this go too high - no point
+ /*else if ( cv->vmCvar == &cg_latentSnaps ) {
+ CG_Cvar_ClampInt( cv->cvarName, cv->vmCvar, 0, 10 );
+ }*/
+ // don't let this get too large
+ /*else if ( cv->vmCvar == &cg_latentCmds ) {
+ CG_Cvar_ClampInt( cv->cvarName, cv->vmCvar, 0, MAX_LATENT_CMDS - 1 );
+ }*/
+ // no more than 100% packet loss
+ /*else if ( cv->vmCvar == &cg_plOut ) {
+ CG_Cvar_ClampInt( cv->cvarName, cv->vmCvar, 0, 100 );
+ }*/
+//unlagged - client options
+ else if ( cv->vmCvar == &cg_errorDecay ) {
+ CG_Cvar_ClampInt( cv->cvarName, cv->vmCvar, 0, 250 );
+ }
+ trap_Cvar_Update( cv->vmCvar );
+ }
+
+ // check for modications here
+
+ // If team overlay is on, ask for updates from the server. If its off,
+ // let the server know so we don't receive it
+ if ( drawTeamOverlayModificationCount != cg_drawTeamOverlay.modificationCount ) {
+ drawTeamOverlayModificationCount = cg_drawTeamOverlay.modificationCount;
+
+ if ( cg_drawTeamOverlay.integer > 0 ) {
+ trap_Cvar_Set( "teamoverlay", "1" );
+ } else {
+ trap_Cvar_Set( "teamoverlay", "0" );
+ }
+ }
+
+ // if force model changed
+ if ( forceModelModificationCount != cg_forceModel.modificationCount ) {
+ forceModelModificationCount = cg_forceModel.modificationCount;
+ CG_ForceModelChange();
+ }
+}
+
+int CG_CrosshairPlayer( void ) {
+ if ( cg.time > ( cg.crosshairClientTime + 1000 ) ) {
+ return -1;
+ }
+ return cg.crosshairClientNum;
+}
+
+int CG_LastAttacker( void ) {
+ if ( !cg.attackerTime ) {
+ return -1;
+ }
+ return cg.snap->ps.persistant[PERS_ATTACKER];
+}
+
+void QDECL CG_Printf( const char *msg, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, msg);
+ Q_vsnprintf (text, sizeof(text), msg, argptr);
+ va_end (argptr);
+
+ trap_Print( text );
+}
+
+void QDECL CG_Error( const char *msg, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, msg);
+ Q_vsnprintf (text, sizeof(text), msg, argptr);
+ va_end (argptr);
+
+ trap_Error( text );
+}
+
+void QDECL Com_Error( int level, const char *error, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, error);
+ Q_vsnprintf (text, sizeof(text), error, argptr);
+ va_end (argptr);
+
+ CG_Error( "%s", text);
+}
+
+void QDECL Com_Printf( const char *msg, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, msg);
+ Q_vsnprintf (text, sizeof(text), msg, argptr);
+ va_end (argptr);
+
+ CG_Printf ("%s", text);
+}
+
+/*
+================
+CG_Argv
+================
+*/
+const char *CG_Argv( int arg ) {
+ static char buffer[MAX_STRING_CHARS];
+
+ trap_Argv( arg, buffer, sizeof( buffer ) );
+
+ return buffer;
+}
+
+
+//========================================================================
+
+/*
+=================
+CG_RegisterItemSounds
+
+The server says this item is used on this level
+=================
+*/
+static void CG_RegisterItemSounds( int itemNum ) {
+ gitem_t *item;
+ char data[MAX_QPATH];
+ char *s, *start;
+ int len;
+
+ item = &bg_itemlist[ itemNum ];
+
+ if( item->pickup_sound ) {
+ trap_S_RegisterSound( item->pickup_sound, qfalse );
+ }
+
+ // parse the space seperated precache string for other media
+ s = item->sounds;
+ if (!s || !s[0])
+ return;
+
+ while (*s) {
+ start = s;
+ while (*s && *s != ' ') {
+ s++;
+ }
+
+ len = s-start;
+ if (len >= MAX_QPATH || len < 5) {
+ CG_Error( "PrecacheItem: %s has bad precache string",
+ item->classname);
+ return;
+ }
+ memcpy (data, start, len);
+ data[len] = 0;
+ if ( *s ) {
+ s++;
+ }
+
+ if ( !strcmp(data+len-3, "wav" )) {
+ trap_S_RegisterSound( data, qfalse );
+ }
+ }
+}
+
+
+/*
+=================
+CG_RegisterSounds
+
+called during a precache command
+=================
+*/
+static void CG_RegisterSounds( void ) {
+ int i;
+ char items[MAX_ITEMS+1];
+ char name[MAX_QPATH];
+ const char *soundName;
+
+ // voice commands
+#ifdef MISSIONPACK
+ CG_LoadVoiceChats();
+#endif
+
+ cgs.media.oneMinuteSound = trap_S_RegisterSound( "sound/feedback/1_minute.wav", qtrue );
+ cgs.media.fiveMinuteSound = trap_S_RegisterSound( "sound/feedback/5_minute.wav", qtrue );
+ cgs.media.suddenDeathSound = trap_S_RegisterSound( "sound/feedback/sudden_death.wav", qtrue );
+ cgs.media.oneFragSound = trap_S_RegisterSound( "sound/feedback/1_frag.wav", qtrue );
+ cgs.media.twoFragSound = trap_S_RegisterSound( "sound/feedback/2_frags.wav", qtrue );
+ cgs.media.threeFragSound = trap_S_RegisterSound( "sound/feedback/3_frags.wav", qtrue );
+ cgs.media.count3Sound = trap_S_RegisterSound( "sound/feedback/three.wav", qtrue );
+ cgs.media.count2Sound = trap_S_RegisterSound( "sound/feedback/two.wav", qtrue );
+ cgs.media.count1Sound = trap_S_RegisterSound( "sound/feedback/one.wav", qtrue );
+ cgs.media.countFightSound = trap_S_RegisterSound( "sound/feedback/fight.wav", qtrue );
+ cgs.media.countPrepareSound = trap_S_RegisterSound( "sound/feedback/prepare.wav", qtrue );
+#ifdef MISSIONPACK
+ cgs.media.countPrepareTeamSound = trap_S_RegisterSound( "sound/feedback/prepare_team.wav", qtrue );
+#endif
+
+ // N_G: Another condition that makes no sense to me, see for
+ // yourself if you really meant this
+ // Sago: Makes perfect sense: Load team game stuff if the gametype is a teamgame and not an exception (like GT_LMS)
+ if ( ( ( cgs.gametype >= GT_TEAM ) && ( cgs.ffa_gt != 1 ) ) ||
+ cg_buildScript.integer ) {
+
+ cgs.media.captureAwardSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qtrue );
+ cgs.media.redLeadsSound = trap_S_RegisterSound( "sound/feedback/redleads.wav", qtrue );
+ cgs.media.blueLeadsSound = trap_S_RegisterSound( "sound/feedback/blueleads.wav", qtrue );
+ cgs.media.teamsTiedSound = trap_S_RegisterSound( "sound/feedback/teamstied.wav", qtrue );
+ cgs.media.hitTeamSound = trap_S_RegisterSound( "sound/feedback/hit_teammate.wav", qtrue );
+
+ cgs.media.redScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_red_scores.wav", qtrue );
+ cgs.media.blueScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_scores.wav", qtrue );
+
+ cgs.media.captureYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qtrue );
+ cgs.media.captureOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_opponent.wav", qtrue );
+
+ cgs.media.returnYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_yourteam.wav", qtrue );
+ cgs.media.returnOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue );
+
+ cgs.media.takenYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_yourteam.wav", qtrue );
+ cgs.media.takenOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_opponent.wav", qtrue );
+
+ if ( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION|| cg_buildScript.integer ) {
+ cgs.media.redFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_red_returned.wav", qtrue );
+ cgs.media.blueFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_returned.wav", qtrue );
+ cgs.media.enemyTookYourFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_flag.wav", qtrue );
+ cgs.media.yourTeamTookEnemyFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_flag.wav", qtrue );
+ }
+
+ if ( cgs.gametype == GT_1FCTF || cg_buildScript.integer ) {
+ // FIXME: get a replacement for this sound ?
+ cgs.media.neutralFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue );
+ cgs.media.yourTeamTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_1flag.wav", qtrue );
+ cgs.media.enemyTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_1flag.wav", qtrue );
+ }
+
+ if ( cgs.gametype == GT_1FCTF || cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION ||cg_buildScript.integer ) {
+ cgs.media.youHaveFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_you_flag.wav", qtrue );
+ cgs.media.holyShitSound = trap_S_RegisterSound("sound/feedback/voc_holyshit.wav", qtrue);
+ }
+
+ if ( cgs.gametype == GT_OBELISK || cg_buildScript.integer ) {
+ cgs.media.yourBaseIsUnderAttackSound = trap_S_RegisterSound( "sound/teamplay/voc_base_attack.wav", qtrue );
+ }
+ }
+
+ cgs.media.tracerSound = trap_S_RegisterSound( "sound/weapons/machinegun/buletby1.wav", qfalse );
+ cgs.media.selectSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse );
+ cgs.media.wearOffSound = trap_S_RegisterSound( "sound/items/wearoff.wav", qfalse );
+ cgs.media.useNothingSound = trap_S_RegisterSound( "sound/items/use_nothing.wav", qfalse );
+ cgs.media.gibSound = trap_S_RegisterSound( "sound/player/gibsplt1.wav", qfalse );
+ cgs.media.gibBounce1Sound = trap_S_RegisterSound( "sound/player/gibimp1.wav", qfalse );
+ cgs.media.gibBounce2Sound = trap_S_RegisterSound( "sound/player/gibimp2.wav", qfalse );
+ cgs.media.gibBounce3Sound = trap_S_RegisterSound( "sound/player/gibimp3.wav", qfalse );
+
+
+ // LEILEI
+
+ cgs.media.lspl1Sound = trap_S_RegisterSound( "sound/le/splat1.wav", qfalse );
+ cgs.media.lspl2Sound = trap_S_RegisterSound( "sound/le/splat2.wav", qfalse );
+ cgs.media.lspl3Sound = trap_S_RegisterSound( "sound/le/splat3.wav", qfalse );
+
+ cgs.media.lbul1Sound = trap_S_RegisterSound( "sound/le/bullet1.wav", qfalse );
+ cgs.media.lbul2Sound = trap_S_RegisterSound( "sound/le/bullet2.wav", qfalse );
+ cgs.media.lbul3Sound = trap_S_RegisterSound( "sound/le/bullet3.wav", qfalse );
+
+ cgs.media.lshl1Sound = trap_S_RegisterSound( "sound/le/shell1.wav", qfalse );
+ cgs.media.lshl2Sound = trap_S_RegisterSound( "sound/le/shell2.wav", qfalse );
+ cgs.media.lshl3Sound = trap_S_RegisterSound( "sound/le/shell3.wav", qfalse );
+
+ cgs.media.useInvulnerabilitySound = trap_S_RegisterSound( "sound/items/invul_activate.wav", qfalse );
+ cgs.media.invulnerabilityImpactSound1 = trap_S_RegisterSound( "sound/items/invul_impact_01.wav", qfalse );
+ cgs.media.invulnerabilityImpactSound2 = trap_S_RegisterSound( "sound/items/invul_impact_02.wav", qfalse );
+ cgs.media.invulnerabilityImpactSound3 = trap_S_RegisterSound( "sound/items/invul_impact_03.wav", qfalse );
+ cgs.media.invulnerabilityJuicedSound = trap_S_RegisterSound( "sound/items/invul_juiced.wav", qfalse );
+
+ cgs.media.ammoregenSound = trap_S_RegisterSound("sound/items/cl_ammoregen.wav", qfalse);
+ cgs.media.doublerSound = trap_S_RegisterSound("sound/items/cl_doubler.wav", qfalse);
+ cgs.media.guardSound = trap_S_RegisterSound("sound/items/cl_guard.wav", qfalse);
+ cgs.media.scoutSound = trap_S_RegisterSound("sound/items/cl_scout.wav", qfalse);
+ cgs.media.obeliskHitSound1 = trap_S_RegisterSound( "sound/items/obelisk_hit_01.wav", qfalse );
+ cgs.media.obeliskHitSound2 = trap_S_RegisterSound( "sound/items/obelisk_hit_02.wav", qfalse );
+ cgs.media.obeliskHitSound3 = trap_S_RegisterSound( "sound/items/obelisk_hit_03.wav", qfalse );
+ cgs.media.obeliskRespawnSound = trap_S_RegisterSound( "sound/items/obelisk_respawn.wav", qfalse );
+
+ cgs.media.teleInSound = trap_S_RegisterSound( "sound/world/telein.wav", qfalse );
+ cgs.media.teleOutSound = trap_S_RegisterSound( "sound/world/teleout.wav", qfalse );
+ cgs.media.respawnSound = trap_S_RegisterSound( "sound/items/respawn1.wav", qfalse );
+
+ cgs.media.noAmmoSound = trap_S_RegisterSound( "sound/weapons/noammo.wav", qfalse );
+
+ cgs.media.talkSound = trap_S_RegisterSound( "sound/player/talk.wav", qfalse );
+ cgs.media.landSound = trap_S_RegisterSound( "sound/player/land1.wav", qfalse);
+
+ switch(cg_hitsound.integer) {
+
+ case 0:
+ default:
+ cgs.media.hitSound = trap_S_RegisterSound( "sound/feedback/hit.wav", qfalse );
+ };
+
+#ifdef MISSIONPACK
+ cgs.media.hitSoundHighArmor = trap_S_RegisterSound( "sound/feedback/hithi.wav", qfalse );
+ cgs.media.hitSoundLowArmor = trap_S_RegisterSound( "sound/feedback/hitlo.wav", qfalse );
+#endif
+
+ cgs.media.impressiveSound = trap_S_RegisterSound( "sound/feedback/impressive.wav", qtrue );
+ cgs.media.excellentSound = trap_S_RegisterSound( "sound/feedback/excellent.wav", qtrue );
+ cgs.media.deniedSound = trap_S_RegisterSound( "sound/feedback/denied.wav", qtrue );
+ cgs.media.humiliationSound = trap_S_RegisterSound( "sound/feedback/humiliation.wav", qtrue );
+ cgs.media.assistSound = trap_S_RegisterSound( "sound/feedback/assist.wav", qtrue );
+ cgs.media.defendSound = trap_S_RegisterSound( "sound/feedback/defense.wav", qtrue );
+#ifdef MISSIONPACK
+ cgs.media.firstImpressiveSound = trap_S_RegisterSound( "sound/feedback/first_impressive.wav", qtrue );
+ cgs.media.firstExcellentSound = trap_S_RegisterSound( "sound/feedback/first_excellent.wav", qtrue );
+ cgs.media.firstHumiliationSound = trap_S_RegisterSound( "sound/feedback/first_gauntlet.wav", qtrue );
+#endif
+
+ cgs.media.takenLeadSound = trap_S_RegisterSound( "sound/feedback/takenlead.wav", qtrue);
+ cgs.media.tiedLeadSound = trap_S_RegisterSound( "sound/feedback/tiedlead.wav", qtrue);
+ cgs.media.lostLeadSound = trap_S_RegisterSound( "sound/feedback/lostlead.wav", qtrue);
+
+#ifdef MISSIONPACK
+ cgs.media.voteNow = trap_S_RegisterSound( "sound/feedback/vote_now.wav", qtrue);
+ cgs.media.votePassed = trap_S_RegisterSound( "sound/feedback/vote_passed.wav", qtrue);
+ cgs.media.voteFailed = trap_S_RegisterSound( "sound/feedback/vote_failed.wav", qtrue);
+#endif
+
+ cgs.media.watrInSound = trap_S_RegisterSound( "sound/player/watr_in.wav", qfalse);
+ cgs.media.watrOutSound = trap_S_RegisterSound( "sound/player/watr_out.wav", qfalse);
+ cgs.media.watrUnSound = trap_S_RegisterSound( "sound/player/watr_un.wav", qfalse);
+
+ cgs.media.jumpPadSound = trap_S_RegisterSound ("sound/world/jumppad.wav", qfalse );
+
+ for (i=0 ; i<4 ; i++) {
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/step%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_NORMAL][i] = trap_S_RegisterSound (name, qfalse);
+
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/boot%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_BOOT][i] = trap_S_RegisterSound (name, qfalse);
+
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/flesh%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_FLESH][i] = trap_S_RegisterSound (name, qfalse);
+
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/mech%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_MECH][i] = trap_S_RegisterSound (name, qfalse);
+
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/energy%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_ENERGY][i] = trap_S_RegisterSound (name, qfalse);
+
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/splash%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_SPLASH][i] = trap_S_RegisterSound (name, qfalse);
+
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/clank%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_METAL][i] = trap_S_RegisterSound (name, qfalse);
+ }
+
+ // only register the items that the server says we need
+ Q_strncpyz(items, CG_ConfigString(CS_ITEMS), sizeof(items));
+
+ for ( i = 1 ; i < bg_numItems ; i++ ) {
+// if ( items[ i ] == '1' || cg_buildScript.integer ) {
+ CG_RegisterItemSounds( i );
+// }
+ }
+
+ for ( i = 1 ; i < MAX_SOUNDS ; i++ ) {
+ soundName = CG_ConfigString( CS_SOUNDS+i );
+ if ( !soundName[0] ) {
+ break;
+ }
+ if ( soundName[0] == '*' ) {
+ continue; // custom sound
+ }
+ cgs.gameSounds[i] = trap_S_RegisterSound( soundName, qfalse );
+ }
+
+ // FIXME: only needed with item
+ cgs.media.flightSound = trap_S_RegisterSound( "sound/items/flight.wav", qfalse );
+ cgs.media.medkitSound = trap_S_RegisterSound ("sound/items/use_medkit.wav", qfalse);
+ cgs.media.quadSound = trap_S_RegisterSound("sound/items/damage3.wav", qfalse);
+ cgs.media.sfx_ric1 = trap_S_RegisterSound ("sound/weapons/machinegun/ric1.wav", qfalse);
+ cgs.media.sfx_ric2 = trap_S_RegisterSound ("sound/weapons/machinegun/ric2.wav", qfalse);
+ cgs.media.sfx_ric3 = trap_S_RegisterSound ("sound/weapons/machinegun/ric3.wav", qfalse);
+ cgs.media.sfx_railg = trap_S_RegisterSound ("sound/weapons/railgun/railgf1a.wav", qfalse);
+ cgs.media.sfx_rockexp = trap_S_RegisterSound ("sound/weapons/rocket/rocklx1a.wav", qfalse);
+ cgs.media.sfx_plasmaexp = trap_S_RegisterSound ("sound/weapons/plasma/plasmx1a.wav", qfalse);
+ cgs.media.sfx_proxexp = trap_S_RegisterSound( "sound/weapons/proxmine/wstbexpl.wav" , qfalse);
+ cgs.media.sfx_nghit = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpd.wav" , qfalse);
+ cgs.media.sfx_nghitflesh = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpl.wav" , qfalse);
+ cgs.media.sfx_nghitmetal = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpm.wav", qfalse );
+ cgs.media.sfx_chghit = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpd.wav", qfalse );
+ cgs.media.sfx_chghitflesh = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpl.wav", qfalse );
+ cgs.media.sfx_chghitmetal = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpm.wav", qfalse );
+ cgs.media.weaponHoverSound = trap_S_RegisterSound( "sound/weapons/weapon_hover.wav", qfalse );
+ cgs.media.kamikazeExplodeSound = trap_S_RegisterSound( "sound/items/kam_explode.wav", qfalse );
+ cgs.media.kamikazeImplodeSound = trap_S_RegisterSound( "sound/items/kam_implode.wav", qfalse );
+ cgs.media.kamikazeFarSound = trap_S_RegisterSound( "sound/items/kam_explode_far.wav", qfalse );
+ cgs.media.winnerSound = trap_S_RegisterSound( "sound/feedback/voc_youwin.wav", qfalse );
+ cgs.media.loserSound = trap_S_RegisterSound( "sound/feedback/voc_youlose.wav", qfalse );
+ cgs.media.youSuckSound = trap_S_RegisterSound( "sound/misc/yousuck.wav", qfalse );
+
+ cgs.media.wstbimplSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpl.wav", qfalse);
+ cgs.media.wstbimpmSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpm.wav", qfalse);
+ cgs.media.wstbimpdSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpd.wav", qfalse);
+ cgs.media.wstbactvSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbactv.wav", qfalse);
+
+ cgs.media.regenSound = trap_S_RegisterSound("sound/items/regen.wav", qfalse);
+ cgs.media.protectSound = trap_S_RegisterSound("sound/items/protect3.wav", qfalse);
+ cgs.media.n_healthSound = trap_S_RegisterSound("sound/items/n_health.wav", qfalse );
+ cgs.media.hgrenb1aSound = trap_S_RegisterSound("sound/weapons/grenade/hgrenb1a.wav", qfalse);
+ cgs.media.hgrenb2aSound = trap_S_RegisterSound("sound/weapons/grenade/hgrenb2a.wav", qfalse);
+
+#ifdef MISSIONPACK
+ trap_S_RegisterSound("sound/player/sergei/death1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/sergei/death2.wav", qfalse );
+ trap_S_RegisterSound("sound/player/sergei/death3.wav", qfalse );
+ trap_S_RegisterSound("sound/player/sergei/jump1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/sergei/pain25_1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/sergei/pain75_1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/sergei/pain100_1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/sergei/falling1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/sergei/gasp.wav", qfalse );
+ trap_S_RegisterSound("sound/player/sergei/drown.wav", qfalse );
+ trap_S_RegisterSound("sound/player/sergei/fall1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/sergei/taunt.wav", qfalse );
+
+ trap_S_RegisterSound("sound/player/kyonshi/death1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/kyonshi/death2.wav", qfalse );
+ trap_S_RegisterSound("sound/player/kyonshi/death3.wav", qfalse );
+ trap_S_RegisterSound("sound/player/kyonshi/jump1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/kyonshi/pain25_1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/kyonshi/pain75_1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/kyonshi/pain100_1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/kyonshi/falling1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/kyonshi/gasp.wav", qfalse );
+ trap_S_RegisterSound("sound/player/kyonshi/drown.wav", qfalse );
+ trap_S_RegisterSound("sound/player/kyonshi/fall1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/kyonshi/taunt.wav", qfalse );
+#endif
+
+}
+
+
+//===================================================================================
+
+
+/*
+=================
+CG_RegisterGraphics
+
+This function may execute for a couple of minutes with a slow disk.
+=================
+*/
+static void CG_RegisterGraphics( void ) {
+ int i;
+ char items[MAX_ITEMS+1];
+ static char *sb_nums[11] = {
+ "gfx/2d/numbers/zero_32b",
+ "gfx/2d/numbers/one_32b",
+ "gfx/2d/numbers/two_32b",
+ "gfx/2d/numbers/three_32b",
+ "gfx/2d/numbers/four_32b",
+ "gfx/2d/numbers/five_32b",
+ "gfx/2d/numbers/six_32b",
+ "gfx/2d/numbers/seven_32b",
+ "gfx/2d/numbers/eight_32b",
+ "gfx/2d/numbers/nine_32b",
+ "gfx/2d/numbers/minus_32b",
+ };
+
+ // clear any references to old media
+ memset( &cg.refdef, 0, sizeof( cg.refdef ) );
+ trap_R_ClearScene();
+
+ CG_LoadingString( cgs.mapname );
+
+ trap_R_LoadWorldMap( cgs.mapname );
+
+ // precache status bar pics
+ CG_LoadingString( "game media" );
+
+ for ( i=0 ; i<11 ; i++) {
+ cgs.media.numberShaders[i] = trap_R_RegisterShader( sb_nums[i] );
+ }
+
+ cgs.media.botSkillShaders[0] = trap_R_RegisterShader( "menu/art/skill1.tga" );
+ cgs.media.botSkillShaders[1] = trap_R_RegisterShader( "menu/art/skill2.tga" );
+ cgs.media.botSkillShaders[2] = trap_R_RegisterShader( "menu/art/skill3.tga" );
+ cgs.media.botSkillShaders[3] = trap_R_RegisterShader( "menu/art/skill4.tga" );
+ cgs.media.botSkillShaders[4] = trap_R_RegisterShader( "menu/art/skill5.tga" );
+
+ cgs.media.viewBloodShader = trap_R_RegisterShader( "viewBloodBlend" );
+
+ cgs.media.deferShader = trap_R_RegisterShaderNoMip( "gfx/2d/defer.tga" );
+
+ cgs.media.scoreboardName = trap_R_RegisterShaderNoMip( "menu/tab/name.tga" );
+ cgs.media.scoreboardPing = trap_R_RegisterShaderNoMip( "menu/tab/ping.tga" );
+ cgs.media.scoreboardScore = trap_R_RegisterShaderNoMip( "menu/tab/score.tga" );
+ cgs.media.scoreboardTime = trap_R_RegisterShaderNoMip( "menu/tab/time.tga" );
+
+ cgs.media.smokePuffShader = trap_R_RegisterShader( "smokePuff" );
+ cgs.media.smokePuffRageProShader = trap_R_RegisterShader( "smokePuffRagePro" );
+ cgs.media.shotgunSmokePuffShader = trap_R_RegisterShader( "shotgunSmokePuff" );
+ cgs.media.nailPuffShader = trap_R_RegisterShader( "nailtrail" );
+ cgs.media.blueProxMine = trap_R_RegisterModel( "models/weaphits/proxmineb.md3" );
+ cgs.media.plasmaBallShader = trap_R_RegisterShader( "sprites/plasma1" );
+ cgs.media.bloodTrailShader = trap_R_RegisterShader( "bloodTrail" );
+ cgs.media.lagometerShader = trap_R_RegisterShader("lagometer" );
+ cgs.media.connectionShader = trap_R_RegisterShader( "disconnected" );
+
+ cgs.media.waterBubbleShader = trap_R_RegisterShader( "waterBubble" );
+
+ cgs.media.tracerShader = trap_R_RegisterShader( "gfx/misc/tracer" );
+ cgs.media.selectShader = trap_R_RegisterShader( "gfx/2d/select" );
+
+ for (i = 0; i < NUM_CROSSHAIRS; i++ ) {
+ if (i < 10)
+ cgs.media.crosshairShader[i] = trap_R_RegisterShader( va("gfx/2d/crosshair%c", 'a'+i) );
+ else
+ cgs.media.crosshairShader[i] = trap_R_RegisterShader( va("gfx/2d/crosshair%02d", i - 10) );
+ }
+
+ cgs.media.backTileShader = trap_R_RegisterShader( "gfx/2d/backtile" );
+ cgs.media.noammoShader = trap_R_RegisterShader( "icons/noammo" );
+
+ // powerup shaders
+ cgs.media.quadShader = trap_R_RegisterShader("powerups/quad" );
+ cgs.media.quadWeaponShader = trap_R_RegisterShader("powerups/quadWeapon" );
+ cgs.media.battleSuitShader = trap_R_RegisterShader("powerups/battleSuit" );
+ cgs.media.battleWeaponShader = trap_R_RegisterShader("powerups/battleWeapon" );
+ cgs.media.invisShader = trap_R_RegisterShader("powerups/invisibility" );
+ cgs.media.regenShader = trap_R_RegisterShader("powerups/regen" );
+ cgs.media.hastePuffShader = trap_R_RegisterShader("hasteSmokePuff" );
+
+ if ( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION|| cgs.gametype == GT_1FCTF || cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
+ cgs.media.redCubeModel = trap_R_RegisterModel( "models/powerups/orb/r_orb.md3" );
+ cgs.media.blueCubeModel = trap_R_RegisterModel( "models/powerups/orb/b_orb.md3" );
+ cgs.media.redCubeIcon = trap_R_RegisterShader( "icons/skull_red" );
+ cgs.media.blueCubeIcon = trap_R_RegisterShader( "icons/skull_blue" );
+ }
+
+ if( ( cgs.gametype >= GT_TEAM ) && ( cgs.ffa_gt != 1 ) ) {
+ cgs.media.redOverlay = trap_R_RegisterShader( "playeroverlays/playerSuit1_Red");
+ cgs.media.blueOverlay = trap_R_RegisterShader( "playeroverlays/playerSuit1_Blue");
+ } else {
+ cgs.media.neutralOverlay = trap_R_RegisterShader( "playeroverlays/playerSuit1_Neutral");
+ }
+
+//For Double Domination:
+ if ( cgs.gametype == GT_DOUBLE_D ) {
+ cgs.media.ddPointSkinA[TEAM_RED] = trap_R_RegisterShaderNoMip( "icons/icona_red" );
+ cgs.media.ddPointSkinA[TEAM_BLUE] = trap_R_RegisterShaderNoMip( "icons/icona_blue" );
+ cgs.media.ddPointSkinA[TEAM_FREE] = trap_R_RegisterShaderNoMip( "icons/icona_white" );
+ cgs.media.ddPointSkinA[TEAM_NONE] = trap_R_RegisterShaderNoMip( "icons/noammo" );
+
+ cgs.media.ddPointSkinB[TEAM_RED] = trap_R_RegisterShaderNoMip( "icons/iconb_red" );
+ cgs.media.ddPointSkinB[TEAM_BLUE] = trap_R_RegisterShaderNoMip( "icons/iconb_blue" );
+ cgs.media.ddPointSkinB[TEAM_FREE] = trap_R_RegisterShaderNoMip( "icons/iconb_white" );
+ cgs.media.ddPointSkinB[TEAM_NONE] = trap_R_RegisterShaderNoMip( "icons/noammo" );
+ }
+
+ if ( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION || cgs.gametype == GT_1FCTF || cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
+ cgs.media.redFlagModel = trap_R_RegisterModel( "models/flags/r_flag.md3" );
+ cgs.media.blueFlagModel = trap_R_RegisterModel( "models/flags/b_flag.md3" );
+ cgs.media.neutralFlagModel = trap_R_RegisterModel( "models/flags/n_flag.md3" );
+ cgs.media.redFlagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_red1" );
+ cgs.media.redFlagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_red2" );
+ cgs.media.redFlagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_red3" );
+ cgs.media.blueFlagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_blu1" );
+ cgs.media.blueFlagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_blu2" );
+ cgs.media.blueFlagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_blu3" );
+ cgs.media.flagPoleModel = trap_R_RegisterModel( "models/flag2/flagpole.md3" );
+ cgs.media.flagFlapModel = trap_R_RegisterModel( "models/flag2/flagflap3.md3" );
+
+ cgs.media.redFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/red.skin" );
+ cgs.media.blueFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/blue.skin" );
+ cgs.media.neutralFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/white.skin" );
+
+ cgs.media.redFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/red_base.md3" );
+ cgs.media.blueFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/blue_base.md3" );
+ cgs.media.neutralFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/ntrl_base.md3" );
+ }
+
+ if ( cgs.gametype == GT_1FCTF || cg_buildScript.integer ) {
+ cgs.media.neutralFlagModel = trap_R_RegisterModel( "models/flags/n_flag.md3" );
+ cgs.media.flagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_neutral1" );
+ cgs.media.flagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_red2" );
+ cgs.media.flagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_blu2" );
+ cgs.media.flagShader[3] = trap_R_RegisterShaderNoMip( "icons/iconf_neutral3" );
+ }
+
+ if ( cgs.gametype == GT_OBELISK || cg_buildScript.integer ) {
+ cgs.media.rocketExplosionShader = trap_R_RegisterShader("rocketExplosion");
+ cgs.media.overloadBaseModel = trap_R_RegisterModel( "models/powerups/overload_base.md3" );
+ cgs.media.overloadTargetModel = trap_R_RegisterModel( "models/powerups/overload_target.md3" );
+ cgs.media.overloadLightsModel = trap_R_RegisterModel( "models/powerups/overload_lights.md3" );
+ cgs.media.overloadEnergyModel = trap_R_RegisterModel( "models/powerups/overload_energy.md3" );
+ }
+
+ if ( cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
+ cgs.media.harvesterModel = trap_R_RegisterModel( "models/powerups/harvester/harvester.md3" );
+ cgs.media.harvesterRedSkin = trap_R_RegisterSkin( "models/powerups/harvester/red.skin" );
+ cgs.media.harvesterBlueSkin = trap_R_RegisterSkin( "models/powerups/harvester/blue.skin" );
+ cgs.media.harvesterNeutralModel = trap_R_RegisterModel( "models/powerups/obelisk/obelisk.md3" );
+ }
+
+ cgs.media.redKamikazeShader = trap_R_RegisterShader( "models/weaphits/kamikred" );
+ cgs.media.dustPuffShader = trap_R_RegisterShader("hasteSmokePuff" );
+
+ if ( ( ( cgs.gametype >= GT_TEAM ) && ( cgs.ffa_gt != 1 ) ) ||
+ cg_buildScript.integer ) {
+
+ cgs.media.friendShader = trap_R_RegisterShader( "sprites/foe" );
+ cgs.media.redQuadShader = trap_R_RegisterShader("powerups/blueflag" );
+ //cgs.media.teamStatusBar = trap_R_RegisterShader( "gfx/2d/colorbar.tga" ); - moved outside, used by accuracy
+ cgs.media.blueKamikazeShader = trap_R_RegisterShader( "models/weaphits/kamikblu" );
+ }
+ cgs.media.teamStatusBar = trap_R_RegisterShader( "gfx/2d/colorbar.tga" );
+
+ cgs.media.armorModel = trap_R_RegisterModel( "models/powerups/armor/armor_yel.md3" );
+ cgs.media.armorIcon = trap_R_RegisterShaderNoMip( "icons/iconr_yellow" );
+
+ cgs.media.machinegunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/m_shell.md3" );
+ cgs.media.shotgunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/s_shell.md3" );
+
+ cgs.media.gibAbdomen = trap_R_RegisterModel( "models/gibs/abdomen.md3" );
+ cgs.media.gibArm = trap_R_RegisterModel( "models/gibs/arm.md3" );
+ cgs.media.gibChest = trap_R_RegisterModel( "models/gibs/chest.md3" );
+ cgs.media.gibFist = trap_R_RegisterModel( "models/gibs/fist.md3" );
+ cgs.media.gibFoot = trap_R_RegisterModel( "models/gibs/foot.md3" );
+ cgs.media.gibForearm = trap_R_RegisterModel( "models/gibs/forearm.md3" );
+ cgs.media.gibIntestine = trap_R_RegisterModel( "models/gibs/intestine.md3" );
+ cgs.media.gibLeg = trap_R_RegisterModel( "models/gibs/leg.md3" );
+ cgs.media.gibSkull = trap_R_RegisterModel( "models/gibs/skull.md3" );
+ cgs.media.gibBrain = trap_R_RegisterModel( "models/gibs/brain.md3" );
+
+ cgs.media.smoke2 = trap_R_RegisterModel( "models/weapons2/shells/s_shell.md3" );
+
+ cgs.media.balloonShader = trap_R_RegisterShader( "sprites/balloon3" );
+
+ cgs.media.bloodExplosionShader = trap_R_RegisterShader( "bloodExplosion" );
+
+ cgs.media.bulletFlashModel = trap_R_RegisterModel("models/weaphits/bullet.md3");
+ cgs.media.ringFlashModel = trap_R_RegisterModel("models/weaphits/ring02.md3");
+ cgs.media.dishFlashModel = trap_R_RegisterModel("models/weaphits/boom01.md3");
+#ifdef MISSIONPACK
+ cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/powerups/pop.md3" );
+#else
+ cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/misc/telep.md3" );
+ cgs.media.teleportEffectShader = trap_R_RegisterShader( "teleportEffect" );
+#endif
+ cgs.media.kamikazeEffectModel = trap_R_RegisterModel( "models/weaphits/kamboom2.md3" );
+ cgs.media.kamikazeShockWave = trap_R_RegisterModel( "models/weaphits/kamwave.md3" );
+ cgs.media.kamikazeHeadModel = trap_R_RegisterModel( "models/powerups/kamikazi.md3" );
+ cgs.media.kamikazeHeadTrail = trap_R_RegisterModel( "models/powerups/trailtest.md3" );
+ cgs.media.guardPowerupModel = trap_R_RegisterModel( "models/powerups/guard_player.md3" );
+ cgs.media.scoutPowerupModel = trap_R_RegisterModel( "models/powerups/scout_player.md3" );
+ cgs.media.doublerPowerupModel = trap_R_RegisterModel( "models/powerups/doubler_player.md3" );
+ cgs.media.ammoRegenPowerupModel = trap_R_RegisterModel( "models/powerups/ammo_player.md3" );
+ cgs.media.invulnerabilityImpactModel = trap_R_RegisterModel( "models/powerups/shield/impact.md3" );
+ cgs.media.invulnerabilityJuicedModel = trap_R_RegisterModel( "models/powerups/shield/juicer.md3" );
+ cgs.media.medkitUsageModel = trap_R_RegisterModel( "models/powerups/regen.md3" );
+ cgs.media.heartShader = trap_R_RegisterShaderNoMip( "ui/assets/statusbar/selectedhealth.tga" );
+
+
+ cgs.media.invulnerabilityPowerupModel = trap_R_RegisterModel( "models/powerups/shield/shield.md3" );
+ cgs.media.medalImpressive = trap_R_RegisterShaderNoMip( "medal_impressive" );
+ cgs.media.medalExcellent = trap_R_RegisterShaderNoMip( "medal_excellent" );
+ cgs.media.medalGauntlet = trap_R_RegisterShaderNoMip( "medal_gauntlet" );
+ cgs.media.medalDefend = trap_R_RegisterShaderNoMip( "medal_defend" );
+ cgs.media.medalAssist = trap_R_RegisterShaderNoMip( "medal_assist" );
+ cgs.media.medalCapture = trap_R_RegisterShaderNoMip( "medal_capture" );
+
+ // LEILEI SHADERS
+ cgs.media.lsmkShader1 = trap_R_RegisterShader("leismoke1" );
+ cgs.media.lsmkShader2 = trap_R_RegisterShader("leismoke2" );
+ cgs.media.lsmkShader3 = trap_R_RegisterShader("leismoke3" );
+ cgs.media.lsmkShader4 = trap_R_RegisterShader("leismoke4" );
+
+ cgs.media.lsplShader = trap_R_RegisterShader("leisplash" );
+ cgs.media.lspkShader1 = trap_R_RegisterShader("leispark" );
+ cgs.media.lspkShader2 = trap_R_RegisterShader("leispark2" );
+ cgs.media.lbumShader1 = trap_R_RegisterShader("leiboom1" );
+ cgs.media.lfblShader1 = trap_R_RegisterShader("leifball" );
+
+ cgs.media.lbldShader1 = trap_R_RegisterShader("leiblood1" );
+ cgs.media.lbldShader2 = trap_R_RegisterShader("leiblood2" ); // this is a mark, by the way
+
+ // New Bullet Marks
+ cgs.media.lmarkmetal1 = trap_R_RegisterShader("leimetalmark1" );
+ cgs.media.lmarkmetal2 = trap_R_RegisterShader("leimetalmark2" );
+ cgs.media.lmarkmetal3 = trap_R_RegisterShader("leimetalmark3" );
+ cgs.media.lmarkmetal4 = trap_R_RegisterShader("leimetalmark4" );
+ cgs.media.lmarkbullet1 = trap_R_RegisterShader("leibulletmark1" );
+ cgs.media.lmarkbullet2 = trap_R_RegisterShader("leibulletmark2" );
+ cgs.media.lmarkbullet3 = trap_R_RegisterShader("leibulletmark3" );
+ cgs.media.lmarkbullet4 = trap_R_RegisterShader("leibulletmark4" );
+
+
+ memset( cg_items, 0, sizeof( cg_items ) );
+ memset( cg_weapons, 0, sizeof( cg_weapons ) );
+
+ // only register the items that the server says we need
+ Q_strncpyz(items, CG_ConfigString(CS_ITEMS), sizeof(items));
+
+ for ( i = 1 ; i < bg_numItems ; i++ ) {
+ if ( items[ i ] == '1' || cg_buildScript.integer ) {
+ CG_LoadingItem( i );
+ CG_RegisterItemVisuals( i );
+ }
+ }
+
+ // wall marks
+ cgs.media.bulletMarkShader = trap_R_RegisterShader( "gfx/damage/bullet_mrk" );
+ cgs.media.burnMarkShader = trap_R_RegisterShader( "gfx/damage/burn_med_mrk" );
+ cgs.media.holeMarkShader = trap_R_RegisterShader( "gfx/damage/hole_lg_mrk" );
+ cgs.media.energyMarkShader = trap_R_RegisterShader( "gfx/damage/plasma_mrk" );
+ cgs.media.shadowMarkShader = trap_R_RegisterShader( "markShadow" );
+ cgs.media.wakeMarkShader = trap_R_RegisterShader( "wake" );
+ cgs.media.bloodMarkShader = trap_R_RegisterShader( "bloodMark" );
+
+ // register the inline models
+ cgs.numInlineModels = trap_CM_NumInlineModels();
+ for ( i = 1 ; i < cgs.numInlineModels ; i++ ) {
+ char name[10];
+ vec3_t mins, maxs;
+ int j;
+
+ Com_sprintf( name, sizeof(name), "*%i", i );
+ cgs.inlineDrawModel[i] = trap_R_RegisterModel( name );
+ trap_R_ModelBounds( cgs.inlineDrawModel[i], mins, maxs );
+ for ( j = 0 ; j < 3 ; j++ ) {
+ cgs.inlineModelMidpoints[i][j] = mins[j] + 0.5 * ( maxs[j] - mins[j] );
+ }
+ }
+
+ // register all the server specified models
+ for (i=1 ; i<MAX_MODELS ; i++) {
+ const char *modelName;
+
+ modelName = CG_ConfigString( CS_MODELS+i );
+ if ( !modelName[0] ) {
+ break;
+ }
+ cgs.gameModels[i] = trap_R_RegisterModel( modelName );
+ }
+
+#ifdef MISSIONPACK
+ // new stuff
+ cgs.media.patrolShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/patrol.tga");
+ cgs.media.assaultShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/assault.tga");
+ cgs.media.campShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/camp.tga");
+ cgs.media.followShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/follow.tga");
+ cgs.media.defendShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/defend.tga");
+ cgs.media.teamLeaderShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/team_leader.tga");
+ cgs.media.retrieveShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/retrieve.tga");
+ cgs.media.escortShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/escort.tga");
+ cgs.media.deathShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/death.tga");
+
+ cgs.media.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
+ cgs.media.sizeCursor = trap_R_RegisterShaderNoMip( "ui/assets/sizecursor.tga" );
+ cgs.media.selectCursor = trap_R_RegisterShaderNoMip( "ui/assets/selectcursor.tga" );
+ cgs.media.flagShaders[0] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_in_base.tga");
+ cgs.media.flagShaders[1] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_capture.tga");
+ cgs.media.flagShaders[2] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_missing.tga");
+
+ trap_R_RegisterModel( "models/players/sergei/lower.md3" );
+ trap_R_RegisterModel( "models/players/sergei/upper.md3" );
+ trap_R_RegisterModel( "models/players/sergei/head.md3" );
+
+ trap_R_RegisterModel( "models/players/kyonshi/lower.md3" );
+ trap_R_RegisterModel( "models/players/kyonshi/upper.md3" );
+ trap_R_RegisterModel( "models/players/kyonshi/head.md3" );
+
+#endif
+ CG_ClearParticles ();
+/*
+ for (i=1; i<MAX_PARTICLES_AREAS; i++)
+ {
+ {
+ int rval;
+
+ rval = CG_NewParticleArea ( CS_PARTICLES + i);
+ if (!rval)
+ break;
+ }
+ }
+*/
+}
+
+
+
+/*
+=======================
+CG_BuildSpectatorString
+
+=======================
+*/
+void CG_BuildSpectatorString(void) {
+ int i;
+ cg.spectatorList[0] = 0;
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ if (cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_SPECTATOR ) {
+ Q_strcat(cg.spectatorList, sizeof(cg.spectatorList), va("%s ", cgs.clientinfo[i].name));
+ }
+ }
+ i = strlen(cg.spectatorList);
+ if (i != cg.spectatorLen) {
+ cg.spectatorLen = i;
+ cg.spectatorWidth = -1;
+ }
+}
+
+
+/*
+===================
+CG_RegisterClients
+===================
+*/
+static void CG_RegisterClients( void ) {
+ int i;
+
+ CG_LoadingClient(cg.clientNum);
+ CG_NewClientInfo(cg.clientNum);
+
+ for (i=0 ; i<MAX_CLIENTS ; i++) {
+ const char *clientInfo;
+
+ if (cg.clientNum == i) {
+ continue;
+ }
+
+ clientInfo = CG_ConfigString( CS_PLAYERS+i );
+ if ( !clientInfo[0]) {
+ continue;
+ }
+ CG_LoadingClient( i );
+ CG_NewClientInfo( i );
+ }
+ CG_BuildSpectatorString();
+}
+
+//===========================================================================
+
+/*
+=================
+CG_ConfigString
+=================
+*/
+const char *CG_ConfigString( int index ) {
+ if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
+ CG_Error( "CG_ConfigString: bad index: %i", index );
+ }
+ return cgs.gameState.stringData + cgs.gameState.stringOffsets[ index ];
+}
+
+//==================================================================
+
+/*
+======================
+CG_StartMusic
+
+======================
+*/
+void CG_StartMusic( void ) {
+ char *s;
+ char parm1[MAX_QPATH], parm2[MAX_QPATH];
+
+ // start the background music
+ if ( *cg_music.string && Q_stricmp( cg_music.string, "none" ) ) {
+ s = (char *)cg_music.string;
+ } else {
+ s = (char *)CG_ConfigString( CS_MUSIC );
+ Q_strncpyz( parm1, COM_Parse( &s ), sizeof( parm1 ) );
+ Q_strncpyz( parm2, COM_Parse( &s ), sizeof( parm2 ) );
+
+ trap_S_StartBackgroundTrack( parm1, parm2 );
+ }
+}
+#ifdef MISSIONPACK
+char *CG_GetMenuBuffer(const char *filename) {
+ int len;
+ fileHandle_t f;
+ static char buf[MAX_MENUFILE];
+
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( !f ) {
+ trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
+ return NULL;
+ }
+ if ( len >= MAX_MENUFILE ) {
+ trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i\n", filename, len, MAX_MENUFILE ) );
+ trap_FS_FCloseFile( f );
+ return NULL;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ return buf;
+}
+
+//
+// ==============================
+// new hud stuff ( mission pack )
+// ==============================
+//
+qboolean CG_Asset_Parse(int handle) {
+ pc_token_t token;
+ const char *tempStr;
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+ if (Q_stricmp(token.string, "{") != 0) {
+ return qfalse;
+ }
+
+ while ( 1 ) {
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+
+ if (Q_stricmp(token.string, "}") == 0) {
+ return qtrue;
+ }
+
+ // font
+ if (Q_stricmp(token.string, "font") == 0) {
+ int pointSize;
+ if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
+ return qfalse;
+ }
+ cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.textFont);
+ continue;
+ }
+
+ // smallFont
+ if (Q_stricmp(token.string, "smallFont") == 0) {
+ int pointSize;
+ if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
+ return qfalse;
+ }
+ cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.smallFont);
+ continue;
+ }
+
+ // font
+ if (Q_stricmp(token.string, "bigfont") == 0) {
+ int pointSize;
+ if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
+ return qfalse;
+ }
+ cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.bigFont);
+ continue;
+ }
+
+ // gradientbar
+ if (Q_stricmp(token.string, "gradientbar") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
+ continue;
+ }
+
+ // enterMenuSound
+ if (Q_stricmp(token.string, "menuEnterSound") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ cgDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse );
+ continue;
+ }
+
+ // exitMenuSound
+ if (Q_stricmp(token.string, "menuExitSound") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ cgDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse );
+ continue;
+ }
+
+ // itemFocusSound
+ if (Q_stricmp(token.string, "itemFocusSound") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ cgDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse );
+ continue;
+ }
+
+ // menuBuzzSound
+ if (Q_stricmp(token.string, "menuBuzzSound") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ cgDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse );
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "cursor") == 0) {
+ if (!PC_String_Parse(handle, &cgDC.Assets.cursorStr)) {
+ return qfalse;
+ }
+ cgDC.Assets.cursor = trap_R_RegisterShaderNoMip( cgDC.Assets.cursorStr);
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "fadeClamp") == 0) {
+ if (!PC_Float_Parse(handle, &cgDC.Assets.fadeClamp)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "fadeCycle") == 0) {
+ if (!PC_Int_Parse(handle, &cgDC.Assets.fadeCycle)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "fadeAmount") == 0) {
+ if (!PC_Float_Parse(handle, &cgDC.Assets.fadeAmount)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "shadowX") == 0) {
+ if (!PC_Float_Parse(handle, &cgDC.Assets.shadowX)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "shadowY") == 0) {
+ if (!PC_Float_Parse(handle, &cgDC.Assets.shadowY)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "shadowColor") == 0) {
+ if (!PC_Color_Parse(handle, &cgDC.Assets.shadowColor)) {
+ return qfalse;
+ }
+ cgDC.Assets.shadowFadeClamp = cgDC.Assets.shadowColor[3];
+ continue;
+ }
+ }
+ return qfalse; // bk001204 - why not?
+}
+
+void CG_ParseMenu(const char *menuFile) {
+ pc_token_t token;
+ int handle;
+
+ handle = trap_PC_LoadSource(menuFile);
+ if (!handle)
+ handle = trap_PC_LoadSource("ui/testhud.menu");
+ if (!handle)
+ return;
+
+ while ( 1 ) {
+ if (!trap_PC_ReadToken( handle, &token )) {
+ break;
+ }
+
+ //if ( Q_stricmp( token, "{" ) ) {
+ // Com_Printf( "Missing { in menu file\n" );
+ // break;
+ //}
+
+ //if ( menuCount == MAX_MENUS ) {
+ // Com_Printf( "Too many menus!\n" );
+ // break;
+ //}
+
+ if ( token.string[0] == '}' ) {
+ break;
+ }
+
+ if (Q_stricmp(token.string, "assetGlobalDef") == 0) {
+ if (CG_Asset_Parse(handle)) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+
+ if (Q_stricmp(token.string, "menudef") == 0) {
+ // start a new menu
+ Menu_New(handle);
+ }
+ }
+ trap_PC_FreeSource(handle);
+}
+
+qboolean CG_Load_Menu(char **p) {
+ char *token;
+
+ token = COM_ParseExt(p, qtrue);
+
+ if (token[0] != '{') {
+ return qfalse;
+ }
+
+ while ( 1 ) {
+
+ token = COM_ParseExt(p, qtrue);
+
+ if (Q_stricmp(token, "}") == 0) {
+ return qtrue;
+ }
+
+ if ( !token || token[0] == 0 ) {
+ return qfalse;
+ }
+
+ CG_ParseMenu(token);
+ }
+ return qfalse;
+}
+
+
+
+void CG_LoadMenus(const char *menuFile) {
+ char *token;
+ char *p;
+ int len, start;
+ fileHandle_t f;
+ static char buf[MAX_MENUDEFFILE];
+
+ start = trap_Milliseconds();
+
+ len = trap_FS_FOpenFile( menuFile, &f, FS_READ );
+ if ( !f ) {
+ trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );
+ len = trap_FS_FOpenFile( "ui/hud.txt", &f, FS_READ );
+ if (!f) {
+ trap_Error( va( S_COLOR_RED "default menu file not found: ui/hud.txt, unable to continue!\n") );
+ }
+ }
+
+ if ( len >= MAX_MENUDEFFILE ) {
+ trap_Error( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i\n", menuFile, len, MAX_MENUDEFFILE ) );
+ trap_FS_FCloseFile( f );
+ return;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ COM_Compress(buf);
+
+ Menu_Reset();
+
+ p = buf;
+
+ while ( 1 ) {
+ token = COM_ParseExt( &p, qtrue );
+ if( !token || token[0] == 0 || token[0] == '}') {
+ break;
+ }
+
+ //if ( Q_stricmp( token, "{" ) ) {
+ // Com_Printf( "Missing { in menu file\n" );
+ // break;
+ //}
+
+ //if ( menuCount == MAX_MENUS ) {
+ // Com_Printf( "Too many menus!\n" );
+ // break;
+ //}
+
+ if ( Q_stricmp( token, "}" ) == 0 ) {
+ break;
+ }
+
+ if (Q_stricmp(token, "loadmenu") == 0) {
+ if (CG_Load_Menu(&p)) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ }
+
+ Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start);
+
+}
+
+
+
+static qboolean CG_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) {
+ return qfalse;
+}
+
+
+static int CG_FeederCount(float feederID) {
+ int i, count;
+ count = 0;
+ if (feederID == FEEDER_REDTEAM_LIST) {
+ for (i = 0; i < cg.numScores; i++) {
+ if (cg.scores[i].team == TEAM_RED) {
+ count++;
+ }
+ }
+ } else if (feederID == FEEDER_BLUETEAM_LIST) {
+ for (i = 0; i < cg.numScores; i++) {
+ if (cg.scores[i].team == TEAM_BLUE) {
+ count++;
+ }
+ }
+ } else if (feederID == FEEDER_SCOREBOARD) {
+ return cg.numScores;
+ }
+ return count;
+}
+
+
+void CG_SetScoreSelection(void *p) {
+ menuDef_t *menu = (menuDef_t*)p;
+ playerState_t *ps = &cg.snap->ps;
+ int i, red, blue;
+ red = blue = 0;
+ for (i = 0; i < cg.numScores; i++) {
+ if (cg.scores[i].team == TEAM_RED) {
+ red++;
+ } else if (cg.scores[i].team == TEAM_BLUE) {
+ blue++;
+ }
+ if (ps->clientNum == cg.scores[i].client) {
+ cg.selectedScore = i;
+ }
+ }
+
+ if (menu == NULL) {
+ // just interested in setting the selected score
+ return;
+ }
+
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ int feeder = FEEDER_REDTEAM_LIST;
+ i = red;
+ if (cg.scores[cg.selectedScore].team == TEAM_BLUE) {
+ feeder = FEEDER_BLUETEAM_LIST;
+ i = blue;
+ }
+ Menu_SetFeederSelection(menu, feeder, i, NULL);
+ } else {
+ Menu_SetFeederSelection(menu, FEEDER_SCOREBOARD, cg.selectedScore, NULL);
+ }
+}
+
+// FIXME: might need to cache this info
+static clientInfo_t * CG_InfoFromScoreIndex(int index, int team, int *scoreIndex) {
+ int i, count;
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ count = 0;
+ for (i = 0; i < cg.numScores; i++) {
+ if (cg.scores[i].team == team) {
+ if (count == index) {
+ *scoreIndex = i;
+ return &cgs.clientinfo[cg.scores[i].client];
+ }
+ count++;
+ }
+ }
+ }
+ *scoreIndex = index;
+ return &cgs.clientinfo[ cg.scores[index].client ];
+}
+
+static const char *CG_FeederItemText(float feederID, int index, int column, qhandle_t *handle) {
+ gitem_t *item;
+ int scoreIndex = 0;
+ clientInfo_t *info = NULL;
+ int team = -1;
+ score_t *sp = NULL;
+
+ *handle = -1;
+
+ if (feederID == FEEDER_REDTEAM_LIST) {
+ team = TEAM_RED;
+ } else if (feederID == FEEDER_BLUETEAM_LIST) {
+ team = TEAM_BLUE;
+ }
+
+ info = CG_InfoFromScoreIndex(index, team, &scoreIndex);
+ sp = &cg.scores[scoreIndex];
+
+ if (info && info->infoValid) {
+ switch (column) {
+ case 0:
+ if ( info->powerups & ( 1 << PW_NEUTRALFLAG ) ) {
+ item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
+ *handle = cg_items[ ITEM_INDEX(item) ].icon;
+ } else if ( info->powerups & ( 1 << PW_REDFLAG ) ) {
+ item = BG_FindItemForPowerup( PW_REDFLAG );
+ *handle = cg_items[ ITEM_INDEX(item) ].icon;
+ } else if ( info->powerups & ( 1 << PW_BLUEFLAG ) ) {
+ item = BG_FindItemForPowerup( PW_BLUEFLAG );
+ *handle = cg_items[ ITEM_INDEX(item) ].icon;
+ } else {
+ if ( info->botSkill > 0 && info->botSkill <= 5 ) {
+ *handle = cgs.media.botSkillShaders[ info->botSkill - 1 ];
+ } else if ( info->handicap < 100 ) {
+ return va("%i", info->handicap );
+ }
+ }
+ break;
+ case 1:
+ if (team == -1) {
+ return "";
+ } else if (info->isDead) {
+ *handle = cgs.media.deathShader;
+ } else {
+ *handle = CG_StatusHandle(info->teamTask);
+ }
+ break;
+ case 2:
+ if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << sp->client ) ) {
+ return "Ready";
+ }
+ if (team == -1) {
+ if (cgs.gametype == GT_TOURNAMENT) {
+ return va("%i/%i", info->wins, info->losses);
+ } else if (info->infoValid && info->team == TEAM_SPECTATOR ) {
+ return "Spectator";
+ } else {
+ return "";
+ }
+ } else {
+ if (info->teamLeader) {
+ return "Leader";
+ }
+ }
+ break;
+ case 3:
+ return info->name;
+ break;
+ case 4:
+ return va("%i", info->score);
+ break;
+ case 5:
+ return va("%4i", sp->time);
+ break;
+ case 6:
+ if ( sp->ping == -1 ) {
+ return "connecting";
+ }
+ return va("%4i", sp->ping);
+ break;
+ }
+ }
+
+ return "";
+}
+
+static qhandle_t CG_FeederItemImage(float feederID, int index) {
+ return 0;
+}
+
+static void CG_FeederSelection(float feederID, int index) {
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ int i, count;
+ int team = (feederID == FEEDER_REDTEAM_LIST) ? TEAM_RED : TEAM_BLUE;
+ count = 0;
+ for (i = 0; i < cg.numScores; i++) {
+ if (cg.scores[i].team == team) {
+ if (index == count) {
+ cg.selectedScore = i;
+ }
+ count++;
+ }
+ }
+ } else {
+ cg.selectedScore = index;
+ }
+}
+#endif
+
+#ifdef MISSIONPACK // bk001204 - only needed there
+static float CG_Cvar_Get(const char *cvar) {
+ char buff[128];
+ memset(buff, 0, sizeof(buff));
+ trap_Cvar_VariableStringBuffer(cvar, buff, sizeof(buff));
+ return atof(buff);
+}
+#endif
+
+#ifdef MISSIONPACK
+void CG_Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) {
+ CG_Text_Paint(x, y, scale, color, text, 0, limit, style);
+}
+
+static int CG_OwnerDrawWidth(int ownerDraw, float scale) {
+ switch (ownerDraw) {
+ case CG_GAME_TYPE:
+ return CG_Text_Width(CG_GameTypeString(), scale, 0);
+ case CG_GAME_STATUS:
+ return CG_Text_Width(CG_GetGameStatusText(), scale, 0);
+ break;
+ case CG_KILLER:
+ return CG_Text_Width(CG_GetKillerText(), scale, 0);
+ break;
+ case CG_RED_NAME:
+ return CG_Text_Width(cg_redTeamName.string, scale, 0);
+ break;
+ case CG_BLUE_NAME:
+ return CG_Text_Width(cg_blueTeamName.string, scale, 0);
+ break;
+
+
+ }
+ return 0;
+}
+
+static int CG_PlayCinematic(const char *name, float x, float y, float w, float h) {
+ return trap_CIN_PlayCinematic(name, x, y, w, h, CIN_loop);
+}
+
+static void CG_StopCinematic(int handle) {
+ trap_CIN_StopCinematic(handle);
+}
+
+static void CG_DrawCinematic(int handle, float x, float y, float w, float h) {
+ trap_CIN_SetExtents(handle, x, y, w, h);
+ trap_CIN_DrawCinematic(handle);
+}
+
+static void CG_RunCinematicFrame(int handle) {
+ trap_CIN_RunCinematic(handle);
+}
+
+/*
+=================
+CG_LoadHudMenu();
+
+=================
+*/
+void CG_LoadHudMenu( void ) {
+ char buff[1024];
+ const char *hudSet;
+
+ cgDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
+ cgDC.setColor = &trap_R_SetColor;
+ cgDC.drawHandlePic = &CG_DrawPic;
+ cgDC.drawStretchPic = &trap_R_DrawStretchPic;
+ cgDC.drawText = &CG_Text_Paint;
+ cgDC.textWidth = &CG_Text_Width;
+ cgDC.textHeight = &CG_Text_Height;
+ cgDC.registerModel = &trap_R_RegisterModel;
+ cgDC.modelBounds = &trap_R_ModelBounds;
+ cgDC.fillRect = &CG_FillRect;
+ cgDC.drawRect = &CG_DrawRect;
+ cgDC.drawSides = &CG_DrawSides;
+ cgDC.drawTopBottom = &CG_DrawTopBottom;
+ cgDC.clearScene = &trap_R_ClearScene;
+ cgDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
+ cgDC.renderScene = &trap_R_RenderScene;
+ cgDC.registerFont = &trap_R_RegisterFont;
+ cgDC.ownerDrawItem = &CG_OwnerDraw;
+ cgDC.getValue = &CG_GetValue;
+ cgDC.ownerDrawVisible = &CG_OwnerDrawVisible;
+ cgDC.runScript = &CG_RunMenuScript;
+ cgDC.getTeamColor = &CG_GetTeamColor;
+ cgDC.setCVar = trap_Cvar_Set;
+ cgDC.getCVarString = trap_Cvar_VariableStringBuffer;
+ cgDC.getCVarValue = CG_Cvar_Get;
+ cgDC.drawTextWithCursor = &CG_Text_PaintWithCursor;
+ //cgDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
+ //cgDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
+ cgDC.startLocalSound = &trap_S_StartLocalSound;
+ cgDC.ownerDrawHandleKey = &CG_OwnerDrawHandleKey;
+ cgDC.feederCount = &CG_FeederCount;
+ cgDC.feederItemImage = &CG_FeederItemImage;
+ cgDC.feederItemText = &CG_FeederItemText;
+ cgDC.feederSelection = &CG_FeederSelection;
+ //cgDC.setBinding = &trap_Key_SetBinding;
+ //cgDC.getBindingBuf = &trap_Key_GetBindingBuf;
+ //cgDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
+ //cgDC.executeText = &trap_Cmd_ExecuteText;
+ cgDC.Error = &Com_Error;
+ cgDC.Print = &Com_Printf;
+ cgDC.ownerDrawWidth = &CG_OwnerDrawWidth;
+ //cgDC.Pause = &CG_Pause;
+ cgDC.registerSound = &trap_S_RegisterSound;
+ cgDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
+ cgDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
+ cgDC.playCinematic = &CG_PlayCinematic;
+ cgDC.stopCinematic = &CG_StopCinematic;
+ cgDC.drawCinematic = &CG_DrawCinematic;
+ cgDC.runCinematicFrame = &CG_RunCinematicFrame;
+
+ Init_Display(&cgDC);
+
+ Menu_Reset();
+
+ trap_Cvar_VariableStringBuffer("cg_hudFiles", buff, sizeof(buff));
+ hudSet = buff;
+ if (hudSet[0] == '\0') {
+ hudSet = "ui/hud.txt";
+ }
+
+ CG_LoadMenus(hudSet);
+}
+
+void CG_AssetCache( void ) {
+ //if (Assets.textFont == NULL) {
+ // trap_R_RegisterFont("fonts/arial.ttf", 72, &Assets.textFont);
+ //}
+ //Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND );
+ //Com_Printf("Menu Size: %i bytes\n", sizeof(Menus));
+ cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
+ cgDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
+ cgDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
+ cgDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
+ cgDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
+ cgDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
+ cgDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
+ cgDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
+ cgDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
+ cgDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
+ cgDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
+ cgDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
+ cgDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
+ cgDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
+ cgDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
+ cgDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
+ cgDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
+}
+#endif
+/*
+=================
+CG_Init
+
+Called after every level change or subsystem restart
+Will perform callbacks to make the loading info screen update.
+=================
+*/
+void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) {
+ const char *s;
+
+ // clear everything
+ memset( &cgs, 0, sizeof( cgs ) );
+ memset( &cg, 0, sizeof( cg ) );
+ memset( cg_entities, 0, sizeof(cg_entities) );
+ memset( cg_weapons, 0, sizeof(cg_weapons) );
+ memset( cg_items, 0, sizeof(cg_items) );
+
+ cg.clientNum = clientNum;
+
+ cgs.processedSnapshotNum = serverMessageNum;
+ cgs.serverCommandSequence = serverCommandSequence;
+
+ // load a few needed things before we do any screen updates
+ cgs.media.charsetShader = trap_R_RegisterShader( "gfx/2d/bigchars" );
+ cgs.media.whiteShader = trap_R_RegisterShader( "white" );
+ cgs.media.charsetProp = trap_R_RegisterShaderNoMip( "menu/art/font1_prop.tga" );
+ cgs.media.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" );
+ cgs.media.charsetPropB = trap_R_RegisterShaderNoMip( "menu/art/font2_prop.tga" );
+
+ CG_RegisterCvars();
+
+ CG_InitConsoleCommands();
+
+ cg.weaponSelect = WP_MACHINEGUN;
+
+ cgs.redflag = cgs.blueflag = -1; // For compatibily, default to unset for
+ cgs.flagStatus = -1;
+ // old servers
+
+ // get the rendering configuration from the client system
+ trap_GetGlconfig( &cgs.glconfig );
+ cgs.screenXScale = cgs.glconfig.vidWidth / 640.0;
+ cgs.screenYScale = cgs.glconfig.vidHeight / 480.0;
+
+ // get the gamestate from the client system
+ trap_GetGameState( &cgs.gameState );
+
+ // check version
+ s = CG_ConfigString( CS_GAME_VERSION );
+ if ( strcmp( s, GAME_VERSION ) ) {
+ CG_Error( "Client/Server game mismatch: %s/%s", GAME_VERSION, s );
+ }
+
+ s = CG_ConfigString( CS_LEVEL_START_TIME );
+ cgs.levelStartTime = atoi( s );
+
+ CG_ParseServerinfo();
+
+ // load the new map
+ CG_LoadingString( "collision map" );
+
+ trap_CM_LoadMap( cgs.mapname );
+
+#ifdef MISSIONPACK
+ String_Init();
+#endif
+
+ cg.loading = qtrue; // force players to load instead of defer
+
+ CG_LoadingString( "sounds" );
+
+ CG_RegisterSounds();
+
+ CG_LoadingString( "graphics" );
+
+ CG_RegisterGraphics();
+
+ CG_LoadingString( "clients" );
+
+ CG_RegisterClients(); // if low on memory, some clients will be deferred
+
+#ifdef MISSIONPACK
+ CG_AssetCache();
+ CG_LoadHudMenu(); // load new hud stuff
+#endif
+
+ cg.loading = qfalse; // future players will be deferred
+
+ CG_InitLocalEntities();
+
+ CG_InitMarkPolys();
+
+ // remove the last loading update
+ cg.infoScreenText[0] = 0;
+
+ // Make sure we have update values (scores)
+ CG_SetConfigValues();
+
+ CG_StartMusic();
+
+ CG_LoadingString( "" );
+
+#ifdef MISSIONPACK
+ CG_InitTeamChat();
+#endif
+
+ CG_ShaderStateChanged();
+
+ //Init challenge system
+ challenges_init();
+
+ addChallenge(GENERAL_TEST);
+
+ trap_S_ClearLoopingSounds( qtrue );
+}
+
+/*
+=================
+CG_Shutdown
+
+Called before every level change or subsystem restart
+=================
+*/
+void CG_Shutdown( void ) {
+ // some mods may need to do cleanup work here,
+ // like closing files or archiving session data
+ challenges_save();
+}
+
+
+/*
+==================
+CG_EventHandling
+==================
+ type 0 - no event handling
+ 1 - team menu
+ 2 - hud editor
+
+*/
+#ifndef MISSIONPACK
+void CG_EventHandling(int type) {
+}
+
+
+
+void CG_KeyEvent(int key, qboolean down) {
+}
+
+void CG_MouseEvent(int x, int y) {
+}
+#endif
+
+//unlagged - attack prediction #3
+// moved from g_weapon.c
+/*
+======================
+SnapVectorTowards
+
+Round a vector to integers for more efficient network
+transmission, but make sure that it rounds towards a given point
+rather than blindly truncating. This prevents it from truncating
+into a wall.
+======================
+*/
+void SnapVectorTowards( vec3_t v, vec3_t to ) {
+ int i;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ if ( to[i] <= v[i] ) {
+ v[i] = (int)v[i];
+ } else {
+ v[i] = (int)v[i] + 1;
+ }
+ }
+}
+//unlagged - attack prediction #3
+
+static qboolean do_vid_restart = qfalse;
+
+void CG_FairCvars() {
+ qboolean vid_restart_required = qfalse;
+ char rendererinfos[128];
+
+ if(cgs.gametype == GT_SINGLE_PLAYER) {
+ trap_Cvar_VariableStringBuffer("r_vertexlight",rendererinfos,sizeof(rendererinfos) );
+ if(cg_autovertex.integer && atoi( rendererinfos ) == 0 ) {
+ trap_Cvar_Set("r_vertexlight","1");
+ vid_restart_required = qtrue;
+ }
+ return; //Don't do anything in single player
+ }
+
+ if(cgs.videoflags & VF_LOCK_CVARS_BASIC) {
+ //Lock basic cvars.
+ trap_Cvar_VariableStringBuffer("r_subdivisions",rendererinfos,sizeof(rendererinfos) );
+ if(atoi( rendererinfos ) > 80 ) {
+ trap_Cvar_Set("r_subdivisions","80");
+ vid_restart_required = qtrue;
+ }
+
+ trap_Cvar_VariableStringBuffer("cg_shadows",rendererinfos,sizeof(rendererinfos) );
+ if (atoi( rendererinfos )!=0 && atoi( rendererinfos )!=1 ) {
+ trap_Cvar_Set("cg_shadows","1");
+ }
+ }
+
+ if(cgs.videoflags & VF_LOCK_CVARS_EXTENDED) {
+ //Lock extended cvars.
+ trap_Cvar_VariableStringBuffer("r_subdivisions",rendererinfos,sizeof(rendererinfos) );
+ if(atoi( rendererinfos ) > 20 ) {
+ trap_Cvar_Set("r_subdivisions","20");
+ vid_restart_required = qtrue;
+ }
+
+ trap_Cvar_VariableStringBuffer("r_picmip",rendererinfos,sizeof(rendererinfos) );
+ if(atoi( rendererinfos ) > 3 ) {
+ trap_Cvar_Set("r_picmip","3");
+ vid_restart_required = qtrue;
+ } else if(atoi( rendererinfos ) < 0 ) {
+ trap_Cvar_Set("r_picmip","0");
+ vid_restart_required = qtrue;
+ }
+
+ trap_Cvar_VariableStringBuffer("r_intensity",rendererinfos,sizeof(rendererinfos) );
+ if(atoi( rendererinfos ) > 2 ) {
+ trap_Cvar_Set("r_intensity","2");
+ vid_restart_required = qtrue;
+ } else if(atoi( rendererinfos ) < 0 ) {
+ trap_Cvar_Set("r_intensity","0");
+ vid_restart_required = qtrue;
+ }
+
+ trap_Cvar_VariableStringBuffer("r_mapoverbrightbits",rendererinfos,sizeof(rendererinfos) );
+ if(atoi( rendererinfos ) > 2 ) {
+ trap_Cvar_Set("r_mapoverbrightbits","2");
+ vid_restart_required = qtrue;
+ } else if(atoi( rendererinfos ) < 0 ) {
+ trap_Cvar_Set("r_mapoverbrightbits","0");
+ vid_restart_required = qtrue;
+ }
+
+ trap_Cvar_VariableStringBuffer("r_overbrightbits",rendererinfos,sizeof(rendererinfos) );
+ if(atoi( rendererinfos ) > 2 ) {
+ trap_Cvar_Set("r_overbrightbits","2");
+ vid_restart_required = qtrue;
+ } else if(atoi( rendererinfos ) < 0 ) {
+ trap_Cvar_Set("r_overbrightbits","0");
+ vid_restart_required = qtrue;
+ }
+ }
+
+ if(cgs.videoflags & VF_LOCK_VERTEX) {
+ trap_Cvar_VariableStringBuffer("r_vertexlight",rendererinfos,sizeof(rendererinfos) );
+ if(atoi( rendererinfos ) != 0 ) {
+ trap_Cvar_Set("r_vertexlight","0");
+ vid_restart_required = qtrue;
+ }
+ } else if(cg_autovertex.integer){
+ trap_Cvar_VariableStringBuffer("r_vertexlight",rendererinfos,sizeof(rendererinfos) );
+ if(atoi( rendererinfos ) == 0 ) {
+ trap_Cvar_Set("r_vertexlight","1");
+ vid_restart_required = qtrue;
+ }
+ }
+
+ if(vid_restart_required && do_vid_restart)
+ trap_SendConsoleCommand("vid_restart");
+
+ do_vid_restart = qtrue;
+}
+
diff --git a/code/cgame/cg_marks.c b/code/cgame/cg_marks.c
new file mode 100644
index 0000000..55e3cdc
--- /dev/null
+++ b/code/cgame/cg_marks.c
@@ -0,0 +1,2563 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_marks.c -- wall marks
+
+#include "cg_local.h"
+
+/*
+===================================================================
+
+MARK POLYS
+
+===================================================================
+*/
+
+
+markPoly_t cg_activeMarkPolys; // double linked list
+markPoly_t *cg_freeMarkPolys; // single linked list
+markPoly_t cg_markPolys[MAX_MARK_POLYS];
+static int markTotal;
+
+/*
+===================
+CG_InitMarkPolys
+
+This is called at startup and for tournement restarts
+===================
+*/
+void CG_InitMarkPolys( void ) {
+ int i;
+
+ memset( cg_markPolys, 0, sizeof(cg_markPolys) );
+
+ cg_activeMarkPolys.nextMark = &cg_activeMarkPolys;
+ cg_activeMarkPolys.prevMark = &cg_activeMarkPolys;
+ cg_freeMarkPolys = cg_markPolys;
+ for ( i = 0 ; i < MAX_MARK_POLYS - 1 ; i++ ) {
+ cg_markPolys[i].nextMark = &cg_markPolys[i+1];
+ }
+}
+
+
+/*
+==================
+CG_FreeMarkPoly
+==================
+*/
+void CG_FreeMarkPoly( markPoly_t *le ) {
+ if ( !le->prevMark ) {
+ CG_Error( "CG_FreeLocalEntity: not active" );
+ }
+
+ // remove from the doubly linked active list
+ le->prevMark->nextMark = le->nextMark;
+ le->nextMark->prevMark = le->prevMark;
+
+ // the free list is only singly linked
+ le->nextMark = cg_freeMarkPolys;
+ cg_freeMarkPolys = le;
+}
+
+/*
+===================
+CG_AllocMark
+
+Will allways succeed, even if it requires freeing an old active mark
+===================
+*/
+markPoly_t *CG_AllocMark( void ) {
+ markPoly_t *le;
+ int time;
+
+ if ( !cg_freeMarkPolys ) {
+ // no free entities, so free the one at the end of the chain
+ // remove the oldest active entity
+ time = cg_activeMarkPolys.prevMark->time;
+ while (cg_activeMarkPolys.prevMark && time == cg_activeMarkPolys.prevMark->time) {
+ CG_FreeMarkPoly( cg_activeMarkPolys.prevMark );
+ }
+ }
+
+ le = cg_freeMarkPolys;
+ cg_freeMarkPolys = cg_freeMarkPolys->nextMark;
+
+ memset( le, 0, sizeof( *le ) );
+
+ // link into the active list
+ le->nextMark = cg_activeMarkPolys.nextMark;
+ le->prevMark = &cg_activeMarkPolys;
+ cg_activeMarkPolys.nextMark->prevMark = le;
+ cg_activeMarkPolys.nextMark = le;
+ return le;
+}
+
+
+
+/*
+=================
+CG_ImpactMark
+
+origin should be a point within a unit of the plane
+dir should be the plane normal
+
+temporary marks will not be stored or randomly oriented, but immediately
+passed to the renderer.
+=================
+*/
+#define MAX_MARK_FRAGMENTS 128
+#define MAX_MARK_POINTS 384
+
+void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir,
+ float orientation, float red, float green, float blue, float alpha,
+ qboolean alphaFade, float radius, qboolean temporary ) {
+ vec3_t axis[3];
+ float texCoordScale;
+ vec3_t originalPoints[4];
+ byte colors[4];
+ int i, j;
+ int numFragments;
+ markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf;
+ vec3_t markPoints[MAX_MARK_POINTS];
+ vec3_t projection;
+
+ if ( !cg_addMarks.integer ) {
+ return;
+ }
+
+ if ( radius <= 0 ) {
+ CG_Error( "CG_ImpactMark called with <= 0 radius" );
+ }
+
+ //if ( markTotal >= MAX_MARK_POLYS ) {
+ // return;
+ //}
+
+ // create the texture axis
+ VectorNormalize2( dir, axis[0] );
+ PerpendicularVector( axis[1], axis[0] );
+ if (cg_leiEnhancement.integer) // LEILEI HACK HACK HACK - don't spin atlas variated particles (for consistent lighting on the texture)
+ orientation = 90;
+
+ RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
+ CrossProduct( axis[0], axis[2], axis[1] );
+
+ texCoordScale = 0.5 * 1.0 / radius;
+
+ // create the full polygon
+ for ( i = 0 ; i < 3 ; i++ ) {
+ originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
+ originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
+ originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
+ originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
+ }
+
+ // get the fragments
+ VectorScale( dir, -20, projection );
+ numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints,
+ projection, MAX_MARK_POINTS, markPoints[0],
+ MAX_MARK_FRAGMENTS, markFragments );
+
+ colors[0] = red * 255;
+ colors[1] = green * 255;
+ colors[2] = blue * 255;
+ colors[3] = alpha * 255;
+
+ for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
+ polyVert_t *v;
+ polyVert_t verts[MAX_VERTS_ON_POLY];
+ markPoly_t *mark;
+
+ // we have an upper limit on the complexity of polygons
+ // that we store persistantly
+ if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
+ mf->numPoints = MAX_VERTS_ON_POLY;
+ }
+ for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
+ vec3_t delta;
+
+ VectorCopy( markPoints[mf->firstPoint + j], v->xyz );
+
+ VectorSubtract( v->xyz, origin, delta );
+ v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
+ v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
+ *(int *)v->modulate = *(int *)colors;
+ }
+
+ // if it is a temporary (shadow) mark, add it immediately and forget about it
+ if ( temporary ) {
+ trap_R_AddPolyToScene( markShader, mf->numPoints, verts );
+ continue;
+ }
+
+ // otherwise save it persistantly
+ mark = CG_AllocMark();
+ mark->time = cg.time;
+ mark->alphaFade = alphaFade;
+ mark->markShader = markShader;
+ mark->poly.numVerts = mf->numPoints;
+ mark->color[0] = red;
+ mark->color[1] = green;
+ mark->color[2] = blue;
+ mark->color[3] = alpha;
+ memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
+ markTotal++;
+ }
+}
+
+
+/*
+===============
+CG_AddMarks
+===============
+*/
+#define MARK_TOTAL_TIME 10000
+#define MARK_FADE_TIME 1000
+
+void CG_AddMarks( void ) {
+ int j;
+ markPoly_t *mp, *next;
+ int t;
+ int fade;
+
+ if ( !cg_addMarks.integer ) {
+ return;
+ }
+
+ mp = cg_activeMarkPolys.nextMark;
+ for ( ; mp != &cg_activeMarkPolys ; mp = next ) {
+ // grab next now, so if the local entity is freed we
+ // still have it
+ next = mp->nextMark;
+
+ // see if it is time to completely remove it
+ if ( cg.time > mp->time + MARK_TOTAL_TIME ) {
+ CG_FreeMarkPoly( mp );
+ continue;
+ }
+
+ // fade out the energy bursts
+ if ( mp->markShader == cgs.media.energyMarkShader ) {
+
+ fade = 450 - 450 * ( (cg.time - mp->time ) / 3000.0 );
+ if ( fade < 255 ) {
+ if ( fade < 0 ) {
+ fade = 0;
+ }
+ if ( mp->verts[0].modulate[0] != 0 ) {
+ for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
+ mp->verts[j].modulate[0] = mp->color[0] * fade;
+ mp->verts[j].modulate[1] = mp->color[1] * fade;
+ mp->verts[j].modulate[2] = mp->color[2] * fade;
+ }
+ }
+ }
+ }
+
+ // fade all marks out with time
+ t = mp->time + MARK_TOTAL_TIME - cg.time;
+ if ( t < MARK_FADE_TIME ) {
+ fade = 255 * t / MARK_FADE_TIME;
+ if ( mp->alphaFade ) {
+ for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
+ mp->verts[j].modulate[3] = fade;
+ }
+ } else {
+ for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
+ mp->verts[j].modulate[0] = mp->color[0] * fade;
+ mp->verts[j].modulate[1] = mp->color[1] * fade;
+ mp->verts[j].modulate[2] = mp->color[2] * fade;
+ }
+ }
+ }
+
+
+ trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts );
+ }
+}
+
+// cg_particles.c
+
+#define BLOODRED 2
+#define EMISIVEFADE 3
+#define GREY75 4
+
+typedef struct particle_s
+{
+ struct particle_s *next;
+
+ float time;
+ float endtime;
+
+ vec3_t org;
+ vec3_t vel;
+ vec3_t accel;
+ int color;
+ float colorvel;
+ float alpha;
+ float alphavel;
+ int type;
+ qhandle_t pshader;
+
+ float height;
+ float width;
+
+ float endheight;
+ float endwidth;
+
+ float start;
+ float end;
+
+ float startfade;
+ qboolean rotate;
+ int snum;
+
+ qboolean link;
+
+ // Ridah
+ int shaderAnim;
+ int roll;
+
+ int accumroll;
+
+} cparticle_t;
+
+typedef enum
+{
+ P_NONE,
+ P_WEATHER,
+ P_FLAT,
+ P_SMOKE,
+ P_ROTATE,
+ P_WEATHER_TURBULENT,
+ P_ANIM, // Ridah
+ P_BAT,
+ P_BLEED,
+ P_FLAT_SCALEUP,
+ P_FLAT_SCALEUP_FADE,
+ P_WEATHER_FLURRY,
+ P_SMOKE_IMPACT,
+ P_BUBBLE,
+ P_BUBBLE_TURBULENT,
+ P_SPRITE
+} particle_type_t;
+
+#define MAX_SHADER_ANIMS 32
+#define MAX_SHADER_ANIM_FRAMES 64
+
+static char *shaderAnimNames[MAX_SHADER_ANIMS] = {
+ "explode1",
+ NULL
+};
+static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];
+static int shaderAnimCounts[MAX_SHADER_ANIMS] = {
+ 23
+};
+static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = {
+ 1.0f
+};
+static int numShaderAnims;
+// done.
+
+#define PARTICLE_GRAVITY 40
+#define MAX_PARTICLES 1024
+
+cparticle_t *active_particles, *free_particles;
+cparticle_t particles[MAX_PARTICLES];
+int cl_numparticles = MAX_PARTICLES;
+
+qboolean initparticles = qfalse;
+vec3_t pvforward, pvright, pvup;
+vec3_t rforward, rright, rup;
+
+float oldtime;
+
+/*
+===============
+CL_ClearParticles
+===============
+*/
+void CG_ClearParticles (void)
+{
+ int i;
+
+ memset( particles, 0, sizeof(particles) );
+
+ free_particles = &particles[0];
+ active_particles = NULL;
+
+ for (i=0 ;i<cl_numparticles ; i++)
+ {
+ particles[i].next = &particles[i+1];
+ particles[i].type = 0;
+ }
+ particles[cl_numparticles-1].next = NULL;
+
+ oldtime = cg.time;
+
+ // Ridah, init the shaderAnims
+ for (i=0; shaderAnimNames[i]; i++) {
+ int j;
+
+ for (j=0; j<shaderAnimCounts[i]; j++) {
+ shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) );
+ }
+ }
+ numShaderAnims = i;
+ // done.
+
+ initparticles = qtrue;
+}
+
+
+/*
+=====================
+CG_AddParticleToScene
+=====================
+*/
+void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)
+{
+
+ vec3_t point;
+ polyVert_t verts[4];
+ float width;
+ float height;
+ float time, time2;
+ float ratio;
+ float invratio;
+ vec3_t color;
+ polyVert_t TRIverts[3];
+ vec3_t rright2, rup2;
+
+ if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY
+ || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
+ {// create a front facing polygon
+
+ if (p->type != P_WEATHER_FLURRY)
+ {
+ if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
+ {
+ if (org[2] > p->end)
+ {
+ p->time = cg.time;
+ VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
+
+ p->org[2] = ( p->start + crandom () * 4 );
+
+
+ if (p->type == P_BUBBLE_TURBULENT)
+ {
+ p->vel[0] = crandom() * 4;
+ p->vel[1] = crandom() * 4;
+ }
+
+ }
+ }
+ else
+ {
+ if (org[2] < p->end)
+ {
+ p->time = cg.time;
+ VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
+
+ while (p->org[2] < p->end)
+ {
+ p->org[2] += (p->start - p->end);
+ }
+
+
+ if (p->type == P_WEATHER_TURBULENT)
+ {
+ p->vel[0] = crandom() * 16;
+ p->vel[1] = crandom() * 16;
+ }
+
+ }
+ }
+
+
+ // Rafael snow pvs check
+ if (!p->link)
+ return;
+
+ p->alpha = 1;
+ }
+
+ // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp
+ if (Distance( cg.snap->ps.origin, org ) > 1024) {
+ return;
+ }
+ // done.
+
+ if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
+ {
+ VectorMA (org, -p->height, pvup, point);
+ VectorMA (point, -p->width, pvright, point);
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, -p->height, pvup, point);
+ VectorMA (point, p->width, pvright, point);
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, p->height, pvup, point);
+ VectorMA (point, p->width, pvright, point);
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, p->height, pvup, point);
+ VectorMA (point, -p->width, pvright, point);
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255 * p->alpha;
+ }
+ else
+ {
+ VectorMA (org, -p->height, pvup, point);
+ VectorMA (point, -p->width, pvright, point);
+ VectorCopy( point, TRIverts[0].xyz );
+ TRIverts[0].st[0] = 1;
+ TRIverts[0].st[1] = 0;
+ TRIverts[0].modulate[0] = 255;
+ TRIverts[0].modulate[1] = 255;
+ TRIverts[0].modulate[2] = 255;
+ TRIverts[0].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, p->height, pvup, point);
+ VectorMA (point, -p->width, pvright, point);
+ VectorCopy (point, TRIverts[1].xyz);
+ TRIverts[1].st[0] = 0;
+ TRIverts[1].st[1] = 0;
+ TRIverts[1].modulate[0] = 255;
+ TRIverts[1].modulate[1] = 255;
+ TRIverts[1].modulate[2] = 255;
+ TRIverts[1].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, p->height, pvup, point);
+ VectorMA (point, p->width, pvright, point);
+ VectorCopy (point, TRIverts[2].xyz);
+ TRIverts[2].st[0] = 0;
+ TRIverts[2].st[1] = 1;
+ TRIverts[2].modulate[0] = 255;
+ TRIverts[2].modulate[1] = 255;
+ TRIverts[2].modulate[2] = 255;
+ TRIverts[2].modulate[3] = 255 * p->alpha;
+ }
+
+ }
+ else if (p->type == P_SPRITE)
+ {
+ vec3_t rr, ru;
+ vec3_t rotate_ang;
+
+ VectorSet (color, 1.0, 1.0, 0.5);
+ time = cg.time - p->time;
+ time2 = p->endtime - p->time;
+ ratio = time / time2;
+
+ width = p->width + ( ratio * ( p->endwidth - p->width) );
+ height = p->height + ( ratio * ( p->endheight - p->height) );
+
+ if (p->roll) {
+ vectoangles( cg.refdef.viewaxis[0], rotate_ang );
+ rotate_ang[ROLL] += p->roll;
+ AngleVectors ( rotate_ang, NULL, rr, ru);
+ }
+
+ if (p->roll) {
+ VectorMA (org, -height, ru, point);
+ VectorMA (point, -width, rr, point);
+ } else {
+ VectorMA (org, -height, pvup, point);
+ VectorMA (point, -width, pvright, point);
+ }
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, 2*height, ru, point);
+ } else {
+ VectorMA (point, 2*height, pvup, point);
+ }
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, 2*width, rr, point);
+ } else {
+ VectorMA (point, 2*width, pvright, point);
+ }
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, -2*height, ru, point);
+ } else {
+ VectorMA (point, -2*height, pvup, point);
+ }
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255;
+ }
+ else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)
+ {// create a front rotating facing polygon
+
+ if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {
+ return;
+ }
+
+ if (p->color == BLOODRED)
+ VectorSet (color, 0.22f, 0.0f, 0.0f);
+ else if (p->color == GREY75)
+ {
+ float len;
+ float greyit;
+ float val;
+ len = Distance (cg.snap->ps.origin, org);
+ if (!len)
+ len = 1;
+
+ val = 4096/len;
+ greyit = 0.25 * val;
+ if (greyit > 0.5)
+ greyit = 0.5;
+
+ VectorSet (color, greyit, greyit, greyit);
+ }
+ else
+ VectorSet (color, 1.0, 1.0, 1.0);
+
+ time = cg.time - p->time;
+ time2 = p->endtime - p->time;
+ ratio = time / time2;
+
+ if (cg.time > p->startfade)
+ {
+ invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );
+
+ if (p->color == EMISIVEFADE)
+ {
+ float fval;
+ fval = (invratio * invratio);
+ if (fval < 0)
+ fval = 0;
+ VectorSet (color, fval , fval , fval );
+ }
+ invratio *= p->alpha;
+ }
+ else
+ invratio = 1 * p->alpha;
+
+ if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
+ invratio = 1;
+
+ if (invratio > 1)
+ invratio = 1;
+
+ width = p->width + ( ratio * ( p->endwidth - p->width) );
+ height = p->height + ( ratio * ( p->endheight - p->height) );
+
+ if (p->type != P_SMOKE_IMPACT)
+ {
+ vec3_t temp;
+
+ vectoangles (rforward, temp);
+ p->accumroll += p->roll;
+ temp[ROLL] += p->accumroll * 0.1;
+ AngleVectors ( temp, NULL, rright2, rup2);
+ }
+ else
+ {
+ VectorCopy (rright, rright2);
+ VectorCopy (rup, rup2);
+ }
+
+ if (p->rotate)
+ {
+ VectorMA (org, -height, rup2, point);
+ VectorMA (point, -width, rright2, point);
+ }
+ else
+ {
+ VectorMA (org, -p->height, pvup, point);
+ VectorMA (point, -p->width, pvright, point);
+ }
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255 * color[0];
+ verts[0].modulate[1] = 255 * color[1];
+ verts[0].modulate[2] = 255 * color[2];
+ verts[0].modulate[3] = 255 * invratio;
+
+ if (p->rotate)
+ {
+ VectorMA (org, -height, rup2, point);
+ VectorMA (point, width, rright2, point);
+ }
+ else
+ {
+ VectorMA (org, -p->height, pvup, point);
+ VectorMA (point, p->width, pvright, point);
+ }
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255 * color[0];
+ verts[1].modulate[1] = 255 * color[1];
+ verts[1].modulate[2] = 255 * color[2];
+ verts[1].modulate[3] = 255 * invratio;
+
+ if (p->rotate)
+ {
+ VectorMA (org, height, rup2, point);
+ VectorMA (point, width, rright2, point);
+ }
+ else
+ {
+ VectorMA (org, p->height, pvup, point);
+ VectorMA (point, p->width, pvright, point);
+ }
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255 * color[0];
+ verts[2].modulate[1] = 255 * color[1];
+ verts[2].modulate[2] = 255 * color[2];
+ verts[2].modulate[3] = 255 * invratio;
+
+ if (p->rotate)
+ {
+ VectorMA (org, height, rup2, point);
+ VectorMA (point, -width, rright2, point);
+ }
+ else
+ {
+ VectorMA (org, p->height, pvup, point);
+ VectorMA (point, -p->width, pvright, point);
+ }
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255 * color[0];
+ verts[3].modulate[1] = 255 * color[1];
+ verts[3].modulate[2] = 255 * color[2];
+ verts[3].modulate[3] = 255 * invratio;
+
+ }
+ else if (p->type == P_BLEED)
+ {
+ vec3_t rr, ru;
+ vec3_t rotate_ang;
+ float alpha;
+
+ alpha = p->alpha;
+
+ if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
+ alpha = 1;
+
+ if (p->roll)
+ {
+ vectoangles( cg.refdef.viewaxis[0], rotate_ang );
+ rotate_ang[ROLL] += p->roll;
+ AngleVectors ( rotate_ang, NULL, rr, ru);
+ }
+ else
+ {
+ VectorCopy (pvup, ru);
+ VectorCopy (pvright, rr);
+ }
+
+ VectorMA (org, -p->height, ru, point);
+ VectorMA (point, -p->width, rr, point);
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 111;
+ verts[0].modulate[1] = 19;
+ verts[0].modulate[2] = 9;
+ verts[0].modulate[3] = 255 * alpha;
+
+ VectorMA (org, -p->height, ru, point);
+ VectorMA (point, p->width, rr, point);
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 111;
+ verts[1].modulate[1] = 19;
+ verts[1].modulate[2] = 9;
+ verts[1].modulate[3] = 255 * alpha;
+
+ VectorMA (org, p->height, ru, point);
+ VectorMA (point, p->width, rr, point);
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 111;
+ verts[2].modulate[1] = 19;
+ verts[2].modulate[2] = 9;
+ verts[2].modulate[3] = 255 * alpha;
+
+ VectorMA (org, p->height, ru, point);
+ VectorMA (point, -p->width, rr, point);
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 111;
+ verts[3].modulate[1] = 19;
+ verts[3].modulate[2] = 9;
+ verts[3].modulate[3] = 255 * alpha;
+
+ }
+ else if (p->type == P_FLAT_SCALEUP)
+ {
+ float width, height;
+ float sinR, cosR;
+
+ if (p->color == BLOODRED)
+ VectorSet (color, 1, 1, 1);
+ else
+ VectorSet (color, 0.5, 0.5, 0.5);
+
+ time = cg.time - p->time;
+ time2 = p->endtime - p->time;
+ ratio = time / time2;
+
+ width = p->width + ( ratio * ( p->endwidth - p->width) );
+ height = p->height + ( ratio * ( p->endheight - p->height) );
+
+ if (width > p->endwidth)
+ width = p->endwidth;
+
+ if (height > p->endheight)
+ height = p->endheight;
+
+ sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);
+ cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);
+
+ VectorCopy (org, verts[0].xyz);
+ verts[0].xyz[0] -= sinR;
+ verts[0].xyz[1] -= cosR;
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255 * color[0];
+ verts[0].modulate[1] = 255 * color[1];
+ verts[0].modulate[2] = 255 * color[2];
+ verts[0].modulate[3] = 255;
+
+ VectorCopy (org, verts[1].xyz);
+ verts[1].xyz[0] -= cosR;
+ verts[1].xyz[1] += sinR;
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255 * color[0];
+ verts[1].modulate[1] = 255 * color[1];
+ verts[1].modulate[2] = 255 * color[2];
+ verts[1].modulate[3] = 255;
+
+ VectorCopy (org, verts[2].xyz);
+ verts[2].xyz[0] += sinR;
+ verts[2].xyz[1] += cosR;
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255 * color[0];
+ verts[2].modulate[1] = 255 * color[1];
+ verts[2].modulate[2] = 255 * color[2];
+ verts[2].modulate[3] = 255;
+
+ VectorCopy (org, verts[3].xyz);
+ verts[3].xyz[0] += cosR;
+ verts[3].xyz[1] -= sinR;
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255 * color[0];
+ verts[3].modulate[1] = 255 * color[1];
+ verts[3].modulate[2] = 255 * color[2];
+ verts[3].modulate[3] = 255;
+ }
+ else if (p->type == P_FLAT)
+ {
+
+ VectorCopy (org, verts[0].xyz);
+ verts[0].xyz[0] -= p->height;
+ verts[0].xyz[1] -= p->width;
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255;
+
+ VectorCopy (org, verts[1].xyz);
+ verts[1].xyz[0] -= p->height;
+ verts[1].xyz[1] += p->width;
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255;
+
+ VectorCopy (org, verts[2].xyz);
+ verts[2].xyz[0] += p->height;
+ verts[2].xyz[1] += p->width;
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255;
+
+ VectorCopy (org, verts[3].xyz);
+ verts[3].xyz[0] += p->height;
+ verts[3].xyz[1] -= p->width;
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255;
+
+ }
+ // Ridah
+ else if (p->type == P_ANIM) {
+ vec3_t rr, ru;
+ vec3_t rotate_ang;
+ int i, j;
+
+ time = cg.time - p->time;
+ time2 = p->endtime - p->time;
+ ratio = time / time2;
+ if (ratio >= 1.0f) {
+ ratio = 0.9999f;
+ }
+
+ width = p->width + ( ratio * ( p->endwidth - p->width) );
+ height = p->height + ( ratio * ( p->endheight - p->height) );
+
+ // if we are "inside" this sprite, don't draw
+ if (Distance( cg.snap->ps.origin, org ) < width/1.5) {
+ return;
+ }
+
+ i = p->shaderAnim;
+ j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);
+ p->pshader = shaderAnims[i][j];
+
+ if (p->roll) {
+ vectoangles( cg.refdef.viewaxis[0], rotate_ang );
+ rotate_ang[ROLL] += p->roll;
+ AngleVectors ( rotate_ang, NULL, rr, ru);
+ }
+
+ if (p->roll) {
+ VectorMA (org, -height, ru, point);
+ VectorMA (point, -width, rr, point);
+ } else {
+ VectorMA (org, -height, pvup, point);
+ VectorMA (point, -width, pvright, point);
+ }
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, 2*height, ru, point);
+ } else {
+ VectorMA (point, 2*height, pvup, point);
+ }
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, 2*width, rr, point);
+ } else {
+ VectorMA (point, 2*width, pvright, point);
+ }
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, -2*height, ru, point);
+ } else {
+ VectorMA (point, -2*height, pvup, point);
+ }
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255;
+ }
+ // done.
+
+ if (!p->pshader) {
+// (SA) temp commented out for DM
+// CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type);
+ return;
+ }
+
+ if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)
+ trap_R_AddPolyToScene( p->pshader, 3, TRIverts );
+ else
+ trap_R_AddPolyToScene( p->pshader, 4, verts );
+
+}
+
+// Ridah, made this static so it doesn't interfere with other files
+static float roll = 0.0;
+
+/*
+===============
+CG_AddParticles
+===============
+*/
+void CG_AddParticles (void)
+{
+ cparticle_t *p, *next;
+ float alpha;
+ float time, time2;
+ vec3_t org;
+ int color;
+ cparticle_t *active, *tail;
+ int type;
+ vec3_t rotate_ang;
+
+ if (!initparticles)
+ CG_ClearParticles ();
+
+ VectorCopy( cg.refdef.viewaxis[0], pvforward );
+ VectorCopy( cg.refdef.viewaxis[1], pvright );
+ VectorCopy( cg.refdef.viewaxis[2], pvup );
+
+ vectoangles( cg.refdef.viewaxis[0], rotate_ang );
+ roll += ((cg.time - oldtime) * 0.1) ;
+ rotate_ang[ROLL] += (roll*0.9);
+ AngleVectors ( rotate_ang, rforward, rright, rup);
+
+ oldtime = cg.time;
+
+ active = NULL;
+ tail = NULL;
+
+ for (p=active_particles ; p ; p=next)
+ {
+
+ next = p->next;
+
+ time = (cg.time - p->time)*0.001;
+
+ alpha = p->alpha + time*p->alphavel;
+ if (alpha <= 0)
+ { // faded out
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+ continue;
+ }
+
+ if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)
+ {
+ if (cg.time > p->endtime)
+ {
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+
+ continue;
+ }
+
+ }
+
+ if (p->type == P_WEATHER_FLURRY)
+ {
+ if (cg.time > p->endtime)
+ {
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+
+ continue;
+ }
+ }
+
+
+ if (p->type == P_FLAT_SCALEUP_FADE)
+ {
+ if (cg.time > p->endtime)
+ {
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+ continue;
+ }
+
+ }
+
+ if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {
+ // temporary sprite
+ CG_AddParticleToScene (p, p->org, alpha);
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+ continue;
+ }
+
+ p->next = NULL;
+ if (!tail)
+ active = tail = p;
+ else
+ {
+ tail->next = p;
+ tail = p;
+ }
+
+ if (alpha > 1.0)
+ alpha = 1;
+
+ color = p->color;
+
+ time2 = time*time;
+
+ org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
+ org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
+ org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
+
+ type = p->type;
+
+ CG_AddParticleToScene (p, org, alpha);
+ }
+
+ active_particles = active;
+}
+
+/*
+======================
+CG_AddParticles
+======================
+*/
+void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent)
+{
+ cparticle_t *p;
+ qboolean turb = qtrue;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->color = 0;
+ p->alpha = 0.90f;
+ p->alphavel = 0;
+
+ p->start = cent->currentState.origin2[0];
+ p->end = cent->currentState.origin2[1];
+
+ p->endtime = cg.time + cent->currentState.time;
+ p->startfade = cg.time + cent->currentState.time2;
+
+ p->pshader = pshader;
+
+ if (rand()%100 > 90)
+ {
+ p->height = 32;
+ p->width = 32;
+ p->alpha = 0.10f;
+ }
+ else
+ {
+ p->height = 1;
+ p->width = 1;
+ }
+
+ p->vel[2] = -20;
+
+ p->type = P_WEATHER_FLURRY;
+
+ if (turb)
+ p->vel[2] = -10;
+
+ VectorCopy(cent->currentState.origin, p->org);
+
+ p->org[0] = p->org[0];
+ p->org[1] = p->org[1];
+ p->org[2] = p->org[2];
+
+ p->vel[0] = p->vel[1] = 0;
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16);
+ p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16);
+ p->vel[2] += cent->currentState.angles[2];
+
+ if (turb)
+ {
+ p->accel[0] = crandom () * 16;
+ p->accel[1] = crandom () * 16;
+ }
+
+}
+
+void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->color = 0;
+ p->alpha = 0.40f;
+ p->alphavel = 0;
+ p->start = origin[2];
+ p->end = origin2[2];
+ p->pshader = pshader;
+ p->height = 1;
+ p->width = 1;
+
+ p->vel[2] = -50;
+
+ if (turb)
+ {
+ p->type = P_WEATHER_TURBULENT;
+ p->vel[2] = -50 * 1.3;
+ }
+ else
+ {
+ p->type = P_WEATHER;
+ }
+
+ VectorCopy(origin, p->org);
+
+ p->org[0] = p->org[0] + ( crandom() * range);
+ p->org[1] = p->org[1] + ( crandom() * range);
+ p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
+
+ p->vel[0] = p->vel[1] = 0;
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ if (turb)
+ {
+ p->vel[0] = crandom() * 16;
+ p->vel[1] = crandom() * 16;
+ }
+
+ // Rafael snow pvs check
+ p->snum = snum;
+ p->link = qtrue;
+
+}
+
+void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
+{
+ cparticle_t *p;
+ float randsize;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->color = 0;
+ p->alpha = 0.40f;
+ p->alphavel = 0;
+ p->start = origin[2];
+ p->end = origin2[2];
+ p->pshader = pshader;
+
+ randsize = 1 + (crandom() * 0.5);
+
+ p->height = randsize;
+ p->width = randsize;
+
+ p->vel[2] = 50 + ( crandom() * 10 );
+
+ if (turb)
+ {
+ p->type = P_BUBBLE_TURBULENT;
+ p->vel[2] = 50 * 1.3;
+ }
+ else
+ {
+ p->type = P_BUBBLE;
+ }
+
+ VectorCopy(origin, p->org);
+
+ p->org[0] = p->org[0] + ( crandom() * range);
+ p->org[1] = p->org[1] + ( crandom() * range);
+ p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
+
+ p->vel[0] = p->vel[1] = 0;
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ if (turb)
+ {
+ p->vel[0] = crandom() * 4;
+ p->vel[1] = crandom() * 4;
+ }
+
+ // Rafael snow pvs check
+ p->snum = snum;
+ p->link = qtrue;
+
+}
+
+void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent)
+{
+
+ // using cent->density = enttime
+ // cent->frame = startfade
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleSmoke == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + cent->currentState.time;
+ p->startfade = cg.time + cent->currentState.time2;
+
+ p->color = 0;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->start = cent->currentState.origin[2];
+ p->end = cent->currentState.origin2[2];
+ p->pshader = pshader;
+ p->rotate = qfalse;
+ p->height = 8;
+ p->width = 8;
+ p->endheight = 32;
+ p->endwidth = 32;
+ p->type = P_SMOKE;
+
+ VectorCopy(cent->currentState.origin, p->org);
+
+ p->vel[0] = p->vel[1] = 0;
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[2] = 5;
+
+ if (cent->currentState.frame == 1)// reverse gravity
+ p->vel[2] *= -1;
+
+ p->roll = 8 + (crandom() * 4);
+}
+
+
+void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration)
+{
+
+ cparticle_t *p;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + duration;
+ p->startfade = cg.time + duration/2;
+
+ p->color = EMISIVEFADE;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+
+ p->height = 0.5;
+ p->width = 0.5;
+ p->endheight = 0.5;
+ p->endwidth = 0.5;
+
+ p->pshader = cgs.media.tracerShader;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(org, p->org);
+
+ p->vel[0] = vel[0];
+ p->vel[1] = vel[1];
+ p->vel[2] = vel[2];
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->accel[2] = -60;
+ p->vel[2] += -20;
+
+}
+
+/*
+======================
+CG_ParticleExplosion
+======================
+*/
+
+void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd)
+{
+ cparticle_t *p;
+ int anim;
+
+ if (animStr < (char *)10)
+ CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" );
+
+ // find the animation string
+ for (anim=0; shaderAnimNames[anim]; anim++) {
+ if (!Q_stricmp( animStr, shaderAnimNames[anim] ))
+ break;
+ }
+ if (!shaderAnimNames[anim]) {
+ CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr);
+ return;
+ }
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 0.5;
+ p->alphavel = 0;
+
+ if (duration < 0) {
+ duration *= -1;
+ p->roll = 0;
+ } else {
+ p->roll = crandom()*179;
+ }
+
+ p->shaderAnim = anim;
+
+ p->width = sizeStart;
+ p->height = sizeStart*shaderAnimSTRatio[anim]; // for sprites that are stretch in either direction
+
+ p->endheight = sizeEnd;
+ p->endwidth = sizeEnd*shaderAnimSTRatio[anim];
+
+ p->endtime = cg.time + duration;
+
+ p->type = P_ANIM;
+
+ VectorCopy( origin, p->org );
+ VectorCopy( vel, p->vel );
+ VectorClear( p->accel );
+
+}
+
+// Rafael Shrapnel
+void CG_AddParticleShrapnel (localEntity_t *le)
+{
+ return;
+}
+// done.
+
+int CG_NewParticleArea (int num)
+{
+ // const char *str;
+ char *str;
+ char *token;
+ int type;
+ vec3_t origin, origin2;
+ int i;
+ float range = 0;
+ int turb;
+ int numparticles;
+ int snum;
+
+ str = (char *) CG_ConfigString (num);
+ if (!str[0])
+ return (0);
+
+ // returns type 128 64 or 32
+ token = COM_Parse (&str);
+ type = atoi (token);
+
+ if (type == 1)
+ range = 128;
+ else if (type == 2)
+ range = 64;
+ else if (type == 3)
+ range = 32;
+ else if (type == 0)
+ range = 256;
+ else if (type == 4)
+ range = 8;
+ else if (type == 5)
+ range = 16;
+ else if (type == 6)
+ range = 32;
+ else if (type == 7)
+ range = 64;
+
+
+ for (i=0; i<3; i++)
+ {
+ token = COM_Parse (&str);
+ origin[i] = atof (token);
+ }
+
+ for (i=0; i<3; i++)
+ {
+ token = COM_Parse (&str);
+ origin2[i] = atof (token);
+ }
+
+ token = COM_Parse (&str);
+ numparticles = atoi (token);
+
+ token = COM_Parse (&str);
+ turb = atoi (token);
+
+ token = COM_Parse (&str);
+ snum = atoi (token);
+
+ for (i=0; i<numparticles; i++)
+ {
+ if (type >= 4)
+ CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
+ else
+ CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
+ }
+
+ return (1);
+}
+
+void CG_SnowLink (centity_t *cent, qboolean particleOn)
+{
+ cparticle_t *p, *next;
+ int id;
+
+ id = cent->currentState.frame;
+
+ for (p=active_particles ; p ; p=next)
+ {
+ next = p->next;
+
+ if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT)
+ {
+ if (p->snum == id)
+ {
+ if (particleOn)
+ p->link = qtrue;
+ else
+ p->link = qfalse;
+ }
+ }
+
+ }
+}
+
+void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 0.25;
+ p->alphavel = 0;
+ p->roll = crandom()*179;
+
+ p->pshader = pshader;
+
+ p->endtime = cg.time + 1000;
+ p->startfade = cg.time + 100;
+
+ p->width = rand()%4 + 8;
+ p->height = rand()%4 + 8;
+
+ p->endheight = p->height *2;
+ p->endwidth = p->width * 2;
+
+ p->endtime = cg.time + 500;
+
+ p->type = P_SMOKE_IMPACT;
+
+ VectorCopy( origin, p->org );
+ VectorSet(p->vel, 0, 0, 20);
+ VectorSet(p->accel, 0, 0, 20);
+
+ p->rotate = qtrue;
+}
+
+void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = pshader;
+
+ p->endtime = cg.time + duration;
+
+ if (fleshEntityNum)
+ p->startfade = cg.time;
+ else
+ p->startfade = cg.time + 100;
+
+ p->width = 4;
+ p->height = 4;
+
+ p->endheight = 4+rand()%3;
+ p->endwidth = p->endheight;
+
+ p->type = P_SMOKE;
+
+ VectorCopy( start, p->org );
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = -20;
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->color = BLOODRED;
+ p->alpha = 0.75;
+
+}
+
+void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent)
+{
+ cparticle_t *p;
+
+ int time;
+ int time2;
+ float ratio;
+
+ float duration = 1500;
+
+ time = cg.time;
+ time2 = cg.time + cent->currentState.time;
+
+ ratio =(float)1 - ((float)time / (float)time2);
+
+ if (!pshader)
+ CG_Printf ("CG_Particle_OilParticle == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = pshader;
+
+ p->endtime = cg.time + duration;
+
+ p->startfade = p->endtime;
+
+ p->width = 1;
+ p->height = 3;
+
+ p->endheight = 3;
+ p->endwidth = 1;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(cent->currentState.origin, p->org );
+
+ p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio));
+ p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio));
+ p->vel[2] = (cent->currentState.origin2[2]);
+
+ p->snum = 1.0f;
+
+ VectorClear( p->accel );
+
+ p->accel[2] = -20;
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->alpha = 0.75;
+
+}
+
+
+void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_Particle_OilSlick == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ if (cent->currentState.angles2[2])
+ p->endtime = cg.time + cent->currentState.angles2[2];
+ else
+ p->endtime = cg.time + 60000;
+
+ p->startfade = p->endtime;
+
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = pshader;
+
+ if (cent->currentState.angles2[0] || cent->currentState.angles2[1])
+ {
+ p->width = cent->currentState.angles2[0];
+ p->height = cent->currentState.angles2[0];
+
+ p->endheight = cent->currentState.angles2[1];
+ p->endwidth = cent->currentState.angles2[1];
+ }
+ else
+ {
+ p->width = 8;
+ p->height = 8;
+
+ p->endheight = 16;
+ p->endwidth = 16;
+ }
+
+ p->type = P_FLAT_SCALEUP;
+
+ p->snum = 1.0;
+
+ VectorCopy(cent->currentState.origin, p->org );
+
+ p->org[2]+= 0.55 + (crandom() * 0.5);
+
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = 0;
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->alpha = 0.75;
+
+}
+
+void CG_OilSlickRemove (centity_t *cent)
+{
+ cparticle_t *p, *next;
+ int id;
+
+ id = 1.0f;
+
+ if (!id)
+ CG_Printf ("CG_OilSlickRevove NULL id\n");
+
+ for (p=active_particles ; p ; p=next)
+ {
+ next = p->next;
+
+ if (p->type == P_FLAT_SCALEUP)
+ {
+ if (p->snum == id)
+ {
+ p->endtime = cg.time + 100;
+ p->startfade = p->endtime;
+ p->type = P_FLAT_SCALEUP_FADE;
+
+ }
+ }
+
+ }
+}
+
+qboolean ValidBloodPool (vec3_t start)
+{
+#define EXTRUDE_DIST 0.5
+
+ vec3_t angles;
+ vec3_t right, up;
+ vec3_t this_pos, x_pos, center_pos, end_pos;
+ float x, y;
+ float fwidth, fheight;
+ trace_t trace;
+ vec3_t normal;
+
+ fwidth = 16;
+ fheight = 16;
+
+ VectorSet (normal, 0, 0, 1);
+
+ vectoangles (normal, angles);
+ AngleVectors (angles, NULL, right, up);
+
+ VectorMA (start, EXTRUDE_DIST, normal, center_pos);
+
+ for (x= -fwidth/2; x<fwidth; x+= fwidth)
+ {
+ VectorMA (center_pos, x, right, x_pos);
+
+ for (y= -fheight/2; y<fheight; y+= fheight)
+ {
+ VectorMA (x_pos, y, up, this_pos);
+ VectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos);
+
+ CG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID);
+
+
+ if (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world
+ return qfalse;
+
+ if (!(!trace.startsolid && trace.fraction < 1))
+ return qfalse;
+
+ }
+ }
+
+ return qtrue;
+}
+
+void CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr)
+{
+ cparticle_t *p;
+ qboolean legit;
+ vec3_t start;
+ float rndSize;
+
+ if (!pshader)
+ CG_Printf ("CG_BloodPool pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+
+ VectorCopy (tr->endpos, start);
+ legit = ValidBloodPool (start);
+
+ if (!legit)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + 3000;
+ p->startfade = p->endtime;
+
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = pshader;
+
+ rndSize = 0.4 + random()*0.6;
+
+ p->width = 8*rndSize;
+ p->height = 8*rndSize;
+
+ p->endheight = 16*rndSize;
+ p->endwidth = 16*rndSize;
+
+ p->type = P_FLAT_SCALEUP;
+
+ VectorCopy(start, p->org );
+
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = 0;
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->alpha = 0.75;
+
+ p->color = BLOODRED;
+}
+
+#define NORMALSIZE 16
+#define LARGESIZE 32
+
+void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir)
+{
+ float length;
+ float dist;
+ float crittersize;
+ vec3_t angles, forward;
+ vec3_t point;
+ cparticle_t *p;
+ int i;
+
+ dist = 0;
+
+ length = VectorLength (dir);
+ vectoangles (dir, angles);
+ AngleVectors (angles, forward, NULL, NULL);
+
+ crittersize = LARGESIZE;
+
+ if (length)
+ dist = length / crittersize;
+
+ if (dist < 1)
+ dist = 1;
+
+ VectorCopy (origin, point);
+
+ for (i=0; i<dist; i++)
+ {
+ VectorMA (point, crittersize, forward, point);
+
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cg.time;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = cgs.media.smokePuffShader;
+
+ p->endtime = cg.time + 350 + (crandom() * 100);
+
+ p->startfade = cg.time;
+
+ p->width = LARGESIZE;
+ p->height = LARGESIZE;
+ p->endheight = LARGESIZE;
+ p->endwidth = LARGESIZE;
+
+ p->type = P_SMOKE;
+
+ VectorCopy( origin, p->org );
+
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = -1;
+
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->color = BLOODRED;
+
+ p->alpha = 0.75;
+
+ }
+
+
+}
+
+void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
+{
+ cparticle_t *p;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + duration;
+ p->startfade = cg.time + duration/2;
+
+ p->color = EMISIVEFADE;
+ p->alpha = 0.4f;
+ p->alphavel = 0;
+
+ p->height = 0.5;
+ p->width = 0.5;
+ p->endheight = 0.5;
+ p->endwidth = 0.5;
+
+ p->pshader = cgs.media.tracerShader;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(org, p->org);
+
+ p->org[0] += (crandom() * x);
+ p->org[1] += (crandom() * y);
+
+ p->vel[0] = vel[0];
+ p->vel[1] = vel[1];
+ p->vel[2] = vel[2];
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[0] += (crandom() * 4);
+ p->vel[1] += (crandom() * 4);
+ p->vel[2] += (20 + (crandom() * 10)) * speed;
+
+ p->accel[0] = crandom () * 4;
+ p->accel[1] = crandom () * 4;
+
+}
+
+void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir)
+{
+ float length;
+ float dist;
+ float crittersize;
+ vec3_t angles, forward;
+ vec3_t point;
+ cparticle_t *p;
+ int i;
+
+ dist = 0;
+
+ VectorNegate (dir, dir);
+ length = VectorLength (dir);
+ vectoangles (dir, angles);
+ AngleVectors (angles, forward, NULL, NULL);
+
+ crittersize = LARGESIZE;
+
+ if (length)
+ dist = length / crittersize;
+
+ if (dist < 1)
+ dist = 1;
+
+ VectorCopy (origin, point);
+
+ for (i=0; i<dist; i++)
+ {
+ VectorMA (point, crittersize, forward, point);
+
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cg.time;
+ p->alpha = 5.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = cgs.media.smokePuffShader;
+
+ // RF, stay around for long enough to expand and dissipate naturally
+ if (length)
+ p->endtime = cg.time + 4500 + (crandom() * 3500);
+ else
+ p->endtime = cg.time + 750 + (crandom() * 500);
+
+ p->startfade = cg.time;
+
+ p->width = LARGESIZE;
+ p->height = LARGESIZE;
+
+ // RF, expand while falling
+ p->endheight = LARGESIZE*3.0;
+ p->endwidth = LARGESIZE*3.0;
+
+ if (!length)
+ {
+ p->width *= 0.2f;
+ p->height *= 0.2f;
+
+ p->endheight = NORMALSIZE;
+ p->endwidth = NORMALSIZE;
+ }
+
+ p->type = P_SMOKE;
+
+ VectorCopy( point, p->org );
+
+ p->vel[0] = crandom()*6;
+ p->vel[1] = crandom()*6;
+ p->vel[2] = random()*20;
+
+ // RF, add some gravity/randomness
+ p->accel[0] = crandom()*3;
+ p->accel[1] = crandom()*3;
+ p->accel[2] = -PARTICLE_GRAVITY*0.4;
+
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->alpha = 0.75;
+
+ }
+
+
+}
+
+void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = rand()%179;
+
+ p->pshader = pshader;
+
+ if (duration > 0)
+ p->endtime = cg.time + duration;
+ else
+ p->endtime = duration;
+
+ p->startfade = cg.time;
+
+ p->width = size;
+ p->height = size;
+
+ p->endheight = size;
+ p->endwidth = size;
+
+ p->type = P_SPRITE;
+
+ VectorCopy( origin, p->org );
+
+ p->rotate = qfalse;
+}
+
+
+
+
+
+// LEILEI ENHANCEMENT PARTICLE EFFECTS
+
+
+// sparks!
+// for small arms
+
+void CG_LeiSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
+{
+ cparticle_t *p;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + duration;
+ p->startfade = cg.time + duration/2;
+
+ p->color = EMISIVEFADE;
+ p->alpha = 0.8f;
+ p->alphavel = 0.8f;
+
+ p->height = 4;
+ p->width = 4;
+ p->endheight = 4;
+ p->endwidth = 4;
+
+ p->pshader = cgs.media.lspkShader1;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(org, p->org);
+
+ p->org[0] += (crandom() * x);
+ p->org[1] += (crandom() * y);
+
+ p->vel[0] = vel[0] * 75;
+ p->vel[1] = vel[1] * 75;
+ p->vel[2] = vel[2] * 75;
+
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[0] += (crandom() * speed);
+ p->vel[1] += (crandom() * speed);
+ p->vel[2] += speed + (crandom() * speed);
+
+ p->vel[0] += (crandom() * 24);
+ p->vel[1] += (crandom() * 24);
+ p->vel[2] += (20 + (crandom() * 180));
+
+ p->accel[0] = crandom()*6;
+ p->accel[1] = crandom()*6;
+ p->accel[2] = -PARTICLE_GRAVITY*7.2;
+
+}
+
+// a different sort of puff
+
+void CG_LeiPuff (vec3_t org, vec3_t vel, int duration, float x, float y, float speed, float size)
+{
+ cparticle_t *p;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + duration;
+ p->startfade = cg.time + duration/2;
+
+ p->color = EMISIVEFADE;
+ p->alpha = 0.8f;
+ p->alphavel = 0.8f;
+
+ p->height = size;
+ p->width = size;
+ p->endheight = size * 1.8;
+ p->endwidth = size * 1.8;
+
+ p->pshader = cgs.media.lspkShader1;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(org, p->org);
+
+ p->org[0] += (crandom() * x);
+ p->org[1] += (crandom() * y);
+
+ p->vel[0] = vel[0] * speed;
+ p->vel[1] = vel[1] * speed;
+ p->vel[2] = vel[2] * speed;
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[0] += (crandom() * 44);
+ p->vel[1] += (crandom() * 44);
+ p->vel[2] += (crandom() * 44);
+ p->roll = (crandom() * 256 - 128);
+
+
+ // p->vel[0] += (crandom() * 24);
+ //p->vel[1] += (crandom() * 24);
+ //p->vel[2] += (20 + (crandom() * 180)) * speed;
+
+ p->accel[0] = -2;
+ p->accel[1] = -2;
+ p->accel[2] = -2;
+
+}
+
+// a violent blast puff
+
+void CG_LeiBlast (vec3_t org, vec3_t vel, int duration, float x, float y, float speed, float size)
+{
+ cparticle_t *p;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + duration;
+ p->startfade = cg.time + duration/2;
+
+ p->color = EMISIVEFADE;
+ p->alpha = 1.0f;
+ p->alphavel = 0.72f;
+
+ p->height = size;
+ p->width = size;
+ p->endheight = size * 6;
+ p->endwidth = size * 6;
+
+ p->pshader = cgs.media.lbumShader1;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(org, p->org);
+
+ p->org[0] += (crandom() * x);
+ p->org[1] += (crandom() * y);
+
+ p->vel[0] = vel[0] * speed;
+ p->vel[1] = vel[1] * speed;
+ p->vel[2] = vel[2] * speed;
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[0] += (crandom() * 84);
+ p->vel[1] += (crandom() * 84);
+ p->vel[2] += (crandom() * 84);
+ p->roll = (crandom() * 256 - 128);
+
+
+ // p->vel[0] += (crandom() * 24);
+ //p->vel[1] += (crandom() * 24);
+ //p->vel[2] += (20 + (crandom() * 180)) * speed;
+
+ p->accel[0] = -2;
+ p->accel[1] = -2;
+ p->accel[2] = -2;
+
+}
+
+// for explosions
+
+void CG_LeiSparks2 (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
+{
+ cparticle_t *p;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + duration;
+ p->startfade = cg.time + duration/2;
+
+ p->color = EMISIVEFADE;
+ p->alpha = 0.8f;
+ p->alphavel = 0;
+
+ p->height = 9;
+ p->width = 9;
+ p->endheight = 32;
+ p->endwidth = 32;
+
+ p->pshader = cgs.media.lspkShader1;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(org, p->org);
+
+ p->org[0] += (crandom() * x);
+ p->org[1] += (crandom() * y);
+
+ p->vel[0] = vel[0] * 15;
+ p->vel[1] = vel[1] * 15;
+ p->vel[2] = vel[2] * 15;
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[0] += (crandom() * 524);
+ p->vel[1] += (crandom() * 524);
+ p->vel[2] += (120 + (crandom() * 780)) * speed;
+
+ // p->accel[0] = crandom()*76;
+ // p->accel[1] = crandom()*76;
+ // p->accel[2] = crandom()*76;
+
+
+// VectorCopy( origin, p->org );
+// VectorCopy( vel, p->vel );
+// VectorClear( p->accel );
+
+
+
+}
+
+// not so friendly water splash
+void CG_LeiSplash2 (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
+{
+ cparticle_t *p;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + duration;
+ p->startfade = cg.time + duration/2;
+
+ p->color = EMISIVEFADE;
+ p->alpha = 0.9f;
+ p->alphavel = 0;
+
+ p->height = 4;
+ p->width = 4;
+ p->endheight = 2;
+ p->endwidth = 2;
+
+ p->pshader = cgs.media.lsplShader;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(org, p->org);
+
+ p->org[0] += (crandom() * x);
+ p->org[1] += (crandom() * y);
+
+ p->vel[0] = vel[0] * 44;
+ p->vel[1] = vel[1] * 44;
+ p->vel[2] = vel[2] * 872;
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[0] += (crandom() * 4);
+ p->vel[1] += (crandom() * 4);
+ p->vel[2] += (20 + (crandom() * 10)) * speed;
+
+ p->accel[0] = crandom()*3;
+ p->accel[1] = crandom()*3;
+ p->accel[2] = -PARTICLE_GRAVITY*4.2;
+
+}
+
diff --git a/game/code/cgame/cg_newdraw.c b/code/cgame/cg_newdraw.c
similarity index 100%
rename from game/code/cgame/cg_newdraw.c
rename to code/cgame/cg_newdraw.c
diff --git a/game/code/cgame/cg_particles.c b/code/cgame/cg_particles.c
similarity index 100%
rename from game/code/cgame/cg_particles.c
rename to code/cgame/cg_particles.c
diff --git a/code/cgame/cg_players.c b/code/cgame/cg_players.c
new file mode 100644
index 0000000..e2b44d9
--- /dev/null
+++ b/code/cgame/cg_players.c
@@ -0,0 +1,2624 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_players.c -- handle the media and animation for player entities
+#include "cg_local.h"
+
+char *cg_customSoundNames[MAX_CUSTOM_SOUNDS] = {
+ "*death1.wav",
+ "*death2.wav",
+ "*death3.wav",
+ "*jump1.wav",
+ "*pain25_1.wav",
+ "*pain50_1.wav",
+ "*pain75_1.wav",
+ "*pain100_1.wav",
+ "*falling1.wav",
+ "*gasp.wav",
+ "*drown.wav",
+ "*fall1.wav",
+ "*taunt.wav"
+};
+
+
+/*
+================
+CG_CustomSound
+
+================
+*/
+sfxHandle_t CG_CustomSound( int clientNum, const char *soundName ) {
+ clientInfo_t *ci;
+ int i;
+
+ if ( soundName[0] != '*' ) {
+ return trap_S_RegisterSound( soundName, qfalse );
+ }
+
+ if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
+ clientNum = 0;
+ }
+ ci = &cgs.clientinfo[ clientNum ];
+
+ for ( i = 0 ; i < MAX_CUSTOM_SOUNDS && cg_customSoundNames[i] ; i++ ) {
+ if ( !strcmp( soundName, cg_customSoundNames[i] ) ) {
+ return ci->sounds[i];
+ }
+ }
+
+ CG_Error( "Unknown custom sound: %s", soundName );
+ return 0;
+}
+
+
+
+/*
+=============================================================================
+
+CLIENT INFO
+
+=============================================================================
+*/
+
+/*
+======================
+CG_ParseAnimationFile
+
+Read a configuration file containing animation coutns and rates
+models/players/visor/animation.cfg, etc
+======================
+*/
+static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) {
+ char *text_p, *prev;
+ int len;
+ int i;
+ char *token;
+ float fps;
+ int skip;
+ char text[20000];
+ fileHandle_t f;
+ animation_t *animations;
+
+ animations = ci->animations;
+
+ // load the file
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( len <= 0 ) {
+ return qfalse;
+ }
+ if ( len >= sizeof( text ) - 1 ) {
+ CG_Printf( "File %s too long\n", filename );
+ trap_FS_FCloseFile( f );
+ return qfalse;
+ }
+ trap_FS_Read( text, len, f );
+ text[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ // parse the text
+ text_p = text;
+ skip = 0; // quite the compiler warning
+
+ ci->footsteps = FOOTSTEP_NORMAL;
+ VectorClear( ci->headOffset );
+ ci->gender = GENDER_MALE;
+ ci->fixedlegs = qfalse;
+ ci->fixedtorso = qfalse;
+
+ // read optional parameters
+ while ( 1 ) {
+ prev = text_p; // so we can unget
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ if ( !Q_stricmp( token, "footsteps" ) ) {
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ if ( !Q_stricmp( token, "default" ) || !Q_stricmp( token, "normal" ) ) {
+ ci->footsteps = FOOTSTEP_NORMAL;
+ } else if ( !Q_stricmp( token, "boot" ) ) {
+ ci->footsteps = FOOTSTEP_BOOT;
+ } else if ( !Q_stricmp( token, "flesh" ) ) {
+ ci->footsteps = FOOTSTEP_FLESH;
+ } else if ( !Q_stricmp( token, "mech" ) ) {
+ ci->footsteps = FOOTSTEP_MECH;
+ } else if ( !Q_stricmp( token, "energy" ) ) {
+ ci->footsteps = FOOTSTEP_ENERGY;
+ } else {
+ CG_Printf( "Bad footsteps parm in %s: %s\n", filename, token );
+ }
+ continue;
+ } else if ( !Q_stricmp( token, "headoffset" ) ) {
+ for ( i = 0 ; i < 3 ; i++ ) {
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ ci->headOffset[i] = atof( token );
+ }
+ continue;
+ } else if ( !Q_stricmp( token, "sex" ) ) {
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ if ( token[0] == 'f' || token[0] == 'F' ) {
+ ci->gender = GENDER_FEMALE;
+ } else if ( token[0] == 'n' || token[0] == 'N' ) {
+ ci->gender = GENDER_NEUTER;
+ } else {
+ ci->gender = GENDER_MALE;
+ }
+ continue;
+ } else if ( !Q_stricmp( token, "fixedlegs" ) ) {
+ ci->fixedlegs = qtrue;
+ continue;
+ } else if ( !Q_stricmp( token, "fixedtorso" ) ) {
+ ci->fixedtorso = qtrue;
+ continue;
+ }
+
+ // if it is a number, start parsing animations
+ if ( token[0] >= '0' && token[0] <= '9' ) {
+ text_p = prev; // unget the token
+ break;
+ }
+ Com_Printf( "unknown token '%s' is %s\n", token, filename );
+ }
+
+ // read information for each frame
+ for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
+
+ token = COM_Parse( &text_p );
+ if ( !*token ) {
+ if( i >= TORSO_GETFLAG && i <= TORSO_NEGATIVE ) {
+ animations[i].firstFrame = animations[TORSO_GESTURE].firstFrame;
+ animations[i].frameLerp = animations[TORSO_GESTURE].frameLerp;
+ animations[i].initialLerp = animations[TORSO_GESTURE].initialLerp;
+ animations[i].loopFrames = animations[TORSO_GESTURE].loopFrames;
+ animations[i].numFrames = animations[TORSO_GESTURE].numFrames;
+ animations[i].reversed = qfalse;
+ animations[i].flipflop = qfalse;
+ continue;
+ }
+ break;
+ }
+ animations[i].firstFrame = atoi( token );
+ // leg only frames are adjusted to not count the upper body only frames
+ if ( i == LEGS_WALKCR ) {
+ skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
+ }
+ if ( i >= LEGS_WALKCR && i<TORSO_GETFLAG) {
+ animations[i].firstFrame -= skip;
+ }
+
+ token = COM_Parse( &text_p );
+ if ( !*token ) {
+ break;
+ }
+ animations[i].numFrames = atoi( token );
+
+ animations[i].reversed = qfalse;
+ animations[i].flipflop = qfalse;
+ // if numFrames is negative the animation is reversed
+ if (animations[i].numFrames < 0) {
+ animations[i].numFrames = -animations[i].numFrames;
+ animations[i].reversed = qtrue;
+ }
+
+ token = COM_Parse( &text_p );
+ if ( !*token ) {
+ break;
+ }
+ animations[i].loopFrames = atoi( token );
+
+ token = COM_Parse( &text_p );
+ if ( !*token ) {
+ break;
+ }
+ fps = atof( token );
+ if ( fps == 0 ) {
+ fps = 1;
+ }
+ animations[i].frameLerp = 1000 / fps;
+ animations[i].initialLerp = 1000 / fps;
+ }
+
+ if ( i != MAX_ANIMATIONS ) {
+ CG_Printf( "Error parsing animation file: %s\n", filename );
+ return qfalse;
+ }
+
+ // crouch backward animation
+ memcpy(&animations[LEGS_BACKCR], &animations[LEGS_WALKCR], sizeof(animation_t));
+ animations[LEGS_BACKCR].reversed = qtrue;
+ // walk backward animation
+ memcpy(&animations[LEGS_BACKWALK], &animations[LEGS_WALK], sizeof(animation_t));
+ animations[LEGS_BACKWALK].reversed = qtrue;
+ // flag moving fast
+ animations[FLAG_RUN].firstFrame = 0;
+ animations[FLAG_RUN].numFrames = 16;
+ animations[FLAG_RUN].loopFrames = 16;
+ animations[FLAG_RUN].frameLerp = 1000 / 15;
+ animations[FLAG_RUN].initialLerp = 1000 / 15;
+ animations[FLAG_RUN].reversed = qfalse;
+ // flag not moving or moving slowly
+ animations[FLAG_STAND].firstFrame = 16;
+ animations[FLAG_STAND].numFrames = 5;
+ animations[FLAG_STAND].loopFrames = 0;
+ animations[FLAG_STAND].frameLerp = 1000 / 20;
+ animations[FLAG_STAND].initialLerp = 1000 / 20;
+ animations[FLAG_STAND].reversed = qfalse;
+ // flag speeding up
+ animations[FLAG_STAND2RUN].firstFrame = 16;
+ animations[FLAG_STAND2RUN].numFrames = 5;
+ animations[FLAG_STAND2RUN].loopFrames = 1;
+ animations[FLAG_STAND2RUN].frameLerp = 1000 / 15;
+ animations[FLAG_STAND2RUN].initialLerp = 1000 / 15;
+ animations[FLAG_STAND2RUN].reversed = qtrue;
+ //
+ // new anims changes
+ //
+ animations[TORSO_GETFLAG].flipflop = qtrue;
+ animations[TORSO_GUARDBASE].flipflop = qtrue;
+ animations[TORSO_PATROL].flipflop = qtrue;
+ animations[TORSO_AFFIRMATIVE].flipflop = qtrue;
+ animations[TORSO_NEGATIVE].flipflop = qtrue;
+ //
+ return qtrue;
+}
+
+/*
+==========================
+CG_FileExists
+==========================
+*/
+static qboolean CG_FileExists(const char *filename) {
+ int len;
+
+ len = trap_FS_FOpenFile( filename, NULL, FS_READ );
+ if (len>0) {
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==========================
+CG_FindClientModelFile
+==========================
+*/
+static qboolean CG_FindClientModelFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *base, const char *ext ) {
+ char *team, *charactersFolder;
+ int i;
+
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ switch ( ci->team ) {
+ case TEAM_BLUE: {
+ team = "blue";
+ break;
+ }
+ default: {
+ team = "red";
+ break;
+ }
+ }
+ }
+ else {
+ team = "default";
+ }
+ charactersFolder = "";
+ while(1) {
+ for ( i = 0; i < 2; i++ ) {
+ if ( i == 0 && teamName && *teamName ) {
+ // "models/players/characters/sergei/stroggs/lower_lily_red.skin"
+ Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, team, ext );
+ }
+ else {
+ // "models/players/characters/sergei/lower_lily_red.skin"
+ Com_sprintf( filename, length, "models/players/%s%s/%s_%s_%s.%s", charactersFolder, modelName, base, skinName, team, ext );
+ }
+ if ( CG_FileExists( filename ) ) {
+ return qtrue;
+ }
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ if ( i == 0 && teamName && *teamName ) {
+ // "models/players/characters/sergei/stroggs/lower_red.skin"
+ Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, team, ext );
+ }
+ else {
+ // "models/players/characters/sergei/lower_red.skin"
+ Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, team, ext );
+ }
+ }
+ else {
+ if ( i == 0 && teamName && *teamName ) {
+ // "models/players/characters/sergei/stroggs/lower_lily.skin"
+ Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, ext );
+ }
+ else {
+ // "models/players/characters/sergei/lower_lily.skin"
+ Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, skinName, ext );
+ }
+ }
+ if ( CG_FileExists( filename ) ) {
+ return qtrue;
+ }
+ if ( !teamName || !*teamName ) {
+ break;
+ }
+ }
+ // if tried the heads folder first
+ if ( charactersFolder[0] ) {
+ break;
+ }
+ charactersFolder = "characters/";
+ }
+
+ return qfalse;
+}
+
+/*
+==========================
+CG_FindClientHeadFile
+==========================
+*/
+static qboolean CG_FindClientHeadFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) {
+ char *team, *headsFolder;
+ int i;
+
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ switch ( ci->team ) {
+ case TEAM_BLUE: {
+ team = "blue";
+ break;
+ }
+ default: {
+ team = "red";
+ break;
+ }
+ }
+ }
+ else {
+ team = "default";
+ }
+
+ if ( headModelName[0] == '*' ) {
+ headsFolder = "heads/";
+ headModelName++;
+ }
+ else {
+ headsFolder = "";
+ }
+ while(1) {
+ for ( i = 0; i < 2; i++ ) {
+ if ( i == 0 && teamName && *teamName ) {
+ Com_sprintf( filename, length, "models/players/%s%s/%s/%s%s_%s.%s", headsFolder, headModelName, headSkinName, teamName, base, team, ext );
+ }
+ else {
+ Com_sprintf( filename, length, "models/players/%s%s/%s/%s_%s.%s", headsFolder, headModelName, headSkinName, base, team, ext );
+ }
+ if ( CG_FileExists( filename ) ) {
+ return qtrue;
+ }
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ if ( i == 0 && teamName && *teamName ) {
+ Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, team, ext );
+ }
+ else {
+ Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, team, ext );
+ }
+ }
+ else {
+ if ( i == 0 && teamName && *teamName ) {
+ Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, headSkinName, ext );
+ }
+ else {
+ Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, headSkinName, ext );
+ }
+ }
+ if ( CG_FileExists( filename ) ) {
+ return qtrue;
+ }
+ if ( !teamName || !*teamName ) {
+ break;
+ }
+ }
+ // if tried the heads folder first
+ if ( headsFolder[0] ) {
+ break;
+ }
+ headsFolder = "heads/";
+ }
+
+ return qfalse;
+}
+
+/*
+==========================
+CG_RegisterClientSkin
+==========================
+*/
+static qboolean CG_RegisterClientSkin( clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName ) {
+ char filename[MAX_QPATH];
+
+ /*
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/%slower_%s.skin", modelName, teamName, skinName );
+ ci->legsSkin = trap_R_RegisterSkin( filename );
+ if (!ci->legsSkin) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%slower_%s.skin", modelName, teamName, skinName );
+ ci->legsSkin = trap_R_RegisterSkin( filename );
+ if (!ci->legsSkin) {
+ Com_Printf( "Leg skin load failure: %s\n", filename );
+ }
+ }
+
+
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/%supper_%s.skin", modelName, teamName, skinName );
+ ci->torsoSkin = trap_R_RegisterSkin( filename );
+ if (!ci->torsoSkin) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%supper_%s.skin", modelName, teamName, skinName );
+ ci->torsoSkin = trap_R_RegisterSkin( filename );
+ if (!ci->torsoSkin) {
+ Com_Printf( "Torso skin load failure: %s\n", filename );
+ }
+ }
+ */
+ if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "lower", "skin" ) ) {
+ ci->legsSkin = trap_R_RegisterSkin( filename );
+ }
+ if (!ci->legsSkin) {
+ Com_Printf( "Leg skin load failure: %s\n", filename );
+ }
+
+ if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "upper", "skin" ) ) {
+ ci->torsoSkin = trap_R_RegisterSkin( filename );
+ }
+ if (!ci->torsoSkin) {
+ Com_Printf( "Torso skin load failure: %s\n", filename );
+ }
+
+ if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headModelName, headSkinName, "head", "skin" ) ) {
+ ci->headSkin = trap_R_RegisterSkin( filename );
+ }
+ if (!ci->headSkin) {
+ Com_Printf( "Head skin load failure: %s\n", filename );
+ }
+
+ // if any skins failed to load
+ if ( !ci->legsSkin || !ci->torsoSkin || !ci->headSkin ) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+/*
+==========================
+CG_RegisterClientModelname
+==========================
+*/
+static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName, const char *teamName ) {
+ char filename[MAX_QPATH*2];
+ const char *headName;
+ char newTeamName[MAX_QPATH*2];
+
+ if ( headModelName[0] == '\0' ) {
+ headName = modelName;
+ }
+ else {
+ headName = headModelName;
+ }
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
+ ci->legsModel = trap_R_RegisterModel( filename );
+ if ( !ci->legsModel ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower.md3", modelName );
+ ci->legsModel = trap_R_RegisterModel( filename );
+ if ( !ci->legsModel ) {
+ Com_Printf( "Failed to load model file %s\n", filename );
+ return qfalse;
+ }
+ }
+
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
+ ci->torsoModel = trap_R_RegisterModel( filename );
+ if ( !ci->torsoModel ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper.md3", modelName );
+ ci->torsoModel = trap_R_RegisterModel( filename );
+ if ( !ci->torsoModel ) {
+ Com_Printf( "Failed to load model file %s\n", filename );
+ return qfalse;
+ }
+ }
+
+ if( headName[0] == '*' ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", &headModelName[1], &headModelName[1] );
+ }
+ else {
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headName );
+ }
+ ci->headModel = trap_R_RegisterModel( filename );
+ // if the head model could not be found and we didn't load from the heads folder try to load from there
+ if ( !ci->headModel && headName[0] != '*' ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", headModelName, headModelName );
+ ci->headModel = trap_R_RegisterModel( filename );
+ }
+ if ( !ci->headModel ) {
+ Com_Printf( "Failed to load model file %s\n", filename );
+ return qfalse;
+ }
+
+ // if any skins failed to load, return failure
+ if ( !CG_RegisterClientSkin( ci, teamName, modelName, skinName, headName, headSkinName ) ) {
+ if ( teamName && *teamName) {
+ Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", teamName, modelName, skinName, headName, headSkinName );
+ if( ci->team == TEAM_BLUE ) {
+ Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_BLUETEAM_NAME);
+ }
+ else {
+ Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_REDTEAM_NAME);
+ }
+ if ( !CG_RegisterClientSkin( ci, newTeamName, modelName, skinName, headName, headSkinName ) ) {
+ Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", newTeamName, modelName, skinName, headName, headSkinName );
+ return qfalse;
+ }
+ } else {
+ Com_Printf( "Failed to load skin file: %s : %s, %s : %s\n", modelName, skinName, headName, headSkinName );
+ return qfalse;
+ }
+ }
+
+ // load the animations
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
+ if ( !CG_ParseAnimationFile( filename, ci ) ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName );
+ if ( !CG_ParseAnimationFile( filename, ci ) ) {
+ Com_Printf( "Failed to load animation file %s\n", filename );
+ return qfalse;
+ }
+ }
+
+ if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "skin" ) ) {
+ ci->modelIcon = trap_R_RegisterShaderNoMip( filename );
+ }
+ else if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "tga" ) ) {
+ ci->modelIcon = trap_R_RegisterShaderNoMip( filename );
+ }
+
+ if ( !ci->modelIcon ) {
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+/*
+====================
+CG_ColorFromString
+====================
+*/
+static void CG_ColorFromString( const char *v, vec3_t color ) {
+ int val;
+
+ VectorClear( color );
+
+ val = atoi( v );
+
+ if ( val < 1 || val > 7 ) {
+ VectorSet( color, 1, 1, 1 );
+ return;
+ }
+
+ if ( val & 1 ) {
+ color[2] = 1.0f;
+ }
+ if ( val & 2 ) {
+ color[1] = 1.0f;
+ }
+ if ( val & 4 ) {
+ color[0] = 1.0f;
+ }
+}
+
+/*
+===================
+CG_LoadClientInfo
+
+Load it now, taking the disk hits.
+This will usually be deferred to a safe time
+===================
+*/
+static void CG_LoadClientInfo( int clientNum, clientInfo_t *ci ) {
+ const char *dir, *fallback;
+ int i, modelloaded;
+ const char *s;
+ char teamname[MAX_QPATH];
+
+ teamname[0] = 0;
+#ifdef MISSIONPACK
+ if( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ if( ci->team == TEAM_BLUE ) {
+ Q_strncpyz(teamname, cg_blueTeamName.string, sizeof(teamname) );
+ } else {
+ Q_strncpyz(teamname, cg_redTeamName.string, sizeof(teamname) );
+ }
+ }
+ if( teamname[0] ) {
+ strcat( teamname, "/" );
+ }
+#endif
+ modelloaded = qtrue;
+ if ( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname ) ) {
+ if ( cg_buildScript.integer ) {
+ CG_Error( "CG_RegisterClientModelname( %s, %s, %s, %s %s ) failed", ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname );
+ }
+
+ // fall back to default team name
+ if( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ // keep skin name
+ if( ci->team == TEAM_BLUE ) {
+ Q_strncpyz(teamname, DEFAULT_BLUETEAM_NAME, sizeof(teamname) );
+ } else {
+ Q_strncpyz(teamname, DEFAULT_REDTEAM_NAME, sizeof(teamname) );
+ }
+ if ( !CG_RegisterClientModelname( ci, DEFAULT_TEAM_MODEL, ci->skinName, DEFAULT_TEAM_HEAD, ci->skinName, teamname ) ) {
+ CG_Error( "DEFAULT_TEAM_MODEL / skin (%s/%s) failed to register", DEFAULT_TEAM_MODEL, ci->skinName );
+ }
+ } else {
+ if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default", DEFAULT_MODEL, "default", teamname ) ) {
+ CG_Error( "DEFAULT_MODEL (%s) failed to register", DEFAULT_MODEL );
+ }
+ }
+ modelloaded = qfalse;
+ }
+
+ ci->newAnims = qfalse;
+ if ( ci->torsoModel ) {
+ orientation_t tag;
+ // if the torso model has the "tag_flag"
+ if ( trap_R_LerpTag( &tag, ci->torsoModel, 0, 0, 1, "tag_flag" ) ) {
+ ci->newAnims = qtrue;
+ }
+ }
+
+ // sounds
+ dir = ci->modelName;
+ fallback = (cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) ? DEFAULT_TEAM_MODEL : DEFAULT_MODEL;
+
+ for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i++ ) {
+ s = cg_customSoundNames[i];
+ if ( !s ) {
+ break;
+ }
+ ci->sounds[i] = 0;
+ // if the model didn't load use the sounds of the default model
+ if (modelloaded) {
+ ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", dir, s + 1), qfalse );
+ }
+ if ( !ci->sounds[i] ) {
+ ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", fallback, s + 1), qfalse );
+ }
+ }
+
+ ci->deferred = qfalse;
+
+ // reset any existing players and bodies, because they might be in bad
+ // frames for this new model
+ for ( i = 0 ; i < MAX_GENTITIES ; i++ ) {
+ if ( cg_entities[i].currentState.clientNum == clientNum
+ && cg_entities[i].currentState.eType == ET_PLAYER ) {
+ CG_ResetPlayerEntity( &cg_entities[i] );
+ }
+ }
+}
+
+/*
+======================
+CG_CopyClientInfoModel
+======================
+*/
+static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to ) {
+ VectorCopy( from->headOffset, to->headOffset );
+ to->footsteps = from->footsteps;
+ to->gender = from->gender;
+
+ to->legsModel = from->legsModel;
+ to->legsSkin = from->legsSkin;
+ to->torsoModel = from->torsoModel;
+ to->torsoSkin = from->torsoSkin;
+ to->headModel = from->headModel;
+ to->headSkin = from->headSkin;
+ to->modelIcon = from->modelIcon;
+
+ to->newAnims = from->newAnims;
+
+ memcpy( to->animations, from->animations, sizeof( to->animations ) );
+ memcpy( to->sounds, from->sounds, sizeof( to->sounds ) );
+}
+
+/*
+======================
+CG_ScanForExistingClientInfo
+======================
+*/
+static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci ) {
+ int i;
+ clientInfo_t *match;
+
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ match = &cgs.clientinfo[ i ];
+ if ( !match->infoValid ) {
+ continue;
+ }
+ if ( match->deferred ) {
+ continue;
+ }
+ if ( !Q_stricmp( ci->modelName, match->modelName )
+ && !Q_stricmp( ci->skinName, match->skinName )
+ && !Q_stricmp( ci->headModelName, match->headModelName )
+ && !Q_stricmp( ci->headSkinName, match->headSkinName )
+ && !Q_stricmp( ci->blueTeam, match->blueTeam )
+ && !Q_stricmp( ci->redTeam, match->redTeam )
+ && (cgs.gametype < GT_TEAM || cgs.ffa_gt==1 || ci->team == match->team) ) {
+ // this clientinfo is identical, so use it's handles
+
+ ci->deferred = qfalse;
+
+ CG_CopyClientInfoModel( match, ci );
+
+ return qtrue;
+ }
+ }
+
+ // nothing matches, so defer the load
+ return qfalse;
+}
+
+/*
+======================
+CG_SetDeferredClientInfo
+
+We aren't going to load it now, so grab some other
+client's info to use until we have some spare time.
+======================
+*/
+static void CG_SetDeferredClientInfo( int clientNum, clientInfo_t *ci ) {
+ int i;
+ clientInfo_t *match;
+
+ // if someone else is already the same models and skins we
+ // can just load the client info
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ match = &cgs.clientinfo[ i ];
+ if ( !match->infoValid || match->deferred ) {
+ continue;
+ }
+ if ( Q_stricmp( ci->skinName, match->skinName ) ||
+ Q_stricmp( ci->modelName, match->modelName ) ||
+// Q_stricmp( ci->headModelName, match->headModelName ) ||
+// Q_stricmp( ci->headSkinName, match->headSkinName ) ||
+ (cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1 && ci->team != match->team) ) {
+ continue;
+ }
+ // just load the real info cause it uses the same models and skins
+ CG_LoadClientInfo( clientNum, ci );
+ return;
+ }
+
+ // if we are in teamplay, only grab a model if the skin is correct
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ match = &cgs.clientinfo[ i ];
+ if ( !match->infoValid || match->deferred ) {
+ continue;
+ }
+ if ( Q_stricmp( ci->skinName, match->skinName ) ||
+ (cgs.gametype >= GT_TEAM && cgs.ffa_gt != 1 && ci->team != match->team) ) {
+ continue;
+ }
+ ci->deferred = qtrue;
+ CG_CopyClientInfoModel( match, ci );
+ return;
+ }
+ // load the full model, because we don't ever want to show
+ // an improper team skin. This will cause a hitch for the first
+ // player, when the second enters. Combat shouldn't be going on
+ // yet, so it shouldn't matter
+ CG_LoadClientInfo( clientNum, ci );
+ return;
+ }
+
+ // find the first valid clientinfo and grab its stuff
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ match = &cgs.clientinfo[ i ];
+ if ( !match->infoValid ) {
+ continue;
+ }
+
+ ci->deferred = qtrue;
+ CG_CopyClientInfoModel( match, ci );
+ return;
+ }
+
+ // we should never get here...
+ CG_Printf( "CG_SetDeferredClientInfo: no valid clients!\n" );
+
+ CG_LoadClientInfo( clientNum, ci );
+}
+
+
+/*
+======================
+CG_NewClientInfo
+======================
+*/
+void CG_NewClientInfo( int clientNum ) {
+ clientInfo_t *ci;
+ clientInfo_t newInfo;
+ const char *configstring;
+ const char *v;
+ char *slash;
+
+ ci = &cgs.clientinfo[clientNum];
+
+ configstring = CG_ConfigString( clientNum + CS_PLAYERS );
+ if ( !configstring[0] ) {
+ memset( ci, 0, sizeof( *ci ) );
+ return; // player just left
+ }
+
+ // build into a temp buffer so the defer checks can use
+ // the old value
+ memset( &newInfo, 0, sizeof( newInfo ) );
+
+ // isolate the player's name
+ v = Info_ValueForKey(configstring, "n");
+ Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) );
+
+ // colors
+ v = Info_ValueForKey( configstring, "c1" );
+ CG_ColorFromString( v, newInfo.color1 );
+
+ v = Info_ValueForKey( configstring, "c2" );
+ CG_ColorFromString( v, newInfo.color2 );
+
+ // bot skill
+ v = Info_ValueForKey( configstring, "skill" );
+ newInfo.botSkill = atoi( v );
+
+ // handicap
+ v = Info_ValueForKey( configstring, "hc" );
+ newInfo.handicap = atoi( v );
+
+ // wins
+ v = Info_ValueForKey( configstring, "w" );
+ newInfo.wins = atoi( v );
+
+ // losses
+ v = Info_ValueForKey( configstring, "l" );
+ newInfo.losses = atoi( v );
+
+ // team
+ v = Info_ValueForKey( configstring, "t" );
+ newInfo.team = atoi( v );
+
+ // team task
+ v = Info_ValueForKey( configstring, "tt" );
+ newInfo.teamTask = atoi(v);
+
+ // team leader
+ v = Info_ValueForKey( configstring, "tl" );
+ newInfo.teamLeader = atoi(v);
+
+ v = Info_ValueForKey( configstring, "g_redteam" );
+ Q_strncpyz(newInfo.redTeam, v, MAX_TEAMNAME);
+
+ v = Info_ValueForKey( configstring, "g_blueteam" );
+ Q_strncpyz(newInfo.blueTeam, v, MAX_TEAMNAME);
+
+ // model
+ v = Info_ValueForKey( configstring, "model" );
+ if ( cg_forceModel.integer ) {
+ // forcemodel makes everyone use a single model
+ // to prevent load hitches
+ char modelStr[MAX_QPATH];
+ char *skin;
+
+ if( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ Q_strncpyz( newInfo.modelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.modelName ) );
+ Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
+ } else {
+ trap_Cvar_VariableStringBuffer( "model", modelStr, sizeof( modelStr ) );
+ if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
+ skin = "default";
+ } else {
+ *skin++ = 0;
+ }
+
+ Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) );
+ Q_strncpyz( newInfo.modelName, modelStr, sizeof( newInfo.modelName ) );
+ }
+
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1 ) {
+ // keep skin name
+ slash = strchr( v, '/' );
+ if ( slash ) {
+ Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
+ }
+ }
+ } else {
+ Q_strncpyz( newInfo.modelName, v, sizeof( newInfo.modelName ) );
+
+ slash = strchr( newInfo.modelName, '/' );
+ if ( !slash ) {
+ // modelName didn not include a skin name
+ Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
+ } else {
+ Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
+ // truncate modelName
+ *slash = 0;
+ }
+ }
+
+ // head model
+ v = Info_ValueForKey( configstring, "hmodel" );
+ if ( cg_forceModel.integer ) {
+ // forcemodel makes everyone use a single model
+ // to prevent load hitches
+ char modelStr[MAX_QPATH];
+ char *skin;
+
+ if( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ Q_strncpyz( newInfo.headModelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.headModelName ) );
+ Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) );
+ } else {
+ trap_Cvar_VariableStringBuffer( "headmodel", modelStr, sizeof( modelStr ) );
+ if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
+ skin = "default";
+ } else {
+ *skin++ = 0;
+ }
+
+ Q_strncpyz( newInfo.headSkinName, skin, sizeof( newInfo.headSkinName ) );
+ Q_strncpyz( newInfo.headModelName, modelStr, sizeof( newInfo.headModelName ) );
+ }
+
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ // keep skin name
+ slash = strchr( v, '/' );
+ if ( slash ) {
+ Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) );
+ }
+ }
+ } else {
+ Q_strncpyz( newInfo.headModelName, v, sizeof( newInfo.headModelName ) );
+
+ slash = strchr( newInfo.headModelName, '/' );
+ if ( !slash ) {
+ // modelName didn not include a skin name
+ Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) );
+ } else {
+ Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) );
+ // truncate modelName
+ *slash = 0;
+ }
+ }
+
+ // scan for an existing clientinfo that matches this modelname
+ // so we can avoid loading checks if possible
+ if ( !CG_ScanForExistingClientInfo( &newInfo ) ) {
+ qboolean forceDefer;
+
+ forceDefer = trap_MemoryRemaining() < 4000000;
+
+ // if we are defering loads, just have it pick the first valid
+ if ( forceDefer || (cg_deferPlayers.integer && !cg_buildScript.integer && !cg.loading ) ) {
+ // keep whatever they had if it won't violate team skins
+ CG_SetDeferredClientInfo( clientNum, &newInfo );
+ // if we are low on memory, leave them with this model
+ if ( forceDefer ) {
+ CG_Printf( "Memory is low. Using deferred model.\n" );
+ newInfo.deferred = qfalse;
+ }
+ } else {
+ CG_LoadClientInfo( clientNum, &newInfo );
+ }
+ }
+
+ // replace whatever was there with the new one
+ newInfo.infoValid = qtrue;
+ *ci = newInfo;
+}
+
+
+
+/*
+======================
+CG_LoadDeferredPlayers
+
+Called each frame when a player is dead
+and the scoreboard is up
+so deferred players can be loaded
+======================
+*/
+void CG_LoadDeferredPlayers( void ) {
+ int i;
+ clientInfo_t *ci;
+
+ // scan for a deferred player to load
+ for ( i = 0, ci = cgs.clientinfo ; i < cgs.maxclients ; i++, ci++ ) {
+ if ( ci->infoValid && ci->deferred ) {
+ // if we are low on memory, leave it deferred
+ if ( trap_MemoryRemaining() < 4000000 ) {
+ CG_Printf( "Memory is low. Using deferred model.\n" );
+ ci->deferred = qfalse;
+ continue;
+ }
+ CG_LoadClientInfo( i, ci );
+// break;
+ }
+ }
+}
+
+/*
+=============================================================================
+
+PLAYER ANIMATION
+
+=============================================================================
+*/
+
+
+/*
+===============
+CG_SetLerpFrameAnimation
+
+may include ANIM_TOGGLEBIT
+===============
+*/
+static void CG_SetLerpFrameAnimation( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
+ animation_t *anim;
+
+ lf->animationNumber = newAnimation;
+ newAnimation &= ~ANIM_TOGGLEBIT;
+
+ if ( newAnimation < 0 || newAnimation >= MAX_TOTALANIMATIONS ) {
+ CG_Error( "Bad animation number: %i", newAnimation );
+ }
+
+ anim = &ci->animations[ newAnimation ];
+
+ lf->animation = anim;
+ lf->animationTime = lf->frameTime + anim->initialLerp;
+
+ if ( cg_debugAnim.integer ) {
+ CG_Printf( "Anim: %i\n", newAnimation );
+ }
+}
+
+/*
+===============
+CG_RunLerpFrame
+
+Sets cg.snap, cg.oldFrame, and cg.backlerp
+cg.time should be between oldFrameTime and frameTime after exit
+===============
+*/
+static void CG_RunLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation, float speedScale ) {
+ int f, numFrames;
+ animation_t *anim;
+
+ // debugging tool to get no animations
+ if ( cg_animSpeed.integer == 0 ) {
+ lf->oldFrame = lf->frame = lf->backlerp = 0;
+ return;
+ }
+
+ // see if the animation sequence is switching
+ if ( newAnimation != lf->animationNumber || !lf->animation ) {
+ CG_SetLerpFrameAnimation( ci, lf, newAnimation );
+ }
+
+ // if we have passed the current frame, move it to
+ // oldFrame and calculate a new frame
+ if ( cg.time >= lf->frameTime ) {
+ lf->oldFrame = lf->frame;
+ lf->oldFrameTime = lf->frameTime;
+
+ // get the next frame based on the animation
+ anim = lf->animation;
+ if ( !anim->frameLerp ) {
+ return; // shouldn't happen
+ }
+ if ( cg.time < lf->animationTime ) {
+ lf->frameTime = lf->animationTime; // initial lerp
+ } else {
+ lf->frameTime = lf->oldFrameTime + anim->frameLerp;
+ }
+ f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
+ f *= speedScale; // adjust for haste, etc
+
+ numFrames = anim->numFrames;
+ if (anim->flipflop) {
+ numFrames *= 2;
+ }
+ if ( f >= numFrames ) {
+ f -= numFrames;
+ if ( anim->loopFrames ) {
+ f %= anim->loopFrames;
+ f += anim->numFrames - anim->loopFrames;
+ } else {
+ f = numFrames - 1;
+ // the animation is stuck at the end, so it
+ // can immediately transition to another sequence
+ lf->frameTime = cg.time;
+ }
+ }
+ if ( anim->reversed ) {
+ lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
+ }
+ else if (anim->flipflop && f>=anim->numFrames) {
+ lf->frame = anim->firstFrame + anim->numFrames - 1 - (f%anim->numFrames);
+ }
+ else {
+ lf->frame = anim->firstFrame + f;
+ }
+ if ( cg.time > lf->frameTime ) {
+ lf->frameTime = cg.time;
+ if ( cg_debugAnim.integer ) {
+ CG_Printf( "Clamp lf->frameTime\n");
+ }
+ }
+ }
+
+ if ( lf->frameTime > cg.time + 200 ) {
+ lf->frameTime = cg.time;
+ }
+
+ if ( lf->oldFrameTime > cg.time ) {
+ lf->oldFrameTime = cg.time;
+ }
+ // calculate current lerp value
+ if ( lf->frameTime == lf->oldFrameTime ) {
+ lf->backlerp = 0;
+ } else {
+ lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
+ }
+}
+
+
+/*
+===============
+CG_ClearLerpFrame
+===============
+*/
+static void CG_ClearLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int animationNumber ) {
+ lf->frameTime = lf->oldFrameTime = cg.time;
+ CG_SetLerpFrameAnimation( ci, lf, animationNumber );
+ lf->oldFrame = lf->frame = lf->animation->firstFrame;
+}
+
+
+/*
+===============
+CG_PlayerAnimation
+===============
+*/
+static void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float *legsBackLerp,
+ int *torsoOld, int *torso, float *torsoBackLerp ) {
+ clientInfo_t *ci;
+ int clientNum;
+ float speedScale;
+
+ clientNum = cent->currentState.clientNum;
+
+ if ( cg_noPlayerAnims.integer ) {
+ *legsOld = *legs = *torsoOld = *torso = 0;
+ return;
+ }
+
+ if ( cent->currentState.powerups & ( 1 << PW_HASTE ) ) {
+ speedScale = 1.5;
+ } else {
+ speedScale = 1;
+ }
+
+ ci = &cgs.clientinfo[ clientNum ];
+
+ // do the shuffle turn frames locally
+ if ( cent->pe.legs.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {
+ CG_RunLerpFrame( ci, ¢->pe.legs, LEGS_TURN, speedScale );
+ } else {
+ CG_RunLerpFrame( ci, ¢->pe.legs, cent->currentState.legsAnim, speedScale );
+ }
+
+ *legsOld = cent->pe.legs.oldFrame;
+ *legs = cent->pe.legs.frame;
+ *legsBackLerp = cent->pe.legs.backlerp;
+
+ CG_RunLerpFrame( ci, ¢->pe.torso, cent->currentState.torsoAnim, speedScale );
+
+ *torsoOld = cent->pe.torso.oldFrame;
+ *torso = cent->pe.torso.frame;
+ *torsoBackLerp = cent->pe.torso.backlerp;
+}
+
+/*
+=============================================================================
+
+PLAYER ANGLES
+
+=============================================================================
+*/
+
+/*
+==================
+CG_SwingAngles
+==================
+*/
+static void CG_SwingAngles( float destination, float swingTolerance, float clampTolerance,
+ float speed, float *angle, qboolean *swinging ) {
+ float swing;
+ float move;
+ float scale;
+
+ if ( !*swinging ) {
+ // see if a swing should be started
+ swing = AngleSubtract( *angle, destination );
+ if ( swing > swingTolerance || swing < -swingTolerance ) {
+ *swinging = qtrue;
+ }
+ }
+
+ if ( !*swinging ) {
+ return;
+ }
+
+ // modify the speed depending on the delta
+ // so it doesn't seem so linear
+ swing = AngleSubtract( destination, *angle );
+ scale = fabs( swing );
+ if ( scale < swingTolerance * 0.5 ) {
+ scale = 0.5;
+ } else if ( scale < swingTolerance ) {
+ scale = 1.0;
+ } else {
+ scale = 2.0;
+ }
+
+ // swing towards the destination angle
+ if ( swing >= 0 ) {
+ move = cg.frametime * scale * speed;
+ if ( move >= swing ) {
+ move = swing;
+ *swinging = qfalse;
+ }
+ *angle = AngleMod( *angle + move );
+ } else if ( swing < 0 ) {
+ move = cg.frametime * scale * -speed;
+ if ( move <= swing ) {
+ move = swing;
+ *swinging = qfalse;
+ }
+ *angle = AngleMod( *angle + move );
+ }
+
+ // clamp to no more than tolerance
+ swing = AngleSubtract( destination, *angle );
+ if ( swing > clampTolerance ) {
+ *angle = AngleMod( destination - (clampTolerance - 1) );
+ } else if ( swing < -clampTolerance ) {
+ *angle = AngleMod( destination + (clampTolerance - 1) );
+ }
+}
+
+/*
+=================
+CG_AddPainTwitch
+=================
+*/
+static void CG_AddPainTwitch( centity_t *cent, vec3_t torsoAngles ) {
+ int t;
+ float f;
+
+ t = cg.time - cent->pe.painTime;
+ if ( t >= PAIN_TWITCH_TIME ) {
+ return;
+ }
+
+ f = 1.0 - (float)t / PAIN_TWITCH_TIME;
+
+ if ( cent->pe.painDirection ) {
+ torsoAngles[ROLL] += 20 * f;
+ } else {
+ torsoAngles[ROLL] -= 20 * f;
+ }
+}
+
+
+/*
+===============
+CG_PlayerAngles
+
+Handles seperate torso motion
+
+ legs pivot based on direction of movement
+
+ head always looks exactly at cent->lerpAngles
+
+ if motion < 20 degrees, show in head only
+ if < 45 degrees, also show in torso
+===============
+*/
+static void CG_PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {
+ vec3_t legsAngles, torsoAngles, headAngles;
+ float dest;
+ static int movementOffsets[8] = { 0, 22, 45, -22, 0, 22, -45, -22 };
+ vec3_t velocity;
+ float speed;
+ int dir, clientNum;
+ clientInfo_t *ci;
+
+ VectorCopy( cent->lerpAngles, headAngles );
+ headAngles[YAW] = AngleMod( headAngles[YAW] );
+ VectorClear( legsAngles );
+ VectorClear( torsoAngles );
+
+ // --------- yaw -------------
+
+ // allow yaw to drift a bit
+ if ( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE
+ || ((cent->currentState.torsoAnim & ~ANIM_TOGGLEBIT) != TORSO_STAND
+ && (cent->currentState.torsoAnim & ~ANIM_TOGGLEBIT) != TORSO_STAND2)) {
+ // if not standing still, always point all in the same direction
+ cent->pe.torso.yawing = qtrue; // always center
+ cent->pe.torso.pitching = qtrue; // always center
+ cent->pe.legs.yawing = qtrue; // always center
+ }
+
+ // adjust legs for movement dir
+ if ( cent->currentState.eFlags & EF_DEAD ) {
+ // don't let dead bodies twitch
+ dir = 0;
+ } else {
+ dir = cent->currentState.angles2[YAW];
+ if ( dir < 0 || dir > 7 ) {
+ CG_Error( "Bad player movement angle" );
+ }
+ }
+ legsAngles[YAW] = headAngles[YAW] + movementOffsets[ dir ];
+ torsoAngles[YAW] = headAngles[YAW] + 0.25 * movementOffsets[ dir ];
+
+ // torso
+ CG_SwingAngles( torsoAngles[YAW], 25, 90, cg_swingSpeed.value, ¢->pe.torso.yawAngle, ¢->pe.torso.yawing );
+ CG_SwingAngles( legsAngles[YAW], 40, 90, cg_swingSpeed.value, ¢->pe.legs.yawAngle, ¢->pe.legs.yawing );
+
+ torsoAngles[YAW] = cent->pe.torso.yawAngle;
+ legsAngles[YAW] = cent->pe.legs.yawAngle;
+
+
+ // --------- pitch -------------
+
+ // only show a fraction of the pitch angle in the torso
+ if ( headAngles[PITCH] > 180 ) {
+ dest = (-360 + headAngles[PITCH]) * 0.75f;
+ } else {
+ dest = headAngles[PITCH] * 0.75f;
+ }
+ CG_SwingAngles( dest, 15, 30, 0.1f, ¢->pe.torso.pitchAngle, ¢->pe.torso.pitching );
+ torsoAngles[PITCH] = cent->pe.torso.pitchAngle;
+
+ //
+ clientNum = cent->currentState.clientNum;
+ if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
+ ci = &cgs.clientinfo[ clientNum ];
+ if ( ci->fixedtorso ) {
+ torsoAngles[PITCH] = 0.0f;
+ }
+ }
+
+ // --------- roll -------------
+
+
+ // lean towards the direction of travel
+ VectorCopy( cent->currentState.pos.trDelta, velocity );
+ speed = VectorNormalize( velocity );
+ if ( speed ) {
+ vec3_t axis[3];
+ float side;
+
+ speed *= 0.05f;
+
+ AnglesToAxis( legsAngles, axis );
+ side = speed * DotProduct( velocity, axis[1] );
+ legsAngles[ROLL] -= side;
+
+ side = speed * DotProduct( velocity, axis[0] );
+ legsAngles[PITCH] += side;
+ }
+
+ //
+ clientNum = cent->currentState.clientNum;
+ if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
+ ci = &cgs.clientinfo[ clientNum ];
+ if ( ci->fixedlegs ) {
+ legsAngles[YAW] = torsoAngles[YAW];
+ legsAngles[PITCH] = 0.0f;
+ legsAngles[ROLL] = 0.0f;
+ }
+ }
+
+ // pain twitch
+ CG_AddPainTwitch( cent, torsoAngles );
+
+ // pull the angles back out of the hierarchial chain
+ AnglesSubtract( headAngles, torsoAngles, headAngles );
+ AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
+ AnglesToAxis( legsAngles, legs );
+ AnglesToAxis( torsoAngles, torso );
+ AnglesToAxis( headAngles, head );
+}
+
+
+//==========================================================================
+
+/*
+===============
+CG_HasteTrail
+===============
+*/
+static void CG_HasteTrail( centity_t *cent ) {
+ localEntity_t *smoke;
+ vec3_t origin;
+ int anim;
+
+ if ( cent->trailTime > cg.time ) {
+ return;
+ }
+ anim = cent->pe.legs.animationNumber & ~ANIM_TOGGLEBIT;
+ if ( anim != LEGS_RUN && anim != LEGS_BACK ) {
+ return;
+ }
+
+ cent->trailTime += 100;
+ if ( cent->trailTime < cg.time ) {
+ cent->trailTime = cg.time;
+ }
+
+ VectorCopy( cent->lerpOrigin, origin );
+ origin[2] -= 16;
+
+ smoke = CG_SmokePuff( origin, vec3_origin,
+ 8,
+ 1, 1, 1, 1,
+ 500,
+ cg.time,
+ 0,
+ 0,
+ cgs.media.hastePuffShader );
+
+ // use the optimized local entity add
+ smoke->leType = LE_SCALE_FADE;
+}
+
+/*
+===============
+CG_BreathPuffs
+===============
+*/
+static void CG_BreathPuffs( centity_t *cent, refEntity_t *head) {
+ clientInfo_t *ci;
+ vec3_t up, origin;
+ int contents;
+
+ ci = &cgs.clientinfo[ cent->currentState.number ];
+
+ if (!cg_enableBreath.integer) {
+ return;
+ }
+ if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson) {
+ return;
+ }
+ if ( cent->currentState.eFlags & EF_DEAD ) {
+ return;
+ }
+ contents = CG_PointContents( head->origin, 0 );
+ if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
+ return;
+ }
+ if ( ci->breathPuffTime > cg.time ) {
+ return;
+ }
+
+ VectorSet( up, 0, 0, 8 );
+ VectorMA(head->origin, 8, head->axis[0], origin);
+ VectorMA(origin, -4, head->axis[2], origin);
+ CG_SmokePuff( origin, up, 16, 1, 1, 1, 0.66f, 1500, cg.time, cg.time + 400, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
+ ci->breathPuffTime = cg.time + 2000;
+}
+
+/*
+===============
+CG_DustTrail
+===============
+*/
+static void CG_DustTrail( centity_t *cent ) {
+ int anim;
+ localEntity_t *dust;
+ vec3_t end, vel;
+ trace_t tr;
+
+ if (!cg_enableDust.integer)
+ return;
+
+ if ( cent->dustTrailTime > cg.time ) {
+ return;
+ }
+
+ anim = cent->pe.legs.animationNumber & ~ANIM_TOGGLEBIT;
+ if ( anim != LEGS_LANDB && anim != LEGS_LAND ) {
+ return;
+ }
+
+ cent->dustTrailTime += 40;
+ if ( cent->dustTrailTime < cg.time ) {
+ cent->dustTrailTime = cg.time;
+ }
+
+ VectorCopy(cent->currentState.pos.trBase, end);
+ end[2] -= 64;
+ CG_Trace( &tr, cent->currentState.pos.trBase, NULL, NULL, end, cent->currentState.number, MASK_PLAYERSOLID );
+
+ if ( !(tr.surfaceFlags & SURF_DUST) )
+ return;
+
+ VectorCopy( cent->currentState.pos.trBase, end );
+ end[2] -= 16;
+
+ VectorSet(vel, 0, 0, -30);
+ dust = CG_SmokePuff( end, vel,
+ 24,
+ .8f, .8f, 0.7f, 0.33f,
+ 500,
+ cg.time,
+ 0,
+ 0,
+ cgs.media.dustPuffShader );
+}
+
+/*
+===============
+CG_TrailItem
+===============
+*/
+static void CG_TrailItem( centity_t *cent, qhandle_t hModel ) {
+ refEntity_t ent;
+ vec3_t angles;
+ vec3_t axis[3];
+
+ VectorCopy( cent->lerpAngles, angles );
+ angles[PITCH] = 0;
+ angles[ROLL] = 0;
+ AnglesToAxis( angles, axis );
+
+ memset( &ent, 0, sizeof( ent ) );
+ VectorMA( cent->lerpOrigin, -16, axis[0], ent.origin );
+ ent.origin[2] += 16;
+ angles[YAW] += 90;
+ AnglesToAxis( angles, ent.axis );
+
+ ent.hModel = hModel;
+ trap_R_AddRefEntityToScene( &ent );
+}
+
+
+/*
+===============
+CG_PlayerFlag
+===============
+*/
+static void CG_PlayerFlag( centity_t *cent, qhandle_t hSkin, refEntity_t *torso ) {
+ clientInfo_t *ci;
+ refEntity_t pole;
+ refEntity_t flag;
+ vec3_t angles, dir;
+ int legsAnim, flagAnim, updateangles;
+ float angle, d;
+
+ // show the flag pole model
+ memset( &pole, 0, sizeof(pole) );
+ pole.hModel = cgs.media.flagPoleModel;
+ VectorCopy( torso->lightingOrigin, pole.lightingOrigin );
+ pole.shadowPlane = torso->shadowPlane;
+ pole.renderfx = torso->renderfx;
+ CG_PositionEntityOnTag( &pole, torso, torso->hModel, "tag_flag" );
+ trap_R_AddRefEntityToScene( &pole );
+
+ // show the flag model
+ memset( &flag, 0, sizeof(flag) );
+ flag.hModel = cgs.media.flagFlapModel;
+ flag.customSkin = hSkin;
+ VectorCopy( torso->lightingOrigin, flag.lightingOrigin );
+ flag.shadowPlane = torso->shadowPlane;
+ flag.renderfx = torso->renderfx;
+
+ VectorClear(angles);
+
+ updateangles = qfalse;
+ legsAnim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
+ if( legsAnim == LEGS_IDLE || legsAnim == LEGS_IDLECR ) {
+ flagAnim = FLAG_STAND;
+ } else if ( legsAnim == LEGS_WALK || legsAnim == LEGS_WALKCR ) {
+ flagAnim = FLAG_STAND;
+ updateangles = qtrue;
+ } else {
+ flagAnim = FLAG_RUN;
+ updateangles = qtrue;
+ }
+
+ if ( updateangles ) {
+
+ VectorCopy( cent->currentState.pos.trDelta, dir );
+ // add gravity
+ dir[2] += 100;
+ VectorNormalize( dir );
+ d = DotProduct(pole.axis[2], dir);
+ // if there is anough movement orthogonal to the flag pole
+ if (fabs(d) < 0.9) {
+ //
+ d = DotProduct(pole.axis[0], dir);
+ if (d > 1.0f) {
+ d = 1.0f;
+ }
+ else if (d < -1.0f) {
+ d = -1.0f;
+ }
+ angle = acos(d);
+
+ d = DotProduct(pole.axis[1], dir);
+ if (d < 0) {
+ angles[YAW] = 360 - angle * 180 / M_PI;
+ }
+ else {
+ angles[YAW] = angle * 180 / M_PI;
+ }
+ if (angles[YAW] < 0)
+ angles[YAW] += 360;
+ if (angles[YAW] > 360)
+ angles[YAW] -= 360;
+
+ //vectoangles( cent->currentState.pos.trDelta, tmpangles );
+ //angles[YAW] = tmpangles[YAW] + 45 - cent->pe.torso.yawAngle;
+ // change the yaw angle
+ CG_SwingAngles( angles[YAW], 25, 90, 0.15f, ¢->pe.flag.yawAngle, ¢->pe.flag.yawing );
+ }
+
+ /*
+ d = DotProduct(pole.axis[2], dir);
+ angle = Q_acos(d);
+
+ d = DotProduct(pole.axis[1], dir);
+ if (d < 0) {
+ angle = 360 - angle * 180 / M_PI;
+ }
+ else {
+ angle = angle * 180 / M_PI;
+ }
+ if (angle > 340 && angle < 20) {
+ flagAnim = FLAG_RUNUP;
+ }
+ if (angle > 160 && angle < 200) {
+ flagAnim = FLAG_RUNDOWN;
+ }
+ */
+ }
+
+ // set the yaw angle
+ angles[YAW] = cent->pe.flag.yawAngle;
+ // lerp the flag animation frames
+ ci = &cgs.clientinfo[ cent->currentState.clientNum ];
+ CG_RunLerpFrame( ci, ¢->pe.flag, flagAnim, 1 );
+ flag.oldframe = cent->pe.flag.oldFrame;
+ flag.frame = cent->pe.flag.frame;
+ flag.backlerp = cent->pe.flag.backlerp;
+
+ AnglesToAxis( angles, flag.axis );
+ CG_PositionRotatedEntityOnTag( &flag, &pole, pole.hModel, "tag_flag" );
+
+ trap_R_AddRefEntityToScene( &flag );
+}
+
+/*
+===============
+CG_PlayerTokens
+===============
+*/
+static void CG_PlayerTokens( centity_t *cent, int renderfx ) {
+ int tokens, i, j;
+ float angle;
+ refEntity_t ent;
+ vec3_t dir, origin;
+ skulltrail_t *trail;
+ trail = &cg.skulltrails[cent->currentState.number];
+ tokens = cent->currentState.generic1;
+ if ( !tokens ) {
+ trail->numpositions = 0;
+ return;
+ }
+
+ if ( tokens > MAX_SKULLTRAIL ) {
+ tokens = MAX_SKULLTRAIL;
+ }
+
+ // add skulls if there are more than last time
+ for (i = 0; i < tokens - trail->numpositions; i++) {
+ for (j = trail->numpositions; j > 0; j--) {
+ VectorCopy(trail->positions[j-1], trail->positions[j]);
+ }
+ VectorCopy(cent->lerpOrigin, trail->positions[0]);
+ }
+ trail->numpositions = tokens;
+
+ // move all the skulls along the trail
+ VectorCopy(cent->lerpOrigin, origin);
+ for (i = 0; i < trail->numpositions; i++) {
+ VectorSubtract(trail->positions[i], origin, dir);
+ if (VectorNormalize(dir) > 30) {
+ VectorMA(origin, 30, dir, trail->positions[i]);
+ }
+ VectorCopy(trail->positions[i], origin);
+ }
+
+ memset( &ent, 0, sizeof( ent ) );
+ if( cgs.clientinfo[ cent->currentState.clientNum ].team == TEAM_BLUE ) {
+ ent.hModel = cgs.media.redCubeModel;
+ } else {
+ ent.hModel = cgs.media.blueCubeModel;
+ }
+ ent.renderfx = renderfx;
+
+ VectorCopy(cent->lerpOrigin, origin);
+ for (i = 0; i < trail->numpositions; i++) {
+ VectorSubtract(origin, trail->positions[i], ent.axis[0]);
+ ent.axis[0][2] = 0;
+ VectorNormalize(ent.axis[0]);
+ VectorSet(ent.axis[2], 0, 0, 1);
+ CrossProduct(ent.axis[0], ent.axis[2], ent.axis[1]);
+
+ VectorCopy(trail->positions[i], ent.origin);
+ angle = (((cg.time + 500 * MAX_SKULLTRAIL - 500 * i) / 16) & 255) * (M_PI * 2) / 255;
+ ent.origin[2] += sin(angle) * 10;
+ trap_R_AddRefEntityToScene( &ent );
+ VectorCopy(trail->positions[i], origin);
+ }
+}
+
+
+/*
+===============
+CG_PlayerPowerups
+===============
+*/
+static void CG_PlayerPowerups( centity_t *cent, refEntity_t *torso ) {
+ int powerups;
+ clientInfo_t *ci;
+
+ powerups = cent->currentState.powerups;
+ if ( !powerups ) {
+ return;
+ }
+
+ // quad gives a dlight
+ if ( powerups & ( 1 << PW_QUAD ) ) {
+ trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1 );
+ }
+
+ // flight plays a looped sound
+ if ( powerups & ( 1 << PW_FLIGHT ) ) {
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.flightSound );
+ }
+
+ ci = &cgs.clientinfo[ cent->currentState.clientNum ];
+ // redflag
+ if ( powerups & ( 1 << PW_REDFLAG ) ) {
+ if (ci->newAnims) {
+ CG_PlayerFlag( cent, cgs.media.redFlagFlapSkin, torso );
+ }
+ else {
+ CG_TrailItem( cent, cgs.media.redFlagModel );
+ }
+ trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 0.2f, 0.2f );
+ }
+
+ // blueflag
+ if ( powerups & ( 1 << PW_BLUEFLAG ) ) {
+ if (ci->newAnims){
+ CG_PlayerFlag( cent, cgs.media.blueFlagFlapSkin, torso );
+ }
+ else {
+ CG_TrailItem( cent, cgs.media.blueFlagModel );
+ }
+ trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1.0 );
+ }
+
+ // neutralflag
+ if ( powerups & ( 1 << PW_NEUTRALFLAG ) ) {
+ if (ci->newAnims) {
+ CG_PlayerFlag( cent, cgs.media.neutralFlagFlapSkin, torso );
+ }
+ else {
+ CG_TrailItem( cent, cgs.media.neutralFlagModel );
+ }
+ trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 1.0, 1.0 );
+ }
+
+ // haste leaves smoke trails
+ if ( powerups & ( 1 << PW_HASTE ) ) {
+ CG_HasteTrail( cent );
+ }
+}
+
+
+/*
+===============
+CG_PlayerFloatSprite
+
+Float a sprite over the player's head
+===============
+*/
+static void CG_PlayerFloatSprite( centity_t *cent, qhandle_t shader ) {
+ int rf;
+ refEntity_t ent;
+
+ if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) {
+ rf = RF_THIRD_PERSON; // only show in mirrors
+ } else {
+ rf = 0;
+ }
+
+ memset( &ent, 0, sizeof( ent ) );
+ VectorCopy( cent->lerpOrigin, ent.origin );
+ ent.origin[2] += 48;
+ ent.reType = RT_SPRITE;
+ ent.customShader = shader;
+ ent.radius = 10;
+ ent.renderfx = rf;
+ ent.shaderRGBA[0] = 255;
+ ent.shaderRGBA[1] = 255;
+ ent.shaderRGBA[2] = 255;
+ ent.shaderRGBA[3] = 255;
+ trap_R_AddRefEntityToScene( &ent );
+}
+
+
+
+/*
+===============
+CG_PlayerSprites
+
+Float sprites over the player's head
+===============
+*/
+static void CG_PlayerSprites( centity_t *cent ) {
+ int team;
+
+ if ( cent->currentState.eFlags & EF_CONNECTION ) {
+ CG_PlayerFloatSprite( cent, cgs.media.connectionShader );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_TALK ) {
+ CG_PlayerFloatSprite( cent, cgs.media.balloonShader );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_AWARD_IMPRESSIVE ) {
+ CG_PlayerFloatSprite( cent, cgs.media.medalImpressive );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_AWARD_EXCELLENT ) {
+ CG_PlayerFloatSprite( cent, cgs.media.medalExcellent );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_AWARD_GAUNTLET ) {
+ CG_PlayerFloatSprite( cent, cgs.media.medalGauntlet );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_AWARD_DEFEND ) {
+ CG_PlayerFloatSprite( cent, cgs.media.medalDefend );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_AWARD_ASSIST ) {
+ CG_PlayerFloatSprite( cent, cgs.media.medalAssist );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_AWARD_CAP ) {
+ CG_PlayerFloatSprite( cent, cgs.media.medalCapture );
+ return;
+ }
+
+ team = cgs.clientinfo[ cent->currentState.clientNum ].team;
+ if ( !(cent->currentState.eFlags & EF_DEAD) &&
+ cg.snap->ps.persistant[PERS_TEAM] == team &&
+ cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ if (cg_drawFriend.integer) {
+ CG_PlayerFloatSprite( cent, cgs.media.friendShader );
+ }
+ return;
+ }
+}
+
+/*
+===============
+CG_PlayerShadow
+
+Returns the Z component of the surface being shadowed
+
+ should it return a full plane instead of a Z?
+===============
+*/
+#define SHADOW_DISTANCE 128
+static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane ) {
+ vec3_t end, mins = {-15, -15, 0}, maxs = {15, 15, 2};
+ trace_t trace;
+ float alpha;
+
+ *shadowPlane = 0;
+
+ if ( cg_shadows.integer == 0 ) {
+ return qfalse;
+ }
+
+ // no shadows when invisible
+ if ( cent->currentState.powerups & ( 1 << PW_INVIS ) ) {
+ return qfalse;
+ }
+
+ // send a trace down from the player to the ground
+ VectorCopy( cent->lerpOrigin, end );
+ end[2] -= SHADOW_DISTANCE;
+
+ trap_CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID );
+
+ // no shadow if too high
+ if ( trace.fraction == 1.0 || trace.startsolid || trace.allsolid ) {
+ return qfalse;
+ }
+
+ *shadowPlane = trace.endpos[2] + 1;
+
+ if ( cg_shadows.integer != 1 ) { // no mark for stencil or projection shadows
+ return qtrue;
+ }
+
+ // fade the shadow out with height
+ alpha = 1.0 - trace.fraction;
+
+ // bk0101022 - hack / FPE - bogus planes?
+ //assert( DotProduct( trace.plane.normal, trace.plane.normal ) != 0.0f )
+
+ // add the mark as a temporary, so it goes directly to the renderer
+ // without taking a spot in the cg_marks array
+ CG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal,
+ cent->pe.legs.yawAngle, alpha,alpha,alpha,1, qfalse, 24, qtrue );
+
+ return qtrue;
+}
+
+
+/*
+===============
+CG_PlayerSplash
+
+Draw a mark at the water surface
+===============
+*/
+static void CG_PlayerSplash( centity_t *cent ) {
+ vec3_t start, end;
+ trace_t trace;
+ int contents;
+ polyVert_t verts[4];
+
+ if ( !cg_shadows.integer ) {
+ return;
+ }
+
+ VectorCopy( cent->lerpOrigin, end );
+ end[2] -= 24;
+
+ // if the feet aren't in liquid, don't make a mark
+ // this won't handle moving water brushes, but they wouldn't draw right anyway...
+ contents = CG_PointContents( end, 0 );
+ if ( !( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) ) {
+ return;
+ }
+
+ VectorCopy( cent->lerpOrigin, start );
+ start[2] += 32;
+
+ // if the head isn't out of liquid, don't make a mark
+ contents = CG_PointContents( start, 0 );
+ if ( contents & ( CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
+ return;
+ }
+
+ // trace down to find the surface
+ trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) );
+
+ if ( trace.fraction == 1.0 ) {
+ return;
+ }
+
+ // create a mark polygon
+ VectorCopy( trace.endpos, verts[0].xyz );
+ verts[0].xyz[0] -= 32;
+ verts[0].xyz[1] -= 32;
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255;
+
+ VectorCopy( trace.endpos, verts[1].xyz );
+ verts[1].xyz[0] -= 32;
+ verts[1].xyz[1] += 32;
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255;
+
+ VectorCopy( trace.endpos, verts[2].xyz );
+ verts[2].xyz[0] += 32;
+ verts[2].xyz[1] += 32;
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255;
+
+ VectorCopy( trace.endpos, verts[3].xyz );
+ verts[3].xyz[0] += 32;
+ verts[3].xyz[1] -= 32;
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255;
+
+ trap_R_AddPolyToScene( cgs.media.wakeMarkShader, 4, verts );
+}
+
+
+
+/*
+===============
+CG_AddRefEntityWithPowerups
+
+Adds a piece with modifications or duplications for powerups
+Also called by CG_Missile for quad rockets, but nobody can tell...
+===============
+*/
+void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team, qboolean isMissile ) {
+
+ if ( state->powerups & ( 1 << PW_INVIS ) ) {
+ if( (cgs.dmflags & DF_INVIS) == 0) {
+ ent->customShader = cgs.media.invisShader;
+ trap_R_AddRefEntityToScene( ent );
+ }
+ } else {
+ /*
+ if ( state->eFlags & EF_KAMIKAZE ) {
+ if (team == TEAM_BLUE)
+ ent->customShader = cgs.media.blueKamikazeShader;
+ else
+ ent->customShader = cgs.media.redKamikazeShader;
+ trap_R_AddRefEntityToScene( ent );
+ }
+ else {*/
+ trap_R_AddRefEntityToScene( ent );
+ //}
+ if(!isMissile && (cgs.dmflags & DF_PLAYER_OVERLAY) && !(state->eFlags & EF_DEAD) ) {
+ switch(team) {
+ case TEAM_RED:
+ ent->customShader = cgs.media.redOverlay;
+ trap_R_AddRefEntityToScene( ent );
+ break;
+ case TEAM_BLUE:
+ ent->customShader = cgs.media.blueOverlay;
+ trap_R_AddRefEntityToScene( ent );
+ break;
+ default:
+ ent->customShader = cgs.media.neutralOverlay;
+ trap_R_AddRefEntityToScene( ent );
+ }
+ }
+
+ if ( state->powerups & ( 1 << PW_QUAD ) )
+ {
+ if (team == TEAM_RED)
+ ent->customShader = cgs.media.redQuadShader;
+ else
+ ent->customShader = cgs.media.quadShader;
+ trap_R_AddRefEntityToScene( ent );
+ }
+ if ( state->powerups & ( 1 << PW_REGEN ) ) {
+ if ( ( ( cg.time / 100 ) % 10 ) == 1 ) {
+ ent->customShader = cgs.media.regenShader;
+ trap_R_AddRefEntityToScene( ent );
+ }
+ }
+ if ( state->powerups & ( 1 << PW_BATTLESUIT ) ) {
+ ent->customShader = cgs.media.battleSuitShader;
+ trap_R_AddRefEntityToScene( ent );
+ }
+ }
+}
+
+
+
+/*
+=================
+CG_LightVerts
+=================
+*/
+int CG_LightVerts( vec3_t normal, int numVerts, polyVert_t *verts )
+{
+ int i, j;
+ float incoming;
+ vec3_t ambientLight;
+ vec3_t lightDir;
+ vec3_t directedLight;
+
+ trap_R_LightForPoint( verts[0].xyz, ambientLight, directedLight, lightDir );
+
+ for (i = 0; i < numVerts; i++) {
+ incoming = DotProduct (normal, lightDir);
+ if ( incoming <= 0 ) {
+ verts[i].modulate[0] = ambientLight[0];
+ verts[i].modulate[1] = ambientLight[1];
+ verts[i].modulate[2] = ambientLight[2];
+ verts[i].modulate[3] = 255;
+ continue;
+ }
+ j = ( ambientLight[0] + incoming * directedLight[0] );
+ if ( j > 255 ) {
+ j = 255;
+ }
+ verts[i].modulate[0] = j;
+
+ j = ( ambientLight[1] + incoming * directedLight[1] );
+ if ( j > 255 ) {
+ j = 255;
+ }
+ verts[i].modulate[1] = j;
+
+ j = ( ambientLight[2] + incoming * directedLight[2] );
+ if ( j > 255 ) {
+ j = 255;
+ }
+ verts[i].modulate[2] = j;
+
+ verts[i].modulate[3] = 255;
+ }
+ return qtrue;
+}
+
+/*
+===============
+CG_Player
+===============
+*/
+void CG_Player( centity_t *cent ) {
+ clientInfo_t *ci;
+ refEntity_t legs;
+ refEntity_t torso;
+ refEntity_t head;
+ int clientNum;
+ int renderfx;
+ qboolean shadow;
+ float shadowPlane;
+ refEntity_t skull;
+ refEntity_t powerup;
+ int t;
+ float c;
+ float angle;
+ vec3_t dir, angles;
+
+ // the client number is stored in clientNum. It can't be derived
+ // from the entity number, because a single client may have
+ // multiple corpses on the level using the same clientinfo
+ clientNum = cent->currentState.clientNum;
+ if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
+ CG_Error( "Bad clientNum on player entity");
+ }
+ ci = &cgs.clientinfo[ clientNum ];
+
+ // it is possible to see corpses from disconnected players that may
+ // not have valid clientinfo
+ if ( !ci->infoValid ) {
+ return;
+ }
+
+ // get the player model information
+ renderfx = 0;
+ if ( cent->currentState.number == cg.snap->ps.clientNum) {
+ if (!cg.renderingThirdPerson) {
+ renderfx = RF_THIRD_PERSON; // only draw in mirrors
+ } else {
+ if (cg_cameraMode.integer) {
+ return;
+ }
+ }
+ }
+
+
+ memset( &legs, 0, sizeof(legs) );
+ memset( &torso, 0, sizeof(torso) );
+ memset( &head, 0, sizeof(head) );
+
+ // get the rotation information
+ CG_PlayerAngles( cent, legs.axis, torso.axis, head.axis );
+
+ // get the animation state (after rotation, to allow feet shuffle)
+ CG_PlayerAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp,
+ &torso.oldframe, &torso.frame, &torso.backlerp );
+
+ // add the talk baloon or disconnect icon
+ CG_PlayerSprites( cent );
+
+ // add the shadow
+ shadow = CG_PlayerShadow( cent, &shadowPlane );
+
+ // add a water splash if partially in and out of water
+ CG_PlayerSplash( cent );
+
+ if ( cg_shadows.integer == 3 && shadow ) {
+ renderfx |= RF_SHADOW_PLANE;
+ }
+ renderfx |= RF_LIGHTING_ORIGIN; // use the same origin for all
+ if( cgs.gametype == GT_HARVESTER ) {
+ CG_PlayerTokens( cent, renderfx );
+ }
+ //
+ // add the legs
+ //
+ legs.hModel = ci->legsModel;
+ legs.customSkin = ci->legsSkin;
+
+ VectorCopy( cent->lerpOrigin, legs.origin );
+
+ VectorCopy( cent->lerpOrigin, legs.lightingOrigin );
+ legs.shadowPlane = shadowPlane;
+ legs.renderfx = renderfx;
+ VectorCopy (legs.origin, legs.oldorigin); // don't positionally lerp at all
+
+ CG_AddRefEntityWithPowerups( &legs, ¢->currentState, ci->team, qfalse );
+
+ // if the model failed, allow the default nullmodel to be displayed
+ if (!legs.hModel) {
+ return;
+ }
+
+ //
+ // add the torso
+ //
+ torso.hModel = ci->torsoModel;
+ if (!torso.hModel) {
+ return;
+ }
+
+ torso.customSkin = ci->torsoSkin;
+
+ VectorCopy( cent->lerpOrigin, torso.lightingOrigin );
+
+ CG_PositionRotatedEntityOnTag( &torso, &legs, ci->legsModel, "tag_torso");
+
+ torso.shadowPlane = shadowPlane;
+ torso.renderfx = renderfx;
+
+ CG_AddRefEntityWithPowerups( &torso, ¢->currentState, ci->team, qfalse );
+
+ if ( cent->currentState.eFlags & EF_KAMIKAZE ) {
+
+ memset( &skull, 0, sizeof(skull) );
+
+ VectorCopy( cent->lerpOrigin, skull.lightingOrigin );
+ skull.shadowPlane = shadowPlane;
+ skull.renderfx = renderfx;
+
+ if ( cent->currentState.eFlags & EF_DEAD ) {
+ // one skull bobbing above the dead body
+ angle = ((cg.time / 7) & 255) * (M_PI * 2) / 255;
+ if (angle > M_PI * 2)
+ angle -= (float)M_PI * 2;
+ dir[0] = sin(angle) * 20;
+ dir[1] = cos(angle) * 20;
+ angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255;
+ dir[2] = 15 + sin(angle) * 8;
+ VectorAdd(torso.origin, dir, skull.origin);
+
+ dir[2] = 0;
+ VectorCopy(dir, skull.axis[1]);
+ VectorNormalize(skull.axis[1]);
+ VectorSet(skull.axis[2], 0, 0, 1);
+ CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
+
+ skull.hModel = cgs.media.kamikazeHeadModel;
+ trap_R_AddRefEntityToScene( &skull );
+ skull.hModel = cgs.media.kamikazeHeadTrail;
+ trap_R_AddRefEntityToScene( &skull );
+ }
+ else {
+ // three skulls spinning around the player
+ angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255;
+ dir[0] = cos(angle) * 20;
+ dir[1] = sin(angle) * 20;
+ dir[2] = cos(angle) * 20;
+ VectorAdd(torso.origin, dir, skull.origin);
+
+ angles[0] = sin(angle) * 30;
+ angles[1] = (angle * 180 / M_PI) + 90;
+ if (angles[1] > 360)
+ angles[1] -= 360;
+ angles[2] = 0;
+ AnglesToAxis( angles, skull.axis );
+
+ /*
+ dir[2] = 0;
+ VectorInverse(dir);
+ VectorCopy(dir, skull.axis[1]);
+ VectorNormalize(skull.axis[1]);
+ VectorSet(skull.axis[2], 0, 0, 1);
+ CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
+ */
+
+ skull.hModel = cgs.media.kamikazeHeadModel;
+ trap_R_AddRefEntityToScene( &skull );
+ // flip the trail because this skull is spinning in the other direction
+ VectorInverse(skull.axis[1]);
+ skull.hModel = cgs.media.kamikazeHeadTrail;
+ trap_R_AddRefEntityToScene( &skull );
+
+ angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255 + M_PI;
+ if (angle > M_PI * 2)
+ angle -= (float)M_PI * 2;
+ dir[0] = sin(angle) * 20;
+ dir[1] = cos(angle) * 20;
+ dir[2] = cos(angle) * 20;
+ VectorAdd(torso.origin, dir, skull.origin);
+
+ angles[0] = cos(angle - 0.5 * M_PI) * 30;
+ angles[1] = 360 - (angle * 180 / M_PI);
+ if (angles[1] > 360)
+ angles[1] -= 360;
+ angles[2] = 0;
+ AnglesToAxis( angles, skull.axis );
+
+ /*
+ dir[2] = 0;
+ VectorCopy(dir, skull.axis[1]);
+ VectorNormalize(skull.axis[1]);
+ VectorSet(skull.axis[2], 0, 0, 1);
+ CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
+ */
+
+ skull.hModel = cgs.media.kamikazeHeadModel;
+ trap_R_AddRefEntityToScene( &skull );
+ skull.hModel = cgs.media.kamikazeHeadTrail;
+ trap_R_AddRefEntityToScene( &skull );
+
+ angle = ((cg.time / 3) & 255) * (M_PI * 2) / 255 + 0.5 * M_PI;
+ if (angle > M_PI * 2)
+ angle -= (float)M_PI * 2;
+ dir[0] = sin(angle) * 20;
+ dir[1] = cos(angle) * 20;
+ dir[2] = 0;
+ VectorAdd(torso.origin, dir, skull.origin);
+
+ VectorCopy(dir, skull.axis[1]);
+ VectorNormalize(skull.axis[1]);
+ VectorSet(skull.axis[2], 0, 0, 1);
+ CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
+
+ skull.hModel = cgs.media.kamikazeHeadModel;
+ trap_R_AddRefEntityToScene( &skull );
+ skull.hModel = cgs.media.kamikazeHeadTrail;
+ trap_R_AddRefEntityToScene( &skull );
+ }
+ }
+
+ if ( cent->currentState.powerups & ( 1 << PW_GUARD ) ) {
+ memcpy(&powerup, &torso, sizeof(torso));
+ powerup.hModel = cgs.media.guardPowerupModel;
+ powerup.frame = 0;
+ powerup.oldframe = 0;
+ powerup.customSkin = 0;
+ trap_R_AddRefEntityToScene( &powerup );
+ }
+ if ( cent->currentState.powerups & ( 1 << PW_SCOUT ) ) {
+ memcpy(&powerup, &torso, sizeof(torso));
+ powerup.hModel = cgs.media.scoutPowerupModel;
+ powerup.frame = 0;
+ powerup.oldframe = 0;
+ powerup.customSkin = 0;
+ trap_R_AddRefEntityToScene( &powerup );
+ }
+ if ( cent->currentState.powerups & ( 1 << PW_DOUBLER ) ) {
+ memcpy(&powerup, &torso, sizeof(torso));
+ powerup.hModel = cgs.media.doublerPowerupModel;
+ powerup.frame = 0;
+ powerup.oldframe = 0;
+ powerup.customSkin = 0;
+ trap_R_AddRefEntityToScene( &powerup );
+ }
+ if ( cent->currentState.powerups & ( 1 << PW_AMMOREGEN ) ) {
+ memcpy(&powerup, &torso, sizeof(torso));
+ powerup.hModel = cgs.media.ammoRegenPowerupModel;
+ powerup.frame = 0;
+ powerup.oldframe = 0;
+ powerup.customSkin = 0;
+ trap_R_AddRefEntityToScene( &powerup );
+ }
+ if ( cent->currentState.powerups & ( 1 << PW_INVULNERABILITY ) ) {
+ if ( !ci->invulnerabilityStartTime ) {
+ ci->invulnerabilityStartTime = cg.time;
+ }
+ ci->invulnerabilityStopTime = cg.time;
+ }
+ else {
+ ci->invulnerabilityStartTime = 0;
+ }
+ if ( (cent->currentState.powerups & ( 1 << PW_INVULNERABILITY ) ) ||
+ cg.time - ci->invulnerabilityStopTime < 250 ) {
+
+ memcpy(&powerup, &torso, sizeof(torso));
+ powerup.hModel = cgs.media.invulnerabilityPowerupModel;
+ powerup.customSkin = 0;
+ // always draw
+ powerup.renderfx &= ~RF_THIRD_PERSON;
+ VectorCopy(cent->lerpOrigin, powerup.origin);
+
+ if ( cg.time - ci->invulnerabilityStartTime < 250 ) {
+ c = (float) (cg.time - ci->invulnerabilityStartTime) / 250;
+ }
+ else if (cg.time - ci->invulnerabilityStopTime < 250 ) {
+ c = (float) (250 - (cg.time - ci->invulnerabilityStopTime)) / 250;
+ }
+ else {
+ c = 1;
+ }
+ VectorSet( powerup.axis[0], c, 0, 0 );
+ VectorSet( powerup.axis[1], 0, c, 0 );
+ VectorSet( powerup.axis[2], 0, 0, c );
+ trap_R_AddRefEntityToScene( &powerup );
+ }
+
+ t = cg.time - ci->medkitUsageTime;
+ if ( ci->medkitUsageTime && t < 500 ) {
+ memcpy(&powerup, &torso, sizeof(torso));
+ powerup.hModel = cgs.media.medkitUsageModel;
+ powerup.customSkin = 0;
+ // always draw
+ powerup.renderfx &= ~RF_THIRD_PERSON;
+ VectorClear(angles);
+ AnglesToAxis(angles, powerup.axis);
+ VectorCopy(cent->lerpOrigin, powerup.origin);
+ powerup.origin[2] += -24 + (float) t * 80 / 500;
+ if ( t > 400 ) {
+ c = (float) (t - 1000) * 0xff / 100;
+ powerup.shaderRGBA[0] = 0xff - c;
+ powerup.shaderRGBA[1] = 0xff - c;
+ powerup.shaderRGBA[2] = 0xff - c;
+ powerup.shaderRGBA[3] = 0xff - c;
+ }
+ else {
+ powerup.shaderRGBA[0] = 0xff;
+ powerup.shaderRGBA[1] = 0xff;
+ powerup.shaderRGBA[2] = 0xff;
+ powerup.shaderRGBA[3] = 0xff;
+ }
+ trap_R_AddRefEntityToScene( &powerup );
+ }
+
+ //
+ // add the head
+ //
+ head.hModel = ci->headModel;
+ if (!head.hModel) {
+ return;
+ }
+ head.customSkin = ci->headSkin;
+
+ VectorCopy( cent->lerpOrigin, head.lightingOrigin );
+
+ CG_PositionRotatedEntityOnTag( &head, &torso, ci->torsoModel, "tag_head");
+
+ head.shadowPlane = shadowPlane;
+ head.renderfx = renderfx;
+
+ CG_AddRefEntityWithPowerups( &head, ¢->currentState, ci->team, qfalse );
+
+ CG_BreathPuffs(cent, &head);
+
+ CG_DustTrail(cent);
+
+ //
+ // add the gun / barrel / flash
+ //
+ CG_AddPlayerWeapon( &torso, NULL, cent, ci->team );
+
+ // add powerups floating behind the player
+ CG_PlayerPowerups( cent, &torso );
+}
+
+
+//=====================================================================
+
+/*
+===============
+CG_ResetPlayerEntity
+
+A player just came into view or teleported, so reset all animation info
+===============
+*/
+void CG_ResetPlayerEntity( centity_t *cent ) {
+ cent->errorTime = -99999; // guarantee no error decay added
+ cent->extrapolated = qfalse;
+
+ CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.legs, cent->currentState.legsAnim );
+ CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.torso, cent->currentState.torsoAnim );
+
+ BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin );
+ BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles );
+
+ VectorCopy( cent->lerpOrigin, cent->rawOrigin );
+ VectorCopy( cent->lerpAngles, cent->rawAngles );
+
+ memset( ¢->pe.legs, 0, sizeof( cent->pe.legs ) );
+ cent->pe.legs.yawAngle = cent->rawAngles[YAW];
+ cent->pe.legs.yawing = qfalse;
+ cent->pe.legs.pitchAngle = 0;
+ cent->pe.legs.pitching = qfalse;
+
+ memset( ¢->pe.torso, 0, sizeof( cent->pe.legs ) );
+ cent->pe.torso.yawAngle = cent->rawAngles[YAW];
+ cent->pe.torso.yawing = qfalse;
+ cent->pe.torso.pitchAngle = cent->rawAngles[PITCH];
+ cent->pe.torso.pitching = qfalse;
+
+ if ( cg_debugPosition.integer ) {
+ CG_Printf("%i ResetPlayerEntity yaw=%i\n", cent->currentState.number, cent->pe.torso.yawAngle );
+ }
+}
+
diff --git a/code/cgame/cg_playerstate.c b/code/cgame/cg_playerstate.c
new file mode 100644
index 0000000..91dc258
--- /dev/null
+++ b/code/cgame/cg_playerstate.c
@@ -0,0 +1,536 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_playerstate.c -- this file acts on changes in a new playerState_t
+// With normal play, this will be done after local prediction, but when
+// following another player or playing back a demo, it will be checked
+// when the snapshot transitions like all the other entities
+
+#include "cg_local.h"
+
+/*
+==============
+CG_CheckAmmo
+
+If the ammo has gone low enough to generate the warning, play a sound
+==============
+*/
+void CG_CheckAmmo( void ) {
+ int i;
+ int total;
+ int previous;
+ int weapons;
+
+ // see about how many seconds of ammo we have remaining
+ weapons = cg.snap->ps.stats[ STAT_WEAPONS ];
+ total = 0;
+ for ( i = WP_MACHINEGUN ; i < WP_NUM_WEAPONS ; i++ ) {
+ if ( ! ( weapons & ( 1 << i ) ) || i == WP_GRAPPLING_HOOK ) {
+ continue;
+ }
+ switch ( i ) {
+ case WP_ROCKET_LAUNCHER:
+ case WP_GRENADE_LAUNCHER:
+ case WP_RAILGUN:
+ case WP_SHOTGUN:
+//#ifdef MISSIONPACK
+ case WP_PROX_LAUNCHER:
+//#endif
+ total += cg.snap->ps.ammo[i] * 1000;
+ break;
+ default:
+ total += cg.snap->ps.ammo[i] * 200;
+ break;
+ }
+ if ( total >= 5000 ) {
+ cg.lowAmmoWarning = 0;
+ return;
+ }
+ }
+
+ previous = cg.lowAmmoWarning;
+
+ if ( total == 0 ) {
+ cg.lowAmmoWarning = 2;
+ } else {
+ cg.lowAmmoWarning = 1;
+ }
+
+ // play a sound on transitions
+ if ( cg.lowAmmoWarning != previous ) {
+ trap_S_StartLocalSound( cgs.media.noAmmoSound, CHAN_LOCAL_SOUND );
+ }
+}
+
+/*
+==============
+CG_DamageFeedback
+==============
+*/
+void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) {
+ float left, front, up;
+ float kick;
+ int health;
+ float scale;
+ vec3_t dir;
+ vec3_t angles;
+ float dist;
+ float yaw, pitch;
+
+ // show the attacking player's head and name in corner
+ cg.attackerTime = cg.time;
+
+ // the lower on health you are, the greater the view kick will be
+ health = cg.snap->ps.stats[STAT_HEALTH];
+ if ( health < 40 ) {
+ scale = 1;
+ } else {
+ scale = 40.0 / health;
+ }
+ kick = damage * scale;
+
+ if (kick < 5)
+ kick = 5;
+ if (kick > 10)
+ kick = 10;
+
+ // if yaw and pitch are both 255, make the damage always centered (falling, etc)
+ if ( yawByte == 255 && pitchByte == 255 ) {
+ cg.damageX = 0;
+ cg.damageY = 0;
+ cg.v_dmg_roll = 0;
+ cg.v_dmg_pitch = -kick;
+ } else {
+ // positional
+ pitch = pitchByte / 255.0 * 360;
+ yaw = yawByte / 255.0 * 360;
+
+ angles[PITCH] = pitch;
+ angles[YAW] = yaw;
+ angles[ROLL] = 0;
+
+ AngleVectors( angles, dir, NULL, NULL );
+ VectorSubtract( vec3_origin, dir, dir );
+
+ front = DotProduct (dir, cg.refdef.viewaxis[0] );
+ left = DotProduct (dir, cg.refdef.viewaxis[1] );
+ up = DotProduct (dir, cg.refdef.viewaxis[2] );
+
+ dir[0] = front;
+ dir[1] = left;
+ dir[2] = 0;
+ dist = VectorLength( dir );
+ if ( dist < 0.1 ) {
+ dist = 0.1f;
+ }
+
+ cg.v_dmg_roll = kick * left;
+
+ cg.v_dmg_pitch = -kick * front;
+
+ if ( front <= 0.1 ) {
+ front = 0.1f;
+ }
+ cg.damageX = -left / front;
+ cg.damageY = up / dist;
+ }
+
+ // clamp the position
+ if ( cg.damageX > 1.0 ) {
+ cg.damageX = 1.0;
+ }
+ if ( cg.damageX < - 1.0 ) {
+ cg.damageX = -1.0;
+ }
+
+ if ( cg.damageY > 1.0 ) {
+ cg.damageY = 1.0;
+ }
+ if ( cg.damageY < - 1.0 ) {
+ cg.damageY = -1.0;
+ }
+
+ // don't let the screen flashes vary as much
+ if ( kick > 10 ) {
+ kick = 10;
+ }
+ cg.damageValue = kick;
+ cg.v_dmg_time = cg.time + DAMAGE_TIME;
+ cg.damageTime = cg.snap->serverTime;
+}
+
+
+
+
+/*
+================
+CG_Respawn
+
+A respawn happened this snapshot
+================
+*/
+void CG_Respawn( void ) {
+ // no error decay on player movement
+ cg.thisFrameTeleport = qtrue;
+
+ // display weapons available
+ cg.weaponSelectTime = cg.time;
+
+ // select the weapon the server says we are using
+ cg.weaponSelect = cg.snap->ps.weapon;
+}
+
+extern char *eventnames[];
+
+/*
+==============
+CG_CheckPlayerstateEvents
+==============
+*/
+void CG_CheckPlayerstateEvents( playerState_t *ps, playerState_t *ops ) {
+ int i;
+ int event;
+ centity_t *cent;
+
+ if ( ps->externalEvent && ps->externalEvent != ops->externalEvent ) {
+ cent = &cg_entities[ ps->clientNum ];
+ cent->currentState.event = ps->externalEvent;
+ cent->currentState.eventParm = ps->externalEventParm;
+ CG_EntityEvent( cent, cent->lerpOrigin );
+ }
+
+ cent = &cg.predictedPlayerEntity; // cg_entities[ ps->clientNum ];
+ // go through the predictable events buffer
+ for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {
+ // if we have a new predictable event
+ if ( i >= ops->eventSequence
+ // or the server told us to play another event instead of a predicted event we already issued
+ // or something the server told us changed our prediction causing a different event
+ || (i > ops->eventSequence - MAX_PS_EVENTS && ps->events[i & (MAX_PS_EVENTS-1)] != ops->events[i & (MAX_PS_EVENTS-1)]) ) {
+
+ event = ps->events[ i & (MAX_PS_EVENTS-1) ];
+ cent->currentState.event = event;
+ cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];
+ CG_EntityEvent( cent, cent->lerpOrigin );
+
+ cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event;
+
+ cg.eventSequence++;
+ }
+ }
+}
+
+/*
+==================
+CG_CheckChangedPredictableEvents
+==================
+*/
+void CG_CheckChangedPredictableEvents( playerState_t *ps ) {
+ int i;
+ int event;
+ centity_t *cent;
+
+ cent = &cg.predictedPlayerEntity;
+ for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {
+ //
+ if (i >= cg.eventSequence) {
+ continue;
+ }
+ // if this event is not further back in than the maximum predictable events we remember
+ if (i > cg.eventSequence - MAX_PREDICTED_EVENTS) {
+ // if the new playerstate event is different from a previously predicted one
+ if ( ps->events[i & (MAX_PS_EVENTS-1)] != cg.predictableEvents[i & (MAX_PREDICTED_EVENTS-1) ] ) {
+
+ event = ps->events[ i & (MAX_PS_EVENTS-1) ];
+ cent->currentState.event = event;
+ cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];
+ CG_EntityEvent( cent, cent->lerpOrigin );
+
+ cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event;
+
+ if ( cg_showmiss.integer ) {
+ CG_Printf("WARNING: changed predicted event\n");
+ }
+ }
+ }
+ }
+}
+
+/*
+==================
+pushReward
+==================
+*/
+static void pushReward(sfxHandle_t sfx, qhandle_t shader, int rewardCount) {
+ if (cg.rewardStack < (MAX_REWARDSTACK-1)) {
+ cg.rewardStack++;
+ cg.rewardSound[cg.rewardStack] = sfx;
+ cg.rewardShader[cg.rewardStack] = shader;
+ cg.rewardCount[cg.rewardStack] = rewardCount;
+ }
+}
+
+
+/*
+==================
+CG_CheckLocalSounds
+==================
+*/
+void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) {
+ int highScore, health, armor, reward;
+ sfxHandle_t sfx;
+
+ // don't play the sounds if the player just changed teams
+ if ( ps->persistant[PERS_TEAM] != ops->persistant[PERS_TEAM] ) {
+ return;
+ }
+
+ // hit changes
+ if ( ps->persistant[PERS_HITS] > ops->persistant[PERS_HITS] ) {
+ armor = ps->persistant[PERS_ATTACKEE_ARMOR] & 0xff;
+ health = ps->persistant[PERS_ATTACKEE_ARMOR] >> 8;
+#ifdef MISSIONPACK
+ if (armor > 50 ) {
+ trap_S_StartLocalSound( cgs.media.hitSoundHighArmor, CHAN_LOCAL_SOUND );
+ } else if (armor || health > 100) {
+ trap_S_StartLocalSound( cgs.media.hitSoundLowArmor, CHAN_LOCAL_SOUND );
+ } else {
+ trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND );
+ }
+#else
+ trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND );
+#endif
+ } else if ( ps->persistant[PERS_HITS] < ops->persistant[PERS_HITS] ) {
+ trap_S_StartLocalSound( cgs.media.hitTeamSound, CHAN_LOCAL_SOUND );
+ }
+
+ // health changes of more than -1 should make pain sounds
+ if ( ps->stats[STAT_HEALTH] < ops->stats[STAT_HEALTH] - 1 ) {
+ if ( ps->stats[STAT_HEALTH] > 0 ) {
+ CG_PainEvent( &cg.predictedPlayerEntity, ps->stats[STAT_HEALTH] );
+ }
+ }
+
+
+ // if we are going into the intermission, don't start any voices
+ if ( cg.intermissionStarted ) {
+ return;
+ }
+
+ // reward sounds
+ reward = qfalse;
+ if (ps->persistant[PERS_CAPTURES] != ops->persistant[PERS_CAPTURES]) {
+ pushReward(cgs.media.captureAwardSound, cgs.media.medalCapture, ps->persistant[PERS_CAPTURES]);
+ reward = qtrue;
+ //Com_Printf("capture\n");
+ }
+ if (ps->persistant[PERS_IMPRESSIVE_COUNT] != ops->persistant[PERS_IMPRESSIVE_COUNT]) {
+#ifdef MISSIONPACK
+ if (ps->persistant[PERS_IMPRESSIVE_COUNT] == 1) {
+ sfx = cgs.media.firstImpressiveSound;
+ } else {
+ sfx = cgs.media.impressiveSound;
+ }
+#else
+ sfx = cgs.media.impressiveSound;
+#endif
+ pushReward(sfx, cgs.media.medalImpressive, ps->persistant[PERS_IMPRESSIVE_COUNT]);
+ reward = qtrue;
+ //Com_Printf("impressive\n");
+ }
+ //KK-OAX We Just Won't Draw The Excellent Stuff if Multikills are Enabled!!!
+ if( !cgs.altExcellent ) {
+ if (ps->persistant[PERS_EXCELLENT_COUNT] != ops->persistant[PERS_EXCELLENT_COUNT]) {
+#ifdef MISSIONPACK
+ if (ps->persistant[PERS_EXCELLENT_COUNT] == 1) {
+ sfx = cgs.media.firstExcellentSound;
+ } else {
+ sfx = cgs.media.excellentSound;
+ }
+#else
+ sfx = cgs.media.excellentSound;
+#endif
+
+ pushReward(sfx, cgs.media.medalExcellent, ps->persistant[PERS_EXCELLENT_COUNT]);
+ reward = qtrue;
+ //Com_Printf("excellent\n");
+ }
+ }
+ if (ps->persistant[PERS_GAUNTLET_FRAG_COUNT] != ops->persistant[PERS_GAUNTLET_FRAG_COUNT]) {
+#ifdef MISSIONPACK
+ if (ops->persistant[PERS_GAUNTLET_FRAG_COUNT] == 1) {
+ sfx = cgs.media.firstHumiliationSound;
+ } else {
+ sfx = cgs.media.humiliationSound;
+ }
+#else
+ sfx = cgs.media.humiliationSound;
+#endif
+ pushReward(sfx, cgs.media.medalGauntlet, ps->persistant[PERS_GAUNTLET_FRAG_COUNT]);
+ reward = qtrue;
+ //Com_Printf("guantlet frag\n");
+ }
+ if (ps->persistant[PERS_DEFEND_COUNT] != ops->persistant[PERS_DEFEND_COUNT]) {
+ pushReward(cgs.media.defendSound, cgs.media.medalDefend, ps->persistant[PERS_DEFEND_COUNT]);
+ reward = qtrue;
+ //Com_Printf("defend\n");
+ }
+ if (ps->persistant[PERS_ASSIST_COUNT] != ops->persistant[PERS_ASSIST_COUNT]) {
+ pushReward(cgs.media.assistSound, cgs.media.medalAssist, ps->persistant[PERS_ASSIST_COUNT]);
+ reward = qtrue;
+ //Com_Printf("assist\n");
+ }
+ // if any of the player event bits changed
+ if (ps->persistant[PERS_PLAYEREVENTS] != ops->persistant[PERS_PLAYEREVENTS]) {
+ if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD) !=
+ (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD)) {
+ trap_S_StartLocalSound( cgs.media.deniedSound, CHAN_ANNOUNCER );
+ }
+ else if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD) !=
+ (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD)) {
+ trap_S_StartLocalSound( cgs.media.humiliationSound, CHAN_ANNOUNCER );
+ }
+ else if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT) !=
+ (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT)) {
+ trap_S_StartLocalSound( cgs.media.holyShitSound, CHAN_ANNOUNCER );
+ }
+ reward = qtrue;
+ }
+
+ // check for flag pickup
+ if ( cgs.gametype > GT_TEAM ) {
+ if ((ps->powerups[PW_REDFLAG] != ops->powerups[PW_REDFLAG] && ps->powerups[PW_REDFLAG]) ||
+ (ps->powerups[PW_BLUEFLAG] != ops->powerups[PW_BLUEFLAG] && ps->powerups[PW_BLUEFLAG]) ||
+ (ps->powerups[PW_NEUTRALFLAG] != ops->powerups[PW_NEUTRALFLAG] && ps->powerups[PW_NEUTRALFLAG]) )
+ {
+ trap_S_StartLocalSound( cgs.media.youHaveFlagSound, CHAN_ANNOUNCER );
+ }
+ }
+
+ // lead changes
+ if (!reward) {
+ //
+ if ( !cg.warmup ) {
+ // never play lead changes during warmup
+ if ( ps->persistant[PERS_RANK] != ops->persistant[PERS_RANK] ) {
+ if ( cgs.gametype < GT_TEAM || cgs.ffa_gt==1) {
+ if ( ps->persistant[PERS_RANK] == 0 ) {
+ CG_AddBufferedSound(cgs.media.takenLeadSound);
+ } else if ( ps->persistant[PERS_RANK] == RANK_TIED_FLAG ) {
+ CG_AddBufferedSound(cgs.media.tiedLeadSound);
+ } else if ( ( ops->persistant[PERS_RANK] & ~RANK_TIED_FLAG ) == 0 ) {
+ CG_AddBufferedSound(cgs.media.lostLeadSound);
+ }
+ }
+ }
+ }
+ }
+
+ // timelimit warnings
+ if ( cgs.timelimit > 0 && cgs.timelimit <= 1000 ) {
+ int msec;
+
+ msec = cg.time - cgs.levelStartTime;
+ if ( !( cg.timelimitWarnings & 4 ) && msec > ( cgs.timelimit * 60 + 2 ) * 1000 ) {
+ cg.timelimitWarnings |= 1 | 2 | 4;
+ trap_S_StartLocalSound( cgs.media.suddenDeathSound, CHAN_ANNOUNCER );
+ }
+ else if ( !( cg.timelimitWarnings & 2 ) && msec > (cgs.timelimit - 1) * 60 * 1000 ) {
+ cg.timelimitWarnings |= 1 | 2;
+ trap_S_StartLocalSound( cgs.media.oneMinuteSound, CHAN_ANNOUNCER );
+ }
+ else if ( cgs.timelimit > 5 && !( cg.timelimitWarnings & 1 ) && msec > (cgs.timelimit - 5) * 60 * 1000 ) {
+ cg.timelimitWarnings |= 1;
+ trap_S_StartLocalSound( cgs.media.fiveMinuteSound, CHAN_ANNOUNCER );
+ }
+ }
+
+ // fraglimit warnings
+ if ( cgs.fraglimit > 0 && cgs.gametype < GT_CTF) {
+ highScore = cgs.scores1;
+
+ if (cgs.gametype == GT_TEAM && cgs.scores2 > highScore) {
+ highScore = cgs.scores2;
+ }
+
+ if ( !( cg.fraglimitWarnings & 4 ) && highScore == (cgs.fraglimit - 1) ) {
+ cg.fraglimitWarnings |= 1 | 2 | 4;
+ CG_AddBufferedSound(cgs.media.oneFragSound);
+ }
+ else if ( cgs.fraglimit > 2 && !( cg.fraglimitWarnings & 2 ) && highScore == (cgs.fraglimit - 2) ) {
+ cg.fraglimitWarnings |= 1 | 2;
+ CG_AddBufferedSound(cgs.media.twoFragSound);
+ }
+ else if ( cgs.fraglimit > 3 && !( cg.fraglimitWarnings & 1 ) && highScore == (cgs.fraglimit - 3) ) {
+ cg.fraglimitWarnings |= 1;
+ CG_AddBufferedSound(cgs.media.threeFragSound);
+ }
+ }
+}
+
+/*
+===============
+CG_TransitionPlayerState
+
+===============
+*/
+void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) {
+ // check for changing follow mode
+ if ( ps->clientNum != ops->clientNum ) {
+ cg.thisFrameTeleport = qtrue;
+ // make sure we don't get any unwanted transition effects
+ *ops = *ps;
+ }
+
+ // damage events (player is getting wounded)
+ if ( ps->damageEvent != ops->damageEvent && ps->damageCount ) {
+ CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount );
+ }
+
+ // respawning
+ if ( ps->persistant[PERS_SPAWN_COUNT] != ops->persistant[PERS_SPAWN_COUNT] ) {
+ CG_Respawn();
+ }
+
+ if ( cg.mapRestart ) {
+ CG_Respawn();
+ cg.mapRestart = qfalse;
+ }
+
+ if ( cg.snap->ps.pm_type != PM_INTERMISSION
+ && ps->persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
+ CG_CheckLocalSounds( ps, ops );
+ }
+
+ // check for going low on ammo
+ CG_CheckAmmo();
+
+ // run events
+ CG_CheckPlayerstateEvents( ps, ops );
+
+ // smooth the ducking viewheight change
+ if ( ps->viewheight != ops->viewheight ) {
+ cg.duckChange = ps->viewheight - ops->viewheight;
+ cg.duckTime = cg.time;
+ }
+}
+
diff --git a/code/cgame/cg_predict.c b/code/cgame/cg_predict.c
new file mode 100644
index 0000000..2592e01
--- /dev/null
+++ b/code/cgame/cg_predict.c
@@ -0,0 +1,942 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_predict.c -- this file generates cg.predictedPlayerState by either
+// interpolating between snapshots from the server or locally predicting
+// ahead the client's movement.
+// It also handles local physics interaction, like fragments bouncing off walls
+
+#include "cg_local.h"
+
+static pmove_t cg_pmove;
+
+static int cg_numSolidEntities;
+static centity_t *cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT];
+static int cg_numTriggerEntities;
+static centity_t *cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT];
+
+/*
+====================
+CG_BuildSolidList
+
+When a new cg.snap has been set, this function builds a sublist
+of the entities that are actually solid, to make for more
+efficient collision detection
+====================
+*/
+void CG_BuildSolidList( void ) {
+ int i;
+ centity_t *cent;
+ snapshot_t *snap;
+ entityState_t *ent;
+
+ cg_numSolidEntities = 0;
+ cg_numTriggerEntities = 0;
+
+ if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
+ snap = cg.nextSnap;
+ } else {
+ snap = cg.snap;
+ }
+
+ for ( i = 0 ; i < snap->numEntities ; i++ ) {
+ cent = &cg_entities[ snap->entities[ i ].number ];
+ ent = ¢->currentState;
+
+ if ( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) {
+ cg_triggerEntities[cg_numTriggerEntities] = cent;
+ cg_numTriggerEntities++;
+ continue;
+ }
+
+ if ( cent->nextState.solid ) {
+ cg_solidEntities[cg_numSolidEntities] = cent;
+ cg_numSolidEntities++;
+ continue;
+ }
+ }
+}
+
+/*
+====================
+CG_ClipMoveToEntities
+
+====================
+*/
+static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
+ int skipNumber, int mask, trace_t *tr ) {
+ int i, x, zd, zu;
+ trace_t trace;
+ entityState_t *ent;
+ clipHandle_t cmodel;
+ vec3_t bmins, bmaxs;
+ vec3_t origin, angles;
+ centity_t *cent;
+
+ for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
+ cent = cg_solidEntities[ i ];
+ ent = ¢->currentState;
+
+ if ( ent->number == skipNumber ) {
+ continue;
+ }
+
+ if ( ent->solid == SOLID_BMODEL ) {
+ // special value for bmodel
+ cmodel = trap_CM_InlineModel( ent->modelindex );
+ VectorCopy( cent->lerpAngles, angles );
+ BG_EvaluateTrajectory( ¢->currentState.pos, cg.physicsTime, origin );
+ } else {
+ // encoded bbox
+ x = (ent->solid & 255);
+ zd = ((ent->solid>>8) & 255);
+ zu = ((ent->solid>>16) & 255) - 32;
+
+ bmins[0] = bmins[1] = -x;
+ bmaxs[0] = bmaxs[1] = x;
+ bmins[2] = -zd;
+ bmaxs[2] = zu;
+
+ cmodel = trap_CM_TempBoxModel( bmins, bmaxs );
+ VectorCopy( vec3_origin, angles );
+ VectorCopy( cent->lerpOrigin, origin );
+ }
+
+
+ trap_CM_TransformedBoxTrace ( &trace, start, end,
+ mins, maxs, cmodel, mask, origin, angles);
+
+ if (trace.allsolid || trace.fraction < tr->fraction) {
+ trace.entityNum = ent->number;
+ *tr = trace;
+ } else if (trace.startsolid) {
+ tr->startsolid = qtrue;
+ }
+ if ( tr->allsolid ) {
+ return;
+ }
+ }
+}
+
+/*
+================
+CG_Trace
+================
+*/
+void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
+ int skipNumber, int mask ) {
+ trace_t t;
+
+ trap_CM_BoxTrace ( &t, start, end, mins, maxs, 0, mask);
+ t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
+ // check all other solid models
+ CG_ClipMoveToEntities (start, mins, maxs, end, skipNumber, mask, &t);
+
+ *result = t;
+}
+
+/*
+================
+CG_PointContents
+================
+*/
+int CG_PointContents( const vec3_t point, int passEntityNum ) {
+ int i;
+ entityState_t *ent;
+ centity_t *cent;
+ clipHandle_t cmodel;
+ int contents;
+
+ contents = trap_CM_PointContents (point, 0);
+
+ for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
+ cent = cg_solidEntities[ i ];
+
+ ent = ¢->currentState;
+
+ if ( ent->number == passEntityNum ) {
+ continue;
+ }
+
+ if (ent->solid != SOLID_BMODEL) { // special value for bmodel
+ continue;
+ }
+
+ cmodel = trap_CM_InlineModel( ent->modelindex );
+ if ( !cmodel ) {
+ continue;
+ }
+
+ contents |= trap_CM_TransformedPointContents( point, cmodel, cent->lerpOrigin, cent->lerpAngles );
+ }
+
+ return contents;
+}
+
+
+/*
+========================
+CG_InterpolatePlayerState
+
+Generates cg.predictedPlayerState by interpolating between
+cg.snap->player_state and cg.nextFrame->player_state
+========================
+*/
+static void CG_InterpolatePlayerState( qboolean grabAngles ) {
+ float f;
+ int i;
+ playerState_t *out;
+ snapshot_t *prev, *next;
+
+ out = &cg.predictedPlayerState;
+ prev = cg.snap;
+ next = cg.nextSnap;
+
+ *out = cg.snap->ps;
+
+ // if we are still allowing local input, short circuit the view angles
+ if ( grabAngles ) {
+ usercmd_t cmd;
+ int cmdNum;
+
+ cmdNum = trap_GetCurrentCmdNumber();
+ trap_GetUserCmd( cmdNum, &cmd );
+
+ PM_UpdateViewAngles( out, &cmd );
+ }
+
+ // if the next frame is a teleport, we can't lerp to it
+ if ( cg.nextFrameTeleport ) {
+ return;
+ }
+
+ if ( !next || next->serverTime <= prev->serverTime ) {
+ return;
+ }
+
+ f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime );
+
+ i = next->ps.bobCycle;
+ if ( i < prev->ps.bobCycle ) {
+ i += 256; // handle wraparound
+ }
+ out->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle );
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ out->origin[i] = prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i] );
+ if ( !grabAngles ) {
+ out->viewangles[i] = LerpAngle(
+ prev->ps.viewangles[i], next->ps.viewangles[i], f );
+ }
+ out->velocity[i] = prev->ps.velocity[i] +
+ f * (next->ps.velocity[i] - prev->ps.velocity[i] );
+ }
+
+}
+
+/*
+===================
+CG_TouchItem
+===================
+*/
+static void CG_TouchItem( centity_t *cent ) {
+ gitem_t *item;
+ //For instantgib
+ qboolean canBePicked;
+
+ if(cgs.gametype == GT_ELIMINATION || cgs.gametype == GT_LMS)
+ return; //No weapon pickup in elimination
+
+ //normally we can
+ canBePicked = qtrue;
+
+ //But in instantgib, rocket arena, and CTF_ELIMINATION we normally can't:
+ if(cgs.nopickup || cgs.gametype == GT_CTF_ELIMINATION)
+ canBePicked = qfalse;
+
+ if ( !cg_predictItems.integer ) {
+ return;
+ }
+ if ( !BG_PlayerTouchesItem( &cg.predictedPlayerState, ¢->currentState, cg.time ) ) {
+ return;
+ }
+
+ // never pick an item up twice in a prediction
+ if ( cent->miscTime == cg.time ) {
+ return;
+ }
+
+ if ( !BG_CanItemBeGrabbed( cgs.gametype, ¢->currentState, &cg.predictedPlayerState ) ) {
+ return; // can't hold it
+ }
+
+ item = &bg_itemlist[ cent->currentState.modelindex ];
+
+ // Special case for flags.
+ // We don't predict touching our own flag
+#if 1 //MISSIONPACK
+ if( cgs.gametype == GT_1FCTF ) {
+ if( item->giTag != PW_NEUTRALFLAG ) {
+ return;
+ }
+ }
+ if( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION || cgs.gametype == GT_HARVESTER ) {
+#else
+ if( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION ) {
+#endif
+ if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_RED &&
+ item->giTag == PW_REDFLAG)
+ return;
+ if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_BLUE &&
+ item->giTag == PW_BLUEFLAG)
+ return;
+ //Even in instantgib, we can predict our enemy flag
+ if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_RED &&
+ item->giTag == PW_BLUEFLAG && (!(cgs.elimflags&EF_ONEWAY) || cgs.attackingTeam == TEAM_RED))
+ canBePicked = qtrue;
+ if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_BLUE &&
+ item->giTag == PW_REDFLAG && (!(cgs.elimflags&EF_ONEWAY) || cgs.attackingTeam == TEAM_BLUE))
+ canBePicked = qtrue;
+ if (item->giTag == WP_RAILGUN)
+ canBePicked = qfalse;
+ if (item->giTag == WP_PLASMAGUN)
+ canBePicked = qfalse;
+ }
+
+ //Currently we don't predict anything in Double Domination because it looks like we take a flag
+ if( cgs.gametype == GT_DOUBLE_D ) {
+ if(cgs.redflag == TEAM_NONE)
+ return; //Can never pick if just one flag is NONE (because then the other is too)
+ if(item->giTag == PW_REDFLAG){ //at point A
+ if(cgs.redflag != cg.predictedPlayerState.persistant[PERS_TEAM]) //not already taken
+ trap_S_StartLocalSound( cgs.media.hitSound , CHAN_ANNOUNCER );
+ return;
+ }
+ if(item->giTag == PW_BLUEFLAG){ //at point B
+ if(cgs.blueflag != cg.predictedPlayerState.persistant[PERS_TEAM]) //already taken
+ trap_S_StartLocalSound( cgs.media.hitSound , CHAN_ANNOUNCER );
+ return;
+ }
+ }
+
+ // grab it
+ if(canBePicked)
+ {
+ BG_AddPredictableEventToPlayerstate( EV_ITEM_PICKUP, cent->currentState.modelindex , &cg.predictedPlayerState);
+
+ // remove it from the frame so it won't be drawn
+ cent->currentState.eFlags |= EF_NODRAW;
+
+ // don't touch it again this prediction
+ cent->miscTime = cg.time;
+
+ // if its a weapon, give them some predicted ammo so the autoswitch will work
+ if ( item->giType == IT_WEAPON ) {
+ cg.predictedPlayerState.stats[ STAT_WEAPONS ] |= 1 << item->giTag;
+ if ( !cg.predictedPlayerState.ammo[ item->giTag ] ) {
+ cg.predictedPlayerState.ammo[ item->giTag ] = 1;
+ }
+ }
+ }
+}
+
+
+/*
+=========================
+CG_TouchTriggerPrediction
+
+Predict push triggers and items
+=========================
+*/
+static void CG_TouchTriggerPrediction( void ) {
+ int i;
+ trace_t trace;
+ entityState_t *ent;
+ clipHandle_t cmodel;
+ centity_t *cent;
+ qboolean spectator;
+
+ // dead clients don't activate triggers
+ if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
+ return;
+ }
+
+ spectator = ( cg.predictedPlayerState.pm_type == PM_SPECTATOR );
+
+ if ( cg.predictedPlayerState.pm_type != PM_NORMAL && !spectator ) {
+ return;
+ }
+
+ for ( i = 0 ; i < cg_numTriggerEntities ; i++ ) {
+ cent = cg_triggerEntities[ i ];
+ ent = ¢->currentState;
+
+ if ( ent->eType == ET_ITEM && !spectator ) {
+ CG_TouchItem( cent );
+ continue;
+ }
+
+ if ( ent->solid != SOLID_BMODEL ) {
+ continue;
+ }
+
+ cmodel = trap_CM_InlineModel( ent->modelindex );
+ if ( !cmodel ) {
+ continue;
+ }
+
+ trap_CM_BoxTrace( &trace, cg.predictedPlayerState.origin, cg.predictedPlayerState.origin,
+ cg_pmove.mins, cg_pmove.maxs, cmodel, -1 );
+
+ if ( !trace.startsolid ) {
+ continue;
+ }
+
+ if ( ent->eType == ET_TELEPORT_TRIGGER ) {
+ cg.hyperspace = qtrue;
+ } else if ( ent->eType == ET_PUSH_TRIGGER ) {
+ BG_TouchJumpPad( &cg.predictedPlayerState, ent );
+ }
+ }
+
+ // if we didn't touch a jump pad this pmove frame
+ if ( cg.predictedPlayerState.jumppad_frame != cg.predictedPlayerState.pmove_framecount ) {
+ cg.predictedPlayerState.jumppad_frame = 0;
+ cg.predictedPlayerState.jumppad_ent = 0;
+ }
+}
+
+//unlagged - optimized prediction
+#define ABS(x) ((x) < 0 ? (-(x)) : (x))
+
+static int IsUnacceptableError( playerState_t *ps, playerState_t *pps ) {
+ vec3_t delta;
+ int i;
+
+ if ( pps->pm_type != ps->pm_type ||
+ pps->pm_flags != ps->pm_flags ||
+ pps->pm_time != ps->pm_time ) {
+ return 1;
+ }
+
+ VectorSubtract( pps->origin, ps->origin, delta );
+ if ( VectorLengthSquared( delta ) > 0.1f * 0.1f ) {
+ if ( cg_showmiss.integer ) {
+ CG_Printf("delta: %.2f ", VectorLength(delta) );
+ }
+ return 2;
+ }
+
+ VectorSubtract( pps->velocity, ps->velocity, delta );
+ if ( VectorLengthSquared( delta ) > 0.1f * 0.1f ) {
+ if ( cg_showmiss.integer ) {
+ CG_Printf("delta: %.2f ", VectorLength(delta) );
+ }
+ return 3;
+ }
+
+ if ( pps->weaponTime != ps->weaponTime ||
+ pps->gravity != ps->gravity ||
+ pps->speed != ps->speed ||
+ pps->delta_angles[0] != ps->delta_angles[0] ||
+ pps->delta_angles[1] != ps->delta_angles[1] ||
+ pps->delta_angles[2] != ps->delta_angles[2] ||
+ pps->groundEntityNum != ps->groundEntityNum ) {
+ return 4;
+ }
+
+ if ( pps->legsTimer != ps->legsTimer ||
+ pps->legsAnim != ps->legsAnim ||
+ pps->torsoTimer != ps->torsoTimer ||
+ pps->torsoAnim != ps->torsoAnim ||
+ pps->movementDir != ps->movementDir ) {
+ return 5;
+ }
+
+ VectorSubtract( pps->grapplePoint, ps->grapplePoint, delta );
+ if ( VectorLengthSquared( delta ) > 0.1f * 0.1f ) {
+ return 6;
+ }
+
+ if ( pps->eFlags != ps->eFlags ) {
+ return 7;
+ }
+
+ if ( pps->eventSequence != ps->eventSequence ) {
+ return 8;
+ }
+
+ for ( i = 0; i < MAX_PS_EVENTS; i++ ) {
+ if ( pps->events[i] != ps->events[i] ||
+ pps->eventParms[i] != ps->eventParms[i] ) {
+ return 9;
+ }
+ }
+
+ if ( pps->externalEvent != ps->externalEvent ||
+ pps->externalEventParm != ps->externalEventParm ||
+ pps->externalEventTime != ps->externalEventTime ) {
+ return 10;
+ }
+
+ if ( pps->clientNum != ps->clientNum ||
+ pps->weapon != ps->weapon ||
+ pps->weaponstate != ps->weaponstate ) {
+ return 11;
+ }
+
+ if ( ABS(pps->viewangles[0] - ps->viewangles[0]) > 1.0f ||
+ ABS(pps->viewangles[1] - ps->viewangles[1]) > 1.0f ||
+ ABS(pps->viewangles[2] - ps->viewangles[2]) > 1.0f ) {
+ return 12;
+ }
+
+ if ( pps->viewheight != ps->viewheight ) {
+ return 13;
+ }
+
+ if ( pps->damageEvent != ps->damageEvent ||
+ pps->damageYaw != ps->damageYaw ||
+ pps->damagePitch != ps->damagePitch ||
+ pps->damageCount != ps->damageCount ) {
+ return 14;
+ }
+
+ for ( i = 0; i < MAX_STATS; i++ ) {
+ if ( pps->stats[i] != ps->stats[i] ) {
+ return 15;
+ }
+ }
+
+ for ( i = 0; i < MAX_PERSISTANT; i++ ) {
+ if ( pps->persistant[i] != ps->persistant[i] ) {
+ return 16;
+ }
+ }
+
+ for ( i = 0; i < MAX_POWERUPS; i++ ) {
+ if ( pps->powerups[i] != ps->powerups[i] ) {
+ return 17;
+ }
+ }
+
+ for ( i = 0; i < MAX_WEAPONS; i++ ) {
+ if ( pps->ammo[i] != ps->ammo[i] ) {
+ return 18;
+ }
+ }
+
+ if ( pps->generic1 != ps->generic1 ||
+ pps->loopSound != ps->loopSound ||
+ pps->jumppad_ent != ps->jumppad_ent ) {
+ return 19;
+ }
+
+ return 0;
+}
+//unlagged - optimized prediction
+
+/*
+=================
+CG_PredictPlayerState
+
+Generates cg.predictedPlayerState for the current cg.time
+cg.predictedPlayerState is guaranteed to be valid after exiting.
+
+For demo playback, this will be an interpolation between two valid
+playerState_t.
+
+For normal gameplay, it will be the result of predicted usercmd_t on
+top of the most recent playerState_t received from the server.
+
+Each new snapshot will usually have one or more new usercmd over the last,
+but we simulate all unacknowledged commands each time, not just the new ones.
+This means that on an internet connection, quite a few pmoves may be issued
+each frame.
+
+OPTIMIZE: don't re-simulate unless the newly arrived snapshot playerState_t
+differs from the predicted one. Would require saving all intermediate
+playerState_t during prediction.
+
+We detect prediction errors and allow them to be decayed off over several frames
+to ease the jerk.
+=================
+*/
+void CG_PredictPlayerState( void ) {
+ int cmdNum, current;
+ playerState_t oldPlayerState;
+ qboolean moved;
+ usercmd_t oldestCmd;
+ usercmd_t latestCmd;
+//unlagged - optimized prediction
+ int stateIndex = 0, predictCmd = 0; //Sago: added initializing
+ int numPredicted = 0, numPlayedBack = 0; // debug code
+//unlagged - optimized prediction
+
+ cg.hyperspace = qfalse; // will be set if touching a trigger_teleport
+
+ // if this is the first frame we must guarantee
+ // predictedPlayerState is valid even if there is some
+ // other error condition
+ if ( !cg.validPPS ) {
+ cg.validPPS = qtrue;
+ cg.predictedPlayerState = cg.snap->ps;
+ }
+
+
+ // demo playback just copies the moves
+ if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
+ CG_InterpolatePlayerState( qfalse );
+ return;
+ }
+
+ // non-predicting local movement will grab the latest angles
+ if ( cg_nopredict.integer || cg_synchronousClients.integer ) {
+ CG_InterpolatePlayerState( qtrue );
+ return;
+ }
+
+ // prepare for pmove
+ cg_pmove.ps = &cg.predictedPlayerState;
+ cg_pmove.trace = CG_Trace;
+ cg_pmove.pointcontents = CG_PointContents;
+ if ( cg_pmove.ps->pm_type == PM_DEAD ) {
+ cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
+ }
+ else {
+ cg_pmove.tracemask = MASK_PLAYERSOLID;
+ }
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
+ cg_pmove.tracemask &= ~CONTENTS_BODY; // spectators can fly through bodies
+ }
+ cg_pmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0;
+
+ // save the state before the pmove so we can detect transitions
+ oldPlayerState = cg.predictedPlayerState;
+
+ current = trap_GetCurrentCmdNumber();
+
+ // if we don't have the commands right after the snapshot, we
+ // can't accurately predict a current position, so just freeze at
+ // the last good position we had
+ cmdNum = current - CMD_BACKUP + 1;
+ trap_GetUserCmd( cmdNum, &oldestCmd );
+ if ( oldestCmd.serverTime > cg.snap->ps.commandTime
+ && oldestCmd.serverTime < cg.time ) { // special check for map_restart
+ if ( cg_showmiss.integer ) {
+ CG_Printf ("exceeded PACKET_BACKUP on commands\n");
+ }
+ return;
+ }
+
+ // get the latest command so we can know which commands are from previous map_restarts
+ trap_GetUserCmd( current, &latestCmd );
+
+ // get the most recent information we have, even if
+ // the server time is beyond our current cg.time,
+ // because predicted player positions are going to
+ // be ahead of everything else anyway
+ if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
+ cg.predictedPlayerState = cg.nextSnap->ps;
+ cg.physicsTime = cg.nextSnap->serverTime;
+ } else {
+ cg.predictedPlayerState = cg.snap->ps;
+ cg.physicsTime = cg.snap->serverTime;
+ }
+
+ if ( pmove_msec.integer < 8 ) {
+ trap_Cvar_Set("pmove_msec", "8");
+ }
+ else if (pmove_msec.integer > 33) {
+ trap_Cvar_Set("pmove_msec", "33");
+ }
+
+ cg_pmove.pmove_fixed = pmove_fixed.integer;// | cg_pmove_fixed.integer;
+ cg_pmove.pmove_msec = pmove_msec.integer;
+ cg_pmove.pmove_float = pmove_float.integer;
+ cg_pmove.pmove_flags = cgs.dmflags;
+
+
+//unlagged - optimized prediction
+ // Like the comments described above, a player's state is entirely
+ // re-predicted from the last valid snapshot every client frame, which
+ // can be really, really, really slow. Every old command has to be
+ // run again. For every client frame that is *not* directly after a
+ // snapshot, this is unnecessary, since we have no new information.
+ // For those, we'll play back the predictions from the last frame and
+ // predict only the newest commands. Essentially, we'll be doing
+ // an incremental predict instead of a full predict.
+ //
+ // If we have a new snapshot, we can compare its player state's command
+ // time to the command times in the queue to find a match. If we find
+ // a matching state, and the predicted version has not deviated, we can
+ // use the predicted state as a base - and also do an incremental predict.
+ //
+ // With this method, we get incremental predicts on every client frame
+ // except a frame following a new snapshot in which there was a prediction
+ // error. This yeilds anywhere from a 15% to 40% performance increase,
+ // depending on how much of a bottleneck the CPU is.
+
+ if ( cg_optimizePrediction.integer ) {
+ if ( cg.nextFrameTeleport || cg.thisFrameTeleport ) {
+ // do a full predict
+ cg.lastPredictedCommand = 0;
+ cg.stateTail = cg.stateHead;
+ predictCmd = current - CMD_BACKUP + 1;
+ }
+ // cg.physicsTime is the current snapshot's serverTime
+ // if it's the same as the last one
+ else if ( cg.physicsTime == cg.lastServerTime ) {
+ // we have no new information, so do an incremental predict
+ predictCmd = cg.lastPredictedCommand + 1;
+ }
+ else {
+ // we have a new snapshot
+
+ int i;
+ qboolean error = qtrue;
+
+ // loop through the saved states queue
+ for ( i = cg.stateHead; i != cg.stateTail; i = (i + 1) % NUM_SAVED_STATES ) {
+ // if we find a predicted state whose commandTime matches the snapshot player state's commandTime
+ if ( cg.savedPmoveStates[i].commandTime == cg.predictedPlayerState.commandTime ) {
+ // make sure the state differences are acceptable
+ int errorcode = IsUnacceptableError( &cg.predictedPlayerState, &cg.savedPmoveStates[i] );
+
+ // too much change?
+ if ( errorcode ) {
+ if ( cg_showmiss.integer ) {
+ CG_Printf("errorcode %d at %d\n", errorcode, cg.time);
+ }
+ // yeah, so do a full predict
+ break;
+ }
+
+ // this one is almost exact, so we'll copy it in as the starting point
+ *cg_pmove.ps = cg.savedPmoveStates[i];
+ // advance the head
+ cg.stateHead = (i + 1) % NUM_SAVED_STATES;
+
+ // set the next command to predict
+ predictCmd = cg.lastPredictedCommand + 1;
+
+ // a saved state matched, so flag it
+ error = qfalse;
+ break;
+ }
+ }
+
+ // if no saved states matched
+ if ( error ) {
+ // do a full predict
+ cg.lastPredictedCommand = 0;
+ cg.stateTail = cg.stateHead;
+ predictCmd = current - CMD_BACKUP + 1;
+ }
+ }
+
+ // keep track of the server time of the last snapshot so we
+ // know when we're starting from a new one in future calls
+ cg.lastServerTime = cg.physicsTime;
+ stateIndex = cg.stateHead;
+ }
+//unlagged - optimized prediction
+
+ // run cmds
+ moved = qfalse;
+ for ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) {
+ // get the command
+ trap_GetUserCmd( cmdNum, &cg_pmove.cmd );
+
+ if ( cg_pmove.pmove_fixed ) {
+ PM_UpdateViewAngles( cg_pmove.ps, &cg_pmove.cmd );
+ }
+
+ // don't do anything if the time is before the snapshot player time
+ if ( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime ) {
+ continue;
+ }
+
+ // don't do anything if the command was from a previous map_restart
+ if ( cg_pmove.cmd.serverTime > latestCmd.serverTime ) {
+ continue;
+ }
+
+ // check for a prediction error from last frame
+ // on a lan, this will often be the exact value
+ // from the snapshot, but on a wan we will have
+ // to predict several commands to get to the point
+ // we want to compare
+ if ( cg.predictedPlayerState.commandTime == oldPlayerState.commandTime ) {
+ vec3_t delta;
+ float len;
+
+ if ( cg.thisFrameTeleport ) {
+ // a teleport will not cause an error decay
+ VectorClear( cg.predictedError );
+ if ( cg_showmiss.integer ) {
+ CG_Printf( "PredictionTeleport\n" );
+ }
+ cg.thisFrameTeleport = qfalse;
+ } else {
+ vec3_t adjusted;
+ CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
+ cg.predictedPlayerState.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted );
+
+ if ( cg_showmiss.integer ) {
+ if (!VectorCompare( oldPlayerState.origin, adjusted )) {
+ CG_Printf("prediction error\n");
+ }
+ }
+ VectorSubtract( oldPlayerState.origin, adjusted, delta );
+ len = VectorLength( delta );
+ if ( len > 0.1 ) {
+ if ( cg_showmiss.integer ) {
+ CG_Printf("Prediction miss: %f\n", len);
+ }
+ if ( cg_errorDecay.integer ) {
+ int t;
+ float f;
+
+ t = cg.time - cg.predictedErrorTime;
+ f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
+ if ( f < 0 ) {
+ f = 0;
+ }
+ if ( f > 0 && cg_showmiss.integer ) {
+ CG_Printf("Double prediction decay: %f\n", f);
+ }
+ VectorScale( cg.predictedError, f, cg.predictedError );
+ } else {
+ VectorClear( cg.predictedError );
+ }
+ VectorAdd( delta, cg.predictedError, cg.predictedError );
+ cg.predictedErrorTime = cg.oldTime;
+ }
+ }
+ }
+
+ // don't predict gauntlet firing, which is only supposed to happen
+ // when it actually inflicts damage
+ cg_pmove.gauntletHit = qfalse;
+
+ if ( cg_pmove.pmove_fixed ) {
+ cg_pmove.cmd.serverTime = ((cg_pmove.cmd.serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;
+ }
+
+//unlagged - optimized prediction
+ if ( cg_optimizePrediction.integer ) {
+ // if we need to predict this command, or we've run out of space in the saved states queue
+ if ( cmdNum >= predictCmd || (stateIndex + 1) % NUM_SAVED_STATES == cg.stateHead ) {
+ // run the Pmove
+ Pmove (&cg_pmove);
+
+ numPredicted++; // debug code
+
+ // record the last predicted command
+ cg.lastPredictedCommand = cmdNum;
+
+ // if we haven't run out of space in the saved states queue
+ if ( (stateIndex + 1) % NUM_SAVED_STATES != cg.stateHead ) {
+ // save the state for the false case (of cmdNum >= predictCmd)
+ // in later calls to this function
+ cg.savedPmoveStates[stateIndex] = *cg_pmove.ps;
+ stateIndex = (stateIndex + 1) % NUM_SAVED_STATES;
+ cg.stateTail = stateIndex;
+ }
+ }
+ else {
+ numPlayedBack++; // debug code
+
+ if ( cg_showmiss.integer &&
+ cg.savedPmoveStates[stateIndex].commandTime != cg_pmove.cmd.serverTime) {
+ // this should ONLY happen just after changing the value of pmove_fixed
+ CG_Printf( "saved state miss\n" );
+ }
+
+ // play back the command from the saved states
+ *cg_pmove.ps = cg.savedPmoveStates[stateIndex];
+
+ // go to the next element in the saved states array
+ stateIndex = (stateIndex + 1) % NUM_SAVED_STATES;
+ }
+ }
+ else {
+ // run the Pmove
+ Pmove (&cg_pmove);
+
+ numPredicted++; // debug code
+ }
+//unlagged - optimized prediction
+
+ moved = qtrue;
+
+ // add push trigger movement effects
+ CG_TouchTriggerPrediction();
+
+ // check for predictable events that changed from previous predictions
+ //CG_CheckChangedPredictableEvents(&cg.predictedPlayerState);
+ }
+
+//unlagged - optimized prediction
+ // do a /condump after a few seconds of this
+ //CG_Printf("cg.time: %d, numPredicted: %d, numPlayedBack: %d\n", cg.time, numPredicted, numPlayedBack); // debug code
+ // if everything is working right, numPredicted should be 1 more than 98%
+ // of the time, meaning only ONE predicted move was done in the frame
+ // you should see other values for numPredicted after IsUnacceptableError
+ // returns nonzero, and that's it
+//unlagged - optimized prediction
+
+ if ( cg_showmiss.integer > 1 ) {
+ CG_Printf( "[%i : %i] ", cg_pmove.cmd.serverTime, cg.time );
+ }
+
+ if ( !moved ) {
+ if ( cg_showmiss.integer ) {
+ CG_Printf( "not moved\n" );
+ }
+ return;
+ }
+
+ // adjust for the movement of the groundentity
+ CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
+ cg.predictedPlayerState.groundEntityNum,
+ cg.physicsTime, cg.time, cg.predictedPlayerState.origin );
+
+ if ( cg_showmiss.integer ) {
+ if (cg.predictedPlayerState.eventSequence > oldPlayerState.eventSequence + MAX_PS_EVENTS) {
+ CG_Printf("WARNING: dropped event\n");
+ }
+ }
+
+ // fire events and other transition triggered things
+ CG_TransitionPlayerState( &cg.predictedPlayerState, &oldPlayerState );
+
+ if ( cg_showmiss.integer ) {
+ if (cg.eventSequence > cg.predictedPlayerState.eventSequence) {
+ CG_Printf("WARNING: double event\n");
+ cg.eventSequence = cg.predictedPlayerState.eventSequence;
+ }
+ }
+}
+
+
diff --git a/engine/code/cgame/cg_public.h b/code/cgame/cg_public.h
similarity index 100%
rename from engine/code/cgame/cg_public.h
rename to code/cgame/cg_public.h
diff --git a/code/cgame/cg_scoreboard.c b/code/cgame/cg_scoreboard.c
new file mode 100644
index 0000000..29a7f1c
--- /dev/null
+++ b/code/cgame/cg_scoreboard.c
@@ -0,0 +1,553 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_scoreboard -- draw the scoreboard on top of the game screen
+#include "cg_local.h"
+
+
+#define SCOREBOARD_X (0)
+
+#define SB_HEADER 86
+#define SB_TOP (SB_HEADER+32)
+
+// Where the status bar starts, so we don't overwrite it
+#define SB_STATUSBAR 420
+
+#define SB_NORMAL_HEIGHT 40
+#define SB_INTER_HEIGHT 16 // interleaved height
+
+#define SB_MAXCLIENTS_NORMAL ((SB_STATUSBAR - SB_TOP) / SB_NORMAL_HEIGHT)
+#define SB_MAXCLIENTS_INTER ((SB_STATUSBAR - SB_TOP) / SB_INTER_HEIGHT - 1)
+
+// Used when interleaved
+
+
+
+#define SB_LEFT_BOTICON_X (SCOREBOARD_X+0)
+#define SB_LEFT_HEAD_X (SCOREBOARD_X+32)
+#define SB_RIGHT_BOTICON_X (SCOREBOARD_X+64)
+#define SB_RIGHT_HEAD_X (SCOREBOARD_X+96)
+// Normal
+#define SB_BOTICON_X (SCOREBOARD_X+32)
+#define SB_HEAD_X (SCOREBOARD_X+64)
+
+#define SB_SCORELINE_X 112
+
+#define SB_RATING_WIDTH (6 * BIGCHAR_WIDTH) // width 6
+#define SB_SCORE_X (SB_SCORELINE_X + BIGCHAR_WIDTH) // width 6
+#define SB_RATING_X (SB_SCORELINE_X + 6 * BIGCHAR_WIDTH) // width 6
+#define SB_PING_X (SB_SCORELINE_X + 12 * BIGCHAR_WIDTH + 8) // width 5
+#define SB_TIME_X (SB_SCORELINE_X + 17 * BIGCHAR_WIDTH + 8) // width 5
+#define SB_NAME_X (SB_SCORELINE_X + 22 * BIGCHAR_WIDTH) // width 15
+
+// The new and improved score board
+//
+// In cases where the number of clients is high, the score board heads are interleaved
+// here's the layout
+
+//
+// 0 32 80 112 144 240 320 400 <-- pixel position
+// bot head bot head score ping time name
+//
+// wins/losses are drawn on bot icon now
+
+static qboolean localClient; // true if local client has been displayed
+
+
+ /*
+=================
+CG_DrawScoreboard
+=================
+*/
+static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) {
+ char string[1024];
+ vec3_t headAngles;
+ clientInfo_t *ci;
+ int iconx, headx;
+
+ if ( score->client < 0 || score->client >= cgs.maxclients ) {
+ Com_Printf( "Bad score->client: %i\n", score->client );
+ return;
+ }
+
+ ci = &cgs.clientinfo[score->client];
+
+ iconx = SB_BOTICON_X + (SB_RATING_WIDTH / 2);
+ headx = SB_HEAD_X + (SB_RATING_WIDTH / 2);
+
+ // draw the handicap or bot skill marker (unless player has flag)
+ if ( ci->powerups & ( 1 << PW_NEUTRALFLAG ) ) {
+ if( largeFormat ) {
+ CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_FREE, qfalse );
+ }
+ else {
+ CG_DrawFlagModel( iconx, y, 16, 16, TEAM_FREE, qfalse );
+ }
+ } else if ( ci->powerups & ( 1 << PW_REDFLAG ) ) {
+ if( largeFormat ) {
+ CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_RED, qfalse );
+ }
+ else {
+ CG_DrawFlagModel( iconx, y, 16, 16, TEAM_RED, qfalse );
+ }
+ } else if ( ci->powerups & ( 1 << PW_BLUEFLAG ) ) {
+ if( largeFormat ) {
+ CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_BLUE, qfalse );
+ }
+ else {
+ CG_DrawFlagModel( iconx, y, 16, 16, TEAM_BLUE, qfalse );
+ }
+ } else {
+ if ( ci->botSkill > 0 && ci->botSkill <= 5 ) {
+ if ( cg_drawIcons.integer ) {
+ if( largeFormat ) {
+ CG_DrawPic( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
+ }
+ else {
+ CG_DrawPic( iconx, y, 16, 16, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
+ }
+ }
+ } else if ( ci->handicap < 100 ) {
+ Com_sprintf( string, sizeof( string ), "%i", ci->handicap );
+ if ( cgs.gametype == GT_TOURNAMENT )
+ CG_DrawSmallStringColor( iconx, y - SMALLCHAR_HEIGHT/2, string, color );
+ else
+ CG_DrawSmallStringColor( iconx, y, string, color );
+ }
+
+ // draw the wins / losses
+ if ( cgs.gametype == GT_TOURNAMENT ) {
+ Com_sprintf( string, sizeof( string ), "%i/%i", ci->wins, ci->losses );
+ if( ci->handicap < 100 && !ci->botSkill ) {
+ CG_DrawSmallStringColor( iconx, y + SMALLCHAR_HEIGHT/2, string, color );
+ }
+ else {
+ CG_DrawSmallStringColor( iconx, y, string, color );
+ }
+ }
+ }
+
+ // draw the face
+ VectorClear( headAngles );
+ headAngles[YAW] = 180;
+ if( largeFormat ) {
+ CG_DrawHead( headx, y - ( ICON_SIZE - BIGCHAR_HEIGHT ) / 2, ICON_SIZE, ICON_SIZE,
+ score->client, headAngles );
+ }
+ else {
+ CG_DrawHead( headx, y, 16, 16, score->client, headAngles );
+ }
+
+#ifdef MISSIONPACK
+ // draw the team task
+ if ( ci->teamTask != TEAMTASK_NONE ) {
+ if (ci->isDead) {
+ CG_DrawPic( headx + 48, y, 16, 16, cgs.media.deathShader );
+ }
+ else if ( ci->teamTask == TEAMTASK_OFFENSE ) {
+ CG_DrawPic( headx + 48, y, 16, 16, cgs.media.assaultShader );
+ }
+ else if ( ci->teamTask == TEAMTASK_DEFENSE ) {
+ CG_DrawPic( headx + 48, y, 16, 16, cgs.media.defendShader );
+ }
+ }
+#endif
+ // draw the score line
+ if ( score->ping == -1 ) {
+ Com_sprintf(string, sizeof(string),
+ " connecting %s", ci->name);
+ } else if ( ci->team == TEAM_SPECTATOR ) {
+ Com_sprintf(string, sizeof(string),
+ " SPECT %3i %4i %s", score->ping, score->time, ci->name);
+ } else {
+ /*if(cgs.gametype == GT_LMS)
+ Com_sprintf(string, sizeof(string),
+ "%5i %4i %4i %s *%i*", score->score, score->ping, score->time, ci->name, ci->isDead);
+ else*/
+ /*if(ci->isDead)
+ Com_sprintf(string, sizeof(string),
+ "%5i %4i %4i %s *DEAD*", score->score, score->ping, score->time, ci->name);
+ else*/
+ Com_sprintf(string, sizeof(string),
+ "%5i %4i %4i %s", score->score, score->ping, score->time, ci->name);
+ }
+
+ // highlight your position
+ if ( score->client == cg.snap->ps.clientNum ) {
+ float hcolor[4];
+ int rank;
+
+ localClient = qtrue;
+
+ if ( ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) ||
+ ( ( cgs.gametype >= GT_TEAM ) &&
+ ( cgs.ffa_gt != 1 ) ) ) {
+ // Sago: I think this means that it doesn't matter if two players are tied in team game - only team score counts
+ rank = -1;
+ } else {
+ rank = cg.snap->ps.persistant[PERS_RANK] & ~RANK_TIED_FLAG;
+ }
+ if ( rank == 0 ) {
+ hcolor[0] = 0;
+ hcolor[1] = 0;
+ hcolor[2] = 0.7f;
+ } else if ( rank == 1 ) {
+ hcolor[0] = 0.7f;
+ hcolor[1] = 0;
+ hcolor[2] = 0;
+ } else if ( rank == 2 ) {
+ hcolor[0] = 0.7f;
+ hcolor[1] = 0.7f;
+ hcolor[2] = 0;
+ } else {
+ hcolor[0] = 0.7f;
+ hcolor[1] = 0.7f;
+ hcolor[2] = 0.7f;
+ }
+
+ hcolor[3] = fade * 0.7;
+ CG_FillRect( SB_SCORELINE_X + BIGCHAR_WIDTH + (SB_RATING_WIDTH / 2), y,
+ 640 - SB_SCORELINE_X - BIGCHAR_WIDTH, BIGCHAR_HEIGHT+1, hcolor );
+ }
+
+ CG_DrawBigString( SB_SCORELINE_X + (SB_RATING_WIDTH / 2), y, string, fade );
+
+ // add the "ready" marker for intermission exiting
+ if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) ) {
+ CG_DrawBigStringColor( iconx, y, "READY", color );
+ } else
+ if(cgs.gametype == GT_LMS) {
+ CG_DrawBigStringColor( iconx-50, y, va("*%i*",ci->isDead), color );
+ } else
+ if(ci->isDead) {
+ CG_DrawBigStringColor( iconx-60, y, "DEAD", color );
+ }
+}
+
+/*
+=================
+CG_TeamScoreboard
+=================
+*/
+static int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, int lineHeight ) {
+ int i;
+ score_t *score;
+ float color[4];
+ int count;
+ clientInfo_t *ci;
+
+ color[0] = color[1] = color[2] = 1.0;
+ color[3] = fade;
+
+ count = 0;
+ for ( i = 0 ; i < cg.numScores && count < maxClients ; i++ ) {
+ score = &cg.scores[i];
+ ci = &cgs.clientinfo[ score->client ];
+
+ if ( team != ci->team ) {
+ continue;
+ }
+
+ CG_DrawClientScore( y + lineHeight * count, score, color, fade, lineHeight == SB_NORMAL_HEIGHT );
+
+ count++;
+ }
+
+ return count;
+}
+
+/*
+=================
+CG_DrawScoreboard
+
+Draw the normal in-game scoreboard
+=================
+*/
+qboolean CG_DrawOldScoreboard( void ) {
+ int x, y, w, i, n1, n2;
+ float fade;
+ float *fadeColor;
+ char *s;
+ int maxClients;
+ int lineHeight;
+ int topBorderSize, bottomBorderSize;
+
+ // don't draw amuthing if the menu or console is up
+ if ( cg_paused.integer ) {
+ cg.deferredPlayerLoading = 0;
+ return qfalse;
+ }
+
+ if ( cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
+ cg.deferredPlayerLoading = 0;
+ return qfalse;
+ }
+
+ // don't draw scoreboard during death while warmup up
+ if ( cg.warmup && !cg.showScores ) {
+ return qfalse;
+ }
+
+ if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD ||
+ cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
+ fade = 1.0;
+ fadeColor = colorWhite;
+ } else {
+ fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
+
+ if ( !fadeColor ) {
+ // next time scoreboard comes up, don't print killer
+ cg.deferredPlayerLoading = 0;
+ cg.killerName[0] = 0;
+ return qfalse;
+ }
+ fade = *fadeColor;
+ }
+
+
+ // fragged by ... line
+ if ( cg.killerName[0] ) {
+ s = va("Fragged by %s", cg.killerName );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ x = ( SCREEN_WIDTH - w ) / 2;
+ y = 40;
+ CG_DrawBigString( x, y, s, fade );
+ }
+
+ // current rank
+ if ( cgs.gametype < GT_TEAM || cgs.ffa_gt == 1) {
+ if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
+ s = va("%s place with %i",
+ CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
+ cg.snap->ps.persistant[PERS_SCORE] );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ x = ( SCREEN_WIDTH - w ) / 2;
+ y = 60;
+ CG_DrawBigString( x, y, s, fade );
+ }
+ } else {
+ if ( cg.teamScores[0] == cg.teamScores[1] ) {
+ s = va("Teams are tied at %i", cg.teamScores[0] );
+ } else if ( cg.teamScores[0] >= cg.teamScores[1] ) {
+ s = va("Red leads %i to %i",cg.teamScores[0], cg.teamScores[1] );
+ } else {
+ s = va("Blue leads %i to %i",cg.teamScores[1], cg.teamScores[0] );
+ }
+
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ x = ( SCREEN_WIDTH - w ) / 2;
+ y = 60;
+ CG_DrawBigString( x, y, s, fade );
+ }
+
+ // scoreboard
+ y = SB_HEADER;
+
+ CG_DrawPic( SB_SCORE_X + (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardScore );
+ CG_DrawPic( SB_PING_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardPing );
+ CG_DrawPic( SB_TIME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardTime );
+ CG_DrawPic( SB_NAME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardName );
+
+ y = SB_TOP;
+
+ // If there are more than SB_MAXCLIENTS_NORMAL, use the interleaved scores
+ if ( cg.numScores > SB_MAXCLIENTS_NORMAL ) {
+ maxClients = SB_MAXCLIENTS_INTER;
+ lineHeight = SB_INTER_HEIGHT;
+ topBorderSize = 8;
+ bottomBorderSize = 16;
+ } else {
+ maxClients = SB_MAXCLIENTS_NORMAL;
+ lineHeight = SB_NORMAL_HEIGHT;
+ topBorderSize = 16;
+ bottomBorderSize = 16;
+ }
+
+ localClient = qfalse;
+
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ //
+ // teamplay scoreboard
+ //
+ y += lineHeight/2;
+
+ if ( cg.teamScores[0] >= cg.teamScores[1] ) {
+ n1 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
+ CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );
+ y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
+ maxClients -= n1;
+ n2 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
+ CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );
+ y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
+ maxClients -= n2;
+ } else {
+ n1 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
+ CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );
+ y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
+ maxClients -= n1;
+ n2 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
+ CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );
+ y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
+ maxClients -= n2;
+ }
+ n1 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients, lineHeight );
+ y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
+
+ } else {
+ //
+ // free for all scoreboard
+ //
+ n1 = CG_TeamScoreboard( y, TEAM_FREE, fade, maxClients, lineHeight );
+ y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
+ n2 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients - n1, lineHeight );
+ y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
+ }
+
+ if (!localClient) {
+ // draw local client at the bottom
+ for ( i = 0 ; i < cg.numScores ; i++ ) {
+ if ( cg.scores[i].client == cg.snap->ps.clientNum ) {
+ CG_DrawClientScore( y, &cg.scores[i], fadeColor, fade, lineHeight == SB_NORMAL_HEIGHT );
+ break;
+ }
+ }
+ }
+
+ // load any models that have been deferred
+ if ( ++cg.deferredPlayerLoading > 10 ) {
+ CG_LoadDeferredPlayers();
+ }
+
+ return qtrue;
+}
+
+//================================================================================
+
+/*
+================
+CG_CenterGiantLine
+================
+*/
+static void CG_CenterGiantLine( float y, const char *string ) {
+ float x;
+ vec4_t color;
+
+ color[0] = 1;
+ color[1] = 1;
+ color[2] = 1;
+ color[3] = 1;
+
+ x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( string ) );
+
+ CG_DrawStringExt( x, y, string, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+}
+
+/*
+=================
+CG_DrawTourneyScoreboard
+
+Draw the oversize scoreboard for tournements
+=================
+*/
+void CG_DrawOldTourneyScoreboard( void ) {
+ const char *s;
+ vec4_t color;
+ int min, tens, ones;
+ clientInfo_t *ci;
+ int y;
+ int i;
+
+ // request more scores regularly
+ if ( cg.scoresRequestTime + 2000 < cg.time ) {
+ cg.scoresRequestTime = cg.time;
+ trap_SendClientCommand( "score" );
+ }
+
+ // draw the dialog background
+ color[0] = color[1] = color[2] = 0;
+ color[3] = 1;
+ CG_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, color );
+
+ color[0] = 1;
+ color[1] = 1;
+ color[2] = 1;
+ color[3] = 1;
+
+ // print the mesage of the day
+ s = CG_ConfigString( CS_MOTD );
+ if ( !s[0] ) {
+ s = "Scoreboard";
+ }
+
+ // print optional title
+ CG_CenterGiantLine( 8, s );
+
+ // print server time
+ ones = cg.time / 1000;
+ min = ones / 60;
+ ones %= 60;
+ tens = ones / 10;
+ ones %= 10;
+ s = va("%i:%i%i", min, tens, ones );
+
+ CG_CenterGiantLine( 64, s );
+
+
+ // print the two scores
+
+ y = 160;
+ if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
+ //
+ // teamplay scoreboard
+ //
+ CG_DrawStringExt( 8, y, "Red Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+ s = va("%i", cg.teamScores[0] );
+ CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+
+ y += 64;
+
+ CG_DrawStringExt( 8, y, "Blue Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+ s = va("%i", cg.teamScores[1] );
+ CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+ } else {
+ //
+ // free for all scoreboard
+ //
+ for ( i = 0 ; i < MAX_CLIENTS ; i++ ) {
+ ci = &cgs.clientinfo[i];
+ if ( !ci->infoValid ) {
+ continue;
+ }
+ if ( ci->team != TEAM_FREE ) {
+ continue;
+ }
+
+ CG_DrawStringExt( 8, y, ci->name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+ s = va("%i", ci->score );
+ CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+ y += 64;
+ }
+ }
+
+
+}
+
diff --git a/code/cgame/cg_servercmds.c b/code/cgame/cg_servercmds.c
new file mode 100644
index 0000000..7295d9a
--- /dev/null
+++ b/code/cgame/cg_servercmds.c
@@ -0,0 +1,1402 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_servercmds.c -- reliably sequenced text commands sent by the server
+// these are processed at snapshot transition time, so there will definately
+// be a valid snapshot this frame
+
+#include "cg_local.h"
+#include "../../ui/menudef.h" // bk001205 - for Q3_ui as well
+
+typedef struct {
+ const char *order;
+ int taskNum;
+} orderTask_t;
+
+static const orderTask_t validOrders[] = {
+ { VOICECHAT_GETFLAG, TEAMTASK_OFFENSE },
+ { VOICECHAT_OFFENSE, TEAMTASK_OFFENSE },
+ { VOICECHAT_DEFEND, TEAMTASK_DEFENSE },
+ { VOICECHAT_DEFENDFLAG, TEAMTASK_DEFENSE },
+ { VOICECHAT_PATROL, TEAMTASK_PATROL },
+ { VOICECHAT_CAMP, TEAMTASK_CAMP },
+ { VOICECHAT_FOLLOWME, TEAMTASK_FOLLOW },
+ { VOICECHAT_RETURNFLAG, TEAMTASK_RETRIEVE },
+ { VOICECHAT_FOLLOWFLAGCARRIER, TEAMTASK_ESCORT }
+};
+
+static const int numValidOrders = sizeof(validOrders) / sizeof(orderTask_t);
+
+#ifdef MISSIONPACK // bk001204
+static int CG_ValidOrder(const char *p) {
+ int i;
+ for (i = 0; i < numValidOrders; i++) {
+ if (Q_stricmp(p, validOrders[i].order) == 0) {
+ return validOrders[i].taskNum;
+ }
+ }
+ return -1;
+}
+#endif
+
+/*
+=================
+CG_ParseScores
+
+=================
+*/
+static void CG_ParseScores( void ) {
+ int i, powerups;
+
+ cg.numScores = atoi( CG_Argv( 1 ) );
+ if ( cg.numScores > MAX_CLIENTS ) {
+ cg.numScores = MAX_CLIENTS;
+ }
+
+ cg.teamScores[0] = atoi( CG_Argv( 2 ) );
+ cg.teamScores[1] = atoi( CG_Argv( 3 ) );
+
+ cgs.roundStartTime = atoi( CG_Argv( 4 ) );
+
+ //Update thing in lower-right corner
+ if(cgs.gametype == GT_ELIMINATION || cgs.gametype == GT_CTF_ELIMINATION)
+ {
+ cgs.scores1 = cg.teamScores[0];
+ cgs.scores2 = cg.teamScores[1];
+ }
+
+ memset( cg.scores, 0, sizeof( cg.scores ) );
+
+#define NUM_DATA 15
+#define FIRST_DATA 4
+
+ for ( i = 0 ; i < cg.numScores ; i++ ) {
+ //
+ cg.scores[i].client = atoi( CG_Argv( i * NUM_DATA + FIRST_DATA + 1 ) );
+ cg.scores[i].score = atoi( CG_Argv( i * NUM_DATA + FIRST_DATA + 2 ) );
+ cg.scores[i].ping = atoi( CG_Argv( i * NUM_DATA + FIRST_DATA + 3 ) );
+ cg.scores[i].time = atoi( CG_Argv( i * NUM_DATA + FIRST_DATA + 4 ) );
+ cg.scores[i].scoreFlags = atoi( CG_Argv( i * NUM_DATA + FIRST_DATA + 5 ) );
+ powerups = atoi( CG_Argv( i * NUM_DATA + FIRST_DATA + 6 ) );
+ cg.scores[i].accuracy = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 7));
+ cg.scores[i].impressiveCount = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 8));
+ cg.scores[i].excellentCount = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 9));
+ cg.scores[i].guantletCount = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 10));
+ cg.scores[i].defendCount = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 11));
+ cg.scores[i].assistCount = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 12));
+ cg.scores[i].perfect = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 13));
+ cg.scores[i].captures = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 14));
+ cg.scores[i].isDead = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 15));
+ //cgs.roundStartTime =
+
+ if ( cg.scores[i].client < 0 || cg.scores[i].client >= MAX_CLIENTS ) {
+ cg.scores[i].client = 0;
+ }
+ cgs.clientinfo[ cg.scores[i].client ].score = cg.scores[i].score;
+ cgs.clientinfo[ cg.scores[i].client ].powerups = powerups;
+ cgs.clientinfo[ cg.scores[i].client ].isDead = cg.scores[i].isDead;
+
+ cg.scores[i].team = cgs.clientinfo[cg.scores[i].client].team;
+ }
+#ifdef MISSIONPACK
+ CG_SetScoreSelection(NULL);
+#endif
+
+}
+
+static void CG_ParseAccuracy( void ) {
+ int i;
+
+ for ( i = WP_MACHINEGUN ; i < WP_NUM_WEAPONS ; i++ ) {
+ cg.accuracys[i-WP_MACHINEGUN][0] = atoi( CG_Argv( (i-WP_MACHINEGUN)*2 + 1 ) );
+ cg.accuracys[i-WP_MACHINEGUN][1] = atoi( CG_Argv( (i-WP_MACHINEGUN)*2 + 2 ) );
+ #if DEBUG
+ CG_Printf("W: %i shots: %i Hits: %i\n", i,cg.accuracys[i][0], cg.accuracys[i][1]);
+ #endif
+ }
+
+}
+
+
+/*
+=================
+CG_ParseElimination
+
+=================
+*/
+static void CG_ParseElimination( void ) {
+ if(cgs.gametype == GT_ELIMINATION || cgs.gametype == GT_CTF_ELIMINATION)
+ {
+ cgs.scores1 = atoi( CG_Argv( 1 ) );
+ cgs.scores2 = atoi( CG_Argv( 2 ) );
+ }
+ cgs.roundStartTime = atoi( CG_Argv( 3 ) );
+}
+
+/*
+=================
+CG_ParseMappage
+Sago: This parses values from the server rather directly. Some checks are performed, but beware if you change it or new
+security holes are found
+=================
+*/
+static void CG_ParseMappage( void ) {
+ char command[1024];
+ const char *temp;
+ const char* c;
+ int i;
+
+ temp = CG_Argv( 1 );
+ for( c = temp; *c; ++c) {
+ switch(*c) {
+ case '\n':
+ case '\r':
+ case ';':
+ //The server tried something bad!
+ return;
+ break;
+ }
+ }
+ Q_strncpyz(command,va("ui_mappage %s",temp),1024);
+ for(i=2;i<12;i++) {
+ temp = CG_Argv( i );
+ for( c = temp; *c; ++c) {
+ switch(*c) {
+ case '\n':
+ case '\r':
+ case ';':
+ //The server tried something bad!
+ return;
+ break;
+ }
+ }
+ if(strlen(temp)<1)
+ temp = "---";
+ Q_strcat(command,1024,va(" %s ",temp));
+ }
+ trap_SendConsoleCommand(command);
+
+}
+
+/*
+=================
+CG_ParseDDtimetaken
+
+=================
+*/
+static void CG_ParseDDtimetaken( void ) {
+ cgs.timetaken = atoi( CG_Argv( 1 ) );
+}
+
+/*
+=================
+CG_ParseDomPointNames
+=================
+*/
+
+static void CG_ParseDomPointNames( void ) {
+ int i,j;
+ cgs.domination_points_count = atoi( CG_Argv( 1 ) );
+ if(cgs.domination_points_count>=MAX_DOMINATION_POINTS)
+ cgs.domination_points_count = MAX_DOMINATION_POINTS;
+ for(i = 0;i<cgs.domination_points_count;i++) {
+ Q_strncpyz(cgs.domination_points_names[i],CG_Argv(2)+i*MAX_DOMINATION_POINTS_NAMES,MAX_DOMINATION_POINTS_NAMES-1);
+ for(j=MAX_DOMINATION_POINTS_NAMES-1; cgs.domination_points_names[i][j] < '0' && j>0; j--) {
+ cgs.domination_points_names[i][j] = 0;
+ }
+ }
+}
+
+/*
+=================
+CG_ParseDomScores
+=================
+*/
+
+static void CG_ParseDomStatus( void ) {
+ int i;
+ if( cgs.domination_points_count!=atoi( CG_Argv(1) ) ) {
+ cgs.domination_points_count = 0;
+ return;
+ }
+ for(i = 0;i<cgs.domination_points_count;i++) {
+ cgs.domination_points_status[i] = atoi( CG_Argv(2+i) );
+ }
+}
+
+/*
+=================
+CG_ParseChallenge
+=================
+*/
+
+static void CG_ParseChallenge( void ) {
+ addChallenge(atoi( CG_Argv(1) ) );
+}
+
+static void CG_ParseObeliskHealth( void ) {
+ cg.redObeliskHealth = atoi( CG_Argv(1) );
+ cg.blueObeliskHealth = atoi( CG_Argv(2) );
+}
+
+/**
+ * Sets the respawn counter for the client.
+ */
+static void CG_ParseRespawnTime( void ) {
+ cg.respawnTime = atoi( CG_Argv(1) );
+}
+
+/*
+=================
+CG_ParseTeam
+=================
+*/
+
+static void CG_ParseTeam( void ) {
+ //TODO: Add code here
+ if(cg_voip_teamonly.integer)
+ trap_Cvar_Set("cl_voipSendTarget",CG_Argv(1));
+}
+
+/*
+=================
+CG_ParseAttackingTeam
+
+=================
+*/
+static void CG_ParseAttackingTeam( void ) {
+ int temp;
+ temp = atoi( CG_Argv( 1 ) );
+ if(temp==TEAM_RED)
+ cgs.attackingTeam = TEAM_RED;
+ else if (temp==TEAM_BLUE)
+ cgs.attackingTeam = TEAM_BLUE;
+ else
+ cgs.attackingTeam = TEAM_NONE; //Should never happen.
+}
+
+/*
+=================
+CG_ParseTeamInfo
+
+=================
+*/
+static void CG_ParseTeamInfo( void ) {
+ int i;
+ int client;
+
+ numSortedTeamPlayers = atoi( CG_Argv( 1 ) );
+ if( numSortedTeamPlayers < 0 || numSortedTeamPlayers > TEAM_MAXOVERLAY )
+ {
+ CG_Error( "CG_ParseTeamInfo: numSortedTeamPlayers out of range (%d)",
+ numSortedTeamPlayers );
+ return;
+ }
+
+ for ( i = 0 ; i < numSortedTeamPlayers ; i++ ) {
+ client = atoi( CG_Argv( i * 6 + 2 ) );
+ if( client < 0 || client >= MAX_CLIENTS )
+ {
+ CG_Error( "CG_ParseTeamInfo: bad client number: %d", client );
+ return;
+ }
+
+
+ sortedTeamPlayers[i] = client;
+
+ cgs.clientinfo[ client ].location = atoi( CG_Argv( i * 6 + 3 ) );
+ cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 6 + 4 ) );
+ cgs.clientinfo[ client ].armor = atoi( CG_Argv( i * 6 + 5 ) );
+ cgs.clientinfo[ client ].curWeapon = atoi( CG_Argv( i * 6 + 6 ) );
+ cgs.clientinfo[ client ].powerups = atoi( CG_Argv( i * 6 + 7 ) );
+ }
+}
+
+
+/*
+================
+CG_ParseServerinfo
+
+This is called explicitly when the gamestate is first received,
+and whenever the server updates any serverinfo flagged cvars
+================
+*/
+void CG_ParseServerinfo( void ) {
+ const char *info;
+ char *mapname;
+
+ info = CG_ConfigString( CS_SERVERINFO );
+ cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
+ //By default do as normal:
+ cgs.ffa_gt = 0;
+ //See if ffa gametype
+ if(cgs.gametype == GT_LMS)
+ cgs.ffa_gt = 1;
+ trap_Cvar_Set("g_gametype", va("%i", cgs.gametype));
+ cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) );
+ cgs.videoflags = atoi( Info_ValueForKey( info, "videoflags" ) );
+ cgs.elimflags = atoi( Info_ValueForKey( info, "elimflags" ) );
+ cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) );
+ cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) );
+ cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) );
+ cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) );
+ cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
+ cgs.roundtime = atoi( Info_ValueForKey( info, "elimination_roundtime" ) );
+ cgs.nopickup = atoi( Info_ValueForKey( info, "g_rockets" ) ) + atoi( Info_ValueForKey( info, "g_instantgib" ) ) + atoi( Info_ValueForKey( info, "g_elimination" ) );
+ cgs.lms_mode = atoi( Info_ValueForKey( info, "g_lms_mode" ) );
+ cgs.altExcellent = atoi( Info_ValueForKey( info, "g_altExcellent" ) );
+ mapname = Info_ValueForKey( info, "mapname" );
+ Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname );
+ Q_strncpyz( cgs.redTeam, Info_ValueForKey( info, "g_redTeam" ), sizeof(cgs.redTeam) );
+ trap_Cvar_Set("g_redTeam", cgs.redTeam);
+ Q_strncpyz( cgs.blueTeam, Info_ValueForKey( info, "g_blueTeam" ), sizeof(cgs.blueTeam) );
+ trap_Cvar_Set("g_blueTeam", cgs.blueTeam);
+
+//unlagged - server options
+ // we'll need this for deciding whether or not to predict weapon effects
+ cgs.delagHitscan = atoi( Info_ValueForKey( info, "g_delagHitscan" ) );
+ trap_Cvar_Set("g_delagHitscan", va("%i", cgs.delagHitscan));
+//unlagged - server options
+
+ //Copy allowed votes directly to the client:
+ trap_Cvar_Set("cg_voteflags",Info_ValueForKey( info, "voteflags" ) );
+}
+
+/*
+==================
+CG_ParseWarmup
+==================
+*/
+static void CG_ParseWarmup( void ) {
+ const char *info;
+ int warmup;
+
+ info = CG_ConfigString( CS_WARMUP );
+
+ warmup = atoi( info );
+ cg.warmupCount = -1;
+
+ if ( warmup == 0 && cg.warmup ) {
+
+ } else if ( warmup > 0 && cg.warmup <= 0 ) {
+#ifdef MISSIONPACK
+ if (cgs.gametype >= GT_CTF && cgs.gametype < GT_MAX_GAME_TYPE && !cgs.ffa_gt) {
+ trap_S_StartLocalSound( cgs.media.countPrepareTeamSound, CHAN_ANNOUNCER );
+ } else
+#endif
+ {
+ trap_S_StartLocalSound( cgs.media.countPrepareSound, CHAN_ANNOUNCER );
+ }
+ }
+
+ cg.warmup = warmup;
+}
+
+/*
+================
+CG_SetConfigValues
+
+Called on load to set the initial values from configure strings
+================
+*/
+void CG_SetConfigValues( void ) {
+ const char *s;
+
+ cgs.scores1 = atoi( CG_ConfigString( CS_SCORES1 ) );
+ cgs.scores2 = atoi( CG_ConfigString( CS_SCORES2 ) );
+ cgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) );
+ if( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION || cgs.gametype == GT_DOUBLE_D) {
+ s = CG_ConfigString( CS_FLAGSTATUS );
+ cgs.redflag = s[0] - '0';
+ cgs.blueflag = s[1] - '0';
+ }
+//#ifdef MISSIONPACK
+ else if( cgs.gametype == GT_1FCTF ) {
+ s = CG_ConfigString( CS_FLAGSTATUS );
+ cgs.flagStatus = s[0] - '0';
+ }
+//#endif
+ cg.warmup = atoi( CG_ConfigString( CS_WARMUP ) );
+}
+
+/*
+=====================
+CG_ShaderStateChanged
+=====================
+*/
+void CG_ShaderStateChanged(void) {
+ char originalShader[MAX_QPATH];
+ char newShader[MAX_QPATH];
+ char timeOffset[16];
+ const char *o;
+ char *n,*t;
+
+ o = CG_ConfigString( CS_SHADERSTATE );
+ while (o && *o) {
+ n = strstr(o, "=");
+ if (n && *n) {
+ strncpy(originalShader, o, n-o);
+ originalShader[n-o] = 0;
+ n++;
+ t = strstr(n, ":");
+ if (t && *t) {
+ strncpy(newShader, n, t-n);
+ newShader[t-n] = 0;
+ } else {
+ break;
+ }
+ t++;
+ o = strstr(t, "@");
+ if (o) {
+ strncpy(timeOffset, t, o-t);
+ timeOffset[o-t] = 0;
+ o++;
+ trap_R_RemapShader( originalShader, newShader, timeOffset );
+ }
+ } else {
+ break;
+ }
+ }
+}
+
+/*
+================
+CG_ConfigStringModified
+
+================
+*/
+static void CG_ConfigStringModified( void ) {
+ const char *str;
+ int num;
+
+ num = atoi( CG_Argv( 1 ) );
+
+ // get the gamestate from the client system, which will have the
+ // new configstring already integrated
+ trap_GetGameState( &cgs.gameState );
+
+ // look up the individual string that was modified
+ str = CG_ConfigString( num );
+
+ // do something with it if necessary
+ if ( num == CS_MUSIC ) {
+ CG_StartMusic();
+ } else if ( num == CS_SERVERINFO ) {
+ CG_ParseServerinfo();
+ } else if ( num == CS_WARMUP ) {
+ CG_ParseWarmup();
+ } else if ( num == CS_SCORES1 ) {
+ cgs.scores1 = atoi( str );
+ } else if ( num == CS_SCORES2 ) {
+ cgs.scores2 = atoi( str );
+ } else if ( num == CS_LEVEL_START_TIME ) {
+ cgs.levelStartTime = atoi( str );
+ } else if ( num == CS_VOTE_TIME ) {
+ cgs.voteTime = atoi( str );
+ cgs.voteModified = qtrue;
+ } else if ( num == CS_VOTE_YES ) {
+ cgs.voteYes = atoi( str );
+ cgs.voteModified = qtrue;
+ } else if ( num == CS_VOTE_NO ) {
+ cgs.voteNo = atoi( str );
+ cgs.voteModified = qtrue;
+ } else if ( num == CS_VOTE_STRING ) {
+ Q_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) );
+#ifdef MISSIONPACK
+ trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER );
+#endif //MISSIONPACK
+ } else if ( num >= CS_TEAMVOTE_TIME && num <= CS_TEAMVOTE_TIME + 1) {
+ cgs.teamVoteTime[num-CS_TEAMVOTE_TIME] = atoi( str );
+ cgs.teamVoteModified[num-CS_TEAMVOTE_TIME] = qtrue;
+ } else if ( num >= CS_TEAMVOTE_YES && num <= CS_TEAMVOTE_YES + 1) {
+ cgs.teamVoteYes[num-CS_TEAMVOTE_YES] = atoi( str );
+ cgs.teamVoteModified[num-CS_TEAMVOTE_YES] = qtrue;
+ } else if ( num >= CS_TEAMVOTE_NO && num <= CS_TEAMVOTE_NO + 1) {
+ cgs.teamVoteNo[num-CS_TEAMVOTE_NO] = atoi( str );
+ cgs.teamVoteModified[num-CS_TEAMVOTE_NO] = qtrue;
+ } else if ( num >= CS_TEAMVOTE_STRING && num <= CS_TEAMVOTE_STRING + 1) {
+ Q_strncpyz( cgs.teamVoteString[num-CS_TEAMVOTE_STRING], str, sizeof( cgs.teamVoteString ) );
+#ifdef MISSIONPACK
+ trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER );
+#endif
+ } else if ( num == CS_INTERMISSION ) {
+ cg.intermissionStarted = atoi( str );
+ } else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) {
+ cgs.gameModels[ num-CS_MODELS ] = trap_R_RegisterModel( str );
+ } else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_SOUNDS ) {
+ if ( str[0] != '*' ) { // player specific sounds don't register here
+ cgs.gameSounds[ num-CS_SOUNDS] = trap_S_RegisterSound( str, qfalse );
+ }
+ } else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) {
+ CG_NewClientInfo( num - CS_PLAYERS );
+ CG_BuildSpectatorString();
+ } else if ( num == CS_FLAGSTATUS ) {
+ if( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION || cgs.gametype == GT_DOUBLE_D) {
+ // format is rb where its red/blue, 0 is at base, 1 is taken, 2 is dropped
+ cgs.redflag = str[0] - '0';
+ cgs.blueflag = str[1] - '0';
+ }
+//#ifdef MISSIONPACK
+ else if( cgs.gametype == GT_1FCTF ) {
+ cgs.flagStatus = str[0] - '0';
+ }
+//#endif
+ }
+ else if ( num == CS_SHADERSTATE ) {
+ CG_ShaderStateChanged();
+ }
+
+}
+
+
+/*
+=======================
+CG_AddToTeamChat
+
+=======================
+*/
+static void CG_AddToTeamChat( const char *str ) {
+ int len;
+ char *p, *ls;
+ int lastcolor;
+ int chatHeight;
+
+ if (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT) {
+ chatHeight = cg_teamChatHeight.integer;
+ } else {
+ chatHeight = TEAMCHAT_HEIGHT;
+ }
+
+ if (chatHeight <= 0 || cg_teamChatTime.integer <= 0) {
+ // team chat disabled, dump into normal chat
+ cgs.teamChatPos = cgs.teamLastChatPos = 0;
+ return;
+ }
+
+ len = 0;
+
+ p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
+ *p = 0;
+
+ lastcolor = '7';
+
+ ls = NULL;
+ while (*str) {
+ if (len > TEAMCHAT_WIDTH - 1) {
+ if (ls) {
+ str -= (p - ls);
+ str++;
+ p -= (p - ls);
+ }
+ *p = 0;
+
+ cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
+
+ cgs.teamChatPos++;
+ p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
+ *p = 0;
+ *p++ = Q_COLOR_ESCAPE;
+ *p++ = lastcolor;
+ len = 0;
+ ls = NULL;
+ }
+
+ if ( Q_IsColorString( str ) ) {
+ *p++ = *str++;
+ lastcolor = *str;
+ *p++ = *str++;
+ continue;
+ }
+ if (*str == ' ') {
+ ls = p;
+ }
+ *p++ = *str++;
+ len++;
+ }
+ *p = 0;
+
+ cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
+ cgs.teamChatPos++;
+
+ if (cgs.teamChatPos - cgs.teamLastChatPos > chatHeight)
+ cgs.teamLastChatPos = cgs.teamChatPos - chatHeight;
+}
+
+/*
+===============
+CG_MapRestart
+
+The server has issued a map_restart, so the next snapshot
+is completely new and should not be interpolated to.
+
+A tournement restart will clear everything, but doesn't
+require a reload of all the media
+===============
+*/
+static void CG_MapRestart( void ) {
+ if ( cg_showmiss.integer ) {
+ CG_Printf( "CG_MapRestart\n" );
+ }
+
+ CG_InitLocalEntities();
+ CG_InitMarkPolys();
+ CG_ClearParticles ();
+
+ // make sure the "3 frags left" warnings play again
+ cg.fraglimitWarnings = 0;
+
+ cg.timelimitWarnings = 0;
+
+ cg.intermissionStarted = qfalse;
+
+ cgs.voteTime = 0;
+
+ cg.mapRestart = qtrue;
+
+ CG_StartMusic();
+
+ trap_S_ClearLoopingSounds(qtrue);
+
+ // we really should clear more parts of cg here and stop sounds
+
+ // play the "fight" sound if this is a restart without warmup
+ if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) {
+ trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER );
+ CG_CenterPrint( "FIGHT!", 120, GIANTCHAR_WIDTH*2 );
+ }
+#ifdef MISSIONPACK
+ if (cg_singlePlayerActive.integer) {
+ trap_Cvar_Set("ui_matchStartTime", va("%i", cg.time));
+ if (cg_recordSPDemo.integer && cg_recordSPDemoName.string && *cg_recordSPDemoName.string) {
+ trap_SendConsoleCommand(va("set g_synchronousclients 1 ; record %s \n", cg_recordSPDemoName.string));
+ }
+ }
+#endif
+ trap_Cvar_Set("cg_thirdPerson", "0");
+}
+
+#define MAX_VOICEFILESIZE 16384
+#define MAX_VOICEFILES 8
+#define MAX_VOICECHATS 64
+#define MAX_VOICESOUNDS 64
+#define MAX_CHATSIZE 64
+#define MAX_HEADMODELS 64
+
+typedef struct voiceChat_s
+{
+ char id[64];
+ int numSounds;
+ sfxHandle_t sounds[MAX_VOICESOUNDS];
+ char chats[MAX_VOICESOUNDS][MAX_CHATSIZE];
+} voiceChat_t;
+
+typedef struct voiceChatList_s
+{
+ char name[64];
+ int gender;
+ int numVoiceChats;
+ voiceChat_t voiceChats[MAX_VOICECHATS];
+} voiceChatList_t;
+
+typedef struct headModelVoiceChat_s
+{
+ char headmodel[64];
+ int voiceChatNum;
+} headModelVoiceChat_t;
+
+voiceChatList_t voiceChatLists[MAX_VOICEFILES];
+headModelVoiceChat_t headModelVoiceChat[MAX_HEADMODELS];
+
+/*
+=================
+CG_ParseVoiceChats
+=================
+*/
+int CG_ParseVoiceChats( const char *filename, voiceChatList_t *voiceChatList, int maxVoiceChats ) {
+ int len, i;
+ fileHandle_t f;
+ char buf[MAX_VOICEFILESIZE];
+ char **p, *ptr;
+ char *token;
+ voiceChat_t *voiceChats;
+ qboolean compress;
+ sfxHandle_t sound;
+
+ compress = qtrue;
+ if (cg_buildScript.integer) {
+ compress = qfalse;
+ }
+
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( !f ) {
+ trap_Print( va( S_COLOR_RED "voice chat file not found: %s\n", filename ) );
+ return qfalse;
+ }
+ if ( len >= MAX_VOICEFILESIZE ) {
+ trap_Print( va( S_COLOR_RED "voice chat file too large: %s is %i, max allowed is %i\n", filename, len, MAX_VOICEFILESIZE ) );
+ trap_FS_FCloseFile( f );
+ return qfalse;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ ptr = buf;
+ p = &ptr;
+
+ Com_sprintf(voiceChatList->name, sizeof(voiceChatList->name), "%s", filename);
+ voiceChats = voiceChatList->voiceChats;
+ for ( i = 0; i < maxVoiceChats; i++ ) {
+ voiceChats[i].id[0] = 0;
+ }
+ token = COM_ParseExt(p, qtrue);
+ if (!token || token[0] == 0) {
+ return qtrue;
+ }
+ if (!Q_stricmp(token, "female")) {
+ voiceChatList->gender = GENDER_FEMALE;
+ }
+ else if (!Q_stricmp(token, "male")) {
+ voiceChatList->gender = GENDER_MALE;
+ }
+ else if (!Q_stricmp(token, "neuter")) {
+ voiceChatList->gender = GENDER_NEUTER;
+ }
+ else {
+ trap_Print( va( S_COLOR_RED "expected gender not found in voice chat file: %s\n", filename ) );
+ return qfalse;
+ }
+
+ voiceChatList->numVoiceChats = 0;
+ while ( 1 ) {
+ token = COM_ParseExt(p, qtrue);
+ if (!token || token[0] == 0) {
+ return qtrue;
+ }
+ Com_sprintf(voiceChats[voiceChatList->numVoiceChats].id, sizeof( voiceChats[voiceChatList->numVoiceChats].id ), "%s", token);
+ token = COM_ParseExt(p, qtrue);
+ if (Q_stricmp(token, "{")) {
+ trap_Print( va( S_COLOR_RED "expected { found %s in voice chat file: %s\n", token, filename ) );
+ return qfalse;
+ }
+ voiceChats[voiceChatList->numVoiceChats].numSounds = 0;
+ while(1) {
+ token = COM_ParseExt(p, qtrue);
+ if (!token || token[0] == 0) {
+ return qtrue;
+ }
+ if (!Q_stricmp(token, "}"))
+ break;
+ sound = trap_S_RegisterSound( token, compress );
+ voiceChats[voiceChatList->numVoiceChats].sounds[voiceChats[voiceChatList->numVoiceChats].numSounds] = sound;
+ token = COM_ParseExt(p, qtrue);
+ if (!token || token[0] == 0) {
+ return qtrue;
+ }
+ Com_sprintf(voiceChats[voiceChatList->numVoiceChats].chats[
+ voiceChats[voiceChatList->numVoiceChats].numSounds], MAX_CHATSIZE, "%s", token);
+ if (sound)
+ voiceChats[voiceChatList->numVoiceChats].numSounds++;
+ if (voiceChats[voiceChatList->numVoiceChats].numSounds >= MAX_VOICESOUNDS)
+ break;
+ }
+ voiceChatList->numVoiceChats++;
+ if (voiceChatList->numVoiceChats >= maxVoiceChats)
+ return qtrue;
+ }
+ return qtrue;
+}
+
+/*
+=================
+CG_LoadVoiceChats
+=================
+*/
+void CG_LoadVoiceChats( void ) {
+ int size;
+
+ size = trap_MemoryRemaining();
+ CG_ParseVoiceChats( "scripts/female1.voice", &voiceChatLists[0], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/female2.voice", &voiceChatLists[1], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/female3.voice", &voiceChatLists[2], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/male1.voice", &voiceChatLists[3], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/male2.voice", &voiceChatLists[4], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/male3.voice", &voiceChatLists[5], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/male4.voice", &voiceChatLists[6], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/male5.voice", &voiceChatLists[7], MAX_VOICECHATS );
+ CG_Printf("voice chat memory size = %d\n", size - trap_MemoryRemaining());
+}
+
+/*
+=================
+CG_HeadModelVoiceChats
+=================
+*/
+int CG_HeadModelVoiceChats( char *filename ) {
+ int len, i;
+ fileHandle_t f;
+ char buf[MAX_VOICEFILESIZE];
+ char **p, *ptr;
+ char *token;
+
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( !f ) {
+ //trap_Print( va( "voice chat file not found: %s\n", filename ) );
+ return -1;
+ }
+ if ( len >= MAX_VOICEFILESIZE ) {
+ trap_Print( va( S_COLOR_RED "voice chat file too large: %s is %i, max allowed is %i\n", filename, len, MAX_VOICEFILESIZE ) );
+ trap_FS_FCloseFile( f );
+ return -1;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ ptr = buf;
+ p = &ptr;
+
+ token = COM_ParseExt(p, qtrue);
+ if (!token || token[0] == 0) {
+ return -1;
+ }
+
+ for ( i = 0; i < MAX_VOICEFILES; i++ ) {
+ if ( !Q_stricmp(token, voiceChatLists[i].name) ) {
+ return i;
+ }
+ }
+
+ //FIXME: maybe try to load the .voice file which name is stored in token?
+
+ return -1;
+}
+
+
+/*
+=================
+CG_GetVoiceChat
+=================
+*/
+int CG_GetVoiceChat( voiceChatList_t *voiceChatList, const char *id, sfxHandle_t *snd, char **chat) {
+ int i, rnd;
+
+ for ( i = 0; i < voiceChatList->numVoiceChats; i++ ) {
+ if ( !Q_stricmp( id, voiceChatList->voiceChats[i].id ) ) {
+ rnd = random() * voiceChatList->voiceChats[i].numSounds;
+ *snd = voiceChatList->voiceChats[i].sounds[rnd];
+ *chat = voiceChatList->voiceChats[i].chats[rnd];
+ return qtrue;
+ }
+ }
+ return qfalse;
+}
+
+/*
+=================
+CG_VoiceChatListForClient
+=================
+*/
+voiceChatList_t *CG_VoiceChatListForClient( int clientNum ) {
+ clientInfo_t *ci;
+ int voiceChatNum, i, j, k, gender;
+ char filename[MAX_QPATH], headModelName[MAX_QPATH];
+
+ if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
+ clientNum = 0;
+ }
+ ci = &cgs.clientinfo[ clientNum ];
+
+ for ( k = 0; k < 2; k++ ) {
+ if ( k == 0 ) {
+ if (ci->headModelName[0] == '*') {
+ Com_sprintf( headModelName, sizeof(headModelName), "%s/%s", ci->headModelName+1, ci->headSkinName );
+ }
+ else {
+ Com_sprintf( headModelName, sizeof(headModelName), "%s/%s", ci->headModelName, ci->headSkinName );
+ }
+ }
+ else {
+ if (ci->headModelName[0] == '*') {
+ Com_sprintf( headModelName, sizeof(headModelName), "%s", ci->headModelName+1 );
+ }
+ else {
+ Com_sprintf( headModelName, sizeof(headModelName), "%s", ci->headModelName );
+ }
+ }
+ // find the voice file for the head model the client uses
+ for ( i = 0; i < MAX_HEADMODELS; i++ ) {
+ if (!Q_stricmp(headModelVoiceChat[i].headmodel, headModelName)) {
+ break;
+ }
+ }
+ if (i < MAX_HEADMODELS) {
+ return &voiceChatLists[headModelVoiceChat[i].voiceChatNum];
+ }
+ // find a <headmodelname>.vc file
+ for ( i = 0; i < MAX_HEADMODELS; i++ ) {
+ if (!strlen(headModelVoiceChat[i].headmodel)) {
+ Com_sprintf(filename, sizeof(filename), "scripts/%s.vc", headModelName);
+ voiceChatNum = CG_HeadModelVoiceChats(filename);
+ if (voiceChatNum == -1)
+ break;
+ Com_sprintf(headModelVoiceChat[i].headmodel, sizeof ( headModelVoiceChat[i].headmodel ),
+ "%s", headModelName);
+ headModelVoiceChat[i].voiceChatNum = voiceChatNum;
+ return &voiceChatLists[headModelVoiceChat[i].voiceChatNum];
+ }
+ }
+ }
+ gender = ci->gender;
+ for (k = 0; k < 2; k++) {
+ // just pick the first with the right gender
+ for ( i = 0; i < MAX_VOICEFILES; i++ ) {
+ if (strlen(voiceChatLists[i].name)) {
+ if (voiceChatLists[i].gender == gender) {
+ // store this head model with voice chat for future reference
+ for ( j = 0; j < MAX_HEADMODELS; j++ ) {
+ if (!strlen(headModelVoiceChat[j].headmodel)) {
+ Com_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ),
+ "%s", headModelName);
+ headModelVoiceChat[j].voiceChatNum = i;
+ break;
+ }
+ }
+ return &voiceChatLists[i];
+ }
+ }
+ }
+ // fall back to male gender because we don't have neuter in the mission pack
+ if (gender == GENDER_MALE)
+ break;
+ gender = GENDER_MALE;
+ }
+ // store this head model with voice chat for future reference
+ for ( j = 0; j < MAX_HEADMODELS; j++ ) {
+ if (!strlen(headModelVoiceChat[j].headmodel)) {
+ Com_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ),
+ "%s", headModelName);
+ headModelVoiceChat[j].voiceChatNum = 0;
+ break;
+ }
+ }
+ // just return the first voice chat list
+ return &voiceChatLists[0];
+}
+
+#define MAX_VOICECHATBUFFER 32
+
+typedef struct bufferedVoiceChat_s
+{
+ int clientNum;
+ sfxHandle_t snd;
+ int voiceOnly;
+ char cmd[MAX_SAY_TEXT];
+ char message[MAX_SAY_TEXT];
+} bufferedVoiceChat_t;
+
+bufferedVoiceChat_t voiceChatBuffer[MAX_VOICECHATBUFFER];
+
+/*
+=================
+CG_PlayVoiceChat
+=================
+*/
+void CG_PlayVoiceChat( bufferedVoiceChat_t *vchat ) {
+#ifdef MISSIONPACK
+ // if we are going into the intermission, don't start any voices
+ if ( cg.intermissionStarted ) {
+ return;
+ }
+
+ if ( !cg_noVoiceChats.integer ) {
+ trap_S_StartLocalSound( vchat->snd, CHAN_VOICE);
+ if (vchat->clientNum != cg.snap->ps.clientNum) {
+ int orderTask = CG_ValidOrder(vchat->cmd);
+ if (orderTask > 0) {
+ cgs.acceptOrderTime = cg.time + 5000;
+ Q_strncpyz(cgs.acceptVoice, vchat->cmd, sizeof(cgs.acceptVoice));
+ cgs.acceptTask = orderTask;
+ cgs.acceptLeader = vchat->clientNum;
+ }
+ // see if this was an order
+ CG_ShowResponseHead();
+ }
+ }
+ if (!vchat->voiceOnly && !cg_noVoiceText.integer) {
+ CG_AddToTeamChat( vchat->message );
+ CG_Printf( "%s\n", vchat->message );
+ }
+ voiceChatBuffer[cg.voiceChatBufferOut].snd = 0;
+#endif
+}
+
+/*
+=====================
+CG_PlayBufferedVoieChats
+=====================
+*/
+void CG_PlayBufferedVoiceChats( void ) {
+#ifdef MISSIONPACK
+ if ( cg.voiceChatTime < cg.time ) {
+ if (cg.voiceChatBufferOut != cg.voiceChatBufferIn && voiceChatBuffer[cg.voiceChatBufferOut].snd) {
+ //
+ CG_PlayVoiceChat(&voiceChatBuffer[cg.voiceChatBufferOut]);
+ //
+ cg.voiceChatBufferOut = (cg.voiceChatBufferOut + 1) % MAX_VOICECHATBUFFER;
+ cg.voiceChatTime = cg.time + 1000;
+ }
+ }
+#endif
+}
+
+/*
+=====================
+CG_AddBufferedVoiceChat
+=====================
+*/
+void CG_AddBufferedVoiceChat( bufferedVoiceChat_t *vchat ) {
+#ifdef MISSIONPACK
+ // if we are going into the intermission, don't start any voices
+ if ( cg.intermissionStarted ) {
+ return;
+ }
+
+ memcpy(&voiceChatBuffer[cg.voiceChatBufferIn], vchat, sizeof(bufferedVoiceChat_t));
+ cg.voiceChatBufferIn = (cg.voiceChatBufferIn + 1) % MAX_VOICECHATBUFFER;
+ if (cg.voiceChatBufferIn == cg.voiceChatBufferOut) {
+ CG_PlayVoiceChat( &voiceChatBuffer[cg.voiceChatBufferOut] );
+ cg.voiceChatBufferOut++;
+ }
+#endif
+}
+
+/*
+=================
+CG_VoiceChatLocal
+=================
+*/
+void CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd ) {
+#ifdef MISSIONPACK
+ char *chat;
+ voiceChatList_t *voiceChatList;
+ clientInfo_t *ci;
+ sfxHandle_t snd;
+ bufferedVoiceChat_t vchat;
+
+ // if we are going into the intermission, don't start any voices
+ if ( cg.intermissionStarted ) {
+ return;
+ }
+
+ if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
+ clientNum = 0;
+ }
+ ci = &cgs.clientinfo[ clientNum ];
+
+ cgs.currentVoiceClient = clientNum;
+
+ voiceChatList = CG_VoiceChatListForClient( clientNum );
+
+ if ( CG_GetVoiceChat( voiceChatList, cmd, &snd, &chat ) ) {
+ //
+ if ( mode == SAY_TEAM || !cg_teamChatsOnly.integer ) {
+ vchat.clientNum = clientNum;
+ vchat.snd = snd;
+ vchat.voiceOnly = voiceOnly;
+ Q_strncpyz(vchat.cmd, cmd, sizeof(vchat.cmd));
+ if ( mode == SAY_TELL ) {
+ Com_sprintf(vchat.message, sizeof(vchat.message), "[%s]: %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
+ }
+ else if ( mode == SAY_TEAM ) {
+ Com_sprintf(vchat.message, sizeof(vchat.message), "(%s): %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
+ }
+ else {
+ Com_sprintf(vchat.message, sizeof(vchat.message), "%s: %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
+ }
+ CG_AddBufferedVoiceChat(&vchat);
+ }
+ }
+#endif
+}
+
+/*
+=================
+CG_VoiceChat
+=================
+*/
+void CG_VoiceChat( int mode ) {
+#ifdef MISSIONPACK
+ const char *cmd;
+ int clientNum, color;
+ qboolean voiceOnly;
+
+ voiceOnly = atoi(CG_Argv(1));
+ clientNum = atoi(CG_Argv(2));
+ color = atoi(CG_Argv(3));
+ cmd = CG_Argv(4);
+
+ if (cg_noTaunt.integer != 0) {
+ if (!strcmp(cmd, VOICECHAT_KILLINSULT) || !strcmp(cmd, VOICECHAT_TAUNT) || \
+ !strcmp(cmd, VOICECHAT_DEATHINSULT) || !strcmp(cmd, VOICECHAT_KILLGAUNTLET) || \
+ !strcmp(cmd, VOICECHAT_PRAISE)) {
+ return;
+ }
+ }
+
+ CG_VoiceChatLocal( mode, voiceOnly, clientNum, color, cmd );
+#endif
+}
+
+/*
+=================
+CG_RemoveChatEscapeChar
+=================
+*/
+static void CG_RemoveChatEscapeChar( char *text ) {
+ int i, l;
+
+ l = 0;
+ for ( i = 0; text[i]; i++ ) {
+ if (text[i] == '\x19')
+ continue;
+ text[l++] = text[i];
+ }
+ text[l] = '\0';
+}
+
+/*
+=================
+CG_ServerCommand
+
+The string has been tokenized and can be retrieved with
+Cmd_Argc() / Cmd_Argv()
+=================
+*/
+static void CG_ServerCommand( void ) {
+ const char *cmd;
+ char text[MAX_SAY_TEXT];
+
+ cmd = CG_Argv(0);
+
+ if ( !cmd[0] ) {
+ // server claimed the command
+ return;
+ }
+
+ if ( !strcmp( cmd, "cp" ) ) {
+ CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
+ return;
+ }
+
+ if ( !strcmp( cmd, "cs" ) ) {
+ CG_ConfigStringModified();
+ return;
+ }
+
+ if ( !strcmp( cmd, "print" ) ) {
+ CG_Printf( "%s", CG_Argv(1) );
+#ifdef MISSIONPACK
+ cmd = CG_Argv(1); // yes, this is obviously a hack, but so is the way we hear about
+ // votes passing or failing
+ if ( !Q_stricmpn( cmd, "vote failed", 11 ) || !Q_stricmpn( cmd, "team vote failed", 16 )) {
+ trap_S_StartLocalSound( cgs.media.voteFailed, CHAN_ANNOUNCER );
+ } else if ( !Q_stricmpn( cmd, "vote passed", 11 ) || !Q_stricmpn( cmd, "team vote passed", 16 ) ) {
+ trap_S_StartLocalSound( cgs.media.votePassed, CHAN_ANNOUNCER );
+ }
+#endif
+ return;
+ }
+
+ if ( !strcmp( cmd, "chat" ) ) {
+ if ( !cg_teamChatsOnly.integer ) {
+ if( cg_chatBeep.integer )
+ trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
+ Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
+ CG_RemoveChatEscapeChar( text );
+ CG_Printf( "%s\n", text );
+ }
+ return;
+ }
+
+ if ( !strcmp( cmd, "tchat" ) ) {
+ if( cg_teamChatBeep.integer )
+ trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
+ Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
+ CG_RemoveChatEscapeChar( text );
+ CG_AddToTeamChat( text );
+ CG_Printf( "%s\n", text );
+ return;
+ }
+ if ( !strcmp( cmd, "vchat" ) ) {
+ CG_VoiceChat( SAY_ALL );
+ return;
+ }
+
+ if ( !strcmp( cmd, "vtchat" ) ) {
+ CG_VoiceChat( SAY_TEAM );
+ return;
+ }
+
+ if ( !strcmp( cmd, "vtell" ) ) {
+ CG_VoiceChat( SAY_TELL );
+ return;
+ }
+
+ if ( !strcmp( cmd, "scores" ) ) {
+ CG_ParseScores();
+ return;
+ }
+
+
+ if ( !strcmp( cmd, "accs" ) ) {
+ CG_ParseAccuracy();
+ return;
+ }
+
+
+ if ( !strcmp( cmd, "ddtaken" ) ) {
+ CG_ParseDDtimetaken();
+ return;
+ }
+
+ if ( !strcmp( cmd, "dompointnames" ) ) {
+ CG_ParseDomPointNames();
+ return;
+ }
+
+ if ( !strcmp( cmd, "domStatus" ) ) {
+ CG_ParseDomStatus();
+ return;
+ }
+
+ if ( !strcmp( cmd, "elimination" ) ) {
+ CG_ParseElimination();
+ return;
+ }
+
+ if ( !strcmp( cmd, "mappage" ) ) {
+ CG_ParseMappage();
+ return;
+ }
+
+ if ( !strcmp( cmd, "attackingteam" ) ) {
+ CG_ParseAttackingTeam();
+ return;
+ }
+
+ if ( !strcmp( cmd, "tinfo" ) ) {
+ CG_ParseTeamInfo();
+ return;
+ }
+
+ if ( !strcmp( cmd, "map_restart" ) ) {
+ CG_MapRestart();
+ return;
+ }
+
+ if ( Q_stricmp (cmd, "remapShader") == 0 )
+ {
+ if (trap_Argc() == 4)
+ {
+ char shader1[MAX_QPATH];
+ char shader2[MAX_QPATH];
+ char shader3[MAX_QPATH];
+
+ Q_strncpyz(shader1, CG_Argv(1), sizeof(shader1));
+ Q_strncpyz(shader2, CG_Argv(2), sizeof(shader2));
+ Q_strncpyz(shader3, CG_Argv(3), sizeof(shader3));
+
+ trap_R_RemapShader(shader1, shader2, shader3);
+ }
+
+ return;
+ }
+
+ // loaddeferred can be both a servercmd and a consolecmd
+ if ( !strcmp( cmd, "loaddefered" ) ) { // FIXME: spelled wrong, but not changing for demo
+ CG_LoadDeferredPlayers();
+ return;
+ }
+
+ // clientLevelShot is sent before taking a special screenshot for
+ // the menu system during development
+ if ( !strcmp( cmd, "clientLevelShot" ) ) {
+ cg.levelShot = qtrue;
+ return;
+ }
+
+ // challenge completed is determened by the server. A client should consider this message valid:
+ if ( !strcmp( cmd, "ch" ) ) {
+ CG_ParseChallenge();
+ return;
+ }
+
+ if ( !strcmp (cmd, "oh") ) {
+ CG_ParseObeliskHealth();
+ return;
+ }
+
+ if ( !strcmp( cmd, "respawn" ) ) {
+ CG_ParseRespawnTime();
+ return;
+ }
+
+ if ( !strcmp( cmd, "team" ) ) {
+ CG_ParseTeam();
+ return;
+ }
+
+ if ( !strcmp( cmd, "customvotes" ) ) {
+ char infoString[1024];
+ int i;
+ //TODO: Create a ParseCustomvotes function
+ memset(&infoString,0,sizeof(infoString));
+ for(i=1;i<=12;i++) {
+ Q_strcat(infoString,sizeof(infoString),CG_Argv( i ));
+ Q_strcat(infoString,sizeof(infoString)," ");
+ }
+ trap_Cvar_Set("cg_vote_custom_commands",infoString);
+ return;
+ }
+
+ CG_Printf( "Unknown client game command: %s\n", cmd );
+}
+
+
+/*
+====================
+CG_ExecuteNewServerCommands
+
+Execute all of the server commands that were received along
+with this this snapshot.
+====================
+*/
+void CG_ExecuteNewServerCommands( int latestSequence ) {
+ while ( cgs.serverCommandSequence < latestSequence ) {
+ if ( trap_GetServerCommand( ++cgs.serverCommandSequence ) ) {
+ CG_ServerCommand();
+ }
+ }
+}
diff --git a/game/code/cgame/cg_snapshot.c b/code/cgame/cg_snapshot.c
similarity index 100%
rename from game/code/cgame/cg_snapshot.c
rename to code/cgame/cg_snapshot.c
diff --git a/engine/code/cgame/cg_syscalls.asm b/code/cgame/cg_syscalls.asm
similarity index 100%
rename from engine/code/cgame/cg_syscalls.asm
rename to code/cgame/cg_syscalls.asm
diff --git a/code/cgame/cg_syscalls.c b/code/cgame/cg_syscalls.c
new file mode 100644
index 0000000..4823d67
--- /dev/null
+++ b/code/cgame/cg_syscalls.c
@@ -0,0 +1,446 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_syscalls.c -- this file is only included when building a dll
+// cg_syscalls.asm is included instead when building a qvm
+#ifdef Q3_VM
+#error "Do not use in VM build"
+#endif
+
+#include "cg_local.h"
+
+static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;
+
+
+void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) {
+ syscall = syscallptr;
+}
+
+
+int PASSFLOAT( float x ) {
+ float floatTemp;
+ floatTemp = x;
+ return *(int *)&floatTemp;
+}
+
+void trap_Print( const char *fmt ) {
+ syscall( CG_PRINT, fmt );
+}
+
+void trap_Error( const char *fmt ) {
+ syscall( CG_ERROR, fmt );
+ exit(CG_ERROR); //Will never occour but makes compiler happy
+}
+
+int trap_Milliseconds( void ) {
+ return syscall( CG_MILLISECONDS );
+}
+
+void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) {
+ syscall( CG_CVAR_REGISTER, vmCvar, varName, defaultValue, flags );
+}
+
+void trap_Cvar_Update( vmCvar_t *vmCvar ) {
+ syscall( CG_CVAR_UPDATE, vmCvar );
+}
+
+void trap_Cvar_Set( const char *var_name, const char *value ) {
+ syscall( CG_CVAR_SET, var_name, value );
+}
+
+void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
+ syscall( CG_CVAR_VARIABLESTRINGBUFFER, var_name, buffer, bufsize );
+}
+
+int trap_Argc( void ) {
+ return syscall( CG_ARGC );
+}
+
+void trap_Argv( int n, char *buffer, int bufferLength ) {
+ syscall( CG_ARGV, n, buffer, bufferLength );
+}
+
+void trap_Args( char *buffer, int bufferLength ) {
+ syscall( CG_ARGS, buffer, bufferLength );
+}
+
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
+ return syscall( CG_FS_FOPENFILE, qpath, f, mode );
+}
+
+void trap_FS_Read( void *buffer, int len, fileHandle_t f ) {
+ syscall( CG_FS_READ, buffer, len, f );
+}
+
+void trap_FS_Write( const void *buffer, int len, fileHandle_t f ) {
+ syscall( CG_FS_WRITE, buffer, len, f );
+}
+
+void trap_FS_FCloseFile( fileHandle_t f ) {
+ syscall( CG_FS_FCLOSEFILE, f );
+}
+
+int trap_FS_Seek( fileHandle_t f, long offset, int origin ) {
+ return syscall( CG_FS_SEEK, f, offset, origin );
+}
+
+void trap_SendConsoleCommand( const char *text ) {
+ syscall( CG_SENDCONSOLECOMMAND, text );
+}
+
+void trap_AddCommand( const char *cmdName ) {
+ syscall( CG_ADDCOMMAND, cmdName );
+}
+
+void trap_RemoveCommand( const char *cmdName ) {
+ syscall( CG_REMOVECOMMAND, cmdName );
+}
+
+void trap_SendClientCommand( const char *s ) {
+ syscall( CG_SENDCLIENTCOMMAND, s );
+}
+
+void trap_UpdateScreen( void ) {
+ syscall( CG_UPDATESCREEN );
+}
+
+void trap_CM_LoadMap( const char *mapname ) {
+ syscall( CG_CM_LOADMAP, mapname );
+}
+
+int trap_CM_NumInlineModels( void ) {
+ return syscall( CG_CM_NUMINLINEMODELS );
+}
+
+clipHandle_t trap_CM_InlineModel( int index ) {
+ return syscall( CG_CM_INLINEMODEL, index );
+}
+
+clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) {
+ return syscall( CG_CM_TEMPBOXMODEL, mins, maxs );
+}
+
+clipHandle_t trap_CM_TempCapsuleModel( const vec3_t mins, const vec3_t maxs ) {
+ return syscall( CG_CM_TEMPCAPSULEMODEL, mins, maxs );
+}
+
+int trap_CM_PointContents( const vec3_t p, clipHandle_t model ) {
+ return syscall( CG_CM_POINTCONTENTS, p, model );
+}
+
+int trap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles ) {
+ return syscall( CG_CM_TRANSFORMEDPOINTCONTENTS, p, model, origin, angles );
+}
+
+void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ const vec3_t mins, const vec3_t maxs,
+ clipHandle_t model, int brushmask ) {
+ syscall( CG_CM_BOXTRACE, results, start, end, mins, maxs, model, brushmask );
+}
+
+void trap_CM_CapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ const vec3_t mins, const vec3_t maxs,
+ clipHandle_t model, int brushmask ) {
+ syscall( CG_CM_CAPSULETRACE, results, start, end, mins, maxs, model, brushmask );
+}
+
+void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ const vec3_t mins, const vec3_t maxs,
+ clipHandle_t model, int brushmask,
+ const vec3_t origin, const vec3_t angles ) {
+ syscall( CG_CM_TRANSFORMEDBOXTRACE, results, start, end, mins, maxs, model, brushmask, origin, angles );
+}
+
+void trap_CM_TransformedCapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ const vec3_t mins, const vec3_t maxs,
+ clipHandle_t model, int brushmask,
+ const vec3_t origin, const vec3_t angles ) {
+ syscall( CG_CM_TRANSFORMEDCAPSULETRACE, results, start, end, mins, maxs, model, brushmask, origin, angles );
+}
+
+int trap_CM_MarkFragments( int numPoints, const vec3_t *points,
+ const vec3_t projection,
+ int maxPoints, vec3_t pointBuffer,
+ int maxFragments, markFragment_t *fragmentBuffer ) {
+ return syscall( CG_CM_MARKFRAGMENTS, numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer );
+}
+
+void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ) {
+ syscall( CG_S_STARTSOUND, origin, entityNum, entchannel, sfx );
+}
+
+void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ) {
+ syscall( CG_S_STARTLOCALSOUND, sfx, channelNum );
+}
+
+void trap_S_ClearLoopingSounds( qboolean killall ) {
+ syscall( CG_S_CLEARLOOPINGSOUNDS, killall );
+}
+
+void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) {
+ syscall( CG_S_ADDLOOPINGSOUND, entityNum, origin, velocity, sfx );
+}
+
+void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) {
+ syscall( CG_S_ADDREALLOOPINGSOUND, entityNum, origin, velocity, sfx );
+}
+
+void trap_S_StopLoopingSound( int entityNum ) {
+ syscall( CG_S_STOPLOOPINGSOUND, entityNum );
+}
+
+void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin ) {
+ syscall( CG_S_UPDATEENTITYPOSITION, entityNum, origin );
+}
+
+void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater ) {
+ syscall( CG_S_RESPATIALIZE, entityNum, origin, axis, inwater );
+}
+
+sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ) {
+ return syscall( CG_S_REGISTERSOUND, sample, compressed );
+}
+
+void trap_S_StartBackgroundTrack( const char *intro, const char *loop ) {
+ syscall( CG_S_STARTBACKGROUNDTRACK, intro, loop );
+}
+
+void trap_R_LoadWorldMap( const char *mapname ) {
+ syscall( CG_R_LOADWORLDMAP, mapname );
+}
+
+qhandle_t trap_R_RegisterModel( const char *name ) {
+ return syscall( CG_R_REGISTERMODEL, name );
+}
+
+qhandle_t trap_R_RegisterSkin( const char *name ) {
+ return syscall( CG_R_REGISTERSKIN, name );
+}
+
+qhandle_t trap_R_RegisterShader( const char *name ) {
+ return syscall( CG_R_REGISTERSHADER, name );
+}
+
+qhandle_t trap_R_RegisterShaderNoMip( const char *name ) {
+ return syscall( CG_R_REGISTERSHADERNOMIP, name );
+}
+
+void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {
+ syscall(CG_R_REGISTERFONT, fontName, pointSize, font );
+}
+
+void trap_R_ClearScene( void ) {
+ syscall( CG_R_CLEARSCENE );
+}
+
+void trap_R_AddRefEntityToScene( const refEntity_t *re ) {
+ syscall( CG_R_ADDREFENTITYTOSCENE, re );
+}
+
+void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ) {
+ syscall( CG_R_ADDPOLYTOSCENE, hShader, numVerts, verts );
+}
+
+void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ) {
+ syscall( CG_R_ADDPOLYSTOSCENE, hShader, numVerts, verts, num );
+}
+
+int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) {
+ return syscall( CG_R_LIGHTFORPOINT, point, ambientLight, directedLight, lightDir );
+}
+
+void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
+ syscall( CG_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );
+}
+
+void trap_R_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
+ syscall( CG_R_ADDADDITIVELIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );
+}
+
+void trap_R_RenderScene( const refdef_t *fd ) {
+ syscall( CG_R_RENDERSCENE, fd );
+}
+
+void trap_R_SetColor( const float *rgba ) {
+ syscall( CG_R_SETCOLOR, rgba );
+}
+
+void trap_R_DrawStretchPic( float x, float y, float w, float h,
+ float s1, float t1, float s2, float t2, qhandle_t hShader ) {
+ syscall( CG_R_DRAWSTRETCHPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), hShader );
+}
+
+void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {
+ syscall( CG_R_MODELBOUNDS, model, mins, maxs );
+}
+
+int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame,
+ float frac, const char *tagName ) {
+ return syscall( CG_R_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName );
+}
+
+void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) {
+ syscall( CG_R_REMAP_SHADER, oldShader, newShader, timeOffset );
+}
+
+void trap_GetGlconfig( glconfig_t *glconfig ) {
+ syscall( CG_GETGLCONFIG, glconfig );
+}
+
+void trap_GetGameState( gameState_t *gamestate ) {
+ syscall( CG_GETGAMESTATE, gamestate );
+}
+
+void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) {
+ syscall( CG_GETCURRENTSNAPSHOTNUMBER, snapshotNumber, serverTime );
+}
+
+qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {
+ return syscall( CG_GETSNAPSHOT, snapshotNumber, snapshot );
+}
+
+qboolean trap_GetServerCommand( int serverCommandNumber ) {
+ return syscall( CG_GETSERVERCOMMAND, serverCommandNumber );
+}
+
+int trap_GetCurrentCmdNumber( void ) {
+ return syscall( CG_GETCURRENTCMDNUMBER );
+}
+
+qboolean trap_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) {
+ return syscall( CG_GETUSERCMD, cmdNumber, ucmd );
+}
+
+void trap_SetUserCmdValue( int stateValue, float sensitivityScale ) {
+ syscall( CG_SETUSERCMDVALUE, stateValue, PASSFLOAT(sensitivityScale) );
+}
+
+void testPrintInt( char *string, int i ) {
+ syscall( CG_TESTPRINTINT, string, i );
+}
+
+void testPrintFloat( char *string, float f ) {
+ syscall( CG_TESTPRINTFLOAT, string, PASSFLOAT(f) );
+}
+
+int trap_MemoryRemaining( void ) {
+ return syscall( CG_MEMORY_REMAINING );
+}
+
+qboolean trap_Key_IsDown( int keynum ) {
+ return syscall( CG_KEY_ISDOWN, keynum );
+}
+
+int trap_Key_GetCatcher( void ) {
+ return syscall( CG_KEY_GETCATCHER );
+}
+
+void trap_Key_SetCatcher( int catcher ) {
+ syscall( CG_KEY_SETCATCHER, catcher );
+}
+
+int trap_Key_GetKey( const char *binding ) {
+ return syscall( CG_KEY_GETKEY, binding );
+}
+
+int trap_PC_AddGlobalDefine( char *define ) {
+ return syscall( CG_PC_ADD_GLOBAL_DEFINE, define );
+}
+
+int trap_PC_LoadSource( const char *filename ) {
+ return syscall( CG_PC_LOAD_SOURCE, filename );
+}
+
+int trap_PC_FreeSource( int handle ) {
+ return syscall( CG_PC_FREE_SOURCE, handle );
+}
+
+int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) {
+ return syscall( CG_PC_READ_TOKEN, handle, pc_token );
+}
+
+int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) {
+ return syscall( CG_PC_SOURCE_FILE_AND_LINE, handle, filename, line );
+}
+
+void trap_S_StopBackgroundTrack( void ) {
+ syscall( CG_S_STOPBACKGROUNDTRACK );
+}
+
+int trap_RealTime(qtime_t *qtime) {
+ return syscall( CG_REAL_TIME, qtime );
+}
+
+void trap_SnapVector( float *v ) {
+ syscall( CG_SNAPVECTOR, v );
+}
+
+// this returns a handle. arg0 is the name in the format "idlogo.roq", set arg1 to NULL, alteredstates to qfalse (do not alter gamestate)
+int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits) {
+ return syscall(CG_CIN_PLAYCINEMATIC, arg0, xpos, ypos, width, height, bits);
+}
+
+// stops playing the cinematic and ends it. should always return FMV_EOF
+// cinematics must be stopped in reverse order of when they are started
+e_status trap_CIN_StopCinematic(int handle) {
+ return syscall(CG_CIN_STOPCINEMATIC, handle);
+}
+
+
+// will run a frame of the cinematic but will not draw it. Will return FMV_EOF if the end of the cinematic has been reached.
+e_status trap_CIN_RunCinematic (int handle) {
+ return syscall(CG_CIN_RUNCINEMATIC, handle);
+}
+
+
+// draws the current frame
+void trap_CIN_DrawCinematic (int handle) {
+ syscall(CG_CIN_DRAWCINEMATIC, handle);
+}
+
+
+// allows you to resize the animation dynamically
+void trap_CIN_SetExtents (int handle, int x, int y, int w, int h) {
+ syscall(CG_CIN_SETEXTENTS, handle, x, y, w, h);
+}
+
+/*
+qboolean trap_loadCamera( const char *name ) {
+ return syscall( CG_LOADCAMERA, name );
+}
+
+void trap_startCamera(int time) {
+ syscall(CG_STARTCAMERA, time);
+}
+
+qboolean trap_getCameraInfo( int time, vec3_t *origin, vec3_t *angles) {
+ return syscall( CG_GETCAMERAINFO, time, origin, angles );
+}
+*/
+
+qboolean trap_GetEntityToken( char *buffer, int bufferSize ) {
+ return syscall( CG_GET_ENTITY_TOKEN, buffer, bufferSize );
+}
+
+qboolean trap_R_inPVS( const vec3_t p1, const vec3_t p2 ) {
+ return syscall( CG_R_INPVS, p1, p2 );
+}
diff --git a/game/code/cgame/cg_unlagged.c b/code/cgame/cg_unlagged.c
similarity index 100%
rename from game/code/cgame/cg_unlagged.c
rename to code/cgame/cg_unlagged.c
diff --git a/code/cgame/cg_view.c b/code/cgame/cg_view.c
new file mode 100644
index 0000000..ec76dc7
--- /dev/null
+++ b/code/cgame/cg_view.c
@@ -0,0 +1,889 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_view.c -- setup all the parameters (position, angle, etc)
+// for a 3D rendering
+#include "cg_local.h"
+
+
+/*
+=============================================================================
+
+ MODEL TESTING
+
+The viewthing and gun positioning tools from Q2 have been integrated and
+enhanced into a single model testing facility.
+
+Model viewing can begin with either "testmodel <modelname>" or "testgun <modelname>".
+
+The names must be the full pathname after the basedir, like
+"models/weapons/v_launch/tris.md3" or "players/male/tris.md3"
+
+Testmodel will create a fake entity 100 units in front of the current view
+position, directly facing the viewer. It will remain immobile, so you can
+move around it to view it from different angles.
+
+Testgun will cause the model to follow the player around and supress the real
+view weapon model. The default frame 0 of most guns is completely off screen,
+so you will probably have to cycle a couple frames to see it.
+
+"nextframe", "prevframe", "nextskin", and "prevskin" commands will change the
+frame or skin of the testmodel. These are bound to F5, F6, F7, and F8 in
+q3default.cfg.
+
+If a gun is being tested, the "gun_x", "gun_y", and "gun_z" variables will let
+you adjust the positioning.
+
+Note that none of the model testing features update while the game is paused, so
+it may be convenient to test with deathmatch set to 1 so that bringing down the
+console doesn't pause the game.
+
+=============================================================================
+*/
+
+/*
+=================
+CG_TestModel_f
+
+Creates an entity in front of the current position, which
+can then be moved around
+=================
+*/
+void CG_TestModel_f (void) {
+ vec3_t angles;
+
+ memset( &cg.testModelEntity, 0, sizeof(cg.testModelEntity) );
+ if ( trap_Argc() < 2 ) {
+ return;
+ }
+
+ Q_strncpyz (cg.testModelName, CG_Argv( 1 ), MAX_QPATH );
+ cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
+
+ if ( trap_Argc() == 3 ) {
+ cg.testModelEntity.backlerp = atof( CG_Argv( 2 ) );
+ cg.testModelEntity.frame = 1;
+ cg.testModelEntity.oldframe = 0;
+ }
+ if (! cg.testModelEntity.hModel ) {
+ CG_Printf( "Can't register model\n" );
+ return;
+ }
+
+ VectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[0], cg.testModelEntity.origin );
+
+ angles[PITCH] = 0;
+ angles[YAW] = 180 + cg.refdefViewAngles[1];
+ angles[ROLL] = 0;
+
+ AnglesToAxis( angles, cg.testModelEntity.axis );
+ cg.testGun = qfalse;
+}
+
+/*
+=================
+CG_TestGun_f
+
+Replaces the current view weapon with the given model
+=================
+*/
+void CG_TestGun_f (void) {
+ CG_TestModel_f();
+ cg.testGun = qtrue;
+ cg.testModelEntity.renderfx = RF_MINLIGHT | RF_DEPTHHACK | RF_FIRST_PERSON;
+}
+
+
+void CG_TestModelNextFrame_f (void) {
+ cg.testModelEntity.frame++;
+ CG_Printf( "frame %i\n", cg.testModelEntity.frame );
+}
+
+void CG_TestModelPrevFrame_f (void) {
+ cg.testModelEntity.frame--;
+ if ( cg.testModelEntity.frame < 0 ) {
+ cg.testModelEntity.frame = 0;
+ }
+ CG_Printf( "frame %i\n", cg.testModelEntity.frame );
+}
+
+void CG_TestModelNextSkin_f (void) {
+ cg.testModelEntity.skinNum++;
+ CG_Printf( "skin %i\n", cg.testModelEntity.skinNum );
+}
+
+void CG_TestModelPrevSkin_f (void) {
+ cg.testModelEntity.skinNum--;
+ if ( cg.testModelEntity.skinNum < 0 ) {
+ cg.testModelEntity.skinNum = 0;
+ }
+ CG_Printf( "skin %i\n", cg.testModelEntity.skinNum );
+}
+
+static void CG_AddTestModel (void) {
+ int i;
+
+ // re-register the model, because the level may have changed
+ cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
+ if (! cg.testModelEntity.hModel ) {
+ CG_Printf ("Can't register model\n");
+ return;
+ }
+
+ // if testing a gun, set the origin reletive to the view origin
+ if ( cg.testGun ) {
+ VectorCopy( cg.refdef.vieworg, cg.testModelEntity.origin );
+ VectorCopy( cg.refdef.viewaxis[0], cg.testModelEntity.axis[0] );
+ VectorCopy( cg.refdef.viewaxis[1], cg.testModelEntity.axis[1] );
+ VectorCopy( cg.refdef.viewaxis[2], cg.testModelEntity.axis[2] );
+
+ // allow the position to be adjusted
+ for (i=0 ; i<3 ; i++) {
+ cg.testModelEntity.origin[i] += cg.refdef.viewaxis[0][i] * cg_gun_x.value;
+ cg.testModelEntity.origin[i] += cg.refdef.viewaxis[1][i] * cg_gun_y.value;
+ cg.testModelEntity.origin[i] += cg.refdef.viewaxis[2][i] * cg_gun_z.value;
+ }
+ }
+
+ trap_R_AddRefEntityToScene( &cg.testModelEntity );
+}
+
+
+
+//============================================================================
+
+
+/*
+=================
+CG_CalcVrect
+
+Sets the coordinates of the rendered window
+=================
+*/
+static void CG_CalcVrect (void) {
+ int size;
+
+ // the intermission should allways be full screen
+ if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
+ size = 100;
+ } else {
+ // bound normal viewsize
+ if (cg_viewsize.integer < 30) {
+ trap_Cvar_Set ("cg_viewsize","30");
+ size = 30;
+ } else if (cg_viewsize.integer > 100) {
+ trap_Cvar_Set ("cg_viewsize","100");
+ size = 100;
+ } else {
+ size = cg_viewsize.integer;
+ }
+
+ }
+ cg.refdef.width = cgs.glconfig.vidWidth*size/100;
+ cg.refdef.width &= ~1;
+
+ cg.refdef.height = cgs.glconfig.vidHeight*size/100;
+ cg.refdef.height &= ~1;
+
+ cg.refdef.x = (cgs.glconfig.vidWidth - cg.refdef.width)/2;
+ cg.refdef.y = (cgs.glconfig.vidHeight - cg.refdef.height)/2;
+}
+
+//==============================================================================
+
+
+/*
+===============
+CG_OffsetThirdPersonView
+
+===============
+*/
+#define FOCUS_DISTANCE 512
+static void CG_OffsetThirdPersonView( void ) {
+ vec3_t forward, right, up;
+ vec3_t view;
+ vec3_t focusAngles;
+ trace_t trace;
+ static vec3_t mins = { -4, -4, -4 };
+ static vec3_t maxs = { 4, 4, 4 };
+ vec3_t focusPoint;
+ float focusDist;
+ float forwardScale, sideScale;
+
+ cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight;
+
+ VectorCopy( cg.refdefViewAngles, focusAngles );
+
+ // if dead, look at killer
+ if ( (cg.predictedPlayerState.stats[STAT_HEALTH] <= 0) &&
+ (cgs.gametype !=GT_ELIMINATION && cgs.gametype !=GT_CTF_ELIMINATION && cgs.gametype !=GT_LMS) ) {
+ focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
+ cg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
+ }
+
+ if ( focusAngles[PITCH] > 45 ) {
+ focusAngles[PITCH] = 45; // don't go too far overhead
+ }
+ AngleVectors( focusAngles, forward, NULL, NULL );
+
+ VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint );
+
+ VectorCopy( cg.refdef.vieworg, view );
+
+ view[2] += 8;
+
+ cg.refdefViewAngles[PITCH] *= 0.5;
+
+ AngleVectors( cg.refdefViewAngles, forward, right, up );
+
+ forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI );
+ sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI );
+ VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view );
+ VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view );
+
+ // trace a ray from the origin to the viewpoint to make sure the view isn't
+ // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything
+
+ if (!cg_cameraMode.integer) {
+ CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
+
+ if ( trace.fraction != 1.0 ) {
+ VectorCopy( trace.endpos, view );
+ view[2] += (1.0 - trace.fraction) * 32;
+ // try another trace to this position, because a tunnel may have the ceiling
+ // close enogh that this is poking out
+
+ CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
+ VectorCopy( trace.endpos, view );
+ }
+ }
+
+
+ VectorCopy( view, cg.refdef.vieworg );
+
+ // select pitch to look at focus point from vieword
+ VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
+ focusDist = sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] );
+ if ( focusDist < 1 ) {
+ focusDist = 1; // should never happen
+ }
+ cg.refdefViewAngles[PITCH] = -180 / M_PI * atan2( focusPoint[2], focusDist );
+ cg.refdefViewAngles[YAW] -= cg_thirdPersonAngle.value;
+}
+
+
+// this causes a compiler bug on mac MrC compiler
+static void CG_StepOffset( void ) {
+ int timeDelta;
+
+ // smooth out stair climbing
+ timeDelta = cg.time - cg.stepTime;
+ if ( timeDelta < STEP_TIME ) {
+ cg.refdef.vieworg[2] -= cg.stepChange
+ * (STEP_TIME - timeDelta) / STEP_TIME;
+ }
+}
+
+/*
+===============
+CG_OffsetFirstPersonView
+
+===============
+*/
+static void CG_OffsetFirstPersonView( void ) {
+ float *origin;
+ float *angles;
+ float bob;
+ float ratio;
+ float delta;
+ float speed;
+ float f;
+ vec3_t predictedVelocity;
+ int timeDelta;
+
+ if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
+ return;
+ }
+
+ origin = cg.refdef.vieworg;
+ angles = cg.refdefViewAngles;
+
+ // if dead, fix the angle and don't add any kick
+ if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
+ angles[ROLL] = 40;
+ angles[PITCH] = -15;
+ angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW];
+ origin[2] += cg.predictedPlayerState.viewheight;
+ return;
+ }
+
+ // add angles based on weapon kick
+ VectorAdd (angles, cg.kick_angles, angles);
+
+ // add angles based on damage kick
+ if ( cg.damageTime && cgs.gametype!=GT_ELIMINATION && cgs.gametype!=GT_CTF_ELIMINATION && cgs.gametype!=GT_LMS) {
+ ratio = cg.time - cg.damageTime;
+ if ( ratio < DAMAGE_DEFLECT_TIME ) {
+ ratio /= DAMAGE_DEFLECT_TIME;
+ angles[PITCH] += ratio * cg.v_dmg_pitch;
+ angles[ROLL] += ratio * cg.v_dmg_roll;
+ } else {
+ ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME;
+ if ( ratio > 0 ) {
+ angles[PITCH] += ratio * cg.v_dmg_pitch;
+ angles[ROLL] += ratio * cg.v_dmg_roll;
+ }
+ }
+ }
+
+ // add pitch based on fall kick
+#if 0
+ ratio = ( cg.time - cg.landTime) / FALL_TIME;
+ if (ratio < 0)
+ ratio = 0;
+ angles[PITCH] += ratio * cg.fall_value;
+#endif
+
+ // add angles based on velocity
+ VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity );
+
+ delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[0]);
+ angles[PITCH] += delta * cg_runpitch.value;
+
+ delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[1]);
+ angles[ROLL] -= delta * cg_runroll.value;
+
+ // add angles based on bob
+
+ // make sure the bob is visible even at low speeds
+ speed = cg.xyspeed > 200 ? cg.xyspeed : 200;
+
+ delta = cg.bobfracsin * cg_bobpitch.value * speed;
+ if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
+ delta *= 3; // crouching
+ angles[PITCH] += delta;
+ delta = cg.bobfracsin * cg_bobroll.value * speed;
+ if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
+ delta *= 3; // crouching accentuates roll
+ if (cg.bobcycle & 1)
+ delta = -delta;
+ angles[ROLL] += delta;
+
+//===================================
+
+ // add view height
+ origin[2] += cg.predictedPlayerState.viewheight;
+
+ // smooth out duck height changes
+ timeDelta = cg.time - cg.duckTime;
+ if ( timeDelta < DUCK_TIME) {
+ cg.refdef.vieworg[2] -= cg.duckChange
+ * (DUCK_TIME - timeDelta) / DUCK_TIME;
+ }
+
+ // add bob height
+ bob = cg.bobfracsin * cg.xyspeed * cg_bobup.value;
+ if (bob > 6) {
+ bob = 6;
+ }
+
+ origin[2] += bob;
+
+
+ // add fall height
+ delta = cg.time - cg.landTime;
+ if ( delta < LAND_DEFLECT_TIME ) {
+ f = delta / LAND_DEFLECT_TIME;
+ cg.refdef.vieworg[2] += cg.landChange * f;
+ } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
+ delta -= LAND_DEFLECT_TIME;
+ f = 1.0 - ( delta / LAND_RETURN_TIME );
+ cg.refdef.vieworg[2] += cg.landChange * f;
+ }
+
+ // add step offset
+ CG_StepOffset();
+
+ // add kick offset
+
+ VectorAdd (origin, cg.kick_origin, origin);
+
+ // pivot the eye based on a neck length
+#if 0
+ {
+#define NECK_LENGTH 8
+ vec3_t forward, up;
+
+ cg.refdef.vieworg[2] -= NECK_LENGTH;
+ AngleVectors( cg.refdefViewAngles, forward, NULL, up );
+ VectorMA( cg.refdef.vieworg, 3, forward, cg.refdef.vieworg );
+ VectorMA( cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg );
+ }
+#endif
+}
+
+//======================================================================
+
+void CG_ZoomDown_f( void ) {
+ if ( cg.zoomed ) {
+ return;
+ }
+ cg.zoomed = qtrue;
+ cg.zoomTime = cg.time;
+}
+
+void CG_ZoomUp_f( void ) {
+ if ( !cg.zoomed ) {
+ return;
+ }
+ cg.zoomed = qfalse;
+ cg.zoomTime = cg.time;
+}
+
+
+/*
+====================
+CG_CalcFov
+
+Fixed fov at intermissions, otherwise account for fov variable and zooms.
+====================
+*/
+#define WAVE_AMPLITUDE 1
+#define WAVE_FREQUENCY 0.4
+
+static int CG_CalcFov( void ) {
+ float x;
+ float phase;
+ float v;
+ int contents;
+ float fov_x, fov_y;
+ float zoomFov;
+ float f;
+ int inwater;
+
+ if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
+ // if in intermission, use a fixed value
+ fov_x = 90;
+ } else {
+ // user selectable
+ if ( cgs.dmflags & DF_FIXED_FOV ) {
+ // dmflag to prevent wide fov for all clients
+ fov_x = 90;
+ } else {
+ fov_x = cg_fov.value;
+ if ( fov_x < 1 ) {
+ fov_x = 1;
+ } else if ( fov_x > 160 ) {
+ fov_x = 160;
+ }
+ if( (cgs.videoflags & VF_LOCK_CVARS_BASIC) && fov_x>140 )
+ fov_x = 140;
+
+ }
+
+ if ( cgs.dmflags & DF_FIXED_FOV ) {
+ // dmflag to prevent wide fov for all clients
+ zoomFov = 22.5;
+ } else {
+ // account for zooms
+ zoomFov = cg_zoomFov.value;
+ if ( zoomFov < 1 ) {
+ zoomFov = 1;
+ } else if ( zoomFov > 160 ) {
+ zoomFov = 160;
+ }
+
+ if( (cgs.videoflags & VF_LOCK_CVARS_BASIC) && zoomFov>140 )
+ zoomFov = 140;
+ }
+
+ if ( cg.zoomed ) {
+ f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
+ if ( f > 1.0 ) {
+ fov_x = zoomFov;
+ } else {
+ fov_x = fov_x + f * ( zoomFov - fov_x );
+ }
+ } else {
+ f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
+ if ( f > 1.0 ) {
+ fov_x = fov_x;
+ } else {
+ fov_x = zoomFov + f * ( fov_x - zoomFov );
+ }
+ }
+ }
+
+ x = cg.refdef.width / tan( fov_x / 360 * M_PI );
+ fov_y = atan2( cg.refdef.height, x );
+ fov_y = fov_y * 360 / M_PI;
+
+ // warp if underwater
+ contents = CG_PointContents( cg.refdef.vieworg, -1 );
+ if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ){
+ phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
+ v = WAVE_AMPLITUDE * sin( phase );
+ fov_x += v;
+ fov_y -= v;
+ inwater = qtrue;
+ }
+ else {
+ inwater = qfalse;
+ }
+
+
+ // set it
+ cg.refdef.fov_x = fov_x;
+ cg.refdef.fov_y = fov_y;
+
+ if ( !cg.zoomed ) {
+ cg.zoomSensitivity = 1;
+ } else {
+ cg.zoomSensitivity = cg.refdef.fov_y / 75.0;
+ }
+
+ return inwater;
+}
+
+
+
+/*
+===============
+CG_DamageBlendBlob
+
+===============
+*/
+static void CG_DamageBlendBlob( void ) {
+ int t;
+ int maxTime;
+ refEntity_t ent;
+
+ if ( !cg.damageValue ) {
+ return;
+ }
+
+ //if (cg.cameraMode) {
+ // return;
+ //}
+
+ // ragePro systems can't fade blends, so don't obscure the screen
+ if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
+ return;
+ }
+
+ maxTime = DAMAGE_TIME;
+ t = cg.time - cg.damageTime;
+ if ( t <= 0 || t >= maxTime ) {
+ return;
+ }
+
+
+ memset( &ent, 0, sizeof( ent ) );
+ ent.reType = RT_SPRITE;
+ ent.renderfx = RF_FIRST_PERSON;
+
+ VectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], ent.origin );
+ VectorMA( ent.origin, cg.damageX * -8, cg.refdef.viewaxis[1], ent.origin );
+ VectorMA( ent.origin, cg.damageY * 8, cg.refdef.viewaxis[2], ent.origin );
+
+ ent.radius = cg.damageValue * 3;
+ ent.customShader = cgs.media.viewBloodShader;
+ ent.shaderRGBA[0] = 255;
+ ent.shaderRGBA[1] = 255;
+ ent.shaderRGBA[2] = 255;
+ ent.shaderRGBA[3] = 200 * ( 1.0 - ((float)t / maxTime) );
+ trap_R_AddRefEntityToScene( &ent );
+}
+
+
+/*
+===============
+CG_CalcViewValues
+
+Sets cg.refdef view values
+===============
+*/
+static int CG_CalcViewValues( void ) {
+ playerState_t *ps;
+
+ memset( &cg.refdef, 0, sizeof( cg.refdef ) );
+
+ // strings for in game rendering
+ // Q_strncpyz( cg.refdef.text[0], "Park Ranger", sizeof(cg.refdef.text[0]) );
+ // Q_strncpyz( cg.refdef.text[1], "19", sizeof(cg.refdef.text[1]) );
+
+ // calculate size of 3D view
+ CG_CalcVrect();
+
+ ps = &cg.predictedPlayerState;
+/*
+ if (cg.cameraMode) {
+ vec3_t origin, angles;
+ if (trap_getCameraInfo(cg.time, &origin, &angles)) {
+ VectorCopy(origin, cg.refdef.vieworg);
+ angles[ROLL] = 0;
+ VectorCopy(angles, cg.refdefViewAngles);
+ AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
+ return CG_CalcFov();
+ } else {
+ cg.cameraMode = qfalse;
+ }
+ }
+*/
+ // intermission view
+ if ( ps->pm_type == PM_INTERMISSION ) {
+ VectorCopy( ps->origin, cg.refdef.vieworg );
+ VectorCopy( ps->viewangles, cg.refdefViewAngles );
+ AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
+ return CG_CalcFov();
+ }
+
+ cg.bobcycle = ( ps->bobCycle & 128 ) >> 7;
+ cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) );
+
+ cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] +
+ ps->velocity[1] * ps->velocity[1] );
+
+
+ VectorCopy( ps->origin, cg.refdef.vieworg );
+ VectorCopy( ps->viewangles, cg.refdefViewAngles );
+
+ if (cg_cameraOrbit.integer) {
+ if (cg.time > cg.nextOrbitTime) {
+ cg.nextOrbitTime = cg.time + cg_cameraOrbitDelay.integer;
+ cg_thirdPersonAngle.value += cg_cameraOrbit.value;
+ }
+ }
+ // add error decay
+ if ( cg_errorDecay.value > 0 ) {
+ int t;
+ float f;
+
+ t = cg.time - cg.predictedErrorTime;
+ f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
+ if ( f > 0 && f < 1 ) {
+ VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg );
+ } else {
+ cg.predictedErrorTime = 0;
+ }
+ }
+
+ if ( cg.renderingThirdPerson ) {
+ // back away from character
+ CG_OffsetThirdPersonView();
+ } else {
+ // offset for local bobbing and kicks
+ CG_OffsetFirstPersonView();
+ }
+
+ // position eye reletive to origin
+ AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
+
+ if ( cg.hyperspace ) {
+ cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE;
+ }
+
+ // field of view
+ return CG_CalcFov();
+}
+
+
+/*
+=====================
+CG_PowerupTimerSounds
+=====================
+*/
+static void CG_PowerupTimerSounds( void ) {
+ int i;
+ int t;
+
+ // powerup timers going away
+ for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
+ t = cg.snap->ps.powerups[i];
+ if ( t <= cg.time ) {
+ continue;
+ }
+ if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
+ continue;
+ }
+ if ( ( t - cg.time ) / POWERUP_BLINK_TIME != ( t - cg.oldTime ) / POWERUP_BLINK_TIME ) {
+ trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_ITEM, cgs.media.wearOffSound );
+ }
+ }
+}
+
+/*
+=====================
+CG_AddBufferedSound
+=====================
+*/
+void CG_AddBufferedSound( sfxHandle_t sfx ) {
+ if ( !sfx )
+ return;
+ cg.soundBuffer[cg.soundBufferIn] = sfx;
+ cg.soundBufferIn = (cg.soundBufferIn + 1) % MAX_SOUNDBUFFER;
+ if (cg.soundBufferIn == cg.soundBufferOut) {
+ cg.soundBufferOut++;
+ }
+}
+
+/*
+=====================
+CG_PlayBufferedSounds
+=====================
+*/
+static void CG_PlayBufferedSounds( void ) {
+ if ( cg.soundTime < cg.time ) {
+ if (cg.soundBufferOut != cg.soundBufferIn && cg.soundBuffer[cg.soundBufferOut]) {
+ trap_S_StartLocalSound(cg.soundBuffer[cg.soundBufferOut], CHAN_ANNOUNCER);
+ cg.soundBuffer[cg.soundBufferOut] = 0;
+ cg.soundBufferOut = (cg.soundBufferOut + 1) % MAX_SOUNDBUFFER;
+ cg.soundTime = cg.time + 750;
+ }
+ }
+}
+
+//=========================================================================
+
+/*
+=================
+CG_DrawActiveFrame
+
+Generates and draws a game scene and status information at the given time.
+=================
+*/
+void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) {
+ int inwater;
+
+ cg.time = serverTime;
+ cg.demoPlayback = demoPlayback;
+
+ // update cvars
+ CG_UpdateCvars();
+
+ // if we are only updating the screen as a loading
+ // pacifier, don't even try to read snapshots
+ if ( cg.infoScreenText[0] != 0 ) {
+ CG_DrawInformation();
+ return;
+ }
+
+ // any looped sounds will be respecified as entities
+ // are added to the render list
+ trap_S_ClearLoopingSounds(qfalse);
+
+ // clear all the render lists
+ trap_R_ClearScene();
+
+ // set up cg.snap and possibly cg.nextSnap
+ CG_ProcessSnapshots();
+
+ // if we haven't received any snapshots yet, all
+ // we can draw is the information screen
+ if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
+ CG_DrawInformation();
+ return;
+ }
+
+ // let the client system know what our weapon and zoom settings are
+ trap_SetUserCmdValue( cg.weaponSelect, cg.zoomSensitivity );
+
+ // this counter will be bumped for every valid scene we generate
+ cg.clientFrame++;
+
+ // update cg.predictedPlayerState
+ CG_PredictPlayerState();
+
+ // decide on third person view
+ cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0);
+
+ // build cg.refdef
+ inwater = CG_CalcViewValues();
+
+ // first person blend blobs, done after AnglesToAxis
+ if ( !cg.renderingThirdPerson ) {
+ CG_DamageBlendBlob();
+ }
+
+ // build the render lists
+ if ( !cg.hyperspace ) {
+ CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct
+ CG_AddMarks();
+ CG_AddParticles ();
+ CG_AddLocalEntities();
+ }
+ CG_AddViewWeapon( &cg.predictedPlayerState );
+
+ // add buffered sounds
+ CG_PlayBufferedSounds();
+
+ // play buffered voice chats
+ CG_PlayBufferedVoiceChats();
+
+ // finish up the rest of the refdef
+ if ( cg.testModelEntity.hModel ) {
+ CG_AddTestModel();
+ }
+ cg.refdef.time = cg.time;
+ memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) );
+
+ // warning sounds when powerup is wearing off
+ CG_PowerupTimerSounds();
+
+ // update audio positions
+ trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater );
+
+ // make sure the lagometerSample and frame timing isn't done twice when in stereo
+ if ( stereoView != STEREO_RIGHT ) {
+ cg.frametime = cg.time - cg.oldTime;
+ if ( cg.frametime < 0 ) {
+ cg.frametime = 0;
+ }
+ cg.oldTime = cg.time;
+ CG_AddLagometerFrameInfo();
+ }
+ if (cg_timescale.value != cg_timescaleFadeEnd.value) {
+ if (cg_timescale.value < cg_timescaleFadeEnd.value) {
+ cg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;
+ if (cg_timescale.value > cg_timescaleFadeEnd.value)
+ cg_timescale.value = cg_timescaleFadeEnd.value;
+ }
+ else {
+ cg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;
+ if (cg_timescale.value < cg_timescaleFadeEnd.value)
+ cg_timescale.value = cg_timescaleFadeEnd.value;
+ }
+ if (cg_timescaleFadeSpeed.value) {
+ trap_Cvar_Set("timescale", va("%f", cg_timescale.value));
+ }
+ }
+
+ // actually issue the rendering calls
+ CG_DrawActive( stereoView );
+
+ if ( cg_stats.integer ) {
+ CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame );
+ }
+
+
+}
+
diff --git a/code/cgame/cg_weapons.c b/code/cgame/cg_weapons.c
new file mode 100644
index 0000000..a75707e
--- /dev/null
+++ b/code/cgame/cg_weapons.c
@@ -0,0 +1,3654 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_weapons.c -- events and effects dealing with weapons
+#include "cg_local.h"
+
+/*
+==========================
+CG_MachineGunEjectBrass
+==========================
+*/
+static void CG_MachineGunEjectBrass( centity_t *cent ) {
+ localEntity_t *le;
+ refEntity_t *re;
+ vec3_t velocity, xvelocity;
+ vec3_t offset, xoffset;
+ float waterScale = 1.0f;
+ vec3_t v[3];
+
+ if ( cg_brassTime.integer <= 0 ) {
+ return;
+ }
+
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+
+ velocity[0] = 0;
+ velocity[1] = -50 + 40 * crandom();
+ velocity[2] = 100 + 50 * crandom();
+
+ le->leType = LE_FRAGMENT;
+ le->startTime = cg.time;
+ le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random();
+
+ le->pos.trType = TR_GRAVITY;
+ le->pos.trTime = cg.time - (rand()&15);
+
+ AnglesToAxis( cent->lerpAngles, v );
+
+ offset[0] = 8;
+ offset[1] = -4;
+ offset[2] = 24;
+
+ xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
+ xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
+ xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
+ VectorAdd( cent->lerpOrigin, xoffset, re->origin );
+
+ VectorCopy( re->origin, le->pos.trBase );
+
+ if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
+ waterScale = 0.10f;
+ }
+
+ xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
+ xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
+ xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
+ VectorScale( xvelocity, waterScale, le->pos.trDelta );
+
+ AxisCopy( axisDefault, re->axis );
+ re->hModel = cgs.media.machinegunBrassModel;
+
+ le->bounceFactor = 0.4 * waterScale;
+
+ le->angles.trType = TR_LINEAR;
+ le->angles.trTime = cg.time;
+ le->angles.trBase[0] = rand()&31;
+ le->angles.trBase[1] = rand()&31;
+ le->angles.trBase[2] = rand()&31;
+ le->angles.trDelta[0] = 2;
+ le->angles.trDelta[1] = 1;
+ le->angles.trDelta[2] = 0;
+
+ le->leFlags = LEF_TUMBLE;
+ le->leBounceSoundType = LEBS_BRASS;
+ le->leMarkType = LEMT_NONE;
+}
+
+
+
+/*
+==========================
+CG_ShotgunEjectBrass
+==========================
+*/
+static void CG_ShotgunEjectBrass( centity_t *cent ) {
+ localEntity_t *le;
+ refEntity_t *re;
+ vec3_t velocity, xvelocity;
+ vec3_t offset, xoffset;
+ vec3_t v[3];
+ int i;
+
+ if ( cg_brassTime.integer <= 0 ) {
+ return;
+ }
+
+ for ( i = 0; i < 2; i++ ) {
+ float waterScale = 1.0f;
+
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+
+ velocity[0] = 60 + 60 * crandom();
+ if ( i == 0 ) {
+ velocity[1] = 40 + 10 * crandom();
+ } else {
+ velocity[1] = -40 + 10 * crandom();
+ }
+ velocity[2] = 100 + 50 * crandom();
+
+ le->leType = LE_FRAGMENT;
+ le->startTime = cg.time;
+ le->endTime = le->startTime + cg_brassTime.integer*3 + cg_brassTime.integer * random();
+
+ le->pos.trType = TR_GRAVITY;
+ le->pos.trTime = cg.time;
+
+ AnglesToAxis( cent->lerpAngles, v );
+
+ offset[0] = 8;
+ offset[1] = 0;
+ offset[2] = 24;
+
+ xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
+ xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
+ xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
+ VectorAdd( cent->lerpOrigin, xoffset, re->origin );
+ VectorCopy( re->origin, le->pos.trBase );
+ if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
+ waterScale = 0.10f;
+ }
+
+ xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
+ xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
+ xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
+ VectorScale( xvelocity, waterScale, le->pos.trDelta );
+
+ AxisCopy( axisDefault, re->axis );
+ re->hModel = cgs.media.shotgunBrassModel;
+ le->bounceFactor = 0.3f;
+
+ le->angles.trType = TR_LINEAR;
+ le->angles.trTime = cg.time;
+ le->angles.trBase[0] = rand()&31;
+ le->angles.trBase[1] = rand()&31;
+ le->angles.trBase[2] = rand()&31;
+ le->angles.trDelta[0] = 1;
+ le->angles.trDelta[1] = 0.5;
+ le->angles.trDelta[2] = 0;
+
+ le->leFlags = LEF_TUMBLE;
+ le->leBounceSoundType = LEBS_SHELL; // LEILEI shell noises
+ le->leMarkType = LEMT_NONE;
+ }
+}
+
+
+//#ifdef MISSIONPACK
+/*
+==========================
+CG_NailgunEjectBrass
+==========================
+*/
+static void CG_NailgunEjectBrass( centity_t *cent ) {
+ localEntity_t *smoke;
+ vec3_t origin;
+ vec3_t v[3];
+ vec3_t offset;
+ vec3_t xoffset;
+ vec3_t up;
+
+ AnglesToAxis( cent->lerpAngles, v );
+
+ offset[0] = 0;
+ offset[1] = -12;
+ offset[2] = 24;
+
+ xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
+ xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
+ xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
+ VectorAdd( cent->lerpOrigin, xoffset, origin );
+
+ VectorSet( up, 0, 0, 64 );
+
+ smoke = CG_SmokePuff( origin, up, 32, 1, 1, 1, 0.33f, 700, cg.time, 0, 0, cgs.media.smokePuffShader );
+ // use the optimized local entity add
+ smoke->leType = LE_SCALE_FADE;
+}
+//#endif
+
+
+/*
+==========================
+CG_RailTrail
+==========================
+*/
+void CG_RailTrail (clientInfo_t *ci, vec3_t start, vec3_t end) {
+ vec3_t axis[36], move, move2, next_move, vec, temp;
+ float len;
+ int i, j, skip;
+
+ localEntity_t *le;
+ refEntity_t *re;
+
+#define RADIUS 4
+#define ROTATION 1
+#define SPACING 5
+
+ start[2] -= 4;
+
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+
+ le->leType = LE_FADE_RGB;
+ le->startTime = cg.time;
+ le->endTime = cg.time + cg_railTrailTime.value;
+ le->lifeRate = 1.0 / (le->endTime - le->startTime);
+
+ re->shaderTime = cg.time / 1000.0f;
+ re->reType = RT_RAIL_CORE;
+ re->customShader = cgs.media.railCoreShader;
+
+ VectorCopy(start, re->origin);
+ VectorCopy(end, re->oldorigin);
+
+ re->shaderRGBA[0] = ci->color1[0] * 255;
+ re->shaderRGBA[1] = ci->color1[1] * 255;
+ re->shaderRGBA[2] = ci->color1[2] * 255;
+ re->shaderRGBA[3] = 255;
+
+ le->color[0] = ci->color1[0] * 0.75;
+ le->color[1] = ci->color1[1] * 0.75;
+ le->color[2] = ci->color1[2] * 0.75;
+ le->color[3] = 1.0f;
+
+ AxisClear( re->axis );
+
+ if (cg_oldRail.integer)
+ {
+ // nudge down a bit so it isn't exactly in center
+ re->origin[2] -= 8;
+ re->oldorigin[2] -= 8;
+ return;
+ }
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+ PerpendicularVector(temp, vec);
+ for (i = 0 ; i < 36; i++)
+ {
+ RotatePointAroundVector(axis[i], vec, temp, i * 10);//banshee 2.4 was 10
+ }
+
+ VectorMA(move, 20, vec, move);
+ VectorCopy(move, next_move);
+ VectorScale (vec, SPACING, vec);
+
+ skip = -1;
+
+ j = 18;
+ for (i = 0; i < len; i += SPACING)
+ {
+ if (i != skip)
+ {
+ skip = i + SPACING;
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+ le->leFlags = LEF_PUFF_DONT_SCALE;
+ le->leType = LE_MOVE_SCALE_FADE;
+ le->startTime = cg.time;
+ le->endTime = cg.time + (i>>1) + 600;
+ le->lifeRate = 1.0 / (le->endTime - le->startTime);
+
+ re->shaderTime = cg.time / 1000.0f;
+ re->reType = RT_SPRITE;
+ re->radius = 1.1f;
+ re->customShader = cgs.media.railRingsShader;
+
+ re->shaderRGBA[0] = ci->color2[0] * 255;
+ re->shaderRGBA[1] = ci->color2[1] * 255;
+ re->shaderRGBA[2] = ci->color2[2] * 255;
+ re->shaderRGBA[3] = 255;
+
+ le->color[0] = ci->color2[0] * 0.75;
+ le->color[1] = ci->color2[1] * 0.75;
+ le->color[2] = ci->color2[2] * 0.75;
+ le->color[3] = 1.0f;
+
+ le->pos.trType = TR_LINEAR;
+ le->pos.trTime = cg.time;
+
+ VectorCopy( move, move2);
+ VectorMA(move2, RADIUS , axis[j], move2);
+ VectorCopy(move2, le->pos.trBase);
+
+ le->pos.trDelta[0] = axis[j][0]*6;
+ le->pos.trDelta[1] = axis[j][1]*6;
+ le->pos.trDelta[2] = axis[j][2]*6;
+ }
+
+ VectorAdd (move, vec, move);
+
+ j = (j + ROTATION) % 36;
+ }
+}
+
+/*
+==========================
+CG_OldRocketTrail (for the crappy old rocket trail.)
+==========================
+*/
+static void CG_OldRocketTrail( centity_t *ent, const weaponInfo_t *wi ) {
+ int step;
+ vec3_t origin, lastPos;
+ int t;
+ int startTime, contents;
+ int lastContents;
+ entityState_t *es;
+ vec3_t up;
+ localEntity_t *smoke;
+
+ if ( cg_noProjectileTrail.integer ) {
+ return;
+ }
+
+ up[0] = 0;
+ up[1] = 0;
+ up[2] = 0;
+
+ step = 50;
+
+ es = &ent->currentState;
+ startTime = ent->trailTime;
+ t = step * ( (startTime + step) / step );
+
+ BG_EvaluateTrajectory( &es->pos, cg.time, origin );
+ contents = CG_PointContents( origin, -1 );
+
+ // if object (e.g. grenade) is stationary, don't toss up smoke
+ if ( es->pos.trType == TR_STATIONARY ) {
+ ent->trailTime = cg.time;
+ return;
+ }
+
+ BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
+ lastContents = CG_PointContents( lastPos, -1 );
+
+ ent->trailTime = cg.time;
+
+ if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
+ if ( contents & lastContents & CONTENTS_WATER ) {
+ CG_BubbleTrail( lastPos, origin, 8 );
+ }
+ return;
+ }
+
+ for ( ; t <= ent->trailTime ; t += step ) {
+ BG_EvaluateTrajectory( &es->pos, t, lastPos );
+
+ smoke = CG_SmokePuff( lastPos, up,
+ wi->trailRadius,
+ 1, 1, 1, 0.33f,
+ wi->wiTrailTime,
+ t,
+ 0,
+ 0,
+ cgs.media.smokePuffShader );
+ // use the optimized local entity add
+ smoke->leType = LE_SCALE_FADE;
+ }
+
+}
+
+/*
+==========================
+CG_LeiSmokeTrail
+==========================
+*/
+
+static void CG_LeiSmokeTrail( centity_t *ent, const weaponInfo_t *wi ) {
+ int step;
+ vec3_t origin, lastPos;
+ int t;
+ int startTime, contents;
+ int lastContents;
+ entityState_t *es;
+ vec3_t up;
+ localEntity_t *smoke;
+ int therando;
+ int theradio;
+
+ if ( cg_noProjectileTrail.integer ) {
+ return;
+ }
+
+ up[0] = 5 - 10 * crandom();
+ up[1] = 5 - 10 * crandom();
+ up[2] = 8 - 5 * crandom();
+
+ step = 18;
+
+ es = &ent->currentState;
+ startTime = ent->trailTime;
+ t = step * ( (startTime + step) / step );
+
+ BG_EvaluateTrajectory( &es->pos, cg.time, origin );
+ contents = CG_PointContents( origin, -1 );
+
+ // if object (e.g. grenade) is stationary, don't toss up smoke
+ if ( es->pos.trType == TR_STATIONARY ) {
+ ent->trailTime = cg.time;
+ return;
+ }
+
+ BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
+ lastContents = CG_PointContents( lastPos, -1 );
+
+ ent->trailTime = cg.time;
+
+ if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
+ if ( contents & lastContents & CONTENTS_WATER ) {
+ CG_BubbleTrail( lastPos, origin, 8 );
+ }
+ return;
+ }
+
+ for ( ; t <= ent->trailTime ; t += step ) {
+ BG_EvaluateTrajectory( &es->pos, t, lastPos );
+ therando = crandom() * 4;
+
+ theradio = wi->trailRadius * (rand() * 0.7); // what is this doing here
+ if (therando == 3) smoke = CG_SmokePuff( lastPos, up, 27, 1, 1, 1, 0.9f, wi->wiTrailTime, t, 0, 0, cgs.media.lsmkShader1 );
+ else if (therando == 1) smoke = CG_SmokePuff( lastPos, up, 27, 1, 1, 1, 0.9f, wi->wiTrailTime, t, 0, 0, cgs.media.lsmkShader2 );
+ else if (therando == 2) smoke = CG_SmokePuff( lastPos, up, 27, 1, 1, 1, 0.9f, wi->wiTrailTime, t, 0, 0, cgs.media.lsmkShader3 );
+ else smoke = CG_SmokePuff( lastPos, up, 27, 1, 1, 1, 0.9f, wi->wiTrailTime, t, 0, 0, cgs.media.lsmkShader4 );
+ // use the optimized local entity add
+ smoke->leType = LE_MOVE_SCALE_FADE;
+ //smoke->trType = TR_GRAVITY;
+ }
+
+}
+
+
+static void CG_LeiPlasmaTrail( centity_t *ent, const weaponInfo_t *wi ) {
+ int step;
+ vec3_t origin, lastPos;
+ int t;
+ int startTime, contents;
+ int lastContents;
+ entityState_t *es;
+ vec3_t up;
+ localEntity_t *smoke;
+
+ if ( cg_noProjectileTrail.integer ) {
+ return;
+ }
+
+ up[0] = 0;
+ up[1] = 0;
+ up[2] = 0;
+
+ step = 16;
+
+ es = &ent->currentState;
+ startTime = ent->trailTime;
+ t = step * ( (startTime + step) / step );
+
+ BG_EvaluateTrajectory( &es->pos, cg.time, origin );
+ contents = CG_PointContents( origin, -1 );
+
+ // if object (e.g. grenade) is stationary, don't toss up smoke
+ if ( es->pos.trType == TR_STATIONARY ) {
+ ent->trailTime = cg.time;
+ return;
+ }
+
+ BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
+ lastContents = CG_PointContents( lastPos, -1 );
+
+ ent->trailTime = cg.time;
+
+ if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
+ return;
+ }
+
+ for ( ; t <= ent->trailTime ; t += step ) {
+ BG_EvaluateTrajectory( &es->pos, t, lastPos );
+
+ smoke = CG_SmokePuff( lastPos, up, 27, 1, 1, 1, 0.9f, wi->wiTrailTime, t, 0, 0, cgs.media.lsmkShader1 );
+ // use the optimized local entity add
+ smoke->leType = LE_SCALE_FADE;
+ //smoke->trType = TR_GRAVITY;
+ }
+
+}
+
+
+//#ifdef MISSIONPACK
+/*
+==========================
+CG_NailTrail
+==========================
+*/
+static void CG_NailTrail( centity_t *ent, const weaponInfo_t *wi ) {
+ int step;
+ vec3_t origin, lastPos;
+ int t;
+ int startTime, contents;
+ int lastContents;
+ entityState_t *es;
+ vec3_t up;
+ localEntity_t *smoke;
+
+ if ( cg_noProjectileTrail.integer ) {
+ return;
+ }
+
+ up[0] = 0;
+ up[1] = 0;
+ up[2] = 0;
+
+ step = 50;
+
+ es = &ent->currentState;
+ startTime = ent->trailTime;
+ t = step * ( (startTime + step) / step );
+
+ BG_EvaluateTrajectory( &es->pos, cg.time, origin );
+ contents = CG_PointContents( origin, -1 );
+
+ // if object (e.g. grenade) is stationary, don't toss up smoke
+ if ( es->pos.trType == TR_STATIONARY ) {
+ ent->trailTime = cg.time;
+ return;
+ }
+
+ BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
+ lastContents = CG_PointContents( lastPos, -1 );
+
+ ent->trailTime = cg.time;
+
+ if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
+ if ( contents & lastContents & CONTENTS_WATER ) {
+ CG_BubbleTrail( lastPos, origin, 8 );
+ }
+ return;
+ }
+
+ for ( ; t <= ent->trailTime ; t += step ) {
+ BG_EvaluateTrajectory( &es->pos, t, lastPos );
+
+ smoke = CG_SmokePuff( lastPos, up,
+ wi->trailRadius,
+ 1, 1, 1, 0.33f,
+ wi->wiTrailTime,
+ t,
+ 0,
+ 0,
+ cgs.media.nailPuffShader );
+ // use the optimized local entity add
+ smoke->leType = LE_SCALE_FADE;
+ }
+
+}
+//#endif
+
+/*
+==========================
+CG_NailTrail
+==========================
+*/
+static void CG_OldPlasmaTrail( centity_t *cent, const weaponInfo_t *wi ) {
+ localEntity_t *le;
+ refEntity_t *re;
+ entityState_t *es;
+ vec3_t velocity, xvelocity, origin;
+ vec3_t offset, xoffset;
+ vec3_t v[3];
+ int t, startTime, step;
+
+ float waterScale = 1.0f;
+
+ if ( cg_noProjectileTrail.integer || cg_oldPlasma.integer ) {
+ return;
+ }
+
+ step = 50;
+
+ es = ¢->currentState;
+ startTime = cent->trailTime;
+ t = step * ( (startTime + step) / step );
+
+ BG_EvaluateTrajectory( &es->pos, cg.time, origin );
+
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+
+ velocity[0] = 60 - 120 * crandom();
+ velocity[1] = 40 - 80 * crandom();
+ velocity[2] = 100 - 200 * crandom();
+
+ le->leType = LE_MOVE_SCALE_FADE;
+ le->leFlags = LEF_TUMBLE;
+ le->leBounceSoundType = LEBS_NONE;
+ le->leMarkType = LEMT_NONE;
+
+ le->startTime = cg.time;
+ le->endTime = le->startTime + 600;
+
+ le->pos.trType = TR_GRAVITY;
+ le->pos.trTime = cg.time;
+
+ AnglesToAxis( cent->lerpAngles, v );
+
+ offset[0] = 2;
+ offset[1] = 2;
+ offset[2] = 2;
+
+ xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
+ xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
+ xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
+
+ VectorAdd( origin, xoffset, re->origin );
+ VectorCopy( re->origin, le->pos.trBase );
+
+ if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
+ waterScale = 0.10f;
+ }
+
+ xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
+ xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
+ xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
+ VectorScale( xvelocity, waterScale, le->pos.trDelta );
+
+ AxisCopy( axisDefault, re->axis );
+ re->shaderTime = cg.time / 1000.0f;
+ re->reType = RT_SPRITE;
+ re->radius = 0.25f;
+ re->customShader = cgs.media.railRingsShader;
+ le->bounceFactor = 0.3f;
+
+
+ re->shaderRGBA[0] = wi->flashDlightColor[0] * 63;
+ re->shaderRGBA[1] = wi->flashDlightColor[1] * 63;
+ re->shaderRGBA[2] = wi->flashDlightColor[2] * 63;
+ re->shaderRGBA[3] = 63;
+
+ le->color[0] = wi->flashDlightColor[0] * 0.2;
+ le->color[1] = wi->flashDlightColor[1] * 0.2;
+ le->color[2] = wi->flashDlightColor[2] * 0.2;
+ le->color[3] = 0.25f;
+
+ le->angles.trType = TR_LINEAR;
+ le->angles.trTime = cg.time;
+ le->angles.trBase[0] = rand()&31;
+ le->angles.trBase[1] = rand()&31;
+ le->angles.trBase[2] = rand()&31;
+ le->angles.trDelta[0] = 1;
+ le->angles.trDelta[1] = 0.5;
+ le->angles.trDelta[2] = 0;
+
+}
+/*
+==========================
+CG_GrappleTrail
+==========================
+*/
+void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi ) {
+ vec3_t origin;
+ entityState_t *es;
+ vec3_t forward, up;
+ refEntity_t beam;
+
+ es = &ent->currentState;
+
+ BG_EvaluateTrajectory( &es->pos, cg.time, origin );
+ ent->trailTime = cg.time;
+
+ memset( &beam, 0, sizeof( beam ) );
+ //FIXME adjust for muzzle position
+ VectorCopy ( cg_entities[ ent->currentState.otherEntityNum ].lerpOrigin, beam.origin );
+ beam.origin[2] += 26;
+ AngleVectors( cg_entities[ ent->currentState.otherEntityNum ].lerpAngles, forward, NULL, up );
+ VectorMA( beam.origin, -6, up, beam.origin );
+ VectorCopy( origin, beam.oldorigin );
+
+ if (Distance( beam.origin, beam.oldorigin ) < 64 )
+ return; // Don't draw if close
+
+ beam.reType = RT_RAIL_CORE;
+ beam.customShader = cgs.media.grappleShader;
+
+ AxisClear( beam.axis );
+ beam.shaderRGBA[0] = 0xff;
+ beam.shaderRGBA[1] = 0xff;
+ beam.shaderRGBA[2] = 0xff;
+ beam.shaderRGBA[3] = 0xff;
+ trap_R_AddRefEntityToScene( &beam );
+}
+
+/*
+==========================
+CG_GrenadeTrail
+==========================
+*/
+// LEILEI enhancment
+static void CG_RocketTrail( centity_t *ent, const weaponInfo_t *wi ) {
+
+ if (cg_leiEnhancement.integer) {
+ CG_LeiSmokeTrail( ent, wi );
+ }
+ else
+ {
+ CG_OldRocketTrail( ent, wi );
+ }
+}
+
+static void CG_PlasmaTrail( centity_t *ent, const weaponInfo_t *wi ) {
+
+ if (cg_leiEnhancement.integer) {
+ CG_LeiPlasmaTrail( ent, wi );
+ }
+ else
+ {
+ CG_OldPlasmaTrail( ent, wi );
+ }
+}
+
+
+static void CG_GrenadeTrail( centity_t *ent, const weaponInfo_t *wi ) {
+ CG_RocketTrail( ent, wi );
+}
+
+
+
+
+
+
+/*
+=================
+CG_RegisterWeapon
+
+The server says this item is used on this level
+=================
+*/
+void CG_RegisterWeapon( int weaponNum ) {
+ weaponInfo_t *weaponInfo;
+ gitem_t *item, *ammo;
+ char path[MAX_QPATH];
+ vec3_t mins, maxs;
+ int i;
+
+ weaponInfo = &cg_weapons[weaponNum];
+
+ if ( weaponNum == 0 ) {
+ return;
+ }
+
+ if ( weaponInfo->registered ) {
+ return;
+ }
+
+ memset( weaponInfo, 0, sizeof( *weaponInfo ) );
+ weaponInfo->registered = qtrue;
+
+ for ( item = bg_itemlist + 1 ; item->classname ; item++ ) {
+ if ( item->giType == IT_WEAPON && item->giTag == weaponNum ) {
+ weaponInfo->item = item;
+ break;
+ }
+ }
+ if ( !item->classname ) {
+ CG_Error( "Couldn't find weapon %i", weaponNum );
+ }
+ CG_RegisterItemVisuals( item - bg_itemlist );
+
+ // load cmodel before model so filecache works
+ weaponInfo->weaponModel = trap_R_RegisterModel( item->world_model[0] );
+
+ // calc midpoint for rotation
+ trap_R_ModelBounds( weaponInfo->weaponModel, mins, maxs );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ weaponInfo->weaponMidpoint[i] = mins[i] + 0.5 * ( maxs[i] - mins[i] );
+ }
+
+ weaponInfo->weaponIcon = trap_R_RegisterShader( item->icon );
+ weaponInfo->ammoIcon = trap_R_RegisterShader( item->icon );
+
+ for ( ammo = bg_itemlist + 1 ; ammo->classname ; ammo++ ) {
+ if ( ammo->giType == IT_AMMO && ammo->giTag == weaponNum ) {
+ break;
+ }
+ }
+ if ( ammo->classname && ammo->world_model[0] ) {
+ weaponInfo->ammoModel = trap_R_RegisterModel( ammo->world_model[0] );
+ }
+
+ Q_strncpyz( path, item->world_model[0], MAX_QPATH );
+ COM_StripExtension(path, path, sizeof(path));
+ strcat( path, "_flash.md3" );
+ weaponInfo->flashModel = trap_R_RegisterModel( path );
+
+ Q_strncpyz( path, item->world_model[0], MAX_QPATH );
+ COM_StripExtension(path, path, sizeof(path));
+ strcat( path, "_barrel.md3" );
+ weaponInfo->barrelModel = trap_R_RegisterModel( path );
+
+ Q_strncpyz( path, item->world_model[0], MAX_QPATH );
+ COM_StripExtension(path, path, sizeof(path));
+ strcat( path, "_hand.md3" );
+ weaponInfo->handsModel = trap_R_RegisterModel( path );
+
+ if ( !weaponInfo->handsModel ) {
+ weaponInfo->handsModel = trap_R_RegisterModel( "models/weapons2/shotgun/shotgun_hand.md3" );
+ }
+
+ weaponInfo->loopFireSound = qfalse;
+
+ switch ( weaponNum ) {
+ case WP_GAUNTLET:
+ MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
+ weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/melee/fstatck.wav", qfalse );
+ break;
+
+ case WP_LIGHTNING:
+ MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
+ weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse );
+ weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/lightning/lg_hum.wav", qfalse );
+
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/lightning/lg_fire.wav", qfalse );
+ cgs.media.lightningShader = trap_R_RegisterShader( "lightningBoltNew");
+ cgs.media.lightningExplosionModel = trap_R_RegisterModel( "models/weaphits/crackle.md3" );
+ cgs.media.sfx_lghit1 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit.wav", qfalse );
+ cgs.media.sfx_lghit2 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit2.wav", qfalse );
+ cgs.media.sfx_lghit3 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit3.wav", qfalse );
+
+ break;
+
+ case WP_GRAPPLING_HOOK:
+ MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
+ weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/hook/hook.md3" );
+ weaponInfo->missileTrailFunc = CG_GrappleTrail;
+ weaponInfo->missileDlight = 0;
+ weaponInfo->wiTrailTime = 2000;
+ weaponInfo->trailRadius = 64;
+ MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );
+ cgs.media.grappleShader = trap_R_RegisterShader( "grappleRope");
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/grapple/grapfire.wav", qfalse );
+ weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/grapple/grappull.wav", qfalse );
+ //cgs.media.lightningShader = trap_R_RegisterShader( "lightningBoltNew");
+ break;
+
+//#ifdef MISSIONPACK
+ case WP_CHAINGUN:
+ weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/vulcan/wvulfire.wav", qfalse );
+ weaponInfo->loopFireSound = qtrue;
+ MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf1b.wav", qfalse );
+ weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf2b.wav", qfalse );
+ weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf3b.wav", qfalse );
+ weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf4b.wav", qfalse );
+ weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;
+ cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
+ break;
+//#endif
+
+ case WP_MACHINEGUN:
+ MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf1b.wav", qfalse );
+ weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf2b.wav", qfalse );
+ weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf3b.wav", qfalse );
+ weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf4b.wav", qfalse );
+ weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;
+ cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
+ break;
+
+ case WP_SHOTGUN:
+ MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/shotgun/sshotf1b.wav", qfalse );
+ weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass;
+ break;
+
+ case WP_ROCKET_LAUNCHER:
+ weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" );
+ weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse );
+ weaponInfo->missileTrailFunc = CG_RocketTrail;
+ weaponInfo->missileDlight = 200;
+ weaponInfo->wiTrailTime = 2000;
+ weaponInfo->trailRadius = 64;
+
+ MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );
+ MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 );
+
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse );
+ cgs.media.rocketExplosionShader = trap_R_RegisterShader( "rocketExplosion" );
+ break;
+
+//#ifdef MISSIONPACK
+ case WP_PROX_LAUNCHER:
+ weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/proxmine.md3" );
+ weaponInfo->missileTrailFunc = CG_GrenadeTrail;
+ weaponInfo->wiTrailTime = 700;
+ weaponInfo->trailRadius = 32;
+ MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/proxmine/wstbfire.wav", qfalse );
+ cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" );
+ break;
+//#endif
+
+ case WP_GRENADE_LAUNCHER:
+ weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/grenade1.md3" );
+ weaponInfo->missileTrailFunc = CG_GrenadeTrail;
+ weaponInfo->wiTrailTime = 700;
+ weaponInfo->trailRadius = 32;
+ MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/grenade/grenlf1a.wav", qfalse );
+ cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" );
+ break;
+
+//#ifdef MISSIONPACK
+ case WP_NAILGUN:
+ weaponInfo->ejectBrassFunc = CG_NailgunEjectBrass;
+ weaponInfo->missileTrailFunc = CG_NailTrail;
+// weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/nailgun/wnalflit.wav", qfalse );
+ weaponInfo->trailRadius = 16;
+ weaponInfo->wiTrailTime = 250;
+ weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/nail.md3" );
+ MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/nailgun/wnalfire.wav", qfalse );
+ break;
+//#endif
+
+ case WP_PLASMAGUN:
+// weaponInfo->missileModel = cgs.media.invulnerabilityPowerupModel;
+ weaponInfo->missileTrailFunc = CG_PlasmaTrail;
+ weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/plasma/lasfly.wav", qfalse );
+ MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/plasma/hyprbf1a.wav", qfalse );
+ cgs.media.plasmaExplosionShader = trap_R_RegisterShader( "plasmaExplosion" );
+ cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" );
+ break;
+
+ case WP_RAILGUN:
+ weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/railgun/rg_hum.wav", qfalse );
+ MAKERGB( weaponInfo->flashDlightColor, 1, 0.5f, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/railgun/railgf1a.wav", qfalse );
+ cgs.media.railExplosionShader = trap_R_RegisterShader( "railExplosion" );
+ cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" );
+ cgs.media.railCoreShader = trap_R_RegisterShader( "railCore" );
+ break;
+
+ case WP_BFG:
+ weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/bfg/bfg_hum.wav", qfalse );
+ MAKERGB( weaponInfo->flashDlightColor, 1, 0.7f, 1 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/bfg/bfg_fire.wav", qfalse );
+ cgs.media.bfgExplosionShader = trap_R_RegisterShader( "bfgExplosion" );
+ weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/bfg.md3" );
+ weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse );
+ break;
+
+ default:
+ MAKERGB( weaponInfo->flashDlightColor, 1, 1, 1 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse );
+ break;
+ }
+}
+
+/*
+=================
+CG_RegisterItemVisuals
+
+The server says this item is used on this level
+=================
+*/
+void CG_RegisterItemVisuals( int itemNum ) {
+ itemInfo_t *itemInfo;
+ gitem_t *item;
+
+ if ( itemNum < 0 || itemNum >= bg_numItems ) {
+ CG_Error( "CG_RegisterItemVisuals: itemNum %d out of range [0-%d]", itemNum, bg_numItems-1 );
+ }
+
+ itemInfo = &cg_items[ itemNum ];
+ if ( itemInfo->registered ) {
+ return;
+ }
+
+ item = &bg_itemlist[ itemNum ];
+
+ memset( itemInfo, 0, sizeof( &itemInfo ) );
+ itemInfo->registered = qtrue;
+
+ itemInfo->models[0] = trap_R_RegisterModel( item->world_model[0] );
+
+ itemInfo->icon = trap_R_RegisterShader( item->icon );
+
+ if ( item->giType == IT_WEAPON ) {
+ CG_RegisterWeapon( item->giTag );
+ }
+
+ //
+ // powerups have an accompanying ring or sphere
+ //
+ if ( item->giType == IT_POWERUP || item->giType == IT_HEALTH ||
+ item->giType == IT_ARMOR || item->giType == IT_HOLDABLE ) {
+ if ( item->world_model[1] ) {
+ itemInfo->models[1] = trap_R_RegisterModel( item->world_model[1] );
+ }
+ }
+}
+
+
+/*
+========================================================================================
+
+VIEW WEAPON
+
+========================================================================================
+*/
+
+/*
+=================
+CG_MapTorsoToWeaponFrame
+
+=================
+*/
+static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame ) {
+
+ // change weapon
+ if ( frame >= ci->animations[TORSO_DROP].firstFrame
+ && frame < ci->animations[TORSO_DROP].firstFrame + 9 ) {
+ return frame - ci->animations[TORSO_DROP].firstFrame + 6;
+ }
+
+ // stand attack
+ if ( frame >= ci->animations[TORSO_ATTACK].firstFrame
+ && frame < ci->animations[TORSO_ATTACK].firstFrame + 6 ) {
+ return 1 + frame - ci->animations[TORSO_ATTACK].firstFrame;
+ }
+
+ // stand attack 2
+ if ( frame >= ci->animations[TORSO_ATTACK2].firstFrame
+ && frame < ci->animations[TORSO_ATTACK2].firstFrame + 6 ) {
+ return 1 + frame - ci->animations[TORSO_ATTACK2].firstFrame;
+ }
+
+ return 0;
+}
+
+
+/*
+==============
+CG_CalculateWeaponPosition
+==============
+*/
+static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) {
+ float scale;
+ int delta;
+ float fracsin;
+
+ VectorCopy( cg.refdef.vieworg, origin );
+ VectorCopy( cg.refdefViewAngles, angles );
+
+ // on odd legs, invert some angles
+ if ( cg.bobcycle & 1 ) {
+ scale = -cg.xyspeed;
+ } else {
+ scale = cg.xyspeed;
+ }
+
+ // gun angles from bobbing
+ angles[ROLL] += scale * cg.bobfracsin * 0.005;
+ angles[YAW] += scale * cg.bobfracsin * 0.01;
+ angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005;
+
+ // drop the weapon when landing
+ delta = cg.time - cg.landTime;
+ if ( delta < LAND_DEFLECT_TIME ) {
+ origin[2] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME;
+ } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
+ origin[2] += cg.landChange*0.25 *
+ (LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME;
+ }
+
+#if 0
+ // drop the weapon when stair climbing
+ delta = cg.time - cg.stepTime;
+ if ( delta < STEP_TIME/2 ) {
+ origin[2] -= cg.stepChange*0.25 * delta / (STEP_TIME/2);
+ } else if ( delta < STEP_TIME ) {
+ origin[2] -= cg.stepChange*0.25 * (STEP_TIME - delta) / (STEP_TIME/2);
+ }
+#endif
+
+ // idle drift
+ scale = cg.xyspeed + 40;
+ fracsin = sin( cg.time * 0.001 );
+ angles[ROLL] += scale * fracsin * 0.01;
+ angles[YAW] += scale * fracsin * 0.01;
+ angles[PITCH] += scale * fracsin * 0.01;
+}
+
+
+/*
+===============
+CG_LightningBolt
+
+Origin will be the exact tag point, which is slightly
+different than the muzzle point used for determining hits.
+The cent should be the non-predicted cent if it is from the player,
+so the endpoint will reflect the simulated strike (lagging the predicted
+angle)
+===============
+*/
+static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
+ trace_t trace;
+ refEntity_t beam;
+ vec3_t forward;
+ vec3_t muzzlePoint, endPoint;
+
+ if (cent->currentState.weapon != WP_LIGHTNING) {
+ return;
+ }
+
+ memset( &beam, 0, sizeof( beam ) );
+
+//unlagged - attack prediction #1
+ // if the entity is us, unlagged is on server-side, and we've got it on for the lightning gun
+ if ( (cent->currentState.number == cg.predictedPlayerState.clientNum) && cgs.delagHitscan &&
+ ( cg_delag.integer & 1 || cg_delag.integer & 8 ) ) {
+ // always shoot straight forward from our current position
+ AngleVectors( cg.predictedPlayerState.viewangles, forward, NULL, NULL );
+ VectorCopy( cg.predictedPlayerState.origin, muzzlePoint );
+ }
+ else
+//unlagged - attack prediction #1
+
+ // CPMA "true" lightning
+ if ((cent->currentState.number == cg.predictedPlayerState.clientNum) && (cg_trueLightning.value != 0)) {
+ vec3_t angle;
+ int i;
+
+//unlagged - true lightning
+ // might as well fix up true lightning while we're at it
+ vec3_t viewangles;
+ VectorCopy( cg.predictedPlayerState.viewangles, viewangles );
+//unlagged - true lightning
+
+ for (i = 0; i < 3; i++) {
+ float a = cent->lerpAngles[i] - cg.refdefViewAngles[i];
+ if (a > 180) {
+ a -= 360;
+ }
+ if (a < -180) {
+ a += 360;
+ }
+
+ angle[i] = cg.refdefViewAngles[i] + a * (1.0 - cg_trueLightning.value);
+ if (angle[i] < 0) {
+ angle[i] += 360;
+ }
+ if (angle[i] > 360) {
+ angle[i] -= 360;
+ }
+ }
+
+ AngleVectors(angle, forward, NULL, NULL );
+//unlagged - true lightning
+// VectorCopy(cent->lerpOrigin, muzzlePoint );
+// VectorCopy(cg.refdef.vieworg, muzzlePoint );
+ // *this* is the correct origin for true lightning
+ VectorCopy(cg.predictedPlayerState.origin, muzzlePoint );
+//unlagged - true lightning
+ } else {
+ // !CPMA
+ AngleVectors( cent->lerpAngles, forward, NULL, NULL );
+ VectorCopy(cent->lerpOrigin, muzzlePoint );
+ }
+
+ // FIXME: crouch
+ muzzlePoint[2] += DEFAULT_VIEWHEIGHT;
+
+ VectorMA( muzzlePoint, 14, forward, muzzlePoint );
+
+ // project forward by the lightning range
+ VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );
+
+ // see if it hit a wall
+ CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint,
+ cent->currentState.number, MASK_SHOT );
+
+ // this is the endpoint
+ VectorCopy( trace.endpos, beam.oldorigin );
+
+ // use the provided origin, even though it may be slightly
+ // different than the muzzle origin
+ VectorCopy( origin, beam.origin );
+
+ beam.reType = RT_LIGHTNING;
+ beam.customShader = cgs.media.lightningShader;
+ trap_R_AddRefEntityToScene( &beam );
+
+ // add the impact flare if it hit something
+ if ( trace.fraction < 1.0 ) {
+ vec3_t angles;
+ vec3_t dir;
+
+ VectorSubtract( beam.oldorigin, beam.origin, dir );
+ VectorNormalize( dir );
+
+ memset( &beam, 0, sizeof( beam ) );
+ beam.hModel = cgs.media.lightningExplosionModel;
+
+ VectorMA( trace.endpos, -16, dir, beam.origin );
+
+ // make a random orientation
+ angles[0] = rand() % 360;
+ angles[1] = rand() % 360;
+ angles[2] = rand() % 360;
+ AnglesToAxis( angles, beam.axis );
+ trap_R_AddRefEntityToScene( &beam );
+ }
+}
+/*
+
+static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
+ trace_t trace;
+ refEntity_t beam;
+ vec3_t forward;
+ vec3_t muzzlePoint, endPoint;
+
+ if ( cent->currentState.weapon != WP_LIGHTNING ) {
+ return;
+ }
+
+ memset( &beam, 0, sizeof( beam ) );
+
+ // find muzzle point for this frame
+ VectorCopy( cent->lerpOrigin, muzzlePoint );
+ AngleVectors( cent->lerpAngles, forward, NULL, NULL );
+
+ // FIXME: crouch
+ muzzlePoint[2] += DEFAULT_VIEWHEIGHT;
+
+ VectorMA( muzzlePoint, 14, forward, muzzlePoint );
+
+ // project forward by the lightning range
+ VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );
+
+ // see if it hit a wall
+ CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint,
+ cent->currentState.number, MASK_SHOT );
+
+ // this is the endpoint
+ VectorCopy( trace.endpos, beam.oldorigin );
+
+ // use the provided origin, even though it may be slightly
+ // different than the muzzle origin
+ VectorCopy( origin, beam.origin );
+
+ beam.reType = RT_LIGHTNING;
+ beam.customShader = cgs.media.lightningShader;
+ trap_R_AddRefEntityToScene( &beam );
+
+ // add the impact flare if it hit something
+ if ( trace.fraction < 1.0 ) {
+ vec3_t angles;
+ vec3_t dir;
+
+ VectorSubtract( beam.oldorigin, beam.origin, dir );
+ VectorNormalize( dir );
+
+ memset( &beam, 0, sizeof( beam ) );
+ beam.hModel = cgs.media.lightningExplosionModel;
+
+ VectorMA( trace.endpos, -16, dir, beam.origin );
+
+ // make a random orientation
+ angles[0] = rand() % 360;
+ angles[1] = rand() % 360;
+ angles[2] = rand() % 360;
+ AnglesToAxis( angles, beam.axis );
+ trap_R_AddRefEntityToScene( &beam );
+ }
+}
+*/
+
+/*
+===============
+CG_SpawnRailTrail
+
+Origin will be the exact tag point, which is slightly
+different than the muzzle point used for determining hits.
+===============
+*/
+static void CG_SpawnRailTrail( centity_t *cent, vec3_t origin ) {
+ clientInfo_t *ci;
+
+ if ( cent->currentState.weapon != WP_RAILGUN ) {
+ return;
+ }
+ if ( !cent->pe.railgunFlash ) {
+ return;
+ }
+ cent->pe.railgunFlash = qtrue;
+ ci = &cgs.clientinfo[ cent->currentState.clientNum ];
+ CG_RailTrail( ci, origin, cent->pe.railgunImpact );
+}
+
+
+/*
+======================
+CG_MachinegunSpinAngle
+======================
+*/
+#define SPIN_SPEED 0.9
+#define COAST_TIME 1000
+static float CG_MachinegunSpinAngle( centity_t *cent ) {
+ int delta;
+ float angle;
+ float speed;
+
+ delta = cg.time - cent->pe.barrelTime;
+ if ( cent->pe.barrelSpinning ) {
+ angle = cent->pe.barrelAngle + delta * SPIN_SPEED;
+ } else {
+ if ( delta > COAST_TIME ) {
+ delta = COAST_TIME;
+ }
+
+ speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
+ angle = cent->pe.barrelAngle + delta * speed;
+ }
+
+ if ( cent->pe.barrelSpinning == !(cent->currentState.eFlags & EF_FIRING) ) {
+ cent->pe.barrelTime = cg.time;
+ cent->pe.barrelAngle = AngleMod( angle );
+ cent->pe.barrelSpinning = !!(cent->currentState.eFlags & EF_FIRING);
+//#ifdef MISSIONPACK
+ if ( cent->currentState.weapon == WP_CHAINGUN && !cent->pe.barrelSpinning ) {
+ trap_S_StartSound( NULL, cent->currentState.number, CHAN_WEAPON, trap_S_RegisterSound( "sound/weapons/vulcan/wvulwind.wav", qfalse ) );
+ }
+//#endif
+ }
+
+ return angle;
+}
+
+
+/*
+========================
+CG_AddWeaponWithPowerups
+========================
+*/
+static void CG_AddWeaponWithPowerups( refEntity_t *gun, int powerups ) {
+ // add powerup effects
+ if ( powerups & ( 1 << PW_INVIS ) ) {
+ if( (cgs.dmflags & DF_INVIS) == 0) {
+ gun->customShader = cgs.media.invisShader;
+ trap_R_AddRefEntityToScene( gun );
+ }
+ } else {
+ trap_R_AddRefEntityToScene( gun );
+
+ if ( powerups & ( 1 << PW_BATTLESUIT ) ) {
+ gun->customShader = cgs.media.battleWeaponShader;
+ trap_R_AddRefEntityToScene( gun );
+ }
+ if ( powerups & ( 1 << PW_QUAD ) ) {
+ gun->customShader = cgs.media.quadWeaponShader;
+ trap_R_AddRefEntityToScene( gun );
+ }
+ }
+}
+
+
+/*
+=============
+CG_AddPlayerWeapon
+
+Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL)
+The main player will have this called for BOTH cases, so effects like light and
+sound should only be done on the world model case.
+=============
+*/
+void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team ) {
+ refEntity_t gun;
+ refEntity_t barrel;
+ refEntity_t flash;
+ vec3_t angles;
+ weapon_t weaponNum;
+ weaponInfo_t *weapon;
+ centity_t *nonPredictedCent;
+ orientation_t lerped;
+
+ weaponNum = cent->currentState.weapon;
+
+ CG_RegisterWeapon( weaponNum );
+ weapon = &cg_weapons[weaponNum];
+
+ // add the weapon
+ memset( &gun, 0, sizeof( gun ) );
+ VectorCopy( parent->lightingOrigin, gun.lightingOrigin );
+ gun.shadowPlane = parent->shadowPlane;
+ gun.renderfx = parent->renderfx;
+
+ // set custom shading for railgun refire rate
+ if ( ps || cent->currentState.clientNum == cg.predictedPlayerState.clientNum ) {
+ if ( cg.predictedPlayerState.weapon == WP_RAILGUN
+ && cg.predictedPlayerState.weaponstate == WEAPON_FIRING ) {
+ float f;
+
+ f = (float)cg.predictedPlayerState.weaponTime / 1500;
+ gun.shaderRGBA[1] = 0;
+ gun.shaderRGBA[0] =
+ gun.shaderRGBA[2] = 255 * ( 1.0 - f );
+ } else {
+ gun.shaderRGBA[0] = 255;
+ gun.shaderRGBA[1] = 255;
+ gun.shaderRGBA[2] = 255;
+ gun.shaderRGBA[3] = 255;
+ }
+ }
+
+ gun.hModel = weapon->weaponModel;
+ if (!gun.hModel) {
+ return;
+ }
+
+ if ( !ps ) {
+ // add weapon ready sound
+ cent->pe.lightningFiring = qfalse;
+ if ( ( cent->currentState.eFlags & EF_FIRING ) && weapon->firingSound ) {
+ // lightning gun and guantlet make a different sound when fire is held down
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound );
+ cent->pe.lightningFiring = qtrue;
+ } else if ( weapon->readySound ) {
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound );
+ }
+ }
+
+ trap_R_LerpTag(&lerped, parent->hModel, parent->oldframe, parent->frame,
+ 1.0 - parent->backlerp, "tag_weapon");
+ VectorCopy(parent->origin, gun.origin);
+
+ VectorMA(gun.origin, lerped.origin[0], parent->axis[0], gun.origin);
+
+ // Make weapon appear left-handed for 2 and centered for 3
+ if(ps && cg_drawGun.integer == 2)
+ VectorMA(gun.origin, -lerped.origin[1], parent->axis[1], gun.origin);
+ else if(!ps || cg_drawGun.integer != 3)
+ VectorMA(gun.origin, lerped.origin[1], parent->axis[1], gun.origin);
+
+ VectorMA(gun.origin, lerped.origin[2], parent->axis[2], gun.origin);
+
+ MatrixMultiply(lerped.axis, ((refEntity_t *)parent)->axis, gun.axis);
+ gun.backlerp = parent->backlerp;
+
+ CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups );
+
+ // add the spinning barrel
+ if ( weapon->barrelModel ) {
+ memset( &barrel, 0, sizeof( barrel ) );
+ VectorCopy( parent->lightingOrigin, barrel.lightingOrigin );
+ barrel.shadowPlane = parent->shadowPlane;
+ barrel.renderfx = parent->renderfx;
+
+ barrel.hModel = weapon->barrelModel;
+ angles[YAW] = 0;
+ angles[PITCH] = 0;
+ angles[ROLL] = CG_MachinegunSpinAngle( cent );
+ AnglesToAxis( angles, barrel.axis );
+
+ CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" );
+
+ CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups );
+ }
+
+ // make sure we aren't looking at cg.predictedPlayerEntity for LG
+ nonPredictedCent = &cg_entities[cent->currentState.clientNum];
+
+ // if the index of the nonPredictedCent is not the same as the clientNum
+ // then this is a fake player (like on teh single player podiums), so
+ // go ahead and use the cent
+ if( ( nonPredictedCent - cg_entities ) != cent->currentState.clientNum ) {
+ nonPredictedCent = cent;
+ }
+
+ // add the flash
+ if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK )
+ && ( nonPredictedCent->currentState.eFlags & EF_FIRING ) )
+ {
+ // continuous flash
+ } else {
+ // impulse flash
+ if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash ) {
+ return;
+ }
+ }
+
+ memset( &flash, 0, sizeof( flash ) );
+ VectorCopy( parent->lightingOrigin, flash.lightingOrigin );
+ flash.shadowPlane = parent->shadowPlane;
+ flash.renderfx = parent->renderfx;
+
+ flash.hModel = weapon->flashModel;
+ if (!flash.hModel) {
+ return;
+ }
+ angles[YAW] = 0;
+ angles[PITCH] = 0;
+ angles[ROLL] = crandom() * 10;
+ AnglesToAxis( angles, flash.axis );
+
+ // colorize the railgun blast
+ if ( weaponNum == WP_RAILGUN ) {
+ clientInfo_t *ci;
+
+ ci = &cgs.clientinfo[ cent->currentState.clientNum ];
+ flash.shaderRGBA[0] = 255 * ci->color1[0];
+ flash.shaderRGBA[1] = 255 * ci->color1[1];
+ flash.shaderRGBA[2] = 255 * ci->color1[2];
+ }
+
+ CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash");
+ trap_R_AddRefEntityToScene( &flash );
+
+ if ( ps || cg.renderingThirdPerson ||
+ cent->currentState.number != cg.predictedPlayerState.clientNum ) {
+ // add lightning bolt
+ CG_LightningBolt( nonPredictedCent, flash.origin );
+
+ // add rail trail
+ CG_SpawnRailTrail( cent, flash.origin );
+
+ if ( weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2] ) {
+ trap_R_AddLightToScene( flash.origin, 300 + (rand()&31), weapon->flashDlightColor[0],
+ weapon->flashDlightColor[1], weapon->flashDlightColor[2] );
+ }
+ }
+}
+
+/*
+==============
+CG_AddViewWeapon
+
+Add the weapon, and flash for the player's view
+==============
+*/
+void CG_AddViewWeapon( playerState_t *ps ) {
+ refEntity_t hand;
+ centity_t *cent;
+ clientInfo_t *ci;
+ float fovOffset;
+ vec3_t angles;
+ weaponInfo_t *weapon;
+
+ if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
+ return;
+ }
+
+ if ( ps->pm_type == PM_INTERMISSION ) {
+ return;
+ }
+
+ // no gun if in third person view or a camera is active
+ //if ( cg.renderingThirdPerson || cg.cameraMode) {
+ if ( cg.renderingThirdPerson ) {
+ return;
+ }
+
+
+ // allow the gun to be completely removed
+ if ( !cg_drawGun.integer ) {
+ vec3_t origin;
+
+ if ( cg.predictedPlayerState.eFlags & EF_FIRING ) {
+ // special hack for lightning gun...
+ VectorCopy( cg.refdef.vieworg, origin );
+ VectorMA( origin, -8, cg.refdef.viewaxis[2], origin );
+ CG_LightningBolt( &cg_entities[ps->clientNum], origin );
+ }
+ return;
+ }
+
+ // don't draw if testing a gun model
+ if ( cg.testGun ) {
+ return;
+ }
+
+ // drop gun lower at higher fov
+ if ( cg_fov.integer > 90 ) {
+ fovOffset = -0.2 * ( cg_fov.integer - 90 );
+ } else {
+ fovOffset = 0;
+ }
+
+ cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum];
+ CG_RegisterWeapon( ps->weapon );
+ weapon = &cg_weapons[ ps->weapon ];
+
+ memset (&hand, 0, sizeof(hand));
+
+ // set up gun position
+ CG_CalculateWeaponPosition( hand.origin, angles );
+
+ VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin );
+ VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin );
+ VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin );
+
+ AnglesToAxis( angles, hand.axis );
+
+ // map torso animations to weapon animations
+ if ( cg_gun_frame.integer ) {
+ // development tool
+ hand.frame = hand.oldframe = cg_gun_frame.integer;
+ hand.backlerp = 0;
+ } else {
+ // get clientinfo for animation map
+ ci = &cgs.clientinfo[ cent->currentState.clientNum ];
+ hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame );
+ hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame );
+ hand.backlerp = cent->pe.torso.backlerp;
+ }
+
+ hand.hModel = weapon->handsModel;
+ hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT;
+
+ // add everything onto the hand
+ CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->persistant[PERS_TEAM] );
+}
+
+/*
+==============================================================================
+
+WEAPON SELECTION
+
+==============================================================================
+*/
+
+/*
+===================
+CG_DrawWeaponSelect
+===================
+*/
+void CG_DrawWeaponSelect( void ) {
+ int i;
+ int bits;
+ int count;
+ float *color;
+ vec4_t realColor;
+
+
+
+ // don't display if dead
+ if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
+ return;
+ }
+
+ color = CG_FadeColor( cg.weaponSelectTime, WEAPON_SELECT_TIME );
+
+ //Elimination: Always show weapon bar
+ if(cg_alwaysWeaponBar.integer) {
+ realColor[0] = 1.0;
+ realColor[1] = 1.0;
+ realColor[2] = 1.0;
+ realColor[3] = 1.0;
+ color = realColor;
+ }
+
+ if ( !color ) {
+ return;
+ }
+ trap_R_SetColor( color );
+
+ // showing weapon select clears pickup item display, but not the blend blob
+ cg.itemPickupTime = 0;
+
+ // count the number of weapons owned
+ bits = cg.snap->ps.stats[ STAT_WEAPONS ];
+ count = 0;
+ for ( i = 1 ; i < MAX_WEAPONS ; i++ ) {
+ if ( bits & ( 1 << i ) ) {
+ count++;
+ }
+ }
+
+ switch(cg_weaponBarStyle.integer){
+ case 0:
+ CG_DrawWeaponBar0(count,bits);
+ break;
+ case 1:
+ CG_DrawWeaponBar1(count,bits);
+ break;
+ case 2:
+ CG_DrawWeaponBar2(count,bits, color);
+ break;
+ case 3:
+ CG_DrawWeaponBar3(count,bits, color);
+ break;
+ case 4:
+ CG_DrawWeaponBar4(count,bits, color);
+ break;
+ case 5:
+ CG_DrawWeaponBar5(count,bits, color);
+ break;
+ case 6:
+ CG_DrawWeaponBar6(count,bits, color);
+ break;
+ case 7:
+ CG_DrawWeaponBar7(count,bits, color);
+ break;
+ }
+ trap_R_SetColor(NULL);
+ return;
+}
+
+/*
+===============
+CG_DrawWeaponBar0
+===============
+*/
+
+void CG_DrawWeaponBar0(int count, int bits){
+
+ int y = 380;
+ int x = 320 - count * 20;
+ int i;
+
+ for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
+ //Sago: Do mad change of grapple placement:
+ if(i==10)
+ continue;
+ if(i==0)
+ i=10;
+ if ( !( bits & ( 1 << i ) ) ) {
+ if(i==10)
+ i=0;
+ continue;
+ }
+
+ CG_RegisterWeapon( i );
+ // draw weapon icon
+ CG_DrawPic( x, y, 32, 32, cg_weapons[i].weaponIcon );
+
+ // draw selection marker
+ if ( i == cg.weaponSelect ) {
+ CG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader );
+ }
+
+ // no ammo cross on top
+ if ( !cg.snap->ps.ammo[ i ] ) {
+ CG_DrawPic( x, y, 32, 32, cgs.media.noammoShader );
+ }
+
+ x += 40;
+ //Sago: Undo mad change of weapons
+ if(i==10)
+ i=0;
+ }
+}
+
+/*
+===============
+CG_DrawWeaponBar1
+===============
+*/
+
+void CG_DrawWeaponBar1(int count, int bits){
+
+ int y = 380;
+ int x = 320 - count * 20;
+ int i;
+ int ammo;
+ int br;
+ int max;
+ float red[4];
+ float yellow[4];
+ float green[4];
+
+ red[0] = 1.0f;
+ red[1] = 0;
+ red[2] = 0;
+ red[3] = 1.0f;
+
+ yellow[0] = 1.0f;
+ yellow[1] = 0.6f;
+ yellow[2] = 0;
+ yellow[3] = 1.0f;
+
+ green[0] = 0;
+ green[1] = 1.0f;
+ green[2] = 0;
+ green[3] = 1.0f;
+
+ for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
+ //Sago: Do mad change of grapple placement:
+ if(i==10)
+ continue;
+ if(i==0)
+ i=10;
+ if ( !( bits & ( 1 << i ) ) ) {
+ if(i==10)
+ i=0;
+ continue;
+ }
+
+ ammo=cg.snap->ps.ammo[i];
+
+ switch(i) {
+ case WP_MACHINEGUN: max = 100; break;
+ case WP_SHOTGUN: max = 10; break;
+ case WP_GRENADE_LAUNCHER: max = 10; break;
+ case WP_ROCKET_LAUNCHER: max = 10; break;
+ case WP_LIGHTNING: max = 100; break;
+ case WP_RAILGUN: max = 10; break;
+ case WP_PLASMAGUN: max = 50; break;
+ case WP_BFG: max = 10; break;
+ case WP_NAILGUN: max = 10; break;
+ case WP_PROX_LAUNCHER: max = 5; break;
+ case WP_CHAINGUN: max = 100; break;
+ default: max = 1; break;
+ }
+
+ ammo = (ammo*100)/max;
+ if(ammo >=100)
+ ammo=100;
+
+ br=ammo*32/100;
+
+ if(i!=WP_GAUNTLET && i!=WP_GRAPPLING_HOOK){
+ if(ammo <= 20)
+ CG_FillRect( x, y+38, br,4, red);
+ if(ammo > 20 && ammo <= 50)
+ CG_FillRect( x, y+38, br, 4, yellow);
+ if(ammo > 50)
+ CG_FillRect( x, y+38, br, 4, green);
+ }
+
+ CG_RegisterWeapon( i );
+ // draw weapon icon
+ CG_DrawPic( x, y, 32, 32, cg_weapons[i].weaponIcon );
+
+ // draw selection marker
+ if ( i == cg.weaponSelect ) {
+ CG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader );
+ }
+
+ // no ammo cross on top
+ if ( !cg.snap->ps.ammo[ i ] ) {
+ CG_DrawPic( x, y, 32, 32, cgs.media.noammoShader );
+ }
+
+ x += 40;
+ //Sago: Undo mad change of weapons
+ if(i==10)
+ i=0;
+ }
+}
+
+/*
+===============
+CG_DrawWeaponBar2
+===============
+*/
+
+void CG_DrawWeaponBar2(int count, int bits, float *color){
+
+ int y = 200 + count * 12;
+ int x = 0;
+ int i;
+ int w;
+ char *s;
+ float red[4];
+ float yellow[4];
+ float blue[4];
+
+ red[0] = 1.0f;
+ red[1] = 0;
+ red[2] = 0;
+ red[3] = 0.4f;
+
+ yellow[0] = 1.0f;
+ yellow[1] = 1.0f;
+ yellow[2] = 0;
+ yellow[3] = 1.0f;
+
+ blue[0] = 0;
+ blue[1] = 0;
+ blue[2] = 1.0f;
+ blue[3] = 0.4f;
+
+ for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
+ //Sago: Do mad change of grapple placement:
+ if(i==10)
+ continue;
+ if(i==0)
+ i=10;
+ if ( !( bits & ( 1 << i ) ) ) {
+ if(i==10)
+ i=0;
+ continue;
+ }
+
+ if(cg.snap->ps.ammo[i]){
+ if ( i == cg.weaponSelect) {
+ CG_FillRect( x, y, 50, 24, blue );
+ CG_DrawRect( x, y, 50, 24, 2, yellow);
+ }
+ else{
+ CG_FillRect( x, y,50, 24, blue );
+ }
+ }
+ else{
+ if ( i == cg.weaponSelect) {
+ CG_FillRect( x, y, 50, 24, red );
+ CG_DrawRect( x, y, 50, 24, 2, yellow);
+ }
+ else{
+ CG_FillRect( x, y,50, 24, red );
+ }
+ }
+
+ CG_RegisterWeapon( i );
+ // draw weapon icon
+ CG_DrawPic( x+2, y+4, 16, 16, cg_weapons[i].weaponIcon );
+
+ /** Draw Weapon Ammo **/
+ if(cg.snap->ps.ammo[ i ]!=-1){
+ s = va("%i", cg.snap->ps.ammo[ i ] );
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallStringColor(x - w/2 + 32, y+4, s, color);
+ }
+
+ y -= 24;
+ //Sago: Undo mad change of weapons
+ if(i==10)
+ i=0;
+ }
+}
+
+/*
+===============
+CG_DrawWeaponBar3
+===============
+*/
+
+void CG_DrawWeaponBar3(int count, int bits, float *color){
+
+ int y = 200 + count * 12;
+ int x = 0;
+ int i;
+ int ammo;
+ int max;
+ int br;
+ int w;
+ char *s;
+ float red[4];
+ float yellow[4];
+ float green[4];
+ float blue[4];
+
+ red[0] = 1.0f;
+ red[1] = 0;
+ red[2] = 0;
+ red[3] = 0.4f;
+
+ yellow[0] = 1.0f;
+ yellow[1] = 1.0f;
+ yellow[2] = 0;
+ yellow[3] = 1.0f;
+
+ green[0] = 0;
+ green[1] = 1.0f;
+ green[2] = 0;
+ green[3] = 1.0f;
+
+ blue[0] = 0;
+ blue[1] = 0;
+ blue[2] = 1.0f;
+ blue[3] = 0.4f;
+
+ for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
+ //Sago: Do mad change of grapple placement:
+ if(i==10)
+ continue;
+ if(i==0)
+ i=10;
+ if ( !( bits & ( 1 << i ) ) ) {
+ if(i==10)
+ i=0;
+ continue;
+ }
+
+ ammo=cg.snap->ps.ammo[i];
+
+ switch(i) {
+ case WP_MACHINEGUN: max = 100; break;
+ case WP_SHOTGUN: max = 10; break;
+ case WP_GRENADE_LAUNCHER: max = 10; break;
+ case WP_ROCKET_LAUNCHER: max = 10; break;
+ case WP_LIGHTNING: max = 100; break;
+ case WP_RAILGUN: max = 10; break;
+ case WP_PLASMAGUN: max = 50; break;
+ case WP_BFG: max = 10; break;
+ case WP_NAILGUN: max = 10; break;
+ case WP_PROX_LAUNCHER: max = 5; break;
+ case WP_CHAINGUN: max = 100; break;
+ default: max = 1; break;
+ }
+
+ ammo = (ammo*100)/max;
+ if(ammo >=100)
+ ammo=100;
+
+ br=ammo*20/100;
+
+ if(i!=WP_GAUNTLET && i!=WP_GRAPPLING_HOOK){
+ if(ammo <= 20)
+ CG_FillRect( 51, y+2+20-br, 4,br, red);
+ if(ammo > 20 && ammo <= 50)
+ CG_FillRect( 51, y+2+20-br, 4,br, yellow);
+ if(ammo > 50)
+ CG_FillRect( 51, y+2+20-br, 4,br, green);
+ }
+
+ if(cg.snap->ps.ammo[i]){
+ if ( i == cg.weaponSelect) {
+ CG_FillRect( x, y, 50, 24, blue );
+ CG_DrawRect( x, y, 50, 24, 2, yellow);
+ }
+ else{
+ CG_FillRect( x, y,50, 24, blue );
+ }
+ }
+ else{
+ if ( i == cg.weaponSelect) {
+ CG_FillRect( x, y, 50, 24, red );
+ CG_DrawRect( x, y, 50, 24, 2, yellow);
+ }
+ else{
+ CG_FillRect( x, y,50, 24, red );
+ }
+ }
+ CG_RegisterWeapon( i );
+ // draw weapon icon
+ CG_DrawPic( x+2, y+4, 16, 16, cg_weapons[i].weaponIcon );
+
+ /** Draw Weapon Ammo **/
+ if(cg.snap->ps.ammo[ i ]!=-1){
+ s = va("%i", cg.snap->ps.ammo[ i ] );
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallStringColor(x - w/2 + 32, y+4, s, color);
+ }
+
+ y -= 24;
+ //Sago: Undo mad change of weapons
+ if(i==10)
+ i=0;
+ }
+}
+
+/*
+===============
+CG_DrawWeaponBar4
+===============
+*/
+
+void CG_DrawWeaponBar4(int count, int bits, float *color){
+
+ int y = 200 + count * 12;
+ int x = 0;
+ int i;
+ float ammo;
+ int max;
+ int w;
+ char *s;
+ float boxColor[4];
+ float yellow[4];
+
+ boxColor[1]=0;
+ boxColor[3]=0.4f;
+
+ yellow[0] = 1.0f;
+ yellow[1] = 1.0f;
+ yellow[2] = 0;
+ yellow[3] = 1.0f;
+
+ for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
+ //Sago: Do mad change of grapple placement:
+ if(i==10)
+ continue;
+ if(i==0)
+ i=10;
+ if ( !( bits & ( 1 << i ) ) ) {
+ if(i==10)
+ i=0;
+ continue;
+ }
+
+ ammo=cg.snap->ps.ammo[i];
+
+ switch(i) {
+ case WP_MACHINEGUN: max = 100; break;
+ case WP_SHOTGUN: max = 10; break;
+ case WP_GRENADE_LAUNCHER: max = 10; break;
+ case WP_ROCKET_LAUNCHER: max = 10; break;
+ case WP_LIGHTNING: max = 100; break;
+ case WP_RAILGUN: max = 10; break;
+ case WP_PLASMAGUN: max = 50; break;
+ case WP_BFG: max = 10; break;
+ case WP_NAILGUN: max = 10; break;
+ case WP_PROX_LAUNCHER: max = 5; break;
+ case WP_CHAINGUN: max = 100; break;
+ default: max = 1; break;
+ }
+
+ ammo = (ammo*100)/max;
+
+ if((ammo >=100) || (ammo < 0))
+ ammo=100;
+
+ boxColor[2]=(ammo/100.0f)*1.0f;
+ boxColor[0]=1.0f-(ammo/100.0f)*1.0f;
+
+ if ( i == cg.weaponSelect) {
+ CG_FillRect( x, y, 50, 24, boxColor );
+ CG_DrawRect( x, y, 50, 24, 2, yellow);
+ }
+ else{
+ CG_FillRect( x, y,50, 24, boxColor );
+ }
+ CG_RegisterWeapon( i );
+ // draw weapon icon
+ CG_DrawPic( x+2, y+4, 16, 16, cg_weapons[i].weaponIcon );
+
+ /** Draw Weapon Ammo **/
+ if(cg.snap->ps.ammo[ i ]!=-1){
+ s = va("%i", cg.snap->ps.ammo[ i ] );
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallStringColor(x - w/2 + 32, y+4, s, color);
+ }
+
+ y -= 24;
+ //Sago: Undo mad change of weapons
+ if(i==10)
+ i=0;
+ }
+}
+
+/*
+===============
+CG_DrawWeaponBar5
+===============
+*/
+
+void CG_DrawWeaponBar5(int count, int bits, float *color){
+
+ int y = 380;
+ int x = 320 - count * 15;
+ int i;
+ int w;
+ char *s;
+ float red[4];
+ float yellow[4];
+ float blue[4];
+
+ red[0] = 1.0f;
+ red[1] = 0;
+ red[2] = 0;
+ red[3] = 0.4f;
+
+ yellow[0] = 1.0f;
+ yellow[1] = 1.0f;
+ yellow[2] = 0;
+ yellow[3] = 1.0f;
+
+ blue[0] = 0;
+ blue[1] = 0;
+ blue[2] = 1.0f;
+ blue[3] = 0.4f;
+
+ for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
+ //Sago: Do mad change of grapple placement:
+ if(i==10)
+ continue;
+ if(i==0)
+ i=10;
+ if ( !( bits & ( 1 << i ) ) ) {
+ if(i==10)
+ i=0;
+ continue;
+ }
+
+ if(cg.snap->ps.ammo[i]){
+ if ( i == cg.weaponSelect) {
+ CG_FillRect( x, y , 30 , 38, blue );
+ CG_DrawRect( x, y, 30 ,38 ,2, yellow);
+ }
+ else{
+ CG_FillRect( x, y,30, 38, blue );
+ }
+ }
+ else{
+ if ( i == cg.weaponSelect) {
+ CG_FillRect( x, y , 30 , 38, red );
+ CG_DrawRect( x , y, 30,38,2, yellow);
+ }
+ else{
+ CG_FillRect( x, y,30, 38, red );
+ }
+ }
+ CG_RegisterWeapon( i );
+ CG_DrawPic( x+7, y+2, 16, 16, cg_weapons[i].weaponIcon );
+
+ if(cg.snap->ps.ammo[ i ]!=-1){
+ s = va("%i", cg.snap->ps.ammo[ i ] );
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallStringColor(x - w/2 + 15, y+20, s, color);
+ }
+
+ x += 30;
+ //Sago: Undo mad change of weapons
+ if(i==10)
+ i=0;
+ }
+}
+
+/*
+===============
+CG_DrawWeaponBar6
+===============
+*/
+
+void CG_DrawWeaponBar6(int count, int bits, float *color){
+
+ int y = 380;
+ int x = 320 - count * 15;
+ int i;
+ int ammo;
+ int max;
+ int br;
+ int w;
+ char *s;
+ float red[4];
+ float yellow[4];
+ float green[4];
+ float blue[4];
+
+ red[0] = 1.0f;
+ red[1] = 0;
+ red[2] = 0;
+ red[3] = 0.4f;
+
+ yellow[0] = 1.0f;
+ yellow[1] = 1.0f;
+ yellow[2] = 0;
+ yellow[3] = 1.0f;
+
+ green[0] = 0;
+ green[1] = 1.0f;
+ green[2] = 0;
+ green[3] = 1.0f;
+
+ blue[0] = 0;
+ blue[1] = 0;
+ blue[2] = 1.0f;
+ blue[3] = 0.4f;
+
+ for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
+ //Sago: Do mad change of grapple placement:
+ if(i==10)
+ continue;
+ if(i==0)
+ i=10;
+ if ( !( bits & ( 1 << i ) ) ) {
+ if(i==10)
+ i=0;
+ continue;
+ }
+
+ ammo=cg.snap->ps.ammo[i];
+
+ switch(i) {
+ case WP_MACHINEGUN: max = 100; break;
+ case WP_SHOTGUN: max = 10; break;
+ case WP_GRENADE_LAUNCHER: max = 10; break;
+ case WP_ROCKET_LAUNCHER: max = 10; break;
+ case WP_LIGHTNING: max = 100; break;
+ case WP_RAILGUN: max = 10; break;
+ case WP_PLASMAGUN: max = 50; break;
+ case WP_BFG: max = 10; break;
+ case WP_NAILGUN: max = 10; break;
+ case WP_PROX_LAUNCHER: max = 5; break;
+ case WP_CHAINGUN: max = 100; break;
+ default: max = 1; break;
+ }
+
+ ammo = (ammo*100)/max;
+
+ if(ammo >=100)
+ ammo=100;
+
+ br=ammo*26/100;
+
+ if(i!=WP_GAUNTLET && i!=WP_GRAPPLING_HOOK){
+ if(ammo <= 20)
+ CG_FillRect( x+2, y +40, br, 4, red);
+ if(ammo > 20 && ammo <= 50)
+ CG_FillRect( x+2, y+40, br, 4, yellow);
+ if(ammo > 50)
+ CG_FillRect( x+2, y+40, br, 4, green);
+ }
+
+ if(cg.snap->ps.ammo[i]){
+ if ( i == cg.weaponSelect) {
+ CG_FillRect( x, y , 30 , 38, blue );
+ CG_DrawRect( x, y, 30 ,38 ,2, yellow);
+ }
+ else{
+ CG_FillRect( x, y,30, 38, blue );
+ }
+ }
+ else{
+ if ( i == cg.weaponSelect) {
+ CG_FillRect( x, y , 30 , 38, red );
+ CG_DrawRect( x , y, 30,38,2, yellow);
+ }
+ else{
+ CG_FillRect( x, y,30, 38, red );
+ }
+ }
+ CG_RegisterWeapon( i );
+ CG_DrawPic( x+7, y+2, 16, 16, cg_weapons[i].weaponIcon );
+
+ if(cg.snap->ps.ammo[ i ]!=-1){
+ s = va("%i", cg.snap->ps.ammo[ i ] );
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallStringColor(x - w/2 + 15, y+20, s, color);
+ }
+
+ x += 30;
+ //Sago: Undo mad change of weapons
+ if(i==10)
+ i=0;
+ }
+}
+
+/*
+===============
+CG_DrawWeaponBar7
+===============
+*/
+
+void CG_DrawWeaponBar7(int count, int bits, float *color){
+
+ int y = 380;
+ int x = 320 - count * 15;
+ int i;
+ float ammo;
+ float max;
+ int w;
+ char *s;
+ float yellow[4];
+ float boxColor[4];
+
+ boxColor[1]=0;
+ boxColor[3]=0.4f;
+
+ yellow[0] = 1.0f;
+ yellow[1] = 1.0f;
+ yellow[2] = 0;
+ yellow[3] = 1.0f;
+
+ for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
+ //Sago: Do mad change of grapple placement:
+ if(i==10)
+ continue;
+ if(i==0)
+ i=10;
+ if ( !( bits & ( 1 << i ) ) ) {
+ if(i==10)
+ i=0;
+ continue;
+ }
+
+ ammo=cg.snap->ps.ammo[i];
+
+ switch(i) {
+ case WP_MACHINEGUN: max = 100; break;
+ case WP_SHOTGUN: max = 10; break;
+ case WP_GRENADE_LAUNCHER: max = 10; break;
+ case WP_ROCKET_LAUNCHER: max = 10; break;
+ case WP_LIGHTNING: max = 100; break;
+ case WP_RAILGUN: max = 10; break;
+ case WP_PLASMAGUN: max = 50; break;
+ case WP_BFG: max = 10; break;
+ case WP_NAILGUN: max = 10; break;
+ case WP_PROX_LAUNCHER: max = 5; break;
+ case WP_CHAINGUN: max = 100; break;
+ default: max = 1; break;
+ }
+
+ ammo = (ammo*100)/max;
+
+ if((ammo >=100) || (ammo < 0))
+ ammo=100;
+
+ boxColor[2]=(ammo/100.0f)*1.0f;
+ boxColor[0]=1.0f-(ammo/100.0f)*1.0f;
+
+ if ( i == cg.weaponSelect) {
+ CG_FillRect( x, y , 30 , 38, boxColor );
+ CG_DrawRect( x, y, 30 ,38 ,2, yellow);
+ }
+ else{
+ CG_FillRect( x, y,30, 38, boxColor );
+ }
+ CG_RegisterWeapon( i );
+ CG_DrawPic( x+7, y+2, 16, 16, cg_weapons[i].weaponIcon );
+
+ if(cg.snap->ps.ammo[ i ]!=-1){
+ s = va("%i", cg.snap->ps.ammo[ i ] );
+ w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
+ CG_DrawSmallStringColor(x - w/2 + 15, y+20, s, color);
+ }
+
+ x += 30;
+ //Sago: Undo mad change of weapons
+ if(i==10)
+ i=0;
+ }
+}
+
+
+/*
+===============
+CG_WeaponSelectable
+===============
+*/
+static qboolean CG_WeaponSelectable( int i ) {
+ if ( !cg.snap->ps.ammo[i] ) {
+ return qfalse;
+ }
+ if ( ! (cg.snap->ps.stats[ STAT_WEAPONS ] & ( 1 << i ) ) ) {
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+/*
+===============
+CG_NextWeapon_f
+===============
+*/
+void CG_NextWeapon_f( void ) {
+ int i;
+ int original;
+
+ if ( !cg.snap ) {
+ return;
+ }
+ if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
+ return;
+ }
+
+ cg.weaponSelectTime = cg.time;
+ original = cg.weaponSelect;
+ //Part of mad hook select code:
+ if(cg.weaponSelect == WP_GRAPPLING_HOOK)
+ cg.weaponSelect = 0;
+
+ for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
+ cg.weaponSelect++;
+ if ( cg.weaponSelect == MAX_WEAPONS ) {
+ cg.weaponSelect = 0;
+ }
+ if ( cg.weaponSelect == WP_GAUNTLET ) {
+ continue; // never cycle to gauntlet
+ }
+ //Sago: Mad change of grapple order
+ if( cg.weaponSelect == WP_GRAPPLING_HOOK) {
+ continue;
+ }
+ if( cg.weaponSelect == 0)
+ cg.weaponSelect = WP_GRAPPLING_HOOK;
+ if ( cg.weaponSelect == WP_GRAPPLING_HOOK && !cg_cyclegrapple.integer ) {
+ cg.weaponSelect = 0;
+ continue; // never cycle to grapple unless the client wants it
+ }
+ if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
+ break;
+ }
+ if( cg.weaponSelect == WP_GRAPPLING_HOOK)
+ cg.weaponSelect = 0;
+ }
+ if ( i == MAX_WEAPONS ) {
+ cg.weaponSelect = original;
+ }
+}
+
+/*
+===============
+CG_PrevWeapon_f
+===============
+*/
+void CG_PrevWeapon_f( void ) {
+ int i;
+ int original;
+
+ if ( !cg.snap ) {
+ return;
+ }
+ if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
+ return;
+ }
+
+ cg.weaponSelectTime = cg.time;
+ original = cg.weaponSelect;
+ //Part of mad hook select code:
+ if(cg.weaponSelect == WP_GRAPPLING_HOOK)
+ cg.weaponSelect = 0;
+
+ for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
+ cg.weaponSelect--;
+ if ( cg.weaponSelect == -1 ) {
+ cg.weaponSelect = MAX_WEAPONS - 1;
+ }
+ if ( cg.weaponSelect == WP_GAUNTLET ) {
+ continue; // never cycle to gauntlet
+ }
+ //Sago: Mad change of grapple order
+ if( cg.weaponSelect == WP_GRAPPLING_HOOK) {
+ continue;
+ }
+ if( cg.weaponSelect == 0)
+ cg.weaponSelect = WP_GRAPPLING_HOOK;
+ if ( cg.weaponSelect == WP_GRAPPLING_HOOK && !cg_cyclegrapple.integer ) {
+ cg.weaponSelect = 0;
+ continue; // never cycle to grapple unless the client wants it
+ }
+ if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
+ break;
+ }
+ if( cg.weaponSelect == WP_GRAPPLING_HOOK)
+ cg.weaponSelect = 0;
+ }
+ if ( i == MAX_WEAPONS ) {
+ cg.weaponSelect = original;
+ }
+}
+
+/*
+===============
+CG_Weapon_f
+===============
+*/
+void CG_Weapon_f( void ) {
+ int num;
+
+ if ( !cg.snap ) {
+ return;
+ }
+ if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
+ return;
+ }
+
+ num = atoi( CG_Argv( 1 ) );
+
+ if ( num < 1 || num > MAX_WEAPONS-1 ) {
+ return;
+ }
+
+ cg.weaponSelectTime = cg.time;
+
+ if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) ) {
+ return; // don't have the weapon
+ }
+
+ cg.weaponSelect = num;
+}
+
+/*
+===================
+CG_OutOfAmmoChange
+
+The current weapon has just run out of ammo
+===================
+*/
+void CG_OutOfAmmoChange( void ) {
+ int i;
+
+ cg.weaponSelectTime = cg.time;
+
+ for ( i = MAX_WEAPONS-1 ; i > 0 ; i-- ) {
+ if ( CG_WeaponSelectable( i ) && i != WP_GRAPPLING_HOOK ) {
+ cg.weaponSelect = i;
+ break;
+ }
+ }
+}
+
+
+
+/*
+===================================================================================================
+
+WEAPON EVENTS
+
+===================================================================================================
+*/
+
+/*
+================
+CG_FireWeapon
+
+Caused by an EV_FIRE_WEAPON event
+================
+*/
+void CG_FireWeapon( centity_t *cent ) {
+ entityState_t *ent;
+ int c;
+ weaponInfo_t *weap;
+
+ if((cgs.gametype == GT_ELIMINATION || cgs.gametype == GT_CTF_ELIMINATION) && cgs.roundStartTime>=cg.time)
+ return; //if we havn't started in ELIMINATION then do not fire
+
+ ent = ¢->currentState;
+ if ( ent->weapon == WP_NONE ) {
+ return;
+ }
+ if ( ent->weapon >= WP_NUM_WEAPONS ) {
+ CG_Error( "CG_FireWeapon: ent->weapon >= WP_NUM_WEAPONS" );
+ return;
+ }
+ weap = &cg_weapons[ ent->weapon ];
+
+ // mark the entity as muzzle flashing, so when it is added it will
+ // append the flash to the weapon model
+ cent->muzzleFlashTime = cg.time;
+
+ // lightning gun only does this this on initial press
+ if ( ent->weapon == WP_LIGHTNING ) {
+ if ( cent->pe.lightningFiring ) {
+ return;
+ }
+ }
+
+ // play quad sound if needed
+ if ( cent->currentState.powerups & ( 1 << PW_QUAD ) ) {
+ trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.media.quadSound );
+ }
+
+ // play a sound
+ for ( c = 0 ; c < 4 ; c++ ) {
+ if ( !weap->flashSound[c] ) {
+ break;
+ }
+ }
+ if ( c > 0 ) {
+ c = rand() % c;
+ if ( weap->flashSound[c] )
+ {
+ trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound[c] );
+ }
+ }
+
+ // do brass ejection
+ if ( weap->ejectBrassFunc && cg_brassTime.integer > 0 ) {
+ weap->ejectBrassFunc( cent );
+ }
+
+//unlagged - attack prediction #1
+ CG_PredictWeaponEffects( cent );
+//unlagged - attack prediction #1
+}
+
+
+/*
+==========================
+CG_Explosionia LEILEI
+==========================
+
+static void CG_Explosionia ( centity_t *cent ) {
+ localEntity_t *le;
+ ec3_t velocity, xvelocity;
+ vec3_t offset, xoffset;
+ float waterScale = 1.0f;
+ vec3_t v[3];
+
+ if ( cg_brassTime.integer <= 0 ) {
+ return;
+ }
+
+ le = CG_AllocLocalEntity();
+
+
+ velocity[0] = -50 + 100 * crandom();
+ velocity[1] = -50 + 100 * crandom();
+ velocity[2] = -50 + 100 * crandom();
+
+ le->leType = LE_FALL_SCALE_FADE;
+ le->startTime = cg.time;
+ le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random();
+
+ //le->pos.trType = TR_GRAVITY;
+ le->pos.trTime = cg.time - (rand()&15);
+
+ AnglesToAxis( cent->lerpAngles, v );
+
+ offset[0] = 8;
+ offset[1] = -4;
+ offset[2] = 24;
+
+ xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
+ xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
+ xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
+ VectorAdd( cent->lerpOrigin, xoffset, re->origin );
+
+ VectorCopy( re->origin, le->pos.trBase );
+
+ if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
+ waterScale = 0.10f;
+ }
+
+ xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
+ xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
+ xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
+ VectorScale( xvelocity, waterScale, le->pos.trDelta );
+
+ le->bounceFactor = 0.4 * waterScale;
+
+ le->angles.trType = TR_LINEAR;
+ le->angles.trTime = cg.time;
+ le->angles.trBase[0] = rand()&31;
+ le->angles.trBase[1] = rand()&31;
+ le->angles.trBase[2] = rand()&31;
+ le->angles.trDelta[0] = 2;
+ le->angles.trDelta[1] = 1;
+ le->angles.trDelta[2] = 0;
+ le = CG_SmokePuff( le->origin, le->velocity,
+ 30, // radius
+ 1, 1, 1, 1, // color
+ 2000, // trailTime
+ cg.time, // startTime
+ 0, // fadeInTime
+ 0, // flags
+ cgs.media.lbumShader1 );
+ le->leFlags = LEF_TUMBLE;
+ le->leBounceSoundType = LEBS_NONE;
+ le->leMarkType = LEMT_NONE;
+}
+
+*/
+
+/*
+=================
+CG_MissileHitWall
+
+Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing
+=================
+*/
+void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType ) {
+ qhandle_t mod;
+ qhandle_t mark;
+ qhandle_t shader;
+ sfxHandle_t sfx;
+ float radius;
+ float light;
+ vec3_t lightColor;
+ localEntity_t *le;
+ int r;
+ qboolean alphaFade;
+ qboolean isSprite;
+ int duration;
+ vec3_t sprOrg;
+ vec3_t sprVel;
+
+ mark = 0;
+ radius = 32;
+ sfx = 0;
+ mod = 0;
+ shader = 0;
+ light = 0;
+ lightColor[0] = 1;
+ lightColor[1] = 1;
+ lightColor[2] = 0;
+
+ // set defaults
+ isSprite = qfalse;
+ duration = 600;
+
+ switch ( weapon ) {
+ default:
+//#ifdef MISSIONPACK
+ case WP_NAILGUN:
+ if( soundType == IMPACTSOUND_FLESH ) {
+ sfx = cgs.media.sfx_nghitflesh;
+ } else if( soundType == IMPACTSOUND_METAL ) {
+ sfx = cgs.media.sfx_nghitmetal;
+ } else {
+ sfx = cgs.media.sfx_nghit;
+ }
+ mark = cgs.media.holeMarkShader;
+ radius = 12;
+ break;
+//#endif
+ case WP_LIGHTNING:
+ // no explosion at LG impact, it is added with the beam
+ r = rand() & 3;
+ if ( r < 2 ) {
+ sfx = cgs.media.sfx_lghit2;
+ } else if ( r == 2 ) {
+ sfx = cgs.media.sfx_lghit1;
+ } else {
+ sfx = cgs.media.sfx_lghit3;
+ }
+ mark = cgs.media.holeMarkShader;
+ radius = 12;
+ break;
+//#ifdef MISSIONPACK
+ case WP_PROX_LAUNCHER:
+ mod = cgs.media.dishFlashModel;
+ shader = cgs.media.grenadeExplosionShader;
+ sfx = cgs.media.sfx_proxexp;
+ mark = cgs.media.burnMarkShader;
+ radius = 64;
+ light = 300;
+ isSprite = qtrue;
+ // LEILEI START enhancement
+ if (cg_leiEnhancement.integer) {
+ // some more fireball, fireball, fireball, fire fire!
+ VectorMA( origin, 24, dir, sprOrg );
+ VectorScale( dir, 64, sprVel );
+ lightColor[0] = 0.7; // subtler explosion colors
+ lightColor[1] = 0.6;
+ lightColor[2] = 0.4;
+ VectorMA( origin, 4, dir, sprOrg );
+ VectorScale( dir, 2, sprVel );
+ VectorMA( origin, 4, dir, sprOrg );
+ VectorScale( dir, 42, sprVel );
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 700, 10, 108 );
+ VectorMA( origin, 4, dir, sprOrg );
+ VectorScale( dir, 82, sprVel );
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 400, 11, 158 );
+ VectorMA( origin, -5, dir, sprOrg );
+ VectorScale( dir, 182, sprVel );
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 600, 47, 88 );
+ VectorMA( origin, -5, dir, sprOrg );
+ VectorScale( dir, 64, sprVel );
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 110, 72, 28 );
+ mod = 0; // turns off the sprite (unfortunately, disables dlight)
+ }
+ // LEILEI END enhancement
+
+ break;
+//#endif
+ case WP_GRENADE_LAUNCHER:
+ mod = cgs.media.dishFlashModel;
+ shader = cgs.media.grenadeExplosionShader;
+ sfx = cgs.media.sfx_rockexp;
+ mark = cgs.media.burnMarkShader;
+ radius = 64;
+ light = 300;
+ isSprite = qtrue;
+ // LEILEI START enhancement
+ if (cg_leiEnhancement.integer) {
+ // some more fireball, fireball, fireball, fire fire!
+ VectorMA( origin, 24, dir, sprOrg );
+ VectorScale( dir, 64, sprVel );
+ lightColor[0] = 0.7; // subtler explosion colors
+ lightColor[1] = 0.6;
+ lightColor[2] = 0.4;
+ VectorMA( origin, 4, dir, sprOrg );
+ VectorScale( dir, 2, sprVel );
+ VectorMA( origin, 4, dir, sprOrg );
+ VectorScale( dir, 42, sprVel );
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 700, 10, 108 );
+ VectorMA( origin, 4, dir, sprOrg );
+ VectorScale( dir, 82, sprVel );
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 400, 11, 158 );
+ VectorMA( origin, -5, dir, sprOrg );
+ VectorScale( dir, 182, sprVel );
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 600, 47, 88 );
+ VectorMA( origin, -5, dir, sprOrg );
+ VectorScale( dir, 64, sprVel );
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 110, 72, 28 );
+ mod = 0; // turns off the sprite (unfortunately, disables dlight)
+ }
+ // LEILEI END enhancement
+ break;
+ case WP_ROCKET_LAUNCHER:
+ mod = cgs.media.dishFlashModel;
+ shader = cgs.media.rocketExplosionShader;
+ sfx = cgs.media.sfx_rockexp;
+ mark = cgs.media.burnMarkShader;
+ radius = 64;
+ light = 300;
+ isSprite = qtrue;
+ duration = 1000;
+ lightColor[0] = 1;
+ lightColor[1] = 0.75;
+ lightColor[2] = 0.0;
+ if (!cg_oldRocket.integer) {
+ // explosion sprite animation
+ VectorMA( origin, 24, dir, sprOrg );
+ VectorScale( dir, 64, sprVel );
+
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 1400, 20, 30 );
+ }
+ // LEILEI START enhancement
+ if (cg_leiEnhancement.integer) {
+ // some more fireball, fireball, fireball, fire fire!
+ VectorMA( origin, 24, dir, sprOrg );
+ VectorScale( dir, 64, sprVel );
+ lightColor[0] = 0.7; // subtler explosion colors
+ lightColor[1] = 0.6;
+ lightColor[2] = 0.4;
+ VectorMA( origin, 4, dir, sprOrg );
+ VectorScale( dir, 2, sprVel );
+ VectorMA( origin, 4, dir, sprOrg );
+ VectorScale( dir, 42, sprVel );
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 700, 10, 108 );
+ VectorMA( origin, 4, dir, sprOrg );
+ VectorScale( dir, 82, sprVel );
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 400, 11, 158 );
+ VectorMA( origin, -5, dir, sprOrg );
+ VectorScale( dir, 182, sprVel );
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 600, 47, 88 );
+ VectorMA( origin, -5, dir, sprOrg );
+ VectorScale( dir, 64, sprVel );
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 110, 72, 28 );
+ mod = 0; // turns off the sprite (unfortunately, disables dlight)
+ }
+ // LEILEI END enhancement
+ break;
+ case WP_RAILGUN:
+ mod = cgs.media.ringFlashModel;
+ shader = cgs.media.railExplosionShader;
+ sfx = cgs.media.sfx_plasmaexp;
+ mark = cgs.media.energyMarkShader;
+ radius = 24;
+ break;
+ case WP_PLASMAGUN:
+ mod = cgs.media.ringFlashModel;
+ shader = cgs.media.plasmaExplosionShader;
+ sfx = cgs.media.sfx_plasmaexp;
+ mark = cgs.media.energyMarkShader;
+ radius = 16;
+ break;
+ case WP_BFG:
+ mod = cgs.media.dishFlashModel;
+ shader = cgs.media.bfgExplosionShader;
+ sfx = cgs.media.sfx_rockexp;
+ mark = cgs.media.burnMarkShader;
+ radius = 32;
+ isSprite = qtrue;
+ break;
+ case WP_SHOTGUN:
+ mod = cgs.media.bulletFlashModel;
+ shader = cgs.media.bulletExplosionShader;
+ mark = cgs.media.bulletMarkShader;
+#if 0
+//Some problems here
+ if (cg_leiEnhancement.integer) {
+ if( soundType == IMPACTSOUND_FLESH ) {
+ mark = cgs.media.lbldShader2;
+ } else if( soundType == IMPACTSOUND_METAL ) {
+ r = rand() & 4; if ( r < 3 ) { mark = cgs.media.lmarkmetal1;
+ } else if ( r == 2 ) { mark = cgs.media.lmarkmetal2;
+ } else if ( r == 1 ) { mark = cgs.media.lmarkmetal3;
+ } else { mark = cgs.media.lmarkmetal4; }
+ } else {
+ r = rand() & 4; if ( r < 3 ) { mark = cgs.media.lmarkbullet1;
+ } else if ( r == 2 ) { mark = cgs.media.lmarkbullet2;
+ } else if ( r == 1 ) { mark = cgs.media.lmarkbullet3;
+ } else { mark = cgs.media.lmarkbullet4;
+ } }
+ }
+#endif
+ sfx = 0;
+ radius = 4;
+ break;
+
+//#ifdef MISSIONPACK
+ case WP_CHAINGUN:
+ mod = cgs.media.bulletFlashModel;
+ if( soundType == IMPACTSOUND_FLESH ) {
+ sfx = cgs.media.sfx_chghitflesh;
+ } else if( soundType == IMPACTSOUND_METAL ) {
+ sfx = cgs.media.sfx_chghitmetal;
+ } else {
+ sfx = cgs.media.sfx_chghit;
+ }
+
+ mark = cgs.media.bulletMarkShader;
+#if 0
+//Some problems here
+ if (cg_leiEnhancement.integer) {
+
+ if( soundType == IMPACTSOUND_FLESH ) {
+ mark = cgs.media.lbldShader2;
+ } else if( soundType == IMPACTSOUND_METAL ) {
+ r = rand() & 4; if ( r < 3 ) { mark = cgs.media.lmarkmetal1;
+ } else if ( r == 2 ) { mark = cgs.media.lmarkmetal2;
+ } else if ( r == 1 ) { mark = cgs.media.lmarkmetal3;
+ } else { mark = cgs.media.lmarkmetal4; }
+ } else {
+ r = rand() & 4; if ( r < 3 ) { mark = cgs.media.lmarkbullet1;
+ } else if ( r == 2 ) { mark = cgs.media.lmarkbullet2;
+ } else if ( r == 1 ) { mark = cgs.media.lmarkbullet3;
+ } else { mark = cgs.media.lmarkbullet4; }
+ }
+ }
+#endif
+ r = rand() & 3;
+ if ( r < 2 ) {
+ sfx = cgs.media.sfx_ric1;
+ } else if ( r == 2 ) {
+ sfx = cgs.media.sfx_ric2;
+ } else {
+ sfx = cgs.media.sfx_ric3;
+ }
+
+ radius = 8;
+ break;
+//#endif
+
+ case WP_MACHINEGUN:
+ mod = cgs.media.bulletFlashModel;
+ shader = cgs.media.bulletExplosionShader;
+ mark = cgs.media.bulletMarkShader;
+#if 0
+//Some problems here
+ if (cg_leiEnhancement.integer) {
+ if( soundType == IMPACTSOUND_FLESH ) {
+ mark = cgs.media.lbldShader2;
+ } else if( soundType == IMPACTSOUND_METAL ) {
+ r = rand() & 4; if ( r < 3 ) { mark = cgs.media.lmarkmetal1;
+ } else if ( r == 2 ) { mark = cgs.media.lmarkmetal2;
+ } else if ( r == 1 ) { mark = cgs.media.lmarkmetal3;
+ } else { mark = cgs.media.lmarkmetal4; }
+ } else {
+ r = rand() & 4; if ( r < 3 ) { mark = cgs.media.lmarkbullet1;
+ } else if ( r == 2 ) { mark = cgs.media.lmarkbullet2;
+ } else if ( r == 1 ) { mark = cgs.media.lmarkbullet3;
+ } else { mark = cgs.media.lmarkbullet4;
+ }
+ VectorMA( origin, 4, dir, sprOrg );
+ VectorScale( dir, 82, sprVel );
+
+ }
+ }
+#endif
+ r = rand() & 3;
+ if ( r == 0 ) {
+ sfx = cgs.media.sfx_ric1;
+ } else if ( r == 1 ) {
+ sfx = cgs.media.sfx_ric2;
+ } else {
+ sfx = cgs.media.sfx_ric3;
+ }
+
+ radius = 8;
+ break;
+ }
+
+ if ( sfx ) {
+ trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, sfx );
+ }
+
+ //
+ // create the explosion
+ //
+ if ( mod ) {
+ le = CG_MakeExplosion( origin, dir,
+ mod, shader,
+ duration, isSprite );
+ le->light = light;
+ VectorCopy( lightColor, le->lightColor );
+ if ( weapon == WP_RAILGUN ) {
+ // colorize with client color
+ VectorCopy( cgs.clientinfo[clientNum].color1, le->color );
+ le->refEntity.shaderRGBA[0] = le->color[0] * 0xff;
+ le->refEntity.shaderRGBA[1] = le->color[1] * 0xff;
+ le->refEntity.shaderRGBA[2] = le->color[2] * 0xff;
+ le->refEntity.shaderRGBA[3] = 0xff;
+ }
+ }
+
+ //
+ // impact mark
+ //
+ alphaFade = (mark == cgs.media.energyMarkShader); // plasma fades alpha, all others fade color
+ if ( weapon == WP_RAILGUN ) {
+ float *color;
+
+ // colorize with client color
+ color = cgs.clientinfo[clientNum].color1;
+ CG_ImpactMark( mark, origin, dir, random()*360, color[0],color[1], color[2],1, alphaFade, radius, qfalse );
+ } else {
+ CG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse );
+ }
+}
+
+
+/*
+=================
+CG_MissileHitPlayer
+=================
+*/
+void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum ) {
+// LEILEI ENHANCEMENT
+ if (cg_leiEnhancement.integer) {
+ CG_SmokePuff( origin, dir, 22, 1, 1, 1, 1.0f, 900, cg.time, 0, 0, cgs.media.lbldShader1 );
+ CG_SpurtBlood( origin, dir, 1);
+// CG_SpurtBlood( origin, dir, 4);
+// CG_SpurtBlood( origin, dir, -12);
+ }
+
+ else
+ CG_Bleed( origin, entityNum );
+
+ // some weapons will make an explosion with the blood, while
+ // others will just make the blood
+ switch ( weapon ) {
+ case WP_GRENADE_LAUNCHER:
+ case WP_ROCKET_LAUNCHER:
+//#ifdef MISSIONPACK
+ case WP_NAILGUN:
+ case WP_CHAINGUN:
+ case WP_PROX_LAUNCHER:
+//#endif
+ CG_MissileHitWall( weapon, 0, origin, dir, IMPACTSOUND_FLESH );
+ break;
+ default:
+ break;
+ }
+}
+
+
+
+/*
+============================================================================
+
+SHOTGUN TRACING
+
+============================================================================
+*/
+
+/*
+================
+CG_ShotgunPellet
+================
+*/
+static void CG_ShotgunPellet( vec3_t start, vec3_t end, int skipNum ) {
+ trace_t tr;
+ int sourceContentType, destContentType;
+
+// LEILEI ENHACNEMENT
+ localEntity_t *smoke;
+ vec3_t kapow;
+
+
+
+ CG_Trace( &tr, start, NULL, NULL, end, skipNum, MASK_SHOT );
+
+ sourceContentType = CG_PointContents( start, 0 );
+ destContentType = CG_PointContents( tr.endpos, 0 );
+
+ // FIXME: should probably move this cruft into CG_BubbleTrail
+ if ( sourceContentType == destContentType ) {
+ if ( sourceContentType & CONTENTS_WATER ) {
+ CG_BubbleTrail( start, tr.endpos, 32 );
+ }
+ } else if ( sourceContentType & CONTENTS_WATER ) {
+ trace_t trace;
+
+ trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
+ CG_BubbleTrail( start, trace.endpos, 32 );
+
+// LEILEI ENHANCEMENT
+ if (cg_leiEnhancement.integer) {
+ // Water Splash
+ VectorCopy( trace.plane.normal, kapow );
+
+ kapow[0] = kapow[0] * (crandom() * 22);
+ kapow[1] = kapow[1] * (crandom() * 22);
+ kapow[2] = kapow[2] * (crandom() * 65 + 37);
+ smoke = CG_SmokePuff( trace.endpos, kapow, 14, 1, 1, 1, 1.0f, 400, cg.time, 0, 0, cgs.media.lsplShader );
+ smoke = CG_SmokePuff( trace.endpos, kapow, 6, 1, 1, 1, 1.0f, 200, cg.time, 0, 0, cgs.media.lsplShader );
+ smoke = CG_SmokePuff( trace.endpos, kapow, 10, 1, 1, 1, 1.0f, 300, cg.time, 0, 0, cgs.media.lsplShader );
+
+ }
+// END LEIHANCMENET
+ } else if ( destContentType & CONTENTS_WATER ) {
+ trace_t trace;
+
+ trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
+ CG_BubbleTrail( tr.endpos, trace.endpos, 32 );
+
+// LEILEI ENHANCEMENT
+ if (cg_leiEnhancement.integer) {
+ // Water Splash
+ VectorCopy( trace.plane.normal, kapow );
+
+ kapow[0] = kapow[0] * (crandom() * 22);
+ kapow[1] = kapow[1] * (crandom() * 22);
+ kapow[2] = kapow[2] * (crandom() * 65 + 37);
+ smoke = CG_SmokePuff( trace.endpos, kapow, 14, 1, 1, 1, 1.0f, 400, cg.time, 0, 0, cgs.media.lsplShader );
+ smoke = CG_SmokePuff( trace.endpos, kapow, 6, 1, 1, 1, 1.0f, 200, cg.time, 0, 0, cgs.media.lsplShader );
+ smoke = CG_SmokePuff( trace.endpos, kapow, 10, 1, 1, 1, 1.0f, 300, cg.time, 0, 0, cgs.media.lsplShader );
+ }
+// END LEIHANCMENET
+ }
+
+ if ( tr.surfaceFlags & SURF_NOIMPACT ) {
+ return;
+ }
+
+ if ( cg_entities[tr.entityNum].currentState.eType == ET_PLAYER ) {
+ CG_MissileHitPlayer( WP_SHOTGUN, tr.endpos, tr.plane.normal, tr.entityNum );
+ } else {
+ if ( tr.surfaceFlags & SURF_NOIMPACT ) {
+ // SURF_NOIMPACT will not make a flame puff or a mark
+ return;
+ }
+ if ( tr.surfaceFlags & SURF_METALSTEPS ) {
+ CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL );
+// LEILEI ENHANCEMENT
+ if (cg_leiEnhancement.integer) {
+ VectorCopy( tr.plane.normal, kapow );
+
+ kapow[0] = kapow[0] * (crandom() * 65 + 37);
+ kapow[1] = kapow[1] * (crandom() * 65 + 37);
+ kapow[2] = kapow[2] * (crandom() * 65 + 37);
+ CG_LeiSparks(tr.endpos, tr.plane.normal, 800, 0, 0, 7);
+ CG_LeiSparks(tr.endpos, tr.plane.normal, 800, 0, 0, 3);
+ CG_LeiSparks(tr.endpos, tr.plane.normal, 800, 0, 0, 1);
+
+ }
+// END LEIHANCMENET
+ } else {
+ CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT );
+
+// LEILEI ENHANCEMENT
+ if (cg_leiEnhancement.integer) {
+ VectorCopy( tr.plane.normal, kapow );
+
+ kapow[0] = kapow[0] * (crandom() * 65 + 37);
+ kapow[1] = kapow[1] * (crandom() * 65 + 37);
+ kapow[2] = kapow[2] * (crandom() * 65 + 37);
+ CG_LeiSparks(tr.endpos, tr.plane.normal, 800, 0, 0, 7);
+ CG_LeiSparks(tr.endpos, tr.plane.normal, 800, 0, 0, 2);
+
+ smoke = CG_SmokePuff( tr.endpos, kapow, 21, 1, 1, 1, 0.9f, 1200, cg.time, 0, 0, cgs.media.lsmkShader2 );
+ //smoke = CG_SmokePuff( tr.endpos, kapow, 21, 1, 1, 1, 0.9f, 1200, cg.time, 0, 0, cgs.media.lbumShader1 );
+#if 0
+ CG_LeiPuff(tr.endpos, kapow, 500, 0, 0, 177, 6);
+ CG_LeiPuff(tr.endpos, tr.plane.normal, 500, 0, 0, 127, 12);
+ CG_LeiPuff(tr.endpos, tr.plane.normal, 500, 0, 0, 77, 16);
+ CG_LeiPuff(tr.endpos, tr.plane.normal, 500, 0, 0, 127, 12);
+ CG_LeiPuff(tr.endpos, tr.plane.normal, 500, 0, 0, 77, 16);
+ CG_LeiPuff(tr.endpos, tr.plane.normal, 500, 0, 0, 127, 12);
+ CG_LeiPuff(tr.endpos, tr.plane.normal, 500, 0, 0, 77, 16);
+#endif
+ }
+// END LEIHANCMENET
+ }
+ }
+}
+
+/*
+================
+CG_ShotgunPattern
+
+Perform the same traces the server did to locate the
+hit splashes
+================
+*/
+//unlagged - attack prediction
+// made this non-static for access from cg_unlagged.c
+void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) {
+ int i;
+ float r, u;
+ vec3_t end;
+ vec3_t forward, right, up;
+
+ // derive the right and up vectors from the forward vector, because
+ // the client won't have any other information
+ VectorNormalize2( origin2, forward );
+ PerpendicularVector( right, forward );
+ CrossProduct( forward, right, up );
+
+ // generate the "random" spread pattern
+ for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {
+ r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
+ u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
+ VectorMA( origin, 8192 * 16, forward, end);
+ VectorMA (end, r, right, end);
+ VectorMA (end, u, up, end);
+
+ CG_ShotgunPellet( origin, end, otherEntNum );
+ }
+}
+
+/*
+==============
+CG_ShotgunFire
+==============
+*/
+void CG_ShotgunFire( entityState_t *es ) {
+ vec3_t v;
+ int contents;
+
+ VectorSubtract( es->origin2, es->pos.trBase, v );
+ VectorNormalize( v );
+ VectorScale( v, 32, v );
+ VectorAdd( es->pos.trBase, v, v );
+ if ( cgs.glconfig.hardwareType != GLHW_RAGEPRO ) {
+ // ragepro can't alpha fade, so don't even bother with smoke
+ vec3_t up;
+ vec3_t forward;
+
+ contents = CG_PointContents( es->pos.trBase, 0 );
+ if ( !( contents & CONTENTS_WATER ) ) {
+ VectorSet( up, 0, 0, 8 );
+// LEILEI ENHANCEMENT
+ if (cg_leiEnhancement.integer) {
+ // Shotgun puffy
+ CG_LeiSparks(v, forward, 1500, 0, 0, 7);
+ CG_LeiSparks(v, forward, 1500, 0, 0, 7);
+ CG_LeiSparks(v, forward, 1500, 0, 0, 7);
+ CG_LeiSparks(v, forward, 1500, 0, 0, 7);
+ CG_LeiSparks(v, forward, 1500, 0, 0, 7);
+ CG_LeiSparks(v, forward, 1500, 0, 0, 7);
+ /* VectorSet( up, 4, 4, 4 );
+ up[0] = up[0] * (crandom() * 22 + 44); up[1] = up[1] * (crandom() * 22 + 44); up[2] = up[2] * (crandom() * 22 + 44);
+ CG_SmokePuff( v, up, 14, 1, 1, 1, 0.4f, 900, cg.time, 0, 0, cgs.media.lsmkShader1 );
+ up[0] = up[0] * (crandom() * 22 + 44); up[1] = up[1] * (crandom() * 22 + 44); up[2] = up[2] * (crandom() * 22 + 44);
+ CG_SmokePuff( v, up, 14, 1, 1, 1, 0.4f, 900, cg.time, 0, 0, cgs.media.lsmkShader2 );
+ up[0] = up[0] * (crandom() * 22 + 44); up[1] = up[1] * (crandom() * 22 + 44); up[2] = up[2] * (crandom() * 22 + 44);
+ CG_SmokePuff( v, up, 14, 1, 1, 1, 0.4f, 900, cg.time, 0, 0, cgs.media.lsmkShader3 );
+ up[0] = up[0] * (crandom() * 22 + 44); up[1] = up[1] * (crandom() * 22 + 44); up[2] = up[2] * (crandom() * 22 + 44);
+ CG_SmokePuff( v, up, 14, 1, 1, 1, 0.4f, 900, cg.time, 0, 0, cgs.media.lsmkShader4 );
+ */
+ }
+ else
+
+// END LEIHANCMENET
+
+CG_SmokePuff( v, up, 32, 1, 1, 1, 0.33f, 900, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
+
+ }
+ }
+ CG_ShotgunPattern( es->pos.trBase, es->origin2, es->eventParm, es->otherEntityNum );
+}
+
+/*
+============================================================================
+
+BULLETS
+
+============================================================================
+*/
+
+
+/*
+===============
+CG_Tracer
+===============
+*/
+void CG_Tracer( vec3_t source, vec3_t dest ) {
+ vec3_t forward, right;
+ polyVert_t verts[4];
+ vec3_t line;
+ float len, begin, end;
+ vec3_t start, finish;
+ vec3_t midpoint;
+
+ // tracer
+ VectorSubtract( dest, source, forward );
+ len = VectorNormalize( forward );
+
+ // start at least a little ways from the muzzle
+ if ( len < 100 ) {
+ return;
+ }
+ begin = 50 + random() * (len - 60);
+ end = begin + cg_tracerLength.value;
+ if ( end > len ) {
+ end = len;
+ }
+ VectorMA( source, begin, forward, start );
+ VectorMA( source, end, forward, finish );
+
+ line[0] = DotProduct( forward, cg.refdef.viewaxis[1] );
+ line[1] = DotProduct( forward, cg.refdef.viewaxis[2] );
+
+ VectorScale( cg.refdef.viewaxis[1], line[1], right );
+ VectorMA( right, -line[0], cg.refdef.viewaxis[2], right );
+ VectorNormalize( right );
+
+ VectorMA( finish, cg_tracerWidth.value, right, verts[0].xyz );
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 1;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255;
+
+ VectorMA( finish, -cg_tracerWidth.value, right, verts[1].xyz );
+ verts[1].st[0] = 1;
+ verts[1].st[1] = 0;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255;
+
+ VectorMA( start, -cg_tracerWidth.value, right, verts[2].xyz );
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255;
+
+ VectorMA( start, cg_tracerWidth.value, right, verts[3].xyz );
+ verts[3].st[0] = 0;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255;
+
+ trap_R_AddPolyToScene( cgs.media.tracerShader, 4, verts );
+
+ midpoint[0] = ( start[0] + finish[0] ) * 0.5;
+ midpoint[1] = ( start[1] + finish[1] ) * 0.5;
+ midpoint[2] = ( start[2] + finish[2] ) * 0.5;
+
+ // add the tracer sound
+ trap_S_StartSound( midpoint, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.tracerSound );
+
+}
+
+
+/*
+======================
+CG_CalcMuzzlePoint
+======================
+*/
+static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) {
+ vec3_t forward;
+ centity_t *cent;
+ int anim;
+
+ if ( entityNum == cg.snap->ps.clientNum ) {
+ VectorCopy( cg.snap->ps.origin, muzzle );
+ muzzle[2] += cg.snap->ps.viewheight;
+ AngleVectors( cg.snap->ps.viewangles, forward, NULL, NULL );
+ VectorMA( muzzle, 14, forward, muzzle );
+ return qtrue;
+ }
+
+ cent = &cg_entities[entityNum];
+ if ( !cent->currentValid ) {
+ return qfalse;
+ }
+
+ VectorCopy( cent->currentState.pos.trBase, muzzle );
+
+ AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL );
+ anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
+ if ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) {
+ muzzle[2] += CROUCH_VIEWHEIGHT;
+ } else {
+ muzzle[2] += DEFAULT_VIEWHEIGHT;
+ }
+
+ VectorMA( muzzle, 14, forward, muzzle );
+
+ return qtrue;
+
+}
+
+/*
+======================
+CG_Bullet
+
+Renders bullet effects.
+======================
+*/
+void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ) {
+ trace_t trace;
+ int sourceContentType, destContentType;
+ vec3_t start;
+// LEILEI ENHACNEMENT
+ localEntity_t *smoke;
+ vec3_t kapew;
+ vec3_t kapow;
+
+
+
+
+ // if the shooter is currently valid, calc a source point and possibly
+ // do trail effects
+ if ( sourceEntityNum >= 0 && cg_tracerChance.value > 0 ) {
+ if ( CG_CalcMuzzlePoint( sourceEntityNum, start ) ) {
+ sourceContentType = CG_PointContents( start, 0 );
+ destContentType = CG_PointContents( end, 0 );
+
+ // do a complete bubble trail if necessary
+ if ( ( sourceContentType == destContentType ) && ( sourceContentType & CONTENTS_WATER ) ) {
+ CG_BubbleTrail( start, end, 32 );
+ }
+ // bubble trail from water into air
+ else if ( ( sourceContentType & CONTENTS_WATER ) ) {
+ trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
+ CG_BubbleTrail( start, trace.endpos, 32 );
+
+
+// LEILEI ENHANCEMENT
+ if (cg_leiEnhancement.integer) {
+ // Water Splash
+ VectorCopy( trace.plane.normal, kapow );
+ kapow[0] = kapow[0] * (crandom() * 22);
+ kapow[1] = kapow[1] * (crandom() * 22);
+ kapow[2] = kapow[2] * (crandom() * 65 + 37);
+ smoke = CG_SmokePuff( trace.endpos, kapow, 14, 1, 1, 1, 1.0f, 400, cg.time, 0, 0, cgs.media.lsplShader );
+ smoke = CG_SmokePuff( trace.endpos, kapow, 6, 1, 1, 1, 1.0f, 200, cg.time, 0, 0, cgs.media.lsplShader );
+ smoke = CG_SmokePuff( trace.endpos, kapow, 10, 1, 1, 1, 1.0f, 300, cg.time, 0, 0, cgs.media.lsplShader );
+ // CG_LeiSplash2(trace.endpos, kapow, 900, 0, 0, 444);
+
+ }
+// END LEIHANCMENET
+
+
+ }
+ // bubble trail from air into water
+ else if ( ( destContentType & CONTENTS_WATER ) ) {
+ trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
+ CG_BubbleTrail( trace.endpos, end, 32 );
+
+// LEILEI ENHANCEMENT
+ if (cg_leiEnhancement.integer) {
+ // Water Splash
+ VectorCopy( trace.plane.normal, kapow );
+
+ kapow[0] = kapow[0] * (crandom() * 22);
+ kapow[1] = kapow[1] * (crandom() * 22);
+ kapow[2] = kapow[2] * (crandom() * 65 + 37);
+ smoke = CG_SmokePuff( trace.endpos, kapow, 14, 1, 1, 1, 1.0f, 400, cg.time, 0, 0, cgs.media.lsplShader );
+ smoke = CG_SmokePuff( trace.endpos, kapow, 6, 1, 1, 1, 1.0f, 200, cg.time, 0, 0, cgs.media.lsplShader );
+ smoke = CG_SmokePuff( trace.endpos, kapow, 10, 1, 1, 1, 1.0f, 300, cg.time, 0, 0, cgs.media.lsplShader );
+ //CG_LeiSplash2(trace.endpos, kapow, 500, 0, 0, 1);
+ }
+// END LEIHANCMENET
+ }
+
+ // draw a tracer
+ if ( random() < cg_tracerChance.value ) {
+ CG_Tracer( start, end );
+ }
+ }
+ }
+
+ // impact splash and mark
+ if ( flesh ) {
+// LEILEI ENHANCEMENT
+ if (cg_leiEnhancement.integer) {
+
+
+ // Blood Hack
+ VectorCopy( normal, kapow );
+
+ kapow[0] = kapow[0] * (crandom() * 65 + 37);
+ kapow[1] = kapow[1] * (crandom() * 65 + 37);
+ kapow[2] = kapow[2] * (crandom() * 65 + 37);
+ VectorCopy( kapow, kapew );
+
+ kapew[0] = kapew[0] * (crandom() * 2 + 37);
+ kapew[1] = kapew[1] * (crandom() * 2 + 37);
+ kapew[2] = kapew[2] * (crandom() * 2 + 37);
+
+ CG_SmokePuff( end, kapow, 6, 1, 1, 1, 1.0f, 600, cg.time, 0, 0, cgs.media.lbldShader1 );
+// CG_SpurtBlood( end, kapow, 2);
+ CG_SpurtBlood( end, kapew, 1);
+ //CG_Particle_Bleed(cgs.media.lbldShader1,kapew,'0 0 0', 0, 100);
+// CG_Particle_Bleed(cgs.media.lbldShader1,kapew,kapow, 0, 100);
+// CG_Particle_BloodCloud(self,end,'0 0 0');
+
+if (cg_leiSuperGoreyAwesome.integer) {
+ CG_SpurtBlood( end, kapow, -2);
+ }
+ }
+
+ else
+ CG_Bleed( end, fleshEntityNum );
+ } else {
+ CG_MissileHitWall( WP_MACHINEGUN, 0, end, normal, IMPACTSOUND_DEFAULT );
+
+// LEILEI ENHANCEMENT
+ if (cg_leiEnhancement.integer) {
+
+ // Smoke puff
+ VectorCopy( normal, kapow );
+
+ kapow[0] = kapow[0] * (crandom() * 65 + 37);
+ kapow[1] = kapow[1] * (crandom() * 65 + 37);
+ kapow[2] = kapow[2] * (crandom() * 65 + 37);
+ VectorCopy( kapow, kapew );
+
+ kapew[0] = kapew[0] * (crandom() * 65 + 37);
+ kapew[1] = kapew[1] * (crandom() * 65 + 37);
+ kapew[2] = kapew[2] * (crandom() * 65 + 37);
+
+
+ smoke = CG_SmokePuff( end, kapow, 14, 1, 1, 1, 1.0f, 600, cg.time, 0, 0, cgs.media.lsmkShader1 );
+ // CG_LeiSparks(end, normal, 600, 0, 0, 177);
+ // CG_LeiSparks(end, normal, 600, 0, 0, 155);
+ // CG_LeiSparks(end, normal, 600, 0, 0, 444);
+ // CG_LeiSparks(trace.endpos, trace.plane.normal, 800, 0, 0, 7);
+ // CG_LeiSparks(trace.endpos, trace.plane.normal, 800, 0, 0, 3);
+ // CG_LeiSparks(trace.endpos, trace.plane.normal, 800, 0, 0, 1);
+
+ }
+// END LEIHANCMENET
+ }
+
+}
diff --git a/game/code/client/keycodes.h b/code/client/keycodes.h
similarity index 100%
rename from game/code/client/keycodes.h
rename to code/client/keycodes.h
diff --git a/code/game/ai_chat.c b/code/game/ai_chat.c
new file mode 100644
index 0000000..cf21d5e
--- /dev/null
+++ b/code/game/ai_chat.c
@@ -0,0 +1,1218 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+/*****************************************************************************
+ * name: ai_chat.c
+ *
+ * desc: Quake3 bot AI
+ *
+ * $Archive: /MissionPack/code/game/ai_chat.c $
+ *
+ *****************************************************************************/
+
+#include "g_local.h"
+#include "../botlib/botlib.h"
+#include "../botlib/be_aas.h"
+#include "../botlib/be_ea.h"
+#include "../botlib/be_ai_char.h"
+#include "../botlib/be_ai_chat.h"
+#include "../botlib/be_ai_gen.h"
+#include "../botlib/be_ai_goal.h"
+#include "../botlib/be_ai_move.h"
+#include "../botlib/be_ai_weap.h"
+//
+#include "ai_main.h"
+#include "ai_dmq3.h"
+#include "ai_chat.h"
+#include "ai_cmd.h"
+#include "ai_dmnet.h"
+//
+#include "chars.h" //characteristics
+#include "inv.h" //indexes into the inventory
+#include "syn.h" //synonyms
+#include "match.h" //string matching types and vars
+
+// for the voice chats
+#ifdef MISSIONPACK // bk001205
+#include "../../ui/menudef.h"
+#endif
+
+#define TIME_BETWEENCHATTING 25
+
+
+/*
+==================
+BotNumActivePlayers
+==================
+*/
+int BotNumActivePlayers(void) {
+ int i, num;
+ char buf[MAX_INFO_STRING];
+ static int maxclients;
+
+ if (!maxclients)
+ maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
+
+ num = 0;
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ //if no config string or no name
+ if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
+ //skip spectators
+ if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
+ //
+ num++;
+ }
+ return num;
+}
+
+/*
+==================
+BotIsFirstInRankings
+==================
+*/
+int BotIsFirstInRankings(bot_state_t *bs) {
+ int i, score;
+ char buf[MAX_INFO_STRING];
+ static int maxclients;
+ playerState_t ps;
+
+ if (!maxclients)
+ maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
+
+ score = bs->cur_ps.persistant[PERS_SCORE];
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ //if no config string or no name
+ if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
+ //skip spectators
+ if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
+ //
+ BotAI_GetClientState(i, &ps);
+ if (score < ps.persistant[PERS_SCORE]) return qfalse;
+ }
+ return qtrue;
+}
+
+/*
+==================
+BotIsLastInRankings
+==================
+*/
+int BotIsLastInRankings(bot_state_t *bs) {
+ int i, score;
+ char buf[MAX_INFO_STRING];
+ static int maxclients;
+ playerState_t ps;
+
+ if (!maxclients)
+ maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
+
+ score = bs->cur_ps.persistant[PERS_SCORE];
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ //if no config string or no name
+ if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
+ //skip spectators
+ if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
+ //
+ BotAI_GetClientState(i, &ps);
+ if (score > ps.persistant[PERS_SCORE]) return qfalse;
+ }
+ return qtrue;
+}
+
+/*
+==================
+BotFirstClientInRankings
+==================
+*/
+char *BotFirstClientInRankings(void) {
+ int i, bestscore, bestclient;
+ char buf[MAX_INFO_STRING];
+ static char name[32];
+ static int maxclients;
+ playerState_t ps;
+
+ if (!maxclients)
+ maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
+
+ bestscore = -999999;
+ bestclient = 0;
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ //if no config string or no name
+ if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
+ //skip spectators
+ if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
+ //
+ BotAI_GetClientState(i, &ps);
+ if (ps.persistant[PERS_SCORE] > bestscore) {
+ bestscore = ps.persistant[PERS_SCORE];
+ bestclient = i;
+ }
+ }
+ EasyClientName(bestclient, name, 32);
+ return name;
+}
+
+/*
+==================
+BotLastClientInRankings
+==================
+*/
+char *BotLastClientInRankings(void) {
+ int i, worstscore, bestclient;
+ char buf[MAX_INFO_STRING];
+ static char name[32];
+ static int maxclients;
+ playerState_t ps;
+
+ if (!maxclients)
+ maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
+
+ worstscore = 999999;
+ bestclient = 0;
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ //if no config string or no name
+ if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
+ //skip spectators
+ if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
+ //
+ BotAI_GetClientState(i, &ps);
+ if (ps.persistant[PERS_SCORE] < worstscore) {
+ worstscore = ps.persistant[PERS_SCORE];
+ bestclient = i;
+ }
+ }
+ EasyClientName(bestclient, name, 32);
+ return name;
+}
+
+/*
+==================
+BotRandomOpponentName
+==================
+*/
+char *BotRandomOpponentName(bot_state_t *bs) {
+ int i, count;
+ char buf[MAX_INFO_STRING];
+ int opponents[MAX_CLIENTS], numopponents;
+ static int maxclients;
+ static char name[32];
+
+ if (!maxclients)
+ maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
+
+ numopponents = 0;
+ opponents[0] = 0;
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ if (i == bs->client) continue;
+ //
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ //if no config string or no name
+ if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
+ //skip spectators
+ if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
+ //skip team mates
+ if (BotSameTeam(bs, i)) continue;
+ //
+ opponents[numopponents] = i;
+ numopponents++;
+ }
+ count = random() * numopponents;
+ for (i = 0; i < numopponents; i++) {
+ count--;
+ if (count <= 0) {
+ EasyClientName(opponents[i], name, sizeof(name));
+ return name;
+ }
+ }
+ EasyClientName(opponents[0], name, sizeof(name));
+ return name;
+}
+
+/*
+==================
+BotMapTitle
+==================
+*/
+
+char *BotMapTitle(void) {
+ char info[1024];
+ static char mapname[128];
+
+ trap_GetServerinfo(info, sizeof(info));
+
+ strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1);
+ mapname[sizeof(mapname)-1] = '\0';
+
+ return mapname;
+}
+
+
+/*
+==================
+BotWeaponNameForMeansOfDeath
+==================
+*/
+
+char *BotWeaponNameForMeansOfDeath(int mod) {
+ switch(mod) {
+ case MOD_SHOTGUN: return "Shotgun";
+ case MOD_GAUNTLET: return "Gauntlet";
+ case MOD_MACHINEGUN: return "Machinegun";
+ case MOD_GRENADE:
+ case MOD_GRENADE_SPLASH: return "Grenade Launcher";
+ case MOD_ROCKET:
+ case MOD_ROCKET_SPLASH: return "Rocket Launcher";
+ case MOD_PLASMA:
+ case MOD_PLASMA_SPLASH: return "Plasmagun";
+ case MOD_RAILGUN: return "Railgun";
+ case MOD_LIGHTNING: return "Lightning Gun";
+ case MOD_BFG:
+ case MOD_BFG_SPLASH: return "BFG10K";
+ case MOD_NAIL: return "Nailgun";
+ case MOD_CHAINGUN: return "Chaingun";
+ case MOD_PROXIMITY_MINE: return "Proximity Launcher";
+ case MOD_KAMIKAZE: return "Kamikaze";
+ case MOD_JUICED: return "Prox mine";
+ case MOD_GRAPPLE: return "Grapple";
+ default: return "[unknown weapon]";
+ }
+}
+
+/*
+==================
+BotRandomWeaponName
+==================
+*/
+char *BotRandomWeaponName(void) {
+ int rnd;
+
+ rnd = random() * 11.9;
+ switch(rnd) {
+ case 0: return "Gauntlet";
+ case 1: return "Shotgun";
+ case 2: return "Machinegun";
+ case 3: return "Grenade Launcher";
+ case 4: return "Rocket Launcher";
+ case 5: return "Plasmagun";
+ case 6: return "Railgun";
+ case 7: return "Lightning Gun";
+ case 8: return "Nailgun";
+ case 9: return "Chaingun";
+ case 10: return "Proximity Launcher";
+ default: return "BFG10K";
+ }
+}
+
+/*
+==================
+BotVisibleEnemies
+==================
+*/
+int BotVisibleEnemies(bot_state_t *bs) {
+ float vis;
+ int i;
+ aas_entityinfo_t entinfo;
+
+ for (i = 0; i < MAX_CLIENTS; i++) {
+
+ if (i == bs->client) continue;
+ //
+ BotEntityInfo(i, &entinfo);
+ //
+ if (!entinfo.valid) continue;
+ //if the enemy isn't dead and the enemy isn't the bot self
+ if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;
+ //if the enemy is invisible and not shooting
+ if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
+ continue;
+ }
+ //if on the same team
+ if (BotSameTeam(bs, i)) continue;
+ //check if the enemy is visible
+ vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
+ if (vis > 0) return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+BotValidChatPosition
+==================
+*/
+int BotValidChatPosition(bot_state_t *bs) {
+ vec3_t point, start, end, mins, maxs;
+ bsp_trace_t trace;
+
+ //if the bot is dead all positions are valid
+ if (BotIsDead(bs)) return qtrue;
+ if (BotIsObserver(bs)) return qtrue;
+ //never start chatting with a powerup
+ if (bs->inventory[INVENTORY_QUAD] ||
+ bs->inventory[INVENTORY_ENVIRONMENTSUIT] ||
+ bs->inventory[INVENTORY_HASTE] ||
+ bs->inventory[INVENTORY_INVISIBILITY] ||
+ bs->inventory[INVENTORY_REGEN] ||
+ bs->inventory[INVENTORY_FLIGHT]) return qfalse;
+ //must be on the ground
+ //if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) return qfalse;
+ //do not chat if in lava or slime
+ VectorCopy(bs->origin, point);
+ point[2] -= 24;
+ if (trap_PointContents(point,bs->entitynum) & (CONTENTS_LAVA|CONTENTS_SLIME)) return qfalse;
+ //do not chat if under water
+ VectorCopy(bs->origin, point);
+ point[2] += 32;
+ if (trap_PointContents(point,bs->entitynum) & MASK_WATER) return qfalse;
+ //must be standing on the world entity
+ VectorCopy(bs->origin, start);
+ VectorCopy(bs->origin, end);
+ start[2] += 1;
+ end[2] -= 10;
+ trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs);
+ BotAI_Trace(&trace, start, mins, maxs, end, bs->client, MASK_SOLID);
+ if (trace.ent != ENTITYNUM_WORLD) return qfalse;
+ //the bot is in a position where it can chat
+ return qtrue;
+}
+
+/*
+==================
+BotChat_EnterGame
+==================
+*/
+int BotChat_EnterGame(bot_state_t *bs) {
+ char name[32];
+ float rnd;
+
+ if (bot_nochat.integer) return qfalse;
+ if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
+ //don't chat in teamplay
+ if (TeamPlayIsOn()) return qfalse;
+ // don't chat in tournament mode
+ if (gametype == GT_TOURNAMENT) return qfalse;
+ rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);
+ if (!bot_fastchat.integer) {
+ if (random() > rnd) return qfalse;
+ }
+ if (BotNumActivePlayers() <= 1) return qfalse;
+ if (!BotValidChatPosition(bs)) return qfalse;
+ BotAI_BotInitialChat(bs, "game_enter",
+ EasyClientName(bs->client, name, 32), // 0
+ BotRandomOpponentName(bs), // 1
+ "[invalid var]", // 2
+ "[invalid var]", // 3
+ BotMapTitle(), // 4
+ NULL);
+ bs->lastchat_time = FloatTime();
+ bs->chatto = CHAT_ALL;
+ return qtrue;
+}
+
+/*
+==================
+BotChat_ExitGame
+==================
+*/
+int BotChat_ExitGame(bot_state_t *bs) {
+ char name[32];
+ float rnd;
+
+ if (bot_nochat.integer) return qfalse;
+ if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
+ //don't chat in teamplay
+ if (TeamPlayIsOn()) return qfalse;
+ // don't chat in tournament mode
+ if (gametype == GT_TOURNAMENT) return qfalse;
+ rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);
+ if (!bot_fastchat.integer) {
+ if (random() > rnd) return qfalse;
+ }
+ if (BotNumActivePlayers() <= 1) return qfalse;
+ //
+ BotAI_BotInitialChat(bs, "game_exit",
+ EasyClientName(bs->client, name, 32), // 0
+ BotRandomOpponentName(bs), // 1
+ "[invalid var]", // 2
+ "[invalid var]", // 3
+ BotMapTitle(), // 4
+ NULL);
+ bs->lastchat_time = FloatTime();
+ bs->chatto = CHAT_ALL;
+ return qtrue;
+}
+
+/*
+==================
+BotChat_StartLevel
+==================
+*/
+int BotChat_StartLevel(bot_state_t *bs) {
+ char name[32];
+ float rnd;
+
+ if (bot_nochat.integer) return qfalse;
+ if (BotIsObserver(bs)) return qfalse;
+ if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
+ //don't chat in teamplay
+ if (TeamPlayIsOn()) {
+ trap_EA_Command(bs->client, "vtaunt");
+ return qfalse;
+ }
+ // don't chat in tournament mode
+ if (gametype == GT_TOURNAMENT) return qfalse;
+ rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);
+ if (!bot_fastchat.integer) {
+ if (random() > rnd) return qfalse;
+ }
+ if (BotNumActivePlayers() <= 1) return qfalse;
+ BotAI_BotInitialChat(bs, "level_start",
+ EasyClientName(bs->client, name, 32), // 0
+ NULL);
+ bs->lastchat_time = FloatTime();
+ bs->chatto = CHAT_ALL;
+ return qtrue;
+}
+
+/*
+==================
+BotChat_EndLevel
+==================
+*/
+int BotChat_EndLevel(bot_state_t *bs) {
+ char name[32];
+ float rnd;
+
+ if (bot_nochat.integer) return qfalse;
+ if (BotIsObserver(bs)) return qfalse;
+ if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
+ // teamplay
+ if (TeamPlayIsOn())
+ {
+ if (BotIsFirstInRankings(bs)) {
+ trap_EA_Command(bs->client, "vtaunt");
+ }
+ return qtrue;
+ }
+ // don't chat in tournament mode
+ if (gametype == GT_TOURNAMENT) return qfalse;
+ rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);
+ if (!bot_fastchat.integer) {
+ if (random() > rnd) return qfalse;
+ }
+ if (BotNumActivePlayers() <= 1) return qfalse;
+ //
+ if (BotIsFirstInRankings(bs)) {
+ BotAI_BotInitialChat(bs, "level_end_victory",
+ EasyClientName(bs->client, name, 32), // 0
+ BotRandomOpponentName(bs), // 1
+ "[invalid var]", // 2
+ BotLastClientInRankings(), // 3
+ BotMapTitle(), // 4
+ NULL);
+ }
+ else if (BotIsLastInRankings(bs)) {
+ BotAI_BotInitialChat(bs, "level_end_lose",
+ EasyClientName(bs->client, name, 32), // 0
+ BotRandomOpponentName(bs), // 1
+ BotFirstClientInRankings(), // 2
+ "[invalid var]", // 3
+ BotMapTitle(), // 4
+ NULL);
+ }
+ else {
+ BotAI_BotInitialChat(bs, "level_end",
+ EasyClientName(bs->client, name, 32), // 0
+ BotRandomOpponentName(bs), // 1
+ BotFirstClientInRankings(), // 2
+ BotLastClientInRankings(), // 3
+ BotMapTitle(), // 4
+ NULL);
+ }
+ bs->lastchat_time = FloatTime();
+ bs->chatto = CHAT_ALL;
+ return qtrue;
+}
+
+/*
+==================
+BotChat_Death
+==================
+*/
+int BotChat_Death(bot_state_t *bs) {
+ char name[32];
+ float rnd;
+
+ if (bot_nochat.integer) return qfalse;
+ if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
+ rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_DEATH, 0, 1);
+ // don't chat in tournament mode
+ if (gametype == GT_TOURNAMENT) return qfalse;
+ //if fast chatting is off
+ if (!bot_fastchat.integer) {
+ if (random() > rnd) return qfalse;
+ }
+ if (BotNumActivePlayers() <= 1) return qfalse;
+ //
+ if (bs->lastkilledby >= 0 && bs->lastkilledby < MAX_CLIENTS)
+ EasyClientName(bs->lastkilledby, name, 32);
+ else
+ strcpy(name, "[world]");
+ //
+ if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledby)) {
+ if (bs->lastkilledby == bs->client) return qfalse;
+ BotAI_BotInitialChat(bs, "death_teammate", name, NULL);
+ bs->chatto = CHAT_TEAM;
+ }
+ else
+ {
+ //teamplay
+ if (TeamPlayIsOn()) {
+ trap_EA_Command(bs->client, "vtaunt");
+ return qtrue;
+ }
+ //
+ if (bs->botdeathtype == MOD_WATER)
+ BotAI_BotInitialChat(bs, "death_drown", BotRandomOpponentName(bs), NULL);
+ else if (bs->botdeathtype == MOD_SLIME)
+ BotAI_BotInitialChat(bs, "death_slime", BotRandomOpponentName(bs), NULL);
+ else if (bs->botdeathtype == MOD_LAVA)
+ BotAI_BotInitialChat(bs, "death_lava", BotRandomOpponentName(bs), NULL);
+ else if (bs->botdeathtype == MOD_FALLING)
+ BotAI_BotInitialChat(bs, "death_cratered", BotRandomOpponentName(bs), NULL);
+ else if (bs->botsuicide || //all other suicides by own weapon
+ bs->botdeathtype == MOD_CRUSH ||
+ bs->botdeathtype == MOD_SUICIDE ||
+ bs->botdeathtype == MOD_TARGET_LASER ||
+ bs->botdeathtype == MOD_TRIGGER_HURT ||
+ bs->botdeathtype == MOD_UNKNOWN)
+ BotAI_BotInitialChat(bs, "death_suicide", BotRandomOpponentName(bs), NULL);
+ else if (bs->botdeathtype == MOD_TELEFRAG)
+ BotAI_BotInitialChat(bs, "death_telefrag", name, NULL);
+ else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "death_kamikaze"))
+ BotAI_BotInitialChat(bs, "death_kamikaze", name, NULL);
+ else {
+ if ((bs->botdeathtype == MOD_GAUNTLET ||
+ bs->botdeathtype == MOD_RAILGUN ||
+ bs->botdeathtype == MOD_BFG ||
+ bs->botdeathtype == MOD_BFG_SPLASH) && random() < 0.5) {
+
+ if (bs->botdeathtype == MOD_GAUNTLET)
+ BotAI_BotInitialChat(bs, "death_gauntlet",
+ name, // 0
+ BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
+ NULL);
+ else if (bs->botdeathtype == MOD_RAILGUN)
+ BotAI_BotInitialChat(bs, "death_rail",
+ name, // 0
+ BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
+ NULL);
+ else
+ BotAI_BotInitialChat(bs, "death_bfg",
+ name, // 0
+ BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
+ NULL);
+ }
+ //choose between insult and praise
+ else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {
+ BotAI_BotInitialChat(bs, "death_insult",
+ name, // 0
+ BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
+ NULL);
+ }
+ else {
+ BotAI_BotInitialChat(bs, "death_praise",
+ name, // 0
+ BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
+ NULL);
+ }
+ }
+ bs->chatto = CHAT_ALL;
+ }
+ bs->lastchat_time = FloatTime();
+ return qtrue;
+}
+
+/*
+==================
+BotChat_Kill
+==================
+*/
+int BotChat_Kill(bot_state_t *bs) {
+ char name[32];
+ float rnd;
+
+ if (bot_nochat.integer) return qfalse;
+ if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
+ rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1);
+ // don't chat in tournament mode
+ if (gametype == GT_TOURNAMENT) return qfalse;
+ //if fast chat is off
+ if (!bot_fastchat.integer) {
+ if (random() > rnd) return qfalse;
+ }
+ if (bs->lastkilledplayer == bs->client) return qfalse;
+ if (BotNumActivePlayers() <= 1) return qfalse;
+ if (!BotValidChatPosition(bs)) return qfalse;
+ //
+ if (BotVisibleEnemies(bs)) return qfalse;
+ //
+ EasyClientName(bs->lastkilledplayer, name, 32);
+ //
+ bs->chatto = CHAT_ALL;
+ if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledplayer)) {
+ BotAI_BotInitialChat(bs, "kill_teammate", name, NULL);
+ bs->chatto = CHAT_TEAM;
+ }
+ else
+ {
+ //don't chat in teamplay
+ if (TeamPlayIsOn()) {
+ trap_EA_Command(bs->client, "vtaunt");
+ return qfalse; // don't wait
+ }
+ //
+ if (bs->enemydeathtype == MOD_GAUNTLET) {
+ BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL);
+ }
+ else if (bs->enemydeathtype == MOD_RAILGUN) {
+ BotAI_BotInitialChat(bs, "kill_rail", name, NULL);
+ }
+ else if (bs->enemydeathtype == MOD_TELEFRAG) {
+ BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL);
+ }
+ else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "kill_kamikaze"))
+ BotAI_BotInitialChat(bs, "kill_kamikaze", name, NULL);
+ //choose between insult and praise
+ else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {
+ BotAI_BotInitialChat(bs, "kill_insult", name, NULL);
+ }
+ else {
+ BotAI_BotInitialChat(bs, "kill_praise", name, NULL);
+ }
+ }
+ bs->lastchat_time = FloatTime();
+ return qtrue;
+}
+
+/*
+==================
+BotChat_EnemySuicide
+==================
+*/
+int BotChat_EnemySuicide(bot_state_t *bs) {
+ char name[32];
+ float rnd;
+
+ if (bot_nochat.integer) return qfalse;
+ if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
+ if (BotNumActivePlayers() <= 1) return qfalse;
+ //
+ rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENEMYSUICIDE, 0, 1);
+ //don't chat in teamplay
+ if (TeamPlayIsOn()) return qfalse;
+ // don't chat in tournament mode
+ if (gametype == GT_TOURNAMENT) return qfalse;
+ //if fast chat is off
+ if (!bot_fastchat.integer) {
+ if (random() > rnd) return qfalse;
+ }
+ if (!BotValidChatPosition(bs)) return qfalse;
+ //
+ if (BotVisibleEnemies(bs)) return qfalse;
+ //
+ if (bs->enemy >= 0) EasyClientName(bs->enemy, name, 32);
+ else strcpy(name, "");
+ BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL);
+ bs->lastchat_time = FloatTime();
+ bs->chatto = CHAT_ALL;
+ return qtrue;
+}
+
+/*
+==================
+BotChat_HitTalking
+==================
+*/
+int BotChat_HitTalking(bot_state_t *bs) {
+ char name[32], *weap;
+ int lasthurt_client;
+ float rnd;
+
+ if (bot_nochat.integer) return qfalse;
+ if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
+ if (BotNumActivePlayers() <= 1) return qfalse;
+ lasthurt_client = g_entities[bs->client].client->lasthurt_client;
+ if (!lasthurt_client) return qfalse;
+ if (lasthurt_client == bs->client) return qfalse;
+ //
+ if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;
+ //
+ rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITTALKING, 0, 1);
+ //don't chat in teamplay
+ if (TeamPlayIsOn()) return qfalse;
+ // don't chat in tournament mode
+ if (gametype == GT_TOURNAMENT) return qfalse;
+ //if fast chat is off
+ if (!bot_fastchat.integer) {
+ if (random() > rnd * 0.5) return qfalse;
+ }
+ if (!BotValidChatPosition(bs)) return qfalse;
+ //
+ ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name));
+ weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_mod);
+ //
+ BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL);
+ bs->lastchat_time = FloatTime();
+ bs->chatto = CHAT_ALL;
+ return qtrue;
+}
+
+/*
+==================
+BotChat_HitNoDeath
+==================
+*/
+int BotChat_HitNoDeath(bot_state_t *bs) {
+ char name[32], *weap;
+ float rnd;
+ int lasthurt_client;
+ aas_entityinfo_t entinfo;
+
+ lasthurt_client = g_entities[bs->client].client->lasthurt_client;
+ if (!lasthurt_client) return qfalse;
+ if (lasthurt_client == bs->client) return qfalse;
+ //
+ if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;
+ //
+ if (bot_nochat.integer) return qfalse;
+ if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
+ if (BotNumActivePlayers() <= 1) return qfalse;
+ rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNODEATH, 0, 1);
+ //don't chat in teamplay
+ if (TeamPlayIsOn()) return qfalse;
+ // don't chat in tournament mode
+ if (gametype == GT_TOURNAMENT) return qfalse;
+ //if fast chat is off
+ if (!bot_fastchat.integer) {
+ if (random() > rnd * 0.5) return qfalse;
+ }
+ if (!BotValidChatPosition(bs)) return qfalse;
+ //
+ if (BotVisibleEnemies(bs)) return qfalse;
+ //
+ BotEntityInfo(bs->enemy, &entinfo);
+ if (EntityIsShooting(&entinfo)) return qfalse;
+ //
+ ClientName(lasthurt_client, name, sizeof(name));
+ weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_mod);
+ //
+ BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL);
+ bs->lastchat_time = FloatTime();
+ bs->chatto = CHAT_ALL;
+ return qtrue;
+}
+
+/*
+==================
+BotChat_HitNoKill
+==================
+*/
+int BotChat_HitNoKill(bot_state_t *bs) {
+ char name[32], *weap;
+ float rnd;
+ aas_entityinfo_t entinfo;
+
+ if (bot_nochat.integer) return qfalse;
+ if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
+ if (BotNumActivePlayers() <= 1) return qfalse;
+ rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNOKILL, 0, 1);
+ //don't chat in teamplay
+ if (TeamPlayIsOn()) return qfalse;
+ // don't chat in tournament mode
+ if (gametype == GT_TOURNAMENT) return qfalse;
+ //if fast chat is off
+ if (!bot_fastchat.integer) {
+ if (random() > rnd * 0.5) return qfalse;
+ }
+ if (!BotValidChatPosition(bs)) return qfalse;
+ //
+ if (BotVisibleEnemies(bs)) return qfalse;
+ //
+ BotEntityInfo(bs->enemy, &entinfo);
+ if (EntityIsShooting(&entinfo)) return qfalse;
+ //
+ ClientName(bs->enemy, name, sizeof(name));
+ weap = BotWeaponNameForMeansOfDeath(g_entities[bs->enemy].client->lasthurt_mod);
+ //
+ BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL);
+ bs->lastchat_time = FloatTime();
+ bs->chatto = CHAT_ALL;
+ return qtrue;
+}
+
+/*
+==================
+BotChat_Random
+==================
+*/
+int BotChat_Random(bot_state_t *bs) {
+ float rnd;
+ char name[32];
+
+ if (bot_nochat.integer) return qfalse;
+ if (BotIsObserver(bs)) return qfalse;
+ if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
+ // don't chat in tournament mode
+ if (gametype == GT_TOURNAMENT) return qfalse;
+ //don't chat when doing something important :)
+ if (bs->ltgtype == LTG_TEAMHELP ||
+ bs->ltgtype == LTG_TEAMACCOMPANY ||
+ bs->ltgtype == LTG_RUSHBASE) return qfalse;
+ //
+ rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_RANDOM, 0, 1);
+ if (random() > bs->thinktime * 0.1) return qfalse;
+ if (!bot_fastchat.integer) {
+ if (random() > rnd) return qfalse;
+ if (random() > 0.25) return qfalse;
+ }
+ if (BotNumActivePlayers() <= 1) return qfalse;
+ //
+ if (!BotValidChatPosition(bs)) return qfalse;
+ //
+ if (BotVisibleEnemies(bs)) return qfalse;
+ //
+ if (bs->lastkilledplayer == bs->client) {
+ Q_strncpyz(name, BotRandomOpponentName(bs),sizeof(name));
+ }
+ else {
+ EasyClientName(bs->lastkilledplayer, name, sizeof(name));
+ }
+ if (TeamPlayIsOn()) {
+ trap_EA_Command(bs->client, "vtaunt");
+ return qfalse; // don't wait
+ }
+ //
+ if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_MISC, 0, 1)) {
+ BotAI_BotInitialChat(bs, "random_misc",
+ BotRandomOpponentName(bs), // 0
+ name, // 1
+ "[invalid var]", // 2
+ "[invalid var]", // 3
+ BotMapTitle(), // 4
+ BotRandomWeaponName(), // 5
+ NULL);
+ }
+ else {
+ BotAI_BotInitialChat(bs, "random_insult",
+ BotRandomOpponentName(bs), // 0
+ name, // 1
+ "[invalid var]", // 2
+ "[invalid var]", // 3
+ BotMapTitle(), // 4
+ BotRandomWeaponName(), // 5
+ NULL);
+ }
+ bs->lastchat_time = FloatTime();
+ bs->chatto = CHAT_ALL;
+ return qtrue;
+}
+
+/*
+==================
+BotChatTime
+==================
+*/
+float BotChatTime(bot_state_t *bs) {
+ int cpm;
+
+ cpm = trap_Characteristic_BInteger(bs->character, CHARACTERISTIC_CHAT_CPM, 1, 4000);
+
+ return 2.0; //(float) trap_BotChatLength(bs->cs) * 30 / cpm;
+}
+
+/*
+==================
+BotChatTest
+==================
+*/
+void BotChatTest(bot_state_t *bs) {
+
+ char name[32];
+ char *weap;
+ int num, i;
+
+ if (bot_nochat.integer) return;
+
+ num = trap_BotNumInitialChats(bs->cs, "game_enter");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "game_enter",
+ EasyClientName(bs->client, name, 32), // 0
+ BotRandomOpponentName(bs), // 1
+ "[invalid var]", // 2
+ "[invalid var]", // 3
+ BotMapTitle(), // 4
+ NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "game_exit");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "game_exit",
+ EasyClientName(bs->client, name, 32), // 0
+ BotRandomOpponentName(bs), // 1
+ "[invalid var]", // 2
+ "[invalid var]", // 3
+ BotMapTitle(), // 4
+ NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "level_start");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "level_start",
+ EasyClientName(bs->client, name, 32), // 0
+ NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "level_end_victory");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "level_end_victory",
+ EasyClientName(bs->client, name, 32), // 0
+ BotRandomOpponentName(bs), // 1
+ BotFirstClientInRankings(), // 2
+ BotLastClientInRankings(), // 3
+ BotMapTitle(), // 4
+ NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "level_end_lose");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "level_end_lose",
+ EasyClientName(bs->client, name, 32), // 0
+ BotRandomOpponentName(bs), // 1
+ BotFirstClientInRankings(), // 2
+ BotLastClientInRankings(), // 3
+ BotMapTitle(), // 4
+ NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "level_end");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "level_end",
+ EasyClientName(bs->client, name, 32), // 0
+ BotRandomOpponentName(bs), // 1
+ BotFirstClientInRankings(), // 2
+ BotLastClientInRankings(), // 3
+ BotMapTitle(), // 4
+ NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ EasyClientName(bs->lastkilledby, name, sizeof(name));
+ num = trap_BotNumInitialChats(bs->cs, "death_drown");
+ for (i = 0; i < num; i++)
+ {
+ //
+ BotAI_BotInitialChat(bs, "death_drown", name, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "death_slime");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "death_slime", name, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "death_lava");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "death_lava", name, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "death_cratered");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "death_cratered", name, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "death_suicide");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "death_suicide", name, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "death_telefrag");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "death_telefrag", name, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "death_gauntlet");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "death_gauntlet",
+ name, // 0
+ BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
+ NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "death_rail");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "death_rail",
+ name, // 0
+ BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
+ NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "death_bfg");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "death_bfg",
+ name, // 0
+ BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
+ NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "death_insult");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "death_insult",
+ name, // 0
+ BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
+ NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "death_praise");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "death_praise",
+ name, // 0
+ BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
+ NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ //
+ EasyClientName(bs->lastkilledplayer, name, 32);
+ //
+ num = trap_BotNumInitialChats(bs->cs, "kill_gauntlet");
+ for (i = 0; i < num; i++)
+ {
+ //
+ BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "kill_rail");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "kill_rail", name, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "kill_telefrag");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "kill_insult");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "kill_insult", name, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "kill_praise");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "kill_praise", name, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "enemy_suicide");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name));
+ weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client);
+ num = trap_BotNumInitialChats(bs->cs, "hit_talking");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "hit_nodeath");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "hit_nokill");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ //
+ if (bs->lastkilledplayer == bs->client) {
+ Q_strncpyz(name, BotRandomOpponentName(bs), sizeof(name));
+ }
+ else {
+ EasyClientName(bs->lastkilledplayer, name, sizeof(name));
+ }
+ //
+ num = trap_BotNumInitialChats(bs->cs, "random_misc");
+ for (i = 0; i < num; i++)
+ {
+ //
+ BotAI_BotInitialChat(bs, "random_misc",
+ BotRandomOpponentName(bs), // 0
+ name, // 1
+ "[invalid var]", // 2
+ "[invalid var]", // 3
+ BotMapTitle(), // 4
+ BotRandomWeaponName(), // 5
+ NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+ num = trap_BotNumInitialChats(bs->cs, "random_insult");
+ for (i = 0; i < num; i++)
+ {
+ BotAI_BotInitialChat(bs, "random_insult",
+ BotRandomOpponentName(bs), // 0
+ name, // 1
+ "[invalid var]", // 2
+ "[invalid var]", // 3
+ BotMapTitle(), // 4
+ BotRandomWeaponName(), // 5
+ NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
+ }
+}
diff --git a/engine/code/game/ai_chat.h b/code/game/ai_chat.h
similarity index 100%
rename from engine/code/game/ai_chat.h
rename to code/game/ai_chat.h
diff --git a/game/code/game/ai_cmd.c b/code/game/ai_cmd.c
similarity index 100%
rename from game/code/game/ai_cmd.c
rename to code/game/ai_cmd.c
diff --git a/engine/code/game/ai_cmd.h b/code/game/ai_cmd.h
similarity index 100%
rename from engine/code/game/ai_cmd.h
rename to code/game/ai_cmd.h
diff --git a/code/game/ai_dmnet.c b/code/game/ai_dmnet.c
new file mode 100644
index 0000000..3ce2b65
--- /dev/null
+++ b/code/game/ai_dmnet.c
@@ -0,0 +1,2698 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+/*****************************************************************************
+ * name: ai_dmnet.c
+ *
+ * desc: Quake3 bot AI
+ *
+ * $Archive: /MissionPack/code/game/ai_dmnet.c $
+ *
+ *****************************************************************************/
+
+#include "g_local.h"
+#include "../botlib/botlib.h"
+#include "../botlib/be_aas.h"
+#include "../botlib/be_ea.h"
+#include "../botlib/be_ai_char.h"
+#include "../botlib/be_ai_chat.h"
+#include "../botlib/be_ai_gen.h"
+#include "../botlib/be_ai_goal.h"
+#include "../botlib/be_ai_move.h"
+#include "../botlib/be_ai_weap.h"
+//
+#include "ai_main.h"
+#include "ai_dmq3.h"
+#include "ai_chat.h"
+#include "ai_cmd.h"
+#include "ai_dmnet.h"
+#include "ai_team.h"
+//data file headers
+#include "chars.h" //characteristics
+#include "inv.h" //indexes into the inventory
+#include "syn.h" //synonyms
+#include "match.h" //string matching types and vars
+
+// for the voice chats
+#include "../../ui/menudef.h"
+
+//goal flag, see ../botlib/be_ai_goal.h for the other GFL_*
+#define GFL_AIR 128
+
+int numnodeswitches;
+char nodeswitch[MAX_NODESWITCHES+1][144];
+
+#define LOOKAHEAD_DISTANCE 300
+
+extern bot_goal_t dom_points_bot[MAX_DOMINATION_POINTS];
+
+/*
+==================
+BotResetNodeSwitches
+==================
+*/
+void BotResetNodeSwitches(void) {
+ numnodeswitches = 0;
+}
+
+/*
+==================
+BotDumpNodeSwitches
+==================
+*/
+void BotDumpNodeSwitches(bot_state_t *bs) {
+ int i;
+ char netname[MAX_NETNAME];
+
+ ClientName(bs->client, netname, sizeof(netname));
+ BotAI_Print(PRT_MESSAGE, "%s at %1.1f switched more than %d AI nodes\n", netname, FloatTime(), MAX_NODESWITCHES);
+ for (i = 0; i < numnodeswitches; i++) {
+ BotAI_Print(PRT_MESSAGE, "%s", nodeswitch[i]);
+ }
+ BotAI_Print(PRT_FATAL, "");
+}
+
+/*
+==================
+BotRecordNodeSwitch
+==================
+*/
+void BotRecordNodeSwitch(bot_state_t *bs, char *node, char *str, char *s) {
+ char netname[MAX_NETNAME];
+
+ ClientName(bs->client, netname, sizeof(netname));
+ Com_sprintf(nodeswitch[numnodeswitches], 144, "%s at %2.1f entered %s: %s from %s\n", netname, FloatTime(), node, str, s);
+#ifdef DEBUG
+ if (0) {
+ BotAI_Print(PRT_MESSAGE, "%s", nodeswitch[numnodeswitches]);
+ }
+#endif //DEBUG
+ numnodeswitches++;
+}
+
+/*
+==================
+BotGetAirGoal
+==================
+*/
+int BotGetAirGoal(bot_state_t *bs, bot_goal_t *goal) {
+ bsp_trace_t bsptrace;
+ vec3_t end, mins = {-15, -15, -2}, maxs = {15, 15, 2};
+ int areanum;
+
+ //trace up until we hit solid
+ VectorCopy(bs->origin, end);
+ end[2] += 1000;
+ BotAI_Trace(&bsptrace, bs->origin, mins, maxs, end, bs->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
+ //trace down until we hit water
+ VectorCopy(bsptrace.endpos, end);
+ BotAI_Trace(&bsptrace, end, mins, maxs, bs->origin, bs->entitynum, CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA);
+ //if we found the water surface
+ if (bsptrace.fraction > 0) {
+ areanum = BotPointAreaNum(bsptrace.endpos);
+ if (areanum) {
+ VectorCopy(bsptrace.endpos, goal->origin);
+ goal->origin[2] -= 2;
+ goal->areanum = areanum;
+ goal->mins[0] = -15;
+ goal->mins[1] = -15;
+ goal->mins[2] = -1;
+ goal->maxs[0] = 15;
+ goal->maxs[1] = 15;
+ goal->maxs[2] = 1;
+ goal->flags = GFL_AIR;
+ goal->number = 0;
+ goal->iteminfo = 0;
+ goal->entitynum = 0;
+ return qtrue;
+ }
+ }
+ return qfalse;
+}
+
+/*
+==================
+BotGoForAir
+==================
+*/
+int BotGoForAir(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) {
+ bot_goal_t goal;
+
+ //if the bot needs air
+ if (bs->lastair_time < FloatTime() - 6) {
+ //
+#ifdef DEBUG
+ //BotAI_Print(PRT_MESSAGE, "going for air\n");
+#endif //DEBUG
+ //if we can find an air goal
+ if (BotGetAirGoal(bs, &goal)) {
+ trap_BotPushGoal(bs->gs, &goal);
+ return qtrue;
+ }
+ else {
+ //get a nearby goal outside the water
+ while(trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range)) {
+ trap_BotGetTopGoal(bs->gs, &goal);
+ //if the goal is not in water
+ if (!(trap_AAS_PointContents(goal.origin) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))) {
+ return qtrue;
+ }
+ trap_BotPopGoal(bs->gs);
+ }
+ trap_BotResetAvoidGoals(bs->gs);
+ }
+ }
+ return qfalse;
+}
+
+/*
+==================
+BotNearbyGoal
+==================
+*/
+int BotNearbyGoal(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) {
+ int ret;
+
+ //check if the bot should go for air
+ if (BotGoForAir(bs, tfl, ltg, range)) return qtrue;
+ // if the bot is carrying a flag or cubes
+ if (BotCTFCarryingFlag(bs)
+#ifdef MISSIONPACK
+ || Bot1FCTFCarryingFlag(bs) || BotHarvesterCarryingCubes(bs)
+#endif
+ ) {
+ //if the bot is just a few secs away from the base
+ if (trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin,
+ bs->teamgoal.areanum, TFL_DEFAULT) < 300) {
+ //make the range really small
+ range = 50;
+ }
+ }
+ //
+ ret = trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range);
+ /*
+ if (ret)
+ {
+ char buf[128];
+ //get the goal at the top of the stack
+ trap_BotGetTopGoal(bs->gs, &goal);
+ trap_BotGoalName(goal.number, buf, sizeof(buf));
+ BotAI_Print(PRT_MESSAGE, "%1.1f: new nearby goal %s\n", FloatTime(), buf);
+ }
+ */
+ return ret;
+}
+
+/*
+==================
+BotReachedGoal
+==================
+*/
+int BotReachedGoal(bot_state_t *bs, bot_goal_t *goal) {
+ if (goal->flags & GFL_ITEM) {
+ //if touching the goal
+ if (trap_BotTouchingGoal(bs->origin, goal)) {
+ if (!(goal->flags & GFL_DROPPED)) {
+ trap_BotSetAvoidGoalTime(bs->gs, goal->number, -1);
+ }
+ return qtrue;
+ }
+ //if the goal isn't there
+ if (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) {
+ /*
+ float avoidtime;
+ int t;
+
+ avoidtime = trap_BotAvoidGoalTime(bs->gs, goal->number);
+ if (avoidtime > 0) {
+ t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, goal->areanum, bs->tfl);
+ if ((float) t * 0.009 < avoidtime)
+ return qtrue;
+ }
+ */
+ return qtrue;
+ }
+ //if in the goal area and below or above the goal and not swimming
+ if (bs->areanum == goal->areanum) {
+ if (bs->origin[0] > goal->origin[0] + goal->mins[0] && bs->origin[0] < goal->origin[0] + goal->maxs[0]) {
+ if (bs->origin[1] > goal->origin[1] + goal->mins[1] && bs->origin[1] < goal->origin[1] + goal->maxs[1]) {
+ if (!trap_AAS_Swimming(bs->origin)) {
+ return qtrue;
+ }
+ }
+ }
+ }
+ }
+ else if (goal->flags & GFL_AIR) {
+ //if touching the goal
+ if (trap_BotTouchingGoal(bs->origin, goal)) return qtrue;
+ //if the bot got air
+ if (bs->lastair_time > FloatTime() - 1) return qtrue;
+ }
+ else {
+ //if touching the goal
+ if (trap_BotTouchingGoal(bs->origin, goal)) return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+BotGetItemLongTermGoal
+==================
+*/
+int BotGetItemLongTermGoal(bot_state_t *bs, int tfl, bot_goal_t *goal) {
+ //if the bot has no goal
+ if (!trap_BotGetTopGoal(bs->gs, goal)) {
+ //BotAI_Print(PRT_MESSAGE, "no ltg on stack\n");
+ bs->ltg_time = 0;
+ }
+ //if the bot touches the current goal
+ else if (BotReachedGoal(bs, goal)) {
+ BotChooseWeapon(bs);
+ bs->ltg_time = 0;
+ }
+ //if it is time to find a new long term goal
+ if (bs->ltg_time < FloatTime()) {
+ //pop the current goal from the stack
+ trap_BotPopGoal(bs->gs);
+ //BotAI_Print(PRT_MESSAGE, "%s: choosing new ltg\n", ClientName(bs->client, netname, sizeof(netname)));
+ //choose a new goal
+ //BotAI_Print(PRT_MESSAGE, "%6.1f client %d: BotChooseLTGItem\n", FloatTime(), bs->client);
+ if (trap_BotChooseLTGItem(bs->gs, bs->origin, bs->inventory, tfl)) {
+ /*
+ char buf[128];
+ //get the goal at the top of the stack
+ trap_BotGetTopGoal(bs->gs, goal);
+ trap_BotGoalName(goal->number, buf, sizeof(buf));
+ BotAI_Print(PRT_MESSAGE, "%1.1f: new long term goal %s\n", FloatTime(), buf);
+ */
+ bs->ltg_time = FloatTime() + 20;
+ }
+ else {//the bot gets sorta stuck with all the avoid timings, shouldn't happen though
+ //
+#ifdef DEBUG
+ char netname[128];
+
+ BotAI_Print(PRT_MESSAGE, "%s: no valid ltg (probably stuck)\n", ClientName(bs->client, netname, sizeof(netname)));
+#endif
+ //trap_BotDumpAvoidGoals(bs->gs);
+ //reset the avoid goals and the avoid reach
+ trap_BotResetAvoidGoals(bs->gs);
+ trap_BotResetAvoidReach(bs->ms);
+ }
+ //get the goal at the top of the stack
+ return trap_BotGetTopGoal(bs->gs, goal);
+ }
+ return qtrue;
+}
+
+/*
+==================
+BotGetLongTermGoal
+
+we could also create a seperate AI node for every long term goal type
+however this saves us a lot of code
+==================
+*/
+int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) {
+ vec3_t target, dir, dir2;
+ char netname[MAX_NETNAME];
+ char buf[MAX_MESSAGE_SIZE];
+ int areanum;
+ float croucher;
+ aas_entityinfo_t entinfo, botinfo;
+ bot_waypoint_t *wp;
+
+ if (bs->ltgtype == LTG_TEAMHELP && !retreat) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "help_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
+ trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
+ BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
+ trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
+ bs->teammessage_time = 0;
+ }
+ //if trying to help the team mate for more than a minute
+ if (bs->teamgoal_time < FloatTime())
+ bs->ltgtype = 0;
+ //if the team mate IS visible for quite some time
+ if (bs->teammatevisible_time < FloatTime() - 10) bs->ltgtype = 0;
+ //get entity information of the companion
+ BotEntityInfo(bs->teammate, &entinfo);
+ //if the team mate is visible
+ if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) {
+ //if close just stand still there
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ if (VectorLengthSquared(dir) < Square(100)) {
+ trap_BotResetAvoidReach(bs->ms);
+ return qfalse;
+ }
+ }
+ else {
+ //last time the bot was NOT visible
+ bs->teammatevisible_time = FloatTime();
+ }
+ //if the entity information is valid (entity in PVS)
+ if (entinfo.valid) {
+ areanum = BotPointAreaNum(entinfo.origin);
+ if (areanum && trap_AAS_AreaReachability(areanum)) {
+ //update team goal
+ bs->teamgoal.entitynum = bs->teammate;
+ bs->teamgoal.areanum = areanum;
+ VectorCopy(entinfo.origin, bs->teamgoal.origin);
+ VectorSet(bs->teamgoal.mins, -8, -8, -8);
+ VectorSet(bs->teamgoal.maxs, 8, 8, 8);
+ }
+ }
+ memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
+ return qtrue;
+ }
+ //if the bot accompanies someone
+ if (bs->ltgtype == LTG_TEAMACCOMPANY && !retreat) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "accompany_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
+ trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
+ BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
+ trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
+ bs->teammessage_time = 0;
+ }
+ //if accompanying the companion for 3 minutes
+ if (bs->teamgoal_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "accompany_stop", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
+ trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
+ bs->ltgtype = 0;
+ }
+ //get entity information of the companion
+ BotEntityInfo(bs->teammate, &entinfo);
+ //if the companion is visible
+ if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) {
+ //update visible time
+ bs->teammatevisible_time = FloatTime();
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ if (VectorLengthSquared(dir) < Square(bs->formation_dist)) {
+ //
+ // if the client being followed bumps into this bot then
+ // the bot should back up
+ BotEntityInfo(bs->entitynum, &botinfo);
+ // if the followed client is not standing ontop of the bot
+ if (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2]) {
+ // if the bounding boxes touch each other
+ if (botinfo.origin[0] + botinfo.maxs[0] > entinfo.origin[0] + entinfo.mins[0] - 4&&
+ botinfo.origin[0] + botinfo.mins[0] < entinfo.origin[0] + entinfo.maxs[0] + 4) {
+ if (botinfo.origin[1] + botinfo.maxs[1] > entinfo.origin[1] + entinfo.mins[1] - 4 &&
+ botinfo.origin[1] + botinfo.mins[1] < entinfo.origin[1] + entinfo.maxs[1] + 4) {
+ if (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2] - 4 &&
+ botinfo.origin[2] + botinfo.mins[2] < entinfo.origin[2] + entinfo.maxs[2] + 4) {
+ // if the followed client looks in the direction of this bot
+ AngleVectors(entinfo.angles, dir, NULL, NULL);
+ dir[2] = 0;
+ VectorNormalize(dir);
+ //VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir);
+ VectorSubtract(bs->origin, entinfo.origin, dir2);
+ VectorNormalize(dir2);
+ if (DotProduct(dir, dir2) > 0.7) {
+ // back up
+ BotSetupForMovement(bs);
+ trap_BotMoveInDirection(bs->ms, dir2, 400, MOVE_WALK);
+ }
+ }
+ }
+ }
+ }
+ //check if the bot wants to crouch
+ //don't crouch if crouched less than 5 seconds ago
+ if (bs->attackcrouch_time < FloatTime() - 5) {
+ croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);
+ if (random() < bs->thinktime * croucher) {
+ bs->attackcrouch_time = FloatTime() + 5 + croucher * 15;
+ }
+ }
+ //don't crouch when swimming
+ if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1;
+ //if not arrived yet or arived some time ago
+ if (bs->arrive_time < FloatTime() - 2) {
+ //if not arrived yet
+ if (!bs->arrive_time) {
+ trap_EA_Gesture(bs->client);
+ BotAI_BotInitialChat(bs, "accompany_arrive", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
+ trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
+ bs->arrive_time = FloatTime();
+ }
+ //if the bot wants to crouch
+ else if (bs->attackcrouch_time > FloatTime()) {
+ trap_EA_Crouch(bs->client);
+ }
+ //else do some model taunts
+ else if (random() < bs->thinktime * 0.05) {
+ //do a gesture :)
+ trap_EA_Gesture(bs->client);
+ }
+ }
+ //if just arrived look at the companion
+ if (bs->arrive_time > FloatTime() - 2) {
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ bs->ideal_viewangles[2] *= 0.5;
+ }
+ //else look strategically around for enemies
+ else if (random() < bs->thinktime * 0.8) {
+ BotRoamGoal(bs, target);
+ VectorSubtract(target, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ bs->ideal_viewangles[2] *= 0.5;
+ }
+ //check if the bot wants to go for air
+ if (BotGoForAir(bs, bs->tfl, &bs->teamgoal, 400)) {
+ trap_BotResetLastAvoidReach(bs->ms);
+ //get the goal at the top of the stack
+ //trap_BotGetTopGoal(bs->gs, &tmpgoal);
+ //trap_BotGoalName(tmpgoal.number, buf, 144);
+ //BotAI_Print(PRT_MESSAGE, "new nearby goal %s\n", buf);
+ //time the bot gets to pick up the nearby goal item
+ bs->nbg_time = FloatTime() + 8;
+ AIEnter_Seek_NBG(bs, "BotLongTermGoal: go for air");
+ return qfalse;
+ }
+ //
+ trap_BotResetAvoidReach(bs->ms);
+ return qfalse;
+ }
+ }
+ //if the entity information is valid (entity in PVS)
+ if (entinfo.valid) {
+ areanum = BotPointAreaNum(entinfo.origin);
+ if (areanum && trap_AAS_AreaReachability(areanum)) {
+ //update team goal
+ bs->teamgoal.entitynum = bs->teammate;
+ bs->teamgoal.areanum = areanum;
+ VectorCopy(entinfo.origin, bs->teamgoal.origin);
+ VectorSet(bs->teamgoal.mins, -8, -8, -8);
+ VectorSet(bs->teamgoal.maxs, 8, 8, 8);
+ }
+ }
+ //the goal the bot should go for
+ memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
+ //if the companion is NOT visible for too long
+ if (bs->teammatevisible_time < FloatTime() - 60) {
+ BotAI_BotInitialChat(bs, "accompany_cannotfind", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
+ trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
+ bs->ltgtype = 0;
+ // just to make sure the bot won't spam this message
+ bs->teammatevisible_time = FloatTime();
+ }
+ return qtrue;
+ }
+ //
+ if (bs->ltgtype == LTG_DEFENDKEYAREA) {
+ if (trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin,
+ bs->teamgoal.areanum, TFL_DEFAULT) > bs->defendaway_range) {
+ bs->defendaway_time = 0;
+ }
+ }
+ //For double domination
+ if (bs->ltgtype == LTG_POINTA &&
+ bs->defendaway_time < FloatTime()) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
+ BotAI_BotInitialChat(bs, "dd_start_pointa", buf, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ //BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE);
+ bs->teammessage_time = 0;
+ }
+ //set the bot goal
+ memcpy(goal, &ctf_redflag, sizeof(bot_goal_t));
+ //if very close... go away for some time
+ VectorSubtract(goal->origin, bs->origin, dir);
+ if (VectorLengthSquared(dir) < Square(70)) {
+ trap_BotResetAvoidReach(bs->ms);
+ bs->defendaway_time = FloatTime() + 3 + 3 * random();
+ if (BotHasPersistantPowerupAndWeapon(bs)) {
+ bs->defendaway_range = 100;
+ }
+ else {
+ bs->defendaway_range = 350;
+ }
+ }
+ return qtrue;
+ }
+ if (bs->ltgtype == LTG_POINTB &&
+ bs->defendaway_time < FloatTime()) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
+ BotAI_BotInitialChat(bs, "dd_start_pointb", buf, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ //BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE);
+ bs->teammessage_time = 0;
+ }
+ //set the bot goal
+ memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t));
+ //if very close... go away for some time
+ VectorSubtract(goal->origin, bs->origin, dir);
+ if (VectorLengthSquared(dir) < Square(70)) {
+ trap_BotResetAvoidReach(bs->ms);
+ bs->defendaway_time = FloatTime() + 3 + 3 * random();
+ if (BotHasPersistantPowerupAndWeapon(bs)) {
+ bs->defendaway_range = 100;
+ }
+ else {
+ bs->defendaway_range = 350;
+ }
+ }
+ return qtrue;
+ }
+ //if (bs->ltgtype == LTG_DOMHOLD &&
+ // bs->defendaway_time < FloatTime()) {
+ //check for bot typing status message
+ /*if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
+ BotAI_BotInitialChat(bs, "dd_start_pointb", buf, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ //BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE);
+ bs->teammessage_time = 0;
+ }*/
+ //set the bot goal
+ // memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
+ //if very close... go away for some time
+ // VectorSubtract(goal->origin, bs->origin, dir);
+ // if (VectorLengthSquared(dir) < Square(30)) {
+ /*trap_BotResetAvoidReach(bs->ms);
+ bs->defendaway_time = FloatTime() + 3 + 3 * random();
+ if (BotHasPersistantPowerupAndWeapon(bs)) {
+ bs->defendaway_range = 100;
+ }
+ else {
+ bs->defendaway_range = 350;
+ }*/
+ // memcpy(&bs->teamgoal, &dom_points_bot[((rand()) % (level.domination_points_count))], sizeof(bot_goal_t));
+ // BotAlternateRoute(bs, &bs->teamgoal);
+ // BotSetTeamStatus(bs);
+
+ //}
+ //return qtrue;
+
+ // }
+ //if defending a key area
+ if (bs->ltgtype == LTG_DEFENDKEYAREA && !retreat &&
+ bs->defendaway_time < FloatTime()) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
+ BotAI_BotInitialChat(bs, "defend_start", buf, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE);
+ bs->teammessage_time = 0;
+ }
+ //set the bot goal
+ memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
+ //stop after 2 minutes
+ if (bs->teamgoal_time < FloatTime()) {
+ trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
+ BotAI_BotInitialChat(bs, "defend_stop", buf, NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ bs->ltgtype = 0;
+ }
+ //if very close... go away for some time
+ VectorSubtract(goal->origin, bs->origin, dir);
+ if (VectorLengthSquared(dir) < Square(70)) {
+ trap_BotResetAvoidReach(bs->ms);
+ bs->defendaway_time = FloatTime() + 3 + 3 * random();
+ if (BotHasPersistantPowerupAndWeapon(bs)) {
+ bs->defendaway_range = 100;
+ }
+ else {
+ bs->defendaway_range = 350;
+ }
+ }
+ return qtrue;
+ }
+ //going to kill someone
+ if (bs->ltgtype == LTG_KILL && !retreat) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf));
+ BotAI_BotInitialChat(bs, "kill_start", buf, NULL);
+ trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
+ bs->teammessage_time = 0;
+ }
+ //
+ if (bs->lastkilledplayer == bs->teamgoal.entitynum) {
+ EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf));
+ BotAI_BotInitialChat(bs, "kill_done", buf, NULL);
+ trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
+ bs->lastkilledplayer = -1;
+ bs->ltgtype = 0;
+ }
+ //
+ if (bs->teamgoal_time < FloatTime()) {
+ bs->ltgtype = 0;
+ }
+ //just roam around
+ return BotGetItemLongTermGoal(bs, tfl, goal);
+ }
+ //get an item
+ if (bs->ltgtype == LTG_GETITEM && !retreat) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
+ BotAI_BotInitialChat(bs, "getitem_start", buf, NULL);
+ trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
+ BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
+ trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
+ bs->teammessage_time = 0;
+ }
+ //set the bot goal
+ memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
+ //stop after some time
+ if (bs->teamgoal_time < FloatTime()) {
+ bs->ltgtype = 0;
+ }
+ //
+ if (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) {
+ trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
+ BotAI_BotInitialChat(bs, "getitem_notthere", buf, NULL);
+ trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
+ bs->ltgtype = 0;
+ }
+ else if (BotReachedGoal(bs, goal)) {
+ trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
+ BotAI_BotInitialChat(bs, "getitem_gotit", buf, NULL);
+ trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
+ bs->ltgtype = 0;
+ }
+ return qtrue;
+ }
+ //if camping somewhere
+ if ((bs->ltgtype == LTG_CAMP || bs->ltgtype == LTG_CAMPORDER) && !retreat) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ if (bs->ltgtype == LTG_CAMPORDER) {
+ BotAI_BotInitialChat(bs, "camp_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
+ trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
+ BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
+ trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
+ }
+ bs->teammessage_time = 0;
+ }
+ //set the bot goal
+ memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
+ //
+ if (bs->teamgoal_time < FloatTime()) {
+ if (bs->ltgtype == LTG_CAMPORDER) {
+ BotAI_BotInitialChat(bs, "camp_stop", NULL);
+ trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
+ }
+ bs->ltgtype = 0;
+ }
+ //if really near the camp spot
+ VectorSubtract(goal->origin, bs->origin, dir);
+ if (VectorLengthSquared(dir) < Square(60))
+ {
+ //if not arrived yet
+ if (!bs->arrive_time) {
+ if (bs->ltgtype == LTG_CAMPORDER) {
+ BotAI_BotInitialChat(bs, "camp_arrive", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
+ trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
+ BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_INPOSITION);
+ }
+ bs->arrive_time = FloatTime();
+ }
+ //look strategically around for enemies
+ if (random() < bs->thinktime * 0.8) {
+ BotRoamGoal(bs, target);
+ VectorSubtract(target, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ bs->ideal_viewangles[2] *= 0.5;
+ }
+ //check if the bot wants to crouch
+ //don't crouch if crouched less than 5 seconds ago
+ if (bs->attackcrouch_time < FloatTime() - 5) {
+ croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);
+ if (random() < bs->thinktime * croucher) {
+ bs->attackcrouch_time = FloatTime() + 5 + croucher * 15;
+ }
+ }
+ //if the bot wants to crouch
+ if (bs->attackcrouch_time > FloatTime()) {
+ trap_EA_Crouch(bs->client);
+ }
+ //don't crouch when swimming
+ if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1;
+ //make sure the bot is not gonna drown
+ if (trap_PointContents(bs->eye,bs->entitynum) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) {
+ if (bs->ltgtype == LTG_CAMPORDER) {
+ BotAI_BotInitialChat(bs, "camp_stop", NULL);
+ trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
+ //
+ if (bs->lastgoal_ltgtype == LTG_CAMPORDER) {
+ bs->lastgoal_ltgtype = 0;
+ }
+ }
+ bs->ltgtype = 0;
+ }
+ //
+ if (bs->camp_range > 0) {
+ //FIXME: move around a bit
+ }
+ //
+ trap_BotResetAvoidReach(bs->ms);
+ return qfalse;
+ }
+ return qtrue;
+ }
+ //patrolling along several waypoints
+ if (bs->ltgtype == LTG_PATROL && !retreat) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ strcpy(buf, "");
+ for (wp = bs->patrolpoints; wp; wp = wp->next) {
+ strcat(buf, wp->name);
+ if (wp->next) strcat(buf, " to ");
+ }
+ BotAI_BotInitialChat(bs, "patrol_start", buf, NULL);
+ trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
+ BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
+ trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
+ bs->teammessage_time = 0;
+ }
+ //
+ if (!bs->curpatrolpoint) {
+ bs->ltgtype = 0;
+ return qfalse;
+ }
+ //if the bot touches the current goal
+ if (trap_BotTouchingGoal(bs->origin, &bs->curpatrolpoint->goal)) {
+ if (bs->patrolflags & PATROL_BACK) {
+ if (bs->curpatrolpoint->prev) {
+ bs->curpatrolpoint = bs->curpatrolpoint->prev;
+ }
+ else {
+ bs->curpatrolpoint = bs->curpatrolpoint->next;
+ bs->patrolflags &= ~PATROL_BACK;
+ }
+ }
+ else {
+ if (bs->curpatrolpoint->next) {
+ bs->curpatrolpoint = bs->curpatrolpoint->next;
+ }
+ else {
+ bs->curpatrolpoint = bs->curpatrolpoint->prev;
+ bs->patrolflags |= PATROL_BACK;
+ }
+ }
+ }
+ //stop after 5 minutes
+ if (bs->teamgoal_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "patrol_stop", NULL);
+ trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
+ bs->ltgtype = 0;
+ }
+ if (!bs->curpatrolpoint) {
+ bs->ltgtype = 0;
+ return qfalse;
+ }
+ memcpy(goal, &bs->curpatrolpoint->goal, sizeof(bot_goal_t));
+ return qtrue;
+ }
+#ifdef CTF
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ //if going for enemy flag
+ if (bs->ltgtype == LTG_GETFLAG) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "captureflag_start", NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ BotVoiceChatOnly(bs, -1, VOICECHAT_ONGETFLAG);
+ bs->teammessage_time = 0;
+ }
+ //
+ switch(BotTeam(bs)) {
+ case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
+ case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
+ default: bs->ltgtype = 0; return qfalse;
+ }
+ //if touching the flag
+ if (trap_BotTouchingGoal(bs->origin, goal)) {
+ // make sure the bot knows the flag isn't there anymore
+ switch(BotTeam(bs)) {
+ case TEAM_RED: bs->blueflagstatus = 1; break;
+ case TEAM_BLUE: bs->redflagstatus = 1; break;
+ }
+ bs->ltgtype = 0;
+ }
+ //stop after 3 minutes
+ if (bs->teamgoal_time < FloatTime()) {
+ bs->ltgtype = 0;
+ }
+ BotAlternateRoute(bs, goal);
+ return qtrue;
+ }
+ //if rushing to the base
+ if (bs->ltgtype == LTG_RUSHBASE && bs->rushbaseaway_time < FloatTime()) {
+ switch(BotTeam(bs)) {
+ case TEAM_RED: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
+ case TEAM_BLUE: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
+ default: bs->ltgtype = 0; return qfalse;
+ }
+ //if not carrying the flag anymore
+ if (!BotCTFCarryingFlag(bs)) bs->ltgtype = 0;
+ //quit rushing after 2 minutes
+ if (bs->teamgoal_time < FloatTime()) bs->ltgtype = 0;
+ //if touching the base flag the bot should loose the enemy flag
+ if (trap_BotTouchingGoal(bs->origin, goal)) {
+ //if the bot is still carrying the enemy flag then the
+ //base flag is gone, now just walk near the base a bit
+ if (BotCTFCarryingFlag(bs)) {
+ trap_BotResetAvoidReach(bs->ms);
+ bs->rushbaseaway_time = FloatTime() + 5 + 10 * random();
+ //FIXME: add chat to tell the others to get back the flag
+ }
+ else {
+ bs->ltgtype = 0;
+ }
+ }
+ BotAlternateRoute(bs, goal);
+ return qtrue;
+ }
+ //returning flag
+ if (bs->ltgtype == LTG_RETURNFLAG) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "returnflag_start", NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ BotVoiceChatOnly(bs, -1, VOICECHAT_ONRETURNFLAG);
+ bs->teammessage_time = 0;
+ }
+ //
+ switch(BotTeam(bs)) {
+ case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
+ case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
+ default: bs->ltgtype = 0; return qfalse;
+ }
+ //if touching the flag
+ if (trap_BotTouchingGoal(bs->origin, goal)) bs->ltgtype = 0;
+ //stop after 3 minutes
+ if (bs->teamgoal_time < FloatTime()) {
+ bs->ltgtype = 0;
+ }
+ BotAlternateRoute(bs, goal);
+ return qtrue;
+ }
+ }
+#endif //CTF
+ else if (gametype == GT_1FCTF) {
+ if (bs->ltgtype == LTG_GETFLAG) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "captureflag_start", NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ BotVoiceChatOnly(bs, -1, VOICECHAT_ONGETFLAG);
+ bs->teammessage_time = 0;
+ }
+ memcpy(goal, &ctf_neutralflag, sizeof(bot_goal_t));
+ //if touching the flag
+ if (trap_BotTouchingGoal(bs->origin, goal)) {
+ bs->ltgtype = 0;
+ }
+ //stop after 3 minutes
+ if (bs->teamgoal_time < FloatTime()) {
+ bs->ltgtype = 0;
+ }
+ return qtrue;
+ }
+ //if rushing to the base
+ if (bs->ltgtype == LTG_RUSHBASE) {
+ switch(BotTeam(bs)) {
+ case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
+ case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
+ default: bs->ltgtype = 0; return qfalse;
+ }
+ //if not carrying the flag anymore
+ if (!Bot1FCTFCarryingFlag(bs)) {
+ bs->ltgtype = 0;
+ }
+ //quit rushing after 2 minutes
+ if (bs->teamgoal_time < FloatTime()) {
+ bs->ltgtype = 0;
+ }
+ //if touching the base flag the bot should loose the enemy flag
+ if (trap_BotTouchingGoal(bs->origin, goal)) {
+ bs->ltgtype = 0;
+ }
+ BotAlternateRoute(bs, goal);
+ return qtrue;
+ }
+ //attack the enemy base
+ if (bs->ltgtype == LTG_ATTACKENEMYBASE &&
+ bs->attackaway_time < FloatTime()) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "attackenemybase_start", NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
+ bs->teammessage_time = 0;
+ }
+ switch(BotTeam(bs)) {
+ case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
+ case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
+ default: bs->ltgtype = 0; return qfalse;
+ }
+ //quit rushing after 2 minutes
+ if (bs->teamgoal_time < FloatTime()) {
+ bs->ltgtype = 0;
+ }
+ //if touching the base flag the bot should loose the enemy flag
+ if (trap_BotTouchingGoal(bs->origin, goal)) {
+ bs->attackaway_time = FloatTime() + 2 + 5 * random();
+ }
+ return qtrue;
+ }
+ //returning flag
+ if (bs->ltgtype == LTG_RETURNFLAG) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "returnflag_start", NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ BotVoiceChatOnly(bs, -1, VOICECHAT_ONRETURNFLAG);
+ bs->teammessage_time = 0;
+ }
+ //
+ if (bs->teamgoal_time < FloatTime()) {
+ bs->ltgtype = 0;
+ }
+ //just roam around
+ return BotGetItemLongTermGoal(bs, tfl, goal);
+ }
+ }
+ else if (gametype == GT_OBELISK) {
+ if (bs->ltgtype == LTG_ATTACKENEMYBASE &&
+ bs->attackaway_time < FloatTime()) {
+
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "attackenemybase_start", NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
+ bs->teammessage_time = 0;
+ }
+ switch(BotTeam(bs)) {
+ case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break;
+ case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break;
+ default: bs->ltgtype = 0; return qfalse;
+ }
+ //if the bot no longer wants to attack the obelisk
+ if (BotFeelingBad(bs) > 50) {
+ return BotGetItemLongTermGoal(bs, tfl, goal);
+ }
+ //if touching the obelisk
+ if (trap_BotTouchingGoal(bs->origin, goal)) {
+ bs->attackaway_time = FloatTime() + 3 + 5 * random();
+ }
+ // or very close to the obelisk
+ VectorSubtract(bs->origin, goal->origin, dir);
+ if (VectorLengthSquared(dir) < Square(60)) {
+ bs->attackaway_time = FloatTime() + 3 + 5 * random();
+ }
+ //quit rushing after 2 minutes
+ if (bs->teamgoal_time < FloatTime()) {
+ bs->ltgtype = 0;
+ }
+ BotAlternateRoute(bs, goal);
+ //just move towards the obelisk
+ return qtrue;
+ }
+ }
+ else if (gametype == GT_HARVESTER) {
+ //if rushing to the base
+ if (bs->ltgtype == LTG_RUSHBASE) {
+ switch(BotTeam(bs)) {
+ case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break;
+ case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break;
+ default: BotGoHarvest(bs); return qfalse;
+ }
+ //if not carrying any cubes
+ if (!BotHarvesterCarryingCubes(bs)) {
+ BotGoHarvest(bs);
+ return qfalse;
+ }
+ //quit rushing after 2 minutes
+ if (bs->teamgoal_time < FloatTime()) {
+ BotGoHarvest(bs);
+ return qfalse;
+ }
+ //if touching the base flag the bot should loose the enemy flag
+ if (trap_BotTouchingGoal(bs->origin, goal)) {
+ BotGoHarvest(bs);
+ return qfalse;
+ }
+ BotAlternateRoute(bs, goal);
+ return qtrue;
+ }
+ //attack the enemy base
+ if (bs->ltgtype == LTG_ATTACKENEMYBASE &&
+ bs->attackaway_time < FloatTime()) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "attackenemybase_start", NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
+ bs->teammessage_time = 0;
+ }
+ switch(BotTeam(bs)) {
+ case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break;
+ case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break;
+ default: bs->ltgtype = 0; return qfalse;
+ }
+ //quit rushing after 2 minutes
+ if (bs->teamgoal_time < FloatTime()) {
+ bs->ltgtype = 0;
+ }
+ //if touching the base flag the bot should loose the enemy flag
+ if (trap_BotTouchingGoal(bs->origin, goal)) {
+ bs->attackaway_time = FloatTime() + 2 + 5 * random();
+ }
+ return qtrue;
+ }
+ //harvest cubes
+ if (bs->ltgtype == LTG_HARVEST &&
+ bs->harvestaway_time < FloatTime()) {
+ //check for bot typing status message
+ if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "harvest_start", NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
+ bs->teammessage_time = 0;
+ }
+ memcpy(goal, &neutralobelisk, sizeof(bot_goal_t));
+ //
+ if (bs->teamgoal_time < FloatTime()) {
+ bs->ltgtype = 0;
+ }
+ //
+ if (trap_BotTouchingGoal(bs->origin, goal)) {
+ bs->harvestaway_time = FloatTime() + 4 + 3 * random();
+ }
+ return qtrue;
+ }
+ }
+//#endif
+ //normal goal stuff
+ return BotGetItemLongTermGoal(bs, tfl, goal);
+}
+
+/*
+==================
+BotLongTermGoal
+==================
+*/
+int BotLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) {
+ aas_entityinfo_t entinfo;
+ char teammate[MAX_MESSAGE_SIZE];
+ float squaredist;
+ int areanum;
+ vec3_t dir;
+
+ //FIXME: also have air long term goals?
+ //
+ //if the bot is leading someone and not retreating
+ if (bs->lead_time > 0 && !retreat) {
+ if (bs->lead_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "lead_stop", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);
+ trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
+ bs->lead_time = 0;
+ return BotGetLongTermGoal(bs, tfl, retreat, goal);
+ }
+ //
+ if (bs->leadmessage_time < 0 && -bs->leadmessage_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);
+ trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
+ bs->leadmessage_time = FloatTime();
+ }
+ //get entity information of the companion
+ BotEntityInfo(bs->lead_teammate, &entinfo);
+ //
+ if (entinfo.valid) {
+ areanum = BotPointAreaNum(entinfo.origin);
+ if (areanum && trap_AAS_AreaReachability(areanum)) {
+ //update team goal
+ bs->lead_teamgoal.entitynum = bs->lead_teammate;
+ bs->lead_teamgoal.areanum = areanum;
+ VectorCopy(entinfo.origin, bs->lead_teamgoal.origin);
+ VectorSet(bs->lead_teamgoal.mins, -8, -8, -8);
+ VectorSet(bs->lead_teamgoal.maxs, 8, 8, 8);
+ }
+ }
+ //if the team mate is visible
+ if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->lead_teammate)) {
+ bs->leadvisible_time = FloatTime();
+ }
+ //if the team mate is not visible for 1 seconds
+ if (bs->leadvisible_time < FloatTime() - 1) {
+ bs->leadbackup_time = FloatTime() + 2;
+ }
+ //distance towards the team mate
+ VectorSubtract(bs->origin, bs->lead_teamgoal.origin, dir);
+ squaredist = VectorLengthSquared(dir);
+ //if backing up towards the team mate
+ if (bs->leadbackup_time > FloatTime()) {
+ if (bs->leadmessage_time < FloatTime() - 20) {
+ BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);
+ trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
+ bs->leadmessage_time = FloatTime();
+ }
+ //if very close to the team mate
+ if (squaredist < Square(100)) {
+ bs->leadbackup_time = 0;
+ }
+ //the bot should go back to the team mate
+ memcpy(goal, &bs->lead_teamgoal, sizeof(bot_goal_t));
+ return qtrue;
+ }
+ else {
+ //if quite distant from the team mate
+ if (squaredist > Square(500)) {
+ if (bs->leadmessage_time < FloatTime() - 20) {
+ BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);
+ trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
+ bs->leadmessage_time = FloatTime();
+ }
+ //look at the team mate
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ bs->ideal_viewangles[2] *= 0.5;
+ //just wait for the team mate
+ return qfalse;
+ }
+ }
+ }
+ return BotGetLongTermGoal(bs, tfl, retreat, goal);
+}
+
+/*
+==================
+AIEnter_Intermission
+==================
+*/
+void AIEnter_Intermission(bot_state_t *bs, char *s) {
+ BotRecordNodeSwitch(bs, "intermission", "", s);
+ //reset the bot state
+ BotResetState(bs);
+ //check for end level chat
+ if (BotChat_EndLevel(bs)) {
+ trap_BotEnterChat(bs->cs, 0, bs->chatto);
+ }
+ bs->ainode = AINode_Intermission;
+}
+
+/*
+==================
+AINode_Intermission
+==================
+*/
+int AINode_Intermission(bot_state_t *bs) {
+ //if the intermission ended
+ if (!BotIntermission(bs)) {
+ if (BotChat_StartLevel(bs)) {
+ bs->stand_time = FloatTime() + BotChatTime(bs);
+ }
+ else {
+ bs->stand_time = FloatTime() + 2;
+ }
+ AIEnter_Stand(bs, "intermission: chat");
+ }
+ return qtrue;
+}
+
+/*
+==================
+AIEnter_Observer
+==================
+*/
+void AIEnter_Observer(bot_state_t *bs, char *s) {
+ BotRecordNodeSwitch(bs, "observer", "", s);
+ //reset the bot state
+ BotResetState(bs);
+ bs->ainode = AINode_Observer;
+}
+
+/*
+==================
+AINode_Observer
+==================
+*/
+int AINode_Observer(bot_state_t *bs) {
+ //if the bot left observer mode
+ if (!BotIsObserver(bs)) {
+ AIEnter_Stand(bs, "observer: left observer");
+ }
+ return qtrue;
+}
+
+/*
+==================
+AIEnter_Stand
+==================
+*/
+void AIEnter_Stand(bot_state_t *bs, char *s) {
+ BotRecordNodeSwitch(bs, "stand", "", s);
+ bs->standfindenemy_time = FloatTime() + 1;
+ bs->ainode = AINode_Stand;
+}
+
+/*
+==================
+AINode_Stand
+==================
+*/
+int AINode_Stand(bot_state_t *bs) {
+
+ //if the bot's health decreased
+ if (bs->lastframe_health > bs->inventory[INVENTORY_HEALTH]) {
+ if (BotChat_HitTalking(bs)) {
+ bs->standfindenemy_time = FloatTime() + BotChatTime(bs) + 0.1;
+ bs->stand_time = FloatTime() + BotChatTime(bs) + 0.1;
+ }
+ }
+ if (bs->standfindenemy_time < FloatTime()) {
+ if (BotFindEnemy(bs, -1)) {
+ AIEnter_Battle_Fight(bs, "stand: found enemy");
+ return qfalse;
+ }
+ bs->standfindenemy_time = FloatTime() + 1;
+ }
+ // put up chat icon
+ trap_EA_Talk(bs->client);
+ // when done standing
+ if (bs->stand_time < FloatTime()) {
+ trap_BotEnterChat(bs->cs, 0, bs->chatto);
+ AIEnter_Seek_LTG(bs, "stand: time out");
+ return qfalse;
+ }
+ //
+ return qtrue;
+}
+
+/*
+==================
+AIEnter_Respawn
+==================
+*/
+void AIEnter_Respawn(bot_state_t *bs, char *s) {
+ BotRecordNodeSwitch(bs, "respawn", "", s);
+ //reset some states
+ trap_BotResetMoveState(bs->ms);
+ trap_BotResetGoalState(bs->gs);
+ trap_BotResetAvoidGoals(bs->gs);
+ trap_BotResetAvoidReach(bs->ms);
+ //if the bot wants to chat
+ if (BotChat_Death(bs)) {
+ bs->respawn_time = FloatTime() + BotChatTime(bs);
+ bs->respawnchat_time = FloatTime();
+ }
+ else {
+ bs->respawn_time = FloatTime() + 1 + random();
+ bs->respawnchat_time = 0;
+ }
+ //set respawn state
+ bs->respawn_wait = qfalse;
+ bs->ainode = AINode_Respawn;
+}
+
+/*
+==================
+AINode_Respawn
+==================
+*/
+int AINode_Respawn(bot_state_t *bs) {
+ // if waiting for the actual respawn
+ if (bs->respawn_wait) {
+ if (!BotIsDead(bs)) {
+ AIEnter_Seek_LTG(bs, "respawn: respawned");
+ }
+ else {
+ trap_EA_Respawn(bs->client);
+ }
+ }
+ else if (bs->respawn_time < FloatTime()) {
+ // wait until respawned
+ bs->respawn_wait = qtrue;
+ // elementary action respawn
+ trap_EA_Respawn(bs->client);
+ //
+ if (bs->respawnchat_time) {
+ trap_BotEnterChat(bs->cs, 0, bs->chatto);
+ bs->enemy = -1;
+ }
+ }
+ if (bs->respawnchat_time && bs->respawnchat_time < FloatTime() - 0.5) {
+ trap_EA_Talk(bs->client);
+ }
+ //
+ return qtrue;
+}
+
+/*
+==================
+BotSelectActivateWeapon
+==================
+*/
+int BotSelectActivateWeapon(bot_state_t *bs) {
+ //
+ if (bs->inventory[INVENTORY_MACHINEGUN] > 0 && bs->inventory[INVENTORY_BULLETS] > 0)
+ return WEAPONINDEX_MACHINEGUN;
+ else if (bs->inventory[INVENTORY_SHOTGUN] > 0 && bs->inventory[INVENTORY_SHELLS] > 0)
+ return WEAPONINDEX_SHOTGUN;
+ else if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0)
+ return WEAPONINDEX_PLASMAGUN;
+ else if (bs->inventory[INVENTORY_LIGHTNING] > 0 && bs->inventory[INVENTORY_LIGHTNINGAMMO] > 0)
+ return WEAPONINDEX_LIGHTNING;
+ else if (bs->inventory[INVENTORY_CHAINGUN] > 0 && bs->inventory[INVENTORY_BELT] > 0)
+ return WEAPONINDEX_CHAINGUN;
+ else if (bs->inventory[INVENTORY_NAILGUN] > 0 && bs->inventory[INVENTORY_NAILS] > 0)
+ return WEAPONINDEX_NAILGUN;
+ else if (bs->inventory[INVENTORY_PROXLAUNCHER] > 0 && bs->inventory[INVENTORY_MINES] > 0)
+ return WEAPONINDEX_PROXLAUNCHER;
+ else if (bs->inventory[INVENTORY_GRENADELAUNCHER] > 0 && bs->inventory[INVENTORY_GRENADES] > 0)
+ return WEAPONINDEX_GRENADE_LAUNCHER;
+ else if (bs->inventory[INVENTORY_RAILGUN] > 0 && bs->inventory[INVENTORY_SLUGS] > 0)
+ return WEAPONINDEX_RAILGUN;
+ else if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0)
+ return WEAPONINDEX_ROCKET_LAUNCHER;
+ else if (bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0)
+ return WEAPONINDEX_BFG;
+ else {
+ return -1;
+ }
+}
+
+/*
+==================
+BotClearPath
+
+ try to deactivate obstacles like proximity mines on the bot's path
+==================
+*/
+void BotClearPath(bot_state_t *bs, bot_moveresult_t *moveresult) {
+ int i, bestmine;
+ float dist, bestdist;
+ vec3_t target, dir;
+ bsp_trace_t bsptrace;
+ entityState_t state;
+
+ // if there is a dead body wearing kamikze nearby
+ if (bs->kamikazebody) {
+ // if the bot's view angles and weapon are not used for movement
+ if ( !(moveresult->flags & (MOVERESULT_MOVEMENTVIEW | MOVERESULT_MOVEMENTWEAPON)) ) {
+ //
+ BotAI_GetEntityState(bs->kamikazebody, &state);
+ VectorCopy(state.pos.trBase, target);
+ target[2] += 8;
+ VectorSubtract(target, bs->eye, dir);
+ vectoangles(dir, moveresult->ideal_viewangles);
+ //
+ moveresult->weapon = BotSelectActivateWeapon(bs);
+ if (moveresult->weapon == -1) {
+ // FIXME: run away!
+ moveresult->weapon = 0;
+ }
+ if (moveresult->weapon) {
+ //
+ moveresult->flags |= MOVERESULT_MOVEMENTWEAPON | MOVERESULT_MOVEMENTVIEW;
+ // if holding the right weapon
+ if (bs->cur_ps.weapon == moveresult->weapon) {
+ // if the bot is pretty close with it's aim
+ if (InFieldOfVision(bs->viewangles, 20, moveresult->ideal_viewangles)) {
+ //
+ BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, target, bs->entitynum, MASK_SHOT);
+ // if the mine is visible from the current position
+ if (bsptrace.fraction >= 1.0 || bsptrace.ent == state.number) {
+ // shoot at the mine
+ trap_EA_Attack(bs->client);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (moveresult->flags & MOVERESULT_BLOCKEDBYAVOIDSPOT) {
+ bs->blockedbyavoidspot_time = FloatTime() + 5;
+ }
+ // if blocked by an avoid spot and the view angles and weapon are used for movement
+ if (bs->blockedbyavoidspot_time > FloatTime() &&
+ !(moveresult->flags & (MOVERESULT_MOVEMENTVIEW | MOVERESULT_MOVEMENTWEAPON)) ) {
+ bestdist = 300;
+ bestmine = -1;
+ for (i = 0; i < bs->numproxmines; i++) {
+ BotAI_GetEntityState(bs->proxmines[i], &state);
+ VectorSubtract(state.pos.trBase, bs->origin, dir);
+ dist = VectorLength(dir);
+ if (dist < bestdist) {
+ bestdist = dist;
+ bestmine = i;
+ }
+ }
+ if (bestmine != -1) {
+ //
+ // state->generic1 == TEAM_RED || state->generic1 == TEAM_BLUE
+ //
+ // deactivate prox mines in the bot's path by shooting
+ // rockets or plasma cells etc. at them
+ BotAI_GetEntityState(bs->proxmines[bestmine], &state);
+ VectorCopy(state.pos.trBase, target);
+ target[2] += 2;
+ VectorSubtract(target, bs->eye, dir);
+ vectoangles(dir, moveresult->ideal_viewangles);
+ // if the bot has a weapon that does splash damage
+ if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0)
+ moveresult->weapon = WEAPONINDEX_PLASMAGUN;
+ else if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0)
+ moveresult->weapon = WEAPONINDEX_ROCKET_LAUNCHER;
+ else if (bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0)
+ moveresult->weapon = WEAPONINDEX_BFG;
+ else {
+ moveresult->weapon = 0;
+ }
+ if (moveresult->weapon) {
+ //
+ moveresult->flags |= MOVERESULT_MOVEMENTWEAPON | MOVERESULT_MOVEMENTVIEW;
+ // if holding the right weapon
+ if (bs->cur_ps.weapon == moveresult->weapon) {
+ // if the bot is pretty close with it's aim
+ if (InFieldOfVision(bs->viewangles, 20, moveresult->ideal_viewangles)) {
+ //
+ BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, target, bs->entitynum, MASK_SHOT);
+ // if the mine is visible from the current position
+ if (bsptrace.fraction >= 1.0 || bsptrace.ent == state.number) {
+ // shoot at the mine
+ trap_EA_Attack(bs->client);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+==================
+AIEnter_Seek_ActivateEntity
+==================
+*/
+void AIEnter_Seek_ActivateEntity(bot_state_t *bs, char *s) {
+ BotRecordNodeSwitch(bs, "activate entity", "", s);
+ bs->ainode = AINode_Seek_ActivateEntity;
+}
+
+/*
+==================
+AINode_Seek_Activate_Entity
+==================
+*/
+int AINode_Seek_ActivateEntity(bot_state_t *bs) {
+ bot_goal_t *goal;
+ vec3_t target, dir, ideal_viewangles;
+ bot_moveresult_t moveresult;
+ int targetvisible;
+ bsp_trace_t bsptrace;
+ aas_entityinfo_t entinfo;
+
+ if (BotIsObserver(bs)) {
+ BotClearActivateGoalStack(bs);
+ AIEnter_Observer(bs, "active entity: observer");
+ return qfalse;
+ }
+ //if in the intermission
+ if (BotIntermission(bs)) {
+ BotClearActivateGoalStack(bs);
+ AIEnter_Intermission(bs, "activate entity: intermission");
+ return qfalse;
+ }
+ //respawn if dead
+ if (BotIsDead(bs)) {
+ BotClearActivateGoalStack(bs);
+ AIEnter_Respawn(bs, "activate entity: bot dead");
+ return qfalse;
+ }
+ //
+ bs->tfl = TFL_DEFAULT;
+ if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
+ // if in lava or slime the bot should be able to get out
+ if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
+ // map specific code
+ BotMapScripts(bs);
+ // no enemy
+ bs->enemy = -1;
+ // if the bot has no activate goal
+ if (!bs->activatestack) {
+ BotClearActivateGoalStack(bs);
+ AIEnter_Seek_NBG(bs, "activate entity: no goal");
+ return qfalse;
+ }
+ //
+ goal = &bs->activatestack->goal;
+ // initialize target being visible to false
+ targetvisible = qfalse;
+ // if the bot has to shoot at a target to activate something
+ if (bs->activatestack->shoot) {
+ //
+ BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, bs->activatestack->target, bs->entitynum, MASK_SHOT);
+ // if the shootable entity is visible from the current position
+ if (bsptrace.fraction >= 1.0 || bsptrace.ent == goal->entitynum) {
+ targetvisible = qtrue;
+ // if holding the right weapon
+ if (bs->cur_ps.weapon == bs->activatestack->weapon) {
+ VectorSubtract(bs->activatestack->target, bs->eye, dir);
+ vectoangles(dir, ideal_viewangles);
+ // if the bot is pretty close with it's aim
+ if (InFieldOfVision(bs->viewangles, 20, ideal_viewangles)) {
+ trap_EA_Attack(bs->client);
+ }
+ }
+ }
+ }
+ // if the shoot target is visible
+ if (targetvisible) {
+ // get the entity info of the entity the bot is shooting at
+ BotEntityInfo(goal->entitynum, &entinfo);
+ // if the entity the bot shoots at moved
+ if (!VectorCompare(bs->activatestack->origin, entinfo.origin)) {
+#ifdef DEBUG
+ BotAI_Print(PRT_MESSAGE, "hit shootable button or trigger\n");
+#endif //DEBUG
+ bs->activatestack->time = 0;
+ }
+ // if the activate goal has been activated or the bot takes too long
+ if (bs->activatestack->time < FloatTime()) {
+ BotPopFromActivateGoalStack(bs);
+ // if there are more activate goals on the stack
+ if (bs->activatestack) {
+ bs->activatestack->time = FloatTime() + 10;
+ return qfalse;
+ }
+ AIEnter_Seek_NBG(bs, "activate entity: time out");
+ return qfalse;
+ }
+ memset(&moveresult, 0, sizeof(bot_moveresult_t));
+ }
+ else {
+ // if the bot has no goal
+ if (!goal) {
+ bs->activatestack->time = 0;
+ }
+ // if the bot does not have a shoot goal
+ else if (!bs->activatestack->shoot) {
+ //if the bot touches the current goal
+ if (trap_BotTouchingGoal(bs->origin, goal)) {
+#ifdef DEBUG
+ BotAI_Print(PRT_MESSAGE, "touched button or trigger\n");
+#endif //DEBUG
+ bs->activatestack->time = 0;
+ }
+ }
+ // if the activate goal has been activated or the bot takes too long
+ if (bs->activatestack->time < FloatTime()) {
+ BotPopFromActivateGoalStack(bs);
+ // if there are more activate goals on the stack
+ if (bs->activatestack) {
+ bs->activatestack->time = FloatTime() + 10;
+ return qfalse;
+ }
+ AIEnter_Seek_NBG(bs, "activate entity: activated");
+ return qfalse;
+ }
+ //predict obstacles
+ if (BotAIPredictObstacles(bs, goal))
+ return qfalse;
+ //initialize the movement state
+ BotSetupForMovement(bs);
+ //move towards the goal
+ trap_BotMoveToGoal(&moveresult, bs->ms, goal, bs->tfl);
+ //if the movement failed
+ if (moveresult.failure) {
+ //reset the avoid reach, otherwise bot is stuck in current area
+ trap_BotResetAvoidReach(bs->ms);
+ //
+ bs->activatestack->time = 0;
+ }
+ //check if the bot is blocked
+ BotAIBlocked(bs, &moveresult, qtrue);
+ }
+ //
+ BotClearPath(bs, &moveresult);
+ // if the bot has to shoot to activate
+ if (bs->activatestack->shoot) {
+ // if the view angles aren't yet used for the movement
+ if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEW)) {
+ VectorSubtract(bs->activatestack->target, bs->eye, dir);
+ vectoangles(dir, moveresult.ideal_viewangles);
+ moveresult.flags |= MOVERESULT_MOVEMENTVIEW;
+ }
+ // if there's no weapon yet used for the movement
+ if (!(moveresult.flags & MOVERESULT_MOVEMENTWEAPON)) {
+ moveresult.flags |= MOVERESULT_MOVEMENTWEAPON;
+ //
+ bs->activatestack->weapon = BotSelectActivateWeapon(bs);
+ if (bs->activatestack->weapon == -1) {
+ //FIXME: find a decent weapon first
+ bs->activatestack->weapon = 0;
+ }
+ moveresult.weapon = bs->activatestack->weapon;
+ }
+ }
+ // if the ideal view angles are set for movement
+ if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
+ VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
+ }
+ // if waiting for something
+ else if (moveresult.flags & MOVERESULT_WAITING) {
+ if (random() < bs->thinktime * 0.8) {
+ BotRoamGoal(bs, target);
+ VectorSubtract(target, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ bs->ideal_viewangles[2] *= 0.5;
+ }
+ }
+ else if (!(bs->flags & BFL_IDEALVIEWSET)) {
+ if (trap_BotMovementViewTarget(bs->ms, goal, bs->tfl, 300, target)) {
+ VectorSubtract(target, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ }
+ else {
+ vectoangles(moveresult.movedir, bs->ideal_viewangles);
+ }
+ bs->ideal_viewangles[2] *= 0.5;
+ }
+ // if the weapon is used for the bot movement
+ if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON)
+ bs->weaponnum = moveresult.weapon;
+ // if there is an enemy
+ if (BotFindEnemy(bs, -1)) {
+ if (BotWantsToRetreat(bs)) {
+ //keep the current long term goal and retreat
+ AIEnter_Battle_NBG(bs, "activate entity: found enemy");
+ }
+ else {
+ trap_BotResetLastAvoidReach(bs->ms);
+ //empty the goal stack
+ trap_BotEmptyGoalStack(bs->gs);
+ //go fight
+ AIEnter_Battle_Fight(bs, "activate entity: found enemy");
+ }
+ BotClearActivateGoalStack(bs);
+ }
+ return qtrue;
+}
+
+/*
+==================
+AIEnter_Seek_NBG
+==================
+*/
+void AIEnter_Seek_NBG(bot_state_t *bs, char *s) {
+ bot_goal_t goal;
+ char buf[144];
+
+ if (trap_BotGetTopGoal(bs->gs, &goal)) {
+ trap_BotGoalName(goal.number, buf, 144);
+ BotRecordNodeSwitch(bs, "seek NBG", buf, s);
+ }
+ else {
+ BotRecordNodeSwitch(bs, "seek NBG", "no goal", s);
+ }
+ bs->ainode = AINode_Seek_NBG;
+}
+
+/*
+==================
+AINode_Seek_NBG
+==================
+*/
+int AINode_Seek_NBG(bot_state_t *bs) {
+ bot_goal_t goal;
+ vec3_t target, dir;
+ bot_moveresult_t moveresult;
+
+ if (BotIsObserver(bs)) {
+ AIEnter_Observer(bs, "seek nbg: observer");
+ return qfalse;
+ }
+ //if in the intermission
+ if (BotIntermission(bs)) {
+ AIEnter_Intermission(bs, "seek nbg: intermision");
+ return qfalse;
+ }
+ //respawn if dead
+ if (BotIsDead(bs)) {
+ AIEnter_Respawn(bs, "seek nbg: bot dead");
+ return qfalse;
+ }
+ //
+ bs->tfl = TFL_DEFAULT;
+ if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
+ //if in lava or slime the bot should be able to get out
+ if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
+ //
+ if (BotCanAndWantsToRocketJump(bs)) {
+ bs->tfl |= TFL_ROCKETJUMP;
+ }
+ //map specific code
+ BotMapScripts(bs);
+ //no enemy
+ bs->enemy = -1;
+ //if the bot has no goal
+ if (!trap_BotGetTopGoal(bs->gs, &goal)) bs->nbg_time = 0;
+ //if the bot touches the current goal
+ else if (BotReachedGoal(bs, &goal)) {
+ BotChooseWeapon(bs);
+ bs->nbg_time = 0;
+ }
+ //
+ if (bs->nbg_time < FloatTime()) {
+ //pop the current goal from the stack
+ trap_BotPopGoal(bs->gs);
+ //check for new nearby items right away
+ //NOTE: we canNOT reset the check_time to zero because it would create an endless loop of node switches
+ bs->check_time = FloatTime() + 0.05;
+ //go back to seek ltg
+ AIEnter_Seek_LTG(bs, "seek nbg: time out");
+ return qfalse;
+ }
+ //predict obstacles
+ if (BotAIPredictObstacles(bs, &goal))
+ return qfalse;
+ //initialize the movement state
+ BotSetupForMovement(bs);
+ //move towards the goal
+ trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
+ //if the movement failed
+ if (moveresult.failure) {
+ //reset the avoid reach, otherwise bot is stuck in current area
+ trap_BotResetAvoidReach(bs->ms);
+ bs->nbg_time = 0;
+ }
+ //check if the bot is blocked
+ BotAIBlocked(bs, &moveresult, qtrue);
+ //
+ BotClearPath(bs, &moveresult);
+ //if the viewangles are used for the movement
+ if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
+ VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
+ }
+ //if waiting for something
+ else if (moveresult.flags & MOVERESULT_WAITING) {
+ if (random() < bs->thinktime * 0.8) {
+ BotRoamGoal(bs, target);
+ VectorSubtract(target, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ bs->ideal_viewangles[2] *= 0.5;
+ }
+ }
+ else if (!(bs->flags & BFL_IDEALVIEWSET)) {
+ if (!trap_BotGetSecondGoal(bs->gs, &goal)) trap_BotGetTopGoal(bs->gs, &goal);
+ if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
+ VectorSubtract(target, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ }
+ //FIXME: look at cluster portals?
+ else vectoangles(moveresult.movedir, bs->ideal_viewangles);
+ bs->ideal_viewangles[2] *= 0.5;
+ }
+ //if the weapon is used for the bot movement
+ if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
+ //if there is an enemy
+ if (BotFindEnemy(bs, -1)) {
+ if (BotWantsToRetreat(bs)) {
+ //keep the current long term goal and retreat
+ AIEnter_Battle_NBG(bs, "seek nbg: found enemy");
+ }
+ else {
+ trap_BotResetLastAvoidReach(bs->ms);
+ //empty the goal stack
+ trap_BotEmptyGoalStack(bs->gs);
+ //go fight
+ AIEnter_Battle_Fight(bs, "seek nbg: found enemy");
+ }
+ }
+ return qtrue;
+}
+
+/*
+==================
+AIEnter_Seek_LTG
+==================
+*/
+void AIEnter_Seek_LTG(bot_state_t *bs, char *s) {
+ bot_goal_t goal;
+ char buf[144];
+
+ if (trap_BotGetTopGoal(bs->gs, &goal)) {
+ trap_BotGoalName(goal.number, buf, 144);
+ BotRecordNodeSwitch(bs, "seek LTG", buf, s);
+ }
+ else {
+ BotRecordNodeSwitch(bs, "seek LTG", "no goal", s);
+ }
+ bs->ainode = AINode_Seek_LTG;
+}
+
+/*
+==================
+AINode_Seek_LTG
+==================
+*/
+int AINode_Seek_LTG(bot_state_t *bs)
+{
+ bot_goal_t goal;
+ vec3_t target, dir;
+ bot_moveresult_t moveresult;
+ int range;
+ //char buf[128];
+ //bot_goal_t tmpgoal;
+
+ if (BotIsObserver(bs)) {
+ AIEnter_Observer(bs, "seek ltg: observer");
+ return qfalse;
+ }
+ //if in the intermission
+ if (BotIntermission(bs)) {
+ AIEnter_Intermission(bs, "seek ltg: intermission");
+ return qfalse;
+ }
+ //respawn if dead
+ if (BotIsDead(bs)) {
+ AIEnter_Respawn(bs, "seek ltg: bot dead");
+ return qfalse;
+ }
+ //
+ if (BotChat_Random(bs)) {
+ bs->stand_time = FloatTime() + BotChatTime(bs);
+ AIEnter_Stand(bs, "seek ltg: random chat");
+ return qfalse;
+ }
+ //
+ bs->tfl = TFL_DEFAULT;
+ if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
+ //if in lava or slime the bot should be able to get out
+ if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
+ //
+ if (BotCanAndWantsToRocketJump(bs)) {
+ bs->tfl |= TFL_ROCKETJUMP;
+ }
+ //map specific code
+ BotMapScripts(bs);
+ //no enemy
+ bs->enemy = -1;
+ //
+ if (bs->killedenemy_time > FloatTime() - 2) {
+ if (random() < bs->thinktime * 1) {
+ trap_EA_Gesture(bs->client);
+ }
+ }
+ //if there is an enemy
+ if (BotFindEnemy(bs, -1)) {
+ if (BotWantsToRetreat(bs)) {
+ //keep the current long term goal and retreat
+ AIEnter_Battle_Retreat(bs, "seek ltg: found enemy");
+ return qfalse;
+ }
+ else {
+ trap_BotResetLastAvoidReach(bs->ms);
+ //empty the goal stack
+ trap_BotEmptyGoalStack(bs->gs);
+ //go fight
+ AIEnter_Battle_Fight(bs, "seek ltg: found enemy");
+ return qfalse;
+ }
+ }
+ //
+ BotTeamGoals(bs, qfalse);
+ //get the current long term goal
+ if (!BotLongTermGoal(bs, bs->tfl, qfalse, &goal)) {
+ return qtrue;
+ }
+ //check for nearby goals periodicly
+ if (bs->check_time < FloatTime()) {
+ bs->check_time = FloatTime() + 0.5;
+ //check if the bot wants to camp
+ BotWantsToCamp(bs);
+ //
+ if (bs->ltgtype == LTG_DEFENDKEYAREA) range = 400;
+ else range = 150;
+ //
+#ifdef CTF
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ //if carrying a flag the bot shouldn't be distracted too much
+ if (BotCTFCarryingFlag(bs))
+ range = 50;
+ }
+#endif //CTF
+ else if (gametype == GT_1FCTF) {
+ if (Bot1FCTFCarryingFlag(bs))
+ range = 50;
+ }
+ else if (gametype == GT_HARVESTER) {
+ if (BotHarvesterCarryingCubes(bs))
+ range = 80;
+ }
+ //
+ if (BotNearbyGoal(bs, bs->tfl, &goal, range)) {
+ trap_BotResetLastAvoidReach(bs->ms);
+ //get the goal at the top of the stack
+ //trap_BotGetTopGoal(bs->gs, &tmpgoal);
+ //trap_BotGoalName(tmpgoal.number, buf, 144);
+ //BotAI_Print(PRT_MESSAGE, "new nearby goal %s\n", buf);
+ //time the bot gets to pick up the nearby goal item
+ bs->nbg_time = FloatTime() + 4 + range * 0.01;
+ AIEnter_Seek_NBG(bs, "ltg seek: nbg");
+ return qfalse;
+ }
+ }
+ //predict obstacles
+ if (BotAIPredictObstacles(bs, &goal))
+ return qfalse;
+ //initialize the movement state
+ BotSetupForMovement(bs);
+ //move towards the goal
+ trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
+ //if the movement failed
+ if (moveresult.failure) {
+ //reset the avoid reach, otherwise bot is stuck in current area
+ trap_BotResetAvoidReach(bs->ms);
+ //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
+ bs->ltg_time = 0;
+ }
+ //
+ BotAIBlocked(bs, &moveresult, qtrue);
+ //
+ BotClearPath(bs, &moveresult);
+ //if the viewangles are used for the movement
+ if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
+ VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
+ }
+ //if waiting for something
+ else if (moveresult.flags & MOVERESULT_WAITING) {
+ if (random() < bs->thinktime * 0.8) {
+ BotRoamGoal(bs, target);
+ VectorSubtract(target, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ bs->ideal_viewangles[2] *= 0.5;
+ }
+ }
+ else if (!(bs->flags & BFL_IDEALVIEWSET)) {
+ if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
+ VectorSubtract(target, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ }
+ //FIXME: look at cluster portals?
+ else if (VectorLengthSquared(moveresult.movedir)) {
+ vectoangles(moveresult.movedir, bs->ideal_viewangles);
+ }
+ else if (random() < bs->thinktime * 0.8) {
+ BotRoamGoal(bs, target);
+ VectorSubtract(target, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ bs->ideal_viewangles[2] *= 0.5;
+ }
+ bs->ideal_viewangles[2] *= 0.5;
+ }
+ //if the weapon is used for the bot movement
+ if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
+ //
+ return qtrue;
+}
+
+/*
+==================
+AIEnter_Battle_Fight
+==================
+*/
+void AIEnter_Battle_Fight(bot_state_t *bs, char *s) {
+ BotRecordNodeSwitch(bs, "battle fight", "", s);
+ trap_BotResetLastAvoidReach(bs->ms);
+ bs->ainode = AINode_Battle_Fight;
+ bs->flags &= ~BFL_FIGHTSUICIDAL;
+}
+
+/*
+==================
+AIEnter_Battle_SuicidalFight
+==================
+*/
+void AIEnter_Battle_SuicidalFight(bot_state_t *bs, char *s) {
+ BotRecordNodeSwitch(bs, "battle fight", "", s);
+ trap_BotResetLastAvoidReach(bs->ms);
+ bs->ainode = AINode_Battle_Fight;
+ bs->flags |= BFL_FIGHTSUICIDAL;
+}
+
+/*
+==================
+AINode_Battle_Fight
+==================
+*/
+int AINode_Battle_Fight(bot_state_t *bs) {
+ int areanum;
+ vec3_t target;
+ aas_entityinfo_t entinfo;
+ bot_moveresult_t moveresult;
+
+ if (BotIsObserver(bs)) {
+ AIEnter_Observer(bs, "battle fight: observer");
+ return qfalse;
+ }
+
+ //if in the intermission
+ if (BotIntermission(bs)) {
+ AIEnter_Intermission(bs, "battle fight: intermission");
+ return qfalse;
+ }
+ //respawn if dead
+ if (BotIsDead(bs)) {
+ AIEnter_Respawn(bs, "battle fight: bot dead");
+ return qfalse;
+ }
+ //if there is another better enemy
+ if (BotFindEnemy(bs, bs->enemy)) {
+#ifdef DEBUG
+ BotAI_Print(PRT_MESSAGE, "found new better enemy\n");
+#endif
+ }
+ //if no enemy
+ if (bs->enemy < 0) {
+ AIEnter_Seek_LTG(bs, "battle fight: no enemy");
+ return qfalse;
+ }
+ //
+ BotEntityInfo(bs->enemy, &entinfo);
+ //if the enemy is dead
+ if (bs->enemydeath_time) {
+ if (bs->enemydeath_time < FloatTime() - 1.0) {
+ bs->enemydeath_time = 0;
+ if (bs->enemysuicide) {
+ BotChat_EnemySuicide(bs);
+ }
+ if (bs->lastkilledplayer == bs->enemy && BotChat_Kill(bs)) {
+ bs->stand_time = FloatTime() + BotChatTime(bs);
+ AIEnter_Stand(bs, "battle fight: enemy dead");
+ }
+ else {
+ bs->ltg_time = 0;
+ AIEnter_Seek_LTG(bs, "battle fight: enemy dead");
+ }
+ return qfalse;
+ }
+ }
+ else {
+ if (EntityIsDead(&entinfo)) {
+ bs->enemydeath_time = FloatTime();
+ }
+ }
+ //if the enemy is invisible and not shooting the bot looses track easily
+ if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
+ if (random() < 0.2) {
+ AIEnter_Seek_LTG(bs, "battle fight: invisible");
+ return qfalse;
+ }
+ }
+ //
+ VectorCopy(entinfo.origin, target);
+ // if not a player enemy
+ if (bs->enemy >= MAX_CLIENTS) {
+ // if attacking an obelisk
+ if ( bs->enemy == redobelisk.entitynum ||
+ bs->enemy == blueobelisk.entitynum ) {
+ target[2] += 16;
+ }
+ }
+ //update the reachability area and origin if possible
+ areanum = BotPointAreaNum(target);
+ if (areanum && trap_AAS_AreaReachability(areanum)) {
+ VectorCopy(target, bs->lastenemyorigin);
+ bs->lastenemyareanum = areanum;
+ }
+ //update the attack inventory values
+ BotUpdateBattleInventory(bs, bs->enemy);
+ //if the bot's health decreased
+ if (bs->lastframe_health > bs->inventory[INVENTORY_HEALTH]) {
+ if (BotChat_HitNoDeath(bs)) {
+ bs->stand_time = FloatTime() + BotChatTime(bs);
+ AIEnter_Stand(bs, "battle fight: chat health decreased");
+ return qfalse;
+ }
+ }
+ //if the bot hit someone
+ if (bs->cur_ps.persistant[PERS_HITS] > bs->lasthitcount) {
+ if (BotChat_HitNoKill(bs)) {
+ bs->stand_time = FloatTime() + BotChatTime(bs);
+ AIEnter_Stand(bs, "battle fight: chat hit someone");
+ return qfalse;
+ }
+ }
+ //if the enemy is not visible
+ if (!BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
+#ifdef MISSIONPACK
+ if (bs->enemy == redobelisk.entitynum || bs->enemy == blueobelisk.entitynum) {
+ AIEnter_Battle_Chase(bs, "battle fight: obelisk out of sight");
+ return qfalse;
+ }
+#endif
+ if (BotWantsToChase(bs)) {
+ AIEnter_Battle_Chase(bs, "battle fight: enemy out of sight");
+ return qfalse;
+ }
+ else {
+ AIEnter_Seek_LTG(bs, "battle fight: enemy out of sight");
+ return qfalse;
+ }
+ }
+ //use holdable items
+ BotBattleUseItems(bs);
+ //
+ bs->tfl = TFL_DEFAULT;
+ if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
+ //if in lava or slime the bot should be able to get out
+ if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
+ //
+ if (BotCanAndWantsToRocketJump(bs)) {
+ bs->tfl |= TFL_ROCKETJUMP;
+ }
+ //choose the best weapon to fight with
+ BotChooseWeapon(bs);
+ //do attack movements
+ moveresult = BotAttackMove(bs, bs->tfl);
+ //if the movement failed
+ if (moveresult.failure) {
+ //reset the avoid reach, otherwise bot is stuck in current area
+ trap_BotResetAvoidReach(bs->ms);
+ //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
+ bs->ltg_time = 0;
+ }
+ //
+ BotAIBlocked(bs, &moveresult, qfalse);
+ //aim at the enemy
+ BotAimAtEnemy(bs);
+ //attack the enemy if possible
+ BotCheckAttack(bs);
+ //if the bot wants to retreat
+ if (!(bs->flags & BFL_FIGHTSUICIDAL)) {
+ if (BotWantsToRetreat(bs)) {
+ AIEnter_Battle_Retreat(bs, "battle fight: wants to retreat");
+ return qtrue;
+ }
+ }
+ return qtrue;
+}
+
+/*
+==================
+AIEnter_Battle_Chase
+==================
+*/
+void AIEnter_Battle_Chase(bot_state_t *bs, char *s) {
+ BotRecordNodeSwitch(bs, "battle chase", "", s);
+ bs->chase_time = FloatTime();
+ bs->ainode = AINode_Battle_Chase;
+}
+
+/*
+==================
+AINode_Battle_Chase
+==================
+*/
+int AINode_Battle_Chase(bot_state_t *bs)
+{
+ bot_goal_t goal;
+ vec3_t target, dir;
+ bot_moveresult_t moveresult;
+ float range;
+
+ if (BotIsObserver(bs)) {
+ AIEnter_Observer(bs, "battle chase: observer");
+ return qfalse;
+ }
+ //if in the intermission
+ if (BotIntermission(bs)) {
+ AIEnter_Intermission(bs, "battle chase: intermission");
+ return qfalse;
+ }
+ //respawn if dead
+ if (BotIsDead(bs)) {
+ AIEnter_Respawn(bs, "battle chase: bot dead");
+ return qfalse;
+ }
+ //if no enemy
+ if (bs->enemy < 0) {
+ AIEnter_Seek_LTG(bs, "battle chase: no enemy");
+ return qfalse;
+ }
+ //if the enemy is visible
+ if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
+ AIEnter_Battle_Fight(bs, "battle chase");
+ return qfalse;
+ }
+ //if there is another enemy
+ if (BotFindEnemy(bs, -1)) {
+ AIEnter_Battle_Fight(bs, "battle chase: better enemy");
+ return qfalse;
+ }
+ //there is no last enemy area
+ if (!bs->lastenemyareanum) {
+ AIEnter_Seek_LTG(bs, "battle chase: no enemy area");
+ return qfalse;
+ }
+ //
+ bs->tfl = TFL_DEFAULT;
+ if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
+ //if in lava or slime the bot should be able to get out
+ if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
+ //
+ if (BotCanAndWantsToRocketJump(bs)) {
+ bs->tfl |= TFL_ROCKETJUMP;
+ }
+ //map specific code
+ BotMapScripts(bs);
+ //create the chase goal
+ goal.entitynum = bs->enemy;
+ goal.areanum = bs->lastenemyareanum;
+ VectorCopy(bs->lastenemyorigin, goal.origin);
+ VectorSet(goal.mins, -8, -8, -8);
+ VectorSet(goal.maxs, 8, 8, 8);
+ //if the last seen enemy spot is reached the enemy could not be found
+ if (trap_BotTouchingGoal(bs->origin, &goal)) bs->chase_time = 0;
+ //if there's no chase time left
+ if (!bs->chase_time || bs->chase_time < FloatTime() - 10) {
+ AIEnter_Seek_LTG(bs, "battle chase: time out");
+ return qfalse;
+ }
+ //check for nearby goals periodicly
+ if (bs->check_time < FloatTime()) {
+ bs->check_time = FloatTime() + 1;
+ range = 150;
+ //
+ if (BotNearbyGoal(bs, bs->tfl, &goal, range)) {
+ //the bot gets 5 seconds to pick up the nearby goal item
+ bs->nbg_time = FloatTime() + 0.1 * range + 1;
+ trap_BotResetLastAvoidReach(bs->ms);
+ AIEnter_Battle_NBG(bs, "battle chase: nbg");
+ return qfalse;
+ }
+ }
+ //
+ BotUpdateBattleInventory(bs, bs->enemy);
+ //initialize the movement state
+ BotSetupForMovement(bs);
+ //move towards the goal
+ trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
+ //if the movement failed
+ if (moveresult.failure) {
+ //reset the avoid reach, otherwise bot is stuck in current area
+ trap_BotResetAvoidReach(bs->ms);
+ //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
+ bs->ltg_time = 0;
+ }
+ //
+ BotAIBlocked(bs, &moveresult, qfalse);
+ //
+ if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
+ VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
+ }
+ else if (!(bs->flags & BFL_IDEALVIEWSET)) {
+ if (bs->chase_time > FloatTime() - 2) {
+ BotAimAtEnemy(bs);
+ }
+ else {
+ if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
+ VectorSubtract(target, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ }
+ else {
+ vectoangles(moveresult.movedir, bs->ideal_viewangles);
+ }
+ }
+ bs->ideal_viewangles[2] *= 0.5;
+ }
+ //if the weapon is used for the bot movement
+ if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
+ //if the bot is in the area the enemy was last seen in
+ if (bs->areanum == bs->lastenemyareanum) bs->chase_time = 0;
+ //if the bot wants to retreat (the bot could have been damage during the chase)
+ if (BotWantsToRetreat(bs)) {
+ AIEnter_Battle_Retreat(bs, "battle chase: wants to retreat");
+ return qtrue;
+ }
+ return qtrue;
+}
+
+/*
+==================
+AIEnter_Battle_Retreat
+==================
+*/
+void AIEnter_Battle_Retreat(bot_state_t *bs, char *s) {
+ BotRecordNodeSwitch(bs, "battle retreat", "", s);
+ bs->ainode = AINode_Battle_Retreat;
+}
+
+/*
+==================
+AINode_Battle_Retreat
+==================
+*/
+int AINode_Battle_Retreat(bot_state_t *bs) {
+ bot_goal_t goal;
+ aas_entityinfo_t entinfo;
+ bot_moveresult_t moveresult;
+ vec3_t target, dir;
+ float attack_skill, range;
+ int areanum;
+
+ if (BotIsObserver(bs)) {
+ AIEnter_Observer(bs, "battle retreat: observer");
+ return qfalse;
+ }
+ //if in the intermission
+ if (BotIntermission(bs)) {
+ AIEnter_Intermission(bs, "battle retreat: intermission");
+ return qfalse;
+ }
+ //respawn if dead
+ if (BotIsDead(bs)) {
+ AIEnter_Respawn(bs, "battle retreat: bot dead");
+ return qfalse;
+ }
+ //if no enemy
+ if (bs->enemy < 0) {
+ AIEnter_Seek_LTG(bs, "battle retreat: no enemy");
+ return qfalse;
+ }
+ //
+ BotEntityInfo(bs->enemy, &entinfo);
+ if (EntityIsDead(&entinfo)) {
+ AIEnter_Seek_LTG(bs, "battle retreat: enemy dead");
+ return qfalse;
+ }
+ //if there is another better enemy
+ if (BotFindEnemy(bs, bs->enemy)) {
+#ifdef DEBUG
+ BotAI_Print(PRT_MESSAGE, "found new better enemy\n");
+#endif
+ }
+ //
+ bs->tfl = TFL_DEFAULT;
+ if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
+ //if in lava or slime the bot should be able to get out
+ if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
+ //map specific code
+ BotMapScripts(bs);
+ //update the attack inventory values
+ BotUpdateBattleInventory(bs, bs->enemy);
+ //if the bot doesn't want to retreat anymore... probably picked up some nice items
+ if (BotWantsToChase(bs)) {
+ //empty the goal stack, when chasing, only the enemy is the goal
+ trap_BotEmptyGoalStack(bs->gs);
+ //go chase the enemy
+ AIEnter_Battle_Chase(bs, "battle retreat: wants to chase");
+ return qfalse;
+ }
+ //update the last time the enemy was visible
+ if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
+ bs->enemyvisible_time = FloatTime();
+ VectorCopy(entinfo.origin, target);
+ // if not a player enemy
+ if (bs->enemy >= MAX_CLIENTS) {
+ // if attacking an obelisk
+ if ( bs->enemy == redobelisk.entitynum ||
+ bs->enemy == blueobelisk.entitynum ) {
+ target[2] += 16;
+ }
+ }
+ //update the reachability area and origin if possible
+ areanum = BotPointAreaNum(target);
+ if (areanum && trap_AAS_AreaReachability(areanum)) {
+ VectorCopy(target, bs->lastenemyorigin);
+ bs->lastenemyareanum = areanum;
+ }
+ }
+ //if the enemy is NOT visible for 4 seconds
+ if (bs->enemyvisible_time < FloatTime() - 4) {
+ AIEnter_Seek_LTG(bs, "battle retreat: lost enemy");
+ return qfalse;
+ }
+ //else if the enemy is NOT visible
+ else if (bs->enemyvisible_time < FloatTime()) {
+ //if there is another enemy
+ if (BotFindEnemy(bs, -1)) {
+ AIEnter_Battle_Fight(bs, "battle retreat: another enemy");
+ return qfalse;
+ }
+ }
+ //
+ BotTeamGoals(bs, qtrue);
+ //use holdable items
+ BotBattleUseItems(bs);
+ //get the current long term goal while retreating
+ if (!BotLongTermGoal(bs, bs->tfl, qtrue, &goal)) {
+ AIEnter_Battle_SuicidalFight(bs, "battle retreat: no way out");
+ return qfalse;
+ }
+ //check for nearby goals periodicly
+ if (bs->check_time < FloatTime()) {
+ bs->check_time = FloatTime() + 1;
+ range = 150;
+#ifdef CTF
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ //if carrying a flag the bot shouldn't be distracted too much
+ if (BotCTFCarryingFlag(bs))
+ range = 50;
+ }
+#endif //CTF
+ else if (gametype == GT_1FCTF) {
+ if (Bot1FCTFCarryingFlag(bs))
+ range = 50;
+ }
+ else if (gametype == GT_HARVESTER) {
+ if (BotHarvesterCarryingCubes(bs))
+ range = 80;
+ }
+ //
+ if (BotNearbyGoal(bs, bs->tfl, &goal, range)) {
+ trap_BotResetLastAvoidReach(bs->ms);
+ //time the bot gets to pick up the nearby goal item
+ bs->nbg_time = FloatTime() + range / 100 + 1;
+ AIEnter_Battle_NBG(bs, "battle retreat: nbg");
+ return qfalse;
+ }
+ }
+ //initialize the movement state
+ BotSetupForMovement(bs);
+ //move towards the goal
+ trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
+ //if the movement failed
+ if (moveresult.failure) {
+ //reset the avoid reach, otherwise bot is stuck in current area
+ trap_BotResetAvoidReach(bs->ms);
+ //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
+ bs->ltg_time = 0;
+ }
+ //
+ BotAIBlocked(bs, &moveresult, qfalse);
+ //choose the best weapon to fight with
+ BotChooseWeapon(bs);
+ //if the view is fixed for the movement
+ if (moveresult.flags & (MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
+ VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
+ }
+ else if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET)
+ && !(bs->flags & BFL_IDEALVIEWSET) ) {
+ attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1);
+ //if the bot is skilled anough
+ if (attack_skill > 0.3) {
+ BotAimAtEnemy(bs);
+ }
+ else {
+ if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
+ VectorSubtract(target, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ }
+ else {
+ vectoangles(moveresult.movedir, bs->ideal_viewangles);
+ }
+ bs->ideal_viewangles[2] *= 0.5;
+ }
+ }
+ //if the weapon is used for the bot movement
+ if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
+ //attack the enemy if possible
+ BotCheckAttack(bs);
+ //
+ return qtrue;
+}
+
+/*
+==================
+AIEnter_Battle_NBG
+==================
+*/
+void AIEnter_Battle_NBG(bot_state_t *bs, char *s) {
+ BotRecordNodeSwitch(bs, "battle NBG", "", s);
+ bs->ainode = AINode_Battle_NBG;
+}
+
+/*
+==================
+AINode_Battle_NBG
+==================
+*/
+int AINode_Battle_NBG(bot_state_t *bs) {
+ int areanum;
+ bot_goal_t goal;
+ aas_entityinfo_t entinfo;
+ bot_moveresult_t moveresult;
+ float attack_skill;
+ vec3_t target, dir;
+
+ if (BotIsObserver(bs)) {
+ AIEnter_Observer(bs, "battle nbg: observer");
+ return qfalse;
+ }
+ //if in the intermission
+ if (BotIntermission(bs)) {
+ AIEnter_Intermission(bs, "battle nbg: intermission");
+ return qfalse;
+ }
+ //respawn if dead
+ if (BotIsDead(bs)) {
+ AIEnter_Respawn(bs, "battle nbg: bot dead");
+ return qfalse;
+ }
+ //if no enemy
+ if (bs->enemy < 0) {
+ AIEnter_Seek_NBG(bs, "battle nbg: no enemy");
+ return qfalse;
+ }
+ //
+ BotEntityInfo(bs->enemy, &entinfo);
+ if (EntityIsDead(&entinfo)) {
+ AIEnter_Seek_NBG(bs, "battle nbg: enemy dead");
+ return qfalse;
+ }
+ //
+ bs->tfl = TFL_DEFAULT;
+ if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
+ //if in lava or slime the bot should be able to get out
+ if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
+ //
+ if (BotCanAndWantsToRocketJump(bs)) {
+ bs->tfl |= TFL_ROCKETJUMP;
+ }
+ //map specific code
+ BotMapScripts(bs);
+ //update the last time the enemy was visible
+ if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
+ bs->enemyvisible_time = FloatTime();
+ VectorCopy(entinfo.origin, target);
+ // if not a player enemy
+ if (bs->enemy >= MAX_CLIENTS) {
+ // if attacking an obelisk
+ if ( bs->enemy == redobelisk.entitynum ||
+ bs->enemy == blueobelisk.entitynum ) {
+ target[2] += 16;
+ }
+ }
+ //update the reachability area and origin if possible
+ areanum = BotPointAreaNum(target);
+ if (areanum && trap_AAS_AreaReachability(areanum)) {
+ VectorCopy(target, bs->lastenemyorigin);
+ bs->lastenemyareanum = areanum;
+ }
+ }
+ //if the bot has no goal or touches the current goal
+ if (!trap_BotGetTopGoal(bs->gs, &goal)) {
+ bs->nbg_time = 0;
+ }
+ else if (BotReachedGoal(bs, &goal)) {
+ bs->nbg_time = 0;
+ }
+ //
+ if (bs->nbg_time < FloatTime()) {
+ //pop the current goal from the stack
+ trap_BotPopGoal(bs->gs);
+ //if the bot still has a goal
+ if (trap_BotGetTopGoal(bs->gs, &goal))
+ AIEnter_Battle_Retreat(bs, "battle nbg: time out");
+ else
+ AIEnter_Battle_Fight(bs, "battle nbg: time out");
+ //
+ return qfalse;
+ }
+ //initialize the movement state
+ BotSetupForMovement(bs);
+ //move towards the goal
+ trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
+ //if the movement failed
+ if (moveresult.failure) {
+ //reset the avoid reach, otherwise bot is stuck in current area
+ trap_BotResetAvoidReach(bs->ms);
+ //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
+ bs->nbg_time = 0;
+ }
+ //
+ BotAIBlocked(bs, &moveresult, qfalse);
+ //update the attack inventory values
+ BotUpdateBattleInventory(bs, bs->enemy);
+ //choose the best weapon to fight with
+ BotChooseWeapon(bs);
+ //if the view is fixed for the movement
+ if (moveresult.flags & (MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
+ VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
+ }
+ else if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET)
+ && !(bs->flags & BFL_IDEALVIEWSET)) {
+ attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1);
+ //if the bot is skilled anough and the enemy is visible
+ if (attack_skill > 0.3) {
+ //&& BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)
+ BotAimAtEnemy(bs);
+ }
+ else {
+ if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
+ VectorSubtract(target, bs->origin, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ }
+ else {
+ vectoangles(moveresult.movedir, bs->ideal_viewangles);
+ }
+ bs->ideal_viewangles[2] *= 0.5;
+ }
+ }
+ //if the weapon is used for the bot movement
+ if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
+ //attack the enemy if possible
+ BotCheckAttack(bs);
+ //
+ return qtrue;
+}
+
diff --git a/engine/code/game/ai_dmnet.h b/code/game/ai_dmnet.h
similarity index 100%
rename from engine/code/game/ai_dmnet.h
rename to code/game/ai_dmnet.h
diff --git a/code/game/ai_dmq3.c b/code/game/ai_dmq3.c
new file mode 100644
index 0000000..f8c4173
--- /dev/null
+++ b/code/game/ai_dmq3.c
@@ -0,0 +1,5580 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+/*****************************************************************************
+ * name: ai_dmq3.c
+ *
+ * desc: Quake3 bot AI
+ *
+ * $Archive: /MissionPack/code/game/ai_dmq3.c $
+ *
+ *****************************************************************************/
+
+
+#include "g_local.h"
+#include "../botlib/botlib.h"
+#include "../botlib/be_aas.h"
+#include "../botlib/be_ea.h"
+#include "../botlib/be_ai_char.h"
+#include "../botlib/be_ai_chat.h"
+#include "../botlib/be_ai_gen.h"
+#include "../botlib/be_ai_goal.h"
+#include "../botlib/be_ai_move.h"
+#include "../botlib/be_ai_weap.h"
+//
+#include "ai_main.h"
+#include "ai_dmq3.h"
+#include "ai_chat.h"
+#include "ai_cmd.h"
+#include "ai_dmnet.h"
+#include "ai_team.h"
+//
+#include "chars.h" //characteristics
+#include "inv.h" //indexes into the inventory
+#include "syn.h" //synonyms
+#include "match.h" //string matching types and vars
+
+// for the voice chats
+#include "../../ui/menudef.h" // sos001205 - for q3_ui also
+
+// from aasfile.h
+#define AREACONTENTS_MOVER 1024
+#define AREACONTENTS_MODELNUMSHIFT 24
+#define AREACONTENTS_MAXMODELNUM 0xFF
+#define AREACONTENTS_MODELNUM (AREACONTENTS_MAXMODELNUM << AREACONTENTS_MODELNUMSHIFT)
+
+#define IDEAL_ATTACKDIST 140
+
+#define MAX_WAYPOINTS 128
+
+#define MAX_EPAIRKEY 128
+//
+bot_waypoint_t botai_waypoints[MAX_WAYPOINTS];
+bot_waypoint_t *botai_freewaypoints;
+
+//NOTE: not using a cvars which can be updated because the game should be reloaded anyway
+int gametype; //game type
+int maxclients; //maximum number of clients
+
+vmCvar_t bot_grapple;
+vmCvar_t bot_rocketjump;
+vmCvar_t bot_fastchat;
+vmCvar_t bot_nochat;
+vmCvar_t bot_testrchat;
+vmCvar_t bot_challenge;
+vmCvar_t bot_predictobstacles;
+vmCvar_t g_spSkill;
+
+extern vmCvar_t bot_developer;
+
+vec3_t lastteleport_origin; //last teleport event origin
+float lastteleport_time; //last teleport event time
+int max_bspmodelindex; //maximum BSP model index
+
+//CTF flag goals
+bot_goal_t ctf_redflag;
+bot_goal_t ctf_blueflag;
+//Domination goals:
+bot_goal_t dom_points_bot[MAX_DOMINATION_POINTS];
+bot_goal_t ctf_neutralflag;
+bot_goal_t redobelisk;
+bot_goal_t blueobelisk;
+bot_goal_t neutralobelisk;
+
+#define MAX_ALTROUTEGOALS 32
+
+int altroutegoals_setup;
+aas_altroutegoal_t red_altroutegoals[MAX_ALTROUTEGOALS];
+int red_numaltroutegoals;
+aas_altroutegoal_t blue_altroutegoals[MAX_ALTROUTEGOALS];
+int blue_numaltroutegoals;
+
+/*
+==================
+untrap_BotGetLevelItemGoal
+ *same as trap_BotGetLevelItemGoal, but respects the gametype flag!
+==================
+ */
+int untrap_BotGetLevelItemGoal(int start, char *classname, void /* struct bot_goal_s */ *goal) {
+ static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester", "elimination", "ctf", "lms", "dd", "dom"};
+ char allowedGametypes[MAX_EPAIRKEY];
+ char *gametypeName;
+
+ start = trap_BotGetLevelItemGoal(start,classname,goal);
+ while(start>-1) {
+ if(!trap_AAS_ValueForBSPEpairKey(start,"gametype",allowedGametypes,MAX_EPAIRKEY))
+ return start; //No gametype flag
+ if( gametype >= GT_FFA && gametype < GT_MAX_GAME_TYPE ) {
+ gametypeName = gametypeNames[gametype];
+ if(strstr( allowedGametypes, gametypeName ))
+ {
+ //In gametype strig
+ return start;
+ }
+ }
+ else
+ return start;
+ start = trap_BotGetLevelItemGoal(start,classname,goal);
+ }
+ return -1;
+}
+
+/*
+==================
+BotSetUserInfo
+==================
+*/
+void BotSetUserInfo(bot_state_t *bs, char *key, char *value) {
+ char userinfo[MAX_INFO_STRING];
+
+ trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo));
+ Info_SetValueForKey(userinfo, key, value);
+ trap_SetUserinfo(bs->client, userinfo);
+ ClientUserinfoChanged( bs->client );
+}
+
+/*
+==================
+BotCTFCarryingFlag
+==================
+*/
+int BotCTFCarryingFlag(bot_state_t *bs) {
+ if (gametype != GT_CTF && gametype!=GT_CTF_ELIMINATION) return CTF_FLAG_NONE;
+
+ if (bs->inventory[INVENTORY_REDFLAG] > 0) return CTF_FLAG_RED;
+ else if (bs->inventory[INVENTORY_BLUEFLAG] > 0) return CTF_FLAG_BLUE;
+ return CTF_FLAG_NONE;
+}
+
+/*
+==================
+BotTeam
+==================
+*/
+int BotTeam(bot_state_t *bs) {
+ if (bs->client < 0 || bs->client >= MAX_CLIENTS) {
+ return qfalse;
+ }
+
+ if (level.clients[bs->client].sess.sessionTeam == TEAM_RED) {
+ return TEAM_RED;
+ } else if (level.clients[bs->client].sess.sessionTeam == TEAM_BLUE) {
+ return TEAM_BLUE;
+ }
+
+ return TEAM_FREE;
+}
+
+/*
+==================
+BotOppositeTeam
+==================
+*/
+int BotOppositeTeam(bot_state_t *bs) {
+ switch(BotTeam(bs)) {
+ case TEAM_RED: return TEAM_BLUE;
+ case TEAM_BLUE: return TEAM_RED;
+ default: return TEAM_FREE;
+ }
+}
+
+/*
+==================
+BotEnemyFlag
+==================
+*/
+bot_goal_t *BotEnemyFlag(bot_state_t *bs) {
+ if (BotTeam(bs) == TEAM_RED) {
+ return &ctf_blueflag;
+ }
+ else {
+ return &ctf_redflag;
+ }
+}
+
+/*
+==================
+BotTeamFlag
+==================
+*/
+bot_goal_t *BotTeamFlag(bot_state_t *bs) {
+ if (BotTeam(bs) == TEAM_RED) {
+ return &ctf_redflag;
+ }
+ else {
+ return &ctf_blueflag;
+ }
+}
+
+
+/*
+==================
+EntityIsDead
+==================
+*/
+qboolean EntityIsDead(aas_entityinfo_t *entinfo) {
+ playerState_t ps;
+
+ if (entinfo->number >= 0 && entinfo->number < MAX_CLIENTS) {
+ //retrieve the current client state
+ BotAI_GetClientState( entinfo->number, &ps );
+ if (ps.pm_type != PM_NORMAL) return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+EntityCarriesFlag
+==================
+*/
+qboolean EntityCarriesFlag(aas_entityinfo_t *entinfo) {
+ if ( entinfo->powerups & ( 1 << PW_REDFLAG ) )
+ return qtrue;
+ if ( entinfo->powerups & ( 1 << PW_BLUEFLAG ) )
+ return qtrue;
+ if ( entinfo->powerups & ( 1 << PW_NEUTRALFLAG ) )
+ return qtrue;
+ return qfalse;
+}
+
+/*
+==================
+EntityIsInvisible
+==================
+*/
+qboolean EntityIsInvisible(aas_entityinfo_t *entinfo) {
+ // the flag is always visible
+ if (EntityCarriesFlag(entinfo)) {
+ return qfalse;
+ }
+ if (entinfo->powerups & (1 << PW_INVIS)) {
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+EntityIsShooting
+==================
+*/
+qboolean EntityIsShooting(aas_entityinfo_t *entinfo) {
+ if (entinfo->flags & EF_FIRING) {
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+EntityIsChatting
+==================
+*/
+qboolean EntityIsChatting(aas_entityinfo_t *entinfo) {
+ if (entinfo->flags & EF_TALK) {
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+EntityHasQuad
+==================
+*/
+qboolean EntityHasQuad(aas_entityinfo_t *entinfo) {
+ if (entinfo->powerups & (1 << PW_QUAD)) {
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+EntityHasKamikze
+==================
+*/
+qboolean EntityHasKamikaze(aas_entityinfo_t *entinfo) {
+ if (entinfo->flags & EF_KAMIKAZE) {
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+EntityCarriesCubes
+==================
+*/
+qboolean EntityCarriesCubes(aas_entityinfo_t *entinfo) {
+ entityState_t state;
+
+ if (gametype != GT_HARVESTER)
+ return qfalse;
+ //FIXME: get this info from the aas_entityinfo_t ?
+ BotAI_GetEntityState(entinfo->number, &state);
+ if (state.generic1 > 0)
+ return qtrue;
+ return qfalse;
+}
+
+/*
+==================
+Bot1FCTFCarryingFlag
+==================
+*/
+int Bot1FCTFCarryingFlag(bot_state_t *bs) {
+ if (gametype != GT_1FCTF) return qfalse;
+
+ if (bs->inventory[INVENTORY_NEUTRALFLAG] > 0) return qtrue;
+ return qfalse;
+}
+
+/*
+==================
+BotHarvesterCarryingCubes
+==================
+*/
+int BotHarvesterCarryingCubes(bot_state_t *bs) {
+ if (gametype != GT_HARVESTER) return qfalse;
+
+ if (bs->inventory[INVENTORY_REDCUBE] > 0) return qtrue;
+ if (bs->inventory[INVENTORY_BLUECUBE] > 0) return qtrue;
+ return qfalse;
+}
+//#endif
+
+/*
+==================
+BotRememberLastOrderedTask
+==================
+*/
+void BotRememberLastOrderedTask(bot_state_t *bs) {
+ if (!bs->ordered) {
+ return;
+ }
+ bs->lastgoal_decisionmaker = bs->decisionmaker;
+ bs->lastgoal_ltgtype = bs->ltgtype;
+ memcpy(&bs->lastgoal_teamgoal, &bs->teamgoal, sizeof(bot_goal_t));
+ bs->lastgoal_teammate = bs->teammate;
+}
+
+/*
+==================
+BotSetTeamStatus
+==================
+*/
+void BotSetTeamStatus(bot_state_t *bs) {
+ int teamtask;
+ aas_entityinfo_t entinfo;
+
+ teamtask = TEAMTASK_PATROL;
+
+ switch(bs->ltgtype) {
+ case LTG_TEAMHELP:
+ break;
+ case LTG_TEAMACCOMPANY:
+ BotEntityInfo(bs->teammate, &entinfo);
+ if ( ( (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION || gametype == GT_1FCTF) && EntityCarriesFlag(&entinfo))
+ || ( gametype == GT_HARVESTER && EntityCarriesCubes(&entinfo)) ) {
+ teamtask = TEAMTASK_ESCORT;
+ }
+ else {
+ teamtask = TEAMTASK_FOLLOW;
+ }
+ break;
+ case LTG_DEFENDKEYAREA:
+ teamtask = TEAMTASK_DEFENSE;
+ break;
+ case LTG_GETFLAG:
+ teamtask = TEAMTASK_OFFENSE;
+ break;
+ case LTG_RUSHBASE:
+ teamtask = TEAMTASK_DEFENSE;
+ break;
+ case LTG_RETURNFLAG:
+ teamtask = TEAMTASK_RETRIEVE;
+ break;
+ case LTG_CAMP:
+ case LTG_CAMPORDER:
+ teamtask = TEAMTASK_CAMP;
+ break;
+ case LTG_PATROL:
+ teamtask = TEAMTASK_PATROL;
+ break;
+ case LTG_GETITEM:
+ teamtask = TEAMTASK_PATROL;
+ break;
+ case LTG_KILL:
+ teamtask = TEAMTASK_PATROL;
+ break;
+ case LTG_HARVEST:
+ teamtask = TEAMTASK_OFFENSE;
+ break;
+ case LTG_ATTACKENEMYBASE:
+ teamtask = TEAMTASK_OFFENSE;
+ break;
+ case LTG_POINTA:
+ if(BotTeam(bs) == TEAM_BLUE)
+ teamtask = TEAMTASK_OFFENSE;
+ else
+ teamtask = TEAMTASK_DEFENSE;
+ case LTG_POINTB:
+ if(BotTeam(bs) == TEAM_RED)
+ teamtask = TEAMTASK_OFFENSE;
+ else
+ teamtask = TEAMTASK_DEFENSE;
+ default:
+ teamtask = TEAMTASK_PATROL;
+ break;
+ }
+ BotSetUserInfo(bs, "teamtask", va("%d", teamtask));
+}
+
+/*
+==================
+BotSetLastOrderedTask
+==================
+*/
+int BotSetLastOrderedTask(bot_state_t *bs) {
+
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ // don't go back to returning the flag if it's at the base
+ if ( bs->lastgoal_ltgtype == LTG_RETURNFLAG ) {
+ if ( BotTeam(bs) == TEAM_RED ) {
+ if ( bs->redflagstatus == 0 ) {
+ bs->lastgoal_ltgtype = 0;
+ }
+ }
+ else {
+ if ( bs->blueflagstatus == 0 ) {
+ bs->lastgoal_ltgtype = 0;
+ }
+ }
+ }
+ }
+
+ if ( bs->lastgoal_ltgtype ) {
+ bs->decisionmaker = bs->lastgoal_decisionmaker;
+ bs->ordered = qtrue;
+ bs->ltgtype = bs->lastgoal_ltgtype;
+ memcpy(&bs->teamgoal, &bs->lastgoal_teamgoal, sizeof(bot_goal_t));
+ bs->teammate = bs->lastgoal_teammate;
+ bs->teamgoal_time = FloatTime() + 300;
+ BotSetTeamStatus(bs);
+ //
+ if ( gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ if ( bs->ltgtype == LTG_GETFLAG ) {
+ bot_goal_t *tb, *eb;
+ int tt, et;
+
+ tb = BotTeamFlag(bs);
+ eb = BotEnemyFlag(bs);
+ tt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, tb->areanum, TFL_DEFAULT);
+ et = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, eb->areanum, TFL_DEFAULT);
+ // if the travel time towards the enemy base is larger than towards our base
+ if (et > tt) {
+ //get an alternative route goal towards the enemy base
+ BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
+ }
+ }
+ }
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+BotRefuseOrder
+==================
+*/
+void BotRefuseOrder(bot_state_t *bs) {
+ if (!bs->ordered)
+ return;
+ // if the bot was ordered to do something
+ if ( bs->order_time && bs->order_time > FloatTime() - 10 ) {
+ trap_EA_Action(bs->client, ACTION_NEGATIVE);
+ BotVoiceChat(bs, bs->decisionmaker, VOICECHAT_NO);
+ bs->order_time = 0;
+ }
+}
+
+/*
+==================
+BotCTFSeekGoals
+==================
+*/
+void BotCTFSeekGoals(bot_state_t *bs) {
+ float rnd, l1, l2;
+ int flagstatus, c;
+ vec3_t dir;
+ aas_entityinfo_t entinfo;
+
+ //when carrying a flag in ctf the bot should rush to the base
+ if (BotCTFCarryingFlag(bs)) {
+ //if not already rushing to the base
+ if (bs->ltgtype != LTG_RUSHBASE) {
+ BotRefuseOrder(bs);
+ bs->ltgtype = LTG_RUSHBASE;
+ bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
+ bs->rushbaseaway_time = 0;
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //
+ switch(BotTeam(bs)) {
+ case TEAM_RED: VectorSubtract(bs->origin, ctf_blueflag.origin, dir); break;
+ case TEAM_BLUE: VectorSubtract(bs->origin, ctf_redflag.origin, dir); break;
+ default: VectorSet(dir, 999, 999, 999); break;
+ }
+ // if the bot picked up the flag very close to the enemy base
+ if ( VectorLength(dir) < 128 ) {
+ // get an alternative route goal through the enemy base
+ BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
+ } else {
+ // don't use any alt route goal, just get the hell out of the base
+ bs->altroutegoal.areanum = 0;
+ }
+ BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_OFFENSE));
+ BotVoiceChat(bs, -1, VOICECHAT_IHAVEFLAG);
+ }
+ else if (bs->rushbaseaway_time > FloatTime()) {
+ if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus;
+ else flagstatus = bs->blueflagstatus;
+ //if the flag is back
+ if (flagstatus == 0) {
+ bs->rushbaseaway_time = 0;
+ }
+ }
+ return;
+ }
+ // if the bot decided to follow someone
+ if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) {
+ // if the team mate being accompanied no longer carries the flag
+ BotEntityInfo(bs->teammate, &entinfo);
+ if (!EntityCarriesFlag(&entinfo)) {
+ bs->ltgtype = 0;
+ }
+ }
+ //
+ if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus;
+ else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus;
+ //if our team has the enemy flag and our flag is at the base
+ if (flagstatus == 1) {
+ //
+ if (bs->owndecision_time < FloatTime()) {
+ //if Not defending the base already
+ if (!(bs->ltgtype == LTG_DEFENDKEYAREA &&
+ (bs->teamgoal.number == ctf_redflag.number ||
+ bs->teamgoal.number == ctf_blueflag.number))) {
+ //if there is a visible team mate flag carrier
+ c = BotTeamFlagCarrierVisible(bs);
+ if (c >= 0 &&
+ // and not already following the team mate flag carrier
+ (bs->ltgtype != LTG_TEAMACCOMPANY || bs->teammate != c)) {
+ //
+ BotRefuseOrder(bs);
+ //follow the flag carrier
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //the team mate
+ bs->teammate = c;
+ //last time the team mate was visible
+ bs->teammatevisible_time = FloatTime();
+ //no message
+ bs->teammessage_time = 0;
+ //no arrive message
+ bs->arrive_time = 1;
+ //
+ BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
+ //get the team goal time
+ bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
+ bs->ltgtype = LTG_TEAMACCOMPANY;
+ bs->formation_dist = 3.5 * 32; //3.5 meter
+ BotSetTeamStatus(bs);
+ bs->owndecision_time = FloatTime() + 5;
+ }
+ }
+ }
+ return;
+ }
+ //if the enemy has our flag
+ else if (flagstatus == 2) {
+ //
+ if (bs->owndecision_time < FloatTime()) {
+ //if enemy flag carrier is visible
+ c = BotEnemyFlagCarrierVisible(bs);
+ if (c >= 0) {
+ //FIXME: fight enemy flag carrier
+ }
+ //if not already doing something important
+ if (bs->ltgtype != LTG_GETFLAG &&
+ bs->ltgtype != LTG_RETURNFLAG &&
+ bs->ltgtype != LTG_TEAMHELP &&
+ bs->ltgtype != LTG_TEAMACCOMPANY &&
+ bs->ltgtype != LTG_CAMPORDER &&
+ bs->ltgtype != LTG_PATROL &&
+ bs->ltgtype != LTG_GETITEM) {
+
+ BotRefuseOrder(bs);
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //
+ if (random() < 0.5) {
+ //go for the enemy flag
+ bs->ltgtype = LTG_GETFLAG;
+ }
+ else {
+ bs->ltgtype = LTG_RETURNFLAG;
+ }
+ //no team message
+ bs->teammessage_time = 0;
+ //set the time the bot will stop getting the flag
+ bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
+ //get an alternative route goal towards the enemy base
+ BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
+ //
+ BotSetTeamStatus(bs);
+ bs->owndecision_time = FloatTime() + 5;
+ }
+ }
+ return;
+ }
+ //if both flags Not at their bases
+ else if (flagstatus == 3) {
+ //
+ if (bs->owndecision_time < FloatTime()) {
+ // if not trying to return the flag and not following the team flag carrier
+ if ( bs->ltgtype != LTG_RETURNFLAG && bs->ltgtype != LTG_TEAMACCOMPANY ) {
+ //
+ c = BotTeamFlagCarrierVisible(bs);
+ // if there is a visible team mate flag carrier
+ if (c >= 0) {
+ BotRefuseOrder(bs);
+ //follow the flag carrier
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //the team mate
+ bs->teammate = c;
+ //last time the team mate was visible
+ bs->teammatevisible_time = FloatTime();
+ //no message
+ bs->teammessage_time = 0;
+ //no arrive message
+ bs->arrive_time = 1;
+ //
+ BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
+ //get the team goal time
+ bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
+ bs->ltgtype = LTG_TEAMACCOMPANY;
+ bs->formation_dist = 3.5 * 32; //3.5 meter
+ //
+ BotSetTeamStatus(bs);
+ bs->owndecision_time = FloatTime() + 5;
+ }
+ else {
+ BotRefuseOrder(bs);
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //get the enemy flag
+ bs->teammessage_time = FloatTime() + 2 * random();
+ //get the flag
+ bs->ltgtype = LTG_RETURNFLAG;
+ //set the time the bot will stop getting the flag
+ bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME;
+ //get an alternative route goal towards the enemy base
+ BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
+ //
+ BotSetTeamStatus(bs);
+ bs->owndecision_time = FloatTime() + 5;
+ }
+ }
+ }
+ return;
+ }
+ // don't just do something wait for the bot team leader to give orders
+ if (BotTeamLeader(bs)) {
+ return;
+ }
+ // if the bot is ordered to do something
+ if ( bs->lastgoal_ltgtype ) {
+ bs->teamgoal_time += 60;
+ }
+ // if the bot decided to do something on it's own and has a last ordered goal
+ if ( !bs->ordered && bs->lastgoal_ltgtype ) {
+ bs->ltgtype = 0;
+ }
+ //if already a CTF or team goal
+ if (bs->ltgtype == LTG_TEAMHELP ||
+ bs->ltgtype == LTG_TEAMACCOMPANY ||
+ bs->ltgtype == LTG_DEFENDKEYAREA ||
+ bs->ltgtype == LTG_GETFLAG ||
+ bs->ltgtype == LTG_RUSHBASE ||
+ bs->ltgtype == LTG_RETURNFLAG ||
+ bs->ltgtype == LTG_CAMPORDER ||
+ bs->ltgtype == LTG_PATROL ||
+ bs->ltgtype == LTG_GETITEM ||
+ bs->ltgtype == LTG_MAKELOVE_UNDER ||
+ bs->ltgtype == LTG_MAKELOVE_ONTOP) {
+ return;
+ }
+ //
+ if (BotSetLastOrderedTask(bs))
+ return;
+ //
+ if (bs->owndecision_time > FloatTime())
+ return;;
+ //if the bot is roaming
+ if (bs->ctfroam_time > FloatTime())
+ return;
+ //if the bot has anough aggression to decide what to do
+ if (BotAggression(bs) < 50)
+ return;
+ //set the time to send a message to the team mates
+ bs->teammessage_time = FloatTime() + 2 * random();
+ //
+ if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
+ if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
+ l1 = 0.7f;
+ }
+ else {
+ l1 = 0.2f;
+ }
+ l2 = 0.9f;
+ }
+ else {
+ l1 = 0.4f;
+ l2 = 0.7f;
+ }
+ //get the flag or defend the base
+ rnd = random();
+ if (rnd < l1 && ctf_redflag.areanum && ctf_blueflag.areanum) {
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ bs->ltgtype = LTG_GETFLAG;
+ //set the time the bot will stop getting the flag
+ bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
+ //get an alternative route goal towards the enemy base
+ BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
+ BotSetTeamStatus(bs);
+ }
+ else if (rnd < l2 && ctf_redflag.areanum && ctf_blueflag.areanum) {
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //
+ if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
+ else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
+ //set the ltg type
+ bs->ltgtype = LTG_DEFENDKEYAREA;
+ //set the time the bot stops defending the base
+ bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
+ bs->defendaway_time = 0;
+ BotSetTeamStatus(bs);
+ }
+ else {
+ bs->ltgtype = 0;
+ //set the time the bot will stop roaming
+ bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
+ BotSetTeamStatus(bs);
+ }
+ bs->owndecision_time = FloatTime() + 5;
+#ifdef DEBUG
+ BotPrintTeamGoal(bs);
+#endif //DEBUG
+}
+
+/*
+==================
+BotCTFRetreatGoals
+==================
+*/
+void BotCTFRetreatGoals(bot_state_t *bs) {
+ //when carrying a flag in ctf the bot should rush to the base
+ if (BotCTFCarryingFlag(bs)) {
+ //if not already rushing to the base
+ if (bs->ltgtype != LTG_RUSHBASE) {
+ BotRefuseOrder(bs);
+ bs->ltgtype = LTG_RUSHBASE;
+ bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
+ bs->rushbaseaway_time = 0;
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ BotSetTeamStatus(bs);
+ }
+ }
+}
+
+/*
+==================
+BotDomSeekGoals
+==================
+ */
+
+/*void BotDomSeekGoals(bot_state_t *bs) {
+ int index;
+ bs->ltgtype = LTG_DOMHOLD; //For debugging we are forcing roam
+
+ index=0;
+ //dom_points_bot[i]
+
+ if(bs->ltgtype == LTG_DOMHOLD) {
+ //index = 0;
+ index = ((rand()) % (level.domination_points_count));
+ }
+
+ //if(bs->ltgtype == LTG_DOMROAM) {
+
+ //}
+
+ memcpy(&bs->teamgoal, &dom_points_bot[index], sizeof(bot_goal_t));
+
+ BotAlternateRoute(bs, &bs->teamgoal);
+
+ BotSetTeamStatus(bs);
+}*/
+
+/*
+==================
+BotDDSeekGoals
+==================
+*/
+
+void BotDDSeekGoals(bot_state_t *bs) {
+
+ /*if (bs->ltgtype == LTG_TEAMHELP ||
+ bs->ltgtype == LTG_TEAMACCOMPANY ||
+ bs->ltgtype == LTG_CAMPORDER ||
+ bs->ltgtype == LTG_PATROL ||
+ bs->ltgtype == LTG_GETITEM) {
+ return;
+ }*/
+
+ if(bs->ltgtype == LTG_POINTA)
+ memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
+ if(bs->ltgtype == LTG_POINTB)
+ memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
+
+ if(bs->ltgtype == LTG_POINTA || bs->ltgtype == LTG_POINTB)
+ return;
+
+ if(rand()%2==0)
+ bs->ltgtype = LTG_POINTA;
+ else
+ bs->ltgtype = LTG_POINTB;
+
+ if(bs->ltgtype == LTG_POINTA) {
+ memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
+ if(BotTeam(bs) == TEAM_BLUE)
+ BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_OFFENSE));
+ else
+ BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_DEFENSE));
+ } else
+ if(bs->ltgtype == LTG_POINTB) {
+ memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
+ if(BotTeam(bs) == TEAM_RED)
+ BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_OFFENSE));
+ else
+ BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_DEFENSE));
+ }
+
+
+}
+
+/*
+==================
+Bot1FCTFSeekGoals
+==================
+*/
+void Bot1FCTFSeekGoals(bot_state_t *bs) {
+ aas_entityinfo_t entinfo;
+ float rnd, l1, l2;
+ int c;
+
+ //when carrying a flag in ctf the bot should rush to the base
+ if (Bot1FCTFCarryingFlag(bs)) {
+ //if not already rushing to the base
+ if (bs->ltgtype != LTG_RUSHBASE) {
+ BotRefuseOrder(bs);
+ bs->ltgtype = LTG_RUSHBASE;
+ bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
+ bs->rushbaseaway_time = 0;
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //get an alternative route goal towards the enemy base
+ BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
+ //
+ BotSetTeamStatus(bs);
+ BotVoiceChat(bs, -1, VOICECHAT_IHAVEFLAG);
+ }
+ return;
+ }
+ // if the bot decided to follow someone
+ if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) {
+ // if the team mate being accompanied no longer carries the flag
+ BotEntityInfo(bs->teammate, &entinfo);
+ if (!EntityCarriesFlag(&entinfo)) {
+ bs->ltgtype = 0;
+ }
+ }
+ //our team has the flag
+ if (bs->neutralflagstatus == 1) {
+ if (bs->owndecision_time < FloatTime()) {
+ // if not already following someone
+ if (bs->ltgtype != LTG_TEAMACCOMPANY) {
+ //if there is a visible team mate flag carrier
+ c = BotTeamFlagCarrierVisible(bs);
+ if (c >= 0) {
+ BotRefuseOrder(bs);
+ //follow the flag carrier
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //the team mate
+ bs->teammate = c;
+ //last time the team mate was visible
+ bs->teammatevisible_time = FloatTime();
+ //no message
+ bs->teammessage_time = 0;
+ //no arrive message
+ bs->arrive_time = 1;
+ //
+ BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
+ //get the team goal time
+ bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
+ bs->ltgtype = LTG_TEAMACCOMPANY;
+ bs->formation_dist = 3.5 * 32; //3.5 meter
+ BotSetTeamStatus(bs);
+ bs->owndecision_time = FloatTime() + 5;
+ return;
+ }
+ }
+ //if already a CTF or team goal
+ if (bs->ltgtype == LTG_TEAMHELP ||
+ bs->ltgtype == LTG_TEAMACCOMPANY ||
+ bs->ltgtype == LTG_DEFENDKEYAREA ||
+ bs->ltgtype == LTG_GETFLAG ||
+ bs->ltgtype == LTG_RUSHBASE ||
+ bs->ltgtype == LTG_CAMPORDER ||
+ bs->ltgtype == LTG_PATROL ||
+ bs->ltgtype == LTG_ATTACKENEMYBASE ||
+ bs->ltgtype == LTG_GETITEM ||
+ bs->ltgtype == LTG_MAKELOVE_UNDER ||
+ bs->ltgtype == LTG_MAKELOVE_ONTOP) {
+ return;
+ }
+ //if not already attacking the enemy base
+ if (bs->ltgtype != LTG_ATTACKENEMYBASE) {
+ BotRefuseOrder(bs);
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //
+ if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
+ else memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
+ //set the ltg type
+ bs->ltgtype = LTG_ATTACKENEMYBASE;
+ //set the time the bot will stop getting the flag
+ bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
+ BotSetTeamStatus(bs);
+ bs->owndecision_time = FloatTime() + 5;
+ }
+ }
+ return;
+ }
+ //enemy team has the flag
+ else if (bs->neutralflagstatus == 2) {
+ if (bs->owndecision_time < FloatTime()) {
+ c = BotEnemyFlagCarrierVisible(bs);
+ if (c >= 0) {
+ //FIXME: attack enemy flag carrier
+ }
+ //if already a CTF or team goal
+ if (bs->ltgtype == LTG_TEAMHELP ||
+ bs->ltgtype == LTG_TEAMACCOMPANY ||
+ bs->ltgtype == LTG_CAMPORDER ||
+ bs->ltgtype == LTG_PATROL ||
+ bs->ltgtype == LTG_GETITEM) {
+ return;
+ }
+ // if not already defending the base
+ if (bs->ltgtype != LTG_DEFENDKEYAREA) {
+ BotRefuseOrder(bs);
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //
+ if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
+ else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
+ //set the ltg type
+ bs->ltgtype = LTG_DEFENDKEYAREA;
+ //set the time the bot stops defending the base
+ bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
+ bs->defendaway_time = 0;
+ BotSetTeamStatus(bs);
+ bs->owndecision_time = FloatTime() + 5;
+ }
+ }
+ return;
+ }
+ // don't just do something wait for the bot team leader to give orders
+ if (BotTeamLeader(bs)) {
+ return;
+ }
+ // if the bot is ordered to do something
+ if ( bs->lastgoal_ltgtype ) {
+ bs->teamgoal_time += 60;
+ }
+ // if the bot decided to do something on it's own and has a last ordered goal
+ if ( !bs->ordered && bs->lastgoal_ltgtype ) {
+ bs->ltgtype = 0;
+ }
+ //if already a CTF or team goal
+ if (bs->ltgtype == LTG_TEAMHELP ||
+ bs->ltgtype == LTG_TEAMACCOMPANY ||
+ bs->ltgtype == LTG_DEFENDKEYAREA ||
+ bs->ltgtype == LTG_GETFLAG ||
+ bs->ltgtype == LTG_RUSHBASE ||
+ bs->ltgtype == LTG_RETURNFLAG ||
+ bs->ltgtype == LTG_CAMPORDER ||
+ bs->ltgtype == LTG_PATROL ||
+ bs->ltgtype == LTG_ATTACKENEMYBASE ||
+ bs->ltgtype == LTG_GETITEM ||
+ bs->ltgtype == LTG_MAKELOVE_UNDER ||
+ bs->ltgtype == LTG_MAKELOVE_ONTOP) {
+ return;
+ }
+ //
+ if (BotSetLastOrderedTask(bs))
+ return;
+ //
+ if (bs->owndecision_time > FloatTime())
+ return;;
+ //if the bot is roaming
+ if (bs->ctfroam_time > FloatTime())
+ return;
+ //if the bot has anough aggression to decide what to do
+ if (BotAggression(bs) < 50)
+ return;
+ //set the time to send a message to the team mates
+ bs->teammessage_time = FloatTime() + 2 * random();
+ //
+ if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
+ if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
+ l1 = 0.7f;
+ }
+ else {
+ l1 = 0.2f;
+ }
+ l2 = 0.9f;
+ }
+ else {
+ l1 = 0.4f;
+ l2 = 0.7f;
+ }
+ //get the flag or defend the base
+ rnd = random();
+ if (rnd < l1 && ctf_neutralflag.areanum) {
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ bs->ltgtype = LTG_GETFLAG;
+ //set the time the bot will stop getting the flag
+ bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
+ BotSetTeamStatus(bs);
+ }
+ else if (rnd < l2 && ctf_redflag.areanum && ctf_blueflag.areanum) {
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //
+ if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
+ else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
+ //set the ltg type
+ bs->ltgtype = LTG_DEFENDKEYAREA;
+ //set the time the bot stops defending the base
+ bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
+ bs->defendaway_time = 0;
+ BotSetTeamStatus(bs);
+ }
+ else {
+ bs->ltgtype = 0;
+ //set the time the bot will stop roaming
+ bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
+ BotSetTeamStatus(bs);
+ }
+ bs->owndecision_time = FloatTime() + 5;
+#ifdef DEBUG
+ BotPrintTeamGoal(bs);
+#endif //DEBUG
+}
+
+/*
+==================
+Bot1FCTFRetreatGoals
+==================
+*/
+void Bot1FCTFRetreatGoals(bot_state_t *bs) {
+ //when carrying a flag in ctf the bot should rush to the enemy base
+ if (Bot1FCTFCarryingFlag(bs)) {
+ //if not already rushing to the base
+ if (bs->ltgtype != LTG_RUSHBASE) {
+ BotRefuseOrder(bs);
+ bs->ltgtype = LTG_RUSHBASE;
+ bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
+ bs->rushbaseaway_time = 0;
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //get an alternative route goal towards the enemy base
+ BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
+ BotSetTeamStatus(bs);
+ }
+ }
+}
+
+/*
+==================
+BotObeliskSeekGoals
+==================
+*/
+void BotObeliskSeekGoals(bot_state_t *bs) {
+ float rnd, l1, l2;
+
+ // don't just do something wait for the bot team leader to give orders
+ if (BotTeamLeader(bs)) {
+ return;
+ }
+ // if the bot is ordered to do something
+ if ( bs->lastgoal_ltgtype ) {
+ bs->teamgoal_time += 60;
+ }
+ //if already a team goal
+ if (bs->ltgtype == LTG_TEAMHELP ||
+ bs->ltgtype == LTG_TEAMACCOMPANY ||
+ bs->ltgtype == LTG_DEFENDKEYAREA ||
+ bs->ltgtype == LTG_GETFLAG ||
+ bs->ltgtype == LTG_RUSHBASE ||
+ bs->ltgtype == LTG_RETURNFLAG ||
+ bs->ltgtype == LTG_CAMPORDER ||
+ bs->ltgtype == LTG_PATROL ||
+ bs->ltgtype == LTG_ATTACKENEMYBASE ||
+ bs->ltgtype == LTG_GETITEM ||
+ bs->ltgtype == LTG_MAKELOVE_UNDER ||
+ bs->ltgtype == LTG_MAKELOVE_ONTOP) {
+ return;
+ }
+ //
+ if (BotSetLastOrderedTask(bs))
+ return;
+ //if the bot is roaming
+ if (bs->ctfroam_time > FloatTime())
+ return;
+ //if the bot has anough aggression to decide what to do
+ if (BotAggression(bs) < 50)
+ return;
+ //set the time to send a message to the team mates
+ bs->teammessage_time = FloatTime() + 2 * random();
+ //
+ if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
+ if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
+ l1 = 0.7f;
+ }
+ else {
+ l1 = 0.2f;
+ }
+ l2 = 0.9f;
+ }
+ else {
+ l1 = 0.4f;
+ l2 = 0.7f;
+ }
+ //get the flag or defend the base
+ rnd = random();
+ if (rnd < l1 && redobelisk.areanum && blueobelisk.areanum) {
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //
+ if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
+ else memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
+ //set the ltg type
+ bs->ltgtype = LTG_ATTACKENEMYBASE;
+ //set the time the bot will stop attacking the enemy base
+ bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
+ //get an alternate route goal towards the enemy base
+ BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
+ BotSetTeamStatus(bs);
+ }
+ else if (rnd < l2 && redobelisk.areanum && blueobelisk.areanum) {
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //
+ if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
+ else memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
+ //set the ltg type
+ bs->ltgtype = LTG_DEFENDKEYAREA;
+ //set the time the bot stops defending the base
+ bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
+ bs->defendaway_time = 0;
+ BotSetTeamStatus(bs);
+ }
+ else {
+ bs->ltgtype = 0;
+ //set the time the bot will stop roaming
+ bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
+ BotSetTeamStatus(bs);
+ }
+}
+
+/*
+==================
+BotGoHarvest
+==================
+*/
+void BotGoHarvest(bot_state_t *bs) {
+ //
+ if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
+ else memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
+ //set the ltg type
+ bs->ltgtype = LTG_HARVEST;
+ //set the time the bot will stop harvesting
+ bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME;
+ bs->harvestaway_time = 0;
+ BotSetTeamStatus(bs);
+}
+
+/*
+==================
+BotObeliskRetreatGoals
+==================
+*/
+void BotObeliskRetreatGoals(bot_state_t *bs) {
+ //nothing special
+}
+
+/*
+==================
+BotHarvesterSeekGoals
+==================
+*/
+void BotHarvesterSeekGoals(bot_state_t *bs) {
+ aas_entityinfo_t entinfo;
+ float rnd, l1, l2;
+ int c;
+
+ //when carrying cubes in harvester the bot should rush to the base
+ if (BotHarvesterCarryingCubes(bs)) {
+ //if not already rushing to the base
+ if (bs->ltgtype != LTG_RUSHBASE) {
+ BotRefuseOrder(bs);
+ bs->ltgtype = LTG_RUSHBASE;
+ bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
+ bs->rushbaseaway_time = 0;
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //get an alternative route goal towards the enemy base
+ BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
+ //
+ BotSetTeamStatus(bs);
+ }
+ return;
+ }
+ // don't just do something wait for the bot team leader to give orders
+ if (BotTeamLeader(bs)) {
+ return;
+ }
+ // if the bot decided to follow someone
+ if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) {
+ // if the team mate being accompanied no longer carries the flag
+ BotEntityInfo(bs->teammate, &entinfo);
+ if (!EntityCarriesCubes(&entinfo)) {
+ bs->ltgtype = 0;
+ }
+ }
+ // if the bot is ordered to do something
+ if ( bs->lastgoal_ltgtype ) {
+ bs->teamgoal_time += 60;
+ }
+ //if not yet doing something
+ if (bs->ltgtype == LTG_TEAMHELP ||
+ bs->ltgtype == LTG_TEAMACCOMPANY ||
+ bs->ltgtype == LTG_DEFENDKEYAREA ||
+ bs->ltgtype == LTG_GETFLAG ||
+ bs->ltgtype == LTG_CAMPORDER ||
+ bs->ltgtype == LTG_PATROL ||
+ bs->ltgtype == LTG_ATTACKENEMYBASE ||
+ bs->ltgtype == LTG_HARVEST ||
+ bs->ltgtype == LTG_GETITEM ||
+ bs->ltgtype == LTG_MAKELOVE_UNDER ||
+ bs->ltgtype == LTG_MAKELOVE_ONTOP) {
+ return;
+ }
+ //
+ if (BotSetLastOrderedTask(bs))
+ return;
+ //if the bot is roaming
+ if (bs->ctfroam_time > FloatTime())
+ return;
+ //if the bot has anough aggression to decide what to do
+ if (BotAggression(bs) < 50)
+ return;
+ //set the time to send a message to the team mates
+ bs->teammessage_time = FloatTime() + 2 * random();
+ //
+ c = BotEnemyCubeCarrierVisible(bs);
+ if (c >= 0) {
+ //FIXME: attack enemy cube carrier
+ }
+ if (bs->ltgtype != LTG_TEAMACCOMPANY) {
+ //if there is a visible team mate carrying cubes
+ c = BotTeamCubeCarrierVisible(bs);
+ if (c >= 0) {
+ //follow the team mate carrying cubes
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //the team mate
+ bs->teammate = c;
+ //last time the team mate was visible
+ bs->teammatevisible_time = FloatTime();
+ //no message
+ bs->teammessage_time = 0;
+ //no arrive message
+ bs->arrive_time = 1;
+ //
+ BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
+ //get the team goal time
+ bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
+ bs->ltgtype = LTG_TEAMACCOMPANY;
+ bs->formation_dist = 3.5 * 32; //3.5 meter
+ BotSetTeamStatus(bs);
+ return;
+ }
+ }
+ //
+ if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
+ if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
+ l1 = 0.7f;
+ }
+ else {
+ l1 = 0.2f;
+ }
+ l2 = 0.9f;
+ }
+ else {
+ l1 = 0.4f;
+ l2 = 0.7f;
+ }
+ //
+ rnd = random();
+ if (rnd < l1 && redobelisk.areanum && blueobelisk.areanum) {
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ BotGoHarvest(bs);
+ }
+ else if (rnd < l2 && redobelisk.areanum && blueobelisk.areanum) {
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ //
+ if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
+ else memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
+ //set the ltg type
+ bs->ltgtype = LTG_DEFENDKEYAREA;
+ //set the time the bot stops defending the base
+ bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
+ bs->defendaway_time = 0;
+ BotSetTeamStatus(bs);
+ }
+ else {
+ bs->ltgtype = 0;
+ //set the time the bot will stop roaming
+ bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
+ BotSetTeamStatus(bs);
+ }
+}
+
+/*
+==================
+BotHarvesterRetreatGoals
+==================
+*/
+void BotHarvesterRetreatGoals(bot_state_t *bs) {
+ //when carrying cubes in harvester the bot should rush to the base
+ if (BotHarvesterCarryingCubes(bs)) {
+ //if not already rushing to the base
+ if (bs->ltgtype != LTG_RUSHBASE) {
+ BotRefuseOrder(bs);
+ bs->ltgtype = LTG_RUSHBASE;
+ bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
+ bs->rushbaseaway_time = 0;
+ bs->decisionmaker = bs->client;
+ bs->ordered = qfalse;
+ BotSetTeamStatus(bs);
+ }
+ return;
+ }
+}
+//#endif
+
+/*
+==================
+BotTeamGoals
+==================
+*/
+void BotTeamGoals(bot_state_t *bs, int retreat) {
+
+ if ( retreat ) {
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION ) {
+ BotCTFRetreatGoals(bs);
+ }
+ else if (gametype == GT_1FCTF) {
+ Bot1FCTFRetreatGoals(bs);
+ }
+ else if (gametype == GT_OBELISK) {
+ BotObeliskRetreatGoals(bs);
+ }
+ else if (gametype == GT_HARVESTER) {
+ BotHarvesterRetreatGoals(bs);
+ }
+ }
+ else {
+ if (gametype == GT_CTF|| gametype == GT_CTF_ELIMINATION) {
+ //decide what to do in CTF mode
+ BotCTFSeekGoals(bs);
+ }
+ else if (gametype == GT_1FCTF) {
+ Bot1FCTFSeekGoals(bs);
+ }
+ else if (gametype == GT_OBELISK) {
+ BotObeliskSeekGoals(bs);
+ }
+ else if (gametype == GT_HARVESTER) {
+ BotHarvesterSeekGoals(bs);
+ }
+ }
+
+ if(gametype == GT_DOUBLE_D) //Don't care about retreat
+ BotDDSeekGoals(bs);
+
+ //if(gametype == GT_DOMINATION) //Don't care about retreat
+ // BotDomSeekGoals(bs);
+
+ // reset the order time which is used to see if
+ // we decided to refuse an order
+ bs->order_time = 0;
+}
+
+/*
+==================
+BotPointAreaNum
+==================
+*/
+int BotPointAreaNum(vec3_t origin) {
+ int areanum, numareas, areas[10];
+ vec3_t end;
+
+ areanum = trap_AAS_PointAreaNum(origin);
+ if (areanum) return areanum;
+ VectorCopy(origin, end);
+ end[2] += 10;
+ numareas = trap_AAS_TraceAreas(origin, end, areas, NULL, 10);
+ if (numareas > 0) return areas[0];
+ return 0;
+}
+
+/*
+==================
+ClientName
+==================
+*/
+char *ClientName(int client, char *name, int size) {
+ char buf[MAX_INFO_STRING];
+
+ if (client < 0 || client >= MAX_CLIENTS) {
+ BotAI_Print(PRT_ERROR, "ClientName: client out of range\n");
+ return "[client out of range]";
+ }
+ trap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf));
+ strncpy(name, Info_ValueForKey(buf, "n"), size-1);
+ name[size-1] = '\0';
+ Q_CleanStr( name );
+ return name;
+}
+
+/*
+==================
+ClientSkin
+==================
+*/
+char *ClientSkin(int client, char *skin, int size) {
+ char buf[MAX_INFO_STRING];
+
+ if (client < 0 || client >= MAX_CLIENTS) {
+ BotAI_Print(PRT_ERROR, "ClientSkin: client out of range\n");
+ return "[client out of range]";
+ }
+ trap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf));
+ strncpy(skin, Info_ValueForKey(buf, "model"), size-1);
+ skin[size-1] = '\0';
+ return skin;
+}
+
+/*
+==================
+ClientFromName
+==================
+*/
+int ClientFromName(char *name) {
+ int i;
+ char buf[MAX_INFO_STRING];
+ static int maxclients;
+
+ if (!maxclients)
+ maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ Q_CleanStr( buf );
+ if (!Q_stricmp(Info_ValueForKey(buf, "n"), name)) return i;
+ }
+ return -1;
+}
+
+/*
+==================
+ClientOnSameTeamFromName
+==================
+*/
+int ClientOnSameTeamFromName(bot_state_t *bs, char *name) {
+ int i;
+ char buf[MAX_INFO_STRING];
+ static int maxclients;
+
+ if (!maxclients)
+ maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ if (!BotSameTeam(bs, i))
+ continue;
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ Q_CleanStr( buf );
+ if (!Q_stricmp(Info_ValueForKey(buf, "n"), name)) return i;
+ }
+ return -1;
+}
+
+/*
+==================
+stristr
+==================
+*/
+char *stristr(char *str, char *charset) {
+ int i;
+
+ while(*str) {
+ for (i = 0; charset[i] && str[i]; i++) {
+ if (toupper(charset[i]) != toupper(str[i])) break;
+ }
+ if (!charset[i]) return str;
+ str++;
+ }
+ return NULL;
+}
+
+/*
+==================
+EasyClientName
+==================
+*/
+char *EasyClientName(int client, char *buf, int size) {
+ int i;
+ char *str1, *str2, *ptr, c;
+ char name[128];
+
+ ClientName(client, name, sizeof(name));
+ for (i = 0; name[i]; i++) name[i] &= 127;
+ //remove all spaces
+ for (ptr = strstr(name, " "); ptr; ptr = strstr(name, " ")) {
+ memmove(ptr, ptr+1, strlen(ptr+1)+1);
+ }
+ //check for [x] and ]x[ clan names
+ str1 = strstr(name, "[");
+ str2 = strstr(name, "]");
+ if (str1 && str2) {
+ if (str2 > str1) memmove(str1, str2+1, strlen(str2+1)+1);
+ else memmove(str2, str1+1, strlen(str1+1)+1);
+ }
+ //remove Mr prefix
+ if ((name[0] == 'm' || name[0] == 'M') &&
+ (name[1] == 'r' || name[1] == 'R')) {
+ memmove(name, name+2, strlen(name+2)+1);
+ }
+ //only allow lower case alphabet characters
+ ptr = name;
+ while(*ptr) {
+ c = *ptr;
+ if ((c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') || c == '_') {
+ ptr++;
+ }
+ else if (c >= 'A' && c <= 'Z') {
+ *ptr += 'a' - 'A';
+ ptr++;
+ }
+ else {
+ memmove(ptr, ptr+1, strlen(ptr + 1)+1);
+ }
+ }
+ strncpy(buf, name, size-1);
+ buf[size-1] = '\0';
+ return buf;
+}
+
+/*
+==================
+BotSynonymContext
+==================
+*/
+int BotSynonymContext(bot_state_t *bs) {
+ int context;
+
+ context = CONTEXT_NORMAL|CONTEXT_NEARBYITEM|CONTEXT_NAMES;
+ //
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION
+ || gametype == GT_1FCTF
+ ) {
+ if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_CTFREDTEAM;
+ else context |= CONTEXT_CTFBLUETEAM;
+ }
+ else if (gametype == GT_OBELISK) {
+ if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_OBELISKREDTEAM;
+ else context |= CONTEXT_OBELISKBLUETEAM;
+ }
+ else if (gametype == GT_HARVESTER) {
+ if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_HARVESTERREDTEAM;
+ else context |= CONTEXT_HARVESTERBLUETEAM;
+ }
+ return context;
+}
+
+/*
+==================
+BotChooseWeapon
+==================
+*/
+void BotChooseWeapon(bot_state_t *bs) {
+ int newweaponnum;
+
+ if (bs->cur_ps.weaponstate == WEAPON_RAISING ||
+ bs->cur_ps.weaponstate == WEAPON_DROPPING) {
+ trap_EA_SelectWeapon(bs->client, bs->weaponnum);
+ }
+ else {
+ if(g_instantgib.integer)
+ newweaponnum = WP_RAILGUN;
+ else if(g_rockets.integer)
+ newweaponnum = WP_ROCKET_LAUNCHER;
+ else
+ newweaponnum = trap_BotChooseBestFightWeapon(bs->ws, bs->inventory);
+ if (bs->weaponnum != newweaponnum) bs->weaponchange_time = FloatTime();
+ bs->weaponnum = newweaponnum;
+ //BotAI_Print(PRT_MESSAGE, "bs->weaponnum = %d\n", bs->weaponnum);
+ trap_EA_SelectWeapon(bs->client, bs->weaponnum);
+ }
+}
+
+/*
+==================
+BotSetupForMovement
+==================
+*/
+void BotSetupForMovement(bot_state_t *bs) {
+ bot_initmove_t initmove;
+
+ memset(&initmove, 0, sizeof(bot_initmove_t));
+ VectorCopy(bs->cur_ps.origin, initmove.origin);
+ VectorCopy(bs->cur_ps.velocity, initmove.velocity);
+ VectorClear(initmove.viewoffset);
+ initmove.viewoffset[2] += bs->cur_ps.viewheight;
+ initmove.entitynum = bs->entitynum;
+ initmove.client = bs->client;
+ initmove.thinktime = bs->thinktime;
+ //set the onground flag
+ if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) initmove.or_moveflags |= MFL_ONGROUND;
+ //set the teleported flag
+ if ((bs->cur_ps.pm_flags & PMF_TIME_KNOCKBACK) && (bs->cur_ps.pm_time > 0)) {
+ initmove.or_moveflags |= MFL_TELEPORTED;
+ }
+ //set the waterjump flag
+ if ((bs->cur_ps.pm_flags & PMF_TIME_WATERJUMP) && (bs->cur_ps.pm_time > 0)) {
+ initmove.or_moveflags |= MFL_WATERJUMP;
+ }
+ //set presence type
+ if (bs->cur_ps.pm_flags & PMF_DUCKED) initmove.presencetype = PRESENCE_CROUCH;
+ else initmove.presencetype = PRESENCE_NORMAL;
+ //
+ if (bs->walker > 0.5) initmove.or_moveflags |= MFL_WALK;
+ //
+ VectorCopy(bs->viewangles, initmove.viewangles);
+ //
+ trap_BotInitMoveState(bs->ms, &initmove);
+}
+
+/*
+==================
+BotCheckItemPickup
+==================
+*/
+void BotCheckItemPickup(bot_state_t *bs, int *oldinventory) {
+ int offence, leader;
+
+ if (gametype <= GT_TEAM && g_ffa_gt==0)
+ return;
+
+ offence = -1;
+ // go into offence if picked up the kamikaze or invulnerability
+ if (!oldinventory[INVENTORY_KAMIKAZE] && bs->inventory[INVENTORY_KAMIKAZE] >= 1) {
+ offence = qtrue;
+ }
+ if (!oldinventory[INVENTORY_INVULNERABILITY] && bs->inventory[INVENTORY_INVULNERABILITY] >= 1) {
+ offence = qtrue;
+ }
+ // if not already wearing the kamikaze or invulnerability
+ if (!bs->inventory[INVENTORY_KAMIKAZE] && !bs->inventory[INVENTORY_INVULNERABILITY]) {
+ if (!oldinventory[INVENTORY_SCOUT] && bs->inventory[INVENTORY_SCOUT] >= 1) {
+ offence = qtrue;
+ }
+ if (!oldinventory[INVENTORY_GUARD] && bs->inventory[INVENTORY_GUARD] >= 1) {
+ offence = qtrue;
+ }
+ if (!oldinventory[INVENTORY_DOUBLER] && bs->inventory[INVENTORY_DOUBLER] >= 1) {
+ offence = qfalse;
+ }
+ if (!oldinventory[INVENTORY_AMMOREGEN] && bs->inventory[INVENTORY_AMMOREGEN] >= 1) {
+ offence = qfalse;
+ }
+ }
+
+ if (offence >= 0) {
+ leader = ClientFromName(bs->teamleader);
+ if (offence) {
+ if (!(bs->teamtaskpreference & TEAMTP_ATTACKER)) {
+ // if we have a bot team leader
+ if (BotTeamLeader(bs)) {
+ // tell the leader we want to be on offence
+ BotVoiceChat(bs, leader, VOICECHAT_WANTONOFFENSE);
+ //BotAI_BotInitialChat(bs, "wantoffence", NULL);
+ //trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
+ }
+ else if (g_spSkill.integer <= 3) {
+ if ( ( bs->ltgtype != LTG_GETFLAG ) &&
+ ( bs->ltgtype != LTG_ATTACKENEMYBASE ) &&
+ ( bs->ltgtype != LTG_HARVEST ) &&
+ ( ( ( gametype != GT_CTF ) &&
+ ( gametype != GT_CTF_ELIMINATION ) ) ||
+ ( ( bs->redflagstatus == 0 ) &&
+ ( bs->blueflagstatus == 0 ) ) ) &&
+ ( ( gametype != GT_1FCTF ) ||
+ ( bs->neutralflagstatus == 0 ) ) ) {
+ // tell the leader we want to be on offence
+ BotVoiceChat(bs, leader, VOICECHAT_WANTONOFFENSE);
+ //BotAI_BotInitialChat(bs, "wantoffence", NULL);
+ //trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
+ }
+ bs->teamtaskpreference |= TEAMTP_ATTACKER;
+ }
+ }
+ bs->teamtaskpreference &= ~TEAMTP_DEFENDER;
+ }
+ else {
+ if (!(bs->teamtaskpreference & TEAMTP_DEFENDER)) {
+ // if we have a bot team leader
+ if (BotTeamLeader(bs)) {
+ // tell the leader we want to be on defense
+ BotVoiceChat(bs, -1, VOICECHAT_WANTONDEFENSE);
+ //BotAI_BotInitialChat(bs, "wantdefence", NULL);
+ //trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
+ }
+ else if ( (g_spSkill.integer <= 3) &&
+ ( bs->ltgtype != LTG_DEFENDKEYAREA ) &&
+ ( ( ( gametype != GT_CTF ) &&
+ ( gametype != GT_CTF_ELIMINATION ) ) ||
+ ( ( bs->redflagstatus == 0 ) &&
+ ( bs->blueflagstatus == 0 ) ) ) &&
+ ( ( gametype != GT_1FCTF ) ||
+ ( bs->neutralflagstatus == 0 ) ) ) {
+
+ // tell the leader we want to be on defense
+ BotVoiceChat(bs, -1, VOICECHAT_WANTONDEFENSE);
+ //BotAI_BotInitialChat(bs, "wantdefence", NULL);
+ //trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
+ }
+ bs->teamtaskpreference |= TEAMTP_DEFENDER;
+ }
+ bs->teamtaskpreference &= ~TEAMTP_ATTACKER;
+ }
+ }
+//#endif
+}
+
+/*
+==================
+BotUpdateInventory
+==================
+*/
+void BotUpdateInventory(bot_state_t *bs) {
+ int oldinventory[MAX_ITEMS];
+
+ memcpy(oldinventory, bs->inventory, sizeof(oldinventory));
+ //armor
+ bs->inventory[INVENTORY_ARMOR] = bs->cur_ps.stats[STAT_ARMOR];
+ //weapons
+ bs->inventory[INVENTORY_GAUNTLET] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GAUNTLET)) != 0;
+ bs->inventory[INVENTORY_SHOTGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_SHOTGUN)) != 0;
+ bs->inventory[INVENTORY_MACHINEGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_MACHINEGUN)) != 0;
+ bs->inventory[INVENTORY_GRENADELAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRENADE_LAUNCHER)) != 0;
+ bs->inventory[INVENTORY_ROCKETLAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_ROCKET_LAUNCHER)) != 0;
+ bs->inventory[INVENTORY_LIGHTNING] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_LIGHTNING)) != 0;
+ bs->inventory[INVENTORY_RAILGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_RAILGUN)) != 0;
+ bs->inventory[INVENTORY_PLASMAGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_PLASMAGUN)) != 0;
+ bs->inventory[INVENTORY_BFG10K] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_BFG)) != 0;
+ bs->inventory[INVENTORY_GRAPPLINGHOOK] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRAPPLING_HOOK)) != 0;
+ bs->inventory[INVENTORY_NAILGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_NAILGUN)) != 0;;
+ bs->inventory[INVENTORY_PROXLAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_PROX_LAUNCHER)) != 0;;
+ bs->inventory[INVENTORY_CHAINGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_CHAINGUN)) != 0;;
+ //ammo
+ bs->inventory[INVENTORY_SHELLS] = bs->cur_ps.ammo[WP_SHOTGUN];
+ bs->inventory[INVENTORY_BULLETS] = bs->cur_ps.ammo[WP_MACHINEGUN];
+ bs->inventory[INVENTORY_GRENADES] = bs->cur_ps.ammo[WP_GRENADE_LAUNCHER];
+ bs->inventory[INVENTORY_CELLS] = bs->cur_ps.ammo[WP_PLASMAGUN];
+ bs->inventory[INVENTORY_LIGHTNINGAMMO] = bs->cur_ps.ammo[WP_LIGHTNING];
+ bs->inventory[INVENTORY_ROCKETS] = bs->cur_ps.ammo[WP_ROCKET_LAUNCHER];
+ bs->inventory[INVENTORY_SLUGS] = bs->cur_ps.ammo[WP_RAILGUN];
+ bs->inventory[INVENTORY_BFGAMMO] = bs->cur_ps.ammo[WP_BFG];
+ bs->inventory[INVENTORY_NAILS] = bs->cur_ps.ammo[WP_NAILGUN];
+ bs->inventory[INVENTORY_MINES] = bs->cur_ps.ammo[WP_PROX_LAUNCHER];
+ bs->inventory[INVENTORY_BELT] = bs->cur_ps.ammo[WP_CHAINGUN];
+ //powerups
+ bs->inventory[INVENTORY_HEALTH] = bs->cur_ps.stats[STAT_HEALTH];
+ bs->inventory[INVENTORY_TELEPORTER] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_TELEPORTER;
+ bs->inventory[INVENTORY_MEDKIT] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_MEDKIT;
+ bs->inventory[INVENTORY_KAMIKAZE] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_KAMIKAZE;
+ bs->inventory[INVENTORY_PORTAL] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_PORTAL;
+ bs->inventory[INVENTORY_INVULNERABILITY] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_INVULNERABILITY;
+ bs->inventory[INVENTORY_QUAD] = bs->cur_ps.powerups[PW_QUAD] != 0;
+ bs->inventory[INVENTORY_ENVIRONMENTSUIT] = bs->cur_ps.powerups[PW_BATTLESUIT] != 0;
+ bs->inventory[INVENTORY_HASTE] = bs->cur_ps.powerups[PW_HASTE] != 0;
+ bs->inventory[INVENTORY_INVISIBILITY] = bs->cur_ps.powerups[PW_INVIS] != 0;
+ bs->inventory[INVENTORY_REGEN] = bs->cur_ps.powerups[PW_REGEN] != 0;
+ bs->inventory[INVENTORY_FLIGHT] = bs->cur_ps.powerups[PW_FLIGHT] != 0;
+ bs->inventory[INVENTORY_SCOUT] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_SCOUT;
+ bs->inventory[INVENTORY_GUARD] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_GUARD;
+ bs->inventory[INVENTORY_DOUBLER] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_DOUBLER;
+ bs->inventory[INVENTORY_AMMOREGEN] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_AMMOREGEN;
+ bs->inventory[INVENTORY_REDFLAG] = bs->cur_ps.powerups[PW_REDFLAG] != 0;
+ bs->inventory[INVENTORY_BLUEFLAG] = bs->cur_ps.powerups[PW_BLUEFLAG] != 0;
+ bs->inventory[INVENTORY_NEUTRALFLAG] = bs->cur_ps.powerups[PW_NEUTRALFLAG] != 0;
+ if (BotTeam(bs) == TEAM_RED) {
+ bs->inventory[INVENTORY_REDCUBE] = bs->cur_ps.generic1;
+ bs->inventory[INVENTORY_BLUECUBE] = 0;
+ }
+ else {
+ bs->inventory[INVENTORY_REDCUBE] = 0;
+ bs->inventory[INVENTORY_BLUECUBE] = bs->cur_ps.generic1;
+ }
+ BotCheckItemPickup(bs, oldinventory);
+}
+
+/*
+==================
+BotUpdateBattleInventory
+==================
+*/
+void BotUpdateBattleInventory(bot_state_t *bs, int enemy) {
+ vec3_t dir;
+ aas_entityinfo_t entinfo;
+
+ BotEntityInfo(enemy, &entinfo);
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ bs->inventory[ENEMY_HEIGHT] = (int) dir[2];
+ dir[2] = 0;
+ bs->inventory[ENEMY_HORIZONTAL_DIST] = (int) VectorLength(dir);
+ //FIXME: add num visible enemies and num visible team mates to the inventory
+}
+
+/*
+==================
+BotUseKamikaze
+==================
+*/
+#define KAMIKAZE_DIST 1024
+
+void BotUseKamikaze(bot_state_t *bs) {
+ int c, teammates, enemies;
+ aas_entityinfo_t entinfo;
+ vec3_t dir, target;
+ bot_goal_t *goal;
+ bsp_trace_t trace;
+
+ //if the bot has no kamikaze
+ if (bs->inventory[INVENTORY_KAMIKAZE] <= 0)
+ return;
+ if (bs->kamikaze_time > FloatTime())
+ return;
+ bs->kamikaze_time = FloatTime() + 0.2;
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ //never use kamikaze if the team flag carrier is visible
+ if (BotCTFCarryingFlag(bs))
+ return;
+ c = BotTeamFlagCarrierVisible(bs);
+ if (c >= 0) {
+ BotEntityInfo(c, &entinfo);
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST))
+ return;
+ }
+ c = BotEnemyFlagCarrierVisible(bs);
+ if (c >= 0) {
+ BotEntityInfo(c, &entinfo);
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) {
+ trap_EA_Use(bs->client);
+ return;
+ }
+ }
+ }
+ else if (gametype == GT_1FCTF) {
+ //never use kamikaze if the team flag carrier is visible
+ if (Bot1FCTFCarryingFlag(bs))
+ return;
+ c = BotTeamFlagCarrierVisible(bs);
+ if (c >= 0) {
+ BotEntityInfo(c, &entinfo);
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST))
+ return;
+ }
+ c = BotEnemyFlagCarrierVisible(bs);
+ if (c >= 0) {
+ BotEntityInfo(c, &entinfo);
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) {
+ trap_EA_Use(bs->client);
+ return;
+ }
+ }
+ }
+ else if (gametype == GT_OBELISK) {
+ switch(BotTeam(bs)) {
+ case TEAM_RED: goal = &blueobelisk; break;
+ default: goal = &redobelisk; break;
+ }
+ //if the obelisk is visible
+ VectorCopy(goal->origin, target);
+ target[2] += 1;
+ VectorSubtract(bs->origin, target, dir);
+ if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST * 0.9)) {
+ BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
+ if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
+ trap_EA_Use(bs->client);
+ return;
+ }
+ }
+ }
+ else if (gametype == GT_HARVESTER) {
+ //
+ if (BotHarvesterCarryingCubes(bs))
+ return;
+ //never use kamikaze if a team mate carrying cubes is visible
+ c = BotTeamCubeCarrierVisible(bs);
+ if (c >= 0) {
+ BotEntityInfo(c, &entinfo);
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST))
+ return;
+ }
+ c = BotEnemyCubeCarrierVisible(bs);
+ if (c >= 0) {
+ BotEntityInfo(c, &entinfo);
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) {
+ trap_EA_Use(bs->client);
+ return;
+ }
+ }
+ }
+ //
+ BotVisibleTeamMatesAndEnemies(bs, &teammates, &enemies, KAMIKAZE_DIST);
+ //
+ if (enemies > 2 && enemies > teammates+1) {
+ trap_EA_Use(bs->client);
+ return;
+ }
+}
+
+/*
+==================
+BotUseInvulnerability
+==================
+*/
+void BotUseInvulnerability(bot_state_t *bs) {
+ int c;
+ vec3_t dir, target;
+ bot_goal_t *goal;
+ bsp_trace_t trace;
+
+ //if the bot has no invulnerability
+ if (bs->inventory[INVENTORY_INVULNERABILITY] <= 0)
+ return;
+ if (bs->invulnerability_time > FloatTime())
+ return;
+ bs->invulnerability_time = FloatTime() + 0.2;
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ //never use kamikaze if the team flag carrier is visible
+ if (BotCTFCarryingFlag(bs))
+ return;
+ c = BotEnemyFlagCarrierVisible(bs);
+ if (c >= 0)
+ return;
+ //if near enemy flag and the flag is visible
+ switch(BotTeam(bs)) {
+ case TEAM_RED: goal = &ctf_blueflag; break;
+ default: goal = &ctf_redflag; break;
+ }
+ //if the obelisk is visible
+ VectorCopy(goal->origin, target);
+ target[2] += 1;
+ VectorSubtract(bs->origin, target, dir);
+ if (VectorLengthSquared(dir) < Square(200)) {
+ BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
+ if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
+ trap_EA_Use(bs->client);
+ return;
+ }
+ }
+ }
+ else if (gametype == GT_1FCTF) {
+ //never use kamikaze if the team flag carrier is visible
+ if (Bot1FCTFCarryingFlag(bs))
+ return;
+ c = BotEnemyFlagCarrierVisible(bs);
+ if (c >= 0)
+ return;
+ //if near enemy flag and the flag is visible
+ switch(BotTeam(bs)) {
+ case TEAM_RED: goal = &ctf_blueflag; break;
+ default: goal = &ctf_redflag; break;
+ }
+ //if the obelisk is visible
+ VectorCopy(goal->origin, target);
+ target[2] += 1;
+ VectorSubtract(bs->origin, target, dir);
+ if (VectorLengthSquared(dir) < Square(200)) {
+ BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
+ if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
+ trap_EA_Use(bs->client);
+ return;
+ }
+ }
+ }
+ else if (gametype == GT_OBELISK) {
+ switch(BotTeam(bs)) {
+ case TEAM_RED: goal = &blueobelisk; break;
+ default: goal = &redobelisk; break;
+ }
+ //if the obelisk is visible
+ VectorCopy(goal->origin, target);
+ target[2] += 1;
+ VectorSubtract(bs->origin, target, dir);
+ if (VectorLengthSquared(dir) < Square(300)) {
+ BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
+ if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
+ trap_EA_Use(bs->client);
+ return;
+ }
+ }
+ }
+ else if (gametype == GT_HARVESTER) {
+ //
+ if (BotHarvesterCarryingCubes(bs))
+ return;
+ c = BotEnemyCubeCarrierVisible(bs);
+ if (c >= 0)
+ return;
+ //if near enemy base and enemy base is visible
+ switch(BotTeam(bs)) {
+ case TEAM_RED: goal = &blueobelisk; break;
+ default: goal = &redobelisk; break;
+ }
+ //if the obelisk is visible
+ VectorCopy(goal->origin, target);
+ target[2] += 1;
+ VectorSubtract(bs->origin, target, dir);
+ if (VectorLengthSquared(dir) < Square(200)) {
+ BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
+ if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
+ trap_EA_Use(bs->client);
+ return;
+ }
+ }
+ }
+}
+
+/*
+==================
+BotBattleUseItems
+==================
+*/
+void BotBattleUseItems(bot_state_t *bs) {
+ if (bs->inventory[INVENTORY_HEALTH] < 40) {
+ if (bs->inventory[INVENTORY_TELEPORTER] > 0) {
+ if (!BotCTFCarryingFlag(bs)
+ && !Bot1FCTFCarryingFlag(bs)
+ && !BotHarvesterCarryingCubes(bs)
+ ) {
+ trap_EA_Use(bs->client);
+ }
+ }
+ }
+ if (bs->inventory[INVENTORY_HEALTH] < 60) {
+ if (bs->inventory[INVENTORY_MEDKIT] > 0) {
+ trap_EA_Use(bs->client);
+ }
+ }
+ BotUseKamikaze(bs);
+ BotUseInvulnerability(bs);
+}
+
+/*
+==================
+BotSetTeleportTime
+==================
+*/
+void BotSetTeleportTime(bot_state_t *bs) {
+ if ((bs->cur_ps.eFlags ^ bs->last_eFlags) & EF_TELEPORT_BIT) {
+ bs->teleport_time = FloatTime();
+ }
+ bs->last_eFlags = bs->cur_ps.eFlags;
+}
+
+/*
+==================
+BotIsDead
+==================
+*/
+qboolean BotIsDead(bot_state_t *bs) {
+ return (bs->cur_ps.pm_type == PM_DEAD);
+}
+
+/*
+==================
+BotIsObserver
+==================
+*/
+qboolean BotIsObserver(bot_state_t *bs) {
+ char buf[MAX_INFO_STRING];
+ if (bs->cur_ps.pm_type == PM_SPECTATOR) return qtrue;
+ trap_GetConfigstring(CS_PLAYERS+bs->client, buf, sizeof(buf));
+ if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) return qtrue;
+ return qfalse;
+}
+
+/*
+==================
+BotIntermission
+==================
+*/
+qboolean BotIntermission(bot_state_t *bs) {
+ //NOTE: we shouldn't be looking at the game code...
+ if (level.intermissiontime) return qtrue;
+ return (bs->cur_ps.pm_type == PM_FREEZE || bs->cur_ps.pm_type == PM_INTERMISSION);
+}
+
+/*
+==================
+BotInLavaOrSlime
+==================
+*/
+qboolean BotInLavaOrSlime(bot_state_t *bs) {
+ vec3_t feet;
+
+ VectorCopy(bs->origin, feet);
+ feet[2] -= 23;
+ return (trap_AAS_PointContents(feet) & (CONTENTS_LAVA|CONTENTS_SLIME));
+}
+
+/*
+==================
+BotCreateWayPoint
+==================
+*/
+bot_waypoint_t *BotCreateWayPoint(char *name, vec3_t origin, int areanum) {
+ bot_waypoint_t *wp;
+ vec3_t waypointmins = {-8, -8, -8}, waypointmaxs = {8, 8, 8};
+
+ wp = botai_freewaypoints;
+ if ( !wp ) {
+ BotAI_Print( PRT_WARNING, "BotCreateWayPoint: Out of waypoints\n" );
+ return NULL;
+ }
+ botai_freewaypoints = botai_freewaypoints->next;
+
+ Q_strncpyz( wp->name, name, sizeof(wp->name) );
+ VectorCopy(origin, wp->goal.origin);
+ VectorCopy(waypointmins, wp->goal.mins);
+ VectorCopy(waypointmaxs, wp->goal.maxs);
+ wp->goal.areanum = areanum;
+ wp->next = NULL;
+ wp->prev = NULL;
+ return wp;
+}
+
+/*
+==================
+BotFindWayPoint
+==================
+*/
+bot_waypoint_t *BotFindWayPoint(bot_waypoint_t *waypoints, char *name) {
+ bot_waypoint_t *wp;
+
+ for (wp = waypoints; wp; wp = wp->next) {
+ if (!Q_stricmp(wp->name, name)) return wp;
+ }
+ return NULL;
+}
+
+/*
+==================
+BotFreeWaypoints
+==================
+*/
+void BotFreeWaypoints(bot_waypoint_t *wp) {
+ bot_waypoint_t *nextwp;
+
+ for (; wp; wp = nextwp) {
+ nextwp = wp->next;
+ wp->next = botai_freewaypoints;
+ botai_freewaypoints = wp;
+ }
+}
+
+/*
+==================
+BotInitWaypoints
+==================
+*/
+void BotInitWaypoints(void) {
+ int i;
+
+ botai_freewaypoints = NULL;
+ for (i = 0; i < MAX_WAYPOINTS; i++) {
+ botai_waypoints[i].next = botai_freewaypoints;
+ botai_freewaypoints = &botai_waypoints[i];
+ }
+}
+
+/*
+==================
+TeamPlayIsOn
+==================
+*/
+int TeamPlayIsOn(void) {
+ return ( gametype >= GT_TEAM && g_ffa_gt!=1);
+}
+
+/*
+==================
+BotAggression
+==================
+*/
+float BotAggression(bot_state_t *bs) {
+ //if the bot has quad
+ if (bs->inventory[INVENTORY_QUAD]) {
+ //if the bot is not holding the gauntlet or the enemy is really nearby
+ if (bs->weaponnum != WP_GAUNTLET ||
+ bs->inventory[ENEMY_HORIZONTAL_DIST] < 80) {
+ return 70;
+ }
+ }
+ //if the enemy is located way higher than the bot
+ if (bs->inventory[ENEMY_HEIGHT] > 200) return 0;
+ //if the bot is very low on health
+ if (bs->inventory[INVENTORY_HEALTH] < 60) return 0;
+ //if the bot is low on health
+ if (bs->inventory[INVENTORY_HEALTH] < 80) {
+ //if the bot has insufficient armor
+ if (bs->inventory[INVENTORY_ARMOR] < 40) return 0;
+ }
+ //if the bot can use the bfg
+ if (bs->inventory[INVENTORY_BFG10K] > 0 &&
+ bs->inventory[INVENTORY_BFGAMMO] > 7) return 100;
+ //if the bot can use the railgun
+ if (bs->inventory[INVENTORY_RAILGUN] > 0 &&
+ bs->inventory[INVENTORY_SLUGS] > 5) return 95;
+ //if the bot can use the lightning gun
+ if (bs->inventory[INVENTORY_LIGHTNING] > 0 &&
+ bs->inventory[INVENTORY_LIGHTNINGAMMO] > 50) return 90;
+ //if the bot can use the rocketlauncher
+ if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 &&
+ bs->inventory[INVENTORY_ROCKETS] > 5) return 90;
+ //if the bot can use the plasmagun
+ if (bs->inventory[INVENTORY_PLASMAGUN] > 0 &&
+ bs->inventory[INVENTORY_CELLS] > 40) return 85;
+ //if the bot can use the grenade launcher
+ if (bs->inventory[INVENTORY_GRENADELAUNCHER] > 0 &&
+ bs->inventory[INVENTORY_GRENADES] > 10) return 80;
+ //if the bot can use the shotgun
+ if (bs->inventory[INVENTORY_SHOTGUN] > 0 &&
+ bs->inventory[INVENTORY_SHELLS] > 10) return 50;
+ //otherwise the bot is not feeling too good
+ return 0;
+}
+
+/*
+==================
+BotFeelingBad
+==================
+*/
+float BotFeelingBad(bot_state_t *bs) {
+ if (bs->weaponnum == WP_GAUNTLET) {
+ return 100;
+ }
+ if (bs->inventory[INVENTORY_HEALTH] < 40) {
+ return 100;
+ }
+ if (bs->weaponnum == WP_MACHINEGUN) {
+ return 90;
+ }
+ if (bs->inventory[INVENTORY_HEALTH] < 60) {
+ return 80;
+ }
+ return 0;
+}
+
+/*
+==================
+BotWantsToRetreat
+==================
+*/
+int BotWantsToRetreat(bot_state_t *bs) {
+ aas_entityinfo_t entinfo;
+
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ //always retreat when carrying a CTF flag
+ if (BotCTFCarryingFlag(bs))
+ return qtrue;
+ }
+ else if (gametype == GT_1FCTF) {
+ //if carrying the flag then always retreat
+ if (Bot1FCTFCarryingFlag(bs))
+ return qtrue;
+ }
+ else if (gametype == GT_OBELISK) {
+ //the bots should be dedicated to attacking the enemy obelisk
+ if (bs->ltgtype == LTG_ATTACKENEMYBASE) {
+ if (bs->enemy != redobelisk.entitynum &&
+ bs->enemy != blueobelisk.entitynum) {
+ return qtrue;
+ }
+ }
+ if (BotFeelingBad(bs) > 50) {
+ return qtrue;
+ }
+ return qfalse;
+ }
+ else if (gametype == GT_HARVESTER) {
+ //if carrying cubes then always retreat
+ if (BotHarvesterCarryingCubes(bs)) return qtrue;
+ }
+ //
+ if (bs->enemy >= 0) {
+ //if the enemy is carrying a flag
+ BotEntityInfo(bs->enemy, &entinfo);
+ // if the enemy is carrying a flag
+ if (EntityCarriesFlag(&entinfo)) return qfalse;
+#ifdef MISSIONPACK
+ // if the enemy is carrying cubes
+ if (EntityCarriesCubes(&entinfo)) return qfalse;
+#endif
+ }
+ //if the bot is getting the flag
+ if (bs->ltgtype == LTG_GETFLAG)
+ return qtrue;
+ //
+ if (BotAggression(bs) < 50)
+ return qtrue;
+ return qfalse;
+}
+
+/*
+==================
+BotWantsToChase
+==================
+*/
+int BotWantsToChase(bot_state_t *bs) {
+ aas_entityinfo_t entinfo;
+
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ //never chase when carrying a CTF flag
+ if (BotCTFCarryingFlag(bs))
+ return qfalse;
+ //always chase if the enemy is carrying a flag
+ BotEntityInfo(bs->enemy, &entinfo);
+ if (EntityCarriesFlag(&entinfo))
+ return qtrue;
+ }
+ else if (gametype == GT_1FCTF) {
+ //never chase if carrying the flag
+ if (Bot1FCTFCarryingFlag(bs))
+ return qfalse;
+ //always chase if the enemy is carrying a flag
+ BotEntityInfo(bs->enemy, &entinfo);
+ if (EntityCarriesFlag(&entinfo))
+ return qtrue;
+ }
+ else if (gametype == GT_OBELISK) {
+ //the bots should be dedicated to attacking the enemy obelisk
+ if (bs->ltgtype == LTG_ATTACKENEMYBASE) {
+ if (bs->enemy != redobelisk.entitynum &&
+ bs->enemy != blueobelisk.entitynum) {
+ return qfalse;
+ }
+ }
+ }
+ else if (gametype == GT_HARVESTER) {
+ //never chase if carrying cubes
+ if (BotHarvesterCarryingCubes(bs)) return qfalse;
+
+ BotEntityInfo(bs->enemy, &entinfo);
+ // always chase if the enemy is carrying cubes
+ if (EntityCarriesCubes(&entinfo)) return qtrue;
+ }
+ //if the bot is getting the flag
+ if (bs->ltgtype == LTG_GETFLAG)
+ return qfalse;
+ //
+ if (BotAggression(bs) > 50)
+ return qtrue;
+ return qfalse;
+}
+
+/*
+==================
+BotWantsToHelp
+==================
+*/
+int BotWantsToHelp(bot_state_t *bs) {
+ return qtrue;
+}
+
+/*
+==================
+BotCanAndWantsToRocketJump
+==================
+*/
+int BotCanAndWantsToRocketJump(bot_state_t *bs) {
+ float rocketjumper;
+
+ //if rocket jumping is disabled
+ if (!bot_rocketjump.integer) return qfalse;
+ //if no rocket launcher
+ if (bs->inventory[INVENTORY_ROCKETLAUNCHER] <= 0) return qfalse;
+ //if low on rockets
+ if (bs->inventory[INVENTORY_ROCKETS] < 3) return qfalse;
+ //Sago: Special rule - always happy to rocket jump in elimination, eCTF end LMS if
+ if ( (g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION || g_gametype.integer==GT_LMS )
+ && g_elimination_selfdamage.integer==0) {
+ return qtrue;
+ }
+ //never rocket jump with the Quad
+ if (bs->inventory[INVENTORY_QUAD]) return qfalse;
+ //if low on health
+ if (bs->inventory[INVENTORY_HEALTH] < 60) return qfalse;
+ //if not full health
+ if (bs->inventory[INVENTORY_HEALTH] < 90) {
+ //if the bot has insufficient armor
+ if (bs->inventory[INVENTORY_ARMOR] < 40) return qfalse;
+ }
+ rocketjumper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WEAPONJUMPING, 0, 1);
+ if (rocketjumper < 0.5) return qfalse;
+ return qtrue;
+}
+
+/*
+==================
+BotHasPersistantPowerupAndWeapon
+==================
+*/
+int BotHasPersistantPowerupAndWeapon(bot_state_t *bs) {
+ // if the bot does not have a persistant powerup
+ //Sago - FIXME - This causes problems if there are no persistant powerups
+/* if (!bs->inventory[INVENTORY_SCOUT] &&
+ !bs->inventory[INVENTORY_GUARD] &&
+ !bs->inventory[INVENTORY_DOUBLER] &&
+ !bs->inventory[INVENTORY_AMMOREGEN] ) {
+ return qfalse;
+ }*/
+ //if the bot is very low on health
+ if (bs->inventory[INVENTORY_HEALTH] < 60) return qfalse;
+ //if the bot is low on health
+ if (bs->inventory[INVENTORY_HEALTH] < 80) {
+ //if the bot has insufficient armor
+ if (bs->inventory[INVENTORY_ARMOR] < 40) return qfalse;
+ }
+ //if the bot can use the bfg
+ if (bs->inventory[INVENTORY_BFG10K] > 0 &&
+ bs->inventory[INVENTORY_BFGAMMO] > 7) return qtrue;
+ //if the bot can use the railgun
+ if (bs->inventory[INVENTORY_RAILGUN] > 0 &&
+ bs->inventory[INVENTORY_SLUGS] > 5) return qtrue;
+ //if the bot can use the lightning gun
+ if (bs->inventory[INVENTORY_LIGHTNING] > 0 &&
+ bs->inventory[INVENTORY_LIGHTNINGAMMO] > 50) return qtrue;
+ //if the bot can use the rocketlauncher
+ if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 &&
+ bs->inventory[INVENTORY_ROCKETS] > 5) return qtrue;
+ //
+ if (bs->inventory[INVENTORY_NAILGUN] > 0 &&
+ bs->inventory[INVENTORY_NAILS] > 5) return qtrue;
+ //
+ if (bs->inventory[INVENTORY_PROXLAUNCHER] > 0 &&
+ bs->inventory[INVENTORY_MINES] > 5) return qtrue;
+ //
+ if (bs->inventory[INVENTORY_CHAINGUN] > 0 &&
+ bs->inventory[INVENTORY_BELT] > 40) return qtrue;
+ //if the bot can use the plasmagun
+ if (bs->inventory[INVENTORY_PLASMAGUN] > 0 &&
+ bs->inventory[INVENTORY_CELLS] > 20) return qtrue;
+ return qfalse;
+}
+
+/*
+==================
+BotGoCamp
+==================
+*/
+void BotGoCamp(bot_state_t *bs, bot_goal_t *goal) {
+ float camper;
+
+ bs->decisionmaker = bs->client;
+ //set message time to zero so bot will NOT show any message
+ bs->teammessage_time = 0;
+ //set the ltg type
+ bs->ltgtype = LTG_CAMP;
+ //set the team goal
+ memcpy(&bs->teamgoal, goal, sizeof(bot_goal_t));
+ //get the team goal time
+ camper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CAMPER, 0, 1);
+ if (camper > 0.99) bs->teamgoal_time = FloatTime() + 99999;
+ else bs->teamgoal_time = FloatTime() + 120 + 180 * camper + random() * 15;
+ //set the last time the bot started camping
+ bs->camp_time = FloatTime();
+ //the teammate that requested the camping
+ bs->teammate = 0;
+ //do NOT type arrive message
+ bs->arrive_time = 1;
+}
+
+/*
+==================
+BotWantsToCamp
+==================
+*/
+int BotWantsToCamp(bot_state_t *bs) {
+ float camper;
+ int cs, traveltime, besttraveltime;
+ bot_goal_t goal, bestgoal;
+
+ camper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CAMPER, 0, 1);
+ if (camper < 0.1) return qfalse;
+ //if the bot has a team goal
+ if (bs->ltgtype == LTG_TEAMHELP ||
+ bs->ltgtype == LTG_TEAMACCOMPANY ||
+ bs->ltgtype == LTG_DEFENDKEYAREA ||
+ bs->ltgtype == LTG_GETFLAG ||
+ bs->ltgtype == LTG_RUSHBASE ||
+ bs->ltgtype == LTG_CAMP ||
+ bs->ltgtype == LTG_CAMPORDER ||
+ bs->ltgtype == LTG_PATROL) {
+ return qfalse;
+ }
+ //if camped recently
+ if (bs->camp_time > FloatTime() - 60 + 300 * (1-camper)) return qfalse;
+ //
+ if (random() > camper) {
+ bs->camp_time = FloatTime();
+ return qfalse;
+ }
+ //if the bot isn't healthy anough
+ if (BotAggression(bs) < 50) return qfalse;
+ //the bot should have at least have the rocket launcher, the railgun or the bfg10k with some ammo
+ if ((bs->inventory[INVENTORY_ROCKETLAUNCHER] <= 0 || bs->inventory[INVENTORY_ROCKETS] < 10) &&
+ (bs->inventory[INVENTORY_RAILGUN] <= 0 || bs->inventory[INVENTORY_SLUGS] < 10) &&
+ (bs->inventory[INVENTORY_BFG10K] <= 0 || bs->inventory[INVENTORY_BFGAMMO] < 10)) {
+ return qfalse;
+ }
+ //find the closest camp spot
+ besttraveltime = 99999;
+ for (cs = trap_BotGetNextCampSpotGoal(0, &goal); cs; cs = trap_BotGetNextCampSpotGoal(cs, &goal)) {
+ traveltime = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, goal.areanum, TFL_DEFAULT);
+ if (traveltime && traveltime < besttraveltime) {
+ besttraveltime = traveltime;
+ memcpy(&bestgoal, &goal, sizeof(bot_goal_t));
+ }
+ }
+ if (besttraveltime > 150) return qfalse;
+ //ok found a camp spot, go camp there
+ BotGoCamp(bs, &bestgoal);
+ bs->ordered = qfalse;
+ //
+ return qtrue;
+}
+
+/*
+==================
+BotDontAvoid
+==================
+*/
+void BotDontAvoid(bot_state_t *bs, char *itemname) {
+ bot_goal_t goal;
+ int num;
+
+ num = trap_BotGetLevelItemGoal(-1, itemname, &goal);
+ while(num >= 0) {
+ trap_BotRemoveFromAvoidGoals(bs->gs, goal.number);
+ num = trap_BotGetLevelItemGoal(num, itemname, &goal);
+ }
+}
+
+/*
+==================
+BotGoForPowerups
+==================
+*/
+void BotGoForPowerups(bot_state_t *bs) {
+
+ //don't avoid any of the powerups anymore
+ BotDontAvoid(bs, "Quad Damage");
+ BotDontAvoid(bs, "Regeneration");
+ BotDontAvoid(bs, "Battle Suit");
+ BotDontAvoid(bs, "Speed");
+ BotDontAvoid(bs, "Invisibility");
+ //BotDontAvoid(bs, "Flight");
+ //reset the long term goal time so the bot will go for the powerup
+ //NOTE: the long term goal type doesn't change
+ bs->ltg_time = 0;
+}
+
+/*
+==================
+BotRoamGoal
+==================
+*/
+void BotRoamGoal(bot_state_t *bs, vec3_t goal) {
+ int pc, i;
+ float len, rnd;
+ vec3_t dir, bestorg, belowbestorg;
+ bsp_trace_t trace;
+
+ for (i = 0; i < 10; i++) {
+ //start at the bot origin
+ VectorCopy(bs->origin, bestorg);
+ rnd = random();
+ if (rnd > 0.25) {
+ //add a random value to the x-coordinate
+ if (random() < 0.5) bestorg[0] -= 800 * random() + 100;
+ else bestorg[0] += 800 * random() + 100;
+ }
+ if (rnd < 0.75) {
+ //add a random value to the y-coordinate
+ if (random() < 0.5) bestorg[1] -= 800 * random() + 100;
+ else bestorg[1] += 800 * random() + 100;
+ }
+ //add a random value to the z-coordinate (NOTE: 48 = maxjump?)
+ bestorg[2] += 2 * 48 * crandom();
+ //trace a line from the origin to the roam target
+ BotAI_Trace(&trace, bs->origin, NULL, NULL, bestorg, bs->entitynum, MASK_SOLID);
+ //direction and length towards the roam target
+ VectorSubtract(trace.endpos, bs->origin, dir);
+ len = VectorNormalize(dir);
+ //if the roam target is far away anough
+ if (len > 200) {
+ //the roam target is in the given direction before walls
+ VectorScale(dir, len * trace.fraction - 40, dir);
+ VectorAdd(bs->origin, dir, bestorg);
+ //get the coordinates of the floor below the roam target
+ belowbestorg[0] = bestorg[0];
+ belowbestorg[1] = bestorg[1];
+ belowbestorg[2] = bestorg[2] - 800;
+ BotAI_Trace(&trace, bestorg, NULL, NULL, belowbestorg, bs->entitynum, MASK_SOLID);
+ //
+ if (!trace.startsolid) {
+ trace.endpos[2]++;
+ pc = trap_PointContents(trace.endpos, bs->entitynum);
+ if (!(pc & (CONTENTS_LAVA | CONTENTS_SLIME))) {
+ VectorCopy(bestorg, goal);
+ return;
+ }
+ }
+ }
+ }
+ VectorCopy(bestorg, goal);
+}
+
+/*
+==================
+BotAttackMove
+==================
+*/
+bot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl) {
+ int movetype, i, attackentity;
+ float attack_skill, jumper, croucher, dist, strafechange_time;
+ float attack_dist, attack_range;
+ vec3_t forward, backward, sideward, hordir, up = {0, 0, 1};
+ aas_entityinfo_t entinfo;
+ bot_moveresult_t moveresult;
+ bot_goal_t goal;
+
+ attackentity = bs->enemy;
+ //
+ if (bs->attackchase_time > FloatTime()) {
+ //create the chase goal
+ goal.entitynum = attackentity;
+ goal.areanum = bs->lastenemyareanum;
+ VectorCopy(bs->lastenemyorigin, goal.origin);
+ VectorSet(goal.mins, -8, -8, -8);
+ VectorSet(goal.maxs, 8, 8, 8);
+ //initialize the movement state
+ BotSetupForMovement(bs);
+ //move towards the goal
+ trap_BotMoveToGoal(&moveresult, bs->ms, &goal, tfl);
+ return moveresult;
+ }
+ //
+ memset(&moveresult, 0, sizeof(bot_moveresult_t));
+ //
+ attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1);
+ jumper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_JUMPER, 0, 1);
+ croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);
+ //if the bot is really stupid
+ if (attack_skill < 0.2) return moveresult;
+ //initialize the movement state
+ BotSetupForMovement(bs);
+ //get the enemy entity info
+ BotEntityInfo(attackentity, &entinfo);
+ //direction towards the enemy
+ VectorSubtract(entinfo.origin, bs->origin, forward);
+ //the distance towards the enemy
+ dist = VectorNormalize(forward);
+ VectorNegate(forward, backward);
+ //walk, crouch or jump
+ movetype = MOVE_WALK;
+ //
+ if (bs->attackcrouch_time < FloatTime() - 1) {
+ if (random() < jumper) {
+ movetype = MOVE_JUMP;
+ }
+ //wait at least one second before crouching again
+ else if (bs->attackcrouch_time < FloatTime() - 1 && random() < croucher) {
+ bs->attackcrouch_time = FloatTime() + croucher * 5;
+ }
+ }
+ if (bs->attackcrouch_time > FloatTime()) movetype = MOVE_CROUCH;
+ //if the bot should jump
+ if (movetype == MOVE_JUMP) {
+ //if jumped last frame
+ if (bs->attackjump_time > FloatTime()) {
+ movetype = MOVE_WALK;
+ }
+ else {
+ bs->attackjump_time = FloatTime() + 1;
+ }
+ }
+ if (bs->cur_ps.weapon == WP_GAUNTLET) {
+ attack_dist = 0;
+ attack_range = 0;
+ }
+ else {
+ attack_dist = IDEAL_ATTACKDIST;
+ attack_range = 40;
+ }
+ //if the bot is stupid
+ if (attack_skill <= 0.4) {
+ //just walk to or away from the enemy
+ if (dist > attack_dist + attack_range) {
+ if (trap_BotMoveInDirection(bs->ms, forward, 400, movetype)) return moveresult;
+ }
+ if (dist < attack_dist - attack_range) {
+ if (trap_BotMoveInDirection(bs->ms, backward, 400, movetype)) return moveresult;
+ }
+ return moveresult;
+ }
+ //increase the strafe time
+ bs->attackstrafe_time += bs->thinktime;
+ //get the strafe change time
+ strafechange_time = 0.4 + (1 - attack_skill) * 0.2;
+ if (attack_skill > 0.7) strafechange_time += crandom() * 0.2;
+ //if the strafe direction should be changed
+ if (bs->attackstrafe_time > strafechange_time) {
+ //some magic number :)
+ if (random() > 0.935) {
+ //flip the strafe direction
+ bs->flags ^= BFL_STRAFERIGHT;
+ bs->attackstrafe_time = 0;
+ }
+ }
+ //
+ for (i = 0; i < 2; i++) {
+ hordir[0] = forward[0];
+ hordir[1] = forward[1];
+ hordir[2] = 0;
+ VectorNormalize(hordir);
+ //get the sideward vector
+ CrossProduct(hordir, up, sideward);
+ //reverse the vector depending on the strafe direction
+ if (bs->flags & BFL_STRAFERIGHT) VectorNegate(sideward, sideward);
+ //randomly go back a little
+ if (random() > 0.9) {
+ VectorAdd(sideward, backward, sideward);
+ }
+ else {
+ //walk forward or backward to get at the ideal attack distance
+ if (dist > attack_dist + attack_range) {
+ VectorAdd(sideward, forward, sideward);
+ }
+ else if (dist < attack_dist - attack_range) {
+ VectorAdd(sideward, backward, sideward);
+ }
+ }
+ //perform the movement
+ if (trap_BotMoveInDirection(bs->ms, sideward, 400, movetype))
+ return moveresult;
+ //movement failed, flip the strafe direction
+ bs->flags ^= BFL_STRAFERIGHT;
+ bs->attackstrafe_time = 0;
+ }
+ //bot couldn't do any usefull movement
+// bs->attackchase_time = AAS_Time() + 6;
+ return moveresult;
+}
+
+/*
+==================
+BotSameTeam
+==================
+*/
+int BotSameTeam(bot_state_t *bs, int entnum) {
+ if (bs->client < 0 || bs->client >= MAX_CLIENTS) {
+ //BotAI_Print(PRT_ERROR, "BotSameTeam: client out of range\n");
+ return qfalse;
+ }
+ if (entnum < 0 || entnum >= MAX_CLIENTS) {
+ //BotAI_Print(PRT_ERROR, "BotSameTeam: client out of range\n");
+ return qfalse;
+ }
+ if ( gametype >= GT_TEAM && g_ffa_gt!=1) {
+ /*Sago: I don't know why they decided to check the configstring instead of the real value.
+ For some reason bots sometimes gets a wrong config string when chaning gametypes.
+ Now we check the real value: */
+ if(level.clients[bs->client].sess.sessionTeam==level.clients[entnum].sess.sessionTeam) return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+InFieldOfVision
+==================
+*/
+qboolean InFieldOfVision(vec3_t viewangles, float fov, vec3_t angles)
+{
+ int i;
+ float diff, angle;
+
+ for (i = 0; i < 2; i++) {
+ angle = AngleMod(viewangles[i]);
+ angles[i] = AngleMod(angles[i]);
+ diff = angles[i] - angle;
+ if (angles[i] > angle) {
+ if (diff > 180.0) diff -= 360.0;
+ }
+ else {
+ if (diff < -180.0) diff += 360.0;
+ }
+ if (diff > 0) {
+ if (diff > fov * 0.5) return qfalse;
+ }
+ else {
+ if (diff < -fov * 0.5) return qfalse;
+ }
+ }
+ return qtrue;
+}
+
+/*
+==================
+BotEntityVisible
+
+returns visibility in the range [0, 1] taking fog and water surfaces into account
+==================
+*/
+float BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int ent) {
+ int i, contents_mask, passent, hitent, infog, inwater, otherinfog, pc;
+ float squaredfogdist, waterfactor, vis, bestvis;
+ bsp_trace_t trace;
+ aas_entityinfo_t entinfo;
+ vec3_t dir, entangles, start, end, middle;
+
+ //calculate middle of bounding box
+ BotEntityInfo(ent, &entinfo);
+ VectorAdd(entinfo.mins, entinfo.maxs, middle);
+ VectorScale(middle, 0.5, middle);
+ VectorAdd(entinfo.origin, middle, middle);
+ //check if entity is within field of vision
+ VectorSubtract(middle, eye, dir);
+ vectoangles(dir, entangles);
+ if (!InFieldOfVision(viewangles, fov, entangles)) return 0;
+ //
+ pc = trap_AAS_PointContents(eye);
+ infog = (pc & CONTENTS_FOG);
+ inwater = (pc & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER));
+ //
+ bestvis = 0;
+ for (i = 0; i < 3; i++) {
+ //if the point is not in potential visible sight
+ //if (!AAS_inPVS(eye, middle)) continue;
+ //
+ contents_mask = CONTENTS_SOLID|CONTENTS_PLAYERCLIP;
+ passent = viewer;
+ hitent = ent;
+ VectorCopy(eye, start);
+ VectorCopy(middle, end);
+ //if the entity is in water, lava or slime
+ if (trap_AAS_PointContents(middle) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) {
+ contents_mask |= (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER);
+ }
+ //if eye is in water, lava or slime
+ if (inwater) {
+ if (!(contents_mask & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) {
+ passent = ent;
+ hitent = viewer;
+ VectorCopy(middle, start);
+ VectorCopy(eye, end);
+ }
+ contents_mask ^= (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER);
+ }
+ //trace from start to end
+ BotAI_Trace(&trace, start, NULL, NULL, end, passent, contents_mask);
+ //if water was hit
+ waterfactor = 1.0;
+ if (trace.contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) {
+ //if the water surface is translucent
+ if (1) {
+ //trace through the water
+ contents_mask &= ~(CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER);
+ BotAI_Trace(&trace, trace.endpos, NULL, NULL, end, passent, contents_mask);
+ waterfactor = 0.5;
+ }
+ }
+ //if a full trace or the hitent was hit
+ if (trace.fraction >= 1 || trace.ent == hitent) {
+ //check for fog, assuming there's only one fog brush where
+ //either the viewer or the entity is in or both are in
+ otherinfog = (trap_AAS_PointContents(middle) & CONTENTS_FOG);
+ if (infog && otherinfog) {
+ VectorSubtract(trace.endpos, eye, dir);
+ squaredfogdist = VectorLengthSquared(dir);
+ }
+ else if (infog) {
+ VectorCopy(trace.endpos, start);
+ BotAI_Trace(&trace, start, NULL, NULL, eye, viewer, CONTENTS_FOG);
+ VectorSubtract(eye, trace.endpos, dir);
+ squaredfogdist = VectorLengthSquared(dir);
+ }
+ else if (otherinfog) {
+ VectorCopy(trace.endpos, end);
+ BotAI_Trace(&trace, eye, NULL, NULL, end, viewer, CONTENTS_FOG);
+ VectorSubtract(end, trace.endpos, dir);
+ squaredfogdist = VectorLengthSquared(dir);
+ }
+ else {
+ //if the entity and the viewer are not in fog assume there's no fog in between
+ squaredfogdist = 0;
+ }
+ //decrease visibility with the view distance through fog
+ vis = 1 / ((squaredfogdist * 0.001) < 1 ? 1 : (squaredfogdist * 0.001));
+ //if entering water visibility is reduced
+ vis *= waterfactor;
+ //
+ if (vis > bestvis) bestvis = vis;
+ //if pretty much no fog
+ if (bestvis >= 0.95) return bestvis;
+ }
+ //check bottom and top of bounding box as well
+ if (i == 0) middle[2] += entinfo.mins[2];
+ else if (i == 1) middle[2] += entinfo.maxs[2] - entinfo.mins[2];
+ }
+ return bestvis;
+}
+
+/*
+==================
+BotFindEnemy
+==================
+*/
+int BotFindEnemy(bot_state_t *bs, int curenemy) {
+ int i, healthdecrease;
+ float f, alertness, easyfragger, vis;
+ float squaredist, cursquaredist;
+ aas_entityinfo_t entinfo, curenemyinfo;
+ vec3_t dir, angles;
+
+ alertness = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ALERTNESS, 0, 1);
+ easyfragger = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_EASY_FRAGGER, 0, 1);
+ //check if the health decreased
+ healthdecrease = bs->lasthealth > bs->inventory[INVENTORY_HEALTH];
+ //remember the current health value
+ bs->lasthealth = bs->inventory[INVENTORY_HEALTH];
+ //
+ if (curenemy >= 0) {
+ BotEntityInfo(curenemy, &curenemyinfo);
+ if (EntityCarriesFlag(&curenemyinfo)) return qfalse;
+ VectorSubtract(curenemyinfo.origin, bs->origin, dir);
+ cursquaredist = VectorLengthSquared(dir);
+ }
+ else {
+ cursquaredist = 0;
+ }
+ if (gametype == GT_OBELISK) {
+ vec3_t target;
+ bot_goal_t *goal;
+ bsp_trace_t trace;
+
+ if (BotTeam(bs) == TEAM_RED)
+ goal = &blueobelisk;
+ else
+ goal = &redobelisk;
+ //if the obelisk is visible
+ VectorCopy(goal->origin, target);
+ target[2] += 1;
+ BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
+ if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
+ if (goal->entitynum == bs->enemy) {
+ return qfalse;
+ }
+ bs->enemy = goal->entitynum;
+ bs->enemysight_time = FloatTime();
+ bs->enemysuicide = qfalse;
+ bs->enemydeath_time = 0;
+ bs->enemyvisible_time = FloatTime();
+ return qtrue;
+ }
+ }
+ //
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+
+ if (i == bs->client) continue;
+ //if it's the current enemy
+ if (i == curenemy) continue;
+ //
+ BotEntityInfo(i, &entinfo);
+ //
+ if (!entinfo.valid) continue;
+ //if the enemy isn't dead and the enemy isn't the bot self
+ if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;
+ //if the enemy is invisible and not shooting
+ if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
+ continue;
+ }
+//Neil Torontos unlagged
+//unlagged - misc
+ // this has nothing to do with lag compensation, but it's great for testing
+ if ( g_entities[i].flags & FL_NOTARGET ) continue;
+//unlagged - misc
+ //if not an easy fragger don't shoot at chatting players
+ if (easyfragger < 0.5 && EntityIsChatting(&entinfo)) continue;
+ //
+ if (lastteleport_time > FloatTime() - 3) {
+ VectorSubtract(entinfo.origin, lastteleport_origin, dir);
+ if (VectorLengthSquared(dir) < Square(70)) continue;
+ }
+ //calculate the distance towards the enemy
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ squaredist = VectorLengthSquared(dir);
+ //if this entity is not carrying a flag
+ if (!EntityCarriesFlag(&entinfo))
+ {
+ //if this enemy is further away than the current one
+ if (curenemy >= 0 && squaredist > cursquaredist) continue;
+ } //end if
+ //if the bot has no
+ if (squaredist > Square(900.0 + alertness * 4000.0)) continue;
+ //if on the same team
+ if (BotSameTeam(bs, i)) continue;
+ //if the bot's health decreased or the enemy is shooting
+ if (curenemy < 0 && (healthdecrease || EntityIsShooting(&entinfo)))
+ f = 360;
+ else
+ f = 90 + 90 - (90 - (squaredist > Square(810) ? Square(810) : squaredist) / (810 * 9));
+ //check if the enemy is visible
+ vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, f, i);
+ if (vis <= 0) continue;
+ //if the enemy is quite far away, not shooting and the bot is not damaged
+ if (curenemy < 0 && squaredist > Square(100) && !healthdecrease && !EntityIsShooting(&entinfo))
+ {
+ //check if we can avoid this enemy
+ VectorSubtract(bs->origin, entinfo.origin, dir);
+ vectoangles(dir, angles);
+ //if the bot isn't in the fov of the enemy
+ if (!InFieldOfVision(entinfo.angles, 90, angles)) {
+ //update some stuff for this enemy
+ BotUpdateBattleInventory(bs, i);
+ //if the bot doesn't really want to fight
+ if (BotWantsToRetreat(bs)) continue;
+ }
+ }
+ //found an enemy
+ bs->enemy = entinfo.number;
+ if (curenemy >= 0) bs->enemysight_time = FloatTime() - 2;
+ else bs->enemysight_time = FloatTime();
+ bs->enemysuicide = qfalse;
+ bs->enemydeath_time = 0;
+ bs->enemyvisible_time = FloatTime();
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+BotTeamFlagCarrierVisible
+==================
+*/
+int BotTeamFlagCarrierVisible(bot_state_t *bs) {
+ int i;
+ float vis;
+ aas_entityinfo_t entinfo;
+
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ if (i == bs->client)
+ continue;
+ //
+ BotEntityInfo(i, &entinfo);
+ //if this player is active
+ if (!entinfo.valid)
+ continue;
+ //if this player is carrying a flag
+ if (!EntityCarriesFlag(&entinfo))
+ continue;
+ //if the flag carrier is not on the same team
+ if (!BotSameTeam(bs, i))
+ continue;
+ //if the flag carrier is not visible
+ vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
+ if (vis <= 0)
+ continue;
+ //
+ return i;
+ }
+ return -1;
+}
+
+/*
+==================
+BotTeamFlagCarrier
+==================
+*/
+int BotTeamFlagCarrier(bot_state_t *bs) {
+ int i;
+ aas_entityinfo_t entinfo;
+
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ if (i == bs->client)
+ continue;
+ //
+ BotEntityInfo(i, &entinfo);
+ //if this player is active
+ if (!entinfo.valid)
+ continue;
+ //if this player is carrying a flag
+ if (!EntityCarriesFlag(&entinfo))
+ continue;
+ //if the flag carrier is not on the same team
+ if (!BotSameTeam(bs, i))
+ continue;
+ //
+ return i;
+ }
+ return -1;
+}
+
+/*
+==================
+BotEnemyFlagCarrierVisible
+==================
+*/
+int BotEnemyFlagCarrierVisible(bot_state_t *bs) {
+ int i;
+ float vis;
+ aas_entityinfo_t entinfo;
+
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ if (i == bs->client)
+ continue;
+ //
+ BotEntityInfo(i, &entinfo);
+ //if this player is active
+ if (!entinfo.valid)
+ continue;
+ //if this player is carrying a flag
+ if (!EntityCarriesFlag(&entinfo))
+ continue;
+ //if the flag carrier is on the same team
+ if (BotSameTeam(bs, i))
+ continue;
+ //if the flag carrier is not visible
+ vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
+ if (vis <= 0)
+ continue;
+ //
+ return i;
+ }
+ return -1;
+}
+
+/*
+==================
+BotVisibleTeamMatesAndEnemies
+==================
+*/
+void BotVisibleTeamMatesAndEnemies(bot_state_t *bs, int *teammates, int *enemies, float range) {
+ int i;
+ float vis;
+ aas_entityinfo_t entinfo;
+ vec3_t dir;
+
+ if (teammates)
+ *teammates = 0;
+ if (enemies)
+ *enemies = 0;
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ if (i == bs->client)
+ continue;
+ //
+ BotEntityInfo(i, &entinfo);
+ //if this player is active
+ if (!entinfo.valid)
+ continue;
+ //if this player is carrying a flag
+ if (!EntityCarriesFlag(&entinfo))
+ continue;
+ //if not within range
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ if (VectorLengthSquared(dir) > Square(range))
+ continue;
+ //if the flag carrier is not visible
+ vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
+ if (vis <= 0)
+ continue;
+ //if the flag carrier is on the same team
+ if (BotSameTeam(bs, i)) {
+ if (teammates)
+ (*teammates)++;
+ }
+ else {
+ if (enemies)
+ (*enemies)++;
+ }
+ }
+}
+
+/*
+==================
+BotTeamCubeCarrierVisible
+==================
+*/
+int BotTeamCubeCarrierVisible(bot_state_t *bs) {
+ int i;
+ float vis;
+ aas_entityinfo_t entinfo;
+
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ if (i == bs->client) continue;
+ //
+ BotEntityInfo(i, &entinfo);
+ //if this player is active
+ if (!entinfo.valid) continue;
+ //if this player is carrying a flag
+ if (!EntityCarriesCubes(&entinfo)) continue;
+ //if the flag carrier is not on the same team
+ if (!BotSameTeam(bs, i)) continue;
+ //if the flag carrier is not visible
+ vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
+ if (vis <= 0) continue;
+ //
+ return i;
+ }
+ return -1;
+}
+
+/*
+==================
+BotEnemyCubeCarrierVisible
+==================
+*/
+int BotEnemyCubeCarrierVisible(bot_state_t *bs) {
+ int i;
+ float vis;
+ aas_entityinfo_t entinfo;
+
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ if (i == bs->client)
+ continue;
+ //
+ BotEntityInfo(i, &entinfo);
+ //if this player is active
+ if (!entinfo.valid)
+ continue;
+ //if this player is carrying a flag
+ if (!EntityCarriesCubes(&entinfo)) continue;
+ //if the flag carrier is on the same team
+ if (BotSameTeam(bs, i))
+ continue;
+ //if the flag carrier is not visible
+ vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
+ if (vis <= 0)
+ continue;
+ //
+ return i;
+ }
+ return -1;
+}
+//#endif
+
+/*
+==================
+BotAimAtEnemy
+==================
+*/
+void BotAimAtEnemy(bot_state_t *bs) {
+ int i, enemyvisible;
+ float dist, f, aim_skill, aim_accuracy, speed, reactiontime;
+ vec3_t dir, bestorigin, end, start, groundtarget, cmdmove, enemyvelocity;
+ vec3_t mins = {-4,-4,-4}, maxs = {4, 4, 4};
+ weaponinfo_t wi;
+ aas_entityinfo_t entinfo;
+ bot_goal_t goal;
+ bsp_trace_t trace;
+ vec3_t target;
+
+ //if the bot has no enemy
+ if (bs->enemy < 0) {
+ return;
+ }
+ //get the enemy entity information
+ BotEntityInfo(bs->enemy, &entinfo);
+ //if this is not a player (should be an obelisk)
+ if (bs->enemy >= MAX_CLIENTS) {
+ //if the obelisk is visible
+ VectorCopy(entinfo.origin, target);
+ // if attacking an obelisk
+ if ( bs->enemy == redobelisk.entitynum ||
+ bs->enemy == blueobelisk.entitynum ) {
+ target[2] += 32;
+ }
+ //aim at the obelisk
+ VectorSubtract(target, bs->eye, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ //set the aim target before trying to attack
+ VectorCopy(target, bs->aimtarget);
+ return;
+ }
+ //
+ //BotAI_Print(PRT_MESSAGE, "client %d: aiming at client %d\n", bs->entitynum, bs->enemy);
+ //
+ aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL, 0, 1);
+ aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY, 0, 1);
+ //
+ if (aim_skill > 0.95) {
+ //don't aim too early
+ reactiontime = 0.5 * trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_REACTIONTIME, 0, 1);
+ if (bs->enemysight_time > FloatTime() - reactiontime) return;
+ if (bs->teleport_time > FloatTime() - reactiontime) return;
+ }
+
+ //get the weapon information
+ trap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi);
+ //get the weapon specific aim accuracy and or aim skill
+ if (wi.number == WP_MACHINEGUN) {
+ aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1);
+ }
+ else if (wi.number == WP_SHOTGUN) {
+ aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_SHOTGUN, 0, 1);
+ }
+ else if (wi.number == WP_GRENADE_LAUNCHER) {
+ aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_GRENADELAUNCHER, 0, 1);
+ aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_GRENADELAUNCHER, 0, 1);
+ }
+ else if (wi.number == WP_ROCKET_LAUNCHER) {
+ aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_ROCKETLAUNCHER, 0, 1);
+ aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_ROCKETLAUNCHER, 0, 1);
+ }
+ else if (wi.number == WP_LIGHTNING) {
+ aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_LIGHTNING, 0, 1);
+ }
+ else if (wi.number == WP_RAILGUN) {
+ aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_RAILGUN, 0, 1);
+ }
+ else if (wi.number == WP_PLASMAGUN) {
+ aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_PLASMAGUN, 0, 1);
+ aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_PLASMAGUN, 0, 1);
+ }
+ else if (wi.number == WP_BFG) {
+ aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_BFG10K, 0, 1);
+ aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_BFG10K, 0, 1);
+ }
+ //
+ if (aim_accuracy <= 0) aim_accuracy = 0.0001f;
+ //get the enemy entity information
+ BotEntityInfo(bs->enemy, &entinfo);
+ //if the enemy is invisible then shoot crappy most of the time
+ if (EntityIsInvisible(&entinfo)) {
+ if (random() > 0.1) aim_accuracy *= 0.4f;
+ }
+ //
+ VectorSubtract(entinfo.origin, entinfo.lastvisorigin, enemyvelocity);
+ VectorScale(enemyvelocity, 1 / entinfo.update_time, enemyvelocity);
+ //enemy origin and velocity is remembered every 0.5 seconds
+ if (bs->enemyposition_time < FloatTime()) {
+ //
+ bs->enemyposition_time = FloatTime() + 0.5;
+ VectorCopy(enemyvelocity, bs->enemyvelocity);
+ VectorCopy(entinfo.origin, bs->enemyorigin);
+ }
+ //if not extremely skilled
+ if (aim_skill < 0.9) {
+ VectorSubtract(entinfo.origin, bs->enemyorigin, dir);
+ //if the enemy moved a bit
+ if (VectorLengthSquared(dir) > Square(48)) {
+ //if the enemy changed direction
+ if (DotProduct(bs->enemyvelocity, enemyvelocity) < 0) {
+ //aim accuracy should be worse now
+ aim_accuracy *= 0.7f;
+ }
+ }
+ }
+ //check visibility of enemy
+ enemyvisible = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy);
+ //if the enemy is visible
+ if (enemyvisible) {
+ //
+ VectorCopy(entinfo.origin, bestorigin);
+ bestorigin[2] += 8;
+ //get the start point shooting from
+ //NOTE: the x and y projectile start offsets are ignored
+ VectorCopy(bs->origin, start);
+ start[2] += bs->cur_ps.viewheight;
+ start[2] += wi.offset[2];
+ //
+ BotAI_Trace(&trace, start, mins, maxs, bestorigin, bs->entitynum, MASK_SHOT);
+ //if the enemy is NOT hit
+ if (trace.fraction <= 1 && trace.ent != entinfo.number) {
+ bestorigin[2] += 16;
+ }
+ //if it is not an instant hit weapon the bot might want to predict the enemy
+ if (wi.speed) {
+ //
+ VectorSubtract(bestorigin, bs->origin, dir);
+ dist = VectorLength(dir);
+ VectorSubtract(entinfo.origin, bs->enemyorigin, dir);
+ //if the enemy is NOT pretty far away and strafing just small steps left and right
+ if (!(dist > 100 && VectorLengthSquared(dir) < Square(32))) {
+ //if skilled anough do exact prediction
+ if (aim_skill > 0.8 &&
+ //if the weapon is ready to fire
+ bs->cur_ps.weaponstate == WEAPON_READY) {
+ aas_clientmove_t move;
+ vec3_t origin;
+
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ //distance towards the enemy
+ dist = VectorLength(dir);
+ //direction the enemy is moving in
+ VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir);
+ //
+ VectorScale(dir, 1 / entinfo.update_time, dir);
+ //
+ VectorCopy(entinfo.origin, origin);
+ origin[2] += 1;
+ //
+ VectorClear(cmdmove);
+ //AAS_ClearShownDebugLines();
+ trap_AAS_PredictClientMovement(&move, bs->enemy, origin,
+ PRESENCE_CROUCH, qfalse,
+ dir, cmdmove, 0,
+ dist * 10 / wi.speed, 0.1f, 0, 0, qfalse);
+ VectorCopy(move.endpos, bestorigin);
+ //BotAI_Print(PRT_MESSAGE, "%1.1f predicted speed = %f, frames = %f\n", FloatTime(), VectorLength(dir), dist * 10 / wi.speed);
+ }
+ //if not that skilled do linear prediction
+ else if (aim_skill > 0.4) {
+ VectorSubtract(entinfo.origin, bs->origin, dir);
+ //distance towards the enemy
+ dist = VectorLength(dir);
+ //direction the enemy is moving in
+ VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir);
+ dir[2] = 0;
+ //
+ speed = VectorNormalize(dir) / entinfo.update_time;
+ //botimport.Print(PRT_MESSAGE, "speed = %f, wi->speed = %f\n", speed, wi->speed);
+ //best spot to aim at
+ VectorMA(entinfo.origin, (dist / wi.speed) * speed, dir, bestorigin);
+ }
+ }
+ }
+ //if the projectile does radial damage
+ if (aim_skill > 0.6 && wi.proj.damagetype & DAMAGETYPE_RADIAL) {
+ //if the enemy isn't standing significantly higher than the bot
+ if (entinfo.origin[2] < bs->origin[2] + 16) {
+ //try to aim at the ground in front of the enemy
+ VectorCopy(entinfo.origin, end);
+ end[2] -= 64;
+ BotAI_Trace(&trace, entinfo.origin, NULL, NULL, end, entinfo.number, MASK_SHOT);
+ //
+ VectorCopy(bestorigin, groundtarget);
+ if (trace.startsolid) groundtarget[2] = entinfo.origin[2] - 16;
+ else groundtarget[2] = trace.endpos[2] - 8;
+ //trace a line from projectile start to ground target
+ BotAI_Trace(&trace, start, NULL, NULL, groundtarget, bs->entitynum, MASK_SHOT);
+ //if hitpoint is not vertically too far from the ground target
+ if (fabs(trace.endpos[2] - groundtarget[2]) < 50) {
+ VectorSubtract(trace.endpos, groundtarget, dir);
+ //if the hitpoint is near anough the ground target
+ if (VectorLengthSquared(dir) < Square(60)) {
+ VectorSubtract(trace.endpos, start, dir);
+ //if the hitpoint is far anough from the bot
+ if (VectorLengthSquared(dir) > Square(100)) {
+ //check if the bot is visible from the ground target
+ trace.endpos[2] += 1;
+ BotAI_Trace(&trace, trace.endpos, NULL, NULL, entinfo.origin, entinfo.number, MASK_SHOT);
+ if (trace.fraction >= 1) {
+ //botimport.Print(PRT_MESSAGE, "%1.1f aiming at ground\n", AAS_Time());
+ VectorCopy(groundtarget, bestorigin);
+ }
+ }
+ }
+ }
+ }
+ }
+ bestorigin[0] += 20 * crandom() * (1 - aim_accuracy);
+ bestorigin[1] += 20 * crandom() * (1 - aim_accuracy);
+ bestorigin[2] += 10 * crandom() * (1 - aim_accuracy);
+ }
+ else {
+ //
+ VectorCopy(bs->lastenemyorigin, bestorigin);
+ bestorigin[2] += 8;
+ //if the bot is skilled anough
+ if (aim_skill > 0.5) {
+ //do prediction shots around corners
+ if (wi.number == WP_BFG ||
+ wi.number == WP_ROCKET_LAUNCHER ||
+ wi.number == WP_GRENADE_LAUNCHER) {
+ //create the chase goal
+ goal.entitynum = bs->client;
+ goal.areanum = bs->areanum;
+ VectorCopy(bs->eye, goal.origin);
+ VectorSet(goal.mins, -8, -8, -8);
+ VectorSet(goal.maxs, 8, 8, 8);
+ //
+ if (trap_BotPredictVisiblePosition(bs->lastenemyorigin, bs->lastenemyareanum, &goal, TFL_DEFAULT, target)) {
+ VectorSubtract(target, bs->eye, dir);
+ if (VectorLengthSquared(dir) > Square(80)) {
+ VectorCopy(target, bestorigin);
+ bestorigin[2] -= 20;
+ }
+ }
+ aim_accuracy = 1;
+ }
+ }
+ }
+ //
+ if (enemyvisible) {
+ BotAI_Trace(&trace, bs->eye, NULL, NULL, bestorigin, bs->entitynum, MASK_SHOT);
+ VectorCopy(trace.endpos, bs->aimtarget);
+ }
+ else {
+ VectorCopy(bestorigin, bs->aimtarget);
+ }
+ //get aim direction
+ VectorSubtract(bestorigin, bs->eye, dir);
+ //
+ if (wi.number == WP_MACHINEGUN ||
+ wi.number == WP_SHOTGUN ||
+ wi.number == WP_LIGHTNING ||
+ wi.number == WP_RAILGUN) {
+ //distance towards the enemy
+ dist = VectorLength(dir);
+ if (dist > 150) dist = 150;
+ f = 0.6 + dist / 150 * 0.4;
+ aim_accuracy *= f;
+ }
+ //add some random stuff to the aim direction depending on the aim accuracy
+ if (aim_accuracy < 0.8) {
+ VectorNormalize(dir);
+ for (i = 0; i < 3; i++) dir[i] += 0.3 * crandom() * (1 - aim_accuracy);
+ }
+ //set the ideal view angles
+ vectoangles(dir, bs->ideal_viewangles);
+ //take the weapon spread into account for lower skilled bots
+ bs->ideal_viewangles[PITCH] += 6 * wi.vspread * crandom() * (1 - aim_accuracy);
+ bs->ideal_viewangles[PITCH] = AngleMod(bs->ideal_viewangles[PITCH]);
+ bs->ideal_viewangles[YAW] += 6 * wi.hspread * crandom() * (1 - aim_accuracy);
+ bs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]);
+ //if the bots should be really challenging
+ if (bot_challenge.integer) {
+ //if the bot is really accurate and has the enemy in view for some time
+ if (aim_accuracy > 0.9 && bs->enemysight_time < FloatTime() - 1) {
+ //set the view angles directly
+ if (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360;
+ VectorCopy(bs->ideal_viewangles, bs->viewangles);
+ trap_EA_View(bs->client, bs->viewangles);
+ }
+ }
+}
+
+/*
+==================
+BotCheckAttack
+==================
+*/
+void BotCheckAttack(bot_state_t *bs) {
+ float points, reactiontime, fov, firethrottle;
+ int attackentity;
+ bsp_trace_t bsptrace;
+ //float selfpreservation;
+ vec3_t forward, right, start, end, dir, angles;
+ weaponinfo_t wi;
+ bsp_trace_t trace;
+ aas_entityinfo_t entinfo;
+ vec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8};
+
+ attackentity = bs->enemy;
+ //
+ BotEntityInfo(attackentity, &entinfo);
+ // if not attacking a player
+ if (attackentity >= MAX_CLIENTS) {
+ // if attacking an obelisk
+ if ( entinfo.number == redobelisk.entitynum ||
+ entinfo.number == blueobelisk.entitynum ) {
+ // if obelisk is respawning return
+ if ( g_entities[entinfo.number].activator &&
+ g_entities[entinfo.number].activator->s.frame == 2 ) {
+ return;
+ }
+ }
+ }
+ //
+ reactiontime = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_REACTIONTIME, 0, 1);
+ if (bs->enemysight_time > FloatTime() - reactiontime) return;
+ if (bs->teleport_time > FloatTime() - reactiontime) return;
+ //if changing weapons
+ if (bs->weaponchange_time > FloatTime() - 0.1) return;
+ //check fire throttle characteristic
+ if (bs->firethrottlewait_time > FloatTime()) return;
+ firethrottle = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_FIRETHROTTLE, 0, 1);
+ if (bs->firethrottleshoot_time < FloatTime()) {
+ if (random() > firethrottle) {
+ bs->firethrottlewait_time = FloatTime() + firethrottle;
+ bs->firethrottleshoot_time = 0;
+ }
+ else {
+ bs->firethrottleshoot_time = FloatTime() + 1 - firethrottle;
+ bs->firethrottlewait_time = 0;
+ }
+ }
+ //
+ //
+ VectorSubtract(bs->aimtarget, bs->eye, dir);
+ //
+ if (bs->weaponnum == WP_GAUNTLET) {
+ if (VectorLengthSquared(dir) > Square(60)) {
+ return;
+ }
+ }
+ if (VectorLengthSquared(dir) < Square(100))
+ fov = 120;
+ else
+ fov = 50;
+ //
+ vectoangles(dir, angles);
+ if (!InFieldOfVision(bs->viewangles, fov, angles))
+ return;
+ BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, bs->aimtarget, bs->client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
+ if (bsptrace.fraction < 1 && bsptrace.ent != attackentity)
+ return;
+
+ //get the weapon info
+ trap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi);
+ //get the start point shooting from
+ VectorCopy(bs->origin, start);
+ start[2] += bs->cur_ps.viewheight;
+ AngleVectors(bs->viewangles, forward, right, NULL);
+ start[0] += forward[0] * wi.offset[0] + right[0] * wi.offset[1];
+ start[1] += forward[1] * wi.offset[0] + right[1] * wi.offset[1];
+ start[2] += forward[2] * wi.offset[0] + right[2] * wi.offset[1] + wi.offset[2];
+ //end point aiming at
+ VectorMA(start, 1000, forward, end);
+ //a little back to make sure not inside a very close enemy
+ VectorMA(start, -12, forward, start);
+ BotAI_Trace(&trace, start, mins, maxs, end, bs->entitynum, MASK_SHOT);
+ //if the entity is a client
+ if (trace.ent >= 0 && trace.ent < MAX_CLIENTS) {
+ if (trace.ent != attackentity) {
+ //if a teammate is hit
+ if (BotSameTeam(bs, trace.ent))
+ return;
+ }
+ }
+ //if won't hit the enemy or not attacking a player (obelisk)
+ if (trace.ent != attackentity || attackentity >= MAX_CLIENTS) {
+ //if the projectile does radial damage
+ if (wi.proj.damagetype & DAMAGETYPE_RADIAL) {
+ if (trace.fraction * 1000 < wi.proj.radius) {
+ points = (wi.proj.damage - 0.5 * trace.fraction * 1000) * 0.5;
+ if (points > 0) {
+ return;
+ }
+ }
+ //FIXME: check if a teammate gets radial damage
+ }
+ }
+ //if fire has to be release to activate weapon
+ if (wi.flags & WFL_FIRERELEASED) {
+ if (bs->flags & BFL_ATTACKED) {
+ trap_EA_Attack(bs->client);
+ }
+ }
+ else {
+ trap_EA_Attack(bs->client);
+ }
+ bs->flags ^= BFL_ATTACKED;
+}
+
+/*
+==================
+BotMapScripts
+==================
+*/
+void BotMapScripts(bot_state_t *bs) {
+ char info[1024];
+ char mapname[128];
+ int i, shootbutton;
+ float aim_accuracy;
+ aas_entityinfo_t entinfo;
+ vec3_t dir;
+
+ trap_GetServerinfo(info, sizeof(info));
+
+ strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1);
+ mapname[sizeof(mapname)-1] = '\0';
+
+ if (!Q_stricmp(mapname, "q3tourney6")) {
+ vec3_t mins = {700, 204, 672}, maxs = {964, 468, 680};
+ vec3_t buttonorg = {304, 352, 920};
+ //NOTE: NEVER use the func_bobbing in q3tourney6
+ bs->tfl &= ~TFL_FUNCBOB;
+ //if the bot is below the bounding box
+ if (bs->origin[0] > mins[0] && bs->origin[0] < maxs[0]) {
+ if (bs->origin[1] > mins[1] && bs->origin[1] < maxs[1]) {
+ if (bs->origin[2] < mins[2]) {
+ return;
+ }
+ }
+ }
+ shootbutton = qfalse;
+ //if an enemy is below this bounding box then shoot the button
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+
+ if (i == bs->client) continue;
+ //
+ BotEntityInfo(i, &entinfo);
+ //
+ if (!entinfo.valid) continue;
+ //if the enemy isn't dead and the enemy isn't the bot self
+ if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;
+ //
+ if (entinfo.origin[0] > mins[0] && entinfo.origin[0] < maxs[0]) {
+ if (entinfo.origin[1] > mins[1] && entinfo.origin[1] < maxs[1]) {
+ if (entinfo.origin[2] < mins[2]) {
+ //if there's a team mate below the crusher
+ if (BotSameTeam(bs, i)) {
+ shootbutton = qfalse;
+ break;
+ }
+ else {
+ shootbutton = qtrue;
+ }
+ }
+ }
+ }
+ }
+ if (shootbutton) {
+ bs->flags |= BFL_IDEALVIEWSET;
+ VectorSubtract(buttonorg, bs->eye, dir);
+ vectoangles(dir, bs->ideal_viewangles);
+ aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY, 0, 1);
+ bs->ideal_viewangles[PITCH] += 8 * crandom() * (1 - aim_accuracy);
+ bs->ideal_viewangles[PITCH] = AngleMod(bs->ideal_viewangles[PITCH]);
+ bs->ideal_viewangles[YAW] += 8 * crandom() * (1 - aim_accuracy);
+ bs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]);
+ //
+ if (InFieldOfVision(bs->viewangles, 20, bs->ideal_viewangles)) {
+ trap_EA_Attack(bs->client);
+ }
+ }
+ }
+ else if (!Q_stricmp(mapname, "mpq3tourney6")) {
+ //NOTE: NEVER use the func_bobbing in mpq3tourney6
+ bs->tfl &= ~TFL_FUNCBOB;
+ }
+}
+
+/*
+==================
+BotSetMovedir
+==================
+*/
+// bk001205 - made these static
+static vec3_t VEC_UP = {0, -1, 0};
+static vec3_t MOVEDIR_UP = {0, 0, 1};
+static vec3_t VEC_DOWN = {0, -2, 0};
+static vec3_t MOVEDIR_DOWN = {0, 0, -1};
+
+void BotSetMovedir(vec3_t angles, vec3_t movedir) {
+ if (VectorCompare(angles, VEC_UP)) {
+ VectorCopy(MOVEDIR_UP, movedir);
+ }
+ else if (VectorCompare(angles, VEC_DOWN)) {
+ VectorCopy(MOVEDIR_DOWN, movedir);
+ }
+ else {
+ AngleVectors(angles, movedir, NULL, NULL);
+ }
+}
+
+/*
+==================
+BotModelMinsMaxs
+
+this is ugly
+==================
+*/
+int BotModelMinsMaxs(int modelindex, int eType, int contents, vec3_t mins, vec3_t maxs) {
+ gentity_t *ent;
+ int i;
+
+ ent = &g_entities[0];
+ for (i = 0; i < level.num_entities; i++, ent++) {
+ if ( !ent->inuse ) {
+ continue;
+ }
+ if ( eType && ent->s.eType != eType) {
+ continue;
+ }
+ if ( contents && ent->r.contents != contents) {
+ continue;
+ }
+ if (ent->s.modelindex == modelindex) {
+ if (mins)
+ VectorAdd(ent->r.currentOrigin, ent->r.mins, mins);
+ if (maxs)
+ VectorAdd(ent->r.currentOrigin, ent->r.maxs, maxs);
+ return i;
+ }
+ }
+ if (mins)
+ VectorClear(mins);
+ if (maxs)
+ VectorClear(maxs);
+ return 0;
+}
+
+/*
+==================
+BotFuncButtonGoal
+==================
+*/
+int BotFuncButtonActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) {
+ int i, areas[10], numareas, modelindex, entitynum;
+ char model[128];
+ float lip, dist, health, angle;
+ vec3_t size, start, end, mins, maxs, angles, points[10];
+ vec3_t movedir, origin, goalorigin, bboxmins, bboxmaxs;
+ vec3_t extramins = {1, 1, 1}, extramaxs = {-1, -1, -1};
+ bsp_trace_t bsptrace;
+
+ activategoal->shoot = qfalse;
+ VectorClear(activategoal->target);
+ //create a bot goal towards the button
+ trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model));
+ if (!*model)
+ return qfalse;
+ modelindex = atoi(model+1);
+ if (!modelindex)
+ return qfalse;
+ VectorClear(angles);
+ entitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs);
+ //get the lip of the button
+ trap_AAS_FloatForBSPEpairKey(bspent, "lip", &lip);
+ if (!lip) lip = 4;
+ //get the move direction from the angle
+ trap_AAS_FloatForBSPEpairKey(bspent, "angle", &angle);
+ VectorSet(angles, 0, angle, 0);
+ BotSetMovedir(angles, movedir);
+ //button size
+ VectorSubtract(maxs, mins, size);
+ //button origin
+ VectorAdd(mins, maxs, origin);
+ VectorScale(origin, 0.5, origin);
+ //touch distance of the button
+ dist = fabs(movedir[0]) * size[0] + fabs(movedir[1]) * size[1] + fabs(movedir[2]) * size[2];
+ dist *= 0.5;
+ //
+ trap_AAS_FloatForBSPEpairKey(bspent, "health", &health);
+ //if the button is shootable
+ if (health) {
+ //calculate the shoot target
+ VectorMA(origin, -dist, movedir, goalorigin);
+ //
+ VectorCopy(goalorigin, activategoal->target);
+ activategoal->shoot = qtrue;
+ //
+ BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, goalorigin, bs->entitynum, MASK_SHOT);
+ // if the button is visible from the current position
+ if (bsptrace.fraction >= 1.0 || bsptrace.ent == entitynum) {
+ //
+ activategoal->goal.entitynum = entitynum; //NOTE: this is the entity number of the shootable button
+ activategoal->goal.number = 0;
+ activategoal->goal.flags = 0;
+ VectorCopy(bs->origin, activategoal->goal.origin);
+ activategoal->goal.areanum = bs->areanum;
+ VectorSet(activategoal->goal.mins, -8, -8, -8);
+ VectorSet(activategoal->goal.maxs, 8, 8, 8);
+ //
+ return qtrue;
+ }
+ else {
+ //create a goal from where the button is visible and shoot at the button from there
+ //add bounding box size to the dist
+ trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs);
+ for (i = 0; i < 3; i++) {
+ if (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]);
+ else dist += fabs(movedir[i]) * fabs(bboxmins[i]);
+ }
+ //calculate the goal origin
+ VectorMA(origin, -dist, movedir, goalorigin);
+ //
+ VectorCopy(goalorigin, start);
+ start[2] += 24;
+ VectorCopy(start, end);
+ end[2] -= 512;
+ numareas = trap_AAS_TraceAreas(start, end, areas, points, 10);
+ //
+ for (i = numareas-1; i >= 0; i--) {
+ if (trap_AAS_AreaReachability(areas[i])) {
+ break;
+ }
+ }
+ if (i < 0) {
+ // FIXME: trace forward and maybe in other directions to find a valid area
+ }
+ if (i >= 0) {
+ //
+ VectorCopy(points[i], activategoal->goal.origin);
+ activategoal->goal.areanum = areas[i];
+ VectorSet(activategoal->goal.mins, 8, 8, 8);
+ VectorSet(activategoal->goal.maxs, -8, -8, -8);
+ //
+ for (i = 0; i < 3; i++)
+ {
+ if (movedir[i] < 0) activategoal->goal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]);
+ else activategoal->goal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]);
+ } //end for
+ //
+ activategoal->goal.entitynum = entitynum;
+ activategoal->goal.number = 0;
+ activategoal->goal.flags = 0;
+ return qtrue;
+ }
+ }
+ return qfalse;
+ }
+ else {
+ //add bounding box size to the dist
+ trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs);
+ for (i = 0; i < 3; i++) {
+ if (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]);
+ else dist += fabs(movedir[i]) * fabs(bboxmins[i]);
+ }
+ //calculate the goal origin
+ VectorMA(origin, -dist, movedir, goalorigin);
+ //
+ VectorCopy(goalorigin, start);
+ start[2] += 24;
+ VectorCopy(start, end);
+ end[2] -= 100;
+ numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10);
+ //
+ for (i = 0; i < numareas; i++) {
+ if (trap_AAS_AreaReachability(areas[i])) {
+ break;
+ }
+ }
+ if (i < numareas) {
+ //
+ VectorCopy(origin, activategoal->goal.origin);
+ activategoal->goal.areanum = areas[i];
+ VectorSubtract(mins, origin, activategoal->goal.mins);
+ VectorSubtract(maxs, origin, activategoal->goal.maxs);
+ //
+ for (i = 0; i < 3; i++)
+ {
+ if (movedir[i] < 0) activategoal->goal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]);
+ else activategoal->goal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]);
+ } //end for
+ //
+ activategoal->goal.entitynum = entitynum;
+ activategoal->goal.number = 0;
+ activategoal->goal.flags = 0;
+ return qtrue;
+ }
+ }
+ return qfalse;
+}
+
+/*
+==================
+BotFuncDoorGoal
+==================
+*/
+int BotFuncDoorActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) {
+ int modelindex, entitynum;
+ char model[MAX_INFO_STRING];
+ vec3_t mins, maxs, origin, angles;
+
+ //shoot at the shootable door
+ trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model));
+ if (!*model)
+ return qfalse;
+ modelindex = atoi(model+1);
+ if (!modelindex)
+ return qfalse;
+ VectorClear(angles);
+ entitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs);
+ //door origin
+ VectorAdd(mins, maxs, origin);
+ VectorScale(origin, 0.5, origin);
+ VectorCopy(origin, activategoal->target);
+ activategoal->shoot = qtrue;
+ //
+ activategoal->goal.entitynum = entitynum; //NOTE: this is the entity number of the shootable door
+ activategoal->goal.number = 0;
+ activategoal->goal.flags = 0;
+ VectorCopy(bs->origin, activategoal->goal.origin);
+ activategoal->goal.areanum = bs->areanum;
+ VectorSet(activategoal->goal.mins, -8, -8, -8);
+ VectorSet(activategoal->goal.maxs, 8, 8, 8);
+ return qtrue;
+}
+
+/*
+==================
+BotTriggerMultipleGoal
+==================
+*/
+int BotTriggerMultipleActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) {
+ int i, areas[10], numareas, modelindex, entitynum;
+ char model[128];
+ vec3_t start, end, mins, maxs, angles;
+ vec3_t origin, goalorigin;
+
+ activategoal->shoot = qfalse;
+ VectorClear(activategoal->target);
+ //create a bot goal towards the trigger
+ trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model));
+ if (!*model)
+ return qfalse;
+ modelindex = atoi(model+1);
+ if (!modelindex)
+ return qfalse;
+ VectorClear(angles);
+ entitynum = BotModelMinsMaxs(modelindex, 0, CONTENTS_TRIGGER, mins, maxs);
+ //trigger origin
+ VectorAdd(mins, maxs, origin);
+ VectorScale(origin, 0.5, origin);
+ VectorCopy(origin, goalorigin);
+ //
+ VectorCopy(goalorigin, start);
+ start[2] += 24;
+ VectorCopy(start, end);
+ end[2] -= 100;
+ numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10);
+ //
+ for (i = 0; i < numareas; i++) {
+ if (trap_AAS_AreaReachability(areas[i])) {
+ break;
+ }
+ }
+ if (i < numareas) {
+ VectorCopy(origin, activategoal->goal.origin);
+ activategoal->goal.areanum = areas[i];
+ VectorSubtract(mins, origin, activategoal->goal.mins);
+ VectorSubtract(maxs, origin, activategoal->goal.maxs);
+ //
+ activategoal->goal.entitynum = entitynum;
+ activategoal->goal.number = 0;
+ activategoal->goal.flags = 0;
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+BotPopFromActivateGoalStack
+==================
+*/
+int BotPopFromActivateGoalStack(bot_state_t *bs) {
+ if (!bs->activatestack)
+ return qfalse;
+ BotEnableActivateGoalAreas(bs->activatestack, qtrue);
+ bs->activatestack->inuse = qfalse;
+ bs->activatestack->justused_time = FloatTime();
+ bs->activatestack = bs->activatestack->next;
+ return qtrue;
+}
+
+/*
+==================
+BotPushOntoActivateGoalStack
+==================
+*/
+int BotPushOntoActivateGoalStack(bot_state_t *bs, bot_activategoal_t *activategoal) {
+ int i, best;
+ float besttime;
+
+ best = -1;
+ besttime = FloatTime() + 9999;
+ //
+ for (i = 0; i < MAX_ACTIVATESTACK; i++) {
+ if (!bs->activategoalheap[i].inuse) {
+ if (bs->activategoalheap[i].justused_time < besttime) {
+ besttime = bs->activategoalheap[i].justused_time;
+ best = i;
+ }
+ }
+ }
+ if (best != -1) {
+ memcpy(&bs->activategoalheap[best], activategoal, sizeof(bot_activategoal_t));
+ bs->activategoalheap[best].inuse = qtrue;
+ bs->activategoalheap[best].next = bs->activatestack;
+ bs->activatestack = &bs->activategoalheap[best];
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+BotClearActivateGoalStack
+==================
+*/
+void BotClearActivateGoalStack(bot_state_t *bs) {
+ while(bs->activatestack)
+ BotPopFromActivateGoalStack(bs);
+}
+
+/*
+==================
+BotEnableActivateGoalAreas
+==================
+*/
+void BotEnableActivateGoalAreas(bot_activategoal_t *activategoal, int enable) {
+ int i;
+
+ if (activategoal->areasdisabled == !enable)
+ return;
+ for (i = 0; i < activategoal->numareas; i++)
+ trap_AAS_EnableRoutingArea( activategoal->areas[i], enable );
+ activategoal->areasdisabled = !enable;
+}
+
+/*
+==================
+BotIsGoingToActivateEntity
+==================
+*/
+int BotIsGoingToActivateEntity(bot_state_t *bs, int entitynum) {
+ bot_activategoal_t *a;
+ int i;
+
+ for (a = bs->activatestack; a; a = a->next) {
+ if (a->time < FloatTime())
+ continue;
+ if (a->goal.entitynum == entitynum)
+ return qtrue;
+ }
+ for (i = 0; i < MAX_ACTIVATESTACK; i++) {
+ if (bs->activategoalheap[i].inuse)
+ continue;
+ //
+ if (bs->activategoalheap[i].goal.entitynum == entitynum) {
+ // if the bot went for this goal less than 2 seconds ago
+ if (bs->activategoalheap[i].justused_time > FloatTime() - 2)
+ return qtrue;
+ }
+ }
+ return qfalse;
+}
+
+/*
+==================
+BotGetActivateGoal
+
+ returns the number of the bsp entity to activate
+ goal->entitynum will be set to the game entity to activate
+==================
+*/
+//#define OBSTACLEDEBUG
+
+int BotGetActivateGoal(bot_state_t *bs, int entitynum, bot_activategoal_t *activategoal) {
+ int i, ent, cur_entities[10], spawnflags, modelindex, areas[MAX_ACTIVATEAREAS*2], numareas, t;
+ char model[MAX_INFO_STRING], tmpmodel[128];
+ char target[128], classname[128];
+ float health;
+ char targetname[10][128];
+ aas_entityinfo_t entinfo;
+ aas_areainfo_t areainfo;
+ vec3_t origin, angles, absmins, absmaxs;
+
+ memset(activategoal, 0, sizeof(bot_activategoal_t));
+ BotEntityInfo(entitynum, &entinfo);
+ Com_sprintf(model, sizeof( model ), "*%d", entinfo.modelindex);
+ for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) {
+ if (!trap_AAS_ValueForBSPEpairKey(ent, "model", tmpmodel, sizeof(tmpmodel))) continue;
+ if (!strcmp(model, tmpmodel)) break;
+ }
+ if (!ent) {
+ BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no entity found with model %s\n", model);
+ return 0;
+ }
+ trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname));
+ if (!*classname) {
+ BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with model %s has no classname\n", model);
+ return 0;
+ }
+ //if it is a door
+ if (!strcmp(classname, "func_door")) {
+ if (trap_AAS_FloatForBSPEpairKey(ent, "health", &health)) {
+ //if the door has health then the door must be shot to open
+ if (health) {
+ BotFuncDoorActivateGoal(bs, ent, activategoal);
+ return ent;
+ }
+ }
+ //
+ trap_AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags);
+ // if the door starts open then just wait for the door to return
+ if ( spawnflags & 1 )
+ return 0;
+ //get the door origin
+ if (!trap_AAS_VectorForBSPEpairKey(ent, "origin", origin)) {
+ VectorClear(origin);
+ }
+ //if the door is open or opening already
+ if (!VectorCompare(origin, entinfo.origin))
+ return 0;
+ // store all the areas the door is in
+ trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model));
+ if (*model) {
+ modelindex = atoi(model+1);
+ if (modelindex) {
+ VectorClear(angles);
+ BotModelMinsMaxs(modelindex, ET_MOVER, 0, absmins, absmaxs);
+ //
+ numareas = trap_AAS_BBoxAreas(absmins, absmaxs, areas, MAX_ACTIVATEAREAS*2);
+ // store the areas with reachabilities first
+ for (i = 0; i < numareas; i++) {
+ if (activategoal->numareas >= MAX_ACTIVATEAREAS)
+ break;
+ if ( !trap_AAS_AreaReachability(areas[i]) ) {
+ continue;
+ }
+ trap_AAS_AreaInfo(areas[i], &areainfo);
+ if (areainfo.contents & AREACONTENTS_MOVER) {
+ activategoal->areas[activategoal->numareas++] = areas[i];
+ }
+ }
+ // store any remaining areas
+ for (i = 0; i < numareas; i++) {
+ if (activategoal->numareas >= MAX_ACTIVATEAREAS)
+ break;
+ if ( trap_AAS_AreaReachability(areas[i]) ) {
+ continue;
+ }
+ trap_AAS_AreaInfo(areas[i], &areainfo);
+ if (areainfo.contents & AREACONTENTS_MOVER) {
+ activategoal->areas[activategoal->numareas++] = areas[i];
+ }
+ }
+ }
+ }
+ }
+ // if the bot is blocked by or standing on top of a button
+ if (!strcmp(classname, "func_button")) {
+ return 0;
+ }
+ // get the targetname so we can find an entity with a matching target
+ if (!trap_AAS_ValueForBSPEpairKey(ent, "targetname", targetname[0], sizeof(targetname[0]))) {
+ if (bot_developer.integer) {
+ BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with model \"%s\" has no targetname\n", model);
+ }
+ return 0;
+ }
+ // allow tree-like activation
+ cur_entities[0] = trap_AAS_NextBSPEntity(0);
+ for (i = 0; i >= 0 && i < 10;) {
+ for (ent = cur_entities[i]; ent; ent = trap_AAS_NextBSPEntity(ent)) {
+ if (!trap_AAS_ValueForBSPEpairKey(ent, "target", target, sizeof(target))) continue;
+ if (!strcmp(targetname[i], target)) {
+ cur_entities[i] = trap_AAS_NextBSPEntity(ent);
+ break;
+ }
+ }
+ if (!ent) {
+ if (bot_developer.integer) {
+ BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no entity with target \"%s\"\n", targetname[i]);
+ }
+ i--;
+ continue;
+ }
+ if (!trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname))) {
+ if (bot_developer.integer) {
+ BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with target \"%s\" has no classname\n", targetname[i]);
+ }
+ continue;
+ }
+ // BSP button model
+ if (!strcmp(classname, "func_button")) {
+ //
+ if (!BotFuncButtonActivateGoal(bs, ent, activategoal))
+ continue;
+ // if the bot tries to activate this button already
+ if ( bs->activatestack && bs->activatestack->inuse &&
+ bs->activatestack->goal.entitynum == activategoal->goal.entitynum &&
+ bs->activatestack->time > FloatTime() &&
+ bs->activatestack->start_time < FloatTime() - 2)
+ continue;
+ // if the bot is in a reachability area
+ if ( trap_AAS_AreaReachability(bs->areanum) ) {
+ // disable all areas the blocking entity is in
+ BotEnableActivateGoalAreas( activategoal, qfalse );
+ //
+ t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, activategoal->goal.areanum, bs->tfl);
+ // if the button is not reachable
+ if (!t) {
+ continue;
+ }
+ activategoal->time = FloatTime() + t * 0.01 + 5;
+ }
+ return ent;
+ }
+ // invisible trigger multiple box
+ else if (!strcmp(classname, "trigger_multiple")) {
+ //
+ if (!BotTriggerMultipleActivateGoal(bs, ent, activategoal))
+ continue;
+ // if the bot tries to activate this trigger already
+ if ( bs->activatestack && bs->activatestack->inuse &&
+ bs->activatestack->goal.entitynum == activategoal->goal.entitynum &&
+ bs->activatestack->time > FloatTime() &&
+ bs->activatestack->start_time < FloatTime() - 2)
+ continue;
+ // if the bot is in a reachability area
+ if ( trap_AAS_AreaReachability(bs->areanum) ) {
+ // disable all areas the blocking entity is in
+ BotEnableActivateGoalAreas( activategoal, qfalse );
+ //
+ t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, activategoal->goal.areanum, bs->tfl);
+ // if the trigger is not reachable
+ if (!t) {
+ continue;
+ }
+ activategoal->time = FloatTime() + t * 0.01 + 5;
+ }
+ return ent;
+ }
+ else if (!strcmp(classname, "func_timer")) {
+ // just skip the func_timer
+ continue;
+ }
+ // the actual button or trigger might be linked through a target_relay or target_delay
+ else if (!strcmp(classname, "target_relay") || !strcmp(classname, "target_delay")) {
+ if (trap_AAS_ValueForBSPEpairKey(ent, "targetname", targetname[i+1], sizeof(targetname[0]))) {
+ i++;
+ cur_entities[i] = trap_AAS_NextBSPEntity(0);
+ }
+ }
+ }
+#ifdef OBSTACLEDEBUG
+ BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no valid activator for entity with target \"%s\"\n", targetname[0]);
+#endif
+ return 0;
+}
+
+/*
+==================
+BotGoForActivateGoal
+==================
+*/
+int BotGoForActivateGoal(bot_state_t *bs, bot_activategoal_t *activategoal) {
+ aas_entityinfo_t activateinfo;
+
+ activategoal->inuse = qtrue;
+ if (!activategoal->time)
+ activategoal->time = FloatTime() + 10;
+ activategoal->start_time = FloatTime();
+ BotEntityInfo(activategoal->goal.entitynum, &activateinfo);
+ VectorCopy(activateinfo.origin, activategoal->origin);
+ //
+ if (BotPushOntoActivateGoalStack(bs, activategoal)) {
+ // enter the activate entity AI node
+ AIEnter_Seek_ActivateEntity(bs, "BotGoForActivateGoal");
+ return qtrue;
+ }
+ else {
+ // enable any routing areas that were disabled
+ BotEnableActivateGoalAreas(activategoal, qtrue);
+ return qfalse;
+ }
+}
+
+/*
+==================
+BotPrintActivateGoalInfo
+==================
+*/
+void BotPrintActivateGoalInfo(bot_state_t *bs, bot_activategoal_t *activategoal, int bspent) {
+ char netname[MAX_NETNAME];
+ char classname[128];
+ char buf[128];
+
+ ClientName(bs->client, netname, sizeof(netname));
+ trap_AAS_ValueForBSPEpairKey(bspent, "classname", classname, sizeof(classname));
+ if (activategoal->shoot) {
+ Com_sprintf(buf, sizeof(buf), "%s: I have to shoot at a %s from %1.1f %1.1f %1.1f in area %d\n",
+ netname, classname,
+ activategoal->goal.origin[0],
+ activategoal->goal.origin[1],
+ activategoal->goal.origin[2],
+ activategoal->goal.areanum);
+ }
+ else {
+ Com_sprintf(buf, sizeof(buf), "%s: I have to activate a %s at %1.1f %1.1f %1.1f in area %d\n",
+ netname, classname,
+ activategoal->goal.origin[0],
+ activategoal->goal.origin[1],
+ activategoal->goal.origin[2],
+ activategoal->goal.areanum);
+ }
+ trap_EA_Say(bs->client, buf);
+}
+
+/*
+==================
+BotRandomMove
+==================
+*/
+void BotRandomMove(bot_state_t *bs, bot_moveresult_t *moveresult) {
+ vec3_t dir, angles;
+
+ angles[0] = 0;
+ angles[1] = random() * 360;
+ angles[2] = 0;
+ AngleVectors(angles, dir, NULL, NULL);
+
+ trap_BotMoveInDirection(bs->ms, dir, 400, MOVE_WALK);
+
+ moveresult->failure = qfalse;
+ VectorCopy(dir, moveresult->movedir);
+}
+
+/*
+==================
+BotAIBlocked
+
+Very basic handling of bots being blocked by other entities.
+Check what kind of entity is blocking the bot and try to activate
+it. If that's not an option then try to walk around or over the entity.
+Before the bot ends in this part of the AI it should predict which doors to
+open, which buttons to activate etc.
+==================
+*/
+void BotAIBlocked(bot_state_t *bs, bot_moveresult_t *moveresult, int activate) {
+ int movetype, bspent;
+ vec3_t hordir, start, end, mins, maxs, sideward, angles, up = {0, 0, 1};
+ aas_entityinfo_t entinfo;
+ bot_activategoal_t activategoal;
+
+ // if the bot is not blocked by anything
+ if (!moveresult->blocked) {
+ bs->notblocked_time = FloatTime();
+ return;
+ }
+ // if stuck in a solid area
+ if ( moveresult->type == RESULTTYPE_INSOLIDAREA ) {
+ // move in a random direction in the hope to get out
+ BotRandomMove(bs, moveresult);
+ //
+ return;
+ }
+ // get info for the entity that is blocking the bot
+ BotEntityInfo(moveresult->blockentity, &entinfo);
+#ifdef OBSTACLEDEBUG
+ ClientName(bs->client, netname, sizeof(netname));
+ BotAI_Print(PRT_MESSAGE, "%s: I'm blocked by model %d\n", netname, entinfo.modelindex);
+#endif // OBSTACLEDEBUG
+ // if blocked by a bsp model and the bot wants to activate it
+ if (activate && entinfo.modelindex > 0 && entinfo.modelindex <= max_bspmodelindex) {
+ // find the bsp entity which should be activated in order to get the blocking entity out of the way
+ bspent = BotGetActivateGoal(bs, entinfo.number, &activategoal);
+ if (bspent) {
+ //
+ if (bs->activatestack && !bs->activatestack->inuse)
+ bs->activatestack = NULL;
+ // if not already trying to activate this entity
+ if (!BotIsGoingToActivateEntity(bs, activategoal.goal.entitynum)) {
+ //
+ BotGoForActivateGoal(bs, &activategoal);
+ }
+ // if ontop of an obstacle or
+ // if the bot is not in a reachability area it'll still
+ // need some dynamic obstacle avoidance, otherwise return
+ if (!(moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE) &&
+ trap_AAS_AreaReachability(bs->areanum))
+ return;
+ }
+ else {
+ // enable any routing areas that were disabled
+ BotEnableActivateGoalAreas(&activategoal, qtrue);
+ }
+ }
+ // just some basic dynamic obstacle avoidance code
+ hordir[0] = moveresult->movedir[0];
+ hordir[1] = moveresult->movedir[1];
+ hordir[2] = 0;
+ // if no direction just take a random direction
+ if (VectorNormalize(hordir) < 0.1) {
+ VectorSet(angles, 0, 360 * random(), 0);
+ AngleVectors(angles, hordir, NULL, NULL);
+ }
+ //
+ //if (moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE) movetype = MOVE_JUMP;
+ //else
+ movetype = MOVE_WALK;
+ // if there's an obstacle at the bot's feet and head then
+ // the bot might be able to crouch through
+ VectorCopy(bs->origin, start);
+ start[2] += 18;
+ VectorMA(start, 5, hordir, end);
+ VectorSet(mins, -16, -16, -24);
+ VectorSet(maxs, 16, 16, 4);
+ //
+ //bsptrace = AAS_Trace(start, mins, maxs, end, bs->entitynum, MASK_PLAYERSOLID);
+ //if (bsptrace.fraction >= 1) movetype = MOVE_CROUCH;
+ // get the sideward vector
+ CrossProduct(hordir, up, sideward);
+ //
+ if (bs->flags & BFL_AVOIDRIGHT) VectorNegate(sideward, sideward);
+ // try to crouch straight forward?
+ if (movetype != MOVE_CROUCH || !trap_BotMoveInDirection(bs->ms, hordir, 400, movetype)) {
+ // perform the movement
+ if (!trap_BotMoveInDirection(bs->ms, sideward, 400, movetype)) {
+ // flip the avoid direction flag
+ bs->flags ^= BFL_AVOIDRIGHT;
+ // flip the direction
+ // VectorNegate(sideward, sideward);
+ VectorMA(sideward, -1, hordir, sideward);
+ // move in the other direction
+ trap_BotMoveInDirection(bs->ms, sideward, 400, movetype);
+ }
+ }
+ //
+ if (bs->notblocked_time < FloatTime() - 0.4) {
+ // just reset goals and hope the bot will go into another direction?
+ // is this still needed??
+ if (bs->ainode == AINode_Seek_NBG) bs->nbg_time = 0;
+ else if (bs->ainode == AINode_Seek_LTG) bs->ltg_time = 0;
+ }
+}
+
+/*
+==================
+BotAIPredictObstacles
+
+Predict the route towards the goal and check if the bot
+will be blocked by certain obstacles. When the bot has obstacles
+on it's path the bot should figure out if they can be removed
+by activating certain entities.
+==================
+*/
+int BotAIPredictObstacles(bot_state_t *bs, bot_goal_t *goal) {
+ int modelnum, entitynum, bspent;
+ bot_activategoal_t activategoal;
+ aas_predictroute_t route;
+
+ if (!bot_predictobstacles.integer)
+ return qfalse;
+
+ // always predict when the goal change or at regular intervals
+ if (bs->predictobstacles_goalareanum == goal->areanum &&
+ bs->predictobstacles_time > FloatTime() - 6) {
+ return qfalse;
+ }
+ bs->predictobstacles_goalareanum = goal->areanum;
+ bs->predictobstacles_time = FloatTime();
+
+ // predict at most 100 areas or 10 seconds ahead
+ trap_AAS_PredictRoute(&route, bs->areanum, bs->origin,
+ goal->areanum, bs->tfl, 100, 1000,
+ RSE_USETRAVELTYPE|RSE_ENTERCONTENTS,
+ AREACONTENTS_MOVER, TFL_BRIDGE, 0);
+ // if bot has to travel through an area with a mover
+ if (route.stopevent & RSE_ENTERCONTENTS) {
+ // if the bot will run into a mover
+ if (route.endcontents & AREACONTENTS_MOVER) {
+ //NOTE: this only works with bspc 2.1 or higher
+ modelnum = (route.endcontents & AREACONTENTS_MODELNUM) >> AREACONTENTS_MODELNUMSHIFT;
+ if (modelnum) {
+ //
+ entitynum = BotModelMinsMaxs(modelnum, ET_MOVER, 0, NULL, NULL);
+ if (entitynum) {
+ //NOTE: BotGetActivateGoal already checks if the door is open or not
+ bspent = BotGetActivateGoal(bs, entitynum, &activategoal);
+ if (bspent) {
+ //
+ if (bs->activatestack && !bs->activatestack->inuse)
+ bs->activatestack = NULL;
+ // if not already trying to activate this entity
+ if (!BotIsGoingToActivateEntity(bs, activategoal.goal.entitynum)) {
+ //
+ //BotAI_Print(PRT_MESSAGE, "blocked by mover model %d, entity %d ?\n", modelnum, entitynum);
+ //
+ BotGoForActivateGoal(bs, &activategoal);
+ return qtrue;
+ }
+ else {
+ // enable any routing areas that were disabled
+ BotEnableActivateGoalAreas(&activategoal, qtrue);
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (route.stopevent & RSE_USETRAVELTYPE) {
+ if (route.endtravelflags & TFL_BRIDGE) {
+ //FIXME: check if the bridge is available to travel over
+ }
+ }
+ return qfalse;
+}
+
+/*
+==================
+BotCheckConsoleMessages
+==================
+*/
+void BotCheckConsoleMessages(bot_state_t *bs) {
+ char botname[MAX_NETNAME], message[MAX_MESSAGE_SIZE], netname[MAX_NETNAME], *ptr;
+ float chat_reply;
+ int context, handle;
+ bot_consolemessage_t m;
+ bot_match_t match;
+
+ //the name of this bot
+ ClientName(bs->client, botname, sizeof(botname));
+ //
+ while((handle = trap_BotNextConsoleMessage(bs->cs, &m)) != 0) {
+ //if the chat state is flooded with messages the bot will read them quickly
+ if (trap_BotNumConsoleMessages(bs->cs) < 10) {
+ //if it is a chat message the bot needs some time to read it
+ if (m.type == CMS_CHAT && m.time > FloatTime() - (1 + random())) break;
+ }
+ //
+ ptr = m.message;
+ //if it is a chat message then don't unify white spaces and don't
+ //replace synonyms in the netname
+ if (m.type == CMS_CHAT) {
+ //
+ if (trap_BotFindMatch(m.message, &match, MTCONTEXT_REPLYCHAT)) {
+ ptr = m.message + match.variables[MESSAGE].offset;
+ }
+ }
+ //unify the white spaces in the message
+ trap_UnifyWhiteSpaces(ptr);
+ //replace synonyms in the right context
+ context = BotSynonymContext(bs);
+ trap_BotReplaceSynonyms(ptr, context);
+ //if there's no match
+ if (!BotMatchMessage(bs, m.message)) {
+ //if it is a chat message
+ if (m.type == CMS_CHAT && !bot_nochat.integer) {
+ //
+ if (!trap_BotFindMatch(m.message, &match, MTCONTEXT_REPLYCHAT)) {
+ trap_BotRemoveConsoleMessage(bs->cs, handle);
+ continue;
+ }
+ //don't use eliza chats with team messages
+ if (match.subtype & ST_TEAM) {
+ trap_BotRemoveConsoleMessage(bs->cs, handle);
+ continue;
+ }
+ //
+ trap_BotMatchVariable(&match, NETNAME, netname, sizeof(netname));
+ trap_BotMatchVariable(&match, MESSAGE, message, sizeof(message));
+ //if this is a message from the bot self
+ if (bs->client == ClientFromName(netname)) {
+ trap_BotRemoveConsoleMessage(bs->cs, handle);
+ continue;
+ }
+ //unify the message
+ trap_UnifyWhiteSpaces(message);
+ //
+ trap_Cvar_Update(&bot_testrchat);
+ if (bot_testrchat.integer) {
+ //
+ trap_BotLibVarSet("bot_testrchat", "1");
+ //if bot replies with a chat message
+ if (trap_BotReplyChat(bs->cs, message, context, CONTEXT_REPLY,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ botname, netname)) {
+ BotAI_Print(PRT_MESSAGE, "------------------------\n");
+ }
+ else {
+ BotAI_Print(PRT_MESSAGE, "**** no valid reply ****\n");
+ }
+ }
+ //if at a valid chat position and not chatting already and not in teamplay
+ else if (bs->ainode != AINode_Stand && BotValidChatPosition(bs) && !TeamPlayIsOn()) {
+ chat_reply = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_REPLY, 0, 1);
+ if (random() < 1.5 / (NumBots()+1) && random() < chat_reply) {
+ //if bot replies with a chat message
+ if (trap_BotReplyChat(bs->cs, message, context, CONTEXT_REPLY,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ botname, netname)) {
+ //remove the console message
+ trap_BotRemoveConsoleMessage(bs->cs, handle);
+ bs->stand_time = FloatTime() + BotChatTime(bs);
+ AIEnter_Stand(bs, "BotCheckConsoleMessages: reply chat");
+ //EA_Say(bs->client, bs->cs.chatmessage);
+ break;
+ }
+ }
+ }
+ }
+ }
+ //remove the console message
+ trap_BotRemoveConsoleMessage(bs->cs, handle);
+ }
+}
+
+/*
+==================
+BotCheckEvents
+==================
+*/
+void BotCheckForGrenades(bot_state_t *bs, entityState_t *state) {
+ // if this is not a grenade
+ if (state->eType != ET_MISSILE || state->weapon != WP_GRENADE_LAUNCHER)
+ return;
+ // try to avoid the grenade
+ trap_BotAddAvoidSpot(bs->ms, state->pos.trBase, 160, AVOID_ALWAYS);
+}
+
+
+/*
+==================
+BotCheckForProxMines
+==================
+*/
+void BotCheckForProxMines(bot_state_t *bs, entityState_t *state) {
+ // if this is not a prox mine
+ if (state->eType != ET_MISSILE || state->weapon != WP_PROX_LAUNCHER)
+ return;
+ // if this prox mine is from someone on our own team
+ if (state->generic1 == BotTeam(bs))
+ return;
+ // if the bot doesn't have a weapon to deactivate the mine
+ if (!(bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0) &&
+ !(bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0) &&
+ !(bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0) ) {
+ return;
+ }
+ // try to avoid the prox mine
+ trap_BotAddAvoidSpot(bs->ms, state->pos.trBase, 160, AVOID_ALWAYS);
+ //
+ if (bs->numproxmines >= MAX_PROXMINES)
+ return;
+ bs->proxmines[bs->numproxmines] = state->number;
+ bs->numproxmines++;
+}
+
+/*
+==================
+BotCheckForKamikazeBody
+==================
+*/
+void BotCheckForKamikazeBody(bot_state_t *bs, entityState_t *state) {
+ // if this entity is not wearing the kamikaze
+ if (!(state->eFlags & EF_KAMIKAZE))
+ return;
+ // if this entity isn't dead
+ if (!(state->eFlags & EF_DEAD))
+ return;
+ //remember this kamikaze body
+ bs->kamikazebody = state->number;
+}
+
+/*
+==================
+BotCheckEvents
+==================
+*/
+void BotCheckEvents(bot_state_t *bs, entityState_t *state) {
+ int event;
+ char buf[128];
+ aas_entityinfo_t entinfo;
+
+ //NOTE: this sucks, we're accessing the gentity_t directly
+ //but there's no other fast way to do it right now
+ if (bs->entityeventTime[state->number] == g_entities[state->number].eventTime) {
+ return;
+ }
+ bs->entityeventTime[state->number] = g_entities[state->number].eventTime;
+ //if it's an event only entity
+ if (state->eType > ET_EVENTS) {
+ event = (state->eType - ET_EVENTS) & ~EV_EVENT_BITS;
+ }
+ else {
+ event = state->event & ~EV_EVENT_BITS;
+ }
+ //
+ switch(event) {
+ //client obituary event
+ case EV_OBITUARY:
+ {
+ int target, attacker, mod;
+
+ target = state->otherEntityNum;
+ attacker = state->otherEntityNum2;
+ mod = state->eventParm;
+ //
+ if (target == bs->client) {
+ bs->botdeathtype = mod;
+ bs->lastkilledby = attacker;
+ //
+ if (target == attacker ||
+ target == ENTITYNUM_NONE ||
+ target == ENTITYNUM_WORLD) bs->botsuicide = qtrue;
+ else bs->botsuicide = qfalse;
+ //
+ bs->num_deaths++;
+ }
+ //else if this client was killed by the bot
+ else if (attacker == bs->client) {
+ bs->enemydeathtype = mod;
+ bs->lastkilledplayer = target;
+ bs->killedenemy_time = FloatTime();
+ //
+ bs->num_kills++;
+ }
+ else if (attacker == bs->enemy && target == attacker) {
+ bs->enemysuicide = qtrue;
+ }
+ //
+ if (gametype == GT_1FCTF) {
+ //
+ BotEntityInfo(target, &entinfo);
+ if ( entinfo.powerups & ( 1 << PW_NEUTRALFLAG ) ) {
+ if (!BotSameTeam(bs, target)) {
+ bs->neutralflagstatus = 3; //enemy dropped the flag
+ bs->flagstatuschanged = qtrue;
+ }
+ }
+ }
+ break;
+ }
+ case EV_GLOBAL_SOUND:
+ {
+ if (state->eventParm < 0 || state->eventParm > MAX_SOUNDS) {
+ BotAI_Print(PRT_ERROR, "EV_GLOBAL_SOUND: eventParm (%d) out of range\n", state->eventParm);
+ break;
+ }
+ trap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf));
+ /*
+ if (!strcmp(buf, "sound/teamplay/flagret_red.wav")) {
+ //red flag is returned
+ bs->redflagstatus = 0;
+ bs->flagstatuschanged = qtrue;
+ }
+ else if (!strcmp(buf, "sound/teamplay/flagret_blu.wav")) {
+ //blue flag is returned
+ bs->blueflagstatus = 0;
+ bs->flagstatuschanged = qtrue;
+ }
+ else*/
+ if (!strcmp(buf, "sound/items/kamikazerespawn.wav" )) {
+ //the kamikaze respawned so dont avoid it
+ BotDontAvoid(bs, "Kamikaze");
+ }
+ else
+ if (!strcmp(buf, "sound/items/poweruprespawn.wav")) {
+ //powerup respawned... go get it
+ BotGoForPowerups(bs);
+ }
+ break;
+ }
+ case EV_GLOBAL_TEAM_SOUND:
+ {
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ switch(state->eventParm) {
+ case GTS_RED_CAPTURE:
+ bs->blueflagstatus = 0;
+ bs->redflagstatus = 0;
+ bs->flagstatuschanged = qtrue;
+ break; //see BotMatch_CTF
+ case GTS_BLUE_CAPTURE:
+ bs->blueflagstatus = 0;
+ bs->redflagstatus = 0;
+ bs->flagstatuschanged = qtrue;
+ break; //see BotMatch_CTF
+ case GTS_RED_RETURN:
+ //blue flag is returned
+ bs->blueflagstatus = 0;
+ bs->flagstatuschanged = qtrue;
+ break;
+ case GTS_BLUE_RETURN:
+ //red flag is returned
+ bs->redflagstatus = 0;
+ bs->flagstatuschanged = qtrue;
+ break;
+ case GTS_RED_TAKEN:
+ //blue flag is taken
+ bs->blueflagstatus = 1;
+ bs->flagstatuschanged = qtrue;
+ break; //see BotMatch_CTF
+ case GTS_BLUE_TAKEN:
+ //red flag is taken
+ bs->redflagstatus = 1;
+ bs->flagstatuschanged = qtrue;
+ break; //see BotMatch_CTF
+ }
+ }
+ else if (gametype == GT_1FCTF) {
+ switch(state->eventParm) {
+ case GTS_RED_CAPTURE:
+ bs->neutralflagstatus = 0;
+ bs->flagstatuschanged = qtrue;
+ break;
+ case GTS_BLUE_CAPTURE:
+ bs->neutralflagstatus = 0;
+ bs->flagstatuschanged = qtrue;
+ break;
+ case GTS_RED_RETURN:
+ //flag has returned
+ bs->neutralflagstatus = 0;
+ bs->flagstatuschanged = qtrue;
+ break;
+ case GTS_BLUE_RETURN:
+ //flag has returned
+ bs->neutralflagstatus = 0;
+ bs->flagstatuschanged = qtrue;
+ break;
+ case GTS_RED_TAKEN:
+ bs->neutralflagstatus = BotTeam(bs) == TEAM_RED ? 2 : 1; //FIXME: check Team_TakeFlagSound in g_team.c
+ bs->flagstatuschanged = qtrue;
+ break;
+ case GTS_BLUE_TAKEN:
+ bs->neutralflagstatus = BotTeam(bs) == TEAM_BLUE ? 2 : 1; //FIXME: check Team_TakeFlagSound in g_team.c
+ bs->flagstatuschanged = qtrue;
+ break;
+ }
+ }
+ break;
+ }
+ case EV_PLAYER_TELEPORT_IN:
+ {
+ VectorCopy(state->origin, lastteleport_origin);
+ lastteleport_time = FloatTime();
+ break;
+ }
+ case EV_GENERAL_SOUND:
+ {
+ //if this sound is played on the bot
+ if (state->number == bs->client) {
+ if (state->eventParm < 0 || state->eventParm > MAX_SOUNDS) {
+ BotAI_Print(PRT_ERROR, "EV_GENERAL_SOUND: eventParm (%d) out of range\n", state->eventParm);
+ break;
+ }
+ //check out the sound
+ trap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf));
+ //if falling into a death pit
+ if (!strcmp(buf, "*falling1.wav")) {
+ //if the bot has a personal teleporter
+ if (bs->inventory[INVENTORY_TELEPORTER] > 0) {
+ //use the holdable item
+ trap_EA_Use(bs->client);
+ }
+ }
+ }
+ break;
+ }
+ case EV_FOOTSTEP:
+ case EV_FOOTSTEP_METAL:
+ case EV_FOOTSPLASH:
+ case EV_FOOTWADE:
+ case EV_SWIM:
+ case EV_FALL_SHORT:
+ case EV_FALL_MEDIUM:
+ case EV_FALL_FAR:
+ case EV_STEP_4:
+ case EV_STEP_8:
+ case EV_STEP_12:
+ case EV_STEP_16:
+ case EV_JUMP_PAD:
+ case EV_JUMP:
+ case EV_TAUNT:
+ case EV_WATER_TOUCH:
+ case EV_WATER_LEAVE:
+ case EV_WATER_UNDER:
+ case EV_WATER_CLEAR:
+ case EV_ITEM_PICKUP:
+ case EV_GLOBAL_ITEM_PICKUP:
+ case EV_NOAMMO:
+ case EV_CHANGE_WEAPON:
+ case EV_FIRE_WEAPON:
+ //FIXME: either add to sound queue or mark player as someone making noise
+ break;
+ case EV_USE_ITEM0:
+ case EV_USE_ITEM1:
+ case EV_USE_ITEM2:
+ case EV_USE_ITEM3:
+ case EV_USE_ITEM4:
+ case EV_USE_ITEM5:
+ case EV_USE_ITEM6:
+ case EV_USE_ITEM7:
+ case EV_USE_ITEM8:
+ case EV_USE_ITEM9:
+ case EV_USE_ITEM10:
+ case EV_USE_ITEM11:
+ case EV_USE_ITEM12:
+ case EV_USE_ITEM13:
+ case EV_USE_ITEM14:
+ break;
+ }
+}
+
+/*
+==================
+BotCheckSnapshot
+==================
+*/
+void BotCheckSnapshot(bot_state_t *bs) {
+ int ent;
+ entityState_t state;
+
+ //remove all avoid spots
+ trap_BotAddAvoidSpot(bs->ms, vec3_origin, 0, AVOID_CLEAR);
+ //reset kamikaze body
+ bs->kamikazebody = 0;
+ //reset number of proxmines
+ bs->numproxmines = 0;
+ //
+ ent = 0;
+ while( ( ent = BotAI_GetSnapshotEntity( bs->client, ent, &state ) ) != -1 ) {
+ //check the entity state for events
+ BotCheckEvents(bs, &state);
+ //check for grenades the bot should avoid
+ BotCheckForGrenades(bs, &state);
+ //
+
+ //check for proximity mines which the bot should deactivate
+ BotCheckForProxMines(bs, &state);
+ //check for dead bodies with the kamikaze effect which should be gibbed
+ BotCheckForKamikazeBody(bs, &state);
+ }
+ //check the player state for events
+ BotAI_GetEntityState(bs->client, &state);
+ //copy the player state events to the entity state
+ state.event = bs->cur_ps.externalEvent;
+ state.eventParm = bs->cur_ps.externalEventParm;
+ //
+ BotCheckEvents(bs, &state);
+}
+
+/*
+==================
+BotCheckAir
+==================
+*/
+void BotCheckAir(bot_state_t *bs) {
+ if (bs->inventory[INVENTORY_ENVIRONMENTSUIT] <= 0) {
+ if (trap_AAS_PointContents(bs->eye) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) {
+ return;
+ }
+ }
+ bs->lastair_time = FloatTime();
+}
+
+/*
+==================
+BotAlternateRoute
+==================
+*/
+bot_goal_t *BotAlternateRoute(bot_state_t *bs, bot_goal_t *goal) {
+ int t;
+
+ // if the bot has an alternative route goal
+ if (bs->altroutegoal.areanum) {
+ //
+ if (bs->reachedaltroutegoal_time)
+ return goal;
+ // travel time towards alternative route goal
+ t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, bs->altroutegoal.areanum, bs->tfl);
+ if (t && t < 20) {
+ //BotAI_Print(PRT_MESSAGE, "reached alternate route goal\n");
+ bs->reachedaltroutegoal_time = FloatTime();
+ }
+ memcpy(goal, &bs->altroutegoal, sizeof(bot_goal_t));
+ return &bs->altroutegoal;
+ }
+ return goal;
+}
+
+/*
+==================
+BotGetAlternateRouteGoal
+==================
+*/
+int BotGetAlternateRouteGoal(bot_state_t *bs, int base) {
+ aas_altroutegoal_t *altroutegoals;
+ bot_goal_t *goal;
+ int numaltroutegoals, rnd;
+
+ if (base == TEAM_RED) {
+ altroutegoals = red_altroutegoals;
+ numaltroutegoals = red_numaltroutegoals;
+ }
+ else {
+ altroutegoals = blue_altroutegoals;
+ numaltroutegoals = blue_numaltroutegoals;
+ }
+ if (!numaltroutegoals)
+ return qfalse;
+ rnd = (float) random() * numaltroutegoals;
+ if (rnd >= numaltroutegoals)
+ rnd = numaltroutegoals-1;
+ goal = &bs->altroutegoal;
+ goal->areanum = altroutegoals[rnd].areanum;
+ VectorCopy(altroutegoals[rnd].origin, goal->origin);
+ VectorSet(goal->mins, -8, -8, -8);
+ VectorSet(goal->maxs, 8, 8, 8);
+ goal->entitynum = 0;
+ goal->iteminfo = 0;
+ goal->number = 0;
+ goal->flags = 0;
+ //
+ bs->reachedaltroutegoal_time = 0;
+ return qtrue;
+}
+
+/*
+==================
+BotSetupAlternateRouteGoals
+==================
+*/
+void BotSetupAlternativeRouteGoals(void) {
+
+ if (altroutegoals_setup)
+ return;
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ if (trap_BotGetLevelItemGoal(-1, "Neutral Flag", &ctf_neutralflag) < 0)
+ BotAI_Print(PRT_WARNING, "No alt routes without Neutral Flag\n");
+ if (ctf_neutralflag.areanum) {
+ //
+ red_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
+ ctf_neutralflag.origin, ctf_neutralflag.areanum,
+ ctf_redflag.origin, ctf_redflag.areanum, TFL_DEFAULT,
+ red_altroutegoals, MAX_ALTROUTEGOALS,
+ ALTROUTEGOAL_CLUSTERPORTALS|
+ ALTROUTEGOAL_VIEWPORTALS);
+ blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
+ ctf_neutralflag.origin, ctf_neutralflag.areanum,
+ ctf_blueflag.origin, ctf_blueflag.areanum, TFL_DEFAULT,
+ blue_altroutegoals, MAX_ALTROUTEGOALS,
+ ALTROUTEGOAL_CLUSTERPORTALS|
+ ALTROUTEGOAL_VIEWPORTALS);
+ }
+ }
+ else if (gametype == GT_1FCTF) {
+ if (trap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0)
+ BotAI_Print(PRT_WARNING, "One Flag CTF without Neutral Obelisk\n");
+ red_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
+ ctf_neutralflag.origin, ctf_neutralflag.areanum,
+ ctf_redflag.origin, ctf_redflag.areanum, TFL_DEFAULT,
+ red_altroutegoals, MAX_ALTROUTEGOALS,
+ ALTROUTEGOAL_CLUSTERPORTALS|
+ ALTROUTEGOAL_VIEWPORTALS);
+ blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
+ ctf_neutralflag.origin, ctf_neutralflag.areanum,
+ ctf_blueflag.origin, ctf_blueflag.areanum, TFL_DEFAULT,
+ blue_altroutegoals, MAX_ALTROUTEGOALS,
+ ALTROUTEGOAL_CLUSTERPORTALS|
+ ALTROUTEGOAL_VIEWPORTALS);
+ }
+ else if (gametype == GT_OBELISK) {
+ if (trap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0)
+ BotAI_Print(PRT_WARNING, "Obelisk without neutral obelisk\n");
+ //
+ red_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
+ neutralobelisk.origin, neutralobelisk.areanum,
+ redobelisk.origin, redobelisk.areanum, TFL_DEFAULT,
+ red_altroutegoals, MAX_ALTROUTEGOALS,
+ ALTROUTEGOAL_CLUSTERPORTALS|
+ ALTROUTEGOAL_VIEWPORTALS);
+ blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
+ neutralobelisk.origin, neutralobelisk.areanum,
+ blueobelisk.origin, blueobelisk.areanum, TFL_DEFAULT,
+ blue_altroutegoals, MAX_ALTROUTEGOALS,
+ ALTROUTEGOAL_CLUSTERPORTALS|
+ ALTROUTEGOAL_VIEWPORTALS);
+ }
+ else if (gametype == GT_HARVESTER) {
+ if (untrap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0)
+ BotAI_Print(PRT_WARNING, "Harvester without neutral obelisk\n");
+ //
+ red_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
+ neutralobelisk.origin, neutralobelisk.areanum,
+ redobelisk.origin, redobelisk.areanum, TFL_DEFAULT,
+ red_altroutegoals, MAX_ALTROUTEGOALS,
+ ALTROUTEGOAL_CLUSTERPORTALS|
+ ALTROUTEGOAL_VIEWPORTALS);
+ blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
+ neutralobelisk.origin, neutralobelisk.areanum,
+ blueobelisk.origin, blueobelisk.areanum, TFL_DEFAULT,
+ blue_altroutegoals, MAX_ALTROUTEGOALS,
+ ALTROUTEGOAL_CLUSTERPORTALS|
+ ALTROUTEGOAL_VIEWPORTALS);
+ }
+ altroutegoals_setup = qtrue;
+}
+
+/*
+==================
+BotDeathmatchAI
+==================
+*/
+void BotDeathmatchAI(bot_state_t *bs, float thinktime) {
+ char gender[144], name[144], buf[144];
+ char userinfo[MAX_INFO_STRING];
+ int i;
+
+ //if the bot has just been setup
+ if (bs->setupcount > 0) {
+ bs->setupcount--;
+ if (bs->setupcount > 0) return;
+ //get the gender characteristic
+ trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, sizeof(gender));
+ //set the bot gender
+ trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo));
+ Info_SetValueForKey(userinfo, "sex", gender);
+ trap_SetUserinfo(bs->client, userinfo);
+ //set the team
+ if ( !bs->map_restart && g_gametype.integer != GT_TOURNAMENT ) {
+ Com_sprintf(buf, sizeof(buf), "team %s", bs->settings.team);
+ trap_EA_Command(bs->client, buf);
+ }
+ //set the chat gender
+ if (gender[0] == 'm') trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE);
+ else if (gender[0] == 'f') trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE);
+ else trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS);
+ //set the chat name
+ ClientName(bs->client, name, sizeof(name));
+ trap_BotSetChatName(bs->cs, name, bs->client);
+ //
+ bs->lastframe_health = bs->inventory[INVENTORY_HEALTH];
+ bs->lasthitcount = bs->cur_ps.persistant[PERS_HITS];
+ //
+ bs->setupcount = 0;
+ //
+ BotSetupAlternativeRouteGoals();
+ }
+ //no ideal view set
+ bs->flags &= ~BFL_IDEALVIEWSET;
+ //
+ if (!BotIntermission(bs)) {
+ //set the teleport time
+ BotSetTeleportTime(bs);
+ //update some inventory values
+ BotUpdateInventory(bs);
+ //check out the snapshot
+ BotCheckSnapshot(bs);
+ //check for air
+ BotCheckAir(bs);
+ }
+ //check the console messages
+ BotCheckConsoleMessages(bs);
+ //if not in the intermission and not in observer mode
+ if (!BotIntermission(bs) && !BotIsObserver(bs)) {
+ //do team AI
+ BotTeamAI(bs);
+ }
+ //if the bot has no ai node
+ if (!bs->ainode) {
+ AIEnter_Seek_LTG(bs, "BotDeathmatchAI: no ai node");
+ }
+ //if the bot entered the game less than 8 seconds ago
+ if (!bs->entergamechat && bs->entergame_time > FloatTime() - 8) {
+ if (BotChat_EnterGame(bs)) {
+ bs->stand_time = FloatTime() + BotChatTime(bs);
+ AIEnter_Stand(bs, "BotDeathmatchAI: chat enter game");
+ }
+ bs->entergamechat = qtrue;
+ }
+ //reset the node switches from the previous frame
+ BotResetNodeSwitches();
+ //execute AI nodes
+ for (i = 0; i < MAX_NODESWITCHES; i++) {
+ if (bs->ainode(bs)) break;
+ }
+ //if the bot removed itself :)
+ if (!bs->inuse) return;
+ //if the bot executed too many AI nodes
+ //Sago: FIXME - Outcommented this test... this is wrong
+ #ifdef DEBUG
+ if (i >= MAX_NODESWITCHES) {
+ trap_BotDumpGoalStack(bs->gs);
+ trap_BotDumpAvoidGoals(bs->gs);
+ BotDumpNodeSwitches(bs);
+ ClientName(bs->client, name, sizeof(name));
+ BotAI_Print(PRT_ERROR, "%s at %1.1f switched more than %d AI nodes\n", name, FloatTime(), MAX_NODESWITCHES);
+ }
+ #endif
+ //
+ bs->lastframe_health = bs->inventory[INVENTORY_HEALTH];
+ bs->lasthitcount = bs->cur_ps.persistant[PERS_HITS];
+}
+
+/*
+==================
+BotSetEntityNumForGoalWithModel
+==================
+*/
+void BotSetEntityNumForGoalWithModel(bot_goal_t *goal, int eType, char *modelname) {
+ gentity_t *ent;
+ int i, modelindex;
+ vec3_t dir;
+
+ modelindex = G_ModelIndex( modelname );
+ ent = &g_entities[0];
+ for (i = 0; i < level.num_entities; i++, ent++) {
+ if ( !ent->inuse ) {
+ continue;
+ }
+ if ( eType && ent->s.eType != eType) {
+ continue;
+ }
+ if (ent->s.modelindex != modelindex) {
+ continue;
+ }
+ VectorSubtract(goal->origin, ent->s.origin, dir);
+ if (VectorLengthSquared(dir) < Square(10)) {
+ goal->entitynum = i;
+ return;
+ }
+ }
+}
+
+/*
+==================
+BotSetEntityNumForGoal
+==================
+*/
+void BotSetEntityNumForGoal(bot_goal_t *goal, char *classname) {
+ gentity_t *ent;
+ int i;
+ vec3_t dir;
+
+ ent = &g_entities[0];
+ for (i = 0; i < level.num_entities; i++, ent++) {
+ if ( !ent->inuse ) {
+ continue;
+ }
+ if ( !Q_stricmp(ent->classname, classname) ) {
+ continue;
+ }
+ VectorSubtract(goal->origin, ent->s.origin, dir);
+ if (VectorLengthSquared(dir) < Square(10)) {
+ goal->entitynum = i;
+ return;
+ }
+ }
+}
+
+/*
+==================
+BotGoalForBSPEntity
+==================
+*/
+int BotGoalForBSPEntity( char *classname, bot_goal_t *goal ) {
+ char value[MAX_INFO_STRING];
+ vec3_t origin, start, end;
+ int ent, numareas, areas[10];
+
+ memset(goal, 0, sizeof(bot_goal_t));
+ for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) {
+ if (!trap_AAS_ValueForBSPEpairKey(ent, "classname", value, sizeof(value)))
+ continue;
+ if (!strcmp(value, classname)) {
+ if (!trap_AAS_VectorForBSPEpairKey(ent, "origin", origin))
+ return qfalse;
+ VectorCopy(origin, goal->origin);
+ VectorCopy(origin, start);
+ start[2] -= 32;
+ VectorCopy(origin, end);
+ end[2] += 32;
+ numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10);
+ if (!numareas)
+ return qfalse;
+ goal->areanum = areas[0];
+ return qtrue;
+ }
+ }
+ return qfalse;
+}
+
+/*
+==================
+BotSetupDeathmatchAI
+==================
+*/
+void BotSetupDeathmatchAI(void) {
+ int ent, modelnum,i;
+ char model[128];
+
+ gametype = trap_Cvar_VariableIntegerValue("g_gametype");
+ maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
+
+ trap_Cvar_Register(&bot_rocketjump, "bot_rocketjump", "1", 0);
+ trap_Cvar_Register(&bot_grapple, "bot_grapple", "0", 0);
+ trap_Cvar_Register(&bot_fastchat, "bot_fastchat", "0", 0);
+ trap_Cvar_Register(&bot_nochat, "bot_nochat", "0", 0);
+ trap_Cvar_Register(&bot_testrchat, "bot_testrchat", "0", 0);
+ trap_Cvar_Register(&bot_challenge, "bot_challenge", "0", 0);
+ trap_Cvar_Register(&bot_predictobstacles, "bot_predictobstacles", "1", 0);
+ trap_Cvar_Register(&g_spSkill, "g_spSkill", "2", 0);
+ //
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ if (untrap_BotGetLevelItemGoal(-1, "Red Flag", &ctf_redflag) < 0)
+ BotAI_Print(PRT_WARNING, "CTF without Red Flag\n");
+ if (untrap_BotGetLevelItemGoal(-1, "Blue Flag", &ctf_blueflag) < 0)
+ BotAI_Print(PRT_WARNING, "CTF without Blue Flag\n");
+ }
+ else if (gametype == GT_DOUBLE_D) {
+ if (untrap_BotGetLevelItemGoal(-1, "Red Flag", &ctf_redflag) < 0)
+ BotAI_Print(PRT_WARNING, "DD without Point A\n");
+ if (untrap_BotGetLevelItemGoal(-1, "Blue Flag", &ctf_blueflag) < 0)
+ BotAI_Print(PRT_WARNING, "DD without Point B\n");
+ }
+ else if (gametype == GT_DOMINATION) {
+ ent = untrap_BotGetLevelItemGoal(-1, "Domination point", &dom_points_bot[0]);
+ if(ent < 0)
+ BotAI_Print(PRT_WARNING, "Domination without a single domination point\n");
+ else
+ BotSetEntityNumForGoal(&dom_points_bot[0], va("domination_point%i",0) );
+ for(i=1;i<level.domination_points_count;i++) {
+ //Find next from the privius found entity
+ ent = untrap_BotGetLevelItemGoal(ent, "Domination point", &dom_points_bot[i]);
+ if(ent < 0)
+ BotAI_Print(PRT_WARNING, "Domination point %i not found!\n",i);
+ else
+ BotSetEntityNumForGoal(&dom_points_bot[0], va("domination_point%i",i) );
+ }
+ //MAX_DOMINATION_POINTS
+ }
+ else if (gametype == GT_1FCTF) {
+ if (untrap_BotGetLevelItemGoal(-1, "Neutral Flag", &ctf_neutralflag) < 0)
+ BotAI_Print(PRT_WARNING, "One Flag CTF without Neutral Flag\n");
+ if (untrap_BotGetLevelItemGoal(-1, "Red Flag", &ctf_redflag) < 0)
+ BotAI_Print(PRT_WARNING, "CTF without Red Flag\n");
+ if (untrap_BotGetLevelItemGoal(-1, "Blue Flag", &ctf_blueflag) < 0)
+ BotAI_Print(PRT_WARNING, "CTF without Blue Flag\n");
+ }
+ else if (gametype == GT_OBELISK) {
+ if (untrap_BotGetLevelItemGoal(-1, "Red Obelisk", &redobelisk) < 0)
+ BotAI_Print(PRT_WARNING, "Obelisk without red obelisk\n");
+ BotSetEntityNumForGoal(&redobelisk, "team_redobelisk");
+ if (untrap_BotGetLevelItemGoal(-1, "Blue Obelisk", &blueobelisk) < 0)
+ BotAI_Print(PRT_WARNING, "Obelisk without blue obelisk\n");
+ BotSetEntityNumForGoal(&blueobelisk, "team_blueobelisk");
+ }
+ else if (gametype == GT_HARVESTER) {
+ if (untrap_BotGetLevelItemGoal(-1, "Red Obelisk", &redobelisk) < 0)
+ BotAI_Print(PRT_WARNING, "Harvester without red obelisk\n");
+ BotSetEntityNumForGoal(&redobelisk, "team_redobelisk");
+ if (untrap_BotGetLevelItemGoal(-1, "Blue Obelisk", &blueobelisk) < 0)
+ BotAI_Print(PRT_WARNING, "Harvester without blue obelisk\n");
+ BotSetEntityNumForGoal(&blueobelisk, "team_blueobelisk");
+ if (untrap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0)
+ BotAI_Print(PRT_WARNING, "Harvester without neutral obelisk\n");
+ BotSetEntityNumForGoal(&neutralobelisk, "team_neutralobelisk");
+ }
+
+ max_bspmodelindex = 0;
+ for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) {
+ if (!trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model))) continue;
+ if (model[0] == '*') {
+ modelnum = atoi(model+1);
+ if (modelnum > max_bspmodelindex)
+ max_bspmodelindex = modelnum;
+ }
+ }
+ //initialize the waypoint heap
+ BotInitWaypoints();
+}
+
+/*
+==================
+BotShutdownDeathmatchAI
+==================
+*/
+void BotShutdownDeathmatchAI(void) {
+ altroutegoals_setup = qfalse;
+}
diff --git a/game/code/game/ai_dmq3.h b/code/game/ai_dmq3.h
similarity index 100%
rename from game/code/game/ai_dmq3.h
rename to code/game/ai_dmq3.h
diff --git a/code/game/ai_main.c b/code/game/ai_main.c
new file mode 100644
index 0000000..1ee21b8
--- /dev/null
+++ b/code/game/ai_main.c
@@ -0,0 +1,1738 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+/*****************************************************************************
+ * name: ai_main.c
+ *
+ * desc: Quake3 bot AI
+ *
+ * $Archive: /MissionPack/code/game/ai_main.c $
+ *
+ *****************************************************************************/
+
+
+#include "g_local.h"
+#include "../qcommon/q_shared.h"
+#include "../botlib/botlib.h" //bot lib interface
+#include "../botlib/be_aas.h"
+#include "../botlib/be_ea.h"
+#include "../botlib/be_ai_char.h"
+#include "../botlib/be_ai_chat.h"
+#include "../botlib/be_ai_gen.h"
+#include "../botlib/be_ai_goal.h"
+#include "../botlib/be_ai_move.h"
+#include "../botlib/be_ai_weap.h"
+//
+#include "ai_main.h"
+#include "ai_dmq3.h"
+#include "ai_chat.h"
+#include "ai_cmd.h"
+#include "ai_dmnet.h"
+#include "ai_vcmd.h"
+
+//
+#include "chars.h"
+#include "inv.h"
+#include "syn.h"
+
+#ifndef MAX_PATH
+#define MAX_PATH 144
+#endif
+
+
+//bot states
+bot_state_t *botstates[MAX_CLIENTS];
+//number of bots
+int numbots;
+//floating point time
+float floattime;
+//time to do a regular update
+float regularupdate_time;
+//
+int bot_interbreed;
+int bot_interbreedmatchcount;
+//
+vmCvar_t bot_thinktime;
+vmCvar_t bot_memorydump;
+vmCvar_t bot_saveroutingcache;
+vmCvar_t bot_pause;
+vmCvar_t bot_report;
+vmCvar_t bot_testsolid;
+vmCvar_t bot_testclusters;
+vmCvar_t bot_developer;
+vmCvar_t bot_interbreedchar;
+vmCvar_t bot_interbreedbots;
+vmCvar_t bot_interbreedcycle;
+vmCvar_t bot_interbreedwrite;
+
+
+void ExitLevel( void );
+
+
+/*
+==================
+BotAI_Print
+==================
+*/
+void QDECL BotAI_Print(int type, char *fmt, ...) {
+ char str[2048];
+ va_list ap;
+
+ va_start(ap, fmt);
+ Q_vsnprintf(str, sizeof(str), fmt, ap);
+ va_end(ap);
+
+ switch(type) {
+ case PRT_MESSAGE: {
+ G_Printf("%s", str);
+ break;
+ }
+ case PRT_WARNING: {
+ G_Printf( S_COLOR_YELLOW "Warning: %s", str );
+ break;
+ }
+ case PRT_ERROR: {
+ G_Printf( S_COLOR_RED "Error: %s", str );
+ break;
+ }
+ case PRT_FATAL: {
+ G_Printf( S_COLOR_RED "Fatal: %s", str );
+ break;
+ }
+ case PRT_EXIT: {
+ G_Error( S_COLOR_RED "Exit: %s", str );
+ break;
+ }
+ default: {
+ G_Printf( "unknown print type\n" );
+ break;
+ }
+ }
+}
+
+
+/*
+==================
+BotAI_Trace
+==================
+*/
+void BotAI_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) {
+ trace_t trace;
+
+ trap_Trace(&trace, start, mins, maxs, end, passent, contentmask);
+ //copy the trace information
+ bsptrace->allsolid = trace.allsolid;
+ bsptrace->startsolid = trace.startsolid;
+ bsptrace->fraction = trace.fraction;
+ VectorCopy(trace.endpos, bsptrace->endpos);
+ bsptrace->plane.dist = trace.plane.dist;
+ VectorCopy(trace.plane.normal, bsptrace->plane.normal);
+ bsptrace->plane.signbits = trace.plane.signbits;
+ bsptrace->plane.type = trace.plane.type;
+ bsptrace->surface.value = trace.surfaceFlags;
+ bsptrace->ent = trace.entityNum;
+ bsptrace->exp_dist = 0;
+ bsptrace->sidenum = 0;
+ bsptrace->contents = 0;
+}
+
+/*
+==================
+BotAI_GetClientState
+==================
+*/
+int BotAI_GetClientState( int clientNum, playerState_t *state ) {
+ gentity_t *ent;
+
+ ent = &g_entities[clientNum];
+ if ( !ent->inuse ) {
+ return qfalse;
+ }
+ if ( !ent->client ) {
+ return qfalse;
+ }
+
+ memcpy( state, &ent->client->ps, sizeof(playerState_t) );
+ return qtrue;
+}
+
+/*
+==================
+BotAI_GetEntityState
+==================
+*/
+int BotAI_GetEntityState( int entityNum, entityState_t *state ) {
+ gentity_t *ent;
+
+ ent = &g_entities[entityNum];
+ memset( state, 0, sizeof(entityState_t) );
+ if (!ent->inuse) return qfalse;
+ if (!ent->r.linked) return qfalse;
+ if ( !(g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_LMS ||g_instantgib.integer || g_rockets.integer || g_elimination_allgametypes.integer || g_gametype.integer==GT_CTF_ELIMINATION)
+ && (ent->r.svFlags & SVF_NOCLIENT) ) return qfalse;
+ memcpy( state, &ent->s, sizeof(entityState_t) );
+ return qtrue;
+}
+
+/*
+==================
+BotAI_GetSnapshotEntity
+==================
+*/
+int BotAI_GetSnapshotEntity( int clientNum, int sequence, entityState_t *state ) {
+ int entNum;
+
+ entNum = trap_BotGetSnapshotEntity( clientNum, sequence );
+ if ( entNum == -1 ) {
+ memset(state, 0, sizeof(entityState_t));
+ return -1;
+ }
+
+ BotAI_GetEntityState( entNum, state );
+
+ return sequence + 1;
+}
+
+/*
+==================
+BotAI_BotInitialChat
+==================
+*/
+void QDECL BotAI_BotInitialChat( bot_state_t *bs, char *type, ... ) {
+ int i, mcontext;
+ va_list ap;
+ char *p;
+ char *vars[MAX_MATCHVARIABLES];
+
+ memset(vars, 0, sizeof(vars));
+ va_start(ap, type);
+ p = va_arg(ap, char *);
+ for (i = 0; i < MAX_MATCHVARIABLES; i++) {
+ if( !p ) {
+ break;
+ }
+ vars[i] = p;
+ p = va_arg(ap, char *);
+ }
+ va_end(ap);
+
+ mcontext = BotSynonymContext(bs);
+
+ trap_BotInitialChat( bs->cs, type, mcontext, vars[0], vars[1], vars[2], vars[3], vars[4], vars[5], vars[6], vars[7] );
+}
+
+
+/*
+==================
+BotTestAAS
+==================
+*/
+void BotTestAAS(vec3_t origin) {
+ int areanum;
+ aas_areainfo_t info;
+
+ trap_Cvar_Update(&bot_testsolid);
+ trap_Cvar_Update(&bot_testclusters);
+ if (bot_testsolid.integer) {
+ if (!trap_AAS_Initialized()) return;
+ areanum = BotPointAreaNum(origin);
+ if (areanum) BotAI_Print(PRT_MESSAGE, "\remtpy area");
+ else BotAI_Print(PRT_MESSAGE, "\r^1SOLID area");
+ }
+ else if (bot_testclusters.integer) {
+ if (!trap_AAS_Initialized()) return;
+ areanum = BotPointAreaNum(origin);
+ if (!areanum)
+ BotAI_Print(PRT_MESSAGE, "\r^1Solid! ");
+ else {
+ trap_AAS_AreaInfo(areanum, &info);
+ BotAI_Print(PRT_MESSAGE, "\rarea %d, cluster %d ", areanum, info.cluster);
+ }
+ }
+}
+
+/*
+==================
+BotReportStatus
+==================
+*/
+void BotReportStatus(bot_state_t *bs) {
+ char goalname[MAX_MESSAGE_SIZE];
+ char netname[MAX_MESSAGE_SIZE];
+ char *leader, flagstatus[32];
+ //
+ ClientName(bs->client, netname, sizeof(netname));
+ if (Q_stricmp(netname, bs->teamleader) == 0) leader = "L";
+ else leader = " ";
+
+ strcpy(flagstatus, " ");
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ if (BotCTFCarryingFlag(bs)) {
+ if (BotTeam(bs) == TEAM_RED) strcpy(flagstatus, S_COLOR_RED"F ");
+ else strcpy(flagstatus, S_COLOR_BLUE"F ");
+ }
+ }
+ else if (gametype == GT_1FCTF) {
+ if (Bot1FCTFCarryingFlag(bs)) {
+ if (BotTeam(bs) == TEAM_RED) strcpy(flagstatus, S_COLOR_RED"F ");
+ else strcpy(flagstatus, S_COLOR_BLUE"F ");
+ }
+ }
+ else if (gametype == GT_HARVESTER) {
+ if (BotHarvesterCarryingCubes(bs)) {
+ if (BotTeam(bs) == TEAM_RED) Com_sprintf(flagstatus, sizeof(flagstatus), S_COLOR_RED"%2d", bs->inventory[INVENTORY_REDCUBE]);
+ else Com_sprintf(flagstatus, sizeof(flagstatus), S_COLOR_BLUE"%2d", bs->inventory[INVENTORY_BLUECUBE]);
+ }
+ }
+
+ switch(bs->ltgtype) {
+ case LTG_TEAMHELP:
+ {
+ EasyClientName(bs->teammate, goalname, sizeof(goalname));
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: helping %s\n", netname, leader, flagstatus, goalname);
+ break;
+ }
+ case LTG_TEAMACCOMPANY:
+ {
+ EasyClientName(bs->teammate, goalname, sizeof(goalname));
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: accompanying %s\n", netname, leader, flagstatus, goalname);
+ break;
+ }
+ case LTG_DEFENDKEYAREA:
+ {
+ trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: defending %s\n", netname, leader, flagstatus, goalname);
+ break;
+ }
+ case LTG_GETITEM:
+ {
+ trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: getting item %s\n", netname, leader, flagstatus, goalname);
+ break;
+ }
+ case LTG_KILL:
+ {
+ ClientName(bs->teamgoal.entitynum, goalname, sizeof(goalname));
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: killing %s\n", netname, leader, flagstatus, goalname);
+ break;
+ }
+ case LTG_CAMP:
+ case LTG_CAMPORDER:
+ {
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: camping\n", netname, leader, flagstatus);
+ break;
+ }
+ case LTG_PATROL:
+ {
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: patrolling\n", netname, leader, flagstatus);
+ break;
+ }
+ case LTG_GETFLAG:
+ {
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: capturing flag\n", netname, leader, flagstatus);
+ break;
+ }
+ case LTG_RUSHBASE:
+ {
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: rushing base\n", netname, leader, flagstatus);
+ break;
+ }
+ case LTG_RETURNFLAG:
+ {
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: returning flag\n", netname, leader, flagstatus);
+ break;
+ }
+ case LTG_ATTACKENEMYBASE:
+ {
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: attacking the enemy base\n", netname, leader, flagstatus);
+ break;
+ }
+ case LTG_HARVEST:
+ {
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: harvesting\n", netname, leader, flagstatus);
+ break;
+ }
+ case LTG_POINTA:
+ {
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: going for point A\n", netname, leader, flagstatus);
+ break;
+ }
+ case LTG_POINTB:
+ {
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: going for point B\n", netname, leader, flagstatus);
+ break;
+ }
+ default:
+ {
+ BotAI_Print(PRT_MESSAGE, "%-20s%s%s: roaming\n", netname, leader, flagstatus);
+ break;
+ }
+ }
+}
+
+/*
+==================
+BotTeamplayReport
+==================
+*/
+void BotTeamplayReport(void) {
+ int i;
+ char buf[MAX_INFO_STRING];
+
+ BotAI_Print(PRT_MESSAGE, S_COLOR_RED"RED\n");
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ //
+ if ( !botstates[i] || !botstates[i]->inuse ) continue;
+ //
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ //if no config string or no name
+ if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
+ //skip spectators
+ if (atoi(Info_ValueForKey(buf, "t")) == TEAM_RED) {
+ BotReportStatus(botstates[i]);
+ }
+ }
+ BotAI_Print(PRT_MESSAGE, S_COLOR_BLUE"BLUE\n");
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ //
+ if ( !botstates[i] || !botstates[i]->inuse ) continue;
+ //
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ //if no config string or no name
+ if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
+ //skip spectators
+ if (atoi(Info_ValueForKey(buf, "t")) == TEAM_BLUE) {
+ BotReportStatus(botstates[i]);
+ }
+ }
+}
+
+/*
+==================
+BotSetInfoConfigString
+==================
+*/
+void BotSetInfoConfigString(bot_state_t *bs) {
+ char goalname[MAX_MESSAGE_SIZE];
+ char netname[MAX_MESSAGE_SIZE];
+ char action[MAX_MESSAGE_SIZE];
+ char *leader, carrying[32], *cs;
+ bot_goal_t goal;
+ //
+ ClientName(bs->client, netname, sizeof(netname));
+ if (Q_stricmp(netname, bs->teamleader) == 0) leader = "L";
+ else leader = " ";
+
+ strcpy(carrying, " ");
+ if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
+ if (BotCTFCarryingFlag(bs)) {
+ strcpy(carrying, "F ");
+ }
+ }
+ else if (gametype == GT_1FCTF) {
+ if (Bot1FCTFCarryingFlag(bs)) {
+ strcpy(carrying, "F ");
+ }
+ }
+ else if (gametype == GT_HARVESTER) {
+ if (BotHarvesterCarryingCubes(bs)) {
+ if (BotTeam(bs) == TEAM_RED) Com_sprintf(carrying, sizeof(carrying), "%2d", bs->inventory[INVENTORY_REDCUBE]);
+ else Com_sprintf(carrying, sizeof(carrying), "%2d", bs->inventory[INVENTORY_BLUECUBE]);
+ }
+ }
+
+ switch(bs->ltgtype) {
+ case LTG_TEAMHELP:
+ {
+ EasyClientName(bs->teammate, goalname, sizeof(goalname));
+ Com_sprintf(action, sizeof(action), "helping %s", goalname);
+ break;
+ }
+ case LTG_TEAMACCOMPANY:
+ {
+ EasyClientName(bs->teammate, goalname, sizeof(goalname));
+ Com_sprintf(action, sizeof(action), "accompanying %s", goalname);
+ break;
+ }
+ case LTG_DEFENDKEYAREA:
+ {
+ trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
+ Com_sprintf(action, sizeof(action), "defending %s", goalname);
+ break;
+ }
+ case LTG_GETITEM:
+ {
+ trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
+ Com_sprintf(action, sizeof(action), "getting item %s", goalname);
+ break;
+ }
+ case LTG_KILL:
+ {
+ ClientName(bs->teamgoal.entitynum, goalname, sizeof(goalname));
+ Com_sprintf(action, sizeof(action), "killing %s", goalname);
+ break;
+ }
+ case LTG_CAMP:
+ case LTG_CAMPORDER:
+ {
+ Com_sprintf(action, sizeof(action), "camping");
+ break;
+ }
+ case LTG_PATROL:
+ {
+ Com_sprintf(action, sizeof(action), "patrolling");
+ break;
+ }
+ case LTG_GETFLAG:
+ {
+ Com_sprintf(action, sizeof(action), "capturing flag");
+ break;
+ }
+ case LTG_RUSHBASE:
+ {
+ Com_sprintf(action, sizeof(action), "rushing base");
+ break;
+ }
+ case LTG_RETURNFLAG:
+ {
+ Com_sprintf(action, sizeof(action), "returning flag");
+ break;
+ }
+ case LTG_ATTACKENEMYBASE:
+ {
+ Com_sprintf(action, sizeof(action), "attacking the enemy base");
+ break;
+ }
+ case LTG_HARVEST:
+ {
+ Com_sprintf(action, sizeof(action), "harvesting");
+ break;
+ }
+ case LTG_POINTA:
+ {
+ Com_sprintf(action, sizeof(action), "going for point A");
+ break;
+ }
+ case LTG_POINTB:
+ {
+ Com_sprintf(action, sizeof(action), "going for point B");
+ break;
+ }
+ default:
+ {
+ trap_BotGetTopGoal(bs->gs, &goal);
+ trap_BotGoalName(goal.number, goalname, sizeof(goalname));
+ Com_sprintf(action, sizeof(action), "roaming %s", goalname);
+ break;
+ }
+ }
+ cs = va("l\\%s\\c\\%s\\a\\%s",
+ leader,
+ carrying,
+ action);
+ trap_SetConfigstring (CS_BOTINFO + bs->client, cs);
+}
+
+/*
+==============
+BotUpdateInfoConfigStrings
+==============
+*/
+void BotUpdateInfoConfigStrings(void) {
+ int i;
+ char buf[MAX_INFO_STRING];
+
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ //
+ if ( !botstates[i] || !botstates[i]->inuse )
+ continue;
+ //
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ //if no config string or no name
+ if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n")))
+ continue;
+ BotSetInfoConfigString(botstates[i]);
+ }
+}
+
+/*
+==============
+BotInterbreedBots
+==============
+*/
+void BotInterbreedBots(void) {
+ float ranks[MAX_CLIENTS];
+ int parent1, parent2, child;
+ int i;
+
+ // get rankings for all the bots
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ if ( botstates[i] && botstates[i]->inuse ) {
+ ranks[i] = botstates[i]->num_kills * 2 - botstates[i]->num_deaths;
+ }
+ else {
+ ranks[i] = -1;
+ }
+ }
+
+ if (trap_GeneticParentsAndChildSelection(MAX_CLIENTS, ranks, &parent1, &parent2, &child)) {
+ trap_BotInterbreedGoalFuzzyLogic(botstates[parent1]->gs, botstates[parent2]->gs, botstates[child]->gs);
+ trap_BotMutateGoalFuzzyLogic(botstates[child]->gs, 1);
+ }
+ // reset the kills and deaths
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ if (botstates[i] && botstates[i]->inuse) {
+ botstates[i]->num_kills = 0;
+ botstates[i]->num_deaths = 0;
+ }
+ }
+}
+
+/*
+==============
+BotWriteInterbreeded
+==============
+*/
+void BotWriteInterbreeded(char *filename) {
+ float rank, bestrank;
+ int i, bestbot;
+
+ bestrank = 0;
+ bestbot = -1;
+ // get the best bot
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ if ( botstates[i] && botstates[i]->inuse ) {
+ rank = botstates[i]->num_kills * 2 - botstates[i]->num_deaths;
+ }
+ else {
+ rank = -1;
+ }
+ if (rank > bestrank) {
+ bestrank = rank;
+ bestbot = i;
+ }
+ }
+ if (bestbot >= 0) {
+ //write out the new goal fuzzy logic
+ trap_BotSaveGoalFuzzyLogic(botstates[bestbot]->gs, filename);
+ }
+}
+
+/*
+==============
+BotInterbreedEndMatch
+
+add link back into ExitLevel?
+==============
+*/
+void BotInterbreedEndMatch(void) {
+
+ if (!bot_interbreed) return;
+ bot_interbreedmatchcount++;
+ if (bot_interbreedmatchcount >= bot_interbreedcycle.integer) {
+ bot_interbreedmatchcount = 0;
+ //
+ trap_Cvar_Update(&bot_interbreedwrite);
+ if (strlen(bot_interbreedwrite.string)) {
+ BotWriteInterbreeded(bot_interbreedwrite.string);
+ trap_Cvar_Set("bot_interbreedwrite", "");
+ }
+ BotInterbreedBots();
+ }
+}
+
+/*
+==============
+BotInterbreeding
+==============
+*/
+void BotInterbreeding(void) {
+ int i;
+
+ trap_Cvar_Update(&bot_interbreedchar);
+ if (!strlen(bot_interbreedchar.string)) return;
+ //make sure we are in tournament mode
+ if (gametype != GT_TOURNAMENT) {
+ trap_Cvar_Set("g_gametype", va("%d", GT_TOURNAMENT));
+ ExitLevel();
+ return;
+ }
+ //shutdown all the bots
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ if (botstates[i] && botstates[i]->inuse) {
+ BotAIShutdownClient(botstates[i]->client, qfalse);
+ }
+ }
+ //make sure all item weight configs are reloaded and Not shared
+ trap_BotLibVarSet("bot_reloadcharacters", "1");
+ //add a number of bots using the desired bot character
+ for (i = 0; i < bot_interbreedbots.integer; i++) {
+ trap_SendConsoleCommand( EXEC_INSERT, va("addbot %s 4 free %i %s%d\n",
+ bot_interbreedchar.string, i * 50, bot_interbreedchar.string, i) );
+ }
+ //
+ trap_Cvar_Set("bot_interbreedchar", "");
+ bot_interbreed = qtrue;
+}
+
+/*
+==============
+BotEntityInfo
+==============
+*/
+void BotEntityInfo(int entnum, aas_entityinfo_t *info) {
+ trap_AAS_EntityInfo(entnum, info);
+}
+
+/*
+==============
+NumBots
+==============
+*/
+int NumBots(void) {
+ return numbots;
+}
+
+/*
+==============
+BotTeamLeader
+==============
+*/
+int BotTeamLeader(bot_state_t *bs) {
+ int leader;
+
+ leader = ClientFromName(bs->teamleader);
+ if (leader < 0) return qfalse;
+ if (!botstates[leader] || !botstates[leader]->inuse) return qfalse;
+ return qtrue;
+}
+
+/*
+==============
+AngleDifference
+==============
+*/
+float AngleDifference(float ang1, float ang2) {
+ float diff;
+
+ diff = ang1 - ang2;
+ if (ang1 > ang2) {
+ if (diff > 180.0) diff -= 360.0;
+ }
+ else {
+ if (diff < -180.0) diff += 360.0;
+ }
+ return diff;
+}
+
+/*
+==============
+BotChangeViewAngle
+==============
+*/
+float BotChangeViewAngle(float angle, float ideal_angle, float speed) {
+ float move;
+
+ angle = AngleMod(angle);
+ ideal_angle = AngleMod(ideal_angle);
+ if (angle == ideal_angle) return angle;
+ move = ideal_angle - angle;
+ if (ideal_angle > angle) {
+ if (move > 180.0) move -= 360.0;
+ }
+ else {
+ if (move < -180.0) move += 360.0;
+ }
+ if (move > 0) {
+ if (move > speed) move = speed;
+ }
+ else {
+ if (move < -speed) move = -speed;
+ }
+ return AngleMod(angle + move);
+}
+
+/*
+==============
+BotChangeViewAngles
+==============
+*/
+void BotChangeViewAngles(bot_state_t *bs, float thinktime) {
+ float diff, factor, maxchange, anglespeed, disired_speed;
+ int i;
+
+ if (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360;
+ //
+ if (bs->enemy >= 0) {
+ factor = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_FACTOR, 0.01f, 1);
+ maxchange = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_MAXCHANGE, 1, 1800);
+ }
+ else {
+ factor = 0.05f;
+ maxchange = 360;
+ }
+ if (maxchange < 240) maxchange = 240;
+ maxchange *= thinktime;
+ for (i = 0; i < 2; i++) {
+ //
+ if (bot_challenge.integer) {
+ //smooth slowdown view model
+ diff = abs(AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]));
+ anglespeed = diff * factor;
+ if (anglespeed > maxchange) anglespeed = maxchange;
+ bs->viewangles[i] = BotChangeViewAngle(bs->viewangles[i],
+ bs->ideal_viewangles[i], anglespeed);
+ }
+ else {
+ //over reaction view model
+ bs->viewangles[i] = AngleMod(bs->viewangles[i]);
+ bs->ideal_viewangles[i] = AngleMod(bs->ideal_viewangles[i]);
+ diff = AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]);
+ disired_speed = diff * factor;
+ bs->viewanglespeed[i] += (bs->viewanglespeed[i] - disired_speed);
+ if (bs->viewanglespeed[i] > 180) bs->viewanglespeed[i] = maxchange;
+ if (bs->viewanglespeed[i] < -180) bs->viewanglespeed[i] = -maxchange;
+ anglespeed = bs->viewanglespeed[i];
+ if (anglespeed > maxchange) anglespeed = maxchange;
+ if (anglespeed < -maxchange) anglespeed = -maxchange;
+ bs->viewangles[i] += anglespeed;
+ bs->viewangles[i] = AngleMod(bs->viewangles[i]);
+ //demping
+ bs->viewanglespeed[i] *= 0.45 * (1 - factor);
+ }
+ //BotAI_Print(PRT_MESSAGE, "ideal_angles %f %f\n", bs->ideal_viewangles[0], bs->ideal_viewangles[1], bs->ideal_viewangles[2]);`
+ //bs->viewangles[i] = bs->ideal_viewangles[i];
+ }
+ //bs->viewangles[PITCH] = 0;
+ if (bs->viewangles[PITCH] > 180) bs->viewangles[PITCH] -= 360;
+ //elementary action: view
+ trap_EA_View(bs->client, bs->viewangles);
+}
+
+/*
+==============
+BotInputToUserCommand
+==============
+*/
+void BotInputToUserCommand(bot_input_t *bi, usercmd_t *ucmd, int delta_angles[3], int time) {
+ vec3_t angles, forward, right;
+ short temp;
+ int j;
+ float f, r, u, m;
+
+ //clear the whole structure
+ memset(ucmd, 0, sizeof(usercmd_t));
+ //the duration for the user command in milli seconds
+ ucmd->serverTime = time;
+ //
+ if (bi->actionflags & ACTION_DELAYEDJUMP) {
+ bi->actionflags |= ACTION_JUMP;
+ bi->actionflags &= ~ACTION_DELAYEDJUMP;
+ }
+ //set the buttons
+ if (bi->actionflags & ACTION_RESPAWN) ucmd->buttons = BUTTON_ATTACK;
+ if (bi->actionflags & ACTION_ATTACK) ucmd->buttons |= BUTTON_ATTACK;
+ if (bi->actionflags & ACTION_TALK) ucmd->buttons |= BUTTON_TALK;
+ if (bi->actionflags & ACTION_GESTURE) ucmd->buttons |= BUTTON_GESTURE;
+ if (bi->actionflags & ACTION_USE) ucmd->buttons |= BUTTON_USE_HOLDABLE;
+ if (bi->actionflags & ACTION_WALK) ucmd->buttons |= BUTTON_WALKING;
+ if (bi->actionflags & ACTION_AFFIRMATIVE) ucmd->buttons |= BUTTON_AFFIRMATIVE;
+ if (bi->actionflags & ACTION_NEGATIVE) ucmd->buttons |= BUTTON_NEGATIVE;
+ if (bi->actionflags & ACTION_GETFLAG) ucmd->buttons |= BUTTON_GETFLAG;
+ if (bi->actionflags & ACTION_GUARDBASE) ucmd->buttons |= BUTTON_GUARDBASE;
+ if (bi->actionflags & ACTION_PATROL) ucmd->buttons |= BUTTON_PATROL;
+ if (bi->actionflags & ACTION_FOLLOWME) ucmd->buttons |= BUTTON_FOLLOWME;
+ //
+ ucmd->weapon = bi->weapon;
+ //set the view angles
+ //NOTE: the ucmd->angles are the angles WITHOUT the delta angles
+ ucmd->angles[PITCH] = ANGLE2SHORT(bi->viewangles[PITCH]);
+ ucmd->angles[YAW] = ANGLE2SHORT(bi->viewangles[YAW]);
+ ucmd->angles[ROLL] = ANGLE2SHORT(bi->viewangles[ROLL]);
+ //subtract the delta angles
+ for (j = 0; j < 3; j++) {
+ temp = ucmd->angles[j] - delta_angles[j];
+ /*NOTE: disabled because temp should be mod first
+ if ( j == PITCH ) {
+ // don't let the player look up or down more than 90 degrees
+ if ( temp > 16000 ) temp = 16000;
+ else if ( temp < -16000 ) temp = -16000;
+ }
+ */
+ ucmd->angles[j] = temp;
+ }
+ //NOTE: movement is relative to the REAL view angles
+ //get the horizontal forward and right vector
+ //get the pitch in the range [-180, 180]
+ if (bi->dir[2]) angles[PITCH] = bi->viewangles[PITCH];
+ else angles[PITCH] = 0;
+ angles[YAW] = bi->viewangles[YAW];
+ angles[ROLL] = 0;
+ AngleVectors(angles, forward, right, NULL);
+ //bot input speed is in the range [0, 400]
+ bi->speed = bi->speed * 127 / 400;
+ //set the view independent movement
+ f = DotProduct(forward, bi->dir);
+ r = DotProduct(right, bi->dir);
+ u = abs(forward[2]) * bi->dir[2];
+ m = fabs(f);
+
+ if (fabs(r) > m) {
+ m = fabs(r);
+ }
+
+ if (fabs(u) > m) {
+ m = fabs(u);
+ }
+
+ if (m > 0) {
+ f *= bi->speed / m;
+ r *= bi->speed / m;
+ u *= bi->speed / m;
+ }
+
+ ucmd->forwardmove = f;
+ ucmd->rightmove = r;
+ ucmd->upmove = u;
+
+ if (bi->actionflags & ACTION_MOVEFORWARD) ucmd->forwardmove = 127;
+ if (bi->actionflags & ACTION_MOVEBACK) ucmd->forwardmove = -127;
+ if (bi->actionflags & ACTION_MOVELEFT) ucmd->rightmove = -127;
+ if (bi->actionflags & ACTION_MOVERIGHT) ucmd->rightmove = 127;
+ //jump/moveup
+ if (bi->actionflags & ACTION_JUMP) ucmd->upmove = 127;
+ //crouch/movedown
+ if (bi->actionflags & ACTION_CROUCH) ucmd->upmove = -127;
+}
+
+/*
+==============
+BotUpdateInput
+==============
+*/
+void BotUpdateInput(bot_state_t *bs, int time, int elapsed_time) {
+ bot_input_t bi;
+ int j;
+
+ //add the delta angles to the bot's current view angles
+ for (j = 0; j < 3; j++) {
+ bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
+ }
+ //change the bot view angles
+ BotChangeViewAngles(bs, (float) elapsed_time / 1000);
+ //retrieve the bot input
+ trap_EA_GetInput(bs->client, (float) time / 1000, &bi);
+ //respawn hack
+ if (bi.actionflags & ACTION_RESPAWN) {
+ if (bs->lastucmd.buttons & BUTTON_ATTACK) bi.actionflags &= ~(ACTION_RESPAWN|ACTION_ATTACK);
+ }
+ //convert the bot input to a usercmd
+ BotInputToUserCommand(&bi, &bs->lastucmd, bs->cur_ps.delta_angles, time);
+ //subtract the delta angles
+ for (j = 0; j < 3; j++) {
+ bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
+ }
+}
+
+/*
+==============
+BotAIRegularUpdate
+==============
+*/
+void BotAIRegularUpdate(void) {
+ if (regularupdate_time < FloatTime()) {
+ trap_BotUpdateEntityItems();
+ regularupdate_time = FloatTime() + 0.3;
+ }
+}
+
+/*
+==============
+RemoveColorEscapeSequences
+==============
+*/
+void RemoveColorEscapeSequences( char *text ) {
+ int i, l;
+
+ l = 0;
+ for ( i = 0; text[i]; i++ ) {
+ if (Q_IsColorString(&text[i])) {
+ i++;
+ continue;
+ }
+ if (text[i] > 0x7E)
+ continue;
+ text[l++] = text[i];
+ }
+ text[l] = '\0';
+}
+
+/*
+==============
+BotAI
+==============
+*/
+int BotAI(int client, float thinktime) {
+ bot_state_t *bs;
+ char buf[1024], *args;
+ int j;
+
+ trap_EA_ResetInput(client);
+ //
+ bs = botstates[client];
+ if (!bs || !bs->inuse) {
+ BotAI_Print(PRT_FATAL, "BotAI: client %d is not setup\n", client);
+ return qfalse;
+ }
+
+ //retrieve the current client state
+ BotAI_GetClientState( client, &bs->cur_ps );
+
+ //retrieve any waiting server commands
+ while( trap_BotGetServerCommand(client, buf, sizeof(buf)) ) {
+ //have buf point to the command and args to the command arguments
+ args = strchr( buf, ' ');
+ if (!args) continue;
+ *args++ = '\0';
+
+ //remove color espace sequences from the arguments
+ RemoveColorEscapeSequences( args );
+
+ if (!Q_stricmp(buf, "cp "))
+ { /*CenterPrintf*/ }
+ else if (!Q_stricmp(buf, "cs"))
+ { /*ConfigStringModified*/ }
+ else if (!Q_stricmp(buf, "print")) {
+ //remove first and last quote from the chat message
+ memmove(args, args+1, strlen(args));
+ args[strlen(args)-1] = '\0';
+ trap_BotQueueConsoleMessage(bs->cs, CMS_NORMAL, args);
+ }
+ else if (!Q_stricmp(buf, "chat")) {
+ //remove first and last quote from the chat message
+ memmove(args, args+1, strlen(args));
+ args[strlen(args)-1] = '\0';
+ trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, args);
+ }
+ else if (!Q_stricmp(buf, "tchat")) {
+ //remove first and last quote from the chat message
+ memmove(args, args+1, strlen(args));
+ args[strlen(args)-1] = '\0';
+ trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, args);
+ }
+#ifdef MISSIONPACK
+ else if (!Q_stricmp(buf, "vchat")) {
+ BotVoiceChatCommand(bs, SAY_ALL, args);
+ }
+ else if (!Q_stricmp(buf, "vtchat")) {
+ BotVoiceChatCommand(bs, SAY_TEAM, args);
+ }
+ else if (!Q_stricmp(buf, "vtell")) {
+ BotVoiceChatCommand(bs, SAY_TELL, args);
+ }
+#endif
+ else if (!Q_stricmp(buf, "scores"))
+ { /*FIXME: parse scores?*/ }
+ else if (!Q_stricmp(buf, "clientLevelShot"))
+ { /*ignore*/ }
+ }
+ //add the delta angles to the bot's current view angles
+ for (j = 0; j < 3; j++) {
+ bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
+ }
+ //increase the local time of the bot
+ bs->ltime += thinktime;
+ //
+ bs->thinktime = thinktime;
+ //origin of the bot
+ VectorCopy(bs->cur_ps.origin, bs->origin);
+ //eye coordinates of the bot
+ VectorCopy(bs->cur_ps.origin, bs->eye);
+ bs->eye[2] += bs->cur_ps.viewheight;
+ //get the area the bot is in
+ bs->areanum = BotPointAreaNum(bs->origin);
+ //the real AI
+ BotDeathmatchAI(bs, thinktime);
+ //set the weapon selection every AI frame
+ trap_EA_SelectWeapon(bs->client, bs->weaponnum);
+ //subtract the delta angles
+ for (j = 0; j < 3; j++) {
+ bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
+ }
+ //everything was ok
+ return qtrue;
+}
+
+/*
+==================
+BotScheduleBotThink
+==================
+*/
+void BotScheduleBotThink(void) {
+ int i, botnum;
+
+ botnum = 0;
+
+ for( i = 0; i < MAX_CLIENTS; i++ ) {
+ if( !botstates[i] || !botstates[i]->inuse ) {
+ continue;
+ }
+ //initialize the bot think residual time
+ botstates[i]->botthink_residual = bot_thinktime.integer * botnum / numbots;
+ botnum++;
+ }
+}
+
+/*
+==============
+BotWriteSessionData
+==============
+*/
+void BotWriteSessionData(bot_state_t *bs) {
+ const char *s;
+ const char *var;
+
+ s = va(
+ "%i %i %i %i %i %i %i %i"
+ " %f %f %f"
+ " %f %f %f"
+ " %f %f %f",
+ bs->lastgoal_decisionmaker,
+ bs->lastgoal_ltgtype,
+ bs->lastgoal_teammate,
+ bs->lastgoal_teamgoal.areanum,
+ bs->lastgoal_teamgoal.entitynum,
+ bs->lastgoal_teamgoal.flags,
+ bs->lastgoal_teamgoal.iteminfo,
+ bs->lastgoal_teamgoal.number,
+ bs->lastgoal_teamgoal.origin[0],
+ bs->lastgoal_teamgoal.origin[1],
+ bs->lastgoal_teamgoal.origin[2],
+ bs->lastgoal_teamgoal.mins[0],
+ bs->lastgoal_teamgoal.mins[1],
+ bs->lastgoal_teamgoal.mins[2],
+ bs->lastgoal_teamgoal.maxs[0],
+ bs->lastgoal_teamgoal.maxs[1],
+ bs->lastgoal_teamgoal.maxs[2]
+ );
+
+ var = va( "botsession%i", bs->client );
+
+ trap_Cvar_Set( var, s );
+}
+
+/*
+==============
+BotReadSessionData
+==============
+*/
+void BotReadSessionData(bot_state_t *bs) {
+ char s[MAX_STRING_CHARS];
+ const char *var;
+
+ var = va( "botsession%i", bs->client );
+ trap_Cvar_VariableStringBuffer( var, s, sizeof(s) );
+
+ sscanf(s,
+ "%i %i %i %i %i %i %i %i"
+ " %f %f %f"
+ " %f %f %f"
+ " %f %f %f",
+ &bs->lastgoal_decisionmaker,
+ &bs->lastgoal_ltgtype,
+ &bs->lastgoal_teammate,
+ &bs->lastgoal_teamgoal.areanum,
+ &bs->lastgoal_teamgoal.entitynum,
+ &bs->lastgoal_teamgoal.flags,
+ &bs->lastgoal_teamgoal.iteminfo,
+ &bs->lastgoal_teamgoal.number,
+ &bs->lastgoal_teamgoal.origin[0],
+ &bs->lastgoal_teamgoal.origin[1],
+ &bs->lastgoal_teamgoal.origin[2],
+ &bs->lastgoal_teamgoal.mins[0],
+ &bs->lastgoal_teamgoal.mins[1],
+ &bs->lastgoal_teamgoal.mins[2],
+ &bs->lastgoal_teamgoal.maxs[0],
+ &bs->lastgoal_teamgoal.maxs[1],
+ &bs->lastgoal_teamgoal.maxs[2]
+ );
+}
+
+/*
+==============
+BotAISetupClient
+==============
+*/
+int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean restart) {
+ char filename[MAX_PATH], name[MAX_PATH], gender[MAX_PATH];
+ bot_state_t *bs;
+ int errnum;
+ //KK-OAX Changed to Tremulous's BG_Alloc
+ if (!botstates[client]) {
+ if(!BG_CanAlloc(sizeof(bot_state_t))) {
+ //We cannot run BG_Alloc, fail nicely
+ BotAI_Print(PRT_FATAL, "BotAISetupClient: Not enough heap memory\n", client);
+ return qfalse;
+ }
+ botstates[client] = BG_Alloc(sizeof(bot_state_t));
+ //BG_Allow will succed or terminate
+ }
+ bs = botstates[client];
+
+ if (bs && bs->inuse) {
+ BotAI_Print(PRT_FATAL, "BotAISetupClient: client %d already setup\n", client);
+ return qfalse;
+ }
+
+ if (!trap_AAS_Initialized()) {
+ BotAI_Print(PRT_FATAL, "AAS not initialized\n");
+ return qfalse;
+ }
+
+ //load the bot character
+ bs->character = trap_BotLoadCharacter(settings->characterfile, settings->skill);
+ if (!bs->character) {
+ BotAI_Print(PRT_FATAL, "couldn't load skill %f from %s\n", settings->skill, settings->characterfile);
+ return qfalse;
+ }
+ //copy the settings
+ memcpy(&bs->settings, settings, sizeof(bot_settings_t));
+ //allocate a goal state
+ bs->gs = trap_BotAllocGoalState(client);
+ //load the item weights
+ trap_Characteristic_String(bs->character, CHARACTERISTIC_ITEMWEIGHTS, filename, MAX_PATH);
+ errnum = trap_BotLoadItemWeights(bs->gs, filename);
+ if (errnum != BLERR_NOERROR) {
+ trap_BotFreeGoalState(bs->gs);
+ return qfalse;
+ }
+ //allocate a weapon state
+ bs->ws = trap_BotAllocWeaponState();
+ //load the weapon weights
+ trap_Characteristic_String(bs->character, CHARACTERISTIC_WEAPONWEIGHTS, filename, MAX_PATH);
+ errnum = trap_BotLoadWeaponWeights(bs->ws, filename);
+ if (errnum != BLERR_NOERROR) {
+ trap_BotFreeGoalState(bs->gs);
+ trap_BotFreeWeaponState(bs->ws);
+ return qfalse;
+ }
+ //allocate a chat state
+ bs->cs = trap_BotAllocChatState();
+ //load the chat file
+ trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_FILE, filename, MAX_PATH);
+ trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_NAME, name, MAX_PATH);
+ errnum = trap_BotLoadChatFile(bs->cs, filename, name);
+ if (errnum != BLERR_NOERROR) {
+ trap_BotFreeChatState(bs->cs);
+ trap_BotFreeGoalState(bs->gs);
+ trap_BotFreeWeaponState(bs->ws);
+ return qfalse;
+ }
+ //get the gender characteristic
+ trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, MAX_PATH);
+ //set the chat gender
+ if (*gender == 'f' || *gender == 'F') trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE);
+ else if (*gender == 'm' || *gender == 'M') trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE);
+ else trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS);
+
+ bs->inuse = qtrue;
+ bs->client = client;
+ bs->entitynum = client;
+ bs->setupcount = 4;
+ bs->entergame_time = FloatTime();
+ bs->ms = trap_BotAllocMoveState();
+ bs->walker = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WALKER, 0, 1);
+ numbots++;
+
+ if (trap_Cvar_VariableIntegerValue("bot_testichat")) {
+ trap_BotLibVarSet("bot_testichat", "1");
+ BotChatTest(bs);
+ }
+ //NOTE: reschedule the bot thinking
+ BotScheduleBotThink();
+ //if interbreeding start with a mutation
+ if (bot_interbreed) {
+ trap_BotMutateGoalFuzzyLogic(bs->gs, 1);
+ }
+ // if we kept the bot client
+ if (restart) {
+ BotReadSessionData(bs);
+ }
+ //bot has been setup succesfully
+ return qtrue;
+}
+
+/*
+==============
+BotAIShutdownClient
+==============
+*/
+int BotAIShutdownClient(int client, qboolean restart) {
+ bot_state_t *bs;
+
+ bs = botstates[client];
+ if (!bs || !bs->inuse) {
+ //BotAI_Print(PRT_ERROR, "BotAIShutdownClient: client %d already shutdown\n", client);
+ return qfalse;
+ }
+
+ if (restart) {
+ BotWriteSessionData(bs);
+ }
+
+ if (BotChat_ExitGame(bs)) {
+ trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
+ }
+
+ trap_BotFreeMoveState(bs->ms);
+ //free the goal state`
+ trap_BotFreeGoalState(bs->gs);
+ //free the chat file
+ trap_BotFreeChatState(bs->cs);
+ //free the weapon weights
+ trap_BotFreeWeaponState(bs->ws);
+ //free the bot character
+ trap_BotFreeCharacter(bs->character);
+ //
+ BotFreeWaypoints(bs->checkpoints);
+ BotFreeWaypoints(bs->patrolpoints);
+ //clear activate goal stack
+ BotClearActivateGoalStack(bs);
+ //clear the bot state
+ memset(bs, 0, sizeof(bot_state_t));
+ //set the inuse flag to qfalse
+ bs->inuse = qfalse;
+
+ //there's one bot less
+ numbots--;
+ //everything went ok
+ return qtrue;
+}
+
+/*
+==============
+BotResetState
+
+called when a bot enters the intermission or observer mode and
+when the level is changed
+==============
+*/
+void BotResetState(bot_state_t *bs) {
+ int client, entitynum, inuse;
+ int movestate, goalstate, chatstate, weaponstate;
+ bot_settings_t settings;
+ int character;
+ playerState_t ps; //current player state
+ float entergame_time;
+
+ //save some things that should not be reset here
+ memcpy(&settings, &bs->settings, sizeof(bot_settings_t));
+ memcpy(&ps, &bs->cur_ps, sizeof(playerState_t));
+ inuse = bs->inuse;
+ client = bs->client;
+ entitynum = bs->entitynum;
+ character = bs->character;
+ movestate = bs->ms;
+ goalstate = bs->gs;
+ chatstate = bs->cs;
+ weaponstate = bs->ws;
+ entergame_time = bs->entergame_time;
+ //free checkpoints and patrol points
+ BotFreeWaypoints(bs->checkpoints);
+ BotFreeWaypoints(bs->patrolpoints);
+ //reset the whole state
+ memset(bs, 0, sizeof(bot_state_t));
+ //copy back some state stuff that should not be reset
+ bs->ms = movestate;
+ bs->gs = goalstate;
+ bs->cs = chatstate;
+ bs->ws = weaponstate;
+ memcpy(&bs->cur_ps, &ps, sizeof(playerState_t));
+ memcpy(&bs->settings, &settings, sizeof(bot_settings_t));
+ bs->inuse = inuse;
+ bs->client = client;
+ bs->entitynum = entitynum;
+ bs->character = character;
+ bs->entergame_time = entergame_time;
+ //reset several states
+ if (bs->ms) trap_BotResetMoveState(bs->ms);
+ if (bs->gs) trap_BotResetGoalState(bs->gs);
+ if (bs->ws) trap_BotResetWeaponState(bs->ws);
+ if (bs->gs) trap_BotResetAvoidGoals(bs->gs);
+ if (bs->ms) trap_BotResetAvoidReach(bs->ms);
+}
+
+/*
+==============
+BotAILoadMap
+==============
+*/
+int BotAILoadMap( int restart ) {
+ int i;
+ vmCvar_t mapname;
+
+ if (!restart) {
+ trap_Cvar_Register( &mapname, "mapname", "", CVAR_SERVERINFO | CVAR_ROM );
+ trap_BotLibLoadMap( mapname.string );
+ }
+
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ if (botstates[i] && botstates[i]->inuse) {
+ BotResetState( botstates[i] );
+ botstates[i]->setupcount = 4;
+ }
+ }
+
+ BotSetupDeathmatchAI();
+
+ return qtrue;
+}
+
+void ProximityMine_Trigger( gentity_t *trigger, gentity_t *other, trace_t *trace );
+
+/*
+==================
+BotAIStartFrame
+==================
+*/
+int BotAIStartFrame(int time) {
+ int i;
+ gentity_t *ent;
+ bot_entitystate_t state;
+ int elapsed_time, thinktime;
+ static int local_time;
+ static int botlib_residual;
+ static int lastbotthink_time;
+
+ G_CheckBotSpawn();
+
+ trap_Cvar_Update(&bot_rocketjump);
+ trap_Cvar_Update(&bot_grapple);
+ trap_Cvar_Update(&bot_fastchat);
+ trap_Cvar_Update(&bot_nochat);
+ trap_Cvar_Update(&bot_testrchat);
+ trap_Cvar_Update(&bot_thinktime);
+ trap_Cvar_Update(&bot_memorydump);
+ trap_Cvar_Update(&bot_saveroutingcache);
+ trap_Cvar_Update(&bot_pause);
+ trap_Cvar_Update(&bot_report);
+
+ if (bot_report.integer) {
+// BotTeamplayReport();
+// trap_Cvar_Set("bot_report", "0");
+ BotUpdateInfoConfigStrings();
+ }
+
+ if (bot_pause.integer) {
+ // execute bot user commands every frame
+ for( i = 0; i < MAX_CLIENTS; i++ ) {
+ if( !botstates[i] || !botstates[i]->inuse ) {
+ continue;
+ }
+ if( g_entities[i].client->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ botstates[i]->lastucmd.forwardmove = 0;
+ botstates[i]->lastucmd.rightmove = 0;
+ botstates[i]->lastucmd.upmove = 0;
+ botstates[i]->lastucmd.buttons = 0;
+ botstates[i]->lastucmd.serverTime = time;
+ trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd);
+ }
+ return qtrue;
+ }
+
+ if (bot_memorydump.integer) {
+ trap_BotLibVarSet("memorydump", "1");
+ trap_Cvar_Set("bot_memorydump", "0");
+ }
+ if (bot_saveroutingcache.integer) {
+ trap_BotLibVarSet("saveroutingcache", "1");
+ trap_Cvar_Set("bot_saveroutingcache", "0");
+ }
+ //check if bot interbreeding is activated
+ BotInterbreeding();
+ //cap the bot think time
+ if (bot_thinktime.integer > 200) {
+ trap_Cvar_Set("bot_thinktime", "200");
+ }
+ //if the bot think time changed we should reschedule the bots
+ if (bot_thinktime.integer != lastbotthink_time) {
+ lastbotthink_time = bot_thinktime.integer;
+ BotScheduleBotThink();
+ }
+
+ elapsed_time = time - local_time;
+ local_time = time;
+
+ botlib_residual += elapsed_time;
+
+ if (elapsed_time > bot_thinktime.integer) thinktime = elapsed_time;
+ else thinktime = bot_thinktime.integer;
+
+ // update the bot library
+ if ( botlib_residual >= thinktime ) {
+ botlib_residual -= thinktime;
+
+ trap_BotLibStartFrame((float) time / 1000);
+
+ if (!trap_AAS_Initialized()) return qfalse;
+
+ //update entities in the botlib
+ for (i = 0; i < MAX_GENTITIES; i++) {
+ ent = &g_entities[i];
+ if (!ent->inuse) {
+ trap_BotLibUpdateEntity(i, NULL);
+ continue;
+ }
+ if (!ent->r.linked) {
+ trap_BotLibUpdateEntity(i, NULL);
+ continue;
+ }
+ if ( !(g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_LMS ||g_instantgib.integer || g_rockets.integer || g_elimination_allgametypes.integer || g_gametype.integer==GT_CTF_ELIMINATION)
+ && ent->r.svFlags & SVF_NOCLIENT) {
+ trap_BotLibUpdateEntity(i, NULL);
+ continue;
+ }
+ // do not update missiles
+ if (ent->s.eType == ET_MISSILE && ent->s.weapon != WP_GRAPPLING_HOOK) {
+ trap_BotLibUpdateEntity(i, NULL);
+ continue;
+ }
+ // do not update event only entities
+ if (ent->s.eType > ET_EVENTS) {
+ trap_BotLibUpdateEntity(i, NULL);
+ continue;
+ }
+
+ // never link prox mine triggers
+ if (ent->r.contents == CONTENTS_TRIGGER) {
+ if (ent->touch == ProximityMine_Trigger) {
+ trap_BotLibUpdateEntity(i, NULL);
+ continue;
+ }
+ }
+
+ //
+ memset(&state, 0, sizeof(bot_entitystate_t));
+ //
+ VectorCopy(ent->r.currentOrigin, state.origin);
+ if (i < MAX_CLIENTS) {
+ VectorCopy(ent->s.apos.trBase, state.angles);
+ } else {
+ VectorCopy(ent->r.currentAngles, state.angles);
+ }
+ VectorCopy(ent->s.origin2, state.old_origin);
+ VectorCopy(ent->r.mins, state.mins);
+ VectorCopy(ent->r.maxs, state.maxs);
+ state.type = ent->s.eType;
+ state.flags = ent->s.eFlags;
+ if (ent->r.bmodel) state.solid = SOLID_BSP;
+ else state.solid = SOLID_BBOX;
+ state.groundent = ent->s.groundEntityNum;
+ state.modelindex = ent->s.modelindex;
+ state.modelindex2 = ent->s.modelindex2;
+ state.frame = ent->s.frame;
+ state.event = ent->s.event;
+ state.eventParm = ent->s.eventParm;
+ state.powerups = ent->s.powerups;
+ state.legsAnim = ent->s.legsAnim;
+ state.torsoAnim = ent->s.torsoAnim;
+ state.weapon = ent->s.weapon;
+ //
+ trap_BotLibUpdateEntity(i, &state);
+ }
+
+ BotAIRegularUpdate();
+ }
+
+ floattime = trap_AAS_Time();
+
+ // execute scheduled bot AI
+ for( i = 0; i < MAX_CLIENTS; i++ ) {
+ if( !botstates[i] || !botstates[i]->inuse ) {
+ continue;
+ }
+ //
+ botstates[i]->botthink_residual += elapsed_time;
+ //
+ if ( botstates[i]->botthink_residual >= thinktime ) {
+ botstates[i]->botthink_residual -= thinktime;
+
+ if (!trap_AAS_Initialized()) return qfalse;
+
+ if (g_entities[i].client->pers.connected == CON_CONNECTED) {
+ BotAI(i, (float) thinktime / 1000);
+ }
+ }
+ }
+
+
+ // execute bot user commands every frame
+ for( i = 0; i < MAX_CLIENTS; i++ ) {
+ if( !botstates[i] || !botstates[i]->inuse ) {
+ continue;
+ }
+ if( g_entities[i].client->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+
+ BotUpdateInput(botstates[i], time, elapsed_time);
+ trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd);
+ }
+
+ return qtrue;
+}
+
+/*
+==============
+BotInitLibrary
+==============
+*/
+int BotInitLibrary(void) {
+ char buf[144];
+
+ //set the maxclients and maxentities library variables before calling BotSetupLibrary
+ trap_Cvar_VariableStringBuffer("sv_maxclients", buf, sizeof(buf));
+ if (!strlen(buf)) strcpy(buf, "8");
+ trap_BotLibVarSet("maxclients", buf);
+ Com_sprintf(buf, sizeof(buf), "%d", MAX_GENTITIES);
+ trap_BotLibVarSet("maxentities", buf);
+ //bsp checksum
+ trap_Cvar_VariableStringBuffer("sv_mapChecksum", buf, sizeof(buf));
+ if (strlen(buf)) trap_BotLibVarSet("sv_mapChecksum", buf);
+ //maximum number of aas links
+ trap_Cvar_VariableStringBuffer("max_aaslinks", buf, sizeof(buf));
+ if (strlen(buf)) trap_BotLibVarSet("max_aaslinks", buf);
+ //maximum number of items in a level
+ trap_Cvar_VariableStringBuffer("max_levelitems", buf, sizeof(buf));
+ if (strlen(buf)) trap_BotLibVarSet("max_levelitems", buf);
+ //game type
+ trap_Cvar_VariableStringBuffer("g_gametype", buf, sizeof(buf));
+ if (!strlen(buf)) strcpy(buf, "0");
+ trap_BotLibVarSet("g_gametype", buf);
+ //bot developer mode and log file
+ trap_BotLibVarSet("bot_developer", bot_developer.string);
+ trap_Cvar_VariableStringBuffer("logfile", buf, sizeof(buf));
+ trap_BotLibVarSet("log", buf);
+ //no chatting
+ trap_Cvar_VariableStringBuffer("bot_nochat", buf, sizeof(buf));
+ if (strlen(buf)) trap_BotLibVarSet("nochat", buf);
+ //visualize jump pads
+ trap_Cvar_VariableStringBuffer("bot_visualizejumppads", buf, sizeof(buf));
+ if (strlen(buf)) trap_BotLibVarSet("bot_visualizejumppads", buf);
+ //forced clustering calculations
+ trap_Cvar_VariableStringBuffer("bot_forceclustering", buf, sizeof(buf));
+ if (strlen(buf)) trap_BotLibVarSet("forceclustering", buf);
+ //forced reachability calculations
+ trap_Cvar_VariableStringBuffer("bot_forcereachability", buf, sizeof(buf));
+ if (strlen(buf)) trap_BotLibVarSet("forcereachability", buf);
+ //force writing of AAS to file
+ trap_Cvar_VariableStringBuffer("bot_forcewrite", buf, sizeof(buf));
+ if (strlen(buf)) trap_BotLibVarSet("forcewrite", buf);
+ //no AAS optimization
+ trap_Cvar_VariableStringBuffer("bot_aasoptimize", buf, sizeof(buf));
+ if (strlen(buf)) trap_BotLibVarSet("aasoptimize", buf);
+ //
+ trap_Cvar_VariableStringBuffer("bot_saveroutingcache", buf, sizeof(buf));
+ if (strlen(buf)) trap_BotLibVarSet("saveroutingcache", buf);
+ //reload instead of cache bot character files
+ trap_Cvar_VariableStringBuffer("bot_reloadcharacters", buf, sizeof(buf));
+ if (!strlen(buf)) strcpy(buf, "0");
+ trap_BotLibVarSet("bot_reloadcharacters", buf);
+ //base directory
+ trap_Cvar_VariableStringBuffer("fs_basepath", buf, sizeof(buf));
+ if (strlen(buf)) trap_BotLibVarSet("basedir", buf);
+ //game directory
+ trap_Cvar_VariableStringBuffer("fs_game", buf, sizeof(buf));
+ if (strlen(buf)) trap_BotLibVarSet("gamedir", buf);
+ //home directory
+ trap_Cvar_VariableStringBuffer("fs_homepath", buf, sizeof(buf));
+ if (strlen(buf)) trap_BotLibVarSet("homedir", buf);
+ //
+#ifdef MISSIONPACK
+ trap_BotLibDefine("MISSIONPACK");
+#endif
+ //setup the bot library
+ return trap_BotLibSetup();
+}
+
+/*
+==============
+BotAISetup
+==============
+*/
+int BotAISetup( int restart ) {
+ int errnum;
+
+ trap_Cvar_Register(&bot_thinktime, "bot_thinktime", "100", CVAR_CHEAT);
+ trap_Cvar_Register(&bot_memorydump, "bot_memorydump", "0", CVAR_CHEAT);
+ trap_Cvar_Register(&bot_saveroutingcache, "bot_saveroutingcache", "0", CVAR_CHEAT);
+ trap_Cvar_Register(&bot_pause, "bot_pause", "0", CVAR_CHEAT);
+ trap_Cvar_Register(&bot_report, "bot_report", "0", CVAR_CHEAT);
+ trap_Cvar_Register(&bot_testsolid, "bot_testsolid", "0", CVAR_CHEAT);
+ trap_Cvar_Register(&bot_testclusters, "bot_testclusters", "0", CVAR_CHEAT);
+ trap_Cvar_Register(&bot_developer, "bot_developer", "0", CVAR_CHEAT);
+ trap_Cvar_Register(&bot_interbreedchar, "bot_interbreedchar", "", 0);
+ trap_Cvar_Register(&bot_interbreedbots, "bot_interbreedbots", "10", 0);
+ trap_Cvar_Register(&bot_interbreedcycle, "bot_interbreedcycle", "20", 0);
+ trap_Cvar_Register(&bot_interbreedwrite, "bot_interbreedwrite", "", 0);
+
+ //if the game is restarted for a tournament
+ if (restart) {
+ return qtrue;
+ }
+
+ //initialize the bot states
+ memset( botstates, 0, sizeof(botstates) );
+
+ errnum = BotInitLibrary();
+ if (errnum != BLERR_NOERROR) return qfalse;
+ return qtrue;
+}
+
+/*
+==============
+BotAIShutdown
+==============
+*/
+int BotAIShutdown( int restart ) {
+
+ int i;
+
+ //if the game is restarted for a tournament
+ if ( restart ) {
+ //shutdown all the bots in the botlib
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ if (botstates[i] && botstates[i]->inuse) {
+ BotAIShutdownClient(botstates[i]->client, restart);
+ }
+ }
+ //don't shutdown the bot library
+ }
+ else {
+ trap_BotLibShutdown();
+ }
+ return qtrue;
+}
+
diff --git a/game/code/game/ai_main.h b/code/game/ai_main.h
similarity index 100%
rename from game/code/game/ai_main.h
rename to code/game/ai_main.h
diff --git a/code/game/ai_team.c b/code/game/ai_team.c
new file mode 100644
index 0000000..c1d0394
--- /dev/null
+++ b/code/game/ai_team.c
@@ -0,0 +1,2277 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+/*****************************************************************************
+ * name: ai_team.c
+ *
+ * desc: Quake3 bot AI
+ *
+ * $Archive: /MissionPack/code/game/ai_team.c $
+ *
+ *****************************************************************************/
+
+#include "g_local.h"
+#include "../botlib/botlib.h"
+#include "../botlib/be_aas.h"
+#include "../botlib/be_ea.h"
+#include "../botlib/be_ai_char.h"
+#include "../botlib/be_ai_chat.h"
+#include "../botlib/be_ai_gen.h"
+#include "../botlib/be_ai_goal.h"
+#include "../botlib/be_ai_move.h"
+#include "../botlib/be_ai_weap.h"
+//
+#include "ai_main.h"
+#include "ai_dmq3.h"
+#include "ai_chat.h"
+#include "ai_cmd.h"
+#include "ai_dmnet.h"
+#include "ai_team.h"
+#include "ai_vcmd.h"
+
+#include "match.h"
+
+// for the voice chats
+#include "../../ui/menudef.h"
+
+//ctf task preferences for a client
+typedef struct bot_ctftaskpreference_s
+{
+ char name[36];
+ int preference;
+} bot_ctftaskpreference_t;
+
+bot_ctftaskpreference_t ctftaskpreferences[MAX_CLIENTS];
+
+
+/*
+==================
+BotValidTeamLeader
+==================
+*/
+int BotValidTeamLeader(bot_state_t *bs) {
+ if (!strlen(bs->teamleader)) return qfalse;
+ if (ClientFromName(bs->teamleader) == -1) return qfalse;
+ return qtrue;
+}
+
+/*
+==================
+BotNumTeamMates
+==================
+*/
+int BotNumTeamMates(bot_state_t *bs) {
+ int i, numplayers;
+ char buf[MAX_INFO_STRING];
+ static int maxclients;
+
+ if (!maxclients)
+ maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
+
+ numplayers = 0;
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ //if no config string or no name
+ if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
+ //skip spectators
+ if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
+ //
+ if (BotSameTeam(bs, i)) {
+ numplayers++;
+ }
+ }
+ return numplayers;
+}
+
+/*
+==================
+BotClientTravelTimeToGoal
+==================
+*/
+int BotClientTravelTimeToGoal(int client, bot_goal_t *goal) {
+ playerState_t ps;
+ int areanum;
+
+ BotAI_GetClientState(client, &ps);
+ areanum = BotPointAreaNum(ps.origin);
+ if (!areanum) return 1;
+ return trap_AAS_AreaTravelTimeToGoalArea(areanum, ps.origin, goal->areanum, TFL_DEFAULT);
+}
+
+/*
+==================
+BotSortTeamMatesByBaseTravelTime
+==================
+*/
+int BotSortTeamMatesByBaseTravelTime(bot_state_t *bs, int *teammates, int maxteammates) {
+
+ int i, j, k, numteammates, traveltime;
+ char buf[MAX_INFO_STRING];
+ static int maxclients;
+ int traveltimes[MAX_CLIENTS];
+ bot_goal_t *goal = NULL;
+
+ if (gametype == GT_CTF || gametype == GT_1FCTF || gametype == GT_CTF_ELIMINATION) {
+ if (BotTeam(bs) == TEAM_RED)
+ goal = &ctf_redflag;
+ else
+ goal = &ctf_blueflag;
+ }
+ else {
+ if (BotTeam(bs) == TEAM_RED)
+ goal = &redobelisk;
+ else
+ goal = &blueobelisk;
+ }
+ if (!maxclients)
+ maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
+
+ numteammates = 0;
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ //if no config string or no name
+ if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
+ //skip spectators
+ if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
+ //
+ if (BotSameTeam(bs, i)) {
+ //
+ traveltime = BotClientTravelTimeToGoal(i, goal);
+ //
+ for (j = 0; j < numteammates; j++) {
+ if (traveltime < traveltimes[j]) {
+ for (k = numteammates; k > j; k--) {
+ traveltimes[k] = traveltimes[k-1];
+ teammates[k] = teammates[k-1];
+ }
+ break;
+ }
+ }
+ traveltimes[j] = traveltime;
+ teammates[j] = i;
+ numteammates++;
+ if (numteammates >= maxteammates) break;
+ }
+ }
+ return numteammates;
+}
+
+/*
+==================
+BotSortTeamMatesByReletiveTravelTime2ddA
+For Double Domination
+==================
+*/
+int BotSortTeamMatesByRelativeTravelTime2ddA(bot_state_t *bs, int *teammates, int maxteammates) {
+ int i, j, k, numteammates;
+ double traveltime, traveltime2b;
+ char buf[MAX_INFO_STRING];
+ static int maxclients;
+ double traveltimes[MAX_CLIENTS];
+ //int traveltimes2b[MAX_CLIENTS];
+ bot_goal_t *goalA = &ctf_redflag;
+ bot_goal_t *goalB = &ctf_blueflag;
+
+ if (!maxclients)
+ maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
+
+ numteammates = 0;
+
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ //if no config string or no name
+ if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
+ //skip spectators
+ if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
+ if (BotSameTeam(bs, i)) {
+ traveltime = (double)BotClientTravelTimeToGoal(i, goalA);
+ traveltime2b = (double)BotClientTravelTimeToGoal(i, goalB);
+ traveltime = traveltime/traveltime2b;
+
+ for (j = 0; j < numteammates; j++) {
+ if (traveltime < traveltimes[j]) {
+ for (k = numteammates; k > j; k--) {
+ traveltimes[k] = traveltimes[k-1];
+ teammates[k] = teammates[k-1];
+ }
+ break;
+ }
+ }
+ traveltimes[j] = traveltime;
+ teammates[j] = i;
+ numteammates++;
+ if (numteammates >= maxteammates) break;
+ }
+ }
+
+ return numteammates;
+}
+
+/*
+==================
+BotSetTeamMateTaskPreference
+==================
+*/
+void BotSetTeamMateTaskPreference(bot_state_t *bs, int teammate, int preference) {
+ char teammatename[MAX_NETNAME];
+
+ ctftaskpreferences[teammate].preference = preference;
+ ClientName(teammate, teammatename, sizeof(teammatename));
+ strcpy(ctftaskpreferences[teammate].name, teammatename);
+}
+
+/*
+==================
+BotGetTeamMateTaskPreference
+==================
+*/
+int BotGetTeamMateTaskPreference(bot_state_t *bs, int teammate) {
+ char teammatename[MAX_NETNAME];
+
+ if (!ctftaskpreferences[teammate].preference) return 0;
+ ClientName(teammate, teammatename, sizeof(teammatename));
+ if (Q_stricmp(teammatename, ctftaskpreferences[teammate].name)) return 0;
+ return ctftaskpreferences[teammate].preference;
+}
+
+/*
+==================
+BotSortTeamMatesByTaskPreference
+==================
+*/
+int BotSortTeamMatesByTaskPreference(bot_state_t *bs, int *teammates, int numteammates) {
+ int defenders[MAX_CLIENTS], numdefenders;
+ int attackers[MAX_CLIENTS], numattackers;
+ int roamers[MAX_CLIENTS], numroamers;
+ int i, preference;
+
+ numdefenders = numattackers = numroamers = 0;
+ for (i = 0; i < numteammates; i++) {
+ preference = BotGetTeamMateTaskPreference(bs, teammates[i]);
+ if (preference & TEAMTP_DEFENDER) {
+ defenders[numdefenders++] = teammates[i];
+ }
+ else if (preference & TEAMTP_ATTACKER) {
+ attackers[numattackers++] = teammates[i];
+ }
+ else {
+ roamers[numroamers++] = teammates[i];
+ }
+ }
+ numteammates = 0;
+ //defenders at the front of the list
+ memcpy(&teammates[numteammates], defenders, numdefenders * sizeof(int));
+ numteammates += numdefenders;
+ //roamers in the middle
+ memcpy(&teammates[numteammates], roamers, numroamers * sizeof(int));
+ numteammates += numroamers;
+ //attacker in the back of the list
+ memcpy(&teammates[numteammates], attackers, numattackers * sizeof(int));
+ numteammates += numattackers;
+
+ return numteammates;
+}
+
+/*
+==================
+BotSayTeamOrders
+==================
+*/
+void BotSayTeamOrderAlways(bot_state_t *bs, int toclient) {
+ char teamchat[MAX_MESSAGE_SIZE];
+ char buf[MAX_MESSAGE_SIZE];
+ char name[MAX_NETNAME];
+
+ if (bot_nochat.integer>2) return;
+
+ //if the bot is talking to itself
+ if (bs->client == toclient) {
+ //don't show the message just put it in the console message queue
+ trap_BotGetChatMessage(bs->cs, buf, sizeof(buf));
+ ClientName(bs->client, name, sizeof(name));
+ Com_sprintf(teamchat, sizeof(teamchat), EC"(%s"EC")"EC": %s", name, buf);
+ trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, teamchat);
+ }
+ else {
+ trap_BotEnterChat(bs->cs, toclient, CHAT_TELL);
+ }
+}
+
+/*
+==================
+BotSayTeamOrders
+==================
+*/
+void BotSayTeamOrder(bot_state_t *bs, int toclient) {
+#ifdef MISSIONPACK
+ // voice chats only
+ char buf[MAX_MESSAGE_SIZE];
+
+ trap_BotGetChatMessage(bs->cs, buf, sizeof(buf));
+#else
+ BotSayTeamOrderAlways(bs, toclient);
+#endif
+}
+
+/*
+==================
+BotVoiceChat
+==================
+*/
+void BotVoiceChat(bot_state_t *bs, int toclient, char *voicechat) {
+#ifdef MISSIONPACK
+ if (toclient == -1)
+ // voice only say team
+ trap_EA_Command(bs->client, va("vsay_team %s", voicechat));
+ else
+ // voice only tell single player
+ trap_EA_Command(bs->client, va("vtell %d %s", toclient, voicechat));
+#endif
+}
+
+/*
+==================
+BotVoiceChatOnly
+==================
+*/
+void BotVoiceChatOnly(bot_state_t *bs, int toclient, char *voicechat) {
+
+#ifdef MISSIONPACK
+ if (toclient == -1)
+ // voice only say team
+ trap_EA_Command(bs->client, va("vosay_team %s", voicechat));
+ else
+ // voice only tell single player
+ trap_EA_Command(bs->client, va("votell %d %s", toclient, voicechat));
+#endif
+}
+
+/*
+==================
+BotSayVoiceTeamOrder
+==================
+*/
+void BotSayVoiceTeamOrder(bot_state_t *bs, int toclient, char *voicechat) {
+
+#ifdef MISSIONPACK
+ BotVoiceChat(bs, toclient, voicechat);
+#endif
+}
+
+/*
+==================
+BotCTFOrders
+==================
+*/
+void BotCTFOrders_BothFlagsNotAtBase(bot_state_t *bs) {
+ int numteammates, defenders, attackers, i, other;
+ int teammates[MAX_CLIENTS];
+ char name[MAX_NETNAME], carriername[MAX_NETNAME];
+
+ numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
+ BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
+ //different orders based on the number of team mates
+ switch(bs->numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //tell the one not carrying the flag to attack the enemy base
+ if (teammates[0] != bs->flagcarrier) other = teammates[0];
+ else other = teammates[1];
+ ClientName(other, name, sizeof(name));
+ if (bot_nochat.integer<3) BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, other);
+ BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
+ break;
+ }
+ case 3:
+ {
+ //tell the one closest to the base not carrying the flag to accompany the flag carrier
+ if (teammates[0] != bs->flagcarrier) other = teammates[0];
+ else other = teammates[1];
+ ClientName(other, name, sizeof(name));
+ if ( bs->flagcarrier != -1 ) {
+ ClientName(bs->flagcarrier, carriername, sizeof(carriername));
+ if (bs->flagcarrier == bs->client) {
+ if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
+ if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
+ }
+ else {
+ if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
+ if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
+ }
+ }
+ else {
+ //
+ if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
+ }
+ if (bot_nochat.integer<3)BotSayTeamOrder(bs, other);
+ //tell the one furthest from the the base not carrying the flag to get the enemy flag
+ if (teammates[2] != bs->flagcarrier) other = teammates[2];
+ else other = teammates[1];
+ ClientName(other, name, sizeof(name));
+ if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ if (bot_nochat.integer<3)BotSayTeamOrder(bs, other);
+ if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, other, VOICECHAT_RETURNFLAG);
+ break;
+ }
+ default:
+ {
+ defenders = (int) (float) numteammates * 0.4 + 0.5;
+ if (defenders > 4) defenders = 4;
+ attackers = (int) (float) numteammates * 0.5 + 0.5;
+ if (attackers > 5) attackers = 5;
+ if (bs->flagcarrier != -1) {
+ ClientName(bs->flagcarrier, carriername, sizeof(carriername));
+ for (i = 0; i < defenders; i++) {
+ //
+ if (teammates[i] == bs->flagcarrier) {
+ continue;
+ }
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ if (bs->flagcarrier == bs->client) {
+ if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
+ if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWME);
+ }
+ else {
+ if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
+ if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWFLAGCARRIER);
+ }
+ if (bot_nochat.integer<3)BotSayTeamOrder(bs, teammates[i]);
+ }
+ }
+ else {
+ for (i = 0; i < defenders; i++) {
+ //
+ if (teammates[i] == bs->flagcarrier) {
+ continue;
+ }
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_GETFLAG);
+ if (bot_nochat.integer<3)BotSayTeamOrder(bs, teammates[i]);
+ }
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ if (teammates[numteammates - i - 1] == bs->flagcarrier) {
+ continue;
+ }
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ if (bot_nochat.integer<3)BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_RETURNFLAG);
+ }
+ //
+ break;
+ }
+ }
+}
+
+/*
+==================
+BotCTFOrders
+==================
+*/
+void BotCTFOrders_FlagNotAtBase(bot_state_t *bs) {
+ int numteammates, defenders, attackers, i;
+ int teammates[MAX_CLIENTS];
+ char name[MAX_NETNAME];
+ qboolean weAreAttacking;
+
+ if (bot_nochat.integer>2) return;
+
+ numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
+ BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
+
+ weAreAttacking = qfalse;
+
+ //In oneway ctf we must all move out of the base (only one strategi, maybe we can also send some to the enemy base to meet the flag carier?)
+ //We must be defending
+ if(g_elimination_ctf_oneway.integer > 0) {
+ for (i = 0; i < numteammates; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_GETFLAG);
+ }
+ return;
+ }
+
+ //passive strategy
+ if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
+ //different orders based on the number of team mates
+ switch(bs->numteammates) {
+ case 1: break;
+ case 2:
+ {
+ // keep one near the base for when the flag is returned
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
+ break;
+ }
+ case 3:
+ {
+ //keep one near the base for when the flag is returned
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the other two get the flag
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
+ //
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
+ break;
+ }
+ default:
+ {
+ //keep some people near the base for when the flag is returned
+ defenders = (int) (float) numteammates * 0.3 + 0.5;
+ if (defenders > 3) defenders = 3;
+ attackers = (int) (float) numteammates * 0.6 + 0.5;
+ if (attackers > 6) attackers = 6;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
+ }
+ //
+ break;
+ }
+ }
+ }
+ else {
+ //different orders based on the number of team mates
+ switch(bs->numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //both will go for the enemy flag
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
+ //
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
+ break;
+ }
+ case 3:
+ {
+ //everyone go for the flag
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
+ //
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
+ //
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
+ break;
+ }
+ default:
+ {
+ //keep some people near the base for when the flag is returned
+ defenders = (int) (float) numteammates * 0.2 + 0.5;
+ if (defenders > 2) defenders = 2;
+ attackers = (int) (float) numteammates * 0.7 + 0.5;
+ if (attackers > 7) attackers = 7;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
+ }
+ //
+ break;
+ }
+ }
+ }
+}
+
+/*
+==================
+BotCTFOrders
+==================
+*/
+void BotCTFOrders_EnemyFlagNotAtBase(bot_state_t *bs) {
+ int numteammates, defenders, attackers, i, other;
+ int teammates[MAX_CLIENTS];
+ char name[MAX_NETNAME], carriername[MAX_NETNAME];
+
+ if (bot_nochat.integer>2) return;
+
+ numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
+ BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //tell the one not carrying the flag to defend the base
+ if (teammates[0] == bs->flagcarrier) other = teammates[1];
+ else other = teammates[0];
+ ClientName(other, name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, other);
+ BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
+ break;
+ }
+ case 3:
+ {
+ //tell the one closest to the base not carrying the flag to defend the base
+ if (teammates[0] != bs->flagcarrier) other = teammates[0];
+ else other = teammates[1];
+ ClientName(other, name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, other);
+ BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
+ //tell the other also to defend the base
+ if (teammates[2] != bs->flagcarrier) other = teammates[2];
+ else other = teammates[1];
+ ClientName(other, name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, other);
+ BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
+ break;
+ }
+ default:
+ {
+ //60% will defend the base
+ defenders = (int) (float) numteammates * 0.6 + 0.5;
+ if (defenders > 6) defenders = 6;
+ //30% accompanies the flag carrier
+ attackers = (int) (float) numteammates * 0.3 + 0.5;
+ if (attackers > 3) attackers = 3;
+ for (i = 0; i < defenders; i++) {
+ //
+ if (teammates[i] == bs->flagcarrier) {
+ continue;
+ }
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ // if we have a flag carrier
+ if ( bs->flagcarrier != -1 ) {
+ ClientName(bs->flagcarrier, carriername, sizeof(carriername));
+ for (i = 0; i < attackers; i++) {
+ //
+ if (teammates[numteammates - i - 1] == bs->flagcarrier) {
+ continue;
+ }
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ if (bs->flagcarrier == bs->client) {
+ BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
+ }
+ else {
+ BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
+ }
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ }
+ }
+ else {
+ for (i = 0; i < attackers; i++) {
+ //
+ if (teammates[numteammates - i - 1] == bs->flagcarrier) {
+ continue;
+ }
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ }
+ }
+ //
+ break;
+ }
+ }
+}
+
+/*
+==================
+BotDDorders
+==================
+*/
+
+void BotDDorders_Standard(bot_state_t *bs) {
+ int numteammates, i;
+ int teammates[MAX_CLIENTS];
+ char name[MAX_NETNAME];
+
+ if (bot_nochat.integer>2) return;
+
+ //sort team mates by travel time to base
+ numteammates = BotSortTeamMatesByRelativeTravelTime2ddA(bs, teammates, sizeof(teammates));
+
+ switch(numteammates) {
+ case 1: break;
+ /*case 2:
+ {
+ //the one closest to point A will take that
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_takea", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ //BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_TAKEA);
+ //the other goes for point B
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_takeb", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ //BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_TAKEB);
+ break;
+ }*/
+ default:
+ {
+ for(i=0;i<numteammates/2;i++) { //Half take point A
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_takea", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ //BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_TAKEA);
+ }
+ for(i=numteammates/2+1;i<numteammates;i++) { //Rest takes point B
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_takeb", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ //BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_TAKEB);
+ }
+ break;
+ }
+ }
+}
+
+/*
+==================
+BotCTFOrders
+==================
+*/
+void BotCTFOrders_BothFlagsAtBase(bot_state_t *bs) {
+ int numteammates, defenders, attackers, i;
+ int teammates[MAX_CLIENTS];
+ char name[MAX_NETNAME];
+ qboolean weAreAttacking;
+
+ if (bot_nochat.integer>2) return;
+
+ //sort team mates by travel time to base
+ numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
+ //sort team mates by CTF preference
+ BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
+
+ weAreAttacking = qfalse;
+
+ if(g_elimination_ctf_oneway.integer > 0) {
+ //See if we are attacking:
+ if( ( (level.eliminationSides+level.roundNumber)%2 == 0 ) && (BotTeam(bs) == TEAM_RED))
+ weAreAttacking = qtrue;
+
+ if(weAreAttacking) {
+ for (i = 0; i < numteammates; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_GETFLAG);
+ }
+ } else {
+ for (i = 0; i < numteammates; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ }
+ return; //Sago: Or the leader will make a counter order.
+ }
+
+ //passive strategy
+ if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the other will get the flag
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
+ break;
+ }
+ case 3:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the second one closest to the base will defend the base
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
+ //the other will get the flag
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
+ break;
+ }
+ default:
+ {
+ defenders = (int) (float) numteammates * 0.5 + 0.5;
+ if (defenders > 5) defenders = 5;
+ attackers = (int) (float) numteammates * 0.4 + 0.5;
+ if (attackers > 4) attackers = 4;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
+ }
+ //
+ break;
+ }
+ }
+ }
+ else {
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the other will get the flag
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
+ break;
+ }
+ case 3:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the others should go for the enemy flag
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
+ //
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
+ break;
+ }
+ default:
+ {
+ defenders = (int) (float) numteammates * 0.4 + 0.5;
+ if (defenders > 4) defenders = 4;
+ attackers = (int) (float) numteammates * 0.5 + 0.5;
+ if (attackers > 5) attackers = 5;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
+ }
+ //
+ break;
+ }
+ }
+ }
+}
+
+/*
+==================
+BotCTFOrders
+==================
+*/
+void BotCTFOrders(bot_state_t *bs) {
+ int flagstatus;
+
+ //
+ if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus;
+ else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus;
+ //
+ switch(flagstatus) {
+ case 0: BotCTFOrders_BothFlagsAtBase(bs); break;
+ case 1: BotCTFOrders_EnemyFlagNotAtBase(bs); break;
+ case 2: BotCTFOrders_FlagNotAtBase(bs); break;
+ case 3: BotCTFOrders_BothFlagsNotAtBase(bs); break;
+ }
+}
+
+/*
+==================
+BotDDorders
+==================
+*/
+void BotDDorders(bot_state_t *bs) {
+ BotDDorders_Standard(bs);
+}
+
+
+/*
+==================
+BotCreateGroup
+==================
+*/
+void BotCreateGroup(bot_state_t *bs, int *teammates, int groupsize) {
+ char name[MAX_NETNAME], leadername[MAX_NETNAME];
+ int i;
+
+ if (bot_nochat.integer>2) return;
+
+ // the others in the group will follow the teammates[0]
+ ClientName(teammates[0], leadername, sizeof(leadername));
+ for (i = 1; i < groupsize; i++)
+ {
+ ClientName(teammates[i], name, sizeof(name));
+ if (teammates[0] == bs->client) {
+ BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
+ }
+ else {
+ BotAI_BotInitialChat(bs, "cmd_accompany", name, leadername, NULL);
+ }
+ BotSayTeamOrderAlways(bs, teammates[i]);
+ }
+}
+
+/*
+==================
+BotTeamOrders
+
+ FIXME: defend key areas?
+==================
+*/
+void BotTeamOrders(bot_state_t *bs) {
+ int teammates[MAX_CLIENTS];
+ int numteammates, i;
+ char buf[MAX_INFO_STRING];
+ static int maxclients;
+
+ if (!maxclients)
+ maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
+
+ numteammates = 0;
+ for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
+ trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
+ //if no config string or no name
+ if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
+ //skip spectators
+ if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
+ //
+ if (BotSameTeam(bs, i)) {
+ teammates[numteammates] = i;
+ numteammates++;
+ }
+ }
+ //
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //nothing special
+ break;
+ }
+ case 3:
+ {
+ //have one follow another and one free roaming
+ BotCreateGroup(bs, teammates, 2);
+ break;
+ }
+ case 4:
+ {
+ BotCreateGroup(bs, teammates, 2); //a group of 2
+ BotCreateGroup(bs, &teammates[2], 2); //a group of 2
+ break;
+ }
+ case 5:
+ {
+ BotCreateGroup(bs, teammates, 2); //a group of 2
+ BotCreateGroup(bs, &teammates[2], 3); //a group of 3
+ break;
+ }
+ default:
+ {
+ if (numteammates <= 10) {
+ for (i = 0; i < numteammates / 2; i++) {
+ BotCreateGroup(bs, &teammates[i*2], 2); //groups of 2
+ }
+ }
+ break;
+ }
+ }
+}
+
+/*
+==================
+Bot1FCTFOrders_FlagAtCenter
+
+ X% defend the base, Y% get the flag
+==================
+*/
+void Bot1FCTFOrders_FlagAtCenter(bot_state_t *bs) {
+ int numteammates, defenders, attackers, i;
+ int teammates[MAX_CLIENTS];
+ char name[MAX_NETNAME];
+
+ if (bot_nochat.integer>2) return;
+
+ //sort team mates by travel time to base
+ numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
+ //sort team mates by CTF preference
+ BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
+ //passive strategy
+ if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the other will get the flag
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
+ break;
+ }
+ case 3:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the second one closest to the base will defend the base
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the other will get the flag
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
+ break;
+ }
+ default:
+ {
+ //50% defend the base
+ defenders = (int) (float) numteammates * 0.5 + 0.5;
+ if (defenders > 5) defenders = 5;
+ //40% get the flag
+ attackers = (int) (float) numteammates * 0.4 + 0.5;
+ if (attackers > 4) attackers = 4;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
+ }
+ //
+ break;
+ }
+ }
+ }
+ else { //agressive
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the other will get the flag
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
+ break;
+ }
+ case 3:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the others should go for the enemy flag
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
+ //
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
+ break;
+ }
+ default:
+ {
+ //30% defend the base
+ defenders = (int) (float) numteammates * 0.3 + 0.5;
+ if (defenders > 3) defenders = 3;
+ //60% get the flag
+ attackers = (int) (float) numteammates * 0.6 + 0.5;
+ if (attackers > 6) attackers = 6;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
+ }
+ //
+ break;
+ }
+ }
+ }
+}
+
+/*
+==================
+Bot1FCTFOrders_TeamHasFlag
+
+ X% towards neutral flag, Y% go towards enemy base and accompany flag carrier if visible
+==================
+*/
+void Bot1FCTFOrders_TeamHasFlag(bot_state_t *bs) {
+ int numteammates, defenders, attackers, i, other;
+ int teammates[MAX_CLIENTS];
+ char name[MAX_NETNAME], carriername[MAX_NETNAME];
+
+ if (bot_nochat.integer>2) return;
+
+ //sort team mates by travel time to base
+ numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
+ //sort team mates by CTF preference
+ BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
+ //passive strategy
+ if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //tell the one not carrying the flag to attack the enemy base
+ if (teammates[0] == bs->flagcarrier) other = teammates[1];
+ else other = teammates[0];
+ ClientName(other, name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
+ BotSayTeamOrder(bs, other);
+ BotSayVoiceTeamOrder(bs, other, VOICECHAT_OFFENSE);
+ break;
+ }
+ case 3:
+ {
+ //tell the one closest to the base not carrying the flag to defend the base
+ if (teammates[0] != bs->flagcarrier) other = teammates[0];
+ else other = teammates[1];
+ ClientName(other, name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, other);
+ BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
+ //tell the one furthest from the base not carrying the flag to accompany the flag carrier
+ if (teammates[2] != bs->flagcarrier) other = teammates[2];
+ else other = teammates[1];
+ ClientName(other, name, sizeof(name));
+ if ( bs->flagcarrier != -1 ) {
+ ClientName(bs->flagcarrier, carriername, sizeof(carriername));
+ if (bs->flagcarrier == bs->client) {
+ BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
+ BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
+ }
+ else {
+ BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
+ BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
+ }
+ }
+ else {
+ //
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
+ }
+ BotSayTeamOrder(bs, other);
+ break;
+ }
+ default:
+ {
+ //30% will defend the base
+ defenders = (int) (float) numteammates * 0.3 + 0.5;
+ if (defenders > 3) defenders = 3;
+ //70% accompanies the flag carrier
+ attackers = (int) (float) numteammates * 0.7 + 0.5;
+ if (attackers > 7) attackers = 7;
+ for (i = 0; i < defenders; i++) {
+ //
+ if (teammates[i] == bs->flagcarrier) {
+ continue;
+ }
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ if (bs->flagcarrier != -1) {
+ ClientName(bs->flagcarrier, carriername, sizeof(carriername));
+ for (i = 0; i < attackers; i++) {
+ //
+ if (teammates[numteammates - i - 1] == bs->flagcarrier) {
+ continue;
+ }
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ if (bs->flagcarrier == bs->client) {
+ BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
+ }
+ else {
+ BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
+ }
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ }
+ }
+ else {
+ for (i = 0; i < attackers; i++) {
+ //
+ if (teammates[numteammates - i - 1] == bs->flagcarrier) {
+ continue;
+ }
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
+ }
+ }
+ //
+ break;
+ }
+ }
+ }
+ else { //agressive
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //tell the one not carrying the flag to defend the base
+ if (teammates[0] == bs->flagcarrier) other = teammates[1];
+ else other = teammates[0];
+ ClientName(other, name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, other);
+ BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
+ break;
+ }
+ case 3:
+ {
+ //tell the one closest to the base not carrying the flag to defend the base
+ if (teammates[0] != bs->flagcarrier) other = teammates[0];
+ else other = teammates[1];
+ ClientName(other, name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, other);
+ BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
+ //tell the one furthest from the base not carrying the flag to accompany the flag carrier
+ if (teammates[2] != bs->flagcarrier) other = teammates[2];
+ else other = teammates[1];
+ ClientName(other, name, sizeof(name));
+ ClientName(bs->flagcarrier, carriername, sizeof(carriername));
+ if (bs->flagcarrier == bs->client) {
+ BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
+ BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
+ }
+ else {
+ BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
+ BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
+ }
+ BotSayTeamOrder(bs, other);
+ break;
+ }
+ default:
+ {
+ //20% will defend the base
+ defenders = (int) (float) numteammates * 0.2 + 0.5;
+ if (defenders > 2) defenders = 2;
+ //80% accompanies the flag carrier
+ attackers = (int) (float) numteammates * 0.8 + 0.5;
+ if (attackers > 8) attackers = 8;
+ for (i = 0; i < defenders; i++) {
+ //
+ if (teammates[i] == bs->flagcarrier) {
+ continue;
+ }
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ ClientName(bs->flagcarrier, carriername, sizeof(carriername));
+ for (i = 0; i < attackers; i++) {
+ //
+ if (teammates[numteammates - i - 1] == bs->flagcarrier) {
+ continue;
+ }
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ if (bs->flagcarrier == bs->client) {
+ BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
+ }
+ else {
+ BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
+ }
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ }
+ //
+ break;
+ }
+ }
+ }
+}
+
+/*
+==================
+Bot1FCTFOrders_EnemyHasFlag
+
+ X% defend the base, Y% towards neutral flag
+==================
+*/
+void Bot1FCTFOrders_EnemyHasFlag(bot_state_t *bs) {
+ int numteammates, defenders, attackers, i;
+ int teammates[MAX_CLIENTS];
+ char name[MAX_NETNAME];
+
+ if (bot_nochat.integer>2) return;
+
+ //sort team mates by travel time to base
+ numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
+ //sort team mates by CTF preference
+ BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
+ //passive strategy
+ if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //both defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
+ break;
+ }
+ case 3:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the second one closest to the base will defend the base
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
+ //the other will also defend the base
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_DEFEND);
+ break;
+ }
+ default:
+ {
+ //80% will defend the base
+ defenders = (int) (float) numteammates * 0.8 + 0.5;
+ if (defenders > 8) defenders = 8;
+ //10% will try to return the flag
+ attackers = (int) (float) numteammates * 0.1 + 0.5;
+ if (attackers > 1) attackers = 1;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
+ }
+ //
+ break;
+ }
+ }
+ }
+ else { //agressive
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the other will get the flag
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
+ break;
+ }
+ case 3:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the others should go for the enemy flag
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
+ //
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
+ break;
+ }
+ default:
+ {
+ //70% defend the base
+ defenders = (int) (float) numteammates * 0.7 + 0.5;
+ if (defenders > 7) defenders = 7;
+ //20% try to return the flag
+ attackers = (int) (float) numteammates * 0.2 + 0.5;
+ if (attackers > 2) attackers = 2;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
+ }
+ //
+ break;
+ }
+ }
+ }
+}
+
+/*
+==================
+Bot1FCTFOrders_EnemyDroppedFlag
+
+ X% defend the base, Y% get the flag
+==================
+*/
+void Bot1FCTFOrders_EnemyDroppedFlag(bot_state_t *bs) {
+ int numteammates, defenders, attackers, i;
+ int teammates[MAX_CLIENTS];
+ char name[MAX_NETNAME];
+
+ if (bot_nochat.integer>2) return;
+
+ //sort team mates by travel time to base
+ numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
+ //sort team mates by CTF preference
+ BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
+ //passive strategy
+ if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the other will get the flag
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
+ break;
+ }
+ case 3:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the second one closest to the base will defend the base
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
+ //the other will get the flag
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
+ break;
+ }
+ default:
+ {
+ //50% defend the base
+ defenders = (int) (float) numteammates * 0.5 + 0.5;
+ if (defenders > 5) defenders = 5;
+ //40% get the flag
+ attackers = (int) (float) numteammates * 0.4 + 0.5;
+ if (attackers > 4) attackers = 4;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
+ }
+ //
+ break;
+ }
+ }
+ }
+ else { //agressive
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the other will get the flag
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
+ break;
+ }
+ case 3:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the others should go for the enemy flag
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
+ //
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
+ break;
+ }
+ default:
+ {
+ //30% defend the base
+ defenders = (int) (float) numteammates * 0.3 + 0.5;
+ if (defenders > 3) defenders = 3;
+ //60% get the flag
+ attackers = (int) (float) numteammates * 0.6 + 0.5;
+ if (attackers > 6) attackers = 6;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
+ }
+ //
+ break;
+ }
+ }
+ }
+}
+
+/*
+==================
+Bot1FCTFOrders
+==================
+*/
+void Bot1FCTFOrders(bot_state_t *bs) {
+ switch(bs->neutralflagstatus) {
+ case 0: Bot1FCTFOrders_FlagAtCenter(bs); break;
+ case 1: Bot1FCTFOrders_TeamHasFlag(bs); break;
+ case 2: Bot1FCTFOrders_EnemyHasFlag(bs); break;
+ case 3: Bot1FCTFOrders_EnemyDroppedFlag(bs); break;
+ }
+}
+
+/*
+==================
+BotObeliskOrders
+
+ X% in defence Y% in offence
+==================
+*/
+void BotObeliskOrders(bot_state_t *bs) {
+ int numteammates, defenders, attackers, i;
+ int teammates[MAX_CLIENTS];
+ char name[MAX_NETNAME];
+
+ if (bot_nochat.integer>2) return;
+
+ //sort team mates by travel time to base
+ numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
+ //sort team mates by CTF preference
+ BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
+ //passive strategy
+ if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the other will attack the enemy base
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
+ break;
+ }
+ case 3:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the one second closest to the base also defends the base
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
+ //the other one attacks the enemy base
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
+ break;
+ }
+ default:
+ {
+ //50% defend the base
+ defenders = (int) (float) numteammates * 0.5 + 0.5;
+ if (defenders > 5) defenders = 5;
+ //40% attack the enemy base
+ attackers = (int) (float) numteammates * 0.4 + 0.5;
+ if (attackers > 4) attackers = 4;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
+ }
+ //
+ break;
+ }
+ }
+ }
+ else {
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the other will attack the enemy base
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
+ break;
+ }
+ case 3:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the others attack the enemy base
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
+ //
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
+ break;
+ }
+ default:
+ {
+ //30% defend the base
+ defenders = (int) (float) numteammates * 0.3 + 0.5;
+ if (defenders > 3) defenders = 3;
+ //70% attack the enemy base
+ attackers = (int) (float) numteammates * 0.7 + 0.5;
+ if (attackers > 7) attackers = 7;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
+ }
+ //
+ break;
+ }
+ }
+ }
+}
+
+/*
+==================
+BotHarvesterOrders
+
+ X% defend the base, Y% harvest
+==================
+*/
+void BotHarvesterOrders(bot_state_t *bs) {
+ int numteammates, defenders, attackers, i;
+ int teammates[MAX_CLIENTS];
+ char name[MAX_NETNAME];
+
+ if (bot_nochat.integer>2) return;
+
+ //sort team mates by travel time to base
+ numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
+ //sort team mates by CTF preference
+ BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
+ //passive strategy
+ if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the other will harvest
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
+ break;
+ }
+ case 3:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the one second closest to the base also defends the base
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
+ //the other one goes harvesting
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
+ break;
+ }
+ default:
+ {
+ //50% defend the base
+ defenders = (int) (float) numteammates * 0.5 + 0.5;
+ if (defenders > 5) defenders = 5;
+ //40% goes harvesting
+ attackers = (int) (float) numteammates * 0.4 + 0.5;
+ if (attackers > 4) attackers = 4;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
+ }
+ //
+ break;
+ }
+ }
+ }
+ else {
+ //different orders based on the number of team mates
+ switch(numteammates) {
+ case 1: break;
+ case 2:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the other will harvest
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
+ break;
+ }
+ case 3:
+ {
+ //the one closest to the base will defend the base
+ ClientName(teammates[0], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[0]);
+ BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
+ //the others go harvesting
+ ClientName(teammates[1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
+ BotSayTeamOrder(bs, teammates[1]);
+ BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
+ //
+ ClientName(teammates[2], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
+ BotSayTeamOrder(bs, teammates[2]);
+ BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
+ break;
+ }
+ default:
+ {
+ //30% defend the base
+ defenders = (int) (float) numteammates * 0.3 + 0.5;
+ if (defenders > 3) defenders = 3;
+ //70% go harvesting
+ attackers = (int) (float) numteammates * 0.7 + 0.5;
+ if (attackers > 7) attackers = 7;
+ for (i = 0; i < defenders; i++) {
+ //
+ ClientName(teammates[i], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
+ BotSayTeamOrder(bs, teammates[i]);
+ BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
+ }
+ for (i = 0; i < attackers; i++) {
+ //
+ ClientName(teammates[numteammates - i - 1], name, sizeof(name));
+ BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
+ BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
+ BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
+ }
+ //
+ break;
+ }
+ }
+ }
+}
+
+/*
+==================
+FindHumanTeamLeader
+==================
+*/
+int FindHumanTeamLeader(bot_state_t *bs) {
+ int i;
+
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ if ( g_entities[i].inuse ) {
+ // if this player is not a bot
+ if ( !(g_entities[i].r.svFlags & SVF_BOT) ) {
+ // if this player is ok with being the leader
+ if (!notleader[i]) {
+ // if this player is on the same team
+ if ( BotSameTeam(bs, i) ) {
+ ClientName(i, bs->teamleader, sizeof(bs->teamleader));
+ // if not yet ordered to do anything
+ if ( !BotSetLastOrderedTask(bs) ) {
+ // go on defense by default
+ if (bot_nochat.integer<3)BotVoiceChat_Defend(bs, i, SAY_TELL);
+ }
+ return qtrue;
+ }
+ }
+ }
+ }
+ }
+ return qfalse;
+}
+
+int lastRoundNumber; //used to give new orders every round
+
+/*
+==================
+BotTeamAI
+==================
+*/
+void BotTeamAI(bot_state_t *bs) {
+ int numteammates;
+ char netname[MAX_NETNAME];
+
+ if (bot_nochat.integer>2) return;
+
+ //
+ if ( gametype < GT_TEAM || g_ffa_gt == 1 )
+ return;
+ // make sure we've got a valid team leader
+ if (!BotValidTeamLeader(bs)) {
+ //
+ if (!FindHumanTeamLeader(bs)) {
+ //
+ if (!bs->askteamleader_time && !bs->becometeamleader_time) {
+ if (bs->entergame_time + 10 > FloatTime()) {
+ bs->askteamleader_time = FloatTime() + 5 + random() * 10;
+ }
+ else {
+ bs->becometeamleader_time = FloatTime() + 5 + random() * 10;
+ }
+ }
+ if (bs->askteamleader_time && bs->askteamleader_time < FloatTime()) {
+ // if asked for a team leader and no response
+ BotAI_BotInitialChat(bs, "whoisteamleader", NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ bs->askteamleader_time = 0;
+ bs->becometeamleader_time = FloatTime() + 8 + random() * 10;
+ }
+ if (bs->becometeamleader_time && bs->becometeamleader_time < FloatTime()) {
+ BotAI_BotInitialChat(bs, "iamteamleader", NULL);
+ trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
+ BotSayVoiceTeamOrder(bs, -1, VOICECHAT_STARTLEADER);
+ ClientName(bs->client, netname, sizeof(netname));
+ strncpy(bs->teamleader, netname, sizeof(bs->teamleader));
+ bs->teamleader[sizeof(bs->teamleader)-1] = '\0';
+ bs->becometeamleader_time = 0;
+ }
+ return;
+ }
+ }
+ bs->askteamleader_time = 0;
+ bs->becometeamleader_time = 0;
+
+ //return if this bot is NOT the team leader
+ ClientName(bs->client, netname, sizeof(netname));
+ if (Q_stricmp(netname, bs->teamleader) != 0) return;
+ //
+ numteammates = BotNumTeamMates(bs);
+ //give orders
+ switch(gametype) {
+ case GT_TEAM:
+ {
+ if (bs->numteammates != numteammates || bs->forceorders) {
+ bs->teamgiveorders_time = FloatTime();
+ bs->numteammates = numteammates;
+ bs->forceorders = qfalse;
+ }
+ //if it's time to give orders
+ if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
+ BotTeamOrders(bs);
+ //give orders again after 120 seconds
+ bs->teamgiveorders_time = FloatTime() + 120;
+ }
+ break;
+ }
+ case GT_CTF:
+ case GT_CTF_ELIMINATION:
+ {
+ //if the number of team mates changed or the flag status changed
+ //or someone wants to know what to do
+ if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders || lastRoundNumber != level.roundNumber) {
+ bs->teamgiveorders_time = FloatTime();
+ bs->numteammates = numteammates;
+ bs->flagstatuschanged = qfalse;
+ bs->forceorders = qfalse;
+ lastRoundNumber = level.roundNumber;
+ }
+ //if there were no flag captures the last 3 minutes
+ if (bs->lastflagcapture_time < FloatTime() - 240) {
+ bs->lastflagcapture_time = FloatTime();
+ //randomly change the CTF strategy
+ if (random() < 0.4) {
+ bs->ctfstrategy ^= CTFS_AGRESSIVE;
+ bs->teamgiveorders_time = FloatTime();
+ }
+ }
+ //if it's time to give orders
+ if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 3) {
+ BotCTFOrders(bs);
+ //
+ bs->teamgiveorders_time = 0;
+ }
+ break;
+ }
+ case GT_DOUBLE_D:
+ {
+ //if the number of team mates changed or the domination point status changed
+ //or someone wants to know what to do
+ if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) {
+ bs->teamgiveorders_time = FloatTime();
+ bs->numteammates = numteammates;
+ bs->flagstatuschanged = qfalse;
+ bs->forceorders = qfalse;
+ }
+ //if it's time to give orders
+ if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 3) {
+ BotDDorders(bs);
+ //
+ bs->teamgiveorders_time = 0;
+ }
+ break;
+ }
+ case GT_1FCTF:
+ {
+ if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) {
+ bs->teamgiveorders_time = FloatTime();
+ bs->numteammates = numteammates;
+ bs->flagstatuschanged = qfalse;
+ bs->forceorders = qfalse;
+ }
+ //if there were no flag captures the last 4 minutes
+ if (bs->lastflagcapture_time < FloatTime() - 240) {
+ bs->lastflagcapture_time = FloatTime();
+ //randomly change the CTF strategy
+ if (random() < 0.4) {
+ bs->ctfstrategy ^= CTFS_AGRESSIVE;
+ bs->teamgiveorders_time = FloatTime();
+ }
+ }
+ //if it's time to give orders
+ if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 2) {
+ Bot1FCTFOrders(bs);
+ //
+ bs->teamgiveorders_time = 0;
+ }
+ break;
+ }
+ case GT_OBELISK:
+ {
+ if (bs->numteammates != numteammates || bs->forceorders) {
+ bs->teamgiveorders_time = FloatTime();
+ bs->numteammates = numteammates;
+ bs->forceorders = qfalse;
+ }
+ //if it's time to give orders
+ if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
+ BotObeliskOrders(bs);
+ //give orders again after 30 seconds
+ bs->teamgiveorders_time = FloatTime() + 30;
+ }
+ break;
+ }
+ case GT_HARVESTER:
+ {
+ if (bs->numteammates != numteammates || bs->forceorders) {
+ bs->teamgiveorders_time = FloatTime();
+ bs->numteammates = numteammates;
+ bs->forceorders = qfalse;
+ }
+ //if it's time to give orders
+ if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
+ BotHarvesterOrders(bs);
+ //give orders again after 30 seconds
+ bs->teamgiveorders_time = FloatTime() + 30;
+ }
+ break;
+ }
+ }
+}
+
diff --git a/engine/code/game/ai_team.h b/code/game/ai_team.h
similarity index 100%
rename from engine/code/game/ai_team.h
rename to code/game/ai_team.h
diff --git a/game/code/game/ai_vcmd.c b/code/game/ai_vcmd.c
similarity index 100%
rename from game/code/game/ai_vcmd.c
rename to code/game/ai_vcmd.c
diff --git a/engine/code/game/ai_vcmd.h b/code/game/ai_vcmd.h
similarity index 100%
rename from engine/code/game/ai_vcmd.h
rename to code/game/ai_vcmd.h
diff --git a/game/code/game/bg_alloc.c b/code/game/bg_alloc.c
similarity index 100%
rename from game/code/game/bg_alloc.c
rename to code/game/bg_alloc.c
diff --git a/code/game/bg_lib.c b/code/game/bg_lib.c
new file mode 100644
index 0000000..5b96cdd
--- /dev/null
+++ b/code/game/bg_lib.c
@@ -0,0 +1,2154 @@
+//
+//
+// bg_lib,c -- standard C library replacement routines used by code
+// compiled for the virtual machine
+
+#ifdef Q3_VM
+
+#include "../qcommon/q_shared.h"
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "bg_lib.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
+#endif
+static const char rcsid[] =
+#endif /* LIBC_SCCS and not lint */
+
+static char* med3(char *, char *, char *, cmp_t *);
+static void swapfunc(char *, char *, int, int);
+
+#ifndef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) { \
+ long i = (n) / sizeof (TYPE); \
+ register TYPE *pi = (TYPE *) (parmi); \
+ register TYPE *pj = (TYPE *) (parmj); \
+ do { \
+ register TYPE t = *pi; \
+ *pi++ = *pj; \
+ *pj++ = t; \
+ } while (--i > 0); \
+}
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+ es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+
+static void
+swapfunc(a, b, n, swaptype)
+ char *a, *b;
+ int n, swaptype;
+{
+ if(swaptype <= 1)
+ swapcode(long, a, b, n)
+ else
+ swapcode(char, a, b, n)
+}
+
+#define swap(a, b) \
+ if (swaptype == 0) { \
+ long t = *(long *)(a); \
+ *(long *)(a) = *(long *)(b); \
+ *(long *)(b) = t; \
+ } else \
+ swapfunc(a, b, es, swaptype)
+
+#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+static char *
+med3(a, b, c, cmp)
+ char *a, *b, *c;
+ cmp_t *cmp;
+{
+ return cmp(a, b) < 0 ?
+ (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
+ :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
+}
+
+void
+qsort(a, n, es, cmp)
+ void *a;
+ size_t n, es;
+ cmp_t *cmp;
+{
+ char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+ int d, r, swaptype, swap_cnt;
+
+loop: SWAPINIT(a, es);
+ swap_cnt = 0;
+ if (n < 7) {
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+ pm = (char *)a + (n / 2) * es;
+ if (n > 7) {
+ pl = a;
+ pn = (char *)a + (n - 1) * es;
+ if (n > 40) {
+ d = (n / 8) * es;
+ pl = med3(pl, pl + d, pl + 2 * d, cmp);
+ pm = med3(pm - d, pm, pm + d, cmp);
+ pn = med3(pn - 2 * d, pn - d, pn, cmp);
+ }
+ pm = med3(pl, pm, pn, cmp);
+ }
+ swap(a, pm);
+ pa = pb = (char *)a + es;
+
+ pc = pd = (char *)a + (n - 1) * es;
+ for (;;) {
+ while (pb <= pc && (r = cmp(pb, a)) <= 0) {
+ if (r == 0) {
+ swap_cnt = 1;
+ swap(pa, pb);
+ pa += es;
+ }
+ pb += es;
+ }
+ while (pb <= pc && (r = cmp(pc, a)) >= 0) {
+ if (r == 0) {
+ swap_cnt = 1;
+ swap(pc, pd);
+ pd -= es;
+ }
+ pc -= es;
+ }
+ if (pb > pc)
+ break;
+ swap(pb, pc);
+ swap_cnt = 1;
+ pb += es;
+ pc -= es;
+ }
+ if (swap_cnt == 0) { /* Switch to insertion sort */
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+
+ pn = (char *)a + n * es;
+ r = min(pa - (char *)a, pb - pa);
+ vecswap(a, pb - r, r);
+ r = min(pd - pc, pn - pd - es);
+ vecswap(pb, pn - r, r);
+ if ((r = pb - pa) > es)
+ qsort(a, r / es, es, cmp);
+ if ((r = pd - pc) > es) {
+ /* Iterate rather than recurse to save stack space */
+ a = pn - r;
+ n = r / es;
+ goto loop;
+ }
+/* qsort(pn - r, r / es, es, cmp);*/
+}
+
+//==================================================================================
+
+size_t strlen( const char *string ) {
+ const char *s;
+
+ s = string;
+ while ( *s ) {
+ s++;
+ }
+ return s - string;
+}
+
+
+char *strcat( char *strDestination, const char *strSource ) {
+ char *s;
+
+ s = strDestination;
+ while ( *s ) {
+ s++;
+ }
+ while ( *strSource ) {
+ *s++ = *strSource++;
+ }
+ *s = 0;
+ return strDestination;
+}
+
+char *strcpy( char *strDestination, const char *strSource ) {
+ char *s;
+
+ s = strDestination;
+ while ( *strSource ) {
+ *s++ = *strSource++;
+ }
+ *s = 0;
+ return strDestination;
+}
+
+
+int strcmp( const char *string1, const char *string2 ) {
+ while ( *string1 == *string2 && *string1 && *string2 ) {
+ string1++;
+ string2++;
+ }
+ return *string1 - *string2;
+}
+
+
+char *strchr( const char *string, int c ) {
+ while ( *string ) {
+ if ( *string == c ) {
+ return ( char * )string;
+ }
+ string++;
+ }
+ if(c)
+ return NULL;
+ else
+ return (char*) string;
+}
+
+char *strrchr(const char *string, int c)
+{
+ const char *found = NULL;
+
+ while(*string)
+ {
+ if(*string == c)
+ found = string;
+
+ string++;
+ }
+
+ if(c)
+ return (char *) found;
+ else
+ return (char *) string;
+}
+
+char *strstr( const char *string, const char *strCharSet ) {
+ while ( *string ) {
+ int i;
+
+ for ( i = 0 ; strCharSet[i] ; i++ ) {
+ if ( string[i] != strCharSet[i] ) {
+ break;
+ }
+ }
+ if ( !strCharSet[i] ) {
+ return (char *)string;
+ }
+ string++;
+ }
+ return (char *)0;
+}
+
+int tolower( int c ) {
+ if ( c >= 'A' && c <= 'Z' ) {
+ c += 'a' - 'A';
+ }
+ return c;
+}
+
+
+int toupper( int c ) {
+ if ( c >= 'a' && c <= 'z' ) {
+ c += 'A' - 'a';
+ }
+ return c;
+}
+
+void *memmove( void *dest, const void *src, size_t count ) {
+ int i;
+
+ if ( dest > src ) {
+ for ( i = count-1 ; i >= 0 ; i-- ) {
+ ((char *)dest)[i] = ((char *)src)[i];
+ }
+ } else {
+ for ( i = 0 ; i < count ; i++ ) {
+ ((char *)dest)[i] = ((char *)src)[i];
+ }
+ }
+ return dest;
+}
+
+
+#if 0
+
+double floor( double x ) {
+ return (int)(x + 0x40000000) - 0x40000000;
+}
+
+void *memset( void *dest, int c, size_t count ) {
+ while ( count-- ) {
+ ((char *)dest)[count] = c;
+ }
+ return dest;
+}
+
+void *memcpy( void *dest, const void *src, size_t count ) {
+ while ( count-- ) {
+ ((char *)dest)[count] = ((char *)src)[count];
+ }
+ return dest;
+}
+
+char *strncpy( char *strDest, const char *strSource, size_t count ) {
+ char *s;
+
+ s = strDest;
+ while ( *strSource && count ) {
+ *s++ = *strSource++;
+ count--;
+ }
+ while ( count-- ) {
+ *s++ = 0;
+ }
+ return strDest;
+}
+
+double sqrt( double x ) {
+ float y;
+ float delta;
+ float maxError;
+
+ if ( x <= 0 ) {
+ return 0;
+ }
+
+ // initial guess
+ y = x / 2;
+
+ // refine
+ maxError = x * 0.001;
+
+ do {
+ delta = ( y * y ) - x;
+ y -= delta / ( 2 * y );
+ } while ( delta > maxError || delta < -maxError );
+
+ return y;
+}
+
+
+float sintable[1024] = {
+0.000000,0.001534,0.003068,0.004602,0.006136,0.007670,0.009204,0.010738,
+0.012272,0.013805,0.015339,0.016873,0.018407,0.019940,0.021474,0.023008,
+0.024541,0.026075,0.027608,0.029142,0.030675,0.032208,0.033741,0.035274,
+0.036807,0.038340,0.039873,0.041406,0.042938,0.044471,0.046003,0.047535,
+0.049068,0.050600,0.052132,0.053664,0.055195,0.056727,0.058258,0.059790,
+0.061321,0.062852,0.064383,0.065913,0.067444,0.068974,0.070505,0.072035,
+0.073565,0.075094,0.076624,0.078153,0.079682,0.081211,0.082740,0.084269,
+0.085797,0.087326,0.088854,0.090381,0.091909,0.093436,0.094963,0.096490,
+0.098017,0.099544,0.101070,0.102596,0.104122,0.105647,0.107172,0.108697,
+0.110222,0.111747,0.113271,0.114795,0.116319,0.117842,0.119365,0.120888,
+0.122411,0.123933,0.125455,0.126977,0.128498,0.130019,0.131540,0.133061,
+0.134581,0.136101,0.137620,0.139139,0.140658,0.142177,0.143695,0.145213,
+0.146730,0.148248,0.149765,0.151281,0.152797,0.154313,0.155828,0.157343,
+0.158858,0.160372,0.161886,0.163400,0.164913,0.166426,0.167938,0.169450,
+0.170962,0.172473,0.173984,0.175494,0.177004,0.178514,0.180023,0.181532,
+0.183040,0.184548,0.186055,0.187562,0.189069,0.190575,0.192080,0.193586,
+0.195090,0.196595,0.198098,0.199602,0.201105,0.202607,0.204109,0.205610,
+0.207111,0.208612,0.210112,0.211611,0.213110,0.214609,0.216107,0.217604,
+0.219101,0.220598,0.222094,0.223589,0.225084,0.226578,0.228072,0.229565,
+0.231058,0.232550,0.234042,0.235533,0.237024,0.238514,0.240003,0.241492,
+0.242980,0.244468,0.245955,0.247442,0.248928,0.250413,0.251898,0.253382,
+0.254866,0.256349,0.257831,0.259313,0.260794,0.262275,0.263755,0.265234,
+0.266713,0.268191,0.269668,0.271145,0.272621,0.274097,0.275572,0.277046,
+0.278520,0.279993,0.281465,0.282937,0.284408,0.285878,0.287347,0.288816,
+0.290285,0.291752,0.293219,0.294685,0.296151,0.297616,0.299080,0.300543,
+0.302006,0.303468,0.304929,0.306390,0.307850,0.309309,0.310767,0.312225,
+0.313682,0.315138,0.316593,0.318048,0.319502,0.320955,0.322408,0.323859,
+0.325310,0.326760,0.328210,0.329658,0.331106,0.332553,0.334000,0.335445,
+0.336890,0.338334,0.339777,0.341219,0.342661,0.344101,0.345541,0.346980,
+0.348419,0.349856,0.351293,0.352729,0.354164,0.355598,0.357031,0.358463,
+0.359895,0.361326,0.362756,0.364185,0.365613,0.367040,0.368467,0.369892,
+0.371317,0.372741,0.374164,0.375586,0.377007,0.378428,0.379847,0.381266,
+0.382683,0.384100,0.385516,0.386931,0.388345,0.389758,0.391170,0.392582,
+0.393992,0.395401,0.396810,0.398218,0.399624,0.401030,0.402435,0.403838,
+0.405241,0.406643,0.408044,0.409444,0.410843,0.412241,0.413638,0.415034,
+0.416430,0.417824,0.419217,0.420609,0.422000,0.423390,0.424780,0.426168,
+0.427555,0.428941,0.430326,0.431711,0.433094,0.434476,0.435857,0.437237,
+0.438616,0.439994,0.441371,0.442747,0.444122,0.445496,0.446869,0.448241,
+0.449611,0.450981,0.452350,0.453717,0.455084,0.456449,0.457813,0.459177,
+0.460539,0.461900,0.463260,0.464619,0.465976,0.467333,0.468689,0.470043,
+0.471397,0.472749,0.474100,0.475450,0.476799,0.478147,0.479494,0.480839,
+0.482184,0.483527,0.484869,0.486210,0.487550,0.488889,0.490226,0.491563,
+0.492898,0.494232,0.495565,0.496897,0.498228,0.499557,0.500885,0.502212,
+0.503538,0.504863,0.506187,0.507509,0.508830,0.510150,0.511469,0.512786,
+0.514103,0.515418,0.516732,0.518045,0.519356,0.520666,0.521975,0.523283,
+0.524590,0.525895,0.527199,0.528502,0.529804,0.531104,0.532403,0.533701,
+0.534998,0.536293,0.537587,0.538880,0.540171,0.541462,0.542751,0.544039,
+0.545325,0.546610,0.547894,0.549177,0.550458,0.551738,0.553017,0.554294,
+0.555570,0.556845,0.558119,0.559391,0.560662,0.561931,0.563199,0.564466,
+0.565732,0.566996,0.568259,0.569521,0.570781,0.572040,0.573297,0.574553,
+0.575808,0.577062,0.578314,0.579565,0.580814,0.582062,0.583309,0.584554,
+0.585798,0.587040,0.588282,0.589521,0.590760,0.591997,0.593232,0.594466,
+0.595699,0.596931,0.598161,0.599389,0.600616,0.601842,0.603067,0.604290,
+0.605511,0.606731,0.607950,0.609167,0.610383,0.611597,0.612810,0.614022,
+0.615232,0.616440,0.617647,0.618853,0.620057,0.621260,0.622461,0.623661,
+0.624859,0.626056,0.627252,0.628446,0.629638,0.630829,0.632019,0.633207,
+0.634393,0.635578,0.636762,0.637944,0.639124,0.640303,0.641481,0.642657,
+0.643832,0.645005,0.646176,0.647346,0.648514,0.649681,0.650847,0.652011,
+0.653173,0.654334,0.655493,0.656651,0.657807,0.658961,0.660114,0.661266,
+0.662416,0.663564,0.664711,0.665856,0.667000,0.668142,0.669283,0.670422,
+0.671559,0.672695,0.673829,0.674962,0.676093,0.677222,0.678350,0.679476,
+0.680601,0.681724,0.682846,0.683965,0.685084,0.686200,0.687315,0.688429,
+0.689541,0.690651,0.691759,0.692866,0.693971,0.695075,0.696177,0.697278,
+0.698376,0.699473,0.700569,0.701663,0.702755,0.703845,0.704934,0.706021,
+0.707107,0.708191,0.709273,0.710353,0.711432,0.712509,0.713585,0.714659,
+0.715731,0.716801,0.717870,0.718937,0.720003,0.721066,0.722128,0.723188,
+0.724247,0.725304,0.726359,0.727413,0.728464,0.729514,0.730563,0.731609,
+0.732654,0.733697,0.734739,0.735779,0.736817,0.737853,0.738887,0.739920,
+0.740951,0.741980,0.743008,0.744034,0.745058,0.746080,0.747101,0.748119,
+0.749136,0.750152,0.751165,0.752177,0.753187,0.754195,0.755201,0.756206,
+0.757209,0.758210,0.759209,0.760207,0.761202,0.762196,0.763188,0.764179,
+0.765167,0.766154,0.767139,0.768122,0.769103,0.770083,0.771061,0.772036,
+0.773010,0.773983,0.774953,0.775922,0.776888,0.777853,0.778817,0.779778,
+0.780737,0.781695,0.782651,0.783605,0.784557,0.785507,0.786455,0.787402,
+0.788346,0.789289,0.790230,0.791169,0.792107,0.793042,0.793975,0.794907,
+0.795837,0.796765,0.797691,0.798615,0.799537,0.800458,0.801376,0.802293,
+0.803208,0.804120,0.805031,0.805940,0.806848,0.807753,0.808656,0.809558,
+0.810457,0.811355,0.812251,0.813144,0.814036,0.814926,0.815814,0.816701,
+0.817585,0.818467,0.819348,0.820226,0.821103,0.821977,0.822850,0.823721,
+0.824589,0.825456,0.826321,0.827184,0.828045,0.828904,0.829761,0.830616,
+0.831470,0.832321,0.833170,0.834018,0.834863,0.835706,0.836548,0.837387,
+0.838225,0.839060,0.839894,0.840725,0.841555,0.842383,0.843208,0.844032,
+0.844854,0.845673,0.846491,0.847307,0.848120,0.848932,0.849742,0.850549,
+0.851355,0.852159,0.852961,0.853760,0.854558,0.855354,0.856147,0.856939,
+0.857729,0.858516,0.859302,0.860085,0.860867,0.861646,0.862424,0.863199,
+0.863973,0.864744,0.865514,0.866281,0.867046,0.867809,0.868571,0.869330,
+0.870087,0.870842,0.871595,0.872346,0.873095,0.873842,0.874587,0.875329,
+0.876070,0.876809,0.877545,0.878280,0.879012,0.879743,0.880471,0.881197,
+0.881921,0.882643,0.883363,0.884081,0.884797,0.885511,0.886223,0.886932,
+0.887640,0.888345,0.889048,0.889750,0.890449,0.891146,0.891841,0.892534,
+0.893224,0.893913,0.894599,0.895284,0.895966,0.896646,0.897325,0.898001,
+0.898674,0.899346,0.900016,0.900683,0.901349,0.902012,0.902673,0.903332,
+0.903989,0.904644,0.905297,0.905947,0.906596,0.907242,0.907886,0.908528,
+0.909168,0.909806,0.910441,0.911075,0.911706,0.912335,0.912962,0.913587,
+0.914210,0.914830,0.915449,0.916065,0.916679,0.917291,0.917901,0.918508,
+0.919114,0.919717,0.920318,0.920917,0.921514,0.922109,0.922701,0.923291,
+0.923880,0.924465,0.925049,0.925631,0.926210,0.926787,0.927363,0.927935,
+0.928506,0.929075,0.929641,0.930205,0.930767,0.931327,0.931884,0.932440,
+0.932993,0.933544,0.934093,0.934639,0.935184,0.935726,0.936266,0.936803,
+0.937339,0.937872,0.938404,0.938932,0.939459,0.939984,0.940506,0.941026,
+0.941544,0.942060,0.942573,0.943084,0.943593,0.944100,0.944605,0.945107,
+0.945607,0.946105,0.946601,0.947094,0.947586,0.948075,0.948561,0.949046,
+0.949528,0.950008,0.950486,0.950962,0.951435,0.951906,0.952375,0.952842,
+0.953306,0.953768,0.954228,0.954686,0.955141,0.955594,0.956045,0.956494,
+0.956940,0.957385,0.957826,0.958266,0.958703,0.959139,0.959572,0.960002,
+0.960431,0.960857,0.961280,0.961702,0.962121,0.962538,0.962953,0.963366,
+0.963776,0.964184,0.964590,0.964993,0.965394,0.965793,0.966190,0.966584,
+0.966976,0.967366,0.967754,0.968139,0.968522,0.968903,0.969281,0.969657,
+0.970031,0.970403,0.970772,0.971139,0.971504,0.971866,0.972226,0.972584,
+0.972940,0.973293,0.973644,0.973993,0.974339,0.974684,0.975025,0.975365,
+0.975702,0.976037,0.976370,0.976700,0.977028,0.977354,0.977677,0.977999,
+0.978317,0.978634,0.978948,0.979260,0.979570,0.979877,0.980182,0.980485,
+0.980785,0.981083,0.981379,0.981673,0.981964,0.982253,0.982539,0.982824,
+0.983105,0.983385,0.983662,0.983937,0.984210,0.984480,0.984749,0.985014,
+0.985278,0.985539,0.985798,0.986054,0.986308,0.986560,0.986809,0.987057,
+0.987301,0.987544,0.987784,0.988022,0.988258,0.988491,0.988722,0.988950,
+0.989177,0.989400,0.989622,0.989841,0.990058,0.990273,0.990485,0.990695,
+0.990903,0.991108,0.991311,0.991511,0.991710,0.991906,0.992099,0.992291,
+0.992480,0.992666,0.992850,0.993032,0.993212,0.993389,0.993564,0.993737,
+0.993907,0.994075,0.994240,0.994404,0.994565,0.994723,0.994879,0.995033,
+0.995185,0.995334,0.995481,0.995625,0.995767,0.995907,0.996045,0.996180,
+0.996313,0.996443,0.996571,0.996697,0.996820,0.996941,0.997060,0.997176,
+0.997290,0.997402,0.997511,0.997618,0.997723,0.997825,0.997925,0.998023,
+0.998118,0.998211,0.998302,0.998390,0.998476,0.998559,0.998640,0.998719,
+0.998795,0.998870,0.998941,0.999011,0.999078,0.999142,0.999205,0.999265,
+0.999322,0.999378,0.999431,0.999481,0.999529,0.999575,0.999619,0.999660,
+0.999699,0.999735,0.999769,0.999801,0.999831,0.999858,0.999882,0.999905,
+0.999925,0.999942,0.999958,0.999971,0.999981,0.999989,0.999995,0.999999
+};
+
+double sin( double x ) {
+ int index;
+ int quad;
+
+ index = 1024 * x / (M_PI * 0.5);
+ quad = ( index >> 10 ) & 3;
+ index &= 1023;
+ switch ( quad ) {
+ case 0:
+ return sintable[index];
+ case 1:
+ return sintable[1023-index];
+ case 2:
+ return -sintable[index];
+ case 3:
+ return -sintable[1023-index];
+ }
+ return 0;
+}
+
+
+double cos( double x ) {
+ int index;
+ int quad;
+
+ index = 1024 * x / (M_PI * 0.5);
+ quad = ( index >> 10 ) & 3;
+ index &= 1023;
+ switch ( quad ) {
+ case 3:
+ return sintable[index];
+ case 0:
+ return sintable[1023-index];
+ case 1:
+ return -sintable[index];
+ case 2:
+ return -sintable[1023-index];
+ }
+ return 0;
+}
+
+
+/*
+void create_acostable( void ) {
+ int i;
+ FILE *fp;
+ float a;
+
+ fp = fopen("c:\\acostable.txt", "w");
+ fprintf(fp, "float acostable[] = {");
+ for (i = 0; i < 1024; i++) {
+ if (!(i & 7))
+ fprintf(fp, "\n");
+ a = acos( (float) -1 + i / 512 );
+ fprintf(fp, "%1.8f,", a);
+ }
+ fprintf(fp, "\n}\n");
+ fclose(fp);
+}
+*/
+
+float acostable[] = {
+3.14159265,3.07908248,3.05317551,3.03328655,3.01651113,3.00172442,2.98834964,2.97604422,
+2.96458497,2.95381690,2.94362719,2.93393068,2.92466119,2.91576615,2.90720289,2.89893629,
+2.89093699,2.88318015,2.87564455,2.86831188,2.86116621,2.85419358,2.84738169,2.84071962,
+2.83419760,2.82780691,2.82153967,2.81538876,2.80934770,2.80341062,2.79757211,2.79182724,
+2.78617145,2.78060056,2.77511069,2.76969824,2.76435988,2.75909250,2.75389319,2.74875926,
+2.74368816,2.73867752,2.73372510,2.72882880,2.72398665,2.71919677,2.71445741,2.70976688,
+2.70512362,2.70052613,2.69597298,2.69146283,2.68699438,2.68256642,2.67817778,2.67382735,
+2.66951407,2.66523692,2.66099493,2.65678719,2.65261279,2.64847088,2.64436066,2.64028133,
+2.63623214,2.63221238,2.62822133,2.62425835,2.62032277,2.61641398,2.61253138,2.60867440,
+2.60484248,2.60103507,2.59725167,2.59349176,2.58975488,2.58604053,2.58234828,2.57867769,
+2.57502832,2.57139977,2.56779164,2.56420354,2.56063509,2.55708594,2.55355572,2.55004409,
+2.54655073,2.54307530,2.53961750,2.53617701,2.53275354,2.52934680,2.52595650,2.52258238,
+2.51922417,2.51588159,2.51255441,2.50924238,2.50594525,2.50266278,2.49939476,2.49614096,
+2.49290115,2.48967513,2.48646269,2.48326362,2.48007773,2.47690482,2.47374472,2.47059722,
+2.46746215,2.46433933,2.46122860,2.45812977,2.45504269,2.45196720,2.44890314,2.44585034,
+2.44280867,2.43977797,2.43675809,2.43374890,2.43075025,2.42776201,2.42478404,2.42181622,
+2.41885841,2.41591048,2.41297232,2.41004380,2.40712480,2.40421521,2.40131491,2.39842379,
+2.39554173,2.39266863,2.38980439,2.38694889,2.38410204,2.38126374,2.37843388,2.37561237,
+2.37279910,2.36999400,2.36719697,2.36440790,2.36162673,2.35885335,2.35608768,2.35332964,
+2.35057914,2.34783610,2.34510044,2.34237208,2.33965094,2.33693695,2.33423003,2.33153010,
+2.32883709,2.32615093,2.32347155,2.32079888,2.31813284,2.31547337,2.31282041,2.31017388,
+2.30753373,2.30489988,2.30227228,2.29965086,2.29703556,2.29442632,2.29182309,2.28922580,
+2.28663439,2.28404881,2.28146900,2.27889490,2.27632647,2.27376364,2.27120637,2.26865460,
+2.26610827,2.26356735,2.26103177,2.25850149,2.25597646,2.25345663,2.25094195,2.24843238,
+2.24592786,2.24342836,2.24093382,2.23844420,2.23595946,2.23347956,2.23100444,2.22853408,
+2.22606842,2.22360742,2.22115104,2.21869925,2.21625199,2.21380924,2.21137096,2.20893709,
+2.20650761,2.20408248,2.20166166,2.19924511,2.19683280,2.19442469,2.19202074,2.18962092,
+2.18722520,2.18483354,2.18244590,2.18006225,2.17768257,2.17530680,2.17293493,2.17056692,
+2.16820274,2.16584236,2.16348574,2.16113285,2.15878367,2.15643816,2.15409630,2.15175805,
+2.14942338,2.14709226,2.14476468,2.14244059,2.14011997,2.13780279,2.13548903,2.13317865,
+2.13087163,2.12856795,2.12626757,2.12397047,2.12167662,2.11938600,2.11709859,2.11481435,
+2.11253326,2.11025530,2.10798044,2.10570867,2.10343994,2.10117424,2.09891156,2.09665185,
+2.09439510,2.09214129,2.08989040,2.08764239,2.08539725,2.08315496,2.08091550,2.07867884,
+2.07644495,2.07421383,2.07198545,2.06975978,2.06753681,2.06531651,2.06309887,2.06088387,
+2.05867147,2.05646168,2.05425445,2.05204979,2.04984765,2.04764804,2.04545092,2.04325628,
+2.04106409,2.03887435,2.03668703,2.03450211,2.03231957,2.03013941,2.02796159,2.02578610,
+2.02361292,2.02144204,2.01927344,2.01710710,2.01494300,2.01278113,2.01062146,2.00846399,
+2.00630870,2.00415556,2.00200457,1.99985570,1.99770895,1.99556429,1.99342171,1.99128119,
+1.98914271,1.98700627,1.98487185,1.98273942,1.98060898,1.97848051,1.97635399,1.97422942,
+1.97210676,1.96998602,1.96786718,1.96575021,1.96363511,1.96152187,1.95941046,1.95730088,
+1.95519310,1.95308712,1.95098292,1.94888050,1.94677982,1.94468089,1.94258368,1.94048818,
+1.93839439,1.93630228,1.93421185,1.93212308,1.93003595,1.92795046,1.92586659,1.92378433,
+1.92170367,1.91962459,1.91754708,1.91547113,1.91339673,1.91132385,1.90925250,1.90718266,
+1.90511432,1.90304746,1.90098208,1.89891815,1.89685568,1.89479464,1.89273503,1.89067683,
+1.88862003,1.88656463,1.88451060,1.88245794,1.88040664,1.87835668,1.87630806,1.87426076,
+1.87221477,1.87017008,1.86812668,1.86608457,1.86404371,1.86200412,1.85996577,1.85792866,
+1.85589277,1.85385809,1.85182462,1.84979234,1.84776125,1.84573132,1.84370256,1.84167495,
+1.83964848,1.83762314,1.83559892,1.83357582,1.83155381,1.82953289,1.82751305,1.82549429,
+1.82347658,1.82145993,1.81944431,1.81742973,1.81541617,1.81340362,1.81139207,1.80938151,
+1.80737194,1.80536334,1.80335570,1.80134902,1.79934328,1.79733848,1.79533460,1.79333164,
+1.79132959,1.78932843,1.78732817,1.78532878,1.78333027,1.78133261,1.77933581,1.77733985,
+1.77534473,1.77335043,1.77135695,1.76936428,1.76737240,1.76538132,1.76339101,1.76140148,
+1.75941271,1.75742470,1.75543743,1.75345090,1.75146510,1.74948002,1.74749565,1.74551198,
+1.74352900,1.74154672,1.73956511,1.73758417,1.73560389,1.73362426,1.73164527,1.72966692,
+1.72768920,1.72571209,1.72373560,1.72175971,1.71978441,1.71780969,1.71583556,1.71386199,
+1.71188899,1.70991653,1.70794462,1.70597325,1.70400241,1.70203209,1.70006228,1.69809297,
+1.69612416,1.69415584,1.69218799,1.69022062,1.68825372,1.68628727,1.68432127,1.68235571,
+1.68039058,1.67842588,1.67646160,1.67449772,1.67253424,1.67057116,1.66860847,1.66664615,
+1.66468420,1.66272262,1.66076139,1.65880050,1.65683996,1.65487975,1.65291986,1.65096028,
+1.64900102,1.64704205,1.64508338,1.64312500,1.64116689,1.63920905,1.63725148,1.63529416,
+1.63333709,1.63138026,1.62942366,1.62746728,1.62551112,1.62355517,1.62159943,1.61964388,
+1.61768851,1.61573332,1.61377831,1.61182346,1.60986877,1.60791422,1.60595982,1.60400556,
+1.60205142,1.60009739,1.59814349,1.59618968,1.59423597,1.59228235,1.59032882,1.58837536,
+1.58642196,1.58446863,1.58251535,1.58056211,1.57860891,1.57665574,1.57470259,1.57274945,
+1.57079633,1.56884320,1.56689007,1.56493692,1.56298375,1.56103055,1.55907731,1.55712403,
+1.55517069,1.55321730,1.55126383,1.54931030,1.54735668,1.54540297,1.54344917,1.54149526,
+1.53954124,1.53758710,1.53563283,1.53367843,1.53172389,1.52976919,1.52781434,1.52585933,
+1.52390414,1.52194878,1.51999323,1.51803748,1.51608153,1.51412537,1.51216900,1.51021240,
+1.50825556,1.50629849,1.50434117,1.50238360,1.50042576,1.49846765,1.49650927,1.49455060,
+1.49259163,1.49063237,1.48867280,1.48671291,1.48475270,1.48279215,1.48083127,1.47887004,
+1.47690845,1.47494650,1.47298419,1.47102149,1.46905841,1.46709493,1.46513106,1.46316677,
+1.46120207,1.45923694,1.45727138,1.45530538,1.45333893,1.45137203,1.44940466,1.44743682,
+1.44546850,1.44349969,1.44153038,1.43956057,1.43759024,1.43561940,1.43364803,1.43167612,
+1.42970367,1.42773066,1.42575709,1.42378296,1.42180825,1.41983295,1.41785705,1.41588056,
+1.41390346,1.41192573,1.40994738,1.40796840,1.40598877,1.40400849,1.40202755,1.40004594,
+1.39806365,1.39608068,1.39409701,1.39211264,1.39012756,1.38814175,1.38615522,1.38416795,
+1.38217994,1.38019117,1.37820164,1.37621134,1.37422025,1.37222837,1.37023570,1.36824222,
+1.36624792,1.36425280,1.36225684,1.36026004,1.35826239,1.35626387,1.35426449,1.35226422,
+1.35026307,1.34826101,1.34625805,1.34425418,1.34224937,1.34024364,1.33823695,1.33622932,
+1.33422072,1.33221114,1.33020059,1.32818904,1.32617649,1.32416292,1.32214834,1.32013273,
+1.31811607,1.31609837,1.31407960,1.31205976,1.31003885,1.30801684,1.30599373,1.30396951,
+1.30194417,1.29991770,1.29789009,1.29586133,1.29383141,1.29180031,1.28976803,1.28773456,
+1.28569989,1.28366400,1.28162688,1.27958854,1.27754894,1.27550809,1.27346597,1.27142257,
+1.26937788,1.26733189,1.26528459,1.26323597,1.26118602,1.25913471,1.25708205,1.25502803,
+1.25297262,1.25091583,1.24885763,1.24679802,1.24473698,1.24267450,1.24061058,1.23854519,
+1.23647833,1.23440999,1.23234015,1.23026880,1.22819593,1.22612152,1.22404557,1.22196806,
+1.21988898,1.21780832,1.21572606,1.21364219,1.21155670,1.20946958,1.20738080,1.20529037,
+1.20319826,1.20110447,1.19900898,1.19691177,1.19481283,1.19271216,1.19060973,1.18850553,
+1.18639955,1.18429178,1.18218219,1.18007079,1.17795754,1.17584244,1.17372548,1.17160663,
+1.16948589,1.16736324,1.16523866,1.16311215,1.16098368,1.15885323,1.15672081,1.15458638,
+1.15244994,1.15031147,1.14817095,1.14602836,1.14388370,1.14173695,1.13958808,1.13743709,
+1.13528396,1.13312866,1.13097119,1.12881153,1.12664966,1.12448556,1.12231921,1.12015061,
+1.11797973,1.11580656,1.11363107,1.11145325,1.10927308,1.10709055,1.10490563,1.10271831,
+1.10052856,1.09833638,1.09614174,1.09394462,1.09174500,1.08954287,1.08733820,1.08513098,
+1.08292118,1.08070879,1.07849378,1.07627614,1.07405585,1.07183287,1.06960721,1.06737882,
+1.06514770,1.06291382,1.06067715,1.05843769,1.05619540,1.05395026,1.05170226,1.04945136,
+1.04719755,1.04494080,1.04268110,1.04041841,1.03815271,1.03588399,1.03361221,1.03133735,
+1.02905939,1.02677830,1.02449407,1.02220665,1.01991603,1.01762219,1.01532509,1.01302471,
+1.01072102,1.00841400,1.00610363,1.00378986,1.00147268,0.99915206,0.99682798,0.99450039,
+0.99216928,0.98983461,0.98749636,0.98515449,0.98280898,0.98045980,0.97810691,0.97575030,
+0.97338991,0.97102573,0.96865772,0.96628585,0.96391009,0.96153040,0.95914675,0.95675912,
+0.95436745,0.95197173,0.94957191,0.94716796,0.94475985,0.94234754,0.93993099,0.93751017,
+0.93508504,0.93265556,0.93022170,0.92778341,0.92534066,0.92289341,0.92044161,0.91798524,
+0.91552424,0.91305858,0.91058821,0.90811309,0.90563319,0.90314845,0.90065884,0.89816430,
+0.89566479,0.89316028,0.89065070,0.88813602,0.88561619,0.88309116,0.88056088,0.87802531,
+0.87548438,0.87293806,0.87038629,0.86782901,0.86526619,0.86269775,0.86012366,0.85754385,
+0.85495827,0.85236686,0.84976956,0.84716633,0.84455709,0.84194179,0.83932037,0.83669277,
+0.83405893,0.83141877,0.82877225,0.82611928,0.82345981,0.82079378,0.81812110,0.81544172,
+0.81275556,0.81006255,0.80736262,0.80465570,0.80194171,0.79922057,0.79649221,0.79375655,
+0.79101352,0.78826302,0.78550497,0.78273931,0.77996593,0.77718475,0.77439569,0.77159865,
+0.76879355,0.76598029,0.76315878,0.76032891,0.75749061,0.75464376,0.75178826,0.74892402,
+0.74605092,0.74316887,0.74027775,0.73737744,0.73446785,0.73154885,0.72862033,0.72568217,
+0.72273425,0.71977644,0.71680861,0.71383064,0.71084240,0.70784376,0.70483456,0.70181469,
+0.69878398,0.69574231,0.69268952,0.68962545,0.68654996,0.68346288,0.68036406,0.67725332,
+0.67413051,0.67099544,0.66784794,0.66468783,0.66151492,0.65832903,0.65512997,0.65191753,
+0.64869151,0.64545170,0.64219789,0.63892987,0.63564741,0.63235028,0.62903824,0.62571106,
+0.62236849,0.61901027,0.61563615,0.61224585,0.60883911,0.60541564,0.60197515,0.59851735,
+0.59504192,0.59154856,0.58803694,0.58450672,0.58095756,0.57738911,0.57380101,0.57019288,
+0.56656433,0.56291496,0.55924437,0.55555212,0.55183778,0.54810089,0.54434099,0.54055758,
+0.53675018,0.53291825,0.52906127,0.52517867,0.52126988,0.51733431,0.51337132,0.50938028,
+0.50536051,0.50131132,0.49723200,0.49312177,0.48897987,0.48480547,0.48059772,0.47635573,
+0.47207859,0.46776530,0.46341487,0.45902623,0.45459827,0.45012983,0.44561967,0.44106652,
+0.43646903,0.43182577,0.42713525,0.42239588,0.41760600,0.41276385,0.40786755,0.40291513,
+0.39790449,0.39283339,0.38769946,0.38250016,0.37723277,0.37189441,0.36648196,0.36099209,
+0.35542120,0.34976542,0.34402054,0.33818204,0.33224495,0.32620390,0.32005298,0.31378574,
+0.30739505,0.30087304,0.29421096,0.28739907,0.28042645,0.27328078,0.26594810,0.25841250,
+0.25065566,0.24265636,0.23438976,0.22582651,0.21693146,0.20766198,0.19796546,0.18777575,
+0.17700769,0.16554844,0.15324301,0.13986823,0.12508152,0.10830610,0.08841715,0.06251018,
+}
+
+double acos( double x ) {
+ int index;
+
+ if (x < -1)
+ x = -1;
+ if (x > 1)
+ x = 1;
+ index = (float) (1.0 + x) * 511.9;
+ return acostable[index];
+}
+
+double atan2( double y, double x ) {
+ float base;
+ float temp;
+ float dir;
+ float test;
+ int i;
+
+ if ( x < 0 ) {
+ if ( y >= 0 ) {
+ // quad 1
+ base = M_PI / 2;
+ temp = x;
+ x = y;
+ y = -temp;
+ } else {
+ // quad 2
+ base = M_PI;
+ x = -x;
+ y = -y;
+ }
+ } else {
+ if ( y < 0 ) {
+ // quad 3
+ base = 3 * M_PI / 2;
+ temp = x;
+ x = -y;
+ y = temp;
+ }
+ }
+
+ if ( y > x ) {
+ base += M_PI/2;
+ temp = x;
+ x = y;
+ y = temp;
+ dir = -1;
+ } else {
+ dir = 1;
+ }
+
+ // calcualte angle in octant 0
+ if ( x == 0 ) {
+ return base;
+ }
+ y /= x;
+
+ for ( i = 0 ; i < 512 ; i++ ) {
+ test = sintable[i] / sintable[1023-i];
+ if ( test > y ) {
+ break;
+ }
+ }
+
+ return base + dir * i * ( M_PI/2048);
+}
+
+
+#endif
+
+double tan( double x ) {
+ return sin(x) / cos(x);
+}
+
+
+static int randSeed = 0;
+
+void srand( unsigned seed ) {
+ randSeed = seed;
+}
+
+int rand( void ) {
+ randSeed = (69069 * randSeed + 1);
+ return randSeed & 0x7fff;
+}
+
+double atof( const char *string ) {
+ float sign;
+ float value;
+ int c;
+
+
+ // skip whitespace
+ while ( *string <= ' ' ) {
+ if ( !*string ) {
+ return 0;
+ }
+ string++;
+ }
+
+ // check sign
+ switch ( *string ) {
+ case '+':
+ string++;
+ sign = 1;
+ break;
+ case '-':
+ string++;
+ sign = -1;
+ break;
+ default:
+ sign = 1;
+ break;
+ }
+
+ // read digits
+ value = 0;
+ c = string[0];
+ if ( c != '.' ) {
+ do {
+ c = *string++;
+ if ( c < '0' || c > '9' ) {
+ break;
+ }
+ c -= '0';
+ value = value * 10 + c;
+ } while ( 1 );
+ } else {
+ string++;
+ }
+
+ // check for decimal point
+ if ( c == '.' ) {
+ double fraction;
+
+ fraction = 0.1;
+ do {
+ c = *string++;
+ if ( c < '0' || c > '9' ) {
+ break;
+ }
+ c -= '0';
+ value += c * fraction;
+ fraction *= 0.1;
+ } while ( 1 );
+
+ }
+
+ // not handling 10e10 notation...
+
+ return value * sign;
+}
+
+double _atof( const char **stringPtr ) {
+ const char *string;
+ float sign;
+ float value;
+ int c = '0';
+
+ string = *stringPtr;
+
+ // skip whitespace
+ while ( *string <= ' ' ) {
+ if ( !*string ) {
+ *stringPtr = string;
+ return 0;
+ }
+ string++;
+ }
+
+ // check sign
+ switch ( *string ) {
+ case '+':
+ string++;
+ sign = 1;
+ break;
+ case '-':
+ string++;
+ sign = -1;
+ break;
+ default:
+ sign = 1;
+ break;
+ }
+
+ // read digits
+ value = 0;
+ if ( string[0] != '.' ) {
+ do {
+ c = *string++;
+ if ( c < '0' || c > '9' ) {
+ break;
+ }
+ c -= '0';
+ value = value * 10 + c;
+ } while ( 1 );
+ }
+
+ // check for decimal point
+ if ( c == '.' ) {
+ double fraction;
+
+ fraction = 0.1;
+ do {
+ c = *string++;
+ if ( c < '0' || c > '9' ) {
+ break;
+ }
+ c -= '0';
+ value += c * fraction;
+ fraction *= 0.1;
+ } while ( 1 );
+
+ }
+
+ // not handling 10e10 notation...
+ *stringPtr = string;
+
+ return value * sign;
+}
+
+/*
+==============
+strtod
+
+Without an errno variable, this is a fair bit less useful than it is in libc
+but it's still a fair bit more capable than atof or _atof
+Handles inf[inity], nan (ignoring case), hexadecimals, and decimals
+Handles decimal exponents like 10e10 and hex exponents like 0x7f8p20
+10e10 == 10000000000 (power of ten)
+0x7f8p20 == 0x7f800000 (decimal power of two)
+The variable pointed to by endptr will hold the location of the first character
+in the nptr string that was not used in the conversion
+==============
+*/
+double strtod( const char *nptr, const char **endptr )
+{
+ double res;
+ qboolean neg = qfalse;
+
+ // skip whitespace
+ while( isspace( *nptr ) )
+ nptr++;
+
+ // special string parsing
+ if( Q_stricmpn( nptr, "nan", 3 ) == 0 )
+ {
+ floatint_t nan;
+ if( endptr == NULL )
+ {
+ nan.ui = 0x7fffffff;
+ return nan.f;
+ }
+ *endptr = &nptr[3];
+ // nan can be followed by a bracketed number (in hex, octal,
+ // or decimal) which is then put in the mantissa
+ // this can be used to generate signalling or quiet NaNs, for
+ // example (though I doubt it'll ever be used)
+ // note that nan(0) is infinity!
+ if( nptr[3] == '(' )
+ {
+ const char *end;
+ int mantissa = strtol( &nptr[4], &end, 0 );
+ if( *end == ')' )
+ {
+ nan.ui = 0x7f800000 | ( mantissa & 0x7fffff );
+ if( endptr )
+ *endptr = &end[1];
+ return nan.f;
+ }
+ }
+ nan.ui = 0x7fffffff;
+ return nan.f;
+ }
+ if( Q_stricmpn( nptr, "inf", 3 ) == 0 )
+ {
+ floatint_t inf;
+ inf.ui = 0x7f800000;
+ if( endptr == NULL )
+ return inf.f;
+ if( Q_stricmpn( &nptr[3], "inity", 5 ) == 0 )
+ *endptr = &nptr[8];
+ else
+ *endptr = &nptr[3];
+ return inf.f;
+ }
+
+ // normal numeric parsing
+ // sign
+ if( *nptr == '-' )
+ {
+ nptr++;
+ neg = qtrue;
+ }
+ else if( *nptr == '+' )
+ nptr++;
+ // hex
+ if( Q_stricmpn( nptr, "0x", 2 ) == 0 )
+ {
+ // track if we use any digits
+ const char *s = &nptr[1], *end = s;
+ nptr += 2;
+ res = 0;
+ while( qtrue )
+ {
+ if( isdigit( *nptr ) )
+ res = 16 * res + ( *nptr++ - '0' );
+ else if( *nptr >= 'A' && *nptr <= 'F' )
+ res = 16 * res + 10 + *nptr++ - 'A';
+ else if( *nptr >= 'a' && *nptr <= 'f' )
+ res = 16 * res + 10 + *nptr++ - 'a';
+ else
+ break;
+ }
+ // if nptr moved, save it
+ if( end + 1 < nptr )
+ end = nptr;
+ if( *nptr == '.' )
+ {
+ float place;
+ nptr++;
+ // 1.0 / 16.0 == 0.0625
+ // I don't expect the float accuracy to hold out for
+ // very long but since we need to know the length of
+ // the string anyway we keep on going regardless
+ for( place = 0.0625;; place /= 16.0 )
+ {
+ if( isdigit( *nptr ) )
+ res += place * ( *nptr++ - '0' );
+ else if( *nptr >= 'A' && *nptr <= 'F' )
+ res += place * ( 10 + *nptr++ - 'A' );
+ else if( *nptr >= 'a' && *nptr <= 'f' )
+ res += place * ( 10 + *nptr++ - 'a' );
+ else
+ break;
+ }
+ if( end < nptr )
+ end = nptr;
+ }
+ // parse an optional exponent, representing multiplication
+ // by a power of two
+ // exponents are only valid if we encountered at least one
+ // digit already (and have therefore set end to something)
+ if( end != s && tolower( *nptr ) == 'p' )
+ {
+ int exp;
+ float res2;
+ // apparently (confusingly) the exponent should be
+ // decimal
+ exp = strtol( &nptr[1], &end, 10 );
+ if( &nptr[1] == end )
+ {
+ // no exponent
+ if( endptr )
+ *endptr = nptr;
+ return res;
+ }
+ if( exp > 0 )
+ {
+ while( exp-- > 0 )
+ {
+ res2 = res * 2;
+ // check for infinity
+ if( res2 <= res )
+ break;
+ res = res2;
+ }
+ }
+ else
+ {
+ while( exp++ < 0 )
+ {
+ res2 = res / 2;
+ // check for underflow
+ if( res2 >= res )
+ break;
+ res = res2;
+ }
+ }
+ }
+ if( endptr )
+ *endptr = end;
+ return res;
+ }
+ // decimal
+ else
+ {
+ // track if we find any digits
+ const char *end = nptr, *p = nptr;
+ // this is most of the work
+ for( res = 0; isdigit( *nptr );
+ res = 10 * res + *nptr++ - '0' );
+ // if nptr moved, we read something
+ if( end < nptr )
+ end = nptr;
+ if( *nptr == '.' )
+ {
+ // fractional part
+ float place;
+ nptr++;
+ for( place = 0.1; isdigit( *nptr ); place /= 10.0 )
+ res += ( *nptr++ - '0' ) * place;
+ // if nptr moved, we read something
+ if( end + 1 < nptr )
+ end = nptr;
+ }
+ // exponent
+ // meaningless without having already read digits, so check
+ // we've set end to something
+ if( p != end && tolower( *nptr ) == 'e' )
+ {
+ int exp;
+ float res10;
+ exp = strtol( &nptr[1], &end, 10 );
+ if( &nptr[1] == end )
+ {
+ // no exponent
+ if( endptr )
+ *endptr = nptr;
+ return res;
+ }
+ if( exp > 0 )
+ {
+ while( exp-- > 0 )
+ {
+ res10 = res * 10;
+ // check for infinity to save us time
+ if( res10 <= res )
+ break;
+ res = res10;
+ }
+ }
+ else if( exp < 0 )
+ {
+ while( exp++ < 0 )
+ {
+ res10 = res / 10;
+ // check for underflow
+ // (test for 0 would probably be just
+ // as good)
+ if( res10 >= res )
+ break;
+ res = res10;
+ }
+ }
+ }
+ if( endptr )
+ *endptr = end;
+ return res;
+ }
+}
+
+int atoi( const char *string ) {
+ int sign;
+ int value;
+ int c;
+
+
+ // skip whitespace
+ while ( *string <= ' ' ) {
+ if ( !*string ) {
+ return 0;
+ }
+ string++;
+ }
+
+ // check sign
+ switch ( *string ) {
+ case '+':
+ string++;
+ sign = 1;
+ break;
+ case '-':
+ string++;
+ sign = -1;
+ break;
+ default:
+ sign = 1;
+ break;
+ }
+
+ // read digits
+ value = 0;
+ do {
+ c = *string++;
+ if ( c < '0' || c > '9' ) {
+ break;
+ }
+ c -= '0';
+ value = value * 10 + c;
+ } while ( 1 );
+
+ // not handling 10e10 notation...
+
+ return value * sign;
+}
+
+
+int _atoi( const char **stringPtr ) {
+ int sign;
+ int value;
+ int c;
+ const char *string;
+
+ string = *stringPtr;
+
+ // skip whitespace
+ while ( *string <= ' ' ) {
+ if ( !*string ) {
+ return 0;
+ }
+ string++;
+ }
+
+ // check sign
+ switch ( *string ) {
+ case '+':
+ string++;
+ sign = 1;
+ break;
+ case '-':
+ string++;
+ sign = -1;
+ break;
+ default:
+ sign = 1;
+ break;
+ }
+
+ // read digits
+ value = 0;
+ do {
+ c = *string++;
+ if ( c < '0' || c > '9' ) {
+ break;
+ }
+ c -= '0';
+ value = value * 10 + c;
+ } while ( 1 );
+
+ // not handling 10e10 notation...
+
+ *stringPtr = string;
+
+ return value * sign;
+}
+
+/*
+==============
+strtol
+
+Handles any base from 2 to 36. If base is 0 then it guesses
+decimal, hex, or octal based on the format of the number (leading 0 or 0x)
+Will not overflow - returns LONG_MIN or LONG_MAX as appropriate
+*endptr is set to the location of the first character not used
+==============
+*/
+long strtol( const char *nptr, const char **endptr, int base )
+{
+ long res;
+ qboolean pos = qtrue;
+
+ if( endptr )
+ *endptr = nptr;
+ // bases other than 0, 2, 8, 16 are very rarely used, but they're
+ // not much extra effort to support
+ if( base < 0 || base == 1 || base > 36 )
+ return 0;
+ // skip leading whitespace
+ while( isspace( *nptr ) )
+ nptr++;
+ // sign
+ if( *nptr == '-' )
+ {
+ nptr++;
+ pos = qfalse;
+ }
+ else if( *nptr == '+' )
+ nptr++;
+ // look for base-identifying sequences e.g. 0x for hex, 0 for octal
+ if( nptr[0] == '0' )
+ {
+ nptr++;
+ // 0 is always a valid digit
+ if( endptr )
+ *endptr = nptr;
+ if( *nptr == 'x' || *nptr == 'X' )
+ {
+ if( base != 0 && base != 16 )
+ {
+ // can't be hex, reject x (accept 0)
+ if( endptr )
+ *endptr = nptr;
+ return 0;
+ }
+ nptr++;
+ base = 16;
+ }
+ else if( base == 0 )
+ base = 8;
+ }
+ else if( base == 0 )
+ base = 10;
+ res = 0;
+ while( qtrue )
+ {
+ int val;
+ if( isdigit( *nptr ) )
+ val = *nptr - '0';
+ else if( islower( *nptr ) )
+ val = 10 + *nptr - 'a';
+ else if( isupper( *nptr ) )
+ val = 10 + *nptr - 'A';
+ else
+ break;
+ if( val >= base )
+ break;
+ // we go negative because LONG_MIN is further from 0 than
+ // LONG_MAX
+ if( res < ( LONG_MIN + val ) / base )
+ res = LONG_MIN; // overflow
+ else
+ res = res * base - val;
+ nptr++;
+ if( endptr )
+ *endptr = nptr;
+ }
+ if( pos )
+ {
+ // can't represent LONG_MIN positive
+ if( res == LONG_MIN )
+ res = LONG_MAX;
+ else
+ res = -res;
+ }
+ return res;
+}
+
+int abs( int n ) {
+ return n < 0 ? -n : n;
+}
+
+double fabs( double x ) {
+ return x < 0 ? -x : x;
+}
+
+
+
+//=========================================================
+
+/*
+ * New implementation by Patrick Powell and others for vsnprintf.
+ * Supports length checking in strings.
+*/
+
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell at astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh. This sort of thing is always nasty do deal with. Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length. This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ * Brandon Long <blong at fiction.net> 9/15/96 for mutt 0.43
+ * This was ugly. It is still ugly. I opted out of floating point
+ * numbers, but the formatter understands just about everything
+ * from the normal C string format, at least as far as I can tell from
+ * the Solaris 2.5 printf(3S) man page.
+ *
+ * Brandon Long <blong at fiction.net> 10/22/97 for mutt 0.87.1
+ * Ok, added some minimal floating point support, which means this
+ * probably requires libm on most operating systems. Don't yet
+ * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
+ * was pretty badly broken, it just wasn't being exercised in ways
+ * which showed it, so that's been fixed. Also, formated the code
+ * to mutt conventions, and removed dead code left over from the
+ * original. Also, there is now a builtin-test, just compile with:
+ * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ * and run snprintf for results.
+ *
+ * Thomas Roessler <roessler at guug.de> 01/27/98 for mutt 0.89i
+ * The PGP code was using unsigned hexadecimal formats.
+ * Unfortunately, unsigned formats simply didn't work.
+ *
+ * Michael Elkins <me at cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ * The original code assumed that both snprintf() and vsnprintf() were
+ * missing. Some systems only have snprintf() but not vsnprintf(), so
+ * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ * Andrew Tridgell (tridge at samba.org) Oct 1998
+ * fixed handling of %.0f
+ * added test for HAVE_LONG_DOUBLE
+ *
+ * Russ Allbery <rra at stanford.edu> 2000-08-26
+ * fixed return value to comply with C99
+ * fixed handling of snprintf(NULL, ...)
+ *
+ * Hrvoje Niksic <hniksic at arsdigita.com> 2000-11-04
+ * include <config.h> instead of "config.h".
+ * moved TEST_SNPRINTF stuff out of HAVE_SNPRINTF ifdef.
+ * include <stdio.h> for NULL.
+ * added support and test cases for long long.
+ * don't declare argument types to (v)snprintf if stdarg is not used.
+ * use int instead of short int as 2nd arg to va_arg.
+ *
+ **************************************************************/
+
+/* BDR 2002-01-13 %e and %g were being ignored. Now do something,
+ if not necessarily correctly */
+
+#if (SIZEOF_LONG_DOUBLE > 0)
+/* #ifdef HAVE_LONG_DOUBLE */
+#define LDOUBLE long double
+#else
+#define LDOUBLE double
+#endif
+
+#if (SIZEOF_LONG_LONG > 0)
+/* #ifdef HAVE_LONG_LONG */
+# define LLONG long long
+#else
+# define LLONG long
+#endif
+
+static int dopr (char *buffer, size_t maxlen, const char *format,
+ va_list args);
+static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
+ char *value, int flags, int min, int max);
+static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
+ LLONG value, int base, int min, int max, int flags);
+static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+ LDOUBLE fvalue, int min, int max, int flags);
+static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS 1
+#define DP_S_MIN 2
+#define DP_S_DOT 3
+#define DP_S_MAX 4
+#define DP_S_MOD 5
+#define DP_S_MOD_L 6
+#define DP_S_CONV 7
+#define DP_S_DONE 8
+
+/* format flags - Bits */
+#define DP_F_MINUS (1 << 0)
+#define DP_F_PLUS (1 << 1)
+#define DP_F_SPACE (1 << 2)
+#define DP_F_NUM (1 << 3)
+#define DP_F_ZERO (1 << 4)
+#define DP_F_UP (1 << 5)
+#define DP_F_UNSIGNED (1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT 1
+#define DP_C_LONG 2
+#define DP_C_LLONG 3
+#define DP_C_LDOUBLE 4
+
+#define char_to_int(p) (p - '0')
+#define MAX(p,q) ((p >= q) ? p : q)
+#define MIN(p,q) ((p <= q) ? p : q)
+
+static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
+{
+ char ch;
+ LLONG value;
+ LDOUBLE fvalue;
+ char *strvalue;
+ int min;
+ int max;
+ int state;
+ int flags;
+ int cflags;
+ int total;
+ size_t currlen;
+
+ state = DP_S_DEFAULT;
+ currlen = flags = cflags = min = 0;
+ max = -1;
+ ch = *format++;
+ total = 0;
+
+ while (state != DP_S_DONE)
+ {
+ if (ch == '\0')
+ state = DP_S_DONE;
+
+ switch(state)
+ {
+ case DP_S_DEFAULT:
+ if (ch == '%')
+ state = DP_S_FLAGS;
+ else
+ total += dopr_outch (buffer, &currlen, maxlen, ch);
+ ch = *format++;
+ break;
+ case DP_S_FLAGS:
+ switch (ch)
+ {
+ case '-':
+ flags |= DP_F_MINUS;
+ ch = *format++;
+ break;
+ case '+':
+ flags |= DP_F_PLUS;
+ ch = *format++;
+ break;
+ case ' ':
+ flags |= DP_F_SPACE;
+ ch = *format++;
+ break;
+ case '#':
+ flags |= DP_F_NUM;
+ ch = *format++;
+ break;
+ case '0':
+ flags |= DP_F_ZERO;
+ ch = *format++;
+ break;
+ default:
+ state = DP_S_MIN;
+ break;
+ }
+ break;
+ case DP_S_MIN:
+ if ('0' <= ch && ch <= '9')
+ {
+ min = 10*min + char_to_int (ch);
+ ch = *format++;
+ }
+ else if (ch == '*')
+ {
+ min = va_arg (args, int);
+ ch = *format++;
+ state = DP_S_DOT;
+ }
+ else
+ state = DP_S_DOT;
+ break;
+ case DP_S_DOT:
+ if (ch == '.')
+ {
+ state = DP_S_MAX;
+ ch = *format++;
+ }
+ else
+ state = DP_S_MOD;
+ break;
+ case DP_S_MAX:
+ if ('0' <= ch && ch <= '9')
+ {
+ if (max < 0)
+ max = 0;
+ max = 10*max + char_to_int (ch);
+ ch = *format++;
+ }
+ else if (ch == '*')
+ {
+ max = va_arg (args, int);
+ ch = *format++;
+ state = DP_S_MOD;
+ }
+ else
+ state = DP_S_MOD;
+ break;
+ case DP_S_MOD:
+ switch (ch)
+ {
+ case 'h':
+ cflags = DP_C_SHORT;
+ ch = *format++;
+ break;
+ case 'l':
+ cflags = DP_C_LONG;
+ ch = *format++;
+ break;
+ case 'L':
+ cflags = DP_C_LDOUBLE;
+ ch = *format++;
+ break;
+ default:
+ break;
+ }
+ if (cflags != DP_C_LONG)
+ state = DP_S_CONV;
+ else
+ state = DP_S_MOD_L;
+ break;
+ case DP_S_MOD_L:
+ switch (ch)
+ {
+ case 'l':
+ cflags = DP_C_LLONG;
+ ch = *format++;
+ break;
+ default:
+ break;
+ }
+ state = DP_S_CONV;
+ break;
+ case DP_S_CONV:
+ switch (ch)
+ {
+ case 'd':
+ case 'i':
+ if (cflags == DP_C_SHORT)
+ value = (short int)va_arg (args, int);
+ else if (cflags == DP_C_LONG)
+ value = va_arg (args, long int);
+ else if (cflags == DP_C_LLONG)
+ value = va_arg (args, LLONG);
+ else
+ value = va_arg (args, int);
+ total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+ break;
+ case 'o':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+// value = (unsigned short int) va_arg (args, unsigned short int); // Thilo: This does not work because the rcc compiler cannot do that cast correctly.
+ value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1); // Using this workaround instead.
+ else if (cflags == DP_C_LONG)
+ value = va_arg (args, unsigned long int);
+ else if (cflags == DP_C_LLONG)
+ value = va_arg (args, unsigned LLONG);
+ else
+ value = va_arg (args, unsigned int);
+ total += fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
+ break;
+ case 'u':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1);
+ else if (cflags == DP_C_LONG)
+ value = va_arg (args, unsigned long int);
+ else if (cflags == DP_C_LLONG)
+ value = va_arg (args, unsigned LLONG);
+ else
+ value = va_arg (args, unsigned int);
+ total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+ break;
+ case 'X':
+ flags |= DP_F_UP;
+ case 'x':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1);
+ else if (cflags == DP_C_LONG)
+ value = va_arg (args, unsigned long int);
+ else if (cflags == DP_C_LLONG)
+ value = va_arg (args, unsigned LLONG);
+ else
+ value = va_arg (args, unsigned int);
+ total += fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
+ break;
+ case 'f':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg (args, LDOUBLE);
+ else
+ fvalue = va_arg (args, double);
+ /* um, floating point? */
+ total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
+ break;
+ case 'E':
+ flags |= DP_F_UP;
+ case 'e':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg (args, LDOUBLE);
+ else
+ fvalue = va_arg (args, double);
+ /* um, floating point? */
+ total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
+ break;
+ case 'G':
+ flags |= DP_F_UP;
+ case 'g':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg (args, LDOUBLE);
+ else
+ fvalue = va_arg (args, double);
+ /* um, floating point? */
+ total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
+ break;
+ case 'c':
+ total += dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
+ break;
+ case 's':
+ strvalue = va_arg (args, char *);
+ total += fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
+ break;
+ case 'p':
+ strvalue = va_arg (args, void *);
+ total += fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min,
+ max, flags);
+ break;
+ case 'n':
+ if (cflags == DP_C_SHORT)
+ {
+ short int *num;
+ num = va_arg (args, short int *);
+ *num = currlen;
+ }
+ else if (cflags == DP_C_LONG)
+ {
+ long int *num;
+ num = va_arg (args, long int *);
+ *num = currlen;
+ }
+ else if (cflags == DP_C_LLONG)
+ {
+ LLONG *num;
+ num = va_arg (args, LLONG *);
+ *num = currlen;
+ }
+ else
+ {
+ int *num;
+ num = va_arg (args, int *);
+ *num = currlen;
+ }
+ break;
+ case '%':
+ total += dopr_outch (buffer, &currlen, maxlen, ch);
+ break;
+ case 'w':
+ /* not supported yet, treat as next char */
+ ch = *format++;
+ break;
+ default:
+ /* Unknown, skip */
+ break;
+ }
+ ch = *format++;
+ state = DP_S_DEFAULT;
+ flags = cflags = min = 0;
+ max = -1;
+ break;
+ case DP_S_DONE:
+ break;
+ default:
+ /* hmm? */
+ break; /* some picky compilers need this */
+ }
+ }
+ if (buffer != NULL)
+ {
+ if (currlen < maxlen - 1)
+ buffer[currlen] = '\0';
+ else
+ buffer[maxlen - 1] = '\0';
+ }
+ return total;
+}
+
+static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
+ char *value, int flags, int min, int max)
+{
+ int padlen, strln; /* amount to pad */
+ int cnt = 0;
+ int total = 0;
+
+ if (value == 0)
+ {
+ value = "<NULL>";
+ }
+
+ for (strln = 0; value[strln]; ++strln); /* strlen */
+ if (max >= 0 && max < strln)
+ strln = max;
+ padlen = min - strln;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justify */
+
+ while (padlen > 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, ' ');
+ --padlen;
+ }
+ while (*value && ((max < 0) || (cnt < max)))
+ {
+ total += dopr_outch (buffer, currlen, maxlen, *value++);
+ ++cnt;
+ }
+ while (padlen < 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, ' ');
+ ++padlen;
+ }
+ return total;
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
+ LLONG value, int base, int min, int max, int flags)
+{
+ int signvalue = 0;
+ unsigned LLONG uvalue;
+ char convert[24];
+ int place = 0;
+ int spadlen = 0; /* amount to space pad */
+ int zpadlen = 0; /* amount to zero pad */
+ const char *digits;
+ int total = 0;
+
+ if (max < 0)
+ max = 0;
+
+ uvalue = value;
+
+ if(!(flags & DP_F_UNSIGNED))
+ {
+ if( value < 0 ) {
+ signvalue = '-';
+ uvalue = -value;
+ }
+ else
+ if (flags & DP_F_PLUS) /* Do a sign (+/i) */
+ signvalue = '+';
+ else
+ if (flags & DP_F_SPACE)
+ signvalue = ' ';
+ }
+
+ if (flags & DP_F_UP)
+ /* Should characters be upper case? */
+ digits = "0123456789ABCDEF";
+ else
+ digits = "0123456789abcdef";
+
+ do {
+ convert[place++] = digits[uvalue % (unsigned)base];
+ uvalue = (uvalue / (unsigned)base );
+ } while(uvalue && (place < sizeof (convert)));
+ if (place == sizeof (convert)) place--;
+ convert[place] = 0;
+
+ zpadlen = max - place;
+ spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
+ if (zpadlen < 0) zpadlen = 0;
+ if (spadlen < 0) spadlen = 0;
+ if (flags & DP_F_ZERO)
+ {
+ zpadlen = MAX(zpadlen, spadlen);
+ spadlen = 0;
+ }
+ if (flags & DP_F_MINUS)
+ spadlen = -spadlen; /* Left Justifty */
+
+#ifdef DEBUG_SNPRINTF
+ dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+ zpadlen, spadlen, min, max, place));
+#endif
+
+ /* Spaces */
+ while (spadlen > 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, ' ');
+ --spadlen;
+ }
+
+ /* Sign */
+ if (signvalue)
+ total += dopr_outch (buffer, currlen, maxlen, signvalue);
+
+ /* Zeros */
+ if (zpadlen > 0)
+ {
+ while (zpadlen > 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, '0');
+ --zpadlen;
+ }
+ }
+
+ /* Digits */
+ while (place > 0)
+ total += dopr_outch (buffer, currlen, maxlen, convert[--place]);
+
+ /* Left Justified spaces */
+ while (spadlen < 0) {
+ total += dopr_outch (buffer, currlen, maxlen, ' ');
+ ++spadlen;
+ }
+
+ return total;
+}
+
+static LDOUBLE abs_val (LDOUBLE value)
+{
+ LDOUBLE result = value;
+
+ if (value < 0)
+ result = -value;
+
+ return result;
+}
+
+static LDOUBLE pow10 (int exp)
+{
+ LDOUBLE result = 1;
+
+ while (exp)
+ {
+ result *= 10;
+ exp--;
+ }
+
+ return result;
+}
+
+static long round (LDOUBLE value)
+{
+ long intpart;
+
+ intpart = value;
+ value = value - intpart;
+ if (value >= 0.5)
+ intpart++;
+
+ return intpart;
+}
+
+static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+ LDOUBLE fvalue, int min, int max, int flags)
+{
+ int signvalue = 0;
+ LDOUBLE ufvalue;
+ char iconvert[20];
+ char fconvert[20];
+ int iplace = 0;
+ int fplace = 0;
+ int padlen = 0; /* amount to pad */
+ int zpadlen = 0;
+ int caps = 0;
+ int total = 0;
+ long intpart;
+ long fracpart;
+
+ /*
+ * AIX manpage says the default is 0, but Solaris says the default
+ * is 6, and sprintf on AIX defaults to 6
+ */
+ if (max < 0)
+ max = 6;
+
+ ufvalue = abs_val (fvalue);
+
+ if (fvalue < 0)
+ signvalue = '-';
+ else
+ if (flags & DP_F_PLUS) /* Do a sign (+/i) */
+ signvalue = '+';
+ else
+ if (flags & DP_F_SPACE)
+ signvalue = ' ';
+
+#if 0
+ if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+#endif
+
+ intpart = ufvalue;
+
+ /*
+ * Sorry, we only support 9 digits past the decimal because of our
+ * conversion method
+ */
+ if (max > 9)
+ max = 9;
+
+ /* We "cheat" by converting the fractional part to integer by
+ * multiplying by a factor of 10
+ */
+ fracpart = round ((pow10 (max)) * (ufvalue - intpart));
+
+ if (fracpart >= pow10 (max))
+ {
+ intpart++;
+ fracpart -= pow10 (max);
+ }
+
+#ifdef DEBUG_SNPRINTF
+ dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
+#endif
+
+ /* Convert integer part */
+ do {
+ iconvert[iplace++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
+ intpart = (intpart / 10);
+ } while(intpart && (iplace < 20));
+ if (iplace == 20) iplace--;
+ iconvert[iplace] = 0;
+
+ /* Convert fractional part */
+ do {
+ fconvert[fplace++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
+ fracpart = (fracpart / 10);
+ } while(fracpart && (fplace < 20));
+ if (fplace == 20) fplace--;
+ fconvert[fplace] = 0;
+
+ /* -1 for decimal point, another -1 if we are printing a sign */
+ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
+ zpadlen = max - fplace;
+ if (zpadlen < 0)
+ zpadlen = 0;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justifty */
+
+ if ((flags & DP_F_ZERO) && (padlen > 0))
+ {
+ if (signvalue)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, signvalue);
+ --padlen;
+ signvalue = 0;
+ }
+ while (padlen > 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, '0');
+ --padlen;
+ }
+ }
+ while (padlen > 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, ' ');
+ --padlen;
+ }
+ if (signvalue)
+ total += dopr_outch (buffer, currlen, maxlen, signvalue);
+
+ while (iplace > 0)
+ total += dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
+
+ /*
+ * Decimal point. This should probably use locale to find the correct
+ * char to print out.
+ */
+ if (max > 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, '.');
+
+ while (zpadlen-- > 0)
+ total += dopr_outch (buffer, currlen, maxlen, '0');
+
+ while (fplace > 0)
+ total += dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
+ }
+
+ while (padlen < 0)
+ {
+ total += dopr_outch (buffer, currlen, maxlen, ' ');
+ ++padlen;
+ }
+
+ return total;
+}
+
+static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+ if (*currlen + 1 < maxlen)
+ buffer[(*currlen)++] = c;
+ return 1;
+}
+
+int Q_vsnprintf(char *str, size_t length, const char *fmt, va_list args)
+{
+ if (str != NULL)
+ str[0] = 0;
+ return dopr(str, length, fmt, args);
+}
+
+int Q_snprintf(char *str, size_t length, const char *fmt, ...)
+{
+ va_list ap;
+ int retval;
+
+ va_start(ap, fmt);
+ retval = Q_vsnprintf(str, length, fmt, ap);
+ va_end(ap);
+
+ return retval;
+}
+
+/* this is really crappy */
+int sscanf( const char *buffer, const char *fmt, ... ) {
+ int cmd;
+ va_list ap;
+ int count;
+ size_t len;
+
+ va_start (ap, fmt);
+ count = 0;
+
+ while ( *fmt ) {
+ if ( fmt[0] != '%' ) {
+ fmt++;
+ continue;
+ }
+
+ fmt++;
+ cmd = *fmt;
+
+ if (isdigit (cmd)) {
+ len = (size_t)_atoi (&fmt);
+ cmd = *(fmt - 1);
+ } else {
+ len = MAX_STRING_CHARS - 1;
+ fmt++;
+ }
+
+ switch ( cmd ) {
+ case 'i':
+ case 'd':
+ case 'u':
+ *(va_arg (ap, int *)) = _atoi( &buffer );
+ break;
+ case 'f':
+ *(va_arg (ap, float *)) = _atof( &buffer );
+ break;
+ case 's':
+ {
+ char *s = va_arg (ap, char *);
+ while (isspace (*buffer))
+ buffer++;
+ while (*buffer && !isspace (*buffer) && len-- > 0 )
+ *s++ = *buffer++;
+ *s++ = '\0';
+ break;
+ }
+ }
+ }
+
+ va_end (ap);
+ return count;
+}
+
+#endif
diff --git a/code/game/bg_lib.h b/code/game/bg_lib.h
new file mode 100644
index 0000000..6191967
--- /dev/null
+++ b/code/game/bg_lib.h
@@ -0,0 +1,126 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+// bg_lib.h -- standard C library replacement routines used by code
+// compiled for the virtual machine
+
+// This file is NOT included on native builds
+#if !defined( BG_LIB_H ) && defined( Q3_VM )
+#define BG_LIB_H
+
+//Ignore __attribute__ on non-gcc platforms
+#ifndef __GNUC__
+#ifndef __attribute__
+#define __attribute__(x)
+#endif
+#endif
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+typedef int size_t;
+
+typedef char * va_list;
+#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
+#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
+#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
+#define va_end(ap) ( ap = (va_list)0 )
+
+#define CHAR_BIT 8 /* number of bits in a char */
+#define SCHAR_MAX 0x7f /* maximum signed char value */
+#define SCHAR_MIN (-SCHAR_MAX - 1) /* minimum signed char value */
+#define UCHAR_MAX 0xff /* maximum unsigned char value */
+
+#define SHRT_MAX 0x7fff /* maximum (signed) short value */
+#define SHRT_MIN (-SHRT_MAX - 1) /* minimum (signed) short value */
+#define USHRT_MAX 0xffff /* maximum unsigned short value */
+#define INT_MAX 0x7fffffff /* maximum (signed) int value */
+#define INT_MIN (-INT_MAX - 1) /* minimum (signed) int value */
+#define UINT_MAX 0xffffffff /* maximum unsigned int value */
+#define LONG_MAX 0x7fffffffL /* maximum (signed) long value */
+#define LONG_MIN (-LONG_MAX - 1) /* minimum (signed) long value */
+#define ULONG_MAX 0xffffffffUL /* maximum unsigned long value */
+
+#define isalnum(c) (isalpha(c) || isdigit(c))
+#define isalpha(c) (isupper(c) || islower(c))
+#define isascii(c) ((c) > 0 && (c) <= 0x7f)
+#define iscntrl(c) (((c) >= 0) && (((c) <= 0x1f) || ((c) == 0x7f)))
+#define isdigit(c) ((c) >= '0' && (c) <= '9')
+#define isgraph(c) ((c) != ' ' && isprint(c))
+#define islower(c) ((c) >= 'a' && (c) <= 'z')
+#define isprint(c) ((c) >= ' ' && (c) <= '~')
+#define ispunct(c) (((c) > ' ' && (c) <= '~') && !isalnum(c))
+#define isspace(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || (c) == '\r' || \
+ (c) == '\t' || (c) == '\v')
+#define isupper(c) ((c) >= 'A' && (c) <= 'Z')
+#define isxdigit(c) (isxupper(c) || isxlower(c))
+#define isxlower(c) (isdigit(c) || (c >= 'a' && c <= 'f'))
+#define isxupper(c) (isdigit(c) || (c >= 'A' && c <= 'F'))
+
+// Misc functions
+typedef int cmp_t(const void *, const void *);
+void qsort(void *a, size_t n, size_t es, cmp_t *cmp);
+void srand( unsigned seed );
+int rand( void );
+
+// String functions
+size_t strlen( const char *string );
+char *strcat( char *strDestination, const char *strSource );
+char *strcpy( char *strDestination, const char *strSource );
+int strcmp( const char *string1, const char *string2 );
+char *strchr( const char *string, int c );
+char *strrchr(const char *string, int c);
+char *strstr( const char *string, const char *strCharSet );
+char *strncpy( char *strDest, const char *strSource, size_t count );
+int tolower( int c );
+int toupper( int c );
+
+double atof( const char *string );
+double _atof( const char **stringPtr );
+double strtod( const char *nptr, const char **endptr );
+int atoi( const char *string );
+int _atoi( const char **stringPtr );
+long strtol( const char *nptr, const char **endptr, int base );
+
+int Q_vsnprintf( char *buffer, size_t length, const char *fmt, va_list argptr );
+int Q_snprintf( char *buffer, size_t length, const char *fmt, ... ) __attribute__ ((format (printf, 3, 4)));
+
+int sscanf( const char *buffer, const char *fmt, ... ) __attribute__ ((format (scanf, 2, 3)));
+
+// Memory functions
+void *memmove( void *dest, const void *src, size_t count );
+void *memset( void *dest, int c, size_t count );
+void *memcpy( void *dest, const void *src, size_t count );
+
+// Math functions
+double ceil( double x );
+double floor( double x );
+double sqrt( double x );
+double sin( double x );
+double cos( double x );
+double atan2( double y, double x );
+double tan( double x );
+int abs( int n );
+double fabs( double x );
+double acos( double x );
+
+#endif // BG_LIB_H
diff --git a/engine/code/game/bg_local.h b/code/game/bg_local.h
similarity index 100%
rename from engine/code/game/bg_local.h
rename to code/game/bg_local.h
diff --git a/game/code/game/bg_misc.c b/code/game/bg_misc.c
similarity index 100%
rename from game/code/game/bg_misc.c
rename to code/game/bg_misc.c
diff --git a/code/game/bg_pmove.c b/code/game/bg_pmove.c
new file mode 100644
index 0000000..de3d1f5
--- /dev/null
+++ b/code/game/bg_pmove.c
@@ -0,0 +1,2085 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// bg_pmove.c -- both games player movement code
+// takes a playerstate and a usercmd as input and returns a modifed playerstate
+
+#include "../qcommon/q_shared.h"
+#include "bg_public.h"
+#include "bg_local.h"
+
+pmove_t *pm;
+pml_t pml;
+
+// movement parameters
+float pm_stopspeed = 100.0f;
+float pm_duckScale = 0.25f;
+float pm_swimScale = 0.50f;
+float pm_wadeScale = 0.70f;
+
+float pm_accelerate = 10.0f;
+float pm_airaccelerate = 1.0f;
+float pm_wateraccelerate = 4.0f;
+float pm_flyaccelerate = 8.0f;
+
+float pm_friction = 6.0f;
+float pm_waterfriction = 1.0f;
+float pm_flightfriction = 3.0f;
+float pm_spectatorfriction = 5.0f;
+
+int c_pmove = 0;
+
+/*
+===============
+PM_AddEvent
+
+===============
+*/
+void PM_AddEvent( int newEvent ) {
+ BG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps );
+}
+
+/*
+===============
+PM_AddTouchEnt
+===============
+*/
+void PM_AddTouchEnt( int entityNum ) {
+ int i;
+
+ if ( entityNum == ENTITYNUM_WORLD ) {
+ return;
+ }
+ if ( pm->numtouch == MAXTOUCH ) {
+ return;
+ }
+
+ // see if it is already added
+ for ( i = 0 ; i < pm->numtouch ; i++ ) {
+ if ( pm->touchents[ i ] == entityNum ) {
+ return;
+ }
+ }
+
+ // add it
+ pm->touchents[pm->numtouch] = entityNum;
+ pm->numtouch++;
+}
+
+/*
+===================
+PM_StartTorsoAnim
+===================
+*/
+static void PM_StartTorsoAnim( int anim ) {
+ if ( pm->ps->pm_type >= PM_DEAD ) {
+ return;
+ }
+ pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
+ | anim;
+}
+static void PM_StartLegsAnim( int anim ) {
+ if ( pm->ps->pm_type >= PM_DEAD ) {
+ return;
+ }
+ if ( pm->ps->legsTimer > 0 ) {
+ return; // a high priority animation is running
+ }
+ pm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
+ | anim;
+}
+
+static void PM_ContinueLegsAnim( int anim ) {
+ if ( ( pm->ps->legsAnim & ~ANIM_TOGGLEBIT ) == anim ) {
+ return;
+ }
+ if ( pm->ps->legsTimer > 0 ) {
+ return; // a high priority animation is running
+ }
+ PM_StartLegsAnim( anim );
+}
+
+static void PM_ContinueTorsoAnim( int anim ) {
+ if ( ( pm->ps->torsoAnim & ~ANIM_TOGGLEBIT ) == anim ) {
+ return;
+ }
+ if ( pm->ps->torsoTimer > 0 ) {
+ return; // a high priority animation is running
+ }
+ PM_StartTorsoAnim( anim );
+}
+
+static void PM_ForceLegsAnim( int anim ) {
+ pm->ps->legsTimer = 0;
+ PM_StartLegsAnim( anim );
+}
+
+
+/*
+==================
+PM_ClipVelocity
+
+Slide off of the impacting surface
+==================
+*/
+void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) {
+ float backoff;
+ float change;
+ int i;
+
+ backoff = DotProduct (in, normal);
+
+ if ( backoff < 0 ) {
+ backoff *= overbounce;
+ } else {
+ backoff /= overbounce;
+ }
+
+ for ( i=0 ; i<3 ; i++ ) {
+ change = normal[i]*backoff;
+ out[i] = in[i] - change;
+ }
+}
+
+
+/*
+==================
+PM_Friction
+
+Handles both ground friction and water friction
+==================
+*/
+static void PM_Friction( void ) {
+ vec3_t vec;
+ float *vel;
+ float speed, newspeed, control;
+ float drop;
+
+ vel = pm->ps->velocity;
+
+ VectorCopy( vel, vec );
+ if ( pml.walking ) {
+ vec[2] = 0; // ignore slope movement
+ }
+
+ speed = VectorLength(vec);
+ if (speed < 1) {
+ vel[0] = 0;
+ vel[1] = 0; // allow sinking underwater
+ // FIXME: still have z friction underwater?
+ return;
+ }
+
+ drop = 0;
+
+ // apply ground friction
+ if ( pm->waterlevel <= 1 ) {
+ if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) {
+ // if getting knocked back, no friction
+ if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) {
+ control = speed < pm_stopspeed ? pm_stopspeed : speed;
+ drop += control*pm_friction*pml.frametime;
+ }
+ }
+ }
+
+ // apply water friction even if just wading
+ if ( pm->waterlevel ) {
+ drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
+ }
+
+ // apply flying friction
+ if ( pm->ps->powerups[PW_FLIGHT]) {
+ drop += speed*pm_flightfriction*pml.frametime;
+ }
+
+ if ( pm->ps->pm_type == PM_SPECTATOR) {
+ drop += speed*pm_spectatorfriction*pml.frametime;
+ }
+
+ // scale the velocity
+ newspeed = speed - drop;
+ if (newspeed < 0) {
+ newspeed = 0;
+ }
+ newspeed /= speed;
+
+ vel[0] = vel[0] * newspeed;
+ vel[1] = vel[1] * newspeed;
+ vel[2] = vel[2] * newspeed;
+}
+
+
+/*
+==============
+PM_Accelerate
+
+TODO: bunny hoping
+
+Handles user intended acceleration
+==============
+*/
+static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) {
+if(! (pm->pmove_flags & DF_NO_BUNNY) ) {
+//#if 1
+
+ // q2 style
+ int i;
+ float addspeed, accelspeed, currentspeed;
+
+ currentspeed = DotProduct (pm->ps->velocity, wishdir);
+ addspeed = wishspeed - currentspeed;
+ if (addspeed <= 0) {
+ return;
+ }
+ accelspeed = accel*pml.frametime*wishspeed;
+ if (accelspeed > addspeed) {
+ accelspeed = addspeed;
+ }
+
+ for (i=0 ; i<3 ; i++) {
+ pm->ps->velocity[i] += accelspeed*wishdir[i];
+ }
+} else {
+ //#else
+ // proper way (avoids strafe jump maxspeed bug), but feels bad
+ vec3_t wishVelocity;
+ vec3_t pushDir;
+ float pushLen;
+ float canPush;
+
+ VectorScale( wishdir, wishspeed, wishVelocity );
+ VectorSubtract( wishVelocity, pm->ps->velocity, pushDir );
+ pushLen = VectorNormalize( pushDir );
+
+ canPush = accel*pml.frametime*wishspeed;
+ if (canPush > pushLen) {
+ canPush = pushLen;
+ }
+
+ VectorMA( pm->ps->velocity, canPush, pushDir, pm->ps->velocity );
+}
+//#endif
+}
+
+
+
+/*
+============
+PM_CmdScale
+
+Returns the scale factor to apply to cmd movements
+This allows the clients to use axial -127 to 127 values for all directions
+without getting a sqrt(2) distortion in speed.
+============
+*/
+static float PM_CmdScale( usercmd_t *cmd ) {
+ int max;
+ float total;
+ float scale;
+
+ max = abs( cmd->forwardmove );
+ if ( abs( cmd->rightmove ) > max ) {
+ max = abs( cmd->rightmove );
+ }
+ if ( abs( cmd->upmove ) > max ) {
+ max = abs( cmd->upmove );
+ }
+ if ( !max ) {
+ return 0;
+ }
+
+ total = sqrt( cmd->forwardmove * cmd->forwardmove
+ + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove );
+ scale = (float)pm->ps->speed * max / ( 127.0 * total );
+
+ return scale;
+}
+
+
+/*
+================
+PM_SetMovementDir
+
+Determine the rotation of the legs reletive
+to the facing dir
+================
+*/
+static void PM_SetMovementDir( void ) {
+ if ( pm->cmd.forwardmove || pm->cmd.rightmove ) {
+ if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove > 0 ) {
+ pm->ps->movementDir = 0;
+ } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove > 0 ) {
+ pm->ps->movementDir = 1;
+ } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove == 0 ) {
+ pm->ps->movementDir = 2;
+ } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove < 0 ) {
+ pm->ps->movementDir = 3;
+ } else if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove < 0 ) {
+ pm->ps->movementDir = 4;
+ } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove < 0 ) {
+ pm->ps->movementDir = 5;
+ } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove == 0 ) {
+ pm->ps->movementDir = 6;
+ } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove > 0 ) {
+ pm->ps->movementDir = 7;
+ }
+ } else {
+ // if they aren't actively going directly sideways,
+ // change the animation to the diagonal so they
+ // don't stop too crooked
+ if ( pm->ps->movementDir == 2 ) {
+ pm->ps->movementDir = 1;
+ } else if ( pm->ps->movementDir == 6 ) {
+ pm->ps->movementDir = 7;
+ }
+ }
+}
+
+
+/*
+=============
+PM_CheckJump
+=============
+*/
+static qboolean PM_CheckJump( void ) {
+
+
+ if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
+ return qfalse; // don't allow jump until all buttons are up
+ }
+
+ if ( pm->cmd.upmove < 10 ) {
+ // not holding jump
+ return qfalse;
+ }
+
+
+ // must wait for jump to be released
+ if ( pm->ps->pm_flags & PMF_JUMP_HELD ) {
+ // clear upmove so cmdscale doesn't lower running speed
+ pm->cmd.upmove = 0;
+ return qfalse;
+ }
+
+
+
+
+ pml.groundPlane = qfalse; // jumping away
+ pml.walking = qfalse;
+ pm->ps->pm_flags |= PMF_JUMP_HELD;
+
+ pm->ps->groundEntityNum = ENTITYNUM_NONE;
+ pm->ps->velocity[2] = JUMP_VELOCITY;
+ PM_AddEvent( EV_JUMP );
+
+ if ( pm->cmd.forwardmove >= 0 ) {
+ PM_ForceLegsAnim( LEGS_JUMP );
+ pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
+ } else {
+ PM_ForceLegsAnim( LEGS_JUMPB );
+ pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
+ }
+
+ return qtrue;
+}
+
+/*
+=============
+PM_CheckWaterJump
+=============
+*/
+static qboolean PM_CheckWaterJump( void ) {
+ vec3_t spot;
+ int cont;
+ vec3_t flatforward;
+
+ if (pm->ps->pm_time) {
+ return qfalse;
+ }
+
+ // check for water jump
+ if ( pm->waterlevel != 2 ) {
+ return qfalse;
+ }
+
+ flatforward[0] = pml.forward[0];
+ flatforward[1] = pml.forward[1];
+ flatforward[2] = 0;
+ VectorNormalize (flatforward);
+
+ VectorMA (pm->ps->origin, 30, flatforward, spot);
+ spot[2] += 4;
+ cont = pm->pointcontents (spot, pm->ps->clientNum );
+ if ( !(cont & CONTENTS_SOLID) ) {
+ return qfalse;
+ }
+
+ spot[2] += 16;
+ cont = pm->pointcontents (spot, pm->ps->clientNum );
+ if ( cont & (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY) ) {
+ return qfalse;
+ }
+
+ // jump out of water
+ VectorScale (pml.forward, 200, pm->ps->velocity);
+ pm->ps->velocity[2] = 350;
+
+ pm->ps->pm_flags |= PMF_TIME_WATERJUMP;
+ pm->ps->pm_time = 2000;
+
+ return qtrue;
+}
+
+//============================================================================
+
+
+/*
+===================
+PM_WaterJumpMove
+
+Flying out of the water
+===================
+*/
+static void PM_WaterJumpMove( void ) {
+ // waterjump has no control, but falls
+
+ PM_StepSlideMove( qtrue );
+
+ pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
+ if (pm->ps->velocity[2] < 0) {
+ // cancel as soon as we are falling down again
+ pm->ps->pm_flags &= ~PMF_ALL_TIMES;
+ pm->ps->pm_time = 0;
+ }
+}
+
+/*
+===================
+PM_WaterMove
+
+===================
+*/
+static void PM_WaterMove( void ) {
+ int i;
+ vec3_t wishvel;
+ float wishspeed;
+ vec3_t wishdir;
+ float scale;
+ float vel;
+
+ if ( PM_CheckWaterJump() ) {
+ PM_WaterJumpMove();
+ return;
+ }
+#if 0
+ // jump = head for surface
+ if ( pm->cmd.upmove >= 10 ) {
+ if (pm->ps->velocity[2] > -300) {
+ if ( pm->watertype == CONTENTS_WATER ) {
+ pm->ps->velocity[2] = 100;
+ } else if (pm->watertype == CONTENTS_SLIME) {
+ pm->ps->velocity[2] = 80;
+ } else {
+ pm->ps->velocity[2] = 50;
+ }
+ }
+ }
+#endif
+ PM_Friction ();
+
+ scale = PM_CmdScale( &pm->cmd );
+ //
+ // user intentions
+ //
+ if ( !scale ) {
+ wishvel[0] = 0;
+ wishvel[1] = 0;
+ wishvel[2] = -60; // sink towards bottom
+ } else {
+ for (i=0 ; i<3 ; i++)
+ wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;
+
+ wishvel[2] += scale * pm->cmd.upmove;
+ }
+
+ VectorCopy (wishvel, wishdir);
+ wishspeed = VectorNormalize(wishdir);
+
+ if ( wishspeed > pm->ps->speed * pm_swimScale ) {
+ wishspeed = pm->ps->speed * pm_swimScale;
+ }
+
+ PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);
+
+ // make sure we can go up slopes easily under water
+ if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) {
+ vel = VectorLength(pm->ps->velocity);
+ // slide along the ground plane
+ PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
+ pm->ps->velocity, OVERCLIP );
+
+ VectorNormalize(pm->ps->velocity);
+ VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
+ }
+
+ PM_SlideMove( qfalse );
+}
+
+/*
+===================
+PM_InvulnerabilityMove
+
+Only with the invulnerability powerup
+===================
+*/
+static void PM_InvulnerabilityMove( void ) {
+ pm->cmd.forwardmove = 0;
+ pm->cmd.rightmove = 0;
+ pm->cmd.upmove = 0;
+ VectorClear(pm->ps->velocity);
+}
+
+/*
+===================
+PM_FlyMove
+
+Only with the flight powerup
+===================
+*/
+static void PM_FlyMove( void ) {
+ int i;
+ vec3_t wishvel;
+ float wishspeed;
+ vec3_t wishdir;
+ float scale;
+
+ // normal slowdown
+ PM_Friction ();
+
+ scale = PM_CmdScale( &pm->cmd );
+ //
+ // user intentions
+ //
+ if ( !scale ) {
+ wishvel[0] = 0;
+ wishvel[1] = 0;
+ wishvel[2] = 0;
+ } else {
+ for (i=0 ; i<3 ; i++) {
+ wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;
+ }
+
+ wishvel[2] += scale * pm->cmd.upmove;
+ }
+
+ VectorCopy (wishvel, wishdir);
+ wishspeed = VectorNormalize(wishdir);
+
+ PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate);
+
+ PM_StepSlideMove( qfalse );
+}
+
+
+/*
+===================
+PM_AirMove
+
+===================
+*/
+static void PM_AirMove( void ) {
+ int i;
+ vec3_t wishvel;
+ float fmove, smove;
+ vec3_t wishdir;
+ float wishspeed;
+ float scale;
+ usercmd_t cmd;
+
+ PM_Friction();
+
+ fmove = pm->cmd.forwardmove;
+ smove = pm->cmd.rightmove;
+
+ cmd = pm->cmd;
+ scale = PM_CmdScale( &cmd );
+
+ // set the movementDir so clients can rotate the legs for strafing
+ PM_SetMovementDir();
+
+ // project moves down to flat plane
+ pml.forward[2] = 0;
+ pml.right[2] = 0;
+ VectorNormalize (pml.forward);
+ VectorNormalize (pml.right);
+
+ for ( i = 0 ; i < 2 ; i++ ) {
+ wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
+ }
+ wishvel[2] = 0;
+
+ VectorCopy (wishvel, wishdir);
+ wishspeed = VectorNormalize(wishdir);
+ wishspeed *= scale;
+
+ // not on ground, so little effect on velocity
+ PM_Accelerate (wishdir, wishspeed, pm_airaccelerate);
+
+ // we may have a ground plane that is very steep, even
+ // though we don't have a groundentity
+ // slide along the steep plane
+ if ( pml.groundPlane ) {
+ PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
+ pm->ps->velocity, OVERCLIP );
+ }
+
+#if 0
+ //ZOID: If we are on the grapple, try stair-stepping
+ //this allows a player to use the grapple to pull himself
+ //over a ledge
+ if (pm->ps->pm_flags & PMF_GRAPPLE_PULL)
+ PM_StepSlideMove ( qtrue );
+ else
+ PM_SlideMove ( qtrue );
+#endif
+
+ PM_StepSlideMove ( qtrue );
+}
+
+/*
+===================
+PM_GrappleMove
+
+===================
+*/
+static void PM_GrappleMove( void ) {
+ vec3_t vel, v;
+ float vlen;
+
+ VectorScale(pml.forward, -16, v);
+ VectorAdd(pm->ps->grapplePoint, v, v);
+ VectorSubtract(v, pm->ps->origin, vel);
+ vlen = VectorLength(vel);
+ VectorNormalize( vel );
+
+ if (vlen <= 100)
+ VectorScale(vel, 10 * vlen, vel);
+ else
+ VectorScale(vel, 800, vel);
+
+ VectorCopy(vel, pm->ps->velocity);
+
+ pml.groundPlane = qfalse;
+}
+
+/*
+===================
+PM_WalkMove
+
+===================
+*/
+static void PM_WalkMove( void ) {
+ int i;
+ vec3_t wishvel;
+ float fmove, smove;
+ vec3_t wishdir;
+ float wishspeed;
+ float scale;
+ usercmd_t cmd;
+ float accelerate;
+ float vel;
+
+ if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) {
+ // begin swimming
+ PM_WaterMove();
+ return;
+ }
+
+
+ if ( PM_CheckJump () ) {
+ // jumped away
+ if ( pm->waterlevel > 1 ) {
+ PM_WaterMove();
+ } else {
+ PM_AirMove();
+ }
+ return;
+ }
+
+ PM_Friction ();
+
+ fmove = pm->cmd.forwardmove;
+ smove = pm->cmd.rightmove;
+
+ cmd = pm->cmd;
+ scale = PM_CmdScale( &cmd );
+
+ // set the movementDir so clients can rotate the legs for strafing
+ PM_SetMovementDir();
+
+ // project moves down to flat plane
+ pml.forward[2] = 0;
+ pml.right[2] = 0;
+
+ // project the forward and right directions onto the ground plane
+ PM_ClipVelocity (pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP );
+ PM_ClipVelocity (pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP );
+ //
+ VectorNormalize (pml.forward);
+ VectorNormalize (pml.right);
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
+ }
+ // when going up or down slopes the wish velocity should Not be zero
+// wishvel[2] = 0;
+
+ VectorCopy (wishvel, wishdir);
+ wishspeed = VectorNormalize(wishdir);
+ wishspeed *= scale;
+
+ // clamp the speed lower if ducking
+ if ( pm->ps->pm_flags & PMF_DUCKED ) {
+ if ( wishspeed > pm->ps->speed * pm_duckScale ) {
+ wishspeed = pm->ps->speed * pm_duckScale;
+ }
+ }
+
+ // clamp the speed lower if wading or walking on the bottom
+ if ( pm->waterlevel ) {
+ float waterScale;
+
+ waterScale = pm->waterlevel / 3.0;
+ waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale;
+ if ( wishspeed > pm->ps->speed * waterScale ) {
+ wishspeed = pm->ps->speed * waterScale;
+ }
+ }
+
+ // when a player gets hit, they temporarily lose
+ // full control, which allows them to be moved a bit
+ if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
+ accelerate = pm_airaccelerate;
+ } else {
+ accelerate = pm_accelerate;
+ }
+
+ PM_Accelerate (wishdir, wishspeed, accelerate);
+
+ //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]);
+ //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity));
+
+ if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
+ pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
+ } else {
+ // don't reset the z velocity for slopes
+// pm->ps->velocity[2] = 0;
+ }
+
+ vel = VectorLength(pm->ps->velocity);
+
+ // slide along the ground plane
+ PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
+ pm->ps->velocity, OVERCLIP );
+
+ // don't decrease velocity when going up or down a slope
+ VectorNormalize(pm->ps->velocity);
+ VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
+
+ // don't do anything if standing still
+ if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) {
+ return;
+ }
+
+ PM_StepSlideMove( qfalse );
+
+ //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity));
+
+}
+
+
+/*
+==============
+PM_DeadMove
+==============
+*/
+static void PM_DeadMove( void ) {
+ float forward;
+
+ if ( !pml.walking ) {
+ return;
+ }
+
+ // extra friction
+
+ forward = VectorLength (pm->ps->velocity);
+ forward -= 20;
+ if ( forward <= 0 ) {
+ VectorClear (pm->ps->velocity);
+ } else {
+ VectorNormalize (pm->ps->velocity);
+ VectorScale (pm->ps->velocity, forward, pm->ps->velocity);
+ }
+}
+
+
+/*
+===============
+PM_NoclipMove
+===============
+*/
+static void PM_NoclipMove( void ) {
+ float speed, drop, friction, control, newspeed;
+ int i;
+ vec3_t wishvel;
+ float fmove, smove;
+ vec3_t wishdir;
+ float wishspeed;
+ float scale;
+
+ pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
+
+ // friction
+
+ speed = VectorLength (pm->ps->velocity);
+ if (speed < 1)
+ {
+ VectorCopy (vec3_origin, pm->ps->velocity);
+ }
+ else
+ {
+ drop = 0;
+
+ friction = pm_friction*1.5; // extra friction
+ control = speed < pm_stopspeed ? pm_stopspeed : speed;
+ drop += control*friction*pml.frametime;
+
+ // scale the velocity
+ newspeed = speed - drop;
+ if (newspeed < 0)
+ newspeed = 0;
+ newspeed /= speed;
+
+ VectorScale (pm->ps->velocity, newspeed, pm->ps->velocity);
+ }
+
+ // accelerate
+ scale = PM_CmdScale( &pm->cmd );
+
+ fmove = pm->cmd.forwardmove;
+ smove = pm->cmd.rightmove;
+
+ for (i=0 ; i<3 ; i++)
+ wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
+ wishvel[2] += pm->cmd.upmove;
+
+ VectorCopy (wishvel, wishdir);
+ wishspeed = VectorNormalize(wishdir);
+ wishspeed *= scale;
+
+ PM_Accelerate( wishdir, wishspeed, pm_accelerate );
+
+ // move
+ VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin);
+}
+
+//============================================================================
+
+/*
+================
+PM_FootstepForSurface
+
+Returns an event number apropriate for the groundsurface
+================
+*/
+static int PM_FootstepForSurface( void ) {
+ if ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) {
+ return 0;
+ }
+ if ( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) {
+ return EV_FOOTSTEP_METAL;
+ }
+ return EV_FOOTSTEP;
+}
+
+
+/*
+=================
+PM_CrashLand
+
+Check for hard landings that generate sound events
+=================
+*/
+static void PM_CrashLand( void ) {
+ float delta;
+ float dist;
+ float vel, acc;
+ float t;
+ float a, b, c, den;
+
+ // decide which landing animation to use
+ if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) {
+ PM_ForceLegsAnim( LEGS_LANDB );
+ } else {
+ PM_ForceLegsAnim( LEGS_LAND );
+ }
+
+ pm->ps->legsTimer = TIMER_LAND;
+
+ // calculate the exact velocity on landing
+ dist = pm->ps->origin[2] - pml.previous_origin[2];
+ vel = pml.previous_velocity[2];
+ acc = -pm->ps->gravity;
+
+ a = acc / 2;
+ b = vel;
+ c = -dist;
+
+ den = b * b - 4 * a * c;
+ if ( den < 0 ) {
+ return;
+ }
+ t = (-b - sqrt( den ) ) / ( 2 * a );
+
+ delta = vel + t * acc;
+ delta = delta*delta * 0.0001;
+
+ // ducking while falling doubles damage
+ if ( pm->ps->pm_flags & PMF_DUCKED ) {
+ delta *= 2;
+ }
+
+ // never take falling damage if completely underwater
+ if ( pm->waterlevel == 3 ) {
+ return;
+ }
+
+ // reduce falling damage if there is standing water
+ if ( pm->waterlevel == 2 ) {
+ delta *= 0.25;
+ }
+ if ( pm->waterlevel == 1 ) {
+ delta *= 0.5;
+ }
+
+ if ( delta < 1 ) {
+ return;
+ }
+
+ // create a local entity event to play the sound
+
+ // SURF_NODAMAGE is used for bounce pads where you don't ever
+ // want to take damage or play a crunch sound
+ if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) {
+ if ( delta > 60 ) {
+ PM_AddEvent( EV_FALL_FAR );
+ } else if ( delta > 40 ) {
+ // this is a pain grunt, so don't play it if dead
+ if ( pm->ps->stats[STAT_HEALTH] > 0 ) {
+ PM_AddEvent( EV_FALL_MEDIUM );
+ }
+ } else if ( delta > 7 ) {
+ PM_AddEvent( EV_FALL_SHORT );
+ } else {
+ PM_AddEvent( PM_FootstepForSurface() );
+ }
+ }
+
+ // start footstep cycle over
+ pm->ps->bobCycle = 0;
+}
+
+/*
+=============
+PM_CheckStuck
+=============
+*/
+/*
+void PM_CheckStuck(void) {
+ trace_t trace;
+
+ pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask);
+ if (trace.allsolid) {
+ //int shit = qtrue;
+ }
+}
+*/
+
+/*
+=============
+PM_CorrectAllSolid
+=============
+*/
+static int PM_CorrectAllSolid( trace_t *trace ) {
+ int i, j, k;
+ vec3_t point;
+
+ if ( pm->debugLevel ) {
+ Com_Printf("%i:allsolid\n", c_pmove);
+ }
+
+ // jitter around
+ for (i = -1; i <= 1; i++) {
+ for (j = -1; j <= 1; j++) {
+ for (k = -1; k <= 1; k++) {
+ VectorCopy(pm->ps->origin, point);
+ point[0] += (float) i;
+ point[1] += (float) j;
+ point[2] += (float) k;
+ pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
+ if ( !trace->allsolid ) {
+ point[0] = pm->ps->origin[0];
+ point[1] = pm->ps->origin[1];
+ point[2] = pm->ps->origin[2] - 0.25;
+
+ pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
+ pml.groundTrace = *trace;
+ return qtrue;
+ }
+ }
+ }
+ }
+
+ pm->ps->groundEntityNum = ENTITYNUM_NONE;
+ pml.groundPlane = qfalse;
+ pml.walking = qfalse;
+
+ return qfalse;
+}
+
+
+/*
+=============
+PM_GroundTraceMissed
+
+The ground trace didn't hit a surface, so we are in freefall
+=============
+*/
+static void PM_GroundTraceMissed( void ) {
+ trace_t trace;
+ vec3_t point;
+
+ if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) {
+ // we just transitioned into freefall
+ if ( pm->debugLevel ) {
+ Com_Printf("%i:lift\n", c_pmove);
+ }
+
+ // if they aren't in a jumping animation and the ground is a ways away, force into it
+ // if we didn't do the trace, the player would be backflipping down staircases
+ VectorCopy( pm->ps->origin, point );
+ point[2] -= 64;
+
+ pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
+ if ( trace.fraction == 1.0 ) {
+ if ( pm->cmd.forwardmove >= 0 ) {
+ PM_ForceLegsAnim( LEGS_JUMP );
+ pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
+ } else {
+ PM_ForceLegsAnim( LEGS_JUMPB );
+ pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
+ }
+ }
+ }
+
+ pm->ps->groundEntityNum = ENTITYNUM_NONE;
+ pml.groundPlane = qfalse;
+ pml.walking = qfalse;
+}
+
+
+/*
+=============
+PM_GroundTrace
+=============
+*/
+static void PM_GroundTrace( void ) {
+ vec3_t point;
+ trace_t trace;
+
+ point[0] = pm->ps->origin[0];
+ point[1] = pm->ps->origin[1];
+ point[2] = pm->ps->origin[2] - 0.25;
+
+ pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
+ pml.groundTrace = trace;
+
+ // do something corrective if the trace starts in a solid...
+ if ( trace.allsolid ) {
+ if ( !PM_CorrectAllSolid(&trace) )
+ return;
+ }
+
+ // if the trace didn't hit anything, we are in free fall
+ if ( trace.fraction == 1.0 ) {
+ PM_GroundTraceMissed();
+ pml.groundPlane = qfalse;
+ pml.walking = qfalse;
+ return;
+ }
+
+ // check if getting thrown off the ground
+ if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) {
+ if ( pm->debugLevel ) {
+ Com_Printf("%i:kickoff\n", c_pmove);
+ }
+ // go into jump animation
+ if ( pm->cmd.forwardmove >= 0 ) {
+ PM_ForceLegsAnim( LEGS_JUMP );
+ pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
+ } else {
+ PM_ForceLegsAnim( LEGS_JUMPB );
+ pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
+ }
+
+ pm->ps->groundEntityNum = ENTITYNUM_NONE;
+ pml.groundPlane = qfalse;
+ pml.walking = qfalse;
+ return;
+ }
+
+ // slopes that are too steep will not be considered onground
+ if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) {
+ if ( pm->debugLevel ) {
+ Com_Printf("%i:steep\n", c_pmove);
+ }
+ // FIXME: if they can't slide down the slope, let them
+ // walk (sharp crevices)
+ pm->ps->groundEntityNum = ENTITYNUM_NONE;
+ pml.groundPlane = qtrue;
+ pml.walking = qfalse;
+ return;
+ }
+
+ pml.groundPlane = qtrue;
+ pml.walking = qtrue;
+
+ // hitting solid ground will end a waterjump
+ if (pm->ps->pm_flags & PMF_TIME_WATERJUMP)
+ {
+ pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND);
+ pm->ps->pm_time = 0;
+ }
+
+ if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
+ // just hit the ground
+ if ( pm->debugLevel ) {
+ Com_Printf("%i:Land\n", c_pmove);
+ }
+
+ PM_CrashLand();
+
+ // don't do landing time if we were just going down a slope
+ if ( pml.previous_velocity[2] < -200 ) {
+ // don't allow another jump for a little while
+ pm->ps->pm_flags |= PMF_TIME_LAND;
+ pm->ps->pm_time = 250;
+ }
+ }
+
+ pm->ps->groundEntityNum = trace.entityNum;
+
+ // don't reset the z velocity for slopes
+// pm->ps->velocity[2] = 0;
+
+ PM_AddTouchEnt( trace.entityNum );
+}
+
+
+/*
+=============
+PM_SetWaterLevel FIXME: avoid this twice? certainly if not moving
+=============
+*/
+static void PM_SetWaterLevel( void ) {
+ vec3_t point;
+ int cont;
+ int sample1;
+ int sample2;
+
+ //
+ // get waterlevel, accounting for ducking
+ //
+ pm->waterlevel = 0;
+ pm->watertype = 0;
+
+ point[0] = pm->ps->origin[0];
+ point[1] = pm->ps->origin[1];
+ point[2] = pm->ps->origin[2] + MINS_Z + 1;
+ cont = pm->pointcontents( point, pm->ps->clientNum );
+
+ if ( cont & MASK_WATER ) {
+ sample2 = pm->ps->viewheight - MINS_Z;
+ sample1 = sample2 / 2;
+
+ pm->watertype = cont;
+ pm->waterlevel = 1;
+ point[2] = pm->ps->origin[2] + MINS_Z + sample1;
+ cont = pm->pointcontents (point, pm->ps->clientNum );
+ if ( cont & MASK_WATER ) {
+ pm->waterlevel = 2;
+ point[2] = pm->ps->origin[2] + MINS_Z + sample2;
+ cont = pm->pointcontents (point, pm->ps->clientNum );
+ if ( cont & MASK_WATER ){
+ pm->waterlevel = 3;
+ }
+ }
+ }
+
+}
+
+/*
+==============
+PM_CheckDuck
+
+Sets mins, maxs, and pm->ps->viewheight
+==============
+*/
+static void PM_CheckDuck (void)
+{
+ trace_t trace;
+
+ if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
+ if ( pm->ps->pm_flags & PMF_INVULEXPAND ) {
+ // invulnerability sphere has a 42 units radius
+ VectorSet( pm->mins, -42, -42, -42 );
+ VectorSet( pm->maxs, 42, 42, 42 );
+ }
+ else {
+ VectorSet( pm->mins, -15, -15, MINS_Z );
+ VectorSet( pm->maxs, 15, 15, 16 );
+ }
+ pm->ps->pm_flags |= PMF_DUCKED;
+ pm->ps->viewheight = CROUCH_VIEWHEIGHT;
+ return;
+ }
+ pm->ps->pm_flags &= ~PMF_INVULEXPAND;
+
+ pm->mins[0] = -15;
+ pm->mins[1] = -15;
+
+ pm->maxs[0] = 15;
+ pm->maxs[1] = 15;
+
+ pm->mins[2] = MINS_Z;
+
+ if (pm->ps->pm_type == PM_DEAD)
+ {
+ pm->maxs[2] = -8;
+ pm->ps->viewheight = DEAD_VIEWHEIGHT;
+ return;
+ }
+
+ if (pm->cmd.upmove < 0)
+ { // duck
+ pm->ps->pm_flags |= PMF_DUCKED;
+ }
+ else
+ { // stand up if possible
+ if (pm->ps->pm_flags & PMF_DUCKED)
+ {
+ // try to stand up
+ pm->maxs[2] = 32;
+ pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask );
+ if (!trace.allsolid)
+ pm->ps->pm_flags &= ~PMF_DUCKED;
+ }
+ }
+
+ if (pm->ps->pm_flags & PMF_DUCKED)
+ {
+ pm->maxs[2] = 16;
+ pm->ps->viewheight = CROUCH_VIEWHEIGHT;
+ }
+ else
+ {
+ pm->maxs[2] = 32;
+ pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
+ }
+}
+
+
+
+//===================================================================
+
+
+/*
+===============
+PM_Footsteps
+===============
+*/
+static void PM_Footsteps( void ) {
+ float bobmove;
+ int old;
+ qboolean footstep;
+
+ //
+ // calculate speed and cycle to be used for
+ // all cyclic walking effects
+ //
+ pm->xyspeed = sqrt( pm->ps->velocity[0] * pm->ps->velocity[0]
+ + pm->ps->velocity[1] * pm->ps->velocity[1] );
+
+ if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
+
+ if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
+ PM_ContinueLegsAnim( LEGS_IDLECR );
+ }
+ // airborne leaves position in cycle intact, but doesn't advance
+ if ( pm->waterlevel > 1 ) {
+ PM_ContinueLegsAnim( LEGS_SWIM );
+ }
+ return;
+ }
+
+ // if not trying to move
+ if ( !pm->cmd.forwardmove && !pm->cmd.rightmove ) {
+ if ( pm->xyspeed < 5 ) {
+ pm->ps->bobCycle = 0; // start at beginning of cycle again
+ if ( pm->ps->pm_flags & PMF_DUCKED ) {
+ PM_ContinueLegsAnim( LEGS_IDLECR );
+ } else {
+ PM_ContinueLegsAnim( LEGS_IDLE );
+ }
+ }
+ return;
+ }
+
+
+ footstep = qfalse;
+
+ if ( pm->ps->pm_flags & PMF_DUCKED ) {
+ bobmove = 0.5; // ducked characters bob much faster
+ if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
+ PM_ContinueLegsAnim( LEGS_BACKCR );
+ }
+ else {
+ PM_ContinueLegsAnim( LEGS_WALKCR );
+ }
+ // ducked characters never play footsteps
+ /*
+ } else if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
+ if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
+ bobmove = 0.4; // faster speeds bob faster
+ footstep = qtrue;
+ } else {
+ bobmove = 0.3;
+ }
+ PM_ContinueLegsAnim( LEGS_BACK );
+ */
+ } else {
+ if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
+ bobmove = 0.4f; // faster speeds bob faster
+ if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
+ PM_ContinueLegsAnim( LEGS_BACK );
+ }
+ else {
+ PM_ContinueLegsAnim( LEGS_RUN );
+ }
+ footstep = qtrue;
+ } else {
+ bobmove = 0.3f; // walking bobs slow
+ if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
+ PM_ContinueLegsAnim( LEGS_BACKWALK );
+ }
+ else {
+ PM_ContinueLegsAnim( LEGS_WALK );
+ }
+ }
+ }
+
+ // check for footstep / splash sounds
+ old = pm->ps->bobCycle;
+ pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255;
+
+ // if we just crossed a cycle boundary, play an apropriate footstep event
+ if ( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) {
+ if ( pm->waterlevel == 0 ) {
+ // on ground will only play sounds if running
+ if ( footstep && !pm->noFootsteps ) {
+ PM_AddEvent( PM_FootstepForSurface() );
+ }
+ } else if ( pm->waterlevel == 1 ) {
+ // splashing
+ PM_AddEvent( EV_FOOTSPLASH );
+ } else if ( pm->waterlevel == 2 ) {
+ // wading / swimming at surface
+ PM_AddEvent( EV_SWIM );
+ } else if ( pm->waterlevel == 3 ) {
+ // no sound when completely underwater
+
+ }
+ }
+}
+
+/*
+==============
+PM_WaterEvents
+
+Generate sound events for entering and leaving water
+==============
+*/
+static void PM_WaterEvents( void ) { // FIXME?
+ //
+ // if just entered a water volume, play a sound
+ //
+ if (!pml.previous_waterlevel && pm->waterlevel) {
+ PM_AddEvent( EV_WATER_TOUCH );
+ }
+
+ //
+ // if just completely exited a water volume, play a sound
+ //
+ if (pml.previous_waterlevel && !pm->waterlevel) {
+ PM_AddEvent( EV_WATER_LEAVE );
+ }
+
+ //
+ // check for head just going under water
+ //
+ if (pml.previous_waterlevel != 3 && pm->waterlevel == 3) {
+ PM_AddEvent( EV_WATER_UNDER );
+ }
+
+ //
+ // check for head just coming out of water
+ //
+ if (pml.previous_waterlevel == 3 && pm->waterlevel != 3) {
+ PM_AddEvent( EV_WATER_CLEAR );
+ }
+}
+
+
+/*
+===============
+PM_BeginWeaponChange
+===============
+*/
+static void PM_BeginWeaponChange( int weapon ) {
+ if ( weapon <= WP_NONE || weapon >= WP_NUM_WEAPONS ) {
+ return;
+ }
+
+ if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
+ return;
+ }
+
+ if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
+ return;
+ }
+
+ if(pm->pmove_flags & DF_INSTANT_WEAPON_CHANGE)
+ {
+ pm->ps->weaponstate = WEAPON_DROPPING;
+ } else
+ {
+ PM_AddEvent( EV_CHANGE_WEAPON );
+ pm->ps->weaponstate = WEAPON_DROPPING;
+ pm->ps->weaponTime += 200;
+ PM_StartTorsoAnim( TORSO_DROP );
+ }
+}
+
+
+/*
+===============
+PM_FinishWeaponChange
+===============
+*/
+static void PM_FinishWeaponChange( void ) {
+ int weapon;
+
+ weapon = pm->cmd.weapon;
+ if ( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) {
+ weapon = WP_NONE;
+ }
+
+ if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
+ weapon = WP_NONE;
+ }
+
+ pm->ps->weapon = weapon;
+ pm->ps->weaponstate = WEAPON_RAISING;
+ if(! (pm->pmove_flags & DF_INSTANT_WEAPON_CHANGE))
+ {
+ pm->ps->weaponTime += 250;
+ PM_StartTorsoAnim( TORSO_RAISE );
+ }
+}
+
+
+/*
+==============
+PM_TorsoAnimation
+
+==============
+*/
+static void PM_TorsoAnimation( void ) {
+ if ( pm->ps->weaponstate == WEAPON_READY ) {
+ if ( pm->ps->weapon == WP_GAUNTLET ) {
+ PM_ContinueTorsoAnim( TORSO_STAND2 );
+ } else {
+ PM_ContinueTorsoAnim( TORSO_STAND );
+ }
+ return;
+ }
+}
+
+
+/*
+==============
+PM_Weapon
+
+Generates weapon events and modifes the weapon counter
+
+Elimination TODO:
+Make this thing stop during warmup (done)
+==============
+*/
+static void PM_Weapon( void ) {
+ int addTime;
+
+ // don't allow attack until all buttons are up
+ if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
+ return;
+ }
+
+ // ignore if spectator
+ if ( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR || pm->ps->pm_type == PM_SPECTATOR) {
+ return;
+ }
+
+ // check for dead player
+ if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
+ pm->ps->weapon = WP_NONE;
+ return;
+ }
+
+ // check for item using
+ if ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) {
+ if ( ! ( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) {
+ if ( bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_MEDKIT
+ && pm->ps->stats[STAT_HEALTH] >= (pm->ps->stats[STAT_MAX_HEALTH] + 25) ) {
+ // don't use medkit if at max health
+ } else {
+ pm->ps->pm_flags |= PMF_USE_ITEM_HELD;
+ PM_AddEvent( EV_USE_ITEM0 + bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag );
+ pm->ps->stats[STAT_HOLDABLE_ITEM] = 0;
+ }
+ return;
+ }
+ } else {
+ pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD;
+ }
+
+
+ // make weapon function
+ if ( pm->ps->weaponTime > 0 ) {
+ pm->ps->weaponTime -= pml.msec;
+ }
+
+ // check for weapon change
+ // can't change if weapon is firing, but can change
+ // again if lowering or raising
+ if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) {
+ if ( pm->ps->weapon != pm->cmd.weapon ) {
+ PM_BeginWeaponChange( pm->cmd.weapon );
+ }
+ }
+
+ if ( pm->ps->weaponTime > 0 ) {
+ return;
+ }
+
+ // change weapon if time
+ if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
+ PM_FinishWeaponChange();
+ return;
+ }
+
+ if ( pm->ps->weaponstate == WEAPON_RAISING ) {
+ pm->ps->weaponstate = WEAPON_READY;
+ if ( pm->ps->weapon == WP_GAUNTLET ) {
+ PM_StartTorsoAnim( TORSO_STAND2 );
+ } else {
+ PM_StartTorsoAnim( TORSO_STAND );
+ }
+ return;
+ }
+
+ // check for fire
+ if ( ! (pm->cmd.buttons & BUTTON_ATTACK) ) {
+ pm->ps->weaponTime = 0;
+ pm->ps->weaponstate = WEAPON_READY;
+ return;
+ }
+
+ // start the animation even if out of ammo
+ if ( pm->ps->weapon == WP_GAUNTLET ) {
+ // the guantlet only "fires" when it actually hits something
+ if ( !pm->gauntletHit ) {
+ pm->ps->weaponTime = 0;
+ pm->ps->weaponstate = WEAPON_READY;
+ return;
+ }
+ PM_StartTorsoAnim( TORSO_ATTACK2 );
+ } else {
+ PM_StartTorsoAnim( TORSO_ATTACK );
+ }
+
+ pm->ps->weaponstate = WEAPON_FIRING;
+
+ // check for out of ammo
+ if ( ! pm->ps->ammo[ pm->ps->weapon ] ) {
+ PM_AddEvent( EV_NOAMMO );
+ pm->ps->weaponTime += 500;
+ return;
+ }
+
+ // take an ammo away if not infinite, 999 or up
+ if ( !(pm->ps->ammo[ pm->ps->weapon ] == -1 || pm->ps->ammo[ pm->ps->weapon ] >=999 )) {
+ pm->ps->ammo[ pm->ps->weapon ]--;
+ }
+
+ // fire weapon
+ PM_AddEvent( EV_FIRE_WEAPON );
+
+ switch( pm->ps->weapon ) {
+ default:
+ case WP_GAUNTLET:
+ addTime = 400;
+ break;
+ case WP_LIGHTNING:
+ addTime = 50;
+ break;
+ case WP_SHOTGUN:
+ addTime = 1000;
+ break;
+ case WP_MACHINEGUN:
+ addTime = 100;
+ break;
+ case WP_GRENADE_LAUNCHER:
+ addTime = 800;
+ break;
+ case WP_ROCKET_LAUNCHER:
+ addTime = 800;
+ break;
+ case WP_PLASMAGUN:
+ addTime = 100;
+ break;
+ case WP_RAILGUN:
+ addTime = 1500;
+ break;
+ case WP_BFG:
+ addTime = 200;
+ break;
+ case WP_GRAPPLING_HOOK:
+ addTime = 400;
+ break;
+ case WP_NAILGUN:
+ addTime = 1000;
+ break;
+ case WP_PROX_LAUNCHER:
+ addTime = 800;
+ break;
+ case WP_CHAINGUN:
+ addTime = 30;
+ break;
+ }
+
+ if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
+ addTime /= 1.5;
+ }
+ else
+ if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
+ addTime /= 1.3;
+ }
+ else
+ if ( pm->ps->powerups[PW_HASTE] ) {
+ addTime /= 1.3;
+ }
+
+ pm->ps->weaponTime += addTime;
+}
+
+/*
+================
+PM_Animate
+================
+*/
+
+static void PM_Animate( void ) {
+ if ( pm->cmd.buttons & BUTTON_GESTURE ) {
+ if ( pm->ps->torsoTimer == 0 ) {
+ PM_StartTorsoAnim( TORSO_GESTURE );
+ pm->ps->torsoTimer = TIMER_GESTURE;
+ PM_AddEvent( EV_TAUNT );
+ }
+ } else if ( pm->cmd.buttons & BUTTON_GETFLAG ) {
+ if ( pm->ps->torsoTimer == 0 ) {
+ PM_StartTorsoAnim( TORSO_GETFLAG );
+ pm->ps->torsoTimer = 600; //TIMER_GESTURE;
+ }
+ } else if ( pm->cmd.buttons & BUTTON_GUARDBASE ) {
+ if ( pm->ps->torsoTimer == 0 ) {
+ PM_StartTorsoAnim( TORSO_GUARDBASE );
+ pm->ps->torsoTimer = 600; //TIMER_GESTURE;
+ }
+ } else if ( pm->cmd.buttons & BUTTON_PATROL ) {
+ if ( pm->ps->torsoTimer == 0 ) {
+ PM_StartTorsoAnim( TORSO_PATROL );
+ pm->ps->torsoTimer = 600; //TIMER_GESTURE;
+ }
+ } else if ( pm->cmd.buttons & BUTTON_FOLLOWME ) {
+ if ( pm->ps->torsoTimer == 0 ) {
+ PM_StartTorsoAnim( TORSO_FOLLOWME );
+ pm->ps->torsoTimer = 600; //TIMER_GESTURE;
+ }
+ } else if ( pm->cmd.buttons & BUTTON_AFFIRMATIVE ) {
+ if ( pm->ps->torsoTimer == 0 ) {
+ PM_StartTorsoAnim( TORSO_AFFIRMATIVE);
+ pm->ps->torsoTimer = 600; //TIMER_GESTURE;
+ }
+ } else if ( pm->cmd.buttons & BUTTON_NEGATIVE ) {
+ if ( pm->ps->torsoTimer == 0 ) {
+ PM_StartTorsoAnim( TORSO_NEGATIVE );
+ pm->ps->torsoTimer = 600; //TIMER_GESTURE;
+ }
+ }
+}
+
+
+/*
+================
+PM_DropTimers
+================
+*/
+static void PM_DropTimers( void ) {
+ // drop misc timing counter
+ if ( pm->ps->pm_time ) {
+ if ( pml.msec >= pm->ps->pm_time ) {
+ pm->ps->pm_flags &= ~PMF_ALL_TIMES;
+ pm->ps->pm_time = 0;
+ } else {
+ pm->ps->pm_time -= pml.msec;
+ }
+ }
+
+ // drop animation counter
+ if ( pm->ps->legsTimer > 0 ) {
+ pm->ps->legsTimer -= pml.msec;
+ if ( pm->ps->legsTimer < 0 ) {
+ pm->ps->legsTimer = 0;
+ }
+ }
+
+ if ( pm->ps->torsoTimer > 0 ) {
+ pm->ps->torsoTimer -= pml.msec;
+ if ( pm->ps->torsoTimer < 0 ) {
+ pm->ps->torsoTimer = 0;
+ }
+ }
+}
+
+/*
+================
+PM_UpdateViewAngles
+
+This can be used as another entry point when only the viewangles
+are being updated isntead of a full move
+================
+*/
+void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) {
+ short temp;
+ int i;
+
+ if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) {
+ return; // no view changes at all
+ }
+
+ if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) {
+ return; // no view changes at all
+ }
+
+ // circularly clamp the angles with deltas
+ for (i=0 ; i<3 ; i++) {
+ temp = cmd->angles[i] + ps->delta_angles[i];
+ if ( i == PITCH ) {
+ // don't let the player look up or down more than 90 degrees
+ if ( temp > 16000 ) {
+ ps->delta_angles[i] = 16000 - cmd->angles[i];
+ temp = 16000;
+ } else if ( temp < -16000 ) {
+ ps->delta_angles[i] = -16000 - cmd->angles[i];
+ temp = -16000;
+ }
+ }
+ ps->viewangles[i] = SHORT2ANGLE(temp);
+ }
+
+}
+
+
+/*
+================
+PmoveSingle
+
+================
+*/
+void trap_SnapVector( float *v );
+
+void PmoveSingle (pmove_t *pmove) {
+ pm = pmove;
+
+ // this counter lets us debug movement problems with a journal
+ // by setting a conditional breakpoint fot the previous frame
+ c_pmove++;
+
+ // clear results
+ pm->numtouch = 0;
+ pm->watertype = 0;
+ pm->waterlevel = 0;
+
+ if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
+ pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies
+ }
+
+ // make sure walking button is clear if they are running, to avoid
+ // proxy no-footsteps cheats
+ if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) {
+ pm->cmd.buttons &= ~BUTTON_WALKING;
+ }
+
+ // set the talk balloon flag
+ if ( pm->cmd.buttons & BUTTON_TALK ) {
+ pm->ps->eFlags |= EF_TALK;
+ } else {
+ pm->ps->eFlags &= ~EF_TALK;
+ }
+
+ // set the firing flag for continuous beam weapons
+ if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION && pm->ps->pm_type != PM_NOCLIP
+ && ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) {
+ pm->ps->eFlags |= EF_FIRING;
+ } else {
+ pm->ps->eFlags &= ~EF_FIRING;
+ }
+
+ // clear the respawned flag if attack and use are cleared
+ if ( pm->ps->stats[STAT_HEALTH] > 0 &&
+ !( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) {
+ pm->ps->pm_flags &= ~PMF_RESPAWNED;
+ }
+
+ // if talk button is down, dissallow all other input
+ // this is to prevent any possible intercept proxy from
+ // adding fake talk balloons
+ if ( pmove->cmd.buttons & BUTTON_TALK ) {
+ // keep the talk button set tho for when the cmd.serverTime > 66 msec
+ // and the same cmd is used multiple times in Pmove
+ pmove->cmd.buttons = BUTTON_TALK;
+ pmove->cmd.forwardmove = 0;
+ pmove->cmd.rightmove = 0;
+ pmove->cmd.upmove = 0;
+ }
+
+ // clear all pmove local vars
+ memset (&pml, 0, sizeof(pml));
+
+ // determine the time
+ pml.msec = pmove->cmd.serverTime - pm->ps->commandTime;
+ if ( pml.msec < 1 ) {
+ pml.msec = 1;
+ } else if ( pml.msec > 200 ) {
+ pml.msec = 200;
+ }
+ pm->ps->commandTime = pmove->cmd.serverTime;
+
+ // save old org in case we get stuck
+ VectorCopy (pm->ps->origin, pml.previous_origin);
+
+ // save old velocity for crashlanding
+ VectorCopy (pm->ps->velocity, pml.previous_velocity);
+
+ pml.frametime = pml.msec * 0.001;
+
+ // update the viewangles
+ PM_UpdateViewAngles( pm->ps, &pm->cmd );
+
+ AngleVectors (pm->ps->viewangles, pml.forward, pml.right, pml.up);
+
+ if ( pm->cmd.upmove < 10 ) {
+ // not holding jump
+ pm->ps->pm_flags &= ~PMF_JUMP_HELD;
+ }
+
+ // decide if backpedaling animations should be used
+ if ( pm->cmd.forwardmove < 0 ) {
+ pm->ps->pm_flags |= PMF_BACKWARDS_RUN;
+ } else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) {
+ pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;
+ }
+
+ if ( pm->ps->pm_type >= PM_DEAD ) {
+ pm->cmd.forwardmove = 0;
+ pm->cmd.rightmove = 0;
+ pm->cmd.upmove = 0;
+ }
+
+ if ( pm->ps->pm_type == PM_SPECTATOR ) {
+ PM_CheckDuck ();
+ PM_FlyMove ();
+ PM_DropTimers ();
+ return;
+ }
+
+ if ( pm->ps->pm_type == PM_NOCLIP ) {
+ PM_NoclipMove ();
+ PM_DropTimers ();
+ return;
+ }
+
+ if (pm->ps->pm_type == PM_FREEZE) {
+ return; // no movement at all
+ }
+
+ if ( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION) {
+ return; // no movement at all
+ }
+
+ // set watertype, and waterlevel
+ PM_SetWaterLevel();
+ pml.previous_waterlevel = pmove->waterlevel;
+
+ // set mins, maxs, and viewheight
+ PM_CheckDuck ();
+
+ // set groundentity
+ PM_GroundTrace();
+
+ if ( pm->ps->pm_type == PM_DEAD ) {
+ PM_DeadMove ();
+ }
+
+ PM_DropTimers();
+
+ if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
+ PM_InvulnerabilityMove();
+ } else
+ if ( pm->ps->powerups[PW_FLIGHT] ) {
+ // flight powerup doesn't allow jump and has different friction
+ PM_FlyMove();
+ } else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) {
+ PM_GrappleMove();
+ // We can wiggle a bit
+ PM_AirMove();
+ } else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) {
+ PM_WaterJumpMove();
+ } else if ( pm->waterlevel > 1 ) {
+ // swimming
+ PM_WaterMove();
+ } else if ( pml.walking ) {
+ // walking on ground
+ PM_WalkMove();
+ } else {
+ // airborne
+ PM_AirMove();
+ }
+
+ PM_Animate();
+
+ // set groundentity, watertype, and waterlevel
+ PM_GroundTrace();
+ PM_SetWaterLevel();
+
+ // weapons
+ if(!(pm->ps->pm_flags & PMF_ELIMWARMUP))
+ PM_Weapon();
+
+ // torso animation
+ PM_TorsoAnimation();
+
+ // footstep events / legs animations
+ PM_Footsteps();
+
+ // entering / leaving water splashes
+ PM_WaterEvents();
+
+ // snap some parts of playerstate to save network bandwidth
+ //But only if pmove_float is not enabled
+ if(!(pm->pmove_float))
+ trap_SnapVector( pm->ps->velocity );
+}
+
+
+/*
+================
+Pmove
+
+Can be called by either the server or the client
+================
+*/
+void Pmove (pmove_t *pmove) {
+ int finalTime;
+
+ finalTime = pmove->cmd.serverTime;
+
+ if ( finalTime < pmove->ps->commandTime ) {
+ return; // should not happen
+ }
+
+ if ( finalTime > pmove->ps->commandTime + 1000 ) {
+ pmove->ps->commandTime = finalTime - 1000;
+ }
+
+ pmove->ps->pmove_framecount = (pmove->ps->pmove_framecount+1) & ((1<<PS_PMOVEFRAMECOUNTBITS)-1);
+
+ // chop the move up if it is too long, to prevent framerate
+ // dependent behavior
+ while ( pmove->ps->commandTime != finalTime ) {
+ int msec;
+
+ msec = finalTime - pmove->ps->commandTime;
+
+ if ( pmove->pmove_fixed ) {
+ if ( msec > pmove->pmove_msec ) {
+ msec = pmove->pmove_msec;
+ }
+ }
+ else {
+ if ( msec > 66 ) {
+ msec = 66;
+ }
+ }
+ pmove->cmd.serverTime = pmove->ps->commandTime + msec;
+ PmoveSingle( pmove );
+
+ if ( pmove->ps->pm_flags & PMF_JUMP_HELD ) {
+ pmove->cmd.upmove = 20;
+ }
+ }
+
+ //PM_CheckStuck();
+
+}
+
diff --git a/code/game/bg_public.h b/code/game/bg_public.h
new file mode 100644
index 0000000..e7b0ad1
--- /dev/null
+++ b/code/game/bg_public.h
@@ -0,0 +1,825 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// bg_public.h -- definitions shared by both the server game and client game modules
+
+// because games can change separately from the main system version, we need a
+// second version that must match between game and cgame
+
+#if defined(BG_PUBLIC_H)
+#else
+#define BG_PUBLIC_H 1
+
+#define GAME_VERSION BASEGAME "-1"
+
+#define DEFAULT_GRAVITY 800
+#define GIB_HEALTH -40
+#define ARMOR_PROTECTION 0.66
+
+#define MAX_ITEMS 256
+
+#define RANK_TIED_FLAG 0x4000
+
+#define DEFAULT_SHOTGUN_SPREAD 700
+#define DEFAULT_SHOTGUN_COUNT 11
+
+#define ITEM_RADIUS 15 // item sizes are needed for client side pickup detection
+
+#define LIGHTNING_RANGE 768
+
+#define SCORE_NOT_PRESENT -9999 // for the CS_SCORES[12] when only one player is present
+
+#define VOTE_TIME 30000 // 30 seconds before vote times out
+
+#define MINS_Z -24
+#define DEFAULT_VIEWHEIGHT 26
+#define CROUCH_VIEWHEIGHT 12
+#define DEAD_VIEWHEIGHT -16
+
+//Domination points
+#define MAX_DOMINATION_POINTS 6
+#define MAX_DOMINATION_POINTS_NAMES 20
+
+//
+// config strings are a general means of communicating variable length strings
+// from the server to all connected clients.
+//
+
+// CS_SERVERINFO and CS_SYSTEMINFO are defined in q_shared.h
+#define CS_MUSIC 2
+#define CS_MESSAGE 3 // from the map worldspawn's message field
+#define CS_MOTD 4 // g_motd string for server message of the day
+#define CS_WARMUP 5 // server time when the match will be restarted
+#define CS_SCORES1 6
+#define CS_SCORES2 7
+#define CS_VOTE_TIME 8
+#define CS_VOTE_STRING 9
+#define CS_VOTE_YES 10
+#define CS_VOTE_NO 11
+
+#define CS_TEAMVOTE_TIME 12
+#define CS_TEAMVOTE_STRING 14
+#define CS_TEAMVOTE_YES 16
+#define CS_TEAMVOTE_NO 18
+
+#define CS_GAME_VERSION 20
+#define CS_LEVEL_START_TIME 21 // so the timer only shows the current level
+#define CS_INTERMISSION 22 // when 1, fraglimit/timelimit has been hit and intermission will start in a second or two
+#define CS_FLAGSTATUS 23 // string indicating flag status in CTF
+#define CS_SHADERSTATE 24
+#define CS_BOTINFO 25
+
+#define CS_ITEMS 27 // string of 0's and 1's that tell which items are present
+
+#define CS_MODELS 32
+#define CS_SOUNDS (CS_MODELS+MAX_MODELS)
+#define CS_PLAYERS (CS_SOUNDS+MAX_SOUNDS)
+#define CS_LOCATIONS (CS_PLAYERS+MAX_CLIENTS)
+#define CS_PARTICLES (CS_LOCATIONS+MAX_LOCATIONS)
+
+#define CS_MAX (CS_PARTICLES+MAX_LOCATIONS)
+
+#if (CS_MAX) > MAX_CONFIGSTRINGS
+#error overflow: (CS_MAX) > MAX_CONFIGSTRINGS
+#endif
+
+typedef enum {
+ GT_FFA, // free for all
+ GT_TOURNAMENT, // one on one tournament
+ GT_SINGLE_PLAYER, // single player ffa
+
+ //-- team games go after this --
+
+ GT_TEAM, // team deathmatch
+
+ //-- team games that uses bases go after this
+
+ GT_CTF, // capture the flag
+ GT_1FCTF,
+ GT_OBELISK,
+ GT_HARVESTER,
+
+ //-- custom game types, there will be a variable in
+
+ GT_ELIMINATION, // team elimination (custom)
+ GT_CTF_ELIMINATION, // ctf elimination
+ GT_LMS, // Last man standing
+ GT_DOUBLE_D, // Double Domination
+ GT_DOMINATION, // Standard domination 12
+ GT_MAX_GAME_TYPE
+
+} gametype_t;
+
+typedef enum { GENDER_MALE, GENDER_FEMALE, GENDER_NEUTER } gender_t;
+
+/*
+===================================================================================
+
+PMOVE MODULE
+
+The pmove code takes a player_state_t and a usercmd_t and generates a new player_state_t
+and some other output data. Used for local prediction on the client game and true
+movement on the server game.
+===================================================================================
+*/
+
+typedef enum {
+ PM_NORMAL, // can accelerate and turn
+ PM_NOCLIP, // noclip movement
+ PM_SPECTATOR, // still run into walls
+ PM_DEAD, // no acceleration or turning, but free falling
+ PM_FREEZE, // stuck in place with no control
+ PM_INTERMISSION, // no movement or status bar
+ PM_SPINTERMISSION // no movement or status bar
+} pmtype_t;
+
+typedef enum {
+ WEAPON_READY,
+ WEAPON_RAISING,
+ WEAPON_DROPPING,
+ WEAPON_FIRING
+} weaponstate_t;
+
+// pmove->pm_flags
+#define PMF_DUCKED 1
+#define PMF_JUMP_HELD 2
+#define PMF_BACKWARDS_JUMP 8 // go into backwards land
+#define PMF_BACKWARDS_RUN 16 // coast down to backwards run
+#define PMF_TIME_LAND 32 // pm_time is time before rejump
+#define PMF_TIME_KNOCKBACK 64 // pm_time is an air-accelerate only time
+#define PMF_TIME_WATERJUMP 256 // pm_time is waterjump
+#define PMF_RESPAWNED 512 // clear after attack and jump buttons come up
+#define PMF_USE_ITEM_HELD 1024
+#define PMF_GRAPPLE_PULL 2048 // pull towards grapple location
+#define PMF_FOLLOW 4096 // spectate following another player
+#define PMF_SCOREBOARD 8192 // spectate as a scoreboard
+#define PMF_INVULEXPAND 16384 // invulnerability sphere set to full size
+//Elimination players cannot fire in warmup
+#define PMF_ELIMWARMUP 32768 //I hope this is more than 16 signed bits! (it's not but it just works anyway...)
+//Don't add anymore, I have already set the sign bit :-(
+
+#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK)
+
+#define MAXTOUCH 32
+typedef struct {
+ // state (in / out)
+ playerState_t *ps;
+
+ // command (in)
+ usercmd_t cmd;
+ int tracemask; // collide against these types of surfaces
+ int debugLevel; // if set, diagnostic output will be printed
+ qboolean noFootsteps; // if the game is setup for no footsteps by the server
+ qboolean gauntletHit; // true if a gauntlet attack would actually hit something
+
+ int framecount;
+
+ // results (out)
+ int numtouch;
+ int touchents[MAXTOUCH];
+
+ vec3_t mins, maxs; // bounding box size
+
+ int watertype;
+ int waterlevel;
+
+ float xyspeed;
+
+ // for fixed msec Pmove
+ int pmove_fixed;
+ int pmove_msec;
+
+ //Sago's pmove
+ int pmove_float;
+
+ //Flags effecting movement (see dmflags)
+ int pmove_flags;
+
+ // callbacks to test the world
+ // these will be different functions during game and cgame
+ void (*trace)( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask );
+ int (*pointcontents)( const vec3_t point, int passEntityNum );
+} pmove_t;
+
+// if a full pmove isn't done on the client, you can just update the angles
+void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd );
+void Pmove (pmove_t *pmove);
+
+//===================================================================================
+
+
+// player_state->stats[] indexes
+// NOTE: may not have more than 16
+typedef enum {
+ STAT_HEALTH,
+ STAT_HOLDABLE_ITEM,
+ STAT_PERSISTANT_POWERUP,
+ STAT_WEAPONS, // 16 bit fields
+ STAT_ARMOR,
+ STAT_DEAD_YAW, // look this direction when dead (FIXME: get rid of?)
+ STAT_CLIENTS_READY, // bit mask of clients wishing to exit the intermission (FIXME: configstring?)
+ STAT_MAX_HEALTH // health / armor limit, changable by handicap
+} statIndex_t;
+
+
+// player_state->persistant[] indexes
+// these fields are the only part of player_state that isn't
+// cleared on respawn
+// NOTE: may not have more than 16
+typedef enum {
+ PERS_SCORE, // !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!!
+ PERS_HITS, // total points damage inflicted so damage beeps can sound on change
+ PERS_RANK, // player rank or team rank
+ PERS_TEAM, // player team
+ PERS_SPAWN_COUNT, // incremented every respawn
+ PERS_PLAYEREVENTS, // 16 bits that can be flipped for events
+ PERS_ATTACKER, // clientnum of last damage inflicter
+ PERS_ATTACKEE_ARMOR, // health/armor of last person we attacked
+ PERS_KILLED, // count of the number of times you died
+ // player awards tracking
+ PERS_IMPRESSIVE_COUNT, // two railgun hits in a row
+ PERS_EXCELLENT_COUNT, // two successive kills in a short amount of time
+ PERS_DEFEND_COUNT, // defend awards
+ PERS_ASSIST_COUNT, // assist awards
+ PERS_GAUNTLET_FRAG_COUNT, // kills with the guantlet
+ PERS_CAPTURES // captures
+} persEnum_t;
+
+
+// entityState_t->eFlags
+#define EF_DEAD 0x00000001 // don't draw a foe marker over players with EF_DEAD
+#define EF_TICKING 0x00000002 // used to make players play the prox mine ticking sound
+#define EF_TELEPORT_BIT 0x00000004 // toggled every time the origin abruptly changes
+#define EF_AWARD_EXCELLENT 0x00000008 // draw an excellent sprite
+#define EF_PLAYER_EVENT 0x00000010
+#define EF_BOUNCE 0x00000010 // for missiles
+#define EF_BOUNCE_HALF 0x00000020 // for missiles
+#define EF_AWARD_GAUNTLET 0x00000040 // draw a gauntlet sprite
+#define EF_NODRAW 0x00000080 // may have an event, but no model (unspawned items)
+#define EF_FIRING 0x00000100 // for lightning gun
+#define EF_KAMIKAZE 0x00000200
+#define EF_MOVER_STOP 0x00000400 // will push otherwise
+#define EF_AWARD_CAP 0x00000800 // draw the capture sprite
+#define EF_TALK 0x00001000 // draw a talk balloon
+#define EF_CONNECTION 0x00002000 // draw a connection trouble sprite
+#define EF_VOTED 0x00004000 // already cast a vote
+#define EF_AWARD_IMPRESSIVE 0x00008000 // draw an impressive sprite
+#define EF_AWARD_DEFEND 0x00010000 // draw a defend sprite
+#define EF_AWARD_ASSIST 0x00020000 // draw a assist sprite
+#define EF_AWARD_DENIED 0x00040000 // denied
+#define EF_TEAMVOTED 0x00080000 // already cast a team vote
+
+// NOTE: may not have more than 16
+typedef enum {
+ PW_NONE,
+
+ PW_QUAD,
+ PW_BATTLESUIT,
+ PW_HASTE,
+ PW_INVIS,
+ PW_REGEN,
+ PW_FLIGHT,
+
+ PW_REDFLAG,
+ PW_BLUEFLAG,
+ PW_NEUTRALFLAG,
+
+ PW_SCOUT,
+ PW_GUARD,
+ PW_DOUBLER,
+ PW_AMMOREGEN,
+ PW_INVULNERABILITY,
+
+ PW_NUM_POWERUPS
+
+} powerup_t;
+
+typedef enum {
+ HI_NONE,
+
+ HI_TELEPORTER,
+ HI_MEDKIT,
+ HI_KAMIKAZE,
+ HI_PORTAL,
+ HI_INVULNERABILITY,
+
+ HI_NUM_HOLDABLE
+} holdable_t;
+
+typedef enum {
+ DD_NONE,
+
+ DD_POINTARED,
+ DD_POINTABLUE,
+ DD_POINTAWHITE,
+ DD_POINTBRED,
+ DD_POINTBBLUE,
+ DD_POINTBWHITE
+} doubled_t;
+
+typedef enum {
+ DOM_NONE,
+
+ DOM_POINTRED,
+ DOM_POINTBLUE,
+ DOM_POINTWHITE,
+} domination_t;
+
+
+typedef enum {
+ WP_NONE,
+
+ WP_GAUNTLET,
+ WP_MACHINEGUN,
+ WP_SHOTGUN,
+ WP_GRENADE_LAUNCHER,
+ WP_ROCKET_LAUNCHER,
+ WP_LIGHTNING,
+ WP_RAILGUN,
+ WP_PLASMAGUN,
+ WP_BFG,
+ WP_GRAPPLING_HOOK,
+ WP_NAILGUN,
+ WP_PROX_LAUNCHER,
+ WP_CHAINGUN,
+
+ WP_NUM_WEAPONS
+} weapon_t;
+
+
+// reward sounds (stored in ps->persistant[PERS_PLAYEREVENTS])
+#define PLAYEREVENT_DENIEDREWARD 0x0001
+#define PLAYEREVENT_GAUNTLETREWARD 0x0002
+#define PLAYEREVENT_HOLYSHIT 0x0004
+
+// entityState_t->event values
+// entity events are for effects that take place reletive
+// to an existing entities origin. Very network efficient.
+
+// two bits at the top of the entityState->event field
+// will be incremented with each change in the event so
+// that an identical event started twice in a row can
+// be distinguished. And off the value with ~EV_EVENT_BITS
+// to retrieve the actual event number
+#define EV_EVENT_BIT1 0x00000100
+#define EV_EVENT_BIT2 0x00000200
+#define EV_EVENT_BITS (EV_EVENT_BIT1|EV_EVENT_BIT2)
+
+#define EVENT_VALID_MSEC 300
+
+typedef enum {
+ EV_NONE,
+
+ EV_FOOTSTEP,
+ EV_FOOTSTEP_METAL,
+ EV_FOOTSPLASH,
+ EV_FOOTWADE,
+ EV_SWIM,
+
+ EV_STEP_4,
+ EV_STEP_8,
+ EV_STEP_12,
+ EV_STEP_16,
+
+ EV_FALL_SHORT,
+ EV_FALL_MEDIUM,
+ EV_FALL_FAR,
+
+ EV_JUMP_PAD, // boing sound at origin, jump sound on player
+
+ EV_JUMP, //Event 14
+ EV_WATER_TOUCH, // foot touches
+ EV_WATER_LEAVE, // foot leaves
+ EV_WATER_UNDER, // head touches
+ EV_WATER_CLEAR, // head leaves
+
+ EV_ITEM_PICKUP, // normal item pickups are predictable
+ EV_GLOBAL_ITEM_PICKUP, // powerup / team sounds are broadcast to everyone
+
+ EV_NOAMMO,
+ EV_CHANGE_WEAPON,
+ EV_FIRE_WEAPON,
+
+ EV_USE_ITEM0, //Event 24
+ EV_USE_ITEM1,
+ EV_USE_ITEM2,
+ EV_USE_ITEM3,
+ EV_USE_ITEM4,
+ EV_USE_ITEM5,
+ EV_USE_ITEM6,
+ EV_USE_ITEM7,
+ EV_USE_ITEM8,
+ EV_USE_ITEM9,
+ EV_USE_ITEM10,
+ EV_USE_ITEM11,
+ EV_USE_ITEM12,
+ EV_USE_ITEM13,
+ EV_USE_ITEM14,
+ EV_USE_ITEM15,
+
+ EV_ITEM_RESPAWN, //Event 40
+ EV_ITEM_POP,
+ EV_PLAYER_TELEPORT_IN,
+ EV_PLAYER_TELEPORT_OUT,
+
+ EV_GRENADE_BOUNCE, // eventParm will be the soundindex
+
+ EV_GENERAL_SOUND,
+ EV_GLOBAL_SOUND, // no attenuation
+ EV_GLOBAL_TEAM_SOUND,
+
+ EV_BULLET_HIT_FLESH,
+ EV_BULLET_HIT_WALL,
+
+ EV_MISSILE_HIT, //Event 50
+ EV_MISSILE_MISS,
+ EV_MISSILE_MISS_METAL,
+ EV_RAILTRAIL,
+ EV_SHOTGUN,
+ EV_BULLET, // otherEntity is the shooter
+
+ EV_PAIN,
+ EV_DEATH1,
+ EV_DEATH2,
+ EV_DEATH3,
+ EV_OBITUARY, //Event 60
+
+ EV_POWERUP_QUAD,
+ EV_POWERUP_BATTLESUIT,
+ EV_POWERUP_REGEN,
+
+ EV_GIB_PLAYER, // gib a previously living player
+ EV_SCOREPLUM, // score plum
+
+ EV_PROXIMITY_MINE_STICK,
+ EV_PROXIMITY_MINE_TRIGGER,
+ EV_KAMIKAZE, // kamikaze explodes
+ EV_OBELISKEXPLODE, // obelisk explodes
+ EV_OBELISKPAIN, // obelisk is in pain
+ EV_INVUL_IMPACT, // invulnerability sphere impact
+ EV_JUICED, // invulnerability juiced effect
+ EV_LIGHTNINGBOLT, // lightning bolt bounced of invulnerability sphere
+
+ EV_DEBUG_LINE,
+ EV_STOPLOOPINGSOUND,
+ EV_TAUNT,
+ EV_TAUNT_YES,
+ EV_TAUNT_NO,
+ EV_TAUNT_FOLLOWME,
+ EV_TAUNT_GETFLAG,
+ EV_TAUNT_GUARDBASE,
+ EV_TAUNT_PATROL
+
+} entity_event_t;
+
+
+typedef enum {
+ GTS_RED_CAPTURE,
+ GTS_BLUE_CAPTURE,
+ GTS_RED_RETURN,
+ GTS_BLUE_RETURN,
+ GTS_RED_TAKEN,
+ GTS_BLUE_TAKEN,
+ GTS_REDOBELISK_ATTACKED,
+ GTS_BLUEOBELISK_ATTACKED,
+ GTS_REDTEAM_SCORED,
+ GTS_BLUETEAM_SCORED,
+ GTS_REDTEAM_TOOK_LEAD,
+ GTS_BLUETEAM_TOOK_LEAD,
+ GTS_TEAMS_ARE_TIED,
+ GTS_KAMIKAZE
+} global_team_sound_t;
+
+// animations
+typedef enum {
+ BOTH_DEATH1,
+ BOTH_DEAD1,
+ BOTH_DEATH2,
+ BOTH_DEAD2,
+ BOTH_DEATH3,
+ BOTH_DEAD3,
+
+ TORSO_GESTURE,
+
+ TORSO_ATTACK,
+ TORSO_ATTACK2,
+
+ TORSO_DROP,
+ TORSO_RAISE,
+
+ TORSO_STAND,
+ TORSO_STAND2,
+
+ LEGS_WALKCR,
+ LEGS_WALK,
+ LEGS_RUN,
+ LEGS_BACK,
+ LEGS_SWIM,
+
+ LEGS_JUMP,
+ LEGS_LAND,
+
+ LEGS_JUMPB,
+ LEGS_LANDB,
+
+ LEGS_IDLE,
+ LEGS_IDLECR,
+
+ LEGS_TURN,
+
+ TORSO_GETFLAG,
+ TORSO_GUARDBASE,
+ TORSO_PATROL,
+ TORSO_FOLLOWME,
+ TORSO_AFFIRMATIVE,
+ TORSO_NEGATIVE,
+
+// BOTH_POSE, // leilei - crappy ui posing code trying
+
+ MAX_ANIMATIONS,
+
+ LEGS_BACKCR,
+ LEGS_BACKWALK,
+ FLAG_RUN,
+ FLAG_STAND,
+ FLAG_STAND2RUN,
+
+ MAX_TOTALANIMATIONS
+} animNumber_t;
+
+
+typedef struct animation_s {
+ int firstFrame;
+ int numFrames;
+ int loopFrames; // 0 to numFrames
+ int frameLerp; // msec between frames
+ int initialLerp; // msec to get to first frame
+ int reversed; // true if animation is reversed
+ int flipflop; // true if animation should flipflop back to base
+} animation_t;
+
+
+// flip the togglebit every time an animation
+// changes so a restart of the same anim can be detected
+#define ANIM_TOGGLEBIT 128
+
+
+typedef enum {
+ TEAM_FREE,
+ TEAM_RED,
+ TEAM_BLUE,
+ TEAM_SPECTATOR,
+
+ TEAM_NUM_TEAMS
+} team_t;
+
+// This is a fair assumption for Double Domination:
+#define TEAM_NONE TEAM_SPECTATOR
+
+// Time between location updates
+#define TEAM_LOCATION_UPDATE_TIME 1000
+
+// How many players on the overlay
+#define TEAM_MAXOVERLAY 32
+
+//team task
+typedef enum {
+ TEAMTASK_NONE,
+ TEAMTASK_OFFENSE,
+ TEAMTASK_DEFENSE,
+ TEAMTASK_PATROL,
+ TEAMTASK_FOLLOW,
+ TEAMTASK_RETRIEVE,
+ TEAMTASK_ESCORT,
+ TEAMTASK_CAMP
+} teamtask_t;
+
+// means of death
+typedef enum {
+ MOD_UNKNOWN,
+ MOD_SHOTGUN,
+ MOD_GAUNTLET,
+ MOD_MACHINEGUN,
+ MOD_GRENADE,
+ MOD_GRENADE_SPLASH,
+ MOD_ROCKET,
+ MOD_ROCKET_SPLASH,
+ MOD_PLASMA,
+ MOD_PLASMA_SPLASH,
+ MOD_RAILGUN,
+ MOD_LIGHTNING,
+ MOD_BFG,
+ MOD_BFG_SPLASH,
+ MOD_WATER,
+ MOD_SLIME,
+ MOD_LAVA,
+ MOD_CRUSH,
+ MOD_TELEFRAG,
+ MOD_FALLING,
+ MOD_SUICIDE,
+ MOD_TARGET_LASER,
+ MOD_TRIGGER_HURT,
+ MOD_NAIL,
+ MOD_CHAINGUN,
+ MOD_PROXIMITY_MINE,
+ MOD_KAMIKAZE,
+ MOD_JUICED,
+ MOD_GRAPPLE
+} meansOfDeath_t;
+
+
+//---------------------------------------------------------
+
+// gitem_t->type
+typedef enum {
+ IT_BAD,
+ IT_WEAPON, // EFX: rotate + upscale + minlight
+ IT_AMMO, // EFX: rotate
+ IT_ARMOR, // EFX: rotate + minlight
+ IT_HEALTH, // EFX: static external sphere + rotating internal
+ IT_POWERUP, // instant on, timer based
+ // EFX: rotate + external ring that rotates
+ IT_HOLDABLE, // single use, holdable item
+ // EFX: rotate + bob
+ IT_PERSISTANT_POWERUP,
+ IT_TEAM
+} itemType_t;
+
+#define MAX_ITEM_MODELS 4
+
+typedef struct gitem_s {
+ char *classname; // spawning name
+ char *pickup_sound;
+ char *world_model[MAX_ITEM_MODELS];
+
+ char *icon;
+ char *pickup_name; // for printing on pickup
+
+ int quantity; // for ammo how much, or duration of powerup
+ itemType_t giType; // IT_* flags
+
+ int giTag;
+
+ char *precaches; // string of all models and images this item will use
+ char *sounds; // string of all sounds this item will use
+} gitem_t;
+
+// included in both the game dll and the client
+extern gitem_t bg_itemlist[];
+extern int bg_numItems;
+
+gitem_t *BG_FindItem( const char *pickupName );
+gitem_t *BG_FindItemForWeapon( weapon_t weapon );
+gitem_t *BG_FindItemForPowerup( powerup_t pw );
+gitem_t *BG_FindItemForHoldable( holdable_t pw );
+#define ITEM_INDEX(x) ((x)-bg_itemlist)
+
+qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps );
+
+
+// g_dmflags->integer flags
+#define DF_NO_FALLING 8
+#define DF_FIXED_FOV 16
+#define DF_NO_FOOTSTEPS 32
+#define DF_INSTANT_WEAPON_CHANGE 64
+#define DF_NO_BUNNY 128
+#define DF_INVIS 256
+#define DF_LIGHT_VOTING 512
+#define DF_NO_SELF_DAMAGE 1024
+#define DF_PLAYER_OVERLAY 2048
+
+//g_videoflags->integer
+#define VF_LOCK_CVARS_BASIC 1
+#define VF_LOCK_CVARS_EXTENDED 2
+#define VF_LOCK_VERTEX 4
+
+// g_elimflags->integer
+//This is used to signal the client that it cannot go to free spectator:
+#define EF_ONEWAY 1
+#define EF_NO_FREESPEC 2
+
+//g_voteflags->integer
+//Autoparsed from allowedvote
+//List: "/map_restart/nextmap/map/g_gametype/kick/clientkick/g_doWarmup/timelimit/fraglimit/custom/shuffle/"
+#define VF_map_restart 1
+#define VF_nextmap 2
+#define VF_map 4
+#define VF_g_gametype 8
+//Note that we skipped kick... not needed
+#define VF_clientkick 16
+#define VF_g_doWarmup 32
+#define VF_timelimit 64
+#define VF_fraglimit 128
+#define VF_custom 256
+#define VF_shuffle 512
+
+// content masks
+#define MASK_ALL (-1)
+#define MASK_SOLID (CONTENTS_SOLID)
+#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY)
+#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP)
+#define MASK_WATER (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME)
+#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA)
+#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE)
+
+
+//
+// entityState_t->eType
+//
+typedef enum {
+ ET_GENERAL,
+ ET_PLAYER,
+ ET_ITEM,
+ ET_MISSILE,
+ ET_MOVER,
+ ET_BEAM,
+ ET_PORTAL,
+ ET_SPEAKER,
+ ET_PUSH_TRIGGER,
+ ET_TELEPORT_TRIGGER,
+ ET_INVISIBLE,
+ ET_GRAPPLE, // grapple hooked on wall
+ ET_TEAM,
+
+ ET_EVENTS // any of the EV_* events can be added freestanding
+ // by setting eType to ET_EVENTS + eventNum
+ // this avoids having to set eFlags and eventNum
+} entityType_t;
+
+//KK-OAX Using this now instead of g_mem.c
+// bg_alloc.c
+//
+qboolean BG_CanAlloc( unsigned int size );
+void *BG_Alloc( unsigned int size );
+void BG_InitMemory( void );
+void BG_Free( void *ptr );
+void BG_DefragmentMemory( void );
+
+
+void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result );
+void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result );
+
+void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps );
+
+void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad );
+
+void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap );
+void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap );
+
+qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime );
+
+
+#define ARENAS_PER_TIER 4
+#define MAX_ARENAS 1024
+#define MAX_ARENAS_TEXT 8192
+
+#define MAX_BOTS 1024
+#define MAX_BOTS_TEXT 8192
+
+
+// Kamikaze
+
+// 1st shockwave times
+#define KAMI_SHOCKWAVE_STARTTIME 0
+#define KAMI_SHOCKWAVEFADE_STARTTIME 1500
+#define KAMI_SHOCKWAVE_ENDTIME 2000
+// explosion/implosion times
+#define KAMI_EXPLODE_STARTTIME 250
+#define KAMI_IMPLODE_STARTTIME 2000
+#define KAMI_IMPLODE_ENDTIME 2250
+// 2nd shockwave times
+#define KAMI_SHOCKWAVE2_STARTTIME 2000
+#define KAMI_SHOCKWAVE2FADE_STARTTIME 2500
+#define KAMI_SHOCKWAVE2_ENDTIME 3000
+// radius of the models without scaling
+#define KAMI_SHOCKWAVEMODEL_RADIUS 88
+#define KAMI_BOOMSPHEREMODEL_RADIUS 72
+// maximum radius of the models during the effect
+#define KAMI_SHOCKWAVE_MAXRADIUS 1320
+#define KAMI_BOOMSPHERE_MAXRADIUS 720
+#define KAMI_SHOCKWAVE2_MAXRADIUS 704
+
+//KK-OAX
+//bg_misc.c
+char *BG_TeamName( team_t team );
+
+#endif
diff --git a/engine/code/game/bg_slidemove.c b/code/game/bg_slidemove.c
similarity index 100%
rename from engine/code/game/bg_slidemove.c
rename to code/game/bg_slidemove.c
diff --git a/game/code/game/challenges.h b/code/game/challenges.h
similarity index 100%
rename from game/code/game/challenges.h
rename to code/game/challenges.h
diff --git a/code/game/challenges.xml b/code/game/challenges.xml
new file mode 100644
index 0000000..a3041ed
--- /dev/null
+++ b/code/game/challenges.xml
@@ -0,0 +1,339 @@
+<Challenges>
+ <Group>
+ <Id>0</Id>
+ <DefineName>GENERAL_</DefineName>
+ <Name>Overall statistics</Name>
+ <Description>Totals</Description>
+ <Challenge>
+ <Id>0</Id>
+ <DefineName>TEST</DefineName>
+ <HideInMenu>1</HideInMenu>
+ <Name>Test</Name>
+ <Description>Used for test</Description>
+ </Challenge>
+ <Challenge>
+ <Id>1</Id>
+ <DefineName>TOTALKILLS</DefineName>
+ <Name>Kills</Name>
+ <Description>Total number of players killed</Description>
+ </Challenge>
+ <Challenge>
+ <Id>2</Id>
+ <DefineName>TOTALDEATHS</DefineName>
+ <Name>Deaths</Name>
+ <Description>Number of times killed by another player</Description>
+ </Challenge>
+ <Challenge>
+ <Id>3</Id>
+ <DefineName>TOTALGAMES</DefineName>
+ <Name>Games</Name>
+ <Description>Number of games played with 2 or more human players</Description>
+ </Challenge>
+ </Group>
+ <Group>
+ <Id>1</Id>
+ <DefineName>GAMETYPE_</DefineName>
+ <Name>Gametype wins</Name>
+ <Description>Number of wins in the different gametypes</Description>
+ <Challenge>
+ <Id>1</Id>
+ <DefineName>FFA_WINS</DefineName>
+ <Name>Deathmatch</Name>
+ <Description>Number of victories in deathmatch games</Description>
+ </Challenge>
+ <Challenge>
+ <Id>2</Id>
+ <DefineName>TOURNEY_WINS</DefineName>
+ <Name>Tournament</Name>
+ <Description>Number of victories in tournament games</Description>
+ </Challenge>
+ <Challenge>
+ <Id>3</Id>
+ <DefineName>TDM_WINS</DefineName>
+ <Name>Team Deathmatch</Name>
+ <Description>Number of victories in team deathmatch games</Description>
+ </Challenge>
+ <Challenge>
+ <Id>4</Id>
+ <DefineName>CTF_WINS</DefineName>
+ <Name>Capture the flag</Name>
+ <Description>Number of victories in capture the flag games</Description>
+ </Challenge>
+ <Challenge>
+ <Id>5</Id>
+ <DefineName>1FCTF_WINS</DefineName>
+ <Name>One flag capture</Name>
+ <Description>Number of victories in one flag capture games</Description>
+ </Challenge>
+ <Challenge>
+ <Id>6</Id>
+ <DefineName>OVERLOAD_WINS</DefineName>
+ <Name>Obelisk</Name>
+ <Description>Number of victories in obelisk games</Description>
+ </Challenge>
+ <Challenge>
+ <Id>7</Id>
+ <DefineName>HARVESTER_WINS</DefineName>
+ <Name>Harvester</Name>
+ <Description>Number of victories in harvester games</Description>
+ </Challenge>
+ <Challenge>
+ <Id>8</Id>
+ <DefineName>ELIMINATION_WINS</DefineName>
+ <Name>Elimination</Name>
+ <Description>Number of victories in elimination games</Description>
+ </Challenge>
+ <Challenge>
+ <Id>9</Id>
+ <DefineName>CTF_ELIMINATION_WINS</DefineName>
+ <Name>CTF Elimination</Name>
+ <Description>Number of victories in CTF elimination games</Description>
+ </Challenge>
+ <Challenge>
+ <Id>10</Id>
+ <DefineName>LMS_WINS</DefineName>
+ <Name>Last man standing</Name>
+ <Description>Number of victories in last man standing games</Description>
+ </Challenge>
+ <Challenge>
+ <Id>11</Id>
+ <DefineName>DD_WINS</DefineName>
+ <Name>Double Domination</Name>
+ <Description>Number of victories in double domination games</Description>
+ </Challenge>
+ <Challenge>
+ <Id>12</Id>
+ <DefineName>DOM_WINS</DefineName>
+ <Name>Domination</Name>
+ <Description>Number of victories in domination games</Description>
+ </Challenge>
+ </Group>
+ <Group>
+ <Id>2</Id>
+ <DefineName>WEAPON_</DefineName>
+ <Name>Weapon kills</Name>
+ <Description>Number of kills with different weapons</Description>
+ <Challenge>
+ <Id>1</Id>
+ <DefineName>GAUNTLET_KILLS</DefineName>
+ <Name>Gauntlet</Name>
+ <Description>Number of kills with gauntlet</Description>
+ </Challenge>
+ <Challenge>
+ <Id>2</Id>
+ <DefineName>MACHINEGUN_KILLS</DefineName>
+ <Name>Machinegun</Name>
+ <Description>Number of kills with machinegun</Description>
+ </Challenge>
+ <Challenge>
+ <Id>3</Id>
+ <DefineName>SHOTGUN_KILLS</DefineName>
+ <Name>Shotgun</Name>
+ <Description>Number of kills with shotgun</Description>
+ </Challenge>
+ <Challenge>
+ <Id>4</Id>
+ <DefineName>GRANADE_KILLS</DefineName>
+ <Name>Granade launcher</Name>
+ <Description>Number of kills with granade launcher</Description>
+ </Challenge>
+ <Challenge>
+ <Id>5</Id>
+ <DefineName>ROCKET_KILLS</DefineName>
+ <Name>Rocket launcher</Name>
+ <Description>Number of kills with rocket launcher</Description>
+ </Challenge>
+ <Challenge>
+ <Id>6</Id>
+ <DefineName>LIGHTNING_KILLS</DefineName>
+ <Name>Lightning gun</Name>
+ <Description>Number of kills with lightning</Description>
+ </Challenge>
+ <Challenge>
+ <Id>7</Id>
+ <DefineName>PLASMA_KILLS</DefineName>
+ <Name>Plasma gun</Name>
+ <Description>Number of kills with plasma</Description>
+ </Challenge>
+ <Challenge>
+ <Id>8</Id>
+ <DefineName>RAIL_KILLS</DefineName>
+ <Name>Railgun</Name>
+ <Description>Number of kills with railgun</Description>
+ </Challenge>
+ <Challenge>
+ <Id>9</Id>
+ <DefineName>BFG_KILLS</DefineName>
+ <Name>BFG</Name>
+ <Description>Number of kills with BFG</Description>
+ </Challenge>
+ <Challenge>
+ <Id>10</Id>
+ <DefineName>GRAPPLE_KILLS</DefineName>
+ <Name>Grapple</Name>
+ <Description>Number of kills with grapple gun (almost impossible)</Description>
+ </Challenge>
+ <Challenge>
+ <Id>11</Id>
+ <DefineName>CHAINGUN_KILLS</DefineName>
+ <Name>Chaingun</Name>
+ <Description>Number of kills with the chaingun</Description>
+ </Challenge>
+ <Challenge>
+ <Id>12</Id>
+ <DefineName>NAILGUN_KILLS</DefineName>
+ <Name>Nailgun</Name>
+ <Description>Number of kills with nails</Description>
+ </Challenge>
+ <Challenge>
+ <Id>13</Id>
+ <DefineName>MINE_KILLS</DefineName>
+ <Name>Mines</Name>
+ <Description>Number of kills with mines</Description>
+ </Challenge>
+ <Challenge>
+ <Id>14</Id>
+ <DefineName>PUSH_KILLS</DefineName>
+ <Name>Push kills</Name>
+ <Description>Number of kills by pushing players into lava or void</Description>
+ </Challenge>
+ <Challenge>
+ <Id>15</Id>
+ <DefineName>INSTANT_RAIL_KILLS</DefineName>
+ <Name>Instant rail</Name>
+ <Description>Number of kills with railgun in instantgib</Description>
+ </Challenge>
+ <Challenge>
+ <Id>16</Id>
+ <DefineName>TELEFRAG_KILLS</DefineName>
+ <Name>Telefrags</Name>
+ <Description>Number of kills by telefrag</Description>
+ </Challenge>
+ <Challenge>
+ <Id>17</Id>
+ <DefineName>CRUSH_KILLS</DefineName>
+ <Name>Crushing</Name>
+ <Description>Number of kills by crushing</Description>
+ </Challenge>
+ </Group>
+ <Group>
+ <Id>3</Id>
+ <DefineName>AWARD_</DefineName>
+ <Name>Awards</Name>
+ <Description>Number of times different awards have been archived</Description>
+ <Challenge>
+ <Id>101</Id>
+ <MenuOnly>1</MenuOnly>
+ <Name>Gauntlet</Name>
+ <Description>Number of kills by gauntlet</Description>
+ </Challenge>
+ <Challenge>
+ <Id>1</Id>
+ <DefineName>IMPRESSIVE</DefineName>
+ <Name>Impressive</Name>
+ <Description>Two hits in a row with railgun</Description>
+ </Challenge>
+ <Challenge>
+ <Id>2</Id>
+ <DefineName>EXCELLENT</DefineName>
+ <Name>Excelent</Name>
+ <Description>Two kills in two seconds</Description>
+ </Challenge>
+ <Challenge>
+ <Id>3</Id>
+ <DefineName>CAPTURE</DefineName>
+ <Name>Capture</Name>
+ <Description>Scoring in team games</Description>
+ </Challenge>
+ <Challenge>
+ <Id>4</Id>
+ <DefineName>ASSIST</DefineName>
+ <Name>Assist</Name>
+ <Description>Asisting a capture</Description>
+ </Challenge>
+ <Challenge>
+ <Id>5</Id>
+ <DefineName>DEFENCE</DefineName>
+ <Name>Defence</Name>
+ <Description>Defending objective</Description>
+ </Challenge>
+ </Group>
+ <Group>
+ <Id>4</Id>
+ <DefineName>POWERUP_</DefineName>
+ <Name>Power-ups</Name>
+ <Description>Number of kills with different powerups involved</Description>
+ <Challenge>
+ <Id>1</Id>
+ <DefineName>QUAD_KILL</DefineName>
+ <Name>Defence</Name>
+ <Description>Defending objective</Description>
+ </Challenge>
+ <Challenge>
+ <Id>2</Id>
+ <DefineName>SPEED_KILL</DefineName>
+ <Name>Defence</Name>
+ <Description>Defending objective</Description>
+ </Challenge>
+ <Challenge>
+ <Id>3</Id>
+ <DefineName>FLIGHT_KILL</DefineName>
+ <Name>Defence</Name>
+ <Description>Defending objective</Description>
+ </Challenge>
+ <Challenge>
+ <Id>4</Id>
+ <DefineName>INVIS_KILL</DefineName>
+ <Name>Defence</Name>
+ <Description>Defending objective</Description>
+ </Challenge>
+ <Challenge>
+ <Id>5</Id>
+ <DefineName>MULTI_KILL</DefineName>
+ <Name>Defence</Name>
+ <Description>Defending objective</Description>
+ </Challenge>
+ <Challenge>
+ <Id>6</Id>
+ <DefineName>DEFENCE</DefineName>
+ <Name>Defence</Name>
+ <Description>Defending objective</Description>
+ </Challenge>
+ <Challenge>
+ <Id>7</Id>
+ <DefineName>DEFENCE</DefineName>
+ <Name>Defence</Name>
+ <Description>Defending objective</Description>
+ </Challenge>
+ <Challenge>
+ <Id>8</Id>
+ <DefineName>DEFENCE</DefineName>
+ <Name>Defence</Name>
+ <Description>Defending objective</Description>
+ </Challenge>
+ <Challenge>
+ <Id>9</Id>
+ <DefineName>DEFENCE</DefineName>
+ <Name>Defence</Name>
+ <Description>Defending objective</Description>
+ </Challenge>
+ <Challenge>
+ <Id>10</Id>
+ <DefineName>DEFENCE</DefineName>
+ <Name>Defence</Name>
+ <Description>Defending objective</Description>
+ </Challenge>
+ <Challenge>
+ <Id>11</Id>
+ <DefineName>DEFENCE</DefineName>
+ <Name>Defence</Name>
+ <Description>Defending objective</Description>
+ </Challenge>
+ <Challenge>
+ <Id>12</Id>
+ <DefineName>DEFENCE</DefineName>
+ <Name>Defence</Name>
+ <Description>Defending objective</Description>
+ </Challenge>
+ </Group>
+</Challenges>
diff --git a/engine/code/game/chars.h b/code/game/chars.h
similarity index 100%
rename from engine/code/game/chars.h
rename to code/game/chars.h
diff --git a/code/game/g_active.c b/code/game/g_active.c
new file mode 100644
index 0000000..d7c2311
--- /dev/null
+++ b/code/game/g_active.c
@@ -0,0 +1,1368 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+#include "g_local.h"
+
+
+/*
+===============
+G_DamageFeedback
+
+Called just before a snapshot is sent to the given player.
+Totals up all damage and generates both the player_state_t
+damage values to that client for pain blends and kicks, and
+global pain sound events for all clients.
+===============
+*/
+void P_DamageFeedback( gentity_t *player ) {
+ gclient_t *client;
+ float count;
+ vec3_t angles;
+
+ client = player->client;
+ if ( client->ps.pm_type == PM_DEAD ) {
+ return;
+ }
+
+ // total points of damage shot at the player this frame
+ count = client->damage_blood + client->damage_armor;
+ if ( count == 0 ) {
+ return; // didn't take any damage
+ }
+
+ if ( count > 255 ) {
+ count = 255;
+ }
+
+ // send the information to the client
+
+ // world damage (falling, slime, etc) uses a special code
+ // to make the blend blob centered instead of positional
+ if ( client->damage_fromWorld ) {
+ client->ps.damagePitch = 255;
+ client->ps.damageYaw = 255;
+
+ client->damage_fromWorld = qfalse;
+ } else {
+ vectoangles( client->damage_from, angles );
+ client->ps.damagePitch = angles[PITCH]/360.0 * 256;
+ client->ps.damageYaw = angles[YAW]/360.0 * 256;
+ }
+
+ // play an apropriate pain sound
+ if ( (level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) ) {
+ player->pain_debounce_time = level.time + 700;
+ G_AddEvent( player, EV_PAIN, player->health );
+ client->ps.damageEvent++;
+ }
+
+
+ client->ps.damageCount = count;
+
+ //
+ // clear totals
+ //
+ client->damage_blood = 0;
+ client->damage_armor = 0;
+ client->damage_knockback = 0;
+}
+
+
+
+/*
+=============
+P_WorldEffects
+
+Check for lava / slime contents and drowning
+=============
+*/
+void P_WorldEffects( gentity_t *ent ) {
+ qboolean envirosuit;
+ int waterlevel;
+
+ if ( ent->client->noclip ) {
+ ent->client->airOutTime = level.time + 12000; // don't need air
+ return;
+ }
+
+ waterlevel = ent->waterlevel;
+
+ envirosuit = ent->client->ps.powerups[PW_BATTLESUIT] > level.time;
+
+ //
+ // check for drowning
+ //
+ if ( waterlevel == 3 ) {
+ // envirosuit give air
+ if ( envirosuit ) {
+ ent->client->airOutTime = level.time + 10000;
+ }
+
+ // if out of air, start drowning
+ if ( ent->client->airOutTime < level.time) {
+ // drown!
+ ent->client->airOutTime += 1000;
+ if ( ent->health > 0 ) {
+ // take more damage the longer underwater
+ ent->damage += 2;
+ if (ent->damage > 15)
+ ent->damage = 15;
+
+ // don't play a normal pain sound
+ ent->pain_debounce_time = level.time + 200;
+
+ G_Damage (ent, NULL, NULL, NULL, NULL,
+ ent->damage, DAMAGE_NO_ARMOR, MOD_WATER);
+ }
+ }
+ } else {
+ ent->client->airOutTime = level.time + 12000;
+ ent->damage = 2;
+ }
+
+ //
+ // check for sizzle damage (move to pmove?)
+ //
+ if (waterlevel &&
+ (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) {
+ if (ent->health > 0
+ && ent->pain_debounce_time <= level.time ) {
+
+ if ( envirosuit ) {
+ G_AddEvent( ent, EV_POWERUP_BATTLESUIT, 0 );
+ } else {
+ if (ent->watertype & CONTENTS_LAVA) {
+ G_Damage (ent, NULL, NULL, NULL, NULL,
+ 30*waterlevel, 0, MOD_LAVA);
+ }
+
+ if (ent->watertype & CONTENTS_SLIME) {
+ G_Damage (ent, NULL, NULL, NULL, NULL,
+ 10*waterlevel, 0, MOD_SLIME);
+ }
+ }
+ }
+ }
+}
+
+
+
+/*
+===============
+G_SetClientSound
+===============
+*/
+void G_SetClientSound( gentity_t *ent ) {
+ if( ent->s.eFlags & EF_TICKING ) {
+ ent->client->ps.loopSound = G_SoundIndex( "sound/weapons/proxmine/wstbtick.wav");
+ }
+ else
+ if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) {
+ ent->client->ps.loopSound = level.snd_fry;
+ } else {
+ ent->client->ps.loopSound = 0;
+ }
+}
+
+
+
+//==============================================================
+
+/*
+==============
+ClientImpacts
+==============
+*/
+void ClientImpacts( gentity_t *ent, pmove_t *pm ) {
+ int i, j;
+ trace_t trace;
+ gentity_t *other;
+
+ memset( &trace, 0, sizeof( trace ) );
+ for (i=0 ; i<pm->numtouch ; i++) {
+ for (j=0 ; j<i ; j++) {
+ if (pm->touchents[j] == pm->touchents[i] ) {
+ break;
+ }
+ }
+ if (j != i) {
+ continue; // duplicated
+ }
+ other = &g_entities[ pm->touchents[i] ];
+
+ if ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) {
+ ent->touch( ent, other, &trace );
+ }
+
+ if ( !other->touch ) {
+ continue;
+ }
+
+ other->touch( other, ent, &trace );
+ }
+
+}
+
+/*
+============
+G_TouchTriggers
+
+Find all trigger entities that ent's current position touches.
+Spectators will only interact with teleporters.
+============
+*/
+void G_TouchTriggers( gentity_t *ent ) {
+ int i, num;
+ int touch[MAX_GENTITIES];
+ gentity_t *hit;
+ trace_t trace;
+ vec3_t mins, maxs;
+ static vec3_t range = { 40, 40, 52 };
+
+ if ( !ent->client ) {
+ return;
+ }
+
+ //ELIMINATION LMS
+ // dead clients don't activate triggers! The reason our pm_spectators can't do anything
+ if ( ent->client->ps.stats[STAT_HEALTH] <= 0 && ent->client->ps.pm_type != PM_SPECTATOR) {
+ return;
+ }
+
+ VectorSubtract( ent->client->ps.origin, range, mins );
+ VectorAdd( ent->client->ps.origin, range, maxs );
+
+ num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
+
+ // can't use ent->absmin, because that has a one unit pad
+ VectorAdd( ent->client->ps.origin, ent->r.mins, mins );
+ VectorAdd( ent->client->ps.origin, ent->r.maxs, maxs );
+
+ for ( i=0 ; i<num ; i++ ) {
+ hit = &g_entities[touch[i]];
+
+ if ( !hit->touch && !ent->touch ) {
+ continue;
+ }
+ if ( !( hit->r.contents & CONTENTS_TRIGGER ) ) {
+ continue;
+ }
+
+ // ignore most entities if a spectator
+ if ( (ent->client->sess.sessionTeam == TEAM_SPECTATOR) || ent->client->ps.pm_type == PM_SPECTATOR ) {
+ if ( hit->s.eType != ET_TELEPORT_TRIGGER &&
+ // this is ugly but adding a new ET_? type will
+ // most likely cause network incompatibilities
+ //We need to stop eliminated players from opening doors somewhere else /Sago007 20070814
+ hit->touch != Touch_DoorTrigger ) {
+ continue;
+ }
+ }
+
+ // use seperate code for determining if an item is picked up
+ // so you don't have to actually contact its bounding box
+ if ( hit->s.eType == ET_ITEM ) {
+ if ( !BG_PlayerTouchesItem( &ent->client->ps, &hit->s, level.time ) ) {
+ continue;
+ }
+ } else {
+ if ( !trap_EntityContact( mins, maxs, hit ) ) {
+ continue;
+ }
+ }
+
+ memset( &trace, 0, sizeof(trace) );
+
+ if ( hit->touch ) {
+ hit->touch (hit, ent, &trace);
+ }
+
+ if ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) {
+ ent->touch( ent, hit, &trace );
+ }
+ }
+
+ // if we didn't touch a jump pad this pmove frame
+ if ( ent->client->ps.jumppad_frame != ent->client->ps.pmove_framecount ) {
+ ent->client->ps.jumppad_frame = 0;
+ ent->client->ps.jumppad_ent = 0;
+ }
+}
+
+/*
+=================
+SpectatorThink
+=================
+*/
+void SpectatorThink( gentity_t *ent, usercmd_t *ucmd ) {
+ pmove_t pm;
+ gclient_t *client;
+
+ client = ent->client;
+
+ if ( ( g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) &&
+ client->sess.spectatorState != SPECTATOR_FOLLOW &&
+ g_elimination_lockspectator.integer>1 &&
+ ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
+ Cmd_FollowCycle_f(ent);
+ }
+
+ if ( client->sess.spectatorState != SPECTATOR_FOLLOW ) {
+ client->ps.pm_type = PM_SPECTATOR;
+ client->ps.speed = 400; // faster than normal
+
+ // set up for pmove
+ memset (&pm, 0, sizeof(pm));
+ pm.ps = &client->ps;
+ pm.cmd = *ucmd;
+ pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; // spectators can fly through bodies
+ pm.trace = trap_Trace;
+ pm.pointcontents = trap_PointContents;
+
+ // perform a pmove
+ Pmove (&pm);
+ // save results of pmove
+ VectorCopy( client->ps.origin, ent->s.origin );
+
+ G_TouchTriggers( ent );
+ trap_UnlinkEntity( ent );
+ }
+
+ /* Stopped players from going into follow mode in B5, should be fixed in B9
+ if(ent->client->sess.sessionTeam != TEAM_SPECTATOR && g_gametype.integer>=GT_ELIMINATION && g_gametype.integer<=GT_LMS)
+ return;
+ */
+
+ client->oldbuttons = client->buttons;
+ client->buttons = ucmd->buttons;
+
+ //KK-OAX Changed to keep followcycle functional
+ // attack button cycles through spectators
+ if ( ( client->buttons & BUTTON_ATTACK ) && ! ( client->oldbuttons & BUTTON_ATTACK ) ) {
+ Cmd_FollowCycle_f( ent );
+ }
+
+ if ( ( client->buttons & BUTTON_USE_HOLDABLE ) && ! ( client->oldbuttons & BUTTON_USE_HOLDABLE ) ) {
+ if ( ( g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) &&
+ g_elimination_lockspectator.integer>1 &&
+ ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
+ return;
+ }
+ StopFollowing(ent);
+ }
+}
+
+
+
+/*
+=================
+ClientInactivityTimer
+
+Returns qfalse if the client is dropped
+=================
+*/
+qboolean ClientInactivityTimer( gclient_t *client ) {
+ if ( ! g_inactivity.integer ) {
+ // give everyone some time, so if the operator sets g_inactivity during
+ // gameplay, everyone isn't kicked
+ client->inactivityTime = level.time + 60 * 1000;
+ client->inactivityWarning = qfalse;
+ } else if ( client->pers.cmd.forwardmove ||
+ client->pers.cmd.rightmove ||
+ client->pers.cmd.upmove ||
+ (client->pers.cmd.buttons & BUTTON_ATTACK) ) {
+ client->inactivityTime = level.time + g_inactivity.integer * 1000;
+ client->inactivityWarning = qfalse;
+ } else if ( !client->pers.localClient ) {
+ if ( level.time > client->inactivityTime ) {
+ trap_DropClient( client - level.clients, "Dropped due to inactivity" );
+ return qfalse;
+ }
+ if ( level.time > client->inactivityTime - 10000 && !client->inactivityWarning ) {
+ client->inactivityWarning = qtrue;
+ trap_SendServerCommand( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" );
+ }
+ }
+ return qtrue;
+}
+
+/*
+==================
+ClientTimerActions
+
+Actions that happen once a second
+==================
+*/
+void ClientTimerActions( gentity_t *ent, int msec ) {
+ gclient_t *client;
+ int maxHealth;
+
+ client = ent->client;
+ client->timeResidual += msec;
+
+ while ( client->timeResidual >= 1000 ) {
+ client->timeResidual -= 1000;
+
+ //Stop in elimination!!!
+ if (client->ps.pm_flags & PMF_ELIMWARMUP)
+ continue;
+
+ // regenerate
+ if( bg_itemlist[client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
+ maxHealth = client->ps.stats[STAT_MAX_HEALTH] / 2;
+ }
+ else if ( client->ps.powerups[PW_REGEN] ) {
+ maxHealth = client->ps.stats[STAT_MAX_HEALTH];
+ }
+ else {
+ maxHealth = 0;
+ }
+ if( maxHealth ) {
+ if ( ent->health < maxHealth ) {
+ ent->health += 15;
+ if ( ent->health > maxHealth * 1.1 ) {
+ ent->health = maxHealth * 1.1;
+ }
+ G_AddEvent( ent, EV_POWERUP_REGEN, 0 );
+ } else if ( ent->health < maxHealth * 2) {
+ ent->health += 5;
+ if ( ent->health > maxHealth * 2 ) {
+ ent->health = maxHealth * 2;
+ }
+ G_AddEvent( ent, EV_POWERUP_REGEN, 0 );
+ }
+ } else {
+ // count down health when over max
+ if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] ) {
+ ent->health--;
+ }
+ //Start killing players in LMS, if we are in overtime
+ if(g_elimination_roundtime.integer&&g_gametype.integer==GT_LMS && TeamHealthCount( -1, TEAM_FREE ) != ent->health &&(level.roundNumber==level.roundNumberStarted)&&(level.time>=level.roundStartTime+1000*g_elimination_roundtime.integer)) {
+ ent->damage=5;
+ G_Damage (ent, NULL, NULL, NULL, NULL,
+ ent->damage, DAMAGE_NO_ARMOR, MOD_UNKNOWN);
+ }
+ else
+ if ( ent->health < client->ps.stats[STAT_MAX_HEALTH] ) {
+ ent->health+=g_regen.integer;
+ if(ent->health>client->ps.stats[STAT_MAX_HEALTH])
+ ent->health= client->ps.stats[STAT_MAX_HEALTH];
+ }
+ }
+
+ // count down armor when over max
+ if ( client->ps.stats[STAT_ARMOR] > client->ps.stats[STAT_MAX_HEALTH] ) {
+ client->ps.stats[STAT_ARMOR]--;
+ }
+ }
+ if( bg_itemlist[client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
+ int w, max, inc, t, i;
+ int weapList[]={WP_MACHINEGUN,WP_SHOTGUN,WP_GRENADE_LAUNCHER,WP_ROCKET_LAUNCHER,WP_LIGHTNING,WP_RAILGUN,WP_PLASMAGUN,WP_BFG,WP_NAILGUN,WP_PROX_LAUNCHER,WP_CHAINGUN};
+ int weapCount = sizeof(weapList) / sizeof(int);
+ //
+ for (i = 0; i < weapCount; i++) {
+ w = weapList[i];
+
+ switch(w) {
+ case WP_MACHINEGUN: max = 50; inc = 4; t = 1000; break;
+ case WP_SHOTGUN: max = 10; inc = 1; t = 1500; break;
+ case WP_GRENADE_LAUNCHER: max = 10; inc = 1; t = 2000; break;
+ case WP_ROCKET_LAUNCHER: max = 10; inc = 1; t = 1750; break;
+ case WP_LIGHTNING: max = 50; inc = 5; t = 1500; break;
+ case WP_RAILGUN: max = 10; inc = 1; t = 1750; break;
+ case WP_PLASMAGUN: max = 50; inc = 5; t = 1500; break;
+ case WP_BFG: max = 10; inc = 1; t = 4000; break;
+ case WP_NAILGUN: max = 10; inc = 1; t = 1250; break;
+ case WP_PROX_LAUNCHER: max = 5; inc = 1; t = 2000; break;
+ case WP_CHAINGUN: max = 100; inc = 5; t = 1000; break;
+ default: max = 0; inc = 0; t = 1000; break;
+ }
+ client->ammoTimes[w] += msec;
+ if ( client->ps.ammo[w] >= max ) {
+ client->ammoTimes[w] = 0;
+ }
+ if ( client->ammoTimes[w] >= t ) {
+ while ( client->ammoTimes[w] >= t )
+ client->ammoTimes[w] -= t;
+ client->ps.ammo[w] += inc;
+ if ( client->ps.ammo[w] > max ) {
+ client->ps.ammo[w] = max;
+ }
+ }
+ }
+ }
+}
+
+/*
+====================
+ClientIntermissionThink
+====================
+*/
+void ClientIntermissionThink( gclient_t *client ) {
+ client->ps.eFlags &= ~EF_TALK;
+ client->ps.eFlags &= ~EF_FIRING;
+
+ // the level will exit when everyone wants to or after timeouts
+
+ if( g_entities[client->ps.clientNum].r.svFlags & SVF_BOT )
+ return; //Bots cannot mark themself as ready
+
+ // swap and latch button actions
+ client->oldbuttons = client->buttons;
+ client->buttons = client->pers.cmd.buttons;
+ if ( client->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) & ( client->oldbuttons ^ client->buttons ) ) {
+ // this used to be an ^1 but once a player says ready, it should stick
+ client->readyToExit = 1;
+ }
+}
+
+
+/*
+================
+ClientEvents
+
+Events will be passed on to the clients for presentation,
+but any server game effects are handled here
+================
+*/
+void ClientEvents( gentity_t *ent, int oldEventSequence ) {
+ int i, j;
+ int event;
+ gclient_t *client;
+ int damage;
+ vec3_t dir;
+ vec3_t origin, angles;
+// qboolean fired;
+ gitem_t *item;
+ gentity_t *drop;
+
+ client = ent->client;
+
+ if ( oldEventSequence < client->ps.eventSequence - MAX_PS_EVENTS ) {
+ oldEventSequence = client->ps.eventSequence - MAX_PS_EVENTS;
+ }
+ for ( i = oldEventSequence ; i < client->ps.eventSequence ; i++ ) {
+ event = client->ps.events[ i & (MAX_PS_EVENTS-1) ];
+
+ switch ( event ) {
+ case EV_FALL_MEDIUM:
+ case EV_FALL_FAR:
+ if ( ent->s.eType != ET_PLAYER ) {
+ break; // not in the player model
+ }
+ if ( g_dmflags.integer & DF_NO_FALLING ) {
+ break;
+ }
+ if ( event == EV_FALL_FAR ) {
+ damage = 10;
+ } else {
+ damage = 5;
+ }
+ VectorSet (dir, 0, 0, 1);
+ ent->pain_debounce_time = level.time + 200; // no normal pain sound
+ G_Damage (ent, NULL, NULL, NULL, NULL, damage, 0, MOD_FALLING);
+ break;
+
+ case EV_FIRE_WEAPON:
+ FireWeapon( ent );
+ break;
+
+ case EV_USE_ITEM1: // teleporter
+ // drop flags in CTF
+ item = NULL;
+ j = 0;
+
+ if ( ent->client->ps.powerups[ PW_REDFLAG ] ) {
+ item = BG_FindItemForPowerup( PW_REDFLAG );
+ j = PW_REDFLAG;
+ } else if ( ent->client->ps.powerups[ PW_BLUEFLAG ] ) {
+ item = BG_FindItemForPowerup( PW_BLUEFLAG );
+ j = PW_BLUEFLAG;
+ } else if ( ent->client->ps.powerups[ PW_NEUTRALFLAG ] ) {
+ item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
+ j = PW_NEUTRALFLAG;
+ }
+
+ if ( item ) {
+ drop = Drop_Item( ent, item, 0 );
+ // decide how many seconds it has left
+ drop->count = ( ent->client->ps.powerups[ j ] - level.time ) / 1000;
+ if ( drop->count < 1 ) {
+ drop->count = 1;
+ }
+
+ ent->client->ps.powerups[ j ] = 0;
+ }
+
+ if ( g_gametype.integer == GT_HARVESTER ) {
+ if ( ent->client->ps.generic1 > 0 ) {
+ if ( ent->client->sess.sessionTeam == TEAM_RED ) {
+ item = BG_FindItem( "Blue Cube" );
+ } else {
+ item = BG_FindItem( "Red Cube" );
+ }
+ if ( item ) {
+ for ( j = 0; j < ent->client->ps.generic1; j++ ) {
+ drop = Drop_Item( ent, item, 0 );
+ if ( ent->client->sess.sessionTeam == TEAM_RED ) {
+ drop->spawnflags = TEAM_BLUE;
+ } else {
+ drop->spawnflags = TEAM_RED;
+ }
+ }
+ }
+ ent->client->ps.generic1 = 0;
+ }
+ }
+ SelectSpawnPoint( ent->client->ps.origin, origin, angles );
+ TeleportPlayer( ent, origin, angles );
+ break;
+
+ case EV_USE_ITEM2: // medkit
+ ent->health = ent->client->ps.stats[STAT_MAX_HEALTH] + 25;
+
+ break;
+
+ case EV_USE_ITEM3: // kamikaze
+ // make sure the invulnerability is off
+ ent->client->invulnerabilityTime = 0;
+ // start the kamikze
+ G_StartKamikaze( ent );
+ break;
+
+ case EV_USE_ITEM4: // portal
+ if( ent->client->portalID ) {
+ DropPortalSource( ent );
+ }
+ else {
+ DropPortalDestination( ent );
+ }
+ break;
+ case EV_USE_ITEM5: // invulnerability
+ ent->client->invulnerabilityTime = level.time + 10000;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+}
+
+/*
+==============
+StuckInOtherClient
+==============
+*/
+static int StuckInOtherClient(gentity_t *ent) {
+ int i;
+ gentity_t *ent2;
+
+ ent2 = &g_entities[0];
+ for ( i = 0; i < MAX_CLIENTS; i++, ent2++ ) {
+ if ( ent2 == ent ) {
+ continue;
+ }
+ if ( !ent2->inuse ) {
+ continue;
+ }
+ if ( !ent2->client ) {
+ continue;
+ }
+ if ( ent2->health <= 0 ) {
+ continue;
+ }
+ //
+ if (ent2->r.absmin[0] > ent->r.absmax[0])
+ continue;
+ if (ent2->r.absmin[1] > ent->r.absmax[1])
+ continue;
+ if (ent2->r.absmin[2] > ent->r.absmax[2])
+ continue;
+ if (ent2->r.absmax[0] < ent->r.absmin[0])
+ continue;
+ if (ent2->r.absmax[1] < ent->r.absmin[1])
+ continue;
+ if (ent2->r.absmax[2] < ent->r.absmin[2])
+ continue;
+ return qtrue;
+ }
+ return qfalse;
+}
+
+void BotTestSolid(vec3_t origin);
+
+/*
+==============
+SendPendingPredictableEvents
+==============
+*/
+void SendPendingPredictableEvents( playerState_t *ps ) {
+ gentity_t *t;
+ int event, seq;
+ int extEvent, number;
+
+ // if there are still events pending
+ if ( ps->entityEventSequence < ps->eventSequence ) {
+ // create a temporary entity for this event which is sent to everyone
+ // except the client who generated the event
+ seq = ps->entityEventSequence & (MAX_PS_EVENTS-1);
+ event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );
+ // set external event to zero before calling BG_PlayerStateToEntityState
+ extEvent = ps->externalEvent;
+ ps->externalEvent = 0;
+ // create temporary entity for event
+ t = G_TempEntity( ps->origin, event );
+ number = t->s.number;
+ BG_PlayerStateToEntityState( ps, &t->s, qtrue );
+ t->s.number = number;
+ t->s.eType = ET_EVENTS + event;
+ t->s.eFlags |= EF_PLAYER_EVENT;
+ t->s.otherEntityNum = ps->clientNum;
+ // send to everyone except the client who generated the event
+ t->r.svFlags |= SVF_NOTSINGLECLIENT;
+ t->r.singleClient = ps->clientNum;
+ // set back external event
+ ps->externalEvent = extEvent;
+ }
+}
+
+/*
+==============
+ClientThink
+
+This will be called once for each client frame, which will
+usually be a couple times for each server frame on fast clients.
+
+If "g_synchronousClients 1" is set, this will be called exactly
+once for each server frame, which makes for smooth demo recording.
+==============
+*/
+void ClientThink_real( gentity_t *ent ) {
+ gclient_t *client;
+ pmove_t pm;
+ int oldEventSequence;
+ int msec;
+ usercmd_t *ucmd;
+
+ client = ent->client;
+
+ // don't think if the client is not yet connected (and thus not yet spawned in)
+ if (client->pers.connected != CON_CONNECTED) {
+ return;
+ }
+ // mark the time, so the connection sprite can be removed
+ ucmd = &ent->client->pers.cmd;
+
+ // sanity check the command time to prevent speedup cheating
+ if ( ucmd->serverTime > level.time + 200 ) {
+ ucmd->serverTime = level.time + 200;
+// G_Printf("serverTime <<<<<\n" );
+ }
+ if ( ucmd->serverTime < level.time - 1000 ) {
+ ucmd->serverTime = level.time - 1000;
+// G_Printf("serverTime >>>>>\n" );
+ }
+
+//Here comes the unlagged bit!
+//unlagged - backward reconciliation #4
+ // frameOffset should be about the number of milliseconds into a frame
+ // this command packet was received, depending on how fast the server
+ // does a G_RunFrame()
+ client->frameOffset = trap_Milliseconds() - level.frameStartTime;
+//unlagged - backward reconciliation #4
+
+
+//unlagged - lag simulation #3
+ // if the client wants to simulate outgoing packet loss
+/* if ( client->pers.plOut ) {
+ // see if a random value is below the threshhold
+ float thresh = (float)client->pers.plOut / 100.0f;
+ if ( random() < thresh ) {
+ // do nothing at all if it is - this is a lost command
+ return;
+ }
+ }*/
+//unlagged - lag simulation #3
+
+
+//unlagged - true ping
+ // save the estimated ping in a queue for averaging later
+
+ // we use level.previousTime to account for 50ms lag correction
+ // besides, this will turn out numbers more like what players are used to
+ client->pers.pingsamples[client->pers.samplehead] = level.previousTime + client->frameOffset - ucmd->serverTime;
+ client->pers.samplehead++;
+ if ( client->pers.samplehead >= NUM_PING_SAMPLES ) {
+ client->pers.samplehead -= NUM_PING_SAMPLES;
+ }
+
+ // initialize the real ping
+ if ( g_truePing.integer ) {
+ int i, sum = 0;
+
+ // get an average of the samples we saved up
+ for ( i = 0; i < NUM_PING_SAMPLES; i++ ) {
+ sum += client->pers.pingsamples[i];
+ }
+
+ client->pers.realPing = sum / NUM_PING_SAMPLES;
+ }
+ else {
+ // if g_truePing is off, use the normal ping
+ client->pers.realPing = client->ps.ping;
+ }
+//unlagged - true ping
+
+
+//unlagged - lag simulation #2
+ // keep a queue of past commands
+/* client->pers.cmdqueue[client->pers.cmdhead] = client->pers.cmd;
+ client->pers.cmdhead++;
+ if ( client->pers.cmdhead >= MAX_LATENT_CMDS ) {
+ client->pers.cmdhead -= MAX_LATENT_CMDS;
+ }
+
+ // if the client wants latency in commands (client-to-server latency)
+ if ( client->pers.latentCmds ) {
+ // save the actual command time
+ int time = ucmd->serverTime;
+
+ // find out which index in the queue we want
+ int cmdindex = client->pers.cmdhead - client->pers.latentCmds - 1;
+ while ( cmdindex < 0 ) {
+ cmdindex += MAX_LATENT_CMDS;
+ }
+
+ // read in the old command
+ client->pers.cmd = client->pers.cmdqueue[cmdindex];
+
+ // adjust the real ping to reflect the new latency
+ client->pers.realPing += time - ucmd->serverTime;
+ }*/
+//unlagged - lag simulation #2
+
+
+//unlagged - backward reconciliation #4
+ // save the command time *before* pmove_fixed messes with the serverTime,
+ // and *after* lag simulation messes with it :)
+ // attackTime will be used for backward reconciliation later (time shift)
+ client->attackTime = ucmd->serverTime;
+//unlagged - backward reconciliation #4
+
+
+//unlagged - smooth clients #1
+ // keep track of this for later - we'll use this to decide whether or not
+ // to send extrapolated positions for this client
+ client->lastUpdateFrame = level.framenum;
+//unlagged - smooth clients #1
+
+
+//unlagged - lag simulation #1
+ // if the client is adding latency to received snapshots (server-to-client latency)
+ /*if ( client->pers.latentSnaps ) {
+ // adjust the real ping
+ client->pers.realPing += client->pers.latentSnaps * (1000 / sv_fps.integer);
+ // adjust the attack time so backward reconciliation will work
+ client->attackTime -= client->pers.latentSnaps * (1000 / sv_fps.integer);
+ }*/
+//unlagged - lag simulation #1
+
+
+//unlagged - true ping
+ // make sure the true ping is over 0 - with cl_timenudge it can be less
+ if ( client->pers.realPing < 0 ) {
+ client->pers.realPing = 0;
+ }
+//unlagged - true ping
+
+ msec = ucmd->serverTime - client->ps.commandTime;
+ // following others may result in bad times, but we still want
+ // to check for follow toggles
+ if ( msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW ) {
+ return;
+ }
+ if ( msec > 200 ) {
+ msec = 200;
+ }
+
+ if ( pmove_msec.integer < 8 ) {
+ trap_Cvar_Set("pmove_msec", "8");
+ }
+ else if (pmove_msec.integer > 33) {
+ trap_Cvar_Set("pmove_msec", "33");
+ }
+
+ if ( pmove_fixed.integer || client->pers.pmoveFixed ) {
+ ucmd->serverTime = ((ucmd->serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;
+ //if (ucmd->serverTime - client->ps.commandTime <= 0)
+ // return;
+ }
+
+ //
+ // check for exiting intermission
+ //
+ if ( level.intermissiontime ) {
+ ClientIntermissionThink( client );
+ return;
+ }
+
+ // spectators don't do much
+ if ( (client->sess.sessionTeam == TEAM_SPECTATOR) || client->isEliminated ) {
+ if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
+ return;
+ }
+ SpectatorThink( ent, ucmd );
+ return;
+ }
+
+ // check for inactivity timer, but never drop the local client of a non-dedicated server
+ if ( !ClientInactivityTimer( client ) ) {
+ return;
+ }
+
+ // clear the rewards if time
+ if ( level.time > client->rewardTime ) {
+ client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ }
+
+ if ( client->noclip ) {
+ client->ps.pm_type = PM_NOCLIP;
+ } else if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
+ client->ps.pm_type = PM_DEAD;
+ } else {
+ client->ps.pm_type = PM_NORMAL;
+ }
+
+ client->ps.gravity = g_gravity.value*g_gravityModifier.value;
+
+ // set speed
+ client->ps.speed = g_speed.value;
+
+ if( bg_itemlist[client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
+ client->ps.speed *= 1.5;
+ }
+ else
+ if ( client->ps.powerups[PW_HASTE] ) {
+ client->ps.speed *= 1.3;
+ }
+
+ // Let go of the hook if we aren't firing
+ if ( client->ps.weapon == WP_GRAPPLING_HOOK &&
+ client->hook && !( ucmd->buttons & BUTTON_ATTACK ) ) {
+ Weapon_HookFree(client->hook);
+ }
+
+ // set up for pmove
+ oldEventSequence = client->ps.eventSequence;
+
+ memset (&pm, 0, sizeof(pm));
+
+ // check for the hit-scan gauntlet, don't let the action
+ // go through as an attack unless it actually hits something
+ if ( client->ps.weapon == WP_GAUNTLET && !( ucmd->buttons & BUTTON_TALK ) &&
+ ( ucmd->buttons & BUTTON_ATTACK ) && client->ps.weaponTime <= 0 ) {
+ pm.gauntletHit = CheckGauntletAttack( ent );
+ }
+
+ if ( ent->flags & FL_FORCE_GESTURE ) {
+ ent->flags &= ~FL_FORCE_GESTURE;
+ ent->client->pers.cmd.buttons |= BUTTON_GESTURE;
+ }
+
+ // check for invulnerability expansion before doing the Pmove
+ if (client->ps.powerups[PW_INVULNERABILITY] ) {
+ if ( !(client->ps.pm_flags & PMF_INVULEXPAND) ) {
+ vec3_t mins = { -42, -42, -42 };
+ vec3_t maxs = { 42, 42, 42 };
+ vec3_t oldmins, oldmaxs;
+
+ VectorCopy (ent->r.mins, oldmins);
+ VectorCopy (ent->r.maxs, oldmaxs);
+ // expand
+ VectorCopy (mins, ent->r.mins);
+ VectorCopy (maxs, ent->r.maxs);
+ trap_LinkEntity(ent);
+ // check if this would get anyone stuck in this player
+ if ( !StuckInOtherClient(ent) ) {
+ // set flag so the expanded size will be set in PM_CheckDuck
+ client->ps.pm_flags |= PMF_INVULEXPAND;
+ }
+ // set back
+ VectorCopy (oldmins, ent->r.mins);
+ VectorCopy (oldmaxs, ent->r.maxs);
+ trap_LinkEntity(ent);
+ }
+ }
+
+ pm.ps = &client->ps;
+ pm.cmd = *ucmd;
+ if ( pm.ps->pm_type == PM_DEAD ) {
+ pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
+ }
+ else if ( ent->r.svFlags & SVF_BOT ) {
+ pm.tracemask = MASK_PLAYERSOLID | CONTENTS_BOTCLIP;
+ }
+ else {
+ pm.tracemask = MASK_PLAYERSOLID;
+ }
+ pm.trace = trap_Trace;
+ pm.pointcontents = trap_PointContents;
+ pm.debugLevel = g_debugMove.integer;
+ pm.noFootsteps = ( g_dmflags.integer & DF_NO_FOOTSTEPS ) > 0;
+
+ pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed;
+ pm.pmove_msec = pmove_msec.integer;
+ pm.pmove_float = pmove_float.integer;
+ pm.pmove_flags = g_dmflags.integer;
+
+ VectorCopy( client->ps.origin, client->oldOrigin );
+
+ #ifdef MISSIONPACK
+ if (level.intermissionQueued != 0 && g_singlePlayer.integer) {
+ if ( level.time - level.intermissionQueued >= 1000 ) {
+ pm.cmd.buttons = 0;
+ pm.cmd.forwardmove = 0;
+ pm.cmd.rightmove = 0;
+ pm.cmd.upmove = 0;
+ if ( level.time - level.intermissionQueued >= 2000 && level.time - level.intermissionQueued <= 2500 ) {
+ trap_SendConsoleCommand( EXEC_APPEND, "centerview\n");
+ }
+ ent->client->ps.pm_type = PM_SPINTERMISSION;
+ }
+ }
+ #endif
+ Pmove (&pm);
+
+ // save results of pmove
+ if ( ent->client->ps.eventSequence != oldEventSequence ) {
+ ent->eventTime = level.time;
+ }
+//unlagged - smooth clients #2
+ // clients no longer do extrapolation if cg_smoothClients is 1, because
+ // skip correction is all handled server-side now
+ // since that's the case, it makes no sense to store the extra info
+ // in the client's snapshot entity, so let's save a little bandwidth
+/*
+ if (g_smoothClients.integer) {
+ BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
+ }
+ else {
+*/
+ BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
+// }
+//unlagged - smooth clients #2
+ SendPendingPredictableEvents( &ent->client->ps );
+
+ if ( !( ent->client->ps.eFlags & EF_FIRING ) ) {
+ client->fireHeld = qfalse; // for grapple
+ }
+
+ // use the snapped origin for linking so it matches client predicted versions
+ VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );
+
+ VectorCopy (pm.mins, ent->r.mins);
+ VectorCopy (pm.maxs, ent->r.maxs);
+
+ ent->waterlevel = pm.waterlevel;
+ ent->watertype = pm.watertype;
+
+ // execute client events
+ ClientEvents( ent, oldEventSequence );
+
+ // link entity now, after any personal teleporters have been used
+ trap_LinkEntity (ent);
+ if ( !ent->client->noclip ) {
+ G_TouchTriggers( ent );
+ }
+
+ // NOTE: now copy the exact origin over otherwise clients can be snapped into solid
+ VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
+
+ //test for solid areas in the AAS file
+ BotTestAAS(ent->r.currentOrigin);
+
+ // touch other objects
+ ClientImpacts( ent, &pm );
+
+ // save results of triggers and client events
+ if (ent->client->ps.eventSequence != oldEventSequence) {
+ ent->eventTime = level.time;
+ }
+
+ // swap and latch button actions
+ client->oldbuttons = client->buttons;
+ client->buttons = ucmd->buttons;
+ client->latched_buttons |= client->buttons & ~client->oldbuttons;
+
+ // check for respawning
+ if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
+ // wait for the attack button to be pressed
+ // forcerespawn is to prevent users from waiting out powerups
+ // In Last man standing, we force a quick respawn, since
+ // the player must be able to loose health
+ // pressing attack or use is the normal respawn method
+ if ( ( level.time > client->respawnTime ) &&
+ ( ( ( g_forcerespawn.integer > 0 ) &&
+ ( level.time - client->respawnTime > g_forcerespawn.integer * 1000 ) ) ||
+ ( ( ( g_gametype.integer == GT_LMS ) ||
+ ( g_gametype.integer == GT_ELIMINATION ) ||
+ ( g_gametype.integer == GT_CTF_ELIMINATION ) ) &&
+ ( level.time - client->respawnTime > 0 ) ) ||
+ ( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) ) ) {
+
+ ClientRespawn( ent );
+ }
+ return;
+ }
+
+ if ( pm.waterlevel <= 1 && pm.ps->groundEntityNum!=ENTITYNUM_NONE && client->lastSentFlyingTime+500>level.time) {
+ if ( ! (pm.ps->pm_flags & PMF_TIME_KNOCKBACK) ) {
+ client->lastSentFlying = -1;
+ }
+ }
+
+ // perform once-a-second actions
+ ClientTimerActions( ent, msec );
+}
+
+/*
+==================
+ClientThink
+
+A new command has arrived from the client
+==================
+*/
+void ClientThink( int clientNum ) {
+ gentity_t *ent;
+
+ ent = g_entities + clientNum;
+ trap_GetUsercmd( clientNum, &ent->client->pers.cmd );
+
+ //Unlagged: commented out
+ // mark the time we got info, so we can display the
+ // phone jack if they don't get any for a while
+ //ent->client->lastCmdTime = level.time;
+
+ if ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) {
+ ClientThink_real( ent );
+ }
+}
+
+
+void G_RunClient( gentity_t *ent ) {
+ if ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) {
+ return;
+ }
+ ent->client->pers.cmd.serverTime = level.time;
+ ClientThink_real( ent );
+}
+
+
+/*
+==================
+SpectatorClientEndFrame
+
+==================
+*/
+void SpectatorClientEndFrame( gentity_t *ent ) {
+ gclient_t *cl;
+ int i, preservedScore[MAX_PERSISTANT]; //for keeping in elimination
+
+ // if we are doing a chase cam or a remote view, grab the latest info
+ if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {
+ int clientNum, flags;
+
+ clientNum = ent->client->sess.spectatorClient;
+
+ // team follow1 and team follow2 go to whatever clients are playing
+ if ( clientNum == -1 ) {
+ clientNum = level.follow1;
+ } else if ( clientNum == -2 ) {
+ clientNum = level.follow2;
+ }
+ if ( clientNum >= 0 ) {
+ cl = &level.clients[ clientNum ];
+ if ( cl->pers.connected == CON_CONNECTED && cl->sess.sessionTeam != TEAM_SPECTATOR ) {
+ flags = (cl->ps.eFlags & ~(EF_VOTED | EF_TEAMVOTED)) | (ent->client->ps.eFlags & (EF_VOTED | EF_TEAMVOTED));
+ //this is here LMS/Elimination goes wrong with player follow
+ if(ent->client->sess.sessionTeam!=TEAM_SPECTATOR){
+ for(i = 0; i < MAX_PERSISTANT; i++)
+ preservedScore[i] = ent->client->ps.persistant[i];
+ ent->client->ps = cl->ps;
+ for(i = 0; i < MAX_PERSISTANT; i++)
+ ent->client->ps.persistant[i] = preservedScore[i];
+ }
+ else
+ ent->client->ps = cl->ps;
+ ent->client->ps.pm_flags |= PMF_FOLLOW;
+ ent->client->ps.eFlags = flags;
+ return;
+ } else {
+ // drop them to free spectators unless they are dedicated camera followers
+ if ( ent->client->sess.spectatorClient >= 0 ) {
+ ent->client->sess.spectatorState = SPECTATOR_FREE;
+ ClientBegin( ent->client - level.clients );
+ }
+ }
+ }
+
+
+
+ }
+
+ if ( ent->client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
+ ent->client->ps.pm_flags |= PMF_SCOREBOARD;
+ } else {
+ ent->client->ps.pm_flags &= ~PMF_SCOREBOARD;
+ }
+}
+
+/*
+==============
+ClientEndFrame
+
+Called at the end of each server frame for each connected client
+A fast client will have multiple ClientThink for each ClientEdFrame,
+while a slow client may have multiple ClientEndFrame between ClientThink.
+==============
+*/
+void ClientEndFrame( gentity_t *ent ) {
+ int i;
+ clientPersistant_t *pers;
+
+//unlagged - smooth clients #1
+ int frames;
+//unlagged - smooth clients #1
+
+ if ( (ent->client->sess.sessionTeam == TEAM_SPECTATOR) || ent->client->isEliminated ) {
+ SpectatorClientEndFrame( ent );
+ return;
+ }
+
+ pers = &ent->client->pers;
+
+ // turn off any expired powerups
+ for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
+ if ( ent->client->ps.powerups[ i ] < level.time ) {
+ ent->client->ps.powerups[ i ] = 0;
+ }
+ }
+
+ // set powerup for player animation
+ if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
+ ent->client->ps.powerups[PW_GUARD] = level.time;
+ }
+ if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
+ ent->client->ps.powerups[PW_SCOUT] = level.time;
+ }
+ if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_DOUBLER ) {
+ ent->client->ps.powerups[PW_DOUBLER] = level.time;
+ }
+ if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
+ ent->client->ps.powerups[PW_AMMOREGEN] = level.time;
+ }
+ if ( ent->client->invulnerabilityTime > level.time ) {
+ ent->client->ps.powerups[PW_INVULNERABILITY] = level.time;
+ }
+
+ // save network bandwidth
+#if 0
+ if ( !g_synchronousClients->integer && ent->client->ps.pm_type == PM_NORMAL ) {
+ // FIXME: this must change eventually for non-sync demo recording
+ VectorClear( ent->client->ps.viewangles );
+ }
+#endif
+
+ //
+ // If the end of unit layout is displayed, don't give
+ // the player any normal movement attributes
+ //
+ if ( level.intermissiontime ) {
+ return;
+ }
+
+ // burn from lava, etc
+ P_WorldEffects (ent);
+
+ // apply all the damage taken this frame
+ P_DamageFeedback (ent);
+
+ //Unlagged: Commented out
+ // add the EF_CONNECTION flag if we haven't gotten commands recently
+ /*if ( level.time - ent->client->lastCmdTime > 1000 ) {
+ ent->s.eFlags |= EF_CONNECTION;
+ } else {
+ ent->s.eFlags &= ~EF_CONNECTION;
+ }*/
+
+ ent->client->ps.stats[STAT_HEALTH] = ent->health; // FIXME: get rid of ent->health...
+
+ G_SetClientSound (ent);
+
+//Unlagged: Always do the else clause
+ // set the latest infor
+/* if (g_smoothClients.integer) {
+ BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
+ }
+ else { */
+ BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
+// }
+ SendPendingPredictableEvents( &ent->client->ps );
+
+//unlagged - smooth clients #1
+ // mark as not missing updates initially
+ ent->client->ps.eFlags &= ~EF_CONNECTION;
+
+ // see how many frames the client has missed
+ frames = level.framenum - ent->client->lastUpdateFrame - 1;
+
+ // don't extrapolate more than two frames
+ if ( frames > 2 ) {
+ frames = 2;
+
+ // if they missed more than two in a row, show the phone jack
+ ent->client->ps.eFlags |= EF_CONNECTION;
+ ent->s.eFlags |= EF_CONNECTION;
+ }
+
+ // did the client miss any frames?
+ if ( frames > 0 && g_smoothClients.integer ) {
+ // yep, missed one or more, so extrapolate the player's movement
+ G_PredictPlayerMove( ent, (float)frames / sv_fps.integer );
+ // save network bandwidth
+ SnapVector( ent->s.pos.trBase );
+ }
+//unlagged - smooth clients #1
+
+//unlagged - backward reconciliation #1
+ // store the client's position for backward reconciliation later
+ G_StoreHistory( ent );
+//unlagged - backward reconciliation #1
+
+ // set the bit for the reachability area the client is currently in
+// i = trap_AAS_PointReachabilityAreaIndex( ent->client->ps.origin );
+// ent->client->areabits[i >> 3] |= 1 << (i & 7);
+}
+
+
diff --git a/code/game/g_admin.c b/code/game/g_admin.c
new file mode 100644
index 0000000..ded5121
--- /dev/null
+++ b/code/game/g_admin.c
@@ -0,0 +1,3470 @@
+/*
+===========================================================================
+Copyright (C) 2004-2006 Tony J. White
+
+This file is part of the Open Arena source code.
+
+Originally copied from Tremulous under GPL version 2 including any later version.
+
+Several modifications, additions, and deletions were made by developers of the
+Open Arena source code.
+
+This shrubbot implementation is the original work of Tony J. White.
+
+Contains contributions from Wesley van Beelen, Chris Bajumpaa, Josh Menke,
+and Travis Maurer.
+
+The functionality of this code mimics the behaviour of the currently
+inactive project shrubet (http://www.etstats.com/shrubet/index.php?ver=2)
+by Ryan Mannion. However, shrubet was a closed-source project and
+none of it's code has been copied, only it's functionality.
+
+Open Arena Source code 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.
+
+Open Arena Source code 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 Open Arena Source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+/* KK-OAX TODO
+1. Clean up the default admin levels to include the commands which I have added
+3. Implement Disorientation in Code
+4. DEBUG, DEBUG, DEBUG
+*/
+
+#include "g_local.h"
+
+// big ugly global buffer for use with buffered printing of long outputs
+static char g_bfb[ 32000 ];
+
+// note: list ordered alphabetically
+g_admin_cmd_t g_admin_cmds[ ] =
+ {
+ {"adjustban", G_admin_adjustban, "b",
+ "change the duration or reason of a ban. duration is specified as "
+ "numbers followed by units 'w' (weeks), 'd' (days), 'h' (hours) or "
+ "'m' (minutes), or seconds if no units are specified. if the duration is"
+ " preceded by a + or -, the ban duration will be extended or shortened by"
+ " the specified amount",
+ "[^3ban#^7] (^5duration^7) (^5reason^7)"
+ },
+
+ {"admintest", G_admin_admintest, "a",
+ "display your current admin level",
+ ""
+ },
+
+ {"allready", G_admin_allready, "y",
+ "makes everyone ready in intermission",
+ ""
+ },
+
+ {"ban", G_admin_ban, "b",
+ "ban a player by IP and GUID with an optional expiration time and reason."
+ " duration is specified as numbers followed by units 'w' (weeks), 'd' "
+ "(days), 'h' (hours) or 'm' (minutes), or seconds if no units are "
+ "specified",
+ "[^3name|slot#|IP^7] (^5duration^7) (^5reason^7)"
+ },
+
+ {"cancelvote", G_admin_cancelvote, "c",
+ "cancel a vote taking place",
+ ""
+ },
+ //KK-OAX
+ {"disorient", G_admin_disorient, "d",
+ "disorient a player by flipping player's view and controls",
+ "[^3name|slot#^7] (^hreason^7)"
+ },
+ //{"fling", G_admin_fling, "d",
+ // "throws the player specified",
+ // "[^3name|slot#^7]"
+ //},
+
+ {"help", G_admin_help, "h",
+ "display commands available to you or help on a specific command",
+ "(^5command^7)"
+ },
+
+ {"kick", G_admin_kick, "k",
+ "kick a player with an optional reason",
+ "[^3name|slot#^7] (^5reason^7)"
+ },
+
+ {"listadmins", G_admin_listadmins, "D",
+ "display a list of all server admins and their levels",
+ "(^5name|start admin#^7)"
+ },
+
+ {"listplayers", G_admin_listplayers, "i",
+ "display a list of players, their client numbers and their levels",
+ ""
+ },
+
+ {"lock", G_admin_lock, "K",
+ "lock a team to prevent anyone from joining it",
+ "[^3a|h^7]"
+ },
+ //KK-OAX
+ {"map", G_admin_map, "M",
+ "load a map",
+ "[^3mapname^7]"
+ },
+
+ {"mute", G_admin_mute, "m",
+ "mute a player",
+ "[^3name|slot#^7]"
+ },
+
+ {"namelog", G_admin_namelog, "e",
+ "display a list of names used by recently connected players",
+ "(^5name^7)"
+ },
+
+ {"nextmap", G_admin_nextmap, "n",
+ "go to the next map in the cycle",
+ ""
+ },
+ //KK-OAX
+ {"orient", G_admin_orient, "d",
+ "orient a player after a !disorient", "[^3name|slot#^7]"
+ },
+
+ {"passvote", G_admin_passvote, "V",
+ "pass a vote currently taking place",
+ ""
+ },
+
+ {"putteam", G_admin_putteam, "p",
+ "move a player to a specified team",
+ "[^3name|slot#^7] [^3h|a|s^7]"
+ },
+
+ {"readconfig", G_admin_readconfig, "G",
+ "reloads the admin config file and refreshes permission flags",
+ ""
+ },
+
+ {"rename", G_admin_rename, "N",
+ "rename a player",
+ "[^3name|slot#^7] [^3new name^7]"
+ },
+
+ {"restart", G_admin_restart, "r",
+ "restart the current map (optionally using named layout)",
+ ""
+ },
+
+ {"setlevel", G_admin_setlevel, "s",
+ "sets the admin level of a player",
+ "[^3name|slot#|admin#^7] [^3level^7]"
+ },
+
+ {"showbans", G_admin_showbans, "B",
+ "display a (partial) list of active bans",
+ "(^5start at ban#^7) (^5name|IP^7)"
+ },
+ //KK-OAX
+ {"shuffle", G_admin_shuffle, "f",
+ "Shuffles the teams"
+ ""
+ },
+
+ {"slap", G_admin_slap, "S",
+ "Reduces the health of the selected player by the damage specified",
+ "[^3name|slot#] [damage] [reason]"
+ },
+
+ {"spec999", G_admin_spec999, "P",
+ "move 999 pingers to the spectator team",
+ ""},
+
+ {"time", G_admin_time, "C",
+ "show the current local server time",
+ ""},
+
+ {"unban", G_admin_unban, "b",
+ "unbans a player specified by the slot as seen in showbans",
+ "[^3ban#^7]"
+ },
+
+ {"unlock", G_admin_unlock, "K",
+ "unlock a locked team",
+ "[^3a|h^7]"
+ },
+
+ {"unmute", G_admin_mute, "m",
+ "unmute a muted player",
+ "[^3name|slot#^7]"
+ },
+
+//KK-OAX
+ {"warn", G_admin_warn, "w",
+ "warn a player",
+ "[^3name|slot#^7] [reason]"
+ }
+
+ };
+
+static int adminNumCmds = sizeof( g_admin_cmds ) / sizeof( g_admin_cmds[ 0 ] );
+
+static int admin_level_maxname = 0;
+g_admin_level_t *g_admin_levels[ MAX_ADMIN_LEVELS ];
+g_admin_admin_t *g_admin_admins[ MAX_ADMIN_ADMINS ];
+g_admin_ban_t *g_admin_bans[ MAX_ADMIN_BANS ];
+g_admin_command_t *g_admin_commands[ MAX_ADMIN_COMMANDS ];
+g_admin_namelog_t *g_admin_namelog[ MAX_ADMIN_NAMELOGS ];
+//KK-OAX Load us up some warnings here....
+g_admin_warning_t *g_admin_warnings[ MAX_ADMIN_WARNINGS ];
+
+qboolean G_admin_permission( gentity_t *ent, char flag )
+{
+ int i;
+ int l = 0;
+ char *flags;
+
+ // console always wins
+ if( !ent )
+ return qtrue;
+
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ {
+ if( !Q_stricmp( ent->client->pers.guid, g_admin_admins[ i ]->guid ) )
+ {
+ flags = g_admin_admins[ i ]->flags;
+ while( *flags )
+ {
+ if( *flags == flag )
+ return qtrue;
+ else if( *flags == '-' )
+ {
+ while( *flags++ )
+ {
+ if( *flags == flag )
+ return qfalse;
+ if( *flags == '+' )
+ break;
+ }
+ }
+ else if( *flags == '*' )
+ {
+ while( *flags++ )
+ {
+ if( *flags == flag )
+ return qfalse;
+ }
+ // flags with significance only for individuals (
+ // like ADMF_INCOGNITO and ADMF_IMMUTABLE are NOT covered
+ // by the '*' wildcard. They must be specified manually.
+ return ( flag != ADMF_INCOGNITO && flag != ADMF_IMMUTABLE );
+ }
+ flags++;
+ }
+ l = g_admin_admins[ i ]->level;
+ }
+ }
+ for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
+ {
+ if( g_admin_levels[ i ]->level == l )
+ {
+ flags = g_admin_levels[ i ]->flags;
+ while( *flags )
+ {
+ if( *flags == flag )
+ return qtrue;
+ if( *flags == '*' )
+ {
+ while( *flags++ )
+ {
+ if( *flags == flag )
+ return qfalse;
+ }
+ // flags with significance only for individuals (
+ // like ADMF_INCOGNITO and ADMF_IMMUTABLE are NOT covered
+ // by the '*' wildcard. They must be specified manually.
+ return ( flag != ADMF_INCOGNITO && flag != ADMF_IMMUTABLE );
+ }
+ flags++;
+ }
+ }
+ }
+ return qfalse;
+}
+
+qboolean G_admin_name_check( gentity_t *ent, char *name, char *err, int len )
+{
+ int i;
+ gclient_t *client;
+ char testName[ MAX_NAME_LENGTH ] = {""};
+ char name2[ MAX_NAME_LENGTH ] = {""};
+
+ G_SanitiseString( name, name2, sizeof( name2 ) );
+
+ if( !Q_stricmp( name2, "UnnamedPlayer" ) )
+ return qtrue;
+
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ client = &level.clients[ i ];
+ if( client->pers.connected == CON_DISCONNECTED )
+ continue;
+
+ // can rename ones self to the same name using different colors
+ if( i == ( ent - g_entities ) )
+ continue;
+
+ G_SanitiseString( client->pers.netname, testName, sizeof( testName ) );
+ if( !Q_stricmp( name2, testName ) )
+ {
+ Com_sprintf( err, len, "The name '%s^7' is already in use", name );
+ return qfalse;
+ }
+ }
+
+ if( !g_adminNameProtect.integer )
+ return qtrue;
+
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ {
+ if( g_admin_admins[ i ]->level < 1 )
+ continue;
+ G_SanitiseString( g_admin_admins[ i ]->name, testName, sizeof( testName ) );
+ if( !Q_stricmp( name2, testName ) &&
+ Q_stricmp( ent->client->pers.guid, g_admin_admins[ i ]->guid ) )
+ {
+ Com_sprintf( err, len, "The name '%s^7' belongs to an admin, "
+ "please use another name", name );
+ return qfalse;
+ }
+ }
+ return qtrue;
+}
+
+static qboolean admin_higher_guid( char *admin_guid, char *victim_guid )
+{
+ int i;
+ int alevel = 0;
+
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ {
+ if( !Q_stricmp( admin_guid, g_admin_admins[ i ]->guid ) )
+ {
+ alevel = g_admin_admins[ i ]->level;
+ break;
+ }
+ }
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ {
+ if( !Q_stricmp( victim_guid, g_admin_admins[ i ]->guid ) )
+ {
+ if( alevel < g_admin_admins[ i ]->level )
+ return qfalse;
+ return !strstr( g_admin_admins[ i ]->flags, va( "%c", ADMF_IMMUTABLE ) );
+ }
+ }
+ return qtrue;
+}
+
+static qboolean admin_higher( gentity_t *admin, gentity_t *victim )
+{
+
+ // console always wins
+ if( !admin )
+ return qtrue;
+ // just in case
+ if( !victim )
+ return qtrue;
+
+ return admin_higher_guid( admin->client->pers.guid,
+ victim->client->pers.guid );
+}
+
+//KK-OAX Moved the Read/Write int/String functions to g_fileops.c for portability
+//across GAME
+
+//KK-OAX Added Warnings
+static void admin_writeconfig( void )
+{
+ fileHandle_t f;
+ int len, i, j;
+ int t;
+ char levels[ MAX_STRING_CHARS ] = {""};
+
+ if( !g_admin.string[ 0 ] )
+ {
+ G_Printf( S_COLOR_YELLOW "WARNING: g_admin is not set. "
+ " configuration will not be saved to a file.\n" );
+ return;
+ }
+ t = trap_RealTime( NULL );
+ len = trap_FS_FOpenFile( g_admin.string, &f, FS_WRITE );
+ if( len < 0 )
+ {
+ G_Printf( "admin_writeconfig: could not open g_admin file \"%s\"\n",
+ g_admin.string );
+ return;
+ }
+ for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
+ {
+ trap_FS_Write( "[level]\n", 8, f );
+ trap_FS_Write( "level = ", 10, f );
+ writeFile_int( g_admin_levels[ i ]->level, f );
+ trap_FS_Write( "name = ", 10, f );
+ writeFile_string( g_admin_levels[ i ]->name, f );
+ trap_FS_Write( "flags = ", 10, f );
+ writeFile_string( g_admin_levels[ i ]->flags, f );
+ trap_FS_Write( "\n", 1, f );
+ }
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ {
+ // don't write level 0 users
+ if( g_admin_admins[ i ]->level == 0 )
+ continue;
+
+ trap_FS_Write( "[admin]\n", 8, f );
+ trap_FS_Write( "name = ", 10, f );
+ writeFile_string( g_admin_admins[ i ]->name, f );
+ trap_FS_Write( "guid = ", 10, f );
+ writeFile_string( g_admin_admins[ i ]->guid, f );
+ trap_FS_Write( "level = ", 10, f );
+ writeFile_int( g_admin_admins[ i ]->level, f );
+ trap_FS_Write( "flags = ", 10, f );
+ writeFile_string( g_admin_admins[ i ]->flags, f );
+ trap_FS_Write( "\n", 1, f );
+ }
+ for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
+ {
+ // don't write expired bans
+ // if expires is 0, then it's a perm ban
+ if( g_admin_bans[ i ]->expires != 0 &&
+ ( g_admin_bans[ i ]->expires - t ) < 1 )
+ continue;
+
+ trap_FS_Write( "[ban]\n", 6, f );
+ trap_FS_Write( "name = ", 10, f );
+ writeFile_string( g_admin_bans[ i ]->name, f );
+ trap_FS_Write( "guid = ", 10, f );
+ writeFile_string( g_admin_bans[ i ]->guid, f );
+ trap_FS_Write( "ip = ", 10, f );
+ writeFile_string( g_admin_bans[ i ]->ip, f );
+ trap_FS_Write( "reason = ", 10, f );
+ writeFile_string( g_admin_bans[ i ]->reason, f );
+ trap_FS_Write( "made = ", 10, f );
+ writeFile_string( g_admin_bans[ i ]->made, f );
+ trap_FS_Write( "expires = ", 10, f );
+ writeFile_int( g_admin_bans[ i ]->expires, f );
+ trap_FS_Write( "banner = ", 10, f );
+ writeFile_string( g_admin_bans[ i ]->banner, f );
+ trap_FS_Write( "\n", 1, f );
+ }
+ for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
+ {
+ levels[ 0 ] = '\0';
+ trap_FS_Write( "[command]\n", 10, f );
+ trap_FS_Write( "command = ", 10, f );
+ writeFile_string( g_admin_commands[ i ]->command, f );
+ trap_FS_Write( "exec = ", 10, f );
+ writeFile_string( g_admin_commands[ i ]->exec, f );
+ trap_FS_Write( "desc = ", 10, f );
+ writeFile_string( g_admin_commands[ i ]->desc, f );
+ trap_FS_Write( "levels = ", 10, f );
+ for( j = 0; g_admin_commands[ i ]->levels[ j ] != -1; j++ )
+ {
+ Q_strcat( levels, sizeof( levels ),
+ va( "%i ", g_admin_commands[ i ]->levels[ j ] ) );
+ }
+ writeFile_string( levels, f );
+ trap_FS_Write( "\n", 1, f );
+ }
+ for( i = 0; i < MAX_ADMIN_WARNINGS && g_admin_warnings[ i ]; i++ )
+ {
+ // don't write expired warnings
+ // if expires is 0, then it's a perm warning
+ // it will get loaded everytime they connect!!!!
+ if( g_admin_warnings[ i ]->expires != 0 &&
+ ( g_admin_warnings[ i ]->expires - t ) < 1 )
+ continue;
+
+ trap_FS_Write( "[warning]\n", 10, f );
+ trap_FS_Write( "name = ", 10, f );
+ writeFile_string( g_admin_warnings[ i ]->name, f );
+ trap_FS_Write( "guid = ", 10, f );
+ writeFile_string( g_admin_warnings[ i ]->guid, f );
+ trap_FS_Write( "ip = ", 10, f );
+ writeFile_string( g_admin_warnings[ i ]->ip, f );
+ trap_FS_Write( "warning = ", 10, f );
+ writeFile_string( g_admin_warnings[ i ]->warning, f );
+ trap_FS_Write( "made = ", 10, f );
+ writeFile_string( g_admin_warnings[ i ]->made, f );
+ trap_FS_Write( "expires = ", 10, f );
+ writeFile_int( g_admin_warnings[ i ]->expires, f );
+ trap_FS_Write( "warner = ", 10, f );
+ writeFile_string( g_admin_warnings[ i ]->warner, f );
+ trap_FS_Write( "\n", 1, f );
+ }
+ trap_FS_FCloseFile( f );
+}
+
+
+// if we can't parse any levels from readconfig, set up default
+// ones to make new installs easier for admins
+//KK-OAX TODO: Add all features to default levels...
+static void admin_default_levels( void )
+{
+ g_admin_level_t *l;
+ int i;
+
+ for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
+ {
+ BG_Free( g_admin_levels[ i ] );
+ g_admin_levels[ i ] = NULL;
+ }
+ for( i = 0; i <= 5; i++ )
+ {
+ l = BG_Alloc( sizeof( g_admin_level_t ) );
+ l->level = i;
+ *l->name = '\0';
+ *l->flags = '\0';
+ g_admin_levels[ i ] = l;
+ }
+ Q_strncpyz( g_admin_levels[ 0 ]->name, "^4Unknown Player",
+ sizeof( l->name ) );
+ Q_strncpyz( g_admin_levels[ 0 ]->flags, "ahC", sizeof( l->flags ) );
+
+ Q_strncpyz( g_admin_levels[ 1 ]->name, "^5Server Regular",
+ sizeof( l->name ) );
+ Q_strncpyz( g_admin_levels[ 1 ]->flags, "iahC", sizeof( l->flags ) );
+
+ Q_strncpyz( g_admin_levels[ 2 ]->name, "^6Team Manager",
+ sizeof( l->name ) );
+ Q_strncpyz( g_admin_levels[ 2 ]->flags, "iahCpPwr", sizeof( l->flags ) );
+
+ Q_strncpyz( g_admin_levels[ 3 ]->name, "^2Junior Admin",
+ sizeof( l->name ) );
+ Q_strncpyz( g_admin_levels[ 3 ]->flags, "iahCpPwrkmfKncN?", sizeof( l->flags ) );
+
+ Q_strncpyz( g_admin_levels[ 4 ]->name, "^3Senior Admin",
+ sizeof( l->name ) );
+ Q_strncpyz( g_admin_levels[ 4 ]->flags, "iahCpPwrkmfKncN?MVdBbeDS51", sizeof( l->flags ) );
+
+ Q_strncpyz( g_admin_levels[ 5 ]->name, "^1Server Operator",
+ sizeof( l->name ) );
+ Q_strncpyz( g_admin_levels[ 5 ]->flags, "*", sizeof( l->flags ) );
+ admin_level_maxname = 15;
+}
+
+// return a level for a player entity.
+int G_admin_level( gentity_t *ent )
+{
+ int i;
+
+ if( !ent )
+ {
+ return MAX_ADMIN_LEVELS;
+ }
+
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ {
+ if( !Q_stricmp( g_admin_admins[ i ]->guid, ent->client->pers.guid ) )
+ return g_admin_admins[ i ]->level;
+ }
+
+ return 0;
+}
+
+static qboolean admin_command_permission( gentity_t *ent, char *command )
+{
+ int i, j;
+ int level;
+
+ if( !ent )
+ return qtrue;
+ level = ent->client->pers.adminLevel;
+ for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
+ {
+ if( !Q_stricmp( command, g_admin_commands[ i ]->command ) )
+ {
+ for( j = 0; g_admin_commands[ i ]->levels[ j ] != -1; j++ )
+ {
+ if( g_admin_commands[ i ]->levels[ j ] == level )
+ {
+ return qtrue;
+ }
+ }
+ }
+ }
+ return qfalse;
+}
+
+static void admin_log( gentity_t *admin, char *cmd, int skiparg )
+{
+ fileHandle_t f;
+ int len, i, j;
+ char string[ MAX_STRING_CHARS ];
+ int min, tens, sec;
+ g_admin_admin_t *a;
+ g_admin_level_t *l;
+ char flags[ MAX_ADMIN_FLAGS * 2 ];
+ gentity_t *victim = NULL;
+ int pids[ MAX_CLIENTS ];
+ char name[ MAX_NAME_LENGTH ];
+
+ if( !g_adminLog.string[ 0 ] )
+ return;
+
+
+ len = trap_FS_FOpenFile( g_adminLog.string, &f, FS_APPEND );
+ if( len < 0 )
+ {
+ G_Printf( "admin_log: error could not open %s\n", g_adminLog.string );
+ return;
+ }
+
+ sec = level.time / 1000;
+ min = sec / 60;
+ sec -= min * 60;
+ tens = sec / 10;
+ sec -= tens * 10;
+
+ *flags = '\0';
+ if( admin )
+ {
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ {
+ if( !Q_stricmp( g_admin_admins[ i ]->guid , admin->client->pers.guid ) )
+ {
+
+ a = g_admin_admins[ i ];
+ Q_strncpyz( flags, a->flags, sizeof( flags ) );
+ for( j = 0; j < MAX_ADMIN_LEVELS && g_admin_levels[ j ]; j++ )
+ {
+ if( g_admin_levels[ j ]->level == a->level )
+ {
+ l = g_admin_levels[ j ];
+ Q_strcat( flags, sizeof( flags ), l->flags );
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if( G_SayArgc() > 1 + skiparg )
+ {
+ G_SayArgv( 1 + skiparg, name, sizeof( name ) );
+ if( G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) == 1 )
+ {
+ victim = &g_entities[ pids[ 0 ] ];
+ }
+ }
+
+ if( victim && Q_stricmp( cmd, "attempted" ) )
+ {
+ Com_sprintf( string, sizeof( string ),
+ "%3i:%i%i: %i: %s: %s: %s: %s: %s: %s: \"%s\"\n",
+ min,
+ tens,
+ sec,
+ ( admin ) ? admin->s.clientNum : -1,
+ ( admin ) ? admin->client->pers.guid
+ : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+ ( admin ) ? admin->client->pers.netname : "console",
+ flags,
+ cmd,
+ victim->client->pers.guid,
+ victim->client->pers.netname,
+ G_SayConcatArgs( 2 + skiparg ) );
+ }
+ else
+ {
+ Com_sprintf( string, sizeof( string ),
+ "%3i:%i%i: %i: %s: %s: %s: %s: \"%s\"\n",
+ min,
+ tens,
+ sec,
+ ( admin ) ? admin->s.clientNum : -1,
+ ( admin ) ? admin->client->pers.guid
+ : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+ ( admin ) ? admin->client->pers.netname : "console",
+ flags,
+ cmd,
+ G_SayConcatArgs( 1 + skiparg ) );
+ }
+ trap_FS_Write( string, strlen( string ), f );
+ trap_FS_FCloseFile( f );
+}
+
+static int admin_listadmins( gentity_t *ent, int start, char *search )
+{
+ int drawn = 0;
+ char guid_stub[9];
+ char name[ MAX_NAME_LENGTH ] = {""};
+ char name2[ MAX_NAME_LENGTH ] = {""};
+ char lname[ MAX_NAME_LENGTH ] = {""};
+ int i, j;
+ gentity_t *vic;
+ int l = 0;
+ qboolean dup = qfalse;
+
+ ADMBP_begin();
+
+ // print out all connected players regardless of level if name searching
+ for( i = 0; i < level.maxclients && search[ 0 ]; i++ )
+ {
+ vic = &g_entities[ i ];
+
+ if( !vic->client || vic->client->pers.connected != CON_CONNECTED )
+ continue;
+
+ l = vic->client->pers.adminLevel;
+
+ G_SanitiseString( vic->client->pers.netname, name, sizeof( name ) );
+ if( !strstr( name, search ) )
+ continue;
+
+ for( j = 0; j < 8; j++ )
+ guid_stub[ j ] = vic->client->pers.guid[ j + 24 ];
+ guid_stub[ j ] = '\0';
+
+ lname[ 0 ] = '\0';
+ for( j = 0; j < MAX_ADMIN_LEVELS && g_admin_levels[ j ]; j++ )
+ {
+ if( g_admin_levels[ j ]->level == l )
+ {
+ int k, colorlen;
+
+ for( colorlen = k = 0; g_admin_levels[ j ]->name[ k ]; k++ )
+ if( Q_IsColorString( &g_admin_levels[ j ]->name[ k ] ) )
+ colorlen += 2;
+ Com_sprintf( lname, sizeof( lname ), "%*s",
+ admin_level_maxname + colorlen,
+ g_admin_levels[ j ]->name );
+ break;
+ }
+ }
+ ADMBP( va( "%4i %4i %s^7 (*%s) %s^7\n",
+ i,
+ l,
+ lname,
+ guid_stub,
+ vic->client->pers.netname ) );
+ drawn++;
+ }
+
+ for( i = start; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] &&
+ drawn < MAX_ADMIN_LISTITEMS; i++ )
+ {
+ if( search[ 0 ] )
+ {
+ G_SanitiseString( g_admin_admins[ i ]->name, name, sizeof( name ) );
+ if( !strstr( name, search ) )
+ continue;
+
+ // verify we don't have the same guid/name pair in connected players
+ // since we don't want to draw the same player twice
+ dup = qfalse;
+ for( j = 0; j < level.maxclients; j++ )
+ {
+ vic = &g_entities[ j ];
+ if( !vic->client || vic->client->pers.connected != CON_CONNECTED )
+ continue;
+ G_SanitiseString( vic->client->pers.netname, name2, sizeof( name2 ) );
+ if( !Q_stricmp( vic->client->pers.guid, g_admin_admins[ i ]->guid ) &&
+ strstr( name2, search ) )
+ {
+ dup = qtrue;
+ break;
+ }
+ }
+ if( dup )
+ continue;
+ }
+ for( j = 0; j < 8; j++ )
+ guid_stub[ j ] = g_admin_admins[ i ]->guid[ j + 24 ];
+ guid_stub[ j ] = '\0';
+
+ lname[ 0 ] = '\0';
+ for( j = 0; j < MAX_ADMIN_LEVELS && g_admin_levels[ j ]; j++ )
+ {
+ if( g_admin_levels[ j ]->level == g_admin_admins[ i ]->level )
+ {
+ int k, colorlen;
+
+ for( colorlen = k = 0; g_admin_levels[ j ]->name[ k ]; k++ )
+ if( Q_IsColorString( &g_admin_levels[ j ]->name[ k ] ) )
+ colorlen += 2;
+ Com_sprintf( lname, sizeof( lname ), "%*s",
+ admin_level_maxname + colorlen,
+ g_admin_levels[ j ]->name );
+ break;
+ }
+ }
+ ADMBP( va( "%4i %4i %s^7 (*%s) %s^7\n",
+ ( i + MAX_CLIENTS ),
+ g_admin_admins[ i ]->level,
+ lname,
+ guid_stub,
+ g_admin_admins[ i ]->name ) );
+ drawn++;
+ }
+ ADMBP_end();
+ return drawn;
+}
+
+void G_admin_duration( int secs, char *duration, int dursize )
+{
+
+ if( secs > ( 60 * 60 * 24 * 365 * 50 ) || secs < 0 )
+ Q_strncpyz( duration, "PERMANENT", dursize );
+ else if( secs >= ( 60 * 60 * 24 * 365 ) )
+ Com_sprintf( duration, dursize, "%1.1f years",
+ ( secs / ( 60 * 60 * 24 * 365.0f ) ) );
+ else if( secs >= ( 60 * 60 * 24 * 90 ) )
+ Com_sprintf( duration, dursize, "%1.1f weeks",
+ ( secs / ( 60 * 60 * 24 * 7.0f ) ) );
+ else if( secs >= ( 60 * 60 * 24 ) )
+ Com_sprintf( duration, dursize, "%1.1f days",
+ ( secs / ( 60 * 60 * 24.0f ) ) );
+ else if( secs >= ( 60 * 60 ) )
+ Com_sprintf( duration, dursize, "%1.1f hours",
+ ( secs / ( 60 * 60.0f ) ) );
+ else if( secs >= 60 )
+ Com_sprintf( duration, dursize, "%1.1f minutes",
+ ( secs / 60.0f ) );
+ else
+ Com_sprintf( duration, dursize, "%i seconds", secs );
+}
+
+qboolean G_admin_ban_check( char *userinfo, char *reason, int rlen )
+{
+ char *guid, *ip;
+ int i;
+ int t;
+
+ *reason = '\0';
+ t = trap_RealTime( NULL );
+ if( !*userinfo )
+ return qfalse;
+ ip = Info_ValueForKey( userinfo, "ip" );
+ if( !*ip )
+ return qfalse;
+ guid = Info_ValueForKey( userinfo, "cl_guid" );
+ for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
+ {
+ // 0 is for perm ban
+ if( g_admin_bans[ i ]->expires != 0 &&
+ ( g_admin_bans[ i ]->expires - t ) < 1 )
+ continue;
+ if( strstr( ip, g_admin_bans[ i ]->ip ) )
+ {
+ char duration[ 32 ];
+ G_admin_duration( ( g_admin_bans[ i ]->expires - t ),
+ duration, sizeof( duration ) );
+ Com_sprintf(
+ reason,
+ rlen,
+ "You have been banned by %s^7 reason: %s^7 expires: %s",
+ g_admin_bans[ i ]->banner,
+ g_admin_bans[ i ]->reason,
+ duration
+ );
+ G_Printf( "Banned player tried to connect from IP %s\n", ip );
+ return qtrue;
+ }
+ if( *guid && !Q_stricmp( g_admin_bans[ i ]->guid, guid ) )
+ {
+ char duration[ 32 ];
+ G_admin_duration( ( g_admin_bans[ i ]->expires - t ),
+ duration, sizeof( duration ) );
+ Com_sprintf(
+ reason,
+ rlen,
+ "You have been banned by %s^7 reason: %s^7 expires: %s",
+ g_admin_bans[ i ]->banner,
+ g_admin_bans[ i ]->reason,
+ duration
+ );
+ G_Printf( "Banned player tried to connect with GUID %s\n", guid );
+ return qtrue;
+ }
+ }
+ return qfalse;
+}
+
+qboolean G_admin_cmd_check( gentity_t *ent, qboolean say )
+{
+ int i;
+ char command[ MAX_ADMIN_CMD_LEN ];
+ char *cmd;
+ int skip = 0;
+
+ command[ 0 ] = '\0';
+ G_SayArgv( 0, command, sizeof( command ) );
+ if( !command[ 0 ] )
+ return qfalse;
+ if( !Q_stricmp( command, "say" ) ||
+ ( !Q_stricmp( command, "say_team" ) &&
+ G_admin_permission( ent, ADMF_TEAMCHAT_CMD ) ) )
+ {
+ skip = 1;
+ G_SayArgv( 1, command, sizeof( command ) );
+ }
+
+ if( command[ 0 ] == '!' )
+ {
+ cmd = &command[ 1 ];
+ }
+ else
+ {
+ return qfalse;
+ }
+
+ for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
+ {
+ if( Q_stricmp( cmd, g_admin_commands[ i ]->command ) )
+ continue;
+
+ if( admin_command_permission( ent, cmd ) )
+ {
+ // flooding say will have already been accounted for in ClientCommand
+ if( !say && G_FloodLimited( ent ) )
+ return qtrue;
+ trap_SendConsoleCommand( EXEC_APPEND, g_admin_commands[ i ]->exec );
+ admin_log( ent, cmd, skip );
+ }
+ else
+ {
+ ADMP( va( "^3!%s: ^7permission denied\n", g_admin_commands[ i ]->command ) );
+ admin_log( ent, "attempted", skip - 1 );
+ }
+ return qtrue;
+ }
+
+ for( i = 0; i < adminNumCmds; i++ )
+ {
+ if( Q_stricmp( cmd, g_admin_cmds[ i ].keyword ) )
+ continue;
+
+ if( G_admin_permission( ent, g_admin_cmds[ i ].flag[ 0 ] ) )
+ {
+ // flooding say will have already been accounted for in ClientCommand
+ if( !say && G_FloodLimited( ent ) )
+ return qtrue;
+ g_admin_cmds[ i ].handler( ent, skip );
+ admin_log( ent, cmd, skip );
+ }
+ else
+ {
+ ADMP( va( "^3!%s: ^7permission denied\n", g_admin_cmds[ i ].keyword ) );
+ admin_log( ent, "attempted", skip - 1 );
+ }
+ return qtrue;
+ }
+ return qfalse;
+}
+
+void G_admin_namelog_cleanup( )
+{
+ int i;
+
+ for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
+ {
+ BG_Free( g_admin_namelog[ i ] );
+ g_admin_namelog[ i ] = NULL;
+ }
+}
+
+void G_admin_namelog_update( gclient_t *client, qboolean disconnect )
+{
+ int i, j;
+ g_admin_namelog_t *namelog;
+ char n1[ MAX_NAME_LENGTH ];
+ char n2[ MAX_NAME_LENGTH ];
+ int clientNum = ( client - level.clients );
+
+ G_SanitiseString( client->pers.netname, n1, sizeof( n1 ) );
+ for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
+ {
+ if( disconnect && g_admin_namelog[ i ]->slot != clientNum )
+ continue;
+
+ if( !disconnect && !( g_admin_namelog[ i ]->slot == clientNum ||
+ g_admin_namelog[ i ]->slot == -1 ) )
+ {
+ continue;
+ }
+
+ if( !Q_stricmp( client->pers.ip, g_admin_namelog[ i ]->ip ) &&
+ !Q_stricmp( client->pers.guid, g_admin_namelog[ i ]->guid ) )
+ {
+ for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES &&
+ g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
+ {
+ G_SanitiseString( g_admin_namelog[ i ]->name[ j ], n2, sizeof( n2 ) );
+ if( !Q_stricmp( n1, n2 ) )
+ break;
+ }
+ if( j == MAX_ADMIN_NAMELOG_NAMES )
+ j = MAX_ADMIN_NAMELOG_NAMES - 1;
+ Q_strncpyz( g_admin_namelog[ i ]->name[ j ], client->pers.netname,
+ sizeof( g_admin_namelog[ i ]->name[ j ] ) );
+ g_admin_namelog[ i ]->slot = ( disconnect ) ? -1 : clientNum;
+
+ // if this player is connecting, they are no longer banned
+ if( !disconnect )
+ g_admin_namelog[ i ]->banned = qfalse;
+
+ return;
+ }
+ }
+ if( i >= MAX_ADMIN_NAMELOGS )
+ {
+ G_Printf( "G_admin_namelog_update: warning, g_admin_namelogs overflow\n" );
+ return;
+ }
+ namelog = BG_Alloc( sizeof( g_admin_namelog_t ) );
+ memset( namelog, 0, sizeof( namelog ) );
+ for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES; j++ )
+ namelog->name[ j ][ 0 ] = '\0';
+ Q_strncpyz( namelog->ip, client->pers.ip, sizeof( namelog->ip ) );
+ Q_strncpyz( namelog->guid, client->pers.guid, sizeof( namelog->guid ) );
+ Q_strncpyz( namelog->name[ 0 ], client->pers.netname,
+ sizeof( namelog->name[ 0 ] ) );
+ namelog->slot = ( disconnect ) ? -1 : clientNum;
+ g_admin_namelog[ i ] = namelog;
+}
+
+//KK-OAX Added Parsing Warnings
+qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
+{
+ g_admin_level_t *l = NULL;
+ g_admin_admin_t *a = NULL;
+ g_admin_ban_t *b = NULL;
+ g_admin_command_t *c = NULL;
+ g_admin_warning_t *w = NULL;
+ int lc = 0, ac = 0, bc = 0, cc = 0, wc = 0;
+ fileHandle_t f;
+ int len;
+ char *cnf, *cnf2;
+ char *t;
+ qboolean level_open, admin_open, ban_open, command_open, warning_open;
+ int i;
+
+ G_admin_cleanup();
+
+ if( !g_admin.string[ 0 ] )
+ {
+ ADMP( "^3!readconfig: g_admin is not set, not loading configuration "
+ "from a file\n" );
+ admin_default_levels();
+ return qfalse;
+ }
+
+ len = trap_FS_FOpenFile( g_admin.string, &f, FS_READ );
+ if( len < 0 )
+ {
+ G_Printf( "^3!readconfig: ^7could not open admin config file %s\n",
+ g_admin.string );
+ admin_default_levels();
+ return qfalse;
+ }
+ cnf = BG_Alloc( len + 1 );
+ cnf2 = cnf;
+ trap_FS_Read( cnf, len, f );
+ *( cnf + len ) = '\0';
+ trap_FS_FCloseFile( f );
+
+ admin_level_maxname = 0;
+
+ level_open = admin_open = ban_open = command_open = warning_open = qfalse;
+ COM_BeginParseSession( g_admin.string );
+ while( 1 )
+ {
+ t = COM_Parse( &cnf );
+ if( !*t )
+ break;
+
+ if( !Q_stricmp( t, "[level]" ) )
+ {
+ if( lc >= MAX_ADMIN_LEVELS )
+ return qfalse;
+ l = BG_Alloc( sizeof( g_admin_level_t ) );
+ g_admin_levels[ lc++ ] = l;
+ level_open = qtrue;
+ admin_open = ban_open = command_open = warning_open = qfalse;
+ }
+ else if( !Q_stricmp( t, "[admin]" ) )
+ {
+ if( ac >= MAX_ADMIN_ADMINS )
+ return qfalse;
+ a = BG_Alloc( sizeof( g_admin_admin_t ) );
+ g_admin_admins[ ac++ ] = a;
+ admin_open = qtrue;
+ level_open = ban_open = command_open = warning_open = qfalse;
+ }
+ else if( !Q_stricmp( t, "[ban]" ) )
+ {
+ if( bc >= MAX_ADMIN_BANS )
+ return qfalse;
+ b = BG_Alloc( sizeof( g_admin_ban_t ) );
+ g_admin_bans[ bc++ ] = b;
+ ban_open = qtrue;
+ level_open = admin_open = command_open = warning_open = qfalse;
+ }
+ else if( !Q_stricmp( t, "[command]" ) )
+ {
+ if( cc >= MAX_ADMIN_COMMANDS )
+ return qfalse;
+ c = BG_Alloc( sizeof( g_admin_command_t ) );
+ g_admin_commands[ cc++ ] = c;
+ c->levels[ 0 ] = -1;
+ command_open = qtrue;
+ level_open = admin_open = ban_open = warning_open = qfalse;
+ }
+ else if( !Q_stricmp( t, "[warning]" ) )
+ {
+ if( wc >= MAX_ADMIN_WARNINGS )
+ return qfalse;
+ w = BG_Alloc( sizeof( g_admin_warning_t ) );
+ g_admin_warnings[ wc++ ] = w;
+ warning_open = qtrue;
+ level_open = admin_open = ban_open = command_open = qfalse;
+ }
+ else if( level_open )
+ {
+ if( !Q_stricmp( t, "level" ) )
+ {
+ readFile_int( &cnf, &l->level );
+ }
+ else if( !Q_stricmp( t, "name" ) )
+ {
+ readFile_string( &cnf, l->name, sizeof( l->name ) );
+ }
+ else if( !Q_stricmp( t, "flags" ) )
+ {
+ readFile_string( &cnf, l->flags, sizeof( l->flags ) );
+ }
+ else
+ {
+ COM_ParseError( "[level] unrecognized token \"%s\"", t );
+ }
+ }
+ else if( admin_open )
+ {
+ if( !Q_stricmp( t, "name" ) )
+ {
+ readFile_string( &cnf, a->name, sizeof( a->name ) );
+ }
+ else if( !Q_stricmp( t, "guid" ) )
+ {
+ readFile_string( &cnf, a->guid, sizeof( a->guid ) );
+ }
+ else if( !Q_stricmp( t, "level" ) )
+ {
+ readFile_int( &cnf, &a->level );
+ }
+ else if( !Q_stricmp( t, "flags" ) )
+ {
+ readFile_string( &cnf, a->flags, sizeof( a->flags ) );
+ }
+ else
+ {
+ COM_ParseError( "[admin] unrecognized token \"%s\"", t );
+ }
+
+ }
+ else if( ban_open )
+ {
+ if( !Q_stricmp( t, "name" ) )
+ {
+ readFile_string( &cnf, b->name, sizeof( b->name ) );
+ }
+ else if( !Q_stricmp( t, "guid" ) )
+ {
+ readFile_string( &cnf, b->guid, sizeof( b->guid ) );
+ }
+ else if( !Q_stricmp( t, "ip" ) )
+ {
+ readFile_string( &cnf, b->ip, sizeof( b->ip ) );
+ }
+ else if( !Q_stricmp( t, "reason" ) )
+ {
+ readFile_string( &cnf, b->reason, sizeof( b->reason ) );
+ }
+ else if( !Q_stricmp( t, "made" ) )
+ {
+ readFile_string( &cnf, b->made, sizeof( b->made ) );
+ }
+ else if( !Q_stricmp( t, "expires" ) )
+ {
+ readFile_int( &cnf, &b->expires );
+ }
+ else if( !Q_stricmp( t, "banner" ) )
+ {
+ readFile_string( &cnf, b->banner, sizeof( b->banner ) );
+ }
+ else
+ {
+ COM_ParseError( "[ban] unrecognized token \"%s\"", t );
+ }
+ }
+ else if( command_open )
+ {
+ if( !Q_stricmp( t, "command" ) )
+ {
+ readFile_string( &cnf, c->command, sizeof( c->command ) );
+ }
+ else if( !Q_stricmp( t, "exec" ) )
+ {
+ readFile_string( &cnf, c->exec, sizeof( c->exec ) );
+ }
+ else if( !Q_stricmp( t, "desc" ) )
+ {
+ readFile_string( &cnf, c->desc, sizeof( c->desc ) );
+ }
+ else if( !Q_stricmp( t, "levels" ) )
+ {
+ char levels[ MAX_STRING_CHARS ] = {""};
+ char *level = levels;
+ char *lp;
+ int cmdlevel = 0;
+
+ readFile_string( &cnf, levels, sizeof( levels ) );
+ while( cmdlevel < MAX_ADMIN_LEVELS )
+ {
+ lp = COM_Parse( &level );
+ if( !*lp )
+ break;
+ c->levels[ cmdlevel++ ] = atoi( lp );
+ }
+ // ensure the list is -1 terminated
+ c->levels[ cmdlevel ] = -1;
+ }
+ else
+ {
+ COM_ParseError( "[command] unrecognized token \"%s\"", t );
+ }
+ }
+ else if( warning_open )
+ {
+ if( !Q_stricmp( t, "name" ) )
+ {
+ readFile_string( &cnf, w->name, sizeof( w->name ) );
+ }
+ else if( !Q_stricmp( t, "guid" ) )
+ {
+ readFile_string( &cnf, w->guid, sizeof( w->guid ) );
+ }
+ else if( !Q_stricmp( t, "ip" ) )
+ {
+ readFile_string( &cnf, w->ip, sizeof( w->ip ) );
+ }
+ else if( !Q_stricmp( t, "warning" ) )
+ {
+ readFile_string( &cnf, w->warning, sizeof( w->warning ) );
+ }
+ else if( !Q_stricmp( t, "made" ) )
+ {
+ readFile_string( &cnf, w->made, sizeof( w->made ) );
+ }
+ else if( !Q_stricmp( t, "expires" ) )
+ {
+ readFile_int( &cnf, &w->expires );
+ }
+ else if( !Q_stricmp( t, "warner" ) )
+ {
+ readFile_string( &cnf, w->warner, sizeof( w->warner ) );
+ }
+ else
+ {
+ COM_ParseError( "[warning] unrecognized token \"%s\"", t );
+ }
+ }
+ else
+ {
+ COM_ParseError( "unexpected token \"%s\"", t );
+ }
+ }
+ BG_Free( cnf2 );
+ ADMP( va( "^3!readconfig: ^7loaded %d levels, %d admins, %d bans, %d commands, %d warnings\n",
+ lc, ac, bc, cc, wc ) );
+ if( lc == 0 )
+ admin_default_levels();
+ else
+ {
+ // max printable name length for formatting
+ for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
+ {
+ len = Q_PrintStrlen( g_admin_levels[ i ]->name );
+ if( len > admin_level_maxname )
+ admin_level_maxname = len;
+ }
+ }
+ // reset adminLevel
+ for( i = 0; i < level.maxclients; i++ )
+ if( level.clients[ i ].pers.connected != CON_DISCONNECTED )
+ level.clients[ i ].pers.adminLevel = G_admin_level( &g_entities[ i ] );
+ return qtrue;
+}
+
+qboolean G_admin_time( gentity_t *ent, int skiparg )
+{
+ qtime_t qt;
+
+ trap_RealTime( &qt );
+ ADMP( va( "^3!time: ^7local time is %02i:%02i:%02i\n",
+ qt.tm_hour, qt.tm_min, qt.tm_sec ) );
+ return qtrue;
+}
+
+qboolean G_admin_setlevel( gentity_t *ent, int skiparg )
+{
+ char name[ MAX_NAME_LENGTH ] = {""};
+ char lstr[ 11 ]; // 10 is max strlen() for 32-bit int
+ char adminname[ MAX_NAME_LENGTH ] = {""};
+ char testname[ MAX_NAME_LENGTH ] = {""};
+ char guid[ 33 ];
+ int l, i;
+ gentity_t *vic = NULL;
+ qboolean updated = qfalse;
+ g_admin_admin_t *a;
+ qboolean found = qfalse;
+ qboolean numeric = qtrue;
+ int matches = 0;
+ int id = -1;
+
+
+ if( G_SayArgc() < 3 + skiparg )
+ {
+ ADMP( "^3!setlevel: ^7usage: !setlevel [name|slot#] [level]\n" );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, testname, sizeof( testname ) );
+ G_SayArgv( 2 + skiparg, lstr, sizeof( lstr ) );
+ l = atoi( lstr );
+ G_SanitiseString( testname, name, sizeof( name ) );
+ for( i = 0; i < sizeof( name ) && name[ i ]; i++ )
+ {
+ if( !isdigit( name[ i ] ) )
+ {
+ numeric = qfalse;
+ break;
+ }
+ }
+ if( numeric )
+ id = atoi( name );
+
+ if( ent && l > ent->client->pers.adminLevel )
+ {
+ ADMP( "^3!setlevel: ^7you may not use !setlevel to set a level higher "
+ "than your current level\n" );
+ return qfalse;
+ }
+
+ // if admin is activated for the first time on a running server, we need
+ // to ensure at least the default levels get created
+ if( !ent && !g_admin_levels[ 0 ] )
+ G_admin_readconfig(NULL, 0);
+
+ for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
+ {
+ if( g_admin_levels[ i ]->level == l )
+ {
+ found = qtrue;
+ break;
+ }
+ }
+ if( !found )
+ {
+ ADMP( "^3!setlevel: ^7level is not defined\n" );
+ return qfalse;
+ }
+
+ if( numeric && id >= 0 && id < level.maxclients )
+ vic = &g_entities[ id ];
+
+ if( vic && vic->client && vic->client->pers.connected != CON_DISCONNECTED )
+ {
+ Q_strncpyz( adminname, vic->client->pers.netname, sizeof( adminname ) );
+ Q_strncpyz( guid, vic->client->pers.guid, sizeof( guid ) );
+ matches = 1;
+ }
+ else if( numeric && id >= MAX_CLIENTS && id < MAX_CLIENTS + MAX_ADMIN_ADMINS
+ && g_admin_admins[ id - MAX_CLIENTS ] )
+ {
+ Q_strncpyz( adminname, g_admin_admins[ id - MAX_CLIENTS ]->name,
+ sizeof( adminname ) );
+ Q_strncpyz( guid, g_admin_admins[ id - MAX_CLIENTS ]->guid,
+ sizeof( guid ) );
+ matches = 1;
+ }
+ else
+ {
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] && matches < 2; i++ )
+ {
+ G_SanitiseString( g_admin_admins[ i ]->name, testname, sizeof( testname ) );
+ if( strstr( testname, name ) )
+ {
+ Q_strncpyz( adminname, g_admin_admins[ i ]->name, sizeof( adminname ) );
+ Q_strncpyz( guid, g_admin_admins[ i ]->guid, sizeof( guid ) );
+ matches++;
+ }
+ }
+ for( i = 0; i < level.maxclients && matches < 2; i++ )
+ {
+ if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
+ continue;
+ if( matches && !Q_stricmp( level.clients[ i ].pers.guid, guid ) )
+ {
+ vic = &g_entities[ i ];
+ continue;
+ }
+ G_SanitiseString( level.clients[ i ].pers.netname, testname,
+ sizeof( testname ) );
+ if( strstr( testname, name ) )
+ {
+ vic = &g_entities[ i ];
+ matches++;
+ Q_strncpyz( guid, vic->client->pers.guid, sizeof( guid ) );
+ }
+ }
+ if( vic && vic->client)
+ Q_strncpyz( adminname, vic->client->pers.netname, sizeof( adminname ) );
+ }
+
+ if( matches == 0 )
+ {
+ ADMP( "^3!setlevel:^7 no match. use !listplayers or !listadmins to "
+ "find an appropriate number to use instead of name.\n" );
+ return qfalse;
+ }
+ if( matches > 1 )
+ {
+ ADMP( "^3!setlevel:^7 more than one match. Use the admin number "
+ "instead:\n" );
+ admin_listadmins( ent, 0, name );
+ return qfalse;
+ }
+
+ if( ent && !admin_higher_guid( ent->client->pers.guid, guid ) )
+ {
+ ADMP( "^3!setlevel: ^7sorry, but your intended victim has a higher"
+ " admin level than you\n" );
+ return qfalse;
+ }
+
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ];i++ )
+ {
+ if( !Q_stricmp( g_admin_admins[ i ]->guid, guid ) )
+ {
+ g_admin_admins[ i ]->level = l;
+ Q_strncpyz( g_admin_admins[ i ]->name, adminname,
+ sizeof( g_admin_admins[ i ]->name ) );
+ updated = qtrue;
+ }
+ }
+ if( !updated )
+ {
+ if( i == MAX_ADMIN_ADMINS )
+ {
+ ADMP( "^3!setlevel: ^7too many admins\n" );
+ return qfalse;
+ }
+ a = BG_Alloc( sizeof( g_admin_admin_t ) );
+ a->level = l;
+ Q_strncpyz( a->name, adminname, sizeof( a->name ) );
+ Q_strncpyz( a->guid, guid, sizeof( a->guid ) );
+ *a->flags = '\0';
+ g_admin_admins[ i ] = a;
+ }
+
+ AP( va(
+ "print \"^3!setlevel: ^7%s^7 was given level %d admin rights by %s\n\"",
+ adminname, l, ( ent ) ? ent->client->pers.netname : "console" ) );
+ if( vic && vic->client )
+ vic->client->pers.adminLevel = l;
+
+ if( !g_admin.string[ 0 ] )
+ ADMP( "^3!setlevel: ^7WARNING g_admin not set, not saving admin record "
+ "to a file\n" );
+ else
+ admin_writeconfig();
+ return qtrue;
+}
+
+static qboolean admin_create_ban( gentity_t *ent,
+ char *netname,
+ char *guid,
+ char *ip,
+ int seconds,
+ char *reason )
+{
+ g_admin_ban_t *b = NULL;
+ qtime_t qt;
+ int t;
+ int i;
+
+ t = trap_RealTime( &qt );
+ b = BG_Alloc( sizeof( g_admin_ban_t ) );
+
+ if( !b )
+ return qfalse;
+
+ Q_strncpyz( b->name, netname, sizeof( b->name ) );
+ Q_strncpyz( b->guid, guid, sizeof( b->guid ) );
+ Q_strncpyz( b->ip, ip, sizeof( b->ip ) );
+
+ //strftime( b->made, sizeof( b->made ), "%m/%d/%y %H:%M:%S", lt );
+ Com_sprintf( b->made, sizeof( b->made ), "%02i/%02i/%02i %02i:%02i:%02i",
+ qt.tm_mon + 1, qt.tm_mday, qt.tm_year % 100,
+ qt.tm_hour, qt.tm_min, qt.tm_sec );
+
+ if( ent )
+ Q_strncpyz( b->banner, ent->client->pers.netname, sizeof( b->banner ) );
+ else
+ Q_strncpyz( b->banner, "console", sizeof( b->banner ) );
+ if( !seconds )
+ b->expires = 0;
+ else
+ b->expires = t + seconds;
+ if( !*reason )
+ Q_strncpyz( b->reason, "banned by admin", sizeof( b->reason ) );
+ else
+ Q_strncpyz( b->reason, reason, sizeof( b->reason ) );
+ for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
+ ;
+ if( i == MAX_ADMIN_BANS )
+ {
+ ADMP( "^3!ban: ^7too many bans\n" );
+ BG_Free( b );
+ return qfalse;
+ }
+ g_admin_bans[ i ] = b;
+ return qtrue;
+}
+//KK-OAX Copied create_ban to get Time Stuff Right (Didn't feel like writing code to parse it)
+static qboolean admin_create_warning( gentity_t *ent, char *netname, char *guid, char *ip, int seconds, char *warning )
+{
+ g_admin_warning_t *w = NULL;
+ qtime_t qt;
+ int t;
+ int i;
+
+ t = trap_RealTime( &qt );
+ w = BG_Alloc( sizeof( g_admin_warning_t ) );
+
+ if( !w )
+ return qfalse;
+
+ Q_strncpyz( w->name, netname, sizeof( w->name ) );
+ Q_strncpyz( w->guid, guid, sizeof( w->guid ) );
+ Q_strncpyz( w->ip, ip, sizeof( w->ip ) );
+
+ //strftime( b->made, sizeof( b->made ), "%m/%d/%y %H:%M:%S", lt );
+ Com_sprintf( w->made, sizeof( w->made ), "%02i/%02i/%02i %02i:%02i:%02i",
+ qt.tm_mon + 1, qt.tm_mday, qt.tm_year % 100,
+ qt.tm_hour, qt.tm_min, qt.tm_sec );
+
+ if( ent )
+ Q_strncpyz( w->warner, ent->client->pers.netname, sizeof( w->warner ) );
+ else
+ Q_strncpyz( w->warner, "console", sizeof( w->warner ) );
+ if( !seconds )
+ w->expires = 0;
+ else
+ w->expires = t + seconds;
+ if( !*warning )
+ Q_strncpyz( w->warning, "warned by admin", sizeof( w->warning ) );
+ else
+ Q_strncpyz( w->warning, warning, sizeof( w->warning ) );
+ for( i = 0; i < MAX_ADMIN_WARNINGS && g_admin_warnings[ i ]; i++ )
+ ;
+ if( i == MAX_ADMIN_WARNINGS )
+ {
+ ADMP( "^3!warn: ^7too many warnings\n" );
+ BG_Free( w );
+ return qfalse;
+ }
+ g_admin_warnings[ i ] = w;
+ return qtrue;
+}
+
+
+int G_admin_parse_time( const char *time )
+{
+ int seconds = 0, num = 0;
+ while( *time )
+ {
+ if( !isdigit( *time ) )
+ return -1;
+ while( isdigit( *time ) )
+ num = num * 10 + *time++ - '0';
+
+ if( !*time )
+ break;
+ switch( *time++ )
+ {
+ case 'w': num *= 7;
+ case 'd': num *= 24;
+ case 'h': num *= 60;
+ case 'm': num *= 60;
+ case 's': break;
+ default: return -1;
+ }
+ seconds += num;
+ num = 0;
+ }
+ if( num )
+ seconds += num;
+ return seconds;
+}
+
+qboolean G_admin_kick( gentity_t *ent, int skiparg )
+{
+ int pids[ MAX_CLIENTS ], found;
+ char name[ MAX_NAME_LENGTH ], *reason, err[ MAX_STRING_CHARS ];
+ int minargc;
+ gentity_t *vic;
+
+ minargc = 3 + skiparg;
+ if( G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
+ minargc = 2 + skiparg;
+
+ if( G_SayArgc() < minargc )
+ {
+ ADMP( "^3!kick: ^7usage: !kick [name] [reason]\n" );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, name, sizeof( name ) );
+ reason = G_SayConcatArgs( 2 + skiparg );
+ if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
+ {
+ G_MatchOnePlayer( pids, found, err, sizeof( err ) );
+ ADMP( va( "^3!kick: ^7%s\n", err ) );
+ return qfalse;
+ }
+ vic = &g_entities[ pids[ 0 ] ];
+ if( !admin_higher( ent, vic ) )
+ {
+ ADMP( "^3!kick: ^7sorry, but your intended victim has a higher admin"
+ " level than you\n" );
+ return qfalse;
+ }
+ if( vic->client->pers.localClient )
+ {
+ ADMP( "^3!kick: ^7disconnecting the host would end the game\n" );
+ return qfalse;
+ }
+ admin_create_ban( ent,
+ vic->client->pers.netname,
+ vic->client->pers.guid,
+ vic->client->pers.ip,
+ G_admin_parse_time( va( "1s%s", g_adminTempBan.string ) ),
+ ( *reason ) ? reason : "kicked by admin" );
+ if( g_admin.string[ 0 ] )
+ admin_writeconfig();
+
+ trap_SendServerCommand( pids[ 0 ],
+ va( "disconnect \"You have been kicked.\n%s^7\nreason:\n%s\"",
+ ( ent ) ? va( "admin:\n%s", ent->client->pers.netname ) : "",
+ ( *reason ) ? reason : "kicked by admin" ) );
+
+ trap_DropClient( pids[ 0 ], va( "has been kicked%s^7. reason: %s",
+ ( ent ) ? va( " by %s", ent->client->pers.netname ) : "",
+ ( *reason ) ? reason : "kicked by admin" ) );
+
+ return qtrue;
+}
+
+qboolean G_admin_ban( gentity_t *ent, int skiparg )
+{
+ int seconds;
+ char search[ MAX_NAME_LENGTH ];
+ char secs[ MAX_TOKEN_CHARS ];
+ char *reason;
+ int minargc;
+ char duration[ 32 ];
+ int logmatch = -1, logmatches = 0;
+ int i, j;
+ qboolean exactmatch = qfalse;
+ char n2[ MAX_NAME_LENGTH ];
+ char s2[ MAX_NAME_LENGTH ];
+ char guid_stub[ 9 ];
+
+ if( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
+ G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
+ {
+ minargc = 2 + skiparg;
+ }
+ else if( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) ||
+ G_admin_permission( ent, ADMF_UNACCOUNTABLE ) ||
+ g_adminMaxBan.integer )
+ {
+ minargc = 3 + skiparg;
+ }
+ else
+ {
+ minargc = 4 + skiparg;
+ }
+ if( G_SayArgc() < minargc )
+ {
+ ADMP( "^3!ban: ^7usage: !ban [name|slot|ip] [duration] [reason]\n" );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, search, sizeof( search ) );
+ G_SanitiseString( search, s2, sizeof( s2 ) );
+ G_SayArgv( 2 + skiparg, secs, sizeof( secs ) );
+
+ seconds = G_admin_parse_time( secs );
+ if( seconds <= 0 )
+ {
+ if( g_adminMaxBan.integer && !G_admin_permission( ent, ADMF_CAN_PERM_BAN) )
+ {
+ ADMP( va( "^3!ban: ^7using your admin level's maximum ban length of %s\n",
+ g_adminMaxBan.string ) );
+ seconds = G_admin_parse_time( g_adminMaxBan.string );
+ }
+ else if( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
+ {
+ seconds = 0;
+ }
+ else
+ {
+ ADMP( "^3!ban: ^7you may not issue permanent bans\n" );
+ return qfalse;
+ }
+ reason = G_SayConcatArgs( 2 + skiparg );
+ }
+ else
+ {
+ if( g_adminMaxBan.integer &&
+ !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
+ seconds > G_admin_parse_time( g_adminMaxBan.string ) )
+ {
+ ADMP( va( "^3!ban: ^7ban length limited to %s for your admin level\n",
+ g_adminMaxBan.string ) );
+ seconds = G_admin_parse_time( g_adminMaxBan.string );
+ }
+ reason = G_SayConcatArgs( 3 + skiparg );
+ }
+
+ for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
+ {
+ // skip players in the namelog who have already been banned
+ if( g_admin_namelog[ i ]->banned )
+ continue;
+
+ // skip disconnected players when banning on slot number
+ if( g_admin_namelog[ i ]->slot == -1 )
+ continue;
+
+ if( !Q_stricmp( va( "%d", g_admin_namelog[ i ]->slot ), search ) )
+ {
+ logmatches = 1;
+ logmatch = i;
+ exactmatch = qtrue;
+ break;
+ }
+ }
+
+ for( i = 0;
+ !exactmatch && i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ];
+ i++ )
+ {
+ // skip players in the namelog who have already been banned
+ if( g_admin_namelog[ i ]->banned )
+ continue;
+
+ if( !Q_stricmp( g_admin_namelog[ i ]->ip, search ) )
+ {
+ logmatches = 1;
+ logmatch = i;
+ exactmatch = qtrue;
+ break;
+ }
+ for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES &&
+ g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
+ {
+ G_SanitiseString( g_admin_namelog[ i ]->name[ j ], n2, sizeof( n2 ) );
+ if( strstr( n2, s2 ) )
+ {
+ if( logmatch != i )
+ logmatches++;
+ logmatch = i;
+ }
+ }
+ }
+
+ if( !logmatches )
+ {
+ ADMP( "^3!ban: ^7no player found by that name, IP, or slot number\n" );
+ return qfalse;
+ }
+ if( logmatches > 1 )
+ {
+ ADMBP_begin();
+ ADMBP( "^3!ban: ^7multiple recent clients match name, use IP or slot#:\n" );
+ for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
+ {
+ for( j = 0; j < 8; j++ )
+ guid_stub[ j ] = g_admin_namelog[ i ]->guid[ j + 24 ];
+ guid_stub[ j ] = '\0';
+ for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES &&
+ g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
+ {
+ G_SanitiseString( g_admin_namelog[ i ]->name[ j ], n2, sizeof( n2 ) );
+ if( strstr( n2, s2 ) )
+ {
+ if( g_admin_namelog[ i ]->slot > -1 )
+ ADMBP( "^3" );
+ ADMBP( va( "%-2s (*%s) %15s ^7'%s^7'\n",
+ ( g_admin_namelog[ i ]->slot > -1 ) ?
+ va( "%d", g_admin_namelog[ i ]->slot ) : "-",
+ guid_stub,
+ g_admin_namelog[ i ]->ip,
+ g_admin_namelog[ i ]->name[ j ] ) );
+ }
+ }
+ }
+ ADMBP_end();
+ return qfalse;
+ }
+
+ if( ent && !admin_higher_guid( ent->client->pers.guid,
+ g_admin_namelog[ logmatch ]->guid ) )
+ {
+
+ ADMP( "^3!ban: ^7sorry, but your intended victim has a higher admin"
+ " level than you\n" );
+ return qfalse;
+ }
+ if( !strcmp( g_admin_namelog[ logmatch ]->ip, "localhost" ) )
+ {
+ ADMP( "^3!ban: ^7disconnecting the host would end the game\n" );
+ return qfalse;
+ }
+
+ G_admin_duration( ( seconds ) ? seconds : -1,
+ duration, sizeof( duration ) );
+
+ admin_create_ban( ent,
+ g_admin_namelog[ logmatch ]->name[ 0 ],
+ g_admin_namelog[ logmatch ]->guid,
+ g_admin_namelog[ logmatch ]->ip,
+ seconds, reason );
+
+ g_admin_namelog[ logmatch ]->banned = qtrue;
+
+ if( !g_admin.string[ 0 ] )
+ ADMP( "^3!ban: ^7WARNING g_admin not set, not saving ban to a file\n" );
+ else
+ if(strlen(g_admin_namelog[ logmatch ]->guid)==0 || strlen(g_admin_namelog[ logmatch ]->ip) )
+ ADMP( "^3!ban: ^7WARNING bot or without GUID or IP cannot write to ban file\n");
+ else
+ admin_writeconfig();
+
+ if( g_admin_namelog[ logmatch ]->slot == -1 )
+ {
+ // client is already disconnected so stop here
+ AP( va( "print \"^3!ban:^7 %s^7 has been banned by %s^7, "
+ "duration: %s, reason: %s\n\"",
+ g_admin_namelog[ logmatch ]->name[ 0 ],
+ ( ent ) ? ent->client->pers.netname : "console",
+ duration,
+ ( *reason ) ? reason : "banned by admin" ) );
+ return qtrue;
+ }
+
+ trap_SendServerCommand( g_admin_namelog[ logmatch ]->slot,
+ va( "disconnect \"You have been banned.\n"
+ "admin:\n%s^7\nduration:\n%s\nreason:\n%s\"",
+ ( ent ) ? ent->client->pers.netname : "console",
+ duration,
+ ( *reason ) ? reason : "banned by admin" ) );
+
+ trap_DropClient( g_admin_namelog[ logmatch ]->slot,
+ va( "has been banned by %s^7, duration: %s, reason: %s",
+ ( ent ) ? ent->client->pers.netname : "console",
+ duration,
+ ( *reason ) ? reason : "banned by admin" ) );
+ return qtrue;
+}
+
+qboolean G_admin_unban( gentity_t *ent, int skiparg )
+{
+ int bnum;
+ int time = trap_RealTime( NULL );
+ char bs[ 5 ];
+
+ if( G_SayArgc() < 2 + skiparg )
+ {
+ ADMP( "^3!unban: ^7usage: !unban [ban#]\n" );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, bs, sizeof( bs ) );
+ bnum = atoi( bs );
+ if( bnum < 1 || bnum > MAX_ADMIN_BANS || !g_admin_bans[ bnum - 1 ] )
+ {
+ ADMP( "^3!unban: ^7invalid ban#\n" );
+ return qfalse;
+ }
+ if( g_admin_bans[ bnum - 1 ]->expires == 0 &&
+ !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
+ {
+ ADMP( "^3!unban: ^7you cannot remove permanent bans\n" );
+ return qfalse;
+ }
+ if( g_adminMaxBan.integer &&
+ !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
+ g_admin_bans[ bnum - 1 ]->expires - time > G_admin_parse_time( g_adminMaxBan.string ) )
+ {
+ ADMP( va( "^3!unban: ^7your admin level cannot remove bans longer than %s\n",
+ g_adminMaxBan.string ) );
+ return qfalse;
+ }
+ g_admin_bans[ bnum - 1 ]->expires = time;
+ AP( va( "print \"^3!unban: ^7ban #%d for %s^7 has been removed by %s\n\"",
+ bnum,
+ g_admin_bans[ bnum - 1 ]->name,
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ if( g_admin.string[ 0 ] )
+ admin_writeconfig();
+ return qtrue;
+}
+
+qboolean G_admin_adjustban( gentity_t *ent, int skiparg )
+{
+ int bnum;
+ int length;
+ int expires;
+ int time = trap_RealTime( NULL );
+ char duration[ 32 ] = {""};
+ char *reason;
+ char bs[ 5 ];
+ char secs[ MAX_TOKEN_CHARS ];
+ char mode = '\0';
+ g_admin_ban_t *ban;
+
+ if( G_SayArgc() < 3 + skiparg )
+ {
+ ADMP( "^3!adjustban: ^7usage: !adjustban [ban#] [duration] [reason]\n" );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, bs, sizeof( bs ) );
+ bnum = atoi( bs );
+ if( bnum < 1 || bnum > MAX_ADMIN_BANS || !g_admin_bans[ bnum - 1 ] )
+ {
+ ADMP( "^3!adjustban: ^7invalid ban#\n" );
+ return qfalse;
+ }
+ ban = g_admin_bans[ bnum - 1 ];
+ if( ban->expires == 0 && !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
+ {
+ ADMP( "^3!adjustban: ^7you cannot modify permanent bans\n" );
+ return qfalse;
+ }
+ if( g_adminMaxBan.integer &&
+ !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
+ ban->expires - time > G_admin_parse_time( g_adminMaxBan.string ) )
+ {
+ ADMP( va( "^3!adjustban: ^7your admin level cannot modify bans longer than %s\n",
+ g_adminMaxBan.string ) );
+ return qfalse;
+ }
+ G_SayArgv( 2 + skiparg, secs, sizeof( secs ) );
+ if( secs[ 0 ] == '+' || secs[ 0 ] == '-' )
+ mode = secs[ 0 ];
+ length = G_admin_parse_time( &secs[ mode ? 1 : 0 ] );
+ if( length < 0 )
+ skiparg--;
+ else
+ {
+ if( length )
+ {
+ if( ban->expires == 0 && mode )
+ {
+ ADMP( "^3!adjustban: ^7new duration must be explicit\n" );
+ return qfalse;
+ }
+ if( mode == '+' )
+ expires = ban->expires + length;
+ else if( mode == '-' )
+ expires = ban->expires - length;
+ else
+ expires = time + length;
+ if( expires <= time )
+ {
+ ADMP( "^3!adjustban: ^7ban duration must be positive\n" );
+ return qfalse;
+ }
+ if( g_adminMaxBan.integer &&
+ !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
+ expires - time > G_admin_parse_time( g_adminMaxBan.string ) )
+ {
+ ADMP( va( "^3!adjustban: ^7ban length is limited to %s for your admin level\n",
+ g_adminMaxBan.string ) );
+ length = G_admin_parse_time( g_adminMaxBan.string );
+ expires = time + length;
+ }
+ }
+ else if( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
+ expires = 0;
+ else
+ {
+ ADMP( "^3!adjustban: ^7ban duration must be positive\n" );
+ return qfalse;
+ }
+
+ ban->expires = expires;
+ G_admin_duration( ( expires ) ? expires - time : -1, duration,
+ sizeof( duration ) );
+ }
+ reason = G_SayConcatArgs( 3 + skiparg );
+ if( *reason )
+ Q_strncpyz( ban->reason, reason, sizeof( ban->reason ) );
+ AP( va( "print \"^3!adjustban: ^7ban #%d for %s^7 has been updated by %s^7 "
+ "%s%s%s%s%s\n\"",
+ bnum,
+ ban->name,
+ ( ent ) ? ent->client->pers.netname : "console",
+ ( length >= 0 ) ? "duration: " : "",
+ duration,
+ ( length >= 0 && *reason ) ? ", " : "",
+ ( *reason ) ? "reason: " : "",
+ reason ) );
+ if( ent )
+ Q_strncpyz( ban->banner, ent->client->pers.netname, sizeof( ban->banner ) );
+ if( g_admin.string[ 0 ] )
+ admin_writeconfig();
+ return qtrue;
+}
+
+qboolean G_admin_putteam( gentity_t *ent, int skiparg )
+{
+ int pids[ MAX_CLIENTS ], found;
+ //KK-OAPub Changed Team Name Length so "Spectator" doesn't crash Game
+ char name[ MAX_NAME_LENGTH ], team[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
+ gentity_t *vic;
+ team_t teamnum = TEAM_NONE;
+
+ G_SayArgv( 1 + skiparg, name, sizeof( name ) );
+ G_SayArgv( 2 + skiparg, team, sizeof( team ) );
+ if( G_SayArgc() < 3 + skiparg )
+ {
+ ADMP( "^3!putteam: ^7usage: !putteam [name] [h|a|s]\n" );
+ return qfalse;
+ }
+
+ if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
+ {
+ G_MatchOnePlayer( pids, found, err, sizeof( err ) );
+ ADMP( va( "^3!putteam: ^7%s\n", err ) );
+ return qfalse;
+ }
+ if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
+ {
+ ADMP( "^3!putteam: ^7sorry, but your intended victim has a higher "
+ " admin level than you\n" );
+ return qfalse;
+ }
+ vic = &g_entities[ pids[ 0 ] ];
+ teamnum = G_TeamFromString( team );
+ if( teamnum == TEAM_NUM_TEAMS )
+ {
+ ADMP( va( "^3!putteam: ^7unknown team %s\n", team ) );
+ return qfalse;
+ }
+ if( vic->client->sess.sessionTeam == teamnum )
+ return qfalse;
+
+ SetTeam( vic, team );
+
+ AP( va( "print \"^3!putteam: ^7%s^7 put %s^7 on to the %s team\n\"",
+ ( ent ) ? ent->client->pers.netname : "console",
+ vic->client->pers.netname, BG_TeamName( teamnum ) ) );
+ return qtrue;
+}
+
+//KK-Fixed!!!!
+//KK-Removed Layouts from The command
+qboolean G_admin_map( gentity_t *ent, int skiparg )
+{
+ char map[ MAX_QPATH ];
+
+ if( G_SayArgc( ) < 2 + skiparg )
+ {
+ ADMP( "^3!map: ^7usage: !map [map] (layout)\n" );
+ return qfalse;
+ }
+
+ G_SayArgv( skiparg + 1, map, sizeof( map ) );
+
+ if( !trap_FS_FOpenFile( va( "maps/%s.bsp", map ), NULL, FS_READ ) )
+ {
+ ADMP( va( "^3!map: ^7invalid map name '%s'\n", map ) );
+ return qfalse;
+ }
+
+ trap_SendConsoleCommand( EXEC_APPEND, va( "map %s", map ) );
+ level.restarted = qtrue;
+ AP( va( "print \"^3!map: ^7map '%s' started by %s\n\"", map,
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ return qtrue;
+}
+
+qboolean G_admin_mute( gentity_t *ent, int skiparg )
+{
+ int pids[ MAX_CLIENTS ], found;
+ char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
+ char command[ MAX_ADMIN_CMD_LEN ], *cmd;
+ gentity_t *vic;
+
+ G_SayArgv( skiparg, command, sizeof( command ) );
+ cmd = command;
+ if( cmd && *cmd == '!' )
+ cmd++;
+ if( G_SayArgc() < 2 + skiparg )
+ {
+ ADMP( va( "^3!%s: ^7usage: !%s [name|slot#]\n", cmd, cmd ) );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, name, sizeof( name ) );
+ if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
+ {
+ G_MatchOnePlayer( pids, found, err, sizeof( err ) );
+ ADMP( va( "^3!%s: ^7%s\n", cmd, err ) );
+ return qfalse;
+ }
+ if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
+ {
+ ADMP( va( "^3!%s: ^7sorry, but your intended victim has a higher admin"
+ " level than you\n", cmd ) );
+ return qfalse;
+ }
+ vic = &g_entities[ pids[ 0 ] ];
+ if( vic->client->pers.muted == qtrue )
+ {
+ if( !Q_stricmp( cmd, "mute" ) )
+ {
+ ADMP( "^3!mute: ^7player is already muted\n" );
+ return qtrue;
+ }
+ vic->client->pers.muted = qfalse;
+ CPx( pids[ 0 ], "cp \"^1You have been unmuted\"" );
+ AP( va( "print \"^3!unmute: ^7%s^7 has been unmuted by %s\n\"",
+ vic->client->pers.netname,
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ }
+ else
+ {
+ if( !Q_stricmp( cmd, "unmute" ) )
+ {
+ ADMP( "^3!unmute: ^7player is not currently muted\n" );
+ return qtrue;
+ }
+ vic->client->pers.muted = qtrue;
+ CPx( pids[ 0 ], "cp \"^1You've been muted\"" );
+ AP( va( "print \"^3!mute: ^7%s^7 has been muted by ^7%s\n\"",
+ vic->client->pers.netname,
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ }
+ return qtrue;
+}
+
+
+
+qboolean G_admin_listadmins( gentity_t *ent, int skiparg )
+{
+ int i, found = 0;
+ char search[ MAX_NAME_LENGTH ] = {""};
+ char s[ MAX_NAME_LENGTH ] = {""};
+ int start = 0;
+ qboolean numeric = qtrue;
+ int drawn = 0;
+
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ {
+ if( g_admin_admins[ i ]->level == 0 )
+ continue;
+ found++;
+ }
+ if( !found )
+ {
+ ADMP( "^3!listadmins: ^7no admins defined\n" );
+ return qfalse;
+ }
+
+ if( G_SayArgc() == 2 + skiparg )
+ {
+ G_SayArgv( 1 + skiparg, s, sizeof( s ) );
+ for( i = 0; i < sizeof( s ) && s[ i ]; i++ )
+ {
+ if( isdigit( s[ i ] ) )
+ continue;
+ numeric = qfalse;
+ }
+ if( numeric )
+ {
+ start = atoi( s );
+ if( start > 0 )
+ start -= 1;
+ else if( start < 0 )
+ start = found + start;
+ }
+ else
+ G_SanitiseString( s, search, sizeof( search ) );
+ }
+
+ if( start >= found || start < 0 )
+ start = 0;
+
+ if( start >= found )
+ {
+ ADMP( va( "^3!listadmins: ^7listing %d admins\n", found ) );
+ return qfalse;
+ }
+
+ drawn = admin_listadmins( ent, start, search );
+
+ if( search[ 0 ] )
+ {
+ ADMP( va( "^3!listadmins:^7 found %d admins matching '%s^7'\n",
+ drawn, search ) );
+ }
+ else
+ {
+ ADMBP_begin();
+ ADMBP( va( "^3!listadmins:^7 showing admin %d - %d of %d. ",
+ ( found ) ? ( start + 1 ) : 0,
+ ( ( start + MAX_ADMIN_LISTITEMS ) > found ) ?
+ found : ( start + MAX_ADMIN_LISTITEMS ),
+ found ) );
+ if( ( start + MAX_ADMIN_LISTITEMS ) < found )
+ {
+ ADMBP( va( "run '!listadmins %d' to see more",
+ ( start + MAX_ADMIN_LISTITEMS + 1 ) ) );
+ }
+ ADMBP( "\n" );
+ ADMBP_end();
+ }
+ return qtrue;
+}
+
+
+qboolean G_admin_listplayers( gentity_t *ent, int skiparg )
+{
+ int i, j;
+ gclient_t *p;
+ char c[ 3 ], t[ 2 ]; // color and team letter
+ char n[ MAX_NAME_LENGTH ] = {""};
+ char n2[ MAX_NAME_LENGTH ] = {""};
+ char n3[ MAX_NAME_LENGTH ] = {""};
+ char lname[ MAX_NAME_LENGTH ];
+ char guid_stub[ 9 ];
+ char muted[ 2 ];
+ int l;
+
+ ADMBP_begin();
+ ADMBP( va( "^3!listplayers: ^7%d players connected:\n",
+ level.numConnectedClients ) );
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ p = &level.clients[ i ];
+ Q_strncpyz( t, "S", sizeof( t ) );
+ Q_strncpyz( c, S_COLOR_YELLOW, sizeof( c ) );
+ if( p->sess.sessionTeam == TEAM_BLUE )
+ {
+ Q_strncpyz( t, "B", sizeof( t ) );
+ Q_strncpyz( c, S_COLOR_BLUE, sizeof( c ) );
+ }
+ else if( p->sess.sessionTeam == TEAM_RED )
+ {
+ Q_strncpyz( t, "R", sizeof( t ) );
+ Q_strncpyz( c, S_COLOR_RED, sizeof( c ) );
+ }
+ else if( p->sess.sessionTeam == TEAM_FREE )
+ {
+ Q_strncpyz( t, "F", sizeof( t ) );
+ Q_strncpyz( c, S_COLOR_GREEN, sizeof( c ) );
+ }
+ else if( p->sess.sessionTeam == TEAM_NONE )
+ {
+ Q_strncpyz( t, "S", sizeof( t ) );
+ Q_strncpyz( c, S_COLOR_WHITE, sizeof( c ) );
+ }
+ if( p->pers.connected == CON_CONNECTING )
+ {
+ Q_strncpyz( t, "C", sizeof( t ) );
+ Q_strncpyz( c, S_COLOR_CYAN, sizeof( c ) );
+ }
+ else if( p->pers.connected != CON_CONNECTED )
+ {
+ continue;
+ }
+
+ for( j = 0; j < 8; j++ )
+ guid_stub[ j ] = p->pers.guid[ j + 24 ];
+ guid_stub[ j ] = '\0';
+
+ muted[ 0 ] = '\0';
+ if( p->pers.muted )
+ {
+ Q_strncpyz( muted, "M", sizeof( muted ) );
+ }
+ //Put DisOriented Junk Here!!!
+
+ l = 0;
+ G_SanitiseString( p->pers.netname, n2, sizeof( n2 ) );
+ n[ 0 ] = '\0';
+ for( j = 0; j < MAX_ADMIN_ADMINS && g_admin_admins[ j ]; j++ )
+ {
+ if( !Q_stricmp( g_admin_admins[ j ]->guid, p->pers.guid ) )
+ {
+ // don't gather aka or level info if the admin is incognito
+ if( ent && G_admin_permission( &g_entities[ i ], ADMF_INCOGNITO ) )
+ {
+ break;
+ }
+ l = g_admin_admins[ j ]->level;
+ G_SanitiseString( g_admin_admins[ j ]->name, n3, sizeof( n3 ) );
+ if( Q_stricmp( n2, n3 ) )
+ {
+ Q_strncpyz( n, g_admin_admins[ j ]->name, sizeof( n ) );
+ }
+ break;
+ }
+ }
+ lname[ 0 ] = '\0';
+ for( j = 0; j < MAX_ADMIN_LEVELS && g_admin_levels[ j ]; j++ )
+ {
+ if( g_admin_levels[ j ]->level == l )
+ {
+ int k, colorlen;
+
+ for( colorlen = k = 0; g_admin_levels[ j ]->name[ k ]; k++ )
+ if( Q_IsColorString( &g_admin_levels[ j ]->name[ k ] ) )
+ colorlen += 2;
+ Com_sprintf( lname, sizeof( lname ), "%*s",
+ admin_level_maxname + colorlen,
+ g_admin_levels[ j ]->name );
+ break;
+ }
+ }
+
+ ADMBP( va( "%2i %s%s^7 %-2i %s^7 (*%s) ^1%1s^7 %s^7 %s%s^7%s\n",
+ i,
+ c,
+ t,
+ l,
+ lname,
+ guid_stub,
+ muted,
+ p->pers.netname,
+ ( *n ) ? "(a.k.a. " : "",
+ n,
+ ( *n ) ? ")" : "" ) );
+ }
+ ADMBP_end();
+ return qtrue;
+}
+
+qboolean G_admin_showbans( gentity_t *ent, int skiparg )
+{
+ int i, found = 0;
+ int max = -1, count;
+ int t;
+ char duration[ 32 ];
+ int max_name = 1, max_banner = 1, colorlen;
+ int len;
+ int secs;
+ int start = 0;
+ char filter[ MAX_NAME_LENGTH ] = {""};
+ char date[ 11 ];
+ char *made;
+ int j, k;
+ char n1[ MAX_NAME_LENGTH * 2 ] = {""};
+ char n2[ MAX_NAME_LENGTH * 2 ] = {""};
+ qboolean numeric = qtrue;
+ char *ip_match = NULL;
+ int ip_match_len = 0;
+ char name_match[ MAX_NAME_LENGTH ] = {""};
+
+ t = trap_RealTime( NULL );
+
+ for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
+ {
+ if( g_admin_bans[ i ]->expires != 0 &&
+ ( g_admin_bans[ i ]->expires - t ) < 1 )
+ {
+ continue;
+ }
+ found++;
+ max = i;
+ }
+
+ if( max < 0 )
+ {
+ ADMP( "^3!showbans: ^7no bans to display\n" );
+ return qfalse;
+ }
+
+ if( G_SayArgc() >= 2 + skiparg )
+ {
+ G_SayArgv( 1 + skiparg, filter, sizeof( filter ) );
+ if( G_SayArgc() >= 3 + skiparg )
+ {
+ start = atoi( filter );
+ G_SayArgv( 2 + skiparg, filter, sizeof( filter ) );
+ }
+ for( i = 0; i < sizeof( filter ) && filter[ i ] ; i++ )
+ {
+ if( !isdigit( filter[ i ] ) &&
+ filter[ i ] != '.' && filter[ i ] != '-' )
+ {
+ numeric = qfalse;
+ break;
+ }
+ }
+ if( !numeric )
+ {
+ G_SanitiseString( filter, name_match, sizeof( name_match ) );
+ }
+ else if( strchr( filter, '.' ) )
+ {
+ ip_match = filter;
+ ip_match_len = strlen(ip_match);
+ }
+ else
+ {
+ start = atoi( filter );
+ filter[ 0 ] = '\0';
+ }
+ // showbans 1 means start with ban 0
+ if( start > 0 )
+ start--;
+ else if( start < 0 )
+ {
+ for( i = max, count = 0; i >= 0 && count < -start; i-- )
+ if( g_admin_bans[ i ]->expires == 0 ||
+ ( g_admin_bans[ i ]->expires - t ) > 0 )
+ count++;
+ start = i + 1;
+ }
+ }
+
+ if( start < 0 )
+ start = 0;
+
+ if( start > max )
+ {
+ ADMP( va( "^3!showbans: ^7%d is the last valid ban\n", max + 1 ) );
+ return qfalse;
+ }
+
+ for( i = start, count = 0; i <= max && count < MAX_ADMIN_SHOWBANS; i++ )
+ {
+ if( g_admin_bans[ i ]->expires != 0 &&
+ ( g_admin_bans[ i ]->expires - t ) < 1 )
+ continue;
+
+ if( name_match[ 0 ] )
+ {
+ G_SanitiseString( g_admin_bans[ i ]->name, n1, sizeof( n1 ) );
+ if( !strstr( n1, name_match) )
+ continue;
+ }
+ if( ip_match &&
+ Q_strncmp( ip_match, g_admin_bans[ i ]->ip, ip_match_len ) )
+ continue;
+
+ count++;
+
+ len = Q_PrintStrlen( g_admin_bans[ i ]->name );
+ if( len > max_name )
+ max_name = len;
+ len = Q_PrintStrlen( g_admin_bans[ i ]->banner );
+ if( len > max_banner )
+ max_banner = len;
+ }
+
+ ADMBP_begin();
+ for( i = start, count = 0; i <= max && count < MAX_ADMIN_SHOWBANS; i++ )
+ {
+ if( g_admin_bans[ i ]->expires != 0 &&
+ ( g_admin_bans[ i ]->expires - t ) < 1 )
+ continue;
+
+ if( name_match[ 0 ] )
+ {
+ G_SanitiseString( g_admin_bans[ i ]->name, n1, sizeof( n1 ) );
+ if( !strstr( n1, name_match) )
+ continue;
+ }
+ if( ip_match &&
+ Q_strncmp( ip_match, g_admin_bans[ i ]->ip, ip_match_len ) )
+ continue;
+
+ count++;
+
+ // only print out the the date part of made
+ date[ 0 ] = '\0';
+ made = g_admin_bans[ i ]->made;
+ for( j = 0; made && *made; j++ )
+ {
+ if( ( j + 1 ) >= sizeof( date ) )
+ break;
+ if( *made == ' ' )
+ break;
+ date[ j ] = *made;
+ date[ j + 1 ] = '\0';
+ made++;
+ }
+
+ secs = ( g_admin_bans[ i ]->expires - t );
+ G_admin_duration( secs, duration, sizeof( duration ) );
+
+ for( colorlen = k = 0; g_admin_bans[ i ]->name[ k ]; k++ )
+ if( Q_IsColorString( &g_admin_bans[ i ]->name[ k ] ) )
+ colorlen += 2;
+ Com_sprintf( n1, sizeof( n1 ), "%*s", max_name + colorlen,
+ g_admin_bans[ i ]->name );
+
+ for( colorlen = k = 0; g_admin_bans[ i ]->banner[ k ]; k++ )
+ if( Q_IsColorString( &g_admin_bans[ i ]->banner[ k ] ) )
+ colorlen += 2;
+ Com_sprintf( n2, sizeof( n2 ), "%*s", max_banner + colorlen,
+ g_admin_bans[ i ]->banner );
+
+ ADMBP( va( "%4i %s^7 %-15s %-8s %s^7 %-10s\n \\__ %s\n",
+ ( i + 1 ),
+ n1,
+ g_admin_bans[ i ]->ip,
+ date,
+ n2,
+ duration,
+ g_admin_bans[ i ]->reason ) );
+ }
+
+ if( name_match[ 0 ] || ip_match )
+ {
+ ADMBP( va( "^3!showbans:^7 found %d matching bans by %s. ",
+ count,
+ ( ip_match ) ? "IP" : "name" ) );
+ }
+ else
+ {
+ ADMBP( va( "^3!showbans:^7 showing bans %d - %d of %d (%d total).",
+ ( found ) ? ( start + 1 ) : 0,
+ i,
+ max + 1,
+ found ) );
+ }
+
+ if( i <= max )
+ ADMBP( va( " run !showbans %d%s%s to see more",
+ i + 1,
+ ( filter[ 0 ] ) ? " " : "",
+ ( filter[ 0 ] ) ? filter : "" ) );
+ ADMBP( "\n" );
+ ADMBP_end();
+ return qtrue;
+}
+
+qboolean G_admin_help( gentity_t *ent, int skiparg )
+{
+ int i;
+
+ if( G_SayArgc() < 2 + skiparg )
+ {
+ int j = 0;
+ int count = 0;
+
+ ADMBP_begin();
+ for( i = 0; i < adminNumCmds; i++ )
+ {
+ if( G_admin_permission( ent, g_admin_cmds[ i ].flag[ 0 ] ) )
+ {
+ ADMBP( va( "^3!%-12s", g_admin_cmds[ i ].keyword ) );
+ j++;
+ count++;
+ }
+ // show 6 commands per line
+ if( j == 6 )
+ {
+ ADMBP( "\n" );
+ j = 0;
+ }
+ }
+ for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
+ {
+ if( ! admin_command_permission( ent, g_admin_commands[ i ]->command ) )
+ continue;
+ ADMBP( va( "^3!%-12s", g_admin_commands[ i ]->command ) );
+ j++;
+ count++;
+ // show 6 commands per line
+ if( j == 6 )
+ {
+ ADMBP( "\n" );
+ j = 0;
+ }
+ }
+ if( count )
+ ADMBP( "\n" );
+ ADMBP( va( "^3!help: ^7%i available commands\n", count ) );
+ ADMBP( "run !help [^3command^7] for help with a specific command.\n" );
+ ADMBP_end();
+
+ return qtrue;
+ }
+ else
+ {
+ //!help param
+ char param[ MAX_ADMIN_CMD_LEN ];
+ char *cmd;
+
+ G_SayArgv( 1 + skiparg, param, sizeof( param ) );
+ cmd = ( param[0] == '!' ) ? ¶m[1] : ¶m[0];
+ ADMBP_begin();
+ for( i = 0; i < adminNumCmds; i++ )
+ {
+ if( !Q_stricmp( cmd, g_admin_cmds[ i ].keyword ) )
+ {
+ if( !G_admin_permission( ent, g_admin_cmds[ i ].flag[ 0 ] ) )
+ {
+ ADMBP( va( "^3!help: ^7you do not have permission to use '%s'\n",
+ g_admin_cmds[ i ].keyword ) );
+ ADMBP_end();
+ return qfalse;
+ }
+ ADMBP( va( "^3!help: ^7help for '!%s':\n",
+ g_admin_cmds[ i ].keyword ) );
+ ADMBP( va( " ^3Function: ^7%s\n", g_admin_cmds[ i ].function ) );
+ ADMBP( va( " ^3Syntax: ^7!%s %s\n", g_admin_cmds[ i ].keyword,
+ g_admin_cmds[ i ].syntax ) );
+ ADMBP( va( " ^3Flag: ^7'%c'\n", g_admin_cmds[ i ].flag[ 0 ] ) );
+ ADMBP_end();
+ return qtrue;
+ }
+ }
+ for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
+ {
+ if( !Q_stricmp( cmd, g_admin_commands[ i ]->command ) )
+ {
+ if( !admin_command_permission( ent, g_admin_commands[ i ]->command ) )
+ {
+ ADMBP( va( "^3!help: ^7you do not have permission to use '%s'\n",
+ g_admin_commands[ i ]->command ) );
+ ADMBP_end();
+ return qfalse;
+ }
+ ADMBP( va( "^3!help: ^7help for '%s':\n",
+ g_admin_commands[ i ]->command ) );
+ ADMBP( va( " ^3Description: ^7%s\n", g_admin_commands[ i ]->desc ) );
+ ADMBP( va( " ^3Syntax: ^7!%s\n", g_admin_commands[ i ]->command ) );
+ ADMBP_end();
+ return qtrue;
+ }
+ }
+ ADMBP( va( "^3!help: ^7no help found for '%s'\n", cmd ) );
+ ADMBP_end();
+ return qfalse;
+ }
+}
+
+qboolean G_admin_admintest( gentity_t *ent, int skiparg )
+{
+ int i, l = 0;
+ qboolean found = qfalse;
+ qboolean lname = qfalse;
+
+ if( !ent )
+ {
+ ADMP( "^3!admintest: ^7you are on the console.\n" );
+ return qtrue;
+ }
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ {
+ if( !Q_stricmp( g_admin_admins[ i ]->guid, ent->client->pers.guid ) )
+ {
+ found = qtrue;
+ break;
+ }
+ }
+
+ if( found )
+ {
+ l = g_admin_admins[ i ]->level;
+ for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
+ {
+ if( g_admin_levels[ i ]->level != l )
+ continue;
+ if( *g_admin_levels[ i ]->name )
+ {
+ lname = qtrue;
+ break;
+ }
+ }
+ }
+ AP( va( "print \"^3!admintest: ^7%s^7 is a level %d admin %s%s^7%s\n\"",
+ ent->client->pers.netname,
+ l,
+ ( lname ) ? "(" : "",
+ ( lname ) ? g_admin_levels[ i ]->name : "",
+ ( lname ) ? ")" : "" ) );
+ return qtrue;
+}
+
+qboolean G_admin_allready( gentity_t *ent, int skiparg )
+{
+ int i = 0;
+ gclient_t *cl;
+
+ if( !level.intermissiontime )
+ {
+ ADMP( "^3!allready: ^7this command is only valid during intermission\n" );
+ return qfalse;
+ }
+
+ for( i = 0; i < g_maxclients.integer; i++ )
+ {
+ cl = level.clients + i;
+ if( cl->pers.connected != CON_CONNECTED )
+ continue;
+
+ if( cl->sess.sessionTeam == TEAM_NONE )
+ continue;
+
+ cl->readyToExit = 1;
+ }
+ AP( va( "print \"^3!allready:^7 %s^7 says everyone is READY now\n\"",
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ return qtrue;
+}
+
+qboolean G_admin_cancelvote( gentity_t *ent, int skiparg )
+{
+
+ if(!level.voteTime && !level.teamVoteTime[ 0 ] && !level.teamVoteTime[ 1 ] )
+ {
+ ADMP( "^3!cancelvote: ^7no vote in progress\n" );
+ return qfalse;
+ }
+ level.voteNo = level.numConnectedClients;
+ level.voteYes = 0;
+ CheckVote( );
+ level.teamVoteNo[ 0 ] = level.numConnectedClients;
+ level.teamVoteYes[ 0 ] = 0;
+ CheckTeamVote( TEAM_RED );
+ level.teamVoteNo[ 1 ] = level.numConnectedClients;
+ level.teamVoteYes[ 1 ] = 0;
+ CheckTeamVote( TEAM_BLUE );
+ AP( va( "print \"^3!cancelvote: ^7%s^7 decided that everyone voted No\n\"",
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ return qtrue;
+}
+
+qboolean G_admin_passvote( gentity_t *ent, int skiparg )
+{
+ if(!level.voteTime && !level.teamVoteTime[ 0 ] && !level.teamVoteTime[ 1 ] )
+ {
+ ADMP( "^3!passvote: ^7no vote in progress\n" );
+ return qfalse;
+ }
+ level.voteYes = level.numConnectedClients;
+ level.voteNo = 0;
+ CheckVote( );
+ level.teamVoteYes[ 0 ] = level.numConnectedClients;
+ level.teamVoteNo[ 0 ] = 0;
+ CheckTeamVote( TEAM_RED );
+ level.teamVoteYes[ 1 ] = level.numConnectedClients;
+ level.teamVoteNo[ 1 ] = 0;
+ CheckTeamVote( TEAM_BLUE );
+ AP( va( "print \"^3!passvote: ^7%s^7 decided that everyone voted Yes\n\"",
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ return qtrue;
+}
+
+qboolean G_admin_spec999( gentity_t *ent, int skiparg )
+{
+ int i;
+ gentity_t *vic;
+
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ vic = &g_entities[ i ];
+ if( !vic->client )
+ continue;
+ if( vic->client->pers.connected != CON_CONNECTED )
+ continue;
+ if( vic->client->sess.sessionTeam == TEAM_NONE )
+ continue;
+ if( vic->client->ps.ping == 999 )
+ {
+ SetTeam( vic, "spectator" );
+ AP( va( "print \"^3!spec999: ^7%s^7 moved ^7%s^7 to spectators\n\"",
+ ( ent ) ? ent->client->pers.netname : "console",
+ vic->client->pers.netname ) );
+ }
+ }
+ return qtrue;
+}
+
+qboolean G_admin_rename( gentity_t *ent, int skiparg )
+{
+ int pids[ MAX_CLIENTS ], found;
+ char name[ MAX_NAME_LENGTH ];
+ char newname[ MAX_NAME_LENGTH ];
+ char oldname[ MAX_NAME_LENGTH ];
+ char err[ MAX_STRING_CHARS ];
+ char userinfo[ MAX_INFO_STRING ];
+ char *s;
+ gentity_t *victim = NULL;
+
+ if( G_SayArgc() < 3 + skiparg )
+ {
+ ADMP( "^3!rename: ^7usage: !rename [name] [newname]\n" );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, name, sizeof( name ) );
+ s = G_SayConcatArgs( 2 + skiparg );
+ Q_strncpyz( newname, s, sizeof( newname ) );
+ if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
+ {
+ G_MatchOnePlayer( pids, found, err, sizeof( err ) );
+ ADMP( va( "^3!rename: ^7%s\n", err ) );
+ return qfalse;
+ }
+ victim = &g_entities[ pids[ 0 ] ];
+ if( !admin_higher( ent, victim ) )
+ {
+ ADMP( "^3!rename: ^7sorry, but your intended victim has a higher admin"
+ " level than you\n" );
+ return qfalse;
+ }
+ if( !G_admin_name_check( victim, newname, err, sizeof( err ) ) )
+ {
+ ADMP( va( "^3!rename: ^7%s\n", err ) );
+ return qfalse;
+ }
+
+ //KK-OAX Since NameChanges are not going to be implemented just yet...let's ignore this.
+ level.clients[ pids[ 0 ] ].pers.nameChanges--;
+ level.clients[ pids[ 0 ] ].pers.nameChangeTime = 0;
+
+ trap_GetUserinfo( pids[ 0 ], userinfo, sizeof( userinfo ) );
+ s = Info_ValueForKey( userinfo, "name" );
+ Q_strncpyz( oldname, s, sizeof( oldname ) );
+ Info_SetValueForKey( userinfo, "name", newname );
+ trap_SetUserinfo( pids[ 0 ], userinfo );
+ ClientUserinfoChanged( pids[ 0 ] );
+ AP( va( "print \"^3!rename: ^7%s^7 has been renamed to %s^7 by %s\n\"",
+ oldname,
+ newname,
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ return qtrue;
+}
+
+//KK-Will Fix this For OAPub
+qboolean G_admin_restart( gentity_t *ent, int skiparg )
+{
+ char layout[ MAX_CVAR_VALUE_STRING ] = { "" };
+
+ if( G_SayArgc( ) > 1 + skiparg )
+ {
+ char map[ MAX_QPATH ];
+
+ trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
+ G_SayArgv( skiparg + 1, layout, sizeof( layout ) );
+
+ }
+
+ trap_SendConsoleCommand( EXEC_APPEND, "map_restart" );
+ AP( va( "print \"^3!restart: ^7map restarted by %s \n\"",
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ return qtrue;
+}
+
+qboolean G_admin_nextmap( gentity_t *ent, int skiparg )
+{
+ AP( va( "print \"^3!nextmap: ^7%s^7 decided to load the next map\n\"",
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ //level.lastWin = TEAM_NONE;
+ //trap_SetConfigstring( CS_WINNER, "NextMap" );
+ LogExit( va( "nextmap was run by %s", ( ent ) ? ent->client->pers.netname : "console" ) );
+ return qtrue;
+}
+
+qboolean G_admin_namelog( gentity_t *ent, int skiparg )
+{
+ int i, j;
+ char search[ MAX_NAME_LENGTH ] = {""};
+ char s2[ MAX_NAME_LENGTH ] = {""};
+ char n2[ MAX_NAME_LENGTH ] = {""};
+ char guid_stub[ 9 ];
+ qboolean found = qfalse;
+ int printed = 0;
+
+ if( G_SayArgc() > 1 + skiparg )
+ {
+ G_SayArgv( 1 + skiparg, search, sizeof( search ) );
+ G_SanitiseString( search, s2, sizeof( s2 ) );
+ }
+ ADMBP_begin();
+ for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
+ {
+ if( search[ 0 ] )
+ {
+ found = qfalse;
+ for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES &&
+ g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
+ {
+ G_SanitiseString( g_admin_namelog[ i ]->name[ j ], n2, sizeof( n2 ) );
+ if( strstr( n2, s2 ) )
+ {
+ found = qtrue;
+ break;
+ }
+ }
+ if( !found )
+ continue;
+ }
+ printed++;
+ for( j = 0; j < 8; j++ )
+ guid_stub[ j ] = g_admin_namelog[ i ]->guid[ j + 24 ];
+ guid_stub[ j ] = '\0';
+ if( g_admin_namelog[ i ]->slot > -1 )
+ ADMBP( "^3" );
+ ADMBP( va( "%-2s (*%s) %15s^7",
+ ( g_admin_namelog[ i ]->slot > -1 ) ?
+ va( "%d", g_admin_namelog[ i ]->slot ) : "-",
+ guid_stub, g_admin_namelog[ i ]->ip ) );
+ for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES &&
+ g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
+ {
+ ADMBP( va( " '%s^7'", g_admin_namelog[ i ]->name[ j ] ) );
+ }
+ ADMBP( "\n" );
+ }
+ ADMBP( va( "^3!namelog:^7 %d recent clients found\n", printed ) );
+ ADMBP_end();
+ return qtrue;
+}
+
+qboolean G_admin_lock( gentity_t *ent, int skiparg )
+{
+ char teamName[2] = {""};
+ team_t team;
+
+ if( G_SayArgc() < 2 + skiparg )
+ {
+ ADMP( "^3!lock: ^7usage: !lock [r|b|f]\n" );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, teamName, sizeof( teamName ) );
+ team = G_TeamFromString( teamName );
+
+ if( team == TEAM_RED )
+ {
+ if( level.RedTeamLocked )
+ {
+ ADMP( "^3!lock: ^7the Red team is already locked\n" );
+ return qfalse;
+ }
+ level.RedTeamLocked = qtrue;
+ }
+ else if( team == TEAM_BLUE ) {
+ if( level.BlueTeamLocked )
+ {
+ ADMP( "^3!lock: ^7the Blue team is already locked\n" );
+ return qfalse;
+ }
+ level.BlueTeamLocked = qtrue;
+ }
+ else if(team == TEAM_FREE ) {
+ if( level.FFALocked )
+ {
+ ADMP( "^3!lock: ^7DeathMatch is already Locked!!!\n" );
+ return qfalse;
+ }
+ level.FFALocked = qtrue;
+ }
+ else
+ {
+ ADMP( va( "^3!lock: ^7invalid team\"%c\"\n", teamName[0] ) );
+ return qfalse;
+ }
+
+ AP( va( "print \"^3!lock: ^7the %s team has been locked by %s\n\"",
+ BG_TeamName( team ),
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ return qtrue;
+}
+
+qboolean G_admin_unlock( gentity_t *ent, int skiparg )
+{
+ char teamName[2] = {""};
+ team_t team;
+
+ if( G_SayArgc() < 2 + skiparg )
+ {
+ ADMP( "^3!unlock: ^7usage: !unlock [r|b|f]\n" );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, teamName, sizeof( teamName ) );
+ team = G_TeamFromString( teamName );
+
+ if( team == TEAM_RED )
+ {
+ if( !level.RedTeamLocked )
+ {
+ ADMP( "^3!unlock: ^7the Red team is not currently locked\n" );
+ return qfalse;
+ }
+ level.RedTeamLocked = qfalse;
+ }
+ else if( team == TEAM_BLUE ) {
+ if( !level.BlueTeamLocked )
+ {
+ ADMP( "^3!unlock: ^7the Blue team is not currently locked\n" );
+ return qfalse;
+ }
+ level.BlueTeamLocked = qfalse;
+ }
+ else if( team == TEAM_FREE ) {
+ if( !level.FFALocked )
+ {
+ ADMP( "^!unlock: ^7Deathmatch is not currently Locked!!!\n" );
+ return qfalse;
+ }
+ level.FFALocked = qfalse;
+ }
+ else
+ {
+ ADMP( va( "^3!unlock: ^7invalid team\"%c\"\n", teamName[0] ) );
+ return qfalse;
+ }
+ AP( va( "print \"^3!unlock: ^7the %s team has been unlocked by %s\n\"",
+ BG_TeamName( team ),
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ return qtrue;
+}
+//KK-OAX Begin Addition
+qboolean G_admin_disorient(gentity_t *ent, int skiparg)
+{
+ int pids[MAX_CLIENTS], found;
+ char name[MAX_NAME_LENGTH], err[MAX_STRING_CHARS];
+ char *reason;
+ gentity_t *vic;
+
+ if(G_SayArgc() < 2+skiparg) {
+ ADMP("^/disorient usage: ^7!disorient [name|slot#] [reason]");
+ return qfalse;
+ }
+ G_SayArgv(1+skiparg, name, sizeof(name));
+ reason = G_SayConcatArgs(2+skiparg);
+
+ if((found = G_ClientNumbersFromString(name, pids, MAX_CLIENTS)) != 1) {
+ G_MatchOnePlayer(pids, found, err, sizeof(err));
+ ADMP(va("^/disorient: ^7%s", err));
+ return qfalse;
+ }
+ vic = &g_entities[pids[0]];
+ if(!admin_higher(ent, vic)) {
+ ADMP("^/disorient: ^7sorry, but your intended victim has a higher admin level than you do");
+ return qfalse;
+ }
+
+ if(!(vic->client->sess.sessionTeam == TEAM_RED ||
+ vic->client->sess.sessionTeam == TEAM_BLUE ||
+ vic->client->sess.sessionTeam == TEAM_FREE )) {
+ ADMP("^/disorient: ^7player must be on a team");
+ return qfalse;
+ }
+ if(vic->client->pers.disoriented) {
+ ADMP(va("^/disorient: ^7%s^7 is already disoriented",
+ vic->client->pers.netname));
+ return qfalse;
+ }
+ vic->client->pers.disoriented = qtrue;
+ AP(va("chat \"^/disorient: ^7%s ^7is disoriented\" -1",
+ vic->client->pers.netname));
+
+ CPx(pids[0], va("cp \"%s ^7disoriented you%s%s\"",
+ (ent?ent->client->pers.netname:"^3SERVER CONSOLE"),
+ (*reason) ? " because:\n" : "",
+ (*reason) ? reason : ""));
+ return qtrue;
+}
+qboolean G_admin_orient(gentity_t *ent, int skiparg)
+{
+ int pids[MAX_CLIENTS], found;
+ char name[MAX_NAME_LENGTH], err[MAX_STRING_CHARS];
+ gentity_t *vic;
+
+ if(G_SayArgc() < 2+skiparg) {
+ ADMP("^/orient usage: ^7!orient [name|slot#]");
+ return qfalse;
+ }
+ G_SayArgv(1+skiparg, name, sizeof(name));
+ //Fix
+ if((found = G_ClientNumbersFromString(name, pids, MAX_CLIENTS)) != 1) {
+ G_MatchOnePlayer(pids, found, err, sizeof(err));
+ ADMP(va("^/orient: ^7%s", err));
+ return qfalse;
+ }
+ vic = &g_entities[pids[0]];
+
+ if(!vic->client->pers.disoriented) {
+ ADMP(va("^/orient: ^7%s^7 is not currently disoriented",
+ vic->client->pers.netname));
+ return qfalse;
+ }
+ vic->client->pers.disoriented = qfalse;
+ AP(va("chat \"^/orient: ^7%s ^7is no longer disoriented\" -1",
+ vic->client->pers.netname));
+
+ CPx(pids[0], va("cp \"%s ^7oriented you\"",
+ (ent?ent->client->pers.netname:"^3SERVER CONSOLE")));
+ return qtrue;
+}
+
+qboolean G_admin_slap( gentity_t *ent, int skiparg )
+{
+ int pids[MAX_CLIENTS], found, dmg;
+ char name[MAX_NAME_LENGTH], err[MAX_STRING_CHARS];
+ char *reason;
+ char damage[4];
+ gentity_t *vic;
+ int soundIndex;
+
+ //KK-Too many Parameters Check removed. It'll truncate the reason message.
+
+ if(G_SayArgc() < 2+skiparg)
+ {
+ ADMP("^/slap usage: ^7!slap [name|slot#] [reason] [damage]");
+ return qfalse;
+ }
+
+ G_SayArgv(1+skiparg, name, sizeof(name));
+ G_SayArgv(2+skiparg, damage, sizeof(damage));
+
+ dmg = atoi(damage);
+ if(!dmg)
+ {
+ dmg = 25;
+ reason = G_SayConcatArgs(2+skiparg);
+ }
+ else
+ {
+ reason = G_SayConcatArgs(3+skiparg);
+ }
+
+ if((found = G_ClientNumbersFromString(name, pids, MAX_CLIENTS)) != 1) {
+ G_MatchOnePlayer(pids, found, err, sizeof(err));
+ ADMP(va("^/slap: ^7%s", err));
+ return qfalse;
+ }
+
+ vic = &g_entities[pids[0]];
+ if(!admin_higher(ent, vic)) {
+ ADMP("^/slap: ^7sorry, but your intended victim has a higher admin level than you do");
+ return qfalse;
+ }
+
+ if(!(vic->client->sess.sessionTeam == TEAM_RED ||
+ vic->client->sess.sessionTeam == TEAM_BLUE ||
+ vic->client->sess.sessionTeam == TEAM_FREE )) {
+ ADMP("^/slap: ^7player must be in the game!");
+ return qfalse;
+ }
+ //Player Not Alive
+ if( vic->health < 1 )
+ {
+ //Is Their Body Alive?
+ if(vic->s.eType != ET_INVISIBLE)
+ {
+ //Make 'em a Bloody mess
+ G_Damage(vic, NULL, NULL, NULL, NULL, 500, 0, MOD_UNKNOWN);
+ }
+ //Force Their Butt to Respawn
+ ClientSpawn( vic );
+ }
+ // Will the Slap Kill them? (Obviously false if we Respawned 'em)
+ if(!(vic->health > dmg ))
+ {
+ vic->health = 1;
+ }
+ else //If it won't kill em...Do the full Damage
+ {
+ vic->health -= dmg;
+ }
+
+ //KK-OAX Play them the slap sound
+ soundIndex = G_SoundIndex("sound/admin/slap.wav");
+ G_Sound(vic, CHAN_VOICE, soundIndex );
+
+ //Print it to everybody
+ AP(va("chat \"^/slap: ^7%s ^7was slapped\" -1", vic->client->pers.netname));
+ //CenterPrint it to the Person Being Slapped
+ CPx(pids[0], va("cp \"%s ^7slapped you%s%s\"",
+ (ent?ent->client->pers.netname:"^3SERVER CONSOLE"),
+ (*reason) ? " because:\n" : "",
+ (*reason) ? reason : ""));
+ return qtrue;
+}
+
+
+//Called Each Time a Warning is Created
+int G_admin_warn_check( gentity_t *ent )
+{
+ char *ip, *guid;
+ int i;
+ int t;
+ int numWarnings = 0;
+
+ t = trap_RealTime( NULL );
+
+ ip = ent->client->pers.ip;
+
+ //We Don't Want to Count Warnings for the LocalHost
+ if( !*ip )
+ return 0;
+
+ guid = ent->client->pers.guid;
+
+ //Just to make sure...Don't want to crash...Will Figure something better out later
+ if( !*guid )
+ return 0;
+
+ //For Each Warning, up to the max number of warnings
+ for( i = 0; i < MAX_ADMIN_WARNINGS && g_admin_warnings[ i ]; i++ )
+ {
+ // Ignore Expired Warnings
+ if( ( g_admin_warnings[ i ]->expires - t ) < 1 )
+ continue;
+ //If a warning matches their IP or GUID
+ if( strstr( ip, g_admin_warnings[ i ]->ip ) || strstr( guid, g_admin_warnings[ i ]->guid ))
+ {
+ numWarnings++;
+ }
+ }
+ //If we get here, return the number of warnings;
+ return numWarnings;
+}
+
+
+qboolean G_admin_warn( gentity_t *ent, int skiparg )
+{
+ int pids[MAX_CLIENTS], found;
+ int seconds;
+ char name[ MAX_NAME_LENGTH ], err[MAX_STRING_CHARS];
+ char *reason;
+ int minargc;
+ char duration[ 32 ];
+ char s2[ MAX_NAME_LENGTH ];
+ gentity_t *vic;
+ int totalWarnings;
+ int soundIndex;
+
+ if( G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
+ {
+ minargc = 1 + skiparg;
+ }
+ else
+ {
+ minargc = 2 + skiparg;
+ }
+
+ if( G_SayArgc() < minargc )
+ {
+ ADMP( "^3!warn: ^7usage: !warn [name|slot|ip] [reason]\n" );
+ return qfalse;
+ }
+
+ G_SayArgv( 1 + skiparg, name, sizeof( name ) );
+ G_SanitiseString( name, s2, sizeof( s2 ) );
+ reason = G_SayConcatArgs(2+skiparg);
+
+ seconds = g_warningExpire.integer;
+
+ if((found = G_ClientNumbersFromString(name, pids, MAX_CLIENTS)) != 1) {
+ G_MatchOnePlayer(pids, found, err, sizeof(err));
+ ADMP(va("^/warn: ^7%s", err));
+ return qfalse;
+ }
+
+ vic = &g_entities[pids[0]];
+ if(!admin_higher(ent, vic)) {
+ ADMP("^/slap: ^7sorry, but your intended victim has a higher admin level than you do");
+ return qfalse;
+ }
+
+ G_admin_duration( ( seconds ) ? seconds : -1,
+ duration, sizeof( duration ) );
+
+ admin_create_warning( ent,
+ vic->client->pers.netname,
+ vic->client->pers.guid,
+ vic->client->pers.ip,
+ seconds, reason );
+
+ if( !g_admin.string[ 0 ] )
+ ADMP( "^3!warn: ^7WARNING g_admin not set, not saving warning to a file\n" );
+ else
+ admin_writeconfig();
+
+ //KK, Use The Check Warnings Deal Here
+ totalWarnings = G_admin_warn_check( vic );
+
+ // Play the whistle
+ soundIndex = G_SoundIndex("sound/admin/whistle.wav");
+ G_GlobalSound( soundIndex );
+
+ //First Check to make sure g_maxWarnings isn't a Null Value
+ if( g_maxWarnings.integer )
+ {
+ //If they have gone over the max number of warnings...
+ if( totalWarnings >= g_maxWarnings.integer )
+ {
+ //Give them The Boot till the Warning Expires
+ admin_create_ban( ent,
+ vic->client->pers.netname,
+ vic->client->pers.guid,
+ vic->client->pers.ip,
+ seconds,
+ "Too Many Warnings" );
+
+ if( g_admin.string[ 0 ] )
+ admin_writeconfig();
+
+ trap_SendServerCommand( pids[ 0 ],
+ va( "disconnect \"You have been kicked.\n%s^7\nreason:\n%s\"",
+ ( ent ) ? va( "admin:\n%s", ent->client->pers.netname ) : "SERVER",
+ "Too Many Warnings" ) );
+
+ trap_DropClient( pids[ 0 ], va( "has been kicked%s^7. reason: %s",
+ "Auto-Admin System",
+ "Too Many Warnings" ) );
+ return qtrue;
+ }
+ else
+ {
+
+ //Print it to everybody
+ AP(va("chat \"^/warn: ^7%s ^7was warned\" -1", vic->client->pers.netname));
+ //CenterPrint it to the Person Being Slapped
+ CPx(pids[0], va("cp \"%s ^7warned you%s%s\"",
+ (ent?ent->client->pers.netname:"^3SERVER CONSOLE"),
+ (*reason) ? " because:\n" : "",
+ (*reason) ? reason : ""));
+ return qtrue;
+ }
+ }
+ else //KK-OAX g_maxWarnings is null or 0
+ {
+ AP(va("chat \"^/warn: ^7%s ^7was warned\" -1", vic->client->pers.netname));
+ //CenterPrint it to the Person Being Slapped
+ CPx(pids[0], va("cp \"%s ^7warned you%s%s\"",
+ (ent?ent->client->pers.netname:"^3SERVER CONSOLE"),
+ (*reason) ? " because:\n" : "",
+ (*reason) ? reason : ""));
+ return qtrue;
+ }
+
+}
+
+qboolean G_admin_shuffle( gentity_t *ent, int skipargs )
+{
+ trap_SendConsoleCommand( EXEC_APPEND, "shuffle" );
+ AP( va( "print \"^3!shuffle: ^7teams shuffled by %s \n\"",
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ return qtrue;
+}
+
+//KK-OAX End Additions
+
+/*
+================
+ G_admin_print
+
+ This function facilitates the ADMP define. ADMP() is similar to CP except
+ that it prints the message to the server console if ent is not defined.
+================
+*/
+void G_admin_print( gentity_t *ent, char *m )
+{
+ if( ent )
+ trap_SendServerCommand( ent - level.gentities, va( "print \"%s\"", m ) );
+ else
+ {
+ char m2[ MAX_STRING_CHARS ];
+ if( !trap_Cvar_VariableIntegerValue( "com_ansiColor" ) )
+ {
+ G_DecolorString( m, m2, sizeof( m2 ) );
+ trap_Printf( m2 );
+ }
+ else
+ trap_Printf( m );
+ }
+}
+
+void G_admin_buffer_begin()
+{
+ g_bfb[ 0 ] = '\0';
+}
+
+void G_admin_buffer_end( gentity_t *ent )
+{
+ ADMP( g_bfb );
+}
+
+void G_admin_buffer_print( gentity_t *ent, char *m )
+{
+ // 1022 - strlen("print 64 \"\"") - 1
+ if( strlen( m ) + strlen( g_bfb ) >= 1009 )
+ {
+ ADMP( g_bfb );
+ g_bfb[ 0 ] = '\0';
+ }
+ Q_strcat( g_bfb, sizeof( g_bfb ), m );
+}
+
+
+void G_admin_cleanup()
+{
+ int i = 0;
+
+ for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
+ {
+ BG_Free( g_admin_levels[ i ] );
+ g_admin_levels[ i ] = NULL;
+ }
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ {
+ BG_Free( g_admin_admins[ i ] );
+ g_admin_admins[ i ] = NULL;
+ }
+ for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
+ {
+ BG_Free( g_admin_bans[ i ] );
+ g_admin_bans[ i ] = NULL;
+ }
+ for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
+ {
+ BG_Free( g_admin_commands[ i ] );
+ g_admin_commands[ i ] = NULL;
+ }
+}
+
+
+
diff --git a/game/code/game/g_admin.h b/code/game/g_admin.h
similarity index 100%
rename from game/code/game/g_admin.h
rename to code/game/g_admin.h
diff --git a/code/game/g_arenas.c b/code/game/g_arenas.c
new file mode 100644
index 0000000..c16ad01
--- /dev/null
+++ b/code/game/g_arenas.c
@@ -0,0 +1,376 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+//
+// g_arenas.c
+//
+
+#include "g_local.h"
+
+
+gentity_t *podium1;
+gentity_t *podium2;
+gentity_t *podium3;
+
+
+/*
+==================
+UpdateTournamentInfo
+==================
+*/
+void UpdateTournamentInfo( void ) {
+ int i;
+ gentity_t *player;
+ int playerClientNum;
+ int n, accuracy, perfect, msglen;
+#ifdef MISSIONPACK // bk001205
+ int score1, score2;
+ qboolean won;
+#endif
+ char buf[32];
+ char msg[MAX_STRING_CHARS];
+
+ // find the real player
+ player = NULL;
+ for (i = 0; i < level.maxclients; i++ ) {
+ player = &g_entities[i];
+ if ( !player->inuse ) {
+ continue;
+ }
+ if ( !( player->r.svFlags & SVF_BOT ) ) {
+ break;
+ }
+ }
+ // this should never happen!
+ if ( !player || i == level.maxclients ) {
+ return;
+ }
+ playerClientNum = i;
+
+ CalculateRanks();
+
+ if ( level.clients[playerClientNum].sess.sessionTeam == TEAM_SPECTATOR ) {
+#ifdef MISSIONPACK
+ Com_sprintf( msg, sizeof(msg), "postgame %i %i 0 0 0 0 0 0 0 0 0 0 0", level.numNonSpectatorClients, playerClientNum );
+#else
+ Com_sprintf( msg, sizeof(msg), "postgame %i %i 0 0 0 0 0 0", level.numNonSpectatorClients, playerClientNum );
+#endif
+ }
+ else {
+ if( player->client->accuracy_shots ) {
+ accuracy = player->client->accuracy_hits * 100 / player->client->accuracy_shots;
+ }
+ else {
+ accuracy = 0;
+ }
+#ifdef MISSIONPACK
+ won = qfalse;
+ if (g_gametype.integer >= GT_CTF && g_ffa_gt==0) {
+ score1 = level.teamScores[TEAM_RED];
+ score2 = level.teamScores[TEAM_BLUE];
+ if (level.clients[playerClientNum].sess.sessionTeam == TEAM_RED) {
+ won = (level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE]);
+ } else {
+ won = (level.teamScores[TEAM_BLUE] > level.teamScores[TEAM_RED]);
+ }
+ } else {
+ if (&level.clients[playerClientNum] == &level.clients[ level.sortedClients[0] ]) {
+ won = qtrue;
+ score1 = level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE];
+ score2 = level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE];
+ } else {
+ score2 = level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE];
+ score1 = level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE];
+ }
+ }
+ if (won && player->client->ps.persistant[PERS_KILLED] == 0) {
+ perfect = 1;
+ } else {
+ perfect = 0;
+ }
+ Com_sprintf( msg, sizeof(msg), "postgame %i %i %i %i %i %i %i %i %i %i %i %i %i %i", level.numNonSpectatorClients, playerClientNum, accuracy,
+ player->client->ps.persistant[PERS_IMPRESSIVE_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT],player->client->ps.persistant[PERS_DEFEND_COUNT],
+ player->client->ps.persistant[PERS_ASSIST_COUNT], player->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE],
+ perfect, score1, score2, level.time, player->client->ps.persistant[PERS_CAPTURES] );
+
+#else
+ perfect = ( level.clients[playerClientNum].ps.persistant[PERS_RANK] == 0 && player->client->ps.persistant[PERS_KILLED] == 0 ) ? 1 : 0;
+ Com_sprintf( msg, sizeof(msg), "postgame %i %i %i %i %i %i %i %i", level.numNonSpectatorClients, playerClientNum, accuracy,
+ player->client->ps.persistant[PERS_IMPRESSIVE_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT],
+ player->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE],
+ perfect );
+#endif
+ }
+
+ msglen = strlen( msg );
+ for( i = 0; i < level.numNonSpectatorClients; i++ ) {
+ n = level.sortedClients[i];
+ Com_sprintf( buf, sizeof(buf), " %i %i %i", n, level.clients[n].ps.persistant[PERS_RANK], level.clients[n].ps.persistant[PERS_SCORE] );
+ msglen += strlen( buf );
+ if( msglen >= sizeof(msg) ) {
+
+ break;
+ }
+ strcat( msg, buf );
+ }
+ trap_SendConsoleCommand( EXEC_APPEND, msg );
+}
+
+
+static gentity_t *SpawnModelOnVictoryPad( gentity_t *pad, vec3_t offset, gentity_t *ent, int place ) {
+ gentity_t *body;
+ vec3_t vec;
+ vec3_t f, r, u;
+
+ body = G_Spawn();
+ if ( !body ) {
+ G_Printf( S_COLOR_RED "ERROR: out of gentities\n" );
+ return NULL;
+ }
+
+ body->classname = ent->client->pers.netname;
+ body->client = ent->client;
+ body->s = ent->s;
+ body->s.eType = ET_PLAYER; // could be ET_INVISIBLE
+ body->s.eFlags = 0; // clear EF_TALK, etc
+ body->s.powerups = 0; // clear powerups
+ body->s.loopSound = 0; // clear lava burning
+ body->s.number = body - g_entities;
+ body->timestamp = level.time;
+ body->physicsObject = qtrue;
+ body->physicsBounce = 0; // don't bounce
+ body->s.event = 0;
+ body->s.pos.trType = TR_STATIONARY;
+ body->s.groundEntityNum = ENTITYNUM_WORLD;
+ body->s.legsAnim = LEGS_IDLE;
+ body->s.torsoAnim = TORSO_STAND;
+ if( body->s.weapon == WP_NONE ) {
+ body->s.weapon = WP_MACHINEGUN;
+ }
+ if( body->s.weapon == WP_GAUNTLET) {
+ body->s.torsoAnim = TORSO_STAND2;
+ }
+ body->s.event = 0;
+ body->r.svFlags = ent->r.svFlags;
+ VectorCopy (ent->r.mins, body->r.mins);
+ VectorCopy (ent->r.maxs, body->r.maxs);
+ VectorCopy (ent->r.absmin, body->r.absmin);
+ VectorCopy (ent->r.absmax, body->r.absmax);
+ body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
+ body->r.contents = CONTENTS_BODY;
+ body->r.ownerNum = ent->r.ownerNum;
+ body->takedamage = qfalse;
+
+ VectorSubtract( level.intermission_origin, pad->r.currentOrigin, vec );
+ vectoangles( vec, body->s.apos.trBase );
+ body->s.apos.trBase[PITCH] = 0;
+ body->s.apos.trBase[ROLL] = 0;
+
+ AngleVectors( body->s.apos.trBase, f, r, u );
+ VectorMA( pad->r.currentOrigin, offset[0], f, vec );
+ VectorMA( vec, offset[1], r, vec );
+ VectorMA( vec, offset[2], u, vec );
+
+ G_SetOrigin( body, vec );
+
+ trap_LinkEntity (body);
+
+ body->count = place;
+
+ return body;
+}
+
+
+static void CelebrateStop( gentity_t *player ) {
+ int anim;
+
+ if( player->s.weapon == WP_GAUNTLET) {
+ anim = TORSO_STAND2;
+ }
+ else {
+ anim = TORSO_STAND;
+ }
+ player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
+}
+
+
+#define TIMER_GESTURE (34*66+50)
+static void CelebrateStart( gentity_t *player ) {
+ player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | TORSO_GESTURE;
+ player->nextthink = level.time + TIMER_GESTURE;
+ player->think = CelebrateStop;
+
+ /*
+ player->client->ps.events[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = EV_TAUNT;
+ player->client->ps.eventParms[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = 0;
+ player->client->ps.eventSequence++;
+ */
+ G_AddEvent(player, EV_TAUNT, 0);
+}
+
+
+static vec3_t offsetFirst = {0, 0, 74};
+static vec3_t offsetSecond = {-10, 60, 54};
+static vec3_t offsetThird = {-19, -60, 45};
+
+static void PodiumPlacementThink( gentity_t *podium ) {
+ vec3_t vec;
+ vec3_t origin;
+ vec3_t f, r, u;
+
+ podium->nextthink = level.time + 100;
+
+ AngleVectors( level.intermission_angle, vec, NULL, NULL );
+ VectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( "g_podiumDist" ), vec, origin );
+ origin[2] -= trap_Cvar_VariableIntegerValue( "g_podiumDrop" );
+ G_SetOrigin( podium, origin );
+
+ if( podium1 ) {
+ VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
+ vectoangles( vec, podium1->s.apos.trBase );
+ podium1->s.apos.trBase[PITCH] = 0;
+ podium1->s.apos.trBase[ROLL] = 0;
+
+ AngleVectors( podium1->s.apos.trBase, f, r, u );
+ VectorMA( podium->r.currentOrigin, offsetFirst[0], f, vec );
+ VectorMA( vec, offsetFirst[1], r, vec );
+ VectorMA( vec, offsetFirst[2], u, vec );
+
+ G_SetOrigin( podium1, vec );
+ }
+
+ if( podium2 ) {
+ VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
+ vectoangles( vec, podium2->s.apos.trBase );
+ podium2->s.apos.trBase[PITCH] = 0;
+ podium2->s.apos.trBase[ROLL] = 0;
+
+ AngleVectors( podium2->s.apos.trBase, f, r, u );
+ VectorMA( podium->r.currentOrigin, offsetSecond[0], f, vec );
+ VectorMA( vec, offsetSecond[1], r, vec );
+ VectorMA( vec, offsetSecond[2], u, vec );
+
+ G_SetOrigin( podium2, vec );
+ }
+
+ if( podium3 ) {
+ VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
+ vectoangles( vec, podium3->s.apos.trBase );
+ podium3->s.apos.trBase[PITCH] = 0;
+ podium3->s.apos.trBase[ROLL] = 0;
+
+ AngleVectors( podium3->s.apos.trBase, f, r, u );
+ VectorMA( podium->r.currentOrigin, offsetThird[0], f, vec );
+ VectorMA( vec, offsetThird[1], r, vec );
+ VectorMA( vec, offsetThird[2], u, vec );
+
+ G_SetOrigin( podium3, vec );
+ }
+}
+
+
+static gentity_t *SpawnPodium( void ) {
+ gentity_t *podium;
+ vec3_t vec;
+ vec3_t origin;
+
+ podium = G_Spawn();
+ if ( !podium ) {
+ return NULL;
+ }
+
+ podium->classname = "podium";
+ podium->s.eType = ET_GENERAL;
+ podium->s.number = podium - g_entities;
+ podium->clipmask = CONTENTS_SOLID;
+ podium->r.contents = CONTENTS_SOLID;
+ podium->s.modelindex = G_ModelIndex( SP_PODIUM_MODEL );
+
+ AngleVectors( level.intermission_angle, vec, NULL, NULL );
+ VectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( "g_podiumDist" ), vec, origin );
+ origin[2] -= trap_Cvar_VariableIntegerValue( "g_podiumDrop" );
+ G_SetOrigin( podium, origin );
+
+ VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
+ podium->s.apos.trBase[YAW] = vectoyaw( vec );
+ trap_LinkEntity (podium);
+
+ podium->think = PodiumPlacementThink;
+ podium->nextthink = level.time + 100;
+ return podium;
+}
+
+
+/*
+==================
+SpawnModelsOnVictoryPads
+==================
+*/
+void SpawnModelsOnVictoryPads( void ) {
+ gentity_t *player;
+ gentity_t *podium;
+
+ podium1 = NULL;
+ podium2 = NULL;
+ podium3 = NULL;
+
+ podium = SpawnPodium();
+
+ player = SpawnModelOnVictoryPad( podium, offsetFirst, &g_entities[level.sortedClients[0]],
+ level.clients[ level.sortedClients[0] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
+ if ( player ) {
+ player->nextthink = level.time + 2000;
+ player->think = CelebrateStart;
+ podium1 = player;
+ }
+
+ player = SpawnModelOnVictoryPad( podium, offsetSecond, &g_entities[level.sortedClients[1]],
+ level.clients[ level.sortedClients[1] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
+ if ( player ) {
+ podium2 = player;
+ }
+
+ if ( level.numNonSpectatorClients > 2 ) {
+ player = SpawnModelOnVictoryPad( podium, offsetThird, &g_entities[level.sortedClients[2]],
+ level.clients[ level.sortedClients[2] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
+ if ( player ) {
+ podium3 = player;
+ }
+ }
+}
+
+
+/*
+===============
+Svcmd_AbortPodium_f
+===============
+*/
+void Svcmd_AbortPodium_f( void ) {
+ if( g_gametype.integer != GT_SINGLE_PLAYER ) {
+ return;
+ }
+
+ if( podium1 ) {
+ podium1->nextthink = level.time;
+ podium1->think = CelebrateStop;
+ }
+}
diff --git a/code/game/g_bot.c b/code/game/g_bot.c
new file mode 100644
index 0000000..d7538bc
--- /dev/null
+++ b/code/game/g_bot.c
@@ -0,0 +1,1026 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// g_bot.c
+
+#include "g_local.h"
+
+
+static int g_numBots;
+static char *g_botInfos[MAX_BOTS];
+
+
+int g_numArenas;
+static char *g_arenaInfos[MAX_ARENAS];
+
+
+#define BOT_BEGIN_DELAY_BASE 2000
+#define BOT_BEGIN_DELAY_INCREMENT 1500
+
+#define BOT_SPAWN_QUEUE_DEPTH 16
+
+typedef struct {
+ int clientNum;
+ int spawnTime;
+} botSpawnQueue_t;
+
+//static int botBeginDelay = 0; // bk001206 - unused, init
+static botSpawnQueue_t botSpawnQueue[BOT_SPAWN_QUEUE_DEPTH];
+
+vmCvar_t bot_minplayers;
+
+extern gentity_t *podium1;
+extern gentity_t *podium2;
+extern gentity_t *podium3;
+
+float trap_Cvar_VariableValue( const char *var_name ) {
+ char buf[128];
+
+ trap_Cvar_VariableStringBuffer(var_name, buf, sizeof(buf));
+ return atof(buf);
+}
+
+
+
+/*
+===============
+G_ParseInfos
+===============
+*/
+int G_ParseInfos( char *buf, int max, char *infos[] ) {
+ char *token;
+ int count;
+ char key[MAX_TOKEN_CHARS];
+ char info[MAX_INFO_STRING];
+
+ count = 0;
+
+ while ( 1 ) {
+ token = COM_Parse( &buf );
+ if ( !token[0] ) {
+ break;
+ }
+ if ( strcmp( token, "{" ) ) {
+ Com_Printf( "Missing { in info file\n" );
+ break;
+ }
+
+ if ( count == max ) {
+ Com_Printf( "Max infos exceeded\n" );
+ break;
+ }
+
+ info[0] = '\0';
+ while ( 1 ) {
+ token = COM_ParseExt( &buf, qtrue );
+ if ( !token[0] ) {
+ Com_Printf( "Unexpected end of info file\n" );
+ break;
+ }
+ if ( !strcmp( token, "}" ) ) {
+ break;
+ }
+ Q_strncpyz( key, token, sizeof( key ) );
+
+ token = COM_ParseExt( &buf, qfalse );
+ if ( !token[0] ) {
+ strcpy( token, "<NULL>" );
+ }
+ Info_SetValueForKey( info, key, token );
+ }
+ if(!BG_CanAlloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1))
+ break; //Not enough memory. Don't even try
+ //NOTE: extra space for arena number
+ //KK-OAX Changed to Tremulous's BG_Alloc
+ infos[count] = BG_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
+ if (infos[count]) {
+ strcpy(infos[count], info);
+ count++;
+ }
+ }
+ return count;
+}
+
+/*
+===============
+G_LoadArenasFromFile
+===============
+*/
+static void G_LoadArenasFromFile( char *filename ) {
+ int len;
+ fileHandle_t f;
+ char buf[MAX_ARENAS_TEXT];
+
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( !f ) {
+ trap_Printf( va( S_COLOR_RED "file not found: %s\n", filename ) );
+ return;
+ }
+ if ( len >= MAX_ARENAS_TEXT ) {
+ trap_Printf( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i\n", filename, len, MAX_ARENAS_TEXT ) );
+ trap_FS_FCloseFile( f );
+ return;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ g_numArenas += G_ParseInfos( buf, MAX_ARENAS - g_numArenas, &g_arenaInfos[g_numArenas] );
+}
+
+/*
+===============
+G_LoadArenas
+===============
+*/
+static void G_LoadArenas( void ) {
+ int numdirs;
+ vmCvar_t arenasFile;
+ char filename[128];
+ char dirlist[1024];
+ char* dirptr;
+ int i, n;
+ int dirlen;
+
+ g_numArenas = 0;
+
+ trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
+ if( *arenasFile.string ) {
+ G_LoadArenasFromFile(arenasFile.string);
+ }
+ else {
+ G_LoadArenasFromFile("scripts/arenas.txt");
+ }
+
+ // get all arenas from .arena files
+ numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 );
+ dirptr = dirlist;
+ for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
+ dirlen = strlen(dirptr);
+ strcpy(filename, "scripts/");
+ strcat(filename, dirptr);
+ G_LoadArenasFromFile(filename);
+ }
+ trap_Printf( va( "%i arenas parsed\n", g_numArenas ) );
+
+ for( n = 0; n < g_numArenas; n++ ) {
+ Info_SetValueForKey( g_arenaInfos[n], "num", va( "%i", n ) );
+ }
+}
+
+
+/*
+===============
+G_GetArenaInfoByNumber
+===============
+*/
+const char *G_GetArenaInfoByMap( const char *map ) {
+ int n;
+
+ for( n = 0; n < g_numArenas; n++ ) {
+ if( Q_stricmp( Info_ValueForKey( g_arenaInfos[n], "map" ), map ) == 0 ) {
+ return g_arenaInfos[n];
+ }
+ }
+
+ return NULL;
+}
+
+
+/*
+=================
+PlayerIntroSound
+=================
+*/
+static void PlayerIntroSound( const char *modelAndSkin ) {
+ char model[MAX_QPATH];
+ char *skin;
+
+ Q_strncpyz( model, modelAndSkin, sizeof(model) );
+ skin = strrchr( model, '/' );
+ if ( skin ) {
+ *skin++ = '\0';
+ }
+ else {
+ skin = model;
+ }
+
+ if( Q_stricmp( skin, "default" ) == 0 ) {
+ skin = model;
+ }
+
+ trap_SendConsoleCommand( EXEC_APPEND, va( "play sound/player/announce/%s.wav\n", skin ) );
+}
+
+/*
+===============
+G_AddRandomBot
+===============
+*/
+void G_AddRandomBot( int team ) {
+ int i, n, num;
+ float skill;
+ char *value, netname[36], *teamstr;
+ gclient_t *cl;
+
+ if (!trap_AAS_Initialized())
+ return; //If no AAS then don't even try
+
+ num = 0;
+ for ( n = 0; n < g_numBots ; n++ ) {
+ value = Info_ValueForKey( g_botInfos[n], "name" );
+ //
+ for ( i=0 ; i< g_maxclients.integer ; i++ ) {
+ cl = level.clients + i;
+ if ( cl->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
+ continue;
+ }
+ if ( team >= 0 && cl->sess.sessionTeam != team ) {
+ continue;
+ }
+ if ( !Q_stricmp( value, cl->pers.netname ) ) {
+ break;
+ }
+ }
+ if (i >= g_maxclients.integer) {
+ num++;
+ }
+ }
+ num = random() * num;
+ for ( n = 0; n < g_numBots ; n++ ) {
+ value = Info_ValueForKey( g_botInfos[n], "name" );
+ //
+ for ( i=0 ; i< g_maxclients.integer ; i++ ) {
+ cl = level.clients + i;
+ if ( cl->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
+ continue;
+ }
+ if ( team >= 0 && cl->sess.sessionTeam != team ) {
+ continue;
+ }
+ if ( !Q_stricmp( value, cl->pers.netname ) ) {
+ break;
+ }
+ }
+ if (i >= g_maxclients.integer) {
+ num--;
+ if (num <= 0) {
+ skill = trap_Cvar_VariableValue( "g_spSkill" );
+ if (team == TEAM_RED) teamstr = "red";
+ else if (team == TEAM_BLUE) teamstr = "blue";
+ else teamstr = "";
+ strncpy(netname, value, sizeof(netname)-1);
+ netname[sizeof(netname)-1] = '\0';
+ Q_CleanStr(netname);
+ trap_SendConsoleCommand( EXEC_INSERT, va("addbot %s %f %s %i\n", netname, skill, teamstr, 0) );
+ return;
+ }
+ }
+ }
+}
+
+/*
+===============
+G_RemoveRandomBot
+===============
+*/
+int G_RemoveRandomBot( int team ) {
+ int i;
+ gclient_t *cl;
+
+ for ( i=0 ; i< g_maxclients.integer ; i++ ) {
+ cl = level.clients + i;
+ if ( cl->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
+ continue;
+ }
+ if ( team >= 0 && cl->sess.sessionTeam != team ) {
+ continue;
+ }
+ trap_SendConsoleCommand( EXEC_INSERT, va("clientkick %d\n", cl->ps.clientNum) );
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+===============
+G_CountHumanPlayers
+===============
+*/
+int G_CountHumanPlayers( int team ) {
+ int i, num;
+ gclient_t *cl;
+
+ num = 0;
+ for ( i=0 ; i< g_maxclients.integer ; i++ ) {
+ cl = level.clients + i;
+ if ( cl->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ if ( g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT ) {
+ continue;
+ }
+ if ( team >= 0 && cl->sess.sessionTeam != team ) {
+ continue;
+ }
+ num++;
+ }
+ return num;
+}
+
+/*
+===============
+G_CountBotPlayers
+===============
+*/
+int G_CountBotPlayers( int team ) {
+ int i, n, num;
+ gclient_t *cl;
+
+ num = 0;
+ for ( i=0 ; i< g_maxclients.integer ; i++ ) {
+ cl = level.clients + i;
+ if ( cl->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
+ continue;
+ }
+ if ( team >= 0 && cl->sess.sessionTeam != team ) {
+ continue;
+ }
+ num++;
+ }
+ for( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {
+ if( !botSpawnQueue[n].spawnTime ) {
+ continue;
+ }
+ if ( botSpawnQueue[n].spawnTime > level.time ) {
+ continue;
+ }
+ num++;
+ }
+ return num;
+}
+
+/*
+===============
+G_CheckMinimumPlayers
+===============
+*/
+void G_CheckMinimumPlayers( void ) {
+ int minplayers;
+ int humanplayers, botplayers;
+ static int checkminimumplayers_time;
+
+ if (level.intermissiontime) return;
+ //only check once each 10 seconds
+ if (checkminimumplayers_time > level.time - 10000) {
+ return;
+ }
+ checkminimumplayers_time = level.time;
+ trap_Cvar_Update(&bot_minplayers);
+ minplayers = bot_minplayers.integer;
+ if (minplayers <= 0) return;
+
+ if (!trap_AAS_Initialized())
+ {
+ minplayers = 0;
+ checkminimumplayers_time = level.time+600*1000;
+ return; //If no AAS then don't even try
+ }
+
+ if (g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
+ if (minplayers >= g_maxclients.integer / 2) {
+ minplayers = (g_maxclients.integer / 2) -1;
+ }
+
+ humanplayers = G_CountHumanPlayers( TEAM_RED );
+ botplayers = G_CountBotPlayers( TEAM_RED );
+ //
+ if (humanplayers + botplayers < minplayers) {
+ G_AddRandomBot( TEAM_RED );
+ } else if (humanplayers + botplayers > minplayers && botplayers) {
+ G_RemoveRandomBot( TEAM_RED );
+ }
+ //
+ humanplayers = G_CountHumanPlayers( TEAM_BLUE );
+ botplayers = G_CountBotPlayers( TEAM_BLUE );
+ //
+ if (humanplayers + botplayers < minplayers) {
+ G_AddRandomBot( TEAM_BLUE );
+ } else if (humanplayers + botplayers > minplayers && botplayers) {
+ G_RemoveRandomBot( TEAM_BLUE );
+ }
+ }
+ else if (g_gametype.integer == GT_TOURNAMENT ) {
+ if (minplayers >= g_maxclients.integer) {
+ minplayers = g_maxclients.integer-1;
+ }
+ humanplayers = G_CountHumanPlayers( -1 );
+ botplayers = G_CountBotPlayers( -1 );
+ //
+ if (humanplayers + botplayers < minplayers) {
+ G_AddRandomBot( TEAM_FREE );
+ } else if (humanplayers + botplayers > minplayers && botplayers) {
+ // try to remove spectators first
+ if (!G_RemoveRandomBot( TEAM_SPECTATOR )) {
+ // just remove the bot that is playing
+ G_RemoveRandomBot( -1 );
+ }
+ }
+ }
+ else if (g_gametype.integer == GT_FFA || g_gametype.integer == GT_LMS) {
+ if (minplayers >= g_maxclients.integer) {
+ minplayers = g_maxclients.integer-1;
+ }
+ humanplayers = G_CountHumanPlayers( TEAM_FREE );
+ botplayers = G_CountBotPlayers( TEAM_FREE );
+ //
+ if (humanplayers + botplayers < minplayers) {
+ G_AddRandomBot( TEAM_FREE );
+ } else if (humanplayers + botplayers > minplayers && botplayers) {
+ G_RemoveRandomBot( TEAM_FREE );
+ }
+ }
+}
+
+/*
+===============
+G_CheckBotSpawn
+===============
+*/
+void G_CheckBotSpawn( void ) {
+ int n;
+ char userinfo[MAX_INFO_VALUE];
+
+ G_CheckMinimumPlayers();
+
+ for( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {
+ if( !botSpawnQueue[n].spawnTime ) {
+ continue;
+ }
+ if ( botSpawnQueue[n].spawnTime > level.time ) {
+ continue;
+ }
+ ClientBegin( botSpawnQueue[n].clientNum );
+ botSpawnQueue[n].spawnTime = 0;
+
+ if( g_gametype.integer == GT_SINGLE_PLAYER ) {
+ trap_GetUserinfo( botSpawnQueue[n].clientNum, userinfo, sizeof(userinfo) );
+ PlayerIntroSound( Info_ValueForKey (userinfo, "model") );
+ }
+ }
+}
+
+
+/*
+===============
+AddBotToSpawnQueue
+===============
+*/
+static void AddBotToSpawnQueue( int clientNum, int delay ) {
+ int n;
+
+ for( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {
+ if( !botSpawnQueue[n].spawnTime ) {
+ botSpawnQueue[n].spawnTime = level.time + delay;
+ botSpawnQueue[n].clientNum = clientNum;
+ return;
+ }
+ }
+ G_Printf( S_COLOR_YELLOW "Unable to delay spawn\n" );
+ ClientBegin( clientNum );
+}
+
+
+/*
+===============
+G_RemoveQueuedBotBegin
+
+Called on client disconnect to make sure the delayed spawn
+doesn't happen on a freed index
+===============
+*/
+void G_RemoveQueuedBotBegin( int clientNum ) {
+ int n;
+
+ for( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {
+ if( botSpawnQueue[n].clientNum == clientNum ) {
+ botSpawnQueue[n].spawnTime = 0;
+ return;
+ }
+ }
+}
+
+
+/*
+===============
+G_BotConnect
+===============
+*/
+qboolean G_BotConnect( int clientNum, qboolean restart ) {
+ bot_settings_t settings;
+ char userinfo[MAX_INFO_STRING];
+
+ trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
+
+ Q_strncpyz( settings.characterfile, Info_ValueForKey( userinfo, "characterfile" ), sizeof(settings.characterfile) );
+ settings.skill = atof( Info_ValueForKey( userinfo, "skill" ) );
+ Q_strncpyz( settings.team, Info_ValueForKey( userinfo, "team" ), sizeof(settings.team) );
+
+ if (!trap_AAS_Initialized() || !BotAISetupClient( clientNum, &settings, restart )) {
+ trap_DropClient( clientNum, "BotAISetupClient failed" );
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+
+/*
+===============
+G_AddBot
+===============
+*/
+static void G_AddBot( const char *name, float skill, const char *team, int delay, char *altname) {
+ int clientNum;
+ char *botinfo;
+ gentity_t *bot;
+ char *key;
+ char *s;
+ char *botname;
+ char *model;
+ char *headmodel;
+ char userinfo[MAX_INFO_STRING];
+
+ // get the botinfo from bots.txt
+ botinfo = G_GetBotInfoByName( name );
+ if ( !botinfo ) {
+ G_Printf( S_COLOR_RED "Error: Bot '%s' not defined\n", name );
+ return;
+ }
+
+ // create the bot's userinfo
+ userinfo[0] = '\0';
+
+ botname = Info_ValueForKey( botinfo, "funname" );
+ if( !botname[0] ) {
+ botname = Info_ValueForKey( botinfo, "name" );
+ }
+ // check for an alternative name
+ if (altname && altname[0]) {
+ botname = altname;
+ }
+ Info_SetValueForKey( userinfo, "name", botname );
+ Info_SetValueForKey( userinfo, "rate", "25000" );
+ Info_SetValueForKey( userinfo, "snaps", "20" );
+ Info_SetValueForKey( userinfo, "skill", va("%1.2f", skill) );
+
+ if ( skill >= 1 && skill < 2 ) {
+ Info_SetValueForKey( userinfo, "handicap", "50" );
+ }
+ else if ( skill >= 2 && skill < 3 ) {
+ Info_SetValueForKey( userinfo, "handicap", "70" );
+ }
+ else if ( skill >= 3 && skill < 4 ) {
+ Info_SetValueForKey( userinfo, "handicap", "90" );
+ }
+
+ key = "model";
+ model = Info_ValueForKey( botinfo, key );
+ if ( !*model ) {
+ model = "sarge/default";
+ }
+ Info_SetValueForKey( userinfo, key, model );
+ key = "team_model";
+ Info_SetValueForKey( userinfo, key, model );
+
+ key = "headmodel";
+ headmodel = Info_ValueForKey( botinfo, key );
+ if ( !*headmodel ) {
+ headmodel = model;
+ }
+ Info_SetValueForKey( userinfo, key, headmodel );
+ key = "team_headmodel";
+ Info_SetValueForKey( userinfo, key, headmodel );
+
+ key = "gender";
+ s = Info_ValueForKey( botinfo, key );
+ if ( !*s ) {
+ s = "male";
+ }
+ Info_SetValueForKey( userinfo, "sex", s );
+
+ key = "color1";
+ s = Info_ValueForKey( botinfo, key );
+ if ( !*s ) {
+ s = "4";
+ }
+ Info_SetValueForKey( userinfo, key, s );
+
+ key = "color2";
+ s = Info_ValueForKey( botinfo, key );
+ if ( !*s ) {
+ s = "5";
+ }
+ Info_SetValueForKey( userinfo, key, s );
+
+ s = Info_ValueForKey(botinfo, "aifile");
+ if (!*s ) {
+ trap_Printf( S_COLOR_RED "Error: bot has no aifile specified\n" );
+ return;
+ }
+
+ // have the server allocate a client slot
+ clientNum = trap_BotAllocateClient();
+ if ( clientNum == -1 ) {
+ G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" );
+ G_Printf( S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n" );
+ return;
+ }
+
+ // initialize the bot settings
+ if( !team || !*team ) {
+ if( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
+ if( PickTeam(clientNum) == TEAM_RED) {
+ team = "red";
+ }
+ else {
+ team = "blue";
+ }
+ }
+ else {
+ team = "red";
+ }
+ }
+ Info_SetValueForKey( userinfo, "characterfile", Info_ValueForKey( botinfo, "aifile" ) );
+ Info_SetValueForKey( userinfo, "skill", va( "%5.2f", skill ) );
+ Info_SetValueForKey( userinfo, "team", team );
+
+ bot = &g_entities[ clientNum ];
+ bot->r.svFlags |= SVF_BOT;
+ bot->inuse = qtrue;
+
+ // register the userinfo
+ trap_SetUserinfo( clientNum, userinfo );
+
+ // have it connect to the game as a normal client
+ if ( ClientConnect( clientNum, qtrue, qtrue ) ) {
+ return;
+ }
+
+ if( delay == 0 ) {
+ ClientBegin( clientNum );
+ return;
+ }
+
+ AddBotToSpawnQueue( clientNum, delay );
+}
+
+
+/*
+===============
+Svcmd_AddBot_f
+===============
+*/
+void Svcmd_AddBot_f( void ) {
+ float skill;
+ int delay;
+ char name[MAX_TOKEN_CHARS];
+ char altname[MAX_TOKEN_CHARS];
+ char string[MAX_TOKEN_CHARS];
+ char team[MAX_TOKEN_CHARS];
+
+ // are bots enabled?
+ if ( !trap_Cvar_VariableIntegerValue( "bot_enable" ) || !trap_AAS_Initialized() ) {
+ return;
+ }
+
+ // name
+ trap_Argv( 1, name, sizeof( name ) );
+ if ( !name[0] ) {
+ trap_Printf( "Usage: Addbot <botname> [skill 1-5] [team] [msec delay] [altname]\n" );
+ return;
+ }
+
+ // skill
+ trap_Argv( 2, string, sizeof( string ) );
+ if ( !string[0] ) {
+ skill = 4;
+ }
+ else {
+ skill = atof( string );
+ }
+
+ // team
+ trap_Argv( 3, team, sizeof( team ) );
+
+ // delay
+ trap_Argv( 4, string, sizeof( string ) );
+ if ( !string[0] ) {
+ delay = 0;
+ }
+ else {
+ delay = atoi( string );
+ }
+
+ // alternative name
+ trap_Argv( 5, altname, sizeof( altname ) );
+
+ G_AddBot( name, skill, team, delay, altname );
+
+ // if this was issued during gameplay and we are playing locally,
+ // go ahead and load the bot's media immediately
+ if ( level.time - level.startTime > 1000 &&
+ trap_Cvar_VariableIntegerValue( "cl_running" ) ) {
+ trap_SendServerCommand( -1, "loaddefered\n" ); // FIXME: spelled wrong, but not changing for demo
+ }
+}
+
+/*
+===============
+Svcmd_BotList_f
+===============
+*/
+void Svcmd_BotList_f( void ) {
+ int i;
+ char name[MAX_TOKEN_CHARS];
+ char funname[MAX_TOKEN_CHARS];
+ char model[MAX_TOKEN_CHARS];
+ char aifile[MAX_TOKEN_CHARS];
+
+ trap_Printf("^1name model aifile funname\n");
+ for (i = 0; i < g_numBots; i++) {
+ strcpy(name, Info_ValueForKey( g_botInfos[i], "name" ));
+ if ( !*name ) {
+ strcpy(name, "UnnamedPlayer");
+ }
+ strcpy(funname, Info_ValueForKey( g_botInfos[i], "funname" ));
+ if ( !*funname ) {
+ strcpy(funname, "");
+ }
+ strcpy(model, Info_ValueForKey( g_botInfos[i], "model" ));
+ if ( !*model ) {
+ strcpy(model, "sarge/default");
+ }
+ strcpy(aifile, Info_ValueForKey( g_botInfos[i], "aifile"));
+ if (!*aifile ) {
+ strcpy(aifile, "bots/default_c.c");
+ }
+ trap_Printf(va("%-16s %-16s %-20s %-20s\n", name, model, aifile, funname));
+ }
+}
+
+
+/*
+===============
+G_SpawnBots
+===============
+*/
+static void G_SpawnBots( char *botList, int baseDelay ) {
+ char *bot;
+ char *p;
+ float skill;
+ int delay;
+ char bots[MAX_INFO_VALUE];
+
+ podium1 = NULL;
+ podium2 = NULL;
+ podium3 = NULL;
+
+ skill = trap_Cvar_VariableValue( "g_spSkill" );
+ if( skill < 1 ) {
+ trap_Cvar_Set( "g_spSkill", "1" );
+ skill = 1;
+ }
+ else if ( skill > 5 ) {
+ trap_Cvar_Set( "g_spSkill", "5" );
+ skill = 5;
+ }
+
+ Q_strncpyz( bots, botList, sizeof(bots) );
+ p = &bots[0];
+ delay = baseDelay;
+ while( *p ) {
+ //skip spaces
+ while( *p && *p == ' ' ) {
+ p++;
+ }
+ if( !p ) {
+ break;
+ }
+
+ // mark start of bot name
+ bot = p;
+
+ // skip until space of null
+ while( *p && *p != ' ' ) {
+ p++;
+ }
+ if( *p ) {
+ *p++ = 0;
+ }
+
+ // we must add the bot this way, calling G_AddBot directly at this stage
+ // does "Bad Things"
+ trap_SendConsoleCommand( EXEC_INSERT, va("addbot %s %f free %i\n", bot, skill, delay) );
+
+ delay += BOT_BEGIN_DELAY_INCREMENT;
+ }
+}
+
+
+/*
+===============
+G_LoadBotsFromFile
+===============
+*/
+static void G_LoadBotsFromFile( char *filename ) {
+ int len;
+ fileHandle_t f;
+ char buf[MAX_BOTS_TEXT];
+
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( !f ) {
+ trap_Printf( va( S_COLOR_RED "file not found: %s\n", filename ) );
+ return;
+ }
+ if ( len >= MAX_BOTS_TEXT ) {
+ trap_Printf( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i\n", filename, len, MAX_BOTS_TEXT ) );
+ trap_FS_FCloseFile( f );
+ return;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ g_numBots += G_ParseInfos( buf, MAX_BOTS - g_numBots, &g_botInfos[g_numBots] );
+}
+
+/*
+===============
+G_LoadBots
+===============
+*/
+static void G_LoadBots( void ) {
+ vmCvar_t botsFile;
+ int numdirs;
+ char filename[128];
+ char dirlist[1024];
+ char* dirptr;
+ int i;
+ int dirlen;
+
+ if ( !trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
+ return;
+ }
+
+ g_numBots = 0;
+
+ trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
+ if( *botsFile.string ) {
+ G_LoadBotsFromFile(botsFile.string);
+ }
+ else {
+ G_LoadBotsFromFile("scripts/bots.txt");
+ }
+
+ // get all bots from .bot files
+ numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
+ dirptr = dirlist;
+ for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
+ dirlen = strlen(dirptr);
+ strcpy(filename, "scripts/");
+ strcat(filename, dirptr);
+ G_LoadBotsFromFile(filename);
+ }
+ trap_Printf( va( "%i bots parsed\n", g_numBots ) );
+}
+
+
+
+/*
+===============
+G_GetBotInfoByNumber
+===============
+*/
+char *G_GetBotInfoByNumber( int num ) {
+ if( num < 0 || num >= g_numBots ) {
+ trap_Printf( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
+ return NULL;
+ }
+ return g_botInfos[num];
+}
+
+
+/*
+===============
+G_GetBotInfoByName
+===============
+*/
+char *G_GetBotInfoByName( const char *name ) {
+ int n;
+ char *value;
+
+ for ( n = 0; n < g_numBots ; n++ ) {
+ value = Info_ValueForKey( g_botInfos[n], "name" );
+ if ( !Q_stricmp( value, name ) ) {
+ return g_botInfos[n];
+ }
+ }
+
+ return NULL;
+}
+
+/*
+===============
+G_InitBots
+===============
+*/
+void G_InitBots( qboolean restart ) {
+ int fragLimit;
+ int timeLimit;
+ const char *arenainfo;
+ char *strValue;
+ int basedelay;
+ char map[MAX_QPATH];
+ char serverinfo[MAX_INFO_STRING];
+
+ G_LoadBots();
+ G_LoadArenas();
+
+ trap_Cvar_Register( &bot_minplayers, "bot_minplayers", "0", CVAR_SERVERINFO );
+
+ if( g_gametype.integer == GT_SINGLE_PLAYER ) {
+ trap_GetServerinfo( serverinfo, sizeof(serverinfo) );
+ Q_strncpyz( map, Info_ValueForKey( serverinfo, "mapname" ), sizeof(map) );
+ arenainfo = G_GetArenaInfoByMap( map );
+ if ( !arenainfo ) {
+ return;
+ }
+
+ strValue = Info_ValueForKey( arenainfo, "fraglimit" );
+ fragLimit = atoi( strValue );
+ if ( fragLimit ) {
+ trap_Cvar_Set( "fraglimit", strValue );
+ }
+ else {
+ trap_Cvar_Set( "fraglimit", "0" );
+ }
+
+ strValue = Info_ValueForKey( arenainfo, "timelimit" );
+ timeLimit = atoi( strValue );
+ if ( timeLimit ) {
+ trap_Cvar_Set( "timelimit", strValue );
+ }
+ else {
+ trap_Cvar_Set( "timelimit", "0" );
+ }
+
+ if ( !fragLimit && !timeLimit ) {
+ trap_Cvar_Set( "fraglimit", "10" );
+ trap_Cvar_Set( "timelimit", "0" );
+ }
+
+ basedelay = BOT_BEGIN_DELAY_BASE;
+ strValue = Info_ValueForKey( arenainfo, "special" );
+ if( Q_stricmp( strValue, "training" ) == 0 ) {
+ basedelay += 10000;
+ }
+
+ if( !restart ) {
+ G_SpawnBots( Info_ValueForKey( arenainfo, "bots" ), basedelay );
+ }
+ }
+}
diff --git a/code/game/g_client.c b/code/game/g_client.c
new file mode 100644
index 0000000..e58ef91
--- /dev/null
+++ b/code/game/g_client.c
@@ -0,0 +1,2218 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#include "g_local.h"
+
+// g_client.c -- client functions that don't happen every frame
+
+static vec3_t playerMins = {-15, -15, -24};
+static vec3_t playerMaxs = {15, 15, 32};
+
+/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32) initial
+potential spawning position for deathmatch games.
+The first time a player enters the game, they will be at an 'initial' spot.
+Targets will be fired when someone spawns in on them.
+"nobots" will prevent bots from using this spot.
+"nohumans" will prevent non-bots from using this spot.
+*/
+void SP_info_player_deathmatch( gentity_t *ent ) {
+ int i;
+
+ G_SpawnInt( "nobots", "0", &i);
+ if ( i ) {
+ ent->flags |= FL_NO_BOTS;
+ }
+ G_SpawnInt( "nohumans", "0", &i );
+ if ( i ) {
+ ent->flags |= FL_NO_HUMANS;
+ }
+}
+
+/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
+equivelant to info_player_deathmatch
+*/
+void SP_info_player_start(gentity_t *ent) {
+ ent->classname = "info_player_deathmatch";
+ SP_info_player_deathmatch( ent );
+}
+
+//Three for Double_D
+void SP_info_player_dd(gentity_t *ent) {
+}
+void SP_info_player_dd_red(gentity_t *ent) {
+}
+void SP_info_player_dd_blue(gentity_t *ent) {
+}
+
+//One for Standard Domination, not really a player spawn point
+void SP_domination_point(gentity_t *ent) {
+}
+
+/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)
+The intermission will be viewed from this point. Target an info_notnull for the view direction.
+*/
+void SP_info_player_intermission( gentity_t *ent ) {
+
+}
+
+
+
+/*
+=======================================================================
+
+ SelectSpawnPoint
+
+=======================================================================
+*/
+
+/*
+================
+SpotWouldTelefrag
+
+================
+*/
+qboolean SpotWouldTelefrag( gentity_t *spot ) {
+ int i, num;
+ int touch[MAX_GENTITIES];
+ gentity_t *hit;
+ vec3_t mins, maxs;
+
+ VectorAdd( spot->s.origin, playerMins, mins );
+ VectorAdd( spot->s.origin, playerMaxs, maxs );
+ num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
+
+ for (i=0 ; i<num ; i++) {
+ hit = &g_entities[touch[i]];
+ //if ( hit->client && hit->client->ps.stats[STAT_HEALTH] > 0 ) {
+ if ( hit->client) {
+ return qtrue;
+ }
+
+ }
+
+ return qfalse;
+}
+
+/*
+================
+SelectNearestDeathmatchSpawnPoint
+
+Find the spot that we DON'T want to use
+================
+*/
+#define MAX_SPAWN_POINTS 128
+gentity_t *SelectNearestDeathmatchSpawnPoint( vec3_t from ) {
+ gentity_t *spot;
+ vec3_t delta;
+ float dist, nearestDist;
+ gentity_t *nearestSpot;
+
+ nearestDist = 999999;
+ nearestSpot = NULL;
+ spot = NULL;
+
+ while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
+
+ VectorSubtract( spot->s.origin, from, delta );
+ dist = VectorLength( delta );
+ if ( dist < nearestDist ) {
+ nearestDist = dist;
+ nearestSpot = spot;
+ }
+ }
+
+ return nearestSpot;
+}
+
+
+/*
+================
+SelectRandomDeathmatchSpawnPoint
+
+go to a random point that doesn't telefrag
+================
+*/
+#define MAX_SPAWN_POINTS 128
+gentity_t *SelectRandomDeathmatchSpawnPoint( void ) {
+ gentity_t *spot;
+ int count;
+ int selection;
+ gentity_t *spots[MAX_SPAWN_POINTS];
+
+ count = 0;
+ spot = NULL;
+
+ while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
+ if ( SpotWouldTelefrag( spot ) ) {
+ continue;
+ }
+ spots[ count ] = spot;
+ count++;
+ }
+
+ if ( !count ) { // no spots that won't telefrag
+ return G_Find( NULL, FOFS(classname), "info_player_deathmatch");
+ }
+
+ selection = rand() % count;
+ return spots[ selection ];
+}
+
+/*
+===========
+SelectRandomFurthestSpawnPoint
+
+Chooses a player start, deathmatch start, etc
+============
+*/
+gentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) {
+ gentity_t *spot;
+ vec3_t delta;
+ float dist;
+ float list_dist[64];
+ gentity_t *list_spot[64];
+ int numSpots, rnd, i, j;
+
+ numSpots = 0;
+ spot = NULL;
+
+ while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
+ if ( SpotWouldTelefrag( spot ) ) {
+ continue;
+ }
+ VectorSubtract( spot->s.origin, avoidPoint, delta );
+ dist = VectorLength( delta );
+ for (i = 0; i < numSpots; i++) {
+ if ( dist > list_dist[i] ) {
+ if ( numSpots >= 64 )
+ numSpots = 64-1;
+ for (j = numSpots; j > i; j--) {
+ list_dist[j] = list_dist[j-1];
+ list_spot[j] = list_spot[j-1];
+ }
+ list_dist[i] = dist;
+ list_spot[i] = spot;
+ numSpots++;
+ if (numSpots > 64)
+ numSpots = 64;
+ break;
+ }
+ }
+ if (i >= numSpots && numSpots < 64) {
+ list_dist[numSpots] = dist;
+ list_spot[numSpots] = spot;
+ numSpots++;
+ }
+ }
+ if (!numSpots) {
+ spot = G_Find( NULL, FOFS(classname), "info_player_deathmatch");
+ if (!spot)
+ G_Error( "Couldn't find a spawn point" );
+ VectorCopy (spot->s.origin, origin);
+ origin[2] += 9;
+ VectorCopy (spot->s.angles, angles);
+ return spot;
+ }
+
+ // select a random spot from the spawn points furthest away
+ rnd = random() * (numSpots / 2);
+
+ VectorCopy (list_spot[rnd]->s.origin, origin);
+ origin[2] += 9;
+ VectorCopy (list_spot[rnd]->s.angles, angles);
+
+ return list_spot[rnd];
+}
+
+/*
+===========
+SelectSpawnPoint
+
+Chooses a player start, deathmatch start, etc
+============
+*/
+gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) {
+ //return SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles );
+
+
+ gentity_t *spot;
+ gentity_t *nearestSpot;
+
+ nearestSpot = SelectNearestDeathmatchSpawnPoint( avoidPoint );
+
+ spot = SelectRandomDeathmatchSpawnPoint ( );
+ if ( spot == nearestSpot ) {
+ // roll again if it would be real close to point of death
+ spot = SelectRandomDeathmatchSpawnPoint ( );
+ if ( spot == nearestSpot ) {
+ // last try
+ spot = SelectRandomDeathmatchSpawnPoint ( );
+ }
+ }
+
+ // find a single player start spot
+ if (!spot) {
+ G_Error( "Couldn't find a spawn point" );
+ }
+
+ VectorCopy (spot->s.origin, origin);
+ origin[2] += 9;
+ VectorCopy (spot->s.angles, angles);
+
+ return spot;
+}
+
+/*
+===========
+SelectInitialSpawnPoint
+
+Try to find a spawn point marked 'initial', otherwise
+use normal spawn selection.
+============
+*/
+gentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles ) {
+ gentity_t *spot;
+
+ spot = NULL;
+ while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
+ if ( spot->spawnflags & 1 ) {
+ break;
+ }
+ }
+
+ if ( !spot || SpotWouldTelefrag( spot ) ) {
+ return SelectSpawnPoint( vec3_origin, origin, angles );
+ }
+
+ VectorCopy (spot->s.origin, origin);
+ origin[2] += 9;
+ VectorCopy (spot->s.angles, angles);
+
+ return spot;
+}
+
+/*
+===========
+SelectSpectatorSpawnPoint
+
+============
+*/
+gentity_t *SelectSpectatorSpawnPoint( vec3_t origin, vec3_t angles ) {
+ //gentity_t *spot;
+
+ FindIntermissionPoint();
+
+ VectorCopy( level.intermission_origin, origin );
+ VectorCopy( level.intermission_angle, angles );
+
+
+
+ //for some reason we need to return an specific point in elimination (this might not be neccecary anymore but to be sure...)
+ //if(g_gametype.integer == GT_ELIMINATION)
+ // return SelectSpawnPoint( vec3_origin, origin, angles );
+
+ //VectorCopy (origin,spot->s.origin);
+ //spot->s.origin[2] += 9;
+ //VectorCopy (angles, spot->s.angles);
+
+ return NULL; //spot;
+}
+
+/*
+=======================================================================
+
+BODYQUE
+
+=======================================================================
+*/
+
+/*
+===============
+InitBodyQue
+===============
+*/
+void InitBodyQue (void) {
+ int i;
+ gentity_t *ent;
+
+ level.bodyQueIndex = 0;
+ for (i=0; i<BODY_QUEUE_SIZE ; i++) {
+ ent = G_Spawn();
+ ent->classname = "bodyque";
+ ent->neverFree = qtrue;
+ level.bodyQue[i] = ent;
+ }
+}
+
+/*
+=============
+BodySink
+
+After sitting around for five seconds, fall into the ground and dissapear
+=============
+*/
+void BodySink( gentity_t *ent ) {
+ if ( level.time - ent->timestamp > 6500 ) {
+
+
+ // the body ques are never actually freed, they are just unlinked
+ trap_UnlinkEntity( ent );
+ ent->physicsObject = qfalse;
+ return;
+ }
+ ent->nextthink = level.time + 100;
+ ent->s.pos.trBase[2] -= 1;
+}
+
+/*
+=============
+CopyToBodyQue
+
+A player is respawning, so make an entity that looks
+just like the existing corpse to leave behind.
+=============
+*/
+void CopyToBodyQue( gentity_t *ent ) {
+ gentity_t *e;
+ int i;
+ gentity_t *body;
+ int contents;
+
+ trap_UnlinkEntity (ent);
+
+ // if client is in a nodrop area, don't leave the body
+ contents = trap_PointContents( ent->s.origin, -1 );
+ if ( (contents & CONTENTS_NODROP) && !(ent->s.eFlags & EF_KAMIKAZE) ) { //the check for kamikaze is a workaround for ctf4ish
+ return;
+ }
+
+ // grab a body que and cycle to the next one
+ body = level.bodyQue[ level.bodyQueIndex ];
+ level.bodyQueIndex = (level.bodyQueIndex + 1) % BODY_QUEUE_SIZE;
+
+ //Check if the next body has the kamikaze, in that case skip it.
+ for(i=0;(level.bodyQue[ level.bodyQueIndex ]->s.eFlags & EF_KAMIKAZE) && (i<10);i++) {
+ level.bodyQueIndex = (level.bodyQueIndex + 1) % BODY_QUEUE_SIZE;
+ }
+
+ body->s = ent->s;
+ body->s.eFlags = EF_DEAD; // clear EF_TALK, etc
+ if ( ent->s.eFlags & EF_KAMIKAZE ) {
+ ent->s.eFlags &= ~EF_KAMIKAZE;
+ body->s.eFlags |= EF_KAMIKAZE;
+
+ // check if there is a kamikaze timer around for this owner
+ for (i = 0; i < MAX_GENTITIES; i++) {
+ e = &g_entities[i];
+ if (!e->inuse)
+ continue;
+ if (e->activator != ent)
+ continue;
+ if (strcmp(e->classname, "kamikaze timer"))
+ continue;
+ e->activator = body;
+ break;
+ }
+ }
+ body->s.powerups = 0; // clear powerups
+ body->s.loopSound = 0; // clear lava burning
+ body->s.number = body - g_entities;
+ body->timestamp = level.time;
+ body->physicsObject = qtrue;
+ body->physicsBounce = 0; // don't bounce
+ if ( body->s.groundEntityNum == ENTITYNUM_NONE ) {
+ body->s.pos.trType = TR_GRAVITY;
+ body->s.pos.trTime = level.time;
+ VectorCopy( ent->client->ps.velocity, body->s.pos.trDelta );
+ } else {
+ body->s.pos.trType = TR_STATIONARY;
+ }
+ body->s.event = 0;
+
+ // change the animation to the last-frame only, so the sequence
+ // doesn't repeat anew for the body
+ switch ( body->s.legsAnim & ~ANIM_TOGGLEBIT ) {
+ case BOTH_DEATH1:
+ case BOTH_DEAD1:
+ body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD1;
+ break;
+ case BOTH_DEATH2:
+ case BOTH_DEAD2:
+ body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD2;
+ break;
+ case BOTH_DEATH3:
+ case BOTH_DEAD3:
+ default:
+ body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD3;
+ break;
+ }
+
+ body->r.svFlags = ent->r.svFlags;
+ VectorCopy (ent->r.mins, body->r.mins);
+ VectorCopy (ent->r.maxs, body->r.maxs);
+ VectorCopy (ent->r.absmin, body->r.absmin);
+ VectorCopy (ent->r.absmax, body->r.absmax);
+
+ body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
+ body->r.contents = CONTENTS_CORPSE;
+ body->r.ownerNum = ent->s.number;
+
+ body->nextthink = level.time + 5000;
+ body->think = BodySink;
+
+ body->die = body_die;
+
+ // don't take more damage if already gibbed
+ if ( ent->health <= GIB_HEALTH ) {
+ body->takedamage = qfalse;
+ } else {
+ body->takedamage = qtrue;
+ }
+
+
+ VectorCopy ( body->s.pos.trBase, body->r.currentOrigin );
+ trap_LinkEntity (body);
+}
+
+//======================================================================
+
+
+/*
+==================
+SetClientViewAngle
+
+==================
+*/
+void SetClientViewAngle( gentity_t *ent, vec3_t angle ) {
+ int i;
+
+ // set the delta angle
+ for (i=0 ; i<3 ; i++) {
+ int cmdAngle;
+
+ cmdAngle = ANGLE2SHORT(angle[i]);
+ ent->client->ps.delta_angles[i] = cmdAngle - ent->client->pers.cmd.angles[i];
+ }
+ VectorCopy( angle, ent->s.angles );
+ VectorCopy (ent->s.angles, ent->client->ps.viewangles);
+}
+
+/*
+================
+respawn
+================
+*/
+void ClientRespawn( gentity_t *ent ) {
+ gentity_t *tent;
+
+ if((g_gametype.integer!=GT_ELIMINATION && g_gametype.integer!=GT_CTF_ELIMINATION && g_gametype.integer !=GT_LMS) && !ent->client->isEliminated)
+ {
+ ent->client->isEliminated = qtrue; //must not be true in warmup
+ //Tried moving CopyToBodyQue
+ } else {
+ //Must always be false in other gametypes
+ ent->client->isEliminated = qfalse;
+ }
+ CopyToBodyQue (ent); //Unlinks ent
+
+ if(g_gametype.integer==GT_LMS) {
+ if(ent->client->pers.livesLeft>0)
+ {
+ //ent->client->pers.livesLeft--; Coutned down somewhere else
+ ent->client->isEliminated = qfalse;
+ }
+ else //We have used all our lives
+ {
+ if( ent->client->isEliminated!=qtrue) {
+ ent->client->isEliminated = qtrue;
+ if((g_lms_mode.integer == 2 || g_lms_mode.integer == 3) && level.roundNumber == level.roundNumberStarted)
+ LMSpoint();
+ //Sago: This is really bad
+ //TODO: Try not to make people spectators here
+ ent->client->sess.spectatorState = PM_SPECTATOR;
+ //We have to force spawn imidiantly to prevent lag.
+ ClientSpawn(ent);
+ }
+ return;
+ }
+ }
+
+ if((g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION || g_gametype.integer==GT_LMS)
+ && ent->client->ps.pm_type == PM_SPECTATOR && ent->client->ps.stats[STAT_HEALTH] > 0)
+ return;
+ ClientSpawn(ent);
+
+ // add a teleportation effect
+ if(g_gametype.integer!=GT_ELIMINATION && g_gametype.integer!=GT_CTF_ELIMINATION && g_gametype.integer!=GT_LMS)
+ {
+ tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );
+ tent->s.clientNum = ent->s.clientNum;
+ }
+}
+
+/*
+================
+respawnRound
+================
+*/
+void respawnRound( gentity_t *ent ) {
+ gentity_t *tent;
+
+ //if(g_gametype.integer!=GT_ELIMINATION || !ent->client->isEliminated)
+ //{
+ // ent->client->isEliminated = qtrue;
+ //CopyToBodyQue (ent);
+ //}
+
+
+ //if(g_gametype.integer==GT_ELIMINATION && ent->client->ps.pm_type == PM_SPECTATOR && ent->client->ps.stats[STAT_HEALTH] > 0)
+ // return;
+ if(ent->client->hook)
+ Weapon_HookFree(ent->client->hook);
+
+ trap_UnlinkEntity (ent);
+
+ ClientSpawn(ent);
+
+ // add a teleportation effect
+ if(g_gametype.integer!=GT_ELIMINATION && g_gametype.integer!=GT_CTF_ELIMINATION && g_gametype.integer!=GT_LMS)
+ {
+ tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );
+ tent->s.clientNum = ent->s.clientNum;
+ }
+}
+
+/*
+================
+TeamCvarSet
+
+Sets the red and blue team client number cvars.
+================
+ */
+void TeamCvarSet( void )
+{
+ int i;
+ qboolean redChanged = qfalse;
+ qboolean blueChanged = qfalse;
+ qboolean first = qtrue;
+ char* temp = NULL;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+ if ( level.clients[i].sess.sessionTeam == TEAM_RED ) {
+ if(first) {
+ temp = va("%i",i);
+ first = qfalse;
+ }
+ else
+ temp = va("%s,%i",temp,i);
+ }
+ }
+
+ if(Q_stricmp(g_redTeamClientNumbers.string,temp))
+ redChanged = qtrue;
+ trap_Cvar_Set("g_redTeamClientNumbers",temp); //Set it right
+ first= qtrue;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+ if ( level.clients[i].sess.sessionTeam == TEAM_BLUE ) {
+ if(first) {
+ temp = va("%i",i);
+ first = qfalse;
+ }
+ else
+ temp = va("%s,%i",temp,i);
+ }
+ }
+ if(Q_stricmp(g_blueTeamClientNumbers.string,temp))
+ blueChanged = qtrue;
+ trap_Cvar_Set("g_blueTeamClientNumbers",temp);
+
+ //Note: We need to force update of the cvar or SendYourTeamMessage will send the old cvar value!
+ if(redChanged) {
+ trap_Cvar_Update(&g_redTeamClientNumbers); //Force update of CVAR
+ SendYourTeamMessageToTeam(TEAM_RED);
+ }
+ if(blueChanged) {
+ trap_Cvar_Update(&g_blueTeamClientNumbers);
+ SendYourTeamMessageToTeam(TEAM_BLUE); //Force update of CVAR
+ }
+}
+
+/*
+================
+TeamCount
+
+Returns number of players on a team
+================
+*/
+team_t TeamCount( int ignoreClientNum, int team ) {
+ int i;
+ int count = 0;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( i == ignoreClientNum ) {
+ continue;
+ }
+ if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+
+ if ( level.clients[i].pers.connected == CON_CONNECTING) {
+ continue;
+ }
+
+ if ( level.clients[i].sess.sessionTeam == team ) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+/*
+================
+TeamLivingCount
+
+Returns number of living players on a team
+================
+*/
+team_t TeamLivingCount( int ignoreClientNum, int team ) {
+ int i;
+ int count = 0;
+ qboolean LMS = (g_gametype.integer==GT_LMS);
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( i == ignoreClientNum ) {
+ continue;
+ }
+ if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+
+ if ( level.clients[i].pers.connected == CON_CONNECTING) {
+ continue;
+ }
+ //crash if g_gametype.integer is used here, why?
+ if ( level.clients[i].sess.sessionTeam == team && (level.clients[i].ps.stats[STAT_HEALTH]>0 || LMS) && !(level.clients[i].isEliminated)) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+/*
+================
+TeamHealthCount
+
+Count total number of healthpoints on teh teams used for draws in Elimination
+================
+*/
+
+team_t TeamHealthCount(int ignoreClientNum, int team ) {
+ int i;
+ int count = 0;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( i == ignoreClientNum ) {
+ continue;
+ }
+ if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+
+ if ( level.clients[i].pers.connected == CON_CONNECTING) {
+ continue;
+ }
+
+ //only count clients with positive health
+ if ( level.clients[i].sess.sessionTeam == team && (level.clients[i].ps.stats[STAT_HEALTH]>0)&& !(level.clients[i].isEliminated)) {
+ count+=level.clients[i].ps.stats[STAT_HEALTH];
+ }
+ }
+
+ return count;
+}
+
+
+/*
+================
+RespawnAll
+
+Forces all clients to respawn.
+================
+*/
+
+void RespawnAll(void)
+{
+ int i;
+ gentity_t *client;
+ for(i=0;i<level.maxclients;i++)
+ {
+ if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+
+ if ( level.clients[i].pers.connected == CON_CONNECTING) {
+ continue;
+ }
+
+ if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR ) {
+ continue;
+ }
+ client = g_entities + i;
+ client->client->ps.pm_type = PM_NORMAL;
+ client->client->pers.livesLeft = g_lms_lives.integer;
+ respawnRound(client);
+ }
+ return;
+}
+
+/*
+================
+RespawnDead
+
+Forces all *DEAD* clients to respawn.
+================
+*/
+
+void RespawnDead(void)
+{
+ int i;
+ gentity_t *client;
+ for(i=0;i<level.maxclients;i++)
+ {
+
+ if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+ if ( level.clients[i].pers.connected == CON_CONNECTING) {
+ continue;
+ }
+ client = g_entities + i;
+ client->client->pers.livesLeft = g_lms_lives.integer-1;
+ if ( level.clients[i].isEliminated == qfalse ){
+ continue;
+ }
+ if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR ) {
+ continue;
+ }
+
+ client->client->pers.livesLeft = g_lms_lives.integer;
+
+ respawnRound(client);
+ }
+ return;
+}
+
+/*
+================
+DisableWeapons
+
+disables all weapons
+================
+*/
+
+void DisableWeapons(void)
+{
+ int i;
+ gentity_t *client;
+ for(i=0;i<level.maxclients;i++)
+ {
+ if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+ if ( level.clients[i].pers.connected == CON_CONNECTING) {
+ continue;
+ }
+
+ if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR ) {
+ continue;
+ }
+ client = g_entities + i;
+ client->client->ps.pm_flags |= PMF_ELIMWARMUP;
+ }
+ ProximityMine_RemoveAll(); //Remove all the prox mines
+ return;
+}
+
+/*
+================
+EnableWeapons
+
+enables all weapons
+================
+*/
+
+void EnableWeapons(void)
+{
+ int i;
+ gentity_t *client;
+ for(i=0;i<level.maxclients;i++)
+ {
+ if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+
+ if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR ) {
+ continue;
+ }
+
+ /*if ( level.clients[i].isEliminated == qtrue ){
+ continue;
+ }*/
+
+ client = g_entities + i;
+ client->client->ps.pm_flags &= ~PMF_ELIMWARMUP;
+ }
+ return;
+}
+
+/*
+================
+LMSpoint
+
+Gives a point to the lucky survivor
+================
+*/
+
+void LMSpoint(void)
+{
+ int i;
+ gentity_t *client;
+ for(i=0;i<level.maxclients;i++)
+ {
+ if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+
+ if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR ) {
+ continue;
+ }
+
+ if ( level.clients[i].isEliminated ){
+ continue;
+ }
+
+ client = g_entities + i;
+ /*
+ Not good in mode 2 & 3
+ if ( client->health <= 0 ){
+ continue;
+ }
+ */
+
+ client->client->ps.persistant[PERS_SCORE] += 1;
+ G_LogPrintf("PlayerScore: %i %i: %s now has %d points\n",
+ i, client->client->ps.persistant[PERS_SCORE], client->client->pers.netname, client->client->ps.persistant[PERS_SCORE] );
+ }
+
+ CalculateRanks();
+ return;
+}
+
+/*
+================
+TeamLeader
+
+Returns the client number of the team leader
+================
+*/
+int TeamLeader( int team ) {
+ int i;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+ if ( level.clients[i].sess.sessionTeam == team ) {
+ if ( level.clients[i].sess.teamLeader )
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+
+/*
+================
+PickTeam
+
+================
+*/
+team_t PickTeam( int ignoreClientNum ) {
+ int counts[TEAM_NUM_TEAMS];
+
+ counts[TEAM_BLUE] = TeamCount( ignoreClientNum, TEAM_BLUE );
+ counts[TEAM_RED] = TeamCount( ignoreClientNum, TEAM_RED );
+
+ //KK-OAX Both Teams locked...forget about it, print an error message, keep as spec
+ if ( level.RedTeamLocked && level.BlueTeamLocked ) {
+ G_Printf( "Both teams have been locked by the Admin! \n" );
+ return TEAM_NONE;
+ }
+ if ( ( counts[TEAM_BLUE] > counts[TEAM_RED] ) && ( !level.RedTeamLocked ) ) {
+ return TEAM_RED;
+ }
+ if ( ( counts[TEAM_RED] > counts[TEAM_BLUE] ) && ( !level.BlueTeamLocked ) ) {
+ return TEAM_BLUE;
+ }
+ // equal team count, so join the team with the lowest score
+ if ( ( level.teamScores[TEAM_BLUE] > level.teamScores[TEAM_RED] ) && ( !level.RedTeamLocked ) ) {
+ return TEAM_RED;
+ }
+ if ( ( level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE] ) && ( !level.BlueTeamLocked ) ) {
+ return TEAM_BLUE;
+ }
+ //KK-OAX Force Team Blue?
+ return TEAM_BLUE;
+}
+
+/*
+===========
+ForceClientSkin
+
+Forces a client's skin (for teamplay)
+===========
+*/
+/*
+static void ForceClientSkin( gclient_t *client, char *model, const char *skin ) {
+ char *p;
+
+ if ((p = strrchr(model, '/')) != 0) {
+ *p = 0;
+ }
+
+ Q_strcat(model, MAX_QPATH, "/");
+ Q_strcat(model, MAX_QPATH, skin);
+}
+*/
+
+/*
+===========
+ClientCheckName
+============
+*/
+static void ClientCleanName(const char *in, char *out, int outSize, int clientNum)
+{
+ int outpos = 0, colorlessLen = 0, spaces = 0, notblack=0;
+ qboolean black = qfalse;
+
+ // discard leading spaces
+ for(; *in == ' '; in++);
+
+ for(; *in && outpos < outSize - 1; in++)
+ {
+ out[outpos] = *in;
+
+ if(*in == ' ')
+ {
+ // don't allow too many consecutive spaces
+ if(spaces > 2)
+ continue;
+
+ spaces++;
+ }
+ else if(outpos > 0 && out[outpos - 1] == Q_COLOR_ESCAPE)
+ {
+ if(Q_IsColorString(&out[outpos - 1]))
+ {
+ colorlessLen--;
+
+ if(ColorIndex(*in) == 0)
+ {
+ // Disallow color black in names to prevent players
+ // from getting advantage playing in front of black backgrounds
+ //outpos--;
+ //continue;
+ black = qtrue;
+ }
+ else
+ black = qfalse;
+ }
+ else
+ {
+ spaces = 0;
+ colorlessLen++;
+ }
+ }
+ else
+ {
+ spaces = 0;
+ colorlessLen++;
+ if(!black && (Q_isalpha(*in) || (*in>='0' && *in<='9') ) )
+ notblack++;
+ }
+
+ outpos++;
+ }
+
+ out[outpos] = '\0';
+
+ //There was none not-black alphanum chars. Remove all colors
+ if(notblack<1)
+ Q_CleanStr(out);
+
+ // don't allow empty names
+ if( *out == '\0' || colorlessLen == 0)
+ Q_strncpyz(out, va("Nameless%i",clientNum), outSize );
+}
+
+
+
+/*
+===========
+ClientUserInfoChanged
+
+Called from ClientConnect when the player first connects and
+directly by the server system when the player updates a userinfo variable.
+
+The game can override any of the settings and call trap_SetUserinfo
+if desired.
+============
+*/
+void ClientUserinfoChanged( int clientNum ) {
+ gentity_t *ent;
+ int teamTask, teamLeader, team, health;
+ char *s;
+ char model[MAX_QPATH];
+ char headModel[MAX_QPATH];
+ char oldname[MAX_STRING_CHARS];
+ //KK-OAX
+ char err[MAX_STRING_CHARS];
+ qboolean revertName = qfalse;
+
+ gclient_t *client;
+ char c1[MAX_INFO_STRING];
+ char c2[MAX_INFO_STRING];
+ char redTeam[MAX_INFO_STRING];
+ char blueTeam[MAX_INFO_STRING];
+ char userinfo[MAX_INFO_STRING];
+
+ ent = g_entities + clientNum;
+ client = ent->client;
+
+ trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
+
+ // check for malformed or illegal info strings
+ if ( !Info_Validate(userinfo) ) {
+ strcpy (userinfo, "\\name\\badinfo");
+ }
+
+ // check for local client
+ s = Info_ValueForKey( userinfo, "ip" );
+ if ( !strcmp( s, "localhost" ) ) {
+ client->pers.localClient = qtrue;
+ }
+
+ // check the item prediction
+ s = Info_ValueForKey( userinfo, "cg_predictItems" );
+ if ( !atoi( s ) ) {
+ client->pers.predictItemPickup = qfalse;
+ } else {
+ client->pers.predictItemPickup = qtrue;
+ }
+
+//unlagged - client options
+ // see if the player has opted out
+ s = Info_ValueForKey( userinfo, "cg_delag" );
+ if ( !atoi( s ) ) {
+ client->pers.delag = 0;
+ } else {
+ client->pers.delag = atoi( s );
+ }
+
+ // see if the player is nudging his shots
+ s = Info_ValueForKey( userinfo, "cg_cmdTimeNudge" );
+ client->pers.cmdTimeNudge = atoi( s );
+
+ // see if the player wants to debug the backward reconciliation
+ /*s = Info_ValueForKey( userinfo, "cg_debugDelag" );
+ if ( !atoi( s ) ) {
+ client->pers.debugDelag = qfalse;
+ }
+ else {
+ client->pers.debugDelag = qtrue;
+ }*/
+
+ // see if the player is simulating incoming latency
+ //s = Info_ValueForKey( userinfo, "cg_latentSnaps" );
+ //client->pers.latentSnaps = atoi( s );
+
+ // see if the player is simulating outgoing latency
+ //s = Info_ValueForKey( userinfo, "cg_latentCmds" );
+ //client->pers.latentCmds = atoi( s );
+
+ // see if the player is simulating outgoing packet loss
+ //s = Info_ValueForKey( userinfo, "cg_plOut" );
+ //client->pers.plOut = atoi( s );
+//unlagged - client options
+
+ // set name
+ Q_strncpyz ( oldname, client->pers.netname, sizeof( oldname ) );
+ s = Info_ValueForKey (userinfo, "name");
+ ClientCleanName( s, client->pers.netname, sizeof(client->pers.netname), clientNum );
+
+ //KK-OAPub Added From Tremulous-Control Name Changes
+ if( strcmp( oldname, client->pers.netname ) )
+ {
+ if( client->pers.nameChangeTime &&
+ ( level.time - client->pers.nameChangeTime )
+ <= ( g_minNameChangePeriod.value * 1000 ) )
+ {
+ trap_SendServerCommand( ent - g_entities, va(
+ "print \"Name change spam protection (g_minNameChangePeriod = %d)\n\"",
+ g_minNameChangePeriod.integer ) );
+ revertName = qtrue;
+ }
+ else if( g_maxNameChanges.integer > 0
+ && client->pers.nameChanges >= g_maxNameChanges.integer )
+ {
+ trap_SendServerCommand( ent - g_entities, va(
+ "print \"Maximum name changes reached (g_maxNameChanges = %d)\n\"",
+ g_maxNameChanges.integer ) );
+ revertName = qtrue;
+ }
+ else if( client->pers.muted )
+ {
+ trap_SendServerCommand( ent - g_entities,
+ "print \"You cannot change your name while you are muted\n\"" );
+ revertName = qtrue;
+ }
+ else if( !G_admin_name_check( ent, client->pers.netname, err, sizeof( err ) ) )
+ {
+ trap_SendServerCommand( ent - g_entities, va( "print \"%s\n\"", err ) );
+ revertName = qtrue;
+ }
+
+ //Never revert a bots name... just to bad if it hapens... but the bot will always be expendeble :-)
+ if (ent->r.svFlags & SVF_BOT)
+ revertName = qfalse;
+
+ if( revertName )
+ {
+ Q_strncpyz( client->pers.netname, *oldname ? oldname : "UnnamedPlayer",
+ sizeof( client->pers.netname ) );
+ Info_SetValueForKey( userinfo, "name", oldname );
+ trap_SetUserinfo( clientNum, userinfo );
+ }
+ else
+ {
+ if( client->pers.connected == CON_CONNECTED )
+ {
+ client->pers.nameChangeTime = level.time;
+ client->pers.nameChanges++;
+ }
+ }
+ }
+ // N_G: this condition makes no sense to me and I'm not going to
+ // try finding out what it means, I've added parentheses according to
+ // evaluation rules of the original code so grab a
+ // parentheses pairing highlighting text editor and see for yourself
+ // if you got it right
+ //Sago: One redundant check and CTF Elim and LMS was missing. Not an important function and I might never have noticed, should properly be ||
+ if ( ( ( client->sess.sessionTeam == TEAM_SPECTATOR ) ||
+ ( ( ( client->isEliminated ) /*||
+ ( client->ps.pm_type == PM_SPECTATOR )*/ ) && //Sago: If this is true client.isEliminated or TEAM_SPECTATOR is true to and this is redundant
+ ( g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS) ) ) &&
+ ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) ) {
+
+ Q_strncpyz( client->pers.netname, "scoreboard", sizeof(client->pers.netname) );
+ }
+
+ if ( client->pers.connected == CON_CONNECTED ) {
+ if ( strcmp( oldname, client->pers.netname ) ) {
+ trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname,
+ client->pers.netname) );
+ }
+ }
+
+ // set max health
+ if (client->ps.powerups[PW_GUARD]) {
+ client->pers.maxHealth = 200;
+ } else {
+ health = atoi( Info_ValueForKey( userinfo, "handicap" ) );
+ client->pers.maxHealth = health;
+ if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) {
+ client->pers.maxHealth = 100;
+ }
+ }
+ client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;
+
+ // set model
+ if( g_gametype.integer >= GT_TEAM && g_ffa_gt==0) {
+ Q_strncpyz( model, Info_ValueForKey (userinfo, "team_model"), sizeof( model ) );
+ Q_strncpyz( headModel, Info_ValueForKey (userinfo, "team_headmodel"), sizeof( headModel ) );
+ } else {
+ Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) );
+ Q_strncpyz( headModel, Info_ValueForKey (userinfo, "headmodel"), sizeof( headModel ) );
+ }
+
+ // bots set their team a few frames later
+ if (g_gametype.integer >= GT_TEAM && g_ffa_gt==0 && g_entities[clientNum].r.svFlags & SVF_BOT) {
+ s = Info_ValueForKey( userinfo, "team" );
+ if ( !Q_stricmp( s, "red" ) || !Q_stricmp( s, "r" ) ) {
+ team = TEAM_RED;
+ } else if ( !Q_stricmp( s, "blue" ) || !Q_stricmp( s, "b" ) ) {
+ team = TEAM_BLUE;
+ } else {
+ // pick the team with the least number of players
+ team = PickTeam( clientNum );
+ }
+ client->sess.sessionTeam = team;
+ }
+ else {
+ team = client->sess.sessionTeam;
+ }
+
+/* NOTE: all client side now
+Sago: I am not happy with this exception
+
+ // team
+ switch( team ) {
+ case TEAM_RED:
+ ForceClientSkin(client, model, "red");
+// ForceClientSkin(client, headModel, "red");
+ break;
+ case TEAM_BLUE:
+ ForceClientSkin(client, model, "blue");
+// ForceClientSkin(client, headModel, "blue");
+ break;
+ }
+ // don't ever use a default skin in teamplay, it would just waste memory
+ // however bots will always join a team but they spawn in as spectator
+ if ( g_gametype.integer >= GT_TEAM && team == TEAM_SPECTATOR) {
+ ForceClientSkin(client, model, "red");
+// ForceClientSkin(client, headModel, "red");
+ }
+*/
+
+ if (g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
+ client->pers.teamInfo = qtrue;
+ } else {
+ s = Info_ValueForKey( userinfo, "teamoverlay" );
+ if ( ! *s || atoi( s ) != 0 ) {
+ client->pers.teamInfo = qtrue;
+ } else {
+ client->pers.teamInfo = qfalse;
+ }
+ }
+ /*
+ s = Info_ValueForKey( userinfo, "cg_pmove_fixed" );
+ if ( !*s || atoi( s ) == 0 ) {
+ client->pers.pmoveFixed = qfalse;
+ }
+ else {
+ client->pers.pmoveFixed = qtrue;
+ }
+ */
+
+ // team task (0 = none, 1 = offence, 2 = defence)
+ teamTask = atoi(Info_ValueForKey(userinfo, "teamtask"));
+ // team Leader (1 = leader, 0 is normal player)
+ teamLeader = client->sess.teamLeader;
+
+ // colors
+ if( g_gametype.integer >= GT_TEAM && g_ffa_gt==0 && g_instantgib.integer) {
+ switch(team) {
+ case TEAM_RED:
+ c1[0] = COLOR_BLUE;
+ c2[0] = COLOR_BLUE;
+ c1[1] = 0;
+ c2[1] = 0;
+ break;
+ case TEAM_BLUE:
+ c1[0] = COLOR_RED;
+ c2[0] = COLOR_RED;
+ c1[1] = 0;
+ c2[1] = 0;
+ break;
+ default:
+ break;
+ }
+ } else {
+ strcpy(c1, Info_ValueForKey( userinfo, "color1" ));
+ strcpy(c2, Info_ValueForKey( userinfo, "color2" ));
+ }
+
+ strcpy(redTeam, Info_ValueForKey( userinfo, "g_redteam" ));
+ strcpy(blueTeam, Info_ValueForKey( userinfo, "g_blueteam" ));
+
+ // send over a subset of the userinfo keys so other clients can
+ // print scoreboards, display models, and play custom sounds
+ if ( ent->r.svFlags & SVF_BOT ) {
+ s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d",
+ client->pers.netname, team, model, headModel, c1, c2,
+ client->pers.maxHealth, client->sess.wins, client->sess.losses,
+ Info_ValueForKey( userinfo, "skill" ), teamTask, teamLeader );
+ } else {
+ s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\g_redteam\\%s\\g_blueteam\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d",
+ client->pers.netname, client->sess.sessionTeam, model, headModel, redTeam, blueTeam, c1, c2,
+ client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader);
+ }
+
+ trap_SetConfigstring( CS_PLAYERS+clientNum, s );
+
+ // this is not the userinfo, more like the configstring actually
+ G_LogPrintf( "ClientUserinfoChanged: %i %s\\id\\%s\n", clientNum, s, Info_ValueForKey(userinfo, "cl_guid") );
+}
+
+
+/*
+===========
+ClientConnect
+
+Called when a player begins connecting to the server.
+Called again for every map change or tournement restart.
+
+The session information will be valid after exit.
+
+Return NULL if the client should be allowed, otherwise return
+a string with the reason for denial.
+
+Otherwise, the client will be sent the current gamestate
+and will eventually get to ClientBegin.
+
+firstTime will be qtrue the very first time a client connects
+to the server machine, but qfalse on map changes and tournement
+restarts.
+============
+*/
+char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) {
+ char *value;
+// char *areabits;
+ gclient_t *client;
+ char userinfo[MAX_INFO_STRING];
+ gentity_t *ent;
+ char reason[ MAX_STRING_CHARS ] = {""};
+ int i;
+
+ //KK-OAX I moved these up so userinfo could be assigned/used.
+ ent = &g_entities[ clientNum ];
+ client = &level.clients[ clientNum ];
+ ent->client = client;
+ memset( client, 0, sizeof(*client) );
+
+ trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
+
+ value = Info_ValueForKey( userinfo, "cl_guid" );
+ Q_strncpyz( client->pers.guid, value, sizeof( client->pers.guid ) );
+
+
+ // IP filtering //KK-OAX Has this been obsoleted?
+ // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=500
+ // recommanding PB based IP / GUID banning, the builtin system is pretty limited
+ // check to see if they are on the banned IP list
+ value = Info_ValueForKey (userinfo, "ip");
+ Q_strncpyz( client->pers.ip, value, sizeof( client->pers.ip ) );
+
+ if ( G_FilterPacket( value ) && !Q_stricmp(value,"localhost") ) {
+ G_Printf("Player with IP: %s is banned\n",value);
+ return "You are banned from this server.";
+ }
+
+ if( G_admin_ban_check( userinfo, reason, sizeof( reason ) ) ) {
+ return va( "%s", reason );
+ }
+
+ //KK-OAX
+ // we don't check GUID or password for bots and local client
+ // NOTE: local client <-> "ip" "localhost"
+ // this means this client is not running in our current process
+ if ( !isBot && (strcmp(value, "localhost") != 0)) {
+ // check for a password
+ value = Info_ValueForKey (userinfo, "password");
+ if ( g_password.string[0] && Q_stricmp( g_password.string, "none" ) &&
+ strcmp( g_password.string, value) != 0) {
+ return "Invalid password";
+ }
+ for( i = 0; i < sizeof( client->pers.guid ) - 1 &&
+ isxdigit( client->pers.guid[ i ] ); i++ );
+ if( i < sizeof( client->pers.guid ) - 1 )
+ return "Invalid GUID";
+
+ for( i = 0; i < level.maxclients; i++ ) {
+
+ if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
+ continue;
+
+ if( !Q_stricmp( client->pers.guid, level.clients[ i ].pers.guid ) ) {
+ if( !G_ClientIsLagging( level.clients + i ) ) {
+ trap_SendServerCommand( i, "cp \"Your GUID is not secure\"" );
+ return "Duplicate GUID";
+ }
+ trap_DropClient( i, "Ghost" );
+ }
+ }
+
+ }
+
+ //Check for local client
+ if( !strcmp( client->pers.ip, "localhost" ) )
+ client->pers.localClient = qtrue;
+ client->pers.adminLevel = G_admin_level( ent );
+
+ client->pers.connected = CON_CONNECTING;
+
+ // read or initialize the session data
+ if ( firstTime || level.newSession ) {
+ G_InitSessionData( client, userinfo );
+ }
+ G_ReadSessionData( client );
+
+ if( isBot ) {
+ ent->r.svFlags |= SVF_BOT;
+ ent->inuse = qtrue;
+ if( !G_BotConnect( clientNum, !firstTime ) ) {
+ return "BotConnectfailed";
+ }
+ }
+
+ //KK-OAX Swapped these in order...seemed to help the connection process.
+ // get and distribute relevent paramters
+ ClientUserinfoChanged( clientNum );
+ G_LogPrintf( "ClientConnect: %i\n", clientNum );
+
+
+ // don't do the "xxx connected" messages if they were caried over from previous level
+ if ( firstTime ) {
+ trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname) );
+ }
+
+ if ( g_gametype.integer >= GT_TEAM &&
+ client->sess.sessionTeam != TEAM_SPECTATOR ) {
+ BroadcastTeamChange( client, -1 );
+ }
+
+ // count current clients and rank for scoreboard
+ CalculateRanks();
+
+ // for statistics
+// client->areabits = areabits;
+// if ( !client->areabits )
+// client->areabits = G_Alloc( (trap_AAS_PointReachabilityAreaIndex( NULL ) + 7) / 8 );
+
+//Sago: Changed the message
+//unlagged - backward reconciliation #5
+ // announce it
+ if ( g_delagHitscan.integer ) {
+ trap_SendServerCommand( clientNum, "print \"Full lag compensation is ON!\n\"" );
+ }
+ else {
+ trap_SendServerCommand( clientNum, "print \"Full lag compensation is OFF!\n\"" );
+ }
+
+//unlagged - backward reconciliation #5
+ G_admin_namelog_update( client, qfalse );
+ return NULL;
+}
+
+void motd (gentity_t *ent)
+{
+ char motd[1024];
+ fileHandle_t motdFile;
+ int motdLen;
+ int fileLen;
+
+ strcpy (motd, "cp \"");
+ fileLen = trap_FS_FOpenFile(g_motdfile.string, &motdFile, FS_READ);
+ if(motdFile)
+ {
+ char * p;
+
+ motdLen = strlen(motd);
+ if((motdLen + fileLen) > (sizeof(motd) - 2))
+ fileLen = (sizeof(motd) - 2 - motdLen);
+ trap_FS_Read(motd + motdLen, fileLen, motdFile);
+ motd[motdLen + fileLen] = '"';
+ motd[motdLen + fileLen + 1] = 0;
+ trap_FS_FCloseFile(motdFile);
+
+ while((p = strchr(motd, '\r'))) //Remove carrier return. 0x0D
+ memmove(p, p + 1, motdLen + fileLen - (p - motd));
+ }
+ trap_SendServerCommand(ent - g_entities, motd);
+}
+
+/*
+===========
+ClientBegin
+
+called when a client has finished connecting, and is ready
+to be placed into the level. This will happen every level load,
+and on transition between teams, but doesn't happen on respawns
+============
+*/
+void ClientBegin( int clientNum ) {
+ gentity_t *ent;
+ gclient_t *client;
+ gentity_t *tent;
+ int flags;
+ int countRed, countBlue, countFree;
+ char userinfo[MAX_INFO_STRING];
+
+ trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
+
+ ent = g_entities + clientNum;
+
+ client = level.clients + clientNum;
+
+ if ( ent->r.linked ) {
+ trap_UnlinkEntity( ent );
+ }
+ G_InitGentity( ent );
+ ent->touch = 0;
+ ent->pain = 0;
+ ent->client = client;
+
+ client->pers.connected = CON_CONNECTED;
+ client->pers.enterTime = level.time;
+ client->pers.teamState.state = TEAM_BEGIN;
+
+ //Elimination:
+ client->pers.roundReached = 0; //We will spawn in next round
+ if(g_gametype.integer == GT_LMS) {
+ client->isEliminated = qtrue; //So player does not give a point in gamemode 2 and 3
+ //trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " will start dead\n\"", client->pers.netname) );
+ }
+
+ //player is a bot:
+ if( ent->r.svFlags & SVF_BOT )
+ {
+ if(!level.hadBots)
+ {
+ G_LogPrintf( "Info: There has been at least 1 bot now\n" );
+ level.hadBots = qtrue;
+ }
+ }
+
+ //Count smallest team
+ countFree = TeamCount(-1,TEAM_FREE);
+ countRed = TeamCount(-1,TEAM_RED);
+ countBlue = TeamCount(-1,TEAM_BLUE);
+ if(g_gametype.integer < GT_TEAM || g_ffa_gt)
+ {
+ if(countFree>level.teamSize)
+ level.teamSize=countFree;
+ }
+ else
+ if(countRed>countBlue)
+ {
+ if(countBlue>level.teamSize)
+ level.teamSize=countBlue;
+ }
+ else
+ {
+ if(countRed>level.teamSize)
+ level.teamSize=countRed;
+ }
+
+ // save eflags around this, because changing teams will
+ // cause this to happen with a valid entity, and we
+ // want to make sure the teleport bit is set right
+ // so the viewpoint doesn't interpolate through the
+ // world to the new position
+ flags = client->ps.eFlags;
+ memset( &client->ps, 0, sizeof( client->ps ) );
+ if( client->sess.sessionTeam != TEAM_SPECTATOR )
+ PlayerStore_restore(Info_ValueForKey(userinfo,"cl_guid"),&(client->ps));
+ client->ps.eFlags = flags;
+
+ // locate ent at a spawn point
+ ClientSpawn( ent );
+
+ if( ( client->sess.sessionTeam != TEAM_SPECTATOR ) &&
+ ( ( !( client->isEliminated ) /*&&
+ ( ( !client->ps.pm_type ) == PM_SPECTATOR ) */ ) || //Sago: Yes, it made no sense
+ ( ( g_gametype.integer != GT_ELIMINATION || level.intermissiontime) &&
+ ( g_gametype.integer != GT_CTF_ELIMINATION || level.intermissiontime) &&
+ ( g_gametype.integer != GT_LMS || level.intermissiontime ) ) ) ) {
+ // send event
+ tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );
+ tent->s.clientNum = ent->s.clientNum;
+
+ if ( g_gametype.integer != GT_TOURNAMENT ) {
+ trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname) );
+ }
+ }
+
+ motd ( ent );
+
+ G_LogPrintf( "ClientBegin: %i\n", clientNum );
+
+ //Send domination point names:
+ if(g_gametype.integer == GT_DOMINATION) {
+ DominationPointNamesMessage(ent);
+ DominationPointStatusMessage(ent);
+ }
+
+ TeamCvarSet();
+
+ // count current clients and rank for scoreboard
+ CalculateRanks();
+
+ //Send the list of custom vote options:
+ if(strlen(custom_vote_info))
+ SendCustomVoteCommands(clientNum);
+}
+
+/*
+===========
+ClientSpawn
+
+Called every time a client is placed fresh in the world:
+after the first ClientBegin, and after each respawn
+Initializes all non-persistant parts of playerState
+============
+*/
+void ClientSpawn(gentity_t *ent) {
+ int index;
+ vec3_t spawn_origin, spawn_angles;
+ gclient_t *client;
+ int i;
+ clientPersistant_t saved;
+ clientSession_t savedSess;
+ int persistant[MAX_PERSISTANT];
+ gentity_t *spawnPoint;
+ //gentity_t *tent;
+ int flags;
+ int savedPing;
+// char *savedAreaBits;
+ int accuracy_hits, accuracy_shots,vote;
+ int accuracy[WP_NUM_WEAPONS][2];
+ int eventSequence;
+ char userinfo[MAX_INFO_STRING];
+
+ index = ent - g_entities;
+ client = ent->client;
+
+ //In Elimination the player should not spawn if he have already spawned in the round (but not for spectators)
+ // N_G: You've obviously wanted something ELSE
+ //Sago: Yes, the !level.intermissiontime is currently redundant but it might still be the bast place to make the test, CheckElimination in g_main makes sure the next if will fail and the rest of the things this block does might not affect if in Intermission (I'll just test that)
+ if(
+ (
+ (
+ g_gametype.integer == GT_ELIMINATION ||
+ g_gametype.integer == GT_CTF_ELIMINATION || (g_gametype.integer == GT_LMS && client->isEliminated)) &&
+ (!level.intermissiontime || level.warmupTime != 0)
+ ) &&
+ ( client->sess.sessionTeam != TEAM_SPECTATOR )
+ )
+ {
+ // N_G: Another condition that makes no sense to me, see for
+ // yourself if you really meant this
+ // Sago: I beleive the TeamCount is to make sure people can join even if the game can't start
+ if( ( level.roundNumber == level.roundNumberStarted ) ||
+ ( (level.time < level.roundStartTime - g_elimination_activewarmup.integer*1000 ) &&
+ TeamCount( -1, TEAM_BLUE ) &&
+ TeamCount( -1, TEAM_RED ) ) )
+ {
+ client->sess.spectatorState = SPECTATOR_FREE;
+ client->isEliminated = qtrue;
+ if(g_gametype.integer == GT_LMS)
+ G_LogPrintf( "LMS: %i %i %i: Player \"%s^7\" eliminated!\n", level.roundNumber, index, 1, client->pers.netname );
+ client->ps.pm_type = PM_SPECTATOR;
+ CalculateRanks();
+ return;
+ }
+ else
+ {
+ client->pers.roundReached = level.roundNumber+1;
+ client->sess.spectatorState = SPECTATOR_NOT;
+ client->ps.pm_type = PM_NORMAL;
+ client->isEliminated = qfalse;
+ CalculateRanks();
+ }
+ } else {
+ //Force false.
+ if(client->isEliminated) {
+ client->isEliminated = qfalse;
+ CalculateRanks();
+ }
+ }
+
+ if(g_gametype.integer == GT_LMS && client->sess.sessionTeam != TEAM_SPECTATOR && (!level.intermissiontime || level.warmupTime != 0))
+ {
+ if(level.roundNumber==level.roundNumberStarted /*|| level.time<level.roundStartTime-g_elimination_activewarmup.integer*1000*/ && 1>client->pers.livesLeft)
+ {
+ client->sess.spectatorState = SPECTATOR_FREE;
+ if( ent->client->isEliminated!=qtrue) {
+ client->isEliminated = qtrue;
+ if((g_lms_mode.integer == 2 || g_lms_mode.integer == 3) && level.roundNumber == level.roundNumberStarted)
+ LMSpoint();
+ G_LogPrintf( "LMS: %i %i %i: Player \"%s^7\" eliminated!\n", level.roundNumber, index, 1, client->pers.netname );
+ }
+ client->ps.pm_type = PM_SPECTATOR;
+ return;
+ }
+
+ client->sess.spectatorState = SPECTATOR_NOT;
+ client->ps.pm_type = PM_NORMAL;
+ client->isEliminated = qfalse;
+ if(client->pers.livesLeft>0)
+ client->pers.livesLeft--;
+ }
+
+ // find a spawn point
+ // do it before setting health back up, so farthest
+ // ranging doesn't count this client
+ if ((client->sess.sessionTeam == TEAM_SPECTATOR)
+ || ( (client->ps.pm_type == PM_SPECTATOR || client->isEliminated ) && (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) ) ) {
+ spawnPoint = SelectSpectatorSpawnPoint ( spawn_origin, spawn_angles);
+ } else if (g_gametype.integer == GT_DOUBLE_D) {
+ //Double Domination uses special spawn points:
+ spawnPoint = SelectDoubleDominationSpawnPoint (client->sess.sessionTeam, spawn_origin, spawn_angles);
+ } else if (g_gametype.integer >= GT_CTF && g_ffa_gt==0 && g_gametype.integer!= GT_DOMINATION) {
+ // all base oriented team games use the CTF spawn points
+ spawnPoint = SelectCTFSpawnPoint (
+ client->sess.sessionTeam,
+ client->pers.teamState.state,
+ spawn_origin, spawn_angles);
+ } else {
+ do {
+ // the first spawn should be at a good looking spot
+ if ( !client->pers.initialSpawn && client->pers.localClient ) {
+ client->pers.initialSpawn = qtrue;
+ spawnPoint = SelectInitialSpawnPoint( spawn_origin, spawn_angles );
+ } else {
+ // don't spawn near existing origin if possible
+ spawnPoint = SelectSpawnPoint (
+ client->ps.origin,
+ spawn_origin, spawn_angles);
+ }
+
+ // Tim needs to prevent bots from spawning at the initial point
+ // on q3dm0...
+ if ( ( spawnPoint->flags & FL_NO_BOTS ) && ( ent->r.svFlags & SVF_BOT ) ) {
+ //Sago: The game has a tendency to select the furtest spawn point
+ //This is a problem if the fursest spawnpoint keeps being NO_BOTS and it does!
+ //This is a hot fix that seeks a spawn point faraway from the the currently found one
+ vec3_t old_origin;
+ VectorCopy(spawn_origin,old_origin);
+ spawnPoint = SelectSpawnPoint (old_origin, spawn_origin, spawn_angles);
+ if ( ( spawnPoint->flags & FL_NO_BOTS ) && ( ent->r.svFlags & SVF_BOT ) ) {
+ continue; // try again
+ }
+ }
+ // just to be symetric, we have a nohumans option...
+ if ( ( spawnPoint->flags & FL_NO_HUMANS ) && !( ent->r.svFlags & SVF_BOT ) ) {
+ continue; // try again
+ }
+
+ break;
+
+ } while ( 1 );
+ }
+ client->pers.teamState.state = TEAM_ACTIVE;
+
+ // always clear the kamikaze flag
+ ent->s.eFlags &= ~EF_KAMIKAZE;
+
+ // toggle the teleport bit so the client knows to not lerp
+ // and never clear the voted flag
+ flags = ent->client->ps.eFlags & (EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED);
+ flags ^= EF_TELEPORT_BIT;
+
+//unlagged - backward reconciliation #3
+ // we don't want players being backward-reconciled to the place they died
+ G_ResetHistory( ent );
+ // and this is as good a time as any to clear the saved state
+ ent->client->saved.leveltime = 0;
+//unlagged - backward reconciliation #3
+
+ // clear everything but the persistant data
+
+ saved = client->pers;
+ savedSess = client->sess;
+ savedPing = client->ps.ping;
+ vote = client->vote;
+// savedAreaBits = client->areabits;
+ accuracy_hits = client->accuracy_hits;
+ accuracy_shots = client->accuracy_shots;
+ memcpy(accuracy,client->accuracy,sizeof(accuracy));
+
+ memcpy(persistant,client->ps.persistant,MAX_PERSISTANT*sizeof(int));
+ eventSequence = client->ps.eventSequence;
+
+ Com_Memset (client, 0, sizeof(*client));
+
+ client->pers = saved;
+ client->sess = savedSess;
+ client->ps.ping = savedPing;
+ client->vote = vote;
+// client->areabits = savedAreaBits;
+ client->accuracy_hits = accuracy_hits;
+ client->accuracy_shots = accuracy_shots;
+ for( i = 0 ; i < WP_NUM_WEAPONS ; i++ ){
+ client->accuracy[i][0] = accuracy[i][0];
+ client->accuracy[i][1] = accuracy[i][1];
+ }
+
+ client->lastkilled_client = -1;
+
+ for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) {
+ client->ps.persistant[i] = persistant[i];
+ }
+ client->ps.eventSequence = eventSequence;
+ // increment the spawncount so the client will detect the respawn
+ client->ps.persistant[PERS_SPAWN_COUNT]++;
+ client->ps.persistant[PERS_TEAM] = client->sess.sessionTeam;
+
+ client->airOutTime = level.time + 12000;
+
+ trap_GetUserinfo( index, userinfo, sizeof(userinfo) );
+ // set max health
+ client->pers.maxHealth = atoi( Info_ValueForKey( userinfo, "handicap" ) );
+ if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) {
+ client->pers.maxHealth = 100;
+ }
+ // clear entity values
+ client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;
+ client->ps.eFlags = flags;
+
+ ent->s.groundEntityNum = ENTITYNUM_NONE;
+ ent->client = &level.clients[index];
+ ent->takedamage = qtrue;
+ ent->inuse = qtrue;
+ ent->classname = "player";
+ ent->r.contents = CONTENTS_BODY;
+ ent->clipmask = MASK_PLAYERSOLID;
+ ent->die = player_die;
+ ent->waterlevel = 0;
+ ent->watertype = 0;
+ ent->flags = 0;
+
+ //Sago: No one has hit the client yet!
+ client->lastSentFlying = -1;
+
+ VectorCopy (playerMins, ent->r.mins);
+ VectorCopy (playerMaxs, ent->r.maxs);
+
+ client->ps.clientNum = index;
+
+if(g_gametype.integer != GT_ELIMINATION && g_gametype.integer != GT_CTF_ELIMINATION && g_gametype.integer != GT_LMS && !g_elimination_allgametypes.integer)
+{
+ client->ps.stats[STAT_WEAPONS] = ( 1 << WP_MACHINEGUN );
+ if ( g_gametype.integer == GT_TEAM ) {
+ client->ps.ammo[WP_MACHINEGUN] = 50;
+ } else {
+ client->ps.ammo[WP_MACHINEGUN] = 100;
+ }
+
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GAUNTLET );
+ client->ps.ammo[WP_GAUNTLET] = -1;
+ client->ps.ammo[WP_GRAPPLING_HOOK] = -1;
+
+ // health will count down towards max_health
+ ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] + 25;
+}
+else
+{
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GAUNTLET );
+ client->ps.ammo[WP_GAUNTLET] = -1;
+ client->ps.ammo[WP_GRAPPLING_HOOK] = -1;
+ if (g_elimination_machinegun.integer > 0) {
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_MACHINEGUN );
+ client->ps.ammo[WP_MACHINEGUN] = g_elimination_machinegun.integer;
+ }
+ if (g_elimination_shotgun.integer > 0) {
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_SHOTGUN );
+ client->ps.ammo[WP_SHOTGUN] = g_elimination_shotgun.integer;
+ }
+ if (g_elimination_grenade.integer > 0) {
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GRENADE_LAUNCHER );
+ client->ps.ammo[WP_GRENADE_LAUNCHER] = g_elimination_grenade.integer;
+ }
+ if (g_elimination_rocket.integer > 0) {
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_ROCKET_LAUNCHER );
+ client->ps.ammo[WP_ROCKET_LAUNCHER] = g_elimination_rocket.integer;
+ }
+ if (g_elimination_lightning.integer > 0) {
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_LIGHTNING );
+ client->ps.ammo[WP_LIGHTNING] = g_elimination_lightning.integer;
+ }
+ if (g_elimination_railgun.integer > 0) {
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_RAILGUN );
+ client->ps.ammo[WP_RAILGUN] = g_elimination_railgun.integer;
+ }
+ if (g_elimination_plasmagun.integer > 0) {
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_PLASMAGUN );
+ client->ps.ammo[WP_PLASMAGUN] = g_elimination_plasmagun.integer;
+ }
+ if (g_elimination_bfg.integer > 0) {
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BFG );
+ client->ps.ammo[WP_BFG] = g_elimination_bfg.integer;
+ }
+ if (g_elimination_grapple.integer) {
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GRAPPLING_HOOK );
+ }
+ if (g_elimination_nail.integer > 0) {
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_NAILGUN );
+ client->ps.ammo[WP_NAILGUN] = g_elimination_nail.integer;
+ }
+ if (g_elimination_mine.integer > 0) {
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_PROX_LAUNCHER );
+ client->ps.ammo[WP_PROX_LAUNCHER] = g_elimination_mine.integer;
+ }
+ if (g_elimination_chain.integer > 0) {
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_CHAINGUN );
+ client->ps.ammo[WP_CHAINGUN] = g_elimination_chain.integer;
+ }
+
+ ent->health = client->ps.stats[STAT_ARMOR] = g_elimination_startArmor.integer; //client->ps.stats[STAT_MAX_HEALTH]*2;
+ ent->health = client->ps.stats[STAT_HEALTH] = g_elimination_startHealth.integer; //client->ps.stats[STAT_MAX_HEALTH]*2;
+
+
+ // ent->health = client->ps.stats[STAT_HEALTH] = 0;
+}
+ //Instantgib mode, replace weapons with rail (and maybe gauntlet)
+ if(g_instantgib.integer)
+ {
+ client->ps.stats[STAT_WEAPONS] = ( 1 << WP_RAILGUN );
+ client->ps.ammo[WP_RAILGUN] = 999; //Don't display any ammo
+ if(g_instantgib.integer>1)
+ {
+ client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GAUNTLET );
+ client->ps.ammo[WP_GAUNTLET] = -1;
+ }
+ }
+
+ //nexuiz style rocket arena (rocket launcher only)
+ if(g_rockets.integer)
+ {
+ client->ps.stats[STAT_WEAPONS] = ( 1 << WP_ROCKET_LAUNCHER );
+ client->ps.ammo[WP_ROCKET_LAUNCHER] = 999;
+ }
+
+ G_SetOrigin( ent, spawn_origin );
+ VectorCopy( spawn_origin, client->ps.origin );
+
+ // the respawned flag will be cleared after the attack and jump keys come up
+ client->ps.pm_flags |= PMF_RESPAWNED;
+ if(g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION || g_gametype.integer==GT_LMS)
+ client->ps.pm_flags |= PMF_ELIMWARMUP;
+
+ trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd );
+ SetClientViewAngle( ent, spawn_angles );
+
+ if ( (ent->client->sess.sessionTeam == TEAM_SPECTATOR) || ((client->ps.pm_type == PM_SPECTATOR || client->isEliminated) &&
+ (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS) ) ) {
+ //Sago: Lets see if this fixes the bots only bug - loose all point on dead bug. (It didn't)
+ /*if(g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS) {
+ G_KillBox( ent );
+ trap_LinkEntity (ent);
+ }*/
+ } else {
+ G_KillBox( ent );
+ trap_LinkEntity (ent);
+
+ // force the base weapon up
+ client->ps.weapon = WP_MACHINEGUN;
+ client->ps.weaponstate = WEAPON_READY;
+
+ }
+
+ // don't allow full run speed for a bit
+ client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
+ client->ps.pm_time = 100;
+
+ client->respawnTime = level.time;
+ client->inactivityTime = level.time + g_inactivity.integer * 1000;
+ client->latched_buttons = 0;
+
+ // set default animations
+ client->ps.torsoAnim = TORSO_STAND;
+ client->ps.legsAnim = LEGS_IDLE;
+
+ if ( level.intermissiontime ) {
+ MoveClientToIntermission( ent );
+ } else {
+ // fire the targets of the spawn point
+ G_UseTargets( spawnPoint, ent );
+
+ // select the highest weapon number available, after any
+ // spawn given items have fired
+ client->ps.weapon = 1;
+ for ( i = WP_NUM_WEAPONS - 1 ; i > 0 ; i-- ) {
+ if ( client->ps.stats[STAT_WEAPONS] & ( 1 << i ) && i !=WP_GRAPPLING_HOOK ) {
+ client->ps.weapon = i;
+ break;
+ }
+ }
+ }
+
+ // run a client frame to drop exactly to the floor,
+ // initialize animations and other things
+ client->ps.commandTime = level.time - 100;
+ ent->client->pers.cmd.serverTime = level.time;
+ ClientThink( ent-g_entities );
+
+ // positively link the client, even if the command times are weird
+ if ( (ent->client->sess.sessionTeam != TEAM_SPECTATOR) || ( (!client->isEliminated || client->ps.pm_type != PM_SPECTATOR)&&
+ (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS) ) ) {
+ BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
+ VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
+ trap_LinkEntity( ent );
+ }
+
+ // run the presend to set anything else
+ ClientEndFrame( ent );
+
+ // clear entity state values
+ BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
+
+ if(g_spawnprotect.integer)
+ client->spawnprotected = qtrue;
+
+ RespawnTimeMessage(ent,0);
+}
+
+
+/*
+===========
+ClientDisconnect
+
+Called when a player drops from the server.
+Will not be called between levels.
+
+This should NOT be called directly by any game logic,
+call trap_DropClient(), which will call this and do
+server system housekeeping.
+============
+*/
+void ClientDisconnect( int clientNum ) {
+ gentity_t *ent;
+ int i;
+ char userinfo[MAX_INFO_STRING];
+
+ // cleanup if we are kicking a bot that
+ // hasn't spawned yet
+ G_RemoveQueuedBotBegin( clientNum );
+
+ ent = g_entities + clientNum;
+ if ( !ent->client ) {
+ return;
+ }
+
+ ClientLeaving( clientNum);
+ //KK-OAX Admin
+ G_admin_namelog_update( ent->client, qtrue );
+
+ trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
+
+ // stop any following clients
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( (level.clients[i].sess.sessionTeam == TEAM_SPECTATOR || level.clients[i].ps.pm_type == PM_SPECTATOR)
+ && level.clients[i].sess.spectatorState == SPECTATOR_FOLLOW
+ && level.clients[i].sess.spectatorClient == clientNum ) {
+ StopFollowing( &g_entities[i] );
+ }
+ }
+
+ // send effect if they were completely connected
+ /*
+ *Sago: I have removed this. A little dangerous but I make him suicide in a moment.
+ */
+ /*if ( ent->client->pers.connected == CON_CONNECTED
+ && ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
+ tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
+ tent->s.clientNum = ent->s.clientNum;
+
+ // They don't get to take powerups with them!
+ // Especially important for stuff like CTF flags
+ TossClientItems( ent );
+ TossClientPersistantPowerups( ent );
+ if( g_gametype.integer == GT_HARVESTER ) {
+ TossClientCubes( ent );
+ }
+//#endif
+
+ }*/
+
+ //Is the player alive?
+ i = (ent->client->ps.stats[STAT_HEALTH]>0);
+ //Commit suicide!
+ if ( ent->client->pers.connected == CON_CONNECTED
+ && ent->client->sess.sessionTeam != TEAM_SPECTATOR && i ) {
+ //Prevent a team from loosing point because of player leaving
+ int teamscore = 0;
+ if(g_gametype.integer == GT_TEAM)
+ teamscore = level.teamScores[ ent->client->sess.sessionTeam ];
+ // Kill him (makes sure he loses flags, etc)
+ ent->flags &= ~FL_GODMODE;
+ ent->client->ps.stats[STAT_HEALTH] = ent->health = 0;
+ player_die (ent, ent, g_entities + ENTITYNUM_WORLD, 100000, MOD_SUICIDE);
+ if(g_gametype.integer == GT_TEAM)
+ level.teamScores[ ent->client->sess.sessionTeam ] = teamscore;
+ }
+
+
+
+ if ( ent->client->pers.connected == CON_CONNECTED && ent->client->sess.sessionTeam != TEAM_SPECTATOR)
+ PlayerStore_store(Info_ValueForKey(userinfo,"cl_guid"),ent->client->ps);
+
+ G_LogPrintf( "ClientDisconnect: %i\n", clientNum );
+
+ // if we are playing in tourney mode and losing, give a win to the other player
+ if ( (g_gametype.integer == GT_TOURNAMENT )
+ && !level.intermissiontime
+ && !level.warmupTime && level.sortedClients[1] == clientNum ) {
+ level.clients[ level.sortedClients[0] ].sess.wins++;
+ ClientUserinfoChanged( level.sortedClients[0] );
+ }
+
+ if( g_gametype.integer == GT_TOURNAMENT &&
+ ent->client->sess.sessionTeam == TEAM_FREE &&
+ level.intermissiontime ) {
+
+ trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
+ level.restarted = qtrue;
+ level.changemap = NULL;
+ level.intermissiontime = 0;
+ }
+
+ trap_UnlinkEntity (ent);
+ ent->s.modelindex = 0;
+ ent->inuse = qfalse;
+ ent->classname = "disconnected";
+ ent->client->pers.connected = CON_DISCONNECTED;
+ ent->client->ps.persistant[PERS_TEAM] = TEAM_FREE;
+ ent->client->sess.sessionTeam = TEAM_FREE;
+
+ trap_SetConfigstring( CS_PLAYERS + clientNum, "");
+
+ CalculateRanks();
+ CountVotes();
+
+ if ( ent->r.svFlags & SVF_BOT ) {
+ BotAIShutdownClient( clientNum, qfalse );
+ }
+}
+
+
diff --git a/code/game/g_cmds.c b/code/game/g_cmds.c
new file mode 100644
index 0000000..3a14e51
--- /dev/null
+++ b/code/game/g_cmds.c
@@ -0,0 +1,2312 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#include "g_local.h"
+
+#include "../../ui/menudef.h" // for the voice chats
+
+/*
+==================
+DeathmatchScoreboardMessage
+
+==================
+*/
+void DeathmatchScoreboardMessage( gentity_t *ent ) {
+ char entry[1024];
+ char string[1400];
+ int stringlength;
+ int i, j;
+ gclient_t *cl;
+ int numSorted, scoreFlags, accuracy, perfect;
+
+ // send the latest information on all clients
+ string[0] = 0;
+ stringlength = 0;
+ scoreFlags = 0;
+
+ numSorted = level.numConnectedClients;
+
+ for (i=0 ; i < numSorted ; i++) {
+ int ping;
+
+ cl = &level.clients[level.sortedClients[i]];
+
+ if ( cl->pers.connected == CON_CONNECTING ) {
+ ping = -1;
+ } else {
+//unlagged - true ping
+ //ping = cl->ps.ping < 999 ? cl->ps.ping : 999;
+ ping = cl->pers.realPing < 999 ? cl->pers.realPing : 999;
+//unlagged - true ping
+ }
+
+ if( cl->accuracy_shots ) {
+ accuracy = cl->accuracy_hits * 100 / cl->accuracy_shots;
+ }
+ else {
+ accuracy = 0;
+ }
+ perfect = ( cl->ps.persistant[PERS_RANK] == 0 && cl->ps.persistant[PERS_KILLED] == 0 ) ? 1 : 0;
+
+ if(g_gametype.integer == GT_LMS) {
+ Com_sprintf (entry, sizeof(entry),
+ " %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i", level.sortedClients[i],
+ cl->ps.persistant[PERS_SCORE], ping, (level.time - cl->pers.enterTime)/60000,
+ scoreFlags, g_entities[level.sortedClients[i]].s.powerups, accuracy,
+ cl->ps.persistant[PERS_IMPRESSIVE_COUNT],
+ cl->ps.persistant[PERS_EXCELLENT_COUNT],
+ cl->ps.persistant[PERS_GAUNTLET_FRAG_COUNT],
+ cl->ps.persistant[PERS_DEFEND_COUNT],
+ cl->ps.persistant[PERS_ASSIST_COUNT],
+ perfect,
+ cl->ps.persistant[PERS_CAPTURES],
+ cl->pers.livesLeft + (cl->isEliminated?0:1));
+ }
+ else {
+ Com_sprintf (entry, sizeof(entry),
+ " %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i", level.sortedClients[i],
+ cl->ps.persistant[PERS_SCORE], ping, (level.time - cl->pers.enterTime)/60000,
+ scoreFlags, g_entities[level.sortedClients[i]].s.powerups, accuracy,
+ cl->ps.persistant[PERS_IMPRESSIVE_COUNT],
+ cl->ps.persistant[PERS_EXCELLENT_COUNT],
+ cl->ps.persistant[PERS_GAUNTLET_FRAG_COUNT],
+ cl->ps.persistant[PERS_DEFEND_COUNT],
+ cl->ps.persistant[PERS_ASSIST_COUNT],
+ perfect,
+ cl->ps.persistant[PERS_CAPTURES],
+ cl->isEliminated);
+ }
+ j = strlen(entry);
+ if (stringlength + j > 1024)
+ break;
+ strcpy (string + stringlength, entry);
+ stringlength += j;
+ }
+
+ trap_SendServerCommand( ent-g_entities, va("scores %i %i %i %i%s", i,
+ level.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE], level.roundStartTime,
+ string ) );
+}
+
+/*
+==================
+AccMessage
+
+==================
+*/
+void AccMessage( gentity_t *ent ) {
+ char entry[1024];
+
+ Com_sprintf (entry, sizeof(entry),
+ " %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i ",
+ ent->client->accuracy[WP_MACHINEGUN][0], ent->client->accuracy[WP_MACHINEGUN][1],
+ ent->client->accuracy[WP_SHOTGUN][0], ent->client->accuracy[WP_SHOTGUN][1],
+ ent->client->accuracy[WP_GRENADE_LAUNCHER][0], ent->client->accuracy[WP_GRENADE_LAUNCHER][1],
+ ent->client->accuracy[WP_ROCKET_LAUNCHER][0], ent->client->accuracy[WP_ROCKET_LAUNCHER][1],
+ ent->client->accuracy[WP_LIGHTNING][0], ent->client->accuracy[WP_LIGHTNING][1],
+ ent->client->accuracy[WP_RAILGUN][0], ent->client->accuracy[WP_RAILGUN][1],
+ ent->client->accuracy[WP_PLASMAGUN][0], ent->client->accuracy[WP_PLASMAGUN][1],
+ ent->client->accuracy[WP_BFG][0], ent->client->accuracy[WP_BFG][1],
+ 0,0, //Hook
+ ent->client->accuracy[WP_NAILGUN][0], ent->client->accuracy[WP_NAILGUN][1],
+ 0,0,
+ ent->client->accuracy[WP_CHAINGUN][0], ent->client->accuracy[WP_CHAINGUN][1]
+ );
+
+ trap_SendServerCommand( ent-g_entities, va("accs%s", entry ));
+}
+
+
+/*
+==================
+DominationPointStatusMessage
+
+==================
+*/
+void DominationPointStatusMessage( gentity_t *ent ) {
+ char entry[10]; //Will more likely be 2... in fact cannot be more since we are the server
+ char string[10*(MAX_DOMINATION_POINTS+1)];
+ int stringlength;
+ int i, j;
+
+ string[0] = 0;
+ stringlength = 0;
+
+ for(i = 0;i<MAX_DOMINATION_POINTS && i<level.domination_points_count; i++) {
+ Com_sprintf (entry, sizeof(entry)," %i",level.pointStatusDom[i]);
+ j = strlen(entry);
+ if (stringlength + j > 10*MAX_DOMINATION_POINTS)
+ break;
+ strcpy (string + stringlength, entry);
+ stringlength += j;
+ }
+
+ trap_SendServerCommand( ent-g_entities, va("domStatus %i%s", level.domination_points_count, string ) );
+}
+
+/*
+==================
+EliminationMessage
+
+==================
+*/
+
+void EliminationMessage(gentity_t *ent) {
+ trap_SendServerCommand( ent-g_entities, va("elimination %i %i %i",
+ level.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE], level.roundStartTime) );
+}
+
+void RespawnTimeMessage(gentity_t *ent, int time) {
+ trap_SendServerCommand( ent-g_entities, va("respawn %i", time) );
+}
+
+/*
+==================
+DoubleDominationScoreTime
+
+==================
+*/
+void DoubleDominationScoreTimeMessage( gentity_t *ent ) {
+ trap_SendServerCommand( ent-g_entities, va("ddtaken %i", level.timeTaken));
+}
+
+/*
+==================
+DominationPointNames
+==================
+*/
+
+void DominationPointNamesMessage( gentity_t *ent ) {
+ char text[MAX_DOMINATION_POINTS_NAMES*MAX_DOMINATION_POINTS];
+ int i,j;
+ qboolean nullFound;
+ for(i=0;i<MAX_DOMINATION_POINTS;i++) {
+ Q_strncpyz(text+i*MAX_DOMINATION_POINTS_NAMES,level.domination_points_names[i],MAX_DOMINATION_POINTS_NAMES-1);
+ if(i!=MAX_DOMINATION_POINTS-1) {
+ //Don't allow "/0"!
+ nullFound = qfalse;
+ for(j=i*MAX_DOMINATION_POINTS_NAMES; j<(i+1)*MAX_DOMINATION_POINTS_NAMES;j++) {
+ if(text[j]==0)
+ nullFound = qtrue;
+ if(nullFound)
+ text[j] = ' ';
+ }
+ }
+ text[MAX_DOMINATION_POINTS_NAMES*MAX_DOMINATION_POINTS-2]=0x19;
+ text[MAX_DOMINATION_POINTS_NAMES*MAX_DOMINATION_POINTS-1]=0;
+ }
+ trap_SendServerCommand( ent-g_entities, va("dompointnames %i \"%s\"", level.domination_points_count, text));
+}
+
+/*
+==================
+YourTeamMessage
+==================
+*/
+
+void YourTeamMessage( gentity_t *ent) {
+ int team = level.clients[ent-g_entities].sess.sessionTeam;
+
+ switch(team) {
+ case TEAM_RED:
+ trap_SendServerCommand( ent-g_entities, va("team \"%s\"", g_redTeamClientNumbers.string));
+ break;
+ case TEAM_BLUE:
+ trap_SendServerCommand( ent-g_entities, va("team \"%s\"", g_blueTeamClientNumbers.string));
+ break;
+ default:
+ trap_SendServerCommand( ent-g_entities, "team \"all\"");
+ };
+}
+
+/*
+==================
+AttackingTeamMessage
+
+==================
+*/
+void AttackingTeamMessage( gentity_t *ent ) {
+ int team;
+ if ( (level.eliminationSides+level.roundNumber)%2 == 0 )
+ team = TEAM_RED;
+ else
+ team = TEAM_BLUE;
+ trap_SendServerCommand( ent-g_entities, va("attackingteam %i", team));
+}
+
+/*
+
+ */
+
+void ObeliskHealthMessage() {
+ if(level.MustSendObeliskHealth) {
+ trap_SendServerCommand( -1, va("oh %i %i",level.healthRedObelisk,level.healthBlueObelisk) );
+ level.MustSendObeliskHealth = qfalse;
+ }
+}
+
+/*
+==================
+ChallengeMessage
+
+==================
+*/
+
+void ChallengeMessage(gentity_t *ent, int challenge) {
+ if ( level.warmupTime != 0)
+ return; //We don't send anything doring warmup
+ trap_SendServerCommand( ent-g_entities, va("ch %u", challenge) );
+ G_LogPrintf( "Challenge: %i %i %i: Client %i got award %i\n",ent-g_entities,challenge,1,ent-g_entities,challenge);
+}
+
+/*
+==================
+SendCustomVoteCommands
+
+==================
+*/
+
+void SendCustomVoteCommands(int clientNum) {
+ trap_SendServerCommand( clientNum, va("customvotes %s", custom_vote_info) );
+}
+
+/*
+==================
+Cmd_Score_f
+
+Request current scoreboard information
+==================
+*/
+void Cmd_Score_f( gentity_t *ent ) {
+ DeathmatchScoreboardMessage( ent );
+}
+
+
+/*
+==================
+ Cmd_Acc_f
+ Request current scoreboard information
+==================
+*/
+void Cmd_Acc_f( gentity_t *ent ) {
+ AccMessage( ent );
+}
+
+
+/*
+==================
+CheatsOk
+==================
+*/
+qboolean CheatsOk( gentity_t *ent ) {
+ if ( !g_cheats.integer ) {
+ trap_SendServerCommand( ent-g_entities, va("print \"Cheats are not enabled on this server.\n\""));
+ return qfalse;
+ }
+ if ( ent->health <= 0 ) {
+ trap_SendServerCommand( ent-g_entities, va("print \"You must be alive to use this command.\n\""));
+ return qfalse;
+ }
+ return qtrue;
+}
+
+
+/*
+==================
+ConcatArgs
+==================
+*/
+char *ConcatArgs( int start ) {
+ int i, c, tlen;
+ static char line[MAX_STRING_CHARS];
+ int len;
+ char arg[MAX_STRING_CHARS];
+
+ len = 0;
+ c = trap_Argc();
+ for ( i = start ; i < c ; i++ ) {
+ trap_Argv( i, arg, sizeof( arg ) );
+ tlen = strlen( arg );
+ if ( len + tlen >= MAX_STRING_CHARS - 1 ) {
+ break;
+ }
+ memcpy( line + len, arg, tlen );
+ len += tlen;
+ if ( i != c - 1 ) {
+ line[len] = ' ';
+ len++;
+ }
+ }
+
+ line[len] = 0;
+
+ return line;
+}
+
+/*
+==================
+ClientNumberFromString
+
+Returns a player number for either a number or name string
+Returns -1 if invalid
+==================
+*/
+int ClientNumberFromString( gentity_t *to, char *s ) {
+ gclient_t *cl;
+ int idnum;
+ char cleanName[MAX_STRING_CHARS];
+
+ // numeric values are just slot numbers
+ if (s[0] >= '0' && s[0] <= '9') {
+ idnum = atoi( s );
+ if ( idnum < 0 || idnum >= level.maxclients ) {
+ trap_SendServerCommand( to-g_entities, va("print \"Bad client slot: %i\n\"", idnum));
+ return -1;
+ }
+
+ cl = &level.clients[idnum];
+ if ( cl->pers.connected != CON_CONNECTED ) {
+ trap_SendServerCommand( to-g_entities, va("print \"Client %i is not active\n\"", idnum));
+ return -1;
+ }
+ return idnum;
+ }
+
+ // check for a name match
+ for ( idnum=0,cl=level.clients ; idnum < level.maxclients ; idnum++,cl++ ) {
+ if ( cl->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ Q_strncpyz(cleanName, cl->pers.netname, sizeof(cleanName));
+ Q_CleanStr(cleanName);
+ if ( Q_strequal( cleanName, s ) ) {
+ return idnum;
+ }
+ }
+
+ trap_SendServerCommand( to-g_entities, va("print \"User %s is not on the server\n\"", s));
+ return -1;
+}
+
+/*
+==================
+Cmd_Give_f
+
+Give items to a client
+==================
+*/
+void Cmd_Give_f (gentity_t *ent)
+{
+ char *name;
+ gitem_t *it;
+ int i;
+ qboolean give_all;
+ gentity_t *it_ent;
+ trace_t trace;
+
+ if ( !CheatsOk( ent ) ) {
+ return;
+ }
+
+ name = ConcatArgs( 1 );
+
+ if Q_strequal(name, "all")
+ give_all = qtrue;
+ else
+ give_all = qfalse;
+
+ if (give_all || Q_strequal( name, "health"))
+ {
+ ent->health = ent->client->ps.stats[STAT_MAX_HEALTH];
+ if (!give_all)
+ return;
+ }
+
+ if (give_all || Q_strequal(name, "weapons"))
+ {
+ ent->client->ps.stats[STAT_WEAPONS] = (1 << WP_NUM_WEAPONS) - 1 -
+ ( 1 << WP_GRAPPLING_HOOK ) - ( 1 << WP_NONE );
+ if (!give_all)
+ return;
+ }
+
+ if (give_all || Q_strequal(name, "ammo"))
+ {
+ for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
+ ent->client->ps.ammo[i] = 999;
+ }
+ if (!give_all)
+ return;
+ }
+
+ if (give_all || Q_strequal(name, "armor"))
+ {
+ ent->client->ps.stats[STAT_ARMOR] = 200;
+
+ if (!give_all)
+ return;
+ }
+
+ if (Q_strequal(name, "excellent")) {
+ ent->client->ps.persistant[PERS_EXCELLENT_COUNT]++;
+ return;
+ }
+ if (Q_strequal(name, "impressive")) {
+ ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
+ return;
+ }
+ if (Q_strequal(name, "gauntletaward")) {
+ ent->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;
+ return;
+ }
+ if (Q_strequal(name, "defend")) {
+ ent->client->ps.persistant[PERS_DEFEND_COUNT]++;
+ return;
+ }
+ if (Q_strequal(name, "assist")) {
+ ent->client->ps.persistant[PERS_ASSIST_COUNT]++;
+ return;
+ }
+
+ // spawn a specific item right on the player
+ if ( !give_all ) {
+ it = BG_FindItem (name);
+ if (!it) {
+ return;
+ }
+
+ it_ent = G_Spawn();
+ VectorCopy( ent->r.currentOrigin, it_ent->s.origin );
+ it_ent->classname = it->classname;
+ G_SpawnItem (it_ent, it);
+ FinishSpawningItem(it_ent );
+ memset( &trace, 0, sizeof( trace ) );
+ Touch_Item (it_ent, ent, &trace);
+ if (it_ent->inuse) {
+ G_FreeEntity( it_ent );
+ }
+ }
+}
+
+
+/*
+==================
+Cmd_God_f
+
+Sets client to godmode
+
+argv(0) god
+==================
+*/
+void Cmd_God_f (gentity_t *ent)
+{
+ char *msg;
+
+ if ( !CheatsOk( ent ) ) {
+ return;
+ }
+
+ ent->flags ^= FL_GODMODE;
+ if (!(ent->flags & FL_GODMODE) )
+ msg = "godmode OFF\n";
+ else
+ msg = "godmode ON\n";
+
+ trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg));
+}
+
+
+/*
+==================
+Cmd_Notarget_f
+
+Sets client to notarget
+
+argv(0) notarget
+==================
+*/
+void Cmd_Notarget_f( gentity_t *ent ) {
+ char *msg;
+
+ if ( !CheatsOk( ent ) ) {
+ return;
+ }
+
+ ent->flags ^= FL_NOTARGET;
+ if (!(ent->flags & FL_NOTARGET) )
+ msg = "notarget OFF\n";
+ else
+ msg = "notarget ON\n";
+
+ trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg));
+}
+
+
+/*
+==================
+Cmd_Noclip_f
+
+argv(0) noclip
+==================
+*/
+void Cmd_Noclip_f( gentity_t *ent ) {
+ char *msg;
+
+ if ( !CheatsOk( ent ) ) {
+ return;
+ }
+
+ if ( ent->client->noclip ) {
+ msg = "noclip OFF\n";
+ } else {
+ msg = "noclip ON\n";
+ }
+ ent->client->noclip = !ent->client->noclip;
+
+ trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg));
+}
+
+
+/*
+==================
+Cmd_LevelShot_f
+
+This is just to help generate the level pictures
+for the menus. It goes to the intermission immediately
+and sends over a command to the client to resize the view,
+hide the scoreboard, and take a special screenshot
+==================
+*/
+void Cmd_LevelShot_f( gentity_t *ent ) {
+ if ( !CheatsOk( ent ) ) {
+ return;
+ }
+
+ // doesn't work in single player
+ if ( g_gametype.integer != 0 ) {
+ trap_SendServerCommand( ent-g_entities,
+ "print \"Must be in g_gametype 0 for levelshot\n\"" );
+ return;
+ }
+
+ if(!ent->client->pers.localClient)
+ {
+ trap_SendServerCommand(ent-g_entities,
+ "print \"The levelshot command must be executed by a local client\n\"");
+ return;
+ }
+
+
+ BeginIntermission();
+ trap_SendServerCommand( ent-g_entities, "clientLevelShot" );
+}
+
+
+/*
+==================
+Cmd_LevelShot_f
+
+This is just to help generate the level pictures
+for the menus. It goes to the intermission immediately
+and sends over a command to the client to resize the view,
+hide the scoreboard, and take a special screenshot
+==================
+*/
+void Cmd_TeamTask_f( gentity_t *ent ) {
+ char userinfo[MAX_INFO_STRING];
+ char arg[MAX_TOKEN_CHARS];
+ int task;
+ int client = ent->client - level.clients;
+
+ if ( trap_Argc() != 2 ) {
+ return;
+ }
+ trap_Argv( 1, arg, sizeof( arg ) );
+ task = atoi( arg );
+
+ trap_GetUserinfo(client, userinfo, sizeof(userinfo));
+ Info_SetValueForKey(userinfo, "teamtask", va("%d", task));
+ trap_SetUserinfo(client, userinfo);
+ ClientUserinfoChanged(client);
+}
+
+
+
+/*
+=================
+Cmd_Kill_f
+=================
+*/
+void Cmd_Kill_f( gentity_t *ent ) {
+ if ( (ent->client->sess.sessionTeam == TEAM_SPECTATOR) || ent->client->isEliminated ) {
+ return;
+ }
+ if (ent->health <= 0) {
+ return;
+ }
+ ent->flags &= ~FL_GODMODE;
+ ent->client->ps.stats[STAT_HEALTH] = ent->health = -999;
+ if(ent->client->lastSentFlying>-1)
+ //If player is in the air because of knockback we give credit to the person who sent it flying
+ player_die (ent, ent, &g_entities[ent->client->lastSentFlying], 100000, MOD_FALLING);
+ else
+ player_die (ent, ent, ent, 100000, MOD_SUICIDE);
+}
+
+/*
+=================
+BroadCastTeamChange
+
+Let everyone know about a team change
+=================
+*/
+void BroadcastTeamChange( gclient_t *client, int oldTeam )
+{
+ if ( client->sess.sessionTeam == TEAM_RED ) {
+ trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the red team.\n\"",
+ client->pers.netname) );
+ } else if ( client->sess.sessionTeam == TEAM_BLUE ) {
+ trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the blue team.\n\"",
+ client->pers.netname));
+ } else if ( client->sess.sessionTeam == TEAM_SPECTATOR && oldTeam != TEAM_SPECTATOR ) {
+ trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the spectators.\n\"",
+ client->pers.netname));
+ } else if ( client->sess.sessionTeam == TEAM_FREE ) {
+ trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the battle.\n\"",
+ client->pers.netname));
+ }
+}
+
+/*
+=================
+SetTeam
+KK-OAX Modded this to accept a forced admin change.
+=================
+*/
+void SetTeam( gentity_t *ent, char *s ) {
+ int team, oldTeam;
+ gclient_t *client;
+ int clientNum;
+ spectatorState_t specState;
+ int specClient;
+ int teamLeader;
+ char userinfo[MAX_INFO_STRING];
+ qboolean force;
+
+ force = G_admin_permission(ent, ADMF_FORCETEAMCHANGE);
+
+ //
+ // see what change is requested
+ //
+ client = ent->client;
+
+ clientNum = client - level.clients;
+ trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
+ specClient = 0;
+ specState = SPECTATOR_NOT;
+ if ( Q_strequal( s, "scoreboard" ) || Q_strequal( s, "score" ) ) {
+ team = TEAM_SPECTATOR;
+ specState = SPECTATOR_SCOREBOARD;
+ } else if ( Q_strequal( s, "follow1" ) ) {
+ team = TEAM_SPECTATOR;
+ specState = SPECTATOR_FOLLOW;
+ specClient = -1;
+ } else if ( Q_strequal( s, "follow2" ) ) {
+ team = TEAM_SPECTATOR;
+ specState = SPECTATOR_FOLLOW;
+ specClient = -2;
+ } else if ( Q_strequal( s, "spectator" ) || Q_strequal( s, "s" ) ) {
+ team = TEAM_SPECTATOR;
+ specState = SPECTATOR_FREE;
+ } else if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
+ // if running a team game, assign player to one of the teams
+ specState = SPECTATOR_NOT;
+ if ( Q_strequal( s, "red" ) || Q_strequal( s, "r" ) ) {
+ team = TEAM_RED;
+ } else if ( Q_strequal( s, "blue" ) || Q_strequal( s, "b" ) ) {
+ team = TEAM_BLUE;
+ } else {
+ // pick the team with the least number of players
+ team = PickTeam( clientNum );
+ }
+ if ( !force ) {
+ if ( g_teamForceBalance.integer ) {
+ int counts[TEAM_NUM_TEAMS];
+
+ counts[TEAM_BLUE] = TeamCount( ent->client->ps.clientNum, TEAM_BLUE );
+ counts[TEAM_RED] = TeamCount( ent->client->ps.clientNum, TEAM_RED );
+
+ // We allow a spread of two
+ if ( team == TEAM_RED && counts[TEAM_RED] - counts[TEAM_BLUE] > 1 ) {
+ trap_SendServerCommand( ent->client->ps.clientNum,
+ "cp \"Red team has too many players.\n\"" );
+ return; // ignore the request
+ }
+ if ( team == TEAM_BLUE && counts[TEAM_BLUE] - counts[TEAM_RED] > 1 ) {
+ trap_SendServerCommand( ent->client->ps.clientNum,
+ "cp \"Blue team has too many players.\n\"" );
+ return; // ignore the request
+ }
+
+ // It's ok, the team we are switching to has less or same number of players
+ }
+ }
+ } else {
+ // force them to spectators if there aren't any spots free
+ team = TEAM_FREE;
+ }
+ if ( !force ) {
+ // override decision if limiting the players
+ if ( (g_gametype.integer == GT_TOURNAMENT)
+ && level.numNonSpectatorClients >= 2 ) {
+ team = TEAM_SPECTATOR;
+ } else if ( g_maxGameClients.integer > 0 &&
+ level.numNonSpectatorClients >= g_maxGameClients.integer ) {
+ team = TEAM_SPECTATOR;
+ }
+ }
+
+ //
+ // decide if we will allow the change
+ //
+ oldTeam = client->sess.sessionTeam;
+ if ( team == oldTeam && team != TEAM_SPECTATOR ) {
+ return;
+ }
+ //KK-OAX Check to make sure the team is not locked from Admin
+ if ( !force ) {
+ if ( team == TEAM_RED && level.RedTeamLocked ) {
+ trap_SendServerCommand( ent->client->ps.clientNum,
+ "cp \"The Red Team has been locked by the Admin! \n\"" );
+ return;
+ }
+ if ( team == TEAM_BLUE && level.BlueTeamLocked ) {
+ trap_SendServerCommand( ent->client->ps.clientNum,
+ "cp \"The Blue Team has been locked by the Admin! \n\"" );
+ return;
+ }
+ if ( team == TEAM_FREE && level.FFALocked ) {
+ trap_SendServerCommand( ent->client->ps.clientNum,
+ "cp \"This Deathmatch has been locked by the Admin! \n\"" );
+ return;
+ }
+ }
+ //
+ // execute the team change
+ //
+
+ // if the player was dead leave the body
+ if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
+ CopyToBodyQue(ent);
+ }
+
+ // he starts at 'base'
+ client->pers.teamState.state = TEAM_BEGIN;
+ if ( oldTeam != TEAM_SPECTATOR ) {
+ int teamscore = -99;
+ //Prevent a team from loosing point because of player leaving team
+ if(g_gametype.integer == GT_TEAM && ent->client->ps.stats[STAT_HEALTH])
+ teamscore = level.teamScores[ ent->client->sess.sessionTeam ];
+ // Kill him (makes sure he loses flags, etc)
+ ent->flags &= ~FL_GODMODE;
+ ent->client->ps.stats[STAT_HEALTH] = ent->health = 0;
+ player_die (ent, ent, ent, 100000, MOD_SUICIDE);
+ if(teamscore != -99)
+ level.teamScores[ ent->client->sess.sessionTeam ] = teamscore;
+
+ }
+
+ if(oldTeam!=TEAM_SPECTATOR)
+ PlayerStore_store(Info_ValueForKey(userinfo,"cl_guid"),client->ps);
+
+ // they go to the end of the line for tournements
+ if(team == TEAM_SPECTATOR && oldTeam != team)
+ AddTournamentQueue(client);
+
+ client->sess.sessionTeam = team;
+ client->sess.spectatorState = specState;
+ client->sess.spectatorClient = specClient;
+
+ client->sess.teamLeader = qfalse;
+ if ( team == TEAM_RED || team == TEAM_BLUE ) {
+ teamLeader = TeamLeader( team );
+ // if there is no team leader or the team leader is a bot and this client is not a bot
+ if ( teamLeader == -1 || ( !(g_entities[clientNum].r.svFlags & SVF_BOT) && (g_entities[teamLeader].r.svFlags & SVF_BOT) ) ) {
+ SetLeader( team, clientNum );
+ }
+ }
+ // make sure there is a team leader on the team the player came from
+ if ( oldTeam == TEAM_RED || oldTeam == TEAM_BLUE ) {
+ CheckTeamLeader( oldTeam );
+ }
+
+ BroadcastTeamChange( client, oldTeam );
+
+ // get and distribute relevent paramters
+ ClientUserinfoChanged( clientNum );
+
+ ClientBegin( clientNum );
+}
+
+/*
+=================
+StopFollowing
+
+If the client being followed leaves the game, or you just want to drop
+to free floating spectator mode
+=================
+*/
+void StopFollowing( gentity_t *ent ) {
+ if(g_gametype.integer<GT_ELIMINATION || g_gametype.integer>GT_LMS)
+ {
+ //Shouldn't this already be the case?
+ ent->client->ps.persistant[ PERS_TEAM ] = TEAM_SPECTATOR;
+ ent->client->sess.sessionTeam = TEAM_SPECTATOR;
+ }
+ else {
+ ent->client->ps.stats[STAT_HEALTH] = 0;
+ ent->health = 0;
+ }
+ ent->client->sess.spectatorState = SPECTATOR_FREE;
+ ent->client->ps.pm_flags &= ~PMF_FOLLOW;
+ ent->r.svFlags &= ~SVF_BOT;
+ ent->client->ps.clientNum = ent - g_entities;
+}
+
+/*
+=================
+Cmd_Team_f
+=================
+*/
+void Cmd_Team_f( gentity_t *ent ) {
+ int oldTeam;
+ char s[MAX_TOKEN_CHARS];
+ qboolean force;
+
+ if ( trap_Argc() != 2 ) {
+ oldTeam = ent->client->sess.sessionTeam;
+ switch ( oldTeam ) {
+ case TEAM_BLUE:
+ trap_SendServerCommand( ent-g_entities, "print \"Blue team\n\"" );
+ break;
+ case TEAM_RED:
+ trap_SendServerCommand( ent-g_entities, "print \"Red team\n\"" );
+ break;
+ case TEAM_FREE:
+ trap_SendServerCommand( ent-g_entities, "print \"Deathmatch-Playing\n\"" );
+ break;
+ case TEAM_SPECTATOR:
+ trap_SendServerCommand( ent-g_entities, "print \"Spectator team\n\"" );
+ break;
+ }
+ return;
+ }
+
+ force = G_admin_permission(ent, ADMF_FORCETEAMCHANGE);
+
+ if( !force ) {
+ if ( ent->client->switchTeamTime > level.time ) {
+ trap_SendServerCommand( ent-g_entities, "print \"May not switch teams more than once per 5 seconds.\n\"" );
+ return;
+ }
+ }
+
+ // if they are playing a tournement game, count as a loss
+ if ( (g_gametype.integer == GT_TOURNAMENT )
+ && ent->client->sess.sessionTeam == TEAM_FREE ) {
+ ent->client->sess.losses++;
+ }
+
+ trap_Argv( 1, s, sizeof( s ) );
+
+ SetTeam( ent, s );
+
+ ent->client->switchTeamTime = level.time + 5000;
+}
+
+
+/*
+=================
+Cmd_Follow_f
+=================
+*/
+void Cmd_Follow_f( gentity_t *ent ) {
+ int i;
+ char arg[MAX_TOKEN_CHARS];
+
+ if ( trap_Argc() != 2 ) {
+ if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {
+ StopFollowing( ent );
+ }
+ return;
+ }
+
+
+ trap_Argv( 1, arg, sizeof( arg ) );
+ i = ClientNumberFromString( ent, arg );
+ if ( i == -1 ) {
+ return;
+ }
+
+
+
+ // can't follow self
+ if ( &level.clients[ i ] == ent->client ) {
+ return;
+ }
+
+ // can't follow another spectator (or an eliminated player)
+ if ( (level.clients[ i ].sess.sessionTeam == TEAM_SPECTATOR) || level.clients[ i ].isEliminated) {
+ return;
+ }
+
+ if ( (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) && g_elimination_lockspectator.integer
+ && ((ent->client->sess.sessionTeam == TEAM_RED && level.clients[ i ].sess.sessionTeam == TEAM_BLUE) ||
+ (ent->client->sess.sessionTeam == TEAM_BLUE && level.clients[ i ].sess.sessionTeam == TEAM_RED) ) ) {
+ return;
+ }
+
+ // if they are playing a tournement game, count as a loss
+ if ( (g_gametype.integer == GT_TOURNAMENT )
+ && ent->client->sess.sessionTeam == TEAM_FREE ) {
+ ent->client->sess.losses++;
+ }
+
+ // first set them to spectator
+ //if ( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
+ if ( ent->client->sess.spectatorState == SPECTATOR_NOT ) {
+ SetTeam( ent, "spectator" );
+ }
+
+ ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
+ ent->client->sess.spectatorClient = i;
+}
+
+/*
+=================
+Cmd_FollowCycle_f
+KK-OAX Modified to trap arguments.
+=================
+*/
+void Cmd_FollowCycle_f( gentity_t *ent ) {
+ int clientnum;
+ int original;
+ int count;
+ char args[11];
+ int dir;
+
+ if( ent->client->sess.sessionTeam == TEAM_NONE ) {
+ dir = 1;
+ }
+
+ trap_Argv( 0, args, sizeof( args ) );
+ if( Q_strequal( args, "followprev" )) {
+ dir = -1;
+ } else if( Q_strequal( args, "follownext" )) {
+ dir = 1;
+ } else {
+ dir = 1;
+ }
+
+ // if they are playing a tournement game, count as a loss
+ if ( (g_gametype.integer == GT_TOURNAMENT )
+ && ent->client->sess.sessionTeam == TEAM_FREE ) {
+ ent->client->sess.losses++;
+ }
+ // first set them to spectator
+ if ( ent->client->sess.spectatorState == SPECTATOR_NOT ) {
+ SetTeam( ent, "spectator" );
+ }
+
+ if ( dir != 1 && dir != -1 ) {
+ G_Error( "Cmd_FollowCycle_f: bad dir %i", dir );
+ }
+
+ clientnum = ent->client->sess.spectatorClient;
+ original = clientnum;
+ count = 0;
+ do {
+ clientnum += dir;
+ count++;
+ if ( clientnum >= level.maxclients ) {
+ clientnum = 0;
+ }
+ if ( clientnum < 0 ) {
+ clientnum = level.maxclients - 1;
+ }
+
+ if(count>level.maxclients) //We have looked at all clients at least once and found nothing
+ return; //We might end up in an infinite loop here. Stop it!
+
+ // can only follow connected clients
+ if ( level.clients[ clientnum ].pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+
+ // can't follow another spectator
+ if ( (level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR) || level.clients[ clientnum ].isEliminated) {
+ continue;
+ }
+
+ //Stop players from spectating players on the enemy team in elimination modes.
+ if ( (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) && g_elimination_lockspectator.integer
+ && ((ent->client->sess.sessionTeam == TEAM_RED && level.clients[ clientnum ].sess.sessionTeam == TEAM_BLUE) ||
+ (ent->client->sess.sessionTeam == TEAM_BLUE && level.clients[ clientnum ].sess.sessionTeam == TEAM_RED) ) ) {
+ continue;
+ }
+
+ // this is good, we can use it
+ ent->client->sess.spectatorClient = clientnum;
+ ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
+ return;
+ } while ( clientnum != original );
+
+ // leave it where it was
+}
+
+
+/*
+==================
+G_Say
+==================
+*/
+
+static void G_SayTo( gentity_t *ent, gentity_t *other, int mode, int color, const char *name, const char *message ) {
+ if (!other) {
+ return;
+ }
+ if (!other->inuse) {
+ return;
+ }
+ if (!other->client) {
+ return;
+ }
+ if ( other->client->pers.connected != CON_CONNECTED ) {
+ return;
+ }
+ if ( mode == SAY_TEAM && !OnSameTeam(ent, other) ) {
+ return;
+ }
+
+ if ((ent->r.svFlags & SVF_BOT) && trap_Cvar_VariableValue( "bot_nochat" )>1) return;
+
+ // no chatting to players in tournements
+ if ( (g_gametype.integer == GT_TOURNAMENT )
+ && other->client->sess.sessionTeam == TEAM_FREE
+ && ent->client->sess.sessionTeam != TEAM_FREE ) {
+ return;
+ }
+
+ trap_SendServerCommand( other-g_entities, va("%s \"%s%c%c%s\"",
+ mode == SAY_TEAM ? "tchat" : "chat",
+ name, Q_COLOR_ESCAPE, color, message));
+}
+
+#define EC "\x19"
+
+void G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText ) {
+ int j;
+ gentity_t *other;
+ int color;
+ char name[64];
+ // don't let text be too long for malicious reasons
+ char text[MAX_SAY_TEXT];
+ char location[64];
+
+ if ((ent->r.svFlags & SVF_BOT) && trap_Cvar_VariableValue( "bot_nochat" )>1) return;
+
+ if ( (g_gametype.integer < GT_TEAM || g_ffa_gt == 1) && mode == SAY_TEAM ) {
+ mode = SAY_ALL;
+ }
+
+ switch ( mode ) {
+ default:
+ case SAY_ALL:
+ G_LogPrintf( "say: %s: %s\n", ent->client->pers.netname, chatText );
+ Com_sprintf (name, sizeof(name), "%s%c%c"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
+ color = COLOR_GREEN;
+ break;
+ case SAY_TEAM:
+ G_LogPrintf( "sayteam: %s: %s\n", ent->client->pers.netname, chatText );
+ if (Team_GetLocationMsg(ent, location, sizeof(location)))
+ Com_sprintf (name, sizeof(name), EC"(%s%c%c"EC") (%s)"EC": ",
+ ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location);
+ else
+ Com_sprintf (name, sizeof(name), EC"(%s%c%c"EC")"EC": ",
+ ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
+ color = COLOR_CYAN;
+ break;
+ case SAY_TELL:
+ if (target && g_gametype.integer >= GT_TEAM && g_ffa_gt != 1 &&
+ target->client->sess.sessionTeam == ent->client->sess.sessionTeam &&
+ Team_GetLocationMsg(ent, location, sizeof(location)))
+ Com_sprintf (name, sizeof(name), EC"[%s%c%c"EC"] (%s)"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location );
+ else
+ Com_sprintf (name, sizeof(name), EC"[%s%c%c"EC"]"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
+ color = COLOR_MAGENTA;
+ break;
+ }
+
+ Q_strncpyz( text, chatText, sizeof(text) );
+
+ if ( target ) {
+ G_SayTo( ent, target, mode, color, name, text );
+ return;
+ }
+
+ // echo the text to the console
+ if ( g_dedicated.integer ) {
+ G_Printf( "%s%s\n", name, text);
+ }
+
+ // send it to all the apropriate clients
+ for (j = 0; j < level.maxclients; j++) {
+ other = &g_entities[j];
+ G_SayTo( ent, other, mode, color, name, text );
+ }
+ //KK-OAX Admin Command Check from Say/SayTeam line
+ if( g_adminParseSay.integer )
+ {
+ G_admin_cmd_check ( ent, qtrue );
+ }
+}
+
+
+/*
+==================
+Cmd_Say_f
+KK-OAX Modified this to trap the additional arguments from console.
+==================
+*/
+static void Cmd_Say_f( gentity_t *ent ){
+ char *p;
+ char arg[MAX_TOKEN_CHARS];
+ int mode = SAY_ALL;
+
+ trap_Argv( 0, arg, sizeof( arg ) );
+ if( Q_strequal( arg, "say_team" ) )
+ mode = SAY_TEAM ;
+ // KK-OAX Disabled until PM'ing is added
+ // support parsing /m out of say text since some people have a hard
+ // time figuring out what the console is.
+ /*if( !Q_stricmpn( args, "say /m ", 7 ) ||
+ !Q_stricmpn( args, "say_team /m ", 12 ) ||
+ !Q_stricmpn( args, "say /mt ", 8 ) ||
+ !Q_stricmpn( args, "say_team /mt ", 13 ) )
+ {
+ Cmd_PrivateMessage_f( ent );
+ return;
+ }
+
+ // support parsing /a out of say text for the same reason
+ if( !Q_stricmpn( args, "say /a ", 7 ) ||
+ !Q_stricmpn( args, "say_team /a ", 12 ) )
+ {
+ Cmd_AdminMessage_f( ent );
+ return;
+ }*/
+
+ if( trap_Argc( ) < 2 )
+ return;
+
+ p = ConcatArgs( 1 );
+
+ G_Say( ent, NULL, mode, p );
+}
+
+/*
+==================
+Cmd_Tell_f
+==================
+*/
+static void Cmd_Tell_f( gentity_t *ent ) {
+ int targetNum;
+ gentity_t *target;
+ char *p;
+ char arg[MAX_TOKEN_CHARS];
+
+ if ( trap_Argc () < 2 ) {
+ return;
+ }
+
+ trap_Argv( 1, arg, sizeof( arg ) );
+ targetNum = atoi( arg );
+ if ( targetNum < 0 || targetNum >= level.maxclients ) {
+ return;
+ }
+
+ target = &g_entities[targetNum];
+ if ( !target || !target->inuse || !target->client ) {
+ return;
+ }
+
+ p = ConcatArgs( 2 );
+
+ G_LogPrintf( "tell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, p );
+ G_Say( ent, target, SAY_TELL, p );
+ // don't tell to the player self if it was already directed to this player
+ // also don't send the chat back to a bot
+ if ( ent != target && !(ent->r.svFlags & SVF_BOT)) {
+ G_Say( ent, ent, SAY_TELL, p );
+ }
+}
+
+
+static void G_VoiceTo( gentity_t *ent, gentity_t *other, int mode, const char *id, qboolean voiceonly ) {
+ int color;
+ char *cmd;
+
+ if (!other) {
+ return;
+ }
+ if (!other->inuse) {
+ return;
+ }
+ if (!other->client) {
+ return;
+ }
+ if ( mode == SAY_TEAM && !OnSameTeam(ent, other) ) {
+ return;
+ }
+ // no chatting to players in tournements
+ if ( (g_gametype.integer == GT_TOURNAMENT )) {
+ return;
+ }
+
+ if (mode == SAY_TEAM) {
+ color = COLOR_CYAN;
+ cmd = "vtchat";
+ }
+ else if (mode == SAY_TELL) {
+ color = COLOR_MAGENTA;
+ cmd = "vtell";
+ }
+ else {
+ color = COLOR_GREEN;
+ cmd = "vchat";
+ }
+
+ trap_SendServerCommand( other-g_entities, va("%s %d %d %d %s", cmd, voiceonly, ent->s.number, color, id));
+}
+
+void G_Voice( gentity_t *ent, gentity_t *target, int mode, const char *id, qboolean voiceonly ) {
+ int j;
+ gentity_t *other;
+
+ if ( (g_gametype.integer < GT_TEAM || g_ffa_gt==1 ) && mode == SAY_TEAM ) {
+ mode = SAY_ALL;
+ }
+
+ if ( target ) {
+ G_VoiceTo( ent, target, mode, id, voiceonly );
+ return;
+ }
+
+ // echo the text to the console
+ if ( g_dedicated.integer ) {
+ G_Printf( "voice: %s %s\n", ent->client->pers.netname, id);
+ }
+
+ // send it to all the apropriate clients
+ for (j = 0; j < level.maxclients; j++) {
+ other = &g_entities[j];
+ G_VoiceTo( ent, other, mode, id, voiceonly );
+ }
+}
+
+/*
+==================
+Cmd_Voice_f
+KK-OAX Modified this to trap args.
+
+In the original, every call to this function would always set "arg0" to false, and it was
+never passed along to other functions, so I removed/commented it out.
+==================
+*/
+static void Cmd_Voice_f( gentity_t *ent ) {
+ char *p;
+ char arg[MAX_TOKEN_CHARS];
+ int mode = SAY_ALL;
+ qboolean voiceonly = qfalse;
+
+ trap_Argv( 0, arg, sizeof( arg ) );
+ if((Q_strequal( arg, "vsay_team" ) ) ||
+ Q_strequal( arg, "vosay_team" ) )
+ mode = SAY_TEAM;
+
+ if((Q_strequal( arg, "vosay" ) ) ||
+ Q_strequal( arg, "vosay_team" ) )
+ voiceonly = qtrue;
+
+ //KK-OAX Removed "arg0" since it will always be set to qfalse.
+ if ( trap_Argc () < 2 ) {
+ return;
+ }
+ //KK-OAX This was tricky to figure out, but since none of the original command handlings
+ //set it to "qtrue"...
+
+ /*if (arg0)
+ {
+ p = ConcatArgs( 0 );
+ }
+ else
+ {*/
+ p = ConcatArgs( 1 );
+ //}
+
+ G_Voice( ent, NULL, mode, p, voiceonly );
+}
+
+/*
+==================
+Cmd_VoiceTell_f
+KK-OAX Modified this to trap args.
+==================
+*/
+static void Cmd_VoiceTell_f( gentity_t *ent ) {
+ int targetNum;
+ gentity_t *target;
+ char *id;
+ char arg[MAX_TOKEN_CHARS];
+ qboolean voiceonly = qfalse;
+
+ if ( trap_Argc () < 2 ) {
+ return;
+ }
+
+ trap_Argv( 0, arg, sizeof( arg ) );
+ if( Q_strequal( arg, "votell" ) )
+ voiceonly = qtrue;
+
+ trap_Argv( 1, arg, sizeof( arg ) );
+ targetNum = atoi( arg );
+ if ( targetNum < 0 || targetNum >= level.maxclients ) {
+ return;
+ }
+
+ target = &g_entities[targetNum];
+ if ( !target || !target->inuse || !target->client ) {
+ return;
+ }
+
+ id = ConcatArgs( 2 );
+
+ G_LogPrintf( "vtell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, id );
+ G_Voice( ent, target, SAY_TELL, id, voiceonly );
+ // don't tell to the player self if it was already directed to this player
+ // also don't send the chat back to a bot
+ if ( ent != target && !(ent->r.svFlags & SVF_BOT)) {
+ G_Voice( ent, ent, SAY_TELL, id, voiceonly );
+ }
+}
+
+
+/*
+==================
+Cmd_VoiceTaunt_f
+==================
+*/
+static void Cmd_VoiceTaunt_f( gentity_t *ent ) {
+ gentity_t *who;
+ int i;
+
+ if (!ent->client) {
+ return;
+ }
+
+ // insult someone who just killed you
+ if (ent->enemy && ent->enemy->client && ent->enemy->client->lastkilled_client == ent->s.number) {
+ // i am a dead corpse
+ if (!(ent->enemy->r.svFlags & SVF_BOT)) {
+ G_Voice( ent, ent->enemy, SAY_TELL, VOICECHAT_DEATHINSULT, qfalse );
+ }
+ if (!(ent->r.svFlags & SVF_BOT)) {
+ G_Voice( ent, ent, SAY_TELL, VOICECHAT_DEATHINSULT, qfalse );
+ }
+ ent->enemy = NULL;
+ return;
+ }
+ // insult someone you just killed
+ if (ent->client->lastkilled_client >= 0 && ent->client->lastkilled_client != ent->s.number) {
+ who = g_entities + ent->client->lastkilled_client;
+ if (who->client) {
+ // who is the person I just killed
+ if (who->client->lasthurt_mod == MOD_GAUNTLET) {
+ if (!(who->r.svFlags & SVF_BOT)) {
+ G_Voice( ent, who, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse ); // and I killed them with a gauntlet
+ }
+ if (!(ent->r.svFlags & SVF_BOT)) {
+ G_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse );
+ }
+ } else {
+ if (!(who->r.svFlags & SVF_BOT)) {
+ G_Voice( ent, who, SAY_TELL, VOICECHAT_KILLINSULT, qfalse ); // and I killed them with something else
+ }
+ if (!(ent->r.svFlags & SVF_BOT)) {
+ G_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLINSULT, qfalse );
+ }
+ }
+ ent->client->lastkilled_client = -1;
+ return;
+ }
+ }
+
+ if (g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
+ // praise a team mate who just got a reward
+ for(i = 0; i < MAX_CLIENTS; i++) {
+ who = g_entities + i;
+ if (who->client && who != ent && who->client->sess.sessionTeam == ent->client->sess.sessionTeam) {
+ if (who->client->rewardTime > level.time) {
+ if (!(who->r.svFlags & SVF_BOT)) {
+ G_Voice( ent, who, SAY_TELL, VOICECHAT_PRAISE, qfalse );
+ }
+ if (!(ent->r.svFlags & SVF_BOT)) {
+ G_Voice( ent, ent, SAY_TELL, VOICECHAT_PRAISE, qfalse );
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ // just say something
+ G_Voice( ent, NULL, SAY_ALL, VOICECHAT_TAUNT, qfalse );
+}
+
+
+
+static char *gc_orders[] = {
+ "hold your position",
+ "hold this position",
+ "come here",
+ "cover me",
+ "guard location",
+ "search and destroy",
+ "report"
+};
+
+void Cmd_GameCommand_f( gentity_t *ent ) {
+ int player;
+ int order;
+ char str[MAX_TOKEN_CHARS];
+
+ trap_Argv( 1, str, sizeof( str ) );
+ player = atoi( str );
+ trap_Argv( 2, str, sizeof( str ) );
+ order = atoi( str );
+
+ if ( player < 0 || player >= MAX_CLIENTS ) {
+ return;
+ }
+ if ( order < 0 || order > sizeof(gc_orders)/sizeof(char *) ) {
+ return;
+ }
+ G_Say( ent, &g_entities[player], SAY_TELL, gc_orders[order] );
+ G_Say( ent, ent, SAY_TELL, gc_orders[order] );
+}
+
+/*
+==================
+Cmd_Where_f
+==================
+*/
+void Cmd_Where_f( gentity_t *ent ) {
+ trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", vtos(ent->r.currentOrigin) ) );
+}
+
+static const char *gameNames[] = {
+ "Free For All",
+ "Tournament",
+ "Single Player",
+ "Team Deathmatch",
+ "Capture the Flag",
+ "One Flag CTF",
+ "Overload",
+ "Harvester",
+ "Elimination",
+ "CTF Elimination",
+ "Last Man Standing",
+ "Double Domination",
+ "Domination"
+};
+
+
+
+/*
+==================
+Cmd_CallVote_f
+==================
+*/
+void Cmd_CallVote_f( gentity_t *ent ) {
+ char* c;
+ int i;
+ char arg1[MAX_STRING_TOKENS];
+ char arg2[MAX_STRING_TOKENS];
+ char buffer[256];
+
+ if ( !g_allowVote.integer ) {
+ trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here.\n\"" );
+ return;
+ }
+
+ if ( level.voteTime ) {
+ trap_SendServerCommand( ent-g_entities, "print \"A vote is already in progress.\n\"" );
+ return;
+ }
+ if ( ent->client->pers.voteCount >= g_maxvotes.integer ) {
+ trap_SendServerCommand( ent-g_entities, "print \"You have called the maximum number of votes.\n\"" );
+ return;
+ }
+ if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
+ trap_SendServerCommand( ent-g_entities, "print \"Not allowed to call a vote as spectator.\n\"" );
+ return;
+ }
+
+ // make sure it is a valid command to vote on
+ trap_Argv( 1, arg1, sizeof( arg1 ) );
+ trap_Argv( 2, arg2, sizeof( arg2 ) );
+
+ // check for command separators in arg2
+ for( c = arg2; *c; ++c) {
+ switch(*c) {
+ case '\n':
+ case '\r':
+ case ';':
+ trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
+ return;
+ break;
+ }
+ }
+
+
+ if ( !Q_stricmp( arg1, "map_restart" ) ) {
+ } else if ( !Q_stricmp( arg1, "nextmap" ) ) {
+ } else if ( !Q_stricmp( arg1, "map" ) ) {
+ } else if ( !Q_stricmp( arg1, "g_gametype" ) ) {
+ } else if ( !Q_stricmp( arg1, "kick" ) ) {
+ } else if ( !Q_stricmp( arg1, "clientkick" ) ) {
+ } else if ( !Q_stricmp( arg1, "g_doWarmup" ) ) {
+ } else if ( !Q_stricmp( arg1, "timelimit" ) ) {
+ } else if ( !Q_stricmp( arg1, "fraglimit" ) ) {
+ } else if ( !Q_stricmp( arg1, "custom" ) ) {
+ } else if ( !Q_stricmp( arg1, "shuffle" ) ) {
+ } else {
+ trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
+ //trap_SendServerCommand( ent-g_entities, "print \"Vote commands are: map_restart, nextmap, map <mapname>, g_gametype <n>, kick <player>, clientkick <clientnum>, g_doWarmup, timelimit <time>, fraglimit <frags>.\n\"" );
+ buffer[0] = 0;
+ strcat(buffer,"print \"Vote commands are: ");
+ if(allowedVote("map_restart"))
+ strcat(buffer, "map_restart, ");
+ if(allowedVote("nextmap"))
+ strcat(buffer, "nextmap, ");
+ if(allowedVote("map"))
+ strcat(buffer, "map <mapname>, ");
+ if(allowedVote("g_gametype"))
+ strcat(buffer, "g_gametype <n>, ");
+ if(allowedVote("kick"))
+ strcat(buffer, "kick <player>, ");
+ if(allowedVote("clientkick"))
+ strcat(buffer, "clientkick <clientnum>, ");
+ if(allowedVote("g_doWarmup"))
+ strcat(buffer, "g_doWarmup, ");
+ if(allowedVote("timelimit"))
+ strcat(buffer, "timelimit <time>, ");
+ if(allowedVote("fraglimit"))
+ strcat(buffer, "fraglimit <frags>, ");
+ if(allowedVote("shuffle"))
+ strcat(buffer, "shuffle, ");
+ if(allowedVote("custom"))
+ strcat(buffer, "custom <special>, ");
+ buffer[strlen(buffer)-2] = 0;
+ strcat(buffer, ".\"");
+ trap_SendServerCommand( ent-g_entities, buffer);
+ return;
+ }
+
+ if(!allowedVote(arg1)) {
+ trap_SendServerCommand( ent-g_entities, "print \"Not allowed here.\n\"" );
+ buffer[0] = 0;
+ strcat(buffer,"print \"Vote commands are: ");
+ if(allowedVote("map_restart"))
+ strcat(buffer, "map_restart, ");
+ if(allowedVote("nextmap"))
+ strcat(buffer, "nextmap, ");
+ if(allowedVote("map"))
+ strcat(buffer, "map <mapname>, ");
+ if(allowedVote("g_gametype"))
+ strcat(buffer, "g_gametype <n>, ");
+ if(allowedVote("kick"))
+ strcat(buffer, "kick <player>, ");
+ if(allowedVote("clientkick"))
+ strcat(buffer, "clientkick <clientnum>, ");
+ if(allowedVote("shuffle"))
+ strcat(buffer, "shuffle, ");
+ if(allowedVote("g_doWarmup"))
+ strcat(buffer, "g_doWarmup, ");
+ if(allowedVote("timelimit"))
+ strcat(buffer, "timelimit <time>, ");
+ if(allowedVote("fraglimit"))
+ strcat(buffer, "fraglimit <frags>, ");
+ if(allowedVote("custom"))
+ strcat(buffer, "custom <special>, ");
+ buffer[strlen(buffer)-2] = 0;
+ strcat(buffer, ".\"");
+ trap_SendServerCommand( ent-g_entities, buffer);
+ return;
+ }
+
+ // if there is still a vote to be executed
+ if ( level.voteExecuteTime ) {
+ level.voteExecuteTime = 0;
+ trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.voteString ) );
+ }
+
+ level.voteKickClient = -1; //not a client
+ level.voteKickType = 0; //not a ban
+
+ // special case for g_gametype, check for bad values
+ if ( !Q_stricmp( arg1, "g_gametype" ) ) {
+ char s[MAX_STRING_CHARS];
+ i = atoi( arg2 );
+ if( i == GT_SINGLE_PLAYER || i < GT_FFA || i >= GT_MAX_GAME_TYPE) {
+ trap_SendServerCommand( ent-g_entities, "print \"Invalid gametype.\n\"" );
+ return;
+ }
+
+ if( i== g_gametype.integer ) {
+ trap_SendServerCommand( ent-g_entities, "print \"This is current gametype\n\"" );
+ return;
+ }
+
+ if(!allowedGametype(arg2)){
+ trap_SendServerCommand( ent-g_entities, "print \"Gametype is not available.\n\"" );
+ return;
+ }
+
+ trap_Cvar_VariableStringBuffer( "nextmap", s, sizeof(s) );
+ if (*s) {
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %d; map_restart; set nextmap \"%s\"", arg1, i,s );
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Change gametype to: %s?", gameNames[i] );
+ } else {
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %d; mao_restart", arg1, i );
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Change gametype to: %s?", gameNames[i] );
+ }
+ } else if ( !Q_stricmp( arg1, "map" ) ) {
+ // special case for map changes, we want to reset the nextmap setting
+ // this allows a player to change maps, but not upset the map rotation
+ char s[MAX_STRING_CHARS];
+
+ if(!allowedMap(arg2)){
+ trap_SendServerCommand( ent-g_entities, "print \"Map is not available.\n\"" );
+ return;
+ }
+
+ trap_Cvar_VariableStringBuffer( "nextmap", s, sizeof(s) );
+ if (*s) {
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %s; set nextmap \"%s\"", arg1, arg2, s );
+ } else {
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %s", arg1, arg2 );
+ }
+ //Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString );
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Change map to: %s?", arg2 );
+ } else if ( !Q_stricmp( arg1, "nextmap" ) ) {
+ char s[MAX_STRING_CHARS];
+
+ //Sago: Needs to think about this, we miss code to parse if nextmap has arg2
+ /*if(!allowedMap(arg2)){
+ trap_SendServerCommand( ent-g_entities, "print \"Map is not available.\n\"" );
+ return;
+ }*/
+
+ if(g_autonextmap.integer) {
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "endgamenow");
+ } else {
+ trap_Cvar_VariableStringBuffer( "nextmap", s, sizeof(s) );
+ if (!*s) {
+ trap_SendServerCommand( ent-g_entities, "print \"nextmap not set.\n\"" );
+ return;
+ }
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "vstr nextmap");
+ }
+
+ //Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString );
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", "Next map?" );
+ } else if ( !Q_stricmp( arg1, "fraglimit" ) ) {
+ i = atoi(arg2);
+ if(!allowedFraglimit(i)) {
+ trap_SendServerCommand( ent-g_entities, "print \"Cannot set fraglimit.\n\"" );
+ return;
+ }
+
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "%s \"%d\"", arg1, i );
+ if(i)
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Change fraglimit to: %d", i );
+ else
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Remove fraglimit?");
+ } else if ( !Q_stricmp( arg1, "timelimit" ) ) {
+ i = atoi(arg2);
+ if(!allowedTimelimit(i)) {
+ trap_SendServerCommand( ent-g_entities, "print \"Cannot set timelimit.\n\"" );
+ return;
+ }
+
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "%s \"%d\"", arg1, i );
+ if(i)
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Change timelimit to: %d", i );
+ else
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Remove timelimit?" );
+ } else if ( !Q_stricmp( arg1, "map_restart" ) ) {
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "map_restart" );
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Restart map?" );
+ } else if ( !Q_stricmp( arg1, "g_doWarmup" ) ) {
+ i = atoi(arg2);
+ if(i) {
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "g_doWarmup \"1\"" );
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Enable warmup?" );
+ }
+ else {
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "g_doWarmup \"0\"" );
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Disable warmup?" );
+ }
+ } else if ( !Q_stricmp( arg1, "clientkick" ) ) {
+ i = atoi(arg2);
+
+ if(i>=MAX_CLIENTS) { //Only numbers <128 is clients
+ trap_SendServerCommand( ent-g_entities, "print \"Cannot kick that number.\n\"" );
+ return;
+ }
+ level.voteKickClient = i;
+ if(g_voteBan.integer<1) {
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "clientkick_game \"%d\"", i );
+ } else {
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "!ban \"%d\" \"%dm\" \"Banned by public vote\"", i, g_voteBan.integer );
+ level.voteKickType = 1; //ban
+ }
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Kick %s?" , level.clients[i].pers.netname );
+ } else if ( !Q_stricmp( arg1, "shuffle" ) ) {
+ if(g_gametype.integer<GT_TEAM || g_ffa_gt==1) { //Not a team game
+ trap_SendServerCommand( ent-g_entities, "print \"Can only be used in team games.\n\"" );
+ return;
+ }
+
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "shuffle" );
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Shuffle teams?" );
+ } else if ( !Q_stricmp( arg1, "kick" ) ) {
+ i = 0;
+ while(Q_stricmp(arg2,(g_entities+i)->client->pers.netname)) {
+ //Not client i, try next
+ i++;
+ if(i>=MAX_CLIENTS){ //Only numbers <128 is clients
+ trap_SendServerCommand( ent-g_entities, "print \"Cannot find the playername. Try clientkick instead.\n\"" );
+ return;
+ }
+ }
+ level.voteKickClient = i;
+ if(g_voteBan.integer<1) {
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "clientkick_game \"%d\"", i );
+ } else {
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "!ban \"%d\" \"%dm\" \"Banned by public vote\"", i, g_voteBan.integer );
+ level.voteKickType = 1; //ban
+ }
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Kick %s?" , level.clients[i].pers.netname );
+ } else if ( !Q_stricmp( arg1, "custom" ) ) {
+ t_customvote customvote;
+ //Sago: There must always be a test to ensure that length(arg2) is non-zero or the client might be able to execute random commands.
+ if(strlen(arg2)<1) {
+ trap_SendServerCommand( ent-g_entities, va("print \"Custom vote commands are: %s\n\"",custom_vote_info) );
+ return;
+ }
+ customvote = getCustomVote(arg2);
+ if(Q_stricmp(customvote.votename,arg2)) {
+ trap_SendServerCommand( ent-g_entities, "print \"Command could not be found\n\"" );
+ return;
+ }
+ Com_sprintf( level.voteString, sizeof( level.voteString ), "%s", customvote.command );
+ if(strlen(customvote.displayname))
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", customvote.displayname );
+ else
+ Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", customvote.command );
+ } else {
+ //Com_sprintf( level.voteString, sizeof( level.voteString ), "%s \"%s\"", arg1, arg2 );
+ //Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString );
+ trap_SendServerCommand( ent-g_entities, "print \"Server vality check failed, appears to be my fault. Sorry\n\"" );
+ return;
+ }
+
+ ent->client->pers.voteCount++;
+ trap_SendServerCommand( -1, va("print \"%s called a vote.\n\"", ent->client->pers.netname ) );
+
+ // start the voting, the caller autoamtically votes yes
+ level.voteTime = level.time;
+ level.voteYes = 1;
+ level.voteNo = 0;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ level.clients[i].ps.eFlags &= ~EF_VOTED;
+ level.clients[i].vote = 0;
+ }
+ ent->client->ps.eFlags |= EF_VOTED;
+ ent->client->vote = 1;
+ //Do a first count to make sure that numvotingclients is correct!
+ CountVotes();
+
+ trap_SetConfigstring( CS_VOTE_TIME, va("%i", level.voteTime ) );
+ trap_SetConfigstring( CS_VOTE_STRING, level.voteDisplayString );
+ trap_SetConfigstring( CS_VOTE_YES, va("%i", level.voteYes ) );
+ trap_SetConfigstring( CS_VOTE_NO, va("%i", level.voteNo ) );
+}
+
+/*
+==================
+Cmd_Vote_f
+==================
+*/
+void Cmd_Vote_f( gentity_t *ent ) {
+ char msg[64];
+
+ if ( !level.voteTime ) {
+ trap_SendServerCommand( ent-g_entities, "print \"No vote in progress.\n\"" );
+ return;
+ }
+ /*if ( ent->client->ps.eFlags & EF_VOTED ) {
+ trap_SendServerCommand( ent-g_entities, "print \"Vote already cast.\n\"" );
+ return;
+ }*/
+ if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
+ trap_SendServerCommand( ent-g_entities, "print \"Not allowed to vote as spectator.\n\"" );
+ return;
+ }
+
+ trap_SendServerCommand( ent-g_entities, "print \"Vote cast.\n\"" );
+
+ ent->client->ps.eFlags |= EF_VOTED;
+
+ trap_Argv( 1, msg, sizeof( msg ) );
+
+ if ( msg[0] == 'y' || msg[1] == 'Y' || msg[1] == '1' ) {
+ ent->client->vote = 1;
+ } else {
+ ent->client->vote = -1;
+ }
+
+ //Re count the votes
+ CountVotes();
+
+ // a majority will be determined in CheckVote, which will also account
+ // for players entering or leaving
+}
+
+/*
+==================
+Cmd_CallTeamVote_f
+==================
+*/
+void Cmd_CallTeamVote_f( gentity_t *ent ) {
+ int i, team, cs_offset;
+ char arg1[MAX_STRING_TOKENS];
+ char arg2[MAX_STRING_TOKENS];
+
+ team = ent->client->sess.sessionTeam;
+ if ( team == TEAM_RED )
+ cs_offset = 0;
+ else if ( team == TEAM_BLUE )
+ cs_offset = 1;
+ else
+ return;
+
+ if ( !g_allowVote.integer ) {
+ trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here.\n\"" );
+ return;
+ }
+
+ if ( level.teamVoteTime[cs_offset] ) {
+ trap_SendServerCommand( ent-g_entities, "print \"A team vote is already in progress.\n\"" );
+ return;
+ }
+ if ( ent->client->pers.teamVoteCount >= g_maxvotes.integer ) {
+ trap_SendServerCommand( ent-g_entities, "print \"You have called the maximum number of team votes.\n\"" );
+ return;
+ }
+ if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
+ trap_SendServerCommand( ent-g_entities, "print \"Not allowed to call a vote as spectator.\n\"" );
+ return;
+ }
+
+ // make sure it is a valid command to vote on
+ trap_Argv( 1, arg1, sizeof( arg1 ) );
+ arg2[0] = '\0';
+ for ( i = 2; i < trap_Argc(); i++ ) {
+ if (i > 2)
+ strcat(arg2, " ");
+ trap_Argv( i, &arg2[strlen(arg2)], sizeof( arg2 ) - strlen(arg2) );
+ }
+
+ if( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) {
+ trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
+ return;
+ }
+
+ if ( !Q_stricmp( arg1, "leader" ) ) {
+ char netname[MAX_NETNAME], leader[MAX_NETNAME];
+
+ if ( !arg2[0] ) {
+ i = ent->client->ps.clientNum;
+ }
+ else {
+ // numeric values are just slot numbers
+ for (i = 0; i < 3; i++) {
+ if ( !arg2[i] || arg2[i] < '0' || arg2[i] > '9' )
+ break;
+ }
+ if ( i >= 3 || !arg2[i]) {
+ i = atoi( arg2 );
+ if ( i < 0 || i >= level.maxclients ) {
+ trap_SendServerCommand( ent-g_entities, va("print \"Bad client slot: %i\n\"", i) );
+ return;
+ }
+
+ if ( !g_entities[i].inuse ) {
+ trap_SendServerCommand( ent-g_entities, va("print \"Client %i is not active\n\"", i) );
+ return;
+ }
+ }
+ else {
+ Q_strncpyz(leader, arg2, sizeof(leader));
+ Q_CleanStr(leader);
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[i].pers.connected == CON_DISCONNECTED )
+ continue;
+ if (level.clients[i].sess.sessionTeam != team)
+ continue;
+ Q_strncpyz(netname, level.clients[i].pers.netname, sizeof(netname));
+ Q_CleanStr(netname);
+ if ( !Q_stricmp(netname, leader) ) {
+ break;
+ }
+ }
+ if ( i >= level.maxclients ) {
+ trap_SendServerCommand( ent-g_entities, va("print \"%s is not a valid player on your team.\n\"", arg2) );
+ return;
+ }
+ }
+ }
+ Com_sprintf(arg2, sizeof(arg2), "%d", i);
+ } else {
+ trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
+ trap_SendServerCommand( ent-g_entities, "print \"Team vote commands are: leader <player>.\n\"" );
+ return;
+ }
+
+ Com_sprintf( level.teamVoteString[cs_offset], sizeof( level.teamVoteString[cs_offset] ), "%s %s", arg1, arg2 );
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[i].pers.connected == CON_DISCONNECTED )
+ continue;
+ if (level.clients[i].sess.sessionTeam == team)
+ trap_SendServerCommand( i, va("print \"%s called a team vote.\n\"", ent->client->pers.netname ) );
+ }
+
+ // start the voting, the caller autoamtically votes yes
+ level.teamVoteTime[cs_offset] = level.time;
+ level.teamVoteYes[cs_offset] = 1;
+ level.teamVoteNo[cs_offset] = 0;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if (level.clients[i].sess.sessionTeam == team)
+ level.clients[i].ps.eFlags &= ~EF_TEAMVOTED;
+ }
+ ent->client->ps.eFlags |= EF_TEAMVOTED;
+
+ trap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, va("%i", level.teamVoteTime[cs_offset] ) );
+ trap_SetConfigstring( CS_TEAMVOTE_STRING + cs_offset, level.teamVoteString[cs_offset] );
+ trap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, va("%i", level.teamVoteYes[cs_offset] ) );
+ trap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, va("%i", level.teamVoteNo[cs_offset] ) );
+}
+
+/*
+==================
+Cmd_TeamVote_f
+==================
+*/
+void Cmd_TeamVote_f( gentity_t *ent ) {
+ int team, cs_offset;
+ char msg[64];
+
+ team = ent->client->sess.sessionTeam;
+ if ( team == TEAM_RED )
+ cs_offset = 0;
+ else if ( team == TEAM_BLUE )
+ cs_offset = 1;
+ else
+ return;
+
+ if ( !level.teamVoteTime[cs_offset] ) {
+ trap_SendServerCommand( ent-g_entities, "print \"No team vote in progress.\n\"" );
+ return;
+ }
+ if ( ent->client->ps.eFlags & EF_TEAMVOTED ) {
+ trap_SendServerCommand( ent-g_entities, "print \"Team vote already cast.\n\"" );
+ return;
+ }
+ if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
+ trap_SendServerCommand( ent-g_entities, "print \"Not allowed to vote as spectator.\n\"" );
+ return;
+ }
+
+ trap_SendServerCommand( ent-g_entities, "print \"Team vote cast.\n\"" );
+
+ ent->client->ps.eFlags |= EF_TEAMVOTED;
+
+ trap_Argv( 1, msg, sizeof( msg ) );
+
+ if ( msg[0] == 'y' || msg[1] == 'Y' || msg[1] == '1' ) {
+ level.teamVoteYes[cs_offset]++;
+ trap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, va("%i", level.teamVoteYes[cs_offset] ) );
+ } else {
+ level.teamVoteNo[cs_offset]++;
+ trap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, va("%i", level.teamVoteNo[cs_offset] ) );
+ }
+
+ // a majority will be determined in TeamCheckVote, which will also account
+ // for players entering or leaving
+}
+
+
+/*
+=================
+Cmd_SetViewpos_f
+=================
+*/
+void Cmd_SetViewpos_f( gentity_t *ent ) {
+ vec3_t origin, angles;
+ char buffer[MAX_TOKEN_CHARS];
+ int i;
+
+ if ( !g_cheats.integer ) {
+ trap_SendServerCommand( ent-g_entities, va("print \"Cheats are not enabled on this server.\n\""));
+ return;
+ }
+ if ( trap_Argc() != 5 ) {
+ trap_SendServerCommand( ent-g_entities, va("print \"usage: setviewpos x y z yaw\n\""));
+ return;
+ }
+
+ VectorClear( angles );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ trap_Argv( i + 1, buffer, sizeof( buffer ) );
+ origin[i] = atof( buffer );
+ }
+
+ trap_Argv( 4, buffer, sizeof( buffer ) );
+ angles[YAW] = atof( buffer );
+
+ TeleportPlayer( ent, origin, angles );
+}
+
+
+
+/*
+=================
+Cmd_Stats_f
+=================
+*/
+void Cmd_Stats_f( gentity_t *ent ) {
+/*
+ int max, n, i;
+
+ max = trap_AAS_PointReachabilityAreaIndex( NULL );
+
+ n = 0;
+ for ( i = 0; i < max; i++ ) {
+ if ( ent->client->areabits[i >> 3] & (1 << (i & 7)) )
+ n++;
+ }
+
+ //trap_SendServerCommand( ent-g_entities, va("print \"visited %d of %d areas\n\"", n, max));
+ trap_SendServerCommand( ent-g_entities, va("print \"%d%% level coverage\n\"", n * 100 / max));
+*/
+}
+
+void Cmd_GetMappage_f( gentity_t *ent ) {
+ t_mappage page;
+ char string[(MAX_MAPNAME+1)*MAPS_PER_PAGE+1];
+ char arg[MAX_STRING_TOKENS];
+ trap_Argv( 1, arg, sizeof( arg ) );
+ page = getMappage(atoi(arg));
+ Q_strncpyz(string,va("mappage %d %s %s %s %s %s %s %s %s %s %s",page.pagenumber,page.mapname[0],\
+ page.mapname[1],page.mapname[2],page.mapname[3],page.mapname[4],page.mapname[5],\
+ page.mapname[6],page.mapname[7],page.mapname[8],page.mapname[9]),sizeof(string));
+ //G_Printf("Mappage sent: \"%s\"\n", string);
+ trap_SendServerCommand( ent-g_entities, string );
+}
+
+//KK-OAX This is the table that ClientCommands runs the console entry against.
+commands_t cmds[ ] =
+{
+ // normal commands
+ { "team", 0, Cmd_Team_f },
+ { "vote", 0, Cmd_Vote_f },
+ /*{ "ignore", 0, Cmd_Ignore_f },
+ { "unignore", 0, Cmd_Ignore_f },*/
+
+ // communication commands
+ { "tell", CMD_MESSAGE, Cmd_Tell_f },
+ { "callvote", CMD_MESSAGE, Cmd_CallVote_f },
+ { "callteamvote", CMD_MESSAGE|CMD_TEAM, Cmd_CallTeamVote_f },
+ // can be used even during intermission
+ { "say", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
+ { "say_team", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
+ { "vsay", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Voice_f },
+ { "vsay_team", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Voice_f },
+ { "vsay_local", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Voice_f },
+ { "vtell", CMD_MESSAGE|CMD_INTERMISSION, Cmd_VoiceTell_f },
+ { "vosay", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Voice_f },
+ { "vosay_team", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Voice_f },
+ { "vosay_local", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Voice_f },
+ { "votell", CMD_MESSAGE|CMD_INTERMISSION, Cmd_VoiceTell_f },
+ { "vtaunt", CMD_MESSAGE|CMD_INTERMISSION, Cmd_VoiceTaunt_f },
+ /*{ "m", CMD_MESSAGE|CMD_INTERMISSION, Cmd_PrivateMessage_f },
+ { "mt", CMD_MESSAGE|CMD_INTERMISSION, Cmd_PrivateMessage_f },
+ { "a", CMD_MESSAGE|CMD_INTERMISSION, Cmd_AdminMessage_f },*/
+
+ { "score", CMD_INTERMISSION, Cmd_Score_f },
+ { "acc", CMD_INTERMISSION, Cmd_Acc_f},
+
+ // cheats
+ { "give", CMD_CHEAT|CMD_LIVING, Cmd_Give_f },
+ { "god", CMD_CHEAT|CMD_LIVING, Cmd_God_f },
+ { "notarget", CMD_CHEAT|CMD_LIVING, Cmd_Notarget_f },
+ { "levelshot", CMD_CHEAT, Cmd_LevelShot_f },
+ { "setviewpos", CMD_CHEAT, Cmd_SetViewpos_f },
+ { "noclip", CMD_CHEAT, Cmd_Noclip_f },
+
+ { "kill", CMD_TEAM|CMD_LIVING, Cmd_Kill_f },
+ { "where", 0, Cmd_Where_f },
+
+ // game commands
+
+ { "follow", CMD_NOTEAM, Cmd_Follow_f },
+ { "follownext", CMD_NOTEAM, Cmd_FollowCycle_f },
+ { "followprev", CMD_NOTEAM, Cmd_FollowCycle_f },
+
+ { "teamvote", CMD_TEAM, Cmd_TeamVote_f },
+ { "teamtask", CMD_TEAM, Cmd_TeamTask_f },
+ //KK-OAX
+ { "freespectator", CMD_NOTEAM, StopFollowing },
+ { "getmappage", 0, Cmd_GetMappage_f },
+ { "gc", 0, Cmd_GameCommand_f }
+
+};
+
+static int numCmds = sizeof( cmds ) / sizeof( cmds[ 0 ] );
+
+/*
+=================
+ClientCommand
+KK-OAX, Takes the client command and runs it through a loop which matches
+it against the table.
+=================
+*/
+void ClientCommand( int clientNum )
+{
+ gentity_t *ent;
+ char cmd[ MAX_TOKEN_CHARS ];
+ int i;
+
+ ent = g_entities + clientNum;
+ if( !ent->client )
+ return; // not fully in game yet
+
+ trap_Argv( 0, cmd, sizeof( cmd ) );
+
+ for( i = 0; i < numCmds; i++ )
+ {
+ if( Q_stricmp( cmd, cmds[ i ].cmdName ) == 0 )
+ break;
+ }
+
+ if( i == numCmds )
+ { // KK-OAX Admin Command Check
+ if( !G_admin_cmd_check( ent, qfalse ) )
+ trap_SendServerCommand( clientNum,
+ va( "print \"Unknown command %s\n\"", cmd ) );
+ return;
+ }
+
+ // do tests here to reduce the amount of repeated code
+ if( !( cmds[ i ].cmdFlags & CMD_INTERMISSION ) && level.intermissiontime )
+ return;
+
+ if( cmds[ i ].cmdFlags & CMD_CHEAT && !g_cheats.integer )
+ {
+ trap_SendServerCommand( clientNum,
+ "print \"Cheats are not enabled on this server\n\"" );
+ return;
+ }
+ //KK-OAX When the corresponding code is integrated, I will activate these.
+ //if( cmds[ i ].cmdFlags & CMD_MESSAGE &&
+ // ( ent->client->pers.muted || G_FloodLimited( ent ) ) )
+ // return;
+
+ //KK-OAX Do I need to change this for FFA gametype?
+ if( cmds[ i ].cmdFlags & CMD_TEAM &&
+ ent->client->sess.sessionTeam == TEAM_SPECTATOR )
+ {
+ trap_SendServerCommand( clientNum, "print \"Join a team first\n\"" );
+ return;
+ }
+
+ if( ( cmds[ i ].cmdFlags & CMD_NOTEAM ||
+ ( cmds[ i ].cmdFlags & CMD_CHEAT_TEAM && !g_cheats.integer ) ) &&
+ ent->client->sess.sessionTeam != TEAM_NONE )
+ {
+ trap_SendServerCommand( clientNum,
+ "print \"Cannot use this command when on a team\n\"" );
+ return;
+ }
+
+ if( cmds[ i ].cmdFlags & CMD_RED &&
+ ent->client->sess.sessionTeam != TEAM_RED )
+ {
+ trap_SendServerCommand( clientNum,
+ "print \"Must be on the Red Team to use this command\n\"" );
+ return;
+ }
+
+ if( cmds[ i ].cmdFlags & CMD_BLUE &&
+ ent->client->sess.sessionTeam != TEAM_BLUE )
+ {
+ trap_SendServerCommand( clientNum,
+ "print \"Must be on the Blue Team to use this command\n\"" );
+ return;
+ }
+
+ if( ( ent->client->ps.pm_type == PM_DEAD ) && ( cmds[ i ].cmdFlags & CMD_LIVING ) )
+ {
+ trap_SendServerCommand( clientNum,
+ "print \"Must be alive to use this command\n\"" );
+ return;
+ }
+
+ cmds[ i ].cmdHandler( ent );
+}
+
diff --git a/game/code/game/g_cmds_ext.c b/code/game/g_cmds_ext.c
similarity index 100%
rename from game/code/game/g_cmds_ext.c
rename to code/game/g_cmds_ext.c
diff --git a/code/game/g_combat.c b/code/game/g_combat.c
new file mode 100644
index 0000000..8c61944
--- /dev/null
+++ b/code/game/g_combat.c
@@ -0,0 +1,1453 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// g_combat.c
+
+#include "g_local.h"
+#include "challenges.h"
+
+/*
+============
+ScorePlum
+============
+*/
+void ScorePlum( gentity_t *ent, vec3_t origin, int score ) {
+ gentity_t *plum;
+
+ plum = G_TempEntity( origin, EV_SCOREPLUM );
+ // only send this temp entity to a single client
+ plum->r.svFlags |= SVF_SINGLECLIENT;
+ plum->r.singleClient = ent->s.number;
+ //
+ plum->s.otherEntityNum = ent->s.number;
+ plum->s.time = score;
+}
+
+/*
+============
+AddScore
+
+Adds score to both the client and his team
+============
+*/
+void AddScore( gentity_t *ent, vec3_t origin, int score ) {
+ int i;
+
+ if ( !ent->client ) {
+ return;
+ }
+ // no scoring during pre-match warmup
+ if ( level.warmupTime ) {
+ return;
+ }
+
+ //No scoring during intermission
+ if ( level.intermissiontime ) {
+ return;
+ }
+ // show score plum
+ if( level.numNonSpectatorClients<3 && score < 0 && (g_gametype.integer<GT_TEAM || g_ffa_gt==1)) {
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[ i ].pers.connected != CON_CONNECTED )
+ continue; //Client was not connected
+
+ if (level.clients[i].sess.sessionTeam == TEAM_SPECTATOR)
+ continue; //Don't give anything to spectators
+
+ if (g_entities+i == ent)
+ continue; //Don't award dead one
+
+ level.clients[i].ps.persistant[PERS_SCORE] -= score;
+ ScorePlum(ent, origin, -score);
+ }
+ }
+ else {
+ ScorePlum(ent, origin, score);
+ //
+ ent->client->ps.persistant[PERS_SCORE] += score;
+ if ( g_gametype.integer == GT_TEAM ) {
+ int team = ent->client->ps.persistant[PERS_TEAM];
+ level.teamScores[ team ] += score;
+ G_LogPrintf("TeamScore: %i %i: Team %d now has %d points\n",
+ team, level.teamScores[ team ], team, level.teamScores[ team ] );
+ }
+ }
+ G_LogPrintf("PlayerScore: %i %i: %s now has %d points\n",
+ ent->s.number, ent->client->ps.persistant[PERS_SCORE], ent->client->pers.netname, ent->client->ps.persistant[PERS_SCORE] );
+ CalculateRanks();
+}
+
+/*
+=================
+TossClientItems
+
+Toss the weapon and powerups for the killed player
+=================
+*/
+void TossClientItems( gentity_t *self ) {
+ gitem_t *item;
+ int weapon;
+ float angle;
+ int i;
+ gentity_t *drop;
+
+ // drop the weapon if not a gauntlet or machinegun
+ weapon = self->s.weapon;
+
+ //Never drop in elimination or last man standing mode!
+ if( g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_LMS)
+ return;
+
+ // make a special check to see if they are changing to a new
+ // weapon that isn't the mg or gauntlet. Without this, a client
+ // can pick up a weapon, be killed, and not drop the weapon because
+ // their weapon change hasn't completed yet and they are still holding the MG.
+ if ( weapon == WP_MACHINEGUN || weapon == WP_GRAPPLING_HOOK ) {
+ if ( self->client->ps.weaponstate == WEAPON_DROPPING ) {
+ weapon = self->client->pers.cmd.weapon;
+ }
+ if ( !( self->client->ps.stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
+ weapon = WP_NONE;
+ }
+ }
+
+ if (g_instantgib.integer || g_rockets.integer || g_gametype.integer == GT_CTF_ELIMINATION || g_elimination_allgametypes.integer){
+ //Nothing!
+ }
+ else
+ if ( weapon > WP_MACHINEGUN && weapon != WP_GRAPPLING_HOOK &&
+ self->client->ps.ammo[ weapon ] ) {
+ // find the item type for this weapon
+ item = BG_FindItemForWeapon( weapon );
+
+ // spawn the item
+ Drop_Item( self, item, 0 );
+ }
+
+ // drop all the powerups if not in teamplay
+ if ( g_gametype.integer != GT_TEAM ) {
+ angle = 45;
+ for ( i = 1 ; i < PW_NUM_POWERUPS ; i++ ) {
+ if ( self->client->ps.powerups[ i ] > level.time ) {
+ item = BG_FindItemForPowerup( i );
+ if ( !item ) {
+ continue;
+ }
+ drop = Drop_Item( self, item, angle );
+ // decide how many seconds it has left
+ drop->count = ( self->client->ps.powerups[ i ] - level.time ) / 1000;
+ if ( drop->count < 1 ) {
+ drop->count = 1;
+ }
+ angle += 45;
+ }
+ }
+ }
+}
+
+/*
+=================
+TossClientCubes
+=================
+*/
+extern gentity_t *neutralObelisk;
+
+void TossClientCubes( gentity_t *self ) {
+ gitem_t *item;
+ gentity_t *drop;
+ vec3_t velocity;
+ vec3_t angles;
+ vec3_t origin;
+
+ self->client->ps.generic1 = 0;
+
+ // this should never happen but we should never
+ // get the server to crash due to skull being spawned in
+ if (!G_EntitiesFree()) {
+ return;
+ }
+
+ if( self->client->sess.sessionTeam == TEAM_RED ) {
+ item = BG_FindItem( "Red Cube" );
+ }
+ else {
+ item = BG_FindItem( "Blue Cube" );
+ }
+
+ angles[YAW] = (float)(level.time % 360);
+ angles[PITCH] = 0; // always forward
+ angles[ROLL] = 0;
+
+ AngleVectors( angles, velocity, NULL, NULL );
+ VectorScale( velocity, 150, velocity );
+ velocity[2] += 200 + crandom() * 50;
+
+ if( neutralObelisk ) {
+ VectorCopy( neutralObelisk->s.pos.trBase, origin );
+ origin[2] += 44;
+ } else {
+ VectorClear( origin ) ;
+ }
+
+ drop = LaunchItem( item, origin, velocity );
+
+ drop->nextthink = level.time + g_cubeTimeout.integer * 1000;
+ drop->think = G_FreeEntity;
+ drop->spawnflags = self->client->sess.sessionTeam;
+}
+
+/*
+=================
+TossClientPersistantPowerups
+=================
+*/
+void TossClientPersistantPowerups( gentity_t *ent ) {
+ gentity_t *powerup;
+
+ if( !ent->client ) {
+ return;
+ }
+
+ if( !ent->client->persistantPowerup ) {
+ return;
+ }
+
+ powerup = ent->client->persistantPowerup;
+
+ powerup->r.svFlags &= ~SVF_NOCLIENT;
+ powerup->s.eFlags &= ~EF_NODRAW;
+ powerup->r.contents = CONTENTS_TRIGGER;
+ trap_LinkEntity( powerup );
+
+ ent->client->ps.stats[STAT_PERSISTANT_POWERUP] = 0;
+ ent->client->persistantPowerup = NULL;
+}
+
+
+/*
+==================
+LookAtKiller
+==================
+*/
+void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker ) {
+ vec3_t dir;
+ //vec3_t angles;
+
+ if ( attacker && attacker != self ) {
+ VectorSubtract (attacker->s.pos.trBase, self->s.pos.trBase, dir);
+ } else if ( inflictor && inflictor != self ) {
+ VectorSubtract (inflictor->s.pos.trBase, self->s.pos.trBase, dir);
+ } else {
+ self->client->ps.stats[STAT_DEAD_YAW] = self->s.angles[YAW];
+ return;
+ }
+
+ self->client->ps.stats[STAT_DEAD_YAW] = vectoyaw ( dir );
+
+ /*angles[YAW] =*/ vectoyaw ( dir );
+ //angles[PITCH] = 0;
+ //angles[ROLL] = 0;
+}
+
+/*
+==================
+GibEntity
+==================
+*/
+void GibEntity( gentity_t *self, int killer ) {
+ gentity_t *ent;
+ int i;
+
+ //if this entity still has kamikaze
+ if (self->s.eFlags & EF_KAMIKAZE) {
+ // check if there is a kamikaze timer around for this owner
+ for (i = 0; i < MAX_GENTITIES; i++) {
+ ent = &g_entities[i];
+ if (!ent->inuse)
+ continue;
+ if (ent->activator != self)
+ continue;
+ if (strcmp(ent->classname, "kamikaze timer"))
+ continue;
+ G_FreeEntity(ent);
+ break;
+ }
+ }
+ G_AddEvent( self, EV_GIB_PLAYER, killer );
+ self->takedamage = qfalse;
+ self->s.eType = ET_INVISIBLE;
+ self->r.contents = 0;
+}
+
+/*
+==================
+body_die
+==================
+*/
+void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
+ if ( self->health > GIB_HEALTH ) {
+ return;
+ }
+ if ( !g_blood.integer ) {
+ self->health = GIB_HEALTH+1;
+ return;
+ }
+
+ GibEntity( self, 0 );
+}
+
+
+// these are just for logging, the client prints its own messages
+char *modNames[] = {
+ "MOD_UNKNOWN",
+ "MOD_SHOTGUN",
+ "MOD_GAUNTLET",
+ "MOD_MACHINEGUN",
+ "MOD_GRENADE",
+ "MOD_GRENADE_SPLASH",
+ "MOD_ROCKET",
+ "MOD_ROCKET_SPLASH",
+ "MOD_PLASMA",
+ "MOD_PLASMA_SPLASH",
+ "MOD_RAILGUN",
+ "MOD_LIGHTNING",
+ "MOD_BFG",
+ "MOD_BFG_SPLASH",
+ "MOD_WATER",
+ "MOD_SLIME",
+ "MOD_LAVA",
+ "MOD_CRUSH",
+ "MOD_TELEFRAG",
+ "MOD_FALLING",
+ "MOD_SUICIDE",
+ "MOD_TARGET_LASER",
+ "MOD_TRIGGER_HURT",
+ "MOD_NAIL",
+ "MOD_CHAINGUN",
+ "MOD_PROXIMITY_MINE",
+ "MOD_KAMIKAZE",
+ "MOD_JUICED",
+ "MOD_GRAPPLE"
+};
+
+/*
+==================
+Kamikaze_DeathActivate
+==================
+*/
+void Kamikaze_DeathActivate( gentity_t *ent ) {
+ G_StartKamikaze(ent);
+ G_FreeEntity(ent);
+}
+
+/*
+==================
+Kamikaze_DeathTimer
+==================
+*/
+void Kamikaze_DeathTimer( gentity_t *self ) {
+ gentity_t *ent;
+
+ ent = G_Spawn();
+ ent->classname = "kamikaze timer";
+ VectorCopy(self->s.pos.trBase, ent->s.pos.trBase);
+ ent->r.svFlags |= SVF_NOCLIENT;
+ ent->think = Kamikaze_DeathActivate;
+ ent->nextthink = level.time + 5 * 1000;
+
+ ent->activator = self;
+}
+
+
+/*
+==================
+CheckAlmostCapture
+==================
+*/
+void CheckAlmostCapture( gentity_t *self, gentity_t *attacker ) {
+ gentity_t *ent;
+ vec3_t dir;
+ char *classname;
+
+ // if this player was carrying a flag
+ if ( self->client->ps.powerups[PW_REDFLAG] ||
+ self->client->ps.powerups[PW_BLUEFLAG] ||
+ self->client->ps.powerups[PW_NEUTRALFLAG] ) {
+ // get the goal flag this player should have been going for
+ if ( g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTF_ELIMINATION) {
+ if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
+ classname = "team_CTF_blueflag";
+ }
+ else {
+ classname = "team_CTF_redflag";
+ }
+ }
+ else {
+ if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
+ classname = "team_CTF_redflag";
+ }
+ else {
+ classname = "team_CTF_blueflag";
+ }
+ }
+ ent = NULL;
+ do
+ {
+ ent = G_Find(ent, FOFS(classname), classname);
+ } while (ent && (ent->flags & FL_DROPPED_ITEM));
+ // if we found the destination flag and it's not picked up
+ if (ent && !(ent->r.svFlags & SVF_NOCLIENT) ) {
+ // if the player was *very* close
+ VectorSubtract( self->client->ps.origin, ent->s.origin, dir );
+ if ( VectorLength(dir) < 200 ) {
+ self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
+ if ( attacker->client ) {
+ attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
+ }
+ }
+ }
+ }
+}
+
+/*
+==================
+CheckAlmostScored
+==================
+*/
+void CheckAlmostScored( gentity_t *self, gentity_t *attacker ) {
+ gentity_t *ent;
+ vec3_t dir;
+ char *classname;
+
+ // if the player was carrying cubes
+ if ( self->client->ps.generic1 ) {
+ if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
+ classname = "team_redobelisk";
+ }
+ else {
+ classname = "team_blueobelisk";
+ }
+ ent = G_Find(NULL, FOFS(classname), classname);
+ // if we found the destination obelisk
+ if ( ent ) {
+ // if the player was *very* close
+ VectorSubtract( self->client->ps.origin, ent->s.origin, dir );
+ if ( VectorLength(dir) < 200 ) {
+ self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
+ if ( attacker->client ) {
+ attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
+ }
+ }
+ }
+ }
+}
+
+/*
+==================
+player_die
+==================
+*/
+void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
+ gentity_t *ent;
+ int anim;
+ int contents;
+ int killer;
+ int i,counter2;
+ char *killerName, *obit;
+
+ if ( self->client->ps.pm_type == PM_DEAD ) {
+ return;
+ }
+
+ if ( level.intermissiontime ) {
+ return;
+ }
+
+//unlagged - backward reconciliation #2
+ // make sure the body shows up in the client's current position
+ G_UnTimeShiftClient( self );
+//unlagged - backward reconciliation #2
+ //KK-OAX Here is where we run the streak logic.
+ G_RunStreakLogic( attacker, self );
+
+ // check for an almost capture
+ CheckAlmostCapture( self, attacker );
+ // check for a player that almost brought in cubes
+ CheckAlmostScored( self, attacker );
+
+ if (self->client && self->client->hook) {
+ Weapon_HookFree(self->client->hook);
+ }
+ if ((self->client->ps.eFlags & EF_TICKING) && self->activator) {
+ self->client->ps.eFlags &= ~EF_TICKING;
+ self->activator->think = G_FreeEntity;
+ self->activator->nextthink = level.time;
+ }
+ self->client->ps.pm_type = PM_DEAD;
+
+ if ( attacker ) {
+ killer = attacker->s.number;
+ if ( attacker->client ) {
+ killerName = attacker->client->pers.netname;
+ } else {
+ killerName = "<non-client>";
+ }
+ } else {
+ killer = ENTITYNUM_WORLD;
+ killerName = "<world>";
+ }
+
+ if ( killer < 0 || killer >= MAX_CLIENTS ) {
+ killer = ENTITYNUM_WORLD;
+ killerName = "<world>";
+ }
+
+ if ( meansOfDeath < 0 || meansOfDeath >= sizeof( modNames ) / sizeof( modNames[0] ) ) {
+ obit = "<bad obituary>";
+ } else {
+ obit = modNames[meansOfDeath];
+ }
+
+ G_LogPrintf("Kill: %i %i %i: %s killed %s by %s\n",
+ killer, self->s.number, meansOfDeath, killerName,
+ self->client->pers.netname, obit );
+
+ // broadcast the death event to everyone
+ ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
+ ent->s.eventParm = meansOfDeath;
+ ent->s.otherEntityNum = self->s.number;
+ ent->s.otherEntityNum2 = killer;
+ //Sago: Hmmm... generic? Can I transmit anything I like? Like if it is a team kill? Let's try
+ ent->s.generic1 = OnSameTeam (self, attacker);
+ if( !((g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION) && level.time < level.roundStartTime) )
+ ent->r.svFlags = SVF_BROADCAST; // send to everyone (if not an elimination gametype during active warmup)
+ else
+ ent->r.svFlags = SVF_NOCLIENT;
+
+ self->enemy = attacker;
+
+ self->client->ps.persistant[PERS_KILLED]++;
+
+ if (attacker && attacker->client) {
+ attacker->client->lastkilled_client = self->s.number;
+
+ if ( attacker == self || OnSameTeam (self, attacker ) ) {
+ if(g_gametype.integer!=GT_LMS && !((g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION) && level.time < level.roundStartTime))
+ if( (g_gametype.integer <GT_TEAM && g_ffa_gt!=1 && self->client->ps.persistant[PERS_SCORE]>0) || level.numNonSpectatorClients<3) //Cannot get negative scores by suicide
+ AddScore( attacker, self->r.currentOrigin, -1 );
+ } else {
+ if(g_gametype.integer!=GT_LMS)
+ AddScore( attacker, self->r.currentOrigin, 1 );
+
+ if( meansOfDeath == MOD_GAUNTLET ) {
+
+ // Attack gets a challenge complete:
+ if(!(attacker->r.svFlags & SVF_BOT) && !(self->r.svFlags & SVF_BOT))
+ ChallengeMessage(attacker,WEAPON_GAUNTLET_KILLS);
+
+ // play humiliation on player
+ attacker->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 0, attacker->client->pers.netname, "GAUNTLET" );
+
+ // add the sprite over the player's head
+ attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ attacker->client->ps.eFlags |= EF_AWARD_GAUNTLET;
+ attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+
+ // also play humiliation on target
+ self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_GAUNTLETREWARD;
+ }
+
+ //If neither attacker or taget is bots and not the same
+ if(!(attacker->r.svFlags & SVF_BOT) && !(self->r.svFlags & SVF_BOT) && self!=attacker)
+ {
+ switch(meansOfDeath)
+ {
+ case MOD_GAUNTLET:
+ ChallengeMessage(attacker,WEAPON_GAUNTLET_KILLS);
+ break;
+ case MOD_MACHINEGUN:
+ ChallengeMessage(attacker,WEAPON_MACHINEGUN_KILLS);
+ break;
+ case MOD_SHOTGUN:
+ ChallengeMessage(attacker,WEAPON_SHOTGUN_KILLS);
+ break;
+ case MOD_GRENADE:
+ case MOD_GRENADE_SPLASH:
+ ChallengeMessage(attacker,WEAPON_GRANADE_KILLS);
+ break;
+ case MOD_ROCKET:
+ case MOD_ROCKET_SPLASH:
+ ChallengeMessage(attacker,WEAPON_ROCKET_KILLS);
+ break;
+ case MOD_LIGHTNING:
+ ChallengeMessage(attacker,WEAPON_LIGHTNING_KILLS);
+ break;
+ case MOD_PLASMA:
+ case MOD_PLASMA_SPLASH:
+ ChallengeMessage(attacker,WEAPON_PLASMA_KILLS);
+ break;
+ case MOD_RAILGUN:
+ if(g_instantgib.integer)
+ ChallengeMessage(attacker,WEAPON_INSTANT_RAIL_KILLS);
+ else
+ ChallengeMessage(attacker,WEAPON_RAIL_KILLS);
+ break;
+ case MOD_BFG:
+ case MOD_BFG_SPLASH:
+ ChallengeMessage(attacker,WEAPON_BFG_KILLS);
+ break;
+ case MOD_NAIL:
+ ChallengeMessage(attacker,WEAPON_NAILGUN_KILLS);
+ break;
+ case MOD_CHAINGUN:
+ ChallengeMessage(attacker,WEAPON_CHAINGUN_KILLS);
+ break;
+ case MOD_PROXIMITY_MINE:
+ ChallengeMessage(attacker,WEAPON_MINE_KILLS);
+ break;
+ case MOD_GRAPPLE:
+ ChallengeMessage(attacker,WEAPON_GRAPPLE_KILLS);
+ break;
+ case MOD_LAVA:
+ case MOD_SLIME:
+ case MOD_TRIGGER_HURT:
+ case MOD_FALLING:
+ ChallengeMessage(attacker,WEAPON_PUSH_KILLS);
+ break;
+ case MOD_CRUSH:
+ ChallengeMessage(attacker,WEAPON_CRUSH_KILLS);
+ break;
+ case MOD_TELEFRAG:
+ ChallengeMessage(attacker,WEAPON_TELEFRAG_KILLS);
+ break;
+ };
+ ChallengeMessage(attacker,GENERAL_TOTALKILLS);
+ ChallengeMessage(self,GENERAL_TOTALDEATHS);
+
+ //Lets count number of powerups:
+ i = 0;
+ counter2 = 0;
+
+ if(attacker->client->ps.powerups[PW_QUAD]) {
+ ChallengeMessage(attacker,POWERUP_QUAD_KILL);
+ counter2++;
+ }
+ if(self->client->ps.powerups[PW_QUAD]) {
+ ChallengeMessage(attacker,POWERUP_COUNTER_QUAD);
+ i++;
+ }
+
+ if(attacker->client->ps.powerups[PW_HASTE]) {
+ ChallengeMessage(attacker,POWERUP_SPEED_KILL);
+ counter2++;
+ }
+ if(self->client->ps.powerups[PW_HASTE]) {
+ ChallengeMessage(attacker,POWERUP_COUNTER_SPEED);
+ i++;
+ }
+
+ if(attacker->client->ps.powerups[PW_INVIS]) {
+ ChallengeMessage(attacker,POWERUP_INVIS_KILL);
+ counter2++;
+ }
+ if(self->client->ps.powerups[PW_INVIS]) {
+ ChallengeMessage(attacker,POWERUP_COUNTER_INVIS);
+ i++;
+ }
+
+ if(attacker->client->ps.powerups[PW_FLIGHT]) {
+ ChallengeMessage(attacker,POWERUP_FLIGHT_KILL);
+ counter2++;
+ }
+ if(self->client->ps.powerups[PW_FLIGHT]) {
+ ChallengeMessage(attacker,POWERUP_COUNTER_FLIGHT);
+ i++;
+ }
+
+ if(self->client->ps.powerups[PW_BATTLESUIT]) {
+ ChallengeMessage(attacker,POWERUP_COUNTER_ENVIR);
+ i++;
+ }
+
+ if(self->client->ps.powerups[PW_REGEN]) {
+ ChallengeMessage(attacker,POWERUP_COUNTER_REGEN);
+ i++;
+ }
+
+ if(i>1) //The target had more than one powerup
+ ChallengeMessage(attacker,POWERUP_COUNTER_MULTI);
+ if(counter2>1) //The attacker has more than one powerup
+ ChallengeMessage(attacker,POWERUP_MULTI_KILL);
+ }
+
+ // check for two kills in a short amount of time
+ // if this is close enough to the last kill, give a reward sound
+ if ( level.time - attacker->client->lastKillTime < CARNAGE_REWARD_TIME ) {
+ // KK-OAX
+ // Check if Multikills are enabled
+ if( g_altExcellent.integer ) {
+ attacker->client->pers.multiKillCount++;
+ G_checkForMultiKill( attacker );
+ } // play excellent on player
+ attacker->client->ps.persistant[PERS_EXCELLENT_COUNT]++;
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 1, attacker->client->pers.netname, "EXCELLENT" );
+ if(!level.hadBots) //There has not been any bots
+ ChallengeMessage(attacker,AWARD_EXCELLENT);
+ // add the sprite over the player's head
+ attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ attacker->client->ps.eFlags |= EF_AWARD_EXCELLENT;
+ attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+ } else {
+ //KK-OAX Clear multikill count
+ //Must be 1 so the correct number of kills are displayed to the clients.
+ attacker->client->pers.multiKillCount = 1;
+ }
+ attacker->client->lastKillTime = level.time;
+ }
+ } else {
+ if(g_gametype.integer!=GT_LMS && !((g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION) && level.time < level.roundStartTime))
+ if(self->client->ps.persistant[PERS_SCORE]>0 || level.numNonSpectatorClients<3) //Cannot get negative scores by suicide
+ AddScore( self, self->r.currentOrigin, -1 );
+ }
+
+ // Add team bonuses
+ Team_FragBonuses(self, inflictor, attacker);
+
+ // if I committed suicide, the flag does not fall, it returns.
+ if (meansOfDeath == MOD_SUICIDE) {
+ if ( self->client->ps.powerups[PW_NEUTRALFLAG] ) { // only happens in One Flag CTF
+ Team_ReturnFlag( TEAM_FREE );
+ self->client->ps.powerups[PW_NEUTRALFLAG] = 0;
+ }
+ else if ( self->client->ps.powerups[PW_REDFLAG] ) { // only happens in standard CTF
+ Team_ReturnFlag( TEAM_RED );
+ self->client->ps.powerups[PW_REDFLAG] = 0;
+ }
+ else if ( self->client->ps.powerups[PW_BLUEFLAG] ) { // only happens in standard CTF
+ Team_ReturnFlag( TEAM_BLUE );
+ self->client->ps.powerups[PW_BLUEFLAG] = 0;
+ }
+ }
+ TossClientPersistantPowerups( self );
+ if( g_gametype.integer == GT_HARVESTER ) {
+ TossClientCubes( self );
+ }
+ // if client is in a nodrop area, don't drop anything (but return CTF flags!)
+ TossClientItems( self );
+//#endif
+
+ Cmd_Score_f( self ); // show scores
+ // send updated scores to any clients that are following this one,
+ // or they would get stale scoreboards
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ gclient_t *client;
+
+ client = &level.clients[i];
+ if ( client->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
+ continue;
+ }
+ if ( client->sess.spectatorClient == self->s.number ) {
+ Cmd_Score_f( g_entities + i );
+ }
+ }
+
+ self->takedamage = qtrue; // can still be gibbed
+
+ self->s.weapon = WP_NONE;
+ self->s.powerups = 0;
+ self->r.contents = CONTENTS_CORPSE;
+
+ self->s.angles[0] = 0;
+ self->s.angles[2] = 0;
+ LookAtKiller (self, inflictor, attacker);
+
+ VectorCopy( self->s.angles, self->client->ps.viewangles );
+
+ self->s.loopSound = 0;
+
+ self->r.maxs[2] = -8;
+
+ // don't allow respawn until the death anim is done
+ // g_forcerespawn may force spawning at some later time
+ self->client->respawnTime = level.time + 1700 +i;
+ if(g_respawntime.integer>0) {
+ for(i=0; self->client->respawnTime > i*g_respawntime.integer*1000;i++);
+
+ self->client->respawnTime = i*g_respawntime.integer*1000;
+ }
+ //For testing:
+ //G_Printf("Respawntime: %i\n",self->client->respawnTime);
+ //However during warm up, we should respawn quicker!
+ if(g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS)
+ if(level.time<=level.roundStartTime && level.time>level.roundStartTime-1000*g_elimination_activewarmup.integer)
+ self->client->respawnTime = level.time + rand()%800;
+
+ RespawnTimeMessage(self,self->client->respawnTime);
+
+
+ // remove powerups
+ memset( self->client->ps.powerups, 0, sizeof(self->client->ps.powerups) );
+
+ // never gib in a nodrop
+ contents = trap_PointContents( self->r.currentOrigin, -1 );
+
+ if ( (self->health <= GIB_HEALTH && !(contents & CONTENTS_NODROP) && g_blood.integer) || meansOfDeath == MOD_SUICIDE) {
+ // gib death
+ GibEntity( self, killer );
+ } else {
+ // normal death
+ static int i;
+
+ switch ( i ) {
+ case 0:
+ anim = BOTH_DEATH1;
+ break;
+ case 1:
+ anim = BOTH_DEATH2;
+ break;
+ case 2:
+ default:
+ anim = BOTH_DEATH3;
+ break;
+ }
+
+ // for the no-blood option, we need to prevent the health
+ // from going to gib level
+ if ( self->health <= GIB_HEALTH ) {
+ self->health = GIB_HEALTH+1;
+ }
+
+ self->client->ps.legsAnim =
+ ( ( self->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
+ self->client->ps.torsoAnim =
+ ( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
+
+ G_AddEvent( self, EV_DEATH1 + i, killer );
+
+ // the body can still be gibbed
+ self->die = body_die;
+
+ // globally cycle through the different death animations
+ i = ( i + 1 ) % 3;
+
+ if (self->s.eFlags & EF_KAMIKAZE) {
+ Kamikaze_DeathTimer( self );
+ }
+ }
+
+ trap_LinkEntity (self);
+
+}
+
+
+/*
+================
+CheckArmor
+================
+*/
+int CheckArmor (gentity_t *ent, int damage, int dflags)
+{
+ gclient_t *client;
+ int save;
+ int count;
+
+ if (!damage)
+ return 0;
+
+ client = ent->client;
+
+ if (!client)
+ return 0;
+
+ if (dflags & DAMAGE_NO_ARMOR)
+ return 0;
+
+ // armor
+ count = client->ps.stats[STAT_ARMOR];
+ save = ceil( damage * ARMOR_PROTECTION );
+ if (save >= count)
+ save = count;
+
+ if (!save)
+ return 0;
+
+ client->ps.stats[STAT_ARMOR] -= save;
+
+ return save;
+}
+
+/*
+================
+RaySphereIntersections
+================
+*/
+int RaySphereIntersections( vec3_t origin, float radius, vec3_t point, vec3_t dir, vec3_t intersections[2] ) {
+ float b, c, d, t;
+
+ // | origin - (point + t * dir) | = radius
+ // a = dir[0]^2 + dir[1]^2 + dir[2]^2;
+ // b = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2]));
+ // c = (point[0] - origin[0])^2 + (point[1] - origin[1])^2 + (point[2] - origin[2])^2 - radius^2;
+
+ // normalize dir so a = 1
+ VectorNormalize(dir);
+ b = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2]));
+ c = (point[0] - origin[0]) * (point[0] - origin[0]) +
+ (point[1] - origin[1]) * (point[1] - origin[1]) +
+ (point[2] - origin[2]) * (point[2] - origin[2]) -
+ radius * radius;
+
+ d = b * b - 4 * c;
+ if (d > 0) {
+ t = (- b + sqrt(d)) / 2;
+ VectorMA(point, t, dir, intersections[0]);
+ t = (- b - sqrt(d)) / 2;
+ VectorMA(point, t, dir, intersections[1]);
+ return 2;
+ }
+ else if (d == 0) {
+ t = (- b ) / 2;
+ VectorMA(point, t, dir, intersections[0]);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+================
+G_InvulnerabilityEffect
+================
+*/
+int G_InvulnerabilityEffect( gentity_t *targ, vec3_t dir, vec3_t point, vec3_t impactpoint, vec3_t bouncedir ) {
+ gentity_t *impact;
+ vec3_t intersections[2], vec;
+ int n;
+
+ if ( !targ->client ) {
+ return qfalse;
+ }
+ VectorCopy(dir, vec);
+ VectorInverse(vec);
+ // sphere model radius = 42 units
+ n = RaySphereIntersections( targ->client->ps.origin, 42, point, vec, intersections);
+ if (n > 0) {
+ impact = G_TempEntity( targ->client->ps.origin, EV_INVUL_IMPACT );
+ VectorSubtract(intersections[0], targ->client->ps.origin, vec);
+ vectoangles(vec, impact->s.angles);
+ impact->s.angles[0] += 90;
+ if (impact->s.angles[0] > 360)
+ impact->s.angles[0] -= 360;
+ if ( impactpoint ) {
+ VectorCopy( intersections[0], impactpoint );
+ }
+ if ( bouncedir ) {
+ VectorCopy( vec, bouncedir );
+ VectorNormalize( bouncedir );
+ }
+ return qtrue;
+ }
+ else {
+ return qfalse;
+ }
+}
+
+/*
+catchup_damage
+*/
+static int catchup_damage(int damage, int attacker_points, int target_points) {
+ int newdamage;
+ if(g_catchup.integer <= 0 )
+ return damage;
+ //Reduce damage
+ if(attacker_points<=target_points+5)
+ return damage; //Never reduce damage if only 5 points ahead.
+
+ newdamage=damage-((attacker_points-target_points-5) * (g_catchup.integer*damage))/100;
+ if(newdamage<damage/2)
+ return damage/2;
+ return newdamage;
+}
+
+/*
+============
+T_Damage
+
+targ entity that is being damaged
+inflictor entity that is causing the damage
+attacker entity that caused the inflictor to damage targ
+ example: targ=monster, inflictor=rocket, attacker=player
+
+dir direction of the attack for knockback
+point point at which the damage is being inflicted, used for headshots
+damage amount of damage being inflicted
+knockback force to be applied against targ as a result of the damage
+
+inflictor, attacker, dir, and point can be NULL for environmental effects
+
+dflags these flags are used to control how T_Damage works
+ DAMAGE_RADIUS damage was indirect (from a nearby explosion)
+ DAMAGE_NO_ARMOR armor does not protect from this damage
+ DAMAGE_NO_KNOCKBACK do not affect velocity, just view angles
+ DAMAGE_NO_PROTECTION kills godmode, armor, everything
+============
+*/
+
+void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
+ vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {
+ gclient_t *client;
+ int take;
+ //int save;
+ int asave;
+ int knockback;
+ int max;
+
+ vec3_t bouncedir, impactpoint;
+
+ if (!targ->takedamage) {
+ return;
+ }
+
+ // the intermission has allready been qualified for, so don't
+ // allow any extra scoring
+ if ( level.intermissionQueued ) {
+ return;
+ }
+ if ( targ->client && mod != MOD_JUICED) {
+ if ( targ->client->invulnerabilityTime > level.time) {
+ if ( dir && point ) {
+ G_InvulnerabilityEffect( targ, dir, point, impactpoint, bouncedir );
+ }
+ return;
+ }
+ }
+ //Sago: This was moved up
+ client = targ->client;
+
+ //Sago: See if the client was sent flying
+ //Check if damage is by somebody who is not a player!
+ if( (!attacker || attacker->s.eType != ET_PLAYER) && client && client->lastSentFlying>-1 && ( mod==MOD_FALLING || mod==MOD_LAVA || mod==MOD_SLIME || mod==MOD_TRIGGER_HURT || mod==MOD_SUICIDE) ) {
+ if( client->lastSentFlyingTime+5000<level.time) {
+ client->lastSentFlying = -1; //More than 5 seconds, not a kill!
+ } else {
+ //G_Printf("LastSentFlying %i\n",client->lastSentFlying);
+ attacker = &g_entities[client->lastSentFlying];
+ }
+ }
+
+ if ( !inflictor ) {
+ inflictor = &g_entities[ENTITYNUM_WORLD];
+ }
+ if ( !attacker ) {
+ attacker = &g_entities[ENTITYNUM_WORLD];
+ }
+
+ // shootable doors / buttons don't actually have any health
+ if ( targ->s.eType == ET_MOVER ) {
+ if ( targ->use && targ->moverState == MOVER_POS1 ) {
+ targ->use( targ, inflictor, attacker );
+ }
+ return;
+ }
+ if( g_gametype.integer == GT_OBELISK && CheckObeliskAttack( targ, attacker ) ) {
+ return;
+ }
+ // reduce damage by the attacker's handicap value
+ // unless they are rocket jumping
+ if ( attacker->client && attacker != targ ) {
+ max = attacker->client->ps.stats[STAT_MAX_HEALTH];
+ if( bg_itemlist[attacker->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
+ max /= 2;
+ }
+ damage = damage * max / 100;
+ }
+
+ //Sago: I have moved this up
+ //client = targ->client;
+
+ if ( client ) {
+ if ( client->noclip ) {
+ return;
+ }
+ }
+
+ if ( !dir ) {
+ dflags |= DAMAGE_NO_KNOCKBACK;
+ } else {
+ VectorNormalize(dir);
+ }
+
+ knockback = damage;
+ if ( knockback > 200 ) {
+ knockback = 200;
+ }
+ if ( targ->flags & FL_NO_KNOCKBACK ) {
+ knockback = 0;
+ }
+ if ( dflags & DAMAGE_NO_KNOCKBACK ) {
+ knockback = 0;
+ }
+
+ // figure momentum add, even if the damage won't be taken
+ if ( knockback && targ->client ) {
+ vec3_t kvel;
+ float mass;
+
+ mass = 200;
+
+ VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
+ VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);
+
+ // set the timer so that the other client can't cancel
+ // out the movement immediately
+ if ( !targ->client->ps.pm_time ) {
+ int t;
+
+ t = knockback * 2;
+ if ( t < 50 ) {
+ t = 50;
+ }
+ if ( t > 200 ) {
+ t = 200;
+ }
+ targ->client->ps.pm_time = t;
+ targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
+ }
+ //Remeber the last person to hurt the player
+ if( !g_awardpushing.integer || targ==attacker || OnSameTeam (targ, attacker)) {
+ targ->client->lastSentFlying = -1;
+ } else {
+ /*if ( pm->waterlevel <= 1 ) {
+ if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) {
+ // if getting knocked back, no friction
+ if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) {
+ control = speed < pm_stopspeed ? pm_stopspeed : speed;
+ drop += control*pm_friction*pml.frametime;
+ }
+ }
+ }*/
+ targ->client->lastSentFlying = attacker->s.number;
+ targ->client->lastSentFlyingTime = level.time;
+ }
+ }
+
+ // check for completely getting out of the damage
+ if ( !(dflags & DAMAGE_NO_PROTECTION) ) {
+
+ // if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
+ // if the attacker was on the same team
+ if ( mod != MOD_JUICED && mod != MOD_CRUSH && targ != attacker && !(dflags & DAMAGE_NO_TEAM_PROTECTION) && OnSameTeam (targ, attacker) ) {
+ if ( ( !g_friendlyFire.integer && g_gametype.integer != GT_ELIMINATION && g_gametype.integer != GT_CTF_ELIMINATION ) || ( g_elimination_selfdamage.integer<2 && (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) ) ) {
+ return;
+ }
+ }
+ if (mod == MOD_PROXIMITY_MINE) {
+ if (inflictor && inflictor->parent && OnSameTeam(targ, inflictor->parent)) {
+ return;
+ }
+ if (targ == attacker) {
+ return;
+ }
+ }
+
+ // check for godmode
+ if ( targ->flags & FL_GODMODE ) {
+ return;
+ }
+
+ if(targ->client && targ->client->spawnprotected) {
+ if(level.time>targ->client->respawnTime+g_spawnprotect.integer)
+ targ->client->spawnprotected = qfalse;
+ else
+ if( (mod > MOD_UNKNOWN && mod < MOD_WATER) || mod == MOD_TELEFRAG || mod>MOD_TRIGGER_HURT)
+ return;
+ }
+ }
+
+ // battlesuit protects from all radius damage (but takes knockback)
+ // and protects 50% against all damage
+ if ( client && client->ps.powerups[PW_BATTLESUIT] ) {
+ G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );
+ if ( ( dflags & DAMAGE_RADIUS ) || ( mod == MOD_FALLING ) ) {
+ return;
+ }
+ damage *= 0.5;
+ }
+
+ // add to the attacker's hit counter (if the target isn't a general entity like a prox mine)
+ if ( attacker->client && client
+ && targ != attacker && targ->health > 0
+ && targ->s.eType != ET_MISSILE
+ && targ->s.eType != ET_GENERAL) {
+ if ( OnSameTeam( targ, attacker ) ) {
+ attacker->client->ps.persistant[PERS_HITS]--;
+ } else {
+ attacker->client->ps.persistant[PERS_HITS]++;
+ }
+ attacker->client->ps.persistant[PERS_ATTACKEE_ARMOR] = (targ->health<<8)|(client->ps.stats[STAT_ARMOR]);
+ }
+
+ // always give half damage if hurting self
+ // calculated after knockback, so rocket jumping works
+ if ( targ == attacker) {
+ damage *= 0.5;
+ }
+
+ if(targ && targ->client && attacker->client )
+ damage = catchup_damage(damage, attacker->client->ps.persistant[PERS_SCORE], targ->client->ps.persistant[PERS_SCORE]);
+
+ if(g_damageModifier.value > 0.01) {
+ damage *= g_damageModifier.value;
+ }
+
+ if ( damage < 1 ) {
+ damage = 1;
+ }
+
+ if(targ == attacker && (g_dmflags.integer & DF_NO_SELF_DAMAGE) )
+ damage = 0;
+
+ if ((g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS || g_elimination_allgametypes.integer)
+ && g_elimination_selfdamage.integer<1 && ( targ == attacker || mod == MOD_FALLING )) {
+ damage = 0;
+ }
+
+
+//So people can be telefragged!
+ if ((g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS) && level.time < level.roundStartTime && ((mod == MOD_LAVA) || (mod == MOD_SLIME)) ) {
+ damage = 1000;
+ }
+
+
+ take = damage;
+ //save = 0;
+
+ // save some from armor
+ asave = CheckArmor (targ, take, dflags);
+ take -= asave;
+
+ if ( g_debugDamage.integer ) {
+ G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number,
+ targ->health, take, asave );
+ }
+
+ // add to the damage inflicted on a player this frame
+ // the total will be turned into screen blends and view angle kicks
+ // at the end of the frame
+ if ( client ) {
+ if ( attacker ) {
+ client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
+ } else if(client->lastSentFlying) {
+ client->ps.persistant[PERS_ATTACKER] = client->lastSentFlying;
+ } else {
+ client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
+ }
+ client->damage_armor += asave;
+ client->damage_blood += take;
+ client->damage_knockback += knockback;
+ if ( dir ) {
+ VectorCopy ( dir, client->damage_from );
+ client->damage_fromWorld = qfalse;
+ } else {
+ VectorCopy ( targ->r.currentOrigin, client->damage_from );
+ client->damage_fromWorld = qtrue;
+ }
+ }
+
+ // See if it's the player hurting the emeny flag carrier
+ if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF || g_gametype.integer == GT_CTF_ELIMINATION) {
+ Team_CheckHurtCarrier(targ, attacker);
+ }
+
+ if (targ->client) {
+ // set the last client who damaged the target
+ targ->client->lasthurt_client = attacker->s.number;
+ targ->client->lasthurt_mod = mod;
+ }
+
+ //If vampire is enabled, gain health but not from self or teammate, cannot steal more than targ has
+ if( g_vampire.value>0.0 && (targ != attacker) && take > 0 &&
+ !(OnSameTeam(targ, attacker)) && attacker->health > 0 && targ->health > 0 )
+ {
+ if(take<targ->health)
+ attacker->health += (int)(((float)take)*g_vampire.value);
+ else
+ attacker->health += (int)(((float)targ->health)*g_vampire.value);
+ if(attacker->health>g_vampireMaxHealth.integer)
+ attacker->health = g_vampireMaxHealth.integer;
+ }
+
+ // do the damage
+ if (take) {
+ targ->health = targ->health - take;
+ if ( targ->client ) {
+ targ->client->ps.stats[STAT_HEALTH] = targ->health;
+ }
+
+ if ( targ->health <= 0 ) {
+ if ( client )
+ targ->flags |= FL_NO_KNOCKBACK;
+
+ if (targ->health < -999)
+ targ->health = -999;
+
+ targ->enemy = attacker;
+ targ->die (targ, inflictor, attacker, take, mod);
+ return;
+ } else if ( targ->pain ) {
+ targ->pain (targ, attacker, take);
+ }
+ }
+
+
+}
+
+
+/*
+============
+CanDamage
+
+Returns qtrue if the inflictor can directly damage the target. Used for
+explosions and melee attacks.
+============
+*/
+qboolean CanDamage (gentity_t *targ, vec3_t origin) {
+ vec3_t dest;
+ trace_t tr;
+ vec3_t midpoint;
+
+ // use the midpoint of the bounds instead of the origin, because
+ // bmodels may have their origin is 0,0,0
+ VectorAdd (targ->r.absmin, targ->r.absmax, midpoint);
+ VectorScale (midpoint, 0.5, midpoint);
+
+ VectorCopy (midpoint, dest);
+ trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
+ if (tr.fraction == 1.0 || tr.entityNum == targ->s.number)
+ return qtrue;
+
+ // this should probably check in the plane of projection,
+ // rather than in world coordinate, and also include Z
+ VectorCopy (midpoint, dest);
+ dest[0] += 15.0;
+ dest[1] += 15.0;
+ trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
+ if (tr.fraction == 1.0)
+ return qtrue;
+
+ VectorCopy (midpoint, dest);
+ dest[0] += 15.0;
+ dest[1] -= 15.0;
+ trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
+ if (tr.fraction == 1.0)
+ return qtrue;
+
+ VectorCopy (midpoint, dest);
+ dest[0] -= 15.0;
+ dest[1] += 15.0;
+ trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
+ if (tr.fraction == 1.0)
+ return qtrue;
+
+ VectorCopy (midpoint, dest);
+ dest[0] -= 15.0;
+ dest[1] -= 15.0;
+ trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
+ if (tr.fraction == 1.0)
+ return qtrue;
+
+
+ return qfalse;
+}
+
+
+/*
+============
+G_RadiusDamage
+============
+*/
+qboolean G_RadiusDamage ( vec3_t origin, gentity_t *attacker, float damage, float radius,
+ gentity_t *ignore, int mod) {
+ float points, dist;
+ gentity_t *ent;
+ int entityList[MAX_GENTITIES];
+ int numListedEntities;
+ vec3_t mins, maxs;
+ vec3_t v;
+ vec3_t dir;
+ int i, e;
+ qboolean hitClient = qfalse;
+
+ if ( radius < 1 ) {
+ radius = 1;
+ }
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ mins[i] = origin[i] - radius;
+ maxs[i] = origin[i] + radius;
+ }
+
+ numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+
+ for ( e = 0 ; e < numListedEntities ; e++ ) {
+ ent = &g_entities[entityList[ e ]];
+
+ if (ent == ignore)
+ continue;
+ if (!ent->takedamage)
+ continue;
+
+ // find the distance from the edge of the bounding box
+ for ( i = 0 ; i < 3 ; i++ ) {
+ if ( origin[i] < ent->r.absmin[i] ) {
+ v[i] = ent->r.absmin[i] - origin[i];
+ } else if ( origin[i] > ent->r.absmax[i] ) {
+ v[i] = origin[i] - ent->r.absmax[i];
+ } else {
+ v[i] = 0;
+ }
+ }
+
+ dist = VectorLength( v );
+ if ( dist >= radius ) {
+ continue;
+ }
+
+ points = damage * ( 1.0 - dist / radius );
+
+ if( CanDamage (ent, origin) ) {
+ if( LogAccuracyHit( ent, attacker ) ) {
+ hitClient = qtrue;
+ }
+ VectorSubtract (ent->r.currentOrigin, origin, dir);
+ // push the center of mass higher than the origin so players
+ // get knocked into the air more
+ dir[2] += 24;
+ G_Damage (ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod);
+ }
+ }
+
+ return hitClient;
+}
diff --git a/game/code/game/g_fileops.c b/code/game/g_fileops.c
similarity index 100%
rename from game/code/game/g_fileops.c
rename to code/game/g_fileops.c
diff --git a/code/game/g_items.c b/code/game/g_items.c
new file mode 100644
index 0000000..c5a546c
--- /dev/null
+++ b/code/game/g_items.c
@@ -0,0 +1,1096 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#include "g_local.h"
+
+/*
+
+ Items are any object that a player can touch to gain some effect.
+
+ Pickup will return the number of seconds until they should respawn.
+
+ all items should pop when dropped in lava or slime
+
+ Respawnable items don't actually go away when picked up, they are
+ just made invisible and untouchable. This allows them to ride
+ movers and respawn apropriately.
+*/
+
+
+#define RESPAWN_ARMOR 25
+#define RESPAWN_HEALTH 35
+#define RESPAWN_AMMO 40
+#define RESPAWN_HOLDABLE 60
+#define RESPAWN_MEGAHEALTH 35//120
+#define RESPAWN_POWERUP 120
+
+
+//======================================================================
+
+int Pickup_Powerup( gentity_t *ent, gentity_t *other ) {
+ int quantity;
+ int i;
+ gclient_t *client;
+
+ if ( !other->client->ps.powerups[ent->item->giTag] ) {
+ // round timing to seconds to make multiple powerup timers
+ // count in sync
+ other->client->ps.powerups[ent->item->giTag] =
+ level.time - ( level.time % 1000 );
+ }
+
+ if ( ent->count ) {
+ quantity = ent->count;
+ } else {
+ quantity = ent->item->quantity;
+ }
+
+ other->client->ps.powerups[ent->item->giTag] += quantity * 1000;
+
+ // give any nearby players a "denied" anti-reward
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ vec3_t delta;
+ float len;
+ vec3_t forward;
+ trace_t tr;
+
+ client = &level.clients[i];
+ if ( client == other->client ) {
+ continue;
+ }
+ if ( client->pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+ if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
+ continue;
+ }
+
+ // if same team in team game, no sound
+ // cannot use OnSameTeam as it expects to g_entities, not clients
+ if ( g_gametype.integer >= GT_TEAM && g_ffa_gt==0 && other->client->sess.sessionTeam == client->sess.sessionTeam ) {
+ continue;
+ }
+
+ // if too far away, no sound
+ VectorSubtract( ent->s.pos.trBase, client->ps.origin, delta );
+ len = VectorNormalize( delta );
+ if ( len > 192 ) {
+ continue;
+ }
+
+ // if not facing, no sound
+ AngleVectors( client->ps.viewangles, forward, NULL, NULL );
+ if ( DotProduct( delta, forward ) < 0.4 ) {
+ continue;
+ }
+
+ // if not line of sight, no sound
+ trap_Trace( &tr, client->ps.origin, NULL, NULL, ent->s.pos.trBase, ENTITYNUM_NONE, CONTENTS_SOLID );
+ if ( tr.fraction != 1.0 ) {
+ continue;
+ }
+
+ // anti-reward
+ client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_DENIEDREWARD;
+ }
+ return RESPAWN_POWERUP;
+}
+
+//======================================================================
+
+int Pickup_PersistantPowerup( gentity_t *ent, gentity_t *other ) {
+ int clientNum;
+ char userinfo[MAX_INFO_STRING];
+ float handicap;
+ int max;
+
+ other->client->ps.stats[STAT_PERSISTANT_POWERUP] = ent->item - bg_itemlist;
+ other->client->persistantPowerup = ent;
+
+ switch( ent->item->giTag ) {
+ case PW_GUARD:
+ clientNum = other->client->ps.clientNum;
+ trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
+ handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
+ if( handicap<=0.0f || handicap>100.0f) {
+ handicap = 100.0f;
+ }
+ max = (int)(2 * handicap);
+
+ other->health = max;
+ other->client->ps.stats[STAT_HEALTH] = max;
+ other->client->ps.stats[STAT_MAX_HEALTH] = max;
+ other->client->ps.stats[STAT_ARMOR] = max;
+ other->client->pers.maxHealth = max;
+
+ break;
+
+ case PW_SCOUT:
+ clientNum = other->client->ps.clientNum;
+ trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
+ handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
+ if( handicap<=0.0f || handicap>100.0f) {
+ handicap = 100.0f;
+ }
+ other->client->pers.maxHealth = handicap;
+ other->client->ps.stats[STAT_ARMOR] = 0;
+ break;
+
+ case PW_DOUBLER:
+ clientNum = other->client->ps.clientNum;
+ trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
+ handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
+ if( handicap<=0.0f || handicap>100.0f) {
+ handicap = 100.0f;
+ }
+ other->client->pers.maxHealth = handicap;
+ break;
+ case PW_AMMOREGEN:
+ clientNum = other->client->ps.clientNum;
+ trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
+ handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
+ if( handicap<=0.0f || handicap>100.0f) {
+ handicap = 100.0f;
+ }
+ other->client->pers.maxHealth = handicap;
+ memset(other->client->ammoTimes, 0, sizeof(other->client->ammoTimes));
+ break;
+ default:
+ clientNum = other->client->ps.clientNum;
+ trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
+ handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
+ if( handicap<=0.0f || handicap>100.0f) {
+ handicap = 100.0f;
+ }
+ other->client->pers.maxHealth = handicap;
+ break;
+ }
+
+ return -1;
+}
+
+//======================================================================
+
+int Pickup_Holdable( gentity_t *ent, gentity_t *other ) {
+
+ other->client->ps.stats[STAT_HOLDABLE_ITEM] = ent->item - bg_itemlist;
+
+ if( ent->item->giTag == HI_KAMIKAZE ) {
+ other->client->ps.eFlags |= EF_KAMIKAZE;
+ }
+
+ return RESPAWN_HOLDABLE;
+}
+
+
+//======================================================================
+
+void Add_Ammo (gentity_t *ent, int weapon, int count)
+{
+ ent->client->ps.ammo[weapon] += count;
+ if ( ent->client->ps.ammo[weapon] > 200 ) {
+ ent->client->ps.ammo[weapon] = 200;
+ }
+}
+
+int Pickup_Ammo (gentity_t *ent, gentity_t *other)
+{
+ int quantity;
+
+ if ( ent->count ) {
+ quantity = ent->count;
+ } else {
+ quantity = ent->item->quantity;
+ }
+
+ Add_Ammo (other, ent->item->giTag, quantity);
+
+ return RESPAWN_AMMO;
+}
+
+//======================================================================
+
+
+int Pickup_Weapon (gentity_t *ent, gentity_t *other) {
+ int quantity;
+
+ if ( ent->count < 0 ) {
+ quantity = 0; // None for you, sir!
+ } else {
+ if ( ent->count ) {
+ quantity = ent->count;
+ } else {
+ quantity = ent->item->quantity;
+ }
+
+ // dropped items and teamplay weapons always have full ammo
+ if ( ! (ent->flags & FL_DROPPED_ITEM) && g_gametype.integer != GT_TEAM ) {
+ // respawning rules
+ // drop the quantity if the already have over the minimum
+ if ( other->client->ps.ammo[ ent->item->giTag ] < quantity ) {
+ quantity = quantity - other->client->ps.ammo[ ent->item->giTag ];
+ } else {
+ quantity = 1; // only add a single shot
+ }
+ }
+ }
+
+ // add the weapon
+ other->client->ps.stats[STAT_WEAPONS] |= ( 1 << ent->item->giTag );
+
+ Add_Ammo( other, ent->item->giTag, quantity );
+
+ if (ent->item->giTag == WP_GRAPPLING_HOOK)
+ other->client->ps.ammo[ent->item->giTag] = -1; // unlimited ammo
+
+ // team deathmatch has slow weapon respawns
+ if ( g_gametype.integer == GT_TEAM ) {
+ return g_weaponTeamRespawn.integer;
+ }
+
+ return g_weaponRespawn.integer;
+}
+
+
+//======================================================================
+
+int Pickup_Health (gentity_t *ent, gentity_t *other) {
+ int max;
+ int quantity;
+
+ if( !other->client)
+ return RESPAWN_HEALTH;
+
+ // small and mega healths will go over the max
+ if( other->client && bg_itemlist[other->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
+ max = other->client->ps.stats[STAT_MAX_HEALTH];
+ }
+ else
+ if ( ent->item->quantity != 5 && ent->item->quantity != 100 ) {
+ max = other->client->ps.stats[STAT_MAX_HEALTH];
+ } else {
+ max = other->client->ps.stats[STAT_MAX_HEALTH] * 2;
+ }
+
+ if ( ent->count ) {
+ quantity = ent->count;
+ } else {
+ quantity = ent->item->quantity;
+ }
+
+ other->health += quantity;
+
+ if (other->health > max ) {
+ other->health = max;
+ }
+ other->client->ps.stats[STAT_HEALTH] = other->health;
+
+ if ( ent->item->quantity == 100 ) { // mega health respawns slow
+ return RESPAWN_MEGAHEALTH;
+ }
+
+ return RESPAWN_HEALTH;
+}
+
+//======================================================================
+
+int Pickup_Armor( gentity_t *ent, gentity_t *other ) {
+ int upperBound;
+
+ other->client->ps.stats[STAT_ARMOR] += ent->item->quantity;
+
+ if( other->client && bg_itemlist[other->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
+ upperBound = other->client->ps.stats[STAT_MAX_HEALTH];
+ }
+ else {
+ upperBound = other->client->ps.stats[STAT_MAX_HEALTH] * 2;
+ }
+
+ if ( other->client->ps.stats[STAT_ARMOR] > upperBound ) {
+ other->client->ps.stats[STAT_ARMOR] = upperBound;
+ }
+
+ return RESPAWN_ARMOR;
+}
+
+//======================================================================
+
+/*
+===============
+RespawnItem
+===============
+*/
+void RespawnItem( gentity_t *ent ) {
+ //Don't spawn quad if quadfactor are 1.0 or less
+ if(ent->item->giType == IT_POWERUP && ent->item->giTag == PW_QUAD && g_quadfactor.value <= 1.0)
+ return;
+
+ // randomly select from teamed entities
+ if (ent->team) {
+ gentity_t *master;
+ int count;
+ int choice;
+
+ if ( !ent->teammaster ) {
+ G_Error( "RespawnItem: bad teammaster");
+ }
+ master = ent->teammaster;
+
+ for (count = 0, ent = master; ent; ent = ent->teamchain, count++)
+ ;
+
+ choice = (count > 0)? rand()%count : 0;
+
+ for (count = 0, ent = master; count < choice; ent = ent->teamchain, count++)
+ ;
+ }
+
+ ent->r.contents = CONTENTS_TRIGGER;
+ ent->s.eFlags &= ~EF_NODRAW;
+ ent->r.svFlags &= ~SVF_NOCLIENT;
+ trap_LinkEntity (ent);
+
+ if ( ent->item->giType == IT_POWERUP ) {
+ // play powerup spawn sound to all clients
+ gentity_t *te;
+
+ // if the powerup respawn sound should Not be global
+ if (ent->speed) {
+ te = G_TempEntity( ent->s.pos.trBase, EV_GENERAL_SOUND );
+ }
+ else {
+ te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_SOUND );
+ }
+ te->s.eventParm = G_SoundIndex( "sound/items/poweruprespawn.wav" );
+ te->r.svFlags |= SVF_BROADCAST;
+ }
+
+ if ( ent->item->giType == IT_HOLDABLE && ent->item->giTag == HI_KAMIKAZE ) {
+ // play powerup spawn sound to all clients
+ gentity_t *te;
+
+ // if the powerup respawn sound should Not be global
+ if (ent->speed) {
+ te = G_TempEntity( ent->s.pos.trBase, EV_GENERAL_SOUND );
+ }
+ else {
+ te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_SOUND );
+ }
+ te->s.eventParm = G_SoundIndex( "sound/items/kamikazerespawn.wav" );
+ te->r.svFlags |= SVF_BROADCAST;
+ }
+
+ // play the normal respawn sound only to nearby clients
+ G_AddEvent( ent, EV_ITEM_RESPAWN, 0 );
+
+ ent->nextthink = 0;
+}
+
+
+/*
+===============
+Touch_Item
+===============
+*/
+void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) {
+ int respawn;
+ qboolean predict;
+
+ //instant gib
+ if ((g_instantgib.integer || g_rockets.integer || g_gametype.integer == GT_CTF_ELIMINATION || g_elimination_allgametypes.integer)
+ && ent->item->giType != IT_TEAM)
+ return;
+
+ //Cannot touch flag before round starts
+ if(g_gametype.integer == GT_CTF_ELIMINATION && level.roundNumber != level.roundNumberStarted)
+ return;
+
+ //Cannot take ctf elimination oneway
+ if(g_gametype.integer == GT_CTF_ELIMINATION && g_elimination_ctf_oneway.integer!=0 && (
+ (other->client->sess.sessionTeam==TEAM_BLUE && (level.eliminationSides+level.roundNumber)%2 == 0 ) ||
+ (other->client->sess.sessionTeam==TEAM_RED && (level.eliminationSides+level.roundNumber)%2 != 0 ) ))
+ return;
+
+ if (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_LMS)
+ return; //nothing to pick up in elimination
+
+ if (!other->client)
+ return;
+ if (other->health < 1)
+ return; // dead people can't pickup
+
+ // the same pickup rules are used for client side and server side
+ if ( !BG_CanItemBeGrabbed( g_gametype.integer, &ent->s, &other->client->ps ) ) {
+ return;
+ }
+
+ //In double DD we cannot "pick up" a flag we already got
+ if(g_gametype.integer == GT_DOUBLE_D) {
+ if( strcmp(ent->classname, "team_CTF_redflag") == 0 )
+ if(other->client->sess.sessionTeam == level.pointStatusA)
+ return;
+ if( strcmp(ent->classname, "team_CTF_blueflag") == 0 )
+ if(other->client->sess.sessionTeam == level.pointStatusB)
+ return;
+ }
+
+ G_LogPrintf( "Item: %i %s\n", other->s.number, ent->item->classname );
+
+ predict = other->client->pers.predictItemPickup;
+
+ // call the item-specific pickup function
+ switch( ent->item->giType ) {
+ case IT_WEAPON:
+ respawn = Pickup_Weapon(ent, other);
+// predict = qfalse;
+ break;
+ case IT_AMMO:
+ respawn = Pickup_Ammo(ent, other);
+// predict = qfalse;
+ break;
+ case IT_ARMOR:
+ respawn = Pickup_Armor(ent, other);
+ break;
+ case IT_HEALTH:
+ respawn = Pickup_Health(ent, other);
+ break;
+ case IT_POWERUP:
+ respawn = Pickup_Powerup(ent, other);
+ predict = qfalse;
+ break;
+ case IT_PERSISTANT_POWERUP:
+ respawn = Pickup_PersistantPowerup(ent, other);
+ break;
+ case IT_TEAM:
+ respawn = Pickup_Team(ent, other);
+ //If touching a team item remove spawnprotection
+ if(other->client->spawnprotected)
+ other->client->spawnprotected = qfalse;
+ break;
+ case IT_HOLDABLE:
+ respawn = Pickup_Holdable(ent, other);
+ break;
+ default:
+ return;
+ }
+
+ if ( !respawn ) {
+ return;
+ }
+
+ // play the normal pickup sound
+ if (predict) {
+ G_AddPredictableEvent( other, EV_ITEM_PICKUP, ent->s.modelindex );
+ } else {
+ G_AddEvent( other, EV_ITEM_PICKUP, ent->s.modelindex );
+ }
+
+ // powerup pickups are global broadcasts
+ if ( ent->item->giType == IT_POWERUP || ent->item->giType == IT_TEAM) {
+ // if we want the global sound to play
+ if (!ent->speed) {
+ gentity_t *te;
+
+ te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP );
+ te->s.eventParm = ent->s.modelindex;
+ te->r.svFlags |= SVF_BROADCAST;
+ } else {
+ gentity_t *te;
+
+ te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP );
+ te->s.eventParm = ent->s.modelindex;
+ // only send this temp entity to a single client
+ te->r.svFlags |= SVF_SINGLECLIENT;
+ te->r.singleClient = other->s.number;
+ }
+ }
+
+ // fire item targets
+ G_UseTargets (ent, other);
+
+ // wait of -1 will not respawn
+ if ( ent->wait == -1 ) {
+ ent->r.svFlags |= SVF_NOCLIENT;
+ ent->s.eFlags |= EF_NODRAW;
+ ent->r.contents = 0;
+ ent->unlinkAfterEvent = qtrue;
+ return;
+ }
+
+ // non zero wait overrides respawn time
+ if ( ent->wait ) {
+ respawn = ent->wait;
+ }
+
+ // random can be used to vary the respawn time
+ if ( ent->random ) {
+ respawn += crandom() * ent->random;
+ if ( respawn < 1 ) {
+ respawn = 1;
+ }
+ }
+
+ // dropped items will not respawn
+ if ( ent->flags & FL_DROPPED_ITEM ) {
+ ent->freeAfterEvent = qtrue;
+ }
+
+ // picked up items still stay around, they just don't
+ // draw anything. This allows respawnable items
+ // to be placed on movers.
+ ent->r.svFlags |= SVF_NOCLIENT;
+ ent->s.eFlags |= EF_NODRAW;
+ ent->r.contents = 0;
+
+ // ZOID
+ // A negative respawn times means to never respawn this item (but don't
+ // delete it). This is used by items that are respawned by third party
+ // events such as ctf flags
+ if ( respawn <= 0 ) {
+ ent->nextthink = 0;
+ ent->think = 0;
+ } else {
+ ent->nextthink = level.time + respawn * 1000;
+ ent->think = RespawnItem;
+ }
+ trap_LinkEntity( ent );
+}
+
+
+//======================================================================
+
+/*
+================
+LaunchItem
+
+Spawns an item and tosses it forward
+================
+*/
+gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity ) {
+ gentity_t *dropped;
+
+ dropped = G_Spawn();
+
+ dropped->s.eType = ET_ITEM;
+ dropped->s.modelindex = item - bg_itemlist; // store item number in modelindex
+ dropped->s.modelindex2 = 1; // This is non-zero is it's a dropped item
+
+ dropped->classname = item->classname;
+ dropped->item = item;
+ VectorSet (dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS);
+ VectorSet (dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
+ dropped->r.contents = CONTENTS_TRIGGER;
+
+ dropped->touch = Touch_Item;
+
+ G_SetOrigin( dropped, origin );
+ dropped->s.pos.trType = TR_GRAVITY;
+ dropped->s.pos.trTime = level.time;
+ VectorCopy( velocity, dropped->s.pos.trDelta );
+
+ dropped->s.eFlags |= EF_BOUNCE_HALF;
+ if ((g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_DOUBLE_D) && item->giType == IT_TEAM) { // Special case for CTF flags
+ dropped->think = Team_DroppedFlagThink;
+ dropped->nextthink = level.time + 30000;
+ Team_CheckDroppedItem( dropped );
+ } else { // auto-remove after 30 seconds
+ dropped->think = G_FreeEntity;
+ dropped->nextthink = level.time + 30000;
+ }
+
+ dropped->flags = FL_DROPPED_ITEM;
+
+ trap_LinkEntity (dropped);
+
+ return dropped;
+}
+
+/*
+================
+Drop_Item
+
+Spawns an item and tosses it forward
+================
+*/
+gentity_t *Drop_Item( gentity_t *ent, gitem_t *item, float angle ) {
+ vec3_t velocity;
+ vec3_t angles;
+
+ VectorCopy( ent->s.apos.trBase, angles );
+ angles[YAW] += angle;
+ angles[PITCH] = 0; // always forward
+
+ AngleVectors( angles, velocity, NULL, NULL );
+ VectorScale( velocity, 150, velocity );
+ velocity[2] += 200 + crandom() * 50;
+
+ return LaunchItem( item, ent->s.pos.trBase, velocity );
+}
+
+
+/*
+================
+Use_Item
+
+Respawn the item
+================
+*/
+void Use_Item( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
+ RespawnItem( ent );
+}
+
+//======================================================================
+
+/*
+================
+FinishSpawningItem
+
+Traces down to find where an item should rest, instead of letting them
+free fall from their spawn points
+================
+*/
+void FinishSpawningItem( gentity_t *ent ) {
+ trace_t tr;
+ vec3_t dest;
+
+ VectorSet( ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS );
+ VectorSet( ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS );
+
+ ent->s.eType = ET_ITEM;
+ ent->s.modelindex = ent->item - bg_itemlist; // store item number in modelindex
+ ent->s.modelindex2 = 0; // zero indicates this isn't a dropped item
+
+ ent->r.contents = CONTENTS_TRIGGER;
+ ent->touch = Touch_Item;
+ // useing an item causes it to respawn
+ ent->use = Use_Item;
+
+ if ( ent->spawnflags & 1 ) {
+ // suspended
+ G_SetOrigin( ent, ent->s.origin );
+ } else {
+ // drop to floor
+ VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
+ trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
+ if ( tr.startsolid ) {
+ G_Printf ("FinishSpawningItem: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
+ G_FreeEntity( ent );
+ return;
+ }
+
+ // allow to ride movers
+ ent->s.groundEntityNum = tr.entityNum;
+
+ G_SetOrigin( ent, tr.endpos );
+ }
+
+ // team slaves and targeted items aren't present at start
+ if ( ( ent->flags & FL_TEAMSLAVE ) || ent->targetname ) {
+ ent->s.eFlags |= EF_NODRAW;
+ ent->r.contents = 0;
+ return;
+ }
+
+
+ // powerups don't spawn in for a while (but not in elimination)
+ if(g_gametype.integer != GT_ELIMINATION && g_gametype.integer != GT_CTF_ELIMINATION && g_gametype.integer != GT_LMS
+ && !g_instantgib.integer && !g_elimination_allgametypes.integer && !g_rockets.integer )
+ if ( ent->item->giType == IT_POWERUP ) {
+ float respawn;
+
+ respawn = 45 + crandom() * 15;
+ ent->s.eFlags |= EF_NODRAW;
+ ent->r.contents = 0;
+ ent->nextthink = level.time + respawn * 1000;
+ ent->think = RespawnItem;
+ return;
+ }
+
+
+ trap_LinkEntity (ent);
+}
+
+
+qboolean itemRegistered[MAX_ITEMS];
+
+/*
+==================
+G_CheckTeamItems
+==================
+*/
+void G_CheckTeamItems( void ) {
+
+ // Set up team stuff
+ Team_InitGame();
+
+ if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_DOUBLE_D) {
+ gitem_t *item;
+
+ // check for the two flags
+ item = BG_FindItem( "Red Flag" );
+ if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
+ G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_redflag in map\n" );
+ }
+ item = BG_FindItem( "Blue Flag" );
+ if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
+ G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_blueflag in map\n" );
+ }
+ }
+ if( g_gametype.integer == GT_1FCTF ) {
+ gitem_t *item;
+
+ // check for all three flags
+ item = BG_FindItem( "Red Flag" );
+ if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
+ G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_redflag in map\n" );
+ }
+ item = BG_FindItem( "Blue Flag" );
+ if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
+ G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_blueflag in map\n" );
+ }
+ item = BG_FindItem( "Neutral Flag" );
+ if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
+ G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_neutralflag in map\n" );
+ }
+ }
+
+ if( g_gametype.integer == GT_OBELISK ) {
+ gentity_t *ent;
+
+ // check for the two obelisks
+ ent = NULL;
+ ent = G_Find( ent, FOFS(classname), "team_redobelisk" );
+ if( !ent ) {
+ G_Printf( S_COLOR_YELLOW "WARNING: No team_redobelisk in map\n" );
+ }
+
+ ent = NULL;
+ ent = G_Find( ent, FOFS(classname), "team_blueobelisk" );
+ if( !ent ) {
+ G_Printf( S_COLOR_YELLOW "WARNING: No team_blueobelisk in map\n" );
+ }
+ }
+
+ if( g_gametype.integer == GT_HARVESTER ) {
+ gentity_t *ent;
+
+ // check for all three obelisks
+ ent = NULL;
+ ent = G_Find( ent, FOFS(classname), "team_redobelisk" );
+ if( !ent ) {
+ G_Printf( S_COLOR_YELLOW "WARNING: No team_redobelisk in map\n" );
+ }
+
+ ent = NULL;
+ ent = G_Find( ent, FOFS(classname), "team_blueobelisk" );
+ if( !ent ) {
+ G_Printf( S_COLOR_YELLOW "WARNING: No team_blueobelisk in map\n" );
+ }
+
+ ent = NULL;
+ ent = G_Find( ent, FOFS(classname), "team_neutralobelisk" );
+ if( !ent ) {
+ G_Printf( S_COLOR_YELLOW "WARNING: No team_neutralobelisk in map\n" );
+ }
+ }
+}
+
+/*
+==============
+ClearRegisteredItems
+==============
+*/
+void ClearRegisteredItems( void ) {
+ memset( itemRegistered, 0, sizeof( itemRegistered ) );
+
+ if(g_instantgib.integer) {
+ if(g_instantgib.integer & 2)
+ RegisterItem( BG_FindItemForWeapon( WP_GAUNTLET ) );
+ //RegisterItem( BG_FindItemForWeapon( WP_MACHINEGUN ) );
+ RegisterItem( BG_FindItemForWeapon( WP_RAILGUN ) );
+ }
+ else
+ if(g_rockets.integer) {
+ //RegisterItem( BG_FindItemForWeapon( WP_GAUNTLET ) );
+ //RegisterItem( BG_FindItemForWeapon( WP_MACHINEGUN ) );
+ RegisterItem( BG_FindItemForWeapon( WP_ROCKET_LAUNCHER ) );
+ }
+ else
+ {
+ // players always start with the base weapon
+ RegisterItem( BG_FindItemForWeapon( WP_MACHINEGUN ) );
+ RegisterItem( BG_FindItemForWeapon( WP_GAUNTLET ) );
+ if(g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION
+ || g_gametype.integer == GT_LMS || g_elimination_allgametypes.integer)
+ {
+ RegisterItem( BG_FindItemForWeapon( WP_SHOTGUN ) );
+ RegisterItem( BG_FindItemForWeapon( WP_GRENADE_LAUNCHER ) );
+ RegisterItem( BG_FindItemForWeapon( WP_ROCKET_LAUNCHER ) );
+ RegisterItem( BG_FindItemForWeapon( WP_LIGHTNING ) );
+ RegisterItem( BG_FindItemForWeapon( WP_RAILGUN ) );
+ RegisterItem( BG_FindItemForWeapon( WP_PLASMAGUN ) );
+ RegisterItem( BG_FindItemForWeapon( WP_BFG ) );
+ RegisterItem( BG_FindItemForWeapon( WP_NAILGUN ) );
+ RegisterItem( BG_FindItemForWeapon( WP_PROX_LAUNCHER ) );
+ RegisterItem( BG_FindItemForWeapon( WP_CHAINGUN ) );
+ }
+ }
+ if( g_gametype.integer == GT_HARVESTER ) {
+ RegisterItem( BG_FindItem( "Red Cube" ) );
+ RegisterItem( BG_FindItem( "Blue Cube" ) );
+ }
+
+ if(g_gametype.integer == GT_DOUBLE_D ) {
+ RegisterItem( BG_FindItem( "Point A (Blue)" ) );
+ RegisterItem( BG_FindItem( "Point A (Red)" ) );
+ RegisterItem( BG_FindItem( "Point A (White)" ) );
+ RegisterItem( BG_FindItem( "Point B (Blue)" ) );
+ RegisterItem( BG_FindItem( "Point B (Red)" ) );
+ RegisterItem( BG_FindItem( "Point B (White)" ) );
+ }
+
+ if(g_gametype.integer == GT_DOMINATION ) {
+ RegisterItem( BG_FindItem( "Neutral domination point" ) );
+ RegisterItem( BG_FindItem( "Red domination point" ) );
+ RegisterItem( BG_FindItem( "Blue domination point" ) );
+ }
+
+}
+
+/*
+===============
+RegisterItem
+
+The item will be added to the precache list
+===============
+*/
+void RegisterItem( gitem_t *item ) {
+ if ( !item ) {
+ G_Error( "RegisterItem: NULL" );
+ }
+ itemRegistered[ item - bg_itemlist ] = qtrue;
+}
+
+
+/*
+===============
+SaveRegisteredItems
+
+Write the needed items to a config string
+so the client will know which ones to precache
+===============
+*/
+void SaveRegisteredItems( void ) {
+ char string[MAX_ITEMS+1];
+ int i;
+ int count;
+
+ count = 0;
+ for ( i = 0 ; i < bg_numItems ; i++ ) {
+ if ( itemRegistered[i] ) {
+ count++;
+ string[i] = '1';
+ } else {
+ string[i] = '0';
+ }
+ }
+ string[ bg_numItems ] = 0;
+ G_Printf( "%i items registered\n", count );
+ trap_SetConfigstring(CS_ITEMS, string);
+}
+
+/*
+============
+G_ItemDisabled
+============
+*/
+int G_ItemDisabled( gitem_t *item ) {
+
+ char name[128];
+
+ Com_sprintf(name, sizeof(name), "disable_%s", item->classname);
+ return trap_Cvar_VariableIntegerValue( name );
+}
+
+/*
+============
+G_SpawnItem
+
+Sets the clipping size and plants the object on the floor.
+
+Items can't be immediately dropped to floor, because they might
+be on an entity that hasn't spawned yet.
+============
+*/
+void G_SpawnItem (gentity_t *ent, gitem_t *item) {
+ G_SpawnFloat( "random", "0", &ent->random );
+ G_SpawnFloat( "wait", "0", &ent->wait );
+
+ if((item->giType == IT_TEAM && (g_instantgib.integer || g_rockets.integer) ) || (!g_instantgib.integer && !g_rockets.integer) )
+ {
+ //Don't load pickups in Elimination (or maybe... gives warnings)
+ if (g_gametype.integer != GT_ELIMINATION && g_gametype.integer != GT_CTF_ELIMINATION && g_gametype.integer != GT_LMS)
+ RegisterItem( item );
+ //Registrer flags anyway in CTF Elimination:
+ if (g_gametype.integer == GT_CTF_ELIMINATION && item->giType == IT_TEAM)
+ RegisterItem( item );
+ if ( G_ItemDisabled(item) )
+ return;
+ }
+ if(!g_persistantpowerups.integer && item->giType == IT_PERSISTANT_POWERUP)
+ return;
+
+ ent->item = item;
+ // some movers spawn on the second frame, so delay item
+ // spawns until the third frame so they can ride trains
+ ent->nextthink = level.time + FRAMETIME * 2;
+ ent->think = FinishSpawningItem;
+
+ ent->physicsBounce = 0.50; // items are bouncy
+
+ if (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_LMS ||
+ ( item->giType != IT_TEAM && (g_instantgib.integer || g_rockets.integer || g_elimination_allgametypes.integer || g_gametype.integer==GT_CTF_ELIMINATION) ) ) {
+ ent->s.eFlags |= EF_NODRAW; //Invisible in elimination
+ ent->r.svFlags |= SVF_NOCLIENT; //Don't broadcast
+ }
+
+ if(g_gametype.integer == GT_DOUBLE_D && (strcmp(ent->classname, "team_CTF_redflag")==0 || strcmp(ent->classname, "team_CTF_blueflag")==0 || strcmp(ent->classname, "team_CTF_neutralflag") == 0 || item->giType == IT_PERSISTANT_POWERUP ))
+ ent->s.eFlags |= EF_NODRAW; //Don't draw the flag models/persistant powerups
+
+ if( g_gametype.integer != GT_1FCTF && strcmp(ent->classname, "team_CTF_neutralflag") == 0)
+ ent->s.eFlags |= EF_NODRAW; // Don't draw the flag in CTF_elimination
+
+ if(strcmp(ent->classname, "domination_point") == 0)
+ ent->s.eFlags |= EF_NODRAW; // Don't draw domination_point. It is just a pointer to where the Domination points should be placed
+ if ( item->giType == IT_POWERUP ) {
+ G_SoundIndex( "sound/items/poweruprespawn.wav" );
+ G_SpawnFloat( "noglobalsound", "0", &ent->speed);
+ }
+
+ if ( item->giType == IT_PERSISTANT_POWERUP ) {
+ ent->s.generic1 = ent->spawnflags;
+ }
+}
+
+
+/*
+================
+G_BounceItem
+
+================
+*/
+void G_BounceItem( gentity_t *ent, trace_t *trace ) {
+ vec3_t velocity;
+ float dot;
+ int hitTime;
+
+ // reflect the velocity on the trace plane
+ hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
+ BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
+ dot = DotProduct( velocity, trace->plane.normal );
+ VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );
+
+ // cut the velocity to keep from bouncing forever
+ VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta );
+
+ // check for stop
+ if ( trace->plane.normal[2] > 0 && ent->s.pos.trDelta[2] < 40 ) {
+ trace->endpos[2] += 1.0; // make sure it is off ground
+ SnapVector( trace->endpos );
+ G_SetOrigin( ent, trace->endpos );
+ ent->s.groundEntityNum = trace->entityNum;
+ return;
+ }
+
+ VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
+ VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
+ ent->s.pos.trTime = level.time;
+}
+
+
+/*
+================
+G_RunItem
+
+================
+*/
+void G_RunItem( gentity_t *ent ) {
+ vec3_t origin;
+ trace_t tr;
+ int contents;
+ int mask;
+
+ // if groundentity has been set to -1, it may have been pushed off an edge
+ if ( ent->s.groundEntityNum == -1 ) {
+ if ( ent->s.pos.trType != TR_GRAVITY ) {
+ ent->s.pos.trType = TR_GRAVITY;
+ ent->s.pos.trTime = level.time;
+ }
+ }
+
+ if ( ent->s.pos.trType == TR_STATIONARY ) {
+ // check think function
+ G_RunThink( ent );
+ return;
+ }
+
+ // get current position
+ BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
+
+ // trace a line from the previous position to the current position
+ if ( ent->clipmask ) {
+ mask = ent->clipmask;
+ } else {
+ mask = MASK_PLAYERSOLID & ~CONTENTS_BODY;//MASK_SOLID;
+ }
+ trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin,
+ ent->r.ownerNum, mask );
+
+ VectorCopy( tr.endpos, ent->r.currentOrigin );
+
+ if ( tr.startsolid ) {
+ tr.fraction = 0;
+ }
+
+ trap_LinkEntity( ent ); // FIXME: avoid this for stationary?
+
+ // check think function
+ G_RunThink( ent );
+
+ if ( tr.fraction == 1 ) {
+ return;
+ }
+
+ // if it is in a nodrop volume, remove it
+ contents = trap_PointContents( ent->r.currentOrigin, -1 );
+ if ( contents & CONTENTS_NODROP ) {
+ if (ent->item && ent->item->giType == IT_TEAM) {
+ Team_FreeEntity(ent);
+ } else {
+ G_FreeEntity( ent );
+ }
+ return;
+ }
+
+ G_BounceItem( ent, &tr );
+}
+
diff --git a/code/game/g_killspree.c b/code/game/g_killspree.c
new file mode 100644
index 0000000..9a13303
--- /dev/null
+++ b/code/game/g_killspree.c
@@ -0,0 +1,517 @@
+/*
+===========================================================================
+Copyright (C) 2009 Karl Kuglin
+
+This file is part of the Open Arena source code.
+Parts of this file utilize code originally written for Tremulous by
+Tony J. White.
+Use of that code is governed by GPL version 2 and any later versions.
+
+Open Arena source code 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.
+
+Open Arena source code 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 Open Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+// NOTE: This code is by no means complete.
+
+#include "g_local.h"
+
+killspree_t *killSprees[ MAX_KSPREE ];
+deathspree_t *deathSprees[ MAX_DSPREE ];
+multikill_t *multiKills[ MAX_MULTIKILLS ];
+
+/*
+=================
+G_ReadAltKillSettings
+Since this is cvar dependent, it has to be placed in G_InitGame after cvars are registered.
+=================
+*/
+qboolean G_ReadAltKillSettings( gentity_t *ent, int skiparg )
+{
+ //Let's Initialize some Spree structs/objects
+ killspree_t *k = NULL;
+ deathspree_t *d = NULL;
+ multikill_t *m = NULL;
+ //spree counters
+ int ksc = 0, dsc = 0, mc = 0;
+ int spreeDivisor;
+
+ //Give us an int to use in "for" loops
+ int i = 0;
+
+ //File Stuff
+ fileHandle_t file;
+ int length;
+ qboolean kspree_read;
+ qboolean dspree_read;
+ qboolean mkill_read;
+ char *cnf, *cnf2;
+ char *t;
+
+ //Let's clear out any existing killing sprees/death sprees. YAYY BG_FREE!!!!!
+ for( i = 0; i < MAX_KSPREE && killSprees[ i ]; i++ ) {
+ BG_Free( killSprees[ i ] );
+ killSprees[ i ] = NULL;
+ }
+
+ for( i = 0; i < MAX_KSPREE && deathSprees[ i ]; i++ ) {
+ BG_Free( deathSprees[ i ] );
+ deathSprees[ i ] = NULL;
+ }
+
+ for( i = 0; i < MAX_MULTIKILLS && multiKills[ i ]; i++ ) {
+ BG_Free( multiKills[ i ] );
+ multiKills[ i ] = NULL;
+ }
+
+ // If the config file is not defined...forget reading/loading
+ if( !g_sprees.string[0] ) {
+ //Let's disable multikills to keep stock excellent sound
+ if( g_altExcellent.integer == 1 )
+ {
+ trap_Cvar_Set( "g_altExcellent", "0" );
+ }
+ return qfalse;
+ }
+ /*
+ only set spreeDivisor to cvar g_spreeDiv if g_spreeDiv is >= "2".
+ 0 will cause problems and having 1 is just a fool who wants to hear something
+ on every kill.
+ */
+ if( g_spreeDiv.integer >= 2 ) {
+ level.spreeDivisor = g_spreeDiv.integer;
+ spreeDivisor = level.spreeDivisor;
+ } else {
+ level.spreeDivisor = 5;
+ // We don't want to change the value, keep reminding the server operator.
+ //g_spreeDiv.integer = 5;
+ spreeDivisor = 5;
+ G_Printf( "Error: cvar g_spreeDiv must not be set to 0 or 1, reverting to default settings!\n" );
+ G_Printf( "Error: Set g_spreeDiv higher than 1 if 5 is not desired!\n" );
+ }
+
+ length = trap_FS_FOpenFile( g_sprees.string, &file, FS_READ );
+
+ //If the file can't be accessed/opened.
+ if( length < 0 ) {
+ G_Printf( "Could not open configuration file for Sprees and Multikills %s\n", g_sprees.string );
+ trap_Cvar_Set( "g_altExcellent", "0" );
+ return qfalse;
+ }
+ //Allocate some memory.
+ cnf = BG_Alloc( length + 1 );
+ cnf2 = cnf;
+
+ //Load the whole file up.
+ trap_FS_Read( cnf, length, file );
+ *( cnf + length ) = '\0';
+ trap_FS_FCloseFile( file );
+
+ kspree_read = dspree_read = mkill_read = qfalse;
+
+ //Let's start parsing em.
+ COM_BeginParseSession( g_sprees.string );
+ while( 1 )
+ {
+ t = COM_Parse( &cnf );
+ if( !*t )
+ break;
+ if( !Q_stricmp( t, "[kspree]" ) ) {
+
+ if( ksc >= MAX_KSPREE )
+ return qfalse;
+ k = BG_Alloc( sizeof( killspree_t ) );
+ killSprees[ ksc++ ] = k;
+ kspree_read = qtrue;
+ dspree_read = qfalse;
+ mkill_read = qfalse;
+
+ } else if ( !Q_stricmp( t, "[dspree]" ) ) {
+
+ if( dsc >= MAX_DSPREE )
+ return qfalse;
+ d = BG_Alloc( sizeof( deathspree_t ) );
+ deathSprees[ dsc++ ] = d;
+ dspree_read = qtrue;
+ kspree_read = qfalse;
+ mkill_read = qfalse;
+ } else if ( !Q_stricmp( t, "[mkill]" ) ) {
+
+ if( mc >= MAX_MULTIKILLS )
+ return qfalse;
+ m = BG_Alloc( sizeof( multikill_t ) );
+ multiKills[ mc++ ] = m;
+ mkill_read = qtrue;
+ kspree_read = qfalse;
+ dspree_read = qfalse;
+ //Parse a killing spree
+ } else if ( kspree_read ) {
+ if( !Q_stricmp( t, "level" ) ) {
+ readFile_int( &cnf, &k->spreeLevel );
+ //Let's take the spreeLevel and multiply it by the spreeDivisor to give us our count
+ k->streakCount = ( ( k->spreeLevel ) * ( spreeDivisor ) );
+ } else if ( !Q_stricmp( t, "message" ) ) {
+ readFile_string( &cnf, k->spreeMsg, sizeof( k->spreeMsg ) );
+ } else if ( !Q_stricmp( t, "printpos" ) ) {
+ readFile_int( &cnf, &k->position );
+ } else if ( !Q_stricmp( t, "sound" ) ) {
+ readFile_string( &cnf, k->sound2Play, sizeof( k->sound2Play ) );
+ } else {
+ COM_ParseError( "Killing Spree unrecognized token \"%s\"", t );
+ }
+ } else if ( dspree_read ) {
+ if( !Q_stricmp( t, "level" ) ) {
+ readFile_int( &cnf, &d->spreeLevel );
+ //Let's take the spreeLevel and multiply it by the spreeDivisor to give us our count
+ d->streakCount = ( ( d->spreeLevel ) * ( spreeDivisor ) );
+ } else if ( !Q_stricmp( t, "message" ) ) {
+ readFile_string( &cnf, d->spreeMsg, sizeof( d->spreeMsg ) );
+ } else if ( !Q_stricmp( t, "printpos" ) ) {
+ readFile_int( &cnf, &d->position );
+ } else if ( !Q_stricmp( t, "sound" ) ) {
+ readFile_string( &cnf, d->sound2Play, sizeof( d->sound2Play ) );
+ } else {
+ COM_ParseError( "Death Spree unrecognized token \"%s\"", t );
+ }
+ } else if ( mkill_read ) {
+ if ( !Q_stricmp( t, "kills" ) ) {
+ readFile_int( &cnf, &m->kills );
+ } else if ( !Q_stricmp( t, "message" ) ) {
+ readFile_string( &cnf, m->killMsg, sizeof( m->killMsg ) );
+ } else if ( !Q_stricmp( t, "sound" ) ) {
+ readFile_string( &cnf, m->sound2Play, sizeof( m->sound2Play ) );
+ } else {
+ COM_ParseError( "Multikill unrecognized token \"%s\"", t );
+ }
+ } else {
+ COM_ParseError( "unexpected token \"%s\"", t );
+ }
+ }
+ //Let's "free" some memory now.
+ BG_Free( cnf2 );
+ G_Printf("Sprees/Kills: loaded %d killing sprees, %d death sprees, and %d multikills.\n", ksc, dsc, mc );
+ //Mark the Upper Bounds of the Arrays (Since they start numbering at 0, We subtract 1 )
+ level.kSpreeUBound = ( ksc - 1 );
+ level.dSpreeUBound = ( dsc - 1 );
+ if( mc > 0 ) {
+ level.mKillUBound = ( mc - 1 );
+ } else {
+ level.mKillUBound = -1;
+ //KK-OAX We don't have any kills defined, revert to stock.
+ //FIXME: Make sure this change shows up in the console...
+ if( g_altExcellent.integer == 1 ) {
+ trap_Cvar_Set( "g_altExcellent", "0" );
+ }
+
+ }
+ return qtrue;
+}
+
+
+static char *fillPlaceHolder( char *stringToSearch, char *placeHolder, char *replaceWith )
+{
+ static char output[ MAX_SAY_TEXT ];
+ char *p;
+
+ if( !( p = strstr( stringToSearch, placeHolder ) ) )
+ return stringToSearch;
+
+ strncpy( output, stringToSearch, p - stringToSearch );
+ output[ p - stringToSearch ] = '\0';
+
+ Q_snprintf( output + ( p - stringToSearch ), output - stringToSearch, "%s%s", replaceWith, p + strlen( placeHolder ) );
+
+ return output;
+}
+
+//This concatenate's the message to broadcast to the clients.
+static char *CreateMessage( gentity_t *ent, char *message, char *spreeNumber )
+{
+ static char output[ MAX_SAY_TEXT ] = { "" };
+
+ char name[ MAX_NAME_LENGTH ];
+ //Do some sanity checks
+ if( !ent ) {
+ return output;
+ } else if ( !*message ) {
+ return output;
+ } else if ( !spreeNumber ) {
+ return output;
+ }
+ //Get the player name.
+ Q_strncpyz( name, ent->client->pers.netname, sizeof( name ) );
+ //Do Our Replacements
+ Q_strncpyz( output, fillPlaceHolder( message, "[n]", name ), sizeof( output ) );
+ Q_strncpyz( output, fillPlaceHolder( output, "[k]", spreeNumber ), sizeof( output ) );
+ return output;
+}
+
+
+/*
+================
+G_RunStreakLogic
+KK-OAX This is called from player_die.
+It does all the adding resetting of kill/death streaks
+to be compared against the kill/death spree levels.
+================
+*/
+void G_RunStreakLogic( gentity_t *attacker, gentity_t *victim )
+{
+ //We only want to sanity check for the victim at this point.
+ if( !victim || !victim->client )
+ return;
+
+ //We will reset the victim's killstreak counter
+ victim->client->pers.killstreak = 0;
+ //Add one to the death streak counter
+ victim->client->pers.deathstreak++;
+
+ //Let's check for a deathspree for the victim
+ G_CheckForSpree( victim, victim->client->pers.deathstreak, qfalse );
+
+ //Move on to the attacker
+ //Make sure they are a client and that the attacker and victim are not the same client
+ //We don't want suicide to count towards a killstreak...
+ if( ( attacker )
+ && ( attacker->client )
+ && ( attacker != victim ) ) {
+
+ //Check the gametype--If FFA enabled, everybody's on the same team.
+ if( g_gametype.integer >= GT_TEAM && g_ffa_gt!= 1 ) {
+ //If they are on the same team we don't want to count it towards a killing spree.
+ if( OnSameTeam( victim, attacker ) ) {
+ return;
+ }
+ }
+ //Add to the killstreak, reset the deathstreak
+ attacker->client->pers.deathstreak = 0;
+ attacker->client->pers.killstreak++;
+
+ //Let's check for a killingspree for the attacker
+ G_CheckForSpree( attacker, attacker->client->pers.killstreak, qtrue );
+
+ }
+}
+
+
+
+//If the streak / spree divisor is a whole number, we have a spree
+static qboolean TestSpreeWhole( int streak2Test ) {
+ float float2Test;
+ float spreeFDiv;
+ float resultf;
+ int spreeDiv;
+ int result;
+
+ float2Test = streak2Test;
+ spreeFDiv = level.spreeDivisor;
+ spreeDiv = level.spreeDivisor;
+ result = ( streak2Test / spreeDiv );
+ resultf = ( float2Test / spreeFDiv );
+
+ if( result == resultf ) {
+ return qtrue;
+ } else {
+ return qfalse;
+ }
+}
+
+/*
+==================
+G_CheckForSpree
+==================
+*/
+void G_CheckForSpree( gentity_t *ent, int streak2Test, qboolean checkKillSpree )
+{
+ int i;
+ char *returnedString;
+ //If somebody want's to award killing sprees above 99 kills he/she can mod this his/herself!!! :)
+ char streakcount[ 3 ];
+ char *sound;
+ int position;
+ int soundIndex;
+
+ qboolean isSpree = qfalse;
+ int divisionHolder;
+
+ //Probably Not Needed, but to protect Server Ops from Crashing their Stuff MidMatch
+ if( level.spreeDivisor < 1 ) {
+ return;
+ }
+ divisionHolder = ( streak2Test / level.spreeDivisor );
+ //if it's a deathspree
+ if( !checkKillSpree ) {
+ //Is the streak higher than the largest level defined?
+ if( divisionHolder > level.dSpreeUBound ) {
+ //Let's make sure it's a whole number to mimic the other sprees
+ isSpree = TestSpreeWhole( streak2Test );
+ if( !isSpree ) {
+ return;
+ }
+ //We've made it this far...now do the largest spree defined.
+ Q_snprintf( streakcount, sizeof( streakcount ), "%i", streak2Test );
+ //Check if deathSprees is NULL (actual problem!)
+ if(!deathSprees[ level.dSpreeUBound ])
+ return;
+ returnedString = CreateMessage( ent, deathSprees[ level.dSpreeUBound ]->spreeMsg, streakcount );
+ position = deathSprees[ level.dSpreeUBound ]->position;
+ sound = deathSprees[ level.dSpreeUBound ]->sound2Play;
+ soundIndex = G_SoundIndex( sound );
+ //Play the Sound
+ G_GlobalSound( soundIndex );
+ //Print the Message
+ if( position == CENTER_PRINT ) {
+ AP( va("cp \"%s\"", returnedString ) );
+ } else {
+ AP( va("chat \"%s\"", returnedString ) );
+ }
+ } else {
+ for( i = 0; deathSprees[ i ]; i++ ) {
+ //If the deathSpree is equal to the streak to test
+ if( deathSprees[ i ]->streakCount == streak2Test ) {
+ //Using Q_snprintf to change the int into a char for replacement.
+ Q_snprintf( streakcount, sizeof( streakcount ), "%i", deathSprees[ i ]->streakCount );
+ //Let's grab the message to show, fill up the placeholders and concatenate it.
+ returnedString = CreateMessage ( ent, deathSprees[ i ]->spreeMsg, streakcount );
+ //Grab the Print Position ( 1 for Center Printing, 2 for Chat )
+ position = deathSprees[ i ]->position;
+ //Grab the Sound
+ sound = deathSprees[ i ]->sound2Play;
+ //Index the Sound
+ soundIndex = G_SoundIndex( sound );
+ //Play the Sound
+ G_GlobalSound( soundIndex );
+ //Print the Message
+ if( position == CENTER_PRINT ) {
+ AP( va("cp \"%s\"", returnedString ) );
+ } else {
+ AP( va("chat \"%s\"", returnedString ) );
+ }
+ break;
+ }
+ }
+ }
+ } else /*if( checkKillSpree )*/ {
+ //Is the streak higher than the largest level defined?
+ if( divisionHolder > level.kSpreeUBound ) {
+ //Let's make sure it's a whole number to mimic the other sprees
+ isSpree = TestSpreeWhole( streak2Test );
+ if( !isSpree ) {
+ return;
+ }
+ //We've made it this far...now do the largest spree defined.
+ Q_snprintf( streakcount, sizeof( streakcount ), "%i", streak2Test );
+ //Check if killSprees is NULL (actual problem!)
+ if(!killSprees[ level.kSpreeUBound ])
+ return;
+ returnedString = CreateMessage( ent, killSprees[ level.kSpreeUBound ]->spreeMsg, streakcount );
+ position = killSprees[ level.kSpreeUBound ]->position;
+ sound = killSprees[ level.kSpreeUBound ]->sound2Play;
+ soundIndex = G_SoundIndex( sound );
+ soundIndex = G_SoundIndex( sound );
+ //G_GlobalSound( soundIndex );
+ G_Sound(ent,0,soundIndex);
+ /* Doesn't do anything at the moment. cp does not work while kill message is displayed
+ * if( position == CENTER_PRINT ) {
+ //Only Center print for player doing the killing spree
+ CP( va("cp \"%s\"", returnedString ) );
+ }*/
+ AP( va("chat \"%s\"", returnedString ) );
+ } else {
+ for( i = 0; killSprees[ i ]; i++ ) {
+ if( killSprees[ i ]->streakCount == streak2Test ) {
+ Q_snprintf( streakcount, sizeof( streakcount ), "%i", killSprees[ i ]->streakCount );
+ returnedString = CreateMessage ( ent, killSprees[ i ]->spreeMsg, streakcount );
+ position = killSprees[ i ]->position;
+ sound = killSprees[ i ]->sound2Play;
+ soundIndex = G_SoundIndex( sound );
+ soundIndex = G_SoundIndex( sound );
+ //G_GlobalSound( soundIndex );
+ G_Sound(ent,0,soundIndex);
+ /*if( position == CENTER_PRINT ) {
+ //Only Center print for player doing the killing spree
+ CP( va("cp \"%s\"", returnedString ) );
+ }*/
+ AP( va("chat \"%s\"", returnedString ) );
+ break;
+ }
+ }
+ }
+ } /*else {
+ G_Printf("Killing Spree Error in G_CheckForSpree\n");
+ return;
+ }*/
+}
+
+
+/*
+===============
+G_checkForMultiKill
+===============
+*/
+void G_checkForMultiKill( gentity_t *ent ) {
+
+ int i;
+ char *returnedString;
+ char *sound;
+ int soundIndex;
+ int multiKillCount;
+ char multiKillString[ 2 ];
+ gclient_t *client;
+ int clientNum;
+
+ client = ent->client;
+ clientNum = client - level.clients;
+
+ //Let's grab the multikill count for the player first
+ multiKillCount = ent->client->pers.multiKillCount;
+
+ if( multiKillCount > multiKills[ level.mKillUBound ]->kills ) {
+ Q_snprintf( multiKillString, sizeof( multiKillString ), "%i", multiKillCount );
+ if(!multiKills[ level.mKillUBound ])
+ return; //If null
+ returnedString = CreateMessage ( ent, multiKills[ level.mKillUBound ]->killMsg, multiKillString );
+ sound = multiKills[ level.mKillUBound ]->sound2Play;
+ soundIndex = G_SoundIndex( sound );
+ G_Sound(ent, 0, soundIndex );
+ AP( va("chat \"%s\"", returnedString ) );
+ return;
+ } else {
+ for( i = 0; multiKills[ i ]; i++ ) {
+ //If the multikill count is equal to a killLevel let's do this.
+
+ if( multiKills[ i ]->kills == multiKillCount ) {
+ Q_snprintf( multiKillString, sizeof( multiKillString ), "%i", multiKills[ i ]->kills );
+ //Build the Message
+ returnedString = CreateMessage ( ent, multiKills[ i ]->killMsg, multiKillString );
+ //Grab the sound
+ sound = multiKills[ i ]->sound2Play;
+ //Index the sound
+ soundIndex = G_SoundIndex( sound );
+ //Play the sound
+ G_Sound(ent, 0, soundIndex );
+ /* Print the String
+ Since we don't want to clutter screens (the player is already going to get the excellent icon)
+ we won't give them an option to centerprint.
+ */
+ AP( va("chat \"%s\"", returnedString ) );
+ break;
+ }
+ }
+
+ }
+
+}
+
+
+
\ No newline at end of file
diff --git a/game/code/game/g_killspree.h b/code/game/g_killspree.h
similarity index 100%
rename from game/code/game/g_killspree.h
rename to code/game/g_killspree.h
diff --git a/code/game/g_local.h b/code/game/g_local.h
new file mode 100644
index 0000000..4b82323
--- /dev/null
+++ b/code/game/g_local.h
@@ -0,0 +1,1391 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 copyPl of the GNU General Public License
+along with Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// g_local.h -- local definitions for game module
+
+#include "../qcommon/q_shared.h"
+#include "bg_public.h"
+#include "g_public.h"
+#include "challenges.h"
+
+//==================================================================
+
+// the "gameversion" client command will print this plus compile date
+#define GAMEVERSION BASEGAME
+
+#define BODY_QUEUE_SIZE 8
+
+#define INFINITE 1000000
+
+#define FRAMETIME 100 // msec
+#define CARNAGE_REWARD_TIME 3000
+#define REWARD_SPRITE_TIME 2000
+
+#define INTERMISSION_DELAY_TIME 1000
+#define SP_INTERMISSION_DELAY_TIME 5000
+
+//Domination how many seconds between awarded a point (multiplied by two if more than 3 points)
+#define DOM_SECSPERPOINT 2000
+
+//limit of the votemaps.cfg file and other custom map files
+#define MAX_MAPS_TEXT 8192
+
+// gentity->flags
+#define FL_GODMODE 0x00000010
+#define FL_NOTARGET 0x00000020
+#define FL_TEAMSLAVE 0x00000400 // not the first on the team
+#define FL_NO_KNOCKBACK 0x00000800
+#define FL_DROPPED_ITEM 0x00001000
+#define FL_NO_BOTS 0x00002000 // spawn point not for bot use
+#define FL_NO_HUMANS 0x00004000 // spawn point just for bots
+#define FL_FORCE_GESTURE 0x00008000 // force gesture on client
+
+// movers are things like doors, plats, buttons, etc
+typedef enum {
+ MOVER_POS1,
+ MOVER_POS2,
+ MOVER_1TO2,
+ MOVER_2TO1
+} moverState_t;
+
+#define SP_PODIUM_MODEL "models/mapobjects/podium/podium4.md3"
+
+//============================================================================
+
+typedef struct gentity_s gentity_t;
+typedef struct gclient_s gclient_t;
+
+struct gentity_s {
+ entityState_t s; // communicated by server to clients
+ entityShared_t r; // shared by both the server system and game
+
+ // DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
+ // EXPECTS THE FIELDS IN THAT ORDER!
+ //================================
+
+ struct gclient_s *client; // NULL if not a client
+
+ qboolean inuse;
+
+ char *classname; // set in QuakeEd
+ int spawnflags; // set in QuakeEd
+
+ qboolean neverFree; // if true, FreeEntity will only unlink
+ // bodyque uses this
+
+ int flags; // FL_* variables
+
+ char *model;
+ char *model2;
+ int freetime; // level.time when the object was freed
+
+ int eventTime; // events will be cleared EVENT_VALID_MSEC after set
+ qboolean freeAfterEvent;
+ qboolean unlinkAfterEvent;
+
+ qboolean physicsObject; // if true, it can be pushed by movers and fall off edges
+ // all game items are physicsObjects,
+ float physicsBounce; // 1.0 = continuous bounce, 0.0 = no bounce
+ int clipmask; // brushes with this content value will be collided against
+ // when moving. items and corpses do not collide against
+ // players, for instance
+
+ // movers
+ moverState_t moverState;
+ int soundPos1;
+ int sound1to2;
+ int sound2to1;
+ int soundPos2;
+ int soundLoop;
+ gentity_t *parent;
+ gentity_t *nextTrain;
+ gentity_t *prevTrain;
+ vec3_t pos1, pos2;
+
+ char *message;
+
+ int timestamp; // body queue sinking, etc
+
+ float angle; // set in editor, -1 = up, -2 = down
+ char *target;
+ char *targetname;
+ char *team;
+ char *targetShaderName;
+ char *targetShaderNewName;
+ gentity_t *target_ent;
+
+ float speed;
+ vec3_t movedir;
+
+ int nextthink;
+ void (*think)(gentity_t *self);
+ void (*reached)(gentity_t *self); // movers call this when hitting endpoint
+ void (*blocked)(gentity_t *self, gentity_t *other);
+ void (*touch)(gentity_t *self, gentity_t *other, trace_t *trace);
+ void (*use)(gentity_t *self, gentity_t *other, gentity_t *activator);
+ void (*pain)(gentity_t *self, gentity_t *attacker, int damage);
+ void (*die)(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod);
+
+ int pain_debounce_time;
+ int fly_sound_debounce_time; // wind tunnel
+ int last_move_time;
+
+ int health;
+
+ qboolean takedamage;
+
+ int damage;
+ int splashDamage; // quad will increase this without increasing radius
+ int splashRadius;
+ int methodOfDeath;
+ int splashMethodOfDeath;
+
+ int count;
+
+ gentity_t *chain;
+ gentity_t *enemy;
+ gentity_t *activator;
+ gentity_t *teamchain; // next entity in team
+ gentity_t *teammaster; // master of the team
+
+ int kamikazeTime;
+ int kamikazeShockTime;
+
+ int watertype;
+ int waterlevel;
+
+ int noise_index;
+
+ // timing variables
+ float wait;
+ float random;
+
+ gitem_t *item; // for bonus items
+};
+
+
+typedef enum {
+ CON_DISCONNECTED,
+ CON_CONNECTING,
+ CON_CONNECTED
+} clientConnected_t;
+
+typedef enum {
+ SPECTATOR_NOT,
+ SPECTATOR_FREE,
+ SPECTATOR_FOLLOW,
+ SPECTATOR_SCOREBOARD
+} spectatorState_t;
+
+typedef enum {
+ TEAM_BEGIN, // Beginning a team game, spawn at base
+ TEAM_ACTIVE // Now actively playing
+} playerTeamStateState_t;
+
+typedef struct {
+ playerTeamStateState_t state;
+
+ int location;
+
+ int captures;
+ int basedefense;
+ int carrierdefense;
+ int flagrecovery;
+ int fragcarrier;
+ int assists;
+
+ float lasthurtcarrier;
+ float lastreturnedflag;
+ float flagsince;
+ float lastfraggedcarrier;
+} playerTeamState_t;
+
+// the auto following clients don't follow a specific client
+// number, but instead follow the first two active players
+#define FOLLOW_ACTIVE1 -1
+#define FOLLOW_ACTIVE2 -2
+
+// client data that stays across multiple levels or tournament restarts
+// this is achieved by writing all the data to cvar strings at game shutdown
+// time and reading them back at connection time. Anything added here
+// MUST be dealt with in G_InitSessionData() / G_ReadSessionData() / G_WriteSessionData()
+typedef struct {
+ team_t sessionTeam;
+ int spectatorNum; // for determining next-in-line to play
+ spectatorState_t spectatorState;
+ int spectatorClient; // for chasecam and follow mode
+ int wins, losses; // tournament stats
+ qboolean teamLeader; // true when this client is a team leader
+} clientSession_t;
+
+//
+#define MAX_NETNAME 36
+#define MAX_VOTE_COUNT "3"
+
+//unlagged - true ping
+#define NUM_PING_SAMPLES 64
+//unlagged - true ping
+
+// client data that stays across multiple respawns, but is cleared
+// on each level change or team change at ClientBegin()
+typedef struct {
+ clientConnected_t connected;
+ usercmd_t cmd; // we would lose angles if not persistant
+ qboolean localClient; // true if "ip" info key is "localhost"
+ qboolean initialSpawn; // the first spawn should be at a cool location
+ qboolean predictItemPickup; // based on cg_predictItems userinfo
+ qboolean pmoveFixed; //
+ char netname[MAX_NETNAME];
+ int maxHealth; // for handicapping
+ int enterTime; // level.time the client entered the game
+ playerTeamState_t teamState; // status in teamplay games
+ int voteCount; // to prevent people from constantly calling votes
+ int teamVoteCount; // to prevent people from constantly calling votes
+ qboolean teamInfo; // send team overlay updates?
+ //elimination:
+ int roundReached; //Only spawn if we are new to this round
+ int livesLeft; //lives in LMS
+
+//unlagged - client options
+ // these correspond with variables in the userinfo string
+ int delag;
+// int debugDelag;
+ int cmdTimeNudge;
+//unlagged - client options
+//unlagged - lag simulation #2
+/* int latentSnaps;
+ int latentCmds;
+ int plOut;
+ usercmd_t cmdqueue[MAX_LATENT_CMDS];
+ int cmdhead;*/
+//unlagged - lag simulation #2
+//unlagged - true ping
+ int realPing;
+ int pingsamples[NUM_PING_SAMPLES];
+ int samplehead;
+//unlagged - true ping
+//KK-OAX Killing Sprees/Multikills
+ int killstreak;
+ int deathstreak;
+ qboolean onSpree;
+ int multiKillCount;
+
+//KK-OAX Admin Stuff
+ char guid[ 33 ];
+ char ip[ 40 ];
+ qboolean muted;
+ qboolean disoriented;
+ qboolean wasdisoriented;
+ int adminLevel;
+
+// flood protection
+ int floodDemerits;
+ int floodTime;
+
+//Used To Track Name Changes
+ int nameChangeTime;
+ int nameChanges;
+
+} clientPersistant_t;
+
+//unlagged - backward reconciliation #1
+// the size of history we'll keep
+#define NUM_CLIENT_HISTORY 17
+
+// everything we need to know to backward reconcile
+typedef struct {
+ vec3_t mins, maxs;
+ vec3_t currentOrigin;
+ int leveltime;
+} clientHistory_t;
+//unlagged - backward reconciliation #1
+
+// this structure is cleared on each ClientSpawn(),
+// except for 'client->pers' and 'client->sess'
+struct gclient_s {
+ // ps MUST be the first element, because the server expects it
+ playerState_t ps; // communicated by server to clients
+
+ // the rest of the structure is private to game
+ clientPersistant_t pers;
+ clientSession_t sess;
+
+ qboolean readyToExit; // wishes to leave the intermission
+
+ qboolean noclip;
+
+ //Unlagged - commented out - handled differently
+ //int lastCmdTime; // level.time of last usercmd_t, for EF_CONNECTION
+ // we can't just use pers.lastCommand.time, because
+ // of the g_sycronousclients case
+ int buttons;
+ int oldbuttons;
+ int latched_buttons;
+
+ vec3_t oldOrigin;
+
+ // sum up damage over an entire frame, so
+ // shotgun blasts give a single big kick
+ int damage_armor; // damage absorbed by armor
+ int damage_blood; // damage taken out of health
+ int damage_knockback; // impact damage
+ vec3_t damage_from; // origin for vector calculation
+ qboolean damage_fromWorld; // if true, don't use the damage_from vector
+
+ int accurateCount; // for "impressive" reward sound
+
+ int accuracy_shots; // total number of shots
+ int accuracy_hits; // total number of hits
+
+ //
+ int lastkilled_client; // last client that this client killed
+ int lasthurt_client; // last client that damaged this client
+ int lasthurt_mod; // type of damage the client did
+
+ // timers
+ int respawnTime; // can respawn when time > this, force after g_forcerespwan
+ int inactivityTime; // kick players when time > this
+ qboolean inactivityWarning; // qtrue if the five seoond warning has been given
+ int rewardTime; // clear the EF_AWARD_IMPRESSIVE, etc when time > this
+
+ int airOutTime;
+
+ int lastKillTime; // for multiple kill rewards
+
+ qboolean fireHeld; // used for hook
+ gentity_t *hook; // grapple hook if out
+
+ int switchTeamTime; // time the player switched teams
+
+ // timeResidual is used to handle events that happen every second
+ // like health / armor countdowns and regeneration
+ int timeResidual;
+
+ gentity_t *persistantPowerup;
+ int portalID;
+ int ammoTimes[WP_NUM_WEAPONS];
+ int invulnerabilityTime;
+
+
+ char *areabits;
+
+ qboolean isEliminated; //Has been killed in this round
+
+ //New vote system. The votes are saved in the client info, so we know who voted on what and can cancel votes on leave.
+ //0=not voted, 1=voted yes, -1=voted no
+ int vote;
+
+ int lastSentFlying; //The last client that sent the player flying
+ int lastSentFlyingTime; //So we can time out
+
+
+ //unlagged - backward reconciliation #1
+ // the serverTime the button was pressed
+ // (stored before pmove_fixed changes serverTime)
+ int attackTime;
+ // the head of the history queue
+ int historyHead;
+ // the history queue
+ clientHistory_t history[NUM_CLIENT_HISTORY];
+ // the client's saved position
+ clientHistory_t saved; // used to restore after time shift
+ // an approximation of the actual server time we received this
+ // command (not in 50ms increments)
+ int frameOffset;
+//unlagged - backward reconciliation #1
+
+//unlagged - smooth clients #1
+ // the last frame number we got an update from this client
+ int lastUpdateFrame;
+//unlagged - smooth clients #1
+ qboolean spawnprotected;
+
+ int accuracy[WP_NUM_WEAPONS][2];
+};
+
+
+//
+// this structure is cleared as each map is entered
+//
+#define MAX_SPAWN_VARS 64
+#define MAX_SPAWN_VARS_CHARS 4096
+
+typedef struct {
+ struct gclient_s *clients; // [maxclients]
+
+ struct gentity_s *gentities;
+ int gentitySize;
+ int num_entities; // current number, <= MAX_GENTITIES
+
+ int warmupTime; // restart match at this time
+
+ fileHandle_t logFile;
+
+ // store latched cvars here that we want to get at often
+ int maxclients;
+
+ int framenum;
+ int time; // in msec
+ int previousTime; // so movers can back up when blocked
+
+ int startTime; // level.time the map was started
+
+ int teamScores[TEAM_NUM_TEAMS];
+ int lastTeamLocationTime; // last time of client team location update
+
+ qboolean newSession; // don't use any old session data, because
+ // we changed gametype
+
+ qboolean restarted; // waiting for a map_restart to fire
+
+ int numConnectedClients;
+ int numNonSpectatorClients; // includes connecting clients
+ int numPlayingClients; // connected, non-spectators
+ int sortedClients[MAX_CLIENTS]; // sorted by score
+ int follow1, follow2; // clientNums for auto-follow spectators
+
+ int snd_fry; // sound index for standing in lava
+
+ int warmupModificationCount; // for detecting if g_warmup is changed
+
+ // voting state
+ char voteString[MAX_STRING_CHARS];
+ char voteDisplayString[MAX_STRING_CHARS];
+ int voteTime; // level.time vote was called
+ int voteExecuteTime; // time the vote is executed
+ int voteYes;
+ int voteNo;
+ int numVotingClients; // set by CountVotes
+ int voteKickClient; // if non-negative the current vote is about this client.
+ int voteKickType; // if 1 = ban (execute ban)
+
+ // team voting state
+ char teamVoteString[2][MAX_STRING_CHARS];
+ int teamVoteTime[2]; // level.time vote was called
+ int teamVoteYes[2];
+ int teamVoteNo[2];
+ int numteamVotingClients[TEAM_NUM_TEAMS];// set by CalculateRanks
+
+ // spawn variables
+ qboolean spawning; // the G_Spawn*() functions are valid
+ int numSpawnVars;
+ char *spawnVars[MAX_SPAWN_VARS][2]; // key / value pairs
+ int numSpawnVarChars;
+ char spawnVarChars[MAX_SPAWN_VARS_CHARS];
+
+ // intermission state
+ int intermissionQueued; // intermission was qualified, but
+ // wait INTERMISSION_DELAY_TIME before
+ // actually going there so the last
+ // frag can be watched. Disable future
+ // kills during this delay
+ int intermissiontime; // time the intermission was started
+ char *changemap;
+ qboolean readyToExit; // at least one client wants to exit
+ int exitTime;
+ vec3_t intermission_origin; // also used for spectator spawns
+ vec3_t intermission_angle;
+
+ qboolean locationLinked; // target_locations get linked
+ gentity_t *locationHead; // head of the location list
+ int bodyQueIndex; // dead bodies
+ gentity_t *bodyQue[BODY_QUEUE_SIZE];
+ int portalSequence;
+ //Added for elimination:
+ int roundStartTime; //time the current round was started
+ int roundNumber; //The round number we have reached
+ int roundNumberStarted; //1 less than roundNumber if we are allowed to spawn
+ int roundRedPlayers; //How many players was there at start of round
+ int roundBluePlayers; //used to find winners in a draw.
+ qboolean roundRespawned; //We have respawned for this round!
+ int eliminationSides; //Random, change red/blue bases
+
+ //Added for Double Domination
+ //Points get status: TEAM_FREE for not taking, TEAM_RED/TEAM_BLUE for taken and TEAM_NONE for not spawned yet
+ int pointStatusA; //Status of the RED (A) domination point
+ int pointStatusB; //Status of the BLUE (B) doimination point
+ int timeTaken; //Time team started having both points
+ //use roundStartTime for telling, then the points respawn
+
+ //Added for standard domination
+ int pointStatusDom[MAX_DOMINATION_POINTS]; //Holds the owner of all the points
+ int dom_scoreGiven; //Number of times we have provided scores
+ int domination_points_count;
+ char domination_points_names[MAX_DOMINATION_POINTS][MAX_DOMINATION_POINTS_NAMES];
+
+ //Added to keep track of challenges (can only be completed against humanplayers)
+ qboolean hadBots; //There was bots in the level
+ int teamSize; //The highest number of players on the least populated team when there was most players
+
+//unlagged - backward reconciliation #4
+ // actual time this server frame started
+ int frameStartTime;
+//unlagged - backward reconciliation #4
+//KK-OAX Storing upper bounds of spree/multikill arrays
+ int kSpreeUBound;
+ int dSpreeUBound;
+ int mKillUBound;
+//KK-OAX Storing g_spreeDiv to avoid dividing by 0.
+ int spreeDivisor;
+
+ qboolean RedTeamLocked;
+ qboolean BlueTeamLocked;
+ qboolean FFALocked;
+
+ //Obelisk tell
+ int healthRedObelisk; //health in percent
+ int healthBlueObelisk; //helth in percent
+ qboolean MustSendObeliskHealth; //Health has changed
+
+} level_locals_t;
+
+//KK-OAX These are some Print Shortcuts for KillingSprees and Admin
+//KK-Moved to g_admin.h
+//Prints to All when using "va()" in conjunction.
+//#define AP(x) trap_SendServerCommand(-1, x)
+
+//
+// g_spawn.c
+//
+qboolean G_SpawnString( const char *key, const char *defaultString, char **out );
+// spawn string returns a temporary reference, you must CopyString() if you want to keep it
+qboolean G_SpawnFloat( const char *key, const char *defaultString, float *out );
+qboolean G_SpawnInt( const char *key, const char *defaultString, int *out );
+qboolean G_SpawnVector( const char *key, const char *defaultString, float *out );
+void G_SpawnEntitiesFromString( void );
+char *G_NewString( const char *string );
+
+//
+// g_cmds.c
+//
+void Cmd_Score_f (gentity_t *ent);
+void StopFollowing( gentity_t *ent );
+void BroadcastTeamChange( gclient_t *client, int oldTeam );
+void SetTeam( gentity_t *ent, char *s );
+void Cmd_FollowCycle_f( gentity_t *ent ); //KK-OAX Changed to match definition
+char *ConcatArgs( int start ); //KK-OAX This declaration moved from g_svccmds.c
+//KK-OAX Added this to make accessible from g_svcmds_ext.c
+void G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText );
+
+
+// KK-OAX Added these in a seperate file to keep g_cmds.c familiar.
+// g_cmds_ext.c
+//
+
+int G_SayArgc( void );
+qboolean G_SayArgv( int n, char *buffer, int bufferLength );
+char *G_SayConcatArgs( int start );
+void G_DecolorString( char *in, char *out, int len );
+void G_MatchOnePlayer( int *plist, int num, char *err, int len );
+void G_SanitiseString( char *in, char *out, int len );
+int G_ClientNumbersFromString( char *s, int *plist, int max );
+int G_FloodLimited( gentity_t *ent );
+//void QDECL G_AdminMessage( const char *prefix, const char *fmt, ... )
+// ^^ Do Not Need to Declare--Just for Documentation of where it is.
+void Cmd_AdminMessage_f( gentity_t *ent );
+int G_ClientNumberFromString( char *s );
+qboolean G_ClientIsLagging( gclient_t *client );
+void SanitizeString( char *in, char *out );
+
+// KK-OAX Added this for common file stuff between Admin and Sprees.
+// g_fileops.c
+//
+void readFile_int( char **cnf, int *v );
+void readFile_string( char **cnf, char *s, int size );
+void writeFile_int( int v, fileHandle_t f );
+void writeFile_string( char *s, fileHandle_t f );
+
+//
+// g_items.c
+//
+void G_CheckTeamItems( void );
+void G_RunItem( gentity_t *ent );
+void RespawnItem( gentity_t *ent );
+
+void UseHoldableItem( gentity_t *ent );
+void PrecacheItem (gitem_t *it);
+gentity_t *Drop_Item( gentity_t *ent, gitem_t *item, float angle );
+gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity );
+void SetRespawn (gentity_t *ent, float delay);
+void G_SpawnItem (gentity_t *ent, gitem_t *item);
+void FinishSpawningItem( gentity_t *ent );
+void Think_Weapon (gentity_t *ent);
+int ArmorIndex (gentity_t *ent);
+void Add_Ammo (gentity_t *ent, int weapon, int count);
+void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace);
+
+void ClearRegisteredItems( void );
+void RegisterItem( gitem_t *item );
+void SaveRegisteredItems( void );
+
+//
+// g_utils.c
+//
+int G_ModelIndex( char *name );
+int G_SoundIndex( char *name );
+void G_TeamCommand( team_t team, char *cmd );
+void G_KillBox (gentity_t *ent);
+gentity_t *G_Find (gentity_t *from, int fieldofs, const char *match);
+gentity_t *G_PickTarget (char *targetname);
+void G_UseTargets (gentity_t *ent, gentity_t *activator);
+void G_SetMovedir ( vec3_t angles, vec3_t movedir);
+
+void G_InitGentity( gentity_t *e );
+gentity_t *G_Spawn (void);
+gentity_t *G_TempEntity( vec3_t origin, int event );
+void G_Sound( gentity_t *ent, int channel, int soundIndex );
+
+//KK-OAX For Playing Sounds Globally
+void G_GlobalSound( int soundIndex );
+
+void G_FreeEntity( gentity_t *e );
+qboolean G_EntitiesFree( void );
+
+void G_TouchTriggers (gentity_t *ent);
+void G_TouchSolids (gentity_t *ent);
+
+float *tv (float x, float y, float z);
+char *vtos( const vec3_t v );
+
+float vectoyaw( const vec3_t vec );
+
+void G_AddPredictableEvent( gentity_t *ent, int event, int eventParm );
+void G_AddEvent( gentity_t *ent, int event, int eventParm );
+void G_SetOrigin( gentity_t *ent, vec3_t origin );
+void AddRemap(const char *oldShader, const char *newShader, float timeOffset);
+const char *BuildShaderStateConfig( void );
+
+//
+// g_combat.c
+//
+qboolean CanDamage (gentity_t *targ, vec3_t origin);
+void G_Damage (gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_t dir, vec3_t point, int damage, int dflags, int mod);
+qboolean G_RadiusDamage (vec3_t origin, gentity_t *attacker, float damage, float radius, gentity_t *ignore, int mod);
+int G_InvulnerabilityEffect( gentity_t *targ, vec3_t dir, vec3_t point, vec3_t impactpoint, vec3_t bouncedir );
+void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath );
+void TossClientItems( gentity_t *self );
+void TossClientPersistantPowerups( gentity_t *self );
+void TossClientCubes( gentity_t *self );
+
+// damage flags
+#define DAMAGE_RADIUS 0x00000001 // damage was indirect
+#define DAMAGE_NO_ARMOR 0x00000002 // armour does not protect from this damage
+#define DAMAGE_NO_KNOCKBACK 0x00000004 // do not affect velocity, just view angles
+#define DAMAGE_NO_PROTECTION 0x00000008 // armor, shields, invulnerability, and godmode have no effect
+#define DAMAGE_NO_TEAM_PROTECTION 0x00000010 // armor, shields, invulnerability, and godmode have no effect
+
+//
+// g_missile.c
+//
+void G_RunMissile( gentity_t *ent );
+void ProximityMine_RemoveAll( void );
+
+gentity_t *fire_blaster (gentity_t *self, vec3_t start, vec3_t aimdir);
+gentity_t *fire_plasma (gentity_t *self, vec3_t start, vec3_t aimdir);
+gentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t aimdir);
+gentity_t *fire_rocket (gentity_t *self, vec3_t start, vec3_t dir);
+gentity_t *fire_bfg (gentity_t *self, vec3_t start, vec3_t dir);
+gentity_t *fire_grapple (gentity_t *self, vec3_t start, vec3_t dir);
+gentity_t *fire_nail( gentity_t *self, vec3_t start, vec3_t forward, vec3_t right, vec3_t up );
+gentity_t *fire_prox( gentity_t *self, vec3_t start, vec3_t aimdir );
+
+
+//
+// g_mover.c
+//
+void G_RunMover( gentity_t *ent );
+void Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace );
+
+//
+// g_trigger.c
+//
+void trigger_teleporter_touch (gentity_t *self, gentity_t *other, trace_t *trace );
+
+
+//
+// g_misc.c
+//
+void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles );
+void DropPortalSource( gentity_t *ent );
+void DropPortalDestination( gentity_t *ent );
+
+
+//
+// g_weapon.c
+//
+qboolean LogAccuracyHit( gentity_t *target, gentity_t *attacker );
+void CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint );
+//unlagged - attack prediction #3
+// we're making this available to both games
+void SnapVectorTowards( vec3_t v, vec3_t to );
+//unlagged - attack prediction #3
+qboolean CheckGauntletAttack( gentity_t *ent );
+void Weapon_HookFree (gentity_t *ent);
+void Weapon_HookThink (gentity_t *ent);
+
+//unlagged - g_unlagged.c
+void G_ResetHistory( gentity_t *ent );
+void G_StoreHistory( gentity_t *ent );
+void G_TimeShiftAllClients( int time, gentity_t *skip );
+void G_UnTimeShiftAllClients( gentity_t *skip );
+void G_DoTimeShiftFor( gentity_t *ent );
+void G_UndoTimeShiftFor( gentity_t *ent );
+void G_UnTimeShiftClient( gentity_t *client );
+void G_PredictPlayerMove( gentity_t *ent, float frametime );
+//unlagged - g_unlagged.c
+
+//
+// g_client.c
+//
+team_t TeamCount( int ignoreClientNum, int team );
+team_t TeamLivingCount( int ignoreClientNum, int team ); //Elimination
+team_t TeamHealthCount( int ignoreClientNum, int team ); //Elimination
+void RespawnAll(void); //For round elimination
+void RespawnDead(void);
+void EnableWeapons(void);
+void DisableWeapons(void);
+void EndEliminationRound(void);
+void LMSpoint(void);
+//void wins2score(void);
+int TeamLeader( int team );
+team_t PickTeam( int ignoreClientNum );
+void SetClientViewAngle( gentity_t *ent, vec3_t angle );
+gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles );
+void CopyToBodyQue( gentity_t *ent );
+void ClientRespawn(gentity_t *ent);
+void BeginIntermission (void);
+void InitClientPersistant (gclient_t *client);
+void InitClientResp (gclient_t *client);
+void InitBodyQue (void);
+void ClientSpawn( gentity_t *ent );
+void player_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod);
+void AddScore( gentity_t *ent, vec3_t origin, int score );
+void CalculateRanks( void );
+qboolean SpotWouldTelefrag( gentity_t *spot );
+
+//
+// g_svcmds.c
+//
+qboolean ConsoleCommand( void );
+void G_ProcessIPBans(void);
+qboolean G_FilterPacket (char *from);
+
+//KK-OAX Added this to make accessible from g_svcmds_ext.c
+gclient_t *ClientForString( const char *s );
+
+//
+// g_weapon.c
+//
+void FireWeapon( gentity_t *ent );
+void G_StartKamikaze( gentity_t *ent );
+
+//
+// p_hud.c
+//
+void MoveClientToIntermission (gentity_t *client);
+void G_SetStats (gentity_t *ent);
+
+//
+// g_cmds.c
+// Also another place /Sago
+
+void DoubleDominationScoreTimeMessage( gentity_t *ent );
+void YourTeamMessage( gentity_t *ent);
+void AttackingTeamMessage( gentity_t *ent );
+void ObeliskHealthMessage( void );
+void DeathmatchScoreboardMessage (gentity_t *client);
+void EliminationMessage (gentity_t *client);
+void RespawnTimeMessage(gentity_t *ent, int time);
+void DominationPointNamesMessage (gentity_t *client);
+void DominationPointStatusMessage( gentity_t *ent );
+void ChallengeMessage( gentity_t *ent, int challengeNumber );
+void SendCustomVoteCommands(int clientNum);
+
+//
+// g_pweapon.c
+//
+
+
+//
+// g_main.c
+//
+void FindIntermissionPoint( void );
+void SetLeader(int team, int client);
+void CheckTeamLeader( int team );
+void G_RunThink (gentity_t *ent);
+void AddTournamentQueue(gclient_t *client);
+void ExitLevel( void );
+void QDECL G_LogPrintf( const char *fmt, ... );
+void SendScoreboardMessageToAllClients( void );
+void SendEliminationMessageToAllClients( void );
+void SendDDtimetakenMessageToAllClients( void );
+void SendDominationPointsStatusMessageToAllClients( void );
+void SendYourTeamMessageToTeam( team_t team );
+void QDECL G_Printf( const char *fmt, ... );
+void QDECL G_Error( const char *fmt, ... ) __attribute__((noreturn));
+//KK-OAX Made Accessible for g_admin.c
+void LogExit( const char *string );
+void CheckTeamVote( int team );
+
+//
+// g_client.c
+//
+char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot );
+void ClientUserinfoChanged( int clientNum );
+void ClientDisconnect( int clientNum );
+void ClientBegin( int clientNum );
+void ClientCommand( int clientNum );
+
+//
+// g_active.c
+//
+void ClientThink( int clientNum );
+void ClientEndFrame( gentity_t *ent );
+void G_RunClient( gentity_t *ent );
+
+//
+// g_team.c
+//
+qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 );
+void Team_CheckDroppedItem( gentity_t *dropped );
+qboolean CheckObeliskAttack( gentity_t *obelisk, gentity_t *attacker );
+void ShuffleTeams(void);
+//KK-OAX Added for Command Handling Changes (r24)
+team_t G_TeamFromString( char *str );
+
+//KK-OAX Removed these in Code in favor of bg_alloc.c from Tremulous
+// g_mem.c
+//
+//void *G_Alloc( int size );
+//void G_InitMemory( void );
+
+//KK-OAX This was moved
+// bg_alloc.c
+//
+void Svcmd_GameMem_f( void );
+
+//
+// g_session.c
+//
+void G_ReadSessionData( gclient_t *client );
+void G_InitSessionData( gclient_t *client, char *userinfo );
+
+void G_InitWorldSession( void );
+void G_WriteSessionData( void );
+
+//
+// g_arenas.c
+//
+void UpdateTournamentInfo( void );
+void SpawnModelsOnVictoryPads( void );
+void Svcmd_AbortPodium_f( void );
+
+//
+// g_bot.c
+//
+void G_InitBots( qboolean restart );
+char *G_GetBotInfoByNumber( int num );
+char *G_GetBotInfoByName( const char *name );
+void G_CheckBotSpawn( void );
+void G_RemoveQueuedBotBegin( int clientNum );
+qboolean G_BotConnect( int clientNum, qboolean restart );
+void Svcmd_AddBot_f( void );
+void Svcmd_BotList_f( void );
+void BotInterbreedEndMatch( void );
+
+//
+// g_playerstore.c
+//
+
+void PlayerStoreInit( void );
+void PlayerStore_store(char* guid, playerState_t ps);
+void PlayerStore_restore(char* guid, playerState_t *ps);
+
+//
+// g_vote.c
+//
+int allowedVote(char *commandStr);
+void CheckVote( void );
+void CountVotes( void );
+void ClientLeaving(int clientNumber);
+
+#define MAX_MAPNAME 32
+#define MAPS_PER_PAGE 10
+#define MAX_MAPNAME_BUFFER MAX_MAPNAME*600
+#define MAX_MAPNAME_LENGTH 34
+#define MAX_CUSTOMNAME MAX_MAPNAME
+#define MAX_CUSTOMCOMMAND 100
+#define MAX_CUSTOMDISPLAYNAME 50
+
+typedef struct {
+ int pagenumber;
+ char mapname[MAPS_PER_PAGE][MAX_MAPNAME];
+} t_mappage;
+
+typedef struct {
+ char votename[MAX_CUSTOMNAME]; //Used like "/callvote custom VOTENAME"
+ char displayname[MAX_CUSTOMDISPLAYNAME]; //Displayed during voting
+ char command[MAX_CUSTOMCOMMAND]; //The command executed
+} t_customvote;
+
+extern char custom_vote_info[1024];
+
+extern t_mappage getMappage(int page);
+extern int allowedMap(char *mapname);
+extern int allowedGametype(char *gametypeStr);
+extern int allowedTimelimit(int limit);
+extern int allowedFraglimit(int limit);
+extern int VoteParseCustomVotes( void );
+extern t_customvote getCustomVote(char* votecommand);
+
+// ai_main.c
+#define MAX_FILEPATH 144
+
+//bot settings
+typedef struct bot_settings_s
+{
+ char characterfile[MAX_FILEPATH];
+ float skill;
+ char team[MAX_FILEPATH];
+} bot_settings_t;
+
+int BotAISetup( int restart );
+int BotAIShutdown( int restart );
+int BotAILoadMap( int restart );
+int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean restart);
+int BotAIShutdownClient( int client, qboolean restart );
+int BotAIStartFrame( int time );
+void BotTestAAS(vec3_t origin);
+
+#include "g_team.h" // teamplay specific stuff
+
+
+extern level_locals_t level;
+extern gentity_t g_entities[MAX_GENTITIES];
+
+#define FOFS(x) ((size_t)&(((gentity_t *)0)->x))
+
+//CVARS
+extern vmCvar_t g_gametype;
+extern vmCvar_t g_dedicated;
+extern vmCvar_t g_cheats;
+extern vmCvar_t g_maxclients; // allow this many total, including spectators
+extern vmCvar_t g_maxGameClients; // allow this many active
+extern vmCvar_t g_restarted;
+
+extern vmCvar_t g_dmflags;
+extern vmCvar_t g_videoflags;
+extern vmCvar_t g_elimflags;
+extern vmCvar_t g_voteflags;
+extern vmCvar_t g_fraglimit;
+extern vmCvar_t g_timelimit;
+extern vmCvar_t g_capturelimit;
+extern vmCvar_t g_friendlyFire;
+extern vmCvar_t g_password;
+extern vmCvar_t g_needpass;
+extern vmCvar_t g_gravity;
+extern vmCvar_t g_gravityModifier;
+extern vmCvar_t g_damageModifier;
+extern vmCvar_t g_speed;
+extern vmCvar_t g_knockback;
+extern vmCvar_t g_quadfactor;
+extern vmCvar_t g_forcerespawn;
+extern vmCvar_t g_respawntime;
+extern vmCvar_t g_inactivity;
+extern vmCvar_t g_debugMove;
+extern vmCvar_t g_debugAlloc;
+extern vmCvar_t g_debugDamage;
+extern vmCvar_t g_weaponRespawn;
+extern vmCvar_t g_weaponTeamRespawn;
+extern vmCvar_t g_synchronousClients;
+extern vmCvar_t g_motd;
+extern vmCvar_t g_motdfile;
+extern vmCvar_t g_votemaps;
+extern vmCvar_t g_votecustom;
+extern vmCvar_t g_warmup;
+extern vmCvar_t g_doWarmup;
+extern vmCvar_t g_blood;
+extern vmCvar_t g_allowVote;
+extern vmCvar_t g_teamAutoJoin;
+extern vmCvar_t g_teamForceBalance;
+extern vmCvar_t g_banIPs;
+extern vmCvar_t g_filterBan;
+extern vmCvar_t g_obeliskHealth;
+extern vmCvar_t g_obeliskRegenPeriod;
+extern vmCvar_t g_obeliskRegenAmount;
+extern vmCvar_t g_obeliskRespawnDelay;
+extern vmCvar_t g_cubeTimeout;
+extern vmCvar_t g_smoothClients;
+extern vmCvar_t pmove_fixed;
+extern vmCvar_t pmove_msec;
+extern vmCvar_t pmove_float;
+extern vmCvar_t g_rankings;
+#ifdef MISSIONPACK
+extern vmCvar_t g_singlePlayer;
+extern vmCvar_t g_redteam;
+extern vmCvar_t g_blueteam;
+#endif
+extern vmCvar_t g_enableDust;
+extern vmCvar_t g_enableBreath;
+extern vmCvar_t g_proxMineTimeout;
+extern vmCvar_t g_music;
+extern vmCvar_t g_spawnprotect;
+
+//elimination:
+extern vmCvar_t g_elimination_selfdamage;
+extern vmCvar_t g_elimination_startHealth;
+extern vmCvar_t g_elimination_startArmor;
+extern vmCvar_t g_elimination_bfg;
+extern vmCvar_t g_elimination_grapple;
+extern vmCvar_t g_elimination_roundtime;
+extern vmCvar_t g_elimination_warmup;
+extern vmCvar_t g_elimination_activewarmup;
+extern vmCvar_t g_elimination_allgametypes;
+extern vmCvar_t g_elimination_machinegun;
+extern vmCvar_t g_elimination_shotgun;
+extern vmCvar_t g_elimination_grenade;
+extern vmCvar_t g_elimination_rocket;
+extern vmCvar_t g_elimination_railgun;
+extern vmCvar_t g_elimination_lightning;
+extern vmCvar_t g_elimination_plasmagun;
+extern vmCvar_t g_elimination_chain;
+extern vmCvar_t g_elimination_mine;
+extern vmCvar_t g_elimination_nail;
+
+//If lockspectator: 0=no limit, 1 = cannot follow enemy, 2 = must follow friend
+extern vmCvar_t g_elimination_lockspectator;
+
+extern vmCvar_t g_rockets;
+
+//new in elimination Beta2
+extern vmCvar_t g_instantgib;
+extern vmCvar_t g_vampire;
+extern vmCvar_t g_vampireMaxHealth;
+//new in elimination Beta3
+extern vmCvar_t g_regen;
+//Free for all gametype
+extern int g_ffa_gt; //0 = TEAM GAME, 1 = FFA, 2 = TEAM GAME without bases
+
+extern vmCvar_t g_lms_lives;
+
+extern vmCvar_t g_lms_mode; //How do we score: 0 = One Survivor get a point, 1 = same but without overtime, 2 = one point for each player killed (+overtime), 3 = same without overtime
+
+extern vmCvar_t g_elimination_ctf_oneway; //Only attack in one direction (level.eliminationSides+level.roundNumber)%2 == 0 red attacks
+
+extern vmCvar_t g_awardpushing; //The server can decide if players are awarded for pushing people in lave etc.
+
+extern vmCvar_t g_persistantpowerups;
+
+extern vmCvar_t g_catchup; //Favors the week players
+
+extern vmCvar_t g_autonextmap; //Autochange map
+extern vmCvar_t g_mappools; //mappools to be used for autochange
+
+extern vmCvar_t g_voteNames;
+extern vmCvar_t g_voteBan;
+extern vmCvar_t g_voteGametypes;
+extern vmCvar_t g_voteMinTimelimit;
+extern vmCvar_t g_voteMaxTimelimit;
+extern vmCvar_t g_voteMinFraglimit;
+extern vmCvar_t g_voteMaxFraglimit;
+extern vmCvar_t g_maxvotes;
+
+extern vmCvar_t g_humanplayers;
+
+//used for voIP
+extern vmCvar_t g_redTeamClientNumbers;
+extern vmCvar_t g_blueTeamClientNumbers;
+
+//unlagged - server options
+// some new server-side variables
+extern vmCvar_t g_delagHitscan;
+extern vmCvar_t g_truePing;
+// this is for convenience - using "sv_fps.integer" is nice :)
+extern vmCvar_t sv_fps;
+extern vmCvar_t g_lagLightning;
+//unlagged - server options
+//KK-OAX Killing Sprees
+extern vmCvar_t g_sprees; //Used for specifiying the config file
+extern vmCvar_t g_altExcellent; //Turns on Multikills instead of Excellent
+extern vmCvar_t g_spreeDiv; // Interval of a "streak" that form the spree triggers
+//KK-OAX Command/Chat Flooding/Spamming
+extern vmCvar_t g_floodMaxDemerits;
+extern vmCvar_t g_floodMinTime;
+//KK-OAX Admin
+extern vmCvar_t g_admin;
+extern vmCvar_t g_adminLog;
+extern vmCvar_t g_adminParseSay;
+extern vmCvar_t g_adminNameProtect;
+extern vmCvar_t g_adminTempBan;
+extern vmCvar_t g_adminMaxBan;
+//KK-OAX Admin-Like
+extern vmCvar_t g_specChat;
+extern vmCvar_t g_publicAdminMessages;
+
+extern vmCvar_t g_maxWarnings;
+extern vmCvar_t g_warningExpire;
+
+extern vmCvar_t g_minNameChangePeriod;
+extern vmCvar_t g_maxNameChanges;
+
+
+void trap_Printf( const char *fmt );
+void trap_Error( const char *fmt ) __attribute__((noreturn));
+int trap_Milliseconds( void );
+int trap_RealTime( qtime_t *qtime );
+int trap_Argc( void );
+void trap_Argv( int n, char *buffer, int bufferLength );
+void trap_Args( char *buffer, int bufferLength );
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
+void trap_FS_Read( void *buffer, int len, fileHandle_t f );
+void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
+void trap_FS_FCloseFile( fileHandle_t f );
+int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
+int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
+void trap_SendConsoleCommand( int exec_when, const char *text );
+void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags );
+void trap_Cvar_Update( vmCvar_t *cvar );
+void trap_Cvar_Set( const char *var_name, const char *value );
+int trap_Cvar_VariableIntegerValue( const char *var_name );
+float trap_Cvar_VariableValue( const char *var_name );
+void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
+void trap_LocateGameData( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t, playerState_t *gameClients, int sizeofGameClient );
+void trap_DropClient( int clientNum, const char *reason );
+void trap_SendServerCommand( int clientNum, const char *text );
+void trap_SetConfigstring( int num, const char *string );
+void trap_GetConfigstring( int num, char *buffer, int bufferSize );
+void trap_GetUserinfo( int num, char *buffer, int bufferSize );
+void trap_SetUserinfo( int num, const char *buffer );
+void trap_GetServerinfo( char *buffer, int bufferSize );
+void trap_SetBrushModel( gentity_t *ent, const char *name );
+void trap_Trace( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
+int trap_PointContents( const vec3_t point, int passEntityNum );
+qboolean trap_InPVS( const vec3_t p1, const vec3_t p2 );
+qboolean trap_InPVSIgnorePortals( const vec3_t p1, const vec3_t p2 );
+void trap_AdjustAreaPortalState( gentity_t *ent, qboolean open );
+qboolean trap_AreasConnected( int area1, int area2 );
+void trap_LinkEntity( gentity_t *ent );
+void trap_UnlinkEntity( gentity_t *ent );
+int trap_EntitiesInBox( const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount );
+qboolean trap_EntityContact( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
+int trap_BotAllocateClient( void );
+void trap_BotFreeClient( int clientNum );
+void trap_GetUsercmd( int clientNum, usercmd_t *cmd );
+qboolean trap_GetEntityToken( char *buffer, int bufferSize );
+
+int trap_DebugPolygonCreate(int color, int numPoints, vec3_t *points);
+void trap_DebugPolygonDelete(int id);
+
+int trap_BotLibSetup( void );
+int trap_BotLibShutdown( void );
+int trap_BotLibVarSet(char *var_name, char *value);
+int trap_BotLibVarGet(char *var_name, char *value, int size);
+int trap_BotLibDefine(char *string);
+int trap_BotLibStartFrame(float time);
+int trap_BotLibLoadMap(const char *mapname);
+int trap_BotLibUpdateEntity(int ent, void /* struct bot_updateentity_s */ *bue);
+int trap_BotLibTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3);
+
+int trap_BotGetSnapshotEntity( int clientNum, int sequence );
+int trap_BotGetServerCommand(int clientNum, char *message, int size);
+void trap_BotUserCommand(int client, usercmd_t *ucmd);
+
+int trap_AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas);
+int trap_AAS_AreaInfo( int areanum, void /* struct aas_areainfo_s */ *info );
+void trap_AAS_EntityInfo(int entnum, void /* struct aas_entityinfo_s */ *info);
+
+int trap_AAS_Initialized(void);
+void trap_AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs);
+float trap_AAS_Time(void);
+
+int trap_AAS_PointAreaNum(vec3_t point);
+int trap_AAS_PointReachabilityAreaIndex(vec3_t point);
+int trap_AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas);
+
+int trap_AAS_PointContents(vec3_t point);
+int trap_AAS_NextBSPEntity(int ent);
+int trap_AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size);
+int trap_AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v);
+int trap_AAS_FloatForBSPEpairKey(int ent, char *key, float *value);
+int trap_AAS_IntForBSPEpairKey(int ent, char *key, int *value);
+
+int trap_AAS_AreaReachability(int areanum);
+
+int trap_AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags);
+int trap_AAS_EnableRoutingArea( int areanum, int enable );
+int trap_AAS_PredictRoute(void /*struct aas_predictroute_s*/ *route, int areanum, vec3_t origin,
+ int goalareanum, int travelflags, int maxareas, int maxtime,
+ int stopevent, int stopcontents, int stoptfl, int stopareanum);
+
+int trap_AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,
+ void /*struct aas_altroutegoal_s*/ *altroutegoals, int maxaltroutegoals,
+ int type);
+int trap_AAS_Swimming(vec3_t origin);
+int trap_AAS_PredictClientMovement(void /* aas_clientmove_s */ *move, int entnum, vec3_t origin, int presencetype, int onground, vec3_t velocity, vec3_t cmdmove, int cmdframes, int maxframes, float frametime, int stopevent, int stopareanum, int visualize);
+
+
+void trap_EA_Say(int client, char *str);
+void trap_EA_SayTeam(int client, char *str);
+void trap_EA_Command(int client, char *command);
+
+void trap_EA_Action(int client, int action);
+void trap_EA_Gesture(int client);
+void trap_EA_Talk(int client);
+void trap_EA_Attack(int client);
+void trap_EA_Use(int client);
+void trap_EA_Respawn(int client);
+void trap_EA_Crouch(int client);
+void trap_EA_MoveUp(int client);
+void trap_EA_MoveDown(int client);
+void trap_EA_MoveForward(int client);
+void trap_EA_MoveBack(int client);
+void trap_EA_MoveLeft(int client);
+void trap_EA_MoveRight(int client);
+void trap_EA_SelectWeapon(int client, int weapon);
+void trap_EA_Jump(int client);
+void trap_EA_DelayedJump(int client);
+void trap_EA_Move(int client, vec3_t dir, float speed);
+void trap_EA_View(int client, vec3_t viewangles);
+
+void trap_EA_EndRegular(int client, float thinktime);
+void trap_EA_GetInput(int client, float thinktime, void /* struct bot_input_s */ *input);
+void trap_EA_ResetInput(int client);
+
+
+int trap_BotLoadCharacter(char *charfile, float skill);
+void trap_BotFreeCharacter(int character);
+float trap_Characteristic_Float(int character, int index);
+float trap_Characteristic_BFloat(int character, int index, float min, float max);
+int trap_Characteristic_Integer(int character, int index);
+int trap_Characteristic_BInteger(int character, int index, int min, int max);
+void trap_Characteristic_String(int character, int index, char *buf, int size);
+
+int trap_BotAllocChatState(void);
+void trap_BotFreeChatState(int handle);
+void trap_BotQueueConsoleMessage(int chatstate, int type, char *message);
+void trap_BotRemoveConsoleMessage(int chatstate, int handle);
+int trap_BotNextConsoleMessage(int chatstate, void /* struct bot_consolemessage_s */ *cm);
+int trap_BotNumConsoleMessages(int chatstate);
+void trap_BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 );
+int trap_BotNumInitialChats(int chatstate, char *type);
+int trap_BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 );
+int trap_BotChatLength(int chatstate);
+void trap_BotEnterChat(int chatstate, int client, int sendto);
+void trap_BotGetChatMessage(int chatstate, char *buf, int size);
+int trap_StringContains(char *str1, char *str2, int casesensitive);
+int trap_BotFindMatch(char *str, void /* struct bot_match_s */ *match, unsigned long int context);
+void trap_BotMatchVariable(void /* struct bot_match_s */ *match, int variable, char *buf, int size);
+void trap_UnifyWhiteSpaces(char *string);
+void trap_BotReplaceSynonyms(char *string, unsigned long int context);
+int trap_BotLoadChatFile(int chatstate, char *chatfile, char *chatname);
+void trap_BotSetChatGender(int chatstate, int gender);
+void trap_BotSetChatName(int chatstate, char *name, int client);
+void trap_BotResetGoalState(int goalstate);
+void trap_BotRemoveFromAvoidGoals(int goalstate, int number);
+void trap_BotResetAvoidGoals(int goalstate);
+void trap_BotPushGoal(int goalstate, void /* struct bot_goal_s */ *goal);
+void trap_BotPopGoal(int goalstate);
+void trap_BotEmptyGoalStack(int goalstate);
+void trap_BotDumpAvoidGoals(int goalstate);
+void trap_BotDumpGoalStack(int goalstate);
+void trap_BotGoalName(int number, char *name, int size);
+int trap_BotGetTopGoal(int goalstate, void /* struct bot_goal_s */ *goal);
+int trap_BotGetSecondGoal(int goalstate, void /* struct bot_goal_s */ *goal);
+int trap_BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags);
+int trap_BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, void /* struct bot_goal_s */ *ltg, float maxtime);
+int trap_BotTouchingGoal(vec3_t origin, void /* struct bot_goal_s */ *goal);
+int trap_BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, void /* struct bot_goal_s */ *goal);
+int trap_BotGetNextCampSpotGoal(int num, void /* struct bot_goal_s */ *goal);
+int trap_BotGetMapLocationGoal(char *name, void /* struct bot_goal_s */ *goal);
+int trap_BotGetLevelItemGoal(int index, char *classname, void /* struct bot_goal_s */ *goal);
+float trap_BotAvoidGoalTime(int goalstate, int number);
+void trap_BotSetAvoidGoalTime(int goalstate, int number, float avoidtime);
+void trap_BotInitLevelItems(void);
+void trap_BotUpdateEntityItems(void);
+int trap_BotLoadItemWeights(int goalstate, char *filename);
+void trap_BotFreeItemWeights(int goalstate);
+void trap_BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child);
+void trap_BotSaveGoalFuzzyLogic(int goalstate, char *filename);
+void trap_BotMutateGoalFuzzyLogic(int goalstate, float range);
+int trap_BotAllocGoalState(int state);
+void trap_BotFreeGoalState(int handle);
+
+void trap_BotResetMoveState(int movestate);
+void trap_BotMoveToGoal(void /* struct bot_moveresult_s */ *result, int movestate, void /* struct bot_goal_s */ *goal, int travelflags);
+int trap_BotMoveInDirection(int movestate, vec3_t dir, float speed, int type);
+void trap_BotResetAvoidReach(int movestate);
+void trap_BotResetLastAvoidReach(int movestate);
+int trap_BotReachabilityArea(vec3_t origin, int testground);
+int trap_BotMovementViewTarget(int movestate, void /* struct bot_goal_s */ *goal, int travelflags, float lookahead, vec3_t target);
+int trap_BotPredictVisiblePosition(vec3_t origin, int areanum, void /* struct bot_goal_s */ *goal, int travelflags, vec3_t target);
+int trap_BotAllocMoveState(void);
+void trap_BotFreeMoveState(int handle);
+void trap_BotInitMoveState(int handle, void /* struct bot_initmove_s */ *initmove);
+void trap_BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type);
+
+int trap_BotChooseBestFightWeapon(int weaponstate, int *inventory);
+void trap_BotGetWeaponInfo(int weaponstate, int weapon, void /* struct weaponinfo_s */ *weaponinfo);
+int trap_BotLoadWeaponWeights(int weaponstate, char *filename);
+int trap_BotAllocWeaponState(void);
+void trap_BotFreeWeaponState(int weaponstate);
+void trap_BotResetWeaponState(int weaponstate);
+
+int trap_GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child);
+
+void trap_SnapVector( float *v );
+
+//KK-OAX
+//These enable the simplified command handling.
+
+#define CMD_CHEAT 0x0001
+#define CMD_CHEAT_TEAM 0x0002 // is a cheat when used on a team
+#define CMD_MESSAGE 0x0004 // sends message to others (skip when muted)
+#define CMD_TEAM 0x0008 // must be on a team
+#define CMD_NOTEAM 0x0010 // must not be on a team
+#define CMD_RED 0x0020 // must be on the red team (useless right now)
+#define CMD_BLUE 0x0040 // must be on the blue team (useless right now)
+#define CMD_LIVING 0x0080
+#define CMD_INTERMISSION 0x0100 // valid during intermission
+
+
+typedef struct
+{
+ char *cmdName;
+ int cmdFlags;
+ void ( *cmdHandler )( gentity_t *ent );
+} commands_t;
+
+//
+// g_svcmds_ext.c
+// These were added to a seperate file to keep g_svcmds.c navigable.
+void Svcmd_Status_f( void );
+void Svcmd_TeamMessage_f( void );
+void Svcmd_CenterPrint_f( void );
+void Svcmd_BannerPrint_f( void );
+void Svcmd_EjectClient_f( void );
+void Svcmd_DumpUser_f( void );
+void Svcmd_Chat_f( void );
+void Svcmd_ListIP_f( void );
+void Svcmd_MessageWrapper( void );
+
+#include "g_killspree.h"
+#include "g_admin.h"
diff --git a/code/game/g_main.c b/code/game/g_main.c
new file mode 100644
index 0000000..48baac7
--- /dev/null
+++ b/code/game/g_main.c
@@ -0,0 +1,2911 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+#include "g_local.h"
+
+level_locals_t level;
+
+typedef struct {
+ vmCvar_t *vmCvar;
+ char *cvarName;
+ char *defaultString;
+ int cvarFlags;
+ int modificationCount; // for tracking changes
+ qboolean trackChange; // track this variable, and announce if changed
+ qboolean teamShader; // track and if changed, update shader state
+} cvarTable_t;
+
+gentity_t g_entities[MAX_GENTITIES];
+gclient_t g_clients[MAX_CLIENTS];
+
+vmCvar_t g_gametype;
+vmCvar_t g_dmflags;
+vmCvar_t g_videoflags;
+vmCvar_t g_elimflags;
+vmCvar_t g_voteflags;
+vmCvar_t g_fraglimit;
+vmCvar_t g_timelimit;
+vmCvar_t g_capturelimit;
+vmCvar_t g_friendlyFire;
+vmCvar_t g_password;
+vmCvar_t g_needpass;
+vmCvar_t g_maxclients;
+vmCvar_t g_maxGameClients;
+vmCvar_t g_dedicated;
+vmCvar_t g_speed;
+vmCvar_t g_gravity;
+vmCvar_t g_gravityModifier;
+vmCvar_t g_damageModifier;
+vmCvar_t g_cheats;
+vmCvar_t g_knockback;
+vmCvar_t g_quadfactor;
+vmCvar_t g_forcerespawn;
+vmCvar_t g_respawntime;
+vmCvar_t g_inactivity;
+vmCvar_t g_debugMove;
+vmCvar_t g_debugDamage;
+vmCvar_t g_debugAlloc;
+vmCvar_t g_weaponRespawn;
+vmCvar_t g_weaponTeamRespawn;
+vmCvar_t g_motd;
+vmCvar_t g_motdfile;
+vmCvar_t g_votemaps;
+vmCvar_t g_votecustom;
+vmCvar_t g_synchronousClients;
+vmCvar_t g_warmup;
+vmCvar_t g_doWarmup;
+vmCvar_t g_restarted;
+vmCvar_t g_logfile;
+vmCvar_t g_logfileSync;
+vmCvar_t g_blood;
+vmCvar_t g_podiumDist;
+vmCvar_t g_podiumDrop;
+vmCvar_t g_allowVote;
+vmCvar_t g_teamAutoJoin;
+vmCvar_t g_teamForceBalance;
+vmCvar_t g_banIPs;
+vmCvar_t g_filterBan;
+vmCvar_t g_smoothClients;
+vmCvar_t pmove_fixed;
+vmCvar_t pmove_msec;
+vmCvar_t pmove_float;
+vmCvar_t g_rankings;
+vmCvar_t g_listEntity;
+vmCvar_t g_obeliskHealth;
+vmCvar_t g_obeliskRegenPeriod;
+vmCvar_t g_obeliskRegenAmount;
+vmCvar_t g_obeliskRespawnDelay;
+vmCvar_t g_cubeTimeout;
+#ifdef MISSIONPACK
+vmCvar_t g_redteam;
+vmCvar_t g_blueteam;
+vmCvar_t g_singlePlayer;
+#endif
+vmCvar_t g_enableDust;
+vmCvar_t g_enableBreath;
+vmCvar_t g_proxMineTimeout;
+vmCvar_t g_music;
+vmCvar_t g_spawnprotect;
+//Following for elimination:
+vmCvar_t g_elimination_selfdamage;
+vmCvar_t g_elimination_startHealth;
+vmCvar_t g_elimination_startArmor;
+vmCvar_t g_elimination_bfg;
+vmCvar_t g_elimination_grapple;
+vmCvar_t g_elimination_roundtime;
+vmCvar_t g_elimination_warmup;
+vmCvar_t g_elimination_activewarmup;
+vmCvar_t g_elimination_allgametypes;
+vmCvar_t g_elimination_machinegun;
+vmCvar_t g_elimination_shotgun;
+vmCvar_t g_elimination_grenade;
+vmCvar_t g_elimination_rocket;
+vmCvar_t g_elimination_railgun;
+vmCvar_t g_elimination_lightning;
+vmCvar_t g_elimination_plasmagun;
+vmCvar_t g_elimination_chain;
+vmCvar_t g_elimination_mine;
+vmCvar_t g_elimination_nail;
+
+vmCvar_t g_elimination_lockspectator;
+
+vmCvar_t g_rockets;
+
+//dmn_clowns suggestions (with my idea of implementing):
+vmCvar_t g_instantgib;
+vmCvar_t g_vampire;
+vmCvar_t g_vampireMaxHealth;
+//Regen
+vmCvar_t g_regen;
+int g_ffa_gt; //Are this a FFA gametype even if gametype is high?
+vmCvar_t g_lms_lives;
+vmCvar_t g_lms_mode;
+vmCvar_t g_elimination_ctf_oneway;
+vmCvar_t g_awardpushing; //The server can decide if players are awarded for pushing people in lave etc.
+vmCvar_t g_persistantpowerups; //Allow missionpack style persistant powerups?
+
+vmCvar_t g_catchup; //Favors the week players
+
+vmCvar_t g_autonextmap; //Autochange map
+vmCvar_t g_mappools; //mappools to be used for autochange
+
+vmCvar_t g_voteNames;
+vmCvar_t g_voteBan;
+vmCvar_t g_voteGametypes;
+vmCvar_t g_voteMinTimelimit;
+vmCvar_t g_voteMaxTimelimit;
+vmCvar_t g_voteMinFraglimit;
+vmCvar_t g_voteMaxFraglimit;
+vmCvar_t g_maxvotes;
+
+vmCvar_t g_humanplayers;
+
+//used for voIP
+vmCvar_t g_redTeamClientNumbers;
+vmCvar_t g_blueTeamClientNumbers;
+
+//unlagged - server options
+vmCvar_t g_delagHitscan;
+vmCvar_t g_truePing;
+vmCvar_t sv_fps;
+vmCvar_t g_lagLightning; //Adds a little lag to the lightninggun to make it less powerfull
+//unlagged - server options
+//KK-OAX
+vmCvar_t g_sprees;
+vmCvar_t g_altExcellent;
+vmCvar_t g_spreeDiv;
+
+//Command/Chat spamming/flooding
+vmCvar_t g_floodMaxDemerits;
+vmCvar_t g_floodMinTime;
+
+//Admin
+vmCvar_t g_admin;
+vmCvar_t g_adminLog;
+vmCvar_t g_adminParseSay;
+vmCvar_t g_adminNameProtect;
+vmCvar_t g_adminTempBan;
+vmCvar_t g_adminMaxBan;
+vmCvar_t g_specChat;
+vmCvar_t g_publicAdminMessages;
+
+vmCvar_t g_maxWarnings;
+vmCvar_t g_warningExpire;
+
+vmCvar_t g_minNameChangePeriod;
+vmCvar_t g_maxNameChanges;
+
+vmCvar_t g_timestamp_startgame;
+
+// bk001129 - made static to avoid aliasing
+static cvarTable_t gameCvarTable[] = {
+ // don't override the cheat state set by the system
+ { &g_cheats, "sv_cheats", "", 0, 0, qfalse },
+
+ // noset vars
+ { NULL, "gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
+ { NULL, "gamedate", __DATE__ , CVAR_ROM, 0, qfalse },
+ { &g_restarted, "g_restarted", "0", CVAR_ROM, 0, qfalse },
+ { NULL, "sv_mapname", "", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
+
+ // latched vars
+ { &g_gametype, "g_gametype", "0", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH, 0, qfalse },
+
+ { &g_maxclients, "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse },
+ { &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse },
+
+ // change anytime vars
+ { &g_dmflags, "dmflags", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
+ { &g_videoflags, "videoflags", "7", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
+ { &g_elimflags, "elimflags", "0", CVAR_SERVERINFO, 0, qfalse },
+ { &g_voteflags, "voteflags", "0", CVAR_SERVERINFO, 0, qfalse },
+ { &g_fraglimit, "fraglimit", "20", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
+ { &g_timelimit, "timelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
+ { &g_capturelimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
+
+ { &g_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO, 0, qfalse },
+
+ { &g_friendlyFire, "g_friendlyFire", "0", CVAR_ARCHIVE, 0, qtrue },
+
+ { &g_teamAutoJoin, "g_teamAutoJoin", "0", CVAR_ARCHIVE },
+ { &g_teamForceBalance, "g_teamForceBalance", "0", CVAR_ARCHIVE },
+
+ { &g_warmup, "g_warmup", "20", CVAR_ARCHIVE, 0, qtrue },
+ { &g_doWarmup, "g_doWarmup", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
+ { &g_logfile, "g_log", "games.log", CVAR_ARCHIVE, 0, qfalse },
+ { &g_logfileSync, "g_logsync", "0", CVAR_ARCHIVE, 0, qfalse },
+
+ { &g_password, "g_password", "", CVAR_USERINFO, 0, qfalse },
+
+ { &g_banIPs, "g_banIPs", "", CVAR_ARCHIVE, 0, qfalse },
+ { &g_filterBan, "g_filterBan", "1", CVAR_ARCHIVE, 0, qfalse },
+
+ { &g_needpass, "g_needpass", "0", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
+
+ { &g_dedicated, "dedicated", "0", 0, 0, qfalse },
+
+ { &g_speed, "g_speed", "320", 0, 0, qtrue },
+ { &g_gravity, "g_gravity", "800", 0, 0, qtrue },
+ { &g_gravityModifier, "g_gravityModifier", "1", 0, 0, qtrue },
+ { &g_damageModifier, "g_damageModifier", "0", 0, 0, qtrue },
+ { &g_knockback, "g_knockback", "1000", 0, 0, qtrue },
+ { &g_quadfactor, "g_quadfactor", "3", 0, 0, qtrue },
+ { &g_weaponRespawn, "g_weaponrespawn", "5", 0, 0, qtrue },
+ { &g_weaponTeamRespawn, "g_weaponTeamRespawn", "30", 0, 0, qtrue },
+ { &g_forcerespawn, "g_forcerespawn", "20", 0, 0, qtrue },
+ { &g_respawntime, "g_respawntime", "0", CVAR_ARCHIVE, 0, qtrue },
+ { &g_inactivity, "g_inactivity", "0", 0, 0, qtrue },
+ { &g_debugMove, "g_debugMove", "0", 0, 0, qfalse },
+ { &g_debugDamage, "g_debugDamage", "0", 0, 0, qfalse },
+ { &g_debugAlloc, "g_debugAlloc", "0", 0, 0, qfalse },
+ { &g_motd, "g_motd", "", 0, 0, qfalse },
+ { &g_motdfile, "g_motdfile", "motd.cfg", 0, 0, qfalse },
+ { &g_blood, "com_blood", "1", 0, 0, qfalse },
+
+ { &g_podiumDist, "g_podiumDist", "80", 0, 0, qfalse },
+ { &g_podiumDrop, "g_podiumDrop", "70", 0, 0, qfalse },
+
+ //Votes start:
+ { &g_allowVote, "g_allowVote", "1", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
+ { &g_maxvotes, "g_maxVotes", MAX_VOTE_COUNT, CVAR_ARCHIVE, 0, qfalse },
+ { &g_voteNames, "g_voteNames", "/map_restart/nextmap/map/g_gametype/kick/clientkick/g_doWarmup/timelimit/fraglimit/shuffle/", CVAR_ARCHIVE, 0, qfalse }, //clientkick g_doWarmup timelimit fraglimit
+ { &g_voteBan, "g_voteBan", "0", CVAR_ARCHIVE, 0, qfalse },
+ { &g_voteGametypes, "g_voteGametypes", "/0/1/3/4/5/6/7/8/9/10/11/12/", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
+ { &g_voteMaxTimelimit, "g_voteMaxTimelimit", "1000", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
+ { &g_voteMinTimelimit, "g_voteMinTimelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
+ { &g_voteMaxFraglimit, "g_voteMaxFraglimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
+ { &g_voteMinFraglimit, "g_voteMinFraglimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
+ { &g_votemaps, "g_votemapsfile", "votemaps.cfg", 0, 0, qfalse },
+ { &g_votecustom, "g_votecustomfile", "votecustom.cfg", 0, 0, qfalse },
+
+ { &g_listEntity, "g_listEntity", "0", 0, 0, qfalse },
+
+ { &g_obeliskHealth, "g_obeliskHealth", "2500", 0, 0, qfalse },
+ { &g_obeliskRegenPeriod, "g_obeliskRegenPeriod", "1", 0, 0, qfalse },
+ { &g_obeliskRegenAmount, "g_obeliskRegenAmount", "15", 0, 0, qfalse },
+ { &g_obeliskRespawnDelay, "g_obeliskRespawnDelay", "10", CVAR_SERVERINFO, 0, qfalse },
+
+ { &g_cubeTimeout, "g_cubeTimeout", "30", 0, 0, qfalse },
+ #ifdef MISSIONPACK
+ { &g_redteam, "g_redteam", "Stroggs", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO , 0, qtrue, qtrue },
+ { &g_blueteam, "g_blueteam", "Pagans", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO , 0, qtrue, qtrue },
+ { &g_singlePlayer, "ui_singlePlayerActive", "", 0, 0, qfalse, qfalse },
+ #endif
+
+ { &g_enableDust, "g_enableDust", "0", CVAR_SERVERINFO, 0, qtrue, qfalse },
+ { &g_enableBreath, "g_enableBreath", "0", CVAR_SERVERINFO, 0, qtrue, qfalse },
+ { &g_proxMineTimeout, "g_proxMineTimeout", "20000", 0, 0, qfalse },
+
+ { &g_smoothClients, "g_smoothClients", "1", 0, 0, qfalse},
+ { &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO | CVAR_ARCHIVE, 0, qfalse},
+ { &pmove_msec, "pmove_msec", "11", CVAR_SYSTEMINFO | CVAR_ARCHIVE, 0, qfalse},
+
+ { &pmove_float, "pmove_float", "1", CVAR_SYSTEMINFO | CVAR_ARCHIVE, 0, qtrue},
+
+//unlagged - server options
+ { &g_delagHitscan, "g_delagHitscan", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qtrue },
+ { &g_truePing, "g_truePing", "0", CVAR_ARCHIVE, 0, qtrue },
+ // it's CVAR_SYSTEMINFO so the client's sv_fps will be automagically set to its value
+ { &sv_fps, "sv_fps", "20", CVAR_SYSTEMINFO | CVAR_ARCHIVE, 0, qfalse },
+ { &g_lagLightning, "g_lagLightning", "1", CVAR_ARCHIVE, 0, qtrue },
+//unlagged - server options
+
+ { &g_rankings, "g_rankings", "0", 0, 0, qfalse},
+ { &g_music, "g_music", "", 0, 0, qfalse},
+ { &g_spawnprotect, "g_spawnprotect", "500", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue},
+ //Now for elimination stuff:
+ { &g_elimination_selfdamage, "elimination_selfdamage", "0", 0, 0, qtrue },
+ { &g_elimination_startHealth, "elimination_startHealth", "200", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_startArmor, "elimination_startArmor", "150", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_bfg, "elimination_bfg", "0", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_grapple, "elimination_grapple", "0", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_roundtime, "elimination_roundtime", "120", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_warmup, "elimination_warmup", "7", CVAR_ARCHIVE | CVAR_NORESTART , 0, qtrue },
+ { &g_elimination_activewarmup, "elimination_activewarmup", "5", CVAR_ARCHIVE | CVAR_NORESTART , 0, qtrue },
+ { &g_elimination_allgametypes, "g_elimination", "0", CVAR_LATCH | CVAR_NORESTART, 0, qfalse },
+
+ { &g_elimination_machinegun, "elimination_machinegun", "500", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_shotgun, "elimination_shotgun", "500", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_grenade, "elimination_grenade", "100", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_rocket, "elimination_rocket", "50", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_railgun, "elimination_railgun", "20", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_lightning, "elimination_lightning", "300", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_plasmagun, "elimination_plasmagun", "200", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_chain, "elimination_chain", "0", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_mine, "elimination_mine", "0", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
+ { &g_elimination_nail, "elimination_nail", "0", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
+
+ { &g_elimination_ctf_oneway, "elimination_ctf_oneway", "0", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
+
+ { &g_elimination_lockspectator, "elimination_lockspectator", "0", CVAR_NORESTART, 0, qtrue },
+
+ { &g_awardpushing, "g_awardpushing", "1", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
+
+ //g_persistantpowerups
+ #ifdef MISSIONPACK
+ { &g_persistantpowerups, "g_runes", "1", CVAR_LATCH, 0, qfalse },
+ #else
+ { &g_persistantpowerups, "g_runes", "0", CVAR_LATCH|CVAR_ARCHIVE, 0, qfalse },
+ #endif
+
+
+ //nexuiz style rocket arena
+ { &g_rockets, "g_rockets", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_NORESTART, 0, qfalse },
+
+ //Instantgib and Vampire thingies
+ { &g_instantgib, "g_instantgib", "0", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse },
+ { &g_vampire, "g_vampire", "0.0", CVAR_NORESTART, 0, qtrue },
+ { &g_regen, "g_regen", "0", CVAR_NORESTART, 0, qtrue },
+ { &g_vampireMaxHealth, "g_vampire_max_health", "500", CVAR_NORESTART, 0, qtrue },
+ { &g_lms_lives, "g_lms_lives", "1", CVAR_NORESTART, 0, qtrue },
+ { &g_lms_mode, "g_lms_mode", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
+
+ { &g_catchup, "g_catchup", "0", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue},
+
+ { &g_autonextmap, "g_autonextmap", "0", CVAR_ARCHIVE | CVAR_NORESTART, 0, qfalse},
+ { &g_mappools, "g_mappools", "0\\maps_dm.cfg\\1\\maps_tourney.cfg\\3\\maps_tdm.cfg\\4\\maps_ctf.cfg\\5\\maps_oneflag.cfg\\6\\maps_obelisk.cfg\
+\\7\\maps_harvester.cfg\\8\\maps_elimination.cfg\\9\\maps_ctf.cfg\\10\\maps_lms.cfg\\11\\maps_dd.cfg\\12\\maps_dom.cfg\\", CVAR_ARCHIVE | CVAR_NORESTART, 0, qfalse},
+ { &g_humanplayers, "g_humanplayers", "0", CVAR_ROM | CVAR_NORESTART, 0, qfalse },
+//used for voIP
+ { &g_redTeamClientNumbers, "g_redTeamClientNumbers", "0",CVAR_ROM, 0, qfalse },
+ { &g_blueTeamClientNumbers, "g_blueTeamClientNumbers", "0",CVAR_ROM, 0, qfalse },
+
+ //KK-OAX
+ { &g_sprees, "g_sprees", "sprees.dat", 0, 0, qfalse },
+ { &g_altExcellent, "g_altExcellent", "0", CVAR_SERVERINFO, 0, qtrue},
+ { &g_spreeDiv, "g_spreeDiv", "5", 0, 0, qfalse},
+
+ //Used for command/chat flooding
+ { &g_floodMaxDemerits, "g_floodMaxDemerits", "5000", CVAR_ARCHIVE, 0, qfalse },
+ { &g_floodMinTime, "g_floodMinTime", "2000", CVAR_ARCHIVE, 0, qfalse },
+
+ //Admin
+ { &g_admin, "g_admin", "admin.dat", CVAR_ARCHIVE, 0, qfalse },
+ { &g_adminLog, "g_adminLog", "admin.log", CVAR_ARCHIVE, 0, qfalse },
+ { &g_adminParseSay, "g_adminParseSay", "1", CVAR_ARCHIVE, 0, qfalse },
+ { &g_adminNameProtect, "g_adminNameProtect", "1", CVAR_ARCHIVE, 0, qfalse },
+ { &g_adminTempBan, "g_adminTempBan", "2m", CVAR_ARCHIVE, 0, qfalse },
+ { &g_adminMaxBan, "g_adminMaxBan", "2w", CVAR_ARCHIVE, 0, qfalse },
+
+ { &g_specChat, "g_specChat", "1", CVAR_ARCHIVE, 0, qfalse },
+ { &g_publicAdminMessages, "g_publicAdminMessages", "1", CVAR_ARCHIVE, 0, qfalse },
+
+ { &g_maxWarnings, "g_maxWarnings", "3", CVAR_ARCHIVE, 0, qfalse },
+ { &g_warningExpire, "g_warningExpire", "3600", CVAR_ARCHIVE, 0, qfalse },
+
+ { &g_minNameChangePeriod, "g_minNameChangePeriod", "10", 0, 0, qfalse},
+ { &g_maxNameChanges, "g_maxNameChanges", "50", 0, 0, qfalse},
+
+ { &g_timestamp_startgame, "g_timestamp", "0001-01-01 00:00:00", CVAR_SERVERINFO, 0, qfalse}
+
+};
+
+// bk001129 - made static to avoid aliasing
+static int gameCvarTableSize = sizeof( gameCvarTable ) / sizeof( gameCvarTable[0] );
+
+
+void G_InitGame( int levelTime, int randomSeed, int restart );
+void G_RunFrame( int levelTime );
+void G_ShutdownGame( int restart );
+void CheckExitRules( void );
+
+
+/*
+================
+vmMain
+
+This is the only way control passes into the module.
+This must be the very first function compiled into the .q3vm file
+================
+*/
+intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
+ switch ( command ) {
+ case GAME_INIT:
+ G_InitGame( arg0, arg1, arg2 );
+ return 0;
+ case GAME_SHUTDOWN:
+ G_ShutdownGame( arg0 );
+ return 0;
+ case GAME_CLIENT_CONNECT:
+ return (intptr_t)ClientConnect( arg0, arg1, arg2 );
+ case GAME_CLIENT_THINK:
+ ClientThink( arg0 );
+ return 0;
+ case GAME_CLIENT_USERINFO_CHANGED:
+ ClientUserinfoChanged( arg0 );
+ return 0;
+ case GAME_CLIENT_DISCONNECT:
+ ClientDisconnect( arg0 );
+ return 0;
+ case GAME_CLIENT_BEGIN:
+ ClientBegin( arg0 );
+ return 0;
+ case GAME_CLIENT_COMMAND:
+ ClientCommand( arg0 );
+ return 0;
+ case GAME_RUN_FRAME:
+ G_RunFrame( arg0 );
+ return 0;
+ case GAME_CONSOLE_COMMAND:
+ return ConsoleCommand();
+ case BOTAI_START_FRAME:
+ return BotAIStartFrame( arg0 );
+ }
+
+ return -1;
+}
+
+
+void QDECL G_Printf( const char *fmt, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, fmt);
+ Q_vsnprintf (text, sizeof(text), fmt, argptr);
+ va_end (argptr);
+
+ trap_Printf( text );
+}
+
+void QDECL G_Error( const char *fmt, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, fmt);
+ Q_vsnprintf (text, sizeof(text), fmt, argptr);
+ va_end (argptr);
+
+ trap_Error( text );
+}
+
+/*
+================
+G_FindTeams
+
+Chain together all entities with a matching team field.
+Entity teams are used for item groups and multi-entity mover groups.
+
+All but the first will have the FL_TEAMSLAVE flag set and teammaster field set
+All but the last will have the teamchain field set to the next one
+================
+*/
+void G_FindTeams( void ) {
+ gentity_t *e, *e2;
+ int i, j;
+ int c, c2;
+
+ c = 0;
+ c2 = 0;
+ for ( i=1, e=g_entities+i ; i < level.num_entities ; i++,e++ ){
+ if (!e->inuse)
+ continue;
+ if (!e->team)
+ continue;
+ if (e->flags & FL_TEAMSLAVE)
+ continue;
+ e->teammaster = e;
+ c++;
+ c2++;
+ for (j=i+1, e2=e+1 ; j < level.num_entities ; j++,e2++)
+ {
+ if (!e2->inuse)
+ continue;
+ if (!e2->team)
+ continue;
+ if (e2->flags & FL_TEAMSLAVE)
+ continue;
+ if (!strcmp(e->team, e2->team))
+ {
+ c2++;
+ e2->teamchain = e->teamchain;
+ e->teamchain = e2;
+ e2->teammaster = e;
+ e2->flags |= FL_TEAMSLAVE;
+
+ // make sure that targets only point at the master
+ if ( e2->targetname ) {
+ e->targetname = e2->targetname;
+ e2->targetname = NULL;
+ }
+ }
+ }
+ }
+ G_Printf ("%i teams with %i entities\n", c, c2);
+}
+
+void G_RemapTeamShaders( void ) {
+#ifdef MISSIONPACK
+ char string[1024];
+ float f = level.time * 0.001;
+ Com_sprintf( string, sizeof(string), "team_icon/%s_red", g_redteam.string );
+ AddRemap("textures/ctf2/redteam01", string, f);
+ AddRemap("textures/ctf2/redteam02", string, f);
+ Com_sprintf( string, sizeof(string), "team_icon/%s_blue", g_blueteam.string );
+ AddRemap("textures/ctf2/blueteam01", string, f);
+ AddRemap("textures/ctf2/blueteam02", string, f);
+ trap_SetConfigstring(CS_SHADERSTATE, BuildShaderStateConfig());
+#endif
+}
+
+
+/*
+=================
+G_RegisterCvars
+=================
+*/
+void G_RegisterCvars( void ) {
+ int i;
+ cvarTable_t *cv;
+ qboolean remapped = qfalse;
+
+ for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) {
+ trap_Cvar_Register( cv->vmCvar, cv->cvarName,
+ cv->defaultString, cv->cvarFlags );
+ if ( cv->vmCvar )
+ cv->modificationCount = cv->vmCvar->modificationCount;
+
+ if (cv->teamShader) {
+ remapped = qtrue;
+ }
+ }
+
+ if (remapped) {
+ G_RemapTeamShaders();
+ }
+
+ // check some things
+ if ( g_gametype.integer < 0 || g_gametype.integer >= GT_MAX_GAME_TYPE ) {
+ G_Printf( "g_gametype %i is out of range, defaulting to 0\n", g_gametype.integer );
+ trap_Cvar_Set( "g_gametype", "0" );
+ }
+
+ //set FFA status for high gametypes:
+ if ( g_gametype.integer == GT_LMS ) {
+ g_ffa_gt = 1; //Last Man standig is a FFA gametype
+ } else {
+ g_ffa_gt = 0; //If >GT_CTF use bases
+ }
+
+ level.warmupModificationCount = g_warmup.modificationCount;
+}
+
+/*
+=================
+G_UpdateCvars
+=================
+*/
+void G_UpdateCvars( void ) {
+ int i;
+ cvarTable_t *cv;
+ qboolean remapped = qfalse;
+
+ for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) {
+ if ( cv->vmCvar ) {
+ trap_Cvar_Update( cv->vmCvar );
+
+ if ( cv->modificationCount != cv->vmCvar->modificationCount ) {
+ cv->modificationCount = cv->vmCvar->modificationCount;
+
+ if ( cv->trackChange ) {
+ trap_SendServerCommand( -1, va("print \"Server: %s changed to %s\n\"",
+ cv->cvarName, cv->vmCvar->string ) );
+ }
+
+ if ( cv->vmCvar == &g_votecustom )
+ VoteParseCustomVotes();
+
+ //Here comes the cvars that must trigger a map_restart
+ if (cv->vmCvar == &g_instantgib || cv->vmCvar == &g_rockets || cv->vmCvar == &g_elimination_allgametypes) {
+ trap_Cvar_Set("sv_dorestart","1");
+ }
+
+ if ( cv->vmCvar == &g_voteNames ) {
+ //Set vote flags
+ int voteflags=0;
+ if( allowedVote("map_restart") )
+ voteflags|=VF_map_restart;
+
+ if( allowedVote("map") )
+ voteflags|=VF_map;
+
+ if( allowedVote("clientkick") )
+ voteflags|=VF_clientkick;
+
+ if( allowedVote("shuffle") )
+ voteflags|=VF_shuffle;
+
+ if( allowedVote("nextmap") )
+ voteflags|=VF_nextmap;
+
+ if( allowedVote("g_gametype") )
+ voteflags|=VF_g_gametype;
+
+ if( allowedVote("g_doWarmup") )
+ voteflags|=VF_g_doWarmup;
+
+ if( allowedVote("timelimit") )
+ voteflags|=VF_timelimit;
+
+ if( allowedVote("fraglimit") )
+ voteflags|=VF_fraglimit;
+
+ if( allowedVote("custom") )
+ voteflags|=VF_custom;
+
+ trap_Cvar_Set("voteflags",va("%i",voteflags));
+ }
+
+ if (cv->teamShader) {
+ remapped = qtrue;
+ }
+ }
+ }
+ }
+
+ if (remapped) {
+ G_RemapTeamShaders();
+ }
+}
+
+/*
+ Sets the cvar g_timestamp. Return 0 if success or !0 for errors.
+ */
+int G_UpdateTimestamp( void ) {
+ int ret = 0;
+ qtime_t timestamp;
+ ret = trap_RealTime(×tamp);
+ trap_Cvar_Set("g_timestamp",va("%04i-%02i-%02i %02i:%02i:%02i",
+ 1900+timestamp.tm_year,1+timestamp.tm_mon, timestamp.tm_mday,
+ timestamp.tm_hour,timestamp.tm_min,timestamp.tm_sec));
+
+ return ret;
+}
+
+/*
+============
+G_InitGame
+
+============
+*/
+void G_InitGame( int levelTime, int randomSeed, int restart ) {
+ int i;
+
+
+ G_Printf ("------- Game Initialization -------\n");
+ G_Printf ("gamename: %s\n", GAMEVERSION);
+ G_Printf ("gamedate: %s\n", __DATE__);
+
+ srand( randomSeed );
+
+ G_RegisterCvars();
+
+ G_UpdateTimestamp();
+
+ //disable unwanted cvars
+ if( g_gametype.integer == GT_SINGLE_PLAYER )
+ {
+ g_instantgib.integer = 0;
+ g_rockets.integer = 0;
+ g_vampire.value = 0.0f;
+ }
+
+ G_ProcessIPBans();
+
+ //KK-OAX Changed to Tremulous's BG_InitMemory
+ BG_InitMemory();
+
+ // set some level globals
+ memset( &level, 0, sizeof( level ) );
+
+ level.time = levelTime;
+ level.startTime = levelTime;
+
+ level.snd_fry = G_SoundIndex("sound/player/fry.wav"); // FIXME standing in lava / slime
+
+ if ( g_gametype.integer != GT_SINGLE_PLAYER && g_logfile.string[0] ) {
+ if ( g_logfileSync.integer ) {
+ trap_FS_FOpenFile( g_logfile.string, &level.logFile, FS_APPEND_SYNC );
+ } else {
+ trap_FS_FOpenFile( g_logfile.string, &level.logFile, FS_APPEND );
+ }
+ if ( !level.logFile ) {
+ G_Printf( "WARNING: Couldn't open logfile: %s\n", g_logfile.string );
+ } else {
+ char serverinfo[MAX_INFO_STRING];
+
+ trap_GetServerinfo( serverinfo, sizeof( serverinfo ) );
+
+ G_LogPrintf("------------------------------------------------------------\n" );
+ G_LogPrintf("InitGame: %s\n", serverinfo );
+ G_LogPrintf("Info: ServerInfo length: %d of %d\n", strlen(serverinfo), MAX_INFO_STRING );
+ }
+ } else {
+ G_Printf( "Not logging to disk.\n" );
+ }
+
+ //Parse the custom vote names:
+ VoteParseCustomVotes();
+
+ G_InitWorldSession();
+
+ //KK-OAX Get Admin Configuration
+ G_admin_readconfig( NULL, 0 );
+ //Let's Load up any killing sprees/multikills
+ G_ReadAltKillSettings( NULL, 0 );
+
+ // initialize all entities for this game
+ memset( g_entities, 0, MAX_GENTITIES * sizeof(g_entities[0]) );
+ level.gentities = g_entities;
+
+ // initialize all clients for this game
+ level.maxclients = g_maxclients.integer;
+ memset( g_clients, 0, MAX_CLIENTS * sizeof(g_clients[0]) );
+ level.clients = g_clients;
+
+ // set client fields on player ents
+ for ( i=0 ; i<level.maxclients ; i++ ) {
+ g_entities[i].client = level.clients + i;
+ }
+
+ // always leave room for the max number of clients,
+ // even if they aren't all used, so numbers inside that
+ // range are NEVER anything but clients
+ level.num_entities = MAX_CLIENTS;
+
+ for ( i=0 ; i<MAX_CLIENTS ; i++ ) {
+ g_entities[i].classname = "clientslot";
+ }
+
+ // let the server system know where the entites are
+ trap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ),
+ &level.clients[0].ps, sizeof( level.clients[0] ) );
+
+ // reserve some spots for dead player bodies
+ InitBodyQue();
+
+ ClearRegisteredItems();
+
+ // parse the key/value pairs and spawn gentities
+ G_SpawnEntitiesFromString();
+
+ // general initialization
+ G_FindTeams();
+
+ // make sure we have flags for CTF, etc
+ if( g_gametype.integer >= GT_TEAM && (g_ffa_gt!=1)) {
+ G_CheckTeamItems();
+ }
+
+ SaveRegisteredItems();
+
+ G_Printf ("-----------------------------------\n");
+
+ if( g_gametype.integer == GT_SINGLE_PLAYER || trap_Cvar_VariableIntegerValue( "com_buildScript" ) ) {
+ G_ModelIndex( SP_PODIUM_MODEL );
+ }
+
+ if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
+ BotAISetup( restart );
+ BotAILoadMap( restart );
+ G_InitBots( restart );
+ }
+
+ G_RemapTeamShaders();
+
+ //elimination:
+ level.roundNumber = 1;
+ level.roundNumberStarted = 0;
+ level.roundStartTime = level.time+g_elimination_warmup.integer*1000;
+ level.roundRespawned = qfalse;
+ level.eliminationSides = rand()%2; //0 or 1
+
+ //Challenges:
+ level.teamSize = 0;
+ level.hadBots = qfalse;
+
+ if(g_gametype.integer == GT_DOUBLE_D)
+ Team_SpawnDoubleDominationPoints();
+
+ if(g_gametype.integer == GT_DOMINATION ){
+ level.dom_scoreGiven = 0;
+ for(i=0;i<MAX_DOMINATION_POINTS;i++)
+ level.pointStatusDom[i] = TEAM_NONE;
+ level.domination_points_count = 0; //make sure its not too big
+ }
+
+ PlayerStoreInit();
+
+ //Set vote flags
+ {
+ int voteflags=0;
+ if( allowedVote("map_restart") )
+ voteflags|=VF_map_restart;
+
+ if( allowedVote("map") )
+ voteflags|=VF_map;
+
+ if( allowedVote("clientkick") )
+ voteflags|=VF_clientkick;
+
+ if( allowedVote("shuffle") )
+ voteflags|=VF_shuffle;
+
+ if( allowedVote("nextmap") )
+ voteflags|=VF_nextmap;
+
+ if( allowedVote("g_gametype") )
+ voteflags|=VF_g_gametype;
+
+ if( allowedVote("g_doWarmup") )
+ voteflags|=VF_g_doWarmup;
+
+ if( allowedVote("timelimit") )
+ voteflags|=VF_timelimit;
+
+ if( allowedVote("fraglimit") )
+ voteflags|=VF_fraglimit;
+
+ if( allowedVote("custom") )
+ voteflags|=VF_custom;
+
+ trap_Cvar_Set("voteflags",va("%i",voteflags));
+ }
+}
+
+
+
+/*
+=================
+G_ShutdownGame
+=================
+*/
+void G_ShutdownGame( int restart ) {
+ G_Printf ("==== ShutdownGame ====\n");
+
+ if ( level.logFile ) {
+ G_LogPrintf("ShutdownGame:\n" );
+ G_LogPrintf("------------------------------------------------------------\n" );
+ trap_FS_FCloseFile( level.logFile );
+ level.logFile = 0;
+ }
+
+ // write all the client session data so we can get it back
+ G_WriteSessionData();
+
+ //KK-OAX Admin Cleanup
+ G_admin_cleanup( );
+ G_admin_namelog_cleanup( );
+
+ if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
+ BotAIShutdown( restart );
+ }
+}
+
+
+
+//===================================================================
+
+void QDECL Com_Error ( int level, const char *error, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, error);
+ Q_vsnprintf (text, sizeof(text), error, argptr);
+ va_end (argptr);
+
+ G_Error( "%s", text);
+}
+
+void QDECL Com_Printf( const char *msg, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, msg);
+ Q_vsnprintf (text, sizeof(text), msg, argptr);
+ va_end (argptr);
+
+ G_Printf ("%s", text);
+}
+
+/*
+========================================================================
+
+PLAYER COUNTING / SCORE SORTING
+
+========================================================================
+*/
+
+/*
+=============
+AddTournamentPlayer
+
+If there are less than two tournament players, put a
+spectator in the game and restart
+=============
+*/
+void AddTournamentPlayer( void ) {
+ int i;
+ gclient_t *client;
+ gclient_t *nextInLine;
+
+ if ( level.numPlayingClients >= 2 ) {
+ return;
+ }
+
+ // never change during intermission
+ if ( level.intermissiontime ) {
+ return;
+ }
+
+ nextInLine = NULL;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ client = &level.clients[i];
+ if ( client->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
+ continue;
+ }
+ // never select the dedicated follow or scoreboard clients
+ if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ||
+ client->sess.spectatorClient < 0 ) {
+ continue;
+ }
+
+ if(!nextInLine || client->sess.spectatorNum > nextInLine->sess.spectatorNum) {
+ nextInLine = client;
+ }
+ }
+
+ if ( !nextInLine ) {
+ return;
+ }
+
+ level.warmupTime = -1;
+
+ // set them to free-for-all team
+ SetTeam( &g_entities[ nextInLine - level.clients ], "f" );
+}
+
+/*
+=======================
+AddTournamentQueue
+
+Add client to end of tournament queue
+=======================
+*/
+void AddTournamentQueue(gclient_t *client)
+{
+ int index;
+ gclient_t *curclient;
+ for(index = 0; index < level.maxclients; index++)
+ {
+ curclient = &level.clients[index];
+ if(curclient->pers.connected != CON_DISCONNECTED)
+ {
+ if(curclient == client)
+ curclient->sess.spectatorNum = 0;
+ else if(curclient->sess.sessionTeam == TEAM_SPECTATOR)
+ curclient->sess.spectatorNum++;
+ }
+ }
+}
+
+/*
+=======================
+RemoveTournamentLoser
+
+Make the loser a spectator at the back of the line
+=======================
+*/
+void RemoveTournamentLoser( void ) {
+ int clientNum;
+
+ if ( level.numPlayingClients != 2 ) {
+ return;
+ }
+
+ clientNum = level.sortedClients[1];
+
+ if ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) {
+ return;
+ }
+
+ // make them a spectator
+ SetTeam( &g_entities[ clientNum ], "s" );
+}
+
+/*
+=======================
+RemoveTournamentWinner
+=======================
+*/
+void RemoveTournamentWinner( void ) {
+ int clientNum;
+
+ if ( level.numPlayingClients != 2 ) {
+ return;
+ }
+
+ clientNum = level.sortedClients[0];
+
+ if ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) {
+ return;
+ }
+
+ // make them a spectator
+ SetTeam( &g_entities[ clientNum ], "s" );
+}
+
+/*
+=======================
+AdjustTournamentScores
+=======================
+*/
+void AdjustTournamentScores( void ) {
+ int clientNum;
+
+ clientNum = level.sortedClients[0];
+ if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {
+ level.clients[ clientNum ].sess.wins++;
+ ClientUserinfoChanged( clientNum );
+ }
+
+ clientNum = level.sortedClients[1];
+ if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {
+ level.clients[ clientNum ].sess.losses++;
+ ClientUserinfoChanged( clientNum );
+ }
+
+}
+
+/*
+=============
+SortRanks
+
+=============
+*/
+int QDECL SortRanks( const void *a, const void *b ) {
+ gclient_t *ca, *cb;
+
+ ca = &level.clients[*(int *)a];
+ cb = &level.clients[*(int *)b];
+
+ // sort special clients last
+ if ( ca->sess.spectatorState == SPECTATOR_SCOREBOARD || ca->sess.spectatorClient < 0 ) {
+ return 1;
+ }
+ if ( cb->sess.spectatorState == SPECTATOR_SCOREBOARD || cb->sess.spectatorClient < 0 ) {
+ return -1;
+ }
+
+ // then connecting clients
+ if ( ca->pers.connected == CON_CONNECTING ) {
+ return 1;
+ }
+ if ( cb->pers.connected == CON_CONNECTING ) {
+ return -1;
+ }
+
+
+ // then spectators
+ if ( ca->sess.sessionTeam == TEAM_SPECTATOR && cb->sess.sessionTeam == TEAM_SPECTATOR ) {
+ if ( ca->sess.spectatorNum > cb->sess.spectatorNum ) {
+ return -1;
+ }
+ if ( ca->sess.spectatorNum < cb->sess.spectatorNum ) {
+ return 1;
+ }
+ return 0;
+ }
+ if ( ca->sess.sessionTeam == TEAM_SPECTATOR ) {
+ return 1;
+ }
+ if ( cb->sess.sessionTeam == TEAM_SPECTATOR ) {
+ return -1;
+ }
+
+ //In elimination and CTF elimination, sort dead players last
+ if((g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION)
+ && level.roundNumber==level.roundNumberStarted && (ca->isEliminated != cb->isEliminated)) {
+ if( ca->isEliminated )
+ return 1;
+ if( cb->isEliminated )
+ return -1;
+ }
+
+ // then sort by score
+ if ( ca->ps.persistant[PERS_SCORE]
+ > cb->ps.persistant[PERS_SCORE] ) {
+ return -1;
+ }
+ if ( ca->ps.persistant[PERS_SCORE]
+ < cb->ps.persistant[PERS_SCORE] ) {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+============
+CalculateRanks
+
+Recalculates the score ranks of all players
+This will be called on every client connect, begin, disconnect, death,
+and team change.
+============
+*/
+void CalculateRanks( void ) {
+ int i;
+ int rank;
+ int score;
+ int newScore;
+ int humanplayers;
+ gclient_t *cl;
+
+ level.follow1 = -1;
+ level.follow2 = -1;
+ level.numConnectedClients = 0;
+ level.numNonSpectatorClients = 0;
+ level.numPlayingClients = 0;
+ humanplayers = 0; // don't count bots
+ for ( i = 0; i < TEAM_NUM_TEAMS; i++ ) {
+ level.numteamVotingClients[i] = 0;
+ }
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[i].pers.connected != CON_DISCONNECTED ) {
+ level.sortedClients[level.numConnectedClients] = i;
+ level.numConnectedClients++;
+
+ //We just set humanplayers to 0 during intermission
+ if ( !level.intermissiontime && level.clients[i].pers.connected == CON_CONNECTED && !(g_entities[i].r.svFlags & SVF_BOT) ) {
+ humanplayers++;
+ }
+
+ if ( level.clients[i].sess.sessionTeam != TEAM_SPECTATOR ) {
+ level.numNonSpectatorClients++;
+ // decide if this should be auto-followed
+ if ( level.clients[i].pers.connected == CON_CONNECTED ) {
+ level.numPlayingClients++;
+ if ( !(g_entities[i].r.svFlags & SVF_BOT) ) {
+ if ( level.clients[i].sess.sessionTeam == TEAM_RED )
+ level.numteamVotingClients[0]++;
+ else if ( level.clients[i].sess.sessionTeam == TEAM_BLUE )
+ level.numteamVotingClients[1]++;
+ }
+ if ( level.follow1 == -1 ) {
+ level.follow1 = i;
+ } else if ( level.follow2 == -1 ) {
+ level.follow2 = i;
+ }
+ }
+ }
+ }
+ }
+
+ qsort( level.sortedClients, level.numConnectedClients,
+ sizeof(level.sortedClients[0]), SortRanks );
+
+ // set the rank value for all clients that are connected and not spectators
+ if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
+ // in team games, rank is just the order of the teams, 0=red, 1=blue, 2=tied
+ for ( i = 0; i < level.numConnectedClients; i++ ) {
+ cl = &level.clients[ level.sortedClients[i] ];
+ if ( level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE] ) {
+ cl->ps.persistant[PERS_RANK] = 2;
+ } else if ( level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE] ) {
+ cl->ps.persistant[PERS_RANK] = 0;
+ } else {
+ cl->ps.persistant[PERS_RANK] = 1;
+ }
+ }
+ } else {
+ rank = -1;
+ score = 0;
+ for ( i = 0; i < level.numPlayingClients; i++ ) {
+ cl = &level.clients[ level.sortedClients[i] ];
+ newScore = cl->ps.persistant[PERS_SCORE];
+ if ( i == 0 || newScore != score ) {
+ rank = i;
+ // assume we aren't tied until the next client is checked
+ level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank;
+ } else {
+ // we are tied with the previous client
+ level.clients[ level.sortedClients[i-1] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
+ level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
+ }
+ score = newScore;
+ if ( g_gametype.integer == GT_SINGLE_PLAYER && level.numPlayingClients == 1 ) {
+ level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
+ }
+ }
+ }
+
+ // set the CS_SCORES1/2 configstrings, which will be visible to everyone
+ if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
+ trap_SetConfigstring( CS_SCORES1, va("%i", level.teamScores[TEAM_RED] ) );
+ trap_SetConfigstring( CS_SCORES2, va("%i", level.teamScores[TEAM_BLUE] ) );
+ } else {
+ if ( level.numConnectedClients == 0 ) {
+ trap_SetConfigstring( CS_SCORES1, va("%i", SCORE_NOT_PRESENT) );
+ trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) );
+ } else if ( level.numConnectedClients == 1 ) {
+ trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );
+ trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) );
+ } else {
+ trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );
+ trap_SetConfigstring( CS_SCORES2, va("%i", level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE] ) );
+ }
+ }
+
+ // see if it is time to end the level
+ CheckExitRules();
+
+ // if we are at the intermission, send the new info to everyone
+ if ( level.intermissiontime ) {
+ SendScoreboardMessageToAllClients();
+ }
+
+ if(g_humanplayers.integer != humanplayers) //Presume all spectators are humans!
+ trap_Cvar_Set( "g_humanplayers", va("%i", humanplayers) );
+}
+
+
+/*
+========================================================================
+
+MAP CHANGING
+
+========================================================================
+*/
+
+/*
+========================
+SendScoreboardMessageToAllClients
+
+Do this at BeginIntermission time and whenever ranks are recalculated
+due to enters/exits/forced team changes
+========================
+*/
+void SendScoreboardMessageToAllClients( void ) {
+ int i;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
+ DeathmatchScoreboardMessage( g_entities + i );
+ EliminationMessage( g_entities + i );
+ }
+ }
+}
+
+/*
+========================
+SendElimiantionMessageToAllClients
+
+Used to send information important to Elimination
+========================
+*/
+void SendEliminationMessageToAllClients( void ) {
+ int i;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
+ EliminationMessage( g_entities + i );
+ }
+ }
+}
+
+/*
+========================
+SendDDtimetakenMessageToAllClients
+
+Do this if a team just started dominating.
+========================
+*/
+void SendDDtimetakenMessageToAllClients( void ) {
+ int i;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
+ DoubleDominationScoreTimeMessage( g_entities + i );
+ }
+ }
+}
+
+/*
+========================
+SendAttackingTeamMessageToAllClients
+
+Used for CTF Elimination oneway
+========================
+*/
+void SendAttackingTeamMessageToAllClients( void ) {
+ int i;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
+ AttackingTeamMessage( g_entities + i );
+ }
+ }
+}
+
+/*
+========================
+SendDominationPointsStatusMessageToAllClients
+
+Used for Standard domination
+========================
+*/
+void SendDominationPointsStatusMessageToAllClients( void ) {
+ int i;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
+ DominationPointStatusMessage( g_entities + i );
+ }
+ }
+}
+/*
+========================
+SendYourTeamMessageToTeam
+
+Tell all players on a given team who there allies are. Used for VoIP
+========================
+*/
+void SendYourTeamMessageToTeam( team_t team ) {
+ int i;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[ i ].pers.connected == CON_CONNECTED && level.clients[ i ].sess.sessionTeam == team ) {
+ YourTeamMessage( g_entities + i );
+ }
+ }
+}
+
+
+/*
+========================
+MoveClientToIntermission
+
+When the intermission starts, this will be called for all players.
+If a new client connects, this will be called after the spawn function.
+========================
+*/
+void MoveClientToIntermission( gentity_t *ent ) {
+ // take out of follow mode if needed
+ if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {
+ StopFollowing( ent );
+ }
+
+ FindIntermissionPoint();
+ // move to the spot
+ VectorCopy( level.intermission_origin, ent->s.origin );
+ VectorCopy( level.intermission_origin, ent->client->ps.origin );
+ VectorCopy (level.intermission_angle, ent->client->ps.viewangles);
+ ent->client->ps.pm_type = PM_INTERMISSION;
+
+ // clean up powerup info
+ memset( ent->client->ps.powerups, 0, sizeof(ent->client->ps.powerups) );
+
+ ent->client->ps.eFlags = 0;
+ ent->s.eFlags = 0;
+ ent->s.eType = ET_GENERAL;
+ ent->s.modelindex = 0;
+ ent->s.loopSound = 0;
+ ent->s.event = 0;
+ ent->r.contents = 0;
+}
+
+/*
+==================
+FindIntermissionPoint
+
+This is also used for spectator spawns
+==================
+*/
+void FindIntermissionPoint( void ) {
+ gentity_t *ent, *target;
+ vec3_t dir;
+
+ // find the intermission spot
+ ent = G_Find (NULL, FOFS(classname), "info_player_intermission");
+ if ( !ent ) { // the map creator forgot to put in an intermission point...
+ SelectSpawnPoint ( vec3_origin, level.intermission_origin, level.intermission_angle );
+ } else {
+ VectorCopy (ent->s.origin, level.intermission_origin);
+ VectorCopy (ent->s.angles, level.intermission_angle);
+ // if it has a target, look towards it
+ if ( ent->target ) {
+ target = G_PickTarget( ent->target );
+ if ( target ) {
+ VectorSubtract( target->s.origin, level.intermission_origin, dir );
+ vectoangles( dir, level.intermission_angle );
+ }
+ }
+ }
+
+}
+
+/*
+==================
+BeginIntermission
+==================
+*/
+void BeginIntermission( void ) {
+ int i;
+ gentity_t *client;
+
+ if ( level.intermissiontime ) {
+ return; // already active
+ }
+
+ // if in tournement mode, change the wins / losses
+ if ( g_gametype.integer == GT_TOURNAMENT ) {
+ AdjustTournamentScores();
+ }
+
+ level.intermissiontime = level.time;
+ // move all clients to the intermission point
+ for (i=0 ; i< level.maxclients ; i++) {
+ client = g_entities + i;
+ if (!client->inuse)
+ continue;
+ // respawn if dead
+ if (client->health <= 0) {
+ ClientRespawn(client);
+ }
+ MoveClientToIntermission( client );
+ }
+#ifdef MISSIONPACK
+ if (g_singlePlayer.integer) {
+ trap_Cvar_Set("ui_singlePlayerActive", "0");
+ UpdateTournamentInfo();
+ }
+#else
+ // if single player game
+ if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
+ UpdateTournamentInfo();
+ SpawnModelsOnVictoryPads();
+ }
+#endif
+ // send the current scoring to all clients
+ SendScoreboardMessageToAllClients();
+
+}
+
+
+/*
+=============
+ExitLevel
+
+When the intermission has been exited, the server is either killed
+or moved to a new level based on the "nextmap" cvar
+
+=============
+*/
+void ExitLevel (void) {
+ int i;
+ gclient_t *cl;
+ char nextmap[MAX_STRING_CHARS];
+ char d1[MAX_STRING_CHARS];
+ char serverinfo[MAX_INFO_STRING];
+
+ //bot interbreeding
+ BotInterbreedEndMatch();
+
+ // if we are running a tournement map, kick the loser to spectator status,
+ // which will automatically grab the next spectator and restart
+ if ( g_gametype.integer == GT_TOURNAMENT ) {
+ if ( !level.restarted ) {
+ RemoveTournamentLoser();
+ trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
+ level.restarted = qtrue;
+ level.changemap = NULL;
+ level.intermissiontime = 0;
+ }
+ return;
+ }
+
+ trap_Cvar_VariableStringBuffer( "nextmap", nextmap, sizeof(nextmap) );
+ trap_Cvar_VariableStringBuffer( "d1", d1, sizeof(d1) );
+
+ trap_GetServerinfo( serverinfo, sizeof( serverinfo ) );
+
+ //Here the game finds the nextmap if g_autonextmap is set
+ if(g_autonextmap.integer ) {
+ char filename[MAX_FILEPATH];
+ fileHandle_t file,mapfile;
+ //Look in g_mappools.string for the file to look for maps in
+ Q_strncpyz(filename,Info_ValueForKey(g_mappools.string, va("%i",g_gametype.integer)),MAX_FILEPATH);
+ //If we found a filename:
+ if(filename[0]) {
+ //Read the file:
+ /*int len =*/ trap_FS_FOpenFile(filename, &file, FS_READ);
+ if(!file)
+ trap_FS_FOpenFile(va("%s.org",filename), &file, FS_READ);
+ if(file) {
+ char buffer[4*1024]; // buffer to read file into
+ char mapnames[1024][20]; // Array of mapnames in the map pool
+ char *pointer;
+ int choice, count=0; //The random choice from mapnames and count of mapnames
+ int i;
+ memset(&buffer,0,sizeof(buffer));
+ trap_FS_Read(&buffer,sizeof(buffer),file);
+ pointer = buffer;
+ while ( qtrue ) {
+ Q_strncpyz(mapnames[count],COM_Parse( &pointer ),20);
+ if ( !mapnames[count][0] ) {
+ break;
+ }
+ G_Printf("Mapname in mappool: %s\n",mapnames[count]);
+ count++;
+ }
+ trap_FS_FCloseFile(file);
+ //It is possible that the maps in the file read are flawed, so we try up to ten times:
+ for(i=0;i<10;i++) {
+ choice = (count > 0)? rand()%count : 0;
+ if(Q_strequal(mapnames[choice],Info_ValueForKey(serverinfo,"mapname")))
+ continue;
+ //Now check that the map exists:
+ trap_FS_FOpenFile(va("maps/%s.bsp",mapnames[choice]),&mapfile,FS_READ);
+ if(mapfile) {
+ G_Printf("Picked map number %i - %s\n",choice,mapnames[choice]);
+ Q_strncpyz(nextmap,va("map %s",mapnames[choice]),sizeof(nextmap));
+ trap_Cvar_Set("nextmap",nextmap);
+ trap_FS_FCloseFile(mapfile);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if( !Q_stricmp( nextmap, "map_restart 0" ) && Q_stricmp( d1, "" ) ) {
+ trap_Cvar_Set( "nextmap", "vstr d2" );
+ trap_SendConsoleCommand( EXEC_APPEND, "vstr d1\n" );
+ } else {
+ trap_SendConsoleCommand( EXEC_APPEND, "vstr nextmap\n" );
+ }
+
+ level.changemap = NULL;
+ level.intermissiontime = 0;
+
+ // reset all the scores so we don't enter the intermission again
+ level.teamScores[TEAM_RED] = 0;
+ level.teamScores[TEAM_BLUE] = 0;
+ for ( i=0 ; i< g_maxclients.integer ; i++ ) {
+ cl = level.clients + i;
+ if ( cl->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ cl->ps.persistant[PERS_SCORE] = 0;
+ }
+
+ // we need to do this here before chaning to CON_CONNECTING
+ G_WriteSessionData();
+
+ // change all client states to connecting, so the early players into the
+ // next level will know the others aren't done reconnecting
+ for (i=0 ; i< g_maxclients.integer ; i++) {
+ if ( level.clients[i].pers.connected == CON_CONNECTED ) {
+ level.clients[i].pers.connected = CON_CONNECTING;
+ }
+ }
+
+}
+
+/*
+=================
+G_LogPrintf
+
+Print to the logfile with a time stamp if it is open
+=================
+*/
+void QDECL G_LogPrintf( const char *fmt, ... ) {
+ va_list argptr;
+ char string[1024];
+ int min, tens, sec;
+
+ sec = level.time / 1000;
+
+ min = sec / 60;
+ sec -= min * 60;
+ tens = sec / 10;
+ sec -= tens * 10;
+
+ Com_sprintf( string, sizeof(string), "%3i:%i%i ", min, tens, sec );
+
+ va_start( argptr, fmt );
+ Q_vsnprintf(string + 7, sizeof(string) - 7, fmt, argptr);
+ va_end( argptr );
+
+ if ( g_dedicated.integer ) {
+ G_Printf( "%s", string + 7 );
+ }
+
+ if ( !level.logFile ) {
+ return;
+ }
+
+ trap_FS_Write( string, strlen( string ), level.logFile );
+}
+
+/*
+================
+LogExit
+
+Append information about this game to the log file
+================
+*/
+void LogExit( const char *string ) {
+ int i, numSorted;
+ gclient_t *cl;
+#ifdef MISSIONPACK
+ qboolean won = qtrue;
+ #endif
+ G_LogPrintf( "Exit: %s\n", string );
+
+ level.intermissionQueued = level.time;
+
+ // this will keep the clients from playing any voice sounds
+ // that will get cut off when the queued intermission starts
+ trap_SetConfigstring( CS_INTERMISSION, "1" );
+
+ // don't send more than 32 scores (FIXME?)
+ numSorted = level.numConnectedClients;
+ if ( numSorted > 32 ) {
+ numSorted = 32;
+ }
+
+ if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
+ G_LogPrintf( "red:%i blue:%i\n",
+ level.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE] );
+ }
+
+ for (i=0 ; i < numSorted ; i++) {
+ int ping;
+
+ cl = &level.clients[level.sortedClients[i]];
+
+ if ( cl->sess.sessionTeam == TEAM_SPECTATOR ) {
+ continue;
+ }
+ if ( cl->pers.connected == CON_CONNECTING ) {
+ continue;
+ }
+
+ ping = cl->ps.ping < 999 ? cl->ps.ping : 999;
+
+ G_LogPrintf( "score: %i ping: %i client: %i %s\n", cl->ps.persistant[PERS_SCORE], ping, level.sortedClients[i], cl->pers.netname );
+#ifdef MISSIONPACK
+ if (g_singlePlayer.integer && g_gametype.integer == GT_TOURNAMENT) {
+ if (g_entities[cl - level.clients].r.svFlags & SVF_BOT && cl->ps.persistant[PERS_RANK] == 0) {
+ won = qfalse;
+ }
+ }
+#endif
+
+ }
+
+#ifdef MISSIONPACK
+ if (g_singlePlayer.integer) {
+ if (g_gametype.integer >= GT_CTF && g_ffa_gt==0) {
+ won = level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE];
+ }
+ trap_SendConsoleCommand( EXEC_APPEND, (won) ? "spWin\n" : "spLose\n" );
+ }
+#endif
+
+
+}
+
+
+/*
+=================
+CheckIntermissionExit
+
+The level will stay at the intermission for a minimum of 5 seconds
+If all players wish to continue, the level will then exit.
+If one or more players have not acknowledged the continue, the game will
+wait 10 seconds before going on.
+=================
+*/
+void CheckIntermissionExit( void ) {
+ int ready, notReady, playerCount;
+ int i;
+ gclient_t *cl;
+ int readyMask;
+
+ if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
+ return;
+ }
+
+ // see which players are ready
+ ready = 0;
+ notReady = 0;
+ readyMask = 0;
+ playerCount = 0;
+ for (i=0 ; i< g_maxclients.integer ; i++) {
+ cl = level.clients + i;
+ if ( cl->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ if ( g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT ) {
+ continue;
+ }
+
+ playerCount++;
+ if ( cl->readyToExit ) {
+ ready++;
+ if ( i < 16 ) {
+ readyMask |= 1 << i;
+ }
+ } else {
+ notReady++;
+ }
+ }
+
+ // copy the readyMask to each player's stats so
+ // it can be displayed on the scoreboard
+ for (i=0 ; i< g_maxclients.integer ; i++) {
+ cl = level.clients + i;
+ if ( cl->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ cl->ps.stats[STAT_CLIENTS_READY] = readyMask;
+ }
+
+ // never exit in less than five seconds
+ if ( level.time < level.intermissiontime + 5000 ) {
+ return;
+ }
+
+ // only test ready status when there are real players present
+ if ( playerCount > 0 ) {
+ // if nobody wants to go, clear timer
+ if ( !ready ) {
+ level.readyToExit = qfalse;
+ return;
+ }
+
+ // if everyone wants to go, go now
+ if ( !notReady ) {
+ ExitLevel();
+ return;
+ }
+ }
+
+ // the first person to ready starts the ten second timeout
+ if ( !level.readyToExit ) {
+ level.readyToExit = qtrue;
+ level.exitTime = level.time;
+ }
+
+ // if we have waited ten seconds since at least one player
+ // wanted to exit, go ahead
+ if ( level.time < level.exitTime + 10000 ) {
+ return;
+ }
+
+ ExitLevel();
+}
+
+/*
+=============
+ScoreIsTied
+=============
+*/
+qboolean ScoreIsTied( void ) {
+ int a, b;
+
+ if ( level.numPlayingClients < 2 ) {
+ return qfalse;
+ }
+
+ //Sago: In Elimination and Oneway Flag Capture teams must win by two points.
+ if ( g_gametype.integer == GT_ELIMINATION ||
+ (g_gametype.integer == GT_CTF_ELIMINATION && g_elimination_ctf_oneway.integer)) {
+ return (level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE] ||
+ level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE]+1 ||
+ level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE]-1);
+ }
+
+ if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
+ return level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE];
+ }
+
+ a = level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE];
+ b = level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE];
+
+ return a == b;
+}
+
+/*
+=================
+CheckExitRules
+
+There will be a delay between the time the exit is qualified for
+and the time everyone is moved to the intermission spot, so you
+can see the last frag.
+=================
+*/
+void CheckExitRules( void ) {
+ int i;
+ gclient_t *cl;
+ // if at the intermission, wait for all non-bots to
+ // signal ready, then go to next level
+ if ( level.intermissiontime ) {
+ CheckIntermissionExit ();
+ return;
+ } else {
+ //sago: Find the reason for this to be neccesary.
+ for (i=0 ; i< g_maxclients.integer ; i++) {
+ cl = level.clients + i;
+ if ( cl->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ cl->ps.stats[STAT_CLIENTS_READY] = 0;
+ }
+ }
+
+ if ( level.intermissionQueued ) {
+#ifdef MISSIONPACK
+ int time = (g_singlePlayer.integer) ? SP_INTERMISSION_DELAY_TIME : INTERMISSION_DELAY_TIME;
+ if ( level.time - level.intermissionQueued >= time ) {
+ level.intermissionQueued = 0;
+ BeginIntermission();
+ }
+#else
+ if ( level.time - level.intermissionQueued >= INTERMISSION_DELAY_TIME ) {
+ level.intermissionQueued = 0;
+ BeginIntermission();
+ }
+#endif
+ return;
+ }
+
+ // check for sudden death
+ if ( ScoreIsTied() ) {
+ // always wait for sudden death
+ return;
+ }
+
+ if ( g_timelimit.integer > 0 && !level.warmupTime ) {
+ if ( (level.time - level.startTime)/60000 >= g_timelimit.integer ) {
+ trap_SendServerCommand( -1, "print \"Timelimit hit.\n\"");
+ LogExit( "Timelimit hit." );
+ return;
+ }
+ }
+
+ if ( level.numPlayingClients < 2 ) {
+ return;
+ }
+
+ if ( (g_gametype.integer < GT_CTF || g_ffa_gt>0 ) && g_fraglimit.integer ) {
+ if ( level.teamScores[TEAM_RED] >= g_fraglimit.integer ) {
+ trap_SendServerCommand( -1, "print \"Red hit the fraglimit.\n\"" );
+ LogExit( "Fraglimit hit." );
+ return;
+ }
+
+ if ( level.teamScores[TEAM_BLUE] >= g_fraglimit.integer ) {
+ trap_SendServerCommand( -1, "print \"Blue hit the fraglimit.\n\"" );
+ LogExit( "Fraglimit hit." );
+ return;
+ }
+
+ for ( i=0 ; i< g_maxclients.integer ; i++ ) {
+ cl = level.clients + i;
+ if ( cl->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+ if ( cl->sess.sessionTeam != TEAM_FREE ) {
+ continue;
+ }
+
+ if ( cl->ps.persistant[PERS_SCORE] >= g_fraglimit.integer ) {
+ LogExit( "Fraglimit hit." );
+ trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " hit the fraglimit.\n\"",
+ cl->pers.netname ) );
+ return;
+ }
+ }
+ }
+
+ if ( (g_gametype.integer >= GT_CTF && g_ffa_gt<1) && g_capturelimit.integer ) {
+
+ if ( level.teamScores[TEAM_RED] >= g_capturelimit.integer ) {
+ trap_SendServerCommand( -1, "print \"Red hit the capturelimit.\n\"" );
+ LogExit( "Capturelimit hit." );
+ return;
+ }
+
+ if ( level.teamScores[TEAM_BLUE] >= g_capturelimit.integer ) {
+ trap_SendServerCommand( -1, "print \"Blue hit the capturelimit.\n\"" );
+ LogExit( "Capturelimit hit." );
+ return;
+ }
+ }
+}
+
+//LMS - Last man Stading functions:
+void StartLMSRound(void) {
+ int countsLiving;
+ countsLiving = TeamLivingCount( -1, TEAM_FREE );
+ if(countsLiving<2) {
+ trap_SendServerCommand( -1, "print \"Not enough players to start the round\n\"");
+ level.roundNumberStarted = level.roundNumber-1;
+ level.roundStartTime = level.time+1000*g_elimination_warmup.integer;
+ return;
+ }
+
+ //If we are enough to start a round:
+ level.roundNumberStarted = level.roundNumber; //Set numbers
+
+ G_LogPrintf( "LMS: %i %i %i: Round %i has started!\n", level.roundNumber, -1, 0, level.roundNumber );
+
+ SendEliminationMessageToAllClients();
+ EnableWeapons();
+}
+
+//the elimination start function
+void StartEliminationRound(void) {
+
+ int countsLiving[TEAM_NUM_TEAMS];
+ countsLiving[TEAM_BLUE] = TeamLivingCount( -1, TEAM_BLUE );
+ countsLiving[TEAM_RED] = TeamLivingCount( -1, TEAM_RED );
+ if((countsLiving[TEAM_BLUE]==0) || (countsLiving[TEAM_RED]==0))
+ {
+ trap_SendServerCommand( -1, "print \"Not enough players to start the round\n\"");
+ level.roundNumberStarted = level.roundNumber-1;
+ level.roundRespawned = qfalse;
+ //Remember that one of the teams is empty!
+ level.roundRedPlayers = countsLiving[TEAM_RED];
+ level.roundBluePlayers = countsLiving[TEAM_BLUE];
+ level.roundStartTime = level.time+1000*g_elimination_warmup.integer;
+ return;
+ }
+
+ //If we are enough to start a round:
+ level.roundNumberStarted = level.roundNumber; //Set numbers
+ level.roundRedPlayers = countsLiving[TEAM_RED];
+ level.roundBluePlayers = countsLiving[TEAM_BLUE];
+ if(g_gametype.integer == GT_CTF_ELIMINATION) {
+ Team_ReturnFlag( TEAM_RED );
+ Team_ReturnFlag( TEAM_BLUE );
+ }
+ if(g_gametype.integer == GT_ELIMINATION) {
+ G_LogPrintf( "ELIMINATION: %i %i %i: Round %i has started!\n", level.roundNumber, -1, 0, level.roundNumber );
+ } else if(g_gametype.integer == GT_CTF_ELIMINATION) {
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: Round %i has started!\n", level.roundNumber, -1, -1, 4, level.roundNumber );
+ }
+ SendEliminationMessageToAllClients();
+ if(g_elimination_ctf_oneway.integer)
+ SendAttackingTeamMessageToAllClients(); //Ensure that evaryone know who should attack.
+ EnableWeapons();
+}
+
+//things to do at end of round:
+void EndEliminationRound(void)
+{
+ DisableWeapons();
+ level.roundNumber++;
+ level.roundStartTime = level.time+1000*g_elimination_warmup.integer;
+ SendEliminationMessageToAllClients();
+ CalculateRanks();
+ level.roundRespawned = qfalse;
+ if(g_elimination_ctf_oneway.integer)
+ SendAttackingTeamMessageToAllClients();
+}
+
+//Things to do if we don't want to move the roundNumber
+void RestartEliminationRound(void) {
+ DisableWeapons();
+ level.roundNumberStarted = level.roundNumber-1;
+ level.roundStartTime = level.time+1000*g_elimination_warmup.integer;
+ if(!level.intermissiontime)
+ SendEliminationMessageToAllClients();
+ level.roundRespawned = qfalse;
+ if(g_elimination_ctf_oneway.integer)
+ SendAttackingTeamMessageToAllClients();
+}
+
+//Things to do during match warmup
+void WarmupEliminationRound(void) {
+ EnableWeapons();
+ level.roundNumberStarted = level.roundNumber-1;
+ level.roundStartTime = level.time+1000*g_elimination_warmup.integer;
+ SendEliminationMessageToAllClients();
+ level.roundRespawned = qfalse;
+ if(g_elimination_ctf_oneway.integer)
+ SendAttackingTeamMessageToAllClients();
+}
+
+/*
+========================================================================
+
+FUNCTIONS CALLED EVERY FRAME
+
+========================================================================
+*/
+
+/*
+CheckDoubleDomination
+*/
+
+void CheckDoubleDomination( void ) {
+ if ( level.numPlayingClients < 1 ) {
+ return;
+ }
+
+ if ( level.warmupTime != 0) {
+ if( ((level.pointStatusA == TEAM_BLUE && level.pointStatusB == TEAM_BLUE) ||
+ (level.pointStatusA == TEAM_RED && level.pointStatusB == TEAM_RED)) &&
+ level.timeTaken + 10*1000 <= level.time ) {
+ Team_RemoveDoubleDominationPoints();
+ level.roundStartTime = level.time + 10*1000;
+ SendScoreboardMessageToAllClients();
+ }
+ return;
+ }
+
+ if(g_gametype.integer != GT_DOUBLE_D)
+ return;
+
+ //Don't score if we are in intermission. Both points might have been taken when we went into intermission
+ if(level.intermissiontime)
+ return;
+
+ if(level.pointStatusA == TEAM_RED && level.pointStatusB == TEAM_RED && level.timeTaken + 10*1000 <= level.time) {
+ //Red scores
+ trap_SendServerCommand( -1, "print \"Red team scores!\n\"");
+ AddTeamScore(level.intermission_origin,TEAM_RED,1);
+ G_LogPrintf( "DD: %i %i %i: %s scores!\n", -1, TEAM_RED, 2, TeamName(TEAM_RED) );
+ Team_ForceGesture(TEAM_RED);
+ Team_DD_bonusAtPoints(TEAM_RED);
+ Team_RemoveDoubleDominationPoints();
+ //We start again in 10 seconds:
+ level.roundStartTime = level.time + 10*1000;
+ SendScoreboardMessageToAllClients();
+ CalculateRanks();
+ }
+
+ if(level.pointStatusA == TEAM_BLUE && level.pointStatusB == TEAM_BLUE && level.timeTaken + 10*1000 <= level.time) {
+ //Blue scores
+ trap_SendServerCommand( -1, "print \"Blue team scores!\n\"");
+ AddTeamScore(level.intermission_origin,TEAM_BLUE,1);
+ G_LogPrintf( "DD: %i %i %i: %s scores!\n", -1, TEAM_BLUE, 2, TeamName(TEAM_BLUE) );
+ Team_ForceGesture(TEAM_BLUE);
+ Team_DD_bonusAtPoints(TEAM_BLUE);
+ Team_RemoveDoubleDominationPoints();
+ //We start again in 10 seconds:
+ level.roundStartTime = level.time + 10*1000;
+ SendScoreboardMessageToAllClients();
+ CalculateRanks();
+ }
+
+ if((level.pointStatusA == TEAM_NONE || level.pointStatusB == TEAM_NONE) && level.time>level.roundStartTime) {
+ trap_SendServerCommand( -1, "print \"A new round has started\n\"");
+ Team_SpawnDoubleDominationPoints();
+ SendScoreboardMessageToAllClients();
+ }
+}
+
+/*
+CheckLMS
+*/
+
+void CheckLMS(void) {
+ int mode;
+ mode = g_lms_mode.integer;
+ if ( level.numPlayingClients < 1 ) {
+ return;
+ }
+
+
+
+ //We don't want to do anything in intermission
+ if(level.intermissiontime) {
+ if(level.roundRespawned) {
+ RestartEliminationRound();
+ }
+ level.roundStartTime = level.time; //so that a player might join at any time to fix the bots+no humans+autojoin bug
+ return;
+ }
+
+ if(g_gametype.integer == GT_LMS)
+ {
+ int countsLiving[TEAM_NUM_TEAMS];
+ //trap_SendServerCommand( -1, "print \"This is LMS!\n\"");
+ countsLiving[TEAM_FREE] = TeamLivingCount( -1, TEAM_FREE );
+ if(countsLiving[TEAM_FREE]==1 && level.roundNumber==level.roundNumberStarted)
+ {
+ if(mode <=1 )
+ LMSpoint();
+ trap_SendServerCommand( -1, "print \"We have a winner!\n\"");
+ EndEliminationRound();
+ Team_ForceGesture(TEAM_FREE);
+ }
+
+ if(countsLiving[TEAM_FREE]==0 && level.roundNumber==level.roundNumberStarted)
+ {
+ trap_SendServerCommand( -1, "print \"All death... how sad\n\"");
+ EndEliminationRound();
+ }
+
+ if((g_elimination_roundtime.integer) && (level.roundNumber==level.roundNumberStarted)&&(g_lms_mode.integer == 1 || g_lms_mode.integer==3)&&(level.time>=level.roundStartTime+1000*g_elimination_roundtime.integer))
+ {
+ trap_SendServerCommand( -1, "print \"Time up - Overtime disabled\n\"");
+ if(mode <=1 )
+ LMSpoint();
+ EndEliminationRound();
+ }
+
+ //This might be better placed another place:
+ if(g_elimination_activewarmup.integer<2)
+ g_elimination_activewarmup.integer=2; //We need at least 2 seconds to spawn all players
+ if(g_elimination_activewarmup.integer >= g_elimination_warmup.integer) //This must not be true
+ g_elimination_warmup.integer = g_elimination_activewarmup.integer+1; //Increase warmup
+
+ //Force respawn
+ if(level.roundNumber != level.roundNumberStarted && level.time>level.roundStartTime-1000*g_elimination_activewarmup.integer && !level.roundRespawned)
+ {
+ level.roundRespawned = qtrue;
+ RespawnAll();
+ DisableWeapons();
+ SendEliminationMessageToAllClients();
+ }
+
+ if(level.time<=level.roundStartTime && level.time>level.roundStartTime-1000*g_elimination_activewarmup.integer)
+ {
+ RespawnDead();
+ //DisableWeapons();
+ }
+
+ if(level.roundNumber == level.roundNumberStarted)
+ {
+ EnableWeapons();
+ }
+
+ if((level.roundNumber>level.roundNumberStarted)&&(level.time>=level.roundStartTime))
+ StartLMSRound();
+
+ if(level.time+1000*g_elimination_warmup.integer-500>level.roundStartTime && level.numPlayingClients < 2)
+ {
+ RespawnDead(); //Allow player to run around anyway
+ WarmupEliminationRound(); //Start over
+ return;
+ }
+
+ if(level.warmupTime != 0) {
+ if(level.time+1000*g_elimination_warmup.integer-500>level.roundStartTime)
+ {
+ RespawnDead();
+ WarmupEliminationRound();
+ }
+ }
+
+ }
+}
+
+/*
+=============
+CheckElimination
+=============
+*/
+void CheckElimination(void) {
+ if ( level.numPlayingClients < 1 ) {
+ if( (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) &&
+ ( level.time+1000*g_elimination_warmup.integer-500>level.roundStartTime ))
+ RestartEliminationRound(); //For spectators
+ return;
+ }
+
+ //We don't want to do anything in itnermission
+ if(level.intermissiontime) {
+ if(level.roundRespawned)
+ RestartEliminationRound();
+ level.roundStartTime = level.time+1000*g_elimination_warmup.integer;
+ return;
+ }
+
+ if(g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION)
+ {
+ int counts[TEAM_NUM_TEAMS];
+ int countsLiving[TEAM_NUM_TEAMS];
+ int countsHealth[TEAM_NUM_TEAMS];
+ counts[TEAM_BLUE] = TeamCount( -1, TEAM_BLUE );
+ counts[TEAM_RED] = TeamCount( -1, TEAM_RED );
+
+ countsLiving[TEAM_BLUE] = TeamLivingCount( -1, TEAM_BLUE );
+ countsLiving[TEAM_RED] = TeamLivingCount( -1, TEAM_RED );
+
+ countsHealth[TEAM_BLUE] = TeamHealthCount( -1, TEAM_BLUE );
+ countsHealth[TEAM_RED] = TeamHealthCount( -1, TEAM_RED );
+
+ if(level.roundBluePlayers != 0 && level.roundRedPlayers != 0) { //Cannot score if one of the team never got any living players
+ if((countsLiving[TEAM_BLUE]==0)&&(level.roundNumber==level.roundNumberStarted))
+ {
+ //Blue team has been eliminated!
+ trap_SendServerCommand( -1, "print \"Blue Team eliminated!\n\"");
+ AddTeamScore(level.intermission_origin,TEAM_RED,1);
+ if(g_gametype.integer == GT_ELIMINATION) {
+ G_LogPrintf( "ELIMINATION: %i %i %i: %s wins round %i by eleminating the enemy team!\n", level.roundNumber, TEAM_RED, 1, TeamName(TEAM_RED), level.roundNumber );
+ } else {
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i by eleminating the enemy team!\n", level.roundNumber, -1, TEAM_RED, 6, TeamName(TEAM_RED), level.roundNumber );
+ }
+ EndEliminationRound();
+ Team_ForceGesture(TEAM_RED);
+ }
+ else if((countsLiving[TEAM_RED]==0)&&(level.roundNumber==level.roundNumberStarted))
+ {
+ //Red team eliminated!
+ trap_SendServerCommand( -1, "print \"Red Team eliminated!\n\"");
+ AddTeamScore(level.intermission_origin,TEAM_BLUE,1);
+ if(g_gametype.integer == GT_ELIMINATION) {
+ G_LogPrintf( "ELIMINATION: %i %i %i: %s wins round %i by eleminating the enemy team!\n", level.roundNumber, TEAM_BLUE, 1, TeamName(TEAM_BLUE), level.roundNumber );
+ } else {
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i by eleminating the enemy team!\n", level.roundNumber, -1, TEAM_BLUE, 6, TeamName(TEAM_BLUE), level.roundNumber );
+ }
+ EndEliminationRound();
+ Team_ForceGesture(TEAM_BLUE);
+ }
+ }
+
+ //Time up
+ if((level.roundNumber==level.roundNumberStarted)&&(g_elimination_roundtime.integer)&&(level.time>=level.roundStartTime+1000*g_elimination_roundtime.integer))
+ {
+ trap_SendServerCommand( -1, "print \"No teams eliminated.\n\"");
+
+ if(level.roundBluePlayers != 0 && level.roundRedPlayers != 0) {//We don't want to divide by zero. (should not be possible)
+ if(g_gametype.integer == GT_CTF_ELIMINATION && g_elimination_ctf_oneway.integer) {
+ //One way CTF, make defensice team the winner.
+ if ( (level.eliminationSides+level.roundNumber)%2 == 0 ) { //Red was attacking
+ trap_SendServerCommand( -1, "print \"Blue team defended the base\n\"");
+ AddTeamScore(level.intermission_origin,TEAM_BLUE,1);
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i by defending the flag!\n", level.roundNumber, -1, TEAM_BLUE, 5, TeamName(TEAM_BLUE), level.roundNumber );
+ }
+ else {
+ trap_SendServerCommand( -1, "print \"Red team defended the base\n\"");
+ AddTeamScore(level.intermission_origin,TEAM_RED,1);
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i by defending the flag!\n", level.roundNumber, -1, TEAM_RED, 5, TeamName(TEAM_RED), level.roundNumber );
+ }
+ }
+ else if(((double)countsLiving[TEAM_RED])/((double)level.roundRedPlayers)>((double)countsLiving[TEAM_BLUE])/((double)level.roundBluePlayers))
+ {
+ //Red team has higher procentage survivors
+ trap_SendServerCommand( -1, "print \"Red team has most survivers!\n\"");
+ AddTeamScore(level.intermission_origin,TEAM_RED,1);
+ if(g_gametype.integer == GT_ELIMINATION) {
+ G_LogPrintf( "ELIMINATION: %i %i %i: %s wins round %i due to more survivors!\n", level.roundNumber, TEAM_RED, 2, TeamName(TEAM_RED), level.roundNumber );
+ } else {
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i due to more survivors!\n", level.roundNumber, -1, TEAM_RED, 7, TeamName(TEAM_RED), level.roundNumber );
+ }
+ }
+ else if(((double)countsLiving[TEAM_RED])/((double)level.roundRedPlayers)<((double)countsLiving[TEAM_BLUE])/((double)level.roundBluePlayers))
+ {
+ //Blue team has higher procentage survivors
+ trap_SendServerCommand( -1, "print \"Blue team has most survivers!\n\"");
+ AddTeamScore(level.intermission_origin,TEAM_BLUE,1);
+ if(g_gametype.integer == GT_ELIMINATION) {
+ G_LogPrintf( "ELIMINATION: %i %i %i: %s wins round %i due to more survivors!\n", level.roundNumber, TEAM_BLUE, 2, TeamName(TEAM_BLUE), level.roundNumber );
+ } else {
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i due to more survivors!\n", level.roundNumber, -1, TEAM_BLUE, 7, TeamName(TEAM_BLUE), level.roundNumber );
+ }
+ }
+ else if(countsHealth[TEAM_RED]>countsHealth[TEAM_BLUE])
+ {
+ //Red team has more health
+ trap_SendServerCommand( -1, "print \"Red team has more health left!\n\"");
+ AddTeamScore(level.intermission_origin,TEAM_RED,1);
+ if(g_gametype.integer == GT_ELIMINATION) {
+ G_LogPrintf( "ELIMINATION: %i %i %i: %s wins round %i due to more health left!\n", level.roundNumber, TEAM_RED, 3, TeamName(TEAM_RED), level.roundNumber );
+ } else {
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i due to more health left!\n", level.roundNumber, -1, TEAM_RED, 8, TeamName(TEAM_RED), level.roundNumber );
+ }
+ }
+ else if(countsHealth[TEAM_RED]<countsHealth[TEAM_BLUE])
+ {
+ //Blue team has more health
+ trap_SendServerCommand( -1, "print \"Blue team has more health left!\n\"");
+ AddTeamScore(level.intermission_origin,TEAM_BLUE,1);
+ if(g_gametype.integer == GT_ELIMINATION) {
+ G_LogPrintf( "ELIMINATION: %i %i %i: %s wins round %i due to more health left!\n", level.roundNumber, TEAM_BLUE, 3, TeamName(TEAM_BLUE), level.roundNumber );
+ } else {
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i due to more health left!\n", level.roundNumber, -1, TEAM_BLUE, 8, TeamName(TEAM_BLUE), level.roundNumber );
+ }
+ }
+ }
+ //Draw
+ if(g_gametype.integer == GT_ELIMINATION) {
+ G_LogPrintf( "ELIMINATION: %i %i %i: Round %i ended in a draw!\n", level.roundNumber, -1, 4, level.roundNumber );
+ } else {
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: Round %i ended in a draw!\n", level.roundNumber, -1, -1, 9, level.roundNumber );
+ }
+ EndEliminationRound();
+ }
+
+ //This might be better placed another place:
+ if(g_elimination_activewarmup.integer<1)
+ g_elimination_activewarmup.integer=1; //We need at least 1 second to spawn all players
+ if(g_elimination_activewarmup.integer >= g_elimination_warmup.integer) //This must not be true
+ g_elimination_warmup.integer = g_elimination_activewarmup.integer+1; //Increase warmup
+
+ //Force respawn
+ if(level.roundNumber!=level.roundNumberStarted && level.time>level.roundStartTime-1000*g_elimination_activewarmup.integer && !level.roundRespawned)
+ {
+ level.roundRespawned = qtrue;
+ RespawnAll();
+ SendEliminationMessageToAllClients();
+ }
+
+ if(level.time<=level.roundStartTime && level.time>level.roundStartTime-1000*g_elimination_activewarmup.integer)
+ {
+ RespawnDead();
+ }
+
+
+ if((level.roundNumber>level.roundNumberStarted)&&(level.time>=level.roundStartTime))
+ StartEliminationRound();
+
+ if(level.time+1000*g_elimination_warmup.integer-500>level.roundStartTime)
+ if(counts[TEAM_BLUE]<1 || counts[TEAM_RED]<1)
+ {
+ RespawnDead(); //Allow players to run around anyway
+ WarmupEliminationRound(); //Start over
+ return;
+ }
+
+ if(level.warmupTime != 0) {
+ if(level.time+1000*g_elimination_warmup.integer-500>level.roundStartTime)
+ {
+ RespawnDead();
+ WarmupEliminationRound();
+ }
+ }
+ }
+}
+
+/*
+=============
+CheckDomination
+=============
+*/
+void CheckDomination(void) {
+ int i;
+ int scoreFactor = 1;
+
+ if ( (level.numPlayingClients < 1) || (g_gametype.integer != GT_DOMINATION) ) {
+ return;
+ }
+
+ //Do nothing if warmup
+ if(level.warmupTime != 0)
+ return;
+
+ //Don't score if we are in intermission. Just plain stupid
+ if(level.intermissiontime)
+ return;
+
+ //Sago: I use if instead of while, since if the server stops for more than 2 seconds people should not be allowed to score anyway
+ if(level.domination_points_count>3)
+ scoreFactor = 2; //score more slowly if there are many points
+ if(level.time>=level.dom_scoreGiven*DOM_SECSPERPOINT*scoreFactor) {
+ for(i=0;i<level.domination_points_count;i++) {
+ if ( level.pointStatusDom[i] == TEAM_RED )
+ AddTeamScore(level.intermission_origin,TEAM_RED,1);
+ if ( level.pointStatusDom[i] == TEAM_BLUE )
+ AddTeamScore(level.intermission_origin,TEAM_BLUE,1);
+ G_LogPrintf( "DOM: %i %i %i %i: %s holds point %s for 1 point!\n",
+ -1,i,1,level.pointStatusDom[i],
+ TeamName(level.pointStatusDom[i]),level.domination_points_names[i]);
+ }
+ level.dom_scoreGiven++;
+ while(level.time>level.dom_scoreGiven*DOM_SECSPERPOINT*scoreFactor)
+ level.dom_scoreGiven++;
+ CalculateRanks();
+ }
+}
+
+/*
+=============
+CheckTournament
+
+Once a frame, check for changes in tournement player state
+=============
+*/
+void CheckTournament( void ) {
+ // check because we run 3 game frames before calling Connect and/or ClientBegin
+ // for clients on a map_restart
+ if ( level.numPlayingClients == 0 ) {
+ return;
+ }
+
+ if ( g_gametype.integer == GT_TOURNAMENT ) {
+
+ // pull in a spectator if needed
+ if ( level.numPlayingClients < 2 ) {
+ AddTournamentPlayer();
+ }
+
+ // if we don't have two players, go back to "waiting for players"
+ if ( level.numPlayingClients != 2 ) {
+ if ( level.warmupTime != -1 ) {
+ level.warmupTime = -1;
+ trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
+ G_LogPrintf( "Warmup:\n" );
+ }
+ return;
+ }
+
+ if ( level.warmupTime == 0 ) {
+ return;
+ }
+
+ // if the warmup is changed at the console, restart it
+ if ( g_warmup.modificationCount != level.warmupModificationCount ) {
+ level.warmupModificationCount = g_warmup.modificationCount;
+ level.warmupTime = -1;
+ }
+
+ // if all players have arrived, start the countdown
+ if ( level.warmupTime < 0 ) {
+ if ( level.numPlayingClients == 2 ) {
+ // fudge by -1 to account for extra delays
+ if ( g_warmup.integer > 1 ) {
+ level.warmupTime = level.time + ( g_warmup.integer - 1 ) * 1000;
+ } else {
+ level.warmupTime = 0;
+ }
+
+ trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
+ }
+ return;
+ }
+
+ // if the warmup time has counted down, restart
+ if ( level.time > level.warmupTime ) {
+ level.warmupTime += 10000;
+ trap_Cvar_Set( "g_restarted", "1" );
+ trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
+ level.restarted = qtrue;
+ return;
+ }
+ } else if ( g_gametype.integer != GT_SINGLE_PLAYER && level.warmupTime != 0 ) {
+ int counts[TEAM_NUM_TEAMS];
+ qboolean notEnough = qfalse;
+
+ if ( g_gametype.integer > GT_TEAM && !g_ffa_gt ) {
+ counts[TEAM_BLUE] = TeamCount( -1, TEAM_BLUE );
+ counts[TEAM_RED] = TeamCount( -1, TEAM_RED );
+
+ if (counts[TEAM_RED] < 1 || counts[TEAM_BLUE] < 1) {
+ notEnough = qtrue;
+ }
+ } else if ( level.numPlayingClients < 2 ) {
+ notEnough = qtrue;
+ }
+
+ if ( notEnough ) {
+ if ( level.warmupTime != -1 ) {
+ level.warmupTime = -1;
+ trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
+ G_LogPrintf( "Warmup:\n" );
+ }
+ return; // still waiting for team members
+ }
+
+ if ( level.warmupTime == 0 ) {
+ return;
+ }
+
+ // if the warmup is changed at the console, restart it
+ if ( g_warmup.modificationCount != level.warmupModificationCount ) {
+ level.warmupModificationCount = g_warmup.modificationCount;
+ level.warmupTime = -1;
+ }
+
+ // if all players have arrived, start the countdown
+ if ( level.warmupTime < 0 ) {
+ // fudge by -1 to account for extra delays
+ level.warmupTime = level.time + ( g_warmup.integer - 1 ) * 1000;
+ trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
+ return;
+ }
+
+ // if the warmup time has counted down, restart
+ if ( level.time > level.warmupTime ) {
+ level.warmupTime += 10000;
+ trap_Cvar_Set( "g_restarted", "1" );
+ trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
+ level.restarted = qtrue;
+ return;
+ }
+ }
+}
+
+
+
+
+/*
+==================
+PrintTeam
+==================
+*/
+void PrintTeam(int team, char *message) {
+ int i;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if (level.clients[i].sess.sessionTeam != team)
+ continue;
+ trap_SendServerCommand( i, message );
+ }
+}
+
+/*
+==================
+SetLeader
+==================
+*/
+void SetLeader(int team, int client) {
+ int i;
+
+ if ( level.clients[client].pers.connected == CON_DISCONNECTED ) {
+ PrintTeam(team, va("print \"%s is not connected\n\"", level.clients[client].pers.netname) );
+ return;
+ }
+ if (level.clients[client].sess.sessionTeam != team) {
+ PrintTeam(team, va("print \"%s is not on the team anymore\n\"", level.clients[client].pers.netname) );
+ return;
+ }
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if (level.clients[i].sess.sessionTeam != team)
+ continue;
+ if (level.clients[i].sess.teamLeader) {
+ level.clients[i].sess.teamLeader = qfalse;
+ ClientUserinfoChanged(i);
+ }
+ }
+ level.clients[client].sess.teamLeader = qtrue;
+ ClientUserinfoChanged( client );
+ PrintTeam(team, va("print \"%s is the new team leader\n\"", level.clients[client].pers.netname) );
+}
+
+/*
+==================
+CheckTeamLeader
+==================
+*/
+void CheckTeamLeader( int team ) {
+ int i;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if (level.clients[i].sess.sessionTeam != team)
+ continue;
+ if (level.clients[i].sess.teamLeader)
+ break;
+ }
+ if (i >= level.maxclients) {
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if (level.clients[i].sess.sessionTeam != team)
+ continue;
+ if (!(g_entities[i].r.svFlags & SVF_BOT)) {
+ level.clients[i].sess.teamLeader = qtrue;
+ break;
+ }
+ }
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if (level.clients[i].sess.sessionTeam != team)
+ continue;
+ level.clients[i].sess.teamLeader = qtrue;
+ break;
+ }
+ }
+}
+
+/*
+==================
+CheckTeamVote
+==================
+*/
+void CheckTeamVote( int team ) {
+ int cs_offset;
+
+ if ( team == TEAM_RED )
+ cs_offset = 0;
+ else if ( team == TEAM_BLUE )
+ cs_offset = 1;
+ else
+ return;
+
+ if ( !level.teamVoteTime[cs_offset] ) {
+ return;
+ }
+ if ( level.time - level.teamVoteTime[cs_offset] >= VOTE_TIME ) {
+ trap_SendServerCommand( -1, "print \"Team vote failed.\n\"" );
+ } else {
+ if ( level.teamVoteYes[cs_offset] > level.numteamVotingClients[cs_offset]/2 ) {
+ // execute the command, then remove the vote
+ trap_SendServerCommand( -1, "print \"Team vote passed.\n\"" );
+ //
+ if ( !Q_strncmp( "leader", level.teamVoteString[cs_offset], 6) ) {
+ //set the team leader
+ SetLeader(team, atoi(level.teamVoteString[cs_offset] + 7));
+ }
+ else {
+ trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.teamVoteString[cs_offset] ) );
+ }
+ } else if ( level.teamVoteNo[cs_offset] >= level.numteamVotingClients[cs_offset]/2 ) {
+ // same behavior as a timeout
+ trap_SendServerCommand( -1, "print \"Team vote failed.\n\"" );
+ } else {
+ // still waiting for a majority
+ return;
+ }
+ }
+ level.teamVoteTime[cs_offset] = 0;
+ trap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, "" );
+
+}
+
+
+/*
+==================
+CheckCvars
+==================
+*/
+void CheckCvars( void ) {
+ static int lastMod = -1;
+
+ if ( g_password.modificationCount != lastMod ) {
+ lastMod = g_password.modificationCount;
+ if ( *g_password.string && Q_stricmp( g_password.string, "none" ) ) {
+ trap_Cvar_Set( "g_needpass", "1" );
+ } else {
+ trap_Cvar_Set( "g_needpass", "0" );
+ }
+ }
+}
+
+/*
+=============
+G_RunThink
+
+Runs thinking code for this frame if necessary
+=============
+*/
+void G_RunThink (gentity_t *ent) {
+ float thinktime;
+
+ thinktime = ent->nextthink;
+ if (thinktime <= 0) {
+ return;
+ }
+ if (thinktime > level.time) {
+ return;
+ }
+
+ ent->nextthink = 0;
+ if (!ent->think) {
+ G_Error ( "NULL ent->think");
+ }
+ ent->think (ent);
+}
+
+/*
+================
+G_RunFrame
+
+Advances the non-player objects in the world
+================
+*/
+void G_RunFrame( int levelTime ) {
+ int i;
+ gentity_t *ent;
+ int msec;
+int start, end;
+
+ // if we are waiting for the level to restart, do nothing
+ if ( level.restarted ) {
+ return;
+ }
+
+ level.framenum++;
+ level.previousTime = level.time;
+ level.time = levelTime;
+ msec = level.time - level.previousTime;
+
+ // get any cvar changes
+ G_UpdateCvars();
+
+ if( (g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION) && !(g_elimflags.integer & EF_NO_FREESPEC) && g_elimination_lockspectator.integer>1)
+ trap_Cvar_Set("elimflags",va("%i",g_elimflags.integer|EF_NO_FREESPEC));
+ else
+ if( (g_elimflags.integer & EF_NO_FREESPEC) && g_elimination_lockspectator.integer<2)
+ trap_Cvar_Set("elimflags",va("%i",g_elimflags.integer&(~EF_NO_FREESPEC) ) );
+
+ if( g_elimination_ctf_oneway.integer && !(g_elimflags.integer & EF_ONEWAY) ) {
+ trap_Cvar_Set("elimflags",va("%i",g_elimflags.integer|EF_ONEWAY ) );
+ //If the server admin has enabled it midgame imidiantly braodcast attacking team
+ SendAttackingTeamMessageToAllClients();
+ }
+ else
+ if( !g_elimination_ctf_oneway.integer && (g_elimflags.integer & EF_ONEWAY) ) {
+ trap_Cvar_Set("elimflags",va("%i",g_elimflags.integer&(~EF_ONEWAY) ) );
+ }
+
+ //
+ // go through all allocated objects
+ //
+ start = trap_Milliseconds();
+ ent = &g_entities[0];
+ for (i=0 ; i<level.num_entities ; i++, ent++) {
+ if ( !ent->inuse ) {
+ continue;
+ }
+
+ // clear events that are too old
+ if ( level.time - ent->eventTime > EVENT_VALID_MSEC ) {
+ if ( ent->s.event ) {
+ ent->s.event = 0; // &= EV_EVENT_BITS;
+ if ( ent->client ) {
+ ent->client->ps.externalEvent = 0;
+ // predicted events should never be set to zero
+ //ent->client->ps.events[0] = 0;
+ //ent->client->ps.events[1] = 0;
+ }
+ }
+ if ( ent->freeAfterEvent ) {
+ // tempEntities or dropped items completely go away after their event
+ G_FreeEntity( ent );
+ continue;
+ } else if ( ent->unlinkAfterEvent ) {
+ // items that will respawn will hide themselves after their pickup event
+ ent->unlinkAfterEvent = qfalse;
+ trap_UnlinkEntity( ent );
+ }
+ }
+
+ // temporary entities don't think
+ if ( ent->freeAfterEvent ) {
+ continue;
+ }
+
+ if ( !ent->r.linked && ent->neverFree ) {
+ continue;
+ }
+
+//unlagged - backward reconciliation #2
+ // we'll run missiles separately to save CPU in backward reconciliation
+/*
+ if ( ent->s.eType == ET_MISSILE ) {
+ G_RunMissile( ent );
+ continue;
+ }
+*/
+//unlagged - backward reconciliation #2
+
+ if ( ent->s.eType == ET_ITEM || ent->physicsObject ) {
+ G_RunItem( ent );
+ continue;
+ }
+
+ if ( ent->s.eType == ET_MOVER ) {
+ G_RunMover( ent );
+ continue;
+ }
+
+ if ( i < MAX_CLIENTS ) {
+ G_RunClient( ent );
+ continue;
+ }
+
+ G_RunThink( ent );
+ }
+
+//unlagged - backward reconciliation #2
+ // NOW run the missiles, with all players backward-reconciled
+ // to the positions they were in exactly 50ms ago, at the end
+ // of the last server frame
+ G_TimeShiftAllClients( level.previousTime, NULL );
+
+ ent = &g_entities[0];
+ for (i=0 ; i<level.num_entities ; i++, ent++) {
+ if ( !ent->inuse ) {
+ continue;
+ }
+
+ // temporary entities don't think
+ if ( ent->freeAfterEvent ) {
+ continue;
+ }
+
+ if ( ent->s.eType == ET_MISSILE ) {
+ G_RunMissile( ent );
+ }
+ }
+
+ G_UnTimeShiftAllClients( NULL );
+//unlagged - backward reconciliation #2
+
+end = trap_Milliseconds();
+
+start = trap_Milliseconds();
+ // perform final fixups on the players
+ ent = &g_entities[0];
+ for (i=0 ; i < level.maxclients ; i++, ent++ ) {
+ if ( ent->inuse ) {
+ ClientEndFrame( ent );
+ }
+ }
+end = trap_Milliseconds();
+
+ // see if it is time to do a tournement restart
+ CheckTournament();
+
+ //Check Elimination state
+ CheckElimination();
+ CheckLMS();
+
+ //Check Double Domination
+ CheckDoubleDomination();
+
+ CheckDomination();
+
+ //Sago: I just need to think why I placed this here... they should only spawn once
+ if(g_gametype.integer == GT_DOMINATION)
+ Team_Dom_SpawnPoints();
+
+ // see if it is time to end the level
+ CheckExitRules();
+
+ // update to team status?
+ CheckTeamStatus();
+
+ // cancel vote if timed out
+ CheckVote();
+
+ // check team votes
+ CheckTeamVote( TEAM_RED );
+ CheckTeamVote( TEAM_BLUE );
+
+ // for tracking changes
+ CheckCvars();
+
+ if (g_listEntity.integer) {
+ for (i = 0; i < MAX_GENTITIES; i++) {
+ G_Printf("%4i: %s\n", i, g_entities[i].classname);
+ }
+ trap_Cvar_Set("g_listEntity", "0");
+ }
+
+//unlagged - backward reconciliation #4
+ // record the time at the end of this frame - it should be about
+ // the time the next frame begins - when the server starts
+ // accepting commands from connected clients
+ level.frameStartTime = trap_Milliseconds();
+//unlagged - backward reconciliation #4
+}
+
diff --git a/game/code/game/g_mem.c b/code/game/g_mem.c
similarity index 100%
rename from game/code/game/g_mem.c
rename to code/game/g_mem.c
diff --git a/code/game/g_misc.c b/code/game/g_misc.c
new file mode 100644
index 0000000..6b7fee5
--- /dev/null
+++ b/code/game/g_misc.c
@@ -0,0 +1,488 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// g_misc.c
+
+#include "g_local.h"
+
+
+/*QUAKED func_group (0 0 0) ?
+Used to group brushes together just for editor convenience. They are turned into normal brushes by the utilities.
+*/
+
+
+/*QUAKED info_camp (0 0.5 0) (-4 -4 -4) (4 4 4)
+Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
+*/
+void SP_info_camp( gentity_t *self ) {
+ G_SetOrigin( self, self->s.origin );
+}
+
+
+/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
+Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
+*/
+void SP_info_null( gentity_t *self ) {
+ G_FreeEntity( self );
+}
+
+
+/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
+Used as a positional target for in-game calculation, like jumppad targets.
+target_position does the same thing
+*/
+void SP_info_notnull( gentity_t *self ){
+ G_SetOrigin( self, self->s.origin );
+}
+
+
+/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) linear
+Non-displayed light.
+"light" overrides the default 300 intensity.
+Linear checbox gives linear falloff instead of inverse square
+Lights pointed at a target will be spotlights.
+"radius" overrides the default 64 unit radius of a spotlight at the target point.
+*/
+void SP_light( gentity_t *self ) {
+ G_FreeEntity( self );
+}
+
+
+
+/*
+=================================================================================
+
+TELEPORTERS
+
+=================================================================================
+*/
+
+void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles ) {
+ gentity_t *tent;
+ qboolean noAngles;
+
+ noAngles = (angles[0] > 999999.0);
+ // use temp events at source and destination to prevent the effect
+ // from getting dropped by a second player event
+ if ( player->client->sess.sessionTeam != TEAM_SPECTATOR && player->client->ps.pm_type != PM_SPECTATOR) {
+ tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
+ tent->s.clientNum = player->s.clientNum;
+
+ tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN );
+ tent->s.clientNum = player->s.clientNum;
+ }
+
+ // unlink to make sure it can't possibly interfere with G_KillBox
+ trap_UnlinkEntity (player);
+
+ VectorCopy ( origin, player->client->ps.origin );
+ player->client->ps.origin[2] += 1;
+
+ if (!noAngles) {
+ // spit the player out
+ AngleVectors( angles, player->client->ps.velocity, NULL, NULL );
+ VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );
+ player->client->ps.pm_time = 160; // hold time
+ player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
+
+ // set angles
+ SetClientViewAngle(player, angles);
+ }
+
+ // toggle the teleport bit so the client knows to not lerp
+ player->client->ps.eFlags ^= EF_TELEPORT_BIT;
+
+//unlagged - backward reconciliation #3
+ // we don't want players being backward-reconciled back through teleporters
+ G_ResetHistory( player );
+//unlagged - backward reconciliation #3
+
+ // kill anything at the destination
+ if ( player->client->sess.sessionTeam != TEAM_SPECTATOR && player->client->ps.pm_type != PM_SPECTATOR ) {
+ G_KillBox (player);
+ }
+
+ // save results of pmove
+ BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );
+
+ // use the precise origin for linking
+ VectorCopy( player->client->ps.origin, player->r.currentOrigin );
+
+ if ( player->client->sess.sessionTeam != TEAM_SPECTATOR && player->client->ps.pm_type != PM_SPECTATOR ) {
+ trap_LinkEntity (player);
+ }
+}
+
+
+/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
+Point teleporters at these.
+Now that we don't have teleport destination pads, this is just
+an info_notnull
+*/
+void SP_misc_teleporter_dest( gentity_t *ent ) {
+}
+
+
+//===========================================================
+
+/*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16)
+"model" arbitrary .md3 file to display
+*/
+void SP_misc_model( gentity_t *ent ) {
+
+#if 0
+ ent->s.modelindex = G_ModelIndex( ent->model );
+ VectorSet (ent->mins, -16, -16, -16);
+ VectorSet (ent->maxs, 16, 16, 16);
+ trap_LinkEntity (ent);
+
+ G_SetOrigin( ent, ent->s.origin );
+ VectorCopy( ent->s.angles, ent->s.apos.trBase );
+#else
+ G_FreeEntity( ent );
+#endif
+}
+
+//===========================================================
+
+void locateCamera( gentity_t *ent ) {
+ vec3_t dir;
+ gentity_t *target;
+ gentity_t *owner;
+
+ owner = G_PickTarget( ent->target );
+ if ( !owner ) {
+ G_Printf( "Couldn't find target for misc_partal_surface\n" );
+ G_FreeEntity( ent );
+ return;
+ }
+ ent->r.ownerNum = owner->s.number;
+
+ // frame holds the rotate speed
+ if ( owner->spawnflags & 1 ) {
+ ent->s.frame = 25;
+ } else if ( owner->spawnflags & 2 ) {
+ ent->s.frame = 75;
+ }
+
+ // swing camera ?
+ if ( owner->spawnflags & 4 ) {
+ // set to 0 for no rotation at all
+ ent->s.powerups = 0;
+ }
+ else {
+ ent->s.powerups = 1;
+ }
+
+ // clientNum holds the rotate offset
+ ent->s.clientNum = owner->s.clientNum;
+
+ VectorCopy( owner->s.origin, ent->s.origin2 );
+
+ // see if the portal_camera has a target
+ target = G_PickTarget( owner->target );
+ if ( target ) {
+ VectorSubtract( target->s.origin, owner->s.origin, dir );
+ VectorNormalize( dir );
+ } else {
+ G_SetMovedir( owner->s.angles, dir );
+ }
+
+ ent->s.eventParm = DirToByte( dir );
+}
+
+/*QUAKED misc_portal_surface (0 0 1) (-8 -8 -8) (8 8 8)
+The portal surface nearest this entity will show a view from the targeted misc_portal_camera, or a mirror view if untargeted.
+This must be within 64 world units of the surface!
+*/
+void SP_misc_portal_surface(gentity_t *ent) {
+ VectorClear( ent->r.mins );
+ VectorClear( ent->r.maxs );
+ trap_LinkEntity (ent);
+
+ ent->r.svFlags = SVF_PORTAL;
+ ent->s.eType = ET_PORTAL;
+
+ if ( !ent->target ) {
+ VectorCopy( ent->s.origin, ent->s.origin2 );
+ } else {
+ ent->think = locateCamera;
+ ent->nextthink = level.time + 100;
+ }
+}
+
+/*QUAKED misc_portal_camera (0 0 1) (-8 -8 -8) (8 8 8) slowrotate fastrotate noswing
+The target for a misc_portal_director. You can set either angles or target another entity to determine the direction of view.
+"roll" an angle modifier to orient the camera around the target vector;
+*/
+void SP_misc_portal_camera(gentity_t *ent) {
+ float roll;
+
+ VectorClear( ent->r.mins );
+ VectorClear( ent->r.maxs );
+ trap_LinkEntity (ent);
+
+ G_SpawnFloat( "roll", "0", &roll );
+
+ ent->s.clientNum = roll/360.0 * 256;
+}
+
+/*
+======================================================================
+
+ SHOOTERS
+
+======================================================================
+*/
+
+void Use_Shooter( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
+ vec3_t dir;
+ float deg;
+ vec3_t up, right;
+
+ // see if we have a target
+ if ( ent->enemy ) {
+ VectorSubtract( ent->enemy->r.currentOrigin, ent->s.origin, dir );
+ VectorNormalize( dir );
+ } else {
+ VectorCopy( ent->movedir, dir );
+ }
+
+ // randomize a bit
+ PerpendicularVector( up, dir );
+ CrossProduct( up, dir, right );
+
+ deg = crandom() * ent->random;
+ VectorMA( dir, deg, up, dir );
+
+ deg = crandom() * ent->random;
+ VectorMA( dir, deg, right, dir );
+
+ VectorNormalize( dir );
+
+ switch ( ent->s.weapon ) {
+ case WP_GRENADE_LAUNCHER:
+ fire_grenade( ent, ent->s.origin, dir );
+ break;
+ case WP_ROCKET_LAUNCHER:
+ fire_rocket( ent, ent->s.origin, dir );
+ break;
+ case WP_PLASMAGUN:
+ fire_plasma( ent, ent->s.origin, dir );
+ break;
+ }
+
+ G_AddEvent( ent, EV_FIRE_WEAPON, 0 );
+}
+
+
+static void InitShooter_Finish( gentity_t *ent ) {
+ ent->enemy = G_PickTarget( ent->target );
+ ent->think = 0;
+ ent->nextthink = 0;
+}
+
+void InitShooter( gentity_t *ent, int weapon ) {
+ ent->use = Use_Shooter;
+ ent->s.weapon = weapon;
+
+ RegisterItem( BG_FindItemForWeapon( weapon ) );
+
+ G_SetMovedir( ent->s.angles, ent->movedir );
+
+ if ( !ent->random ) {
+ ent->random = 1.0;
+ }
+ ent->random = sin( M_PI * ent->random / 180 );
+ // target might be a moving object, so we can't set movedir for it
+ if ( ent->target ) {
+ ent->think = InitShooter_Finish;
+ ent->nextthink = level.time + 500;
+ }
+ trap_LinkEntity( ent );
+}
+
+/*QUAKED shooter_rocket (1 0 0) (-16 -16 -16) (16 16 16)
+Fires at either the target or the current direction.
+"random" the number of degrees of deviance from the taget. (1.0 default)
+*/
+void SP_shooter_rocket( gentity_t *ent ) {
+ InitShooter( ent, WP_ROCKET_LAUNCHER );
+}
+
+/*QUAKED shooter_plasma (1 0 0) (-16 -16 -16) (16 16 16)
+Fires at either the target or the current direction.
+"random" is the number of degrees of deviance from the taget. (1.0 default)
+*/
+void SP_shooter_plasma( gentity_t *ent ) {
+ InitShooter( ent, WP_PLASMAGUN);
+}
+
+/*QUAKED shooter_grenade (1 0 0) (-16 -16 -16) (16 16 16)
+Fires at either the target or the current direction.
+"random" is the number of degrees of deviance from the taget. (1.0 default)
+*/
+void SP_shooter_grenade( gentity_t *ent ) {
+ InitShooter( ent, WP_GRENADE_LAUNCHER);
+}
+
+static void PortalDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod) {
+ G_FreeEntity( self );
+ //FIXME do something more interesting
+}
+
+
+void DropPortalDestination( gentity_t *player ) {
+ gentity_t *ent;
+ vec3_t snapped;
+
+ // create the portal destination
+ ent = G_Spawn();
+ ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_exit.md3" );
+
+ VectorCopy( player->s.pos.trBase, snapped );
+ SnapVector( snapped );
+ G_SetOrigin( ent, snapped );
+ VectorCopy( player->r.mins, ent->r.mins );
+ VectorCopy( player->r.maxs, ent->r.maxs );
+
+ ent->classname = "hi_portal destination";
+ ent->s.pos.trType = TR_STATIONARY;
+
+ ent->r.contents = CONTENTS_CORPSE;
+ ent->takedamage = qtrue;
+ ent->health = 200;
+ ent->die = PortalDie;
+
+ VectorCopy( player->s.apos.trBase, ent->s.angles );
+
+ ent->think = G_FreeEntity;
+ ent->nextthink = level.time + 2 * 60 * 1000;
+
+ trap_LinkEntity( ent );
+
+ player->client->portalID = ++level.portalSequence;
+ ent->count = player->client->portalID;
+
+ // give the item back so they can drop the source now
+ player->client->ps.stats[STAT_HOLDABLE_ITEM] = BG_FindItem( "Portal" ) - bg_itemlist;
+}
+
+
+static void PortalTouch( gentity_t *self, gentity_t *other, trace_t *trace) {
+ gentity_t *destination;
+
+ // see if we will even let other try to use it
+ if( other->health <= 0 ) {
+ return;
+ }
+ if( !other->client ) {
+ return;
+ }
+// if( other->client->ps.persistant[PERS_TEAM] != self->spawnflags ) {
+// return;
+// }
+
+ if ( other->client->ps.powerups[PW_NEUTRALFLAG] ) { // only happens in One Flag CTF
+ Drop_Item( other, BG_FindItemForPowerup( PW_NEUTRALFLAG ), 0 );
+ other->client->ps.powerups[PW_NEUTRALFLAG] = 0;
+ }
+ else if ( other->client->ps.powerups[PW_REDFLAG] ) { // only happens in standard CTF
+ Drop_Item( other, BG_FindItemForPowerup( PW_REDFLAG ), 0 );
+ other->client->ps.powerups[PW_REDFLAG] = 0;
+ }
+ else if ( other->client->ps.powerups[PW_BLUEFLAG] ) { // only happens in standard CTF
+ Drop_Item( other, BG_FindItemForPowerup( PW_BLUEFLAG ), 0 );
+ other->client->ps.powerups[PW_BLUEFLAG] = 0;
+ }
+
+ // find the destination
+ destination = NULL;
+ while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
+ if( destination->count == self->count ) {
+ break;
+ }
+ }
+
+ // if there is not one, die!
+ if( !destination ) {
+ if( self->pos1[0] || self->pos1[1] || self->pos1[2] ) {
+ TeleportPlayer( other, self->pos1, self->s.angles );
+ }
+ G_Damage( other, other, other, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG );
+ return;
+ }
+
+ TeleportPlayer( other, destination->s.pos.trBase, destination->s.angles );
+}
+
+
+static void PortalEnable( gentity_t *self ) {
+ self->touch = PortalTouch;
+ self->think = G_FreeEntity;
+ self->nextthink = level.time + 2 * 60 * 1000;
+}
+
+
+void DropPortalSource( gentity_t *player ) {
+ gentity_t *ent;
+ gentity_t *destination;
+ vec3_t snapped;
+
+ // create the portal source
+ ent = G_Spawn();
+ ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_enter.md3" );
+
+ VectorCopy( player->s.pos.trBase, snapped );
+ SnapVector( snapped );
+ G_SetOrigin( ent, snapped );
+ VectorCopy( player->r.mins, ent->r.mins );
+ VectorCopy( player->r.maxs, ent->r.maxs );
+
+ ent->classname = "hi_portal source";
+ ent->s.pos.trType = TR_STATIONARY;
+
+ ent->r.contents = CONTENTS_CORPSE | CONTENTS_TRIGGER;
+ ent->takedamage = qtrue;
+ ent->health = 200;
+ ent->die = PortalDie;
+
+ trap_LinkEntity( ent );
+
+ ent->count = player->client->portalID;
+ player->client->portalID = 0;
+
+// ent->spawnflags = player->client->ps.persistant[PERS_TEAM];
+
+ ent->nextthink = level.time + 1000;
+ ent->think = PortalEnable;
+
+ // find the destination
+ destination = NULL;
+ while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
+ if( destination->count == ent->count ) {
+ VectorCopy( destination->s.pos.trBase, ent->pos1 );
+ break;
+ }
+ }
+
+}
diff --git a/code/game/g_missile.c b/code/game/g_missile.c
new file mode 100644
index 0000000..fcd7a4c
--- /dev/null
+++ b/code/game/g_missile.c
@@ -0,0 +1,893 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#include "g_local.h"
+
+#define MISSILE_PRESTEP_TIME 50
+
+/*
+================
+G_BounceMissile
+
+================
+*/
+void G_BounceMissile( gentity_t *ent, trace_t *trace ) {
+ vec3_t velocity;
+ float dot;
+ int hitTime;
+
+ // reflect the velocity on the trace plane
+ hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
+ BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
+ dot = DotProduct( velocity, trace->plane.normal );
+ VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );
+
+ if ( ent->s.eFlags & EF_BOUNCE_HALF ) {
+ VectorScale( ent->s.pos.trDelta, 0.65, ent->s.pos.trDelta );
+ // check for stop
+ if ( trace->plane.normal[2] > 0.2 && VectorLength( ent->s.pos.trDelta ) < 40 ) {
+ G_SetOrigin( ent, trace->endpos );
+ ent->s.time = level.time / 4;
+ return;
+ }
+ }
+
+ VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
+ VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
+ ent->s.pos.trTime = level.time;
+}
+
+
+/*
+================
+G_ExplodeMissile
+
+Explode a missile without an impact
+================
+*/
+void G_ExplodeMissile( gentity_t *ent ) {
+ vec3_t dir;
+ vec3_t origin;
+
+ BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
+ SnapVector( origin );
+ G_SetOrigin( ent, origin );
+
+ // we don't have a valid direction, so just point straight up
+ dir[0] = dir[1] = 0;
+ dir[2] = 1;
+
+ ent->s.eType = ET_GENERAL;
+ G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );
+
+ ent->freeAfterEvent = qtrue;
+
+ // splash damage
+ if ( ent->splashDamage ) {
+ if( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent
+ , ent->splashMethodOfDeath ) ) {
+ g_entities[ent->r.ownerNum].client->accuracy_hits++;
+ g_entities[ent->r.ownerNum].client->accuracy[ent->s.weapon][1]++;
+ }
+ }
+
+ trap_LinkEntity( ent );
+}
+
+/*
+================
+ProximityMine_Explode
+================
+*/
+static void ProximityMine_Explode( gentity_t *mine ) {
+ G_ExplodeMissile( mine );
+ // if the prox mine has a trigger free it
+ if (mine->activator) {
+ G_FreeEntity(mine->activator);
+ mine->activator = NULL;
+ }
+}
+
+/*
+================
+ProximityMine_Die
+================
+*/
+static void ProximityMine_Die( gentity_t *ent, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) {
+ ent->think = ProximityMine_Explode;
+ ent->nextthink = level.time + 1;
+}
+
+/*
+================
+ProximityMine_Trigger
+================
+*/
+void ProximityMine_Trigger( gentity_t *trigger, gentity_t *other, trace_t *trace ) {
+ vec3_t v;
+ gentity_t *mine;
+
+ if( !other->client ) {
+ return;
+ }
+
+ // trigger is a cube, do a distance test now to act as if it's a sphere
+ VectorSubtract( trigger->s.pos.trBase, other->s.pos.trBase, v );
+ if( VectorLength( v ) > trigger->parent->splashRadius ) {
+ return;
+ }
+
+
+ if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
+ // don't trigger same team mines
+ if (trigger->parent->s.generic1 == other->client->sess.sessionTeam) {
+ return;
+ }
+ }
+
+ // ok, now check for ability to damage so we don't get triggered thru walls, closed doors, etc...
+ if( !CanDamage( other, trigger->s.pos.trBase ) ) {
+ return;
+ }
+
+ // trigger the mine!
+ mine = trigger->parent;
+ mine->s.loopSound = 0;
+ G_AddEvent( mine, EV_PROXIMITY_MINE_TRIGGER, 0 );
+ mine->nextthink = level.time + 500;
+
+ G_FreeEntity( trigger );
+}
+
+/*
+================
+ProximityMine_Activate
+================
+*/
+static void ProximityMine_Activate( gentity_t *ent ) {
+ gentity_t *trigger;
+ float r;
+ vec3_t v1;
+ gentity_t *flag;
+ char *c;
+ qboolean nearFlag = qfalse;
+
+ // find the flag
+ switch (ent->s.generic1) {
+ case TEAM_RED:
+ c = "team_CTF_redflag";
+ break;
+ case TEAM_BLUE:
+ c = "team_CTF_blueflag";
+ break;
+ default:
+ c = NULL;
+ }
+
+ if(c) {
+ flag = NULL;
+ while ((flag = G_Find (flag, FOFS(classname), c)) != NULL) {
+ if (!(flag->flags & FL_DROPPED_ITEM))
+ break;
+ }
+
+ if(flag) {
+ VectorSubtract(ent->r.currentOrigin,flag->r.currentOrigin , v1);
+ if(VectorLength(v1) < 500)
+ nearFlag = qtrue;
+ }
+ }
+
+ ent->think = ProximityMine_Explode;
+ if( nearFlag)
+ ent->nextthink = level.time + g_proxMineTimeout.integer/15;
+ else
+ ent->nextthink = level.time + g_proxMineTimeout.integer;
+
+ ent->takedamage = qtrue;
+ ent->health = 1;
+ ent->die = ProximityMine_Die;
+
+ ent->s.loopSound = G_SoundIndex( "sound/weapons/proxmine/wstbtick.wav" );
+
+ // build the proximity trigger
+ trigger = G_Spawn ();
+
+ trigger->classname = "proxmine_trigger";
+
+ r = ent->splashRadius;
+ VectorSet( trigger->r.mins, -r, -r, -r );
+ VectorSet( trigger->r.maxs, r, r, r );
+
+ G_SetOrigin( trigger, ent->s.pos.trBase );
+
+ trigger->parent = ent;
+ trigger->r.contents = CONTENTS_TRIGGER;
+ trigger->touch = ProximityMine_Trigger;
+
+ trap_LinkEntity (trigger);
+
+ // set pointer to trigger so the entity can be freed when the mine explodes
+ ent->activator = trigger;
+}
+
+/*
+================
+ProximityMine_ExplodeOnPlayer
+================
+*/
+static void ProximityMine_ExplodeOnPlayer( gentity_t *mine ) {
+ gentity_t *player;
+
+ player = mine->enemy;
+ player->client->ps.eFlags &= ~EF_TICKING;
+
+ if ( player->client->invulnerabilityTime > level.time ) {
+ G_Damage( player, mine->parent, mine->parent, vec3_origin, mine->s.origin, 1000, DAMAGE_NO_KNOCKBACK, MOD_JUICED );
+ player->client->invulnerabilityTime = 0;
+ G_TempEntity( player->client->ps.origin, EV_JUICED );
+ }
+ else {
+ G_SetOrigin( mine, player->s.pos.trBase );
+ // make sure the explosion gets to the client
+ mine->r.svFlags &= ~SVF_NOCLIENT;
+ mine->splashMethodOfDeath = MOD_PROXIMITY_MINE;
+ G_ExplodeMissile( mine );
+ }
+}
+
+/*
+================
+ProximityMine_Player
+================
+*/
+static void ProximityMine_Player( gentity_t *mine, gentity_t *player ) {
+ if( mine->s.eFlags & EF_NODRAW ) {
+ return;
+ }
+
+ G_AddEvent( mine, EV_PROXIMITY_MINE_STICK, 0 );
+
+ if( player->s.eFlags & EF_TICKING ) {
+ player->activator->splashDamage += mine->splashDamage;
+ player->activator->splashRadius *= 1.50;
+ mine->think = G_FreeEntity;
+ mine->nextthink = level.time;
+ return;
+ }
+
+ player->client->ps.eFlags |= EF_TICKING;
+ player->activator = mine;
+
+ mine->s.eFlags |= EF_NODRAW;
+ mine->r.svFlags |= SVF_NOCLIENT;
+ mine->s.pos.trType = TR_LINEAR;
+ VectorClear( mine->s.pos.trDelta );
+
+ mine->enemy = player;
+ mine->think = ProximityMine_ExplodeOnPlayer;
+ if ( player->client->invulnerabilityTime > level.time ) {
+ mine->nextthink = level.time + 2 * 1000;
+ }
+ else {
+ mine->nextthink = level.time + 10 * 1000;
+ }
+}
+
+/*
+ *=================
+ *ProximityMine_RemoveAll
+ *=================
+ */
+
+void ProximityMine_RemoveAll() {
+ gentity_t *mine;
+
+ mine = NULL;
+
+ while ((mine = G_Find (mine, FOFS(classname), "prox mine")) != NULL) {
+ mine->think = ProximityMine_Explode;
+ mine->nextthink = level.time + 1;
+ }
+}
+
+/*
+================
+G_MissileImpact
+================
+*/
+void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
+ gentity_t *other;
+ qboolean hitClient = qfalse;
+ vec3_t forward, impactpoint, bouncedir;
+ int eFlags;
+ other = &g_entities[trace->entityNum];
+
+ // check for bounce
+ if ( !other->takedamage &&
+ ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) ) {
+ G_BounceMissile( ent, trace );
+ G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
+ return;
+ }
+
+ if ( other->takedamage ) {
+ if ( ent->s.weapon != WP_PROX_LAUNCHER ) {
+ if ( other->client && other->client->invulnerabilityTime > level.time ) {
+
+ //
+ VectorCopy( ent->s.pos.trDelta, forward );
+ VectorNormalize( forward );
+ if (G_InvulnerabilityEffect( other, forward, ent->s.pos.trBase, impactpoint, bouncedir )) {
+ VectorCopy( bouncedir, trace->plane.normal );
+ eFlags = ent->s.eFlags & EF_BOUNCE_HALF;
+ ent->s.eFlags &= ~EF_BOUNCE_HALF;
+ G_BounceMissile( ent, trace );
+ ent->s.eFlags |= eFlags;
+ }
+ ent->target_ent = other;
+ return;
+ }
+ }
+ }
+ // impact damage
+ if (other->takedamage) {
+ // FIXME: wrong damage direction?
+ if ( ent->damage ) {
+ vec3_t velocity;
+
+ if( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) {
+ g_entities[ent->r.ownerNum].client->accuracy_hits++;
+ hitClient = qtrue;
+ g_entities[ent->r.ownerNum].client->accuracy[ent->s.weapon][1]++;
+ }
+ BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
+ if ( VectorLength( velocity ) == 0 ) {
+ velocity[2] = 1; // stepped on a grenade
+ }
+ G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
+ ent->s.origin, ent->damage,
+ 0, ent->methodOfDeath);
+ }
+ }
+
+ if( ent->s.weapon == WP_PROX_LAUNCHER ) {
+ if( ent->s.pos.trType != TR_GRAVITY ) {
+ return;
+ }
+
+ // if it's a player, stick it on to them (flag them and remove this entity)
+ if( other->s.eType == ET_PLAYER && other->health > 0 ) {
+ ProximityMine_Player( ent, other );
+ return;
+ }
+
+ SnapVectorTowards( trace->endpos, ent->s.pos.trBase );
+ G_SetOrigin( ent, trace->endpos );
+ ent->s.pos.trType = TR_STATIONARY;
+ VectorClear( ent->s.pos.trDelta );
+
+ G_AddEvent( ent, EV_PROXIMITY_MINE_STICK, trace->surfaceFlags );
+
+ ent->think = ProximityMine_Activate;
+ ent->nextthink = level.time + 2000;
+
+ vectoangles( trace->plane.normal, ent->s.angles );
+ ent->s.angles[0] += 90;
+
+ // link the prox mine to the other entity
+ ent->enemy = other;
+ ent->die = ProximityMine_Die;
+ VectorCopy(trace->plane.normal, ent->movedir);
+ VectorSet(ent->r.mins, -4, -4, -4);
+ VectorSet(ent->r.maxs, 4, 4, 4);
+ trap_LinkEntity(ent);
+
+ return;
+ }
+
+ if (!strcmp(ent->classname, "hook")) {
+ gentity_t *nent;
+ vec3_t v;
+
+ nent = G_Spawn();
+ if ( other->takedamage && other->client ) {
+
+ G_AddEvent( nent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
+ nent->s.otherEntityNum = other->s.number;
+
+ ent->enemy = other;
+
+ v[0] = other->r.currentOrigin[0] + (other->r.mins[0] + other->r.maxs[0]) * 0.5;
+ v[1] = other->r.currentOrigin[1] + (other->r.mins[1] + other->r.maxs[1]) * 0.5;
+ v[2] = other->r.currentOrigin[2] + (other->r.mins[2] + other->r.maxs[2]) * 0.5;
+
+ SnapVectorTowards( v, ent->s.pos.trBase ); // save net bandwidth
+ } else {
+ VectorCopy(trace->endpos, v);
+ G_AddEvent( nent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
+ ent->enemy = NULL;
+ }
+
+ SnapVectorTowards( v, ent->s.pos.trBase ); // save net bandwidth
+
+ nent->freeAfterEvent = qtrue;
+ // change over to a normal entity right at the point of impact
+ nent->s.eType = ET_GENERAL;
+ ent->s.eType = ET_GRAPPLE;
+
+ G_SetOrigin( ent, v );
+ G_SetOrigin( nent, v );
+
+ ent->think = Weapon_HookThink;
+ ent->nextthink = level.time + FRAMETIME;
+
+ ent->parent->client->ps.pm_flags |= PMF_GRAPPLE_PULL;
+ VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);
+
+ trap_LinkEntity( ent );
+ trap_LinkEntity( nent );
+
+ return;
+ }
+
+ // is it cheaper in bandwidth to just remove this ent and create a new
+ // one, rather than changing the missile into the explosion?
+
+ if ( other->takedamage && other->client ) {
+ G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
+ ent->s.otherEntityNum = other->s.number;
+ } else if( trace->surfaceFlags & SURF_METALSTEPS ) {
+ G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
+ } else {
+ G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
+ }
+
+ ent->freeAfterEvent = qtrue;
+
+ // change over to a normal entity right at the point of impact
+ ent->s.eType = ET_GENERAL;
+
+ SnapVectorTowards( trace->endpos, ent->s.pos.trBase ); // save net bandwidth
+
+ G_SetOrigin( ent, trace->endpos );
+
+ // splash damage (doesn't apply to person directly hit)
+ if ( ent->splashDamage ) {
+ if( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
+ other, ent->splashMethodOfDeath ) ) {
+ if( !hitClient ) {
+ g_entities[ent->r.ownerNum].client->accuracy_hits++;
+ g_entities[ent->r.ownerNum].client->accuracy[ent->s.weapon][1]++;
+ }
+ }
+ }
+
+ trap_LinkEntity( ent );
+}
+
+/*
+================
+G_RunMissile
+================
+*/
+void G_RunMissile( gentity_t *ent ) {
+ vec3_t origin;
+ trace_t tr;
+ int passent;
+
+ // get current position
+ BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
+
+ // if this missile bounced off an invulnerability sphere
+ if ( ent->target_ent ) {
+ passent = ent->target_ent->s.number;
+ }
+ // prox mines that left the owner bbox will attach to anything, even the owner
+ else if (ent->s.weapon == WP_PROX_LAUNCHER && ent->count) {
+ passent = ENTITYNUM_NONE;
+ }
+ else {
+ // ignore interactions with the missile owner
+ passent = ent->r.ownerNum;
+ }
+ // trace a line from the previous position to the current position
+ trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );
+
+ if ( tr.startsolid || tr.allsolid ) {
+ // make sure the tr.entityNum is set to the entity we're stuck in
+ trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask );
+ tr.fraction = 0;
+ }
+ else {
+ VectorCopy( tr.endpos, ent->r.currentOrigin );
+ }
+
+ trap_LinkEntity( ent );
+
+ if ( tr.fraction != 1 ) {
+ // never explode or bounce on sky
+ if ( tr.surfaceFlags & SURF_NOIMPACT ) {
+ // If grapple, reset owner
+ if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {
+ ent->parent->client->hook = NULL;
+ }
+ G_FreeEntity( ent );
+ return;
+ }
+ G_MissileImpact( ent, &tr );
+ if ( ent->s.eType != ET_MISSILE ) {
+ return; // exploded
+ }
+ }
+ // if the prox mine wasn't yet outside the player body
+ if (ent->s.weapon == WP_PROX_LAUNCHER && !ent->count) {
+ // check if the prox mine is outside the owner bbox
+ trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, ENTITYNUM_NONE, ent->clipmask );
+ if (!tr.startsolid || tr.entityNum != ent->r.ownerNum) {
+ ent->count = 1;
+ }
+ }
+ // check think function after bouncing
+ G_RunThink( ent );
+}
+
+
+//=============================================================================
+
+/*
+=================
+fire_plasma
+
+=================
+*/
+gentity_t *fire_plasma (gentity_t *self, vec3_t start, vec3_t dir) {
+ gentity_t *bolt;
+
+ VectorNormalize (dir);
+
+ bolt = G_Spawn();
+ bolt->classname = "plasma";
+ bolt->nextthink = level.time + 10000;
+ bolt->think = G_ExplodeMissile;
+ bolt->s.eType = ET_MISSILE;
+ bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
+ bolt->s.weapon = WP_PLASMAGUN;
+ bolt->r.ownerNum = self->s.number;
+//unlagged - projectile nudge
+ // we'll need this for nudging projectiles later
+ bolt->s.otherEntityNum = self->s.number;
+//unlagged - projectile nudge
+ bolt->parent = self;
+ bolt->damage = 20;
+ bolt->splashDamage = 15;
+ bolt->splashRadius = 20;
+ bolt->methodOfDeath = MOD_PLASMA;
+ bolt->splashMethodOfDeath = MOD_PLASMA_SPLASH;
+ bolt->clipmask = MASK_SHOT;
+ bolt->target_ent = NULL;
+
+ bolt->s.pos.trType = TR_LINEAR;
+ bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
+ VectorCopy( start, bolt->s.pos.trBase );
+ VectorScale( dir, 2000, bolt->s.pos.trDelta );
+ SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
+
+ VectorCopy (start, bolt->r.currentOrigin);
+
+ return bolt;
+}
+
+//=============================================================================
+
+
+/*
+=================
+fire_grenade
+=================
+*/
+gentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t dir) {
+ gentity_t *bolt;
+
+ VectorNormalize (dir);
+
+ bolt = G_Spawn();
+ bolt->classname = "grenade";
+ bolt->nextthink = level.time + 2500;
+ bolt->think = G_ExplodeMissile;
+ bolt->s.eType = ET_MISSILE;
+ bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
+ bolt->s.weapon = WP_GRENADE_LAUNCHER;
+ bolt->s.eFlags = EF_BOUNCE_HALF;
+ bolt->r.ownerNum = self->s.number;
+//unlagged - projectile nudge
+ // we'll need this for nudging projectiles later
+ bolt->s.otherEntityNum = self->s.number;
+//unlagged - projectile nudge
+ bolt->parent = self;
+ bolt->damage = 100;
+ bolt->splashDamage = 100;
+ bolt->splashRadius = 150;
+ bolt->methodOfDeath = MOD_GRENADE;
+ bolt->splashMethodOfDeath = MOD_GRENADE_SPLASH;
+ bolt->clipmask = MASK_SHOT;
+ bolt->target_ent = NULL;
+
+ bolt->s.pos.trType = TR_GRAVITY;
+ bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
+ VectorCopy( start, bolt->s.pos.trBase );
+ VectorScale( dir, 700, bolt->s.pos.trDelta );
+ SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
+
+ VectorCopy (start, bolt->r.currentOrigin);
+
+ return bolt;
+}
+
+//=============================================================================
+
+
+/*
+=================
+fire_bfg
+=================
+*/
+gentity_t *fire_bfg (gentity_t *self, vec3_t start, vec3_t dir) {
+ gentity_t *bolt;
+
+ VectorNormalize (dir);
+
+ bolt = G_Spawn();
+ bolt->classname = "bfg";
+ bolt->nextthink = level.time + 10000;
+ bolt->think = G_ExplodeMissile;
+ bolt->s.eType = ET_MISSILE;
+ bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
+ bolt->s.weapon = WP_BFG;
+ bolt->r.ownerNum = self->s.number;
+//unlagged - projectile nudge
+ // we'll need this for nudging projectiles later
+ bolt->s.otherEntityNum = self->s.number;
+//unlagged - projectile nudge
+ bolt->parent = self;
+ bolt->damage = 100;
+ bolt->splashDamage = 100;
+ bolt->splashRadius = 120;
+ bolt->methodOfDeath = MOD_BFG;
+ bolt->splashMethodOfDeath = MOD_BFG_SPLASH;
+ bolt->clipmask = MASK_SHOT;
+ bolt->target_ent = NULL;
+
+ bolt->s.pos.trType = TR_LINEAR;
+ bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
+ VectorCopy( start, bolt->s.pos.trBase );
+ VectorScale( dir, 2000, bolt->s.pos.trDelta );
+ SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
+ VectorCopy (start, bolt->r.currentOrigin);
+
+ return bolt;
+}
+
+//=============================================================================
+
+
+/*
+=================
+fire_rocket
+=================
+*/
+gentity_t *fire_rocket (gentity_t *self, vec3_t start, vec3_t dir) {
+ gentity_t *bolt;
+
+ VectorNormalize (dir);
+
+ bolt = G_Spawn();
+ bolt->classname = "rocket";
+ bolt->nextthink = level.time + 15000;
+ bolt->think = G_ExplodeMissile;
+ bolt->s.eType = ET_MISSILE;
+ bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
+ bolt->s.weapon = WP_ROCKET_LAUNCHER;
+ bolt->r.ownerNum = self->s.number;
+//unlagged - projectile nudge
+ // we'll need this for nudging projectiles later
+ bolt->s.otherEntityNum = self->s.number;
+//unlagged - projectile nudge
+ bolt->parent = self;
+ bolt->damage = 100;
+ bolt->splashDamage = 100;
+ bolt->splashRadius = 120;
+ bolt->methodOfDeath = MOD_ROCKET;
+ bolt->splashMethodOfDeath = MOD_ROCKET_SPLASH;
+ bolt->clipmask = MASK_SHOT;
+ bolt->target_ent = NULL;
+
+ bolt->s.pos.trType = TR_LINEAR;
+ bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
+ VectorCopy( start, bolt->s.pos.trBase );
+ VectorScale( dir, 900, bolt->s.pos.trDelta );
+ SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
+ VectorCopy (start, bolt->r.currentOrigin);
+
+ return bolt;
+}
+
+/*
+=================
+fire_grapple
+=================
+*/
+gentity_t *fire_grapple (gentity_t *self, vec3_t start, vec3_t dir) {
+ gentity_t *hook;
+//unlagged - grapple
+ int hooktime;
+//unlagged - grapple
+
+ VectorNormalize (dir);
+
+ hook = G_Spawn();
+ hook->classname = "hook";
+ hook->nextthink = level.time + 10000;
+ hook->think = Weapon_HookFree;
+ hook->s.eType = ET_MISSILE;
+ hook->r.svFlags = SVF_USE_CURRENT_ORIGIN;
+ hook->s.weapon = WP_GRAPPLING_HOOK;
+ hook->r.ownerNum = self->s.number;
+ hook->methodOfDeath = MOD_GRAPPLE;
+ hook->clipmask = MASK_SHOT;
+ hook->parent = self;
+ hook->target_ent = NULL;
+
+//unlagged - grapple
+ // we might want this later
+ hook->s.otherEntityNum = self->s.number;
+
+ // setting the projectile base time back makes the hook's first
+ // step larger
+
+ if ( self->client ) {
+ hooktime = self->client->pers.cmd.serverTime + 50;
+ }
+ else {
+ hooktime = level.time - MISSILE_PRESTEP_TIME;
+ }
+
+ hook->s.pos.trTime = hooktime;
+//unlagged - grapple
+
+ hook->s.pos.trType = TR_LINEAR;
+//unlagged - grapple
+ //hook->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
+//unlagged - grapple
+ hook->s.otherEntityNum = self->s.number; // use to match beam in client
+ VectorCopy( start, hook->s.pos.trBase );
+ VectorScale( dir, 800, hook->s.pos.trDelta );
+ SnapVector( hook->s.pos.trDelta ); // save net bandwidth
+ VectorCopy (start, hook->r.currentOrigin);
+
+ self->client->hook = hook;
+
+ return hook;
+}
+
+/*
+=================
+fire_nail
+=================
+*/
+#define NAILGUN_SPREAD 500
+
+gentity_t *fire_nail( gentity_t *self, vec3_t start, vec3_t forward, vec3_t right, vec3_t up ) {
+ gentity_t *bolt;
+ vec3_t dir;
+ vec3_t end;
+ float r, u, scale;
+
+ bolt = G_Spawn();
+ bolt->classname = "nail";
+ bolt->nextthink = level.time + 10000;
+ bolt->think = G_ExplodeMissile;
+ bolt->s.eType = ET_MISSILE;
+ bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
+ bolt->s.weapon = WP_NAILGUN;
+ bolt->r.ownerNum = self->s.number;
+//unlagged - projectile nudge
+ // we'll need this for nudging projectiles later
+ bolt->s.otherEntityNum = self->s.number;
+//unlagged - projectile nudge
+ bolt->parent = self;
+ bolt->damage = 20;
+ bolt->methodOfDeath = MOD_NAIL;
+ bolt->clipmask = MASK_SHOT;
+ bolt->target_ent = NULL;
+
+ bolt->s.pos.trType = TR_LINEAR;
+ bolt->s.pos.trTime = level.time;
+ VectorCopy( start, bolt->s.pos.trBase );
+
+ r = random() * M_PI * 2.0f;
+ u = sin(r) * crandom() * NAILGUN_SPREAD * 16;
+ r = cos(r) * crandom() * NAILGUN_SPREAD * 16;
+ VectorMA( start, 8192 * 16, forward, end);
+ VectorMA (end, r, right, end);
+ VectorMA (end, u, up, end);
+ VectorSubtract( end, start, dir );
+ VectorNormalize( dir );
+
+ scale = 555 + random() * 1800;
+ VectorScale( dir, scale, bolt->s.pos.trDelta );
+ SnapVector( bolt->s.pos.trDelta );
+
+ VectorCopy( start, bolt->r.currentOrigin );
+
+ return bolt;
+}
+
+
+/*
+=================
+fire_prox
+=================
+*/
+gentity_t *fire_prox( gentity_t *self, vec3_t start, vec3_t dir ) {
+ gentity_t *bolt;
+
+ VectorNormalize (dir);
+
+ bolt = G_Spawn();
+ bolt->classname = "prox mine";
+ bolt->nextthink = level.time + 3000;
+ bolt->think = G_ExplodeMissile;
+ bolt->s.eType = ET_MISSILE;
+ bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
+ bolt->s.weapon = WP_PROX_LAUNCHER;
+ bolt->s.eFlags = 0;
+ bolt->r.ownerNum = self->s.number;
+//unlagged - projectile nudge
+ // we'll need this for nudging projectiles later
+ bolt->s.otherEntityNum = self->s.number;
+//unlagged - projectile nudge
+ bolt->parent = self;
+ bolt->damage = 0;
+ bolt->splashDamage = 100;
+ bolt->splashRadius = 150;
+ bolt->methodOfDeath = MOD_PROXIMITY_MINE;
+ bolt->splashMethodOfDeath = MOD_PROXIMITY_MINE;
+ bolt->clipmask = MASK_SHOT;
+ bolt->target_ent = NULL;
+ // count is used to check if the prox mine left the player bbox
+ // if count == 1 then the prox mine left the player bbox and can attack to it
+ bolt->count = 0;
+
+ //FIXME: we prolly wanna abuse another field
+ bolt->s.generic1 = self->client->sess.sessionTeam;
+
+ bolt->s.pos.trType = TR_GRAVITY;
+ bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
+ VectorCopy( start, bolt->s.pos.trBase );
+ VectorScale( dir, 700, bolt->s.pos.trDelta );
+ SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
+
+ VectorCopy (start, bolt->r.currentOrigin);
+
+ return bolt;
+}
diff --git a/code/game/g_mover.c b/code/game/g_mover.c
new file mode 100644
index 0000000..608a827
--- /dev/null
+++ b/code/game/g_mover.c
@@ -0,0 +1,1633 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+#include "g_local.h"
+
+
+
+/*
+===============================================================================
+
+PUSHMOVE
+
+===============================================================================
+*/
+
+void MatchTeam( gentity_t *teamLeader, int moverState, int time );
+
+typedef struct {
+ gentity_t *ent;
+ vec3_t origin;
+ vec3_t angles;
+ float deltayaw;
+} pushed_t;
+pushed_t pushed[MAX_GENTITIES], *pushed_p;
+
+
+/*
+============
+G_TestEntityPosition
+
+============
+*/
+gentity_t *G_TestEntityPosition( gentity_t *ent ) {
+ trace_t tr;
+ int mask;
+
+ if ( ent->clipmask ) {
+ mask = ent->clipmask;
+ } else {
+ mask = MASK_SOLID;
+ }
+ if ( ent->client ) {
+ trap_Trace( &tr, ent->client->ps.origin, ent->r.mins, ent->r.maxs, ent->client->ps.origin, ent->s.number, mask );
+ } else {
+ trap_Trace( &tr, ent->s.pos.trBase, ent->r.mins, ent->r.maxs, ent->s.pos.trBase, ent->s.number, mask );
+ }
+
+ if (tr.startsolid)
+ return &g_entities[ tr.entityNum ];
+
+ return NULL;
+}
+
+/*
+================
+G_CreateRotationMatrix
+================
+*/
+void G_CreateRotationMatrix(vec3_t angles, vec3_t matrix[3]) {
+ AngleVectors(angles, matrix[0], matrix[1], matrix[2]);
+ VectorInverse(matrix[1]);
+}
+
+/*
+================
+G_TransposeMatrix
+================
+*/
+void G_TransposeMatrix(vec3_t matrix[3], vec3_t transpose[3]) {
+ int i, j;
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++) {
+ transpose[i][j] = matrix[j][i];
+ }
+ }
+}
+
+/*
+================
+G_RotatePoint
+================
+*/
+void G_RotatePoint(vec3_t point, vec3_t matrix[3]) {
+ vec3_t tvec;
+
+ VectorCopy(point, tvec);
+ point[0] = DotProduct(matrix[0], tvec);
+ point[1] = DotProduct(matrix[1], tvec);
+ point[2] = DotProduct(matrix[2], tvec);
+}
+
+/*
+==================
+G_TryPushingEntity
+
+Returns qfalse if the move is blocked
+==================
+*/
+qboolean G_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, vec3_t amove ) {
+ vec3_t matrix[3], transpose[3];
+ vec3_t org, org2, move2;
+ gentity_t *block;
+
+ // EF_MOVER_STOP will just stop when contacting another entity
+ // instead of pushing it, but entities can still ride on top of it
+ if ( ( pusher->s.eFlags & EF_MOVER_STOP ) &&
+ check->s.groundEntityNum != pusher->s.number ) {
+ return qfalse;
+ }
+
+ // save off the old position
+ if (pushed_p > &pushed[MAX_GENTITIES]) {
+ G_Error( "pushed_p > &pushed[MAX_GENTITIES]" );
+ }
+ pushed_p->ent = check;
+ VectorCopy (check->s.pos.trBase, pushed_p->origin);
+ VectorCopy (check->s.apos.trBase, pushed_p->angles);
+ if ( check->client ) {
+ pushed_p->deltayaw = check->client->ps.delta_angles[YAW];
+ VectorCopy (check->client->ps.origin, pushed_p->origin);
+ }
+ pushed_p++;
+
+ // try moving the contacted entity
+ // figure movement due to the pusher's amove
+ G_CreateRotationMatrix( amove, transpose );
+ G_TransposeMatrix( transpose, matrix );
+ if ( check->client ) {
+ VectorSubtract (check->client->ps.origin, pusher->r.currentOrigin, org);
+ }
+ else {
+ VectorSubtract (check->s.pos.trBase, pusher->r.currentOrigin, org);
+ }
+ VectorCopy( org, org2 );
+ G_RotatePoint( org2, matrix );
+ VectorSubtract (org2, org, move2);
+ // add movement
+ VectorAdd (check->s.pos.trBase, move, check->s.pos.trBase);
+ VectorAdd (check->s.pos.trBase, move2, check->s.pos.trBase);
+ if ( check->client ) {
+ VectorAdd (check->client->ps.origin, move, check->client->ps.origin);
+ VectorAdd (check->client->ps.origin, move2, check->client->ps.origin);
+ // make sure the client's view rotates when on a rotating mover
+ check->client->ps.delta_angles[YAW] += ANGLE2SHORT(amove[YAW]);
+ }
+
+ // may have pushed them off an edge
+ if ( check->s.groundEntityNum != pusher->s.number ) {
+ check->s.groundEntityNum = -1;
+ }
+
+ block = G_TestEntityPosition( check );
+ if (!block) {
+ // pushed ok
+ if ( check->client ) {
+ VectorCopy( check->client->ps.origin, check->r.currentOrigin );
+ } else {
+ VectorCopy( check->s.pos.trBase, check->r.currentOrigin );
+ }
+ trap_LinkEntity (check);
+ return qtrue;
+ }
+
+ // if it is ok to leave in the old position, do it
+ // this is only relevent for riding entities, not pushed
+ // Sliding trapdoors can cause this.
+ VectorCopy( (pushed_p-1)->origin, check->s.pos.trBase);
+ if ( check->client ) {
+ VectorCopy( (pushed_p-1)->origin, check->client->ps.origin);
+ }
+ VectorCopy( (pushed_p-1)->angles, check->s.apos.trBase );
+ block = G_TestEntityPosition (check);
+ if ( !block ) {
+ check->s.groundEntityNum = -1;
+ pushed_p--;
+ return qtrue;
+ }
+
+ // blocked
+ return qfalse;
+}
+
+/*
+==================
+G_CheckProxMinePosition
+==================
+*/
+qboolean G_CheckProxMinePosition( gentity_t *check ) {
+ vec3_t start, end;
+ trace_t tr;
+
+ VectorMA(check->s.pos.trBase, 0.125, check->movedir, start);
+ VectorMA(check->s.pos.trBase, 2, check->movedir, end);
+ trap_Trace( &tr, start, NULL, NULL, end, check->s.number, MASK_SOLID );
+
+ if (tr.startsolid || tr.fraction < 1)
+ return qfalse;
+
+ return qtrue;
+}
+
+/*
+==================
+G_TryPushingProxMine
+==================
+*/
+qboolean G_TryPushingProxMine( gentity_t *check, gentity_t *pusher, vec3_t move, vec3_t amove ) {
+ vec3_t forward, right, up;
+ vec3_t org, org2, move2;
+ int ret;
+
+ // we need this for pushing things later
+ VectorSubtract (vec3_origin, amove, org);
+ AngleVectors (org, forward, right, up);
+
+ // try moving the contacted entity
+ VectorAdd (check->s.pos.trBase, move, check->s.pos.trBase);
+
+ // figure movement due to the pusher's amove
+ VectorSubtract (check->s.pos.trBase, pusher->r.currentOrigin, org);
+ org2[0] = DotProduct (org, forward);
+ org2[1] = -DotProduct (org, right);
+ org2[2] = DotProduct (org, up);
+ VectorSubtract (org2, org, move2);
+ VectorAdd (check->s.pos.trBase, move2, check->s.pos.trBase);
+
+ ret = G_CheckProxMinePosition( check );
+ if (ret) {
+ VectorCopy( check->s.pos.trBase, check->r.currentOrigin );
+ trap_LinkEntity (check);
+ }
+ return ret;
+}
+
+void G_ExplodeMissile( gentity_t *ent );
+
+/*
+============
+G_MoverPush
+
+Objects need to be moved back on a failed push,
+otherwise riders would continue to slide.
+If qfalse is returned, *obstacle will be the blocking entity
+============
+*/
+qboolean G_MoverPush( gentity_t *pusher, vec3_t move, vec3_t amove, gentity_t **obstacle ) {
+ int i, e;
+ gentity_t *check;
+ vec3_t mins, maxs;
+ pushed_t *p;
+ int entityList[MAX_GENTITIES];
+ int listedEntities;
+ vec3_t totalMins, totalMaxs;
+
+ *obstacle = NULL;
+
+
+ // mins/maxs are the bounds at the destination
+ // totalMins / totalMaxs are the bounds for the entire move
+ if ( pusher->r.currentAngles[0] || pusher->r.currentAngles[1] || pusher->r.currentAngles[2]
+ || amove[0] || amove[1] || amove[2] ) {
+ float radius;
+
+ radius = RadiusFromBounds( pusher->r.mins, pusher->r.maxs );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ mins[i] = pusher->r.currentOrigin[i] + move[i] - radius;
+ maxs[i] = pusher->r.currentOrigin[i] + move[i] + radius;
+ totalMins[i] = mins[i] - move[i];
+ totalMaxs[i] = maxs[i] - move[i];
+ }
+ } else {
+ for (i=0 ; i<3 ; i++) {
+ mins[i] = pusher->r.absmin[i] + move[i];
+ maxs[i] = pusher->r.absmax[i] + move[i];
+ }
+
+ VectorCopy( pusher->r.absmin, totalMins );
+ VectorCopy( pusher->r.absmax, totalMaxs );
+ for (i=0 ; i<3 ; i++) {
+ if ( move[i] > 0 ) {
+ totalMaxs[i] += move[i];
+ } else {
+ totalMins[i] += move[i];
+ }
+ }
+ }
+
+ // unlink the pusher so we don't get it in the entityList
+ trap_UnlinkEntity( pusher );
+
+ listedEntities = trap_EntitiesInBox( totalMins, totalMaxs, entityList, MAX_GENTITIES );
+
+ // move the pusher to it's final position
+ VectorAdd( pusher->r.currentOrigin, move, pusher->r.currentOrigin );
+ VectorAdd( pusher->r.currentAngles, amove, pusher->r.currentAngles );
+ trap_LinkEntity( pusher );
+
+ // see if any solid entities are inside the final position
+ for ( e = 0 ; e < listedEntities ; e++ ) {
+ check = &g_entities[ entityList[ e ] ];
+
+ if ( check->s.eType == ET_MISSILE ) {
+ // if it is a prox mine
+ if ( !strcmp(check->classname, "prox mine") ) {
+ // if this prox mine is attached to this mover try to move it with the pusher
+ if ( check->enemy == pusher ) {
+ if (!G_TryPushingProxMine( check, pusher, move, amove )) {
+ //explode
+ check->s.loopSound = 0;
+ G_AddEvent( check, EV_PROXIMITY_MINE_TRIGGER, 0 );
+ G_ExplodeMissile(check);
+ if (check->activator) {
+ G_FreeEntity(check->activator);
+ check->activator = NULL;
+ }
+ //G_Printf("prox mine explodes\n");
+ }
+ }
+ else {
+ //check if the prox mine is crushed by the mover
+ if (!G_CheckProxMinePosition( check )) {
+ //explode
+ check->s.loopSound = 0;
+ G_AddEvent( check, EV_PROXIMITY_MINE_TRIGGER, 0 );
+ G_ExplodeMissile(check);
+ if (check->activator) {
+ G_FreeEntity(check->activator);
+ check->activator = NULL;
+ }
+ //G_Printf("prox mine explodes\n");
+ }
+ }
+ continue;
+ }
+ }
+ // only push items and players
+ if ( check->s.eType != ET_ITEM && check->s.eType != ET_PLAYER && !check->physicsObject ) {
+ continue;
+ }
+
+ // if the entity is standing on the pusher, it will definitely be moved
+ if ( check->s.groundEntityNum != pusher->s.number ) {
+ // see if the ent needs to be tested
+ if ( check->r.absmin[0] >= maxs[0]
+ || check->r.absmin[1] >= maxs[1]
+ || check->r.absmin[2] >= maxs[2]
+ || check->r.absmax[0] <= mins[0]
+ || check->r.absmax[1] <= mins[1]
+ || check->r.absmax[2] <= mins[2] ) {
+ continue;
+ }
+ // see if the ent's bbox is inside the pusher's final position
+ // this does allow a fast moving object to pass through a thin entity...
+ if (!G_TestEntityPosition (check)) {
+ continue;
+ }
+ }
+
+ // the entity needs to be pushed
+ if ( G_TryPushingEntity( check, pusher, move, amove ) ) {
+ continue;
+ }
+
+ // the move was blocked an entity
+
+ // bobbing entities are instant-kill and never get blocked
+ if ( pusher->s.pos.trType == TR_SINE || pusher->s.apos.trType == TR_SINE ) {
+ G_Damage( check, pusher, pusher, NULL, NULL, 99999, 0, MOD_CRUSH );
+ continue;
+ }
+
+
+ // save off the obstacle so we can call the block function (crush, etc)
+ *obstacle = check;
+
+ // move back any entities we already moved
+ // go backwards, so if the same entity was pushed
+ // twice, it goes back to the original position
+ for ( p=pushed_p-1 ; p>=pushed ; p-- ) {
+ VectorCopy (p->origin, p->ent->s.pos.trBase);
+ VectorCopy (p->angles, p->ent->s.apos.trBase);
+ if ( p->ent->client ) {
+ p->ent->client->ps.delta_angles[YAW] = p->deltayaw;
+ VectorCopy (p->origin, p->ent->client->ps.origin);
+ }
+ trap_LinkEntity (p->ent);
+ }
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+
+/*
+=================
+G_MoverTeam
+=================
+*/
+void G_MoverTeam( gentity_t *ent ) {
+ vec3_t move, amove;
+ gentity_t *part, *obstacle;
+ vec3_t origin, angles;
+
+ obstacle = NULL;
+
+ // make sure all team slaves can move before commiting
+ // any moves or calling any think functions
+ // if the move is blocked, all moved objects will be backed out
+ pushed_p = pushed;
+ for (part = ent ; part ; part=part->teamchain) {
+ // get current position
+ BG_EvaluateTrajectory( &part->s.pos, level.time, origin );
+ BG_EvaluateTrajectory( &part->s.apos, level.time, angles );
+ VectorSubtract( origin, part->r.currentOrigin, move );
+ VectorSubtract( angles, part->r.currentAngles, amove );
+ if ( !G_MoverPush( part, move, amove, &obstacle ) ) {
+ break; // move was blocked
+ }
+ }
+
+ if (part) {
+ // go back to the previous position
+ for ( part = ent ; part ; part = part->teamchain ) {
+ part->s.pos.trTime += level.time - level.previousTime;
+ part->s.apos.trTime += level.time - level.previousTime;
+ BG_EvaluateTrajectory( &part->s.pos, level.time, part->r.currentOrigin );
+ BG_EvaluateTrajectory( &part->s.apos, level.time, part->r.currentAngles );
+ trap_LinkEntity( part );
+ }
+
+ // if the pusher has a "blocked" function, call it
+ if (ent->blocked) {
+ ent->blocked( ent, obstacle );
+ }
+ return;
+ }
+
+ // the move succeeded
+ for ( part = ent ; part ; part = part->teamchain ) {
+ // call the reached function if time is at or past end point
+ if ( part->s.pos.trType == TR_LINEAR_STOP ) {
+ if ( level.time >= part->s.pos.trTime + part->s.pos.trDuration ) {
+ if ( part->reached ) {
+ part->reached( part );
+ }
+ }
+ }
+ }
+}
+
+/*
+================
+G_RunMover
+
+================
+*/
+void G_RunMover( gentity_t *ent ) {
+ // if not a team captain, don't do anything, because
+ // the captain will handle everything
+ if ( ent->flags & FL_TEAMSLAVE ) {
+ return;
+ }
+
+ // if stationary at one of the positions, don't move anything
+ if ( ent->s.pos.trType != TR_STATIONARY || ent->s.apos.trType != TR_STATIONARY ) {
+ G_MoverTeam( ent );
+ }
+
+ // check think function
+ G_RunThink( ent );
+}
+
+/*
+============================================================================
+
+GENERAL MOVERS
+
+Doors, plats, and buttons are all binary (two position) movers
+Pos1 is "at rest", pos2 is "activated"
+============================================================================
+*/
+
+/*
+===============
+SetMoverState
+===============
+*/
+void SetMoverState( gentity_t *ent, moverState_t moverState, int time ) {
+ vec3_t delta;
+ float f;
+
+ ent->moverState = moverState;
+
+ ent->s.pos.trTime = time;
+ switch( moverState ) {
+ case MOVER_POS1:
+ VectorCopy( ent->pos1, ent->s.pos.trBase );
+ ent->s.pos.trType = TR_STATIONARY;
+ break;
+ case MOVER_POS2:
+ VectorCopy( ent->pos2, ent->s.pos.trBase );
+ ent->s.pos.trType = TR_STATIONARY;
+ break;
+ case MOVER_1TO2:
+ VectorCopy( ent->pos1, ent->s.pos.trBase );
+ VectorSubtract( ent->pos2, ent->pos1, delta );
+ f = 1000.0 / ent->s.pos.trDuration;
+ VectorScale( delta, f, ent->s.pos.trDelta );
+ ent->s.pos.trType = TR_LINEAR_STOP;
+ break;
+ case MOVER_2TO1:
+ VectorCopy( ent->pos2, ent->s.pos.trBase );
+ VectorSubtract( ent->pos1, ent->pos2, delta );
+ f = 1000.0 / ent->s.pos.trDuration;
+ VectorScale( delta, f, ent->s.pos.trDelta );
+ ent->s.pos.trType = TR_LINEAR_STOP;
+ break;
+ }
+ BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin );
+ trap_LinkEntity( ent );
+}
+
+/*
+================
+MatchTeam
+
+All entities in a mover team will move from pos1 to pos2
+in the same amount of time
+================
+*/
+void MatchTeam( gentity_t *teamLeader, int moverState, int time ) {
+ gentity_t *slave;
+
+ for ( slave = teamLeader ; slave ; slave = slave->teamchain ) {
+ SetMoverState( slave, moverState, time );
+ }
+}
+
+
+
+/*
+================
+ReturnToPos1
+================
+*/
+void ReturnToPos1( gentity_t *ent ) {
+ MatchTeam( ent, MOVER_2TO1, level.time );
+
+ // looping sound
+ ent->s.loopSound = ent->soundLoop;
+
+ // starting sound
+ if ( ent->sound2to1 ) {
+ G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
+ }
+}
+
+
+/*
+================
+Reached_BinaryMover
+================
+*/
+void Reached_BinaryMover( gentity_t *ent ) {
+
+ // stop the looping sound
+ ent->s.loopSound = ent->soundLoop;
+
+ if ( ent->moverState == MOVER_1TO2 ) {
+ // reached pos2
+ SetMoverState( ent, MOVER_POS2, level.time );
+
+ // play sound
+ if ( ent->soundPos2 ) {
+ G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos2 );
+ }
+
+ // return to pos1 after a delay
+ ent->think = ReturnToPos1;
+ ent->nextthink = level.time + ent->wait;
+
+ // fire targets
+ if ( !ent->activator ) {
+ ent->activator = ent;
+ }
+ G_UseTargets( ent, ent->activator );
+ } else if ( ent->moverState == MOVER_2TO1 ) {
+ // reached pos1
+ SetMoverState( ent, MOVER_POS1, level.time );
+
+ // play sound
+ if ( ent->soundPos1 ) {
+ G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos1 );
+ }
+
+ // close areaportals
+ if ( ent->teammaster == ent || !ent->teammaster ) {
+ trap_AdjustAreaPortalState( ent, qfalse );
+ }
+ } else {
+ G_Error( "Reached_BinaryMover: bad moverState" );
+ }
+}
+
+
+/*
+================
+Use_BinaryMover
+================
+*/
+void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
+ int total;
+ int partial;
+
+ // only the master should be used
+ if ( ent->flags & FL_TEAMSLAVE ) {
+ Use_BinaryMover( ent->teammaster, other, activator );
+ return;
+ }
+
+ ent->activator = activator;
+
+ if ( ent->moverState == MOVER_POS1 ) {
+ // start moving 50 msec later, becase if this was player
+ // triggered, level.time hasn't been advanced yet
+ MatchTeam( ent, MOVER_1TO2, level.time + 50 );
+
+ // starting sound
+ if ( ent->sound1to2 ) {
+ G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );
+ }
+
+ // looping sound
+ ent->s.loopSound = ent->soundLoop;
+
+ // open areaportal
+ if ( ent->teammaster == ent || !ent->teammaster ) {
+ trap_AdjustAreaPortalState( ent, qtrue );
+ }
+ return;
+ }
+
+ // if all the way up, just delay before coming down
+ if ( ent->moverState == MOVER_POS2 ) {
+ ent->nextthink = level.time + ent->wait;
+ return;
+ }
+
+ // only partway down before reversing
+ if ( ent->moverState == MOVER_2TO1 ) {
+ total = ent->s.pos.trDuration;
+ partial = level.time - ent->s.pos.trTime;
+ if ( partial > total ) {
+ partial = total;
+ }
+
+ MatchTeam( ent, MOVER_1TO2, level.time - ( total - partial ) );
+
+ if ( ent->sound1to2 ) {
+ G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );
+ }
+ return;
+ }
+
+ // only partway up before reversing
+ if ( ent->moverState == MOVER_1TO2 ) {
+ total = ent->s.pos.trDuration;
+ partial = level.time - ent->s.pos.trTime;
+ if ( partial > total ) {
+ partial = total;
+ }
+
+ MatchTeam( ent, MOVER_2TO1, level.time - ( total - partial ) );
+
+ if ( ent->sound2to1 ) {
+ G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
+ }
+ return;
+ }
+}
+
+
+
+/*
+================
+InitMover
+
+"pos1", "pos2", and "speed" should be set before calling,
+so the movement delta can be calculated
+================
+*/
+void InitMover( gentity_t *ent ) {
+ vec3_t move;
+ float distance;
+ float light;
+ vec3_t color;
+ qboolean lightSet, colorSet;
+ char *sound;
+
+ // if the "model2" key is set, use a seperate model
+ // for drawing, but clip against the brushes
+ if ( ent->model2 ) {
+ ent->s.modelindex2 = G_ModelIndex( ent->model2 );
+ }
+
+ // if the "loopsound" key is set, use a constant looping sound when moving
+ if ( G_SpawnString( "noise", "100", &sound ) ) {
+ ent->s.loopSound = G_SoundIndex( sound );
+ }
+
+ // if the "color" or "light" keys are set, setup constantLight
+ lightSet = G_SpawnFloat( "light", "100", &light );
+ colorSet = G_SpawnVector( "color", "1 1 1", color );
+ if ( lightSet || colorSet ) {
+ int r, g, b, i;
+
+ r = color[0] * 255;
+ if ( r > 255 ) {
+ r = 255;
+ }
+ g = color[1] * 255;
+ if ( g > 255 ) {
+ g = 255;
+ }
+ b = color[2] * 255;
+ if ( b > 255 ) {
+ b = 255;
+ }
+ i = light / 4;
+ if ( i > 255 ) {
+ i = 255;
+ }
+ ent->s.constantLight = r | ( g << 8 ) | ( b << 16 ) | ( i << 24 );
+ }
+
+
+ ent->use = Use_BinaryMover;
+ ent->reached = Reached_BinaryMover;
+
+ ent->moverState = MOVER_POS1;
+ ent->r.svFlags = SVF_USE_CURRENT_ORIGIN;
+ ent->s.eType = ET_MOVER;
+ VectorCopy (ent->pos1, ent->r.currentOrigin);
+ trap_LinkEntity (ent);
+
+ ent->s.pos.trType = TR_STATIONARY;
+ VectorCopy( ent->pos1, ent->s.pos.trBase );
+
+ // calculate time to reach second position from speed
+ VectorSubtract( ent->pos2, ent->pos1, move );
+ distance = VectorLength( move );
+ if ( ! ent->speed ) {
+ ent->speed = 100;
+ }
+ VectorScale( move, ent->speed, ent->s.pos.trDelta );
+ ent->s.pos.trDuration = distance * 1000 / ent->speed;
+ if ( ent->s.pos.trDuration <= 0 ) {
+ ent->s.pos.trDuration = 1;
+ }
+}
+
+
+/*
+===============================================================================
+
+DOOR
+
+A use can be triggered either by a touch function, by being shot, or by being
+targeted by another entity.
+
+===============================================================================
+*/
+
+/*
+================
+Blocked_Door
+================
+*/
+void Blocked_Door( gentity_t *ent, gentity_t *other ) {
+ // remove anything other than a client
+ if ( !other->client ) {
+ // except CTF flags!!!!
+ if( other->s.eType == ET_ITEM && other->item->giType == IT_TEAM ) {
+ Team_DroppedFlagThink( other );
+ return;
+ }
+ G_TempEntity( other->s.origin, EV_ITEM_POP );
+ G_FreeEntity( other );
+ return;
+ }
+
+ if ( ent->damage ) {
+ if(g_awardpushing.integer)
+ G_Damage( other, ent, ent->activator, NULL, NULL, ent->damage, 0, MOD_CRUSH );
+ else
+ G_Damage( other, ent, ent, NULL, NULL, ent->damage, 0, MOD_CRUSH );
+
+ }
+ if ( ent->spawnflags & 4 ) {
+ return; // crushers don't reverse
+ }
+
+ // reverse direction
+ Use_BinaryMover( ent, ent, other );
+}
+
+/*
+================
+Touch_DoorTriggerSpectator
+================
+*/
+static void Touch_DoorTriggerSpectator( gentity_t *ent, gentity_t *other, trace_t *trace ) {
+ int axis;
+ float doorMin, doorMax;
+ vec3_t origin;
+
+ axis = ent->count;
+ // the constants below relate to constants in Think_SpawnNewDoorTrigger()
+ doorMin = ent->r.absmin[axis] + 100;
+ doorMax = ent->r.absmax[axis] - 100;
+
+ VectorCopy(other->client->ps.origin, origin);
+
+ if (origin[axis] < doorMin || origin[axis] > doorMax) return;
+
+ if (fabs(origin[axis] - doorMax) < fabs(origin[axis] - doorMin)) {
+ origin[axis] = doorMin - 10;
+ } else {
+ origin[axis] = doorMax + 10;
+ }
+
+ TeleportPlayer(other, origin, tv(10000000.0, 0, 0));
+}
+
+/*
+================
+Touch_DoorTrigger
+================
+*/
+void Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace ) {
+ if ( other->client && (other->client->sess.sessionTeam == TEAM_SPECTATOR || other->client->ps.pm_type == PM_SPECTATOR)) {
+ // if the door is not open and not opening
+ if ( ent->parent->moverState != MOVER_1TO2 &&
+ ent->parent->moverState != MOVER_POS2) {
+ Touch_DoorTriggerSpectator( ent, other, trace );
+ }
+ }
+ else if ( ent->parent->moverState != MOVER_1TO2 ) {
+ Use_BinaryMover( ent->parent, ent, other );
+ }
+}
+
+void Think_SpawnNewDoorTrigger( gentity_t *ent ) __attribute__((nonnull));
+/*
+======================
+Think_SpawnNewDoorTrigger
+
+All of the parts of a door have been spawned, so create
+a trigger that encloses all of them
+======================
+*/
+void Think_SpawnNewDoorTrigger( gentity_t *ent ) {
+ gentity_t *other;
+ vec3_t mins, maxs;
+ int i, best;
+
+ // set all of the slaves as shootable
+ for ( other = ent ; other ; other = other->teamchain ) {
+ other->takedamage = qtrue;
+ }
+
+ // find the bounds of everything on the team
+ VectorCopy (ent->r.absmin, mins);
+ VectorCopy (ent->r.absmax, maxs);
+
+ for (other = ent->teamchain ; other ; other=other->teamchain) {
+ AddPointToBounds (other->r.absmin, mins, maxs);
+ AddPointToBounds (other->r.absmax, mins, maxs);
+ }
+
+ // find the thinnest axis, which will be the one we expand
+ best = 0;
+ for ( i = 1 ; i < 3 ; i++ ) {
+ if ( maxs[i] - mins[i] < maxs[best] - mins[best] ) {
+ best = i;
+ }
+ }
+ maxs[best] += 120;
+ mins[best] -= 120;
+
+ // create a trigger with this size
+ other = G_Spawn ();
+ other->classname = "door_trigger";
+ VectorCopy (mins, other->r.mins);
+ VectorCopy (maxs, other->r.maxs);
+ other->parent = ent;
+ other->r.contents = CONTENTS_TRIGGER;
+ other->touch = Touch_DoorTrigger;
+ // remember the thinnest axis
+ other->count = best;
+ trap_LinkEntity (other);
+
+ MatchTeam( ent, ent->moverState, level.time );
+}
+
+void Think_MatchTeam( gentity_t *ent ) {
+ MatchTeam( ent, ent->moverState, level.time );
+}
+
+
+/*QUAKED func_door (0 .5 .8) ? START_OPEN x CRUSHER
+TOGGLE wait in both the start and end states for a trigger event.
+START_OPEN the door to moves to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
+NOMONSTER monsters will not trigger this door
+
+"model2" .md3 model to also draw
+"angle" determines the opening direction
+"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"speed" movement speed (100 default)
+"wait" wait before returning (3 default, -1 = never return)
+"lip" lip remaining at end of move (8 default)
+"dmg" damage to inflict when blocked (2 default)
+"color" constantLight color
+"light" constantLight radius
+"health" if set, the door must be shot open
+*/
+void SP_func_door (gentity_t *ent) {
+ vec3_t abs_movedir;
+ float distance;
+ vec3_t size;
+ float lip;
+
+ ent->sound1to2 = ent->sound2to1 = G_SoundIndex("sound/movers/doors/dr1_strt.wav");
+ ent->soundPos1 = ent->soundPos2 = G_SoundIndex("sound/movers/doors/dr1_end.wav");
+
+ ent->blocked = Blocked_Door;
+
+ // default speed of 400
+ if (!ent->speed)
+ ent->speed = 400;
+
+ // default wait of 2 seconds
+ if (!ent->wait)
+ ent->wait = 2;
+ ent->wait *= 1000;
+
+ // default lip of 8 units
+ G_SpawnFloat( "lip", "8", &lip );
+
+ // default damage of 2 points
+ G_SpawnInt( "dmg", "2", &ent->damage );
+
+ // first position at start
+ VectorCopy( ent->s.origin, ent->pos1 );
+
+ // calculate second position
+ trap_SetBrushModel( ent, ent->model );
+ G_SetMovedir (ent->s.angles, ent->movedir);
+ abs_movedir[0] = fabs(ent->movedir[0]);
+ abs_movedir[1] = fabs(ent->movedir[1]);
+ abs_movedir[2] = fabs(ent->movedir[2]);
+ VectorSubtract( ent->r.maxs, ent->r.mins, size );
+ distance = DotProduct( abs_movedir, size ) - lip;
+ VectorMA( ent->pos1, distance, ent->movedir, ent->pos2 );
+
+ // if "start_open", reverse position 1 and 2
+ if ( ent->spawnflags & 1 ) {
+ vec3_t temp;
+
+ VectorCopy( ent->pos2, temp );
+ VectorCopy( ent->s.origin, ent->pos2 );
+ VectorCopy( temp, ent->pos1 );
+ }
+
+ InitMover( ent );
+
+ ent->nextthink = level.time + FRAMETIME;
+
+ if ( ! (ent->flags & FL_TEAMSLAVE ) ) {
+ int health;
+
+ G_SpawnInt( "health", "0", &health );
+ if ( health ) {
+ ent->takedamage = qtrue;
+ }
+ if ( ent->targetname || health ) {
+ // non touch/shoot doors
+ ent->think = Think_MatchTeam;
+ } else {
+ ent->think = Think_SpawnNewDoorTrigger;
+ }
+ }
+
+
+}
+
+/*
+===============================================================================
+
+PLAT
+
+===============================================================================
+*/
+
+/*
+==============
+Touch_Plat
+
+Don't allow decent if a living player is on it
+===============
+*/
+void Touch_Plat( gentity_t *ent, gentity_t *other, trace_t *trace ) {
+ if ( !other->client || other->client->ps.stats[STAT_HEALTH] <= 0 ) {
+ return;
+ }
+
+ // delay return-to-pos1 by one second
+ if ( ent->moverState == MOVER_POS2 ) {
+ ent->nextthink = level.time + 1000;
+ }
+}
+
+/*
+==============
+Touch_PlatCenterTrigger
+
+If the plat is at the bottom position, start it going up
+===============
+*/
+void Touch_PlatCenterTrigger(gentity_t *ent, gentity_t *other, trace_t *trace ) {
+ if ( !other->client ) {
+ return;
+ }
+
+ if ( ent->parent->moverState == MOVER_POS1 ) {
+ Use_BinaryMover( ent->parent, ent, other );
+ }
+}
+
+
+/*
+================
+SpawnPlatTrigger
+
+Spawn a trigger in the middle of the plat's low position
+Elevator cars require that the trigger extend through the entire low position,
+not just sit on top of it.
+================
+*/
+void SpawnPlatTrigger( gentity_t *ent ) {
+ gentity_t *trigger;
+ vec3_t tmin, tmax;
+
+ // the middle trigger will be a thin trigger just
+ // above the starting position
+ trigger = G_Spawn();
+ trigger->classname = "plat_trigger";
+ trigger->touch = Touch_PlatCenterTrigger;
+ trigger->r.contents = CONTENTS_TRIGGER;
+ trigger->parent = ent;
+
+ tmin[0] = ent->pos1[0] + ent->r.mins[0] + 33;
+ tmin[1] = ent->pos1[1] + ent->r.mins[1] + 33;
+ tmin[2] = ent->pos1[2] + ent->r.mins[2];
+
+ tmax[0] = ent->pos1[0] + ent->r.maxs[0] - 33;
+ tmax[1] = ent->pos1[1] + ent->r.maxs[1] - 33;
+ tmax[2] = ent->pos1[2] + ent->r.maxs[2] + 8;
+
+ if ( tmax[0] <= tmin[0] ) {
+ tmin[0] = ent->pos1[0] + (ent->r.mins[0] + ent->r.maxs[0]) *0.5;
+ tmax[0] = tmin[0] + 1;
+ }
+ if ( tmax[1] <= tmin[1] ) {
+ tmin[1] = ent->pos1[1] + (ent->r.mins[1] + ent->r.maxs[1]) *0.5;
+ tmax[1] = tmin[1] + 1;
+ }
+
+ VectorCopy (tmin, trigger->r.mins);
+ VectorCopy (tmax, trigger->r.maxs);
+
+ trap_LinkEntity (trigger);
+}
+
+
+/*QUAKED func_plat (0 .5 .8) ?
+Plats are always drawn in the extended position so they will light correctly.
+
+"lip" default 8, protrusion above rest position
+"height" total height of movement, defaults to model height
+"speed" overrides default 200.
+"dmg" overrides default 2
+"model2" .md3 model to also draw
+"color" constantLight color
+"light" constantLight radius
+*/
+void SP_func_plat (gentity_t *ent) {
+ float lip, height;
+
+ ent->sound1to2 = ent->sound2to1 = G_SoundIndex("sound/movers/plats/pt1_strt.wav");
+ ent->soundPos1 = ent->soundPos2 = G_SoundIndex("sound/movers/plats/pt1_end.wav");
+
+ VectorClear (ent->s.angles);
+
+ G_SpawnFloat( "speed", "200", &ent->speed );
+ G_SpawnInt( "dmg", "2", &ent->damage );
+ G_SpawnFloat( "wait", "1", &ent->wait );
+ G_SpawnFloat( "lip", "8", &lip );
+
+ ent->wait = 1000;
+
+ // create second position
+ trap_SetBrushModel( ent, ent->model );
+
+ if ( !G_SpawnFloat( "height", "0", &height ) ) {
+ height = (ent->r.maxs[2] - ent->r.mins[2]) - lip;
+ }
+
+ // pos1 is the rest (bottom) position, pos2 is the top
+ VectorCopy( ent->s.origin, ent->pos2 );
+ VectorCopy( ent->pos2, ent->pos1 );
+ ent->pos1[2] -= height;
+
+ InitMover( ent );
+
+ // touch function keeps the plat from returning while
+ // a live player is standing on it
+ ent->touch = Touch_Plat;
+
+ ent->blocked = Blocked_Door;
+
+ ent->parent = ent; // so it can be treated as a door
+
+ // spawn the trigger if one hasn't been custom made
+ if ( !ent->targetname ) {
+ SpawnPlatTrigger(ent);
+ }
+}
+
+
+/*
+===============================================================================
+
+BUTTON
+
+===============================================================================
+*/
+
+/*
+==============
+Touch_Button
+
+===============
+*/
+void Touch_Button(gentity_t *ent, gentity_t *other, trace_t *trace ) {
+ if ( !other->client ) {
+ return;
+ }
+
+ if ( ent->moverState == MOVER_POS1 ) {
+ Use_BinaryMover( ent, other, other );
+ }
+}
+
+
+/*QUAKED func_button (0 .5 .8) ?
+When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
+
+"model2" .md3 model to also draw
+"angle" determines the opening direction
+"target" all entities with a matching targetname will be used
+"speed" override the default 40 speed
+"wait" override the default 1 second wait (-1 = never return)
+"lip" override the default 4 pixel lip remaining at end of move
+"health" if set, the button must be killed instead of touched
+"color" constantLight color
+"light" constantLight radius
+*/
+void SP_func_button( gentity_t *ent ) {
+ vec3_t abs_movedir;
+ float distance;
+ vec3_t size;
+ float lip;
+
+ ent->sound1to2 = G_SoundIndex("sound/movers/switches/butn2.wav");
+
+ if ( !ent->speed ) {
+ ent->speed = 40;
+ }
+
+ if ( !ent->wait ) {
+ ent->wait = 1;
+ }
+ ent->wait *= 1000;
+
+ // first position
+ VectorCopy( ent->s.origin, ent->pos1 );
+
+ // calculate second position
+ trap_SetBrushModel( ent, ent->model );
+
+ G_SpawnFloat( "lip", "4", &lip );
+
+ G_SetMovedir( ent->s.angles, ent->movedir );
+ abs_movedir[0] = fabs(ent->movedir[0]);
+ abs_movedir[1] = fabs(ent->movedir[1]);
+ abs_movedir[2] = fabs(ent->movedir[2]);
+ VectorSubtract( ent->r.maxs, ent->r.mins, size );
+ distance = abs_movedir[0] * size[0] + abs_movedir[1] * size[1] + abs_movedir[2] * size[2] - lip;
+ VectorMA (ent->pos1, distance, ent->movedir, ent->pos2);
+
+ if (ent->health) {
+ // shootable button
+ ent->takedamage = qtrue;
+ } else {
+ // touchable button
+ ent->touch = Touch_Button;
+ }
+
+ InitMover( ent );
+}
+
+
+
+/*
+===============================================================================
+
+TRAIN
+
+===============================================================================
+*/
+
+
+#define TRAIN_START_ON 1
+#define TRAIN_TOGGLE 2
+#define TRAIN_BLOCK_STOPS 4
+
+/*
+===============
+Think_BeginMoving
+
+The wait time at a corner has completed, so start moving again
+===============
+*/
+void Think_BeginMoving( gentity_t *ent ) {
+ ent->s.pos.trTime = level.time;
+ ent->s.pos.trType = TR_LINEAR_STOP;
+}
+
+/*
+===============
+Reached_Train
+===============
+*/
+void Reached_Train( gentity_t *ent ) {
+ gentity_t *next;
+ float speed;
+ vec3_t move;
+ float length;
+
+ // copy the apropriate values
+ next = ent->nextTrain;
+ if ( !next || !next->nextTrain ) {
+ return; // just stop
+ }
+
+ // fire all other targets
+ G_UseTargets( next, NULL );
+
+ // set the new trajectory
+ ent->nextTrain = next->nextTrain;
+ VectorCopy( next->s.origin, ent->pos1 );
+ VectorCopy( next->nextTrain->s.origin, ent->pos2 );
+
+ // if the path_corner has a speed, use that
+ if ( next->speed ) {
+ speed = next->speed;
+ } else {
+ // otherwise use the train's speed
+ speed = ent->speed;
+ }
+ if ( speed < 1 ) {
+ speed = 1;
+ }
+
+ // calculate duration
+ VectorSubtract( ent->pos2, ent->pos1, move );
+ length = VectorLength( move );
+
+ ent->s.pos.trDuration = length * 1000 / speed;
+
+ // Tequila comment: Be sure to send to clients after any fast move case
+ ent->r.svFlags &= ~SVF_NOCLIENT;
+
+ // Tequila comment: Fast move case
+ if(ent->s.pos.trDuration<1) {
+ // Tequila comment: As trDuration is used later in a division, we need to avoid that case now
+ // With null trDuration,
+ // the calculated rocks bounding box becomes infinite and the engine think for a short time
+ // any entity is riding that mover but not the world entity... In rare case, I found it
+ // can also stuck every map entities after func_door are used.
+ // The desired effect with very very big speed is to have instant move, so any not null duration
+ // lower than a frame duration should be sufficient.
+ // Afaik, the negative case don't have to be supported.
+ ent->s.pos.trDuration=1;
+
+ // Tequila comment: Don't send entity to clients so it becomes really invisible
+ ent->r.svFlags |= SVF_NOCLIENT;
+ }
+
+ // looping sound
+ ent->s.loopSound = next->soundLoop;
+
+ // start it going
+ SetMoverState( ent, MOVER_1TO2, level.time );
+
+ // if there is a "wait" value on the target, don't start moving yet
+ if ( next->wait ) {
+ ent->nextthink = level.time + next->wait * 1000;
+ ent->think = Think_BeginMoving;
+ ent->s.pos.trType = TR_STATIONARY;
+ }
+}
+
+
+/*
+===============
+Think_SetupTrainTargets
+
+Link all the corners together
+===============
+*/
+void Think_SetupTrainTargets( gentity_t *ent ) {
+ gentity_t *path, *next, *start;
+
+ ent->nextTrain = G_Find( NULL, FOFS(targetname), ent->target );
+ if ( !ent->nextTrain ) {
+ G_Printf( "func_train at %s with an unfound target\n",
+ vtos(ent->r.absmin) );
+ return;
+ }
+
+ start = NULL;
+ for ( path = ent->nextTrain ; path != start ; path = next ) {
+ if ( !start ) {
+ start = path;
+ }
+
+ if ( !path->target ) {
+ G_Printf( "Train corner at %s without a target\n",
+ vtos(path->s.origin) );
+ return;
+ }
+
+ // find a path_corner among the targets
+ // there may also be other targets that get fired when the corner
+ // is reached
+ next = NULL;
+ do {
+ next = G_Find( next, FOFS(targetname), path->target );
+ if ( !next ) {
+ G_Printf( "Train corner at %s without a target path_corner\n",
+ vtos(path->s.origin) );
+ return;
+ }
+ } while ( strcmp( next->classname, "path_corner" ) );
+
+ path->nextTrain = next;
+ }
+
+ // start the train moving from the first corner
+ Reached_Train( ent );
+}
+
+
+
+/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8)
+Train path corners.
+Target: next path corner and other targets to fire
+"speed" speed to move to the next corner
+"wait" seconds to wait before behining move to next corner
+*/
+void SP_path_corner( gentity_t *self ) {
+ if ( !self->targetname ) {
+ G_Printf ("path_corner with no targetname at %s\n", vtos(self->s.origin));
+ G_FreeEntity( self );
+ return;
+ }
+ // path corners don't need to be linked in
+}
+
+
+
+/*QUAKED func_train (0 .5 .8) ? START_ON TOGGLE BLOCK_STOPS
+A train is a mover that moves between path_corner target points.
+Trains MUST HAVE AN ORIGIN BRUSH.
+The train spawns at the first target it is pointing at.
+"model2" .md3 model to also draw
+"speed" default 100
+"dmg" default 2
+"noise" looping sound to play when the train is in motion
+"target" next path corner
+"color" constantLight color
+"light" constantLight radius
+*/
+void SP_func_train (gentity_t *self) {
+ VectorClear (self->s.angles);
+
+ if (self->spawnflags & TRAIN_BLOCK_STOPS) {
+ self->damage = 0;
+ } else {
+ if (!self->damage) {
+ self->damage = 2;
+ }
+ }
+
+ if ( !self->speed ) {
+ self->speed = 100;
+ }
+
+ if ( !self->target ) {
+ G_Printf ("func_train without a target at %s\n", vtos(self->r.absmin));
+ G_FreeEntity( self );
+ return;
+ }
+
+ trap_SetBrushModel( self, self->model );
+ InitMover( self );
+
+ self->reached = Reached_Train;
+
+ // start trains on the second frame, to make sure their targets have had
+ // a chance to spawn
+ self->nextthink = level.time + FRAMETIME;
+ self->think = Think_SetupTrainTargets;
+}
+
+/*
+===============================================================================
+
+STATIC
+
+===============================================================================
+*/
+
+
+/*QUAKED func_static (0 .5 .8) ?
+A bmodel that just sits there, doing nothing. Can be used for conditional walls and models.
+"model2" .md3 model to also draw
+"color" constantLight color
+"light" constantLight radius
+*/
+void SP_func_static( gentity_t *ent ) {
+ trap_SetBrushModel( ent, ent->model );
+ InitMover( ent );
+ VectorCopy( ent->s.origin, ent->s.pos.trBase );
+ VectorCopy( ent->s.origin, ent->r.currentOrigin );
+}
+
+
+/*
+===============================================================================
+
+ROTATING
+
+===============================================================================
+*/
+
+
+/*QUAKED func_rotating (0 .5 .8) ? START_ON - X_AXIS Y_AXIS
+You need to have an origin brush as part of this entity. The center of that brush will be
+the point around which it is rotated. It will rotate around the Z axis by default. You can
+check either the X_AXIS or Y_AXIS box to change that.
+
+"model2" .md3 model to also draw
+"speed" determines how fast it moves; default value is 100.
+"dmg" damage to inflict when blocked (2 default)
+"color" constantLight color
+"light" constantLight radius
+*/
+void SP_func_rotating (gentity_t *ent) {
+ if ( !ent->speed ) {
+ ent->speed = 100;
+ }
+
+ // set the axis of rotation
+ ent->s.apos.trType = TR_LINEAR;
+ if ( ent->spawnflags & 4 ) {
+ ent->s.apos.trDelta[2] = ent->speed;
+ } else if ( ent->spawnflags & 8 ) {
+ ent->s.apos.trDelta[0] = ent->speed;
+ } else {
+ ent->s.apos.trDelta[1] = ent->speed;
+ }
+
+ if (!ent->damage) {
+ ent->damage = 2;
+ }
+
+ trap_SetBrushModel( ent, ent->model );
+ InitMover( ent );
+
+ VectorCopy( ent->s.origin, ent->s.pos.trBase );
+ VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );
+ VectorCopy( ent->s.apos.trBase, ent->r.currentAngles );
+
+ trap_LinkEntity( ent );
+}
+
+
+/*
+===============================================================================
+
+BOBBING
+
+===============================================================================
+*/
+
+
+/*QUAKED func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS
+Normally bobs on the Z axis
+"model2" .md3 model to also draw
+"height" amplitude of bob (32 default)
+"speed" seconds to complete a bob cycle (4 default)
+"phase" the 0.0 to 1.0 offset in the cycle to start at
+"dmg" damage to inflict when blocked (2 default)
+"color" constantLight color
+"light" constantLight radius
+*/
+void SP_func_bobbing (gentity_t *ent) {
+ float height;
+ float phase;
+
+ G_SpawnFloat( "speed", "4", &ent->speed );
+ G_SpawnFloat( "height", "32", &height );
+ G_SpawnInt( "dmg", "2", &ent->damage );
+ G_SpawnFloat( "phase", "0", &phase );
+
+ trap_SetBrushModel( ent, ent->model );
+ InitMover( ent );
+
+ VectorCopy( ent->s.origin, ent->s.pos.trBase );
+ VectorCopy( ent->s.origin, ent->r.currentOrigin );
+
+ ent->s.pos.trDuration = ent->speed * 1000;
+ ent->s.pos.trTime = ent->s.pos.trDuration * phase;
+ ent->s.pos.trType = TR_SINE;
+
+ // set the axis of bobbing
+ if ( ent->spawnflags & 1 ) {
+ ent->s.pos.trDelta[0] = height;
+ } else if ( ent->spawnflags & 2 ) {
+ ent->s.pos.trDelta[1] = height;
+ } else {
+ ent->s.pos.trDelta[2] = height;
+ }
+}
+
+/*
+===============================================================================
+
+PENDULUM
+
+===============================================================================
+*/
+
+
+/*QUAKED func_pendulum (0 .5 .8) ?
+You need to have an origin brush as part of this entity.
+Pendulums always swing north / south on unrotated models. Add an angles field to the model to allow rotation in other directions.
+Pendulum frequency is a physical constant based on the length of the beam and gravity.
+"model2" .md3 model to also draw
+"speed" the number of degrees each way the pendulum swings, (30 default)
+"phase" the 0.0 to 1.0 offset in the cycle to start at
+"dmg" damage to inflict when blocked (2 default)
+"color" constantLight color
+"light" constantLight radius
+*/
+void SP_func_pendulum(gentity_t *ent) {
+ float freq;
+ float length;
+ float phase;
+ float speed;
+
+ G_SpawnFloat( "speed", "30", &speed );
+ G_SpawnInt( "dmg", "2", &ent->damage );
+ G_SpawnFloat( "phase", "0", &phase );
+
+ trap_SetBrushModel( ent, ent->model );
+
+ // find pendulum length
+ length = fabs( ent->r.mins[2] );
+ if ( length < 8 ) {
+ length = 8;
+ }
+
+ freq = 1 / ( M_PI * 2 ) * sqrt( g_gravity.value*g_gravityModifier.value / ( 3 * length ) );
+
+ ent->s.pos.trDuration = ( 1000 / freq );
+
+ InitMover( ent );
+
+ VectorCopy( ent->s.origin, ent->s.pos.trBase );
+ VectorCopy( ent->s.origin, ent->r.currentOrigin );
+
+ VectorCopy( ent->s.angles, ent->s.apos.trBase );
+
+ ent->s.apos.trDuration = 1000 / freq;
+ ent->s.apos.trTime = ent->s.apos.trDuration * phase;
+ ent->s.apos.trType = TR_SINE;
+ ent->s.apos.trDelta[2] = speed;
+}
diff --git a/code/game/g_playerstore.c b/code/game/g_playerstore.c
new file mode 100644
index 0000000..7c6be2c
--- /dev/null
+++ b/code/game/g_playerstore.c
@@ -0,0 +1,105 @@
+/*
+===========================================================================
+Copyright (C) 2008-2009 Poul Sander
+
+This file is part of Open Arena source code.
+
+Open Arena source code 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.
+
+Open Arena source code 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 Open Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "g_local.h"
+
+#define MAX_PLAYERS_STORED 32
+
+#define GUID_SIZE 32
+
+typedef struct {
+ char guid[GUID_SIZE+1]; //The guid is 32 chars long
+ int age; //int that grows each time a new player is stored. The lowest number is always replaced. Reset to 0 then retrieved.
+ int persistant[MAX_PERSISTANT]; //This is the only information we need to save
+ int timePlayed;
+ int accuracy[WP_NUM_WEAPONS][2];
+} playerstore_t;
+
+static playerstore_t playerstore[MAX_PLAYERS_STORED];
+
+static int nextAge;
+
+/*
+ *Resets the player store. Should be called everytime game.qvm is loaded.
+ */
+void PlayerStoreInit( void ) {
+ memset(playerstore,0,sizeof(playerstore));
+ nextAge = 1;
+}
+
+void PlayerStore_store(char* guid, playerState_t ps) {
+ int place2store = -1;
+ int lowestAge = 32000;
+ int i;
+ if(strlen(guid)<32)
+ {
+ G_LogPrintf("Playerstore: Failed to store player. Invalid guid: %s\n",guid);
+ return;
+ }
+ for(i=0;i<MAX_PLAYERS_STORED;i++) {
+ if(!Q_stricmp(guid,playerstore[i].guid)) {
+ place2store=i;
+ }
+ }
+
+ if(place2store<0)
+ for(i=0;i<MAX_PLAYERS_STORED;i++) {
+ if(playerstore[i].age < lowestAge) {
+ place2store = i;
+ lowestAge = playerstore[i].age;
+ }
+ }
+
+ //Make sure we don't store in -1
+ if(place2store<0)
+ place2store = 0;
+ //place2store is now the place to store to.
+ playerstore[place2store].age = nextAge++;
+ Q_strncpyz(playerstore[place2store].guid,guid,GUID_SIZE+1);
+ memcpy(playerstore[place2store].persistant,ps.persistant,sizeof(int[MAX_PERSISTANT]));
+ memcpy(playerstore[place2store].accuracy,level.clients[ps.clientNum].accuracy, sizeof(playerstore[0].accuracy) );
+ playerstore[place2store].timePlayed = level.time - level.clients[ps.clientNum].pers.enterTime;
+ G_LogPrintf("Playerstore: Stored player with guid: %s in %u\n", playerstore[place2store].guid,place2store);
+}
+
+void PlayerStore_restore(char* guid, playerState_t *ps) {
+ int i;
+ if(strlen(guid)<32)
+ {
+ G_LogPrintf("Playerstore: Failed to restore player. Invalid guid: %s\n",guid);
+ return;
+ }
+ for(i=0;i<MAX_PLAYERS_STORED;i++) {
+ if(!Q_stricmpn(guid,playerstore[i].guid,GUID_SIZE) && playerstore[i].age != -1) {
+ memcpy(ps->persistant,playerstore[i].persistant,sizeof(int[MAX_PERSISTANT]));
+ memcpy(level.clients[ps->clientNum].accuracy, playerstore[i].accuracy,sizeof(playerstore[0].accuracy) );
+ level.clients[ps->clientNum].pers.enterTime = level.time - playerstore[i].timePlayed;
+ //Never ever restore a player with negative score
+ if(ps->persistant[PERS_SCORE]<0)
+ ps->persistant[PERS_SCORE]=0;
+ playerstore[i].age = -1;
+ G_LogPrintf("Restored player with guid: %s\n",guid);
+ return;
+ }
+ }
+ G_LogPrintf("Playerstore: Nothing to restore. Guid: %s\n",guid);
+}
diff --git a/engine/code/game/g_public.h b/code/game/g_public.h
similarity index 100%
rename from engine/code/game/g_public.h
rename to code/game/g_public.h
diff --git a/game/code/game/g_rankings.c b/code/game/g_rankings.c
similarity index 100%
rename from game/code/game/g_rankings.c
rename to code/game/g_rankings.c
diff --git a/game/code/game/g_rankings.h b/code/game/g_rankings.h
similarity index 100%
rename from game/code/game/g_rankings.h
rename to code/game/g_rankings.h
diff --git a/code/game/g_session.c b/code/game/g_session.c
new file mode 100644
index 0000000..993fa97
--- /dev/null
+++ b/code/game/g_session.c
@@ -0,0 +1,194 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#include "g_local.h"
+
+
+/*
+=======================================================================
+
+ SESSION DATA
+
+Session data is the only data that stays persistant across level loads
+and tournament restarts.
+=======================================================================
+*/
+
+/*
+================
+G_WriteClientSessionData
+
+Called on game shutdown
+================
+*/
+void G_WriteClientSessionData( gclient_t *client ) {
+ const char *s;
+ const char *var;
+
+ s = va("%i %i %i %i %i %i %i",
+ client->sess.sessionTeam,
+ client->sess.spectatorNum,
+ client->sess.spectatorState,
+ client->sess.spectatorClient,
+ client->sess.wins,
+ client->sess.losses,
+ client->sess.teamLeader
+ );
+
+ var = va( "session%i", (int)(client - level.clients) );
+
+ trap_Cvar_Set( var, s );
+}
+
+/*
+================
+G_ReadSessionData
+
+Called on a reconnect
+================
+*/
+void G_ReadSessionData( gclient_t *client ) {
+ char s[MAX_STRING_CHARS];
+ const char *var;
+
+ // bk001205 - format
+ int teamLeader;
+ int spectatorState;
+ int sessionTeam;
+
+ var = va( "session%i", (int)(client - level.clients) );
+ trap_Cvar_VariableStringBuffer( var, s, sizeof(s) );
+
+ sscanf( s, "%i %i %i %i %i %i %i",
+ &sessionTeam, // bk010221 - format
+ &client->sess.spectatorNum,
+ &spectatorState, // bk010221 - format
+ &client->sess.spectatorClient,
+ &client->sess.wins,
+ &client->sess.losses,
+ &teamLeader // bk010221 - format
+ );
+
+ // bk001205 - format issues
+ client->sess.sessionTeam = (team_t)sessionTeam;
+ client->sess.spectatorState = (spectatorState_t)spectatorState;
+ client->sess.teamLeader = (qboolean)teamLeader;
+}
+
+
+/*
+================
+G_InitSessionData
+
+Called on a first-time connect
+================
+*/
+void G_InitSessionData( gclient_t *client, char *userinfo ) {
+ clientSession_t *sess;
+ const char *value;
+
+ sess = &client->sess;
+
+ // initial team determination
+ if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
+ if ( g_teamAutoJoin.integer ) {
+ sess->sessionTeam = PickTeam( -1 );
+ BroadcastTeamChange( client, -1 );
+ } else {
+ // always spawn as spectator in team games
+ sess->sessionTeam = TEAM_SPECTATOR;
+ }
+ } else {
+ value = Info_ValueForKey( userinfo, "team" );
+ if ( value[0] == 's' ) {
+ // a willing spectator, not a waiting-in-line
+ sess->sessionTeam = TEAM_SPECTATOR;
+ } else {
+ switch ( g_gametype.integer ) {
+ default:
+ case GT_FFA:
+ case GT_LMS:
+ case GT_SINGLE_PLAYER:
+ if ( g_maxGameClients.integer > 0 &&
+ level.numNonSpectatorClients >= g_maxGameClients.integer ) {
+ sess->sessionTeam = TEAM_SPECTATOR;
+ } else {
+ sess->sessionTeam = TEAM_FREE;
+ }
+ break;
+ case GT_TOURNAMENT:
+ // if the game is full, go into a waiting mode
+ if ( level.numNonSpectatorClients >= 2 ) {
+ sess->sessionTeam = TEAM_SPECTATOR;
+ } else {
+ sess->sessionTeam = TEAM_FREE;
+ }
+ break;
+ }
+ }
+ }
+
+ sess->spectatorState = SPECTATOR_FREE;
+ AddTournamentQueue(client);
+
+ G_WriteClientSessionData( client );
+}
+
+
+/*
+==================
+G_InitWorldSession
+
+==================
+*/
+void G_InitWorldSession( void ) {
+ char s[MAX_STRING_CHARS];
+ int gt;
+
+ trap_Cvar_VariableStringBuffer( "session", s, sizeof(s) );
+ gt = atoi( s );
+
+ // if the gametype changed since the last session, don't use any
+ // client sessions
+ if ( g_gametype.integer != gt ) {
+ level.newSession = qtrue;
+ G_Printf( "Gametype changed, clearing session data.\n" );
+ }
+}
+
+/*
+==================
+G_WriteSessionData
+
+==================
+*/
+void G_WriteSessionData( void ) {
+ int i;
+
+ trap_Cvar_Set( "session", va("%i", g_gametype.integer) );
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[i].pers.connected == CON_CONNECTED ) {
+ G_WriteClientSessionData( &level.clients[i] );
+ }
+ }
+}
diff --git a/code/game/g_spawn.c b/code/game/g_spawn.c
new file mode 100644
index 0000000..cb5ffbe
--- /dev/null
+++ b/code/game/g_spawn.c
@@ -0,0 +1,690 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+#include "g_local.h"
+
+qboolean G_SpawnString( const char *key, const char *defaultString, char **out ) {
+ int i;
+
+ if ( !level.spawning ) {
+ *out = (char *)defaultString;
+// G_Error( "G_SpawnString() called while not spawning" );
+ }
+
+ for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
+ if ( !Q_stricmp( key, level.spawnVars[i][0] ) ) {
+ *out = level.spawnVars[i][1];
+ return qtrue;
+ }
+ }
+
+ *out = (char *)defaultString;
+ return qfalse;
+}
+
+qboolean G_SpawnFloat( const char *key, const char *defaultString, float *out ) {
+ char *s;
+ qboolean present;
+
+ present = G_SpawnString( key, defaultString, &s );
+ *out = atof( s );
+ return present;
+}
+
+qboolean G_SpawnInt( const char *key, const char *defaultString, int *out ) {
+ char *s;
+ qboolean present;
+
+ present = G_SpawnString( key, defaultString, &s );
+ *out = atoi( s );
+ return present;
+}
+
+qboolean G_SpawnVector( const char *key, const char *defaultString, float *out ) {
+ char *s;
+ qboolean present;
+
+ present = G_SpawnString( key, defaultString, &s );
+ sscanf( s, "%f %f %f", &out[0], &out[1], &out[2] );
+ return present;
+}
+
+
+
+//
+// fields are needed for spawning from the entity string
+//
+typedef enum {
+ F_INT,
+ F_FLOAT,
+ F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL
+ F_GSTRING, // string on disk, pointer in memory, TAG_GAME
+ F_VECTOR,
+ F_ANGLEHACK,
+ F_ENTITY, // index on disk, pointer in memory
+ F_ITEM, // index on disk, pointer in memory
+ F_CLIENT, // index on disk, pointer in memory
+ F_IGNORE
+} fieldtype_t;
+
+typedef struct
+{
+ char *name;
+ int ofs;
+ fieldtype_t type;
+// int flags;
+} field_t;
+
+field_t fields[] = {
+ {"classname", FOFS(classname), F_LSTRING},
+ {"origin", FOFS(s.origin), F_VECTOR},
+ {"model", FOFS(model), F_LSTRING},
+ {"model2", FOFS(model2), F_LSTRING},
+ {"spawnflags", FOFS(spawnflags), F_INT},
+ {"speed", FOFS(speed), F_FLOAT},
+ {"target", FOFS(target), F_LSTRING},
+ {"targetname", FOFS(targetname), F_LSTRING},
+ {"message", FOFS(message), F_LSTRING},
+ {"team", FOFS(team), F_LSTRING},
+ {"wait", FOFS(wait), F_FLOAT},
+ {"random", FOFS(random), F_FLOAT},
+ {"count", FOFS(count), F_INT},
+ {"health", FOFS(health), F_INT},
+ {"light", 0, F_IGNORE},
+ {"dmg", FOFS(damage), F_INT},
+ {"angles", FOFS(s.angles), F_VECTOR},
+ {"angle", FOFS(s.angles), F_ANGLEHACK},
+ {"targetShaderName", FOFS(targetShaderName), F_LSTRING},
+ {"targetShaderNewName", FOFS(targetShaderNewName), F_LSTRING},
+
+ {NULL}
+};
+
+
+typedef struct {
+ char *name;
+ void (*spawn)(gentity_t *ent);
+} spawn_t;
+
+void SP_info_player_start (gentity_t *ent);
+void SP_info_player_deathmatch (gentity_t *ent);
+void SP_info_player_intermission (gentity_t *ent);
+//For Double Domination:
+void SP_info_player_dd (gentity_t *ent);
+void SP_info_player_dd_red (gentity_t *ent);
+void SP_info_player_dd_blue (gentity_t *ent);
+//standard domination:
+void SP_domination_point ( gentity_t *ent);
+
+void SP_info_firstplace(gentity_t *ent);
+void SP_info_secondplace(gentity_t *ent);
+void SP_info_thirdplace(gentity_t *ent);
+void SP_info_podium(gentity_t *ent);
+
+void SP_func_plat (gentity_t *ent);
+void SP_func_static (gentity_t *ent);
+void SP_func_rotating (gentity_t *ent);
+void SP_func_bobbing (gentity_t *ent);
+void SP_func_pendulum( gentity_t *ent );
+void SP_func_button (gentity_t *ent);
+void SP_func_door (gentity_t *ent);
+void SP_func_train (gentity_t *ent);
+void SP_func_timer (gentity_t *self);
+
+void SP_trigger_always (gentity_t *ent);
+void SP_trigger_multiple (gentity_t *ent);
+void SP_trigger_push (gentity_t *ent);
+void SP_trigger_teleport (gentity_t *ent);
+void SP_trigger_hurt (gentity_t *ent);
+
+void SP_target_remove_powerups( gentity_t *ent );
+void SP_target_give (gentity_t *ent);
+void SP_target_delay (gentity_t *ent);
+void SP_target_speaker (gentity_t *ent);
+void SP_target_print (gentity_t *ent);
+void SP_target_laser (gentity_t *self);
+void SP_target_character (gentity_t *ent);
+void SP_target_score( gentity_t *ent );
+void SP_target_teleporter( gentity_t *ent );
+void SP_target_relay (gentity_t *ent);
+void SP_target_kill (gentity_t *ent);
+void SP_target_position (gentity_t *ent);
+void SP_target_location (gentity_t *ent);
+void SP_target_push (gentity_t *ent);
+
+void SP_light (gentity_t *self);
+void SP_info_null (gentity_t *self);
+void SP_info_notnull (gentity_t *self);
+void SP_info_camp (gentity_t *self);
+void SP_path_corner (gentity_t *self);
+
+void SP_misc_teleporter_dest (gentity_t *self);
+void SP_misc_model(gentity_t *ent);
+void SP_misc_portal_camera(gentity_t *ent);
+void SP_misc_portal_surface(gentity_t *ent);
+
+void SP_shooter_rocket( gentity_t *ent );
+void SP_shooter_plasma( gentity_t *ent );
+void SP_shooter_grenade( gentity_t *ent );
+
+void SP_team_CTF_redplayer( gentity_t *ent );
+void SP_team_CTF_blueplayer( gentity_t *ent );
+
+void SP_team_CTF_redspawn( gentity_t *ent );
+void SP_team_CTF_bluespawn( gentity_t *ent );
+
+void SP_team_blueobelisk( gentity_t *ent );
+void SP_team_redobelisk( gentity_t *ent );
+void SP_team_neutralobelisk( gentity_t *ent );
+
+void SP_item_botroam( gentity_t *ent ) { }
+
+spawn_t spawns[] = {
+ // info entities don't do anything at all, but provide positional
+ // information for things controlled by other processes
+ {"info_player_start", SP_info_player_start},
+ {"info_player_deathmatch", SP_info_player_deathmatch},
+ {"info_player_intermission", SP_info_player_intermission},
+//Double Domination player spawn:
+ {"info_player_dd", SP_info_player_dd},
+ {"info_player_dd_red", SP_info_player_dd_red},
+ {"info_player_dd_blue", SP_info_player_dd_blue},
+//Standard Domination point spawn:
+ {"domination_point", SP_domination_point},
+
+
+ {"info_null", SP_info_null},
+ {"info_notnull", SP_info_notnull}, // use target_position instead
+ {"info_camp", SP_info_camp},
+
+ {"func_plat", SP_func_plat},
+ {"func_button", SP_func_button},
+ {"func_door", SP_func_door},
+ {"func_static", SP_func_static},
+ {"func_rotating", SP_func_rotating},
+ {"func_bobbing", SP_func_bobbing},
+ {"func_pendulum", SP_func_pendulum},
+ {"func_train", SP_func_train},
+ {"func_group", SP_info_null},
+ {"func_timer", SP_func_timer}, // rename trigger_timer?
+
+ // Triggers are brush objects that cause an effect when contacted
+ // by a living player, usually involving firing targets.
+ // While almost everything could be done with
+ // a single trigger class and different targets, triggered effects
+ // could not be client side predicted (push and teleport).
+ {"trigger_always", SP_trigger_always},
+ {"trigger_multiple", SP_trigger_multiple},
+ {"trigger_push", SP_trigger_push},
+ {"trigger_teleport", SP_trigger_teleport},
+ {"trigger_hurt", SP_trigger_hurt},
+
+ // targets perform no action by themselves, but must be triggered
+ // by another entity
+ {"target_give", SP_target_give},
+ {"target_remove_powerups", SP_target_remove_powerups},
+ {"target_delay", SP_target_delay},
+ {"target_speaker", SP_target_speaker},
+ {"target_print", SP_target_print},
+ {"target_laser", SP_target_laser},
+ {"target_score", SP_target_score},
+ {"target_teleporter", SP_target_teleporter},
+ {"target_relay", SP_target_relay},
+ {"target_kill", SP_target_kill},
+ {"target_position", SP_target_position},
+ {"target_location", SP_target_location},
+ {"target_push", SP_target_push},
+
+ {"light", SP_light},
+ {"path_corner", SP_path_corner},
+
+ {"misc_teleporter_dest", SP_misc_teleporter_dest},
+ {"misc_model", SP_misc_model},
+ {"misc_portal_surface", SP_misc_portal_surface},
+ {"misc_portal_camera", SP_misc_portal_camera},
+
+ {"shooter_rocket", SP_shooter_rocket},
+ {"shooter_grenade", SP_shooter_grenade},
+ {"shooter_plasma", SP_shooter_plasma},
+
+ {"team_CTF_redplayer", SP_team_CTF_redplayer},
+ {"team_CTF_blueplayer", SP_team_CTF_blueplayer},
+
+ {"team_CTF_redspawn", SP_team_CTF_redspawn},
+ {"team_CTF_bluespawn", SP_team_CTF_bluespawn},
+
+ {"team_redobelisk", SP_team_redobelisk},
+ {"team_blueobelisk", SP_team_blueobelisk},
+ {"team_neutralobelisk", SP_team_neutralobelisk},
+
+ {"item_botroam", SP_item_botroam},
+
+ {NULL, 0}
+};
+
+/*
+===============
+G_CallSpawn
+
+Finds the spawn function for the entity and calls it,
+returning qfalse if not found
+===============
+*/
+qboolean G_CallSpawn( gentity_t *ent ) {
+ spawn_t *s;
+ gitem_t *item;
+ char cvarname[128];
+ char itemname[128];
+
+ //Construct a replace cvar:
+ Com_sprintf(cvarname, sizeof(cvarname), "replace_%s", ent->classname);
+
+ //Look an alternative item up:
+ trap_Cvar_VariableStringBuffer(cvarname,itemname,sizeof(itemname));
+ if(itemname[0]==0) //If nothing found use original
+ Com_sprintf(itemname, sizeof(itemname), "%s", ent->classname);
+ else
+ G_Printf ("%s replaced by %s\n", ent->classname, itemname);
+
+
+ if ( itemname[0]==0) {
+ G_Printf ("G_CallSpawn: NULL classname\n");
+ return qfalse;
+ }
+
+ // check item spawn functions
+ for ( item=bg_itemlist+1 ; item->classname ; item++ ) {
+ if ( !strcmp(item->classname, itemname) ) {
+ G_SpawnItem( ent, item );
+ return qtrue;
+ }
+ }
+
+ // check normal spawn functions
+ for ( s=spawns ; s->name ; s++ ) {
+ if ( !strcmp(s->name, itemname) ) {
+ // found it
+ s->spawn(ent);
+ return qtrue;
+ }
+ }
+ G_Printf ("%s doesn't have a spawn function\n", itemname);
+ return qfalse;
+}
+
+/*
+=============
+G_NewString
+
+Builds a copy of the string, translating \n to real linefeeds
+so message texts can be multi-line
+=============
+*/
+char *G_NewString( const char *string ) {
+ char *newb, *new_p;
+ int i,l;
+
+ l = strlen(string) + 1;
+ //KK-OAX Changed to Tremulous's BG_Alloc
+ newb = BG_Alloc( l );
+
+ new_p = newb;
+
+ // turn \n into a real linefeed
+ for ( i=0 ; i< l ; i++ ) {
+ if (string[i] == '\\' && i < l-1) {
+ i++;
+ if (string[i] == 'n') {
+ *new_p++ = '\n';
+ } else {
+ *new_p++ = '\\';
+ }
+ } else {
+ *new_p++ = string[i];
+ }
+ }
+
+ return newb;
+}
+
+
+
+
+/*
+===============
+G_ParseField
+
+Takes a key/value pair and sets the binary values
+in a gentity
+===============
+*/
+void G_ParseField( const char *key, const char *value, gentity_t *ent ) {
+ field_t *f;
+ byte *b;
+ float v;
+ vec3_t vec;
+
+ for ( f=fields ; f->name ; f++ ) {
+ if ( !Q_stricmp(f->name, key) ) {
+ // found it
+ b = (byte *)ent;
+
+ switch( f->type ) {
+ case F_LSTRING:
+ *(char **)(b+f->ofs) = G_NewString (value);
+ break;
+ case F_VECTOR:
+ sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
+ ((float *)(b+f->ofs))[0] = vec[0];
+ ((float *)(b+f->ofs))[1] = vec[1];
+ ((float *)(b+f->ofs))[2] = vec[2];
+ break;
+ case F_INT:
+ *(int *)(b+f->ofs) = atoi(value);
+ break;
+ case F_FLOAT:
+ *(float *)(b+f->ofs) = atof(value);
+ break;
+ case F_ANGLEHACK:
+ v = atof(value);
+ ((float *)(b+f->ofs))[0] = 0;
+ ((float *)(b+f->ofs))[1] = v;
+ ((float *)(b+f->ofs))[2] = 0;
+ break;
+ default:
+ case F_IGNORE:
+ break;
+ }
+ return;
+ }
+ }
+}
+
+
+
+
+/*
+===================
+G_SpawnGEntityFromSpawnVars
+
+Spawn an entity and fill in all of the level fields from
+level.spawnVars[], then call the class specfic spawn function
+===================
+*/
+void G_SpawnGEntityFromSpawnVars( void ) {
+ int i;
+ gentity_t *ent;
+ char *s, *value, *gametypeName;
+ static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester", "elimination", "ctf", "lms", "dd", "dom"};
+
+ // get the next free entity
+ ent = G_Spawn();
+
+ for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
+ G_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], ent );
+ }
+
+ // check for "notsingle" flag
+ if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
+ G_SpawnInt( "notsingle", "0", &i );
+ if ( i ) {
+ G_FreeEntity( ent );
+ return;
+ }
+ }
+ // check for "notteam" flag (GT_FFA, GT_TOURNAMENT, GT_SINGLE_PLAYER)
+ if ( g_gametype.integer >= GT_TEAM && !g_ffa_gt ) {
+ G_SpawnInt( "notteam", "0", &i );
+ if ( i ) {
+ G_FreeEntity( ent );
+ return;
+ }
+ } else {
+ G_SpawnInt( "notfree", "0", &i );
+ if ( i ) {
+ G_FreeEntity( ent );
+ return;
+ }
+ }
+
+#ifdef MISSIONPACK
+ G_SpawnInt( "notta", "0", &i );
+ if ( i ) {
+ G_FreeEntity( ent );
+ return;
+ }
+#else
+ G_SpawnInt( "notq3a", "0", &i );
+ if ( i ) {
+ G_FreeEntity( ent );
+ return;
+ }
+#endif
+
+ if( G_SpawnString( "!gametype", NULL, &value ) ) {
+ if( g_gametype.integer >= GT_FFA && g_gametype.integer < GT_MAX_GAME_TYPE ) {
+ gametypeName = gametypeNames[g_gametype.integer];
+
+ s = strstr( value, gametypeName );
+ if( s ) {
+ G_FreeEntity( ent );
+ return;
+ }
+ }
+ }
+
+ if( G_SpawnString( "gametype", NULL, &value ) ) {
+ if( g_gametype.integer >= GT_FFA && g_gametype.integer < GT_MAX_GAME_TYPE ) {
+ gametypeName = gametypeNames[g_gametype.integer];
+
+ s = strstr( value, gametypeName );
+ if( !s ) {
+ G_FreeEntity( ent );
+ return;
+ }
+ }
+ }
+
+ // move editor origin to pos
+ VectorCopy( ent->s.origin, ent->s.pos.trBase );
+ VectorCopy( ent->s.origin, ent->r.currentOrigin );
+
+ // if we didn't get a classname, don't bother spawning anything
+ if ( !G_CallSpawn( ent ) ) {
+ G_FreeEntity( ent );
+ }
+}
+
+
+
+/*
+====================
+G_AddSpawnVarToken
+====================
+*/
+char *G_AddSpawnVarToken( const char *string ) {
+ int l;
+ char *dest;
+
+ l = strlen( string );
+ if ( level.numSpawnVarChars + l + 1 > MAX_SPAWN_VARS_CHARS ) {
+ G_Error( "G_AddSpawnVarToken: MAX_SPAWN_VARS" );
+ }
+
+ dest = level.spawnVarChars + level.numSpawnVarChars;
+ memcpy( dest, string, l+1 );
+
+ level.numSpawnVarChars += l + 1;
+
+ return dest;
+}
+
+/*
+====================
+G_ParseSpawnVars
+
+Parses a brace bounded set of key / value pairs out of the
+level's entity strings into level.spawnVars[]
+
+This does not actually spawn an entity.
+====================
+*/
+qboolean G_ParseSpawnVars( void ) {
+ char keyname[MAX_TOKEN_CHARS];
+ char com_token[MAX_TOKEN_CHARS];
+
+ level.numSpawnVars = 0;
+ level.numSpawnVarChars = 0;
+
+ // parse the opening brace
+ if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
+ // end of spawn string
+ return qfalse;
+ }
+ if ( com_token[0] != '{' ) {
+ G_Error( "G_ParseSpawnVars: found %s when expecting {",com_token );
+ }
+
+ // go through all the key / value pairs
+ while ( 1 ) {
+ // parse key
+ if ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) {
+ G_Error( "G_ParseSpawnVars: EOF without closing brace" );
+ }
+
+ if ( keyname[0] == '}' ) {
+ break;
+ }
+
+ // parse value
+ if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
+ G_Error( "G_ParseSpawnVars: EOF without closing brace" );
+ }
+
+ if ( com_token[0] == '}' ) {
+ G_Error( "G_ParseSpawnVars: closing brace without data" );
+ }
+ if ( level.numSpawnVars == MAX_SPAWN_VARS ) {
+ G_Error( "G_ParseSpawnVars: MAX_SPAWN_VARS" );
+ }
+ level.spawnVars[ level.numSpawnVars ][0] = G_AddSpawnVarToken( keyname );
+ level.spawnVars[ level.numSpawnVars ][1] = G_AddSpawnVarToken( com_token );
+ level.numSpawnVars++;
+ }
+
+ return qtrue;
+}
+
+
+
+/*QUAKED worldspawn (0 0 0) ?
+
+Every map should have exactly one worldspawn.
+"music" music wav file
+"gravity" 800 is default gravity
+"message" Text to print during connection process
+*/
+void SP_worldspawn( void ) {
+ char *s;
+
+ G_SpawnString( "classname", "", &s );
+ if ( Q_stricmp( s, "worldspawn" ) ) {
+ G_Error( "SP_worldspawn: The first entity isn't 'worldspawn'" );
+ }
+
+ // make some data visible to connecting client
+ trap_SetConfigstring( CS_GAME_VERSION, GAME_VERSION );
+
+ trap_SetConfigstring( CS_LEVEL_START_TIME, va("%i", level.startTime ) );
+
+ if ( *g_music.string && Q_stricmp( g_music.string, "none" ) ) {
+ trap_SetConfigstring( CS_MUSIC, g_music.string );
+ } else {
+ G_SpawnString( "music", "", &s );
+ trap_SetConfigstring( CS_MUSIC, s );
+ }
+
+ G_SpawnString( "message", "", &s );
+ trap_SetConfigstring( CS_MESSAGE, s ); // map specific message
+
+ trap_SetConfigstring( CS_MOTD, g_motd.string ); // message of the day
+
+ G_SpawnString( "gravity", "800", &s );
+ trap_Cvar_Set( "g_gravity", s );
+
+ G_SpawnString( "enableDust", "0", &s );
+ trap_Cvar_Set( "g_enableDust", s );
+
+ G_SpawnString( "enableBreath", "0", &s );
+ trap_Cvar_Set( "g_enableBreath", s );
+
+ g_entities[ENTITYNUM_WORLD].s.number = ENTITYNUM_WORLD;
+ g_entities[ENTITYNUM_WORLD].r.ownerNum = ENTITYNUM_NONE;
+ g_entities[ENTITYNUM_WORLD].classname = "worldspawn";
+
+ g_entities[ENTITYNUM_NONE].s.number = ENTITYNUM_NONE;
+ g_entities[ENTITYNUM_NONE].r.ownerNum = ENTITYNUM_NONE;
+ g_entities[ENTITYNUM_NONE].classname = "nothing";
+
+ // see if we want a warmup time
+ trap_SetConfigstring( CS_WARMUP, "" );
+ if ( g_restarted.integer ) {
+ trap_Cvar_Set( "g_restarted", "0" );
+ level.warmupTime = 0;
+ } else if ( g_doWarmup.integer ) { // Turn it on
+ level.warmupTime = -1;
+ trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
+ G_LogPrintf( "Warmup:\n" );
+ }
+
+}
+
+
+/*
+==============
+G_SpawnEntitiesFromString
+
+Parses textual entity definitions out of an entstring and spawns gentities.
+==============
+*/
+void G_SpawnEntitiesFromString( void ) {
+ // allow calls to G_Spawn*()
+ level.spawning = qtrue;
+ level.numSpawnVars = 0;
+
+ // the worldspawn is not an actual entity, but it still
+ // has a "spawn" function to perform any global setup
+ // needed by a level (setting configstrings or cvars, etc)
+ if ( !G_ParseSpawnVars() ) {
+ G_Error( "SpawnEntities: no entities" );
+ }
+ SP_worldspawn();
+
+ // parse ents
+ while( G_ParseSpawnVars() ) {
+ G_SpawnGEntityFromSpawnVars();
+ }
+
+ level.spawning = qfalse; // any future calls to G_Spawn*() will be errors
+}
+
diff --git a/code/game/g_svcmds.c b/code/game/g_svcmds.c
new file mode 100644
index 0000000..33b7387
--- /dev/null
+++ b/code/game/g_svcmds.c
@@ -0,0 +1,547 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+// this file holds commands that can be executed by the server console, but not remote clients
+
+#include "g_local.h"
+
+
+/*
+==============================================================================
+
+PACKET FILTERING
+
+
+You can add or remove addresses from the filter list with:
+
+addip <ip>
+removeip <ip>
+
+The ip address is specified in dot format, and you can use '*' to match any value
+so you can specify an entire class C network with "addip 192.246.40.*"
+
+Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host.
+
+listip
+Prints the current list of filters.
+
+g_filterban <0 or 1>
+
+If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game. This is the default setting.
+
+If 0, then only addresses matching the list will be allowed. This lets you easily set up a private game, or a game that only allows players from your local network.
+
+TTimo NOTE: for persistence, bans are stored in g_banIPs cvar MAX_CVAR_VALUE_STRING
+The size of the cvar string buffer is limiting the banning to around 20 masks
+this could be improved by putting some g_banIPs2 g_banIps3 etc. maybe
+still, you should rely on PB for banning instead
+
+==============================================================================
+*/
+
+typedef struct ipFilter_s
+{
+ unsigned mask;
+ unsigned compare;
+} ipFilter_t;
+
+#define MAX_IPFILTERS 1024
+
+static ipFilter_t ipFilters[MAX_IPFILTERS];
+static int numIPFilters;
+
+/*
+=================
+StringToFilter
+=================
+*/
+static qboolean StringToFilter (char *s, ipFilter_t *f)
+{
+ char num[128];
+ int i, j;
+ byte b[4];
+ byte m[4];
+
+ for (i=0 ; i<4 ; i++)
+ {
+ b[i] = 0;
+ m[i] = 0;
+ }
+
+ for (i=0 ; i<4 ; i++)
+ {
+ if (*s < '0' || *s > '9')
+ {
+ if (*s == '*') // 'match any'
+ {
+ // b[i] and m[i] to 0
+ s++;
+ if (!*s)
+ break;
+ s++;
+ continue;
+ }
+ G_Printf( "Bad filter address: %s\n", s );
+ return qfalse;
+ }
+
+ j = 0;
+ while (*s >= '0' && *s <= '9')
+ {
+ num[j++] = *s++;
+ }
+ num[j] = 0;
+ b[i] = atoi(num);
+ m[i] = 255;
+
+ if (!*s)
+ break;
+ s++;
+ }
+
+ f->mask = *(unsigned *)m;
+ f->compare = *(unsigned *)b;
+
+ return qtrue;
+}
+
+/*
+=================
+UpdateIPBans
+=================
+*/
+static void UpdateIPBans (void)
+{
+ byte b[4];
+ byte m[4];
+ int i,j;
+ char iplist_final[MAX_CVAR_VALUE_STRING];
+ char ip[64];
+
+ *iplist_final = 0;
+ for (i = 0 ; i < numIPFilters ; i++)
+ {
+ if (ipFilters[i].compare == 0xffffffff)
+ continue;
+
+ *(unsigned *)b = ipFilters[i].compare;
+ *(unsigned *)m = ipFilters[i].mask;
+ *ip = 0;
+ for (j = 0 ; j < 4 ; j++)
+ {
+ if (m[j]!=255)
+ Q_strcat(ip, sizeof(ip), "*");
+ else
+ Q_strcat(ip, sizeof(ip), va("%i", b[j]));
+ Q_strcat(ip, sizeof(ip), (j<3) ? "." : " ");
+ }
+ if (strlen(iplist_final)+strlen(ip) < MAX_CVAR_VALUE_STRING)
+ {
+ Q_strcat( iplist_final, sizeof(iplist_final), ip);
+ }
+ else
+ {
+ Com_Printf("g_banIPs overflowed at MAX_CVAR_VALUE_STRING\n");
+ break;
+ }
+ }
+
+ trap_Cvar_Set( "g_banIPs", iplist_final );
+}
+
+/*
+=================
+G_FilterPacket
+=================
+*/
+qboolean G_FilterPacket (char *from)
+{
+ int i;
+ unsigned in;
+ byte m[4];
+ char *p;
+
+ i = 0;
+ p = from;
+ while (*p && i < 4) {
+ m[i] = 0;
+ while (*p >= '0' && *p <= '9') {
+ m[i] = m[i]*10 + (*p - '0');
+ p++;
+ }
+ if (!*p || *p == ':')
+ break;
+ i++, p++;
+ }
+
+ in = *(unsigned *)m;
+
+ for (i=0 ; i<numIPFilters ; i++)
+ if ( (in & ipFilters[i].mask) == ipFilters[i].compare)
+ return g_filterBan.integer != 0;
+
+ return g_filterBan.integer == 0;
+}
+
+/*
+=================
+AddIP
+=================
+*/
+static void AddIP( char *str )
+{
+ int i;
+
+ for (i = 0 ; i < numIPFilters ; i++)
+ if (ipFilters[i].compare == 0xffffffff)
+ break; // free spot
+ if (i == numIPFilters)
+ {
+ if (numIPFilters == MAX_IPFILTERS)
+ {
+ G_Printf ("IP filter list is full\n");
+ return;
+ }
+ numIPFilters++;
+ }
+
+ if (!StringToFilter (str, &ipFilters[i]))
+ ipFilters[i].compare = 0xffffffffu;
+
+ UpdateIPBans();
+}
+
+/*
+=================
+G_ProcessIPBans
+=================
+*/
+void G_ProcessIPBans(void)
+{
+ char *s, *t;
+ char str[MAX_CVAR_VALUE_STRING];
+
+ Q_strncpyz( str, g_banIPs.string, sizeof(str) );
+
+ for (t = s = g_banIPs.string; *t; /* */ ) {
+ s = strchr(s, ' ');
+ if (!s)
+ break;
+ while (*s == ' ')
+ *s++ = 0;
+ if (*t)
+ AddIP( t );
+ t = s;
+ }
+}
+
+
+/*
+=================
+Svcmd_AddIP_f
+=================
+*/
+void Svcmd_AddIP_f (void)
+{
+ char str[MAX_TOKEN_CHARS];
+
+ if ( trap_Argc() < 2 ) {
+ G_Printf("Usage: addip <ip-mask>\n");
+ return;
+ }
+
+ trap_Argv( 1, str, sizeof( str ) );
+
+ AddIP( str );
+
+}
+
+/*
+=================
+Svcmd_RemoveIP_f
+=================
+*/
+void Svcmd_RemoveIP_f (void)
+{
+ ipFilter_t f;
+ int i;
+ char str[MAX_TOKEN_CHARS];
+
+ if ( trap_Argc() < 2 ) {
+ G_Printf("Usage: sv removeip <ip-mask>\n");
+ return;
+ }
+
+ trap_Argv( 1, str, sizeof( str ) );
+
+ if (!StringToFilter (str, &f))
+ return;
+
+ for (i=0 ; i<numIPFilters ; i++) {
+ if (ipFilters[i].mask == f.mask &&
+ ipFilters[i].compare == f.compare) {
+ ipFilters[i].compare = 0xffffffffu;
+ G_Printf ("Removed.\n");
+
+ UpdateIPBans();
+ return;
+ }
+ }
+ G_Printf ( "Didn't find %s.\n", str );
+}
+
+/*
+===================
+Svcmd_EntityList_f
+===================
+*/
+void Svcmd_EntityList_f (void) {
+ int e;
+ gentity_t *check;
+
+ check = g_entities+1;
+ for (e = 1; e < level.num_entities ; e++, check++) {
+ if ( !check->inuse ) {
+ continue;
+ }
+ G_Printf("%3i:", e);
+ switch ( check->s.eType ) {
+ case ET_GENERAL:
+ G_Printf("ET_GENERAL ");
+ break;
+ case ET_PLAYER:
+ G_Printf("ET_PLAYER ");
+ break;
+ case ET_ITEM:
+ G_Printf("ET_ITEM ");
+ break;
+ case ET_MISSILE:
+ G_Printf("ET_MISSILE ");
+ break;
+ case ET_MOVER:
+ G_Printf("ET_MOVER ");
+ break;
+ case ET_BEAM:
+ G_Printf("ET_BEAM ");
+ break;
+ case ET_PORTAL:
+ G_Printf("ET_PORTAL ");
+ break;
+ case ET_SPEAKER:
+ G_Printf("ET_SPEAKER ");
+ break;
+ case ET_PUSH_TRIGGER:
+ G_Printf("ET_PUSH_TRIGGER ");
+ break;
+ case ET_TELEPORT_TRIGGER:
+ G_Printf("ET_TELEPORT_TRIGGER ");
+ break;
+ case ET_INVISIBLE:
+ G_Printf("ET_INVISIBLE ");
+ break;
+ case ET_GRAPPLE:
+ G_Printf("ET_GRAPPLE ");
+ break;
+ default:
+ G_Printf("%3i ", check->s.eType);
+ break;
+ }
+ if ( check->classname ) {
+ G_Printf("%s", check->classname);
+ }
+ G_Printf("\n");
+ }
+}
+
+gclient_t *ClientForString( const char *s ) {
+ gclient_t *cl;
+ int i;
+ int idnum;
+
+ // numeric values are just slot numbers
+ if ( s[0] >= '0' && s[0] <= '9' ) {
+ idnum = atoi( s );
+ if ( idnum < 0 || idnum >= level.maxclients ) {
+ Com_Printf( "Bad client slot: %i\n", idnum );
+ return NULL;
+ }
+
+ cl = &level.clients[idnum];
+ if ( cl->pers.connected == CON_DISCONNECTED ) {
+ G_Printf( "Client %i is not connected\n", idnum );
+ return NULL;
+ }
+ return cl;
+ }
+
+ // check for a name match
+ for ( i=0 ; i < level.maxclients ; i++ ) {
+ cl = &level.clients[i];
+ if ( cl->pers.connected == CON_DISCONNECTED ) {
+ continue;
+ }
+ if ( !Q_stricmp( cl->pers.netname, s ) ) {
+ return cl;
+ }
+ }
+ G_Printf( "User %s is not on the server\n", s );
+
+ return NULL;
+}
+
+/*
+===================
+Svcmd_ForceTeam_f
+
+forceteam <player> <team>
+===================
+*/
+void Svcmd_ForceTeam_f( void ) {
+ gclient_t *cl;
+ char str[MAX_TOKEN_CHARS];
+
+ // find the player
+ trap_Argv( 1, str, sizeof( str ) );
+ cl = ClientForString( str );
+ if ( !cl ) {
+ return;
+ }
+
+ // set the team
+ trap_Argv( 2, str, sizeof( str ) );
+ SetTeam( &g_entities[cl - level.clients], str );
+}
+
+void ClientKick_f( void ) {
+ int idnum, i;
+ char str[MAX_TOKEN_CHARS];
+
+ trap_Argv( 1, str, sizeof( str ) );
+
+ for (i = 0; str[i]; i++) {
+ if (str[i] < '0' || str[i] > '9') {
+ G_Printf("not a valid client number: \"%s\"\n",str);
+ return;
+ }
+ }
+
+ idnum = atoi( str );
+
+ //Local client
+ if( !strcmp( level.clients[idnum].pers.ip, "localhost" ) ) {
+ G_Printf("Kick failed - local player\n");
+ return;
+ }
+
+ //Now clientkick has been moved into game, but we still need to find the idnum the server expects....
+ //FIXME: To fix this, we need a relieble way to generate difference between the server's client number and the game's client numbers
+ //FIXME: This should not depend on the engine's clientkick at all
+ trap_DropClient( idnum, "was kicked" );
+ //trap_SendConsoleCommand( EXEC_INSERT, va("clientkick %d\n", level.clients[idnum].ps.clientNum) );
+
+}
+
+void EndGame_f ( void ) {
+ ExitLevel();
+}
+
+//KK-OAX Moved this Declaration to g_local.h
+//char *ConcatArgs( int start );
+
+/*KK-OAX
+===============
+Server Command Table
+Not Worth Listing Elsewhere
+================
+*/
+struct
+{
+ char *cmd;
+ qboolean dedicated; //if it has to be entered from a dedicated server or RCON
+ void ( *function )( void );
+} svcmds[ ] = {
+
+ { "entityList", qfalse, Svcmd_EntityList_f },
+ { "forceTeam", qfalse, Svcmd_ForceTeam_f },
+ { "game_memory", qfalse, Svcmd_GameMem_f },
+ { "addbot", qfalse, Svcmd_AddBot_f },
+ { "botlist", qfalse, Svcmd_BotList_f },
+ { "abort_podium", qfalse, Svcmd_AbortPodium_f },
+ { "addip", qfalse, Svcmd_AddIP_f },
+ { "removeip", qfalse, Svcmd_RemoveIP_f },
+
+ //KK-OAX Uses wrapper in g_svccmds_ext.c
+ { "listip", qfalse, Svcmd_ListIP_f },
+ //KK-OAX New
+ { "status", qfalse, Svcmd_Status_f },
+ { "eject", qfalse, Svcmd_EjectClient_f },
+ { "dumpuser", qfalse, Svcmd_DumpUser_f },
+ // don't handle communication commands unless dedicated
+ { "cp", qtrue, Svcmd_CenterPrint_f },
+ { "say_team", qtrue, Svcmd_TeamMessage_f },
+ { "say", qtrue, Svcmd_MessageWrapper },
+ { "chat", qtrue, Svcmd_Chat_f },
+ /*{ "m", qtrue, Svcmd_MessageWrapper },
+ { "a", qtrue, Svcmd_MessageWrapper },
+ { "bp", qtrue, Svcmd_BannerPrint_f }, */
+ //Shuffle the teams
+ { "shuffle", qfalse, ShuffleTeams },
+ //Kicks a player by number in the game logic rather than the server number
+ { "clientkick_game", qfalse, ClientKick_f },
+ { "endgamenow", qfalse, EndGame_f },
+};
+
+/*
+=================
+ConsoleCommand
+
+=================
+*/
+qboolean ConsoleCommand( void )
+{
+ char cmd[ MAX_TOKEN_CHARS ];
+ int i;
+
+ trap_Argv( 0, cmd, sizeof( cmd ) );
+
+ for( i = 0; i < sizeof( svcmds ) / sizeof( svcmds[ 0 ] ); i++ )
+ {
+ if( !Q_stricmp( cmd, svcmds[ i ].cmd ) )
+ {
+ if( svcmds[ i ].dedicated && !g_dedicated.integer )
+ return qfalse;
+ svcmds[ i ].function( );
+ return qtrue;
+ }
+ }
+ // KK-OAX Will be enabled when admin is added.
+ // see if this is an admin command
+ if( G_admin_cmd_check( NULL, qfalse ) )
+ return qtrue;
+
+ if( g_dedicated.integer )
+ G_Printf( "unknown command: %s\n", cmd );
+
+ return qfalse;
+}
+
diff --git a/game/code/game/g_svcmds_ext.c b/code/game/g_svcmds_ext.c
similarity index 100%
rename from game/code/game/g_svcmds_ext.c
rename to code/game/g_svcmds_ext.c
diff --git a/engine/code/game/g_syscalls.asm b/code/game/g_syscalls.asm
similarity index 100%
rename from engine/code/game/g_syscalls.asm
rename to code/game/g_syscalls.asm
diff --git a/code/game/g_syscalls.c b/code/game/g_syscalls.c
new file mode 100644
index 0000000..4b2b9a8
--- /dev/null
+++ b/code/game/g_syscalls.c
@@ -0,0 +1,791 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#include "g_local.h"
+
+// this file is only included when building a dll
+// g_syscalls.asm is included instead when building a qvm
+#ifdef Q3_VM
+#error "Do not use in VM build"
+#endif
+
+static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;
+
+
+Q_EXPORT void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) {
+ syscall = syscallptr;
+}
+
+int PASSFLOAT( float x ) {
+ floatint_t fi;
+ fi.f = x;
+ return fi.i;
+}
+
+void trap_Printf( const char *fmt ) {
+ syscall( G_PRINT, fmt );
+}
+
+void trap_Error( const char *fmt ) {
+ syscall( G_ERROR, fmt );
+ exit(0); //Will never be executed. Makes compiler happy
+}
+
+int trap_Milliseconds( void ) {
+ return syscall( G_MILLISECONDS );
+}
+int trap_Argc( void ) {
+ return syscall( G_ARGC );
+}
+
+void trap_Argv( int n, char *buffer, int bufferLength ) {
+ syscall( G_ARGV, n, buffer, bufferLength );
+}
+
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
+ return syscall( G_FS_FOPEN_FILE, qpath, f, mode );
+}
+
+void trap_FS_Read( void *buffer, int len, fileHandle_t f ) {
+ syscall( G_FS_READ, buffer, len, f );
+}
+
+void trap_FS_Write( const void *buffer, int len, fileHandle_t f ) {
+ syscall( G_FS_WRITE, buffer, len, f );
+}
+
+void trap_FS_FCloseFile( fileHandle_t f ) {
+ syscall( G_FS_FCLOSE_FILE, f );
+}
+
+int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ) {
+ return syscall( G_FS_GETFILELIST, path, extension, listbuf, bufsize );
+}
+
+int trap_FS_Seek( fileHandle_t f, long offset, int origin ) {
+ return syscall( G_FS_SEEK, f, offset, origin );
+}
+
+void trap_SendConsoleCommand( int exec_when, const char *text ) {
+ syscall( G_SEND_CONSOLE_COMMAND, exec_when, text );
+}
+
+void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags ) {
+ syscall( G_CVAR_REGISTER, cvar, var_name, value, flags );
+}
+
+void trap_Cvar_Update( vmCvar_t *cvar ) {
+ syscall( G_CVAR_UPDATE, cvar );
+}
+
+void trap_Cvar_Set( const char *var_name, const char *value ) {
+ syscall( G_CVAR_SET, var_name, value );
+}
+
+int trap_Cvar_VariableIntegerValue( const char *var_name ) {
+ return syscall( G_CVAR_VARIABLE_INTEGER_VALUE, var_name );
+}
+
+void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
+ syscall( G_CVAR_VARIABLE_STRING_BUFFER, var_name, buffer, bufsize );
+}
+
+
+void trap_LocateGameData( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
+ playerState_t *clients, int sizeofGClient ) {
+ syscall( G_LOCATE_GAME_DATA, gEnts, numGEntities, sizeofGEntity_t, clients, sizeofGClient );
+}
+
+void trap_DropClient( int clientNum, const char *reason ) {
+ syscall( G_DROP_CLIENT, clientNum, reason );
+}
+
+void trap_SendServerCommand( int clientNum, const char *text ) {
+ syscall( G_SEND_SERVER_COMMAND, clientNum, text );
+}
+
+void trap_SetConfigstring( int num, const char *string ) {
+ syscall( G_SET_CONFIGSTRING, num, string );
+}
+
+void trap_GetConfigstring( int num, char *buffer, int bufferSize ) {
+ syscall( G_GET_CONFIGSTRING, num, buffer, bufferSize );
+}
+
+void trap_GetUserinfo( int num, char *buffer, int bufferSize ) {
+ syscall( G_GET_USERINFO, num, buffer, bufferSize );
+}
+
+void trap_SetUserinfo( int num, const char *buffer ) {
+ syscall( G_SET_USERINFO, num, buffer );
+}
+
+void trap_GetServerinfo( char *buffer, int bufferSize ) {
+ syscall( G_GET_SERVERINFO, buffer, bufferSize );
+}
+
+void trap_SetBrushModel( gentity_t *ent, const char *name ) {
+ syscall( G_SET_BRUSH_MODEL, ent, name );
+}
+
+void trap_Trace( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask ) {
+ syscall( G_TRACE, results, start, mins, maxs, end, passEntityNum, contentmask );
+}
+
+void trap_TraceCapsule( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask ) {
+ syscall( G_TRACECAPSULE, results, start, mins, maxs, end, passEntityNum, contentmask );
+}
+
+int trap_PointContents( const vec3_t point, int passEntityNum ) {
+ return syscall( G_POINT_CONTENTS, point, passEntityNum );
+}
+
+
+qboolean trap_InPVS( const vec3_t p1, const vec3_t p2 ) {
+ return syscall( G_IN_PVS, p1, p2 );
+}
+
+qboolean trap_InPVSIgnorePortals( const vec3_t p1, const vec3_t p2 ) {
+ return syscall( G_IN_PVS_IGNORE_PORTALS, p1, p2 );
+}
+
+void trap_AdjustAreaPortalState( gentity_t *ent, qboolean open ) {
+ syscall( G_ADJUST_AREA_PORTAL_STATE, ent, open );
+}
+
+qboolean trap_AreasConnected( int area1, int area2 ) {
+ return syscall( G_AREAS_CONNECTED, area1, area2 );
+}
+
+void trap_LinkEntity( gentity_t *ent ) {
+ syscall( G_LINKENTITY, ent );
+}
+
+void trap_UnlinkEntity( gentity_t *ent ) {
+ syscall( G_UNLINKENTITY, ent );
+}
+
+int trap_EntitiesInBox( const vec3_t mins, const vec3_t maxs, int *list, int maxcount ) {
+ return syscall( G_ENTITIES_IN_BOX, mins, maxs, list, maxcount );
+}
+
+qboolean trap_EntityContact( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ) {
+ return syscall( G_ENTITY_CONTACT, mins, maxs, ent );
+}
+
+qboolean trap_EntityContactCapsule( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ) {
+ return syscall( G_ENTITY_CONTACTCAPSULE, mins, maxs, ent );
+}
+
+int trap_BotAllocateClient( void ) {
+ return syscall( G_BOT_ALLOCATE_CLIENT );
+}
+
+void trap_BotFreeClient( int clientNum ) {
+ syscall( G_BOT_FREE_CLIENT, clientNum );
+}
+
+void trap_GetUsercmd( int clientNum, usercmd_t *cmd ) {
+ syscall( G_GET_USERCMD, clientNum, cmd );
+}
+
+qboolean trap_GetEntityToken( char *buffer, int bufferSize ) {
+ return syscall( G_GET_ENTITY_TOKEN, buffer, bufferSize );
+}
+
+int trap_DebugPolygonCreate(int color, int numPoints, vec3_t *points) {
+ return syscall( G_DEBUG_POLYGON_CREATE, color, numPoints, points );
+}
+
+void trap_DebugPolygonDelete(int id) {
+ syscall( G_DEBUG_POLYGON_DELETE, id );
+}
+
+int trap_RealTime( qtime_t *qtime ) {
+ return syscall( G_REAL_TIME, qtime );
+}
+
+void trap_SnapVector( float *v ) {
+ syscall( G_SNAPVECTOR, v );
+ return;
+}
+
+// BotLib traps start here
+int trap_BotLibSetup( void ) {
+ return syscall( BOTLIB_SETUP );
+}
+
+int trap_BotLibShutdown( void ) {
+ return syscall( BOTLIB_SHUTDOWN );
+}
+
+int trap_BotLibVarSet(char *var_name, char *value) {
+ return syscall( BOTLIB_LIBVAR_SET, var_name, value );
+}
+
+int trap_BotLibVarGet(char *var_name, char *value, int size) {
+ return syscall( BOTLIB_LIBVAR_GET, var_name, value, size );
+}
+
+int trap_BotLibDefine(char *string) {
+ return syscall( BOTLIB_PC_ADD_GLOBAL_DEFINE, string );
+}
+
+int trap_BotLibStartFrame(float time) {
+ return syscall( BOTLIB_START_FRAME, PASSFLOAT( time ) );
+}
+
+int trap_BotLibLoadMap(const char *mapname) {
+ return syscall( BOTLIB_LOAD_MAP, mapname );
+}
+
+int trap_BotLibUpdateEntity(int ent, void /* struct bot_updateentity_s */ *bue) {
+ return syscall( BOTLIB_UPDATENTITY, ent, bue );
+}
+
+int trap_BotLibTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3) {
+ return syscall( BOTLIB_TEST, parm0, parm1, parm2, parm3 );
+}
+
+int trap_BotGetSnapshotEntity( int clientNum, int sequence ) {
+ return syscall( BOTLIB_GET_SNAPSHOT_ENTITY, clientNum, sequence );
+}
+
+int trap_BotGetServerCommand(int clientNum, char *message, int size) {
+ return syscall( BOTLIB_GET_CONSOLE_MESSAGE, clientNum, message, size );
+}
+
+void trap_BotUserCommand(int clientNum, usercmd_t *ucmd) {
+ syscall( BOTLIB_USER_COMMAND, clientNum, ucmd );
+}
+
+void trap_AAS_EntityInfo(int entnum, void /* struct aas_entityinfo_s */ *info) {
+ syscall( BOTLIB_AAS_ENTITY_INFO, entnum, info );
+}
+
+int trap_AAS_Initialized(void) {
+ return syscall( BOTLIB_AAS_INITIALIZED );
+}
+
+void trap_AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs) {
+ syscall( BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX, presencetype, mins, maxs );
+}
+
+float trap_AAS_Time(void) {
+ floatint_t fi;
+ fi.i = syscall( BOTLIB_AAS_TIME );
+ return fi.f;
+}
+
+int trap_AAS_PointAreaNum(vec3_t point) {
+ return syscall( BOTLIB_AAS_POINT_AREA_NUM, point );
+}
+
+int trap_AAS_PointReachabilityAreaIndex(vec3_t point) {
+ return syscall( BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX, point );
+}
+
+int trap_AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas) {
+ return syscall( BOTLIB_AAS_TRACE_AREAS, start, end, areas, points, maxareas );
+}
+
+int trap_AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas) {
+ return syscall( BOTLIB_AAS_BBOX_AREAS, absmins, absmaxs, areas, maxareas );
+}
+
+int trap_AAS_AreaInfo( int areanum, void /* struct aas_areainfo_s */ *info ) {
+ return syscall( BOTLIB_AAS_AREA_INFO, areanum, info );
+}
+
+int trap_AAS_PointContents(vec3_t point) {
+ return syscall( BOTLIB_AAS_POINT_CONTENTS, point );
+}
+
+int trap_AAS_NextBSPEntity(int ent) {
+ return syscall( BOTLIB_AAS_NEXT_BSP_ENTITY, ent );
+}
+
+int trap_AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size) {
+ return syscall( BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY, ent, key, value, size );
+}
+
+int trap_AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v) {
+ return syscall( BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY, ent, key, v );
+}
+
+int trap_AAS_FloatForBSPEpairKey(int ent, char *key, float *value) {
+ return syscall( BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY, ent, key, value );
+}
+
+int trap_AAS_IntForBSPEpairKey(int ent, char *key, int *value) {
+ return syscall( BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY, ent, key, value );
+}
+
+int trap_AAS_AreaReachability(int areanum) {
+ return syscall( BOTLIB_AAS_AREA_REACHABILITY, areanum );
+}
+
+int trap_AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags) {
+ return syscall( BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA, areanum, origin, goalareanum, travelflags );
+}
+
+int trap_AAS_EnableRoutingArea( int areanum, int enable ) {
+ return syscall( BOTLIB_AAS_ENABLE_ROUTING_AREA, areanum, enable );
+}
+
+int trap_AAS_PredictRoute(void /*struct aas_predictroute_s*/ *route, int areanum, vec3_t origin,
+ int goalareanum, int travelflags, int maxareas, int maxtime,
+ int stopevent, int stopcontents, int stoptfl, int stopareanum) {
+ return syscall( BOTLIB_AAS_PREDICT_ROUTE, route, areanum, origin, goalareanum, travelflags, maxareas, maxtime, stopevent, stopcontents, stoptfl, stopareanum );
+}
+
+int trap_AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,
+ void /*struct aas_altroutegoal_s*/ *altroutegoals, int maxaltroutegoals,
+ int type) {
+ return syscall( BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL, start, startareanum, goal, goalareanum, travelflags, altroutegoals, maxaltroutegoals, type );
+}
+
+int trap_AAS_Swimming(vec3_t origin) {
+ return syscall( BOTLIB_AAS_SWIMMING, origin );
+}
+
+int trap_AAS_PredictClientMovement(void /* struct aas_clientmove_s */ *move, int entnum, vec3_t origin, int presencetype, int onground, vec3_t velocity, vec3_t cmdmove, int cmdframes, int maxframes, float frametime, int stopevent, int stopareanum, int visualize) {
+ return syscall( BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT, move, entnum, origin, presencetype, onground, velocity, cmdmove, cmdframes, maxframes, PASSFLOAT(frametime), stopevent, stopareanum, visualize );
+}
+
+void trap_EA_Say(int client, char *str) {
+ syscall( BOTLIB_EA_SAY, client, str );
+}
+
+void trap_EA_SayTeam(int client, char *str) {
+ syscall( BOTLIB_EA_SAY_TEAM, client, str );
+}
+
+void trap_EA_Command(int client, char *command) {
+ syscall( BOTLIB_EA_COMMAND, client, command );
+}
+
+void trap_EA_Action(int client, int action) {
+ syscall( BOTLIB_EA_ACTION, client, action );
+}
+
+void trap_EA_Gesture(int client) {
+ syscall( BOTLIB_EA_GESTURE, client );
+}
+
+void trap_EA_Talk(int client) {
+ syscall( BOTLIB_EA_TALK, client );
+}
+
+void trap_EA_Attack(int client) {
+ syscall( BOTLIB_EA_ATTACK, client );
+}
+
+void trap_EA_Use(int client) {
+ syscall( BOTLIB_EA_USE, client );
+}
+
+void trap_EA_Respawn(int client) {
+ syscall( BOTLIB_EA_RESPAWN, client );
+}
+
+void trap_EA_Crouch(int client) {
+ syscall( BOTLIB_EA_CROUCH, client );
+}
+
+void trap_EA_MoveUp(int client) {
+ syscall( BOTLIB_EA_MOVE_UP, client );
+}
+
+void trap_EA_MoveDown(int client) {
+ syscall( BOTLIB_EA_MOVE_DOWN, client );
+}
+
+void trap_EA_MoveForward(int client) {
+ syscall( BOTLIB_EA_MOVE_FORWARD, client );
+}
+
+void trap_EA_MoveBack(int client) {
+ syscall( BOTLIB_EA_MOVE_BACK, client );
+}
+
+void trap_EA_MoveLeft(int client) {
+ syscall( BOTLIB_EA_MOVE_LEFT, client );
+}
+
+void trap_EA_MoveRight(int client) {
+ syscall( BOTLIB_EA_MOVE_RIGHT, client );
+}
+
+void trap_EA_SelectWeapon(int client, int weapon) {
+ syscall( BOTLIB_EA_SELECT_WEAPON, client, weapon );
+}
+
+void trap_EA_Jump(int client) {
+ syscall( BOTLIB_EA_JUMP, client );
+}
+
+void trap_EA_DelayedJump(int client) {
+ syscall( BOTLIB_EA_DELAYED_JUMP, client );
+}
+
+void trap_EA_Move(int client, vec3_t dir, float speed) {
+ syscall( BOTLIB_EA_MOVE, client, dir, PASSFLOAT(speed) );
+}
+
+void trap_EA_View(int client, vec3_t viewangles) {
+ syscall( BOTLIB_EA_VIEW, client, viewangles );
+}
+
+void trap_EA_EndRegular(int client, float thinktime) {
+ syscall( BOTLIB_EA_END_REGULAR, client, PASSFLOAT(thinktime) );
+}
+
+void trap_EA_GetInput(int client, float thinktime, void /* struct bot_input_s */ *input) {
+ syscall( BOTLIB_EA_GET_INPUT, client, PASSFLOAT(thinktime), input );
+}
+
+void trap_EA_ResetInput(int client) {
+ syscall( BOTLIB_EA_RESET_INPUT, client );
+}
+
+int trap_BotLoadCharacter(char *charfile, float skill) {
+ return syscall( BOTLIB_AI_LOAD_CHARACTER, charfile, PASSFLOAT(skill));
+}
+
+void trap_BotFreeCharacter(int character) {
+ syscall( BOTLIB_AI_FREE_CHARACTER, character );
+}
+
+float trap_Characteristic_Float(int character, int index) {
+ floatint_t fi;
+ fi.i = syscall( BOTLIB_AI_CHARACTERISTIC_FLOAT, character, index );
+ return fi.f;
+}
+
+float trap_Characteristic_BFloat(int character, int index, float min, float max) {
+ floatint_t fi;
+ fi.i = syscall( BOTLIB_AI_CHARACTERISTIC_BFLOAT, character, index, PASSFLOAT(min), PASSFLOAT(max) );
+ return fi.f;
+}
+
+int trap_Characteristic_Integer(int character, int index) {
+ return syscall( BOTLIB_AI_CHARACTERISTIC_INTEGER, character, index );
+}
+
+int trap_Characteristic_BInteger(int character, int index, int min, int max) {
+ return syscall( BOTLIB_AI_CHARACTERISTIC_BINTEGER, character, index, min, max );
+}
+
+void trap_Characteristic_String(int character, int index, char *buf, int size) {
+ syscall( BOTLIB_AI_CHARACTERISTIC_STRING, character, index, buf, size );
+}
+
+int trap_BotAllocChatState(void) {
+ return syscall( BOTLIB_AI_ALLOC_CHAT_STATE );
+}
+
+void trap_BotFreeChatState(int handle) {
+ syscall( BOTLIB_AI_FREE_CHAT_STATE, handle );
+}
+
+void trap_BotQueueConsoleMessage(int chatstate, int type, char *message) {
+ syscall( BOTLIB_AI_QUEUE_CONSOLE_MESSAGE, chatstate, type, message );
+}
+
+void trap_BotRemoveConsoleMessage(int chatstate, int handle) {
+ syscall( BOTLIB_AI_REMOVE_CONSOLE_MESSAGE, chatstate, handle );
+}
+
+int trap_BotNextConsoleMessage(int chatstate, void /* struct bot_consolemessage_s */ *cm) {
+ return syscall( BOTLIB_AI_NEXT_CONSOLE_MESSAGE, chatstate, cm );
+}
+
+int trap_BotNumConsoleMessages(int chatstate) {
+ return syscall( BOTLIB_AI_NUM_CONSOLE_MESSAGE, chatstate );
+}
+
+void trap_BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 ) {
+ syscall( BOTLIB_AI_INITIAL_CHAT, chatstate, type, mcontext, var0, var1, var2, var3, var4, var5, var6, var7 );
+}
+
+int trap_BotNumInitialChats(int chatstate, char *type) {
+ return syscall( BOTLIB_AI_NUM_INITIAL_CHATS, chatstate, type );
+}
+
+int trap_BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 ) {
+ return syscall( BOTLIB_AI_REPLY_CHAT, chatstate, message, mcontext, vcontext, var0, var1, var2, var3, var4, var5, var6, var7 );
+}
+
+int trap_BotChatLength(int chatstate) {
+ return syscall( BOTLIB_AI_CHAT_LENGTH, chatstate );
+}
+
+void trap_BotEnterChat(int chatstate, int client, int sendto) {
+ syscall( BOTLIB_AI_ENTER_CHAT, chatstate, client, sendto );
+}
+
+void trap_BotGetChatMessage(int chatstate, char *buf, int size) {
+ syscall( BOTLIB_AI_GET_CHAT_MESSAGE, chatstate, buf, size);
+}
+
+int trap_StringContains(char *str1, char *str2, int casesensitive) {
+ return syscall( BOTLIB_AI_STRING_CONTAINS, str1, str2, casesensitive );
+}
+
+int trap_BotFindMatch(char *str, void /* struct bot_match_s */ *match, unsigned long int context) {
+ return syscall( BOTLIB_AI_FIND_MATCH, str, match, context );
+}
+
+void trap_BotMatchVariable(void /* struct bot_match_s */ *match, int variable, char *buf, int size) {
+ syscall( BOTLIB_AI_MATCH_VARIABLE, match, variable, buf, size );
+}
+
+void trap_UnifyWhiteSpaces(char *string) {
+ syscall( BOTLIB_AI_UNIFY_WHITE_SPACES, string );
+}
+
+void trap_BotReplaceSynonyms(char *string, unsigned long int context) {
+ syscall( BOTLIB_AI_REPLACE_SYNONYMS, string, context );
+}
+
+int trap_BotLoadChatFile(int chatstate, char *chatfile, char *chatname) {
+ return syscall( BOTLIB_AI_LOAD_CHAT_FILE, chatstate, chatfile, chatname );
+}
+
+void trap_BotSetChatGender(int chatstate, int gender) {
+ syscall( BOTLIB_AI_SET_CHAT_GENDER, chatstate, gender );
+}
+
+void trap_BotSetChatName(int chatstate, char *name, int client) {
+ syscall( BOTLIB_AI_SET_CHAT_NAME, chatstate, name, client );
+}
+
+void trap_BotResetGoalState(int goalstate) {
+ syscall( BOTLIB_AI_RESET_GOAL_STATE, goalstate );
+}
+
+void trap_BotResetAvoidGoals(int goalstate) {
+ syscall( BOTLIB_AI_RESET_AVOID_GOALS, goalstate );
+}
+
+void trap_BotRemoveFromAvoidGoals(int goalstate, int number) {
+ syscall( BOTLIB_AI_REMOVE_FROM_AVOID_GOALS, goalstate, number);
+}
+
+void trap_BotPushGoal(int goalstate, void /* struct bot_goal_s */ *goal) {
+ syscall( BOTLIB_AI_PUSH_GOAL, goalstate, goal );
+}
+
+void trap_BotPopGoal(int goalstate) {
+ syscall( BOTLIB_AI_POP_GOAL, goalstate );
+}
+
+void trap_BotEmptyGoalStack(int goalstate) {
+ syscall( BOTLIB_AI_EMPTY_GOAL_STACK, goalstate );
+}
+
+void trap_BotDumpAvoidGoals(int goalstate) {
+ syscall( BOTLIB_AI_DUMP_AVOID_GOALS, goalstate );
+}
+
+void trap_BotDumpGoalStack(int goalstate) {
+ syscall( BOTLIB_AI_DUMP_GOAL_STACK, goalstate );
+}
+
+void trap_BotGoalName(int number, char *name, int size) {
+ syscall( BOTLIB_AI_GOAL_NAME, number, name, size );
+}
+
+int trap_BotGetTopGoal(int goalstate, void /* struct bot_goal_s */ *goal) {
+ return syscall( BOTLIB_AI_GET_TOP_GOAL, goalstate, goal );
+}
+
+int trap_BotGetSecondGoal(int goalstate, void /* struct bot_goal_s */ *goal) {
+ return syscall( BOTLIB_AI_GET_SECOND_GOAL, goalstate, goal );
+}
+
+int trap_BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags) {
+ return syscall( BOTLIB_AI_CHOOSE_LTG_ITEM, goalstate, origin, inventory, travelflags );
+}
+
+int trap_BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, void /* struct bot_goal_s */ *ltg, float maxtime) {
+ return syscall( BOTLIB_AI_CHOOSE_NBG_ITEM, goalstate, origin, inventory, travelflags, ltg, PASSFLOAT(maxtime) );
+}
+
+int trap_BotTouchingGoal(vec3_t origin, void /* struct bot_goal_s */ *goal) {
+ return syscall( BOTLIB_AI_TOUCHING_GOAL, origin, goal );
+}
+
+int trap_BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, void /* struct bot_goal_s */ *goal) {
+ return syscall( BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE, viewer, eye, viewangles, goal );
+}
+
+int trap_BotGetLevelItemGoal(int index, char *classname, void /* struct bot_goal_s */ *goal) {
+ return syscall( BOTLIB_AI_GET_LEVEL_ITEM_GOAL, index, classname, goal );
+}
+
+int trap_BotGetNextCampSpotGoal(int num, void /* struct bot_goal_s */ *goal) {
+ return syscall( BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL, num, goal );
+}
+
+int trap_BotGetMapLocationGoal(char *name, void /* struct bot_goal_s */ *goal) {
+ return syscall( BOTLIB_AI_GET_MAP_LOCATION_GOAL, name, goal );
+}
+
+float trap_BotAvoidGoalTime(int goalstate, int number) {
+ floatint_t fi;
+ fi.i = syscall( BOTLIB_AI_AVOID_GOAL_TIME, goalstate, number );
+ return fi.f;
+}
+
+void trap_BotSetAvoidGoalTime(int goalstate, int number, float avoidtime) {
+ syscall( BOTLIB_AI_SET_AVOID_GOAL_TIME, goalstate, number, PASSFLOAT(avoidtime));
+}
+
+void trap_BotInitLevelItems(void) {
+ syscall( BOTLIB_AI_INIT_LEVEL_ITEMS );
+}
+
+void trap_BotUpdateEntityItems(void) {
+ syscall( BOTLIB_AI_UPDATE_ENTITY_ITEMS );
+}
+
+int trap_BotLoadItemWeights(int goalstate, char *filename) {
+ return syscall( BOTLIB_AI_LOAD_ITEM_WEIGHTS, goalstate, filename );
+}
+
+void trap_BotFreeItemWeights(int goalstate) {
+ syscall( BOTLIB_AI_FREE_ITEM_WEIGHTS, goalstate );
+}
+
+void trap_BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child) {
+ syscall( BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC, parent1, parent2, child );
+}
+
+void trap_BotSaveGoalFuzzyLogic(int goalstate, char *filename) {
+ syscall( BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC, goalstate, filename );
+}
+
+void trap_BotMutateGoalFuzzyLogic(int goalstate, float range) {
+ syscall( BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC, goalstate, range );
+}
+
+int trap_BotAllocGoalState(int state) {
+ return syscall( BOTLIB_AI_ALLOC_GOAL_STATE, state );
+}
+
+void trap_BotFreeGoalState(int handle) {
+ syscall( BOTLIB_AI_FREE_GOAL_STATE, handle );
+}
+
+void trap_BotResetMoveState(int movestate) {
+ syscall( BOTLIB_AI_RESET_MOVE_STATE, movestate );
+}
+
+void trap_BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type) {
+ syscall( BOTLIB_AI_ADD_AVOID_SPOT, movestate, origin, PASSFLOAT(radius), type);
+}
+
+void trap_BotMoveToGoal(void /* struct bot_moveresult_s */ *result, int movestate, void /* struct bot_goal_s */ *goal, int travelflags) {
+ syscall( BOTLIB_AI_MOVE_TO_GOAL, result, movestate, goal, travelflags );
+}
+
+int trap_BotMoveInDirection(int movestate, vec3_t dir, float speed, int type) {
+ return syscall( BOTLIB_AI_MOVE_IN_DIRECTION, movestate, dir, PASSFLOAT(speed), type );
+}
+
+void trap_BotResetAvoidReach(int movestate) {
+ syscall( BOTLIB_AI_RESET_AVOID_REACH, movestate );
+}
+
+void trap_BotResetLastAvoidReach(int movestate) {
+ syscall( BOTLIB_AI_RESET_LAST_AVOID_REACH,movestate );
+}
+
+int trap_BotReachabilityArea(vec3_t origin, int testground) {
+ return syscall( BOTLIB_AI_REACHABILITY_AREA, origin, testground );
+}
+
+int trap_BotMovementViewTarget(int movestate, void /* struct bot_goal_s */ *goal, int travelflags, float lookahead, vec3_t target) {
+ return syscall( BOTLIB_AI_MOVEMENT_VIEW_TARGET, movestate, goal, travelflags, PASSFLOAT(lookahead), target );
+}
+
+int trap_BotPredictVisiblePosition(vec3_t origin, int areanum, void /* struct bot_goal_s */ *goal, int travelflags, vec3_t target) {
+ return syscall( BOTLIB_AI_PREDICT_VISIBLE_POSITION, origin, areanum, goal, travelflags, target );
+}
+
+int trap_BotAllocMoveState(void) {
+ return syscall( BOTLIB_AI_ALLOC_MOVE_STATE );
+}
+
+void trap_BotFreeMoveState(int handle) {
+ syscall( BOTLIB_AI_FREE_MOVE_STATE, handle );
+}
+
+void trap_BotInitMoveState(int handle, void /* struct bot_initmove_s */ *initmove) {
+ syscall( BOTLIB_AI_INIT_MOVE_STATE, handle, initmove );
+}
+
+int trap_BotChooseBestFightWeapon(int weaponstate, int *inventory) {
+ return syscall( BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON, weaponstate, inventory );
+}
+
+void trap_BotGetWeaponInfo(int weaponstate, int weapon, void /* struct weaponinfo_s */ *weaponinfo) {
+ syscall( BOTLIB_AI_GET_WEAPON_INFO, weaponstate, weapon, weaponinfo );
+}
+
+int trap_BotLoadWeaponWeights(int weaponstate, char *filename) {
+ return syscall( BOTLIB_AI_LOAD_WEAPON_WEIGHTS, weaponstate, filename );
+}
+
+int trap_BotAllocWeaponState(void) {
+ return syscall( BOTLIB_AI_ALLOC_WEAPON_STATE );
+}
+
+void trap_BotFreeWeaponState(int weaponstate) {
+ syscall( BOTLIB_AI_FREE_WEAPON_STATE, weaponstate );
+}
+
+void trap_BotResetWeaponState(int weaponstate) {
+ syscall( BOTLIB_AI_RESET_WEAPON_STATE, weaponstate );
+}
+
+int trap_GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child) {
+ return syscall( BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION, numranks, ranks, parent1, parent2, child );
+}
+
+int trap_PC_LoadSource( const char *filename ) {
+ return syscall( BOTLIB_PC_LOAD_SOURCE, filename );
+}
+
+int trap_PC_FreeSource( int handle ) {
+ return syscall( BOTLIB_PC_FREE_SOURCE, handle );
+}
+
+int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) {
+ return syscall( BOTLIB_PC_READ_TOKEN, handle, pc_token );
+}
+
+int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) {
+ return syscall( BOTLIB_PC_SOURCE_FILE_AND_LINE, handle, filename, line );
+}
diff --git a/game/code/game/g_target.c b/code/game/g_target.c
similarity index 100%
rename from game/code/game/g_target.c
rename to code/game/g_target.c
diff --git a/code/game/g_team.c b/code/game/g_team.c
new file mode 100644
index 0000000..be5ed65
--- /dev/null
+++ b/code/game/g_team.c
@@ -0,0 +1,2209 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Open Arena source code.
+Portions copied from Tremulous under GPL version 2 including any later version.
+
+Open Arena source code 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.
+
+Open Arena source code 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 Open Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+#include "g_local.h"
+
+
+typedef struct teamgame_s {
+ float last_flag_capture;
+ int last_capture_team;
+ flagStatus_t redStatus; // CTF
+ flagStatus_t blueStatus; // CTF
+ flagStatus_t flagStatus; // One Flag CTF
+ int redTakenTime;
+ int blueTakenTime;
+ int redObeliskAttackedTime;
+ int blueObeliskAttackedTime;
+} teamgame_t;
+
+teamgame_t teamgame;
+
+gentity_t *neutralObelisk;
+
+//Some pointers for Double Domination so we don't need GFind (I think it might crash at random times...)
+gentity_t *ddA;
+gentity_t *ddB;
+//Pointers for Standard Domination
+gentity_t *dom_points[MAX_DOMINATION_POINTS];
+
+void Team_SetFlagStatus( int team, flagStatus_t status );
+
+qboolean dominationPointsSpawned;
+
+void Team_InitGame( void ) {
+ memset(&teamgame, 0, sizeof teamgame);
+
+ switch( g_gametype.integer ) {
+ case GT_CTF:
+ case GT_CTF_ELIMINATION:
+ case GT_DOUBLE_D:
+ teamgame.redStatus = -1; // Invalid to force update
+ Team_SetFlagStatus( TEAM_RED, FLAG_ATBASE );
+ teamgame.blueStatus = -1; // Invalid to force update
+ Team_SetFlagStatus( TEAM_BLUE, FLAG_ATBASE );
+ ddA = NULL;
+ ddB = NULL;
+ break;
+ case GT_DOMINATION:
+ dominationPointsSpawned = qfalse;
+ break;
+ case GT_1FCTF:
+ teamgame.flagStatus = -1; // Invalid to force update
+ Team_SetFlagStatus( TEAM_FREE, FLAG_ATBASE );
+ break;
+ default:
+ break;
+ }
+}
+
+int OtherTeam(int team) {
+ if (team==TEAM_RED)
+ return TEAM_BLUE;
+ else if (team==TEAM_BLUE)
+ return TEAM_RED;
+ return team;
+}
+
+const char *TeamName(int team) {
+ if (team==TEAM_RED)
+ return "RED";
+ else if (team==TEAM_BLUE)
+ return "BLUE";
+ else if (team==TEAM_SPECTATOR)
+ return "SPECTATOR";
+ return "FREE";
+}
+
+const char *OtherTeamName(int team) {
+ if (team==TEAM_RED)
+ return "BLUE";
+ else if (team==TEAM_BLUE)
+ return "RED";
+ else if (team==TEAM_SPECTATOR)
+ return "SPECTATOR";
+ return "FREE";
+}
+
+const char *TeamColorString(int team) {
+ if (team==TEAM_RED)
+ return S_COLOR_RED;
+ else if (team==TEAM_BLUE)
+ return S_COLOR_BLUE;
+ else if (team==TEAM_SPECTATOR)
+ return S_COLOR_YELLOW;
+ return S_COLOR_WHITE;
+}
+
+// NULL for everyone
+void QDECL PrintMsg( gentity_t *ent, const char *fmt, ... ) {
+ char msg[1024];
+ va_list argptr;
+ char *p;
+
+ va_start (argptr,fmt);
+ if (Q_vsnprintf (msg, sizeof(msg), fmt, argptr) >= sizeof(msg)) {
+ G_Error ( "PrintMsg overrun" );
+ }
+ va_end (argptr);
+
+ // double quotes are bad
+ while ((p = strchr(msg, '"')) != NULL)
+ *p = '\'';
+
+ trap_SendServerCommand ( ( (ent == NULL) ? -1 : ent-g_entities ), va("print \"%s\"", msg ));
+}
+
+/*
+================
+KK-OAX From Tremulous
+G_TeamFromString
+Return the team referenced by a string
+================
+*/
+team_t G_TeamFromString( char *str )
+{
+ switch( tolower( *str ) )
+ {
+ case '0': case 's': return TEAM_NONE;
+ case '1': case 'f': return TEAM_FREE;
+ case '2': case 'r': return TEAM_RED;
+ case '3': case 'b': return TEAM_BLUE;
+ default: return TEAM_NUM_TEAMS;
+ }
+}
+
+/*
+==============
+AddTeamScore
+
+ used for gametype > GT_TEAM
+ for gametype GT_TEAM the level.teamScores is updated in AddScore in g_combat.c
+==============
+*/
+void AddTeamScore(vec3_t origin, int team, int score) {
+ gentity_t *te;
+
+
+ if ( g_gametype.integer != GT_DOMINATION ) {
+ te = G_TempEntity(origin, EV_GLOBAL_TEAM_SOUND );
+ te->r.svFlags |= SVF_BROADCAST;
+
+
+
+ if ( team == TEAM_RED ) {
+ if ( level.teamScores[ TEAM_RED ] + score == level.teamScores[ TEAM_BLUE ] ) {
+ //teams are tied sound
+ te->s.eventParm = GTS_TEAMS_ARE_TIED;
+ }
+ else if ( level.teamScores[ TEAM_RED ] <= level.teamScores[ TEAM_BLUE ] &&
+ level.teamScores[ TEAM_RED ] + score > level.teamScores[ TEAM_BLUE ]) {
+ // red took the lead sound
+ te->s.eventParm = GTS_REDTEAM_TOOK_LEAD;
+ }
+ else {
+ // red scored sound
+ te->s.eventParm = GTS_REDTEAM_SCORED;
+ }
+ }
+ else {
+ if ( level.teamScores[ TEAM_BLUE ] + score == level.teamScores[ TEAM_RED ] ) {
+ //teams are tied sound
+ te->s.eventParm = GTS_TEAMS_ARE_TIED;
+ }
+ else if ( level.teamScores[ TEAM_BLUE ] <= level.teamScores[ TEAM_RED ] &&
+ level.teamScores[ TEAM_BLUE ] + score > level.teamScores[ TEAM_RED ]) {
+ // blue took the lead sound
+ te->s.eventParm = GTS_BLUETEAM_TOOK_LEAD;
+ }
+ else {
+ // blue scored sound
+ te->s.eventParm = GTS_BLUETEAM_SCORED;
+ }
+ }
+ }
+ level.teamScores[ team ] += score;
+}
+
+/*
+==============
+OnSameTeam
+==============
+*/
+qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 ) {
+ if ( !ent1->client || !ent2->client ) {
+ return qfalse;
+ }
+
+ if ( g_gametype.integer < GT_TEAM || g_ffa_gt==1) {
+ return qfalse;
+ }
+
+ if ( ent1->client->sess.sessionTeam == ent2->client->sess.sessionTeam ) {
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+
+static char ctfFlagStatusRemap[] = { '0', '1', '*', '*', '2' };
+static char oneFlagStatusRemap[] = { '0', '1', '2', '3', '4' };
+
+void Team_SetFlagStatus( int team, flagStatus_t status ) {
+ qboolean modified = qfalse;
+
+ switch( team ) {
+ case TEAM_RED: // CTF
+ if( teamgame.redStatus != status ) {
+ teamgame.redStatus = status;
+ modified = qtrue;
+ }
+ break;
+
+ case TEAM_BLUE: // CTF
+ if( teamgame.blueStatus != status ) {
+ teamgame.blueStatus = status;
+ modified = qtrue;
+ }
+ break;
+
+ case TEAM_FREE: // One Flag CTF
+ if( teamgame.flagStatus != status ) {
+ teamgame.flagStatus = status;
+ modified = qtrue;
+ }
+ break;
+ }
+
+
+ if( modified ) {
+ char st[4];
+
+ if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTF_ELIMINATION) {
+ st[0] = ctfFlagStatusRemap[teamgame.redStatus];
+ st[1] = ctfFlagStatusRemap[teamgame.blueStatus];
+ st[2] = 0;
+ }
+ else if (g_gametype.integer == GT_DOUBLE_D) {
+ st[0] = oneFlagStatusRemap[teamgame.redStatus];
+ st[1] = oneFlagStatusRemap[teamgame.blueStatus];
+ st[2] = 0;
+ }
+ else { // GT_1FCTF
+ st[0] = oneFlagStatusRemap[teamgame.flagStatus];
+ st[1] = 0;
+ }
+
+ trap_SetConfigstring( CS_FLAGSTATUS, st );
+ }
+}
+
+void Team_CheckDroppedItem( gentity_t *dropped ) {
+ if( dropped->item->giTag == PW_REDFLAG ) {
+ Team_SetFlagStatus( TEAM_RED, FLAG_DROPPED );
+ }
+ else if( dropped->item->giTag == PW_BLUEFLAG ) {
+ Team_SetFlagStatus( TEAM_BLUE, FLAG_DROPPED );
+ }
+ else if( dropped->item->giTag == PW_NEUTRALFLAG ) {
+ Team_SetFlagStatus( TEAM_FREE, FLAG_DROPPED );
+ }
+}
+
+/*
+================
+Team_ForceGesture
+================
+*/
+void Team_ForceGesture(int team) {
+ int i;
+ gentity_t *ent;
+
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ ent = &g_entities[i];
+ if (!ent->inuse)
+ continue;
+ if (!ent->client)
+ continue;
+ if (ent->client->sess.sessionTeam != team)
+ continue;
+ ent->flags |= FL_FORCE_GESTURE;
+ }
+}
+
+/*
+================
+Team_DD_bonusAtPoints
+Adds bonus point to a player if he is close to the point and on the team that scores
+================
+*/
+
+void Team_DD_bonusAtPoints(int team) {
+ vec3_t v1, v2;
+ int i;
+ gentity_t *player;
+
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ player = &g_entities[i];
+ if (!player->inuse)
+ continue;
+ if (!player->client)
+ continue;
+
+ if( player->client->sess.sessionTeam != team )
+ return; //player was not on scoring team
+
+ //See if the player is close to any of the points:
+ VectorSubtract(player->r.currentOrigin, ddA->r.currentOrigin, v1);
+ VectorSubtract(player->r.currentOrigin, ddB->r.currentOrigin, v2);
+ if (!( ( ( VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS &&
+ trap_InPVS(ddA->r.currentOrigin, player->r.currentOrigin ) ) ||
+ ( VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS &&
+ trap_InPVS(ddB->r.currentOrigin, player->r.currentOrigin ) ) )))
+ return; //Wasn't close to any of the points
+
+ AddScore(player, player->r.currentOrigin, DD_AT_POINT_AT_CAPTURE);
+ }
+}
+
+/*
+================
+Team_FragBonuses
+
+Calculate the bonuses for flag defense, flag carrier defense, etc.
+Note that bonuses are not cumulative. You get one, they are in importance
+order.
+================
+*/
+void Team_FragBonuses(gentity_t *targ, gentity_t *inflictor, gentity_t *attacker)
+{
+ int i;
+ gentity_t *ent;
+ int flag_pw, enemy_flag_pw;
+ int otherteam;
+ int tokens;
+ gentity_t *flag, *carrier = NULL;
+ char *c;
+ vec3_t v1, v2;
+ int team;
+
+ // no bonus for fragging yourself or team mates
+ if (!targ->client || !attacker->client || targ == attacker || OnSameTeam(targ, attacker))
+ return;
+
+ team = targ->client->sess.sessionTeam;
+ otherteam = OtherTeam(targ->client->sess.sessionTeam);
+ if (otherteam < 0)
+ return; // whoever died isn't on a team
+
+ // same team, if the flag at base, check to he has the enemy flag
+ if (team == TEAM_RED) {
+ flag_pw = PW_REDFLAG;
+ enemy_flag_pw = PW_BLUEFLAG;
+ } else {
+ flag_pw = PW_BLUEFLAG;
+ enemy_flag_pw = PW_REDFLAG;
+ }
+
+ if (g_gametype.integer == GT_1FCTF) {
+ enemy_flag_pw = PW_NEUTRALFLAG;
+ }
+
+ // did the attacker frag the flag carrier?
+ tokens = 0;
+ if( g_gametype.integer == GT_HARVESTER ) {
+ tokens = targ->client->ps.generic1;
+ }
+ if (targ->client->ps.powerups[enemy_flag_pw]) {
+ attacker->client->pers.teamState.lastfraggedcarrier = level.time;
+ AddScore(attacker, targ->r.currentOrigin, CTF_FRAG_CARRIER_BONUS);
+ attacker->client->pers.teamState.fragcarrier++;
+ PrintMsg(NULL, "%s" S_COLOR_WHITE " fragged %s's flag carrier!\n",
+ attacker->client->pers.netname, TeamName(team));
+ if(g_gametype.integer == GT_CTF) {
+ G_LogPrintf( "CTF: %i %i %i: %s fragged %s's flag carrier!\n", attacker->client->ps.clientNum, team, 3, attacker->client->pers.netname, TeamName(team) );
+ } else if(g_gametype.integer == GT_CTF_ELIMINATION) {
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s fragged %s's flag carrier!\n", level.roundNumber, attacker->client->ps.clientNum, team, 3, attacker->client->pers.netname, TeamName(team) );
+ } else if(g_gametype.integer == GT_1FCTF) {
+ G_LogPrintf( "1fCTF: %i %i %i: %s fragged %s's flag carrier!\n", attacker->client->ps.clientNum, team, 3, attacker->client->pers.netname, TeamName(team) );
+ }
+
+
+ // the target had the flag, clear the hurt carrier
+ // field on the other team
+ for (i = 0; i < g_maxclients.integer; i++) {
+ ent = g_entities + i;
+ if (ent->inuse && ent->client->sess.sessionTeam == otherteam)
+ ent->client->pers.teamState.lasthurtcarrier = 0;
+ }
+ return;
+ }
+
+ // did the attacker frag a head carrier? other->client->ps.generic1
+ if (tokens) {
+ attacker->client->pers.teamState.lastfraggedcarrier = level.time;
+ AddScore(attacker, targ->r.currentOrigin, CTF_FRAG_CARRIER_BONUS * tokens * tokens);
+ attacker->client->pers.teamState.fragcarrier++;
+ PrintMsg(NULL, "%s" S_COLOR_WHITE " fragged %s's skull carrier!\n",
+ attacker->client->pers.netname, TeamName(team));
+
+ G_LogPrintf("HARVESTER: %i %i %i %i %i: %s fragged %s (%s) who had %i skulls.\n",
+ attacker->client->ps.clientNum, team, 1, targ->client->ps.clientNum, tokens,
+ attacker->client->pers.netname, targ->client->pers.netname,TeamName(team),tokens);
+
+ // the target had the flag, clear the hurt carrier
+ // field on the other team
+ for (i = 0; i < g_maxclients.integer; i++) {
+ ent = g_entities + i;
+ if (ent->inuse && ent->client->sess.sessionTeam == otherteam)
+ ent->client->pers.teamState.lasthurtcarrier = 0;
+ }
+ return;
+ }
+
+ if (targ->client->pers.teamState.lasthurtcarrier &&
+ level.time - targ->client->pers.teamState.lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT &&
+ !attacker->client->ps.powerups[flag_pw]) {
+ // attacker is on the same team as the flag carrier and
+ // fragged a guy who hurt our flag carrier
+ AddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_DANGER_PROTECT_BONUS);
+
+ attacker->client->pers.teamState.carrierdefense++;
+ targ->client->pers.teamState.lasthurtcarrier = 0;
+
+ attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 3, attacker->client->pers.netname, "DEFENCE" );
+ if(!level.hadBots)
+ ChallengeMessage(attacker,AWARD_DEFENCE);
+ team = attacker->client->sess.sessionTeam;
+ // add the sprite over the player's head
+ attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
+ attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+
+ return;
+ }
+
+ if (targ->client->pers.teamState.lasthurtcarrier &&
+ level.time - targ->client->pers.teamState.lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT) {
+ // attacker is on the same team as the skull carrier and
+ AddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_DANGER_PROTECT_BONUS);
+
+ attacker->client->pers.teamState.carrierdefense++;
+ targ->client->pers.teamState.lasthurtcarrier = 0;
+
+ attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
+ if(!level.hadBots)
+ ChallengeMessage(attacker,AWARD_DEFENCE);
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 3, attacker->client->pers.netname, "DEFENCE" );
+ team = attacker->client->sess.sessionTeam;
+ // add the sprite over the player's head
+ attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
+ attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+
+ return;
+ }
+
+//We place the Double Domination bonus test here! This appears to be the best place to place them.
+ if ( g_gametype.integer == GT_DOUBLE_D ) {
+ if(attacker->client->sess.sessionTeam == level.pointStatusA ) { //Attack must defend point A
+ //See how close attacker and target was to Point A:
+ VectorSubtract(targ->r.currentOrigin, ddA->r.currentOrigin, v1);
+ VectorSubtract(attacker->r.currentOrigin, ddA->r.currentOrigin, v2);
+
+ if ( ( ( VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS &&
+ trap_InPVS(ddA->r.currentOrigin, targ->r.currentOrigin ) ) ||
+ ( VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS &&
+ trap_InPVS(ddA->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&
+ attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam) {
+
+ //We defended point A
+ //Was we dominating and maybe close to score?
+ if(attacker->client->sess.sessionTeam == level.pointStatusB && level.time - level.timeTaken > (10-DD_CLOSE)*1000)
+ AddScore(attacker, targ->r.currentOrigin, DD_POINT_DEFENCE_CLOSE_BONUS);
+ else
+ AddScore(attacker, targ->r.currentOrigin, DD_POINT_DEFENCE_BONUS);
+ attacker->client->pers.teamState.basedefense++;
+
+ attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 3, attacker->client->pers.netname, "DEFENCE" );
+ if(!level.hadBots)
+ ChallengeMessage(attacker,AWARD_DEFENCE);
+ // add the sprite over the player's head
+ attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
+ attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+
+ return; //Return so we don't recieve credits for point B also
+
+ } //We denfended point A
+
+
+
+ } //Defend point A
+
+ if(attacker->client->sess.sessionTeam == level.pointStatusB ) { //Attack must defend point B
+ //See how close attacker and target was to Point B:
+ VectorSubtract(targ->r.currentOrigin, ddB->r.currentOrigin, v1);
+ VectorSubtract(attacker->r.currentOrigin, ddB->r.currentOrigin, v2);
+
+ if ( ( ( VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS &&
+ trap_InPVS(ddB->r.currentOrigin, targ->r.currentOrigin ) ) ||
+ ( VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS &&
+ trap_InPVS(ddB->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&
+ attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam) {
+
+ //We defended point B
+ //Was we dominating and maybe close to score?
+ if(attacker->client->sess.sessionTeam == level.pointStatusA && level.time - level.timeTaken > (10-DD_CLOSE)*1000)
+ AddScore(attacker, targ->r.currentOrigin, DD_POINT_DEFENCE_CLOSE_BONUS);
+ else
+ AddScore(attacker, targ->r.currentOrigin, DD_POINT_DEFENCE_BONUS);
+ attacker->client->pers.teamState.basedefense++;
+
+ attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
+ if(!level.hadBots)
+ ChallengeMessage(attacker,AWARD_DEFENCE);
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 3, attacker->client->pers.netname, "DEFENCE" );
+ // add the sprite over the player's head
+ attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
+ attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+
+ return;
+
+ } //We denfended point B
+
+
+
+ } //Defend point B
+ return; //In double Domination we shall not go on, or we would test for team bases that we don't use
+ }
+
+ // flag and flag carrier area defense bonuses
+
+ // we have to find the flag and carrier entities
+
+ if( g_gametype.integer == GT_OBELISK ) {
+ // find the team obelisk
+ switch (attacker->client->sess.sessionTeam) {
+ case TEAM_RED:
+ c = "team_redobelisk";
+ break;
+ case TEAM_BLUE:
+ c = "team_blueobelisk";
+ break;
+ default:
+ return;
+ }
+
+ } else if (g_gametype.integer == GT_HARVESTER ) {
+ // find the center obelisk
+ c = "team_neutralobelisk";
+ } else {
+ // find the flag
+ switch (attacker->client->sess.sessionTeam) {
+ case TEAM_RED:
+ c = "team_CTF_redflag";
+ break;
+ case TEAM_BLUE:
+ c = "team_CTF_blueflag";
+ break;
+ default:
+ return;
+ }
+ // find attacker's team's flag carrier
+ for (i = 0; i < g_maxclients.integer; i++) {
+ carrier = g_entities + i;
+ if (carrier->inuse && carrier->client->ps.powerups[flag_pw])
+ break;
+ carrier = NULL;
+ }
+ }
+ flag = NULL;
+ while ((flag = G_Find (flag, FOFS(classname), c)) != NULL) {
+ if (!(flag->flags & FL_DROPPED_ITEM))
+ break;
+ }
+
+ if (!flag)
+ return; // can't find attacker's flag
+
+ // ok we have the attackers flag and a pointer to the carrier
+
+ // check to see if we are defending the base's flag
+ VectorSubtract(targ->r.currentOrigin, flag->r.currentOrigin, v1);
+ VectorSubtract(attacker->r.currentOrigin, flag->r.currentOrigin, v2);
+
+ if ( ( ( VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS &&
+ trap_InPVS(flag->r.currentOrigin, targ->r.currentOrigin ) ) ||
+ ( VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS &&
+ trap_InPVS(flag->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&
+ attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam && g_gametype.integer != GT_ELIMINATION &&
+ (g_gametype.integer != GT_CTF_ELIMINATION || !g_elimination_ctf_oneway.integer ||
+ ((level.eliminationSides+level.roundNumber)%2 == 0 && attacker->client->sess.sessionTeam == TEAM_BLUE ) ||
+ ((level.eliminationSides+level.roundNumber)%2 == 1 && attacker->client->sess.sessionTeam == TEAM_RED ) ) ) {
+
+ // we defended the base flag
+ AddScore(attacker, targ->r.currentOrigin, CTF_FLAG_DEFENSE_BONUS);
+ attacker->client->pers.teamState.basedefense++;
+
+ attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
+ if(!level.hadBots)
+ ChallengeMessage(attacker,AWARD_DEFENCE);
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 3, attacker->client->pers.netname, "DEFENCE" );
+ // add the sprite over the player's head
+ attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
+ attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+
+ return;
+ }
+
+ if (carrier && carrier != attacker) {
+ VectorSubtract(targ->r.currentOrigin, carrier->r.currentOrigin, v1);
+ VectorSubtract(attacker->r.currentOrigin, carrier->r.currentOrigin, v1);
+
+ if ( ( ( VectorLength(v1) < CTF_ATTACKER_PROTECT_RADIUS &&
+ trap_InPVS(carrier->r.currentOrigin, targ->r.currentOrigin ) ) ||
+ ( VectorLength(v2) < CTF_ATTACKER_PROTECT_RADIUS &&
+ trap_InPVS(carrier->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&
+ attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam) {
+ AddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_PROTECT_BONUS);
+ attacker->client->pers.teamState.carrierdefense++;
+
+ attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
+ if(!level.hadBots)
+ ChallengeMessage(attacker,AWARD_DEFENCE);
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 3, attacker->client->pers.netname, "DEFENCE" );
+ // add the sprite over the player's head
+ attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
+ attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+
+ return;
+ }
+ }
+}
+
+/*
+================
+Team_CheckHurtCarrier
+
+Check to see if attacker hurt the flag carrier. Needed when handing out bonuses for assistance to flag
+carrier defense.
+================
+*/
+void Team_CheckHurtCarrier(gentity_t *targ, gentity_t *attacker)
+{
+ int flag_pw;
+
+ if (!targ->client || !attacker->client)
+ return;
+
+ if (targ->client->sess.sessionTeam == TEAM_RED)
+ flag_pw = PW_BLUEFLAG;
+ else
+ flag_pw = PW_REDFLAG;
+
+ // flags
+ if (targ->client->ps.powerups[flag_pw] &&
+ targ->client->sess.sessionTeam != attacker->client->sess.sessionTeam)
+ attacker->client->pers.teamState.lasthurtcarrier = level.time;
+
+ // skulls
+ if (targ->client->ps.generic1 &&
+ targ->client->sess.sessionTeam != attacker->client->sess.sessionTeam)
+ attacker->client->pers.teamState.lasthurtcarrier = level.time;
+}
+
+
+gentity_t *Team_ResetFlag( int team ) {
+ char *c;
+ gentity_t *ent, *rent = NULL;
+
+ switch (team) {
+ case TEAM_RED:
+ c = "team_CTF_redflag";
+ break;
+ case TEAM_BLUE:
+ c = "team_CTF_blueflag";
+ break;
+ case TEAM_FREE:
+ c = "team_CTF_neutralflag";
+ break;
+ default:
+ return NULL;
+ }
+
+ ent = NULL;
+ while ((ent = G_Find (ent, FOFS(classname), c)) != NULL) {
+ if (ent->flags & FL_DROPPED_ITEM)
+ G_FreeEntity(ent);
+ else {
+ rent = ent;
+ RespawnItem(ent);
+ }
+ }
+
+ Team_SetFlagStatus( team, FLAG_ATBASE );
+
+ return rent;
+}
+
+//Functions for Domination
+
+void Team_Dom_SpawnPoints( void ) {
+ char *c;
+ gentity_t *flag;
+ int i;
+ gitem_t *it;
+
+ flag = NULL;
+
+ if(dominationPointsSpawned)
+ return;
+ dominationPointsSpawned = qtrue;
+
+ it = NULL;
+ it = BG_FindItem ("Neutral domination point");
+ if(it == NULL) {
+ PrintMsg( NULL, "No domination item\n");
+ return;
+ } else {
+ PrintMsg( NULL, "Domination item found\n");
+ }
+ i = 0;
+ c = "domination_point";
+
+ //return; Just to test, the lines below crashes game
+
+ while ((flag = G_Find (flag, FOFS(classname), c)) != NULL) {
+ if(i>=MAX_DOMINATION_POINTS)
+ break;
+ //domination_points_names[i] = flag->message;
+ if(flag->message) {
+ Q_strncpyz(level.domination_points_names[i],flag->message,MAX_DOMINATION_POINTS_NAMES-1);
+ PrintMsg( NULL, "Domination point \'%s\' found\n",level.domination_points_names[i]);
+ } else {
+ Q_strncpyz(level.domination_points_names[i],va("Point %i",i),MAX_DOMINATION_POINTS_NAMES-1);
+ PrintMsg( NULL, "Domination point \'%s\' found (autonamed)\n",level.domination_points_names[i]);
+ }
+ dom_points[i] = G_Spawn();
+ VectorCopy( flag->r.currentOrigin, dom_points[i]->s.origin );
+ dom_points[i]->classname = it->classname;
+ G_SpawnItem(dom_points[i], it);
+ FinishSpawningItem(dom_points[i] );
+
+ i++;
+ }
+ level.domination_points_count = i;
+}
+
+int getDomPointNumber( gentity_t *point ) {
+ int i;
+ for(i=1;i<MAX_DOMINATION_POINTS && i<level.domination_points_count;i++) {
+ if(dom_points[i] == NULL)
+ return 0; //Not found, just return first, so we don't crash
+ if(dom_points[i] == point)
+ return i;
+ }
+ return 0;
+}
+
+void Team_Dom_TakePoint( gentity_t *point, int team, int clientnumber ) {
+ gitem_t *it;
+ vec3_t origin;
+ int i;
+ i = getDomPointNumber(point);
+ if(i<0)
+ i = 0;
+ if(i>=MAX_DOMINATION_POINTS)
+ i = MAX_DOMINATION_POINTS - 1;
+
+ it = NULL;
+ VectorCopy( point->r.currentOrigin, origin );
+
+ if(team == TEAM_RED) {
+ it = BG_FindItem ("Red domination point");
+ PrintMsg( NULL, "Red took \'%s\'\n",level.domination_points_names[i]);
+ } else
+ if(team == TEAM_BLUE) {
+ it = BG_FindItem ("Blue domination point");
+ PrintMsg( NULL, "Blue took \'%s\'\n",level.domination_points_names[i]);
+ }
+ if (!it || it == NULL) {
+ PrintMsg( NULL, "No item\n");
+ return;
+ }
+
+ G_FreeEntity(point);
+
+ point = G_Spawn();
+
+ VectorCopy( origin, point->s.origin );
+ point->classname = it->classname;
+ dom_points[i] = point;
+ G_SpawnItem(point, it);
+ FinishSpawningItem( point );
+ level.pointStatusDom[i] = team;
+ G_LogPrintf( "DOM: %i %i %i %i: %s takes point %s!\n",
+ clientnumber,i,0,team,
+ TeamName(team),level.domination_points_names[i]);
+ SendDominationPointsStatusMessageToAllClients();
+}
+
+//Functions for Double Domination
+
+void Team_DD_RemovePointAgfx( void ) {
+ if(ddA!=NULL) {
+ G_FreeEntity(ddA);
+ ddA = NULL;
+ }
+}
+
+void Team_DD_RemovePointBgfx( void ) {
+ if(ddB!=NULL) {
+ G_FreeEntity(ddB);
+ ddB = NULL;
+ }
+}
+
+void Team_DD_makeA2team( gentity_t *target, int team ) {
+ gitem_t *it;
+ //gentity_t *it_ent;
+ Team_DD_RemovePointAgfx();
+ it = NULL;
+ if(team == TEAM_NONE)
+ return;
+ if(team == TEAM_RED)
+ it = BG_FindItem ("Point A (Red)");
+ if(team == TEAM_BLUE)
+ it = BG_FindItem ("Point A (Blue)");
+ if(team == TEAM_FREE)
+ it = BG_FindItem ("Point A (White)");
+ if (!it || it == NULL) {
+ PrintMsg( NULL, "No item\n");
+ return;
+ }
+ ddA = G_Spawn();
+
+ VectorCopy( target->r.currentOrigin, ddA->s.origin );
+ ddA->classname = it->classname;
+ G_SpawnItem(ddA, it);
+ FinishSpawningItem(ddA );
+}
+
+void Team_DD_makeB2team( gentity_t *target, int team ) {
+ gitem_t *it;
+ //gentity_t *it_ent;
+
+ Team_DD_RemovePointBgfx();
+ it = NULL;
+ if(team == TEAM_NONE)
+ return;
+ if(team == TEAM_RED)
+ it = BG_FindItem ("Point B (Red)");
+ if(team == TEAM_BLUE)
+ it = BG_FindItem ("Point B (Blue)");
+ if(team == TEAM_FREE)
+ it = BG_FindItem ("Point B (White)");
+ if (!it || it == NULL) {
+ PrintMsg( NULL, "No item\n");
+ return;
+ }
+ ddB = G_Spawn();
+
+ VectorCopy( target->r.currentOrigin, ddB->s.origin );
+ ddB->classname = it->classname;
+ G_SpawnItem(ddB, it);
+ FinishSpawningItem(ddB );
+}
+
+void Team_ResetFlags( void ) {
+ if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTF_ELIMINATION) {
+ Team_ResetFlag( TEAM_RED );
+ Team_ResetFlag( TEAM_BLUE );
+ }
+ else if( g_gametype.integer == GT_1FCTF ) {
+ Team_ResetFlag( TEAM_FREE );
+ }
+}
+
+void Team_ReturnFlagSound( gentity_t *ent, int team ) {
+ gentity_t *te;
+
+ if (ent == NULL) {
+ G_Printf ("Warning: NULL passed to Team_ReturnFlagSound\n");
+ return;
+ }
+
+ //See if we are during CTF_ELIMINATION warmup
+ if((level.time<=level.roundStartTime && level.time>level.roundStartTime-1000*g_elimination_activewarmup.integer)&&g_gametype.integer == GT_CTF_ELIMINATION)
+ return;
+
+ te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
+ if( team == TEAM_BLUE ) {
+ te->s.eventParm = GTS_RED_RETURN;
+ }
+ else {
+ te->s.eventParm = GTS_BLUE_RETURN;
+ }
+ te->r.svFlags |= SVF_BROADCAST;
+}
+
+void Team_TakeFlagSound( gentity_t *ent, int team ) {
+ gentity_t *te;
+
+ if (ent == NULL) {
+ G_Printf ("Warning: NULL passed to Team_TakeFlagSound\n");
+ return;
+ }
+
+ // only play sound when the flag was at the base
+ // or not picked up the last 10 seconds
+ switch(team) {
+ case TEAM_RED:
+ if( teamgame.blueStatus != FLAG_ATBASE ) {
+ if (teamgame.blueTakenTime > level.time - 10000 && g_gametype.integer != GT_CTF_ELIMINATION)
+ return;
+ }
+ teamgame.blueTakenTime = level.time;
+ break;
+
+ case TEAM_BLUE: // CTF
+ if( teamgame.redStatus != FLAG_ATBASE ) {
+ if (teamgame.redTakenTime > level.time - 10000 && g_gametype.integer != GT_CTF_ELIMINATION)
+ return;
+ }
+ teamgame.redTakenTime = level.time;
+ break;
+ }
+
+ te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
+ if( team == TEAM_BLUE ) {
+ te->s.eventParm = GTS_RED_TAKEN;
+ }
+ else {
+ te->s.eventParm = GTS_BLUE_TAKEN;
+ }
+ te->r.svFlags |= SVF_BROADCAST;
+}
+
+void Team_CaptureFlagSound( gentity_t *ent, int team ) {
+ gentity_t *te;
+
+ if (ent == NULL) {
+ G_Printf ("Warning: NULL passed to Team_CaptureFlagSound\n");
+ return;
+ }
+
+ te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
+ if( team == TEAM_BLUE ) {
+ te->s.eventParm = GTS_BLUE_CAPTURE;
+ }
+ else {
+ te->s.eventParm = GTS_RED_CAPTURE;
+ }
+ te->r.svFlags |= SVF_BROADCAST;
+}
+
+void Team_ReturnFlag( int team ) {
+ Team_ReturnFlagSound(Team_ResetFlag(team), team);
+ if( team == TEAM_FREE ) {
+ PrintMsg(NULL, "The flag has returned!\n" );
+ if(g_gametype.integer == GT_1FCTF) {
+ G_LogPrintf( "1FCTF: %i %i %i: The flag was returned!\n", -1, -1, 2 );
+ }
+ }
+ else {
+ PrintMsg(NULL, "The %s flag has returned!\n", TeamName(team));
+ if(g_gametype.integer == GT_CTF_ELIMINATION) {
+ G_LogPrintf( "CTF: %i %i %i: The %s flag was returned!\n", -1, team, 2, TeamName(team) );
+ } else
+ if(g_gametype.integer == GT_CTF_ELIMINATION) {
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: The %s flag was returned!\n", level.roundNumber, -1, team, 2, TeamName(team) );
+ }
+ }
+}
+
+void Team_FreeEntity( gentity_t *ent ) {
+ if( ent->item->giTag == PW_REDFLAG ) {
+ Team_ReturnFlag( TEAM_RED );
+ }
+ else if( ent->item->giTag == PW_BLUEFLAG ) {
+ Team_ReturnFlag( TEAM_BLUE );
+ }
+ else if( ent->item->giTag == PW_NEUTRALFLAG ) {
+ Team_ReturnFlag( TEAM_FREE );
+ }
+}
+
+/*
+==============
+Team_DroppedFlagThink
+
+Automatically set in Launch_Item if the item is one of the flags
+
+Flags are unique in that if they are dropped, the base flag must be respawned when they time out
+==============
+*/
+void Team_DroppedFlagThink(gentity_t *ent) {
+ int team = TEAM_FREE;
+
+ if( ent->item->giTag == PW_REDFLAG ) {
+ team = TEAM_RED;
+ }
+ else if( ent->item->giTag == PW_BLUEFLAG ) {
+ team = TEAM_BLUE;
+ }
+ else if( ent->item->giTag == PW_NEUTRALFLAG ) {
+ team = TEAM_FREE;
+ }
+
+ Team_ReturnFlagSound( Team_ResetFlag( team ), team );
+ // Reset Flag will delete this entity
+}
+
+/*
+Update DD points
+*/
+
+void updateDDpoints(void) {
+ //teamgame.redStatus = -1; // Invalid to force update
+ Team_SetFlagStatus( TEAM_RED, level.pointStatusA );
+ //teamgame.blueStatus = -1; // Invalid to force update
+ Team_SetFlagStatus( TEAM_BLUE, level.pointStatusB );
+}
+
+/*
+==============
+Team_SpawnDoubleDominationPoints
+==============
+*/
+
+int Team_SpawnDoubleDominationPoints ( void ) {
+ gentity_t *ent;
+ level.pointStatusA = TEAM_FREE;
+ level.pointStatusB = TEAM_FREE;
+ updateDDpoints();
+ ent = NULL;
+ if ((ent = G_Find (ent, FOFS(classname), "team_CTF_redflag")) != NULL) {
+ Team_DD_makeA2team( ent, TEAM_FREE );
+ }
+ ent = NULL;
+ if ((ent = G_Find (ent, FOFS(classname), "team_CTF_blueflag")) != NULL) {
+ Team_DD_makeB2team( ent, TEAM_FREE );
+ }
+ return 1;
+}
+
+/*
+==============
+Team_RemoveDoubleDominationPoints
+==============
+*/
+
+int Team_RemoveDoubleDominationPoints ( void ) {
+ level.pointStatusA = TEAM_NONE;
+ level.pointStatusB = TEAM_NONE;
+ updateDDpoints();
+ Team_DD_makeA2team( NULL, TEAM_NONE );
+ Team_DD_makeB2team( NULL, TEAM_NONE );
+ return 1;
+}
+
+/*
+==============
+Team_TouchDoubleDominationPoint
+==============
+*/
+
+//team is the either TEAM_RED(A) or TEAM_BLUE(B)
+int Team_TouchDoubleDominationPoint( gentity_t *ent, gentity_t *other, int team ) {
+ gclient_t *cl = other->client;
+ qboolean otherDominating, isClose;
+ int clientTeam = cl->sess.sessionTeam;
+ int otherTeam;
+ int score; //Used to add the scores together
+
+ if(clientTeam == TEAM_RED)
+ otherTeam = TEAM_BLUE;
+ else
+ otherTeam = TEAM_RED;
+
+ otherDominating = qfalse;
+ isClose = qfalse;
+
+ if(level.pointStatusA == otherTeam && level.pointStatusB == otherTeam) {
+ otherDominating = qtrue;
+ if(level.time - level.timeTaken > (10-DD_CLOSE)*1000)
+ isClose = qtrue;
+ }
+
+
+ if(team == TEAM_RED) //We have touched point A
+ {
+ if(TEAM_NONE == level.pointStatusA)
+ return 0; //Haven't spawned yet
+ if(clientTeam == level.pointStatusA)
+ return 0; //If we already have the flag
+ //if we didn't have the point, then we have now!
+ level.pointStatusA = clientTeam;
+ PrintMsg( NULL, "%s" S_COLOR_WHITE " (%s) took control of A!\n", cl->pers.netname, TeamName(clientTeam) );
+ Team_DD_makeA2team( ent, clientTeam );
+ G_LogPrintf( "DD: %i %i %i: %s took point A for %s!\n", cl->ps.clientNum, clientTeam, 0, cl->pers.netname, TeamName(clientTeam) );
+ //Give personal score
+ score = DD_POINT_CAPTURE; //Base score for capture
+ if(otherDominating){
+ score += DD_POINT_CAPTURE_BREAK;
+ if(isClose)
+ score += DD_POINT_CAPTURE_CLOSE;
+ }
+ AddScore(other, ent->r.currentOrigin, score);
+ //Do we also have point B?
+ if(clientTeam == level.pointStatusB)
+ {
+ //We are dominating!
+ level.timeTaken = level.time; //At this time
+ PrintMsg( NULL, "%s" S_COLOR_WHITE " is dominating!\n", TeamName(clientTeam) );
+ SendDDtimetakenMessageToAllClients();
+ }
+ }
+
+ if(team == TEAM_BLUE) //We have touched point B
+ {
+ if(TEAM_NONE == level.pointStatusB)
+ return 0; //Haven't spawned yet
+ if(clientTeam == level.pointStatusB)
+ return 0; //If we already have the flag
+ //if we didn't have the point, then we have now!
+ level.pointStatusB = clientTeam;
+ PrintMsg( NULL, "%s" S_COLOR_WHITE " (%s) took control of B!\n", cl->pers.netname, TeamName(clientTeam) );
+ Team_DD_makeB2team( ent, clientTeam );
+ G_LogPrintf( "DD: %i %i %i: %s took point B for %s!\n", cl->ps.clientNum, clientTeam, 1, cl->pers.netname, TeamName(clientTeam) );
+ //Give personal score
+ score = DD_POINT_CAPTURE; //Base score for capture
+ if(otherDominating){
+ score += DD_POINT_CAPTURE_BREAK;
+ if(isClose)
+ score += DD_POINT_CAPTURE_CLOSE;
+ }
+ AddScore(other, ent->r.currentOrigin, score);
+ //Do we also have point A?
+ if(clientTeam == level.pointStatusA)
+ {
+ //We are dominating!
+ level.timeTaken = level.time; //At this time
+ PrintMsg( NULL, "%s" S_COLOR_WHITE " is dominating!\n", TeamName(clientTeam) );
+ SendDDtimetakenMessageToAllClients();
+ }
+ }
+
+ updateDDpoints();
+
+ return 0;
+}
+
+/*
+==============
+Team_TouchOurFlag
+==============
+*/
+int Team_TouchOurFlag( gentity_t *ent, gentity_t *other, int team ) {
+ int i;
+ gentity_t *player;
+ gclient_t *cl = other->client;
+ int enemy_flag;
+
+ if( g_gametype.integer == GT_1FCTF ) {
+ enemy_flag = PW_NEUTRALFLAG;
+ }
+ else {
+ if (cl->sess.sessionTeam == TEAM_RED) {
+ enemy_flag = PW_BLUEFLAG;
+ } else {
+ enemy_flag = PW_REDFLAG;
+ }
+
+ if ( ent->flags & FL_DROPPED_ITEM ) {
+ // hey, its not home. return it by teleporting it back
+ PrintMsg( NULL, "%s" S_COLOR_WHITE " returned the %s flag!\n",
+ cl->pers.netname, TeamName(team));
+ AddScore(other, ent->r.currentOrigin, CTF_RECOVERY_BONUS);
+ if(g_gametype.integer == GT_CTF) {
+ G_LogPrintf( "CTF: %i %i %i: %s returned the %s flag!\n", cl->ps.clientNum, team, 2, cl->pers.netname, TeamName(team) );
+ } else if(g_gametype.integer == GT_CTF_ELIMINATION) {
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s returned the %s flag!\n", level.roundNumber, cl->ps.clientNum, team, 2, cl->pers.netname, TeamName(team) );
+ }
+ other->client->pers.teamState.flagrecovery++;
+ other->client->pers.teamState.lastreturnedflag = level.time;
+ //ResetFlag will remove this entity! We must return zero
+ Team_ReturnFlagSound(Team_ResetFlag(team), team);
+ return 0;
+ }
+ }
+
+ // the flag is at home base. if the player has the enemy
+ // flag, he's just won!
+ if (!cl->ps.powerups[enemy_flag])
+ return 0; // We don't have the flag
+ if( g_gametype.integer == GT_1FCTF ) {
+ PrintMsg( NULL, "%s" S_COLOR_WHITE " captured the flag!\n", cl->pers.netname );
+ G_LogPrintf( "1FCTF: %i %i %i: %s captured the flag!\n", cl->ps.clientNum, -1, 1, cl->pers.netname );
+ }
+ else {
+ PrintMsg( NULL, "%s" S_COLOR_WHITE " captured the %s flag!\n", cl->pers.netname, TeamName(OtherTeam(team)));
+ if(g_gametype.integer == GT_CTF)
+ G_LogPrintf( "CTF: %i %i %i: %s captured the %s flag!\n", cl->ps.clientNum, OtherTeam(team), 1, cl->pers.netname, TeamName(OtherTeam(team)) );
+ if(g_gametype.integer == GT_CTF_ELIMINATION)
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s captured the %s flag!\n", level.roundNumber, cl->ps.clientNum, OtherTeam(team), 1, cl->pers.netname, TeamName(OtherTeam(team)) );
+ }
+
+ cl->ps.powerups[enemy_flag] = 0;
+
+ teamgame.last_flag_capture = level.time;
+ teamgame.last_capture_team = team;
+
+ // Increase the team's score
+ AddTeamScore(ent->s.pos.trBase, other->client->sess.sessionTeam, 1);
+ Team_ForceGesture(other->client->sess.sessionTeam);
+ //If CTF Elimination, stop the round:
+ if(g_gametype.integer==GT_CTF_ELIMINATION) {
+ EndEliminationRound();
+ }
+
+ other->client->pers.teamState.captures++;
+ // add the sprite over the player's head
+ other->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ other->client->ps.eFlags |= EF_AWARD_CAP;
+ other->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+ other->client->ps.persistant[PERS_CAPTURES]++;
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", other->client->ps.clientNum, 4, other->client->pers.netname, "CAPTURE" );
+ if(TeamCount(-1,TEAM_RED) && TeamCount(-1,TEAM_BLUE) && !level.hadBots)
+ ChallengeMessage(other,AWARD_CAPTURE);
+ // other gets another 10 frag bonus
+ AddScore(other, ent->r.currentOrigin, CTF_CAPTURE_BONUS);
+
+ Team_CaptureFlagSound( ent, team );
+
+ // Ok, let's do the player loop, hand out the bonuses
+ for (i = 0; i < g_maxclients.integer; i++) {
+ player = &g_entities[i];
+ if (!player->inuse || player == other)
+ continue;
+
+ if (player->client->sess.sessionTeam !=
+ cl->sess.sessionTeam) {
+ player->client->pers.teamState.lasthurtcarrier = -5;
+ } else if (player->client->sess.sessionTeam ==
+ cl->sess.sessionTeam) {
+ if (player != other)
+ AddScore(player, ent->r.currentOrigin, CTF_TEAM_BONUS);
+ // award extra points for capture assists
+ if (player->client->pers.teamState.lastreturnedflag +
+ CTF_RETURN_FLAG_ASSIST_TIMEOUT > level.time) {
+ AddScore (player, ent->r.currentOrigin, CTF_RETURN_FLAG_ASSIST_BONUS);
+ other->client->pers.teamState.assists++;
+
+ player->client->ps.persistant[PERS_ASSIST_COUNT]++;
+ if(!level.hadBots)
+ ChallengeMessage(player,AWARD_ASSIST);
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", player->client->ps.clientNum, 5, player->client->pers.netname, "ASSIST" );
+ // add the sprite over the player's head
+ player->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ player->client->ps.eFlags |= EF_AWARD_ASSIST;
+ player->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+
+ }
+ if (player->client->pers.teamState.lastfraggedcarrier +
+ CTF_FRAG_CARRIER_ASSIST_TIMEOUT > level.time) {
+ AddScore(player, ent->r.currentOrigin, CTF_FRAG_CARRIER_ASSIST_BONUS);
+ other->client->pers.teamState.assists++;
+ player->client->ps.persistant[PERS_ASSIST_COUNT]++;
+ if(!level.hadBots)
+ ChallengeMessage(player,AWARD_ASSIST);
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", player->client->ps.clientNum, 5, player->client->pers.netname, "ASSIST" );
+ // add the sprite over the player's head
+ player->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ player->client->ps.eFlags |= EF_AWARD_ASSIST;
+ player->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+ }
+ }
+ }
+ Team_ResetFlags();
+
+ CalculateRanks();
+
+ return 0; // Do not respawn this automatically
+}
+
+int Team_TouchEnemyFlag( gentity_t *ent, gentity_t *other, int team ) {
+ gclient_t *cl = other->client;
+
+ if( g_gametype.integer == GT_1FCTF ) {
+ PrintMsg (NULL, "%s" S_COLOR_WHITE " got the flag!\n", other->client->pers.netname );
+
+ G_LogPrintf( "1FCTF: %i %i %i: %s got the flag!\n", cl->ps.clientNum, team, 0, cl->pers.netname);
+
+ cl->ps.powerups[PW_NEUTRALFLAG] = INT_MAX; // flags never expire
+
+ if( team == TEAM_RED ) {
+ Team_SetFlagStatus( TEAM_FREE, FLAG_TAKEN_RED );
+ }
+ else {
+ Team_SetFlagStatus( TEAM_FREE, FLAG_TAKEN_BLUE );
+ }
+ }
+ else{
+ PrintMsg (NULL, "%s" S_COLOR_WHITE " got the %s flag!\n",
+ other->client->pers.netname, TeamName(team));
+
+ if(g_gametype.integer == GT_CTF) {
+ G_LogPrintf( "CTF: %i %i %i: %s got the %s flag!\n", cl->ps.clientNum, team, 0, cl->pers.netname, TeamName(team));
+ } else if(g_gametype.integer == GT_CTF_ELIMINATION) {
+ G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s got the %s flag!\n", level.roundNumber, cl->ps.clientNum, team, 0, cl->pers.netname, TeamName(team));
+ }
+
+ if (team == TEAM_RED)
+ cl->ps.powerups[PW_REDFLAG] = INT_MAX; // flags never expire
+ else
+ cl->ps.powerups[PW_BLUEFLAG] = INT_MAX; // flags never expire
+
+ Team_SetFlagStatus( team, FLAG_TAKEN );
+ }
+
+ AddScore(other, ent->r.currentOrigin, CTF_FLAG_BONUS);
+ cl->pers.teamState.flagsince = level.time;
+ Team_TakeFlagSound( ent, team );
+
+ return -1; // Do not respawn this automatically, but do delete it if it was FL_DROPPED
+}
+
+int Pickup_Team( gentity_t *ent, gentity_t *other ) {
+ int team;
+ gclient_t *cl = other->client;
+
+ if( g_gametype.integer == GT_OBELISK ) {
+ // there are no team items that can be picked up in obelisk
+ G_FreeEntity( ent );
+ return 0;
+ }
+
+ if( g_gametype.integer == GT_HARVESTER ) {
+ // the only team items that can be picked up in harvester are the cubes
+ if( ent->spawnflags != cl->sess.sessionTeam ) {
+ cl->ps.generic1 += 1; //Skull pickedup
+ G_LogPrintf("HARVESTER: %i %i %i %i %i: %s picked up a skull.\n",
+ cl->ps.clientNum,cl->sess.sessionTeam,3,-1,1,
+ cl->pers.netname);
+ } else {
+ G_LogPrintf("HARVESTER: %i %i %i %i %i: %s destroyed a skull.\n,",
+ cl->ps.clientNum,cl->sess.sessionTeam,2,-1,1,
+ cl->pers.netname);
+ }
+ G_FreeEntity( ent ); //Destory skull
+ return 0;
+ }
+ if ( g_gametype.integer == GT_DOMINATION ) {
+ Team_Dom_TakePoint(ent, cl->sess.sessionTeam,cl->ps.clientNum);
+ return 0;
+ }
+ // figure out what team this flag is
+ if( strcmp(ent->classname, "team_CTF_redflag") == 0 ) {
+ team = TEAM_RED;
+ }
+ else if( strcmp(ent->classname, "team_CTF_blueflag") == 0 ) {
+ team = TEAM_BLUE;
+ }
+ else if( strcmp(ent->classname, "team_CTF_neutralflag") == 0 ) {
+ team = TEAM_FREE;
+ }
+ else {
+ PrintMsg ( other, "Don't know what team the flag is on.\n");
+ return 0;
+ }
+ if( g_gametype.integer == GT_1FCTF ) {
+ if( team == TEAM_FREE ) {
+ return Team_TouchEnemyFlag( ent, other, cl->sess.sessionTeam );
+ }
+ if( team != cl->sess.sessionTeam) {
+ return Team_TouchOurFlag( ent, other, cl->sess.sessionTeam );
+ }
+ return 0;
+ }
+ if( g_gametype.integer == GT_DOUBLE_D) {
+ return Team_TouchDoubleDominationPoint( ent, other, team );
+ }
+ // GT_CTF
+ if( team == cl->sess.sessionTeam) {
+ return Team_TouchOurFlag( ent, other, team );
+ }
+ return Team_TouchEnemyFlag( ent, other, team );
+}
+
+/*
+===========
+Team_GetLocation
+
+Report a location for the player. Uses placed nearby target_location entities
+============
+*/
+gentity_t *Team_GetLocation(gentity_t *ent)
+{
+ gentity_t *eloc, *best;
+ float bestlen, len;
+ vec3_t origin;
+
+ best = NULL;
+ bestlen = 3*8192.0*8192.0;
+
+ VectorCopy( ent->r.currentOrigin, origin );
+
+ for (eloc = level.locationHead; eloc; eloc = eloc->nextTrain) {
+ len = ( origin[0] - eloc->r.currentOrigin[0] ) * ( origin[0] - eloc->r.currentOrigin[0] )
+ + ( origin[1] - eloc->r.currentOrigin[1] ) * ( origin[1] - eloc->r.currentOrigin[1] )
+ + ( origin[2] - eloc->r.currentOrigin[2] ) * ( origin[2] - eloc->r.currentOrigin[2] );
+
+ if ( len > bestlen ) {
+ continue;
+ }
+
+ if ( !trap_InPVS( origin, eloc->r.currentOrigin ) ) {
+ continue;
+ }
+
+ bestlen = len;
+ best = eloc;
+ }
+
+ return best;
+}
+
+
+/*
+===========
+Team_GetLocation
+
+Report a location for the player. Uses placed nearby target_location entities
+============
+*/
+qboolean Team_GetLocationMsg(gentity_t *ent, char *loc, int loclen)
+{
+ gentity_t *best;
+
+ best = Team_GetLocation( ent );
+
+ if (!best)
+ return qfalse;
+
+ if (best->count) {
+ if (best->count < 0)
+ best->count = 0;
+ if (best->count > 7)
+ best->count = 7;
+ Com_sprintf(loc, loclen, "%c%c%s" S_COLOR_WHITE, Q_COLOR_ESCAPE, best->count + '0', best->message );
+ } else
+ Com_sprintf(loc, loclen, "%s", best->message);
+
+ return qtrue;
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/*
+================
+SelectRandomDeathmatchSpawnPoint
+
+go to a random point that doesn't telefrag
+================
+*/
+#define MAX_TEAM_SPAWN_POINTS 32
+gentity_t *SelectRandomTeamSpawnPoint( int teamstate, team_t team ) {
+ gentity_t *spot;
+ int count;
+ int selection;
+ gentity_t *spots[MAX_TEAM_SPAWN_POINTS];
+ char *classname;
+
+ if(g_gametype.integer == GT_ELIMINATION) { //change sides every round
+ if((level.roundNumber+level.eliminationSides)%2==1){
+ if(team == TEAM_RED)
+ team = TEAM_BLUE;
+ else if(team == TEAM_BLUE)
+ team = TEAM_RED;
+ }
+ }
+
+ if (teamstate == TEAM_BEGIN) {
+ if (team == TEAM_RED)
+ classname = "team_CTF_redplayer";
+ else if (team == TEAM_BLUE)
+ classname = "team_CTF_blueplayer";
+ else
+ return NULL;
+ } else {
+ if (team == TEAM_RED)
+ classname = "team_CTF_redspawn";
+ else if (team == TEAM_BLUE)
+ classname = "team_CTF_bluespawn";
+ else
+ return NULL;
+ }
+ count = 0;
+
+ spot = NULL;
+
+ while ((spot = G_Find (spot, FOFS(classname), classname)) != NULL) {
+ if ( SpotWouldTelefrag( spot ) ) {
+ continue;
+ }
+ spots[ count ] = spot;
+ if (++count == MAX_TEAM_SPAWN_POINTS)
+ break;
+ }
+
+ if ( !count ) { // no spots that won't telefrag
+ return G_Find( NULL, FOFS(classname), classname);
+ }
+
+ selection = rand() % count;
+ return spots[ selection ];
+}
+
+/*
+================
+SelectRandomDDSpawnPoint
+
+go to a random Double Domination Spawn Point
+================
+*/
+#define MAX_TEAM_SPAWN_POINTS 32
+gentity_t *SelectRandomDDSpawnPoint( void ) {
+ gentity_t *spot;
+ int count;
+ int selection;
+ gentity_t *spots[MAX_TEAM_SPAWN_POINTS];
+ char *classname;
+
+
+ classname = "info_player_dd";
+
+ count = 0;
+
+ spot = NULL;
+
+ while ((spot = G_Find (spot, FOFS(classname), classname)) != NULL) {
+ if ( SpotWouldTelefrag( spot ) ) {
+ continue;
+ }
+ spots[ count ] = spot;
+ if (++count == MAX_TEAM_SPAWN_POINTS)
+ break;
+ }
+
+ if ( !count ) { // no spots that won't telefrag
+ return G_Find( NULL, FOFS(classname), classname);
+ }
+
+ selection = rand() % count;
+ return spots[ selection ];
+}
+
+gentity_t *SelectRandomTeamDDSpawnPoint( team_t team ) {
+ gentity_t *spot;
+ int count;
+ int selection;
+ gentity_t *spots[MAX_TEAM_SPAWN_POINTS];
+ char *classname;
+
+ if(team == TEAM_RED)
+ classname = "info_player_dd_red";
+ else
+ classname = "info_player_dd_blue";
+
+ count = 0;
+
+ spot = NULL;
+
+ while ((spot = G_Find (spot, FOFS(classname), classname)) != NULL) {
+ if ( SpotWouldTelefrag( spot ) ) {
+ continue;
+ }
+ spots[ count ] = spot;
+ if (++count == MAX_TEAM_SPAWN_POINTS)
+ break;
+ }
+
+ if ( !count ) { // no spots that won't telefrag
+ return G_Find( NULL, FOFS(classname), classname);
+ }
+
+ selection = rand() % count;
+ return spots[ selection ];
+}
+
+
+/*
+===========
+SelectCTFSpawnPoint
+
+============
+*/
+gentity_t *SelectCTFSpawnPoint ( team_t team, int teamstate, vec3_t origin, vec3_t angles ) {
+ gentity_t *spot;
+
+ spot = SelectRandomTeamSpawnPoint ( teamstate, team );
+
+ if (!spot) {
+ return SelectSpawnPoint( vec3_origin, origin, angles );
+ }
+
+ VectorCopy (spot->s.origin, origin);
+ origin[2] += 9;
+ VectorCopy (spot->s.angles, angles);
+
+ return spot;
+}
+
+/*
+===========
+SelectDoubleDominationSpawnPoint
+
+============
+*/
+gentity_t *SelectDoubleDominationSpawnPoint ( team_t team, vec3_t origin, vec3_t angles ) {
+ gentity_t *spot;
+
+ spot = SelectRandomTeamDDSpawnPoint( team );
+
+ if(!spot) {
+ spot = SelectRandomDDSpawnPoint ( );
+ }
+
+ if (!spot) {
+ return SelectSpawnPoint( vec3_origin, origin, angles );
+ }
+
+ VectorCopy (spot->s.origin, origin);
+ origin[2] += 9;
+ VectorCopy (spot->s.angles, angles);
+
+ return spot;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static int QDECL SortClients( const void *a, const void *b ) {
+ return *(int *)a - *(int *)b;
+}
+
+
+/*
+==================
+TeamplayLocationsMessage
+
+Format:
+ clientNum location health armor weapon powerups
+
+==================
+*/
+void TeamplayInfoMessage( gentity_t *ent ) {
+ char entry[1024];
+ char string[8192];
+ int stringlength;
+ int i, j;
+ gentity_t *player;
+ int cnt;
+ int h, a, w;
+ int clients[TEAM_MAXOVERLAY];
+
+ if ( ! ent->client->pers.teamInfo )
+ return;
+
+ // figure out what client should be on the display
+ // we are limited to 8, but we want to use the top eight players
+ // but in client order (so they don't keep changing position on the overlay)
+ for (i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {
+ player = g_entities + level.sortedClients[i];
+ if (player->inuse && player->client->sess.sessionTeam ==
+ ent->client->sess.sessionTeam ) {
+ clients[cnt++] = level.sortedClients[i];
+ }
+ }
+
+ // We have the top eight players, sort them by clientNum
+ qsort( clients, cnt, sizeof( clients[0] ), SortClients );
+
+ // send the latest information on all clients
+ string[0] = 0;
+ stringlength = 0;
+
+ for (i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {
+ player = g_entities + i;
+ if (player->inuse && player->client->sess.sessionTeam ==
+ ent->client->sess.sessionTeam ) {
+
+ h = player->client->ps.stats[STAT_HEALTH];
+ a = player->client->ps.stats[STAT_ARMOR];
+ w = player->client->ps.weapon;
+ if(player->client->isEliminated)
+ {
+ h = 0;
+ a = 0;
+ w = 0;
+ }
+ if (h < 0) h = 0;
+ if (a < 0) a = 0;
+
+ Com_sprintf (entry, sizeof(entry),
+ " %i %i %i %i %i %i",
+// level.sortedClients[i], player->client->pers.teamState.location, h, a,
+ i, player->client->pers.teamState.location, h, a,
+ w, player->s.powerups);
+ j = strlen(entry);
+ if (stringlength + j > sizeof(string))
+ break;
+ strcpy (string + stringlength, entry);
+ stringlength += j;
+ cnt++;
+ }
+ }
+
+ trap_SendServerCommand( ent-g_entities, va("tinfo %i %s", cnt, string) );
+}
+
+void CheckTeamStatus(void) {
+ int i;
+ gentity_t *loc, *ent;
+
+ if (level.time - level.lastTeamLocationTime > TEAM_LOCATION_UPDATE_TIME) {
+
+ level.lastTeamLocationTime = level.time;
+
+ for (i = 0; i < g_maxclients.integer; i++) {
+ ent = g_entities + i;
+
+ if ( ent->client->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+
+ if (ent->inuse && (ent->client->sess.sessionTeam == TEAM_RED || ent->client->sess.sessionTeam == TEAM_BLUE)) {
+ loc = Team_GetLocation( ent );
+ if (loc)
+ ent->client->pers.teamState.location = loc->health;
+ else
+ ent->client->pers.teamState.location = 0;
+ }
+ }
+
+ for (i = 0; i < g_maxclients.integer; i++) {
+ ent = g_entities + i;
+
+ if ( ent->client->pers.connected != CON_CONNECTED ) {
+ continue;
+ }
+
+ if (ent->inuse && (ent->client->sess.sessionTeam == TEAM_RED || ent->client->sess.sessionTeam == TEAM_BLUE)) {
+ TeamplayInfoMessage( ent );
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+
+/*QUAKED team_CTF_redplayer (1 0 0) (-16 -16 -16) (16 16 32)
+Only in CTF games. Red players spawn here at game start.
+*/
+void SP_team_CTF_redplayer( gentity_t *ent ) {
+}
+
+
+/*QUAKED team_CTF_blueplayer (0 0 1) (-16 -16 -16) (16 16 32)
+Only in CTF games. Blue players spawn here at game start.
+*/
+void SP_team_CTF_blueplayer( gentity_t *ent ) {
+}
+
+
+/*QUAKED team_CTF_redspawn (1 0 0) (-16 -16 -24) (16 16 32)
+potential spawning position for red team in CTF games.
+Targets will be fired when someone spawns in on them.
+*/
+void SP_team_CTF_redspawn(gentity_t *ent) {
+}
+
+/*QUAKED team_CTF_bluespawn (0 0 1) (-16 -16 -24) (16 16 32)
+potential spawning position for blue team in CTF games.
+Targets will be fired when someone spawns in on them.
+*/
+void SP_team_CTF_bluespawn(gentity_t *ent) {
+}
+
+/*
+================
+Obelisks
+================
+*/
+
+static void ObeliskHealthChange( int team, int health ) {
+ int currentPercentage;
+ int percentage = (health*100)/g_obeliskHealth.integer;
+ if(percentage < 0)
+ percentage = 0;
+ currentPercentage = level.healthRedObelisk;
+ if(team != TEAM_RED)
+ currentPercentage = level.healthBlueObelisk;
+ if(percentage != currentPercentage) {
+ if(team == TEAM_RED) {
+ level.healthRedObelisk = percentage;
+ } else {
+ level.healthBlueObelisk = percentage;
+ }
+ level.MustSendObeliskHealth = qtrue;
+ //G_Printf("Obelisk health %i %i\n",team,percentage);
+ ObeliskHealthMessage();
+ }
+}
+
+static void ObeliskRegen( gentity_t *self ) {
+ self->nextthink = level.time + g_obeliskRegenPeriod.integer * 1000;
+ ObeliskHealthChange(self->spawnflags,self->health);
+ if( self->health >= g_obeliskHealth.integer ) {
+ return;
+ }
+
+ G_AddEvent( self, EV_POWERUP_REGEN, 0 );
+ self->health += g_obeliskRegenAmount.integer;
+ if ( self->health > g_obeliskHealth.integer ) {
+ self->health = g_obeliskHealth.integer;
+ }
+
+ self->activator->s.modelindex2 = self->health * 0xff / g_obeliskHealth.integer;
+ self->activator->s.frame = 0;
+}
+
+
+static void ObeliskRespawn( gentity_t *self ) {
+ self->takedamage = qtrue;
+ self->health = g_obeliskHealth.integer;
+
+ self->think = ObeliskRegen;
+ self->nextthink = level.time + g_obeliskRegenPeriod.integer * 1000;
+
+ self->activator->s.frame = 0;
+}
+
+
+static void ObeliskDie( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) {
+ int otherTeam;
+
+ otherTeam = OtherTeam( self->spawnflags );
+ AddTeamScore(self->s.pos.trBase, otherTeam, 1);
+ Team_ForceGesture(otherTeam);
+
+ CalculateRanks();
+
+ self->takedamage = qfalse;
+ self->think = ObeliskRespawn;
+ self->nextthink = level.time + g_obeliskRespawnDelay.integer * 1000;
+
+ self->activator->s.modelindex2 = 0xff;
+ self->activator->s.frame = 2;
+
+ G_AddEvent( self->activator, EV_OBELISKEXPLODE, 0 );
+
+ AddScore(attacker, self->r.currentOrigin, CTF_CAPTURE_BONUS);
+
+ // add the sprite over the player's head
+ attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ attacker->client->ps.eFlags |= EF_AWARD_CAP;
+ attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+ attacker->client->ps.persistant[PERS_CAPTURES]++;
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 4, attacker->client->pers.netname, "CAPTURE" );
+ G_LogPrintf("OBELISK: %i %i %i %i: %s destroyed the enemy obelisk.\n",
+ attacker->client->ps.clientNum,attacker->client->sess.sessionTeam,3,0,
+ attacker->client->pers.netname);
+ if(TeamCount(-1,TEAM_RED) && TeamCount(-1,TEAM_BLUE) && !level.hadBots)
+ ChallengeMessage(attacker,AWARD_CAPTURE);
+
+ ObeliskHealthChange(self->spawnflags,self->health);
+ teamgame.redObeliskAttackedTime = 0;
+ teamgame.blueObeliskAttackedTime = 0;
+}
+
+
+static void ObeliskTouch( gentity_t *self, gentity_t *other, trace_t *trace ) {
+ int tokens,i;
+
+ if ( !other->client ) {
+ return;
+ }
+
+ if ( OtherTeam(other->client->sess.sessionTeam) != self->spawnflags ) {
+ return;
+ }
+
+ tokens = other->client->ps.generic1;
+ if( tokens <= 0 ) {
+ return;
+ }
+
+ PrintMsg(NULL, "%s" S_COLOR_WHITE " brought in %i skull%s.\n",
+ other->client->pers.netname, tokens, tokens>1 ? "s" : "" );
+
+ G_LogPrintf("HARVESTER: %i %i %i %i %i: %s brought in %i skull%s for %s\n",
+ other->client->ps.clientNum,other->client->sess.sessionTeam,0,-1,tokens,
+ other->client->pers.netname,tokens, tokens>1 ? "s" : "", TeamName(other->client->sess.sessionTeam));
+
+ AddTeamScore(self->s.pos.trBase, other->client->sess.sessionTeam, tokens);
+ Team_ForceGesture(other->client->sess.sessionTeam);
+
+ AddScore(other, self->r.currentOrigin, CTF_CAPTURE_BONUS*tokens);
+
+ // add the sprite over the player's head
+ other->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ other->client->ps.eFlags |= EF_AWARD_CAP;
+ other->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+ other->client->ps.persistant[PERS_CAPTURES] += tokens;
+ for(i = 0;i<tokens;i++)
+ {
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", other->client->ps.clientNum, 4, other->client->pers.netname, "CAPTURE" );
+ if(TeamCount(-1,TEAM_RED) && TeamCount(-1,TEAM_BLUE) && !level.hadBots)
+ ChallengeMessage(other,AWARD_CAPTURE);
+ }
+
+ other->client->ps.generic1 = 0;
+ CalculateRanks();
+
+ Team_CaptureFlagSound( self, self->spawnflags );
+}
+
+static void ObeliskPain( gentity_t *self, gentity_t *attacker, int damage ) {
+ int actualDamage = damage / 10;
+ if (actualDamage <= 0) {
+ actualDamage = 1;
+ }
+ self->activator->s.modelindex2 = self->health * 0xff / g_obeliskHealth.integer;
+ if (!self->activator->s.frame) {
+ G_AddEvent(self, EV_OBELISKPAIN, 0);
+ }
+ self->activator->s.frame = 1;
+ AddScore(attacker, self->r.currentOrigin, actualDamage);
+ G_LogPrintf("OBELISK: %i %i %i %i: %s dealt %i damage to the enemy obelisk.\n",
+ attacker->client->ps.clientNum,attacker->client->sess.sessionTeam,1,actualDamage,
+ attacker->client->pers.netname,actualDamage);
+}
+
+gentity_t *SpawnObelisk( vec3_t origin, int team, int spawnflags) {
+ trace_t tr;
+ vec3_t dest;
+ gentity_t *ent;
+
+ ent = G_Spawn();
+
+ VectorCopy( origin, ent->s.origin );
+ VectorCopy( origin, ent->s.pos.trBase );
+ VectorCopy( origin, ent->r.currentOrigin );
+
+ VectorSet( ent->r.mins, -15, -15, 0 );
+ VectorSet( ent->r.maxs, 15, 15, 87 );
+
+ ent->s.eType = ET_GENERAL;
+ ent->flags = FL_NO_KNOCKBACK;
+
+ if( g_gametype.integer == GT_OBELISK ) {
+ ent->r.contents = CONTENTS_SOLID;
+ ent->takedamage = qtrue;
+ ent->health = g_obeliskHealth.integer;
+ ent->die = ObeliskDie;
+ ent->pain = ObeliskPain;
+ ent->think = ObeliskRegen;
+ ent->nextthink = level.time + g_obeliskRegenPeriod.integer * 1000;
+ }
+ if( g_gametype.integer == GT_HARVESTER ) {
+ ent->r.contents = CONTENTS_TRIGGER;
+ ent->touch = ObeliskTouch;
+ }
+
+ if ( spawnflags & 1 ) {
+ // suspended
+ G_SetOrigin( ent, ent->s.origin );
+ } else {
+ // mappers like to put them exactly on the floor, but being coplanar
+ // will sometimes show up as starting in solid, so lif it up one pixel
+ ent->s.origin[2] += 1;
+
+ // drop to floor
+ VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
+ trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
+ if ( tr.startsolid ) {
+ ent->s.origin[2] -= 1;
+ G_Printf( "SpawnObelisk: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin) );
+
+ ent->s.groundEntityNum = ENTITYNUM_NONE;
+ G_SetOrigin( ent, ent->s.origin );
+ }
+ else {
+ // allow to ride movers
+ ent->s.groundEntityNum = tr.entityNum;
+ G_SetOrigin( ent, tr.endpos );
+ }
+ }
+
+ ent->spawnflags = team;
+
+ trap_LinkEntity( ent );
+
+ return ent;
+}
+
+/*QUAKED team_redobelisk (1 0 0) (-16 -16 0) (16 16 8)
+*/
+void SP_team_redobelisk( gentity_t *ent ) {
+ gentity_t *obelisk;
+
+ if ( g_gametype.integer <= GT_TEAM || g_ffa_gt>0) {
+ G_FreeEntity(ent);
+ return;
+ }
+ ent->s.eType = ET_TEAM;
+ if ( g_gametype.integer == GT_OBELISK ) {
+ obelisk = SpawnObelisk( ent->s.origin, TEAM_RED, ent->spawnflags );
+ obelisk->activator = ent;
+ // initial obelisk health value
+ ent->s.modelindex2 = 0xff;
+ ent->s.frame = 0;
+ }
+ if ( g_gametype.integer == GT_HARVESTER ) {
+ obelisk = SpawnObelisk( ent->s.origin, TEAM_RED, ent->spawnflags );
+ obelisk->activator = ent;
+ }
+ ent->s.modelindex = TEAM_RED;
+ trap_LinkEntity(ent);
+}
+
+/*QUAKED team_blueobelisk (0 0 1) (-16 -16 0) (16 16 88)
+*/
+void SP_team_blueobelisk( gentity_t *ent ) {
+ gentity_t *obelisk;
+
+ if ( g_gametype.integer <= GT_TEAM || g_ffa_gt>0) {
+ G_FreeEntity(ent);
+ return;
+ }
+ ent->s.eType = ET_TEAM;
+ if ( g_gametype.integer == GT_OBELISK ) {
+ obelisk = SpawnObelisk( ent->s.origin, TEAM_BLUE, ent->spawnflags );
+ obelisk->activator = ent;
+ // initial obelisk health value
+ ent->s.modelindex2 = 0xff;
+ ent->s.frame = 0;
+ }
+ if ( g_gametype.integer == GT_HARVESTER ) {
+ obelisk = SpawnObelisk( ent->s.origin, TEAM_BLUE, ent->spawnflags );
+ obelisk->activator = ent;
+ }
+ ent->s.modelindex = TEAM_BLUE;
+ trap_LinkEntity(ent);
+}
+
+/*QUAKED team_neutralobelisk (0 0 1) (-16 -16 0) (16 16 88)
+*/
+void SP_team_neutralobelisk( gentity_t *ent ) {
+ if ( g_gametype.integer != GT_1FCTF && g_gametype.integer != GT_HARVESTER ) {
+ G_FreeEntity(ent);
+ return;
+ }
+ ent->s.eType = ET_TEAM;
+ if ( g_gametype.integer == GT_HARVESTER) {
+ neutralObelisk = SpawnObelisk( ent->s.origin, TEAM_FREE, ent->spawnflags);
+ neutralObelisk->spawnflags = TEAM_FREE;
+ }
+ ent->s.modelindex = TEAM_FREE;
+ trap_LinkEntity(ent);
+}
+
+
+/*
+================
+CheckObeliskAttack
+================
+*/
+qboolean CheckObeliskAttack( gentity_t *obelisk, gentity_t *attacker ) {
+ gentity_t *te;
+
+ // if this really is an obelisk
+ if( obelisk->die != ObeliskDie ) {
+ return qfalse;
+ }
+
+ // if the attacker is a client
+ if( !attacker->client ) {
+ return qfalse;
+ }
+
+ // if the obelisk is on the same team as the attacker then don't hurt it
+ if( obelisk->spawnflags == attacker->client->sess.sessionTeam ) {
+ return qtrue;
+ }
+
+ // obelisk may be hurt
+
+ // if not played any sounds recently
+ if ((obelisk->spawnflags == TEAM_RED &&
+ teamgame.redObeliskAttackedTime < level.time - OVERLOAD_ATTACK_BASE_SOUND_TIME) ||
+ (obelisk->spawnflags == TEAM_BLUE &&
+ teamgame.blueObeliskAttackedTime < level.time - OVERLOAD_ATTACK_BASE_SOUND_TIME) ) {
+
+ // tell which obelisk is under attack
+ te = G_TempEntity( obelisk->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
+ if( obelisk->spawnflags == TEAM_RED ) {
+ te->s.eventParm = GTS_REDOBELISK_ATTACKED;
+ teamgame.redObeliskAttackedTime = level.time;
+ }
+ else {
+ te->s.eventParm = GTS_BLUEOBELISK_ATTACKED;
+ teamgame.blueObeliskAttackedTime = level.time;
+ }
+ te->r.svFlags |= SVF_BROADCAST;
+ }
+
+ return qfalse;
+}
+
+/*
+================
+ShuffleTeams
+ *Randomizes the teams based on a type of function and then restarts the map
+ *Currently there is only one type so type is ignored. You can add total randomizaion or waighted randomization later.
+ *
+ *The function will split the teams like this:
+ *1. Red team
+ *2. Blue team
+ *3. Blue team
+ *4. Red team
+ *5. Go to 1
+================
+*/
+void ShuffleTeams(void) {
+ int i;
+ int assignedClients=1, nextTeam=TEAM_RED;
+
+ if ( g_gametype.integer < GT_TEAM || g_ffa_gt==1)
+ return; //Can only shuffle team games!
+
+ for( i=0;i < level.numConnectedClients; i++ ) {
+ if( g_entities[ &level.clients[level.sortedClients[i]] - level.clients].r.svFlags & SVF_BOT)
+ continue; //Don't sort bots... they are always equal
+
+ if(level.clients[level.sortedClients[i]].sess.sessionTeam==TEAM_RED || level.clients[level.sortedClients[i]].sess.sessionTeam==TEAM_BLUE ) {
+ //For every second client we chenge team. But we do it a little of to make it slightly more fair
+ if(assignedClients>1) {
+ assignedClients=0;
+ if(nextTeam == TEAM_RED)
+ nextTeam = TEAM_BLUE;
+ else
+ nextTeam = TEAM_RED;
+ }
+
+ //Set the team
+ //We do not run all the logic because we shall run map_restart in a moment.
+ level.clients[level.sortedClients[i]].sess.sessionTeam = nextTeam;
+
+ ClientUserinfoChanged( level.sortedClients[i] );
+ ClientBegin( level.sortedClients[i] );
+
+ assignedClients++;
+ }
+ }
+
+ //Restart!
+ trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
+
+}
+
diff --git a/game/code/game/g_team.h b/code/game/g_team.h
similarity index 100%
rename from game/code/game/g_team.h
rename to code/game/g_team.h
diff --git a/code/game/g_trigger.c b/code/game/g_trigger.c
new file mode 100644
index 0000000..9393b4d
--- /dev/null
+++ b/code/game/g_trigger.c
@@ -0,0 +1,468 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#include "g_local.h"
+
+
+void InitTrigger( gentity_t *self ) {
+ if (!VectorCompare (self->s.angles, vec3_origin))
+ G_SetMovedir (self->s.angles, self->movedir);
+
+ trap_SetBrushModel( self, self->model );
+ self->r.contents = CONTENTS_TRIGGER; // replaces the -1 from trap_SetBrushModel
+ self->r.svFlags = SVF_NOCLIENT;
+}
+
+
+// the wait time has passed, so set back up for another activation
+void multi_wait( gentity_t *ent ) {
+ ent->nextthink = 0;
+}
+
+
+// the trigger was just activated
+// ent->activator should be set to the activator so it can be held through a delay
+// so wait for the delay time before firing
+void multi_trigger( gentity_t *ent, gentity_t *activator ) {
+ ent->activator = activator;
+ if ( ent->nextthink ) {
+ return; // can't retrigger until the wait is over
+ }
+
+ if ( activator->client ) {
+ if ( ( ent->spawnflags & 1 ) &&
+ activator->client->sess.sessionTeam != TEAM_RED ) {
+ return;
+ }
+ if ( ( ent->spawnflags & 2 ) &&
+ activator->client->sess.sessionTeam != TEAM_BLUE ) {
+ return;
+ }
+ }
+
+ G_UseTargets (ent, ent->activator);
+
+ if ( ent->wait > 0 ) {
+ ent->think = multi_wait;
+ ent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;
+ } else {
+ // we can't just remove (self) here, because this is a touch function
+ // called while looping through area links...
+ ent->touch = 0;
+ ent->nextthink = level.time + FRAMETIME;
+ ent->think = G_FreeEntity;
+ }
+}
+
+void Use_Multi( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
+ multi_trigger( ent, activator );
+}
+
+void Touch_Multi( gentity_t *self, gentity_t *other, trace_t *trace ) {
+ if( !other->client ) {
+ return;
+ }
+ multi_trigger( self, other );
+}
+
+/*QUAKED trigger_multiple (.5 .5 .5) ?
+"wait" : Seconds between triggerings, 0.5 default, -1 = one time only.
+"random" wait variance, default is 0
+Variable sized repeatable trigger. Must be targeted at one or more entities.
+so, the basic time between firing is a random time between
+(wait - random) and (wait + random)
+*/
+void SP_trigger_multiple( gentity_t *ent ) {
+ G_SpawnFloat( "wait", "0.5", &ent->wait );
+ G_SpawnFloat( "random", "0", &ent->random );
+
+ if ( ent->random >= ent->wait && ent->wait >= 0 ) {
+ ent->random = ent->wait - FRAMETIME;
+ G_Printf( "trigger_multiple has random >= wait\n" );
+ }
+
+ ent->touch = Touch_Multi;
+ ent->use = Use_Multi;
+
+ InitTrigger( ent );
+ trap_LinkEntity (ent);
+}
+
+
+
+/*
+==============================================================================
+
+trigger_always
+
+==============================================================================
+*/
+
+void trigger_always_think( gentity_t *ent ) {
+ G_UseTargets(ent, ent);
+ G_FreeEntity( ent );
+}
+
+/*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
+This trigger will always fire. It is activated by the world.
+*/
+void SP_trigger_always (gentity_t *ent) {
+ // we must have some delay to make sure our use targets are present
+ ent->nextthink = level.time + 300;
+ ent->think = trigger_always_think;
+}
+
+
+/*
+==============================================================================
+
+trigger_push
+
+==============================================================================
+*/
+
+void trigger_push_touch (gentity_t *self, gentity_t *other, trace_t *trace ) {
+
+ if ( !other->client ) {
+ return;
+ }
+
+ BG_TouchJumpPad( &other->client->ps, &self->s );
+}
+
+
+/*
+=================
+AimAtTarget
+
+Calculate origin2 so the target apogee will be hit
+=================
+*/
+void AimAtTarget( gentity_t *self ) {
+ gentity_t *ent;
+ vec3_t origin;
+ float height, gravity, time, forward;
+ float dist;
+
+ VectorAdd( self->r.absmin, self->r.absmax, origin );
+ VectorScale ( origin, 0.5, origin );
+
+ ent = G_PickTarget( self->target );
+ if ( !ent ) {
+ G_FreeEntity( self );
+ return;
+ }
+
+ height = ent->s.origin[2] - origin[2];
+ gravity = g_gravity.value*g_gravityModifier.value;
+ time = sqrt( height / ( .5 * gravity ) );
+ if ( !time ) {
+ G_FreeEntity( self );
+ return;
+ }
+
+ // set s.origin2 to the push velocity
+ VectorSubtract ( ent->s.origin, origin, self->s.origin2 );
+ self->s.origin2[2] = 0;
+ dist = VectorNormalize( self->s.origin2);
+
+ forward = dist / time;
+ VectorScale( self->s.origin2, forward, self->s.origin2 );
+
+ self->s.origin2[2] = time * gravity;
+}
+
+
+/*QUAKED trigger_push (.5 .5 .5) ?
+Must point at a target_position, which will be the apex of the leap.
+This will be client side predicted, unlike target_push
+*/
+void SP_trigger_push( gentity_t *self ) {
+ InitTrigger (self);
+
+ // unlike other triggers, we need to send this one to the client
+ self->r.svFlags &= ~SVF_NOCLIENT;
+
+ // make sure the client precaches this sound
+ G_SoundIndex("sound/world/jumppad.wav");
+
+ self->s.eType = ET_PUSH_TRIGGER;
+ self->touch = trigger_push_touch;
+ self->think = AimAtTarget;
+ self->nextthink = level.time + FRAMETIME;
+ trap_LinkEntity (self);
+}
+
+
+void Use_target_push( gentity_t *self, gentity_t *other, gentity_t *activator ) {
+ if ( !activator->client ) {
+ return;
+ }
+
+ if ( activator->client->ps.pm_type != PM_NORMAL ) {
+ return;
+ }
+ if ( activator->client->ps.powerups[PW_FLIGHT] ) {
+ return;
+ }
+
+ VectorCopy (self->s.origin2, activator->client->ps.velocity);
+
+ // play fly sound every 1.5 seconds
+ if ( activator->fly_sound_debounce_time < level.time ) {
+ activator->fly_sound_debounce_time = level.time + 1500;
+ G_Sound( activator, CHAN_AUTO, self->noise_index );
+ }
+}
+
+/*QUAKED target_push (.5 .5 .5) (-8 -8 -8) (8 8 8) bouncepad
+Pushes the activator in the direction.of angle, or towards a target apex.
+"speed" defaults to 1000
+if "bouncepad", play bounce noise instead of windfly
+*/
+void SP_target_push( gentity_t *self ) {
+ if (!self->speed) {
+ self->speed = 1000;
+ }
+ G_SetMovedir (self->s.angles, self->s.origin2);
+ VectorScale (self->s.origin2, self->speed, self->s.origin2);
+
+ if ( self->spawnflags & 1 ) {
+ self->noise_index = G_SoundIndex("sound/world/jumppad.wav");
+ } else {
+ self->noise_index = G_SoundIndex("sound/misc/windfly.wav");
+ }
+ if ( self->target ) {
+ VectorCopy( self->s.origin, self->r.absmin );
+ VectorCopy( self->s.origin, self->r.absmax );
+ self->think = AimAtTarget;
+ self->nextthink = level.time + FRAMETIME;
+ }
+ self->use = Use_target_push;
+}
+
+/*
+==============================================================================
+
+trigger_teleport
+
+==============================================================================
+*/
+
+void trigger_teleporter_touch (gentity_t *self, gentity_t *other, trace_t *trace ) {
+ gentity_t *dest;
+
+ if ( !other->client ) {
+ return;
+ }
+
+ if ( other->client->ps.pm_type == PM_DEAD ) {
+ return;
+ }
+ // Spectators only?
+ if ( ( self->spawnflags & 1 ) &&
+ (other->client->sess.sessionTeam != TEAM_SPECTATOR && other->client->ps.pm_type != PM_SPECTATOR) ) {
+ return;
+ }
+
+
+ dest = G_PickTarget( self->target );
+ if (!dest) {
+ G_Printf ("Couldn't find teleporter destination\n");
+ return;
+ }
+
+ TeleportPlayer( other, dest->s.origin, dest->s.angles );
+}
+
+
+/*QUAKED trigger_teleport (.5 .5 .5) ? SPECTATOR
+Allows client side prediction of teleportation events.
+Must point at a target_position, which will be the teleport destination.
+
+If spectator is set, only spectators can use this teleport
+Spectator teleporters are not normally placed in the editor, but are created
+automatically near doors to allow spectators to move through them
+*/
+void SP_trigger_teleport( gentity_t *self ) {
+ InitTrigger (self);
+
+ // unlike other triggers, we need to send this one to the client
+ // unless is a spectator trigger
+ if ( self->spawnflags & 1 ) {
+ self->r.svFlags |= SVF_NOCLIENT;
+ } else {
+ self->r.svFlags &= ~SVF_NOCLIENT;
+ }
+
+ // make sure the client precaches this sound
+ G_SoundIndex("sound/world/jumppad.wav");
+
+ self->s.eType = ET_TELEPORT_TRIGGER;
+ self->touch = trigger_teleporter_touch;
+
+ trap_LinkEntity (self);
+}
+
+
+/*
+==============================================================================
+
+trigger_hurt
+
+==============================================================================
+*/
+
+/*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF - SILENT NO_PROTECTION SLOW
+Any entity that touches this will be hurt.
+It does dmg points of damage each server frame
+Targeting the trigger will toggle its on / off state.
+
+SILENT supresses playing the sound
+SLOW changes the damage rate to once per second
+NO_PROTECTION *nothing* stops the damage
+
+"dmg" default 5 (whole numbers only)
+
+*/
+void hurt_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
+ if ( self->r.linked ) {
+ trap_UnlinkEntity( self );
+ } else {
+ trap_LinkEntity( self );
+ }
+}
+
+void hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) {
+ int dflags;
+
+ if ( !other->takedamage ) {
+ return;
+ }
+
+ if ( self->timestamp > level.time ) {
+ return;
+ }
+
+ if ( self->spawnflags & 16 ) {
+ self->timestamp = level.time + 1000;
+ } else {
+ self->timestamp = level.time + FRAMETIME;
+ }
+
+ // play sound
+ if ( !(self->spawnflags & 4) ) {
+ G_Sound( other, CHAN_AUTO, self->noise_index );
+ }
+
+ if (self->spawnflags & 8)
+ dflags = DAMAGE_NO_PROTECTION;
+ else
+ dflags = 0;
+ G_Damage (other, self, self, NULL, NULL, self->damage, dflags, MOD_TRIGGER_HURT);
+}
+
+void SP_trigger_hurt( gentity_t *self ) {
+ InitTrigger (self);
+
+ self->noise_index = G_SoundIndex( "sound/world/electro.wav" );
+ self->touch = hurt_touch;
+
+ if ( !self->damage ) {
+ self->damage = 5;
+ }
+
+ self->r.contents = CONTENTS_TRIGGER;
+
+ self->use = hurt_use;
+
+ // link in to the world if starting active
+ if ( self->spawnflags & 1 ) {
+ trap_UnlinkEntity (self);
+ }
+ else
+ {
+ trap_LinkEntity (self);
+ }
+}
+
+
+/*
+==============================================================================
+
+timer
+
+==============================================================================
+*/
+
+
+/*QUAKED func_timer (0.3 0.1 0.6) (-8 -8 -8) (8 8 8) START_ON
+This should be renamed trigger_timer...
+Repeatedly fires its targets.
+Can be turned on or off by using.
+
+"wait" base time between triggering all targets, default is 1
+"random" wait variance, default is 0
+so, the basic time between firing is a random time between
+(wait - random) and (wait + random)
+
+*/
+void func_timer_think( gentity_t *self ) {
+ G_UseTargets (self, self->activator);
+ // set time before next firing
+ self->nextthink = level.time + 1000 * ( self->wait + crandom() * self->random );
+}
+
+void func_timer_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
+ self->activator = activator;
+
+ // if on, turn it off
+ if ( self->nextthink ) {
+ self->nextthink = 0;
+ return;
+ }
+
+ // turn it on
+ func_timer_think (self);
+}
+
+void SP_func_timer( gentity_t *self ) {
+ G_SpawnFloat( "random", "1", &self->random);
+ G_SpawnFloat( "wait", "1", &self->wait );
+
+ self->use = func_timer_use;
+ self->think = func_timer_think;
+
+ if ( self->random >= self->wait ) {
+ self->random = self->wait - FRAMETIME;
+ G_Printf( "func_timer at %s has random >= wait\n", vtos( self->s.origin ) );
+ }
+
+ if ( self->spawnflags & 1 ) {
+ self->nextthink = level.time + FRAMETIME;
+ self->activator = self;
+ }
+
+ self->r.svFlags = SVF_NOCLIENT;
+}
+
+
diff --git a/game/code/game/g_unlagged.c b/code/game/g_unlagged.c
similarity index 100%
rename from game/code/game/g_unlagged.c
rename to code/game/g_unlagged.c
diff --git a/game/code/game/g_utils.c b/code/game/g_utils.c
similarity index 100%
rename from game/code/game/g_utils.c
rename to code/game/g_utils.c
diff --git a/code/game/g_vote.c b/code/game/g_vote.c
new file mode 100644
index 0000000..3695674
--- /dev/null
+++ b/code/game/g_vote.c
@@ -0,0 +1,475 @@
+/*
+===========================================================================
+Copyright (C) 2008-2009 Poul Sander
+
+This file is part of Open Arena source code.
+
+Open Arena source code 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.
+
+Open Arena source code 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 Open Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "g_local.h"
+
+/*
+==================
+allowedVote
+ *Note: Keep this in sync with allowedVote in ui_votemenu.c (except for cg_voteNames and g_voteNames)
+==================
+ */
+#define MAX_VOTENAME_LENGTH 14 //currently the longest string is "/map_restart/\0" (14 chars)
+int allowedVote(char *commandStr) {
+ char tempStr[MAX_VOTENAME_LENGTH];
+ int length;
+ char voteNames[MAX_CVAR_VALUE_STRING];
+ trap_Cvar_VariableStringBuffer( "g_voteNames", voteNames, sizeof( voteNames ) );
+ if(!Q_stricmp(voteNames, "*" ))
+ return qtrue; //if star, everything is allowed
+ length = strlen(commandStr);
+ if(length>MAX_VOTENAME_LENGTH-3)
+ {
+ //Error: too long
+ return qfalse;
+ }
+ //Now constructing a string that starts and ends with '/' like: "/clientkick/"
+ tempStr[0] = '/';
+ strncpy(&tempStr[1],commandStr,length);
+ tempStr[length+1] = '/';
+ tempStr[length+2] = '\0';
+ if(Q_stristr(voteNames,tempStr) != NULL)
+ return qtrue;
+ else
+ return qfalse;
+}
+
+/*
+==================
+getMappage
+==================
+ */
+
+t_mappage getMappage(int page) {
+ t_mappage result;
+ fileHandle_t file;
+ char *token,*pointer;
+ char buffer[MAX_MAPNAME_BUFFER];
+ int i, nummaps,maplen;
+
+ memset(&result,0,sizeof(result));
+ memset(&buffer,0,sizeof(buffer));
+
+ //Check if there is a votemaps.cfg
+ trap_FS_FOpenFile(g_votemaps.string,&file,FS_READ);
+ if(file)
+ {
+ //there is a votemaps.cfg file, take allowed maps from there
+ trap_FS_Read(&buffer,sizeof(buffer),file);
+ pointer = buffer;
+ token = COM_Parse(&pointer);
+ if(token[0]==0 && page == 0) {
+ //First page empty
+ result.pagenumber = -1;
+ trap_FS_FCloseFile(file);
+ return result;
+ }
+ //Skip the first pages
+ for(i=0;i<MAPS_PER_PAGE*page;i++) {
+ token = COM_Parse(&pointer);
+ }
+ if(!token || token[0]==0) {
+ //Page empty, return to first page
+ trap_FS_FCloseFile(file);
+ return getMappage(0);
+ }
+ //There is an actual page:
+ result.pagenumber = page;
+ for(i=0;i<MAPS_PER_PAGE && token;i++) {
+ Q_strncpyz(result.mapname[i],token,MAX_MAPNAME);
+ token = COM_Parse(&pointer);
+ }
+ trap_FS_FCloseFile(file);
+ return result;
+ }
+ //There is no votemaps.cfg file, find filelist of maps
+ nummaps = trap_FS_GetFileList("maps",".bsp",buffer,sizeof(buffer));
+
+ if(nummaps && nummaps<=MAPS_PER_PAGE*page)
+ return getMappage(0);
+
+ pointer = buffer;
+ result.pagenumber = page;
+
+ for (i = 0; i < nummaps; i++, pointer += maplen+1) {
+ maplen = strlen(pointer);
+ if(i>=MAPS_PER_PAGE*page && i<MAPS_PER_PAGE*(page+1)) {
+ Q_strncpyz(result.mapname[i-MAPS_PER_PAGE*page],pointer,maplen-3);
+ }
+ }
+ return result;
+
+}
+
+/*
+==================
+allowedMap
+==================
+ */
+
+int allowedMap(char *mapname) {
+ int length;
+ fileHandle_t file; //To check that the map actually exists.
+ char buffer[MAX_MAPS_TEXT];
+ char *token,*pointer;
+ qboolean found;
+
+ trap_FS_FOpenFile(va("maps/%s.bsp",mapname),&file,FS_READ);
+ if(!file)
+ return qfalse; //maps/MAPNAME.bsp does not exist
+ trap_FS_FCloseFile(file);
+
+ //Now read the file votemaps.cfg to see what maps are allowed
+ trap_FS_FOpenFile(g_votemaps.string,&file,FS_READ);
+
+ if(!file)
+ return qtrue; //if no file, everything is allowed
+ length = strlen(mapname);
+ if(length>MAX_MAPNAME_LENGTH-3)
+ {
+ //Error: too long
+ trap_FS_FCloseFile(file);
+ return qfalse;
+ }
+
+ //Add file checking here
+ trap_FS_Read(&buffer,MAX_MAPS_TEXT,file);
+ found = qfalse;
+ pointer = buffer;
+ token = COM_Parse(&pointer);
+ while(token[0]!=0 && !found) {
+ if(!Q_stricmp(token,mapname))
+ found = qtrue;
+ token = COM_Parse(&pointer);
+ }
+
+ trap_FS_FCloseFile(file);
+ //The map was not found
+ return found;
+}
+
+/*
+==================
+allowedGametype
+==================
+ */
+#define MAX_GAMETYPENAME_LENGTH 5 //currently the longest string is "/12/\0" (5 chars)
+int allowedGametype(char *gametypeStr) {
+ char tempStr[MAX_GAMETYPENAME_LENGTH];
+ int length;
+ char voteGametypes[MAX_CVAR_VALUE_STRING];
+ trap_Cvar_VariableStringBuffer( "g_voteGametypes", voteGametypes, sizeof( voteGametypes ) );
+ if(!Q_stricmp(voteGametypes, "*" ))
+ return qtrue; //if star, everything is allowed
+ length = strlen(gametypeStr);
+ if(length>MAX_GAMETYPENAME_LENGTH-3)
+ {
+ //Error: too long
+ return qfalse;
+ }
+ tempStr[0] = '/';
+ strncpy(&tempStr[1],gametypeStr,length);
+ tempStr[length+1] = '/';
+ tempStr[length+2] = '\0';
+ if(Q_stristr(voteGametypes,tempStr) != NULL)
+ return qtrue;
+ else {
+ return qfalse;
+ }
+}
+
+/*
+==================
+allowedTimelimit
+==================
+ */
+int allowedTimelimit(int limit) {
+ int min, max;
+ min = g_voteMinTimelimit.integer;
+ max = g_voteMaxTimelimit.integer;
+ if(limit<min && limit != 0)
+ return qfalse;
+ if(max!=0 && limit>max)
+ return qfalse;
+ if(limit==0 && max > 0)
+ return qfalse;
+ return qtrue;
+}
+
+/*
+==================
+allowedFraglimit
+==================
+ */
+int allowedFraglimit(int limit) {
+ int min, max;
+ min = g_voteMinFraglimit.integer;
+ max = g_voteMaxFraglimit.integer;
+ if(limit<min && limit != 0)
+ return qfalse;
+ if(max != 0 && limit>max)
+ return qfalse;
+ if(limit==0 && max > 0)
+ return qfalse;
+ return qtrue;
+}
+
+#define MAX_CUSTOM_VOTES 12
+
+char custom_vote_info[1024];
+
+/*
+==================
+VoteParseCustomVotes
+ *Reads the file votecustom.cfg. Finds all the commands that can be used with
+ *"/callvote custom COMMAND" and adds the commands to custom_vote_info
+==================
+ */
+int VoteParseCustomVotes( void ) {
+ fileHandle_t file;
+ char buffer[4*1024];
+ int commands;
+ char *token,*pointer;
+
+ trap_FS_FOpenFile(g_votecustom.string,&file,FS_READ);
+
+ if(!file)
+ return 0;
+
+ memset(&buffer,0,sizeof(buffer));
+ memset(&custom_vote_info,0,sizeof(custom_vote_info));
+
+ commands = 0;
+
+ trap_FS_Read(&buffer,sizeof(buffer),file);
+
+ pointer = buffer;
+
+ while ( commands < MAX_CUSTOM_VOTES ) {
+ token = COM_Parse( &pointer );
+ if ( !token[0] ) {
+ break;
+ }
+
+ if ( !strcmp( token, "votecommand" ) ) {
+ token = COM_Parse( &pointer );
+ Q_strcat(custom_vote_info,sizeof(custom_vote_info),va("%s ",token));
+ commands++;
+ }
+ }
+
+ trap_FS_FCloseFile(file);
+
+ return commands;
+}
+/*
+==================
+getCustomVote
+ *Returns a custom vote. This will go beyond MAX_CUSTOM_VOTES.
+==================
+ */
+t_customvote getCustomVote(char* votecommand) {
+ t_customvote result;
+ fileHandle_t file;
+ char buffer[4*1024];
+ char *token,*pointer;
+ char key[MAX_TOKEN_CHARS];
+
+ trap_FS_FOpenFile(g_votecustom.string,&file,FS_READ);
+
+ if(!file) {
+ memset(&result,0,sizeof(result));
+ return result;
+ }
+
+ memset(&buffer,0,sizeof(buffer));
+
+ trap_FS_Read(&buffer,sizeof(buffer),file);
+
+ pointer = buffer;
+
+ while ( qtrue ) {
+ token = COM_Parse( &pointer );
+ if ( !token[0] ) {
+ break;
+ }
+
+ if ( strcmp( token, "{" ) ) {
+ Com_Printf( "Missing { in votecustom.cfg\n" );
+ break;
+ }
+
+ memset(&result,0,sizeof(result));
+
+ while ( 1 ) {
+ token = COM_ParseExt( &pointer, qtrue );
+ if ( !token[0] ) {
+ Com_Printf( "Unexpected end of customvote.cfg\n" );
+ break;
+ }
+ if ( !strcmp( token, "}" ) ) {
+ break;
+ }
+ Q_strncpyz( key, token, sizeof( key ) );
+
+ token = COM_ParseExt( &pointer, qfalse );
+ if ( !token[0] ) {
+ Com_Printf("Invalid/missing argument to %s in customvote.cfg\n",key);
+ }
+ if(!Q_stricmp(key,"votecommand")) {
+ Q_strncpyz(result.votename,token,sizeof(result.votename));
+ } else if(!Q_stricmp(key,"displayname")) {
+ Q_strncpyz(result.displayname,token,sizeof(result.displayname));
+ } else if(!Q_stricmp(key,"command")) {
+ Q_strncpyz(result.command,token,sizeof(result.command));
+ } else {
+ Com_Printf("Unknown key in customvote.cfg: %s\n",key);
+ }
+
+ }
+
+ if(!Q_stricmp(result.votename,votecommand)) {
+ return result;
+ }
+ }
+
+ //Nothing was found
+ memset(&result,0,sizeof(result));
+ return result;
+}
+
+/*
+==================
+CheckVote
+==================
+*/
+void CheckVote( void ) {
+ if ( level.voteExecuteTime && level.voteExecuteTime < level.time ) {
+ level.voteExecuteTime = 0;
+ trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.voteString ) );
+ }
+ if ( !level.voteTime ) {
+ return;
+ }
+ if ( level.time - level.voteTime >= VOTE_TIME ) {
+ if(g_dmflags.integer & DF_LIGHT_VOTING) {
+ //Let pass if there was at least twice as many for as against
+ if ( level.voteYes > level.voteNo*2 ) {
+ trap_SendServerCommand( -1, "print \"Vote passed. At least 2 of 3 voted yes\n\"" );
+ level.voteExecuteTime = level.time + 3000;
+ } else {
+ //Let pass if there is more yes than no and at least 2 yes votes and at least 30% yes of all on the server
+ if ( level.voteYes > level.voteNo && level.voteYes >= 2 && (level.voteYes*10)>(level.numVotingClients*3) ) {
+ trap_SendServerCommand( -1, "print \"Vote passed. More yes than no.\n\"" );
+ level.voteExecuteTime = level.time + 3000;
+ } else
+ trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
+ }
+ } else {
+ trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
+ }
+ } else {
+ // ATVI Q3 1.32 Patch #9, WNF
+ if ( level.voteYes > (level.numVotingClients)/2 ) {
+ // execute the command, then remove the vote
+ trap_SendServerCommand( -1, "print \"Vote passed.\n\"" );
+ level.voteExecuteTime = level.time + 3000;
+ } else if ( level.voteNo >= (level.numVotingClients)/2 ) {
+ // same behavior as a timeout
+ trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
+ } else {
+ // still waiting for a majority
+ return;
+ }
+ }
+ level.voteTime = 0;
+ trap_SetConfigstring( CS_VOTE_TIME, "" );
+
+}
+
+void ForceFail( void ) {
+ level.voteTime = 0;
+ level.voteExecuteTime = 0;
+ level.voteString[0] = 0;
+ level.voteDisplayString[0] = 0;
+ level.voteKickClient = -1;
+ level.voteKickType = 0;
+ trap_SetConfigstring( CS_VOTE_TIME, "" );
+ trap_SetConfigstring( CS_VOTE_STRING, "" );
+ trap_SetConfigstring( CS_VOTE_YES, "" );
+ trap_SetConfigstring( CS_VOTE_NO, "" );
+}
+
+
+/*
+==================
+CountVotes
+
+ Iterates through all the clients and counts the votes
+==================
+*/
+void CountVotes( void ) {
+ int i;
+ int yes=0,no=0;
+
+ level.numVotingClients=0;
+
+ for ( i = 0 ; i < level.maxclients ; i++ ) {
+ if ( level.clients[ i ].pers.connected != CON_CONNECTED )
+ continue; //Client was not connected
+
+ if (level.clients[i].sess.sessionTeam == TEAM_SPECTATOR)
+ continue; //Don't count spectators
+
+ if ( g_entities[i].r.svFlags & SVF_BOT )
+ continue; //Is a bot
+
+ //The client can vote
+ level.numVotingClients++;
+
+ //Did the client vote yes?
+ if(level.clients[i].vote>0)
+ yes++;
+
+ //Did the client vote no?
+ if(level.clients[i].vote<0)
+ no++;
+ }
+
+ //See if anything has changed
+ if(level.voteYes != yes) {
+ level.voteYes = yes;
+ trap_SetConfigstring( CS_VOTE_YES, va("%i", level.voteYes ) );
+ }
+
+ if(level.voteNo != no) {
+ level.voteNo = no;
+ trap_SetConfigstring( CS_VOTE_NO, va("%i", level.voteNo ) );
+ }
+}
+
+void ClientLeaving(int clientNumber) {
+ if(clientNumber == level.voteKickClient) {
+ ForceFail();
+ }
+}
+
diff --git a/code/game/g_weapon.c b/code/game/g_weapon.c
new file mode 100644
index 0000000..056dd14
--- /dev/null
+++ b/code/game/g_weapon.c
@@ -0,0 +1,1238 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// g_weapon.c
+// perform the server side effects of a weapon firing
+
+#include "g_local.h"
+
+static float s_quadFactor;
+static vec3_t forward, right, up;
+static vec3_t muzzle;
+
+#define NUM_NAILSHOTS 15
+
+/*
+================
+G_BounceProjectile
+================
+*/
+void G_BounceProjectile( vec3_t start, vec3_t impact, vec3_t dir, vec3_t endout ) {
+ vec3_t v, newv;
+ float dot;
+
+ VectorSubtract( impact, start, v );
+ dot = DotProduct( v, dir );
+ VectorMA( v, -2*dot, dir, newv );
+
+ VectorNormalize(newv);
+ VectorMA(impact, 8192, newv, endout);
+}
+
+
+/*
+======================================================================
+
+GAUNTLET
+
+======================================================================
+*/
+
+void Weapon_Gauntlet( gentity_t *ent ) {
+
+}
+
+/*
+===============
+CheckGauntletAttack
+===============
+*/
+qboolean CheckGauntletAttack( gentity_t *ent ) {
+ trace_t tr;
+ vec3_t end;
+ gentity_t *tent;
+ gentity_t *traceEnt;
+ int damage;
+
+ // set aiming directions
+ AngleVectors (ent->client->ps.viewangles, forward, right, up);
+
+ CalcMuzzlePoint ( ent, forward, right, up, muzzle );
+
+ VectorMA (muzzle, 32, forward, end);
+
+ trap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT);
+ if ( tr.surfaceFlags & SURF_NOIMPACT ) {
+ return qfalse;
+ }
+
+ if ( ent->client->noclip ) {
+ return qfalse;
+ }
+
+ traceEnt = &g_entities[ tr.entityNum ];
+
+ // send blood impact
+ if ( traceEnt->takedamage && traceEnt->client ) {
+ tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
+ tent->s.otherEntityNum = traceEnt->s.number;
+ tent->s.eventParm = DirToByte( tr.plane.normal );
+ tent->s.weapon = ent->s.weapon;
+ }
+
+ if ( !traceEnt->takedamage) {
+ return qfalse;
+ }
+
+ if (ent->client->ps.powerups[PW_QUAD] ) {
+ G_AddEvent( ent, EV_POWERUP_QUAD, 0 );
+ s_quadFactor = g_quadfactor.value;
+ } else {
+ s_quadFactor = 1;
+ }
+ if( ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->giTag == PW_DOUBLER ) {
+ s_quadFactor *= 2;
+ }
+
+ if(g_instantgib.integer)
+ damage = 500; //High damage in instant gib (normally enough to gib)
+ else
+ damage = 50 * s_quadFactor;
+ G_Damage( traceEnt, ent, ent, forward, tr.endpos,
+ damage, 0, MOD_GAUNTLET );
+
+ return qtrue;
+}
+
+
+/*
+======================================================================
+
+MACHINEGUN
+
+======================================================================
+*/
+
+/*
+======================
+SnapVectorTowards
+
+Round a vector to integers for more efficient network
+transmission, but make sure that it rounds towards a given point
+rather than blindly truncating. This prevents it from truncating
+into a wall.
+======================
+*/
+//unlagged - attack prediction #3
+// moved to q_shared.c
+/*
+void SnapVectorTowards( vec3_t v, vec3_t to ) {
+ int i;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ if ( to[i] <= v[i] ) {
+ v[i] = floor(v[i]);
+ } else {
+ v[i] = ceil(v[i]);
+ }
+ }
+}
+*/
+//unlagged - attack prediction #3
+
+//unlagged - attack prediction #3
+// moved from g_weapon.c
+/*
+======================
+SnapVectorTowards
+
+Round a vector to integers for more efficient network
+transmission, but make sure that it rounds towards a given point
+rather than blindly truncating. This prevents it from truncating
+into a wall.
+======================
+*/
+void SnapVectorTowards( vec3_t v, vec3_t to ) {
+ int i;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ if ( to[i] <= v[i] ) {
+ v[i] = (int)v[i];
+ } else {
+ v[i] = (int)v[i] + 1;
+ }
+ }
+}
+//unlagged - attack prediction #3
+
+#define CHAINGUN_SPREAD 600.0
+#define MACHINEGUN_SPREAD 200
+#define MACHINEGUN_DAMAGE 7
+#define MACHINEGUN_TEAM_DAMAGE 5 // wimpier MG in teamplay
+
+void Bullet_Fire (gentity_t *ent, float spread, int damage ) {
+ trace_t tr;
+ vec3_t end;
+ vec3_t impactpoint, bouncedir;
+ float r;
+ float u;
+ gentity_t *tent;
+ gentity_t *traceEnt;
+ int i, passent;
+
+//unlagged - attack prediction #2
+ // we have to use something now that the client knows in advance
+ int seed = ent->client->attackTime % 256;
+//unlagged - attack prediction #2
+
+ damage *= s_quadFactor;
+
+//unlagged - attack prediction #2
+ // this has to match what's on the client
+/*
+ r = random() * M_PI * 2.0f;
+ u = sin(r) * crandom() * spread * 16;
+ r = cos(r) * crandom() * spread * 16;
+*/
+ r = Q_random(&seed) * M_PI * 2.0f;
+ u = sin(r) * Q_crandom(&seed) * spread * 16;
+ r = cos(r) * Q_crandom(&seed) * spread * 16;
+//unlagged - attack prediction #2
+
+ VectorMA (muzzle, 8192*16, forward, end);
+ VectorMA (end, r, right, end);
+ VectorMA (end, u, up, end);
+
+ passent = ent->s.number;
+ for (i = 0; i < 10; i++) {
+
+//unlagged - backward reconciliation #2
+ // backward-reconcile the other clients
+ G_DoTimeShiftFor( ent );
+//unlagged - backward reconciliation #2
+
+ trap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT);
+
+//unlagged - backward reconciliation #2
+ // put them back
+ G_UndoTimeShiftFor( ent );
+//unlagged - backward reconciliation #2
+
+ if ( tr.surfaceFlags & SURF_NOIMPACT ) {
+ return;
+ }
+
+ traceEnt = &g_entities[ tr.entityNum ];
+
+ // snap the endpos to integers, but nudged towards the line
+ SnapVectorTowards( tr.endpos, muzzle );
+
+ // send bullet impact
+ if ( traceEnt->takedamage && traceEnt->client ) {
+ tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
+ tent->s.eventParm = traceEnt->s.number;
+//unlagged - attack prediction #2
+ // we need the client number to determine whether or not to
+ // suppress this event
+ tent->s.clientNum = ent->s.clientNum;
+//unlagged - attack prediction #2
+ if( LogAccuracyHit( traceEnt, ent ) ) {
+ ent->client->accuracy_hits++;
+ }
+ } else {
+ tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL );
+ tent->s.eventParm = DirToByte( tr.plane.normal );
+//unlagged - attack prediction #2
+ // we need the client number to determine whether or not to
+ // suppress this event
+ tent->s.clientNum = ent->s.clientNum;
+//unlagged - attack prediction #2
+ }
+ tent->s.otherEntityNum = ent->s.number;
+
+ if ( traceEnt->takedamage) {
+ if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
+ if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
+ G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
+ VectorCopy( impactpoint, muzzle );
+ // the player can hit him/herself with the bounced rail
+ passent = ENTITYNUM_NONE;
+ }
+ else {
+ VectorCopy( tr.endpos, muzzle );
+ passent = traceEnt->s.number;
+ }
+ continue;
+ }
+ else {
+ if(spread == CHAINGUN_SPREAD)
+ {
+ G_Damage( traceEnt, ent, ent, forward, tr.endpos,
+ damage, 0, MOD_CHAINGUN);
+ ent->client->accuracy[WP_CHAINGUN][1]++;
+ }
+ else
+ {
+ G_Damage( traceEnt, ent, ent, forward, tr.endpos,
+ damage, 0, MOD_MACHINEGUN);
+ ent->client->accuracy[WP_MACHINEGUN][1]++;
+ }
+ }
+ }
+ break;
+ }
+}
+
+
+/*
+======================================================================
+
+BFG
+
+======================================================================
+*/
+
+void BFG_Fire ( gentity_t *ent ) {
+ gentity_t *m;
+
+ m = fire_bfg (ent, muzzle, forward);
+ m->damage *= s_quadFactor;
+ m->splashDamage *= s_quadFactor;
+
+// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
+}
+
+
+/*
+======================================================================
+
+SHOTGUN
+
+======================================================================
+*/
+
+// DEFAULT_SHOTGUN_SPREAD and DEFAULT_SHOTGUN_COUNT are in bg_public.h, because
+// client predicts same spreads
+#define DEFAULT_SHOTGUN_DAMAGE 10
+
+qboolean ShotgunPellet( vec3_t start, vec3_t end, gentity_t *ent ) {
+ trace_t tr;
+ int damage, i, passent;
+ gentity_t *traceEnt;
+ vec3_t impactpoint, bouncedir;
+ vec3_t tr_start, tr_end;
+
+ passent = ent->s.number;
+ VectorCopy( start, tr_start );
+ VectorCopy( end, tr_end );
+ for (i = 0; i < 10; i++) {
+ trap_Trace (&tr, tr_start, NULL, NULL, tr_end, passent, MASK_SHOT);
+ traceEnt = &g_entities[ tr.entityNum ];
+
+ // send bullet impact
+ if ( tr.surfaceFlags & SURF_NOIMPACT ) {
+ return qfalse;
+ }
+
+ if ( traceEnt->takedamage) {
+ damage = DEFAULT_SHOTGUN_DAMAGE * s_quadFactor;
+ if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
+ if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
+ G_BounceProjectile( tr_start, impactpoint, bouncedir, tr_end );
+ VectorCopy( impactpoint, tr_start );
+ // the player can hit him/herself with the bounced rail
+ passent = ENTITYNUM_NONE;
+ }
+ else {
+ VectorCopy( tr.endpos, tr_start );
+ passent = traceEnt->s.number;
+ }
+ continue;
+ }
+ else {
+ G_Damage( traceEnt, ent, ent, forward, tr.endpos,
+ damage, 0, MOD_SHOTGUN);
+ if( LogAccuracyHit( traceEnt, ent ) ) {
+ return qtrue;
+ }
+ }
+ }
+ return qfalse;
+ }
+ return qfalse;
+}
+
+// this should match CG_ShotgunPattern
+void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {
+ int i;
+ float r, u;
+ vec3_t end;
+ vec3_t forward, right, up;
+ int oldScore;
+ qboolean hitClient = qfalse;
+
+//unlagged - attack prediction #2
+ // use this for testing
+ //Com_Printf( "Server seed: %d\n", seed );
+//unlagged - attack prediction #2
+
+ // derive the right and up vectors from the forward vector, because
+ // the client won't have any other information
+ VectorNormalize2( origin2, forward );
+ PerpendicularVector( right, forward );
+ CrossProduct( forward, right, up );
+
+ oldScore = ent->client->ps.persistant[PERS_SCORE];
+
+//unlagged - backward reconciliation #2
+ // backward-reconcile the other clients
+ G_DoTimeShiftFor( ent );
+//unlagged - backward reconciliation #2
+
+ // generate the "random" spread pattern
+ for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {
+ r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
+ u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
+ VectorMA( origin, 8192 * 16, forward, end);
+ VectorMA (end, r, right, end);
+ VectorMA (end, u, up, end);
+ if( ShotgunPellet( origin, end, ent ) && !hitClient ) {
+ hitClient = qtrue;
+ ent->client->accuracy_hits++;
+ }
+ }
+ if( hitClient )
+ ent->client->accuracy[WP_SHOTGUN][1]++;
+
+//unlagged - backward reconciliation #2
+ // put them back
+ G_UndoTimeShiftFor( ent );
+//unlagged - backward reconciliation #2
+}
+
+
+void weapon_supershotgun_fire (gentity_t *ent) {
+ gentity_t *tent;
+
+ // send shotgun blast
+ tent = G_TempEntity( muzzle, EV_SHOTGUN );
+ VectorScale( forward, 4096, tent->s.origin2 );
+ SnapVector( tent->s.origin2 );
+//Sago: This sound like a bad idea...
+//unlagged - attack prediction #2
+ // this has to be something the client can predict now
+ //tent->s.eventParm = rand() & 255; // seed for spread pattern
+ tent->s.eventParm = ent->client->attackTime % 256; // seed for spread pattern
+//unlagged - attack prediction #2
+ tent->s.otherEntityNum = ent->s.number;
+
+ ShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent );
+}
+
+
+/*
+======================================================================
+
+GRENADE LAUNCHER
+
+======================================================================
+*/
+
+void weapon_grenadelauncher_fire (gentity_t *ent) {
+ gentity_t *m;
+
+ // extra vertical velocity
+ forward[2] += 0.2f;
+ VectorNormalize( forward );
+
+ m = fire_grenade (ent, muzzle, forward);
+ m->damage *= s_quadFactor;
+ m->splashDamage *= s_quadFactor;
+
+// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
+}
+
+/*
+======================================================================
+
+ROCKET
+
+======================================================================
+*/
+
+void Weapon_RocketLauncher_Fire (gentity_t *ent) {
+ gentity_t *m;
+
+ m = fire_rocket (ent, muzzle, forward);
+ m->damage *= s_quadFactor;
+ m->splashDamage *= s_quadFactor;
+
+// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
+}
+
+
+/*
+======================================================================
+
+PLASMA GUN
+
+======================================================================
+*/
+
+void Weapon_Plasmagun_Fire (gentity_t *ent) {
+ gentity_t *m;
+
+ m = fire_plasma (ent, muzzle, forward);
+ m->damage *= s_quadFactor;
+ m->splashDamage *= s_quadFactor;
+
+// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
+}
+
+/*
+======================================================================
+
+RAILGUN
+
+======================================================================
+*/
+
+
+/*
+=================
+weapon_railgun_fire
+=================
+*/
+#define MAX_RAIL_HITS 4
+void weapon_railgun_fire (gentity_t *ent) {
+ vec3_t end;
+ vec3_t impactpoint, bouncedir;
+ trace_t trace;
+ gentity_t *tent;
+ gentity_t *traceEnt;
+ int damage;
+ int i;
+ int hits;
+ int unlinked;
+ int passent;
+ gentity_t *unlinkedEntities[MAX_RAIL_HITS];
+
+ damage = 100 * s_quadFactor;
+ if(g_instantgib.integer)
+ damage = 800;
+
+ VectorMA (muzzle, 8192, forward, end);
+
+//unlagged - backward reconciliation #2
+ // backward-reconcile the other clients
+ G_DoTimeShiftFor( ent );
+//unlagged - backward reconciliation #2
+
+ // trace only against the solids, so the railgun will go through people
+ unlinked = 0;
+ hits = 0;
+ passent = ent->s.number;
+ do {
+ trap_Trace (&trace, muzzle, NULL, NULL, end, passent, MASK_SHOT );
+ if ( trace.entityNum >= ENTITYNUM_MAX_NORMAL ) {
+ break;
+ }
+ traceEnt = &g_entities[ trace.entityNum ];
+ if ( traceEnt->takedamage ) {
+ if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
+ if ( G_InvulnerabilityEffect( traceEnt, forward, trace.endpos, impactpoint, bouncedir ) ) {
+ G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
+ // snap the endpos to integers to save net bandwidth, but nudged towards the line
+ SnapVectorTowards( trace.endpos, muzzle );
+ // send railgun beam effect
+ tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );
+ // set player number for custom colors on the railtrail
+ tent->s.clientNum = ent->s.clientNum;
+ VectorCopy( muzzle, tent->s.origin2 );
+ // move origin a bit to come closer to the drawn gun muzzle
+ VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
+ VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
+ tent->s.eventParm = 255; // don't make the explosion at the end
+ //
+ VectorCopy( impactpoint, muzzle );
+ // the player can hit him/herself with the bounced rail
+ passent = ENTITYNUM_NONE;
+ }
+ }
+ else {
+ if( LogAccuracyHit( traceEnt, ent ) ) {
+ hits++;
+ }
+ G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
+ }
+ }
+ if ( trace.contents & CONTENTS_SOLID ) {
+ break; // we hit something solid enough to stop the beam
+ }
+ // unlink this entity, so the next trace will go past it
+ trap_UnlinkEntity( traceEnt );
+ unlinkedEntities[unlinked] = traceEnt;
+ unlinked++;
+ } while ( unlinked < MAX_RAIL_HITS );
+
+//unlagged - backward reconciliation #2
+ // put them back
+ G_UndoTimeShiftFor( ent );
+//unlagged - backward reconciliation #2
+
+ // link back in any entities we unlinked
+ for ( i = 0 ; i < unlinked ; i++ ) {
+ trap_LinkEntity( unlinkedEntities[i] );
+ }
+
+ // the final trace endpos will be the terminal point of the rail trail
+
+ // snap the endpos to integers to save net bandwidth, but nudged towards the line
+ SnapVectorTowards( trace.endpos, muzzle );
+
+ // send railgun beam effect
+ tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );
+
+ // set player number for custom colors on the railtrail
+ tent->s.clientNum = ent->s.clientNum;
+
+ VectorCopy( muzzle, tent->s.origin2 );
+ // move origin a bit to come closer to the drawn gun muzzle
+ VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
+ VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
+
+ // no explosion at end if SURF_NOIMPACT, but still make the trail
+ if ( trace.surfaceFlags & SURF_NOIMPACT ) {
+ tent->s.eventParm = 255; // don't make the explosion at the end
+ } else {
+ tent->s.eventParm = DirToByte( trace.plane.normal );
+ }
+ tent->s.clientNum = ent->s.clientNum;
+
+ // give the shooter a reward sound if they have made two railgun hits in a row
+ if ( hits == 0 ) {
+ // complete miss
+ ent->client->accurateCount = 0;
+ } else {
+ // check for "impressive" reward sound
+ ent->client->accurateCount += hits;
+ if ( ent->client->accurateCount >= 2 ) {
+ ent->client->accurateCount -= 2;
+ ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
+ G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", ent->client->ps.clientNum, 2, ent->client->pers.netname, "IMPRESSIVE" );
+ if(!level.hadBots) //There has not been any bots
+ ChallengeMessage(ent,AWARD_IMPRESSIVE);
+ // add the sprite over the player's head
+ ent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
+ ent->client->ps.eFlags |= EF_AWARD_IMPRESSIVE;
+ ent->client->rewardTime = level.time + REWARD_SPRITE_TIME;
+ }
+ ent->client->accuracy_hits++;
+ ent->client->accuracy[WP_RAILGUN][1]++;
+ }
+
+}
+
+
+/*
+======================================================================
+
+GRAPPLING HOOK
+
+======================================================================
+*/
+
+void Weapon_GrapplingHook_Fire (gentity_t *ent)
+{
+ if (!ent->client->fireHeld && !ent->client->hook)
+ fire_grapple (ent, muzzle, forward);
+
+ ent->client->fireHeld = qtrue;
+}
+
+void Weapon_HookFree (gentity_t *ent)
+{
+ ent->parent->client->hook = NULL;
+ ent->parent->client->ps.pm_flags &= ~PMF_GRAPPLE_PULL;
+ G_FreeEntity( ent );
+}
+
+void Weapon_HookThink (gentity_t *ent)
+{
+ if (ent->enemy) {
+ vec3_t v, oldorigin;
+
+ VectorCopy(ent->r.currentOrigin, oldorigin);
+ v[0] = ent->enemy->r.currentOrigin[0] + (ent->enemy->r.mins[0] + ent->enemy->r.maxs[0]) * 0.5;
+ v[1] = ent->enemy->r.currentOrigin[1] + (ent->enemy->r.mins[1] + ent->enemy->r.maxs[1]) * 0.5;
+ v[2] = ent->enemy->r.currentOrigin[2] + (ent->enemy->r.mins[2] + ent->enemy->r.maxs[2]) * 0.5;
+ SnapVectorTowards( v, oldorigin ); // save net bandwidth
+
+ G_SetOrigin( ent, v );
+ }
+
+ VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);
+}
+
+/*
+======================================================================
+
+LIGHTNING GUN
+
+======================================================================
+*/
+
+void Weapon_LightningFire( gentity_t *ent ) {
+ trace_t tr;
+ vec3_t end;
+ vec3_t impactpoint, bouncedir;
+ gentity_t *traceEnt, *tent;
+ int damage, i, passent;
+
+ damage = 8 * s_quadFactor;
+
+ passent = ent->s.number;
+ for (i = 0; i < 10; i++) {
+ VectorMA( muzzle, LIGHTNING_RANGE, forward, end );
+
+//Sago: I'm not sure this should recieve backward reconciliation. It is not a real instant hit weapon, it can normally be dogded
+//unlagged - backward reconciliation #2
+ // backward-reconcile the other clients
+ G_DoTimeShiftFor( ent );
+//unlagged - backward reconciliation #2
+
+ trap_Trace( &tr, muzzle, NULL, NULL, end, passent, MASK_SHOT );
+
+//unlagged - backward reconciliation #2
+ // put them back
+ G_UndoTimeShiftFor( ent );
+//unlagged - backward reconciliation #2
+
+ // if not the first trace (the lightning bounced of an invulnerability sphere)
+ if (i) {
+ // add bounced off lightning bolt temp entity
+ // the first lightning bolt is a cgame only visual
+ //
+ tent = G_TempEntity( muzzle, EV_LIGHTNINGBOLT );
+ VectorCopy( tr.endpos, end );
+ SnapVector( end );
+ VectorCopy( end, tent->s.origin2 );
+ }
+ if ( tr.entityNum == ENTITYNUM_NONE ) {
+ return;
+ }
+
+ traceEnt = &g_entities[ tr.entityNum ];
+
+ if ( traceEnt->takedamage) {
+ if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
+ if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
+ G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
+ VectorCopy( impactpoint, muzzle );
+ VectorSubtract( end, impactpoint, forward );
+ VectorNormalize(forward);
+ // the player can hit him/herself with the bounced lightning
+ passent = ENTITYNUM_NONE;
+ }
+ else {
+ VectorCopy( tr.endpos, muzzle );
+ passent = traceEnt->s.number;
+ }
+ continue;
+ }
+ else {
+ G_Damage( traceEnt, ent, ent, forward, tr.endpos,
+ damage, 0, MOD_LIGHTNING);
+ }
+ }
+
+ if ( traceEnt->takedamage && traceEnt->client ) {
+ tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
+ tent->s.otherEntityNum = traceEnt->s.number;
+ tent->s.eventParm = DirToByte( tr.plane.normal );
+ tent->s.weapon = ent->s.weapon;
+ if( LogAccuracyHit( traceEnt, ent ) ) {
+ ent->client->accuracy_hits++;
+ ent->client->accuracy[WP_LIGHTNING][1]++;
+ }
+ } else if ( !( tr.surfaceFlags & SURF_NOIMPACT ) ) {
+ tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS );
+ tent->s.eventParm = DirToByte( tr.plane.normal );
+ }
+
+ break;
+ }
+}
+
+/*
+======================================================================
+
+NAILGUN
+
+======================================================================
+*/
+
+void Weapon_Nailgun_Fire (gentity_t *ent) {
+ gentity_t *m;
+ int count;
+
+ for( count = 0; count < NUM_NAILSHOTS; count++ ) {
+ m = fire_nail (ent, muzzle, forward, right, up );
+ m->damage *= s_quadFactor;
+ m->splashDamage *= s_quadFactor;
+ }
+
+// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
+}
+
+
+/*
+======================================================================
+
+PROXIMITY MINE LAUNCHER
+
+======================================================================
+*/
+
+void weapon_proxlauncher_fire (gentity_t *ent) {
+ gentity_t *m;
+
+ // extra vertical velocity
+ forward[2] += 0.2f;
+ VectorNormalize( forward );
+
+ m = fire_prox (ent, muzzle, forward);
+ m->damage *= s_quadFactor;
+ m->splashDamage *= s_quadFactor;
+
+// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
+}
+
+
+//======================================================================
+
+
+/*
+===============
+LogAccuracyHit
+===============
+*/
+qboolean LogAccuracyHit( gentity_t *target, gentity_t *attacker ) {
+ if( !target->takedamage ) {
+ return qfalse;
+ }
+
+ if ( target == attacker ) {
+ return qfalse;
+ }
+
+ if( !target->client ) {
+ return qfalse;
+ }
+
+ if( !attacker->client ) {
+ return qfalse;
+ }
+
+ if( target->client->ps.stats[STAT_HEALTH] <= 0 ) {
+ return qfalse;
+ }
+
+ if ( OnSameTeam( target, attacker ) ) {
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+
+/*
+===============
+CalcMuzzlePoint
+
+set muzzle location relative to pivoting eye
+===============
+*/
+void CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {
+ VectorCopy( ent->s.pos.trBase, muzzlePoint );
+ muzzlePoint[2] += ent->client->ps.viewheight;
+ VectorMA( muzzlePoint, 14, forward, muzzlePoint );
+ // snap to integer coordinates for more efficient network bandwidth usage
+ SnapVector( muzzlePoint );
+}
+
+/*
+===============
+CalcMuzzlePointOrigin
+
+set muzzle location relative to pivoting eye
+===============
+*/
+void CalcMuzzlePointOrigin ( gentity_t *ent, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {
+ VectorCopy( ent->s.pos.trBase, muzzlePoint );
+ muzzlePoint[2] += ent->client->ps.viewheight;
+ VectorMA( muzzlePoint, 14, forward, muzzlePoint );
+ // snap to integer coordinates for more efficient network bandwidth usage
+ SnapVector( muzzlePoint );
+}
+
+
+
+/*
+===============
+FireWeapon
+===============
+*/
+void FireWeapon( gentity_t *ent ) {
+ //Make people drop out of follow mode (this should be moved, so people can change betwean players.)
+ if (ent->client->sess.spectatorState == SPECTATOR_FOLLOW) {
+ StopFollowing( ent );
+ return;
+ }
+
+ if (ent->client->ps.powerups[PW_QUAD] ) {
+ s_quadFactor = g_quadfactor.value;
+ } else {
+ s_quadFactor = 1;
+ }
+ if( ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->giTag == PW_DOUBLER ) {
+ s_quadFactor *= 2;
+ }
+
+ if (ent->client->spawnprotected)
+ ent->client->spawnprotected = qfalse;
+
+ // track shots taken for accuracy tracking. Grapple is not a weapon and gauntet is just not tracked
+ if( ent->s.weapon != WP_GRAPPLING_HOOK && ent->s.weapon != WP_GAUNTLET ) {
+ if( ent->s.weapon == WP_NAILGUN ) {
+ ent->client->accuracy_shots += NUM_NAILSHOTS;
+ ent->client->accuracy[WP_NAILGUN][0]++;
+ } else {
+ ent->client->accuracy_shots++;
+ ent->client->accuracy[ent->s.weapon][0]++;
+ }
+ }
+
+ // set aiming directions
+ AngleVectors (ent->client->ps.viewangles, forward, right, up);
+
+ CalcMuzzlePointOrigin ( ent, ent->client->oldOrigin, forward, right, up, muzzle );
+
+ // fire the specific weapon
+ switch( ent->s.weapon ) {
+ case WP_GAUNTLET:
+ Weapon_Gauntlet( ent );
+ break;
+ case WP_LIGHTNING:
+ Weapon_LightningFire( ent );
+ break;
+ case WP_SHOTGUN:
+ weapon_supershotgun_fire( ent );
+ break;
+ case WP_MACHINEGUN:
+ if ( g_gametype.integer != GT_TEAM ) {
+ Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_DAMAGE );
+ } else {
+ Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_TEAM_DAMAGE );
+ }
+ break;
+ case WP_GRENADE_LAUNCHER:
+ weapon_grenadelauncher_fire( ent );
+ break;
+ case WP_ROCKET_LAUNCHER:
+ Weapon_RocketLauncher_Fire( ent );
+ break;
+ case WP_PLASMAGUN:
+ Weapon_Plasmagun_Fire( ent );
+ break;
+ case WP_RAILGUN:
+ weapon_railgun_fire( ent );
+ break;
+ case WP_BFG:
+ BFG_Fire( ent );
+ break;
+ case WP_GRAPPLING_HOOK:
+ Weapon_GrapplingHook_Fire( ent );
+ break;
+ case WP_NAILGUN:
+ Weapon_Nailgun_Fire( ent );
+ break;
+ case WP_PROX_LAUNCHER:
+ weapon_proxlauncher_fire( ent );
+ break;
+ case WP_CHAINGUN:
+ Bullet_Fire( ent, CHAINGUN_SPREAD, MACHINEGUN_DAMAGE );
+ break;
+ default:
+// FIXME G_Error( "Bad ent->s.weapon" );
+ break;
+ }
+}
+
+
+/*
+===============
+KamikazeRadiusDamage
+===============
+*/
+static void KamikazeRadiusDamage( vec3_t origin, gentity_t *attacker, float damage, float radius ) {
+ float dist;
+ gentity_t *ent;
+ int entityList[MAX_GENTITIES];
+ int numListedEntities;
+ vec3_t mins, maxs;
+ vec3_t v;
+ vec3_t dir;
+ int i, e;
+
+ if ( radius < 1 ) {
+ radius = 1;
+ }
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ mins[i] = origin[i] - radius;
+ maxs[i] = origin[i] + radius;
+ }
+
+ numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+
+ for ( e = 0 ; e < numListedEntities ; e++ ) {
+ ent = &g_entities[entityList[ e ]];
+
+ if (!ent->takedamage) {
+ continue;
+ }
+
+ // dont hit things we have already hit
+ if( ent->kamikazeTime > level.time ) {
+ continue;
+ }
+
+ // find the distance from the edge of the bounding box
+ for ( i = 0 ; i < 3 ; i++ ) {
+ if ( origin[i] < ent->r.absmin[i] ) {
+ v[i] = ent->r.absmin[i] - origin[i];
+ } else if ( origin[i] > ent->r.absmax[i] ) {
+ v[i] = origin[i] - ent->r.absmax[i];
+ } else {
+ v[i] = 0;
+ }
+ }
+
+ dist = VectorLength( v );
+ if ( dist >= radius ) {
+ continue;
+ }
+
+// if( CanDamage (ent, origin) ) {
+ VectorSubtract (ent->r.currentOrigin, origin, dir);
+ // push the center of mass higher than the origin so players
+ // get knocked into the air more
+ dir[2] += 24;
+ G_Damage( ent, NULL, attacker, dir, origin, damage, DAMAGE_RADIUS|DAMAGE_NO_TEAM_PROTECTION, MOD_KAMIKAZE );
+ ent->kamikazeTime = level.time + 3000;
+// }
+ }
+}
+
+/*
+===============
+KamikazeShockWave
+===============
+*/
+static void KamikazeShockWave( vec3_t origin, gentity_t *attacker, float damage, float push, float radius ) {
+ float dist;
+ gentity_t *ent;
+ int entityList[MAX_GENTITIES];
+ int numListedEntities;
+ vec3_t mins, maxs;
+ vec3_t v;
+ vec3_t dir;
+ int i, e;
+
+ if ( radius < 1 )
+ radius = 1;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ mins[i] = origin[i] - radius;
+ maxs[i] = origin[i] + radius;
+ }
+
+ numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+
+ for ( e = 0 ; e < numListedEntities ; e++ ) {
+ ent = &g_entities[entityList[ e ]];
+
+ // dont hit things we have already hit
+ if( ent->kamikazeShockTime > level.time ) {
+ continue;
+ }
+
+ // find the distance from the edge of the bounding box
+ for ( i = 0 ; i < 3 ; i++ ) {
+ if ( origin[i] < ent->r.absmin[i] ) {
+ v[i] = ent->r.absmin[i] - origin[i];
+ } else if ( origin[i] > ent->r.absmax[i] ) {
+ v[i] = origin[i] - ent->r.absmax[i];
+ } else {
+ v[i] = 0;
+ }
+ }
+
+ dist = VectorLength( v );
+ if ( dist >= radius ) {
+ continue;
+ }
+
+// if( CanDamage (ent, origin) ) {
+ VectorSubtract (ent->r.currentOrigin, origin, dir);
+ dir[2] += 24;
+ G_Damage( ent, NULL, attacker, dir, origin, damage, DAMAGE_RADIUS|DAMAGE_NO_TEAM_PROTECTION, MOD_KAMIKAZE );
+ //
+ dir[2] = 0;
+ VectorNormalize(dir);
+ if ( ent->client ) {
+ ent->client->ps.velocity[0] = dir[0] * push;
+ ent->client->ps.velocity[1] = dir[1] * push;
+ ent->client->ps.velocity[2] = 100;
+ }
+ ent->kamikazeShockTime = level.time + 3000;
+// }
+ }
+}
+
+/*
+===============
+KamikazeDamage
+===============
+*/
+static void KamikazeDamage( gentity_t *self ) {
+ int i;
+ float t;
+ gentity_t *ent;
+ vec3_t newangles;
+
+ self->count += 100;
+
+ if (self->count >= KAMI_SHOCKWAVE_STARTTIME) {
+ // shockwave push back
+ t = self->count - KAMI_SHOCKWAVE_STARTTIME;
+ KamikazeShockWave(self->s.pos.trBase, self->activator, 25, 400, (int) (float) t * KAMI_SHOCKWAVE_MAXRADIUS / (KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVE_STARTTIME) );
+ }
+ //
+ if (self->count >= KAMI_EXPLODE_STARTTIME) {
+ // do our damage
+ t = self->count - KAMI_EXPLODE_STARTTIME;
+ KamikazeRadiusDamage( self->s.pos.trBase, self->activator, 400, (int) (float) t * KAMI_BOOMSPHERE_MAXRADIUS / (KAMI_IMPLODE_STARTTIME - KAMI_EXPLODE_STARTTIME) );
+ }
+
+ // either cycle or kill self
+ if( self->count >= KAMI_SHOCKWAVE_ENDTIME ) {
+ G_FreeEntity( self );
+ return;
+ }
+ self->nextthink = level.time + 100;
+
+ // add earth quake effect
+ newangles[0] = crandom() * 2;
+ newangles[1] = crandom() * 2;
+ newangles[2] = 0;
+ for (i = 0; i < MAX_CLIENTS; i++)
+ {
+ ent = &g_entities[i];
+ if (!ent->inuse)
+ continue;
+ if (!ent->client)
+ continue;
+
+ if (ent->client->ps.groundEntityNum != ENTITYNUM_NONE) {
+ ent->client->ps.velocity[0] += crandom() * 120;
+ ent->client->ps.velocity[1] += crandom() * 120;
+ ent->client->ps.velocity[2] = 30 + random() * 25;
+ }
+
+ ent->client->ps.delta_angles[0] += ANGLE2SHORT(newangles[0] - self->movedir[0]);
+ ent->client->ps.delta_angles[1] += ANGLE2SHORT(newangles[1] - self->movedir[1]);
+ ent->client->ps.delta_angles[2] += ANGLE2SHORT(newangles[2] - self->movedir[2]);
+ }
+ VectorCopy(newangles, self->movedir);
+}
+
+/*
+===============
+G_StartKamikaze
+===============
+*/
+void G_StartKamikaze( gentity_t *ent ) {
+ gentity_t *explosion;
+ gentity_t *te;
+ vec3_t snapped;
+
+ // start up the explosion logic
+ explosion = G_Spawn();
+
+ explosion->s.eType = ET_EVENTS + EV_KAMIKAZE;
+ explosion->eventTime = level.time;
+
+ if ( ent->client ) {
+ VectorCopy( ent->s.pos.trBase, snapped );
+ }
+ else {
+ VectorCopy( ent->activator->s.pos.trBase, snapped );
+ }
+ SnapVector( snapped ); // save network bandwidth
+ G_SetOrigin( explosion, snapped );
+
+ explosion->classname = "kamikaze";
+ explosion->s.pos.trType = TR_STATIONARY;
+
+ explosion->kamikazeTime = level.time;
+
+ explosion->think = KamikazeDamage;
+ explosion->nextthink = level.time + 100;
+ explosion->count = 0;
+ VectorClear(explosion->movedir);
+
+ trap_LinkEntity( explosion );
+
+ if (ent->client) {
+ //
+ explosion->activator = ent;
+ //
+ ent->s.eFlags &= ~EF_KAMIKAZE;
+ // nuke the guy that used it
+ G_Damage( ent, ent, ent, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_KAMIKAZE );
+ }
+ else {
+ if ( !strcmp(ent->activator->classname, "bodyque") ) {
+ explosion->activator = &g_entities[ent->activator->r.ownerNum];
+ }
+ else {
+ explosion->activator = ent->activator;
+ }
+ }
+
+ // play global sound at all clients
+ te = G_TempEntity(snapped, EV_GLOBAL_TEAM_SOUND );
+ te->r.svFlags |= SVF_BROADCAST;
+ te->s.eventParm = GTS_KAMIKAZE;
+}
diff --git a/game/code/game/inv.h b/code/game/inv.h
similarity index 100%
rename from game/code/game/inv.h
rename to code/game/inv.h
diff --git a/game/code/game/match.h b/code/game/match.h
similarity index 100%
rename from game/code/game/match.h
rename to code/game/match.h
diff --git a/engine/code/game/syn.h b/code/game/syn.h
similarity index 100%
rename from engine/code/game/syn.h
rename to code/game/syn.h
diff --git a/game/code/q3_ui/q3_ui.q3asm b/code/q3_ui/q3_ui.q3asm
similarity index 100%
rename from game/code/q3_ui/q3_ui.q3asm
rename to code/q3_ui/q3_ui.q3asm
diff --git a/game/code/q3_ui/ui_addbots.c b/code/q3_ui/ui_addbots.c
similarity index 100%
rename from game/code/q3_ui/ui_addbots.c
rename to code/q3_ui/ui_addbots.c
diff --git a/code/q3_ui/ui_atoms.c b/code/q3_ui/ui_atoms.c
new file mode 100644
index 0000000..7f40b9b
--- /dev/null
+++ b/code/q3_ui/ui_atoms.c
@@ -0,0 +1,1284 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+/**********************************************************************
+ UI_ATOMS.C
+
+ User interface building blocks and support functions.
+**********************************************************************/
+#include "ui_local.h"
+
+uiStatic_t uis;
+qboolean m_entersound; // after a frame, so caching won't disrupt the sound
+
+void QDECL Com_Error( int level, const char *error, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, error);
+ Q_vsnprintf (text, sizeof(text), error, argptr);
+ va_end (argptr);
+
+ trap_Error( va("%s", text) );
+}
+
+void QDECL Com_Printf( const char *msg, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, msg);
+ Q_vsnprintf (text, sizeof(text), msg, argptr);
+ va_end (argptr);
+
+ trap_Print( va("%s", text) );
+}
+
+/*
+=================
+UI_ClampCvar
+=================
+*/
+float UI_ClampCvar( float min, float max, float value )
+{
+ if ( value < min ) return min;
+ if ( value > max ) return max;
+ return value;
+}
+
+/*
+=================
+UI_StartDemoLoop
+=================
+*/
+void UI_StartDemoLoop( void ) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, "d1\n" );
+}
+
+/*
+=================
+UI_PushMenu
+=================
+*/
+void UI_PushMenu( menuframework_s *menu )
+{
+ int i;
+ menucommon_s* item;
+
+ // avoid stacking menus invoked by hotkeys
+ for (i=0 ; i<uis.menusp ; i++)
+ {
+ if (uis.stack[i] == menu)
+ {
+ uis.menusp = i;
+ break;
+ }
+ }
+
+ if (i == uis.menusp)
+ {
+ if (uis.menusp >= MAX_MENUDEPTH)
+ trap_Error("UI_PushMenu: menu stack overflow");
+
+ uis.stack[uis.menusp++] = menu;
+ }
+
+ uis.activemenu = menu;
+
+ // default cursor position
+ menu->cursor = 0;
+ menu->cursor_prev = 0;
+
+ m_entersound = qtrue;
+
+ trap_Key_SetCatcher( KEYCATCH_UI );
+
+ // force first available item to have focus
+ for (i=0; i<menu->nitems; i++)
+ {
+ item = (menucommon_s *)menu->items[i];
+ if (!(item->flags & (QMF_GRAYED|QMF_MOUSEONLY|QMF_INACTIVE)))
+ {
+ menu->cursor_prev = -1;
+ Menu_SetCursor( menu, i );
+ break;
+ }
+ }
+
+ uis.firstdraw = qtrue;
+}
+
+/*
+=================
+UI_PopMenu
+=================
+*/
+void UI_PopMenu (void)
+{
+ trap_S_StartLocalSound( menu_out_sound, CHAN_LOCAL_SOUND );
+
+ uis.menusp--;
+
+ if (uis.menusp < 0)
+ trap_Error ("UI_PopMenu: menu stack underflow");
+
+ if (uis.menusp) {
+ uis.activemenu = uis.stack[uis.menusp-1];
+ uis.firstdraw = qtrue;
+ }
+ else {
+ UI_ForceMenuOff ();
+ }
+}
+
+void UI_ForceMenuOff (void)
+{
+ uis.menusp = 0;
+ uis.activemenu = NULL;
+
+ trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
+ trap_Key_ClearStates();
+ trap_Cvar_Set( "cl_paused", "0" );
+}
+
+/*
+=================
+UI_LerpColor
+=================
+*/
+void UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)
+{
+ int i;
+
+ // lerp and clamp each component
+ for (i=0; i<4; i++)
+ {
+ c[i] = a[i] + t*(b[i]-a[i]);
+ if (c[i] < 0)
+ c[i] = 0;
+ else if (c[i] > 1.0)
+ c[i] = 1.0;
+ }
+}
+
+/*
+=================
+UI_DrawProportionalString2
+=================
+*/
+static int propMap[128][3] = {
+{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
+{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
+
+{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
+{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
+
+{0, 0, PROP_SPACE_WIDTH}, // SPACE
+{11, 122, 7}, // !
+{154, 181, 14}, // "
+{55, 122, 17}, // #
+{79, 122, 18}, // $
+{101, 122, 23}, // %
+{153, 122, 18}, // &
+{9, 93, 7}, // '
+{207, 122, 8}, // (
+{230, 122, 9}, // )
+{177, 122, 18}, // *
+{30, 152, 18}, // +
+{85, 181, 7}, // ,
+{34, 93, 11}, // -
+{110, 181, 6}, // .
+{130, 152, 14}, // /
+
+{22, 64, 17}, // 0
+{41, 64, 12}, // 1
+{58, 64, 17}, // 2
+{78, 64, 18}, // 3
+{98, 64, 19}, // 4
+{120, 64, 18}, // 5
+{141, 64, 18}, // 6
+{204, 64, 16}, // 7
+{162, 64, 17}, // 8
+{182, 64, 18}, // 9
+{59, 181, 7}, // :
+{35,181, 7}, // ;
+{203, 152, 14}, // <
+{56, 93, 14}, // =
+{228, 152, 14}, // >
+{177, 181, 18}, // ?
+
+{28, 122, 22}, // @
+{5, 4, 18}, // A
+{27, 4, 18}, // B
+{48, 4, 18}, // C
+{69, 4, 17}, // D
+{90, 4, 13}, // E
+{106, 4, 13}, // F
+{121, 4, 18}, // G
+{143, 4, 17}, // H
+{164, 4, 8}, // I
+{175, 4, 16}, // J
+{195, 4, 18}, // K
+{216, 4, 12}, // L
+{230, 4, 23}, // M
+{6, 34, 18}, // N
+{27, 34, 18}, // O
+
+{48, 34, 18}, // P
+{68, 34, 18}, // Q
+{90, 34, 17}, // R
+{110, 34, 18}, // S
+{130, 34, 14}, // T
+{146, 34, 18}, // U
+{166, 34, 19}, // V
+{185, 34, 29}, // W
+{215, 34, 18}, // X
+{234, 34, 18}, // Y
+{5, 64, 14}, // Z
+{60, 152, 7}, // [
+{106, 151, 13}, // '\'
+{83, 152, 7}, // ]
+{128, 122, 17}, // ^
+{4, 152, 21}, // _
+
+{134, 181, 5}, // '
+{5, 4, 18}, // A
+{27, 4, 18}, // B
+{48, 4, 18}, // C
+{69, 4, 17}, // D
+{90, 4, 13}, // E
+{106, 4, 13}, // F
+{121, 4, 18}, // G
+{143, 4, 17}, // H
+{164, 4, 8}, // I
+{175, 4, 16}, // J
+{195, 4, 18}, // K
+{216, 4, 12}, // L
+{230, 4, 23}, // M
+{6, 34, 18}, // N
+{27, 34, 18}, // O
+
+{48, 34, 18}, // P
+{68, 34, 18}, // Q
+{90, 34, 17}, // R
+{110, 34, 18}, // S
+{130, 34, 14}, // T
+{146, 34, 18}, // U
+{166, 34, 19}, // V
+{185, 34, 29}, // W
+{215, 34, 18}, // X
+{234, 34, 18}, // Y
+{5, 64, 14}, // Z
+{153, 152, 13}, // {
+{11, 181, 5}, // |
+{180, 152, 13}, // }
+{79, 93, 17}, // ~
+{0, 0, -1} // DEL
+};
+
+static int propMapB[26][3] = {
+{11, 12, 33},
+{49, 12, 31},
+{85, 12, 31},
+{120, 12, 30},
+{156, 12, 21},
+{183, 12, 21},
+{207, 12, 32},
+
+{13, 55, 30},
+{49, 55, 13},
+{66, 55, 29},
+{101, 55, 31},
+{135, 55, 21},
+{158, 55, 40},
+{204, 55, 32},
+
+{12, 97, 31},
+{48, 97, 31},
+{82, 97, 30},
+{118, 97, 30},
+{153, 97, 30},
+{185, 97, 25},
+{213, 97, 30},
+
+{11, 139, 32},
+{42, 139, 51},
+{93, 139, 32},
+{126, 139, 31},
+{158, 139, 25},
+};
+
+#define PROPB_GAP_WIDTH 4
+#define PROPB_SPACE_WIDTH 12
+#define PROPB_HEIGHT 36
+
+// bk001205 - code below duplicated in cgame/cg_drawtools.c
+// bk001205 - FIXME: does this belong in ui_shared.c?
+/*
+=================
+UI_DrawBannerString
+=================
+*/
+static void UI_DrawBannerString2( int x, int y, const char* str, vec4_t color )
+{
+ const char* s;
+ unsigned char ch; // bk001204 - unsigned
+ float ax;
+ float ay;
+ float aw;
+ float ah;
+ float frow;
+ float fcol;
+ float fwidth;
+ float fheight;
+
+ // draw the colored text
+ trap_R_SetColor( color );
+
+ ax = x * uis.xscale + uis.bias;
+ ay = y * uis.yscale;
+
+ s = str;
+ while ( *s )
+ {
+ ch = *s & 127;
+ if ( ch == ' ' ) {
+ ax += ((float)PROPB_SPACE_WIDTH + (float)PROPB_GAP_WIDTH)* uis.xscale;
+ }
+ else if ( ch >= 'A' && ch <= 'Z' ) {
+ ch -= 'A';
+ fcol = (float)propMapB[ch][0] / 256.0f;
+ frow = (float)propMapB[ch][1] / 256.0f;
+ fwidth = (float)propMapB[ch][2] / 256.0f;
+ fheight = (float)PROPB_HEIGHT / 256.0f;
+ aw = (float)propMapB[ch][2] * uis.xscale;
+ ah = (float)PROPB_HEIGHT * uis.yscale;
+ trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, uis.charsetPropB );
+ ax += (aw + (float)PROPB_GAP_WIDTH * uis.xscale);
+ }
+ s++;
+ }
+
+ trap_R_SetColor( NULL );
+}
+
+void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color ) {
+ const char * s;
+ int ch;
+ int width;
+ vec4_t drawcolor;
+
+ // find the width of the drawn text
+ s = str;
+ width = 0;
+ while ( *s ) {
+ ch = *s;
+ if ( ch == ' ' ) {
+ width += PROPB_SPACE_WIDTH;
+ }
+ else if ( ch >= 'A' && ch <= 'Z' ) {
+ width += propMapB[ch - 'A'][2] + PROPB_GAP_WIDTH;
+ }
+ s++;
+ }
+ width -= PROPB_GAP_WIDTH;
+
+ switch( style & UI_FORMATMASK ) {
+ case UI_CENTER:
+ x -= width / 2;
+ break;
+
+ case UI_RIGHT:
+ x -= width;
+ break;
+
+ case UI_LEFT:
+ default:
+ break;
+ }
+
+ if ( style & UI_DROPSHADOW ) {
+ drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
+ drawcolor[3] = color[3];
+ UI_DrawBannerString2( x+2, y+2, str, drawcolor );
+ }
+
+ UI_DrawBannerString2( x, y, str, color );
+}
+
+
+int UI_ProportionalStringWidth( const char* str ) {
+ const char * s;
+ int ch;
+ int charWidth;
+ int width;
+
+ s = str;
+ width = 0;
+ while ( *s ) {
+ ch = *s & 127;
+ charWidth = propMap[ch][2];
+ if ( charWidth != -1 ) {
+ width += charWidth;
+ width += PROP_GAP_WIDTH;
+ }
+ s++;
+ }
+
+ width -= PROP_GAP_WIDTH;
+ return width;
+}
+
+static void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t color, float sizeScale, qhandle_t charset )
+{
+ const char* s;
+ unsigned char ch; // bk001204 - unsigned
+ float ax;
+ float ay;
+ float aw = 0; // bk001204 - init
+ float ah;
+ float frow;
+ float fcol;
+ float fwidth;
+ float fheight;
+
+ // draw the colored text
+ trap_R_SetColor( color );
+
+ ax = x * uis.xscale + uis.bias;
+ ay = y * uis.yscale;
+
+ s = str;
+ while ( *s )
+ {
+ ch = *s & 127;
+ if ( ch == ' ' ) {
+ aw = (float)PROP_SPACE_WIDTH * uis.xscale * sizeScale;
+ }
+ else if ( propMap[ch][2] != -1 ) {
+ fcol = (float)propMap[ch][0] / 256.0f;
+ frow = (float)propMap[ch][1] / 256.0f;
+ fwidth = (float)propMap[ch][2] / 256.0f;
+ fheight = (float)PROP_HEIGHT / 256.0f;
+ aw = (float)propMap[ch][2] * uis.xscale * sizeScale;
+ ah = (float)PROP_HEIGHT * uis.yscale * sizeScale;
+ trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, charset );
+ }
+
+ ax += (aw + (float)PROP_GAP_WIDTH * uis.xscale * sizeScale);
+ s++;
+ }
+
+ trap_R_SetColor( NULL );
+}
+
+/*
+=================
+UI_ProportionalSizeScale
+=================
+*/
+float UI_ProportionalSizeScale( int style ) {
+ if( style & UI_SMALLFONT ) {
+ return PROP_SMALL_SIZE_SCALE;
+ }
+
+ return 1.00;
+}
+
+
+/*
+=================
+UI_DrawProportionalString
+=================
+*/
+void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ) {
+ vec4_t drawcolor;
+ int width;
+ float sizeScale;
+
+ sizeScale = UI_ProportionalSizeScale( style );
+
+ switch( style & UI_FORMATMASK ) {
+ case UI_CENTER:
+ width = UI_ProportionalStringWidth( str ) * sizeScale;
+ x -= width / 2;
+ break;
+
+ case UI_RIGHT:
+ width = UI_ProportionalStringWidth( str ) * sizeScale;
+ x -= width;
+ break;
+
+ case UI_LEFT:
+ default:
+ break;
+ }
+
+ if ( style & UI_DROPSHADOW ) {
+ drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
+ drawcolor[3] = color[3];
+ UI_DrawProportionalString2( x+2, y+2, str, drawcolor, sizeScale, uis.charsetProp );
+ }
+
+ if ( style & UI_INVERSE ) {
+ drawcolor[0] = color[0] * 0.7;
+ drawcolor[1] = color[1] * 0.7;
+ drawcolor[2] = color[2] * 0.7;
+ drawcolor[3] = color[3];
+ UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, uis.charsetProp );
+ return;
+ }
+
+ if ( style & UI_PULSE ) {
+ drawcolor[0] = color[0] * 0.7;
+ drawcolor[1] = color[1] * 0.7;
+ drawcolor[2] = color[2] * 0.7;
+ drawcolor[3] = color[3];
+ UI_DrawProportionalString2( x, y, str, color, sizeScale, uis.charsetProp );
+
+ drawcolor[0] = color[0];
+ drawcolor[1] = color[1];
+ drawcolor[2] = color[2];
+ drawcolor[3] = 0.5 + 0.5 * sin( uis.realtime / PULSE_DIVISOR );
+ UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, uis.charsetPropGlow );
+ return;
+ }
+
+ UI_DrawProportionalString2( x, y, str, color, sizeScale, uis.charsetProp );
+}
+
+/*
+=================
+UI_DrawProportionalString_Wrapped
+=================
+*/
+void UI_DrawProportionalString_AutoWrapped( int x, int y, int xmax, int ystep, const char* str, int style, vec4_t color ) {
+ int width;
+ char *s1,*s2,*s3;
+ char c_bcp;
+ char buf[1024];
+ float sizeScale;
+
+ if (!str || str[0]=='\0')
+ return;
+
+ sizeScale = UI_ProportionalSizeScale( style );
+
+ Q_strncpyz(buf, str, sizeof(buf));
+ s1 = s2 = s3 = buf;
+
+ while (1) {
+ do {
+ s3++;
+ } while (*s3!=' ' && *s3!='\0');
+ c_bcp = *s3;
+ *s3 = '\0';
+ width = UI_ProportionalStringWidth(s1) * sizeScale;
+ *s3 = c_bcp;
+ if (width > xmax) {
+ if (s1==s2)
+ {
+ // fuck, don't have a clean cut, we'll overflow
+ s2 = s3;
+ }
+ *s2 = '\0';
+ UI_DrawProportionalString(x, y, s1, style, color);
+ y += ystep;
+ if (c_bcp == '\0')
+ {
+ // that was the last word
+ // we could start a new loop, but that wouldn't be much use
+ // even if the word is too long, we would overflow it (see above)
+ // so just print it now if needed
+ s2++;
+ if (*s2 != '\0') // if we are printing an overflowing line we have s2 == s3
+ UI_DrawProportionalString(x, y, s2, style, color);
+ break;
+ }
+ s2++;
+ s1 = s2;
+ s3 = s2;
+ }
+ else
+ {
+ s2 = s3;
+ if (c_bcp == '\0') // we reached the end
+ {
+ UI_DrawProportionalString(x, y, s1, style, color);
+ break;
+ }
+ }
+ }
+}
+
+/*
+=================
+UI_DrawString2
+=================
+*/
+static void UI_DrawString2( int x, int y, const char* str, vec4_t color, int charw, int charh )
+{
+ const char* s;
+ char ch;
+ int forceColor = qfalse; //APSFIXME;
+ vec4_t tempcolor;
+ float ax;
+ float ay;
+ float aw;
+ float ah;
+ float frow;
+ float fcol;
+
+ if (y < -charh)
+ // offscreen
+ return;
+
+ // draw the colored text
+ trap_R_SetColor( color );
+
+ ax = x * uis.xscale + uis.bias;
+ ay = y * uis.yscale;
+ aw = charw * uis.xscale;
+ ah = charh * uis.yscale;
+
+ s = str;
+ while ( *s )
+ {
+ if ( Q_IsColorString( s ) )
+ {
+ if ( !forceColor )
+ {
+ memcpy( tempcolor, g_color_table[ColorIndex(s[1])], sizeof( tempcolor ) );
+ tempcolor[3] = color[3];
+ trap_R_SetColor( tempcolor );
+ }
+ s += 2;
+ continue;
+ }
+
+ ch = *s & 255;
+ if (ch != ' ')
+ {
+ frow = (ch>>4)*0.0625;
+ fcol = (ch&15)*0.0625;
+ trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol + 0.0625, frow + 0.0625, uis.charset );
+ }
+
+ ax += aw;
+ s++;
+ }
+
+ trap_R_SetColor( NULL );
+}
+
+/*
+=================
+UI_DrawString
+=================
+*/
+void UI_DrawString( int x, int y, const char* str, int style, vec4_t color )
+{
+ int len;
+ int charw;
+ int charh;
+ vec4_t newcolor;
+ vec4_t lowlight;
+ float *drawcolor;
+ vec4_t dropcolor;
+
+ if( !str ) {
+ return;
+ }
+
+ if ((style & UI_BLINK) && ((uis.realtime/BLINK_DIVISOR) & 1))
+ return;
+
+ if (style & UI_SMALLFONT)
+ {
+ charw = SMALLCHAR_WIDTH;
+ charh = SMALLCHAR_HEIGHT;
+ }
+ else if (style & UI_GIANTFONT)
+ {
+ charw = GIANTCHAR_WIDTH;
+ charh = GIANTCHAR_HEIGHT;
+ }
+ else
+ {
+ charw = BIGCHAR_WIDTH;
+ charh = BIGCHAR_HEIGHT;
+ }
+
+ if (style & UI_PULSE)
+ {
+ lowlight[0] = 0.8*color[0];
+ lowlight[1] = 0.8*color[1];
+ lowlight[2] = 0.8*color[2];
+ lowlight[3] = 0.8*color[3];
+ UI_LerpColor(color,lowlight,newcolor,0.5+0.5*sin(uis.realtime/PULSE_DIVISOR));
+ drawcolor = newcolor;
+ }
+ else
+ drawcolor = color;
+
+ switch (style & UI_FORMATMASK)
+ {
+ case UI_CENTER:
+ // center justify at x
+ len = strlen(str);
+ x = x - len*charw/2;
+ break;
+
+ case UI_RIGHT:
+ // right justify at x
+ len = strlen(str);
+ x = x - len*charw;
+ break;
+
+ default:
+ // left justify at x
+ break;
+ }
+
+ if ( style & UI_DROPSHADOW )
+ {
+ dropcolor[0] = dropcolor[1] = dropcolor[2] = 0;
+ dropcolor[3] = drawcolor[3];
+ UI_DrawString2(x+2,y+2,str,dropcolor,charw,charh);
+ }
+
+ UI_DrawString2(x,y,str,drawcolor,charw,charh);
+}
+
+/*
+=================
+UI_DrawChar
+=================
+*/
+void UI_DrawChar( int x, int y, int ch, int style, vec4_t color )
+{
+ char buff[2];
+
+ buff[0] = ch;
+ buff[1] = '\0';
+
+ UI_DrawString( x, y, buff, style, color );
+}
+
+qboolean UI_IsFullscreen( void ) {
+ if ( uis.activemenu && ( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
+ return uis.activemenu->fullscreen;
+ }
+
+ return qfalse;
+}
+
+static void NeedCDAction( qboolean result ) {
+ if ( !result ) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
+ }
+}
+
+static void NeedCDKeyAction( qboolean result ) {
+ if ( !result ) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
+ }
+}
+
+void UI_SetActiveMenu( uiMenuCommand_t menu ) {
+ // this should be the ONLY way the menu system is brought up
+ // enusure minumum menu data is cached
+ Menu_Cache();
+
+ switch ( menu ) {
+ case UIMENU_NONE:
+ UI_ForceMenuOff();
+ return;
+ case UIMENU_MAIN:
+ UI_MainMenu();
+ return;
+ case UIMENU_NEED_CD:
+ UI_ConfirmMenu( "Insert the CD", 0, NeedCDAction );
+ return;
+ case UIMENU_BAD_CD_KEY:
+ UI_ConfirmMenu( "Bad CD Key", 0, NeedCDKeyAction );
+ return;
+ case UIMENU_INGAME:
+ /*
+ //GRank
+ UI_RankingsMenu();
+ return;
+ */
+ trap_Cvar_Set( "cl_paused", "1" );
+ UI_InGameMenu();
+ return;
+
+ // bk001204
+ case UIMENU_TEAM:
+ case UIMENU_POSTGAME:
+ default:
+#ifndef NDEBUG
+ Com_Printf("UI_SetActiveMenu: bad enum %d\n", menu );
+#endif
+ break;
+ }
+}
+
+/*
+=================
+UI_KeyEvent
+=================
+*/
+void UI_KeyEvent( int key, int down ) {
+ sfxHandle_t s;
+
+ if (!uis.activemenu) {
+ return;
+ }
+
+ if (!down) {
+ return;
+ }
+
+ if (uis.activemenu->key)
+ s = uis.activemenu->key( key );
+ else
+ s = Menu_DefaultKey( uis.activemenu, key );
+
+ if ((s > 0) && (s != menu_null_sound))
+ trap_S_StartLocalSound( s, CHAN_LOCAL_SOUND );
+}
+
+/*
+=================
+UI_MouseEvent
+=================
+*/
+void UI_MouseEvent( int dx, int dy )
+{
+ int i;
+ menucommon_s* m;
+
+ if (!uis.activemenu)
+ return;
+
+ // update mouse screen position
+ uis.cursorx += dx;
+ if (uis.cursorx < -uis.bias)
+ uis.cursorx = -uis.bias;
+ else if (uis.cursorx > SCREEN_WIDTH+uis.bias)
+ uis.cursorx = SCREEN_WIDTH+uis.bias;
+
+ uis.cursory += dy;
+ if (uis.cursory < 0)
+ uis.cursory = 0;
+ else if (uis.cursory > SCREEN_HEIGHT)
+ uis.cursory = SCREEN_HEIGHT;
+
+ // region test the active menu items
+ for (i=0; i<uis.activemenu->nitems; i++)
+ {
+ m = (menucommon_s*)uis.activemenu->items[i];
+
+ if (m->flags & (QMF_GRAYED|QMF_INACTIVE))
+ continue;
+
+ if ((uis.cursorx < m->left) ||
+ (uis.cursorx > m->right) ||
+ (uis.cursory < m->top) ||
+ (uis.cursory > m->bottom))
+ {
+ // cursor out of item bounds
+ continue;
+ }
+
+ // set focus to item at cursor
+ if (uis.activemenu->cursor != i)
+ {
+ Menu_SetCursor( uis.activemenu, i );
+ ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor_prev]))->flags &= ~QMF_HASMOUSEFOCUS;
+
+ if ( !(((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags & QMF_SILENT ) ) {
+ trap_S_StartLocalSound( menu_move_sound, CHAN_LOCAL_SOUND );
+ }
+ }
+
+ ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags |= QMF_HASMOUSEFOCUS;
+ return;
+ }
+
+ if (uis.activemenu->nitems > 0) {
+ // out of any region
+ ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags &= ~QMF_HASMOUSEFOCUS;
+ }
+}
+
+char *UI_Argv( int arg ) {
+ static char buffer[MAX_STRING_CHARS];
+
+ trap_Argv( arg, buffer, sizeof( buffer ) );
+
+ return buffer;
+}
+
+
+char *UI_Cvar_VariableString( const char *var_name ) {
+ static char buffer[MAX_STRING_CHARS];
+
+ trap_Cvar_VariableStringBuffer( var_name, buffer, sizeof( buffer ) );
+
+ return buffer;
+}
+
+
+/*
+=================
+UI_Cache
+=================
+*/
+void UI_Cache_f( void ) {
+ MainMenu_Cache();
+ InGame_Cache();
+ ConfirmMenu_Cache();
+ PlayerModel_Cache();
+ PlayerSettings_Cache();
+ Controls_Cache();
+ Demos_Cache();
+ UI_CinematicsMenu_Cache();
+ Preferences_Cache();
+ ServerInfo_Cache();
+ SpecifyServer_Cache();
+ ArenaServers_Cache();
+ StartServer_Cache();
+ ServerOptions_Cache();
+ DriverInfo_Cache();
+ GraphicsOptions_Cache();
+ UI_DisplayOptionsMenu_Cache();
+ UI_SoundOptionsMenu_Cache();
+ UI_NetworkOptionsMenu_Cache();
+ UI_SPLevelMenu_Cache();
+ UI_SPSkillMenu_Cache();
+ UI_SPPostgameMenu_Cache();
+ TeamMain_Cache();
+ UI_AddBots_Cache();
+ UI_RemoveBots_Cache();
+ UI_SetupMenu_Cache();
+// UI_LoadConfig_Cache();
+// UI_SaveConfigMenu_Cache();
+ UI_BotSelectMenu_Cache();
+ UI_CDKeyMenu_Cache();
+ UI_ModsMenu_Cache();
+
+}
+
+
+/*
+=================
+UI_ConsoleCommand
+=================
+*/
+qboolean UI_ConsoleCommand( int realTime ) {
+ char *cmd;
+
+ uis.frametime = realTime - uis.realtime;
+ uis.realtime = realTime;
+
+ cmd = UI_Argv( 0 );
+
+ // ensure minimum menu data is available
+ Menu_Cache();
+
+ if ( Q_stricmp (cmd, "levelselect") == 0 ) {
+ UI_SPLevelMenu_f();
+ return qtrue;
+ }
+
+ if ( Q_stricmp (cmd, "postgame") == 0 ) {
+ UI_SPPostgameMenu_f();
+ return qtrue;
+ }
+
+ if ( Q_stricmp (cmd, "ui_cache") == 0 ) {
+ UI_Cache_f();
+ return qtrue;
+ }
+
+ if ( Q_stricmp (cmd, "ui_cinematics") == 0 ) {
+ UI_CinematicsMenu_f();
+ return qtrue;
+ }
+
+ if ( Q_stricmp (cmd, "ui_teamOrders") == 0 ) {
+ UI_TeamOrdersMenu_f();
+ return qtrue;
+ }
+
+ if ( Q_stricmp (cmd, "iamacheater") == 0 ) {
+ UI_SPUnlock_f();
+ return qtrue;
+ }
+
+ if ( Q_stricmp (cmd, "iamamonkey") == 0 ) {
+ UI_SPUnlockMedals_f();
+ return qtrue;
+ }
+
+ if ( Q_stricmp (cmd, "ui_cdkey") == 0 ) {
+ UI_CDKeyMenu_f();
+ return qtrue;
+ }
+
+ if ( Q_stricmp (cmd, "ui_mappage") == 0 ) {
+ mappage.pagenumber = atoi(UI_Argv( 1 ));
+ Q_strncpyz(mappage.mapname[0],UI_Argv(2),32);
+ Q_strncpyz(mappage.mapname[1],UI_Argv(3),32);
+ Q_strncpyz(mappage.mapname[2],UI_Argv(4),32);
+ Q_strncpyz(mappage.mapname[3],UI_Argv(5),32);
+ Q_strncpyz(mappage.mapname[4],UI_Argv(6),32);
+ Q_strncpyz(mappage.mapname[5],UI_Argv(7),32);
+ Q_strncpyz(mappage.mapname[6],UI_Argv(8),32);
+ Q_strncpyz(mappage.mapname[7],UI_Argv(9),32);
+ Q_strncpyz(mappage.mapname[8],UI_Argv(10),32);
+ Q_strncpyz(mappage.mapname[9],UI_Argv(11),32);
+
+ UI_VoteMapMenuInternal();
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+/*
+=================
+UI_Shutdown
+=================
+*/
+void UI_Shutdown( void ) {
+}
+
+/*
+=================
+UI_Init
+=================
+*/
+void UI_Init( void ) {
+ UI_RegisterCvars();
+
+ UI_InitGameinfo();
+
+ // cache redundant calulations
+ trap_GetGlconfig( &uis.glconfig );
+
+ // for 640x480 virtualized screen
+ uis.xscale = uis.glconfig.vidWidth * (1.0/640.0);
+ uis.yscale = uis.glconfig.vidHeight * (1.0/480.0);
+ if ( uis.glconfig.vidWidth * 480 > uis.glconfig.vidHeight * 640 ) {
+ // wide screen
+ uis.bias = 0.5 * ( uis.glconfig.vidWidth - ( uis.glconfig.vidHeight * (640.0/480.0) ) );
+ uis.xscale = uis.yscale;
+ }
+ else {
+ // no wide screen
+ uis.bias = 0;
+ }
+
+ // initialize the menu system
+ Menu_Cache();
+
+ uis.activemenu = NULL;
+ uis.menusp = 0;
+}
+
+/*
+================
+UI_AdjustFrom640
+
+Adjusted for resolution and screen aspect ratio
+================
+*/
+void UI_AdjustFrom640( float *x, float *y, float *w, float *h ) {
+ // expect valid pointers
+ *x = *x * uis.xscale + uis.bias;
+ *y *= uis.yscale;
+ *w *= uis.xscale;
+ *h *= uis.yscale;
+}
+
+void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {
+ qhandle_t hShader;
+
+ hShader = trap_R_RegisterShaderNoMip( picname );
+ UI_AdjustFrom640( &x, &y, &width, &height );
+ trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
+}
+
+void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader ) {
+ float s0;
+ float s1;
+ float t0;
+ float t1;
+
+ if( w < 0 ) { // flip about vertical
+ w = -w;
+ s0 = 1;
+ s1 = 0;
+ }
+ else {
+ s0 = 0;
+ s1 = 1;
+ }
+
+ if( h < 0 ) { // flip about horizontal
+ h = -h;
+ t0 = 1;
+ t1 = 0;
+ }
+ else {
+ t0 = 0;
+ t1 = 1;
+ }
+
+ UI_AdjustFrom640( &x, &y, &w, &h );
+ trap_R_DrawStretchPic( x, y, w, h, s0, t0, s1, t1, hShader );
+}
+
+/*
+================
+UI_FillRect
+
+Coordinates are 640*480 virtual values
+=================
+*/
+void UI_FillRect( float x, float y, float width, float height, const float *color ) {
+ trap_R_SetColor( color );
+
+ UI_AdjustFrom640( &x, &y, &width, &height );
+ trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, uis.whiteShader );
+
+ trap_R_SetColor( NULL );
+}
+
+/*
+================
+UI_DrawRect
+
+Coordinates are 640*480 virtual values
+=================
+*/
+void UI_DrawRect( float x, float y, float width, float height, const float *color ) {
+ trap_R_SetColor( color );
+
+ UI_AdjustFrom640( &x, &y, &width, &height );
+
+ trap_R_DrawStretchPic( x, y, width, 1, 0, 0, 0, 0, uis.whiteShader );
+ trap_R_DrawStretchPic( x, y, 1, height, 0, 0, 0, 0, uis.whiteShader );
+ trap_R_DrawStretchPic( x, y + height - 1, width, 1, 0, 0, 0, 0, uis.whiteShader );
+ trap_R_DrawStretchPic( x + width - 1, y, 1, height, 0, 0, 0, 0, uis.whiteShader );
+
+ trap_R_SetColor( NULL );
+}
+
+void UI_SetColor( const float *rgba ) {
+ trap_R_SetColor( rgba );
+}
+
+void UI_UpdateScreen( void ) {
+ trap_UpdateScreen();
+}
+
+/*
+=================
+UI_Refresh
+=================
+*/
+void UI_Refresh( int realtime )
+{
+ uis.frametime = realtime - uis.realtime;
+ uis.realtime = realtime;
+
+ if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
+ return;
+ }
+
+ UI_UpdateCvars();
+
+ if ( uis.activemenu )
+ {
+ if (uis.activemenu->fullscreen)
+ {
+ // draw the background
+ if( uis.activemenu->showlogo ) {
+ UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackShader );
+ }
+ else {
+ UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackNoLogoShader );
+ }
+ }
+
+ if (uis.activemenu->draw)
+ uis.activemenu->draw();
+ else
+ Menu_Draw( uis.activemenu );
+
+ if( uis.firstdraw ) {
+ UI_MouseEvent( 0, 0 );
+ uis.firstdraw = qfalse;
+ }
+ }
+
+ // draw cursor
+ UI_SetColor( NULL );
+ UI_DrawHandlePic( uis.cursorx-16, uis.cursory-16, 32, 32, uis.cursor);
+
+#ifndef NDEBUG
+ if (uis.debug)
+ {
+ // cursor coordinates
+ UI_DrawString( 0, 0, va("(%d,%d)",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed );
+ }
+#endif
+
+ // delay playing the enter sound until after the
+ // menu has been drawn, to avoid delay while
+ // caching images
+ if (m_entersound)
+ {
+ trap_S_StartLocalSound( menu_in_sound, CHAN_LOCAL_SOUND );
+ m_entersound = qfalse;
+ }
+}
+
+void UI_DrawTextBox (int x, int y, int width, int lines)
+{
+ UI_FillRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorBlack );
+ UI_DrawRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorWhite );
+}
+
+qboolean UI_CursorInRect (int x, int y, int width, int height)
+{
+ if (uis.cursorx < x ||
+ uis.cursory < y ||
+ uis.cursorx > x+width ||
+ uis.cursory > y+height)
+ return qfalse;
+
+ return qtrue;
+}
diff --git a/engine/code/q3_ui/ui_cdkey.c b/code/q3_ui/ui_cdkey.c
similarity index 100%
rename from engine/code/q3_ui/ui_cdkey.c
rename to code/q3_ui/ui_cdkey.c
diff --git a/game/code/q3_ui/ui_challenges.c b/code/q3_ui/ui_challenges.c
similarity index 100%
rename from game/code/q3_ui/ui_challenges.c
rename to code/q3_ui/ui_challenges.c
diff --git a/game/code/q3_ui/ui_cinematics.c b/code/q3_ui/ui_cinematics.c
similarity index 100%
rename from game/code/q3_ui/ui_cinematics.c
rename to code/q3_ui/ui_cinematics.c
diff --git a/game/code/q3_ui/ui_confirm.c b/code/q3_ui/ui_confirm.c
similarity index 100%
rename from game/code/q3_ui/ui_confirm.c
rename to code/q3_ui/ui_confirm.c
diff --git a/game/code/q3_ui/ui_connect.c b/code/q3_ui/ui_connect.c
similarity index 100%
rename from game/code/q3_ui/ui_connect.c
rename to code/q3_ui/ui_connect.c
diff --git a/code/q3_ui/ui_controls2.c b/code/q3_ui/ui_controls2.c
new file mode 100644
index 0000000..a6fbced
--- /dev/null
+++ b/code/q3_ui/ui_controls2.c
@@ -0,0 +1,1774 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+/*
+=======================================================================
+
+CONTROLS MENU
+
+=======================================================================
+*/
+
+
+#include "ui_local.h"
+
+#define ART_BACK0 "menu/art_blueish/back_0"
+#define ART_BACK1 "menu/art_blueish/back_1"
+#define ART_FRAMEL "menu/art_blueish/frame2_l"
+#define ART_FRAMER "menu/art_blueish/frame1_r"
+
+
+typedef struct {
+ char *command;
+ char *label;
+ int id;
+ int anim;
+ int defaultbind1;
+ int defaultbind2;
+ int bind1;
+ int bind2;
+} bind_t;
+
+typedef struct
+{
+ char* name;
+ float defaultvalue;
+ float value;
+} configcvar_t;
+
+#define SAVE_NOOP 0
+#define SAVE_YES 1
+#define SAVE_NO 2
+#define SAVE_CANCEL 3
+
+// control sections
+#define C_MOVEMENT 0
+#define C_LOOKING 1
+#define C_WEAPONS 2
+#define C_MISC 3
+#define C_MAX 4
+
+#define ID_MOVEMENT 100
+#define ID_LOOKING 101
+#define ID_WEAPONS 102
+#define ID_MISC 103
+#define ID_DEFAULTS 104
+#define ID_BACK 105
+#define ID_SAVEANDEXIT 106
+#define ID_EXIT 107
+
+// bindable actions
+#define ID_SHOWSCORES 0
+#define ID_USEITEM 1
+#define ID_SPEED 2
+#define ID_FORWARD 3
+#define ID_BACKPEDAL 4
+#define ID_MOVELEFT 5
+#define ID_MOVERIGHT 6
+#define ID_MOVEUP 7
+#define ID_MOVEDOWN 8
+#define ID_LEFT 9
+#define ID_RIGHT 10
+#define ID_STRAFE 11
+#define ID_LOOKUP 12
+#define ID_LOOKDOWN 13
+#define ID_MOUSELOOK 14
+#define ID_CENTERVIEW 15
+#define ID_ZOOMVIEW 16
+#define ID_WEAPON1 17
+#define ID_WEAPON2 18
+#define ID_WEAPON3 19
+#define ID_WEAPON4 20
+#define ID_WEAPON5 21
+#define ID_WEAPON6 22
+#define ID_WEAPON7 23
+#define ID_WEAPON8 24
+#define ID_WEAPON9 25
+#define ID_WEAPON10 26
+#define ID_WEAPON11 27 //Nailgun
+#define ID_WEAPON12 28 //ProxMines
+#define ID_WEAPON13 29 //Chaingun
+#define ID_ATTACK 30
+#define ID_WEAPPREV 31
+#define ID_WEAPNEXT 32
+#define ID_GESTURE 33
+#define ID_CHAT 34
+#define ID_CHAT2 35
+#define ID_CHAT3 36
+#define ID_CHAT4 37
+#define ID_VOIP_TALK 38
+
+// all others
+#define ID_FREELOOK 39
+#define ID_INVERTMOUSE 40
+#define ID_ALWAYSRUN 41
+#define ID_AUTOSWITCH 42
+#define ID_MOUSESPEED 43
+#define ID_JOYENABLE 44
+#define ID_JOYTHRESHOLD 45
+#define ID_SMOOTHMOUSE 46
+#define ID_VOIP_TEAMONLY 47
+
+
+
+#define ANIM_IDLE 0
+#define ANIM_RUN 1
+#define ANIM_WALK 2
+#define ANIM_BACK 3
+#define ANIM_JUMP 4
+#define ANIM_CROUCH 5
+#define ANIM_STEPLEFT 6
+#define ANIM_STEPRIGHT 7
+#define ANIM_TURNLEFT 8
+#define ANIM_TURNRIGHT 9
+#define ANIM_LOOKUP 10
+#define ANIM_LOOKDOWN 11
+#define ANIM_WEAPON1 12
+#define ANIM_WEAPON2 13
+#define ANIM_WEAPON3 14
+#define ANIM_WEAPON4 15
+#define ANIM_WEAPON5 16
+#define ANIM_WEAPON6 17
+#define ANIM_WEAPON7 18
+#define ANIM_WEAPON8 19
+#define ANIM_WEAPON9 20
+#define ANIM_WEAPON10 21
+#define ANIM_ATTACK 22
+#define ANIM_GESTURE 23
+#define ANIM_DIE 24
+#define ANIM_CHAT 25
+
+//New in Beta 23
+#define ANIM_WEAPON11 26 //Nailgun
+#define ANIM_WEAPON12 27 //ProxMines
+#define ANIM_WEAPON13 28 //Chaingun
+
+typedef struct
+{
+ menuframework_s menu;
+
+ menutext_s banner;
+ menubitmap_s framel;
+ menubitmap_s framer;
+ menubitmap_s player;
+
+ menutext_s movement;
+ menutext_s looking;
+ menutext_s weapons;
+ menutext_s misc;
+
+ menuaction_s walkforward;
+ menuaction_s backpedal;
+ menuaction_s stepleft;
+ menuaction_s stepright;
+ menuaction_s moveup;
+ menuaction_s movedown;
+ menuaction_s turnleft;
+ menuaction_s turnright;
+ menuaction_s sidestep;
+ menuaction_s run;
+ menuaction_s machinegun;
+ menuaction_s chainsaw;
+ menuaction_s shotgun;
+ menuaction_s grenadelauncher;
+ menuaction_s rocketlauncher;
+ menuaction_s lightning;
+ menuaction_s railgun;
+ menuaction_s plasma;
+ menuaction_s bfg;
+ menuaction_s grapple;
+ //New in Beta 23
+ menuaction_s nailgun;
+ menuaction_s proxmine;
+ menuaction_s chaingun;
+ //New in 23 end
+ menuaction_s attack;
+ menuaction_s prevweapon;
+ menuaction_s nextweapon;
+ menuaction_s lookup;
+ menuaction_s lookdown;
+ menuaction_s mouselook;
+ menuradiobutton_s freelook;
+ menuaction_s centerview;
+ menuaction_s zoomview;
+ menuaction_s gesture;
+ menuradiobutton_s invertmouse;
+ menuslider_s sensitivity;
+ menuradiobutton_s smoothmouse;
+ menuradiobutton_s alwaysrun;
+ menuaction_s showscores;
+ menulist_s autoswitch;
+ menuaction_s useitem;
+ playerInfo_t playerinfo;
+ qboolean changesmade;
+ menuaction_s chat;
+ menuaction_s chat2;
+ menuaction_s chat3;
+ menuaction_s chat4;
+ menuaction_s voip_talk;
+ menuradiobutton_s voip_teamonly;
+ menuradiobutton_s joyenable;
+ menuslider_s joythreshold;
+ int section;
+ qboolean waitingforkey;
+ char playerModel[64];
+ vec3_t playerViewangles;
+ vec3_t playerMoveangles;
+ int playerLegs;
+ int playerTorso;
+ int playerWeapon;
+ qboolean playerChat;
+
+ menubitmap_s back;
+ menutext_s name;
+} controls_t;
+
+static controls_t s_controls;
+
+static const char *autoswitch_items[] = {
+ "NEVER",
+ "ALWAYS",
+ "NEW",
+ "BETTER",
+ "NEW&BETTER",
+ NULL
+};
+
+// OLD
+//static vec4_t controls_binding_color = {1.00f, 0.43f, 0.00f, 1.00f}; // bk: Win32 C4305
+
+// New!
+static vec4_t controls_binding_color = {0.58f, 0.70f, 0.81f, 1.00f};
+
+static bind_t g_bindings[] =
+{
+ {"+scores", "show scores", ID_SHOWSCORES, ANIM_IDLE, K_TAB, -1, -1, -1},
+ {"+button2", "use item", ID_USEITEM, ANIM_IDLE, K_ENTER, -1, -1, -1},
+ {"+speed", "run / walk", ID_SPEED, ANIM_RUN, K_SHIFT, -1, -1, -1},
+ {"+forward", "walk forward", ID_FORWARD, ANIM_WALK, K_UPARROW, -1, -1, -1},
+ {"+back", "backpedal", ID_BACKPEDAL, ANIM_BACK, K_DOWNARROW, -1, -1, -1},
+ {"+moveleft", "step left", ID_MOVELEFT, ANIM_STEPLEFT, ',', -1, -1, -1},
+ {"+moveright", "step right", ID_MOVERIGHT, ANIM_STEPRIGHT, '.', -1, -1, -1},
+ {"+moveup", "up / jump", ID_MOVEUP, ANIM_JUMP, K_SPACE, -1, -1, -1},
+ {"+movedown", "down / crouch", ID_MOVEDOWN, ANIM_CROUCH, 'c', -1, -1, -1},
+ {"+left", "turn left", ID_LEFT, ANIM_TURNLEFT, K_LEFTARROW, -1, -1, -1},
+ {"+right", "turn right", ID_RIGHT, ANIM_TURNRIGHT, K_RIGHTARROW, -1, -1, -1},
+ {"+strafe", "sidestep / turn", ID_STRAFE, ANIM_IDLE, K_ALT, -1, -1, -1},
+ {"+lookup", "look up", ID_LOOKUP, ANIM_LOOKUP, K_PGDN, -1, -1, -1},
+ {"+lookdown", "look down", ID_LOOKDOWN, ANIM_LOOKDOWN, K_DEL, -1, -1, -1},
+ {"+mlook", "mouse look", ID_MOUSELOOK, ANIM_IDLE, '/', -1, -1, -1},
+ {"centerview", "center view", ID_CENTERVIEW, ANIM_IDLE, K_END, -1, -1, -1},
+ {"+zoom", "zoom view", ID_ZOOMVIEW, ANIM_IDLE, -1, -1, -1, -1},
+ {"weapon 1", "gauntlet", ID_WEAPON1, ANIM_WEAPON1, '1', -1, -1, -1},
+ {"weapon 2", "machinegun", ID_WEAPON2, ANIM_WEAPON2, '2', -1, -1, -1},
+ {"weapon 3", "shotgun", ID_WEAPON3, ANIM_WEAPON3, '3', -1, -1, -1},
+ {"weapon 4", "grenade launcher", ID_WEAPON4, ANIM_WEAPON4, '4', -1, -1, -1},
+ {"weapon 5", "rocket launcher", ID_WEAPON5, ANIM_WEAPON5, '5', -1, -1, -1},
+ {"weapon 6", "lightning", ID_WEAPON6, ANIM_WEAPON6, '6', -1, -1, -1},
+ {"weapon 7", "railgun", ID_WEAPON7, ANIM_WEAPON7, '7', -1, -1, -1},
+ {"weapon 8", "plasma gun", ID_WEAPON8, ANIM_WEAPON8, '8', -1, -1, -1},
+ {"weapon 9", "BFG", ID_WEAPON9, ANIM_WEAPON9, '9', -1, -1, -1},
+ {"weapon 10", "Grapple", ID_WEAPON10, ANIM_WEAPON10, -1, -1, -1, -1},
+ {"weapon 11", "nailgun", ID_WEAPON11, ANIM_WEAPON11, -1, -1, -1, -1},
+ {"weapon 12", "mine Launcher", ID_WEAPON12, ANIM_WEAPON12, -1, -1, -1, -1},
+ {"weapon 13", "chaingun", ID_WEAPON13, ANIM_WEAPON13, -1, -1, -1, -1},
+ {"+attack", "attack", ID_ATTACK, ANIM_ATTACK, K_CTRL, -1, -1, -1},
+ {"weapprev", "prev weapon", ID_WEAPPREV, ANIM_IDLE, '[', -1, -1, -1},
+ {"weapnext", "next weapon", ID_WEAPNEXT, ANIM_IDLE, ']', -1, -1, -1},
+ {"+button3", "gesture", ID_GESTURE, ANIM_GESTURE, K_MOUSE3, -1, -1, -1},
+ {"messagemode", "chat", ID_CHAT, ANIM_CHAT, 't', -1, -1, -1},
+ {"messagemode2", "chat - team", ID_CHAT2, ANIM_CHAT, -1, -1, -1, -1},
+ {"messagemode3", "chat - target", ID_CHAT3, ANIM_CHAT, -1, -1, -1, -1},
+ {"messagemode4", "chat - attacker", ID_CHAT4, ANIM_CHAT, -1, -1, -1, -1},
+ {"+voiprecord", "voice chat", ID_VOIP_TALK, ANIM_CHAT, 'q', -1, -1, -1},
+ {(char*)NULL, (char*)NULL, 0, 0, -1, -1, -1, -1},
+};
+
+static configcvar_t g_configcvars[] =
+{
+ {"cl_run", 0, 0},
+ {"m_pitch", 0, 0},
+ {"cg_autoswitch", 0, 0},
+ {"sensitivity", 0, 0},
+ {"in_joystick", 0, 0},
+ {"joy_threshold", 0, 0},
+ {"m_filter", 0, 0},
+ {"cl_freelook", 0, 0},
+ {"cg_voipTeamOnly", 0, 0},
+ {NULL, 0, 0}
+};
+
+static menucommon_s *g_movement_controls[] =
+{
+ (menucommon_s *)&s_controls.alwaysrun,
+ (menucommon_s *)&s_controls.run,
+ (menucommon_s *)&s_controls.walkforward,
+ (menucommon_s *)&s_controls.backpedal,
+ (menucommon_s *)&s_controls.stepleft,
+ (menucommon_s *)&s_controls.stepright,
+ (menucommon_s *)&s_controls.moveup,
+ (menucommon_s *)&s_controls.movedown,
+ (menucommon_s *)&s_controls.turnleft,
+ (menucommon_s *)&s_controls.turnright,
+ (menucommon_s *)&s_controls.sidestep,
+ NULL
+};
+
+static menucommon_s *g_weapons_controls[] = {
+ (menucommon_s *)&s_controls.attack,
+ (menucommon_s *)&s_controls.nextweapon,
+ (menucommon_s *)&s_controls.prevweapon,
+ (menucommon_s *)&s_controls.autoswitch,
+ (menucommon_s *)&s_controls.chainsaw,
+ (menucommon_s *)&s_controls.machinegun,
+ (menucommon_s *)&s_controls.shotgun,
+ (menucommon_s *)&s_controls.grenadelauncher,
+ (menucommon_s *)&s_controls.rocketlauncher,
+ (menucommon_s *)&s_controls.lightning,
+ (menucommon_s *)&s_controls.railgun,
+ (menucommon_s *)&s_controls.plasma,
+ (menucommon_s *)&s_controls.bfg,
+ (menucommon_s *)&s_controls.grapple,
+ (menucommon_s *)&s_controls.nailgun,
+ (menucommon_s *)&s_controls.proxmine,
+ (menucommon_s *)&s_controls.chaingun,
+ NULL,
+};
+
+static menucommon_s *g_looking_controls[] = {
+ (menucommon_s *)&s_controls.sensitivity,
+ (menucommon_s *)&s_controls.smoothmouse,
+ (menucommon_s *)&s_controls.invertmouse,
+ (menucommon_s *)&s_controls.lookup,
+ (menucommon_s *)&s_controls.lookdown,
+ (menucommon_s *)&s_controls.mouselook,
+ (menucommon_s *)&s_controls.freelook,
+ (menucommon_s *)&s_controls.centerview,
+ (menucommon_s *)&s_controls.zoomview,
+ (menucommon_s *)&s_controls.joyenable,
+ (menucommon_s *)&s_controls.joythreshold,
+ NULL,
+};
+
+static menucommon_s *g_misc_controls[] = {
+ (menucommon_s *)&s_controls.showscores,
+ (menucommon_s *)&s_controls.useitem,
+ (menucommon_s *)&s_controls.gesture,
+ (menucommon_s *)&s_controls.chat,
+ (menucommon_s *)&s_controls.chat2,
+ (menucommon_s *)&s_controls.chat3,
+ (menucommon_s *)&s_controls.chat4,
+ (menucommon_s *)&s_controls.voip_talk,
+ (menucommon_s *)&s_controls.voip_teamonly,
+ NULL,
+};
+
+static menucommon_s **g_controls[] = {
+ g_movement_controls,
+ g_looking_controls,
+ g_weapons_controls,
+ g_misc_controls,
+};
+
+/*
+=================
+Controls_InitCvars
+=================
+*/
+static void Controls_InitCvars( void )
+{
+ int i;
+ configcvar_t* cvarptr;
+
+ cvarptr = g_configcvars;
+ for (i=0; ;i++,cvarptr++)
+ {
+ if (!cvarptr->name)
+ break;
+
+ // get current value
+ cvarptr->value = trap_Cvar_VariableValue( cvarptr->name );
+
+ // get default value
+ trap_Cvar_Reset( cvarptr->name );
+ cvarptr->defaultvalue = trap_Cvar_VariableValue( cvarptr->name );
+
+ // restore current value
+ trap_Cvar_SetValue( cvarptr->name, cvarptr->value );
+ }
+}
+
+/*
+=================
+Controls_GetCvarDefault
+=================
+*/
+static float Controls_GetCvarDefault( char* name )
+{
+ configcvar_t* cvarptr;
+ int i;
+
+ cvarptr = g_configcvars;
+ for (i=0; ;i++,cvarptr++)
+ {
+ if (!cvarptr->name)
+ return (0);
+
+ if (!strcmp(cvarptr->name,name))
+ break;
+ }
+
+ return (cvarptr->defaultvalue);
+}
+
+/*
+=================
+Controls_GetCvarValue
+=================
+*/
+static float Controls_GetCvarValue( char* name )
+{
+ configcvar_t* cvarptr;
+ int i;
+
+ cvarptr = g_configcvars;
+ for (i=0; ;i++,cvarptr++)
+ {
+ if (!cvarptr->name)
+ return (0);
+
+ if (!strcmp(cvarptr->name,name))
+ break;
+ }
+
+ return (cvarptr->value);
+}
+
+
+/*
+=================
+Controls_UpdateModel
+=================
+*/
+static void Controls_UpdateModel( int anim ) {
+ VectorClear( s_controls.playerViewangles );
+ VectorClear( s_controls.playerMoveangles );
+ s_controls.playerViewangles[YAW] = 180 - 30;
+ s_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW];
+ s_controls.playerLegs = LEGS_IDLE;
+ s_controls.playerTorso = TORSO_STAND;
+ s_controls.playerWeapon = -1;
+ s_controls.playerChat = qfalse;
+
+ switch( anim ) {
+ case ANIM_RUN:
+ s_controls.playerLegs = LEGS_RUN;
+ break;
+
+ case ANIM_WALK:
+ s_controls.playerLegs = LEGS_WALK;
+ break;
+
+ case ANIM_BACK:
+ s_controls.playerLegs = LEGS_BACK;
+ break;
+
+ case ANIM_JUMP:
+ s_controls.playerLegs = LEGS_JUMP;
+ break;
+
+ case ANIM_CROUCH:
+ s_controls.playerLegs = LEGS_IDLECR;
+ break;
+
+ case ANIM_TURNLEFT:
+ s_controls.playerViewangles[YAW] += 90;
+ break;
+
+ case ANIM_TURNRIGHT:
+ s_controls.playerViewangles[YAW] -= 90;
+ break;
+
+ case ANIM_STEPLEFT:
+ s_controls.playerLegs = LEGS_WALK;
+ s_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW] + 90;
+ break;
+
+ case ANIM_STEPRIGHT:
+ s_controls.playerLegs = LEGS_WALK;
+ s_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW] - 90;
+ break;
+
+ case ANIM_LOOKUP:
+ s_controls.playerViewangles[PITCH] = -45;
+ break;
+
+ case ANIM_LOOKDOWN:
+ s_controls.playerViewangles[PITCH] = 45;
+ break;
+
+ case ANIM_WEAPON1:
+ s_controls.playerWeapon = WP_GAUNTLET;
+ break;
+
+ case ANIM_WEAPON2:
+ s_controls.playerWeapon = WP_MACHINEGUN;
+ break;
+
+ case ANIM_WEAPON3:
+ s_controls.playerWeapon = WP_SHOTGUN;
+ break;
+
+ case ANIM_WEAPON4:
+ s_controls.playerWeapon = WP_GRENADE_LAUNCHER;
+ break;
+
+ case ANIM_WEAPON5:
+ s_controls.playerWeapon = WP_ROCKET_LAUNCHER;
+ break;
+
+ case ANIM_WEAPON6:
+ s_controls.playerWeapon = WP_LIGHTNING;
+ break;
+
+ case ANIM_WEAPON7:
+ s_controls.playerWeapon = WP_RAILGUN;
+ break;
+
+ case ANIM_WEAPON8:
+ s_controls.playerWeapon = WP_PLASMAGUN;
+ break;
+
+ case ANIM_WEAPON9:
+ s_controls.playerWeapon = WP_BFG;
+ break;
+
+ case ANIM_WEAPON10:
+ s_controls.playerWeapon = WP_GRAPPLING_HOOK;
+ break;
+
+ case ANIM_WEAPON11:
+ s_controls.playerWeapon = WP_NAILGUN;
+ break;
+
+ case ANIM_WEAPON12:
+ s_controls.playerWeapon = WP_PROX_LAUNCHER;
+ break;
+
+ case ANIM_WEAPON13:
+ s_controls.playerWeapon = WP_CHAINGUN;
+ break;
+
+ case ANIM_ATTACK:
+ s_controls.playerTorso = TORSO_ATTACK;
+ break;
+
+ case ANIM_GESTURE:
+ s_controls.playerTorso = TORSO_GESTURE;
+ break;
+
+ case ANIM_DIE:
+ s_controls.playerLegs = BOTH_DEATH1;
+ s_controls.playerTorso = BOTH_DEATH1;
+ s_controls.playerWeapon = WP_NONE;
+ break;
+
+ case ANIM_CHAT:
+ s_controls.playerChat = qtrue;
+ break;
+
+ default:
+ break;
+ }
+
+ UI_PlayerInfo_SetInfo( &s_controls.playerinfo, s_controls.playerLegs, s_controls.playerTorso, s_controls.playerViewangles, s_controls.playerMoveangles, s_controls.playerWeapon, s_controls.playerChat );
+}
+
+
+/*
+=================
+Controls_Update
+=================
+*/
+static void Controls_Update( void ) {
+ int i;
+ int j;
+ int y;
+ menucommon_s **controls;
+ menucommon_s *control;
+
+ // disable all controls in all groups
+ for( i = 0; i < C_MAX; i++ ) {
+ controls = g_controls[i];
+ // bk001204 - parentheses
+ for( j = 0; (control = controls[j]) ; j++ ) {
+ control->flags |= (QMF_HIDDEN|QMF_INACTIVE);
+ }
+ }
+
+ controls = g_controls[s_controls.section];
+
+ // enable controls in active group (and count number of items for vertical centering)
+ // bk001204 - parentheses
+ for( j = 0; (control = controls[j]) ; j++ ) {
+ control->flags &= ~(QMF_GRAYED|QMF_HIDDEN|QMF_INACTIVE);
+ }
+
+ // position controls
+ y = ( SCREEN_HEIGHT - j * SMALLCHAR_HEIGHT ) / 2;
+ // bk001204 - parentheses
+ for( j = 0; (control = controls[j]) ; j++, y += SMALLCHAR_HEIGHT ) {
+ control->x = 320;
+ control->y = y;
+ control->left = 320 - 19*SMALLCHAR_WIDTH;
+ control->right = 320 + 21*SMALLCHAR_WIDTH;
+ control->top = y;
+ control->bottom = y + SMALLCHAR_HEIGHT;
+ }
+
+ if( s_controls.waitingforkey ) {
+ // disable everybody
+ for( i = 0; i < s_controls.menu.nitems; i++ ) {
+ ((menucommon_s*)(s_controls.menu.items[i]))->flags |= QMF_GRAYED;
+ }
+
+ // enable action item
+ ((menucommon_s*)(s_controls.menu.items[s_controls.menu.cursor]))->flags &= ~QMF_GRAYED;
+
+ // don't gray out player's name
+ s_controls.name.generic.flags &= ~QMF_GRAYED;
+
+ return;
+ }
+
+ // enable everybody
+ for( i = 0; i < s_controls.menu.nitems; i++ ) {
+ ((menucommon_s*)(s_controls.menu.items[i]))->flags &= ~QMF_GRAYED;
+ }
+
+ // makes sure flags are right on the group selection controls
+ s_controls.looking.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
+ s_controls.movement.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
+ s_controls.weapons.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
+ s_controls.misc.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
+
+ s_controls.looking.generic.flags |= QMF_PULSEIFFOCUS;
+ s_controls.movement.generic.flags |= QMF_PULSEIFFOCUS;
+ s_controls.weapons.generic.flags |= QMF_PULSEIFFOCUS;
+ s_controls.misc.generic.flags |= QMF_PULSEIFFOCUS;
+
+ // set buttons
+ switch( s_controls.section ) {
+ case C_MOVEMENT:
+ s_controls.movement.generic.flags &= ~QMF_PULSEIFFOCUS;
+ s_controls.movement.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
+ break;
+
+ case C_LOOKING:
+ s_controls.looking.generic.flags &= ~QMF_PULSEIFFOCUS;
+ s_controls.looking.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
+ break;
+
+ case C_WEAPONS:
+ s_controls.weapons.generic.flags &= ~QMF_PULSEIFFOCUS;
+ s_controls.weapons.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
+ break;
+
+ case C_MISC:
+ s_controls.misc.generic.flags &= ~QMF_PULSEIFFOCUS;
+ s_controls.misc.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
+ break;
+ }
+}
+
+
+/*
+=================
+Controls_DrawKeyBinding
+=================
+*/
+static void Controls_DrawKeyBinding( void *self )
+{
+ menuaction_s* a;
+ int x;
+ int y;
+ int b1;
+ int b2;
+ qboolean c;
+ char name[32];
+ char name2[32];
+
+ a = (menuaction_s*) self;
+
+ x = a->generic.x;
+ y = a->generic.y;
+
+ c = (Menu_ItemAtCursor( a->generic.parent ) == a);
+
+ b1 = g_bindings[a->generic.id].bind1;
+ if (b1 == -1)
+ strcpy(name,"???");
+ else
+ {
+ trap_Key_KeynumToStringBuf( b1, name, 32 );
+ Q_strupr(name);
+
+ b2 = g_bindings[a->generic.id].bind2;
+ if (b2 != -1)
+ {
+ trap_Key_KeynumToStringBuf( b2, name2, 32 );
+ Q_strupr(name2);
+
+ strcat( name, " or " );
+ strcat( name, name2 );
+ }
+ }
+
+ if (c)
+ {
+ UI_FillRect( a->generic.left, a->generic.top, a->generic.right-a->generic.left+1, a->generic.bottom-a->generic.top+1, listbar_color );
+
+ UI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, text_color_highlight );
+ UI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT|UI_PULSE, text_color_highlight );
+
+ if (s_controls.waitingforkey)
+ {
+ UI_DrawChar( x, y, '=', UI_CENTER|UI_BLINK|UI_SMALLFONT, text_color_highlight);
+ UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.80, "Waiting for new key ... ESCAPE to cancel", UI_SMALLFONT|UI_CENTER|UI_PULSE, colorWhite );
+ }
+ else
+ {
+ UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, text_color_highlight);
+ UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.78, "Press ENTER or CLICK to change", UI_SMALLFONT|UI_CENTER, colorWhite );
+ UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.82, "Press BACKSPACE to clear", UI_SMALLFONT|UI_CENTER, colorWhite );
+ }
+ }
+ else
+ {
+ if (a->generic.flags & QMF_GRAYED)
+ {
+ UI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, text_color_disabled );
+ UI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT, text_color_disabled );
+ }
+ else
+ {
+ UI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, controls_binding_color );
+ UI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT, controls_binding_color );
+ }
+ }
+}
+
+/*
+=================
+Controls_StatusBar
+=================
+*/
+static void Controls_StatusBar( void *self )
+{
+ UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.80, "Use Arrow Keys or CLICK to change", UI_SMALLFONT|UI_CENTER, colorWhite );
+}
+
+
+/*
+=================
+Controls_DrawPlayer
+=================
+*/
+static void Controls_DrawPlayer( void *self ) {
+ menubitmap_s *b;
+ char buf[MAX_QPATH];
+
+ trap_Cvar_VariableStringBuffer( "model", buf, sizeof( buf ) );
+ if ( strcmp( buf, s_controls.playerModel ) != 0 ) {
+ UI_PlayerInfo_SetModel( &s_controls.playerinfo, buf );
+ strcpy( s_controls.playerModel, buf );
+ Controls_UpdateModel( ANIM_IDLE );
+ }
+
+ b = (menubitmap_s*) self;
+ UI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_controls.playerinfo, uis.realtime/2 );
+}
+
+
+/*
+=================
+Controls_GetKeyAssignment
+=================
+*/
+static void Controls_GetKeyAssignment (char *command, int *twokeys)
+{
+ int count;
+ int j;
+ char b[256];
+
+ twokeys[0] = twokeys[1] = -1;
+ count = 0;
+
+ for ( j = 0; j < 256; j++ )
+ {
+ trap_Key_GetBindingBuf( j, b, 256 );
+ if ( *b == 0 ) {
+ continue;
+ }
+ if ( !Q_stricmp( b, command ) ) {
+ twokeys[count] = j;
+ count++;
+ if (count == 2)
+ break;
+ }
+ }
+}
+
+/*
+=================
+Controls_GetConfig
+=================
+*/
+static void Controls_GetConfig( void )
+{
+ int i;
+ int twokeys[2];
+ bind_t* bindptr;
+
+ // put the bindings into a local store
+ bindptr = g_bindings;
+
+ // iterate each command, get its numeric binding
+ for (i=0; ;i++,bindptr++)
+ {
+ if (!bindptr->label)
+ break;
+
+ Controls_GetKeyAssignment(bindptr->command, twokeys);
+
+ bindptr->bind1 = twokeys[0];
+ bindptr->bind2 = twokeys[1];
+ }
+
+ s_controls.invertmouse.curvalue = Controls_GetCvarValue( "m_pitch" ) < 0;
+ s_controls.smoothmouse.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "m_filter" ) );
+ s_controls.alwaysrun.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_run" ) );
+ s_controls.autoswitch.curvalue = UI_ClampCvar( 0, 4, Controls_GetCvarValue( "cg_autoswitch" ) );
+ s_controls.sensitivity.curvalue = UI_ClampCvar( 2, 30, Controls_GetCvarValue( "sensitivity" ) );
+ s_controls.joyenable.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "in_joystick" ) );
+ s_controls.joythreshold.curvalue = UI_ClampCvar( 0.05f, 0.75f, Controls_GetCvarValue( "joy_threshold" ) );
+ s_controls.freelook.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_freelook" ) );
+ s_controls.voip_teamonly.curvalue= UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_voipTeamOnly" ) );
+}
+
+/*
+=================
+Controls_SetConfig
+=================
+*/
+static void Controls_SetConfig( void )
+{
+ int i;
+ bind_t* bindptr;
+
+ // set the bindings from the local store
+ bindptr = g_bindings;
+
+ // iterate each command, get its numeric binding
+ for (i=0; ;i++,bindptr++)
+ {
+ if (!bindptr->label)
+ break;
+
+ if (bindptr->bind1 != -1)
+ {
+ trap_Key_SetBinding( bindptr->bind1, bindptr->command );
+
+ if (bindptr->bind2 != -1)
+ trap_Key_SetBinding( bindptr->bind2, bindptr->command );
+ }
+ }
+
+ if ( s_controls.invertmouse.curvalue )
+ trap_Cvar_SetValue( "m_pitch", -fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
+ else
+ trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
+
+ trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue );
+ trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue );
+ trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue );
+ trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue );
+ trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue );
+ trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue );
+ trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue );
+ trap_Cvar_SetValue( "cg_voipTeamOnly", s_controls.voip_teamonly.curvalue);
+ trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" );
+}
+
+/*
+=================
+Controls_SetDefaults
+=================
+*/
+static void Controls_SetDefaults( void )
+{
+ int i;
+ bind_t* bindptr;
+
+ // set the bindings from the local store
+ bindptr = g_bindings;
+
+ // iterate each command, set its default binding
+ for (i=0; ;i++,bindptr++)
+ {
+ if (!bindptr->label)
+ break;
+
+ bindptr->bind1 = bindptr->defaultbind1;
+ bindptr->bind2 = bindptr->defaultbind2;
+ }
+
+ s_controls.invertmouse.curvalue = Controls_GetCvarDefault( "m_pitch" ) < 0;
+ s_controls.smoothmouse.curvalue = Controls_GetCvarDefault( "m_filter" );
+ s_controls.alwaysrun.curvalue = Controls_GetCvarDefault( "cl_run" );
+ s_controls.autoswitch.curvalue = Controls_GetCvarDefault( "cg_autoswitch" );
+ s_controls.sensitivity.curvalue = Controls_GetCvarDefault( "sensitivity" );
+ s_controls.joyenable.curvalue = Controls_GetCvarDefault( "in_joystick" );
+ s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" );
+ s_controls.freelook.curvalue = Controls_GetCvarDefault( "cl_freelook" );
+ s_controls.voip_teamonly.curvalue= Controls_GetCvarDefault( "cg_voipTeamOnly");
+}
+
+/*
+=================
+Controls_MenuKey
+=================
+*/
+static sfxHandle_t Controls_MenuKey( int key )
+{
+ int id;
+ int i;
+ qboolean found;
+ bind_t* bindptr;
+ found = qfalse;
+
+ if (!s_controls.waitingforkey)
+ {
+ switch (key)
+ {
+ case K_BACKSPACE:
+ case K_DEL:
+ case K_KP_DEL:
+ key = -1;
+ break;
+
+ case K_MOUSE2:
+ case K_ESCAPE:
+ if (s_controls.changesmade)
+ Controls_SetConfig();
+ goto ignorekey;
+
+ default:
+ goto ignorekey;
+ }
+ }
+ else
+ {
+ if (key & K_CHAR_FLAG)
+ goto ignorekey;
+
+ switch (key)
+ {
+ case K_ESCAPE:
+ s_controls.waitingforkey = qfalse;
+ Controls_Update();
+ return (menu_out_sound);
+
+ case '`':
+ goto ignorekey;
+ }
+ }
+
+ s_controls.changesmade = qtrue;
+
+ if (key != -1)
+ {
+ // remove from any other bind
+ bindptr = g_bindings;
+ for (i=0; ;i++,bindptr++)
+ {
+ if (!bindptr->label)
+ break;
+
+ if (bindptr->bind2 == key)
+ bindptr->bind2 = -1;
+
+ if (bindptr->bind1 == key)
+ {
+ bindptr->bind1 = bindptr->bind2;
+ bindptr->bind2 = -1;
+ }
+ }
+ }
+
+ // assign key to local store
+ id = ((menucommon_s*)(s_controls.menu.items[s_controls.menu.cursor]))->id;
+ bindptr = g_bindings;
+ for (i=0; ;i++,bindptr++)
+ {
+ if (!bindptr->label)
+ break;
+
+ if (bindptr->id == id)
+ {
+ found = qtrue;
+ if (key == -1)
+ {
+ if( bindptr->bind1 != -1 ) {
+ trap_Key_SetBinding( bindptr->bind1, "" );
+ bindptr->bind1 = -1;
+ }
+ if( bindptr->bind2 != -1 ) {
+ trap_Key_SetBinding( bindptr->bind2, "" );
+ bindptr->bind2 = -1;
+ }
+ }
+ else if (bindptr->bind1 == -1) {
+ bindptr->bind1 = key;
+ }
+ else if (bindptr->bind1 != key && bindptr->bind2 == -1) {
+ bindptr->bind2 = key;
+ }
+ else
+ {
+ trap_Key_SetBinding( bindptr->bind1, "" );
+ trap_Key_SetBinding( bindptr->bind2, "" );
+ bindptr->bind1 = key;
+ bindptr->bind2 = -1;
+ }
+ break;
+ }
+ }
+
+ s_controls.waitingforkey = qfalse;
+
+ if (found)
+ {
+ Controls_Update();
+ return (menu_out_sound);
+ }
+
+ignorekey:
+ return Menu_DefaultKey( &s_controls.menu, key );
+}
+
+/*
+=================
+Controls_ResetDefaults_Action
+=================
+*/
+static void Controls_ResetDefaults_Action( qboolean result ) {
+ if( !result ) {
+ return;
+ }
+
+ s_controls.changesmade = qtrue;
+ Controls_SetDefaults();
+ Controls_Update();
+}
+
+/*
+=================
+Controls_ResetDefaults_Draw
+=================
+*/
+static void Controls_ResetDefaults_Draw( void ) {
+ UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, "WARNING: This will reset all", UI_CENTER|UI_SMALLFONT, color_yellow );
+ UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, "controls to their default values.", UI_CENTER|UI_SMALLFONT, color_yellow );
+}
+
+/*
+=================
+Controls_MenuEvent
+=================
+*/
+static void Controls_MenuEvent( void* ptr, int event )
+{
+ switch (((menucommon_s*)ptr)->id)
+ {
+ case ID_MOVEMENT:
+ if (event == QM_ACTIVATED)
+ {
+ s_controls.section = C_MOVEMENT;
+ Controls_Update();
+ }
+ break;
+
+ case ID_LOOKING:
+ if (event == QM_ACTIVATED)
+ {
+ s_controls.section = C_LOOKING;
+ Controls_Update();
+ }
+ break;
+
+ case ID_WEAPONS:
+ if (event == QM_ACTIVATED)
+ {
+ s_controls.section = C_WEAPONS;
+ Controls_Update();
+ }
+ break;
+
+ case ID_MISC:
+ if (event == QM_ACTIVATED)
+ {
+ s_controls.section = C_MISC;
+ Controls_Update();
+ }
+ break;
+
+ case ID_DEFAULTS:
+ if (event == QM_ACTIVATED)
+ {
+ UI_ConfirmMenu( "SET TO DEFAULTS?", Controls_ResetDefaults_Draw, Controls_ResetDefaults_Action );
+ }
+ break;
+
+ case ID_BACK:
+ if (event == QM_ACTIVATED)
+ {
+ if (s_controls.changesmade)
+ Controls_SetConfig();
+ UI_PopMenu();
+ }
+ break;
+
+ case ID_SAVEANDEXIT:
+ if (event == QM_ACTIVATED)
+ {
+ Controls_SetConfig();
+ UI_PopMenu();
+ }
+ break;
+
+ case ID_EXIT:
+ if (event == QM_ACTIVATED)
+ {
+ UI_PopMenu();
+ }
+ break;
+
+ case ID_FREELOOK:
+ case ID_MOUSESPEED:
+ case ID_INVERTMOUSE:
+ case ID_SMOOTHMOUSE:
+ case ID_ALWAYSRUN:
+ case ID_AUTOSWITCH:
+ case ID_VOIP_TEAMONLY:
+ case ID_JOYENABLE:
+ case ID_JOYTHRESHOLD:
+ if (event == QM_ACTIVATED)
+ {
+ s_controls.changesmade = qtrue;
+ }
+ break;
+ }
+}
+
+/*
+=================
+Controls_ActionEvent
+=================
+*/
+static void Controls_ActionEvent( void* ptr, int event )
+{
+ if (event == QM_LOSTFOCUS)
+ {
+ Controls_UpdateModel( ANIM_IDLE );
+ }
+ else if (event == QM_GOTFOCUS)
+ {
+ Controls_UpdateModel( g_bindings[((menucommon_s*)ptr)->id].anim );
+ }
+ else if ((event == QM_ACTIVATED) && !s_controls.waitingforkey)
+ {
+ s_controls.waitingforkey = 1;
+ Controls_Update();
+ }
+}
+
+/*
+=================
+Controls_InitModel
+=================
+*/
+static void Controls_InitModel( void )
+{
+ memset( &s_controls.playerinfo, 0, sizeof(playerInfo_t) );
+
+ UI_PlayerInfo_SetModel( &s_controls.playerinfo, UI_Cvar_VariableString( "model" ) );
+
+ Controls_UpdateModel( ANIM_IDLE );
+}
+
+/*
+=================
+Controls_InitWeapons
+=================
+*/
+static void Controls_InitWeapons( void ) {
+ gitem_t * item;
+
+ for ( item = bg_itemlist + 1 ; item->classname ; item++ ) {
+ if ( item->giType != IT_WEAPON ) {
+ continue;
+ }
+ trap_R_RegisterModel( item->world_model[0] );
+ }
+}
+
+/*
+=================
+Controls_MenuInit
+=================
+*/
+static void Controls_MenuInit( void )
+{
+ static char playername[32];
+
+ // zero set all our globals
+ memset( &s_controls, 0 ,sizeof(controls_t) );
+
+ Controls_Cache();
+
+ s_controls.menu.key = Controls_MenuKey;
+ s_controls.menu.wrapAround = qtrue;
+ s_controls.menu.fullscreen = qtrue;
+
+ s_controls.banner.generic.type = MTYPE_BTEXT;
+ s_controls.banner.generic.flags = QMF_CENTER_JUSTIFY;
+ s_controls.banner.generic.x = 320;
+ s_controls.banner.generic.y = 16;
+ s_controls.banner.string = "CONTROLS";
+ s_controls.banner.color = color_white;
+ s_controls.banner.style = UI_CENTER;
+
+ s_controls.framel.generic.type = MTYPE_BITMAP;
+ s_controls.framel.generic.name = ART_FRAMEL;
+ s_controls.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
+ s_controls.framel.generic.x = 0;
+ s_controls.framel.generic.y = 78;
+ s_controls.framel.width = 256;
+ s_controls.framel.height = 329;
+
+ s_controls.framer.generic.type = MTYPE_BITMAP;
+ s_controls.framer.generic.name = ART_FRAMER;
+ s_controls.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
+ s_controls.framer.generic.x = 376;
+ s_controls.framer.generic.y = 76;
+ s_controls.framer.width = 256;
+ s_controls.framer.height = 334;
+
+ s_controls.looking.generic.type = MTYPE_PTEXT;
+ s_controls.looking.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_controls.looking.generic.id = ID_LOOKING;
+ s_controls.looking.generic.callback = Controls_MenuEvent;
+ s_controls.looking.generic.x = 152;
+ s_controls.looking.generic.y = 240 - 2 * PROP_HEIGHT;
+ s_controls.looking.string = "LOOK";
+ s_controls.looking.style = UI_RIGHT;
+ s_controls.looking.color = color_red;
+
+ s_controls.movement.generic.type = MTYPE_PTEXT;
+ s_controls.movement.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_controls.movement.generic.id = ID_MOVEMENT;
+ s_controls.movement.generic.callback = Controls_MenuEvent;
+ s_controls.movement.generic.x = 152;
+ s_controls.movement.generic.y = 240 - PROP_HEIGHT;
+ s_controls.movement.string = "MOVE";
+ s_controls.movement.style = UI_RIGHT;
+ s_controls.movement.color = color_red;
+
+ s_controls.weapons.generic.type = MTYPE_PTEXT;
+ s_controls.weapons.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_controls.weapons.generic.id = ID_WEAPONS;
+ s_controls.weapons.generic.callback = Controls_MenuEvent;
+ s_controls.weapons.generic.x = 152;
+ s_controls.weapons.generic.y = 240;
+ s_controls.weapons.string = "SHOOT";
+ s_controls.weapons.style = UI_RIGHT;
+ s_controls.weapons.color = color_red;
+
+ s_controls.misc.generic.type = MTYPE_PTEXT;
+ s_controls.misc.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_controls.misc.generic.id = ID_MISC;
+ s_controls.misc.generic.callback = Controls_MenuEvent;
+ s_controls.misc.generic.x = 152;
+ s_controls.misc.generic.y = 240 + PROP_HEIGHT;
+ s_controls.misc.string = "MISC";
+ s_controls.misc.style = UI_RIGHT;
+ s_controls.misc.color = color_red;
+
+ s_controls.back.generic.type = MTYPE_BITMAP;
+ s_controls.back.generic.name = ART_BACK0;
+ s_controls.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_controls.back.generic.x = 0;
+ s_controls.back.generic.y = 480-64;
+ s_controls.back.generic.id = ID_BACK;
+ s_controls.back.generic.callback = Controls_MenuEvent;
+ s_controls.back.width = 128;
+ s_controls.back.height = 64;
+ s_controls.back.focuspic = ART_BACK1;
+
+ s_controls.player.generic.type = MTYPE_BITMAP;
+ s_controls.player.generic.flags = QMF_INACTIVE;
+ s_controls.player.generic.ownerdraw = Controls_DrawPlayer;
+ s_controls.player.generic.x = 400;
+ s_controls.player.generic.y = -40;
+ s_controls.player.width = 32*10;
+ s_controls.player.height = 56*10;
+
+ s_controls.walkforward.generic.type = MTYPE_ACTION;
+ s_controls.walkforward.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.walkforward.generic.callback = Controls_ActionEvent;
+ s_controls.walkforward.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.walkforward.generic.id = ID_FORWARD;
+
+ s_controls.backpedal.generic.type = MTYPE_ACTION;
+ s_controls.backpedal.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.backpedal.generic.callback = Controls_ActionEvent;
+ s_controls.backpedal.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.backpedal.generic.id = ID_BACKPEDAL;
+
+ s_controls.stepleft.generic.type = MTYPE_ACTION;
+ s_controls.stepleft.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.stepleft.generic.callback = Controls_ActionEvent;
+ s_controls.stepleft.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.stepleft.generic.id = ID_MOVELEFT;
+
+ s_controls.stepright.generic.type = MTYPE_ACTION;
+ s_controls.stepright.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.stepright.generic.callback = Controls_ActionEvent;
+ s_controls.stepright.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.stepright.generic.id = ID_MOVERIGHT;
+
+ s_controls.moveup.generic.type = MTYPE_ACTION;
+ s_controls.moveup.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.moveup.generic.callback = Controls_ActionEvent;
+ s_controls.moveup.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.moveup.generic.id = ID_MOVEUP;
+
+ s_controls.movedown.generic.type = MTYPE_ACTION;
+ s_controls.movedown.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.movedown.generic.callback = Controls_ActionEvent;
+ s_controls.movedown.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.movedown.generic.id = ID_MOVEDOWN;
+
+ s_controls.turnleft.generic.type = MTYPE_ACTION;
+ s_controls.turnleft.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.turnleft.generic.callback = Controls_ActionEvent;
+ s_controls.turnleft.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.turnleft.generic.id = ID_LEFT;
+
+ s_controls.turnright.generic.type = MTYPE_ACTION;
+ s_controls.turnright.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.turnright.generic.callback = Controls_ActionEvent;
+ s_controls.turnright.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.turnright.generic.id = ID_RIGHT;
+
+ s_controls.sidestep.generic.type = MTYPE_ACTION;
+ s_controls.sidestep.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.sidestep.generic.callback = Controls_ActionEvent;
+ s_controls.sidestep.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.sidestep.generic.id = ID_STRAFE;
+
+ s_controls.run.generic.type = MTYPE_ACTION;
+ s_controls.run.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.run.generic.callback = Controls_ActionEvent;
+ s_controls.run.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.run.generic.id = ID_SPEED;
+
+ s_controls.chainsaw.generic.type = MTYPE_ACTION;
+ s_controls.chainsaw.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.chainsaw.generic.callback = Controls_ActionEvent;
+ s_controls.chainsaw.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.chainsaw.generic.id = ID_WEAPON1;
+
+ s_controls.machinegun.generic.type = MTYPE_ACTION;
+ s_controls.machinegun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.machinegun.generic.callback = Controls_ActionEvent;
+ s_controls.machinegun.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.machinegun.generic.id = ID_WEAPON2;
+
+ s_controls.shotgun.generic.type = MTYPE_ACTION;
+ s_controls.shotgun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.shotgun.generic.callback = Controls_ActionEvent;
+ s_controls.shotgun.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.shotgun.generic.id = ID_WEAPON3;
+
+ s_controls.grenadelauncher.generic.type = MTYPE_ACTION;
+ s_controls.grenadelauncher.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.grenadelauncher.generic.callback = Controls_ActionEvent;
+ s_controls.grenadelauncher.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.grenadelauncher.generic.id = ID_WEAPON4;
+
+ s_controls.rocketlauncher.generic.type = MTYPE_ACTION;
+ s_controls.rocketlauncher.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.rocketlauncher.generic.callback = Controls_ActionEvent;
+ s_controls.rocketlauncher.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.rocketlauncher.generic.id = ID_WEAPON5;
+
+ s_controls.lightning.generic.type = MTYPE_ACTION;
+ s_controls.lightning.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.lightning.generic.callback = Controls_ActionEvent;
+ s_controls.lightning.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.lightning.generic.id = ID_WEAPON6;
+
+ s_controls.railgun.generic.type = MTYPE_ACTION;
+ s_controls.railgun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.railgun.generic.callback = Controls_ActionEvent;
+ s_controls.railgun.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.railgun.generic.id = ID_WEAPON7;
+
+ s_controls.plasma.generic.type = MTYPE_ACTION;
+ s_controls.plasma.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.plasma.generic.callback = Controls_ActionEvent;
+ s_controls.plasma.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.plasma.generic.id = ID_WEAPON8;
+
+ s_controls.bfg.generic.type = MTYPE_ACTION;
+ s_controls.bfg.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.bfg.generic.callback = Controls_ActionEvent;
+ s_controls.bfg.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.bfg.generic.id = ID_WEAPON9;
+
+ s_controls.grapple.generic.type = MTYPE_ACTION;
+ s_controls.grapple.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.grapple.generic.callback = Controls_ActionEvent;
+ s_controls.grapple.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.grapple.generic.id = ID_WEAPON10;
+
+ s_controls.nailgun.generic.type = MTYPE_ACTION;
+ s_controls.nailgun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.nailgun.generic.callback = Controls_ActionEvent;
+ s_controls.nailgun.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.nailgun.generic.id = ID_WEAPON11;
+
+ s_controls.proxmine.generic.type = MTYPE_ACTION;
+ s_controls.proxmine.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.proxmine.generic.callback = Controls_ActionEvent;
+ s_controls.proxmine.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.proxmine.generic.id = ID_WEAPON12;
+
+ s_controls.chaingun.generic.type = MTYPE_ACTION;
+ s_controls.chaingun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.chaingun.generic.callback = Controls_ActionEvent;
+ s_controls.chaingun.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.chaingun.generic.id = ID_WEAPON13;
+
+ s_controls.attack.generic.type = MTYPE_ACTION;
+ s_controls.attack.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.attack.generic.callback = Controls_ActionEvent;
+ s_controls.attack.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.attack.generic.id = ID_ATTACK;
+
+ s_controls.prevweapon.generic.type = MTYPE_ACTION;
+ s_controls.prevweapon.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.prevweapon.generic.callback = Controls_ActionEvent;
+ s_controls.prevweapon.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.prevweapon.generic.id = ID_WEAPPREV;
+
+ s_controls.nextweapon.generic.type = MTYPE_ACTION;
+ s_controls.nextweapon.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.nextweapon.generic.callback = Controls_ActionEvent;
+ s_controls.nextweapon.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.nextweapon.generic.id = ID_WEAPNEXT;
+
+ s_controls.lookup.generic.type = MTYPE_ACTION;
+ s_controls.lookup.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.lookup.generic.callback = Controls_ActionEvent;
+ s_controls.lookup.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.lookup.generic.id = ID_LOOKUP;
+
+ s_controls.lookdown.generic.type = MTYPE_ACTION;
+ s_controls.lookdown.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.lookdown.generic.callback = Controls_ActionEvent;
+ s_controls.lookdown.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.lookdown.generic.id = ID_LOOKDOWN;
+
+ s_controls.mouselook.generic.type = MTYPE_ACTION;
+ s_controls.mouselook.generic.flags = QMF_LEFT_JUSTIFY|QMF_HIGHLIGHT_IF_FOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.mouselook.generic.callback = Controls_ActionEvent;
+ s_controls.mouselook.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.mouselook.generic.id = ID_MOUSELOOK;
+
+ s_controls.freelook.generic.type = MTYPE_RADIOBUTTON;
+ s_controls.freelook.generic.flags = QMF_SMALLFONT;
+ s_controls.freelook.generic.x = SCREEN_WIDTH/2;
+ s_controls.freelook.generic.name = "free look";
+ s_controls.freelook.generic.id = ID_FREELOOK;
+ s_controls.freelook.generic.callback = Controls_MenuEvent;
+ s_controls.freelook.generic.statusbar = Controls_StatusBar;
+
+ s_controls.centerview.generic.type = MTYPE_ACTION;
+ s_controls.centerview.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.centerview.generic.callback = Controls_ActionEvent;
+ s_controls.centerview.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.centerview.generic.id = ID_CENTERVIEW;
+
+ s_controls.zoomview.generic.type = MTYPE_ACTION;
+ s_controls.zoomview.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.zoomview.generic.callback = Controls_ActionEvent;
+ s_controls.zoomview.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.zoomview.generic.id = ID_ZOOMVIEW;
+
+ s_controls.useitem.generic.type = MTYPE_ACTION;
+ s_controls.useitem.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.useitem.generic.callback = Controls_ActionEvent;
+ s_controls.useitem.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.useitem.generic.id = ID_USEITEM;
+
+ s_controls.showscores.generic.type = MTYPE_ACTION;
+ s_controls.showscores.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.showscores.generic.callback = Controls_ActionEvent;
+ s_controls.showscores.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.showscores.generic.id = ID_SHOWSCORES;
+
+ s_controls.invertmouse.generic.type = MTYPE_RADIOBUTTON;
+ s_controls.invertmouse.generic.flags = QMF_SMALLFONT;
+ s_controls.invertmouse.generic.x = SCREEN_WIDTH/2;
+ s_controls.invertmouse.generic.name = "invert mouse";
+ s_controls.invertmouse.generic.id = ID_INVERTMOUSE;
+ s_controls.invertmouse.generic.callback = Controls_MenuEvent;
+ s_controls.invertmouse.generic.statusbar = Controls_StatusBar;
+
+ s_controls.smoothmouse.generic.type = MTYPE_RADIOBUTTON;
+ s_controls.smoothmouse.generic.flags = QMF_SMALLFONT;
+ s_controls.smoothmouse.generic.x = SCREEN_WIDTH/2;
+ s_controls.smoothmouse.generic.name = "smooth mouse";
+ s_controls.smoothmouse.generic.id = ID_SMOOTHMOUSE;
+ s_controls.smoothmouse.generic.callback = Controls_MenuEvent;
+ s_controls.smoothmouse.generic.statusbar = Controls_StatusBar;
+
+ s_controls.alwaysrun.generic.type = MTYPE_RADIOBUTTON;
+ s_controls.alwaysrun.generic.flags = QMF_SMALLFONT;
+ s_controls.alwaysrun.generic.x = SCREEN_WIDTH/2;
+ s_controls.alwaysrun.generic.name = "always run";
+ s_controls.alwaysrun.generic.id = ID_ALWAYSRUN;
+ s_controls.alwaysrun.generic.callback = Controls_MenuEvent;
+ s_controls.alwaysrun.generic.statusbar = Controls_StatusBar;
+
+ s_controls.autoswitch.generic.type = MTYPE_SPINCONTROL;
+ s_controls.autoswitch.generic.flags = QMF_SMALLFONT;
+ s_controls.autoswitch.generic.x = SCREEN_WIDTH/2;
+ s_controls.autoswitch.generic.name = "autoswitch weapons";
+ s_controls.autoswitch.generic.id = ID_AUTOSWITCH;
+ s_controls.autoswitch.generic.callback = Controls_MenuEvent;
+ s_controls.autoswitch.generic.statusbar = Controls_StatusBar;
+ s_controls.autoswitch.itemnames = autoswitch_items;
+
+ s_controls.sensitivity.generic.type = MTYPE_SLIDER;
+ s_controls.sensitivity.generic.x = SCREEN_WIDTH/2;
+ s_controls.sensitivity.generic.flags = QMF_SMALLFONT;
+ s_controls.sensitivity.generic.name = "mouse speed";
+ s_controls.sensitivity.generic.id = ID_MOUSESPEED;
+ s_controls.sensitivity.generic.callback = Controls_MenuEvent;
+ s_controls.sensitivity.minvalue = 2;
+ s_controls.sensitivity.maxvalue = 30;
+ s_controls.sensitivity.generic.statusbar = Controls_StatusBar;
+
+ s_controls.gesture.generic.type = MTYPE_ACTION;
+ s_controls.gesture.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.gesture.generic.callback = Controls_ActionEvent;
+ s_controls.gesture.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.gesture.generic.id = ID_GESTURE;
+
+ s_controls.chat.generic.type = MTYPE_ACTION;
+ s_controls.chat.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.chat.generic.callback = Controls_ActionEvent;
+ s_controls.chat.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.chat.generic.id = ID_CHAT;
+
+ s_controls.chat2.generic.type = MTYPE_ACTION;
+ s_controls.chat2.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.chat2.generic.callback = Controls_ActionEvent;
+ s_controls.chat2.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.chat2.generic.id = ID_CHAT2;
+
+ s_controls.chat3.generic.type = MTYPE_ACTION;
+ s_controls.chat3.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.chat3.generic.callback = Controls_ActionEvent;
+ s_controls.chat3.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.chat3.generic.id = ID_CHAT3;
+
+ s_controls.chat4.generic.type = MTYPE_ACTION;
+ s_controls.chat4.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.chat4.generic.callback = Controls_ActionEvent;
+ s_controls.chat4.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.chat4.generic.id = ID_CHAT4;
+
+ s_controls.voip_talk.generic.type = MTYPE_ACTION;
+ s_controls.voip_talk.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
+ s_controls.voip_talk.generic.callback = Controls_ActionEvent;
+ s_controls.voip_talk.generic.ownerdraw = Controls_DrawKeyBinding;
+ s_controls.voip_talk.generic.id = ID_VOIP_TALK;
+
+ s_controls.voip_teamonly.generic.type = MTYPE_RADIOBUTTON;
+ s_controls.voip_teamonly.generic.flags = QMF_SMALLFONT;
+ s_controls.voip_teamonly.generic.x = SCREEN_WIDTH/2;
+ s_controls.voip_teamonly.generic.name = "teamonly voicechat";
+ s_controls.voip_teamonly.generic.id = ID_VOIP_TEAMONLY;
+ s_controls.voip_teamonly.generic.callback = Controls_MenuEvent;
+ s_controls.voip_teamonly.generic.statusbar = Controls_StatusBar;
+
+ s_controls.joyenable.generic.type = MTYPE_RADIOBUTTON;
+ s_controls.joyenable.generic.flags = QMF_SMALLFONT;
+ s_controls.joyenable.generic.x = SCREEN_WIDTH/2;
+ s_controls.joyenable.generic.name = "joystick";
+ s_controls.joyenable.generic.id = ID_JOYENABLE;
+ s_controls.joyenable.generic.callback = Controls_MenuEvent;
+ s_controls.joyenable.generic.statusbar = Controls_StatusBar;
+
+ s_controls.joythreshold.generic.type = MTYPE_SLIDER;
+ s_controls.joythreshold.generic.x = SCREEN_WIDTH/2;
+ s_controls.joythreshold.generic.flags = QMF_SMALLFONT;
+ s_controls.joythreshold.generic.name = "joystick threshold";
+ s_controls.joythreshold.generic.id = ID_JOYTHRESHOLD;
+ s_controls.joythreshold.generic.callback = Controls_MenuEvent;
+ s_controls.joythreshold.minvalue = 0.05f;
+ s_controls.joythreshold.maxvalue = 0.75f;
+ s_controls.joythreshold.generic.statusbar = Controls_StatusBar;
+
+ s_controls.name.generic.type = MTYPE_PTEXT;
+ s_controls.name.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
+ s_controls.name.generic.x = 320;
+ s_controls.name.generic.y = 440;
+ s_controls.name.string = playername;
+ s_controls.name.style = UI_CENTER;
+ s_controls.name.color = text_color_normal;
+
+ Menu_AddItem( &s_controls.menu, &s_controls.banner );
+ Menu_AddItem( &s_controls.menu, &s_controls.framel );
+ Menu_AddItem( &s_controls.menu, &s_controls.framer );
+ Menu_AddItem( &s_controls.menu, &s_controls.player );
+ Menu_AddItem( &s_controls.menu, &s_controls.name );
+
+ Menu_AddItem( &s_controls.menu, &s_controls.looking );
+ Menu_AddItem( &s_controls.menu, &s_controls.movement );
+ Menu_AddItem( &s_controls.menu, &s_controls.weapons );
+ Menu_AddItem( &s_controls.menu, &s_controls.misc );
+
+ Menu_AddItem( &s_controls.menu, &s_controls.sensitivity );
+ Menu_AddItem( &s_controls.menu, &s_controls.smoothmouse );
+ Menu_AddItem( &s_controls.menu, &s_controls.invertmouse );
+ Menu_AddItem( &s_controls.menu, &s_controls.lookup );
+ Menu_AddItem( &s_controls.menu, &s_controls.lookdown );
+ Menu_AddItem( &s_controls.menu, &s_controls.mouselook );
+ Menu_AddItem( &s_controls.menu, &s_controls.freelook );
+ Menu_AddItem( &s_controls.menu, &s_controls.centerview );
+ Menu_AddItem( &s_controls.menu, &s_controls.zoomview );
+ Menu_AddItem( &s_controls.menu, &s_controls.joyenable );
+ Menu_AddItem( &s_controls.menu, &s_controls.joythreshold );
+
+ Menu_AddItem( &s_controls.menu, &s_controls.alwaysrun );
+ Menu_AddItem( &s_controls.menu, &s_controls.run );
+ Menu_AddItem( &s_controls.menu, &s_controls.walkforward );
+ Menu_AddItem( &s_controls.menu, &s_controls.backpedal );
+ Menu_AddItem( &s_controls.menu, &s_controls.stepleft );
+ Menu_AddItem( &s_controls.menu, &s_controls.stepright );
+ Menu_AddItem( &s_controls.menu, &s_controls.moveup );
+ Menu_AddItem( &s_controls.menu, &s_controls.movedown );
+ Menu_AddItem( &s_controls.menu, &s_controls.turnleft );
+ Menu_AddItem( &s_controls.menu, &s_controls.turnright );
+ Menu_AddItem( &s_controls.menu, &s_controls.sidestep );
+
+ Menu_AddItem( &s_controls.menu, &s_controls.attack );
+ Menu_AddItem( &s_controls.menu, &s_controls.nextweapon );
+ Menu_AddItem( &s_controls.menu, &s_controls.prevweapon );
+ Menu_AddItem( &s_controls.menu, &s_controls.autoswitch );
+ Menu_AddItem( &s_controls.menu, &s_controls.chainsaw );
+ Menu_AddItem( &s_controls.menu, &s_controls.machinegun );
+ Menu_AddItem( &s_controls.menu, &s_controls.shotgun );
+ Menu_AddItem( &s_controls.menu, &s_controls.grenadelauncher );
+ Menu_AddItem( &s_controls.menu, &s_controls.rocketlauncher );
+ Menu_AddItem( &s_controls.menu, &s_controls.lightning );
+ Menu_AddItem( &s_controls.menu, &s_controls.railgun );
+ Menu_AddItem( &s_controls.menu, &s_controls.plasma );
+ Menu_AddItem( &s_controls.menu, &s_controls.bfg );
+ Menu_AddItem( &s_controls.menu, &s_controls.grapple );
+ Menu_AddItem( &s_controls.menu, &s_controls.nailgun );
+ Menu_AddItem( &s_controls.menu, &s_controls.proxmine );
+ Menu_AddItem( &s_controls.menu, &s_controls.chaingun );
+
+ Menu_AddItem( &s_controls.menu, &s_controls.showscores );
+ Menu_AddItem( &s_controls.menu, &s_controls.useitem );
+ Menu_AddItem( &s_controls.menu, &s_controls.gesture );
+ Menu_AddItem( &s_controls.menu, &s_controls.chat );
+ Menu_AddItem( &s_controls.menu, &s_controls.chat2 );
+ Menu_AddItem( &s_controls.menu, &s_controls.chat3 );
+ Menu_AddItem( &s_controls.menu, &s_controls.chat4 );
+ Menu_AddItem( &s_controls.menu, &s_controls.voip_talk );
+ Menu_AddItem( &s_controls.menu, &s_controls.voip_teamonly );
+
+ Menu_AddItem( &s_controls.menu, &s_controls.back );
+
+ trap_Cvar_VariableStringBuffer( "name", s_controls.name.string, 16 );
+ Q_CleanStr( s_controls.name.string );
+
+ // initialize the configurable cvars
+ Controls_InitCvars();
+
+ // initialize the current config
+ Controls_GetConfig();
+
+ // intialize the model
+ Controls_InitModel();
+
+ // intialize the weapons
+ Controls_InitWeapons ();
+
+ // initial default section
+ s_controls.section = C_LOOKING;
+
+ // update the ui
+ Controls_Update();
+}
+
+
+/*
+=================
+Controls_Cache
+=================
+*/
+void Controls_Cache( void ) {
+ trap_R_RegisterShaderNoMip( ART_BACK0 );
+ trap_R_RegisterShaderNoMip( ART_BACK1 );
+ trap_R_RegisterShaderNoMip( ART_FRAMEL );
+ trap_R_RegisterShaderNoMip( ART_FRAMER );
+}
+
+
+/*
+=================
+UI_ControlsMenu
+=================
+*/
+void UI_ControlsMenu( void ) {
+ Controls_MenuInit();
+ UI_PushMenu( &s_controls.menu );
+}
diff --git a/code/q3_ui/ui_credits.c b/code/q3_ui/ui_credits.c
new file mode 100644
index 0000000..7d66073
--- /dev/null
+++ b/code/q3_ui/ui_credits.c
@@ -0,0 +1,96 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+/*
+=======================================================================
+
+CREDITS
+
+=======================================================================
+*/
+
+/*
+ *Sago 2008-06-29: This is kinda annoying and does not really give usefull information anyway
+ */
+
+
+#include "ui_local.h"
+
+
+typedef struct {
+ menuframework_s menu;
+} creditsmenu_t;
+
+static creditsmenu_t s_credits;
+
+
+/*
+=================
+UI_CreditMenu_Key
+=================
+*/
+static sfxHandle_t UI_CreditMenu_Key( int key ) {
+ if( key & K_CHAR_FLAG ) {
+ return 0;
+ }
+
+ //Sago: I no longer show credits on close. Consider something else if ingame credits are to be made
+ //trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
+ return 0;
+}
+
+
+/*
+===============
+UI_CreditMenu_Draw
+===============
+*/
+static void UI_CreditMenu_Draw( void ) {
+ int y;
+
+ y = 12;
+ UI_DrawProportionalString( 320, y, "Thank you for playing", UI_CENTER|UI_SMALLFONT, color_white );
+ y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
+ UI_DrawProportionalString( 320, y, "Open Arena", UI_CENTER|UI_SMALLFONT, color_white );
+
+ y += 228;
+ UI_DrawString( 320, y, "Terminating...", UI_CENTER|UI_SMALLFONT, color_red );
+
+ y = 480 - PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
+ UI_DrawProportionalString( 320, y, "www.openarena.ws", UI_CENTER|UI_SMALLFONT, color_white );
+}
+
+
+/*
+===============
+UI_CreditMenu
+===============
+*/
+void UI_CreditMenu( void ) {
+ memset( &s_credits, 0 ,sizeof(s_credits) );
+
+ s_credits.menu.draw = UI_CreditMenu_Draw;
+ s_credits.menu.key = UI_CreditMenu_Key;
+ s_credits.menu.fullscreen = qtrue;
+ UI_PushMenu ( &s_credits.menu );
+ trap_Cmd_ExecuteText( EXEC_APPEND, "wait 2; quit\n" );
+}
diff --git a/game/code/q3_ui/ui_demo2.c b/code/q3_ui/ui_demo2.c
similarity index 100%
rename from game/code/q3_ui/ui_demo2.c
rename to code/q3_ui/ui_demo2.c
diff --git a/game/code/q3_ui/ui_display.c b/code/q3_ui/ui_display.c
similarity index 100%
rename from game/code/q3_ui/ui_display.c
rename to code/q3_ui/ui_display.c
diff --git a/game/code/q3_ui/ui_firstconnect.c b/code/q3_ui/ui_firstconnect.c
similarity index 100%
rename from game/code/q3_ui/ui_firstconnect.c
rename to code/q3_ui/ui_firstconnect.c
diff --git a/code/q3_ui/ui_gameinfo.c b/code/q3_ui/ui_gameinfo.c
new file mode 100644
index 0000000..4c6d4d4
--- /dev/null
+++ b/code/q3_ui/ui_gameinfo.c
@@ -0,0 +1,815 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+//
+// gameinfo.c
+//
+
+#include "ui_local.h"
+
+
+//
+// arena and bot info
+//
+
+#define POOLSIZE 128 * 1024
+
+int ui_numBots;
+static char *ui_botInfos[MAX_BOTS];
+
+static int ui_numArenas;
+static char *ui_arenaInfos[MAX_ARENAS];
+
+static int ui_numSinglePlayerArenas;
+static int ui_numSpecialSinglePlayerArenas;
+
+static char memoryPool[POOLSIZE];
+static int allocPoint, outOfMemory;
+
+
+/*
+===============
+UI_Alloc
+===============
+*/
+void *UI_Alloc( int size ) {
+ char *p;
+
+ if ( allocPoint + size > POOLSIZE ) {
+ outOfMemory = qtrue;
+ return NULL;
+ }
+
+ p = &memoryPool[allocPoint];
+
+ allocPoint += ( size + 31 ) & ~31;
+
+ return p;
+}
+
+/*
+===============
+UI_InitMemory
+===============
+*/
+void UI_InitMemory( void ) {
+ allocPoint = 0;
+ outOfMemory = qfalse;
+}
+
+/*
+===============
+UI_ParseInfos
+===============
+*/
+int UI_ParseInfos( char *buf, int max, char *infos[] ) {
+ char *token;
+ int count;
+ char key[MAX_TOKEN_CHARS];
+ char info[MAX_INFO_STRING];
+
+ count = 0;
+
+ while ( 1 ) {
+ token = COM_Parse( &buf );
+ if ( !token[0] ) {
+ break;
+ }
+ if ( strcmp( token, "{" ) ) {
+ Com_Printf( "Missing { in info file\n" );
+ break;
+ }
+
+ if ( count == max ) {
+ Com_Printf( "Max infos exceeded\n" );
+ break;
+ }
+
+ info[0] = '\0';
+ while ( 1 ) {
+ token = COM_ParseExt( &buf, qtrue );
+ if ( !token[0] ) {
+ Com_Printf( "Unexpected end of info file\n" );
+ break;
+ }
+ if ( !strcmp( token, "}" ) ) {
+ break;
+ }
+ Q_strncpyz( key, token, sizeof( key ) );
+
+ token = COM_ParseExt( &buf, qfalse );
+ if ( !token[0] ) {
+ strcpy( token, "<NULL>" );
+ }
+ Info_SetValueForKey( info, key, token );
+ }
+ //NOTE: extra space for arena number
+ infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
+ if (infos[count]) {
+ strcpy(infos[count], info);
+ count++;
+ }
+ }
+ return count;
+}
+
+/*
+===============
+UI_LoadArenasFromFile
+===============
+*/
+static void UI_LoadArenasFromFile( char *filename ) {
+ int len;
+ fileHandle_t f;
+ char buf[MAX_ARENAS_TEXT];
+
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( !f ) {
+ trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
+ return;
+ }
+ if ( len >= MAX_ARENAS_TEXT ) {
+ trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i\n", filename, len, MAX_ARENAS_TEXT ) );
+ trap_FS_FCloseFile( f );
+ return;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] );
+}
+
+/*
+===============
+UI_LoadArenas
+===============
+*/
+static void UI_LoadArenas( void ) {
+ int numdirs;
+ vmCvar_t arenasFile;
+ char filename[128];
+ char dirlist[20*1024];
+ char* dirptr;
+ int i, n;
+ int dirlen;
+ char *type;
+ char *tag;
+ int singlePlayerNum, specialNum, otherNum;
+
+ ui_numArenas = 0;
+
+ trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
+ if( *arenasFile.string ) {
+ UI_LoadArenasFromFile(arenasFile.string);
+ }
+ else {
+ UI_LoadArenasFromFile("scripts/arenas.txt");
+ }
+
+ // get all arenas from .arena files
+ numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, sizeof(dirlist) );
+ dirptr = dirlist;
+ for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
+ dirlen = strlen(dirptr);
+ strcpy(filename, "scripts/");
+ strcat(filename, dirptr);
+ UI_LoadArenasFromFile(filename);
+ }
+ trap_Print( va( "%i arenas parsed\n", ui_numArenas ) );
+ if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all arenas\n");
+
+ // set initial numbers
+ for( n = 0; n < ui_numArenas; n++ ) {
+ Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", n ) );
+ }
+
+ // go through and count single players levels
+ ui_numSinglePlayerArenas = 0;
+ ui_numSpecialSinglePlayerArenas = 0;
+ for( n = 0; n < ui_numArenas; n++ ) {
+ // determine type
+ type = Info_ValueForKey( ui_arenaInfos[n], "type" );
+
+ // if no type specified, it will be treated as "ffa"
+ if( !*type ) {
+ continue;
+ }
+
+ if( strstr( type, "single" ) ) {
+ // check for special single player arenas (training, final)
+ tag = Info_ValueForKey( ui_arenaInfos[n], "special" );
+ if( *tag ) {
+ ui_numSpecialSinglePlayerArenas++;
+ continue;
+ }
+
+ ui_numSinglePlayerArenas++;
+ }
+ }
+
+ n = ui_numSinglePlayerArenas % ARENAS_PER_TIER;
+ if( n != 0 ) {
+ ui_numSinglePlayerArenas -= n;
+ trap_Print( va( "%i arenas ignored to make count divisible by %i\n", n, ARENAS_PER_TIER ) );
+ }
+
+ // go through once more and assign number to the levels
+ singlePlayerNum = 0;
+ specialNum = singlePlayerNum + ui_numSinglePlayerArenas;
+ otherNum = specialNum + ui_numSpecialSinglePlayerArenas + n;
+ for( n = 0; n < ui_numArenas; n++ ) {
+ // determine type
+ type = Info_ValueForKey( ui_arenaInfos[n], "type" );
+
+ // if no type specified, it will be treated as "ffa"
+ if( *type ) {
+ if( strstr( type, "single" ) ) {
+ // check for special single player arenas (training, final)
+ tag = Info_ValueForKey( ui_arenaInfos[n], "special" );
+ if( *tag ) {
+ Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", specialNum++ ) );
+ continue;
+ }
+
+ Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", singlePlayerNum++ ) );
+ continue;
+ }
+ }
+
+ Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", otherNum++ ) );
+ }
+}
+
+/*
+===============
+UI_GetArenaInfoByNumber
+===============
+*/
+const char *UI_GetArenaInfoByNumber( int num ) {
+ int n;
+ char *value;
+
+ if( num < 0 || num >= ui_numArenas ) {
+ trap_Print( va( S_COLOR_RED "Invalid arena number: %i\n", num ) );
+ return NULL;
+ }
+
+ for( n = 0; n < ui_numArenas; n++ ) {
+ value = Info_ValueForKey( ui_arenaInfos[n], "num" );
+ if( *value && atoi(value) == num ) {
+ return ui_arenaInfos[n];
+ }
+ }
+
+ return NULL;
+}
+
+
+/*
+===============
+UI_GetArenaInfoByNumber
+===============
+*/
+const char *UI_GetArenaInfoByMap( const char *map ) {
+ int n;
+
+ for( n = 0; n < ui_numArenas; n++ ) {
+ if( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], "map" ), map ) == 0 ) {
+ return ui_arenaInfos[n];
+ }
+ }
+
+ return NULL;
+}
+
+
+/*
+===============
+UI_GetSpecialArenaInfo
+===============
+*/
+const char *UI_GetSpecialArenaInfo( const char *tag ) {
+ int n;
+
+ for( n = 0; n < ui_numArenas; n++ ) {
+ if( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], "special" ), tag ) == 0 ) {
+ return ui_arenaInfos[n];
+ }
+ }
+
+ return NULL;
+}
+
+/*
+===============
+UI_LoadBotsFromFile
+===============
+*/
+static void UI_LoadBotsFromFile( char *filename ) {
+ int len;
+ fileHandle_t f;
+ char buf[MAX_BOTS_TEXT];
+
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( !f ) {
+ trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
+ return;
+ }
+ if ( len >= MAX_BOTS_TEXT ) {
+ trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i\n", filename, len, MAX_BOTS_TEXT ) );
+ trap_FS_FCloseFile( f );
+ return;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ ui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] );
+ if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all bots\n");
+}
+
+/*
+===============
+UI_LoadBots
+===============
+*/
+static void UI_LoadBots( void ) {
+ vmCvar_t botsFile;
+ int numdirs;
+ char filename[128];
+ char dirlist[1024];
+ char* dirptr;
+ int i;
+ int dirlen;
+
+ ui_numBots = 0;
+
+ trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
+ if( *botsFile.string ) {
+ UI_LoadBotsFromFile(botsFile.string);
+ }
+ else {
+ UI_LoadBotsFromFile("scripts/bots.txt");
+ }
+
+ // get all bots from .bot files
+ numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
+ dirptr = dirlist;
+ for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
+ dirlen = strlen(dirptr);
+ strcpy(filename, "scripts/");
+ strcat(filename, dirptr);
+ UI_LoadBotsFromFile(filename);
+ }
+ trap_Print( va( "%i bots parsed\n", ui_numBots ) );
+}
+
+
+/*
+===============
+UI_GetBotInfoByNumber
+===============
+*/
+char *UI_GetBotInfoByNumber( int num ) {
+ if( num < 0 || num >= ui_numBots ) {
+ trap_Print( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
+ return NULL;
+ }
+ return ui_botInfos[num];
+}
+
+
+/*
+===============
+UI_GetBotInfoByName
+===============
+*/
+char *UI_GetBotInfoByName( const char *name ) {
+ int n;
+ char *value;
+
+ for ( n = 0; n < ui_numBots ; n++ ) {
+ value = Info_ValueForKey( ui_botInfos[n], "name" );
+ if ( !Q_stricmp( value, name ) ) {
+ return ui_botInfos[n];
+ }
+ }
+
+ return NULL;
+}
+
+
+//
+// single player game info
+//
+
+/*
+===============
+UI_GetBestScore
+
+Returns the player's best finish on a given level, 0 if the have not played the level
+===============
+*/
+void UI_GetBestScore( int level, int *score, int *skill ) {
+ int n;
+ int skillScore;
+ int bestScore;
+ int bestScoreSkill;
+ char arenaKey[16];
+ char scores[MAX_INFO_VALUE];
+
+ if( !score || !skill ) {
+ return;
+ }
+
+ if( level < 0 || level > ui_numArenas ) {
+ return;
+ }
+
+ bestScore = 0;
+ bestScoreSkill = 0;
+
+ for( n = 1; n <= 5; n++ ) {
+ trap_Cvar_VariableStringBuffer( va( "g_spScores%i", n ), scores, MAX_INFO_VALUE );
+
+ Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
+ skillScore = atoi( Info_ValueForKey( scores, arenaKey ) );
+
+ if( skillScore < 1 || skillScore > 8 ) {
+ continue;
+ }
+
+ if( !bestScore || skillScore <= bestScore ) {
+ bestScore = skillScore;
+ bestScoreSkill = n;
+ }
+ }
+
+ *score = bestScore;
+ *skill = bestScoreSkill;
+}
+
+
+/*
+===============
+UI_SetBestScore
+
+Set the player's best finish for a level
+===============
+*/
+void UI_SetBestScore( int level, int score ) {
+ int skill;
+ int oldScore;
+ char arenaKey[16];
+ char scores[MAX_INFO_VALUE];
+
+ // validate score
+ if( score < 1 || score > 8 ) {
+ return;
+ }
+
+ // validate skill
+ skill = (int)trap_Cvar_VariableValue( "g_spSkill" );
+ if( skill < 1 || skill > 5 ) {
+ return;
+ }
+
+ // get scores
+ trap_Cvar_VariableStringBuffer( va( "g_spScores%i", skill ), scores, MAX_INFO_VALUE );
+
+ // see if this is better
+ Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
+ oldScore = atoi( Info_ValueForKey( scores, arenaKey ) );
+ if( oldScore && oldScore <= score ) {
+ return;
+ }
+
+ // update scores
+ Info_SetValueForKey( scores, arenaKey, va( "%i", score ) );
+ trap_Cvar_Set( va( "g_spScores%i", skill ), scores );
+}
+
+
+/*
+===============
+UI_LogAwardData
+===============
+*/
+void UI_LogAwardData( int award, int data ) {
+ char key[16];
+ char awardData[MAX_INFO_VALUE];
+ int oldValue;
+
+ if( data == 0 ) {
+ return;
+ }
+
+ if( award > AWARD_PERFECT ) {
+ trap_Print( va( S_COLOR_RED "Bad award %i in UI_LogAwardData\n", award ) );
+ return;
+ }
+
+ trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, sizeof(awardData) );
+
+ Com_sprintf( key, sizeof(key), "a%i", award );
+ oldValue = atoi( Info_ValueForKey( awardData, key ) );
+
+ Info_SetValueForKey( awardData, key, va( "%i", oldValue + data ) );
+ trap_Cvar_Set( "g_spAwards", awardData );
+}
+
+
+/*
+===============
+UI_GetAwardLevel
+===============
+*/
+int UI_GetAwardLevel( int award ) {
+ char key[16];
+ char awardData[MAX_INFO_VALUE];
+
+ trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, sizeof(awardData) );
+
+ Com_sprintf( key, sizeof(key), "a%i", award );
+ return atoi( Info_ValueForKey( awardData, key ) );
+}
+
+
+/*
+===============
+UI_TierCompleted
+===============
+*/
+int UI_TierCompleted( int levelWon ) {
+ int level;
+ int n;
+ int tier;
+ int score;
+ int skill;
+ const char *info;
+
+ tier = levelWon / ARENAS_PER_TIER;
+ level = tier * ARENAS_PER_TIER;
+
+ if( tier == UI_GetNumSPTiers() ) {
+ info = UI_GetSpecialArenaInfo( "training" );
+ if( levelWon == atoi( Info_ValueForKey( info, "num" ) ) ) {
+ return 0;
+ }
+ info = UI_GetSpecialArenaInfo( "final" );
+ if( !info || levelWon == atoi( Info_ValueForKey( info, "num" ) ) ) {
+ return tier + 1;
+ }
+ return -1;
+ }
+
+ for( n = 0; n < ARENAS_PER_TIER; n++, level++ ) {
+ UI_GetBestScore( level, &score, &skill );
+ if ( score != 1 ) {
+ return -1;
+ }
+ }
+ return tier + 1;
+}
+
+
+/*
+===============
+UI_ShowTierVideo
+===============
+*/
+qboolean UI_ShowTierVideo( int tier ) {
+ char key[16];
+ char videos[MAX_INFO_VALUE];
+
+ if( tier <= 0 ) {
+ return qfalse;
+ }
+
+ trap_Cvar_VariableStringBuffer( "g_spVideos", videos, sizeof(videos) );
+
+ Com_sprintf( key, sizeof(key), "tier%i", tier );
+ if( atoi( Info_ValueForKey( videos, key ) ) ) {
+ return qfalse;
+ }
+
+ Info_SetValueForKey( videos, key, va( "%i", 1 ) );
+ trap_Cvar_Set( "g_spVideos", videos );
+
+ return qtrue;
+}
+
+
+/*
+===============
+UI_CanShowTierVideo
+===============
+*/
+qboolean UI_CanShowTierVideo( int tier ) {
+ char key[16];
+ char videos[MAX_INFO_VALUE];
+
+ if( !tier ) {
+ return qfalse;
+ }
+
+ if( uis.demoversion && tier != 8 ) {
+ return qfalse;
+ }
+
+ trap_Cvar_VariableStringBuffer( "g_spVideos", videos, sizeof(videos) );
+
+ Com_sprintf( key, sizeof(key), "tier%i", tier );
+ if( atoi( Info_ValueForKey( videos, key ) ) ) {
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+
+/*
+===============
+UI_GetCurrentGame
+
+Returns the next level the player has not won
+===============
+*/
+int UI_GetCurrentGame( void ) {
+ int level;
+ int rank;
+ int skill;
+ const char *info;
+
+ info = UI_GetSpecialArenaInfo( "training" );
+ if( info ) {
+ level = atoi( Info_ValueForKey( info, "num" ) );
+ UI_GetBestScore( level, &rank, &skill );
+ if ( !rank || rank > 1 ) {
+ return level;
+ }
+ }
+
+ for( level = 0; level < ui_numSinglePlayerArenas; level++ ) {
+ UI_GetBestScore( level, &rank, &skill );
+ if ( !rank || rank > 1 ) {
+ return level;
+ }
+ }
+
+ info = UI_GetSpecialArenaInfo( "final" );
+ if( !info ) {
+ return -1;
+ }
+ return atoi( Info_ValueForKey( info, "num" ) );
+}
+
+
+/*
+===============
+UI_NewGame
+
+Clears the scores and sets the difficutly level
+===============
+*/
+void UI_NewGame( void ) {
+ trap_Cvar_Set( "g_spScores1", "" );
+ trap_Cvar_Set( "g_spScores2", "" );
+ trap_Cvar_Set( "g_spScores3", "" );
+ trap_Cvar_Set( "g_spScores4", "" );
+ trap_Cvar_Set( "g_spScores5", "" );
+ trap_Cvar_Set( "g_spAwards", "" );
+ trap_Cvar_Set( "g_spVideos", "" );
+}
+
+
+/*
+===============
+UI_GetNumArenas
+===============
+*/
+int UI_GetNumArenas( void ) {
+ return ui_numArenas;
+}
+
+
+/*
+===============
+UI_GetNumSPArenas
+===============
+*/
+int UI_GetNumSPArenas( void ) {
+ return ui_numSinglePlayerArenas;
+}
+
+
+/*
+===============
+UI_GetNumSPTiers
+===============
+*/
+int UI_GetNumSPTiers( void ) {
+ return ui_numSinglePlayerArenas / ARENAS_PER_TIER;
+}
+
+
+/*
+===============
+UI_GetNumBots
+===============
+*/
+int UI_GetNumBots( void ) {
+ return ui_numBots;
+}
+
+
+/*
+===============
+UI_SPUnlock_f
+===============
+*/
+void UI_SPUnlock_f( void ) {
+ char arenaKey[16];
+ char scores[MAX_INFO_VALUE];
+ int level;
+ int tier;
+
+ // get scores for skill 1
+ trap_Cvar_VariableStringBuffer( "g_spScores1", scores, MAX_INFO_VALUE );
+
+ // update scores
+ for( level = 0; level < ui_numSinglePlayerArenas + ui_numSpecialSinglePlayerArenas; level++ ) {
+ Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
+ Info_SetValueForKey( scores, arenaKey, "1" );
+ }
+ trap_Cvar_Set( "g_spScores1", scores );
+
+ // unlock cinematics
+ for( tier = 1; tier <= 8; tier++ ) {
+ UI_ShowTierVideo( tier );
+ }
+
+ trap_Print( "All levels unlocked at skill level 1\n" );
+
+ UI_SPLevelMenu_ReInit();
+}
+
+
+/*
+===============
+UI_SPUnlockMedals_f
+===============
+*/
+void UI_SPUnlockMedals_f( void ) {
+ int n;
+ char key[16];
+ char awardData[MAX_INFO_VALUE];
+
+ trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, MAX_INFO_VALUE );
+
+ for( n = 0; n < 6; n++ ) {
+ Com_sprintf( key, sizeof(key), "a%i", n );
+ Info_SetValueForKey( awardData, key, "100" );
+ }
+
+ trap_Cvar_Set( "g_spAwards", awardData );
+
+ trap_Print( "All levels unlocked at 100\n" );
+}
+
+
+/*
+===============
+UI_InitGameinfo
+===============
+*/
+void UI_InitGameinfo( void ) {
+
+ UI_InitMemory();
+ UI_LoadArenas();
+ UI_LoadBots();
+
+ uis.demoversion = qfalse;
+}
diff --git a/game/code/q3_ui/ui_ingame.c b/code/q3_ui/ui_ingame.c
similarity index 100%
rename from game/code/q3_ui/ui_ingame.c
rename to code/q3_ui/ui_ingame.c
diff --git a/game/code/q3_ui/ui_loadconfig.c b/code/q3_ui/ui_loadconfig.c
similarity index 100%
rename from game/code/q3_ui/ui_loadconfig.c
rename to code/q3_ui/ui_loadconfig.c
diff --git a/code/q3_ui/ui_local.h b/code/q3_ui/ui_local.h
new file mode 100644
index 0000000..0ba5512
--- /dev/null
+++ b/code/q3_ui/ui_local.h
@@ -0,0 +1,905 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#ifndef __UI_LOCAL_H__
+#define __UI_LOCAL_H__
+
+#define BASEOA
+
+#include "../qcommon/q_shared.h"
+#include "../renderer/tr_types.h"
+//NOTE: include the ui_public.h from the new UI
+#include "../ui/ui_public.h" // bk001205 - yes, do have to use this
+//redefine to old API version
+#undef UI_API_VERSION
+#define UI_API_VERSION 4
+#include "../client/keycodes.h"
+#include "../game/bg_public.h"
+#include "../ui/ui_shared.h"
+
+typedef void (*voidfunc_f)(void);
+
+extern vmCvar_t ui_ffa_fraglimit;
+extern vmCvar_t ui_ffa_timelimit;
+
+extern vmCvar_t ui_tourney_fraglimit;
+extern vmCvar_t ui_tourney_timelimit;
+
+extern vmCvar_t ui_team_fraglimit;
+extern vmCvar_t ui_team_timelimit;
+extern vmCvar_t ui_team_friendly;
+
+extern vmCvar_t ui_ctf_capturelimit;
+extern vmCvar_t ui_ctf_timelimit;
+extern vmCvar_t ui_ctf_friendly;
+
+extern vmCvar_t ui_1fctf_capturelimit;
+extern vmCvar_t ui_1fctf_timelimit;
+extern vmCvar_t ui_1fctf_friendly;
+
+extern vmCvar_t ui_overload_capturelimit;
+extern vmCvar_t ui_overload_timelimit;
+extern vmCvar_t ui_overload_friendly;
+
+extern vmCvar_t ui_harvester_capturelimit;
+extern vmCvar_t ui_harvester_timelimit;
+extern vmCvar_t ui_harvester_friendly;
+
+extern vmCvar_t ui_elimination_capturelimit;
+extern vmCvar_t ui_elimination_timelimit;
+
+extern vmCvar_t ui_ctf_elimination_capturelimit;
+extern vmCvar_t ui_ctf_elimination_timelimit;
+
+extern vmCvar_t ui_lms_fraglimit;
+extern vmCvar_t ui_lms_timelimit;
+
+extern vmCvar_t ui_dd_capturelimit;
+extern vmCvar_t ui_dd_timelimit;
+extern vmCvar_t ui_dd_friendly;
+
+extern vmCvar_t ui_dom_capturelimit;
+extern vmCvar_t ui_dom_timelimit;
+extern vmCvar_t ui_dom_friendly;
+
+extern vmCvar_t ui_arenasFile;
+extern vmCvar_t ui_botsFile;
+extern vmCvar_t ui_spScores1;
+extern vmCvar_t ui_spScores2;
+extern vmCvar_t ui_spScores3;
+extern vmCvar_t ui_spScores4;
+extern vmCvar_t ui_spScores5;
+extern vmCvar_t ui_spAwards;
+extern vmCvar_t ui_spVideos;
+extern vmCvar_t ui_spSkill;
+
+extern vmCvar_t ui_spSelection;
+
+extern vmCvar_t ui_browserMaster;
+extern vmCvar_t ui_browserGameType;
+extern vmCvar_t ui_browserSortKey;
+extern vmCvar_t ui_browserShowFull;
+extern vmCvar_t ui_browserShowEmpty;
+
+extern vmCvar_t ui_brassTime;
+extern vmCvar_t ui_drawCrosshair;
+extern vmCvar_t ui_drawCrosshairNames;
+extern vmCvar_t ui_marks;
+
+extern vmCvar_t ui_server1;
+extern vmCvar_t ui_server2;
+extern vmCvar_t ui_server3;
+extern vmCvar_t ui_server4;
+extern vmCvar_t ui_server5;
+extern vmCvar_t ui_server6;
+extern vmCvar_t ui_server7;
+extern vmCvar_t ui_server8;
+extern vmCvar_t ui_server9;
+extern vmCvar_t ui_server10;
+extern vmCvar_t ui_server11;
+extern vmCvar_t ui_server12;
+extern vmCvar_t ui_server13;
+extern vmCvar_t ui_server14;
+extern vmCvar_t ui_server15;
+extern vmCvar_t ui_server16;
+
+//extern vmCvar_t ui_cdkey;
+//extern vmCvar_t ui_cdkeychecked;
+extern vmCvar_t ui_setupchecked;
+
+//new in beta 23:
+extern vmCvar_t ui_browserOnlyHumans;
+
+//
+// ui_qmenu.c
+//
+
+#define RCOLUMN_OFFSET ( BIGCHAR_WIDTH )
+#define LCOLUMN_OFFSET (-BIGCHAR_WIDTH )
+
+#define SLIDER_RANGE 10
+#define MAX_EDIT_LINE 256
+
+#define MAX_MENUDEPTH 8
+#ifndef MAX_MENUITEMS
+#define MAX_MENUITEMS 64
+#endif
+
+#define MTYPE_NULL 0
+#define MTYPE_SLIDER 1
+#define MTYPE_ACTION 2
+#define MTYPE_SPINCONTROL 3
+#define MTYPE_FIELD 4
+#define MTYPE_RADIOBUTTON 5
+#define MTYPE_BITMAP 6
+#define MTYPE_TEXT 7
+#define MTYPE_SCROLLLIST 8
+#define MTYPE_PTEXT 9
+#define MTYPE_BTEXT 10
+
+#define QMF_BLINK (unsigned int)0x00000001
+#define QMF_SMALLFONT (unsigned int)0x00000002
+#define QMF_LEFT_JUSTIFY (unsigned int)0x00000004
+#define QMF_CENTER_JUSTIFY (unsigned int)0x00000008
+#define QMF_RIGHT_JUSTIFY (unsigned int)0x00000010
+#define QMF_NUMBERSONLY (unsigned int)0x00000020 // edit field is only numbers
+#define QMF_HIGHLIGHT (unsigned int)0x00000040
+#define QMF_HIGHLIGHT_IF_FOCUS (unsigned int)0x00000080 // steady focus
+#define QMF_PULSEIFFOCUS (unsigned int)0x00000100 // pulse if focus
+#define QMF_HASMOUSEFOCUS (unsigned int)0x00000200
+#define QMF_NOONOFFTEXT (unsigned int)0x00000400
+#define QMF_MOUSEONLY (unsigned int)0x00000800 // only mouse input allowed
+#define QMF_HIDDEN (unsigned int)0x00001000 // skips drawing
+#define QMF_GRAYED (unsigned int)0x00002000 // grays and disables
+#define QMF_INACTIVE (unsigned int)0x00004000 // disables any input
+#define QMF_NODEFAULTINIT (unsigned int)0x00008000 // skip default initialization
+#define QMF_OWNERDRAW (unsigned int)0x00010000
+#define QMF_PULSE (unsigned int)0x00020000
+#define QMF_LOWERCASE (unsigned int)0x00040000 // edit field is all lower case
+#define QMF_UPPERCASE (unsigned int)0x00080000 // edit field is all upper case
+#define QMF_SILENT (unsigned int)0x00100000
+
+//for cgs.ffa_gt and g_ffa kinda leary about this...
+//#define FREEFORALL (s_serveroptions.gametype==GT_LMS)
+//#define TRAP_FREEFORALL (trap_Cvar_VariableValue( "g_gametype" ) == GT_LMS)
+
+// callback notifications
+#define QM_GOTFOCUS 1
+#define QM_LOSTFOCUS 2
+#define QM_ACTIVATED 3
+
+typedef struct _tag_menuframework
+{
+ int cursor;
+ int cursor_prev;
+
+ int nitems;
+ void *items[MAX_MENUITEMS];
+
+ void (*draw) (void);
+ sfxHandle_t (*key) (int key);
+
+ qboolean wrapAround;
+ qboolean fullscreen;
+ qboolean showlogo;
+} menuframework_s;
+
+typedef struct
+{
+ int type;
+ const char *name;
+ int id;
+ int x, y;
+ int left;
+ int top;
+ int right;
+ int bottom;
+ menuframework_s *parent;
+ int menuPosition;
+ unsigned flags;
+
+ void (*callback)( void *self, int event );
+ void (*statusbar)( void *self );
+ void (*ownerdraw)( void *self );
+} menucommon_s;
+
+typedef struct {
+ int cursor;
+ int scroll;
+ int widthInChars;
+ char buffer[MAX_EDIT_LINE];
+ int maxchars;
+} mfield_t;
+
+typedef struct
+{
+ menucommon_s generic;
+ mfield_t field;
+} menufield_s;
+
+typedef struct
+{
+ menucommon_s generic;
+
+ float minvalue;
+ float maxvalue;
+ float curvalue;
+
+ float range;
+} menuslider_s;
+
+typedef struct
+{
+ menucommon_s generic;
+
+ int oldvalue;
+ int curvalue;
+ int numitems;
+ int top;
+
+ const char **itemnames;
+
+ int width;
+ int height;
+ int columns;
+ int seperation;
+} menulist_s;
+
+typedef struct
+{
+ menucommon_s generic;
+} menuaction_s;
+
+typedef struct
+{
+ menucommon_s generic;
+ int curvalue;
+} menuradiobutton_s;
+
+typedef struct
+{
+ menucommon_s generic;
+ char* focuspic;
+ char* errorpic;
+ qhandle_t shader;
+ qhandle_t focusshader;
+ int width;
+ int height;
+ float* focuscolor;
+} menubitmap_s;
+
+typedef struct
+{
+ menucommon_s generic;
+ char* string;
+ int style;
+ float* color;
+} menutext_s;
+
+#define MAX_MAPNAME_LENGTH 32
+
+typedef struct {
+ int pagenumber;
+ char mapname[10][MAX_MAPNAME_LENGTH];
+} t_mappage;
+
+extern t_mappage mappage;
+
+extern void Menu_Cache( void );
+extern void Menu_Focus( menucommon_s *m );
+extern void Menu_AddItem( menuframework_s *menu, void *item );
+extern void Menu_AdjustCursor( menuframework_s *menu, int dir );
+extern void Menu_Draw( menuframework_s *menu );
+extern void *Menu_ItemAtCursor( menuframework_s *m );
+extern sfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item );
+extern void Menu_SetCursor( menuframework_s *s, int cursor );
+extern void Menu_SetCursorToItem( menuframework_s *m, void* ptr );
+extern sfxHandle_t Menu_DefaultKey( menuframework_s *s, int key );
+extern void Bitmap_Init( menubitmap_s *b );
+extern void Bitmap_Draw( menubitmap_s *b );
+extern void ScrollList_Draw( menulist_s *l );
+extern sfxHandle_t ScrollList_Key( menulist_s *l, int key );
+extern sfxHandle_t menu_in_sound;
+extern sfxHandle_t menu_move_sound;
+extern sfxHandle_t menu_out_sound;
+extern sfxHandle_t menu_buzz_sound;
+extern sfxHandle_t menu_null_sound;
+extern sfxHandle_t weaponChangeSound;
+extern vec4_t menu_text_color;
+extern vec4_t menu_grayed_color;
+extern vec4_t menu_dark_color;
+extern vec4_t menu_highlight_color;
+extern vec4_t menu_red_color;
+extern vec4_t menu_black_color;
+extern vec4_t menu_dim_color;
+extern vec4_t color_black;
+extern vec4_t color_white;
+extern vec4_t color_yellow;
+extern vec4_t color_blue;
+extern vec4_t color_orange;
+extern vec4_t color_red;
+extern vec4_t color_dim;
+extern vec4_t name_color;
+extern vec4_t list_color;
+extern vec4_t listbar_color;
+extern vec4_t text_color_disabled;
+extern vec4_t text_color_normal;
+extern vec4_t text_color_highlight;
+
+extern char *ui_medalNames[];
+extern char *ui_medalPicNames[];
+extern char *ui_medalSounds[];
+
+//
+// ui_mfield.c
+//
+extern void MField_Clear( mfield_t *edit );
+extern void MField_KeyDownEvent( mfield_t *edit, int key );
+extern void MField_CharEvent( mfield_t *edit, int ch );
+extern void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color );
+extern void MenuField_Init( menufield_s* m );
+extern void MenuField_Draw( menufield_s *f );
+extern sfxHandle_t MenuField_Key( menufield_s* m, int* key );
+
+//
+// ui_menu.c
+//
+extern void MainMenu_Cache( void );
+extern void UI_MainMenu(void);
+extern void UI_RegisterCvars( void );
+extern void UI_UpdateCvars( void );
+extern void UI_SetDefaultCvar(const char* cvar, const char* value);
+
+//
+// ui_credits.c
+//
+extern void UI_CreditMenu( void );
+
+//
+// ui_ingame.c
+//
+extern void InGame_Cache( void );
+extern void UI_InGameMenu(void);
+
+//
+// ui_confirm.c
+//
+extern void ConfirmMenu_Cache( void );
+extern void UI_ConfirmMenu( const char *question, void (*draw)( void ), void (*action)( qboolean result ) );
+extern void UI_ConfirmMenu_Style( const char *question, int style, void (*draw)( void ), void (*action)( qboolean result ) );
+extern void UI_Message( const char **lines );
+
+//
+// ui_setup.c
+//
+extern void UI_SetupMenu_Cache( void );
+extern void UI_SetupMenu(void);
+
+//
+// ui_team.c
+//
+extern void UI_TeamMainMenu( void );
+extern void TeamMain_Cache( void );
+
+//
+// ui_connect.c
+//
+extern void UI_DrawConnectScreen( qboolean overlay );
+
+//
+// ui_controls2.c
+//
+extern void UI_ControlsMenu( void );
+extern void Controls_Cache( void );
+
+//
+// ui_demo2.c
+//
+extern void UI_DemosMenu( void );
+extern void Demos_Cache( void );
+
+//
+// ui_challenges.c
+//
+extern void UI_Challenges( void );
+
+//
+// ui_cinematics.c
+//
+extern void UI_CinematicsMenu( void );
+extern void UI_CinematicsMenu_f( void );
+extern void UI_CinematicsMenu_Cache( void );
+
+//
+// ui_mods.c
+//
+extern void UI_ModsMenu( void );
+extern void UI_ModsMenu_Cache( void );
+
+//
+// ui_cdkey.c
+//
+extern void UI_CDKeyMenu( void );
+extern void UI_CDKeyMenu_Cache( void );
+extern void UI_CDKeyMenu_f( void );
+
+//
+// ui_playermodel.c
+//
+extern void UI_PlayerModelMenu( void );
+extern void PlayerModel_Cache( void );
+
+//
+// ui_playersettings.c
+//
+extern void UI_PlayerSettingsMenu( void );
+extern void PlayerSettings_Cache( void );
+
+//
+// ui_preferences.c
+//
+extern void UI_PreferencesMenu( void );
+extern void Preferences_Cache( void );
+
+//
+// ui_specifyleague.c
+//
+extern void UI_SpecifyLeagueMenu( void );
+extern void SpecifyLeague_Cache( void );
+
+//
+// ui_specifyserver.c
+//
+extern void UI_SpecifyServerMenu( void );
+extern void SpecifyServer_Cache( void );
+
+//
+// ui_servers2.c
+//
+#define MAX_FAVORITESERVERS 16
+
+extern void UI_ArenaServersMenu( void );
+extern void ArenaServers_Cache( void );
+
+//
+// ui_startserver.c
+//
+extern void UI_StartServerMenu( qboolean multiplayer );
+extern void StartServer_Cache( void );
+extern void ServerOptions_Cache( void );
+extern void UI_BotSelectMenu( char *bot );
+extern void UI_BotSelectMenu_Cache( void );
+
+//
+// ui_serverinfo.c
+//
+extern void UI_ServerInfoMenu( void );
+extern void ServerInfo_Cache( void );
+
+//
+// ui_video.c
+//
+extern void UI_GraphicsOptionsMenu( void );
+extern void GraphicsOptions_Cache( void );
+extern void DriverInfo_Cache( void );
+
+//
+// ui_votemenu.c
+//
+extern void UI_VoteMenuMenu( void );
+
+//
+// ui_votemenu_fraglimit.c
+//
+extern void UI_VoteFraglimitMenu( void );
+
+//
+// ui_votemenu_timelimit.c
+//
+extern void UI_VoteTimelimitMenu( void );
+
+//
+// ui_votemenu_gametype.c
+//
+extern void UI_VoteGametypeMenu( void );
+
+//
+// ui_votemenu_kick.c
+//
+extern void UI_VoteKickMenu( void );
+
+//
+// ui_votemenu_map.c
+//
+extern void UI_VoteMapMenu( void );
+extern void UI_VoteMapMenuInternal( void );
+
+//
+// ui_password.c
+//
+extern void SpecifyPassword_Cache( void );
+extern void UI_SpecifyPasswordMenu( char* string, char *name );
+
+//
+// ui_firstconnect.c
+//
+extern void FirstConnect_Cache( void );
+extern void UI_FirstConnectMenu( void );
+
+//
+// ui_votemenu_custom.c
+
+extern void UI_VoteCustomMenu( void );
+
+//
+// ui_players.c
+//
+
+//FIXME ripped from cg_local.h
+typedef struct {
+ int oldFrame;
+ int oldFrameTime; // time when ->oldFrame was exactly on
+
+ int frame;
+ int frameTime; // time when ->frame will be exactly on
+
+ float backlerp;
+
+ float yawAngle;
+ qboolean yawing;
+ float pitchAngle;
+ qboolean pitching;
+
+ int animationNumber; // may include ANIM_TOGGLEBIT
+ animation_t *animation;
+ int animationTime; // time when the first frame of the animation will be exact
+} lerpFrame_t;
+
+typedef struct {
+ // model info
+ qhandle_t legsModel;
+ qhandle_t legsSkin;
+ lerpFrame_t legs;
+
+ qhandle_t torsoModel;
+ qhandle_t torsoSkin;
+ lerpFrame_t torso;
+
+ qhandle_t headModel;
+ qhandle_t headSkin;
+
+ animation_t animations[MAX_ANIMATIONS];
+
+ qhandle_t weaponModel;
+ qhandle_t barrelModel;
+ qhandle_t flashModel;
+ vec3_t flashDlightColor;
+ int muzzleFlashTime;
+
+ // currently in use drawing parms
+ vec3_t viewAngles;
+ vec3_t moveAngles;
+ weapon_t currentWeapon;
+ int legsAnim;
+ int torsoAnim;
+
+ // animation vars
+ weapon_t weapon;
+ weapon_t lastWeapon;
+ weapon_t pendingWeapon;
+ int weaponTimer;
+ int pendingLegsAnim;
+ int torsoAnimationTimer;
+
+ int pendingTorsoAnim;
+ int legsAnimationTimer;
+
+ qboolean chat;
+ qboolean newModel;
+
+ qboolean barrelSpinning;
+ float barrelAngle;
+ int barrelTime;
+
+ int realWeapon;
+} playerInfo_t;
+
+void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time );
+void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model );
+void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNum, qboolean chat );
+qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName );
+
+//
+// ui_atoms.c
+//
+typedef struct {
+ int frametime;
+ int realtime;
+ int cursorx;
+ int cursory;
+ int menusp;
+ menuframework_s* activemenu;
+ menuframework_s* stack[MAX_MENUDEPTH];
+ glconfig_t glconfig;
+ qboolean debug;
+ qhandle_t whiteShader;
+ qhandle_t menuBackShader;
+ qhandle_t menuBackNoLogoShader;
+ qhandle_t charset;
+ qhandle_t charsetProp;
+ qhandle_t charsetPropGlow;
+ qhandle_t charsetPropB;
+ qhandle_t cursor;
+ qhandle_t rb_on;
+ qhandle_t rb_off;
+ float xscale;
+ float yscale;
+ float bias;
+ qboolean demoversion;
+ qboolean firstdraw;
+} uiStatic_t;
+
+extern void UI_Init( void );
+extern void UI_Shutdown( void );
+extern void UI_KeyEvent( int key, int down );
+extern void UI_MouseEvent( int dx, int dy );
+extern void UI_Refresh( int realtime );
+extern qboolean UI_ConsoleCommand( int realTime );
+extern float UI_ClampCvar( float min, float max, float value );
+extern void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname );
+extern void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader );
+extern void UI_FillRect( float x, float y, float width, float height, const float *color );
+extern void UI_DrawRect( float x, float y, float width, float height, const float *color );
+extern void UI_UpdateScreen( void );
+extern void UI_SetColor( const float *rgba );
+extern void UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t);
+extern void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color );
+extern float UI_ProportionalSizeScale( int style );
+extern void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );
+extern void UI_DrawProportionalString_AutoWrapped( int x, int ystart, int xmax, int ystep, const char* str, int style, vec4_t color );
+extern int UI_ProportionalStringWidth( const char* str );
+extern void UI_DrawString( int x, int y, const char* str, int style, vec4_t color );
+extern void UI_DrawChar( int x, int y, int ch, int style, vec4_t color );
+extern qboolean UI_CursorInRect (int x, int y, int width, int height);
+extern void UI_AdjustFrom640( float *x, float *y, float *w, float *h );
+extern void UI_DrawTextBox (int x, int y, int width, int lines);
+extern qboolean UI_IsFullscreen( void );
+extern void UI_SetActiveMenu( uiMenuCommand_t menu );
+extern void UI_PushMenu ( menuframework_s *menu );
+extern void UI_PopMenu (void);
+extern void UI_ForceMenuOff (void);
+extern char *UI_Argv( int arg );
+extern char *UI_Cvar_VariableString( const char *var_name );
+extern void UI_Refresh( int time );
+extern void UI_StartDemoLoop( void );
+extern qboolean m_entersound;
+extern uiStatic_t uis;
+
+//
+// ui_spLevel.c
+//
+void UI_SPLevelMenu_Cache( void );
+void UI_SPLevelMenu( void );
+void UI_SPLevelMenu_f( void );
+void UI_SPLevelMenu_ReInit( void );
+
+//
+// ui_spArena.c
+//
+void UI_SPArena_Start( const char *arenaInfo );
+
+//
+// ui_spPostgame.c
+//
+void UI_SPPostgameMenu_Cache( void );
+void UI_SPPostgameMenu_f( void );
+
+//
+// ui_spSkill.c
+//
+void UI_SPSkillMenu( const char *arenaInfo );
+void UI_SPSkillMenu_Cache( void );
+
+//
+// ui_syscalls.c
+//
+void trap_Print( const char *string );
+void trap_Error( const char *string ) __attribute__((noreturn));
+int trap_Milliseconds( void );
+void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
+void trap_Cvar_Update( vmCvar_t *vmCvar );
+void trap_Cvar_Set( const char *var_name, const char *value );
+float trap_Cvar_VariableValue( const char *var_name );
+void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
+void trap_Cvar_SetValue( const char *var_name, float value );
+void trap_Cvar_Reset( const char *name );
+void trap_Cvar_Create( const char *var_name, const char *var_value, int flags );
+void trap_Cvar_InfoStringBuffer( int bit, char *buffer, int bufsize );
+int trap_Argc( void );
+void trap_Argv( int n, char *buffer, int bufferLength );
+void trap_Cmd_ExecuteText( int exec_when, const char *text ); // don't use EXEC_NOW!
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
+void trap_FS_Read( void *buffer, int len, fileHandle_t f );
+void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
+void trap_FS_FCloseFile( fileHandle_t f );
+int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
+int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
+qhandle_t trap_R_RegisterModel( const char *name );
+qhandle_t trap_R_RegisterSkin( const char *name );
+qhandle_t trap_R_RegisterShaderNoMip( const char *name );
+void trap_R_ClearScene( void );
+void trap_R_AddRefEntityToScene( const refEntity_t *re );
+void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );
+void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
+void trap_R_RenderScene( const refdef_t *fd );
+void trap_R_SetColor( const float *rgba );
+void trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
+void trap_UpdateScreen( void );
+int trap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName );
+void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );
+sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed );
+void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen );
+void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen );
+void trap_Key_SetBinding( int keynum, const char *binding );
+qboolean trap_Key_IsDown( int keynum );
+qboolean trap_Key_GetOverstrikeMode( void );
+void trap_Key_SetOverstrikeMode( qboolean state );
+void trap_Key_ClearStates( void );
+int trap_Key_GetCatcher( void );
+void trap_Key_SetCatcher( int catcher );
+void trap_GetClipboardData( char *buf, int bufsize );
+void trap_GetClientState( uiClientState_t *state );
+void trap_GetGlconfig( glconfig_t *glconfig );
+int trap_GetConfigString( int index, char* buff, int buffsize );
+int trap_LAN_GetServerCount( int source );
+void trap_LAN_GetServerAddressString( int source, int n, char *buf, int buflen );
+void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen );
+int trap_LAN_GetPingQueueCount( void );
+int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen );
+void trap_LAN_ClearPing( int n );
+void trap_LAN_GetPing( int n, char *buf, int buflen, int *pingtime );
+void trap_LAN_GetPingInfo( int n, char *buf, int buflen );
+int trap_MemoryRemaining( void );
+void trap_GetCDKey( char *buf, int buflen );
+void trap_SetCDKey( char *buf );
+
+qboolean trap_VerifyCDKey( const char *key, const char *chksum); // bk001208 - RC4
+
+void trap_SetPbClStatus( int status );
+
+//
+// ui_addbots.c
+//
+void UI_AddBots_Cache( void );
+void UI_AddBotsMenu( void );
+
+//
+// ui_removebots.c
+//
+void UI_RemoveBots_Cache( void );
+void UI_RemoveBotsMenu( void );
+
+//
+// ui_teamorders.c
+//
+extern void UI_TeamOrdersMenu( void );
+extern void UI_TeamOrdersMenu_f( void );
+extern void UI_TeamOrdersMenu_Cache( void );
+
+//
+// ui_loadconfig.c
+//
+void UI_LoadConfig_Cache( void );
+void UI_LoadConfigMenu( void );
+
+//
+// ui_saveconfig.c
+//
+void UI_SaveConfigMenu_Cache( void );
+void UI_SaveConfigMenu( void );
+
+//
+// ui_display.c
+//
+void UI_DisplayOptionsMenu_Cache( void );
+void UI_DisplayOptionsMenu( void );
+
+//
+// ui_sound.c
+//
+void UI_SoundOptionsMenu_Cache( void );
+void UI_SoundOptionsMenu( void );
+
+//
+// ui_network.c
+//
+void UI_NetworkOptionsMenu_Cache( void );
+void UI_NetworkOptionsMenu( void );
+
+//
+// ui_gameinfo.c
+//
+typedef enum {
+ AWARD_ACCURACY,
+ AWARD_IMPRESSIVE,
+ AWARD_EXCELLENT,
+ AWARD_GAUNTLET,
+ AWARD_FRAGS,
+ AWARD_PERFECT
+} awardType_t;
+
+const char *UI_GetArenaInfoByNumber( int num );
+const char *UI_GetArenaInfoByMap( const char *map );
+const char *UI_GetSpecialArenaInfo( const char *tag );
+int UI_GetNumArenas( void );
+int UI_GetNumSPArenas( void );
+int UI_GetNumSPTiers( void );
+
+char *UI_GetBotInfoByNumber( int num );
+char *UI_GetBotInfoByName( const char *name );
+int UI_GetNumBots( void );
+
+void UI_GetBestScore( int level, int *score, int *skill );
+void UI_SetBestScore( int level, int score );
+int UI_TierCompleted( int levelWon );
+qboolean UI_ShowTierVideo( int tier );
+qboolean UI_CanShowTierVideo( int tier );
+int UI_GetCurrentGame( void );
+void UI_NewGame( void );
+void UI_LogAwardData( int award, int data );
+int UI_GetAwardLevel( int award );
+
+void UI_SPUnlock_f( void );
+void UI_SPUnlockMedals_f( void );
+
+void UI_InitGameinfo( void );
+
+//GRank
+
+//
+// ui_rankings.c
+//
+void Rankings_DrawText( void* self );
+void Rankings_DrawName( void* self );
+void Rankings_DrawPassword( void* self );
+void Rankings_Cache( void );
+void UI_RankingsMenu( void );
+
+//
+// ui_login.c
+//
+void Login_Cache( void );
+void UI_LoginMenu( void );
+
+//
+// ui_signup.c
+//
+void Signup_Cache( void );
+void UI_SignupMenu( void );
+
+//
+// ui_rankstatus.c
+//
+void RankStatus_Cache( void );
+void UI_RankStatusMenu( void );
+
+#endif
diff --git a/game/code/q3_ui/ui_login.c b/code/q3_ui/ui_login.c
similarity index 100%
rename from game/code/q3_ui/ui_login.c
rename to code/q3_ui/ui_login.c
diff --git a/code/q3_ui/ui_main.c b/code/q3_ui/ui_main.c
new file mode 100644
index 0000000..c18bb6a
--- /dev/null
+++ b/code/q3_ui/ui_main.c
@@ -0,0 +1,330 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+/*
+=======================================================================
+
+USER INTERFACE MAIN
+
+=======================================================================
+*/
+
+
+#include "ui_local.h"
+
+
+/*
+================
+vmMain
+
+This is the only way control passes into the module.
+This must be the very first function compiled into the .qvm file
+================
+*/
+intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
+ switch ( command ) {
+ case UI_GETAPIVERSION:
+ return UI_API_VERSION;
+
+ case UI_INIT:
+ UI_Init();
+ return 0;
+
+ case UI_SHUTDOWN:
+ UI_Shutdown();
+ return 0;
+
+ case UI_KEY_EVENT:
+ UI_KeyEvent( arg0, arg1 );
+ return 0;
+
+ case UI_MOUSE_EVENT:
+ UI_MouseEvent( arg0, arg1 );
+ return 0;
+
+ case UI_REFRESH:
+ UI_Refresh( arg0 );
+ return 0;
+
+ case UI_IS_FULLSCREEN:
+ return UI_IsFullscreen();
+
+ case UI_SET_ACTIVE_MENU:
+ UI_SetActiveMenu( arg0 );
+ return 0;
+
+ case UI_CONSOLE_COMMAND:
+ return UI_ConsoleCommand(arg0);
+
+ case UI_DRAW_CONNECT_SCREEN:
+ UI_DrawConnectScreen( arg0 );
+ return 0;
+ case UI_HASUNIQUECDKEY: // mod authors need to observe this
+ return qtrue; // bk010117 - change this to qfalse for mods!
+ }
+
+ return -1;
+}
+
+
+/*
+================
+cvars
+================
+*/
+
+typedef struct {
+ vmCvar_t *vmCvar;
+ char *cvarName;
+ char *defaultString;
+ int cvarFlags;
+} cvarTable_t;
+
+vmCvar_t ui_ffa_fraglimit;
+vmCvar_t ui_ffa_timelimit;
+
+vmCvar_t ui_tourney_fraglimit;
+vmCvar_t ui_tourney_timelimit;
+
+vmCvar_t ui_team_fraglimit;
+vmCvar_t ui_team_timelimit;
+vmCvar_t ui_team_friendly;
+
+vmCvar_t ui_ctf_capturelimit;
+vmCvar_t ui_ctf_timelimit;
+vmCvar_t ui_ctf_friendly;
+
+vmCvar_t ui_1fctf_capturelimit;
+vmCvar_t ui_1fctf_timelimit;
+vmCvar_t ui_1fctf_friendly;
+
+vmCvar_t ui_overload_capturelimit;
+vmCvar_t ui_overload_timelimit;
+vmCvar_t ui_overload_friendly;
+
+vmCvar_t ui_harvester_capturelimit;
+vmCvar_t ui_harvester_timelimit;
+vmCvar_t ui_harvester_friendly;
+
+vmCvar_t ui_elimination_capturelimit;
+vmCvar_t ui_elimination_timelimit;
+
+vmCvar_t ui_ctf_elimination_capturelimit;
+vmCvar_t ui_ctf_elimination_timelimit;
+
+vmCvar_t ui_lms_fraglimit;
+vmCvar_t ui_lms_timelimit;
+
+vmCvar_t ui_dd_capturelimit;
+vmCvar_t ui_dd_timelimit;
+vmCvar_t ui_dd_friendly;
+
+vmCvar_t ui_dom_capturelimit;
+vmCvar_t ui_dom_timelimit;
+vmCvar_t ui_dom_friendly;
+
+vmCvar_t ui_arenasFile;
+vmCvar_t ui_botsFile;
+vmCvar_t ui_spScores1;
+vmCvar_t ui_spScores2;
+vmCvar_t ui_spScores3;
+vmCvar_t ui_spScores4;
+vmCvar_t ui_spScores5;
+vmCvar_t ui_spAwards;
+vmCvar_t ui_spVideos;
+vmCvar_t ui_spSkill;
+
+vmCvar_t ui_spSelection;
+
+vmCvar_t ui_browserMaster;
+vmCvar_t ui_browserGameType;
+vmCvar_t ui_browserSortKey;
+vmCvar_t ui_browserShowFull;
+vmCvar_t ui_browserShowEmpty;
+
+vmCvar_t ui_brassTime;
+vmCvar_t ui_drawCrosshair;
+vmCvar_t ui_drawCrosshairNames;
+vmCvar_t ui_marks;
+
+vmCvar_t ui_server1;
+vmCvar_t ui_server2;
+vmCvar_t ui_server3;
+vmCvar_t ui_server4;
+vmCvar_t ui_server5;
+vmCvar_t ui_server6;
+vmCvar_t ui_server7;
+vmCvar_t ui_server8;
+vmCvar_t ui_server9;
+vmCvar_t ui_server10;
+vmCvar_t ui_server11;
+vmCvar_t ui_server12;
+vmCvar_t ui_server13;
+vmCvar_t ui_server14;
+vmCvar_t ui_server15;
+vmCvar_t ui_server16;
+
+//vmCvar_t ui_cdkeychecked;
+
+//new in beta 23:
+vmCvar_t ui_browserOnlyHumans;
+
+//new in beta 37:
+vmCvar_t ui_setupchecked;
+
+// bk001129 - made static to avoid aliasing.
+static cvarTable_t cvarTable[] = {
+ { &ui_ffa_fraglimit, "ui_ffa_fraglimit", "20", CVAR_ARCHIVE },
+ { &ui_ffa_timelimit, "ui_ffa_timelimit", "0", CVAR_ARCHIVE },
+
+ { &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE },
+ { &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE },
+
+ { &ui_team_fraglimit, "ui_team_fraglimit", "0", CVAR_ARCHIVE },
+ { &ui_team_timelimit, "ui_team_timelimit", "20", CVAR_ARCHIVE },
+ { &ui_team_friendly, "ui_team_friendly", "1", CVAR_ARCHIVE },
+
+ { &ui_ctf_capturelimit, "ui_ctf_capturelimit", "8", CVAR_ARCHIVE },
+ { &ui_ctf_timelimit, "ui_ctf_timelimit", "30", CVAR_ARCHIVE },
+ { &ui_ctf_friendly, "ui_ctf_friendly", "0", CVAR_ARCHIVE },
+
+ { &ui_1fctf_capturelimit, "ui_1fctf_capturelimit", "8", CVAR_ARCHIVE },
+ { &ui_1fctf_timelimit, "ui_1fctf_timelimit", "30", CVAR_ARCHIVE },
+ { &ui_1fctf_friendly, "ui_1fctf_friendly", "0", CVAR_ARCHIVE },
+
+ { &ui_overload_capturelimit, "ui_overload_capturelimit", "8", CVAR_ARCHIVE },
+ { &ui_overload_timelimit, "ui_overload_timelimit", "30", CVAR_ARCHIVE },
+ { &ui_overload_friendly, "ui_overload_friendly", "0", CVAR_ARCHIVE },
+
+ { &ui_harvester_capturelimit, "ui_harvester_capturelimit", "20", CVAR_ARCHIVE },
+ { &ui_harvester_timelimit, "ui_harvester_timelimit", "30", CVAR_ARCHIVE },
+ { &ui_harvester_friendly, "ui_harvester_friendly", "0", CVAR_ARCHIVE },
+
+ { &ui_elimination_capturelimit, "ui_elimination_capturelimit", "8", CVAR_ARCHIVE },
+ { &ui_elimination_timelimit, "ui_elimination_timelimit", "20", CVAR_ARCHIVE },
+
+ { &ui_ctf_elimination_capturelimit, "ui_ctf_elimination_capturelimit", "8", CVAR_ARCHIVE },
+ { &ui_ctf_elimination_timelimit, "ui_ctf_elimination_timelimit", "30", CVAR_ARCHIVE },
+
+ { &ui_lms_fraglimit, "ui_lms_fraglimit", "20", CVAR_ARCHIVE },
+ { &ui_lms_timelimit, "ui_lms_timelimit", "0", CVAR_ARCHIVE },
+
+ { &ui_dd_capturelimit, "ui_dd_capturelimit", "8", CVAR_ARCHIVE },
+ { &ui_dd_timelimit, "ui_dd_timelimit", "30", CVAR_ARCHIVE },
+ { &ui_dd_friendly, "ui_dd_friendly", "0", CVAR_ARCHIVE },
+
+ { &ui_dom_capturelimit, "ui_dom_capturelimit", "500", CVAR_ARCHIVE },
+ { &ui_dom_timelimit, "ui_dom_timelimit", "30", CVAR_ARCHIVE },
+ { &ui_dom_friendly, "ui_dom_friendly", "0", CVAR_ARCHIVE },
+
+ { &ui_arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM },
+ { &ui_botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM },
+ { &ui_spScores1, "g_spScores1", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spScores2, "g_spScores2", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spScores3, "g_spScores3", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spScores4, "g_spScores4", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spScores5, "g_spScores5", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spAwards, "g_spAwards", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spVideos, "g_spVideos", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spSkill, "g_spSkill", "2", CVAR_ARCHIVE | CVAR_LATCH },
+
+ { &ui_spSelection, "ui_spSelection", "", CVAR_ROM },
+
+ { &ui_browserMaster, "ui_browserMaster", "0", CVAR_ARCHIVE },
+ { &ui_browserGameType, "ui_browserGameType", "0", CVAR_ARCHIVE },
+ { &ui_browserSortKey, "ui_browserSortKey", "4", CVAR_ARCHIVE },
+ { &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE },
+ { &ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE },
+
+ { &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
+ { &ui_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
+ { &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
+ { &ui_marks, "cg_marks", "1", CVAR_ARCHIVE },
+
+ { &ui_server1, "server1", "", CVAR_ARCHIVE },
+ { &ui_server2, "server2", "", CVAR_ARCHIVE },
+ { &ui_server3, "server3", "", CVAR_ARCHIVE },
+ { &ui_server4, "server4", "", CVAR_ARCHIVE },
+ { &ui_server5, "server5", "", CVAR_ARCHIVE },
+ { &ui_server6, "server6", "", CVAR_ARCHIVE },
+ { &ui_server7, "server7", "", CVAR_ARCHIVE },
+ { &ui_server8, "server8", "", CVAR_ARCHIVE },
+ { &ui_server9, "server9", "", CVAR_ARCHIVE },
+ { &ui_server10, "server10", "", CVAR_ARCHIVE },
+ { &ui_server11, "server11", "", CVAR_ARCHIVE },
+ { &ui_server12, "server12", "", CVAR_ARCHIVE },
+ { &ui_server13, "server13", "", CVAR_ARCHIVE },
+ { &ui_server14, "server14", "", CVAR_ARCHIVE },
+ { &ui_server15, "server15", "", CVAR_ARCHIVE },
+ { &ui_server16, "server16", "", CVAR_ARCHIVE },
+
+ //{ &ui_cdkeychecked, "ui_cdkeychecked", "0", CVAR_ROM },
+
+ //new in beta 23:
+ { &ui_browserOnlyHumans, "ui_browserOnlyHumans", "0", CVAR_ARCHIVE },
+
+ //new in beta 37:
+ { &ui_setupchecked, "ui_setupchecked", "0", CVAR_ARCHIVE },
+};
+
+// bk001129 - made static to avoid aliasing
+static int cvarTableSize = sizeof(cvarTable) / sizeof(cvarTable[0]);
+
+/*
+=================
+UI_RegisterCvars
+=================
+*/
+void UI_RegisterCvars( void ) {
+ int i;
+ cvarTable_t *cv;
+
+ for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
+ trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );
+ }
+}
+
+/*
+=================
+UI_UpdateCvars
+=================
+*/
+void UI_UpdateCvars( void ) {
+ int i;
+ cvarTable_t *cv;
+
+ for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
+ trap_Cvar_Update( cv->vmCvar );
+ }
+}
+
+/*
+==================
+ * UI_SetDefaultCvar
+ * If the cvar is blank it will be set to value
+ * This is only good for cvars that cannot naturally be blank
+==================
+ */
+void UI_SetDefaultCvar(const char* cvar, const char* value) {
+ if(strlen(UI_Cvar_VariableString(cvar)) == 0)
+ trap_Cvar_Set(cvar,value);
+}
\ No newline at end of file
diff --git a/code/q3_ui/ui_menu.c b/code/q3_ui/ui_menu.c
new file mode 100644
index 0000000..c407a45
--- /dev/null
+++ b/code/q3_ui/ui_menu.c
@@ -0,0 +1,437 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+/*
+=======================================================================
+
+MAIN MENU
+
+=======================================================================
+*/
+
+
+#include "ui_local.h"
+
+
+#define ID_SINGLEPLAYER 10
+#define ID_MULTIPLAYER 11
+#define ID_SETUP 12
+#define ID_DEMOS 13
+//#define ID_CINEMATICS 14
+#define ID_CHALLENGES 14
+#define ID_TEAMARENA 15
+#define ID_MODS 16
+#define ID_EXIT 17
+
+#define MAIN_BANNER_MODEL "models/mapobjects/banner/banner5.md3"
+#define MAIN_MENU_VERTICAL_SPACING 34
+
+
+typedef struct {
+ menuframework_s menu;
+
+ menutext_s singleplayer;
+ menutext_s multiplayer;
+ menutext_s setup;
+ menutext_s demos;
+ //menutext_s cinematics;
+ menutext_s challenges;
+ menutext_s teamArena;
+ menutext_s mods;
+ menutext_s exit;
+
+ qhandle_t bannerModel;
+} mainmenu_t;
+
+
+static mainmenu_t s_main;
+
+typedef struct {
+ menuframework_s menu;
+ char errorMessage[4096];
+} errorMessage_t;
+
+static errorMessage_t s_errorMessage;
+
+/*
+=================
+MainMenu_ExitAction
+=================
+*/
+/*static void MainMenu_ExitAction( qboolean result ) {
+ if( !result ) {
+ return;
+ }
+ UI_PopMenu();
+ //UI_CreditMenu();
+ trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
+}*/
+
+
+
+/*
+=================
+Main_MenuEvent
+=================
+*/
+void Main_MenuEvent (void* ptr, int event) {
+ if( event != QM_ACTIVATED ) {
+ return;
+ }
+
+ switch( ((menucommon_s*)ptr)->id ) {
+ case ID_SINGLEPLAYER:
+ UI_SPLevelMenu();
+ break;
+
+ case ID_MULTIPLAYER:
+ if(ui_setupchecked.integer)
+ UI_ArenaServersMenu();
+ else
+ UI_FirstConnectMenu();
+ break;
+
+ case ID_SETUP:
+ UI_SetupMenu();
+ break;
+
+ case ID_DEMOS:
+ UI_DemosMenu();
+ break;
+
+ /*case ID_CINEMATICS:
+ UI_CinematicsMenu();
+ break;*/
+
+ case ID_CHALLENGES:
+ UI_Challenges();
+ break;
+
+ case ID_MODS:
+ UI_ModsMenu();
+ break;
+
+ case ID_TEAMARENA:
+ trap_Cvar_Set( "fs_game", "missionpack");
+ trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
+ break;
+
+ case ID_EXIT:
+ //UI_ConfirmMenu( "EXIT GAME?", 0, MainMenu_ExitAction );
+ UI_CreditMenu();
+ break;
+ }
+}
+
+
+/*
+===============
+MainMenu_Cache
+===============
+*/
+void MainMenu_Cache( void ) {
+ s_main.bannerModel = trap_R_RegisterModel( MAIN_BANNER_MODEL );
+}
+
+sfxHandle_t ErrorMessage_Key(int key)
+{
+ trap_Cvar_Set( "com_errorMessage", "" );
+ UI_MainMenu();
+ return (menu_null_sound);
+}
+
+/*
+===============
+Main_MenuDraw
+TTimo: this function is common to the main menu and errorMessage menu
+===============
+*/
+
+static void Main_MenuDraw( void ) {
+ refdef_t refdef;
+ refEntity_t ent;
+ vec3_t origin;
+ vec3_t angles;
+ float adjust;
+ float x, y, w, h;
+ vec4_t color = {0.2, 0.2, 1.0, 1};
+
+ // setup the refdef
+
+ memset( &refdef, 0, sizeof( refdef ) );
+
+ refdef.rdflags = RDF_NOWORLDMODEL;
+
+ AxisClear( refdef.viewaxis );
+
+ x = 0;
+ y = 0;
+ w = 640;
+ h = 120;
+ UI_AdjustFrom640( &x, &y, &w, &h );
+ refdef.x = x;
+ refdef.y = y;
+ refdef.width = w;
+ refdef.height = h;
+
+ adjust = 0; // JDC: Kenneth asked me to stop this 1.0 * sin( (float)uis.realtime / 1000 );
+ refdef.fov_x = 60 + adjust;
+ refdef.fov_y = 19.6875 + adjust;
+
+ refdef.time = uis.realtime;
+
+ origin[0] = 300;
+ origin[1] = 0;
+ origin[2] = -32;
+
+ trap_R_ClearScene();
+
+ // add the model
+
+ memset( &ent, 0, sizeof(ent) );
+
+ adjust = 5.0 * sin( (float)uis.realtime / 5000 );
+ VectorSet( angles, 0, 180 + adjust, 0 );
+ AnglesToAxis( angles, ent.axis );
+ ent.hModel = s_main.bannerModel;
+ VectorCopy( origin, ent.origin );
+ VectorCopy( origin, ent.lightingOrigin );
+ ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
+ VectorCopy( ent.origin, ent.oldorigin );
+
+ trap_R_AddRefEntityToScene( &ent );
+
+ trap_R_RenderScene( &refdef );
+
+ if (strlen(s_errorMessage.errorMessage))
+ {
+ UI_DrawProportionalString_AutoWrapped( 320, 192, 600, 20, s_errorMessage.errorMessage, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
+ }
+ else
+ {
+ // standard menu drawing
+ Menu_Draw( &s_main.menu );
+ }
+
+ UI_DrawProportionalString( 320, 372, "", UI_CENTER|UI_SMALLFONT, color );
+ UI_DrawString( 320, 400, "OpenArena(c) 2005-2012 OpenArena Team", UI_CENTER|UI_SMALLFONT, color );
+ UI_DrawString( 320, 414, "OpenArena comes with ABSOLUTELY NO WARRANTY; this is free software", UI_CENTER|UI_SMALLFONT, color );
+ UI_DrawString( 320, 428, "and you are welcome to redistribute it under certain conditions;", UI_CENTER|UI_SMALLFONT, color );
+ UI_DrawString( 320, 444, "read COPYING for details.", UI_CENTER|UI_SMALLFONT, color );
+
+ //Draw version.
+ UI_DrawString( 640-40, 480-14, "^70.8.8", UI_SMALLFONT, color );
+ if((int)trap_Cvar_VariableValue("protocol")!=71)
+ UI_DrawString( 0, 480-14, va("^7Protocol: %i",(int)trap_Cvar_VariableValue("protocol")), UI_SMALLFONT, color);
+}
+
+
+/*
+===============
+UI_TeamArenaExists
+===============
+*/
+static qboolean UI_TeamArenaExists( void ) {
+ int numdirs;
+ char dirlist[2048];
+ char *dirptr;
+ char *descptr;
+ int i;
+ int dirlen;
+
+ numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) );
+ dirptr = dirlist;
+ for( i = 0; i < numdirs; i++ ) {
+ dirlen = strlen( dirptr ) + 1;
+ descptr = dirptr + dirlen;
+ if (Q_stricmp(dirptr, "missionpack") == 0) {
+ return qtrue;
+ }
+ dirptr += dirlen + strlen(descptr) + 1;
+ }
+ return qfalse;
+}
+
+
+/*
+===============
+UI_MainMenu
+
+The main menu only comes up when not in a game,
+so make sure that the attract loop server is down
+and that local cinematics are killed
+===============
+*/
+void UI_MainMenu( void ) {
+ int y;
+ qboolean teamArena = qfalse;
+ int style = UI_CENTER | UI_DROPSHADOW;
+
+ trap_Cvar_Set( "sv_killserver", "1" );
+ trap_Cvar_SetValue( "handicap", 100 ); //Reset handicap during server change, it must be ser per game
+
+ memset( &s_main, 0 ,sizeof(mainmenu_t) );
+ memset( &s_errorMessage, 0 ,sizeof(errorMessage_t) );
+
+ // com_errorMessage would need that too
+ MainMenu_Cache();
+
+ trap_Cvar_VariableStringBuffer( "com_errorMessage", s_errorMessage.errorMessage, sizeof(s_errorMessage.errorMessage) );
+ if (strlen(s_errorMessage.errorMessage))
+ {
+ s_errorMessage.menu.draw = Main_MenuDraw;
+ s_errorMessage.menu.key = ErrorMessage_Key;
+ s_errorMessage.menu.fullscreen = qtrue;
+ s_errorMessage.menu.wrapAround = qtrue;
+ s_errorMessage.menu.showlogo = qtrue;
+
+ trap_Key_SetCatcher( KEYCATCH_UI );
+ uis.menusp = 0;
+ UI_PushMenu ( &s_errorMessage.menu );
+
+ return;
+ }
+
+ s_main.menu.draw = Main_MenuDraw;
+ s_main.menu.fullscreen = qtrue;
+ s_main.menu.wrapAround = qtrue;
+ s_main.menu.showlogo = qtrue;
+
+ y = 134;
+ s_main.singleplayer.generic.type = MTYPE_PTEXT;
+ s_main.singleplayer.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_main.singleplayer.generic.x = 320;
+ s_main.singleplayer.generic.y = y;
+ s_main.singleplayer.generic.id = ID_SINGLEPLAYER;
+ s_main.singleplayer.generic.callback = Main_MenuEvent;
+ s_main.singleplayer.string = "SINGLE PLAYER";
+ s_main.singleplayer.color = color_red;
+ s_main.singleplayer.style = style;
+
+ y += MAIN_MENU_VERTICAL_SPACING;
+ s_main.multiplayer.generic.type = MTYPE_PTEXT;
+ s_main.multiplayer.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_main.multiplayer.generic.x = 320;
+ s_main.multiplayer.generic.y = y;
+ s_main.multiplayer.generic.id = ID_MULTIPLAYER;
+ s_main.multiplayer.generic.callback = Main_MenuEvent;
+ s_main.multiplayer.string = "MULTIPLAYER";
+ s_main.multiplayer.color = color_red;
+ s_main.multiplayer.style = style;
+
+ y += MAIN_MENU_VERTICAL_SPACING;
+ s_main.setup.generic.type = MTYPE_PTEXT;
+ s_main.setup.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_main.setup.generic.x = 320;
+ s_main.setup.generic.y = y;
+ s_main.setup.generic.id = ID_SETUP;
+ s_main.setup.generic.callback = Main_MenuEvent;
+ s_main.setup.string = "SETUP";
+ s_main.setup.color = color_red;
+ s_main.setup.style = style;
+
+ y += MAIN_MENU_VERTICAL_SPACING;
+ s_main.demos.generic.type = MTYPE_PTEXT;
+ s_main.demos.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_main.demos.generic.x = 320;
+ s_main.demos.generic.y = y;
+ s_main.demos.generic.id = ID_DEMOS;
+ s_main.demos.generic.callback = Main_MenuEvent;
+ s_main.demos.string = "DEMOS";
+ s_main.demos.color = color_red;
+ s_main.demos.style = style;
+
+ /*y += MAIN_MENU_VERTICAL_SPACING;
+ s_main.cinematics.generic.type = MTYPE_PTEXT;
+ s_main.cinematics.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_main.cinematics.generic.x = 320;
+ s_main.cinematics.generic.y = y;
+ s_main.cinematics.generic.id = ID_CINEMATICS;
+ s_main.cinematics.generic.callback = Main_MenuEvent;
+ s_main.cinematics.string = "CINEMATICS";
+ s_main.cinematics.color = color_red;
+ s_main.cinematics.style = style;*/
+
+ y += MAIN_MENU_VERTICAL_SPACING;
+ s_main.challenges.generic.type = MTYPE_PTEXT;
+ s_main.challenges.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_main.challenges.generic.x = 320;
+ s_main.challenges.generic.y = y;
+ s_main.challenges.generic.id = ID_CHALLENGES;
+ s_main.challenges.generic.callback = Main_MenuEvent;
+ s_main.challenges.string = "STATISTICS";
+ s_main.challenges.color = color_red;
+ s_main.challenges.style = style;
+
+ if (UI_TeamArenaExists()) {
+ teamArena = qtrue;
+ y += MAIN_MENU_VERTICAL_SPACING;
+ s_main.teamArena.generic.type = MTYPE_PTEXT;
+ s_main.teamArena.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_main.teamArena.generic.x = 320;
+ s_main.teamArena.generic.y = y;
+ s_main.teamArena.generic.id = ID_TEAMARENA;
+ s_main.teamArena.generic.callback = Main_MenuEvent;
+ s_main.teamArena.string = "MISSION PACK";
+ s_main.teamArena.color = color_red;
+ s_main.teamArena.style = style;
+ }
+
+ y += MAIN_MENU_VERTICAL_SPACING;
+ s_main.mods.generic.type = MTYPE_PTEXT;
+ s_main.mods.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_main.mods.generic.x = 320;
+ s_main.mods.generic.y = y;
+ s_main.mods.generic.id = ID_MODS;
+ s_main.mods.generic.callback = Main_MenuEvent;
+ s_main.mods.string = "MODS";
+ s_main.mods.color = color_red;
+ s_main.mods.style = style;
+
+ y += MAIN_MENU_VERTICAL_SPACING;
+ s_main.exit.generic.type = MTYPE_PTEXT;
+ s_main.exit.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_main.exit.generic.x = 320;
+ s_main.exit.generic.y = y;
+ s_main.exit.generic.id = ID_EXIT;
+ s_main.exit.generic.callback = Main_MenuEvent;
+ s_main.exit.string = "EXIT";
+ s_main.exit.color = color_red;
+ s_main.exit.style = style;
+
+ Menu_AddItem( &s_main.menu, &s_main.singleplayer );
+ Menu_AddItem( &s_main.menu, &s_main.multiplayer );
+ Menu_AddItem( &s_main.menu, &s_main.setup );
+ Menu_AddItem( &s_main.menu, &s_main.demos );
+ //Menu_AddItem( &s_main.menu, &s_main.cinematics );
+ Menu_AddItem( &s_main.menu, &s_main.challenges );
+ if (teamArena) {
+ Menu_AddItem( &s_main.menu, &s_main.teamArena );
+ }
+ Menu_AddItem( &s_main.menu, &s_main.mods );
+ Menu_AddItem( &s_main.menu, &s_main.exit );
+
+ trap_Key_SetCatcher( KEYCATCH_UI );
+ uis.menusp = 0;
+ UI_PushMenu ( &s_main.menu );
+
+}
diff --git a/game/code/q3_ui/ui_mfield.c b/code/q3_ui/ui_mfield.c
similarity index 100%
rename from game/code/q3_ui/ui_mfield.c
rename to code/q3_ui/ui_mfield.c
diff --git a/game/code/q3_ui/ui_mods.c b/code/q3_ui/ui_mods.c
similarity index 100%
rename from game/code/q3_ui/ui_mods.c
rename to code/q3_ui/ui_mods.c
diff --git a/game/code/q3_ui/ui_network.c b/code/q3_ui/ui_network.c
similarity index 100%
rename from game/code/q3_ui/ui_network.c
rename to code/q3_ui/ui_network.c
diff --git a/game/code/q3_ui/ui_options.c b/code/q3_ui/ui_options.c
similarity index 100%
rename from game/code/q3_ui/ui_options.c
rename to code/q3_ui/ui_options.c
diff --git a/game/code/q3_ui/ui_password.c b/code/q3_ui/ui_password.c
similarity index 100%
rename from game/code/q3_ui/ui_password.c
rename to code/q3_ui/ui_password.c
diff --git a/code/q3_ui/ui_playermodel.c b/code/q3_ui/ui_playermodel.c
new file mode 100644
index 0000000..04e2596
--- /dev/null
+++ b/code/q3_ui/ui_playermodel.c
@@ -0,0 +1,736 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#include "ui_local.h"
+
+#define MODEL_BACK0 "menu/art_blueish/back_0"
+#define MODEL_BACK1 "menu/art_blueish/back_1"
+#define MODEL_SELECT "menu/art/opponents_select"
+#define MODEL_SELECTED "menu/art/opponents_selected"
+#define MODEL_FRAMEL "menu/art_blueish/frame1_l"
+#define MODEL_FRAMER "menu/art_blueish/frame1_r"
+#define MODEL_PORTS "menu/art_blueish/player_models_ports"
+#define MODEL_ARROWS "menu/art_blueish/gs_arrows_0"
+#define MODEL_ARROWSL "menu/art_blueish/gs_arrows_l"
+#define MODEL_ARROWSR "menu/art_blueish/gs_arrows_r"
+
+#define LOW_MEMORY (5 * 1024 * 1024)
+
+static char* playermodel_artlist[] =
+{
+ MODEL_BACK0,
+ MODEL_BACK1,
+ MODEL_SELECT,
+ MODEL_SELECTED,
+ MODEL_FRAMEL,
+ MODEL_FRAMER,
+ MODEL_PORTS,
+ MODEL_ARROWS,
+ MODEL_ARROWSL,
+ MODEL_ARROWSR,
+ NULL
+};
+
+#define PLAYERGRID_COLS 4
+#define PLAYERGRID_ROWS 4
+#define MAX_MODELSPERPAGE (PLAYERGRID_ROWS*PLAYERGRID_COLS)
+
+#define MAX_PLAYERMODELS 256
+
+#define ID_PLAYERPIC0 0
+#define ID_PLAYERPIC1 1
+#define ID_PLAYERPIC2 2
+#define ID_PLAYERPIC3 3
+#define ID_PLAYERPIC4 4
+#define ID_PLAYERPIC5 5
+#define ID_PLAYERPIC6 6
+#define ID_PLAYERPIC7 7
+#define ID_PLAYERPIC8 8
+#define ID_PLAYERPIC9 9
+#define ID_PLAYERPIC10 10
+#define ID_PLAYERPIC11 11
+#define ID_PLAYERPIC12 12
+#define ID_PLAYERPIC13 13
+#define ID_PLAYERPIC14 14
+#define ID_PLAYERPIC15 15
+#define ID_PREVPAGE 100
+#define ID_NEXTPAGE 101
+#define ID_BACK 102
+
+typedef struct
+{
+ menuframework_s menu;
+ menubitmap_s pics[MAX_MODELSPERPAGE];
+ menubitmap_s picbuttons[MAX_MODELSPERPAGE];
+ menubitmap_s framel;
+ menubitmap_s framer;
+ menubitmap_s ports;
+ menutext_s banner;
+ menubitmap_s back;
+ menubitmap_s player;
+ menubitmap_s arrows;
+ menubitmap_s left;
+ menubitmap_s right;
+ menutext_s modelname;
+ menutext_s skinname;
+ menutext_s playername;
+ playerInfo_t playerinfo;
+ int nummodels;
+ char modelnames[MAX_PLAYERMODELS][128];
+ int modelpage;
+ int numpages;
+ char modelskin[64];
+ int selectedmodel;
+} playermodel_t;
+
+static playermodel_t s_playermodel;
+
+/*
+=================
+PlayerModel_UpdateGrid
+=================
+*/
+static void PlayerModel_UpdateGrid( void )
+{
+ int i;
+ int j;
+
+ j = s_playermodel.modelpage * MAX_MODELSPERPAGE;
+ for (i=0; i<PLAYERGRID_ROWS*PLAYERGRID_COLS; i++,j++)
+ {
+ if (j < s_playermodel.nummodels)
+ {
+ // model/skin portrait
+ s_playermodel.pics[i].generic.name = s_playermodel.modelnames[j];
+ s_playermodel.picbuttons[i].generic.flags &= ~QMF_INACTIVE;
+ }
+ else
+ {
+ // dead slot
+ s_playermodel.pics[i].generic.name = NULL;
+ s_playermodel.picbuttons[i].generic.flags |= QMF_INACTIVE;
+ }
+
+ s_playermodel.pics[i].generic.flags &= ~QMF_HIGHLIGHT;
+ s_playermodel.pics[i].shader = 0;
+ s_playermodel.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
+ }
+
+ if (s_playermodel.selectedmodel/MAX_MODELSPERPAGE == s_playermodel.modelpage)
+ {
+ // set selected model
+ i = s_playermodel.selectedmodel % MAX_MODELSPERPAGE;
+
+ s_playermodel.pics[i].generic.flags |= QMF_HIGHLIGHT;
+ s_playermodel.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
+ }
+
+ if (s_playermodel.numpages > 1)
+ {
+ if (s_playermodel.modelpage > 0)
+ s_playermodel.left.generic.flags &= ~QMF_INACTIVE;
+ else
+ s_playermodel.left.generic.flags |= QMF_INACTIVE;
+
+ if (s_playermodel.modelpage < s_playermodel.numpages-1)
+ s_playermodel.right.generic.flags &= ~QMF_INACTIVE;
+ else
+ s_playermodel.right.generic.flags |= QMF_INACTIVE;
+ }
+ else
+ {
+ // hide left/right markers
+ s_playermodel.left.generic.flags |= QMF_INACTIVE;
+ s_playermodel.right.generic.flags |= QMF_INACTIVE;
+ }
+}
+
+/*
+=================
+PlayerModel_UpdateModel
+=================
+*/
+static void PlayerModel_UpdateModel( void )
+{
+ vec3_t viewangles;
+ vec3_t moveangles;
+
+ memset( &s_playermodel.playerinfo, 0, sizeof(playerInfo_t) );
+
+ viewangles[YAW] = 180 - 30;
+ viewangles[PITCH] = 0;
+ viewangles[ROLL] = 0;
+ VectorClear( moveangles );
+
+ UI_PlayerInfo_SetModel( &s_playermodel.playerinfo, s_playermodel.modelskin );
+ UI_PlayerInfo_SetInfo( &s_playermodel.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, moveangles, WP_MACHINEGUN, qfalse );
+}
+
+/*
+=================
+PlayerModel_SaveChanges
+=================
+*/
+static void PlayerModel_SaveChanges( void )
+{
+ trap_Cvar_Set( "model", s_playermodel.modelskin );
+ trap_Cvar_Set( "headmodel", s_playermodel.modelskin );
+ trap_Cvar_Set( "team_model", s_playermodel.modelskin );
+ trap_Cvar_Set( "team_headmodel", s_playermodel.modelskin );
+}
+
+/*
+=================
+PlayerModel_MenuEvent
+=================
+*/
+static void PlayerModel_MenuEvent( void* ptr, int event )
+{
+ if (event != QM_ACTIVATED)
+ return;
+
+ switch (((menucommon_s*)ptr)->id)
+ {
+ case ID_PREVPAGE:
+ if (s_playermodel.modelpage > 0)
+ {
+ s_playermodel.modelpage--;
+ PlayerModel_UpdateGrid();
+ }
+ break;
+
+ case ID_NEXTPAGE:
+ if (s_playermodel.modelpage < s_playermodel.numpages-1)
+ {
+ s_playermodel.modelpage++;
+ PlayerModel_UpdateGrid();
+ }
+ break;
+
+ case ID_BACK:
+ PlayerModel_SaveChanges();
+ UI_PopMenu();
+ break;
+ }
+}
+
+/*
+=================
+PlayerModel_MenuKey
+=================
+*/
+static sfxHandle_t PlayerModel_MenuKey( int key )
+{
+ menucommon_s* m;
+ int picnum;
+
+ switch (key)
+ {
+ case K_KP_LEFTARROW:
+ case K_LEFTARROW:
+ m = Menu_ItemAtCursor(&s_playermodel.menu);
+ picnum = m->id - ID_PLAYERPIC0;
+ if (picnum >= 0 && picnum <= 15)
+ {
+ if (picnum > 0)
+ {
+ Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor-1);
+ return (menu_move_sound);
+
+ }
+ else if (s_playermodel.modelpage > 0)
+ {
+ s_playermodel.modelpage--;
+ Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor+15);
+ PlayerModel_UpdateGrid();
+ return (menu_move_sound);
+ }
+ else
+ return (menu_buzz_sound);
+ }
+ break;
+
+ case K_KP_RIGHTARROW:
+ case K_RIGHTARROW:
+ m = Menu_ItemAtCursor(&s_playermodel.menu);
+ picnum = m->id - ID_PLAYERPIC0;
+ if (picnum >= 0 && picnum <= 15)
+ {
+ if ((picnum < 15) && (s_playermodel.modelpage*MAX_MODELSPERPAGE + picnum+1 < s_playermodel.nummodels))
+ {
+ Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor+1);
+ return (menu_move_sound);
+ }
+ else if ((picnum == 15) && (s_playermodel.modelpage < s_playermodel.numpages-1))
+ {
+ s_playermodel.modelpage++;
+ Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor-15);
+ PlayerModel_UpdateGrid();
+ return (menu_move_sound);
+ }
+ else
+ return (menu_buzz_sound);
+ }
+ break;
+
+ case K_MOUSE2:
+ case K_ESCAPE:
+ PlayerModel_SaveChanges();
+ break;
+ }
+
+ return ( Menu_DefaultKey( &s_playermodel.menu, key ) );
+}
+
+/*
+=================
+PlayerModel_PicEvent
+=================
+*/
+static void PlayerModel_PicEvent( void* ptr, int event )
+{
+ int modelnum;
+ int maxlen;
+ char* buffptr;
+ char* pdest;
+ int i;
+
+ if (event != QM_ACTIVATED)
+ return;
+
+ for (i=0; i<PLAYERGRID_ROWS*PLAYERGRID_COLS; i++)
+ {
+ // reset
+ s_playermodel.pics[i].generic.flags &= ~QMF_HIGHLIGHT;
+ s_playermodel.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
+ }
+
+ // set selected
+ i = ((menucommon_s*)ptr)->id - ID_PLAYERPIC0;
+ s_playermodel.pics[i].generic.flags |= QMF_HIGHLIGHT;
+ s_playermodel.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
+
+ // get model and strip icon_
+ modelnum = s_playermodel.modelpage*MAX_MODELSPERPAGE + i;
+ buffptr = s_playermodel.modelnames[modelnum] + strlen("models/players/");
+ pdest = strstr(buffptr,"icon_");
+ if (pdest)
+ {
+ // track the whole model/skin name
+ Q_strncpyz(s_playermodel.modelskin,buffptr,pdest-buffptr+1);
+ strcat(s_playermodel.modelskin,pdest + 5);
+
+ // seperate the model name
+ maxlen = pdest-buffptr;
+ if (maxlen > 16)
+ maxlen = 16;
+ Q_strncpyz( s_playermodel.modelname.string, buffptr, maxlen );
+ Q_strupr( s_playermodel.modelname.string );
+
+ // seperate the skin name
+ maxlen = strlen(pdest+5)+1;
+ if (maxlen > 16)
+ maxlen = 16;
+ Q_strncpyz( s_playermodel.skinname.string, pdest+5, maxlen );
+ Q_strupr( s_playermodel.skinname.string );
+
+ s_playermodel.selectedmodel = modelnum;
+
+ if( trap_MemoryRemaining() > LOW_MEMORY ) {
+ PlayerModel_UpdateModel();
+ }
+ }
+}
+
+/*
+=================
+PlayerModel_DrawPlayer
+=================
+*/
+static void PlayerModel_DrawPlayer( void *self )
+{
+ menubitmap_s* b;
+
+ b = (menubitmap_s*) self;
+
+ if( trap_MemoryRemaining() <= LOW_MEMORY ) {
+ UI_DrawProportionalString( b->generic.x, b->generic.y + b->height / 2, "LOW MEMORY", UI_LEFT, color_red );
+ return;
+ }
+
+ UI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_playermodel.playerinfo, uis.realtime/2 );
+}
+
+/*
+=================
+PlayerModel_BuildList
+=================
+*/
+static void PlayerModel_BuildList( void )
+{
+ int numdirs;
+ int numfiles;
+ char dirlist[2048];
+ char filelist[2048];
+ char skinname[MAX_QPATH];
+ char* dirptr;
+ char* fileptr;
+ int i;
+ int j;
+ int dirlen;
+ int filelen;
+ qboolean precache;
+
+ precache = trap_Cvar_VariableValue("com_buildscript");
+
+ s_playermodel.modelpage = 0;
+ s_playermodel.nummodels = 0;
+
+ // iterate directory of all player models
+ numdirs = trap_FS_GetFileList("models/players", "/", dirlist, 2048 );
+ dirptr = dirlist;
+ for (i=0; i<numdirs && s_playermodel.nummodels < MAX_PLAYERMODELS; i++,dirptr+=dirlen+1)
+ {
+ dirlen = strlen(dirptr);
+
+ if (dirlen && dirptr[dirlen-1]=='/') dirptr[dirlen-1]='\0';
+
+ if (!strcmp(dirptr,".") || !strcmp(dirptr,".."))
+ continue;
+
+ // iterate all skin files in directory
+ numfiles = trap_FS_GetFileList( va("models/players/%s",dirptr), "tga", filelist, 2048 );
+ fileptr = filelist;
+ for (j=0; j<numfiles && s_playermodel.nummodels < MAX_PLAYERMODELS;j++,fileptr+=filelen+1)
+ {
+ filelen = strlen(fileptr);
+
+ COM_StripExtension(fileptr,skinname, sizeof(skinname));
+
+ // look for icon_????
+ if (!Q_stricmpn(skinname,"icon_",5))
+ {
+ Com_sprintf( s_playermodel.modelnames[s_playermodel.nummodels++],
+ sizeof( s_playermodel.modelnames[s_playermodel.nummodels] ),
+ "models/players/%s/%s", dirptr, skinname );
+ //if (s_playermodel.nummodels >= MAX_PLAYERMODELS)
+ // return;
+ }
+
+ if( precache ) {
+ trap_S_RegisterSound( va( "sound/player/announce/%s_wins.wav", skinname), qfalse );
+ }
+ }
+ }
+
+ //APSFIXME - Degenerate no models case
+
+ s_playermodel.numpages = s_playermodel.nummodels/MAX_MODELSPERPAGE;
+ if (s_playermodel.nummodels % MAX_MODELSPERPAGE)
+ s_playermodel.numpages++;
+}
+
+/*
+=================
+PlayerModel_SetMenuItems
+=================
+*/
+static void PlayerModel_SetMenuItems( void )
+{
+ int i;
+ int maxlen;
+ char modelskin[64];
+ char* buffptr;
+ char* pdest;
+
+ // name
+ trap_Cvar_VariableStringBuffer( "name", s_playermodel.playername.string, 16 );
+ Q_CleanStr( s_playermodel.playername.string );
+
+ // model
+ trap_Cvar_VariableStringBuffer( "model", s_playermodel.modelskin, 64 );
+
+ // use default skin if none is set
+ if (!strchr(s_playermodel.modelskin, '/')) {
+ Q_strcat(s_playermodel.modelskin, 64, "/default");
+ }
+
+ // find model in our list
+ for (i=0; i<s_playermodel.nummodels; i++)
+ {
+ // strip icon_
+ buffptr = s_playermodel.modelnames[i] + strlen("models/players/");
+ pdest = strstr(buffptr,"icon_");
+ if (pdest)
+ {
+ Q_strncpyz(modelskin,buffptr,pdest-buffptr+1);
+ strcat(modelskin,pdest + 5);
+ }
+ else
+ continue;
+
+ if (!Q_stricmp( s_playermodel.modelskin, modelskin ))
+ {
+ // found pic, set selection here
+ s_playermodel.selectedmodel = i;
+ s_playermodel.modelpage = i/MAX_MODELSPERPAGE;
+
+ // seperate the model name
+ maxlen = pdest-buffptr;
+ if (maxlen > 16)
+ maxlen = 16;
+ Q_strncpyz( s_playermodel.modelname.string, buffptr, maxlen );
+ Q_strupr( s_playermodel.modelname.string );
+
+ // seperate the skin name
+ maxlen = strlen(pdest+5)+1;
+ if (maxlen > 16)
+ maxlen = 16;
+ Q_strncpyz( s_playermodel.skinname.string, pdest+5, maxlen );
+ Q_strupr( s_playermodel.skinname.string );
+ break;
+ }
+ }
+}
+
+/*
+=================
+PlayerModel_MenuInit
+=================
+*/
+static void PlayerModel_MenuInit( void )
+{
+ int i;
+ int j;
+ int k;
+ int x;
+ int y;
+ static char playername[32];
+ static char modelname[32];
+ static char skinname[32];
+
+ // zero set all our globals
+ memset( &s_playermodel, 0 ,sizeof(playermodel_t) );
+
+ PlayerModel_Cache();
+
+ s_playermodel.menu.key = PlayerModel_MenuKey;
+ s_playermodel.menu.wrapAround = qtrue;
+ s_playermodel.menu.fullscreen = qtrue;
+
+ s_playermodel.banner.generic.type = MTYPE_BTEXT;
+ s_playermodel.banner.generic.x = 320;
+ s_playermodel.banner.generic.y = 16;
+ s_playermodel.banner.string = "PLAYER MODEL";
+ s_playermodel.banner.color = color_white;
+ s_playermodel.banner.style = UI_CENTER;
+
+ s_playermodel.framel.generic.type = MTYPE_BITMAP;
+ s_playermodel.framel.generic.name = MODEL_FRAMEL;
+ s_playermodel.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
+ s_playermodel.framel.generic.x = 0;
+ s_playermodel.framel.generic.y = 78;
+ s_playermodel.framel.width = 256;
+ s_playermodel.framel.height = 329;
+
+ s_playermodel.framer.generic.type = MTYPE_BITMAP;
+ s_playermodel.framer.generic.name = MODEL_FRAMER;
+ s_playermodel.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
+ s_playermodel.framer.generic.x = 376;
+ s_playermodel.framer.generic.y = 76;
+ s_playermodel.framer.width = 256;
+ s_playermodel.framer.height = 334;
+
+ s_playermodel.ports.generic.type = MTYPE_BITMAP;
+ s_playermodel.ports.generic.name = MODEL_PORTS;
+ s_playermodel.ports.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
+ s_playermodel.ports.generic.x = 50;
+ s_playermodel.ports.generic.y = 59;
+ s_playermodel.ports.width = 274;
+ s_playermodel.ports.height = 274;
+
+ y = 59;
+ for (i=0,k=0; i<PLAYERGRID_ROWS; i++)
+ {
+ x = 50;
+ for (j=0; j<PLAYERGRID_COLS; j++,k++)
+ {
+ s_playermodel.pics[k].generic.type = MTYPE_BITMAP;
+ s_playermodel.pics[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
+ s_playermodel.pics[k].generic.x = x;
+ s_playermodel.pics[k].generic.y = y;
+ s_playermodel.pics[k].width = 64;
+ s_playermodel.pics[k].height = 64;
+ s_playermodel.pics[k].focuspic = MODEL_SELECTED;
+ s_playermodel.pics[k].focuscolor = colorRed;
+
+ s_playermodel.picbuttons[k].generic.type = MTYPE_BITMAP;
+ s_playermodel.picbuttons[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS;
+ s_playermodel.picbuttons[k].generic.id = ID_PLAYERPIC0+k;
+ s_playermodel.picbuttons[k].generic.callback = PlayerModel_PicEvent;
+ s_playermodel.picbuttons[k].generic.x = x - 16;
+ s_playermodel.picbuttons[k].generic.y = y - 16;
+ s_playermodel.picbuttons[k].generic.left = x;
+ s_playermodel.picbuttons[k].generic.top = y;
+ s_playermodel.picbuttons[k].generic.right = x + 64;
+ s_playermodel.picbuttons[k].generic.bottom = y + 64;
+ s_playermodel.picbuttons[k].width = 128;
+ s_playermodel.picbuttons[k].height = 128;
+ s_playermodel.picbuttons[k].focuspic = MODEL_SELECT;
+ s_playermodel.picbuttons[k].focuscolor = colorRed;
+
+ x += 64+6;
+ }
+ y += 64+6;
+ }
+
+ s_playermodel.playername.generic.type = MTYPE_PTEXT;
+ s_playermodel.playername.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
+ s_playermodel.playername.generic.x = 320;
+ s_playermodel.playername.generic.y = 440;
+ s_playermodel.playername.string = playername;
+ s_playermodel.playername.style = UI_CENTER;
+ s_playermodel.playername.color = text_color_normal;
+
+ s_playermodel.modelname.generic.type = MTYPE_PTEXT;
+ s_playermodel.modelname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
+ s_playermodel.modelname.generic.x = 497;
+ s_playermodel.modelname.generic.y = 54;
+ s_playermodel.modelname.string = modelname;
+ s_playermodel.modelname.style = UI_CENTER;
+ s_playermodel.modelname.color = text_color_normal;
+
+ s_playermodel.skinname.generic.type = MTYPE_PTEXT;
+ s_playermodel.skinname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
+ s_playermodel.skinname.generic.x = 497;
+ s_playermodel.skinname.generic.y = 394;
+ s_playermodel.skinname.string = skinname;
+ s_playermodel.skinname.style = UI_CENTER;
+ s_playermodel.skinname.color = text_color_normal;
+
+ s_playermodel.player.generic.type = MTYPE_BITMAP;
+ s_playermodel.player.generic.flags = QMF_INACTIVE;
+ s_playermodel.player.generic.ownerdraw = PlayerModel_DrawPlayer;
+ s_playermodel.player.generic.x = 400;
+ s_playermodel.player.generic.y = -40;
+ s_playermodel.player.width = 32*10;
+ s_playermodel.player.height = 56*10;
+
+ s_playermodel.arrows.generic.type = MTYPE_BITMAP;
+ s_playermodel.arrows.generic.name = MODEL_ARROWS;
+ s_playermodel.arrows.generic.flags = QMF_INACTIVE;
+ s_playermodel.arrows.generic.x = 125;
+ s_playermodel.arrows.generic.y = 340;
+ s_playermodel.arrows.width = 128;
+ s_playermodel.arrows.height = 32;
+
+ s_playermodel.left.generic.type = MTYPE_BITMAP;
+ s_playermodel.left.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_playermodel.left.generic.callback = PlayerModel_MenuEvent;
+ s_playermodel.left.generic.id = ID_PREVPAGE;
+ s_playermodel.left.generic.x = 125;
+ s_playermodel.left.generic.y = 340;
+ s_playermodel.left.width = 64;
+ s_playermodel.left.height = 32;
+ s_playermodel.left.focuspic = MODEL_ARROWSL;
+
+ s_playermodel.right.generic.type = MTYPE_BITMAP;
+ s_playermodel.right.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_playermodel.right.generic.callback = PlayerModel_MenuEvent;
+ s_playermodel.right.generic.id = ID_NEXTPAGE;
+ s_playermodel.right.generic.x = 125+61;
+ s_playermodel.right.generic.y = 340;
+ s_playermodel.right.width = 64;
+ s_playermodel.right.height = 32;
+ s_playermodel.right.focuspic = MODEL_ARROWSR;
+
+ s_playermodel.back.generic.type = MTYPE_BITMAP;
+ s_playermodel.back.generic.name = MODEL_BACK0;
+ s_playermodel.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_playermodel.back.generic.callback = PlayerModel_MenuEvent;
+ s_playermodel.back.generic.id = ID_BACK;
+ s_playermodel.back.generic.x = 0;
+ s_playermodel.back.generic.y = 480-64;
+ s_playermodel.back.width = 128;
+ s_playermodel.back.height = 64;
+ s_playermodel.back.focuspic = MODEL_BACK1;
+
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.banner );
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.framel );
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.framer );
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.ports );
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.playername );
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.modelname );
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.skinname );
+
+ for (i=0; i<MAX_MODELSPERPAGE; i++)
+ {
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.pics[i] );
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.picbuttons[i] );
+ }
+
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.player );
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.arrows );
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.left );
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.right );
+ Menu_AddItem( &s_playermodel.menu, &s_playermodel.back );
+
+ // find all available models
+// PlayerModel_BuildList();
+
+ // set initial states
+ PlayerModel_SetMenuItems();
+
+ // update user interface
+ PlayerModel_UpdateGrid();
+ PlayerModel_UpdateModel();
+}
+
+/*
+=================
+PlayerModel_Cache
+=================
+*/
+void PlayerModel_Cache( void )
+{
+ int i;
+
+ for( i = 0; playermodel_artlist[i]; i++ ) {
+ trap_R_RegisterShaderNoMip( playermodel_artlist[i] );
+ }
+
+ PlayerModel_BuildList();
+ for( i = 0; i < s_playermodel.nummodels; i++ ) {
+ trap_R_RegisterShaderNoMip( s_playermodel.modelnames[i] );
+ }
+}
+
+void UI_PlayerModelMenu(void)
+{
+ PlayerModel_MenuInit();
+
+ UI_PushMenu( &s_playermodel.menu );
+
+ Menu_SetCursorToItem( &s_playermodel.menu, &s_playermodel.pics[s_playermodel.selectedmodel % MAX_MODELSPERPAGE] );
+}
+
+
diff --git a/code/q3_ui/ui_players.c b/code/q3_ui/ui_players.c
new file mode 100644
index 0000000..4a96d82
--- /dev/null
+++ b/code/q3_ui/ui_players.c
@@ -0,0 +1,1249 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// ui_players.c
+
+#include "ui_local.h"
+
+
+#define UI_TIMER_GESTURE 2300
+#define UI_TIMER_JUMP 1000
+#define UI_TIMER_LAND 130
+#define UI_TIMER_WEAPON_SWITCH 300
+#define UI_TIMER_ATTACK 500
+#define UI_TIMER_MUZZLE_FLASH 20
+#define UI_TIMER_WEAPON_DELAY 250
+
+#define JUMP_HEIGHT 56
+
+#define SWINGSPEED 0.3f
+
+#define SPIN_SPEED 0.9f
+#define COAST_TIME 1000
+
+
+static int dp_realtime;
+static float jumpHeight;
+
+
+/*
+===============
+UI_PlayerInfo_SetWeapon
+===============
+*/
+static void UI_PlayerInfo_SetWeapon( playerInfo_t *pi, weapon_t weaponNum ) {
+ gitem_t * item;
+ char path[MAX_QPATH];
+
+ pi->currentWeapon = weaponNum;
+tryagain:
+ pi->realWeapon = weaponNum;
+ pi->weaponModel = 0;
+ pi->barrelModel = 0;
+ pi->flashModel = 0;
+
+ if ( weaponNum == WP_NONE ) {
+ return;
+ }
+
+ for ( item = bg_itemlist + 1; item->classname ; item++ ) {
+ if ( item->giType != IT_WEAPON ) {
+ continue;
+ }
+ if ( item->giTag == weaponNum ) {
+ break;
+ }
+ }
+
+ if ( item->classname ) {
+ pi->weaponModel = trap_R_RegisterModel( item->world_model[0] );
+ }
+
+ if( pi->weaponModel == 0 ) {
+ if( weaponNum == WP_MACHINEGUN ) {
+ weaponNum = WP_NONE;
+ goto tryagain;
+ }
+ weaponNum = WP_MACHINEGUN;
+ goto tryagain;
+ }
+
+ if ( weaponNum == WP_MACHINEGUN || weaponNum == WP_GAUNTLET || weaponNum == WP_BFG ) {
+ strcpy( path, item->world_model[0] );
+ COM_StripExtension( path, path, sizeof(path) );
+ strcat( path, "_barrel.md3" );
+ pi->barrelModel = trap_R_RegisterModel( path );
+ }
+
+ strcpy( path, item->world_model[0] );
+ COM_StripExtension( path, path, sizeof(path) );
+ strcat( path, "_flash.md3" );
+ pi->flashModel = trap_R_RegisterModel( path );
+
+ switch( weaponNum ) {
+ case WP_GAUNTLET:
+ MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
+ break;
+
+ case WP_MACHINEGUN:
+ MAKERGB( pi->flashDlightColor, 1, 1, 0 );
+ break;
+
+ case WP_SHOTGUN:
+ MAKERGB( pi->flashDlightColor, 1, 1, 0 );
+ break;
+
+ case WP_GRENADE_LAUNCHER:
+ MAKERGB( pi->flashDlightColor, 1, 0.7f, 0.5f );
+ break;
+
+ case WP_ROCKET_LAUNCHER:
+ MAKERGB( pi->flashDlightColor, 1, 0.75f, 0 );
+ break;
+
+ case WP_LIGHTNING:
+ MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
+ break;
+
+ case WP_RAILGUN:
+ MAKERGB( pi->flashDlightColor, 1, 0.5f, 0 );
+ break;
+
+ case WP_PLASMAGUN:
+ MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
+ break;
+
+ case WP_BFG:
+ MAKERGB( pi->flashDlightColor, 1, 0.7f, 1 );
+ break;
+
+ case WP_GRAPPLING_HOOK:
+ MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
+ break;
+
+ default:
+ MAKERGB( pi->flashDlightColor, 1, 1, 1 );
+ break;
+ }
+}
+
+
+/*
+===============
+UI_ForceLegsAnim
+===============
+*/
+static void UI_ForceLegsAnim( playerInfo_t *pi, int anim ) {
+ pi->legsAnim = ( ( pi->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
+
+ if ( anim == LEGS_JUMP ) {
+ pi->legsAnimationTimer = UI_TIMER_JUMP;
+ }
+}
+
+
+/*
+===============
+UI_SetLegsAnim
+===============
+*/
+static void UI_SetLegsAnim( playerInfo_t *pi, int anim ) {
+ if ( pi->pendingLegsAnim ) {
+ anim = pi->pendingLegsAnim;
+ pi->pendingLegsAnim = 0;
+ }
+ UI_ForceLegsAnim( pi, anim );
+}
+
+
+/*
+===============
+UI_ForceTorsoAnim
+===============
+*/
+static void UI_ForceTorsoAnim( playerInfo_t *pi, int anim ) {
+ pi->torsoAnim = ( ( pi->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
+
+ if ( anim == TORSO_GESTURE ) {
+ pi->torsoAnimationTimer = UI_TIMER_GESTURE;
+ }
+
+ if ( anim == TORSO_ATTACK || anim == TORSO_ATTACK2 ) {
+ pi->torsoAnimationTimer = UI_TIMER_ATTACK;
+ }
+}
+
+
+/*
+===============
+UI_SetTorsoAnim
+===============
+*/
+static void UI_SetTorsoAnim( playerInfo_t *pi, int anim ) {
+ if ( pi->pendingTorsoAnim ) {
+ anim = pi->pendingTorsoAnim;
+ pi->pendingTorsoAnim = 0;
+ }
+
+ UI_ForceTorsoAnim( pi, anim );
+}
+
+
+/*
+===============
+UI_TorsoSequencing
+===============
+*/
+static void UI_TorsoSequencing( playerInfo_t *pi ) {
+ int currentAnim;
+
+ currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
+
+ if ( pi->weapon != pi->currentWeapon ) {
+ if ( currentAnim != TORSO_DROP ) {
+ pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
+ UI_ForceTorsoAnim( pi, TORSO_DROP );
+ }
+ }
+
+ if ( pi->torsoAnimationTimer > 0 ) {
+ return;
+ }
+
+ if( currentAnim == TORSO_GESTURE ) {
+ UI_SetTorsoAnim( pi, TORSO_STAND );
+ return;
+ }
+
+ if( currentAnim == TORSO_ATTACK || currentAnim == TORSO_ATTACK2 ) {
+ UI_SetTorsoAnim( pi, TORSO_STAND );
+ return;
+ }
+
+ if ( currentAnim == TORSO_DROP ) {
+ UI_PlayerInfo_SetWeapon( pi, pi->weapon );
+ pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
+ UI_ForceTorsoAnim( pi, TORSO_RAISE );
+ return;
+ }
+
+ if ( currentAnim == TORSO_RAISE ) {
+ UI_SetTorsoAnim( pi, TORSO_STAND );
+ return;
+ }
+}
+
+
+/*
+===============
+UI_LegsSequencing
+===============
+*/
+static void UI_LegsSequencing( playerInfo_t *pi ) {
+ int currentAnim;
+
+ currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
+
+ if ( pi->legsAnimationTimer > 0 ) {
+ if ( currentAnim == LEGS_JUMP ) {
+ jumpHeight = JUMP_HEIGHT * sin( M_PI * ( UI_TIMER_JUMP - pi->legsAnimationTimer ) / UI_TIMER_JUMP );
+ }
+ return;
+ }
+
+ if ( currentAnim == LEGS_JUMP ) {
+ UI_ForceLegsAnim( pi, LEGS_LAND );
+ pi->legsAnimationTimer = UI_TIMER_LAND;
+ jumpHeight = 0;
+ return;
+ }
+
+ if ( currentAnim == LEGS_LAND ) {
+ UI_SetLegsAnim( pi, LEGS_IDLE );
+ return;
+ }
+}
+
+
+/*
+======================
+UI_PositionEntityOnTag
+======================
+*/
+static void UI_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
+ clipHandle_t parentModel, char *tagName ) {
+ int i;
+ orientation_t lerped;
+
+ // lerp the tag
+ trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
+ 1.0 - parent->backlerp, tagName );
+
+ // FIXME: allow origin offsets along tag?
+ VectorCopy( parent->origin, entity->origin );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
+ }
+
+ // cast away const because of compiler problems
+ MatrixMultiply( lerped.axis, ((refEntity_t*)parent)->axis, entity->axis );
+ entity->backlerp = parent->backlerp;
+}
+
+
+/*
+======================
+UI_PositionRotatedEntityOnTag
+======================
+*/
+static void UI_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
+ clipHandle_t parentModel, char *tagName ) {
+ int i;
+ orientation_t lerped;
+ vec3_t tempAxis[3];
+
+ // lerp the tag
+ trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
+ 1.0 - parent->backlerp, tagName );
+
+ // FIXME: allow origin offsets along tag?
+ VectorCopy( parent->origin, entity->origin );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
+ }
+
+ // cast away const because of compiler problems
+ MatrixMultiply( entity->axis, ((refEntity_t *)parent)->axis, tempAxis );
+ MatrixMultiply( lerped.axis, tempAxis, entity->axis );
+}
+
+
+/*
+===============
+UI_SetLerpFrameAnimation
+===============
+*/
+static void UI_SetLerpFrameAnimation( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
+ animation_t *anim;
+
+ lf->animationNumber = newAnimation;
+ newAnimation &= ~ANIM_TOGGLEBIT;
+
+ if ( newAnimation < 0 || newAnimation >= MAX_ANIMATIONS ) {
+ trap_Error( va("Bad animation number: %i", newAnimation) );
+ }
+
+ anim = &ci->animations[ newAnimation ];
+
+ lf->animation = anim;
+ lf->animationTime = lf->frameTime + anim->initialLerp;
+}
+
+
+/*
+===============
+UI_RunLerpFrame
+===============
+*/
+static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
+ int f;
+ animation_t *anim;
+
+ // see if the animation sequence is switching
+ if ( newAnimation != lf->animationNumber || !lf->animation ) {
+ UI_SetLerpFrameAnimation( ci, lf, newAnimation );
+ }
+
+ // if we have passed the current frame, move it to
+ // oldFrame and calculate a new frame
+ if ( dp_realtime >= lf->frameTime ) {
+ lf->oldFrame = lf->frame;
+ lf->oldFrameTime = lf->frameTime;
+
+ // get the next frame based on the animation
+ anim = lf->animation;
+ if ( dp_realtime < lf->animationTime ) {
+ lf->frameTime = lf->animationTime; // initial lerp
+ } else {
+ lf->frameTime = lf->oldFrameTime + anim->frameLerp;
+ }
+ f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
+ if ( f >= anim->numFrames ) {
+ f -= anim->numFrames;
+ if ( anim->loopFrames ) {
+ f %= anim->loopFrames;
+ f += anim->numFrames - anim->loopFrames;
+ } else {
+ f = anim->numFrames - 1;
+ // the animation is stuck at the end, so it
+ // can immediately transition to another sequence
+ lf->frameTime = dp_realtime;
+ }
+ }
+ lf->frame = anim->firstFrame + f;
+ if ( dp_realtime > lf->frameTime ) {
+ lf->frameTime = dp_realtime;
+ }
+ }
+
+ if ( lf->frameTime > dp_realtime + 200 ) {
+ lf->frameTime = dp_realtime;
+ }
+
+ if ( lf->oldFrameTime > dp_realtime ) {
+ lf->oldFrameTime = dp_realtime;
+ }
+ // calculate current lerp value
+ if ( lf->frameTime == lf->oldFrameTime ) {
+ lf->backlerp = 0;
+ } else {
+ lf->backlerp = 1.0 - (float)( dp_realtime - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
+ }
+}
+
+
+/*
+===============
+UI_PlayerAnimation
+===============
+*/
+static void UI_PlayerAnimation( playerInfo_t *pi, int *legsOld, int *legs, float *legsBackLerp,
+ int *torsoOld, int *torso, float *torsoBackLerp ) {
+
+ // legs animation
+ pi->legsAnimationTimer -= uis.frametime;
+ if ( pi->legsAnimationTimer < 0 ) {
+ pi->legsAnimationTimer = 0;
+ }
+
+ UI_LegsSequencing( pi );
+
+ if ( pi->legs.yawing && ( pi->legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {
+ UI_RunLerpFrame( pi, &pi->legs, LEGS_TURN );
+ } else {
+ UI_RunLerpFrame( pi, &pi->legs, pi->legsAnim );
+ }
+ *legsOld = pi->legs.oldFrame;
+ *legs = pi->legs.frame;
+ *legsBackLerp = pi->legs.backlerp;
+
+ // torso animation
+ pi->torsoAnimationTimer -= uis.frametime;
+ if ( pi->torsoAnimationTimer < 0 ) {
+ pi->torsoAnimationTimer = 0;
+ }
+
+ UI_TorsoSequencing( pi );
+
+ UI_RunLerpFrame( pi, &pi->torso, pi->torsoAnim );
+ *torsoOld = pi->torso.oldFrame;
+ *torso = pi->torso.frame;
+ *torsoBackLerp = pi->torso.backlerp;
+}
+
+
+/*
+==================
+UI_SwingAngles
+==================
+*/
+static void UI_SwingAngles( float destination, float swingTolerance, float clampTolerance,
+ float speed, float *angle, qboolean *swinging ) {
+ float swing;
+ float move;
+ float scale;
+
+ if ( !*swinging ) {
+ // see if a swing should be started
+ swing = AngleSubtract( *angle, destination );
+ if ( swing > swingTolerance || swing < -swingTolerance ) {
+ *swinging = qtrue;
+ }
+ }
+
+ if ( !*swinging ) {
+ return;
+ }
+
+ // modify the speed depending on the delta
+ // so it doesn't seem so linear
+ swing = AngleSubtract( destination, *angle );
+ scale = fabs( swing );
+ if ( scale < swingTolerance * 0.5 ) {
+ scale = 0.5;
+ } else if ( scale < swingTolerance ) {
+ scale = 1.0;
+ } else {
+ scale = 2.0;
+ }
+
+ // swing towards the destination angle
+ if ( swing >= 0 ) {
+ move = uis.frametime * scale * speed;
+ if ( move >= swing ) {
+ move = swing;
+ *swinging = qfalse;
+ }
+ *angle = AngleMod( *angle + move );
+ } else if ( swing < 0 ) {
+ move = uis.frametime * scale * -speed;
+ if ( move <= swing ) {
+ move = swing;
+ *swinging = qfalse;
+ }
+ *angle = AngleMod( *angle + move );
+ }
+
+ // clamp to no more than tolerance
+ swing = AngleSubtract( destination, *angle );
+ if ( swing > clampTolerance ) {
+ *angle = AngleMod( destination - (clampTolerance - 1) );
+ } else if ( swing < -clampTolerance ) {
+ *angle = AngleMod( destination + (clampTolerance - 1) );
+ }
+}
+
+
+/*
+======================
+UI_MovedirAdjustment
+======================
+*/
+static float UI_MovedirAdjustment( playerInfo_t *pi ) {
+ vec3_t relativeAngles;
+ vec3_t moveVector;
+
+ VectorSubtract( pi->viewAngles, pi->moveAngles, relativeAngles );
+ AngleVectors( relativeAngles, moveVector, NULL, NULL );
+ if ( Q_fabs( moveVector[0] ) < 0.01 ) {
+ moveVector[0] = 0.0;
+ }
+ if ( Q_fabs( moveVector[1] ) < 0.01 ) {
+ moveVector[1] = 0.0;
+ }
+
+ if ( moveVector[1] == 0 && moveVector[0] > 0 ) {
+ return 0;
+ }
+ if ( moveVector[1] < 0 && moveVector[0] > 0 ) {
+ return 22;
+ }
+ if ( moveVector[1] < 0 && moveVector[0] == 0 ) {
+ return 45;
+ }
+ if ( moveVector[1] < 0 && moveVector[0] < 0 ) {
+ return -22;
+ }
+ if ( moveVector[1] == 0 && moveVector[0] < 0 ) {
+ return 0;
+ }
+ if ( moveVector[1] > 0 && moveVector[0] < 0 ) {
+ return 22;
+ }
+ if ( moveVector[1] > 0 && moveVector[0] == 0 ) {
+ return -45;
+ }
+
+ return -22;
+}
+
+
+/*
+===============
+UI_PlayerAngles
+===============
+*/
+static void UI_PlayerAngles( playerInfo_t *pi, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {
+ vec3_t legsAngles, torsoAngles, headAngles;
+ float dest;
+ float adjust;
+
+ VectorCopy( pi->viewAngles, headAngles );
+ headAngles[YAW] = AngleMod( headAngles[YAW] );
+ VectorClear( legsAngles );
+ VectorClear( torsoAngles );
+
+ // --------- yaw -------------
+
+ // allow yaw to drift a bit
+ if ( ( pi->legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE
+ || ( pi->torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) {
+ // if not standing still, always point all in the same direction
+ pi->torso.yawing = qtrue; // always center
+ pi->torso.pitching = qtrue; // always center
+ pi->legs.yawing = qtrue; // always center
+ }
+
+ // adjust legs for movement dir
+ adjust = UI_MovedirAdjustment( pi );
+ legsAngles[YAW] = headAngles[YAW] + adjust;
+ torsoAngles[YAW] = headAngles[YAW] + 0.25 * adjust;
+
+
+ // torso
+ UI_SwingAngles( torsoAngles[YAW], 25, 90, SWINGSPEED, &pi->torso.yawAngle, &pi->torso.yawing );
+ UI_SwingAngles( legsAngles[YAW], 40, 90, SWINGSPEED, &pi->legs.yawAngle, &pi->legs.yawing );
+
+ torsoAngles[YAW] = pi->torso.yawAngle;
+ legsAngles[YAW] = pi->legs.yawAngle;
+
+ // --------- pitch -------------
+
+ // only show a fraction of the pitch angle in the torso
+ if ( headAngles[PITCH] > 180 ) {
+ dest = (-360 + headAngles[PITCH]) * 0.75;
+ } else {
+ dest = headAngles[PITCH] * 0.75;
+ }
+ UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching );
+ torsoAngles[PITCH] = pi->torso.pitchAngle;
+
+ // pull the angles back out of the hierarchial chain
+ AnglesSubtract( headAngles, torsoAngles, headAngles );
+ AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
+ AnglesToAxis( legsAngles, legs );
+ AnglesToAxis( torsoAngles, torso );
+ AnglesToAxis( headAngles, head );
+}
+
+
+/*
+===============
+UI_PlayerFloatSprite
+===============
+*/
+static void UI_PlayerFloatSprite( playerInfo_t *pi, vec3_t origin, qhandle_t shader ) {
+ refEntity_t ent;
+
+ memset( &ent, 0, sizeof( ent ) );
+ VectorCopy( origin, ent.origin );
+ ent.origin[2] += 48;
+ ent.reType = RT_SPRITE;
+ ent.customShader = shader;
+ ent.radius = 10;
+ ent.renderfx = 0;
+ trap_R_AddRefEntityToScene( &ent );
+}
+
+
+/*
+======================
+UI_MachinegunSpinAngle
+======================
+*/
+float UI_MachinegunSpinAngle( playerInfo_t *pi ) {
+ int delta;
+ float angle;
+ float speed;
+ int torsoAnim;
+
+ delta = dp_realtime - pi->barrelTime;
+ if ( pi->barrelSpinning ) {
+ angle = pi->barrelAngle + delta * SPIN_SPEED;
+ } else {
+ if ( delta > COAST_TIME ) {
+ delta = COAST_TIME;
+ }
+
+ speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
+ angle = pi->barrelAngle + delta * speed;
+ }
+
+ torsoAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
+ if( torsoAnim == TORSO_ATTACK2 ) {
+ torsoAnim = TORSO_ATTACK;
+ }
+ if ( pi->barrelSpinning == !(torsoAnim == TORSO_ATTACK) ) {
+ pi->barrelTime = dp_realtime;
+ pi->barrelAngle = AngleMod( angle );
+ pi->barrelSpinning = !!(torsoAnim == TORSO_ATTACK);
+ }
+
+ return angle;
+}
+
+
+/*
+===============
+UI_DrawPlayer
+===============
+*/
+void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ) {
+ refdef_t refdef;
+ refEntity_t legs;
+ refEntity_t torso;
+ refEntity_t head;
+ refEntity_t gun;
+ refEntity_t barrel;
+ refEntity_t flash;
+ vec3_t origin;
+ int renderfx;
+ vec3_t mins = {-16, -16, -24};
+ vec3_t maxs = {16, 16, 32};
+ float len;
+ float xx;
+
+ if ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) {
+ return;
+ }
+
+ dp_realtime = time;
+
+ if ( pi->pendingWeapon != -1 && dp_realtime > pi->weaponTimer ) {
+ pi->weapon = pi->pendingWeapon;
+ pi->lastWeapon = pi->pendingWeapon;
+ pi->pendingWeapon = -1;
+ pi->weaponTimer = 0;
+ if( pi->currentWeapon != pi->weapon ) {
+ trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL );
+ }
+ }
+
+ UI_AdjustFrom640( &x, &y, &w, &h );
+
+ y -= jumpHeight;
+
+ memset( &refdef, 0, sizeof( refdef ) );
+ memset( &legs, 0, sizeof(legs) );
+ memset( &torso, 0, sizeof(torso) );
+ memset( &head, 0, sizeof(head) );
+
+ refdef.rdflags = RDF_NOWORLDMODEL;
+
+ AxisClear( refdef.viewaxis );
+
+ refdef.x = x;
+ refdef.y = y;
+ refdef.width = w;
+ refdef.height = h;
+
+ refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
+ xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
+ refdef.fov_y = atan2( refdef.height, xx );
+ refdef.fov_y *= ( 360 / M_PI );
+
+ // calculate distance so the player nearly fills the box
+ len = 0.7 * ( maxs[2] - mins[2] );
+ origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 );
+ origin[1] = 0.5 * ( mins[1] + maxs[1] );
+ origin[2] = -0.5 * ( mins[2] + maxs[2] );
+
+ refdef.time = dp_realtime;
+
+ trap_R_ClearScene();
+
+ // get the rotation information
+ UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis );
+
+ // get the animation state (after rotation, to allow feet shuffle)
+ UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp,
+ &torso.oldframe, &torso.frame, &torso.backlerp );
+
+ renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
+
+ //
+ // add the legs
+ //
+ legs.hModel = pi->legsModel;
+ legs.customSkin = pi->legsSkin;
+
+ VectorCopy( origin, legs.origin );
+
+ VectorCopy( origin, legs.lightingOrigin );
+ legs.renderfx = renderfx;
+ VectorCopy (legs.origin, legs.oldorigin);
+
+ trap_R_AddRefEntityToScene( &legs );
+
+ if (!legs.hModel) {
+ return;
+ }
+
+ //
+ // add the torso
+ //
+ torso.hModel = pi->torsoModel;
+ if (!torso.hModel) {
+ return;
+ }
+
+ torso.customSkin = pi->torsoSkin;
+
+ VectorCopy( origin, torso.lightingOrigin );
+
+ UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, "tag_torso");
+
+ torso.renderfx = renderfx;
+
+ trap_R_AddRefEntityToScene( &torso );
+
+ //
+ // add the head
+ //
+ head.hModel = pi->headModel;
+ if (!head.hModel) {
+ return;
+ }
+ head.customSkin = pi->headSkin;
+
+ VectorCopy( origin, head.lightingOrigin );
+
+ UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, "tag_head");
+
+ head.renderfx = renderfx;
+
+ trap_R_AddRefEntityToScene( &head );
+
+ //
+ // add the gun
+ //
+ if ( pi->currentWeapon != WP_NONE ) {
+ memset( &gun, 0, sizeof(gun) );
+ gun.hModel = pi->weaponModel;
+ VectorCopy( origin, gun.lightingOrigin );
+ UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, "tag_weapon");
+ gun.renderfx = renderfx;
+ trap_R_AddRefEntityToScene( &gun );
+ }
+
+ //
+ // add the spinning barrel
+ //
+ if ( pi->realWeapon == WP_MACHINEGUN || pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
+ vec3_t angles;
+
+ memset( &barrel, 0, sizeof(barrel) );
+ VectorCopy( origin, barrel.lightingOrigin );
+ barrel.renderfx = renderfx;
+
+ barrel.hModel = pi->barrelModel;
+ angles[YAW] = 0;
+ angles[PITCH] = 0;
+ angles[ROLL] = UI_MachinegunSpinAngle( pi );
+ if( pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
+ angles[PITCH] = angles[ROLL];
+ angles[ROLL] = 0;
+ }
+ AnglesToAxis( angles, barrel.axis );
+
+ UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel");
+
+ trap_R_AddRefEntityToScene( &barrel );
+ }
+
+ //
+ // add muzzle flash
+ //
+ if ( dp_realtime <= pi->muzzleFlashTime ) {
+ if ( pi->flashModel ) {
+ memset( &flash, 0, sizeof(flash) );
+ flash.hModel = pi->flashModel;
+ VectorCopy( origin, flash.lightingOrigin );
+ UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash");
+ flash.renderfx = renderfx;
+ trap_R_AddRefEntityToScene( &flash );
+ }
+
+ // make a dlight for the flash
+ if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) {
+ trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), pi->flashDlightColor[0],
+ pi->flashDlightColor[1], pi->flashDlightColor[2] );
+ }
+ }
+
+ //
+ // add the chat icon
+ //
+ if ( pi->chat ) {
+ UI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) );
+ }
+
+ //
+ // add an accent light
+ //
+ origin[0] -= 100; // + = behind, - = in front
+ origin[1] += 100; // + = left, - = right
+ origin[2] += 100; // + = above, - = below
+ trap_R_AddLightToScene( origin, 500, 1.0, 1.0, 1.0 );
+
+ origin[0] -= 100;
+ origin[1] -= 100;
+ origin[2] -= 100;
+ trap_R_AddLightToScene( origin, 500, 1.0, 0.0, 0.0 );
+
+ trap_R_RenderScene( &refdef );
+}
+
+
+/*
+==========================
+UI_RegisterClientSkin
+==========================
+*/
+static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, const char *skinName ) {
+ char filename[MAX_QPATH];
+
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName );
+ pi->legsSkin = trap_R_RegisterSkin( filename );
+
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName );
+ pi->torsoSkin = trap_R_RegisterSkin( filename );
+
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/head_%s.skin", modelName, skinName );
+ pi->headSkin = trap_R_RegisterSkin( filename );
+
+ if ( !pi->legsSkin || !pi->torsoSkin || !pi->headSkin ) {
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+
+/*
+======================
+UI_ParseAnimationFile
+======================
+*/
+static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) {
+ char *text_p, *prev;
+ int len;
+ int i;
+ char *token;
+ float fps;
+ int skip;
+ char text[20000];
+ fileHandle_t f;
+
+ memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS );
+
+ // load the file
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( len <= 0 ) {
+ return qfalse;
+ }
+ if ( len >= ( sizeof( text ) - 1 ) ) {
+ Com_Printf( "File %s too long\n", filename );
+ trap_FS_FCloseFile( f );
+ return qfalse;
+ }
+ trap_FS_Read( text, len, f );
+ text[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ // parse the text
+ text_p = text;
+ skip = 0; // quite the compiler warning
+
+ // read optional parameters
+ while ( 1 ) {
+ prev = text_p; // so we can unget
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ if ( !Q_stricmp( token, "footsteps" ) ) {
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ continue;
+ } else if ( !Q_stricmp( token, "headoffset" ) ) {
+ for ( i = 0 ; i < 3 ; i++ ) {
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ }
+ continue;
+ } else if ( !Q_stricmp( token, "sex" ) ) {
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ continue;
+ }
+
+ // if it is a number, start parsing animations
+ if ( token[0] >= '0' && token[0] <= '9' ) {
+ text_p = prev; // unget the token
+ break;
+ }
+
+ Com_Printf( "unknown token '%s' is %s\n", token, filename );
+ }
+
+ // read information for each frame
+ for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
+
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ animations[i].firstFrame = atoi( token );
+ // leg only frames are adjusted to not count the upper body only frames
+ if ( i == LEGS_WALKCR ) {
+ skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
+ }
+ if ( i >= LEGS_WALKCR ) {
+ animations[i].firstFrame -= skip;
+ }
+
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ animations[i].numFrames = atoi( token );
+
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ animations[i].loopFrames = atoi( token );
+
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ fps = atof( token );
+ if ( fps == 0 ) {
+ fps = 1;
+ }
+ animations[i].frameLerp = 1000 / fps;
+ animations[i].initialLerp = 1000 / fps;
+ }
+
+ if ( i != MAX_ANIMATIONS ) {
+ Com_Printf( "Error parsing animation file: %s\n", filename );
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+
+/*
+==========================
+UI_RegisterClientModelname
+==========================
+*/
+qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName ) {
+ char modelName[MAX_QPATH];
+ char skinName[MAX_QPATH];
+ char filename[MAX_QPATH];
+ char *slash;
+
+ pi->torsoModel = 0;
+ pi->headModel = 0;
+
+ if ( !modelSkinName[0] ) {
+ return qfalse;
+ }
+
+ Q_strncpyz( modelName, modelSkinName, sizeof( modelName ) );
+
+ slash = strchr( modelName, '/' );
+ if ( !slash ) {
+ // modelName did not include a skin name
+ Q_strncpyz( skinName, "default", sizeof( skinName ) );
+ } else {
+ Q_strncpyz( skinName, slash + 1, sizeof( skinName ) );
+ // truncate modelName
+ *slash = 0;
+ }
+
+ // load cmodels before models so filecache works
+
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
+ pi->legsModel = trap_R_RegisterModel( filename );
+ if ( !pi->legsModel ) {
+ Com_Printf( "Failed to load model file %s\n", filename );
+ return qfalse;
+ }
+
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
+ pi->torsoModel = trap_R_RegisterModel( filename );
+ if ( !pi->torsoModel ) {
+ Com_Printf( "Failed to load model file %s\n", filename );
+ return qfalse;
+ }
+
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", modelName );
+ pi->headModel = trap_R_RegisterModel( filename );
+ if ( !pi->headModel ) {
+ Com_Printf( "Failed to load model file %s\n", filename );
+ return qfalse;
+ }
+
+ // if any skins failed to load, fall back to default
+ if ( !UI_RegisterClientSkin( pi, modelName, skinName ) ) {
+ if ( !UI_RegisterClientSkin( pi, modelName, "default" ) ) {
+ Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName );
+ return qfalse;
+ }
+ }
+
+ // load the animations
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
+ if ( !UI_ParseAnimationFile( filename, pi->animations ) ) {
+ Com_Printf( "Failed to load animation file %s\n", filename );
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+
+/*
+===============
+UI_PlayerInfo_SetModel
+===============
+*/
+void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model ) {
+ memset( pi, 0, sizeof(*pi) );
+ UI_RegisterClientModelname( pi, model );
+ pi->weapon = WP_MACHINEGUN;
+ pi->currentWeapon = pi->weapon;
+ pi->lastWeapon = pi->weapon;
+ pi->pendingWeapon = -1;
+ pi->weaponTimer = 0;
+ pi->chat = qfalse;
+ pi->newModel = qtrue;
+ UI_PlayerInfo_SetWeapon( pi, pi->weapon );
+}
+
+
+/*
+===============
+UI_PlayerInfo_SetInfo
+===============
+*/
+void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) {
+ int currentAnim;
+ weapon_t weaponNum;
+
+ pi->chat = chat;
+
+ // view angles
+ VectorCopy( viewAngles, pi->viewAngles );
+
+ // move angles
+ VectorCopy( moveAngles, pi->moveAngles );
+
+ if ( pi->newModel ) {
+ pi->newModel = qfalse;
+
+ jumpHeight = 0;
+ pi->pendingLegsAnim = 0;
+ UI_ForceLegsAnim( pi, legsAnim );
+ pi->legs.yawAngle = viewAngles[YAW];
+ pi->legs.yawing = qfalse;
+
+ pi->pendingTorsoAnim = 0;
+ UI_ForceTorsoAnim( pi, torsoAnim );
+ pi->torso.yawAngle = viewAngles[YAW];
+ pi->torso.yawing = qfalse;
+
+ if ( weaponNumber != -1 ) {
+ pi->weapon = weaponNumber;
+ pi->currentWeapon = weaponNumber;
+ pi->lastWeapon = weaponNumber;
+ pi->pendingWeapon = -1;
+ pi->weaponTimer = 0;
+ UI_PlayerInfo_SetWeapon( pi, pi->weapon );
+ }
+
+ return;
+ }
+
+ // weapon
+ if ( weaponNumber == -1 ) {
+ pi->pendingWeapon = -1;
+ pi->weaponTimer = 0;
+ }
+ else if ( weaponNumber != WP_NONE ) {
+ pi->pendingWeapon = weaponNumber;
+ pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY;
+ }
+ weaponNum = pi->lastWeapon;
+ pi->weapon = weaponNum;
+
+ if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) {
+ torsoAnim = legsAnim = BOTH_DEATH1;
+ pi->weapon = pi->currentWeapon = WP_NONE;
+ UI_PlayerInfo_SetWeapon( pi, pi->weapon );
+
+ jumpHeight = 0;
+ pi->pendingLegsAnim = 0;
+ UI_ForceLegsAnim( pi, legsAnim );
+
+ pi->pendingTorsoAnim = 0;
+ UI_ForceTorsoAnim( pi, torsoAnim );
+
+ return;
+ }
+
+ // leg animation
+ currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
+ if ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) {
+ pi->pendingLegsAnim = legsAnim;
+ }
+ else if ( legsAnim != currentAnim ) {
+ jumpHeight = 0;
+ pi->pendingLegsAnim = 0;
+ UI_ForceLegsAnim( pi, legsAnim );
+ }
+
+ // torso animation
+ if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) {
+ if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
+ torsoAnim = TORSO_STAND2;
+ }
+ else {
+ torsoAnim = TORSO_STAND;
+ }
+ }
+
+ if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) {
+ if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
+ torsoAnim = TORSO_ATTACK2;
+ }
+ else {
+ torsoAnim = TORSO_ATTACK;
+ }
+ pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH;
+ //FIXME play firing sound here
+ }
+
+ currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
+
+ if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) {
+ pi->pendingTorsoAnim = torsoAnim;
+ }
+ else if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) {
+ pi->pendingTorsoAnim = torsoAnim;
+ }
+ else if ( torsoAnim != currentAnim ) {
+ pi->pendingTorsoAnim = 0;
+ UI_ForceTorsoAnim( pi, torsoAnim );
+ }
+}
diff --git a/code/q3_ui/ui_playersettings.c b/code/q3_ui/ui_playersettings.c
new file mode 100644
index 0000000..8b9006c
--- /dev/null
+++ b/code/q3_ui/ui_playersettings.c
@@ -0,0 +1,567 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#include "ui_local.h"
+
+#define ART_FRAMEL "menu/art_blueish/frame2_l"
+#define ART_FRAMER "menu/art_blueish/frame1_r"
+#define ART_MODEL0 "menu/art_blueish/model_0"
+#define ART_MODEL1 "menu/art_blueish/model_1"
+#define ART_BACK0 "menu/art_blueish/back_0"
+#define ART_BACK1 "menu/art_blueish/back_1"
+#define ART_FX_BASE "menu/art/fx_base"
+#define ART_FX_BLUE "menu/art/fx_blue"
+#define ART_FX_CYAN "menu/art/fx_cyan"
+#define ART_FX_GREEN "menu/art/fx_grn"
+#define ART_FX_RED "menu/art/fx_red"
+#define ART_FX_TEAL "menu/art/fx_teal"
+#define ART_FX_WHITE "menu/art/fx_white"
+#define ART_FX_YELLOW "menu/art/fx_yel"
+
+#define ID_NAME 10
+#define ID_HANDICAP 11
+#define ID_EFFECTS 12
+#define ID_EFFECTS2 13
+#define ID_BACK 14
+#define ID_MODEL 15
+
+#define MAX_NAMELENGTH 20
+
+
+typedef struct {
+ menuframework_s menu;
+
+ menutext_s banner;
+ menubitmap_s framel;
+ menubitmap_s framer;
+ menubitmap_s player;
+
+ menufield_s name;
+ menulist_s handicap;
+ menulist_s effects;
+
+ //Added in beta 29
+ menulist_s effects2;
+
+ menubitmap_s back;
+ menubitmap_s model;
+ menubitmap_s item_null;
+
+ qhandle_t fxBasePic;
+ qhandle_t fxPic[7];
+ playerInfo_t playerinfo;
+ int current_fx;
+ char playerModel[MAX_QPATH];
+} playersettings_t;
+
+static playersettings_t s_playersettings;
+
+static int gamecodetoui[] = {4,2,3,0,5,1,6};
+static int uitogamecode[] = {4,6,2,3,1,5,7};
+
+static const char *handicap_items[] = {
+ "100",
+ "95",
+ "90",
+ "85",
+ "80",
+ "75",
+ "70",
+ "65",
+ "60",
+ "55",
+ "50",
+ "45",
+ "40",
+ "35",
+ "30",
+ "25",
+ "20",
+ "15",
+ "10",
+ "5",
+ NULL
+};
+
+
+/*
+=================
+PlayerSettings_DrawName
+=================
+*/
+static void PlayerSettings_DrawName( void *self ) {
+ menufield_s *f;
+ qboolean focus;
+ int style;
+ char *txt;
+ char c;
+ float *color;
+ int n;
+ int basex, x, y;
+ char name[32];
+
+ f = (menufield_s*)self;
+ basex = f->generic.x;
+ y = f->generic.y;
+ focus = (f->generic.parent->cursor == f->generic.menuPosition);
+
+ style = UI_LEFT|UI_SMALLFONT;
+ color = text_color_normal;
+ if( focus ) {
+ style |= UI_PULSE;
+ color = text_color_highlight;
+ }
+
+ UI_DrawProportionalString( basex, y, "Name", style, color );
+
+ // draw the actual name
+ basex += 64;
+ y += PROP_HEIGHT;
+ txt = f->field.buffer;
+ color = g_color_table[ColorIndex(COLOR_WHITE)];
+ x = basex;
+ while ( (c = *txt) != 0 ) {
+ if ( !focus && Q_IsColorString( txt ) ) {
+ n = ColorIndex( *(txt+1) );
+ if( n == 0 ) {
+ n = 7;
+ }
+ color = g_color_table[n];
+ txt += 2;
+ continue;
+ }
+ UI_DrawChar( x, y, c, style, color );
+ txt++;
+ x += SMALLCHAR_WIDTH;
+ }
+
+ // draw cursor if we have focus
+ if( focus ) {
+ if ( trap_Key_GetOverstrikeMode() ) {
+ c = 11;
+ } else {
+ c = 10;
+ }
+
+ style &= ~UI_PULSE;
+ style |= UI_BLINK;
+
+ UI_DrawChar( basex + f->field.cursor * SMALLCHAR_WIDTH, y, c, style, color_white );
+ }
+
+ // draw at bottom also using proportional font
+ Q_strncpyz( name, f->field.buffer, sizeof(name) );
+ Q_CleanStr( name );
+ UI_DrawProportionalString( 320, 440, name, UI_CENTER|UI_BIGFONT, text_color_normal );
+}
+
+
+/*
+=================
+PlayerSettings_DrawHandicap
+=================
+*/
+static void PlayerSettings_DrawHandicap( void *self ) {
+ menulist_s *item;
+ qboolean focus;
+ int style;
+ float *color;
+
+ item = (menulist_s *)self;
+ focus = (item->generic.parent->cursor == item->generic.menuPosition);
+
+ style = UI_LEFT|UI_SMALLFONT;
+ color = text_color_normal;
+ if( focus ) {
+ style |= UI_PULSE;
+ color = text_color_highlight;
+ }
+
+ UI_DrawProportionalString( item->generic.x, item->generic.y, "Handicap", style, color );
+ UI_DrawProportionalString( item->generic.x + 64, item->generic.y + PROP_HEIGHT, handicap_items[item->curvalue], style, color );
+}
+
+
+/*
+=================
+PlayerSettings_DrawEffects
+=================
+*/
+static void PlayerSettings_DrawEffects( void *self ) {
+ menulist_s *item;
+ qboolean focus;
+ int style;
+ float *color;
+
+ item = (menulist_s *)self;
+ focus = (item->generic.parent->cursor == item->generic.menuPosition);
+
+ style = UI_LEFT|UI_SMALLFONT;
+ color = text_color_normal;
+ if( focus ) {
+ style |= UI_PULSE;
+ color = text_color_highlight;
+ }
+
+ UI_DrawProportionalString( item->generic.x, item->generic.y, "Effects", style, color );
+
+ UI_DrawHandlePic( item->generic.x + 64, item->generic.y + PROP_HEIGHT + 8, 128, 8, s_playersettings.fxBasePic );
+ UI_DrawHandlePic( item->generic.x + 64 + item->curvalue * 16 + 8, item->generic.y + PROP_HEIGHT + 6, 16, 12, s_playersettings.fxPic[item->curvalue] );
+}
+
+/*
+=================
+PlayerSettings_DrawEffects
+=================
+*/
+static void PlayerSettings_DrawEffects2( void *self ) {
+ menulist_s *item;
+ qboolean focus;
+
+ item = (menulist_s *)self;
+ focus = (item->generic.parent->cursor == item->generic.menuPosition);
+
+ UI_DrawHandlePic( item->generic.x + 64, item->generic.y + 8, 128, 8, s_playersettings.fxBasePic );
+ UI_DrawHandlePic( item->generic.x + 64 + item->curvalue * 16 + 8, item->generic.y + 6, 16, 12, s_playersettings.fxPic[item->curvalue] );
+}
+
+
+/*
+=================
+PlayerSettings_DrawPlayer
+=================
+*/
+static void PlayerSettings_DrawPlayer( void *self ) {
+ menubitmap_s *b;
+ vec3_t viewangles;
+ char buf[MAX_QPATH];
+
+ trap_Cvar_VariableStringBuffer( "model", buf, sizeof( buf ) );
+ if ( strcmp( buf, s_playersettings.playerModel ) != 0 ) {
+ UI_PlayerInfo_SetModel( &s_playersettings.playerinfo, buf );
+ strcpy( s_playersettings.playerModel, buf );
+
+ viewangles[YAW] = 180 - 30;
+ viewangles[PITCH] = 0;
+ viewangles[ROLL] = 0;
+ UI_PlayerInfo_SetInfo( &s_playersettings.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
+ }
+
+ b = (menubitmap_s*) self;
+ UI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_playersettings.playerinfo, uis.realtime/2 );
+}
+
+
+/*
+=================
+PlayerSettings_SaveChanges
+=================
+*/
+static void PlayerSettings_SaveChanges( void ) {
+ // name
+ trap_Cvar_Set( "name", s_playersettings.name.field.buffer );
+
+ // handicap
+ trap_Cvar_SetValue( "handicap", 100 - s_playersettings.handicap.curvalue * 5 );
+
+ // effects color
+ trap_Cvar_SetValue( "color1", uitogamecode[s_playersettings.effects.curvalue] );
+
+ // effects2 color
+ trap_Cvar_SetValue( "color2", uitogamecode[s_playersettings.effects2.curvalue] );
+}
+
+
+/*
+=================
+PlayerSettings_MenuKey
+=================
+*/
+static sfxHandle_t PlayerSettings_MenuKey( int key ) {
+ if( key == K_MOUSE2 || key == K_ESCAPE ) {
+ PlayerSettings_SaveChanges();
+ }
+ return Menu_DefaultKey( &s_playersettings.menu, key );
+}
+
+
+/*
+=================
+PlayerSettings_SetMenuItems
+=================
+*/
+static void PlayerSettings_SetMenuItems( void ) {
+ vec3_t viewangles;
+ int c;
+ int h;
+
+ // name
+ Q_strncpyz( s_playersettings.name.field.buffer, UI_Cvar_VariableString("name"), sizeof(s_playersettings.name.field.buffer) );
+
+ // effects color
+ c = trap_Cvar_VariableValue( "color1" ) - 1;
+ if( c < 0 || c > 6 ) {
+ c = 6;
+ }
+ s_playersettings.effects.curvalue = gamecodetoui[c];
+
+ // effects2 color
+ c = trap_Cvar_VariableValue( "color2" ) - 1;
+ if( c < 0 || c > 6 ) {
+ c = 6;
+ }
+ s_playersettings.effects2.curvalue = gamecodetoui[c];
+
+ // model/skin
+ memset( &s_playersettings.playerinfo, 0, sizeof(playerInfo_t) );
+
+ viewangles[YAW] = 180 - 30;
+ viewangles[PITCH] = 0;
+ viewangles[ROLL] = 0;
+
+ UI_PlayerInfo_SetModel( &s_playersettings.playerinfo, UI_Cvar_VariableString( "model" ) );
+ UI_PlayerInfo_SetInfo( &s_playersettings.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
+
+ // handicap
+ h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
+ s_playersettings.handicap.curvalue = 20 - h / 5;
+}
+
+
+/*
+=================
+PlayerSettings_MenuEvent
+=================
+*/
+static void PlayerSettings_MenuEvent( void* ptr, int event ) {
+ if( event != QM_ACTIVATED ) {
+ return;
+ }
+
+ switch( ((menucommon_s*)ptr)->id ) {
+ case ID_HANDICAP:
+ trap_Cvar_Set( "handicap", va( "%i", 100 - 25 * s_playersettings.handicap.curvalue ) );
+ break;
+
+ case ID_MODEL:
+ PlayerSettings_SaveChanges();
+ UI_PlayerModelMenu();
+ break;
+
+ case ID_BACK:
+ PlayerSettings_SaveChanges();
+ UI_PopMenu();
+ break;
+ }
+}
+
+/*
+=================
+PlayerSettings_StatusBar
+=================
+*/
+static void PlayerSettings_StatusBar( void* ptr ) {
+ UI_DrawString( 320, 400, "Lower handicap makes you weaker", UI_CENTER|UI_SMALLFONT, colorWhite );
+ UI_DrawString( 320, 420, "giving you more challenge", UI_CENTER|UI_SMALLFONT, colorWhite );
+}
+
+/*
+=================
+PlayerSettings_MenuInit
+=================
+*/
+static void PlayerSettings_MenuInit( void ) {
+ int y;
+
+ memset(&s_playersettings,0,sizeof(playersettings_t));
+
+ PlayerSettings_Cache();
+
+ s_playersettings.menu.key = PlayerSettings_MenuKey;
+ s_playersettings.menu.wrapAround = qtrue;
+ s_playersettings.menu.fullscreen = qtrue;
+
+ s_playersettings.banner.generic.type = MTYPE_BTEXT;
+ s_playersettings.banner.generic.x = 320;
+ s_playersettings.banner.generic.y = 16;
+ s_playersettings.banner.string = "PLAYER SETTINGS";
+ s_playersettings.banner.color = color_white;
+ s_playersettings.banner.style = UI_CENTER;
+
+ s_playersettings.framel.generic.type = MTYPE_BITMAP;
+ s_playersettings.framel.generic.name = ART_FRAMEL;
+ s_playersettings.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
+ s_playersettings.framel.generic.x = 0;
+ s_playersettings.framel.generic.y = 78;
+ s_playersettings.framel.width = 256;
+ s_playersettings.framel.height = 329;
+
+ s_playersettings.framer.generic.type = MTYPE_BITMAP;
+ s_playersettings.framer.generic.name = ART_FRAMER;
+ s_playersettings.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
+ s_playersettings.framer.generic.x = 376;
+ s_playersettings.framer.generic.y = 76;
+ s_playersettings.framer.width = 256;
+ s_playersettings.framer.height = 334;
+
+ y = 144;
+ s_playersettings.name.generic.type = MTYPE_FIELD;
+ s_playersettings.name.generic.flags = QMF_NODEFAULTINIT;
+ s_playersettings.name.generic.ownerdraw = PlayerSettings_DrawName;
+ s_playersettings.name.field.widthInChars = MAX_NAMELENGTH;
+ s_playersettings.name.field.maxchars = MAX_NAMELENGTH;
+ s_playersettings.name.generic.x = 192;
+ s_playersettings.name.generic.y = y;
+ s_playersettings.name.generic.left = 192 - 8;
+ s_playersettings.name.generic.top = y - 8;
+ s_playersettings.name.generic.right = 192 + 200;
+ s_playersettings.name.generic.bottom = y + 2 * PROP_HEIGHT;
+
+ y += 3 * PROP_HEIGHT;
+ s_playersettings.handicap.generic.type = MTYPE_SPINCONTROL;
+ s_playersettings.handicap.generic.flags = QMF_NODEFAULTINIT;
+ s_playersettings.handicap.generic.id = ID_HANDICAP;
+ s_playersettings.handicap.generic.ownerdraw = PlayerSettings_DrawHandicap;
+ s_playersettings.handicap.generic.x = 192;
+ s_playersettings.handicap.generic.y = y;
+ s_playersettings.handicap.generic.left = 192 - 8;
+ s_playersettings.handicap.generic.top = y - 8;
+ s_playersettings.handicap.generic.right = 192 + 200;
+ s_playersettings.handicap.generic.bottom = y + 2 * PROP_HEIGHT;
+ s_playersettings.handicap.generic.statusbar = PlayerSettings_StatusBar;
+ s_playersettings.handicap.numitems = 20;
+
+ y += 3 * PROP_HEIGHT;
+ s_playersettings.effects.generic.type = MTYPE_SPINCONTROL;
+ s_playersettings.effects.generic.flags = QMF_NODEFAULTINIT;
+ s_playersettings.effects.generic.id = ID_EFFECTS;
+ s_playersettings.effects.generic.ownerdraw = PlayerSettings_DrawEffects;
+ s_playersettings.effects.generic.x = 192;
+ s_playersettings.effects.generic.y = y;
+ s_playersettings.effects.generic.left = 192 - 8;
+ s_playersettings.effects.generic.top = y - 8;
+ s_playersettings.effects.generic.right = 192 + 200;
+ s_playersettings.effects.generic.bottom = y + 2* PROP_HEIGHT;
+ s_playersettings.effects.numitems = 7;
+
+ y += 2*PROP_HEIGHT;
+ s_playersettings.effects2.generic.type = MTYPE_SPINCONTROL;
+ s_playersettings.effects2.generic.flags = QMF_NODEFAULTINIT;
+ s_playersettings.effects2.generic.id = ID_EFFECTS2;
+ s_playersettings.effects2.generic.ownerdraw = PlayerSettings_DrawEffects2;
+ s_playersettings.effects2.generic.x = 192;
+ s_playersettings.effects2.generic.y = y;
+ s_playersettings.effects2.generic.left = 192 - 8;
+ s_playersettings.effects2.generic.top = y - 8;
+ s_playersettings.effects2.generic.right = 192 + 200;
+ s_playersettings.effects2.generic.bottom = y + 2* PROP_HEIGHT;
+ s_playersettings.effects2.numitems = 7;
+
+ s_playersettings.model.generic.type = MTYPE_BITMAP;
+ s_playersettings.model.generic.name = ART_MODEL0;
+ s_playersettings.model.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_playersettings.model.generic.id = ID_MODEL;
+ s_playersettings.model.generic.callback = PlayerSettings_MenuEvent;
+ s_playersettings.model.generic.x = 640;
+ s_playersettings.model.generic.y = 480-64;
+ s_playersettings.model.width = 128;
+ s_playersettings.model.height = 64;
+ s_playersettings.model.focuspic = ART_MODEL1;
+
+ s_playersettings.player.generic.type = MTYPE_BITMAP;
+ s_playersettings.player.generic.flags = QMF_INACTIVE;
+ s_playersettings.player.generic.ownerdraw = PlayerSettings_DrawPlayer;
+ s_playersettings.player.generic.x = 400;
+ s_playersettings.player.generic.y = -40;
+ s_playersettings.player.width = 32*10;
+ s_playersettings.player.height = 56*10;
+
+ s_playersettings.back.generic.type = MTYPE_BITMAP;
+ s_playersettings.back.generic.name = ART_BACK0;
+ s_playersettings.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_playersettings.back.generic.id = ID_BACK;
+ s_playersettings.back.generic.callback = PlayerSettings_MenuEvent;
+ s_playersettings.back.generic.x = 0;
+ s_playersettings.back.generic.y = 480-64;
+ s_playersettings.back.width = 128;
+ s_playersettings.back.height = 64;
+ s_playersettings.back.focuspic = ART_BACK1;
+
+ s_playersettings.item_null.generic.type = MTYPE_BITMAP;
+ s_playersettings.item_null.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;
+ s_playersettings.item_null.generic.x = 0;
+ s_playersettings.item_null.generic.y = 0;
+ s_playersettings.item_null.width = 640;
+ s_playersettings.item_null.height = 480;
+
+ Menu_AddItem( &s_playersettings.menu, &s_playersettings.banner );
+ Menu_AddItem( &s_playersettings.menu, &s_playersettings.framel );
+ Menu_AddItem( &s_playersettings.menu, &s_playersettings.framer );
+
+ Menu_AddItem( &s_playersettings.menu, &s_playersettings.name );
+ Menu_AddItem( &s_playersettings.menu, &s_playersettings.handicap );
+ Menu_AddItem( &s_playersettings.menu, &s_playersettings.effects );
+ Menu_AddItem( &s_playersettings.menu, &s_playersettings.effects2 );
+ Menu_AddItem( &s_playersettings.menu, &s_playersettings.model );
+ Menu_AddItem( &s_playersettings.menu, &s_playersettings.back );
+
+ Menu_AddItem( &s_playersettings.menu, &s_playersettings.player );
+
+ Menu_AddItem( &s_playersettings.menu, &s_playersettings.item_null );
+
+ PlayerSettings_SetMenuItems();
+}
+
+
+/*
+=================
+PlayerSettings_Cache
+=================
+*/
+void PlayerSettings_Cache( void ) {
+ trap_R_RegisterShaderNoMip( ART_FRAMEL );
+ trap_R_RegisterShaderNoMip( ART_FRAMER );
+ trap_R_RegisterShaderNoMip( ART_MODEL0 );
+ trap_R_RegisterShaderNoMip( ART_MODEL1 );
+ trap_R_RegisterShaderNoMip( ART_BACK0 );
+ trap_R_RegisterShaderNoMip( ART_BACK1 );
+
+ s_playersettings.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
+ s_playersettings.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
+ s_playersettings.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
+ s_playersettings.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
+ s_playersettings.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
+ s_playersettings.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
+ s_playersettings.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
+ s_playersettings.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
+}
+
+
+/*
+=================
+UI_PlayerSettingsMenu
+=================
+*/
+void UI_PlayerSettingsMenu( void ) {
+ PlayerSettings_MenuInit();
+ UI_PushMenu( &s_playersettings.menu );
+}
diff --git a/code/q3_ui/ui_preferences.c b/code/q3_ui/ui_preferences.c
new file mode 100644
index 0000000..32b693f
--- /dev/null
+++ b/code/q3_ui/ui_preferences.c
@@ -0,0 +1,599 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+/*
+=======================================================================
+
+GAME OPTIONS MENU
+
+=======================================================================
+*/
+
+
+#include "ui_local.h"
+
+
+#define ART_FRAMEL "menu/art_blueish/frame2_l"
+#define ART_FRAMER "menu/art_blueish/frame1_r"
+#define ART_BACK0 "menu/art_blueish/back_0"
+#define ART_BACK1 "menu/art_blueish/back_1"
+
+#define PREFERENCES_X_POS 360
+
+#define ID_CROSSHAIR 127
+#define ID_SIMPLEITEMS 128
+#define ID_HIGHQUALITYSKY 129
+#define ID_EJECTINGBRASS 130
+#define ID_WALLMARKS 131
+#define ID_DYNAMICLIGHTS 132
+#define ID_IDENTIFYTARGET 133
+#define ID_SYNCEVERYFRAME 134
+#define ID_FORCEMODEL 135
+#define ID_DRAWTEAMOVERLAY 136
+#define ID_ALLOWDOWNLOAD 137
+#define ID_BACK 138
+//Elimination
+#define ID_WEAPONBAR 139
+#define ID_DELAGHITSCAN 140
+#define ID_COLORRED 141
+#define ID_COLORGREEN 142
+#define ID_COLORBLUE 143
+#define ID_CROSSHAIRHEALTH 144
+#define ID_CHATBEEP 145
+#define ID_TEAMCHATBEEP 146
+
+#define NUM_CROSSHAIRS 99
+
+
+typedef struct {
+ menuframework_s menu;
+
+ menutext_s banner;
+ menubitmap_s framel;
+ menubitmap_s framer;
+
+ menulist_s crosshair;
+ menuradiobutton_s crosshairHealth;
+
+ //Crosshair colors:
+ menuslider_s crosshairColorRed;
+ menuslider_s crosshairColorGreen;
+ menuslider_s crosshairColorBlue;
+
+ menuradiobutton_s simpleitems;
+ menuradiobutton_s alwaysweaponbar;
+ menuradiobutton_s brass;
+ menuradiobutton_s wallmarks;
+ menuradiobutton_s dynamiclights;
+ menuradiobutton_s identifytarget;
+ menuradiobutton_s highqualitysky;
+ menuradiobutton_s synceveryframe;
+ menuradiobutton_s forcemodel;
+ menulist_s drawteamoverlay;
+ menuradiobutton_s delaghitscan;
+ menuradiobutton_s allowdownload;
+ menuradiobutton_s chatbeep;
+ menuradiobutton_s teamchatbeep;
+ menubitmap_s back;
+
+ qhandle_t crosshairShader[NUM_CROSSHAIRS];
+} preferences_t;
+
+static preferences_t s_preferences;
+
+static const char *teamoverlay_names[] =
+{
+ "off",
+ "upper right",
+ "lower right",
+ "lower left",
+ NULL
+};
+
+static void Preferences_SetMenuItems( void ) {
+ s_preferences.crosshair.curvalue = (int)trap_Cvar_VariableValue( "cg_drawCrosshair" ) % NUM_CROSSHAIRS;
+ s_preferences.crosshairHealth.curvalue = trap_Cvar_VariableValue( "cg_crosshairHealth") != 0;
+ s_preferences.crosshairColorRed.curvalue = trap_Cvar_VariableValue( "cg_crosshairColorRed")*255.0f;
+ s_preferences.crosshairColorGreen.curvalue = trap_Cvar_VariableValue( "cg_crosshairColorGreen")*255.0f;
+ s_preferences.crosshairColorBlue.curvalue = trap_Cvar_VariableValue( "cg_crosshairColorBlue")*255.0f;
+ s_preferences.simpleitems.curvalue = trap_Cvar_VariableValue( "cg_simpleItems" ) != 0;
+ s_preferences.alwaysweaponbar.curvalue = trap_Cvar_VariableValue( "cg_alwaysWeaponBar" ) != 0;
+ s_preferences.brass.curvalue = trap_Cvar_VariableValue( "cg_brassTime" ) != 0;
+ s_preferences.wallmarks.curvalue = trap_Cvar_VariableValue( "cg_marks" ) != 0;
+ s_preferences.identifytarget.curvalue = trap_Cvar_VariableValue( "cg_drawCrosshairNames" ) != 0;
+ s_preferences.dynamiclights.curvalue = trap_Cvar_VariableValue( "r_dynamiclight" ) != 0;
+ s_preferences.highqualitysky.curvalue = trap_Cvar_VariableValue ( "r_fastsky" ) == 0;
+ s_preferences.synceveryframe.curvalue = trap_Cvar_VariableValue( "r_finish" ) != 0;
+ s_preferences.forcemodel.curvalue = trap_Cvar_VariableValue( "cg_forcemodel" ) != 0;
+ s_preferences.drawteamoverlay.curvalue = Com_Clamp( 0, 3, trap_Cvar_VariableValue( "cg_drawTeamOverlay" ) );
+ s_preferences.allowdownload.curvalue = trap_Cvar_VariableValue( "cl_allowDownload" ) != 0;
+ s_preferences.delaghitscan.curvalue = trap_Cvar_VariableValue( "cg_delag" ) != 0;
+ s_preferences.chatbeep.curvalue = trap_Cvar_VariableValue( "cg_chatBeep" ) != 0;
+ s_preferences.teamchatbeep.curvalue = trap_Cvar_VariableValue( "cg_teamChatBeep" ) != 0;
+}
+
+static void Preferences_Event( void* ptr, int notification ) {
+ if( notification != QM_ACTIVATED ) {
+ return;
+ }
+
+ switch( ((menucommon_s*)ptr)->id ) {
+ case ID_CROSSHAIR:
+ s_preferences.crosshair.curvalue++;
+ if( s_preferences.crosshair.curvalue == NUM_CROSSHAIRS || s_preferences.crosshairShader[s_preferences.crosshair.curvalue]==0 ) {
+ s_preferences.crosshair.curvalue = 0;
+ }
+ trap_Cvar_SetValue( "cg_drawCrosshair", s_preferences.crosshair.curvalue );
+ break;
+
+ case ID_CROSSHAIRHEALTH:
+ trap_Cvar_SetValue( "cg_crosshairHealth", s_preferences.crosshairHealth.curvalue );
+ if(s_preferences.crosshairHealth.curvalue) {
+ //If crosshairHealth is on: Don't allow color selection
+ s_preferences.crosshairColorRed.generic.flags |= QMF_INACTIVE;
+ s_preferences.crosshairColorGreen.generic.flags |= QMF_INACTIVE;
+ s_preferences.crosshairColorBlue.generic.flags |= QMF_INACTIVE;
+ } else {
+ //If crosshairHealth is off: Allow color selection
+ s_preferences.crosshairColorRed.generic.flags &= ~QMF_INACTIVE;
+ s_preferences.crosshairColorGreen.generic.flags &= ~QMF_INACTIVE;
+ s_preferences.crosshairColorBlue.generic.flags &= ~QMF_INACTIVE;
+ }
+ break;
+
+ case ID_COLORRED:
+ trap_Cvar_SetValue( "cg_crosshairColorRed", ((float)s_preferences.crosshairColorRed.curvalue)/255.f );
+ break;
+
+ case ID_COLORGREEN:
+ trap_Cvar_SetValue( "cg_crosshairColorGreen", ((float)s_preferences.crosshairColorGreen.curvalue)/255.f );
+ break;
+
+ case ID_COLORBLUE:
+ trap_Cvar_SetValue( "cg_crosshairColorBlue", ((float)s_preferences.crosshairColorBlue.curvalue)/255.f );
+ break;
+
+ case ID_SIMPLEITEMS:
+ trap_Cvar_SetValue( "cg_simpleItems", s_preferences.simpleitems.curvalue );
+ break;
+
+ case ID_WEAPONBAR:
+ trap_Cvar_SetValue( "cg_alwaysWeaponBar", s_preferences.alwaysweaponbar.curvalue );
+ break;
+
+ case ID_HIGHQUALITYSKY:
+ trap_Cvar_SetValue( "r_fastsky", !s_preferences.highqualitysky.curvalue );
+ break;
+
+ case ID_EJECTINGBRASS:
+ if ( s_preferences.brass.curvalue )
+ trap_Cvar_Reset( "cg_brassTime" );
+ else
+ trap_Cvar_SetValue( "cg_brassTime", 0 );
+ break;
+
+ case ID_WALLMARKS:
+ trap_Cvar_SetValue( "cg_marks", s_preferences.wallmarks.curvalue );
+ break;
+
+ case ID_DYNAMICLIGHTS:
+ trap_Cvar_SetValue( "r_dynamiclight", s_preferences.dynamiclights.curvalue );
+ break;
+
+ case ID_IDENTIFYTARGET:
+ trap_Cvar_SetValue( "cg_drawCrosshairNames", s_preferences.identifytarget.curvalue );
+ break;
+
+ case ID_SYNCEVERYFRAME:
+ trap_Cvar_SetValue( "r_finish", s_preferences.synceveryframe.curvalue );
+ break;
+
+ case ID_FORCEMODEL:
+ trap_Cvar_SetValue( "cg_forcemodel", s_preferences.forcemodel.curvalue );
+ break;
+
+ case ID_DRAWTEAMOVERLAY:
+ trap_Cvar_SetValue( "cg_drawTeamOverlay", s_preferences.drawteamoverlay.curvalue );
+ break;
+
+ case ID_ALLOWDOWNLOAD:
+ trap_Cvar_SetValue( "cl_allowDownload", s_preferences.allowdownload.curvalue );
+ trap_Cvar_SetValue( "sv_allowDownload", s_preferences.allowdownload.curvalue );
+ break;
+
+ case ID_DELAGHITSCAN:
+ trap_Cvar_SetValue( "g_delagHitscan", s_preferences.delaghitscan.curvalue );
+ trap_Cvar_SetValue( "cg_delag", s_preferences.delaghitscan.curvalue );
+ break;
+
+ case ID_CHATBEEP:
+ trap_Cvar_SetValue( "cg_chatBeep", s_preferences.chatbeep.curvalue );
+ break;
+
+ case ID_TEAMCHATBEEP:
+ trap_Cvar_SetValue( "cg_teamChatBeep", s_preferences.teamchatbeep.curvalue );
+ break;
+
+ case ID_BACK:
+ UI_PopMenu();
+ break;
+ }
+}
+
+
+/*
+=================
+Crosshair_Draw
+=================
+*/
+static void Crosshair_Draw( void *self ) {
+ menulist_s *s;
+ float *color;
+ int x, y;
+ int style;
+ qboolean focus;
+ vec4_t color4;
+
+ s = (menulist_s *)self;
+ x = s->generic.x;
+ y = s->generic.y;
+
+ style = UI_SMALLFONT;
+ focus = (s->generic.parent->cursor == s->generic.menuPosition);
+
+ if ( s->generic.flags & QMF_GRAYED )
+ color = text_color_disabled;
+ else if ( focus )
+ {
+ color = text_color_highlight;
+ style |= UI_PULSE;
+ }
+ else if ( s->generic.flags & QMF_BLINK )
+ {
+ color = text_color_highlight;
+ style |= UI_BLINK;
+ }
+ else
+ color = text_color_normal;
+
+ if ( focus )
+ {
+ // draw cursor
+ UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
+ UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
+ }
+
+ UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );
+ if( !s->curvalue ) {
+ return;
+ }
+ color4[0]=((float)s_preferences.crosshairColorRed.curvalue)/255.f;
+ color4[1]=((float)s_preferences.crosshairColorGreen.curvalue)/255.f;
+ color4[2]=((float)s_preferences.crosshairColorBlue.curvalue)/255.f;
+ color4[3]=1.0f;
+ trap_R_SetColor( color4 );
+ UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y - 4, 24, 24, s_preferences.crosshairShader[s->curvalue] );
+}
+
+
+static void Preferences_MenuInit( void ) {
+ int y;
+
+ UI_SetDefaultCvar("cg_crosshairHealth","1");
+ UI_SetDefaultCvar("cg_crosshairColorRed","1");
+ UI_SetDefaultCvar("cg_crosshairColorBlue","1");
+ UI_SetDefaultCvar("cg_crosshairColorGreen","1");
+
+ memset( &s_preferences, 0 ,sizeof(preferences_t) );
+
+ Preferences_Cache();
+
+ s_preferences.menu.wrapAround = qtrue;
+ s_preferences.menu.fullscreen = qtrue;
+
+ s_preferences.banner.generic.type = MTYPE_BTEXT;
+ s_preferences.banner.generic.x = 320;
+ s_preferences.banner.generic.y = 16;
+ s_preferences.banner.string = "GAME OPTIONS";
+ s_preferences.banner.color = color_white;
+ s_preferences.banner.style = UI_CENTER;
+
+ s_preferences.framel.generic.type = MTYPE_BITMAP;
+ s_preferences.framel.generic.name = ART_FRAMEL;
+ s_preferences.framel.generic.flags = QMF_INACTIVE;
+ s_preferences.framel.generic.x = 0;
+ s_preferences.framel.generic.y = 78;
+ s_preferences.framel.width = 256;
+ s_preferences.framel.height = 329;
+
+ s_preferences.framer.generic.type = MTYPE_BITMAP;
+ s_preferences.framer.generic.name = ART_FRAMER;
+ s_preferences.framer.generic.flags = QMF_INACTIVE;
+ s_preferences.framer.generic.x = 376;
+ s_preferences.framer.generic.y = 76;
+ s_preferences.framer.width = 256;
+ s_preferences.framer.height = 334;
+
+ y = 82;
+ s_preferences.crosshair.generic.type = MTYPE_TEXT;
+ s_preferences.crosshair.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT|QMF_NODEFAULTINIT|QMF_OWNERDRAW;
+ s_preferences.crosshair.generic.x = PREFERENCES_X_POS;
+ s_preferences.crosshair.generic.y = y;
+ s_preferences.crosshair.generic.name = "Crosshair:";
+ s_preferences.crosshair.generic.callback = Preferences_Event;
+ s_preferences.crosshair.generic.ownerdraw = Crosshair_Draw;
+ s_preferences.crosshair.generic.id = ID_CROSSHAIR;
+ s_preferences.crosshair.generic.top = y - 4;
+ s_preferences.crosshair.generic.bottom = y + 20;
+ s_preferences.crosshair.generic.left = PREFERENCES_X_POS - ( ( strlen(s_preferences.crosshair.generic.name) + 1 ) * SMALLCHAR_WIDTH );
+ s_preferences.crosshair.generic.right = PREFERENCES_X_POS + 48;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.crosshairHealth.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.crosshairHealth.generic.name = "Crosshair shows health:";
+ s_preferences.crosshairHealth.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.crosshairHealth.generic.callback = Preferences_Event;
+ s_preferences.crosshairHealth.generic.id = ID_CROSSHAIRHEALTH;
+ s_preferences.crosshairHealth.generic.x = PREFERENCES_X_POS;
+ s_preferences.crosshairHealth.generic.y = y;
+
+ y += BIGCHAR_HEIGHT;
+ s_preferences.crosshairColorRed.generic.type = MTYPE_SLIDER;
+ s_preferences.crosshairColorRed.generic.name = "Crosshair red:";
+ s_preferences.crosshairColorRed.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.crosshairColorRed.generic.callback = Preferences_Event;
+ s_preferences.crosshairColorRed.generic.id = ID_COLORRED;
+ s_preferences.crosshairColorRed.generic.x = PREFERENCES_X_POS;
+ s_preferences.crosshairColorRed.generic.y = y;
+ s_preferences.crosshairColorRed.minvalue = 0.0f;
+ s_preferences.crosshairColorRed.maxvalue = 255.0f;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.crosshairColorGreen.generic.type = MTYPE_SLIDER;
+ s_preferences.crosshairColorGreen.generic.name = "Crosshair green:";
+ s_preferences.crosshairColorGreen.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.crosshairColorGreen.generic.callback = Preferences_Event;
+ s_preferences.crosshairColorGreen.generic.id = ID_COLORGREEN;
+ s_preferences.crosshairColorGreen.generic.x = PREFERENCES_X_POS;
+ s_preferences.crosshairColorGreen.generic.y = y;
+ s_preferences.crosshairColorGreen.minvalue = 0.0f;
+ s_preferences.crosshairColorGreen.maxvalue = 255.0f;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.crosshairColorBlue.generic.type = MTYPE_SLIDER;
+ s_preferences.crosshairColorBlue.generic.name = "Crosshair blue:";
+ s_preferences.crosshairColorBlue.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.crosshairColorBlue.generic.callback = Preferences_Event;
+ s_preferences.crosshairColorBlue.generic.id = ID_COLORBLUE;
+ s_preferences.crosshairColorBlue.generic.x = PREFERENCES_X_POS;
+ s_preferences.crosshairColorBlue.generic.y = y;
+ s_preferences.crosshairColorBlue.minvalue = 0.0f;
+ s_preferences.crosshairColorBlue.maxvalue = 255.0f;
+
+
+ if(s_preferences.crosshairHealth.curvalue) {
+ s_preferences.crosshairColorRed.generic.flags |= QMF_INACTIVE;
+ s_preferences.crosshairColorGreen.generic.flags |= QMF_INACTIVE;
+ s_preferences.crosshairColorBlue.generic.flags |= QMF_INACTIVE;
+ }
+
+ y += BIGCHAR_HEIGHT+2+4;
+ s_preferences.simpleitems.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.simpleitems.generic.name = "Simple Items:";
+ s_preferences.simpleitems.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.simpleitems.generic.callback = Preferences_Event;
+ s_preferences.simpleitems.generic.id = ID_SIMPLEITEMS;
+ s_preferences.simpleitems.generic.x = PREFERENCES_X_POS;
+ s_preferences.simpleitems.generic.y = y;
+
+ //Elimination
+ y += BIGCHAR_HEIGHT;
+ s_preferences.alwaysweaponbar.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.alwaysweaponbar.generic.name = "Always show weapons:";
+ s_preferences.alwaysweaponbar.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.alwaysweaponbar.generic.callback = Preferences_Event;
+ s_preferences.alwaysweaponbar.generic.id = ID_WEAPONBAR;
+ s_preferences.alwaysweaponbar.generic.x = PREFERENCES_X_POS;
+ s_preferences.alwaysweaponbar.generic.y = y;
+
+ y += BIGCHAR_HEIGHT;
+ s_preferences.wallmarks.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.wallmarks.generic.name = "Marks on Walls:";
+ s_preferences.wallmarks.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.wallmarks.generic.callback = Preferences_Event;
+ s_preferences.wallmarks.generic.id = ID_WALLMARKS;
+ s_preferences.wallmarks.generic.x = PREFERENCES_X_POS;
+ s_preferences.wallmarks.generic.y = y;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.brass.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.brass.generic.name = "Ejecting Brass:";
+ s_preferences.brass.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.brass.generic.callback = Preferences_Event;
+ s_preferences.brass.generic.id = ID_EJECTINGBRASS;
+ s_preferences.brass.generic.x = PREFERENCES_X_POS;
+ s_preferences.brass.generic.y = y;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.dynamiclights.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.dynamiclights.generic.name = "Dynamic Lights:";
+ s_preferences.dynamiclights.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.dynamiclights.generic.callback = Preferences_Event;
+ s_preferences.dynamiclights.generic.id = ID_DYNAMICLIGHTS;
+ s_preferences.dynamiclights.generic.x = PREFERENCES_X_POS;
+ s_preferences.dynamiclights.generic.y = y;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.identifytarget.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.identifytarget.generic.name = "Identify Target:";
+ s_preferences.identifytarget.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.identifytarget.generic.callback = Preferences_Event;
+ s_preferences.identifytarget.generic.id = ID_IDENTIFYTARGET;
+ s_preferences.identifytarget.generic.x = PREFERENCES_X_POS;
+ s_preferences.identifytarget.generic.y = y;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.highqualitysky.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.highqualitysky.generic.name = "High Quality Sky:";
+ s_preferences.highqualitysky.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.highqualitysky.generic.callback = Preferences_Event;
+ s_preferences.highqualitysky.generic.id = ID_HIGHQUALITYSKY;
+ s_preferences.highqualitysky.generic.x = PREFERENCES_X_POS;
+ s_preferences.highqualitysky.generic.y = y;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.synceveryframe.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.synceveryframe.generic.name = "Sync Every Frame:";
+ s_preferences.synceveryframe.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.synceveryframe.generic.callback = Preferences_Event;
+ s_preferences.synceveryframe.generic.id = ID_SYNCEVERYFRAME;
+ s_preferences.synceveryframe.generic.x = PREFERENCES_X_POS;
+ s_preferences.synceveryframe.generic.y = y;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.forcemodel.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.forcemodel.generic.name = "Force Player Models:";
+ s_preferences.forcemodel.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.forcemodel.generic.callback = Preferences_Event;
+ s_preferences.forcemodel.generic.id = ID_FORCEMODEL;
+ s_preferences.forcemodel.generic.x = PREFERENCES_X_POS;
+ s_preferences.forcemodel.generic.y = y;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.drawteamoverlay.generic.type = MTYPE_SPINCONTROL;
+ s_preferences.drawteamoverlay.generic.name = "Draw Team Overlay:";
+ s_preferences.drawteamoverlay.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.drawteamoverlay.generic.callback = Preferences_Event;
+ s_preferences.drawteamoverlay.generic.id = ID_DRAWTEAMOVERLAY;
+ s_preferences.drawteamoverlay.generic.x = PREFERENCES_X_POS;
+ s_preferences.drawteamoverlay.generic.y = y;
+ s_preferences.drawteamoverlay.itemnames = teamoverlay_names;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.delaghitscan.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.delaghitscan.generic.name = "Unlag hitscan:";
+ s_preferences.delaghitscan.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.delaghitscan.generic.callback = Preferences_Event;
+ s_preferences.delaghitscan.generic.id = ID_DELAGHITSCAN;
+ s_preferences.delaghitscan.generic.x = PREFERENCES_X_POS;
+ s_preferences.delaghitscan.generic.y = y;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.allowdownload.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.allowdownload.generic.name = "Automatic Downloading:";
+ s_preferences.allowdownload.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.allowdownload.generic.callback = Preferences_Event;
+ s_preferences.allowdownload.generic.id = ID_ALLOWDOWNLOAD;
+ s_preferences.allowdownload.generic.x = PREFERENCES_X_POS;
+ s_preferences.allowdownload.generic.y = y;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.chatbeep.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.chatbeep.generic.name = "Beep on chat:";
+ s_preferences.chatbeep.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.chatbeep.generic.callback = Preferences_Event;
+ s_preferences.chatbeep.generic.id = ID_CHATBEEP;
+ s_preferences.chatbeep.generic.x = PREFERENCES_X_POS;
+ s_preferences.chatbeep.generic.y = y;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.teamchatbeep.generic.type = MTYPE_RADIOBUTTON;
+ s_preferences.teamchatbeep.generic.name = "Beep on team chat:";
+ s_preferences.teamchatbeep.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_preferences.teamchatbeep.generic.callback = Preferences_Event;
+ s_preferences.teamchatbeep.generic.id = ID_TEAMCHATBEEP;
+ s_preferences.teamchatbeep.generic.x = PREFERENCES_X_POS;
+ s_preferences.teamchatbeep.generic.y = y;
+
+ y += BIGCHAR_HEIGHT+2;
+ s_preferences.back.generic.type = MTYPE_BITMAP;
+ s_preferences.back.generic.name = ART_BACK0;
+ s_preferences.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_preferences.back.generic.callback = Preferences_Event;
+ s_preferences.back.generic.id = ID_BACK;
+ s_preferences.back.generic.x = 0;
+ s_preferences.back.generic.y = 480-64;
+ s_preferences.back.width = 128;
+ s_preferences.back.height = 64;
+ s_preferences.back.focuspic = ART_BACK1;
+
+ Menu_AddItem( &s_preferences.menu, &s_preferences.banner );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.framel );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.framer );
+
+ Menu_AddItem( &s_preferences.menu, &s_preferences.crosshair );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.crosshairHealth );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.crosshairColorRed );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.crosshairColorGreen );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.crosshairColorBlue );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.simpleitems );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.alwaysweaponbar );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.wallmarks );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.brass );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.dynamiclights );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.identifytarget );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.highqualitysky );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.synceveryframe );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.forcemodel );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.drawteamoverlay );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.delaghitscan );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.allowdownload );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.teamchatbeep );
+ Menu_AddItem( &s_preferences.menu, &s_preferences.chatbeep );
+
+ Menu_AddItem( &s_preferences.menu, &s_preferences.back );
+
+ Preferences_SetMenuItems();
+}
+
+
+/*
+===============
+Preferences_Cache
+===============
+*/
+void Preferences_Cache( void ) {
+ int n;
+
+ trap_R_RegisterShaderNoMip( ART_FRAMEL );
+ trap_R_RegisterShaderNoMip( ART_FRAMER );
+ trap_R_RegisterShaderNoMip( ART_BACK0 );
+ trap_R_RegisterShaderNoMip( ART_BACK1 );
+ for( n = 0; n < NUM_CROSSHAIRS; n++ ) {
+ if (n < 10)
+ s_preferences.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a' + n ) );
+ else
+ s_preferences.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%02d", n - 10) );
+
+ }
+}
+
+
+/*
+===============
+UI_PreferencesMenu
+===============
+*/
+void UI_PreferencesMenu( void ) {
+ Preferences_MenuInit();
+ UI_PushMenu( &s_preferences.menu );
+}
diff --git a/game/code/q3_ui/ui_qmenu.c b/code/q3_ui/ui_qmenu.c
similarity index 100%
rename from game/code/q3_ui/ui_qmenu.c
rename to code/q3_ui/ui_qmenu.c
diff --git a/game/code/q3_ui/ui_rankings.c b/code/q3_ui/ui_rankings.c
similarity index 100%
rename from game/code/q3_ui/ui_rankings.c
rename to code/q3_ui/ui_rankings.c
diff --git a/game/code/q3_ui/ui_removebots.c b/code/q3_ui/ui_removebots.c
similarity index 100%
rename from game/code/q3_ui/ui_removebots.c
rename to code/q3_ui/ui_removebots.c
diff --git a/game/code/q3_ui/ui_saveconfig.c b/code/q3_ui/ui_saveconfig.c
similarity index 100%
rename from game/code/q3_ui/ui_saveconfig.c
rename to code/q3_ui/ui_saveconfig.c
diff --git a/game/code/q3_ui/ui_serverinfo.c b/code/q3_ui/ui_serverinfo.c
similarity index 100%
rename from game/code/q3_ui/ui_serverinfo.c
rename to code/q3_ui/ui_serverinfo.c
diff --git a/code/q3_ui/ui_servers2.c b/code/q3_ui/ui_servers2.c
new file mode 100644
index 0000000..0cb1a04
--- /dev/null
+++ b/code/q3_ui/ui_servers2.c
@@ -0,0 +1,1850 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+/*
+=======================================================================
+
+MULTIPLAYER MENU (SERVER BROWSER)
+
+=======================================================================
+*/
+
+
+#include "ui_local.h"
+
+
+#define MAX_GLOBALSERVERS 256
+#define MAX_PINGREQUESTS 32
+#define MAX_ADDRESSLENGTH 64
+#define MAX_HOSTNAMELENGTH 31
+#define MAX_MAPNAMELENGTH 20
+#define MAX_LISTBOXITEMS 256
+#define MAX_LOCALSERVERS 124
+#define MAX_STATUSLENGTH 64
+#define MAX_LEAGUELENGTH 28
+#define MAX_LISTBOXWIDTH 70
+
+#define ART_BACK0 "menu/art_blueish/back_0"
+#define ART_BACK1 "menu/art_blueish/back_1"
+#define ART_CREATE0 "menu/art_blueish/create_0"
+#define ART_CREATE1 "menu/art_blueish/create_1"
+#define ART_SPECIFY0 "menu/art_blueish/specify_0"
+#define ART_SPECIFY1 "menu/art_blueish/specify_1"
+#define ART_REFRESH0 "menu/art_blueish/refresh_0"
+#define ART_REFRESH1 "menu/art_blueish/refresh_1"
+#define ART_CONNECT0 "menu/art_blueish/fight_0"
+#define ART_CONNECT1 "menu/art_blueish/fight_1"
+#define ART_ARROWS0 "menu/art_blueish/arrows_vert_0"
+#define ART_ARROWS_UP "menu/art_blueish/arrows_vert_top"
+#define ART_ARROWS_DOWN "menu/art_blueish/arrows_vert_bot"
+#define ART_UNKNOWNMAP "menu/art_blueish/unknownmap"
+#define ART_REMOVE0 "menu/art_blueish/delete_0"
+#define ART_REMOVE1 "menu/art_blueish/delete_1"
+
+#define ID_MASTER 10
+#define ID_GAMETYPE 11
+#define ID_SORTKEY 12
+#define ID_SHOW_FULL 13
+#define ID_SHOW_EMPTY 14
+
+#define ID_LIST 15
+#define ID_SCROLL_UP 16
+#define ID_SCROLL_DOWN 17
+#define ID_BACK 18
+#define ID_REFRESH 19
+#define ID_SPECIFY 20
+#define ID_CREATE 21
+#define ID_CONNECT 22
+#define ID_REMOVE 23
+
+//Beta 23
+#define ID_ONLY_HUMANS 24
+#define ID_HIDE_PRIVATE 25
+
+#define GR_LOGO 30
+#define GR_LETTERS 31
+
+#define UIAS_LOCAL 0
+#define UIAS_GLOBAL1 1
+#define UIAS_GLOBAL2 2
+#define UIAS_GLOBAL3 3
+#define UIAS_GLOBAL4 4
+#define UIAS_GLOBAL5 5
+#define UIAS_FAVORITES 6
+
+#define SORT_HOST 0
+#define SORT_MAP 1
+#define SORT_CLIENTS 2
+#define SORT_GAME 3
+#define SORT_PING 4
+#define SORT_HUMANS 5
+
+#define GAMES_ALL 0
+#define GAMES_FFA 1
+#define GAMES_TEAMPLAY 2
+#define GAMES_TOURNEY 3
+#define GAMES_CTF 4
+#define GAMES_1FCTF 5
+#define GAMES_OBELISK 6
+#define GAMES_HARVESTER 7
+#define GAMES_ELIMINATION 8
+#define GAMES_CTF_ELIMINATION 9
+#define GAMES_LMS 10
+#define GAMES_DOUBLE_D 11
+#define GAMES_DOM 12
+
+
+static const char *master_items[] = {
+ "Local",
+ "Internet",
+ "Internet(2)",
+ "Internet(3)",
+ "Internet(4)",
+ "Internet(5)",
+ "Favorites",
+ NULL
+};
+
+static const char *servertype_items[] = {
+ "All",
+ "Free For All",
+ "Team Deathmatch",
+ "Tournament",
+ "Capture the Flag",
+ "One Flag Capture",
+ "Overload",
+ "Harvester",
+ "Elimination",
+ "CTF Elimination",
+ "Last Man Standing",
+ "Double Domination",
+ "Domination",
+ NULL
+};
+
+static const char *sortkey_items[] = {
+ "Server Name",
+ "Map Name",
+ "Open Player Spots",
+ "Game Type",
+ "Ping Time",
+ "Human Players",
+ NULL
+};
+
+static char* gamenames[] = {
+ "DM ", // deathmatch
+ "1v1", // tournament
+ "SP ", // single player
+ "Team DM", // team deathmatch
+ "CTF", // capture the flag
+ "One Flag CTF", // one flag ctf
+ "OverLoad", // Overload
+ "Harvester", // Harvester
+ "Elimination",
+ "CTF Elimination",
+ "Last Man Standing",
+ "Double Domination",
+ "Domination", // Dom replaces Rocket Arena 3
+ "Q3F", // Q3F
+ "Urban Terror", // Urban Terror
+ "OSP", // Orange Smoothie Productions
+ "???", // unknown
+ NULL
+};
+
+static char* netnames[] = {
+ "???",
+ "IP4",
+ "IP6",
+ NULL
+};
+
+static char quake3worldMessage[] = "Visit www.openarena.ws - News, Community, Events, Files";
+
+
+typedef struct {
+ char adrstr[MAX_ADDRESSLENGTH];
+ int start;
+} pinglist_t;
+
+typedef struct servernode_s {
+ char adrstr[MAX_ADDRESSLENGTH];
+ char hostname[MAX_HOSTNAMELENGTH+3];
+ char mapname[MAX_MAPNAMELENGTH];
+ int numclients;
+ int humanclients;
+ qboolean needPass;
+ int maxclients;
+ int pingtime;
+ int gametype;
+ char gamename[16];
+ int nettype;
+ int minPing;
+ int maxPing;
+ //qboolean bPB;
+
+} servernode_t;
+
+typedef struct {
+ char buff[MAX_LISTBOXWIDTH+64]; // +60 gives room for color codes... Sago: I need four more
+ servernode_t* servernode;
+} table_t;
+
+typedef struct {
+ menuframework_s menu;
+
+ menutext_s banner;
+
+ menulist_s master;
+ menulist_s gametype;
+ menulist_s sortkey;
+ menuradiobutton_s showfull;
+ menuradiobutton_s showempty;
+
+ menuradiobutton_s onlyhumans;
+ menuradiobutton_s hideprivate;
+
+ menulist_s list;
+ menubitmap_s mappic;
+ menubitmap_s arrows;
+ menubitmap_s up;
+ menubitmap_s down;
+ menutext_s status;
+ menutext_s statusbar;
+
+ menubitmap_s remove;
+ menubitmap_s back;
+ menubitmap_s refresh;
+ menubitmap_s specify;
+ menubitmap_s create;
+ menubitmap_s go;
+
+ pinglist_t pinglist[MAX_PINGREQUESTS];
+ table_t table[MAX_LISTBOXITEMS];
+ char* items[MAX_LISTBOXITEMS];
+ int numqueriedservers;
+ int *numservers;
+ servernode_t *serverlist;
+ int currentping;
+ qboolean refreshservers;
+ int nextpingtime;
+ int maxservers;
+ int refreshtime;
+ char favoriteaddresses[MAX_FAVORITESERVERS][MAX_ADDRESSLENGTH];
+ int numfavoriteaddresses;
+} arenaservers_t;
+
+static arenaservers_t g_arenaservers;
+
+
+static servernode_t g_globalserverlist[MAX_GLOBALSERVERS];
+static int g_numglobalservers;
+static servernode_t g_localserverlist[MAX_LOCALSERVERS];
+static int g_numlocalservers;
+static servernode_t g_favoriteserverlist[MAX_FAVORITESERVERS];
+static int g_numfavoriteservers;
+static int g_servertype;
+static int g_gametype;
+static int g_sortkey;
+static int g_emptyservers;
+static int g_fullservers;
+
+static int g_onlyhumans;
+static int g_hideprivate;
+
+/*
+ *Removes illigal chars but keeps colors
+ */
+char *Q_CleanStrWithColor( char *string ) {
+ char* d;
+ char* s;
+ int c;
+
+ s = string;
+ d = string;
+ while ((c = *s) != 0 ) {
+ if ( Q_IsColorString( s ) ) {
+ *d++ = c;
+ }
+ else if ( c >= 0x20 && c <= 0x7E ) {
+ *d++ = c;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return string;
+}
+
+
+/*
+=================
+ArenaServers_MaxPing
+=================
+*/
+static int ArenaServers_MaxPing( void ) {
+ int maxPing;
+
+ maxPing = (int)trap_Cvar_VariableValue( "cl_maxPing" );
+ if( maxPing < 100 ) {
+ maxPing = 100;
+ }
+ return maxPing;
+}
+
+
+/*
+=================
+ArenaServers_Compare
+=================
+*/
+static int QDECL ArenaServers_Compare( const void *arg1, const void *arg2 ) {
+ float f1;
+ float f2;
+ servernode_t* t1;
+ servernode_t* t2;
+
+ t1 = (servernode_t *)arg1;
+ t2 = (servernode_t *)arg2;
+
+ switch( g_sortkey ) {
+ case SORT_HOST:
+ return Q_stricmp( t1->hostname, t2->hostname );
+
+ case SORT_MAP:
+ return Q_stricmp( t1->mapname, t2->mapname );
+
+ case SORT_CLIENTS:
+ f1 = t1->maxclients - t1->numclients;
+ if( f1 < 0 ) {
+ f1 = 0;
+ }
+
+ f2 = t2->maxclients - t2->numclients;
+ if( f2 < 0 ) {
+ f2 = 0;
+ }
+
+ if( f1 < f2 ) {
+ return 1;
+ }
+ if( f1 == f2 ) {
+ return 0;
+ }
+ return -1;
+
+ case SORT_HUMANS:
+ f1 = t1->humanclients;
+ f2 = t2->humanclients;
+
+ if( f1 < f2 ) {
+ return 1;
+ }
+ if( f1 == f2 ) {
+ return 0;
+ }
+ return -1;
+
+ case SORT_GAME:
+ if( t1->gametype < t2->gametype ) {
+ return -1;
+ }
+ if( t1->gametype == t2->gametype ) {
+ return 0;
+ }
+ return 1;
+
+ case SORT_PING:
+ if( t1->pingtime < t2->pingtime ) {
+ return -1;
+ }
+ if( t1->pingtime > t2->pingtime ) {
+ return 1;
+ }
+ return Q_stricmp( t1->hostname, t2->hostname );
+ }
+
+ return 0;
+}
+
+
+/*
+=================
+ArenaServers_Go
+=================
+*/
+static void ArenaServers_Go( void ) {
+ servernode_t* servernode;
+
+ servernode = g_arenaservers.table[g_arenaservers.list.curvalue].servernode;
+ if( servernode ) {
+ if(servernode->needPass) {
+ UI_SpecifyPasswordMenu( va( "connect %s\n", servernode->adrstr ), servernode->hostname );
+ }
+ else
+ trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", servernode->adrstr ) );
+ }
+}
+
+
+/*
+=================
+ArenaServers_UpdatePicture
+=================
+*/
+static void ArenaServers_UpdatePicture( void ) {
+ static char picname[64];
+ servernode_t* servernodeptr;
+
+ if( !g_arenaservers.list.numitems ) {
+ g_arenaservers.mappic.generic.name = NULL;
+ }
+ else {
+ servernodeptr = g_arenaservers.table[g_arenaservers.list.curvalue].servernode;
+ Com_sprintf( picname, sizeof(picname), "levelshots/%s.tga", servernodeptr->mapname );
+ g_arenaservers.mappic.generic.name = picname;
+
+ }
+
+ // force shader update during draw
+ g_arenaservers.mappic.shader = 0;
+}
+
+/*
+=================
+ Q_strcpyColor - This function will return the real length of the string if numChars
+ len of character data is desired. It looks for color codes and adds 2 to the length
+ for each combo found. This is used to make color strings show up correctly in column
+ formatted environments. Otherwise, the columns will be off 2 * num of color codes.
+=================
+*/
+int Q_strcpyColor( const char *src, char *dest, int numChars )
+{
+int count, len;
+char *d;
+const char *s;
+
+ if( !src || !dest )
+ {
+ return 0;
+ }
+
+ count = len = 0;
+ s = src;
+ d = dest;
+
+ while( *s && count < numChars )
+ {
+ if( Q_IsColorString( s ))
+ {
+ *d++ = *s++;
+ *d++ = *s++;
+ len += 2;
+ continue;
+ }
+ *d = *s;
+ s++;
+ d++;
+ count++;
+ len++;
+ }
+
+ // Now fill up the end of the string with space characters if needed...
+ while( count < numChars )
+ {
+ *d = ' ';
+ //d[len] = ' ';
+ d++;
+ len++;
+ count++;
+ }
+ return len;
+}
+
+
+/*
+=================
+ArenaServers_UpdateMenu
+=================
+*/
+static void ArenaServers_UpdateMenu( void ) {
+ int i;
+ int j;
+ int count, bufAddr;
+ char* buff;
+ servernode_t* servernodeptr;
+ table_t* tableptr;
+ char *b, *pingColor;
+
+ if( g_arenaservers.numqueriedservers > 0 ) {
+ // servers found
+ if( g_arenaservers.refreshservers && ( g_arenaservers.currentping <= g_arenaservers.numqueriedservers ) ) {
+ // show progress
+ Com_sprintf( g_arenaservers.status.string, MAX_STATUSLENGTH, "%d of %d Arena Servers.", g_arenaservers.currentping, g_arenaservers.numqueriedservers);
+ g_arenaservers.statusbar.string = "Press SPACE to stop";
+ qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);
+ }
+ else {
+ // all servers pinged - enable controls
+ g_arenaservers.master.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.gametype.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.sortkey.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.showempty.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.onlyhumans.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.hideprivate.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.showfull.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.list.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.refresh.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.go.generic.flags &= ~QMF_GRAYED;
+
+ // update status bar
+ if( g_servertype >= UIAS_GLOBAL1 && g_servertype <= UIAS_GLOBAL5 ) {
+ g_arenaservers.statusbar.string = quake3worldMessage;
+ }
+ else {
+ g_arenaservers.statusbar.string = "";
+ }
+
+ }
+ }
+ else {
+ // no servers found
+ if( g_arenaservers.refreshservers ) {
+ strcpy( g_arenaservers.status.string,"Scanning For Servers." );
+ g_arenaservers.statusbar.string = "Press SPACE to stop";
+
+ // disable controls during refresh
+ g_arenaservers.master.generic.flags |= QMF_GRAYED;
+ g_arenaservers.gametype.generic.flags |= QMF_GRAYED;
+ g_arenaservers.sortkey.generic.flags |= QMF_GRAYED;
+ g_arenaservers.showempty.generic.flags |= QMF_GRAYED;
+ g_arenaservers.onlyhumans.generic.flags |= QMF_GRAYED;
+ g_arenaservers.hideprivate.generic.flags |= QMF_GRAYED;
+ g_arenaservers.showfull.generic.flags |= QMF_GRAYED;
+ g_arenaservers.list.generic.flags |= QMF_GRAYED;
+ g_arenaservers.refresh.generic.flags |= QMF_GRAYED;
+ g_arenaservers.go.generic.flags |= QMF_GRAYED;
+ }
+ else {
+ if( g_arenaservers.numqueriedservers < 0 ) {
+ strcpy(g_arenaservers.status.string,"No Response From Master Server." );
+ }
+ else {
+ strcpy(g_arenaservers.status.string,"No Servers Found." );
+ }
+
+ // update status bar
+ if( g_servertype >= UIAS_GLOBAL1 && g_servertype <= UIAS_GLOBAL5 ) {
+ g_arenaservers.statusbar.string = quake3worldMessage;
+ }
+ else {
+ g_arenaservers.statusbar.string = "";
+ }
+
+ // end of refresh - set control state
+ g_arenaservers.master.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.gametype.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.sortkey.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.showempty.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.onlyhumans.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.hideprivate.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.showfull.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.list.generic.flags |= QMF_GRAYED;
+ g_arenaservers.refresh.generic.flags &= ~QMF_GRAYED;
+ g_arenaservers.go.generic.flags |= QMF_GRAYED;
+ }
+
+ // zero out list box
+ g_arenaservers.list.numitems = 0;
+ g_arenaservers.list.curvalue = 0;
+ g_arenaservers.list.top = 0;
+
+ // update picture
+ ArenaServers_UpdatePicture();
+ return;
+ }
+
+ // build list box strings - apply culling filters
+ servernodeptr = g_arenaservers.serverlist;
+ count = *g_arenaservers.numservers;
+ for( i = 0, j = 0; i < count; i++, servernodeptr++ ) {
+ tableptr = &g_arenaservers.table[j];
+ tableptr->servernode = servernodeptr;
+ buff = tableptr->buff;
+
+ // can only cull valid results
+ if( !g_emptyservers && !servernodeptr->numclients ) {
+ continue;
+ }
+
+ //If "Show only humans" and "Hide empty server" are enabled hide servers that only have bots
+ if( !g_emptyservers && g_onlyhumans && !servernodeptr->humanclients ) {
+ continue;
+ }
+
+ if( !g_fullservers && ( servernodeptr->numclients == servernodeptr->maxclients ) ) {
+ continue;
+ }
+
+ switch( g_gametype ) {
+ case GAMES_ALL:
+ break;
+
+ case GAMES_FFA:
+ if( servernodeptr->gametype != GT_FFA ) {
+ continue;
+ }
+ break;
+
+ case GAMES_TEAMPLAY:
+ if( servernodeptr->gametype != GT_TEAM ) {
+ continue;
+ }
+ break;
+
+ case GAMES_TOURNEY:
+ if( servernodeptr->gametype != GT_TOURNAMENT ) {
+ continue;
+ }
+ break;
+
+ case GAMES_CTF:
+ if( servernodeptr->gametype != GT_CTF ) {
+ continue;
+ }
+ break;
+
+ case GAMES_1FCTF:
+ if( servernodeptr->gametype != GT_1FCTF ) {
+ continue;
+ }
+ break;
+
+ case GAMES_OBELISK:
+ if( servernodeptr->gametype != GT_OBELISK ) {
+ continue;
+ }
+ break;
+
+ case GAMES_HARVESTER:
+ if( servernodeptr->gametype != GT_HARVESTER ) {
+ continue;
+ }
+ break;
+
+ case GAMES_ELIMINATION:
+ if( servernodeptr->gametype != GT_ELIMINATION ) {
+ continue;
+ }
+ break;
+
+ case GAMES_CTF_ELIMINATION:
+ if( servernodeptr->gametype != GT_CTF_ELIMINATION ) {
+ continue;
+ }
+ break;
+
+ case GAMES_LMS:
+ if( servernodeptr->gametype != GT_LMS ) {
+ continue;
+ }
+ break;
+
+ case GAMES_DOUBLE_D:
+ if( servernodeptr->gametype != GT_DOUBLE_D ) {
+ continue;
+ }
+ break;
+
+ case GAMES_DOM:
+ if( servernodeptr->gametype != GT_DOMINATION ) {
+ continue;
+ }
+ break;
+ }
+
+ if(g_hideprivate && servernodeptr->needPass)
+ continue;
+
+ if( servernodeptr->pingtime < servernodeptr->minPing ) {
+ pingColor = S_COLOR_BLUE;
+ }
+ else if( servernodeptr->maxPing && servernodeptr->pingtime > servernodeptr->maxPing ) {
+ pingColor = S_COLOR_BLUE;
+ }
+ else if( servernodeptr->pingtime < 200 ) {
+ pingColor = S_COLOR_GREEN;
+ }
+ else if( servernodeptr->pingtime < 400 ) {
+ pingColor = S_COLOR_YELLOW;
+ }
+ else {
+ pingColor = S_COLOR_RED;
+ }
+
+ /*
+ Com_sprintf( buff, MAX_LISTBOXWIDTH, "%-20.20s %-12.12s %2d/%2d %-8.8s %3s %s%3d ",
+ servernodeptr->hostname, servernodeptr->mapname, servernodeptr->numclients,
+ servernodeptr->maxclients, servernodeptr->gamename,
+ netnames[servernodeptr->nettype], pingColor, servernodeptr->pingtime ); //, servernodeptr->bPB ? "Yes" : "No"
+ */
+ b = buff;
+ *b++ = '^';
+ *b++ = '7';
+ bufAddr = Q_strcpyColor( servernodeptr->hostname, b, 30 );
+ b += bufAddr;
+ *b++ = ' ';
+ *b++ = '^';
+ *b++ = '7';
+
+ bufAddr = Q_strcpyColor( servernodeptr->mapname, b, 16 );
+ b += bufAddr;
+ *b++ = ' ';
+
+ if(g_onlyhumans == 0)
+ Com_sprintf( b, 8, "%2d/%2d ", servernodeptr->numclients, servernodeptr->maxclients );
+ else
+ Com_sprintf( b, 8, "%2d/%2d ", servernodeptr->humanclients, servernodeptr->maxclients );
+ b += 6;
+
+ bufAddr = Q_strcpyColor( servernodeptr->gamename, b, 8 );
+ b += bufAddr;
+ *b++ = ' ';
+
+ bufAddr = Q_strcpyColor( netnames[servernodeptr->nettype], b, 3 );
+ b += bufAddr;
+ *b++ = ' ';
+
+ Com_sprintf( b, 12, "%s%3d ", pingColor, servernodeptr->pingtime );
+ j++;
+ }
+
+ g_arenaservers.list.numitems = j;
+ g_arenaservers.list.curvalue = 0;
+ g_arenaservers.list.top = 0;
+
+ // update picture
+ ArenaServers_UpdatePicture();
+}
+
+
+/*
+=================
+ArenaServers_Remove
+=================
+*/
+static void ArenaServers_Remove( void )
+{
+ int i;
+ servernode_t* servernodeptr;
+ table_t* tableptr;
+
+ if (!g_arenaservers.list.numitems)
+ return;
+
+ // remove selected item from display list
+ // items are in scattered order due to sort and cull
+ // perform delete on list box contents, resync all lists
+
+ tableptr = &g_arenaservers.table[g_arenaservers.list.curvalue];
+ servernodeptr = tableptr->servernode;
+
+ // find address in master list
+ for (i=0; i<g_arenaservers.numfavoriteaddresses; i++)
+ {
+ if (!Q_stricmp(g_arenaservers.favoriteaddresses[i],servernodeptr->adrstr))
+ {
+ // delete address from master list
+ if (i < g_arenaservers.numfavoriteaddresses-1)
+ {
+ // shift items up
+ memcpy( &g_arenaservers.favoriteaddresses[i], &g_arenaservers.favoriteaddresses[i+1], (g_arenaservers.numfavoriteaddresses - i - 1)* MAX_ADDRESSLENGTH );
+ }
+ g_arenaservers.numfavoriteaddresses--;
+ memset( &g_arenaservers.favoriteaddresses[g_arenaservers.numfavoriteaddresses], 0, MAX_ADDRESSLENGTH );
+ break;
+ }
+ }
+
+ // find address in server list
+ for (i=0; i<g_numfavoriteservers; i++)
+ {
+ if (&g_favoriteserverlist[i] == servernodeptr)
+ {
+ // delete address from server list
+ if (i < g_numfavoriteservers-1)
+ {
+ // shift items up
+ memcpy( &g_favoriteserverlist[i], &g_favoriteserverlist[i+1], (g_numfavoriteservers - i - 1)*sizeof(servernode_t));
+ }
+ g_numfavoriteservers--;
+ memset( &g_favoriteserverlist[ g_numfavoriteservers ], 0, sizeof(servernode_t));
+ break;
+ }
+ }
+
+ g_arenaservers.numqueriedservers = g_arenaservers.numfavoriteaddresses;
+ g_arenaservers.currentping = g_arenaservers.numfavoriteaddresses;
+}
+
+
+/*
+=================
+ArenaServers_Insert
+=================
+*/
+static void ArenaServers_Insert( char* adrstr, char* info, int pingtime )
+{
+ servernode_t* servernodeptr;
+ char* s;
+ int i;
+
+
+ if ((pingtime >= ArenaServers_MaxPing()) && (g_servertype != UIAS_FAVORITES))
+ {
+ // slow global or local servers do not get entered
+ return;
+ }
+
+ if (*g_arenaservers.numservers >= g_arenaservers.maxservers) {
+ // list full;
+ servernodeptr = g_arenaservers.serverlist+(*g_arenaservers.numservers)-1;
+ } else {
+ // next slot
+ servernodeptr = g_arenaservers.serverlist+(*g_arenaservers.numservers);
+ (*g_arenaservers.numservers)++;
+ }
+
+ Q_strncpyz( servernodeptr->adrstr, adrstr, MAX_ADDRESSLENGTH );
+
+ Q_strncpyz( servernodeptr->hostname, Info_ValueForKey( info, "hostname"), MAX_HOSTNAMELENGTH );
+ Q_CleanStrWithColor( servernodeptr->hostname );
+ Q_strupr( servernodeptr->hostname );
+
+ Q_strncpyz( servernodeptr->mapname, Info_ValueForKey( info, "mapname"), MAX_MAPNAMELENGTH );
+ Q_CleanStr( servernodeptr->mapname );
+ Q_strupr( servernodeptr->mapname );
+
+ servernodeptr->numclients = atoi( Info_ValueForKey( info, "clients") );
+ servernodeptr->humanclients = atoi( Info_ValueForKey( info, "g_humanplayers") );
+ servernodeptr->needPass = atoi( Info_ValueForKey( info, "g_needpass") );
+ servernodeptr->maxclients = atoi( Info_ValueForKey( info, "sv_maxclients") );
+ servernodeptr->pingtime = pingtime;
+ servernodeptr->minPing = atoi( Info_ValueForKey( info, "minPing") );
+ servernodeptr->maxPing = atoi( Info_ValueForKey( info, "maxPing") );
+
+
+ s = Info_ValueForKey( info, "nettype" );
+ for (i=0; ;i++)
+ {
+ if (!netnames[i])
+ {
+ servernodeptr->nettype = 0;
+ break;
+ }
+ else if (!Q_stricmp( netnames[i], s ))
+ {
+ servernodeptr->nettype = i;
+ break;
+ }
+ }
+
+ servernodeptr->nettype = atoi(Info_ValueForKey(info, "nettype"));
+
+ s = Info_ValueForKey( info, "game");
+ i = atoi( Info_ValueForKey( info, "gametype") );
+ if( i < 0 ) {
+ i = 0;
+ }
+ else if( i > 11 ) {
+ i = 12;
+ }
+ if( *s ) {
+ servernodeptr->gametype = i;//-1;
+ Q_strncpyz( servernodeptr->gamename, s, sizeof(servernodeptr->gamename) );
+ }
+ else {
+ servernodeptr->gametype = i;
+ Q_strncpyz( servernodeptr->gamename, gamenames[i], sizeof(servernodeptr->gamename) );
+ }
+}
+
+
+/*
+=================
+ArenaServers_InsertFavorites
+
+Insert nonresponsive address book entries into display lists.
+=================
+*/
+void ArenaServers_InsertFavorites( void )
+{
+ int i;
+ int j;
+ char info[MAX_INFO_STRING];
+
+ // resync existing results with new or deleted cvars
+ info[0] = '\0';
+ Info_SetValueForKey( info, "hostname", "No Response" );
+ for (i=0; i<g_arenaservers.numfavoriteaddresses; i++)
+ {
+ // find favorite address in refresh list
+ for (j=0; j<g_numfavoriteservers; j++)
+ if (!Q_stricmp(g_arenaservers.favoriteaddresses[i],g_favoriteserverlist[j].adrstr))
+ break;
+
+ if ( j >= g_numfavoriteservers)
+ {
+ // not in list, add it
+ ArenaServers_Insert( g_arenaservers.favoriteaddresses[i], info, ArenaServers_MaxPing() );
+ }
+ }
+}
+
+
+/*
+=================
+ArenaServers_LoadFavorites
+
+Load cvar address book entries into local lists.
+=================
+*/
+void ArenaServers_LoadFavorites( void )
+{
+ int i;
+ int j;
+ int numtempitems;
+ char emptyinfo[MAX_INFO_STRING];
+ char adrstr[MAX_ADDRESSLENGTH];
+ servernode_t templist[MAX_FAVORITESERVERS];
+ qboolean found;
+
+ found = qfalse;
+ emptyinfo[0] = '\0';
+
+ // copy the old
+ memcpy( templist, g_favoriteserverlist, sizeof(servernode_t)*MAX_FAVORITESERVERS );
+ numtempitems = g_numfavoriteservers;
+
+ // clear the current for sync
+ memset( g_favoriteserverlist, 0, sizeof(servernode_t)*MAX_FAVORITESERVERS );
+ g_numfavoriteservers = 0;
+
+ // resync existing results with new or deleted cvars
+ for (i=0; i<MAX_FAVORITESERVERS; i++)
+ {
+ trap_Cvar_VariableStringBuffer( va("server%d",i+1), adrstr, MAX_ADDRESSLENGTH );
+ if (!adrstr[0])
+ continue;
+
+ // quick sanity check to avoid slow domain name resolving
+ // first character must be numeric
+ if (adrstr[0] < '0' || adrstr[0] > '9')
+ continue;
+
+ // favorite server addresses must be maintained outside refresh list
+ // this mimics local and global netadr's stored in client
+ // these can be fetched to fill ping list
+ strcpy( g_arenaservers.favoriteaddresses[g_numfavoriteservers], adrstr );
+
+ // find this server in the old list
+ for (j=0; j<numtempitems; j++)
+ if (!Q_stricmp( templist[j].adrstr, adrstr ))
+ break;
+
+ if (j < numtempitems)
+ {
+ // found server - add exisiting results
+ memcpy( &g_favoriteserverlist[g_numfavoriteservers], &templist[j], sizeof(servernode_t) );
+ found = qtrue;
+ }
+ else
+ {
+ // add new server
+ Q_strncpyz( g_favoriteserverlist[g_numfavoriteservers].adrstr, adrstr, MAX_ADDRESSLENGTH );
+ g_favoriteserverlist[g_numfavoriteservers].pingtime = ArenaServers_MaxPing();
+ }
+
+ g_numfavoriteservers++;
+ }
+
+ g_arenaservers.numfavoriteaddresses = g_numfavoriteservers;
+
+ if (!found)
+ {
+ // no results were found, reset server list
+ // list will be automatically refreshed when selected
+ g_numfavoriteservers = 0;
+ }
+}
+
+
+/*
+=================
+ArenaServers_StopRefresh
+=================
+*/
+static void ArenaServers_StopRefresh( void )
+{
+ if (!g_arenaservers.refreshservers)
+ // not currently refreshing
+ return;
+
+ g_arenaservers.refreshservers = qfalse;
+
+ if (g_servertype == UIAS_FAVORITES)
+ {
+ // nonresponsive favorites must be shown
+ ArenaServers_InsertFavorites();
+ }
+
+ // final tally
+ if (g_arenaservers.numqueriedservers >= 0)
+ {
+ g_arenaservers.currentping = *g_arenaservers.numservers;
+ g_arenaservers.numqueriedservers = *g_arenaservers.numservers;
+ }
+
+ // sort
+ qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);
+
+ ArenaServers_UpdateMenu();
+}
+
+
+/*
+=================
+ArenaServers_DoRefresh
+=================
+*/
+static void ArenaServers_DoRefresh( void )
+{
+ int i;
+ int j;
+ int time;
+ int maxPing;
+ char adrstr[MAX_ADDRESSLENGTH];
+ char info[MAX_INFO_STRING];
+
+ if (uis.realtime < g_arenaservers.refreshtime)
+ {
+ if (g_servertype != UIAS_FAVORITES) {
+ if (g_servertype == UIAS_LOCAL) {
+ if (!trap_LAN_GetServerCount(g_servertype)) {
+ return;
+ }
+ }
+ if (trap_LAN_GetServerCount(g_servertype) < 0) {
+ // still waiting for response
+ return;
+ }
+ }
+ }
+
+ if (uis.realtime < g_arenaservers.nextpingtime)
+ {
+ // wait for time trigger
+ return;
+ }
+
+ // trigger at 10Hz intervals
+ g_arenaservers.nextpingtime = uis.realtime + 10;
+
+ // process ping results
+ maxPing = ArenaServers_MaxPing();
+ for (i=0; i<MAX_PINGREQUESTS; i++)
+ {
+ trap_LAN_GetPing( i, adrstr, MAX_ADDRESSLENGTH, &time );
+ if (!adrstr[0])
+ {
+ // ignore empty or pending pings
+ continue;
+ }
+
+ // find ping result in our local list
+ for (j=0; j<MAX_PINGREQUESTS; j++)
+ if (!Q_stricmp( adrstr, g_arenaservers.pinglist[j].adrstr ))
+ break;
+
+ if (j < MAX_PINGREQUESTS)
+ {
+ // found it
+ if (!time)
+ {
+ time = uis.realtime - g_arenaservers.pinglist[j].start;
+ if (time < maxPing)
+ {
+ // still waiting
+ continue;
+ }
+ }
+
+ if (time > maxPing)
+ {
+ // stale it out
+ info[0] = '\0';
+ time = maxPing;
+ }
+ else
+ {
+ trap_LAN_GetPingInfo( i, info, MAX_INFO_STRING );
+ }
+
+ // insert ping results
+ ArenaServers_Insert( adrstr, info, time );
+
+ // clear this query from internal list
+ g_arenaservers.pinglist[j].adrstr[0] = '\0';
+ }
+
+ // clear this query from external list
+ trap_LAN_ClearPing( i );
+ }
+
+ // get results of servers query
+ // counts can increase as servers respond
+ if (g_servertype == UIAS_FAVORITES) {
+ g_arenaservers.numqueriedservers = g_arenaservers.numfavoriteaddresses;
+ } else {
+ g_arenaservers.numqueriedservers = trap_LAN_GetServerCount(g_servertype);
+ }
+
+// if (g_arenaservers.numqueriedservers > g_arenaservers.maxservers)
+// g_arenaservers.numqueriedservers = g_arenaservers.maxservers;
+
+ // send ping requests in reasonable bursts
+ // iterate ping through all found servers
+ for (i=0; i<MAX_PINGREQUESTS && g_arenaservers.currentping < g_arenaservers.numqueriedservers; i++)
+ {
+ if (trap_LAN_GetPingQueueCount() >= MAX_PINGREQUESTS)
+ {
+ // ping queue is full
+ break;
+ }
+
+ // find empty slot
+ for (j=0; j<MAX_PINGREQUESTS; j++)
+ if (!g_arenaservers.pinglist[j].adrstr[0])
+ break;
+
+ if (j >= MAX_PINGREQUESTS)
+ // no empty slots available yet - wait for timeout
+ break;
+
+ // get an address to ping
+
+ if (g_servertype == UIAS_FAVORITES) {
+ strcpy( adrstr, g_arenaservers.favoriteaddresses[g_arenaservers.currentping] );
+ } else {
+ trap_LAN_GetServerAddressString(g_servertype, g_arenaservers.currentping, adrstr, MAX_ADDRESSLENGTH );
+ }
+
+ strcpy( g_arenaservers.pinglist[j].adrstr, adrstr );
+ g_arenaservers.pinglist[j].start = uis.realtime;
+
+ trap_Cmd_ExecuteText( EXEC_NOW, va( "ping %s\n", adrstr ) );
+
+ // advance to next server
+ g_arenaservers.currentping++;
+ }
+
+ if (!trap_LAN_GetPingQueueCount())
+ {
+ // all pings completed
+ ArenaServers_StopRefresh();
+ return;
+ }
+
+ // update the user interface with ping status
+ ArenaServers_UpdateMenu();
+}
+
+
+/*
+=================
+ArenaServers_StartRefresh
+=================
+*/
+static void ArenaServers_StartRefresh( void )
+{
+ int i;
+ char myargs[32], protocol[32];
+
+ memset( g_arenaservers.serverlist, 0, g_arenaservers.maxservers*sizeof(table_t) );
+
+ for (i=0; i<MAX_PINGREQUESTS; i++)
+ {
+ g_arenaservers.pinglist[i].adrstr[0] = '\0';
+ trap_LAN_ClearPing( i );
+ }
+
+ g_arenaservers.refreshservers = qtrue;
+ g_arenaservers.currentping = 0;
+ g_arenaservers.nextpingtime = 0;
+ *g_arenaservers.numservers = 0;
+ g_arenaservers.numqueriedservers = 0;
+
+ // allow max 5 seconds for responses
+ g_arenaservers.refreshtime = uis.realtime + 5000;
+
+ // place menu in zeroed state
+ ArenaServers_UpdateMenu();
+
+ if( g_servertype == UIAS_LOCAL ) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, "localservers\n" );
+ return;
+ }
+
+ if( g_servertype >= UIAS_GLOBAL1 && g_servertype <= UIAS_GLOBAL5 ) {
+ switch( g_arenaservers.gametype.curvalue ) {
+ default:
+ case GAMES_ALL:
+ myargs[0] = 0;
+ break;
+
+ case GAMES_FFA:
+ strcpy( myargs, " ffa" );
+ break;
+
+ case GAMES_TEAMPLAY:
+ strcpy( myargs, " team" );
+ break;
+
+ case GAMES_TOURNEY:
+ strcpy( myargs, " tourney" );
+ break;
+
+ case GAMES_CTF:
+ strcpy( myargs, " ctf" );
+ break;
+
+ case GAMES_ELIMINATION:
+ strcpy( myargs, " elimination" );
+ break;
+
+ case GAMES_CTF_ELIMINATION:
+ strcpy( myargs, " ctfelimination" );
+ break;
+
+ case GAMES_LMS:
+ strcpy( myargs, " lms" );
+ break;
+
+ case GAMES_DOUBLE_D:
+ strcpy( myargs, " dd" );
+ break;
+
+ case GAMES_DOM:
+ strcpy( myargs, " dom" );
+ break;
+ }
+
+
+ if (g_emptyservers) {
+ strcat(myargs, " empty");
+ }
+
+ if (g_fullservers) {
+ strcat(myargs, " full");
+ }
+
+ protocol[0] = '\0';
+ trap_Cvar_VariableStringBuffer( "debug_protocol", protocol, sizeof(protocol) );
+ if (strlen(protocol)) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, va( "globalservers %d %s%s\n", g_servertype - 1, protocol, myargs ));
+ }
+ else {
+ trap_Cmd_ExecuteText( EXEC_APPEND, va( "globalservers %d %d%s\n", g_servertype - 1, (int)trap_Cvar_VariableValue( "protocol" ), myargs ) );
+ }
+ }
+}
+
+
+/*
+=================
+ArenaServers_SaveChanges
+=================
+*/
+void ArenaServers_SaveChanges( void )
+{
+ int i;
+
+ for (i=0; i<g_arenaservers.numfavoriteaddresses; i++)
+ trap_Cvar_Set( va("server%d",i+1), g_arenaservers.favoriteaddresses[i] );
+
+ for (; i<MAX_FAVORITESERVERS; i++)
+ trap_Cvar_Set( va("server%d",i+1), "" );
+}
+
+
+/*
+=================
+ArenaServers_Sort
+=================
+*/
+void ArenaServers_Sort( int type ) {
+ if( g_sortkey == type ) {
+ return;
+ }
+
+ g_sortkey = type;
+ qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);
+}
+
+
+/*
+=================
+ArenaServers_SetType
+=================
+*/
+int ArenaServers_SetType( int type )
+{
+ if(type >= UIAS_GLOBAL1 && type <= UIAS_GLOBAL5)
+ {
+ char masterstr[2], cvarname[sizeof("sv_master1")];
+
+ while(type <= UIAS_GLOBAL5)
+ {
+ Com_sprintf(cvarname, sizeof(cvarname), "sv_master%d", type);
+ trap_Cvar_VariableStringBuffer(cvarname, masterstr, sizeof(masterstr));
+ if(*masterstr)
+ break;
+
+ type++;
+ }
+ }
+
+ g_servertype = type;
+
+ switch( type ) {
+ default:
+ case UIAS_LOCAL:
+ g_arenaservers.remove.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
+ g_arenaservers.serverlist = g_localserverlist;
+ g_arenaservers.numservers = &g_numlocalservers;
+ g_arenaservers.maxservers = MAX_LOCALSERVERS;
+ break;
+
+ case UIAS_GLOBAL1:
+ case UIAS_GLOBAL2:
+ case UIAS_GLOBAL3:
+ case UIAS_GLOBAL4:
+ case UIAS_GLOBAL5:
+ g_arenaservers.remove.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
+ g_arenaservers.serverlist = g_globalserverlist;
+ g_arenaservers.numservers = &g_numglobalservers;
+ g_arenaservers.maxservers = MAX_GLOBALSERVERS;
+ break;
+
+ case UIAS_FAVORITES:
+ g_arenaservers.remove.generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);
+ g_arenaservers.serverlist = g_favoriteserverlist;
+ g_arenaservers.numservers = &g_numfavoriteservers;
+ g_arenaservers.maxservers = MAX_FAVORITESERVERS;
+ break;
+
+ }
+
+ if( !*g_arenaservers.numservers ) {
+ ArenaServers_StartRefresh();
+ }
+ else {
+ // avoid slow operation, use existing results
+ g_arenaservers.currentping = *g_arenaservers.numservers;
+ g_arenaservers.numqueriedservers = *g_arenaservers.numservers;
+ ArenaServers_UpdateMenu();
+ strcpy(g_arenaservers.status.string,"hit refresh to update");
+ }
+
+ return type;
+}
+
+/*
+=================
+ArenaServers_Event
+=================
+*/
+static void ArenaServers_Event( void* ptr, int event ) {
+ int id;
+
+ id = ((menucommon_s*)ptr)->id;
+
+ if( event != QM_ACTIVATED && id != ID_LIST ) {
+ return;
+ }
+
+ switch( id ) {
+ case ID_MASTER:
+ g_arenaservers.master.curvalue = ArenaServers_SetType(g_arenaservers.master.curvalue);
+ trap_Cvar_SetValue( "ui_browserMaster", g_arenaservers.master.curvalue);
+ break;
+
+ case ID_GAMETYPE:
+ trap_Cvar_SetValue( "ui_browserGameType", g_arenaservers.gametype.curvalue );
+ g_gametype = g_arenaservers.gametype.curvalue;
+ ArenaServers_UpdateMenu();
+ break;
+
+ case ID_SORTKEY:
+ trap_Cvar_SetValue( "ui_browserSortKey", g_arenaservers.sortkey.curvalue );
+ ArenaServers_Sort( g_arenaservers.sortkey.curvalue );
+ ArenaServers_UpdateMenu();
+ break;
+
+ case ID_SHOW_FULL:
+ trap_Cvar_SetValue( "ui_browserShowFull", g_arenaservers.showfull.curvalue );
+ g_fullservers = g_arenaservers.showfull.curvalue;
+ ArenaServers_UpdateMenu();
+ break;
+
+ case ID_SHOW_EMPTY:
+ trap_Cvar_SetValue( "ui_browserShowEmpty", g_arenaservers.showempty.curvalue );
+ g_emptyservers = g_arenaservers.showempty.curvalue;
+ ArenaServers_UpdateMenu();
+ break;
+
+ case ID_ONLY_HUMANS:
+ trap_Cvar_SetValue( "ui_browserOnlyHumans", g_arenaservers.onlyhumans.curvalue );
+ g_onlyhumans = g_arenaservers.onlyhumans.curvalue;
+ ArenaServers_UpdateMenu();
+ break;
+
+ case ID_HIDE_PRIVATE:
+ //trap_Cvar_SetValue( "ui_browserHidePrivate", g_arenaservers.hideprivate.curvalue );
+ g_hideprivate = g_arenaservers.hideprivate.curvalue;
+ ArenaServers_UpdateMenu();
+ break;
+
+ case ID_LIST:
+ if( event == QM_GOTFOCUS ) {
+ ArenaServers_UpdatePicture();
+ }
+ break;
+
+ case ID_SCROLL_UP:
+ ScrollList_Key( &g_arenaservers.list, K_UPARROW );
+ break;
+
+ case ID_SCROLL_DOWN:
+ ScrollList_Key( &g_arenaservers.list, K_DOWNARROW );
+ break;
+
+ case ID_BACK:
+ ArenaServers_StopRefresh();
+ ArenaServers_SaveChanges();
+ UI_PopMenu();
+ break;
+
+ case ID_REFRESH:
+ ArenaServers_StartRefresh();
+ break;
+
+ case ID_SPECIFY:
+ UI_SpecifyServerMenu();
+ break;
+
+ case ID_CREATE:
+ UI_StartServerMenu( qtrue );
+ break;
+
+ case ID_CONNECT:
+ ArenaServers_Go();
+ break;
+
+ case ID_REMOVE:
+ ArenaServers_Remove();
+ ArenaServers_UpdateMenu();
+ break;
+ }
+}
+
+
+/*
+=================
+ArenaServers_MenuDraw
+=================
+*/
+static void ArenaServers_MenuDraw( void )
+{
+ if (g_arenaservers.refreshservers)
+ ArenaServers_DoRefresh();
+
+ Menu_Draw( &g_arenaservers.menu );
+}
+
+
+/*
+=================
+ArenaServers_MenuKey
+=================
+*/
+static sfxHandle_t ArenaServers_MenuKey( int key ) {
+ if( key == K_SPACE && g_arenaservers.refreshservers ) {
+ ArenaServers_StopRefresh();
+ return menu_move_sound;
+ }
+
+ if( ( key == K_DEL || key == K_KP_DEL ) && ( g_servertype == UIAS_FAVORITES ) &&
+ ( Menu_ItemAtCursor( &g_arenaservers.menu) == &g_arenaservers.list ) ) {
+ ArenaServers_Remove();
+ ArenaServers_UpdateMenu();
+ return menu_move_sound;
+ }
+
+ if( key == K_MOUSE2 || key == K_ESCAPE ) {
+ ArenaServers_StopRefresh();
+ ArenaServers_SaveChanges();
+ }
+
+ if( key == K_MWHEELUP ) {
+ ScrollList_Key( &g_arenaservers.list, K_UPARROW );
+ }
+
+ if( key == K_MWHEELDOWN ) {
+ ScrollList_Key( &g_arenaservers.list, K_DOWNARROW );
+ }
+
+
+ return Menu_DefaultKey( &g_arenaservers.menu, key );
+}
+
+
+/*
+=================
+ArenaServers_MenuInit
+=================
+*/
+static void ArenaServers_MenuInit( void ) {
+ int i;
+ int y;
+ int value;
+ static char statusbuffer[MAX_STATUSLENGTH];
+
+ // zero set all our globals
+ memset( &g_arenaservers, 0 ,sizeof(arenaservers_t) );
+
+ ArenaServers_Cache();
+
+ g_arenaservers.menu.fullscreen = qtrue;
+ g_arenaservers.menu.wrapAround = qtrue;
+ g_arenaservers.menu.draw = ArenaServers_MenuDraw;
+ g_arenaservers.menu.key = ArenaServers_MenuKey;
+
+ g_arenaservers.banner.generic.type = MTYPE_BTEXT;
+ g_arenaservers.banner.generic.flags = QMF_CENTER_JUSTIFY;
+ g_arenaservers.banner.generic.x = 320;
+ g_arenaservers.banner.generic.y = 16;
+ g_arenaservers.banner.string = "ARENA SERVERS";
+ g_arenaservers.banner.style = UI_CENTER;
+ g_arenaservers.banner.color = color_white;
+
+ y = 80-SMALLCHAR_HEIGHT;
+ g_arenaservers.master.generic.type = MTYPE_SPINCONTROL;
+ g_arenaservers.master.generic.name = "Servers:";
+ g_arenaservers.master.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ g_arenaservers.master.generic.callback = ArenaServers_Event;
+ g_arenaservers.master.generic.id = ID_MASTER;
+ g_arenaservers.master.generic.x = 320;
+ g_arenaservers.master.generic.y = y;
+ g_arenaservers.master.itemnames = master_items;
+
+ y += SMALLCHAR_HEIGHT;
+ g_arenaservers.gametype.generic.type = MTYPE_SPINCONTROL;
+ g_arenaservers.gametype.generic.name = "Game Type:";
+ g_arenaservers.gametype.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ g_arenaservers.gametype.generic.callback = ArenaServers_Event;
+ g_arenaservers.gametype.generic.id = ID_GAMETYPE;
+ g_arenaservers.gametype.generic.x = 320;
+ g_arenaservers.gametype.generic.y = y;
+ g_arenaservers.gametype.itemnames = servertype_items;
+
+ y += SMALLCHAR_HEIGHT;
+ g_arenaservers.sortkey.generic.type = MTYPE_SPINCONTROL;
+ g_arenaservers.sortkey.generic.name = "Sort By:";
+ g_arenaservers.sortkey.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ g_arenaservers.sortkey.generic.callback = ArenaServers_Event;
+ g_arenaservers.sortkey.generic.id = ID_SORTKEY;
+ g_arenaservers.sortkey.generic.x = 320;
+ g_arenaservers.sortkey.generic.y = y;
+ g_arenaservers.sortkey.itemnames = sortkey_items;
+
+ y += SMALLCHAR_HEIGHT;
+ g_arenaservers.showfull.generic.type = MTYPE_RADIOBUTTON;
+ g_arenaservers.showfull.generic.name = "Show Full:";
+ g_arenaservers.showfull.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ g_arenaservers.showfull.generic.callback = ArenaServers_Event;
+ g_arenaservers.showfull.generic.id = ID_SHOW_FULL;
+ g_arenaservers.showfull.generic.x = 320;
+ g_arenaservers.showfull.generic.y = y;
+
+ y += SMALLCHAR_HEIGHT;
+ g_arenaservers.showempty.generic.type = MTYPE_RADIOBUTTON;
+ g_arenaservers.showempty.generic.name = "Show Empty:";
+ g_arenaservers.showempty.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ g_arenaservers.showempty.generic.callback = ArenaServers_Event;
+ g_arenaservers.showempty.generic.id = ID_SHOW_EMPTY;
+ g_arenaservers.showempty.generic.x = 320;
+ g_arenaservers.showempty.generic.y = y;
+
+ y += SMALLCHAR_HEIGHT;
+ g_arenaservers.onlyhumans.generic.type = MTYPE_RADIOBUTTON;
+ g_arenaservers.onlyhumans.generic.name = "Only humans:";
+ g_arenaservers.onlyhumans.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ g_arenaservers.onlyhumans.generic.callback = ArenaServers_Event;
+ g_arenaservers.onlyhumans.generic.id = ID_ONLY_HUMANS;
+ g_arenaservers.onlyhumans.generic.x = 320;
+ g_arenaservers.onlyhumans.generic.y = y;
+
+ y += SMALLCHAR_HEIGHT;
+ g_arenaservers.hideprivate.generic.type = MTYPE_RADIOBUTTON;
+ g_arenaservers.hideprivate.generic.name = "Hide private:";
+ g_arenaservers.hideprivate.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ g_arenaservers.hideprivate.generic.callback = ArenaServers_Event;
+ g_arenaservers.hideprivate.generic.id = ID_HIDE_PRIVATE;
+ g_arenaservers.hideprivate.generic.x = 320;
+ g_arenaservers.hideprivate.generic.y = y;
+
+ y += 2 * SMALLCHAR_HEIGHT;
+ g_arenaservers.list.generic.type = MTYPE_SCROLLLIST;
+ g_arenaservers.list.generic.flags = QMF_HIGHLIGHT_IF_FOCUS;
+ g_arenaservers.list.generic.id = ID_LIST;
+ g_arenaservers.list.generic.callback = ArenaServers_Event;
+ g_arenaservers.list.generic.x = 22;
+ g_arenaservers.list.generic.y = y;
+ g_arenaservers.list.width = MAX_LISTBOXWIDTH;
+ g_arenaservers.list.height = 11;
+ g_arenaservers.list.itemnames = (const char **)g_arenaservers.items;
+ for( i = 0; i < MAX_LISTBOXITEMS; i++ ) {
+ g_arenaservers.items[i] = g_arenaservers.table[i].buff;
+ }
+
+ g_arenaservers.mappic.generic.type = MTYPE_BITMAP;
+ g_arenaservers.mappic.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
+ g_arenaservers.mappic.generic.x = 72;
+ g_arenaservers.mappic.generic.y = 80;
+ g_arenaservers.mappic.width = 128;
+ g_arenaservers.mappic.height = 96;
+ g_arenaservers.mappic.errorpic = ART_UNKNOWNMAP;
+
+ g_arenaservers.arrows.generic.type = MTYPE_BITMAP;
+ g_arenaservers.arrows.generic.name = ART_ARROWS0;
+ g_arenaservers.arrows.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
+ g_arenaservers.arrows.generic.callback = ArenaServers_Event;
+ g_arenaservers.arrows.generic.x = 512+48+12;
+ g_arenaservers.arrows.generic.y = 240-64+48;
+ g_arenaservers.arrows.width = 64;
+ g_arenaservers.arrows.height = 128;
+
+ g_arenaservers.up.generic.type = MTYPE_BITMAP;
+ g_arenaservers.up.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
+ g_arenaservers.up.generic.callback = ArenaServers_Event;
+ g_arenaservers.up.generic.id = ID_SCROLL_UP;
+ g_arenaservers.up.generic.x = 512+48+12;
+ g_arenaservers.up.generic.y = 240-64+48;
+ g_arenaservers.up.width = 64;
+ g_arenaservers.up.height = 64;
+ g_arenaservers.up.focuspic = ART_ARROWS_UP;
+
+ g_arenaservers.down.generic.type = MTYPE_BITMAP;
+ g_arenaservers.down.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
+ g_arenaservers.down.generic.callback = ArenaServers_Event;
+ g_arenaservers.down.generic.id = ID_SCROLL_DOWN;
+ g_arenaservers.down.generic.x = 512+48+12;
+ g_arenaservers.down.generic.y = 240+48;
+ g_arenaservers.down.width = 64;
+ g_arenaservers.down.height = 64;
+ g_arenaservers.down.focuspic = ART_ARROWS_DOWN;
+
+ y = 376;
+ g_arenaservers.status.generic.type = MTYPE_TEXT;
+ g_arenaservers.status.generic.x = 320;
+ g_arenaservers.status.generic.y = y;
+ g_arenaservers.status.string = statusbuffer;
+ g_arenaservers.status.style = UI_CENTER|UI_SMALLFONT;
+ g_arenaservers.status.color = menu_text_color;
+
+ y += SMALLCHAR_HEIGHT;
+ g_arenaservers.statusbar.generic.type = MTYPE_TEXT;
+ g_arenaservers.statusbar.generic.x = 320;
+ g_arenaservers.statusbar.generic.y = y;
+ g_arenaservers.statusbar.string = "";
+ g_arenaservers.statusbar.style = UI_CENTER|UI_SMALLFONT;
+ g_arenaservers.statusbar.color = text_color_normal;
+
+ g_arenaservers.remove.generic.type = MTYPE_BITMAP;
+ g_arenaservers.remove.generic.name = ART_REMOVE0;
+ g_arenaservers.remove.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ g_arenaservers.remove.generic.callback = ArenaServers_Event;
+ g_arenaservers.remove.generic.id = ID_REMOVE;
+ g_arenaservers.remove.generic.x = 450;
+ g_arenaservers.remove.generic.y = 86;
+ g_arenaservers.remove.width = 96;
+ g_arenaservers.remove.height = 48;
+ g_arenaservers.remove.focuspic = ART_REMOVE1;
+
+ g_arenaservers.back.generic.type = MTYPE_BITMAP;
+ g_arenaservers.back.generic.name = ART_BACK0;
+ g_arenaservers.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ g_arenaservers.back.generic.callback = ArenaServers_Event;
+ g_arenaservers.back.generic.id = ID_BACK;
+ g_arenaservers.back.generic.x = 0;
+ g_arenaservers.back.generic.y = 480-64;
+ g_arenaservers.back.width = 128;
+ g_arenaservers.back.height = 64;
+ g_arenaservers.back.focuspic = ART_BACK1;
+
+ g_arenaservers.specify.generic.type = MTYPE_BITMAP;
+ g_arenaservers.specify.generic.name = ART_SPECIFY0;
+ g_arenaservers.specify.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ g_arenaservers.specify.generic.callback = ArenaServers_Event;
+ g_arenaservers.specify.generic.id = ID_SPECIFY;
+ g_arenaservers.specify.generic.x = 128;
+ g_arenaservers.specify.generic.y = 480-64;
+ g_arenaservers.specify.width = 128;
+ g_arenaservers.specify.height = 64;
+ g_arenaservers.specify.focuspic = ART_SPECIFY1;
+
+ g_arenaservers.refresh.generic.type = MTYPE_BITMAP;
+ g_arenaservers.refresh.generic.name = ART_REFRESH0;
+ g_arenaservers.refresh.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ g_arenaservers.refresh.generic.callback = ArenaServers_Event;
+ g_arenaservers.refresh.generic.id = ID_REFRESH;
+ g_arenaservers.refresh.generic.x = 256;
+ g_arenaservers.refresh.generic.y = 480-64;
+ g_arenaservers.refresh.width = 128;
+ g_arenaservers.refresh.height = 64;
+ g_arenaservers.refresh.focuspic = ART_REFRESH1;
+
+ g_arenaservers.create.generic.type = MTYPE_BITMAP;
+ g_arenaservers.create.generic.name = ART_CREATE0;
+ g_arenaservers.create.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ g_arenaservers.create.generic.callback = ArenaServers_Event;
+ g_arenaservers.create.generic.id = ID_CREATE;
+ g_arenaservers.create.generic.x = 384;
+ g_arenaservers.create.generic.y = 480-64;
+ g_arenaservers.create.width = 128;
+ g_arenaservers.create.height = 64;
+ g_arenaservers.create.focuspic = ART_CREATE1;
+
+ g_arenaservers.go.generic.type = MTYPE_BITMAP;
+ g_arenaservers.go.generic.name = ART_CONNECT0;
+ g_arenaservers.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
+ g_arenaservers.go.generic.callback = ArenaServers_Event;
+ g_arenaservers.go.generic.id = ID_CONNECT;
+ g_arenaservers.go.generic.x = 640;
+ g_arenaservers.go.generic.y = 480-64;
+ g_arenaservers.go.width = 128;
+ g_arenaservers.go.height = 64;
+ g_arenaservers.go.focuspic = ART_CONNECT1;
+
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.banner );
+
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.master );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.gametype );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.sortkey );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.showfull);
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.showempty );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.onlyhumans );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.hideprivate );
+
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.mappic );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.list );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.status );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.statusbar );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.arrows );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.up );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.down );
+
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.remove );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.back );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.specify );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.refresh );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.create );
+ Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.go );
+
+ ArenaServers_LoadFavorites();
+
+ g_servertype = Com_Clamp( 0, 3, ui_browserMaster.integer );
+ // hack to get rid of MPlayer stuff
+ value = g_servertype;
+ if (value >= 1)
+ value--;
+ g_arenaservers.master.curvalue = value;
+
+ g_gametype = Com_Clamp( 0, 12, ui_browserGameType.integer );
+ g_arenaservers.gametype.curvalue = g_gametype;
+
+ g_sortkey = Com_Clamp( 0, 5, ui_browserSortKey.integer );
+ g_arenaservers.sortkey.curvalue = g_sortkey;
+
+ g_fullservers = Com_Clamp( 0, 1, ui_browserShowFull.integer );
+ g_arenaservers.showfull.curvalue = g_fullservers;
+
+ g_emptyservers = Com_Clamp( 0, 1, ui_browserShowEmpty.integer );
+ g_arenaservers.showempty.curvalue = g_emptyservers;
+
+ g_arenaservers.onlyhumans.curvalue = Com_Clamp( 0, 1, ui_browserOnlyHumans.integer );
+ g_onlyhumans = ui_browserOnlyHumans.integer;
+
+ g_arenaservers.hideprivate.curvalue = 1; //Com_Clamp( 0, 1, ui_browserOnlyHumans.integer );
+ g_hideprivate = 1; //ui_browserOnlyHumans.integer;
+
+ // force to initial state and refresh
+ g_arenaservers.master.curvalue = g_servertype = ArenaServers_SetType(g_servertype);
+
+ trap_Cvar_Register(NULL, "debug_protocol", "", 0 );
+}
+
+
+/*
+=================
+ArenaServers_Cache
+=================
+*/
+void ArenaServers_Cache( void ) {
+ trap_R_RegisterShaderNoMip( ART_BACK0 );
+ trap_R_RegisterShaderNoMip( ART_BACK1 );
+ trap_R_RegisterShaderNoMip( ART_CREATE0 );
+ trap_R_RegisterShaderNoMip( ART_CREATE1 );
+ trap_R_RegisterShaderNoMip( ART_SPECIFY0 );
+ trap_R_RegisterShaderNoMip( ART_SPECIFY1 );
+ trap_R_RegisterShaderNoMip( ART_REFRESH0 );
+ trap_R_RegisterShaderNoMip( ART_REFRESH1 );
+ trap_R_RegisterShaderNoMip( ART_CONNECT0 );
+ trap_R_RegisterShaderNoMip( ART_CONNECT1 );
+ trap_R_RegisterShaderNoMip( ART_ARROWS0 );
+ trap_R_RegisterShaderNoMip( ART_ARROWS_UP );
+ trap_R_RegisterShaderNoMip( ART_ARROWS_DOWN );
+ trap_R_RegisterShaderNoMip( ART_UNKNOWNMAP );
+}
+
+
+/*
+=================
+UI_ArenaServersMenu
+=================
+*/
+void UI_ArenaServersMenu( void ) {
+ ArenaServers_MenuInit();
+ UI_PushMenu( &g_arenaservers.menu );
+}
diff --git a/game/code/q3_ui/ui_setup.c b/code/q3_ui/ui_setup.c
similarity index 100%
rename from game/code/q3_ui/ui_setup.c
rename to code/q3_ui/ui_setup.c
diff --git a/game/code/q3_ui/ui_signup.c b/code/q3_ui/ui_signup.c
similarity index 100%
rename from game/code/q3_ui/ui_signup.c
rename to code/q3_ui/ui_signup.c
diff --git a/game/code/q3_ui/ui_sound.c b/code/q3_ui/ui_sound.c
similarity index 100%
rename from game/code/q3_ui/ui_sound.c
rename to code/q3_ui/ui_sound.c
diff --git a/engine/code/q3_ui/ui_sparena.c b/code/q3_ui/ui_sparena.c
similarity index 100%
rename from engine/code/q3_ui/ui_sparena.c
rename to code/q3_ui/ui_sparena.c
diff --git a/game/code/q3_ui/ui_specifyleague.c b/code/q3_ui/ui_specifyleague.c
similarity index 100%
rename from game/code/q3_ui/ui_specifyleague.c
rename to code/q3_ui/ui_specifyleague.c
diff --git a/game/code/q3_ui/ui_specifyserver.c b/code/q3_ui/ui_specifyserver.c
similarity index 100%
rename from game/code/q3_ui/ui_specifyserver.c
rename to code/q3_ui/ui_specifyserver.c
diff --git a/code/q3_ui/ui_splevel.c b/code/q3_ui/ui_splevel.c
new file mode 100644
index 0000000..beee559
--- /dev/null
+++ b/code/q3_ui/ui_splevel.c
@@ -0,0 +1,1011 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+/*
+=============================================================================
+
+SINGLE PLAYER LEVEL SELECT MENU
+
+=============================================================================
+*/
+
+#include "ui_local.h"
+
+
+#define ART_LEVELFRAME_FOCUS "menu/art_blueish/maps_select"
+#define ART_LEVELFRAME_SELECTED "menu/art_blueish/maps_selected"
+#define ART_ARROW "menu/art_blueish/narrow_0"
+#define ART_ARROW_FOCUS "menu/art_blueish/narrow_1"
+#define ART_MAP_UNKNOWN "menu/art/unknownmap"
+#define ART_MAP_COMPLETE1 "menu/art/level_complete1"
+#define ART_MAP_COMPLETE2 "menu/art/level_complete2"
+#define ART_MAP_COMPLETE3 "menu/art/level_complete3"
+#define ART_MAP_COMPLETE4 "menu/art/level_complete4"
+#define ART_MAP_COMPLETE5 "menu/art/level_complete5"
+#define ART_BACK0 "menu/art_blueish/back_0"
+#define ART_BACK1 "menu/art_blueish/back_1"
+#define ART_FIGHT0 "menu/art_blueish/fight_0"
+#define ART_FIGHT1 "menu/art_blueish/fight_1"
+#define ART_RESET0 "menu/art_blueish/reset_0"
+#define ART_RESET1 "menu/art_blueish/reset_1"
+#define ART_CUSTOM0 "menu/art_blueish/skirmish_0"
+#define ART_CUSTOM1 "menu/art_blueish/skirmish_1"
+
+#define ID_LEFTARROW 10
+#define ID_PICTURE0 11
+#define ID_PICTURE1 12
+#define ID_PICTURE2 13
+#define ID_PICTURE3 14
+#define ID_RIGHTARROW 15
+#define ID_PLAYERPIC 16
+#define ID_AWARD1 17
+#define ID_AWARD2 18
+#define ID_AWARD3 19
+#define ID_AWARD4 20
+#define ID_AWARD5 21
+#define ID_AWARD6 22
+#define ID_BACK 23
+#define ID_RESET 24
+#define ID_CUSTOM 25
+#define ID_NEXT 26
+
+#define PLAYER_Y 314
+#define AWARDS_Y (PLAYER_Y + 26)
+
+
+typedef struct {
+ menuframework_s menu;
+ menutext_s item_banner;
+ menubitmap_s item_leftarrow;
+ menubitmap_s item_maps[4];
+ menubitmap_s item_rightarrow;
+ menubitmap_s item_player;
+ menubitmap_s item_awards[6];
+ menubitmap_s item_back;
+ menubitmap_s item_reset;
+ menubitmap_s item_custom;
+ menubitmap_s item_next;
+ menubitmap_s item_null;
+
+ qboolean reinit;
+
+ const char * selectedArenaInfo;
+ int numMaps;
+ char levelPicNames[4][MAX_QPATH];
+ char levelNames[4][16];
+ int levelScores[4];
+ int levelScoresSkill[4];
+ qhandle_t levelSelectedPic;
+ qhandle_t levelFocusPic;
+ qhandle_t levelCompletePic[5];
+
+ char playerModel[MAX_QPATH];
+ char playerPicName[MAX_QPATH];
+ int awardLevels[6];
+ sfxHandle_t awardSounds[6];
+
+ int numBots;
+ qhandle_t botPics[7];
+ char botNames[7][10];
+} levelMenuInfo_t;
+
+static levelMenuInfo_t levelMenuInfo;
+
+static int selectedArenaSet;
+static int selectedArena;
+static int currentSet;
+static int currentGame;
+static int trainingTier;
+static int finalTier;
+static int minTier;
+static int maxTier;
+
+
+/*
+=================
+PlayerIcon
+=================
+*/
+static void PlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize ) {
+ char *skin;
+ char model[MAX_QPATH];
+
+ Q_strncpyz( model, modelAndSkin, sizeof(model));
+ skin = strrchr( model, '/' );
+ if ( skin ) {
+ *skin++ = '\0';
+ }
+ else {
+ skin = "default";
+ }
+
+ Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_%s.tga", model, skin );
+
+ if( !trap_R_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, "default" ) != 0 ) {
+ Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_default.tga", model );
+ }
+}
+
+
+/*
+=================
+PlayerIconhandle
+=================
+*/
+static qhandle_t PlayerIconHandle( const char *modelAndSkin ) {
+ char iconName[MAX_QPATH];
+
+ PlayerIcon( modelAndSkin, iconName, sizeof(iconName) );
+ return trap_R_RegisterShaderNoMip( iconName );
+}
+
+
+/*
+=================
+UI_SPLevelMenu_SetBots
+=================
+*/
+static void UI_SPLevelMenu_SetBots( void ) {
+ char *p;
+ char *bot;
+ char *botInfo;
+ char bots[MAX_INFO_STRING];
+
+ levelMenuInfo.numBots = 0;
+ if ( selectedArenaSet > currentSet ) {
+ return;
+ }
+
+ Q_strncpyz( bots, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "bots" ), sizeof(bots) );
+
+ p = &bots[0];
+ while( *p && levelMenuInfo.numBots < 7 ) {
+ //skip spaces
+ while( *p && *p == ' ' ) {
+ p++;
+ }
+ if( !p ) {
+ break;
+ }
+
+ // mark start of bot name
+ bot = p;
+
+ // skip until space of null
+ while( *p && *p != ' ' ) {
+ p++;
+ }
+ if( *p ) {
+ *p++ = 0;
+ }
+
+ botInfo = UI_GetBotInfoByName( bot );
+ if( !botInfo ) {
+ botInfo = UI_GetBotInfoByNumber( levelMenuInfo.numBots );
+ }
+ if( botInfo ) {
+ levelMenuInfo.botPics[levelMenuInfo.numBots] = PlayerIconHandle( Info_ValueForKey( botInfo, "model" ) );
+ Q_strncpyz( levelMenuInfo.botNames[levelMenuInfo.numBots], Info_ValueForKey( botInfo, "name" ), 10 );
+ }
+ else {
+ levelMenuInfo.botPics[levelMenuInfo.numBots] = 0;
+ Q_strncpyz( levelMenuInfo.botNames[levelMenuInfo.numBots], bot, 10 );
+ }
+ Q_CleanStr( levelMenuInfo.botNames[levelMenuInfo.numBots] );
+ levelMenuInfo.numBots++;
+ }
+}
+
+
+/*
+=================
+UI_SPLevelMenu_SetMenuItems
+=================
+*/
+static void UI_SPLevelMenu_SetMenuArena( int n, int level, const char *arenaInfo ) {
+ char map[MAX_QPATH];
+
+ Q_strncpyz( map, Info_ValueForKey( arenaInfo, "map" ), sizeof(map) );
+
+ Q_strncpyz( levelMenuInfo.levelNames[n], map, sizeof(levelMenuInfo.levelNames[n]) );
+ Q_strupr( levelMenuInfo.levelNames[n] );
+
+ UI_GetBestScore( level, &levelMenuInfo.levelScores[n], &levelMenuInfo.levelScoresSkill[n] );
+ if( levelMenuInfo.levelScores[n] > 8 ) {
+ levelMenuInfo.levelScores[n] = 8;
+ }
+
+ strcpy( levelMenuInfo.levelPicNames[n], va( "levelshots/%s.tga", map ) );
+ if( !trap_R_RegisterShaderNoMip( levelMenuInfo.levelPicNames[n] ) ) {
+ strcpy( levelMenuInfo.levelPicNames[n], ART_MAP_UNKNOWN );
+ }
+ levelMenuInfo.item_maps[n].shader = 0;
+ if ( selectedArenaSet > currentSet ) {
+ levelMenuInfo.item_maps[n].generic.flags |= QMF_GRAYED;
+ }
+ else {
+ levelMenuInfo.item_maps[n].generic.flags &= ~QMF_GRAYED;
+ }
+
+ levelMenuInfo.item_maps[n].generic.flags &= ~QMF_INACTIVE;
+}
+
+static void UI_SPLevelMenu_SetMenuItems( void ) {
+ int n;
+ int level;
+ const char *arenaInfo;
+
+ if ( selectedArenaSet > currentSet ) {
+ selectedArena = -1;
+ }
+ else if ( selectedArena == -1 ) {
+ selectedArena = 0;
+ }
+
+ if( selectedArenaSet == trainingTier || selectedArenaSet == finalTier ) {
+ selectedArena = 0;
+ }
+
+ if( selectedArena != -1 ) {
+ trap_Cvar_SetValue( "ui_spSelection", selectedArenaSet * ARENAS_PER_TIER + selectedArena );
+ }
+
+ if( selectedArenaSet == trainingTier ) {
+ arenaInfo = UI_GetSpecialArenaInfo( "training" );
+ level = atoi( Info_ValueForKey( arenaInfo, "num" ) );
+ UI_SPLevelMenu_SetMenuArena( 0, level, arenaInfo );
+ levelMenuInfo.selectedArenaInfo = arenaInfo;
+
+ levelMenuInfo.item_maps[0].generic.x = 256;
+ Bitmap_Init( &levelMenuInfo.item_maps[0] );
+ levelMenuInfo.item_maps[0].generic.bottom += 32;
+ levelMenuInfo.numMaps = 1;
+
+ levelMenuInfo.item_maps[1].generic.flags |= QMF_INACTIVE;
+ levelMenuInfo.item_maps[2].generic.flags |= QMF_INACTIVE;
+ levelMenuInfo.item_maps[3].generic.flags |= QMF_INACTIVE;
+ levelMenuInfo.levelPicNames[1][0] = 0;
+ levelMenuInfo.levelPicNames[2][0] = 0;
+ levelMenuInfo.levelPicNames[3][0] = 0;
+ levelMenuInfo.item_maps[1].shader = 0;
+ levelMenuInfo.item_maps[2].shader = 0;
+ levelMenuInfo.item_maps[3].shader = 0;
+ }
+ else if( selectedArenaSet == finalTier ) {
+ arenaInfo = UI_GetSpecialArenaInfo( "final" );
+ level = atoi( Info_ValueForKey( arenaInfo, "num" ) );
+ UI_SPLevelMenu_SetMenuArena( 0, level, arenaInfo );
+ levelMenuInfo.selectedArenaInfo = arenaInfo;
+
+ levelMenuInfo.item_maps[0].generic.x = 256;
+ Bitmap_Init( &levelMenuInfo.item_maps[0] );
+ levelMenuInfo.item_maps[0].generic.bottom += 32;
+ levelMenuInfo.numMaps = 1;
+
+ levelMenuInfo.item_maps[1].generic.flags |= QMF_INACTIVE;
+ levelMenuInfo.item_maps[2].generic.flags |= QMF_INACTIVE;
+ levelMenuInfo.item_maps[3].generic.flags |= QMF_INACTIVE;
+ levelMenuInfo.levelPicNames[1][0] = 0;
+ levelMenuInfo.levelPicNames[2][0] = 0;
+ levelMenuInfo.levelPicNames[3][0] = 0;
+ levelMenuInfo.item_maps[1].shader = 0;
+ levelMenuInfo.item_maps[2].shader = 0;
+ levelMenuInfo.item_maps[3].shader = 0;
+ }
+ else {
+ levelMenuInfo.item_maps[0].generic.x = 46;
+ Bitmap_Init( &levelMenuInfo.item_maps[0] );
+ levelMenuInfo.item_maps[0].generic.bottom += 18;
+ levelMenuInfo.numMaps = 4;
+
+ for ( n = 0; n < 4; n++ ) {
+ level = selectedArenaSet * ARENAS_PER_TIER + n;
+ arenaInfo = UI_GetArenaInfoByNumber( level );
+ UI_SPLevelMenu_SetMenuArena( n, level, arenaInfo );
+ }
+
+ if( selectedArena != -1 ) {
+ levelMenuInfo.selectedArenaInfo = UI_GetArenaInfoByNumber( selectedArenaSet * ARENAS_PER_TIER + selectedArena );
+ }
+ }
+
+ // enable/disable arrows when they are valid/invalid
+ if ( selectedArenaSet == minTier ) {
+ levelMenuInfo.item_leftarrow.generic.flags |= ( QMF_INACTIVE | QMF_HIDDEN );
+ }
+ else {
+ levelMenuInfo.item_leftarrow.generic.flags &= ~( QMF_INACTIVE | QMF_HIDDEN );
+ }
+
+ if ( selectedArenaSet == maxTier ) {
+ levelMenuInfo.item_rightarrow.generic.flags |= ( QMF_INACTIVE | QMF_HIDDEN );
+ }
+ else {
+ levelMenuInfo.item_rightarrow.generic.flags &= ~( QMF_INACTIVE | QMF_HIDDEN );
+ }
+
+ UI_SPLevelMenu_SetBots();
+}
+
+
+/*
+=================
+UI_SPLevelMenu_ResetEvent
+=================
+*/
+static void UI_SPLevelMenu_ResetDraw( void ) {
+ UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, "WARNING: This resets all of the", UI_CENTER|UI_SMALLFONT, color_yellow );
+ UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, "single player game variables.", UI_CENTER|UI_SMALLFONT, color_yellow );
+ UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 2, "Do this only if you want to", UI_CENTER|UI_SMALLFONT, color_yellow );
+ UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 3, "start over from the beginning.", UI_CENTER|UI_SMALLFONT, color_yellow );
+}
+
+static void UI_SPLevelMenu_ResetAction( qboolean result ) {
+ if( !result ) {
+ return;
+ }
+
+ // clear game variables
+ UI_NewGame();
+ trap_Cvar_SetValue( "ui_spSelection", -4 );
+
+ // make the level select menu re-initialize
+ UI_PopMenu();
+ UI_SPLevelMenu();
+}
+
+static void UI_SPLevelMenu_ResetEvent( void* ptr, int event )
+{
+ if (event != QM_ACTIVATED) {
+ return;
+ }
+
+ UI_ConfirmMenu( "RESET GAME?", UI_SPLevelMenu_ResetDraw, UI_SPLevelMenu_ResetAction );
+}
+
+
+/*
+=================
+UI_SPLevelMenu_LevelEvent
+=================
+*/
+static void UI_SPLevelMenu_LevelEvent( void* ptr, int notification ) {
+ if (notification != QM_ACTIVATED) {
+ return;
+ }
+
+ if ( selectedArenaSet == trainingTier || selectedArenaSet == finalTier ) {
+ return;
+ }
+
+ selectedArena = ((menucommon_s*)ptr)->id - ID_PICTURE0;
+ levelMenuInfo.selectedArenaInfo = UI_GetArenaInfoByNumber( selectedArenaSet * ARENAS_PER_TIER + selectedArena );
+ UI_SPLevelMenu_SetBots();
+
+ trap_Cvar_SetValue( "ui_spSelection", selectedArenaSet * ARENAS_PER_TIER + selectedArena );
+}
+
+
+/*
+=================
+UI_SPLevelMenu_LeftArrowEvent
+=================
+*/
+static void UI_SPLevelMenu_LeftArrowEvent( void* ptr, int notification ) {
+ if (notification != QM_ACTIVATED) {
+ return;
+ }
+
+ if ( selectedArenaSet == minTier ) {
+ return;
+ }
+
+ selectedArenaSet--;
+ UI_SPLevelMenu_SetMenuItems();
+}
+
+
+/*
+=================
+UI_SPLevelMenu_RightArrowEvent
+=================
+*/
+static void UI_SPLevelMenu_RightArrowEvent( void* ptr, int notification ) {
+ if (notification != QM_ACTIVATED) {
+ return;
+ }
+
+ if ( selectedArenaSet == maxTier ) {
+ return;
+ }
+
+ selectedArenaSet++;
+ UI_SPLevelMenu_SetMenuItems();
+}
+
+
+/*
+=================
+UI_SPLevelMenu_PlayerEvent
+=================
+*/
+static void UI_SPLevelMenu_PlayerEvent( void* ptr, int notification ) {
+ if (notification != QM_ACTIVATED) {
+ return;
+ }
+
+ UI_PlayerSettingsMenu();
+}
+
+
+/*
+=================
+UI_SPLevelMenu_AwardEvent
+=================
+*/
+static void UI_SPLevelMenu_AwardEvent( void* ptr, int notification ) {
+ int n;
+
+ if (notification != QM_ACTIVATED) {
+ return;
+ }
+
+ n = ((menucommon_s*)ptr)->id - ID_AWARD1;
+ trap_S_StartLocalSound( levelMenuInfo.awardSounds[n], CHAN_ANNOUNCER );
+}
+
+
+/*
+=================
+UI_SPLevelMenu_NextEvent
+=================
+*/
+static void UI_SPLevelMenu_NextEvent( void* ptr, int notification ) {
+ if (notification != QM_ACTIVATED) {
+ return;
+ }
+
+ if ( selectedArenaSet > currentSet ) {
+ return;
+ }
+
+ if ( selectedArena == -1 ) {
+ selectedArena = 0;
+ }
+
+ UI_SPSkillMenu( levelMenuInfo.selectedArenaInfo );
+}
+
+
+/*
+=================
+UI_SPLevelMenu_BackEvent
+=================
+*/
+static void UI_SPLevelMenu_BackEvent( void* ptr, int notification ) {
+ if (notification != QM_ACTIVATED) {
+ return;
+ }
+
+ if ( selectedArena == -1 ) {
+ selectedArena = 0;
+ }
+
+ UI_PopMenu();
+}
+
+
+/*
+=================
+UI_SPLevelMenu_CustomEvent
+=================
+*/
+static void UI_SPLevelMenu_CustomEvent( void* ptr, int notification ) {
+ if (notification != QM_ACTIVATED) {
+ return;
+ }
+
+ UI_StartServerMenu( qfalse );
+}
+
+
+/*
+=================
+UI_SPLevelMenu_MenuDraw
+=================
+*/
+#define LEVEL_DESC_LEFT_MARGIN 332
+
+static void UI_SPLevelMenu_MenuDraw( void ) {
+ int n, i;
+ int x, y;
+ vec4_t color;
+ int level;
+// int fraglimit;
+ int pad;
+ char buf[MAX_INFO_VALUE];
+ char string[64];
+
+ if( levelMenuInfo.reinit ) {
+ UI_PopMenu();
+ UI_SPLevelMenu();
+ return;
+ }
+
+ // draw player name
+ trap_Cvar_VariableStringBuffer( "name", string, 32 );
+ Q_CleanStr( string );
+ UI_DrawProportionalString( 320, PLAYER_Y, string, UI_CENTER|UI_SMALLFONT, color_orange );
+
+ // check for model changes
+ trap_Cvar_VariableStringBuffer( "model", buf, sizeof(buf) );
+ if( Q_stricmp( buf, levelMenuInfo.playerModel ) != 0 ) {
+ Q_strncpyz( levelMenuInfo.playerModel, buf, sizeof(levelMenuInfo.playerModel) );
+ PlayerIcon( levelMenuInfo.playerModel, levelMenuInfo.playerPicName, sizeof(levelMenuInfo.playerPicName) );
+ levelMenuInfo.item_player.shader = 0;
+ }
+
+ // standard menu drawing
+ Menu_Draw( &levelMenuInfo.menu );
+
+ // draw player award levels
+ y = AWARDS_Y;
+ i = 0;
+ for( n = 0; n < 6; n++ ) {
+ level = levelMenuInfo.awardLevels[n];
+ if( level > 0 ) {
+ if( i & 1 ) {
+ x = 224 - (i - 1 ) / 2 * (48 + 16);
+ }
+ else {
+ x = 368 + i / 2 * (48 + 16);
+ }
+ i++;
+
+ if( level == 1 ) {
+ continue;
+ }
+
+ if( level >= 1000000 ) {
+ Com_sprintf( string, sizeof(string), "%im", level / 1000000 );
+ }
+ else if( level >= 1000 ) {
+ Com_sprintf( string, sizeof(string), "%ik", level / 1000 );
+ }
+ else {
+ Com_sprintf( string, sizeof(string), "%i", level );
+ }
+
+ UI_DrawString( x + 24, y + 48, string, UI_CENTER, color_yellow );
+ }
+ }
+
+ UI_DrawProportionalString( 18, 38, va( "Tier %i", selectedArenaSet + 1 ), UI_LEFT|UI_SMALLFONT, color_orange );
+
+ for ( n = 0; n < levelMenuInfo.numMaps; n++ ) {
+ x = levelMenuInfo.item_maps[n].generic.x;
+ y = levelMenuInfo.item_maps[n].generic.y;
+ UI_FillRect( x, y + 96, 128, 18, color_black );
+ }
+
+ if ( selectedArenaSet > currentSet ) {
+ UI_DrawProportionalString( 320, 216, "ACCESS DENIED", UI_CENTER|UI_BIGFONT, color_red );
+ return;
+ }
+
+ // show levelshots for levels of current tier
+ Vector4Copy( color_white, color );
+ color[3] = 0.5+0.5*sin(uis.realtime/PULSE_DIVISOR);
+ for ( n = 0; n < levelMenuInfo.numMaps; n++ ) {
+ x = levelMenuInfo.item_maps[n].generic.x;
+ y = levelMenuInfo.item_maps[n].generic.y;
+
+ UI_DrawString( x + 64, y + 96, levelMenuInfo.levelNames[n], UI_CENTER|UI_SMALLFONT, color_orange );
+
+ if( levelMenuInfo.levelScores[n] == 1 ) {
+ UI_DrawHandlePic( x, y, 128, 96, levelMenuInfo.levelCompletePic[levelMenuInfo.levelScoresSkill[n] - 1] );
+ }
+
+ if ( n == selectedArena ) {
+ if( Menu_ItemAtCursor( &levelMenuInfo.menu ) == &levelMenuInfo.item_maps[n] ) {
+ trap_R_SetColor( color );
+ }
+ UI_DrawHandlePic( x-1, y-1, 130, 130 - 14, levelMenuInfo.levelSelectedPic );
+ trap_R_SetColor( NULL );
+ }
+ else if( Menu_ItemAtCursor( &levelMenuInfo.menu ) == &levelMenuInfo.item_maps[n] ) {
+ trap_R_SetColor( color );
+ UI_DrawHandlePic( x-31, y-30, 256, 256-27, levelMenuInfo.levelFocusPic);
+ trap_R_SetColor( NULL );
+ }
+ }
+
+ // show map name and long name of selected level
+ y = 192;
+ Q_strncpyz( buf, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "map" ), 20 );
+ Q_strupr( buf );
+ Com_sprintf( string, sizeof(string), "%s: %s", buf, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "longname" ) );
+ UI_DrawProportionalString( 320, y, string, UI_CENTER|UI_SMALLFONT, color_orange );
+
+// fraglimit = atoi( Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "fraglimit" ) );
+// UI_DrawString( 18, 212, va("Frags %i", fraglimit) , UI_LEFT|UI_SMALLFONT, color_orange );
+
+ // draw bot opponents
+ y += 24;
+ pad = (7 - levelMenuInfo.numBots) * (64 + 26) / 2;
+ for( n = 0; n < levelMenuInfo.numBots; n++ ) {
+ x = 18 + pad + (64 + 26) * n;
+ if( levelMenuInfo.botPics[n] ) {
+ UI_DrawHandlePic( x, y, 64, 64, levelMenuInfo.botPics[n]);
+ }
+ else {
+ UI_FillRect( x, y, 64, 64, color_black );
+ UI_DrawProportionalString( x+22, y+18, "?", UI_BIGFONT, color_orange );
+ }
+ UI_DrawString( x, y + 64, levelMenuInfo.botNames[n], UI_SMALLFONT|UI_LEFT, color_orange );
+ }
+}
+
+
+/*
+=================
+UI_SPLevelMenu_Cache
+=================
+*/
+void UI_SPLevelMenu_Cache( void ) {
+ int n;
+
+ trap_R_RegisterShaderNoMip( ART_LEVELFRAME_FOCUS );
+ trap_R_RegisterShaderNoMip( ART_LEVELFRAME_SELECTED );
+ trap_R_RegisterShaderNoMip( ART_ARROW );
+ trap_R_RegisterShaderNoMip( ART_ARROW_FOCUS );
+ trap_R_RegisterShaderNoMip( ART_MAP_UNKNOWN );
+ trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE1 );
+ trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE2 );
+ trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE3 );
+ trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE4 );
+ trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE5 );
+ trap_R_RegisterShaderNoMip( ART_BACK0 );
+ trap_R_RegisterShaderNoMip( ART_BACK1 );
+ trap_R_RegisterShaderNoMip( ART_FIGHT0 );
+ trap_R_RegisterShaderNoMip( ART_FIGHT1 );
+ trap_R_RegisterShaderNoMip( ART_RESET0 );
+ trap_R_RegisterShaderNoMip( ART_RESET1 );
+ trap_R_RegisterShaderNoMip( ART_CUSTOM0 );
+ trap_R_RegisterShaderNoMip( ART_CUSTOM1 );
+
+ for( n = 0; n < 6; n++ ) {
+ trap_R_RegisterShaderNoMip( ui_medalPicNames[n] );
+ levelMenuInfo.awardSounds[n] = trap_S_RegisterSound( ui_medalSounds[n], qfalse );
+ }
+
+ levelMenuInfo.levelSelectedPic = trap_R_RegisterShaderNoMip( ART_LEVELFRAME_SELECTED );
+ levelMenuInfo.levelFocusPic = trap_R_RegisterShaderNoMip( ART_LEVELFRAME_FOCUS );
+ levelMenuInfo.levelCompletePic[0] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE1 );
+ levelMenuInfo.levelCompletePic[1] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE2 );
+ levelMenuInfo.levelCompletePic[2] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE3 );
+ levelMenuInfo.levelCompletePic[3] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE4 );
+ levelMenuInfo.levelCompletePic[4] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE5 );
+}
+
+
+/*
+=================
+UI_SPLevelMenu_Init
+=================
+*/
+static void UI_SPLevelMenu_Init( void ) {
+ int skill;
+ int n;
+ int x, y;
+ int count;
+ char buf[MAX_QPATH];
+
+ skill = (int)trap_Cvar_VariableValue( "g_spSkill" );
+ if( skill < 1 || skill > 5 ) {
+ trap_Cvar_Set( "g_spSkill", "2" );
+ skill = 2;
+ }
+
+ memset( &levelMenuInfo, 0, sizeof(levelMenuInfo) );
+ levelMenuInfo.menu.fullscreen = qtrue;
+ levelMenuInfo.menu.wrapAround = qtrue;
+ levelMenuInfo.menu.draw = UI_SPLevelMenu_MenuDraw;
+
+ UI_SPLevelMenu_Cache();
+
+ levelMenuInfo.item_banner.generic.type = MTYPE_BTEXT;
+ levelMenuInfo.item_banner.generic.x = 320;
+ levelMenuInfo.item_banner.generic.y = 16;
+ levelMenuInfo.item_banner.string = "CHOOSE LEVEL";
+ levelMenuInfo.item_banner.color = color_red;
+ levelMenuInfo.item_banner.style = UI_CENTER;
+
+ levelMenuInfo.item_leftarrow.generic.type = MTYPE_BITMAP;
+ levelMenuInfo.item_leftarrow.generic.name = ART_ARROW;
+ levelMenuInfo.item_leftarrow.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ levelMenuInfo.item_leftarrow.generic.x = 18;
+ levelMenuInfo.item_leftarrow.generic.y = 64;
+ levelMenuInfo.item_leftarrow.generic.callback = UI_SPLevelMenu_LeftArrowEvent;
+ levelMenuInfo.item_leftarrow.generic.id = ID_LEFTARROW;
+ levelMenuInfo.item_leftarrow.width = 16;
+ levelMenuInfo.item_leftarrow.height = 114;
+ levelMenuInfo.item_leftarrow.focuspic = ART_ARROW_FOCUS;
+
+ levelMenuInfo.item_maps[0].generic.type = MTYPE_BITMAP;
+ levelMenuInfo.item_maps[0].generic.name = levelMenuInfo.levelPicNames[0];
+ levelMenuInfo.item_maps[0].generic.flags = QMF_LEFT_JUSTIFY;
+ levelMenuInfo.item_maps[0].generic.x = 46;
+ levelMenuInfo.item_maps[0].generic.y = 64;
+ levelMenuInfo.item_maps[0].generic.id = ID_PICTURE0;
+ levelMenuInfo.item_maps[0].generic.callback = UI_SPLevelMenu_LevelEvent;
+ levelMenuInfo.item_maps[0].width = 128;
+ levelMenuInfo.item_maps[0].height = 96;
+
+ levelMenuInfo.item_maps[1].generic.type = MTYPE_BITMAP;
+ levelMenuInfo.item_maps[1].generic.name = levelMenuInfo.levelPicNames[1];
+ levelMenuInfo.item_maps[1].generic.flags = QMF_LEFT_JUSTIFY;
+ levelMenuInfo.item_maps[1].generic.x = 186;
+ levelMenuInfo.item_maps[1].generic.y = 64;
+ levelMenuInfo.item_maps[1].generic.id = ID_PICTURE1;
+ levelMenuInfo.item_maps[1].generic.callback = UI_SPLevelMenu_LevelEvent;
+ levelMenuInfo.item_maps[1].width = 128;
+ levelMenuInfo.item_maps[1].height = 96;
+
+ levelMenuInfo.item_maps[2].generic.type = MTYPE_BITMAP;
+ levelMenuInfo.item_maps[2].generic.name = levelMenuInfo.levelPicNames[2];
+ levelMenuInfo.item_maps[2].generic.flags = QMF_LEFT_JUSTIFY;
+ levelMenuInfo.item_maps[2].generic.x = 326;
+ levelMenuInfo.item_maps[2].generic.y = 64;
+ levelMenuInfo.item_maps[2].generic.id = ID_PICTURE2;
+ levelMenuInfo.item_maps[2].generic.callback = UI_SPLevelMenu_LevelEvent;
+ levelMenuInfo.item_maps[2].width = 128;
+ levelMenuInfo.item_maps[2].height = 96;
+
+ levelMenuInfo.item_maps[3].generic.type = MTYPE_BITMAP;
+ levelMenuInfo.item_maps[3].generic.name = levelMenuInfo.levelPicNames[3];
+ levelMenuInfo.item_maps[3].generic.flags = QMF_LEFT_JUSTIFY;
+ levelMenuInfo.item_maps[3].generic.x = 466;
+ levelMenuInfo.item_maps[3].generic.y = 64;
+ levelMenuInfo.item_maps[3].generic.id = ID_PICTURE3;
+ levelMenuInfo.item_maps[3].generic.callback = UI_SPLevelMenu_LevelEvent;
+ levelMenuInfo.item_maps[3].width = 128;
+ levelMenuInfo.item_maps[3].height = 96;
+
+ levelMenuInfo.item_rightarrow.generic.type = MTYPE_BITMAP;
+ levelMenuInfo.item_rightarrow.generic.name = ART_ARROW;
+ levelMenuInfo.item_rightarrow.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ levelMenuInfo.item_rightarrow.generic.x = 606;
+ levelMenuInfo.item_rightarrow.generic.y = 64;
+ levelMenuInfo.item_rightarrow.generic.callback = UI_SPLevelMenu_RightArrowEvent;
+ levelMenuInfo.item_rightarrow.generic.id = ID_RIGHTARROW;
+ levelMenuInfo.item_rightarrow.width = -16;
+ levelMenuInfo.item_rightarrow.height = 114;
+ levelMenuInfo.item_rightarrow.focuspic = ART_ARROW_FOCUS;
+
+ trap_Cvar_VariableStringBuffer( "model", levelMenuInfo.playerModel, sizeof(levelMenuInfo.playerModel) );
+ PlayerIcon( levelMenuInfo.playerModel, levelMenuInfo.playerPicName, sizeof(levelMenuInfo.playerPicName) );
+ levelMenuInfo.item_player.generic.type = MTYPE_BITMAP;
+ levelMenuInfo.item_player.generic.name = levelMenuInfo.playerPicName;
+ levelMenuInfo.item_player.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY;
+ levelMenuInfo.item_player.generic.x = 288;
+ levelMenuInfo.item_player.generic.y = AWARDS_Y;
+ levelMenuInfo.item_player.generic.id = ID_PLAYERPIC;
+ levelMenuInfo.item_player.generic.callback = UI_SPLevelMenu_PlayerEvent;
+ levelMenuInfo.item_player.width = 64;
+ levelMenuInfo.item_player.height = 64;
+
+ for( n = 0; n < 6; n++ ) {
+ levelMenuInfo.awardLevels[n] = UI_GetAwardLevel( n );
+ }
+ levelMenuInfo.awardLevels[AWARD_FRAGS] = 100 * (levelMenuInfo.awardLevels[AWARD_FRAGS] / 100);
+
+ y = AWARDS_Y;
+ count = 0;
+ for( n = 0; n < 6; n++ ) {
+ if( levelMenuInfo.awardLevels[n] ) {
+ if( count & 1 ) {
+ x = 224 - (count - 1 ) / 2 * (48 + 16);
+ }
+ else {
+ x = 368 + count / 2 * (48 + 16);
+ }
+
+ levelMenuInfo.item_awards[count].generic.type = MTYPE_BITMAP;
+ levelMenuInfo.item_awards[count].generic.name = ui_medalPicNames[n];
+ levelMenuInfo.item_awards[count].generic.flags = QMF_LEFT_JUSTIFY|QMF_SILENT|QMF_MOUSEONLY;
+ levelMenuInfo.item_awards[count].generic.x = x;
+ levelMenuInfo.item_awards[count].generic.y = y;
+ levelMenuInfo.item_awards[count].generic.id = ID_AWARD1 + n;
+ levelMenuInfo.item_awards[count].generic.callback = UI_SPLevelMenu_AwardEvent;
+ levelMenuInfo.item_awards[count].width = 48;
+ levelMenuInfo.item_awards[count].height = 48;
+ count++;
+ }
+ }
+
+ levelMenuInfo.item_back.generic.type = MTYPE_BITMAP;
+ levelMenuInfo.item_back.generic.name = ART_BACK0;
+ levelMenuInfo.item_back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ levelMenuInfo.item_back.generic.x = 0;
+ levelMenuInfo.item_back.generic.y = 480-64;
+ levelMenuInfo.item_back.generic.callback = UI_SPLevelMenu_BackEvent;
+ levelMenuInfo.item_back.generic.id = ID_BACK;
+ levelMenuInfo.item_back.width = 128;
+ levelMenuInfo.item_back.height = 64;
+ levelMenuInfo.item_back.focuspic = ART_BACK1;
+
+ levelMenuInfo.item_reset.generic.type = MTYPE_BITMAP;
+ levelMenuInfo.item_reset.generic.name = ART_RESET0;
+ levelMenuInfo.item_reset.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ levelMenuInfo.item_reset.generic.x = 170;
+ levelMenuInfo.item_reset.generic.y = 480-64;
+ levelMenuInfo.item_reset.generic.callback = UI_SPLevelMenu_ResetEvent;
+ levelMenuInfo.item_reset.generic.id = ID_RESET;
+ levelMenuInfo.item_reset.width = 128;
+ levelMenuInfo.item_reset.height = 64;
+ levelMenuInfo.item_reset.focuspic = ART_RESET1;
+
+ levelMenuInfo.item_custom.generic.type = MTYPE_BITMAP;
+ levelMenuInfo.item_custom.generic.name = ART_CUSTOM0;
+ levelMenuInfo.item_custom.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ levelMenuInfo.item_custom.generic.x = 342;
+ levelMenuInfo.item_custom.generic.y = 480-64;
+ levelMenuInfo.item_custom.generic.callback = UI_SPLevelMenu_CustomEvent;
+ levelMenuInfo.item_custom.generic.id = ID_CUSTOM;
+ levelMenuInfo.item_custom.width = 128;
+ levelMenuInfo.item_custom.height = 64;
+ levelMenuInfo.item_custom.focuspic = ART_CUSTOM1;
+
+ levelMenuInfo.item_next.generic.type = MTYPE_BITMAP;
+ levelMenuInfo.item_next.generic.name = ART_FIGHT0;
+ levelMenuInfo.item_next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
+ levelMenuInfo.item_next.generic.x = 640;
+ levelMenuInfo.item_next.generic.y = 480-64;
+ levelMenuInfo.item_next.generic.callback = UI_SPLevelMenu_NextEvent;
+ levelMenuInfo.item_next.generic.id = ID_NEXT;
+ levelMenuInfo.item_next.width = 128;
+ levelMenuInfo.item_next.height = 64;
+ levelMenuInfo.item_next.focuspic = ART_FIGHT1;
+
+ levelMenuInfo.item_null.generic.type = MTYPE_BITMAP;
+ levelMenuInfo.item_null.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;
+ levelMenuInfo.item_null.generic.x = 0;
+ levelMenuInfo.item_null.generic.y = 0;
+ levelMenuInfo.item_null.width = 640;
+ levelMenuInfo.item_null.height = 480;
+
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_banner );
+
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_leftarrow );
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[0] );
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[1] );
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[2] );
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[3] );
+ levelMenuInfo.item_maps[0].generic.bottom += 18;
+ levelMenuInfo.item_maps[1].generic.bottom += 18;
+ levelMenuInfo.item_maps[2].generic.bottom += 18;
+ levelMenuInfo.item_maps[3].generic.bottom += 18;
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_rightarrow );
+
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_player );
+
+ for( n = 0; n < count; n++ ) {
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_awards[n] );
+ }
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_back );
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_reset );
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_custom );
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_next );
+ Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_null );
+
+ trap_Cvar_VariableStringBuffer( "ui_spSelection", buf, sizeof(buf) );
+ if( *buf ) {
+ n = atoi( buf );
+ selectedArenaSet = n / ARENAS_PER_TIER;
+ selectedArena = n % ARENAS_PER_TIER;
+ }
+ else {
+ selectedArenaSet = currentSet;
+ selectedArena = currentGame;
+ }
+
+ UI_SPLevelMenu_SetMenuItems();
+}
+
+
+/*
+=================
+UI_SPLevelMenu
+=================
+*/
+void UI_SPLevelMenu( void ) {
+ int level;
+ int trainingLevel;
+ const char *arenaInfo;
+
+ trainingTier = -1;
+ arenaInfo = UI_GetSpecialArenaInfo( "training" );
+ if( arenaInfo ) {
+ minTier = trainingTier;
+ trainingLevel = atoi( Info_ValueForKey( arenaInfo, "num" ) );
+ }
+ else {
+ minTier = 0;
+ trainingLevel = -2;
+ }
+
+ finalTier = UI_GetNumSPTiers();
+ arenaInfo = UI_GetSpecialArenaInfo( "final" );
+ if( arenaInfo ) {
+ maxTier = finalTier;
+ }
+ else {
+ maxTier = finalTier - 1;
+ if( maxTier < minTier ) {
+ maxTier = minTier;
+ }
+ }
+
+ level = UI_GetCurrentGame();
+ if ( level == -1 ) {
+ level = UI_GetNumSPArenas() - 1;
+ if( maxTier == finalTier ) {
+ level++;
+ }
+ }
+
+ if( level == trainingLevel ) {
+ currentSet = -1;
+ currentGame = 0;
+ }
+ else {
+ currentSet = level / ARENAS_PER_TIER;
+ currentGame = level % ARENAS_PER_TIER;
+ }
+
+ UI_SPLevelMenu_Init();
+ UI_PushMenu( &levelMenuInfo.menu );
+ Menu_SetCursorToItem( &levelMenuInfo.menu, &levelMenuInfo.item_next );
+}
+
+
+/*
+=================
+UI_SPLevelMenu_f
+=================
+*/
+void UI_SPLevelMenu_f( void ) {
+ trap_Key_SetCatcher( KEYCATCH_UI );
+ uis.menusp = 0;
+ UI_SPLevelMenu();
+}
+
+
+/*
+=================
+UI_SPLevelMenu_ReInit
+=================
+*/
+void UI_SPLevelMenu_ReInit( void ) {
+ levelMenuInfo.reinit = qtrue;
+}
diff --git a/game/code/q3_ui/ui_sppostgame.c b/code/q3_ui/ui_sppostgame.c
similarity index 100%
rename from game/code/q3_ui/ui_sppostgame.c
rename to code/q3_ui/ui_sppostgame.c
diff --git a/game/code/q3_ui/ui_spreset.c b/code/q3_ui/ui_spreset.c
similarity index 100%
rename from game/code/q3_ui/ui_spreset.c
rename to code/q3_ui/ui_spreset.c
diff --git a/game/code/q3_ui/ui_spskill.c b/code/q3_ui/ui_spskill.c
similarity index 100%
rename from game/code/q3_ui/ui_spskill.c
rename to code/q3_ui/ui_spskill.c
diff --git a/code/q3_ui/ui_startserver.c b/code/q3_ui/ui_startserver.c
new file mode 100644
index 0000000..382a4ca
--- /dev/null
+++ b/code/q3_ui/ui_startserver.c
@@ -0,0 +1,2348 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+/*
+=============================================================================
+
+START SERVER MENU *****
+
+=============================================================================
+*/
+
+
+#include "ui_local.h"
+
+
+#define GAMESERVER_BACK0 "menu/art_blueish/back_0"
+#define GAMESERVER_BACK1 "menu/art_blueish/back_1"
+#define GAMESERVER_NEXT0 "menu/art_blueish/next_0"
+#define GAMESERVER_NEXT1 "menu/art_blueish/next_1"
+#define GAMESERVER_FRAMEL "menu/art_blueish/frame2_l"
+#define GAMESERVER_FRAMER "menu/art_blueish/frame1_r"
+#define GAMESERVER_SELECT "menu/art_blueish/maps_select"
+#define GAMESERVER_SELECTED "menu/art_blueish/maps_selected"
+#define GAMESERVER_FIGHT0 "menu/art_blueish/fight_0"
+#define GAMESERVER_FIGHT1 "menu/art_blueish/fight_1"
+#define GAMESERVER_UNKNOWNMAP "menu/art/unknownmap"
+#define GAMESERVER_ARROWS "menu/art_blueish/gs_arrows_0"
+#define GAMESERVER_ARROWSL "menu/art_blueish/gs_arrows_l"
+#define GAMESERVER_ARROWSR "menu/art_blueish/gs_arrows_r"
+
+#define MAX_MAPROWS 4
+#define MAX_MAPCOLS 2
+#define MAX_MAPSPERPAGE (MAX_MAPROWS * MAX_MAPCOLS)
+
+//#define MAX_SERVERSTEXT 8192
+
+#define MAX_SERVERMAPS MAX_ARENAS
+#define MAX_NAMELENGTH 16
+
+#define ID_GAMETYPE 10
+#define ID_PICTURES 11 // 12, 13, 14, 15, 16, 17, 18
+#define ID_PREVPAGE 19
+#define ID_NEXTPAGE 20
+#define ID_STARTSERVERBACK 21
+#define ID_STARTSERVERNEXT 22
+
+#define ID_AUTONEXTMAP 23
+
+typedef struct {
+ menuframework_s menu;
+
+ menutext_s banner;
+ menubitmap_s framel;
+ menubitmap_s framer;
+
+ menulist_s gametype;
+ menuradiobutton_s autonextmap;
+ menubitmap_s mappics[MAX_MAPSPERPAGE];
+ menubitmap_s mapbuttons[MAX_MAPSPERPAGE];
+ menubitmap_s arrows;
+ menubitmap_s prevpage;
+ menubitmap_s nextpage;
+ menubitmap_s back;
+ menubitmap_s next;
+
+ menutext_s mapname;
+ menubitmap_s item_null;
+
+ qboolean multiplayer;
+ int currentmap;
+ int nummaps;
+ int page;
+ int maxpages;
+ int maplist[MAX_SERVERMAPS];
+} startserver_t;
+
+static startserver_t s_startserver;
+
+static const char *gametype_items[] = {
+ "Free For All",
+ "Team Deathmatch",
+ "Tournament",
+ "Capture the Flag",
+ "One Flag Capture",
+ "Overload",
+ "Harvester",
+ "Elimination",
+ "CTF Elimination",
+ "Last Man Standing",
+ "Double Domination",
+ "Domination",
+ NULL
+};
+
+static int gametype_remap[] = {
+ GT_FFA,
+ GT_TEAM,
+ GT_TOURNAMENT,
+ GT_CTF,
+ GT_1FCTF,
+ GT_OBELISK,
+ GT_HARVESTER,
+ GT_ELIMINATION,
+ GT_CTF_ELIMINATION,
+ GT_LMS,
+ GT_DOUBLE_D,
+ GT_DOMINATION };
+
+static int gametype_remap2[] = {
+ 0,
+ 2,
+ 0,
+ 1,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11 }; //this works and should increment for more gametypes
+
+static void UI_ServerOptionsMenu( qboolean multiplayer );
+
+
+/*
+=================
+GametypeBits from arenas.txt + .arena files
+=================
+*/
+static int GametypeBits( char *string ) {
+ int bits;
+ char *p;
+ char *token;
+
+ bits = 0;
+ p = string;
+ while( 1 ) {
+ token = COM_ParseExt( &p, qfalse );
+ if( token[0] == 0 ) {
+ break;
+ }
+
+ if( Q_stricmp( token, "ffa" ) == 0 ) {
+ bits |= 1 << GT_FFA;
+ continue;
+ }
+
+ if( Q_stricmp( token, "tourney" ) == 0 ) {
+ bits |= 1 << GT_TOURNAMENT;
+ continue;
+ }
+
+ if( Q_stricmp( token, "single" ) == 0 ) {
+ bits |= 1 << GT_SINGLE_PLAYER;
+ continue;
+ }
+
+ if( Q_stricmp( token, "team" ) == 0 ) {
+ bits |= 1 << GT_TEAM;
+ continue;
+ }
+
+ if( Q_stricmp( token, "ctf" ) == 0 ) {
+ bits |= 1 << GT_CTF;
+ continue;
+ }
+
+ if( Q_stricmp( token, "oneflag" ) == 0 ) {
+ bits |= 1 << GT_1FCTF;
+ continue;
+ }
+
+ if( Q_stricmp( token, "overload" ) == 0 ) {
+ bits |= 1 << GT_OBELISK;
+ continue;
+ }
+
+ if( Q_stricmp( token, "harvester" ) == 0 ) {
+ bits |= 1 << GT_HARVESTER;
+ continue;
+ }
+
+ if( Q_stricmp( token, "elimination" ) == 0 ) {
+ bits |= 1 << GT_ELIMINATION;
+ continue;
+ }
+
+ if( Q_stricmp( token, "ctfelimination" ) == 0 ) {
+ bits |= 1 << GT_CTF_ELIMINATION;
+ continue;
+ }
+
+ if( Q_stricmp( token, "lms" ) == 0 ) {
+ bits |= 1 << GT_LMS;
+ continue;
+ }
+ if( Q_stricmp( token, "dd" ) == 0 ) {
+ bits |= 1 << GT_DOUBLE_D;
+ continue;
+ }
+
+ if( Q_stricmp( token, "dom" ) == 0 ) {
+ bits |= 1 << GT_DOMINATION;
+ continue;
+ }
+}
+ return bits;
+}
+
+
+/*
+=================
+StartServer_Update
+=================
+*/
+static void StartServer_Update( void ) {
+ int i;
+ int top;
+ static char picname[MAX_MAPSPERPAGE][64];
+ const char *info;
+ char mapname[MAX_NAMELENGTH];
+
+ top = s_startserver.page*MAX_MAPSPERPAGE;
+
+ for (i=0; i<MAX_MAPSPERPAGE; i++)
+ {
+ if (top+i >= s_startserver.nummaps)
+ break;
+
+ info = UI_GetArenaInfoByNumber( s_startserver.maplist[ top + i ]);
+ Q_strncpyz( mapname, Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
+ Q_strupr( mapname );
+
+ Com_sprintf( picname[i], sizeof(picname[i]), "levelshots/%s", mapname );
+
+ s_startserver.mappics[i].generic.flags &= ~((unsigned int)QMF_HIGHLIGHT);
+ s_startserver.mappics[i].generic.name = picname[i];
+ s_startserver.mappics[i].shader = 0;
+
+ // reset
+ s_startserver.mapbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
+ s_startserver.mapbuttons[i].generic.flags &= ~((unsigned int)QMF_INACTIVE);
+ }
+
+ for (; i<MAX_MAPSPERPAGE; i++)
+ {
+ s_startserver.mappics[i].generic.flags &= ~((unsigned int)QMF_HIGHLIGHT);
+ s_startserver.mappics[i].generic.name = NULL;
+ s_startserver.mappics[i].shader = 0;
+
+ // disable
+ s_startserver.mapbuttons[i].generic.flags &= ~((unsigned int)QMF_PULSEIFFOCUS);
+ s_startserver.mapbuttons[i].generic.flags |= QMF_INACTIVE;
+ }
+
+
+ // no servers to start
+ if( !s_startserver.nummaps ) {
+ s_startserver.next.generic.flags |= QMF_INACTIVE;
+
+ // set the map name
+ strcpy( s_startserver.mapname.string, "NO MAPS FOUND" );
+ }
+ else {
+ // set the highlight
+ s_startserver.next.generic.flags &= ~((unsigned int)QMF_INACTIVE);
+ i = s_startserver.currentmap - top;
+ if ( i >=0 && i < MAX_MAPSPERPAGE )
+ {
+ s_startserver.mappics[i].generic.flags |= QMF_HIGHLIGHT;
+ s_startserver.mapbuttons[i].generic.flags &= ~((unsigned int)QMF_PULSEIFFOCUS);
+ }
+
+ // set the map name
+ info = UI_GetArenaInfoByNumber( s_startserver.maplist[ s_startserver.currentmap ]);
+ Q_strncpyz( s_startserver.mapname.string, Info_ValueForKey( info, "map" ), MAX_NAMELENGTH);
+ }
+
+ Q_strupr( s_startserver.mapname.string );
+}
+
+
+/*
+=================
+StartServer_MapEvent
+=================
+*/
+static void StartServer_MapEvent( void* ptr, int event ) {
+ if( event != QM_ACTIVATED) {
+ return;
+ }
+
+ s_startserver.currentmap = (s_startserver.page*MAX_MAPSPERPAGE) + (((menucommon_s*)ptr)->id - ID_PICTURES);
+ StartServer_Update();
+}
+
+
+/*
+=================
+StartServer_GametypeEvent
+=================
+*/
+static void StartServer_GametypeEvent( void* ptr, int event ) {
+ int i;
+ int count;
+ int gamebits;
+ int matchbits;
+ const char *info;
+
+ if( event != QM_ACTIVATED) {
+ return;
+ }
+
+ count = UI_GetNumArenas();
+ s_startserver.nummaps = 0;
+ matchbits = 1 << gametype_remap[s_startserver.gametype.curvalue];
+ if( gametype_remap[s_startserver.gametype.curvalue] == GT_FFA ) {
+ matchbits |= ( 1 << GT_SINGLE_PLAYER );
+ }
+ for( i = 0; i < count; i++ ) {
+ info = UI_GetArenaInfoByNumber( i );
+
+ gamebits = GametypeBits( Info_ValueForKey( info, "type") );
+ if( !( gamebits & matchbits ) ) {
+ continue;
+ }
+
+ s_startserver.maplist[s_startserver.nummaps] = i;
+ s_startserver.nummaps++;
+ }
+ s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE;
+ s_startserver.page = 0;
+ s_startserver.currentmap = 0;
+
+ StartServer_Update();
+}
+
+
+/*
+=================
+StartServer_MenuEvent
+=================
+*/
+static void StartServer_MenuEvent( void* ptr, int event ) {
+ if( event != QM_ACTIVATED ) {
+ return;
+ }
+
+ switch( ((menucommon_s*)ptr)->id ) {
+ case ID_PREVPAGE:
+ if( s_startserver.page > 0 ) {
+ s_startserver.page--;
+ StartServer_Update();
+ }
+ break;
+
+ case ID_NEXTPAGE:
+ if( s_startserver.page < s_startserver.maxpages - 1 ) {
+ s_startserver.page++;
+ StartServer_Update();
+ }
+ break;
+
+ case ID_STARTSERVERNEXT:
+ trap_Cvar_SetValue( "g_gameType", gametype_remap[s_startserver.gametype.curvalue] );
+ UI_ServerOptionsMenu( s_startserver.multiplayer );
+ break;
+
+ case ID_AUTONEXTMAP:
+ //trap_Cvar_SetValue( "cg_alwaysWeaponBar", s_preferences.alwaysweaponbar.curvalue );
+ trap_Cvar_SetValue( "g_autonextmap", s_startserver.autonextmap.curvalue );
+ break;
+
+ case ID_STARTSERVERBACK:
+ UI_PopMenu();
+ break;
+ }
+}
+
+
+/*
+===============
+StartServer_LevelshotDraw
+===============
+*/
+static void StartServer_LevelshotDraw( void *self ) {
+ menubitmap_s *b;
+ int x;
+ int y;
+ int w;
+ int h;
+ int n;
+ const char *info;
+
+ b = (menubitmap_s *)self;
+
+ if( !b->generic.name ) {
+ return;
+ }
+
+ if( b->generic.name && !b->shader ) {
+ b->shader = trap_R_RegisterShaderNoMip( b->generic.name );
+ if( !b->shader && b->errorpic ) {
+ b->shader = trap_R_RegisterShaderNoMip( b->errorpic );
+ }
+ }
+
+ if( b->focuspic && !b->focusshader ) {
+ b->focusshader = trap_R_RegisterShaderNoMip( b->focuspic );
+ }
+
+ x = b->generic.x;
+ y = b->generic.y;
+ w = b->width;
+ h = b->height;
+ if( b->shader ) {
+ UI_DrawHandlePic( x, y, w, h, b->shader );
+ }
+
+ x = b->generic.x;
+ y = b->generic.y + b->height;
+ UI_FillRect( x, y, b->width, 28, colorBlack );
+
+ x += b->width / 2;
+ y += 4;
+ n = s_startserver.page * MAX_MAPSPERPAGE + b->generic.id - ID_PICTURES;
+
+ info = UI_GetArenaInfoByNumber( s_startserver.maplist[ n ]);
+ UI_DrawString( x, y, Info_ValueForKey( info, "map" ), UI_CENTER|UI_SMALLFONT, color_orange );
+
+ x = b->generic.x;
+ y = b->generic.y;
+ w = b->width;
+ h = b->height + 28;
+ if( b->generic.flags & QMF_HIGHLIGHT ) {
+ UI_DrawHandlePic( x, y, w, h, b->focusshader );
+ }
+}
+
+
+/*
+=================
+StartServer_MenuInit
+=================
+*/
+static void StartServer_MenuInit( void ) {
+ int i;
+ int x;
+ int y;
+ static char mapnamebuffer[64];
+
+ // zero set all our globals
+ memset( &s_startserver, 0 ,sizeof(startserver_t) );
+
+ StartServer_Cache();
+
+ s_startserver.autonextmap.curvalue = trap_Cvar_VariableValue( "g_autonextmap" ) != 0;
+
+ s_startserver.menu.wrapAround = qtrue;
+ s_startserver.menu.fullscreen = qtrue;
+
+ s_startserver.banner.generic.type = MTYPE_BTEXT;
+ s_startserver.banner.generic.x = 320;
+ s_startserver.banner.generic.y = 16;
+ s_startserver.banner.string = "GAME SERVER";
+ s_startserver.banner.color = color_white;
+ s_startserver.banner.style = UI_CENTER;
+
+ s_startserver.framel.generic.type = MTYPE_BITMAP;
+ s_startserver.framel.generic.name = GAMESERVER_FRAMEL;
+ s_startserver.framel.generic.flags = QMF_INACTIVE;
+ s_startserver.framel.generic.x = 0;
+ s_startserver.framel.generic.y = 78;
+ s_startserver.framel.width = 256;
+ s_startserver.framel.height = 329;
+
+ s_startserver.framer.generic.type = MTYPE_BITMAP;
+ s_startserver.framer.generic.name = GAMESERVER_FRAMER;
+ s_startserver.framer.generic.flags = QMF_INACTIVE;
+ s_startserver.framer.generic.x = 376;
+ s_startserver.framer.generic.y = 76;
+ s_startserver.framer.width = 256;
+ s_startserver.framer.height = 334;
+
+ s_startserver.autonextmap.generic.type = MTYPE_RADIOBUTTON;
+ s_startserver.autonextmap.generic.name = "Auto change map:";
+ s_startserver.autonextmap.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_startserver.autonextmap.generic.callback = StartServer_MenuEvent;
+ s_startserver.autonextmap.generic.id = ID_AUTONEXTMAP;
+ s_startserver.autonextmap.generic.x = 320 +24;
+ s_startserver.autonextmap.generic.y = 368;
+
+ s_startserver.gametype.generic.type = MTYPE_SPINCONTROL;
+ s_startserver.gametype.generic.name = "Game Type:";
+ s_startserver.gametype.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_startserver.gametype.generic.callback = StartServer_GametypeEvent;
+ s_startserver.gametype.generic.id = ID_GAMETYPE;
+ s_startserver.gametype.generic.x = 320 - 24;
+ s_startserver.gametype.generic.y = 70;
+ s_startserver.gametype.itemnames = gametype_items;
+
+ for (i=0; i<MAX_MAPSPERPAGE; i++)
+ {
+ //x = (i % MAX_MAPCOLS) * (128+8) + 188;
+ //y = (i / MAX_MAPROWS) * (128+8) + 96;
+ x = (640-MAX_MAPROWS*140)/2 + ( (i % MAX_MAPROWS) * 140 );
+ y = 96 + ( (i / MAX_MAPROWS) * 140 );
+
+ s_startserver.mappics[i].generic.type = MTYPE_BITMAP;
+ s_startserver.mappics[i].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
+ s_startserver.mappics[i].generic.x = x;
+ s_startserver.mappics[i].generic.y = y;
+ s_startserver.mappics[i].generic.id = ID_PICTURES+i;
+ s_startserver.mappics[i].width = 128;
+ s_startserver.mappics[i].height = 96;
+ s_startserver.mappics[i].focuspic = GAMESERVER_SELECTED;
+ s_startserver.mappics[i].errorpic = GAMESERVER_UNKNOWNMAP;
+ s_startserver.mappics[i].generic.ownerdraw = StartServer_LevelshotDraw;
+
+ s_startserver.mapbuttons[i].generic.type = MTYPE_BITMAP;
+ s_startserver.mapbuttons[i].generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_NODEFAULTINIT;
+ s_startserver.mapbuttons[i].generic.id = ID_PICTURES+i;
+ s_startserver.mapbuttons[i].generic.callback = StartServer_MapEvent;
+ s_startserver.mapbuttons[i].generic.x = x - 30;
+ s_startserver.mapbuttons[i].generic.y = y - 32;
+ s_startserver.mapbuttons[i].width = 256;
+ s_startserver.mapbuttons[i].height = 248;
+ s_startserver.mapbuttons[i].generic.left = x;
+ s_startserver.mapbuttons[i].generic.top = y;
+ s_startserver.mapbuttons[i].generic.right = x + 128;
+ s_startserver.mapbuttons[i].generic.bottom = y + 128;
+ s_startserver.mapbuttons[i].focuspic = GAMESERVER_SELECT;
+ }
+
+ s_startserver.arrows.generic.type = MTYPE_BITMAP;
+ s_startserver.arrows.generic.name = GAMESERVER_ARROWS;
+ s_startserver.arrows.generic.flags = QMF_INACTIVE;
+ s_startserver.arrows.generic.x = 260;
+ s_startserver.arrows.generic.y = 400;
+ s_startserver.arrows.width = 128;
+ s_startserver.arrows.height = 32;
+
+ s_startserver.prevpage.generic.type = MTYPE_BITMAP;
+ s_startserver.prevpage.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_startserver.prevpage.generic.callback = StartServer_MenuEvent;
+ s_startserver.prevpage.generic.id = ID_PREVPAGE;
+ s_startserver.prevpage.generic.x = 260;
+ s_startserver.prevpage.generic.y = 400;
+ s_startserver.prevpage.width = 64;
+ s_startserver.prevpage.height = 32;
+ s_startserver.prevpage.focuspic = GAMESERVER_ARROWSL;
+
+ s_startserver.nextpage.generic.type = MTYPE_BITMAP;
+ s_startserver.nextpage.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_startserver.nextpage.generic.callback = StartServer_MenuEvent;
+ s_startserver.nextpage.generic.id = ID_NEXTPAGE;
+ s_startserver.nextpage.generic.x = 321;
+ s_startserver.nextpage.generic.y = 400;
+ s_startserver.nextpage.width = 64;
+ s_startserver.nextpage.height = 32;
+ s_startserver.nextpage.focuspic = GAMESERVER_ARROWSR;
+
+ s_startserver.mapname.generic.type = MTYPE_PTEXT;
+ s_startserver.mapname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
+ s_startserver.mapname.generic.x = 320;
+ s_startserver.mapname.generic.y = 440;
+ s_startserver.mapname.string = mapnamebuffer;
+ s_startserver.mapname.style = UI_CENTER|UI_BIGFONT;
+ s_startserver.mapname.color = text_color_normal;
+
+ s_startserver.back.generic.type = MTYPE_BITMAP;
+ s_startserver.back.generic.name = GAMESERVER_BACK0;
+ s_startserver.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_startserver.back.generic.callback = StartServer_MenuEvent;
+ s_startserver.back.generic.id = ID_STARTSERVERBACK;
+ s_startserver.back.generic.x = 0;
+ s_startserver.back.generic.y = 480-64;
+ s_startserver.back.width = 128;
+ s_startserver.back.height = 64;
+ s_startserver.back.focuspic = GAMESERVER_BACK1;
+
+ s_startserver.next.generic.type = MTYPE_BITMAP;
+ s_startserver.next.generic.name = GAMESERVER_NEXT0;
+ s_startserver.next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_startserver.next.generic.callback = StartServer_MenuEvent;
+ s_startserver.next.generic.id = ID_STARTSERVERNEXT;
+ s_startserver.next.generic.x = 640;
+ s_startserver.next.generic.y = 480-64;
+ s_startserver.next.width = 128;
+ s_startserver.next.height = 64;
+ s_startserver.next.focuspic = GAMESERVER_NEXT1;
+
+ s_startserver.item_null.generic.type = MTYPE_BITMAP;
+ s_startserver.item_null.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;
+ s_startserver.item_null.generic.x = 0;
+ s_startserver.item_null.generic.y = 0;
+ s_startserver.item_null.width = 640;
+ s_startserver.item_null.height = 480;
+
+ Menu_AddItem( &s_startserver.menu, &s_startserver.banner );
+ Menu_AddItem( &s_startserver.menu, &s_startserver.framel );
+ Menu_AddItem( &s_startserver.menu, &s_startserver.framer );
+
+ Menu_AddItem( &s_startserver.menu, &s_startserver.gametype );
+ Menu_AddItem( &s_startserver.menu, &s_startserver.autonextmap );
+ for (i=0; i<MAX_MAPSPERPAGE; i++)
+ {
+ Menu_AddItem( &s_startserver.menu, &s_startserver.mappics[i] );
+ Menu_AddItem( &s_startserver.menu, &s_startserver.mapbuttons[i] );
+ }
+
+ Menu_AddItem( &s_startserver.menu, &s_startserver.arrows );
+ Menu_AddItem( &s_startserver.menu, &s_startserver.prevpage );
+ Menu_AddItem( &s_startserver.menu, &s_startserver.nextpage );
+ Menu_AddItem( &s_startserver.menu, &s_startserver.back );
+ Menu_AddItem( &s_startserver.menu, &s_startserver.next );
+ Menu_AddItem( &s_startserver.menu, &s_startserver.mapname );
+ Menu_AddItem( &s_startserver.menu, &s_startserver.item_null );
+
+ StartServer_GametypeEvent( NULL, QM_ACTIVATED );
+}
+
+
+/*
+=================
+StartServer_Cache
+=================
+*/
+void StartServer_Cache( void )
+{
+ int i;
+ const char *info;
+ qboolean precache;
+ char picname[64];
+ char mapname[ MAX_NAMELENGTH ];
+
+ trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 );
+ trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 );
+ trap_R_RegisterShaderNoMip( GAMESERVER_NEXT0 );
+ trap_R_RegisterShaderNoMip( GAMESERVER_NEXT1 );
+ trap_R_RegisterShaderNoMip( GAMESERVER_FRAMEL );
+ trap_R_RegisterShaderNoMip( GAMESERVER_FRAMER );
+ trap_R_RegisterShaderNoMip( GAMESERVER_SELECT );
+ trap_R_RegisterShaderNoMip( GAMESERVER_SELECTED );
+ trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );
+ trap_R_RegisterShaderNoMip( GAMESERVER_ARROWS );
+ trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSL );
+ trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSR );
+
+ precache = trap_Cvar_VariableValue("com_buildscript");
+
+ if( precache )
+ {
+ for( i = 0; i < UI_GetNumArenas(); i++ )
+ {
+ info = UI_GetArenaInfoByNumber( i );
+ Q_strncpyz( mapname, Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
+ Q_strupr( mapname );
+
+ Com_sprintf( picname, sizeof(picname), "levelshots/%s", mapname );
+ trap_R_RegisterShaderNoMip(picname);
+ }
+ }
+}
+
+
+/*
+=================
+UI_StartServerMenu
+=================
+*/
+void UI_StartServerMenu( qboolean multiplayer ) {
+ StartServer_MenuInit();
+ s_startserver.multiplayer = multiplayer;
+ UI_PushMenu( &s_startserver.menu );
+}
+
+
+
+/*
+=============================================================================
+
+SERVER OPTIONS MENU *****
+
+=============================================================================
+*/
+
+#define ID_PLAYER_TYPE 25
+#define ID_MAXCLIENTS 26
+//#define ID_DEDICATED 27
+#define ID_GO 28
+#define ID_BACK 29
+
+#define PLAYER_SLOTS 12
+
+
+typedef struct {
+ menuframework_s menu;
+
+ menutext_s banner;
+
+ menubitmap_s mappic;
+ menubitmap_s picframe;
+
+// menulist_s dedicated;
+ menufield_s timelimit;
+ menufield_s fraglimit;
+ menufield_s flaglimit;
+ menuradiobutton_s friendlyfire;
+ menufield_s hostname;
+ menuradiobutton_s pure;
+ menuradiobutton_s lan;
+ menulist_s pmove;
+ //Here are the elimination stuff
+ menuradiobutton_s oneway;
+ menuradiobutton_s instantgib;
+ menuradiobutton_s rockets;
+ menulist_s lmsMode;
+ menulist_s botSkill;
+
+ menutext_s player0;
+ menulist_s playerType[PLAYER_SLOTS];
+ menutext_s playerName[PLAYER_SLOTS];
+ menulist_s playerTeam[PLAYER_SLOTS];
+
+ menubitmap_s go;
+ menubitmap_s next;
+ menubitmap_s back;
+
+ qboolean multiplayer;
+ int gametype;
+ char mapnamebuffer[32];
+ char playerNameBuffers[PLAYER_SLOTS][16];
+
+ qboolean newBot;
+ int newBotIndex;
+ char newBotName[16];
+
+ //menulist_s punkbuster;
+} serveroptions_t;
+
+static serveroptions_t s_serveroptions;
+
+/*static const char *dedicated_list[] = {
+ "No",
+ "LAN",
+ "Internet",
+ NULL
+};*/
+
+static const char *playerType_list[] = {
+ "Open",
+ "Bot",
+ "----",
+ NULL
+};
+
+static const char *playerTeam_list[] = {
+ "Blue",
+ "Red",
+ NULL
+};
+
+static const char *botSkill_list[] = {
+ "I Can Win",
+ "Bring It On",
+ "Hurt Me Plenty",
+ "Hardcore",
+ "Nightmare!",
+ NULL
+};
+
+//Elimiantion - LMS mode
+static const char *lmsMode_list[] = {
+ "Round+OT",
+ "Round-OT",
+ "Kill+OT",
+ "Kill-OT",
+ NULL
+};
+
+static const char *pmove_list[] = {
+ "Framerate dependent",
+ "Fixed framerate 125Hz",
+ "Fixed framerate 91Hz",
+ "Accurate",
+ NULL
+};
+
+/*
+=================
+BotAlreadySelected
+=================
+*/
+static qboolean BotAlreadySelected( const char *checkName ) {
+ int n;
+
+ for( n = 1; n < PLAYER_SLOTS; n++ ) {
+ if( s_serveroptions.playerType[n].curvalue != 1 ) {
+ continue;
+ }
+ if( (s_serveroptions.gametype >= GT_TEAM) && s_serveroptions.gametype != GT_LMS &&
+ (s_serveroptions.playerTeam[n].curvalue != s_serveroptions.playerTeam[s_serveroptions.newBotIndex].curvalue ) ) {
+ continue;
+ }
+ if( Q_stricmp( checkName, s_serveroptions.playerNameBuffers[n] ) == 0 ) {
+ return qtrue;
+ }
+ }
+
+ return qfalse;
+}
+
+
+/*
+=================
+ServerOptions_Start
+=================
+*/
+static void ServerOptions_Start( void ) {
+ int timelimit;
+ int fraglimit;
+ int maxclients;
+// int dedicated;
+ int friendlyfire;
+ int flaglimit;
+ int pure;
+ int pmove;
+ int lan;
+ int instantgib;
+ int rockets;
+ int oneway;
+ int lmsMode;
+ int skill;
+ int n;
+ const char *info;
+ char buf[64];
+
+
+ timelimit = atoi( s_serveroptions.timelimit.field.buffer );
+ fraglimit = atoi( s_serveroptions.fraglimit.field.buffer );
+ flaglimit = atoi( s_serveroptions.flaglimit.field.buffer );
+// dedicated = s_serveroptions.dedicated.curvalue;
+ friendlyfire = s_serveroptions.friendlyfire.curvalue;
+ pure = s_serveroptions.pure.curvalue;
+ lan = s_serveroptions.lan.curvalue;
+ pmove = s_serveroptions.pmove.curvalue;
+ instantgib = s_serveroptions.instantgib.curvalue;
+ rockets = s_serveroptions.rockets.curvalue;
+ oneway = s_serveroptions.oneway.curvalue;
+ //Sago: For some reason you need to add 1 to curvalue to get the UI to show the right thing (fixed?)
+ lmsMode = s_serveroptions.lmsMode.curvalue; //+1;
+ skill = s_serveroptions.botSkill.curvalue + 1;
+
+ //set maxclients
+ for( n = 0, maxclients = 0; n < PLAYER_SLOTS; n++ ) {
+ if( s_serveroptions.playerType[n].curvalue == 2 ) {
+ continue;
+ }
+ if( (s_serveroptions.playerType[n].curvalue == 1) && (s_serveroptions.playerNameBuffers[n][0] == 0) ) {
+ continue;
+ }
+ maxclients++;
+ }
+
+ switch( s_serveroptions.gametype ) {
+ case GT_FFA:
+ default:
+ trap_Cvar_SetValue( "ui_ffa_fraglimit", fraglimit );
+ trap_Cvar_SetValue( "ui_ffa_timelimit", timelimit );
+ break;
+
+ case GT_TOURNAMENT:
+ trap_Cvar_SetValue( "ui_tourney_fraglimit", fraglimit );
+ trap_Cvar_SetValue( "ui_tourney_timelimit", timelimit );
+ break;
+
+ case GT_TEAM:
+ trap_Cvar_SetValue( "ui_team_fraglimit", fraglimit );
+ trap_Cvar_SetValue( "ui_team_timelimit", timelimit );
+ trap_Cvar_SetValue( "ui_team_friendlt", friendlyfire );
+ break;
+
+ case GT_CTF:
+ trap_Cvar_SetValue( "ui_ctf_fraglimit", fraglimit );
+ trap_Cvar_SetValue( "ui_ctf_timelimit", timelimit );
+ trap_Cvar_SetValue( "ui_ctf_friendlt", friendlyfire );
+ break;
+
+ case GT_1FCTF:
+ trap_Cvar_SetValue( "ui_1fctf_capturelimit", fraglimit );
+ trap_Cvar_SetValue( "ui_1fctf_timelimit", timelimit );
+ trap_Cvar_SetValue( "ui_1fctf_friendlt", friendlyfire );
+ break;
+
+ case GT_OBELISK:
+ trap_Cvar_SetValue( "ui_overload_capturelimit", fraglimit );
+ trap_Cvar_SetValue( "ui_overload_timelimit", timelimit );
+ trap_Cvar_SetValue( "ui_overload_friendlt", friendlyfire );
+ break;
+
+ case GT_HARVESTER:
+ trap_Cvar_SetValue( "ui_harvester_capturelimit", fraglimit );
+ trap_Cvar_SetValue( "ui_harvester_timelimit", timelimit );
+ trap_Cvar_SetValue( "ui_harvester_friendlt", friendlyfire );
+ break;
+
+ case GT_ELIMINATION:
+ trap_Cvar_SetValue( "ui_elimination_capturelimit", fraglimit );
+ trap_Cvar_SetValue( "ui_elimination_timelimit", timelimit );
+ //trap_Cvar_SetValue( "ui_elimination_friendlt", friendlyfire );
+ break;
+
+ case GT_CTF_ELIMINATION:
+ trap_Cvar_SetValue( "ui_ctf_elimination_capturelimit", fraglimit );
+ trap_Cvar_SetValue( "ui_ctf_elimination_timelimit", timelimit );
+ //trap_Cvar_SetValue( "ui_ctf_elimination_friendlt", friendlyfire );
+ break;
+
+ case GT_LMS:
+ trap_Cvar_SetValue( "ui_lms_fraglimit", fraglimit );
+ trap_Cvar_SetValue( "ui_lms_timelimit", timelimit );
+ break;
+
+ case GT_DOUBLE_D:
+ trap_Cvar_SetValue( "ui_dd_capturelimit", fraglimit );
+ trap_Cvar_SetValue( "ui_dd_timelimit", timelimit );
+ trap_Cvar_SetValue( "ui_dd_friendlt", friendlyfire );
+ break;
+ }
+
+ trap_Cvar_SetValue( "sv_maxclients", Com_Clamp( 0, 12, maxclients ) );
+// trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, dedicated ) );
+ trap_Cvar_SetValue ("timelimit", Com_Clamp( 0, timelimit, timelimit ) );
+ trap_Cvar_SetValue ("fraglimit", Com_Clamp( 0, fraglimit, fraglimit ) );
+ trap_Cvar_SetValue ("capturelimit", Com_Clamp( 0, flaglimit, flaglimit ) );
+ trap_Cvar_SetValue( "g_friendlyfire", friendlyfire );
+ trap_Cvar_SetValue( "sv_pure", pure );
+ trap_Cvar_SetValue( "sv_lanForceRate", lan );
+ trap_Cvar_SetValue( "g_instantgib", instantgib );
+ trap_Cvar_SetValue( "g_rockets", rockets );
+ trap_Cvar_SetValue( "g_lms_mode", lmsMode);
+ trap_Cvar_SetValue( "elimination_ctf_oneway", oneway );
+ switch(pmove) {
+ case 1:
+ //Fixed framerate 125 Hz
+ trap_Cvar_SetValue( "pmove_fixed", 1);
+ trap_Cvar_SetValue( "pmove_msec", 8);
+ trap_Cvar_SetValue( "pmove_float", 0);
+ break;
+ case 2:
+ //Fixed framerate 91 Hz
+ trap_Cvar_SetValue( "pmove_fixed", 1);
+ trap_Cvar_SetValue( "pmove_msec", 11);
+ trap_Cvar_SetValue( "pmove_float", 0);
+ break;
+ case 3:
+ //Accurate physics
+ trap_Cvar_SetValue( "pmove_fixed", 0);
+ trap_Cvar_SetValue( "pmove_float", 1);
+ break;
+ default:
+ //Framerate dependent
+ trap_Cvar_SetValue( "pmove_fixed", 0);
+ trap_Cvar_SetValue( "pmove_float", 0);
+ break;
+ };
+ trap_Cvar_Set("sv_hostname", s_serveroptions.hostname.field.buffer );
+
+ // the wait commands will allow the dedicated to take effect
+ info = UI_GetArenaInfoByNumber( s_startserver.maplist[ s_startserver.currentmap ]);
+ trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", Info_ValueForKey( info, "map" )));
+
+ // add bots
+ trap_Cmd_ExecuteText( EXEC_APPEND, "wait 3\n" );
+ for( n = 1; n < PLAYER_SLOTS; n++ ) {
+ if( s_serveroptions.playerType[n].curvalue != 1 ) {
+ continue;
+ }
+ if( s_serveroptions.playerNameBuffers[n][0] == 0 ) {
+ continue;
+ }
+ if( s_serveroptions.playerNameBuffers[n][0] == '-' ) {
+ continue;
+ }
+ if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
+ Com_sprintf( buf, sizeof(buf), "addbot %s %i %s\n", s_serveroptions.playerNameBuffers[n], skill,
+ playerTeam_list[s_serveroptions.playerTeam[n].curvalue] );
+ }
+ else {
+ Com_sprintf( buf, sizeof(buf), "addbot %s %i\n", s_serveroptions.playerNameBuffers[n], skill );
+ }
+ trap_Cmd_ExecuteText( EXEC_APPEND, buf );
+ }
+
+ // set player's team
+ if( /*dedicated == 0 &&*/ s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait 5; team %s\n", playerTeam_list[s_serveroptions.playerTeam[0].curvalue] ) );
+ }
+}
+
+
+/*
+=================
+ServerOptions_InitPlayerItems
+=================
+*/
+static void ServerOptions_InitPlayerItems( void ) {
+ int n;
+ int v;
+
+ // init types
+ if( s_serveroptions.multiplayer ) {
+ v = 0; // open
+ }
+ else {
+ v = 1; // bot
+ }
+
+ for( n = 0; n < PLAYER_SLOTS; n++ ) {
+ s_serveroptions.playerType[n].curvalue = v;
+ }
+
+ if( s_serveroptions.multiplayer && (s_serveroptions.gametype < GT_TEAM || s_serveroptions.gametype == GT_LMS ) ) {
+ for( n = 8; n < PLAYER_SLOTS; n++ ) {
+ s_serveroptions.playerType[n].curvalue = 2;
+ }
+ }
+
+ // if not a dedicated server, first slot is reserved for the human on the server
+// if( s_serveroptions.dedicated.curvalue == 0 ) {
+ // human
+ s_serveroptions.playerType[0].generic.flags |= QMF_INACTIVE;
+ s_serveroptions.playerType[0].curvalue = 0;
+ trap_Cvar_VariableStringBuffer( "name", s_serveroptions.playerNameBuffers[0], sizeof(s_serveroptions.playerNameBuffers[0]) );
+ Q_CleanStr( s_serveroptions.playerNameBuffers[0] );
+// }
+
+ // init teams
+ if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
+ for( n = 0; n < (PLAYER_SLOTS / 2); n++ ) {
+ s_serveroptions.playerTeam[n].curvalue = 0;
+ }
+ for( ; n < PLAYER_SLOTS; n++ ) {
+ s_serveroptions.playerTeam[n].curvalue = 1;
+ }
+ }
+ else {
+ for( n = 0; n < PLAYER_SLOTS; n++ ) {
+ s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
+ }
+ }
+}
+
+
+/*
+=================
+ServerOptions_SetPlayerItems
+=================
+*/
+static void ServerOptions_SetPlayerItems( void ) {
+ int start;
+ int n;
+
+ // types
+// for( n = 0; n < PLAYER_SLOTS; n++ ) {
+// if( (!s_serveroptions.multiplayer) && (n > 0) && (s_serveroptions.playerType[n].curvalue == 0) ) {
+// s_serveroptions.playerType[n].curvalue = 1;
+// }
+// }
+
+ // names
+// if( s_serveroptions.dedicated.curvalue == 0 ) {
+ s_serveroptions.player0.string = "Human";
+ s_serveroptions.playerName[0].generic.flags &= ~((unsigned int)QMF_HIDDEN);
+
+ start = 1;
+/* }
+ else {
+ s_serveroptions.player0.string = "Open";
+ start = 0;
+ }*/
+ for( n = start; n < PLAYER_SLOTS; n++ ) {
+ if( s_serveroptions.playerType[n].curvalue == 1 ) {
+ s_serveroptions.playerName[n].generic.flags &= ~( (unsigned int)(QMF_INACTIVE|QMF_HIDDEN));
+ }
+ else {
+ s_serveroptions.playerName[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
+ }
+ }
+
+ // teams
+ if( s_serveroptions.gametype < GT_TEAM || s_serveroptions.gametype == GT_LMS ) {
+ return;
+ }
+ for( n = start; n < PLAYER_SLOTS; n++ ) {
+ if( s_serveroptions.playerType[n].curvalue == 2 ) {
+ s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
+ }
+ else {
+ s_serveroptions.playerTeam[n].generic.flags &= ~((unsigned int) (QMF_INACTIVE|QMF_HIDDEN));
+ }
+ }
+}
+
+
+/*
+=================
+ServerOptions_Event
+=================
+*/
+static void ServerOptions_Event( void* ptr, int event ) {
+ switch( ((menucommon_s*)ptr)->id ) {
+
+ //if( event != QM_ACTIVATED && event != QM_LOSTFOCUS) {
+ // return;
+ //}
+ case ID_PLAYER_TYPE:
+ if( event != QM_ACTIVATED ) {
+ break;
+ }
+ ServerOptions_SetPlayerItems();
+ break;
+
+ case ID_MAXCLIENTS:
+// case ID_DEDICATED:
+ ServerOptions_SetPlayerItems();
+ break;
+ case ID_GO:
+ if( event != QM_ACTIVATED ) {
+ break;
+ }
+ ServerOptions_Start();
+ break;
+
+ case ID_STARTSERVERNEXT:
+ if( event != QM_ACTIVATED ) {
+ break;
+ }
+ break;
+ case ID_BACK:
+ if( event != QM_ACTIVATED ) {
+ break;
+ }
+ UI_PopMenu();
+ break;
+ }
+}
+
+
+static void ServerOptions_PlayerNameEvent( void* ptr, int event ) {
+ int n;
+
+ if( event != QM_ACTIVATED ) {
+ return;
+ }
+ n = ((menutext_s*)ptr)->generic.id;
+ s_serveroptions.newBotIndex = n;
+ UI_BotSelectMenu( s_serveroptions.playerNameBuffers[n] );
+}
+
+
+/*
+=================
+ServerOptions_StatusBar
+=================
+*/
+static void ServerOptions_StatusBar( void* ptr ) {
+ UI_DrawString( 320, 440, "0 = NO LIMIT", UI_CENTER|UI_SMALLFONT, colorWhite );
+}
+
+/*
+=================
+ServerOptions_StatusBar_Instantgib
+=================
+*/
+static void ServerOptions_StatusBar_Instantgib( void* ptr ) {
+ UI_DrawString( 320, 440, "Only railgun and instant kill", UI_CENTER|UI_SMALLFONT, colorWhite );
+}
+
+/*
+=================
+ServerOptions_StatusBar_Allrockets
+=================
+*/
+static void ServerOptions_StatusBar_Allrockets( void* ptr ) {
+ UI_DrawString( 320, 440, "Only Rocket launcher with Inf. ammo", UI_CENTER|UI_SMALLFONT, colorWhite );
+}
+
+/*
+=================
+ServerOptions_StatusBar_Pure
+=================
+*/
+static void ServerOptions_StatusBar_Pure( void* ptr ) {
+ UI_DrawString( 320, 440, "Require identical pk3 files", UI_CENTER|UI_SMALLFONT, colorWhite );
+}
+
+/*
+=================
+ServerOptions_StatusBar_Oneway
+=================
+*/
+static void ServerOptions_StatusBar_Oneway( void* ptr ) {
+ UI_DrawString( 320, 440, "Only one team can capture in a round", UI_CENTER|UI_SMALLFONT, colorWhite );
+}
+
+/*
+=================
+ServerOptions_StatusBar_Pmove
+=================
+*/
+static void ServerOptions_StatusBar_Pmove( void* ptr ) {
+ switch( ((menulist_s*)ptr)->curvalue ) {
+ case 0:
+ UI_DrawString( 320, 440, "Physics depends on players framerates", UI_CENTER|UI_SMALLFONT, colorWhite );
+ UI_DrawString( 320, 460, "Not all players are equal", UI_CENTER|UI_SMALLFONT, colorWhite );
+ break;
+ case 1:
+ case 2:
+ UI_DrawString( 320, 440, "Physics are calculated at fixed intervals", UI_CENTER|UI_SMALLFONT, colorWhite );
+ UI_DrawString( 320, 460, "All players are equal", UI_CENTER|UI_SMALLFONT, colorWhite );
+ break;
+ case 3:
+ UI_DrawString( 320, 440, "Physics are calculated exactly", UI_CENTER|UI_SMALLFONT, colorWhite );
+ UI_DrawString( 320, 460, "All players are equal", UI_CENTER|UI_SMALLFONT, colorWhite );
+ break;
+ default:
+ UI_DrawString( 320, 440, "Framerate dependent or not", UI_CENTER|UI_SMALLFONT, colorWhite );
+ break;
+ }
+
+}
+
+
+/*
+===============
+ServerOptions_LevelshotDraw
+===============
+*/
+static void ServerOptions_LevelshotDraw( void *self ) {
+ menubitmap_s *b;
+ int x;
+ int y;
+
+ // strange place for this, but it works
+ if( s_serveroptions.newBot ) {
+ Q_strncpyz( s_serveroptions.playerNameBuffers[s_serveroptions.newBotIndex], s_serveroptions.newBotName, 16 );
+ s_serveroptions.newBot = qfalse;
+ }
+
+ b = (menubitmap_s *)self;
+
+ Bitmap_Draw( b );
+
+ x = b->generic.x;
+ y = b->generic.y + b->height;
+ UI_FillRect( x, y, b->width, 40, colorBlack );
+
+ x += b->width / 2;
+ y += 4;
+ UI_DrawString( x, y, s_serveroptions.mapnamebuffer, UI_CENTER|UI_SMALLFONT, color_orange );
+
+ y += SMALLCHAR_HEIGHT;
+ UI_DrawString( x, y, gametype_items[gametype_remap2[s_serveroptions.gametype]], UI_CENTER|UI_SMALLFONT, color_orange );
+}
+
+
+static void ServerOptions_InitBotNames( void ) {
+ int count;
+ int n;
+ const char *arenaInfo;
+ const char *botInfo;
+ char *p;
+ char *bot;
+ char bots[MAX_INFO_STRING];
+
+ //this SHOULD work
+ if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
+ Q_strncpyz( s_serveroptions.playerNameBuffers[1], "gargoyle", 16 );
+ Q_strncpyz( s_serveroptions.playerNameBuffers[2], "kyonshi", 16 );
+ Q_strncpyz( s_serveroptions.playerNameBuffers[3], "grism", 16 );
+ if( s_serveroptions.gametype != GT_TEAM ) {
+ s_serveroptions.playerType[3].curvalue = 2;
+ }
+ Q_strncpyz( s_serveroptions.playerNameBuffers[4], "merman", 16 );
+ s_serveroptions.playerType[4].curvalue = 2;
+ Q_strncpyz( s_serveroptions.playerNameBuffers[5], "skelebot", 16 );
+ s_serveroptions.playerType[5].curvalue = 2;
+
+ Q_strncpyz( s_serveroptions.playerNameBuffers[6], "sergei", 16 );
+ Q_strncpyz( s_serveroptions.playerNameBuffers[7], "assassin", 16 );
+ Q_strncpyz( s_serveroptions.playerNameBuffers[8], "grunt", 16 );
+ Q_strncpyz( s_serveroptions.playerNameBuffers[9], "skelebot", 16 );
+ if( s_serveroptions.gametype != GT_TEAM ) {
+ s_serveroptions.playerType[9].curvalue = 2;
+ }
+ Q_strncpyz( s_serveroptions.playerNameBuffers[10], "merman", 16 );
+ s_serveroptions.playerType[10].curvalue = 2;
+ Q_strncpyz( s_serveroptions.playerNameBuffers[11], "skelebot", 16 );
+ s_serveroptions.playerType[11].curvalue = 2;
+
+ return;
+ }
+
+ count = 1; // skip the first slot, reserved for a human
+
+ // get info for this map
+ arenaInfo = UI_GetArenaInfoByMap( s_serveroptions.mapnamebuffer );
+
+ // get the bot info - we'll seed with them if any are listed
+ Q_strncpyz( bots, Info_ValueForKey( arenaInfo, "bots" ), sizeof(bots) );
+ p = &bots[0];
+ while( *p && count < PLAYER_SLOTS ) {
+ //skip spaces
+ while( *p && *p == ' ' ) {
+ p++;
+ }
+ if( !p ) {
+ break;
+ }
+
+ // mark start of bot name
+ bot = p;
+
+ // skip until space of null
+ while( *p && *p != ' ' ) {
+ p++;
+ }
+ if( *p ) {
+ *p++ = 0;
+ }
+
+ botInfo = UI_GetBotInfoByName( bot );
+ bot = Info_ValueForKey( botInfo, "name" );
+
+ if(!Q_stricmp(bot,""))
+ bot = "Sarge";
+
+ Q_strncpyz( s_serveroptions.playerNameBuffers[count], bot, sizeof(s_serveroptions.playerNameBuffers[count]) );
+ count++;
+ }
+
+ // set the rest of the bot slots to to other bots
+ for( n = count; n < PLAYER_SLOTS; n++ ) {
+ switch(n%4){
+ case 0:
+ strcpy( s_serveroptions.playerNameBuffers[n], "Grunt" );
+ break;
+ case 1:
+ strcpy( s_serveroptions.playerNameBuffers[n], "Merman" );
+ break;
+ case 2:
+ strcpy( s_serveroptions.playerNameBuffers[n], "Kyonshi" );
+ break;
+ default:
+ strcpy( s_serveroptions.playerNameBuffers[n], "Skelebot" );
+ }
+ }
+
+ // pad up to #8 as open slots
+ for( ;count < 8; count++ ) {
+ s_serveroptions.playerType[count].curvalue = 0;
+ }
+
+ // close off the rest by default
+ for( ;count < PLAYER_SLOTS; count++ ) {
+ if( s_serveroptions.playerType[count].curvalue == 1 ) {
+ s_serveroptions.playerType[count].curvalue = 2;
+ }
+ }
+}
+
+
+/*
+=================
+ServerOptions_SetMenuItems
+=================
+*/
+static void ServerOptions_SetMenuItems( void ) {
+ static char picname[64];
+ const char *info;
+
+ switch( s_serveroptions.gametype ) {
+ case GT_FFA:
+ default:
+ Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_fraglimit" ) ) );
+ Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_timelimit" ) ) );
+ break;
+
+ case GT_TOURNAMENT:
+ Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_fraglimit" ) ) );
+ Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_timelimit" ) ) );
+ break;
+
+ case GT_TEAM:
+ Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_fraglimit" ) ) );
+ Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_timelimit" ) ) );
+ s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_team_friendly" ) );
+ break;
+
+ case GT_CTF:
+ Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_ctf_capturelimit" ) ) );
+ Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_timelimit" ) ) );
+ s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_ctf_friendly" ) );
+ break;
+
+ case GT_1FCTF:
+ Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_1fctf_capturelimit" ) ) );
+ Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_1fctf_timelimit" ) ) );
+ s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_1fctf_friendly" ) );
+ break;
+
+ case GT_OBELISK:
+ Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_overload_capturelimit" ) ) );
+ Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_overload_timelimit" ) ) );
+ s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_overload_friendly" ) );
+ break;
+
+ case GT_HARVESTER:
+ Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_harvester_capturelimit" ) ) );
+ Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_harvester_timelimit" ) ) );
+ s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_harvester_friendly" ) );
+ break;
+
+ case GT_ELIMINATION:
+ Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_elimination_capturelimit" ) ) );
+ Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_elimination_timelimit" ) ) );
+ //s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_elimination_friendly" ) );
+ break;
+
+ case GT_CTF_ELIMINATION:
+ Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_elimination_capturelimit" ) ) );
+ Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_elimination_timelimit" ) ) );
+ //s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_ctf_elimination_friendly" ) );
+ break;
+
+ case GT_LMS:
+ Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_lms_fraglimit" ) ) );
+ Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_lms_timelimit" ) ) );
+ break;
+
+ case GT_DOUBLE_D:
+ Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_dd_capturelimit" ) ) );
+ Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_dd_timelimit" ) ) );
+ s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_dd_friendly" ) );
+ break;
+
+ case GT_DOMINATION:
+ Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_dom_capturelimit" ) ) );
+ Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_dom_timelimit" ) ) );
+ s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_dom_friendly" ) );
+ break;
+
+ }
+
+ Q_strncpyz( s_serveroptions.hostname.field.buffer, UI_Cvar_VariableString( "sv_hostname" ), sizeof( s_serveroptions.hostname.field.buffer ) );
+ s_serveroptions.pure.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_pure" ) );
+ s_serveroptions.lan.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_lanforcerate" ) );
+ s_serveroptions.instantgib.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "g_instantgib" ) );
+ s_serveroptions.rockets.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "g_rockets" ) );
+ s_serveroptions.lmsMode.curvalue = Com_Clamp( 0, 3, trap_Cvar_VariableValue("g_lms_mode") );
+ s_serveroptions.oneway.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "elimination_ctf_oneway" ) );
+ s_serveroptions.pmove.curvalue = 0;
+ if(trap_Cvar_VariableValue( "pmove_fixed" ))
+ s_serveroptions.pmove.curvalue = 1;
+ if(trap_Cvar_VariableValue( "pmove_fixed" ) && trap_Cvar_VariableValue( "pmove_msec" )==11)
+ s_serveroptions.pmove.curvalue = 2;
+ if(trap_Cvar_VariableValue( "pmove_float" ))
+ s_serveroptions.pmove.curvalue = 3;
+
+ // set the map pic
+ info = UI_GetArenaInfoByNumber(s_startserver.maplist[s_startserver.currentmap]);
+ Com_sprintf( picname, 64, "levelshots/%s", Info_ValueForKey( info, "map") );
+ s_serveroptions.mappic.generic.name = picname;
+
+ // set the map name
+ strcpy( s_serveroptions.mapnamebuffer, s_startserver.mapname.string );
+ Q_strupr( s_serveroptions.mapnamebuffer );
+
+ // get the player selections initialized
+ ServerOptions_InitPlayerItems();
+ ServerOptions_SetPlayerItems();
+
+ // seed bot names
+ ServerOptions_InitBotNames();
+ ServerOptions_SetPlayerItems();
+}
+
+/*
+=================
+PlayerName_Draw
+=================
+*/
+static void PlayerName_Draw( void *item ) {
+ menutext_s *s;
+ float *color;
+ int x, y;
+ int style;
+ qboolean focus;
+
+ s = (menutext_s *)item;
+
+ x = s->generic.x;
+ y = s->generic.y;
+
+ style = UI_SMALLFONT;
+ focus = (s->generic.parent->cursor == s->generic.menuPosition);
+
+ if ( s->generic.flags & QMF_GRAYED )
+ color = text_color_disabled;
+ else if ( focus )
+ {
+ color = text_color_highlight;
+ style |= UI_PULSE;
+ }
+ else if ( s->generic.flags & QMF_BLINK )
+ {
+ color = text_color_highlight;
+ style |= UI_BLINK;
+ }
+ else
+ color = text_color_normal;
+
+ if ( focus )
+ {
+ // draw cursor
+ UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
+ UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
+ }
+
+ UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );
+ UI_DrawString( x + SMALLCHAR_WIDTH, y, s->string, style|UI_LEFT, color );
+}
+
+
+/*
+=================
+ServerOptions_MenuInit
+=================
+*/
+#define OPTIONS_X 456
+
+static void ServerOptions_MenuInit( qboolean multiplayer ) {
+ int y;
+ int n;
+
+ memset( &s_serveroptions, 0 ,sizeof(serveroptions_t) );
+ s_serveroptions.multiplayer = multiplayer;
+ // so the new gametypes work
+ s_serveroptions.gametype = (int)Com_Clamp( 0, GT_MAX_GAME_TYPE - 1, trap_Cvar_VariableValue( "g_gameType" ) );
+
+ ServerOptions_Cache();
+
+ s_serveroptions.menu.wrapAround = qtrue;
+ s_serveroptions.menu.fullscreen = qtrue;
+
+ s_serveroptions.banner.generic.type = MTYPE_BTEXT;
+ s_serveroptions.banner.generic.x = 320;
+ s_serveroptions.banner.generic.y = 16;
+ s_serveroptions.banner.string = "GAME SERVER";
+ s_serveroptions.banner.color = color_white;
+ s_serveroptions.banner.style = UI_CENTER;
+
+ s_serveroptions.mappic.generic.type = MTYPE_BITMAP;
+ s_serveroptions.mappic.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
+ s_serveroptions.mappic.generic.x = 352;
+ s_serveroptions.mappic.generic.y = 80;
+ s_serveroptions.mappic.width = 160;
+ s_serveroptions.mappic.height = 120;
+ s_serveroptions.mappic.errorpic = GAMESERVER_UNKNOWNMAP;
+ s_serveroptions.mappic.generic.ownerdraw = ServerOptions_LevelshotDraw;
+
+ s_serveroptions.picframe.generic.type = MTYPE_BITMAP;
+ s_serveroptions.picframe.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE|QMF_HIGHLIGHT;
+ s_serveroptions.picframe.generic.x = 352 - 38;
+ s_serveroptions.picframe.generic.y = 80 - 40;
+ s_serveroptions.picframe.width = 320;
+ s_serveroptions.picframe.height = 320;
+ s_serveroptions.picframe.focuspic = GAMESERVER_SELECT;
+
+ y = 268;
+ if( s_serveroptions.gametype < GT_CTF || s_serveroptions.gametype== GT_LMS) {
+ s_serveroptions.fraglimit.generic.type = MTYPE_FIELD;
+ s_serveroptions.fraglimit.generic.name = "Frag Limit:";
+ s_serveroptions.fraglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_serveroptions.fraglimit.generic.x = OPTIONS_X;
+ s_serveroptions.fraglimit.generic.y = y;
+ s_serveroptions.fraglimit.generic.statusbar = ServerOptions_StatusBar;
+ s_serveroptions.fraglimit.field.widthInChars = 3;
+ s_serveroptions.fraglimit.field.maxchars = 3;
+ }
+ else {
+ s_serveroptions.flaglimit.generic.type = MTYPE_FIELD;
+ s_serveroptions.flaglimit.generic.name = "Capture Limit:";
+ s_serveroptions.flaglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_serveroptions.flaglimit.generic.x = OPTIONS_X;
+ s_serveroptions.flaglimit.generic.y = y;
+ s_serveroptions.flaglimit.generic.statusbar = ServerOptions_StatusBar;
+ s_serveroptions.flaglimit.field.widthInChars = 3;
+ s_serveroptions.flaglimit.field.maxchars = 3;
+ }
+
+ y += BIGCHAR_HEIGHT+2;
+ s_serveroptions.timelimit.generic.type = MTYPE_FIELD;
+ s_serveroptions.timelimit.generic.name = "Time Limit:";
+ s_serveroptions.timelimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_serveroptions.timelimit.generic.x = OPTIONS_X;
+ s_serveroptions.timelimit.generic.y = y;
+ s_serveroptions.timelimit.generic.statusbar = ServerOptions_StatusBar;
+ s_serveroptions.timelimit.field.widthInChars = 3;
+ s_serveroptions.timelimit.field.maxchars = 3;
+
+ if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS && s_serveroptions.gametype != GT_ELIMINATION && s_serveroptions.gametype != GT_CTF_ELIMINATION) {
+ y += BIGCHAR_HEIGHT+2;
+ s_serveroptions.friendlyfire.generic.type = MTYPE_RADIOBUTTON;
+ s_serveroptions.friendlyfire.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_serveroptions.friendlyfire.generic.x = OPTIONS_X;
+ s_serveroptions.friendlyfire.generic.y = y;
+ s_serveroptions.friendlyfire.generic.name = "Friendly Fire:";
+ }
+
+ if( s_serveroptions.gametype == GT_CTF_ELIMINATION) {
+ y += BIGCHAR_HEIGHT+2;
+ s_serveroptions.oneway.generic.type = MTYPE_RADIOBUTTON;
+ s_serveroptions.oneway.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_serveroptions.oneway.generic.x = OPTIONS_X;
+ s_serveroptions.oneway.generic.y = y;
+ s_serveroptions.oneway.generic.name = "Oneway attack:";
+ s_serveroptions.oneway.generic.statusbar = ServerOptions_StatusBar_Oneway;
+ }
+
+ y += BIGCHAR_HEIGHT+2;
+ s_serveroptions.pure.generic.type = MTYPE_RADIOBUTTON;
+ s_serveroptions.pure.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_serveroptions.pure.generic.x = OPTIONS_X;
+ s_serveroptions.pure.generic.y = y;
+ s_serveroptions.pure.generic.name = "Pure Server:";
+ s_serveroptions.pure.generic.statusbar = ServerOptions_StatusBar_Pure;
+
+ if( s_serveroptions.multiplayer ) {
+ y += BIGCHAR_HEIGHT+2;
+ s_serveroptions.lan.generic.type = MTYPE_RADIOBUTTON;
+ s_serveroptions.lan.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_serveroptions.lan.generic.x = OPTIONS_X;
+ s_serveroptions.lan.generic.y = y;
+ s_serveroptions.lan.generic.name = "Optimize for LAN:";
+ }
+
+ //Insantgib option
+ y += BIGCHAR_HEIGHT+2;
+ s_serveroptions.instantgib.generic.type = MTYPE_RADIOBUTTON;
+ s_serveroptions.instantgib.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_serveroptions.instantgib.generic.x = OPTIONS_X;
+ s_serveroptions.instantgib.generic.y = y;
+ s_serveroptions.instantgib.generic.name = "Instantgib:";
+ s_serveroptions.instantgib.generic.statusbar = ServerOptions_StatusBar_Instantgib;
+
+ //Rockets option
+ y += BIGCHAR_HEIGHT+2;
+ s_serveroptions.rockets.generic.type = MTYPE_RADIOBUTTON;
+ s_serveroptions.rockets.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_serveroptions.rockets.generic.x = OPTIONS_X;
+ s_serveroptions.rockets.generic.y = y;
+ s_serveroptions.rockets.generic.name = "All rockets:";
+ s_serveroptions.rockets.generic.statusbar = ServerOptions_StatusBar_Allrockets;
+
+ if( s_serveroptions.gametype == GT_LMS ) {
+ y += BIGCHAR_HEIGHT+2;
+ s_serveroptions.lmsMode.generic.type = MTYPE_SPINCONTROL;
+ s_serveroptions.lmsMode.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_serveroptions.lmsMode.generic.name = "Score mode:";
+ s_serveroptions.lmsMode.generic.x = OPTIONS_X; //32 + (strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH;
+ s_serveroptions.lmsMode.generic.y = y;
+ s_serveroptions.lmsMode.itemnames = lmsMode_list;
+ //s_serveroptions.lmsMode.curvalue = 0;
+
+ }
+
+ y += BIGCHAR_HEIGHT+2;
+ s_serveroptions.pmove.generic.type = MTYPE_SPINCONTROL;
+ s_serveroptions.pmove.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_serveroptions.pmove.generic.name = "Physics:";
+ s_serveroptions.pmove.generic.x = OPTIONS_X; //32 + (strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH;
+ s_serveroptions.pmove.generic.y = y;
+ s_serveroptions.pmove.itemnames = pmove_list;
+ s_serveroptions.pmove.generic.statusbar = ServerOptions_StatusBar_Pmove;
+
+ if( s_serveroptions.multiplayer ) {
+ y += BIGCHAR_HEIGHT+2;
+ s_serveroptions.hostname.generic.type = MTYPE_FIELD;
+ s_serveroptions.hostname.generic.name = "Hostname:";
+ s_serveroptions.hostname.generic.flags = QMF_SMALLFONT;
+ s_serveroptions.hostname.generic.x = OPTIONS_X;
+ s_serveroptions.hostname.generic.y = y;
+ s_serveroptions.hostname.field.widthInChars = 18;
+ s_serveroptions.hostname.field.maxchars = 64;
+ }
+
+ y = 80;
+ s_serveroptions.botSkill.generic.type = MTYPE_SPINCONTROL;
+ s_serveroptions.botSkill.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_serveroptions.botSkill.generic.name = "Bot Skill:";
+ s_serveroptions.botSkill.generic.x = 32 + (strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH;
+ s_serveroptions.botSkill.generic.y = y;
+ s_serveroptions.botSkill.itemnames = botSkill_list;
+ s_serveroptions.botSkill.curvalue = 1;
+
+ y += ( 2 * SMALLCHAR_HEIGHT );
+ s_serveroptions.player0.generic.type = MTYPE_TEXT;
+ s_serveroptions.player0.generic.flags = QMF_SMALLFONT;
+ s_serveroptions.player0.generic.x = 32 + SMALLCHAR_WIDTH;
+ s_serveroptions.player0.generic.y = y;
+ s_serveroptions.player0.color = color_orange;
+ s_serveroptions.player0.style = UI_LEFT|UI_SMALLFONT;
+
+ for( n = 0; n < PLAYER_SLOTS; n++ ) {
+ s_serveroptions.playerType[n].generic.type = MTYPE_SPINCONTROL;
+ s_serveroptions.playerType[n].generic.flags = QMF_SMALLFONT;
+ s_serveroptions.playerType[n].generic.id = ID_PLAYER_TYPE;
+ s_serveroptions.playerType[n].generic.callback = ServerOptions_Event;
+ s_serveroptions.playerType[n].generic.x = 32;
+ s_serveroptions.playerType[n].generic.y = y;
+ s_serveroptions.playerType[n].itemnames = playerType_list;
+
+ s_serveroptions.playerName[n].generic.type = MTYPE_TEXT;
+ s_serveroptions.playerName[n].generic.flags = QMF_SMALLFONT;
+ s_serveroptions.playerName[n].generic.x = 96;
+ s_serveroptions.playerName[n].generic.y = y;
+ s_serveroptions.playerName[n].generic.callback = ServerOptions_PlayerNameEvent;
+ s_serveroptions.playerName[n].generic.id = n;
+ s_serveroptions.playerName[n].generic.ownerdraw = PlayerName_Draw;
+ s_serveroptions.playerName[n].color = color_orange;
+ s_serveroptions.playerName[n].style = UI_SMALLFONT;
+ s_serveroptions.playerName[n].string = s_serveroptions.playerNameBuffers[n];
+ s_serveroptions.playerName[n].generic.top = s_serveroptions.playerName[n].generic.y;
+ s_serveroptions.playerName[n].generic.bottom = s_serveroptions.playerName[n].generic.y + SMALLCHAR_HEIGHT;
+ s_serveroptions.playerName[n].generic.left = s_serveroptions.playerName[n].generic.x - SMALLCHAR_HEIGHT/ 2;
+ s_serveroptions.playerName[n].generic.right = s_serveroptions.playerName[n].generic.x + 16 * SMALLCHAR_WIDTH;
+
+ s_serveroptions.playerTeam[n].generic.type = MTYPE_SPINCONTROL;
+ s_serveroptions.playerTeam[n].generic.flags = QMF_SMALLFONT;
+ s_serveroptions.playerTeam[n].generic.x = 240;
+ s_serveroptions.playerTeam[n].generic.y = y;
+ s_serveroptions.playerTeam[n].itemnames = playerTeam_list;
+
+ y += ( SMALLCHAR_HEIGHT + 4 );
+ }
+
+ s_serveroptions.back.generic.type = MTYPE_BITMAP;
+ s_serveroptions.back.generic.name = GAMESERVER_BACK0;
+ s_serveroptions.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_serveroptions.back.generic.callback = ServerOptions_Event;
+ s_serveroptions.back.generic.id = ID_BACK;
+ s_serveroptions.back.generic.x = 0;
+ s_serveroptions.back.generic.y = 480-64;
+ s_serveroptions.back.width = 128;
+ s_serveroptions.back.height = 64;
+ s_serveroptions.back.focuspic = GAMESERVER_BACK1;
+
+ s_serveroptions.next.generic.type = MTYPE_BITMAP;
+ s_serveroptions.next.generic.name = GAMESERVER_NEXT0;
+ s_serveroptions.next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE|QMF_GRAYED|QMF_HIDDEN;
+ s_serveroptions.next.generic.callback = ServerOptions_Event;
+ s_serveroptions.next.generic.id = ID_STARTSERVERNEXT;
+ s_serveroptions.next.generic.x = 640;
+ s_serveroptions.next.generic.y = 480-64-72;
+ s_serveroptions.next.generic.statusbar = ServerOptions_StatusBar;
+ s_serveroptions.next.width = 128;
+ s_serveroptions.next.height = 64;
+ s_serveroptions.next.focuspic = GAMESERVER_NEXT1;
+
+ s_serveroptions.go.generic.type = MTYPE_BITMAP;
+ s_serveroptions.go.generic.name = GAMESERVER_FIGHT0;
+ s_serveroptions.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_serveroptions.go.generic.callback = ServerOptions_Event;
+ s_serveroptions.go.generic.id = ID_GO;
+ s_serveroptions.go.generic.x = 640;
+ s_serveroptions.go.generic.y = 480-64;
+ s_serveroptions.go.width = 128;
+ s_serveroptions.go.height = 64;
+ s_serveroptions.go.focuspic = GAMESERVER_FIGHT1;
+
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.banner );
+
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.mappic );
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.picframe );
+
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.botSkill );
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.player0 );
+ for( n = 0; n < PLAYER_SLOTS; n++ ) {
+ if( n != 0 ) {
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerType[n] );
+ }
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerName[n] );
+ if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerTeam[n] );
+ }
+ }
+
+ if( s_serveroptions.gametype < GT_CTF || s_serveroptions.gametype == GT_LMS ) {
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.fraglimit );
+ }
+ else {
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.flaglimit );
+ }
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.timelimit );
+ if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS && s_serveroptions.gametype != GT_ELIMINATION && s_serveroptions.gametype != GT_CTF_ELIMINATION) {
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.friendlyfire );
+ }
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.pure );
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.instantgib );
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.rockets );
+ if( s_serveroptions.gametype == GT_LMS) {
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.lmsMode );
+ }
+ if( s_serveroptions.gametype == GT_CTF_ELIMINATION) {
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.oneway );
+ }
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.pmove );
+ if( s_serveroptions.multiplayer ) {
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.lan );
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.hostname );
+ }
+
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.back );
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.next );
+ Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.go );
+
+ ServerOptions_SetMenuItems();
+}
+
+/*
+=================
+ServerOptions_Cache
+=================
+*/
+void ServerOptions_Cache( void ) {
+ trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 );
+ trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 );
+ trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT0 );
+ trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT1 );
+ trap_R_RegisterShaderNoMip( GAMESERVER_SELECT );
+ trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );
+}
+
+
+/*
+=================
+UI_ServerOptionsMenu
+=================
+*/
+static void UI_ServerOptionsMenu( qboolean multiplayer ) {
+ ServerOptions_MenuInit( multiplayer );
+ UI_PushMenu( &s_serveroptions.menu );
+}
+
+
+
+/*
+=============================================================================
+
+BOT SELECT MENU *****
+
+=============================================================================
+*/
+
+
+#define BOTSELECT_BACK0 "menu/art_blueish/back_0"
+#define BOTSELECT_BACK1 "menu/art_blueish/back_1"
+#define BOTSELECT_ACCEPT0 "menu/art_blueish/accept_0"
+#define BOTSELECT_ACCEPT1 "menu/art_blueish/accept_1"
+#define BOTSELECT_SELECT "menu/art/opponents_select"
+#define BOTSELECT_SELECTED "menu/art/opponents_selected"
+#define BOTSELECT_ARROWS "menu/art_blueish/gs_arrows_0"
+#define BOTSELECT_ARROWSL "menu/art_blueish/gs_arrows_l"
+#define BOTSELECT_ARROWSR "menu/art_blueish/gs_arrows_r"
+
+#define PLAYERGRID_COLS 4
+#define PLAYERGRID_ROWS 4
+#define MAX_MODELSPERPAGE (PLAYERGRID_ROWS * PLAYERGRID_COLS)
+
+
+typedef struct {
+ menuframework_s menu;
+
+ menutext_s banner;
+
+ menubitmap_s pics[MAX_MODELSPERPAGE];
+ menubitmap_s picbuttons[MAX_MODELSPERPAGE];
+ menutext_s picnames[MAX_MODELSPERPAGE];
+
+ menubitmap_s arrows;
+ menubitmap_s left;
+ menubitmap_s right;
+
+ menubitmap_s go;
+ menubitmap_s back;
+
+ int numBots;
+ int modelpage;
+ int numpages;
+ int selectedmodel;
+ int sortedBotNums[MAX_BOTS];
+ char boticons[MAX_MODELSPERPAGE][MAX_QPATH];
+ char botnames[MAX_MODELSPERPAGE][16];
+} botSelectInfo_t;
+
+static botSelectInfo_t botSelectInfo;
+
+
+/*
+=================
+UI_BotSelectMenu_SortCompare
+=================
+*/
+static int QDECL UI_BotSelectMenu_SortCompare( const void *arg1, const void *arg2 ) {
+ int num1, num2;
+ const char *info1, *info2;
+ const char *name1, *name2;
+
+ num1 = *(int *)arg1;
+ num2 = *(int *)arg2;
+
+ info1 = UI_GetBotInfoByNumber( num1 );
+ info2 = UI_GetBotInfoByNumber( num2 );
+
+ name1 = Info_ValueForKey( info1, "name" );
+ name2 = Info_ValueForKey( info2, "name" );
+
+ return Q_stricmp( name1, name2 );
+}
+
+
+/*
+=================
+UI_BotSelectMenu_BuildList
+=================
+*/
+static void UI_BotSelectMenu_BuildList( void ) {
+ int n;
+
+ botSelectInfo.modelpage = 0;
+ botSelectInfo.numBots = UI_GetNumBots();
+ botSelectInfo.numpages = botSelectInfo.numBots / MAX_MODELSPERPAGE;
+ if( botSelectInfo.numBots % MAX_MODELSPERPAGE ) {
+ botSelectInfo.numpages++;
+ }
+
+ // initialize the array
+ for( n = 0; n < botSelectInfo.numBots; n++ ) {
+ botSelectInfo.sortedBotNums[n] = n;
+ }
+
+ // now sort it
+ qsort( botSelectInfo.sortedBotNums, botSelectInfo.numBots, sizeof(botSelectInfo.sortedBotNums[0]), UI_BotSelectMenu_SortCompare );
+}
+
+
+/*
+=================
+ServerPlayerIcon
+=================
+*/
+static void ServerPlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize ) {
+ char *skin;
+ char model[MAX_QPATH];
+
+ Q_strncpyz( model, modelAndSkin, sizeof(model));
+ skin = strrchr( model, '/' );
+ if ( skin ) {
+ *skin++ = '\0';
+ }
+ else {
+ skin = "default";
+ }
+
+ Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_%s.tga", model, skin );
+
+ if( !trap_R_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, "default" ) != 0 ) {
+ Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_default.tga", model );
+ }
+}
+
+
+/*
+=================
+UI_BotSelectMenu_UpdateGrid
+=================
+*/
+static void UI_BotSelectMenu_UpdateGrid( void ) {
+ const char *info;
+ int i;
+ int j;
+
+ j = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
+ for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++, j++) {
+ if( j < botSelectInfo.numBots ) {
+ info = UI_GetBotInfoByNumber( botSelectInfo.sortedBotNums[j] );
+ ServerPlayerIcon( Info_ValueForKey( info, "model" ), botSelectInfo.boticons[i], MAX_QPATH );
+ Q_strncpyz( botSelectInfo.botnames[i], Info_ValueForKey( info, "name" ), 16 );
+ Q_CleanStr( botSelectInfo.botnames[i] );
+ botSelectInfo.pics[i].generic.name = botSelectInfo.boticons[i];
+ if( BotAlreadySelected( botSelectInfo.botnames[i] ) ) {
+ botSelectInfo.picnames[i].color = color_red;
+ }
+ else {
+ botSelectInfo.picnames[i].color = color_orange;
+ }
+ botSelectInfo.picbuttons[i].generic.flags &= ~((unsigned int)QMF_INACTIVE);
+ }
+ else {
+ // dead slot
+ botSelectInfo.pics[i].generic.name = NULL;
+ botSelectInfo.picbuttons[i].generic.flags |= QMF_INACTIVE;
+ botSelectInfo.botnames[i][0] = 0;
+ }
+
+ botSelectInfo.pics[i].generic.flags &= ~((unsigned int)QMF_HIGHLIGHT);
+ botSelectInfo.pics[i].shader = 0;
+ botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
+ }
+
+ // set selected model
+ i = botSelectInfo.selectedmodel % MAX_MODELSPERPAGE;
+ botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;
+ botSelectInfo.picbuttons[i].generic.flags &= ~((unsigned int)QMF_PULSEIFFOCUS);
+
+ if( botSelectInfo.numpages > 1 ) {
+ if( botSelectInfo.modelpage > 0 ) {
+ botSelectInfo.left.generic.flags &= ~((unsigned int)QMF_INACTIVE);
+ }
+ else {
+ botSelectInfo.left.generic.flags |= QMF_INACTIVE;
+ }
+
+ if( botSelectInfo.modelpage < (botSelectInfo.numpages - 1) ) {
+ botSelectInfo.right.generic.flags &= ~((unsigned int)QMF_INACTIVE);
+ }
+ else {
+ botSelectInfo.right.generic.flags |= QMF_INACTIVE;
+ }
+ }
+ else {
+ // hide left/right markers
+ botSelectInfo.left.generic.flags |= QMF_INACTIVE;
+ botSelectInfo.right.generic.flags |= QMF_INACTIVE;
+ }
+}
+
+
+/*
+=================
+UI_BotSelectMenu_Default
+=================
+*/
+static void UI_BotSelectMenu_Default( char *bot ) {
+ const char *botInfo;
+ const char *test;
+ int n;
+ int i;
+
+ for( n = 0; n < botSelectInfo.numBots; n++ ) {
+ botInfo = UI_GetBotInfoByNumber( n );
+ test = Info_ValueForKey( botInfo, "name" );
+ if( Q_stricmp( bot, test ) == 0 ) {
+ break;
+ }
+ }
+ if( n == botSelectInfo.numBots ) {
+ botSelectInfo.selectedmodel = 0;
+ return;
+ }
+
+ for( i = 0; i < botSelectInfo.numBots; i++ ) {
+ if( botSelectInfo.sortedBotNums[i] == n ) {
+ break;
+ }
+ }
+ if( i == botSelectInfo.numBots ) {
+ botSelectInfo.selectedmodel = 0;
+ return;
+ }
+
+ botSelectInfo.selectedmodel = i;
+}
+
+
+/*
+=================
+UI_BotSelectMenu_LeftEvent
+=================
+*/
+static void UI_BotSelectMenu_LeftEvent( void* ptr, int event ) {
+ if( event != QM_ACTIVATED ) {
+ return;
+ }
+ if( botSelectInfo.modelpage > 0 ) {
+ botSelectInfo.modelpage--;
+ botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
+ UI_BotSelectMenu_UpdateGrid();
+ }
+}
+
+
+/*
+=================
+UI_BotSelectMenu_RightEvent
+=================
+*/
+static void UI_BotSelectMenu_RightEvent( void* ptr, int event ) {
+ if( event != QM_ACTIVATED ) {
+ return;
+ }
+ if( botSelectInfo.modelpage < botSelectInfo.numpages - 1 ) {
+ botSelectInfo.modelpage++;
+ botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
+ UI_BotSelectMenu_UpdateGrid();
+ }
+}
+
+
+/*
+=================
+UI_BotSelectMenu_BotEvent
+=================
+*/
+static void UI_BotSelectMenu_BotEvent( void* ptr, int event ) {
+ int i;
+
+ if( event != QM_ACTIVATED ) {
+ return;
+ }
+
+ for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++ ) {
+ botSelectInfo.pics[i].generic.flags &= ~((unsigned int)QMF_HIGHLIGHT);
+ botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
+ }
+
+ // set selected
+ i = ((menucommon_s*)ptr)->id;
+ botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;
+ botSelectInfo.picbuttons[i].generic.flags &= ~((unsigned int)QMF_PULSEIFFOCUS);
+ botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE + i;
+}
+
+
+/*
+=================
+UI_BotSelectMenu_BackEvent
+=================
+*/
+static void UI_BotSelectMenu_BackEvent( void* ptr, int event ) {
+ if( event != QM_ACTIVATED ) {
+ return;
+ }
+ UI_PopMenu();
+}
+
+
+/*
+=================
+UI_BotSelectMenu_SelectEvent
+=================
+*/
+static void UI_BotSelectMenu_SelectEvent( void* ptr, int event ) {
+ if( event != QM_ACTIVATED ) {
+ return;
+ }
+ UI_PopMenu();
+
+ s_serveroptions.newBot = qtrue;
+ Q_strncpyz( s_serveroptions.newBotName, botSelectInfo.botnames[botSelectInfo.selectedmodel % MAX_MODELSPERPAGE], 16 );
+}
+
+
+/*
+=================
+UI_BotSelectMenu_Cache
+=================
+*/
+void UI_BotSelectMenu_Cache( void ) {
+ trap_R_RegisterShaderNoMip( BOTSELECT_BACK0 );
+ trap_R_RegisterShaderNoMip( BOTSELECT_BACK1 );
+ trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT0 );
+ trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT1 );
+ trap_R_RegisterShaderNoMip( BOTSELECT_SELECT );
+ trap_R_RegisterShaderNoMip( BOTSELECT_SELECTED );
+ trap_R_RegisterShaderNoMip( BOTSELECT_ARROWS );
+ trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSL );
+ trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSR );
+}
+
+
+static void UI_BotSelectMenu_Init( char *bot ) {
+ int i, j, k;
+ int x, y;
+
+ memset( &botSelectInfo, 0 ,sizeof(botSelectInfo) );
+ botSelectInfo.menu.wrapAround = qtrue;
+ botSelectInfo.menu.fullscreen = qtrue;
+
+ UI_BotSelectMenu_Cache();
+
+ botSelectInfo.banner.generic.type = MTYPE_BTEXT;
+ botSelectInfo.banner.generic.x = 320;
+ botSelectInfo.banner.generic.y = 16;
+ botSelectInfo.banner.string = "SELECT BOT";
+ botSelectInfo.banner.color = color_white;
+ botSelectInfo.banner.style = UI_CENTER;
+
+ y = 80;
+ for( i = 0, k = 0; i < PLAYERGRID_ROWS; i++) {
+ x = 180;
+ for( j = 0; j < PLAYERGRID_COLS; j++, k++ ) {
+ botSelectInfo.pics[k].generic.type = MTYPE_BITMAP;
+ botSelectInfo.pics[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
+ botSelectInfo.pics[k].generic.x = x;
+ botSelectInfo.pics[k].generic.y = y;
+ botSelectInfo.pics[k].generic.name = botSelectInfo.boticons[k];
+ botSelectInfo.pics[k].width = 64;
+ botSelectInfo.pics[k].height = 64;
+ botSelectInfo.pics[k].focuspic = BOTSELECT_SELECTED;
+ botSelectInfo.pics[k].focuscolor = colorRed;
+
+ botSelectInfo.picbuttons[k].generic.type = MTYPE_BITMAP;
+ botSelectInfo.picbuttons[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS;
+ botSelectInfo.picbuttons[k].generic.callback = UI_BotSelectMenu_BotEvent;
+ botSelectInfo.picbuttons[k].generic.id = k;
+ botSelectInfo.picbuttons[k].generic.x = x - 16;
+ botSelectInfo.picbuttons[k].generic.y = y - 16;
+ botSelectInfo.picbuttons[k].generic.left = x;
+ botSelectInfo.picbuttons[k].generic.top = y;
+ botSelectInfo.picbuttons[k].generic.right = x + 64;
+ botSelectInfo.picbuttons[k].generic.bottom = y + 64;
+ botSelectInfo.picbuttons[k].width = 128;
+ botSelectInfo.picbuttons[k].height = 128;
+ botSelectInfo.picbuttons[k].focuspic = BOTSELECT_SELECT;
+ botSelectInfo.picbuttons[k].focuscolor = colorRed;
+
+ botSelectInfo.picnames[k].generic.type = MTYPE_TEXT;
+ botSelectInfo.picnames[k].generic.flags = QMF_SMALLFONT;
+ botSelectInfo.picnames[k].generic.x = x + 32;
+ botSelectInfo.picnames[k].generic.y = y + 64;
+ botSelectInfo.picnames[k].string = botSelectInfo.botnames[k];
+ botSelectInfo.picnames[k].color = color_orange;
+ botSelectInfo.picnames[k].style = UI_CENTER|UI_SMALLFONT;
+
+ x += (64 + 6);
+ }
+ y += (64 + SMALLCHAR_HEIGHT + 6);
+ }
+
+ botSelectInfo.arrows.generic.type = MTYPE_BITMAP;
+ botSelectInfo.arrows.generic.name = BOTSELECT_ARROWS;
+ botSelectInfo.arrows.generic.flags = QMF_INACTIVE;
+ botSelectInfo.arrows.generic.x = 260;
+ botSelectInfo.arrows.generic.y = 440;
+ botSelectInfo.arrows.width = 128;
+ botSelectInfo.arrows.height = 32;
+
+ botSelectInfo.left.generic.type = MTYPE_BITMAP;
+ botSelectInfo.left.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ botSelectInfo.left.generic.callback = UI_BotSelectMenu_LeftEvent;
+ botSelectInfo.left.generic.x = 260;
+ botSelectInfo.left.generic.y = 440;
+ botSelectInfo.left.width = 64;
+ botSelectInfo.left.height = 32;
+ botSelectInfo.left.focuspic = BOTSELECT_ARROWSL;
+
+ botSelectInfo.right.generic.type = MTYPE_BITMAP;
+ botSelectInfo.right.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ botSelectInfo.right.generic.callback = UI_BotSelectMenu_RightEvent;
+ botSelectInfo.right.generic.x = 321;
+ botSelectInfo.right.generic.y = 440;
+ botSelectInfo.right.width = 64;
+ botSelectInfo.right.height = 32;
+ botSelectInfo.right.focuspic = BOTSELECT_ARROWSR;
+
+ botSelectInfo.back.generic.type = MTYPE_BITMAP;
+ botSelectInfo.back.generic.name = BOTSELECT_BACK0;
+ botSelectInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ botSelectInfo.back.generic.callback = UI_BotSelectMenu_BackEvent;
+ botSelectInfo.back.generic.x = 0;
+ botSelectInfo.back.generic.y = 480-64;
+ botSelectInfo.back.width = 128;
+ botSelectInfo.back.height = 64;
+ botSelectInfo.back.focuspic = BOTSELECT_BACK1;
+
+ botSelectInfo.go.generic.type = MTYPE_BITMAP;
+ botSelectInfo.go.generic.name = BOTSELECT_ACCEPT0;
+ botSelectInfo.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
+ botSelectInfo.go.generic.callback = UI_BotSelectMenu_SelectEvent;
+ botSelectInfo.go.generic.x = 640;
+ botSelectInfo.go.generic.y = 480-64;
+ botSelectInfo.go.width = 128;
+ botSelectInfo.go.height = 64;
+ botSelectInfo.go.focuspic = BOTSELECT_ACCEPT1;
+
+ Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.banner );
+ for( i = 0; i < MAX_MODELSPERPAGE; i++ ) {
+ Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.pics[i] );
+ Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.picbuttons[i] );
+ Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.picnames[i] );
+ }
+ Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.arrows );
+ Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.left );
+ Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.right );
+ Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.back );
+ Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.go );
+
+ UI_BotSelectMenu_BuildList();
+ UI_BotSelectMenu_Default( bot );
+ botSelectInfo.modelpage = botSelectInfo.selectedmodel / MAX_MODELSPERPAGE;
+ UI_BotSelectMenu_UpdateGrid();
+}
+
+
+/*
+=================
+UI_BotSelectMenu
+=================
+*/
+void UI_BotSelectMenu( char *bot ) {
+ UI_BotSelectMenu_Init( bot );
+ UI_PushMenu( &botSelectInfo.menu );
+}
diff --git a/game/code/q3_ui/ui_team.c b/code/q3_ui/ui_team.c
similarity index 100%
rename from game/code/q3_ui/ui_team.c
rename to code/q3_ui/ui_team.c
diff --git a/game/code/q3_ui/ui_teamorders.c b/code/q3_ui/ui_teamorders.c
similarity index 100%
rename from game/code/q3_ui/ui_teamorders.c
rename to code/q3_ui/ui_teamorders.c
diff --git a/code/q3_ui/ui_video.c b/code/q3_ui/ui_video.c
new file mode 100644
index 0000000..c956eee
--- /dev/null
+++ b/code/q3_ui/ui_video.c
@@ -0,0 +1,1308 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#include "ui_local.h"
+
+void GraphicsOptions_MenuInit( void );
+
+/*
+=======================================================================
+
+DRIVER INFORMATION MENU
+
+=======================================================================
+*/
+
+
+#define DRIVERINFO_FRAMEL "menu/art_blueish/frame2_l"
+#define DRIVERINFO_FRAMER "menu/art_blueish/frame1_r"
+#define DRIVERINFO_BACK0 "menu/art_blueish/back_0"
+#define DRIVERINFO_BACK1 "menu/art_blueish/back_1"
+
+static char* driverinfo_artlist[] =
+{
+ DRIVERINFO_FRAMEL,
+ DRIVERINFO_FRAMER,
+ DRIVERINFO_BACK0,
+ DRIVERINFO_BACK1,
+ NULL,
+};
+
+#define ID_DRIVERINFOBACK 100
+
+typedef struct
+{
+ menuframework_s menu;
+ menutext_s banner;
+ menubitmap_s back;
+ menubitmap_s framel;
+ menubitmap_s framer;
+ char stringbuff[1024];
+ char* strings[64];
+ int numstrings;
+} driverinfo_t;
+
+static driverinfo_t s_driverinfo;
+
+/*
+=================
+DriverInfo_Event
+=================
+*/
+static void DriverInfo_Event( void* ptr, int event )
+{
+ if (event != QM_ACTIVATED)
+ return;
+
+ switch (((menucommon_s*)ptr)->id)
+ {
+ case ID_DRIVERINFOBACK:
+ UI_PopMenu();
+ break;
+ }
+}
+
+/*
+=================
+DriverInfo_MenuDraw
+=================
+*/
+static void DriverInfo_MenuDraw( void )
+{
+ int i;
+ int y;
+
+ Menu_Draw( &s_driverinfo.menu );
+
+ UI_DrawString( 320, 80, "VENDOR", UI_CENTER|UI_SMALLFONT, color_red );
+ UI_DrawString( 320, 152, "PIXELFORMAT", UI_CENTER|UI_SMALLFONT, color_red );
+ UI_DrawString( 320, 192, "EXTENSIONS", UI_CENTER|UI_SMALLFONT, color_red );
+
+ UI_DrawString( 320, 80+16, uis.glconfig.vendor_string, UI_CENTER|UI_SMALLFONT, text_color_normal );
+ UI_DrawString( 320, 96+16, uis.glconfig.version_string, UI_CENTER|UI_SMALLFONT, text_color_normal );
+ UI_DrawString( 320, 112+16, uis.glconfig.renderer_string, UI_CENTER|UI_SMALLFONT, text_color_normal );
+ UI_DrawString( 320, 152+16, va ("color(%d-bits) Z(%d-bits) stencil(%d-bits)", uis.glconfig.colorBits, uis.glconfig.depthBits, uis.glconfig.stencilBits), UI_CENTER|UI_SMALLFONT, text_color_normal );
+
+ // double column
+ y = 192+16;
+ for (i=0; i<s_driverinfo.numstrings/2; i++) {
+ UI_DrawString( 320-4, y, s_driverinfo.strings[i*2], UI_RIGHT|UI_SMALLFONT, text_color_normal );
+ UI_DrawString( 320+4, y, s_driverinfo.strings[i*2+1], UI_LEFT|UI_SMALLFONT, text_color_normal );
+ y += SMALLCHAR_HEIGHT;
+ }
+
+ if (s_driverinfo.numstrings & 1)
+ UI_DrawString( 320, y, s_driverinfo.strings[s_driverinfo.numstrings-1], UI_CENTER|UI_SMALLFONT, text_color_normal );
+}
+
+/*
+=================
+DriverInfo_Cache
+=================
+*/
+void DriverInfo_Cache( void )
+{
+ int i;
+
+ // touch all our pics
+ for (i=0; ;i++)
+ {
+ if (!driverinfo_artlist[i])
+ break;
+ trap_R_RegisterShaderNoMip(driverinfo_artlist[i]);
+ }
+}
+
+/*
+=================
+UI_DriverInfo_Menu
+=================
+*/
+static void UI_DriverInfo_Menu( void )
+{
+ char* eptr;
+ int i;
+ int len;
+
+ // zero set all our globals
+ memset( &s_driverinfo, 0 ,sizeof(driverinfo_t) );
+
+ DriverInfo_Cache();
+
+ s_driverinfo.menu.fullscreen = qtrue;
+ s_driverinfo.menu.draw = DriverInfo_MenuDraw;
+
+ s_driverinfo.banner.generic.type = MTYPE_BTEXT;
+ s_driverinfo.banner.generic.x = 320;
+ s_driverinfo.banner.generic.y = 16;
+ s_driverinfo.banner.string = "DRIVER INFO";
+ s_driverinfo.banner.color = color_white;
+ s_driverinfo.banner.style = UI_CENTER;
+
+ s_driverinfo.framel.generic.type = MTYPE_BITMAP;
+ s_driverinfo.framel.generic.name = DRIVERINFO_FRAMEL;
+ s_driverinfo.framel.generic.flags = QMF_INACTIVE;
+ s_driverinfo.framel.generic.x = 0;
+ s_driverinfo.framel.generic.y = 78;
+ s_driverinfo.framel.width = 256;
+ s_driverinfo.framel.height = 329;
+
+ s_driverinfo.framer.generic.type = MTYPE_BITMAP;
+ s_driverinfo.framer.generic.name = DRIVERINFO_FRAMER;
+ s_driverinfo.framer.generic.flags = QMF_INACTIVE;
+ s_driverinfo.framer.generic.x = 376;
+ s_driverinfo.framer.generic.y = 76;
+ s_driverinfo.framer.width = 256;
+ s_driverinfo.framer.height = 334;
+
+ s_driverinfo.back.generic.type = MTYPE_BITMAP;
+ s_driverinfo.back.generic.name = DRIVERINFO_BACK0;
+ s_driverinfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_driverinfo.back.generic.callback = DriverInfo_Event;
+ s_driverinfo.back.generic.id = ID_DRIVERINFOBACK;
+ s_driverinfo.back.generic.x = 0;
+ s_driverinfo.back.generic.y = 480-64;
+ s_driverinfo.back.width = 128;
+ s_driverinfo.back.height = 64;
+ s_driverinfo.back.focuspic = DRIVERINFO_BACK1;
+
+ // TTimo: overflow with particularly long GL extensions (such as the gf3)
+ // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=399
+ // NOTE: could have pushed the size of stringbuff, but the list is already out of the screen
+ // (no matter what your resolution)
+ Q_strncpyz(s_driverinfo.stringbuff, uis.glconfig.extensions_string, 1024);
+
+ // build null terminated extension strings
+ eptr = s_driverinfo.stringbuff;
+ while ( s_driverinfo.numstrings<40 && *eptr )
+ {
+ while ( *eptr && *eptr == ' ' )
+ *eptr++ = '\0';
+
+ // track start of valid string
+ if (*eptr && *eptr != ' ')
+ s_driverinfo.strings[s_driverinfo.numstrings++] = eptr;
+
+ while ( *eptr && *eptr != ' ' )
+ eptr++;
+ }
+
+ // safety length strings for display
+ for (i=0; i<s_driverinfo.numstrings; i++) {
+ len = strlen(s_driverinfo.strings[i]);
+ if (len > 32) {
+ s_driverinfo.strings[i][len-1] = '>';
+ s_driverinfo.strings[i][len] = '\0';
+ }
+ }
+
+ Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.banner );
+ Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.framel );
+ Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.framer );
+ Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.back );
+
+ UI_PushMenu( &s_driverinfo.menu );
+}
+
+/*
+=======================================================================
+
+GRAPHICS OPTIONS MENU
+
+=======================================================================
+*/
+
+#define GRAPHICSOPTIONS_FRAMEL "menu/art_blueish/frame2_l"
+#define GRAPHICSOPTIONS_FRAMER "menu/art_blueish/frame1_r"
+#define GRAPHICSOPTIONS_BACK0 "menu/art_blueish/back_0"
+#define GRAPHICSOPTIONS_BACK1 "menu/art_blueish/back_1"
+#define GRAPHICSOPTIONS_ACCEPT0 "menu/art_blueish/accept_0"
+#define GRAPHICSOPTIONS_ACCEPT1 "menu/art_blueish/accept_1"
+
+#define ID_BACK2 101
+#define ID_FULLSCREEN 102
+#define ID_LIST 103
+#define ID_MODE 104
+#define ID_DRIVERINFO 105
+#define ID_GRAPHICS 106
+#define ID_DISPLAY 107
+#define ID_SOUND 108
+#define ID_NETWORK 109
+#define ID_RATIO 110
+
+typedef struct {
+ menuframework_s menu;
+
+ menutext_s banner;
+ menubitmap_s framel;
+ menubitmap_s framer;
+
+ menutext_s graphics;
+ menutext_s display;
+ menutext_s sound;
+ menutext_s network;
+
+ menulist_s list;
+ menulist_s ratio;
+ menulist_s mode;
+ menulist_s driver;
+ menuslider_s tq;
+ menulist_s fs;
+ menulist_s lighting;
+ menulist_s flares;
+ menulist_s bloom;
+ menulist_s allow_extensions;
+ menulist_s texturebits;
+ menulist_s geometry;
+ menulist_s filter;
+ menulist_s aniso;
+ menutext_s driverinfo;
+
+ menubitmap_s apply;
+ menubitmap_s back;
+} graphicsoptions_t;
+
+typedef struct
+{
+ int mode;
+ qboolean fullscreen;
+ int tq;
+ int lighting;
+ qboolean flares;
+ qboolean bloom;
+ int texturebits;
+ int geometry;
+ int filter;
+ int aniso;
+ int driver;
+ qboolean extensions;
+} InitialVideoOptions_s;
+
+static InitialVideoOptions_s s_ivo;
+static graphicsoptions_t s_graphicsoptions;
+
+static InitialVideoOptions_s s_ivo_templates[] =
+{
+ {
+ 6, qtrue, 3, 0, qfalse,qfalse, 2, 2, 1, 0, 0, qtrue
+ },
+ {
+ 4, qtrue, 2, 0, qfalse,qfalse, 2, 1, 1, 0, 0, qtrue // JDC: this was tq 3
+ },
+ {
+ 3, qtrue, 2, 0, qfalse,qfalse, 0, 1, 0, 0, 0, qtrue
+ },
+ {
+ 2, qtrue, 1, 0, qfalse,qfalse, 0, 0, 0, 0, 0, qtrue
+ },
+ {
+ 2, qtrue, 1, 1, qfalse,qfalse, 0, 0, 0, 0, 0, qtrue
+ },
+ {
+ 3, qtrue, 1, 0, qfalse,qfalse, 0, 1, 0, 0, 0, qtrue
+ }
+};
+
+#define NUM_IVO_TEMPLATES ( sizeof( s_ivo_templates ) / sizeof( s_ivo_templates[0] ) )
+
+static const char *builtinResolutions[ ] =
+{
+ "320x240",
+ "400x300",
+ "512x384",
+ "640x480",
+ "800x600",
+ "960x720",
+ "1024x768",
+ "1152x864",
+ "1280x1024",
+ "1600x1200",
+ "2048x1536",
+ "856x480",
+ NULL
+};
+
+static const char *knownRatios[ ][2] =
+{
+ { "1.25:1", "5:4" },
+ { "1.33:1", "4:3" },
+ { "1.50:1", "3:2" },
+ { "1.56:1", "14:9" },
+ { "1.60:1", "16:10" },
+ { "1.67:1", "5:3" },
+ { "1.78:1", "16:9" },
+ { NULL , NULL }
+};
+
+#define MAX_RESOLUTIONS 32
+
+static const char* ratios[ MAX_RESOLUTIONS ];
+static char ratioBuf[ MAX_RESOLUTIONS ][ 8 ];
+static int ratioToRes[ MAX_RESOLUTIONS ];
+static int resToRatio[ MAX_RESOLUTIONS ];
+
+static char resbuf[ MAX_STRING_CHARS ];
+static const char* detectedResolutions[ MAX_RESOLUTIONS ];
+
+static const char** resolutions = builtinResolutions;
+static qboolean resolutionsDetected = qfalse;
+
+/*
+=================
+GraphicsOptions_FindBuiltinResolution
+=================
+*/
+static int GraphicsOptions_FindBuiltinResolution( int mode )
+{
+ int i;
+
+ if( !resolutionsDetected )
+ return mode;
+
+ if( mode < 0 )
+ return -1;
+
+ for( i = 0; builtinResolutions[ i ]; i++ )
+ {
+ if( !Q_stricmp( builtinResolutions[ i ], detectedResolutions[ mode ] ) )
+ return i;
+ }
+
+ return -1;
+}
+
+/*
+=================
+GraphicsOptions_FindDetectedResolution
+=================
+*/
+static int GraphicsOptions_FindDetectedResolution( int mode )
+{
+ int i;
+
+ if( !resolutionsDetected )
+ return mode;
+
+ if( mode < 0 )
+ return -1;
+
+ for( i = 0; detectedResolutions[ i ]; i++ )
+ {
+ if( !Q_stricmp( builtinResolutions[ mode ], detectedResolutions[ i ] ) )
+ return i;
+ }
+
+ return -1;
+}
+
+/*
+=================
+GraphicsOptions_GetAspectRatios
+=================
+*/
+static void GraphicsOptions_GetAspectRatios( void )
+{
+ int i, r;
+
+ // build ratio list from resolutions
+ for( r = 0; resolutions[r]; r++ )
+ {
+ int w, h;
+ char *x;
+ char str[ sizeof(ratioBuf[0]) ];
+
+ // calculate resolution's aspect ratio
+ x = strchr( resolutions[r], 'x' )+1;
+
+
+ Q_strncpyz( str, resolutions[r], x-resolutions[r] );
+ w = atoi( str );
+ h = atoi( x );
+ Com_sprintf( str, sizeof(str), "%.2f:1", (float)w / (float)h );
+
+ // rename common ratios ("1.33:1" -> "4:3")
+ for( i = 0; knownRatios[i][0]; i++ ) {
+ if( !Q_stricmp( str, knownRatios[i][0] ) ) {
+ Q_strncpyz( str, knownRatios[i][1], sizeof( str ) );
+ break;
+ }
+ }
+
+ // add ratio to list if it is new
+ // establish res/ratio relationship
+ for( i = 0; ratioBuf[i][0]; i++ )
+ {
+ if( !Q_stricmp( str, ratioBuf[i] ) )
+ break;
+ }
+ if( !ratioBuf[i][0] )
+ {
+ Q_strncpyz( ratioBuf[i], str, sizeof(ratioBuf[i]) );
+ ratioToRes[i] = r;
+ }
+ ratios[r] = ratioBuf[r];
+ resToRatio[r] = i;
+ }
+ ratios[r] = NULL;
+}
+
+/*
+=================
+GraphicsOptions_GetInitialVideo
+=================
+*/
+static void GraphicsOptions_GetInitialVideo( void )
+{
+ s_ivo.driver = s_graphicsoptions.driver.curvalue;
+ s_ivo.mode = s_graphicsoptions.mode.curvalue;
+ s_ivo.fullscreen = s_graphicsoptions.fs.curvalue;
+ s_ivo.extensions = s_graphicsoptions.allow_extensions.curvalue;
+ s_ivo.tq = s_graphicsoptions.tq.curvalue;
+ s_ivo.lighting = s_graphicsoptions.lighting.curvalue;
+ s_ivo.flares = s_graphicsoptions.flares.curvalue;
+ s_ivo.bloom = s_graphicsoptions.bloom.curvalue;
+ s_ivo.geometry = s_graphicsoptions.geometry.curvalue;
+ s_ivo.filter = s_graphicsoptions.filter.curvalue;
+ s_ivo.aniso = s_graphicsoptions.aniso.curvalue;
+ s_ivo.texturebits = s_graphicsoptions.texturebits.curvalue;
+}
+
+/*
+=================
+GraphicsOptions_GetResolutions
+=================
+*/
+static void GraphicsOptions_GetResolutions( void )
+{
+ Q_strncpyz(resbuf, UI_Cvar_VariableString("r_availableModes"), sizeof(resbuf));
+ if(*resbuf)
+ {
+ char* s = resbuf;
+ unsigned int i = 0;
+ while( s && i < sizeof(detectedResolutions)/sizeof(detectedResolutions[0])-1)
+ {
+ detectedResolutions[i++] = s;
+ s = strchr(s, ' ');
+ if( s )
+ *s++ = '\0';
+ }
+ detectedResolutions[ i ] = NULL;
+
+ if( i > 0 )
+ {
+ resolutions = detectedResolutions;
+ resolutionsDetected = qtrue;
+ }
+ }
+}
+
+/*
+=================
+GraphicsOptions_CheckConfig
+=================
+*/
+static void GraphicsOptions_CheckConfig( void )
+{
+ int i;
+
+ for ( i = 0; i < NUM_IVO_TEMPLATES-1; i++ )
+ {
+ if ( s_ivo_templates[i].driver != s_graphicsoptions.driver.curvalue )
+ continue;
+ if ( GraphicsOptions_FindDetectedResolution(s_ivo_templates[i].mode) != s_graphicsoptions.mode.curvalue )
+ continue;
+ if ( s_ivo_templates[i].fullscreen != s_graphicsoptions.fs.curvalue )
+ continue;
+ if ( s_ivo_templates[i].tq != s_graphicsoptions.tq.curvalue )
+ continue;
+ if ( s_ivo_templates[i].lighting != s_graphicsoptions.lighting.curvalue )
+ continue;
+ if ( s_ivo_templates[i].flares != s_graphicsoptions.flares.curvalue )
+ continue;
+ if ( s_ivo_templates[i].bloom != s_graphicsoptions.bloom.curvalue )
+ continue;
+ if ( s_ivo_templates[i].geometry != s_graphicsoptions.geometry.curvalue )
+ continue;
+ if ( s_ivo_templates[i].filter != s_graphicsoptions.filter.curvalue )
+ continue;
+ if ( s_ivo_templates[i].aniso != s_graphicsoptions.aniso.curvalue )
+ continue;
+// if ( s_ivo_templates[i].texturebits != s_graphicsoptions.texturebits.curvalue )
+// continue;
+ s_graphicsoptions.list.curvalue = i;
+ return;
+ }
+
+ // return 'Custom' ivo template
+ s_graphicsoptions.list.curvalue = NUM_IVO_TEMPLATES - 1;
+}
+
+/*
+=================
+GraphicsOptions_UpdateMenuItems
+=================
+*/
+static void GraphicsOptions_UpdateMenuItems( void )
+{
+ if ( s_graphicsoptions.driver.curvalue == 1 )
+ {
+ s_graphicsoptions.fs.curvalue = 1;
+ s_graphicsoptions.fs.generic.flags |= QMF_GRAYED;
+ }
+ else
+ {
+ s_graphicsoptions.fs.generic.flags &= ~QMF_GRAYED;
+ }
+
+ if ( s_graphicsoptions.allow_extensions.curvalue == 0 )
+ {
+ if ( s_graphicsoptions.texturebits.curvalue == 0 )
+ {
+ s_graphicsoptions.texturebits.curvalue = 1;
+ }
+ }
+
+ s_graphicsoptions.apply.generic.flags |= QMF_HIDDEN|QMF_INACTIVE;
+
+ if ( s_ivo.mode != s_graphicsoptions.mode.curvalue )
+ {
+ s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
+ }
+ if ( s_ivo.fullscreen != s_graphicsoptions.fs.curvalue )
+ {
+ s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
+ }
+ if ( s_ivo.extensions != s_graphicsoptions.allow_extensions.curvalue )
+ {
+ s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
+ }
+ if ( s_ivo.tq != s_graphicsoptions.tq.curvalue )
+ {
+ s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
+ }
+ if ( s_ivo.lighting != s_graphicsoptions.lighting.curvalue )
+ {
+ s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
+ }
+ if ( s_ivo.flares != s_graphicsoptions.flares.curvalue )
+ {
+ s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
+ }
+ if ( s_ivo.bloom != s_graphicsoptions.bloom.curvalue )
+ {
+ s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
+ }
+ if ( s_ivo.driver != s_graphicsoptions.driver.curvalue )
+ {
+ s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
+ }
+ if ( s_ivo.texturebits != s_graphicsoptions.texturebits.curvalue )
+ {
+ s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
+ }
+ if ( s_ivo.geometry != s_graphicsoptions.geometry.curvalue )
+ {
+ s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
+ }
+ if ( s_ivo.filter != s_graphicsoptions.filter.curvalue )
+ {
+ s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
+ }
+ if ( s_ivo.aniso != s_graphicsoptions.aniso.curvalue )
+ {
+ s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
+ }
+
+ GraphicsOptions_CheckConfig();
+}
+
+/*
+=================
+GraphicsOptions_ApplyChanges
+=================
+*/
+static void GraphicsOptions_ApplyChanges( void *unused, int notification )
+{
+ if (notification != QM_ACTIVATED)
+ return;
+
+ switch ( s_graphicsoptions.texturebits.curvalue )
+ {
+ case 0:
+ trap_Cvar_SetValue( "r_texturebits", 0 );
+ break;
+ case 1:
+ trap_Cvar_SetValue( "r_texturebits", 16 );
+ break;
+ case 2:
+ trap_Cvar_SetValue( "r_texturebits", 32 );
+ break;
+ }
+ trap_Cvar_SetValue( "r_picmip", 3 - s_graphicsoptions.tq.curvalue );
+ trap_Cvar_SetValue( "r_allowExtensions", s_graphicsoptions.allow_extensions.curvalue );
+
+ if( resolutionsDetected )
+ {
+ // search for builtin mode that matches the detected mode
+ int mode;
+ if ( s_graphicsoptions.mode.curvalue == -1
+ || s_graphicsoptions.mode.curvalue >= sizeof(detectedResolutions)/sizeof(detectedResolutions[0]) )
+ s_graphicsoptions.mode.curvalue = 0;
+
+ mode = GraphicsOptions_FindBuiltinResolution( s_graphicsoptions.mode.curvalue );
+ if( mode == -1 )
+ {
+ char w[ 16 ], h[ 16 ];
+ Q_strncpyz( w, detectedResolutions[ s_graphicsoptions.mode.curvalue ], sizeof( w ) );
+ *strchr( w, 'x' ) = 0;
+ Q_strncpyz( h,
+ strchr( detectedResolutions[ s_graphicsoptions.mode.curvalue ], 'x' ) + 1, sizeof( h ) );
+ trap_Cvar_Set( "r_customwidth", w );
+ trap_Cvar_Set( "r_customheight", h );
+ }
+
+ trap_Cvar_SetValue( "r_mode", mode );
+ }
+ else
+ trap_Cvar_SetValue( "r_mode", s_graphicsoptions.mode.curvalue );
+
+ trap_Cvar_SetValue( "r_fullscreen", s_graphicsoptions.fs.curvalue );
+ trap_Cvar_SetValue( "r_colorbits", 0 );
+ trap_Cvar_SetValue( "r_depthbits", 0 );
+ trap_Cvar_SetValue( "r_stencilbits", 0 );
+ trap_Cvar_SetValue( "r_vertexLight", s_graphicsoptions.lighting.curvalue );
+ trap_Cvar_SetValue( "cg_autovertex", s_graphicsoptions.lighting.curvalue );
+ trap_Cvar_SetValue( "r_flares", s_graphicsoptions.flares.curvalue );
+ trap_Cvar_SetValue( "r_bloom", s_graphicsoptions.bloom.curvalue );
+
+ //r_ext_texture_filter_anisotropic is special
+ if(s_graphicsoptions.aniso.curvalue) {
+ trap_Cvar_SetValue( "r_ext_max_anisotropy", s_graphicsoptions.aniso.curvalue*2 );
+ trap_Cvar_SetValue( "r_ext_texture_filter_anisotropic", qtrue );
+ }
+ else
+ trap_Cvar_SetValue( "r_ext_texture_filter_anisotropic", qfalse );
+
+ trap_Cvar_SetValue( "com_hunkmegs", 128 );
+
+
+ if ( s_graphicsoptions.geometry.curvalue == 2 )
+ {
+ trap_Cvar_SetValue( "r_lodBias", 0 );
+ trap_Cvar_SetValue( "r_subdivisions", 4 );
+ }
+ else if ( s_graphicsoptions.geometry.curvalue == 1 )
+ {
+ trap_Cvar_SetValue( "r_lodBias", 1 );
+ trap_Cvar_SetValue( "r_subdivisions", 12 );
+ }
+ else
+ {
+ trap_Cvar_SetValue( "r_lodBias", 1 );
+ trap_Cvar_SetValue( "r_subdivisions", 20 );
+ }
+
+ if ( s_graphicsoptions.filter.curvalue )
+ {
+ trap_Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR" );
+ }
+ else
+ {
+ trap_Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" );
+ }
+
+ trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" );
+}
+
+/*
+=================
+GraphicsOptions_Event
+=================
+*/
+static void GraphicsOptions_Event( void* ptr, int event ) {
+ InitialVideoOptions_s *ivo;
+
+ if( event != QM_ACTIVATED ) {
+ return;
+ }
+
+ switch( ((menucommon_s*)ptr)->id ) {
+ case ID_RATIO:
+ s_graphicsoptions.mode.curvalue = ratioToRes[ s_graphicsoptions.ratio.curvalue ];
+ // fall through to apply mode constraints
+ case ID_MODE:
+ // clamp 3dfx video modes
+ if ( s_graphicsoptions.driver.curvalue == 1 )
+ {
+ if ( s_graphicsoptions.mode.curvalue < 2 )
+ s_graphicsoptions.mode.curvalue = 2;
+ else if ( s_graphicsoptions.mode.curvalue > 6 )
+ s_graphicsoptions.mode.curvalue = 6;
+ }
+ s_graphicsoptions.ratio.curvalue = resToRatio[ s_graphicsoptions.mode.curvalue ];
+ break;
+
+ case ID_LIST:
+ ivo = &s_ivo_templates[s_graphicsoptions.list.curvalue];
+
+ s_graphicsoptions.mode.curvalue = GraphicsOptions_FindDetectedResolution(ivo->mode);
+ s_graphicsoptions.ratio.curvalue = resToRatio[ s_graphicsoptions.mode.curvalue ];
+ s_graphicsoptions.tq.curvalue = ivo->tq;
+ s_graphicsoptions.lighting.curvalue = ivo->lighting;
+ s_graphicsoptions.texturebits.curvalue = ivo->texturebits;
+ s_graphicsoptions.geometry.curvalue = ivo->geometry;
+ s_graphicsoptions.filter.curvalue = ivo->filter;
+ s_graphicsoptions.aniso.curvalue = ivo->aniso;
+ s_graphicsoptions.fs.curvalue = ivo->fullscreen;
+ s_graphicsoptions.flares.curvalue = ivo->flares;
+ s_graphicsoptions.bloom.curvalue = ivo->bloom;
+ break;
+
+ case ID_DRIVERINFO:
+ UI_DriverInfo_Menu();
+ break;
+
+ case ID_BACK2:
+ UI_PopMenu();
+ break;
+
+ case ID_GRAPHICS:
+ break;
+
+ case ID_DISPLAY:
+ UI_PopMenu();
+ UI_DisplayOptionsMenu();
+ break;
+
+ case ID_SOUND:
+ UI_PopMenu();
+ UI_SoundOptionsMenu();
+ break;
+
+ case ID_NETWORK:
+ UI_PopMenu();
+ UI_NetworkOptionsMenu();
+ break;
+ }
+}
+
+
+/*
+================
+GraphicsOptions_TQEvent
+================
+*/
+static void GraphicsOptions_TQEvent( void *ptr, int event ) {
+ if( event != QM_ACTIVATED ) {
+ return;
+ }
+ s_graphicsoptions.tq.curvalue = (int)(s_graphicsoptions.tq.curvalue + 0.5);
+}
+
+
+/*
+================
+GraphicsOptions_MenuDraw
+================
+*/
+void GraphicsOptions_MenuDraw (void)
+{
+//APSFIX - rework this
+ GraphicsOptions_UpdateMenuItems();
+
+ Menu_Draw( &s_graphicsoptions.menu );
+}
+
+/*
+=================
+GraphicsOptions_SetMenuItems
+=================
+*/
+static void GraphicsOptions_SetMenuItems( void )
+{
+ s_graphicsoptions.mode.curvalue =
+ GraphicsOptions_FindDetectedResolution( trap_Cvar_VariableValue( "r_mode" ) );
+
+ if ( s_graphicsoptions.mode.curvalue < 0 )
+ {
+ if( resolutionsDetected )
+ {
+ int i;
+ char buf[MAX_STRING_CHARS];
+ trap_Cvar_VariableStringBuffer("r_customwidth", buf, sizeof(buf)-2);
+ buf[strlen(buf)+1] = 0;
+ buf[strlen(buf)] = 'x';
+ trap_Cvar_VariableStringBuffer("r_customheight", buf+strlen(buf), sizeof(buf)-strlen(buf));
+
+ for(i = 0; detectedResolutions[i]; ++i)
+ {
+ if(!Q_stricmp(buf, detectedResolutions[i]))
+ {
+ s_graphicsoptions.mode.curvalue = i;
+ break;
+ }
+ }
+ if ( s_graphicsoptions.mode.curvalue < 0 )
+ s_graphicsoptions.mode.curvalue = 0;
+ }
+ else
+ {
+ s_graphicsoptions.mode.curvalue = 3;
+ }
+ }
+ s_graphicsoptions.fs.curvalue = trap_Cvar_VariableValue("r_fullscreen");
+ s_graphicsoptions.allow_extensions.curvalue = trap_Cvar_VariableValue("r_allowExtensions");
+ s_graphicsoptions.flares.curvalue = trap_Cvar_VariableValue("r_flares");
+ s_graphicsoptions.bloom.curvalue = trap_Cvar_VariableValue("r_bloom");
+ if(trap_Cvar_VariableValue("r_ext_texture_filter_anisotropic")) {
+ s_graphicsoptions.aniso.curvalue = trap_Cvar_VariableValue("r_ext_max_anisotropy")/2;
+ }
+ s_graphicsoptions.tq.curvalue = 3-trap_Cvar_VariableValue( "r_picmip");
+ if ( s_graphicsoptions.tq.curvalue < 0 )
+ {
+ s_graphicsoptions.tq.curvalue = 0;
+ }
+ else if ( s_graphicsoptions.tq.curvalue > 3 )
+ {
+ s_graphicsoptions.tq.curvalue = 3;
+ }
+
+ s_graphicsoptions.lighting.curvalue = trap_Cvar_VariableValue( "r_vertexLight" ) != 0;
+ switch ( ( int ) trap_Cvar_VariableValue( "r_texturebits" ) )
+ {
+ default:
+ case 0:
+ s_graphicsoptions.texturebits.curvalue = 0;
+ break;
+ case 16:
+ s_graphicsoptions.texturebits.curvalue = 1;
+ break;
+ case 32:
+ s_graphicsoptions.texturebits.curvalue = 2;
+ break;
+ }
+
+ if ( !Q_stricmp( UI_Cvar_VariableString( "r_textureMode" ), "GL_LINEAR_MIPMAP_NEAREST" ) )
+ {
+ s_graphicsoptions.filter.curvalue = 0;
+ }
+ else
+ {
+ s_graphicsoptions.filter.curvalue = 1;
+ }
+
+ if ( trap_Cvar_VariableValue( "r_lodBias" ) > 0 )
+ {
+ if ( trap_Cvar_VariableValue( "r_subdivisions" ) >= 20 )
+ {
+ s_graphicsoptions.geometry.curvalue = 0;
+ }
+ else
+ {
+ s_graphicsoptions.geometry.curvalue = 1;
+ }
+ }
+ else
+ {
+ s_graphicsoptions.geometry.curvalue = 2;
+ }
+}
+
+/*
+================
+GraphicsOptions_MenuInit
+================
+*/
+void GraphicsOptions_MenuInit( void )
+{
+ static const char *s_driver_names[] =
+ {
+ "Default",
+ "Voodoo",
+ NULL
+ };
+
+ static const char *tq_names[] =
+ {
+ "Default",
+ "16 bit",
+ "32 bit",
+ NULL
+ };
+
+ static const char *s_graphics_options_names[] =
+ {
+ "Very High Quality",
+ "High Quality",
+ "Normal",
+ "Fast",
+ "Fastest",
+ "Custom",
+ NULL
+ };
+
+ static const char *lighting_names[] =
+ {
+ "Lightmap (Normal)",
+ "Vertex (Low)",
+ NULL
+ };
+
+
+ static const char *filter_names[] =
+ {
+ "Bilinear",
+ "Trilinear",
+ NULL
+ };
+
+ static const char *aniso_names[] =
+ {
+ "Off",
+ "2x",
+ "4x",
+ "6x",
+ "8x",
+ NULL
+ };
+
+ static const char *quality_names[] =
+ {
+ "Low",
+ "Medium",
+ "High",
+ NULL
+ };
+ static const char *enabled_names[] =
+ {
+ "Off",
+ "On",
+ NULL
+ };
+
+ int y;
+
+ // zero set all our globals
+ memset( &s_graphicsoptions, 0 ,sizeof(graphicsoptions_t) );
+
+
+ GraphicsOptions_GetResolutions();
+ GraphicsOptions_GetAspectRatios();
+
+ GraphicsOptions_Cache();
+
+ s_graphicsoptions.menu.wrapAround = qtrue;
+ s_graphicsoptions.menu.fullscreen = qtrue;
+ s_graphicsoptions.menu.draw = GraphicsOptions_MenuDraw;
+
+ s_graphicsoptions.banner.generic.type = MTYPE_BTEXT;
+ s_graphicsoptions.banner.generic.x = 320;
+ s_graphicsoptions.banner.generic.y = 16;
+ s_graphicsoptions.banner.string = "SYSTEM SETUP";
+ s_graphicsoptions.banner.color = color_white;
+ s_graphicsoptions.banner.style = UI_CENTER;
+
+ s_graphicsoptions.framel.generic.type = MTYPE_BITMAP;
+ s_graphicsoptions.framel.generic.name = GRAPHICSOPTIONS_FRAMEL;
+ s_graphicsoptions.framel.generic.flags = QMF_INACTIVE;
+ s_graphicsoptions.framel.generic.x = 0;
+ s_graphicsoptions.framel.generic.y = 78;
+ s_graphicsoptions.framel.width = 256;
+ s_graphicsoptions.framel.height = 329;
+
+ s_graphicsoptions.framer.generic.type = MTYPE_BITMAP;
+ s_graphicsoptions.framer.generic.name = GRAPHICSOPTIONS_FRAMER;
+ s_graphicsoptions.framer.generic.flags = QMF_INACTIVE;
+ s_graphicsoptions.framer.generic.x = 376;
+ s_graphicsoptions.framer.generic.y = 76;
+ s_graphicsoptions.framer.width = 256;
+ s_graphicsoptions.framer.height = 334;
+
+ s_graphicsoptions.graphics.generic.type = MTYPE_PTEXT;
+ s_graphicsoptions.graphics.generic.flags = QMF_RIGHT_JUSTIFY;
+ s_graphicsoptions.graphics.generic.id = ID_GRAPHICS;
+ s_graphicsoptions.graphics.generic.callback = GraphicsOptions_Event;
+ s_graphicsoptions.graphics.generic.x = 216;
+ s_graphicsoptions.graphics.generic.y = 240 - 2 * PROP_HEIGHT;
+ s_graphicsoptions.graphics.string = "GRAPHICS";
+ s_graphicsoptions.graphics.style = UI_RIGHT;
+ s_graphicsoptions.graphics.color = color_red;
+
+ s_graphicsoptions.display.generic.type = MTYPE_PTEXT;
+ s_graphicsoptions.display.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_graphicsoptions.display.generic.id = ID_DISPLAY;
+ s_graphicsoptions.display.generic.callback = GraphicsOptions_Event;
+ s_graphicsoptions.display.generic.x = 216;
+ s_graphicsoptions.display.generic.y = 240 - PROP_HEIGHT;
+ s_graphicsoptions.display.string = "DISPLAY";
+ s_graphicsoptions.display.style = UI_RIGHT;
+ s_graphicsoptions.display.color = color_red;
+
+ s_graphicsoptions.sound.generic.type = MTYPE_PTEXT;
+ s_graphicsoptions.sound.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_graphicsoptions.sound.generic.id = ID_SOUND;
+ s_graphicsoptions.sound.generic.callback = GraphicsOptions_Event;
+ s_graphicsoptions.sound.generic.x = 216;
+ s_graphicsoptions.sound.generic.y = 240;
+ s_graphicsoptions.sound.string = "SOUND";
+ s_graphicsoptions.sound.style = UI_RIGHT;
+ s_graphicsoptions.sound.color = color_red;
+
+ s_graphicsoptions.network.generic.type = MTYPE_PTEXT;
+ s_graphicsoptions.network.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_graphicsoptions.network.generic.id = ID_NETWORK;
+ s_graphicsoptions.network.generic.callback = GraphicsOptions_Event;
+ s_graphicsoptions.network.generic.x = 216;
+ s_graphicsoptions.network.generic.y = 240 + PROP_HEIGHT;
+ s_graphicsoptions.network.string = "NETWORK";
+ s_graphicsoptions.network.style = UI_RIGHT;
+ s_graphicsoptions.network.color = color_red;
+
+ y = 240 - 7 * (BIGCHAR_HEIGHT + 2);
+ s_graphicsoptions.list.generic.type = MTYPE_SPINCONTROL;
+ s_graphicsoptions.list.generic.name = "Graphics Settings:";
+ s_graphicsoptions.list.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.list.generic.x = 400;
+ s_graphicsoptions.list.generic.y = y;
+ s_graphicsoptions.list.generic.callback = GraphicsOptions_Event;
+ s_graphicsoptions.list.generic.id = ID_LIST;
+ s_graphicsoptions.list.itemnames = s_graphics_options_names;
+ y += 2 * ( BIGCHAR_HEIGHT + 2 );
+
+ s_graphicsoptions.driver.generic.type = MTYPE_SPINCONTROL;
+ s_graphicsoptions.driver.generic.name = "GL Driver:";
+ s_graphicsoptions.driver.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.driver.generic.x = 400;
+ s_graphicsoptions.driver.generic.y = y;
+ s_graphicsoptions.driver.itemnames = s_driver_names;
+ s_graphicsoptions.driver.curvalue = (uis.glconfig.driverType == GLDRV_VOODOO);
+ y += BIGCHAR_HEIGHT+2;
+
+ // references/modifies "r_allowExtensions"
+ s_graphicsoptions.allow_extensions.generic.type = MTYPE_SPINCONTROL;
+ s_graphicsoptions.allow_extensions.generic.name = "GL Extensions:";
+ s_graphicsoptions.allow_extensions.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.allow_extensions.generic.x = 400;
+ s_graphicsoptions.allow_extensions.generic.y = y;
+ s_graphicsoptions.allow_extensions.itemnames = enabled_names;
+ y += BIGCHAR_HEIGHT+2;
+
+ s_graphicsoptions.ratio.generic.type = MTYPE_SPINCONTROL;
+ s_graphicsoptions.ratio.generic.name = "Aspect Ratio:";
+ s_graphicsoptions.ratio.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.ratio.generic.x = 400;
+ s_graphicsoptions.ratio.generic.y = y;
+ s_graphicsoptions.ratio.itemnames = ratios;
+ s_graphicsoptions.ratio.generic.callback = GraphicsOptions_Event;
+ s_graphicsoptions.ratio.generic.id = ID_RATIO;
+ y += BIGCHAR_HEIGHT+2;
+
+
+ // references/modifies "r_mode"
+ s_graphicsoptions.mode.generic.type = MTYPE_SPINCONTROL;
+ s_graphicsoptions.mode.generic.name = "Resolution:";
+ s_graphicsoptions.mode.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.mode.generic.x = 400;
+ s_graphicsoptions.mode.generic.y = y;
+ s_graphicsoptions.mode.itemnames = resolutions;
+ s_graphicsoptions.mode.generic.callback = GraphicsOptions_Event;
+ s_graphicsoptions.mode.generic.id = ID_MODE;
+ y += BIGCHAR_HEIGHT+2;
+
+ // references/modifies "r_fullscreen"
+ s_graphicsoptions.fs.generic.type = MTYPE_SPINCONTROL;
+ s_graphicsoptions.fs.generic.name = "Fullscreen:";
+ s_graphicsoptions.fs.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.fs.generic.x = 400;
+ s_graphicsoptions.fs.generic.y = y;
+ s_graphicsoptions.fs.itemnames = enabled_names;
+ y += BIGCHAR_HEIGHT+2;
+
+ // references/modifies "r_vertexLight"
+ s_graphicsoptions.lighting.generic.type = MTYPE_SPINCONTROL;
+ s_graphicsoptions.lighting.generic.name = "Lighting:";
+ s_graphicsoptions.lighting.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.lighting.generic.x = 400;
+ s_graphicsoptions.lighting.generic.y = y;
+ s_graphicsoptions.lighting.itemnames = lighting_names;
+ y += BIGCHAR_HEIGHT+2;
+
+ // references/modifies "r_flares"
+ s_graphicsoptions.flares.generic.type = MTYPE_SPINCONTROL;
+ s_graphicsoptions.flares.generic.name = "Flares:";
+ s_graphicsoptions.flares.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.flares.generic.x = 400;
+ s_graphicsoptions.flares.generic.y = y;
+ s_graphicsoptions.flares.itemnames = enabled_names;
+ y += BIGCHAR_HEIGHT+2;
+
+ // references/modifies "r_bloom"
+ s_graphicsoptions.bloom.generic.type = MTYPE_SPINCONTROL;
+ s_graphicsoptions.bloom.generic.name = "Bloom:";
+ s_graphicsoptions.bloom.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.bloom.generic.x = 400;
+ s_graphicsoptions.bloom.generic.y = y;
+ s_graphicsoptions.bloom.itemnames = enabled_names;
+ y += BIGCHAR_HEIGHT+2;
+
+ // references/modifies "r_lodBias" & "subdivisions"
+ s_graphicsoptions.geometry.generic.type = MTYPE_SPINCONTROL;
+ s_graphicsoptions.geometry.generic.name = "Geometric Detail:";
+ s_graphicsoptions.geometry.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.geometry.generic.x = 400;
+ s_graphicsoptions.geometry.generic.y = y;
+ s_graphicsoptions.geometry.itemnames = quality_names;
+ y += BIGCHAR_HEIGHT+2;
+
+ // references/modifies "r_picmip"
+ s_graphicsoptions.tq.generic.type = MTYPE_SLIDER;
+ s_graphicsoptions.tq.generic.name = "Texture Detail:";
+ s_graphicsoptions.tq.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.tq.generic.x = 400;
+ s_graphicsoptions.tq.generic.y = y;
+ s_graphicsoptions.tq.minvalue = 0;
+ s_graphicsoptions.tq.maxvalue = 3;
+ s_graphicsoptions.tq.generic.callback = GraphicsOptions_TQEvent;
+ y += BIGCHAR_HEIGHT+2;
+
+ // references/modifies "r_textureBits"
+ s_graphicsoptions.texturebits.generic.type = MTYPE_SPINCONTROL;
+ s_graphicsoptions.texturebits.generic.name = "Texture Quality:";
+ s_graphicsoptions.texturebits.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.texturebits.generic.x = 400;
+ s_graphicsoptions.texturebits.generic.y = y;
+ s_graphicsoptions.texturebits.itemnames = tq_names;
+ y += BIGCHAR_HEIGHT+2;
+
+ // references/modifies "r_textureMode"
+ s_graphicsoptions.filter.generic.type = MTYPE_SPINCONTROL;
+ s_graphicsoptions.filter.generic.name = "Texture Filter:";
+ s_graphicsoptions.filter.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.filter.generic.x = 400;
+ s_graphicsoptions.filter.generic.y = y;
+ s_graphicsoptions.filter.itemnames = filter_names;
+ y += 2+BIGCHAR_HEIGHT;
+
+ s_graphicsoptions.aniso.generic.type = MTYPE_SPINCONTROL;
+ s_graphicsoptions.aniso.generic.name = "Anisotropy:";
+ s_graphicsoptions.aniso.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
+ s_graphicsoptions.aniso.generic.x = 400;
+ s_graphicsoptions.aniso.generic.y = y;
+ s_graphicsoptions.aniso.itemnames = aniso_names;
+ y += 2*BIGCHAR_HEIGHT;
+
+ s_graphicsoptions.driverinfo.generic.type = MTYPE_PTEXT;
+ s_graphicsoptions.driverinfo.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_graphicsoptions.driverinfo.generic.callback = GraphicsOptions_Event;
+ s_graphicsoptions.driverinfo.generic.id = ID_DRIVERINFO;
+ s_graphicsoptions.driverinfo.generic.x = 320;
+ s_graphicsoptions.driverinfo.generic.y = y;
+ s_graphicsoptions.driverinfo.string = "Driver Info";
+ s_graphicsoptions.driverinfo.style = UI_CENTER|UI_SMALLFONT;
+ s_graphicsoptions.driverinfo.color = color_red;
+ y += BIGCHAR_HEIGHT+2;
+
+ s_graphicsoptions.back.generic.type = MTYPE_BITMAP;
+ s_graphicsoptions.back.generic.name = GRAPHICSOPTIONS_BACK0;
+ s_graphicsoptions.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
+ s_graphicsoptions.back.generic.callback = GraphicsOptions_Event;
+ s_graphicsoptions.back.generic.id = ID_BACK2;
+ s_graphicsoptions.back.generic.x = 0;
+ s_graphicsoptions.back.generic.y = 480-64;
+ s_graphicsoptions.back.width = 128;
+ s_graphicsoptions.back.height = 64;
+ s_graphicsoptions.back.focuspic = GRAPHICSOPTIONS_BACK1;
+
+ s_graphicsoptions.apply.generic.type = MTYPE_BITMAP;
+ s_graphicsoptions.apply.generic.name = GRAPHICSOPTIONS_ACCEPT0;
+ s_graphicsoptions.apply.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_HIDDEN|QMF_INACTIVE;
+ s_graphicsoptions.apply.generic.callback = GraphicsOptions_ApplyChanges;
+ s_graphicsoptions.apply.generic.x = 640;
+ s_graphicsoptions.apply.generic.y = 480-64;
+ s_graphicsoptions.apply.width = 128;
+ s_graphicsoptions.apply.height = 64;
+ s_graphicsoptions.apply.focuspic = GRAPHICSOPTIONS_ACCEPT1;
+
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.banner );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.framel );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.framer );
+
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.graphics );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.display );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.sound );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.network );
+
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.list );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.driver );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.allow_extensions );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.ratio );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.mode );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.fs );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.lighting );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.flares );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.bloom );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.geometry );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.tq );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.texturebits );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.filter );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.aniso );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.driverinfo );
+
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.back );
+ Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.apply );
+
+ GraphicsOptions_SetMenuItems();
+ GraphicsOptions_GetInitialVideo();
+
+ if ( uis.glconfig.driverType == GLDRV_ICD &&
+ uis.glconfig.hardwareType == GLHW_3DFX_2D3D )
+ {
+ s_graphicsoptions.driver.generic.flags |= QMF_HIDDEN|QMF_INACTIVE;
+ }
+}
+
+
+/*
+=================
+GraphicsOptions_Cache
+=================
+*/
+void GraphicsOptions_Cache( void ) {
+ trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_FRAMEL );
+ trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_FRAMER );
+ trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_BACK0 );
+ trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_BACK1 );
+ trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_ACCEPT0 );
+ trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_ACCEPT1 );
+}
+
+
+/*
+=================
+UI_GraphicsOptionsMenu
+=================
+*/
+void UI_GraphicsOptionsMenu( void ) {
+ GraphicsOptions_MenuInit();
+ UI_PushMenu( &s_graphicsoptions.menu );
+ Menu_SetCursorToItem( &s_graphicsoptions.menu, &s_graphicsoptions.graphics );
+}
diff --git a/game/code/q3_ui/ui_votemenu.c b/code/q3_ui/ui_votemenu.c
similarity index 100%
rename from game/code/q3_ui/ui_votemenu.c
rename to code/q3_ui/ui_votemenu.c
diff --git a/game/code/q3_ui/ui_votemenu_custom.c b/code/q3_ui/ui_votemenu_custom.c
similarity index 100%
rename from game/code/q3_ui/ui_votemenu_custom.c
rename to code/q3_ui/ui_votemenu_custom.c
diff --git a/game/code/q3_ui/ui_votemenu_fraglimit.c b/code/q3_ui/ui_votemenu_fraglimit.c
similarity index 100%
rename from game/code/q3_ui/ui_votemenu_fraglimit.c
rename to code/q3_ui/ui_votemenu_fraglimit.c
diff --git a/game/code/q3_ui/ui_votemenu_gametype.c b/code/q3_ui/ui_votemenu_gametype.c
similarity index 100%
rename from game/code/q3_ui/ui_votemenu_gametype.c
rename to code/q3_ui/ui_votemenu_gametype.c
diff --git a/game/code/q3_ui/ui_votemenu_kick.c b/code/q3_ui/ui_votemenu_kick.c
similarity index 100%
rename from game/code/q3_ui/ui_votemenu_kick.c
rename to code/q3_ui/ui_votemenu_kick.c
diff --git a/game/code/q3_ui/ui_votemenu_map.c b/code/q3_ui/ui_votemenu_map.c
similarity index 100%
rename from game/code/q3_ui/ui_votemenu_map.c
rename to code/q3_ui/ui_votemenu_map.c
diff --git a/game/code/q3_ui/ui_votemenu_timelimit.c b/code/q3_ui/ui_votemenu_timelimit.c
similarity index 100%
rename from game/code/q3_ui/ui_votemenu_timelimit.c
rename to code/q3_ui/ui_votemenu_timelimit.c
diff --git a/game/code/qcommon/q_math.c b/code/qcommon/q_math.c
similarity index 100%
rename from game/code/qcommon/q_math.c
rename to code/qcommon/q_math.c
diff --git a/game/code/qcommon/q_platform.h b/code/qcommon/q_platform.h
similarity index 100%
rename from game/code/qcommon/q_platform.h
rename to code/qcommon/q_platform.h
diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c
new file mode 100644
index 0000000..d1ead36
--- /dev/null
+++ b/code/qcommon/q_shared.c
@@ -0,0 +1,1398 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// q_shared.c -- stateless support routines that are included in each code dll
+#include "q_shared.h"
+
+float Com_Clamp( float min, float max, float value ) {
+ if ( value < min ) {
+ return min;
+ }
+ if ( value > max ) {
+ return max;
+ }
+ return value;
+}
+
+
+/*
+============
+COM_SkipPath
+============
+*/
+char *COM_SkipPath (char *pathname)
+{
+ char *last;
+
+ last = pathname;
+ while (*pathname)
+ {
+ if (*pathname=='/')
+ last = pathname+1;
+ pathname++;
+ }
+ return last;
+}
+
+/*
+============
+COM_GetExtension
+============
+*/
+const char *COM_GetExtension( const char *name ) {
+ int length, i;
+
+ length = strlen(name)-1;
+ i = length;
+
+ while (name[i] != '.')
+ {
+ i--;
+ if (name[i] == '/' || i == 0)
+ return ""; // no extension
+ }
+
+ return &name[i+1];
+}
+
+
+/*
+============
+COM_StripExtension
+============
+*/
+void COM_StripExtension( const char *in, char *out, int destsize ) {
+ int length;
+
+ Q_strncpyz(out, in, destsize);
+
+ length = strlen(out)-1;
+ while (length > 0 && out[length] != '.')
+ {
+ length--;
+ if (out[length] == '/')
+ return; // no extension
+ }
+ if (length)
+ out[length] = 0;
+}
+
+
+/*
+==================
+COM_DefaultExtension
+==================
+*/
+void COM_DefaultExtension (char *path, int maxSize, const char *extension ) {
+ char oldPath[MAX_QPATH];
+ char *src;
+
+//
+// if path doesn't have a .EXT, append extension
+// (extension should include the .)
+//
+ src = path + strlen(path) - 1;
+
+ while (*src != '/' && src != path) {
+ if ( *src == '.' ) {
+ return; // it has an extension
+ }
+ src--;
+ }
+
+ Q_strncpyz( oldPath, path, sizeof( oldPath ) );
+ Com_sprintf( path, maxSize, "%s%s", oldPath, extension );
+}
+
+/*
+============================================================================
+
+ BYTE ORDER FUNCTIONS
+
+============================================================================
+*/
+/*
+// can't just use function pointers, or dll linkage can
+// mess up when qcommon is included in multiple places
+static short (*_BigShort) (short l);
+static short (*_LittleShort) (short l);
+static int (*_BigLong) (int l);
+static int (*_LittleLong) (int l);
+static qint64 (*_BigLong64) (qint64 l);
+static qint64 (*_LittleLong64) (qint64 l);
+static float (*_BigFloat) (const float *l);
+static float (*_LittleFloat) (const float *l);
+
+short BigShort(short l){return _BigShort(l);}
+short LittleShort(short l) {return _LittleShort(l);}
+int BigLong (int l) {return _BigLong(l);}
+int LittleLong (int l) {return _LittleLong(l);}
+qint64 BigLong64 (qint64 l) {return _BigLong64(l);}
+qint64 LittleLong64 (qint64 l) {return _LittleLong64(l);}
+float BigFloat (const float *l) {return _BigFloat(l);}
+float LittleFloat (const float *l) {return _LittleFloat(l);}
+*/
+
+short ShortSwap (short l)
+{
+ byte b1,b2;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+
+ return (b1<<8) + b2;
+}
+
+short ShortNoSwap (short l)
+{
+ return l;
+}
+
+int LongSwap (int l)
+{
+ byte b1,b2,b3,b4;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+ b3 = (l>>16)&255;
+ b4 = (l>>24)&255;
+
+ return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
+}
+
+int LongNoSwap (int l)
+{
+ return l;
+}
+
+qint64 Long64Swap (qint64 ll)
+{
+ qint64 result;
+
+ result.b0 = ll.b7;
+ result.b1 = ll.b6;
+ result.b2 = ll.b5;
+ result.b3 = ll.b4;
+ result.b4 = ll.b3;
+ result.b5 = ll.b2;
+ result.b6 = ll.b1;
+ result.b7 = ll.b0;
+
+ return result;
+}
+
+qint64 Long64NoSwap (qint64 ll)
+{
+ return ll;
+}
+
+typedef union {
+ float f;
+ unsigned int i;
+} _FloatByteUnion;
+
+float FloatSwap (const float *f) {
+ _FloatByteUnion out;
+
+ out.f = *f;
+ out.i = LongSwap(out.i);
+
+ return out.f;
+}
+
+float FloatNoSwap (const float *f)
+{
+ return *f;
+}
+
+/*
+================
+Swap_Init
+================
+*/
+/*
+void Swap_Init (void)
+{
+ byte swaptest[2] = {1,0};
+
+// set the byte swapping variables in a portable manner
+ if ( *(short *)swaptest == 1)
+ {
+ _BigShort = ShortSwap;
+ _LittleShort = ShortNoSwap;
+ _BigLong = LongSwap;
+ _LittleLong = LongNoSwap;
+ _BigLong64 = Long64Swap;
+ _LittleLong64 = Long64NoSwap;
+ _BigFloat = FloatSwap;
+ _LittleFloat = FloatNoSwap;
+ }
+ else
+ {
+ _BigShort = ShortNoSwap;
+ _LittleShort = ShortSwap;
+ _BigLong = LongNoSwap;
+ _LittleLong = LongSwap;
+ _BigLong64 = Long64NoSwap;
+ _LittleLong64 = Long64Swap;
+ _BigFloat = FloatNoSwap;
+ _LittleFloat = FloatSwap;
+ }
+
+}
+*/
+
+/*
+============================================================================
+
+PARSING
+
+============================================================================
+*/
+
+static char com_token[MAX_TOKEN_CHARS];
+static char com_parsename[MAX_TOKEN_CHARS];
+static int com_lines;
+
+void COM_BeginParseSession( const char *name )
+{
+ com_lines = 0;
+ Com_sprintf(com_parsename, sizeof(com_parsename), "%s", name);
+}
+
+int COM_GetCurrentParseLine( void )
+{
+ return com_lines;
+}
+
+char *COM_Parse( char **data_p )
+{
+ return COM_ParseExt( data_p, qtrue );
+}
+
+void COM_ParseError( char *format, ... )
+{
+ va_list argptr;
+ static char string[4096];
+
+ va_start (argptr, format);
+ Q_vsnprintf (string, sizeof(string), format, argptr);
+ va_end (argptr);
+
+ Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, com_lines, string);
+}
+
+void COM_ParseWarning( char *format, ... )
+{
+ va_list argptr;
+ static char string[4096];
+
+ va_start (argptr, format);
+ Q_vsnprintf (string, sizeof(string), format, argptr);
+ va_end (argptr);
+
+ Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, com_lines, string);
+}
+
+/*
+==============
+COM_Parse
+
+Parse a token out of a string
+Will never return NULL, just empty strings
+
+If "allowLineBreaks" is qtrue then an empty
+string will be returned if the next token is
+a newline.
+==============
+*/
+static char *SkipWhitespace( char *data, qboolean *hasNewLines ) {
+ int c;
+
+ while( (c = *data) <= ' ') {
+ if( !c ) {
+ return NULL;
+ }
+ if( c == '\n' ) {
+ com_lines++;
+ *hasNewLines = qtrue;
+ }
+ data++;
+ }
+
+ return data;
+}
+
+int COM_Compress( char *data_p ) {
+ char *in, *out;
+ int c;
+ qboolean newline = qfalse, whitespace = qfalse;
+
+ in = out = data_p;
+ if (in) {
+ while ((c = *in) != 0) {
+ // skip double slash comments
+ if ( c == '/' && in[1] == '/' ) {
+ while (*in && *in != '\n') {
+ in++;
+ }
+ // skip /* */ comments
+ } else if ( c == '/' && in[1] == '*' ) {
+ while ( *in && ( *in != '*' || in[1] != '/' ) )
+ in++;
+ if ( *in )
+ in += 2;
+ // record when we hit a newline
+ } else if ( c == '\n' || c == '\r' ) {
+ newline = qtrue;
+ in++;
+ // record when we hit whitespace
+ } else if ( c == ' ' || c == '\t') {
+ whitespace = qtrue;
+ in++;
+ // an actual token
+ } else {
+ // if we have a pending newline, emit it (and it counts as whitespace)
+ if (newline) {
+ *out++ = '\n';
+ newline = qfalse;
+ whitespace = qfalse;
+ } if (whitespace) {
+ *out++ = ' ';
+ whitespace = qfalse;
+ }
+
+ // copy quoted strings unmolested
+ if (c == '"') {
+ *out++ = c;
+ in++;
+ while (1) {
+ c = *in;
+ if (c && c != '"') {
+ *out++ = c;
+ in++;
+ } else {
+ break;
+ }
+ }
+ if (c == '"') {
+ *out++ = c;
+ in++;
+ }
+ } else {
+ *out = c;
+ out++;
+ in++;
+ }
+ }
+ }
+ *out = 0;
+ return out - data_p;
+ }
+ return 0;
+}
+
+char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
+{
+ int c = 0, len;
+ qboolean hasNewLines = qfalse;
+ char *data;
+
+ data = *data_p;
+ len = 0;
+ com_token[0] = 0;
+
+ // make sure incoming data is valid
+ if ( !data )
+ {
+ *data_p = NULL;
+ return com_token;
+ }
+
+ while ( 1 )
+ {
+ // skip whitespace
+ data = SkipWhitespace( data, &hasNewLines );
+ if ( !data )
+ {
+ *data_p = NULL;
+ return com_token;
+ }
+ if ( hasNewLines && !allowLineBreaks )
+ {
+ *data_p = data;
+ return com_token;
+ }
+
+ c = *data;
+
+ // skip double slash comments
+ if ( c == '/' && data[1] == '/' )
+ {
+ data += 2;
+ while (*data && *data != '\n') {
+ data++;
+ }
+ }
+ // skip /* */ comments
+ else if ( c=='/' && data[1] == '*' )
+ {
+ data += 2;
+ while ( *data && ( *data != '*' || data[1] != '/' ) )
+ {
+ data++;
+ }
+ if ( *data )
+ {
+ data += 2;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // handle quoted strings
+ if (c == '\"')
+ {
+ data++;
+ while (1)
+ {
+ c = *data++;
+ if (c=='\"' || !c)
+ {
+ com_token[len] = 0;
+ *data_p = ( char * ) data;
+ return com_token;
+ }
+ if (len < MAX_TOKEN_CHARS - 1)
+ {
+ com_token[len] = c;
+ len++;
+ }
+ }
+ }
+
+ // parse a regular word
+ do
+ {
+ if (len < MAX_TOKEN_CHARS - 1)
+ {
+ com_token[len] = c;
+ len++;
+ }
+ data++;
+ c = *data;
+ if ( c == '\n' )
+ com_lines++;
+ } while (c>32);
+
+ com_token[len] = 0;
+
+ *data_p = ( char * ) data;
+ return com_token;
+}
+
+
+#if 0
+// no longer used
+/*
+===============
+COM_ParseInfos
+===============
+*/
+int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ) {
+ char *token;
+ int count;
+ char key[MAX_TOKEN_CHARS];
+
+ count = 0;
+
+ while ( 1 ) {
+ token = COM_Parse( &buf );
+ if ( !token[0] ) {
+ break;
+ }
+ if ( strcmp( token, "{" ) ) {
+ Com_Printf( "Missing { in info file\n" );
+ break;
+ }
+
+ if ( count == max ) {
+ Com_Printf( "Max infos exceeded\n" );
+ break;
+ }
+
+ infos[count][0] = 0;
+ while ( 1 ) {
+ token = COM_ParseExt( &buf, qtrue );
+ if ( !token[0] ) {
+ Com_Printf( "Unexpected end of info file\n" );
+ break;
+ }
+ if ( !strcmp( token, "}" ) ) {
+ break;
+ }
+ Q_strncpyz( key, token, sizeof( key ) );
+
+ token = COM_ParseExt( &buf, qfalse );
+ if ( !token[0] ) {
+ strcpy( token, "<NULL>" );
+ }
+ Info_SetValueForKey( infos[count], key, token );
+ }
+ count++;
+ }
+
+ return count;
+}
+#endif
+
+
+/*
+==================
+COM_MatchToken
+==================
+*/
+void COM_MatchToken( char **buf_p, char *match ) {
+ char *token;
+
+ token = COM_Parse( buf_p );
+ if ( strcmp( token, match ) ) {
+ Com_Error( ERR_DROP, "MatchToken: %s != %s", token, match );
+ }
+}
+
+
+/*
+=================
+SkipBracedSection
+
+The next token should be an open brace.
+Skips until a matching close brace is found.
+Internal brace depths are properly skipped.
+=================
+*/
+void SkipBracedSection (char **program) {
+ char *token;
+ int depth;
+
+ depth = 0;
+ do {
+ token = COM_ParseExt( program, qtrue );
+ if( token[1] == 0 ) {
+ if( token[0] == '{' ) {
+ depth++;
+ }
+ else if( token[0] == '}' ) {
+ depth--;
+ }
+ }
+ } while( depth && *program );
+}
+
+/*
+=================
+SkipRestOfLine
+=================
+*/
+void SkipRestOfLine ( char **data ) {
+ char *p;
+ int c;
+
+ p = *data;
+ while ( (c = *p++) != 0 ) {
+ if ( c == '\n' ) {
+ com_lines++;
+ break;
+ }
+ }
+
+ *data = p;
+}
+
+
+void Parse1DMatrix (char **buf_p, int x, float *m) {
+ char *token;
+ int i;
+
+ COM_MatchToken( buf_p, "(" );
+
+ for (i = 0 ; i < x ; i++) {
+ token = COM_Parse(buf_p);
+ m[i] = atof(token);
+ }
+
+ COM_MatchToken( buf_p, ")" );
+}
+
+void Parse2DMatrix (char **buf_p, int y, int x, float *m) {
+ int i;
+
+ COM_MatchToken( buf_p, "(" );
+
+ for (i = 0 ; i < y ; i++) {
+ Parse1DMatrix (buf_p, x, m + i * x);
+ }
+
+ COM_MatchToken( buf_p, ")" );
+}
+
+void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m) {
+ int i;
+
+ COM_MatchToken( buf_p, "(" );
+
+ for (i = 0 ; i < z ; i++) {
+ Parse2DMatrix (buf_p, y, x, m + i * x*y);
+ }
+
+ COM_MatchToken( buf_p, ")" );
+}
+
+
+/*
+============================================================================
+
+ LIBRARY REPLACEMENT FUNCTIONS
+
+============================================================================
+*/
+
+int Q_isprint( int c )
+{
+ if ( c >= 0x20 && c <= 0x7E )
+ return ( 1 );
+ return ( 0 );
+}
+
+int Q_islower( int c )
+{
+ if (c >= 'a' && c <= 'z')
+ return ( 1 );
+ return ( 0 );
+}
+
+int Q_isupper( int c )
+{
+ if (c >= 'A' && c <= 'Z')
+ return ( 1 );
+ return ( 0 );
+}
+
+int Q_isalpha( int c )
+{
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
+ return ( 1 );
+ return ( 0 );
+}
+
+char* Q_strrchr( const char* string, int c )
+{
+ char cc = c;
+ char *s;
+ char *sp=(char *)0;
+
+ s = (char*)string;
+
+ while (*s)
+ {
+ if (*s == cc)
+ sp = s;
+ s++;
+ }
+ if (cc == 0)
+ sp = s;
+
+ return sp;
+}
+
+/*
+=============
+Q_strncpyz
+
+Safe strncpy that ensures a trailing zero
+=============
+*/
+void Q_strncpyz( char *dest, const char *src, int destsize ) {
+ if ( !dest ) {
+ Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" );
+ }
+ if ( !src ) {
+ Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
+ }
+ if ( destsize < 1 ) {
+ Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
+ }
+
+ strncpy( dest, src, destsize-1 );
+ dest[destsize-1] = 0;
+}
+
+int Q_stricmpn (const char *s1, const char *s2, int n) {
+ int c1, c2;
+
+ if ( s1 == NULL ) {
+ if ( s2 == NULL )
+ return 0;
+ else
+ return -1;
+ }
+ else if ( s2==NULL )
+ return 1;
+
+
+
+ do {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if (!n--) {
+ return 0; // strings are equal until end point
+ }
+
+ if (c1 != c2) {
+ if (c1 >= 'a' && c1 <= 'z') {
+ c1 -= ('a' - 'A');
+ }
+ if (c2 >= 'a' && c2 <= 'z') {
+ c2 -= ('a' - 'A');
+ }
+ if (c1 != c2) {
+ return c1 < c2 ? -1 : 1;
+ }
+ }
+ } while (c1);
+
+ return 0; // strings are equal
+}
+
+int Q_strncmp (const char *s1, const char *s2, int n) {
+ int c1, c2;
+
+ do {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if (!n--) {
+ return 0; // strings are equal until end point
+ }
+
+ if (c1 != c2) {
+ return c1 < c2 ? -1 : 1;
+ }
+ } while (c1);
+
+ return 0; // strings are equal
+}
+
+int Q_stricmp (const char *s1, const char *s2) {
+ return (s1 && s2) ? Q_stricmpn (s1, s2, 99999) : -1;
+}
+
+
+char *Q_strlwr( char *s1 ) {
+ char *s;
+
+ s = s1;
+ while ( *s ) {
+ *s = tolower(*s);
+ s++;
+ }
+ return s1;
+}
+
+char *Q_strupr( char *s1 ) {
+ char *s;
+
+ s = s1;
+ while ( *s ) {
+ *s = toupper(*s);
+ s++;
+ }
+ return s1;
+}
+
+
+// never goes past bounds or leaves without a terminating 0
+void Q_strcat( char *dest, int size, const char *src ) {
+ int l1;
+
+ l1 = strlen( dest );
+ if ( l1 >= size ) {
+ Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
+ }
+ Q_strncpyz( dest + l1, src, size - l1 );
+}
+
+/*
+* Find the first occurrence of find in s.
+*/
+const char *Q_stristr( const char *s, const char *find)
+{
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != 0)
+ {
+ if (c >= 'a' && c <= 'z')
+ {
+ c -= ('a' - 'A');
+ }
+ len = strlen(find);
+ do
+ {
+ do
+ {
+ if ((sc = *s++) == 0)
+ return NULL;
+ if (sc >= 'a' && sc <= 'z')
+ {
+ sc -= ('a' - 'A');
+ }
+ } while (sc != c);
+ } while (Q_stricmpn(s, find, len) != 0);
+ s--;
+ }
+ return s;
+}
+
+
+int Q_PrintStrlen( const char *string ) {
+ int len;
+ const char *p;
+
+ if( !string ) {
+ return 0;
+ }
+
+ len = 0;
+ p = string;
+ while( *p ) {
+ if( Q_IsColorString( p ) ) {
+ p += 2;
+ continue;
+ }
+ p++;
+ len++;
+ }
+
+ return len;
+}
+
+
+char *Q_CleanStr( char *string ) {
+ char* d;
+ char* s;
+ int c;
+ qboolean hadColor = qfalse;
+
+ s = string;
+ d = string;
+ while ((c = *s) != 0 ) {
+ if ( Q_IsColorString( s ) ) {
+ s++;
+ hadColor = qtrue;
+ }
+ else if ( c >= 0x20 && c <= 0x7E ) {
+ *d++ = c;
+ }
+ s++;
+ }
+ *d = '\0';
+ if(hadColor)
+ return Q_CleanStr( string );
+ else
+ return string;
+}
+
+int Q_CountChar(const char *string, char tocount)
+{
+ int count;
+
+ for(count = 0; *string; string++)
+ {
+ if(*string == tocount)
+ count++;
+ }
+
+ return count;
+}
+
+void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {
+ int len;
+ va_list argptr;
+ char bigbuffer[32000]; // big, but small enough to fit in PPC stack
+
+ va_start (argptr,fmt);
+ len = Q_vsnprintf (bigbuffer, sizeof(bigbuffer), fmt,argptr);
+ va_end (argptr);
+ if ( len >= sizeof( bigbuffer ) ) {
+ Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
+ }
+ if (len >= size) {
+ Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
+#ifdef _DEBUG
+ __asm {
+ int 3;
+ }
+#endif
+ }
+ Q_strncpyz (dest, bigbuffer, size );
+}
+
+
+/*
+============
+va
+
+does a varargs printf into a temp buffer, so I don't need to have
+varargs versions of all text functions.
+============
+*/
+char * QDECL va( char *format, ... ) {
+ va_list argptr;
+ static char string[2][32000]; // in case va is called by nested functions
+ static int index = 0;
+ char *buf;
+
+ buf = string[index & 1];
+ index++;
+
+ va_start (argptr, format);
+ Q_vsnprintf (buf, sizeof(*string), format, argptr);
+ va_end (argptr);
+
+ return buf;
+}
+
+/*
+============
+Com_TruncateLongString
+
+Assumes buffer is atleast TRUNCATE_LENGTH big
+============
+*/
+void Com_TruncateLongString( char *buffer, const char *s )
+{
+ int length = strlen( s );
+
+ if( length <= TRUNCATE_LENGTH )
+ Q_strncpyz( buffer, s, TRUNCATE_LENGTH );
+ else
+ {
+ Q_strncpyz( buffer, s, ( TRUNCATE_LENGTH / 2 ) - 3 );
+ Q_strcat( buffer, TRUNCATE_LENGTH, " ... " );
+ Q_strcat( buffer, TRUNCATE_LENGTH, s + length - ( TRUNCATE_LENGTH / 2 ) + 3 );
+ }
+}
+
+/*
+=====================================================================
+
+ INFO STRINGS
+
+=====================================================================
+*/
+
+/*
+===============
+Info_ValueForKey
+
+Searches the string for the given
+key and returns the associated value, or an empty string.
+FIXME: overflow check?
+===============
+*/
+char *Info_ValueForKey( const char *s, const char *key ) {
+ char pkey[BIG_INFO_KEY];
+ static char value[2][BIG_INFO_VALUE]; // use two buffers so compares
+ // work without stomping on each other
+ static int valueindex = 0;
+ char *o;
+
+ if ( !s || !key ) {
+ return "";
+ }
+
+ if ( strlen( s ) >= BIG_INFO_STRING ) {
+ Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
+ }
+
+ valueindex ^= 1;
+ if (*s == '\\')
+ s++;
+ while (1)
+ {
+ o = pkey;
+ while (*s != '\\')
+ {
+ if (!*s)
+ return "";
+ *o++ = *s++;
+ }
+ *o = 0;
+ s++;
+
+ o = value[valueindex];
+
+ while (*s != '\\' && *s)
+ {
+ *o++ = *s++;
+ }
+ *o = 0;
+
+ if (!Q_stricmp (key, pkey) )
+ return value[valueindex];
+
+ if (!*s)
+ break;
+ s++;
+ }
+
+ return "";
+}
+
+
+/*
+===================
+Info_NextPair
+
+Used to itterate through all the key/value pairs in an info string
+===================
+*/
+void Info_NextPair( const char **head, char *key, char *value ) {
+ char *o;
+ const char *s;
+
+ s = *head;
+
+ if ( *s == '\\' ) {
+ s++;
+ }
+ key[0] = 0;
+ value[0] = 0;
+
+ o = key;
+ while ( *s != '\\' ) {
+ if ( !*s ) {
+ *o = 0;
+ *head = s;
+ return;
+ }
+ *o++ = *s++;
+ }
+ *o = 0;
+ s++;
+
+ o = value;
+ while ( *s != '\\' && *s ) {
+ *o++ = *s++;
+ }
+ *o = 0;
+
+ *head = s;
+}
+
+
+/*
+===================
+Info_RemoveKey
+===================
+*/
+void Info_RemoveKey( char *s, const char *key ) {
+ char *start;
+ char pkey[MAX_INFO_KEY];
+ char value[MAX_INFO_VALUE];
+ char *o;
+
+ if ( strlen( s ) >= MAX_INFO_STRING ) {
+ Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
+ }
+
+ if (strchr (key, '\\')) {
+ return;
+ }
+
+ while (1)
+ {
+ start = s;
+ if (*s == '\\')
+ s++;
+ o = pkey;
+ while (*s != '\\')
+ {
+ if (!*s)
+ return;
+ *o++ = *s++;
+ }
+ *o = 0;
+ s++;
+
+ o = value;
+ while (*s != '\\' && *s)
+ {
+ if (!*s)
+ return;
+ *o++ = *s++;
+ }
+ *o = 0;
+
+ if (!strcmp (key, pkey) )
+ {
+ memmove(start, s, strlen(s) + 1); // remove this part
+
+ return;
+ }
+
+ if (!*s)
+ return;
+ }
+
+}
+
+/*
+===================
+Info_RemoveKey_Big
+===================
+*/
+void Info_RemoveKey_Big( char *s, const char *key ) {
+ char *start;
+ char pkey[BIG_INFO_KEY];
+ char value[BIG_INFO_VALUE];
+ char *o;
+
+ if ( strlen( s ) >= BIG_INFO_STRING ) {
+ Com_Error( ERR_DROP, "Info_RemoveKey_Big: oversize infostring" );
+ }
+
+ if (strchr (key, '\\')) {
+ return;
+ }
+
+ while (1)
+ {
+ start = s;
+ if (*s == '\\')
+ s++;
+ o = pkey;
+ while (*s != '\\')
+ {
+ if (!*s)
+ return;
+ *o++ = *s++;
+ }
+ *o = 0;
+ s++;
+
+ o = value;
+ while (*s != '\\' && *s)
+ {
+ if (!*s)
+ return;
+ *o++ = *s++;
+ }
+ *o = 0;
+
+ if (!strcmp (key, pkey) )
+ {
+ strcpy (start, s); // remove this part
+ return;
+ }
+
+ if (!*s)
+ return;
+ }
+
+}
+
+
+
+
+/*
+==================
+Info_Validate
+
+Some characters are illegal in info strings because they
+can mess up the server's parsing
+==================
+*/
+qboolean Info_Validate( const char *s ) {
+ if ( strchr( s, '\"' ) ) {
+ return qfalse;
+ }
+ if ( strchr( s, ';' ) ) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+/*
+==================
+Info_SetValueForKey
+
+Changes or adds a key/value pair
+==================
+*/
+void Info_SetValueForKey( char *s, const char *key, const char *value ) {
+ char newi[MAX_INFO_STRING];
+ const char* blacklist = "\\;\"";
+
+ if ( strlen( s ) >= MAX_INFO_STRING ) {
+ Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
+ }
+
+ for(; *blacklist; ++blacklist)
+ {
+ if (strchr (key, *blacklist) || strchr (value, *blacklist))
+ {
+ Com_Printf (S_COLOR_YELLOW "Can't use keys or values with a '%c': %s = %s\n", *blacklist, key, value);
+ return;
+ }
+ }
+
+ Info_RemoveKey (s, key);
+ if (!value || !strlen(value))
+ return;
+
+ Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
+
+ if (strlen(newi) + strlen(s) >= MAX_INFO_STRING)
+ {
+ Com_Printf ("Info string length exceeded\n");
+ return;
+ }
+
+ strcat (newi, s);
+ strcpy (s, newi);
+}
+
+/*
+==================
+Info_SetValueForKey_Big
+
+Changes or adds a key/value pair
+==================
+*/
+void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
+ char newi[BIG_INFO_STRING];
+ const char* blacklist = "\\;\"";
+
+ if ( strlen( s ) >= BIG_INFO_STRING ) {
+ Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
+ }
+
+ for(; *blacklist; ++blacklist)
+ {
+ if (strchr (key, *blacklist) || strchr (value, *blacklist))
+ {
+ Com_Printf (S_COLOR_YELLOW "Can't use keys or values with a '%c': %s = %s\n", *blacklist, key, value);
+ return;
+ }
+ }
+
+ Info_RemoveKey_Big (s, key);
+ if (!value || !strlen(value))
+ return;
+
+ Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
+
+ if (strlen(newi) + strlen(s) >= BIG_INFO_STRING)
+ {
+ Com_Printf ("BIG Info string length exceeded\n");
+ return;
+ }
+
+ strcat (s, newi);
+}
+
+
+
+
+//====================================================================
+
+/*
+==================
+Com_CharIsOneOfCharset
+==================
+*/
+static qboolean Com_CharIsOneOfCharset( char c, char *set )
+{
+ int i;
+
+ for( i = 0; i < strlen( set ); i++ )
+ {
+ if( set[ i ] == c )
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+/*
+==================
+Com_SkipCharset
+==================
+*/
+char *Com_SkipCharset( char *s, char *sep )
+{
+ char *p = s;
+
+ while( p )
+ {
+ if( Com_CharIsOneOfCharset( *p, sep ) )
+ p++;
+ else
+ break;
+ }
+
+ return p;
+}
+
+/*
+==================
+Com_SkipTokens
+==================
+*/
+char *Com_SkipTokens( char *s, int numTokens, char *sep )
+{
+ int sepCount = 0;
+ char *p = s;
+
+ while( sepCount < numTokens )
+ {
+ if( Com_CharIsOneOfCharset( *p++, sep ) )
+ {
+ sepCount++;
+ while( Com_CharIsOneOfCharset( *p, sep ) )
+ p++;
+ }
+ else if( *p == '\0' )
+ break;
+ }
+
+ if( sepCount == numTokens )
+ return p;
+ else
+ return s;
+}
diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h
new file mode 100644
index 0000000..f8b1365
--- /dev/null
+++ b/code/qcommon/q_shared.h
@@ -0,0 +1,1311 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#ifndef __Q_SHARED_H
+#define __Q_SHARED_H
+
+// q_shared.h -- included first by ALL program modules.
+// A user mod should never modify this file
+
+//#ifdef STANDALONE
+ #define PRODUCT_NAME "ioq3+oa"
+ #define BASEGAME "baseoa"
+ #define CLIENT_WINDOW_TITLE "OpenArena"
+ #define CLIENT_WINDOW_MIN_TITLE "OA"
+/*#else
+ #define PRODUCT_NAME "ioq3"
+ #define BASEGAME "baseq3"
+ #define CLIENT_WINDOW_TITLE "ioquake3"
+ #define CLIENT_WINDOW_MIN_TITLE "ioq3"
+#endif*/
+
+#ifdef _MSC_VER
+ #define PRODUCT_VERSION "1.35"
+#endif
+
+#define Q3_VERSION PRODUCT_NAME " " PRODUCT_VERSION
+
+#define MAX_TEAMNAME 32
+
+#ifdef _MSC_VER
+
+#pragma warning(disable : 4018) // signed/unsigned mismatch
+#pragma warning(disable : 4032)
+#pragma warning(disable : 4051)
+#pragma warning(disable : 4057) // slightly different base types
+#pragma warning(disable : 4100) // unreferenced formal parameter
+#pragma warning(disable : 4115)
+#pragma warning(disable : 4125) // decimal digit terminates octal escape sequence
+#pragma warning(disable : 4127) // conditional expression is constant
+#pragma warning(disable : 4136)
+#pragma warning(disable : 4152) // nonstandard extension, function/data pointer conversion in expression
+//#pragma warning(disable : 4201)
+//#pragma warning(disable : 4214)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4142) // benign redefinition
+//#pragma warning(disable : 4305) // truncation from const double to float
+//#pragma warning(disable : 4310) // cast truncates constant value
+//#pragma warning(disable: 4505) // unreferenced local function has been removed
+#pragma warning(disable : 4514)
+#pragma warning(disable : 4702) // unreachable code
+#pragma warning(disable : 4711) // selected for automatic inline expansion
+#pragma warning(disable : 4220) // varargs matches remaining parameters
+//#pragma intrinsic( memset, memcpy )
+#endif
+
+//Ignore __attribute__ on non-gcc platforms
+#ifndef __GNUC__
+#ifndef __attribute__
+#define __attribute__(x)
+#endif
+#endif
+
+#if (defined _MSC_VER)
+#define Q_EXPORT __declspec(dllexport)
+#elif (defined __SUNPRO_C)
+#define Q_EXPORT __global
+#elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun))
+#define Q_EXPORT __attribute__((visibility("default")))
+#else
+#define Q_EXPORT
+#endif
+
+
+/**********************************************************************
+ VM Considerations
+
+ The VM can not use the standard system headers because we aren't really
+ using the compiler they were meant for. We use bg_lib.h which contains
+ prototypes for the functions we define for our own use in bg_lib.c.
+
+ When writing mods, please add needed headers HERE, do not start including
+ stuff like <stdio.h> in the various .c files that make up each of the VMs
+ since you will be including system headers files can will have issues.
+
+ Remember, if you use a C library function that is not defined in bg_lib.c,
+ you will have to add your own version for support in the VM.
+
+ **********************************************************************/
+
+#ifdef Q3_VM
+
+#include "../game/bg_lib.h"
+
+typedef int intptr_t;
+
+#else
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include <limits.h>
+
+// vsnprintf is ISO/IEC 9899:1999
+// abstracting this to make it portable
+#ifdef _WIN32
+ #define Q_vsnprintf _vsnprintf
+ #define Q_snprintf _snprintf
+#else
+ #define Q_vsnprintf vsnprintf
+ #define Q_snprintf snprintf
+#endif
+
+#ifdef _MSC_VER
+ #include <io.h>
+
+ typedef __int64 int64_t;
+ typedef __int32 int32_t;
+ typedef __int16 int16_t;
+ typedef __int8 int8_t;
+ typedef unsigned __int64 uint64_t;
+ typedef unsigned __int32 uint32_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int8 uint8_t;
+#else
+ #include <stdint.h>
+#endif
+
+#endif
+
+
+#include "q_platform.h"
+
+//=============================================================
+
+typedef unsigned char byte;
+
+typedef enum {qfalse, qtrue} qboolean;
+
+typedef union {
+ float f;
+ int i;
+ unsigned int ui;
+} floatint_t;
+
+typedef int qhandle_t;
+typedef int sfxHandle_t;
+typedef int fileHandle_t;
+typedef int clipHandle_t;
+
+#define PAD(x,y) (((x)+(y)-1) & ~((y)-1))
+
+#ifdef __GNUC__
+#define ALIGN(x) __attribute__((aligned(x)))
+#else
+#define ALIGN(x)
+#endif
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#define MAX_QINT 0x7fffffff
+#define MIN_QINT (-MAX_QINT-1)
+
+
+// angle indexes
+#define PITCH 0 // up / down
+#define YAW 1 // left / right
+#define ROLL 2 // fall over
+
+// the game guarantees that no string from the network will ever
+// exceed MAX_STRING_CHARS
+#define MAX_STRING_CHARS 1024 // max length of a string passed to Cmd_TokenizeString
+#define MAX_STRING_TOKENS 1024 // max tokens resulting from Cmd_TokenizeString
+#define MAX_TOKEN_CHARS 1024 // max length of an individual token
+
+#define MAX_INFO_STRING 1024
+#define MAX_INFO_KEY 1024
+#define MAX_INFO_VALUE 1024
+
+#define BIG_INFO_STRING 8192 // used for system info key only
+#define BIG_INFO_KEY 8192
+#define BIG_INFO_VALUE 8192
+
+
+#define MAX_QPATH 64 // max length of a quake game pathname
+#ifdef PATH_MAX
+#define MAX_OSPATH PATH_MAX
+#else
+#define MAX_OSPATH 256 // max length of a filesystem pathname
+#endif
+
+#define MAX_NAME_LENGTH 32 // max length of a client name
+
+#define MAX_SAY_TEXT 150
+
+// paramters for command buffer stuffing
+typedef enum {
+ EXEC_NOW, // don't return until completed, a VM should NEVER use this,
+ // because some commands might cause the VM to be unloaded...
+ EXEC_INSERT, // insert at current position, but don't run yet
+ EXEC_APPEND // add to end of the command buffer (normal case)
+} cbufExec_t;
+
+
+//
+// these aren't needed by any of the VMs. put in another header?
+//
+#define MAX_MAP_AREA_BYTES 32 // bit vector of area visibility
+
+
+// print levels from renderer (FIXME: set up for game / cgame?)
+typedef enum {
+ PRINT_ALL,
+ PRINT_DEVELOPER, // only print when "developer 1"
+ PRINT_WARNING,
+ PRINT_ERROR
+} printParm_t;
+
+
+#ifdef ERR_FATAL
+#undef ERR_FATAL // this is be defined in malloc.h
+#endif
+
+// parameters to the main Error routine
+typedef enum {
+ ERR_FATAL, // exit the entire game with a popup window
+ ERR_DROP, // print to console and disconnect from game
+ ERR_SERVERDISCONNECT, // don't kill server
+ ERR_DISCONNECT, // client disconnected from the server
+ ERR_NEED_CD // pop up the need-cd dialog
+} errorParm_t;
+
+
+// font rendering values used by ui and cgame
+
+#define PROP_GAP_WIDTH 3
+#define PROP_SPACE_WIDTH 8
+#define PROP_HEIGHT 27
+#define PROP_SMALL_SIZE_SCALE 0.75
+
+#define BLINK_DIVISOR 200
+#define PULSE_DIVISOR 75
+
+#define UI_LEFT 0x00000000 // default
+#define UI_CENTER 0x00000001
+#define UI_RIGHT 0x00000002
+#define UI_FORMATMASK 0x00000007
+#define UI_SMALLFONT 0x00000010
+#define UI_BIGFONT 0x00000020 // default
+#define UI_GIANTFONT 0x00000040
+#define UI_DROPSHADOW 0x00000800
+#define UI_BLINK 0x00001000
+#define UI_INVERSE 0x00002000
+#define UI_PULSE 0x00004000
+
+#if defined(_DEBUG) && !defined(BSPC)
+ #define HUNK_DEBUG
+#endif
+
+typedef enum {
+ h_high,
+ h_low,
+ h_dontcare
+} ha_pref;
+
+#ifdef HUNK_DEBUG
+#define Hunk_Alloc( size, preference ) Hunk_AllocDebug(size, preference, #size, __FILE__, __LINE__)
+void *Hunk_AllocDebug( int size, ha_pref preference, char *label, char *file, int line );
+#else
+void *Hunk_Alloc( int size, ha_pref preference );
+#endif
+
+#define Com_Memset memset
+#define Com_Memcpy memcpy
+
+#define CIN_system 1
+#define CIN_loop 2
+#define CIN_hold 4
+#define CIN_silent 8
+#define CIN_shader 16
+
+/*
+==============================================================
+
+MATHLIB
+
+==============================================================
+*/
+
+
+typedef float vec_t;
+typedef vec_t vec2_t[2];
+typedef vec_t vec3_t[3];
+typedef vec_t vec4_t[4];
+typedef vec_t vec5_t[5];
+
+typedef int fixed4_t;
+typedef int fixed8_t;
+typedef int fixed16_t;
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846f // matches value in gcc v2 math.h
+#endif
+
+#define NUMVERTEXNORMALS 162
+extern vec3_t bytedirs[NUMVERTEXNORMALS];
+
+// all drawing is done to a 640*480 virtual screen size
+// and will be automatically scaled to the real resolution
+#define SCREEN_WIDTH 640
+#define SCREEN_HEIGHT 480
+
+#define TINYCHAR_WIDTH (SMALLCHAR_WIDTH)
+#define TINYCHAR_HEIGHT (SMALLCHAR_HEIGHT/2)
+
+#define SMALLCHAR_WIDTH 8
+#define SMALLCHAR_HEIGHT 16
+
+#define BIGCHAR_WIDTH 16
+#define BIGCHAR_HEIGHT 16
+
+#define GIANTCHAR_WIDTH 32
+#define GIANTCHAR_HEIGHT 48
+
+extern vec4_t colorBlack;
+extern vec4_t colorRed;
+extern vec4_t colorGreen;
+extern vec4_t colorBlue;
+extern vec4_t colorYellow;
+extern vec4_t colorMagenta;
+extern vec4_t colorCyan;
+extern vec4_t colorWhite;
+extern vec4_t colorLtGrey;
+extern vec4_t colorMdGrey;
+extern vec4_t colorDkGrey;
+
+#define Q_COLOR_ESCAPE '^'
+#define Q_IsColorString(p) ((p) && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) >= '0' && *((p)+1) <= '8') // ^[0-8]
+#define COLOR_BLACK '0'
+#define COLOR_RED '1'
+#define COLOR_GREEN '2'
+#define COLOR_YELLOW '3'
+#define COLOR_BLUE '4'
+#define COLOR_CYAN '5'
+#define COLOR_MAGENTA '6'
+#define COLOR_WHITE '7'
+#define COLOR_MENU '8'
+#define ColorIndex(c) ((c) - '0')
+
+#define S_COLOR_BLACK "^0"
+#define S_COLOR_RED "^1"
+#define S_COLOR_GREEN "^2"
+#define S_COLOR_YELLOW "^3"
+#define S_COLOR_BLUE "^4"
+#define S_COLOR_CYAN "^5"
+#define S_COLOR_MAGENTA "^6"
+#define S_COLOR_WHITE "^7"
+#define S_COLOR_MENU "^8"
+
+extern vec4_t g_color_table[9];
+
+#define MAKERGB( v, r, g, b ) v[0]=r;v[1]=g;v[2]=b
+#define MAKERGBA( v, r, g, b, a ) v[0]=r;v[1]=g;v[2]=b;v[3]=a
+
+#define DEG2RAD( a ) ( ( (a) * M_PI ) / 180.0F )
+#define RAD2DEG( a ) ( ( (a) * 180.0f ) / M_PI )
+
+struct cplane_s;
+
+extern vec3_t vec3_origin;
+extern vec3_t axisDefault[3];
+
+#define nanmask (255<<23)
+
+#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
+
+#if idppc
+
+static ID_INLINE float Q_rsqrt( float number ) {
+ float x = 0.5f * number;
+ float y;
+#ifdef __GNUC__
+ asm("frsqrte %0,%1" : "=f" (y) : "f" (number));
+#else
+ y = __frsqrte( number );
+#endif
+ return y * (1.5f - (x * y * y));
+ }
+
+#ifdef __GNUC__
+static ID_INLINE float Q_fabs(float x) {
+ float abs_x;
+
+ asm("fabs %0,%1" : "=f" (abs_x) : "f" (x));
+ return abs_x;
+}
+#else
+#define Q_fabs __fabsf
+#endif
+
+#else
+float Q_fabs( float f );
+float Q_rsqrt( float f ); // reciprocal square root
+#endif
+
+#define SQRTFAST( x ) ( (x) * Q_rsqrt( x ) )
+
+signed char ClampChar( int i );
+signed short ClampShort( int i );
+
+// this isn't a real cheap function to call!
+int DirToByte( vec3_t dir );
+void ByteToDir( int b, vec3_t dir );
+
+#if 1
+
+#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
+#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2])
+#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2])
+#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2])
+#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s))
+#define VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s))
+
+#else
+
+#define DotProduct(x,y) _DotProduct(x,y)
+#define VectorSubtract(a,b,c) _VectorSubtract(a,b,c)
+#define VectorAdd(a,b,c) _VectorAdd(a,b,c)
+#define VectorCopy(a,b) _VectorCopy(a,b)
+#define VectorScale(v, s, o) _VectorScale(v,s,o)
+#define VectorMA(v, s, b, o) _VectorMA(v,s,b,o)
+
+#endif
+
+#ifdef Q3_VM
+#ifdef VectorCopy
+#undef VectorCopy
+// this is a little hack to get more efficient copies in our interpreter
+typedef struct {
+ float v[3];
+} vec3struct_t;
+#define VectorCopy(a,b) (*(vec3struct_t *)b=*(vec3struct_t *)a)
+#endif
+#endif
+
+#define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0)
+#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2])
+#define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z))
+#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
+
+#define SnapVector(v) {v[0]=((int)(v[0]));v[1]=((int)(v[1]));v[2]=((int)(v[2]));}
+// just in case you do't want to use the macros
+vec_t _DotProduct( const vec3_t v1, const vec3_t v2 );
+void _VectorSubtract( const vec3_t veca, const vec3_t vecb, vec3_t out );
+void _VectorAdd( const vec3_t veca, const vec3_t vecb, vec3_t out );
+void _VectorCopy( const vec3_t in, vec3_t out );
+void _VectorScale( const vec3_t in, float scale, vec3_t out );
+void _VectorMA( const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc );
+
+unsigned ColorBytes3 (float r, float g, float b);
+unsigned ColorBytes4 (float r, float g, float b, float a);
+
+float NormalizeColor( const vec3_t in, vec3_t out );
+
+float RadiusFromBounds( const vec3_t mins, const vec3_t maxs );
+void ClearBounds( vec3_t mins, vec3_t maxs );
+void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs );
+
+#if !defined( Q3_VM ) || ( defined( Q3_VM ) && defined( __Q3_VM_MATH ) )
+static ID_INLINE int VectorCompare( const vec3_t v1, const vec3_t v2 ) {
+ if (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2]) {
+ return 0;
+ }
+ return 1;
+}
+
+static ID_INLINE vec_t VectorLength( const vec3_t v ) {
+ return (vec_t)sqrt (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+}
+
+static ID_INLINE vec_t VectorLengthSquared( const vec3_t v ) {
+ return (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+}
+
+static ID_INLINE vec_t Distance( const vec3_t p1, const vec3_t p2 ) {
+ vec3_t v;
+
+ VectorSubtract (p2, p1, v);
+ return VectorLength( v );
+}
+
+static ID_INLINE vec_t DistanceSquared( const vec3_t p1, const vec3_t p2 ) {
+ vec3_t v;
+
+ VectorSubtract (p2, p1, v);
+ return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+}
+
+// fast vector normalize routine that does not check to make sure
+// that length != 0, nor does it return length, uses rsqrt approximation
+static ID_INLINE void VectorNormalizeFast( vec3_t v )
+{
+ float ilength;
+
+ ilength = Q_rsqrt( DotProduct( v, v ) );
+
+ v[0] *= ilength;
+ v[1] *= ilength;
+ v[2] *= ilength;
+}
+
+static ID_INLINE void VectorInverse( vec3_t v ){
+ v[0] = -v[0];
+ v[1] = -v[1];
+ v[2] = -v[2];
+}
+
+static ID_INLINE void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross ) {
+ cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
+ cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
+ cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
+}
+
+#else
+int VectorCompare( const vec3_t v1, const vec3_t v2 );
+
+vec_t VectorLength( const vec3_t v );
+
+vec_t VectorLengthSquared( const vec3_t v );
+
+vec_t Distance( const vec3_t p1, const vec3_t p2 );
+
+vec_t DistanceSquared( const vec3_t p1, const vec3_t p2 );
+
+void VectorNormalizeFast( vec3_t v );
+
+void VectorInverse( vec3_t v );
+
+void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross );
+
+#endif
+
+vec_t VectorNormalize (vec3_t v); // returns vector length
+vec_t VectorNormalize2( const vec3_t v, vec3_t out );
+void Vector4Scale( const vec4_t in, vec_t scale, vec4_t out );
+void VectorRotate( vec3_t in, vec3_t matrix[3], vec3_t out );
+int Q_log2(int val);
+
+float Q_acos(float c);
+
+int Q_rand( int *seed );
+float Q_random( int *seed );
+float Q_crandom( int *seed );
+
+#define random() ((rand () & 0x7fff) / ((float)0x7fff))
+#define crandom() (2.0 * (random() - 0.5))
+
+void vectoangles( const vec3_t value1, vec3_t angles);
+void AnglesToAxis( const vec3_t angles, vec3_t axis[3] );
+
+void AxisClear( vec3_t axis[3] );
+void AxisCopy( vec3_t in[3], vec3_t out[3] );
+
+void SetPlaneSignbits( struct cplane_s *out );
+int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *plane);
+
+qboolean BoundsIntersect(const vec3_t mins, const vec3_t maxs,
+ const vec3_t mins2, const vec3_t maxs2);
+qboolean BoundsIntersectSphere(const vec3_t mins, const vec3_t maxs,
+ const vec3_t origin, vec_t radius);
+qboolean BoundsIntersectPoint(const vec3_t mins, const vec3_t maxs,
+ const vec3_t origin);
+
+float AngleMod(float a);
+float LerpAngle (float from, float to, float frac);
+float AngleSubtract( float a1, float a2 );
+void AnglesSubtract( vec3_t v1, vec3_t v2, vec3_t v3 );
+
+float AngleNormalize360 ( float angle );
+float AngleNormalize180 ( float angle );
+float AngleDelta ( float angle1, float angle2 );
+
+qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c );
+void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal );
+void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
+void RotateAroundDirection( vec3_t axis[3], float yaw );
+void MakeNormalVectors( const vec3_t forward, vec3_t right, vec3_t up );
+// perpendicular vector could be replaced by this
+
+//int PlaneTypeForNormal (vec3_t normal);
+
+void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]);
+void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
+void PerpendicularVector( vec3_t dst, const vec3_t src );
+int Q_isnan( float x );
+
+
+//=============================================
+
+float Com_Clamp( float min, float max, float value );
+
+char *COM_SkipPath( char *pathname );
+const char *COM_GetExtension( const char *name );
+void COM_StripExtension(const char *in, char *out, int destsize);
+void COM_DefaultExtension( char *path, int maxSize, const char *extension );
+
+void COM_BeginParseSession( const char *name );
+int COM_GetCurrentParseLine( void );
+char *COM_Parse( char **data_p );
+char *COM_ParseExt( char **data_p, qboolean allowLineBreak );
+int COM_Compress( char *data_p );
+void COM_ParseError( char *format, ... ) __attribute__ ((format (printf, 1, 2)));
+void COM_ParseWarning( char *format, ... ) __attribute__ ((format (printf, 1, 2)));
+//int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] );
+
+#define MAX_TOKENLENGTH 1024
+
+#ifndef TT_STRING
+//token types
+#define TT_STRING 1 // string
+#define TT_LITERAL 2 // literal
+#define TT_NUMBER 3 // number
+#define TT_NAME 4 // name
+#define TT_PUNCTUATION 5 // punctuation
+#endif
+
+typedef struct pc_token_s
+{
+ int type;
+ int subtype;
+ int intvalue;
+ float floatvalue;
+ char string[MAX_TOKENLENGTH];
+} pc_token_t;
+
+// data is an in/out parm, returns a parsed out token
+
+void COM_MatchToken( char**buf_p, char *match );
+
+void SkipBracedSection (char **program);
+void SkipRestOfLine ( char **data );
+
+void Parse1DMatrix (char **buf_p, int x, float *m);
+void Parse2DMatrix (char **buf_p, int y, int x, float *m);
+void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m);
+
+void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
+
+char *Com_SkipTokens( char *s, int numTokens, char *sep );
+char *Com_SkipCharset( char *s, char *sep );
+
+void Com_RandomBytes( byte *string, int len );
+
+// mode parm for FS_FOpenFile
+typedef enum {
+ FS_READ,
+ FS_WRITE,
+ FS_APPEND,
+ FS_APPEND_SYNC
+} fsMode_t;
+
+typedef enum {
+ FS_SEEK_CUR,
+ FS_SEEK_END,
+ FS_SEEK_SET
+} fsOrigin_t;
+
+//=============================================
+
+int Q_isprint( int c );
+int Q_islower( int c );
+int Q_isupper( int c );
+int Q_isalpha( int c );
+
+// portable case insensitive compare
+int Q_stricmp (const char *s1, const char *s2);
+#define Q_strequal(s1,s2) (Q_stricmp(s1,s2)==0)
+int Q_strncmp (const char *s1, const char *s2, int n);
+int Q_stricmpn (const char *s1, const char *s2, int n);
+char *Q_strlwr( char *s1 );
+char *Q_strupr( char *s1 );
+const char *Q_stristr( const char *s, const char *find);
+
+// buffer size safe library replacements
+/**
+ * Copies a string from one array to another in a safe way
+ *
+ * @param dest (out) pointer to destination array
+ * @param src (in) pointer to source array
+ * @param destsize size of the destination array, at most destsize-1 will be copied
+ */
+void Q_strncpyz( char *dest, const char *src, int destsize );
+/**
+ * Appends a string to another string. The function protects against overflow.
+ * The size is the max size of the destination AFTER the string has been appended
+ * If the length of dest is larger or equal to destsize then nothing will be appended.
+ *
+ * @param dest (in/out) pointer to the string that will be appended to
+ * @param size size of the destination array
+ * @param src (in) the string to append
+ */
+void Q_strcat( char *dest, int size, const char *src );
+
+/**
+ * strlen that counts the length of the string after the color sequences have
+ * been removed. Example: "A^2I" = 2 because it will be printed "AI"
+ *
+ * @param string the string to
+ * @return the length of the string as printed
+ */
+int Q_PrintStrlen( const char *string );
+/**
+ * Removes all colors from a string.
+ *
+ * @param string (in/out) the string to make color less
+ * @return pointer to the string
+ */
+char *Q_CleanStr( char *string );
+// Count the number of char tocount encountered in string
+int Q_CountChar(const char *string, char tocount);
+
+//=============================================
+
+// 64-bit integers for global rankings interface
+// implemented as a struct for qvm compatibility
+typedef struct
+{
+ byte b0;
+ byte b1;
+ byte b2;
+ byte b3;
+ byte b4;
+ byte b5;
+ byte b6;
+ byte b7;
+} qint64;
+
+//=============================================
+/*
+short BigShort(short l);
+short LittleShort(short l);
+int BigLong (int l);
+int LittleLong (int l);
+qint64 BigLong64 (qint64 l);
+qint64 LittleLong64 (qint64 l);
+float BigFloat (const float *l);
+float LittleFloat (const float *l);
+
+void Swap_Init (void);
+*/
+char * QDECL va(char *format, ...) __attribute__ ((format (printf, 1, 2)));
+
+#define TRUNCATE_LENGTH 64
+void Com_TruncateLongString( char *buffer, const char *s );
+
+//=============================================
+
+//
+// key / value info strings
+//
+char *Info_ValueForKey( const char *s, const char *key );
+void Info_RemoveKey( char *s, const char *key );
+void Info_RemoveKey_big( char *s, const char *key );
+void Info_SetValueForKey( char *s, const char *key, const char *value );
+void Info_SetValueForKey_Big( char *s, const char *key, const char *value );
+qboolean Info_Validate( const char *s );
+void Info_NextPair( const char **s, char *key, char *value );
+
+// this is only here so the functions in q_shared.c and bg_*.c can link
+void QDECL Com_Error( int level, const char *error, ... ) __attribute__ ((format (printf, 2, 3))) __attribute__((noreturn));
+void QDECL Com_Printf( const char *msg, ... ) __attribute__ ((format (printf, 1, 2)));
+
+
+/*
+==========================================================
+
+CVARS (console variables)
+
+Many variables can be used for cheating purposes, so when
+cheats is zero, force all unspecified variables to their
+default values.
+==========================================================
+*/
+
+#define CVAR_ARCHIVE 1 // set to cause it to be saved to vars.rc
+ // used for system variables, not for player
+ // specific configurations
+#define CVAR_USERINFO 2 // sent to server on connect or change
+#define CVAR_SERVERINFO 4 // sent in response to front end requests
+#define CVAR_SYSTEMINFO 8 // these cvars will be duplicated on all clients
+#define CVAR_INIT 16 // don't allow change from console at all,
+ // but can be set from the command line
+#define CVAR_LATCH 32 // will only change when C code next does
+ // a Cvar_Get(), so it can't be changed
+ // without proper initialization. modified
+ // will be set, even though the value hasn't
+ // changed yet
+#define CVAR_ROM 64 // display only, cannot be set by user at all
+#define CVAR_USER_CREATED 128 // created by a set command
+#define CVAR_TEMP 256 // can be set even when cheats are disabled, but is not archived
+#define CVAR_CHEAT 512 // can not be changed if cheats are disabled
+#define CVAR_NORESTART 1024 // do not clear when a cvar_restart is issued
+
+#define CVAR_SERVER_CREATED 2048 // cvar was created by a server the client connected to.
+#define CVAR_NONEXISTENT 0xFFFFFFFF // Cvar doesn't exist.
+
+// nothing outside the Cvar_*() functions should modify these fields!
+typedef struct cvar_s {
+ char *name;
+ char *string;
+ char *resetString; // cvar_restart will reset to this value
+ char *latchedString; // for CVAR_LATCH vars
+ int flags;
+ qboolean modified; // set each time the cvar is changed
+ int modificationCount; // incremented each time the cvar is changed
+ float value; // atof( string )
+ int integer; // atoi( string )
+ struct cvar_s *next;
+ struct cvar_s *hashNext;
+} cvar_t;
+
+#define MAX_CVAR_VALUE_STRING 256
+
+typedef int cvarHandle_t;
+
+// the modules that run in the virtual machine can't access the cvar_t directly,
+// so they must ask for structured updates
+typedef struct {
+ cvarHandle_t handle;
+ int modificationCount;
+ float value;
+ int integer;
+ char string[MAX_CVAR_VALUE_STRING];
+} vmCvar_t;
+
+/*
+==============================================================
+
+COLLISION DETECTION
+
+==============================================================
+*/
+
+#include "surfaceflags.h" // shared with the q3map utility
+
+// plane types are used to speed some tests
+// 0-2 are axial planes
+#define PLANE_X 0
+#define PLANE_Y 1
+#define PLANE_Z 2
+#define PLANE_NON_AXIAL 3
+
+
+/*
+=================
+PlaneTypeForNormal
+=================
+*/
+
+#define PlaneTypeForNormal(x) (x[0] == 1.0 ? PLANE_X : (x[1] == 1.0 ? PLANE_Y : (x[2] == 1.0 ? PLANE_Z : PLANE_NON_AXIAL) ) )
+
+// plane_t structure
+// !!! if this is changed, it must be changed in asm code too !!!
+typedef struct cplane_s {
+ vec3_t normal;
+ float dist;
+ byte type; // for fast side tests: 0,1,2 = axial, 3 = nonaxial
+ byte signbits; // signx + (signy<<1) + (signz<<2), used as lookup during collision
+ byte pad[2];
+} cplane_t;
+
+
+// a trace is returned when a box is swept through the world
+typedef struct {
+ qboolean allsolid; // if true, plane is not valid
+ qboolean startsolid; // if true, the initial point was in a solid area
+ float fraction; // time completed, 1.0 = didn't hit anything
+ vec3_t endpos; // final position
+ cplane_t plane; // surface normal at impact, transformed to world space
+ int surfaceFlags; // surface hit
+ int contents; // contents on other side of surface hit
+ int entityNum; // entity the contacted sirface is a part of
+} trace_t;
+
+// trace->entityNum can also be 0 to (MAX_GENTITIES-1)
+// or ENTITYNUM_NONE, ENTITYNUM_WORLD
+
+
+// markfragments are returned by CM_MarkFragments()
+typedef struct {
+ int firstPoint;
+ int numPoints;
+} markFragment_t;
+
+
+
+typedef struct {
+ vec3_t origin;
+ vec3_t axis[3];
+} orientation_t;
+
+//=====================================================================
+
+
+// in order from highest priority to lowest
+// if none of the catchers are active, bound key strings will be executed
+#define KEYCATCH_CONSOLE 0x0001
+#define KEYCATCH_UI 0x0002
+#define KEYCATCH_MESSAGE 0x0004
+#define KEYCATCH_CGAME 0x0008
+
+
+// sound channels
+// channel 0 never willingly overrides
+// other channels will allways override a playing sound on that channel
+typedef enum {
+ CHAN_AUTO,
+ CHAN_LOCAL, // menu sounds, etc
+ CHAN_WEAPON,
+ CHAN_VOICE,
+ CHAN_ITEM,
+ CHAN_BODY,
+ CHAN_LOCAL_SOUND, // chat messages, etc
+ CHAN_ANNOUNCER // announcer voices, etc
+} soundChannel_t;
+
+
+/*
+========================================================================
+
+ ELEMENTS COMMUNICATED ACROSS THE NET
+
+========================================================================
+*/
+
+#define ANGLE2SHORT(x) ((int)((x)*65536/360) & 65535)
+#define SHORT2ANGLE(x) ((x)*(360.0/65536))
+
+#define SNAPFLAG_RATE_DELAYED 1
+#define SNAPFLAG_NOT_ACTIVE 2 // snapshot used during connection and for zombies
+#define SNAPFLAG_SERVERCOUNT 4 // toggled every map_restart so transitions can be detected
+
+//
+// per-level limits
+//
+#define MAX_CLIENTS 64 // absolute limit
+#define MAX_LOCATIONS 64
+
+#define GENTITYNUM_BITS 10 // don't need to send any more
+#define MAX_GENTITIES (1<<GENTITYNUM_BITS)
+
+// entitynums are communicated with GENTITY_BITS, so any reserved
+// values that are going to be communcated over the net need to
+// also be in this range
+#define ENTITYNUM_NONE (MAX_GENTITIES-1)
+#define ENTITYNUM_WORLD (MAX_GENTITIES-2)
+#define ENTITYNUM_MAX_NORMAL (MAX_GENTITIES-2)
+
+
+#define MAX_MODELS 256 // these are sent over the net as 8 bits
+#define MAX_SOUNDS 256 // so they cannot be blindly increased
+
+
+#define MAX_CONFIGSTRINGS 1024
+
+// these are the only configstrings that the system reserves, all the
+// other ones are strictly for servergame to clientgame communication
+#define CS_SERVERINFO 0 // an info string with all the serverinfo cvars
+#define CS_SYSTEMINFO 1 // an info string for server system to client system configuration (timescale, etc)
+
+#define RESERVED_CONFIGSTRINGS 2 // game can't modify below this, only the system can
+
+#define MAX_GAMESTATE_CHARS 16000
+typedef struct {
+ int stringOffsets[MAX_CONFIGSTRINGS];
+ char stringData[MAX_GAMESTATE_CHARS];
+ int dataCount;
+} gameState_t;
+
+//=========================================================
+
+// bit field limits
+#define MAX_STATS 16
+#define MAX_PERSISTANT 16
+#define MAX_POWERUPS 16
+#define MAX_WEAPONS 16
+
+#define MAX_PS_EVENTS 2
+
+#define PS_PMOVEFRAMECOUNTBITS 6
+
+// playerState_t is the information needed by both the client and server
+// to predict player motion and actions
+// nothing outside of pmove should modify these, or some degree of prediction error
+// will occur
+
+// you can't add anything to this without modifying the code in msg.c
+
+// playerState_t is a full superset of entityState_t as it is used by players,
+// so if a playerState_t is transmitted, the entityState_t can be fully derived
+// from it.
+typedef struct playerState_s {
+ int commandTime; // cmd->serverTime of last executed command
+ int pm_type;
+ int bobCycle; // for view bobbing and footstep generation
+ int pm_flags; // ducked, jump_held, etc
+ int pm_time;
+
+ vec3_t origin;
+ vec3_t velocity;
+ int weaponTime;
+ int gravity;
+ int speed;
+ int delta_angles[3]; // add to command angles to get view direction
+ // changed by spawns, rotating objects, and teleporters
+
+ int groundEntityNum;// ENTITYNUM_NONE = in air
+
+ int legsTimer; // don't change low priority animations until this runs out
+ int legsAnim; // mask off ANIM_TOGGLEBIT
+
+ int torsoTimer; // don't change low priority animations until this runs out
+ int torsoAnim; // mask off ANIM_TOGGLEBIT
+
+ int movementDir; // a number 0 to 7 that represents the reletive angle
+ // of movement to the view angle (axial and diagonals)
+ // when at rest, the value will remain unchanged
+ // used to twist the legs during strafing
+
+ vec3_t grapplePoint; // location of grapple to pull towards if PMF_GRAPPLE_PULL
+
+ int eFlags; // copied to entityState_t->eFlags
+
+ int eventSequence; // pmove generated events
+ int events[MAX_PS_EVENTS];
+ int eventParms[MAX_PS_EVENTS];
+
+ int externalEvent; // events set on player from another source
+ int externalEventParm;
+ int externalEventTime;
+
+ int clientNum; // ranges from 0 to MAX_CLIENTS-1
+ int weapon; // copied to entityState_t->weapon
+ int weaponstate;
+
+ vec3_t viewangles; // for fixed views
+ int viewheight;
+
+ // damage feedback
+ int damageEvent; // when it changes, latch the other parms
+ int damageYaw;
+ int damagePitch;
+ int damageCount;
+
+ int stats[MAX_STATS];
+ int persistant[MAX_PERSISTANT]; // stats that aren't cleared on death
+ int powerups[MAX_POWERUPS]; // level.time that the powerup runs out
+ int ammo[MAX_WEAPONS];
+
+ int generic1;
+ int loopSound;
+ int jumppad_ent; // jumppad entity hit this frame
+
+ // not communicated over the net at all
+ int ping; // server to game info for scoreboard
+ int pmove_framecount; // FIXME: don't transmit over the network
+ int jumppad_frame;
+ int entityEventSequence;
+} playerState_t;
+
+
+//====================================================================
+
+
+//
+// usercmd_t->button bits, many of which are generated by the client system,
+// so they aren't game/cgame only definitions
+//
+#define BUTTON_ATTACK 1
+#define BUTTON_TALK 2 // displays talk balloon and disables actions
+#define BUTTON_USE_HOLDABLE 4
+#define BUTTON_GESTURE 8
+#define BUTTON_WALKING 16 // walking can't just be infered from MOVE_RUN
+ // because a key pressed late in the frame will
+ // only generate a small move value for that frame
+ // walking will use different animations and
+ // won't generate footsteps
+#define BUTTON_AFFIRMATIVE 32
+#define BUTTON_NEGATIVE 64
+
+#define BUTTON_GETFLAG 128
+#define BUTTON_GUARDBASE 256
+#define BUTTON_PATROL 512
+#define BUTTON_FOLLOWME 1024
+
+#define BUTTON_ANY 2048 // any key whatsoever
+
+#define MOVE_RUN 120 // if forwardmove or rightmove are >= MOVE_RUN,
+ // then BUTTON_WALKING should be set
+
+// usercmd_t is sent to the server each client frame
+typedef struct usercmd_s {
+ int serverTime;
+ int angles[3];
+ int buttons;
+ byte weapon; // weapon
+ signed char forwardmove, rightmove, upmove;
+} usercmd_t;
+
+//===================================================================
+
+// if entityState->solid == SOLID_BMODEL, modelindex is an inline model number
+#define SOLID_BMODEL 0xffffff
+
+typedef enum {
+ TR_STATIONARY,
+ TR_INTERPOLATE, // non-parametric, but interpolate between snapshots
+ TR_LINEAR,
+ TR_LINEAR_STOP,
+ TR_SINE, // value = base + sin( time / duration ) * delta
+ TR_GRAVITY
+} trType_t;
+
+typedef struct {
+ trType_t trType;
+ int trTime;
+ int trDuration; // if non 0, trTime + trDuration = stop time
+ vec3_t trBase;
+ vec3_t trDelta; // velocity, etc
+} trajectory_t;
+
+// entityState_t is the information conveyed from the server
+// in an update message about entities that the client will
+// need to render in some way
+// Different eTypes may use the information in different ways
+// The messages are delta compressed, so it doesn't really matter if
+// the structure size is fairly large
+
+typedef struct entityState_s {
+ int number; // entity index
+ int eType; // entityType_t
+ int eFlags;
+
+ trajectory_t pos; // for calculating position
+ trajectory_t apos; // for calculating angles
+
+ int time;
+ int time2;
+
+ vec3_t origin;
+ vec3_t origin2;
+
+ vec3_t angles;
+ vec3_t angles2;
+
+ int otherEntityNum; // shotgun sources, etc
+ int otherEntityNum2;
+
+ int groundEntityNum; // -1 = in air
+
+ int constantLight; // r + (g<<8) + (b<<16) + (intensity<<24)
+ int loopSound; // constantly loop this sound
+
+ int modelindex;
+ int modelindex2;
+ int clientNum; // 0 to (MAX_CLIENTS - 1), for players and corpses
+ int frame;
+
+ int solid; // for client side prediction, trap_linkentity sets this properly
+
+ int event; // impulse events -- muzzle flashes, footsteps, etc
+ int eventParm;
+
+ // for players
+ int powerups; // bit flags
+ int weapon; // determines weapon and flash model, etc
+ int legsAnim; // mask off ANIM_TOGGLEBIT
+ int torsoAnim; // mask off ANIM_TOGGLEBIT
+
+ int generic1;
+} entityState_t;
+
+typedef enum {
+ CA_UNINITIALIZED,
+ CA_DISCONNECTED, // not talking to a server
+ CA_AUTHORIZING, // not used any more, was checking cd key
+ CA_CONNECTING, // sending request packets to the server
+ CA_CHALLENGING, // sending challenge packets to the server
+ CA_CONNECTED, // netchan_t established, getting gamestate
+ CA_LOADING, // only during cgame initialization, never during main loop
+ CA_PRIMED, // got gamestate, waiting for first frame
+ CA_ACTIVE, // game views should be displayed
+ CA_CINEMATIC // playing a cinematic or a static pic, not connected to a server
+} connstate_t;
+
+// font support
+
+#define GLYPH_START 0
+#define GLYPH_END 255
+#define GLYPH_CHARSTART 32
+#define GLYPH_CHAREND 127
+#define GLYPHS_PER_FONT GLYPH_END - GLYPH_START + 1
+typedef struct {
+ int height; // number of scan lines
+ int top; // top of glyph in buffer
+ int bottom; // bottom of glyph in buffer
+ int pitch; // width for copying
+ int xSkip; // x adjustment
+ int imageWidth; // width of actual image
+ int imageHeight; // height of actual image
+ float s; // x offset in image where glyph starts
+ float t; // y offset in image where glyph starts
+ float s2;
+ float t2;
+ qhandle_t glyph; // handle to the shader with the glyph
+ char shaderName[32];
+} glyphInfo_t;
+
+typedef struct {
+ glyphInfo_t glyphs [GLYPHS_PER_FONT];
+ float glyphScale;
+ char name[MAX_QPATH];
+} fontInfo_t;
+
+#define Square(x) ((x)*(x))
+
+// real time
+//=============================================
+
+
+typedef struct qtime_s {
+ int tm_sec; /* seconds after the minute - [0,59] */
+ int tm_min; /* minutes after the hour - [0,59] */
+ int tm_hour; /* hours since midnight - [0,23] */
+ int tm_mday; /* day of the month - [1,31] */
+ int tm_mon; /* months since January - [0,11] */
+ int tm_year; /* years since 1900 */
+ int tm_wday; /* days since Sunday - [0,6] */
+ int tm_yday; /* days since January 1 - [0,365] */
+ int tm_isdst; /* daylight savings time flag */
+} qtime_t;
+
+
+// server browser sources
+// TTimo: AS_MPLAYER is no longer used
+#define AS_LOCAL 0
+#define AS_MPLAYER 1
+#define AS_GLOBAL 2
+#define AS_FAVORITES 3
+
+
+// cinematic states
+typedef enum {
+ FMV_IDLE,
+ FMV_PLAY, // play
+ FMV_EOF, // all other conditions, i.e. stop/EOF/abort
+ FMV_ID_BLT,
+ FMV_ID_IDLE,
+ FMV_LOOPED,
+ FMV_ID_WAIT
+} e_status;
+
+typedef enum _flag_status {
+ FLAG_ATBASE = 0,
+ FLAG_TAKEN, // CTF
+ FLAG_TAKEN_RED, // One Flag CTF
+ FLAG_TAKEN_BLUE, // One Flag CTF
+ FLAG_DROPPED
+} flagStatus_t;
+
+
+
+#define MAX_GLOBAL_SERVERS 4096
+#define MAX_OTHER_SERVERS 128
+#define MAX_PINGREQUESTS 32
+#define MAX_SERVERSTATUSREQUESTS 16
+
+#define SAY_ALL 0
+#define SAY_TEAM 1
+#define SAY_TELL 2
+
+#define CDKEY_LEN 16
+#define CDCHKSUM_LEN 2
+
+
+#endif // __Q_SHARED_H
diff --git a/game/code/qcommon/qcommon.h b/code/qcommon/qcommon.h
similarity index 100%
rename from game/code/qcommon/qcommon.h
rename to code/qcommon/qcommon.h
diff --git a/engine/code/qcommon/qfiles.h b/code/qcommon/qfiles.h
similarity index 100%
rename from engine/code/qcommon/qfiles.h
rename to code/qcommon/qfiles.h
diff --git a/engine/code/qcommon/surfaceflags.h b/code/qcommon/surfaceflags.h
similarity index 100%
rename from engine/code/qcommon/surfaceflags.h
rename to code/qcommon/surfaceflags.h
diff --git a/engine/code/renderer/tr_types.h b/code/renderer/tr_types.h
similarity index 100%
rename from engine/code/renderer/tr_types.h
rename to code/renderer/tr_types.h
diff --git a/engine/code/tools/asm/README.Id b/code/tools/asm/README.Id
similarity index 100%
rename from engine/code/tools/asm/README.Id
rename to code/tools/asm/README.Id
diff --git a/code/tools/asm/cmdlib.c b/code/tools/asm/cmdlib.c
new file mode 100644
index 0000000..de2610d
--- /dev/null
+++ b/code/tools/asm/cmdlib.c
@@ -0,0 +1,1138 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+// cmdlib.c
+
+#include "cmdlib.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+#include <direct.h>
+#include <windows.h>
+#elif defined(NeXT)
+#include <libc.h>
+#else
+#include <unistd.h>
+#endif
+
+#define BASEDIRNAME "quake" // assumed to have a 2 or 3 following
+#define PATHSEPERATOR '/'
+
+// set these before calling CheckParm
+int myargc;
+char **myargv;
+
+char com_token[1024];
+qboolean com_eof;
+
+qboolean archive;
+char archivedir[1024];
+
+
+/*
+===================
+ExpandWildcards
+
+Mimic unix command line expansion
+===================
+*/
+#define MAX_EX_ARGC 1024
+int ex_argc;
+char *ex_argv[MAX_EX_ARGC];
+#ifdef _WIN32
+#include "io.h"
+void ExpandWildcards( int *argc, char ***argv )
+{
+ struct _finddata_t fileinfo;
+ int handle;
+ int i;
+ char filename[1024];
+ char filebase[1024];
+ char *path;
+
+ ex_argc = 0;
+ for (i=0 ; i<*argc ; i++)
+ {
+ path = (*argv)[i];
+ if ( path[0] == '-'
+ || ( !strstr(path, "*") && !strstr(path, "?") ) )
+ {
+ ex_argv[ex_argc++] = path;
+ continue;
+ }
+
+ handle = _findfirst (path, &fileinfo);
+ if (handle == -1)
+ return;
+
+ ExtractFilePath (path, filebase);
+
+ do
+ {
+ sprintf (filename, "%s%s", filebase, fileinfo.name);
+ ex_argv[ex_argc++] = copystring (filename);
+ } while (_findnext( handle, &fileinfo ) != -1);
+
+ _findclose (handle);
+ }
+
+ *argc = ex_argc;
+ *argv = ex_argv;
+}
+#else
+void ExpandWildcards (int *argc, char ***argv)
+{
+}
+#endif
+
+#ifdef WIN_ERROR
+#include <windows.h>
+/*
+=================
+Error
+
+For abnormal program terminations in windowed apps
+=================
+*/
+void Error( const char *error, ... )
+{
+ va_list argptr;
+ char text[1024];
+ char text2[1024];
+ int err;
+
+ err = GetLastError ();
+
+ va_start (argptr,error);
+ vsprintf (text, error,argptr);
+ va_end (argptr);
+
+ sprintf (text2, "%s\nGetLastError() = %i", text, err);
+ MessageBox(NULL, text2, "Error", 0 /* MB_OK */ );
+
+ exit (1);
+}
+
+#else
+/*
+=================
+Error
+
+For abnormal program terminations in console apps
+=================
+*/
+void Error( const char *error, ...)
+{
+ va_list argptr;
+
+ _printf ("\n************ ERROR ************\n");
+
+ va_start (argptr,error);
+ vprintf (error,argptr);
+ va_end (argptr);
+ _printf ("\r\n");
+
+ exit (1);
+}
+#endif
+
+// only printf if in verbose mode
+qboolean verbose = qfalse;
+void qprintf( const char *format, ... ) {
+ va_list argptr;
+
+ if (!verbose)
+ return;
+
+ va_start (argptr,format);
+ vprintf (format,argptr);
+ va_end (argptr);
+
+}
+
+#ifdef WIN32
+HWND hwndOut = NULL;
+qboolean lookedForServer = qfalse;
+UINT wm_BroadcastCommand = -1;
+#endif
+
+void _printf( const char *format, ... ) {
+ va_list argptr;
+ char text[4096];
+#ifdef WIN32
+ ATOM a;
+#endif
+ va_start (argptr,format);
+ vsprintf (text, format, argptr);
+ va_end (argptr);
+
+ printf(text);
+
+#ifdef WIN32
+ if (!lookedForServer) {
+ lookedForServer = qtrue;
+ hwndOut = FindWindow(NULL, "Q3Map Process Server");
+ if (hwndOut) {
+ wm_BroadcastCommand = RegisterWindowMessage( "Q3MPS_BroadcastCommand" );
+ }
+ }
+ if (hwndOut) {
+ a = GlobalAddAtom(text);
+ PostMessage(hwndOut, wm_BroadcastCommand, 0, (LPARAM)a);
+ }
+#endif
+}
+
+
+/*
+
+qdir will hold the path up to the quake directory, including the slash
+
+ f:\quake\
+ /raid/quake/
+
+gamedir will hold qdir + the game directory (id1, id2, etc)
+
+ */
+
+char qdir[1024];
+char gamedir[1024];
+char writedir[1024];
+
+void SetQdirFromPath( const char *path )
+{
+ char temp[1024];
+ const char *c;
+ const char *sep;
+ int len, count;
+
+ if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':'))
+ { // path is partial
+ Q_getwd (temp);
+ strcat (temp, path);
+ path = temp;
+ }
+
+ // search for "quake2" in path
+
+ len = strlen(BASEDIRNAME);
+ for (c=path+strlen(path)-1 ; c != path ; c--)
+ {
+ int i;
+
+ if (!Q_strncasecmp (c, BASEDIRNAME, len))
+ {
+ //
+ //strncpy (qdir, path, c+len+2-path);
+ // the +2 assumes a 2 or 3 following quake which is not the
+ // case with a retail install
+ // so we need to add up how much to the next separator
+ sep = c + len;
+ count = 1;
+ while (*sep && *sep != '/' && *sep != '\\')
+ {
+ sep++;
+ count++;
+ }
+ strncpy (qdir, path, c+len+count-path);
+ qprintf ("qdir: %s\n", qdir);
+ for ( i = 0; i < strlen( qdir ); i++ )
+ {
+ if ( qdir[i] == '\\' )
+ qdir[i] = '/';
+ }
+
+ c += len+count;
+ while (*c)
+ {
+ if (*c == '/' || *c == '\\')
+ {
+ strncpy (gamedir, path, c+1-path);
+
+ for ( i = 0; i < strlen( gamedir ); i++ )
+ {
+ if ( gamedir[i] == '\\' )
+ gamedir[i] = '/';
+ }
+
+ qprintf ("gamedir: %s\n", gamedir);
+
+ if ( !writedir[0] )
+ strcpy( writedir, gamedir );
+ else if ( writedir[strlen( writedir )-1] != '/' )
+ {
+ writedir[strlen( writedir )] = '/';
+ writedir[strlen( writedir )+1] = 0;
+ }
+
+ return;
+ }
+ c++;
+ }
+ Error ("No gamedir in %s", path);
+ return;
+ }
+ }
+ Error ("SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path);
+}
+
+char *ExpandArg (const char *path)
+{
+ static char full[1024];
+
+ if (path[0] != '/' && path[0] != '\\' && path[1] != ':')
+ {
+ Q_getwd (full);
+ strcat (full, path);
+ }
+ else
+ strcpy (full, path);
+ return full;
+}
+
+char *ExpandPath (const char *path)
+{
+ static char full[1024];
+ if (!qdir[0])
+ Error ("ExpandPath called without qdir set");
+ if (path[0] == '/' || path[0] == '\\' || path[1] == ':') {
+ strcpy( full, path );
+ return full;
+ }
+ sprintf (full, "%s%s", qdir, path);
+ return full;
+}
+
+char *ExpandGamePath (const char *path)
+{
+ static char full[1024];
+ if (!qdir[0])
+ Error ("ExpandGamePath called without qdir set");
+ if (path[0] == '/' || path[0] == '\\' || path[1] == ':') {
+ strcpy( full, path );
+ return full;
+ }
+ sprintf (full, "%s%s", gamedir, path);
+ return full;
+}
+
+char *ExpandPathAndArchive (const char *path)
+{
+ char *expanded;
+ char archivename[1024];
+
+ expanded = ExpandPath (path);
+
+ if (archive)
+ {
+ sprintf (archivename, "%s/%s", archivedir, path);
+ QCopyFile (expanded, archivename);
+ }
+ return expanded;
+}
+
+
+char *copystring(const char *s)
+{
+ char *b;
+ b = malloc(strlen(s)+1);
+ strcpy (b, s);
+ return b;
+}
+
+
+
+/*
+================
+I_FloatTime
+================
+*/
+double I_FloatTime (void)
+{
+ time_t t;
+
+ time (&t);
+
+ return t;
+#if 0
+// more precise, less portable
+ 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;
+#endif
+}
+
+void Q_getwd (char *out)
+{
+ int i = 0;
+
+#ifdef WIN32
+ _getcwd (out, 256);
+ strcat (out, "\\");
+#else
+ getcwd (out, 256);
+ strcat (out, "/");
+#endif
+
+ while ( out[i] != 0 )
+ {
+ if ( out[i] == '\\' )
+ out[i] = '/';
+ i++;
+ }
+}
+
+
+void Q_mkdir (const char *path)
+{
+#ifdef WIN32
+ if (_mkdir (path) != -1)
+ return;
+#else
+ if (mkdir (path, 0777) != -1)
+ return;
+#endif
+ if (errno != EEXIST)
+ Error ("mkdir %s: %s",path, strerror(errno));
+}
+
+/*
+============
+FileTime
+
+returns -1 if not present
+============
+*/
+int FileTime (const char *path)
+{
+ struct stat buf;
+
+ if (stat (path,&buf) == -1)
+ return -1;
+
+ return buf.st_mtime;
+}
+
+
+
+/*
+==============
+COM_Parse
+
+Parse a token out of a string
+==============
+*/
+char *COM_Parse (char *data)
+{
+ int c;
+ int len;
+
+ len = 0;
+ com_token[0] = 0;
+
+ if (!data)
+ return NULL;
+
+// skip whitespace
+skipwhite:
+ while ( (c = *data) <= ' ')
+ {
+ if (c == 0)
+ {
+ com_eof = qtrue;
+ return NULL; // end of file;
+ }
+ data++;
+ }
+
+// skip // comments
+ if (c=='/' && data[1] == '/')
+ {
+ while (*data && *data != '\n')
+ data++;
+ goto skipwhite;
+ }
+
+
+// handle quoted strings specially
+ if (c == '\"')
+ {
+ data++;
+ do
+ {
+ c = *data++;
+ if (c=='\"')
+ {
+ com_token[len] = 0;
+ return data;
+ }
+ com_token[len] = c;
+ len++;
+ } while (1);
+ }
+
+// parse single characters
+ if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
+ {
+ com_token[len] = c;
+ len++;
+ com_token[len] = 0;
+ return data+1;
+ }
+
+// parse a regular word
+ do
+ {
+ com_token[len] = c;
+ data++;
+ len++;
+ c = *data;
+ if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
+ break;
+ } while (c>32);
+
+ com_token[len] = 0;
+ return data;
+}
+
+
+int Q_strncasecmp (const char *s1, const char *s2, int n)
+{
+ int c1, c2;
+
+ do
+ {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if (!n--)
+ return 0; // strings are equal until end point
+
+ if (c1 != c2)
+ {
+ if (c1 >= 'a' && c1 <= 'z')
+ c1 -= ('a' - 'A');
+ if (c2 >= 'a' && c2 <= 'z')
+ c2 -= ('a' - 'A');
+ if (c1 != c2)
+ return -1; // strings not equal
+ }
+ } while (c1);
+
+ return 0; // strings are equal
+}
+
+int Q_stricmp (const char *s1, const char *s2)
+{
+ return Q_strncasecmp (s1, s2, 99999);
+}
+
+
+char *strupr (char *start)
+{
+ char *in;
+ in = start;
+ while (*in)
+ {
+ *in = toupper(*in);
+ in++;
+ }
+ return start;
+}
+
+char *strlower (char *start)
+{
+ char *in;
+ in = start;
+ while (*in)
+ {
+ *in = tolower(*in);
+ in++;
+ }
+ return start;
+}
+
+
+/*
+=============================================================================
+
+ MISC FUNCTIONS
+
+=============================================================================
+*/
+
+
+/*
+=================
+CheckParm
+
+Checks for the given parameter in the program's command line arguments
+Returns the argument number (1 to argc-1) or 0 if not present
+=================
+*/
+int CheckParm (const char *check)
+{
+ int i;
+
+ for (i = 1;i<myargc;i++)
+ {
+ if ( !Q_stricmp(check, myargv[i]) )
+ return i;
+ }
+
+ return 0;
+}
+
+
+
+/*
+================
+Q_filelength
+================
+*/
+int Q_filelength (FILE *f)
+{
+ int pos;
+ int end;
+
+ pos = ftell (f);
+ fseek (f, 0, SEEK_END);
+ end = ftell (f);
+ fseek (f, pos, SEEK_SET);
+
+ return end;
+}
+
+#ifdef MAX_PATH
+#undef MAX_PATH
+#endif
+#define MAX_PATH 4096
+static FILE* myfopen(const char* filename, const char* mode)
+{
+ char* p;
+ char fn[MAX_PATH];
+
+ fn[0] = '\0';
+ strncat(fn, filename, sizeof(fn)-1);
+
+ for(p=fn;*p;++p) if(*p == '\\') *p = '/';
+
+ return fopen(fn, mode);
+}
+
+
+FILE *SafeOpenWrite (const char *filename)
+{
+ FILE *f;
+
+ f = myfopen(filename, "wb");
+
+ if (!f)
+ Error ("Error opening %s: %s",filename,strerror(errno));
+
+ return f;
+}
+
+FILE *SafeOpenRead (const char *filename)
+{
+ FILE *f;
+
+ f = myfopen(filename, "rb");
+
+ if (!f)
+ Error ("Error opening %s: %s",filename,strerror(errno));
+
+ return f;
+}
+
+
+void SafeRead (FILE *f, void *buffer, int count)
+{
+ if ( fread (buffer, 1, count, f) != (size_t)count)
+ Error ("File read failure");
+}
+
+
+void SafeWrite (FILE *f, const void *buffer, int count)
+{
+ if (fwrite (buffer, 1, count, f) != (size_t)count)
+ Error ("File write failure");
+}
+
+
+/*
+==============
+FileExists
+==============
+*/
+qboolean FileExists (const char *filename)
+{
+ FILE *f;
+
+ f = myfopen (filename, "r");
+ if (!f)
+ return qfalse;
+ fclose (f);
+ return qtrue;
+}
+
+/*
+==============
+LoadFile
+==============
+*/
+int LoadFile( const char *filename, void **bufferptr )
+{
+ FILE *f;
+ int length;
+ void *buffer;
+
+ f = SafeOpenRead (filename);
+ length = Q_filelength (f);
+ buffer = malloc (length+1);
+ ((char *)buffer)[length] = 0;
+ SafeRead (f, buffer, length);
+ fclose (f);
+
+ *bufferptr = buffer;
+ return length;
+}
+
+
+/*
+==============
+LoadFileBlock
+-
+rounds up memory allocation to 4K boundry
+-
+==============
+*/
+int LoadFileBlock( const char *filename, void **bufferptr )
+{
+ FILE *f;
+ int length, nBlock, nAllocSize;
+ void *buffer;
+
+ f = SafeOpenRead (filename);
+ length = Q_filelength (f);
+ nAllocSize = length;
+ nBlock = nAllocSize % MEM_BLOCKSIZE;
+ if ( nBlock > 0) {
+ nAllocSize += MEM_BLOCKSIZE - nBlock;
+ }
+ buffer = malloc (nAllocSize+1);
+ memset(buffer, 0, nAllocSize+1);
+ SafeRead (f, buffer, length);
+ fclose (f);
+
+ *bufferptr = buffer;
+ return length;
+}
+
+
+/*
+==============
+TryLoadFile
+
+Allows failure
+==============
+*/
+int TryLoadFile (const char *filename, void **bufferptr)
+{
+ FILE *f;
+ int length;
+ void *buffer;
+
+ *bufferptr = NULL;
+
+ f = myfopen (filename, "rb");
+ if (!f)
+ return -1;
+ length = Q_filelength (f);
+ buffer = malloc (length+1);
+ ((char *)buffer)[length] = 0;
+ SafeRead (f, buffer, length);
+ fclose (f);
+
+ *bufferptr = buffer;
+ return length;
+}
+
+
+/*
+==============
+SaveFile
+==============
+*/
+void SaveFile (const char *filename, const void *buffer, int count)
+{
+ FILE *f;
+
+ f = SafeOpenWrite (filename);
+ SafeWrite (f, buffer, count);
+ fclose (f);
+}
+
+
+
+void DefaultExtension (char *path, const char *extension)
+{
+ char *src;
+//
+// if path doesnt have a .EXT, append extension
+// (extension should include the .)
+//
+ src = path + strlen(path) - 1;
+
+ while (*src != '/' && *src != '\\' && src != path)
+ {
+ if (*src == '.')
+ return; // it has an extension
+ src--;
+ }
+
+ strcat (path, extension);
+}
+
+
+void DefaultPath (char *path, const char *basepath)
+{
+ char temp[128];
+
+ if (path[0] == PATHSEPERATOR)
+ return; // absolute path location
+ strcpy (temp,path);
+ strcpy (path,basepath);
+ strcat (path,temp);
+}
+
+
+void StripFilename (char *path)
+{
+ int length;
+
+ length = strlen(path)-1;
+ while (length > 0 && path[length] != PATHSEPERATOR)
+ length--;
+ path[length] = 0;
+}
+
+void StripExtension (char *path)
+{
+ int length;
+
+ length = strlen(path)-1;
+ while (length > 0 && path[length] != '.')
+ {
+ length--;
+ if (path[length] == '/')
+ return; // no extension
+ }
+ if (length)
+ path[length] = 0;
+}
+
+
+/*
+====================
+Extract file parts
+====================
+*/
+// FIXME: should include the slash, otherwise
+// backing to an empty path will be wrong when appending a slash
+void ExtractFilePath (const char *path, char *dest)
+{
+ const char *src;
+
+ src = path + strlen(path) - 1;
+
+//
+// back up until a \ or the start
+//
+ while (src != path && *(src-1) != '\\' && *(src-1) != '/')
+ src--;
+
+ memcpy (dest, path, src-path);
+ dest[src-path] = 0;
+}
+
+void ExtractFileBase (const char *path, char *dest)
+{
+ const char *src;
+
+ src = path + strlen(path) - 1;
+
+//
+// back up until a \ or the start
+//
+ while (src != path && *(src-1) != PATHSEPERATOR)
+ src--;
+
+ while (*src && *src != '.')
+ {
+ *dest++ = *src++;
+ }
+ *dest = 0;
+}
+
+void ExtractFileExtension (const char *path, char *dest)
+{
+ const char *src;
+
+ src = path + strlen(path) - 1;
+
+//
+// back up until a . or the start
+//
+ while (src != path && *(src-1) != '.')
+ src--;
+ if (src == path)
+ {
+ *dest = 0; // no extension
+ return;
+ }
+
+ strcpy (dest,src);
+}
+
+
+/*
+==============
+ParseNum / ParseHex
+==============
+*/
+int ParseHex (const char *hex)
+{
+ const char *str;
+ int num;
+
+ num = 0;
+ str = hex;
+
+ while (*str)
+ {
+ num <<= 4;
+ if (*str >= '0' && *str <= '9')
+ num += *str-'0';
+ else if (*str >= 'a' && *str <= 'f')
+ num += 10 + *str-'a';
+ else if (*str >= 'A' && *str <= 'F')
+ num += 10 + *str-'A';
+ else
+ Error ("Bad hex number: %s",hex);
+ str++;
+ }
+
+ return num;
+}
+
+
+int ParseNum (const char *str)
+{
+ if (str[0] == '$')
+ return ParseHex (str+1);
+ if (str[0] == '0' && str[1] == 'x')
+ return ParseHex (str+2);
+ return atol (str);
+}
+
+
+
+/*
+============================================================================
+
+ BYTE ORDER FUNCTIONS
+
+============================================================================
+*/
+
+short ShortSwap (short l)
+{
+ byte b1,b2;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+
+ return (b1<<8) + b2;
+}
+
+int LongSwap (int l)
+{
+ byte b1,b2,b3,b4;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+ b3 = (l>>16)&255;
+ b4 = (l>>24)&255;
+
+ return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
+}
+
+typedef union {
+ float f;
+ unsigned int i;
+} _FloatByteUnion;
+
+float FloatSwap (const float *f) {
+ _FloatByteUnion out;
+
+ out.f = *f;
+ out.i = LongSwap(out.i);
+
+ return out.f;
+}
+
+//=======================================================
+
+
+// FIXME: byte swap?
+
+// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
+// and the initial and final xor values shown below... in other words, the
+// CCITT standard CRC used by XMODEM
+
+#define CRC_INIT_VALUE 0xffff
+#define CRC_XOR_VALUE 0x0000
+
+static unsigned short crctable[256] =
+{
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+void CRC_Init(unsigned short *crcvalue)
+{
+ *crcvalue = CRC_INIT_VALUE;
+}
+
+void CRC_ProcessByte(unsigned short *crcvalue, byte data)
+{
+ *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
+}
+
+unsigned short CRC_Value(unsigned short crcvalue)
+{
+ return crcvalue ^ CRC_XOR_VALUE;
+}
+//=============================================================================
+
+/*
+============
+CreatePath
+============
+*/
+void CreatePath (const char *path)
+{
+ const char *ofs;
+ char c;
+ char dir[1024];
+
+#ifdef _WIN32
+ int olddrive = -1;
+
+ if ( path[1] == ':' )
+ {
+ olddrive = _getdrive();
+ _chdrive( toupper( path[0] ) - 'A' + 1 );
+ }
+#endif
+
+ if (path[1] == ':')
+ path += 2;
+
+ for (ofs = path+1 ; *ofs ; ofs++)
+ {
+ c = *ofs;
+ if (c == '/' || c == '\\')
+ { // create the directory
+ memcpy( dir, path, ofs - path );
+ dir[ ofs - path ] = 0;
+ Q_mkdir( dir );
+ }
+ }
+
+#ifdef _WIN32
+ if ( olddrive != -1 )
+ {
+ _chdrive( olddrive );
+ }
+#endif
+}
+
+
+/*
+============
+QCopyFile
+
+ Used to archive source files
+============
+*/
+void QCopyFile (const char *from, const char *to)
+{
+ void *buffer;
+ int length;
+
+ length = LoadFile (from, &buffer);
+ CreatePath (to);
+ SaveFile (to, buffer, length);
+ free (buffer);
+}
diff --git a/code/tools/asm/cmdlib.h b/code/tools/asm/cmdlib.h
new file mode 100644
index 0000000..c8ee460
--- /dev/null
+++ b/code/tools/asm/cmdlib.h
@@ -0,0 +1,153 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+// cmdlib.h
+
+#ifndef __CMDLIB__
+#define __CMDLIB__
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4244) // MIPS
+#pragma warning(disable : 4136) // X86
+#pragma warning(disable : 4051) // ALPHA
+
+#pragma warning(disable : 4018) // signed/unsigned mismatch
+#pragma warning(disable : 4305) // truncate from double to float
+
+#pragma check_stack(off)
+
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+
+#ifdef _MSC_VER
+
+#pragma intrinsic( memset, memcpy )
+
+#endif
+
+#ifndef __BYTEBOOL__
+#define __BYTEBOOL__
+typedef enum { qfalse, qtrue } qboolean;
+typedef unsigned char byte;
+#endif
+
+#define MAX_OS_PATH 1024
+#define MEM_BLOCKSIZE 4096
+
+// the dec offsetof macro doesnt work very well...
+#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier)
+
+
+// set these before calling CheckParm
+extern int myargc;
+extern char **myargv;
+
+char *strupr (char *in);
+char *strlower (char *in);
+int Q_strncasecmp( const char *s1, const char *s2, int n );
+int Q_stricmp( const char *s1, const char *s2 );
+#define Q_strequal(s1,s2) (Q_stricmp(s1,s2)==0)
+void Q_getwd( char *out );
+
+int Q_filelength (FILE *f);
+int FileTime( const char *path );
+
+void Q_mkdir( const char *path );
+
+extern char qdir[1024];
+extern char gamedir[1024];
+extern char writedir[1024];
+void SetQdirFromPath( const char *path );
+char *ExpandArg( const char *path ); // from cmd line
+char *ExpandPath( const char *path ); // from scripts
+char *ExpandGamePath (const char *path);
+char *ExpandPathAndArchive( const char *path );
+
+
+double I_FloatTime( void );
+
+void Error( const char *error, ... );
+int CheckParm( const char *check );
+
+FILE *SafeOpenWrite( const char *filename );
+FILE *SafeOpenRead( const char *filename );
+void SafeRead (FILE *f, void *buffer, int count);
+void SafeWrite (FILE *f, const void *buffer, int count);
+
+int LoadFile( const char *filename, void **bufferptr );
+int LoadFileBlock( const char *filename, void **bufferptr );
+int TryLoadFile( const char *filename, void **bufferptr );
+void SaveFile( const char *filename, const void *buffer, int count );
+qboolean FileExists( const char *filename );
+
+void DefaultExtension( char *path, const char *extension );
+void DefaultPath( char *path, const char *basepath );
+void StripFilename( char *path );
+void StripExtension( char *path );
+
+void ExtractFilePath( const char *path, char *dest );
+void ExtractFileBase( const char *path, char *dest );
+void ExtractFileExtension( const char *path, char *dest );
+
+int ParseNum (const char *str);
+
+char *COM_Parse (char *data);
+
+extern char com_token[1024];
+extern qboolean com_eof;
+
+char *copystring(const char *s);
+
+
+void CRC_Init(unsigned short *crcvalue);
+void CRC_ProcessByte(unsigned short *crcvalue, byte data);
+unsigned short CRC_Value(unsigned short crcvalue);
+
+void CreatePath( const char *path );
+void QCopyFile( const char *from, const char *to );
+
+extern qboolean archive;
+extern char archivedir[1024];
+
+
+extern qboolean verbose;
+void qprintf( const char *format, ... );
+void _printf( const char *format, ... );
+
+void ExpandWildcards( int *argc, char ***argv );
+
+
+// for compression routines
+typedef struct
+{
+ void *data;
+ int count, width, height;
+} cblock_t;
+
+
+#endif
diff --git a/engine/code/tools/asm/lib.txt b/code/tools/asm/lib.txt
similarity index 100%
rename from engine/code/tools/asm/lib.txt
rename to code/tools/asm/lib.txt
diff --git a/engine/code/tools/asm/mathlib.h b/code/tools/asm/mathlib.h
similarity index 100%
rename from engine/code/tools/asm/mathlib.h
rename to code/tools/asm/mathlib.h
diff --git a/engine/code/tools/asm/notes.txt b/code/tools/asm/notes.txt
similarity index 100%
rename from engine/code/tools/asm/notes.txt
rename to code/tools/asm/notes.txt
diff --git a/engine/code/tools/asm/ops.txt b/code/tools/asm/ops.txt
similarity index 100%
rename from engine/code/tools/asm/ops.txt
rename to code/tools/asm/ops.txt
diff --git a/engine/code/tools/asm/opstrings.h b/code/tools/asm/opstrings.h
similarity index 100%
rename from engine/code/tools/asm/opstrings.h
rename to code/tools/asm/opstrings.h
diff --git a/code/tools/asm/q3asm.c b/code/tools/asm/q3asm.c
new file mode 100644
index 0000000..8b2e183
--- /dev/null
+++ b/code/tools/asm/q3asm.c
@@ -0,0 +1,1645 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "../../qcommon/q_platform.h"
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "../../qcommon/qfiles.h"
+
+/* 19079 total symbols in FI, 2002 Jan 23 */
+#define DEFAULT_HASHTABLE_SIZE 2048
+
+char outputFilename[MAX_OS_PATH];
+
+// the zero page size is just used for detecting run time faults
+#define ZERO_PAGE_SIZE 0 // 256
+
+typedef enum {
+ OP_UNDEF,
+
+ OP_IGNORE,
+
+ OP_BREAK,
+
+ OP_ENTER,
+ OP_LEAVE,
+ OP_CALL,
+ OP_PUSH,
+ OP_POP,
+
+ OP_CONST,
+ OP_LOCAL,
+
+ OP_JUMP,
+
+ //-------------------
+
+ OP_EQ,
+ OP_NE,
+
+ OP_LTI,
+ OP_LEI,
+ OP_GTI,
+ OP_GEI,
+
+ OP_LTU,
+ OP_LEU,
+ OP_GTU,
+ OP_GEU,
+
+ OP_EQF,
+ OP_NEF,
+
+ OP_LTF,
+ OP_LEF,
+ OP_GTF,
+ OP_GEF,
+
+ //-------------------
+
+ OP_LOAD1,
+ OP_LOAD2,
+ OP_LOAD4,
+ OP_STORE1,
+ OP_STORE2,
+ OP_STORE4, // *(stack[top-1]) = stack[yop
+ OP_ARG,
+ OP_BLOCK_COPY,
+
+ //-------------------
+
+ OP_SEX8,
+ OP_SEX16,
+
+ OP_NEGI,
+ OP_ADD,
+ OP_SUB,
+ OP_DIVI,
+ OP_DIVU,
+ OP_MODI,
+ OP_MODU,
+ OP_MULI,
+ OP_MULU,
+
+ OP_BAND,
+ OP_BOR,
+ OP_BXOR,
+ OP_BCOM,
+
+ OP_LSH,
+ OP_RSHI,
+ OP_RSHU,
+
+ OP_NEGF,
+ OP_ADDF,
+ OP_SUBF,
+ OP_DIVF,
+ OP_MULF,
+
+ OP_CVIF,
+ OP_CVFI
+} opcode_t;
+
+typedef struct {
+ int imageBytes; // after decompression
+ int entryPoint;
+ int stackBase;
+ int stackSize;
+} executableHeader_t;
+
+typedef enum {
+ CODESEG,
+ DATASEG, // initialized 32 bit data, will be byte swapped
+ LITSEG, // strings
+ BSSSEG, // 0 filled
+ JTRGSEG, // pseudo-segment that contains only jump table targets
+ NUM_SEGMENTS
+} segmentName_t;
+
+#define MAX_IMAGE 0x400000
+
+typedef struct {
+ byte image[MAX_IMAGE];
+ int imageUsed;
+ int segmentBase; // only valid on second pass
+} segment_t;
+
+typedef struct symbol_s {
+ struct symbol_s *next;
+ int hash;
+ segment_t *segment;
+ char *name;
+ int value;
+} symbol_t;
+
+typedef struct hashchain_s {
+ void *data;
+ struct hashchain_s *next;
+} hashchain_t;
+
+typedef struct hashtable_s {
+ int buckets;
+ hashchain_t **table;
+} hashtable_t;
+
+int symtablelen = DEFAULT_HASHTABLE_SIZE;
+hashtable_t *symtable;
+hashtable_t *optable;
+
+segment_t segment[NUM_SEGMENTS];
+segment_t *currentSegment;
+
+int passNumber;
+
+int numSymbols;
+int errorCount;
+
+typedef struct options_s {
+ qboolean verbose;
+ qboolean writeMapFile;
+ qboolean vanillaQ3Compatibility;
+} options_t;
+
+options_t options = { 0 };
+
+symbol_t *symbols;
+symbol_t *lastSymbol = 0; /* Most recent symbol defined. */
+
+
+#define MAX_ASM_FILES 256
+int numAsmFiles;
+char *asmFiles[MAX_ASM_FILES];
+char *asmFileNames[MAX_ASM_FILES];
+
+int currentFileIndex;
+char *currentFileName;
+int currentFileLine;
+
+//int stackSize = 16384;
+int stackSize = 0x10000;
+
+// we need to convert arg and ret instructions to
+// stores to the local stack frame, so we need to track the
+// characteristics of the current functions stack frame
+int currentLocals; // bytes of locals needed by this function
+int currentArgs; // bytes of largest argument list called from this function
+int currentArgOffset; // byte offset in currentArgs to store next arg, reset each call
+
+#define MAX_LINE_LENGTH 1024
+char lineBuffer[MAX_LINE_LENGTH];
+int lineParseOffset;
+char token[MAX_LINE_LENGTH];
+
+int instructionCount;
+
+typedef struct {
+ char *name;
+ int opcode;
+} sourceOps_t;
+
+sourceOps_t sourceOps[] = {
+#include "opstrings.h"
+};
+
+#define NUM_SOURCE_OPS ( sizeof( sourceOps ) / sizeof( sourceOps[0] ) )
+
+int opcodesHash[ NUM_SOURCE_OPS ];
+
+
+
+static int vreport (const char* fmt, va_list vp)
+{
+ if (options.verbose != qtrue)
+ return 0;
+ return vprintf(fmt, vp);
+}
+
+static int report (const char *fmt, ...)
+{
+ va_list va;
+ int retval;
+
+ va_start(va, fmt);
+ retval = vreport(fmt, va);
+ va_end(va);
+ return retval;
+}
+
+/* The chain-and-bucket hash table. -PH */
+
+static void hashtable_init (hashtable_t *H, int buckets)
+{
+ H->buckets = buckets;
+ H->table = calloc(H->buckets, sizeof(*(H->table)));
+ return;
+}
+
+static hashtable_t *hashtable_new (int buckets)
+{
+ hashtable_t *H;
+
+ H = malloc(sizeof(hashtable_t));
+ hashtable_init(H, buckets);
+ return H;
+}
+
+/* No destroy/destructor. No need. */
+
+static void hashtable_add (hashtable_t *H, int hashvalue, void *datum)
+{
+ hashchain_t *hc, **hb;
+
+ hashvalue = (abs(hashvalue) % H->buckets);
+ hb = &(H->table[hashvalue]);
+ if (*hb == 0)
+ {
+ /* Empty bucket. Create new one. */
+ *hb = calloc(1, sizeof(**hb));
+ hc = *hb;
+ }
+ else
+ {
+ /* Get hc to point to last node in chain. */
+ for (hc = *hb; hc && hc->next; hc = hc->next);
+ hc->next = calloc(1, sizeof(*hc));
+ hc = hc->next;
+ }
+ hc->data = datum;
+ hc->next = 0;
+ return;
+}
+
+static hashchain_t *hashtable_get (hashtable_t *H, int hashvalue)
+{
+ hashvalue = (abs(hashvalue) % H->buckets);
+ return (H->table[hashvalue]);
+}
+
+static void hashtable_stats (hashtable_t *H)
+{
+ int len, empties, longest, nodes;
+ int i;
+ float meanlen;
+ hashchain_t *hc;
+
+ report("Stats for hashtable %08X", H);
+ empties = 0;
+ longest = 0;
+ nodes = 0;
+ for (i = 0; i < H->buckets; i++)
+ {
+ if (H->table[i] == 0)
+ { empties++; continue; }
+ for (hc = H->table[i], len = 0; hc; hc = hc->next, len++);
+ if (len > longest) { longest = len; }
+ nodes += len;
+ }
+ meanlen = (float)(nodes) / (H->buckets - empties);
+#if 0
+/* Long stats display */
+ report(" Total buckets: %d\n", H->buckets);
+ report(" Total stored nodes: %d\n", nodes);
+ report(" Longest chain: %d\n", longest);
+ report(" Empty chains: %d\n", empties);
+ report(" Mean non-empty chain length: %f\n", meanlen);
+#else //0
+/* Short stats display */
+ report(", %d buckets, %d nodes", H->buckets, nodes);
+ report("\n");
+ report(" Longest chain: %d, empty chains: %d, mean non-empty: %f", longest, empties, meanlen);
+#endif //0
+ report("\n");
+}
+
+
+/* Kludge. */
+/* Check if symbol already exists. */
+/* Returns 0 if symbol does NOT already exist, non-zero otherwise. */
+static int hashtable_symbol_exists (hashtable_t *H, int hash, char *sym)
+{
+ hashchain_t *hc;
+ symbol_t *s;
+
+ hash = (abs(hash) % H->buckets);
+ hc = H->table[hash];
+ if (hc == 0)
+ {
+ /* Empty chain means this symbol has not yet been defined. */
+ return 0;
+ }
+ for (; hc; hc = hc->next)
+ {
+ s = (symbol_t*)hc->data;
+// if ((hash == s->hash) && (strcmp(sym, s->name) == 0))
+/* We _already_ know the hash is the same. That's why we're probing! */
+ if (strcmp(sym, s->name) == 0)
+ {
+ /* Symbol collisions -- symbol already exists. */
+ return 1;
+ }
+ }
+ return 0; /* Can't find collision. */
+}
+
+
+
+
+/* Comparator function for quicksorting. */
+static int symlist_cmp (const void *e1, const void *e2)
+{
+ const symbol_t *a, *b;
+
+ a = *(const symbol_t **)e1;
+ b = *(const symbol_t **)e2;
+//crumb("Symbol comparison (1) %d to (2) %d\n", a->value, b->value);
+ return ( a->value - b->value);
+}
+
+/*
+ Sort the symbols list by using QuickSort (qsort()).
+ This may take a LOT of memory (a few megabytes?), but memory is cheap these days.
+ However, qsort(3) already exists, and I'm really lazy.
+ -PH
+*/
+static void sort_symbols ()
+{
+ int i, elems;
+ symbol_t *s;
+ symbol_t **symlist;
+
+//crumb("sort_symbols: Constructing symlist array\n");
+ for (elems = 0, s = symbols; s; s = s->next, elems++) /* nop */ ;
+ symlist = malloc(elems * sizeof(symbol_t*));
+ for (i = 0, s = symbols; s; s = s->next, i++)
+ {
+ symlist[i] = s;
+ }
+//crumbf("sort_symbols: Quick-sorting %d symbols\n", elems);
+ qsort(symlist, elems, sizeof(symbol_t*), symlist_cmp);
+//crumbf("sort_symbols: Reconstructing symbols list\n");
+ s = symbols = symlist[0];
+ for (i = 1; i < elems; i++)
+ {
+ s->next = symlist[i];
+ s = s->next;
+ }
+ lastSymbol = s;
+ s->next = 0;
+//crumbf("sort_symbols: verifying..."); fflush(stdout);
+ for (i = 0, s = symbols; s; s = s->next, i++) /*nop*/ ;
+//crumbf(" %d elements\n", i);
+ free(symlist); /* d'oh. no gc. */
+}
+
+
+#ifdef _MSC_VER
+#define INT64 __int64
+#define atoi64 _atoi64
+#else
+#define INT64 long long int
+#define atoi64 atoll
+#endif
+
+/*
+ Problem:
+ BYTE values are specified as signed decimal string. A properly functional
+ atoip() will cap large signed values at 0x7FFFFFFF. Negative word values are
+ often specified as very large decimal values by lcc. Therefore, values that
+ should be between 0x7FFFFFFF and 0xFFFFFFFF come out as 0x7FFFFFFF when using
+ atoi(). Bad.
+
+ This function is one big evil hack to work around this problem.
+*/
+static int atoiNoCap (const char *s)
+{
+ INT64 l;
+ union {
+ unsigned int u;
+ signed int i;
+ } retval;
+
+ l = atoi64(s);
+ /* Now smash to signed 32 bits accordingly. */
+ if (l < 0) {
+ retval.i = (int)l;
+ } else {
+ retval.u = (unsigned int)l;
+ }
+ return retval.i; /* <- union hackage. I feel dirty with this. -PH */
+}
+
+
+
+/*
+=============
+HashString
+=============
+*/
+/* Default hash function of Kazlib 1.19, slightly modified. */
+static unsigned int HashString (const char *key)
+{
+ static unsigned long randbox[] = {
+ 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
+ 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
+ 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
+ 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
+ };
+
+ const char *str = key;
+ unsigned int acc = 0;
+
+ while (*str) {
+ acc ^= randbox[(*str + acc) & 0xf];
+ acc = (acc << 1) | (acc >> 31);
+ acc &= 0xffffffffU;
+ acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
+ acc = (acc << 2) | (acc >> 30);
+ acc &= 0xffffffffU;
+ }
+ return abs(acc);
+}
+
+
+/*
+============
+CodeError
+============
+*/
+static void CodeError( char *fmt, ... ) {
+ va_list argptr;
+
+ errorCount++;
+
+ report( "%s:%i ", currentFileName, currentFileLine );
+
+ va_start( argptr,fmt );
+ vprintf( fmt,argptr );
+ va_end( argptr );
+}
+
+/*
+============
+EmitByte
+============
+*/
+static void EmitByte( segment_t *seg, int v ) {
+ if ( seg->imageUsed >= MAX_IMAGE ) {
+ Error( "MAX_IMAGE" );
+ }
+ seg->image[ seg->imageUsed ] = v;
+ seg->imageUsed++;
+}
+
+/*
+============
+EmitInt
+============
+*/
+static void EmitInt( segment_t *seg, int v ) {
+ if ( seg->imageUsed >= MAX_IMAGE - 4) {
+ Error( "MAX_IMAGE" );
+ }
+ seg->image[ seg->imageUsed ] = v & 255;
+ seg->image[ seg->imageUsed + 1 ] = ( v >> 8 ) & 255;
+ seg->image[ seg->imageUsed + 2 ] = ( v >> 16 ) & 255;
+ seg->image[ seg->imageUsed + 3 ] = ( v >> 24 ) & 255;
+ seg->imageUsed += 4;
+}
+
+/*
+============
+DefineSymbol
+
+Symbols can only be defined on pass 0
+============
+*/
+static void DefineSymbol( char *sym, int value ) {
+ /* Hand optimization by PhaethonH */
+ symbol_t *s;
+ char expanded[MAX_LINE_LENGTH];
+ int hash;
+
+ if ( passNumber == 1 ) {
+ return;
+ }
+
+ // add the file prefix to local symbols to guarantee unique
+ if ( sym[0] == '$' ) {
+ sprintf( expanded, "%s_%i", sym, currentFileIndex );
+ sym = expanded;
+ }
+
+ hash = HashString( sym );
+
+ if (hashtable_symbol_exists(symtable, hash, sym)) {
+ CodeError( "Multiple definitions for %s\n", sym );
+ return;
+ }
+
+ s = malloc( sizeof( *s ) );
+ s->next = NULL;
+ s->name = copystring( sym );
+ s->hash = hash;
+ s->value = value;
+ s->segment = currentSegment;
+
+ hashtable_add(symtable, hash, s);
+
+/*
+ Hash table lookup already speeds up symbol lookup enormously.
+ We postpone sorting until end of pass 0.
+ Since we're not doing the insertion sort, lastSymbol should always
+ wind up pointing to the end of list.
+ This allows constant time for adding to the list.
+ -PH
+*/
+ if (symbols == 0) {
+ lastSymbol = symbols = s;
+ } else {
+ lastSymbol->next = s;
+ lastSymbol = s;
+ }
+}
+
+
+/*
+============
+LookupSymbol
+
+Symbols can only be evaluated on pass 1
+============
+*/
+static int LookupSymbol( char *sym ) {
+ symbol_t *s;
+ char expanded[MAX_LINE_LENGTH];
+ int hash;
+ hashchain_t *hc;
+
+ if ( passNumber == 0 ) {
+ return 0;
+ }
+
+ // add the file prefix to local symbols to guarantee unique
+ if ( sym[0] == '$' ) {
+ sprintf( expanded, "%s_%i", sym, currentFileIndex );
+ sym = expanded;
+ }
+
+ hash = HashString( sym );
+
+/*
+ Hand optimization by PhaethonH
+
+ Using a hash table with chain/bucket for lookups alone sped up q3asm by almost 3x for me.
+ -PH
+*/
+ for (hc = hashtable_get(symtable, hash); hc; hc = hc->next) {
+ s = (symbol_t*)hc->data; /* ugly typecasting, but it's fast! */
+ if ( (hash == s->hash) && !strcmp(sym, s->name) ) {
+ return s->segment->segmentBase + s->value;
+ }
+ }
+
+ CodeError( "error: symbol %s undefined\n", sym );
+ passNumber = 0;
+ DefineSymbol( sym, 0 ); // so more errors aren't printed
+ passNumber = 1;
+ return 0;
+}
+
+
+/*
+==============
+ExtractLine
+
+Extracts the next line from the given text block.
+If a full line isn't parsed, returns NULL
+Otherwise returns the updated parse pointer
+===============
+*/
+static char *ExtractLine( char *data ) {
+/* Goal:
+ Given a string `data', extract one text line into buffer `lineBuffer' that
+ is no longer than MAX_LINE_LENGTH characters long. Return value is
+ remainder of `data' that isn't part of `lineBuffer'.
+ -PH
+*/
+ /* Hand-optimized by PhaethonH */
+ char *p, *q;
+
+ currentFileLine++;
+
+ lineParseOffset = 0;
+ token[0] = 0;
+ *lineBuffer = 0;
+
+ p = q = data;
+ if (!*q) {
+ return NULL;
+ }
+
+ for ( ; !((*p == 0) || (*p == '\n')); p++) /* nop */ ;
+
+ if ((p - q) >= MAX_LINE_LENGTH) {
+ CodeError( "MAX_LINE_LENGTH" );
+ return data;
+ }
+
+ memcpy( lineBuffer, data, (p - data) );
+ lineBuffer[(p - data)] = 0;
+ p += (*p == '\n') ? 1 : 0; /* Skip over final newline. */
+ return p;
+}
+
+
+/*
+==============
+Parse
+
+Parse a token out of linebuffer
+==============
+*/
+static qboolean Parse( void ) {
+ /* Hand-optimized by PhaethonH */
+ const char *p, *q;
+
+ /* Because lineParseOffset is only updated just before exit, this makes this code version somewhat harder to debug under a symbolic debugger. */
+
+ *token = 0; /* Clear token. */
+
+ // skip whitespace
+ for (p = lineBuffer + lineParseOffset; *p && (*p <= ' '); p++) /* nop */ ;
+
+ // skip ; comments
+ /* die on end-of-string */
+ if ((*p == ';') || (*p == 0)) {
+ lineParseOffset = p - lineBuffer;
+ return qfalse;
+ }
+
+ q = p; /* Mark the start of token. */
+ /* Find separator first. */
+ for ( ; *p > 32; p++) /* nop */ ; /* XXX: unsafe assumptions. */
+ /* *p now sits on separator. Mangle other values accordingly. */
+ strncpy(token, q, p - q);
+ token[p - q] = 0;
+
+ lineParseOffset = p - lineBuffer;
+
+ return qtrue;
+}
+
+
+/*
+==============
+ParseValue
+==============
+*/
+static int ParseValue( void ) {
+ Parse();
+ return atoiNoCap( token );
+}
+
+
+/*
+==============
+ParseExpression
+==============
+*/
+static int ParseExpression(void) {
+ /* Hand optimization, PhaethonH */
+ int i, j;
+ char sym[MAX_LINE_LENGTH];
+ int v;
+
+ /* Skip over a leading minus. */
+ for ( i = ((token[0] == '-') ? 1 : 0) ; i < MAX_LINE_LENGTH ; i++ ) {
+ if ( token[i] == '+' || token[i] == '-' || token[i] == 0 ) {
+ break;
+ }
+ }
+
+ memcpy( sym, token, i );
+ sym[i] = 0;
+
+ switch (*sym) { /* Resolve depending on first character. */
+/* Optimizing compilers can convert cases into "calculated jumps". I think these are faster. -PH */
+ case '-':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ v = atoiNoCap(sym);
+ break;
+ default:
+ v = LookupSymbol(sym);
+ break;
+ }
+
+ // parse add / subtract offsets
+ while ( token[i] != 0 ) {
+ for ( j = i + 1 ; j < MAX_LINE_LENGTH ; j++ ) {
+ if ( token[j] == '+' || token[j] == '-' || token[j] == 0 ) {
+ break;
+ }
+ }
+
+ memcpy( sym, token+i+1, j-i-1 );
+ sym[j-i-1] = 0;
+
+ switch (token[i]) {
+ case '+':
+ v += atoiNoCap(sym);
+ break;
+ case '-':
+ v -= atoiNoCap(sym);
+ break;
+ }
+
+ i = j;
+ }
+
+ return v;
+}
+
+
+/*
+==============
+HackToSegment
+
+BIG HACK: I want to put all 32 bit values in the data
+segment so they can be byte swapped, and all char data in the lit
+segment, but switch jump tables are emited in the lit segment and
+initialized strng variables are put in the data segment.
+
+I can change segments here, but I also need to fixup the
+label that was just defined
+
+Note that the lit segment is read-write in the VM, so strings
+aren't read only as in some architectures.
+==============
+*/
+static void HackToSegment( segmentName_t seg ) {
+ if ( currentSegment == &segment[seg] ) {
+ return;
+ }
+
+ currentSegment = &segment[seg];
+ if ( passNumber == 0 ) {
+ lastSymbol->segment = currentSegment;
+ lastSymbol->value = currentSegment->imageUsed;
+ }
+}
+
+
+
+
+
+
+
+//#define STAT(L) report("STAT " L "\n");
+#define STAT(L)
+#define ASM(O) int TryAssemble##O ()
+
+
+/*
+ These clauses were moved out from AssembleLine() to allow reordering of if's.
+ An optimizing compiler should reconstruct these back into inline code.
+ -PH
+*/
+
+ // call instructions reset currentArgOffset
+ASM(CALL)
+{
+ if ( !strncmp( token, "CALL", 4 ) ) {
+STAT("CALL");
+ EmitByte( &segment[CODESEG], OP_CALL );
+ instructionCount++;
+ currentArgOffset = 0;
+ return 1;
+ }
+ return 0;
+}
+
+ // arg is converted to a reversed store
+ASM(ARG)
+{
+ if ( !strncmp( token, "ARG", 3 ) ) {
+STAT("ARG");
+ EmitByte( &segment[CODESEG], OP_ARG );
+ instructionCount++;
+ if ( 8 + currentArgOffset >= 256 ) {
+ CodeError( "currentArgOffset >= 256" );
+ return 1;
+ }
+ EmitByte( &segment[CODESEG], 8 + currentArgOffset );
+ currentArgOffset += 4;
+ return 1;
+ }
+ return 0;
+}
+
+ // ret just leaves something on the op stack
+ASM(RET)
+{
+ if ( !strncmp( token, "RET", 3 ) ) {
+STAT("RET");
+ EmitByte( &segment[CODESEG], OP_LEAVE );
+ instructionCount++;
+ EmitInt( &segment[CODESEG], 8 + currentLocals + currentArgs );
+ return 1;
+ }
+ return 0;
+}
+
+ // pop is needed to discard the return value of
+ // a function
+ASM(POP)
+{
+ if ( !strncmp( token, "pop", 3 ) ) {
+STAT("POP");
+ EmitByte( &segment[CODESEG], OP_POP );
+ instructionCount++;
+ return 1;
+ }
+ return 0;
+}
+
+ // address of a parameter is converted to OP_LOCAL
+ASM(ADDRF)
+{
+ int v;
+ if ( !strncmp( token, "ADDRF", 5 ) ) {
+STAT("ADDRF");
+ instructionCount++;
+ Parse();
+ v = ParseExpression();
+ v = 16 + currentArgs + currentLocals + v;
+ EmitByte( &segment[CODESEG], OP_LOCAL );
+ EmitInt( &segment[CODESEG], v );
+ return 1;
+ }
+ return 0;
+}
+
+ // address of a local is converted to OP_LOCAL
+ASM(ADDRL)
+{
+ int v;
+ if ( !strncmp( token, "ADDRL", 5 ) ) {
+STAT("ADDRL");
+ instructionCount++;
+ Parse();
+ v = ParseExpression();
+ v = 8 + currentArgs + v;
+ EmitByte( &segment[CODESEG], OP_LOCAL );
+ EmitInt( &segment[CODESEG], v );
+ return 1;
+ }
+ return 0;
+}
+
+ASM(PROC)
+{
+ char name[1024];
+ if ( !strcmp( token, "proc" ) ) {
+STAT("PROC");
+ Parse(); // function name
+ strcpy( name, token );
+
+ DefineSymbol( token, instructionCount ); // segment[CODESEG].imageUsed );
+
+ currentLocals = ParseValue(); // locals
+ currentLocals = ( currentLocals + 3 ) & ~3;
+ currentArgs = ParseValue(); // arg marshalling
+ currentArgs = ( currentArgs + 3 ) & ~3;
+
+ if ( 8 + currentLocals + currentArgs >= 32767 ) {
+ CodeError( "Locals > 32k in %s\n", name );
+ }
+
+ instructionCount++;
+ EmitByte( &segment[CODESEG], OP_ENTER );
+ EmitInt( &segment[CODESEG], 8 + currentLocals + currentArgs );
+ return 1;
+ }
+ return 0;
+}
+
+
+ASM(ENDPROC)
+{
+ int v, v2;
+ if ( !strcmp( token, "endproc" ) ) {
+STAT("ENDPROC");
+ Parse(); // skip the function name
+ v = ParseValue(); // locals
+ v2 = ParseValue(); // arg marshalling
+
+ // all functions must leave something on the opstack
+ instructionCount++;
+ EmitByte( &segment[CODESEG], OP_PUSH );
+
+ instructionCount++;
+ EmitByte( &segment[CODESEG], OP_LEAVE );
+ EmitInt( &segment[CODESEG], 8 + currentLocals + currentArgs );
+
+ return 1;
+ }
+ return 0;
+}
+
+
+ASM(ADDRESS)
+{
+ int v;
+ if ( !strcmp( token, "address" ) ) {
+STAT("ADDRESS");
+ Parse();
+ v = ParseExpression();
+
+/* Addresses are 32 bits wide, and therefore go into data segment. */
+ HackToSegment( DATASEG );
+ EmitInt( currentSegment, v );
+ if( passNumber == 1 && token[ 0 ] == '$' ) // crude test for labels
+ EmitInt( &segment[ JTRGSEG ], v );
+ return 1;
+ }
+ return 0;
+}
+
+ASM(EXPORT)
+{
+ if ( !strcmp( token, "export" ) ) {
+STAT("EXPORT");
+ return 1;
+ }
+ return 0;
+}
+
+ASM(IMPORT)
+{
+ if ( !strcmp( token, "import" ) ) {
+STAT("IMPORT");
+ return 1;
+ }
+ return 0;
+}
+
+ASM(CODE)
+{
+ if ( !strcmp( token, "code" ) ) {
+STAT("CODE");
+ currentSegment = &segment[CODESEG];
+ return 1;
+ }
+ return 0;
+}
+
+ASM(BSS)
+{
+ if ( !strcmp( token, "bss" ) ) {
+STAT("BSS");
+ currentSegment = &segment[BSSSEG];
+ return 1;
+ }
+ return 0;
+}
+
+ASM(DATA)
+{
+ if ( !strcmp( token, "data" ) ) {
+STAT("DATA");
+ currentSegment = &segment[DATASEG];
+ return 1;
+ }
+ return 0;
+}
+
+ASM(LIT)
+{
+ if ( !strcmp( token, "lit" ) ) {
+STAT("LIT");
+ currentSegment = &segment[LITSEG];
+ return 1;
+ }
+ return 0;
+}
+
+ASM(LINE)
+{
+ if ( !strcmp( token, "line" ) ) {
+STAT("LINE");
+ return 1;
+ }
+ return 0;
+}
+
+ASM(FILE)
+{
+ if ( !strcmp( token, "file" ) ) {
+STAT("FILE");
+ return 1;
+ }
+ return 0;
+}
+
+ASM(EQU)
+{
+ char name[1024];
+ if ( !strcmp( token, "equ" ) ) {
+STAT("EQU");
+ Parse();
+ strcpy( name, token );
+ Parse();
+ DefineSymbol( name, atoiNoCap(token) );
+ return 1;
+ }
+ return 0;
+}
+
+ASM(ALIGN)
+{
+ int v;
+ if ( !strcmp( token, "align" ) ) {
+STAT("ALIGN");
+ v = ParseValue();
+ currentSegment->imageUsed = (currentSegment->imageUsed + v - 1 ) & ~( v - 1 );
+ return 1;
+ }
+ return 0;
+}
+
+ASM(SKIP)
+{
+ int v;
+ if ( !strcmp( token, "skip" ) ) {
+STAT("SKIP");
+ v = ParseValue();
+ currentSegment->imageUsed += v;
+ return 1;
+ }
+ return 0;
+}
+
+ASM(BYTE)
+{
+ int i, v, v2;
+ if ( !strcmp( token, "byte" ) ) {
+STAT("BYTE");
+ v = ParseValue();
+ v2 = ParseValue();
+
+ if ( v == 1 ) {
+/* Character (1-byte) values go into lit(eral) segment. */
+ HackToSegment( LITSEG );
+ } else if ( v == 4 ) {
+/* 32-bit (4-byte) values go into data segment. */
+ HackToSegment( DATASEG );
+ } else if ( v == 2 ) {
+/* and 16-bit (2-byte) values will cause q3asm to barf. */
+ CodeError( "16 bit initialized data not supported" );
+ }
+
+ // emit little endien
+ for ( i = 0 ; i < v ; i++ ) {
+ EmitByte( currentSegment, (v2 & 0xFF) ); /* paranoid ANDing -PH */
+ v2 >>= 8;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+ // code labels are emited as instruction counts, not byte offsets,
+ // because the physical size of the code will change with
+ // different run time compilers and we want to minimize the
+ // size of the required translation table
+ASM(LABEL)
+{
+ if ( !strncmp( token, "LABEL", 5 ) ) {
+STAT("LABEL");
+ Parse();
+ if ( currentSegment == &segment[CODESEG] ) {
+ DefineSymbol( token, instructionCount );
+ } else {
+ DefineSymbol( token, currentSegment->imageUsed );
+ }
+ return 1;
+ }
+ return 0;
+}
+
+
+
+/*
+==============
+AssembleLine
+
+==============
+*/
+static void AssembleLine( void ) {
+ hashchain_t *hc;
+ sourceOps_t *op;
+ int i;
+ int hash;
+
+ Parse();
+ if ( !token[0] ) {
+ return;
+ }
+
+ hash = HashString( token );
+
+/*
+ Opcode search using hash table.
+ Since the opcodes stays mostly fixed, this may benefit even more from a tree.
+ Always with the tree :)
+ -PH
+*/
+ for (hc = hashtable_get(optable, hash); hc; hc = hc->next) {
+ op = (sourceOps_t*)(hc->data);
+ i = op - sourceOps;
+ if ((hash == opcodesHash[i]) && (!strcmp(token, op->name))) {
+ int opcode;
+ int expression;
+
+ if ( op->opcode == OP_UNDEF ) {
+ CodeError( "Undefined opcode: %s\n", token );
+ }
+ if ( op->opcode == OP_IGNORE ) {
+ return; // we ignore most conversions
+ }
+
+ // sign extensions need to check next parm
+ opcode = op->opcode;
+ if ( opcode == OP_SEX8 ) {
+ Parse();
+ if ( token[0] == '1' ) {
+ opcode = OP_SEX8;
+ } else if ( token[0] == '2' ) {
+ opcode = OP_SEX16;
+ } else {
+ CodeError( "Bad sign extension: %s\n", token );
+ return;
+ }
+ }
+
+ // check for expression
+ Parse();
+ if ( token[0] && op->opcode != OP_CVIF
+ && op->opcode != OP_CVFI ) {
+ expression = ParseExpression();
+
+ // code like this can generate non-dword block copies:
+ // auto char buf[2] = " ";
+ // we are just going to round up. This might conceivably
+ // be incorrect if other initialized chars follow.
+ if ( opcode == OP_BLOCK_COPY ) {
+ expression = ( expression + 3 ) & ~3;
+ }
+
+ EmitByte( &segment[CODESEG], opcode );
+ EmitInt( &segment[CODESEG], expression );
+ } else {
+ EmitByte( &segment[CODESEG], opcode );
+ }
+
+ instructionCount++;
+ return;
+ }
+ }
+
+/* This falls through if an assembly opcode is not found. -PH */
+
+/* The following should be sorted in sequence of statistical frequency, most frequent first. -PH */
+/*
+Empirical frequency statistics from FI 2001.01.23:
+ 109892 STAT ADDRL
+ 72188 STAT BYTE
+ 51150 STAT LINE
+ 50906 STAT ARG
+ 43704 STAT IMPORT
+ 34902 STAT LABEL
+ 32066 STAT ADDRF
+ 23704 STAT CALL
+ 7720 STAT POP
+ 7256 STAT RET
+ 5198 STAT ALIGN
+ 3292 STAT EXPORT
+ 2878 STAT PROC
+ 2878 STAT ENDPROC
+ 2812 STAT ADDRESS
+ 738 STAT SKIP
+ 374 STAT EQU
+ 280 STAT CODE
+ 176 STAT LIT
+ 102 STAT FILE
+ 100 STAT BSS
+ 68 STAT DATA
+
+ -PH
+*/
+
+#undef ASM
+#define ASM(O) if (TryAssemble##O ()) return;
+
+ ASM(ADDRL)
+ ASM(BYTE)
+ ASM(LINE)
+ ASM(ARG)
+ ASM(IMPORT)
+ ASM(LABEL)
+ ASM(ADDRF)
+ ASM(CALL)
+ ASM(POP)
+ ASM(RET)
+ ASM(ALIGN)
+ ASM(EXPORT)
+ ASM(PROC)
+ ASM(ENDPROC)
+ ASM(ADDRESS)
+ ASM(SKIP)
+ ASM(EQU)
+ ASM(CODE)
+ ASM(LIT)
+ ASM(FILE)
+ ASM(BSS)
+ ASM(DATA)
+
+ CodeError( "Unknown token: %s\n", token );
+}
+
+/*
+==============
+InitTables
+==============
+*/
+void InitTables( void ) {
+ int i;
+
+ symtable = hashtable_new(symtablelen);
+ optable = hashtable_new(100); /* There's hardly 100 opcodes anyway. */
+
+ for ( i = 0 ; i < NUM_SOURCE_OPS ; i++ ) {
+ opcodesHash[i] = HashString( sourceOps[i].name );
+ hashtable_add(optable, opcodesHash[i], sourceOps + i);
+ }
+}
+
+
+/*
+==============
+WriteMapFile
+==============
+*/
+static void WriteMapFile( void ) {
+ FILE *f;
+ symbol_t *s;
+ char imageName[MAX_OS_PATH];
+ int seg;
+
+ strcpy( imageName, outputFilename );
+ StripExtension( imageName );
+ strcat( imageName, ".map" );
+
+ report( "Writing %s...\n", imageName );
+
+ f = SafeOpenWrite( imageName );
+ for ( seg = CODESEG ; seg <= BSSSEG ; seg++ ) {
+ for ( s = symbols ; s ; s = s->next ) {
+ if ( s->name[0] == '$' ) {
+ continue; // skip locals
+ }
+ if ( &segment[seg] != s->segment ) {
+ continue;
+ }
+ fprintf( f, "%i %8x %s\n", seg, s->value, s->name );
+ }
+ }
+ fclose( f );
+}
+
+/*
+===============
+WriteVmFile
+===============
+*/
+static void WriteVmFile( void ) {
+ char imageName[MAX_OS_PATH];
+ vmHeader_t header;
+ FILE *f;
+ int headerSize;
+
+ report( "%i total errors\n", errorCount );
+
+ strcpy( imageName, outputFilename );
+ StripExtension( imageName );
+ strcat( imageName, ".qvm" );
+
+ remove( imageName );
+
+ report( "code segment: %7i\n", segment[CODESEG].imageUsed );
+ report( "data segment: %7i\n", segment[DATASEG].imageUsed );
+ report( "lit segment: %7i\n", segment[LITSEG].imageUsed );
+ report( "bss segment: %7i\n", segment[BSSSEG].imageUsed );
+ report( "instruction count: %i\n", instructionCount );
+
+ if ( errorCount != 0 ) {
+ report( "Not writing a file due to errors\n" );
+ return;
+ }
+
+ if( !options.vanillaQ3Compatibility ) {
+ header.vmMagic = VM_MAGIC_VER2;
+ headerSize = sizeof( header );
+ } else {
+ header.vmMagic = VM_MAGIC;
+
+ // Don't write the VM_MAGIC_VER2 bits when maintaining 1.32b compatibility.
+ // (I know this isn't strictly correct due to padding, but then platforms
+ // that pad wouldn't be able to write a correct header anyway). Note: if
+ // vmHeader_t changes, this needs to be adjusted too.
+ headerSize = sizeof( header ) - sizeof( header.jtrgLength );
+ }
+
+ header.instructionCount = instructionCount;
+ header.codeOffset = headerSize;
+ header.codeLength = segment[CODESEG].imageUsed;
+ header.dataOffset = header.codeOffset + segment[CODESEG].imageUsed;
+ header.dataLength = segment[DATASEG].imageUsed;
+ header.litLength = segment[LITSEG].imageUsed;
+ header.bssLength = segment[BSSSEG].imageUsed;
+ header.jtrgLength = segment[JTRGSEG].imageUsed;
+
+ report( "Writing to %s\n", imageName );
+
+#ifdef Q3_BIG_ENDIAN
+ {
+ int i;
+
+ // byte swap the header
+ for ( i = 0 ; i < sizeof( vmHeader_t ) / 4 ; i++ ) {
+ ((int *)&header)[i] = LittleLong( ((int *)&header)[i] );
+ }
+ }
+#endif
+
+ CreatePath( imageName );
+ f = SafeOpenWrite( imageName );
+ SafeWrite( f, &header, headerSize );
+ SafeWrite( f, &segment[CODESEG].image, segment[CODESEG].imageUsed );
+ SafeWrite( f, &segment[DATASEG].image, segment[DATASEG].imageUsed );
+ SafeWrite( f, &segment[LITSEG].image, segment[LITSEG].imageUsed );
+
+ if( !options.vanillaQ3Compatibility ) {
+ SafeWrite( f, &segment[JTRGSEG].image, segment[JTRGSEG].imageUsed );
+ }
+
+ fclose( f );
+}
+
+/*
+===============
+Assemble
+===============
+*/
+static void Assemble( void ) {
+ int i;
+ char filename[MAX_OS_PATH];
+ char *ptr;
+
+ report( "outputFilename: %s\n", outputFilename );
+
+ for ( i = 0 ; i < numAsmFiles ; i++ ) {
+ strcpy( filename, asmFileNames[ i ] );
+ DefaultExtension( filename, ".asm" );
+ LoadFile( filename, (void **)&asmFiles[i] );
+ }
+
+ // assemble
+ for ( passNumber = 0 ; passNumber < 2 ; passNumber++ ) {
+ segment[LITSEG].segmentBase = segment[DATASEG].imageUsed;
+ segment[BSSSEG].segmentBase = segment[LITSEG].segmentBase + segment[LITSEG].imageUsed;
+ segment[JTRGSEG].segmentBase = segment[BSSSEG].segmentBase + segment[BSSSEG].imageUsed;
+ for ( i = 0 ; i < NUM_SEGMENTS ; i++ ) {
+ segment[i].imageUsed = 0;
+ }
+ segment[DATASEG].imageUsed = 4; // skip the 0 byte, so NULL pointers are fixed up properly
+ instructionCount = 0;
+
+ for ( i = 0 ; i < numAsmFiles ; i++ ) {
+ currentFileIndex = i;
+ currentFileName = asmFileNames[ i ];
+ currentFileLine = 0;
+ report("pass %i: %s\n", passNumber, currentFileName );
+ fflush( NULL );
+ ptr = asmFiles[i];
+ while ( ptr ) {
+ ptr = ExtractLine( ptr );
+ AssembleLine();
+ }
+ }
+
+ // align all segment
+ for ( i = 0 ; i < NUM_SEGMENTS ; i++ ) {
+ segment[i].imageUsed = (segment[i].imageUsed + 3) & ~3;
+ }
+ if (passNumber == 0) {
+ sort_symbols();
+ }
+ }
+
+ // reserve the stack in bss
+ DefineSymbol( "_stackStart", segment[BSSSEG].imageUsed );
+ segment[BSSSEG].imageUsed += stackSize;
+ DefineSymbol( "_stackEnd", segment[BSSSEG].imageUsed );
+
+ // write the image
+ WriteVmFile();
+
+ // write the map file even if there were errors
+ if( options.writeMapFile ) {
+ WriteMapFile();
+ }
+}
+
+
+/*
+=============
+ParseOptionFile
+
+=============
+*/
+static void ParseOptionFile( const char *filename ) {
+ char expanded[MAX_OS_PATH];
+ char *text, *text_p;
+
+ strcpy( expanded, filename );
+ DefaultExtension( expanded, ".q3asm" );
+ LoadFile( expanded, (void **)&text );
+ if ( !text ) {
+ return;
+ }
+
+ text_p = text;
+
+ while( ( text_p = COM_Parse( text_p ) ) != 0 ) {
+ if ( !strcmp( com_token, "-o" ) ) {
+ // allow output override in option file
+ text_p = COM_Parse( text_p );
+ if ( text_p ) {
+ strcpy( outputFilename, com_token );
+ }
+ continue;
+ }
+
+ asmFileNames[ numAsmFiles ] = copystring( com_token );
+ numAsmFiles++;
+ }
+}
+
+static void ShowHelp( char *argv0 ) {
+ Error("Usage: %s [OPTION]... [FILES]...\n\
+Assemble LCC bytecode assembly to Q3VM bytecode.\n\
+\n\
+ -o OUTPUT Write assembled output to file OUTPUT.qvm\n\
+ -f LISTFILE Read options and list of files to assemble from LISTFILE.q3asm\n\
+ -b BUCKETS Set symbol hash table to BUCKETS buckets\n\
+ -v Verbose compilation report\n\
+ -vq3 Produce a qvm file compatible with Q3 1.32b\n\
+ -h --help -? Show this help\n\
+", argv0);
+}
+
+/*
+==============
+main
+==============
+*/
+int main( int argc, char **argv ) {
+ int i;
+ double start, end;
+
+// _chdir( "/quake3/jccode/cgame/lccout" ); // hack for vc profiler
+
+ if ( argc < 2 ) {
+ ShowHelp( argv[0] );
+ }
+
+ start = I_FloatTime ();
+
+ // default filename is "q3asm"
+ strcpy( outputFilename, "q3asm" );
+ numAsmFiles = 0;
+
+ for ( i = 1 ; i < argc ; i++ ) {
+ if ( argv[i][0] != '-' ) {
+ break;
+ }
+ if( !strcmp( argv[ i ], "-h" ) ||
+ !strcmp( argv[ i ], "--help" ) ||
+ !strcmp( argv[ i ], "-?") ) {
+ ShowHelp( argv[0] );
+ }
+
+ if ( !strcmp( argv[i], "-o" ) ) {
+ if ( i == argc - 1 ) {
+ Error( "-o must preceed a filename" );
+ }
+/* Timbo of Tremulous pointed out -o not working; stock ID q3asm folded in the change. Yay. */
+ strcpy( outputFilename, argv[ i+1 ] );
+ i++;
+ continue;
+ }
+
+ if ( !strcmp( argv[i], "-f" ) ) {
+ if ( i == argc - 1 ) {
+ Error( "-f must preceed a filename" );
+ }
+ ParseOptionFile( argv[ i+1 ] );
+ i++;
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-b")) {
+ if (i == argc - 1) {
+ Error("-b requires an argument");
+ }
+ i++;
+ symtablelen = atoiNoCap(argv[i]);
+ continue;
+ }
+
+ if( !strcmp( argv[ i ], "-v" ) ) {
+/* Verbosity option added by Timbo, 2002.09.14.
+By default (no -v option), q3asm remains silent except for critical errors.
+Verbosity turns on all messages, error or not.
+Motivation: not wanting to scrollback for pages to find asm error.
+*/
+ options.verbose = qtrue;
+ continue;
+ }
+
+ if( !strcmp( argv[ i ], "-m" ) ) {
+ options.writeMapFile = qtrue;
+ continue;
+ }
+
+ if( !strcmp( argv[ i ], "-vq3" ) ) {
+ options.vanillaQ3Compatibility = qtrue;
+ continue;
+ }
+
+ Error( "Unknown option: %s", argv[i] );
+ }
+
+ // the rest of the command line args are asm files
+ for ( ; i < argc ; i++ ) {
+ asmFileNames[ numAsmFiles ] = copystring( argv[ i ] );
+ numAsmFiles++;
+ }
+ // In some case it Segfault without this check
+ if ( numAsmFiles == 0 ) {
+ Error( "No file to assemble\n" );
+ }
+
+ InitTables();
+ Assemble();
+
+ {
+ symbol_t *s;
+
+ for ( i = 0, s = symbols ; s ; s = s->next, i++ ) /* nop */ ;
+
+ if (options.verbose)
+ {
+ report("%d symbols defined\n", i);
+ hashtable_stats(symtable);
+ hashtable_stats(optable);
+ }
+ }
+
+ end = I_FloatTime ();
+ report ("%5.0f seconds elapsed\n", end-start);
+
+ return errorCount;
+}
+
diff --git a/code/tools/lcc/COPYRIGHT b/code/tools/lcc/COPYRIGHT
new file mode 100644
index 0000000..961a48f
--- /dev/null
+++ b/code/tools/lcc/COPYRIGHT
@@ -0,0 +1,61 @@
+The authors of this software are Christopher W. Fraser and
+David R. Hanson.
+
+Copyright (c) 1991,1992,1993,1994,1995,1996,1997,1998 by AT&T,
+Christopher W. Fraser, and David R. Hanson. All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose, subject to the provisions described below, without fee is
+hereby granted, provided that this entire notice is included in all
+copies of any software that is or includes a copy or modification of
+this software and in all copies of the supporting documentation for
+such software.
+
+THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
+REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+
+
+lcc is not public-domain software, shareware, and it is not protected
+by a `copyleft' agreement, like the code from the Free Software
+Foundation.
+
+lcc is available free for your personal research and instructional use
+under the `fair use' provisions of the copyright law. You may, however,
+redistribute lcc in whole or in part provided you acknowledge its
+source and include this CPYRIGHT file. You may, for example, include
+the distribution in a CDROM of free software, provided you charge only
+for the media, or mirror the distribution files at your site.
+
+You may not sell lcc or any product derived from it in which it is a
+significant part of the value of the product. Using the lcc front end
+to build a C syntax checker is an example of this kind of product.
+
+You may use parts of lcc in products as long as you charge for only
+those components that are entirely your own and you acknowledge the use
+of lcc clearly in all product documentation and distribution media. You
+must state clearly that your product uses or is based on parts of lcc
+and that lcc is available free of charge. You must also request that
+bug reports on your product be reported to you. Using the lcc front
+end to build a C compiler for the Motorola 88000 chip and charging for
+and distributing only the 88000 code generator is an example of this
+kind of product.
+
+Using parts of lcc in other products is more problematic. For example,
+using parts of lcc in a C++ compiler could save substantial time and
+effort and therefore contribute significantly to the profitability of
+the product. This kind of use, or any use where others stand to make a
+profit from what is primarily our work, requires a license agreement
+with Addison-Wesley. Per-copy and unlimited use licenses are
+available; for more information, contact
+
+ J. Carter Shanklin
+ Addison Wesley Longman, Inc.
+ 2725 Sand Hill Rd.
+ Menlo Park, CA 94025
+ 650/854-0300 x2478 FAX: 650/614-2930 jcs at awl.com
+-----
+Chris Fraser / cwfraser at microsoft.com
+David Hanson / drh at microsoft.com
+$Revision: 145 $ $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $
diff --git a/code/tools/lcc/LOG b/code/tools/lcc/LOG
new file mode 100644
index 0000000..dd23f62
--- /dev/null
+++ b/code/tools/lcc/LOG
@@ -0,0 +1,91 @@
+From lcc 4.0 to 4.1:
+
+Changes:
+
+See doc/4.html for changes in the code-generation interface.
+
+Warns about constants that are too large, eg, short x = 70000;
+
+Warns about expressions that have no effect.
+
+Unsigned shorts are now used for wide-character constants, and
+wchar_t is a typedef for unsigned short.
+
+More assertions in gen.c to confirm that the register allocator is
+configured correctly; ie, that the various masks, wildcards,
+clobbers, and targets are internally consistent. Full checking
+appears impractical, but there's still more than than there was
+before.
+
+On the SPARC, lcc now emits .type and .size directives
+unconditionally.
+
+On the x86, constants are now emitted into the text segment.
+
+If the environment variable "LCCDIR" is defined, it gives the directory
+that contains the preprocessor, the compiler proper, and the
+lcc-specific libraries.
+
+Under Windows, lcc searches the directories named in the environment
+variable "include" for header files.
+
+Errors fixed:
+
+Erroneously complained about unknown sizes for some const fields, eg,
+typedef struct foo ref; struct foo { const ref *q; int a; };
+f(ref *p, int i) { return p->q[i].a; }
+
+-A -A erroneously complained about static main's that didn't conform
+to the ANSI-mandated "int main(void)" or "int main(int, char **)".
+
+Silently generated incorrect code for a structure copy with a
+post-incremented target, eg,
+struct { int x; } data = {1}, copy[2], *q = copy;
+main() { *q++ = data; }
+
+Generated incorrect values in some expressions with constant pointers.
+
+Silently truncated string literals longer than 4095 characters.
+
+Failed to emit debugging information for uninitialized globals.
+
+Failed to diagnose missing sizes in some multi-dimensioned array
+declarators, eg, extern int x[][10]; int x[5][];
+
+Silently emitted incorrect sizes and initalizations for some
+incomplete multi-dimensioned arrays involving pointers and whose size
+is determined by the number of initializers.
+
+Set only the x.name field for some back-end symbols (eg, wildcards),
+and the uninitialized name field crashed some debugging output.
+
+uses() failed to check the register *set* as well as the register
+mask. There's no known bug demo, but a wildcard set might be
+contrived that would need the test.
+
+Crashed with -b on some conditional expressions involving calls, eg,
+int p; void g(void) { p ? f() : 1; }
+
+On the MIPS, sometimes generated an incorrect frame size and thus a
+crash when floating-point registers were saved.
+
+On the SPARC, erroneously reused a register variable as a temporary
+when the variable is compiler-generated.
+
+On the SPARC with -b, emitted incorrect code for returning structs.
+
+On the x86, conversion from float to int rounded instead of truncated
+with the default floating-point mode.
+
+On the x86, eliminate rtargets for kids after the first (see p. 419).
+
+On the x86, substitute reg for freg, in order to use the common reg
+rules. Needed only for debugging output, since we're not using any
+float regs as regs at this time.
+
+On the x86, "double f(); main(){f();}" wasn't popping the FP register stack.
+
+On the x86, ECX was saved by the callee, when it should have been
+saved by the caller.
+
+$Id: LOG 145 2001-10-17 21:53:10Z timo $
diff --git a/code/tools/lcc/README b/code/tools/lcc/README
new file mode 100644
index 0000000..4ba4d3f
--- /dev/null
+++ b/code/tools/lcc/README
@@ -0,0 +1,21 @@
+This hierarchy is the distribution for lcc version 4.1.
+
+lcc version 3.x is described in the book "A Retargetable C Compiler:
+Design and Implementation" (Addison-Wesley, 1995, ISBN 0-8053-1670-1).
+There are significant differences between 3.x and 4.x, most notably in
+the intermediate code. doc/4.html summarizes the differences.
+
+VERSION 4.1 IS INCOMPATIBLE WITH EARLIER VERSIONS OF LCC. DO NOT
+UNLOAD THIS DISTRIBUTION ON TOP OF A 3.X DISTRIBUTION.
+
+LOG describes the changes since the last release.
+
+CPYRIGHT describes the conditions under you can use, copy, modify, and
+distribute lcc or works derived from lcc.
+
+doc/install.html is an HTML file that gives a complete description of
+the distribution and installation instructions.
+
+Chris Fraser / cwfraser at microsoft.com
+David Hanson / drh at microsoft.com
+$Revision: 145 $ $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $
diff --git a/code/tools/lcc/README.id b/code/tools/lcc/README.id
new file mode 100644
index 0000000..6611a37
--- /dev/null
+++ b/code/tools/lcc/README.id
@@ -0,0 +1,3 @@
+2001-10-31 Timothee Besset <ttimo at idsoftware.com>
+updated from the $/source/lcc code
+modified for portability and use with >= 1.31 mod source release
diff --git a/code/tools/lcc/cpp/cpp.c b/code/tools/lcc/cpp/cpp.c
new file mode 100644
index 0000000..1fcffbc
--- /dev/null
+++ b/code/tools/lcc/cpp/cpp.c
@@ -0,0 +1,327 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include "cpp.h"
+
+char rcsid[] = "cpp.c - faked rcsid";
+
+#define OUTS 16384
+char outbuf[OUTS];
+char *outp = outbuf;
+Source *cursource;
+int nerrs;
+struct token nltoken = { NL, 0, 0, 0, 1, (uchar*)"\n" };
+char *curtime;
+int incdepth;
+int ifdepth;
+int ifsatisfied[NIF];
+int skipping;
+
+
+int
+main(int argc, char **argv)
+{
+ Tokenrow tr;
+ time_t t;
+ char ebuf[BUFSIZ];
+
+ setbuf(stderr, ebuf);
+ t = time(NULL);
+ curtime = ctime(&t);
+ maketokenrow(3, &tr);
+ expandlex();
+ setup(argc, argv);
+ fixlex();
+ iniths();
+ genline();
+ process(&tr);
+ flushout();
+ fflush(stderr);
+ exit(nerrs > 0);
+ return 0;
+}
+
+void
+process(Tokenrow *trp)
+{
+ int anymacros = 0;
+
+ for (;;) {
+ if (trp->tp >= trp->lp) {
+ trp->tp = trp->lp = trp->bp;
+ outp = outbuf;
+ anymacros |= gettokens(trp, 1);
+ trp->tp = trp->bp;
+ }
+ if (trp->tp->type == END) {
+ if (--incdepth>=0) {
+ if (cursource->ifdepth)
+ error(ERROR,
+ "Unterminated conditional in #include");
+ unsetsource();
+ cursource->line += cursource->lineinc;
+ trp->tp = trp->lp;
+ genline();
+ continue;
+ }
+ if (ifdepth)
+ error(ERROR, "Unterminated #if/#ifdef/#ifndef");
+ break;
+ }
+ if (trp->tp->type==SHARP) {
+ trp->tp += 1;
+ control(trp);
+ } else if (!skipping && anymacros)
+ expandrow(trp, NULL);
+ if (skipping)
+ setempty(trp);
+ puttokens(trp);
+ anymacros = 0;
+ cursource->line += cursource->lineinc;
+ if (cursource->lineinc>1) {
+ genline();
+ }
+ }
+}
+
+void
+control(Tokenrow *trp)
+{
+ Nlist *np;
+ Token *tp;
+
+ tp = trp->tp;
+ if (tp->type!=NAME) {
+ if (tp->type==NUMBER)
+ goto kline;
+ if (tp->type != NL)
+ error(ERROR, "Unidentifiable control line");
+ return; /* else empty line */
+ }
+ if ((np = lookup(tp, 0))==NULL || ((np->flag&ISKW)==0 && !skipping)) {
+ error(WARNING, "Unknown preprocessor control %t", tp);
+ return;
+ }
+ if (skipping) {
+ switch (np->val) {
+ case KENDIF:
+ if (--ifdepth<skipping)
+ skipping = 0;
+ --cursource->ifdepth;
+ setempty(trp);
+ return;
+
+ case KIFDEF:
+ case KIFNDEF:
+ case KIF:
+ if (++ifdepth >= NIF)
+ error(FATAL, "#if too deeply nested");
+ ++cursource->ifdepth;
+ return;
+
+ case KELIF:
+ case KELSE:
+ if (ifdepth<=skipping)
+ break;
+ return;
+
+ default:
+ return;
+ }
+ }
+ switch (np->val) {
+ case KDEFINE:
+ dodefine(trp);
+ break;
+
+ case KUNDEF:
+ tp += 1;
+ if (tp->type!=NAME || trp->lp - trp->bp != 4) {
+ error(ERROR, "Syntax error in #undef");
+ break;
+ }
+ if ((np = lookup(tp, 0)) != NULL)
+ np->flag &= ~ISDEFINED;
+ break;
+
+ case KPRAGMA:
+ return;
+
+ case KIFDEF:
+ case KIFNDEF:
+ case KIF:
+ if (++ifdepth >= NIF)
+ error(FATAL, "#if too deeply nested");
+ ++cursource->ifdepth;
+ ifsatisfied[ifdepth] = 0;
+ if (eval(trp, np->val))
+ ifsatisfied[ifdepth] = 1;
+ else
+ skipping = ifdepth;
+ break;
+
+ case KELIF:
+ if (ifdepth==0) {
+ error(ERROR, "#elif with no #if");
+ return;
+ }
+ if (ifsatisfied[ifdepth]==2)
+ error(ERROR, "#elif after #else");
+ if (eval(trp, np->val)) {
+ if (ifsatisfied[ifdepth])
+ skipping = ifdepth;
+ else {
+ skipping = 0;
+ ifsatisfied[ifdepth] = 1;
+ }
+ } else
+ skipping = ifdepth;
+ break;
+
+ case KELSE:
+ if (ifdepth==0 || cursource->ifdepth==0) {
+ error(ERROR, "#else with no #if");
+ return;
+ }
+ if (ifsatisfied[ifdepth]==2)
+ error(ERROR, "#else after #else");
+ if (trp->lp - trp->bp != 3)
+ error(ERROR, "Syntax error in #else");
+ skipping = ifsatisfied[ifdepth]? ifdepth: 0;
+ ifsatisfied[ifdepth] = 2;
+ break;
+
+ case KENDIF:
+ if (ifdepth==0 || cursource->ifdepth==0) {
+ error(ERROR, "#endif with no #if");
+ return;
+ }
+ --ifdepth;
+ --cursource->ifdepth;
+ if (trp->lp - trp->bp != 3)
+ error(WARNING, "Syntax error in #endif");
+ break;
+
+ case KWARNING:
+ trp->tp = tp+1;
+ error(WARNING, "#warning directive: %r", trp);
+ break;
+
+ case KERROR:
+ trp->tp = tp+1;
+ error(ERROR, "#error directive: %r", trp);
+ break;
+
+ case KLINE:
+ trp->tp = tp+1;
+ expandrow(trp, "<line>");
+ tp = trp->bp+2;
+ kline:
+ if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp
+ || ((tp+3==trp->lp && ((tp+1)->type!=STRING))||*(tp+1)->t=='L')){
+ error(ERROR, "Syntax error in #line");
+ return;
+ }
+ cursource->line = atol((char*)tp->t)-1;
+ if (cursource->line<0 || cursource->line>=32768)
+ error(WARNING, "#line specifies number out of range");
+ tp = tp+1;
+ if (tp+1<trp->lp)
+ cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0);
+ return;
+
+ case KDEFINED:
+ error(ERROR, "Bad syntax for control line");
+ break;
+
+ case KINCLUDE:
+ doinclude(trp);
+ trp->lp = trp->bp;
+ return;
+
+ case KEVAL:
+ eval(trp, np->val);
+ break;
+
+ default:
+ error(ERROR, "Preprocessor control `%t' not yet implemented", tp);
+ break;
+ }
+ setempty(trp);
+ return;
+}
+
+void *
+domalloc(int size)
+{
+ void *p = malloc(size);
+
+ if (p==NULL)
+ error(FATAL, "Out of memory from malloc");
+ return p;
+}
+
+void
+dofree(void *p)
+{
+ free(p);
+}
+
+void
+error(enum errtype type, char *string, ...)
+{
+ va_list ap;
+ char *cp, *ep;
+ Token *tp;
+ Tokenrow *trp;
+ Source *s;
+ int i;
+
+ fprintf(stderr, "cpp: ");
+ for (s=cursource; s; s=s->next)
+ if (*s->filename)
+ fprintf(stderr, "%s:%d ", s->filename, s->line);
+ va_start(ap, string);
+ for (ep=string; *ep; ep++) {
+ if (*ep=='%') {
+ switch (*++ep) {
+
+ case 's':
+ cp = va_arg(ap, char *);
+ fprintf(stderr, "%s", cp);
+ break;
+ case 'd':
+ i = va_arg(ap, int);
+ fprintf(stderr, "%d", i);
+ break;
+ case 't':
+ tp = va_arg(ap, Token *);
+ fprintf(stderr, "%.*s", tp->len, tp->t);
+ break;
+
+ case 'r':
+ trp = va_arg(ap, Tokenrow *);
+ for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) {
+ if (tp>trp->tp && tp->wslen)
+ fputc(' ', stderr);
+ fprintf(stderr, "%.*s", tp->len, tp->t);
+ }
+ break;
+
+ default:
+ fputc(*ep, stderr);
+ break;
+ }
+ } else
+ fputc(*ep, stderr);
+ }
+ va_end(ap);
+ fputc('\n', stderr);
+ if (type==FATAL)
+ exit(1);
+ if (type!=WARNING)
+ nerrs = 1;
+ fflush(stderr);
+}
diff --git a/code/tools/lcc/cpp/cpp.h b/code/tools/lcc/cpp/cpp.h
new file mode 100644
index 0000000..87871d9
--- /dev/null
+++ b/code/tools/lcc/cpp/cpp.h
@@ -0,0 +1,166 @@
+#define INS 32768 /* input buffer */
+#define OBS 4096 /* outbut buffer */
+#define NARG 32 /* Max number arguments to a macro */
+#define NINCLUDE 32 /* Max number of include directories (-I) */
+#define NIF 32 /* depth of nesting of #if */
+#ifndef EOF
+#define EOF (-1)
+#endif
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef __alpha
+typedef unsigned char uchar;
+#endif
+
+enum toktype { END, UNCLASS, NAME, NUMBER, STRING, CCON, NL, WS, DSHARP,
+ EQ, NEQ, LEQ, GEQ, LSH, RSH, LAND, LOR, PPLUS, MMINUS,
+ ARROW, SBRA, SKET, LP, RP, DOT, AND, STAR, PLUS, MINUS,
+ TILDE, NOT, SLASH, PCT, LT, GT, CIRC, OR, QUEST,
+ COLON, ASGN, COMMA, SHARP, SEMIC, CBRA, CKET,
+ ASPLUS, ASMINUS, ASSTAR, ASSLASH, ASPCT, ASCIRC, ASLSH,
+ ASRSH, ASOR, ASAND, ELLIPS,
+ DSHARP1, NAME1, DEFINED, UMINUS };
+
+enum kwtype { KIF, KIFDEF, KIFNDEF, KELIF, KELSE, KENDIF, KINCLUDE, KDEFINE,
+ KUNDEF, KLINE, KWARNING, KERROR, KPRAGMA, KDEFINED,
+ KLINENO, KFILE, KDATE, KTIME, KSTDC, KEVAL };
+
+#define ISDEFINED 01 /* has #defined value */
+#define ISKW 02 /* is PP keyword */
+#define ISUNCHANGE 04 /* can't be #defined in PP */
+#define ISMAC 010 /* builtin macro, e.g. __LINE__ */
+
+#define EOB 0xFE /* sentinel for end of input buffer */
+#define EOFC 0xFD /* sentinel for end of input file */
+#define XPWS 1 /* token flag: white space to assure token sep. */
+
+typedef struct token {
+ unsigned char type;
+ unsigned char flag;
+ unsigned short hideset;
+ unsigned int wslen;
+ unsigned int len;
+ uchar *t;
+} Token;
+
+typedef struct tokenrow {
+ Token *tp; /* current one to scan */
+ Token *bp; /* base (allocated value) */
+ Token *lp; /* last+1 token used */
+ int max; /* number allocated */
+} Tokenrow;
+
+typedef struct source {
+ char *filename; /* name of file of the source */
+ int line; /* current line number */
+ int lineinc; /* adjustment for \\n lines */
+ uchar *inb; /* input buffer */
+ uchar *inp; /* input pointer */
+ uchar *inl; /* end of input */
+ int fd; /* input source */
+ int ifdepth; /* conditional nesting in include */
+ struct source *next; /* stack for #include */
+} Source;
+
+typedef struct nlist {
+ struct nlist *next;
+ uchar *name;
+ int len;
+ Tokenrow *vp; /* value as macro */
+ Tokenrow *ap; /* list of argument names, if any */
+ char val; /* value as preprocessor name */
+ char flag; /* is defined, is pp name */
+} Nlist;
+
+typedef struct includelist {
+ char deleted;
+ char always;
+ char *file;
+} Includelist;
+
+#define new(t) (t *)domalloc(sizeof(t))
+#define quicklook(a,b) (namebit[(a)&077] & (1<<((b)&037)))
+#define quickset(a,b) namebit[(a)&077] |= (1<<((b)&037))
+extern unsigned long namebit[077+1];
+
+enum errtype { WARNING, ERROR, FATAL };
+
+void expandlex(void);
+void fixlex(void);
+void setup(int, char **);
+int gettokens(Tokenrow *, int);
+int comparetokens(Tokenrow *, Tokenrow *);
+Source *setsource(char *, int, char *);
+void unsetsource(void);
+void puttokens(Tokenrow *);
+void process(Tokenrow *);
+void *domalloc(int);
+void dofree(void *);
+void error(enum errtype, char *, ...);
+void flushout(void);
+int fillbuf(Source *);
+int trigraph(Source *);
+int foldline(Source *);
+Nlist *lookup(Token *, int);
+void control(Tokenrow *);
+void dodefine(Tokenrow *);
+void doadefine(Tokenrow *, int);
+void doinclude(Tokenrow *);
+void appendDirToIncludeList( char *dir );
+void doif(Tokenrow *, enum kwtype);
+void expand(Tokenrow *, Nlist *);
+void builtin(Tokenrow *, int);
+int gatherargs(Tokenrow *, Tokenrow **, int *);
+void substargs(Nlist *, Tokenrow *, Tokenrow **);
+void expandrow(Tokenrow *, char *);
+void maketokenrow(int, Tokenrow *);
+Tokenrow *copytokenrow(Tokenrow *, Tokenrow *);
+Token *growtokenrow(Tokenrow *);
+Tokenrow *normtokenrow(Tokenrow *);
+void adjustrow(Tokenrow *, int);
+void movetokenrow(Tokenrow *, Tokenrow *);
+void insertrow(Tokenrow *, int, Tokenrow *);
+void peektokens(Tokenrow *, char *);
+void doconcat(Tokenrow *);
+Tokenrow *stringify(Tokenrow *);
+int lookuparg(Nlist *, Token *);
+long eval(Tokenrow *, int);
+void genline(void);
+void setempty(Tokenrow *);
+void makespace(Tokenrow *);
+char *outnum(char *, int);
+int digit(int);
+uchar *newstring(uchar *, int, int);
+int checkhideset(int, Nlist *);
+void prhideset(int);
+int newhideset(int, Nlist *);
+int unionhideset(int, int);
+void iniths(void);
+void setobjname(char *);
+#define rowlen(tokrow) ((tokrow)->lp - (tokrow)->bp)
+
+char *basepath( char *fname );
+
+extern char *outp;
+extern Token nltoken;
+extern Source *cursource;
+extern char *curtime;
+extern int incdepth;
+extern int ifdepth;
+extern int ifsatisfied[NIF];
+extern int Mflag;
+extern int skipping;
+extern int verbose;
+extern int Cplusplus;
+extern Nlist *kwdefined;
+extern Includelist includelist[NINCLUDE];
+extern char wd[];
+
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
diff --git a/code/tools/lcc/cpp/eval.c b/code/tools/lcc/cpp/eval.c
new file mode 100644
index 0000000..95a9e11
--- /dev/null
+++ b/code/tools/lcc/cpp/eval.c
@@ -0,0 +1,524 @@
+#include <stdlib.h>
+#include <string.h>
+#include "cpp.h"
+
+#define NSTAK 32
+#define SGN 0
+#define UNS 1
+#define UND 2
+
+#define UNSMARK 0x1000
+
+struct value {
+ long val;
+ int type;
+};
+
+/* conversion types */
+#define RELAT 1
+#define ARITH 2
+#define LOGIC 3
+#define SPCL 4
+#define SHIFT 5
+#define UNARY 6
+
+/* operator priority, arity, and conversion type, indexed by tokentype */
+struct pri {
+ char pri;
+ char arity;
+ char ctype;
+} priority[] = {
+ { 0, 0, 0 }, /* END */
+ { 0, 0, 0 }, /* UNCLASS */
+ { 0, 0, 0 }, /* NAME */
+ { 0, 0, 0 }, /* NUMBER */
+ { 0, 0, 0 }, /* STRING */
+ { 0, 0, 0 }, /* CCON */
+ { 0, 0, 0 }, /* NL */
+ { 0, 0, 0 }, /* WS */
+ { 0, 0, 0 }, /* DSHARP */
+ { 11, 2, RELAT }, /* EQ */
+ { 11, 2, RELAT }, /* NEQ */
+ { 12, 2, RELAT }, /* LEQ */
+ { 12, 2, RELAT }, /* GEQ */
+ { 13, 2, SHIFT }, /* LSH */
+ { 13, 2, SHIFT }, /* RSH */
+ { 7, 2, LOGIC }, /* LAND */
+ { 6, 2, LOGIC }, /* LOR */
+ { 0, 0, 0 }, /* PPLUS */
+ { 0, 0, 0 }, /* MMINUS */
+ { 0, 0, 0 }, /* ARROW */
+ { 0, 0, 0 }, /* SBRA */
+ { 0, 0, 0 }, /* SKET */
+ { 3, 0, 0 }, /* LP */
+ { 3, 0, 0 }, /* RP */
+ { 0, 0, 0 }, /* DOT */
+ { 10, 2, ARITH }, /* AND */
+ { 15, 2, ARITH }, /* STAR */
+ { 14, 2, ARITH }, /* PLUS */
+ { 14, 2, ARITH }, /* MINUS */
+ { 16, 1, UNARY }, /* TILDE */
+ { 16, 1, UNARY }, /* NOT */
+ { 15, 2, ARITH }, /* SLASH */
+ { 15, 2, ARITH }, /* PCT */
+ { 12, 2, RELAT }, /* LT */
+ { 12, 2, RELAT }, /* GT */
+ { 9, 2, ARITH }, /* CIRC */
+ { 8, 2, ARITH }, /* OR */
+ { 5, 2, SPCL }, /* QUEST */
+ { 5, 2, SPCL }, /* COLON */
+ { 0, 0, 0 }, /* ASGN */
+ { 4, 2, 0 }, /* COMMA */
+ { 0, 0, 0 }, /* SHARP */
+ { 0, 0, 0 }, /* SEMIC */
+ { 0, 0, 0 }, /* CBRA */
+ { 0, 0, 0 }, /* CKET */
+ { 0, 0, 0 }, /* ASPLUS */
+ { 0, 0, 0 }, /* ASMINUS */
+ { 0, 0, 0 }, /* ASSTAR */
+ { 0, 0, 0 }, /* ASSLASH */
+ { 0, 0, 0 }, /* ASPCT */
+ { 0, 0, 0 }, /* ASCIRC */
+ { 0, 0, 0 }, /* ASLSH */
+ { 0, 0, 0 }, /* ASRSH */
+ { 0, 0, 0 }, /* ASOR */
+ { 0, 0, 0 }, /* ASAND */
+ { 0, 0, 0 }, /* ELLIPS */
+ { 0, 0, 0 }, /* DSHARP1 */
+ { 0, 0, 0 }, /* NAME1 */
+ { 16, 1, UNARY }, /* DEFINED */
+ { 16, 0, UNARY }, /* UMINUS */
+};
+
+int evalop(struct pri);
+struct value tokval(Token *);
+struct value vals[NSTAK], *vp;
+enum toktype ops[NSTAK], *op;
+
+/*
+ * Evaluate an #if #elif #ifdef #ifndef line. trp->tp points to the keyword.
+ */
+long
+eval(Tokenrow *trp, int kw)
+{
+ Token *tp;
+ Nlist *np;
+ int ntok, rand;
+
+ trp->tp++;
+ if (kw==KIFDEF || kw==KIFNDEF) {
+ if (trp->lp - trp->bp != 4 || trp->tp->type!=NAME) {
+ error(ERROR, "Syntax error in #ifdef/#ifndef");
+ return 0;
+ }
+ np = lookup(trp->tp, 0);
+ return (kw==KIFDEF) == (np && np->flag&(ISDEFINED|ISMAC));
+ }
+ ntok = trp->tp - trp->bp;
+ kwdefined->val = KDEFINED; /* activate special meaning of defined */
+ expandrow(trp, "<if>");
+ kwdefined->val = NAME;
+ vp = vals;
+ op = ops;
+ *op++ = END;
+ for (rand=0, tp = trp->bp+ntok; tp < trp->lp; tp++) {
+ switch(tp->type) {
+ case WS:
+ case NL:
+ continue;
+
+ /* nilary */
+ case NAME:
+ case NAME1:
+ case NUMBER:
+ case CCON:
+ case STRING:
+ if (rand)
+ goto syntax;
+ *vp++ = tokval(tp);
+ rand = 1;
+ continue;
+
+ /* unary */
+ case DEFINED:
+ case TILDE:
+ case NOT:
+ if (rand)
+ goto syntax;
+ *op++ = tp->type;
+ continue;
+
+ /* unary-binary */
+ case PLUS: case MINUS: case STAR: case AND:
+ if (rand==0) {
+ if (tp->type==MINUS)
+ *op++ = UMINUS;
+ if (tp->type==STAR || tp->type==AND) {
+ error(ERROR, "Illegal operator * or & in #if/#elsif");
+ return 0;
+ }
+ continue;
+ }
+ /* flow through */
+
+ /* plain binary */
+ case EQ: case NEQ: case LEQ: case GEQ: case LSH: case RSH:
+ case LAND: case LOR: case SLASH: case PCT:
+ case LT: case GT: case CIRC: case OR: case QUEST:
+ case COLON: case COMMA:
+ if (rand==0)
+ goto syntax;
+ if (evalop(priority[tp->type])!=0)
+ return 0;
+ *op++ = tp->type;
+ rand = 0;
+ continue;
+
+ case LP:
+ if (rand)
+ goto syntax;
+ *op++ = LP;
+ continue;
+
+ case RP:
+ if (!rand)
+ goto syntax;
+ if (evalop(priority[RP])!=0)
+ return 0;
+ if (op<=ops || op[-1]!=LP) {
+ goto syntax;
+ }
+ op--;
+ continue;
+
+ default:
+ error(ERROR,"Bad operator (%t) in #if/#elsif", tp);
+ return 0;
+ }
+ }
+ if (rand==0)
+ goto syntax;
+ if (evalop(priority[END])!=0)
+ return 0;
+ if (op!=&ops[1] || vp!=&vals[1]) {
+ error(ERROR, "Botch in #if/#elsif");
+ return 0;
+ }
+ if (vals[0].type==UND)
+ error(ERROR, "Undefined expression value");
+ return vals[0].val;
+syntax:
+ error(ERROR, "Syntax error in #if/#elsif");
+ return 0;
+}
+
+int
+evalop(struct pri pri)
+{
+ struct value v1, v2;
+ long rv1, rv2;
+ int rtype, oper;
+
+ /* prevent compiler whining. */
+ v1.val = v2.val = 0;
+ v1.type = v2.type = 0;
+
+ rv2=0;
+ rtype=0;
+ while (pri.pri < priority[op[-1]].pri) {
+ oper = *--op;
+ if (priority[oper].arity==2) {
+ v2 = *--vp;
+ rv2 = v2.val;
+ }
+ v1 = *--vp;
+ rv1 = v1.val;
+/*lint -e574 -e644 */
+ switch (priority[oper].ctype) {
+ case 0:
+ default:
+ error(WARNING, "Syntax error in #if/#endif");
+ return 1;
+ case ARITH:
+ case RELAT:
+ if (v1.type==UNS || v2.type==UNS)
+ rtype = UNS;
+ else
+ rtype = SGN;
+ if (v1.type==UND || v2.type==UND)
+ rtype = UND;
+ if (priority[oper].ctype==RELAT && rtype==UNS) {
+ oper |= UNSMARK;
+ rtype = SGN;
+ }
+ break;
+ case SHIFT:
+ if (v1.type==UND || v2.type==UND)
+ rtype = UND;
+ else
+ rtype = v1.type;
+ if (rtype==UNS)
+ oper |= UNSMARK;
+ break;
+ case UNARY:
+ rtype = v1.type;
+ break;
+ case LOGIC:
+ case SPCL:
+ break;
+ }
+ switch (oper) {
+ case EQ: case EQ|UNSMARK:
+ rv1 = rv1==rv2; break;
+ case NEQ: case NEQ|UNSMARK:
+ rv1 = rv1!=rv2; break;
+ case LEQ:
+ rv1 = rv1<=rv2; break;
+ case GEQ:
+ rv1 = rv1>=rv2; break;
+ case LT:
+ rv1 = rv1<rv2; break;
+ case GT:
+ rv1 = rv1>rv2; break;
+ case LEQ|UNSMARK:
+ rv1 = (unsigned long)rv1<=rv2; break;
+ case GEQ|UNSMARK:
+ rv1 = (unsigned long)rv1>=rv2; break;
+ case LT|UNSMARK:
+ rv1 = (unsigned long)rv1<rv2; break;
+ case GT|UNSMARK:
+ rv1 = (unsigned long)rv1>rv2; break;
+ case LSH:
+ rv1 <<= rv2; break;
+ case LSH|UNSMARK:
+ rv1 = (unsigned long)rv1<<rv2; break;
+ case RSH:
+ rv1 >>= rv2; break;
+ case RSH|UNSMARK:
+ rv1 = (unsigned long)rv1>>rv2; break;
+ case LAND:
+ rtype = UND;
+ if (v1.type==UND)
+ break;
+ if (rv1!=0) {
+ if (v2.type==UND)
+ break;
+ rv1 = rv2!=0;
+ } else
+ rv1 = 0;
+ rtype = SGN;
+ break;
+ case LOR:
+ rtype = UND;
+ if (v1.type==UND)
+ break;
+ if (rv1==0) {
+ if (v2.type==UND)
+ break;
+ rv1 = rv2!=0;
+ } else
+ rv1 = 1;
+ rtype = SGN;
+ break;
+ case AND:
+ rv1 &= rv2; break;
+ case STAR:
+ rv1 *= rv2; break;
+ case PLUS:
+ rv1 += rv2; break;
+ case MINUS:
+ rv1 -= rv2; break;
+ case UMINUS:
+ if (v1.type==UND)
+ rtype = UND;
+ rv1 = -rv1; break;
+ case OR:
+ rv1 |= rv2; break;
+ case CIRC:
+ rv1 ^= rv2; break;
+ case TILDE:
+ rv1 = ~rv1; break;
+ case NOT:
+ rv1 = !rv1; if (rtype!=UND) rtype = SGN; break;
+ case SLASH:
+ if (rv2==0) {
+ rtype = UND;
+ break;
+ }
+ if (rtype==UNS)
+ rv1 /= (unsigned long)rv2;
+ else
+ rv1 /= rv2;
+ break;
+ case PCT:
+ if (rv2==0) {
+ rtype = UND;
+ break;
+ }
+ if (rtype==UNS)
+ rv1 %= (unsigned long)rv2;
+ else
+ rv1 %= rv2;
+ break;
+ case COLON:
+ if (op[-1] != QUEST)
+ error(ERROR, "Bad ?: in #if/endif");
+ else {
+ op--;
+ if ((--vp)->val==0)
+ v1 = v2;
+ rtype = v1.type;
+ rv1 = v1.val;
+ }
+ break;
+ case DEFINED:
+ break;
+ default:
+ error(ERROR, "Eval botch (unknown operator)");
+ return 1;
+ }
+/*lint +e574 +e644 */
+ v1.val = rv1;
+ v1.type = rtype;
+ *vp++ = v1;
+ }
+ return 0;
+}
+
+struct value
+tokval(Token *tp)
+{
+ struct value v;
+ Nlist *np;
+ int i, base, c;
+ unsigned long n;
+ uchar *p;
+
+ v.type = SGN;
+ v.val = 0;
+ switch (tp->type) {
+
+ case NAME:
+ v.val = 0;
+ break;
+
+ case NAME1:
+ if ((np = lookup(tp, 0)) != NULL && np->flag&(ISDEFINED|ISMAC))
+ v.val = 1;
+ break;
+
+ case NUMBER:
+ n = 0;
+ base = 10;
+ p = tp->t;
+ c = p[tp->len];
+ p[tp->len] = '\0';
+ if (*p=='0') {
+ base = 8;
+ if (p[1]=='x' || p[1]=='X') {
+ base = 16;
+ p++;
+ }
+ p++;
+ }
+ for (;; p++) {
+ if ((i = digit(*p)) < 0)
+ break;
+ if (i>=base)
+ error(WARNING,
+ "Bad digit in number %t", tp);
+ n *= base;
+ n += i;
+ }
+ if (n>=0x80000000 && base!=10)
+ v.type = UNS;
+ for (; *p; p++) {
+ if (*p=='u' || *p=='U')
+ v.type = UNS;
+ else if (*p=='l' || *p=='L')
+ ;
+ else {
+ error(ERROR,
+ "Bad number %t in #if/#elsif", tp);
+ break;
+ }
+ }
+ v.val = n;
+ tp->t[tp->len] = c;
+ break;
+
+ case CCON:
+ n = 0;
+ p = tp->t;
+ if (*p=='L') {
+ p += 1;
+ error(WARNING, "Wide char constant value undefined");
+ }
+ p += 1;
+ if (*p=='\\') {
+ p += 1;
+ if ((i = digit(*p))>=0 && i<=7) {
+ n = i;
+ p += 1;
+ if ((i = digit(*p))>=0 && i<=7) {
+ p += 1;
+ n <<= 3;
+ n += i;
+ if ((i = digit(*p))>=0 && i<=7) {
+ p += 1;
+ n <<= 3;
+ n += i;
+ }
+ }
+ } else if (*p=='x') {
+ p += 1;
+ while ((i = digit(*p))>=0 && i<=15) {
+ p += 1;
+ n <<= 4;
+ n += i;
+ }
+ } else {
+ static char cvcon[]
+ = "b\bf\fn\nr\rt\tv\v''\"\"??\\\\";
+ for (i=0; i<sizeof(cvcon); i+=2) {
+ if (*p == cvcon[i]) {
+ n = cvcon[i+1];
+ break;
+ }
+ }
+ p += 1;
+ if (i>=sizeof(cvcon))
+ error(WARNING,
+ "Undefined escape in character constant");
+ }
+ } else if (*p=='\'')
+ error(ERROR, "Empty character constant");
+ else
+ n = *p++;
+ if (*p!='\'')
+ error(WARNING, "Multibyte character constant undefined");
+ else if (n>127)
+ error(WARNING, "Character constant taken as not signed");
+ v.val = n;
+ break;
+
+ case STRING:
+ error(ERROR, "String in #if/#elsif");
+ break;
+ }
+ return v;
+}
+
+int
+digit(int i)
+{
+ if ('0'<=i && i<='9')
+ i -= '0';
+ else if ('a'<=i && i<='f')
+ i -= 'a'-10;
+ else if ('A'<=i && i<='F')
+ i -= 'A'-10;
+ else
+ i = -1;
+ return i;
+}
diff --git a/code/tools/lcc/cpp/getopt.c b/code/tools/lcc/cpp/getopt.c
new file mode 100644
index 0000000..c4d1af7
--- /dev/null
+++ b/code/tools/lcc/cpp/getopt.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <string.h>
+#define EPR fprintf(stderr,
+#define ERR(str, chr) if(opterr){EPR "%s%c\n", str, chr);}
+int opterr = 1;
+int optind = 1;
+int optopt;
+char *optarg;
+
+int
+lcc_getopt (int argc, char *const argv[], const char *opts)
+{
+ static int sp = 1;
+ int c;
+ char *cp;
+
+ if (sp == 1) {
+ if (optind >= argc ||
+ argv[optind][0] != '-' || argv[optind][1] == '\0')
+ return -1;
+ else if (strcmp(argv[optind], "--") == 0) {
+ optind++;
+ return -1;
+ }
+ }
+ optopt = c = argv[optind][sp];
+ if (c == ':' || (cp=strchr(opts, c)) == 0) {
+ ERR (": illegal option -- ", c);
+ if (argv[optind][++sp] == '\0') {
+ optind++;
+ sp = 1;
+ }
+ return '?';
+ }
+ if (*++cp == ':') {
+ if (argv[optind][sp+1] != '\0')
+ optarg = &argv[optind++][sp+1];
+ else if (++optind >= argc) {
+ ERR (": option requires an argument -- ", c);
+ sp = 1;
+ return '?';
+ } else
+ optarg = argv[optind++];
+ sp = 1;
+ } else {
+ if (argv[optind][++sp] == '\0') {
+ sp = 1;
+ optind++;
+ }
+ optarg = 0;
+ }
+ return c;
+}
diff --git a/code/tools/lcc/cpp/hideset.c b/code/tools/lcc/cpp/hideset.c
new file mode 100644
index 0000000..bd2540d
--- /dev/null
+++ b/code/tools/lcc/cpp/hideset.c
@@ -0,0 +1,112 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpp.h"
+
+/*
+ * A hideset is a null-terminated array of Nlist pointers.
+ * They are referred to by indices in the hidesets array.
+ * Hideset 0 is empty.
+ */
+
+#define HSSIZ 32
+typedef Nlist **Hideset;
+Hideset *hidesets;
+int nhidesets = 0;
+int maxhidesets = 3;
+int inserths(Hideset, Hideset, Nlist *);
+
+/*
+ * Test for membership in a hideset
+ */
+int
+checkhideset(int hs, Nlist *np)
+{
+ Hideset hsp;
+
+ if (hs>=nhidesets)
+ abort();
+ for (hsp = hidesets[hs]; *hsp; hsp++) {
+ if (*hsp == np)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Return the (possibly new) hideset obtained by adding np to hs.
+ */
+int
+newhideset(int hs, Nlist *np)
+{
+ int i, len;
+ Nlist *nhs[HSSIZ+3];
+ Hideset hs1, hs2;
+
+ len = inserths(nhs, hidesets[hs], np);
+ for (i=0; i<nhidesets; i++) {
+ for (hs1=nhs, hs2=hidesets[i]; *hs1==*hs2; hs1++, hs2++)
+ if (*hs1 == NULL)
+ return i;
+ }
+ if (len>=HSSIZ)
+ return hs;
+ if (nhidesets >= maxhidesets) {
+ maxhidesets = 3*maxhidesets/2+1;
+ hidesets = (Hideset *)realloc(hidesets, (sizeof (Hideset *))*maxhidesets);
+ if (hidesets == NULL)
+ error(FATAL, "Out of memory from realloc");
+ }
+ hs1 = (Hideset)domalloc(len*sizeof(Hideset));
+ memmove(hs1, nhs, len*sizeof(Hideset));
+ hidesets[nhidesets] = hs1;
+ return nhidesets++;
+}
+
+int
+inserths(Hideset dhs, Hideset shs, Nlist *np)
+{
+ Hideset odhs = dhs;
+
+ while (*shs && *shs < np)
+ *dhs++ = *shs++;
+ if (*shs != np)
+ *dhs++ = np;
+ do {
+ *dhs++ = *shs;
+ } while (*shs++);
+ return dhs - odhs;
+}
+
+/*
+ * Hideset union
+ */
+int
+unionhideset(int hs1, int hs2)
+{
+ Hideset hp;
+
+ for (hp = hidesets[hs2]; *hp; hp++)
+ hs1 = newhideset(hs1, *hp);
+ return hs1;
+}
+
+void
+iniths(void)
+{
+ hidesets = (Hideset *)domalloc(maxhidesets*sizeof(Hideset *));
+ hidesets[0] = (Hideset)domalloc(sizeof(Hideset));
+ *hidesets[0] = NULL;
+ nhidesets++;
+}
+
+void
+prhideset(int hs)
+{
+ Hideset np;
+
+ for (np = hidesets[hs]; *np; np++) {
+ fprintf(stderr, (char*)(*np)->name, (*np)->len);
+ fprintf(stderr, " ");
+ }
+}
diff --git a/code/tools/lcc/cpp/include.c b/code/tools/lcc/cpp/include.c
new file mode 100644
index 0000000..1bb8847
--- /dev/null
+++ b/code/tools/lcc/cpp/include.c
@@ -0,0 +1,154 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpp.h"
+
+Includelist includelist[NINCLUDE];
+
+extern char *objname;
+
+void appendDirToIncludeList( char *dir )
+{
+ int i;
+ char *fqdir;
+
+ fqdir = (char *)newstring( (uchar *)includelist[NINCLUDE-1].file, 256, 0 );
+ strcat( fqdir, "/" );
+ strcat( fqdir, dir );
+
+ //avoid adding it more than once
+ for (i=NINCLUDE-2; i>=0; i--) {
+ if (includelist[i].file &&
+ !strcmp (includelist[i].file, fqdir)) {
+ return;
+ }
+ }
+
+ for (i=NINCLUDE-2; i>=0; i--) {
+ if (includelist[i].file==NULL) {
+ includelist[i].always = 1;
+ includelist[i].file = fqdir;
+ break;
+ }
+ }
+ if (i<0)
+ error(FATAL, "Too many -I directives");
+}
+
+void
+doinclude(Tokenrow *trp)
+{
+ char fname[256], iname[256];
+ Includelist *ip;
+ int angled, len, fd, i;
+
+ trp->tp += 1;
+ if (trp->tp>=trp->lp)
+ goto syntax;
+ if (trp->tp->type!=STRING && trp->tp->type!=LT) {
+ len = trp->tp - trp->bp;
+ expandrow(trp, "<include>");
+ trp->tp = trp->bp+len;
+ }
+ if (trp->tp->type==STRING) {
+ len = trp->tp->len-2;
+ if (len > sizeof(fname) - 1)
+ len = sizeof(fname) - 1;
+ strncpy(fname, (char*)trp->tp->t+1, len);
+ angled = 0;
+ } else if (trp->tp->type==LT) {
+ len = 0;
+ trp->tp++;
+ while (trp->tp->type!=GT) {
+ if (trp->tp>trp->lp || len+trp->tp->len+2 >= sizeof(fname))
+ goto syntax;
+ strncpy(fname+len, (char*)trp->tp->t, trp->tp->len);
+ len += trp->tp->len;
+ trp->tp++;
+ }
+ angled = 1;
+ } else
+ goto syntax;
+ trp->tp += 2;
+ if (trp->tp < trp->lp || len==0)
+ goto syntax;
+ fname[len] = '\0';
+
+ appendDirToIncludeList( basepath( fname ) );
+
+ if (fname[0]=='/') {
+ fd = open(fname, 0);
+ strcpy(iname, fname);
+ } else for (fd = -1,i=NINCLUDE-1; i>=0; i--) {
+ ip = &includelist[i];
+ if (ip->file==NULL || ip->deleted || (angled && ip->always==0))
+ continue;
+ if (strlen(fname)+strlen(ip->file)+2 > sizeof(iname))
+ continue;
+ strcpy(iname, ip->file);
+ strcat(iname, "/");
+ strcat(iname, fname);
+ if ((fd = open(iname, 0)) >= 0)
+ break;
+ }
+ if ( Mflag>1 || (!angled&&Mflag==1) ) {
+ write(1,objname,strlen(objname));
+ write(1,iname,strlen(iname));
+ write(1,"\n",1);
+ }
+ if (fd >= 0) {
+ if (++incdepth > 10)
+ error(FATAL, "#include too deeply nested");
+ setsource((char*)newstring((uchar*)iname, strlen(iname), 0), fd, NULL);
+ genline();
+ } else {
+ trp->tp = trp->bp+2;
+ error(ERROR, "Could not find include file %r", trp);
+ }
+ return;
+syntax:
+ error(ERROR, "Syntax error in #include");
+ return;
+}
+
+/*
+ * Generate a line directive for cursource
+ */
+void
+genline(void)
+{
+ static Token ta = { UNCLASS };
+ static Tokenrow tr = { &ta, &ta, &ta+1, 1 };
+ uchar *p;
+
+ ta.t = p = (uchar*)outp;
+ strcpy((char*)p, "#line ");
+ p += sizeof("#line ")-1;
+ p = (uchar*)outnum((char*)p, cursource->line);
+ *p++ = ' '; *p++ = '"';
+ if (cursource->filename[0]!='/' && wd[0]) {
+ strcpy((char*)p, wd);
+ p += strlen(wd);
+ *p++ = '/';
+ }
+ strcpy((char*)p, cursource->filename);
+ p += strlen((char*)p);
+ *p++ = '"'; *p++ = '\n';
+ ta.len = (char*)p-outp;
+ outp = (char*)p;
+ tr.tp = tr.bp;
+ puttokens(&tr);
+}
+
+void
+setobjname(char *f)
+{
+ int n = strlen(f);
+ objname = (char*)domalloc(n+5);
+ strcpy(objname,f);
+ if(objname[n-2]=='.'){
+ strcpy(objname+n-1,"$O: ");
+ }else{
+ strcpy(objname+n,"$O: ");
+ }
+}
diff --git a/code/tools/lcc/cpp/lex.c b/code/tools/lcc/cpp/lex.c
new file mode 100644
index 0000000..8030354
--- /dev/null
+++ b/code/tools/lcc/cpp/lex.c
@@ -0,0 +1,580 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpp.h"
+
+/*
+ * lexical FSM encoding
+ * when in state state, and one of the characters
+ * in ch arrives, enter nextstate.
+ * States >= S_SELF are either final, or at least require special action.
+ * In 'fsm' there is a line for each state X charset X nextstate.
+ * List chars that overwrite previous entries later (e.g. C_ALPH
+ * can be overridden by '_' by a later entry; and C_XX is the
+ * the universal set, and should always be first.
+ * States above S_SELF are represented in the big table as negative values.
+ * S_SELF and S_SELFB encode the resulting token type in the upper bits.
+ * These actions differ in that S_SELF doesn't have a lookahead char,
+ * S_SELFB does.
+ *
+ * The encoding is blown out into a big table for time-efficiency.
+ * Entries have
+ * nextstate: 6 bits; ?\ marker: 1 bit; tokentype: 9 bits.
+ */
+
+#define MAXSTATE 32
+#define ACT(tok,act) ((tok<<7)+act)
+#define QBSBIT 0100
+#define GETACT(st) (st>>7)&0x1ff
+
+/* character classes */
+#define C_WS 1
+#define C_ALPH 2
+#define C_NUM 3
+#define C_EOF 4
+#define C_XX 5
+
+enum state {
+ START=0, NUM1, NUM2, NUM3, ID1, ST1, ST2, ST3, COM1, COM2, COM3, COM4,
+ CC1, CC2, WS1, PLUS1, MINUS1, STAR1, SLASH1, PCT1, SHARP1,
+ CIRC1, GT1, GT2, LT1, LT2, OR1, AND1, ASG1, NOT1, DOTS1,
+ S_SELF=MAXSTATE, S_SELFB, S_EOF, S_NL, S_EOFSTR,
+ S_STNL, S_COMNL, S_EOFCOM, S_COMMENT, S_EOB, S_WS, S_NAME
+};
+
+int tottok;
+int tokkind[256];
+struct fsm {
+ int state; /* if in this state */
+ uchar ch[4]; /* and see one of these characters */
+ int nextstate; /* enter this state if +ve */
+};
+
+/*const*/ struct fsm fsm[] = {
+ /* start state */
+ {START, { C_XX }, ACT(UNCLASS,S_SELF)},
+ {START, { ' ', '\t', '\v' }, WS1},
+ {START, { C_NUM }, NUM1},
+ {START, { '.' }, NUM3},
+ {START, { C_ALPH }, ID1},
+ {START, { 'L' }, ST1},
+ {START, { '"' }, ST2},
+ {START, { '\'' }, CC1},
+ {START, { '/' }, COM1},
+ {START, { EOFC }, S_EOF},
+ {START, { '\n' }, S_NL},
+ {START, { '-' }, MINUS1},
+ {START, { '+' }, PLUS1},
+ {START, { '<' }, LT1},
+ {START, { '>' }, GT1},
+ {START, { '=' }, ASG1},
+ {START, { '!' }, NOT1},
+ {START, { '&' }, AND1},
+ {START, { '|' }, OR1},
+ {START, { '#' }, SHARP1},
+ {START, { '%' }, PCT1},
+ {START, { '[' }, ACT(SBRA,S_SELF)},
+ {START, { ']' }, ACT(SKET,S_SELF)},
+ {START, { '(' }, ACT(LP,S_SELF)},
+ {START, { ')' }, ACT(RP,S_SELF)},
+ {START, { '*' }, STAR1},
+ {START, { ',' }, ACT(COMMA,S_SELF)},
+ {START, { '?' }, ACT(QUEST,S_SELF)},
+ {START, { ':' }, ACT(COLON,S_SELF)},
+ {START, { ';' }, ACT(SEMIC,S_SELF)},
+ {START, { '{' }, ACT(CBRA,S_SELF)},
+ {START, { '}' }, ACT(CKET,S_SELF)},
+ {START, { '~' }, ACT(TILDE,S_SELF)},
+ {START, { '^' }, CIRC1},
+
+ /* saw a digit */
+ {NUM1, { C_XX }, ACT(NUMBER,S_SELFB)},
+ {NUM1, { C_NUM, C_ALPH, '.' }, NUM1},
+ {NUM1, { 'E', 'e' }, NUM2},
+ {NUM1, { '_' }, ACT(NUMBER,S_SELFB)},
+
+ /* saw possible start of exponent, digits-e */
+ {NUM2, { C_XX }, ACT(NUMBER,S_SELFB)},
+ {NUM2, { '+', '-' }, NUM1},
+ {NUM2, { C_NUM, C_ALPH }, NUM1},
+ {NUM2, { '_' }, ACT(NUMBER,S_SELFB)},
+
+ /* saw a '.', which could be a number or an operator */
+ {NUM3, { C_XX }, ACT(DOT,S_SELFB)},
+ {NUM3, { '.' }, DOTS1},
+ {NUM3, { C_NUM }, NUM1},
+
+ {DOTS1, { C_XX }, ACT(UNCLASS, S_SELFB)},
+ {DOTS1, { C_NUM }, NUM1},
+ {DOTS1, { '.' }, ACT(ELLIPS, S_SELF)},
+
+ /* saw a letter or _ */
+ {ID1, { C_XX }, ACT(NAME,S_NAME)},
+ {ID1, { C_ALPH, C_NUM }, ID1},
+
+ /* saw L (start of wide string?) */
+ {ST1, { C_XX }, ACT(NAME,S_NAME)},
+ {ST1, { C_ALPH, C_NUM }, ID1},
+ {ST1, { '"' }, ST2},
+ {ST1, { '\'' }, CC1},
+
+ /* saw " beginning string */
+ {ST2, { C_XX }, ST2},
+ {ST2, { '"' }, ACT(STRING, S_SELF)},
+ {ST2, { '\\' }, ST3},
+ {ST2, { '\n' }, S_STNL},
+ {ST2, { EOFC }, S_EOFSTR},
+
+ /* saw \ in string */
+ {ST3, { C_XX }, ST2},
+ {ST3, { '\n' }, S_STNL},
+ {ST3, { EOFC }, S_EOFSTR},
+
+ /* saw ' beginning character const */
+ {CC1, { C_XX }, CC1},
+ {CC1, { '\'' }, ACT(CCON, S_SELF)},
+ {CC1, { '\\' }, CC2},
+ {CC1, { '\n' }, S_STNL},
+ {CC1, { EOFC }, S_EOFSTR},
+
+ /* saw \ in ccon */
+ {CC2, { C_XX }, CC1},
+ {CC2, { '\n' }, S_STNL},
+ {CC2, { EOFC }, S_EOFSTR},
+
+ /* saw /, perhaps start of comment */
+ {COM1, { C_XX }, ACT(SLASH, S_SELFB)},
+ {COM1, { '=' }, ACT(ASSLASH, S_SELF)},
+ {COM1, { '*' }, COM2},
+ {COM1, { '/' }, COM4},
+
+ /* saw / then *, start of comment */
+ {COM2, { C_XX }, COM2},
+ {COM2, { '\n' }, S_COMNL},
+ {COM2, { '*' }, COM3},
+ {COM2, { EOFC }, S_EOFCOM},
+
+ /* saw the * possibly ending a comment */
+ {COM3, { C_XX }, COM2},
+ {COM3, { '\n' }, S_COMNL},
+ {COM3, { '*' }, COM3},
+ {COM3, { '/' }, S_COMMENT},
+
+ /* // comment */
+ {COM4, { C_XX }, COM4},
+ {COM4, { '\n' }, S_NL},
+ {COM4, { EOFC }, S_EOFCOM},
+
+ /* saw white space, eat it up */
+ {WS1, { C_XX }, S_WS},
+ {WS1, { ' ', '\t', '\v' }, WS1},
+
+ /* saw -, check --, -=, -> */
+ {MINUS1, { C_XX }, ACT(MINUS, S_SELFB)},
+ {MINUS1, { '-' }, ACT(MMINUS, S_SELF)},
+ {MINUS1, { '=' }, ACT(ASMINUS,S_SELF)},
+ {MINUS1, { '>' }, ACT(ARROW,S_SELF)},
+
+ /* saw +, check ++, += */
+ {PLUS1, { C_XX }, ACT(PLUS, S_SELFB)},
+ {PLUS1, { '+' }, ACT(PPLUS, S_SELF)},
+ {PLUS1, { '=' }, ACT(ASPLUS, S_SELF)},
+
+ /* saw <, check <<, <<=, <= */
+ {LT1, { C_XX }, ACT(LT, S_SELFB)},
+ {LT1, { '<' }, LT2},
+ {LT1, { '=' }, ACT(LEQ, S_SELF)},
+ {LT2, { C_XX }, ACT(LSH, S_SELFB)},
+ {LT2, { '=' }, ACT(ASLSH, S_SELF)},
+
+ /* saw >, check >>, >>=, >= */
+ {GT1, { C_XX }, ACT(GT, S_SELFB)},
+ {GT1, { '>' }, GT2},
+ {GT1, { '=' }, ACT(GEQ, S_SELF)},
+ {GT2, { C_XX }, ACT(RSH, S_SELFB)},
+ {GT2, { '=' }, ACT(ASRSH, S_SELF)},
+
+ /* = */
+ {ASG1, { C_XX }, ACT(ASGN, S_SELFB)},
+ {ASG1, { '=' }, ACT(EQ, S_SELF)},
+
+ /* ! */
+ {NOT1, { C_XX }, ACT(NOT, S_SELFB)},
+ {NOT1, { '=' }, ACT(NEQ, S_SELF)},
+
+ /* & */
+ {AND1, { C_XX }, ACT(AND, S_SELFB)},
+ {AND1, { '&' }, ACT(LAND, S_SELF)},
+ {AND1, { '=' }, ACT(ASAND, S_SELF)},
+
+ /* | */
+ {OR1, { C_XX }, ACT(OR, S_SELFB)},
+ {OR1, { '|' }, ACT(LOR, S_SELF)},
+ {OR1, { '=' }, ACT(ASOR, S_SELF)},
+
+ /* # */
+ {SHARP1, { C_XX }, ACT(SHARP, S_SELFB)},
+ {SHARP1, { '#' }, ACT(DSHARP, S_SELF)},
+
+ /* % */
+ {PCT1, { C_XX }, ACT(PCT, S_SELFB)},
+ {PCT1, { '=' }, ACT(ASPCT, S_SELF)},
+
+ /* * */
+ {STAR1, { C_XX }, ACT(STAR, S_SELFB)},
+ {STAR1, { '=' }, ACT(ASSTAR, S_SELF)},
+
+ /* ^ */
+ {CIRC1, { C_XX }, ACT(CIRC, S_SELFB)},
+ {CIRC1, { '=' }, ACT(ASCIRC, S_SELF)},
+
+ {-1}
+};
+
+/* first index is char, second is state */
+/* increase #states to power of 2 to encourage use of shift */
+short bigfsm[256][MAXSTATE];
+
+void
+expandlex(void)
+{
+ /*const*/ struct fsm *fp;
+ int i, j, nstate;
+
+ for (fp = fsm; fp->state>=0; fp++) {
+ for (i=0; fp->ch[i]; i++) {
+ nstate = fp->nextstate;
+ if (nstate >= S_SELF)
+ nstate = ~nstate;
+ switch (fp->ch[i]) {
+
+ case C_XX: /* random characters */
+ for (j=0; j<256; j++)
+ bigfsm[j][fp->state] = nstate;
+ continue;
+ case C_ALPH:
+ for (j=0; j<=256; j++)
+ if (('a'<=j&&j<='z') || ('A'<=j&&j<='Z')
+ || j=='_')
+ bigfsm[j][fp->state] = nstate;
+ continue;
+ case C_NUM:
+ for (j='0'; j<='9'; j++)
+ bigfsm[j][fp->state] = nstate;
+ continue;
+ default:
+ bigfsm[fp->ch[i]][fp->state] = nstate;
+ }
+ }
+ }
+ /* install special cases for ? (trigraphs), \ (splicing), runes, and EOB */
+ for (i=0; i<MAXSTATE; i++) {
+ for (j=0; j<0xFF; j++)
+ if (j=='?' || j=='\\') {
+ if (bigfsm[j][i]>0)
+ bigfsm[j][i] = ~bigfsm[j][i];
+ bigfsm[j][i] &= ~QBSBIT;
+ }
+ bigfsm[EOB][i] = ~S_EOB;
+ if (bigfsm[EOFC][i]>=0)
+ bigfsm[EOFC][i] = ~S_EOF;
+ }
+}
+
+void
+fixlex(void)
+{
+ /* do C++ comments? */
+ if (Cplusplus==0)
+ bigfsm['/'][COM1] = bigfsm['x'][COM1];
+}
+
+/*
+ * fill in a row of tokens from input, terminated by NL or END
+ * First token is put at trp->lp.
+ * Reset is non-zero when the input buffer can be "rewound."
+ * The value is a flag indicating that possible macros have
+ * been seen in the row.
+ */
+int
+gettokens(Tokenrow *trp, int reset)
+{
+ register int c, state, oldstate;
+ register uchar *ip;
+ register Token *tp, *maxp;
+ int runelen;
+ Source *s = cursource;
+ int nmac = 0;
+
+ tp = trp->lp;
+ ip = s->inp;
+ if (reset) {
+ s->lineinc = 0;
+ if (ip>=s->inl) { /* nothing in buffer */
+ s->inl = s->inb;
+ fillbuf(s);
+ ip = s->inp = s->inb;
+ } else if (ip >= s->inb+(3*INS/4)) {
+ memmove(s->inb, ip, 4+s->inl-ip);
+ s->inl = s->inb+(s->inl-ip);
+ ip = s->inp = s->inb;
+ }
+ }
+ maxp = &trp->bp[trp->max];
+ runelen = 1;
+ for (;;) {
+ continue2:
+ if (tp>=maxp) {
+ trp->lp = tp;
+ tp = growtokenrow(trp);
+ maxp = &trp->bp[trp->max];
+ }
+ tp->type = UNCLASS;
+ tp->hideset = 0;
+ tp->t = ip;
+ tp->wslen = 0;
+ tp->flag = 0;
+ state = START;
+ for (;;) {
+ oldstate = state;
+ c = *ip;
+ if ((state = bigfsm[c][state]) >= 0) {
+ ip += runelen;
+ runelen = 1;
+ continue;
+ }
+ state = ~state;
+ reswitch:
+ switch (state&0177) {
+ case S_SELF:
+ ip += runelen;
+ runelen = 1;
+ case S_SELFB:
+ tp->type = GETACT(state);
+ tp->len = ip - tp->t;
+ tp++;
+ goto continue2;
+
+ case S_NAME: /* like S_SELFB but with nmac check */
+ tp->type = NAME;
+ tp->len = ip - tp->t;
+ nmac |= quicklook(tp->t[0], tp->len>1?tp->t[1]:0);
+ tp++;
+ goto continue2;
+
+ case S_WS:
+ tp->wslen = ip - tp->t;
+ tp->t = ip;
+ state = START;
+ continue;
+
+ default:
+ if ((state&QBSBIT)==0) {
+ ip += runelen;
+ runelen = 1;
+ continue;
+ }
+ state &= ~QBSBIT;
+ s->inp = ip;
+ if (c=='?') { /* check trigraph */
+ if (trigraph(s)) {
+ state = oldstate;
+ continue;
+ }
+ goto reswitch;
+ }
+ if (c=='\\') { /* line-folding */
+ if (foldline(s)) {
+ s->lineinc++;
+ state = oldstate;
+ continue;
+ }
+ goto reswitch;
+ }
+ error(WARNING, "Lexical botch in cpp");
+ ip += runelen;
+ runelen = 1;
+ continue;
+
+ case S_EOB:
+ s->inp = ip;
+ fillbuf(cursource);
+ state = oldstate;
+ continue;
+
+ case S_EOF:
+ tp->type = END;
+ tp->len = 0;
+ s->inp = ip;
+ if (tp!=trp->bp && (tp-1)->type!=NL && cursource->fd!=-1)
+ error(WARNING,"No newline at end of file");
+ trp->lp = tp+1;
+ return nmac;
+
+ case S_STNL:
+ error(ERROR, "Unterminated string or char const");
+ case S_NL:
+ tp->t = ip;
+ tp->type = NL;
+ tp->len = 1;
+ tp->wslen = 0;
+ s->lineinc++;
+ s->inp = ip+1;
+ trp->lp = tp+1;
+ return nmac;
+
+ case S_EOFSTR:
+ error(FATAL, "EOF in string or char constant");
+ break;
+
+ case S_COMNL:
+ s->lineinc++;
+ state = COM2;
+ ip += runelen;
+ runelen = 1;
+ if (ip >= s->inb+(7*INS/8)) { /* very long comment */
+ memmove(tp->t, ip, 4+s->inl-ip);
+ s->inl -= ip-tp->t;
+ ip = tp->t+1;
+ }
+ continue;
+
+ case S_EOFCOM:
+ error(WARNING, "EOF inside comment");
+ --ip;
+ case S_COMMENT:
+ ++ip;
+ tp->t = ip;
+ tp->t[-1] = ' ';
+ tp->wslen = 1;
+ state = START;
+ continue;
+ }
+ break;
+ }
+ ip += runelen;
+ runelen = 1;
+ tp->len = ip - tp->t;
+ tp++;
+ }
+}
+
+/* have seen ?; handle the trigraph it starts (if any) else 0 */
+int
+trigraph(Source *s)
+{
+ int c;
+
+ while (s->inp+2 >= s->inl && fillbuf(s)!=EOF)
+ ;
+ if (s->inp[1]!='?')
+ return 0;
+ c = 0;
+ switch(s->inp[2]) {
+ case '=':
+ c = '#'; break;
+ case '(':
+ c = '['; break;
+ case '/':
+ c = '\\'; break;
+ case ')':
+ c = ']'; break;
+ case '\'':
+ c = '^'; break;
+ case '<':
+ c = '{'; break;
+ case '!':
+ c = '|'; break;
+ case '>':
+ c = '}'; break;
+ case '-':
+ c = '~'; break;
+ }
+ if (c) {
+ *s->inp = c;
+ memmove(s->inp+1, s->inp+3, s->inl-s->inp+2);
+ s->inl -= 2;
+ }
+ return c;
+}
+
+int
+foldline(Source *s)
+{
+ while (s->inp+1 >= s->inl && fillbuf(s)!=EOF)
+ ;
+ if (s->inp[1] == '\n') {
+ memmove(s->inp, s->inp+2, s->inl-s->inp+3);
+ s->inl -= 2;
+ return 1;
+ }
+ return 0;
+}
+
+int
+fillbuf(Source *s)
+{
+ int n, nr;
+
+ nr = INS/8;
+ if ((char *)s->inl+nr > (char *)s->inb+INS)
+ error(FATAL, "Input buffer overflow");
+ if (s->fd<0 || (n=read(s->fd, (char *)s->inl, INS/8)) <= 0)
+ n = 0;
+ if ((*s->inp&0xff) == EOB) /* sentinel character appears in input */
+ *s->inp = EOFC;
+ s->inl += n;
+ s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOB;
+ if (n==0) {
+ s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOFC;
+ return EOF;
+ }
+ return 0;
+}
+
+/*
+ * Push down to new source of characters.
+ * If fd>0 and str==NULL, then from a file `name';
+ * if fd==-1 and str, then from the string.
+ */
+Source *
+setsource(char *name, int fd, char *str)
+{
+ Source *s = new(Source);
+ int len;
+
+ s->line = 1;
+ s->lineinc = 0;
+ s->fd = fd;
+ s->filename = name;
+ s->next = cursource;
+ s->ifdepth = 0;
+ cursource = s;
+ /* slop at right for EOB */
+ if (str) {
+ len = strlen(str);
+ s->inb = domalloc(len+4);
+ s->inp = s->inb;
+ strncpy((char *)s->inp, str, len);
+ } else {
+ s->inb = domalloc(INS+4);
+ s->inp = s->inb;
+ len = 0;
+ }
+ s->inl = s->inp+len;
+ s->inl[0] = s->inl[1] = EOB;
+ return s;
+}
+
+void
+unsetsource(void)
+{
+ Source *s = cursource;
+
+ if (s->fd>=0) {
+ close(s->fd);
+ dofree(s->inb);
+ }
+ cursource = s->next;
+ dofree(s);
+}
diff --git a/code/tools/lcc/cpp/macro.c b/code/tools/lcc/cpp/macro.c
new file mode 100644
index 0000000..49d1129
--- /dev/null
+++ b/code/tools/lcc/cpp/macro.c
@@ -0,0 +1,515 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpp.h"
+
+/*
+ * do a macro definition. tp points to the name being defined in the line
+ */
+void
+dodefine(Tokenrow *trp)
+{
+ Token *tp;
+ Nlist *np;
+ Tokenrow *def, *args;
+
+ tp = trp->tp+1;
+ if (tp>=trp->lp || tp->type!=NAME) {
+ error(ERROR, "#defined token is not a name");
+ return;
+ }
+ np = lookup(tp, 1);
+ if (np->flag&ISUNCHANGE) {
+ error(ERROR, "#defined token %t can't be redefined", tp);
+ return;
+ }
+ /* collect arguments */
+ tp += 1;
+ args = NULL;
+ if (tp<trp->lp && tp->type==LP && tp->wslen==0) {
+ /* macro with args */
+ int narg = 0;
+ tp += 1;
+ args = new(Tokenrow);
+ maketokenrow(2, args);
+ if (tp->type!=RP) {
+ int err = 0;
+ for (;;) {
+ Token *atp;
+ if (tp->type!=NAME) {
+ err++;
+ break;
+ }
+ if (narg>=args->max)
+ growtokenrow(args);
+ for (atp=args->bp; atp<args->lp; atp++)
+ if (atp->len==tp->len
+ && strncmp((char*)atp->t, (char*)tp->t, tp->len)==0)
+ error(ERROR, "Duplicate macro argument");
+ *args->lp++ = *tp;
+ narg++;
+ tp += 1;
+ if (tp->type==RP)
+ break;
+ if (tp->type!=COMMA) {
+ err++;
+ break;
+ }
+ tp += 1;
+ }
+ if (err) {
+ error(ERROR, "Syntax error in macro parameters");
+ return;
+ }
+ }
+ tp += 1;
+ }
+ trp->tp = tp;
+ if (((trp->lp)-1)->type==NL)
+ trp->lp -= 1;
+ def = normtokenrow(trp);
+ if (np->flag&ISDEFINED) {
+ if (comparetokens(def, np->vp)
+ || (np->ap==NULL) != (args==NULL)
+ || (np->ap && comparetokens(args, np->ap)))
+ error(ERROR, "Macro redefinition of %t", trp->bp+2);
+ }
+ if (args) {
+ Tokenrow *tap;
+ tap = normtokenrow(args);
+ dofree(args->bp);
+ args = tap;
+ }
+ np->ap = args;
+ np->vp = def;
+ np->flag |= ISDEFINED;
+}
+
+/*
+ * Definition received via -D or -U
+ */
+void
+doadefine(Tokenrow *trp, int type)
+{
+ Nlist *np;
+ static Token onetoken[1] = {{ NUMBER, 0, 0, 0, 1, (uchar*)"1" }};
+ static Tokenrow onetr = { onetoken, onetoken, onetoken+1, 1 };
+
+ trp->tp = trp->bp;
+ if (type=='U') {
+ if (trp->lp-trp->tp != 2 || trp->tp->type!=NAME)
+ goto syntax;
+ if ((np = lookup(trp->tp, 0)) == NULL)
+ return;
+ np->flag &= ~ISDEFINED;
+ return;
+ }
+ if (trp->tp >= trp->lp || trp->tp->type!=NAME)
+ goto syntax;
+ np = lookup(trp->tp, 1);
+ np->flag |= ISDEFINED;
+ trp->tp += 1;
+ if (trp->tp >= trp->lp || trp->tp->type==END) {
+ np->vp = &onetr;
+ return;
+ }
+ if (trp->tp->type!=ASGN)
+ goto syntax;
+ trp->tp += 1;
+ if ((trp->lp-1)->type == END)
+ trp->lp -= 1;
+ np->vp = normtokenrow(trp);
+ return;
+syntax:
+ error(FATAL, "Illegal -D or -U argument %r", trp);
+}
+
+/*
+ * Do macro expansion in a row of tokens.
+ * Flag is NULL if more input can be gathered.
+ */
+void
+expandrow(Tokenrow *trp, char *flag)
+{
+ Token *tp;
+ Nlist *np;
+
+ if (flag)
+ setsource(flag, -1, "");
+ for (tp = trp->tp; tp<trp->lp; ) {
+ if (tp->type!=NAME
+ || quicklook(tp->t[0], tp->len>1?tp->t[1]:0)==0
+ || (np = lookup(tp, 0))==NULL
+ || (np->flag&(ISDEFINED|ISMAC))==0
+ || (tp->hideset && checkhideset(tp->hideset, np))) {
+ tp++;
+ continue;
+ }
+ trp->tp = tp;
+ if (np->val==KDEFINED) {
+ tp->type = DEFINED;
+ if ((tp+1)<trp->lp && (tp+1)->type==NAME)
+ (tp+1)->type = NAME1;
+ else if ((tp+3)<trp->lp && (tp+1)->type==LP
+ && (tp+2)->type==NAME && (tp+3)->type==RP)
+ (tp+2)->type = NAME1;
+ else
+ error(ERROR, "Incorrect syntax for `defined'");
+ tp++;
+ continue;
+ }
+ if (np->flag&ISMAC)
+ builtin(trp, np->val);
+ else {
+ expand(trp, np);
+ }
+ tp = trp->tp;
+ }
+ if (flag)
+ unsetsource();
+}
+
+/*
+ * Expand the macro whose name is np, at token trp->tp, in the tokenrow.
+ * Return trp->tp at the first token next to be expanded
+ * (ordinarily the beginning of the expansion)
+ */
+void
+expand(Tokenrow *trp, Nlist *np)
+{
+ Tokenrow ntr;
+ int ntokc, narg, i;
+ Token *tp;
+ Tokenrow *atr[NARG+1];
+ int hs;
+
+ copytokenrow(&ntr, np->vp); /* copy macro value */
+ if (np->ap==NULL) /* parameterless */
+ ntokc = 1;
+ else {
+ ntokc = gatherargs(trp, atr, &narg);
+ if (narg<0) { /* not actually a call (no '(') */
+ trp->tp++;
+ return;
+ }
+ if (narg != rowlen(np->ap)) {
+ error(ERROR, "Disagreement in number of macro arguments");
+ trp->tp->hideset = newhideset(trp->tp->hideset, np);
+ trp->tp += ntokc;
+ return;
+ }
+ substargs(np, &ntr, atr); /* put args into replacement */
+ for (i=0; i<narg; i++) {
+ dofree(atr[i]->bp);
+ dofree(atr[i]);
+ }
+ }
+ doconcat(&ntr); /* execute ## operators */
+ hs = newhideset(trp->tp->hideset, np);
+ for (tp=ntr.bp; tp<ntr.lp; tp++) { /* distribute hidesets */
+ if (tp->type==NAME) {
+ if (tp->hideset==0)
+ tp->hideset = hs;
+ else
+ tp->hideset = unionhideset(tp->hideset, hs);
+ }
+ }
+ ntr.tp = ntr.bp;
+ insertrow(trp, ntokc, &ntr);
+ trp->tp -= rowlen(&ntr);
+ dofree(ntr.bp);
+ return;
+}
+
+/*
+ * Gather an arglist, starting in trp with tp pointing at the macro name.
+ * Return total number of tokens passed, stash number of args found.
+ * trp->tp is not changed relative to the tokenrow.
+ */
+int
+gatherargs(Tokenrow *trp, Tokenrow **atr, int *narg)
+{
+ int parens = 1;
+ int ntok = 0;
+ Token *bp, *lp;
+ Tokenrow ttr;
+ int ntokp;
+ int needspace;
+
+ *narg = -1; /* means that there is no macro call */
+ /* look for the ( */
+ for (;;) {
+ trp->tp++;
+ ntok++;
+ if (trp->tp >= trp->lp) {
+ gettokens(trp, 0);
+ if ((trp->lp-1)->type==END) {
+ trp->lp -= 1;
+ trp->tp -= ntok;
+ return ntok;
+ }
+ }
+ if (trp->tp->type==LP)
+ break;
+ if (trp->tp->type!=NL)
+ return ntok;
+ }
+ *narg = 0;
+ ntok++;
+ ntokp = ntok;
+ trp->tp++;
+ /* search for the terminating ), possibly extending the row */
+ needspace = 0;
+ while (parens>0) {
+ if (trp->tp >= trp->lp)
+ gettokens(trp, 0);
+ if (needspace) {
+ needspace = 0;
+ makespace(trp);
+ }
+ if (trp->tp->type==END) {
+ trp->lp -= 1;
+ trp->tp -= ntok;
+ error(ERROR, "EOF in macro arglist");
+ return ntok;
+ }
+ if (trp->tp->type==NL) {
+ trp->tp += 1;
+ adjustrow(trp, -1);
+ trp->tp -= 1;
+ makespace(trp);
+ needspace = 1;
+ continue;
+ }
+ if (trp->tp->type==LP)
+ parens++;
+ else if (trp->tp->type==RP)
+ parens--;
+ trp->tp++;
+ ntok++;
+ }
+ trp->tp -= ntok;
+ /* Now trp->tp won't move underneath us */
+ lp = bp = trp->tp+ntokp;
+ for (; parens>=0; lp++) {
+ if (lp->type == LP) {
+ parens++;
+ continue;
+ }
+ if (lp->type==RP)
+ parens--;
+ if (lp->type==DSHARP)
+ lp->type = DSHARP1; /* ## not special in arg */
+ if ((lp->type==COMMA && parens==0) || (parens<0 && (lp-1)->type!=LP)) {
+ if (*narg>=NARG-1)
+ error(FATAL, "Sorry, too many macro arguments");
+ ttr.bp = ttr.tp = bp;
+ ttr.lp = lp;
+ atr[(*narg)++] = normtokenrow(&ttr);
+ bp = lp+1;
+ }
+ }
+ return ntok;
+}
+
+/*
+ * substitute the argument list into the replacement string
+ * This would be simple except for ## and #
+ */
+void
+substargs(Nlist *np, Tokenrow *rtr, Tokenrow **atr)
+{
+ Tokenrow tatr;
+ Token *tp;
+ int ntok, argno;
+
+ for (rtr->tp=rtr->bp; rtr->tp<rtr->lp; ) {
+ if (rtr->tp->type==SHARP) { /* string operator */
+ tp = rtr->tp;
+ rtr->tp += 1;
+ if ((argno = lookuparg(np, rtr->tp))<0) {
+ error(ERROR, "# not followed by macro parameter");
+ continue;
+ }
+ ntok = 1 + (rtr->tp - tp);
+ rtr->tp = tp;
+ insertrow(rtr, ntok, stringify(atr[argno]));
+ continue;
+ }
+ if (rtr->tp->type==NAME
+ && (argno = lookuparg(np, rtr->tp)) >= 0) {
+ if ((rtr->tp+1)->type==DSHARP
+ || (rtr->tp!=rtr->bp && (rtr->tp-1)->type==DSHARP))
+ insertrow(rtr, 1, atr[argno]);
+ else {
+ copytokenrow(&tatr, atr[argno]);
+ expandrow(&tatr, "<macro>");
+ insertrow(rtr, 1, &tatr);
+ dofree(tatr.bp);
+ }
+ continue;
+ }
+ rtr->tp++;
+ }
+}
+
+/*
+ * Evaluate the ## operators in a tokenrow
+ */
+void
+doconcat(Tokenrow *trp)
+{
+ Token *ltp, *ntp;
+ Tokenrow ntr;
+ int len;
+
+ for (trp->tp=trp->bp; trp->tp<trp->lp; trp->tp++) {
+ if (trp->tp->type==DSHARP1)
+ trp->tp->type = DSHARP;
+ else if (trp->tp->type==DSHARP) {
+ char tt[128];
+ ltp = trp->tp-1;
+ ntp = trp->tp+1;
+ if (ltp<trp->bp || ntp>=trp->lp) {
+ error(ERROR, "## occurs at border of replacement");
+ continue;
+ }
+ len = ltp->len + ntp->len;
+ strncpy((char*)tt, (char*)ltp->t, ltp->len);
+ strncpy((char*)tt+ltp->len, (char*)ntp->t, ntp->len);
+ tt[len] = '\0';
+ setsource("<##>", -1, tt);
+ maketokenrow(3, &ntr);
+ gettokens(&ntr, 1);
+ unsetsource();
+ if (ntr.lp-ntr.bp!=2 || ntr.bp->type==UNCLASS)
+ error(WARNING, "Bad token %r produced by ##", &ntr);
+ ntr.lp = ntr.bp+1;
+ trp->tp = ltp;
+ makespace(&ntr);
+ insertrow(trp, (ntp-ltp)+1, &ntr);
+ dofree(ntr.bp);
+ trp->tp--;
+ }
+ }
+}
+
+/*
+ * tp is a potential parameter name of macro mac;
+ * look it up in mac's arglist, and if found, return the
+ * corresponding index in the argname array. Return -1 if not found.
+ */
+int
+lookuparg(Nlist *mac, Token *tp)
+{
+ Token *ap;
+
+ if (tp->type!=NAME || mac->ap==NULL)
+ return -1;
+ for (ap=mac->ap->bp; ap<mac->ap->lp; ap++) {
+ if (ap->len==tp->len && strncmp((char*)ap->t,(char*)tp->t,ap->len)==0)
+ return ap - mac->ap->bp;
+ }
+ return -1;
+}
+
+/*
+ * Return a quoted version of the tokenrow (from # arg)
+ */
+#define STRLEN 512
+Tokenrow *
+stringify(Tokenrow *vp)
+{
+ static Token t = { STRING };
+ static Tokenrow tr = { &t, &t, &t+1, 1 };
+ Token *tp;
+ uchar s[STRLEN];
+ uchar *sp = s, *cp;
+ int i, instring;
+
+ *sp++ = '"';
+ for (tp = vp->bp; tp < vp->lp; tp++) {
+ instring = tp->type==STRING || tp->type==CCON;
+ if (sp+2*tp->len >= &s[STRLEN-10]) {
+ error(ERROR, "Stringified macro arg is too long");
+ break;
+ }
+ if (tp->wslen && (tp->flag&XPWS)==0)
+ *sp++ = ' ';
+ for (i=0, cp=tp->t; i<tp->len; i++) {
+ if (instring && (*cp=='"' || *cp=='\\'))
+ *sp++ = '\\';
+ *sp++ = *cp++;
+ }
+ }
+ *sp++ = '"';
+ *sp = '\0';
+ sp = s;
+ t.len = strlen((char*)sp);
+ t.t = newstring(sp, t.len, 0);
+ return &tr;
+}
+
+/*
+ * expand a builtin name
+ */
+void
+builtin(Tokenrow *trp, int biname)
+{
+ char *op;
+ Token *tp;
+ Source *s;
+
+ tp = trp->tp;
+ trp->tp++;
+ /* need to find the real source */
+ s = cursource;
+ while (s && s->fd==-1)
+ s = s->next;
+ if (s==NULL)
+ s = cursource;
+ /* most are strings */
+ tp->type = STRING;
+ if (tp->wslen) {
+ *outp++ = ' ';
+ tp->wslen = 1;
+ }
+ op = outp;
+ *op++ = '"';
+ switch (biname) {
+
+ case KLINENO:
+ tp->type = NUMBER;
+ op = outnum(op-1, s->line);
+ break;
+
+ case KFILE: {
+ char *src = s->filename;
+ while ((*op++ = *src++) != 0)
+ if (src[-1] == '\\')
+ *op++ = '\\';
+ op--;
+ break;
+ }
+
+ case KDATE:
+ strncpy(op, curtime+4, 7);
+ strncpy(op+7, curtime+20, 4);
+ op += 11;
+ break;
+
+ case KTIME:
+ strncpy(op, curtime+11, 8);
+ op += 8;
+ break;
+
+ default:
+ error(ERROR, "cpp botch: unknown internal macro");
+ return;
+ }
+ if (tp->type==STRING)
+ *op++ = '"';
+ tp->t = (uchar*)outp;
+ tp->len = op - outp;
+ outp = op;
+}
diff --git a/code/tools/lcc/cpp/nlist.c b/code/tools/lcc/cpp/nlist.c
new file mode 100644
index 0000000..d3a8357
--- /dev/null
+++ b/code/tools/lcc/cpp/nlist.c
@@ -0,0 +1,104 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpp.h"
+
+extern char *optarg;
+extern int optind;
+extern int verbose;
+extern int Cplusplus;
+Nlist *kwdefined;
+char wd[128];
+
+#define NLSIZE 128
+
+static Nlist *nlist[NLSIZE];
+
+struct kwtab {
+ char *kw;
+ int val;
+ int flag;
+} kwtab[] = {
+ {"if", KIF, ISKW},
+ {"ifdef", KIFDEF, ISKW},
+ {"ifndef", KIFNDEF, ISKW},
+ {"elif", KELIF, ISKW},
+ {"else", KELSE, ISKW},
+ {"endif", KENDIF, ISKW},
+ {"include", KINCLUDE, ISKW},
+ {"define", KDEFINE, ISKW},
+ {"undef", KUNDEF, ISKW},
+ {"line", KLINE, ISKW},
+ {"warning", KWARNING, ISKW},
+ {"error", KERROR, ISKW},
+ {"pragma", KPRAGMA, ISKW},
+ {"eval", KEVAL, ISKW},
+ {"defined", KDEFINED, ISDEFINED+ISUNCHANGE},
+ {"__LINE__", KLINENO, ISMAC+ISUNCHANGE},
+ {"__FILE__", KFILE, ISMAC+ISUNCHANGE},
+ {"__DATE__", KDATE, ISMAC+ISUNCHANGE},
+ {"__TIME__", KTIME, ISMAC+ISUNCHANGE},
+ {"__STDC__", KSTDC, ISUNCHANGE},
+ {NULL}
+};
+
+unsigned long namebit[077+1];
+Nlist *np;
+
+void
+setup_kwtab(void)
+{
+ struct kwtab *kp;
+ Nlist *np;
+ Token t;
+ static Token deftoken[1] = {{ NAME, 0, 0, 0, 7, (uchar*)"defined" }};
+ static Tokenrow deftr = { deftoken, deftoken, deftoken+1, 1 };
+
+ for (kp=kwtab; kp->kw; kp++) {
+ t.t = (uchar*)kp->kw;
+ t.len = strlen(kp->kw);
+ np = lookup(&t, 1);
+ np->flag = kp->flag;
+ np->val = kp->val;
+ if (np->val == KDEFINED) {
+ kwdefined = np;
+ np->val = NAME;
+ np->vp = &deftr;
+ np->ap = 0;
+ }
+ }
+}
+
+Nlist *
+lookup(Token *tp, int install)
+{
+ unsigned int h;
+ Nlist *np;
+ uchar *cp, *cpe;
+
+ h = 0;
+ for (cp=tp->t, cpe=cp+tp->len; cp<cpe; )
+ h += *cp++;
+ h %= NLSIZE;
+ np = nlist[h];
+ while (np) {
+ if (*tp->t==*np->name && tp->len==np->len
+ && strncmp((char*)tp->t, (char*)np->name, tp->len)==0)
+ return np;
+ np = np->next;
+ }
+ if (install) {
+ np = new(Nlist);
+ np->vp = NULL;
+ np->ap = NULL;
+ np->flag = 0;
+ np->val = 0;
+ np->len = tp->len;
+ np->name = newstring(tp->t, tp->len, 0);
+ np->next = nlist[h];
+ nlist[h] = np;
+ quickset(tp->t[0], tp->len>1? tp->t[1]:0);
+ return np;
+ }
+ return NULL;
+}
diff --git a/code/tools/lcc/cpp/tokens.c b/code/tools/lcc/cpp/tokens.c
new file mode 100644
index 0000000..147569b
--- /dev/null
+++ b/code/tools/lcc/cpp/tokens.c
@@ -0,0 +1,370 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpp.h"
+
+static char wbuf[2*OBS];
+static char *wbp = wbuf;
+
+/*
+ * 1 for tokens that don't need whitespace when they get inserted
+ * by macro expansion
+ */
+static const char wstab[] = {
+ 0, /* END */
+ 0, /* UNCLASS */
+ 0, /* NAME */
+ 0, /* NUMBER */
+ 0, /* STRING */
+ 0, /* CCON */
+ 1, /* NL */
+ 0, /* WS */
+ 0, /* DSHARP */
+ 0, /* EQ */
+ 0, /* NEQ */
+ 0, /* LEQ */
+ 0, /* GEQ */
+ 0, /* LSH */
+ 0, /* RSH */
+ 0, /* LAND */
+ 0, /* LOR */
+ 0, /* PPLUS */
+ 0, /* MMINUS */
+ 0, /* ARROW */
+ 1, /* SBRA */
+ 1, /* SKET */
+ 1, /* LP */
+ 1, /* RP */
+ 0, /* DOT */
+ 0, /* AND */
+ 0, /* STAR */
+ 0, /* PLUS */
+ 0, /* MINUS */
+ 0, /* TILDE */
+ 0, /* NOT */
+ 0, /* SLASH */
+ 0, /* PCT */
+ 0, /* LT */
+ 0, /* GT */
+ 0, /* CIRC */
+ 0, /* OR */
+ 0, /* QUEST */
+ 0, /* COLON */
+ 0, /* ASGN */
+ 1, /* COMMA */
+ 0, /* SHARP */
+ 1, /* SEMIC */
+ 1, /* CBRA */
+ 1, /* CKET */
+ 0, /* ASPLUS */
+ 0, /* ASMINUS */
+ 0, /* ASSTAR */
+ 0, /* ASSLASH */
+ 0, /* ASPCT */
+ 0, /* ASCIRC */
+ 0, /* ASLSH */
+ 0, /* ASRSH */
+ 0, /* ASOR */
+ 0, /* ASAND */
+ 0, /* ELLIPS */
+ 0, /* DSHARP1 */
+ 0, /* NAME1 */
+ 0, /* DEFINED */
+ 0, /* UMINUS */
+};
+
+void
+maketokenrow(int size, Tokenrow *trp)
+{
+ trp->max = size;
+ if (size>0)
+ trp->bp = (Token *)domalloc(size*sizeof(Token));
+ else
+ trp->bp = NULL;
+ trp->tp = trp->bp;
+ trp->lp = trp->bp;
+}
+
+Token *
+growtokenrow(Tokenrow *trp)
+{
+ int ncur = trp->tp - trp->bp;
+ int nlast = trp->lp - trp->bp;
+
+ trp->max = 3*trp->max/2 + 1;
+ trp->bp = (Token *)realloc(trp->bp, trp->max*sizeof(Token));
+ if (trp->bp == NULL)
+ error(FATAL, "Out of memory from realloc");
+ trp->lp = &trp->bp[nlast];
+ trp->tp = &trp->bp[ncur];
+ return trp->lp;
+}
+
+/*
+ * Compare a row of tokens, ignoring the content of WS; return !=0 if different
+ */
+int
+comparetokens(Tokenrow *tr1, Tokenrow *tr2)
+{
+ Token *tp1, *tp2;
+
+ tp1 = tr1->tp;
+ tp2 = tr2->tp;
+ if (tr1->lp-tp1 != tr2->lp-tp2)
+ return 1;
+ for (; tp1<tr1->lp ; tp1++, tp2++) {
+ if (tp1->type != tp2->type
+ || (tp1->wslen==0) != (tp2->wslen==0)
+ || tp1->len != tp2->len
+ || strncmp((char*)tp1->t, (char*)tp2->t, tp1->len)!=0)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * replace ntok tokens starting at dtr->tp with the contents of str.
+ * tp ends up pointing just beyond the replacement.
+ * Canonical whitespace is assured on each side.
+ */
+void
+insertrow(Tokenrow *dtr, int ntok, Tokenrow *str)
+{
+ int nrtok = rowlen(str);
+
+ dtr->tp += ntok;
+ adjustrow(dtr, nrtok-ntok);
+ dtr->tp -= ntok;
+ movetokenrow(dtr, str);
+ makespace(dtr);
+ dtr->tp += nrtok;
+ makespace(dtr);
+}
+
+/*
+ * make sure there is WS before trp->tp, if tokens might merge in the output
+ */
+void
+makespace(Tokenrow *trp)
+{
+ uchar *tt;
+ Token *tp = trp->tp;
+
+ if (tp >= trp->lp)
+ return;
+ if (tp->wslen) {
+ if (tp->flag&XPWS
+ && (wstab[tp->type] || (trp->tp>trp->bp && wstab[(tp-1)->type]))) {
+ tp->wslen = 0;
+ return;
+ }
+ tp->t[-1] = ' ';
+ return;
+ }
+ if (wstab[tp->type] || (trp->tp>trp->bp && wstab[(tp-1)->type]))
+ return;
+ tt = newstring(tp->t, tp->len, 1);
+ *tt++ = ' ';
+ tp->t = tt;
+ tp->wslen = 1;
+ tp->flag |= XPWS;
+}
+
+/*
+ * Copy an entire tokenrow into another, at tp.
+ * It is assumed that there is enough space.
+ * Not strictly conforming.
+ */
+void
+movetokenrow(Tokenrow *dtr, Tokenrow *str)
+{
+ int nby;
+
+ /* nby = sizeof(Token) * (str->lp - str->bp); */
+ nby = (char *)str->lp - (char *)str->bp;
+ memmove(dtr->tp, str->bp, nby);
+}
+
+/*
+ * Move the tokens in a row, starting at tr->tp, rightward by nt tokens;
+ * nt may be negative (left move).
+ * The row may need to be grown.
+ * Non-strictly conforming because of the (char *), but easily fixed
+ */
+void
+adjustrow(Tokenrow *trp, int nt)
+{
+ int nby, size;
+
+ if (nt==0)
+ return;
+ size = (trp->lp - trp->bp) + nt;
+ while (size > trp->max)
+ growtokenrow(trp);
+ /* nby = sizeof(Token) * (trp->lp - trp->tp); */
+ nby = (char *)trp->lp - (char *)trp->tp;
+ if (nby)
+ memmove(trp->tp+nt, trp->tp, nby);
+ trp->lp += nt;
+}
+
+/*
+ * Copy a row of tokens into the destination holder, allocating
+ * the space for the contents. Return the destination.
+ */
+Tokenrow *
+copytokenrow(Tokenrow *dtr, Tokenrow *str)
+{
+ int len = rowlen(str);
+
+ maketokenrow(len, dtr);
+ movetokenrow(dtr, str);
+ dtr->lp += len;
+ return dtr;
+}
+
+/*
+ * Produce a copy of a row of tokens. Start at trp->tp.
+ * The value strings are copied as well. The first token
+ * has WS available.
+ */
+Tokenrow *
+normtokenrow(Tokenrow *trp)
+{
+ Token *tp;
+ Tokenrow *ntrp = new(Tokenrow);
+ int len;
+
+ len = trp->lp - trp->tp;
+ if (len<=0)
+ len = 1;
+ maketokenrow(len, ntrp);
+ for (tp=trp->tp; tp < trp->lp; tp++) {
+ *ntrp->lp = *tp;
+ if (tp->len) {
+ ntrp->lp->t = newstring(tp->t, tp->len, 1);
+ *ntrp->lp->t++ = ' ';
+ if (tp->wslen)
+ ntrp->lp->wslen = 1;
+ }
+ ntrp->lp++;
+ }
+ if (ntrp->lp > ntrp->bp)
+ ntrp->bp->wslen = 0;
+ return ntrp;
+}
+
+/*
+ * Debugging
+ */
+void
+peektokens(Tokenrow *trp, char *str)
+{
+ Token *tp;
+
+ tp = trp->tp;
+ flushout();
+ if (str)
+ fprintf(stderr, "%s ", str);
+ if (tp<trp->bp || tp>trp->lp)
+ fprintf(stderr, "(tp offset %d) ", tp-trp->bp);
+ for (tp=trp->bp; tp<trp->lp && tp<trp->bp+32; tp++) {
+ if (tp->type!=NL) {
+ int c = tp->t[tp->len];
+ tp->t[tp->len] = 0;
+ fprintf(stderr, "%s", tp->t);
+ tp->t[tp->len] = c;
+ }
+ if (tp->type==NAME) {
+ fprintf(stderr, tp==trp->tp?"{*":"{");
+ prhideset(tp->hideset);
+ fprintf(stderr, "} ");
+ } else
+ fprintf(stderr, tp==trp->tp?"{%x*} ":"{%x} ", tp->type);
+ }
+ fprintf(stderr, "\n");
+ fflush(stderr);
+}
+
+void
+puttokens(Tokenrow *trp)
+{
+ Token *tp;
+ int len;
+ uchar *p;
+
+ if (verbose)
+ peektokens(trp, "");
+ tp = trp->bp;
+ for (; tp<trp->lp; tp++) {
+ len = tp->len+tp->wslen;
+ p = tp->t-tp->wslen;
+ while (tp<trp->lp-1 && p+len == (tp+1)->t - (tp+1)->wslen) {
+ tp++;
+ len += tp->wslen+tp->len;
+ }
+ if (len>OBS/2) { /* handle giant token */
+ if (wbp > wbuf)
+ write(1, wbuf, wbp-wbuf);
+ write(1, (char *)p, len);
+ wbp = wbuf;
+ } else {
+ memcpy(wbp, p, len);
+ wbp += len;
+ }
+ if (wbp >= &wbuf[OBS]) {
+ write(1, wbuf, OBS);
+ if (wbp > &wbuf[OBS])
+ memcpy(wbuf, wbuf+OBS, wbp - &wbuf[OBS]);
+ wbp -= OBS;
+ }
+ }
+ trp->tp = tp;
+ if (cursource->fd==0)
+ flushout();
+}
+
+void
+flushout(void)
+{
+ if (wbp>wbuf) {
+ write(1, wbuf, wbp-wbuf);
+ wbp = wbuf;
+ }
+}
+
+/*
+ * turn a row into just a newline
+ */
+void
+setempty(Tokenrow *trp)
+{
+ trp->tp = trp->bp;
+ trp->lp = trp->bp+1;
+ *trp->bp = nltoken;
+}
+
+/*
+ * generate a number
+ */
+char *
+outnum(char *p, int n)
+{
+ if (n>=10)
+ p = outnum(p, n/10);
+ *p++ = n%10 + '0';
+ return p;
+}
+
+/*
+ * allocate and initialize a new string from s, of length l, at offset o
+ * Null terminated.
+ */
+uchar *
+newstring(uchar *s, int l, int o)
+{
+ uchar *ns = (uchar *)domalloc(l+o+1);
+
+ ns[l+o] = '\0';
+ return (uchar*)strncpy((char*)ns+o, (char*)s, l) - o;
+}
diff --git a/code/tools/lcc/cpp/unix.c b/code/tools/lcc/cpp/unix.c
new file mode 100644
index 0000000..17986d8
--- /dev/null
+++ b/code/tools/lcc/cpp/unix.c
@@ -0,0 +1,128 @@
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpp.h"
+
+extern int lcc_getopt(int, char *const *, const char *);
+extern char *optarg, rcsid[];
+extern int optind;
+int verbose;
+int Mflag; /* only print active include files */
+char *objname; /* "src.$O: " */
+int Cplusplus = 1;
+
+void
+setup(int argc, char **argv)
+{
+ int c, fd, i;
+ char *fp, *dp;
+ Tokenrow tr;
+ extern void setup_kwtab(void);
+ uchar *includeDirs[ NINCLUDE ] = { 0 };
+ int numIncludeDirs = 0;
+
+ setup_kwtab();
+ while ((c = lcc_getopt(argc, argv, "MNOVv+I:D:U:F:lg")) != -1)
+ switch (c) {
+ case 'N':
+ for (i=0; i<NINCLUDE; i++)
+ if (includelist[i].always==1)
+ includelist[i].deleted = 1;
+ break;
+ case 'I':
+ includeDirs[ numIncludeDirs++ ] = newstring( (uchar *)optarg, strlen( optarg ), 0 );
+ break;
+ case 'D':
+ case 'U':
+ setsource("<cmdarg>", -1, optarg);
+ maketokenrow(3, &tr);
+ gettokens(&tr, 1);
+ doadefine(&tr, c);
+ unsetsource();
+ break;
+ case 'M':
+ Mflag++;
+ break;
+ case 'v':
+ fprintf(stderr, "%s %s\n", argv[0], rcsid);
+ break;
+ case 'V':
+ verbose++;
+ break;
+ case '+':
+ Cplusplus++;
+ break;
+ default:
+ break;
+ }
+ dp = ".";
+ fp = "<stdin>";
+ fd = 0;
+ if (optind<argc) {
+ dp = basepath( argv[optind] );
+ fp = (char*)newstring((uchar*)argv[optind], strlen(argv[optind]), 0);
+ if ((fd = open(fp, 0)) <= 0)
+ error(FATAL, "Can't open input file %s", fp);
+ }
+ if (optind+1<argc) {
+ int fdo = creat(argv[optind+1], 0666);
+ if (fdo<0)
+ error(FATAL, "Can't open output file %s", argv[optind+1]);
+ dup2(fdo, 1);
+ }
+ if(Mflag)
+ setobjname(fp);
+ includelist[NINCLUDE-1].always = 0;
+ includelist[NINCLUDE-1].file = dp;
+
+ for( i = 0; i < numIncludeDirs; i++ )
+ appendDirToIncludeList( (char *)includeDirs[ i ] );
+
+ setsource(fp, fd, NULL);
+}
+
+
+char *basepath( char *fname )
+{
+ char *dp = ".";
+ char *p;
+ if ((p = strrchr(fname, '/')) != NULL) {
+ int dlen = p - fname;
+ dp = (char*)newstring((uchar*)fname, dlen+1, 0);
+ dp[dlen] = '\0';
+ }
+
+ return dp;
+}
+
+/* memmove is defined here because some vendors don't provide it at
+ all and others do a terrible job (like calling malloc) */
+// -- ouch, that hurts -- ln
+#ifndef MACOS_X /* always use the system memmove() on Mac OS X. --ryan. */
+#ifdef memmove
+#undef memmove
+#endif
+void *
+memmove(void *dp, const void *sp, size_t n)
+{
+ unsigned char *cdp, *csp;
+
+ if (n<=0)
+ return 0;
+ cdp = dp;
+ csp = (unsigned char *)sp;
+ if (cdp < csp) {
+ do {
+ *cdp++ = *csp++;
+ } while (--n);
+ } else {
+ cdp += n;
+ csp += n;
+ do {
+ *--cdp = *--csp;
+ } while (--n);
+ }
+ return 0;
+}
+#endif
diff --git a/code/tools/lcc/doc/4.html b/code/tools/lcc/doc/4.html
new file mode 100644
index 0000000..a2e1213
--- /dev/null
+++ b/code/tools/lcc/doc/4.html
@@ -0,0 +1,754 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+
+<head>
+<link HREF="mailto:drh at microsoft.com" REV="made" TITLE="David R. Hanson">
+<title>The lcc 4.1 Code-Generation Interface</title>
+</head>
+
+<body>
+
+<h1>The lcc 4.1 Code-Generation Interface</h1>
+
+<p ALIGN="LEFT"><strong><a HREF="http://www.research.microsoft.com/~cwfraser/">Christopher
+W. Fraser</a> and <a HREF="http://www.research.microsoft.com/~drh/">David R. Hanson</a>, <a
+HREF="http://www.research.microsoft.com/">Microsoft Research</a></strong></p>
+
+<h2>Contents</h2>
+
+<dir>
+ <li><a HREF="#intro">Introduction</a> </li>
+ <li><a HREF="#metrics">5.1 Type Metrics</a></li>
+ <li><a HREF="#symbols">5.3 Symbols</a> </li>
+ <li><a HREF="#operators">5.5 Dag Operators</a></li>
+ <li><a HREF="#flags">5.6 Interface Flags</a></li>
+ <li><a HREF="#definitions">5.8 Definitions</a></li>
+ <li><a HREF="#constants">5.9 Constants</a></li>
+ <li><a HREF="#upcalls">5.12 Upcalls</a></li>
+</dir>
+
+<h2><a NAME="intro">Introduction</a></h2>
+
+<p>Version 4.1 is the latest release of <a
+HREF="http://www.cs.princeton.edu/software/lcc/">lcc</a>, the ANSI C compiler described in
+our book <cite>A Retargetable C Compiler: Design and Implementation</cite>
+(Addison-Wesley, 1995, ISBN 0-8053-1670-1). This document summarizes the differences
+between the 4.1 code-generation interface and the 3.x interface described in Chap. 5 of <cite>A
+Retargetable C Compiler</cite>.</p>
+
+<p>Previous versions of lcc supported only three sizes of integers, two sizes of floats,
+and insisted that pointers fit in unsigned integers (see Sec. 5.1 of <cite>A Retargetable
+C Compiler</cite>). These assumptions simplified the compiler, and were suitable for
+32-bit architectures. But on 64-bit architectures, such as the DEC ALPHA, it's natural to
+have four sizes of integers and perhaps three sizes of floats, and on 16-bit
+architectures, 32-bit pointers don't fit in unsigned integers. Also, the 3.x constaints
+limited the use of lcc's back ends for other languages, such as Java.</p>
+
+<p>Version 4.x removes all of these restrictions: It supports any number of sizes for
+integers and floats, and the size of pointers need not be related to the size of any of
+the integer types. The major changes in the code-generation interface are:
+
+<ul>
+ <li>The number of type suffixes has been reduced to 6.</li>
+ <li>Dag operators are composed of a generic operator, a type suffix, and a size.</li>
+ <li>Unsigned variants of several operators have been added.</li>
+ <li>Several interface functions have new signatures.</li>
+</ul>
+
+<p>In addition, version 4.x is written in ANSI C and uses the standard I/O library and
+other standard C functions.</p>
+
+<p>The sections below parallel the subsections of Chap. 5 of <cite>A Retargetable C
+Compiler</cite> and summarize the differences between the 3.x and 4.x code-generation
+interface. Unaffected subsections are omitted. Page citations refer to pages in <cite>A
+Retargetable C Compiler</cite>.</p>
+
+<h2><a NAME="metrics">5.1 Type Metrics</a></h2>
+
+<p>There are now 10 metrics in an interface record:</p>
+
+<pre>Metrics charmetric;
+Metrics shortmetric;
+Metrics intmetric;
+Metrics longmetric;
+Metrics longlongmetric;
+Metrics floatmetric;
+Metrics doublemetric;
+Metrics longdoublemetric;
+Metrics ptrmetric;
+Metrics structmetric;</pre>
+
+<p>Each of these specifies the size and alignment of the corresponding type. <code>ptrmetric</code>
+describes all pointers.</p>
+
+<h2><a NAME="symbols">5.3 Symbols</a></h2>
+
+<p>The actual value of a constant is stored in the <code>u.c.v</code> field of a symbol,
+which holds a <code>Value</code>:</p>
+
+<pre>typedef union value {
+ long i;
+ unsigned long u;
+ long double d;
+ void *p;
+ void (*g)(void);
+} Value;</pre>
+
+<p>The value is stored in the appropriate field according to its type, which is given by
+the symbol's <code>type</code> field.</p>
+
+<h2><a NAME="operators">5.5 Dag Operators</a></h2>
+
+<p>The <code>op</code> field a of <code>node</code> structure holds a dag operator, which
+consists of a generic operator, a type suffix, and a size indicator. The type suffixes
+are:</p>
+
+<pre>enum {
+ F=FLOAT,
+ I=INT,
+ U=UNSIGNED,
+ P=POINTER,
+ V=VOID,
+ B=STRUCT
+};
+
+#define sizeop(n) ((n)<<10)</pre>
+
+<p>Given a generic operator <code>o</code>, a type suffix <code>t</code>, and a size <code>s</code>,
+a type- and size-specific operator is formed by <code>o+t+sizeop(s)</code>. For example, <code>ADD+F+sizeop(4)</code>
+forms the operator <code>ADDF4</code>, which denotes the sum of two 4-byte floats.
+Similarly, <code>ADD+F+sizeop(8)</code> forms <code>ADDF8</code>, which denotes 8-byte
+floating addition. In the 3.x code-generation interface, <code>ADDF</code> and <code>ADDD</code>
+denoted these operations. There was no size indicator in the 3.x operators because the
+type suffix supplied both a type and a size.</p>
+
+<p>Table 5.1 lists each generic operator, its valid type suffixes, and the number of <code>kids</code>
+and <code>syms</code> that it uses; multiple values for <code>kids</code> indicate
+type-specific variants. The notations in the <strong>syms</strong> column give the number
+of <code>syms</code> values and a one-letter code that suggests their uses: 1V indicates
+that <code>syms[0]</code> points to a symbol for a variable, 1C indicates that <code>syms[0]</code>
+is a constant, and 1L indicates that <code>syms[0]</code> is a label. For 1S, <code>syms[0]</code>
+is a constant whose value is a size in bytes; 2S adds <code>syms[1]</code>, which is a
+constant whose value is an alignment. For most operators, the type suffix and size
+indicator denote the type and size of operation to perform and the type and size of the
+result.</p>
+
+<table WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0">
+ <tr>
+ <td COLSPAN="6" ALIGN="CENTER"><strong>Table 5.1<img SRC="/~drh/resources/dot_clear.gif"
+ ALT="|" WIDTH="18" HEIGHT="1">Node Operators.</strong></td>
+ </tr>
+ <tr>
+ <td><strong>syms</strong></td>
+ <td><strong>kids</strong></td>
+ <td><strong>Operator</strong></td>
+ <td><strong>Type Suffixes</strong></td>
+ <td><strong>Sizes</strong></td>
+ <td><strong>Operation</strong></td>
+ </tr>
+ <tr>
+ <td>1V</td>
+ <td>0</td>
+ <td><code>ADDRF</code></td>
+ <td><code>...P..</code></td>
+ <td>p</td>
+ <td>address of a parameter</td>
+ </tr>
+ <tr>
+ <td>1V</td>
+ <td>0</td>
+ <td><code>ADDRG</code></td>
+ <td><code>...P..</code></td>
+ <td>p</td>
+ <td>address of a global</td>
+ </tr>
+ <tr>
+ <td>1V</td>
+ <td>0</td>
+ <td><code>ADDRL</code></td>
+ <td><code>...P..</code></td>
+ <td>p</td>
+ <td>address of a local</td>
+ </tr>
+ <tr>
+ <td>1C</td>
+ <td>0</td>
+ <td><code>CNST</code></td>
+ <td><code>FIUP..</code></td>
+ <td>fdx csilh p</td>
+ <td>constant</td>
+ </tr>
+ <tr ALIGN="LEFT" VALIGN="TOP">
+ <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="1" HEIGHT="12"></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>1</td>
+ <td><code>BCOM</code></td>
+ <td><code>.IU...</code></td>
+ <td>ilh</td>
+ <td>bitwise complement</td>
+ </tr>
+ <tr>
+ <td>1S</td>
+ <td>1</td>
+ <td><code>CVF</code></td>
+ <td><code>FI....</code></td>
+ <td>fdx ilh</td>
+ <td>convert from float</td>
+ </tr>
+ <tr>
+ <td>1S</td>
+ <td>1</td>
+ <td><code>CVI</code></td>
+ <td><code>FIU...</code></td>
+ <td>fdx csilh csilhp</td>
+ <td>convert from signed integer</td>
+ </tr>
+ <tr>
+ <td>1S</td>
+ <td>1</td>
+ <td><code>CVP</code></td>
+ <td><code>..U..</code></td>
+ <td>p</td>
+ <td>convert from pointer</td>
+ </tr>
+ <tr>
+ <td>1S</td>
+ <td>1</td>
+ <td><code>CVU</code></td>
+ <td><code>.IUP..</code></td>
+ <td>csilh p</td>
+ <td>convert from unsigned integer</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>1</td>
+ <td><code>INDIR</code></td>
+ <td><code>FIUP.B</code></td>
+ <td>fdx csilh p</td>
+ <td>fetch</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>1</td>
+ <td><code>NEG</code></td>
+ <td><code>FI....</code></td>
+ <td>fdx ilh</td>
+ <td>negation</td>
+ </tr>
+ <tr>
+ <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="1" HEIGHT="12"></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>2</td>
+ <td><code>ADD</code></td>
+ <td><code>FIUP..</code></td>
+ <td>fdx ilh ilhp p</td>
+ <td>addition</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>2</td>
+ <td><code>BAND</code></td>
+ <td><code>.IU...</code></td>
+ <td>ilh</td>
+ <td>bitwise AND</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>2</td>
+ <td><code>BOR</code></td>
+ <td><code>.IU...</code></td>
+ <td>ilh</td>
+ <td>bitwise inclusive OR</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>2</td>
+ <td><code>BXOR</code></td>
+ <td><code>.IU...</code></td>
+ <td>ilh</td>
+ <td>bitwise exclusive OR</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>2</td>
+ <td><code>DIV</code></td>
+ <td><code>FIU...</code></td>
+ <td>fdx ilh</td>
+ <td>division</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>2</td>
+ <td><code>LSH</code></td>
+ <td><code>.IU...</code></td>
+ <td>ilh</td>
+ <td>left shift</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>2</td>
+ <td><code>MOD</code></td>
+ <td><code>.IU...</code></td>
+ <td>ilh</td>
+ <td>modulus</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>2</td>
+ <td><code>MUL</code></td>
+ <td><code>FIU...</code></td>
+ <td>fdx ilh</td>
+ <td>multiplication</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>2</td>
+ <td><code>RSH</code></td>
+ <td><code>.IU...</code></td>
+ <td>ilh</td>
+ <td>right shift</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>2</td>
+ <td><code>SUB</code></td>
+ <td><code>FIUP..</code></td>
+ <td>fdx ilh ilhp p</td>
+ <td>subtraction</td>
+ </tr>
+ <tr>
+ <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="1" HEIGHT="12"></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>2S</td>
+ <td>2</td>
+ <td><code>ASGN</code></td>
+ <td><code>FIUP.B</code></td>
+ <td>fdx csilh p</td>
+ <td>assignment</td>
+ </tr>
+ <tr>
+ <td>1L</td>
+ <td>2</td>
+ <td><code>EQ</code></td>
+ <td><code>FIU...</code></td>
+ <td>fdx ilh ilhp</td>
+ <td>jump if equal</td>
+ </tr>
+ <tr>
+ <td>1L</td>
+ <td>2</td>
+ <td><code>GE</code></td>
+ <td><code>FIU...</code></td>
+ <td>fdx ilh ilhp</td>
+ <td>jump if greater than or equal</td>
+ </tr>
+ <tr>
+ <td>1L</td>
+ <td>2</td>
+ <td><code>GT</code></td>
+ <td><code>FIU...</code></td>
+ <td>fdx ilh ilhp</td>
+ <td>jump if greater than</td>
+ </tr>
+ <tr>
+ <td>1L</td>
+ <td>2</td>
+ <td><code>LE</code></td>
+ <td><code>FIU...</code></td>
+ <td>fdx ilh ilhp</td>
+ <td>jump if less than or equal</td>
+ </tr>
+ <tr>
+ <td>1L</td>
+ <td>2</td>
+ <td><code>LT</code></td>
+ <td><code>FIU...</code></td>
+ <td>fdx ilh ilhp</td>
+ <td>jump if less than</td>
+ </tr>
+ <tr>
+ <td>1L</td>
+ <td>2</td>
+ <td><code>NE</code></td>
+ <td><code>FIU...</code></td>
+ <td>fdx ilh ilhp</td>
+ <td>jump if not equal</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>2S</td>
+ <td>1</td>
+ <td><code>ARG</code></td>
+ <td><code>FIUP.B</code></td>
+ <td>fdx ilh p</td>
+ <td>argument</td>
+ </tr>
+ <tr>
+ <td>1</td>
+ <td>1 or 2</td>
+ <td><code>CALL</code></td>
+ <td><code>FIUPVB</code></td>
+ <td>fdx ilh p</td>
+ <td>function call</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>1</td>
+ <td><code>RET</code></td>
+ <td><code>FIUPV.</code></td>
+ <td>fdx ilh p</td>
+ <td>return from function</td>
+ </tr>
+ <tr>
+ <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="1" HEIGHT="12"></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>1</td>
+ <td><code>JUMP</code></td>
+ <td><code>....V.</code></td>
+ <td></td>
+ <td>unconditional jump</td>
+ </tr>
+ <tr>
+ <td>1L</td>
+ <td>0</td>
+ <td><code>LABEL</code></td>
+ <td><code>....V.</code></td>
+ <td></td>
+ <td>label definition</td>
+ </tr>
+</table>
+
+<p>The entries in the <strong>Sizes</strong> column indicate sizes of the operators that
+back ends must implement. Letters denote the size of float (f), double (d), long double
+(x), character (c), short integer (s), integer (i), long integer (l), "long
+long" integer (h) , and pointer (p). These sizes are separated into sets for each
+type suffix, except that a single set is used for both I and U when the set for I is
+identical to the set for U.</p>
+
+<p>The actual values for the size indicators, fdxcsilhp, depend on the target. A
+specification like <code>ADDF</code>f denotes the operator <code>ADD+F+sizeop(</code>f<code>)</code>,
+where "f" is replaced by a target-dependent value, e.g., <code>ADDF4</code> and <code>ADDF8</code>.
+For example, back ends must implement the following <code>CVI</code> and <code>MUL</code>
+operators.</p>
+
+<blockquote>
+ <p><code>CVIF</code>f <code>CVIF</code>d <code>CVIF</code>x<br>
+ <code>CVII</code>c <code>CVII</code>s <code>CVII</code>i <code>CVII</code>l <code>CVII</code>h<br>
+ <code>CVIU</code>c <code>CVIU</code>s <code>CVIU</code>i <code>CVIU</code>l <code>CVIU</code>h
+ <code>CVIU</code>p<br>
+ <br>
+ <code>MULF</code>f <code>MULF</code>d <code>MULF</code>x<br>
+ <code>MULI</code>i <code>MULI</code>l <code>MULI</code>h<br>
+ <code>MULU</code>i <code>MULU</code>l <code>MULU</code>h</p>
+</blockquote>
+
+<p>On most platforms, there are fewer than three sizes of floats and six sizes of
+integers, and pointers are usually the same size as one of the integers. And lcc doesn't
+support the "long long" type, so h is not currently used. So the set of
+platform-specific operators is usually smaller than the list above suggests. For example,
+the X86, SPARC, and MIPS back ends implement the following <code>CVI</code> and <code>MUL</code>
+operators.</p>
+
+<blockquote>
+ <p><code>CVIF</code>4 <code>CVIF</code>8<br>
+ <code>CVII</code>1 <code>CVII</code>2 <code>CVII</code>4<br>
+ <code>CVIU</code>1 <code>CVIU</code>2 <code>CVIU</code>4 <br>
+ <br>
+ <code>MULF</code>4 <code>MULF</code>8<br>
+ <code>MULI</code>4<br>
+ <code>MULU</code>4</p>
+</blockquote>
+
+<p>The set of operators is thus target-dependent; for example, <code>ADDI8</code> appears
+only if the target supports an 8-byte integer type. <a
+HREF="ftp://ftp.cs.princeton.edu/pub/packages/lcc/contrib/ops.c"><code>ops.c</code></a> is
+a program that, given a set of sizes, prints the required operators and their values,
+e.g.,</p>
+
+<blockquote>
+ <pre>% <em>ops c=1 s=2 i=4 l=4 h=4 f=4 d=8 x=8 p=4</em>
+...
+ CVIF4=4225 CVIF8=8321
+ CVII1=1157 CVII2=2181 CVII4=4229
+ CVIU1=1158 CVIU2=2182 CVIU4=4230
+...
+ MULF4=4561 MULF8=8657
+ MULI4=4565
+ MULU4=4566
+...
+131 operators</pre>
+</blockquote>
+
+<p>The type suffix for a conversion operator denotes the type of the result and the size
+indicator gives the size of the result. For example, <code>CVUI4</code> converts an
+unsigned (<code>U</code>) to a 4-byte signed integer (<code>I4</code>). The <code>syms[0]</code>
+field points to a symbol-table entry for a integer constant that gives the size of the
+source operand. For example, if <code>syms[0]</code> in a <code>CVUI4</code> points to a
+symbol-table entry for 2, the conversion widens a 2-byte unsigned integer to a 4-byte
+signed integer. Conversions that widen unsigned integers zero-extend; those that widen
+signed integers sign-extend.</p>
+
+<p>The front end composes conversions between types <em>T</em><sub>1</sub> and <em>T</em><sub>2</sub>
+by widening <em>T</em><sub>1</sub> to it's "supertype", if necessary, converting
+that result to <em>T</em><sub>2</sub>'s supertype, then narrowing the result to <em>T</em><sub>2</sub>,
+if necessary. The following table lists the supertypes; omitted entries are their own
+supertypes.</p>
+
+<blockquote>
+ <table BORDER="0" CELLPADDING="0" CELLSPACING="0">
+ <tr>
+ <td><strong>Type</strong></td>
+ <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="24" HEIGHT="1"></td>
+ <td><strong>Supertype</strong></td>
+ </tr>
+ <tr>
+ <td>signed char</td>
+ <td></td>
+ <td>int</td>
+ </tr>
+ <tr>
+ <td>signed short</td>
+ <td></td>
+ <td>int</td>
+ </tr>
+ <tr ALIGN="LEFT" VALIGN="TOP">
+ <td>unsigned char</td>
+ <td></td>
+ <td>int, if sizeof (char) < sizeof (int)<br>
+ unsigned, otherwise</td>
+ </tr>
+ <tr ALIGN="LEFT" VALIGN="TOP">
+ <td>unsigned short</td>
+ <td></td>
+ <td>int, if sizeof (short) < sizeof (int)<br>
+ unsigned, otherwise</td>
+ </tr>
+ <tr ALIGN="LEFT" VALIGN="TOP">
+ <td>void *</td>
+ <td></td>
+ <td>an unsigned type as large as a pointer</td>
+ </tr>
+ </table>
+</blockquote>
+
+<p>Pointers are converted to an unsigned type of the same size, even when that type is not
+one of the integer types.</p>
+
+<p>For example, the front end converts a signed short to a float by first converting it to
+an int and then to a float. It converts an unsigned short to an int with a single <code>CVUI</code>i
+conversion, when shorts are smaller than ints.</p>
+
+<p>There are now signed and unsigned variants of <code>ASGN</code>, <code>INDIR</code>, <code>BCOM</code>,
+<code>BOR</code>, <code>BXOR</code>, <code>BAND</code>, <code>ARG</code>, <code>CALL</code>,
+and <code>RET</code> to simplify code generation on platforms that use different
+instructions or register set for signed and unsigned operations. Likewise there are now
+pointer variants of <code>ASGN</code>, <code>INDIR</code>, <code>ARG</code>, <code>CALL</code>,
+and <code>RET</code>.</p>
+
+<h2><a NAME="flags">5.6 Interface Flags</a></h2>
+
+<pre>unsigned unsigned_char:1;</pre>
+
+<p>tells the front end whether plain characters are signed or unsigned. If it's zero, char
+is a signed type; otherwise, char is an unsigned type.</p>
+
+<p>All the interface flags can be set by command-line options, e.g., <code>-Wf-unsigned_char=1</code>
+causes plain characters to be unsigned.</p>
+
+<h2><a NAME="definitions">5.8 Definitions</a></h2>
+
+<p>The front end announces local variables by calling</p>
+
+<pre>void (*local)(Symbol);</pre>
+
+<p>It announces temporaries likewise; these have the symbol's <code>temporary</code> flag
+set, which indicates that the symbol will be used only in the next call to <code>gen</code>.
+If a temporary's <code>u.t.cse</code> field is nonnull, it points to the node that
+computes the value assigned to the temporary; see page 346.</p>
+
+<p>The front end calls</p>
+
+<pre>void (*address)(Symbol p, Symbol q, long n);</pre>
+
+<p>to initialize <code>q</code> to a symbol that represents an address of the form <em>x</em>+<code>n</code>,
+where <em>x</em> is the address represented by <code>p</code> and the long integer <code>n</code>
+is positive or negative.</p>
+
+<h2><a NAME="constants">5.9 Constants</a></h2>
+
+<p>The interface function</p>
+
+<pre>void (*defconst)(int suffix, int size, Value v);</pre>
+
+<p>initializes constants. defconst emits directives to define a cell and initialize it to
+a constant value. v is the constant value, suffix identifies the type of the value, and
+size is the size of the value in bytes. The value of suffix indicates which field of v
+holds the value, as shown in the following table.</p>
+
+<blockquote>
+ <table BORDER="0" CELLPADDING="1" CELLSPACING="1">
+ <tr>
+ <td><strong>suffix</strong></td>
+ <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="24" HEIGHT="1"></td>
+ <td><strong>v Field</strong></td>
+ <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="24" HEIGHT="1"></td>
+ <td><strong>size</strong></td>
+ </tr>
+ <tr>
+ <td><code>F</code></td>
+ <td></td>
+ <td><code>v.d</code></td>
+ <td></td>
+ <td>float, double, long double</td>
+ </tr>
+ <tr>
+ <td><code>I</code></td>
+ <td></td>
+ <td><code>v.i</code></td>
+ <td></td>
+ <td>signed char, signed short, signed int, signed long</td>
+ </tr>
+ <tr>
+ <td><code>U</code></td>
+ <td></td>
+ <td><code>v.u</code></td>
+ <td></td>
+ <td>unsigned char, unsigned short, unsigned int, unsigned long</td>
+ </tr>
+ <tr>
+ <td><code>P</code></td>
+ <td></td>
+ <td><code>v.p</code></td>
+ <td></td>
+ <td>void *</td>
+ </tr>
+ </table>
+</blockquote>
+
+<p><code>defconst</code> must narrow <code>v.</code>x when <code>size</code> is less than <code>sizeof</code>
+<code>v.</code>x; e.g., to emit an unsigned char, <code>defconst</code> should emit <code>(unsigned
+char)v.i</code>.</p>
+
+<h2><a NAME="upcalls">5.12 Upcalls</a></h2>
+
+<p>lcc 4.x uses standard I/O and its I/O functions have been changed accordingly. lcc
+reads input from the standard input, emits code to the standard output, and writes
+diagnostics to the standard error output. It uses <code>freopen</code> to redirect these
+streams to explicit files, when necessary.</p>
+
+<p><code>bp</code>, <code>outflush</code>, and <code>outs</code> have been eliminated.</p>
+
+<pre>extern void fprint(FILE *f, const char *fmt, ...);
+extern void print(const char *fmt, ...);</pre>
+
+<p>print formatted data to file <code>f</code> (<code>fprint</code>) or the standard
+output (<code>print</code>). These functions are like standard C's <code>printf</code> and
+<code>fprintf</code>, but support only some of the standard conversion specifiers and do
+not support flags, precision, and field-width specifications. They support the following
+new conversion specifiers in addition to those described on page 99.</p>
+
+<blockquote>
+ <table BORDER="0" CELLPADDING="0" CELLSPACING="0">
+ <tr>
+ <td><strong>Specifiers</strong></td>
+ <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="24" HEIGHT="1"></td>
+ <td><strong>Corresponding printf Specifiers</strong></td>
+ </tr>
+ <tr>
+ <td><code>%c</code></td>
+ <td></td>
+ <td><code>%c</code></td>
+ </tr>
+ <tr>
+ <td><code>%d %D</code></td>
+ <td></td>
+ <td><code>%d %ld</code></td>
+ </tr>
+ <tr>
+ <td><code>%u %U</code></td>
+ <td></td>
+ <td><code>%u %lu</code></td>
+ </tr>
+ <tr>
+ <td><code>%x %X</code></td>
+ <td></td>
+ <td><code>%x %lx</code></td>
+ </tr>
+ <tr>
+ <td><code>%f %e %g</code></td>
+ <td></td>
+ <td><code>%e %f %g</code></td>
+ </tr>
+ <tr ALIGN="LEFT" VALIGN="TOP">
+ <td><code>%p</code></td>
+ <td></td>
+ <td>Converts the corresponding void * argument to unsigned long and prints it with the <code>printf</code>
+ <code>%#x</code> specifier or just <code>%x</code> when the argument is null.</td>
+ </tr>
+ <tr ALIGN="LEFT" VALIGN="TOP">
+ <td><code>%I</code></td>
+ <td></td>
+ <td>Prints the number of spaces given by the corresponding argument.</td>
+ </tr>
+ </table>
+</blockquote>
+
+<pre>#define generic(op) ((op)&0x3F0)
+#define specific(op) ((op)&0x3FF)</pre>
+
+<p><code>generic(op)</code> returns the generic variant of <code>op</code>; that is,
+without its type suffix and size indicator. <code>specific(op)</code> returns the
+type-specific variant of <code>op</code>; that is, without its size indicator.</p>
+
+<p><code>newconst</code> has been replaced by</p>
+
+<pre>extern Symbol intconst(int n);</pre>
+
+<p>which installs the integer constant <code>n</code> in the symbol table, if necessary,
+and returns a pointer to the symbol-table entry.</p>
+
+<hr>
+
+<address>
+ <a HREF="http://www.research.microsoft.com/~cwfraser/">Chris Fraser</a> / <a
+ HREF="mailto:cwfraser at microsoft.com">cwfraser at microsoft.com</a><br>
+ <a HREF="http://www.research.microsoft.com/~drh/">David Hanson</a> / <a
+ HREF="mailto:drh at microsoft.com">drh at microsoft.com</a><br>
+ $Revision: 145 $ $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $
+</address>
+</body>
+</html>
diff --git a/code/tools/lcc/doc/bprint.1 b/code/tools/lcc/doc/bprint.1
new file mode 100644
index 0000000..8cf9971
--- /dev/null
+++ b/code/tools/lcc/doc/bprint.1
@@ -0,0 +1,83 @@
+.\" $Id: bprint.1 145 2001-10-17 21:53:10Z timo $
+.TH BPRINT 1 "local \- $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $"
+.SH NAME
+bprint \- expression profiler
+.SH SYNOPSIS
+.B bprint
+[
+.I option ...
+]
+[
+.I file ...
+]
+.SH DESCRIPTION
+.I bprint
+produces on the standard output a listing of the programs compiled by
+.I lcc
+with the
+.B \-b
+option.
+Executing an
+.B a.out
+so compiled appends profiling data to
+.BR prof.out .
+The first token of each expression in the listing is preceded
+by the number of times it was executed
+enclosed in angle brackets as determined from the data in
+.BR prof.out .
+.I bprint
+interprets the following options.
+.TP
+.B \-c
+Compress the
+.B prof.out
+file, which otherwise grows with every execution of
+.BR a.out .
+.TP
+.B \-b
+Print an annotated listing as described above.
+.TP
+.B \-n
+Include line numbers in the listing.
+.TP
+.B \-f
+Print only the number of invocations of each function.
+A second
+.B \-f
+summarizes call sites instead of callers.
+.TP
+.BI \-I \*Sdir
+specifies additional directories in which to seek
+files given in
+.B prof.out
+that do not begin with `/'.
+.PP
+If any file names are given, only the requested data for those files are printed
+in the order presented.
+If no options are given,
+.B \-b
+is assumed.
+.SH FILES
+.PP
+.ta \w'$LCCDIR/liblcc.{a,lib}XX'u
+.nf
+prof.out profiling data
+$LCCDIR/liblcc.{a,lib} \fIlcc\fP-specific library
+.SH "SEE ALSO"
+.IR lcc (1),
+.IR prof (1)
+.SH BUGS
+Macros and comments can confuse
+.I bprint
+because it uses post-expansion source coordinates
+to annotate pre-expansion source files.
+If
+.I bprint
+sees that it's about to print a statement count
+.I inside
+a number or identifier, it moves the count to just
+.I before
+the token.
+.PP
+Can't cope with an ill-formed
+.BR prof.out .
diff --git a/code/tools/lcc/doc/bprint.pdf b/code/tools/lcc/doc/bprint.pdf
new file mode 100644
index 0000000..1b11963
Binary files /dev/null and b/code/tools/lcc/doc/bprint.pdf differ
diff --git a/code/tools/lcc/doc/install.html b/code/tools/lcc/doc/install.html
new file mode 100644
index 0000000..3cc59a8
--- /dev/null
+++ b/code/tools/lcc/doc/install.html
@@ -0,0 +1,796 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+
+<head>
+<link HREF="mailto:drh at cs.princeton.edu" REV="made" TITLE="David R. Hanson">
+<title>Installing lcc</title>
+</head>
+
+<body>
+
+<h1>Installing lcc</h1>
+
+<p ALIGN="LEFT"><strong><a HREF="http://www.research.microsoft.com/~cwfraser/">Christopher
+W. Fraser</a> and <a HREF="http://www.research.microsoft.com/~drh/">David R. Hanson</a>, <a
+HREF="http://www.research.microsoft.com/">Microsoft Research</a></strong></p>
+
+<h2>Contents</h2>
+
+<dir>
+ <li><a HREF="#intro">Introduction</a></li>
+ <li><a HREF="#unix">Installation on UNIX</a></li>
+ <li><a HREF="#driver">Building the Driver</a></li>
+ <li><a HREF="#rcc">Building the Compiler and Accessories</a></li>
+ <li><a HREF="#win32">Installation on Windows NT 4.0 and Windows 95/98</a></li>
+ <li><a HREF="#bugs">Reporting Bugs</a></li>
+ <li><a HREF="#mailinglist">Keeping in Touch</a></li>
+</dir>
+
+<h2><a NAME="intro">Introduction</a></h2>
+
+<p><a HREF="http://www.cs.princeton.edu/software/lcc/">lcc</a> is the ANSI C compiler
+described in our book <cite>A Retargetable C Compiler: Design and Implementation</cite>
+(Addison-Wesley, 1995, ISBN 0-8053-1670-1).</p>
+
+<p>If you're installing lcc on a UNIX system, read the remainder of this section and
+continue with the next section. If you're installing lcc on a Windows NT 4.0 or Windows
+95/98 system, and you intend only to <u>use</u> lcc, you can run the <a
+href="ftp://ftp.cs.princeton.edu/pub/packages/lcc/lcc41.exe">InstallShield executable</a>,
+which installs the binaries and the documentation. If you want to <u>modify</u> lcc or <u>rebuild</u>
+it from the source files, you need the <a
+href="ftp://ftp.cs.princeton.edu/packages/lcc/lcc41.zip">complete distribution</a>, and
+you should read the rest of the section, the following three sections, and the <a
+HREF="#win32">Windows NT/95/98</a> section.</p>
+
+<p>Extract the distribution into its own directory. All non-absolute paths below are
+relative to this directory. The distribution holds the following subdirectories.</p>
+
+<blockquote>
+ <table BORDER="0" CELLPADDING="1" CELLSPACING="1" WIDTH="80%">
+ <tr>
+ <td><a HREF="../src"><code>src</code></a></td>
+ <td></td>
+ <td>source code</td>
+ </tr>
+ <tr>
+ <td><a HREF="../etc"><code>etc</code></a></td>
+ <td></td>
+ <td>driver, accessories</td>
+ </tr>
+ <tr>
+ <td><a HREF="../lib"><code>lib</code></a></td>
+ <td></td>
+ <td>runtime library source code</td>
+ </tr>
+ <tr>
+ <td><a HREF="../cpp"><code>cpp</code></a></td>
+ <td></td>
+ <td>preprocessor source code</td>
+ </tr>
+ <tr>
+ <td><a HREF="../lburg"><code>lburg</code></a></td>
+ <td></td>
+ <td>code-generator generator source code</td>
+ </tr>
+ <tr>
+ <td><a HREF="../doc"><code>doc</code></a></td>
+ <td></td>
+ <td>this document, man pages</td>
+ </tr>
+ <tr>
+ <td><code><a HREF="../include">include</a>/*/*</code></td>
+ <td></td>
+ <td>include files</td>
+ </tr>
+ <tr>
+ <td><a HREF="../tst"><code>tst</code></a></td>
+ <td></td>
+ <td>test suite</td>
+ </tr>
+ <tr>
+ <td><code><a HREF="../alpha">alpha</a>/*/tst</code></td>
+ <td></td>
+ <td>ALPHA test outputs</td>
+ </tr>
+ <tr>
+ <td><code><a HREF="../mips">mips</a>/*/tst</code></td>
+ <td></td>
+ <td>MIPS test outputs</td>
+ </tr>
+ <tr>
+ <td><code><a HREF="../sparc">sparc</a>/*/tst</code></td>
+ <td></td>
+ <td>SPARC test outputs</td>
+ </tr>
+ <tr>
+ <td><code><a HREF="../x86">x86</a>/*/tst</code></td>
+ <td></td>
+ <td>X86 test outputs</td>
+ </tr>
+ </table>
+</blockquote>
+
+<p><code>doc/install.html</code> is the HTML file for this document. <a HREF="4.html"><code>doc/4.html</code></a>
+describes the internal differences between lcc 3.x and 4.1.</p>
+
+<p>The installation makefile is designed so that lcc can be installed from a read-only
+file system or directory, which is common in networked environments, so the distribution
+can be unloaded on a central file server. <strong>You will need an existing ANSI/ISO C
+compiler to build and install lcc.</strong></p>
+
+<h2><a NAME="unix">Installation on UNIX</a></h2>
+
+<p>The compilation components (the preprocessor, include files, and compiler proper, etc.)
+are installed in a single <em>build directory</em>. On multi-platform systems supported by
+a central file server, it's common to store the build directory in a location specific to
+the platform and to the version of lcc, and to point a symbolic link to this location. For
+example,</p>
+
+<blockquote>
+ <pre>% ln -s /usr/local/lib/lcc-4.1/sparc-solaris /usr/local/lib/lcc</pre>
+</blockquote>
+
+<p>points <code>/usr/local/lib/lcc</code> to a build directory for lcc version 4.1 on the
+SPARC under Solaris. Links into <code>/usr/local/lib</code> are created for the programs <code>lcc</code>
+and <code>bprint</code>. Thus, a new distribution can be installed by building it in its
+own build directory and changing one symbolic link to point to that directory. If these
+conventions or their equivalents are followed, the host-specific parts of the driver
+program, <code>lcc</code>, can be used unmodified.</p>
+
+<p>Installation on a UNIX system involves the following steps. Below, the build directory
+is referred to as <code>BUILDDIR</code>.
+
+<ol>
+ <li>Create the build directory, using a version- and platform-specific naming convention as
+ suggested above, and record the name of this directory in the <code>BUILDDIR</code>
+ environment variable:<blockquote>
+ <pre>% setenv BUILDDIR /usr/local/lib/lcc-4.1/sparc-solaris
+% mkdir -p $BUILDDIR</pre>
+ </blockquote>
+ <p>Here and below, commands assume the C shell. Also, you'll need a version of <code>mkdir</code>
+ that supports the <code>-p</code> option, which creates intermediate directories as
+ necessary.</p>
+ </li>
+ <li>Copy the man pages to the repository for local man pages, e.g.,<blockquote>
+ <pre>% cp doc/*.1 /usr/local/man/man1</pre>
+ </blockquote>
+ <p>Some users copy the man pages to the build directory and create the appropriate
+ symbolic links, e.g., </p>
+ <blockquote>
+ <pre>% cp doc/*.1 $BUILDDIR
+% ln -s $BUILDDIR/*.1 /usr/local/man/man1</pre>
+ </blockquote>
+ </li>
+ <li>Platform-specific include files are in directories named <code>include/</code><em>target</em><code>/</code><em>os</em>.
+ Create the include directory in the build directory, and copy the include hierarchy for
+ your platform to this directory, e.g.,<blockquote>
+ <pre>% mkdir $BUILDDIR/include
+% cp -p -R include/sparc/solaris/* $BUILDDIR/include</pre>
+ </blockquote>
+ <p>Again, some users create a symbolic link to the appropriate directory in the
+ distribution instead of copying the include files. For example, at Princeton, the
+ distributions are stored under <code>/proj/pkg/lcc</code>, so the included files are
+ "installed" by creating one symbolic link: </p>
+ <blockquote>
+ <pre>% ln -s /proj/pkg/lcc/4.1/include/sparc/solaris $BUILDDIR/include</pre>
+ </blockquote>
+ <p>If you're installing lcc on Linux, you <em>must</em> also plant a symbolic link named <code>gcc</code>
+ to gcc's library directory, because lcc uses gcc's C preprocessor and most of gcc's header
+ files:</p>
+ <blockquote>
+ <pre>% ln -s /usr/lib/gcc-lib/i486-linux/2.7.2.2 $BUILDDIR/gcc</pre>
+ </blockquote>
+ <p>The library directory shown above may be different on your Linux machine; to determine
+ the correct directory, browse <code>/usr/lib/gcc-lib</code>, or execute</p>
+ <blockquote>
+ <pre>% cc -v tst/8q.c</pre>
+ </blockquote>
+ <p>and examine the diagnostic output. Make sure that <code>$BUILDDIR/gcc/cpp</code> and <code>$BUILDDIR/gcc/include</code>
+ point to, respectively, gcc's C preprocessor and header files. On Linux, lcc looks for
+ include files in <code>$BUILDDIR/include</code>, <code>$BUILDDIR/gcc/include</code>, and <code>/usr/include</code>,
+ in that order; see <a HREF="#driver"><em>Building the Driver</em></a> and <a
+ href="../etc/linux.c"><code>etc/linux.c</code></a> for details.</p>
+ </li>
+ <li>The <a HREF="../makefile"><code>makefile</code></a> includes the file named by the <code>CUSTOM</code>
+ macro; the default is <code>custom.mk</code>, and an empty <code>custom.mk</code> is
+ included in the distribution. If desired, prepare a site-specification customization file
+ and define <code>CUSTOM</code> to the path of that file when invoking make in steps 5 and
+ 6, e.g.,<blockquote>
+ <pre>make CUSTOM=/users/drh/solaris.mk</pre>
+ </blockquote>
+ <p>You can, for example, use customization files to record site-specific values for macros
+ instead of using environment variables, and to record targets for the steps in this list.</p>
+ </li>
+ <li>Build the host-specific driver, creating a custom host-specific part, if necessary. See <a
+ HREF="#driver"><em>Building the Driver</em></a>.</li>
+ <li>Build the preprocessor, compiler proper, library, and other accessories. See <a
+ HREF="#rcc"><em>Building the Compiler</em></a>.</li>
+ <li>Plant symbolic links to the build directory and to the installed programs, e.g.,<blockquote>
+ <pre>% ln -s $BUILDDIR /usr/local/lib/lcc
+% ln -s /usr/local/lib/{lcc,bprint} /usr/local/bin</pre>
+ </blockquote>
+ <p>Some users copy <code>bprint</code> and <code>lcc</code> into <code>/usr/local/bin</code>
+ instead of creating symbolic links. The advantange of creating the links for <code>lcc</code>
+ and <code>bprint</code> as shown is that, once established, they point indirectly to
+ whatever <code>/usr/local/lib/lcc</code> points to; installing a new version of lcc, say,
+ 4.2, can be done by changing <code>/usr/local/lib/lcc</code> to point to the 4.2 build
+ directory.</p>
+ </li>
+</ol>
+
+<h2><a NAME="driver">Building the Driver</a></h2>
+
+<p>The preprocessor, compiler, assembler, and loader are invoked by a driver program, <code>lcc</code>,
+which is similar to <code>cc</code> on most systems. It's described in the man page <code>doc/lcc.1</code>.
+The driver is built by combining the host-independent part, <a href="../etc/lcc.c"><code>etc/lcc.c</code></a>,
+with a small host-specific part. Distributed host-specific parts are named <code>etc/</code><em>os</em><code>.c</code>,
+where <em>os</em> is the name of the operating system for the host on which <code>lcc</code>
+is being installed. If you're following the installations conventions described above, you
+can probably use one of the host-specific parts unmodified; otherwise, pick one that is
+closely related to your platform, copy it to <em>whatever</em><code>.c</code>, and edit it
+as described below. You should not have to edit <code>etc/lcc.c</code>.</p>
+
+<p>We'll use <a HREF="../etc/solaris.c"><code>etc/solaris.c</code></a> as an example in
+describing how the host-specific part works. This example illustrates all the important
+features. Make sure you have the environment variable <code>BUILDDIR</code> set correctly,
+and build the driver with a <code>make</code> command, e.g.,</p>
+
+<blockquote>
+ <pre>% make HOSTFILE=etc/solaris.c lcc
+cc -g -c -DTEMPDIR=\"/tmp\" -o /usr/local/lib/lcc-4.1/sparc-solaris/lcc.o etc/lcc.c
+cc -g -c -o /usr/local/lib/lcc-4.1/sparc-solaris/host.o etc/solaris.c
+cc -g -o /usr/local/lib/lcc-4.1/sparc-solaris/lcc /usr/local/lib/lcc-4.1/sparc-solaris/lcc.o /usr/local/lib/lcc-4.1/sparc-solaris/host.o</pre>
+</blockquote>
+
+<p>The symbolic name <code>HOSTFILE</code> specifies the path to the host-specific part,
+either one in the distribution or <em>whatever</em><code>.c</code>. Some versions of make
+may require the <code>-e</code> option in order to read the environment.</p>
+
+<p>Here's <code>etc/solaris.c</code>:</p>
+
+<blockquote>
+ <pre>/* Sparcs running Solaris 2.5.1 at CS Dept., Princeton University */
+
+#include <string.h>
+
+static char rcsid[] = "$ Id: solaris.c,v 1.10 1998/09/14 20:36:33 drh Exp $";
+
+#ifndef LCCDIR
+#define LCCDIR "/usr/local/lib/lcc/"
+#endif
+#ifndef SUNDIR
+#define SUNDIR "/opt/SUNWspro/SC4.2/lib/"
+#endif
+
+char *suffixes[] = { ".c", ".i", ".s", ".o", ".out", 0 };
+char inputs[256] = "";
+char *cpp[] = { LCCDIR "cpp",
+ "-D__STDC__=1", "-Dsparc", "-D__sparc__", "-Dsun", "-D__sun__", "-Dunix",
+ "$1", "$2", "$3", 0 };
+char *include[] = { "-I" LCCDIR "include", "-I/usr/local/include",
+ "-I/usr/include", 0 };
+char *com[] = { LCCDIR "rcc", "-target=sparc/solaris",
+ "$1", "$2", "$3", 0 };
+char *as[] = { "/usr/ccs/bin/as", "-Qy", "-s", "-o", "$3", "$1", "$2", 0 };
+char *ld[] = { "/usr/ccs/bin/ld", "-o", "$3", "$1",
+ SUNDIR "crti.o", SUNDIR "crt1.o",
+ SUNDIR "values-xa.o", "$2", "",
+ "-Y", "P," SUNDIR ":/usr/ccs/lib:/usr/lib", "-Qy",
+ "-L" LCCDIR, "-llcc", "-lm", "-lc", SUNDIR "crtn.o", 0 };
+
+extern char *concat(char *, char *);
+
+int option(char *arg) {
+ if (strncmp(arg, "-lccdir=", 8) == 0) {
+ cpp[0] = concat(&arg[8], "/cpp");
+ include[0] = concat("-I", concat(&arg[8], "/include"));
+ ld[12] = concat("-L", &arg[8]);
+ com[0] = concat(&arg[8], "/rcc");
+ } else if (strcmp(arg, "-p") == 0) {
+ ld[5] = SUNDIR "mcrt1.o";
+ ld[10] = "P," SUNDIR "libp:/usr/ccs/lib/libp:/usr/lib/libp:"
+ SUNDIR ":/usr/ccs/lib:/usr/lib";
+ } else if (strcmp(arg, "-b") == 0)
+ ;
+ else if (strncmp(arg, "-ld=", 4) == 0)
+ ld[0] = &arg[4];
+ else
+ return 0;
+ return 1;
+}</pre>
+</blockquote>
+
+<p><code>LCCDIR</code> defaults to <code>"/usr/local/lib/lcc/"</code> unless
+it's defined by a <code>-D</code> option as part of <code>CFLAGS</code> in the make
+command, e.g.,</p>
+
+<blockquote>
+ <pre>% make HOSTFILE=etc/solaris.c CFLAGS='-DLCCDIR=\"/v/lib/lcc/\"' lcc</pre>
+</blockquote>
+
+<p>Note the trailing slash; <code>SUNDIR</code> is provided so you can use <code>etc/solaris.c</code>
+even if you have a different version of the Sun Pro compiler suite. If you're using the
+gcc compiler tools instead of the Sun Pro tools, see <a HREF="../etc/gcc-solaris.c"><code>etc/gcc-solaris.c</code></a>.</p>
+
+<p>Most of the host-specific code is platform-specific data and templates for the commands
+that invoke the preprocessor, compiler, assembler, and loader. The <code>suffixes</code>
+array lists the file name suffixes for C source files, preprocessed source files, assembly
+language source files, object files, and executable files. <code>suffixes</code> must be
+terminated with a null pointer, as shown above. The initialization of <code>suffixes</code>
+in <code><a HREF="../etc/solaris.c">etc/solaris.c</a></code> are the typical ones for UNIX
+systems. Each element of <code>suffixes</code> is actually a list of suffixes, separated
+by semicolons; <code><a HREF="../etc/win32.c">etc/win32.c</a></code> holds an example:</p>
+
+<blockquote>
+ <pre>char *suffixes[] = { ".c;.C", ".i;.I", ".asm;.ASM;.s;.S", ".obj;.OBJ", ".exe", 0 };</pre>
+</blockquote>
+
+<p>When a list is given, the first suffix is used whenever lcc needs to generate a file
+name. For example, with <code><a HREF="../etc/win32.c">etc/win32.c</a></code>, lcc emits
+the generated assembly code into <code>.asm</code> files.</p>
+
+<p>The <code>inputs</code> array holds a null-terminated string of directories separated
+by colons or semicolons. These are used as the default value of <code>LCCINPUTS</code>, if
+the environment variable <code>LCCINPUTS</code> is not set; see the <a HREF="lcc.pdf">man
+page</a>.</p>
+
+<p>Each command template is an array of pointers to strings terminated with a null
+pointer; the strings are full path names of commands, arguments, or argument placeholders,
+which are described below. Commands are executed in a child process, and templates can
+contain multiple commands by separating commands with newlines. The driver runs each
+command in a new process.</p>
+
+<p>The <code>cpp</code> array gives the command for running lcc's preprocessor, <code>cpp</code>.
+Literal arguments specified in templates, e.g., <code>"-Dsparc"</code> in the <code>cpp</code>
+command above, are passed to the command as given.</p>
+
+<p>The strings <code>"$1"</code>, <code>"$2"</code>, and <code>"$3"</code>
+in templates are placeholders for <em>lists</em> of arguments that are substituted in a
+copy of the template before the command is executed. <code>$1</code> is replaced by the <em>options</em>
+specified by the user; for the preprocessor, this list always contains at least <code>-D__LCC__</code>.
+<code>$2</code> is replaced by the <em>input</em> files, and <code>$3</code> is replaced
+by the <em>output</em> file.</p>
+
+<p>Zero-length arguments after replacement are removed from the argument list before the
+command is invoked. So, for example, if the preprocessor is invoked without an output
+file, <code>"$3"</code> becomes <code>""</code>, which is removed from
+the final argument list.</p>
+
+<p>The <code>include</code> array is a list of <code>-I</code> options that specify which
+directives should be searched to satisfy include directives. These directories are
+searched in the order given. The first directory should be the one to which the ANSI
+header files were copied as described in <a HREF="#unix">UNIX</a> or <a HREF="#win32">Windows</a>
+installation instructions. The driver adds these options to <code>cpp</code>'s arguments
+when it invokes the preprocessor, except when <code>-N</code> is specified.</p>
+
+<p><code>com</code> gives the command for invoking the compiler. This template can appear
+as shown above in a custom host-specific part, but the option <code>-target=sparc/solaris</code>
+should be edited to the <em>target</em><code>/</code><em>os</em> for your platform. If <code>com[1]</code>
+includes the string "<code>win32</code>", the driver assumes it's running on
+Windows. lcc can generate code for <em>all</em> of the <em>target</em><code>/</code><em>os</em>
+combinations listed in the file <code>src/bind.c</code>. The <code>-target</code> option
+specifies the default combination. The driver's <code>-Wf</code> option can be used to
+specify other combinations; the <a HREF="lcc.pdf">man page</a> elaborates.</p>
+
+<p><code>as</code> gives the command for invoking the assembler. On Linux, you must be
+running at least version 2.8.1 of the GNU assembler; earlier versions mis-assemble some
+instructions emitted by lcc.</p>
+
+<p><code>ld</code> gives the command for invoking the loader. For the other commands, the
+list <code>$2</code> contains a single file; for <code>ld</code>, <code>$2</code> contains
+all ".o" files and libraries, and <code>$3</code> is <code>a.out</code>, unless
+the <code>-o</code> option is specified. As suggested in the code above, <code>ld</code>
+must also specify the appropriate startup code and default libraries, including the lcc
+library, <code>liblcc.a</code>.</p>
+
+<p>The <code>option</code> function is described below; the minimal <code>option</code>
+function just returns 0.</p>
+
+<p>You can test <code>lcc</code> with the options <code>-v -v</code> to display the
+commands that would be executed, e.g.,</p>
+
+<blockquote>
+ <pre>% $BUILDDIR/lcc -v -v foo.c baz.c mylib.a -lX11
+/usr/local/lib/lcc-4.1/lcc $ Id: solaris.c,v 1.10 1998/09/14 20:36:33 drh Exp $
+foo.c:
+/usr/local/lib/lcc/cpp -D__STDC__=1 -Dsparc -D__sparc__ -Dsun -D__sun__ -Dunix -D__LCC__ -I/usr/local/lib/lcc/include -I/usr/local/include -I/usr/include foo.c /tmp/lcc266290.i
+/usr/local/lib/lcc/rcc -target=sparc/solaris -v /tmp/lcc266290.i /tmp/lcc266291.
+s
+/usr/ccs/bin/as -Qy -s -o /tmp/lcc266292.o /tmp/lcc266291.s
+baz.c:
+/usr/local/lib/lcc/cpp -D__STDC__=1 -Dsparc -D__sparc__ -Dsun -D__sun__ -Dunix -D__LCC__ -I/usr/local/lib/lcc/include -I/usr/local/include -I/usr/include baz.c /tmp/lcc266290.i
+/usr/local/lib/lcc/rcc -target=sparc/solaris -v /tmp/lcc266290.i /tmp/lcc266291.s
+/usr/ccs/bin/as -Qy -s -o /tmp/lcc266293.o /tmp/lcc266291.s
+/usr/ccs/bin/ld -o a.out /opt/SUNWspro/SC4.2/lib/crti.o /opt/SUNWspro/SC4.2/lib/crt1.o /opt/SUNWspro/SC4.2/lib/values-xa.o /tmp/lcc266292.o /tmp/lcc266293.o mylib.a -lX11 -Y P,/opt/SUNWspro/SC4.2/lib/:/usr/ccs/lib:/usr/lib -Qy -L/usr/local/lib/lcc/ -llcc -lm -lc /opt/SUNWspro/SC4.2/lib/crtn.o
+rm /tmp/lcc266293.o /tmp/lcc266290.i /tmp/lcc266291.s /tmp/lcc266292.o</pre>
+</blockquote>
+
+<p>As the output shows, <code>lcc</code> places temporary files in <code>/tmp</code>; if
+any of the environment variables <code>TMP</code>, <code>TEMP</code>, and <code>TMPDIR</code>
+are set, they override this default (in the order shown) as does the <code>-tempdir=</code><em>dir</em>
+option. The default can be changed by defining <code>TEMPDIR</code> in <code>CFLAGS</code>
+when building the driver.</p>
+
+<p>The <code>option</code> function is called for the options <code>-Wo</code>, <code>-g</code>,
+<code>-p</code>, <code>-pg</code>, and <code>-b</code> because these compiler options
+might also affect the loader's arguments. For these options, the driver calls <code>option(arg)</code>
+to give the host-specific code an opportunity to edit the <code>ld</code> command, if
+necessary. <code>option</code> can change <code>ld</code>, if necessary, and return 1 to
+announce its acceptance of the option. If the option is unsupported, <code>option</code>
+should return 0.</p>
+
+<p>For example, in response to <code>-g</code>, the <code>option</code> function shown
+above accepts the option but does nothing else, because the <code>ld</code> and <code>as</code>
+commands don't need to be modified on the SPARC. <code>-g</code> will also be added to the
+compiler's options by the host-independent part of the driver. The <code>-p</code> causes <code>option</code>
+to change the name of the startup code and changed the list of libraries. The <code>-b</code>
+option turns on <code>lcc</code>'s per-expression profiling, the code for which is in <code>liblcc.a</code>,
+so <code>option</code> need no nothing.</p>
+
+<p>On SPARCs, the driver also recognizes <code>-Bstatic</code> and <code>-Bdynamic</code>
+as linker options. The driver recognizes but ignores "<code>-target</code> <em>name</em>"
+option.</p>
+
+<p>The option <code>-Wo</code><em>arg</em> causes the driver to pass <em>arg</em> to <code>option</code>.
+Such options have no other effect; this mechanism is provided to support system-specific
+options that affect the commands executed by the driver. As illustrated above,
+host-specific parts should support the <code>-Wo-lccdir=</code><em>dir</em> option, which
+causes lcc's compilation components to be found in <em>dir</em>, because this option is
+used by the test scripts, and because the driver simulates a <code>-Wo-lccdir</code>
+option with the value of the environment variable <code>LCCDIR</code>, if it's defined.
+The code above rebuilds the paths to the include files, preprocessor, compiler, and
+library by calling <code>concat</code>, which is defined in <code>etc/lcc.c</code>.</p>
+
+<h2><a NAME="rcc">Building the Compiler and Accessories</a></h2>
+
+<p>To build the rest of compilation components make sure <code>BUILDDIR</code> is set
+appropriately and type "<code>make all</code>". This command builds <code>librcc.a</code>
+(the compiler's private library), <code>rcc</code> (the compiler proper), <code>lburg</code>
+(the code-generator generator), <code>cpp</code> (the preprocessor), <code>liblcc.a</code>
+(the runtime library), and <code>bprint</code> (the profile printer), all in <code>BUILDDIR</code>.
+There may be warnings, but there should be no errors. If you're using an ANSI/ISO compiler
+other than <code>cc</code>, specify its name with the <code>CC=</code> option, e.g.,
+"<code>make CC=gcc all</code>". If you're running on a DEC ALPHA, use "<code>make
+CC='cc -std1' all</code>"; the <code>-std1</code> option is essential on the ALPHA.
+If you're on a DEC 5000 running Ultrix 4.3, use "<code>make CC=c89 all</code>".</p>
+
+<p>Once <code>rcc</code> is built with the host C compiler, run the test suite to verify
+that <code>rcc</code> is working correctly. If any of the steps below fail, contact us
+(see <a HREF="#bugs"><em>Reporting Bugs</em></a>). The commands in the makefile run the
+shell script <code>src/run.sh</code> on each C program in the test suite, <code>tst/*.c</code>.
+It uses the driver, <code>$BUILDDIR/lcc</code>, so you must have the driver in the build
+directory before testing <code>rcc</code>. The <em>target</em><code>/</code><em>os</em>
+combination is read from the variable <code>TARGET</code>, which must be specified when
+invoking <code>make</code>:</p>
+
+<blockquote>
+ <pre>% make TARGET=sparc/solaris test
+mkdir -p /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/8q.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/array.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/cf.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/cq.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/cvt.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/fields.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/front.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/incr.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/init.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/limits.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/paranoia.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/sort.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/spill.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/stdarg.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/struct.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/switch.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/wf1.s:
+/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/yacc.s:</pre>
+</blockquote>
+
+<p>Each line in the output above is of the form</p>
+
+<blockquote>
+ <p><code>$BUILDDIR/rcc -target=</code><em>target</em><code>/</code><em>os</em><code>$BUILDDIR/</code><em>target</em><code>/</code><em>os</em><code>/</code><em>X</em><code>.s:</code></p>
+</blockquote>
+
+<p>where <em>X</em> is the base name of the C program <em>X</em><code>.c</code> in the
+test suite. This output identifies the compiler and the target, e.g., "<code>$BUILDDIR/rcc</code>
+is generating code for a <code>sparc</code> running the <code>solaris</code> operating
+system."</p>
+
+<p>For each program in the test suite, <code>src/run.sh</code> compiles the program, drops
+the generated assembly language code in <code>BUILDDIR</code>/<em>target</em><code>/</code><em>os</em>,
+and uses <code>diff</code> to compare the generated assembly code with the expected code
+(the code expected for <code>tst/8q.c</code> on the SPARC under Solaris is in <code>sparc/solaris/tst/8q.sbk</code>,
+etc.). If there are differences, the script executes the generated code with the input
+given in <code>tst</code> (the input for <code>tst/8q.c</code> is in <code>tst/8q.0</code>,
+etc.) and compares the output with the expected output (the expected output from <code>tst/8q.c</code>
+on the SPARC under Solaris is in <code>sparc/solaris/tst/8q.1bk</code>, etc.). The script
+also compares the diagnostics from the compiler with the expected diagnostics.</p>
+
+<p>On some systems, there may be a few differences between the generated code and the
+expected code. These differences occur because the expected code is generated by cross
+compilation and the least significant bits of some floating-point constants differ from
+those bits in constants generated on your system. On Linux, there may be differences
+because of differences in the header files between our system and yours. There should be
+no differences in the output from executing the test programs.</p>
+
+<p>Next, run the "triple test", which builds <code>rcc</code> using itself:</p>
+
+<blockquote>
+ <pre>% make triple
+/usr/local/lib/lcc-4.1/sparc-solaris/lcc -o /usr/local/lib/lcc-4.1/sparc-solaris/1rcc -d0.6 -Wo-lccdir=/usr/local/lib/lcc-4.1/sparc-solaris -B/usr/local/lib/lcc-4.1/sparc-solaris/ -Isrc src/*.c
+src/alloc.c:
+...
+src/x86.c:
+/usr/local/lib/lcc-4.1/sparc-solaris/lcc -o /usr/local/lib/lcc-4.1/sparc-solaris/1rcc -d0.6 -Wo-lccdir=/usr/local/lib/lcc-4.1/sparc-solaris -B/usr/local/lib/lcc-4.1/sparc-solaris/ -Isrc src/*.c
+src/alloc.c:
+...
+src/x86.c:
+strip /usr/local/lib/lcc-4.1/sparc-solaris/[12]rcc
+dd if=/usr/local/lib/lcc-4.1/sparc-solaris/1rcc of=/usr/local/lib/lcc-4.1/sparc-solaris/rcc1 bs=512 skip=1
+769+1 records in
+769+1 records out
+dd if=/usr/local/lib/lcc-4.1/sparc-solaris/2rcc of=/usr/local/lib/lcc-4.1/sparc-solaris/rcc2 bs=512 skip=1
+769+1 records in
+769+1 records out
+if cmp /usr/local/lib/lcc-4.1/sparc-solaris/rcc[12]; then \
+ mv /usr/local/lib/lcc-4.1/sparc-solaris/2rcc /usr/local/lib/lcc-4.1/sparc-solaris/rcc; \
+ rm -f /usr/local/lib/lcc-4.1/sparc-solaris/1rcc /usr/local/lib/lcc-4.1/sparc-solaris/rcc[12]; fi</pre>
+</blockquote>
+
+<p>This command builds <code>rcc</code> twice; once using the <code>rcc</code> built by <code>cc</code>
+and again using the <code>rcc</code> built by <code>lcc</code>. The resulting binaries are
+compared. They should be identical, as shown at the end of the output above. If they
+aren't, our compiler is generating incorrect code; <a HREF="#bugs">contact</a> us.</p>
+
+<p>The final version of <code>rcc</code> should also pass the test suite; that is, the
+output from</p>
+
+<blockquote>
+ <pre>% make TARGET=sparc/solaris test</pre>
+</blockquote>
+
+<p>should be identical to that from the previous <code>make test</code>.</p>
+
+<p>The command "<code>make clean</code>" cleans up, but does not remove <code>rcc</code>,
+etc., and "<code>make clobber</code>" cleans up and removes <code>lcc</code>, <code>rcc</code>,
+and the other accessories. Test directories under <code>BUILDDIR</code> are <em>not</em>
+removed; you'll need to remove these by hand, e.g.,</p>
+
+<blockquote>
+ <pre>% rm -fr $BUILDDIR/sparc</pre>
+</blockquote>
+
+<p>The code generators for the other targets can be tested by specifying the desired <em>target</em><code>/</code><em>os</em>
+and setting an environment variable that controls what <code>src/run.sh</code> does. For
+example, to test the MIPS code generator, type</p>
+
+<blockquote>
+ <pre>% setenv REMOTEHOST noexecute
+% make TARGET=mips/irix test</pre>
+</blockquote>
+
+<p>As above, <code>src/run.sh</code> compares the MIPS code generated with what's
+expected. There should be no differences. Setting <code>REMOTEHOST</code> to <code>noexecute</code>
+suppresses the assembly and execution of the generated code. If you set <code>REMOTEHOST</code>
+to the name of a MIPS machine to which you can <code>rlogin</code>, <code>src/run.sh</code>
+will <code>rcp</code> the generated code to that machine and execute it there, if
+necessary. See <code>src/run.sh</code> for the details.</p>
+
+<p>You can use lcc as a cross compiler. The options <code>-S</code> and <code>-Wf-target=</code><em>target/os</em>
+generate assembly code for the specified target, which is any of those listed in the file <code>src/bind.c</code>.
+For example, </p>
+
+<blockquote>
+ <pre>% lcc -Wf-target=mips/irix -S tst/8q.c</pre>
+</blockquote>
+
+<p>generates MIPS code for <code>tst/8q.c</code> in <code>8q.s</code>.</p>
+
+<p>lcc can also generate code for a "symbolic" target. This target is used
+routinely in front-end development, and its output is a printable representation of the
+input program, e.g., the dags constructed by the front end are printed, and other
+interface functions print their arguments. You can specify this target with the option <code>-Wf-target=symbolic</code>.
+For example,</p>
+
+<blockquote>
+ <pre>% lcc -Wf-target=symbolic -S tst/8q.c</pre>
+</blockquote>
+
+<p>generates symbolic output for <code>tst/8q.c</code> in <code>8q.s</code>. Adding <code>-Wf-html</code>
+causes the symbolic target to emit HTML instead of plain text. Finally, the option <code>-Wf-target=null</code>
+specifies the "null" target for which lcc emits nothing and thus only checks the
+syntax and semantics of its input files.</p>
+
+<h2><a NAME="win32">Installation on Windows NT 4.0 or Windows 95/98</a></h2>
+
+<p>On Windows NT 4.0 and Windows 95/98, lcc is designed to work with Microsoft's Visual
+C++ 5.0 (VC) and Microsoft's Assembler, MASM 6.11d. It uses the VC header files,
+libraries, and command-line tools, and it uses MASM to assemble the code it generates. If
+you have MASM 6.11, make sure you <a
+HREF="http://support.microsoft.com/support/kb/articles/Q138/9/83.asp">upgrade to 6.11d</a>,
+because earlier 6.11 releases do not generate correct COFF object files.</p>
+
+<p>Building the distribution components from the ground up requires Microsoft's Visual
+C/C++ 5.0 compiler, Microsoft's make, <code>nmake</code>, and the standard Windows command
+interpreter. <a HREF="../makefile.nt"><code>makefile.nt</code></a> is written to use only <code>nmake</code>.
+As on UNIX systems, the compilation components are installed in a single <em>build
+directory</em>, and the top-level programs, <code>lcc.exe</code> and <code>bprint.exe</code>,
+are installed in a directory on the PATH. If the conventions used below are followed, the
+Windows-specific parts of the driver program, <code>lcc.exe</code>, can be used
+unmodified.</p>
+
+<p>Building from the source distribution on a Windows system involves the following steps.
+Below, the build directory is referred to as <code>BUILDDIR</code>, and the distribution
+is in <code>\dist\lcc\4.1</code>.
+
+<ol>
+ <li>Create the build directory, perhaps using a version- and platform-specific naming
+ convention as suggested in <a HREF="#unix"><em>Installation on UNIX</em></a>, and record
+ the name of this directory in the <code>BUILDDIR</code> environment variable:<blockquote>
+ <pre>C:\dist\lcc\4.1>set BUILDDIR=\progra~1\lcc\4.1\bin
+C:\dist\lcc\4.1>mkdir %BUILDDIR%</pre>
+ </blockquote>
+ <p>The default build, or installation, directory is <code>\Program Files\lcc\4.1\bin</code>,
+ but the <code>nmake</code> commands require that you use the corresponding 8.3 file name, <code>progra~1</code>,
+ instead of <code>Program Files</code>.</p>
+ </li>
+ <li><a HREF="../etc/win32.c"><code>etc\win32.c</code></a> is the Windows-specific part of
+ the driver. It assumes that environment variable <code>include</code> gives the locations
+ of the VC header files and that the linker (<code>link.exe</code>) and the assembler (<code>ml.exe</code>)
+ are on the PATH. It also assumes that the macro <code>LCCDIR</code> gives the build
+ directory. If necessary, revise a copy of <a HREF="../etc/win32.c"><code>etc\win32.c</code></a>
+ to reflect the conventions on your computer (see <a HREF="#driver"><em>Building the Driver</em></a>),
+ then build the driver, specifying the default temporary directory, if necessary:<blockquote>
+ <pre>C:\dist\lcc\4.1>nmake -f makefile.nt TEMPDIR=\\temp HOSTFILE=etc/win32.c lcc
+...
+ cl -nologo -Zi -MLd -Fd\progra~1\lcc\4.1\bin\ -c -DTEMPDIR=\"\\temp\" -Fo\progra~1\lcc\4.1\bin\lcc.obj etc/lcc.c
+lcc.c
+ cl -nologo -Zi -MLd -Fd\progra~1\lcc\4.1\bin\ -c -Fo\progra~1\lcc\4.1\bin\host.obj etc/win32.c
+win32.c
+ cl -nologo -Zi -MLd -Fd\progra~1\lcc\4.1\bin\ -Fe\progra~1\lcc\4.1\bin\lcc.exe \progra~1\lcc\4.1\bin\lcc.obj \progra~1\lcc\4.1\bin\host.obj</pre>
+ </blockquote>
+ <p>If you make a copy of <code>etc\win32.c</code>, specify the path of the copy as the
+ value of <code>HOSTFILE</code>. For example, if you copy <code>etc\win32.c</code> to <code>BUILDDIR</code>
+ and edit it, use the command</p>
+ <blockquote>
+ <pre>C:\dist\lcc\4.1>nmake -f makefile.nt TEMPDIR=\\temp HOSTFILE=%BUILDDIR%\win32.c lcc</pre>
+ </blockquote>
+ </li>
+ <li>Build the preprocessor, compiler proper, library, and other accessories (see <a
+ HREF="#rcc"><em>Building the Compiler</em></a>):<blockquote>
+ <pre>C:\dist\lcc\4.1>nmake -f makefile.nt all</pre>
+ </blockquote>
+ <p>This command uses the VC command-line tools <code>cl</code> and <code>lib</code> to
+ build <code>bprint.exe</code>, <code>cpp.exe</code>, <code>lburg.exe</code>, <code>liblcc.lib</code>,
+ <code>librcc.lib</code>, and <code>rcc.exe</code>, all in <code>BUILDDIR</code>. There may
+ be some warnings, but there should be no warnings.</p>
+ </li>
+ <li>Create a test directory and run the test suite:<blockquote>
+ <pre>C:\dist\lcc\4.1>mkdir %BUILDDIR%\x86\win32\tst
+C:\dist\lcc\4.1>nmake -f makefile.nt test</pre>
+ </blockquote>
+ <p>This command compiles each program in <a HREF="../tst">tst</a>, compares the generated
+ assembly code and diagnostics with the expected assembly code and diagnostics, executes
+ the program, and compares the output with the expected output (using <code>fc</code>). For
+ example, when the nmake command compiles <a HREF="../tst/8q.c"><code>tst\8q.c</code></a>,
+ it leaves the generated assembly code and diagnostic output in <code>%BUILDDIR%\x86\win32\tst\8q.s</code>
+ and <code>%BUILDDIR%\x86\win32\tst\8q.2</code>, and it compares them with the expected
+ results in <code>x86\win32\tst\8q.sbk</code>. It builds the executable program in <code>%BUILDDIR%\x86\win32\tst\8q.exe</code>,
+ runs it, and redirects the output to <code>%BUILDDIR%\x86\win32\tst\8q.1</code>, which it
+ compares with <code>x86\win32\tst\8q.1bk</code>. The output from this step is voluminous,
+ but there should be no differences and no errors.</p>
+ </li>
+ <li>Run the "triple" test, which compiles <code>rcc</code> with itself and
+ verifies the results:<blockquote>
+ <pre>C:\dist\lcc\4.1>nmake -f makefile.nt triple
+...
+\progra~1\lcc\4.1\bin\x86.c:
+ Assembling: C:/TEMP/lcc2001.asm
+ fc /b \progra~1\lcc\4.1\bin\1rcc.exe \progra~1\lcc\4.1\bin\2rcc.exe
+Comparing files \progra~1\lcc\4.1\bin\1rcc.exe and \progra~1\lcc\4.1\bin\2RCC.EXE
+00000088: B4 D5</pre>
+ </blockquote>
+ <p>This command builds <code>rcc</code> twice; once using the <code>rcc</code> built by VC
+ and again using the <code>rcc</code> built by <code>lcc</code>. The resulting binaries are
+ compared using <code>fc</code>. They should be identical, except for one or two bytes of
+ timestamp data, as shown at the end of the output above. If they aren't, our compiler is
+ generating incorrect code; <a HREF="#bugs">contact</a> us.</p>
+ </li>
+ <li>Copy <code>lcc.exe</code> and <code>bprint.exe</code> to a directory on your PATH, e.g.,<blockquote>
+ <pre>C:\dist\lcc\4.1>copy %BUILDDIR%\lcc.exe \bin
+ 1 file(s) copied.
+
+C:\dist\lcc\4.1>copy %BUILDDIR%\bprint.exe \bin
+ 1 file(s) copied.</pre>
+ </blockquote>
+ </li>
+ <li>Finally, clean up:<blockquote>
+ <pre>C:\dist\lcc\4.1>nmake -f makefile.nt clean</pre>
+ </blockquote>
+ <p>This command removes the derived files in <code>BUILDDIR</code>, but does not remove <code>rcc.exe</code>,
+ etc.; "<code>nmake -f makefile.nt clobber</code>" cleans up and removes all
+ executables and libraries. Test directories under <code>BUILDDIR</code> are <em>not</em>
+ removed; you'll need to remove these by hand, e.g.,</p>
+ <blockquote>
+ <pre>C:\dist\lcc\4.1>rmdir %BUILDDIR%\x86 /s
+\progra~1\lcc\4.1\bin\x86, Are you sure (Y/N)? y</pre>
+ </blockquote>
+ </li>
+</ol>
+
+<h2><a NAME="bugs">Reporting Bugs</a></h2>
+
+<p>lcc is a large, complex program. We find and repair errors routinely. If you think that
+you've found a error, follow the steps below, which are adapted from the instructions in
+Chapter 1 of <cite>A Retargetable C Compiler: Design and Implementation</cite>.
+
+<ol>
+ <li>If you don't have a source file that displays the error, create one. Most errors are
+ exposed when programmers try to compile a program they think is valid, so you probably
+ have a demonstration program already.</li>
+ <li>Preprocess the source file and capture the preprocessor output. Discard the original
+ code.</li>
+ <li>Prune your source code until it can be pruned no more without sending the error into
+ hiding. We prune most error demonstrations to fewer than five lines.</li>
+ <li>Confirm that the source file displays the error with the <em>distributed</em> version of
+ lcc. If you've changed lcc and the error appears only in your version, then you'll have to
+ chase the error yourself, even if it turns out to be our fault, because we can't work on
+ your code.</li>
+ <li>Annotate your code with comments that explain why you think that lcc is wrong. If lcc
+ dies with an assertion failure, please tell us where it died. If lcc crashes, please
+ report the last part of the call chain if you can. If lcc is rejecting a program you think
+ is valid, please tell us why you think it's valid, and include supporting page numbers in
+ the ANSI Standard, Appendix A in <cite>The C Programming Language</cite>, or the
+ appropriate section in <cite>C: A Reference Manual</cite>, 4th edition by S. B. Harbison
+ and G. L. Steele, Jr. (Prentice Hall, 1995). If lcc silently generates incorrect code for
+ some construct, please include the corrupt assembly code in the comments and flag the
+ incorrect instructions if you can.</li>
+ <li>Confirm that your error hasn't been fixed already. The latest version of lcc is always
+ available for anonymous <code>ftp</code> from <code>ftp.cs.princeton.edu</code> in <a
+ HREF="ftp://ftp.cs.princeton.edu/pub/lcc"><code>pub/lcc</code></a>. A <a
+ HREF="ftp://ftp.cs.princeton.edu/pub/lcc/README"><code>README</code></a> file there gives
+ acquistion details, and the <a HREF="../LOG"><code>LOG</code></a> file reports what errors
+ were fixed and when they were fixed. If you report a error that's been fixed, you might
+ get a canned reply.</li>
+ <li>Send your program by electronic mail to <code>lcc-bugs at cs.princeton.edu</code>. Please
+ send only valid C programs; put all remarks in C comments so that we can process reports
+ semiautomatically.</li>
+</ol>
+
+<h2><a NAME="mailinglist">Keeping in Touch</a></h2>
+
+<p>There is an lcc mailing list for general information about lcc. To be added to the
+list, send a message with the 1-line body</p>
+
+<blockquote>
+ <pre>subscribe lcc</pre>
+</blockquote>
+
+<p>to <code>majordomo at cs.princeton.edu</code>. This line must appear in the message body;
+"Subject:" lines are ignored. To learn more about mailing lists served by <code>majordomo</code>,
+send a message with the 1-word body "<code>help</code>" to <code>majordomo at cs.princeton.edu</code>.
+Mail sent to <code>lcc at cs.princeton.edu</code> is forwarded to everyone on the mailing
+list.</p>
+
+<p>There is also an <code>lcc-bugs</code> mailing list for reporting bugs; subscribe to it
+by sending a message with the 1-line body </p>
+
+<blockquote>
+ <pre>subscribe lcc-bugs</pre>
+</blockquote>
+
+<p>to <code>majordomo at cs.princeton.edu</code>. Mail addressed to <var>lcc-bugs at cs.princeton.edu</var>
+is forwarded to everyone on this list.</p>
+
+<hr>
+
+<address>
+ <a HREF="http://www.research.microsoft.com/~cwfraser/">Chris Fraser</a> / <a
+ HREF="mailto:cwfraser at microsoft.com">cwfraser at microsoft.com</a><br>
+ <a HREF="http://www.research.microsoft.com/~drh/">David Hanson</a> / <a
+ HREF="mailto:drh at microsoft.com">drh at microsoft.com</a><br>
+ $Revision: 145 $ $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $
+</address>
+</body>
+</html>
diff --git a/code/tools/lcc/doc/lcc.1 b/code/tools/lcc/doc/lcc.1
new file mode 100644
index 0000000..fe91bca
--- /dev/null
+++ b/code/tools/lcc/doc/lcc.1
@@ -0,0 +1,605 @@
+.\" $Id: lcc.1 145 2001-10-17 21:53:10Z timo $
+.TH LCC 1 "local \- $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $"
+.SH NAME
+lcc \- ANSI C compiler
+.SH SYNOPSIS
+.B lcc
+[
+.I option
+|
+.I file
+]...
+.br
+.SH DESCRIPTION
+.PP
+.I lcc
+is an ANSI C compiler for a variety of platforms.
+.PP
+Arguments whose names end with `.c' (plus `.C' under Windows) are taken to be
+C source programs; they are preprocessed, compiled, and
+each object program is left on the file
+whose name is that of the source with `.o' (UNIX) or `.obj' (Windows)
+substituted for the extension.
+Arguments whose names end with `.i' are treated similarly,
+except they are not preprocessed.
+In the same way,
+arguments ending with `.s' (plus `.S', `.asm', and `.ASM', under Windows)
+are taken to be assembly source programs
+and are assembled, producing an object file.
+If there are no arguments,
+.I lcc
+summarizes its options on the standard error.
+.PP
+.I lcc
+deletes an object file if and only if exactly one
+source file is mentioned and no other file
+(source, object, library) or
+.B \-l
+option is mentioned.
+.PP
+If the environment variable
+.B LCCINPUTS
+is set,
+.I lcc
+assumes it gives a semicolon- or colon-separated list of directories in which to
+look for source and object files whose names do not begin with `/'.
+These directories are also added to the list of directories
+searched for libraries.
+If
+.B LCCINPUTS
+is defined, it must contain `.' in order for the current directory
+to be searched for input files.
+.PP
+.I lcc
+uses ANSI standard header files (see `FILES' below).
+Include files not found in the ANSI header files
+are taken from the normal default include areas,
+which usually includes
+.BR /usr/include .
+Under Windows, if the environment variable
+.B include
+is defined, it gives a semicolon-separated list of directories in which to search for
+header files.
+.PP
+.I lcc
+interprets the following options; unrecognized options are
+taken as loader options (see
+.IR ld (1))
+unless
+.BR \-c ,
+.BR \-S ,
+or
+.B \-E
+precedes them.
+Except for
+.BR \-l ,
+all options are processed before any of the files
+and apply to all of the files.
+Applicable options are passed to each compilation phase in the order given.
+.TP
+.B \-c
+Suppress the loading phase of the compilation, and force
+an object file to be produced even if only one program is compiled.
+.TP
+.B \-g
+Produce additional symbol table information for the local debuggers.
+.I lcc
+warns when
+.B \-g
+is unsupported.
+.TP
+.BI \-Wf\-g n , x
+Set the debugging level to
+.I n
+and emit source code as comments into the generated assembly code;
+.I x
+must be the assembly language comment character.
+If
+.I n
+is omitted, it defaults to 1, which is similar to
+.BR \-g .
+Omitting
+.BI , x
+just sets the debugging level to
+.IR n .
+.TP
+.B \-w
+Suppress warning diagnostics, such as those
+announcing unreferenced statics, locals, and parameters.
+The line
+.I
+#pragma ref id
+simulates a reference to the variable
+.IR id .
+.TP
+.BI \-d n
+Generate jump tables for switches whose density is at least
+.IR n ,
+a floating point constant between zero and one.
+The default is 0.5.
+.TP
+.B \-A
+Warns about
+declarations and casts of function types without prototypes,
+assignments between pointers to ints and pointers to enums, and
+conversions from pointers to smaller integral types.
+A second
+.B \-A
+warns about
+unrecognized control lines,
+nonANSI language extensions and source characters in literals,
+unreferenced variables and static functions,
+declaring arrays of incomplete types,
+and exceeding
+.I some
+ANSI environmental limits, like more than 257 cases in switches.
+It also arranges for duplicate global definitions in separately compiled
+files to cause loader errors.
+.TP
+.B \-P
+Writes declarations for all defined globals on standard error.
+Function declarations include prototypes;
+editing this output can simplify conversion to ANSI C.
+This output may not correspond to the input when
+there are several typedefs for the same type.
+.TP
+.B \-n
+Arrange for the compiler to produce code
+that tests for dereferencing zero pointers.
+The code reports the offending file and line number and calls
+.IR abort (3).
+.TP
+.B \-O
+is ignored.
+.TP
+.B \-S
+Compile the named C programs, and leave the
+assembler-language output on corresponding files suffixed `.s' or `.asm'.
+.TP
+.B \-E
+Run only the preprocessor on the named C programs
+and unsuffixed file arguments,
+and send the result to the standard output.
+.TP
+.BI \-o " output"
+Name the output file
+.IR output .
+If
+.B \-c
+or
+.B \-S
+is specified and there is exactly one source file,
+this option names the object or assembly file, respectively.
+Otherwise, this option names the final executable
+file generated by the loader, and `a.out' (UNIX) or `a.exe' (Windows) is left undisturbed.
+.I lcc
+warns if
+.B \-o
+and
+.B \-c
+or
+.B \-S
+are given with more than one source file and ignores the
+.B \-o
+option.
+.TP
+.BI \-D name=def
+Define the
+.I name
+to the preprocessor, as if by `#define'.
+If
+.I =def
+is omitted, the name is defined as "1".
+.TP
+.BI \-U name
+Remove any initial definition of
+.IR name .
+.TP
+.BI \-I dir
+`#include' files
+whose names do not begin with `/' are always
+sought first in the directory of the
+.I file
+arguments, then in directories named in
+.B \-I
+options, then in directories on a standard list.
+.TP
+.B \-N
+Do not search
+.I any
+of the standard directories for `#include' files.
+Only those directories specified by subsequent explicit
+.B \-I
+options will be searched, in the order given.
+.TP
+.BI \-B str
+Use the compiler
+.BI "" str rcc
+instead of the default version.
+Note that
+.I str
+often requires a trailing slash.
+On Sparcs only,
+.B \-Bstatic
+and
+.BI \-Bdynamic
+are passed to the loader; see
+.IR ld (1).
+.TP
+.BI \-Wo\-lccdir= dir
+Find the preprocessor, compiler proper, and include directory
+in the directory
+.I dir/
+or
+.I
+dir\\.
+If the environment variable
+.B LCCDIR
+is defined, it gives this directory.
+.I lcc
+warns when this option is unsupported.
+.TP
+.B \-Wf-unsigned_char=1
+.br
+.ns
+.TP
+.B \-Wf-unsigned_char=0
+makes plain
+.B char
+an unsigned (1) or signed (0) type; by default,
+.B char
+is signed.
+.TP
+.B \-Wf\-wchar_t=unsigned_char
+.br
+.ns
+.TP
+.B \-Wf\-wchar_t=unsigned_short
+.br
+.ns
+.TP
+.B \-Wf\-wchar_t=unsigned_int
+Makes wide characters the type indicated; by default,
+wide characters are unsigned short ints, and
+.B wchar_t
+is a typedef for unsigned short defined in stddef.h.
+The definition for
+.B wchar_t
+in stddef.h must correspond to the type specified.
+.TP
+.B \-v
+Print commands as they are executed; some of the executed
+programs are directed to print their version numbers.
+More than one occurrence of
+.B \-v
+causes the commands to be printed, but
+.I not
+executed.
+.TP
+.BR \-help " or " \-?
+Print a message on the standard error summarizing
+.IR lcc 's
+options and giving the values of the environment variables
+.B LCCINPUTS
+and
+.BR LCCDIR ,
+if they are defined.
+Under Windows, the values of
+.B include
+and
+.B lib
+are also given, if they are defined.
+.TP
+.B \-b
+Produce code that counts the number of times each expression is executed.
+If loading takes place, arrange for a
+.B prof.out
+file to be written when the object program terminates.
+A listing annotated with execution counts can then be generated with
+.IR bprint (1).
+.I lcc
+warns when
+.B \-b
+is unsupported.
+.B \-Wf\-C
+is similar, but counts only the number of function calls.
+.TP
+.B \-p
+Produce code that counts the number of times each function is called.
+If loading takes place, replace the standard startup
+function by one that automatically calls
+.IR monitor (3)
+at the start and arranges to write a
+.B mon.out
+file when the object program terminates normally.
+An execution profile can then be generated with
+.IR prof (1).
+.I lcc
+warns when
+.B \-p
+is unsupported.
+.TP
+.B \-pg
+Causes the compiler to produce counting code like
+.BR \-p ,
+but invokes a run-time recording mechanism that keeps more
+extensive statistics and produces a
+.B gmon.out
+file at normal termination.
+Also, a profiling library is searched, in lieu of the standard C library.
+An execution profile can then be generated with
+.IR gprof (1).
+.I lcc
+warns when
+.B \-pg
+is unsupported.
+.TP
+.BI \-t name
+.br
+.ns
+.TP
+.BI \-t
+Produce code to print the name of the function, an activation number,
+and the name and value of each argument at function entry.
+At function exit, produce code to print
+the name of the function, the activation number, and the return value.
+By default,
+.I printf
+does the printing; if
+.I name
+appears, it does.
+For null
+.I char*
+values, "(null)" is printed.
+.BI \-target
+.I name
+is accepted, but ignored.
+.TP
+.BI \-tempdir= dir
+Store temporary files in the directory
+.I dir/
+or
+.I
+dir\\.
+The default is usually
+.BR /tmp .
+.TP
+.BI \-W xarg
+pass argument
+.I arg
+to the program indicated by
+.IR x ;
+.I x
+can be one of
+.BR p ,
+.BR f ,
+.BR a ,
+or
+.BR l ,
+which refer, respectively, to the preprocessor, the compiler proper,
+the assembler, and the loader.
+.I arg
+is passed as given; if a
+.B \-
+is expected, it must be given explicitly.
+.BI \-Wo arg
+specifies a system-specific option,
+.IR arg .
+.PP
+Other arguments
+are taken to be either loader option arguments, or C-compatible
+object programs, typically produced by an earlier
+.I lcc
+run, or perhaps libraries of C-compatible routines.
+Duplicate object files are ignored.
+These programs, together with the results of any
+compilations specified, are loaded (in the order
+given) to produce an executable program with name
+.BR a.out
+(UNIX) or
+.BR a.exe
+(Windows).
+.PP
+.I lcc
+assigns the most frequently referenced scalar parameters and
+locals to registers whenever possible.
+For each block,
+explicit register declarations are obeyed first;
+remaining registers are assigned to automatic locals if they
+are `referenced' at least 3 times.
+Each top-level occurrence of an identifier
+counts as 1 reference. Occurrences in a loop,
+either of the then/else arms of an if statement, or a case
+in a switch statement each count, respectively, as 10, 1/2, or 1/10 references.
+These values are adjusted accordingly for nested control structures.
+.B \-Wf\-a
+causes
+.I lcc
+to read a
+.B prof.out
+file from a previous execution and to use the data therein
+to compute reference counts (see
+.BR \-b ).
+.PP
+.I lcc
+is a cross compiler;
+.BI \-Wf\-target= target/os
+causes
+.I lcc
+to generate code for
+.I target
+running the operating system denoted by
+.IR os .
+The supported
+.I target/os
+combinations may include
+.PP
+.RS
+.ta \w'sparc/solarisxx'u
+.nf
+alpha/osf ALPHA, OSF 3.2
+mips/irix big-endian MIPS, IRIX 5.2
+mips/ultrix little-endian MIPS, ULTRIX 4.3
+sparc/solaris SPARC, Solaris 2.3
+x86/win32 x86, Windows NT 4.0/Windows 95/98
+x86/linux x86, Linux
+symbolic text rendition of the generated code
+null no output
+.fi
+.RE
+.PP
+For
+.BR \-Wf\-target=symbolic ,
+the option
+.B \-Wf-html
+causes the text rendition to be emitted as HTML.
+.B
+.SH LIMITATIONS
+.PP
+.I lcc
+accepts the C programming language
+as described in the ANSI standard.
+If
+.I lcc
+is used with the GNU C preprocessor, the
+.B \-Wp\-trigraphs
+option is required to enable trigraph sequences.
+.PP
+Plain int bit fields are signed.
+Bit fields are aligned like unsigned integers but are otherwise laid out
+as by most standard C compilers.
+Some compilers, such as the GNU C compiler,
+may choose other, incompatible layouts.
+.PP
+Likewise, calling conventions are intended to be compatible with
+the host C compiler,
+except possibly for passing and returning structures.
+Specifically,
+.I lcc
+passes and returns structures like host ANSI C compilers
+on most targets, but some older host C compilers use different conventions.
+Consequently, calls to/from such functions compiled with
+older C compilers may not work.
+Calling a function that returns
+a structure without declaring it as such violates
+the ANSI standard and may cause a fault.
+.SH FILES
+.PP
+The file names listed below are
+.IR typical ,
+but vary among installations; installation-dependent variants
+can be displayed by running
+.I lcc
+with the
+.B \-v
+option.
+.PP
+.RS
+.ta \w'$LCCDIR/liblcc.{a,lib}XX'u
+.nf
+file.{c,C} input file
+file.{s,asm} assembly-language file
+file.{o,obj} object file
+a.{out,exe} loaded output
+/tmp/lcc* temporary files
+$LCCDIR/cpp preprocessor
+$LCCDIR/rcc compiler
+$LCCDIR/liblcc.{a,lib} \fIlcc\fP-specific library
+/lib/crt0.o runtime startup (UNIX)
+/lib/[gm]crt0.o startups for profiling (UNIX)
+/lib/libc.a standard library (UNIX)
+$LCCDIR/include ANSI standard headers
+/usr/local/include local headers
+/usr/include traditional headers
+prof.out file produced for \fIbprint\fR(1)
+mon.out file produced for \fIprof\fR(1)
+gmon.out file produced for \fIgprof\fR(1)
+.fi
+.RE
+.PP
+.I lcc
+predefines the macro
+.B __LCC__
+on all systems.
+It may also predefine some installation-dependent symbols; option
+.B \-v
+exposes them.
+.SH "SEE ALSO"
+.PP
+C. W. Fraser and D. R. Hanson,
+.I A Retargetable C Compiler: Design and Implementation,
+Addison-Wesley, 1995. ISBN 0-8053-1670-1.
+.PP
+The World-Wide Web page at http://www.cs.princeton.edu/software/lcc/.
+.PP
+S. P. Harbison and G. L. Steele, Jr.,
+.I C: A Reference Manual,
+4th ed., Prentice-Hall, 1995.
+.PP
+B. W. Kernighan and D. M. Ritchie,
+.I The C Programming Language,
+2nd ed., Prentice-Hall, 1988.
+.PP
+American National Standards Inst.,
+.I American National Standard for Information Systems\(emProgramming
+.IR Language\(emC ,
+ANSI X3.159-1989, New York, 1990.
+.br
+.SH BUGS
+Mail bug reports along with the shortest preprocessed program
+that exposes them and the details reported by
+.IR lcc 's
+.B \-v
+option to lcc-bugs at princeton.edu. The WWW page at
+URL http://www.cs.princeton.edu/software/lcc/
+includes detailed instructions for reporting bugs.
+.PP
+The ANSI standard headers conform to the specifications in
+the Standard, which may be too restrictive for some applications,
+but necessary for portability.
+Functions given in the ANSI headers may be missing from
+some local C libraries (e.g., wide-character functions)
+or may not correspond exactly to the local versions;
+for example, the ANSI standard
+stdio.h
+specifies that
+.IR printf ,
+.IR fprintf ,
+and
+.I sprintf
+return the number of characters written to the file or array,
+but some existing libraries don't implement this convention.
+.PP
+On the MIPS and SPARC, old-style variadic functions must use
+varargs.h
+from MIPS or Sun. New-style is recommended.
+.PP
+With
+.BR \-b ,
+files compiled
+.I without
+.B \-b
+may cause
+.I bprint
+to print erroneous call graphs.
+For example, if
+.B f
+calls
+.B g
+calls
+.B h
+and
+.B f
+and
+.B h
+are compiled with
+.BR \-b ,
+but
+.B g
+is not,
+.B bprint
+will report that
+.B f
+called
+.BR h .
+The total number of calls is correct, however.
diff --git a/code/tools/lcc/doc/lcc.pdf b/code/tools/lcc/doc/lcc.pdf
new file mode 100644
index 0000000..6134de6
Binary files /dev/null and b/code/tools/lcc/doc/lcc.pdf differ
diff --git a/code/tools/lcc/etc/bytecode.c b/code/tools/lcc/etc/bytecode.c
new file mode 100644
index 0000000..fe4178f
--- /dev/null
+++ b/code/tools/lcc/etc/bytecode.c
@@ -0,0 +1,66 @@
+/* quake3 bytecode target */
+
+#include <string.h>
+#include <stdio.h>
+#include "../../../qcommon/q_platform.h"
+
+#ifdef _WIN32
+#define BINEXT ".exe"
+#else
+#define BINEXT ""
+#endif
+
+char *suffixes[] = { ".c", ".i", ".asm", ".o", ".out", 0 };
+char inputs[256] = "";
+char *cpp[] = { "q3cpp" BINEXT,
+ "-D__STDC__=1", "-D__STRICT_ANSI__", "-D__signed__=signed", "-DQ3_VM",
+ "$1", "$2", "$3", 0 };
+char *include[] = { 0 };
+char *com[] = { "q3rcc" BINEXT, "-target=bytecode", "$1", "$2", "$3", 0 };
+char *ld[] = { 0 };
+char *as[] = { 0 };
+
+extern char *concat(char *, char *);
+
+/*
+===============
+UpdatePaths
+
+Updates the paths to q3cpp and q3rcc based on
+the directory that contains q3lcc
+===============
+*/
+void UpdatePaths( const char *lccBinary )
+{
+ char basepath[ 1024 ];
+ char *p;
+
+ strncpy( basepath, lccBinary, 1024 );
+ p = strrchr( basepath, PATH_SEP );
+
+ if( p )
+ {
+ *( p + 1 ) = '\0';
+
+ cpp[ 0 ] = concat( basepath, "q3cpp" BINEXT );
+ com[ 0 ] = concat( basepath, "q3rcc" BINEXT );
+ }
+}
+
+int option(char *arg) {
+ if (strncmp(arg, "-lccdir=", 8) == 0) {
+ cpp[0] = concat(&arg[8], "/q3cpp" BINEXT);
+ include[0] = concat("-I", concat(&arg[8], "/include"));
+ com[0] = concat(&arg[8], "/q3rcc" BINEXT);
+ } else if (strcmp(arg, "-p") == 0 || strcmp(arg, "-pg") == 0) {
+ fprintf( stderr, "no profiling supported, %s ignored.\n", arg);
+ } else if (strcmp(arg, "-b") == 0)
+ ;
+ else if (strcmp(arg, "-g") == 0)
+ fprintf( stderr, "no debugging supported, %s ignored.\n", arg);
+ else if (strncmp(arg, "-ld=", 4) == 0 || strcmp(arg, "-static") == 0) {
+ fprintf( stderr, "no linking supported, %s ignored.\n", arg);
+ } else
+ return 0;
+ return 1;
+}
diff --git a/code/tools/lcc/etc/lcc.c b/code/tools/lcc/etc/lcc.c
new file mode 100644
index 0000000..13ed690
--- /dev/null
+++ b/code/tools/lcc/etc/lcc.c
@@ -0,0 +1,797 @@
+/*
+ * lcc [ option ]... [ file | -llib ]...
+ * front end for the ANSI C compiler
+ */
+static char rcsid[] = "Id: dummy rcsid";
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <signal.h>
+#include <unistd.h>
+
+#ifndef TEMPDIR
+#define TEMPDIR "/tmp"
+#endif
+
+typedef struct list *List;
+struct list { /* circular list nodes: */
+ char *str; /* option or file name */
+ List link; /* next list element */
+};
+
+static void *alloc(int);
+static List append(char *,List);
+extern char *basename(char *);
+static int callsys(char *[]);
+extern char *concat(char *, char *);
+static int compile(char *, char *);
+static void compose(char *[], List, List, List);
+static void error(char *, char *);
+static char *exists(char *);
+static char *first(char *);
+static int filename(char *, char *);
+static List find(char *, List);
+static void help(void);
+static void initinputs(void);
+static void interrupt(int);
+static void opt(char *);
+static List path2list(const char *);
+extern int main(int, char *[]);
+extern char *replace(const char *, int, int);
+static void rm(List);
+extern char *strsave(const char *);
+extern char *stringf(const char *, ...);
+extern int suffix(char *, char *[], int);
+extern char *tempname(char *);
+
+#ifndef __sun
+extern int getpid(void);
+#endif
+
+extern char *cpp[], *include[], *com[], *as[],*ld[], inputs[], *suffixes[];
+extern int option(char *);
+
+static int errcnt; /* number of errors */
+static int Eflag; /* -E specified */
+static int Sflag = 1; /* -S specified */ //for Q3 we always generate asm
+static int cflag; /* -c specified */
+static int verbose; /* incremented for each -v */
+static List llist[2]; /* loader files, flags */
+static List alist; /* assembler flags */
+static List clist; /* compiler flags */
+static List plist; /* preprocessor flags */
+static List ilist; /* list of additional includes from LCCINPUTS */
+static List rmlist; /* list of files to remove */
+static char *outfile; /* ld output file or -[cS] object file */
+static int ac; /* argument count */
+static char **av; /* argument vector */
+char *tempdir = TEMPDIR; /* directory for temporary files */
+static char *progname;
+static List lccinputs; /* list of input directories */
+
+extern void UpdatePaths( const char *lccBinary );
+
+int main(int argc, char *argv[]) {
+ int i, j, nf;
+
+ progname = argv[0];
+
+ UpdatePaths( progname );
+
+ ac = argc + 50;
+ av = alloc(ac*sizeof(char *));
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ signal(SIGINT, interrupt);
+ if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
+ signal(SIGTERM, interrupt);
+#ifdef SIGHUP
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+ signal(SIGHUP, interrupt);
+#endif
+ if (getenv("TMP"))
+ tempdir = getenv("TMP");
+ else if (getenv("TEMP"))
+ tempdir = getenv("TEMP");
+ else if (getenv("TMPDIR"))
+ tempdir = getenv("TMPDIR");
+ assert(tempdir);
+ i = strlen(tempdir);
+ for (; (i > 0 && tempdir[i-1] == '/') || tempdir[i-1] == '\\'; i--)
+ tempdir[i-1] = '\0';
+ if (argc <= 1) {
+ help();
+ exit(0);
+ }
+ plist = append("-D__LCC__", 0);
+ initinputs();
+ if (getenv("LCCDIR"))
+ option(stringf("-lccdir=%s", getenv("LCCDIR")));
+ for (nf = 0, i = j = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-o") == 0) {
+ if (++i < argc) {
+ if (suffix(argv[i], suffixes, 2) >= 0) {
+ error("-o would overwrite %s", argv[i]);
+ exit(8);
+ }
+ outfile = argv[i];
+ continue;
+ } else {
+ error("unrecognized option `%s'", argv[i-1]);
+ exit(8);
+ }
+ } else if (strcmp(argv[i], "-target") == 0) {
+ if (argv[i+1] && *argv[i+1] != '-')
+ i++;
+ continue;
+ } else if (*argv[i] == '-' && argv[i][1] != 'l') {
+ opt(argv[i]);
+ continue;
+ } else if (*argv[i] != '-' && suffix(argv[i], suffixes, 3) >= 0)
+ nf++;
+ argv[j++] = argv[i];
+ }
+ if ((cflag || Sflag) && outfile && nf != 1) {
+ fprintf(stderr, "%s: -o %s ignored\n", progname, outfile);
+ outfile = 0;
+ }
+ argv[j] = 0;
+ for (i = 0; include[i]; i++)
+ plist = append(include[i], plist);
+ if (ilist) {
+ List b = ilist;
+ do {
+ b = b->link;
+ plist = append(b->str, plist);
+ } while (b != ilist);
+ }
+ ilist = 0;
+ for (i = 1; argv[i]; i++)
+ if (*argv[i] == '-')
+ opt(argv[i]);
+ else {
+ char *name = exists(argv[i]);
+ if (name) {
+ if (strcmp(name, argv[i]) != 0
+ || (nf > 1 && suffix(name, suffixes, 3) >= 0))
+ fprintf(stderr, "%s:\n", name);
+ filename(name, 0);
+ } else
+ error("can't find `%s'", argv[i]);
+ }
+ if (errcnt == 0 && !Eflag && !Sflag && !cflag && llist[1]) {
+ compose(ld, llist[0], llist[1],
+ append(outfile ? outfile : concat("a", first(suffixes[4])), 0));
+ if (callsys(av))
+ errcnt++;
+ }
+ rm(rmlist);
+ return errcnt ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+/* alloc - allocate n bytes or die */
+static void *alloc(int n) {
+ static char *avail, *limit;
+
+ n = (n + sizeof(char *) - 1)&~(sizeof(char *) - 1);
+ if (n >= limit - avail) {
+ avail = malloc(n + 4*1024);
+ assert(avail);
+ limit = avail + n + 4*1024;
+ }
+ avail += n;
+ return avail - n;
+}
+
+/* append - append a node with string str onto list, return new list */
+static List append(char *str, List list) {
+ List p = alloc(sizeof *p);
+
+ p->str = str;
+ if (list) {
+ p->link = list->link;
+ list->link = p;
+ } else
+ p->link = p;
+ return p;
+}
+
+/* basename - return base name for name, e.g. /usr/drh/foo.c => foo */
+char *basename(char *name) {
+ char *s, *b, *t = 0;
+
+ for (b = s = name; *s; s++)
+ if (*s == '/' || *s == '\\') {
+ b = s + 1;
+ t = 0;
+ } else if (*s == '.')
+ t = s;
+ s = strsave(b);
+ if (t)
+ s[t-b] = 0;
+ return s;
+}
+
+#ifdef WIN32
+#include <process.h>
+#else
+#define _P_WAIT 0
+#ifndef __sun
+extern int fork(void);
+#endif
+extern int wait(int *);
+
+static int _spawnvp(int mode, const char *cmdname, char *argv[]) {
+ int pid, n, status;
+
+ switch (pid = fork()) {
+ case -1:
+ fprintf(stderr, "%s: no more processes\n", progname);
+ return 100;
+ case 0:
+ // TTimo removing hardcoded paths, searching in $PATH
+ execvp(cmdname, argv);
+ fprintf(stderr, "%s: ", progname);
+ perror(cmdname);
+ fflush(stdout);
+ exit(100);
+ }
+ while ((n = wait(&status)) != pid && n != -1)
+ ;
+ if (n == -1)
+ status = -1;
+ if (status&0377) {
+ fprintf(stderr, "%s: fatal error in %s\n", progname, cmdname);
+ status |= 0400;
+ }
+ return (status>>8)&0377;
+}
+#endif
+
+/* callsys - execute the command described by av[0...], return status */
+static int callsys(char **av) {
+ int i, status = 0;
+ static char **argv;
+ static int argc;
+ char *executable;
+
+ for (i = 0; av[i] != NULL; i++)
+ ;
+ if (i + 1 > argc) {
+ argc = i + 1;
+ if (argv == NULL)
+ argv = malloc(argc*sizeof *argv);
+ else
+ argv = realloc(argv, argc*sizeof *argv);
+ assert(argv);
+ }
+ for (i = 0; status == 0 && av[i] != NULL; ) {
+ int j = 0;
+ char *s = NULL;
+ for ( ; av[i] != NULL && (s = strchr(av[i], '\n')) == NULL; i++)
+ argv[j++] = av[i];
+ if (s != NULL) {
+ if (s > av[i])
+ argv[j++] = stringf("%.*s", s - av[i], av[i]);
+ if (s[1] != '\0')
+ av[i] = s + 1;
+ else
+ i++;
+ }
+ argv[j] = NULL;
+ executable = strsave( argv[0] );
+ argv[0] = stringf( "\"%s\"", argv[0] );
+ if (verbose > 0) {
+ int k;
+ fprintf(stderr, "%s", argv[0]);
+ for (k = 1; argv[k] != NULL; k++)
+ fprintf(stderr, " %s", argv[k]);
+ fprintf(stderr, "\n");
+ }
+ if (verbose < 2)
+#ifndef WIN32
+ status = _spawnvp(_P_WAIT, executable, argv);
+#else
+ status = _spawnvp(_P_WAIT, executable, (const char* const*)argv);
+#endif
+ if (status == -1) {
+ fprintf(stderr, "%s: ", progname);
+ perror(argv[0]);
+ }
+ }
+ return status;
+}
+
+/* concat - return concatenation of strings s1 and s2 */
+char *concat(char *s1, char *s2) {
+ int n = strlen(s1);
+ char *s = alloc(n + strlen(s2) + 1);
+
+ strcpy(s, s1);
+ strcpy(s + n, s2);
+ return s;
+}
+
+/* compile - compile src into dst, return status */
+static int compile(char *src, char *dst) {
+ compose(com, clist, append(src, 0), append(dst, 0));
+ return callsys(av);
+}
+
+/* compose - compose cmd into av substituting a, b, c for $1, $2, $3, resp. */
+static void compose(char *cmd[], List a, List b, List c) {
+ int i, j;
+ List lists[3];
+
+ lists[0] = a;
+ lists[1] = b;
+ lists[2] = c;
+ for (i = j = 0; cmd[i]; i++) {
+ char *s = strchr(cmd[i], '$');
+ if (s && isdigit(s[1])) {
+ int k = s[1] - '0';
+ assert(k >=1 && k <= 3);
+ if ((b = lists[k-1])) {
+ b = b->link;
+ av[j] = alloc(strlen(cmd[i]) + strlen(b->str) - 1);
+ strncpy(av[j], cmd[i], s - cmd[i]);
+ av[j][s-cmd[i]] = '\0';
+ strcat(av[j], b->str);
+ strcat(av[j++], s + 2);
+ while (b != lists[k-1]) {
+ b = b->link;
+ assert(j < ac);
+ av[j++] = b->str;
+ };
+ }
+ } else if (*cmd[i]) {
+ assert(j < ac);
+ av[j++] = cmd[i];
+ }
+ }
+ av[j] = NULL;
+}
+
+/* error - issue error msg according to fmt, bump error count */
+static void error(char *fmt, char *msg) {
+ fprintf(stderr, "%s: ", progname);
+ fprintf(stderr, fmt, msg);
+ fprintf(stderr, "\n");
+ errcnt++;
+}
+
+/* exists - if `name' readable return its path name or return null */
+static char *exists(char *name) {
+ List b;
+
+ if ( (name[0] == '/' || name[0] == '\\' || name[2] == ':')
+ && access(name, 4) == 0)
+ return name;
+ if (!(name[0] == '/' || name[0] == '\\' || name[2] == ':')
+ && (b = lccinputs))
+ do {
+ b = b->link;
+ if (b->str[0]) {
+ char buf[1024];
+ sprintf(buf, "%s/%s", b->str, name);
+ if (access(buf, 4) == 0)
+ return strsave(buf);
+ } else if (access(name, 4) == 0)
+ return name;
+ } while (b != lccinputs);
+ if (verbose > 1)
+ return name;
+ return 0;
+}
+
+/* first - return first component in semicolon separated list */
+static char *first(char *list) {
+ char *s = strchr(list, ';');
+
+ if (s) {
+ char buf[1024];
+ strncpy(buf, list, s-list);
+ buf[s-list] = '\0';
+ return strsave(buf);
+ } else
+ return list;
+}
+
+/* filename - process file name argument `name', return status */
+static int filename(char *name, char *base) {
+ int status = 0;
+ static char *stemp, *itemp;
+
+ if (base == 0)
+ base = basename(name);
+ switch (suffix(name, suffixes, 4)) {
+ case 0: /* C source files */
+ compose(cpp, plist, append(name, 0), 0);
+ if (Eflag) {
+ status = callsys(av);
+ break;
+ }
+ if (itemp == NULL)
+ itemp = tempname(first(suffixes[1]));
+ compose(cpp, plist, append(name, 0), append(itemp, 0));
+ status = callsys(av);
+ if (status == 0)
+ return filename(itemp, base);
+ break;
+ case 1: /* preprocessed source files */
+ if (Eflag)
+ break;
+ if (Sflag)
+ status = compile(name, outfile ? outfile : concat(base, first(suffixes[2])));
+ else if ((status = compile(name, stemp?stemp:(stemp=tempname(first(suffixes[2]))))) == 0)
+ return filename(stemp, base);
+ break;
+ case 2: /* assembly language files */
+ if (Eflag)
+ break;
+ if (!Sflag) {
+ char *ofile;
+ if (cflag && outfile)
+ ofile = outfile;
+ else if (cflag)
+ ofile = concat(base, first(suffixes[3]));
+ else
+ ofile = tempname(first(suffixes[3]));
+ compose(as, alist, append(name, 0), append(ofile, 0));
+ status = callsys(av);
+ if (!find(ofile, llist[1]))
+ llist[1] = append(ofile, llist[1]);
+ }
+ break;
+ case 3: /* object files */
+ if (!find(name, llist[1]))
+ llist[1] = append(name, llist[1]);
+ break;
+ default:
+ if (Eflag) {
+ compose(cpp, plist, append(name, 0), 0);
+ status = callsys(av);
+ }
+ llist[1] = append(name, llist[1]);
+ break;
+ }
+ if (status)
+ errcnt++;
+ return status;
+}
+
+/* find - find 1st occurrence of str in list, return list node or 0 */
+static List find(char *str, List list) {
+ List b;
+
+ if ((b = list))
+ do {
+ if (strcmp(str, b->str) == 0)
+ return b;
+ } while ((b = b->link) != list);
+ return 0;
+}
+
+/* help - print help message */
+static void help(void) {
+ static char *msgs[] = {
+"", " [ option | file ]...\n",
+" except for -l, options are processed left-to-right before files\n",
+" unrecognized options are taken to be linker options\n",
+"-A warn about nonANSI usage; 2nd -A warns more\n",
+"-b emit expression-level profiling code; see bprint(1)\n",
+#ifdef sparc
+"-Bstatic -Bdynamic specify static or dynamic libraries\n",
+#endif
+"-Bdir/ use the compiler named `dir/rcc'\n",
+"-c compile only\n",
+"-dn set switch statement density to `n'\n",
+"-Dname -Dname=def define the preprocessor symbol `name'\n",
+"-E run only the preprocessor on the named C programs and unsuffixed files\n",
+"-g produce symbol table information for debuggers\n",
+"-help or -? print this message\n",
+"-Idir add `dir' to the beginning of the list of #include directories\n",
+"-lx search library `x'\n",
+"-N do not search the standard directories for #include files\n",
+"-n emit code to check for dereferencing zero pointers\n",
+"-O is ignored\n",
+"-o file leave the output in `file'\n",
+"-P print ANSI-style declarations for globals\n",
+"-p -pg emit profiling code; see prof(1) and gprof(1)\n",
+"-S compile to assembly language\n",
+#ifdef linux
+"-static specify static libraries (default is dynamic)\n",
+#endif
+"-t -tname emit function tracing calls to printf or to `name'\n",
+"-target name is ignored\n",
+"-tempdir=dir place temporary files in `dir/'", "\n"
+"-Uname undefine the preprocessor symbol `name'\n",
+"-v show commands as they are executed; 2nd -v suppresses execution\n",
+"-w suppress warnings\n",
+"-Woarg specify system-specific `arg'\n",
+"-W[pfal]arg pass `arg' to the preprocessor, compiler, assembler, or linker\n",
+ 0 };
+ int i;
+ char *s;
+
+ msgs[0] = progname;
+ for (i = 0; msgs[i]; i++) {
+ fprintf(stderr, "%s", msgs[i]);
+ if (strncmp("-tempdir", msgs[i], 8) == 0 && tempdir)
+ fprintf(stderr, "; default=%s", tempdir);
+ }
+#define xx(v) if ((s = getenv(#v))) fprintf(stderr, #v "=%s\n", s)
+ xx(LCCINPUTS);
+ xx(LCCDIR);
+#undef xx
+}
+
+/* initinputs - if LCCINPUTS or include is defined, use them to initialize various lists */
+static void initinputs(void) {
+ char *s = getenv("LCCINPUTS");
+ List b;
+
+ if (s == 0 || (s = inputs)[0] == 0)
+ s = ".";
+ if (s) {
+ lccinputs = path2list(s);
+ if ((b = lccinputs))
+ do {
+ b = b->link;
+ if (strcmp(b->str, ".") != 0) {
+ ilist = append(concat("-I", b->str), ilist);
+ if (strstr(com[1], "win32") == NULL)
+ llist[0] = append(concat("-L", b->str), llist[0]);
+ } else
+ b->str = "";
+ } while (b != lccinputs);
+ }
+}
+
+/* interrupt - catch interrupt signals */
+static void interrupt(int n) {
+ rm(rmlist);
+ exit(n = 100);
+}
+
+/* opt - process option in arg */
+static void opt(char *arg) {
+ switch (arg[1]) { /* multi-character options */
+ case 'W': /* -Wxarg */
+ if (arg[2] && arg[3])
+ switch (arg[2]) {
+ case 'o':
+ if (option(&arg[3]))
+ return;
+ break;
+ case 'p':
+ plist = append(&arg[3], plist);
+ return;
+ case 'f':
+ if (strcmp(&arg[3], "-C") || option("-b")) {
+ clist = append(&arg[3], clist);
+ return;
+ }
+ break; /* and fall thru */
+ case 'a':
+ alist = append(&arg[3], alist);
+ return;
+ case 'l':
+ llist[0] = append(&arg[3], llist[0]);
+ return;
+ }
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ return;
+ case 'd': /* -dn */
+ arg[1] = 's';
+ clist = append(arg, clist);
+ return;
+ case 't': /* -t -tname -tempdir=dir */
+ if (strncmp(arg, "-tempdir=", 9) == 0)
+ tempdir = arg + 9;
+ else
+ clist = append(arg, clist);
+ return;
+ case 'p': /* -p -pg */
+ if (option(arg))
+ clist = append(arg, clist);
+ else
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ return;
+ case 'D': /* -Dname -Dname=def */
+ case 'U': /* -Uname */
+ case 'I': /* -Idir */
+ plist = append(arg, plist);
+ return;
+ case 'B': /* -Bdir -Bstatic -Bdynamic */
+#ifdef sparc
+ if (strcmp(arg, "-Bstatic") == 0 || strcmp(arg, "-Bdynamic") == 0)
+ llist[1] = append(arg, llist[1]);
+ else
+#endif
+ {
+ static char *path;
+ if (path)
+ error("-B overwrites earlier option", 0);
+ path = arg + 2;
+ if (strstr(com[1], "win32") != NULL)
+ com[0] = concat(replace(path, '/', '\\'), concat("rcc", first(suffixes[4])));
+ else
+ com[0] = concat(path, "rcc");
+ if (path[0] == 0)
+ error("missing directory in -B option", 0);
+ }
+ return;
+ case 'h':
+ if (strcmp(arg, "-help") == 0) {
+ static int printed = 0;
+ case '?':
+ if (!printed)
+ help();
+ printed = 1;
+ return;
+ }
+#ifdef linux
+ case 's':
+ if (strcmp(arg,"-static") == 0) {
+ if (!option(arg))
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ return;
+ }
+#endif
+ }
+ if (arg[2] == 0)
+ switch (arg[1]) { /* single-character options */
+ case 'S':
+ Sflag++;
+ return;
+ case 'O':
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ return;
+ case 'A': case 'n': case 'w': case 'P':
+ clist = append(arg, clist);
+ return;
+ case 'g': case 'b':
+ if (option(arg))
+ clist = append(arg[1] == 'g' ? "-g2" : arg, clist);
+ else
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ return;
+ case 'G':
+ if (option(arg)) {
+ clist = append("-g3", clist);
+ llist[0] = append("-N", llist[0]);
+ } else
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ return;
+ case 'E':
+ Eflag++;
+ return;
+ case 'c':
+ cflag++;
+ return;
+ case 'N':
+ if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
+ plist = append("-nostdinc", plist);
+ include[0] = 0;
+ ilist = 0;
+ return;
+ case 'v':
+ if (verbose++ == 0) {
+ if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
+ plist = append(arg, plist);
+ clist = append(arg, clist);
+ fprintf(stderr, "%s %s\n", progname, rcsid);
+ }
+ return;
+ }
+ if (cflag || Sflag || Eflag)
+ fprintf(stderr, "%s: %s ignored\n", progname, arg);
+ else
+ llist[1] = append(arg, llist[1]);
+}
+
+/* path2list - convert a colon- or semicolon-separated list to a list */
+static List path2list(const char *path) {
+ List list = NULL;
+ char sep = ':';
+
+ if (path == NULL)
+ return NULL;
+ if (strchr(path, ';'))
+ sep = ';';
+ while (*path) {
+ char *p, buf[512];
+ if ((p = strchr(path, sep))) {
+ assert(p - path < sizeof buf);
+ strncpy(buf, path, p - path);
+ buf[p-path] = '\0';
+ } else {
+ assert(strlen(path) < sizeof buf);
+ strcpy(buf, path);
+ }
+ if (!find(buf, list))
+ list = append(strsave(buf), list);
+ if (p == 0)
+ break;
+ path = p + 1;
+ }
+ return list;
+}
+
+/* replace - copy str, then replace occurrences of from with to, return the copy */
+char *replace(const char *str, int from, int to) {
+ char *s = strsave(str), *p = s;
+
+ for ( ; (p = strchr(p, from)) != NULL; p++)
+ *p = to;
+ return s;
+}
+
+/* rm - remove files in list */
+static void rm(List list) {
+ if (list) {
+ List b = list;
+ if (verbose)
+ fprintf(stderr, "rm");
+ do {
+ if (verbose)
+ fprintf(stderr, " %s", b->str);
+ if (verbose < 2)
+ remove(b->str);
+ } while ((b = b->link) != list);
+ if (verbose)
+ fprintf(stderr, "\n");
+ }
+}
+
+/* strsave - return a saved copy of string str */
+char *strsave(const char *str) {
+ return strcpy(alloc(strlen(str)+1), str);
+}
+
+/* stringf - format and return a string */
+char *stringf(const char *fmt, ...) {
+ char buf[1024];
+ va_list ap;
+ int n;
+
+ va_start(ap, fmt);
+ n = vsprintf(buf, fmt, ap);
+ va_end(ap);
+ return strsave(buf);
+}
+
+/* suffix - if one of tails[0..n-1] holds a proper suffix of name, return its index */
+int suffix(char *name, char *tails[], int n) {
+ int i, len = strlen(name);
+
+ for (i = 0; i < n; i++) {
+ char *s = tails[i], *t;
+ for ( ; (t = strchr(s, ';')); s = t + 1) {
+ int m = t - s;
+ if (len > m && strncmp(&name[len-m], s, m) == 0)
+ return i;
+ }
+ if (*s) {
+ int m = strlen(s);
+ if (len > m && strncmp(&name[len-m], s, m) == 0)
+ return i;
+ }
+ }
+ return -1;
+}
+
+/* tempname - generate a temporary file name in tempdir with given suffix */
+char *tempname(char *suffix) {
+ static int n;
+ char *name = stringf("%s/lcc%d%d%s", tempdir, getpid(), n++, suffix);
+
+ if (strstr(com[1], "win32") != NULL)
+ name = replace(name, '/', '\\');
+ rmlist = append(name, rmlist);
+ return name;
+}
diff --git a/code/tools/lcc/lburg/gram.c b/code/tools/lcc/lburg/gram.c
new file mode 100644
index 0000000..a1cc890
--- /dev/null
+++ b/code/tools/lcc/lburg/gram.c
@@ -0,0 +1,682 @@
+#if defined(__STDC__) || defined(__cplusplus)
+#define YYCONST const
+#define YYPARAMS(x) x
+#define YYDEFUN(name, arglist, args) name(args)
+#define YYAND ,
+#define YYPTR void *
+#else
+#define YYCONST
+#define YYPARAMS(x) ()
+#define YYDEFUN(name, arglist, args) name arglist args;
+#define YYAND ;
+#define YYPTR char *
+#endif
+#ifndef lint
+YYCONST static char yysccsid[] = "@(#)yaccpar 1.8 (Berkeley +Cygnus.28) 01/20/91";
+#endif
+#define YYBYACC 1
+#ifndef YYDONT_INCLUDE_STDIO
+#include <stdio.h>
+#endif
+//#ifdef __cplusplus TA <tim at ngus.net> stdlib.h applies to C too
+#include <stdlib.h> /* for malloc/realloc/free */
+//#endif
+#line 2 "lburg/gram.y"
+#include <stdio.h>
+#include "lburg.h"
+/*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */
+static int yylineno = 0;
+#line 8 "lburg/gram.y"
+typedef union {
+ int n;
+ char *string;
+ Tree tree;
+} YYSTYPE;
+#line 37 "y.tab.c"
+#define TERMINAL 257
+#define START 258
+#define PPERCENT 259
+#define ID 260
+#define TEMPLATE 261
+#define CODE 262
+#define INT 263
+#define YYERRCODE 256
+static YYCONST short yylhs[] = { -1,
+ 0, 0, 4, 4, 6, 6, 6, 6, 7, 7,
+ 5, 5, 5, 5, 1, 3, 3, 3, 2,
+};
+static YYCONST short yylen[] = { 2,
+ 3, 1, 0, 2, 3, 3, 1, 2, 0, 4,
+ 0, 7, 2, 3, 1, 1, 4, 6, 1,
+};
+static YYCONST short yydefred[] = { 3,
+ 0, 0, 0, 9, 0, 11, 7, 4, 8, 0,
+ 15, 0, 0, 0, 5, 6, 0, 13, 0, 0,
+ 14, 0, 10, 0, 0, 0, 0, 0, 19, 0,
+ 17, 0, 12, 0, 18,
+};
+static YYCONST short yydgoto[] = { 1,
+ 12, 30, 25, 2, 13, 8, 10,
+};
+static YYCONST short yysindex[] = { 0,
+ 0, -4, -2, 0, -250, 0, 0, 0, 0, -9,
+ 0, 1, -10, -49, 0, 0, 3, 0, -44, -248,
+ 0, -244, 0, -22, -242, -244, -245, -37, 0, 10,
+ 0, -244, 0, -20, 0,
+};
+static YYCONST short yyrindex[] = { 0,
+ 0, 22, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 23, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, -39, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+};
+static YYCONST short yygindex[] = { 0,
+ 11, 0, -23, 0, 0, 0, 0,
+};
+#define YYTABLESIZE 255
+static YYCONST short yytable[] = { 18,
+ 15, 16, 28, 31, 16, 7, 32, 9, 34, 11,
+ 16, 20, 21, 22, 23, 24, 29, 26, 27, 33,
+ 35, 2, 1, 19, 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, 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, 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, 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, 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, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 17, 0, 0, 0, 11,
+ 14, 3, 4, 5, 6,
+};
+static YYCONST short yycheck[] = { 10,
+ 10, 41, 26, 41, 44, 10, 44, 10, 32, 260,
+ 10, 61, 10, 58, 263, 260, 262, 40, 261, 10,
+ 41, 0, 0, 13, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 261, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 256, -1, -1, -1, 260,
+ 260, 256, 257, 258, 259,
+};
+#define YYFINAL 1
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 263
+#if YYDEBUG
+static YYCONST char *YYCONST yyname[] = {
+"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+"TERMINAL","START","PPERCENT","ID","TEMPLATE","CODE","INT",
+};
+static YYCONST char *YYCONST yyrule[] = {
+"$accept : spec",
+"spec : decls PPERCENT rules",
+"spec : decls",
+"decls :",
+"decls : decls decl",
+"decl : TERMINAL blist '\\n'",
+"decl : START nonterm '\\n'",
+"decl : '\\n'",
+"decl : error '\\n'",
+"blist :",
+"blist : blist ID '=' INT",
+"rules :",
+"rules : rules nonterm ':' tree TEMPLATE cost '\\n'",
+"rules : rules '\\n'",
+"rules : rules error '\\n'",
+"nonterm : ID",
+"tree : ID",
+"tree : ID '(' tree ')'",
+"tree : ID '(' tree ',' tree ')'",
+"cost : CODE",
+};
+#endif
+#define YYLEX yylex()
+#define YYEMPTY -1
+#define yyclearin (yychar=(YYEMPTY))
+#define yyerrok (yyerrflag=0)
+#ifndef YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+#ifdef YYSTACKSIZE
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#endif
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 500
+#define YYMAXDEPTH 500
+#endif
+#endif
+#ifndef YYMAXSTACKSIZE
+#define YYMAXSTACKSIZE 10000
+#endif
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+YYSTYPE yyval;
+YYSTYPE yylval;
+static short *yyss;
+static YYSTYPE *yyvs;
+static int yystacksize;
+#define yyfree(x) free(x)
+extern int yylex();
+
+static YYPTR
+YYDEFUN (yymalloc, (bytes), unsigned bytes)
+{
+ YYPTR ptr = (YYPTR) malloc (bytes);
+ if (ptr != 0) return (ptr);
+ yyerror ("yyparse: memory exhausted");
+ return (0);
+}
+
+static YYPTR
+YYDEFUN (yyrealloc, (old, bytes), YYPTR old YYAND unsigned bytes)
+{
+ YYPTR ptr = (YYPTR) realloc (old, bytes);
+ if (ptr != 0) return (ptr);
+ yyerror ("yyparse: memory exhausted");
+ return (0);
+}
+
+static int
+#ifdef __GNUC__
+inline
+#endif
+yygrow ()
+{
+#if YYDEBUG
+ int old_stacksize = yystacksize;
+#endif
+ short *new_yyss;
+ YYSTYPE *new_yyvs;
+
+ if (yystacksize == YYMAXSTACKSIZE)
+ return (1);
+ yystacksize += (yystacksize + 1 ) / 2;
+ if (yystacksize > YYMAXSTACKSIZE)
+ yystacksize = YYMAXSTACKSIZE;
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: growing stack size from %d to %d\n",
+ old_stacksize, yystacksize);
+#endif
+ new_yyss = (short *) yyrealloc ((char *)yyss, yystacksize * sizeof (short));
+ if (new_yyss == 0)
+ return (1);
+ new_yyvs = (YYSTYPE *) yyrealloc ((char *)yyvs, yystacksize * sizeof (YYSTYPE));
+ if (new_yyvs == 0)
+ {
+ yyfree (new_yyss);
+ return (1);
+ }
+ yyss = new_yyss;
+ yyvs = new_yyvs;
+ return (0);
+}
+#line 60 "lburg/gram.y"
+#include <assert.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+
+int errcnt = 0;
+FILE *infp = NULL;
+FILE *outfp = NULL;
+static char buf[BUFSIZ], *bp = buf;
+static int ppercent = 0;
+static int code = 0;
+
+static int get(void) {
+ if (*bp == 0) {
+ bp = buf;
+ *bp = 0;
+ if (fgets(buf, sizeof buf, infp) == NULL)
+ return EOF;
+ yylineno++;
+ while (buf[0] == '%' && buf[1] == '{' && buf[2] == '\n') {
+ for (;;) {
+ if (fgets(buf, sizeof buf, infp) == NULL) {
+ yywarn("unterminated %{...%}\n");
+ return EOF;
+ }
+ yylineno++;
+ if (strcmp(buf, "%}\n") == 0)
+ break;
+ fputs(buf, outfp);
+ }
+ if (fgets(buf, sizeof buf, infp) == NULL)
+ return EOF;
+ yylineno++;
+ }
+ }
+ return *bp++;
+}
+
+void yyerror(char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (yylineno > 0)
+ fprintf(stderr, "line %d: ", yylineno);
+ vfprintf(stderr, fmt, ap);
+ if (fmt[strlen(fmt)-1] != '\n')
+ fprintf(stderr, "\n");
+ errcnt++;
+ va_end(ap);
+}
+
+int yylex(void) {
+ int c;
+
+ if (code) {
+ char *p;
+ bp += strspn(bp, " \t\f");
+ p = strchr(bp, '\n');
+ if (p == NULL)
+ p = strchr(bp, '\n');
+ while (p > bp && isspace(p[-1]))
+ p--;
+ yylval.string = alloc(p - bp + 1);
+ strncpy(yylval.string, bp, p - bp);
+ yylval.string[p - bp] = 0;
+ bp = p;
+ code--;
+ return CODE;
+ }
+ while ((c = get()) != EOF) {
+ switch (c) {
+ case ' ': case '\f': case '\t':
+ continue;
+ case '\n':
+ case '(': case ')': case ',':
+ case ':': case '=':
+ return c;
+ }
+ if (c == '%' && *bp == '%') {
+ bp++;
+ return ppercent++ ? 0 : PPERCENT;
+ } else if (c == '%' && strncmp(bp, "term", 4) == 0
+ && isspace(bp[4])) {
+ bp += 4;
+ return TERMINAL;
+ } else if (c == '%' && strncmp(bp, "start", 5) == 0
+ && isspace(bp[5])) {
+ bp += 5;
+ return START;
+ } else if (c == '"') {
+ char *p = strchr(bp, '"');
+ if (p == NULL) {
+ yyerror("missing \" in assembler template\n");
+ p = strchr(bp, '\n');
+ if (p == NULL)
+ p = strchr(bp, '\0');
+ }
+ assert(p);
+ yylval.string = alloc(p - bp + 1);
+ strncpy(yylval.string, bp, p - bp);
+ yylval.string[p - bp] = 0;
+ bp = *p == '"' ? p + 1 : p;
+ code++;
+ return TEMPLATE;
+ } else if (isdigit(c)) {
+ int n = 0;
+ do {
+ int d = c - '0';
+ if (n > (INT_MAX - d)/10)
+ yyerror("integer greater than %d\n", INT_MAX);
+ else
+ n = 10*n + d;
+ c = get();
+ } while (c != EOF && isdigit(c));
+ bp--;
+ yylval.n = n;
+ return INT;
+ } else if (isalpha(c)) {
+ char *p = bp - 1;
+ while (isalpha(*bp) || isdigit(*bp) || *bp == '_')
+ bp++;
+ yylval.string = alloc(bp - p + 1);
+ strncpy(yylval.string, p, bp - p);
+ yylval.string[bp - p] = 0;
+ return ID;
+ } else if (isprint(c))
+ yyerror("invalid character `%c'\n", c);
+ else
+ yyerror("invalid character `\\%03o'\n", (unsigned char)c);
+ }
+ return 0;
+}
+
+void yywarn(char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (yylineno > 0)
+ fprintf(stderr, "line %d: ", yylineno);
+ fprintf(stderr, "warning: ");
+ vfprintf(stderr, fmt, ap);
+}
+#line 403 "y.tab.c"
+#define YYABORT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+
+#if YYDEBUG
+#ifdef __cplusplus
+extern "C" char *getenv();
+#else
+extern char *getenv();
+#endif
+#endif
+
+int
+yyparse()
+{
+ register int yym, yyn, yystate;
+ register YYSTYPE *yyvsp;
+ register short *yyssp;
+ short *yysse;
+#if YYDEBUG
+ register YYCONST char *yys;
+
+ if (yys = getenv("YYDEBUG"))
+ {
+ yyn = *yys;
+ if (yyn >= '0' && yyn <= '9')
+ yydebug = yyn - '0';
+ }
+#endif
+
+ yynerrs = 0;
+ yyerrflag = 0;
+ yychar = (-1);
+
+ if (yyss == 0)
+ {
+ yyss = (short *) yymalloc (YYSTACKSIZE * sizeof (short));
+ if (yyss == 0)
+ goto yyabort;
+ yyvs = (YYSTYPE *) yymalloc (YYSTACKSIZE * sizeof (YYSTYPE));
+ if (yyvs == 0)
+ {
+ yyfree (yyss);
+ goto yyabort;
+ }
+ yystacksize = YYSTACKSIZE;
+ }
+ yysse = yyss + yystacksize - 1;
+ yyssp = yyss;
+ yyvsp = yyvs;
+ *yyssp = yystate = 0;
+ goto yyloop;
+
+yypush_lex:
+ yyval = yylval;
+ yystate = yytable[yyn];
+yypush:
+ if (yyssp >= yysse)
+ {
+ int depth = yyssp - yyss;
+ if (yygrow() != 0)
+ goto yyoverflow;
+ yysse = yyss + yystacksize -1;
+ yyssp = depth + yyss;
+ yyvsp = depth + yyvs;
+ }
+ *++yyssp = yystate;
+ *++yyvsp = yyval;
+
+yyloop:
+ if ((yyn = yydefred[yystate])) goto yyreduce;
+ yyn = yysindex[yystate];
+ if (yychar < 0)
+ {
+ if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+ if (!yys) yys = "illegal-symbol";
+ printf("yydebug: state %d, reading %d (%s)\n", yystate,
+ yychar, yys);
+ }
+#endif
+ }
+ if (yyn != 0
+ && ((yyn += yychar), ((unsigned)yyn <= (unsigned)YYTABLESIZE))
+ && yycheck[yyn] == yychar)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: state %d, shifting to state %d\n",
+ yystate, yytable[yyn]);
+#endif
+ if (yyerrflag > 0) --yyerrflag;
+ yychar = (-1);
+ goto yypush_lex;
+ }
+ yyn = yyrindex[yystate];
+ if (yyn != 0
+ && ((yyn += yychar), ((unsigned)yyn <= (unsigned)YYTABLESIZE))
+ && yycheck[yyn] == yychar)
+ {
+ yyn = yytable[yyn];
+ goto yyreduce;
+ }
+ if (yyerrflag) goto yyinrecovery;
+#ifdef lint
+ goto yynewerror;
+yynewerror:
+#endif
+ yyerror("syntax error");
+#ifdef lint
+ goto yyerrlab;
+yyerrlab:
+#endif
+ ++yynerrs;
+yyinrecovery:
+ if (yyerrflag < 3)
+ {
+ yyerrflag = 3;
+ for (;;)
+ {
+ yyn = yysindex[*yyssp];
+ if (yyn != 0
+ && ((yyn += YYERRCODE), ((unsigned)yyn <= (unsigned)YYTABLESIZE))
+ && yycheck[yyn] == YYERRCODE)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: state %d, error recovery shifting\
+ to state %d\n", *yyssp, yytable[yyn]);
+#endif
+ goto yypush_lex;
+ }
+ else
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: error recovery discarding state %d\n",
+ *yyssp);
+#endif
+ if (yyssp <= yyss) goto yyabort;
+ --yyssp;
+ --yyvsp;
+ }
+ }
+ }
+ else
+ {
+ if (yychar == 0) goto yyabort;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+ if (!yys) yys = "illegal-symbol";
+ printf("yydebug: state %d, error recovery discards token %d (%s)\n",
+ yystate, yychar, yys);
+ }
+#endif
+ yychar = (-1);
+ goto yyloop;
+ }
+yyreduce:
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: state %d, reducing by rule %d (%s)\n",
+ yystate, yyn, yyrule[yyn]);
+#endif
+ yym = yylen[yyn];
+ yyval = yyvsp[1-yym];
+ switch (yyn)
+ {
+case 1:
+#line 22 "lburg/gram.y"
+{ yylineno = 0; }
+break;
+case 2:
+#line 23 "lburg/gram.y"
+{ yylineno = 0; }
+break;
+case 6:
+#line 31 "lburg/gram.y"
+{
+ if (nonterm(yyvsp[-1].string)->number != 1)
+ yyerror("redeclaration of the start symbol\n");
+ }
+break;
+case 8:
+#line 36 "lburg/gram.y"
+{ yyerrok; }
+break;
+case 10:
+#line 40 "lburg/gram.y"
+{ term(yyvsp[-2].string, yyvsp[0].n); }
+break;
+case 12:
+#line 44 "lburg/gram.y"
+{ rule(yyvsp[-5].string, yyvsp[-3].tree, yyvsp[-2].string, yyvsp[-1].string); }
+break;
+case 14:
+#line 46 "lburg/gram.y"
+{ yyerrok; }
+break;
+case 15:
+#line 49 "lburg/gram.y"
+{ nonterm(yyval.string = yyvsp[0].string); }
+break;
+case 16:
+#line 52 "lburg/gram.y"
+{ yyval.tree = tree(yyvsp[0].string, 0, 0); }
+break;
+case 17:
+#line 53 "lburg/gram.y"
+{ yyval.tree = tree(yyvsp[-3].string, yyvsp[-1].tree, 0); }
+break;
+case 18:
+#line 54 "lburg/gram.y"
+{ yyval.tree = tree(yyvsp[-5].string, yyvsp[-3].tree, yyvsp[-1].tree); }
+break;
+case 19:
+#line 57 "lburg/gram.y"
+{ if (*yyvsp[0].string == 0) yyval.string = "0"; }
+break;
+#line 630 "y.tab.c"
+ }
+ yyssp -= yym;
+ yyvsp -= yym;
+ yym = yylhs[yyn];
+ yystate = *yyssp;
+ if (yystate == 0 && yym == 0)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: after reduction, shifting from state 0 to\
+ state %d\n", YYFINAL);
+#endif
+ yystate = YYFINAL;
+ *++yyssp = YYFINAL;
+ *++yyvsp = yyval;
+ if (yychar < 0)
+ {
+ if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+ if (!yys) yys = "illegal-symbol";
+ printf("yydebug: state %d, reading %d (%s)\n",
+ YYFINAL, yychar, yys);
+ }
+#endif
+ }
+ if (yychar == 0) goto yyaccept;
+ goto yyloop;
+ }
+ yyn = yygindex[yym];
+ if (yyn != 0
+ && ((yyn += yystate), ((unsigned)yyn <= (unsigned)YYTABLESIZE))
+ && yycheck[yyn] == yystate)
+ yystate = yytable[yyn];
+ else
+ yystate = yydgoto[yym];
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: after reduction, shifting from state %d \
+to state %d\n", *yyssp, yystate);
+#endif
+ goto yypush;
+yyoverflow:
+ yyerror("yacc stack overflow");
+yyabort:
+ return (1);
+yyaccept:
+ return (0);
+}
diff --git a/code/tools/lcc/lburg/gram.y b/code/tools/lcc/lburg/gram.y
new file mode 100644
index 0000000..1ecd8a9
--- /dev/null
+++ b/code/tools/lcc/lburg/gram.y
@@ -0,0 +1,202 @@
+%{
+#include <stdio.h>
+#include "lburg.h"
+static char rcsid[] = "$Id: gram.y 145 2001-10-17 21:53:10Z timo $";
+/*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */
+static int yylineno = 0;
+%}
+%union {
+ int n;
+ char *string;
+ Tree tree;
+}
+%term TERMINAL
+%term START
+%term PPERCENT
+
+%token <string> ID TEMPLATE CODE
+%token <n> INT
+%type <string> nonterm cost
+%type <tree> tree
+%%
+spec : decls PPERCENT rules { yylineno = 0; }
+ | decls { yylineno = 0; }
+ ;
+
+decls : /* lambda */
+ | decls decl
+ ;
+
+decl : TERMINAL blist '\n'
+ | START nonterm '\n' {
+ if (nonterm($2)->number != 1)
+ yyerror("redeclaration of the start symbol\n");
+ }
+ | '\n'
+ | error '\n' { yyerrok; }
+ ;
+
+blist : /* lambda */
+ | blist ID '=' INT { term($2, $4); }
+ ;
+
+rules : /* lambda */
+ | rules nonterm ':' tree TEMPLATE cost '\n' { rule($2, $4, $5, $6); }
+ | rules '\n'
+ | rules error '\n' { yyerrok; }
+ ;
+
+nonterm : ID { nonterm($$ = $1); }
+ ;
+
+tree : ID { $$ = tree($1, 0, 0); }
+ | ID '(' tree ')' { $$ = tree($1, $3, 0); }
+ | ID '(' tree ',' tree ')' { $$ = tree($1, $3, $5); }
+ ;
+
+cost : CODE { if (*$1 == 0) $$ = "0"; }
+ ;
+%%
+#include <assert.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+
+int errcnt = 0;
+FILE *infp = NULL;
+FILE *outfp = NULL;
+static char buf[BUFSIZ], *bp = buf;
+static int ppercent = 0;
+static int code = 0;
+
+static int get(void) {
+ if (*bp == 0) {
+ bp = buf;
+ *bp = 0;
+ if (fgets(buf, sizeof buf, infp) == NULL)
+ return EOF;
+ yylineno++;
+ while (buf[0] == '%' && buf[1] == '{' && buf[2] == '\n') {
+ for (;;) {
+ if (fgets(buf, sizeof buf, infp) == NULL) {
+ yywarn("unterminated %{...%}\n");
+ return EOF;
+ }
+ yylineno++;
+ if (strcmp(buf, "%}\n") == 0)
+ break;
+ fputs(buf, outfp);
+ }
+ if (fgets(buf, sizeof buf, infp) == NULL)
+ return EOF;
+ yylineno++;
+ }
+ }
+ return *bp++;
+}
+
+void yyerror(char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (yylineno > 0)
+ fprintf(stderr, "line %d: ", yylineno);
+ vfprintf(stderr, fmt, ap);
+ if (fmt[strlen(fmt)-1] != '\n')
+ fprintf(stderr, "\n");
+ errcnt++;
+ va_end(ap);
+}
+
+int yylex(void) {
+ int c;
+
+ if (code) {
+ char *p;
+ bp += strspn(bp, " \t\f");
+ p = strchr(bp, '\n');
+ if (p == NULL)
+ p = strchr(bp, '\n');
+ while (p > bp && isspace(p[-1]))
+ p--;
+ yylval.string = alloc(p - bp + 1);
+ strncpy(yylval.string, bp, p - bp);
+ yylval.string[p - bp] = 0;
+ bp = p;
+ code--;
+ return CODE;
+ }
+ while ((c = get()) != EOF) {
+ switch (c) {
+ case ' ': case '\f': case '\t':
+ continue;
+ case '\n':
+ case '(': case ')': case ',':
+ case ':': case '=':
+ return c;
+ }
+ if (c == '%' && *bp == '%') {
+ bp++;
+ return ppercent++ ? 0 : PPERCENT;
+ } else if (c == '%' && strncmp(bp, "term", 4) == 0
+ && isspace(bp[4])) {
+ bp += 4;
+ return TERMINAL;
+ } else if (c == '%' && strncmp(bp, "start", 5) == 0
+ && isspace(bp[5])) {
+ bp += 5;
+ return START;
+ } else if (c == '"') {
+ char *p = strchr(bp, '"');
+ if (p == NULL) {
+ yyerror("missing \" in assembler template\n");
+ p = strchr(bp, '\n');
+ if (p == NULL)
+ p = strchr(bp, '\0');
+ }
+ assert(p);
+ yylval.string = alloc(p - bp + 1);
+ strncpy(yylval.string, bp, p - bp);
+ yylval.string[p - bp] = 0;
+ bp = *p == '"' ? p + 1 : p;
+ code++;
+ return TEMPLATE;
+ } else if (isdigit(c)) {
+ int n = 0;
+ do {
+ int d = c - '0';
+ if (n > (INT_MAX - d)/10)
+ yyerror("integer greater than %d\n", INT_MAX);
+ else
+ n = 10*n + d;
+ c = get();
+ } while (c != EOF && isdigit(c));
+ bp--;
+ yylval.n = n;
+ return INT;
+ } else if (isalpha(c)) {
+ char *p = bp - 1;
+ while (isalpha(*bp) || isdigit(*bp) || *bp == '_')
+ bp++;
+ yylval.string = alloc(bp - p + 1);
+ strncpy(yylval.string, p, bp - p);
+ yylval.string[bp - p] = 0;
+ return ID;
+ } else if (isprint(c))
+ yyerror("invalid character `%c'\n", c);
+ else
+ yyerror("invalid character `\\%03o'\n", (unsigned char)c);
+ }
+ return 0;
+}
+
+void yywarn(char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (yylineno > 0)
+ fprintf(stderr, "line %d: ", yylineno);
+ fprintf(stderr, "warning: ");
+ vfprintf(stderr, fmt, ap);
+}
diff --git a/code/tools/lcc/lburg/lburg.1 b/code/tools/lcc/lburg/lburg.1
new file mode 100644
index 0000000..8cf7250
--- /dev/null
+++ b/code/tools/lcc/lburg/lburg.1
@@ -0,0 +1,179 @@
+.TH LBURG 1 "local \- 11/30/94"
+.\" $Id: lburg.1 145 2001-10-17 21:53:10Z timo $
+.SH NAME
+lburg \- lcc's code-generator generator
+.SH SYNOPSIS
+.B lburg
+[
+.I option
+]...
+[ [
+.I input
+]
+.I output
+]
+.br
+.SH DESCRIPTION
+.PP
+.I lburg
+reads an lcc-style BURG specification from
+.I input
+and writes a pattern-matching code generator to
+.IR output .
+If
+.I input
+is `\-' or is omitted,
+.I lburg
+reads the standard input;
+If
+.I output
+is `\-' or is omitted,
+.I lburg
+writes to the standard output.
+.PP
+.I lburg
+accepts specifications that conform to the following EBNF grammar.
+Terminals are enclosed in single quotes or are
+given in uppercase, all other symbols are nonterminals or English phrases,
+{X} denotes zero or more instances of X, and [X] denotes an optional X.
+.PP
+.nf
+.RS
+.ft CW
+spec: `%{' configuration `%}' { dcl } `%%' { rule }
+ [ `%%' C code ]
+
+dcl: `%start' nonterm
+ `%term' { ID `=' INT }
+
+rule: nonterm `:' tree template [ C expression ]
+
+tree: term `(' tree `,' tree `)'
+ term `(' tree `)'
+ term
+ nonterm
+
+nonterm: ID
+
+template: `"' { any character except double quote } `"'
+.RE
+.fi
+.PP
+Specifications are structurally similar to
+.IR yacc 's.
+Text between
+`\f(CW%{\fP'
+and
+`\f(CW%}\fP'
+is called the configuration section; there may be several such segments.
+All are concatenated and copied verbatim into the head of the output.
+Text after the second
+`\f(CW%%\fP',
+if any, is also copied verbatim into the output, at the end.
+.PP
+Specifications consist of declarations, a
+`\f(CW%%\fP'
+separator, and rules.
+Input is line-oriented; each declaration and rule must appear on a separate line,
+and declarations must begin in column 1.
+Declarations declare terminals \(em the operators in subject
+trees \(em and associate a unique, positive external symbol
+number with each one.
+Nonterminals are declared by their presence
+on the left side of rules. The
+\f(CW%start\fP
+declaration optionally declares a nonterminal as the start symbol.
+In the grammar above,
+\f(CWterm\fP
+and
+\f(CWnonterm\fP
+denote identifiers that are terminals and nonterminals.
+.PP
+Rules define tree patterns in a fully parenthesized prefix
+form. Every nonterminal denotes a tree.
+Each operator has a fixed
+arity, which is inferred from the rules in which it is used.
+A chain rule is a rule whose pattern is another nonterminal.
+If no start symbol is declared, the nonterminal defined by the first rule is used.
+.PP
+Each rule ends with an expression that computes the cost of matching
+that rule; omitted costs
+default to zero. Costs of chain rules must be constants.
+.PP
+The configuration section configures the output
+for the trees being parsed and the client's environment.
+As shown, this section must define
+\f(CWNODEPTR_TYPE\fP
+to be a visible typedef symbol for a pointer to a
+node in the subject tree.
+The labeller invokes
+\f(CWOP_LABEL(p)\fP,
+\f(CWLEFT\_CHILD(p)\fP, and
+\f(CWRIGHT\_CHILD(p)\fP
+to read the operator and children from the node pointed to by \f(CWp\fP.
+If the configuration section defines these operations as macros, they are implemented in-line;
+otherwise, they must be implemented as functions.
+.PP
+The matcher
+computes and stores a single integral state in each node of the subject tree.
+The configuration section must define a macro
+\f(CWSTATE_LABEL(p)\fP
+to access the state field of the node pointed to
+by \f(CWp\fP. It must be large enough to hold a pointer, and
+a macro is required because it is used as an lvalue.
+.PP
+.SH OPTIONS
+.TP
+.BI \-p \ prefix
+.br
+.ns
+.TP
+.BI \-p prefix
+Use
+.I prefix
+as the disambiquating prefix for visible names and fields.
+The default is `\f(CW_\fP'.
+.TP
+.B \-T
+Arrange for
+.sp
+.nf
+.ft CW
+ void _trace(NODEPTR_TYPE p, int eruleno,
+ int cost, int bestcost);
+.sp
+.fi
+.ft R
+to be called at each successful match.
+\f(CWp\fP
+identifies the node and
+\f(CWeruleno\fP
+identifies the matching rule; the rules are numbered
+beginning at 1 in the order they appear in the input.
+\f(CWcost\fP
+is the cost of the match and
+\f(CWbestcost\fP
+is the cost of the best previous match. The current match
+wins only if
+\f(CWcost\fP
+is less than \f(CWbestcost\fP.
+32767 represents the infinite cost of no previous match.
+\f(CW_trace\fP must be declared in the configuration section.
+.SH "SEE ALSO"
+.IR lcc (1)
+.PP
+C. W. Fraser and D. R. Hanson,
+.IR A Retargetable C Compiler: Design and Implementation ,
+Benjamin/Cummings, Redwood City, CA, 1995,
+ISBN 0-8053-1670-1. Chapter 14.
+.PP
+C. W. Fraser, D. R. Hanson and T. A. Proebsting,
+`Engineering a simple, efficient code generator generator,'
+.I
+ACM Letters on Programming Languages and Systems
+.BR 1 ,
+3 (Sep. 1992), 213-226.
+.br
+.SH BUGS
+Mail bug reports along with the shortest input
+that exposes them to drh at cs.princeton.edu.
diff --git a/code/tools/lcc/lburg/lburg.c b/code/tools/lcc/lburg/lburg.c
new file mode 100644
index 0000000..c43c96a
--- /dev/null
+++ b/code/tools/lcc/lburg/lburg.c
@@ -0,0 +1,671 @@
+#include <assert.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include "lburg.h"
+
+static char rcsid[] = "lburg.c - faked rcsid";
+
+static char *prefix = "";
+static int Tflag = 0;
+static int ntnumber = 0;
+static Nonterm start = 0;
+static Term terms;
+static Nonterm nts;
+static Rule rules;
+static int nrules;
+static struct block {
+ struct block *link;
+} *memlist; /* list of allocated blocks */
+
+static char *stringf(char *fmt, ...);
+static void print(char *fmt, ...);
+static void ckreach(Nonterm p);
+static void emitclosure(Nonterm nts);
+static void emitcost(Tree t, char *v);
+static void emitdefs(Nonterm nts, int ntnumber);
+static void emitheader(void);
+static void emitkids(Rule rules, int nrules);
+static void emitnts(Rule rules, int nrules);
+static void emitrecalc(char *pre, Term root, Term kid);
+static void emitrecord(char *pre, Rule r, char *c, int cost);
+static void emitrule(Nonterm nts);
+static void emitlabel(Term terms, Nonterm start, int ntnumber);
+static void emitstring(Rule rules);
+static void emitstruct(Nonterm nts, int ntnumber);
+static void emittest(Tree t, char *v, char *suffix);
+
+int main(int argc, char *argv[]) {
+ int c, i;
+ Nonterm p;
+
+ for (i = 1; i < argc; i++)
+ if (strcmp(argv[i], "-T") == 0)
+ Tflag = 1;
+ else if (strncmp(argv[i], "-p", 2) == 0 && argv[i][2])
+ prefix = &argv[i][2];
+ else if (strncmp(argv[i], "-p", 2) == 0 && i + 1 < argc)
+ prefix = argv[++i];
+ else if (*argv[i] == '-' && argv[i][1]) {
+ yyerror("usage: %s [-T | -p prefix]... [ [ input ] output ] \n",
+ argv[0]);
+ exit(1);
+ } else if (infp == NULL) {
+ if (strcmp(argv[i], "-") == 0)
+ infp = stdin;
+ else if ((infp = fopen(argv[i], "r")) == NULL) {
+ yyerror("%s: can't read `%s'\n", argv[0], argv[i]);
+ exit(1);
+ }
+ } else if (outfp == NULL) {
+ if (strcmp(argv[i], "-") == 0)
+ outfp = stdout;
+ if ((outfp = fopen(argv[i], "w")) == NULL) {
+ yyerror("%s: can't write `%s'\n", argv[0], argv[i]);
+ exit(1);
+ }
+ }
+ if (infp == NULL)
+ infp = stdin;
+ if (outfp == NULL)
+ outfp = stdout;
+ yyparse();
+ if (start)
+ ckreach(start);
+ for (p = nts; p; p = p->link) {
+ if (p->rules == NULL)
+ yyerror("undefined nonterminal `%s'\n", p->name);
+ if (!p->reached)
+ yyerror("can't reach nonterminal `%s'\n", p->name);
+ }
+ emitheader();
+ emitdefs(nts, ntnumber);
+ emitstruct(nts, ntnumber);
+ emitnts(rules, nrules);
+ emitstring(rules);
+ emitrule(nts);
+ emitclosure(nts);
+ if (start)
+ emitlabel(terms, start, ntnumber);
+ emitkids(rules, nrules);
+ if (!feof(infp))
+ while ((c = getc(infp)) != EOF)
+ putc(c, outfp);
+ while (memlist) { /* for purify */
+ struct block *q = memlist->link;
+ free(memlist);
+ memlist = q;
+ }
+ return errcnt > 0;
+}
+
+/* alloc - allocate nbytes or issue fatal error */
+void *alloc(int nbytes) {
+ struct block *p = calloc(1, sizeof *p + nbytes);
+
+ if (p == NULL) {
+ yyerror("out of memory\n");
+ exit(1);
+ }
+ p->link = memlist;
+ memlist = p;
+ return p + 1;
+}
+
+/* stringf - format and save a string */
+static char *stringf(char *fmt, ...) {
+ va_list ap;
+ char buf[512];
+
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+ return strcpy(alloc(strlen(buf) + 1), buf);
+}
+
+struct entry {
+ union {
+ char *name;
+ struct term t;
+ struct nonterm nt;
+ } sym;
+ struct entry *link;
+} *table[211];
+#define HASHSIZE (sizeof table/sizeof table[0])
+
+/* hash - return hash number for str */
+static unsigned hash(char *str) {
+ unsigned h = 0;
+
+ while (*str)
+ h = (h<<1) + *str++;
+ return h;
+}
+
+/* lookup - lookup symbol name */
+static void *lookup(char *name) {
+ struct entry *p = table[hash(name)%HASHSIZE];
+
+ for ( ; p; p = p->link)
+ if (strcmp(name, p->sym.name) == 0)
+ return &p->sym;
+ return 0;
+}
+
+/* install - install symbol name */
+static void *install(char *name) {
+ struct entry *p = alloc(sizeof *p);
+ int i = hash(name)%HASHSIZE;
+
+ p->sym.name = name;
+ p->link = table[i];
+ table[i] = p;
+ return &p->sym;
+}
+
+/* nonterm - create a new terminal id, if necessary */
+Nonterm nonterm(char *id) {
+ Nonterm p = lookup(id), *q = &nts;
+
+ if (p && p->kind == NONTERM)
+ return p;
+ if (p && p->kind == TERM)
+ yyerror("`%s' is a terminal\n", id);
+ p = install(id);
+ p->kind = NONTERM;
+ p->number = ++ntnumber;
+ if (p->number == 1)
+ start = p;
+ while (*q && (*q)->number < p->number)
+ q = &(*q)->link;
+ assert(*q == 0 || (*q)->number != p->number);
+ p->link = *q;
+ *q = p;
+ return p;
+}
+
+/* term - create a new terminal id with external symbol number esn */
+Term term(char *id, int esn) {
+ Term p = lookup(id), *q = &terms;
+
+ if (p)
+ yyerror("redefinition of terminal `%s'\n", id);
+ else
+ p = install(id);
+ p->kind = TERM;
+ p->esn = esn;
+ p->arity = -1;
+ while (*q && (*q)->esn < p->esn)
+ q = &(*q)->link;
+ if (*q && (*q)->esn == p->esn)
+ yyerror("duplicate external symbol number `%s=%d'\n",
+ p->name, p->esn);
+ p->link = *q;
+ *q = p;
+ return p;
+}
+
+/* tree - create & initialize a tree node with the given fields */
+Tree tree(char *id, Tree left, Tree right) {
+ Tree t = alloc(sizeof *t);
+ Term p = lookup(id);
+ int arity = 0;
+
+ if (left && right)
+ arity = 2;
+ else if (left)
+ arity = 1;
+ if (p == NULL && arity > 0) {
+ yyerror("undefined terminal `%s'\n", id);
+ p = term(id, -1);
+ } else if (p == NULL && arity == 0)
+ p = (Term)nonterm(id);
+ else if (p && p->kind == NONTERM && arity > 0) {
+ yyerror("`%s' is a nonterminal\n", id);
+ p = term(id, -1);
+ }
+ if (p->kind == TERM && p->arity == -1)
+ p->arity = arity;
+ if (p->kind == TERM && arity != p->arity)
+ yyerror("inconsistent arity for terminal `%s'\n", id);
+ t->op = p;
+ t->nterms = p->kind == TERM;
+ if ((t->left = left) != NULL)
+ t->nterms += left->nterms;
+ if ((t->right = right) != NULL)
+ t->nterms += right->nterms;
+ return t;
+}
+
+/* rule - create & initialize a rule with the given fields */
+Rule rule(char *id, Tree pattern, char *template, char *code) {
+ Rule r = alloc(sizeof *r), *q;
+ Term p = pattern->op;
+ char *end;
+
+ r->lhs = nonterm(id);
+ r->packed = ++r->lhs->lhscount;
+ for (q = &r->lhs->rules; *q; q = &(*q)->decode)
+ ;
+ *q = r;
+ r->pattern = pattern;
+ r->ern = ++nrules;
+ r->template = template;
+ r->code = code;
+ r->cost = strtol(code, &end, 10);
+ if (*end) {
+ r->cost = -1;
+ r->code = stringf("(%s)", code);
+ }
+ if (p->kind == TERM) {
+ for (q = &p->rules; *q; q = &(*q)->next)
+ ;
+ *q = r;
+ } else if (pattern->left == NULL && pattern->right == NULL) {
+ Nonterm p = pattern->op;
+ r->chain = p->chain;
+ p->chain = r;
+ if (r->cost == -1)
+ yyerror("illegal nonconstant cost `%s'\n", code);
+ }
+ for (q = &rules; *q; q = &(*q)->link)
+ ;
+ r->link = *q;
+ *q = r;
+ return r;
+}
+
+/* print - formatted output */
+static void print(char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ for ( ; *fmt; fmt++)
+ if (*fmt == '%')
+ switch (*++fmt) {
+ case 'd': fprintf(outfp, "%d", va_arg(ap, int)); break;
+ case 's': fputs(va_arg(ap, char *), outfp); break;
+ case 'P': fprintf(outfp, "%s_", prefix); break;
+ case 'T': {
+ Tree t = va_arg(ap, Tree);
+ print("%S", t->op);
+ if (t->left && t->right)
+ print("(%T,%T)", t->left, t->right);
+ else if (t->left)
+ print("(%T)", t->left);
+ break;
+ }
+ case 'R': {
+ Rule r = va_arg(ap, Rule);
+ print("%S: %T", r->lhs, r->pattern);
+ break;
+ }
+ case 'S': fputs(va_arg(ap, Term)->name, outfp); break;
+ case '1': case '2': case '3': case '4': case '5': {
+ int n = *fmt - '0';
+ while (n-- > 0)
+ putc('\t', outfp);
+ break;
+ }
+ default: putc(*fmt, outfp); break;
+ }
+ else
+ putc(*fmt, outfp);
+ va_end(ap);
+}
+
+/* reach - mark all nonterminals in tree t as reachable */
+static void reach(Tree t) {
+ Nonterm p = t->op;
+
+ if (p->kind == NONTERM)
+ if (!p->reached)
+ ckreach(p);
+ if (t->left)
+ reach(t->left);
+ if (t->right)
+ reach(t->right);
+}
+
+/* ckreach - mark all nonterminals reachable from p */
+static void ckreach(Nonterm p) {
+ Rule r;
+
+ p->reached = 1;
+ for (r = p->rules; r; r = r->decode)
+ reach(r->pattern);
+}
+
+/* emitcase - emit one case in function state */
+static void emitcase(Term p, int ntnumber) {
+ Rule r;
+
+ print("%1case %d: /* %S */\n", p->esn, p);
+ switch (p->arity) {
+ case 0: case -1:
+ break;
+ case 1:
+ print("%2%Plabel(LEFT_CHILD(a));\n");
+ break;
+ case 2:
+ print("%2%Plabel(LEFT_CHILD(a));\n");
+ print("%2%Plabel(RIGHT_CHILD(a));\n");
+ break;
+ default: assert(0);
+ }
+ for (r = p->rules; r; r = r->next) {
+ char *indent = "\t\t\0";
+ switch (p->arity) {
+ case 0: case -1:
+ print("%2/* %R */\n", r);
+ if (r->cost == -1) {
+ print("%2c = %s;\n", r->code);
+ emitrecord("\t\t", r, "c", 0);
+ } else
+ emitrecord("\t\t", r, r->code, 0);
+ break;
+ case 1:
+ if (r->pattern->nterms > 1) {
+ print("%2if (%1/* %R */\n", r);
+ emittest(r->pattern->left, "LEFT_CHILD(a)", " ");
+ print("%2) {\n");
+ indent = "\t\t\t";
+ } else
+ print("%2/* %R */\n", r);
+ if (r->pattern->nterms == 2 && r->pattern->left
+ && r->pattern->right == NULL)
+ emitrecalc(indent, r->pattern->op, r->pattern->left->op);
+ print("%sc = ", indent);
+ emitcost(r->pattern->left, "LEFT_CHILD(a)");
+ print("%s;\n", r->code);
+ emitrecord(indent, r, "c", 0);
+ if (indent[2])
+ print("%2}\n");
+ break;
+ case 2:
+ if (r->pattern->nterms > 1) {
+ print("%2if (%1/* %R */\n", r);
+ emittest(r->pattern->left, "LEFT_CHILD(a)",
+ r->pattern->right->nterms ? " && " : " ");
+ emittest(r->pattern->right, "RIGHT_CHILD(a)", " ");
+ print("%2) {\n");
+ indent = "\t\t\t";
+ } else
+ print("%2/* %R */\n", r);
+ print("%sc = ", indent);
+ emitcost(r->pattern->left, "LEFT_CHILD(a)");
+ emitcost(r->pattern->right, "RIGHT_CHILD(a)");
+ print("%s;\n", r->code);
+ emitrecord(indent, r, "c", 0);
+ if (indent[2])
+ print("%2}\n");
+ break;
+ default: assert(0);
+ }
+ }
+ print("%2break;\n");
+}
+
+/* emitclosure - emit the closure functions */
+static void emitclosure(Nonterm nts) {
+ Nonterm p;
+
+ for (p = nts; p; p = p->link)
+ if (p->chain)
+ print("static void %Pclosure_%S(NODEPTR_TYPE, int);\n", p);
+ print("\n");
+ for (p = nts; p; p = p->link)
+ if (p->chain) {
+ Rule r;
+ print("static void %Pclosure_%S(NODEPTR_TYPE a, int c) {\n"
+"%1struct %Pstate *p = STATE_LABEL(a);\n", p);
+ for (r = p->chain; r; r = r->chain)
+ emitrecord("\t", r, "c", r->cost);
+ print("}\n\n");
+ }
+}
+
+/* emitcost - emit cost computation for tree t */
+static void emitcost(Tree t, char *v) {
+ Nonterm p = t->op;
+
+ if (p->kind == TERM) {
+ if (t->left)
+ emitcost(t->left, stringf("LEFT_CHILD(%s)", v));
+ if (t->right)
+ emitcost(t->right, stringf("RIGHT_CHILD(%s)", v));
+ } else
+ print("((struct %Pstate *)(%s->x.state))->cost[%P%S_NT] + ", v, p);
+}
+
+/* emitdefs - emit nonterminal defines and data structures */
+static void emitdefs(Nonterm nts, int ntnumber) {
+ Nonterm p;
+
+ for (p = nts; p; p = p->link)
+ print("#define %P%S_NT %d\n", p, p->number);
+ print("\n");
+ print("static char *%Pntname[] = {\n%10,\n");
+ for (p = nts; p; p = p->link)
+ print("%1\"%S\",\n", p);
+ print("%10\n};\n\n");
+}
+
+/* emitheader - emit initial definitions */
+static void emitheader(void) {
+ time_t timer = time(NULL);
+
+ print("/*\ngenerated at %sby %s\n*/\n", ctime(&timer), rcsid);
+ print("static void %Pkids(NODEPTR_TYPE, int, NODEPTR_TYPE[]);\n");
+ print("static void %Plabel(NODEPTR_TYPE);\n");
+ print("static int %Prule(void*, int);\n\n");
+}
+
+/* computekids - compute paths to kids in tree t */
+static char *computekids(Tree t, char *v, char *bp, int *ip) {
+ Term p = t->op;
+
+ if (p->kind == NONTERM) {
+ sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v);
+ bp += strlen(bp);
+ } else if (p->arity > 0) {
+ bp = computekids(t->left, stringf("LEFT_CHILD(%s)", v), bp, ip);
+ if (p->arity == 2)
+ bp = computekids(t->right, stringf("RIGHT_CHILD(%s)", v), bp, ip);
+ }
+ return bp;
+}
+
+/* emitkids - emit _kids */
+static void emitkids(Rule rules, int nrules) {
+ int i;
+ Rule r, *rc = alloc((nrules + 1 + 1)*sizeof *rc);
+ char **str = alloc((nrules + 1 + 1)*sizeof *str);
+
+ for (i = 0, r = rules; r; r = r->link) {
+ int j = 0;
+ char buf[1024], *bp = buf;
+ *computekids(r->pattern, "p", bp, &j) = 0;
+ for (j = 0; str[j] && strcmp(str[j], buf); j++)
+ ;
+ if (str[j] == NULL)
+ str[j] = strcpy(alloc(strlen(buf) + 1), buf);
+ r->kids = rc[j];
+ rc[j] = r;
+ }
+ print("static void %Pkids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]) {\n"
+"%1if (!p)\n%2fatal(\"%Pkids\", \"Null tree\\n\", 0);\n"
+"%1if (!kids)\n%2fatal(\"%Pkids\", \"Null kids\\n\", 0);\n"
+"%1switch (eruleno) {\n");
+ for (i = 0; (r = rc[i]) != NULL; i++) {
+ for ( ; r; r = r->kids)
+ print("%1case %d: /* %R */\n", r->ern, r);
+ print("%s%2break;\n", str[i]);
+ }
+ print("%1default:\n%2fatal(\"%Pkids\", \"Bad rule number %%d\\n\", eruleno);\n%1}\n}\n\n");
+}
+
+/* emitlabel - emit label function */
+static void emitlabel(Term terms, Nonterm start, int ntnumber) {
+ int i;
+ Term p;
+
+ print("static void %Plabel(NODEPTR_TYPE a) {\n%1int c;\n"
+"%1struct %Pstate *p;\n\n"
+"%1if (!a)\n%2fatal(\"%Plabel\", \"Null tree\\n\", 0);\n");
+ print("%1STATE_LABEL(a) = p = allocate(sizeof *p, FUNC);\n"
+"%1p->rule._stmt = 0;\n");
+ for (i = 1; i <= ntnumber; i++)
+ print("%1p->cost[%d] =\n", i);
+ print("%20x7fff;\n%1switch (OP_LABEL(a)) {\n");
+ for (p = terms; p; p = p->link)
+ emitcase(p, ntnumber);
+ print("%1default:\n"
+"%2fatal(\"%Plabel\", \"Bad terminal %%d\\n\", OP_LABEL(a));\n%1}\n}\n\n");
+}
+
+/* computents - fill in bp with _nts vector for tree t */
+static char *computents(Tree t, char *bp) {
+ if (t) {
+ Nonterm p = t->op;
+ if (p->kind == NONTERM) {
+ sprintf(bp, "%s_%s_NT, ", prefix, p->name);
+ bp += strlen(bp);
+ } else
+ bp = computents(t->right, computents(t->left, bp));
+ }
+ return bp;
+}
+
+/* emitnts - emit _nts ragged array */
+static void emitnts(Rule rules, int nrules) {
+ Rule r;
+ int i, j, *nts = alloc((nrules + 1)*sizeof *nts);
+ char **str = alloc((nrules + 1)*sizeof *str);
+
+ for (i = 0, r = rules; r; r = r->link) {
+ char buf[1024];
+ *computents(r->pattern, buf) = 0;
+ for (j = 0; str[j] && strcmp(str[j], buf); j++)
+ ;
+ if (str[j] == NULL) {
+ print("static short %Pnts_%d[] = { %s0 };\n", j, buf);
+ str[j] = strcpy(alloc(strlen(buf) + 1), buf);
+ }
+ nts[i++] = j;
+ }
+ print("\nstatic short *%Pnts[] = {\n");
+ for (i = j = 0, r = rules; r; r = r->link) {
+ for ( ; j < r->ern; j++)
+ print("%10,%1/* %d */\n", j);
+ print("%1%Pnts_%d,%1/* %d */\n", nts[i++], j++);
+ }
+ print("};\n\n");
+}
+
+/* emitrecalc - emit code that tests for recalculation of INDIR?(VREGP) */
+static void emitrecalc(char *pre, Term root, Term kid) {
+ if (root->kind == TERM && strncmp(root->name, "INDIR", 5) == 0
+ && kid->kind == TERM && strcmp(kid->name, "VREGP" ) == 0) {
+ Nonterm p;
+ print("%sif (mayrecalc(a)) {\n", pre);
+ print("%s%1struct %Pstate *q = a->syms[RX]->u.t.cse->x.state;\n", pre);
+ for (p = nts; p; p = p->link) {
+ print("%s%1if (q->cost[%P%S_NT] == 0) {\n", pre, p);
+ print("%s%2p->cost[%P%S_NT] = 0;\n", pre, p);
+ print("%s%2p->rule.%P%S = q->rule.%P%S;\n", pre, p, p);
+ print("%s%1}\n", pre);
+ }
+ print("%s}\n", pre);
+ }
+}
+
+/* emitrecord - emit code that tests for a winning match of rule r */
+static void emitrecord(char *pre, Rule r, char *c, int cost) {
+ if (Tflag)
+ print("%s%Ptrace(a, %d, %s + %d, p->cost[%P%S_NT]);\n",
+ pre, r->ern, c, cost, r->lhs);
+ print("%sif (", pre);
+ print("%s + %d < p->cost[%P%S_NT]) {\n"
+"%s%1p->cost[%P%S_NT] = %s + %d;\n%s%1p->rule.%P%S = %d;\n",
+ c, cost, r->lhs, pre, r->lhs, c, cost, pre, r->lhs,
+ r->packed);
+ if (r->lhs->chain)
+ print("%s%1%Pclosure_%S(a, %s + %d);\n", pre, r->lhs, c, cost);
+ print("%s}\n", pre);
+}
+
+/* emitrule - emit decoding vectors and _rule */
+static void emitrule(Nonterm nts) {
+ Nonterm p;
+
+ for (p = nts; p; p = p->link) {
+ Rule r;
+ print("static short %Pdecode_%S[] = {\n%10,\n", p);
+ for (r = p->rules; r; r = r->decode)
+ print("%1%d,\n", r->ern);
+ print("};\n\n");
+ }
+ print("static int %Prule(void *state, int goalnt) {\n"
+"%1if (goalnt < 1 || goalnt > %d)\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n"
+"%1if (!state)\n%2return 0;\n%1switch (goalnt) {\n", ntnumber);
+ for (p = nts; p; p = p->link)
+ print("%1case %P%S_NT:"
+"%1return %Pdecode_%S[((struct %Pstate *)state)->rule.%P%S];\n", p, p, p);
+ print("%1default:\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n%2return 0;\n%1}\n}\n\n");
+}
+
+/* emitstring - emit arrays of templates, instruction flags, and rules */
+static void emitstring(Rule rules) {
+ Rule r;
+
+ print("static char *%Ptemplates[] = {\n");
+ print("/* 0 */%10,\n");
+ for (r = rules; r; r = r->link)
+ print("/* %d */%1\"%s\",%1/* %R */\n", r->ern, r->template, r);
+ print("};\n");
+ print("\nstatic char %Pisinstruction[] = {\n");
+ print("/* 0 */%10,\n");
+ for (r = rules; r; r = r->link) {
+ int len = strlen(r->template);
+ print("/* %d */%1%d,%1/* %s */\n", r->ern,
+ len >= 2 && r->template[len-2] == '\\' && r->template[len-1] == 'n',
+ r->template);
+ }
+ print("};\n");
+ print("\nstatic char *%Pstring[] = {\n");
+ print("/* 0 */%10,\n");
+ for (r = rules; r; r = r->link)
+ print("/* %d */%1\"%R\",\n", r->ern, r);
+ print("};\n\n");
+}
+
+/* emitstruct - emit the definition of the state structure */
+static void emitstruct(Nonterm nts, int ntnumber) {
+ print("struct %Pstate {\n%1short cost[%d];\n%1struct {\n", ntnumber + 1);
+ for ( ; nts; nts = nts->link) {
+ int n = 1, m = nts->lhscount;
+ while ((m >>= 1) != 0)
+ n++;
+ print("%2unsigned int %P%S:%d;\n", nts, n);
+ }
+ print("%1} rule;\n};\n\n");
+}
+
+/* emittest - emit clause for testing a match */
+static void emittest(Tree t, char *v, char *suffix) {
+ Term p = t->op;
+
+ if (p->kind == TERM) {
+ print("%3%s->op == %d%s/* %S */\n", v, p->esn,
+ t->nterms > 1 ? " && " : suffix, p);
+ if (t->left)
+ emittest(t->left, stringf("LEFT_CHILD(%s)", v),
+ t->right && t->right->nterms ? " && " : suffix);
+ if (t->right)
+ emittest(t->right, stringf("RIGHT_CHILD(%s)", v), suffix);
+ }
+}
diff --git a/code/tools/lcc/lburg/lburg.h b/code/tools/lcc/lburg/lburg.h
new file mode 100644
index 0000000..b67e802
--- /dev/null
+++ b/code/tools/lcc/lburg/lburg.h
@@ -0,0 +1,65 @@
+#ifndef BURG_INCLUDED
+#define BURG_INCLUDED
+
+/* iburg.c: */
+extern void *alloc(int nbytes);
+
+typedef enum { TERM=1, NONTERM } Kind;
+typedef struct rule *Rule;
+typedef struct term *Term;
+struct term { /* terminals: */
+ char *name; /* terminal name */
+ Kind kind; /* TERM */
+ int esn; /* external symbol number */
+ int arity; /* operator arity */
+ Term link; /* next terminal in esn order */
+ Rule rules; /* rules whose pattern starts with term */
+};
+
+typedef struct nonterm *Nonterm;
+struct nonterm { /* nonterminals: */
+ char *name; /* nonterminal name */
+ Kind kind; /* NONTERM */
+ int number; /* identifying number */
+ int lhscount; /* # times nt appears in a rule lhs */
+ int reached; /* 1 iff reached from start nonterminal */
+ Rule rules; /* rules w/nonterminal on lhs */
+ Rule chain; /* chain rules w/nonterminal on rhs */
+ Nonterm link; /* next terminal in number order */
+};
+extern Nonterm nonterm(char *id);
+extern Term term(char *id, int esn);
+
+typedef struct tree *Tree;
+struct tree { /* tree patterns: */
+ void *op; /* a terminal or nonterminal */
+ Tree left, right; /* operands */
+ int nterms; /* number of terminal nodes in this tree */
+};
+extern Tree tree(char *op, Tree left, Tree right);
+
+struct rule { /* rules: */
+ Nonterm lhs; /* lefthand side nonterminal */
+ Tree pattern; /* rule pattern */
+ int ern; /* external rule number */
+ int packed; /* packed external rule number */
+ int cost; /* cost, if a constant */
+ char *code; /* cost, if an expression */
+ char *template; /* assembler template */
+ Rule link; /* next rule in ern order */
+ Rule next; /* next rule with same pattern root */
+ Rule chain; /* next chain rule with same rhs */
+ Rule decode; /* next rule with same lhs */
+ Rule kids; /* next rule with same _kids pattern */
+};
+extern Rule rule(char *id, Tree pattern, char *template, char *code);
+
+/* gram.y: */
+void yyerror(char *fmt, ...);
+int yyparse(void);
+void yywarn(char *fmt, ...);
+extern int errcnt;
+extern FILE *infp;
+extern FILE *outfp;
+
+#endif
diff --git a/code/tools/lcc/src/alloc.c b/code/tools/lcc/src/alloc.c
new file mode 100644
index 0000000..e0566df
--- /dev/null
+++ b/code/tools/lcc/src/alloc.c
@@ -0,0 +1,94 @@
+#include "c.h"
+struct block {
+ struct block *next;
+ char *limit;
+ char *avail;
+};
+union align {
+ long l;
+ char *p;
+ double d;
+ int (*f)(void);
+};
+union header {
+ struct block b;
+ union align a;
+};
+#ifdef PURIFY
+union header *arena[3];
+
+void *allocate(unsigned long n, unsigned a) {
+ union header *new = malloc(sizeof *new + n);
+
+ assert(a < NELEMS(arena));
+ if (new == NULL) {
+ error("insufficient memory\n");
+ exit(1);
+ }
+ new->b.next = (void *)arena[a];
+ arena[a] = new;
+ return new + 1;
+}
+
+void deallocate(unsigned a) {
+ union header *p, *q;
+
+ assert(a < NELEMS(arena));
+ for (p = arena[a]; p; p = q) {
+ q = (void *)p->b.next;
+ free(p);
+ }
+ arena[a] = NULL;
+}
+
+void *newarray(unsigned long m, unsigned long n, unsigned a) {
+ return allocate(m*n, a);
+}
+#else
+static struct block
+ first[] = { { NULL }, { NULL }, { NULL } },
+ *arena[] = { &first[0], &first[1], &first[2] };
+static struct block *freeblocks;
+
+void *allocate(unsigned long n, unsigned a) {
+ struct block *ap;
+
+ assert(a < NELEMS(arena));
+ assert(n > 0);
+ ap = arena[a];
+ n = roundup(n, sizeof (union align));
+ while (n > ap->limit - ap->avail) {
+ if ((ap->next = freeblocks) != NULL) {
+ freeblocks = freeblocks->next;
+ ap = ap->next;
+ } else
+ {
+ unsigned m = sizeof (union header) + n + roundup(10*1024, sizeof (union align));
+ ap->next = malloc(m);
+ ap = ap->next;
+ if (ap == NULL) {
+ error("insufficient memory\n");
+ exit(1);
+ }
+ ap->limit = (char *)ap + m;
+ }
+ ap->avail = (char *)((union header *)ap + 1);
+ ap->next = NULL;
+ arena[a] = ap;
+
+ }
+ ap->avail += n;
+ return ap->avail - n;
+}
+
+void *newarray(unsigned long m, unsigned long n, unsigned a) {
+ return allocate(m*n, a);
+}
+void deallocate(unsigned a) {
+ assert(a < NELEMS(arena));
+ arena[a]->next = freeblocks;
+ freeblocks = first[a].next;
+ first[a].next = NULL;
+ arena[a] = &first[a];
+}
+#endif
diff --git a/code/tools/lcc/src/bind.c b/code/tools/lcc/src/bind.c
new file mode 100644
index 0000000..bc7b983
--- /dev/null
+++ b/code/tools/lcc/src/bind.c
@@ -0,0 +1,8 @@
+#include "c.h"
+extern Interface nullIR;
+extern Interface bytecodeIR;
+Binding bindings[] = {
+ { "null", &nullIR },
+ { "bytecode", &bytecodeIR },
+ { NULL, NULL },
+};
diff --git a/code/tools/lcc/src/bytecode.c b/code/tools/lcc/src/bytecode.c
new file mode 100644
index 0000000..e83429f
--- /dev/null
+++ b/code/tools/lcc/src/bytecode.c
@@ -0,0 +1,367 @@
+#include "c.h"
+#define I(f) b_##f
+
+
+static void I(segment)(int n) {
+ static int cseg;
+
+ if (cseg != n)
+ switch (cseg = n) {
+ case CODE: print("code\n"); return;
+ case DATA: print("data\n"); return;
+ case BSS: print("bss\n"); return;
+ case LIT: print("lit\n"); return;
+ default: assert(0);
+ }
+}
+
+static void I(address)(Symbol q, Symbol p, long n) {
+ q->x.name = stringf("%s%s%D", p->x.name, n > 0 ? "+" : "", n);
+}
+
+static void I(defaddress)(Symbol p) {
+ print("address %s\n", p->x.name);
+}
+
+static void I(defconst)(int suffix, int size, Value v) {
+ switch (suffix) {
+ case I:
+ if (size > sizeof (int))
+ print("byte %d %D\n", size, v.i);
+ else
+ print("byte %d %d\n", size, v.i);
+ return;
+ case U:
+ if (size > sizeof (unsigned))
+ print("byte %d %U\n", size, v.u);
+ else
+ print("byte %d %u\n", size, v.u);
+ return;
+ case P: print("byte %d %U\n", size, (unsigned long)v.p); return;
+ case F:
+ if (size == 4) {
+ floatint_t fi;
+ fi.f = v.d;
+ print("byte 4 %u\n", fi.ui);
+ } else {
+ unsigned *p = (unsigned *)&v.d;
+ print("byte 4 %u\n", p[swap]);
+ print("byte 4 %u\n", p[1 - swap]);
+ }
+ return;
+ }
+ assert(0);
+}
+
+static void I(defstring)(int len, char *str) {
+ char *s;
+
+ for (s = str; s < str + len; s++)
+ print("byte 1 %d\n", (*s)&0377);
+}
+
+static void I(defsymbol)(Symbol p) {
+ if (p->scope == CONSTANTS)
+ switch (optype(ttob(p->type))) {
+ case I: p->x.name = stringf("%D", p->u.c.v.i); break;
+ case U: p->x.name = stringf("%U", p->u.c.v.u); break;
+ case P: p->x.name = stringf("%U", p->u.c.v.p); break;
+ case F:
+ { // JDC: added this to get inline floats
+ floatint_t temp;
+
+ temp.f = p->u.c.v.d;
+ p->x.name = stringf("%U", temp.ui );
+ }
+ break;// JDC: added this
+ default: assert(0);
+ }
+ else if (p->scope >= LOCAL && p->sclass == STATIC)
+ p->x.name = stringf("$%d", genlabel(1));
+ else if (p->scope == LABELS || p->generated)
+ p->x.name = stringf("$%s", p->name);
+ else
+ p->x.name = p->name;
+}
+
+static void dumptree(Node p) {
+ switch (specific(p->op)) {
+ case ASGN+B:
+ assert(p->kids[0]);
+ assert(p->kids[1]);
+ assert(p->syms[0]);
+ dumptree(p->kids[0]);
+ dumptree(p->kids[1]);
+ print("%s %d\n", opname(p->op), p->syms[0]->u.c.v.u);
+ return;
+ case RET+V:
+ assert(!p->kids[0]);
+ assert(!p->kids[1]);
+ print("%s\n", opname(p->op));
+ return;
+ }
+ switch (generic(p->op)) {
+ case CNST: case ADDRG: case ADDRF: case ADDRL: case LABEL:
+ assert(!p->kids[0]);
+ assert(!p->kids[1]);
+ assert(p->syms[0] && p->syms[0]->x.name);
+ print("%s %s\n", opname(p->op), p->syms[0]->x.name);
+ return;
+ case CVF: case CVI: case CVP: case CVU:
+ assert(p->kids[0]);
+ assert(!p->kids[1]);
+ assert(p->syms[0]);
+ dumptree(p->kids[0]);
+ print("%s %d\n", opname(p->op), p->syms[0]->u.c.v.i);
+ return;
+ case ARG: case BCOM: case NEG: case INDIR: case JUMP: case RET:
+ assert(p->kids[0]);
+ assert(!p->kids[1]);
+ dumptree(p->kids[0]);
+ print("%s\n", opname(p->op));
+ return;
+ case CALL:
+ assert(p->kids[0]);
+ assert(!p->kids[1]);
+ assert(optype(p->op) != B);
+ dumptree(p->kids[0]);
+ print("%s\n", opname(p->op));
+ if ( !p->count ) { printf("pop\n"); }; // JDC
+ return;
+ case ASGN: case BOR: case BAND: case BXOR: case RSH: case LSH:
+ case ADD: case SUB: case DIV: case MUL: case MOD:
+ assert(p->kids[0]);
+ assert(p->kids[1]);
+ dumptree(p->kids[0]);
+ dumptree(p->kids[1]);
+ print("%s\n", opname(p->op));
+ return;
+ case EQ: case NE: case GT: case GE: case LE: case LT:
+ assert(p->kids[0]);
+ assert(p->kids[1]);
+ assert(p->syms[0]);
+ assert(p->syms[0]->x.name);
+ dumptree(p->kids[0]);
+ dumptree(p->kids[1]);
+ print("%s %s\n", opname(p->op), p->syms[0]->x.name);
+ return;
+ }
+ assert(0);
+}
+
+static void I(emit)(Node p) {
+ for (; p; p = p->link)
+ dumptree(p);
+}
+
+static void I(export)(Symbol p) {
+ print("export %s\n", p->x.name);
+}
+
+static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
+ int i;
+
+ (*IR->segment)(CODE);
+ offset = 0;
+ for (i = 0; caller[i] && callee[i]; i++) {
+ offset = roundup(offset, caller[i]->type->align);
+ caller[i]->x.name = callee[i]->x.name = stringf("%d", offset);
+ caller[i]->x.offset = callee[i]->x.offset = offset;
+ offset += caller[i]->type->size;
+ }
+ maxargoffset = maxoffset = argoffset = offset = 0;
+ gencode(caller, callee);
+ print("proc %s %d %d\n", f->x.name, maxoffset, maxargoffset);
+ emitcode();
+ print("endproc %s %d %d\n", f->x.name, maxoffset, maxargoffset);
+
+}
+
+static void gen02(Node p) {
+ assert(p);
+ if (generic(p->op) == ARG) {
+ assert(p->syms[0]);
+ argoffset += (p->syms[0]->u.c.v.i < 4 ? 4 : p->syms[0]->u.c.v.i);
+ } else if (generic(p->op) == CALL) {
+ maxargoffset = (argoffset > maxargoffset ? argoffset : maxargoffset);
+ argoffset = 0;
+ }
+}
+
+static void gen01(Node p) {
+ if (p) {
+ gen01(p->kids[0]);
+ gen01(p->kids[1]);
+ gen02(p);
+ }
+}
+
+static Node I(gen)(Node p) {
+ Node q;
+
+ assert(p);
+ for (q = p; q; q = q->link)
+ gen01(q);
+ return p;
+}
+
+static void I(global)(Symbol p) {
+ print("align %d\n", p->type->align > 4 ? 4 : p->type->align);
+ print("LABELV %s\n", p->x.name);
+}
+
+static void I(import)(Symbol p) {
+ print("import %s\n", p->x.name);
+}
+
+static void I(local)(Symbol p) {
+ offset = roundup(offset, p->type->align);
+ p->x.name = stringf("%d", offset);
+ p->x.offset = offset;
+ offset += p->type->size;
+}
+
+static void I(progbeg)(int argc, char *argv[]) {}
+
+static void I(progend)(void) {}
+
+static void I(space)(int n) {
+ print("skip %d\n", n);
+}
+
+//========================================================
+
+// JDC: hacked up to get interleaved source lines in asm code
+static char *sourceFile;
+static char *sourcePtr;
+static int sourceLine;
+
+static int filelength( FILE *f ) {
+ int pos;
+ int end;
+
+ pos = ftell (f);
+ fseek (f, 0, SEEK_END);
+ end = ftell (f);
+ fseek (f, pos, SEEK_SET);
+
+ return end;
+}
+
+static void LoadSourceFile( const char *filename ) {
+ FILE *f;
+ int length;
+
+ f = fopen( filename, "r" );
+ if ( !f ) {
+ print( ";couldn't open %s\n", filename );
+ sourceFile = NULL;
+ return;
+ }
+ length = filelength( f );
+ sourceFile = malloc( length + 1 );
+ if ( sourceFile ) {
+ size_t size;
+ size = fread( sourceFile, length, 1, f );
+ sourceFile[length] = 0;
+ }
+
+ fclose( f );
+ sourceLine = 1;
+ sourcePtr = sourceFile;
+}
+
+static void PrintToSourceLine( int line ) {
+ int c;
+
+ if ( !sourceFile ) {
+ return;
+ }
+ while ( sourceLine <= line ) {
+ int i;
+
+ for ( i = 0 ; sourcePtr[i] && sourcePtr[i] != '\n' ; i++ ) {
+ }
+ c = sourcePtr[i];
+ if ( c == '\n' ) {
+ sourcePtr[i] = 0;
+ }
+ print( ";%d:%s\n", sourceLine, sourcePtr );
+ if ( c == 0 ) {
+ sourcePtr += i; // end of file
+ } else {
+ sourcePtr += i+1;
+ }
+ sourceLine++;
+ }
+}
+
+static void I(stabline)(Coordinate *cp) {
+ static char *prevfile;
+ static int prevline;
+
+ if (cp->file && (prevfile == NULL || strcmp(prevfile, cp->file) != 0)) {
+ print("file \"%s\"\n", prevfile = cp->file);
+ prevline = 0;
+ if ( sourceFile ) {
+ free( sourceFile );
+ sourceFile = NULL;
+ }
+ // load the new source file
+ LoadSourceFile( cp->file );
+ }
+ if (cp->y != prevline) {
+ print("line %d\n", prevline = cp->y);
+ PrintToSourceLine( cp->y );
+ }
+}
+
+//========================================================
+
+#define b_blockbeg blockbeg
+#define b_blockend blockend
+
+Interface bytecodeIR = {
+ {1, 1, 0}, /* char */
+ {2, 2, 0}, /* short */
+ {4, 4, 0}, /* int */
+ {4, 4, 0}, /* long */
+ {4, 4, 0}, /* long long */
+ {4, 4, 0}, /* float */ // JDC: use inline floats
+ {4, 4, 0}, /* double */ // JDC: don't ever emit 8 byte double code
+ {4, 4, 0}, /* long double */ // JDC: don't ever emit 8 byte double code
+ {4, 4, 0}, /* T* */
+ {0, 4, 0}, /* struct */
+ 0, /* little_endian */
+ 0, /* mulops_calls */
+ 0, /* wants_callb */
+ 0, /* wants_argb */
+ 1, /* left_to_right */
+ 0, /* wants_dag */
+ 0, /* unsigned_char */
+ I(address),
+ I(blockbeg),
+ I(blockend),
+ I(defaddress),
+ I(defconst),
+ I(defstring),
+ I(defsymbol),
+ I(emit),
+ I(export),
+ I(function),
+ I(gen),
+ I(global),
+ I(import),
+ I(local),
+ I(progbeg),
+ I(progend),
+ I(segment),
+ I(space),
+ 0, /* I(stabblock) */
+ 0, /* I(stabend) */
+ 0, /* I(stabfend) */
+ 0, /* I(stabinit) */
+ I(stabline),
+ 0, /* I(stabsym) */
+ 0, /* I(stabtype) */
+};
diff --git a/code/tools/lcc/src/c.h b/code/tools/lcc/src/c.h
new file mode 100644
index 0000000..68c8f62
--- /dev/null
+++ b/code/tools/lcc/src/c.h
@@ -0,0 +1,729 @@
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+#define NEW(p,a) ((p) = allocate(sizeof *(p), (a)))
+#define NEW0(p,a) memset(NEW((p),(a)), 0, sizeof *(p))
+#define isaddrop(op) (specific(op)==ADDRG+P || specific(op)==ADDRL+P \
+ || specific(op)==ADDRF+P)
+
+#define MAXLINE 512
+#define BUFSIZE 4096
+
+#define istypename(t,tsym) (kind[t] == CHAR \
+ || (t == ID && tsym && tsym->sclass == TYPEDEF))
+#define sizeop(n) ((n)<<10)
+#define generic(op) ((op)&0x3F0)
+#define specific(op) ((op)&0x3FF)
+#define opindex(op) (((op)>>4)&0x3F)
+#define opkind(op) ((op)&~0x3F0)
+#define opsize(op) ((op)>>10)
+#define optype(op) ((op)&0xF)
+#ifdef __LCC__
+#ifndef __STDC__
+#define __STDC__
+#endif
+#endif
+#define NELEMS(a) ((int)(sizeof (a)/sizeof ((a)[0])))
+#undef roundup
+#define roundup(x,n) (((x)+((n)-1))&(~((n)-1)))
+#define mkop(op,ty) (specific((op) + ttob(ty)))
+
+#define extend(x,ty) ((x)&(1<<(8*(ty)->size-1)) ? (x)|((~0UL)<<(8*(ty)->size-1)) : (x)&ones(8*(ty)->size))
+#define ones(n) ((n)>=8*sizeof (unsigned long) ? ~0UL : ~((~0UL)<<(n)))
+
+#define isqual(t) ((t)->op >= CONST)
+#define unqual(t) (isqual(t) ? (t)->type : (t))
+
+#define isvolatile(t) ((t)->op == VOLATILE \
+ || (t)->op == CONST+VOLATILE)
+#define isconst(t) ((t)->op == CONST \
+ || (t)->op == CONST+VOLATILE)
+#define isarray(t) (unqual(t)->op == ARRAY)
+#define isstruct(t) (unqual(t)->op == STRUCT \
+ || unqual(t)->op == UNION)
+#define isunion(t) (unqual(t)->op == UNION)
+#define isfunc(t) (unqual(t)->op == FUNCTION)
+#define isptr(t) (unqual(t)->op == POINTER)
+#define ischar(t) ((t)->size == 1 && isint(t))
+#define isint(t) (unqual(t)->op == INT \
+ || unqual(t)->op == UNSIGNED)
+#define isfloat(t) (unqual(t)->op == FLOAT)
+#define isarith(t) (unqual(t)->op <= UNSIGNED)
+#define isunsigned(t) (unqual(t)->op == UNSIGNED)
+#define isscalar(t) (unqual(t)->op <= POINTER \
+ || unqual(t)->op == ENUM)
+#define isenum(t) (unqual(t)->op == ENUM)
+#define fieldsize(p) (p)->bitsize
+#define fieldright(p) ((p)->lsb - 1)
+#define fieldleft(p) (8*(p)->type->size - \
+ fieldsize(p) - fieldright(p))
+#define fieldmask(p) (~(~(unsigned)0<<fieldsize(p)))
+typedef struct node *Node;
+
+typedef struct list *List;
+
+typedef struct code *Code;
+
+typedef struct swtch *Swtch;
+
+typedef struct symbol *Symbol;
+
+typedef struct coord {
+ char *file;
+ unsigned x, y;
+} Coordinate;
+typedef struct table *Table;
+
+typedef union value {
+ long i;
+ unsigned long u;
+ double d;
+ void *p;
+ void (*g)(void);
+} Value;
+typedef struct tree *Tree;
+
+typedef struct type *Type;
+
+typedef struct field *Field;
+
+typedef struct {
+ unsigned printed:1;
+ unsigned marked;
+ unsigned short typeno;
+ void *xt;
+} Xtype;
+
+typedef union {
+ float f;
+ int i;
+ unsigned int ui;
+} floatint_t;
+
+#include "config.h"
+typedef struct metrics {
+ unsigned char size, align, outofline;
+} Metrics;
+typedef struct interface {
+ Metrics charmetric;
+ Metrics shortmetric;
+ Metrics intmetric;
+ Metrics longmetric;
+ Metrics longlongmetric;
+ Metrics floatmetric;
+ Metrics doublemetric;
+ Metrics longdoublemetric;
+ Metrics ptrmetric;
+ Metrics structmetric;
+ unsigned little_endian:1;
+ unsigned mulops_calls:1;
+ unsigned wants_callb:1;
+ unsigned wants_argb:1;
+ unsigned left_to_right:1;
+ unsigned wants_dag:1;
+ unsigned unsigned_char:1;
+void (*address)(Symbol p, Symbol q, long n);
+void (*blockbeg)(Env *);
+void (*blockend)(Env *);
+void (*defaddress)(Symbol);
+void (*defconst) (int suffix, int size, Value v);
+void (*defstring)(int n, char *s);
+void (*defsymbol)(Symbol);
+void (*emit) (Node);
+void (*export)(Symbol);
+void (*function)(Symbol, Symbol[], Symbol[], int);
+Node (*gen) (Node);
+void (*global)(Symbol);
+void (*import)(Symbol);
+void (*local)(Symbol);
+void (*progbeg)(int argc, char *argv[]);
+void (*progend)(void);
+void (*segment)(int);
+void (*space)(int);
+void (*stabblock)(int, int, Symbol*);
+void (*stabend) (Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *);
+void (*stabfend) (Symbol, int);
+void (*stabinit) (char *, int, char *[]);
+void (*stabline) (Coordinate *);
+void (*stabsym) (Symbol);
+void (*stabtype) (Symbol);
+ Xinterface x;
+} Interface;
+typedef struct binding {
+ char *name;
+ Interface *ir;
+} Binding;
+
+extern Binding bindings[];
+extern Interface *IR;
+typedef struct {
+ List blockentry;
+ List blockexit;
+ List entry;
+ List exit;
+ List returns;
+ List points;
+ List calls;
+ List end;
+} Events;
+
+enum {
+#define xx(a,b,c,d,e,f,g) a=b,
+#define yy(a,b,c,d,e,f,g)
+#include "token.h"
+ LAST
+};
+struct node {
+ short op;
+ short count;
+ Symbol syms[3];
+ Node kids[2];
+ Node link;
+ Xnode x;
+};
+enum {
+ F=FLOAT,
+ I=INT,
+ U=UNSIGNED,
+ P=POINTER,
+ V=VOID,
+ B=STRUCT
+};
+#define gop(name,value) name=value<<4,
+#define op(name,type,sizes)
+
+enum { gop(CNST,1)
+ op(CNST,F,fdx)
+ op(CNST,I,csilh)
+ op(CNST,P,p)
+ op(CNST,U,csilh)
+ gop(ARG,2)
+ op(ARG,B,-)
+ op(ARG,F,fdx)
+ op(ARG,I,ilh)
+ op(ARG,P,p)
+ op(ARG,U,ilh)
+ gop(ASGN,3)
+ op(ASGN,B,-)
+ op(ASGN,F,fdx)
+ op(ASGN,I,csilh)
+ op(ASGN,P,p)
+ op(ASGN,U,csilh)
+ gop(INDIR,4)
+ op(INDIR,B,-)
+ op(INDIR,F,fdx)
+ op(INDIR,I,csilh)
+ op(INDIR,P,p)
+ op(INDIR,U,csilh)
+ gop(CVF,7)
+ op(CVF,F,fdx)
+ op(CVF,I,ilh)
+ gop(CVI,8)
+ op(CVI,F,fdx)
+ op(CVI,I,csilh)
+ op(CVI,U,csilhp)
+ gop(CVP,9)
+ op(CVP,U,p)
+ gop(CVU,11)
+ op(CVU,I,csilh)
+ op(CVU,P,p)
+ op(CVU,U,csilh)
+ gop(NEG,12)
+ op(NEG,F,fdx)
+ op(NEG,I,ilh)
+ gop(CALL,13)
+ op(CALL,B,-)
+ op(CALL,F,fdx)
+ op(CALL,I,ilh)
+ op(CALL,P,p)
+ op(CALL,U,ilh)
+ op(CALL,V,-)
+ gop(RET,15)
+ op(RET,F,fdx)
+ op(RET,I,ilh)
+ op(RET,P,p)
+ op(RET,U,ilh)
+ op(RET,V,-)
+ gop(ADDRG,16)
+ op(ADDRG,P,p)
+ gop(ADDRF,17)
+ op(ADDRF,P,p)
+ gop(ADDRL,18)
+ op(ADDRL,P,p)
+ gop(ADD,19)
+ op(ADD,F,fdx)
+ op(ADD,I,ilh)
+ op(ADD,P,p)
+ op(ADD,U,ilhp)
+ gop(SUB,20)
+ op(SUB,F,fdx)
+ op(SUB,I,ilh)
+ op(SUB,P,p)
+ op(SUB,U,ilhp)
+ gop(LSH,21)
+ op(LSH,I,ilh)
+ op(LSH,U,ilh)
+ gop(MOD,22)
+ op(MOD,I,ilh)
+ op(MOD,U,ilh)
+ gop(RSH,23)
+ op(RSH,I,ilh)
+ op(RSH,U,ilh)
+ gop(BAND,24)
+ op(BAND,I,ilh)
+ op(BAND,U,ilh)
+ gop(BCOM,25)
+ op(BCOM,I,ilh)
+ op(BCOM,U,ilh)
+ gop(BOR,26)
+ op(BOR,I,ilh)
+ op(BOR,U,ilh)
+ gop(BXOR,27)
+ op(BXOR,I,ilh)
+ op(BXOR,U,ilh)
+ gop(DIV,28)
+ op(DIV,F,fdx)
+ op(DIV,I,ilh)
+ op(DIV,U,ilh)
+ gop(MUL,29)
+ op(MUL,F,fdx)
+ op(MUL,I,ilh)
+ op(MUL,U,ilh)
+ gop(EQ,30)
+ op(EQ,F,fdx)
+ op(EQ,I,ilh)
+ op(EQ,U,ilhp)
+ gop(GE,31)
+ op(GE,F,fdx)
+ op(GE,I,ilh)
+ op(GE,U,ilhp)
+ gop(GT,32)
+ op(GT,F,fdx)
+ op(GT,I,ilh)
+ op(GT,U,ilhp)
+ gop(LE,33)
+ op(LE,F,fdx)
+ op(LE,I,ilh)
+ op(LE,U,ilhp)
+ gop(LT,34)
+ op(LT,F,fdx)
+ op(LT,I,ilh)
+ op(LT,U,ilhp)
+ gop(NE,35)
+ op(NE,F,fdx)
+ op(NE,I,ilh)
+ op(NE,U,ilhp)
+ gop(JUMP,36)
+ op(JUMP,V,-)
+ gop(LABEL,37)
+ op(LABEL,V,-)
+ gop(LOAD,14)
+ op(LOAD,B,-)
+ op(LOAD,F,fdx)
+ op(LOAD,I,csilh)
+ op(LOAD,P,p)
+ op(LOAD,U,csilhp) LASTOP };
+
+#undef gop
+#undef op
+enum { CODE=1, BSS, DATA, LIT };
+enum { PERM=0, FUNC, STMT };
+struct list {
+ void *x;
+ List link;
+};
+
+struct code {
+ enum { Blockbeg, Blockend, Local, Address, Defpoint,
+ Label, Start, Gen, Jump, Switch
+ } kind;
+ Code prev, next;
+ union {
+ struct {
+ int level;
+ Symbol *locals;
+ Table identifiers, types;
+ Env x;
+ } block;
+ Code begin;
+ Symbol var;
+
+ struct {
+ Symbol sym;
+ Symbol base;
+ long offset;
+ } addr;
+ struct {
+ Coordinate src;
+ int point;
+ } point;
+ Node forest;
+ struct {
+ Symbol sym;
+ Symbol table;
+ Symbol deflab;
+ int size;
+ long *values;
+ Symbol *labels;
+ } swtch;
+
+ } u;
+};
+struct swtch {
+ Symbol sym;
+ int lab;
+ Symbol deflab;
+ int ncases;
+ int size;
+ long *values;
+ Symbol *labels;
+};
+struct symbol {
+ char *name;
+ int scope;
+ Coordinate src;
+ Symbol up;
+ List uses;
+ int sclass;
+ unsigned structarg:1;
+
+ unsigned addressed:1;
+ unsigned computed:1;
+ unsigned temporary:1;
+ unsigned generated:1;
+ unsigned defined:1;
+ Type type;
+ float ref;
+ union {
+ struct {
+ int label;
+ Symbol equatedto;
+ } l;
+ struct {
+ unsigned cfields:1;
+ unsigned vfields:1;
+ Table ftab; /* omit */
+ Field flist;
+ } s;
+ int value;
+ Symbol *idlist;
+ struct {
+ Value min, max;
+ } limits;
+ struct {
+ Value v;
+ Symbol loc;
+ } c;
+ struct {
+ Coordinate pt;
+ int label;
+ int ncalls;
+ Symbol *callee;
+ } f;
+ int seg;
+ Symbol alias;
+ struct {
+ Node cse;
+ int replace;
+ Symbol next;
+ } t;
+ } u;
+ Xsymbol x;
+};
+enum { CONSTANTS=1, LABELS, GLOBAL, PARAM, LOCAL };
+struct tree {
+ int op;
+ Type type;
+ Tree kids[2];
+ Node node;
+ union {
+ Value v;
+ Symbol sym;
+
+ Field field;
+ } u;
+};
+enum {
+ AND=38<<4,
+ NOT=39<<4,
+ OR=40<<4,
+ COND=41<<4,
+ RIGHT=42<<4,
+ FIELD=43<<4
+};
+struct type {
+ int op;
+ Type type;
+ int align;
+ int size;
+ union {
+ Symbol sym;
+ struct {
+ unsigned oldstyle:1;
+ Type *proto;
+ } f;
+ } u;
+ Xtype x;
+};
+struct field {
+ char *name;
+ Type type;
+ int offset;
+ short bitsize;
+ short lsb;
+ Field link;
+};
+extern int assignargs;
+extern int prunetemps;
+extern int nodecount;
+extern Symbol cfunc;
+extern Symbol retv;
+extern Tree (*optree[])(int, Tree, Tree);
+
+extern char kind[];
+extern int errcnt;
+extern int errlimit;
+extern int wflag;
+extern Events events;
+extern float refinc;
+
+extern unsigned char *cp;
+extern unsigned char *limit;
+extern char *firstfile;
+extern char *file;
+extern char *line;
+extern int lineno;
+extern int t;
+extern char *token;
+extern Symbol tsym;
+extern Coordinate src;
+extern int Aflag;
+extern int Pflag;
+extern Symbol YYnull;
+extern Symbol YYcheck;
+extern int glevel;
+extern int xref;
+
+extern int ncalled;
+extern int npoints;
+
+extern int needconst;
+extern int explicitCast;
+extern struct code codehead;
+extern Code codelist;
+extern Table stmtlabs;
+extern float density;
+extern Table constants;
+extern Table externals;
+extern Table globals;
+extern Table identifiers;
+extern Table labels;
+extern Table types;
+extern int level;
+
+extern List loci, symbols;
+
+extern List symbols;
+
+extern int where;
+extern Type chartype;
+extern Type doubletype;
+extern Type floattype;
+extern Type inttype;
+extern Type longdouble;
+extern Type longtype;
+extern Type longlong;
+extern Type shorttype;
+extern Type signedchar;
+extern Type unsignedchar;
+extern Type unsignedlonglong;
+extern Type unsignedlong;
+extern Type unsignedshort;
+extern Type unsignedtype;
+extern Type charptype;
+extern Type funcptype;
+extern Type voidptype;
+extern Type voidtype;
+extern Type unsignedptr;
+extern Type signedptr;
+extern Type widechar;
+extern void *allocate(unsigned long n, unsigned a);
+extern void deallocate(unsigned a);
+extern void *newarray(unsigned long m, unsigned long n, unsigned a);
+extern void walk(Tree e, int tlab, int flab);
+extern Node listnodes(Tree e, int tlab, int flab);
+extern Node newnode(int op, Node left, Node right, Symbol p);
+extern Tree cvtconst(Tree);
+extern void printdag(Node, int);
+extern void compound(int, Swtch, int);
+extern void defglobal(Symbol, int);
+extern void finalize(void);
+extern void program(void);
+
+extern Tree vcall(Symbol func, Type ty, ...);
+extern Tree addrof(Tree);
+extern Tree asgn(Symbol, Tree);
+extern Tree asgntree(int, Tree, Tree);
+extern Type assign(Type, Tree);
+extern Tree bittree(int, Tree, Tree);
+extern Tree call(Tree, Type, Coordinate);
+extern Tree calltree(Tree, Type, Tree, Symbol);
+extern Tree condtree(Tree, Tree, Tree);
+extern Tree cnsttree(Type, ...);
+extern Tree consttree(unsigned int, Type);
+extern Tree eqtree(int, Tree, Tree);
+extern int iscallb(Tree);
+extern Tree shtree(int, Tree, Tree);
+extern void typeerror(int, Tree, Tree);
+
+extern void test(int tok, char set[]);
+extern void expect(int tok);
+extern void skipto(int tok, char set[]);
+extern void error(const char *, ...);
+extern int fatal(const char *, const char *, int);
+extern void warning(const char *, ...);
+
+typedef void (*Apply)(void *, void *, void *);
+extern void attach(Apply, void *, List *);
+extern void apply(List event, void *arg1, void *arg2);
+extern Tree retype(Tree p, Type ty);
+extern Tree rightkid(Tree p);
+extern int hascall(Tree p);
+extern Type binary(Type, Type);
+extern Tree cast(Tree, Type);
+extern Tree cond(Tree);
+extern Tree expr0(int);
+extern Tree expr(int);
+extern Tree expr1(int);
+extern Tree field(Tree, const char *);
+extern char *funcname(Tree);
+extern Tree idtree(Symbol);
+extern Tree incr(int, Tree, Tree);
+extern Tree lvalue(Tree);
+extern Tree nullcall(Type, Symbol, Tree, Tree);
+extern Tree pointer(Tree);
+extern Tree rvalue(Tree);
+extern Tree value(Tree);
+
+extern void defpointer(Symbol);
+extern Type initializer(Type, int);
+extern void swtoseg(int);
+
+extern void input_init(int, char *[]);
+extern void fillbuf(void);
+extern void nextline(void);
+
+extern int getchr(void);
+extern int gettok(void);
+
+extern void emitcode(void);
+extern void gencode (Symbol[], Symbol[]);
+extern void fprint(FILE *f, const char *fmt, ...);
+extern char *stringf(const char *, ...);
+extern void check(Node);
+extern void print(const char *, ...);
+
+extern List append(void *x, List list);
+extern int length(List list);
+extern void *ltov (List *list, unsigned a);
+extern void init(int, char *[]);
+
+extern Type typename(void);
+extern void checklab(Symbol p, void *cl);
+extern Type enumdcl(void);
+extern void main_init(int, char *[]);
+extern int main(int, char *[]);
+
+extern void vfprint(FILE *, char *, const char *, va_list);
+
+extern int process(char *);
+extern int findfunc(char *, char *);
+extern int findcount(char *, int, int);
+
+extern Tree constexpr(int);
+extern int intexpr(int, int);
+extern Tree simplify(int, Type, Tree, Tree);
+extern int ispow2(unsigned long u);
+
+extern int reachable(int);
+
+extern void addlocal(Symbol);
+extern void branch(int);
+extern Code code(int);
+extern void definelab(int);
+extern void definept(Coordinate *);
+extern void equatelab(Symbol, Symbol);
+extern Node jump(int);
+extern void retcode(Tree);
+extern void statement(int, Swtch, int);
+extern void swcode(Swtch, int *, int, int);
+extern void swgen(Swtch);
+
+extern char * string(const char *str);
+extern char *stringn(const char *str, int len);
+extern char *stringd(long n);
+extern Symbol relocate(const char *name, Table src, Table dst);
+extern void use(Symbol p, Coordinate src);
+extern void locus(Table tp, Coordinate *cp);
+extern Symbol allsymbols(Table);
+
+extern Symbol constant(Type, Value);
+extern void enterscope(void);
+extern void exitscope(void);
+extern Symbol findlabel(int);
+extern Symbol findtype(Type);
+extern void foreach(Table, int, void (*)(Symbol, void *), void *);
+extern Symbol genident(int, Type, int);
+extern int genlabel(int);
+extern Symbol install(const char *, Table *, int, int);
+extern Symbol intconst(int);
+extern Symbol lookup(const char *, Table);
+extern Symbol mkstr(char *);
+extern Symbol mksymbol(int, const char *, Type);
+extern Symbol newtemp(int, int, int);
+extern Table table(Table, int);
+extern Symbol temporary(int, Type);
+extern char *vtoa(Type, Value);
+
+extern int nodeid(Tree);
+extern char *opname(int);
+extern int *printed(int);
+extern void printtree(Tree, int);
+extern Tree root(Tree);
+extern Tree texpr(Tree (*)(int), int, int);
+extern Tree tree(int, Type, Tree, Tree);
+
+extern void type_init(int, char *[]);
+
+extern Type signedint(Type);
+
+extern int hasproto(Type);
+extern void outtype(Type, FILE *);
+extern void printdecl (Symbol p, Type ty);
+extern void printproto(Symbol p, Symbol args[]);
+extern char *typestring(Type ty, char *id);
+extern Field fieldref(const char *name, Type ty);
+extern Type array(Type, int, int);
+extern Type atop(Type);
+extern Type btot(int, int);
+extern Type compose(Type, Type);
+extern Type deref(Type);
+extern int eqtype(Type, Type, int);
+extern Field fieldlist(Type);
+extern Type freturn(Type);
+extern Type ftype(Type, Type);
+extern Type func(Type, Type *, int);
+extern Field newfield(char *, Type, Type);
+extern Type newstruct(int, char *);
+extern void printtype(Type, int);
+extern Type promote(Type);
+extern Type ptr(Type);
+extern Type qual(int, Type);
+extern void rmtypes(int);
+extern int ttob(Type);
+extern int variadic(Type);
+
diff --git a/code/tools/lcc/src/config.h b/code/tools/lcc/src/config.h
new file mode 100644
index 0000000..6f0d5a6
--- /dev/null
+++ b/code/tools/lcc/src/config.h
@@ -0,0 +1,102 @@
+typedef struct {
+ unsigned char max_unaligned_load;
+ Symbol (*rmap)(int);
+
+ void (*blkfetch)(int size, int off, int reg, int tmp);
+ void (*blkstore)(int size, int off, int reg, int tmp);
+ void (*blkloop)(int dreg, int doff,
+ int sreg, int soff,
+ int size, int tmps[]);
+ void (*_label)(Node);
+ int (*_rule)(void*, int);
+ short **_nts;
+ void (*_kids)(Node, int, Node*);
+ char **_string;
+ char **_templates;
+ char *_isinstruction;
+ char **_ntname;
+ void (*emit2)(Node);
+ void (*doarg)(Node);
+ void (*target)(Node);
+ void (*clobber)(Node);
+} Xinterface;
+extern int askregvar(Symbol, Symbol);
+extern void blkcopy(int, int, int, int, int, int[]);
+extern int getregnum(Node);
+extern int mayrecalc(Node);
+extern int mkactual(int, int);
+extern void mkauto(Symbol);
+extern Symbol mkreg(char *, int, int, int);
+extern Symbol mkwildcard(Symbol *);
+extern int move(Node);
+extern int notarget(Node);
+extern void parseflags(int, char **);
+extern int range(Node, int, int);
+extern unsigned regloc(Symbol); /* omit */
+extern void rtarget(Node, int, Symbol);
+extern void setreg(Node, Symbol);
+extern void spill(unsigned, int, Node);
+extern int widens(Node);
+
+extern int argoffset, maxargoffset;
+extern int bflag, dflag;
+extern int dalign, salign;
+extern int framesize;
+extern unsigned freemask[], usedmask[];
+extern int offset, maxoffset;
+extern int swap;
+extern unsigned tmask[], vmask[];
+typedef struct {
+ unsigned listed:1;
+ unsigned registered:1;
+ unsigned emitted:1;
+ unsigned copy:1;
+ unsigned equatable:1;
+ unsigned spills:1;
+ unsigned mayrecalc:1;
+ void *state;
+ short inst;
+ Node kids[3];
+ Node prev, next;
+ Node prevuse;
+ short argno;
+} Xnode;
+typedef struct {
+ Symbol vbl;
+ short set;
+ short number;
+ unsigned mask;
+} *Regnode;
+enum { IREG=0, FREG=1 };
+typedef struct {
+ char *name;
+ unsigned int eaddr; /* omit */
+ int offset;
+ Node lastuse;
+ int usecount;
+ Regnode regnode;
+ Symbol *wildcard;
+} Xsymbol;
+enum { RX=2 };
+typedef struct {
+ int offset;
+ unsigned freemask[2];
+} Env;
+
+#define LBURG_MAX SHRT_MAX
+
+enum { VREG=(44<<4) };
+
+/* Exported for the front end */
+extern void blockbeg(Env *);
+extern void blockend(Env *);
+extern void emit(Node);
+extern Node gen(Node);
+
+extern unsigned emitbin(Node, int);
+
+#ifdef NDEBUG
+#define debug(x) (void)0
+#else
+#define debug(x) (void)(dflag&&((x),0))
+#endif
diff --git a/code/tools/lcc/src/dag.c b/code/tools/lcc/src/dag.c
new file mode 100644
index 0000000..420cbe7
--- /dev/null
+++ b/code/tools/lcc/src/dag.c
@@ -0,0 +1,736 @@
+#include "c.h"
+
+
+#define iscall(op) (generic(op) == CALL \
+ || (IR->mulops_calls \
+ && (generic(op)==DIV||generic(op)==MOD||generic(op)==MUL) \
+ && ( optype(op)==U || optype(op)==I)))
+static Node forest;
+static struct dag {
+ struct node node;
+ struct dag *hlink;
+} *buckets[16];
+int nodecount;
+static Tree firstarg;
+int assignargs = 1;
+int prunetemps = -1;
+static Node *tail;
+
+static int depth = 0;
+static Node replace(Node);
+static Node prune(Node);
+static Node asgnnode(Symbol, Node);
+static struct dag *dagnode(int, Node, Node, Symbol);
+static Symbol equated(Symbol);
+static void fixup(Node);
+static void labelnode(int);
+static void list(Node);
+static void kill(Symbol);
+static Node node(int, Node, Node, Symbol);
+static void printdag1(Node, int, int);
+static void printnode(Node, int, int);
+static void reset(void);
+static Node tmpnode(Node);
+static void typestab(Symbol, void *);
+static Node undag(Node);
+static Node visit(Node, int);
+static void unlist(void);
+void walk(Tree tp, int tlab, int flab) {
+ listnodes(tp, tlab, flab);
+ if (forest) {
+ Node list = forest->link;
+ forest->link = NULL;
+ if (!IR->wants_dag)
+ list = undag(list);
+ code(Gen)->u.forest = list;
+ forest = NULL;
+ }
+ reset();
+ deallocate(STMT);
+}
+
+static Node node(int op, Node l, Node r, Symbol sym) {
+ int i;
+ struct dag *p;
+
+ i = (opindex(op)^((unsigned long)sym>>2))&(NELEMS(buckets)-1);
+ for (p = buckets[i]; p; p = p->hlink)
+ if (p->node.op == op && p->node.syms[0] == sym
+ && p->node.kids[0] == l && p->node.kids[1] == r)
+ return &p->node;
+ p = dagnode(op, l, r, sym);
+ p->hlink = buckets[i];
+ buckets[i] = p;
+ ++nodecount;
+ return &p->node;
+}
+static struct dag *dagnode(int op, Node l, Node r, Symbol sym) {
+ struct dag *p;
+
+ NEW0(p, FUNC);
+ p->node.op = op;
+ if ((p->node.kids[0] = l) != NULL)
+ ++l->count;
+ if ((p->node.kids[1] = r) != NULL)
+ ++r->count;
+ p->node.syms[0] = sym;
+ return p;
+}
+Node newnode(int op, Node l, Node r, Symbol sym) {
+ return &dagnode(op, l, r, sym)->node;
+}
+static void kill(Symbol p) {
+ int i;
+ struct dag **q;
+
+ for (i = 0; i < NELEMS(buckets); i++)
+ for (q = &buckets[i]; *q; )
+ if (generic((*q)->node.op) == INDIR &&
+ (!isaddrop((*q)->node.kids[0]->op)
+ || (*q)->node.kids[0]->syms[0] == p)) {
+ *q = (*q)->hlink;
+ --nodecount;
+ } else
+ q = &(*q)->hlink;
+}
+static void reset(void) {
+ if (nodecount > 0)
+ memset(buckets, 0, sizeof buckets);
+ nodecount = 0;
+}
+Node listnodes(Tree tp, int tlab, int flab) {
+ Node p = NULL, l, r;
+ int op;
+
+ assert(tlab || flab || (tlab == 0 && flab == 0));
+ if (tp == NULL)
+ return NULL;
+ if (tp->node)
+ return tp->node;
+ op = tp->op + sizeop(tp->type->size);
+ switch (generic(tp->op)) {
+ case AND: { if (depth++ == 0) reset();
+ if (flab) {
+ listnodes(tp->kids[0], 0, flab);
+ listnodes(tp->kids[1], 0, flab);
+ } else {
+ listnodes(tp->kids[0], 0, flab = genlabel(1));
+ listnodes(tp->kids[1], tlab, 0);
+ labelnode(flab);
+ }
+ depth--; } break;
+ case OR: { if (depth++ == 0)
+ reset();
+ if (tlab) {
+ listnodes(tp->kids[0], tlab, 0);
+ listnodes(tp->kids[1], tlab, 0);
+ } else {
+ tlab = genlabel(1);
+ listnodes(tp->kids[0], tlab, 0);
+ listnodes(tp->kids[1], 0, flab);
+ labelnode(tlab);
+ }
+ depth--;
+ } break;
+ case NOT: { return listnodes(tp->kids[0], flab, tlab); }
+ case COND: { Tree q = tp->kids[1];
+ assert(tlab == 0 && flab == 0);
+ if (tp->u.sym)
+ addlocal(tp->u.sym);
+ flab = genlabel(2);
+ listnodes(tp->kids[0], 0, flab);
+ assert(q && q->op == RIGHT);
+ reset();
+ listnodes(q->kids[0], 0, 0);
+ if (forest->op == LABEL+V) {
+ equatelab(forest->syms[0], findlabel(flab + 1));
+ unlist();
+ }
+ list(jump(flab + 1));
+ labelnode(flab);
+ listnodes(q->kids[1], 0, 0);
+ if (forest->op == LABEL+V) {
+ equatelab(forest->syms[0], findlabel(flab + 1));
+ unlist();
+ }
+ labelnode(flab + 1);
+
+ if (tp->u.sym)
+ p = listnodes(idtree(tp->u.sym), 0, 0); } break;
+ case CNST: { Type ty = unqual(tp->type);
+ assert(ty->u.sym);
+ if (tlab || flab) {
+ assert(ty == inttype);
+ if (tlab && tp->u.v.i != 0)
+ list(jump(tlab));
+ else if (flab && tp->u.v.i == 0)
+ list(jump(flab));
+ }
+ else if (ty->u.sym->addressed)
+ p = listnodes(cvtconst(tp), 0, 0);
+ else
+ p = node(op, NULL, NULL, constant(ty, tp->u.v)); } break;
+ case RIGHT: { if ( tp->kids[0] && tp->kids[1]
+ && generic(tp->kids[1]->op) == ASGN
+ && ((generic(tp->kids[0]->op) == INDIR
+ && tp->kids[0]->kids[0] == tp->kids[1]->kids[0])
+ || (tp->kids[0]->op == FIELD
+ && tp->kids[0] == tp->kids[1]->kids[0]))) {
+ assert(tlab == 0 && flab == 0);
+ if (generic(tp->kids[0]->op) == INDIR) {
+ p = listnodes(tp->kids[0], 0, 0);
+ list(p);
+ listnodes(tp->kids[1], 0, 0);
+ }
+ else {
+ assert(generic(tp->kids[0]->kids[0]->op) == INDIR);
+ list(listnodes(tp->kids[0]->kids[0], 0, 0));
+ p = listnodes(tp->kids[0], 0, 0);
+ listnodes(tp->kids[1], 0, 0);
+ }
+ } else if (tp->kids[1]) {
+ listnodes(tp->kids[0], 0, 0);
+ p = listnodes(tp->kids[1], tlab, flab);
+ } else
+ p = listnodes(tp->kids[0], tlab, flab); } break;
+ case JUMP: { assert(tlab == 0 && flab == 0);
+ assert(tp->u.sym == 0);
+ assert(tp->kids[0]);
+ l = listnodes(tp->kids[0], 0, 0);
+ list(newnode(JUMP+V, l, NULL, NULL));
+ reset(); } break;
+ case CALL: { Tree save = firstarg;
+ firstarg = NULL;
+ assert(tlab == 0 && flab == 0);
+ if (tp->op == CALL+B && !IR->wants_callb) {
+ Tree arg0 = tree(ARG+P, tp->kids[1]->type,
+ tp->kids[1], NULL);
+ if (IR->left_to_right)
+ firstarg = arg0;
+ l = listnodes(tp->kids[0], 0, 0);
+ if (!IR->left_to_right || firstarg) {
+ firstarg = NULL;
+ listnodes(arg0, 0, 0);
+ }
+ p = newnode(CALL+V, l, NULL, NULL);
+ } else {
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ p = newnode(tp->op == CALL+B ? tp->op : op, l, r, NULL);
+ }
+ NEW0(p->syms[0], FUNC);
+ assert(isptr(tp->kids[0]->type));
+ assert(isfunc(tp->kids[0]->type->type));
+ p->syms[0]->type = tp->kids[0]->type->type;
+ list(p);
+ reset();
+ cfunc->u.f.ncalls++;
+ firstarg = save;
+ } break;
+ case ARG: { assert(tlab == 0 && flab == 0);
+ if (IR->left_to_right)
+ listnodes(tp->kids[1], 0, 0);
+ if (firstarg) {
+ Tree arg = firstarg;
+ firstarg = NULL;
+ listnodes(arg, 0, 0);
+ }
+ l = listnodes(tp->kids[0], 0, 0);
+ list(newnode(tp->op == ARG+B ? tp->op : op, l, NULL, NULL));
+ forest->syms[0] = intconst(tp->type->size);
+ forest->syms[1] = intconst(tp->type->align);
+ if (!IR->left_to_right)
+ listnodes(tp->kids[1], 0, 0); } break;
+ case EQ: case NE: case GT: case GE: case LE:
+ case LT: { assert(tp->u.sym == 0);
+ assert(errcnt || tlab || flab);
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ assert(errcnt || opkind(l->op) == opkind(r->op));
+ assert(errcnt || optype(op) == optype(l->op));
+ if (tlab)
+ assert(flab == 0),
+ list(newnode(generic(tp->op) + opkind(l->op), l, r, findlabel(tlab)));
+ else if (flab) {
+ switch (generic(tp->op)) {
+ case EQ: op = NE; break;
+ case NE: op = EQ; break;
+ case GT: op = LE; break;
+ case LT: op = GE; break;
+ case GE: op = LT; break;
+ case LE: op = GT; break;
+ default: assert(0);
+ }
+ list(newnode(op + opkind(l->op), l, r, findlabel(flab)));
+ }
+ if (forest && forest->syms[0])
+ forest->syms[0]->ref++; } break;
+ case ASGN: { assert(tlab == 0 && flab == 0);
+ if (tp->kids[0]->op == FIELD) {
+ Tree x = tp->kids[0]->kids[0];
+ Field f = tp->kids[0]->u.field;
+ assert(generic(x->op) == INDIR);
+ reset();
+ l = listnodes(lvalue(x), 0, 0);
+ if (fieldsize(f) < 8*f->type->size) {
+ unsigned int fmask = fieldmask(f);
+ unsigned int mask = fmask<<fieldright(f);
+ Tree q = tp->kids[1];
+ if ((q->op == CNST+I && q->u.v.i == 0)
+ || (q->op == CNST+U && q->u.v.u == 0))
+ q = bittree(BAND, x, cnsttree(unsignedtype, (unsigned long)~mask));
+ else if ((q->op == CNST+I && (q->u.v.i&fmask) == fmask)
+ || (q->op == CNST+U && (q->u.v.u&fmask) == fmask))
+ q = bittree(BOR, x, cnsttree(unsignedtype, (unsigned long)mask));
+ else {
+ listnodes(q, 0, 0);
+ q = bittree(BOR,
+ bittree(BAND, rvalue(lvalue(x)),
+ cnsttree(unsignedtype, (unsigned long)~mask)),
+ bittree(BAND, shtree(LSH, cast(q, unsignedtype),
+ cnsttree(unsignedtype, (unsigned long)fieldright(f))),
+ cnsttree(unsignedtype, (unsigned long)mask)));
+ }
+ r = listnodes(q, 0, 0);
+ op = ASGN + ttob(q->type);
+ } else {
+ r = listnodes(tp->kids[1], 0, 0);
+ op = ASGN + ttob(tp->kids[1]->type);
+ }
+ } else {
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ }
+ list(newnode(tp->op == ASGN+B ? tp->op : op, l, r, NULL));
+ forest->syms[0] = intconst(tp->kids[1]->type->size);
+ forest->syms[1] = intconst(tp->kids[1]->type->align);
+ if (isaddrop(tp->kids[0]->op)
+ && !tp->kids[0]->u.sym->computed)
+ kill(tp->kids[0]->u.sym);
+ else
+ reset();
+ p = listnodes(tp->kids[1], 0, 0); } break;
+ case BOR: case BAND: case BXOR:
+ case ADD: case SUB: case RSH:
+ case LSH: { assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ p = node(op, l, r, NULL); } break;
+ case DIV: case MUL:
+ case MOD: { assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ r = listnodes(tp->kids[1], 0, 0);
+ p = node(op, l, r, NULL);
+ if (IR->mulops_calls && isint(tp->type)) {
+ list(p);
+ cfunc->u.f.ncalls++;
+ } } break;
+ case RET: { assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ list(newnode(op, l, NULL, NULL)); } break;
+ case CVF: case CVI: case CVP:
+ case CVU: { assert(tlab == 0 && flab == 0);
+ assert(optype(tp->kids[0]->op) != optype(tp->op) || tp->kids[0]->type->size != tp->type->size);
+ l = listnodes(tp->kids[0], 0, 0);
+ p = node(op, l, NULL, intconst(tp->kids[0]->type->size));
+ } break;
+ case BCOM:
+ case NEG: { assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ p = node(op, l, NULL, NULL); } break;
+ case INDIR: { Type ty = tp->kids[0]->type;
+ assert(tlab == 0 && flab == 0);
+ l = listnodes(tp->kids[0], 0, 0);
+ if (isptr(ty))
+ ty = unqual(ty)->type;
+ if (isvolatile(ty)
+ || (isstruct(ty) && unqual(ty)->u.sym->u.s.vfields))
+ p = newnode(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL);
+ else
+ p = node(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL); } break;
+ case FIELD: { Tree q = tp->kids[0];
+ if (tp->type == inttype) {
+ long n = fieldleft(tp->u.field);
+ q = shtree(RSH,
+ shtree(LSH, q, cnsttree(inttype, n)),
+ cnsttree(inttype, n + fieldright(tp->u.field)));
+ } else if (fieldsize(tp->u.field) < 8*tp->u.field->type->size)
+ q = bittree(BAND,
+ shtree(RSH, q, cnsttree(inttype, (long)fieldright(tp->u.field))),
+ cnsttree(unsignedtype, (unsigned long)fieldmask(tp->u.field)));
+ assert(tlab == 0 && flab == 0);
+ p = listnodes(q, 0, 0); } break;
+ case ADDRG:
+ case ADDRF: { assert(tlab == 0 && flab == 0);
+ p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym);
+ } break;
+ case ADDRL: { assert(tlab == 0 && flab == 0);
+ if (tp->u.sym->temporary)
+ addlocal(tp->u.sym);
+ p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym); } break;
+ default:assert(0);
+ }
+ tp->node = p;
+ return p;
+}
+static void list(Node p) {
+ if (p && p->link == NULL) {
+ if (forest) {
+ p->link = forest->link;
+ forest->link = p;
+ } else
+ p->link = p;
+ forest = p;
+ }
+}
+static void labelnode(int lab) {
+ assert(lab);
+ if (forest && forest->op == LABEL+V)
+ equatelab(findlabel(lab), forest->syms[0]);
+ else
+ list(newnode(LABEL+V, NULL, NULL, findlabel(lab)));
+ reset();
+}
+static void unlist(void) {
+ Node p;
+
+ assert(forest);
+ assert(forest != forest->link);
+ p = forest->link;
+ while (p->link != forest)
+ p = p->link;
+ p->link = forest->link;
+ forest = p;
+}
+Tree cvtconst(Tree p) {
+ Symbol q = constant(p->type, p->u.v);
+ Tree e;
+
+ if (q->u.c.loc == NULL)
+ q->u.c.loc = genident(STATIC, p->type, GLOBAL);
+ if (isarray(p->type)) {
+ e = simplify(ADDRG, atop(p->type), NULL, NULL);
+ e->u.sym = q->u.c.loc;
+ } else
+ e = idtree(q->u.c.loc);
+ return e;
+}
+void gencode(Symbol caller[], Symbol callee[]) {
+ Code cp;
+ Coordinate save;
+
+ if (prunetemps == -1)
+ prunetemps = !IR->wants_dag;
+ save = src;
+ if (assignargs) {
+ int i;
+ Symbol p, q;
+ cp = codehead.next->next;
+ codelist = codehead.next;
+ for (i = 0; (p = callee[i]) != NULL
+ && (q = caller[i]) != NULL; i++)
+ if (p->sclass != q->sclass || p->type != q->type)
+ walk(asgn(p, idtree(q)), 0, 0);
+ codelist->next = cp;
+ cp->prev = codelist;
+ }
+ if (glevel && IR->stabsym) {
+ int i;
+ Symbol p, q;
+ for (i = 0; (p = callee[i]) != NULL
+ && (q = caller[i]) != NULL; i++) {
+ (*IR->stabsym)(p);
+ if (p->sclass != q->sclass || p->type != q->type)
+ (*IR->stabsym)(q);
+ }
+ swtoseg(CODE);
+ }
+ cp = codehead.next;
+ for ( ; errcnt <= 0 && cp; cp = cp->next)
+ switch (cp->kind) {
+ case Address: (*IR->address)(cp->u.addr.sym, cp->u.addr.base,
+ cp->u.addr.offset); break;
+ case Blockbeg: {
+ Symbol *p = cp->u.block.locals;
+ (*IR->blockbeg)(&cp->u.block.x);
+ for ( ; *p; p++)
+ if ((*p)->ref != 0.0)
+ (*IR->local)(*p);
+ else if (glevel) (*IR->local)(*p);
+ }
+ break;
+ case Blockend: (*IR->blockend)(&cp->u.begin->u.block.x); break;
+ case Defpoint: src = cp->u.point.src; break;
+ case Gen: case Jump:
+ case Label: if (prunetemps)
+ cp->u.forest = prune(cp->u.forest);
+ fixup(cp->u.forest);
+ cp->u.forest = (*IR->gen)(cp->u.forest); break;
+ case Local: (*IR->local)(cp->u.var); break;
+ case Switch: break;
+ default: assert(0);
+ }
+ src = save;
+}
+static void fixup(Node p) {
+ for ( ; p; p = p->link)
+ switch (generic(p->op)) {
+ case JUMP:
+ if (specific(p->kids[0]->op) == ADDRG+P)
+ p->kids[0]->syms[0] =
+ equated(p->kids[0]->syms[0]);
+ break;
+ case LABEL: assert(p->syms[0] == equated(p->syms[0])); break;
+ case EQ: case GE: case GT: case LE: case LT: case NE:
+ assert(p->syms[0]);
+ p->syms[0] = equated(p->syms[0]);
+ }
+}
+static Symbol equated(Symbol p) {
+ { Symbol q; for (q = p->u.l.equatedto; q; q = q->u.l.equatedto) assert(p != q); }
+ while (p->u.l.equatedto)
+ p = p->u.l.equatedto;
+ return p;
+}
+void emitcode(void) {
+ Code cp;
+ Coordinate save;
+
+ save = src;
+ cp = codehead.next;
+ for ( ; errcnt <= 0 && cp; cp = cp->next)
+ switch (cp->kind) {
+ case Address: break;
+ case Blockbeg: if (glevel && IR->stabblock) {
+ (*IR->stabblock)('{', cp->u.block.level - LOCAL, cp->u.block.locals);
+ swtoseg(CODE);
+ }
+ break;
+ case Blockend: if (glevel && IR->stabblock) {
+ Code bp = cp->u.begin;
+ foreach(bp->u.block.identifiers, bp->u.block.level, typestab, NULL);
+ foreach(bp->u.block.types, bp->u.block.level, typestab, NULL);
+ (*IR->stabblock)('}', bp->u.block.level - LOCAL, bp->u.block.locals);
+ swtoseg(CODE);
+ }
+ break;
+ case Defpoint: src = cp->u.point.src;
+ if (glevel > 0 && IR->stabline) {
+ (*IR->stabline)(&cp->u.point.src); swtoseg(CODE); } break;
+ case Gen: case Jump:
+ case Label: if (cp->u.forest)
+ (*IR->emit)(cp->u.forest); break;
+ case Local: if (glevel && IR->stabsym) {
+ (*IR->stabsym)(cp->u.var);
+ swtoseg(CODE);
+ } break;
+ case Switch: { int i;
+ defglobal(cp->u.swtch.table, LIT);
+ (*IR->defaddress)(equated(cp->u.swtch.labels[0]));
+ for (i = 1; i < cp->u.swtch.size; i++) {
+ long k = cp->u.swtch.values[i-1];
+ while (++k < cp->u.swtch.values[i])
+ assert(k < LONG_MAX),
+ (*IR->defaddress)(equated(cp->u.swtch.deflab));
+ (*IR->defaddress)(equated(cp->u.swtch.labels[i]));
+ }
+ swtoseg(CODE);
+ } break;
+ default: assert(0);
+ }
+ src = save;
+}
+
+static Node undag(Node forest) {
+ Node p;
+
+ tail = &forest;
+ for (p = forest; p; p = p->link)
+ if (generic(p->op) == INDIR) {
+ assert(p->count >= 1);
+ visit(p, 1);
+ if (p->syms[2]) {
+ assert(p->syms[2]->u.t.cse);
+ p->syms[2]->u.t.cse = NULL;
+ addlocal(p->syms[2]);
+ }
+ } else if (iscall(p->op) && p->count >= 1)
+ visit(p, 1);
+ else {
+ assert(p->count == 0),
+ visit(p, 1);
+ *tail = p;
+ tail = &p->link;
+ }
+ *tail = NULL;
+ return forest;
+}
+static Node replace(Node p) {
+ if (p && ( generic(p->op) == INDIR
+ && generic(p->kids[0]->op) == ADDRL
+ && p->kids[0]->syms[0]->temporary
+ && p->kids[0]->syms[0]->u.t.replace)) {
+ p = p->kids[0]->syms[0]->u.t.cse;
+ if (generic(p->op) == INDIR && isaddrop(p->kids[0]->op))
+ p = newnode(p->op, newnode(p->kids[0]->op, NULL, NULL,
+ p->kids[0]->syms[0]), NULL, NULL);
+ else if (generic(p->op) == ADDRG)
+ p = newnode(p->op, NULL, NULL, p->syms[0]);
+ else
+ assert(0);
+ p->count = 1;
+ } else if (p) {
+ p->kids[0] = replace(p->kids[0]);
+ p->kids[1] = replace(p->kids[1]);
+ }
+ return p;
+}
+static Node prune(Node forest) {
+ Node p, *tail = &forest;
+ int count = 0;
+
+ for (p = forest; p; p = p->link) {
+ if (count > 0) {
+ p->kids[0] = replace(p->kids[0]);
+ p->kids[1] = replace(p->kids[1]);
+ }
+ if (( generic(p->op) == ASGN
+ && generic(p->kids[0]->op) == ADDRL
+ && p->kids[0]->syms[0]->temporary
+ && p->kids[0]->syms[0]->u.t.cse == p->kids[1])) {
+ Symbol tmp = p->kids[0]->syms[0];
+ if (!tmp->defined)
+ (*IR->local)(tmp);
+ tmp->defined = 1;
+ if (( generic(p->kids[1]->op) == INDIR
+ && isaddrop(p->kids[1]->kids[0]->op)
+ && p->kids[1]->kids[0]->syms[0]->sclass == REGISTER)
+ || (( generic(p->kids[1]->op) == INDIR
+ && isaddrop(p->kids[1]->kids[0]->op)) && tmp->sclass == AUTO)
+ || (generic(p->kids[1]->op) == ADDRG && tmp->sclass == AUTO)) {
+ tmp->u.t.replace = 1;
+ count++;
+ continue; /* and omit the assignment */
+ }
+ }
+ /* keep the assignment and other roots */
+ *tail = p;
+ tail = &(*tail)->link;
+ }
+ assert(*tail == NULL);
+ return forest;
+}
+static Node visit(Node p, int listed) {
+ if (p) {
+ if (p->syms[2])
+ p = tmpnode(p);
+ else if ((p->count <= 1 && !iscall(p->op))
+ || (p->count == 0 && iscall(p->op))) {
+ p->kids[0] = visit(p->kids[0], 0);
+ p->kids[1] = visit(p->kids[1], 0);
+ }
+
+ else if (specific(p->op) == ADDRL+P || specific(p->op) == ADDRF+P) {
+ assert(!listed);
+ p = newnode(p->op, NULL, NULL, p->syms[0]);
+ p->count = 1;
+ }
+ else if (p->op == INDIR+B) {
+ p = newnode(p->op, p->kids[0], NULL, NULL);
+ p->count = 1;
+ p->kids[0] = visit(p->kids[0], 0);
+ p->kids[1] = visit(p->kids[1], 0);
+ }
+ else {
+ p->kids[0] = visit(p->kids[0], 0);
+ p->kids[1] = visit(p->kids[1], 0);
+ p->syms[2] = temporary(REGISTER, btot(p->op, opsize(p->op)));
+ assert(!p->syms[2]->defined);
+ p->syms[2]->ref = 1;
+ p->syms[2]->u.t.cse = p;
+
+ *tail = asgnnode(p->syms[2], p);
+ tail = &(*tail)->link;
+ if (!listed)
+ p = tmpnode(p);
+ };
+ }
+ return p;
+}
+static Node tmpnode(Node p) {
+ Symbol tmp = p->syms[2];
+
+ assert(tmp);
+ if (--p->count == 0)
+ p->syms[2] = NULL;
+ p = newnode(INDIR + ttob(tmp->type),
+ newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), NULL, NULL);
+ p->count = 1;
+ return p;
+}
+static Node asgnnode(Symbol tmp, Node p) {
+ p = newnode(ASGN + ttob(tmp->type),
+ newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), p, NULL);
+ p->syms[0] = intconst(tmp->type->size);
+ p->syms[1] = intconst(tmp->type->align);
+ return p;
+}
+/* printdag - print dag p on fd, or the node list if p == 0 */
+void printdag(Node p, int fd) {
+ FILE *f = fd == 1 ? stdout : stderr;
+
+ printed(0);
+ if (p == 0) {
+ if ((p = forest) != NULL)
+ do {
+ p = p->link;
+ printdag1(p, fd, 0);
+ } while (p != forest);
+ } else if (*printed(nodeid((Tree)p)))
+ fprint(f, "node'%d printed above\n", nodeid((Tree)p));
+ else
+ printdag1(p, fd, 0);
+}
+
+/* printdag1 - recursively print dag p */
+static void printdag1(Node p, int fd, int lev) {
+ int id, i;
+
+ if (p == 0 || *printed(id = nodeid((Tree)p)))
+ return;
+ *printed(id) = 1;
+ for (i = 0; i < NELEMS(p->kids); i++)
+ printdag1(p->kids[i], fd, lev + 1);
+ printnode(p, fd, lev);
+}
+
+/* printnode - print fields of dag p */
+static void printnode(Node p, int fd, int lev) {
+ if (p) {
+ FILE *f = fd == 1 ? stdout : stderr;
+ int i, id = nodeid((Tree)p);
+ fprint(f, "%c%d%s", lev == 0 ? '\'' : '#', id,
+ &" "[id < 10 ? 0 : id < 100 ? 1 : 2]);
+ fprint(f, "%s count=%d", opname(p->op), p->count);
+ for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++)
+ fprint(f, " #%d", nodeid((Tree)p->kids[i]));
+ if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type)
+ fprint(f, " {%t}", p->syms[0]->type);
+ else
+ for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++)
+ if (p->syms[i]->name)
+ fprint(f, " %s", p->syms[i]->name);
+ else
+ fprint(f, " %p", p->syms[i]);
+ fprint(f, "\n");
+ }
+}
+
+/* typestab - emit stab entries for p */
+static void typestab(Symbol p, void *cl) {
+ if (!isfunc(p->type) && (p->sclass == EXTERN || p->sclass == STATIC) && IR->stabsym)
+ (*IR->stabsym)(p);
+ else if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype)
+ (*IR->stabtype)(p);
+}
+
diff --git a/code/tools/lcc/src/dagcheck.md b/code/tools/lcc/src/dagcheck.md
new file mode 100644
index 0000000..292dbee
--- /dev/null
+++ b/code/tools/lcc/src/dagcheck.md
@@ -0,0 +1,210 @@
+%{
+#include "c.h"
+typedef Node NODEPTR_TYPE;
+#define OP_LABEL(p) (specific((p)->op))
+#define LEFT_CHILD(p) ((p)->kids[0])
+#define RIGHT_CHILD(p) ((p)->kids[1])
+#define STATE_LABEL(p) ((p)->x.state)
+#define PANIC error
+%}
+%term CNSTF=17 CNSTI=21 CNSTP=23 CNSTU=22
+%term ARGB=41 ARGF=33 ARGI=37 ARGP=39 ARGU=38
+%term ASGNB=57 ASGNF=49 ASGNI=53 ASGNP=55 ASGNU=54
+%term INDIRB=73 INDIRF=65 INDIRI=69 INDIRP=71 INDIRU=70
+%term CVFF=113 CVFI=117
+%term CVIF=129 CVII=133 CVIU=134
+%term CVPP=151 CVPU=150
+%term CVUI=181 CVUP=183 CVUU=182
+%term NEGF=193 NEGI=197
+%term CALLB=217 CALLF=209 CALLI=213 CALLP=215 CALLU=214 CALLV=216
+%term RETF=241 RETI=245 RETP=247 RETU=246 RETV=248
+%term ADDRGP=263
+%term ADDRFP=279
+%term ADDRLP=295
+%term ADDF=305 ADDI=309 ADDP=311 ADDU=310
+%term SUBF=321 SUBI=325 SUBP=327 SUBU=326
+%term LSHI=341 LSHU=342
+%term MODI=357 MODU=358
+%term RSHI=373 RSHU=374
+%term BANDI=389 BANDU=390
+%term BCOMI=405 BCOMU=406
+%term BORI=421 BORU=422
+%term BXORI=437 BXORU=438
+%term DIVF=449 DIVI=453 DIVU=454
+%term MULF=465 MULI=469 MULU=470
+%term EQF=481 EQI=485 EQU=486
+%term GEF=497 GEI=501 GEU=502
+%term GTF=513 GTI=517 GTU=518
+%term LEF=529 LEI=533 LEU=534
+%term LTF=545 LTI=549 LTU=550
+%term NEF=561 NEI=565 NEU=566
+%term JUMPV=584
+%term LABELV=600
+%%
+stmt: INDIRB(P) ""
+stmt: INDIRF(P) ""
+stmt: INDIRI(P) ""
+stmt: INDIRU(P) ""
+stmt: INDIRP(P) ""
+stmt: CALLF(P) ""
+stmt: CALLI(P) ""
+stmt: CALLU(P) ""
+stmt: CALLP(P) ""
+stmt: V ""
+bogus: I "" 1
+bogus: U "" 1
+bogus: P "" 1
+bogus: F "" 1
+bogus: B "" 1
+bogus: V "" 1
+I: bogus "" 1
+U: bogus "" 1
+P: bogus "" 1
+F: bogus "" 1
+B: bogus "" 1
+V: bogus "" 1
+F: CNSTF ""
+I: CNSTI ""
+P: CNSTP ""
+U: CNSTU ""
+V: ARGB(B) ""
+V: ARGF(F) ""
+V: ARGI(I) ""
+V: ARGU(U) ""
+V: ARGP(P) ""
+V: ASGNB(P,B) ""
+V: ASGNF(P,F) ""
+V: ASGNI(P,I) ""
+V: ASGNU(P,U) ""
+V: ASGNP(P,P) ""
+B: INDIRB(P) ""
+F: INDIRF(P) ""
+I: INDIRI(P) ""
+U: INDIRU(P) ""
+P: INDIRP(P) ""
+I: CVII(I) ""
+I: CVUI(U) ""
+I: CVFI(F) ""
+U: CVIU(I) ""
+U: CVUU(U) ""
+U: CVPU(P) ""
+F: CVIF(I) ""
+F: CVFF(F) ""
+P: CVUP(U) ""
+P: CVPP(P) ""
+F: NEGF(F) ""
+I: NEGI(I) ""
+V: CALLB(P,P) ""
+F: CALLF(P) ""
+I: CALLI(P) ""
+U: CALLU(P) ""
+P: CALLP(P) ""
+V: CALLV(P) ""
+V: RETF(F) ""
+V: RETI(I) ""
+V: RETU(U) ""
+V: RETP(P) ""
+V: RETV ""
+P: ADDRGP ""
+P: ADDRFP ""
+P: ADDRLP ""
+F: ADDF(F,F) ""
+I: ADDI(I,I) ""
+P: ADDP(P,I) ""
+P: ADDP(I,P) ""
+P: ADDP(U,P) ""
+P: ADDP(P,U) ""
+U: ADDU(U,U) ""
+F: SUBF(F,F) ""
+I: SUBI(I,I) ""
+P: SUBP(P,I) ""
+P: SUBP(P,U) ""
+U: SUBU(U,U) ""
+I: LSHI(I,I) ""
+U: LSHU(U,I) ""
+I: MODI(I,I) ""
+U: MODU(U,U) ""
+I: RSHI(I,I) ""
+U: RSHU(U,I) ""
+U: BANDU(U,U) ""
+I: BANDI(I,I) ""
+U: BCOMU(U) ""
+I: BCOMI(I) ""
+I: BORI(I,I) ""
+U: BORU(U,U) ""
+U: BXORU(U,U) ""
+I: BXORI(I,I) ""
+F: DIVF(F,F) ""
+I: DIVI(I,I) ""
+U: DIVU(U,U) ""
+F: MULF(F,F) ""
+I: MULI(I,I) ""
+U: MULU(U,U) ""
+V: EQF(F,F) ""
+V: EQI(I,I) ""
+V: EQU(U,U) ""
+V: GEF(F,F) ""
+V: GEI(I,I) ""
+V: GEU(U,U) ""
+V: GTF(F,F) ""
+V: GTI(I,I) ""
+V: GTU(U,U) ""
+V: LEF(F,F) ""
+V: LEI(I,I) ""
+V: LEU(U,U) ""
+V: LTF(F,F) ""
+V: LTI(I,I) ""
+V: LTU(U,U) ""
+V: NEF(F,F) ""
+V: NEI(I,I) ""
+V: NEU(U,U) ""
+V: JUMPV(P) ""
+V: LABELV ""
+%%
+
+static void reduce(NODEPTR_TYPE p, int goalnt) {
+ int i, sz = opsize(p->op), rulenumber = _rule(p->x.state, goalnt);
+ short *nts = _nts[rulenumber];
+ NODEPTR_TYPE kids[10];
+
+ assert(rulenumber);
+ _kids(p, rulenumber, kids);
+ for (i = 0; nts[i]; i++)
+ reduce(kids[i], nts[i]);
+ switch (optype(p->op)) {
+#define xx(ty) if (sz == ty->size) return
+ case I:
+ case U:
+ xx(chartype);
+ xx(shorttype);
+ xx(inttype);
+ xx(longtype);
+ xx(longlong);
+ break;
+ case F:
+ xx(floattype);
+ xx(doubletype);
+ xx(longdouble);
+ break;
+ case P:
+ xx(voidptype);
+ xx(funcptype);
+ break;
+ case V:
+ case B: if (sz == 0) return;
+#undef xx
+ }
+ printdag(p, 2);
+ assert(0);
+}
+
+void check(Node p) {
+ struct _state { short cost[1]; };
+
+ _label(p);
+ if (((struct _state *)p->x.state)->cost[1] > 0) {
+ printdag(p, 2);
+ assert(0);
+ }
+ reduce(p, 1);
+}
diff --git a/code/tools/lcc/src/decl.c b/code/tools/lcc/src/decl.c
new file mode 100644
index 0000000..132241e
--- /dev/null
+++ b/code/tools/lcc/src/decl.c
@@ -0,0 +1,1162 @@
+#include "c.h"
+
+
+#define add(x,n) (x > inttype->u.sym->u.limits.max.i-(n) ? (overflow=1,x) : x+(n))
+#define chkoverflow(x,n) ((void)add(x,n))
+#define bits2bytes(n) (((n) + 7)/8)
+static int regcount;
+
+static List autos, registers;
+Symbol cfunc; /* current function */
+Symbol retv; /* return value location for structs */
+
+static void checkref(Symbol, void *);
+static Symbol dclglobal(int, char *, Type, Coordinate *);
+static Symbol dcllocal(int, char *, Type, Coordinate *);
+static Symbol dclparam(int, char *, Type, Coordinate *);
+static Type dclr(Type, char **, Symbol **, int);
+static Type dclr1(char **, Symbol **, int);
+static void decl(Symbol (*)(int, char *, Type, Coordinate *));
+extern void doconst(Symbol, void *);
+static void doglobal(Symbol, void *);
+static void doextern(Symbol, void *);
+static void exitparams(Symbol []);
+static void fields(Type);
+static void funcdefn(int, char *, Type, Symbol [], Coordinate);
+static void initglobal(Symbol, int);
+static void oldparam(Symbol, void *);
+static Symbol *parameters(Type);
+static Type specifier(int *);
+static Type structdcl(int);
+static Type tnode(int, Type);
+void program(void) {
+ int n;
+
+ level = GLOBAL;
+ for (n = 0; t != EOI; n++)
+ if (kind[t] == CHAR || kind[t] == STATIC
+ || t == ID || t == '*' || t == '(') {
+ decl(dclglobal);
+ deallocate(STMT);
+ if (!(glevel >= 3 || xref))
+ deallocate(FUNC);
+ } else if (t == ';') {
+ warning("empty declaration\n");
+ t = gettok();
+ } else {
+ error("unrecognized declaration\n");
+ t = gettok();
+ }
+ if (n == 0)
+ warning("empty input file\n");
+}
+static Type specifier(int *sclass) {
+ int cls, cons, sign, size, type, vol;
+ Type ty = NULL;
+
+ cls = vol = cons = sign = size = type = 0;
+ if (sclass == NULL)
+ cls = AUTO;
+ for (;;) {
+ int *p, tt = t;
+ switch (t) {
+ case AUTO:
+ case REGISTER: if (level <= GLOBAL && cls == 0)
+ error("invalid use of `%k'\n", t);
+ p = &cls; t = gettok(); break;
+ case STATIC: case EXTERN:
+ case TYPEDEF: p = &cls; t = gettok(); break;
+ case CONST: p = &cons; t = gettok(); break;
+ case VOLATILE: p = &vol; t = gettok(); break;
+ case SIGNED:
+ case UNSIGNED: p = &sign; t = gettok(); break;
+ case LONG: if (size == LONG) {
+ size = 0;
+ tt = LONG+LONG;
+ }
+ p = &size; t = gettok(); break;
+ case SHORT: p = &size; t = gettok(); break;
+ case VOID: case CHAR: case INT: case FLOAT:
+ case DOUBLE: p = &type; ty = tsym->type;
+ t = gettok(); break;
+ case ENUM: p = &type; ty = enumdcl(); break;
+ case STRUCT:
+ case UNION: p = &type; ty = structdcl(t); break;
+ case ID:
+ if (istypename(t, tsym) && type == 0
+ && sign == 0 && size == 0) {
+ use(tsym, src);
+ ty = tsym->type;
+ if (isqual(ty)
+ && ty->size != ty->type->size) {
+ ty = unqual(ty);
+ if (isconst(tsym->type))
+ ty = qual(CONST, ty);
+ if (isvolatile(tsym->type))
+ ty = qual(VOLATILE, ty);
+ tsym->type = ty;
+ }
+ p = &type;
+ t = gettok();
+ } else
+ p = NULL;
+ break;
+ default: p = NULL;
+ }
+ if (p == NULL)
+ break;
+ if (*p)
+ error("invalid use of `%k'\n", tt);
+ *p = tt;
+ }
+ if (sclass)
+ *sclass = cls;
+ if (type == 0) {
+ type = INT;
+ ty = inttype;
+ }
+ if ((size == SHORT && type != INT)
+ || (size == LONG+LONG && type != INT)
+ || (size == LONG && type != INT && type != DOUBLE)
+ || (sign && type != INT && type != CHAR))
+ error("invalid type specification\n");
+ if (type == CHAR && sign)
+ ty = sign == UNSIGNED ? unsignedchar : signedchar;
+ else if (size == SHORT)
+ ty = sign == UNSIGNED ? unsignedshort : shorttype;
+ else if (size == LONG && type == DOUBLE)
+ ty = longdouble;
+ else if (size == LONG+LONG) {
+ ty = sign == UNSIGNED ? unsignedlonglong : longlong;
+ if (Aflag >= 1)
+ warning("`%t' is a non-ANSI type\n", ty);
+ } else if (size == LONG)
+ ty = sign == UNSIGNED ? unsignedlong : longtype;
+ else if (sign == UNSIGNED && type == INT)
+ ty = unsignedtype;
+ if (cons == CONST)
+ ty = qual(CONST, ty);
+ if (vol == VOLATILE)
+ ty = qual(VOLATILE, ty);
+ return ty;
+}
+static void decl(Symbol (*dcl)(int, char *, Type, Coordinate *)) {
+ int sclass;
+ Type ty, ty1;
+ static char stop[] = { CHAR, STATIC, ID, 0 };
+
+ ty = specifier(&sclass);
+ if (t == ID || t == '*' || t == '(' || t == '[') {
+ char *id;
+ Coordinate pos;
+ id = NULL;
+ pos = src;
+ if (level == GLOBAL) {
+ Symbol *params = NULL;
+ ty1 = dclr(ty, &id, ¶ms, 0);
+ if (params && id && isfunc(ty1)
+ && (t == '{' || istypename(t, tsym)
+ || (kind[t] == STATIC && t != TYPEDEF))) {
+ if (sclass == TYPEDEF) {
+ error("invalid use of `typedef'\n");
+ sclass = EXTERN;
+ }
+ if (ty1->u.f.oldstyle)
+ exitscope();
+ funcdefn(sclass, id, ty1, params, pos);
+ return;
+ } else if (params)
+ exitparams(params);
+ } else
+ ty1 = dclr(ty, &id, NULL, 0);
+ for (;;) {
+ if (Aflag >= 1 && !hasproto(ty1))
+ warning("missing prototype\n");
+ if (id == NULL)
+ error("missing identifier\n");
+ else if (sclass == TYPEDEF)
+ {
+ Symbol p = lookup(id, identifiers);
+ if (p && p->scope == level)
+ error("redeclaration of `%s'\n", id);
+ p = install(id, &identifiers, level,
+ level < LOCAL ? PERM : FUNC);
+ p->type = ty1;
+ p->sclass = TYPEDEF;
+ p->src = pos;
+ }
+ else
+ (void)(*dcl)(sclass, id, ty1, &pos);
+ if (t != ',')
+ break;
+ t = gettok();
+ id = NULL;
+ pos = src;
+ ty1 = dclr(ty, &id, NULL, 0);
+ }
+ } else if (ty == NULL
+ || !(isenum(ty) ||
+ (isstruct(ty) && (*unqual(ty)->u.sym->name < '1' || *unqual(ty)->u.sym->name > '9'))))
+ error("empty declaration\n");
+ test(';', stop);
+}
+static Symbol dclglobal(int sclass, char *id, Type ty, Coordinate *pos) {
+ Symbol p;
+
+ if (sclass == 0)
+ sclass = AUTO;
+ else if (sclass != EXTERN && sclass != STATIC) {
+ error("invalid storage class `%k' for `%t %s'\n",
+ sclass, ty, id);
+ sclass = AUTO;
+ }
+ p = lookup(id, identifiers);
+ if (p && p->scope == GLOBAL) {
+ if (p->sclass != TYPEDEF && eqtype(ty, p->type, 1))
+ ty = compose(ty, p->type);
+ else
+ error("redeclaration of `%s' previously declared at %w\n", p->name, &p->src);
+
+ if (!isfunc(ty) && p->defined && t == '=')
+ error("redefinition of `%s' previously defined at %w\n", p->name, &p->src);
+
+ if ((p->sclass == EXTERN && sclass == STATIC)
+ || (p->sclass == STATIC && sclass == AUTO)
+ || (p->sclass == AUTO && sclass == STATIC))
+ warning("inconsistent linkage for `%s' previously declared at %w\n", p->name, &p->src);
+
+ }
+ if (p == NULL || p->scope != GLOBAL) {
+ Symbol q = lookup(id, externals);
+ if (q) {
+ if (sclass == STATIC || !eqtype(ty, q->type, 1))
+ warning("declaration of `%s' does not match previous declaration at %w\n", id, &q->src);
+
+ p = relocate(id, externals, globals);
+ p->sclass = sclass;
+ } else {
+ p = install(id, &globals, GLOBAL, PERM);
+ p->sclass = sclass;
+ (*IR->defsymbol)(p);
+ }
+ if (p->sclass != STATIC) {
+ static int nglobals;
+ nglobals++;
+ if (Aflag >= 2 && nglobals == 512)
+ warning("more than 511 external identifiers\n");
+ }
+ } else if (p->sclass == EXTERN)
+ p->sclass = sclass;
+ p->type = ty;
+ p->src = *pos;
+ if (t == '=' && isfunc(p->type)) {
+ error("illegal initialization for `%s'\n", p->name);
+ t = gettok();
+ initializer(p->type, 0);
+ } else if (t == '=') {
+ initglobal(p, 0);
+ if (glevel > 0 && IR->stabsym) {
+ (*IR->stabsym)(p); swtoseg(p->u.seg); }
+ } else if (p->sclass == STATIC && !isfunc(p->type)
+ && p->type->size == 0)
+ error("undefined size for `%t %s'\n", p->type, p->name);
+ return p;
+}
+static void initglobal(Symbol p, int flag) {
+ Type ty;
+
+ if (t == '=' || flag) {
+ if (p->sclass == STATIC) {
+ for (ty = p->type; isarray(ty); ty = ty->type)
+ ;
+ defglobal(p, isconst(ty) ? LIT : DATA);
+ } else
+ defglobal(p, DATA);
+ if (t == '=')
+ t = gettok();
+ ty = initializer(p->type, 0);
+ if (isarray(p->type) && p->type->size == 0)
+ p->type = ty;
+ if (p->sclass == EXTERN)
+ p->sclass = AUTO;
+ }
+}
+void defglobal(Symbol p, int seg) {
+ p->u.seg = seg;
+ swtoseg(p->u.seg);
+ if (p->sclass != STATIC)
+ (*IR->export)(p);
+ (*IR->global)(p);
+ p->defined = 1;
+}
+
+static Type dclr(Type basety, char **id, Symbol **params, int abstract) {
+ Type ty = dclr1(id, params, abstract);
+
+ for ( ; ty; ty = ty->type)
+ switch (ty->op) {
+ case POINTER:
+ basety = ptr(basety);
+ break;
+ case FUNCTION:
+ basety = func(basety, ty->u.f.proto,
+ ty->u.f.oldstyle);
+ break;
+ case ARRAY:
+ basety = array(basety, ty->size, 0);
+ break;
+ case CONST: case VOLATILE:
+ basety = qual(ty->op, basety);
+ break;
+ default: assert(0);
+ }
+ if (Aflag >= 2 && basety->size > 32767)
+ warning("more than 32767 bytes in `%t'\n", basety);
+ return basety;
+}
+static Type tnode(int op, Type type) {
+ Type ty;
+
+ NEW0(ty, STMT);
+ ty->op = op;
+ ty->type = type;
+ return ty;
+}
+static Type dclr1(char **id, Symbol **params, int abstract) {
+ Type ty = NULL;
+
+ switch (t) {
+ case ID: if (id)
+ *id = token;
+ else
+ error("extraneous identifier `%s'\n", token);
+ t = gettok(); break;
+ case '*': t = gettok(); if (t == CONST || t == VOLATILE) {
+ Type ty1;
+ ty1 = ty = tnode(t, NULL);
+ while ((t = gettok()) == CONST || t == VOLATILE)
+ ty1 = tnode(t, ty1);
+ ty->type = dclr1(id, params, abstract);
+ ty = ty1;
+ } else
+ ty = dclr1(id, params, abstract);
+ ty = tnode(POINTER, ty); break;
+ case '(': t = gettok(); if (abstract
+ && (t == REGISTER || istypename(t, tsym) || t == ')')) {
+ Symbol *args;
+ ty = tnode(FUNCTION, ty);
+ enterscope();
+ if (level > PARAM)
+ enterscope();
+ args = parameters(ty);
+ exitparams(args);
+ } else {
+ ty = dclr1(id, params, abstract);
+ expect(')');
+ if (abstract && ty == NULL
+ && (id == NULL || *id == NULL))
+ return tnode(FUNCTION, NULL);
+ } break;
+ case '[': break;
+ default: return ty;
+ }
+ while (t == '(' || t == '[')
+ switch (t) {
+ case '(': t = gettok(); { Symbol *args;
+ ty = tnode(FUNCTION, ty);
+ enterscope();
+ if (level > PARAM)
+ enterscope();
+ args = parameters(ty);
+ if (params && *params == NULL)
+ *params = args;
+ else
+ exitparams(args);
+ }
+ break;
+ case '[': t = gettok(); { int n = 0;
+ if (kind[t] == ID) {
+ n = intexpr(']', 1);
+ if (n <= 0) {
+ error("`%d' is an illegal array size\n", n);
+ n = 1;
+ }
+ } else
+ expect(']');
+ ty = tnode(ARRAY, ty);
+ ty->size = n; } break;
+ default: assert(0);
+ }
+ return ty;
+}
+static Symbol *parameters(Type fty) {
+ List list = NULL;
+ Symbol *params;
+
+ if (kind[t] == STATIC || istypename(t, tsym)) {
+ int n = 0;
+ Type ty1 = NULL;
+ for (;;) {
+ Type ty;
+ int sclass = 0;
+ char *id = NULL;
+ if (ty1 && t == ELLIPSIS) {
+ static struct symbol sentinel;
+ if (sentinel.type == NULL) {
+ sentinel.type = voidtype;
+ sentinel.defined = 1;
+ }
+ if (ty1 == voidtype)
+ error("illegal formal parameter types\n");
+ list = append(&sentinel, list);
+ t = gettok();
+ break;
+ }
+ if (!istypename(t, tsym) && t != REGISTER)
+ error("missing parameter type\n");
+ n++;
+ ty = dclr(specifier(&sclass), &id, NULL, 1);
+ if ( (ty == voidtype && (ty1 || id))
+ || ty1 == voidtype)
+ error("illegal formal parameter types\n");
+ if (id == NULL)
+ id = stringd(n);
+ if (ty != voidtype)
+ list = append(dclparam(sclass, id, ty, &src), list);
+ if (Aflag >= 1 && !hasproto(ty))
+ warning("missing prototype\n");
+ if (ty1 == NULL)
+ ty1 = ty;
+ if (t != ',')
+ break;
+ t = gettok();
+ }
+ fty->u.f.proto = newarray(length(list) + 1,
+ sizeof (Type *), PERM);
+ params = ltov(&list, FUNC);
+ for (n = 0; params[n]; n++)
+ fty->u.f.proto[n] = params[n]->type;
+ fty->u.f.proto[n] = NULL;
+ fty->u.f.oldstyle = 0;
+ } else {
+ if (t == ID)
+ for (;;) {
+ Symbol p;
+ if (t != ID) {
+ error("expecting an identifier\n");
+ break;
+ }
+ p = dclparam(0, token, inttype, &src);
+ p->defined = 0;
+ list = append(p, list);
+ t = gettok();
+ if (t != ',')
+ break;
+ t = gettok();
+ }
+ params = ltov(&list, FUNC);
+ fty->u.f.proto = NULL;
+ fty->u.f.oldstyle = 1;
+ }
+ if (t != ')') {
+ static char stop[] = { CHAR, STATIC, IF, ')', 0 };
+ expect(')');
+ skipto('{', stop);
+ }
+ if (t == ')')
+ t = gettok();
+ return params;
+}
+static void exitparams(Symbol params[]) {
+ assert(params);
+ if (params[0] && !params[0]->defined)
+ error("extraneous old-style parameter list\n");
+ if (level > PARAM)
+ exitscope();
+ exitscope();
+}
+
+static Symbol dclparam(int sclass, char *id, Type ty, Coordinate *pos) {
+ Symbol p;
+
+ if (isfunc(ty))
+ ty = ptr(ty);
+ else if (isarray(ty))
+ ty = atop(ty);
+ if (sclass == 0)
+ sclass = AUTO;
+ else if (sclass != REGISTER) {
+ error("invalid storage class `%k' for `%t%s\n",
+ sclass, ty, stringf(id ? " %s'" : "' parameter", id));
+ sclass = AUTO;
+ } else if (isvolatile(ty) || isstruct(ty)) {
+ warning("register declaration ignored for `%t%s\n",
+ ty, stringf(id ? " %s'" : "' parameter", id));
+ sclass = AUTO;
+ }
+
+ p = lookup(id, identifiers);
+ if (p && p->scope == level)
+ error("duplicate declaration for `%s' previously declared at %w\n", id, &p->src);
+
+ else
+ p = install(id, &identifiers, level, FUNC);
+ p->sclass = sclass;
+ p->src = *pos;
+ p->type = ty;
+ p->defined = 1;
+ if (t == '=') {
+ error("illegal initialization for parameter `%s'\n", id);
+ t = gettok();
+ (void)expr1(0);
+ }
+ return p;
+}
+static Type structdcl(int op) {
+ char *tag;
+ Type ty;
+ Symbol p;
+ Coordinate pos;
+
+ t = gettok();
+ pos = src;
+ if (t == ID) {
+ tag = token;
+ t = gettok();
+ } else
+ tag = "";
+ if (t == '{') {
+ static char stop[] = { IF, ',', 0 };
+ ty = newstruct(op, tag);
+ ty->u.sym->src = pos;
+ ty->u.sym->defined = 1;
+ t = gettok();
+ if (istypename(t, tsym))
+ fields(ty);
+ else
+ error("invalid %k field declarations\n", op);
+ test('}', stop);
+ }
+ else if (*tag && (p = lookup(tag, types)) != NULL
+ && p->type->op == op) {
+ ty = p->type;
+ if (t == ';' && p->scope < level)
+ ty = newstruct(op, tag);
+ }
+ else {
+ if (*tag == 0)
+ error("missing %k tag\n", op);
+ ty = newstruct(op, tag);
+ }
+ if (*tag && xref)
+ use(ty->u.sym, pos);
+ return ty;
+}
+static void fields(Type ty) {
+ { int n = 0;
+ while (istypename(t, tsym)) {
+ static char stop[] = { IF, CHAR, '}', 0 };
+ Type ty1 = specifier(NULL);
+ for (;;) {
+ Field p;
+ char *id = NULL;
+ Type fty = dclr(ty1, &id, NULL, 0);
+ p = newfield(id, ty, fty);
+ if (Aflag >= 1 && !hasproto(p->type))
+ warning("missing prototype\n");
+ if (t == ':') {
+ if (unqual(p->type) != inttype
+ && unqual(p->type) != unsignedtype) {
+ error("`%t' is an illegal bit-field type\n",
+ p->type);
+ p->type = inttype;
+ }
+ t = gettok();
+ p->bitsize = intexpr(0, 0);
+ if (p->bitsize > 8*inttype->size || p->bitsize < 0) {
+ error("`%d' is an illegal bit-field size\n",
+ p->bitsize);
+ p->bitsize = 8*inttype->size;
+ } else if (p->bitsize == 0 && id) {
+ warning("extraneous 0-width bit field `%t %s' ignored\n", p->type, id);
+
+ p->name = stringd(genlabel(1));
+ }
+ p->lsb = 1;
+ }
+ else {
+ if (id == NULL)
+ error("field name missing\n");
+ else if (isfunc(p->type))
+ error("`%t' is an illegal field type\n", p->type);
+ else if (p->type->size == 0)
+ error("undefined size for field `%t %s'\n",
+ p->type, id);
+ }
+ if (isconst(p->type))
+ ty->u.sym->u.s.cfields = 1;
+ if (isvolatile(p->type))
+ ty->u.sym->u.s.vfields = 1;
+ n++;
+ if (Aflag >= 2 && n == 128)
+ warning("more than 127 fields in `%t'\n", ty);
+ if (t != ',')
+ break;
+ t = gettok();
+ }
+ test(';', stop);
+ } }
+ { int bits = 0, off = 0, overflow = 0;
+ Field p, *q = &ty->u.sym->u.s.flist;
+ ty->align = IR->structmetric.align;
+ for (p = *q; p; p = p->link) {
+ int a = p->type->align ? p->type->align : 1;
+ if (p->lsb)
+ a = unsignedtype->align;
+ if (ty->op == UNION)
+ off = bits = 0;
+ else if (p->bitsize == 0 || bits == 0
+ || bits - 1 + p->bitsize > 8*unsignedtype->size) {
+ off = add(off, bits2bytes(bits-1));
+ bits = 0;
+ chkoverflow(off, a - 1);
+ off = roundup(off, a);
+ }
+ if (a > ty->align)
+ ty->align = a;
+ p->offset = off;
+
+ if (p->lsb) {
+ if (bits == 0)
+ bits = 1;
+ if (IR->little_endian)
+ p->lsb = bits;
+ else
+ p->lsb = 8*unsignedtype->size - bits + 1
+ - p->bitsize + 1;
+ bits += p->bitsize;
+ } else
+ off = add(off, p->type->size);
+ if (off + bits2bytes(bits-1) > ty->size)
+ ty->size = off + bits2bytes(bits-1);
+ if (p->name == NULL
+ || !('1' <= *p->name && *p->name <= '9')) {
+ *q = p;
+ q = &p->link;
+ }
+ }
+ *q = NULL;
+ chkoverflow(ty->size, ty->align - 1);
+ ty->size = roundup(ty->size, ty->align);
+ if (overflow) {
+ error("size of `%t' exceeds %d bytes\n", ty, inttype->u.sym->u.limits.max.i);
+ ty->size = inttype->u.sym->u.limits.max.i&(~(ty->align - 1));
+ } }
+}
+static void funcdefn(int sclass, char *id, Type ty, Symbol params[], Coordinate pt) {
+ int i, n;
+ Symbol *callee, *caller, p;
+ Type rty = freturn(ty);
+
+ if (isstruct(rty) && rty->size == 0)
+ error("illegal use of incomplete type `%t'\n", rty);
+ for (n = 0; params[n]; n++)
+ ;
+ if (n > 0 && params[n-1]->name == NULL)
+ params[--n] = NULL;
+ if (Aflag >= 2 && n > 31)
+ warning("more than 31 parameters in function `%s'\n", id);
+ if (ty->u.f.oldstyle) {
+ if (Aflag >= 1)
+ warning("old-style function definition for `%s'\n", id);
+ caller = params;
+ callee = newarray(n + 1, sizeof *callee, FUNC);
+ memcpy(callee, caller, (n+1)*sizeof *callee);
+ enterscope();
+ assert(level == PARAM);
+ while (kind[t] == STATIC || istypename(t, tsym))
+ decl(dclparam);
+ foreach(identifiers, PARAM, oldparam, callee);
+
+ for (i = 0; (p = callee[i]) != NULL; i++) {
+ if (!p->defined)
+ callee[i] = dclparam(0, p->name, inttype, &p->src);
+ *caller[i] = *p;
+ caller[i]->sclass = AUTO;
+ caller[i]->type = promote(p->type);
+ }
+ p = lookup(id, identifiers);
+ if (p && p->scope == GLOBAL && isfunc(p->type)
+ && p->type->u.f.proto) {
+ Type *proto = p->type->u.f.proto;
+ for (i = 0; caller[i] && proto[i]; i++) {
+ Type ty = unqual(proto[i]);
+ if (eqtype(isenum(ty) ? ty->type : ty,
+ unqual(caller[i]->type), 1) == 0)
+ break;
+ else if (isenum(ty) && !isenum(unqual(caller[i]->type)))
+ warning("compatibility of `%t' and `%t' is compiler dependent\n",
+ proto[i], caller[i]->type);
+ }
+ if (proto[i] || caller[i])
+ error("conflicting argument declarations for function `%s'\n", id);
+
+ }
+ else {
+ Type *proto = newarray(n + 1, sizeof *proto, PERM);
+ if (Aflag >= 1)
+ warning("missing prototype for `%s'\n", id);
+ for (i = 0; i < n; i++)
+ proto[i] = caller[i]->type;
+ proto[i] = NULL;
+ ty = func(rty, proto, 1);
+ }
+ } else {
+ callee = params;
+ caller = newarray(n + 1, sizeof *caller, FUNC);
+ for (i = 0; (p = callee[i]) != NULL && p->name; i++) {
+ NEW(caller[i], FUNC);
+ *caller[i] = *p;
+ if (isint(p->type))
+ caller[i]->type = promote(p->type);
+ caller[i]->sclass = AUTO;
+ if ('1' <= *p->name && *p->name <= '9')
+ error("missing name for parameter %d to function `%s'\n", i + 1, id);
+
+ }
+ caller[i] = NULL;
+ }
+ for (i = 0; (p = callee[i]) != NULL; i++)
+ if (p->type->size == 0) {
+ error("undefined size for parameter `%t %s'\n",
+ p->type, p->name);
+ caller[i]->type = p->type = inttype;
+ }
+ if (Aflag >= 2 && sclass != STATIC && strcmp(id, "main") == 0) {
+ if (ty->u.f.oldstyle)
+ warning("`%t %s()' is a non-ANSI definition\n", rty, id);
+ else if (!(rty == inttype
+ && ((n == 0 && callee[0] == NULL)
+ || (n == 2 && callee[0]->type == inttype
+ && isptr(callee[1]->type) && callee[1]->type->type == charptype
+ && !variadic(ty)))))
+ warning("`%s' is a non-ANSI definition\n", typestring(ty, id));
+ }
+ p = lookup(id, identifiers);
+ if (p && isfunc(p->type) && p->defined)
+ error("redefinition of `%s' previously defined at %w\n",
+ p->name, &p->src);
+ cfunc = dclglobal(sclass, id, ty, &pt);
+ cfunc->u.f.label = genlabel(1);
+ cfunc->u.f.callee = callee;
+ cfunc->u.f.pt = src;
+ cfunc->defined = 1;
+ if (xref)
+ use(cfunc, cfunc->src);
+ if (Pflag)
+ printproto(cfunc, cfunc->u.f.callee);
+ if (ncalled >= 0)
+ ncalled = findfunc(cfunc->name, pt.file);
+ labels = table(NULL, LABELS);
+ stmtlabs = table(NULL, LABELS);
+ refinc = 1.0;
+ regcount = 0;
+ codelist = &codehead;
+ codelist->next = NULL;
+ if (!IR->wants_callb && isstruct(rty))
+ retv = genident(AUTO, ptr(rty), PARAM);
+ compound(0, NULL, 0);
+
+ {
+ Code cp;
+ for (cp = codelist; cp->kind < Label; cp = cp->prev)
+ ;
+ if (cp->kind != Jump) {
+ if (rty != voidtype) {
+ warning("missing return value\n");
+ retcode(cnsttree(inttype, 0L));
+ } else
+ retcode(NULL);
+ }
+ }
+ definelab(cfunc->u.f.label);
+ if (events.exit)
+ apply(events.exit, cfunc, NULL);
+ walk(NULL, 0, 0);
+ exitscope();
+ assert(level == PARAM);
+ foreach(identifiers, level, checkref, NULL);
+ if (!IR->wants_callb && isstruct(rty)) {
+ Symbol *a;
+ a = newarray(n + 2, sizeof *a, FUNC);
+ a[0] = retv;
+ memcpy(&a[1], callee, (n+1)*sizeof *callee);
+ callee = a;
+ a = newarray(n + 2, sizeof *a, FUNC);
+ NEW(a[0], FUNC);
+ *a[0] = *retv;
+ memcpy(&a[1], caller, (n+1)*sizeof *callee);
+ caller = a;
+ }
+ if (!IR->wants_argb)
+ for (i = 0; caller[i]; i++)
+ if (isstruct(caller[i]->type)) {
+ caller[i]->type = ptr(caller[i]->type);
+ callee[i]->type = ptr(callee[i]->type);
+ caller[i]->structarg = callee[i]->structarg = 1;
+ }
+ if (glevel > 1) for (i = 0; callee[i]; i++) callee[i]->sclass = AUTO;
+ if (cfunc->sclass != STATIC)
+ (*IR->export)(cfunc);
+ if (glevel && IR->stabsym) {
+ swtoseg(CODE); (*IR->stabsym)(cfunc); }
+ swtoseg(CODE);
+ (*IR->function)(cfunc, caller, callee, cfunc->u.f.ncalls);
+ if (glevel && IR->stabfend)
+ (*IR->stabfend)(cfunc, lineno);
+ foreach(stmtlabs, LABELS, checklab, NULL);
+ exitscope();
+ expect('}');
+ labels = stmtlabs = NULL;
+ retv = NULL;
+ cfunc = NULL;
+}
+static void oldparam(Symbol p, void *cl) {
+ int i;
+ Symbol *callee = cl;
+
+ for (i = 0; callee[i]; i++)
+ if (p->name == callee[i]->name) {
+ callee[i] = p;
+ return;
+ }
+ error("declared parameter `%s' is missing\n", p->name);
+}
+void compound(int loop, struct swtch *swp, int lev) {
+ Code cp;
+ int nregs;
+
+ walk(NULL, 0, 0);
+ cp = code(Blockbeg);
+ enterscope();
+ assert(level >= LOCAL);
+ if (level == LOCAL && events.entry)
+ apply(events.entry, cfunc, NULL);
+ definept(NULL);
+ expect('{');
+ autos = registers = NULL;
+ if (level == LOCAL && IR->wants_callb
+ && isstruct(freturn(cfunc->type))) {
+ retv = genident(AUTO, ptr(freturn(cfunc->type)), level);
+ retv->defined = 1;
+ retv->ref = 1;
+ registers = append(retv, registers);
+ }
+ while (kind[t] == CHAR || kind[t] == STATIC
+ || (istypename(t, tsym) && getchr() != ':'))
+ decl(dcllocal);
+ {
+ int i;
+ Symbol *a = ltov(&autos, STMT);
+ nregs = length(registers);
+ for (i = 0; a[i]; i++)
+ registers = append(a[i], registers);
+ cp->u.block.locals = ltov(®isters, FUNC);
+ }
+ if (events.blockentry)
+ apply(events.blockentry, cp->u.block.locals, NULL);
+ while (kind[t] == IF || kind[t] == ID)
+ statement(loop, swp, lev);
+ walk(NULL, 0, 0);
+ foreach(identifiers, level, checkref, NULL);
+ {
+ int i = nregs, j;
+ Symbol p;
+ for ( ; (p = cp->u.block.locals[i]) != NULL; i++) {
+ for (j = i; j > nregs
+ && cp->u.block.locals[j-1]->ref < p->ref; j--)
+ cp->u.block.locals[j] = cp->u.block.locals[j-1];
+ cp->u.block.locals[j] = p;
+ }
+ }
+ if (events.blockexit)
+ apply(events.blockexit, cp->u.block.locals, NULL);
+ cp->u.block.level = level;
+ cp->u.block.identifiers = identifiers;
+ cp->u.block.types = types;
+ code(Blockend)->u.begin = cp;
+ if (reachable(Gen))
+ definept(NULL);
+ if (level > LOCAL) {
+ exitscope();
+ expect('}');
+ }
+}
+static void checkref(Symbol p, void *cl) {
+ if (p->scope >= PARAM
+ && (isvolatile(p->type) || isfunc(p->type)))
+ p->addressed = 1;
+ if (Aflag >= 2 && p->defined && p->ref == 0) {
+ if (p->sclass == STATIC)
+ warning("static `%t %s' is not referenced\n",
+ p->type, p->name);
+ else if (p->scope == PARAM)
+ warning("parameter `%t %s' is not referenced\n",
+ p->type, p->name);
+ else if (p->scope >= LOCAL && p->sclass != EXTERN)
+ warning("local `%t %s' is not referenced\n",
+ p->type, p->name);
+ }
+ if (p->sclass == AUTO
+ && ((p->scope == PARAM && regcount == 0)
+ || p->scope >= LOCAL)
+ && !p->addressed && isscalar(p->type) && p->ref >= 3.0)
+ p->sclass = REGISTER;
+ if (level == GLOBAL && p->sclass == STATIC && !p->defined
+ && isfunc(p->type) && p->ref)
+ error("undefined static `%t %s'\n", p->type, p->name);
+ assert(!(level == GLOBAL && p->sclass == STATIC && !p->defined && !isfunc(p->type)));
+}
+static Symbol dcllocal(int sclass, char *id, Type ty, Coordinate *pos) {
+ Symbol p, q;
+
+ if (sclass == 0)
+ sclass = isfunc(ty) ? EXTERN : AUTO;
+ else if (isfunc(ty) && sclass != EXTERN) {
+ error("invalid storage class `%k' for `%t %s'\n",
+ sclass, ty, id);
+ sclass = EXTERN;
+ } else if (sclass == REGISTER
+ && (isvolatile(ty) || isstruct(ty) || isarray(ty))) {
+ warning("register declaration ignored for `%t %s'\n",
+ ty, id);
+ sclass = AUTO;
+ }
+ q = lookup(id, identifiers);
+ if ((q && q->scope >= level)
+ || (q && q->scope == PARAM && level == LOCAL)) {
+ if (sclass == EXTERN && q->sclass == EXTERN
+ && eqtype(q->type, ty, 1))
+ ty = compose(ty, q->type);
+ else
+ error("redeclaration of `%s' previously declared at %w\n", q->name, &q->src);
+ }
+
+ assert(level >= LOCAL);
+ p = install(id, &identifiers, level, sclass == STATIC || sclass == EXTERN ? PERM : FUNC);
+ p->type = ty;
+ p->sclass = sclass;
+ p->src = *pos;
+ switch (sclass) {
+ case EXTERN: q = lookup(id, globals);
+ if (q == NULL || q->sclass == TYPEDEF || q->sclass == ENUM) {
+ q = lookup(id, externals);
+ if (q == NULL) {
+ q = install(p->name, &externals, GLOBAL, PERM);
+ q->type = p->type;
+ q->sclass = EXTERN;
+ q->src = src;
+ (*IR->defsymbol)(q);
+ }
+ }
+ if (!eqtype(p->type, q->type, 1))
+ warning("declaration of `%s' does not match previous declaration at %w\n", q->name, &q->src);
+
+ p->u.alias = q; break;
+ case STATIC: (*IR->defsymbol)(p);
+ initglobal(p, 0);
+ if (!p->defined) {
+ if (p->type->size > 0) {
+ defglobal(p, BSS);
+ (*IR->space)(p->type->size);
+ } else
+ error("undefined size for `%t %s'\n",
+ p->type, p->name);
+ }
+ p->defined = 1; break;
+ case REGISTER: registers = append(p, registers);
+ regcount++;
+ p->defined = 1;
+ break;
+ case AUTO: autos = append(p, autos);
+ p->defined = 1; break;
+ default: assert(0);
+ }
+ if (t == '=') {
+ Tree e;
+ if (sclass == EXTERN)
+ error("illegal initialization of `extern %s'\n", id);
+ t = gettok();
+ definept(NULL);
+ if (isscalar(p->type)
+ || (isstruct(p->type) && t != '{')) {
+ if (t == '{') {
+ t = gettok();
+ e = expr1(0);
+ expect('}');
+ } else
+ e = expr1(0);
+ } else {
+ Symbol t1;
+ Type ty = p->type, ty1 = ty;
+ while (isarray(ty1))
+ ty1 = ty1->type;
+ if (!isconst(ty) && (!isarray(ty) || !isconst(ty1)))
+ ty = qual(CONST, ty);
+ t1 = genident(STATIC, ty, GLOBAL);
+ initglobal(t1, 1);
+ if (isarray(p->type) && p->type->size == 0
+ && t1->type->size > 0)
+ p->type = array(p->type->type,
+ t1->type->size/t1->type->type->size, 0);
+ e = idtree(t1);
+ }
+ walk(root(asgn(p, e)), 0, 0);
+ p->ref = 1;
+ }
+ if (!isfunc(p->type) && p->defined && p->type->size <= 0)
+ error("undefined size for `%t %s'\n", p->type, id);
+ return p;
+}
+void finalize(void) {
+ foreach(externals, GLOBAL, doextern, NULL);
+ foreach(identifiers, GLOBAL, doglobal, NULL);
+ foreach(identifiers, GLOBAL, checkref, NULL);
+ foreach(constants, CONSTANTS, doconst, NULL);
+}
+static void doextern(Symbol p, void *cl) {
+ (*IR->import)(p);
+}
+static void doglobal(Symbol p, void *cl) {
+ if (!p->defined && (p->sclass == EXTERN
+ || (isfunc(p->type) && p->sclass == AUTO)))
+ (*IR->import)(p);
+ else if (!p->defined && !isfunc(p->type)
+ && (p->sclass == AUTO || p->sclass == STATIC)) {
+ if (isarray(p->type)
+ && p->type->size == 0 && p->type->type->size > 0)
+ p->type = array(p->type->type, 1, 0);
+ if (p->type->size > 0) {
+ defglobal(p, BSS);
+ (*IR->space)(p->type->size);
+ if (glevel > 0 && IR->stabsym)
+ (*IR->stabsym)(p);
+ } else
+ error("undefined size for `%t %s'\n",
+ p->type, p->name);
+ p->defined = 1;
+ }
+ if (Pflag
+ && !isfunc(p->type)
+ && !p->generated && p->sclass != EXTERN)
+ printdecl(p, p->type);
+}
+void doconst(Symbol p, void *cl) {
+ if (p->u.c.loc) {
+ assert(p->u.c.loc->u.seg == 0);
+ defglobal(p->u.c.loc, LIT);
+ if (isarray(p->type) && p->type->type == widechar) {
+ unsigned int *s = p->u.c.v.p;
+ int n = p->type->size/widechar->size;
+ while (n-- > 0) {
+ Value v;
+ v.u = *s++;
+ (*IR->defconst)(widechar->op, widechar->size, v);
+ }
+ } else if (isarray(p->type))
+ (*IR->defstring)(p->type->size, p->u.c.v.p);
+ else
+ (*IR->defconst)(p->type->op, p->type->size, p->u.c.v);
+ p->u.c.loc = NULL;
+ }
+}
+void checklab(Symbol p, void *cl) {
+ if (!p->defined)
+ error("undefined label `%s'\n", p->name);
+ p->defined = 1;
+}
+
+Type enumdcl(void) {
+ char *tag;
+ Type ty;
+ Symbol p = {0};
+ Coordinate pos;
+
+ t = gettok();
+ pos = src;
+ if (t == ID) {
+ tag = token;
+ t = gettok();
+ } else
+ tag = "";
+ if (t == '{') {
+ static char follow[] = { IF, 0 };
+ int n = 0;
+ long k = -1;
+ List idlist = 0;
+ ty = newstruct(ENUM, tag);
+ t = gettok();
+ if (t != ID)
+ error("expecting an enumerator identifier\n");
+ while (t == ID) {
+ char *id = token;
+ Coordinate s;
+ if (tsym && tsym->scope == level)
+ error("redeclaration of `%s' previously declared at %w\n",
+ token, &tsym->src);
+ s = src;
+ t = gettok();
+ if (t == '=') {
+ t = gettok();
+ k = intexpr(0, 0);
+ } else {
+ if (k == inttype->u.sym->u.limits.max.i)
+ error("overflow in value for enumeration constant `%s'\n", id);
+ k++;
+ }
+ p = install(id, &identifiers, level, level < LOCAL ? PERM : FUNC);
+ p->src = s;
+ p->type = ty;
+ p->sclass = ENUM;
+ p->u.value = k;
+ idlist = append(p, idlist);
+ n++;
+ if (Aflag >= 2 && n == 128)
+ warning("more than 127 enumeration constants in `%t'\n", ty);
+ if (t != ',')
+ break;
+ t = gettok();
+ if (Aflag >= 2 && t == '}')
+ warning("non-ANSI trailing comma in enumerator list\n");
+ }
+ test('}', follow);
+ ty->type = inttype;
+ ty->size = ty->type->size;
+ ty->align = ty->type->align;
+ ty->u.sym->u.idlist = ltov(&idlist, PERM);
+ ty->u.sym->defined = 1;
+ } else if ((p = lookup(tag, types)) != NULL && p->type->op == ENUM) {
+ ty = p->type;
+ if (t == ';')
+ error("empty declaration\n");
+ } else {
+ error("unknown enumeration `%s'\n", tag);
+ ty = newstruct(ENUM, tag);
+ ty->type = inttype;
+ }
+ if (*tag && xref)
+ use(p, pos);
+ return ty;
+}
+
+Type typename(void) {
+ Type ty = specifier(NULL);
+
+ if (t == '*' || t == '(' || t == '[') {
+ ty = dclr(ty, NULL, NULL, 1);
+ if (Aflag >= 1 && !hasproto(ty))
+ warning("missing prototype\n");
+ }
+ return ty;
+}
+
diff --git a/code/tools/lcc/src/enode.c b/code/tools/lcc/src/enode.c
new file mode 100644
index 0000000..760096d
--- /dev/null
+++ b/code/tools/lcc/src/enode.c
@@ -0,0 +1,545 @@
+#include "c.h"
+
+
+static Tree addtree(int, Tree, Tree);
+static Tree andtree(int, Tree, Tree);
+static Tree cmptree(int, Tree, Tree);
+static int compatible(Type, Type);
+static int isnullptr(Tree e);
+static Tree multree(int, Tree, Tree);
+static Tree subtree(int, Tree, Tree);
+#define isvoidptr(ty) \
+ (isptr(ty) && unqual(ty->type) == voidtype)
+
+Tree (*optree[])(int, Tree, Tree) = {
+#define xx(a,b,c,d,e,f,g) e,
+#define yy(a,b,c,d,e,f,g) e,
+#include "token.h"
+};
+Tree call(Tree f, Type fty, Coordinate src) {
+ int n = 0;
+ Tree args = NULL, r = NULL, e;
+ Type *proto, rty = unqual(freturn(fty));
+ Symbol t3 = NULL;
+
+ if (fty->u.f.oldstyle)
+ proto = NULL;
+ else
+ proto = fty->u.f.proto;
+ if (hascall(f))
+ r = f;
+ if (isstruct(rty))
+ {
+ t3 = temporary(AUTO, unqual(rty));
+ if (rty->size == 0)
+ error("illegal use of incomplete type `%t'\n", rty);
+ }
+ if (t != ')')
+ for (;;) {
+ Tree q = pointer(expr1(0));
+ if (proto && *proto && *proto != voidtype)
+ {
+ Type aty;
+ q = value(q);
+ aty = assign(*proto, q);
+ if (aty)
+ q = cast(q, aty);
+ else
+ error("type error in argument %d to %s; found `%t' expected `%t'\n", n + 1, funcname(f),
+
+ q->type, *proto);
+ if ((isint(q->type) || isenum(q->type))
+ && q->type->size != inttype->size)
+ q = cast(q, promote(q->type));
+ ++proto;
+ }
+ else
+ {
+ if (!fty->u.f.oldstyle && *proto == NULL)
+ error("too many arguments to %s\n", funcname(f));
+ q = value(q);
+ if (isarray(q->type) || q->type->size == 0)
+ error("type error in argument %d to %s; `%t' is illegal\n", n + 1, funcname(f), q->type);
+
+ else
+ q = cast(q, promote(q->type));
+ }
+ if (!IR->wants_argb && isstruct(q->type)) {
+ if (iscallb(q))
+ q = addrof(q);
+ else {
+ Symbol t1 = temporary(AUTO, unqual(q->type));
+ q = asgn(t1, q);
+ q = tree(RIGHT, ptr(t1->type),
+ root(q), lvalue(idtree(t1)));
+ }
+ }
+ if (q->type->size == 0)
+ q->type = inttype;
+ if (hascall(q))
+ r = r ? tree(RIGHT, voidtype, r, q) : q;
+ args = tree(mkop(ARG, q->type), q->type, q, args);
+ n++;
+ if (Aflag >= 2 && n == 32)
+ warning("more than 31 arguments in a call to %s\n",
+ funcname(f));
+ if (t != ',')
+ break;
+ t = gettok();
+ }
+ expect(')');
+ if (proto && *proto && *proto != voidtype)
+ error("insufficient number of arguments to %s\n",
+ funcname(f));
+ if (r)
+ args = tree(RIGHT, voidtype, r, args);
+ e = calltree(f, rty, args, t3);
+ if (events.calls)
+ apply(events.calls, &src, &e);
+ return e;
+}
+Tree calltree(Tree f, Type ty, Tree args, Symbol t3) {
+ Tree p;
+
+ if (args)
+ f = tree(RIGHT, f->type, args, f);
+ if (isstruct(ty))
+ assert(t3),
+ p = tree(RIGHT, ty,
+ tree(CALL+B, ty, f, addrof(idtree(t3))),
+ idtree(t3));
+ else {
+ Type rty = ty;
+ if (isenum(ty))
+ rty = unqual(ty)->type;
+ if (!isfloat(rty))
+ rty = promote(rty);
+ p = tree(mkop(CALL, rty), rty, f, NULL);
+ if (isptr(ty) || p->type->size > ty->size)
+ p = cast(p, ty);
+ }
+ return p;
+}
+Tree vcall(Symbol func, Type ty, ...) {
+ va_list ap;
+ Tree args = NULL, e, f = pointer(idtree(func)), r = NULL;
+
+ assert(isfunc(func->type));
+ if (ty == NULL)
+ ty = freturn(func->type);
+ va_start(ap, ty);
+ while ((e = va_arg(ap, Tree)) != NULL) {
+ if (hascall(e))
+ r = r == NULL ? e : tree(RIGHT, voidtype, r, e);
+ args = tree(mkop(ARG, e->type), e->type, e, args);
+ }
+ va_end(ap);
+ if (r != NULL)
+ args = tree(RIGHT, voidtype, r, args);
+ return calltree(f, ty, args, NULL);
+}
+int iscallb(Tree e) {
+ return e->op == RIGHT && e->kids[0] && e->kids[1]
+ && e->kids[0]->op == CALL+B
+ && e->kids[1]->op == INDIR+B
+ && isaddrop(e->kids[1]->kids[0]->op)
+ && e->kids[1]->kids[0]->u.sym->temporary;
+}
+
+static Tree addtree(int op, Tree l, Tree r) {
+ Type ty = inttype;
+
+ if (isarith(l->type) && isarith(r->type)) {
+ ty = binary(l->type, r->type);
+ l = cast(l, ty);
+ r = cast(r, ty);
+ } else if (isptr(l->type) && isint(r->type))
+ return addtree(ADD, r, l);
+ else if ( isptr(r->type) && isint(l->type)
+ && !isfunc(r->type->type))
+ {
+ long n;
+ ty = unqual(r->type);
+ n = unqual(ty->type)->size;
+ if (n == 0)
+ error("unknown size for type `%t'\n", ty->type);
+ l = cast(l, promote(l->type));
+ if (n > 1)
+ l = multree(MUL, cnsttree(signedptr, n), l);
+ if (YYcheck && !isaddrop(r->op)) /* omit */
+ return nullcall(ty, YYcheck, r, l); /* omit */
+ return simplify(ADD, ty, l, r);
+ }
+
+ else
+ typeerror(op, l, r);
+ return simplify(op, ty, l, r);
+}
+
+Tree cnsttree(Type ty, ...) {
+ Tree p = tree(mkop(CNST,ty), ty, NULL, NULL);
+ va_list ap;
+
+ va_start(ap, ty);
+ switch (ty->op) {
+ case INT: p->u.v.i = va_arg(ap, long); break;
+ case UNSIGNED:p->u.v.u = va_arg(ap, unsigned long)&ones(8*ty->size); break;
+ case FLOAT: p->u.v.d = va_arg(ap, double); break;
+ case POINTER: p->u.v.p = va_arg(ap, void *); break;
+ default: assert(0);
+ }
+ va_end(ap);
+ return p;
+}
+
+Tree consttree(unsigned n, Type ty) {
+ if (isarray(ty))
+ ty = atop(ty);
+ else assert(isint(ty));
+ return cnsttree(ty, (unsigned long)n);
+}
+static Tree cmptree(int op, Tree l, Tree r) {
+ Type ty;
+
+ if (isarith(l->type) && isarith(r->type)) {
+ ty = binary(l->type, r->type);
+ l = cast(l, ty);
+ r = cast(r, ty);
+ } else if (compatible(l->type, r->type)) {
+ ty = unsignedptr;
+ l = cast(l, ty);
+ r = cast(r, ty);
+ } else {
+ ty = unsignedtype;
+ typeerror(op, l, r);
+ }
+ return simplify(mkop(op,ty), inttype, l, r);
+}
+static int compatible(Type ty1, Type ty2) {
+ return isptr(ty1) && !isfunc(ty1->type)
+ && isptr(ty2) && !isfunc(ty2->type)
+ && eqtype(unqual(ty1->type), unqual(ty2->type), 0);
+}
+static int isnullptr(Tree e) {
+ Type ty = unqual(e->type);
+
+ return generic(e->op) == CNST
+ && ((ty->op == INT && e->u.v.i == 0)
+ || (ty->op == UNSIGNED && e->u.v.u == 0)
+ || (isvoidptr(ty) && e->u.v.p == NULL));
+}
+Tree eqtree(int op, Tree l, Tree r) {
+ Type xty = l->type, yty = r->type;
+
+ if ((isptr(xty) && isnullptr(r))
+ || (isptr(xty) && !isfunc(xty->type) && isvoidptr(yty))
+ || (isptr(xty) && isptr(yty)
+ && eqtype(unqual(xty->type), unqual(yty->type), 1))) {
+ Type ty = unsignedptr;
+ l = cast(l, ty);
+ r = cast(r, ty);
+ return simplify(mkop(op,ty), inttype, l, r);
+ }
+ if ((isptr(yty) && isnullptr(l))
+ || (isptr(yty) && !isfunc(yty->type) && isvoidptr(xty)))
+ return eqtree(op, r, l);
+ return cmptree(op, l, r);
+}
+
+Type assign(Type xty, Tree e) {
+ Type yty = unqual(e->type);
+
+ xty = unqual(xty);
+ if (isenum(xty))
+ xty = xty->type;
+ if (xty->size == 0 || yty->size == 0)
+ return NULL;
+ if ( (isarith(xty) && isarith(yty))
+ || (isstruct(xty) && xty == yty))
+ return xty;
+ if (isptr(xty) && isnullptr(e))
+ return xty;
+ if (((isvoidptr(xty) && isptr(yty))
+ || (isptr(xty) && isvoidptr(yty)))
+ && ( (isconst(xty->type) || !isconst(yty->type))
+ && (isvolatile(xty->type) || !isvolatile(yty->type))))
+ return xty;
+
+ if ((isptr(xty) && isptr(yty)
+ && eqtype(unqual(xty->type), unqual(yty->type), 1))
+ && ( (isconst(xty->type) || !isconst(yty->type))
+ && (isvolatile(xty->type) || !isvolatile(yty->type))))
+ return xty;
+ if (isptr(xty) && isptr(yty)
+ && ( (isconst(xty->type) || !isconst(yty->type))
+ && (isvolatile(xty->type) || !isvolatile(yty->type)))) {
+ Type lty = unqual(xty->type), rty = unqual(yty->type);
+ if ((isenum(lty) && rty == inttype)
+ || (isenum(rty) && lty == inttype)) {
+ if (Aflag >= 1)
+ warning("assignment between `%t' and `%t' is compiler-dependent\n",
+ xty, yty);
+ return xty;
+ }
+ }
+ return NULL;
+}
+Tree asgntree(int op, Tree l, Tree r) {
+ Type aty, ty;
+
+ r = pointer(r);
+ ty = assign(l->type, r);
+ if (ty)
+ r = cast(r, ty);
+ else {
+ typeerror(ASGN, l, r);
+ if (r->type == voidtype)
+ r = retype(r, inttype);
+ ty = r->type;
+ }
+ if (l->op != FIELD)
+ l = lvalue(l);
+ aty = l->type;
+ if (isptr(aty))
+ aty = unqual(aty)->type;
+ if ( isconst(aty)
+ || (isstruct(aty) && unqual(aty)->u.sym->u.s.cfields)) {
+ if (isaddrop(l->op)
+ && !l->u.sym->computed && !l->u.sym->generated)
+ error("assignment to const identifier `%s'\n",
+ l->u.sym->name);
+ else
+ error("assignment to const location\n");
+ }
+ if (l->op == FIELD) {
+ long n = 8*l->u.field->type->size - fieldsize(l->u.field);
+ if (n > 0 && isunsigned(l->u.field->type))
+ r = bittree(BAND, r,
+ cnsttree(r->type, (unsigned long)fieldmask(l->u.field)));
+ else if (n > 0) {
+ if (r->op == CNST+I) {
+ n = r->u.v.i;
+ if (n&(1<<(fieldsize(l->u.field)-1)))
+ n |= ~0UL<<fieldsize(l->u.field);
+ r = cnsttree(r->type, n);
+ } else
+ r = shtree(RSH,
+ shtree(LSH, r, cnsttree(inttype, n)),
+ cnsttree(inttype, n));
+ }
+ }
+ if (isstruct(ty) && isaddrop(l->op) && iscallb(r))
+ return tree(RIGHT, ty,
+ tree(CALL+B, ty, r->kids[0]->kids[0], l),
+ idtree(l->u.sym));
+ return tree(mkop(op,ty), ty, l, r);
+}
+Tree condtree(Tree e, Tree l, Tree r) {
+ Symbol t1;
+ Type ty, xty = l->type, yty = r->type;
+ Tree p;
+
+ if (isarith(xty) && isarith(yty))
+ ty = binary(xty, yty);
+ else if (eqtype(xty, yty, 1))
+ ty = unqual(xty);
+ else if (isptr(xty) && isnullptr(r))
+ ty = xty;
+ else if (isnullptr(l) && isptr(yty))
+ ty = yty;
+ else if ((isptr(xty) && !isfunc(xty->type) && isvoidptr(yty))
+ || (isptr(yty) && !isfunc(yty->type) && isvoidptr(xty)))
+ ty = voidptype;
+ else if ((isptr(xty) && isptr(yty)
+ && eqtype(unqual(xty->type), unqual(yty->type), 1)))
+ ty = xty;
+ else {
+ typeerror(COND, l, r);
+ return consttree(0, inttype);
+ }
+ if (isptr(ty)) {
+ ty = unqual(unqual(ty)->type);
+ if ((isptr(xty) && isconst(unqual(xty)->type))
+ || (isptr(yty) && isconst(unqual(yty)->type)))
+ ty = qual(CONST, ty);
+ if ((isptr(xty) && isvolatile(unqual(xty)->type))
+ || (isptr(yty) && isvolatile(unqual(yty)->type)))
+ ty = qual(VOLATILE, ty);
+ ty = ptr(ty);
+ }
+ switch (e->op) {
+ case CNST+I: return cast(e->u.v.i != 0 ? l : r, ty);
+ case CNST+U: return cast(e->u.v.u != 0 ? l : r, ty);
+ case CNST+P: return cast(e->u.v.p != 0 ? l : r, ty);
+ case CNST+F: return cast(e->u.v.d != 0.0 ? l : r, ty);
+ }
+ if (ty != voidtype && ty->size > 0) {
+ t1 = genident(REGISTER, unqual(ty), level);
+ /* t1 = temporary(REGISTER, unqual(ty)); */
+ l = asgn(t1, l);
+ r = asgn(t1, r);
+ } else
+ t1 = NULL;
+ p = tree(COND, ty, cond(e),
+ tree(RIGHT, ty, root(l), root(r)));
+ p->u.sym = t1;
+ return p;
+}
+/* addrof - address of p */
+Tree addrof(Tree p) {
+ Tree q = p;
+
+ for (;;)
+ switch (generic(q->op)) {
+ case RIGHT:
+ assert(q->kids[0] || q->kids[1]);
+ q = q->kids[1] ? q->kids[1] : q->kids[0];
+ continue;
+ case ASGN:
+ q = q->kids[1];
+ continue;
+ case COND: {
+ Symbol t1 = q->u.sym;
+ q->u.sym = 0;
+ q = idtree(t1);
+ /* fall thru */
+ }
+ case INDIR:
+ if (p == q)
+ return q->kids[0];
+ q = q->kids[0];
+ return tree(RIGHT, q->type, root(p), q);
+ default:
+ error("addressable object required\n");
+ return value(p);
+ }
+}
+
+/* andtree - construct tree for l [&& ||] r */
+static Tree andtree(int op, Tree l, Tree r) {
+ if (!isscalar(l->type) || !isscalar(r->type))
+ typeerror(op, l, r);
+ return simplify(op, inttype, cond(l), cond(r));
+}
+
+/* asgn - generate tree for assignment of expr e to symbol p sans qualifiers */
+Tree asgn(Symbol p, Tree e) {
+ if (isarray(p->type))
+ e = tree(ASGN+B, p->type, idtree(p),
+ tree(INDIR+B, e->type, e, NULL));
+ else {
+ Type ty = p->type;
+ p->type = unqual(p->type);
+ if (isstruct(p->type) && p->type->u.sym->u.s.cfields) {
+ p->type->u.sym->u.s.cfields = 0;
+ e = asgntree(ASGN, idtree(p), e);
+ p->type->u.sym->u.s.cfields = 1;
+ } else
+ e = asgntree(ASGN, idtree(p), e);
+ p->type = ty;
+ }
+ return e;
+}
+
+/* bittree - construct tree for l [& | ^ %] r */
+Tree bittree(int op, Tree l, Tree r) {
+ Type ty = inttype;
+
+ if (isint(l->type) && isint(r->type)) {
+ ty = binary(l->type, r->type);
+ l = cast(l, ty);
+ r = cast(r, ty);
+ } else
+ typeerror(op, l, r);
+ return simplify(op, ty, l, r);
+}
+
+/* multree - construct tree for l [* /] r */
+static Tree multree(int op, Tree l, Tree r) {
+ Type ty = inttype;
+
+ if (isarith(l->type) && isarith(r->type)) {
+ ty = binary(l->type, r->type);
+ l = cast(l, ty);
+ r = cast(r, ty);
+ } else
+ typeerror(op, l, r);
+ return simplify(op, ty, l, r);
+}
+
+/* shtree - construct tree for l [>> <<] r */
+Tree shtree(int op, Tree l, Tree r) {
+ Type ty = inttype;
+
+ if (isint(l->type) && isint(r->type)) {
+ ty = promote(l->type);
+ l = cast(l, ty);
+ r = cast(r, inttype);
+ } else
+ typeerror(op, l, r);
+ return simplify(op, ty, l, r);
+}
+
+/* subtree - construct tree for l - r */
+static Tree subtree(int op, Tree l, Tree r) {
+ long n;
+ Type ty = inttype;
+
+ if (isarith(l->type) && isarith(r->type)) {
+ ty = binary(l->type, r->type);
+ l = cast(l, ty);
+ r = cast(r, ty);
+ } else if (isptr(l->type) && !isfunc(l->type->type) && isint(r->type)) {
+ ty = unqual(l->type);
+ n = unqual(ty->type)->size;
+ if (n == 0)
+ error("unknown size for type `%t'\n", ty->type);
+ r = cast(r, promote(r->type));
+ if (n > 1)
+ r = multree(MUL, cnsttree(signedptr, n), r);
+ if (isunsigned(r->type))
+ r = cast(r, unsignedptr);
+ else
+ r = cast(r, signedptr);
+ return simplify(SUB+P, ty, l, r);
+ } else if (compatible(l->type, r->type)) {
+ ty = unqual(l->type);
+ n = unqual(ty->type)->size;
+ if (n == 0)
+ error("unknown size for type `%t'\n", ty->type);
+ l = simplify(SUB+U, unsignedptr,
+ cast(l, unsignedptr), cast(r, unsignedptr));
+ return simplify(DIV+I, longtype,
+ cast(l, longtype), cnsttree(longtype, n));
+ } else
+ typeerror(op, l, r);
+ return simplify(op, ty, l, r);
+}
+
+/* typeerror - issue "operands of op have illegal types `l' and `r'" */
+void typeerror(int op, Tree l, Tree r) {
+ int i;
+ static struct { int op; char *name; } ops[] = {
+ {ASGN, "="}, {INDIR, "*"}, {NEG, "-"},
+ {ADD, "+"}, {SUB, "-"}, {LSH, "<<"},
+ {MOD, "%"}, {RSH, ">>"}, {BAND, "&"},
+ {BCOM, "~"}, {BOR, "|"}, {BXOR, "^"},
+ {DIV, "/"}, {MUL, "*"}, {EQ, "=="},
+ {GE, ">="}, {GT, ">"}, {LE, "<="},
+ {LT, "<"}, {NE, "!="}, {AND, "&&"},
+ {NOT, "!"}, {OR, "||"}, {COND, "?:"},
+ {0, 0}
+ };
+
+ op = generic(op);
+ for (i = 0; ops[i].op; i++)
+ if (op == ops[i].op)
+ break;
+ assert(ops[i].name);
+ if (r)
+ error("operands of %s have illegal types `%t' and `%t'\n",
+ ops[i].name, l->type, r->type);
+ else
+ error("operand of unary %s has illegal type `%t'\n", ops[i].name,
+ l->type);
+}
diff --git a/code/tools/lcc/src/error.c b/code/tools/lcc/src/error.c
new file mode 100644
index 0000000..2187c10
--- /dev/null
+++ b/code/tools/lcc/src/error.c
@@ -0,0 +1,137 @@
+#include "c.h"
+
+
+static void printtoken(void);
+int errcnt = 0;
+int errlimit = 20;
+char kind[] = {
+#define xx(a,b,c,d,e,f,g) f,
+#define yy(a,b,c,d,e,f,g) f,
+#include "token.h"
+};
+int wflag; /* != 0 to suppress warning messages */
+
+void test(int tok, char set[]) {
+ if (t == tok)
+ t = gettok();
+ else {
+ expect(tok);
+ skipto(tok, set);
+ if (t == tok)
+ t = gettok();
+ }
+}
+void expect(int tok) {
+ if (t == tok)
+ t = gettok();
+ else {
+ error("syntax error; found");
+ printtoken();
+ fprint(stderr, " expecting `%k'\n", tok);
+ }
+}
+void error(const char *fmt, ...) {
+ va_list ap;
+
+ if (errcnt++ >= errlimit) {
+ errcnt = -1;
+ error("too many errors\n");
+ exit(1);
+ }
+ va_start(ap, fmt);
+ if (firstfile != file && firstfile && *firstfile)
+ fprint(stderr, "%s: ", firstfile);
+ fprint(stderr, "%w: ", &src);
+ vfprint(stderr, NULL, fmt, ap);
+ va_end(ap);
+}
+
+void skipto(int tok, char set[]) {
+ int n;
+ char *s;
+
+ assert(set);
+ for (n = 0; t != EOI && t != tok; t = gettok()) {
+ for (s = set; *s && kind[t] != *s; s++)
+ ;
+ if (kind[t] == *s)
+ break;
+ if (n++ == 0)
+ error("skipping");
+ if (n <= 8)
+ printtoken();
+ else if (n == 9)
+ fprint(stderr, " ...");
+ }
+ if (n > 8) {
+ fprint(stderr, " up to");
+ printtoken();
+ }
+ if (n > 0)
+ fprint(stderr, "\n");
+}
+/* fatal - issue fatal error message and exit */
+int fatal(const char *name, const char *fmt, int n) {
+ print("\n");
+ errcnt = -1;
+ error("compiler error in %s--", name);
+ fprint(stderr, fmt, n);
+ exit(EXIT_FAILURE);
+ return 0;
+}
+
+/* printtoken - print current token preceeded by a space */
+static void printtoken(void) {
+ switch (t) {
+ case ID: fprint(stderr, " `%s'", token); break;
+ case ICON:
+ fprint(stderr, " `%s'", vtoa(tsym->type, tsym->u.c.v));
+ break;
+ case SCON: {
+ int i, n;
+ if (ischar(tsym->type->type)) {
+ char *s = tsym->u.c.v.p;
+ n = tsym->type->size;
+ fprint(stderr, " \"");
+ for (i = 0; i < 20 && i < n && *s; s++, i++)
+ if (*s < ' ' || *s >= 0177)
+ fprint(stderr, "\\%o", *s);
+ else
+ fprint(stderr, "%c", *s);
+ } else { /* wchar_t string */
+ unsigned int *s = tsym->u.c.v.p;
+ assert(tsym->type->type->size == widechar->size);
+ n = tsym->type->size/widechar->size;
+ fprint(stderr, " L\"");
+ for (i = 0; i < 20 && i < n && *s; s++, i++)
+ if (*s < ' ' || *s >= 0177)
+ fprint(stderr, "\\x%x", *s);
+ else
+ fprint(stderr, "%c", *s);
+ }
+ if (i < n)
+ fprint(stderr, " ...");
+ else
+ fprint(stderr, "\"");
+ break;
+ }
+ case FCON:
+ fprint(stderr, " `%S'", token, (char*)cp - token);
+ break;
+ case '`': case '\'': fprint(stderr, " \"%k\"", t); break;
+ default: fprint(stderr, " `%k'", t);
+ }
+}
+
+/* warning - issue warning error message */
+void warning(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (wflag == 0) {
+ errcnt--;
+ error("warning: ");
+ vfprint(stderr, NULL, fmt, ap);
+ }
+ va_end(ap);
+}
diff --git a/code/tools/lcc/src/event.c b/code/tools/lcc/src/event.c
new file mode 100644
index 0000000..4549e3f
--- /dev/null
+++ b/code/tools/lcc/src/event.c
@@ -0,0 +1,28 @@
+#include "c.h"
+
+
+struct entry {
+ Apply func;
+ void *cl;
+};
+
+Events events;
+void attach(Apply func, void *cl, List *list) {
+ struct entry *p;
+
+ NEW(p, PERM);
+ p->func = func;
+ p->cl = cl;
+ *list = append(p, *list);
+}
+void apply(List event, void *arg1, void *arg2) {
+ if (event) {
+ List lp = event;
+ do {
+ struct entry *p = lp->x;
+ (*p->func)(p->cl, arg1, arg2);
+ lp = lp->link;
+ } while (lp != event);
+ }
+}
+
diff --git a/code/tools/lcc/src/expr.c b/code/tools/lcc/src/expr.c
new file mode 100644
index 0000000..b8cb08b
--- /dev/null
+++ b/code/tools/lcc/src/expr.c
@@ -0,0 +1,711 @@
+#include "c.h"
+
+
+static char prec[] = {
+#define xx(a,b,c,d,e,f,g) c,
+#define yy(a,b,c,d,e,f,g) c,
+#include "token.h"
+};
+static int oper[] = {
+#define xx(a,b,c,d,e,f,g) d,
+#define yy(a,b,c,d,e,f,g) d,
+#include "token.h"
+};
+float refinc = 1.0;
+static Tree expr2(void);
+static Tree expr3(int);
+static Tree nullcheck(Tree);
+static Tree postfix(Tree);
+static Tree unary(void);
+static Tree primary(void);
+static Type super(Type ty);
+
+static Type super(Type ty) {
+ switch (ty->op) {
+ case INT:
+ if (ty->size < inttype->size)
+ return inttype;
+ break;
+ case UNSIGNED:
+ if (ty->size < unsignedtype->size)
+ return unsignedtype;
+ break;
+ case POINTER:
+ return unsignedptr;
+ }
+ return ty;
+}
+Tree expr(int tok) {
+ static char stop[] = { IF, ID, '}', 0 };
+ Tree p = expr1(0);
+
+ while (t == ',') {
+ Tree q;
+ t = gettok();
+ q = pointer(expr1(0));
+ p = tree(RIGHT, q->type, root(value(p)), q);
+ }
+ if (tok)
+ test(tok, stop);
+ return p;
+}
+Tree expr0(int tok) {
+ return root(expr(tok));
+}
+Tree expr1(int tok) {
+ static char stop[] = { IF, ID, 0 };
+ Tree p = expr2();
+
+ if (t == '='
+ || (prec[t] >= 6 && prec[t] <= 8)
+ || (prec[t] >= 11 && prec[t] <= 13)) {
+ int op = t;
+ t = gettok();
+ if (oper[op] == ASGN)
+ p = asgntree(ASGN, p, value(expr1(0)));
+ else
+ {
+ expect('=');
+ p = incr(op, p, expr1(0));
+ }
+ }
+ if (tok)
+ test(tok, stop);
+ return p;
+}
+Tree incr(int op, Tree v, Tree e) {
+ return asgntree(ASGN, v, (*optree[op])(oper[op], v, e));
+}
+static Tree expr2(void) {
+ Tree p = expr3(4);
+
+ if (t == '?') {
+ Tree l, r;
+ Coordinate pts[2];
+ if (Aflag > 1 && isfunc(p->type))
+ warning("%s used in a conditional expression\n",
+ funcname(p));
+ p = pointer(p);
+ t = gettok();
+ pts[0] = src;
+ l = pointer(expr(':'));
+ pts[1] = src;
+ r = pointer(expr2());
+ if (events.points)
+ {
+ apply(events.points, &pts[0], &l);
+ apply(events.points, &pts[1], &r);
+ }
+ p = condtree(p, l, r);
+ }
+ return p;
+}
+Tree value(Tree p) {
+ int op = generic(rightkid(p)->op);
+
+ if (p->type != voidtype
+ && (op==AND || op==OR || op==NOT || op==EQ || op==NE
+ || op== LE || op==LT || op== GE || op==GT))
+ p = condtree(p, consttree(1, inttype),
+ consttree(0, inttype));
+ return p;
+}
+static Tree expr3(int k) {
+ int k1;
+ Tree p = unary();
+
+ for (k1 = prec[t]; k1 >= k; k1--)
+ while (prec[t] == k1 && *cp != '=') {
+ Tree r;
+ Coordinate pt;
+ int op = t;
+ t = gettok();
+ pt = src;
+ p = pointer(p);
+ if (op == ANDAND || op == OROR) {
+ r = pointer(expr3(k1));
+ if (events.points)
+ apply(events.points, &pt, &r);
+ } else
+ r = pointer(expr3(k1 + 1));
+ p = (*optree[op])(oper[op], p, r);
+ }
+ return p;
+}
+static Tree unary(void) {
+ Tree p;
+
+ switch (t) {
+ case '*': t = gettok(); p = unary(); p = pointer(p);
+ if (isptr(p->type)
+ && (isfunc(p->type->type) || isarray(p->type->type)))
+ p = retype(p, p->type->type);
+ else {
+ if (YYnull)
+ p = nullcheck(p);
+ p = rvalue(p);
+ } break;
+ case '&': t = gettok(); p = unary(); if (isarray(p->type) || isfunc(p->type))
+ p = retype(p, ptr(p->type));
+ else
+ p = lvalue(p);
+ if (isaddrop(p->op) && p->u.sym->sclass == REGISTER)
+ error("invalid operand of unary &; `%s' is declared register\n", p->u.sym->name);
+
+ else if (isaddrop(p->op))
+ p->u.sym->addressed = 1;
+ break;
+ case '+': t = gettok(); p = unary(); p = pointer(p);
+ if (isarith(p->type))
+ p = cast(p, promote(p->type));
+ else
+ typeerror(ADD, p, NULL); break;
+ case '-': t = gettok(); p = unary(); p = pointer(p);
+ if (isarith(p->type)) {
+ Type ty = promote(p->type);
+ p = cast(p, ty);
+ if (isunsigned(ty)) {
+ warning("unsigned operand of unary -\n");
+ p = simplify(ADD, ty, simplify(BCOM, ty, p, NULL), cnsttree(ty, 1UL));
+ } else
+ p = simplify(NEG, ty, p, NULL);
+ } else
+ typeerror(SUB, p, NULL); break;
+ case '~': t = gettok(); p = unary(); p = pointer(p);
+ if (isint(p->type)) {
+ Type ty = promote(p->type);
+ p = simplify(BCOM, ty, cast(p, ty), NULL);
+ } else
+ typeerror(BCOM, p, NULL); break;
+ case '!': t = gettok(); p = unary(); p = pointer(p);
+ if (isscalar(p->type))
+ p = simplify(NOT, inttype, cond(p), NULL);
+ else
+ typeerror(NOT, p, NULL); break;
+ case INCR: t = gettok(); p = unary(); p = incr(INCR, pointer(p), consttree(1, inttype)); break;
+ case DECR: t = gettok(); p = unary(); p = incr(DECR, pointer(p), consttree(1, inttype)); break;
+ case TYPECODE: case SIZEOF: { int op = t;
+ Type ty;
+ p = NULL;
+ t = gettok();
+ if (t == '(') {
+ t = gettok();
+ if (istypename(t, tsym)) {
+ ty = typename();
+ expect(')');
+ } else {
+ p = postfix(expr(')'));
+ ty = p->type;
+ }
+ } else {
+ p = unary();
+ ty = p->type;
+ }
+ assert(ty);
+ if (op == TYPECODE)
+ p = cnsttree(inttype, (long)ty->op);
+ else {
+ if (isfunc(ty) || ty->size == 0)
+ error("invalid type argument `%t' to `sizeof'\n", ty);
+ else if (p && rightkid(p)->op == FIELD)
+ error("`sizeof' applied to a bit field\n");
+ p = cnsttree(unsignedlong, (unsigned long)ty->size);
+ } } break;
+ case '(':
+ t = gettok();
+ if (istypename(t, tsym)) {
+ Type ty, ty1 = typename(), pty;
+ expect(')');
+ ty = unqual(ty1);
+ if (isenum(ty)) {
+ Type ty2 = ty->type;
+ if (isconst(ty1))
+ ty2 = qual(CONST, ty2);
+ if (isvolatile(ty1))
+ ty2 = qual(VOLATILE, ty2);
+ ty1 = ty2;
+ ty = ty->type;
+ }
+ p = pointer(unary());
+ pty = p->type;
+ if (isenum(pty))
+ pty = pty->type;
+ if ((isarith(pty) && isarith(ty))
+ || (isptr(pty) && isptr(ty))) {
+ explicitCast++;
+ p = cast(p, ty);
+ explicitCast--;
+ } else if ((isptr(pty) && isint(ty))
+ || (isint(pty) && isptr(ty))) {
+ if (Aflag >= 1 && ty->size < pty->size)
+ warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, ty);
+
+ p = cast(p, ty);
+ } else if (ty != voidtype) {
+ error("cast from `%t' to `%t' is illegal\n",
+ p->type, ty1);
+ ty1 = inttype;
+ }
+ if (generic(p->op) == INDIR || ty->size == 0)
+ p = tree(RIGHT, ty1, NULL, p);
+ else
+ p = retype(p, ty1);
+ } else
+ p = postfix(expr(')'));
+ break;
+ default:
+ p = postfix(primary());
+ }
+ return p;
+}
+
+static Tree postfix(Tree p) {
+ for (;;)
+ switch (t) {
+ case INCR: p = tree(RIGHT, p->type,
+ tree(RIGHT, p->type,
+ p,
+ incr(t, p, consttree(1, inttype))),
+ p);
+ t = gettok(); break;
+ case DECR: p = tree(RIGHT, p->type,
+ tree(RIGHT, p->type,
+ p,
+ incr(t, p, consttree(1, inttype))),
+ p);
+ t = gettok(); break;
+ case '[': {
+ Tree q;
+ t = gettok();
+ q = expr(']');
+ if (YYnull) {
+ if (isptr(p->type))
+ p = nullcheck(p);
+ else if (isptr(q->type))
+ q = nullcheck(q);
+ }
+ p = (*optree['+'])(ADD, pointer(p), pointer(q));
+ if (isptr(p->type) && isarray(p->type->type))
+ p = retype(p, p->type->type);
+ else
+ p = rvalue(p);
+ } break;
+ case '(': {
+ Type ty;
+ Coordinate pt;
+ p = pointer(p);
+ if (isptr(p->type) && isfunc(p->type->type))
+ ty = p->type->type;
+ else {
+ error("found `%t' expected a function\n", p->type);
+ ty = func(voidtype, NULL, 1);
+ p = retype(p, ptr(ty));
+ }
+ pt = src;
+ t = gettok();
+ p = call(p, ty, pt);
+ } break;
+ case '.': t = gettok();
+ if (t == ID) {
+ if (isstruct(p->type)) {
+ Tree q = addrof(p);
+ p = field(q, token);
+ q = rightkid(q);
+ if (isaddrop(q->op) && q->u.sym->temporary)
+ p = tree(RIGHT, p->type, p, NULL);
+ } else
+ error("left operand of . has incompatible type `%t'\n",
+ p->type);
+ t = gettok();
+ } else
+ error("field name expected\n"); break;
+ case DEREF: t = gettok();
+ p = pointer(p);
+ if (t == ID) {
+ if (isptr(p->type) && isstruct(p->type->type)) {
+ if (YYnull)
+ p = nullcheck(p);
+ p = field(p, token);
+ } else
+ error("left operand of -> has incompatible type `%t'\n", p->type);
+
+ t = gettok();
+ } else
+ error("field name expected\n"); break;
+ default:
+ return p;
+ }
+}
+static Tree primary(void) {
+ Tree p;
+
+ assert(t != '(');
+ switch (t) {
+ case ICON:
+ case FCON: p = tree(mkop(CNST,tsym->type), tsym->type, NULL, NULL);
+ p->u.v = tsym->u.c.v;
+ break;
+ case SCON: if (ischar(tsym->type->type))
+ tsym->u.c.v.p = stringn(tsym->u.c.v.p, tsym->type->size);
+ else
+ tsym->u.c.v.p = memcpy(allocate(tsym->type->size, PERM), tsym->u.c.v.p, tsym->type->size);
+ tsym = constant(tsym->type, tsym->u.c.v);
+ if (tsym->u.c.loc == NULL)
+ tsym->u.c.loc = genident(STATIC, tsym->type, GLOBAL);
+ p = idtree(tsym->u.c.loc); break;
+ case ID: if (tsym == NULL)
+ {
+ Symbol p = install(token, &identifiers, level, FUNC);
+ p->src = src;
+ if (getchr() == '(') {
+ Symbol q = lookup(token, externals);
+ p->type = func(inttype, NULL, 1);
+ p->sclass = EXTERN;
+ if (Aflag >= 1)
+ warning("missing prototype\n");
+ if (q && !eqtype(q->type, p->type, 1))
+ warning("implicit declaration of `%s' does not match previous declaration at %w\n", q->name, &q->src);
+
+ if (q == NULL) {
+ q = install(p->name, &externals, GLOBAL, PERM);
+ q->type = p->type;
+ q->sclass = EXTERN;
+ q->src = src;
+ (*IR->defsymbol)(q);
+ }
+ p->u.alias = q;
+ } else {
+ error("undeclared identifier `%s'\n", p->name);
+ p->sclass = AUTO;
+ p->type = inttype;
+ if (p->scope == GLOBAL)
+ (*IR->defsymbol)(p);
+ else
+ addlocal(p);
+ }
+ t = gettok();
+ if (xref)
+ use(p, src);
+ return idtree(p);
+ }
+ if (xref)
+ use(tsym, src);
+ if (tsym->sclass == ENUM)
+ p = consttree(tsym->u.value, inttype);
+ else {
+ if (tsym->sclass == TYPEDEF)
+ error("illegal use of type name `%s'\n", tsym->name);
+ p = idtree(tsym);
+ } break;
+ case FIRSTARG:
+ if (level > PARAM && cfunc && cfunc->u.f.callee[0])
+ p = idtree(cfunc->u.f.callee[0]);
+ else {
+ error("illegal use of `%k'\n", FIRSTARG);
+ p = cnsttree(inttype, 0L);
+ }
+ break;
+ default:
+ error("illegal expression\n");
+ p = cnsttree(inttype, 0L);
+ }
+ t = gettok();
+ return p;
+}
+Tree idtree(Symbol p) {
+ int op;
+ Tree e;
+ Type ty = p->type ? unqual(p->type) : voidptype;
+
+ if (p->scope == GLOBAL || p->sclass == STATIC)
+ op = ADDRG;
+ else if (p->scope == PARAM) {
+ op = ADDRF;
+ if (isstruct(p->type) && !IR->wants_argb)
+ {
+ e = tree(mkop(op,voidptype), ptr(ptr(p->type)), NULL, NULL);
+ e->u.sym = p;
+ return rvalue(rvalue(e));
+ }
+ } else if (p->sclass == EXTERN) {
+ assert(p->u.alias);
+ p = p->u.alias;
+ op = ADDRG;
+ } else
+ op = ADDRL;
+ p->ref += refinc;
+ if (isarray(ty))
+ e = tree(mkop(op,voidptype), p->type, NULL, NULL);
+ else if (isfunc(ty))
+ e = tree(mkop(op,funcptype), p->type, NULL, NULL);
+ else
+ e = tree(mkop(op,voidptype), ptr(p->type), NULL, NULL);
+ e->u.sym = p;
+ if (isptr(e->type))
+ e = rvalue(e);
+ return e;
+}
+
+Tree rvalue(Tree p) {
+ Type ty = deref(p->type);
+
+ ty = unqual(ty);
+ return tree(mkop(INDIR,ty), ty, p, NULL);
+}
+Tree lvalue(Tree p) {
+ if (generic(p->op) != INDIR) {
+ error("lvalue required\n");
+ return value(p);
+ } else if (unqual(p->type) == voidtype)
+ warning("`%t' used as an lvalue\n", p->type);
+ return p->kids[0];
+}
+Tree retype(Tree p, Type ty) {
+ Tree q;
+
+ if (p->type == ty)
+ return p;
+ q = tree(p->op, ty, p->kids[0], p->kids[1]);
+ q->node = p->node;
+ q->u = p->u;
+ return q;
+}
+Tree rightkid(Tree p) {
+ while (p && p->op == RIGHT)
+ if (p->kids[1])
+ p = p->kids[1];
+ else if (p->kids[0])
+ p = p->kids[0];
+ else
+ assert(0);
+ assert(p);
+ return p;
+}
+int hascall(Tree p) {
+ if (p == 0)
+ return 0;
+ if (generic(p->op) == CALL || (IR->mulops_calls &&
+ (p->op == DIV+I || p->op == MOD+I || p->op == MUL+I
+ || p->op == DIV+U || p->op == MOD+U || p->op == MUL+U)))
+ return 1;
+ return hascall(p->kids[0]) || hascall(p->kids[1]);
+}
+Type binary(Type xty, Type yty) {
+#define xx(t) if (xty == t || yty == t) return t
+ xx(longdouble);
+ xx(doubletype);
+ xx(floattype);
+ xx(unsignedlonglong);
+ xx(longlong);
+ xx(unsignedlong);
+ if ((xty == longtype && yty == unsignedtype)
+ || (xty == unsignedtype && yty == longtype)) {
+ if (longtype->size > unsignedtype->size)
+ return longtype;
+ else
+ return unsignedlong;
+ }
+ xx(longtype);
+ xx(unsignedtype);
+ return inttype;
+#undef xx
+}
+Tree pointer(Tree p) {
+ if (isarray(p->type))
+ /* assert(p->op != RIGHT || p->u.sym == NULL), */
+ p = retype(p, atop(p->type));
+ else if (isfunc(p->type))
+ p = retype(p, ptr(p->type));
+ return p;
+}
+Tree cond(Tree p) {
+ int op = generic(rightkid(p)->op);
+
+ if (op == AND || op == OR || op == NOT
+ || op == EQ || op == NE
+ || op == LE || op == LT || op == GE || op == GT)
+ return p;
+ p = pointer(p);
+ return (*optree[NEQ])(NE, p, consttree(0, inttype));
+}
+Tree cast(Tree p, Type type) {
+ Type src, dst;
+
+ p = value(p);
+ if (p->type == type)
+ return p;
+ dst = unqual(type);
+ src = unqual(p->type);
+ if (src->op != dst->op || src->size != dst->size) {
+ switch (src->op) {
+ case INT:
+ if (src->size < inttype->size)
+ p = simplify(CVI, inttype, p, NULL);
+ break;
+ case UNSIGNED:
+ if (src->size < inttype->size)
+ p = simplify(CVU, inttype, p, NULL);
+ else if (src->size < unsignedtype->size)
+ p = simplify(CVU, unsignedtype, p, NULL);
+ break;
+ case ENUM:
+ p = retype(p, inttype);
+ break;
+ case POINTER:
+ if (isint(dst) && src->size > dst->size)
+ warning("conversion from `%t' to `%t' is undefined\n", p->type, type);
+ p = simplify(CVP, super(src), p, NULL);
+ break;
+ case FLOAT:
+ break;
+ default: assert(0);
+ }
+ {
+ src = unqual(p->type);
+ dst = super(dst);
+ if (src->op != dst->op)
+ switch (src->op) {
+ case INT:
+ p = simplify(CVI, dst, p, NULL);
+ break;
+ case UNSIGNED:
+ if (isfloat(dst)) {
+ Type ssrc = signedint(src);
+ Tree two = cnsttree(longdouble, (double)2.0);
+ p = (*optree['+'])(ADD,
+ (*optree['*'])(MUL,
+ two,
+ simplify(CVU, ssrc,
+ simplify(RSH, src,
+ p, consttree(1, inttype)), NULL)),
+ simplify(CVU, ssrc,
+ simplify(BAND, src,
+ p, consttree(1, unsignedtype)), NULL));
+ } else
+ p = simplify(CVU, dst, p, NULL);
+ break;
+ case FLOAT:
+ if (isunsigned(dst)) {
+ Type sdst = signedint(dst);
+ Tree c = cast(cnsttree(longdouble, (double)sdst->u.sym->u.limits.max.i + 1), src);
+ p = condtree(
+ simplify(GE, src, p, c),
+ (*optree['+'])(ADD,
+ cast(cast(simplify(SUB, src, p, c), sdst), dst),
+ cast(cnsttree(unsignedlong, (unsigned long)sdst->u.sym->u.limits.max.i + 1), dst)),
+ simplify(CVF, sdst, p, NULL));
+ } else
+ p = simplify(CVF, dst, p, NULL);
+ break;
+ default: assert(0);
+ }
+ dst = unqual(type);
+ }
+ }
+ src = unqual(p->type);
+ switch (src->op) {
+ case INT:
+ if (src->op != dst->op || src->size != dst->size)
+ p = simplify(CVI, dst, p, NULL);
+ break;
+ case UNSIGNED:
+ if (src->op != dst->op || src->size != dst->size)
+ p = simplify(CVU, dst, p, NULL);
+ break;
+ case FLOAT:
+ if (src->op != dst->op || src->size != dst->size)
+ p = simplify(CVF, dst, p, NULL);
+ break;
+ case POINTER:
+ if (src->op != dst->op)
+ p = simplify(CVP, dst, p, NULL);
+ else {
+ if ((isfunc(src->type) && !isfunc(dst->type))
+ || (!isfunc(src->type) && isfunc(dst->type)))
+ warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, type);
+
+ if (src->size != dst->size)
+ p = simplify(CVP, dst, p, NULL);
+ }
+ break;
+ default: assert(0);
+ }
+ return retype(p, type);
+}
+Tree field(Tree p, const char *name) {
+ Field q;
+ Type ty1, ty = p->type;
+
+ if (isptr(ty))
+ ty = deref(ty);
+ ty1 = ty;
+ ty = unqual(ty);
+ if ((q = fieldref(name, ty)) != NULL) {
+ if (isarray(q->type)) {
+ ty = q->type->type;
+ if (isconst(ty1) && !isconst(ty))
+ ty = qual(CONST, ty);
+ if (isvolatile(ty1) && !isvolatile(ty))
+ ty = qual(VOLATILE, ty);
+ ty = array(ty, q->type->size/ty->size, q->type->align);
+ } else {
+ ty = q->type;
+ if (isconst(ty1) && !isconst(ty))
+ ty = qual(CONST, ty);
+ if (isvolatile(ty1) && !isvolatile(ty))
+ ty = qual(VOLATILE, ty);
+ ty = ptr(ty);
+ }
+ if (YYcheck && !isaddrop(p->op) && q->offset > 0) /* omit */
+ p = nullcall(ty, YYcheck, p, consttree(q->offset, inttype)); /* omit */
+ else /* omit */
+ p = simplify(ADD+P, ty, p, consttree(q->offset, inttype));
+
+ if (q->lsb) {
+ p = tree(FIELD, ty->type, rvalue(p), NULL);
+ p->u.field = q;
+ } else if (!isarray(q->type))
+ p = rvalue(p);
+
+ } else {
+ error("unknown field `%s' of `%t'\n", name, ty);
+ p = rvalue(retype(p, ptr(inttype)));
+ }
+ return p;
+}
+/* funcname - return name of function f or a function' */
+char *funcname(Tree f) {
+ if (isaddrop(f->op))
+ return stringf("`%s'", f->u.sym->name);
+ return "a function";
+}
+static Tree nullcheck(Tree p) {
+ if (!needconst && YYnull && isptr(p->type)) {
+ p = value(p);
+ if (strcmp(YYnull->name, "_YYnull") == 0) {
+ Symbol t1 = temporary(REGISTER, voidptype);
+ p = tree(RIGHT, p->type,
+ tree(OR, voidtype,
+ cond(asgn(t1, cast(p, voidptype))),
+ vcall(YYnull, voidtype, (file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL)),
+ idtree(t1));
+ }
+
+ else
+ p = nullcall(p->type, YYnull, p, cnsttree(inttype, 0L));
+
+ }
+ return p;
+}
+Tree nullcall(Type pty, Symbol f, Tree p, Tree e) {
+ Type ty;
+
+ if (isarray(pty))
+ return retype(nullcall(atop(pty), f, p, e), pty);
+ ty = unqual(unqual(p->type)->type);
+ return vcall(f, pty,
+ p, e,
+ cnsttree(inttype, (long)ty->size),
+ cnsttree(inttype, (long)ty->align),
+ (file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL);
+}
diff --git a/code/tools/lcc/src/gen.c b/code/tools/lcc/src/gen.c
new file mode 100644
index 0000000..4ee170d
--- /dev/null
+++ b/code/tools/lcc/src/gen.c
@@ -0,0 +1,830 @@
+#include "c.h"
+
+
+#define readsreg(p) \
+ (generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P)
+#define setsrc(d) ((d) && (d)->x.regnode && \
+ (d)->x.regnode->set == src->x.regnode->set && \
+ (d)->x.regnode->mask&src->x.regnode->mask)
+
+#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b))
+
+static Symbol askfixedreg(Symbol);
+static Symbol askreg(Symbol, unsigned*);
+static void blkunroll(int, int, int, int, int, int, int[]);
+static void docall(Node);
+static void dumpcover(Node, int, int);
+static void dumpregs(char *, char *, char *);
+static void dumprule(int);
+static void dumptree(Node);
+static unsigned emitasm(Node, int);
+static void genreload(Node, Symbol, int);
+static void genspill(Symbol, Node, Symbol);
+static Symbol getreg(Symbol, unsigned*, Node);
+static int getrule(Node, int);
+static void linearize(Node, Node);
+static int moveself(Node);
+static void prelabel(Node);
+static Node* prune(Node, Node*);
+static void putreg(Symbol);
+static void ralloc(Node);
+static void reduce(Node, int);
+static int reprune(Node*, int, int, Node);
+static int requate(Node);
+static Node reuse(Node, int);
+static void rewrite(Node);
+static Symbol spillee(Symbol, unsigned mask[], Node);
+static void spillr(Symbol, Node);
+static int uses(Node, Regnode);
+
+int offset;
+
+int maxoffset;
+
+int framesize;
+int argoffset;
+
+int maxargoffset;
+
+int dalign, salign;
+int bflag = 0; /* omit */
+int dflag = 0;
+
+int swap;
+
+unsigned (*emitter)(Node, int) = emitasm;
+static char NeedsReg[] = {
+ 0, /* unused */
+ 1, /* CNST */
+ 0, 0, /* ARG ASGN */
+ 1, /* INDIR */
+ 0, 0, 1, 1, /* - - CVF CVI */
+ 1, 0, 1, 1, /* CVP - CVU NEG */
+ 1, /* CALL */
+ 1, /* LOAD */
+ 0, /* RET */
+ 1, 1, 1, /* ADDRG ADDRF ADDRL */
+ 1, 1, 1, 1, 1, /* ADD SUB LSH MOD RSH */
+ 1, 1, 1, 1, /* BAND BCOM BOR BXOR */
+ 1, 1, /* DIV MUL */
+ 0, 0, 0, 0, 0, 0, /* EQ GE GT LE LT NE */
+ 0, 0 /* JUMP LABEL */
+};
+Node head;
+
+unsigned freemask[2];
+unsigned usedmask[2];
+unsigned tmask[2];
+unsigned vmask[2];
+Symbol mkreg(char *fmt, int n, int mask, int set) {
+ Symbol p;
+
+ NEW0(p, PERM);
+ p->name = p->x.name = stringf(fmt, n);
+ NEW0(p->x.regnode, PERM);
+ p->x.regnode->number = n;
+ p->x.regnode->mask = mask<<n;
+ p->x.regnode->set = set;
+ return p;
+}
+Symbol mkwildcard(Symbol *syms) {
+ Symbol p;
+
+ NEW0(p, PERM);
+ p->name = p->x.name = "wildcard";
+ p->x.wildcard = syms;
+ return p;
+}
+void mkauto(Symbol p) {
+ assert(p->sclass == AUTO);
+ offset = roundup(offset + p->type->size, p->type->align);
+ p->x.offset = -offset;
+ p->x.name = stringd(-offset);
+}
+void blockbeg(Env *e) {
+ e->offset = offset;
+ e->freemask[IREG] = freemask[IREG];
+ e->freemask[FREG] = freemask[FREG];
+}
+void blockend(Env *e) {
+ if (offset > maxoffset)
+ maxoffset = offset;
+ offset = e->offset;
+ freemask[IREG] = e->freemask[IREG];
+ freemask[FREG] = e->freemask[FREG];
+}
+int mkactual(int align, int size) {
+ int n = roundup(argoffset, align);
+
+ argoffset = n + size;
+ return n;
+}
+static void docall(Node p) {
+ p->syms[1] = p->syms[0];
+ p->syms[0] = intconst(argoffset);
+ if (argoffset > maxargoffset)
+ maxargoffset = argoffset;
+ argoffset = 0;
+}
+void blkcopy(int dreg, int doff, int sreg, int soff, int size, int tmp[]) {
+ assert(size >= 0);
+ if (size == 0)
+ return;
+ else if (size <= 2)
+ blkunroll(size, dreg, doff, sreg, soff, size, tmp);
+ else if (size == 3) {
+ blkunroll(2, dreg, doff, sreg, soff, 2, tmp);
+ blkunroll(1, dreg, doff+2, sreg, soff+2, 1, tmp);
+ }
+ else if (size <= 16) {
+ blkunroll(4, dreg, doff, sreg, soff, size&~3, tmp);
+ blkcopy(dreg, doff+(size&~3),
+ sreg, soff+(size&~3), size&3, tmp);
+ }
+ else
+ (*IR->x.blkloop)(dreg, doff, sreg, soff, size, tmp);
+}
+static void blkunroll(int k, int dreg, int doff, int sreg, int soff, int size, int tmp[]) {
+ int i;
+
+ assert(IR->x.max_unaligned_load);
+ if (k > IR->x.max_unaligned_load
+ && (k > salign || k > dalign))
+ k = IR->x.max_unaligned_load;
+ for (i = 0; i+k < size; i += 2*k) {
+ (*IR->x.blkfetch)(k, soff+i, sreg, tmp[0]);
+ (*IR->x.blkfetch)(k, soff+i+k, sreg, tmp[1]);
+ (*IR->x.blkstore)(k, doff+i, dreg, tmp[0]);
+ (*IR->x.blkstore)(k, doff+i+k, dreg, tmp[1]);
+ }
+ if (i < size) {
+ (*IR->x.blkfetch)(k, i+soff, sreg, tmp[0]);
+ (*IR->x.blkstore)(k, i+doff, dreg, tmp[0]);
+ }
+}
+void parseflags(int argc, char *argv[]) {
+ int i;
+
+ for (i = 0; i < argc; i++)
+ if (strcmp(argv[i], "-d") == 0)
+ dflag = 1;
+ else if (strcmp(argv[i], "-b") == 0) /* omit */
+ bflag = 1; /* omit */
+}
+static int getrule(Node p, int nt) {
+ int rulenum;
+
+ assert(p);
+ rulenum = (*IR->x._rule)(p->x.state, nt);
+ if (!rulenum) {
+ fprint(stderr, "(%x->op=%s at %w is corrupt.)\n", p, opname(p->op), &src);
+ assert(0);
+ }
+ return rulenum;
+}
+static void reduce(Node p, int nt) {
+ int rulenum, i;
+ short *nts;
+ Node kids[10];
+
+ p = reuse(p, nt);
+ rulenum = getrule(p, nt);
+ nts = IR->x._nts[rulenum];
+ (*IR->x._kids)(p, rulenum, kids);
+ for (i = 0; nts[i]; i++)
+ reduce(kids[i], nts[i]);
+ if (IR->x._isinstruction[rulenum]) {
+ assert(p->x.inst == 0 || p->x.inst == nt);
+ p->x.inst = nt;
+ if (p->syms[RX] && p->syms[RX]->temporary) {
+ debug(fprint(stderr, "(using %s)\n", p->syms[RX]->name));
+ p->syms[RX]->x.usecount++;
+ }
+ }
+}
+static Node reuse(Node p, int nt) {
+ struct _state {
+ short cost[1];
+ };
+ Symbol r = p->syms[RX];
+
+ if (generic(p->op) == INDIR && p->kids[0]->op == VREG+P
+ && r->u.t.cse && p->x.mayrecalc
+ && ((struct _state*)r->u.t.cse->x.state)->cost[nt] == 0)
+ return r->u.t.cse;
+ else
+ return p;
+}
+
+int mayrecalc(Node p) {
+ int op;
+
+ assert(p && p->syms[RX]);
+ if (p->syms[RX]->u.t.cse == NULL)
+ return 0;
+ op = generic(p->syms[RX]->u.t.cse->op);
+ if (op == CNST || op == ADDRF || op == ADDRG || op == ADDRL) {
+ p->x.mayrecalc = 1;
+ return 1;
+ } else
+ return 0;
+}
+static Node *prune(Node p, Node pp[]) {
+ if (p == NULL)
+ return pp;
+ p->x.kids[0] = p->x.kids[1] = p->x.kids[2] = NULL;
+ if (p->x.inst == 0)
+ return prune(p->kids[1], prune(p->kids[0], pp));
+ else if (p->syms[RX] && p->syms[RX]->temporary
+ && p->syms[RX]->x.usecount < 2) {
+ p->x.inst = 0;
+ debug(fprint(stderr, "(clobbering %s)\n", p->syms[RX]->name));
+ return prune(p->kids[1], prune(p->kids[0], pp));
+ }
+ else {
+ prune(p->kids[1], prune(p->kids[0], &p->x.kids[0]));
+ *pp = p;
+ return pp + 1;
+ }
+}
+
+#define ck(i) return (i) ? 0 : LBURG_MAX
+
+int range(Node p, int lo, int hi) {
+ Symbol s = p->syms[0];
+
+ switch (specific(p->op)) {
+ case ADDRF+P:
+ case ADDRL+P: ck(s->x.offset >= lo && s->x.offset <= hi);
+ case CNST+I: ck(s->u.c.v.i >= lo && s->u.c.v.i <= hi);
+ case CNST+U: ck(s->u.c.v.u >= lo && s->u.c.v.u <= hi);
+ case CNST+P: ck(s->u.c.v.p == 0 && lo <= 0 && hi >= 0);
+ }
+ return LBURG_MAX;
+}
+static void dumptree(Node p) {
+ if (p->op == VREG+P && p->syms[0]) {
+ fprint(stderr, "VREGP(%s)", p->syms[0]->name);
+ return;
+ } else if (generic(p->op) == LOAD) {
+ fprint(stderr, "LOAD(");
+ dumptree(p->kids[0]);
+ fprint(stderr, ")");
+ return;
+ }
+ fprint(stderr, "%s(", opname(p->op));
+ switch (generic(p->op)) {
+ case CNST: case LABEL:
+ case ADDRG: case ADDRF: case ADDRL:
+ if (p->syms[0])
+ fprint(stderr, "%s", p->syms[0]->name);
+ break;
+ case RET:
+ if (p->kids[0])
+ dumptree(p->kids[0]);
+ break;
+ case CVF: case CVI: case CVP: case CVU: case JUMP:
+ case ARG: case BCOM: case NEG: case INDIR:
+ dumptree(p->kids[0]);
+ break;
+ case CALL:
+ if (optype(p->op) != B) {
+ dumptree(p->kids[0]);
+ break;
+ }
+ /* else fall thru */
+ case EQ: case NE: case GT: case GE: case LE: case LT:
+ case ASGN: case BOR: case BAND: case BXOR: case RSH: case LSH:
+ case ADD: case SUB: case DIV: case MUL: case MOD:
+ dumptree(p->kids[0]);
+ fprint(stderr, ", ");
+ dumptree(p->kids[1]);
+ break;
+ default: assert(0);
+ }
+ fprint(stderr, ")");
+}
+static void dumpcover(Node p, int nt, int in) {
+ int rulenum, i;
+ short *nts;
+ Node kids[10];
+
+ p = reuse(p, nt);
+ rulenum = getrule(p, nt);
+ nts = IR->x._nts[rulenum];
+ fprint(stderr, "dumpcover(%x) = ", p);
+ for (i = 0; i < in; i++)
+ fprint(stderr, " ");
+ dumprule(rulenum);
+ (*IR->x._kids)(p, rulenum, kids);
+ for (i = 0; nts[i]; i++)
+ dumpcover(kids[i], nts[i], in+1);
+}
+
+static void dumprule(int rulenum) {
+ assert(rulenum);
+ fprint(stderr, "%s / %s", IR->x._string[rulenum],
+ IR->x._templates[rulenum]);
+ if (!IR->x._isinstruction[rulenum])
+ fprint(stderr, "\n");
+}
+static unsigned emitasm(Node p, int nt) {
+ int rulenum;
+ short *nts;
+ char *fmt;
+ Node kids[10];
+
+ p = reuse(p, nt);
+ rulenum = getrule(p, nt);
+ nts = IR->x._nts[rulenum];
+ fmt = IR->x._templates[rulenum];
+ assert(fmt);
+ if (IR->x._isinstruction[rulenum] && p->x.emitted)
+ print("%s", p->syms[RX]->x.name);
+ else if (*fmt == '#')
+ (*IR->x.emit2)(p);
+ else {
+ if (*fmt == '?') {
+ fmt++;
+ assert(p->kids[0]);
+ if (p->syms[RX] == p->x.kids[0]->syms[RX])
+ while (*fmt++ != '\n')
+ ;
+ }
+ for ((*IR->x._kids)(p, rulenum, kids); *fmt; fmt++)
+ if (*fmt != '%')
+ (void)putchar(*fmt);
+ else if (*++fmt == 'F')
+ print("%d", framesize);
+ else if (*fmt >= '0' && *fmt <= '9')
+ emitasm(kids[*fmt - '0'], nts[*fmt - '0']);
+ else if (*fmt >= 'a' && *fmt < 'a' + NELEMS(p->syms))
+ fputs(p->syms[*fmt - 'a']->x.name, stdout);
+ else
+ (void)putchar(*fmt);
+ }
+ return 0;
+}
+void emit(Node p) {
+ for (; p; p = p->x.next) {
+ assert(p->x.registered);
+ if ((p->x.equatable && requate(p)) || moveself(p))
+ ;
+ else
+ (*emitter)(p, p->x.inst);
+ p->x.emitted = 1;
+ }
+}
+static int moveself(Node p) {
+ return p->x.copy
+ && p->syms[RX]->x.name == p->x.kids[0]->syms[RX]->x.name;
+}
+int move(Node p) {
+ p->x.copy = 1;
+ return 1;
+}
+static int requate(Node q) {
+ Symbol src = q->x.kids[0]->syms[RX];
+ Symbol tmp = q->syms[RX];
+ Node p;
+ int n = 0;
+
+ debug(fprint(stderr, "(requate(%x): tmp=%s src=%s)\n", q, tmp->x.name, src->x.name));
+ for (p = q->x.next; p; p = p->x.next)
+ if (p->x.copy && p->syms[RX] == src
+ && p->x.kids[0]->syms[RX] == tmp)
+ debug(fprint(stderr, "(requate arm 0 at %x)\n", p)),
+ p->syms[RX] = tmp;
+ else if (setsrc(p->syms[RX]) && !moveself(p) && !readsreg(p))
+ return 0;
+ else if (p->x.spills)
+ return 0;
+ else if (generic(p->op) == CALL && p->x.next)
+ return 0;
+ else if (p->op == LABEL+V && p->x.next)
+ return 0;
+ else if (p->syms[RX] == tmp && readsreg(p))
+ debug(fprint(stderr, "(requate arm 5 at %x)\n", p)),
+ n++;
+ else if (p->syms[RX] == tmp)
+ break;
+ debug(fprint(stderr, "(requate arm 7 at %x)\n", p));
+ assert(n > 0);
+ for (p = q->x.next; p; p = p->x.next)
+ if (p->syms[RX] == tmp && readsreg(p)) {
+ p->syms[RX] = src;
+ if (--n <= 0)
+ break;
+ }
+ return 1;
+}
+static void prelabel(Node p) {
+ if (p == NULL)
+ return;
+ prelabel(p->kids[0]);
+ prelabel(p->kids[1]);
+ if (NeedsReg[opindex(p->op)])
+ setreg(p, (*IR->x.rmap)(opkind(p->op)));
+ switch (generic(p->op)) {
+ case ADDRF: case ADDRL:
+ if (p->syms[0]->sclass == REGISTER)
+ p->op = VREG+P;
+ break;
+ case INDIR:
+ if (p->kids[0]->op == VREG+P)
+ setreg(p, p->kids[0]->syms[0]);
+ break;
+ case ASGN:
+ if (p->kids[0]->op == VREG+P)
+ rtarget(p, 1, p->kids[0]->syms[0]);
+ break;
+ case CVI: case CVU: case CVP:
+ if (optype(p->op) != F
+ && opsize(p->op) <= p->syms[0]->u.c.v.i)
+ p->op = LOAD + opkind(p->op);
+ break;
+ }
+ (IR->x.target)(p);
+}
+void setreg(Node p, Symbol r) {
+ p->syms[RX] = r;
+}
+void rtarget(Node p, int n, Symbol r) {
+ Node q = p->kids[n];
+
+ assert(q);
+ assert(r);
+ assert(r->sclass == REGISTER || !r->x.wildcard);
+ assert(q->syms[RX]);
+ if (r != q->syms[RX] && !q->syms[RX]->x.wildcard) {
+ q = newnode(LOAD + opkind(q->op),
+ q, NULL, q->syms[0]);
+ if (r->u.t.cse == p->kids[n])
+ r->u.t.cse = q;
+ p->kids[n] = p->x.kids[n] = q;
+ q->x.kids[0] = q->kids[0];
+ }
+ setreg(q, r);
+ debug(fprint(stderr, "(targeting %x->x.kids[%d]=%x to %s)\n", p, n, p->kids[n], r->x.name));
+}
+static void rewrite(Node p) {
+ assert(p->x.inst == 0);
+ prelabel(p);
+ debug(dumptree(p));
+ debug(fprint(stderr, "\n"));
+ (*IR->x._label)(p);
+ debug(dumpcover(p, 1, 0));
+ reduce(p, 1);
+}
+Node gen(Node forest) {
+ int i;
+ struct node sentinel;
+ Node dummy, p;
+
+ head = forest;
+ for (p = forest; p; p = p->link) {
+ assert(p->count == 0);
+ if (generic(p->op) == CALL)
+ docall(p);
+ else if ( generic(p->op) == ASGN
+ && generic(p->kids[1]->op) == CALL)
+ docall(p->kids[1]);
+ else if (generic(p->op) == ARG)
+ (*IR->x.doarg)(p);
+ rewrite(p);
+ p->x.listed = 1;
+ }
+ for (p = forest; p; p = p->link)
+ prune(p, &dummy);
+ relink(&sentinel, &sentinel);
+ for (p = forest; p; p = p->link)
+ linearize(p, &sentinel);
+ forest = sentinel.x.next;
+ assert(forest);
+ sentinel.x.next->x.prev = NULL;
+ sentinel.x.prev->x.next = NULL;
+ for (p = forest; p; p = p->x.next)
+ for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
+ assert(p->x.kids[i]->syms[RX]);
+ if (p->x.kids[i]->syms[RX]->temporary) {
+ p->x.kids[i]->x.prevuse =
+ p->x.kids[i]->syms[RX]->x.lastuse;
+ p->x.kids[i]->syms[RX]->x.lastuse = p->x.kids[i];
+ }
+ }
+ for (p = forest; p; p = p->x.next) {
+ ralloc(p);
+ if (p->x.listed && NeedsReg[opindex(p->op)]
+ && (*IR->x.rmap)(opkind(p->op))) {
+ assert(generic(p->op) == CALL || generic(p->op) == LOAD);
+ putreg(p->syms[RX]);
+ }
+ }
+ return forest;
+}
+int notarget(Node p) {
+ return p->syms[RX]->x.wildcard ? 0 : LBURG_MAX;
+}
+static void putreg(Symbol r) {
+ assert(r && r->x.regnode);
+ freemask[r->x.regnode->set] |= r->x.regnode->mask;
+ debug(dumpregs("(freeing %s)\n", r->x.name, NULL));
+}
+static Symbol askfixedreg(Symbol s) {
+ Regnode r = s->x.regnode;
+ int n = r->set;
+
+ if (r->mask&~freemask[n])
+ return NULL;
+ else {
+ freemask[n] &= ~r->mask;
+ usedmask[n] |= r->mask;
+ return s;
+ }
+}
+static Symbol askreg(Symbol rs, unsigned rmask[]) {
+ int i;
+
+ if (rs->x.wildcard == NULL)
+ return askfixedreg(rs);
+ for (i = 31; i >= 0; i--) {
+ Symbol r = rs->x.wildcard[i];
+ if (r != NULL
+ && !(r->x.regnode->mask&~rmask[r->x.regnode->set])
+ && askfixedreg(r))
+ return r;
+ }
+ return NULL;
+}
+
+static Symbol getreg(Symbol s, unsigned mask[], Node p) {
+ Symbol r = askreg(s, mask);
+ if (r == NULL) {
+ r = spillee(s, mask, p);
+ assert(r && r->x.regnode);
+ spill(r->x.regnode->mask, r->x.regnode->set, p);
+ r = askreg(s, mask);
+ }
+ assert(r && r->x.regnode);
+ r->x.regnode->vbl = NULL;
+ return r;
+}
+int askregvar(Symbol p, Symbol regs) {
+ Symbol r;
+
+ assert(p);
+ if (p->sclass != REGISTER)
+ return 0;
+ else if (!isscalar(p->type)) {
+ p->sclass = AUTO;
+ return 0;
+ }
+ else if (p->temporary) {
+ p->x.name = "?";
+ return 1;
+ }
+ else if ((r = askreg(regs, vmask)) != NULL) {
+ p->x.regnode = r->x.regnode;
+ p->x.regnode->vbl = p;
+ p->x.name = r->x.name;
+ debug(dumpregs("(allocating %s to symbol %s)\n", p->x.name, p->name));
+ return 1;
+ }
+ else {
+ p->sclass = AUTO;
+ return 0;
+ }
+}
+static void linearize(Node p, Node next) {
+ int i;
+
+ for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++)
+ linearize(p->x.kids[i], next);
+ relink(next->x.prev, p);
+ relink(p, next);
+ debug(fprint(stderr, "(listing %x)\n", p));
+}
+static void ralloc(Node p) {
+ int i;
+ unsigned mask[2];
+
+ mask[0] = tmask[0];
+ mask[1] = tmask[1];
+ assert(p);
+ debug(fprint(stderr, "(rallocing %x)\n", p));
+ for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
+ Node kid = p->x.kids[i];
+ Symbol r = kid->syms[RX];
+ assert(r && kid->x.registered);
+ if (r->sclass != REGISTER && r->x.lastuse == kid)
+ putreg(r);
+ }
+ if (!p->x.registered && NeedsReg[opindex(p->op)]
+ && (*IR->x.rmap)(opkind(p->op))) {
+ Symbol sym = p->syms[RX], set = sym;
+ assert(sym);
+ if (sym->temporary)
+ set = (*IR->x.rmap)(opkind(p->op));
+ assert(set);
+ if (set->sclass != REGISTER) {
+ Symbol r;
+ if (*IR->x._templates[getrule(p, p->x.inst)] == '?')
+ for (i = 1; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
+ Symbol r = p->x.kids[i]->syms[RX];
+ assert(p->x.kids[i]->x.registered);
+ assert(r && r->x.regnode);
+ assert(sym->x.wildcard || sym != r);
+ mask[r->x.regnode->set] &= ~r->x.regnode->mask;
+ }
+ r = getreg(set, mask, p);
+ if (sym->temporary) {
+ Node q;
+ r->x.lastuse = sym->x.lastuse;
+ for (q = sym->x.lastuse; q; q = q->x.prevuse) {
+ q->syms[RX] = r;
+ q->x.registered = 1;
+ if (sym->u.t.cse && q->x.copy)
+ q->x.equatable = 1;
+ }
+ } else {
+ p->syms[RX] = r;
+ r->x.lastuse = p;
+ }
+ debug(dumpregs("(allocating %s to node %x)\n", r->x.name, (char *) p));
+ }
+ }
+ p->x.registered = 1;
+ (*IR->x.clobber)(p);
+}
+static Symbol spillee(Symbol set, unsigned mask[], Node here) {
+ Symbol bestreg = NULL;
+ int bestdist = -1, i;
+
+ assert(set);
+ if (!set->x.wildcard)
+ bestreg = set;
+ else {
+ for (i = 31; i >= 0; i--) {
+ Symbol ri = set->x.wildcard[i];
+ if (
+ ri != NULL &&
+ ri->x.lastuse &&
+ (ri->x.regnode->mask&tmask[ri->x.regnode->set]&mask[ri->x.regnode->set])
+ ) {
+ Regnode rn = ri->x.regnode;
+ Node q = here;
+ int dist = 0;
+ for (; q && !uses(q, rn); q = q->x.next)
+ dist++;
+ if (q && dist > bestdist) {
+ bestdist = dist;
+ bestreg = ri;
+ }
+ }
+ }
+ }
+ assert(bestreg); /* Must be able to spill something. Reconfigure the register allocator
+ to ensure that we can allocate a register for all nodes without spilling
+ the node's necessary input regs. */
+ assert(bestreg->x.regnode->vbl == NULL); /* Can't spill register variables because
+ the reload site might be in other blocks. Reconfigure the register allocator
+ to ensure that this register is never allocated to a variable. */
+ return bestreg;
+}
+static int uses(Node p, Regnode rn) {
+ int i;
+
+ for (i = 0; i < NELEMS(p->x.kids); i++)
+ if (
+ p->x.kids[i] &&
+ p->x.kids[i]->x.registered &&
+ rn->set == p->x.kids[i]->syms[RX]->x.regnode->set &&
+ (rn->mask&p->x.kids[i]->syms[RX]->x.regnode->mask)
+ )
+ return 1;
+ return 0;
+}
+static void spillr(Symbol r, Node here) {
+ int i;
+ Symbol tmp;
+ Node p = r->x.lastuse;
+ assert(p);
+ while (p->x.prevuse)
+ assert(r == p->syms[RX]),
+ p = p->x.prevuse;
+ assert(p->x.registered && !readsreg(p));
+ tmp = newtemp(AUTO, optype(p->op), opsize(p->op));
+ genspill(r, p, tmp);
+ for (p = here->x.next; p; p = p->x.next)
+ for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
+ Node k = p->x.kids[i];
+ if (k->x.registered && k->syms[RX] == r)
+ genreload(p, tmp, i);
+ }
+ putreg(r);
+}
+static void genspill(Symbol r, Node last, Symbol tmp) {
+ Node p, q;
+ Symbol s;
+ unsigned ty;
+
+ debug(fprint(stderr, "(spilling %s to local %s)\n", r->x.name, tmp->x.name));
+ debug(fprint(stderr, "(genspill: "));
+ debug(dumptree(last));
+ debug(fprint(stderr, ")\n"));
+ ty = opkind(last->op);
+ NEW0(s, FUNC);
+ s->sclass = REGISTER;
+ s->name = s->x.name = r->x.name;
+ s->x.regnode = r->x.regnode;
+ q = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, s);
+ q = newnode(INDIR + ty, q, NULL, NULL);
+ p = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, tmp);
+ p = newnode(ASGN + ty, p, q, NULL);
+ p->x.spills = 1;
+ rewrite(p);
+ prune(p, &q);
+ q = last->x.next;
+ linearize(p, q);
+ for (p = last->x.next; p != q; p = p->x.next) {
+ ralloc(p);
+ assert(!p->x.listed || !NeedsReg[opindex(p->op)] || !(*IR->x.rmap)(opkind(p->op)));
+ }
+}
+
+static void genreload(Node p, Symbol tmp, int i) {
+ Node q;
+ int ty;
+
+ debug(fprint(stderr, "(replacing %x with a reload from %s)\n", p->x.kids[i], tmp->x.name));
+ debug(fprint(stderr, "(genreload: "));
+ debug(dumptree(p->x.kids[i]));
+ debug(fprint(stderr, ")\n"));
+ ty = opkind(p->x.kids[i]->op);
+ q = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, tmp);
+ p->x.kids[i] = newnode(INDIR + ty, q, NULL, NULL);
+ rewrite(p->x.kids[i]);
+ prune(p->x.kids[i], &q);
+ reprune(&p->kids[1], reprune(&p->kids[0], 0, i, p), i, p);
+ prune(p, &q);
+ linearize(p->x.kids[i], p);
+}
+static int reprune(Node *pp, int k, int n, Node p) {
+ struct node x, *q = *pp;
+
+ if (q == NULL || k > n)
+ return k;
+ else if (q->x.inst == 0)
+ return reprune(&q->kids[1],
+ reprune(&q->kids[0], k, n, p), n, p);
+ if (k == n) {
+ debug(fprint(stderr, "(reprune changes %x from %x to %x)\n", pp, *pp, p->x.kids[n]));
+ *pp = p->x.kids[n];
+ x = *p;
+ (IR->x.target)(&x);
+ }
+ return k + 1;
+}
+void spill(unsigned mask, int n, Node here) {
+ int i;
+ Node p;
+
+ here->x.spills = 1;
+ usedmask[n] |= mask;
+ if (mask&~freemask[n]) {
+
+ assert( /* It makes no sense for a node to clobber() its target. */
+ here->x.registered == 0 || /* call isn't coming through clobber() */
+ here->syms[RX] == NULL ||
+ here->syms[RX]->x.regnode == NULL ||
+ here->syms[RX]->x.regnode->set != n ||
+ (here->syms[RX]->x.regnode->mask&mask) == 0
+ );
+
+ for (p = here; p; p = p->x.next)
+ for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
+ Symbol r = p->x.kids[i]->syms[RX];
+ assert(r);
+ if (p->x.kids[i]->x.registered && r->x.regnode->set == n
+ && r->x.regnode->mask&mask)
+ spillr(r, here);
+ }
+ }
+}
+static void dumpregs(char *msg, char *a, char *b) {
+ fprint(stderr, msg, a, b);
+ fprint(stderr, "(free[0]=%x)\n", freemask[0]);
+ fprint(stderr, "(free[1]=%x)\n", freemask[1]);
+}
+
+int getregnum(Node p) {
+ assert(p && p->syms[RX] && p->syms[RX]->x.regnode);
+ return p->syms[RX]->x.regnode->number;
+}
+
+
+unsigned regloc(Symbol p) {
+ assert(p && p->sclass == REGISTER && p->sclass == REGISTER && p->x.regnode);
+ return p->x.regnode->set<<8 | p->x.regnode->number;
+}
+
diff --git a/code/tools/lcc/src/init.c b/code/tools/lcc/src/init.c
new file mode 100644
index 0000000..172d7c0
--- /dev/null
+++ b/code/tools/lcc/src/init.c
@@ -0,0 +1,318 @@
+#include "c.h"
+
+
+static int curseg; /* current segment */
+
+/* defpointer - initialize a pointer to p or to 0 if p==0 */
+void defpointer(Symbol p) {
+ if (p) {
+ (*IR->defaddress)(p);
+ p->ref++;
+ } else {
+ static Value v;
+ (*IR->defconst)(P, voidptype->size, v);
+ }
+}
+
+/* genconst - generate/check constant expression e; return size */
+static int genconst(Tree e, int def) {
+ for (;;)
+ switch (generic(e->op)) {
+ case ADDRG:
+ if (def)
+ (*IR->defaddress)(e->u.sym);
+ return e->type->size;
+ case CNST:
+ if (e->op == CNST+P && isarray(e->type)) {
+ e = cvtconst(e);
+ continue;
+ }
+ if (def)
+ (*IR->defconst)(e->type->op, e->type->size, e->u.v);
+ return e->type->size;
+ case RIGHT:
+ assert(e->kids[0] || e->kids[1]);
+ if (e->kids[1] && e->kids[0])
+ error("initializer must be constant\n");
+ e = e->kids[1] ? e->kids[1] : e->kids[0];
+ continue;
+ case CVP:
+ if (isarith(e->type))
+ error("cast from `%t' to `%t' is illegal in constant expressions\n",
+ e->kids[0]->type, e->type);
+ /* fall thru */
+ case CVI: case CVU: case CVF:
+ e = e->kids[0];
+ continue;
+ default:
+ error("initializer must be constant\n");
+ if (def)
+ genconst(consttree(0, inttype), def);
+ return inttype->size;
+ }
+}
+
+/* initvalue - evaluate a constant expression for a value of integer type ty */
+static Tree initvalue(Type ty) {
+ Type aty;
+ Tree e;
+
+ needconst++;
+ e = expr1(0);
+ if ((aty = assign(ty, e)) != NULL)
+ e = cast(e, aty);
+ else {
+ error("invalid initialization type; found `%t' expected `%t'\n",
+ e->type, ty);
+ e = retype(consttree(0, inttype), ty);
+ }
+ needconst--;
+ if (generic(e->op) != CNST) {
+ error("initializer must be constant\n");
+ e = retype(consttree(0, inttype), ty);
+ }
+ return e;
+}
+
+/* initarray - initialize array of ty of <= len bytes; if len == 0, go to } */
+static int initarray(int len, Type ty, int lev) {
+ int n = 0;
+
+ do {
+ initializer(ty, lev);
+ n += ty->size;
+ if ((len > 0 && n >= len) || t != ',')
+ break;
+ t = gettok();
+ } while (t != '}');
+ return n;
+}
+
+/* initchar - initialize array of <= len ty characters; if len == 0, go to } */
+static int initchar(int len, Type ty) {
+ int n = 0;
+ char buf[16], *s = buf;
+
+ do {
+ *s++ = initvalue(ty)->u.v.i;
+ if (++n%inttype->size == 0) {
+ (*IR->defstring)(inttype->size, buf);
+ s = buf;
+ }
+ if ((len > 0 && n >= len) || t != ',')
+ break;
+ t = gettok();
+ } while (t != '}');
+ if (s > buf)
+ (*IR->defstring)(s - buf, buf);
+ return n;
+}
+
+/* initend - finish off an initialization at level lev; accepts trailing comma */
+static void initend(int lev, char follow[]) {
+ if (lev == 0 && t == ',')
+ t = gettok();
+ test('}', follow);
+}
+
+/* initfields - initialize <= an unsigned's worth of bit fields in fields p to q */
+static int initfields(Field p, Field q) {
+ unsigned int bits = 0;
+ int i, n = 0;
+
+ do {
+ i = initvalue(inttype)->u.v.i;
+ if (fieldsize(p) < 8*p->type->size) {
+ if ((p->type == inttype &&
+ (i < -(int)(fieldmask(p)>>1)-1 || i > (int)(fieldmask(p)>>1)))
+ || (p->type == unsignedtype && (i&~fieldmask(p)) != 0))
+ warning("initializer exceeds bit-field width\n");
+ i &= fieldmask(p);
+ }
+ bits |= i<<fieldright(p);
+ if (IR->little_endian) {
+ if (fieldsize(p) + fieldright(p) > n)
+ n = fieldsize(p) + fieldright(p);
+ } else {
+ if (fieldsize(p) + fieldleft(p) > n)
+ n = fieldsize(p) + fieldleft(p);
+ }
+ if (p->link == q)
+ break;
+ p = p->link;
+ } while (t == ',' && (t = gettok()) != 0);
+ n = (n + 7)/8;
+ for (i = 0; i < n; i++) {
+ Value v;
+ if (IR->little_endian) {
+ v.u = (unsigned char)bits;
+ bits >>= 8;
+ } else { /* a big endian */
+ v.u = (unsigned char)(bits>>(8*(unsignedtype->size - 1)));
+ bits <<= 8;
+ }
+ (*IR->defconst)(U, unsignedchar->size, v);
+ }
+ return n;
+}
+
+/* initstruct - initialize a struct ty of <= len bytes; if len == 0, go to } */
+static int initstruct(int len, Type ty, int lev) {
+ int a, n = 0;
+ Field p = ty->u.sym->u.s.flist;
+
+ do {
+ if (p->offset > n) {
+ (*IR->space)(p->offset - n);
+ n += p->offset - n;
+ }
+ if (p->lsb) {
+ Field q = p;
+ while (q->link && q->link->offset == p->offset)
+ q = q->link;
+ n += initfields(p, q->link);
+ p = q;
+ } else {
+ initializer(p->type, lev);
+ n += p->type->size;
+ }
+ if (p->link) {
+ p = p->link;
+ a = p->type->align;
+ } else
+ a = ty->align;
+ if (a && n%a) {
+ (*IR->space)(a - n%a);
+ n = roundup(n, a);
+ }
+ if ((len > 0 && n >= len) || t != ',')
+ break;
+ t = gettok();
+ } while (t != '}');
+ return n;
+}
+
+/* initializer - constexpr | { constexpr ( , constexpr )* [ , ] } */
+Type initializer(Type ty, int lev) {
+ int n = 0;
+ Tree e;
+ Type aty = NULL;
+ static char follow[] = { IF, CHAR, STATIC, 0 };
+
+ ty = unqual(ty);
+ if (isscalar(ty)) {
+ needconst++;
+ if (t == '{') {
+ t = gettok();
+ e = expr1(0);
+ initend(lev, follow);
+ } else
+ e = expr1(0);
+ e = pointer(e);
+ if ((aty = assign(ty, e)) != NULL)
+ e = cast(e, aty);
+ else
+ error("invalid initialization type; found `%t' expected `%t'\n",
+ e->type, ty);
+ n = genconst(e, 1);
+ deallocate(STMT);
+ needconst--;
+ }
+ if ((isunion(ty) || isstruct(ty)) && ty->size == 0) {
+ static char follow[] = { CHAR, STATIC, 0 };
+ error("cannot initialize undefined `%t'\n", ty);
+ skipto(';', follow);
+ return ty;
+ } else if (isunion(ty)) {
+ if (t == '{') {
+ t = gettok();
+ n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
+ initend(lev, follow);
+ } else {
+ if (lev == 0)
+ error("missing { in initialization of `%t'\n", ty);
+ n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
+ }
+ } else if (isstruct(ty)) {
+ if (t == '{') {
+ t = gettok();
+ n = initstruct(0, ty, lev + 1);
+ test('}', follow);
+ } else if (lev > 0)
+ n = initstruct(ty->size, ty, lev + 1);
+ else {
+ error("missing { in initialization of `%t'\n", ty);
+ n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
+ }
+ }
+ if (isarray(ty))
+ aty = unqual(ty->type);
+ if (isarray(ty) && ischar(aty)) {
+ if (t == SCON) {
+ if (ty->size > 0 && ty->size == tsym->type->size - 1)
+ tsym->type = array(chartype, ty->size, 0);
+ n = tsym->type->size;
+ (*IR->defstring)(tsym->type->size, tsym->u.c.v.p);
+ t = gettok();
+ } else if (t == '{') {
+ t = gettok();
+ if (t == SCON) {
+ ty = initializer(ty, lev + 1);
+ initend(lev, follow);
+ return ty;
+ }
+ n = initchar(0, aty);
+ test('}', follow);
+ } else if (lev > 0 && ty->size > 0)
+ n = initchar(ty->size, aty);
+ else { /* eg, char c[] = 0; */
+ error("missing { in initialization of `%t'\n", ty);
+ n = initchar(1, aty);
+ }
+ } else if (isarray(ty)) {
+ if (t == SCON && aty == widechar) {
+ int i;
+ unsigned int *s = tsym->u.c.v.p;
+ if (ty->size > 0 && ty->size == tsym->type->size - widechar->size)
+ tsym->type = array(widechar, ty->size/widechar->size, 0);
+ n = tsym->type->size;
+ for (i = 0; i < n; i += widechar->size) {
+ Value v;
+ v.u = *s++;
+ (*IR->defconst)(widechar->op, widechar->size, v);
+ }
+ t = gettok();
+ } else if (t == '{') {
+ t = gettok();
+ if (t == SCON && aty == widechar) {
+ ty = initializer(ty, lev + 1);
+ initend(lev, follow);
+ return ty;
+ }
+ n = initarray(0, aty, lev + 1);
+ test('}', follow);
+ } else if (lev > 0 && ty->size > 0)
+ n = initarray(ty->size, aty, lev + 1);
+ else {
+ error("missing { in initialization of `%t'\n", ty);
+ n = initarray(aty->size, aty, lev + 1);
+ }
+ }
+ if (ty->size) {
+ if (n > ty->size)
+ error("too many initializers\n");
+ else if (n < ty->size)
+ (*IR->space)(ty->size - n);
+ } else if (isarray(ty) && ty->type->size > 0)
+ ty = array(ty->type, n/ty->type->size, 0);
+ else
+ ty->size = n;
+ return ty;
+}
+
+/* swtoseg - switch to segment seg, if necessary */
+void swtoseg(int seg) {
+ if (curseg != seg)
+ (*IR->segment)(seg);
+ curseg = seg;
+}
diff --git a/code/tools/lcc/src/inits.c b/code/tools/lcc/src/inits.c
new file mode 100644
index 0000000..c42f61e
--- /dev/null
+++ b/code/tools/lcc/src/inits.c
@@ -0,0 +1,7 @@
+void init(int argc, char *argv[]) {
+ {extern void input_init(int, char *[]); input_init(argc, argv);}
+ {extern void main_init(int, char *[]); main_init(argc, argv);}
+ {extern void prof_init(int, char *[]); prof_init(argc, argv);}
+ {extern void trace_init(int, char *[]); trace_init(argc, argv);}
+ {extern void type_init(int, char *[]); type_init(argc, argv);}
+}
diff --git a/code/tools/lcc/src/input.c b/code/tools/lcc/src/input.c
new file mode 100644
index 0000000..c2a084e
--- /dev/null
+++ b/code/tools/lcc/src/input.c
@@ -0,0 +1,135 @@
+#include "c.h"
+
+
+static void pragma(void);
+static void resynch(void);
+
+static int bsize;
+static unsigned char buffer[MAXLINE+1 + BUFSIZE+1];
+unsigned char *cp; /* current input character */
+char *file; /* current input file name */
+char *firstfile; /* first input file */
+unsigned char *limit; /* points to last character + 1 */
+char *line; /* current line */
+int lineno; /* line number of current line */
+
+void nextline(void) {
+ do {
+ if (cp >= limit) {
+ fillbuf();
+ if (cp >= limit)
+ cp = limit;
+ if (cp == limit)
+ return;
+ } else {
+ lineno++;
+ for (line = (char *)cp; *cp==' ' || *cp=='\t'; cp++)
+ ;
+ if (*cp == '#') {
+ resynch();
+ nextline();
+ }
+ }
+ } while (*cp == '\n' && cp == limit);
+}
+void fillbuf(void) {
+ if (bsize == 0)
+ return;
+ if (cp >= limit)
+ cp = &buffer[MAXLINE+1];
+ else
+ {
+ int n = limit - cp;
+ unsigned char *s = &buffer[MAXLINE+1] - n;
+ assert(s >= buffer);
+ line = (char *)s - ((char *)cp - line);
+ while (cp < limit)
+ *s++ = *cp++;
+ cp = &buffer[MAXLINE+1] - n;
+ }
+ if (feof(stdin))
+ bsize = 0;
+ else
+ bsize = fread(&buffer[MAXLINE+1], 1, BUFSIZE, stdin);
+ if (bsize < 0) {
+ error("read error\n");
+ exit(EXIT_FAILURE);
+ }
+ limit = &buffer[MAXLINE+1+bsize];
+ *limit = '\n';
+}
+void input_init(int argc, char *argv[]) {
+ static int inited;
+
+ if (inited)
+ return;
+ inited = 1;
+ main_init(argc, argv);
+ limit = cp = &buffer[MAXLINE+1];
+ bsize = -1;
+ lineno = 0;
+ file = NULL;
+ fillbuf();
+ if (cp >= limit)
+ cp = limit;
+ nextline();
+}
+
+/* pragma - handle #pragma ref id... */
+static void pragma(void) {
+ if ((t = gettok()) == ID && strcmp(token, "ref") == 0)
+ for (;;) {
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == '\n' || *cp == 0)
+ break;
+ if ((t = gettok()) == ID && tsym) {
+ tsym->ref++;
+ use(tsym, src);
+ }
+ }
+}
+
+/* resynch - set line number/file name in # n [ "file" ] and #pragma ... */
+static void resynch(void) {
+ for (cp++; *cp == ' ' || *cp == '\t'; )
+ cp++;
+ if (limit - cp < MAXLINE)
+ fillbuf();
+ if (strncmp((char *)cp, "pragma", 6) == 0) {
+ cp += 6;
+ pragma();
+ } else if (*cp >= '0' && *cp <= '9') {
+ line: for (lineno = 0; *cp >= '0' && *cp <= '9'; )
+ lineno = 10*lineno + *cp++ - '0';
+ lineno--;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == '"') {
+ file = (char *)++cp;
+ while (*cp && *cp != '"' && *cp != '\n')
+ cp++;
+ file = stringn(file, (char *)cp - file);
+ if (*cp == '\n')
+ warning("missing \" in preprocessor line\n");
+ if (firstfile == 0)
+ firstfile = file;
+ }
+ } else if (strncmp((char *)cp, "line", 4) == 0) {
+ for (cp += 4; *cp == ' ' || *cp == '\t'; )
+ cp++;
+ if (*cp >= '0' && *cp <= '9')
+ goto line;
+ if (Aflag >= 2)
+ warning("unrecognized control line\n");
+ } else if (Aflag >= 2 && *cp != '\n')
+ warning("unrecognized control line\n");
+ while (*cp)
+ if (*cp++ == '\n') {
+ if (cp == limit + 1)
+ nextline();
+ else
+ break;
+ }
+}
+
diff --git a/code/tools/lcc/src/lex.c b/code/tools/lcc/src/lex.c
new file mode 100644
index 0000000..ec2f1ec
--- /dev/null
+++ b/code/tools/lcc/src/lex.c
@@ -0,0 +1,923 @@
+#include "c.h"
+#include <float.h>
+#include <errno.h>
+
+
+#define MAXTOKEN 32
+
+enum { BLANK=01, NEWLINE=02, LETTER=04,
+ DIGIT=010, HEX=020, OTHER=040 };
+
+static unsigned char map[256] = { /* 000 nul */ 0,
+ /* 001 soh */ 0,
+ /* 002 stx */ 0,
+ /* 003 etx */ 0,
+ /* 004 eot */ 0,
+ /* 005 enq */ 0,
+ /* 006 ack */ 0,
+ /* 007 bel */ 0,
+ /* 010 bs */ 0,
+ /* 011 ht */ BLANK,
+ /* 012 nl */ NEWLINE,
+ /* 013 vt */ BLANK,
+ /* 014 ff */ BLANK,
+ /* 015 cr */ 0,
+ /* 016 so */ 0,
+ /* 017 si */ 0,
+ /* 020 dle */ 0,
+ /* 021 dc1 */ 0,
+ /* 022 dc2 */ 0,
+ /* 023 dc3 */ 0,
+ /* 024 dc4 */ 0,
+ /* 025 nak */ 0,
+ /* 026 syn */ 0,
+ /* 027 etb */ 0,
+ /* 030 can */ 0,
+ /* 031 em */ 0,
+ /* 032 sub */ 0,
+ /* 033 esc */ 0,
+ /* 034 fs */ 0,
+ /* 035 gs */ 0,
+ /* 036 rs */ 0,
+ /* 037 us */ 0,
+ /* 040 sp */ BLANK,
+ /* 041 ! */ OTHER,
+ /* 042 " */ OTHER,
+ /* 043 # */ OTHER,
+ /* 044 $ */ 0,
+ /* 045 % */ OTHER,
+ /* 046 & */ OTHER,
+ /* 047 ' */ OTHER,
+ /* 050 ( */ OTHER,
+ /* 051 ) */ OTHER,
+ /* 052 * */ OTHER,
+ /* 053 + */ OTHER,
+ /* 054 , */ OTHER,
+ /* 055 - */ OTHER,
+ /* 056 . */ OTHER,
+ /* 057 / */ OTHER,
+ /* 060 0 */ DIGIT,
+ /* 061 1 */ DIGIT,
+ /* 062 2 */ DIGIT,
+ /* 063 3 */ DIGIT,
+ /* 064 4 */ DIGIT,
+ /* 065 5 */ DIGIT,
+ /* 066 6 */ DIGIT,
+ /* 067 7 */ DIGIT,
+ /* 070 8 */ DIGIT,
+ /* 071 9 */ DIGIT,
+ /* 072 : */ OTHER,
+ /* 073 ; */ OTHER,
+ /* 074 < */ OTHER,
+ /* 075 = */ OTHER,
+ /* 076 > */ OTHER,
+ /* 077 ? */ OTHER,
+ /* 100 @ */ 0,
+ /* 101 A */ LETTER|HEX,
+ /* 102 B */ LETTER|HEX,
+ /* 103 C */ LETTER|HEX,
+ /* 104 D */ LETTER|HEX,
+ /* 105 E */ LETTER|HEX,
+ /* 106 F */ LETTER|HEX,
+ /* 107 G */ LETTER,
+ /* 110 H */ LETTER,
+ /* 111 I */ LETTER,
+ /* 112 J */ LETTER,
+ /* 113 K */ LETTER,
+ /* 114 L */ LETTER,
+ /* 115 M */ LETTER,
+ /* 116 N */ LETTER,
+ /* 117 O */ LETTER,
+ /* 120 P */ LETTER,
+ /* 121 Q */ LETTER,
+ /* 122 R */ LETTER,
+ /* 123 S */ LETTER,
+ /* 124 T */ LETTER,
+ /* 125 U */ LETTER,
+ /* 126 V */ LETTER,
+ /* 127 W */ LETTER,
+ /* 130 X */ LETTER,
+ /* 131 Y */ LETTER,
+ /* 132 Z */ LETTER,
+ /* 133 [ */ OTHER,
+ /* 134 \ */ OTHER,
+ /* 135 ] */ OTHER,
+ /* 136 ^ */ OTHER,
+ /* 137 _ */ LETTER,
+ /* 140 ` */ 0,
+ /* 141 a */ LETTER|HEX,
+ /* 142 b */ LETTER|HEX,
+ /* 143 c */ LETTER|HEX,
+ /* 144 d */ LETTER|HEX,
+ /* 145 e */ LETTER|HEX,
+ /* 146 f */ LETTER|HEX,
+ /* 147 g */ LETTER,
+ /* 150 h */ LETTER,
+ /* 151 i */ LETTER,
+ /* 152 j */ LETTER,
+ /* 153 k */ LETTER,
+ /* 154 l */ LETTER,
+ /* 155 m */ LETTER,
+ /* 156 n */ LETTER,
+ /* 157 o */ LETTER,
+ /* 160 p */ LETTER,
+ /* 161 q */ LETTER,
+ /* 162 r */ LETTER,
+ /* 163 s */ LETTER,
+ /* 164 t */ LETTER,
+ /* 165 u */ LETTER,
+ /* 166 v */ LETTER,
+ /* 167 w */ LETTER,
+ /* 170 x */ LETTER,
+ /* 171 y */ LETTER,
+ /* 172 z */ LETTER,
+ /* 173 { */ OTHER,
+ /* 174 | */ OTHER,
+ /* 175 } */ OTHER,
+ /* 176 ~ */ OTHER, };
+static struct symbol tval;
+static char cbuf[BUFSIZE+1];
+static unsigned int wcbuf[BUFSIZE+1];
+
+Coordinate src; /* current source coordinate */
+int t;
+char *token; /* current token */
+Symbol tsym; /* symbol table entry for current token */
+
+static void *cput(int c, void *cl);
+static void *wcput(int c, void *cl);
+static void *scon(int q, void *put(int c, void *cl), void *cl);
+static int backslash(int q);
+static Symbol fcon(void);
+static Symbol icon(unsigned long, int, int);
+static void ppnumber(char *);
+
+int gettok(void) {
+ for (;;) {
+ register unsigned char *rcp = cp;
+ while (map[*rcp]&BLANK)
+ rcp++;
+ if (limit - rcp < MAXTOKEN) {
+ cp = rcp;
+ fillbuf();
+ rcp = cp;
+ }
+ src.file = file;
+ src.x = (char *)rcp - line;
+ src.y = lineno;
+ cp = rcp + 1;
+ switch (*rcp++) {
+ case '/': if (*rcp == '*') {
+ int c = 0;
+ for (rcp++; *rcp != '/' || c != '*'; )
+ if (map[*rcp]&NEWLINE) {
+ if (rcp < limit)
+ c = *rcp;
+ cp = rcp + 1;
+ nextline();
+ rcp = cp;
+ if (rcp == limit)
+ break;
+ } else
+ c = *rcp++;
+ if (rcp < limit)
+ rcp++;
+ else
+ error("unclosed comment\n");
+ cp = rcp;
+ continue;
+ }
+ return '/';
+ case '<':
+ if (*rcp == '=') return cp++, LEQ;
+ if (*rcp == '<') return cp++, LSHIFT;
+ return '<';
+ case '>':
+ if (*rcp == '=') return cp++, GEQ;
+ if (*rcp == '>') return cp++, RSHIFT;
+ return '>';
+ case '-':
+ if (*rcp == '>') return cp++, DEREF;
+ if (*rcp == '-') return cp++, DECR;
+ return '-';
+ case '=': return *rcp == '=' ? cp++, EQL : '=';
+ case '!': return *rcp == '=' ? cp++, NEQ : '!';
+ case '|': return *rcp == '|' ? cp++, OROR : '|';
+ case '&': return *rcp == '&' ? cp++, ANDAND : '&';
+ case '+': return *rcp == '+' ? cp++, INCR : '+';
+ case ';': case ',': case ':':
+ case '*': case '~': case '%': case '^': case '?':
+ case '[': case ']': case '{': case '}': case '(': case ')':
+ return rcp[-1];
+ case '\n': case '\v': case '\r': case '\f':
+ nextline();
+ if (cp == limit) {
+ tsym = NULL;
+ return EOI;
+ }
+ continue;
+
+ case 'i':
+ if (rcp[0] == 'f'
+ && !(map[rcp[1]]&(DIGIT|LETTER))) {
+ cp = rcp + 1;
+ return IF;
+ }
+ if (rcp[0] == 'n'
+ && rcp[1] == 't'
+ && !(map[rcp[2]]&(DIGIT|LETTER))) {
+ cp = rcp + 2;
+ tsym = inttype->u.sym;
+ return INT;
+ }
+ goto id;
+ case 'h': case 'j': case 'k': case 'm': case 'n': case 'o':
+ case 'p': case 'q': case 'x': case 'y': case 'z':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'G': case 'H': case 'I': case 'J': case 'K':
+ case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+ case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+ case 'Y': case 'Z':
+ id:
+ if (limit - rcp < MAXLINE) {
+ cp = rcp - 1;
+ fillbuf();
+ rcp = ++cp;
+ }
+ assert(cp == rcp);
+ token = (char *)rcp - 1;
+ while (map[*rcp]&(DIGIT|LETTER))
+ rcp++;
+ token = stringn(token, (char *)rcp - token);
+ tsym = lookup(token, identifiers);
+ cp = rcp;
+ return ID;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': {
+ unsigned long n = 0;
+ if (limit - rcp < MAXLINE) {
+ cp = rcp - 1;
+ fillbuf();
+ rcp = ++cp;
+ }
+ assert(cp == rcp);
+ token = (char *)rcp - 1;
+ if (*token == '0' && (*rcp == 'x' || *rcp == 'X')) {
+ int d, overflow = 0;
+ while (*++rcp) {
+ if (map[*rcp]&DIGIT)
+ d = *rcp - '0';
+ else if (*rcp >= 'a' && *rcp <= 'f')
+ d = *rcp - 'a' + 10;
+ else if (*rcp >= 'A' && *rcp <= 'F')
+ d = *rcp - 'A' + 10;
+ else
+ break;
+ if (n&~(~0UL >> 4))
+ overflow = 1;
+ else
+ n = (n<<4) + d;
+ }
+ if ((char *)rcp - token <= 2)
+ error("invalid hexadecimal constant `%S'\n", token, (char *)rcp-token);
+ cp = rcp;
+ tsym = icon(n, overflow, 16);
+ } else if (*token == '0') {
+ int err = 0, overflow = 0;
+ for ( ; map[*rcp]&DIGIT; rcp++) {
+ if (*rcp == '8' || *rcp == '9')
+ err = 1;
+ if (n&~(~0UL >> 3))
+ overflow = 1;
+ else
+ n = (n<<3) + (*rcp - '0');
+ }
+ if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') {
+ cp = rcp;
+ tsym = fcon();
+ return FCON;
+ }
+ cp = rcp;
+ tsym = icon(n, overflow, 8);
+ if (err)
+ error("invalid octal constant `%S'\n", token, (char*)cp-token);
+ } else {
+ int overflow = 0;
+ for (n = *token - '0'; map[*rcp]&DIGIT; ) {
+ int d = *rcp++ - '0';
+ if (n > (ULONG_MAX - d)/10)
+ overflow = 1;
+ else
+ n = 10*n + d;
+ }
+ if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') {
+ cp = rcp;
+ tsym = fcon();
+ return FCON;
+ }
+ cp = rcp;
+ tsym = icon(n, overflow, 10);
+ }
+ return ICON;
+ }
+ case '.':
+ if (rcp[0] == '.' && rcp[1] == '.') {
+ cp += 2;
+ return ELLIPSIS;
+ }
+ if ((map[*rcp]&DIGIT) == 0)
+ return '.';
+ if (limit - rcp < MAXLINE) {
+ cp = rcp - 1;
+ fillbuf();
+ rcp = ++cp;
+ }
+ assert(cp == rcp);
+ cp = rcp - 1;
+ token = (char *)cp;
+ tsym = fcon();
+ return FCON;
+ case 'L':
+ if (*rcp == '\'') {
+ unsigned int *s = scon(*cp, wcput, wcbuf);
+ if (s - wcbuf > 2)
+ warning("excess characters in wide-character literal ignored\n");
+ tval.type = widechar;
+ tval.u.c.v.u = wcbuf[0];
+ tsym = &tval;
+ return ICON;
+ } else if (*rcp == '"') {
+ unsigned int *s = scon(*cp, wcput, wcbuf);
+ tval.type = array(widechar, s - wcbuf, 0);
+ tval.u.c.v.p = wcbuf;
+ tsym = &tval;
+ return SCON;
+ } else
+ goto id;
+ case '\'': {
+ char *s = scon(*--cp, cput, cbuf);
+ if (s - cbuf > 2)
+ warning("excess characters in multibyte character literal ignored\n");
+ tval.type = inttype;
+ if (chartype->op == INT)
+ tval.u.c.v.i = extend(cbuf[0], chartype);
+ else
+ tval.u.c.v.i = cbuf[0]&0xFF;
+ tsym = &tval;
+ return ICON;
+ }
+ case '"': {
+ char *s = scon(*--cp, cput, cbuf);
+ tval.type = array(chartype, s - cbuf, 0);
+ tval.u.c.v.p = cbuf;
+ tsym = &tval;
+ return SCON;
+ }
+ case 'a':
+ if (rcp[0] == 'u'
+ && rcp[1] == 't'
+ && rcp[2] == 'o'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ return AUTO;
+ }
+ goto id;
+ case 'b':
+ if (rcp[0] == 'r'
+ && rcp[1] == 'e'
+ && rcp[2] == 'a'
+ && rcp[3] == 'k'
+ && !(map[rcp[4]]&(DIGIT|LETTER))) {
+ cp = rcp + 4;
+ return BREAK;
+ }
+ goto id;
+ case 'c':
+ if (rcp[0] == 'a'
+ && rcp[1] == 's'
+ && rcp[2] == 'e'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ return CASE;
+ }
+ if (rcp[0] == 'h'
+ && rcp[1] == 'a'
+ && rcp[2] == 'r'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ tsym = chartype->u.sym;
+ return CHAR;
+ }
+ if (rcp[0] == 'o'
+ && rcp[1] == 'n'
+ && rcp[2] == 's'
+ && rcp[3] == 't'
+ && !(map[rcp[4]]&(DIGIT|LETTER))) {
+ cp = rcp + 4;
+ return CONST;
+ }
+ if (rcp[0] == 'o'
+ && rcp[1] == 'n'
+ && rcp[2] == 't'
+ && rcp[3] == 'i'
+ && rcp[4] == 'n'
+ && rcp[5] == 'u'
+ && rcp[6] == 'e'
+ && !(map[rcp[7]]&(DIGIT|LETTER))) {
+ cp = rcp + 7;
+ return CONTINUE;
+ }
+ goto id;
+ case 'd':
+ if (rcp[0] == 'e'
+ && rcp[1] == 'f'
+ && rcp[2] == 'a'
+ && rcp[3] == 'u'
+ && rcp[4] == 'l'
+ && rcp[5] == 't'
+ && !(map[rcp[6]]&(DIGIT|LETTER))) {
+ cp = rcp + 6;
+ return DEFAULT;
+ }
+ if (rcp[0] == 'o'
+ && rcp[1] == 'u'
+ && rcp[2] == 'b'
+ && rcp[3] == 'l'
+ && rcp[4] == 'e'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ tsym = doubletype->u.sym;
+ return DOUBLE;
+ }
+ if (rcp[0] == 'o'
+ && !(map[rcp[1]]&(DIGIT|LETTER))) {
+ cp = rcp + 1;
+ return DO;
+ }
+ goto id;
+ case 'e':
+ if (rcp[0] == 'l'
+ && rcp[1] == 's'
+ && rcp[2] == 'e'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ return ELSE;
+ }
+ if (rcp[0] == 'n'
+ && rcp[1] == 'u'
+ && rcp[2] == 'm'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ return ENUM;
+ }
+ if (rcp[0] == 'x'
+ && rcp[1] == 't'
+ && rcp[2] == 'e'
+ && rcp[3] == 'r'
+ && rcp[4] == 'n'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return EXTERN;
+ }
+ goto id;
+ case 'f':
+ if (rcp[0] == 'l'
+ && rcp[1] == 'o'
+ && rcp[2] == 'a'
+ && rcp[3] == 't'
+ && !(map[rcp[4]]&(DIGIT|LETTER))) {
+ cp = rcp + 4;
+ tsym = floattype->u.sym;
+ return FLOAT;
+ }
+ if (rcp[0] == 'o'
+ && rcp[1] == 'r'
+ && !(map[rcp[2]]&(DIGIT|LETTER))) {
+ cp = rcp + 2;
+ return FOR;
+ }
+ goto id;
+ case 'g':
+ if (rcp[0] == 'o'
+ && rcp[1] == 't'
+ && rcp[2] == 'o'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ return GOTO;
+ }
+ goto id;
+ case 'l':
+ if (rcp[0] == 'o'
+ && rcp[1] == 'n'
+ && rcp[2] == 'g'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ return LONG;
+ }
+ goto id;
+ case 'r':
+ if (rcp[0] == 'e'
+ && rcp[1] == 'g'
+ && rcp[2] == 'i'
+ && rcp[3] == 's'
+ && rcp[4] == 't'
+ && rcp[5] == 'e'
+ && rcp[6] == 'r'
+ && !(map[rcp[7]]&(DIGIT|LETTER))) {
+ cp = rcp + 7;
+ return REGISTER;
+ }
+ if (rcp[0] == 'e'
+ && rcp[1] == 't'
+ && rcp[2] == 'u'
+ && rcp[3] == 'r'
+ && rcp[4] == 'n'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return RETURN;
+ }
+ goto id;
+ case 's':
+ if (rcp[0] == 'h'
+ && rcp[1] == 'o'
+ && rcp[2] == 'r'
+ && rcp[3] == 't'
+ && !(map[rcp[4]]&(DIGIT|LETTER))) {
+ cp = rcp + 4;
+ return SHORT;
+ }
+ if (rcp[0] == 'i'
+ && rcp[1] == 'g'
+ && rcp[2] == 'n'
+ && rcp[3] == 'e'
+ && rcp[4] == 'd'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return SIGNED;
+ }
+ if (rcp[0] == 'i'
+ && rcp[1] == 'z'
+ && rcp[2] == 'e'
+ && rcp[3] == 'o'
+ && rcp[4] == 'f'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return SIZEOF;
+ }
+ if (rcp[0] == 't'
+ && rcp[1] == 'a'
+ && rcp[2] == 't'
+ && rcp[3] == 'i'
+ && rcp[4] == 'c'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return STATIC;
+ }
+ if (rcp[0] == 't'
+ && rcp[1] == 'r'
+ && rcp[2] == 'u'
+ && rcp[3] == 'c'
+ && rcp[4] == 't'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return STRUCT;
+ }
+ if (rcp[0] == 'w'
+ && rcp[1] == 'i'
+ && rcp[2] == 't'
+ && rcp[3] == 'c'
+ && rcp[4] == 'h'
+ && !(map[rcp[5]]&(DIGIT|LETTER))) {
+ cp = rcp + 5;
+ return SWITCH;
+ }
+ goto id;
+ case 't':
+ if (rcp[0] == 'y'
+ && rcp[1] == 'p'
+ && rcp[2] == 'e'
+ && rcp[3] == 'd'
+ && rcp[4] == 'e'
+ && rcp[5] == 'f'
+ && !(map[rcp[6]]&(DIGIT|LETTER))) {
+ cp = rcp + 6;
+ return TYPEDEF;
+ }
+ goto id;
+ case 'u':
+ if (rcp[0] == 'n'
+ && rcp[1] == 'i'
+ && rcp[2] == 'o'
+ && rcp[3] == 'n'
+ && !(map[rcp[4]]&(DIGIT|LETTER))) {
+ cp = rcp + 4;
+ return UNION;
+ }
+ if (rcp[0] == 'n'
+ && rcp[1] == 's'
+ && rcp[2] == 'i'
+ && rcp[3] == 'g'
+ && rcp[4] == 'n'
+ && rcp[5] == 'e'
+ && rcp[6] == 'd'
+ && !(map[rcp[7]]&(DIGIT|LETTER))) {
+ cp = rcp + 7;
+ return UNSIGNED;
+ }
+ goto id;
+ case 'v':
+ if (rcp[0] == 'o'
+ && rcp[1] == 'i'
+ && rcp[2] == 'd'
+ && !(map[rcp[3]]&(DIGIT|LETTER))) {
+ cp = rcp + 3;
+ tsym = voidtype->u.sym;
+ return VOID;
+ }
+ if (rcp[0] == 'o'
+ && rcp[1] == 'l'
+ && rcp[2] == 'a'
+ && rcp[3] == 't'
+ && rcp[4] == 'i'
+ && rcp[5] == 'l'
+ && rcp[6] == 'e'
+ && !(map[rcp[7]]&(DIGIT|LETTER))) {
+ cp = rcp + 7;
+ return VOLATILE;
+ }
+ goto id;
+ case 'w':
+ if (rcp[0] == 'h'
+ && rcp[1] == 'i'
+ && rcp[2] == 'l'
+ && rcp[3] == 'e'
+ && !(map[rcp[4]]&(DIGIT|LETTER))) {
+ cp = rcp + 4;
+ return WHILE;
+ }
+ goto id;
+ case '_':
+ if (rcp[0] == '_'
+ && rcp[1] == 't'
+ && rcp[2] == 'y'
+ && rcp[3] == 'p'
+ && rcp[4] == 'e'
+ && rcp[5] == 'c'
+ && rcp[6] == 'o'
+ && rcp[7] == 'd'
+ && rcp[8] == 'e'
+ && !(map[rcp[9]]&(DIGIT|LETTER))) {
+ cp = rcp + 9;
+ return TYPECODE;
+ }
+ if (rcp[0] == '_'
+ && rcp[1] == 'f'
+ && rcp[2] == 'i'
+ && rcp[3] == 'r'
+ && rcp[4] == 's'
+ && rcp[5] == 't'
+ && rcp[6] == 'a'
+ && rcp[7] == 'r'
+ && rcp[8] == 'g'
+ && !(map[rcp[9]]&(DIGIT|LETTER))) {
+ cp = rcp + 9;
+ return FIRSTARG;
+ }
+ goto id;
+ default:
+ if ((map[cp[-1]]&BLANK) == 0) {
+ if (cp[-1] < ' ' || cp[-1] >= 0177)
+ error("illegal character `\\0%o'\n", cp[-1]);
+ else
+ error("illegal character `%c'\n", cp[-1]);
+ }
+ }
+ }
+}
+static Symbol icon(unsigned long n, int overflow, int base) {
+ if (((*cp=='u'||*cp=='U') && (cp[1]=='l'||cp[1]=='L'))
+ || ((*cp=='l'||*cp=='L') && (cp[1]=='u'||cp[1]=='U'))) {
+ tval.type = unsignedlong;
+ cp += 2;
+ } else if (*cp == 'u' || *cp == 'U') {
+ if (overflow || n > unsignedtype->u.sym->u.limits.max.i)
+ tval.type = unsignedlong;
+ else
+ tval.type = unsignedtype;
+ cp += 1;
+ } else if (*cp == 'l' || *cp == 'L') {
+ if (overflow || n > longtype->u.sym->u.limits.max.i)
+ tval.type = unsignedlong;
+ else
+ tval.type = longtype;
+ cp += 1;
+ } else if (overflow || n > longtype->u.sym->u.limits.max.i)
+ tval.type = unsignedlong;
+ else if (n > inttype->u.sym->u.limits.max.i)
+ tval.type = longtype;
+ else if (base != 10 && n > inttype->u.sym->u.limits.max.i)
+ tval.type = unsignedtype;
+ else
+ tval.type = inttype;
+ switch (tval.type->op) {
+ case INT:
+ if (overflow || n > tval.type->u.sym->u.limits.max.i) {
+ warning("overflow in constant `%S'\n", token,
+ (char*)cp - token);
+ tval.u.c.v.i = tval.type->u.sym->u.limits.max.i;
+ } else
+ tval.u.c.v.i = n;
+ break;
+ case UNSIGNED:
+ if (overflow || n > tval.type->u.sym->u.limits.max.u) {
+ warning("overflow in constant `%S'\n", token,
+ (char*)cp - token);
+ tval.u.c.v.u = tval.type->u.sym->u.limits.max.u;
+ } else
+ tval.u.c.v.u = n;
+ break;
+ default: assert(0);
+ }
+ ppnumber("integer");
+ return &tval;
+}
+static void ppnumber(char *which) {
+ unsigned char *rcp = cp--;
+
+ for ( ; (map[*cp]&(DIGIT|LETTER)) || *cp == '.'; cp++)
+ if ((cp[0] == 'E' || cp[0] == 'e')
+ && (cp[1] == '-' || cp[1] == '+'))
+ cp++;
+ if (cp > rcp)
+ error("`%S' is a preprocessing number but an invalid %s constant\n", token,
+
+ (char*)cp-token, which);
+}
+static Symbol fcon(void) {
+ if (*cp == '.')
+ do
+ cp++;
+ while (map[*cp]&DIGIT);
+ if (*cp == 'e' || *cp == 'E') {
+ if (*++cp == '-' || *cp == '+')
+ cp++;
+ if (map[*cp]&DIGIT)
+ do
+ cp++;
+ while (map[*cp]&DIGIT);
+ else
+ error("invalid floating constant `%S'\n", token,
+ (char*)cp - token);
+ }
+
+ errno = 0;
+ tval.u.c.v.d = strtod(token, NULL);
+ if (errno == ERANGE)
+ warning("overflow in floating constant `%S'\n", token,
+ (char*)cp - token);
+ if (*cp == 'f' || *cp == 'F') {
+ ++cp;
+ if (tval.u.c.v.d > floattype->u.sym->u.limits.max.d)
+ warning("overflow in floating constant `%S'\n", token,
+ (char*)cp - token);
+ tval.type = floattype;
+ } else if (*cp == 'l' || *cp == 'L') {
+ cp++;
+ tval.type = longdouble;
+ } else {
+ if (tval.u.c.v.d > doubletype->u.sym->u.limits.max.d)
+ warning("overflow in floating constant `%S'\n", token,
+ (char*)cp - token);
+ tval.type = doubletype;
+ }
+ ppnumber("floating");
+ return &tval;
+}
+
+static void *cput(int c, void *cl) {
+ char *s = cl;
+
+ if (c < 0 || c > 255)
+ warning("overflow in escape sequence with resulting value `%d'\n", c);
+ *s++ = c;
+ return s;
+}
+
+static void *wcput(int c, void *cl) {
+ unsigned int *s = cl;
+
+ *s++ = c;
+ return s;
+}
+
+static void *scon(int q, void *put(int c, void *cl), void *cl) {
+ int n = 0, nbad = 0;
+
+ do {
+ cp++;
+ while (*cp != q) {
+ int c;
+ if (map[*cp]&NEWLINE) {
+ if (cp < limit)
+ break;
+ cp++;
+ nextline();
+ if (cp == limit)
+ break;
+ continue;
+ }
+ c = *cp++;
+ if (c == '\\') {
+ if (map[*cp]&NEWLINE) {
+ if (cp < limit)
+ break;
+ cp++;
+ nextline();
+ }
+ if (limit - cp < MAXTOKEN)
+ fillbuf();
+ c = backslash(q);
+ } else if (c < 0 || c > 255 || map[c] == 0)
+ nbad++;
+ if (n++ < BUFSIZE)
+ cl = put(c, cl);
+ }
+ if (*cp == q)
+ cp++;
+ else
+ error("missing %c\n", q);
+ } while (q == '"' && getchr() == '"');
+ cl = put(0, cl);
+ if (n >= BUFSIZE)
+ error("%s literal too long\n", q == '"' ? "string" : "character");
+ if (Aflag >= 2 && q == '"' && n > 509)
+ warning("more than 509 characters in a string literal\n");
+ if (Aflag >= 2 && nbad > 0)
+ warning("%s literal contains non-portable characters\n",
+ q == '"' ? "string" : "character");
+ return cl;
+}
+int getchr(void) {
+ for (;;) {
+ while (map[*cp]&BLANK)
+ cp++;
+ if (!(map[*cp]&NEWLINE))
+ return *cp;
+ cp++;
+ nextline();
+ if (cp == limit)
+ return EOI;
+ }
+}
+static int backslash(int q) {
+ unsigned int c;
+
+ switch (*cp++) {
+ case 'a': return 7;
+ case 'b': return '\b';
+ case 'f': return '\f';
+ case 'n': return '\n';
+ case 'r': return '\r';
+ case 't': return '\t';
+ case 'v': return '\v';
+ case '\'': case '"': case '\\': case '\?': break;
+ case 'x': {
+ int overflow = 0;
+ if ((map[*cp]&(DIGIT|HEX)) == 0) {
+ if (*cp < ' ' || *cp == 0177)
+ error("ill-formed hexadecimal escape sequence\n");
+ else
+ error("ill-formed hexadecimal escape sequence `\\x%c'\n", *cp);
+ if (*cp != q)
+ cp++;
+ return 0;
+ }
+ for (c = 0; map[*cp]&(DIGIT|HEX); cp++) {
+ if (c >> (8*widechar->size - 4))
+ overflow = 1;
+ if (map[*cp]&DIGIT)
+ c = (c<<4) + *cp - '0';
+ else
+ c = (c<<4) + (*cp&~040) - 'A' + 10;
+ }
+ if (overflow)
+ warning("overflow in hexadecimal escape sequence\n");
+ return c&ones(8*widechar->size);
+ }
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c = *(cp-1) - '0';
+ if (*cp >= '0' && *cp <= '7') {
+ c = (c<<3) + *cp++ - '0';
+ if (*cp >= '0' && *cp <= '7')
+ c = (c<<3) + *cp++ - '0';
+ }
+ return c;
+ default:
+ if (cp[-1] < ' ' || cp[-1] >= 0177)
+ warning("unrecognized character escape sequence\n");
+ else
+ warning("unrecognized character escape sequence `\\%c'\n", cp[-1]);
+ }
+ return cp[-1];
+}
diff --git a/code/tools/lcc/src/list.c b/code/tools/lcc/src/list.c
new file mode 100644
index 0000000..29e660a
--- /dev/null
+++ b/code/tools/lcc/src/list.c
@@ -0,0 +1,56 @@
+#include "c.h"
+
+
+static List freenodes; /* free list nodes */
+
+/* append - append x to list, return new list */
+List append(void *x, List list) {
+ List new;
+
+ if ((new = freenodes) != NULL)
+ freenodes = freenodes->link;
+ else
+ NEW(new, PERM);
+ if (list) {
+ new->link = list->link;
+ list->link = new;
+ } else
+ new->link = new;
+ new->x = x;
+ return new;
+}
+
+/* length - # elements in list */
+int length(List list) {
+ int n = 0;
+
+ if (list) {
+ List lp = list;
+ do
+ n++;
+ while ((lp = lp->link) != list);
+ }
+ return n;
+}
+
+/* ltov - convert list to an NULL-terminated vector allocated in arena */
+void *ltov(List *list, unsigned arena) {
+ int i = 0;
+ void **array = newarray(length(*list) + 1, sizeof array[0], arena);
+
+ if (*list) {
+ List lp = *list;
+ do {
+ lp = lp->link;
+ array[i++] = lp->x;
+ } while (lp != *list);
+#ifndef PURIFY
+ lp = (*list)->link;
+ (*list)->link = freenodes;
+ freenodes = lp;
+#endif
+ }
+ *list = NULL;
+ array[i] = NULL;
+ return array;
+}
diff --git a/code/tools/lcc/src/main.c b/code/tools/lcc/src/main.c
new file mode 100644
index 0000000..63b85f2
--- /dev/null
+++ b/code/tools/lcc/src/main.c
@@ -0,0 +1,225 @@
+#include "c.h"
+
+static char rcsid[] = "main.c - faked rcsid";
+
+static void typestab(Symbol, void *);
+
+static void stabline(Coordinate *);
+static void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *);
+Interface *IR = NULL;
+
+int Aflag; /* >= 0 if -A specified */
+int Pflag; /* != 0 if -P specified */
+int glevel; /* == [0-9] if -g[0-9] specified */
+int xref; /* != 0 for cross-reference data */
+Symbol YYnull; /* _YYnull symbol if -n or -nvalidate specified */
+Symbol YYcheck; /* _YYcheck symbol if -nvalidate,check specified */
+
+static char *comment;
+static Interface stabIR;
+static char *currentfile; /* current file name */
+static int currentline; /* current line number */
+static FILE *srcfp; /* stream for current file, if non-NULL */
+static int srcpos; /* position of srcfp, if srcfp is non-NULL */
+int main(int argc, char *argv[]) {
+ int i, j;
+ for (i = argc - 1; i > 0; i--)
+ if (strncmp(argv[i], "-target=", 8) == 0)
+ break;
+ if (i > 0) {
+ char *s = strchr(argv[i], '\\');
+ if (s != NULL)
+ *s = '/';
+ for (j = 0; bindings[j].name && bindings[j].ir; j++)
+ if (strcmp(&argv[i][8], bindings[j].name) == 0) {
+ IR = bindings[j].ir;
+ break;
+ }
+ if (s != NULL)
+ *s = '\\';
+ }
+ if (!IR) {
+ fprint(stderr, "%s: unknown target", argv[0]);
+ if (i > 0)
+ fprint(stderr, " `%s'", &argv[i][8]);
+ fprint(stderr, "; must specify one of\n");
+ for (i = 0; bindings[i].name; i++)
+ fprint(stderr, "\t-target=%s\n", bindings[i].name);
+ exit(EXIT_FAILURE);
+ }
+ init(argc, argv);
+ t = gettok();
+ (*IR->progbeg)(argc, argv);
+ if (glevel && IR->stabinit)
+ (*IR->stabinit)(firstfile, argc, argv);
+ program();
+ if (events.end)
+ apply(events.end, NULL, NULL);
+ memset(&events, 0, sizeof events);
+ if (glevel || xref) {
+ Symbol symroot = NULL;
+ Coordinate src;
+ foreach(types, GLOBAL, typestab, &symroot);
+ foreach(identifiers, GLOBAL, typestab, &symroot);
+ src.file = firstfile;
+ src.x = 0;
+ src.y = lineno;
+ if ((glevel > 2 || xref) && IR->stabend)
+ (*IR->stabend)(&src, symroot,
+ ltov(&loci, PERM),
+ ltov(&symbols, PERM), NULL);
+ else if (IR->stabend)
+ (*IR->stabend)(&src, NULL, NULL, NULL, NULL);
+ }
+ finalize();
+ (*IR->progend)();
+ deallocate(PERM);
+ return errcnt > 0;
+}
+/* main_init - process program arguments */
+void main_init(int argc, char *argv[]) {
+ char *infile = NULL, *outfile = NULL;
+ int i;
+ static int inited;
+
+ if (inited)
+ return;
+ inited = 1;
+ type_init(argc, argv);
+ for (i = 1; i < argc; i++)
+ if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "-g2") == 0)
+ glevel = 2;
+ else if (strncmp(argv[i], "-g", 2) == 0) { /* -gn[,x] */
+ char *p = strchr(argv[i], ',');
+ glevel = atoi(argv[i]+2);
+ if (p) {
+ comment = p + 1;
+ if (glevel == 0)
+ glevel = 1;
+ if (stabIR.stabline == NULL) {
+ stabIR.stabline = IR->stabline;
+ stabIR.stabend = IR->stabend;
+ IR->stabline = stabline;
+ IR->stabend = stabend;
+ }
+ }
+ } else if (strcmp(argv[i], "-x") == 0)
+ xref++;
+ else if (strcmp(argv[i], "-A") == 0) {
+ ++Aflag;
+ } else if (strcmp(argv[i], "-P") == 0)
+ Pflag++;
+ else if (strcmp(argv[i], "-w") == 0)
+ wflag++;
+ else if (strcmp(argv[i], "-n") == 0) {
+ if (!YYnull) {
+ YYnull = install(string("_YYnull"), &globals, GLOBAL, PERM);
+ YYnull->type = func(voidptype, NULL, 1);
+ YYnull->sclass = EXTERN;
+ (*IR->defsymbol)(YYnull);
+ }
+ } else if (strncmp(argv[i], "-n", 2) == 0) { /* -nvalid[,check] */
+ char *p = strchr(argv[i], ',');
+ if (p) {
+ YYcheck = install(string(p+1), &globals, GLOBAL, PERM);
+ YYcheck->type = func(voidptype, NULL, 1);
+ YYcheck->sclass = EXTERN;
+ (*IR->defsymbol)(YYcheck);
+ p = stringn(argv[i]+2, p - (argv[i]+2));
+ } else
+ p = string(argv[i]+2);
+ YYnull = install(p, &globals, GLOBAL, PERM);
+ YYnull->type = func(voidptype, NULL, 1);
+ YYnull->sclass = EXTERN;
+ (*IR->defsymbol)(YYnull);
+ } else if (strcmp(argv[i], "-v") == 0)
+ fprint(stderr, "%s %s\n", argv[0], rcsid);
+ else if (strncmp(argv[i], "-s", 2) == 0)
+ density = strtod(&argv[i][2], NULL);
+ else if (strncmp(argv[i], "-errout=", 8) == 0) {
+ FILE *f = fopen(argv[i]+8, "w");
+ if (f == NULL) {
+ fprint(stderr, "%s: can't write errors to `%s'\n", argv[0], argv[i]+8);
+ exit(EXIT_FAILURE);
+ }
+ fclose(f);
+ f = freopen(argv[i]+8, "w", stderr);
+ assert(f);
+ } else if (strncmp(argv[i], "-e", 2) == 0) {
+ int x;
+ if ((x = strtol(&argv[i][2], NULL, 0)) > 0)
+ errlimit = x;
+ } else if (strncmp(argv[i], "-little_endian=", 15) == 0)
+ IR->little_endian = argv[i][15] - '0';
+ else if (strncmp(argv[i], "-mulops_calls=", 18) == 0)
+ IR->mulops_calls = argv[i][18] - '0';
+ else if (strncmp(argv[i], "-wants_callb=", 13) == 0)
+ IR->wants_callb = argv[i][13] - '0';
+ else if (strncmp(argv[i], "-wants_argb=", 12) == 0)
+ IR->wants_argb = argv[i][12] - '0';
+ else if (strncmp(argv[i], "-left_to_right=", 15) == 0)
+ IR->left_to_right = argv[i][15] - '0';
+ else if (strncmp(argv[i], "-wants_dag=", 11) == 0)
+ IR->wants_dag = argv[i][11] - '0';
+ else if (*argv[i] != '-' || strcmp(argv[i], "-") == 0) {
+ if (infile == NULL)
+ infile = argv[i];
+ else if (outfile == NULL)
+ outfile = argv[i];
+ }
+
+ if (infile != NULL && strcmp(infile, "-") != 0
+ && freopen(infile, "r", stdin) == NULL) {
+ fprint(stderr, "%s: can't read `%s'\n", argv[0], infile);
+ exit(EXIT_FAILURE);
+ }
+ if (outfile != NULL && strcmp(outfile, "-") != 0
+ && freopen(outfile, "w", stdout) == NULL) {
+ fprint(stderr, "%s: can't write `%s'\n", argv[0], outfile);
+ exit(EXIT_FAILURE);
+ }
+}
+/* typestab - emit stab entries for p */
+static void typestab(Symbol p, void *cl) {
+ if (*(Symbol *)cl == 0 && p->sclass && p->sclass != TYPEDEF)
+ *(Symbol *)cl = p;
+ if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype)
+ (*IR->stabtype)(p);
+}
+
+/* stabline - emit source code for source coordinate *cp */
+static void stabline(Coordinate *cp) {
+ if (cp->file && cp->file != currentfile) {
+ if (srcfp)
+ fclose(srcfp);
+ currentfile = cp->file;
+ srcfp = fopen(currentfile, "r");
+ srcpos = 0;
+ currentline = 0;
+ }
+ if (currentline != cp->y && srcfp) {
+ char buf[512];
+ if (srcpos > cp->y) {
+ rewind(srcfp);
+ srcpos = 0;
+ }
+ for ( ; srcpos < cp->y; srcpos++)
+ if (fgets(buf, sizeof buf, srcfp) == NULL) {
+ fclose(srcfp);
+ srcfp = NULL;
+ break;
+ }
+ if (srcfp && srcpos == cp->y)
+ print("%s%s", comment, buf);
+ }
+ currentline = cp->y;
+ if (stabIR.stabline)
+ (*stabIR.stabline)(cp);
+}
+
+static void stabend(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {
+ if (stabIR.stabend)
+ (*stabIR.stabend)(cp, p, cpp, sp, stab);
+ if (srcfp)
+ fclose(srcfp);
+}
diff --git a/code/tools/lcc/src/null.c b/code/tools/lcc/src/null.c
new file mode 100644
index 0000000..b9f551c
--- /dev/null
+++ b/code/tools/lcc/src/null.c
@@ -0,0 +1,74 @@
+#include "c.h"
+#define I(f) null_##f
+
+static Node I(gen)(Node p) { return p; }
+static void I(address)(Symbol q, Symbol p, long n) {}
+static void I(blockbeg)(Env *e) {}
+static void I(blockend)(Env *e) {}
+static void I(defaddress)(Symbol p) {}
+static void I(defconst)(int suffix, int size, Value v) {}
+static void I(defstring)(int len, char *s) {}
+static void I(defsymbol)(Symbol p) {}
+static void I(emit)(Node p) {}
+static void I(export)(Symbol p) {}
+static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {}
+static void I(global)(Symbol p) {}
+static void I(import)(Symbol p) {}
+static void I(local)(Symbol p) {}
+static void I(progbeg)(int argc, char *argv[]) {}
+static void I(progend)(void) {}
+static void I(segment)(int s) {}
+static void I(space)(int n) {}
+static void I(stabblock)(int brace, int lev, Symbol *p) {}
+static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {}
+static void I(stabfend)(Symbol p, int lineno) {}
+static void I(stabinit)(char *file, int argc, char *argv[]) {}
+static void I(stabline)(Coordinate *cp) {}
+static void I(stabsym)(Symbol p) {}
+static void I(stabtype)(Symbol p) {}
+
+
+Interface nullIR = {
+ {1, 1, 0}, /* char */
+ {2, 2, 0}, /* short */
+ {4, 4, 0}, /* int */
+ {8, 8, 1}, /* long */
+ {8 ,8, 1}, /* long long */
+ {4, 4, 1}, /* float */
+ {8, 8, 1}, /* double */
+ {16,16,1}, /* long double */
+ {4, 4, 0}, /* T* */
+ {0, 4, 0}, /* struct */
+ 1, /* little_endian */
+ 0, /* mulops_calls */
+ 0, /* wants_callb */
+ 0, /* wants_argb */
+ 1, /* left_to_right */
+ 0, /* wants_dag */
+ 0, /* unsigned_char */
+ I(address),
+ I(blockbeg),
+ I(blockend),
+ I(defaddress),
+ I(defconst),
+ I(defstring),
+ I(defsymbol),
+ I(emit),
+ I(export),
+ I(function),
+ I(gen),
+ I(global),
+ I(import),
+ I(local),
+ I(progbeg),
+ I(progend),
+ I(segment),
+ I(space),
+ I(stabblock),
+ I(stabend),
+ I(stabfend),
+ I(stabinit),
+ I(stabline),
+ I(stabsym),
+ I(stabtype)
+};
diff --git a/code/tools/lcc/src/output.c b/code/tools/lcc/src/output.c
new file mode 100644
index 0000000..a9c93e7
--- /dev/null
+++ b/code/tools/lcc/src/output.c
@@ -0,0 +1,135 @@
+#include "c.h"
+
+
+static char *outs(const char *str, FILE *f, char *bp) {
+ if (f)
+ fputs(str, f);
+ else
+ while ((*bp = *str++))
+ bp++;
+ return bp;
+}
+
+static char *outd(long n, FILE *f, char *bp) {
+ unsigned long m;
+ char buf[25], *s = buf + sizeof buf;
+
+ *--s = '\0';
+ if (n < 0)
+ m = -n;
+ else
+ m = n;
+ do
+ *--s = m%10 + '0';
+ while ((m /= 10) != 0);
+ if (n < 0)
+ *--s = '-';
+ return outs(s, f, bp);
+}
+
+static char *outu(unsigned long n, int base, FILE *f, char *bp) {
+ char buf[25], *s = buf + sizeof buf;
+
+ *--s = '\0';
+ do
+ *--s = "0123456789abcdef"[n%base];
+ while ((n /= base) != 0);
+ return outs(s, f, bp);
+}
+void print(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprint(stdout, NULL, fmt, ap);
+ va_end(ap);
+}
+/* fprint - formatted output to f */
+void fprint(FILE *f, const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprint(f, NULL, fmt, ap);
+ va_end(ap);
+}
+
+/* stringf - formatted output to a saved string */
+char *stringf(const char *fmt, ...) {
+ char buf[1024];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprint(NULL, buf, fmt, ap);
+ va_end(ap);
+ return string(buf);
+}
+
+/* vfprint - formatted output to f or string bp */
+void vfprint(FILE *f, char *bp, const char *fmt, va_list ap) {
+ for (; *fmt; fmt++)
+ if (*fmt == '%')
+ switch (*++fmt) {
+ case 'd': bp = outd(va_arg(ap, int), f, bp); break;
+ case 'D': bp = outd(va_arg(ap, long), f, bp); break;
+ case 'U': bp = outu(va_arg(ap, unsigned long), 10, f, bp); break;
+ case 'u': bp = outu(va_arg(ap, unsigned), 10, f, bp); break;
+ case 'o': bp = outu(va_arg(ap, unsigned), 8, f, bp); break;
+ case 'X': bp = outu(va_arg(ap, unsigned long), 16, f, bp); break;
+ case 'x': bp = outu(va_arg(ap, unsigned), 16, f, bp); break;
+ case 'f': case 'e':
+ case 'g': {
+ static char format[] = "%f";
+ char buf[128];
+ format[1] = *fmt;
+ sprintf(buf, format, va_arg(ap, double));
+ bp = outs(buf, f, bp);
+ }
+; break;
+ case 's': bp = outs(va_arg(ap, char *), f, bp); break;
+ case 'p': {
+ void *p = va_arg(ap, void *);
+ if (p)
+ bp = outs("0x", f, bp);
+ bp = outu((unsigned long)p, 16, f, bp);
+ break;
+ }
+ case 'c': if (f) fputc(va_arg(ap, int), f); else *bp++ = va_arg(ap, int); break;
+ case 'S': { char *s = va_arg(ap, char *);
+ int n = va_arg(ap, int);
+ if (s) {
+ for ( ; n-- > 0; s++)
+ if (f) (void)putc(*s, f); else *bp++ = *s;
+ }
+ } break;
+ case 'k': { int t = va_arg(ap, int);
+ static char *tokens[] = {
+#define xx(a,b,c,d,e,f,g) g,
+#define yy(a,b,c,d,e,f,g) g,
+#include "token.h"
+ };
+ assert(tokens[t&0177]);
+ bp = outs(tokens[t&0177], f, bp);
+ } break;
+ case 't': { Type ty = va_arg(ap, Type);
+ assert(f);
+ outtype(ty ? ty : voidtype, f);
+ } break;
+ case 'w': { Coordinate *p = va_arg(ap, Coordinate *);
+ if (p->file && *p->file) {
+ bp = outs(p->file, f, bp);
+ bp = outs(":", f, bp);
+ }
+ bp = outd(p->y, f, bp);
+ } break;
+ case 'I': { int n = va_arg(ap, int);
+ while (--n >= 0)
+ if (f) (void)putc(' ', f); else *bp++ = ' ';
+ } break;
+ default: if (f) (void)putc(*fmt, f); else *bp++ = *fmt; break;
+ }
+ else if (f)
+ (void)putc(*fmt, f);
+ else
+ *bp++ = *fmt;
+ if (!f)
+ *bp = '\0';
+}
diff --git a/code/tools/lcc/src/prof.c b/code/tools/lcc/src/prof.c
new file mode 100644
index 0000000..02709ed
--- /dev/null
+++ b/code/tools/lcc/src/prof.c
@@ -0,0 +1,228 @@
+#include "c.h"
+
+
+struct callsite {
+ char *file, *name;
+ union coordinate {
+ unsigned int coord;
+ struct { unsigned int y:16,x:10,index:6; } le;
+ struct { unsigned int index:6,x:10,y:16; } be;
+ } u;
+};
+struct func {
+ struct func *link;
+ struct caller *callers;
+ char *name;
+ union coordinate src;
+};
+struct map { /* source code map; 200 coordinates/map */
+ int size;
+ union coordinate u[200];
+};
+
+int npoints; /* # of execution points if -b specified */
+int ncalled = -1; /* #times prof.out says current function was called */
+static Symbol YYlink; /* symbol for file's struct _bbdata */
+static Symbol YYcounts; /* symbol for _YYcounts if -b specified */
+static List maplist; /* list of struct map *'s */
+static List filelist; /* list of file names */
+static Symbol funclist; /* list of struct func *'s */
+static Symbol afunc; /* current function's struct func */
+
+/* bbcall - build tree to set _callsite at call site *cp, emit call site data */
+static void bbcall(Symbol yycounts, Coordinate *cp, Tree *e) {
+ static Symbol caller;
+ Value v;
+ union coordinate u;
+ Symbol p = genident(STATIC, array(voidptype, 0, 0), GLOBAL);
+ Tree t = *e;
+
+ defglobal(p, LIT);
+ defpointer(cp->file ? mkstr(cp->file)->u.c.loc : (Symbol)0);
+ defpointer(mkstr(cfunc->name)->u.c.loc);
+ if (IR->little_endian) {
+ u.le.x = cp->x;
+ u.le.y = cp->y;
+ } else {
+ u.be.x = cp->x;
+ u.be.y = cp->y;
+ }
+ (*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v));
+ if (caller == 0) {
+ caller = mksymbol(EXTERN, "_caller", ptr(voidptype));
+ caller->defined = 0;
+ }
+ if (generic((*e)->op) != CALL)
+ t = (*e)->kids[0];
+ assert(generic(t->op) == CALL);
+ t = tree(t->op, t->type,
+ tree(RIGHT, t->kids[0]->type,
+ t->kids[0],
+ tree(RIGHT, t->kids[0]->type, asgn(caller, idtree(p)), t->kids[0])),
+ t->kids[1]);
+ if (generic((*e)->op) != CALL)
+ t = tree((*e)->op, (*e)->type, t, (*e)->kids[1]);
+ *e = t;
+}
+
+/* bbentry - return tree for _prologue(&afunc, &YYlink)' */
+static void bbentry(Symbol yylink, Symbol f) {
+ static Symbol prologue;
+
+ afunc = genident(STATIC, array(voidptype, 4, 0), GLOBAL);
+ if (prologue == 0) {
+ prologue = mksymbol(EXTERN, "_prologue", ftype(inttype, voidptype));
+ prologue->defined = 0;
+ }
+ walk(vcall(prologue, voidtype, pointer(idtree(afunc)), pointer(idtree(yylink)), NULL), 0, 0);
+
+}
+
+/* bbexit - return tree for _epilogue(&afunc)' */
+static void bbexit(Symbol yylink, Symbol f, Tree e) {
+ static Symbol epilogue;
+
+ if (epilogue == 0) {
+ epilogue = mksymbol(EXTERN, "_epilogue", ftype(inttype, voidptype));
+ epilogue->defined = 0;
+ }
+ walk(vcall(epilogue, voidtype, pointer(idtree(afunc)), NULL), 0, 0);
+}
+
+/* bbfile - add file to list of file names, return its index */
+static int bbfile(char *file) {
+ if (file) {
+ List lp;
+ int i = 1;
+ if ((lp = filelist) != NULL)
+ do {
+ lp = lp->link;
+ if (((Symbol)lp->x)->u.c.v.p == file)
+ return i;
+ i++;
+ } while (lp != filelist);
+ filelist = append(mkstr(file), filelist);
+ return i;
+ }
+ return 0;
+}
+
+/* bbfunc - emit function name and src coordinates */
+static void bbfunc(Symbol yylink, Symbol f) {
+ Value v;
+ union coordinate u;
+
+ defglobal(afunc, DATA);
+ defpointer(funclist);
+ defpointer(NULL);
+ defpointer(mkstr(f->name)->u.c.loc);
+ if (IR->little_endian) {
+ u.le.x = f->u.f.pt.x;
+ u.le.y = f->u.f.pt.y;
+ u.le.index = bbfile(f->u.f.pt.file);
+ } else {
+ u.be.x = f->u.f.pt.x;
+ u.be.y = f->u.f.pt.y;
+ u.be.index = bbfile(f->u.f.pt.file);
+ }
+ (*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v));
+ funclist = afunc;
+}
+
+/* bbincr - build tree to increment execution point at *cp */
+static void bbincr(Symbol yycounts, Coordinate *cp, Tree *e) {
+ struct map *mp = maplist->x;
+ Tree t;
+
+ /* append *cp to source map */
+ if (mp->size >= NELEMS(mp->u)) {
+ NEW(mp, PERM);
+ mp->size = 0;
+ maplist = append(mp, maplist);
+ }
+ if (IR->little_endian) {
+ mp->u[mp->size].le.x = cp->x;
+ mp->u[mp->size].le.y = cp->y;
+ mp->u[mp->size++].le.index = bbfile(cp->file);
+ } else {
+ mp->u[mp->size].be.x = cp->x;
+ mp->u[mp->size].be.y = cp->y;
+ mp->u[mp->size++].be.index = bbfile(cp->file);
+ }
+ t = incr('+', rvalue((*optree['+'])(ADD, pointer(idtree(yycounts)),
+ consttree(npoints++, inttype))), consttree(1, inttype));
+ if (*e)
+ *e = tree(RIGHT, (*e)->type, t, *e);
+ else
+ *e = t;
+}
+
+/* bbvars - emit definition for basic block counting data */
+static void bbvars(Symbol yylink) {
+ int i, j, n = npoints;
+ Value v;
+ struct map **mp;
+ Symbol coords, files, *p;
+
+ if (!YYcounts && !yylink)
+ return;
+ if (YYcounts) {
+ if (n <= 0)
+ n = 1;
+ YYcounts->type = array(unsignedtype, n, 0);
+ defglobal(YYcounts, BSS);
+ }
+ files = genident(STATIC, array(charptype, 1, 0), GLOBAL);
+ defglobal(files, LIT);
+ for (p = ltov(&filelist, PERM); *p; p++)
+ defpointer((*p)->u.c.loc);
+ defpointer(NULL);
+ coords = genident(STATIC, array(unsignedtype, n, 0), GLOBAL);
+ defglobal(coords, LIT);
+ for (i = n, mp = ltov(&maplist, PERM); *mp; i -= (*mp)->size, mp++)
+ for (j = 0; j < (*mp)->size; j++)
+ (*IR->defconst)(U, unsignedtype->size, (v.u = (*mp)->u[j].coord, v));
+ if (i > 0)
+ (*IR->space)(i*coords->type->type->size);
+ defpointer(NULL);
+ defglobal(yylink, DATA);
+ defpointer(NULL);
+ (*IR->defconst)(U, unsignedtype->size, (v.u = n, v));
+ defpointer(YYcounts);
+ defpointer(coords);
+ defpointer(files);
+ defpointer(funclist);
+}
+
+/* profInit - initialize basic block profiling options */
+void prof_init(int argc, char *argv[]) {
+ int i;
+ static int inited;
+
+ if (inited)
+ return;
+ inited = 1;
+ type_init(argc, argv);
+ if (IR) {
+ for (i = 1; i < argc; i++)
+ if (strncmp(argv[i], "-a", 2) == 0) {
+ if (ncalled == -1
+ && process(argv[i][2] ? &argv[i][2] : "prof.out") > 0)
+ ncalled = 0;
+ } else if ((strcmp(argv[i], "-b") == 0
+ || strcmp(argv[i], "-C") == 0) && YYlink == 0) {
+ YYlink = genident(STATIC, array(unsignedtype, 0, 0), GLOBAL);
+ attach((Apply)bbentry, YYlink, &events.entry);
+ attach((Apply)bbexit, YYlink, &events.returns);
+ attach((Apply)bbfunc, YYlink, &events.exit);
+ attach((Apply)bbvars, YYlink, &events.end);
+ if (strcmp(argv[i], "-b") == 0) {
+ YYcounts = genident(STATIC, array(unsignedtype, 0, 0), GLOBAL);
+ maplist = append(allocate(sizeof (struct map), PERM), maplist);
+ ((struct map *)maplist->x)->size = 0;
+ attach((Apply)bbcall, YYcounts, &events.calls);
+ attach((Apply)bbincr, YYcounts, &events.points);
+ }
+ }
+ }
+}
diff --git a/code/tools/lcc/src/profio.c b/code/tools/lcc/src/profio.c
new file mode 100644
index 0000000..37fc25b
--- /dev/null
+++ b/code/tools/lcc/src/profio.c
@@ -0,0 +1,276 @@
+/* C compiler: prof.out input
+
+prof.out format:
+#files
+ name
+ ... (#files-1 times)
+#functions
+ name file# x y count caller file x y
+ ... (#functions-1 times)
+#points
+ file# x y count
+ ... (#points-1 times)
+*/
+#include "c.h"
+
+
+struct count { /* count data: */
+ int x, y; /* source coordinate */
+ int count; /* associated execution count */
+};
+
+#define MAXTOKEN 64
+
+struct file { /* per-file prof.out data: */
+ struct file *link; /* link to next file */
+ char *name; /* file name */
+ int size; /* size of counts[] */
+ int count; /* counts[0..count-1] hold valid data */
+ struct count *counts; /* count data */
+ struct func { /* function data: */
+ struct func *link; /* link to next function */
+ char *name; /* function name */
+ struct count count; /* total number of calls */
+ struct caller { /* caller data: */
+ struct caller *link; /* link to next caller */
+ char *name; /* caller's name */
+ char *file; /* call site: file, x, y */
+ int x, y;
+ int count; /* number of calls from this site */
+ } *callers;
+ } *funcs; /* list of functions */
+} *filelist;
+FILE *fp;
+
+/* acaller - add caller and site (file,x,y) to callee's callers list */
+static void acaller(char *caller, char *file, int x, int y, int count, struct func *callee) {
+ struct caller *q;
+
+ assert(callee);
+ for (q = callee->callers; q && (caller != q->name
+ || file != q->file || x != q->x || y != q->y); q = q->link)
+ ;
+ if (!q) {
+ struct caller **r;
+ NEW(q, PERM);
+ q->name = caller;
+ q->file = file;
+ q->x = x;
+ q->y = y;
+ q->count = 0;
+ for (r = &callee->callers; *r && (strcmp(q->name, (*r)->name) > 0
+ || strcmp(q->file, (*r)->file) > 0 || q->y > (*r)->y || q->y > (*r)->y); r = &(*r)->link)
+ ;
+ q->link = *r;
+ *r = q;
+ }
+ q->count += count;
+}
+
+/* compare - return <0, 0, >0 if a<b, a==b, a>b, resp. */
+static int compare(struct count *a, struct count *b) {
+ if (a->y == b->y)
+ return a->x - b->x;
+ return a->y - b->y;
+}
+
+/* findfile - return file name's file list entry, or 0 */
+static struct file *findfile(char *name) {
+ struct file *p;
+
+ for (p = filelist; p; p = p->link)
+ if (p->name == name)
+ return p;
+ return 0;
+}
+
+/* afunction - add function name and its data to file's function list */
+static struct func *afunction(char *name, char *file, int x, int y, int count) {
+ struct file *p = findfile(file);
+ struct func *q;
+
+ assert(p);
+ for (q = p->funcs; q && name != q->name; q = q->link)
+ ;
+ if (!q) {
+ struct func **r;
+ NEW(q, PERM);
+ q->name = name;
+ q->count.x = x;
+ q->count.y = y;
+ q->count.count = 0;
+ q->callers = 0;
+ for (r = &p->funcs; *r && compare(&q->count, &(*r)->count) > 0; r = &(*r)->link)
+ ;
+ q->link = *r;
+ *r = q;
+ }
+ q->count.count += count;
+ return q;
+}
+
+/* apoint - append execution point i to file's data */
+static void apoint(int i, char *file, int x, int y, int count) {
+ struct file *p = findfile(file);
+
+ assert(p);
+ if (i >= p->size) {
+ int j;
+ if (p->size == 0) {
+ p->size = i >= 200 ? 2*i : 200;
+ p->counts = newarray(p->size, sizeof *p->counts, PERM);
+ } else {
+ struct count *new;
+ p->size = 2*i;
+ new = newarray(p->size, sizeof *new, PERM);
+ for (j = 0; j < p->count; j++)
+ new[j] = p->counts[j];
+ p->counts = new;
+ }
+ for (j = p->count; j < p->size; j++) {
+ static struct count z;
+ p->counts[j] = z;
+ }
+ }
+ p->counts[i].x = x;
+ p->counts[i].y = y;
+ p->counts[i].count += count;
+ if (i >= p->count)
+ p->count = i + 1;
+}
+
+/* findcount - return count associated with (file,x,y) or -1 */
+int findcount(char *file, int x, int y) {
+ static struct file *cursor;
+
+ if (cursor == 0 || cursor->name != file)
+ cursor = findfile(file);
+ if (cursor) {
+ int l, u;
+ struct count *c = cursor->counts;
+ for (l = 0, u = cursor->count - 1; l <= u; ) {
+ int k = (l + u)/2;
+ if (c[k].y > y || (c[k].y == y && c[k].x > x))
+ u = k - 1;
+ else if (c[k].y < y || (c[k].y == y && c[k].x < x))
+ l = k + 1;
+ else
+ return c[k].count;
+ }
+ }
+ return -1;
+}
+
+/* findfunc - return count associated with function name in file or -1 */
+int findfunc(char *name, char *file) {
+ static struct file *cursor;
+
+ if (cursor == 0 || cursor->name != file)
+ cursor = findfile(file);
+ if (cursor) {
+ struct func *p;
+ for (p = cursor->funcs; p; p = p->link)
+ if (p->name == name)
+ return p->count.count;
+ }
+ return -1;
+}
+
+/* getd - read a nonnegative number */
+static int getd(void) {
+ int c, n = 0;
+
+ while ((c = getc(fp)) != EOF && (c == ' ' || c == '\n' || c == '\t'))
+ ;
+ if (c >= '0' && c <= '9') {
+ do
+ n = 10*n + (c - '0');
+ while ((c = getc(fp)) >= '0' && c <= '9');
+ return n;
+ }
+ return -1;
+}
+
+/* getstr - read a string */
+static char *getstr(void) {
+ int c;
+ char buf[MAXTOKEN], *s = buf;
+
+ while ((c = getc(fp)) != EOF && c != ' ' && c != '\n' && c != '\t')
+ if (s - buf < (int)sizeof buf - 2)
+ *s++ = c;
+ *s = 0;
+ return s == buf ? (char *)0 : string(buf);
+}
+
+/* gather - read prof.out data from fd */
+static int gather(void) {
+ int i, nfiles, nfuncs, npoints;
+ char *files[64];
+
+ if ((nfiles = getd()) < 0)
+ return 0;
+ assert(nfiles < NELEMS(files));
+ for (i = 0; i < nfiles; i++) {
+ if ((files[i] = getstr()) == 0)
+ return -1;
+ if (!findfile(files[i])) {
+ struct file *new;
+ NEW(new, PERM);
+ new->name = files[i];
+ new->size = new->count = 0;
+ new->counts = 0;
+ new->funcs = 0;
+ new->link = filelist;
+ filelist = new;
+ }
+ }
+ if ((nfuncs = getd()) < 0)
+ return -1;
+ for (i = 0; i < nfuncs; i++) {
+ struct func *q;
+ char *name, *file;
+ int f, x, y, count;
+ if ((name = getstr()) == 0 || (f = getd()) <= 0
+ || (x = getd()) < 0 || (y = getd()) < 0 || (count = getd()) < 0)
+ return -1;
+ q = afunction(name, files[f-1], x, y, count);
+ if ((name = getstr()) == 0 || (file = getstr()) == 0
+ || (x = getd()) < 0 || (y = getd()) < 0)
+ return -1;
+ if (*name != '?')
+ acaller(name, file, x, y, count, q);
+ }
+ if ((npoints = getd()) < 0)
+ return -1;
+ for (i = 0; i < npoints; i++) {
+ int f, x, y, count;
+ if ((f = getd()) < 0 || (x = getd()) < 0 || (y = getd()) < 0
+ || (count = getd()) < 0)
+ return -1;
+ if (f)
+ apoint(i, files[f-1], x, y, count);
+ }
+ return 1;
+}
+
+/* process - read prof.out data from file */
+int process(char *file) {
+ int more;
+
+ if ((fp = fopen(file, "r")) != NULL) {
+ struct file *p;
+ while ((more = gather()) > 0)
+ ;
+ fclose(fp);
+ if (more < 0)
+ return more;
+ for (p = filelist; p; p = p->link)
+ qsort(p->counts, p->count, sizeof *p->counts,
+ (int (*)(const void *, const void *))
+ compare);
+
+ return 1;
+ }
+ return 0;
+}
diff --git a/code/tools/lcc/src/simp.c b/code/tools/lcc/src/simp.c
new file mode 100644
index 0000000..ea26ab6
--- /dev/null
+++ b/code/tools/lcc/src/simp.c
@@ -0,0 +1,587 @@
+#include "c.h"
+#include <float.h>
+
+
+#define foldcnst(TYPE,VAR,OP) \
+ if (l->op == CNST+TYPE && r->op == CNST+TYPE) \
+ return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR)
+#define commute(L,R) \
+ if (generic(R->op) == CNST && generic(L->op) != CNST) \
+ do { Tree t = L; L = R; R = t; } while(0)
+#define xfoldcnst(TYPE,VAR,OP,FUNC)\
+ if (l->op == CNST+TYPE && r->op == CNST+TYPE\
+ && FUNC(l->u.v.VAR,r->u.v.VAR,\
+ ty->u.sym->u.limits.min.VAR,\
+ ty->u.sym->u.limits.max.VAR, needconst)) \
+ return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR)
+#define xcvtcnst(FTYPE,SRC,DST,VAR,EXPR) \
+ if (l->op == CNST+FTYPE) do {\
+ if (!explicitCast\
+ && ((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\
+ warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, DST);\
+ if (needconst\
+ || !((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\
+ return cnsttree(ty, (EXPR)); } while(0)
+#define identity(X,Y,TYPE,VAR,VAL) \
+ if (X->op == CNST+TYPE && X->u.v.VAR == VAL) return Y
+#define zerofield(OP,TYPE,VAR) \
+ if (l->op == FIELD \
+ && r->op == CNST+TYPE && r->u.v.VAR == 0)\
+ return eqtree(OP, bittree(BAND, l->kids[0],\
+ cnsttree(unsignedtype, \
+ (unsigned long)fieldmask(l->u.field)<<fieldright(l->u.field))), r)
+#define cfoldcnst(TYPE,VAR,OP) \
+ if (l->op == CNST+TYPE && r->op == CNST+TYPE) \
+ return cnsttree(inttype, (long)(l->u.v.VAR OP r->u.v.VAR))
+#define foldaddp(L,R,RTYPE,VAR) \
+ if (L->op == CNST+P && R->op == CNST+RTYPE) { \
+ Tree e = tree(CNST+P, ty, NULL, NULL);\
+ e->u.v.p = (char *)L->u.v.p + R->u.v.VAR;\
+ return e; }
+#define ufoldcnst(TYPE,EXP) if (l->op == CNST+TYPE) return EXP
+#define sfoldcnst(OP) \
+ if (l->op == CNST+U && r->op == CNST+I \
+ && r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) \
+ return cnsttree(ty, (unsigned long)(l->u.v.u OP r->u.v.i))
+#define geu(L,R,V) \
+ if (R->op == CNST+U && R->u.v.u == 0) do { \
+ warning("result of unsigned comparison is constant\n"); \
+ return tree(RIGHT, inttype, root(L), cnsttree(inttype, (long)(V))); } while(0)
+#define idempotent(OP) if (l->op == OP) return l->kids[0]
+
+int needconst;
+int explicitCast;
+static int addi(long x, long y, long min, long max, int needconst) {
+ int cond = x == 0 || y == 0
+ || (x < 0 && y < 0 && x >= min - y)
+ || (x < 0 && y > 0)
+ || (x > 0 && y < 0)
+ || (x > 0 && y > 0 && x <= max - y);
+ if (!cond && needconst) {
+ warning("overflow in constant expression\n");
+ cond = 1;
+ }
+ return cond;
+
+
+}
+
+static int addd(double x, double y, double min, double max, int needconst) {
+ int cond = x == 0 || y == 0
+ || (x < 0 && y < 0 && x >= min - y)
+ || (x < 0 && y > 0)
+ || (x > 0 && y < 0)
+ || (x > 0 && y > 0 && x <= max - y);
+ if (!cond && needconst) {
+ warning("overflow in constant expression\n");
+ cond = 1;
+ }
+ return cond;
+
+
+}
+
+static Tree addrtree(Tree e, long n, Type ty) {
+ Symbol p = e->u.sym, q;
+
+ if (p->scope == GLOBAL
+ || p->sclass == STATIC || p->sclass == EXTERN)
+ NEW0(q, PERM);
+ else
+ NEW0(q, FUNC);
+ q->name = stringd(genlabel(1));
+ q->sclass = p->sclass;
+ q->scope = p->scope;
+ assert(isptr(ty) || isarray(ty));
+ q->type = isptr(ty) ? ty->type : ty;
+ q->temporary = p->temporary;
+ q->generated = p->generated;
+ q->addressed = p->addressed;
+ q->computed = 1;
+ q->defined = 1;
+ q->ref = 1;
+ if (p->scope == GLOBAL
+ || p->sclass == STATIC || p->sclass == EXTERN) {
+ if (p->sclass == AUTO)
+ q->sclass = STATIC;
+ (*IR->address)(q, p, n);
+ } else {
+ Code cp;
+ addlocal(p);
+ cp = code(Address);
+ cp->u.addr.sym = q;
+ cp->u.addr.base = p;
+ cp->u.addr.offset = n;
+ }
+ e = tree(e->op, ty, NULL, NULL);
+ e->u.sym = q;
+ return e;
+}
+
+/* div[id] - return 1 if min <= x/y <= max, 0 otherwise */
+static int divi(long x, long y, long min, long max, int needconst) {
+ int cond = y != 0 && !(x == min && y == -1);
+ if (!cond && needconst) {
+ warning("overflow in constant expression\n");
+ cond = 1;
+ }
+ return cond;
+
+
+}
+
+static int divd(double x, double y, double min, double max, int needconst) {
+ int cond;
+
+ if (x < 0) x = -x;
+ if (y < 0) y = -y;
+ cond = y != 0 && !(y < 1 && x > max*y);
+ if (!cond && needconst) {
+ warning("overflow in constant expression\n");
+ cond = 1;
+ }
+ return cond;
+
+}
+
+/* mul[id] - return 1 if min <= x*y <= max, 0 otherwise */
+static int muli(long x, long y, long min, long max, int needconst) {
+ int cond = (x > -1 && x <= 1) || (y > -1 && y <= 1)
+ || (x < 0 && y < 0 && -x <= max/-y)
+ || (x < 0 && y > 0 && x >= min/y)
+ || (x > 0 && y < 0 && y >= min/x)
+ || (x > 0 && y > 0 && x <= max/y);
+ if (!cond && needconst) {
+ warning("overflow in constant expression\n");
+ cond = 1;
+ }
+ return cond;
+
+
+}
+
+static int muld(double x, double y, double min, double max, int needconst) {
+ int cond = (x >= -1 && x <= 1) || (y >= -1 && y <= 1)
+ || (x < 0 && y < 0 && -x <= max/-y)
+ || (x < 0 && y > 0 && x >= min/y)
+ || (x > 0 && y < 0 && y >= min/x)
+ || (x > 0 && y > 0 && x <= max/y);
+ if (!cond && needconst) {
+ warning("overflow in constant expression\n");
+ cond = 1;
+ }
+ return cond;
+
+
+}
+/* sub[id] - return 1 if min <= x-y <= max, 0 otherwise */
+static int subi(long x, long y, long min, long max, int needconst) {
+ return addi(x, -y, min, max, needconst);
+}
+
+static int subd(double x, double y, double min, double max, int needconst) {
+ return addd(x, -y, min, max, needconst);
+}
+Tree constexpr(int tok) {
+ Tree p;
+
+ needconst++;
+ p = expr1(tok);
+ needconst--;
+ return p;
+}
+
+int intexpr(int tok, int n) {
+ Tree p = constexpr(tok);
+
+ needconst++;
+ if (p->op == CNST+I || p->op == CNST+U)
+ n = cast(p, inttype)->u.v.i;
+ else
+ error("integer expression must be constant\n");
+ needconst--;
+ return n;
+}
+Tree simplify(int op, Type ty, Tree l, Tree r) {
+ int n;
+
+ if (optype(op) == 0)
+ op = mkop(op, ty);
+ switch (op) {
+ case ADD+U:
+ foldcnst(U,u,+);
+ commute(r,l);
+ identity(r,l,U,u,0);
+ break;
+ case ADD+I:
+ xfoldcnst(I,i,+,addi);
+ commute(r,l);
+ identity(r,l,I,i,0);
+ break;
+ case CVI+I:
+ xcvtcnst(I,l->u.v.i,ty,i,(long)extend(l->u.v.i,ty));
+ break;
+ case CVU+I:
+ if (l->op == CNST+U) {
+ if (!explicitCast && l->u.v.u > ty->u.sym->u.limits.max.i)
+ warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, ty);
+ if (needconst || !(l->u.v.u > ty->u.sym->u.limits.max.i))
+ return cnsttree(ty, (long)extend(l->u.v.u,ty));
+ }
+ break;
+ case CVP+U:
+ xcvtcnst(P,(unsigned long)l->u.v.p,ty,u,(unsigned long)l->u.v.p);
+ break;
+ case CVU+P:
+ xcvtcnst(U,(void*)l->u.v.u,ty,p,(void*)l->u.v.u);
+ break;
+ case CVP+P:
+ xcvtcnst(P,l->u.v.p,ty,p,l->u.v.p);
+ break;
+ case CVI+U:
+ xcvtcnst(I,l->u.v.i,ty,u,((unsigned long)l->u.v.i)&ones(8*ty->size));
+ break;
+ case CVU+U:
+ xcvtcnst(U,l->u.v.u,ty,u,l->u.v.u&ones(8*ty->size));
+ break;
+
+ case CVI+F:
+ xcvtcnst(I,l->u.v.i,ty,d,(double)l->u.v.i);
+ case CVU+F:
+ xcvtcnst(U,l->u.v.u,ty,d,(double)l->u.v.u);
+ break;
+ case CVF+I:
+ xcvtcnst(F,l->u.v.d,ty,i,(long)l->u.v.d);
+ break;
+ case CVF+F: {
+ float d = 0.0f;
+ if (l->op == CNST+F) {
+ if (l->u.v.d < ty->u.sym->u.limits.min.d)
+ d = ty->u.sym->u.limits.min.d;
+ else if (l->u.v.d > ty->u.sym->u.limits.max.d)
+ d = ty->u.sym->u.limits.max.d;
+ else
+ d = l->u.v.d;
+ }
+ xcvtcnst(F,l->u.v.d,ty,d,(double)d);
+ break;
+ }
+ case BAND+U:
+ foldcnst(U,u,&);
+ commute(r,l);
+ identity(r,l,U,u,ones(8*ty->size));
+ if (r->op == CNST+U && r->u.v.u == 0)
+ return tree(RIGHT, ty, root(l), cnsttree(ty, 0UL));
+ break;
+ case BAND+I:
+ foldcnst(I,i,&);
+ commute(r,l);
+ identity(r,l,I,i,ones(8*ty->size));
+ if (r->op == CNST+I && r->u.v.u == 0)
+ return tree(RIGHT, ty, root(l), cnsttree(ty, 0L));
+ break;
+
+ case MUL+U:
+ commute(l,r);
+ if (l->op == CNST+U && (n = ispow2(l->u.v.u)) != 0)
+ return simplify(LSH, ty, r, cnsttree(inttype, (long)n));
+ foldcnst(U,u,*);
+ identity(r,l,U,u,1);
+ break;
+ case NE+I:
+ cfoldcnst(I,i,!=);
+ commute(r,l);
+ zerofield(NE,I,i);
+ break;
+
+ case EQ+I:
+ cfoldcnst(I,i,==);
+ commute(r,l);
+ zerofield(EQ,I,i);
+ break;
+ case ADD+P:
+ foldaddp(l,r,I,i);
+ foldaddp(l,r,U,u);
+ foldaddp(r,l,I,i);
+ foldaddp(r,l,U,u);
+ commute(r,l);
+ identity(r,retype(l,ty),I,i,0);
+ identity(r,retype(l,ty),U,u,0);
+ if (isaddrop(l->op)
+ && ((r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i
+ && r->u.v.i >= longtype->u.sym->u.limits.min.i)
+ || (r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i)))
+ return addrtree(l, cast(r, longtype)->u.v.i, ty);
+ if (l->op == ADD+P && isaddrop(l->kids[1]->op)
+ && ((r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i
+ && r->u.v.i >= longtype->u.sym->u.limits.min.i)
+ || (r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i)))
+ return simplify(ADD+P, ty, l->kids[0],
+ addrtree(l->kids[1], cast(r, longtype)->u.v.i, ty));
+ if ((l->op == ADD+I || l->op == SUB+I)
+ && l->kids[1]->op == CNST+I && isaddrop(r->op))
+ return simplify(ADD+P, ty, l->kids[0],
+ simplify(generic(l->op)+P, ty, r, l->kids[1]));
+ if (l->op == ADD+P && generic(l->kids[1]->op) == CNST
+ && generic(r->op) == CNST)
+ return simplify(ADD+P, ty, l->kids[0],
+ simplify(ADD, l->kids[1]->type, l->kids[1], r));
+ if (l->op == ADD+I && generic(l->kids[1]->op) == CNST
+ && r->op == ADD+P && generic(r->kids[1]->op) == CNST)
+ return simplify(ADD+P, ty, l->kids[0],
+ simplify(ADD+P, ty, r->kids[0],
+ simplify(ADD, r->kids[1]->type, l->kids[1], r->kids[1])));
+ if (l->op == RIGHT && l->kids[1])
+ return tree(RIGHT, ty, l->kids[0],
+ simplify(ADD+P, ty, l->kids[1], r));
+ else if (l->op == RIGHT && l->kids[0])
+ return tree(RIGHT, ty,
+ simplify(ADD+P, ty, l->kids[0], r), NULL);
+ break;
+
+ case ADD+F:
+ xfoldcnst(F,d,+,addd);
+ commute(r,l);
+ break;
+ case AND+I:
+ op = AND;
+ ufoldcnst(I,l->u.v.i ? cond(r) : l); /* 0&&r => 0, 1&&r => r */
+ break;
+ case OR+I:
+ op = OR;
+ /* 0||r => r, 1||r => 1 */
+ ufoldcnst(I,l->u.v.i ? cnsttree(ty, 1L) : cond(r));
+ break;
+ case BCOM+I:
+ ufoldcnst(I,cnsttree(ty, (long)extend((~l->u.v.i)&ones(8*ty->size), ty)));
+ idempotent(BCOM+U);
+ break;
+ case BCOM+U:
+ ufoldcnst(U,cnsttree(ty, (unsigned long)((~l->u.v.u)&ones(8*ty->size))));
+ idempotent(BCOM+U);
+ break;
+ case BOR+U:
+ foldcnst(U,u,|);
+ commute(r,l);
+ identity(r,l,U,u,0);
+ break;
+ case BOR+I:
+ foldcnst(I,i,|);
+ commute(r,l);
+ identity(r,l,I,i,0);
+ break;
+ case BXOR+U:
+ foldcnst(U,u,^);
+ commute(r,l);
+ identity(r,l,U,u,0);
+ break;
+ case BXOR+I:
+ foldcnst(I,i,^);
+ commute(r,l);
+ identity(r,l,I,i,0);
+ break;
+ case DIV+F:
+ xfoldcnst(F,d,/,divd);
+ break;
+ case DIV+I:
+ identity(r,l,I,i,1);
+ if ((r->op == CNST+I && r->u.v.i == 0)
+ || (l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i
+ && r->op == CNST+I && r->u.v.i == -1))
+ break;
+ xfoldcnst(I,i,/,divi);
+ break;
+ case DIV+U:
+ identity(r,l,U,u,1);
+ if (r->op == CNST+U && r->u.v.u == 0)
+ break;
+ if (r->op == CNST+U && (n = ispow2(r->u.v.u)) != 0)
+ return simplify(RSH, ty, l, cnsttree(inttype, (long)n));
+ foldcnst(U,u,/);
+ break;
+ case EQ+F:
+ cfoldcnst(F,d,==);
+ commute(r,l);
+ break;
+ case EQ+U:
+ cfoldcnst(U,u,==);
+ commute(r,l);
+ zerofield(EQ,U,u);
+ break;
+ case GE+F: cfoldcnst(F,d,>=); break;
+ case GE+I: cfoldcnst(I,i,>=); break;
+ case GE+U:
+ geu(l,r,1); /* l >= 0 => (l,1) */
+ cfoldcnst(U,u,>=);
+ if (l->op == CNST+U && l->u.v.u == 0) /* 0 >= r => r == 0 */
+ return eqtree(EQ, r, l);
+ break;
+ case GT+F: cfoldcnst(F,d, >); break;
+ case GT+I: cfoldcnst(I,i, >); break;
+ case GT+U:
+ geu(r,l,0); /* 0 > r => (r,0) */
+ cfoldcnst(U,u, >);
+ if (r->op == CNST+U && r->u.v.u == 0) /* l > 0 => l != 0 */
+ return eqtree(NE, l, r);
+ break;
+ case LE+F: cfoldcnst(F,d,<=); break;
+ case LE+I: cfoldcnst(I,i,<=); break;
+ case LE+U:
+ geu(r,l,1); /* 0 <= r => (r,1) */
+ cfoldcnst(U,u,<=);
+ if (r->op == CNST+U && r->u.v.u == 0) /* l <= 0 => l == 0 */
+ return eqtree(EQ, l, r);
+ break;
+ case LSH+I:
+ identity(r,l,I,i,0);
+ if (l->op == CNST+I && r->op == CNST+I
+ && r->u.v.i >= 0 && r->u.v.i < 8*l->type->size
+ && muli(l->u.v.i, 1<<r->u.v.i, ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i, needconst))
+ return cnsttree(ty, (long)(l->u.v.i<<r->u.v.i));
+ if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
+ warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
+ break;
+ }
+
+ break;
+ case LSH+U:
+ identity(r,l,I,i,0);
+ sfoldcnst(<<);
+ if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
+ warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
+ break;
+ }
+
+ break;
+
+ case LT+F: cfoldcnst(F,d, <); break;
+ case LT+I: cfoldcnst(I,i, <); break;
+ case LT+U:
+ geu(l,r,0); /* l < 0 => (l,0) */
+ cfoldcnst(U,u, <);
+ if (l->op == CNST+U && l->u.v.u == 0) /* 0 < r => r != 0 */
+ return eqtree(NE, r, l);
+ break;
+ case MOD+I:
+ if (r->op == CNST+I && r->u.v.i == 1) /* l%1 => (l,0) */
+ return tree(RIGHT, ty, root(l), cnsttree(ty, 0L));
+ if ((r->op == CNST+I && r->u.v.i == 0)
+ || (l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i
+ && r->op == CNST+I && r->u.v.i == -1))
+ break;
+ xfoldcnst(I,i,%,divi);
+ break;
+ case MOD+U:
+ if (r->op == CNST+U && ispow2(r->u.v.u)) /* l%2^n => l&(2^n-1) */
+ return bittree(BAND, l, cnsttree(ty, r->u.v.u - 1));
+ if (r->op == CNST+U && r->u.v.u == 0)
+ break;
+ foldcnst(U,u,%);
+ break;
+ case MUL+F:
+ xfoldcnst(F,d,*,muld);
+ commute(l,r);
+ break;
+ case MUL+I:
+ commute(l,r);
+ xfoldcnst(I,i,*,muli);
+ if (l->op == CNST+I && r->op == ADD+I && r->kids[1]->op == CNST+I)
+ /* c1*(x + c2) => c1*x + c1*c2 */
+ return simplify(ADD, ty, simplify(MUL, ty, l, r->kids[0]),
+ simplify(MUL, ty, l, r->kids[1]));
+ if (l->op == CNST+I && r->op == SUB+I && r->kids[1]->op == CNST+I)
+ /* c1*(x - c2) => c1*x - c1*c2 */
+ return simplify(SUB, ty, simplify(MUL, ty, l, r->kids[0]),
+ simplify(MUL, ty, l, r->kids[1]));
+ if (l->op == CNST+I && l->u.v.i > 0 && (n = ispow2(l->u.v.i)) != 0)
+ /* 2^n * r => r<<n */
+ return simplify(LSH, ty, r, cnsttree(inttype, (long)n));
+ identity(r,l,I,i,1);
+ break;
+ case NE+F:
+ cfoldcnst(F,d,!=);
+ commute(r,l);
+ break;
+ case NE+U:
+ cfoldcnst(U,u,!=);
+ commute(r,l);
+ zerofield(NE,U,u);
+ break;
+ case NEG+F:
+ ufoldcnst(F,cnsttree(ty, -l->u.v.d));
+ idempotent(NEG+F);
+ break;
+ case NEG+I:
+ if (l->op == CNST+I) {
+ if (needconst && l->u.v.i == ty->u.sym->u.limits.min.i)
+ warning("overflow in constant expression\n");
+ if (needconst || l->u.v.i != ty->u.sym->u.limits.min.i)
+ return cnsttree(ty, -l->u.v.i);
+ }
+ idempotent(NEG+I);
+ break;
+ case NOT+I:
+ op = NOT;
+ ufoldcnst(I,cnsttree(ty, !l->u.v.i));
+ break;
+ case RSH+I:
+ identity(r,l,I,i,0);
+ if (l->op == CNST+I && r->op == CNST+I
+ && r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) {
+ long n = l->u.v.i>>r->u.v.i;
+ if (l->u.v.i < 0)
+ n |= ~0UL<<(8*l->type->size - r->u.v.i);
+ return cnsttree(ty, n);
+ }
+ if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
+ warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
+ break;
+ }
+
+ break;
+ case RSH+U:
+ identity(r,l,I,i,0);
+ sfoldcnst(>>);
+ if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
+ warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
+ break;
+ }
+
+ break;
+ case SUB+F:
+ xfoldcnst(F,d,-,subd);
+ break;
+ case SUB+I:
+ xfoldcnst(I,i,-,subi);
+ identity(r,l,I,i,0);
+ break;
+ case SUB+U:
+ foldcnst(U,u,-);
+ identity(r,l,U,u,0);
+ break;
+ case SUB+P:
+ if (l->op == CNST+P && r->op == CNST+P)
+ return cnsttree(ty, (long)((char *)l->u.v.p - (char *)r->u.v.p));
+ if (r->op == CNST+I || r->op == CNST+U)
+ return simplify(ADD, ty, l,
+ cnsttree(inttype, r->op == CNST+I ? -r->u.v.i : -(long)r->u.v.u));
+ if (isaddrop(l->op) && r->op == ADD+I && r->kids[1]->op == CNST+I)
+ /* l - (x + c) => l-c - x */
+ return simplify(SUB, ty,
+ simplify(SUB, ty, l, r->kids[1]), r->kids[0]);
+ break;
+ default:assert(0);
+ }
+ return tree(op, ty, l, r);
+}
+/* ispow2 - if u > 1 && u == 2^n, return n, otherwise return 0 */
+int ispow2(unsigned long u) {
+ int n;
+
+ if (u > 1 && (u&(u-1)) == 0)
+ for (n = 0; u; u >>= 1, n++)
+ if (u&1)
+ return n;
+ return 0;
+}
+
diff --git a/code/tools/lcc/src/stmt.c b/code/tools/lcc/src/stmt.c
new file mode 100644
index 0000000..9c3bdbe
--- /dev/null
+++ b/code/tools/lcc/src/stmt.c
@@ -0,0 +1,696 @@
+#include "c.h"
+
+
+#define SWSIZE 512
+
+#define den(i,j) ((j-buckets[i]+1.0)/(v[j]-v[buckets[i]]+1))
+
+struct code codehead = { Start };
+Code codelist = &codehead;
+float density = 0.5;
+Table stmtlabs;
+
+static int foldcond(Tree e1, Tree e2);
+static void caselabel(Swtch, long, int);
+static void cmp(int, Symbol, long, int);
+static Tree conditional(int);
+static void dostmt(int, Swtch, int);
+static int equal(Symbol, Symbol);
+static void forstmt(int, Swtch, int);
+static void ifstmt(int, int, Swtch, int);
+static Symbol localaddr(Tree);
+static void stmtlabel(void);
+static void swstmt(int, int, int);
+static void whilestmt(int, Swtch, int);
+Code code(int kind) {
+ Code cp;
+
+ if (!reachable(kind))
+ warning("unreachable code\n");
+
+ NEW(cp, FUNC);
+ cp->kind = kind;
+ cp->prev = codelist;
+ cp->next = NULL;
+ codelist->next = cp;
+ codelist = cp;
+ return cp;
+}
+int reachable(int kind) {
+
+ if (kind > Start) {
+ Code cp;
+ for (cp = codelist; cp->kind < Label; )
+ cp = cp->prev;
+ if (cp->kind == Jump || cp->kind == Switch)
+ return 0;
+ }
+ return 1;
+}
+void addlocal(Symbol p) {
+ if (!p->defined) {
+ code(Local)->u.var = p;
+ p->defined = 1;
+ p->scope = level;
+ }
+}
+void definept(Coordinate *p) {
+ Code cp = code(Defpoint);
+
+ cp->u.point.src = p ? *p : src;
+ cp->u.point.point = npoints;
+ if (ncalled > 0) {
+ int n = findcount(cp->u.point.src.file,
+ cp->u.point.src.x, cp->u.point.src.y);
+ if (n > 0)
+ refinc = (float)n/ncalled;
+ }
+ if (glevel > 2) locus(identifiers, &cp->u.point.src);
+ if (events.points && reachable(Gen))
+ {
+ Tree e = NULL;
+ apply(events.points, &cp->u.point.src, &e);
+ if (e)
+ listnodes(e, 0, 0);
+ }
+}
+void statement(int loop, Swtch swp, int lev) {
+ float ref = refinc;
+
+ if (Aflag >= 2 && lev == 15)
+ warning("more than 15 levels of nested statements\n");
+ switch (t) {
+ case IF: ifstmt(genlabel(2), loop, swp, lev + 1);
+ break;
+ case WHILE: whilestmt(genlabel(3), swp, lev + 1); break;
+ case DO: dostmt(genlabel(3), swp, lev + 1); expect(';');
+ break;
+
+ case FOR: forstmt(genlabel(4), swp, lev + 1);
+ break;
+ case BREAK: walk(NULL, 0, 0);
+ definept(NULL);
+ if (swp && swp->lab > loop)
+ branch(swp->lab + 1);
+ else if (loop)
+ branch(loop + 2);
+ else
+ error("illegal break statement\n");
+ t = gettok(); expect(';');
+ break;
+
+ case CONTINUE: walk(NULL, 0, 0);
+ definept(NULL);
+ if (loop)
+ branch(loop + 1);
+ else
+ error("illegal continue statement\n");
+ t = gettok(); expect(';');
+ break;
+
+ case SWITCH: swstmt(loop, genlabel(2), lev + 1);
+ break;
+ case CASE: {
+ int lab = genlabel(1);
+ if (swp == NULL)
+ error("illegal case label\n");
+ definelab(lab);
+ while (t == CASE) {
+ static char stop[] = { IF, ID, 0 };
+ Tree p;
+ t = gettok();
+ p = constexpr(0);
+ if (generic(p->op) == CNST && isint(p->type)) {
+ if (swp) {
+ needconst++;
+ p = cast(p, swp->sym->type);
+ if (p->type->op == UNSIGNED)
+ p->u.v.i = extend(p->u.v.u, p->type);
+ needconst--;
+ caselabel(swp, p->u.v.i, lab);
+ }
+ } else
+ error("case label must be a constant integer expression\n");
+
+ test(':', stop);
+ }
+ statement(loop, swp, lev);
+ } break;
+ case DEFAULT: if (swp == NULL)
+ error("illegal default label\n");
+ else if (swp->deflab)
+ error("extra default label\n");
+ else {
+ swp->deflab = findlabel(swp->lab);
+ definelab(swp->deflab->u.l.label);
+ }
+ t = gettok();
+ expect(':');
+ statement(loop, swp, lev); break;
+ case RETURN: {
+ Type rty = freturn(cfunc->type);
+ t = gettok();
+ definept(NULL);
+ if (t != ';')
+ if (rty == voidtype) {
+ error("extraneous return value\n");
+ expr(0);
+ retcode(NULL);
+ } else
+ retcode(expr(0));
+ else {
+ if (rty != voidtype)
+ warning("missing return value\n");
+ retcode(NULL);
+ }
+ branch(cfunc->u.f.label);
+ } expect(';');
+ break;
+
+ case '{': compound(loop, swp, lev + 1); break;
+ case ';': definept(NULL); t = gettok(); break;
+ case GOTO: walk(NULL, 0, 0);
+ definept(NULL);
+ t = gettok();
+ if (t == ID) {
+ Symbol p = lookup(token, stmtlabs);
+ if (p == NULL) {
+ p = install(token, &stmtlabs, 0, FUNC);
+ p->scope = LABELS;
+ p->u.l.label = genlabel(1);
+ p->src = src;
+ }
+ use(p, src);
+ branch(p->u.l.label);
+ t = gettok();
+ } else
+ error("missing label in goto\n"); expect(';');
+ break;
+
+ case ID: if (getchr() == ':') {
+ stmtlabel();
+ statement(loop, swp, lev);
+ break;
+ }
+ default: definept(NULL);
+ if (kind[t] != ID) {
+ error("unrecognized statement\n");
+ t = gettok();
+ } else {
+ Tree e = expr0(0);
+ listnodes(e, 0, 0);
+ if (nodecount == 0 || nodecount > 200)
+ walk(NULL, 0, 0);
+ else if (glevel) walk(NULL, 0, 0);
+ deallocate(STMT);
+ } expect(';');
+ break;
+
+ }
+ if (kind[t] != IF && kind[t] != ID
+ && t != '}' && t != EOI) {
+ static char stop[] = { IF, ID, '}', 0 };
+ error("illegal statement termination\n");
+ skipto(0, stop);
+ }
+ refinc = ref;
+}
+
+static void ifstmt(int lab, int loop, Swtch swp, int lev) {
+ t = gettok();
+ expect('(');
+ definept(NULL);
+ walk(conditional(')'), 0, lab);
+ refinc /= 2.0;
+ statement(loop, swp, lev);
+ if (t == ELSE) {
+ branch(lab + 1);
+ t = gettok();
+ definelab(lab);
+ statement(loop, swp, lev);
+ if (findlabel(lab + 1)->ref)
+ definelab(lab + 1);
+ } else
+ definelab(lab);
+}
+static Tree conditional(int tok) {
+ Tree p = expr(tok);
+
+ if (Aflag > 1 && isfunc(p->type))
+ warning("%s used in a conditional expression\n",
+ funcname(p));
+ return cond(p);
+}
+static void stmtlabel(void) {
+ Symbol p = lookup(token, stmtlabs);
+
+ if (p == NULL) {
+ p = install(token, &stmtlabs, 0, FUNC);
+ p->scope = LABELS;
+ p->u.l.label = genlabel(1);
+ p->src = src;
+ }
+ if (p->defined)
+ error("redefinition of label `%s' previously defined at %w\n", p->name, &p->src);
+
+ p->defined = 1;
+ definelab(p->u.l.label);
+ t = gettok();
+ expect(':');
+}
+static void forstmt(int lab, Swtch swp, int lev) {
+ int once = 0;
+ Tree e1 = NULL, e2 = NULL, e3 = NULL;
+ Coordinate pt2, pt3;
+
+ t = gettok();
+ expect('(');
+ definept(NULL);
+ if (kind[t] == ID)
+ e1 = texpr(expr0, ';', FUNC);
+ else
+ expect(';');
+ walk(e1, 0, 0);
+ pt2 = src;
+ refinc *= 10.0;
+ if (kind[t] == ID)
+ e2 = texpr(conditional, ';', FUNC);
+ else
+ expect(';');
+ pt3 = src;
+ if (kind[t] == ID)
+ e3 = texpr(expr0, ')', FUNC);
+ else {
+ static char stop[] = { IF, ID, '}', 0 };
+ test(')', stop);
+ }
+ if (e2) {
+ once = foldcond(e1, e2);
+ if (!once)
+ branch(lab + 3);
+ }
+ definelab(lab);
+ statement(lab, swp, lev);
+ definelab(lab + 1);
+ definept(&pt3);
+ if (e3)
+ walk(e3, 0, 0);
+ if (e2) {
+ if (!once)
+ definelab(lab + 3);
+ definept(&pt2);
+ walk(e2, lab, 0);
+ } else {
+ definept(&pt2);
+ branch(lab);
+ }
+ if (findlabel(lab + 2)->ref)
+ definelab(lab + 2);
+}
+static void swstmt(int loop, int lab, int lev) {
+ Tree e;
+ struct swtch sw;
+ Code head, tail;
+
+ t = gettok();
+ expect('(');
+ definept(NULL);
+ e = expr(')');
+ if (!isint(e->type)) {
+ error("illegal type `%t' in switch expression\n",
+ e->type);
+ e = retype(e, inttype);
+ }
+ e = cast(e, promote(e->type));
+ if (generic(e->op) == INDIR && isaddrop(e->kids[0]->op)
+ && e->kids[0]->u.sym->type == e->type
+ && !isvolatile(e->kids[0]->u.sym->type)) {
+ sw.sym = e->kids[0]->u.sym;
+ walk(NULL, 0, 0);
+ } else {
+ sw.sym = genident(REGISTER, e->type, level);
+ addlocal(sw.sym);
+ walk(asgn(sw.sym, e), 0, 0);
+ }
+ head = code(Switch);
+ sw.lab = lab;
+ sw.deflab = NULL;
+ sw.ncases = 0;
+ sw.size = SWSIZE;
+ sw.values = newarray(SWSIZE, sizeof *sw.values, FUNC);
+ sw.labels = newarray(SWSIZE, sizeof *sw.labels, FUNC);
+ refinc /= 10.0;
+ statement(loop, &sw, lev);
+ if (sw.deflab == NULL) {
+ sw.deflab = findlabel(lab);
+ definelab(lab);
+ if (sw.ncases == 0)
+ warning("switch statement with no cases\n");
+ }
+ if (findlabel(lab + 1)->ref)
+ definelab(lab + 1);
+ tail = codelist;
+ codelist = head->prev;
+ codelist->next = head->prev = NULL;
+ if (sw.ncases > 0)
+ swgen(&sw);
+ branch(lab);
+ head->next->prev = codelist;
+ codelist->next = head->next;
+ codelist = tail;
+}
+static void caselabel(Swtch swp, long val, int lab) {
+ int k;
+
+ if (swp->ncases >= swp->size)
+ {
+ long *vals = swp->values;
+ Symbol *labs = swp->labels;
+ swp->size *= 2;
+ swp->values = newarray(swp->size, sizeof *swp->values, FUNC);
+ swp->labels = newarray(swp->size, sizeof *swp->labels, FUNC);
+ for (k = 0; k < swp->ncases; k++) {
+ swp->values[k] = vals[k];
+ swp->labels[k] = labs[k];
+ }
+ }
+ k = swp->ncases;
+ for ( ; k > 0 && swp->values[k-1] >= val; k--) {
+ swp->values[k] = swp->values[k-1];
+ swp->labels[k] = swp->labels[k-1];
+ }
+ if (k < swp->ncases && swp->values[k] == val)
+ error("duplicate case label `%d'\n", val);
+ swp->values[k] = val;
+ swp->labels[k] = findlabel(lab);
+ ++swp->ncases;
+ if (Aflag >= 2 && swp->ncases == 258)
+ warning("more than 257 cases in a switch\n");
+}
+void swgen(Swtch swp) {
+ int *buckets, k, n;
+ long *v = swp->values;
+
+ buckets = newarray(swp->ncases + 1,
+ sizeof *buckets, FUNC);
+ for (n = k = 0; k < swp->ncases; k++, n++) {
+ buckets[n] = k;
+ while (n > 0 && den(n-1, k) >= density)
+ n--;
+ }
+ buckets[n] = swp->ncases;
+ swcode(swp, buckets, 0, n - 1);
+}
+void swcode(Swtch swp, int b[], int lb, int ub) {
+ int hilab, lolab, l, u, k = (lb + ub)/2;
+ long *v = swp->values;
+
+ if (k > lb && k < ub) {
+ lolab = genlabel(1);
+ hilab = genlabel(1);
+ } else if (k > lb) {
+ lolab = genlabel(1);
+ hilab = swp->deflab->u.l.label;
+ } else if (k < ub) {
+ lolab = swp->deflab->u.l.label;
+ hilab = genlabel(1);
+ } else
+ lolab = hilab = swp->deflab->u.l.label;
+ l = b[k];
+ u = b[k+1] - 1;
+ if (u - l + 1 <= 3)
+ {
+ int i;
+ for (i = l; i <= u; i++)
+ cmp(EQ, swp->sym, v[i], swp->labels[i]->u.l.label);
+ if (k > lb && k < ub)
+ cmp(GT, swp->sym, v[u], hilab);
+ else if (k > lb)
+ cmp(GT, swp->sym, v[u], hilab);
+ else if (k < ub)
+ cmp(LT, swp->sym, v[l], lolab);
+ else
+ assert(lolab == hilab),
+ branch(lolab);
+ walk(NULL, 0, 0);
+ }
+ else {
+ Tree e;
+ Type ty = signedint(swp->sym->type);
+ Symbol table = genident(STATIC,
+ array(voidptype, u - l + 1, 0), GLOBAL);
+ (*IR->defsymbol)(table);
+ if (!isunsigned(swp->sym->type) || v[l] != 0)
+ cmp(LT, swp->sym, v[l], lolab);
+ cmp(GT, swp->sym, v[u], hilab);
+ e = (*optree['-'])(SUB, cast(idtree(swp->sym), ty), cnsttree(ty, v[l]));
+ if (e->type->size < unsignedptr->size)
+ e = cast(e, unsignedlong);
+ walk(tree(JUMP, voidtype,
+ rvalue((*optree['+'])(ADD, pointer(idtree(table)), e)), NULL),
+ 0, 0);
+ code(Switch);
+ codelist->u.swtch.table = table;
+ codelist->u.swtch.sym = swp->sym;
+ codelist->u.swtch.deflab = swp->deflab;
+ codelist->u.swtch.size = u - l + 1;
+ codelist->u.swtch.values = &v[l];
+ codelist->u.swtch.labels = &swp->labels[l];
+ if (v[u] - v[l] + 1 >= 10000)
+ warning("switch generates a huge table\n");
+ }
+ if (k > lb) {
+ assert(lolab != swp->deflab->u.l.label);
+ definelab(lolab);
+ swcode(swp, b, lb, k - 1);
+ }
+ if (k < ub) {
+ assert(hilab != swp->deflab->u.l.label);
+ definelab(hilab);
+ swcode(swp, b, k + 1, ub);
+ }
+}
+static void cmp(int op, Symbol p, long n, int lab) {
+ Type ty = signedint(p->type);
+
+ listnodes(eqtree(op,
+ cast(idtree(p), ty),
+ cnsttree(ty, n)),
+ lab, 0);
+}
+void retcode(Tree p) {
+ Type ty;
+
+ if (p == NULL) {
+ if (events.returns)
+ apply(events.returns, cfunc, NULL);
+ return;
+ }
+ p = pointer(p);
+ ty = assign(freturn(cfunc->type), p);
+ if (ty == NULL) {
+ error("illegal return type; found `%t' expected `%t'\n",
+ p->type, freturn(cfunc->type));
+ return;
+ }
+ p = cast(p, ty);
+ if (retv)
+ {
+ if (iscallb(p))
+ p = tree(RIGHT, p->type,
+ tree(CALL+B, p->type,
+ p->kids[0]->kids[0], idtree(retv)),
+ rvalue(idtree(retv)));
+ else
+ p = asgntree(ASGN, rvalue(idtree(retv)), p);
+ walk(p, 0, 0);
+ if (events.returns)
+ apply(events.returns, cfunc, rvalue(idtree(retv)));
+ return;
+ }
+ if (events.returns)
+ {
+ Symbol t1 = genident(AUTO, p->type, level);
+ addlocal(t1);
+ walk(asgn(t1, p), 0, 0);
+ apply(events.returns, cfunc, idtree(t1));
+ p = idtree(t1);
+ }
+ if (!isfloat(p->type))
+ p = cast(p, promote(p->type));
+ if (isptr(p->type))
+ {
+ Symbol q = localaddr(p);
+ if (q && (q->computed || q->generated))
+ warning("pointer to a %s is an illegal return value\n",
+ q->scope == PARAM ? "parameter" : "local");
+ else if (q)
+ warning("pointer to %s `%s' is an illegal return value\n",
+ q->scope == PARAM ? "parameter" : "local", q->name);
+ }
+ walk(tree(mkop(RET,p->type), p->type, p, NULL), 0, 0);
+}
+void definelab(int lab) {
+ Code cp;
+ Symbol p = findlabel(lab);
+
+ assert(lab);
+ walk(NULL, 0, 0);
+ code(Label)->u.forest = newnode(LABEL+V, NULL, NULL, p);
+ for (cp = codelist->prev; cp->kind <= Label; )
+ cp = cp->prev;
+ while ( cp->kind == Jump
+ && cp->u.forest->kids[0]
+ && specific(cp->u.forest->kids[0]->op) == ADDRG+P
+ && cp->u.forest->kids[0]->syms[0] == p) {
+ assert(cp->u.forest->kids[0]->syms[0]->u.l.label == lab);
+ p->ref--;
+ assert(cp->next);
+ assert(cp->prev);
+ cp->prev->next = cp->next;
+ cp->next->prev = cp->prev;
+ cp = cp->prev;
+ while (cp->kind <= Label)
+ cp = cp->prev;
+ }
+}
+Node jump(int lab) {
+ Symbol p = findlabel(lab);
+
+ p->ref++;
+ return newnode(JUMP+V, newnode(ADDRG+ttob(voidptype), NULL, NULL, p),
+ NULL, NULL);
+}
+void branch(int lab) {
+ Code cp;
+ Symbol p = findlabel(lab);
+
+ assert(lab);
+ walk(NULL, 0, 0);
+ code(Label)->u.forest = jump(lab);
+ for (cp = codelist->prev; cp->kind < Label; )
+ cp = cp->prev;
+ while ( cp->kind == Label
+ && cp->u.forest->op == LABEL+V
+ && !equal(cp->u.forest->syms[0], p)) {
+ equatelab(cp->u.forest->syms[0], p);
+ assert(cp->next);
+ assert(cp->prev);
+ cp->prev->next = cp->next;
+ cp->next->prev = cp->prev;
+ cp = cp->prev;
+ while (cp->kind < Label)
+ cp = cp->prev;
+ }
+ if (cp->kind == Jump || cp->kind == Switch) {
+ p->ref--;
+ codelist->prev->next = NULL;
+ codelist = codelist->prev;
+ } else {
+ codelist->kind = Jump;
+ if (cp->kind == Label
+ && cp->u.forest->op == LABEL+V
+ && equal(cp->u.forest->syms[0], p))
+ warning("source code specifies an infinite loop");
+ }
+}
+void equatelab(Symbol old, Symbol new) {
+ assert(old->u.l.equatedto == NULL);
+ old->u.l.equatedto = new;
+ new->ref++;
+}
+static int equal(Symbol lprime, Symbol dst) {
+ assert(dst && lprime);
+ for ( ; dst; dst = dst->u.l.equatedto)
+ if (lprime == dst)
+ return 1;
+ return 0;
+}
+/* dostmt - do statement while ( expression ) */
+static void dostmt(int lab, Swtch swp, int lev) {
+ refinc *= 10.0;
+ t = gettok();
+ definelab(lab);
+ statement(lab, swp, lev);
+ definelab(lab + 1);
+ expect(WHILE);
+ expect('(');
+ definept(NULL);
+ walk(conditional(')'), lab, 0);
+ if (findlabel(lab + 2)->ref)
+ definelab(lab + 2);
+}
+
+/* foldcond - check if initial test in for(e1;e2;e3) S is necessary */
+static int foldcond(Tree e1, Tree e2) {
+ int op = generic(e2->op);
+ Symbol v;
+
+ if (e1 == 0 || e2 == 0)
+ return 0;
+ if (generic(e1->op) == ASGN && isaddrop(e1->kids[0]->op)
+ && generic(e1->kids[1]->op) == CNST) {
+ v = e1->kids[0]->u.sym;
+ e1 = e1->kids[1];
+ } else
+ return 0;
+ if ((op==LE || op==LT || op==EQ || op==NE || op==GT || op==GE)
+ && generic(e2->kids[0]->op) == INDIR
+ && e2->kids[0]->kids[0]->u.sym == v
+ && e2->kids[1]->op == e1->op) {
+ e1 = simplify(op, e2->type, e1, e2->kids[1]);
+ if (e1->op == CNST+I)
+ return e1->u.v.i;
+ }
+ return 0;
+}
+
+/* localaddr - returns q if p yields the address of local/parameter q; otherwise returns 0 */
+static Symbol localaddr(Tree p) {
+ if (p == NULL)
+ return NULL;
+ switch (generic(p->op)) {
+ case INDIR: case CALL: case ARG:
+ return NULL;
+ case ADDRL: case ADDRF:
+ return p->u.sym;
+ case RIGHT: case ASGN:
+ if (p->kids[1])
+ return localaddr(p->kids[1]);
+ return localaddr(p->kids[0]);
+ case COND: {
+ Symbol q;
+ assert(p->kids[1] && p->kids[1]->op == RIGHT);
+ if ((q = localaddr(p->kids[1]->kids[0])) != NULL)
+ return q;
+ return localaddr(p->kids[1]->kids[1]);
+ }
+ default: {
+ Symbol q;
+ if (p->kids[0] && (q = localaddr(p->kids[0])) != NULL)
+ return q;
+ return localaddr(p->kids[1]);
+ }
+ }
+}
+
+/* whilestmt - while ( expression ) statement */
+static void whilestmt(int lab, Swtch swp, int lev) {
+ Coordinate pt;
+ Tree e;
+
+ refinc *= 10.0;
+ t = gettok();
+ expect('(');
+ walk(NULL, 0, 0);
+ pt = src;
+ e = texpr(conditional, ')', FUNC);
+ branch(lab + 1);
+ definelab(lab);
+ statement(lab, swp, lev);
+ definelab(lab + 1);
+ definept(&pt);
+ walk(e, lab, 0);
+ if (findlabel(lab + 2)->ref)
+ definelab(lab + 2);
+}
diff --git a/code/tools/lcc/src/string.c b/code/tools/lcc/src/string.c
new file mode 100644
index 0000000..73cfc85
--- /dev/null
+++ b/code/tools/lcc/src/string.c
@@ -0,0 +1,122 @@
+#include "c.h"
+
+
+static struct string {
+ char *str;
+ int len;
+ struct string *link;
+} *buckets[1024];
+static int scatter[] = { /* map characters to random values */
+ 2078917053, 143302914, 1027100827, 1953210302, 755253631,
+ 2002600785, 1405390230, 45248011, 1099951567, 433832350,
+ 2018585307, 438263339, 813528929, 1703199216, 618906479,
+ 573714703, 766270699, 275680090, 1510320440, 1583583926,
+ 1723401032, 1965443329, 1098183682, 1636505764, 980071615,
+ 1011597961, 643279273, 1315461275, 157584038, 1069844923,
+ 471560540, 89017443, 1213147837, 1498661368, 2042227746,
+ 1968401469, 1353778505, 1300134328, 2013649480, 306246424,
+ 1733966678, 1884751139, 744509763, 400011959, 1440466707,
+ 1363416242, 973726663, 59253759, 1639096332, 336563455,
+ 1642837685, 1215013716, 154523136, 593537720, 704035832,
+ 1134594751, 1605135681, 1347315106, 302572379, 1762719719,
+ 269676381, 774132919, 1851737163, 1482824219, 125310639,
+ 1746481261, 1303742040, 1479089144, 899131941, 1169907872,
+ 1785335569, 485614972, 907175364, 382361684, 885626931,
+ 200158423, 1745777927, 1859353594, 259412182, 1237390611,
+ 48433401, 1902249868, 304920680, 202956538, 348303940,
+ 1008956512, 1337551289, 1953439621, 208787970, 1640123668,
+ 1568675693, 478464352, 266772940, 1272929208, 1961288571,
+ 392083579, 871926821, 1117546963, 1871172724, 1771058762,
+ 139971187, 1509024645, 109190086, 1047146551, 1891386329,
+ 994817018, 1247304975, 1489680608, 706686964, 1506717157,
+ 579587572, 755120366, 1261483377, 884508252, 958076904,
+ 1609787317, 1893464764, 148144545, 1415743291, 2102252735,
+ 1788268214, 836935336, 433233439, 2055041154, 2109864544,
+ 247038362, 299641085, 834307717, 1364585325, 23330161,
+ 457882831, 1504556512, 1532354806, 567072918, 404219416,
+ 1276257488, 1561889936, 1651524391, 618454448, 121093252,
+ 1010757900, 1198042020, 876213618, 124757630, 2082550272,
+ 1834290522, 1734544947, 1828531389, 1982435068, 1002804590,
+ 1783300476, 1623219634, 1839739926, 69050267, 1530777140,
+ 1802120822, 316088629, 1830418225, 488944891, 1680673954,
+ 1853748387, 946827723, 1037746818, 1238619545, 1513900641,
+ 1441966234, 367393385, 928306929, 946006977, 985847834,
+ 1049400181, 1956764878, 36406206, 1925613800, 2081522508,
+ 2118956479, 1612420674, 1668583807, 1800004220, 1447372094,
+ 523904750, 1435821048, 923108080, 216161028, 1504871315,
+ 306401572, 2018281851, 1820959944, 2136819798, 359743094,
+ 1354150250, 1843084537, 1306570817, 244413420, 934220434,
+ 672987810, 1686379655, 1301613820, 1601294739, 484902984,
+ 139978006, 503211273, 294184214, 176384212, 281341425,
+ 228223074, 147857043, 1893762099, 1896806882, 1947861263,
+ 1193650546, 273227984, 1236198663, 2116758626, 489389012,
+ 593586330, 275676551, 360187215, 267062626, 265012701,
+ 719930310, 1621212876, 2108097238, 2026501127, 1865626297,
+ 894834024, 552005290, 1404522304, 48964196, 5816381,
+ 1889425288, 188942202, 509027654, 36125855, 365326415,
+ 790369079, 264348929, 513183458, 536647531, 13672163,
+ 313561074, 1730298077, 286900147, 1549759737, 1699573055,
+ 776289160, 2143346068, 1975249606, 1136476375, 262925046,
+ 92778659, 1856406685, 1884137923, 53392249, 1735424165,
+ 1602280572
+};
+char *string(const char *str) {
+ const char *s;
+
+ for (s = str; *s; s++)
+ ;
+ return stringn(str, s - str);
+}
+char *stringd(long n) {
+ char str[25], *s = str + sizeof (str);
+ unsigned long m;
+
+ if (n == LONG_MIN)
+ m = (unsigned long)LONG_MAX + 1;
+ else if (n < 0)
+ m = -n;
+ else
+ m = n;
+ do
+ *--s = m%10 + '0';
+ while ((m /= 10) != 0);
+ if (n < 0)
+ *--s = '-';
+ return stringn(s, str + sizeof (str) - s);
+}
+char *stringn(const char *str, int len) {
+ int i;
+ unsigned int h;
+ const char *end;
+ struct string *p;
+
+ assert(str);
+ for (h = 0, i = len, end = str; i > 0; i--)
+ h = (h<<1) + scatter[*(unsigned char *)end++];
+ h &= NELEMS(buckets)-1;
+ for (p = buckets[h]; p; p = p->link)
+ if (len == p->len) {
+ const char *s1 = str;
+ char *s2 = p->str;
+ do {
+ if (s1 == end)
+ return p->str;
+ } while (*s1++ == *s2++);
+ }
+ {
+ static char *next, *strlimit;
+ if (len + 1 >= strlimit - next) {
+ int n = len + 4*1024;
+ next = allocate(n, PERM);
+ strlimit = next + n;
+ }
+ NEW(p, PERM);
+ p->len = len;
+ for (p->str = next; str < end; )
+ *next++ = *str++;
+ *next++ = 0;
+ p->link = buckets[h];
+ buckets[h] = p;
+ return p->str;
+ }
+}
diff --git a/code/tools/lcc/src/sym.c b/code/tools/lcc/src/sym.c
new file mode 100644
index 0000000..2a1cfeb
--- /dev/null
+++ b/code/tools/lcc/src/sym.c
@@ -0,0 +1,314 @@
+#include "c.h"
+#include <stdio.h>
+
+
+#define equalp(x) v.x == p->sym.u.c.v.x
+
+struct table {
+ int level;
+ Table previous;
+ struct entry {
+ struct symbol sym;
+ struct entry *link;
+ } *buckets[256];
+ Symbol all;
+};
+#define HASHSIZE NELEMS(((Table)0)->buckets)
+static struct table
+ cns = { CONSTANTS },
+ ext = { GLOBAL },
+ ids = { GLOBAL },
+ tys = { GLOBAL };
+Table constants = &cns;
+Table externals = &ext;
+Table identifiers = &ids;
+Table globals = &ids;
+Table types = &tys;
+Table labels;
+int level = GLOBAL;
+static int tempid;
+List loci, symbols;
+
+Table table(Table tp, int level) {
+ Table new;
+
+ NEW0(new, FUNC);
+ new->previous = tp;
+ new->level = level;
+ if (tp)
+ new->all = tp->all;
+ return new;
+}
+void foreach(Table tp, int lev, void (*apply)(Symbol, void *), void *cl) {
+ assert(tp);
+ while (tp && tp->level > lev)
+ tp = tp->previous;
+ if (tp && tp->level == lev) {
+ Symbol p;
+ Coordinate sav;
+ sav = src;
+ for (p = tp->all; p && p->scope == lev; p = p->up) {
+ src = p->src;
+ (*apply)(p, cl);
+ }
+ src = sav;
+ }
+}
+void enterscope(void) {
+ if (++level == LOCAL)
+ tempid = 0;
+}
+void exitscope(void) {
+ rmtypes(level);
+ if (types->level == level)
+ types = types->previous;
+ if (identifiers->level == level) {
+ if (Aflag >= 2) {
+ int n = 0;
+ Symbol p;
+ for (p = identifiers->all; p && p->scope == level; p = p->up)
+ if (++n > 127) {
+ warning("more than 127 identifiers declared in a block\n");
+ break;
+ }
+ }
+ identifiers = identifiers->previous;
+ }
+ assert(level >= GLOBAL);
+ --level;
+}
+Symbol install(const char *name, Table *tpp, int level, int arena) {
+ Table tp = *tpp;
+ struct entry *p;
+ unsigned h = (unsigned long)name&(HASHSIZE-1);
+
+ assert(level == 0 || level >= tp->level);
+ if (level > 0 && tp->level < level)
+ tp = *tpp = table(tp, level);
+ NEW0(p, arena);
+ p->sym.name = (char *)name;
+ p->sym.scope = level;
+ p->sym.up = tp->all;
+ tp->all = &p->sym;
+ p->link = tp->buckets[h];
+ tp->buckets[h] = p;
+ return &p->sym;
+}
+Symbol relocate(const char *name, Table src, Table dst) {
+ struct entry *p, **q;
+ Symbol *r;
+ unsigned h = (unsigned long)name&(HASHSIZE-1);
+
+ for (q = &src->buckets[h]; *q; q = &(*q)->link)
+ if (name == (*q)->sym.name)
+ break;
+ assert(*q);
+ /*
+ Remove the entry from src's hash chain
+ and from its list of all symbols.
+ */
+ p = *q;
+ *q = (*q)->link;
+ for (r = &src->all; *r && *r != &p->sym; r = &(*r)->up)
+ ;
+ assert(*r == &p->sym);
+ *r = p->sym.up;
+ /*
+ Insert the entry into dst's hash chain
+ and into its list of all symbols.
+ Return the symbol-table entry.
+ */
+ p->link = dst->buckets[h];
+ dst->buckets[h] = p;
+ p->sym.up = dst->all;
+ dst->all = &p->sym;
+ return &p->sym;
+}
+Symbol lookup(const char *name, Table tp) {
+ struct entry *p;
+ unsigned h = (unsigned long)name&(HASHSIZE-1);
+
+ assert(tp);
+ do
+ for (p = tp->buckets[h]; p; p = p->link)
+ if (name == p->sym.name)
+ return &p->sym;
+ while ((tp = tp->previous) != NULL);
+ return NULL;
+}
+int genlabel(int n) {
+ static int label = 1;
+
+ label += n;
+ return label - n;
+}
+Symbol findlabel(int lab) {
+ struct entry *p;
+ unsigned h = lab&(HASHSIZE-1);
+
+ for (p = labels->buckets[h]; p; p = p->link)
+ if (lab == p->sym.u.l.label)
+ return &p->sym;
+ NEW0(p, FUNC);
+ p->sym.name = stringd(lab);
+ p->sym.scope = LABELS;
+ p->sym.up = labels->all;
+ labels->all = &p->sym;
+ p->link = labels->buckets[h];
+ labels->buckets[h] = p;
+ p->sym.generated = 1;
+ p->sym.u.l.label = lab;
+ (*IR->defsymbol)(&p->sym);
+ return &p->sym;
+}
+Symbol constant(Type ty, Value v) {
+ struct entry *p;
+ unsigned h = v.u&(HASHSIZE-1);
+
+ ty = unqual(ty);
+ for (p = constants->buckets[h]; p; p = p->link)
+ if (eqtype(ty, p->sym.type, 1))
+ switch (ty->op) {
+ case INT: if (equalp(i)) return &p->sym; break;
+ case UNSIGNED: if (equalp(u)) return &p->sym; break;
+ case FLOAT: if (equalp(d)) return &p->sym; break;
+ case FUNCTION: if (equalp(g)) return &p->sym; break;
+ case ARRAY:
+ case POINTER: if (equalp(p)) return &p->sym; break;
+ default: assert(0);
+ }
+ NEW0(p, PERM);
+ p->sym.name = vtoa(ty, v);
+ p->sym.scope = CONSTANTS;
+ p->sym.type = ty;
+ p->sym.sclass = STATIC;
+ p->sym.u.c.v = v;
+ p->link = constants->buckets[h];
+ p->sym.up = constants->all;
+ constants->all = &p->sym;
+ constants->buckets[h] = p;
+ if (ty->u.sym && !ty->u.sym->addressed)
+ (*IR->defsymbol)(&p->sym);
+ p->sym.defined = 1;
+ return &p->sym;
+}
+Symbol intconst(int n) {
+ Value v;
+
+ v.i = n;
+ return constant(inttype, v);
+}
+Symbol genident(int scls, Type ty, int lev) {
+ Symbol p;
+
+ NEW0(p, lev >= LOCAL ? FUNC : PERM);
+ p->name = stringd(genlabel(1));
+ p->scope = lev;
+ p->sclass = scls;
+ p->type = ty;
+ p->generated = 1;
+ if (lev == GLOBAL)
+ (*IR->defsymbol)(p);
+ return p;
+}
+
+Symbol temporary(int scls, Type ty) {
+ Symbol p;
+
+ NEW0(p, FUNC);
+ p->name = stringd(++tempid);
+ p->scope = level < LOCAL ? LOCAL : level;
+ p->sclass = scls;
+ p->type = ty;
+ p->temporary = 1;
+ p->generated = 1;
+ return p;
+}
+Symbol newtemp(int sclass, int tc, int size) {
+ Symbol p = temporary(sclass, btot(tc, size));
+
+ (*IR->local)(p);
+ p->defined = 1;
+ return p;
+}
+
+Symbol allsymbols(Table tp) {
+ return tp->all;
+}
+
+void locus(Table tp, Coordinate *cp) {
+ loci = append(cp, loci);
+ symbols = append(allsymbols(tp), symbols);
+}
+
+void use(Symbol p, Coordinate src) {
+ Coordinate *cp;
+
+ NEW(cp, PERM);
+ *cp = src;
+ p->uses = append(cp, p->uses);
+}
+/* findtype - find type ty in identifiers */
+Symbol findtype(Type ty) {
+ Table tp = identifiers;
+ int i;
+ struct entry *p;
+
+ assert(tp);
+ do
+ for (i = 0; i < HASHSIZE; i++)
+ for (p = tp->buckets[i]; p; p = p->link)
+ if (p->sym.type == ty && p->sym.sclass == TYPEDEF)
+ return &p->sym;
+ while ((tp = tp->previous) != NULL);
+ return NULL;
+}
+
+/* mkstr - make a string constant */
+Symbol mkstr(char *str) {
+ Value v;
+ Symbol p;
+
+ v.p = str;
+ p = constant(array(chartype, strlen(v.p) + 1, 0), v);
+ if (p->u.c.loc == NULL)
+ p->u.c.loc = genident(STATIC, p->type, GLOBAL);
+ return p;
+}
+
+/* mksymbol - make a symbol for name, install in &globals if sclass==EXTERN */
+Symbol mksymbol(int sclass, const char *name, Type ty) {
+ Symbol p;
+
+ if (sclass == EXTERN)
+ p = install(string(name), &globals, GLOBAL, PERM);
+ else {
+ NEW0(p, PERM);
+ p->name = string(name);
+ p->scope = GLOBAL;
+ }
+ p->sclass = sclass;
+ p->type = ty;
+ (*IR->defsymbol)(p);
+ p->defined = 1;
+ return p;
+}
+
+/* vtoa - return string for the constant v of type ty */
+char *vtoa(Type ty, Value v) {
+
+ ty = unqual(ty);
+ switch (ty->op) {
+ case INT: return stringd(v.i);
+ case UNSIGNED: return stringf((v.u&~0x7FFF) ? "0x%X" : "%U", v.u);
+ case FLOAT: return stringf("%g", (double)v.d);
+ case ARRAY:
+ if (ty->type == chartype || ty->type == signedchar
+ || ty->type == unsignedchar)
+ return v.p;
+ return stringf("%p", v.p);
+ case POINTER: return stringf("%p", v.p);
+ case FUNCTION: return stringf("%p", v.g);
+ }
+ assert(0); return NULL;
+}
diff --git a/code/tools/lcc/src/symbolic.c b/code/tools/lcc/src/symbolic.c
new file mode 100644
index 0000000..affa67a
--- /dev/null
+++ b/code/tools/lcc/src/symbolic.c
@@ -0,0 +1,494 @@
+#include <time.h>
+#include <ctype.h>
+#include "c.h"
+
+#define I(f) s_##f
+
+static Node *tail;
+static int off, maxoff, uid = 0, verbose = 0, html = 0;
+
+static const char *yyBEGIN(const char *tag) {
+ if (html)
+ print("<%s>", tag);
+ return tag;
+}
+
+static void yyEND(const char *tag) {
+ if (html)
+ print("</%s>", tag);
+ if (isupper(*tag))
+ print("\n");
+}
+
+#define BEGIN(tag) do { const char *yytag=yyBEGIN(#tag);
+#define END yyEND(yytag); } while (0)
+#define ITEM BEGIN(li)
+#define START BEGIN(LI)
+#define ANCHOR(attr,code) do { const char *yytag="a"; if (html) { printf("<a " #attr "=\""); code; print("\">"); }
+#define NEWLINE print(html ? "<br>\n" : "\n")
+
+static void emitCoord(Coordinate src) {
+ if (src.file && *src.file) {
+ ANCHOR(href,print("%s", src.file)); print("%s", src.file); END;
+ print(":");
+ }
+ print("%d.%d", src.y, src.x);
+}
+
+static void emitString(int len, const char *s) {
+ for ( ; len-- > 0; s++)
+ if (*s == '&' && html)
+ print("&");
+ else if (*s == '<' && html)
+ print("<");
+ else if (*s == '>' && html)
+ print("<");
+ else if (*s == '"' || *s == '\\')
+ print("\\%c", *s);
+ else if (*s >= ' ' && *s < 0177)
+ print("%c", *s);
+ else
+ print("\\%d%d%d", (*s>>6)&3, (*s>>3)&7, *s&7);
+}
+
+static void emitSymRef(Symbol p) {
+ (*IR->defsymbol)(p);
+ ANCHOR(href,print("#%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END;
+}
+
+static void emitSymbol(Symbol p) {
+ (*IR->defsymbol)(p);
+ ANCHOR(name,print("%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END;
+ BEGIN(ul);
+#define xx(field,code) ITEM; if (!html) print(" "); print(#field "="); code; END
+ if (verbose && (src.y || src.x))
+ xx(src,emitCoord(p->src));
+ xx(type,print("%t", p->type));
+ xx(sclass,print("%k", p->sclass));
+ switch (p->scope) {
+ case CONSTANTS: xx(scope,print("CONSTANTS")); break;
+ case LABELS: xx(scope,print("LABELS")); break;
+ case GLOBAL: xx(scope,print("GLOBAL")); break;
+ case PARAM: xx(scope,print("PARAM")); break;
+ case LOCAL: xx(scope,print("LOCAL")); break;
+ default:
+ if (p->scope > LOCAL)
+ xx(scope,print("LOCAL+%d", p->scope-LOCAL));
+ else
+ xx(scope,print("%d", p->scope));
+ }
+ if (p->scope >= PARAM && p->sclass != STATIC)
+ xx(offset,print("%d", p->x.offset));
+ xx(ref,print("%f", p->ref));
+ if (p->temporary && p->u.t.cse)
+ xx(u.t.cse,print("%p", p->u.t.cse));
+ END;
+#undef xx
+}
+
+/* address - initialize q for addressing expression p+n */
+static void I(address)(Symbol q, Symbol p, long n) {
+ q->name = stringf("%s%s%D", p->name, n > 0 ? "+" : "", n);
+ (*IR->defsymbol)(q);
+ START; print("address "); emitSymbol(q); END;
+}
+
+/* blockbeg - start a block */
+static void I(blockbeg)(Env *e) {
+ e->offset = off;
+ START; print("blockbeg off=%d", off); END;
+}
+
+/* blockend - start a block */
+static void I(blockend)(Env *e) {
+ if (off > maxoff)
+ maxoff = off;
+ START; print("blockend off=%d", off); END;
+ off = e->offset;
+}
+
+/* defaddress - initialize an address */
+static void I(defaddress)(Symbol p){
+ START; print("defaddress "); emitSymRef(p); END;
+}
+
+/* defconst - define a constant */
+static void I(defconst)(int suffix, int size, Value v) {
+ START;
+ print("defconst ");
+ switch (suffix) {
+ case I:
+ print("int.%d ", size);
+ BEGIN(code);
+ if (size > sizeof (int))
+ print("%D", v.i);
+ else
+ print("%d", (int)v.i);
+ END;
+ break;
+ case U:
+ print("unsigned.%d ", size);
+ BEGIN(code);
+ if (size > sizeof (unsigned))
+ print("%U", v.u);
+ else
+ print("%u", (unsigned)v.u);
+ END;
+ break;
+ case P: print("void*.%d ", size); BEGIN(code); print("%p", v.p); END; break;
+ case F: print("float.%d ", size); BEGIN(code); print("%g", (double)v.d); END; break;
+ default: assert(0);
+ }
+ END;
+}
+
+/* defstring - emit a string constant */
+static void I(defstring)(int len, char *s) {
+ START; print("defstring ");
+ BEGIN(code); print("\""); emitString(len, s); print("\""); END;
+ END;
+}
+
+/* defsymbol - define a symbol: initialize p->x */
+static void I(defsymbol)(Symbol p) {
+ if (p->x.name == NULL)
+ p->x.name = stringd(++uid);
+}
+
+/* emit - emit the dags on list p */
+static void I(emit)(Node p){
+ ITEM;
+ if (!html)
+ print(" ");
+ for (; p; p = p->x.next) {
+ if (p->op == LABEL+V) {
+ assert(p->syms[0]);
+ ANCHOR(name,print("%s", p->syms[0]->x.name));
+ BEGIN(code); print("%s", p->syms[0]->name); END;
+ END;
+ print(":");
+ } else {
+ int i;
+ if (p->x.listed) {
+ BEGIN(strong); print("%d", p->x.inst); END; print("'");
+ print(" %s", opname(p->op));
+ } else
+ print("%d. %s", p->x.inst, opname(p->op));
+ if (p->count > 1)
+ print(" count=%d", p->count);
+ for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++)
+ print(" #%d", p->kids[i]->x.inst);
+ if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type)
+ print(" {%t}", p->syms[0]->type);
+ else
+ for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++) {
+ print(" ");
+ if (p->syms[i]->scope == CONSTANTS)
+ print(p->syms[i]->name);
+ else
+ emitSymRef(p->syms[i]);
+ }
+ }
+ NEWLINE;
+ }
+ END;
+}
+
+/* export - announce p as exported */
+static void I(export)(Symbol p) {
+ START; print("export "); emitSymRef(p); END;
+}
+
+/* function - generate code for a function */
+static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
+ int i;
+
+ (*IR->defsymbol)(f);
+ off = 0;
+ for (i = 0; caller[i] && callee[i]; i++) {
+ off = roundup(off, caller[i]->type->align);
+ caller[i]->x.offset = callee[i]->x.offset = off;
+ off += caller[i]->type->size;
+ }
+ if (!html) {
+ print("function ");
+ emitSymbol(f);
+ print(" ncalls=%d\n", ncalls);
+ for (i = 0; caller[i]; i++)
+ START; print("caller "); emitSymbol(caller[i]); END;
+ for (i = 0; callee[i]; i++)
+ START; print("callee "); emitSymbol(callee[i]); END;
+ } else {
+ START;
+ print("function");
+ BEGIN(UL);
+#define xx(field,code) ITEM; print(#field "="); code; END
+ xx(f,emitSymbol(f));
+ xx(ncalls,print("%d", ncalls));
+ if (caller[0]) {
+ ITEM; print("caller"); BEGIN(OL);
+ for (i = 0; caller[i]; i++)
+ ITEM; emitSymbol(caller[i]); END;
+ END; END;
+ ITEM; print("callee"); BEGIN(OL);
+ for (i = 0; callee[i]; i++)
+ ITEM; emitSymbol(callee[i]); END;
+ END; END;
+ } else {
+ xx(caller,BEGIN(em); print("empty"); END);
+ xx(callee,BEGIN(em); print("empty"); END);
+ }
+ END;
+ END;
+ }
+ maxoff = off = 0;
+ gencode(caller, callee);
+ if (html)
+ START; print("emitcode"); BEGIN(ul); emitcode(); END; END;
+ else
+ emitcode();
+ START; print("maxoff=%d", maxoff); END;
+#undef xx
+}
+
+/* visit - generate code for *p */
+static int visit(Node p, int n) {
+ if (p && p->x.inst == 0) {
+ p->x.inst = ++n;
+ n = visit(p->kids[0], n);
+ n = visit(p->kids[1], n);
+ *tail = p;
+ tail = &p->x.next;
+ }
+ return n;
+}
+
+/* gen0 - generate code for the dags on list p */
+static Node I(gen)(Node p) {
+ int n;
+ Node nodelist;
+
+ tail = &nodelist;
+ for (n = 0; p; p = p->link) {
+ switch (generic(p->op)) { /* check for valid forest */
+ case CALL:
+ assert(IR->wants_dag || p->count == 0);
+ break;
+ case ARG:
+ case ASGN: case JUMP: case LABEL: case RET:
+ case EQ: case GE: case GT: case LE: case LT: case NE:
+ assert(p->count == 0);
+ break;
+ case INDIR:
+ assert(IR->wants_dag && p->count > 0);
+ break;
+ default:
+ assert(0);
+ }
+ check(p);
+ p->x.listed = 1;
+ n = visit(p, n);
+ }
+ *tail = 0;
+ return nodelist;
+}
+
+/* global - announce a global */
+static void I(global)(Symbol p) {
+ START; print("global "); emitSymbol(p); END;
+}
+
+/* import - import a symbol */
+static void I(import)(Symbol p) {
+ START; print("import "); emitSymRef(p); END;
+}
+
+/* local - local variable */
+static void I(local)(Symbol p) {
+ if (p->temporary)
+ p->name = stringf("t%s", p->name);
+ (*IR->defsymbol)(p);
+ off = roundup(off, p->type->align);
+ p->x.offset = off;
+ off += p->type->size;
+ START; print(p->temporary ? "temporary " : "local "); emitSymbol(p); END;
+}
+
+/* progbeg - beginning of program */
+static void I(progbeg)(int argc, char *argv[]) {
+ int i;
+
+ for (i = 1; i < argc; i++)
+ if (strcmp(argv[i], "-v") == 0)
+ verbose++;
+ else if (strcmp(argv[i], "-html") == 0)
+ html++;
+ if (html) {
+ print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n");
+ print("<html>");
+ BEGIN(head);
+ if (firstfile && *firstfile)
+ BEGIN(title); emitString(strlen(firstfile), firstfile); END;
+ print("<link rev=made href=\"mailto:drh at microsoft.com\">\n");
+ END;
+ print("<body>\n");
+ if (firstfile && *firstfile)
+ BEGIN(h1); emitString(strlen(firstfile), firstfile); END;
+ BEGIN(P); BEGIN(em);
+ print("Links lead from uses of identifiers and labels to their definitions.");
+ END; END;
+ print("<ul>\n");
+ START;
+ print("progbeg");
+ BEGIN(ol);
+ for (i = 1; i < argc; i++) {
+ ITEM;
+ BEGIN(code); print("\""); emitString(strlen(argv[i]), argv[i]); print("\""); END;
+ END;
+ }
+ END;
+ END;
+ }
+}
+
+/* progend - end of program */
+static void I(progend)(void) {
+ START; print("progend"); END;
+ if (html) {
+ time_t t;
+ print("</ul>\n");
+ time(&t);
+ print("<hr><address>%s</address>\n", ctime(&t));
+ print("</body></html>\n");
+ }
+}
+
+/* segment - switch to segment s */
+static void I(segment)(int s) {
+ START; print("segment %s", &"text\0bss\0.data\0lit\0.sym\0."[5*s-5]); END;
+}
+
+/* space - initialize n bytes of space */
+static void I(space)(int n) {
+ START; print("space %d", n); END;
+}
+
+static void I(stabblock)(int brace, int lev, Symbol *p) {}
+
+/* stabend - finalize stab output */
+static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {
+ int i;
+
+ if (p)
+ emitSymRef(p);
+ print("\n");
+ if (cpp && sp)
+ for (i = 0; cpp[i] && sp[i]; i++) {
+ print("%w.%d: ", cpp[i], cpp[i]->x);
+ emitSymRef(sp[i]);
+ print("\n");
+ }
+}
+
+static void I(stabfend)(Symbol p, int lineno) {}
+static void I(stabinit)(char *file, int argc, char *argv[]) {}
+
+/* stabline - emit line number information for source coordinate *cp */
+static void I(stabline)(Coordinate *cp) {
+ if (cp->file)
+ print("%s:", cp->file);
+ print("%d.%d:\n", cp->y, cp->x);
+}
+
+static void I(stabsym)(Symbol p) {}
+static void I(stabtype)(Symbol p) {}
+
+Interface symbolicIR = {
+ {1, 1, 0}, /* char */
+ {2, 2, 0}, /* short */
+ {4, 4, 0}, /* int */
+ {4, 4, 0}, /* long */
+ {4, 4, 0}, /* long long */
+ {4, 4, 1}, /* float */
+ {8, 8, 1}, /* double */
+ {8, 8, 1}, /* long double */
+ {4, 4, 0}, /* T* */
+ {0, 4, 0}, /* struct */
+ 0, /* little_endian */
+ 0, /* mulops_calls */
+ 0, /* wants_callb */
+ 1, /* wants_argb */
+ 1, /* left_to_right */
+ 1, /* wants_dag */
+ 0, /* unsigned_char */
+ I(address),
+ I(blockbeg),
+ I(blockend),
+ I(defaddress),
+ I(defconst),
+ I(defstring),
+ I(defsymbol),
+ I(emit),
+ I(export),
+ I(function),
+ I(gen),
+ I(global),
+ I(import),
+ I(local),
+ I(progbeg),
+ I(progend),
+ I(segment),
+ I(space),
+ I(stabblock),
+ I(stabend),
+ I(stabfend),
+ I(stabinit),
+ I(stabline),
+ I(stabsym),
+ I(stabtype)
+};
+
+Interface symbolic64IR = {
+ {1, 1, 0}, /* char */
+ {2, 2, 0}, /* short */
+ {4, 4, 0}, /* int */
+ {8, 8, 0}, /* long */
+ {8, 8, 0}, /* long long */
+ {4, 4, 1}, /* float */
+ {8, 8, 1}, /* double */
+ {8, 8, 1}, /* long double */
+ {8, 8, 0}, /* T* */
+ {0, 1, 0}, /* struct */
+ 1, /* little_endian */
+ 0, /* mulops_calls */
+ 0, /* wants_callb */
+ 1, /* wants_argb */
+ 1, /* left_to_right */
+ 1, /* wants_dag */
+ 0, /* unsigned_char */
+ I(address),
+ I(blockbeg),
+ I(blockend),
+ I(defaddress),
+ I(defconst),
+ I(defstring),
+ I(defsymbol),
+ I(emit),
+ I(export),
+ I(function),
+ I(gen),
+ I(global),
+ I(import),
+ I(local),
+ I(progbeg),
+ I(progend),
+ I(segment),
+ I(space),
+ I(stabblock),
+ I(stabend),
+ I(stabfend),
+ I(stabinit),
+ I(stabline),
+ I(stabsym),
+ I(stabtype)
+};
diff --git a/code/tools/lcc/src/token.h b/code/tools/lcc/src/token.h
new file mode 100644
index 0000000..d309f9b
--- /dev/null
+++ b/code/tools/lcc/src/token.h
@@ -0,0 +1,133 @@
+/*
+xx(symbol, value, prec, op, optree, kind, string)
+*/
+yy(0, 0, 0, 0, 0, 0, 0)
+xx(FLOAT, 1, 0, 0, 0, CHAR, "float")
+xx(DOUBLE, 2, 0, 0, 0, CHAR, "double")
+xx(CHAR, 3, 0, 0, 0, CHAR, "char")
+xx(SHORT, 4, 0, 0, 0, CHAR, "short")
+xx(INT, 5, 0, 0, 0, CHAR, "int")
+xx(UNSIGNED, 6, 0, 0, 0, CHAR, "unsigned")
+xx(POINTER, 7, 0, 0, 0, 0, "pointer")
+xx(VOID, 8, 0, 0, 0, CHAR, "void")
+xx(STRUCT, 9, 0, 0, 0, CHAR, "struct")
+xx(UNION, 10, 0, 0, 0, CHAR, "union")
+xx(FUNCTION, 11, 0, 0, 0, 0, "function")
+xx(ARRAY, 12, 0, 0, 0, 0, "array")
+xx(ENUM, 13, 0, 0, 0, CHAR, "enum")
+xx(LONG, 14, 0, 0, 0, CHAR, "long")
+xx(CONST, 15, 0, 0, 0, CHAR, "const")
+xx(VOLATILE, 16, 0, 0, 0, CHAR, "volatile")
+yy(0, 17, 0, 0, 0, 0, 0)
+yy(0, 18, 0, 0, 0, 0, 0)
+yy(0, 19, 0, 0, 0, 0, 0)
+yy(0, 20, 0, 0, 0, 0, 0)
+yy(0, 21, 0, 0, 0, 0, 0)
+yy(0, 22, 0, 0, 0, 0, 0)
+yy(0, 23, 0, 0, 0, 0, 0)
+yy(0, 24, 0, 0, 0, 0, 0)
+yy(0, 25, 0, 0, 0, 0, 0)
+yy(0, 26, 0, 0, 0, 0, 0)
+yy(0, 27, 0, 0, 0, 0, 0)
+yy(0, 28, 0, 0, 0, 0, "long long")
+yy(0, 29, 0, 0, 0, 0, 0)
+yy(0, 30, 0, 0, 0, 0, 0)
+yy(0, 31, 0, 0, 0, 0, "const volatile")
+xx(ID, 32, 0, 0, 0, ID, "identifier")
+yy(0, 33, 0, 0, 0, ID, "!")
+xx(FCON, 34, 0, 0, 0, ID, "floating constant")
+xx(ICON, 35, 0, 0, 0, ID, "integer constant")
+xx(SCON, 36, 0, 0, 0, ID, "string constant")
+yy(0, 37, 13, MOD, bittree,'%', "%")
+yy(0, 38, 8, BAND, bittree,ID, "&")
+xx(INCR, 39, 0, ADD, addtree,ID, "++")
+yy(0, 40, 0, 0, 0, ID, "(")
+yy(0, 41, 0, 0, 0, ')', ")")
+yy(0, 42, 13, MUL, multree,ID, "*")
+yy(0, 43, 12, ADD, addtree,ID, "+")
+yy(0, 44, 1, 0, 0, ',', ",")
+yy(0, 45, 12, SUB, subtree,ID, "-")
+yy(0, 46, 0, 0, 0, '.', ".")
+yy(0, 47, 13, DIV, multree,'/', "/")
+xx(DECR, 48, 0, SUB, subtree,ID, "--")
+xx(DEREF, 49, 0, 0, 0, DEREF, "->")
+xx(ANDAND, 50, 5, AND, andtree,ANDAND, "&&")
+xx(OROR, 51, 4, OR, andtree,OROR, "||")
+xx(LEQ, 52, 10, LE, cmptree,LEQ, "<=")
+xx(EQL, 53, 9, EQ, eqtree, EQL, "==")
+xx(NEQ, 54, 9, NE, eqtree, NEQ, "!=")
+xx(GEQ, 55, 10, GE, cmptree,GEQ, ">=")
+xx(RSHIFT, 56, 11, RSH, shtree, RSHIFT, ">>")
+xx(LSHIFT, 57, 11, LSH, shtree, LSHIFT, "<<")
+yy(0, 58, 0, 0, 0, ':', ":")
+yy(0, 59, 0, 0, 0, IF, ";")
+yy(0, 60, 10, LT, cmptree,'<', "<")
+yy(0, 61, 2, ASGN, asgntree,'=', "=")
+yy(0, 62, 10, GT, cmptree,'>', ">")
+yy(0, 63, 0, 0, 0, '?', "?")
+xx(ELLIPSIS, 64, 0, 0, 0, ELLIPSIS,"...")
+xx(SIZEOF, 65, 0, 0, 0, ID, "sizeof")
+yy(0, 66, 0, 0, 0, 0, 0)
+xx(AUTO, 67, 0, 0, 0, STATIC, "auto")
+xx(BREAK, 68, 0, 0, 0, IF, "break")
+xx(CASE, 69, 0, 0, 0, IF, "case")
+xx(CONTINUE, 70, 0, 0, 0, IF, "continue")
+xx(DEFAULT, 71, 0, 0, 0, IF, "default")
+xx(DO, 72, 0, 0, 0, IF, "do")
+xx(ELSE, 73, 0, 0, 0, IF, "else")
+xx(EXTERN, 74, 0, 0, 0, STATIC, "extern")
+xx(FOR, 75, 0, 0, 0, IF, "for")
+xx(GOTO, 76, 0, 0, 0, IF, "goto")
+xx(IF, 77, 0, 0, 0, IF, "if")
+xx(REGISTER, 78, 0, 0, 0, STATIC, "register")
+xx(RETURN, 79, 0, 0, 0, IF, "return")
+xx(SIGNED, 80, 0, 0, 0, CHAR, "signed")
+xx(STATIC, 81, 0, 0, 0, STATIC, "static")
+xx(SWITCH, 82, 0, 0, 0, IF, "switch")
+xx(TYPEDEF, 83, 0, 0, 0, STATIC, "typedef")
+xx(WHILE, 84, 0, 0, 0, IF, "while")
+xx(TYPECODE, 85, 0, 0, 0, ID, "__typecode")
+xx(FIRSTARG, 86, 0, 0, 0, ID, "__firstarg")
+yy(0, 87, 0, 0, 0, 0, 0)
+yy(0, 88, 0, 0, 0, 0, 0)
+yy(0, 89, 0, 0, 0, 0, 0)
+yy(0, 90, 0, 0, 0, 0, 0)
+yy(0, 91, 0, 0, 0, '[', "[")
+yy(0, 92, 0, 0, 0, 0, 0)
+yy(0, 93, 0, 0, 0, ']', "]")
+yy(0, 94, 7, BXOR, bittree,'^', "^")
+yy(0, 95, 0, 0, 0, 0, 0)
+yy(0, 96, 0, 0, 0, 0, 0)
+yy(0, 97, 0, 0, 0, 0, 0)
+yy(0, 98, 0, 0, 0, 0, 0)
+yy(0, 99, 0, 0, 0, 0, 0)
+yy(0, 100, 0, 0, 0, 0, 0)
+yy(0, 101, 0, 0, 0, 0, 0)
+yy(0, 102, 0, 0, 0, 0, 0)
+yy(0, 103, 0, 0, 0, 0, 0)
+yy(0, 104, 0, 0, 0, 0, 0)
+yy(0, 105, 0, 0, 0, 0, 0)
+yy(0, 106, 0, 0, 0, 0, 0)
+yy(0, 107, 0, 0, 0, 0, 0)
+yy(0, 108, 0, 0, 0, 0, 0)
+yy(0, 109, 0, 0, 0, 0, 0)
+yy(0, 110, 0, 0, 0, 0, 0)
+yy(0, 111, 0, 0, 0, 0, 0)
+yy(0, 112, 0, 0, 0, 0, 0)
+yy(0, 113, 0, 0, 0, 0, 0)
+yy(0, 114, 0, 0, 0, 0, 0)
+yy(0, 115, 0, 0, 0, 0, 0)
+yy(0, 116, 0, 0, 0, 0, 0)
+yy(0, 117, 0, 0, 0, 0, 0)
+yy(0, 118, 0, 0, 0, 0, 0)
+yy(0, 119, 0, 0, 0, 0, 0)
+yy(0, 120, 0, 0, 0, 0, 0)
+yy(0, 121, 0, 0, 0, 0, 0)
+yy(0, 122, 0, 0, 0, 0, 0)
+yy(0, 123, 0, 0, 0, IF, "{")
+yy(0, 124, 6, BOR, bittree,'|', "|")
+yy(0, 125, 0, 0, 0, '}', "}")
+yy(0, 126, 0, BCOM, 0, ID, "~")
+xx(EOI, 127, 0, 0, 0, EOI, "end of input")
+#undef xx
+#undef yy
diff --git a/code/tools/lcc/src/trace.c b/code/tools/lcc/src/trace.c
new file mode 100644
index 0000000..3b9ba78
--- /dev/null
+++ b/code/tools/lcc/src/trace.c
@@ -0,0 +1,181 @@
+#include "c.h"
+
+
+static char *fmt, *fp, *fmtend; /* format string, current & limit pointer */
+static Tree args; /* printf arguments */
+static Symbol frameno; /* local holding frame number */
+
+/* appendstr - append str to the evolving format string, expanding it if necessary */
+static void appendstr(char *str) {
+ do
+ if (fp == fmtend) {
+ if (fp) {
+ char *s = allocate(2*(fmtend - fmt), FUNC);
+ strncpy(s, fmt, fmtend - fmt);
+ fp = s + (fmtend - fmt);
+ fmtend = s + 2*(fmtend - fmt);
+ fmt = s;
+ } else {
+ fp = fmt = allocate(80, FUNC);
+ fmtend = fmt + 80;
+ }
+ }
+ while ((*fp++ = *str++) != 0);
+ fp--;
+}
+
+/* tracevalue - append format and argument to print the value of e */
+static void tracevalue(Tree e, int lev) {
+ Type ty = unqual(e->type);
+
+ switch (ty->op) {
+ case INT:
+ if (ty == chartype || ty == signedchar)
+ appendstr("'\\x%02x'");
+ else if (ty == longtype)
+ appendstr("0x%ld");
+ else
+ appendstr("0x%d");
+ break;
+ case UNSIGNED:
+ if (ty == chartype || ty == unsignedchar)
+ appendstr("'\\x%02x'");
+ else if (ty == unsignedlong)
+ appendstr("0x%lx");
+ else
+ appendstr("0x%x");
+ break;
+ case FLOAT:
+ if (ty == longdouble)
+ appendstr("%Lg");
+ else
+ appendstr("%g");
+ break;
+ case POINTER:
+ if (unqual(ty->type) == chartype
+ || unqual(ty->type) == signedchar
+ || unqual(ty->type) == unsignedchar) {
+ static Symbol null;
+ if (null == NULL)
+ null = mkstr("(null)");
+ tracevalue(cast(e, unsignedtype), lev + 1);
+ appendstr(" \"%.30s\"");
+ e = condtree(e, e, pointer(idtree(null->u.c.loc)));
+ } else {
+ appendstr("("); appendstr(typestring(ty, "")); appendstr(")0x%x");
+ }
+ break;
+ case STRUCT: {
+ Field q;
+ appendstr("("); appendstr(typestring(ty, "")); appendstr("){");
+ for (q = ty->u.sym->u.s.flist; q; q = q->link) {
+ appendstr(q->name); appendstr("=");
+ tracevalue(field(addrof(e), q->name), lev + 1);
+ if (q->link)
+ appendstr(",");
+ }
+ appendstr("}");
+ return;
+ }
+ case UNION:
+ appendstr("("); appendstr(typestring(ty, "")); appendstr("){...}");
+ return;
+ case ARRAY:
+ if (lev && ty->type->size > 0) {
+ int i;
+ e = pointer(e);
+ appendstr("{");
+ for (i = 0; i < ty->size/ty->type->size; i++) {
+ Tree p = (*optree['+'])(ADD, e, consttree(i, inttype));
+ if (isptr(p->type) && isarray(p->type->type))
+ p = retype(p, p->type->type);
+ else
+ p = rvalue(p);
+ if (i)
+ appendstr(",");
+ tracevalue(p, lev + 1);
+ }
+ appendstr("}");
+ } else
+ appendstr(typestring(ty, ""));
+ return;
+ default:
+ assert(0);
+ }
+ e = cast(e, promote(ty));
+ args = tree(mkop(ARG,e->type), e->type, e, args);
+}
+
+/* tracefinis - complete & generate the trace call to print */
+static void tracefinis(Symbol printer) {
+ Tree *ap;
+ Symbol p;
+
+ *fp = 0;
+ p = mkstr(string(fmt));
+ for (ap = &args; *ap; ap = &(*ap)->kids[1])
+ ;
+ *ap = tree(ARG+P, charptype, pointer(idtree(p->u.c.loc)), 0);
+ walk(calltree(pointer(idtree(printer)), freturn(printer->type), args, NULL), 0, 0);
+ args = 0;
+ fp = fmtend = 0;
+}
+
+/* tracecall - generate code to trace entry to f */
+static void tracecall(Symbol printer, Symbol f) {
+ int i;
+ Symbol counter = genident(STATIC, inttype, GLOBAL);
+
+ defglobal(counter, BSS);
+ (*IR->space)(counter->type->size);
+ frameno = genident(AUTO, inttype, level);
+ addlocal(frameno);
+ appendstr(f->name); appendstr("#");
+ tracevalue(asgn(frameno, incr(INCR, idtree(counter), consttree(1, inttype))), 0);
+ appendstr("(");
+ for (i = 0; f->u.f.callee[i]; i++) {
+ if (i)
+ appendstr(",");
+ appendstr(f->u.f.callee[i]->name); appendstr("=");
+ tracevalue(idtree(f->u.f.callee[i]), 0);
+ }
+ if (variadic(f->type))
+ appendstr(",...");
+ appendstr(") called\n");
+ tracefinis(printer);
+}
+
+/* tracereturn - generate code to trace return e */
+static void tracereturn(Symbol printer, Symbol f, Tree e) {
+ appendstr(f->name); appendstr("#");
+ tracevalue(idtree(frameno), 0);
+ appendstr(" returned");
+ if (freturn(f->type) != voidtype && e) {
+ appendstr(" ");
+ tracevalue(e, 0);
+ }
+ appendstr("\n");
+ tracefinis(printer);
+}
+
+/* trace_init - initialize for tracing */
+void trace_init(int argc, char *argv[]) {
+ int i;
+ static int inited;
+
+ if (inited)
+ return;
+ inited = 1;
+ type_init(argc, argv);
+ if (IR)
+ for (i = 1; i < argc; i++)
+ if (strncmp(argv[i], "-t", 2) == 0 && strchr(argv[i], '=') == NULL) {
+ Symbol printer = mksymbol(EXTERN,
+ argv[i][2] ? &argv[i][2] : "printf",
+ ftype(inttype, ptr(qual(CONST, chartype))));
+ printer->defined = 0;
+ attach((Apply)tracecall, printer, &events.entry);
+ attach((Apply)tracereturn, printer, &events.returns);
+ break;
+ }
+}
diff --git a/code/tools/lcc/src/tree.c b/code/tools/lcc/src/tree.c
new file mode 100644
index 0000000..d2b6a91
--- /dev/null
+++ b/code/tools/lcc/src/tree.c
@@ -0,0 +1,223 @@
+#include "c.h"
+
+
+int where = STMT;
+static int warn;
+static int nid = 1; /* identifies trees & nodes in debugging output */
+static struct nodeid {
+ int printed;
+ Tree node;
+} ids[500]; /* if ids[i].node == p, then p's id is i */
+
+static void printtree1(Tree, int, int);
+
+Tree tree(int op, Type type, Tree left, Tree right) {
+ Tree p;
+
+ NEW0(p, where);
+ p->op = op;
+ p->type = type;
+ p->kids[0] = left;
+ p->kids[1] = right;
+ return p;
+}
+
+Tree texpr(Tree (*f)(int), int tok, int a) {
+ int save = where;
+ Tree p;
+
+ where = a;
+ p = (*f)(tok);
+ where = save;
+ return p;
+}
+static Tree root1(Tree p) {
+ if (p == NULL)
+ return p;
+ if (p->type == voidtype)
+ warn++;
+ switch (generic(p->op)) {
+ case COND: {
+ Tree q = p->kids[1];
+ assert(q && q->op == RIGHT);
+ if (p->u.sym && q->kids[0] && generic(q->kids[0]->op) == ASGN)
+ q->kids[0] = root1(q->kids[0]->kids[1]);
+ else
+ q->kids[0] = root1(q->kids[0]);
+ if (p->u.sym && q->kids[1] && generic(q->kids[1]->op) == ASGN)
+ q->kids[1] = root1(q->kids[1]->kids[1]);
+ else
+ q->kids[1] = root1(q->kids[1]);
+ p->u.sym = 0;
+ if (q->kids[0] == 0 && q->kids[1] == 0)
+ p = root1(p->kids[0]);
+ }
+ break;
+ case AND: case OR:
+ if ((p->kids[1] = root1(p->kids[1])) == 0)
+ p = root1(p->kids[0]);
+ break;
+ case NOT:
+ if (warn++ == 0)
+ warning("expression with no effect elided\n");
+ return root1(p->kids[0]);
+ case RIGHT:
+ if (p->kids[1] == 0)
+ return root1(p->kids[0]);
+ if (p->kids[0] && p->kids[0]->op == CALL+B
+ && p->kids[1] && p->kids[1]->op == INDIR+B)
+ /* avoid premature release of the CALL+B temporary */
+ return p->kids[0];
+ if (p->kids[0] && p->kids[0]->op == RIGHT
+ && p->kids[1] == p->kids[0]->kids[0])
+ /* de-construct e++ construction */
+ return p->kids[0]->kids[1];
+ p = tree(RIGHT, p->type, root1(p->kids[0]), root1(p->kids[1]));
+ return p->kids[0] || p->kids[1] ? p : (Tree)0;
+ case EQ: case NE: case GT: case GE: case LE: case LT:
+ case ADD: case SUB: case MUL: case DIV: case MOD:
+ case LSH: case RSH: case BAND: case BOR: case BXOR:
+ if (warn++ == 0)
+ warning("expression with no effect elided\n");
+ p = tree(RIGHT, p->type, root1(p->kids[0]), root1(p->kids[1]));
+ return p->kids[0] || p->kids[1] ? p : (Tree)0;
+ case INDIR:
+ if (p->type->size == 0 && unqual(p->type) != voidtype)
+ warning("reference to `%t' elided\n", p->type);
+ if (isptr(p->kids[0]->type) && isvolatile(p->kids[0]->type->type))
+ warning("reference to `volatile %t' elided\n", p->type);
+ /* fall thru */
+ case CVI: case CVF: case CVU: case CVP:
+ case NEG: case BCOM: case FIELD:
+ if (warn++ == 0)
+ warning("expression with no effect elided\n");
+ return root1(p->kids[0]);
+ case ADDRL: case ADDRG: case ADDRF: case CNST:
+ if (needconst)
+ return p;
+ if (warn++ == 0)
+ warning("expression with no effect elided\n");
+ return NULL;
+ case ARG: case ASGN: case CALL: case JUMP: case LABEL:
+ break;
+ default: assert(0);
+ }
+ return p;
+}
+
+Tree root(Tree p) {
+ warn = 0;
+ return root1(p);
+}
+
+char *opname(int op) {
+ static char *opnames[] = {
+ "",
+ "CNST",
+ "ARG",
+ "ASGN",
+ "INDIR",
+ "CVC",
+ "CVD",
+ "CVF",
+ "CVI",
+ "CVP",
+ "CVS",
+ "CVU",
+ "NEG",
+ "CALL",
+ "*LOAD*",
+ "RET",
+ "ADDRG",
+ "ADDRF",
+ "ADDRL",
+ "ADD",
+ "SUB",
+ "LSH",
+ "MOD",
+ "RSH",
+ "BAND",
+ "BCOM",
+ "BOR",
+ "BXOR",
+ "DIV",
+ "MUL",
+ "EQ",
+ "GE",
+ "GT",
+ "LE",
+ "LT",
+ "NE",
+ "JUMP",
+ "LABEL",
+ "AND",
+ "NOT",
+ "OR",
+ "COND",
+ "RIGHT",
+ "FIELD"
+ }, *suffixes[] = {
+ "0", "F", "D", "C", "S", "I", "U", "P", "V", "B",
+ "10","11","12","13","14","15"
+ };
+
+ if (generic(op) >= AND && generic(op) <= FIELD && opsize(op) == 0)
+ return opnames[opindex(op)];
+ return stringf("%s%s%s",
+ opindex(op) > 0 && opindex(op) < NELEMS(opnames) ?
+ opnames[opindex(op)] : stringd(opindex(op)),
+ suffixes[optype(op)], opsize(op) > 0 ? stringd(opsize(op)) : "");
+}
+
+int nodeid(Tree p) {
+ int i = 1;
+
+ ids[nid].node = p;
+ while (ids[i].node != p)
+ i++;
+ if (i == nid)
+ ids[nid++].printed = 0;
+ return i;
+}
+
+/* printed - return pointer to ids[id].printed */
+int *printed(int id) {
+ if (id)
+ return &ids[id].printed;
+ nid = 1;
+ return 0;
+}
+
+/* printtree - print tree p on fd */
+void printtree(Tree p, int fd) {
+ (void)printed(0);
+ printtree1(p, fd, 1);
+}
+
+/* printtree1 - recursively print tree p */
+static void printtree1(Tree p, int fd, int lev) {
+ FILE *f = fd == 1 ? stdout : stderr;
+ int i;
+ static char blanks[] = " ";
+
+ if (p == 0 || *printed(i = nodeid(p)))
+ return;
+ fprint(f, "#%d%S%S", i, blanks, i < 10 ? 2 : i < 100 ? 1 : 0, blanks, lev);
+ fprint(f, "%s %t", opname(p->op), p->type);
+ *printed(i) = 1;
+ for (i = 0; i < NELEMS(p->kids); i++)
+ if (p->kids[i])
+ fprint(f, " #%d", nodeid(p->kids[i]));
+ if (p->op == FIELD && p->u.field)
+ fprint(f, " %s %d..%d", p->u.field->name,
+ fieldsize(p->u.field) + fieldright(p->u.field), fieldright(p->u.field));
+ else if (generic(p->op) == CNST)
+ fprint(f, " %s", vtoa(p->type, p->u.v));
+ else if (p->u.sym)
+ fprint(f, " %s", p->u.sym->name);
+ if (p->node)
+ fprint(f, " node=%p", p->node);
+ fprint(f, "\n");
+ for (i = 0; i < NELEMS(p->kids); i++)
+ printtree1(p->kids[i], fd, lev + 1);
+}
diff --git a/code/tools/lcc/src/types.c b/code/tools/lcc/src/types.c
new file mode 100644
index 0000000..4aa3d18
--- /dev/null
+++ b/code/tools/lcc/src/types.c
@@ -0,0 +1,748 @@
+#include "c.h"
+#include <float.h>
+
+
+static Field isfield(const char *, Field);
+static Type type(int, Type, int, int, void *);
+
+static struct entry {
+ struct type type;
+ struct entry *link;
+} *typetable[128];
+static int maxlevel;
+
+static Symbol pointersym;
+
+Type chartype; /* char */
+Type doubletype; /* double */
+Type floattype; /* float */
+Type inttype; /* signed int */
+Type longdouble; /* long double */
+Type longtype; /* long */
+Type longlong; /* long long */
+Type shorttype; /* signed short int */
+Type signedchar; /* signed char */
+Type unsignedchar; /* unsigned char */
+Type unsignedlong; /* unsigned long int */
+Type unsignedlonglong; /* unsigned long long int */
+Type unsignedshort; /* unsigned short int */
+Type unsignedtype; /* unsigned int */
+Type funcptype; /* void (*)() */
+Type charptype; /* char* */
+Type voidptype; /* void* */
+Type voidtype; /* basic types: void */
+Type unsignedptr; /* unsigned type to hold void* */
+Type signedptr; /* signed type to hold void* */
+Type widechar; /* unsigned type that represents wchar_t */
+
+static Type xxinit(int op, char *name, Metrics m) {
+ Symbol p = install(string(name), &types, GLOBAL, PERM);
+ Type ty = type(op, 0, m.size, m.align, p);
+
+ assert(ty->align == 0 || ty->size%ty->align == 0);
+ p->type = ty;
+ p->addressed = m.outofline;
+ switch (ty->op) {
+ case INT:
+ p->u.limits.max.i = ones(8*ty->size)>>1;
+ p->u.limits.min.i = -p->u.limits.max.i - 1;
+ break;
+ case UNSIGNED:
+ p->u.limits.max.u = ones(8*ty->size);
+ p->u.limits.min.u = 0;
+ break;
+ case FLOAT:
+ if (ty->size == sizeof (float))
+ p->u.limits.max.d = FLT_MAX;
+ else if (ty->size == sizeof (double))
+ p->u.limits.max.d = DBL_MAX;
+ else
+ p->u.limits.max.d = LDBL_MAX;
+ p->u.limits.min.d = -p->u.limits.max.d;
+ break;
+ default: assert(0);
+ }
+ return ty;
+}
+static Type type(int op, Type ty, int size, int align, void *sym) {
+ unsigned h = (op^((unsigned long)ty>>3))
+&(NELEMS(typetable)-1);
+ struct entry *tn;
+
+ if (op != FUNCTION && (op != ARRAY || size > 0))
+ for (tn = typetable[h]; tn; tn = tn->link)
+ if (tn->type.op == op && tn->type.type == ty
+ && tn->type.size == size && tn->type.align == align
+ && tn->type.u.sym == sym)
+ return &tn->type;
+ NEW0(tn, PERM);
+ tn->type.op = op;
+ tn->type.type = ty;
+ tn->type.size = size;
+ tn->type.align = align;
+ tn->type.u.sym = sym;
+ tn->link = typetable[h];
+ typetable[h] = tn;
+ return &tn->type;
+}
+void type_init(int argc, char *argv[]) {
+ static int inited;
+ int i;
+
+ if (inited)
+ return;
+ inited = 1;
+ if (!IR)
+ return;
+ for (i = 1; i < argc; i++) {
+ int size, align, outofline;
+ if (strncmp(argv[i], "-unsigned_char=", 15) == 0)
+ IR->unsigned_char = argv[i][15] - '0';
+#define xx(name) \
+ else if (sscanf(argv[i], "-" #name "=%d,%d,%d", &size, &align, &outofline) == 3) { \
+ IR->name.size = size; IR->name.align = align; \
+ IR->name.outofline = outofline; }
+ xx(charmetric)
+ xx(shortmetric)
+ xx(intmetric)
+ xx(longmetric)
+ xx(longlongmetric)
+ xx(floatmetric)
+ xx(doublemetric)
+ xx(longdoublemetric)
+ xx(ptrmetric)
+ xx(structmetric)
+#undef xx
+ }
+#define xx(v,name,op,metrics) v=xxinit(op,name,IR->metrics)
+ xx(chartype, "char", IR->unsigned_char ? UNSIGNED : INT,charmetric);
+ xx(doubletype, "double", FLOAT, doublemetric);
+ xx(floattype, "float", FLOAT, floatmetric);
+ xx(inttype, "int", INT, intmetric);
+ xx(longdouble, "long double", FLOAT, longdoublemetric);
+ xx(longtype, "long int", INT, longmetric);
+ xx(longlong, "long long int", INT, longlongmetric);
+ xx(shorttype, "short", INT, shortmetric);
+ xx(signedchar, "signed char", INT, charmetric);
+ xx(unsignedchar, "unsigned char", UNSIGNED,charmetric);
+ xx(unsignedlong, "unsigned long", UNSIGNED,longmetric);
+ xx(unsignedshort, "unsigned short", UNSIGNED,shortmetric);
+ xx(unsignedtype, "unsigned int", UNSIGNED,intmetric);
+ xx(unsignedlonglong,"unsigned long long",UNSIGNED,longlongmetric);
+#undef xx
+ {
+ Symbol p;
+ p = install(string("void"), &types, GLOBAL, PERM);
+ voidtype = type(VOID, NULL, 0, 0, p);
+ p->type = voidtype;
+ }
+ pointersym = install(string("T*"), &types, GLOBAL, PERM);
+ pointersym->addressed = IR->ptrmetric.outofline;
+ pointersym->u.limits.max.p = (void*)ones(8*IR->ptrmetric.size);
+ pointersym->u.limits.min.p = 0;
+ voidptype = ptr(voidtype);
+ funcptype = ptr(func(voidtype, NULL, 1));
+ charptype = ptr(chartype);
+#define xx(v,t) if (v==NULL && t->size==voidptype->size && t->align==voidptype->align) v=t
+ xx(unsignedptr,unsignedshort);
+ xx(unsignedptr,unsignedtype);
+ xx(unsignedptr,unsignedlong);
+ xx(unsignedptr,unsignedlonglong);
+ if (unsignedptr == NULL)
+ unsignedptr = type(UNSIGNED, NULL, voidptype->size, voidptype->align, voidptype->u.sym);
+ xx(signedptr,shorttype);
+ xx(signedptr,inttype);
+ xx(signedptr,longtype);
+ xx(signedptr,longlong);
+ if (signedptr == NULL)
+ signedptr = type(INT, NULL, voidptype->size, voidptype->align, voidptype->u.sym);
+#undef xx
+ widechar = unsignedshort;
+ for (i = 0; i < argc; i++) {
+#define xx(name,type) \
+ if (strcmp(argv[i], "-wchar_t=" #name) == 0) \
+ widechar = type;
+ xx(unsigned_char,unsignedchar)
+ xx(unsigned_int,unsignedtype)
+ xx(unsigned_short,unsignedshort)
+ }
+#undef xx
+}
+void rmtypes(int lev) {
+ if (maxlevel >= lev) {
+ int i;
+ maxlevel = 0;
+ for (i = 0; i < NELEMS(typetable); i++) {
+ struct entry *tn, **tq = &typetable[i];
+ while ((tn = *tq) != NULL)
+ if (tn->type.op == FUNCTION)
+ tq = &tn->link;
+ else if (tn->type.u.sym && tn->type.u.sym->scope >= lev)
+ *tq = tn->link;
+ else {
+ if (tn->type.u.sym && tn->type.u.sym->scope > maxlevel)
+ maxlevel = tn->type.u.sym->scope;
+ tq = &tn->link;
+ }
+
+ }
+ }
+}
+Type ptr(Type ty) {
+ return type(POINTER, ty, IR->ptrmetric.size,
+ IR->ptrmetric.align, pointersym);
+}
+Type deref(Type ty) {
+ if (isptr(ty))
+ ty = ty->type;
+ else
+ error("type error: %s\n", "pointer expected");
+ return isenum(ty) ? unqual(ty)->type : ty;
+}
+Type array(Type ty, int n, int a) {
+ assert(ty);
+ if (isfunc(ty)) {
+ error("illegal type `array of %t'\n", ty);
+ return array(inttype, n, 0);
+ }
+ if (isarray(ty) && ty->size == 0)
+ error("missing array size\n");
+ if (ty->size == 0) {
+ if (unqual(ty) == voidtype)
+ error("illegal type `array of %t'\n", ty);
+ else if (Aflag >= 2)
+ warning("declaring type array of %t' is undefined\n", ty);
+
+ } else if (n > INT_MAX/ty->size) {
+ error("size of `array of %t' exceeds %d bytes\n",
+ ty, INT_MAX);
+ n = 1;
+ }
+ return type(ARRAY, ty, n*ty->size,
+ a ? a : ty->align, NULL);
+}
+Type atop(Type ty) {
+ if (isarray(ty))
+ return ptr(ty->type);
+ error("type error: %s\n", "array expected");
+ return ptr(ty);
+}
+Type qual(int op, Type ty) {
+ if (isarray(ty))
+ ty = type(ARRAY, qual(op, ty->type), ty->size,
+ ty->align, NULL);
+ else if (isfunc(ty))
+ warning("qualified function type ignored\n");
+ else if ((isconst(ty) && op == CONST)
+ || (isvolatile(ty) && op == VOLATILE))
+ error("illegal type `%k %t'\n", op, ty);
+ else {
+ if (isqual(ty)) {
+ op += ty->op;
+ ty = ty->type;
+ }
+ ty = type(op, ty, ty->size, ty->align, NULL);
+ }
+ return ty;
+}
+Type func(Type ty, Type *proto, int style) {
+ if (ty && (isarray(ty) || isfunc(ty)))
+ error("illegal return type `%t'\n", ty);
+ ty = type(FUNCTION, ty, 0, 0, NULL);
+ ty->u.f.proto = proto;
+ ty->u.f.oldstyle = style;
+ return ty;
+}
+Type freturn(Type ty) {
+ if (isfunc(ty))
+ return ty->type;
+ error("type error: %s\n", "function expected");
+ return inttype;
+}
+int variadic(Type ty) {
+ if (isfunc(ty) && ty->u.f.proto) {
+ int i;
+ for (i = 0; ty->u.f.proto[i]; i++)
+ ;
+ return i > 1 && ty->u.f.proto[i-1] == voidtype;
+ }
+ return 0;
+}
+Type newstruct(int op, char *tag) {
+ Symbol p;
+
+ assert(tag);
+ if (*tag == 0)
+ tag = stringd(genlabel(1));
+ else
+ if ((p = lookup(tag, types)) != NULL && (p->scope == level
+ || (p->scope == PARAM && level == PARAM+1))) {
+ if (p->type->op == op && !p->defined)
+ return p->type;
+ error("redefinition of `%s' previously defined at %w\n",
+ p->name, &p->src);
+ }
+ p = install(tag, &types, level, PERM);
+ p->type = type(op, NULL, 0, 0, p);
+ if (p->scope > maxlevel)
+ maxlevel = p->scope;
+ p->src = src;
+ return p->type;
+}
+Field newfield(char *name, Type ty, Type fty) {
+ Field p, *q = &ty->u.sym->u.s.flist;
+
+ if (name == NULL)
+ name = stringd(genlabel(1));
+ for (p = *q; p; q = &p->link, p = *q)
+ if (p->name == name)
+ error("duplicate field name `%s' in `%t'\n",
+ name, ty);
+ NEW0(p, PERM);
+ *q = p;
+ p->name = name;
+ p->type = fty;
+ if (xref) { /* omit */
+ if (ty->u.sym->u.s.ftab == NULL) /* omit */
+ ty->u.sym->u.s.ftab = table(NULL, level); /* omit */
+ install(name, &ty->u.sym->u.s.ftab, 0, PERM)->src = src;/* omit */
+ } /* omit */
+ return p;
+}
+int eqtype(Type ty1, Type ty2, int ret) {
+ if (ty1 == ty2)
+ return 1;
+ if (ty1->op != ty2->op)
+ return 0;
+ switch (ty1->op) {
+ case ENUM: case UNION: case STRUCT:
+ case UNSIGNED: case INT: case FLOAT:
+ return 0;
+ case POINTER: return eqtype(ty1->type, ty2->type, 1);
+ case VOLATILE: case CONST+VOLATILE:
+ case CONST: return eqtype(ty1->type, ty2->type, 1);
+ case ARRAY: if (eqtype(ty1->type, ty2->type, 1)) {
+ if (ty1->size == ty2->size)
+ return 1;
+ if (ty1->size == 0 || ty2->size == 0)
+ return ret;
+ }
+ return 0;
+ case FUNCTION: if (eqtype(ty1->type, ty2->type, 1)) {
+ Type *p1 = ty1->u.f.proto, *p2 = ty2->u.f.proto;
+ if (p1 == p2)
+ return 1;
+ if (p1 && p2) {
+ for ( ; *p1 && *p2; p1++, p2++)
+ if (eqtype(unqual(*p1), unqual(*p2), 1) == 0)
+ return 0;
+ if (*p1 == NULL && *p2 == NULL)
+ return 1;
+ } else {
+ if (variadic(p1 ? ty1 : ty2))
+ return 0;
+ if (p1 == NULL)
+ p1 = p2;
+ for ( ; *p1; p1++) {
+ Type ty = unqual(*p1);
+ if (promote(ty) != (isenum(ty) ? ty->type : ty))
+ return 0;
+ }
+ return 1;
+ }
+ }
+ return 0;
+ }
+ assert(0); return 0;
+}
+Type promote(Type ty) {
+ ty = unqual(ty);
+ switch (ty->op) {
+ case ENUM:
+ return inttype;
+ case INT:
+ if (ty->size < inttype->size)
+ return inttype;
+ break;
+ case UNSIGNED:
+ if (ty->size < inttype->size)
+ return inttype;
+ if (ty->size < unsignedtype->size)
+ return unsignedtype;
+ break;
+ case FLOAT:
+ if (ty->size < doubletype->size)
+ return doubletype;
+ }
+ return ty;
+}
+Type signedint(Type ty) {
+ if (ty->op == INT)
+ return ty;
+ assert(ty->op == UNSIGNED);
+#define xx(t) if (ty->size == t->size) return t
+ xx(inttype);
+ xx(longtype);
+ xx(longlong);
+#undef xx
+ assert(0); return NULL;
+}
+Type compose(Type ty1, Type ty2) {
+ if (ty1 == ty2)
+ return ty1;
+ assert(ty1->op == ty2->op);
+ switch (ty1->op) {
+ case POINTER:
+ return ptr(compose(ty1->type, ty2->type));
+ case CONST+VOLATILE:
+ return qual(CONST, qual(VOLATILE,
+ compose(ty1->type, ty2->type)));
+ case CONST: case VOLATILE:
+ return qual(ty1->op, compose(ty1->type, ty2->type));
+ case ARRAY: { Type ty = compose(ty1->type, ty2->type);
+ if (ty1->size && ((ty1->type->size && ty2->size == 0) || ty1->size == ty2->size))
+ return array(ty, ty1->size/ty1->type->size, ty1->align);
+ if (ty2->size && ty2->type->size && ty1->size == 0)
+ return array(ty, ty2->size/ty2->type->size, ty2->align);
+ return array(ty, 0, 0); }
+ case FUNCTION: { Type *p1 = ty1->u.f.proto, *p2 = ty2->u.f.proto;
+ Type ty = compose(ty1->type, ty2->type);
+ List tlist = NULL;
+ if (p1 == NULL && p2 == NULL)
+ return func(ty, NULL, 1);
+ if (p1 && p2 == NULL)
+ return func(ty, p1, ty1->u.f.oldstyle);
+ if (p2 && p1 == NULL)
+ return func(ty, p2, ty2->u.f.oldstyle);
+ for ( ; *p1 && *p2; p1++, p2++) {
+ Type ty = compose(unqual(*p1), unqual(*p2));
+ if (isconst(*p1) || isconst(*p2))
+ ty = qual(CONST, ty);
+ if (isvolatile(*p1) || isvolatile(*p2))
+ ty = qual(VOLATILE, ty);
+ tlist = append(ty, tlist);
+ }
+ assert(*p1 == NULL && *p2 == NULL);
+ return func(ty, ltov(&tlist, PERM), 0); }
+ }
+ assert(0); return NULL;
+}
+int ttob(Type ty) {
+ switch (ty->op) {
+ case CONST: case VOLATILE: case CONST+VOLATILE:
+ return ttob(ty->type);
+ case VOID: case INT: case UNSIGNED: case FLOAT:
+ return ty->op + sizeop(ty->size);
+ case POINTER:
+ return POINTER + sizeop(voidptype->size);
+ case FUNCTION:
+ return POINTER + sizeop(funcptype->size);
+ case ARRAY: case STRUCT: case UNION:
+ return STRUCT;
+ case ENUM:
+ return INT + sizeop(inttype->size);
+ }
+ assert(0); return INT;
+}
+Type btot(int op, int size) {
+#define xx(ty) if (size == (ty)->size) return ty;
+ switch (optype(op)) {
+ case F:
+ xx(floattype);
+ xx(doubletype);
+ xx(longdouble);
+ assert(0); return 0;
+ case I:
+ if (chartype->op == INT)
+ xx(chartype);
+ xx(signedchar);
+ xx(shorttype);
+ xx(inttype);
+ xx(longtype);
+ xx(longlong);
+ assert(0); return 0;
+ case U:
+ if (chartype->op == UNSIGNED)
+ xx(chartype);
+ xx(unsignedchar);
+ xx(unsignedshort);
+ xx(unsignedtype);
+ xx(unsignedlong);
+ xx(unsignedlonglong);
+ assert(0); return 0;
+ case P:
+ xx(voidptype);
+ xx(funcptype);
+ assert(0); return 0;
+ }
+#undef xx
+ assert(0); return 0;
+}
+int hasproto(Type ty) {
+ if (ty == 0)
+ return 1;
+ switch (ty->op) {
+ case CONST: case VOLATILE: case CONST+VOLATILE: case POINTER:
+ case ARRAY:
+ return hasproto(ty->type);
+ case FUNCTION:
+ return hasproto(ty->type) && ty->u.f.proto;
+ case STRUCT: case UNION:
+ case VOID: case FLOAT: case ENUM: case INT: case UNSIGNED:
+ return 1;
+ }
+ assert(0); return 0;
+}
+/* fieldlist - construct a flat list of fields in type ty */
+Field fieldlist(Type ty) {
+ return ty->u.sym->u.s.flist;
+}
+
+/* fieldref - find field name of type ty, return entry */
+Field fieldref(const char *name, Type ty) {
+ Field p = isfield(name, unqual(ty)->u.sym->u.s.flist);
+
+ if (p && xref) {
+ Symbol q;
+ assert(unqual(ty)->u.sym->u.s.ftab);
+ q = lookup(name, unqual(ty)->u.sym->u.s.ftab);
+ assert(q);
+ use(q, src);
+ }
+ return p;
+}
+
+/* ftype - return a function type for rty function (ty,...)' */
+Type ftype(Type rty, Type ty) {
+ List list = append(ty, NULL);
+
+ list = append(voidtype, list);
+ return func(rty, ltov(&list, PERM), 0);
+}
+
+/* isfield - if name is a field in flist, return pointer to the field structure */
+static Field isfield(const char *name, Field flist) {
+ for ( ; flist; flist = flist->link)
+ if (flist->name == name)
+ break;
+ return flist;
+}
+
+/* outtype - output type ty */
+void outtype(Type ty, FILE *f) {
+ switch (ty->op) {
+ case CONST+VOLATILE: case CONST: case VOLATILE:
+ fprint(f, "%k %t", ty->op, ty->type);
+ break;
+ case STRUCT: case UNION: case ENUM:
+ assert(ty->u.sym);
+ if (ty->size == 0)
+ fprint(f, "incomplete ");
+ assert(ty->u.sym->name);
+ if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9') {
+ Symbol p = findtype(ty);
+ if (p == 0)
+ fprint(f, "%k defined at %w", ty->op, &ty->u.sym->src);
+ else
+ fprint(f, p->name);
+ } else {
+ fprint(f, "%k %s", ty->op, ty->u.sym->name);
+ if (ty->size == 0)
+ fprint(f, " defined at %w", &ty->u.sym->src);
+ }
+ break;
+ case VOID: case FLOAT: case INT: case UNSIGNED:
+ fprint(f, ty->u.sym->name);
+ break;
+ case POINTER:
+ fprint(f, "pointer to %t", ty->type);
+ break;
+ case FUNCTION:
+ fprint(f, "%t function", ty->type);
+ if (ty->u.f.proto && ty->u.f.proto[0]) {
+ int i;
+ fprint(f, "(%t", ty->u.f.proto[0]);
+ for (i = 1; ty->u.f.proto[i]; i++)
+ if (ty->u.f.proto[i] == voidtype)
+ fprint(f, ",...");
+ else
+ fprint(f, ",%t", ty->u.f.proto[i]);
+ fprint(f, ")");
+ } else if (ty->u.f.proto && ty->u.f.proto[0] == 0)
+ fprint(f, "(void)");
+
+ break;
+ case ARRAY:
+ if (ty->size > 0 && ty->type && ty->type->size > 0) {
+ fprint(f, "array %d", ty->size/ty->type->size);
+ while (ty->type && isarray(ty->type) && ty->type->type->size > 0) {
+ ty = ty->type;
+ fprint(f, ",%d", ty->size/ty->type->size);
+ }
+ } else
+ fprint(f, "incomplete array");
+ if (ty->type)
+ fprint(f, " of %t", ty->type);
+ break;
+ default: assert(0);
+ }
+}
+
+/* printdecl - output a C declaration for symbol p of type ty */
+void printdecl(Symbol p, Type ty) {
+ switch (p->sclass) {
+ case AUTO:
+ fprint(stderr, "%s;\n", typestring(ty, p->name));
+ break;
+ case STATIC: case EXTERN:
+ fprint(stderr, "%k %s;\n", p->sclass, typestring(ty, p->name));
+ break;
+ case TYPEDEF: case ENUM:
+ break;
+ default: assert(0);
+ }
+}
+
+/* printproto - output a prototype declaration for function p */
+void printproto(Symbol p, Symbol callee[]) {
+ if (p->type->u.f.proto)
+ printdecl(p, p->type);
+ else {
+ int i;
+ List list = 0;
+ if (callee[0] == 0)
+ list = append(voidtype, list);
+ else
+ for (i = 0; callee[i]; i++)
+ list = append(callee[i]->type, list);
+ printdecl(p, func(freturn(p->type), ltov(&list, PERM), 0));
+ }
+}
+
+/* prtype - print details of type ty on f with given indent */
+static void prtype(Type ty, FILE *f, int indent, unsigned mark) {
+ switch (ty->op) {
+ default:
+ fprint(f, "(%d %d %d [%p])", ty->op, ty->size, ty->align, ty->u.sym);
+ break;
+ case FLOAT: case INT: case UNSIGNED: case VOID:
+ fprint(f, "(%k %d %d [\"%s\"])", ty->op, ty->size, ty->align, ty->u.sym->name);
+ break;
+ case CONST+VOLATILE: case CONST: case VOLATILE: case POINTER: case ARRAY:
+ fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align);
+ prtype(ty->type, f, indent+1, mark);
+ fprint(f, ")");
+ break;
+ case STRUCT: case UNION:
+ fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name);
+ if (ty->x.marked != mark) {
+ Field p;
+ ty->x.marked = mark;
+ for (p = ty->u.sym->u.s.flist; p; p = p->link) {
+ fprint(f, "\n%I", indent+1);
+ prtype(p->type, f, indent+1, mark);
+ fprint(f, " %s@%d", p->name, p->offset);
+ if (p->lsb)
+ fprint(f, ":%d..%d",
+ fieldsize(p) + fieldright(p), fieldright(p));
+ }
+ fprint(f, "\n%I", indent);
+ }
+ fprint(f, ")");
+ break;
+ case ENUM:
+ fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name);
+ if (ty->x.marked != mark) {
+ int i;
+ Symbol *p = ty->u.sym->u.idlist;
+ ty->x.marked = mark;
+ for (i = 0; p[i] != NULL; i++)
+ fprint(f, "%I%s=%d\n", indent+1, p[i]->name, p[i]->u.value);
+ }
+ fprint(f, ")");
+ break;
+ case FUNCTION:
+ fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align);
+ prtype(ty->type, f, indent+1, mark);
+ if (ty->u.f.proto) {
+ int i;
+ fprint(f, "\n%I{", indent+1);
+ for (i = 0; ty->u.f.proto[i]; i++) {
+ if (i > 0)
+ fprint(f, "%I", indent+2);
+ prtype(ty->u.f.proto[i], f, indent+2, mark);
+ fprint(f, "\n");
+ }
+ fprint(f, "%I}", indent+1);
+ }
+ fprint(f, ")");
+ break;
+ }
+}
+
+/* printtype - print details of type ty on fd */
+void printtype(Type ty, int fd) {
+ static unsigned mark;
+ prtype(ty, fd == 1 ? stdout : stderr, 0, ++mark);
+ fprint(fd == 1 ? stdout : stderr, "\n");
+}
+
+/* typestring - return ty as C declaration for str, which may be "" */
+char *typestring(Type ty, char *str) {
+ for ( ; ty; ty = ty->type) {
+ Symbol p;
+ switch (ty->op) {
+ case CONST+VOLATILE: case CONST: case VOLATILE:
+ if (isptr(ty->type))
+ str = stringf("%k %s", ty->op, str);
+ else
+ return stringf("%k %s", ty->op, typestring(ty->type, str));
+ break;
+ case STRUCT: case UNION: case ENUM:
+ assert(ty->u.sym);
+ if ((p = findtype(ty)) != NULL)
+ return *str ? stringf("%s %s", p->name, str) : p->name;
+ if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9')
+ warning("unnamed %k in prototype\n", ty->op);
+ if (*str)
+ return stringf("%k %s %s", ty->op, ty->u.sym->name, str);
+ else
+ return stringf("%k %s", ty->op, ty->u.sym->name);
+ case VOID: case FLOAT: case INT: case UNSIGNED:
+ return *str ? stringf("%s %s", ty->u.sym->name, str) : ty->u.sym->name;
+ case POINTER:
+ if (!ischar(ty->type) && (p = findtype(ty)) != NULL)
+ return *str ? stringf("%s %s", p->name, str) : p->name;
+ str = stringf(isarray(ty->type) || isfunc(ty->type) ? "(*%s)" : "*%s", str);
+ break;
+ case FUNCTION:
+ if ((p = findtype(ty)) != NULL)
+ return *str ? stringf("%s %s", p->name, str) : p->name;
+ if (ty->u.f.proto == 0)
+ str = stringf("%s()", str);
+ else if (ty->u.f.proto[0]) {
+ int i;
+ str = stringf("%s(%s", str, typestring(ty->u.f.proto[0], ""));
+ for (i = 1; ty->u.f.proto[i]; i++)
+ if (ty->u.f.proto[i] == voidtype)
+ str = stringf("%s, ...", str);
+ else
+ str = stringf("%s, %s", str, typestring(ty->u.f.proto[i], ""));
+ str = stringf("%s)", str);
+ } else
+ str = stringf("%s(void)", str);
+ break;
+ case ARRAY:
+ if ((p = findtype(ty)) != NULL)
+ return *str ? stringf("%s %s", p->name, str) : p->name;
+ if (ty->type && ty->type->size > 0)
+ str = stringf("%s[%d]", str, ty->size/ty->type->size);
+ else
+ str = stringf("%s[]", str);
+ break;
+ default: assert(0);
+ }
+ }
+ assert(0); return 0;
+}
+
diff --git a/game/code/ui/ui.q3asm b/code/ui/ui.q3asm
similarity index 100%
rename from game/code/ui/ui.q3asm
rename to code/ui/ui.q3asm
diff --git a/game/code/ui/ui_atoms.c b/code/ui/ui_atoms.c
similarity index 100%
rename from game/code/ui/ui_atoms.c
rename to code/ui/ui_atoms.c
diff --git a/code/ui/ui_gameinfo.c b/code/ui/ui_gameinfo.c
new file mode 100644
index 0000000..4629ec4
--- /dev/null
+++ b/code/ui/ui_gameinfo.c
@@ -0,0 +1,336 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+//
+// gameinfo.c
+//
+
+#include "ui_local.h"
+
+
+//
+// arena and bot info
+//
+
+
+int ui_numBots;
+static char *ui_botInfos[MAX_BOTS];
+
+static int ui_numArenas;
+static char *ui_arenaInfos[MAX_ARENAS];
+
+#ifndef MISSIONPACK // bk001206
+static int ui_numSinglePlayerArenas;
+static int ui_numSpecialSinglePlayerArenas;
+#endif
+
+/*
+===============
+UI_ParseInfos
+===============
+*/
+int UI_ParseInfos( char *buf, int max, char *infos[] ) {
+ char *token;
+ int count;
+ char key[MAX_TOKEN_CHARS];
+ char info[MAX_INFO_STRING];
+
+ count = 0;
+
+ while ( 1 ) {
+ token = COM_Parse( &buf );
+ if ( !token[0] ) {
+ break;
+ }
+ if ( strcmp( token, "{" ) ) {
+ Com_Printf( "Missing { in info file\n" );
+ break;
+ }
+
+ if ( count == max ) {
+ Com_Printf( "Max infos exceeded\n" );
+ break;
+ }
+
+ info[0] = '\0';
+ while ( 1 ) {
+ token = COM_ParseExt( &buf, qtrue );
+ if ( !token[0] ) {
+ Com_Printf( "Unexpected end of info file\n" );
+ break;
+ }
+ if ( !strcmp( token, "}" ) ) {
+ break;
+ }
+ Q_strncpyz( key, token, sizeof( key ) );
+
+ token = COM_ParseExt( &buf, qfalse );
+ if ( !token[0] ) {
+ strcpy( token, "<NULL>" );
+ }
+ Info_SetValueForKey( info, key, token );
+ }
+ //NOTE: extra space for arena number
+ infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
+ if (infos[count]) {
+ strcpy(infos[count], info);
+ count++;
+ }
+ }
+ return count;
+}
+
+/*
+===============
+UI_LoadArenasFromFile
+===============
+*/
+static void UI_LoadArenasFromFile( char *filename ) {
+ int len;
+ fileHandle_t f;
+ char buf[MAX_ARENAS_TEXT];
+
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( !f ) {
+ trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
+ return;
+ }
+ if ( len >= MAX_ARENAS_TEXT ) {
+ trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i\n", filename, len, MAX_ARENAS_TEXT ) );
+ trap_FS_FCloseFile( f );
+ return;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] );
+}
+
+/*
+===============
+UI_LoadArenas
+===============
+*/
+void UI_LoadArenas( void ) {
+ int numdirs;
+ vmCvar_t arenasFile;
+ char filename[128];
+ char dirlist[1024];
+ char* dirptr;
+ int i, n;
+ int dirlen;
+ char *type;
+
+ ui_numArenas = 0;
+ uiInfo.mapCount = 0;
+
+ trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
+ if( *arenasFile.string ) {
+ UI_LoadArenasFromFile(arenasFile.string);
+ }
+ else {
+ UI_LoadArenasFromFile("scripts/arenas.txt");
+ }
+
+ // get all arenas from .arena files
+ numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 );
+ dirptr = dirlist;
+ for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
+ dirlen = strlen(dirptr);
+ strcpy(filename, "scripts/");
+ strcat(filename, dirptr);
+ UI_LoadArenasFromFile(filename);
+ }
+ trap_Print( va( "%i arenas parsed\n", ui_numArenas ) );
+ if (UI_OutOfMemory()) {
+ trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all arenas\n");
+ }
+
+ for( n = 0; n < ui_numArenas; n++ ) {
+ // determine type
+
+ uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
+ uiInfo.mapList[uiInfo.mapCount].mapLoadName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "map"));
+ uiInfo.mapList[uiInfo.mapCount].mapName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "longname"));
+ uiInfo.mapList[uiInfo.mapCount].levelShot = -1;
+ uiInfo.mapList[uiInfo.mapCount].imageName = String_Alloc(va("levelshots/%s", uiInfo.mapList[uiInfo.mapCount].mapLoadName));
+ uiInfo.mapList[uiInfo.mapCount].typeBits = 0;
+
+ type = Info_ValueForKey( ui_arenaInfos[n], "type" );
+ // if no type specified, it will be treated as "ffa"
+ if( *type ) {
+ if( strstr( type, "ffa" ) ) {
+ uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_FFA);
+ }
+ if( strstr( type, "tourney" ) ) {
+ uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_TOURNAMENT);
+ }
+ if( strstr( type, "ctf" ) ) {
+ uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_CTF);
+ }
+ if( strstr( type, "oneflag" ) ) {
+ uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_1FCTF);
+ }
+ if( strstr( type, "overload" ) ) {
+ uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_OBELISK);
+ }
+ if( strstr( type, "harvester" ) ) {
+ uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_HARVESTER);
+ }
+ if( strstr( type, "elimination" ) ) {
+ uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_ELIMINATION);
+ }
+ if( strstr( type, "ctfelimination" ) ) {
+ uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_CTF_ELIMINATION);
+ }
+ if( strstr( type, "lms" ) ) {
+ uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_LMS);
+ }
+ if( strstr( type, "dd" ) ) {
+ uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_DOUBLE_D);
+ }
+ } else {
+ uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_FFA);
+ }
+
+ uiInfo.mapCount++;
+ if (uiInfo.mapCount >= MAX_MAPS) {
+ break;
+ }
+ }
+}
+
+
+/*
+===============
+UI_LoadBotsFromFile
+===============
+*/
+static void UI_LoadBotsFromFile( char *filename ) {
+ int len;
+ fileHandle_t f;
+ char buf[MAX_BOTS_TEXT];
+
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( !f ) {
+ trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
+ return;
+ }
+ if ( len >= MAX_BOTS_TEXT ) {
+ trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i\n", filename, len, MAX_BOTS_TEXT ) );
+ trap_FS_FCloseFile( f );
+ return;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ COM_Compress(buf);
+
+ ui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] );
+}
+
+/*
+===============
+UI_LoadBots
+===============
+*/
+void UI_LoadBots( void ) {
+ vmCvar_t botsFile;
+ int numdirs;
+ char filename[128];
+ char dirlist[1024];
+ char* dirptr;
+ int i;
+ int dirlen;
+
+ ui_numBots = 0;
+
+ trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
+ if( *botsFile.string ) {
+ UI_LoadBotsFromFile(botsFile.string);
+ }
+ else {
+ UI_LoadBotsFromFile("scripts/bots.txt");
+ }
+
+ // get all bots from .bot files
+ numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
+ dirptr = dirlist;
+ for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
+ dirlen = strlen(dirptr);
+ strcpy(filename, "scripts/");
+ strcat(filename, dirptr);
+ UI_LoadBotsFromFile(filename);
+ }
+ trap_Print( va( "%i bots parsed\n", ui_numBots ) );
+}
+
+
+/*
+===============
+UI_GetBotInfoByNumber
+===============
+*/
+char *UI_GetBotInfoByNumber( int num ) {
+ if( num < 0 || num >= ui_numBots ) {
+ trap_Print( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
+ return NULL;
+ }
+ return ui_botInfos[num];
+}
+
+
+/*
+===============
+UI_GetBotInfoByName
+===============
+*/
+char *UI_GetBotInfoByName( const char *name ) {
+ int n;
+ char *value;
+
+ for ( n = 0; n < ui_numBots ; n++ ) {
+ value = Info_ValueForKey( ui_botInfos[n], "name" );
+ if ( !Q_stricmp( value, name ) ) {
+ return ui_botInfos[n];
+ }
+ }
+
+ return NULL;
+}
+
+int UI_GetNumBots( void ) {
+ return ui_numBots;
+}
+
+
+char *UI_GetBotNameByNumber( int num ) {
+ char *info = UI_GetBotInfoByNumber(num);
+ if (info) {
+ return Info_ValueForKey( info, "name" );
+ }
+ return "Sarge";
+}
diff --git a/code/ui/ui_local.h b/code/ui/ui_local.h
new file mode 100644
index 0000000..2ae60fb
--- /dev/null
+++ b/code/ui/ui_local.h
@@ -0,0 +1,1141 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#ifndef __UI_LOCAL_H__
+#define __UI_LOCAL_H__
+
+#include "../qcommon/q_shared.h"
+#include "../renderer/tr_types.h"
+#include "ui_public.h"
+#include "../client/keycodes.h"
+#include "../game/bg_public.h"
+#include "ui_shared.h"
+
+// global display context
+
+extern vmCvar_t ui_ffa_fraglimit;
+extern vmCvar_t ui_ffa_timelimit;
+
+extern vmCvar_t ui_tourney_fraglimit;
+extern vmCvar_t ui_tourney_timelimit;
+
+extern vmCvar_t ui_team_fraglimit;
+extern vmCvar_t ui_team_timelimit;
+extern vmCvar_t ui_team_friendly;
+
+extern vmCvar_t ui_ctf_capturelimit;
+extern vmCvar_t ui_ctf_timelimit;
+extern vmCvar_t ui_ctf_friendly;
+
+extern vmCvar_t ui_arenasFile;
+extern vmCvar_t ui_botsFile;
+extern vmCvar_t ui_spScores1;
+extern vmCvar_t ui_spScores2;
+extern vmCvar_t ui_spScores3;
+extern vmCvar_t ui_spScores4;
+extern vmCvar_t ui_spScores5;
+extern vmCvar_t ui_spAwards;
+extern vmCvar_t ui_spVideos;
+extern vmCvar_t ui_spSkill;
+
+extern vmCvar_t ui_spSelection;
+
+extern vmCvar_t ui_browserMaster;
+extern vmCvar_t ui_browserGameType;
+extern vmCvar_t ui_browserSortKey;
+extern vmCvar_t ui_browserShowFull;
+extern vmCvar_t ui_browserShowEmpty;
+
+extern vmCvar_t ui_brassTime;
+extern vmCvar_t ui_drawCrosshair;
+extern vmCvar_t ui_drawCrosshairNames;
+extern vmCvar_t ui_marks;
+
+extern vmCvar_t ui_server1;
+extern vmCvar_t ui_server2;
+extern vmCvar_t ui_server3;
+extern vmCvar_t ui_server4;
+extern vmCvar_t ui_server5;
+extern vmCvar_t ui_server6;
+extern vmCvar_t ui_server7;
+extern vmCvar_t ui_server8;
+extern vmCvar_t ui_server9;
+extern vmCvar_t ui_server10;
+extern vmCvar_t ui_server11;
+extern vmCvar_t ui_server12;
+extern vmCvar_t ui_server13;
+extern vmCvar_t ui_server14;
+extern vmCvar_t ui_server15;
+extern vmCvar_t ui_server16;
+
+extern vmCvar_t ui_cdkey;
+extern vmCvar_t ui_cdkeychecked;
+
+extern vmCvar_t ui_captureLimit;
+extern vmCvar_t ui_fragLimit;
+extern vmCvar_t ui_gameType;
+extern vmCvar_t ui_netGameType;
+extern vmCvar_t ui_actualNetGameType;
+extern vmCvar_t ui_joinGameType;
+extern vmCvar_t ui_netSource;
+extern vmCvar_t ui_serverFilterType;
+extern vmCvar_t ui_dedicated;
+extern vmCvar_t ui_opponentName;
+extern vmCvar_t ui_menuFiles;
+extern vmCvar_t ui_currentTier;
+extern vmCvar_t ui_currentMap;
+extern vmCvar_t ui_currentNetMap;
+extern vmCvar_t ui_mapIndex;
+extern vmCvar_t ui_currentOpponent;
+extern vmCvar_t ui_selectedPlayer;
+extern vmCvar_t ui_selectedPlayerName;
+extern vmCvar_t ui_lastServerRefresh_0;
+extern vmCvar_t ui_lastServerRefresh_1;
+extern vmCvar_t ui_lastServerRefresh_2;
+extern vmCvar_t ui_lastServerRefresh_3;
+extern vmCvar_t ui_singlePlayerActive;
+extern vmCvar_t ui_scoreAccuracy;
+extern vmCvar_t ui_scoreImpressives;
+extern vmCvar_t ui_scoreExcellents;
+extern vmCvar_t ui_scoreDefends;
+extern vmCvar_t ui_scoreAssists;
+extern vmCvar_t ui_scoreGauntlets;
+extern vmCvar_t ui_scoreScore;
+extern vmCvar_t ui_scorePerfect;
+extern vmCvar_t ui_scoreTeam;
+extern vmCvar_t ui_scoreBase;
+extern vmCvar_t ui_scoreTimeBonus;
+extern vmCvar_t ui_scoreSkillBonus;
+extern vmCvar_t ui_scoreShutoutBonus;
+extern vmCvar_t ui_scoreTime;
+extern vmCvar_t ui_smallFont;
+extern vmCvar_t ui_bigFont;
+extern vmCvar_t ui_serverStatusTimeOut;
+
+extern vmCvar_t ui_humansonly;
+
+
+
+//
+// ui_qmenu.c
+//
+
+#define RCOLUMN_OFFSET ( BIGCHAR_WIDTH )
+#define LCOLUMN_OFFSET (-BIGCHAR_WIDTH )
+
+#define SLIDER_RANGE 10
+#define MAX_EDIT_LINE 256
+
+#define MAX_MENUDEPTH 8
+#define MAX_MENUITEMS 96
+
+#define MTYPE_NULL 0
+#define MTYPE_SLIDER 1
+#define MTYPE_ACTION 2
+#define MTYPE_SPINCONTROL 3
+#define MTYPE_FIELD 4
+#define MTYPE_RADIOBUTTON 5
+#define MTYPE_BITMAP 6
+#define MTYPE_TEXT 7
+#define MTYPE_SCROLLLIST 8
+#define MTYPE_PTEXT 9
+#define MTYPE_BTEXT 10
+
+#define QMF_BLINK 0x00000001
+#define QMF_SMALLFONT 0x00000002
+#define QMF_LEFT_JUSTIFY 0x00000004
+#define QMF_CENTER_JUSTIFY 0x00000008
+#define QMF_RIGHT_JUSTIFY 0x00000010
+#define QMF_NUMBERSONLY 0x00000020 // edit field is only numbers
+#define QMF_HIGHLIGHT 0x00000040
+#define QMF_HIGHLIGHT_IF_FOCUS 0x00000080 // steady focus
+#define QMF_PULSEIFFOCUS 0x00000100 // pulse if focus
+#define QMF_HASMOUSEFOCUS 0x00000200
+#define QMF_NOONOFFTEXT 0x00000400
+#define QMF_MOUSEONLY 0x00000800 // only mouse input allowed
+#define QMF_HIDDEN 0x00001000 // skips drawing
+#define QMF_GRAYED 0x00002000 // grays and disables
+#define QMF_INACTIVE 0x00004000 // disables any input
+#define QMF_NODEFAULTINIT 0x00008000 // skip default initialization
+#define QMF_OWNERDRAW 0x00010000
+#define QMF_PULSE 0x00020000
+#define QMF_LOWERCASE 0x00040000 // edit field is all lower case
+#define QMF_UPPERCASE 0x00080000 // edit field is all upper case
+#define QMF_SILENT 0x00100000
+
+// callback notifications
+#define QM_GOTFOCUS 1
+#define QM_LOSTFOCUS 2
+#define QM_ACTIVATED 3
+
+typedef struct _tag_menuframework
+{
+ int cursor;
+ int cursor_prev;
+
+ int nitems;
+ void *items[MAX_MENUITEMS];
+
+ void (*draw) (void);
+ sfxHandle_t (*key) (int key);
+
+ qboolean wrapAround;
+ qboolean fullscreen;
+ qboolean showlogo;
+} menuframework_s;
+
+typedef struct
+{
+ int type;
+ const char *name;
+ int id;
+ int x, y;
+ int left;
+ int top;
+ int right;
+ int bottom;
+ menuframework_s *parent;
+ int menuPosition;
+ unsigned flags;
+
+ void (*callback)( void *self, int event );
+ void (*statusbar)( void *self );
+ void (*ownerdraw)( void *self );
+} menucommon_s;
+
+typedef struct {
+ int cursor;
+ int scroll;
+ int widthInChars;
+ char buffer[MAX_EDIT_LINE];
+ int maxchars;
+} mfield_t;
+
+typedef struct
+{
+ menucommon_s generic;
+ mfield_t field;
+} menufield_s;
+
+typedef struct
+{
+ menucommon_s generic;
+
+ float minvalue;
+ float maxvalue;
+ float curvalue;
+
+ float range;
+} menuslider_s;
+
+typedef struct
+{
+ menucommon_s generic;
+
+ int oldvalue;
+ int curvalue;
+ int numitems;
+ int top;
+
+ const char **itemnames;
+
+ int width;
+ int height;
+ int columns;
+ int seperation;
+} menulist_s;
+
+typedef struct
+{
+ menucommon_s generic;
+} menuaction_s;
+
+typedef struct
+{
+ menucommon_s generic;
+ int curvalue;
+} menuradiobutton_s;
+
+typedef struct
+{
+ menucommon_s generic;
+ char* focuspic;
+ char* errorpic;
+ qhandle_t shader;
+ qhandle_t focusshader;
+ int width;
+ int height;
+ float* focuscolor;
+} menubitmap_s;
+
+typedef struct
+{
+ menucommon_s generic;
+ char* string;
+ int style;
+ float* color;
+} menutext_s;
+
+extern void Menu_Cache( void );
+extern void Menu_Focus( menucommon_s *m );
+extern void Menu_AddItem( menuframework_s *menu, void *item );
+extern void Menu_AdjustCursor( menuframework_s *menu, int dir );
+extern void Menu_Draw( menuframework_s *menu );
+extern void *Menu_ItemAtCursor( menuframework_s *m );
+extern sfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item );
+extern void Menu_SetCursor( menuframework_s *s, int cursor );
+extern void Menu_SetCursorToItem( menuframework_s *m, void* ptr );
+extern sfxHandle_t Menu_DefaultKey( menuframework_s *s, int key );
+extern void Bitmap_Init( menubitmap_s *b );
+extern void Bitmap_Draw( menubitmap_s *b );
+extern void ScrollList_Draw( menulist_s *l );
+extern sfxHandle_t ScrollList_Key( menulist_s *l, int key );
+extern sfxHandle_t menu_in_sound;
+extern sfxHandle_t menu_move_sound;
+extern sfxHandle_t menu_out_sound;
+extern sfxHandle_t menu_buzz_sound;
+extern sfxHandle_t menu_null_sound;
+extern sfxHandle_t weaponChangeSound;
+extern vec4_t menu_text_color;
+extern vec4_t menu_grayed_color;
+extern vec4_t menu_dark_color;
+extern vec4_t menu_highlight_color;
+extern vec4_t menu_red_color;
+extern vec4_t menu_black_color;
+extern vec4_t menu_dim_color;
+extern vec4_t color_black;
+extern vec4_t color_white;
+extern vec4_t color_yellow;
+extern vec4_t color_blue;
+extern vec4_t color_orange;
+extern vec4_t color_red;
+extern vec4_t color_dim;
+extern vec4_t name_color;
+extern vec4_t list_color;
+extern vec4_t listbar_color;
+extern vec4_t text_color_disabled;
+extern vec4_t text_color_normal;
+extern vec4_t text_color_highlight;
+
+extern char *ui_medalNames[];
+extern char *ui_medalPicNames[];
+extern char *ui_medalSounds[];
+
+//
+// ui_mfield.c
+//
+extern void MField_Clear( mfield_t *edit );
+extern void MField_KeyDownEvent( mfield_t *edit, int key );
+extern void MField_CharEvent( mfield_t *edit, int ch );
+extern void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color );
+extern void MenuField_Init( menufield_s* m );
+extern void MenuField_Draw( menufield_s *f );
+extern sfxHandle_t MenuField_Key( menufield_s* m, int* key );
+
+//
+// ui_main.c
+//
+void UI_Report( void );
+void UI_Load( void );
+void UI_LoadMenus(const char *menuFile, qboolean reset);
+void _UI_SetActiveMenu( uiMenuCommand_t menu );
+int UI_AdjustTimeByGame(int time);
+void UI_ShowPostGame(qboolean newHigh);
+void UI_ClearScores( void );
+void UI_LoadArenas(void);
+
+//
+// ui_menu.c
+//
+extern void MainMenu_Cache( void );
+extern void UI_MainMenu(void);
+extern void UI_RegisterCvars( void );
+extern void UI_UpdateCvars( void );
+
+//
+// ui_credits.c
+//
+extern void UI_CreditMenu( void );
+
+//
+// ui_ingame.c
+//
+extern void InGame_Cache( void );
+extern void UI_InGameMenu(void);
+
+//
+// ui_confirm.c
+//
+extern void ConfirmMenu_Cache( void );
+extern void UI_ConfirmMenu( const char *question, void (*draw)( void ), void (*action)( qboolean result ) );
+
+//
+// ui_setup.c
+//
+extern void UI_SetupMenu_Cache( void );
+extern void UI_SetupMenu(void);
+
+//
+// ui_team.c
+//
+extern void UI_TeamMainMenu( void );
+extern void TeamMain_Cache( void );
+
+//
+// ui_connect.c
+//
+extern void UI_DrawConnectScreen( qboolean overlay );
+
+//
+// ui_controls2.c
+//
+extern void UI_ControlsMenu( void );
+extern void Controls_Cache( void );
+
+//
+// ui_demo2.c
+//
+extern void UI_DemosMenu( void );
+extern void Demos_Cache( void );
+
+//
+// ui_cinematics.c
+//
+extern void UI_CinematicsMenu( void );
+extern void UI_CinematicsMenu_f( void );
+extern void UI_CinematicsMenu_Cache( void );
+
+//
+// ui_mods.c
+//
+extern void UI_ModsMenu( void );
+extern void UI_ModsMenu_Cache( void );
+
+//
+// ui_cdkey.c
+//
+extern void UI_CDKeyMenu( void );
+extern void UI_CDKeyMenu_Cache( void );
+extern void UI_CDKeyMenu_f( void );
+
+//
+// ui_playermodel.c
+//
+extern void UI_PlayerModelMenu( void );
+extern void PlayerModel_Cache( void );
+
+//
+// ui_playersettings.c
+//
+extern void UI_PlayerSettingsMenu( void );
+extern void PlayerSettings_Cache( void );
+
+//
+// ui_preferences.c
+//
+extern void UI_PreferencesMenu( void );
+extern void Preferences_Cache( void );
+
+//
+// ui_specifyleague.c
+//
+extern void UI_SpecifyLeagueMenu( void );
+extern void SpecifyLeague_Cache( void );
+
+//
+// ui_specifyserver.c
+//
+extern void UI_SpecifyServerMenu( void );
+extern void SpecifyServer_Cache( void );
+
+//
+// ui_servers2.c
+//
+#define MAX_FAVORITESERVERS 16
+
+extern void UI_ArenaServersMenu( void );
+extern void ArenaServers_Cache( void );
+
+//
+// ui_startserver.c
+//
+extern void UI_StartServerMenu( qboolean multiplayer );
+extern void StartServer_Cache( void );
+extern void ServerOptions_Cache( void );
+extern void UI_BotSelectMenu( char *bot );
+extern void UI_BotSelectMenu_Cache( void );
+
+//
+// ui_serverinfo.c
+//
+extern void UI_ServerInfoMenu( void );
+extern void ServerInfo_Cache( void );
+
+//
+// ui_video.c
+//
+extern void UI_GraphicsOptionsMenu( void );
+extern void GraphicsOptions_Cache( void );
+extern void DriverInfo_Cache( void );
+
+//
+// ui_players.c
+//
+
+//FIXME ripped from cg_local.h
+typedef struct {
+ int oldFrame;
+ int oldFrameTime; // time when ->oldFrame was exactly on
+
+ int frame;
+ int frameTime; // time when ->frame will be exactly on
+
+ float backlerp;
+
+ float yawAngle;
+ qboolean yawing;
+ float pitchAngle;
+ qboolean pitching;
+
+ int animationNumber; // may include ANIM_TOGGLEBIT
+ animation_t *animation;
+ int animationTime; // time when the first frame of the animation will be exact
+} lerpFrame_t;
+
+typedef struct {
+ // model info
+ qhandle_t legsModel;
+ qhandle_t legsSkin;
+ lerpFrame_t legs;
+
+ qhandle_t torsoModel;
+ qhandle_t torsoSkin;
+ lerpFrame_t torso;
+
+ qhandle_t headModel;
+ qhandle_t headSkin;
+
+ animation_t animations[MAX_TOTALANIMATIONS];
+
+ qhandle_t weaponModel;
+ qhandle_t barrelModel;
+ qhandle_t flashModel;
+ vec3_t flashDlightColor;
+ int muzzleFlashTime;
+
+ // currently in use drawing parms
+ vec3_t viewAngles;
+ vec3_t moveAngles;
+ weapon_t currentWeapon;
+ int legsAnim;
+ int torsoAnim;
+
+ // animation vars
+ weapon_t weapon;
+ weapon_t lastWeapon;
+ weapon_t pendingWeapon;
+ int weaponTimer;
+ int pendingLegsAnim;
+ int torsoAnimationTimer;
+
+ int pendingTorsoAnim;
+ int legsAnimationTimer;
+
+ qboolean chat;
+ qboolean newModel;
+
+ qboolean barrelSpinning;
+ float barrelAngle;
+ int barrelTime;
+
+ int realWeapon;
+} playerInfo_t;
+
+void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time );
+void UI_DrawPlayerII( float x, float y, float w, float h, playerInfo_t *pi, int time );
+void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model, const char *headmodel, char *teamName );
+void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNum, qboolean chat );
+qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName , const char *headName, const char *teamName);
+
+//
+// ui_atoms.c
+//
+// this is only used in the old ui, the new ui has it's own version
+typedef struct {
+ int frametime;
+ int realtime;
+ int cursorx;
+ int cursory;
+ glconfig_t glconfig;
+ qboolean debug;
+ qhandle_t whiteShader;
+ qhandle_t menuBackShader;
+ qhandle_t menuBackShader2;
+ qhandle_t menuBackNoLogoShader;
+ qhandle_t charset;
+ qhandle_t charsetProp;
+ qhandle_t charsetPropGlow;
+ qhandle_t charsetPropB;
+ qhandle_t cursor;
+ qhandle_t rb_on;
+ qhandle_t rb_off;
+ float scale;
+ float bias;
+ qboolean demoversion;
+ qboolean firstdraw;
+} uiStatic_t;
+
+
+// new ui stuff
+#define UI_NUMFX 7
+#define MAX_HEADS 64
+#define MAX_ALIASES 64
+#define MAX_HEADNAME 32
+#define MAX_TEAMS 64
+#define MAX_GAMETYPES 16
+#define MAX_MAPS 128
+#define MAX_SPMAPS 16
+#define PLAYERS_PER_TEAM 5
+#define MAX_PINGREQUESTS 32
+#define MAX_ADDRESSLENGTH 64
+#define MAX_HOSTNAMELENGTH 22
+#define MAX_MAPNAMELENGTH 16
+#define MAX_STATUSLENGTH 64
+#define MAX_LISTBOXWIDTH 59
+#define UI_FONT_THRESHOLD 0.1
+#define MAX_DISPLAY_SERVERS 2048
+#define MAX_SERVERSTATUS_LINES 128
+#define MAX_SERVERSTATUS_TEXT 1024
+#define MAX_FOUNDPLAYER_SERVERS 16
+#define TEAM_MEMBERS 5
+#define GAMES_ALL 0
+#define GAMES_FFA 1
+#define GAMES_TEAMPLAY 2
+#define GAMES_TOURNEY 3
+#define GAMES_CTF 4
+#define MAPS_PER_TIER 3
+#define MAX_TIERS 16
+#define MAX_MODS 64
+#define MAX_DEMOS 256
+#define MAX_MOVIES 256
+//#define MAX_PLAYERMODELS 256
+#define MAX_PLAYERMODELS 1024
+
+
+
+typedef struct {
+ const char *name;
+ const char *imageName;
+ qhandle_t headImage;
+ const char *base;
+ qboolean active;
+ int reference;
+} characterInfo;
+
+typedef struct {
+ const char *name;
+ const char *ai;
+ const char *action;
+} aliasInfo;
+
+typedef struct {
+ const char *teamName;
+ const char *imageName;
+ const char *teamMembers[TEAM_MEMBERS];
+ qhandle_t teamIcon;
+ qhandle_t teamIcon_Metal;
+ qhandle_t teamIcon_Name;
+ int cinematic;
+} teamInfo;
+
+typedef struct {
+ const char *gameType;
+ int gtEnum;
+} gameTypeInfo;
+
+typedef struct {
+ const char *mapName;
+ const char *mapLoadName;
+ const char *imageName;
+ const char *opponentName;
+ int teamMembers;
+ int typeBits;
+ int cinematic;
+ int timeToBeat[MAX_GAMETYPES];
+ qhandle_t levelShot;
+ qboolean active;
+} mapInfo;
+
+typedef struct {
+ const char *tierName;
+ const char *maps[MAPS_PER_TIER];
+ int gameTypes[MAPS_PER_TIER];
+ qhandle_t mapHandles[MAPS_PER_TIER];
+} tierInfo;
+
+typedef struct serverFilter_s {
+ const char *description;
+ const char *basedir;
+} serverFilter_t;
+
+typedef struct {
+ char adrstr[MAX_ADDRESSLENGTH];
+ int start;
+} pinglist_t;
+
+
+typedef struct serverStatus_s {
+ pinglist_t pingList[MAX_PINGREQUESTS];
+ int numqueriedservers;
+ int currentping;
+ int nextpingtime;
+ int maxservers;
+ int refreshtime;
+ int numServers;
+ int sortKey;
+ int sortDir;
+ int lastCount;
+ qboolean refreshActive;
+ int currentServer;
+ int displayServers[MAX_DISPLAY_SERVERS];
+ int numDisplayServers;
+ int numPlayersOnServers;
+ int nextDisplayRefresh;
+ int nextSortTime;
+ qhandle_t currentServerPreview;
+ int currentServerCinematic;
+ int motdLen;
+ int motdWidth;
+ int motdPaintX;
+ int motdPaintX2;
+ int motdOffset;
+ int motdTime;
+ char motd[MAX_STRING_CHARS];
+} serverStatus_t;
+
+
+typedef struct {
+ char adrstr[MAX_ADDRESSLENGTH];
+ char name[MAX_ADDRESSLENGTH];
+ int startTime;
+ int serverNum;
+ qboolean valid;
+} pendingServer_t;
+
+typedef struct {
+ int num;
+ pendingServer_t server[MAX_SERVERSTATUSREQUESTS];
+} pendingServerStatus_t;
+
+typedef struct {
+ char address[MAX_ADDRESSLENGTH];
+ char *lines[MAX_SERVERSTATUS_LINES][4];
+ char text[MAX_SERVERSTATUS_TEXT];
+ char pings[MAX_CLIENTS * 3];
+ int numLines;
+} serverStatusInfo_t;
+
+typedef struct {
+ const char *modName;
+ const char *modDescr;
+} modInfo_t;
+
+
+typedef struct {
+ displayContextDef_t uiDC;
+ int newHighScoreTime;
+ int newBestTime;
+ int showPostGameTime;
+ qboolean newHighScore;
+ qboolean demoAvailable;
+ qboolean soundHighScore;
+
+ int characterCount;
+ int botIndex;
+ characterInfo characterList[MAX_HEADS];
+
+ int aliasCount;
+ aliasInfo aliasList[MAX_ALIASES];
+
+ int teamCount;
+ teamInfo teamList[MAX_TEAMS];
+
+ int numGameTypes;
+ gameTypeInfo gameTypes[MAX_GAMETYPES];
+
+ int numJoinGameTypes;
+ gameTypeInfo joinGameTypes[MAX_GAMETYPES];
+
+ int redBlue;
+ int playerCount;
+ int myTeamCount;
+ int teamIndex;
+ int playerRefresh;
+ int playerIndex;
+ int playerNumber;
+ qboolean teamLeader;
+ char playerNames[MAX_CLIENTS][MAX_NAME_LENGTH];
+ char teamNames[MAX_CLIENTS][MAX_NAME_LENGTH];
+ int teamClientNums[MAX_CLIENTS];
+
+ int mapCount;
+ mapInfo mapList[MAX_MAPS];
+
+
+ int tierCount;
+ tierInfo tierList[MAX_TIERS];
+
+ int skillIndex;
+
+ modInfo_t modList[MAX_MODS];
+ int modCount;
+ int modIndex;
+
+ const char *demoList[MAX_DEMOS];
+ int demoCount;
+ int demoIndex;
+
+ const char *movieList[MAX_MOVIES];
+ int movieCount;
+ int movieIndex;
+ int previewMovie;
+
+ serverStatus_t serverStatus;
+
+ // for the showing the status of a server
+ char serverStatusAddress[MAX_ADDRESSLENGTH];
+ serverStatusInfo_t serverStatusInfo;
+ int nextServerStatusRefresh;
+
+ // to retrieve the status of server to find a player
+ pendingServerStatus_t pendingServerStatus;
+ char findPlayerName[MAX_STRING_CHARS];
+ char foundPlayerServerAddresses[MAX_FOUNDPLAYER_SERVERS][MAX_ADDRESSLENGTH];
+ char foundPlayerServerNames[MAX_FOUNDPLAYER_SERVERS][MAX_ADDRESSLENGTH];
+ int currentFoundPlayerServer;
+ int numFoundPlayerServers;
+ int nextFindPlayerRefresh;
+
+ int currentCrosshair;
+ int startPostGameTime;
+ sfxHandle_t newHighScoreSound;
+
+ int q3HeadCount;
+ char q3HeadNames[MAX_PLAYERMODELS][64];
+ qhandle_t q3HeadIcons[MAX_PLAYERMODELS];
+ int q3SelectedHead;
+
+ int effectsColor;
+
+ qboolean inGameLoad;
+
+} uiInfo_t;
+
+extern uiInfo_t uiInfo;
+
+
+extern void UI_Init( void );
+extern void UI_Shutdown( void );
+extern void UI_KeyEvent( int key );
+extern void UI_MouseEvent( int dx, int dy );
+extern void UI_Refresh( int realtime );
+extern qboolean UI_ConsoleCommand( int realTime );
+extern float UI_ClampCvar( float min, float max, float value );
+extern void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname );
+extern void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader );
+extern void UI_FillRect( float x, float y, float width, float height, const float *color );
+extern void UI_DrawRect( float x, float y, float width, float height, const float *color );
+extern void UI_DrawTopBottom(float x, float y, float w, float h);
+extern void UI_DrawSides(float x, float y, float w, float h);
+extern void UI_UpdateScreen( void );
+extern void UI_SetColor( const float *rgba );
+extern void UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t);
+extern void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color );
+extern float UI_ProportionalSizeScale( int style );
+extern void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );
+extern int UI_ProportionalStringWidth( const char* str );
+extern void UI_DrawString( int x, int y, const char* str, int style, vec4_t color );
+extern void UI_DrawChar( int x, int y, int ch, int style, vec4_t color );
+extern qboolean UI_CursorInRect (int x, int y, int width, int height);
+extern void UI_AdjustFrom640( float *x, float *y, float *w, float *h );
+extern void UI_DrawTextBox (int x, int y, int width, int lines);
+extern qboolean UI_IsFullscreen( void );
+extern void UI_SetActiveMenu( uiMenuCommand_t menu );
+extern void UI_PushMenu ( menuframework_s *menu );
+extern void UI_PopMenu (void);
+extern void UI_ForceMenuOff (void);
+extern char *UI_Argv( int arg );
+extern char *UI_Cvar_VariableString( const char *var_name );
+extern void UI_Refresh( int time );
+extern void UI_KeyEvent( int key );
+extern void UI_StartDemoLoop( void );
+extern qboolean m_entersound;
+void UI_LoadBestScores(const char *map, int game);
+extern uiStatic_t uis;
+
+//
+// ui_spLevel.c
+//
+void UI_SPLevelMenu_Cache( void );
+void UI_SPLevelMenu( void );
+void UI_SPLevelMenu_f( void );
+void UI_SPLevelMenu_ReInit( void );
+
+//
+// ui_spArena.c
+//
+void UI_SPArena_Start( const char *arenaInfo );
+
+//
+// ui_spPostgame.c
+//
+void UI_SPPostgameMenu_Cache( void );
+void UI_SPPostgameMenu_f( void );
+
+//
+// ui_spSkill.c
+//
+void UI_SPSkillMenu( const char *arenaInfo );
+void UI_SPSkillMenu_Cache( void );
+
+//
+// ui_syscalls.c
+//
+void trap_Print( const char *string );
+void trap_Error( const char *string );
+int trap_Milliseconds( void );
+void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
+void trap_Cvar_Update( vmCvar_t *vmCvar );
+void trap_Cvar_Set( const char *var_name, const char *value );
+float trap_Cvar_VariableValue( const char *var_name );
+void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
+void trap_Cvar_SetValue( const char *var_name, float value );
+void trap_Cvar_Reset( const char *name );
+void trap_Cvar_Create( const char *var_name, const char *var_value, int flags );
+void trap_Cvar_InfoStringBuffer( int bit, char *buffer, int bufsize );
+int trap_Argc( void );
+void trap_Argv( int n, char *buffer, int bufferLength );
+void trap_Cmd_ExecuteText( int exec_when, const char *text ); // don't use EXEC_NOW!
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
+void trap_FS_Read( void *buffer, int len, fileHandle_t f );
+void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
+void trap_FS_FCloseFile( fileHandle_t f );
+int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
+int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
+qhandle_t trap_R_RegisterModel( const char *name );
+qhandle_t trap_R_RegisterSkin( const char *name );
+qhandle_t trap_R_RegisterShaderNoMip( const char *name );
+void trap_R_ClearScene( void );
+void trap_R_AddRefEntityToScene( const refEntity_t *re );
+void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );
+void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
+void trap_R_RenderScene( const refdef_t *fd );
+void trap_R_SetColor( const float *rgba );
+void trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
+void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );
+void trap_UpdateScreen( void );
+int trap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName );
+void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );
+sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed );
+void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen );
+void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen );
+void trap_Key_SetBinding( int keynum, const char *binding );
+qboolean trap_Key_IsDown( int keynum );
+qboolean trap_Key_GetOverstrikeMode( void );
+void trap_Key_SetOverstrikeMode( qboolean state );
+void trap_Key_ClearStates( void );
+int trap_Key_GetCatcher( void );
+void trap_Key_SetCatcher( int catcher );
+void trap_GetClipboardData( char *buf, int bufsize );
+void trap_GetClientState( uiClientState_t *state );
+void trap_GetGlconfig( glconfig_t *glconfig );
+int trap_GetConfigString( int index, char* buff, int buffsize );
+int trap_LAN_GetServerCount( int source );
+void trap_LAN_GetServerAddressString( int source, int n, char *buf, int buflen );
+void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen );
+int trap_LAN_GetServerPing( int source, int n );
+int trap_LAN_GetPingQueueCount( void );
+void trap_LAN_ClearPing( int n );
+void trap_LAN_GetPing( int n, char *buf, int buflen, int *pingtime );
+void trap_LAN_GetPingInfo( int n, char *buf, int buflen );
+void trap_LAN_LoadCachedServers( void );
+void trap_LAN_SaveCachedServers( void );
+void trap_LAN_MarkServerVisible(int source, int n, qboolean visible);
+int trap_LAN_ServerIsVisible( int source, int n);
+qboolean trap_LAN_UpdateVisiblePings( int source );
+int trap_LAN_AddServer(int source, const char *name, const char *addr);
+void trap_LAN_RemoveServer(int source, const char *addr);
+void trap_LAN_ResetPings(int n);
+int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen );
+int trap_LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 );
+int trap_MemoryRemaining( void );
+void trap_GetCDKey( char *buf, int buflen );
+void trap_SetCDKey( char *buf );
+void trap_R_RegisterFont(const char *pFontname, int pointSize, fontInfo_t *font);
+void trap_S_StopBackgroundTrack( void );
+void trap_S_StartBackgroundTrack( const char *intro, const char *loop);
+int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits);
+e_status trap_CIN_StopCinematic(int handle);
+e_status trap_CIN_RunCinematic (int handle);
+void trap_CIN_DrawCinematic (int handle);
+void trap_CIN_SetExtents (int handle, int x, int y, int w, int h);
+int trap_RealTime(qtime_t *qtime);
+void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset );
+qboolean trap_VerifyCDKey( const char *key, const char *chksum);
+
+void trap_SetPbClStatus( int status );
+
+//
+// ui_addbots.c
+//
+void UI_AddBots_Cache( void );
+void UI_AddBotsMenu( void );
+
+//
+// ui_removebots.c
+//
+void UI_RemoveBots_Cache( void );
+void UI_RemoveBotsMenu( void );
+
+//
+// ui_teamorders.c
+//
+extern void UI_TeamOrdersMenu( void );
+extern void UI_TeamOrdersMenu_f( void );
+extern void UI_TeamOrdersMenu_Cache( void );
+
+//
+// ui_loadconfig.c
+//
+void UI_LoadConfig_Cache( void );
+void UI_LoadConfigMenu( void );
+
+//
+// ui_saveconfig.c
+//
+void UI_SaveConfigMenu_Cache( void );
+void UI_SaveConfigMenu( void );
+
+//
+// ui_display.c
+//
+void UI_DisplayOptionsMenu_Cache( void );
+void UI_DisplayOptionsMenu( void );
+
+//
+// ui_sound.c
+//
+void UI_SoundOptionsMenu_Cache( void );
+void UI_SoundOptionsMenu( void );
+
+//
+// ui_network.c
+//
+void UI_NetworkOptionsMenu_Cache( void );
+void UI_NetworkOptionsMenu( void );
+
+//
+// ui_gameinfo.c
+//
+typedef enum {
+ AWARD_ACCURACY,
+ AWARD_IMPRESSIVE,
+ AWARD_EXCELLENT,
+ AWARD_GAUNTLET,
+ AWARD_FRAGS,
+ AWARD_PERFECT
+} awardType_t;
+
+const char *UI_GetArenaInfoByNumber( int num );
+const char *UI_GetArenaInfoByMap( const char *map );
+const char *UI_GetSpecialArenaInfo( const char *tag );
+int UI_GetNumArenas( void );
+int UI_GetNumSPArenas( void );
+int UI_GetNumSPTiers( void );
+
+char *UI_GetBotInfoByNumber( int num );
+char *UI_GetBotInfoByName( const char *name );
+int UI_GetNumBots( void );
+void UI_LoadBots( void );
+char *UI_GetBotNameByNumber( int num );
+
+void UI_GetBestScore( int level, int *score, int *skill );
+void UI_SetBestScore( int level, int score );
+int UI_TierCompleted( int levelWon );
+qboolean UI_ShowTierVideo( int tier );
+qboolean UI_CanShowTierVideo( int tier );
+int UI_GetCurrentGame( void );
+void UI_NewGame( void );
+void UI_LogAwardData( int award, int data );
+int UI_GetAwardLevel( int award );
+
+void UI_SPUnlock_f( void );
+void UI_SPUnlockMedals_f( void );
+
+void UI_InitGameinfo( void );
+
+//
+// ui_login.c
+//
+void Login_Cache( void );
+void UI_LoginMenu( void );
+
+//
+// ui_signup.c
+//
+void Signup_Cache( void );
+void UI_SignupMenu( void );
+
+//
+// ui_rankstatus.c
+//
+void RankStatus_Cache( void );
+void UI_RankStatusMenu( void );
+
+
+// new ui
+
+#define ASSET_BACKGROUND "uiBackground"
+
+// for tracking sp game info in Team Arena
+typedef struct postGameInfo_s {
+ int score;
+ int redScore;
+ int blueScore;
+ int perfects;
+ int accuracy;
+ int impressives;
+ int excellents;
+ int defends;
+ int assists;
+ int gauntlets;
+ int captures;
+ int time;
+ int timeBonus;
+ int shutoutBonus;
+ int skillBonus;
+ int baseScore;
+} postGameInfo_t;
+
+
+
+#endif
diff --git a/code/ui/ui_main.c b/code/ui/ui_main.c
new file mode 100644
index 0000000..fd5505a
--- /dev/null
+++ b/code/ui/ui_main.c
@@ -0,0 +1,6077 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+/*
+=======================================================================
+
+USER INTERFACE MAIN
+
+=======================================================================
+*/
+
+// use this to get a demo build without an explicit demo build, i.e. to get the demo ui files to build
+//#define PRE_RELEASE_TADEMO
+
+#include "ui_local.h"
+
+uiInfo_t uiInfo;
+
+static const char *MonthAbbrev[] = {
+ "Jan","Feb","Mar",
+ "Apr","May","Jun",
+ "Jul","Aug","Sep",
+ "Oct","Nov","Dec"
+};
+
+
+static const char *skillLevels[] = {
+ "I Can Win",
+ "Bring It On",
+ "Hurt Me Plenty",
+ "Hardcore",
+ "Nightmare"
+};
+
+static const int numSkillLevels = sizeof(skillLevels) / sizeof(const char*);
+
+/*
+ *These sources are currently hardcoded in the engine.
+ *
+ *Empty options will not be displayed or circled to.
+ */
+static const char *netSources[] = {
+ "Local",
+ "",
+ "Internet",
+ "Favorites"
+};
+static const int numNetSources = sizeof(netSources) / sizeof(const char*);
+
+static const serverFilter_t serverFilters[] = {
+ {"All", "" },
+ {"OpenArena", "" },
+ {"Missionpack", "missionpack" },
+ {"Rocket Arena", "arena" },
+ {"Alliance", "alliance20" },
+ {"Weapons Factory Arena", "wfa" },
+ {"OSP", "osp" },
+};
+
+static const char *teamArenaGameTypes[] = {
+ "FFA",
+ "TOURNAMENT",
+ "SP",
+ "TEAM DM",
+ "CTF",
+ "1FCTF",
+ "OVERLOAD",
+ "HARVESTER",
+ "ELIMINATION",
+ "CTFELIMINATION",
+ "LMS",
+ "DOUBLE D",
+ "DOMINATION"
+};
+
+static int const numTeamArenaGameTypes = sizeof(teamArenaGameTypes) / sizeof(const char*);
+
+
+static const char *teamArenaGameNames[] = {
+ "Free For All",
+ "Tournament",
+ "Single Player",
+ "Team Deathmatch",
+ "Capture the Flag",
+ "One Flag CTF",
+ "Overload",
+ "Harvester",
+ "Elimination",
+ "CTF Elimination",
+ "Last Man Standing",
+ "Double Domination",
+ "Domination"
+};
+
+static int const numTeamArenaGameNames = sizeof(teamArenaGameNames) / sizeof(const char*);
+
+
+static const int numServerFilters = sizeof(serverFilters) / sizeof(serverFilter_t);
+
+static const char *sortKeys[] = {
+ "Server Name",
+ "Map Name",
+ "Open Player Spots",
+ "Game Type",
+ "Ping Time"
+};
+static const int numSortKeys = sizeof(sortKeys) / sizeof(const char*);
+
+static char* netnames[] = {
+ "???",
+ "UDP",
+ NULL
+};
+
+#ifndef MISSIONPACK // bk001206
+static char quake3worldMessage[] = "Visit www.openarena.ws - News, Community, Events, Files";
+#endif
+
+static int gamecodetoui[] = {4,2,3,0,5,1,6};
+static int uitogamecode[] = {4,6,2,3,1,5,7};
+
+
+static void UI_StartServerRefresh(qboolean full);
+static void UI_StopServerRefresh( void );
+static void UI_DoServerRefresh( void );
+static void UI_FeederSelection(float feederID, int index);
+static void UI_BuildServerDisplayList(qboolean force);
+static void UI_BuildServerStatus(qboolean force);
+static void UI_BuildFindPlayerList(qboolean force);
+static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 );
+static int UI_MapCountByGameType(qboolean singlePlayer);
+static int UI_HeadCountByTeam( void );
+static void UI_ParseGameInfo(const char *teamFile);
+static void UI_ParseTeamInfo(const char *teamFile);
+static const char *UI_SelectedMap(int index, int *actual);
+static const char *UI_SelectedHead(int index, int *actual);
+static int UI_GetIndexFromSelection(int actual);
+
+int ProcessNewUI( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 );
+
+/*
+================
+vmMain
+
+This is the only way control passes into the module.
+This must be the very first function compiled into the .qvm file
+================
+*/
+vmCvar_t ui_new;
+vmCvar_t ui_debug;
+vmCvar_t ui_initialized;
+vmCvar_t ui_teamArenaFirstRun;
+
+void _UI_Init( qboolean );
+void _UI_Shutdown( void );
+void _UI_KeyEvent( int key, qboolean down );
+void _UI_MouseEvent( int dx, int dy );
+void _UI_Refresh( int realtime );
+qboolean _UI_IsFullscreen( void );
+intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
+ switch ( command ) {
+ case UI_GETAPIVERSION:
+ return UI_API_VERSION;
+
+ case UI_INIT:
+ _UI_Init(arg0);
+ return 0;
+
+ case UI_SHUTDOWN:
+ _UI_Shutdown();
+ return 0;
+
+ case UI_KEY_EVENT:
+ _UI_KeyEvent( arg0, arg1 );
+ return 0;
+
+ case UI_MOUSE_EVENT:
+ _UI_MouseEvent( arg0, arg1 );
+ return 0;
+
+ case UI_REFRESH:
+ _UI_Refresh( arg0 );
+ return 0;
+
+ case UI_IS_FULLSCREEN:
+ return _UI_IsFullscreen();
+
+ case UI_SET_ACTIVE_MENU:
+ _UI_SetActiveMenu( arg0 );
+ return 0;
+
+ case UI_CONSOLE_COMMAND:
+ return UI_ConsoleCommand(arg0);
+
+ case UI_DRAW_CONNECT_SCREEN:
+ UI_DrawConnectScreen( arg0 );
+ return 0;
+ case UI_HASUNIQUECDKEY: // mod authors need to observe this
+ return qtrue; // bk010117 - change this to qfalse for mods!
+
+ }
+
+ return -1;
+}
+
+
+
+void AssetCache( void ) {
+ int n;
+ //if (Assets.textFont == NULL) {
+ //}
+ //Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND );
+ //Com_Printf("Menu Size: %i bytes\n", sizeof(Menus));
+ uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
+ uiInfo.uiDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
+ uiInfo.uiDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
+ uiInfo.uiDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
+ uiInfo.uiDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
+ uiInfo.uiDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
+ uiInfo.uiDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
+ uiInfo.uiDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
+ uiInfo.uiDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
+ uiInfo.uiDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
+ uiInfo.uiDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
+ uiInfo.uiDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
+ uiInfo.uiDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
+ uiInfo.uiDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
+ uiInfo.uiDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
+ uiInfo.uiDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
+ uiInfo.uiDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
+
+ for( n = 0; n < NUM_CROSSHAIRS; n++ ) {
+ uiInfo.uiDC.Assets.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a' + n ) );
+ }
+
+ uiInfo.newHighScoreSound = trap_S_RegisterSound("sound/feedback/voc_newhighscore.wav", qfalse);
+}
+
+void _UI_DrawSides(float x, float y, float w, float h, float size) {
+ UI_AdjustFrom640( &x, &y, &w, &h );
+ size *= uiInfo.uiDC.xscale;
+ trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
+ trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
+}
+
+void _UI_DrawTopBottom(float x, float y, float w, float h, float size) {
+ UI_AdjustFrom640( &x, &y, &w, &h );
+ size *= uiInfo.uiDC.yscale;
+ trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
+ trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
+}
+/*
+================
+UI_DrawRect
+
+Coordinates are 640*480 virtual values
+=================
+*/
+void _UI_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
+ trap_R_SetColor( color );
+
+ _UI_DrawTopBottom(x, y, width, height, size);
+ _UI_DrawSides(x, y, width, height, size);
+
+ trap_R_SetColor( NULL );
+}
+
+int Text_Width(const char *text, float scale, int limit) {
+ int count,len;
+ float out;
+ glyphInfo_t *glyph;
+ float useScale;
+ const char *s = text;
+ fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
+ if (scale <= ui_smallFont.value) {
+ font = &uiInfo.uiDC.Assets.smallFont;
+ } else if (scale >= ui_bigFont.value) {
+ font = &uiInfo.uiDC.Assets.bigFont;
+ }
+ useScale = scale * font->glyphScale;
+ out = 0;
+ if (text) {
+ len = strlen(text);
+ if (limit > 0 && len > limit) {
+ len = limit;
+ }
+ count = 0;
+ while (s && *s && count < len) {
+ if ( Q_IsColorString(s) ) {
+ s += 2;
+ continue;
+ } else {
+ glyph = &font->glyphs[(int)*s];
+ out += glyph->xSkip;
+ s++;
+ count++;
+ }
+ }
+ }
+ return out * useScale;
+}
+
+int Text_Height(const char *text, float scale, int limit) {
+ int len, count;
+ float max;
+ glyphInfo_t *glyph;
+ float useScale;
+ const char *s = text; // bk001206 - unsigned
+ fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
+ if (scale <= ui_smallFont.value) {
+ font = &uiInfo.uiDC.Assets.smallFont;
+ } else if (scale >= ui_bigFont.value) {
+ font = &uiInfo.uiDC.Assets.bigFont;
+ }
+ useScale = scale * font->glyphScale;
+ max = 0;
+ if (text) {
+ len = strlen(text);
+ if (limit > 0 && len > limit) {
+ len = limit;
+ }
+ count = 0;
+ while (s && *s && count < len) {
+ if ( Q_IsColorString(s) ) {
+ s += 2;
+ continue;
+ } else {
+ glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
+ if (max < glyph->height) {
+ max = glyph->height;
+ }
+ s++;
+ count++;
+ }
+ }
+ }
+ return max * useScale;
+}
+
+void Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
+ float w, h;
+ w = width * scale;
+ h = height * scale;
+ UI_AdjustFrom640( &x, &y, &w, &h );
+ trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
+}
+
+void Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
+ int len, count;
+ vec4_t newColor;
+ glyphInfo_t *glyph;
+ float useScale;
+ fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
+ if (scale <= ui_smallFont.value) {
+ font = &uiInfo.uiDC.Assets.smallFont;
+ } else if (scale >= ui_bigFont.value) {
+ font = &uiInfo.uiDC.Assets.bigFont;
+ }
+ useScale = scale * font->glyphScale;
+ if (text) {
+ const char *s = text; // bk001206 - unsigned
+ trap_R_SetColor( color );
+ memcpy(&newColor[0], &color[0], sizeof(vec4_t));
+ len = strlen(text);
+ if (limit > 0 && len > limit) {
+ len = limit;
+ }
+ count = 0;
+ while (s && *s && count < len) {
+ glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
+ //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
+ //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
+ if ( Q_IsColorString( s ) ) {
+ memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
+ newColor[3] = color[3];
+ trap_R_SetColor( newColor );
+ s += 2;
+ continue;
+ } else {
+ float yadj = useScale * glyph->top;
+ if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
+ int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
+ colorBlack[3] = newColor[3];
+ trap_R_SetColor( colorBlack );
+ Text_PaintChar(x + ofs, y - yadj + ofs,
+ glyph->imageWidth,
+ glyph->imageHeight,
+ useScale,
+ glyph->s,
+ glyph->t,
+ glyph->s2,
+ glyph->t2,
+ glyph->glyph);
+ trap_R_SetColor( newColor );
+ colorBlack[3] = 1.0;
+ }
+ Text_PaintChar(x, y - yadj,
+ glyph->imageWidth,
+ glyph->imageHeight,
+ useScale,
+ glyph->s,
+ glyph->t,
+ glyph->s2,
+ glyph->t2,
+ glyph->glyph);
+
+ x += (glyph->xSkip * useScale) + adjust;
+ s++;
+ count++;
+ }
+ }
+ trap_R_SetColor( NULL );
+ }
+}
+
+void Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) {
+ int len, count;
+ vec4_t newColor;
+ glyphInfo_t *glyph, *glyph2;
+ float yadj;
+ float useScale;
+ fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
+ if (scale <= ui_smallFont.value) {
+ font = &uiInfo.uiDC.Assets.smallFont;
+ } else if (scale >= ui_bigFont.value) {
+ font = &uiInfo.uiDC.Assets.bigFont;
+ }
+ useScale = scale * font->glyphScale;
+ if (text) {
+ const char *s = text; // bk001206 - unsigned
+ trap_R_SetColor( color );
+ memcpy(&newColor[0], &color[0], sizeof(vec4_t));
+ len = strlen(text);
+ if (limit > 0 && len > limit) {
+ len = limit;
+ }
+ count = 0;
+ glyph2 = &font->glyphs[ (int) cursor]; // bk001206 - possible signed char
+ while (s && *s && count < len) {
+ glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
+ //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
+ //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
+ if ( Q_IsColorString( s ) ) {
+ memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
+ newColor[3] = color[3];
+ trap_R_SetColor( newColor );
+ s += 2;
+ continue;
+ } else {
+ yadj = useScale * glyph->top;
+ if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
+ int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
+ colorBlack[3] = newColor[3];
+ trap_R_SetColor( colorBlack );
+ Text_PaintChar(x + ofs, y - yadj + ofs,
+ glyph->imageWidth,
+ glyph->imageHeight,
+ useScale,
+ glyph->s,
+ glyph->t,
+ glyph->s2,
+ glyph->t2,
+ glyph->glyph);
+ colorBlack[3] = 1.0;
+ trap_R_SetColor( newColor );
+ }
+ Text_PaintChar(x, y - yadj,
+ glyph->imageWidth,
+ glyph->imageHeight,
+ useScale,
+ glyph->s,
+ glyph->t,
+ glyph->s2,
+ glyph->t2,
+ glyph->glyph);
+
+ yadj = useScale * glyph2->top;
+ if (count == cursorPos && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
+ Text_PaintChar(x, y - yadj,
+ glyph2->imageWidth,
+ glyph2->imageHeight,
+ useScale,
+ glyph2->s,
+ glyph2->t,
+ glyph2->s2,
+ glyph2->t2,
+ glyph2->glyph);
+ }
+
+ x += (glyph->xSkip * useScale);
+ s++;
+ count++;
+ }
+ }
+ // need to paint cursor at end of text
+ if (cursorPos == len && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
+ yadj = useScale * glyph2->top;
+ Text_PaintChar(x, y - yadj,
+ glyph2->imageWidth,
+ glyph2->imageHeight,
+ useScale,
+ glyph2->s,
+ glyph2->t,
+ glyph2->s2,
+ glyph2->t2,
+ glyph2->glyph);
+
+ }
+
+ trap_R_SetColor( NULL );
+ }
+}
+
+
+static void Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit) {
+ int len, count;
+ vec4_t newColor;
+ glyphInfo_t *glyph;
+ if (text) {
+ const char *s = text; // bk001206 - unsigned
+ float max = *maxX;
+ float useScale;
+ fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
+ if (scale <= ui_smallFont.value) {
+ font = &uiInfo.uiDC.Assets.smallFont;
+ } else if (scale > ui_bigFont.value) {
+ font = &uiInfo.uiDC.Assets.bigFont;
+ }
+ useScale = scale * font->glyphScale;
+ trap_R_SetColor( color );
+ len = strlen(text);
+ if (limit > 0 && len > limit) {
+ len = limit;
+ }
+ count = 0;
+ while (s && *s && count < len) {
+ glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
+ if ( Q_IsColorString( s ) ) {
+ memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
+ newColor[3] = color[3];
+ trap_R_SetColor( newColor );
+ s += 2;
+ continue;
+ } else {
+ float yadj = useScale * glyph->top;
+ if (Text_Width(s, useScale, 1) + x > max) {
+ *maxX = 0;
+ break;
+ }
+ Text_PaintChar(x, y - yadj,
+ glyph->imageWidth,
+ glyph->imageHeight,
+ useScale,
+ glyph->s,
+ glyph->t,
+ glyph->s2,
+ glyph->t2,
+ glyph->glyph);
+ x += (glyph->xSkip * useScale) + adjust;
+ *maxX = x;
+ count++;
+ s++;
+ }
+ }
+ trap_R_SetColor( NULL );
+ }
+
+}
+
+
+void UI_ShowPostGame(qboolean newHigh) {
+ trap_Cvar_Set ("cg_cameraOrbit", "0");
+ trap_Cvar_Set("cg_thirdPerson", "0");
+ uiInfo.soundHighScore = newHigh;
+ _UI_SetActiveMenu(UIMENU_POSTGAME);
+}
+/*
+=================
+_UI_Refresh
+=================
+*/
+
+void UI_DrawCenteredPic(qhandle_t image, int w, int h) {
+ int x, y;
+ x = (SCREEN_WIDTH - w) / 2;
+ y = (SCREEN_HEIGHT - h) / 2;
+ UI_DrawHandlePic(x, y, w, h, image);
+}
+
+int frameCount = 0;
+int startTime;
+
+#define UI_FPS_FRAMES 4
+void _UI_Refresh( int realtime )
+{
+ static int index;
+ static int previousTimes[UI_FPS_FRAMES];
+
+ //if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
+ // return;
+ //}
+
+ uiInfo.uiDC.frameTime = realtime - uiInfo.uiDC.realTime;
+ uiInfo.uiDC.realTime = realtime;
+
+ previousTimes[index % UI_FPS_FRAMES] = uiInfo.uiDC.frameTime;
+ index++;
+ if ( index > UI_FPS_FRAMES ) {
+ int i, total;
+ // average multiple frames together to smooth changes out a bit
+ total = 0;
+ for ( i = 0 ; i < UI_FPS_FRAMES ; i++ ) {
+ total += previousTimes[i];
+ }
+ if ( !total ) {
+ total = 1;
+ }
+ uiInfo.uiDC.FPS = 1000 * UI_FPS_FRAMES / total;
+ }
+
+
+
+ UI_UpdateCvars();
+
+ if (Menu_Count() > 0) {
+ // paint all the menus
+ Menu_PaintAll();
+ // refresh server browser list
+ UI_DoServerRefresh();
+ // refresh server status
+ UI_BuildServerStatus(qfalse);
+ // refresh find player list
+ UI_BuildFindPlayerList(qfalse);
+ }
+
+ // draw cursor
+ UI_SetColor( NULL );
+ if (Menu_Count() > 0) {
+ UI_DrawHandlePic( uiInfo.uiDC.cursorx-16, uiInfo.uiDC.cursory-16, 32, 32, uiInfo.uiDC.Assets.cursor);
+ }
+
+#ifndef NDEBUG
+ if (uiInfo.uiDC.debug)
+ {
+ // cursor coordinates
+ //FIXME
+ //UI_DrawString( 0, 0, va("(%d,%d)",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed );
+ }
+#endif
+
+}
+
+/*
+=================
+_UI_Shutdown
+=================
+*/
+void _UI_Shutdown( void ) {
+ trap_LAN_SaveCachedServers();
+}
+
+char *defaultMenu = NULL;
+
+char *GetMenuBuffer(const char *filename) {
+ int len;
+ fileHandle_t f;
+ static char buf[MAX_MENUFILE];
+
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( !f ) {
+ trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
+ return defaultMenu;
+ }
+ if ( len >= MAX_MENUFILE ) {
+ trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i\n", filename, len, MAX_MENUFILE ) );
+ trap_FS_FCloseFile( f );
+ return defaultMenu;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+ //COM_Compress(buf);
+ return buf;
+
+}
+
+qboolean Asset_Parse(int handle) {
+ pc_token_t token;
+ const char *tempStr;
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+ if (Q_stricmp(token.string, "{") != 0) {
+ return qfalse;
+ }
+
+ while ( 1 ) {
+
+ memset(&token, 0, sizeof(pc_token_t));
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+
+ if (Q_stricmp(token.string, "}") == 0) {
+ return qtrue;
+ }
+
+ // font
+ if (Q_stricmp(token.string, "font") == 0) {
+ int pointSize;
+ if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
+ return qfalse;
+ }
+ trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.textFont);
+ uiInfo.uiDC.Assets.fontRegistered = qtrue;
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "smallFont") == 0) {
+ int pointSize;
+ if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
+ return qfalse;
+ }
+ trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.smallFont);
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "bigFont") == 0) {
+ int pointSize;
+ if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
+ return qfalse;
+ }
+ trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.bigFont);
+ continue;
+ }
+
+
+ // gradientbar
+ if (Q_stricmp(token.string, "gradientbar") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
+ continue;
+ }
+
+ // enterMenuSound
+ if (Q_stricmp(token.string, "menuEnterSound") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ uiInfo.uiDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse );
+ continue;
+ }
+
+ // exitMenuSound
+ if (Q_stricmp(token.string, "menuExitSound") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ uiInfo.uiDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse );
+ continue;
+ }
+
+ // itemFocusSound
+ if (Q_stricmp(token.string, "itemFocusSound") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ uiInfo.uiDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse );
+ continue;
+ }
+
+ // menuBuzzSound
+ if (Q_stricmp(token.string, "menuBuzzSound") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ uiInfo.uiDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse );
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "cursor") == 0) {
+ if (!PC_String_Parse(handle, &uiInfo.uiDC.Assets.cursorStr)) {
+ return qfalse;
+ }
+ uiInfo.uiDC.Assets.cursor = trap_R_RegisterShaderNoMip( uiInfo.uiDC.Assets.cursorStr);
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "fadeClamp") == 0) {
+ if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeClamp)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "fadeCycle") == 0) {
+ if (!PC_Int_Parse(handle, &uiInfo.uiDC.Assets.fadeCycle)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "fadeAmount") == 0) {
+ if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeAmount)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "shadowX") == 0) {
+ if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowX)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "shadowY") == 0) {
+ if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowY)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "shadowColor") == 0) {
+ if (!PC_Color_Parse(handle, &uiInfo.uiDC.Assets.shadowColor)) {
+ return qfalse;
+ }
+ uiInfo.uiDC.Assets.shadowFadeClamp = uiInfo.uiDC.Assets.shadowColor[3];
+ continue;
+ }
+
+ }
+ return qfalse;
+}
+
+void Font_Report( void ) {
+ int i;
+ Com_Printf("Font Info\n");
+ Com_Printf("=========\n");
+ for ( i = 32; i < 96; i++) {
+ Com_Printf("Glyph handle %i: %i\n", i, uiInfo.uiDC.Assets.textFont.glyphs[i].glyph);
+ }
+}
+
+void UI_Report( void ) {
+ String_Report();
+ //Font_Report();
+
+}
+
+void UI_ParseMenu(const char *menuFile) {
+ int handle;
+ pc_token_t token;
+
+ Com_Printf("Parsing menu file:%s\n", menuFile);
+
+ handle = trap_PC_LoadSource(menuFile);
+ if (!handle) {
+ return;
+ }
+
+ while ( 1 ) {
+ memset(&token, 0, sizeof(pc_token_t));
+ if (!trap_PC_ReadToken( handle, &token )) {
+ break;
+ }
+
+ //if ( Q_stricmp( token, "{" ) ) {
+ // Com_Printf( "Missing { in menu file\n" );
+ // break;
+ //}
+
+ //if ( menuCount == MAX_MENUS ) {
+ // Com_Printf( "Too many menus!\n" );
+ // break;
+ //}
+
+ if ( token.string[0] == '}' ) {
+ break;
+ }
+
+ if (Q_stricmp(token.string, "assetGlobalDef") == 0) {
+ if (Asset_Parse(handle)) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (Q_stricmp(token.string, "menudef") == 0) {
+ // start a new menu
+ Menu_New(handle);
+ }
+ }
+ trap_PC_FreeSource(handle);
+}
+
+qboolean Load_Menu(int handle) {
+ pc_token_t token;
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+ if (token.string[0] != '{') {
+ return qfalse;
+ }
+
+ while ( 1 ) {
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+
+ if ( token.string[0] == 0 ) {
+ return qfalse;
+ }
+
+ if ( token.string[0] == '}' ) {
+ return qtrue;
+ }
+
+ UI_ParseMenu(token.string);
+ }
+ return qfalse;
+}
+
+void UI_LoadMenus(const char *menuFile, qboolean reset) {
+ pc_token_t token;
+ int handle;
+ int start;
+
+ start = trap_Milliseconds();
+
+ handle = trap_PC_LoadSource( menuFile );
+ if (!handle) {
+ trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );
+ handle = trap_PC_LoadSource( "ui/menus.txt" );
+ if (!handle) {
+ trap_Error( va( S_COLOR_RED "default menu file not found: ui/menus.txt, unable to continue!\n") );
+ }
+ }
+
+ ui_new.integer = 1;
+
+ if (reset) {
+ Menu_Reset();
+ }
+
+ while ( 1 ) {
+ if (!trap_PC_ReadToken(handle, &token))
+ break;
+ if( token.string[0] == 0 || token.string[0] == '}') {
+ break;
+ }
+
+ if ( token.string[0] == '}' ) {
+ break;
+ }
+
+ if (Q_stricmp(token.string, "loadmenu") == 0) {
+ if (Load_Menu(handle)) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ }
+
+ Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start);
+
+ trap_PC_FreeSource( handle );
+}
+
+void UI_Load(void) {
+ char lastName[1024];
+ menuDef_t *menu = Menu_GetFocused();
+ char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
+ if (menu && menu->window.name) {
+ strcpy(lastName, menu->window.name);
+ }
+ if (menuSet == NULL || menuSet[0] == '\0') {
+ menuSet = "ui/menus.txt";
+ }
+
+ String_Init();
+
+#ifdef PRE_RELEASE_TADEMO
+ UI_ParseGameInfo("demogameinfo.txt");
+#else
+ UI_ParseGameInfo("gameinfo.txt");
+ UI_LoadArenas();
+#endif
+
+ UI_LoadMenus(menuSet, qtrue);
+ Menus_CloseAll();
+ Menus_ActivateByName(lastName);
+
+}
+
+static const char *handicapValues[] = {"None","95","90","85","80","75","70","65","60","55","50","45","40","35","30","25","20","15","10","5",NULL};
+#ifndef MISSIONPACK // bk001206
+static int numHandicaps = sizeof(handicapValues) / sizeof(const char*);
+#endif
+
+static void UI_DrawHandicap(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ int i, h;
+
+ h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
+ i = 20 - h / 5;
+
+ Text_Paint(rect->x, rect->y, scale, color, handicapValues[i], 0, 0, textStyle);
+}
+
+static void UI_DrawClanName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_teamName"), 0, 0, textStyle);
+}
+
+
+static void UI_SetCapFragLimits(qboolean uiVars) {
+ int cap = 5;
+ int frag = 10;
+ if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_OBELISK) {
+ cap = 4;
+ } else if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_HARVESTER) {
+ cap = 15;
+ }
+ if (uiVars) {
+ trap_Cvar_Set("ui_captureLimit", va("%d", cap));
+ trap_Cvar_Set("ui_fragLimit", va("%d", frag));
+ } else {
+ trap_Cvar_Set("capturelimit", va("%d", cap));
+ trap_Cvar_Set("fraglimit", va("%d", frag));
+ }
+}
+// ui_gameType assumes gametype 0 is -1 ALL and will not show
+static void UI_DrawGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_gameType.integer].gameType, 0, 0, textStyle);
+}
+
+static void UI_DrawNetGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ if (ui_netGameType.integer < 0 || ui_netGameType.integer > uiInfo.numGameTypes) {
+ trap_Cvar_Set("ui_netGameType", "0");
+ trap_Cvar_Set("ui_actualNetGameType", "0");
+ }
+ Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_netGameType.integer].gameType , 0, 0, textStyle);
+}
+
+static void UI_DrawJoinGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ if (ui_joinGameType.integer < 0 || ui_joinGameType.integer > uiInfo.numJoinGameTypes) {
+ trap_Cvar_Set("ui_joinGameType", "0");
+ }
+ Text_Paint(rect->x, rect->y, scale, color, uiInfo.joinGameTypes[ui_joinGameType.integer].gameType , 0, 0, textStyle);
+}
+
+
+
+static int UI_TeamIndexFromName(const char *name) {
+ int i;
+
+ if (name && *name) {
+ for (i = 0; i < uiInfo.teamCount; i++) {
+ if (Q_stricmp(name, uiInfo.teamList[i].teamName) == 0) {
+ return i;
+ }
+ }
+ }
+
+ return 0;
+
+}
+
+static void UI_DrawClanLogo(rectDef_t *rect, float scale, vec4_t color) {
+ int i;
+ i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+ if (i >= 0 && i < uiInfo.teamCount) {
+ trap_R_SetColor( color );
+
+ if (uiInfo.teamList[i].teamIcon == -1) {
+ uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
+ uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
+ uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
+ }
+
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
+ trap_R_SetColor(NULL);
+ }
+}
+
+static void UI_DrawClanCinematic(rectDef_t *rect, float scale, vec4_t color) {
+ int i;
+ i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+ if (i >= 0 && i < uiInfo.teamCount) {
+
+ if (uiInfo.teamList[i].cinematic >= -2) {
+ if (uiInfo.teamList[i].cinematic == -1) {
+ uiInfo.teamList[i].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.teamList[i].imageName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
+ }
+ if (uiInfo.teamList[i].cinematic >= 0) {
+ trap_CIN_RunCinematic(uiInfo.teamList[i].cinematic);
+ trap_CIN_SetExtents(uiInfo.teamList[i].cinematic, rect->x, rect->y, rect->w, rect->h);
+ trap_CIN_DrawCinematic(uiInfo.teamList[i].cinematic);
+ } else {
+ trap_R_SetColor( color );
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal);
+ trap_R_SetColor(NULL);
+ uiInfo.teamList[i].cinematic = -2;
+ }
+ } else {
+ trap_R_SetColor( color );
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
+ trap_R_SetColor(NULL);
+ }
+ }
+
+}
+
+static void UI_DrawPreviewCinematic(rectDef_t *rect, float scale, vec4_t color) {
+ if (uiInfo.previewMovie > -2) {
+ uiInfo.previewMovie = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.movieList[uiInfo.movieIndex]), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
+ if (uiInfo.previewMovie >= 0) {
+ trap_CIN_RunCinematic(uiInfo.previewMovie);
+ trap_CIN_SetExtents(uiInfo.previewMovie, rect->x, rect->y, rect->w, rect->h);
+ trap_CIN_DrawCinematic(uiInfo.previewMovie);
+ } else {
+ uiInfo.previewMovie = -2;
+ }
+ }
+
+}
+
+
+
+static void UI_DrawSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ int i;
+ i = trap_Cvar_VariableValue( "g_spSkill" );
+ if (i < 1 || i > numSkillLevels) {
+ i = 1;
+ }
+ Text_Paint(rect->x, rect->y, scale, color, skillLevels[i-1],0, 0, textStyle);
+}
+
+
+static void UI_DrawTeamName(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int textStyle) {
+ int i;
+ i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
+ if (i >= 0 && i < uiInfo.teamCount) {
+ Text_Paint(rect->x, rect->y, scale, color, va("%s: %s", (blue) ? "Blue" : "Red", uiInfo.teamList[i].teamName),0, 0, textStyle);
+ }
+}
+
+static void UI_DrawTeamMember(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int num, int textStyle) {
+ // 0 - None
+ // 1 - Human
+ // 2..NumCharacters - Bot
+ int value = trap_Cvar_VariableValue(va(blue ? "ui_blueteam%i" : "ui_redteam%i", num));
+ const char *text;
+ if (value <= 0) {
+ text = "Closed";
+ } else if (value == 1) {
+ text = "Human";
+ } else {
+ value -= 2;
+
+ if (ui_actualNetGameType.integer >= GT_TEAM) {
+ if (value >= uiInfo.characterCount) {
+ value = 0;
+ }
+ text = uiInfo.characterList[value].name;
+ } else {
+ if (value >= UI_GetNumBots()) {
+ value = 0;
+ }
+ text = UI_GetBotNameByNumber(value);
+ }
+ }
+ Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
+}
+
+static void UI_DrawEffects(rectDef_t *rect, float scale, vec4_t color) {
+ UI_DrawHandlePic( rect->x, rect->y - 14, 128, 8, uiInfo.uiDC.Assets.fxBasePic );
+ UI_DrawHandlePic( rect->x + uiInfo.effectsColor * 16 + 8, rect->y - 16, 16, 12, uiInfo.uiDC.Assets.fxPic[uiInfo.effectsColor] );
+}
+
+static void UI_DrawMapPreview(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
+ int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
+ if (map < 0 || map > uiInfo.mapCount) {
+ if (net) {
+ ui_currentNetMap.integer = 0;
+ trap_Cvar_Set("ui_currentNetMap", "0");
+ } else {
+ ui_currentMap.integer = 0;
+ trap_Cvar_Set("ui_currentMap", "0");
+ }
+ map = 0;
+ }
+
+ if (uiInfo.mapList[map].levelShot == -1) {
+ uiInfo.mapList[map].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[map].imageName);
+ }
+
+ if (uiInfo.mapList[map].levelShot > 0) {
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.mapList[map].levelShot);
+ } else {
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("menu/art/unknownmap"));
+ }
+}
+
+
+static void UI_DrawMapTimeToBeat(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ int minutes, seconds, time;
+ if (ui_currentMap.integer < 0 || ui_currentMap.integer > uiInfo.mapCount) {
+ ui_currentMap.integer = 0;
+ trap_Cvar_Set("ui_currentMap", "0");
+ }
+
+ time = uiInfo.mapList[ui_currentMap.integer].timeToBeat[uiInfo.gameTypes[ui_gameType.integer].gtEnum];
+
+ minutes = time / 60;
+ seconds = time % 60;
+
+ Text_Paint(rect->x, rect->y, scale, color, va("%02i:%02i", minutes, seconds), 0, 0, textStyle);
+}
+
+
+
+static void UI_DrawMapCinematic(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
+
+ int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
+ if (map < 0 || map > uiInfo.mapCount) {
+ if (net) {
+ ui_currentNetMap.integer = 0;
+ trap_Cvar_Set("ui_currentNetMap", "0");
+ } else {
+ ui_currentMap.integer = 0;
+ trap_Cvar_Set("ui_currentMap", "0");
+ }
+ map = 0;
+ }
+
+ if (uiInfo.mapList[map].cinematic >= -1) {
+ if (uiInfo.mapList[map].cinematic == -1) {
+ uiInfo.mapList[map].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[map].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
+ }
+ if (uiInfo.mapList[map].cinematic >= 0) {
+ trap_CIN_RunCinematic(uiInfo.mapList[map].cinematic);
+ trap_CIN_SetExtents(uiInfo.mapList[map].cinematic, rect->x, rect->y, rect->w, rect->h);
+ trap_CIN_DrawCinematic(uiInfo.mapList[map].cinematic);
+ } else {
+ uiInfo.mapList[map].cinematic = -2;
+ }
+ } else {
+ UI_DrawMapPreview(rect, scale, color, net);
+ }
+}
+
+
+
+static qboolean updateModel = qtrue;
+static qboolean q3Model = qfalse;
+
+static void UI_DrawPlayerModel(rectDef_t *rect) {
+ static playerInfo_t info;
+ char model[MAX_QPATH];
+ char team[256];
+ char head[256];
+ vec3_t viewangles;
+ vec3_t moveangles;
+
+ if (trap_Cvar_VariableValue("ui_Q3Model")) {
+ strcpy(model, UI_Cvar_VariableString("model"));
+ strcpy(head, UI_Cvar_VariableString("headmodel"));
+ if (!q3Model) {
+ q3Model = qtrue;
+ updateModel = qtrue;
+ }
+ team[0] = '\0';
+ } else {
+
+ strcpy(team, UI_Cvar_VariableString("ui_teamName"));
+ strcpy(model, UI_Cvar_VariableString("team_model"));
+ strcpy(head, UI_Cvar_VariableString("team_headmodel"));
+ if (q3Model) {
+ q3Model = qfalse;
+ updateModel = qtrue;
+ }
+ }
+ if (updateModel) {
+ memset( &info, 0, sizeof(playerInfo_t) );
+ viewangles[YAW] = 180 - 10;
+ viewangles[PITCH] = 0;
+ viewangles[ROLL] = 0;
+ VectorClear( moveangles );
+ UI_PlayerInfo_SetModel( &info, model, head, team);
+ UI_PlayerInfo_SetInfo( &info, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
+// UI_RegisterClientModelname( &info, model, head, team);
+ updateModel = qfalse;
+ }
+
+ UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info, uiInfo.uiDC.realTime / 2);
+
+}
+
+static void UI_DrawPlayerModel2(rectDef_t *rect) {
+ static playerInfo_t info;
+ char model[MAX_QPATH];
+ char team[256];
+ char head[256];
+ vec3_t viewangles;
+ vec3_t moveangles;
+
+ if (trap_Cvar_VariableValue("ui_Q3Model")) {
+ strcpy(model, UI_Cvar_VariableString("model"));
+ strcpy(head, UI_Cvar_VariableString("headmodel"));
+ if (!q3Model) {
+ q3Model = qtrue;
+ updateModel = qtrue;
+ }
+ team[0] = '\0';
+ } else {
+
+ strcpy(team, UI_Cvar_VariableString("ui_teamName"));
+ strcpy(model, UI_Cvar_VariableString("team_model"));
+ strcpy(head, UI_Cvar_VariableString("team_headmodel"));
+ if (q3Model) {
+ q3Model = qfalse;
+ updateModel = qtrue;
+ }
+ }
+ if (updateModel) {
+ memset( &info, 0, sizeof(playerInfo_t) );
+ viewangles[YAW] = 180 - 10;
+ viewangles[PITCH] = 0;
+ viewangles[ROLL] = 0;
+ VectorClear( moveangles );
+ UI_PlayerInfo_SetModel( &info, model, head, team);
+ UI_PlayerInfo_SetInfo( &info, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
+// UI_RegisterClientModelname( &info, model, head, team);
+ updateModel = qfalse;
+ }
+
+ UI_DrawPlayerII( rect->x, rect->y, rect->w, rect->h, &info, uiInfo.uiDC.realTime / 2);
+
+}
+
+
+static void UI_DrawNetSource(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ if (ui_netSource.integer < 0 || ui_netSource.integer > numNetSources) {
+ ui_netSource.integer = 0;
+ }
+ Text_Paint(rect->x, rect->y, scale, color, va("Source: %s", netSources[ui_netSource.integer]), 0, 0, textStyle);
+}
+
+static void UI_DrawNetMapPreview(rectDef_t *rect, float scale, vec4_t color) {
+
+ if (uiInfo.serverStatus.currentServerPreview > 0) {
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.serverStatus.currentServerPreview);
+ } else {
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("menu/art/unknownmap"));
+ }
+}
+
+static void UI_DrawNetMapCinematic(rectDef_t *rect, float scale, vec4_t color) {
+ if (ui_currentNetMap.integer < 0 || ui_currentNetMap.integer > uiInfo.mapCount) {
+ ui_currentNetMap.integer = 0;
+ trap_Cvar_Set("ui_currentNetMap", "0");
+ }
+
+ if (uiInfo.serverStatus.currentServerCinematic >= 0) {
+ trap_CIN_RunCinematic(uiInfo.serverStatus.currentServerCinematic);
+ trap_CIN_SetExtents(uiInfo.serverStatus.currentServerCinematic, rect->x, rect->y, rect->w, rect->h);
+ trap_CIN_DrawCinematic(uiInfo.serverStatus.currentServerCinematic);
+ } else {
+ UI_DrawNetMapPreview(rect, scale, color);
+ }
+}
+
+
+
+static void UI_DrawNetFilter(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
+ ui_serverFilterType.integer = 0;
+ }
+ Text_Paint(rect->x, rect->y, scale, color, va("Filter: %s", serverFilters[ui_serverFilterType.integer].description), 0, 0, textStyle);
+}
+
+
+static void UI_DrawTier(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ int i;
+ i = trap_Cvar_VariableValue( "ui_currentTier" );
+ if (i < 0 || i >= uiInfo.tierCount) {
+ i = 0;
+ }
+ Text_Paint(rect->x, rect->y, scale, color, va("Tier: %s", uiInfo.tierList[i].tierName),0, 0, textStyle);
+}
+
+static void UI_DrawTierMap(rectDef_t *rect, int index) {
+ int i;
+ i = trap_Cvar_VariableValue( "ui_currentTier" );
+ if (i < 0 || i >= uiInfo.tierCount) {
+ i = 0;
+ }
+
+ if (uiInfo.tierList[i].mapHandles[index] == -1) {
+ uiInfo.tierList[i].mapHandles[index] = trap_R_RegisterShaderNoMip(va("levelshots/%s", uiInfo.tierList[i].maps[index]));
+ }
+
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.tierList[i].mapHandles[index]);
+}
+
+static const char *UI_EnglishMapName(const char *map) {
+ int i;
+ for (i = 0; i < uiInfo.mapCount; i++) {
+ if (Q_stricmp(map, uiInfo.mapList[i].mapLoadName) == 0) {
+ return uiInfo.mapList[i].mapName;
+ }
+ }
+ return "";
+}
+
+static void UI_DrawTierMapName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ int i, j;
+ i = trap_Cvar_VariableValue( "ui_currentTier" );
+ if (i < 0 || i >= uiInfo.tierCount) {
+ i = 0;
+ }
+ j = trap_Cvar_VariableValue("ui_currentMap");
+ if (j < 0 || j > MAPS_PER_TIER) {
+ j = 0;
+ }
+
+ Text_Paint(rect->x, rect->y, scale, color, UI_EnglishMapName(uiInfo.tierList[i].maps[j]), 0, 0, textStyle);
+}
+
+static void UI_DrawTierGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ int i, j;
+ i = trap_Cvar_VariableValue( "ui_currentTier" );
+ if (i < 0 || i >= uiInfo.tierCount) {
+ i = 0;
+ }
+ j = trap_Cvar_VariableValue("ui_currentMap");
+ if (j < 0 || j > MAPS_PER_TIER) {
+ j = 0;
+ }
+
+ Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[uiInfo.tierList[i].gameTypes[j]].gameType , 0, 0, textStyle);
+}
+
+
+#ifndef MISSIONPACK // bk001206
+static const char *UI_OpponentLeaderName(void) {
+ int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
+ return uiInfo.teamList[i].teamMembers[0];
+}
+#endif
+
+static const char *UI_AIFromName(const char *name) {
+ int j;
+ for (j = 0; j < uiInfo.aliasCount; j++) {
+ if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
+ return uiInfo.aliasList[j].ai;
+ }
+ }
+ return "sergei";
+}
+
+#ifndef MISSIONPACK // bk001206
+static const int UI_AIIndex(const char *name) {
+ int j;
+ for (j = 0; j < uiInfo.characterCount; j++) {
+ if (Q_stricmp(name, uiInfo.characterList[j].name) == 0) {
+ return j;
+ }
+ }
+ return 0;
+}
+#endif
+
+#ifndef MISSIONPACK // bk001206
+static const int UI_AIIndexFromName(const char *name) {
+ int j;
+ for (j = 0; j < uiInfo.aliasCount; j++) {
+ if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
+ return UI_AIIndex(uiInfo.aliasList[j].ai);
+ }
+ }
+ return 0;
+}
+#endif
+
+
+#ifndef MISSIONPACK // bk001206
+static const char *UI_OpponentLeaderHead(void) {
+ const char *leader = UI_OpponentLeaderName();
+ return UI_AIFromName(leader);
+}
+#endif
+
+#ifndef MISSIONPACK // bk001206
+static const char *UI_OpponentLeaderModel(void) {
+ int i;
+ const char *head = UI_OpponentLeaderHead();
+ for (i = 0; i < uiInfo.characterCount; i++) {
+ if (Q_stricmp(head, uiInfo.characterList[i].name) == 0) {
+ return uiInfo.characterList[i].base;
+ }
+ }
+ return "sergei";
+}
+#endif
+
+
+static qboolean updateOpponentModel = qtrue;
+static void UI_DrawOpponent(rectDef_t *rect) {
+ static playerInfo_t info2;
+ char model[MAX_QPATH];
+ char headmodel[MAX_QPATH];
+ char team[256];
+ vec3_t viewangles;
+ vec3_t moveangles;
+
+ if (updateOpponentModel) {
+
+ strcpy(model, UI_Cvar_VariableString("ui_opponentModel"));
+ strcpy(headmodel, UI_Cvar_VariableString("ui_opponentModel"));
+ team[0] = '\0';
+
+ memset( &info2, 0, sizeof(playerInfo_t) );
+ viewangles[YAW] = 180 - 10;
+ viewangles[PITCH] = 0;
+ viewangles[ROLL] = 0;
+ VectorClear( moveangles );
+ UI_PlayerInfo_SetModel( &info2, model, headmodel, "");
+ UI_PlayerInfo_SetInfo( &info2, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
+ UI_RegisterClientModelname( &info2, model, headmodel, team);
+ updateOpponentModel = qfalse;
+ }
+
+ UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info2, uiInfo.uiDC.realTime / 2);
+
+}
+
+static void UI_DrawOpponent2(rectDef_t *rect) {
+ static playerInfo_t info2;
+ char model[MAX_QPATH];
+ char headmodel[MAX_QPATH];
+ char team[256];
+ vec3_t viewangles;
+ vec3_t moveangles;
+
+ if (updateOpponentModel) {
+
+ strcpy(model, UI_Cvar_VariableString("ui_opponentModel"));
+ strcpy(headmodel, UI_Cvar_VariableString("ui_opponentModel"));
+ team[0] = '\0';
+
+ memset( &info2, 0, sizeof(playerInfo_t) );
+ viewangles[YAW] = 180 - 10;
+ viewangles[PITCH] = 0;
+ viewangles[ROLL] = 0;
+ VectorClear( moveangles );
+ UI_PlayerInfo_SetModel( &info2, model, headmodel, "");
+ UI_PlayerInfo_SetInfo( &info2, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
+ UI_RegisterClientModelname( &info2, model, headmodel, team);
+ updateOpponentModel = qfalse;
+ }
+
+ UI_DrawPlayerII( rect->x, rect->y, rect->w, rect->h, &info2, uiInfo.uiDC.realTime / 2);
+
+}
+
+static void UI_NextOpponent( void ) {
+ int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
+ int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+ i++;
+ if (i >= uiInfo.teamCount) {
+ i = 0;
+ }
+ if (i == j) {
+ i++;
+ if ( i >= uiInfo.teamCount) {
+ i = 0;
+ }
+ }
+ trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
+}
+
+static void UI_PriorOpponent( void ) {
+ int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
+ int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+ i--;
+ if (i < 0) {
+ i = uiInfo.teamCount - 1;
+ }
+ if (i == j) {
+ i--;
+ if ( i < 0) {
+ i = uiInfo.teamCount - 1;
+ }
+ }
+ trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
+}
+
+static void UI_DrawPlayerLogo(rectDef_t *rect, vec3_t color) {
+ int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+
+ if (uiInfo.teamList[i].teamIcon == -1) {
+ uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
+ uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
+ uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
+ }
+
+ trap_R_SetColor( color );
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
+ trap_R_SetColor( NULL );
+}
+
+static void UI_DrawPlayerLogoMetal(rectDef_t *rect, vec3_t color) {
+ int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+ if (uiInfo.teamList[i].teamIcon == -1) {
+ uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
+ uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
+ uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
+ }
+
+ trap_R_SetColor( color );
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
+ trap_R_SetColor( NULL );
+}
+
+static void UI_DrawPlayerLogoName(rectDef_t *rect, vec3_t color) {
+ int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+ if (uiInfo.teamList[i].teamIcon == -1) {
+ uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
+ uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
+ uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
+ }
+
+ trap_R_SetColor( color );
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
+ trap_R_SetColor( NULL );
+}
+
+static void UI_DrawOpponentLogo(rectDef_t *rect, vec3_t color) {
+ int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
+ if (uiInfo.teamList[i].teamIcon == -1) {
+ uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
+ uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
+ uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
+ }
+
+ trap_R_SetColor( color );
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
+ trap_R_SetColor( NULL );
+}
+
+static void UI_DrawOpponentLogoMetal(rectDef_t *rect, vec3_t color) {
+ int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
+ if (uiInfo.teamList[i].teamIcon == -1) {
+ uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
+ uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
+ uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
+ }
+
+ trap_R_SetColor( color );
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
+ trap_R_SetColor( NULL );
+}
+
+static void UI_DrawOpponentLogoName(rectDef_t *rect, vec3_t color) {
+ int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
+ if (uiInfo.teamList[i].teamIcon == -1) {
+ uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
+ uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
+ uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
+ }
+
+ trap_R_SetColor( color );
+ UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
+ trap_R_SetColor( NULL );
+}
+
+static void UI_DrawAllMapsSelection(rectDef_t *rect, float scale, vec4_t color, int textStyle, qboolean net) {
+ int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
+ if (map >= 0 && map < uiInfo.mapCount) {
+ Text_Paint(rect->x, rect->y, scale, color, uiInfo.mapList[map].mapName, 0, 0, textStyle);
+ }
+}
+
+static void UI_DrawOpponentName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_opponentName"), 0, 0, textStyle);
+}
+
+
+static int UI_OwnerDrawWidth(int ownerDraw, float scale) {
+ int i, h, value;
+ const char *text;
+ const char *s = NULL;
+
+ switch (ownerDraw) {
+ case UI_HANDICAP:
+ h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
+ i = 20 - h / 5;
+ s = handicapValues[i];
+ break;
+ case UI_CLANNAME:
+ s = UI_Cvar_VariableString("ui_teamName");
+ break;
+ case UI_GAMETYPE:
+ s = uiInfo.gameTypes[ui_gameType.integer].gameType;
+ break;
+ case UI_SKILL:
+ i = trap_Cvar_VariableValue( "g_spSkill" );
+ if (i < 1 || i > numSkillLevels) {
+ i = 1;
+ }
+ s = skillLevels[i-1];
+ break;
+ case UI_BLUETEAMNAME:
+ i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_blueTeam"));
+ if (i >= 0 && i < uiInfo.teamCount) {
+ s = va("%s: %s", "Blue", uiInfo.teamList[i].teamName);
+ }
+ break;
+ case UI_REDTEAMNAME:
+ i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_redTeam"));
+ if (i >= 0 && i < uiInfo.teamCount) {
+ s = va("%s: %s", "Red", uiInfo.teamList[i].teamName);
+ }
+ break;
+ case UI_BLUETEAM1:
+ case UI_BLUETEAM2:
+ case UI_BLUETEAM3:
+ case UI_BLUETEAM4:
+ case UI_BLUETEAM5:
+ value = trap_Cvar_VariableValue(va("ui_blueteam%i", ownerDraw-UI_BLUETEAM1 + 1));
+ if (value <= 0) {
+ text = "Closed";
+ } else if (value == 1) {
+ text = "Human";
+ } else {
+ value -= 2;
+ if (value >= uiInfo.aliasCount) {
+ value = 0;
+ }
+ text = uiInfo.aliasList[value].name;
+ }
+ s = va("%i. %s", ownerDraw-UI_BLUETEAM1 + 1, text);
+ break;
+ case UI_REDTEAM1:
+ case UI_REDTEAM2:
+ case UI_REDTEAM3:
+ case UI_REDTEAM4:
+ case UI_REDTEAM5:
+ value = trap_Cvar_VariableValue(va("ui_redteam%i", ownerDraw-UI_REDTEAM1 + 1));
+ if (value <= 0) {
+ text = "Closed";
+ } else if (value == 1) {
+ text = "Human";
+ } else {
+ value -= 2;
+ if (value >= uiInfo.aliasCount) {
+ value = 0;
+ }
+ text = uiInfo.aliasList[value].name;
+ }
+ s = va("%i. %s", ownerDraw-UI_REDTEAM1 + 1, text);
+ break;
+ case UI_NETSOURCE:
+ if (ui_netSource.integer < 0 || ui_netSource.integer > uiInfo.numJoinGameTypes) {
+ ui_netSource.integer = 0;
+ }
+ s = va("Source: %s", netSources[ui_netSource.integer]);
+ break;
+ case UI_NETFILTER:
+ if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
+ ui_serverFilterType.integer = 0;
+ }
+ s = va("Filter: %s", serverFilters[ui_serverFilterType.integer].description );
+ break;
+ case UI_TIER:
+ break;
+ case UI_TIER_MAPNAME:
+ break;
+ case UI_TIER_GAMETYPE:
+ break;
+ case UI_ALLMAPS_SELECTION:
+ break;
+ case UI_OPPONENT_NAME:
+ break;
+ case UI_KEYBINDSTATUS:
+ if (Display_KeyBindPending()) {
+ s = "Waiting for new key... Press ESCAPE to cancel";
+ } else {
+ s = "Press ENTER or CLICK to change, Press BACKSPACE to clear";
+ }
+ break;
+ case UI_SERVERREFRESHDATE:
+ s = UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer));
+ break;
+ default:
+ break;
+ }
+
+ if (s) {
+ return Text_Width(s, scale, 0);
+ }
+ return 0;
+}
+
+static void UI_DrawBotName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ int value = uiInfo.botIndex;
+ int game = trap_Cvar_VariableValue("g_gametype");
+ const char *text = "";
+ if (game >= GT_TEAM && !GT_LMS ) {
+ if (value >= uiInfo.characterCount) {
+ value = 0;
+ }
+ text = uiInfo.characterList[value].name;
+ } else {
+ if (value >= UI_GetNumBots()) {
+ value = 0;
+ }
+ text = UI_GetBotNameByNumber(value);
+ }
+ Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
+}
+
+static void UI_DrawBotSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ if (uiInfo.skillIndex >= 0 && uiInfo.skillIndex < numSkillLevels) {
+ Text_Paint(rect->x, rect->y, scale, color, skillLevels[uiInfo.skillIndex], 0, 0, textStyle);
+ }
+}
+
+static void UI_DrawRedBlue(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ Text_Paint(rect->x, rect->y, scale, color, (uiInfo.redBlue == 0) ? "Red" : "Blue", 0, 0, textStyle);
+}
+
+static void UI_DrawCrosshair(rectDef_t *rect, float scale, vec4_t color) {
+ trap_R_SetColor( color );
+ if (uiInfo.currentCrosshair < 0 || uiInfo.currentCrosshair >= NUM_CROSSHAIRS) {
+ uiInfo.currentCrosshair = 0;
+ }
+ UI_DrawHandlePic( rect->x, rect->y - rect->h, rect->w, rect->h, uiInfo.uiDC.Assets.crosshairShader[uiInfo.currentCrosshair]);
+ trap_R_SetColor( NULL );
+}
+
+/*
+===============
+UI_BuildPlayerList
+===============
+*/
+static void UI_BuildPlayerList( void ) {
+ uiClientState_t cs;
+ int n, count, team, team2, playerTeamNumber;
+ char info[MAX_INFO_STRING];
+
+ trap_GetClientState( &cs );
+ trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );
+ uiInfo.playerNumber = cs.clientNum;
+ uiInfo.teamLeader = atoi(Info_ValueForKey(info, "tl"));
+ team = atoi(Info_ValueForKey(info, "t"));
+ trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
+ count = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
+ uiInfo.playerCount = 0;
+ uiInfo.myTeamCount = 0;
+ playerTeamNumber = 0;
+ for( n = 0; n < count; n++ ) {
+ trap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING );
+
+ if (info[0]) {
+ Q_strncpyz( uiInfo.playerNames[uiInfo.playerCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
+ Q_CleanStr( uiInfo.playerNames[uiInfo.playerCount] );
+ uiInfo.playerCount++;
+ team2 = atoi(Info_ValueForKey(info, "t"));
+ if (team2 == team) {
+ Q_strncpyz( uiInfo.teamNames[uiInfo.myTeamCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
+ Q_CleanStr( uiInfo.teamNames[uiInfo.myTeamCount] );
+ uiInfo.teamClientNums[uiInfo.myTeamCount] = n;
+ if (uiInfo.playerNumber == n) {
+ playerTeamNumber = uiInfo.myTeamCount;
+ }
+ uiInfo.myTeamCount++;
+ }
+ }
+ }
+
+ if (!uiInfo.teamLeader) {
+ trap_Cvar_Set("cg_selectedPlayer", va("%d", playerTeamNumber));
+ }
+
+ n = trap_Cvar_VariableValue("cg_selectedPlayer");
+ if (n < 0 || n > uiInfo.myTeamCount) {
+ n = 0;
+ }
+ if (n < uiInfo.myTeamCount) {
+ trap_Cvar_Set("cg_selectedPlayerName", uiInfo.teamNames[n]);
+ }
+}
+
+
+static void UI_DrawSelectedPlayer(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
+ uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
+ UI_BuildPlayerList();
+ }
+ Text_Paint(rect->x, rect->y, scale, color, (uiInfo.teamLeader) ? UI_Cvar_VariableString("cg_selectedPlayerName") : UI_Cvar_VariableString("name") , 0, 0, textStyle);
+}
+
+static void UI_DrawServerRefreshDate(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ if (uiInfo.serverStatus.refreshActive) {
+ vec4_t lowLight, newColor;
+ lowLight[0] = 0.8 * color[0];
+ lowLight[1] = 0.8 * color[1];
+ lowLight[2] = 0.8 * color[2];
+ lowLight[3] = 0.8 * color[3];
+ LerpColor(color,lowLight,newColor,0.5+0.5*sin(uiInfo.uiDC.realTime / PULSE_DIVISOR));
+ Text_Paint(rect->x, rect->y, scale, newColor, va("Getting info for %d servers (ESC to cancel)", trap_LAN_GetServerCount(ui_netSource.integer)), 0, 0, textStyle);
+ } else {
+ char buff[64];
+ Q_strncpyz(buff, UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer)), 64);
+ Text_Paint(rect->x, rect->y, scale, color, va("Refresh Time: %s", buff), 0, 0, textStyle);
+ }
+}
+
+static void UI_DrawServerMOTD(rectDef_t *rect, float scale, vec4_t color) {
+ if (uiInfo.serverStatus.motdLen) {
+ float maxX;
+
+ if (uiInfo.serverStatus.motdWidth == -1) {
+ uiInfo.serverStatus.motdWidth = 0;
+ uiInfo.serverStatus.motdPaintX = rect->x + 1;
+ uiInfo.serverStatus.motdPaintX2 = -1;
+ }
+
+ if (uiInfo.serverStatus.motdOffset > uiInfo.serverStatus.motdLen) {
+ uiInfo.serverStatus.motdOffset = 0;
+ uiInfo.serverStatus.motdPaintX = rect->x + 1;
+ uiInfo.serverStatus.motdPaintX2 = -1;
+ }
+
+ if (uiInfo.uiDC.realTime > uiInfo.serverStatus.motdTime) {
+ uiInfo.serverStatus.motdTime = uiInfo.uiDC.realTime + 10;
+ if (uiInfo.serverStatus.motdPaintX <= rect->x + 2) {
+ if (uiInfo.serverStatus.motdOffset < uiInfo.serverStatus.motdLen) {
+ uiInfo.serverStatus.motdPaintX += Text_Width(&uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], scale, 1) - 1;
+ uiInfo.serverStatus.motdOffset++;
+ } else {
+ uiInfo.serverStatus.motdOffset = 0;
+ if (uiInfo.serverStatus.motdPaintX2 >= 0) {
+ uiInfo.serverStatus.motdPaintX = uiInfo.serverStatus.motdPaintX2;
+ } else {
+ uiInfo.serverStatus.motdPaintX = rect->x + rect->w - 2;
+ }
+ uiInfo.serverStatus.motdPaintX2 = -1;
+ }
+ } else {
+ //serverStatus.motdPaintX--;
+ uiInfo.serverStatus.motdPaintX -= 2;
+ if (uiInfo.serverStatus.motdPaintX2 >= 0) {
+ //serverStatus.motdPaintX2--;
+ uiInfo.serverStatus.motdPaintX2 -= 2;
+ }
+ }
+ }
+
+ maxX = rect->x + rect->w - 2;
+ Text_Paint_Limit(&maxX, uiInfo.serverStatus.motdPaintX, rect->y + rect->h - 3, scale, color, &uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], 0, 0);
+ if (uiInfo.serverStatus.motdPaintX2 >= 0) {
+ float maxX2 = rect->x + rect->w - 2;
+ Text_Paint_Limit(&maxX2, uiInfo.serverStatus.motdPaintX2, rect->y + rect->h - 3, scale, color, uiInfo.serverStatus.motd, 0, uiInfo.serverStatus.motdOffset);
+ }
+ if (uiInfo.serverStatus.motdOffset && maxX > 0) {
+ // if we have an offset ( we are skipping the first part of the string ) and we fit the string
+ if (uiInfo.serverStatus.motdPaintX2 == -1) {
+ uiInfo.serverStatus.motdPaintX2 = rect->x + rect->w - 2;
+ }
+ } else {
+ uiInfo.serverStatus.motdPaintX2 = -1;
+ }
+
+ }
+}
+
+static void UI_DrawKeyBindStatus(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+// int ofs = 0; TTimo: unused
+ if (Display_KeyBindPending()) {
+ Text_Paint(rect->x, rect->y, scale, color, "Waiting for new key... Press ESCAPE to cancel", 0, 0, textStyle);
+ } else {
+ Text_Paint(rect->x, rect->y, scale, color, "Press ENTER or CLICK to change, Press BACKSPACE to clear", 0, 0, textStyle);
+ }
+}
+
+static void UI_DrawGLInfo(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
+ char * eptr;
+ char buff[1024];
+ const char *lines[64];
+ int y, numLines, i;
+
+ Text_Paint(rect->x + 2, rect->y, scale, color, va("VENDOR: %s", uiInfo.uiDC.glconfig.vendor_string), 0, 30, textStyle);
+ Text_Paint(rect->x + 2, rect->y + 15, scale, color, va("VERSION: %s: %s", uiInfo.uiDC.glconfig.version_string,uiInfo.uiDC.glconfig.renderer_string), 0, 30, textStyle);
+ Text_Paint(rect->x + 2, rect->y + 30, scale, color, va ("PIXELFORMAT: color(%d-bits) Z(%d-bits) stencil(%d-bits)", uiInfo.uiDC.glconfig.colorBits, uiInfo.uiDC.glconfig.depthBits, uiInfo.uiDC.glconfig.stencilBits), 0, 30, textStyle);
+
+ // build null terminated extension strings
+ // TTimo: https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=399
+ // in TA this was not directly crashing, but displaying a nasty broken shader right in the middle
+ // brought down the string size to 1024, there's not much that can be shown on the screen anyway
+ Q_strncpyz(buff, uiInfo.uiDC.glconfig.extensions_string, 1024);
+ eptr = buff;
+ y = rect->y + 45;
+ numLines = 0;
+ while ( y < rect->y + rect->h && *eptr )
+ {
+ while ( *eptr && *eptr == ' ' )
+ *eptr++ = '\0';
+
+ // track start of valid string
+ if (*eptr && *eptr != ' ') {
+ lines[numLines++] = eptr;
+ }
+
+ while ( *eptr && *eptr != ' ' )
+ eptr++;
+ }
+
+ i = 0;
+ while (i < numLines) {
+ Text_Paint(rect->x + 2, y, scale, color, lines[i++], 0, 20, textStyle);
+ if (i < numLines) {
+ Text_Paint(rect->x + rect->w / 2, y, scale, color, lines[i++], 0, 20, textStyle);
+ }
+ y += 10;
+ if (y > rect->y + rect->h - 11) {
+ break;
+ }
+ }
+
+
+}
+
+// FIXME: table drive
+//
+static void UI_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle) {
+ rectDef_t rect;
+
+ rect.x = x + text_x;
+ rect.y = y + text_y;
+ rect.w = w;
+ rect.h = h;
+
+ switch (ownerDraw) {
+ case UI_HANDICAP:
+ UI_DrawHandicap(&rect, scale, color, textStyle);
+ break;
+ case UI_EFFECTS:
+ UI_DrawEffects(&rect, scale, color);
+ break;
+ case UI_PLAYERMODEL:
+ UI_DrawPlayerModel(&rect);
+ break;
+ case UI_PLAYERMODEL2:
+ UI_DrawPlayerModel2(&rect);
+ break;
+ case UI_CLANNAME:
+ UI_DrawClanName(&rect, scale, color, textStyle);
+ break;
+ case UI_CLANLOGO:
+ UI_DrawClanLogo(&rect, scale, color);
+ break;
+ case UI_CLANCINEMATIC:
+ UI_DrawClanCinematic(&rect, scale, color);
+ break;
+ case UI_PREVIEWCINEMATIC:
+ UI_DrawPreviewCinematic(&rect, scale, color);
+ break;
+ case UI_GAMETYPE:
+ UI_DrawGameType(&rect, scale, color, textStyle);
+ break;
+ case UI_NETGAMETYPE:
+ UI_DrawNetGameType(&rect, scale, color, textStyle);
+ break;
+ case UI_JOINGAMETYPE:
+ UI_DrawJoinGameType(&rect, scale, color, textStyle);
+ break;
+ case UI_MAPPREVIEW:
+ UI_DrawMapPreview(&rect, scale, color, qtrue);
+ break;
+ case UI_MAP_TIMETOBEAT:
+ UI_DrawMapTimeToBeat(&rect, scale, color, textStyle);
+ break;
+ case UI_MAPCINEMATIC:
+ UI_DrawMapCinematic(&rect, scale, color, qfalse);
+ break;
+ case UI_STARTMAPCINEMATIC:
+ UI_DrawMapCinematic(&rect, scale, color, qtrue);
+ break;
+ case UI_SKILL:
+ UI_DrawSkill(&rect, scale, color, textStyle);
+ break;
+ case UI_BLUETEAMNAME:
+ UI_DrawTeamName(&rect, scale, color, qtrue, textStyle);
+ break;
+ case UI_REDTEAMNAME:
+ UI_DrawTeamName(&rect, scale, color, qfalse, textStyle);
+ break;
+ case UI_BLUETEAM1:
+ case UI_BLUETEAM2:
+ case UI_BLUETEAM3:
+ case UI_BLUETEAM4:
+ case UI_BLUETEAM5:
+ UI_DrawTeamMember(&rect, scale, color, qtrue, ownerDraw - UI_BLUETEAM1 + 1, textStyle);
+ break;
+ case UI_REDTEAM1:
+ case UI_REDTEAM2:
+ case UI_REDTEAM3:
+ case UI_REDTEAM4:
+ case UI_REDTEAM5:
+ UI_DrawTeamMember(&rect, scale, color, qfalse, ownerDraw - UI_REDTEAM1 + 1, textStyle);
+ break;
+ case UI_NETSOURCE:
+ UI_DrawNetSource(&rect, scale, color, textStyle);
+ break;
+ case UI_NETMAPPREVIEW:
+ UI_DrawNetMapPreview(&rect, scale, color);
+ break;
+ case UI_NETMAPCINEMATIC:
+ UI_DrawNetMapCinematic(&rect, scale, color);
+ break;
+ case UI_NETFILTER:
+ UI_DrawNetFilter(&rect, scale, color, textStyle);
+ break;
+ case UI_TIER:
+ UI_DrawTier(&rect, scale, color, textStyle);
+ break;
+ case UI_OPPONENTMODEL:
+ UI_DrawOpponent(&rect);
+ break;
+ case UI_OPPONENTMODEL2:
+ UI_DrawOpponent2(&rect);
+ break;
+ case UI_TIERMAP1:
+ UI_DrawTierMap(&rect, 0);
+ break;
+ case UI_TIERMAP2:
+ UI_DrawTierMap(&rect, 1);
+ break;
+ case UI_TIERMAP3:
+ UI_DrawTierMap(&rect, 2);
+ break;
+ case UI_PLAYERLOGO:
+ UI_DrawPlayerLogo(&rect, color);
+ break;
+ case UI_PLAYERLOGO_METAL:
+ UI_DrawPlayerLogoMetal(&rect, color);
+ break;
+ case UI_PLAYERLOGO_NAME:
+ UI_DrawPlayerLogoName(&rect, color);
+ break;
+ case UI_OPPONENTLOGO:
+ UI_DrawOpponentLogo(&rect, color);
+ break;
+ case UI_OPPONENTLOGO_METAL:
+ UI_DrawOpponentLogoMetal(&rect, color);
+ break;
+ case UI_OPPONENTLOGO_NAME:
+ UI_DrawOpponentLogoName(&rect, color);
+ break;
+ case UI_TIER_MAPNAME:
+ UI_DrawTierMapName(&rect, scale, color, textStyle);
+ break;
+ case UI_TIER_GAMETYPE:
+ UI_DrawTierGameType(&rect, scale, color, textStyle);
+ break;
+ case UI_ALLMAPS_SELECTION:
+ UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qtrue);
+ break;
+ case UI_MAPS_SELECTION:
+ UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qfalse);
+ break;
+ case UI_OPPONENT_NAME:
+ UI_DrawOpponentName(&rect, scale, color, textStyle);
+ break;
+ case UI_BOTNAME:
+ UI_DrawBotName(&rect, scale, color, textStyle);
+ break;
+ case UI_BOTSKILL:
+ UI_DrawBotSkill(&rect, scale, color, textStyle);
+ break;
+ case UI_REDBLUE:
+ UI_DrawRedBlue(&rect, scale, color, textStyle);
+ break;
+ case UI_CROSSHAIR:
+ UI_DrawCrosshair(&rect, scale, color);
+ break;
+ case UI_SELECTEDPLAYER:
+ UI_DrawSelectedPlayer(&rect, scale, color, textStyle);
+ break;
+ case UI_SERVERREFRESHDATE:
+ UI_DrawServerRefreshDate(&rect, scale, color, textStyle);
+ break;
+ case UI_SERVERMOTD:
+ UI_DrawServerMOTD(&rect, scale, color);
+ break;
+ case UI_GLINFO:
+ UI_DrawGLInfo(&rect,scale, color, textStyle);
+ break;
+ case UI_KEYBINDSTATUS:
+ UI_DrawKeyBindStatus(&rect,scale, color, textStyle);
+ break;
+ default:
+ break;
+ }
+
+}
+
+static qboolean UI_OwnerDrawVisible(int flags) {
+ qboolean vis = qtrue;
+
+ while (flags) {
+
+ if (flags & UI_SHOW_FFA) {
+ if (trap_Cvar_VariableValue("g_gametype") != GT_FFA || trap_Cvar_VariableValue("g_gametype") != GT_LMS ) {
+ vis = qfalse;
+ }
+ flags &= ~UI_SHOW_FFA;
+ }
+
+ if (flags & UI_SHOW_NOTFFA) {
+ if (trap_Cvar_VariableValue("g_gametype") == GT_FFA || trap_Cvar_VariableValue("g_gametype") == GT_LMS ) {
+ vis = qfalse;
+ }
+ flags &= ~UI_SHOW_NOTFFA;
+ }
+
+ if (flags & UI_SHOW_LEADER) {
+ // these need to show when this client can give orders to a player or a group
+ if (!uiInfo.teamLeader) {
+ vis = qfalse;
+ } else {
+ // if showing yourself
+ if (ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber) {
+ vis = qfalse;
+ }
+ }
+ flags &= ~UI_SHOW_LEADER;
+ }
+ if (flags & UI_SHOW_NOTLEADER) {
+ // these need to show when this client is assigning their own status or they are NOT the leader
+ if (uiInfo.teamLeader) {
+ // if not showing yourself
+ if (!(ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber)) {
+ vis = qfalse;
+ }
+ // these need to show when this client can give orders to a player or a group
+ }
+ flags &= ~UI_SHOW_NOTLEADER;
+ }
+ if (flags & UI_SHOW_FAVORITESERVERS) {
+ // this assumes you only put this type of display flag on something showing in the proper context
+ if (ui_netSource.integer != AS_FAVORITES) {
+ vis = qfalse;
+ }
+ flags &= ~UI_SHOW_FAVORITESERVERS;
+ }
+ if (flags & UI_SHOW_NOTFAVORITESERVERS) {
+ // this assumes you only put this type of display flag on something showing in the proper context
+ if (ui_netSource.integer == AS_FAVORITES) {
+ vis = qfalse;
+ }
+ flags &= ~UI_SHOW_NOTFAVORITESERVERS;
+ }
+ if (flags & UI_SHOW_ANYTEAMGAME) {
+ if (uiInfo.gameTypes[ui_gameType.integer].gtEnum <= GT_TEAM && uiInfo.gameTypes[ui_gameType.integer].gtEnum != GT_LMS ) {
+ vis = qfalse;
+ }
+ flags &= ~UI_SHOW_ANYTEAMGAME;
+ }
+ if (flags & UI_SHOW_ANYNONTEAMGAME) {
+ if (uiInfo.gameTypes[ui_gameType.integer].gtEnum > GT_TEAM || uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_LMS ) {
+ vis = qfalse;
+ }
+ flags &= ~UI_SHOW_ANYNONTEAMGAME;
+ }
+ if (flags & UI_SHOW_NETANYTEAMGAME) {
+ if (uiInfo.gameTypes[ui_netGameType.integer].gtEnum <= GT_TEAM && uiInfo.gameTypes[ui_gameType.integer].gtEnum != GT_LMS ) {
+ vis = qfalse;
+ }
+ flags &= ~UI_SHOW_NETANYTEAMGAME;
+ }
+ if (flags & UI_SHOW_NETANYNONTEAMGAME) {
+ if (uiInfo.gameTypes[ui_netGameType.integer].gtEnum > GT_TEAM || uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_LMS ) {
+ vis = qfalse;
+ }
+ flags &= ~UI_SHOW_NETANYNONTEAMGAME;
+ }
+ if (flags & UI_SHOW_NEWHIGHSCORE) {
+ if (uiInfo.newHighScoreTime < uiInfo.uiDC.realTime) {
+ vis = qfalse;
+ } else {
+ if (uiInfo.soundHighScore) {
+ if (trap_Cvar_VariableValue("sv_killserver") == 0) {
+ // wait on server to go down before playing sound
+ trap_S_StartLocalSound(uiInfo.newHighScoreSound, CHAN_ANNOUNCER);
+ uiInfo.soundHighScore = qfalse;
+ }
+ }
+ }
+ flags &= ~UI_SHOW_NEWHIGHSCORE;
+ }
+ if (flags & UI_SHOW_NEWBESTTIME) {
+ if (uiInfo.newBestTime < uiInfo.uiDC.realTime) {
+ vis = qfalse;
+ }
+ flags &= ~UI_SHOW_NEWBESTTIME;
+ }
+ if (flags & UI_SHOW_DEMOAVAILABLE) {
+ if (!uiInfo.demoAvailable) {
+ vis = qfalse;
+ }
+ flags &= ~UI_SHOW_DEMOAVAILABLE;
+ } else {
+ flags = 0;
+ }
+ }
+ return vis;
+}
+
+static qboolean UI_Handicap_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ int h;
+ h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
+ if (key == K_MOUSE2) {
+ h -= 5;
+ } else {
+ h += 5;
+ }
+ if (h > 100) {
+ h = 5;
+ } else if (h < 0) {
+ h = 100;
+ }
+ trap_Cvar_Set( "handicap", va( "%i", h) );
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_Effects_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+
+ if (key == K_MOUSE2) {
+ uiInfo.effectsColor--;
+ } else {
+ uiInfo.effectsColor++;
+ }
+
+ if( uiInfo.effectsColor > 6 ) {
+ uiInfo.effectsColor = 0;
+ } else if (uiInfo.effectsColor < 0) {
+ uiInfo.effectsColor = 6;
+ }
+
+ trap_Cvar_SetValue( "color1", uitogamecode[uiInfo.effectsColor] );
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_ClanName_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ int i;
+ i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+ if (uiInfo.teamList[i].cinematic >= 0) {
+ trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
+ uiInfo.teamList[i].cinematic = -1;
+ }
+ if (key == K_MOUSE2) {
+ i--;
+ } else {
+ i++;
+ }
+ if (i >= uiInfo.teamCount) {
+ i = 0;
+ } else if (i < 0) {
+ i = uiInfo.teamCount - 1;
+ }
+ trap_Cvar_Set( "ui_teamName", uiInfo.teamList[i].teamName);
+ UI_HeadCountByTeam();
+ UI_FeederSelection(FEEDER_HEADS, 0);
+ updateModel = qtrue;
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_GameType_HandleKey(int flags, float *special, int key, qboolean resetMap) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ int oldCount = UI_MapCountByGameType(qtrue);
+
+ // hard coded mess here
+ if (key == K_MOUSE2) {
+ ui_gameType.integer--;
+ if (ui_gameType.integer == 2) {
+ ui_gameType.integer = 1;
+ } else if (ui_gameType.integer < 2) {
+ ui_gameType.integer = uiInfo.numGameTypes - 1;
+ }
+ } else {
+ ui_gameType.integer++;
+ if (ui_gameType.integer >= uiInfo.numGameTypes) {
+ ui_gameType.integer = 1;
+ } else if (ui_gameType.integer == 2) {
+ ui_gameType.integer = 3;
+ }
+ }
+
+ if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_TOURNAMENT) {
+ trap_Cvar_Set("ui_Q3Model", "1");
+ } else {
+ trap_Cvar_Set("ui_Q3Model", "0");
+ }
+
+ trap_Cvar_Set("ui_gameType", va("%d", ui_gameType.integer));
+ UI_SetCapFragLimits(qtrue);
+ UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
+ if (resetMap && oldCount != UI_MapCountByGameType(qtrue)) {
+ trap_Cvar_Set( "ui_currentMap", "0");
+ Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, NULL);
+ }
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_NetGameType_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+
+ if (key == K_MOUSE2) {
+ ui_netGameType.integer--;
+ } else {
+ ui_netGameType.integer++;
+ }
+
+ if (ui_netGameType.integer < 0) {
+ ui_netGameType.integer = uiInfo.numGameTypes - 1;
+ } else if (ui_netGameType.integer >= uiInfo.numGameTypes) {
+ ui_netGameType.integer = 0;
+ }
+
+ trap_Cvar_Set( "ui_netGameType", va("%d", ui_netGameType.integer));
+ trap_Cvar_Set( "ui_actualnetGameType", va("%d", uiInfo.gameTypes[ui_netGameType.integer].gtEnum));
+ trap_Cvar_Set( "ui_currentNetMap", "0");
+ UI_MapCountByGameType(qfalse);
+ Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, NULL);
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_JoinGameType_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+
+ if (key == K_MOUSE2) {
+ ui_joinGameType.integer--;
+ } else {
+ ui_joinGameType.integer++;
+ }
+
+ if (ui_joinGameType.integer < 0) {
+ ui_joinGameType.integer = uiInfo.numJoinGameTypes - 1;
+ } else if (ui_joinGameType.integer >= uiInfo.numJoinGameTypes) {
+ ui_joinGameType.integer = 0;
+ }
+
+ trap_Cvar_Set( "ui_joinGameType", va("%d", ui_joinGameType.integer));
+ UI_BuildServerDisplayList(qtrue);
+ return qtrue;
+ }
+ return qfalse;
+}
+
+
+
+static qboolean UI_Skill_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ int i = trap_Cvar_VariableValue( "g_spSkill" );
+
+ if (key == K_MOUSE2) {
+ i--;
+ } else {
+ i++;
+ }
+
+ if (i < 1) {
+ i = numSkillLevels;
+ } else if (i > numSkillLevels) {
+ i = 1;
+ }
+
+ trap_Cvar_Set("g_spSkill", va("%i", i));
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_TeamName_HandleKey(int flags, float *special, int key, qboolean blue) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ int i;
+ i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
+
+ if (key == K_MOUSE2) {
+ i--;
+ } else {
+ i++;
+ }
+
+ if (i >= uiInfo.teamCount) {
+ i = 0;
+ } else if (i < 0) {
+ i = uiInfo.teamCount - 1;
+ }
+
+ trap_Cvar_Set( (blue) ? "ui_blueTeam" : "ui_redTeam", uiInfo.teamList[i].teamName);
+
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_TeamMember_HandleKey(int flags, float *special, int key, qboolean blue, int num) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ // 0 - None
+ // 1 - Human
+ // 2..NumCharacters - Bot
+ char *cvar = va(blue ? "ui_blueteam%i" : "ui_redteam%i", num);
+ int value = trap_Cvar_VariableValue(cvar);
+
+ if (key == K_MOUSE2) {
+ value--;
+ } else {
+ value++;
+ }
+
+ if (ui_actualNetGameType.integer >= GT_TEAM) {
+ if (value >= uiInfo.characterCount + 2) {
+ value = 0;
+ } else if (value < 0) {
+ value = uiInfo.characterCount + 2 - 1;
+ }
+ } else {
+ if (value >= UI_GetNumBots() + 2) {
+ value = 0;
+ } else if (value < 0) {
+ value = UI_GetNumBots() + 2 - 1;
+ }
+ }
+
+ trap_Cvar_Set(cvar, va("%i", value));
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_NetSource_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+
+ if (key == K_MOUSE2) {
+ ui_netSource.integer--;
+ if(strlen(netSources[ui_netSource.integer])<1)
+ ui_netSource.integer--;
+ } else {
+ ui_netSource.integer++;
+ if(strlen(netSources[ui_netSource.integer])<1)
+ ui_netSource.integer++;
+ }
+
+ if (ui_netSource.integer >= numNetSources) {
+ ui_netSource.integer = 0;
+ } else if (ui_netSource.integer < 0) {
+ ui_netSource.integer = numNetSources - 1;
+ }
+
+ UI_BuildServerDisplayList(qtrue);
+ if (ui_netSource.integer != AS_GLOBAL) {
+ UI_StartServerRefresh(qtrue);
+ }
+ trap_Cvar_Set( "ui_netSource", va("%d", ui_netSource.integer));
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_NetFilter_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+
+ if (key == K_MOUSE2) {
+ ui_serverFilterType.integer--;
+ } else {
+ ui_serverFilterType.integer++;
+ }
+
+ if (ui_serverFilterType.integer >= numServerFilters) {
+ ui_serverFilterType.integer = 0;
+ } else if (ui_serverFilterType.integer < 0) {
+ ui_serverFilterType.integer = numServerFilters - 1;
+ }
+ UI_BuildServerDisplayList(qtrue);
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_OpponentName_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ if (key == K_MOUSE2) {
+ UI_PriorOpponent();
+ } else {
+ UI_NextOpponent();
+ }
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_BotName_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ int game = trap_Cvar_VariableValue("g_gametype");
+ int value = uiInfo.botIndex;
+
+ if (key == K_MOUSE2) {
+ value--;
+ } else {
+ value++;
+ }
+
+ if (game >= GT_TEAM && !GT_LMS) {
+ if (value >= uiInfo.characterCount + 2) {
+ value = 0;
+ } else if (value < 0) {
+ value = uiInfo.characterCount + 2 - 1;
+ }
+ } else {
+ if (value >= UI_GetNumBots() + 2) {
+ value = 0;
+ } else if (value < 0) {
+ value = UI_GetNumBots() + 2 - 1;
+ }
+ }
+ uiInfo.botIndex = value;
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_BotSkill_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ if (key == K_MOUSE2) {
+ uiInfo.skillIndex--;
+ } else {
+ uiInfo.skillIndex++;
+ }
+ if (uiInfo.skillIndex >= numSkillLevels) {
+ uiInfo.skillIndex = 0;
+ } else if (uiInfo.skillIndex < 0) {
+ uiInfo.skillIndex = numSkillLevels-1;
+ }
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_RedBlue_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ uiInfo.redBlue ^= 1;
+ return qtrue;
+ }
+ return qfalse;
+}
+
+static qboolean UI_Crosshair_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ if (key == K_MOUSE2) {
+ uiInfo.currentCrosshair--;
+ } else {
+ uiInfo.currentCrosshair++;
+ }
+
+ if (uiInfo.currentCrosshair >= NUM_CROSSHAIRS) {
+ uiInfo.currentCrosshair = 0;
+ } else if (uiInfo.currentCrosshair < 0) {
+ uiInfo.currentCrosshair = NUM_CROSSHAIRS - 1;
+ }
+ trap_Cvar_Set("cg_drawCrosshair", va("%d", uiInfo.currentCrosshair));
+ return qtrue;
+ }
+ return qfalse;
+}
+
+
+
+static qboolean UI_SelectedPlayer_HandleKey(int flags, float *special, int key) {
+ if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
+ int selected;
+
+ UI_BuildPlayerList();
+ if (!uiInfo.teamLeader) {
+ return qfalse;
+ }
+ selected = trap_Cvar_VariableValue("cg_selectedPlayer");
+
+ if (key == K_MOUSE2) {
+ selected--;
+ } else {
+ selected++;
+ }
+
+ if (selected > uiInfo.myTeamCount) {
+ selected = 0;
+ } else if (selected < 0) {
+ selected = uiInfo.myTeamCount;
+ }
+
+ if (selected == uiInfo.myTeamCount) {
+ trap_Cvar_Set( "cg_selectedPlayerName", "Everyone");
+ } else {
+ trap_Cvar_Set( "cg_selectedPlayerName", uiInfo.teamNames[selected]);
+ }
+ trap_Cvar_Set( "cg_selectedPlayer", va("%d", selected));
+ }
+ return qfalse;
+}
+
+
+static qboolean UI_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) {
+ switch (ownerDraw) {
+ case UI_HANDICAP:
+ return UI_Handicap_HandleKey(flags, special, key);
+ break;
+ case UI_EFFECTS:
+ return UI_Effects_HandleKey(flags, special, key);
+ break;
+ case UI_CLANNAME:
+ return UI_ClanName_HandleKey(flags, special, key);
+ break;
+ case UI_GAMETYPE:
+ return UI_GameType_HandleKey(flags, special, key, qtrue);
+ break;
+ case UI_NETGAMETYPE:
+ return UI_NetGameType_HandleKey(flags, special, key);
+ break;
+ case UI_JOINGAMETYPE:
+ return UI_JoinGameType_HandleKey(flags, special, key);
+ break;
+ case UI_SKILL:
+ return UI_Skill_HandleKey(flags, special, key);
+ break;
+ case UI_BLUETEAMNAME:
+ return UI_TeamName_HandleKey(flags, special, key, qtrue);
+ break;
+ case UI_REDTEAMNAME:
+ return UI_TeamName_HandleKey(flags, special, key, qfalse);
+ break;
+ case UI_BLUETEAM1:
+ case UI_BLUETEAM2:
+ case UI_BLUETEAM3:
+ case UI_BLUETEAM4:
+ case UI_BLUETEAM5:
+ UI_TeamMember_HandleKey(flags, special, key, qtrue, ownerDraw - UI_BLUETEAM1 + 1);
+ break;
+ case UI_REDTEAM1:
+ case UI_REDTEAM2:
+ case UI_REDTEAM3:
+ case UI_REDTEAM4:
+ case UI_REDTEAM5:
+ UI_TeamMember_HandleKey(flags, special, key, qfalse, ownerDraw - UI_REDTEAM1 + 1);
+ break;
+ case UI_NETSOURCE:
+ UI_NetSource_HandleKey(flags, special, key);
+ break;
+ case UI_NETFILTER:
+ UI_NetFilter_HandleKey(flags, special, key);
+ break;
+ case UI_OPPONENT_NAME:
+ UI_OpponentName_HandleKey(flags, special, key);
+ break;
+ case UI_BOTNAME:
+ return UI_BotName_HandleKey(flags, special, key);
+ break;
+ case UI_BOTSKILL:
+ return UI_BotSkill_HandleKey(flags, special, key);
+ break;
+ case UI_REDBLUE:
+ UI_RedBlue_HandleKey(flags, special, key);
+ break;
+ case UI_CROSSHAIR:
+ UI_Crosshair_HandleKey(flags, special, key);
+ break;
+ case UI_SELECTEDPLAYER:
+ UI_SelectedPlayer_HandleKey(flags, special, key);
+ break;
+ default:
+ break;
+ }
+
+ return qfalse;
+}
+
+
+static float UI_GetValue(int ownerDraw) {
+ return 0;
+}
+
+/*
+=================
+UI_ServersQsortCompare
+=================
+*/
+static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 ) {
+ return trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey, uiInfo.serverStatus.sortDir, *(int*)arg1, *(int*)arg2);
+}
+
+
+/*
+=================
+UI_ServersSort
+=================
+*/
+void UI_ServersSort(int column, qboolean force) {
+
+ if ( !force ) {
+ if ( uiInfo.serverStatus.sortKey == column ) {
+ return;
+ }
+ }
+
+ uiInfo.serverStatus.sortKey = column;
+ qsort( &uiInfo.serverStatus.displayServers[0], uiInfo.serverStatus.numDisplayServers, sizeof(int), UI_ServersQsortCompare);
+}
+
+/*
+static void UI_StartSinglePlayer(void) {
+ int i,j, k, skill;
+ char buff[1024];
+ i = trap_Cvar_VariableValue( "ui_currentTier" );
+ if (i < 0 || i >= tierCount) {
+ i = 0;
+ }
+ j = trap_Cvar_VariableValue("ui_currentMap");
+ if (j < 0 || j > MAPS_PER_TIER) {
+ j = 0;
+ }
+
+ trap_Cvar_SetValue( "singleplayer", 1 );
+ trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, 7, tierList[i].gameTypes[j] ) );
+ trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", tierList[i].maps[j] ) );
+ skill = trap_Cvar_VariableValue( "g_spSkill" );
+
+ if (j == MAPS_PER_TIER-1) {
+ k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
+ Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[0]), skill, "", teamList[k].teamMembers[0]);
+ } else {
+ k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
+ for (i = 0; i < PLAYERS_PER_TEAM; i++) {
+ Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[i]), skill, "Blue", teamList[k].teamMembers[i]);
+ trap_Cmd_ExecuteText( EXEC_APPEND, buff );
+ }
+
+ k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+ for (i = 1; i < PLAYERS_PER_TEAM; i++) {
+ Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[i]), skill, "Red", teamList[k].teamMembers[i]);
+ trap_Cmd_ExecuteText( EXEC_APPEND, buff );
+ }
+ trap_Cmd_ExecuteText( EXEC_APPEND, "wait 5; team Red\n" );
+ }
+
+
+}
+*/
+
+/*
+===============
+UI_LoadMods
+===============
+*/
+static void UI_LoadMods( void ) {
+ int numdirs;
+ char dirlist[2048];
+ char *dirptr;
+ char *descptr;
+ int i;
+ int dirlen;
+
+ uiInfo.modCount = 0;
+ numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) );
+ dirptr = dirlist;
+ for( i = 0; i < numdirs; i++ ) {
+ dirlen = strlen( dirptr ) + 1;
+ descptr = dirptr + dirlen;
+ uiInfo.modList[uiInfo.modCount].modName = String_Alloc(dirptr);
+ uiInfo.modList[uiInfo.modCount].modDescr = String_Alloc(descptr);
+ dirptr += dirlen + strlen(descptr) + 1;
+ uiInfo.modCount++;
+ if (uiInfo.modCount >= MAX_MODS) {
+ break;
+ }
+ }
+
+}
+
+
+/*
+===============
+UI_LoadTeams
+===============
+*/
+static void UI_LoadTeams( void ) {
+ char teamList[4096];
+ char *teamName;
+ int i, len, count;
+
+ count = trap_FS_GetFileList( "", "team", teamList, 4096 );
+
+ if (count) {
+ teamName = teamList;
+ for ( i = 0; i < count; i++ ) {
+ len = strlen( teamName );
+ UI_ParseTeamInfo(teamName);
+ teamName += len + 1;
+ }
+ }
+
+}
+
+
+/*
+===============
+UI_LoadMovies
+===============
+*/
+static void UI_LoadMovies( void ) {
+ char movielist[4096];
+ char *moviename;
+ int i, len;
+
+ uiInfo.movieCount = trap_FS_GetFileList( "video", "roq", movielist, 4096 );
+
+ if (uiInfo.movieCount) {
+ if (uiInfo.movieCount > MAX_MOVIES) {
+ uiInfo.movieCount = MAX_MOVIES;
+ }
+ moviename = movielist;
+ for ( i = 0; i < uiInfo.movieCount; i++ ) {
+ len = strlen( moviename );
+ if (!Q_stricmp(moviename + len - 4,".roq")) {
+ moviename[len-4] = '\0';
+ }
+ Q_strupr(moviename);
+ uiInfo.movieList[i] = String_Alloc(moviename);
+ moviename += len + 1;
+ }
+ }
+
+}
+
+
+
+/*
+===============
+UI_LoadDemos
+===============
+*/
+static void UI_LoadDemos( void ) {
+ char demolist[4096];
+ char demoExt[32];
+ char *demoname;
+ int i, len;
+
+ Com_sprintf(demoExt, sizeof(demoExt), "dm_%d", (int)trap_Cvar_VariableValue("protocol"));
+
+ uiInfo.demoCount = trap_FS_GetFileList( "demos", demoExt, demolist, 4096 );
+
+ Com_sprintf(demoExt, sizeof(demoExt), ".dm_%d", (int)trap_Cvar_VariableValue("protocol"));
+
+ if (uiInfo.demoCount) {
+ if (uiInfo.demoCount > MAX_DEMOS) {
+ uiInfo.demoCount = MAX_DEMOS;
+ }
+ demoname = demolist;
+ for ( i = 0; i < uiInfo.demoCount; i++ ) {
+ len = strlen( demoname );
+ if (!Q_stricmp(demoname + len - strlen(demoExt), demoExt)) {
+ demoname[len-strlen(demoExt)] = '\0';
+ }
+ Q_strupr(demoname);
+ uiInfo.demoList[i] = String_Alloc(demoname);
+ demoname += len + 1;
+ }
+ }
+
+}
+
+
+static qboolean UI_SetNextMap(int actual, int index) {
+ int i;
+ for (i = actual + 1; i < uiInfo.mapCount; i++) {
+ if (uiInfo.mapList[i].active) {
+ Menu_SetFeederSelection(NULL, FEEDER_MAPS, index + 1, "skirmish");
+ return qtrue;
+ }
+ }
+ return qfalse;
+}
+
+
+static void UI_StartSkirmish(qboolean next) {
+ int i, k, g, delay, temp;
+ float skill;
+ char buff[MAX_STRING_CHARS];
+
+ if (next) {
+ int actual;
+ int index = trap_Cvar_VariableValue("ui_mapIndex");
+ UI_MapCountByGameType(qtrue);
+ UI_SelectedMap(index, &actual);
+ if (UI_SetNextMap(actual, index)) {
+ } else {
+ UI_GameType_HandleKey(0, NULL, K_MOUSE1, qfalse);
+ UI_MapCountByGameType(qtrue);
+ Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, "skirmish");
+ }
+ }
+
+ g = uiInfo.gameTypes[ui_gameType.integer].gtEnum;
+ trap_Cvar_SetValue( "g_gametype", g );
+ trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName) );
+ skill = trap_Cvar_VariableValue( "g_spSkill" );
+ trap_Cvar_Set("ui_scoreMap", uiInfo.mapList[ui_currentMap.integer].mapName);
+
+ k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
+
+ trap_Cvar_Set("ui_singlePlayerActive", "1");
+
+ // set up sp overrides, will be replaced on postgame
+ temp = trap_Cvar_VariableValue( "capturelimit" );
+ trap_Cvar_Set("ui_saveCaptureLimit", va("%i", temp));
+ temp = trap_Cvar_VariableValue( "fraglimit" );
+ trap_Cvar_Set("ui_saveFragLimit", va("%i", temp));
+
+ UI_SetCapFragLimits(qfalse);
+
+ temp = trap_Cvar_VariableValue( "cg_drawTimer" );
+ trap_Cvar_Set("ui_drawTimer", va("%i", temp));
+ temp = trap_Cvar_VariableValue( "g_doWarmup" );
+ trap_Cvar_Set("ui_doWarmup", va("%i", temp));
+ temp = trap_Cvar_VariableValue( "g_friendlyFire" );
+ trap_Cvar_Set("ui_friendlyFire", va("%i", temp));
+ temp = trap_Cvar_VariableValue( "sv_maxClients" );
+ trap_Cvar_Set("ui_maxClients", va("%i", temp));
+ temp = trap_Cvar_VariableValue( "g_warmup" );
+ trap_Cvar_Set("ui_Warmup", va("%i", temp));
+ temp = trap_Cvar_VariableValue( "sv_pure" );
+ trap_Cvar_Set("ui_pure", va("%i", temp));
+
+ trap_Cvar_Set("cg_cameraOrbit", "0");
+ trap_Cvar_Set("cg_thirdPerson", "0");
+ trap_Cvar_Set("cg_drawTimer", "1");
+ trap_Cvar_Set("g_doWarmup", "1");
+ trap_Cvar_Set("g_warmup", "15");
+ trap_Cvar_Set("sv_pure", "0");
+ trap_Cvar_Set("g_friendlyFire", "0");
+ trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
+ trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
+
+ if (trap_Cvar_VariableValue("ui_recordSPDemo")) {
+ Com_sprintf(buff, MAX_STRING_CHARS, "%s_%i", uiInfo.mapList[ui_currentMap.integer].mapLoadName, g);
+ trap_Cvar_Set("ui_recordSPDemoName", buff);
+ }
+
+ delay = 500;
+
+ if (g == GT_TOURNAMENT) {
+ trap_Cvar_Set("sv_maxClients", "2");
+ Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %f "", %i \n", uiInfo.mapList[ui_currentMap.integer].opponentName, skill, delay);
+ trap_Cmd_ExecuteText( EXEC_APPEND, buff );
+ } else {
+ temp = uiInfo.mapList[ui_currentMap.integer].teamMembers * 2;
+ trap_Cvar_Set("sv_maxClients", va("%d", temp));
+ for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers; i++) {
+ Com_sprintf( buff, sizeof(buff), "addbot %s %f %s %i %s\n", UI_AIFromName(uiInfo.teamList[k].teamMembers[i]), skill, (g == GT_FFA) ? "" : "Blue", delay, uiInfo.teamList[k].teamMembers[i]);
+ trap_Cmd_ExecuteText( EXEC_APPEND, buff );
+ delay += 500;
+ }
+ k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+ for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers-1; i++) {
+ Com_sprintf( buff, sizeof(buff), "addbot %s %f %s %i %s\n", UI_AIFromName(uiInfo.teamList[k].teamMembers[i]), skill, (g == GT_FFA) ? "" : "Red", delay, uiInfo.teamList[k].teamMembers[i]);
+ trap_Cmd_ExecuteText( EXEC_APPEND, buff );
+ delay += 500;
+ }
+ }
+ if (g >= GT_TEAM ) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, "wait 5; team Red\n" );
+ }
+}
+
+static void UI_Update(const char *name) {
+ int val = trap_Cvar_VariableValue(name);
+
+ if (Q_stricmp(name, "ui_SetName") == 0) {
+ trap_Cvar_Set( "name", UI_Cvar_VariableString("ui_Name"));
+ } else if (Q_stricmp(name, "ui_setRate") == 0) {
+ float rate = trap_Cvar_VariableValue("rate");
+ if (rate >= 5000) {
+ trap_Cvar_Set("cl_maxpackets", "30");
+ trap_Cvar_Set("cl_packetdup", "1");
+ } else if (rate >= 4000) {
+ trap_Cvar_Set("cl_maxpackets", "15");
+ trap_Cvar_Set("cl_packetdup", "2"); // favor less prediction errors when there's packet loss
+ } else {
+ trap_Cvar_Set("cl_maxpackets", "15");
+ trap_Cvar_Set("cl_packetdup", "1"); // favor lower bandwidth
+ }
+ } else if (Q_stricmp(name, "ui_GetName") == 0) {
+ trap_Cvar_Set( "ui_Name", UI_Cvar_VariableString("name"));
+ } else if (Q_stricmp(name, "r_colorbits") == 0) {
+ switch (val) {
+ case 0:
+ trap_Cvar_SetValue( "r_depthbits", 0 );
+ trap_Cvar_SetValue( "r_stencilbits", 0 );
+ break;
+ case 16:
+ trap_Cvar_SetValue( "r_depthbits", 16 );
+ trap_Cvar_SetValue( "r_stencilbits", 0 );
+ break;
+ case 32:
+ trap_Cvar_SetValue( "r_depthbits", 24 );
+ break;
+ }
+ } else if (Q_stricmp(name, "r_lodbias") == 0) {
+ switch (val) {
+ case 0:
+ trap_Cvar_SetValue( "r_subdivisions", 4 );
+ break;
+ case 1:
+ trap_Cvar_SetValue( "r_subdivisions", 12 );
+ break;
+ case 2:
+ trap_Cvar_SetValue( "r_subdivisions", 20 );
+ break;
+ }
+ } else if (Q_stricmp(name, "ui_glCustom") == 0) {
+ switch (val) {
+ case 0: // high quality
+ trap_Cvar_SetValue( "r_fullScreen", 1 );
+ trap_Cvar_SetValue( "r_subdivisions", 4 );
+ trap_Cvar_SetValue( "r_vertexlight", 0 );
+ trap_Cvar_SetValue( "r_lodbias", 0 );
+ trap_Cvar_SetValue( "r_colorbits", 32 );
+ trap_Cvar_SetValue( "r_depthbits", 24 );
+ trap_Cvar_SetValue( "r_picmip", 0 );
+ trap_Cvar_SetValue( "r_mode", 4 );
+ trap_Cvar_SetValue( "r_texturebits", 32 );
+ trap_Cvar_SetValue( "r_fastSky", 0 );
+ trap_Cvar_SetValue( "r_inGameVideo", 1 );
+ trap_Cvar_SetValue( "cg_shadows", 1 );
+ trap_Cvar_SetValue( "cg_brassTime", 2500 );
+ trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
+ break;
+ case 1: // normal
+ trap_Cvar_SetValue( "r_fullScreen", 1 );
+ trap_Cvar_SetValue( "r_subdivisions", 12 );
+ trap_Cvar_SetValue( "r_vertexlight", 0 );
+ trap_Cvar_SetValue( "r_lodbias", 0 );
+ trap_Cvar_SetValue( "r_colorbits", 0 );
+ trap_Cvar_SetValue( "r_depthbits", 24 );
+ trap_Cvar_SetValue( "r_picmip", 1 );
+ trap_Cvar_SetValue( "r_mode", 3 );
+ trap_Cvar_SetValue( "r_texturebits", 0 );
+ trap_Cvar_SetValue( "r_fastSky", 0 );
+ trap_Cvar_SetValue( "r_inGameVideo", 1 );
+ trap_Cvar_SetValue( "cg_brassTime", 2500 );
+ trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
+ trap_Cvar_SetValue( "cg_shadows", 0 );
+ break;
+ case 2: // fast
+ trap_Cvar_SetValue( "r_fullScreen", 1 );
+ trap_Cvar_SetValue( "r_subdivisions", 8 );
+ trap_Cvar_SetValue( "r_vertexlight", 0 );
+ trap_Cvar_SetValue( "r_lodbias", 1 );
+ trap_Cvar_SetValue( "r_colorbits", 0 );
+ trap_Cvar_SetValue( "r_depthbits", 0 );
+ trap_Cvar_SetValue( "r_picmip", 1 );
+ trap_Cvar_SetValue( "r_mode", 3 );
+ trap_Cvar_SetValue( "r_texturebits", 0 );
+ trap_Cvar_SetValue( "cg_shadows", 0 );
+ trap_Cvar_SetValue( "r_fastSky", 1 );
+ trap_Cvar_SetValue( "r_inGameVideo", 0 );
+ trap_Cvar_SetValue( "cg_brassTime", 0 );
+ trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
+ break;
+ case 3: // fastest
+ trap_Cvar_SetValue( "r_fullScreen", 1 );
+ trap_Cvar_SetValue( "r_subdivisions", 20 );
+ trap_Cvar_SetValue( "r_vertexlight", 1 );
+ trap_Cvar_SetValue( "r_lodbias", 2 );
+ trap_Cvar_SetValue( "r_colorbits", 16 );
+ trap_Cvar_SetValue( "r_depthbits", 16 );
+ trap_Cvar_SetValue( "r_mode", 3 );
+ trap_Cvar_SetValue( "r_picmip", 2 );
+ trap_Cvar_SetValue( "r_texturebits", 16 );
+ trap_Cvar_SetValue( "cg_shadows", 0 );
+ trap_Cvar_SetValue( "cg_brassTime", 0 );
+ trap_Cvar_SetValue( "r_fastSky", 1 );
+ trap_Cvar_SetValue( "r_inGameVideo", 0 );
+ trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
+ break;
+ }
+ } else if (Q_stricmp(name, "ui_mousePitch") == 0) {
+ if (val == 0) {
+ trap_Cvar_SetValue( "m_pitch", 0.022f );
+ } else {
+ trap_Cvar_SetValue( "m_pitch", -0.022f );
+ }
+ }
+}
+
+static void UI_RunMenuScript(char **args) {
+ const char *name, *name2;
+ char buff[1024];
+
+ if (String_Parse(args, &name)) {
+ if (Q_stricmp(name, "StartServer") == 0) {
+ int i, clients, oldclients;
+ float skill;
+ trap_Cvar_Set("cg_thirdPerson", "0");
+ trap_Cvar_Set("cg_cameraOrbit", "0");
+ trap_Cvar_Set("ui_singlePlayerActive", "0");
+ trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, ui_dedicated.integer ) );
+ trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, 13, uiInfo.gameTypes[ui_netGameType.integer].gtEnum ) );
+ trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
+ trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
+ trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName ) );
+ skill = trap_Cvar_VariableValue( "g_spSkill" );
+ // set max clients based on spots
+ oldclients = trap_Cvar_VariableValue( "sv_maxClients" );
+ clients = 0;
+ for (i = 0; i < PLAYERS_PER_TEAM; i++) {
+ int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
+ if (bot >= 0) {
+ clients++;
+ }
+ bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
+ if (bot >= 0) {
+ clients++;
+ }
+ }
+ if (clients == 0) {
+ clients = 8;
+ }
+
+ if (oldclients > clients) {
+ clients = oldclients;
+ }
+
+ trap_Cvar_Set("sv_maxClients", va("%d",clients));
+
+ for (i = 0; i < PLAYERS_PER_TEAM; i++) {
+ int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
+ if (bot > 1) {
+ if (ui_actualNetGameType.integer >= GT_TEAM) {
+ Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Blue");
+ } else {
+ Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
+ }
+ trap_Cmd_ExecuteText( EXEC_APPEND, buff );
+ }
+ bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
+ if (bot > 1) {
+ if (ui_actualNetGameType.integer >= GT_TEAM) {
+ Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Red");
+ } else {
+ Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
+ }
+ trap_Cmd_ExecuteText( EXEC_APPEND, buff );
+ }
+ }
+ } else if (Q_stricmp(name, "updateSPMenu") == 0) {
+ UI_SetCapFragLimits(qtrue);
+ UI_MapCountByGameType(qtrue);
+ ui_mapIndex.integer = UI_GetIndexFromSelection(ui_currentMap.integer);
+ trap_Cvar_Set("ui_mapIndex", va("%d", ui_mapIndex.integer));
+ Menu_SetFeederSelection(NULL, FEEDER_MAPS, ui_mapIndex.integer, "skirmish");
+ UI_GameType_HandleKey(0, NULL, K_MOUSE1, qfalse);
+ UI_GameType_HandleKey(0, NULL, K_MOUSE2, qfalse);
+ } else if (Q_stricmp(name, "resetDefaults") == 0) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n");
+ trap_Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n");
+ Controls_SetDefaults();
+ trap_Cvar_Set("com_introPlayed", "1" );
+ trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" );
+ } else if (Q_stricmp(name, "getCDKey") == 0) {
+ char out[17];
+ trap_GetCDKey(buff, 17);
+ trap_Cvar_Set("cdkey1", "");
+ trap_Cvar_Set("cdkey2", "");
+ trap_Cvar_Set("cdkey3", "");
+ trap_Cvar_Set("cdkey4", "");
+ if (strlen(buff) == CDKEY_LEN) {
+ Q_strncpyz(out, buff, 5);
+ trap_Cvar_Set("cdkey1", out);
+ Q_strncpyz(out, buff + 4, 5);
+ trap_Cvar_Set("cdkey2", out);
+ Q_strncpyz(out, buff + 8, 5);
+ trap_Cvar_Set("cdkey3", out);
+ Q_strncpyz(out, buff + 12, 5);
+ trap_Cvar_Set("cdkey4", out);
+ }
+
+ } else if (Q_stricmp(name, "verifyCDKey") == 0) {
+ buff[0] = '\0';
+ Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey1"));
+ Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey2"));
+ Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey3"));
+ Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey4"));
+ trap_Cvar_Set("cdkey", buff);
+ if (trap_VerifyCDKey(buff, UI_Cvar_VariableString("cdkeychecksum"))) {
+ trap_Cvar_Set("ui_cdkeyvalid", "CD Key Appears to be valid.");
+ trap_SetCDKey(buff);
+ } else {
+ trap_Cvar_Set("ui_cdkeyvalid", "CD Key does not appear to be valid.");
+ }
+ } else if (Q_stricmp(name, "loadArenas") == 0) {
+ UI_LoadArenas();
+ UI_MapCountByGameType(qfalse);
+ Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, "createserver");
+ } else if (Q_stricmp(name, "saveControls") == 0) {
+ Controls_SetConfig(qtrue);
+ } else if (Q_stricmp(name, "loadControls") == 0) {
+ Controls_GetConfig();
+ } else if (Q_stricmp(name, "clearError") == 0) {
+ trap_Cvar_Set("com_errorMessage", "");
+ } else if (Q_stricmp(name, "loadGameInfo") == 0) {
+#ifdef PRE_RELEASE_TADEMO
+ UI_ParseGameInfo("demogameinfo.txt");
+#else
+ UI_ParseGameInfo("gameinfo.txt");
+#endif
+ UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
+ } else if (Q_stricmp(name, "resetScores") == 0) {
+ UI_ClearScores();
+ } else if (Q_stricmp(name, "RefreshServers") == 0) {
+ UI_StartServerRefresh(qtrue);
+ UI_BuildServerDisplayList(qtrue);
+ } else if (Q_stricmp(name, "RefreshFilter") == 0) {
+ UI_StartServerRefresh(qfalse);
+ UI_BuildServerDisplayList(qtrue);
+ } else if (Q_stricmp(name, "RunSPDemo") == 0) {
+ if (uiInfo.demoAvailable) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s_%i\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum));
+ }
+ } else if (Q_stricmp(name, "LoadDemos") == 0) {
+ UI_LoadDemos();
+ } else if (Q_stricmp(name, "LoadMovies") == 0) {
+ UI_LoadMovies();
+ } else if (Q_stricmp(name, "LoadMods") == 0) {
+ UI_LoadMods();
+ } else if (Q_stricmp(name, "playMovie") == 0) {
+ if (uiInfo.previewMovie >= 0) {
+ trap_CIN_StopCinematic(uiInfo.previewMovie);
+ }
+ trap_Cmd_ExecuteText( EXEC_APPEND, va("cinematic %s.roq 2\n", uiInfo.movieList[uiInfo.movieIndex]));
+ } else if (Q_stricmp(name, "RunMod") == 0) {
+ trap_Cvar_Set( "fs_game", uiInfo.modList[uiInfo.modIndex].modName);
+ trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
+ } else if (Q_stricmp(name, "RunDemo") == 0) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s\n", uiInfo.demoList[uiInfo.demoIndex]));
+ } else if (Q_stricmp(name, "Quake3") == 0) {
+ trap_Cvar_Set( "fs_game", "");
+ trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
+ } else if (Q_stricmp(name, "closeJoin") == 0) {
+ if (uiInfo.serverStatus.refreshActive) {
+ UI_StopServerRefresh();
+ uiInfo.serverStatus.nextDisplayRefresh = 0;
+ uiInfo.nextServerStatusRefresh = 0;
+ uiInfo.nextFindPlayerRefresh = 0;
+ UI_BuildServerDisplayList(qtrue);
+ } else {
+ Menus_CloseByName("joinserver");
+ Menus_OpenByName("main");
+ }
+ } else if (Q_stricmp(name, "StopRefresh") == 0) {
+ UI_StopServerRefresh();
+ uiInfo.serverStatus.nextDisplayRefresh = 0;
+ uiInfo.nextServerStatusRefresh = 0;
+ uiInfo.nextFindPlayerRefresh = 0;
+ } else if (Q_stricmp(name, "UpdateFilter") == 0) {
+ if (ui_netSource.integer == AS_LOCAL) {
+ UI_StartServerRefresh(qtrue);
+ }
+ UI_BuildServerDisplayList(qtrue);
+ UI_FeederSelection(FEEDER_SERVERS, 0);
+ } else if (Q_stricmp(name, "ServerStatus") == 0) {
+ trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], uiInfo.serverStatusAddress, sizeof(uiInfo.serverStatusAddress));
+ UI_BuildServerStatus(qtrue);
+ } else if (Q_stricmp(name, "FoundPlayerServerStatus") == 0) {
+ Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
+ UI_BuildServerStatus(qtrue);
+ Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
+ } else if (Q_stricmp(name, "FindPlayer") == 0) {
+ UI_BuildFindPlayerList(qtrue);
+ // clear the displayed server status info
+ uiInfo.serverStatusInfo.numLines = 0;
+ Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
+ } else if (Q_stricmp(name, "JoinServer") == 0) {
+ trap_Cvar_Set("cg_thirdPerson", "0");
+ trap_Cvar_Set("cg_cameraOrbit", "0");
+ trap_Cvar_Set("ui_singlePlayerActive", "0");
+ if (uiInfo.serverStatus.currentServer >= 0 && uiInfo.serverStatus.currentServer < uiInfo.serverStatus.numDisplayServers) {
+ trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, 1024);
+ trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", buff ) );
+ }
+ } else if (Q_stricmp(name, "FoundPlayerJoinServer") == 0) {
+ trap_Cvar_Set("ui_singlePlayerActive", "0");
+ if (uiInfo.currentFoundPlayerServer >= 0 && uiInfo.currentFoundPlayerServer < uiInfo.numFoundPlayerServers) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer] ) );
+ }
+ } else if (Q_stricmp(name, "Quit") == 0) {
+ trap_Cvar_Set("ui_singlePlayerActive", "0");
+ trap_Cmd_ExecuteText( EXEC_NOW, "quit");
+ } else if (Q_stricmp(name, "Controls") == 0) {
+ trap_Cvar_Set( "cl_paused", "1" );
+ trap_Key_SetCatcher( KEYCATCH_UI );
+ Menus_CloseAll();
+ Menus_ActivateByName("setup_menu2");
+ } else if (Q_stricmp(name, "Leave") == 0) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" );
+ trap_Key_SetCatcher( KEYCATCH_UI );
+ Menus_CloseAll();
+ Menus_ActivateByName("main");
+ } else if (Q_stricmp(name, "ServerSort") == 0) {
+ int sortColumn;
+ if (Int_Parse(args, &sortColumn)) {
+ // if same column we're already sorting on then flip the direction
+ if (sortColumn == uiInfo.serverStatus.sortKey) {
+ uiInfo.serverStatus.sortDir = !uiInfo.serverStatus.sortDir;
+ }
+ // make sure we sort again
+ UI_ServersSort(sortColumn, qtrue);
+ }
+ } else if (Q_stricmp(name, "nextSkirmish") == 0) {
+ UI_StartSkirmish(qtrue);
+ } else if (Q_stricmp(name, "SkirmishStart") == 0) {
+ UI_StartSkirmish(qfalse);
+ } else if (Q_stricmp(name, "closeingame") == 0) {
+ trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
+ trap_Key_ClearStates();
+ trap_Cvar_Set( "cl_paused", "0" );
+ Menus_CloseAll();
+ } else if (Q_stricmp(name, "voteMap") == 0) {
+ if (ui_currentNetMap.integer >=0 && ui_currentNetMap.integer < uiInfo.mapCount) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote map %s\n",uiInfo.mapList[ui_currentNetMap.integer].mapLoadName) );
+ }
+ } else if (Q_stricmp(name, "voteKick") == 0) {
+ if (uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote kick %s\n",uiInfo.playerNames[uiInfo.playerIndex]) );
+ }
+ } else if (Q_stricmp(name, "voteGame") == 0) {
+ if (ui_netGameType.integer >= 0 && ui_netGameType.integer < uiInfo.numGameTypes) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote g_gametype %i\n",uiInfo.gameTypes[ui_netGameType.integer].gtEnum) );
+ }
+ } else if (Q_stricmp(name, "voteLeader") == 0) {
+ if (uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, va("callteamvote leader %s\n",uiInfo.teamNames[uiInfo.teamIndex]) );
+ }
+ } else if (Q_stricmp(name, "addBot") == 0) {
+ if (trap_Cvar_VariableValue("g_gametype") >= GT_TEAM && !GT_LMS ) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", uiInfo.characterList[uiInfo.botIndex].name, uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") );
+ } else {
+ trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", UI_GetBotNameByNumber(uiInfo.botIndex), uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") );
+ }
+ } else if (Q_stricmp(name, "addFavorite") == 0) {
+ if (ui_netSource.integer != AS_FAVORITES) {
+ char name[MAX_NAME_LENGTH];
+ char addr[MAX_NAME_LENGTH];
+ int res;
+
+ trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
+ name[0] = addr[0] = '\0';
+ Q_strncpyz(name, Info_ValueForKey(buff, "hostname"), MAX_NAME_LENGTH);
+ Q_strncpyz(addr, Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
+ if (strlen(name) > 0 && strlen(addr) > 0) {
+ res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
+ if (res == 0) {
+ // server already in the list
+ Com_Printf("Favorite already in list\n");
+ }
+ else if (res == -1) {
+ // list full
+ Com_Printf("Favorite list full\n");
+ }
+ else {
+ // successfully added
+ Com_Printf("Added favorite server %s\n", addr);
+ }
+ }
+ }
+ } else if (Q_stricmp(name, "deleteFavorite") == 0) {
+ if (ui_netSource.integer == AS_FAVORITES) {
+ char addr[MAX_NAME_LENGTH];
+ trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
+ addr[0] = '\0';
+ Q_strncpyz(addr, Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
+ if (strlen(addr) > 0) {
+ trap_LAN_RemoveServer(AS_FAVORITES, addr);
+ }
+ }
+ } else if (Q_stricmp(name, "createFavorite") == 0) {
+ if (ui_netSource.integer == AS_FAVORITES) {
+ char name[MAX_NAME_LENGTH];
+ char addr[MAX_NAME_LENGTH];
+ int res;
+
+ name[0] = addr[0] = '\0';
+ Q_strncpyz(name, UI_Cvar_VariableString("ui_favoriteName"), MAX_NAME_LENGTH);
+ Q_strncpyz(addr, UI_Cvar_VariableString("ui_favoriteAddress"), MAX_NAME_LENGTH);
+ if (strlen(name) > 0 && strlen(addr) > 0) {
+ res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
+ if (res == 0) {
+ // server already in the list
+ Com_Printf("Favorite already in list\n");
+ }
+ else if (res == -1) {
+ // list full
+ Com_Printf("Favorite list full\n");
+ }
+ else {
+ // successfully added
+ Com_Printf("Added favorite server %s\n", addr);
+ }
+ }
+ }
+ } else if (Q_stricmp(name, "orders") == 0) {
+ const char *orders;
+ if (String_Parse(args, &orders)) {
+ int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
+ if (selectedPlayer < uiInfo.myTeamCount) {
+ strcpy(buff, orders);
+ trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
+ trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
+ } else {
+ int i;
+ for (i = 0; i < uiInfo.myTeamCount; i++) {
+ if (Q_stricmp(UI_Cvar_VariableString("name"), uiInfo.teamNames[i]) == 0) {
+ continue;
+ }
+ strcpy(buff, orders);
+ trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamNames[i]) );
+ trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
+ }
+ }
+ trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
+ trap_Key_ClearStates();
+ trap_Cvar_Set( "cl_paused", "0" );
+ Menus_CloseAll();
+ }
+ } else if (Q_stricmp(name, "voiceOrdersTeam") == 0) {
+ const char *orders;
+ if (String_Parse(args, &orders)) {
+ int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
+ if (selectedPlayer == uiInfo.myTeamCount) {
+ trap_Cmd_ExecuteText( EXEC_APPEND, orders );
+ trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
+ }
+ trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
+ trap_Key_ClearStates();
+ trap_Cvar_Set( "cl_paused", "0" );
+ Menus_CloseAll();
+ }
+ } else if (Q_stricmp(name, "voiceOrders") == 0) {
+ const char *orders;
+ if (String_Parse(args, &orders)) {
+ int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
+ if (selectedPlayer < uiInfo.myTeamCount) {
+ strcpy(buff, orders);
+ trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
+ trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
+ }
+ trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
+ trap_Key_ClearStates();
+ trap_Cvar_Set( "cl_paused", "0" );
+ Menus_CloseAll();
+ }
+ } else if (Q_stricmp(name, "glCustom") == 0) {
+ trap_Cvar_Set("ui_glCustom", "4");
+ } else if (Q_stricmp(name, "update") == 0) {
+ if (String_Parse(args, &name2)) {
+ UI_Update(name2);
+ }
+ } else if (Q_stricmp(name, "setPbClStatus") == 0) {
+ int stat;
+ if ( Int_Parse( args, &stat ) )
+ trap_SetPbClStatus( stat );
+ }
+ else {
+ Com_Printf("unknown UI script %s\n", name);
+ }
+ }
+}
+
+static void UI_GetTeamColor(vec4_t *color) {
+}
+
+/*
+==================
+UI_MapCountByGameType
+==================
+*/
+static int UI_MapCountByGameType(qboolean singlePlayer) {
+ int i, c, game;
+ c = 0;
+ game = singlePlayer ? uiInfo.gameTypes[ui_gameType.integer].gtEnum : uiInfo.gameTypes[ui_netGameType.integer].gtEnum;
+ if (game == GT_SINGLE_PLAYER) {
+ game++;
+ }
+ if (game == GT_TEAM) {
+ game = GT_FFA;
+ }
+
+ for (i = 0; i < uiInfo.mapCount; i++) {
+ uiInfo.mapList[i].active = qfalse;
+ if ( uiInfo.mapList[i].typeBits & (1 << game)) {
+ if (singlePlayer) {
+ if (!(uiInfo.mapList[i].typeBits & (1 << GT_SINGLE_PLAYER))) {
+ continue;
+ }
+ }
+ c++;
+ uiInfo.mapList[i].active = qtrue;
+ }
+ }
+ return c;
+}
+
+qboolean UI_hasSkinForBase(const char *base, const char *team) {
+ char test[1024];
+
+ Com_sprintf( test, sizeof( test ), "models/players/%s/%s/lower_default.skin", base, team );
+
+ if (trap_FS_FOpenFile(test, NULL, FS_READ)) {
+ return qtrue;
+ }
+ Com_sprintf( test, sizeof( test ), "models/players/characters/%s/%s/lower_default.skin", base, team );
+
+ if (trap_FS_FOpenFile(test, NULL, FS_READ)) {
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+UI_MapCountByTeam
+==================
+*/
+static int UI_HeadCountByTeam(void) {
+ static int init = 0;
+ int i, j, k, c, tIndex;
+
+ c = 0;
+ if (!init) {
+ for (i = 0; i < uiInfo.characterCount; i++) {
+ uiInfo.characterList[i].reference = 0;
+ for (j = 0; j < uiInfo.teamCount; j++) {
+ if (UI_hasSkinForBase(uiInfo.characterList[i].base, uiInfo.teamList[j].teamName)) {
+ uiInfo.characterList[i].reference |= (1<<j);
+ }
+ }
+ }
+ init = 1;
+ }
+
+ tIndex = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+
+ // do names
+ for (i = 0; i < uiInfo.characterCount; i++) {
+ uiInfo.characterList[i].active = qfalse;
+ for(j = 0; j < TEAM_MEMBERS; j++) {
+ if (uiInfo.teamList[tIndex].teamMembers[j] != NULL) {
+ if (uiInfo.characterList[i].reference&(1<<tIndex)) {// && Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.characterList[i].name)==0) {
+ uiInfo.characterList[i].active = qtrue;
+ c++;
+ break;
+ }
+ }
+ }
+ }
+
+ // and then aliases
+ for(j = 0; j < TEAM_MEMBERS; j++) {
+ for(k = 0; k < uiInfo.aliasCount; k++) {
+ if (uiInfo.aliasList[k].name != NULL) {
+ if (Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.aliasList[k].name)==0) {
+ for (i = 0; i < uiInfo.characterCount; i++) {
+ if (uiInfo.characterList[i].headImage != -1 && uiInfo.characterList[i].reference&(1<<tIndex) && Q_stricmp(uiInfo.aliasList[k].ai, uiInfo.characterList[i].name)==0) {
+ if (uiInfo.characterList[i].active == qfalse) {
+ uiInfo.characterList[i].active = qtrue;
+ c++;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return c;
+}
+
+/*
+==================
+UI_InsertServerIntoDisplayList
+==================
+*/
+static void UI_InsertServerIntoDisplayList(int num, int position) {
+ int i;
+
+ if (position < 0 || position > uiInfo.serverStatus.numDisplayServers ) {
+ return;
+ }
+ //
+ uiInfo.serverStatus.numDisplayServers++;
+ for (i = uiInfo.serverStatus.numDisplayServers; i > position; i--) {
+ uiInfo.serverStatus.displayServers[i] = uiInfo.serverStatus.displayServers[i-1];
+ }
+ uiInfo.serverStatus.displayServers[position] = num;
+}
+
+/*
+==================
+UI_RemoveServerFromDisplayList
+==================
+*/
+static void UI_RemoveServerFromDisplayList(int num) {
+ int i, j;
+
+ for (i = 0; i < uiInfo.serverStatus.numDisplayServers; i++) {
+ if (uiInfo.serverStatus.displayServers[i] == num) {
+ uiInfo.serverStatus.numDisplayServers--;
+ for (j = i; j < uiInfo.serverStatus.numDisplayServers; j++) {
+ uiInfo.serverStatus.displayServers[j] = uiInfo.serverStatus.displayServers[j+1];
+ }
+ return;
+ }
+ }
+}
+
+/*
+==================
+UI_BinaryServerInsertion
+==================
+*/
+static void UI_BinaryServerInsertion(int num) {
+ int mid, offset, res, len;
+
+ // use binary search to insert server
+ len = uiInfo.serverStatus.numDisplayServers;
+ mid = len;
+ offset = 0;
+ res = 0;
+ while(mid > 0) {
+ mid = len >> 1;
+ //
+ res = trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey,
+ uiInfo.serverStatus.sortDir, num, uiInfo.serverStatus.displayServers[offset+mid]);
+ // if equal
+ if (res == 0) {
+ UI_InsertServerIntoDisplayList(num, offset+mid);
+ return;
+ }
+ // if larger
+ else if (res == 1) {
+ offset += mid;
+ len -= mid;
+ }
+ // if smaller
+ else {
+ len -= mid;
+ }
+ }
+ if (res == 1) {
+ offset++;
+ }
+ UI_InsertServerIntoDisplayList(num, offset);
+}
+
+/*
+==================
+UI_BuildServerDisplayList
+==================
+*/
+static void UI_BuildServerDisplayList(qboolean force) {
+ int i, count, clients, maxClients, ping, game, len, visible;
+ char info[MAX_STRING_CHARS];
+// qboolean startRefresh = qtrue; TTimo: unused
+ static int numinvisible;
+
+ if (!(force || uiInfo.uiDC.realTime > uiInfo.serverStatus.nextDisplayRefresh)) {
+ return;
+ }
+ // if we shouldn't reset
+ if ( force == 2 ) {
+ force = 0;
+ }
+
+ // do motd updates here too
+ trap_Cvar_VariableStringBuffer( "cl_motdString", uiInfo.serverStatus.motd, sizeof(uiInfo.serverStatus.motd) );
+ len = strlen(uiInfo.serverStatus.motd);
+ if (len == 0) {
+ strcpy(uiInfo.serverStatus.motd, "Welcome to Team Arena!");
+ len = strlen(uiInfo.serverStatus.motd);
+ }
+ if (len != uiInfo.serverStatus.motdLen) {
+ uiInfo.serverStatus.motdLen = len;
+ uiInfo.serverStatus.motdWidth = -1;
+ }
+
+ if (force) {
+ numinvisible = 0;
+ // clear number of displayed servers
+ uiInfo.serverStatus.numDisplayServers = 0;
+ uiInfo.serverStatus.numPlayersOnServers = 0;
+ // set list box index to zero
+ Menu_SetFeederSelection(NULL, FEEDER_SERVERS, 0, NULL);
+ // mark all servers as visible so we store ping updates for them
+ trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
+ }
+
+ // get the server count (comes from the master)
+ count = trap_LAN_GetServerCount(ui_netSource.integer);
+ if (count == -1 || (ui_netSource.integer == AS_LOCAL && count == 0) ) {
+ // still waiting on a response from the master
+ uiInfo.serverStatus.numDisplayServers = 0;
+ uiInfo.serverStatus.numPlayersOnServers = 0;
+ uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 500;
+ return;
+ }
+
+ visible = qfalse;
+ for (i = 0; i < count; i++) {
+ // if we already got info for this server
+ if (!trap_LAN_ServerIsVisible(ui_netSource.integer, i)) {
+ continue;
+ }
+ visible = qtrue;
+ // get the ping for this server
+ ping = trap_LAN_GetServerPing(ui_netSource.integer, i);
+ if (ping > 0 || ui_netSource.integer == AS_FAVORITES) {
+
+ trap_LAN_GetServerInfo(ui_netSource.integer, i, info, MAX_STRING_CHARS);
+
+ if(trap_Cvar_VariableValue("ui_humansonly"))
+ clients = atoi(Info_ValueForKey(info, "g_humanplayers"));
+ else
+ clients = atoi(Info_ValueForKey(info, "clients"));
+ uiInfo.serverStatus.numPlayersOnServers += clients;
+
+ if (ui_browserShowEmpty.integer == 0) {
+ if (clients == 0) {
+ trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
+ continue;
+ }
+ }
+
+ if (ui_browserShowFull.integer == 0) {
+ maxClients = atoi(Info_ValueForKey(info, "sv_maxclients"));
+ if (clients == maxClients) {
+ trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
+ continue;
+ }
+ }
+
+ if (uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum != -1) {
+ game = atoi(Info_ValueForKey(info, "gametype"));
+ if (game != uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum) {
+ trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
+ continue;
+ }
+ }
+
+ if (ui_serverFilterType.integer > 0) {
+ if (Q_stricmp(Info_ValueForKey(info, "game"), serverFilters[ui_serverFilterType.integer].basedir) != 0) {
+ trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
+ continue;
+ }
+ }
+ // make sure we never add a favorite server twice
+ if (ui_netSource.integer == AS_FAVORITES) {
+ UI_RemoveServerFromDisplayList(i);
+ }
+ // insert the server into the list
+ UI_BinaryServerInsertion(i);
+ // done with this server
+ if (ping > 0) {
+ trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
+ numinvisible++;
+ }
+ }
+ }
+
+ uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime;
+
+ // if there were no servers visible for ping updates
+ if (!visible) {
+// UI_StopServerRefresh();
+// uiInfo.serverStatus.nextDisplayRefresh = 0;
+ }
+}
+
+typedef struct
+{
+ char *name, *altName;
+} serverStatusCvar_t;
+
+serverStatusCvar_t serverStatusCvars[] = {
+ {"sv_hostname", "Name"},
+ {"Address", ""},
+ {"gamename", "Game name"},
+ {"g_gametype", "Game type"},
+ {"mapname", "Map"},
+ {"version", ""},
+ {"protocol", ""},
+ {"timelimit", ""},
+ {"fraglimit", ""},
+ {NULL, NULL}
+};
+
+/*
+==================
+UI_SortServerStatusInfo
+==================
+*/
+static void UI_SortServerStatusInfo( serverStatusInfo_t *info ) {
+ int i, j, index;
+ char *tmp1, *tmp2;
+
+ // FIXME: if "gamename" == "baseq3" or "missionpack" then
+ // replace the gametype number by FFA, CTF etc.
+ //
+ index = 0;
+ for (i = 0; serverStatusCvars[i].name; i++) {
+ for (j = 0; j < info->numLines; j++) {
+ if ( !info->lines[j][1] || info->lines[j][1][0] ) {
+ continue;
+ }
+ if ( !Q_stricmp(serverStatusCvars[i].name, info->lines[j][0]) ) {
+ // swap lines
+ tmp1 = info->lines[index][0];
+ tmp2 = info->lines[index][3];
+ info->lines[index][0] = info->lines[j][0];
+ info->lines[index][3] = info->lines[j][3];
+ info->lines[j][0] = tmp1;
+ info->lines[j][3] = tmp2;
+ //
+ if ( strlen(serverStatusCvars[i].altName) ) {
+ info->lines[index][0] = serverStatusCvars[i].altName;
+ }
+ index++;
+ }
+ }
+ }
+}
+
+/*
+==================
+UI_GetServerStatusInfo
+==================
+*/
+static int UI_GetServerStatusInfo( const char *serverAddress, serverStatusInfo_t *info ) {
+ char *p, *score, *ping, *name;
+ int i, len;
+
+ if (!info) {
+ trap_LAN_ServerStatus( serverAddress, NULL, 0);
+ return qfalse;
+ }
+ memset(info, 0, sizeof(*info));
+ if ( trap_LAN_ServerStatus( serverAddress, info->text, sizeof(info->text)) ) {
+ Q_strncpyz(info->address, serverAddress, sizeof(info->address));
+ p = info->text;
+ info->numLines = 0;
+ info->lines[info->numLines][0] = "Address";
+ info->lines[info->numLines][1] = "";
+ info->lines[info->numLines][2] = "";
+ info->lines[info->numLines][3] = info->address;
+ info->numLines++;
+ // get the cvars
+ while (p && *p) {
+ p = strchr(p, '\\');
+ if (!p) break;
+ *p++ = '\0';
+ if (*p == '\\')
+ break;
+ info->lines[info->numLines][0] = p;
+ info->lines[info->numLines][1] = "";
+ info->lines[info->numLines][2] = "";
+ p = strchr(p, '\\');
+ if (!p) break;
+ *p++ = '\0';
+ info->lines[info->numLines][3] = p;
+
+ info->numLines++;
+ if (info->numLines >= MAX_SERVERSTATUS_LINES)
+ break;
+ }
+ // get the player list
+ if (info->numLines < MAX_SERVERSTATUS_LINES-3) {
+ // empty line
+ info->lines[info->numLines][0] = "";
+ info->lines[info->numLines][1] = "";
+ info->lines[info->numLines][2] = "";
+ info->lines[info->numLines][3] = "";
+ info->numLines++;
+ // header
+ info->lines[info->numLines][0] = "num";
+ info->lines[info->numLines][1] = "score";
+ info->lines[info->numLines][2] = "ping";
+ info->lines[info->numLines][3] = "name";
+ info->numLines++;
+ // parse players
+ i = 0;
+ len = 0;
+ while (p && *p) {
+ if (*p == '\\')
+ *p++ = '\0';
+ if (!p)
+ break;
+ score = p;
+ p = strchr(p, ' ');
+ if (!p)
+ break;
+ *p++ = '\0';
+ ping = p;
+ p = strchr(p, ' ');
+ if (!p)
+ break;
+ *p++ = '\0';
+ name = p;
+ Com_sprintf(&info->pings[len], sizeof(info->pings)-len, "%d", i);
+ info->lines[info->numLines][0] = &info->pings[len];
+ len += strlen(&info->pings[len]) + 1;
+ info->lines[info->numLines][1] = score;
+ info->lines[info->numLines][2] = ping;
+ info->lines[info->numLines][3] = name;
+ info->numLines++;
+ if (info->numLines >= MAX_SERVERSTATUS_LINES)
+ break;
+ p = strchr(p, '\\');
+ if (!p)
+ break;
+ *p++ = '\0';
+ //
+ i++;
+ }
+ }
+ UI_SortServerStatusInfo( info );
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==================
+stristr
+==================
+*/
+static char *stristr(char *str, char *charset) {
+ int i;
+
+ while(*str) {
+ for (i = 0; charset[i] && str[i]; i++) {
+ if (toupper(charset[i]) != toupper(str[i])) break;
+ }
+ if (!charset[i]) return str;
+ str++;
+ }
+ return NULL;
+}
+
+/*
+==================
+UI_BuildFindPlayerList
+==================
+*/
+static void UI_BuildFindPlayerList(qboolean force) {
+ static int numFound, numTimeOuts;
+ int i, j, resend;
+ serverStatusInfo_t info;
+ char name[MAX_NAME_LENGTH+2];
+ char infoString[MAX_STRING_CHARS];
+
+ if (!force) {
+ if (!uiInfo.nextFindPlayerRefresh || uiInfo.nextFindPlayerRefresh > uiInfo.uiDC.realTime) {
+ return;
+ }
+ }
+ else {
+ memset(&uiInfo.pendingServerStatus, 0, sizeof(uiInfo.pendingServerStatus));
+ uiInfo.numFoundPlayerServers = 0;
+ uiInfo.currentFoundPlayerServer = 0;
+ trap_Cvar_VariableStringBuffer( "ui_findPlayer", uiInfo.findPlayerName, sizeof(uiInfo.findPlayerName));
+ Q_CleanStr(uiInfo.findPlayerName);
+ // should have a string of some length
+ if (!strlen(uiInfo.findPlayerName)) {
+ uiInfo.nextFindPlayerRefresh = 0;
+ return;
+ }
+ // set resend time
+ resend = ui_serverStatusTimeOut.integer / 2 - 10;
+ if (resend < 50) {
+ resend = 50;
+ }
+ trap_Cvar_Set("cl_serverStatusResendTime", va("%d", resend));
+ // reset all server status requests
+ trap_LAN_ServerStatus( NULL, NULL, 0);
+ //
+ uiInfo.numFoundPlayerServers = 1;
+ Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
+ sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
+ "searching %d...", uiInfo.pendingServerStatus.num);
+ numFound = 0;
+ numTimeOuts++;
+ }
+ for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
+ // if this pending server is valid
+ if (uiInfo.pendingServerStatus.server[i].valid) {
+ // try to get the server status for this server
+ if (UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, &info ) ) {
+ //
+ numFound++;
+ // parse through the server status lines
+ for (j = 0; j < info.numLines; j++) {
+ // should have ping info
+ if ( !info.lines[j][2] || !info.lines[j][2][0] ) {
+ continue;
+ }
+ // clean string first
+ Q_strncpyz(name, info.lines[j][3], sizeof(name));
+ Q_CleanStr(name);
+ // if the player name is a substring
+ if (stristr(name, uiInfo.findPlayerName)) {
+ // add to found server list if we have space (always leave space for a line with the number found)
+ if (uiInfo.numFoundPlayerServers < MAX_FOUNDPLAYER_SERVERS-1) {
+ //
+ Q_strncpyz(uiInfo.foundPlayerServerAddresses[uiInfo.numFoundPlayerServers-1],
+ uiInfo.pendingServerStatus.server[i].adrstr,
+ sizeof(uiInfo.foundPlayerServerAddresses[0]));
+ Q_strncpyz(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
+ uiInfo.pendingServerStatus.server[i].name,
+ sizeof(uiInfo.foundPlayerServerNames[0]));
+ uiInfo.numFoundPlayerServers++;
+ }
+ else {
+ // can't add any more so we're done
+ uiInfo.pendingServerStatus.num = uiInfo.serverStatus.numDisplayServers;
+ }
+ }
+ }
+ Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
+ sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
+ "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
+ // retrieved the server status so reuse this spot
+ uiInfo.pendingServerStatus.server[i].valid = qfalse;
+ }
+ }
+ // if empty pending slot or timed out
+ if (!uiInfo.pendingServerStatus.server[i].valid ||
+ uiInfo.pendingServerStatus.server[i].startTime < uiInfo.uiDC.realTime - ui_serverStatusTimeOut.integer) {
+ if (uiInfo.pendingServerStatus.server[i].valid) {
+ numTimeOuts++;
+ }
+ // reset server status request for this address
+ UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, NULL );
+ // reuse pending slot
+ uiInfo.pendingServerStatus.server[i].valid = qfalse;
+ // if we didn't try to get the status of all servers in the main browser yet
+ if (uiInfo.pendingServerStatus.num < uiInfo.serverStatus.numDisplayServers) {
+ uiInfo.pendingServerStatus.server[i].startTime = uiInfo.uiDC.realTime;
+ trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num],
+ uiInfo.pendingServerStatus.server[i].adrstr, sizeof(uiInfo.pendingServerStatus.server[i].adrstr));
+ trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num], infoString, sizeof(infoString));
+ Q_strncpyz(uiInfo.pendingServerStatus.server[i].name, Info_ValueForKey(infoString, "hostname"), sizeof(uiInfo.pendingServerStatus.server[0].name));
+ uiInfo.pendingServerStatus.server[i].valid = qtrue;
+ uiInfo.pendingServerStatus.num++;
+ Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
+ sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
+ "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
+ }
+ }
+ }
+ for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
+ if (uiInfo.pendingServerStatus.server[i].valid) {
+ break;
+ }
+ }
+ // if still trying to retrieve server status info
+ if (i < MAX_SERVERSTATUSREQUESTS) {
+ uiInfo.nextFindPlayerRefresh = uiInfo.uiDC.realTime + 25;
+ }
+ else {
+ // add a line that shows the number of servers found
+ if (!uiInfo.numFoundPlayerServers) {
+ Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]), "no servers found");
+ }
+ else {
+ Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]),
+ "%d server%s found with player %s", uiInfo.numFoundPlayerServers-1,
+ uiInfo.numFoundPlayerServers == 2 ? "":"s", uiInfo.findPlayerName);
+ }
+ uiInfo.nextFindPlayerRefresh = 0;
+ // show the server status info for the selected server
+ UI_FeederSelection(FEEDER_FINDPLAYER, uiInfo.currentFoundPlayerServer);
+ }
+}
+
+/*
+==================
+UI_BuildServerStatus
+==================
+*/
+static void UI_BuildServerStatus(qboolean force) {
+
+ if (uiInfo.nextFindPlayerRefresh) {
+ return;
+ }
+ if (!force) {
+ if (!uiInfo.nextServerStatusRefresh || uiInfo.nextServerStatusRefresh > uiInfo.uiDC.realTime) {
+ return;
+ }
+ }
+ else {
+ Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
+ uiInfo.serverStatusInfo.numLines = 0;
+ // reset all server status requests
+ trap_LAN_ServerStatus( NULL, NULL, 0);
+ }
+ if (uiInfo.serverStatus.currentServer < 0 || uiInfo.serverStatus.currentServer > uiInfo.serverStatus.numDisplayServers || uiInfo.serverStatus.numDisplayServers == 0) {
+ return;
+ }
+ if (UI_GetServerStatusInfo( uiInfo.serverStatusAddress, &uiInfo.serverStatusInfo ) ) {
+ uiInfo.nextServerStatusRefresh = 0;
+ UI_GetServerStatusInfo( uiInfo.serverStatusAddress, NULL );
+ }
+ else {
+ uiInfo.nextServerStatusRefresh = uiInfo.uiDC.realTime + 500;
+ }
+}
+
+/*
+==================
+UI_FeederCount
+==================
+*/
+static int UI_FeederCount(float feederID) {
+ if (feederID == FEEDER_HEADS) {
+ return UI_HeadCountByTeam();
+ } else if (feederID == FEEDER_Q3HEADS) {
+ return uiInfo.q3HeadCount;
+ } else if (feederID == FEEDER_CINEMATICS) {
+ return uiInfo.movieCount;
+ } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
+ return UI_MapCountByGameType(feederID == FEEDER_MAPS ? qtrue : qfalse);
+ } else if (feederID == FEEDER_SERVERS) {
+ return uiInfo.serverStatus.numDisplayServers;
+ } else if (feederID == FEEDER_SERVERSTATUS) {
+ return uiInfo.serverStatusInfo.numLines;
+ } else if (feederID == FEEDER_FINDPLAYER) {
+ return uiInfo.numFoundPlayerServers;
+ } else if (feederID == FEEDER_PLAYER_LIST) {
+ if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
+ uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
+ UI_BuildPlayerList();
+ }
+ return uiInfo.playerCount;
+ } else if (feederID == FEEDER_TEAM_LIST) {
+ if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
+ uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
+ UI_BuildPlayerList();
+ }
+ return uiInfo.myTeamCount;
+ } else if (feederID == FEEDER_MODS) {
+ return uiInfo.modCount;
+ } else if (feederID == FEEDER_DEMOS) {
+ return uiInfo.demoCount;
+ }
+ return 0;
+}
+
+static const char *UI_SelectedMap(int index, int *actual) {
+ int i, c;
+ c = 0;
+ *actual = 0;
+ for (i = 0; i < uiInfo.mapCount; i++) {
+ if (uiInfo.mapList[i].active) {
+ if (c == index) {
+ *actual = i;
+ return uiInfo.mapList[i].mapName;
+ } else {
+ c++;
+ }
+ }
+ }
+ return "";
+}
+
+static const char *UI_SelectedHead(int index, int *actual) {
+ int i, c;
+ c = 0;
+ *actual = 0;
+ for (i = 0; i < uiInfo.characterCount; i++) {
+ if (uiInfo.characterList[i].active) {
+ if (c == index) {
+ *actual = i;
+ return uiInfo.characterList[i].name;
+ } else {
+ c++;
+ }
+ }
+ }
+ return "";
+}
+
+static int UI_GetIndexFromSelection(int actual) {
+ int i, c;
+ c = 0;
+ for (i = 0; i < uiInfo.mapCount; i++) {
+ if (uiInfo.mapList[i].active) {
+ if (i == actual) {
+ return c;
+ }
+ c++;
+ }
+ }
+ return 0;
+}
+
+static void UI_UpdatePendingPings( void ) {
+ trap_LAN_ResetPings(ui_netSource.integer);
+ uiInfo.serverStatus.refreshActive = qtrue;
+ uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
+
+}
+
+static const char *UI_FeederItemText(float feederID, int index, int column, qhandle_t *handle) {
+ static char info[MAX_STRING_CHARS];
+ static char hostname[1024];
+ static char clientBuff[32];
+ static int lastColumn = -1;
+ static int lastTime = 0;
+ *handle = -1;
+ if (feederID == FEEDER_HEADS) {
+ int actual;
+ return UI_SelectedHead(index, &actual);
+ } else if (feederID == FEEDER_Q3HEADS) {
+ if (index >= 0 && index < uiInfo.q3HeadCount) {
+ return uiInfo.q3HeadNames[index];
+ }
+ } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
+ int actual;
+ return UI_SelectedMap(index, &actual);
+ } else if (feederID == FEEDER_SERVERS) {
+ if (index >= 0 && index < uiInfo.serverStatus.numDisplayServers) {
+ int ping, game;
+ if (lastColumn != column || lastTime > uiInfo.uiDC.realTime + 5000) {
+ trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
+ lastColumn = column;
+ lastTime = uiInfo.uiDC.realTime;
+ }
+ ping = atoi(Info_ValueForKey(info, "ping"));
+ if (ping == -1) {
+ // if we ever see a ping that is out of date, do a server refresh
+ // UI_UpdatePendingPings();
+ }
+ switch (column) {
+ case SORT_HOST :
+ if (ping <= 0) {
+ return Info_ValueForKey(info, "addr");
+ } else {
+ if ( ui_netSource.integer == AS_LOCAL ) {
+ Com_sprintf( hostname, sizeof(hostname), "%s [%s]",
+ Info_ValueForKey(info, "hostname"),
+ netnames[atoi(Info_ValueForKey(info, "nettype"))] );
+ return hostname;
+ }
+ else {
+ Com_sprintf( hostname, sizeof(hostname), "%s", Info_ValueForKey(info, "hostname"));
+ return hostname;
+ }
+ }
+ case SORT_MAP : return Info_ValueForKey(info, "mapname");
+ case SORT_CLIENTS :
+ Com_sprintf( clientBuff, sizeof(clientBuff), "%s (%s)", trap_Cvar_VariableValue("ui_humansonly")? Info_ValueForKey(info, "g_humanplayers") : Info_ValueForKey(info, "clients"), Info_ValueForKey(info, "sv_maxclients"));
+ return clientBuff;
+ case SORT_GAME :
+ game = atoi(Info_ValueForKey(info, "gametype"));
+ if (game >= 0 && game < numTeamArenaGameTypes) {
+ return teamArenaGameTypes[game];
+ } else {
+ return "Unknown";
+ }
+ case SORT_PING :
+ if (ping <= 0) {
+ return "...";
+ } else {
+ return Info_ValueForKey(info, "ping");
+ }
+ }
+ }
+ } else if (feederID == FEEDER_SERVERSTATUS) {
+ if ( index >= 0 && index < uiInfo.serverStatusInfo.numLines ) {
+ if ( column >= 0 && column < 4 ) {
+ return uiInfo.serverStatusInfo.lines[index][column];
+ }
+ }
+ } else if (feederID == FEEDER_FINDPLAYER) {
+ if ( index >= 0 && index < uiInfo.numFoundPlayerServers ) {
+ //return uiInfo.foundPlayerServerAddresses[index];
+ return uiInfo.foundPlayerServerNames[index];
+ }
+ } else if (feederID == FEEDER_PLAYER_LIST) {
+ if (index >= 0 && index < uiInfo.playerCount) {
+ return uiInfo.playerNames[index];
+ }
+ } else if (feederID == FEEDER_TEAM_LIST) {
+ if (index >= 0 && index < uiInfo.myTeamCount) {
+ return uiInfo.teamNames[index];
+ }
+ } else if (feederID == FEEDER_MODS) {
+ if (index >= 0 && index < uiInfo.modCount) {
+ if (uiInfo.modList[index].modDescr && *uiInfo.modList[index].modDescr) {
+ return uiInfo.modList[index].modDescr;
+ } else {
+ return uiInfo.modList[index].modName;
+ }
+ }
+ } else if (feederID == FEEDER_CINEMATICS) {
+ if (index >= 0 && index < uiInfo.movieCount) {
+ return uiInfo.movieList[index];
+ }
+ } else if (feederID == FEEDER_DEMOS) {
+ if (index >= 0 && index < uiInfo.demoCount) {
+ return uiInfo.demoList[index];
+ }
+ }
+ return "";
+}
+
+
+static qhandle_t UI_FeederItemImage(float feederID, int index) {
+ if (feederID == FEEDER_HEADS) {
+ int actual;
+ UI_SelectedHead(index, &actual);
+ index = actual;
+ if (index >= 0 && index < uiInfo.characterCount) {
+ if (uiInfo.characterList[index].headImage == -1) {
+ uiInfo.characterList[index].headImage = trap_R_RegisterShaderNoMip(uiInfo.characterList[index].imageName);
+ }
+ return uiInfo.characterList[index].headImage;
+ }
+ } else if (feederID == FEEDER_Q3HEADS) {
+ if (index >= 0 && index < uiInfo.q3HeadCount) {
+ return uiInfo.q3HeadIcons[index];
+ }
+ } else if (feederID == FEEDER_ALLMAPS || feederID == FEEDER_MAPS) {
+ int actual;
+ UI_SelectedMap(index, &actual);
+ index = actual;
+ if (index >= 0 && index < uiInfo.mapCount) {
+ if (uiInfo.mapList[index].levelShot == -1) {
+ uiInfo.mapList[index].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[index].imageName);
+ }
+ return uiInfo.mapList[index].levelShot;
+ }
+ }
+ return 0;
+}
+
+static void UI_FeederSelection(float feederID, int index) {
+ static char info[MAX_STRING_CHARS];
+ if (feederID == FEEDER_HEADS) {
+ int actual;
+ UI_SelectedHead(index, &actual);
+ index = actual;
+ if (index >= 0 && index < uiInfo.characterCount) {
+ trap_Cvar_Set( "team_model", va("%s", uiInfo.characterList[index].base));
+ trap_Cvar_Set( "team_headmodel", va("*%s", uiInfo.characterList[index].name));
+ updateModel = qtrue;
+ }
+ } else if (feederID == FEEDER_Q3HEADS) {
+ if (index >= 0 && index < uiInfo.q3HeadCount) {
+ trap_Cvar_Set( "model", uiInfo.q3HeadNames[index]);
+ trap_Cvar_Set( "headmodel", uiInfo.q3HeadNames[index]);
+ updateModel = qtrue;
+ }
+ } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
+ int actual, map;
+ map = (feederID == FEEDER_ALLMAPS) ? ui_currentNetMap.integer : ui_currentMap.integer;
+ if (uiInfo.mapList[map].cinematic >= 0) {
+ trap_CIN_StopCinematic(uiInfo.mapList[map].cinematic);
+ uiInfo.mapList[map].cinematic = -1;
+ }
+ UI_SelectedMap(index, &actual);
+ trap_Cvar_Set("ui_mapIndex", va("%d", index));
+ ui_mapIndex.integer = index;
+
+ if (feederID == FEEDER_MAPS) {
+ ui_currentMap.integer = actual;
+ trap_Cvar_Set("ui_currentMap", va("%d", actual));
+ uiInfo.mapList[ui_currentMap.integer].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[ui_currentMap.integer].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
+ UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
+ trap_Cvar_Set("ui_opponentModel", uiInfo.mapList[ui_currentMap.integer].opponentName);
+ updateOpponentModel = qtrue;
+ } else {
+ ui_currentNetMap.integer = actual;
+ trap_Cvar_Set("ui_currentNetMap", va("%d", actual));
+ uiInfo.mapList[ui_currentNetMap.integer].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
+ }
+
+ } else if (feederID == FEEDER_SERVERS) {
+ const char *mapName = NULL;
+ uiInfo.serverStatus.currentServer = index;
+ trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
+ uiInfo.serverStatus.currentServerPreview = trap_R_RegisterShaderNoMip(va("levelshots/%s", Info_ValueForKey(info, "mapname")));
+ if (uiInfo.serverStatus.currentServerCinematic >= 0) {
+ trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
+ uiInfo.serverStatus.currentServerCinematic = -1;
+ }
+ mapName = Info_ValueForKey(info, "mapname");
+ if (mapName && *mapName) {
+ uiInfo.serverStatus.currentServerCinematic = trap_CIN_PlayCinematic(va("%s.roq", mapName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
+ }
+ } else if (feederID == FEEDER_SERVERSTATUS) {
+ //
+ } else if (feederID == FEEDER_FINDPLAYER) {
+ uiInfo.currentFoundPlayerServer = index;
+ //
+ if ( index < uiInfo.numFoundPlayerServers-1) {
+ // build a new server status for this server
+ Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
+ Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
+ UI_BuildServerStatus(qtrue);
+ }
+ } else if (feederID == FEEDER_PLAYER_LIST) {
+ uiInfo.playerIndex = index;
+ } else if (feederID == FEEDER_TEAM_LIST) {
+ uiInfo.teamIndex = index;
+ } else if (feederID == FEEDER_MODS) {
+ uiInfo.modIndex = index;
+ } else if (feederID == FEEDER_CINEMATICS) {
+ uiInfo.movieIndex = index;
+ if (uiInfo.previewMovie >= 0) {
+ trap_CIN_StopCinematic(uiInfo.previewMovie);
+ }
+ uiInfo.previewMovie = -1;
+ } else if (feederID == FEEDER_DEMOS) {
+ uiInfo.demoIndex = index;
+ }
+}
+
+static qboolean Team_Parse(char **p) {
+ char *token;
+ const char *tempStr;
+ int i;
+
+ token = COM_ParseExt(p, qtrue);
+
+ if (token[0] != '{') {
+ return qfalse;
+ }
+
+ while ( 1 ) {
+
+ token = COM_ParseExt(p, qtrue);
+
+ if (Q_stricmp(token, "}") == 0) {
+ return qtrue;
+ }
+
+ if ( !token || token[0] == 0 ) {
+ return qfalse;
+ }
+
+ if (token[0] == '{') {
+ // seven tokens per line, team name and icon, and 5 team member names
+ if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamName) || !String_Parse(p, &tempStr)) {
+ return qfalse;
+ }
+
+
+ uiInfo.teamList[uiInfo.teamCount].imageName = tempStr;
+ uiInfo.teamList[uiInfo.teamCount].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[uiInfo.teamCount].imageName);
+ uiInfo.teamList[uiInfo.teamCount].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[uiInfo.teamCount].imageName));
+ uiInfo.teamList[uiInfo.teamCount].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[uiInfo.teamCount].imageName));
+
+ uiInfo.teamList[uiInfo.teamCount].cinematic = -1;
+
+ for (i = 0; i < TEAM_MEMBERS; i++) {
+ uiInfo.teamList[uiInfo.teamCount].teamMembers[i] = NULL;
+ if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamMembers[i])) {
+ return qfalse;
+ }
+ }
+
+ Com_Printf("Loaded team %s with team icon %s.\n", uiInfo.teamList[uiInfo.teamCount].teamName, tempStr);
+ if (uiInfo.teamCount < MAX_TEAMS) {
+ uiInfo.teamCount++;
+ } else {
+ Com_Printf("Too many teams, last team replaced!\n");
+ }
+ token = COM_ParseExt(p, qtrue);
+ if (token[0] != '}') {
+ return qfalse;
+ }
+ }
+ }
+
+ return qfalse;
+}
+
+static qboolean Character_Parse(char **p) {
+ char *token;
+ const char *tempStr;
+
+ token = COM_ParseExt(p, qtrue);
+
+ if (token[0] != '{') {
+ return qfalse;
+ }
+
+
+ while ( 1 ) {
+ token = COM_ParseExt(p, qtrue);
+
+ if (Q_stricmp(token, "}") == 0) {
+ return qtrue;
+ }
+
+ if ( !token || token[0] == 0 ) {
+ return qfalse;
+ }
+
+ if (token[0] == '{') {
+ // two tokens per line, character name and sex
+ if (!String_Parse(p, &uiInfo.characterList[uiInfo.characterCount].name) || !String_Parse(p, &tempStr)) {
+ return qfalse;
+ }
+
+ uiInfo.characterList[uiInfo.characterCount].headImage = -1;
+ uiInfo.characterList[uiInfo.characterCount].imageName = String_Alloc(va("models/players/heads/%s/icon_default.tga", uiInfo.characterList[uiInfo.characterCount].name));
+
+ if (tempStr && (!Q_stricmp(tempStr, "female"))) {
+ uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("kyonshi"));
+ } else if (tempStr && (!Q_stricmp(tempStr, "male"))) {
+ uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("sergei"));
+ } else {
+ uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("%s",tempStr));
+ }
+
+ Com_Printf("Loaded %s character %s.\n", uiInfo.characterList[uiInfo.characterCount].base, uiInfo.characterList[uiInfo.characterCount].name);
+ if (uiInfo.characterCount < MAX_HEADS) {
+ uiInfo.characterCount++;
+ } else {
+ Com_Printf("Too many characters, last character replaced!\n");
+ }
+
+ token = COM_ParseExt(p, qtrue);
+ if (token[0] != '}') {
+ return qfalse;
+ }
+ }
+ }
+
+ return qfalse;
+}
+
+
+static qboolean Alias_Parse(char **p) {
+ char *token;
+
+ token = COM_ParseExt(p, qtrue);
+
+ if (token[0] != '{') {
+ return qfalse;
+ }
+
+ while ( 1 ) {
+ token = COM_ParseExt(p, qtrue);
+
+ if (Q_stricmp(token, "}") == 0) {
+ return qtrue;
+ }
+
+ if ( !token || token[0] == 0 ) {
+ return qfalse;
+ }
+
+ if (token[0] == '{') {
+ // three tokens per line, character name, bot alias, and preferred action a - all purpose, d - defense, o - offense
+ if (!String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].name) || !String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].ai) || !String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].action)) {
+ return qfalse;
+ }
+
+ Com_Printf("Loaded character alias %s using character ai %s.\n", uiInfo.aliasList[uiInfo.aliasCount].name, uiInfo.aliasList[uiInfo.aliasCount].ai);
+ if (uiInfo.aliasCount < MAX_ALIASES) {
+ uiInfo.aliasCount++;
+ } else {
+ Com_Printf("Too many aliases, last alias replaced!\n");
+ }
+
+ token = COM_ParseExt(p, qtrue);
+ if (token[0] != '}') {
+ return qfalse;
+ }
+ }
+ }
+
+ return qfalse;
+}
+
+
+
+// mode
+// 0 - high level parsing
+// 1 - team parsing
+// 2 - character parsing
+static void UI_ParseTeamInfo(const char *teamFile) {
+ char *token;
+ char *p;
+ char *buff = NULL;
+ //static int mode = 0; TTimo: unused
+
+ buff = GetMenuBuffer(teamFile);
+ if (!buff) {
+ return;
+ }
+
+ p = buff;
+
+ while ( 1 ) {
+ token = COM_ParseExt( &p, qtrue );
+ if( !token || token[0] == 0 || token[0] == '}') {
+ break;
+ }
+
+ if ( Q_stricmp( token, "}" ) == 0 ) {
+ break;
+ }
+
+ if (Q_stricmp(token, "teams") == 0) {
+
+ if (Team_Parse(&p)) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (Q_stricmp(token, "characters") == 0) {
+ Character_Parse(&p);
+ }
+
+ if (Q_stricmp(token, "aliases") == 0) {
+ Alias_Parse(&p);
+ }
+
+ }
+
+}
+
+
+static qboolean GameType_Parse(char **p, qboolean join) {
+ char *token;
+
+ token = COM_ParseExt(p, qtrue);
+
+ if (token[0] != '{') {
+ return qfalse;
+ }
+
+ if (join) {
+ uiInfo.numJoinGameTypes = 0;
+ } else {
+ uiInfo.numGameTypes = 0;
+ }
+
+ while ( 1 ) {
+ token = COM_ParseExt(p, qtrue);
+
+ if (Q_stricmp(token, "}") == 0) {
+ return qtrue;
+ }
+
+ if ( !token || token[0] == 0 ) {
+ return qfalse;
+ }
+
+ if (token[0] == '{') {
+ // two tokens per line, character name and sex
+ if (join) {
+ if (!String_Parse(p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gameType) || !Int_Parse(p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gtEnum)) {
+ return qfalse;
+ }
+ } else {
+ if (!String_Parse(p, &uiInfo.gameTypes[uiInfo.numGameTypes].gameType) || !Int_Parse(p, &uiInfo.gameTypes[uiInfo.numGameTypes].gtEnum)) {
+ return qfalse;
+ }
+ }
+
+ if (join) {
+ if (uiInfo.numJoinGameTypes < MAX_GAMETYPES) {
+ uiInfo.numJoinGameTypes++;
+ } else {
+ Com_Printf("Too many net game types, last one replace!\n");
+ }
+ } else {
+ if (uiInfo.numGameTypes < MAX_GAMETYPES) {
+ uiInfo.numGameTypes++;
+ } else {
+ Com_Printf("Too many game types, last one replace!\n");
+ }
+ }
+
+ token = COM_ParseExt(p, qtrue);
+ if (token[0] != '}') {
+ return qfalse;
+ }
+ }
+ }
+ return qfalse;
+}
+
+static qboolean MapList_Parse(char **p) {
+ char *token;
+
+ token = COM_ParseExt(p, qtrue);
+
+ if (token[0] != '{') {
+ return qfalse;
+ }
+
+ uiInfo.mapCount = 0;
+
+ while ( 1 ) {
+ token = COM_ParseExt(p, qtrue);
+
+ if (Q_stricmp(token, "}") == 0) {
+ return qtrue;
+ }
+
+ if ( !token || token[0] == 0 ) {
+ return qfalse;
+ }
+
+ if (token[0] == '{') {
+ if (!String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].mapName) || !String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].mapLoadName)
+ ||!Int_Parse(p, &uiInfo.mapList[uiInfo.mapCount].teamMembers) ) {
+ return qfalse;
+ }
+
+ if (!String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].opponentName)) {
+ return qfalse;
+ }
+
+ uiInfo.mapList[uiInfo.mapCount].typeBits = 0;
+
+ while (1) {
+ token = COM_ParseExt(p, qtrue);
+ if (token[0] >= '0' && token[0] <= '9') {
+ uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << (token[0] - 0x030));
+ if (!Int_Parse(p, &uiInfo.mapList[uiInfo.mapCount].timeToBeat[token[0] - 0x30])) {
+ return qfalse;
+ }
+ } else {
+ break;
+ }
+ }
+
+ //mapList[mapCount].imageName = String_Alloc(va("levelshots/%s", mapList[mapCount].mapLoadName));
+ //if (uiInfo.mapCount == 0) {
+ // only load the first cinematic, selection loads the others
+ // uiInfo.mapList[uiInfo.mapCount].cinematic = trap_CIN_PlayCinematic(va("%s.roq",uiInfo.mapList[uiInfo.mapCount].mapLoadName), qfalse, qfalse, qtrue, 0, 0, 0, 0);
+ //}
+ uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
+ uiInfo.mapList[uiInfo.mapCount].levelShot = trap_R_RegisterShaderNoMip(va("levelshots/%s_small", uiInfo.mapList[uiInfo.mapCount].mapLoadName));
+
+ if (uiInfo.mapCount < MAX_MAPS) {
+ uiInfo.mapCount++;
+ } else {
+ Com_Printf("Too many maps, last one replaced!\n");
+ }
+ }
+ }
+ return qfalse;
+}
+
+static void UI_ParseGameInfo(const char *teamFile) {
+ char *token;
+ char *p;
+ char *buff = NULL;
+ //int mode = 0; TTimo: unused
+
+ buff = GetMenuBuffer(teamFile);
+ if (!buff) {
+ return;
+ }
+
+ p = buff;
+
+ while ( 1 ) {
+ token = COM_ParseExt( &p, qtrue );
+ if( !token || token[0] == 0 || token[0] == '}') {
+ break;
+ }
+
+ if ( Q_stricmp( token, "}" ) == 0 ) {
+ break;
+ }
+
+ if (Q_stricmp(token, "gametypes") == 0) {
+
+ if (GameType_Parse(&p, qfalse)) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (Q_stricmp(token, "joingametypes") == 0) {
+
+ if (GameType_Parse(&p, qtrue)) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (Q_stricmp(token, "maps") == 0) {
+ // start a new menu
+ MapList_Parse(&p);
+ }
+
+ }
+}
+
+static void UI_Pause(qboolean b) {
+ if (b) {
+ // pause the game and set the ui keycatcher
+ trap_Cvar_Set( "cl_paused", "1" );
+ trap_Key_SetCatcher( KEYCATCH_UI );
+ } else {
+ // unpause the game and clear the ui keycatcher
+ trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
+ trap_Key_ClearStates();
+ trap_Cvar_Set( "cl_paused", "0" );
+ }
+}
+
+#ifndef MISSIONPACK // bk001206
+static int UI_OwnerDraw_Width(int ownerDraw) {
+ // bk001205 - LCC missing return value
+ return 0;
+}
+#endif
+
+static int UI_PlayCinematic(const char *name, float x, float y, float w, float h) {
+ return trap_CIN_PlayCinematic(name, x, y, w, h, (CIN_loop | CIN_silent));
+}
+
+static void UI_StopCinematic(int handle) {
+ if (handle >= 0) {
+ trap_CIN_StopCinematic(handle);
+ } else {
+ handle = abs(handle);
+ if (handle == UI_MAPCINEMATIC) {
+ if (uiInfo.mapList[ui_currentMap.integer].cinematic >= 0) {
+ trap_CIN_StopCinematic(uiInfo.mapList[ui_currentMap.integer].cinematic);
+ uiInfo.mapList[ui_currentMap.integer].cinematic = -1;
+ }
+ } else if (handle == UI_NETMAPCINEMATIC) {
+ if (uiInfo.serverStatus.currentServerCinematic >= 0) {
+ trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
+ uiInfo.serverStatus.currentServerCinematic = -1;
+ }
+ } else if (handle == UI_CLANCINEMATIC) {
+ int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
+ if (i >= 0 && i < uiInfo.teamCount) {
+ if (uiInfo.teamList[i].cinematic >= 0) {
+ trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
+ uiInfo.teamList[i].cinematic = -1;
+ }
+ }
+ }
+ }
+}
+
+static void UI_DrawCinematic(int handle, float x, float y, float w, float h) {
+ trap_CIN_SetExtents(handle, x, y, w, h);
+ trap_CIN_DrawCinematic(handle);
+}
+
+static void UI_RunCinematicFrame(int handle) {
+ trap_CIN_RunCinematic(handle);
+}
+
+
+
+/*
+=================
+PlayerModel_BuildList
+=================
+*/
+static void UI_BuildQ3Model_List( void )
+{
+ int numdirs;
+ int numfiles;
+ char dirlist[2048];
+ char filelist[2048];
+ char skinname[MAX_QPATH];
+ char scratch[256];
+ char* dirptr;
+ char* fileptr;
+ int i;
+ int j, k, dirty;
+ int dirlen;
+ int filelen;
+
+ uiInfo.q3HeadCount = 0;
+
+ // iterate directory of all player models
+ numdirs = trap_FS_GetFileList("models/players", "/", dirlist, 32768 ); // upped from 2048
+ dirptr = dirlist;
+ for (i=0; i<numdirs && uiInfo.q3HeadCount < MAX_PLAYERMODELS; i++,dirptr+=dirlen+1)
+ {
+ dirlen = strlen(dirptr);
+
+ if (dirlen && dirptr[dirlen-1]=='/') dirptr[dirlen-1]='\0';
+
+ if (!strcmp(dirptr,".") || !strcmp(dirptr,".."))
+ continue;
+
+ // iterate all skin files in directory
+ numfiles = trap_FS_GetFileList( va("models/players/%s",dirptr), "tga", filelist, 2048 );
+ fileptr = filelist;
+ for (j=0; j<numfiles && uiInfo.q3HeadCount < MAX_PLAYERMODELS;j++,fileptr+=filelen+1)
+ {
+ filelen = strlen(fileptr);
+
+ COM_StripExtension(fileptr, skinname, sizeof(skinname));
+
+ // look for icon_????
+ if (Q_stricmpn(skinname, "icon_", 5) == 0 && !(Q_stricmp(skinname,"icon_blue") == 0 || Q_stricmp(skinname,"icon_red") == 0))
+ {
+ if (Q_stricmp(skinname, "icon_default") == 0) {
+ Com_sprintf( scratch, sizeof(scratch), "%s", dirptr);
+ } else {
+ Com_sprintf( scratch, sizeof(scratch), "%s/%s",dirptr, skinname + 5);
+ }
+ dirty = 0;
+ for(k=0;k<uiInfo.q3HeadCount;k++) {
+ if (!Q_stricmp(scratch, uiInfo.q3HeadNames[uiInfo.q3HeadCount])) {
+ dirty = 1;
+ break;
+ }
+ }
+ if (!dirty) {
+ Com_sprintf( uiInfo.q3HeadNames[uiInfo.q3HeadCount], sizeof(uiInfo.q3HeadNames[uiInfo.q3HeadCount]), "%s", scratch);
+ uiInfo.q3HeadIcons[uiInfo.q3HeadCount++] = trap_R_RegisterShaderNoMip(va("models/players/%s/%s",dirptr,skinname));
+ }
+ }
+
+ }
+ }
+
+}
+
+
+
+/*
+=================
+UI_Init
+=================
+*/
+void _UI_Init( qboolean inGameLoad ) {
+ const char *menuSet;
+ int start;
+
+ //uiInfo.inGameLoad = inGameLoad;
+
+ UI_RegisterCvars();
+ UI_InitMemory();
+
+ // cache redundant calulations
+ trap_GetGlconfig( &uiInfo.uiDC.glconfig );
+
+ // for 640x480 virtualized screen
+ uiInfo.uiDC.yscale = uiInfo.uiDC.glconfig.vidHeight * (1.0/480.0);
+ uiInfo.uiDC.xscale = uiInfo.uiDC.glconfig.vidWidth * (1.0/640.0);
+ if ( uiInfo.uiDC.glconfig.vidWidth * 480 > uiInfo.uiDC.glconfig.vidHeight * 640 ) {
+ // wide screen
+ uiInfo.uiDC.bias = 0.5 * ( uiInfo.uiDC.glconfig.vidWidth - ( uiInfo.uiDC.glconfig.vidHeight * (640.0/480.0) ) );
+ }
+ else {
+ // no wide screen
+ uiInfo.uiDC.bias = 0;
+ }
+
+
+ //UI_Load();
+ uiInfo.uiDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
+ uiInfo.uiDC.setColor = &UI_SetColor;
+ uiInfo.uiDC.drawHandlePic = &UI_DrawHandlePic;
+ uiInfo.uiDC.drawStretchPic = &trap_R_DrawStretchPic;
+ uiInfo.uiDC.drawText = &Text_Paint;
+ uiInfo.uiDC.textWidth = &Text_Width;
+ uiInfo.uiDC.textHeight = &Text_Height;
+ uiInfo.uiDC.registerModel = &trap_R_RegisterModel;
+ uiInfo.uiDC.modelBounds = &trap_R_ModelBounds;
+ uiInfo.uiDC.fillRect = &UI_FillRect;
+ uiInfo.uiDC.drawRect = &_UI_DrawRect;
+ uiInfo.uiDC.drawSides = &_UI_DrawSides;
+ uiInfo.uiDC.drawTopBottom = &_UI_DrawTopBottom;
+ uiInfo.uiDC.clearScene = &trap_R_ClearScene;
+ uiInfo.uiDC.drawSides = &_UI_DrawSides;
+ uiInfo.uiDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
+ uiInfo.uiDC.renderScene = &trap_R_RenderScene;
+ uiInfo.uiDC.registerFont = &trap_R_RegisterFont;
+ uiInfo.uiDC.ownerDrawItem = &UI_OwnerDraw;
+ uiInfo.uiDC.getValue = &UI_GetValue;
+ uiInfo.uiDC.ownerDrawVisible = &UI_OwnerDrawVisible;
+ uiInfo.uiDC.runScript = &UI_RunMenuScript;
+ uiInfo.uiDC.getTeamColor = &UI_GetTeamColor;
+ uiInfo.uiDC.setCVar = trap_Cvar_Set;
+ uiInfo.uiDC.getCVarString = trap_Cvar_VariableStringBuffer;
+ uiInfo.uiDC.getCVarValue = trap_Cvar_VariableValue;
+ uiInfo.uiDC.drawTextWithCursor = &Text_PaintWithCursor;
+ uiInfo.uiDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
+ uiInfo.uiDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
+ uiInfo.uiDC.startLocalSound = &trap_S_StartLocalSound;
+ uiInfo.uiDC.ownerDrawHandleKey = &UI_OwnerDrawHandleKey;
+ uiInfo.uiDC.feederCount = &UI_FeederCount;
+ uiInfo.uiDC.feederItemImage = &UI_FeederItemImage;
+ uiInfo.uiDC.feederItemText = &UI_FeederItemText;
+ uiInfo.uiDC.feederSelection = &UI_FeederSelection;
+ uiInfo.uiDC.setBinding = &trap_Key_SetBinding;
+ uiInfo.uiDC.getBindingBuf = &trap_Key_GetBindingBuf;
+ uiInfo.uiDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
+ uiInfo.uiDC.executeText = &trap_Cmd_ExecuteText;
+ uiInfo.uiDC.Error = &Com_Error;
+ uiInfo.uiDC.Print = &Com_Printf;
+ uiInfo.uiDC.Pause = &UI_Pause;
+ uiInfo.uiDC.ownerDrawWidth = &UI_OwnerDrawWidth;
+ uiInfo.uiDC.registerSound = &trap_S_RegisterSound;
+ uiInfo.uiDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
+ uiInfo.uiDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
+ uiInfo.uiDC.playCinematic = &UI_PlayCinematic;
+ uiInfo.uiDC.stopCinematic = &UI_StopCinematic;
+ uiInfo.uiDC.drawCinematic = &UI_DrawCinematic;
+ uiInfo.uiDC.runCinematicFrame = &UI_RunCinematicFrame;
+
+ Init_Display(&uiInfo.uiDC);
+
+ String_Init();
+
+ uiInfo.uiDC.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
+ uiInfo.uiDC.whiteShader = trap_R_RegisterShaderNoMip( "white" );
+
+ AssetCache();
+
+ start = trap_Milliseconds();
+
+ uiInfo.teamCount = 0;
+ uiInfo.characterCount = 0;
+ uiInfo.aliasCount = 0;
+
+#ifdef PRE_RELEASE_TADEMO
+ UI_ParseTeamInfo("demoteaminfo.txt");
+ UI_ParseGameInfo("demogameinfo.txt");
+#else
+ UI_ParseTeamInfo("teaminfo.txt");
+ UI_LoadTeams();
+ UI_ParseGameInfo("gameinfo.txt");
+#endif
+
+ menuSet = UI_Cvar_VariableString("ui_menuFiles");
+ if (menuSet == NULL || menuSet[0] == '\0') {
+ menuSet = "ui/menus.txt";
+ }
+
+#if 0
+ if (uiInfo.inGameLoad) {
+ UI_LoadMenus("ui/ingame.txt", qtrue);
+ } else { // bk010222: left this: UI_LoadMenus(menuSet, qtrue);
+ }
+#else
+ UI_LoadMenus(menuSet, qtrue);
+ UI_LoadMenus("ui/ingame.txt", qfalse);
+#endif
+
+ Menus_CloseAll();
+
+ trap_LAN_LoadCachedServers();
+ UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
+
+ UI_BuildQ3Model_List();
+ UI_LoadBots();
+
+ // sets defaults for ui temp cvars
+ uiInfo.effectsColor = gamecodetoui[(int)trap_Cvar_VariableValue("color1")-1];
+ uiInfo.currentCrosshair = (int)trap_Cvar_VariableValue("cg_drawCrosshair");
+ trap_Cvar_Set("ui_mousePitch", (trap_Cvar_VariableValue("m_pitch") >= 0) ? "0" : "1");
+
+ uiInfo.serverStatus.currentServerCinematic = -1;
+ uiInfo.previewMovie = -1;
+
+ if (trap_Cvar_VariableValue("ui_TeamArenaFirstRun") == 0) {
+ trap_Cvar_Set("s_volume", "0.8");
+ trap_Cvar_Set("s_musicvolume", "0.5");
+ trap_Cvar_Set("ui_TeamArenaFirstRun", "1");
+ }
+
+ trap_Cvar_Register(NULL, "debug_protocol", "", 0 );
+
+ trap_Cvar_Set("ui_actualNetGameType", va("%d", ui_netGameType.integer));
+}
+
+
+/*
+=================
+UI_KeyEvent
+=================
+*/
+void _UI_KeyEvent( int key, qboolean down ) {
+
+ if (Menu_Count() > 0) {
+ menuDef_t *menu = Menu_GetFocused();
+ if (menu) {
+ if (key == K_ESCAPE && down && !Menus_AnyFullScreenVisible()) {
+ Menus_CloseAll();
+ } else {
+ Menu_HandleKey(menu, key, down );
+ }
+ } else {
+ trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
+ trap_Key_ClearStates();
+ trap_Cvar_Set( "cl_paused", "0" );
+ }
+ }
+
+ //if ((s > 0) && (s != menu_null_sound)) {
+ // trap_S_StartLocalSound( s, CHAN_LOCAL_SOUND );
+ //}
+}
+
+/*
+=================
+UI_MouseEvent
+=================
+*/
+void _UI_MouseEvent( int dx, int dy )
+{
+ // update mouse screen position
+ uiInfo.uiDC.cursorx += dx;
+ if (uiInfo.uiDC.cursorx < 0)
+ uiInfo.uiDC.cursorx = 0;
+ else if (uiInfo.uiDC.cursorx > SCREEN_WIDTH)
+ uiInfo.uiDC.cursorx = SCREEN_WIDTH;
+
+ uiInfo.uiDC.cursory += dy;
+ if (uiInfo.uiDC.cursory < 0)
+ uiInfo.uiDC.cursory = 0;
+ else if (uiInfo.uiDC.cursory > SCREEN_HEIGHT)
+ uiInfo.uiDC.cursory = SCREEN_HEIGHT;
+
+ if (Menu_Count() > 0) {
+ //menuDef_t *menu = Menu_GetFocused();
+ //Menu_HandleMouseMove(menu, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
+ Display_MouseMove(NULL, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
+ }
+
+}
+
+void UI_LoadNonIngame( void ) {
+ const char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
+ if (menuSet == NULL || menuSet[0] == '\0') {
+ menuSet = "ui/menus.txt";
+ }
+ UI_LoadMenus(menuSet, qfalse);
+ uiInfo.inGameLoad = qfalse;
+}
+
+void _UI_SetActiveMenu( uiMenuCommand_t menu ) {
+ char buf[256];
+
+ // this should be the ONLY way the menu system is brought up
+ // enusure minumum menu data is cached
+ if (Menu_Count() > 0) {
+ vec3_t v;
+ v[0] = v[1] = v[2] = 0;
+ switch ( menu ) {
+ case UIMENU_NONE:
+ trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
+ trap_Key_ClearStates();
+ trap_Cvar_Set( "cl_paused", "0" );
+ Menus_CloseAll();
+
+ return;
+ case UIMENU_MAIN:
+ trap_Cvar_Set( "sv_killserver", "1" );
+ trap_Key_SetCatcher( KEYCATCH_UI );
+ //trap_S_StartLocalSound( trap_S_RegisterSound("sound/misc/menu_background.wav", qfalse) , CHAN_LOCAL_SOUND );
+ //trap_S_StartBackgroundTrack("sound/misc/menu_background.wav", NULL);
+ if (uiInfo.inGameLoad) {
+ UI_LoadNonIngame();
+ }
+ Menus_CloseAll();
+ Menus_ActivateByName("main");
+ trap_Cvar_VariableStringBuffer("com_errorMessage", buf, sizeof(buf));
+ if (strlen(buf)) {
+ if (!ui_singlePlayerActive.integer) {
+ Menus_ActivateByName("error_popmenu");
+ } else {
+ trap_Cvar_Set("com_errorMessage", "");
+ }
+ }
+ return;
+ case UIMENU_TEAM:
+ trap_Key_SetCatcher( KEYCATCH_UI );
+ Menus_ActivateByName("team");
+ return;
+ case UIMENU_NEED_CD:
+ // no cd check in TA
+ //trap_Key_SetCatcher( KEYCATCH_UI );
+ //Menus_ActivateByName("needcd");
+ //UI_ConfirmMenu( "Insert the CD", NULL, NeedCDAction );
+ return;
+ case UIMENU_BAD_CD_KEY:
+ // no cd check in TA
+ //trap_Key_SetCatcher( KEYCATCH_UI );
+ //Menus_ActivateByName("badcd");
+ //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
+ return;
+ case UIMENU_POSTGAME:
+ trap_Cvar_Set( "sv_killserver", "1" );
+ trap_Key_SetCatcher( KEYCATCH_UI );
+ if (uiInfo.inGameLoad) {
+ UI_LoadNonIngame();
+ }
+ Menus_CloseAll();
+ Menus_ActivateByName("endofgame");
+ //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
+ return;
+ case UIMENU_INGAME:
+ trap_Cvar_Set( "cl_paused", "1" );
+ trap_Key_SetCatcher( KEYCATCH_UI );
+ UI_BuildPlayerList();
+ Menus_CloseAll();
+ Menus_ActivateByName("ingame");
+ return;
+ }
+ }
+}
+
+qboolean _UI_IsFullscreen( void ) {
+ return Menus_AnyFullScreenVisible();
+}
+
+
+
+static connstate_t lastConnState;
+static char lastLoadingText[MAX_INFO_VALUE];
+
+static void UI_ReadableSize ( char *buf, int bufsize, int value )
+{
+ if (value > 1024*1024*1024 ) { // gigs
+ Com_sprintf( buf, bufsize, "%d", value / (1024*1024*1024) );
+ Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d GB",
+ (value % (1024*1024*1024))*100 / (1024*1024*1024) );
+ } else if (value > 1024*1024 ) { // megs
+ Com_sprintf( buf, bufsize, "%d", value / (1024*1024) );
+ Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d MB",
+ (value % (1024*1024))*100 / (1024*1024) );
+ } else if (value > 1024 ) { // kilos
+ Com_sprintf( buf, bufsize, "%d KB", value / 1024 );
+ } else { // bytes
+ Com_sprintf( buf, bufsize, "%d bytes", value );
+ }
+}
+
+// Assumes time is in msec
+static void UI_PrintTime ( char *buf, int bufsize, int time ) {
+ time /= 1000; // change to seconds
+
+ if (time > 3600) { // in the hours range
+ Com_sprintf( buf, bufsize, "%d hr %d min", time / 3600, (time % 3600) / 60 );
+ } else if (time > 60) { // mins
+ Com_sprintf( buf, bufsize, "%d min %d sec", time / 60, time % 60 );
+ } else { // secs
+ Com_sprintf( buf, bufsize, "%d sec", time );
+ }
+}
+
+void Text_PaintCenter(float x, float y, float scale, vec4_t color, const char *text, float adjust) {
+ int len = Text_Width(text, scale, 0);
+ Text_Paint(x - len / 2, y, scale, color, text, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
+}
+
+void Text_PaintCenter_AutoWrapped(float x, float y, float xmax, float ystep, float scale, vec4_t color, const char *str, float adjust) {
+ int width;
+ char *s1,*s2,*s3;
+ char c_bcp;
+ char buf[1024];
+
+ if (!str || str[0]=='\0')
+ return;
+
+ Q_strncpyz(buf, str, sizeof(buf));
+ s1 = s2 = s3 = buf;
+
+ while (1) {
+ do {
+ s3++;
+ } while (*s3!=' ' && *s3!='\0');
+ c_bcp = *s3;
+ *s3 = '\0';
+ width = Text_Width(s1, scale, 0);
+ *s3 = c_bcp;
+ if (width > xmax) {
+ if (s1==s2)
+ {
+ // fuck, don't have a clean cut, we'll overflow
+ s2 = s3;
+ }
+ *s2 = '\0';
+ Text_PaintCenter(x, y, scale, color, s1, adjust);
+ y += ystep;
+ if (c_bcp == '\0')
+ {
+ // that was the last word
+ // we could start a new loop, but that wouldn't be much use
+ // even if the word is too long, we would overflow it (see above)
+ // so just print it now if needed
+ s2++;
+ if (*s2 != '\0') // if we are printing an overflowing line we have s2 == s3
+ Text_PaintCenter(x, y, scale, color, s2, adjust);
+ break;
+ }
+ s2++;
+ s1 = s2;
+ s3 = s2;
+ }
+ else
+ {
+ s2 = s3;
+ if (c_bcp == '\0') // we reached the end
+ {
+ Text_PaintCenter(x, y, scale, color, s1, adjust);
+ break;
+ }
+ }
+ }
+}
+
+static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, float yStart, float scale ) {
+ static char dlText[] = "Downloading:";
+ static char etaText[] = "Estimated time left:";
+ static char xferText[] = "Transfer rate:";
+
+ int downloadSize, downloadCount, downloadTime;
+ char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64];
+ int xferRate;
+ int leftWidth;
+ const char *s;
+
+ downloadSize = trap_Cvar_VariableValue( "cl_downloadSize" );
+ downloadCount = trap_Cvar_VariableValue( "cl_downloadCount" );
+ downloadTime = trap_Cvar_VariableValue( "cl_downloadTime" );
+
+ leftWidth = 320;
+
+ UI_SetColor(colorWhite);
+ Text_PaintCenter(centerPoint, yStart + 112, scale, colorWhite, dlText, 0);
+ Text_PaintCenter(centerPoint, yStart + 192, scale, colorWhite, etaText, 0);
+ Text_PaintCenter(centerPoint, yStart + 248, scale, colorWhite, xferText, 0);
+
+ if (downloadSize > 0) {
+ s = va( "%s (%d%%)", downloadName,
+ (int)( (float)downloadCount * 100.0f / downloadSize ) );
+ } else {
+ s = downloadName;
+ }
+
+ Text_PaintCenter(centerPoint, yStart+136, scale, colorWhite, s, 0);
+
+ UI_ReadableSize( dlSizeBuf, sizeof dlSizeBuf, downloadCount );
+ UI_ReadableSize( totalSizeBuf, sizeof totalSizeBuf, downloadSize );
+
+ if (downloadCount < 4096 || !downloadTime) {
+ Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
+ Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
+ } else {
+ if ((uiInfo.uiDC.realTime - downloadTime) / 1000) {
+ xferRate = downloadCount / ((uiInfo.uiDC.realTime - downloadTime) / 1000);
+ } else {
+ xferRate = 0;
+ }
+ UI_ReadableSize( xferRateBuf, sizeof xferRateBuf, xferRate );
+
+ // Extrapolate estimated completion time
+ if (downloadSize && xferRate) {
+ int n = downloadSize / xferRate; // estimated time for entire d/l in secs
+
+ // We do it in K (/1024) because we'd overflow around 4MB
+ UI_PrintTime ( dlTimeBuf, sizeof dlTimeBuf,
+ (n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000);
+
+ Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, dlTimeBuf, 0);
+ Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
+ } else {
+ Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
+ if (downloadSize) {
+ Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
+ } else {
+ Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s copied)", dlSizeBuf), 0);
+ }
+ }
+
+ if (xferRate) {
+ Text_PaintCenter(leftWidth, yStart+272, scale, colorWhite, va("%s/Sec", xferRateBuf), 0);
+ }
+ }
+}
+
+/*
+========================
+UI_DrawConnectScreen
+
+This will also be overlaid on the cgame info screen during loading
+to prevent it from blinking away too rapidly on local or lan games.
+========================
+*/
+void UI_DrawConnectScreen( qboolean overlay ) {
+ char *s;
+ uiClientState_t cstate;
+ char info[MAX_INFO_VALUE];
+ char text[256];
+ float centerPoint, yStart, scale;
+
+ menuDef_t *menu = Menus_FindByName("Connect");
+
+
+ if ( !overlay && menu ) {
+ Menu_Paint(menu, qtrue);
+ }
+
+ if (!overlay) {
+ centerPoint = 320;
+ yStart = 130;
+ scale = 0.5f;
+ } else {
+ centerPoint = 320;
+ yStart = 32;
+ scale = 0.6f;
+ return;
+ }
+
+ // see what information we should display
+ trap_GetClientState( &cstate );
+
+ info[0] = '\0';
+ if( trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ) ) {
+ Text_PaintCenter(centerPoint, yStart, scale, colorWhite, va( "Loading %s", Info_ValueForKey( info, "mapname" )), 0);
+ }
+
+ if (!Q_stricmp(cstate.servername,"localhost")) {
+ Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite, va("Starting up..."), ITEM_TEXTSTYLE_SHADOWEDMORE);
+ } else {
+ strcpy(text, va("Connecting to %s", cstate.servername));
+ Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite,text , ITEM_TEXTSTYLE_SHADOWEDMORE);
+ }
+
+ // display global MOTD at bottom
+ Text_PaintCenter(centerPoint, 600, scale, colorWhite, Info_ValueForKey( cstate.updateInfoString, "motd" ), 0);
+ // print any server info (server full, bad version, etc)
+ if ( cstate.connState < CA_CONNECTED ) {
+ Text_PaintCenter_AutoWrapped(centerPoint, yStart + 176, 630, 20, scale, colorWhite, cstate.messageString, 0);
+ }
+
+ if ( lastConnState > cstate.connState ) {
+ lastLoadingText[0] = '\0';
+ }
+ lastConnState = cstate.connState;
+
+ switch ( cstate.connState ) {
+ case CA_CONNECTING:
+ s = va("Awaiting connection...%i", cstate.connectPacketCount);
+ break;
+ case CA_CHALLENGING:
+ s = va("Awaiting challenge...%i", cstate.connectPacketCount);
+ break;
+ case CA_CONNECTED: {
+ char downloadName[MAX_INFO_VALUE];
+
+ trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof(downloadName) );
+ if (*downloadName) {
+ UI_DisplayDownloadInfo( downloadName, centerPoint, yStart, scale );
+ return;
+ }
+ }
+ s = "Awaiting gamestate...";
+ break;
+ case CA_LOADING:
+ return;
+ case CA_PRIMED:
+ return;
+ default:
+ return;
+ }
+
+
+ if (Q_stricmp(cstate.servername,"localhost")) {
+ Text_PaintCenter(centerPoint, yStart + 80, scale, colorWhite, s, 0);
+ }
+
+ // password required / connection rejected information goes here
+}
+
+
+/*
+================
+cvars
+================
+*/
+
+typedef struct {
+ vmCvar_t *vmCvar;
+ char *cvarName;
+ char *defaultString;
+ int cvarFlags;
+} cvarTable_t;
+
+vmCvar_t ui_ffa_fraglimit;
+vmCvar_t ui_ffa_timelimit;
+
+vmCvar_t ui_tourney_fraglimit;
+vmCvar_t ui_tourney_timelimit;
+
+vmCvar_t ui_team_fraglimit;
+vmCvar_t ui_team_timelimit;
+vmCvar_t ui_team_friendly;
+
+vmCvar_t ui_ctf_capturelimit;
+vmCvar_t ui_ctf_timelimit;
+vmCvar_t ui_ctf_friendly;
+
+vmCvar_t ui_arenasFile;
+vmCvar_t ui_botsFile;
+vmCvar_t ui_spScores1;
+vmCvar_t ui_spScores2;
+vmCvar_t ui_spScores3;
+vmCvar_t ui_spScores4;
+vmCvar_t ui_spScores5;
+vmCvar_t ui_spAwards;
+vmCvar_t ui_spVideos;
+vmCvar_t ui_spSkill;
+
+vmCvar_t ui_spSelection;
+
+vmCvar_t ui_browserMaster;
+vmCvar_t ui_browserGameType;
+vmCvar_t ui_browserSortKey;
+vmCvar_t ui_browserShowFull;
+vmCvar_t ui_browserShowEmpty;
+
+vmCvar_t ui_brassTime;
+vmCvar_t ui_drawCrosshair;
+vmCvar_t ui_drawCrosshairNames;
+vmCvar_t ui_marks;
+
+vmCvar_t ui_server1;
+vmCvar_t ui_server2;
+vmCvar_t ui_server3;
+vmCvar_t ui_server4;
+vmCvar_t ui_server5;
+vmCvar_t ui_server6;
+vmCvar_t ui_server7;
+vmCvar_t ui_server8;
+vmCvar_t ui_server9;
+vmCvar_t ui_server10;
+vmCvar_t ui_server11;
+vmCvar_t ui_server12;
+vmCvar_t ui_server13;
+vmCvar_t ui_server14;
+vmCvar_t ui_server15;
+vmCvar_t ui_server16;
+
+vmCvar_t ui_cdkeychecked;
+
+vmCvar_t ui_redteam;
+vmCvar_t ui_redteam1;
+vmCvar_t ui_redteam2;
+vmCvar_t ui_redteam3;
+vmCvar_t ui_redteam4;
+vmCvar_t ui_redteam5;
+vmCvar_t ui_blueteam;
+vmCvar_t ui_blueteam1;
+vmCvar_t ui_blueteam2;
+vmCvar_t ui_blueteam3;
+vmCvar_t ui_blueteam4;
+vmCvar_t ui_blueteam5;
+vmCvar_t ui_teamName;
+vmCvar_t ui_dedicated;
+vmCvar_t ui_gameType;
+vmCvar_t ui_netGameType;
+vmCvar_t ui_actualNetGameType;
+vmCvar_t ui_joinGameType;
+vmCvar_t ui_netSource;
+vmCvar_t ui_serverFilterType;
+vmCvar_t ui_opponentName;
+vmCvar_t ui_menuFiles;
+vmCvar_t ui_currentTier;
+vmCvar_t ui_currentMap;
+vmCvar_t ui_currentNetMap;
+vmCvar_t ui_mapIndex;
+vmCvar_t ui_currentOpponent;
+vmCvar_t ui_selectedPlayer;
+vmCvar_t ui_selectedPlayerName;
+vmCvar_t ui_lastServerRefresh_0;
+vmCvar_t ui_lastServerRefresh_1;
+vmCvar_t ui_lastServerRefresh_2;
+vmCvar_t ui_lastServerRefresh_3;
+vmCvar_t ui_singlePlayerActive;
+vmCvar_t ui_scoreAccuracy;
+vmCvar_t ui_scoreImpressives;
+vmCvar_t ui_scoreExcellents;
+vmCvar_t ui_scoreCaptures;
+vmCvar_t ui_scoreDefends;
+vmCvar_t ui_scoreAssists;
+vmCvar_t ui_scoreGauntlets;
+vmCvar_t ui_scoreScore;
+vmCvar_t ui_scorePerfect;
+vmCvar_t ui_scoreTeam;
+vmCvar_t ui_scoreBase;
+vmCvar_t ui_scoreTimeBonus;
+vmCvar_t ui_scoreSkillBonus;
+vmCvar_t ui_scoreShutoutBonus;
+vmCvar_t ui_scoreTime;
+vmCvar_t ui_captureLimit;
+vmCvar_t ui_fragLimit;
+vmCvar_t ui_smallFont;
+vmCvar_t ui_bigFont;
+vmCvar_t ui_findPlayer;
+vmCvar_t ui_Q3Model;
+vmCvar_t ui_hudFiles;
+vmCvar_t ui_recordSPDemo;
+vmCvar_t ui_realCaptureLimit;
+vmCvar_t ui_realWarmUp;
+vmCvar_t ui_serverStatusTimeOut;
+
+vmCvar_t ui_humansonly;
+
+
+// bk001129 - made static to avoid aliasing
+static cvarTable_t cvarTable[] = {
+ { &ui_ffa_fraglimit, "ui_ffa_fraglimit", "20", CVAR_ARCHIVE },
+ { &ui_ffa_timelimit, "ui_ffa_timelimit", "0", CVAR_ARCHIVE },
+
+ { &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE },
+ { &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE },
+
+ { &ui_team_fraglimit, "ui_team_fraglimit", "0", CVAR_ARCHIVE },
+ { &ui_team_timelimit, "ui_team_timelimit", "20", CVAR_ARCHIVE },
+ { &ui_team_friendly, "ui_team_friendly", "1", CVAR_ARCHIVE },
+
+ { &ui_ctf_capturelimit, "ui_ctf_capturelimit", "8", CVAR_ARCHIVE },
+ { &ui_ctf_timelimit, "ui_ctf_timelimit", "30", CVAR_ARCHIVE },
+ { &ui_ctf_friendly, "ui_ctf_friendly", "0", CVAR_ARCHIVE },
+
+ { &ui_arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM },
+ { &ui_botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM },
+ { &ui_spScores1, "g_spScores1", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spScores2, "g_spScores2", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spScores3, "g_spScores3", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spScores4, "g_spScores4", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spScores5, "g_spScores5", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spAwards, "g_spAwards", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spVideos, "g_spVideos", "", CVAR_ARCHIVE | CVAR_ROM },
+ { &ui_spSkill, "g_spSkill", "2", CVAR_ARCHIVE },
+
+ { &ui_spSelection, "ui_spSelection", "", CVAR_ROM },
+
+ { &ui_browserMaster, "ui_browserMaster", "0", CVAR_ARCHIVE },
+ { &ui_browserGameType, "ui_browserGameType", "0", CVAR_ARCHIVE },
+ { &ui_browserSortKey, "ui_browserSortKey", "4", CVAR_ARCHIVE },
+ { &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE },
+ { &ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE },
+
+ { &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
+ { &ui_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
+ { &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
+ { &ui_marks, "cg_marks", "1", CVAR_ARCHIVE },
+
+ { &ui_server1, "server1", "", CVAR_ARCHIVE },
+ { &ui_server2, "server2", "", CVAR_ARCHIVE },
+ { &ui_server3, "server3", "", CVAR_ARCHIVE },
+ { &ui_server4, "server4", "", CVAR_ARCHIVE },
+ { &ui_server5, "server5", "", CVAR_ARCHIVE },
+ { &ui_server6, "server6", "", CVAR_ARCHIVE },
+ { &ui_server7, "server7", "", CVAR_ARCHIVE },
+ { &ui_server8, "server8", "", CVAR_ARCHIVE },
+ { &ui_server9, "server9", "", CVAR_ARCHIVE },
+ { &ui_server10, "server10", "", CVAR_ARCHIVE },
+ { &ui_server11, "server11", "", CVAR_ARCHIVE },
+ { &ui_server12, "server12", "", CVAR_ARCHIVE },
+ { &ui_server13, "server13", "", CVAR_ARCHIVE },
+ { &ui_server14, "server14", "", CVAR_ARCHIVE },
+ { &ui_server15, "server15", "", CVAR_ARCHIVE },
+ { &ui_server16, "server16", "", CVAR_ARCHIVE },
+ { &ui_cdkeychecked, "ui_cdkeychecked", "0", CVAR_ROM },
+ { &ui_new, "ui_new", "0", CVAR_TEMP },
+ { &ui_debug, "ui_debug", "0", CVAR_TEMP },
+ { &ui_initialized, "ui_initialized", "0", CVAR_TEMP },
+ { &ui_teamName, "ui_teamName", "Pagans", CVAR_ARCHIVE },
+ { &ui_opponentName, "ui_opponentName", "Stroggs", CVAR_ARCHIVE },
+ { &ui_redteam, "ui_redteam", "Pagans", CVAR_ARCHIVE },
+ { &ui_blueteam, "ui_blueteam", "Stroggs", CVAR_ARCHIVE },
+ { &ui_dedicated, "ui_dedicated", "0", CVAR_ARCHIVE },
+ { &ui_gameType, "ui_gametype", "3", CVAR_ARCHIVE },
+ { &ui_joinGameType, "ui_joinGametype", "0", CVAR_ARCHIVE },
+ { &ui_netGameType, "ui_netGametype", "3", CVAR_ARCHIVE },
+ { &ui_actualNetGameType, "ui_actualNetGametype", "3", CVAR_ARCHIVE },
+ { &ui_redteam1, "ui_redteam1", "0", CVAR_ARCHIVE },
+ { &ui_redteam2, "ui_redteam2", "0", CVAR_ARCHIVE },
+ { &ui_redteam3, "ui_redteam3", "0", CVAR_ARCHIVE },
+ { &ui_redteam4, "ui_redteam4", "0", CVAR_ARCHIVE },
+ { &ui_redteam5, "ui_redteam5", "0", CVAR_ARCHIVE },
+ { &ui_blueteam1, "ui_blueteam1", "0", CVAR_ARCHIVE },
+ { &ui_blueteam2, "ui_blueteam2", "0", CVAR_ARCHIVE },
+ { &ui_blueteam3, "ui_blueteam3", "0", CVAR_ARCHIVE },
+ { &ui_blueteam4, "ui_blueteam4", "0", CVAR_ARCHIVE },
+ { &ui_blueteam5, "ui_blueteam5", "0", CVAR_ARCHIVE },
+ { &ui_netSource, "ui_netSource", "0", CVAR_ARCHIVE },
+ { &ui_menuFiles, "ui_menuFiles", "ui/menus.txt", CVAR_ARCHIVE },
+ { &ui_currentTier, "ui_currentTier", "0", CVAR_ARCHIVE },
+ { &ui_currentMap, "ui_currentMap", "0", CVAR_ARCHIVE },
+ { &ui_currentNetMap, "ui_currentNetMap", "0", CVAR_ARCHIVE },
+ { &ui_mapIndex, "ui_mapIndex", "0", CVAR_ARCHIVE },
+ { &ui_currentOpponent, "ui_currentOpponent", "0", CVAR_ARCHIVE },
+ { &ui_selectedPlayer, "cg_selectedPlayer", "0", CVAR_ARCHIVE},
+ { &ui_selectedPlayerName, "cg_selectedPlayerName", "", CVAR_ARCHIVE},
+ { &ui_lastServerRefresh_0, "ui_lastServerRefresh_0", "", CVAR_ARCHIVE},
+ { &ui_lastServerRefresh_1, "ui_lastServerRefresh_1", "", CVAR_ARCHIVE},
+ { &ui_lastServerRefresh_2, "ui_lastServerRefresh_2", "", CVAR_ARCHIVE},
+ { &ui_lastServerRefresh_3, "ui_lastServerRefresh_3", "", CVAR_ARCHIVE},
+ { &ui_singlePlayerActive, "ui_singlePlayerActive", "0", 0},
+ { &ui_scoreAccuracy, "ui_scoreAccuracy", "0", CVAR_ARCHIVE},
+ { &ui_scoreImpressives, "ui_scoreImpressives", "0", CVAR_ARCHIVE},
+ { &ui_scoreExcellents, "ui_scoreExcellents", "0", CVAR_ARCHIVE},
+ { &ui_scoreCaptures, "ui_scoreCaptures", "0", CVAR_ARCHIVE},
+ { &ui_scoreDefends, "ui_scoreDefends", "0", CVAR_ARCHIVE},
+ { &ui_scoreAssists, "ui_scoreAssists", "0", CVAR_ARCHIVE},
+ { &ui_scoreGauntlets, "ui_scoreGauntlets", "0",CVAR_ARCHIVE},
+ { &ui_scoreScore, "ui_scoreScore", "0", CVAR_ARCHIVE},
+ { &ui_scorePerfect, "ui_scorePerfect", "0", CVAR_ARCHIVE},
+ { &ui_scoreTeam, "ui_scoreTeam", "0 to 0", CVAR_ARCHIVE},
+ { &ui_scoreBase, "ui_scoreBase", "0", CVAR_ARCHIVE},
+ { &ui_scoreTime, "ui_scoreTime", "00:00", CVAR_ARCHIVE},
+ { &ui_scoreTimeBonus, "ui_scoreTimeBonus", "0", CVAR_ARCHIVE},
+ { &ui_scoreSkillBonus, "ui_scoreSkillBonus", "0", CVAR_ARCHIVE},
+ { &ui_scoreShutoutBonus, "ui_scoreShutoutBonus", "0", CVAR_ARCHIVE},
+ { &ui_fragLimit, "ui_fragLimit", "10", 0},
+ { &ui_captureLimit, "ui_captureLimit", "5", 0},
+ { &ui_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE},
+ { &ui_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE},
+ { &ui_findPlayer, "ui_findPlayer", "Sarge", CVAR_ARCHIVE},
+ { &ui_Q3Model, "ui_q3model", "0", CVAR_ARCHIVE},
+ { &ui_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
+ { &ui_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE},
+ { &ui_teamArenaFirstRun, "ui_teamArenaFirstRun", "0", CVAR_ARCHIVE},
+ { &ui_realWarmUp, "g_warmup", "20", CVAR_ARCHIVE},
+ { &ui_realCaptureLimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART},
+ { &ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE},
+ { &ui_humansonly, "ui_humansonly", "0", CVAR_ARCHIVE},
+};
+
+// bk001129 - made static to avoid aliasing
+static int cvarTableSize = sizeof(cvarTable) / sizeof(cvarTable[0]);
+
+
+/*
+=================
+UI_RegisterCvars
+=================
+*/
+void UI_RegisterCvars( void ) {
+ int i;
+ cvarTable_t *cv;
+
+ for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
+ trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );
+ }
+}
+
+/*
+=================
+UI_UpdateCvars
+=================
+*/
+void UI_UpdateCvars( void ) {
+ int i;
+ cvarTable_t *cv;
+
+ for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
+ trap_Cvar_Update( cv->vmCvar );
+ }
+}
+
+
+/*
+=================
+ArenaServers_StopRefresh
+=================
+*/
+static void UI_StopServerRefresh( void )
+{
+ int count;
+
+ if (!uiInfo.serverStatus.refreshActive) {
+ // not currently refreshing
+ return;
+ }
+ uiInfo.serverStatus.refreshActive = qfalse;
+ Com_Printf("%d servers listed in browser with %d players.\n",
+ uiInfo.serverStatus.numDisplayServers,
+ uiInfo.serverStatus.numPlayersOnServers);
+ count = trap_LAN_GetServerCount(ui_netSource.integer);
+ if (count - uiInfo.serverStatus.numDisplayServers > 0) {
+ Com_Printf("%d servers not listed due to packet loss or pings higher than %d\n",
+ count - uiInfo.serverStatus.numDisplayServers,
+ (int) trap_Cvar_VariableValue("cl_maxPing"));
+ }
+
+}
+
+/*
+=================
+ArenaServers_MaxPing
+=================
+*/
+#ifndef MISSIONPACK // bk001206
+static int ArenaServers_MaxPing( void ) {
+ int maxPing;
+
+ maxPing = (int)trap_Cvar_VariableValue( "cl_maxPing" );
+ if( maxPing < 100 ) {
+ maxPing = 100;
+ }
+ return maxPing;
+}
+#endif
+
+/*
+=================
+UI_DoServerRefresh
+=================
+*/
+static void UI_DoServerRefresh( void )
+{
+ qboolean wait = qfalse;
+
+ if (!uiInfo.serverStatus.refreshActive) {
+ return;
+ }
+ if (ui_netSource.integer != AS_FAVORITES) {
+ if (ui_netSource.integer == AS_LOCAL) {
+ if (!trap_LAN_GetServerCount(ui_netSource.integer)) {
+ wait = qtrue;
+ }
+ } else {
+ if (trap_LAN_GetServerCount(ui_netSource.integer) < 0) {
+ wait = qtrue;
+ }
+ }
+ }
+
+ if (uiInfo.uiDC.realTime < uiInfo.serverStatus.refreshtime) {
+ if (wait) {
+ return;
+ }
+ }
+
+ // if still trying to retrieve pings
+ if (trap_LAN_UpdateVisiblePings(ui_netSource.integer)) {
+ uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
+ } else if (!wait) {
+ // get the last servers in the list
+ UI_BuildServerDisplayList(2);
+ // stop the refresh
+ UI_StopServerRefresh();
+ }
+ //
+ UI_BuildServerDisplayList(qfalse);
+}
+
+/*
+=================
+UI_StartServerRefresh
+=================
+*/
+static void UI_StartServerRefresh(qboolean full)
+{
+ char *ptr;
+
+ qtime_t q;
+ trap_RealTime(&q);
+ trap_Cvar_Set( va("ui_lastServerRefresh_%i", ui_netSource.integer), va("%s-%i, %i at %i:%i", MonthAbbrev[q.tm_mon],q.tm_mday, 1900+q.tm_year,q.tm_hour,q.tm_min));
+
+ if (!full) {
+ UI_UpdatePendingPings();
+ return;
+ }
+
+ uiInfo.serverStatus.refreshActive = qtrue;
+ uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 1000;
+ // clear number of displayed servers
+ uiInfo.serverStatus.numDisplayServers = 0;
+ uiInfo.serverStatus.numPlayersOnServers = 0;
+ // mark all servers as visible so we store ping updates for them
+ trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
+ // reset all the pings
+ trap_LAN_ResetPings(ui_netSource.integer);
+ //
+ if( ui_netSource.integer == AS_LOCAL ) {
+ trap_Cmd_ExecuteText( EXEC_NOW, "localservers\n" );
+ uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
+ return;
+ }
+
+ uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 5000;
+ if( ui_netSource.integer == AS_GLOBAL ) {
+
+ ptr = UI_Cvar_VariableString("debug_protocol");
+ if (strlen(ptr)) {
+ trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers 0 %s full empty\n", ptr));
+ }
+ else {
+ trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers 0 %d full empty\n", (int)trap_Cvar_VariableValue( "protocol" ) ) );
+ }
+ }
+}
+
diff --git a/code/ui/ui_players.c b/code/ui/ui_players.c
new file mode 100644
index 0000000..9a6a394
--- /dev/null
+++ b/code/ui/ui_players.c
@@ -0,0 +1,1613 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// ui_players.c
+
+#include "ui_local.h"
+
+
+#define UI_TIMER_GESTURE 2300
+#define UI_TIMER_JUMP 1000
+#define UI_TIMER_LAND 130
+#define UI_TIMER_WEAPON_SWITCH 300
+#define UI_TIMER_ATTACK 500
+#define UI_TIMER_MUZZLE_FLASH 20
+#define UI_TIMER_WEAPON_DELAY 250
+
+#define JUMP_HEIGHT 56
+
+#define SWINGSPEED 0.3f
+
+#define SPIN_SPEED 0.9f
+#define COAST_TIME 1000
+
+
+static int dp_realtime;
+static float jumpHeight;
+sfxHandle_t weaponChangeSound;
+
+
+/*
+===============
+UI_PlayerInfo_SetWeapon
+===============
+*/
+static void UI_PlayerInfo_SetWeapon( playerInfo_t *pi, weapon_t weaponNum ) {
+ gitem_t * item;
+ char path[MAX_QPATH];
+
+ pi->currentWeapon = weaponNum;
+tryagain:
+ pi->realWeapon = weaponNum;
+ pi->weaponModel = 0;
+ pi->barrelModel = 0;
+ pi->flashModel = 0;
+
+ if ( weaponNum == WP_NONE ) {
+ return;
+ }
+
+ for ( item = bg_itemlist + 1; item->classname ; item++ ) {
+ if ( item->giType != IT_WEAPON ) {
+ continue;
+ }
+ if ( item->giTag == weaponNum ) {
+ break;
+ }
+ }
+
+ if ( item->classname ) {
+ pi->weaponModel = trap_R_RegisterModel( item->world_model[0] );
+ }
+
+ if( pi->weaponModel == 0 ) {
+ if( weaponNum == WP_MACHINEGUN ) {
+ weaponNum = WP_NONE;
+ goto tryagain;
+ }
+ weaponNum = WP_MACHINEGUN;
+ goto tryagain;
+ }
+
+ if ( weaponNum == WP_MACHINEGUN || weaponNum == WP_GAUNTLET || weaponNum == WP_BFG ) {
+ strcpy( path, item->world_model[0] );
+ COM_StripExtension(path, path, sizeof(path));
+ strcat( path, "_barrel.md3" );
+ pi->barrelModel = trap_R_RegisterModel( path );
+ }
+
+ strcpy( path, item->world_model[0] );
+ COM_StripExtension(path, path, sizeof(path));
+ strcat( path, "_flash.md3" );
+ pi->flashModel = trap_R_RegisterModel( path );
+
+ switch( weaponNum ) {
+ case WP_GAUNTLET:
+ MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
+ break;
+
+ case WP_MACHINEGUN:
+ MAKERGB( pi->flashDlightColor, 1, 1, 0 );
+ break;
+
+ case WP_SHOTGUN:
+ MAKERGB( pi->flashDlightColor, 1, 1, 0 );
+ break;
+
+ case WP_GRENADE_LAUNCHER:
+ MAKERGB( pi->flashDlightColor, 1, 0.7f, 0.5f );
+ break;
+
+ case WP_ROCKET_LAUNCHER:
+ MAKERGB( pi->flashDlightColor, 1, 0.75f, 0 );
+ break;
+
+ case WP_LIGHTNING:
+ MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
+ break;
+
+ case WP_RAILGUN:
+ MAKERGB( pi->flashDlightColor, 1, 0.5f, 0 );
+ break;
+
+ case WP_PLASMAGUN:
+ MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
+ break;
+
+ case WP_BFG:
+ MAKERGB( pi->flashDlightColor, 1, 0.7f, 1 );
+ break;
+
+ case WP_GRAPPLING_HOOK:
+ MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
+ break;
+
+ default:
+ MAKERGB( pi->flashDlightColor, 1, 1, 1 );
+ break;
+ }
+}
+
+
+/*
+===============
+UI_ForceLegsAnim
+===============
+*/
+static void UI_ForceLegsAnim( playerInfo_t *pi, int anim ) {
+ pi->legsAnim = ( ( pi->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
+
+ if ( anim == LEGS_JUMP ) {
+ pi->legsAnimationTimer = UI_TIMER_JUMP;
+ }
+}
+
+
+/*
+===============
+UI_SetLegsAnim
+===============
+*/
+static void UI_SetLegsAnim( playerInfo_t *pi, int anim ) {
+ if ( pi->pendingLegsAnim ) {
+ anim = pi->pendingLegsAnim;
+ pi->pendingLegsAnim = 0;
+ }
+ UI_ForceLegsAnim( pi, anim );
+}
+
+
+/*
+===============
+UI_ForceTorsoAnim
+===============
+*/
+static void UI_ForceTorsoAnim( playerInfo_t *pi, int anim ) {
+ pi->torsoAnim = ( ( pi->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
+
+ if ( anim == TORSO_GESTURE ) {
+ pi->torsoAnimationTimer = UI_TIMER_GESTURE;
+ }
+
+ if ( anim == TORSO_ATTACK || anim == TORSO_ATTACK2 ) {
+ pi->torsoAnimationTimer = UI_TIMER_ATTACK;
+ }
+}
+
+
+/*
+===============
+UI_SetTorsoAnim
+===============
+*/
+static void UI_SetTorsoAnim( playerInfo_t *pi, int anim ) {
+ if ( pi->pendingTorsoAnim ) {
+ anim = pi->pendingTorsoAnim;
+ pi->pendingTorsoAnim = 0;
+ }
+
+ UI_ForceTorsoAnim( pi, anim );
+}
+
+
+/*
+===============
+UI_TorsoSequencing
+===============
+*/
+static void UI_TorsoSequencing( playerInfo_t *pi ) {
+ int currentAnim;
+
+ currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
+
+ if ( pi->weapon != pi->currentWeapon ) {
+ if ( currentAnim != TORSO_DROP ) {
+ pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
+ UI_ForceTorsoAnim( pi, TORSO_DROP );
+ }
+ }
+
+ if ( pi->torsoAnimationTimer > 0 ) {
+ return;
+ }
+
+ if( currentAnim == TORSO_GESTURE ) {
+ UI_SetTorsoAnim( pi, TORSO_STAND );
+ return;
+ }
+
+ if( currentAnim == TORSO_ATTACK || currentAnim == TORSO_ATTACK2 ) {
+ UI_SetTorsoAnim( pi, TORSO_STAND );
+ return;
+ }
+
+ if ( currentAnim == TORSO_DROP ) {
+ UI_PlayerInfo_SetWeapon( pi, pi->weapon );
+ pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
+ UI_ForceTorsoAnim( pi, TORSO_RAISE );
+ return;
+ }
+
+ if ( currentAnim == TORSO_RAISE ) {
+ UI_SetTorsoAnim( pi, TORSO_STAND );
+ return;
+ }
+}
+
+
+/*
+===============
+UI_LegsSequencing
+===============
+*/
+static void UI_LegsSequencing( playerInfo_t *pi ) {
+ int currentAnim;
+
+ currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
+
+ if ( pi->legsAnimationTimer > 0 ) {
+ if ( currentAnim == LEGS_JUMP ) {
+ jumpHeight = JUMP_HEIGHT * sin( M_PI * ( UI_TIMER_JUMP - pi->legsAnimationTimer ) / UI_TIMER_JUMP );
+ }
+ return;
+ }
+
+ if ( currentAnim == LEGS_JUMP ) {
+ UI_ForceLegsAnim( pi, LEGS_LAND );
+ pi->legsAnimationTimer = UI_TIMER_LAND;
+ jumpHeight = 0;
+ return;
+ }
+
+ if ( currentAnim == LEGS_LAND ) {
+ UI_SetLegsAnim( pi, LEGS_IDLE );
+ return;
+ }
+}
+
+
+/*
+======================
+UI_PositionEntityOnTag
+======================
+*/
+static void UI_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
+ clipHandle_t parentModel, char *tagName ) {
+ int i;
+ orientation_t lerped;
+
+ // lerp the tag
+ trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
+ 1.0 - parent->backlerp, tagName );
+
+ // FIXME: allow origin offsets along tag?
+ VectorCopy( parent->origin, entity->origin );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
+ }
+
+ // cast away const because of compiler problems
+ MatrixMultiply( lerped.axis, ((refEntity_t*)parent)->axis, entity->axis );
+ entity->backlerp = parent->backlerp;
+}
+
+
+/*
+======================
+UI_PositionRotatedEntityOnTag
+======================
+*/
+static void UI_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
+ clipHandle_t parentModel, char *tagName ) {
+ int i;
+ orientation_t lerped;
+ vec3_t tempAxis[3];
+
+ // lerp the tag
+ trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
+ 1.0 - parent->backlerp, tagName );
+
+ // FIXME: allow origin offsets along tag?
+ VectorCopy( parent->origin, entity->origin );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
+ }
+
+ // cast away const because of compiler problems
+ MatrixMultiply( entity->axis, ((refEntity_t *)parent)->axis, tempAxis );
+ MatrixMultiply( lerped.axis, tempAxis, entity->axis );
+}
+
+
+/*
+===============
+UI_SetLerpFrameAnimation
+===============
+*/
+static void UI_SetLerpFrameAnimation( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
+ animation_t *anim;
+
+ lf->animationNumber = newAnimation;
+ newAnimation &= ~ANIM_TOGGLEBIT;
+
+ if ( newAnimation < 0 || newAnimation >= MAX_ANIMATIONS ) {
+ trap_Error( va("Bad animation number: %i", newAnimation) );
+ }
+
+ anim = &ci->animations[ newAnimation ];
+
+ lf->animation = anim;
+ lf->animationTime = lf->frameTime + anim->initialLerp;
+}
+
+
+/*
+===============
+UI_RunLerpFrame
+===============
+*/
+static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
+ int f;
+ animation_t *anim;
+
+ // see if the animation sequence is switching
+ if ( newAnimation != lf->animationNumber || !lf->animation ) {
+ UI_SetLerpFrameAnimation( ci, lf, newAnimation );
+ }
+
+ // if we have passed the current frame, move it to
+ // oldFrame and calculate a new frame
+ if ( dp_realtime >= lf->frameTime ) {
+ lf->oldFrame = lf->frame;
+ lf->oldFrameTime = lf->frameTime;
+
+ // get the next frame based on the animation
+ anim = lf->animation;
+ if ( dp_realtime < lf->animationTime ) {
+ lf->frameTime = lf->animationTime; // initial lerp
+ } else {
+ lf->frameTime = lf->oldFrameTime + anim->frameLerp;
+ }
+ f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
+ if ( f >= anim->numFrames ) {
+ f -= anim->numFrames;
+ if ( anim->loopFrames ) {
+ f %= anim->loopFrames;
+ f += anim->numFrames - anim->loopFrames;
+ } else {
+ f = anim->numFrames - 1;
+ // the animation is stuck at the end, so it
+ // can immediately transition to another sequence
+ lf->frameTime = dp_realtime;
+ }
+ }
+ lf->frame = anim->firstFrame + f;
+ if ( dp_realtime > lf->frameTime ) {
+ lf->frameTime = dp_realtime;
+ }
+ }
+
+ if ( lf->frameTime > dp_realtime + 200 ) {
+ lf->frameTime = dp_realtime;
+ }
+
+ if ( lf->oldFrameTime > dp_realtime ) {
+ lf->oldFrameTime = dp_realtime;
+ }
+ // calculate current lerp value
+ if ( lf->frameTime == lf->oldFrameTime ) {
+ lf->backlerp = 0;
+ } else {
+ lf->backlerp = 1.0 - (float)( dp_realtime - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
+ }
+}
+
+
+/*
+===============
+UI_PlayerAnimation
+===============
+*/
+static void UI_PlayerAnimation( playerInfo_t *pi, int *legsOld, int *legs, float *legsBackLerp,
+ int *torsoOld, int *torso, float *torsoBackLerp ) {
+
+ // legs animation
+ pi->legsAnimationTimer -= uiInfo.uiDC.frameTime;
+ if ( pi->legsAnimationTimer < 0 ) {
+ pi->legsAnimationTimer = 0;
+ }
+
+ UI_LegsSequencing( pi );
+
+ if ( pi->legs.yawing && ( pi->legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {
+ UI_RunLerpFrame( pi, &pi->legs, LEGS_TURN );
+ } else {
+ UI_RunLerpFrame( pi, &pi->legs, pi->legsAnim );
+ }
+ *legsOld = pi->legs.oldFrame;
+ *legs = pi->legs.frame;
+ *legsBackLerp = pi->legs.backlerp;
+
+ // torso animation
+ pi->torsoAnimationTimer -= uiInfo.uiDC.frameTime;
+ if ( pi->torsoAnimationTimer < 0 ) {
+ pi->torsoAnimationTimer = 0;
+ }
+
+ UI_TorsoSequencing( pi );
+
+ UI_RunLerpFrame( pi, &pi->torso, pi->torsoAnim );
+ *torsoOld = pi->torso.oldFrame;
+ *torso = pi->torso.frame;
+ *torsoBackLerp = pi->torso.backlerp;
+}
+
+
+/*
+==================
+UI_SwingAngles
+==================
+*/
+static void UI_SwingAngles( float destination, float swingTolerance, float clampTolerance,
+ float speed, float *angle, qboolean *swinging ) {
+ float swing;
+ float move;
+ float scale;
+
+ if ( !*swinging ) {
+ // see if a swing should be started
+ swing = AngleSubtract( *angle, destination );
+ if ( swing > swingTolerance || swing < -swingTolerance ) {
+ *swinging = qtrue;
+ }
+ }
+
+ if ( !*swinging ) {
+ return;
+ }
+
+ // modify the speed depending on the delta
+ // so it doesn't seem so linear
+ swing = AngleSubtract( destination, *angle );
+ scale = fabs( swing );
+ if ( scale < swingTolerance * 0.5 ) {
+ scale = 0.5;
+ } else if ( scale < swingTolerance ) {
+ scale = 1.0;
+ } else {
+ scale = 2.0;
+ }
+
+ // swing towards the destination angle
+ if ( swing >= 0 ) {
+ move = uiInfo.uiDC.frameTime * scale * speed;
+ if ( move >= swing ) {
+ move = swing;
+ *swinging = qfalse;
+ }
+ *angle = AngleMod( *angle + move );
+ } else if ( swing < 0 ) {
+ move = uiInfo.uiDC.frameTime * scale * -speed;
+ if ( move <= swing ) {
+ move = swing;
+ *swinging = qfalse;
+ }
+ *angle = AngleMod( *angle + move );
+ }
+
+ // clamp to no more than tolerance
+ swing = AngleSubtract( destination, *angle );
+ if ( swing > clampTolerance ) {
+ *angle = AngleMod( destination - (clampTolerance - 1) );
+ } else if ( swing < -clampTolerance ) {
+ *angle = AngleMod( destination + (clampTolerance - 1) );
+ }
+}
+
+
+/*
+======================
+UI_MovedirAdjustment
+======================
+*/
+static float UI_MovedirAdjustment( playerInfo_t *pi ) {
+ vec3_t relativeAngles;
+ vec3_t moveVector;
+
+ VectorSubtract( pi->viewAngles, pi->moveAngles, relativeAngles );
+ AngleVectors( relativeAngles, moveVector, NULL, NULL );
+ if ( Q_fabs( moveVector[0] ) < 0.01 ) {
+ moveVector[0] = 0.0;
+ }
+ if ( Q_fabs( moveVector[1] ) < 0.01 ) {
+ moveVector[1] = 0.0;
+ }
+
+ if ( moveVector[1] == 0 && moveVector[0] > 0 ) {
+ return 0;
+ }
+ if ( moveVector[1] < 0 && moveVector[0] > 0 ) {
+ return 22;
+ }
+ if ( moveVector[1] < 0 && moveVector[0] == 0 ) {
+ return 45;
+ }
+ if ( moveVector[1] < 0 && moveVector[0] < 0 ) {
+ return -22;
+ }
+ if ( moveVector[1] == 0 && moveVector[0] < 0 ) {
+ return 0;
+ }
+ if ( moveVector[1] > 0 && moveVector[0] < 0 ) {
+ return 22;
+ }
+ if ( moveVector[1] > 0 && moveVector[0] == 0 ) {
+ return -45;
+ }
+
+ return -22;
+}
+
+
+/*
+===============
+UI_PlayerAngles
+===============
+*/
+static void UI_PlayerAngles( playerInfo_t *pi, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {
+ vec3_t legsAngles, torsoAngles, headAngles;
+ float dest;
+ float adjust;
+
+ VectorCopy( pi->viewAngles, headAngles );
+ headAngles[YAW] = AngleMod( headAngles[YAW] );
+ VectorClear( legsAngles );
+ VectorClear( torsoAngles );
+
+ // --------- yaw -------------
+
+ // allow yaw to drift a bit
+ if ( ( pi->legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE
+ || ( pi->torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) {
+ // if not standing still, always point all in the same direction
+ pi->torso.yawing = qtrue; // always center
+ pi->torso.pitching = qtrue; // always center
+ pi->legs.yawing = qtrue; // always center
+ }
+
+ // adjust legs for movement dir
+ adjust = UI_MovedirAdjustment( pi );
+ legsAngles[YAW] = headAngles[YAW] + adjust;
+ torsoAngles[YAW] = headAngles[YAW] + 0.25 * adjust;
+
+
+ // torso
+ UI_SwingAngles( torsoAngles[YAW], 25, 90, SWINGSPEED, &pi->torso.yawAngle, &pi->torso.yawing );
+ UI_SwingAngles( legsAngles[YAW], 40, 90, SWINGSPEED, &pi->legs.yawAngle, &pi->legs.yawing );
+
+ torsoAngles[YAW] = pi->torso.yawAngle;
+ legsAngles[YAW] = pi->legs.yawAngle;
+
+ // --------- pitch -------------
+
+ // only show a fraction of the pitch angle in the torso
+ if ( headAngles[PITCH] > 180 ) {
+ dest = (-360 + headAngles[PITCH]) * 0.75;
+ } else {
+ dest = headAngles[PITCH] * 0.75;
+ }
+ UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching );
+ torsoAngles[PITCH] = pi->torso.pitchAngle;
+
+ // pull the angles back out of the hierarchial chain
+ AnglesSubtract( headAngles, torsoAngles, headAngles );
+ AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
+ AnglesToAxis( legsAngles, legs );
+ AnglesToAxis( torsoAngles, torso );
+ AnglesToAxis( headAngles, head );
+}
+
+
+/*
+===============
+UI_PlayerFloatSprite
+===============
+*/
+static void UI_PlayerFloatSprite( playerInfo_t *pi, vec3_t origin, qhandle_t shader ) {
+ refEntity_t ent;
+
+ memset( &ent, 0, sizeof( ent ) );
+ VectorCopy( origin, ent.origin );
+ ent.origin[2] += 48;
+ ent.reType = RT_SPRITE;
+ ent.customShader = shader;
+ ent.radius = 10;
+ ent.renderfx = 0;
+ trap_R_AddRefEntityToScene( &ent );
+}
+
+
+/*
+======================
+UI_MachinegunSpinAngle
+======================
+*/
+float UI_MachinegunSpinAngle( playerInfo_t *pi ) {
+ int delta;
+ float angle;
+ float speed;
+ int torsoAnim;
+
+ delta = dp_realtime - pi->barrelTime;
+ if ( pi->barrelSpinning ) {
+ angle = pi->barrelAngle + delta * SPIN_SPEED;
+ } else {
+ if ( delta > COAST_TIME ) {
+ delta = COAST_TIME;
+ }
+
+ speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
+ angle = pi->barrelAngle + delta * speed;
+ }
+
+ torsoAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
+ if( torsoAnim == TORSO_ATTACK2 ) {
+ torsoAnim = TORSO_ATTACK;
+ }
+ if ( pi->barrelSpinning == !(torsoAnim == TORSO_ATTACK) ) {
+ pi->barrelTime = dp_realtime;
+ pi->barrelAngle = AngleMod( angle );
+ pi->barrelSpinning = !!(torsoAnim == TORSO_ATTACK);
+ }
+
+ return angle;
+}
+
+
+/*
+===============
+UI_DrawPlayer
+===============
+*/
+void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ) {
+ refdef_t refdef;
+ refEntity_t legs;
+ refEntity_t torso;
+ refEntity_t head;
+ refEntity_t gun;
+ refEntity_t barrel;
+ refEntity_t flash;
+ vec3_t origin;
+ int renderfx;
+ vec3_t mins = {-16, -16, -24};
+ vec3_t maxs = {16, 16, 32};
+ float len;
+ float xx;
+
+ if ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) {
+ return;
+ }
+
+ // this allows the ui to cache the player model on the main menu
+ if (w == 0 || h == 0) {
+ return;
+ }
+
+ dp_realtime = time;
+
+ if ( pi->pendingWeapon != -1 && dp_realtime > pi->weaponTimer ) {
+ pi->weapon = pi->pendingWeapon;
+ pi->lastWeapon = pi->pendingWeapon;
+ pi->pendingWeapon = -1;
+ pi->weaponTimer = 0;
+ if( pi->currentWeapon != pi->weapon ) {
+ trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL );
+ }
+ }
+
+ UI_AdjustFrom640( &x, &y, &w, &h );
+
+ y -= jumpHeight;
+
+ memset( &refdef, 0, sizeof( refdef ) );
+ memset( &legs, 0, sizeof(legs) );
+ memset( &torso, 0, sizeof(torso) );
+ memset( &head, 0, sizeof(head) );
+
+ refdef.rdflags = RDF_NOWORLDMODEL;
+
+ AxisClear( refdef.viewaxis );
+
+ refdef.x = x;
+ refdef.y = y;
+ refdef.width = w;
+ refdef.height = h;
+
+ refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
+ xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
+ refdef.fov_y = atan2( refdef.height, xx );
+ refdef.fov_y *= ( 360 / (float)M_PI );
+
+ // calculate distance so the player nearly fills the box
+ len = 0.7 * ( maxs[2] - mins[2] );
+ origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 );
+ origin[1] = 0.5 * ( mins[1] + maxs[1] );
+ origin[2] = -0.5 * ( mins[2] + maxs[2] );
+
+ refdef.time = dp_realtime;
+
+ trap_R_ClearScene();
+
+ // get the rotation information
+ UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis );
+
+ // get the animation state (after rotation, to allow feet shuffle)
+ UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp,
+ &torso.oldframe, &torso.frame, &torso.backlerp );
+
+ renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
+
+ //
+ // add the legs
+ //
+ legs.hModel = pi->legsModel;
+ legs.customSkin = pi->legsSkin;
+
+ VectorCopy( origin, legs.origin );
+
+ VectorCopy( origin, legs.lightingOrigin );
+ legs.renderfx = renderfx;
+ VectorCopy (legs.origin, legs.oldorigin);
+
+ trap_R_AddRefEntityToScene( &legs );
+
+ if (!legs.hModel) {
+ return;
+ }
+
+ //
+ // add the torso
+ //
+ torso.hModel = pi->torsoModel;
+ if (!torso.hModel) {
+ return;
+ }
+
+ torso.customSkin = pi->torsoSkin;
+
+ VectorCopy( origin, torso.lightingOrigin );
+
+ UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, "tag_torso");
+
+ torso.renderfx = renderfx;
+
+ trap_R_AddRefEntityToScene( &torso );
+
+ //
+ // add the head
+ //
+ head.hModel = pi->headModel;
+ if (!head.hModel) {
+ return;
+ }
+ head.customSkin = pi->headSkin;
+
+ VectorCopy( origin, head.lightingOrigin );
+
+ UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, "tag_head");
+
+ head.renderfx = renderfx;
+
+ trap_R_AddRefEntityToScene( &head );
+
+ //
+ // add the gun
+ //
+ if ( pi->currentWeapon != WP_NONE ) {
+ memset( &gun, 0, sizeof(gun) );
+ gun.hModel = pi->weaponModel;
+ VectorCopy( origin, gun.lightingOrigin );
+ UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, "tag_weapon");
+ gun.renderfx = renderfx;
+ trap_R_AddRefEntityToScene( &gun );
+ }
+
+ //
+ // add the spinning barrel
+ //
+ if ( pi->realWeapon == WP_MACHINEGUN || pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
+ vec3_t angles;
+
+ memset( &barrel, 0, sizeof(barrel) );
+ VectorCopy( origin, barrel.lightingOrigin );
+ barrel.renderfx = renderfx;
+
+ barrel.hModel = pi->barrelModel;
+ angles[YAW] = 0;
+ angles[PITCH] = 0;
+ angles[ROLL] = UI_MachinegunSpinAngle( pi );
+ if( pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
+ angles[PITCH] = angles[ROLL];
+ angles[ROLL] = 0;
+ }
+ AnglesToAxis( angles, barrel.axis );
+
+ UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel");
+
+ trap_R_AddRefEntityToScene( &barrel );
+ }
+
+ //
+ // add muzzle flash
+ //
+ if ( dp_realtime <= pi->muzzleFlashTime ) {
+ if ( pi->flashModel ) {
+ memset( &flash, 0, sizeof(flash) );
+ flash.hModel = pi->flashModel;
+ VectorCopy( origin, flash.lightingOrigin );
+ UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash");
+ flash.renderfx = renderfx;
+ trap_R_AddRefEntityToScene( &flash );
+ }
+
+ // make a dlight for the flash
+ if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) {
+ trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), pi->flashDlightColor[0],
+ pi->flashDlightColor[1], pi->flashDlightColor[2] );
+ }
+ }
+
+ //
+ // add the chat icon
+ //
+ if ( pi->chat ) {
+ UI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) );
+ }
+
+ //
+ // add an accent light
+ //
+ origin[0] -= 100; // + = behind, - = in front
+ origin[1] += 100; // + = left, - = right
+ origin[2] += 100; // + = above, - = below
+ trap_R_AddLightToScene( origin, 500, 1.0, 1.0, 1.0 );
+
+ origin[0] -= 100;
+ origin[1] -= 100;
+ origin[2] -= 100;
+ trap_R_AddLightToScene( origin, 500, 1.0, 0.0, 0.0 );
+
+ trap_R_RenderScene( &refdef );
+}
+
+
+
+/*
+===============
+UI_DrawPlayerII
+
+A less FOV stretched version for drawing on the main menu
+===============
+*/
+void UI_DrawPlayerII( float x, float y, float w, float h, playerInfo_t *pi, int time ) {
+ refdef_t refdef;
+ refEntity_t legs;
+ refEntity_t torso;
+ refEntity_t head;
+ refEntity_t gun;
+ refEntity_t barrel;
+ refEntity_t flash;
+ vec3_t origin;
+ int renderfx;
+ vec3_t mins = {-16, -16, -24};
+ vec3_t maxs = {16, 16, 32};
+ float len;
+ float xx;
+
+ if ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) {
+ return;
+ }
+
+ // this allows the ui to cache the player model on the main menu
+ if (w == 0 || h == 0) {
+ return;
+ }
+
+ dp_realtime = time;
+
+ if ( pi->pendingWeapon != -1 && dp_realtime > pi->weaponTimer ) {
+ pi->weapon = pi->pendingWeapon;
+ pi->lastWeapon = pi->pendingWeapon;
+ pi->pendingWeapon = -1;
+ pi->weaponTimer = 0;
+ if( pi->currentWeapon != pi->weapon ) {
+ trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL );
+ }
+ }
+
+ UI_AdjustFrom640( &x, &y, &w, &h );
+
+ y -= jumpHeight;
+
+ memset( &refdef, 0, sizeof( refdef ) );
+ memset( &legs, 0, sizeof(legs) );
+ memset( &torso, 0, sizeof(torso) );
+ memset( &head, 0, sizeof(head) );
+
+ refdef.rdflags = RDF_NOWORLDMODEL;
+
+ AxisClear( refdef.viewaxis );
+
+ refdef.x = x;
+ refdef.y = y;
+ refdef.width = w;
+ refdef.height = h;
+
+ refdef.fov_x = (int)((float)refdef.width / 640.0f * 30.0f);
+ xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
+ refdef.fov_y = atan2( refdef.height, xx );
+ refdef.fov_y *= ( 360 / (float)M_PI );
+
+ // calculate distance so the player nearly fills the box
+ len = 0.7 * ( maxs[2] - mins[2] );
+ origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.93 );
+ origin[1] = 1.0 * ( mins[1] + maxs[1] );
+ origin[2] = -2.7 * ( mins[2] + maxs[2] );
+
+ refdef.time = dp_realtime;
+
+ trap_R_ClearScene();
+
+ // get the rotation information
+ UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis );
+
+ // get the animation state (after rotation, to allow feet shuffle)
+ UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp,
+ &torso.oldframe, &torso.frame, &torso.backlerp );
+
+ renderfx = RF_LIGHTING_ORIGIN;
+
+ //
+ // add the legs
+ //
+ legs.hModel = pi->legsModel;
+ legs.customSkin = pi->legsSkin;
+
+ VectorCopy( origin, legs.origin );
+
+ VectorCopy( origin, legs.lightingOrigin );
+ legs.renderfx = renderfx;
+ VectorCopy (legs.origin, legs.oldorigin);
+
+ trap_R_AddRefEntityToScene( &legs );
+ if (!legs.hModel) {
+ return;
+ }
+
+ //
+ // add the torso
+ //
+ torso.hModel = pi->torsoModel;
+ if (!torso.hModel) {
+ return;
+ }
+
+ torso.customSkin = pi->torsoSkin;
+
+ VectorCopy( origin, torso.lightingOrigin );
+
+ UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, "tag_torso");
+
+ torso.renderfx = renderfx;
+
+ trap_R_AddRefEntityToScene( &torso );
+
+ //
+ // add the head
+ //
+ head.hModel = pi->headModel;
+ if (!head.hModel) {
+ return;
+ }
+ head.customSkin = pi->headSkin;
+
+ VectorCopy( origin, head.lightingOrigin );
+
+ UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, "tag_head");
+
+ head.renderfx = renderfx;
+
+ trap_R_AddRefEntityToScene( &head );
+
+ //
+ // add the gun
+ //
+ if ( pi->currentWeapon != WP_NONE ) {
+ memset( &gun, 0, sizeof(gun) );
+ gun.hModel = pi->weaponModel;
+ VectorCopy( origin, gun.lightingOrigin );
+ UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, "tag_weapon");
+ gun.renderfx = renderfx;
+ trap_R_AddRefEntityToScene( &gun );
+ }
+
+ //
+ // add the spinning barrel
+ //
+ if ( pi->realWeapon == WP_MACHINEGUN || pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
+ vec3_t angles;
+
+ memset( &barrel, 0, sizeof(barrel) );
+ VectorCopy( origin, barrel.lightingOrigin );
+ barrel.renderfx = renderfx;
+
+ barrel.hModel = pi->barrelModel;
+ angles[YAW] = 0;
+ angles[PITCH] = 0;
+ angles[ROLL] = UI_MachinegunSpinAngle( pi );
+ if( pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
+ angles[PITCH] = angles[ROLL];
+ angles[ROLL] = 0;
+ }
+ AnglesToAxis( angles, barrel.axis );
+
+ UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel");
+
+ trap_R_AddRefEntityToScene( &barrel );
+ }
+
+ //
+ // add muzzle flash
+ //
+ if ( dp_realtime <= pi->muzzleFlashTime ) {
+ if ( pi->flashModel ) {
+ memset( &flash, 0, sizeof(flash) );
+ flash.hModel = pi->flashModel;
+ VectorCopy( origin, flash.lightingOrigin );
+ UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash");
+ flash.renderfx = renderfx;
+ trap_R_AddRefEntityToScene( &flash );
+ }
+
+ // make a dlight for the flash
+ if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) {
+ trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), pi->flashDlightColor[0],
+ pi->flashDlightColor[1], pi->flashDlightColor[2] );
+ }
+ }
+
+ //
+ // add the chat icon
+ //
+ if ( pi->chat ) {
+ UI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) );
+ }
+
+ //
+ // add an accent light
+ //
+ origin[0] -= 100; // + = behind, - = in front
+ origin[1] += 100; // + = left, - = right
+ origin[2] += 100; // + = above, - = below
+ //trap_R_AddLightToScene( origin, 500, 0.3, 0.2, 0.8 );
+
+ origin[0] += 10; // + = behind, - = in front
+ origin[1] += 80; // + = left, - = right
+ origin[2] += 130; // + = above, - = below
+ trap_R_AddLightToScene( origin, 250, 0.54, 0.89, 0.79 );
+
+
+ origin[0] -= 50; // + = behind, - = in front
+ origin[1] -= 90; // + = left, - = right
+ origin[2] -= 69; // + = above, - = below
+ trap_R_AddLightToScene( origin, 350, 0.60, 0.03, 0.22 );
+
+
+ origin[0] -= 100;
+ origin[1] -= 100;
+ origin[2] -= 100;
+ //trap_R_AddLightToScene( origin, 500, 0.8, 0.2, 0.1 );
+// UI_ForceLegsAnim( pi, BOTH_POSE ); // leilei - pose hack
+// UI_ForceTorsoAnim( pi, BOTH_POSE );
+
+ trap_R_RenderScene( &refdef );
+}
+
+
+/*
+==========================
+UI_FileExists
+==========================
+*/
+static qboolean UI_FileExists(const char *filename) {
+ int len;
+
+ len = trap_FS_FOpenFile( filename, NULL, FS_READ );
+ if (len>0) {
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==========================
+UI_FindClientHeadFile
+==========================
+*/
+static qboolean UI_FindClientHeadFile( char *filename, int length, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) {
+ char *team, *headsFolder;
+ int i;
+
+ team = "default";
+
+ if ( headModelName[0] == '*' ) {
+ headsFolder = "heads/";
+ headModelName++;
+ }
+ else {
+ headsFolder = "";
+ }
+ while(1) {
+ for ( i = 0; i < 2; i++ ) {
+ if ( i == 0 && teamName && *teamName ) {
+ Com_sprintf( filename, length, "models/players/%s%s/%s/%s%s_%s.%s", headsFolder, headModelName, headSkinName, teamName, base, team, ext );
+ }
+ else {
+ Com_sprintf( filename, length, "models/players/%s%s/%s/%s_%s.%s", headsFolder, headModelName, headSkinName, base, team, ext );
+ }
+ if ( UI_FileExists( filename ) ) {
+ return qtrue;
+ }
+ if ( i == 0 && teamName && *teamName ) {
+ Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, headSkinName, ext );
+ }
+ else {
+ Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, headSkinName, ext );
+ }
+ if ( UI_FileExists( filename ) ) {
+ return qtrue;
+ }
+ if ( !teamName || !*teamName ) {
+ break;
+ }
+ }
+ // if tried the heads folder first
+ if ( headsFolder[0] ) {
+ break;
+ }
+ headsFolder = "heads/";
+ }
+
+ return qfalse;
+}
+
+/*
+==========================
+UI_RegisterClientSkin
+==========================
+*/
+static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName , const char *teamName) {
+ char filename[MAX_QPATH*2];
+
+ if (teamName && *teamName) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/%s/lower_%s.skin", modelName, teamName, skinName );
+ } else {
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName );
+ }
+ pi->legsSkin = trap_R_RegisterSkin( filename );
+ if (!pi->legsSkin) {
+ if (teamName && *teamName) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%s/lower_%s.skin", modelName, teamName, skinName );
+ } else {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower_%s.skin", modelName, skinName );
+ }
+ pi->legsSkin = trap_R_RegisterSkin( filename );
+ }
+
+ if (teamName && *teamName) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/%s/upper_%s.skin", modelName, teamName, skinName );
+ } else {
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName );
+ }
+ pi->torsoSkin = trap_R_RegisterSkin( filename );
+ if (!pi->torsoSkin) {
+ if (teamName && *teamName) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%s/upper_%s.skin", modelName, teamName, skinName );
+ } else {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper_%s.skin", modelName, skinName );
+ }
+ pi->torsoSkin = trap_R_RegisterSkin( filename );
+ }
+
+ if ( UI_FindClientHeadFile( filename, sizeof(filename), teamName, headModelName, headSkinName, "head", "skin" ) ) {
+ pi->headSkin = trap_R_RegisterSkin( filename );
+ }
+
+ if ( !pi->legsSkin || !pi->torsoSkin || !pi->headSkin ) {
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+
+/*
+======================
+UI_ParseAnimationFile
+======================
+*/
+static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) {
+ char *text_p, *prev;
+ int len;
+ int i;
+ char *token;
+ float fps;
+ int skip;
+ char text[20000];
+ fileHandle_t f;
+
+ memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS );
+
+ // load the file
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( len <= 0 ) {
+ return qfalse;
+ }
+ if ( len >= ( sizeof( text ) - 1 ) ) {
+ Com_Printf( "File %s too long\n", filename );
+ trap_FS_FCloseFile( f );
+ return qfalse;
+ }
+ trap_FS_Read( text, len, f );
+ text[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ COM_Compress(text);
+
+ // parse the text
+ text_p = text;
+ skip = 0; // quite the compiler warning
+
+ // read optional parameters
+ while ( 1 ) {
+ prev = text_p; // so we can unget
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ if ( !Q_stricmp( token, "footsteps" ) ) {
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ continue;
+ } else if ( !Q_stricmp( token, "headoffset" ) ) {
+ for ( i = 0 ; i < 3 ; i++ ) {
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ }
+ continue;
+ } else if ( !Q_stricmp( token, "sex" ) ) {
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ continue;
+ }
+
+ // if it is a number, start parsing animations
+ if ( token[0] >= '0' && token[0] <= '9' ) {
+ text_p = prev; // unget the token
+ break;
+ }
+
+ Com_Printf( "unknown token '%s' is %s\n", token, filename );
+ }
+
+ // read information for each frame
+ for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
+
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ animations[i].firstFrame = atoi( token );
+ // leg only frames are adjusted to not count the upper body only frames
+ if ( i == LEGS_WALKCR ) {
+ skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
+ }
+ if ( i >= LEGS_WALKCR ) {
+ animations[i].firstFrame -= skip;
+ }
+
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ animations[i].numFrames = atoi( token );
+
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ animations[i].loopFrames = atoi( token );
+
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ fps = atof( token );
+ if ( fps == 0 ) {
+ fps = 1;
+ }
+ animations[i].frameLerp = 1000 / fps;
+ animations[i].initialLerp = 1000 / fps;
+ }
+
+ if ( i != MAX_ANIMATIONS ) {
+ Com_Printf( "Error parsing animation file: %s\n", filename );
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+/*
+==========================
+UI_RegisterClientModelname
+==========================
+*/
+qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName, const char *headModelSkinName, const char *teamName ) {
+ char modelName[MAX_QPATH];
+ char skinName[MAX_QPATH];
+ char headModelName[MAX_QPATH];
+ char headSkinName[MAX_QPATH];
+ char filename[MAX_QPATH];
+ char *slash;
+
+ pi->torsoModel = 0;
+ pi->headModel = 0;
+
+ if ( !modelSkinName[0] ) {
+ return qfalse;
+ }
+
+ Q_strncpyz( modelName, modelSkinName, sizeof( modelName ) );
+
+ slash = strchr( modelName, '/' );
+ if ( !slash ) {
+ // modelName did not include a skin name
+ Q_strncpyz( skinName, "default", sizeof( skinName ) );
+ } else {
+ Q_strncpyz( skinName, slash + 1, sizeof( skinName ) );
+ *slash = '\0';
+ }
+
+ Q_strncpyz( headModelName, headModelSkinName, sizeof( headModelName ) );
+ slash = strchr( headModelName, '/' );
+ if ( !slash ) {
+ // modelName did not include a skin name
+ Q_strncpyz( headSkinName, "default", sizeof( skinName ) );
+ } else {
+ Q_strncpyz( headSkinName, slash + 1, sizeof( skinName ) );
+ *slash = '\0';
+ }
+
+ // load cmodels before models so filecache works
+
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
+ pi->legsModel = trap_R_RegisterModel( filename );
+ if ( !pi->legsModel ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower.md3", modelName );
+ pi->legsModel = trap_R_RegisterModel( filename );
+ if ( !pi->legsModel ) {
+ Com_Printf( "Failed to load model file %s\n", filename );
+ return qfalse;
+ }
+ }
+
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
+ pi->torsoModel = trap_R_RegisterModel( filename );
+ if ( !pi->torsoModel ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper.md3", modelName );
+ pi->torsoModel = trap_R_RegisterModel( filename );
+ if ( !pi->torsoModel ) {
+ Com_Printf( "Failed to load model file %s\n", filename );
+ return qfalse;
+ }
+ }
+
+ if (headModelName[0] == '*' ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", &headModelName[1], &headModelName[1] );
+ }
+ else {
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headModelName );
+ }
+ pi->headModel = trap_R_RegisterModel( filename );
+ if ( !pi->headModel && headModelName[0] != '*') {
+ Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", headModelName, headModelName );
+ pi->headModel = trap_R_RegisterModel( filename );
+ }
+
+ if (!pi->headModel) {
+ Com_Printf( "Failed to load model file %s\n", filename );
+ return qfalse;
+ }
+
+ // if any skins failed to load, fall back to default
+ if ( !UI_RegisterClientSkin( pi, modelName, skinName, headModelName, headSkinName, teamName) ) {
+ if ( !UI_RegisterClientSkin( pi, modelName, "default", headModelName, "default", teamName ) ) {
+ Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName );
+ return qfalse;
+ }
+ }
+
+ // load the animations
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
+ if ( !UI_ParseAnimationFile( filename, pi->animations ) ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName );
+ if ( !UI_ParseAnimationFile( filename, pi->animations ) ) {
+ Com_Printf( "Failed to load animation file %s\n", filename );
+ return qfalse;
+ }
+ }
+
+ return qtrue;
+}
+
+
+/*
+===============
+UI_PlayerInfo_SetModel
+===============
+*/
+void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model, const char *headmodel, char *teamName ) {
+ memset( pi, 0, sizeof(*pi) );
+ UI_RegisterClientModelname( pi, model, headmodel, teamName );
+ pi->weapon = WP_MACHINEGUN;
+ pi->currentWeapon = pi->weapon;
+ pi->lastWeapon = pi->weapon;
+ pi->pendingWeapon = -1;
+ pi->weaponTimer = 0;
+ pi->chat = qfalse;
+ pi->newModel = qtrue;
+ UI_PlayerInfo_SetWeapon( pi, pi->weapon );
+}
+
+
+/*
+===============
+UI_PlayerInfo_SetInfo
+===============
+*/
+void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) {
+ int currentAnim;
+ weapon_t weaponNum;
+
+ pi->chat = chat;
+
+ // view angles
+ VectorCopy( viewAngles, pi->viewAngles );
+
+ // move angles
+ VectorCopy( moveAngles, pi->moveAngles );
+
+ if ( pi->newModel ) {
+ pi->newModel = qfalse;
+
+ jumpHeight = 0;
+ pi->pendingLegsAnim = 0;
+ UI_ForceLegsAnim( pi, legsAnim );
+ pi->legs.yawAngle = viewAngles[YAW];
+ pi->legs.yawing = qfalse;
+
+ pi->pendingTorsoAnim = 0;
+ UI_ForceTorsoAnim( pi, torsoAnim );
+ pi->torso.yawAngle = viewAngles[YAW];
+ pi->torso.yawing = qfalse;
+
+ if ( weaponNumber != -1 ) {
+ pi->weapon = weaponNumber;
+ pi->currentWeapon = weaponNumber;
+ pi->lastWeapon = weaponNumber;
+ pi->pendingWeapon = -1;
+ pi->weaponTimer = 0;
+ UI_PlayerInfo_SetWeapon( pi, pi->weapon );
+ }
+
+ return;
+ }
+
+ // weapon
+ if ( weaponNumber == -1 ) {
+ pi->pendingWeapon = -1;
+ pi->weaponTimer = 0;
+ }
+ else if ( weaponNumber != WP_NONE ) {
+ pi->pendingWeapon = weaponNumber;
+ pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY;
+ }
+ weaponNum = pi->lastWeapon;
+ pi->weapon = weaponNum;
+
+ if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) {
+ torsoAnim = legsAnim = BOTH_DEATH1;
+ pi->weapon = pi->currentWeapon = WP_NONE;
+ UI_PlayerInfo_SetWeapon( pi, pi->weapon );
+
+ jumpHeight = 0;
+ pi->pendingLegsAnim = 0;
+ UI_ForceLegsAnim( pi, legsAnim );
+
+ pi->pendingTorsoAnim = 0;
+ UI_ForceTorsoAnim( pi, torsoAnim );
+
+ return;
+ }
+
+ // leg animation
+ currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
+ if ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) {
+ pi->pendingLegsAnim = legsAnim;
+ }
+ else if ( legsAnim != currentAnim ) {
+ jumpHeight = 0;
+ pi->pendingLegsAnim = 0;
+ UI_ForceLegsAnim( pi, legsAnim );
+ }
+
+ // torso animation
+ if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) {
+ if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
+ torsoAnim = TORSO_STAND2;
+ }
+ else {
+ torsoAnim = TORSO_STAND;
+ }
+ }
+
+ if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) {
+ if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
+ torsoAnim = TORSO_ATTACK2;
+ }
+ else {
+ torsoAnim = TORSO_ATTACK;
+ }
+ pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH;
+ //FIXME play firing sound here
+ }
+
+ currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
+
+ if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) {
+ pi->pendingTorsoAnim = torsoAnim;
+ }
+ else if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) {
+ pi->pendingTorsoAnim = torsoAnim;
+ }
+ else if ( torsoAnim != currentAnim ) {
+ pi->pendingTorsoAnim = 0;
+ UI_ForceTorsoAnim( pi, torsoAnim );
+ }
+}
diff --git a/game/code/ui/ui_public.h b/code/ui/ui_public.h
similarity index 100%
rename from game/code/ui/ui_public.h
rename to code/ui/ui_public.h
diff --git a/code/ui/ui_shared.c b/code/ui/ui_shared.c
new file mode 100644
index 0000000..d63a796
--- /dev/null
+++ b/code/ui/ui_shared.c
@@ -0,0 +1,5782 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// string allocation/managment
+
+#include "ui_shared.h"
+
+#define SCROLL_TIME_START 500
+#define SCROLL_TIME_ADJUST 150
+#define SCROLL_TIME_ADJUSTOFFSET 40
+#define SCROLL_TIME_FLOOR 20
+
+typedef struct scrollInfo_s {
+ int nextScrollTime;
+ int nextAdjustTime;
+ int adjustValue;
+ int scrollKey;
+ float xStart;
+ float yStart;
+ itemDef_t *item;
+ qboolean scrollDir;
+} scrollInfo_t;
+
+static scrollInfo_t scrollInfo;
+
+static void (*captureFunc) (void *p) = 0;
+static void *captureData = NULL;
+static itemDef_t *itemCapture = NULL; // item that has the mouse captured ( if any )
+
+displayContextDef_t *DC = NULL;
+
+static qboolean g_waitingForKey = qfalse;
+static qboolean g_editingField = qfalse;
+
+static itemDef_t *g_bindItem = NULL;
+static itemDef_t *g_editItem = NULL;
+
+menuDef_t Menus[MAX_MENUS]; // defined menus
+int menuCount = 0; // how many
+
+menuDef_t *menuStack[MAX_OPEN_MENUS];
+int openMenuCount = 0;
+
+static qboolean debugMode = qfalse;
+
+#define DOUBLE_CLICK_DELAY 300
+static int lastListBoxClickTime = 0;
+
+void Item_RunScript(itemDef_t *item, const char *s);
+void Item_SetupKeywordHash(void);
+void Menu_SetupKeywordHash(void);
+int BindingIDFromName(const char *name);
+qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down);
+itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu);
+itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu);
+static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y);
+
+#ifdef CGAME
+#define MEM_POOL_SIZE 128 * 1024
+#else
+#define MEM_POOL_SIZE 1024 * 1024
+#endif
+
+static char memoryPool[MEM_POOL_SIZE];
+static int allocPoint, outOfMemory;
+
+
+/*
+===============
+UI_Alloc
+===============
+*/
+void *UI_Alloc( int size ) {
+ char *p;
+
+ if ( allocPoint + size > MEM_POOL_SIZE ) {
+ outOfMemory = qtrue;
+ if (DC->Print) {
+ DC->Print("UI_Alloc: Failure. Out of memory!\n");
+ }
+ //DC->trap_Print(S_COLOR_YELLOW"WARNING: UI Out of Memory!\n");
+ return NULL;
+ }
+
+ p = &memoryPool[allocPoint];
+
+ allocPoint += ( size + 15 ) & ~15;
+
+ return p;
+}
+
+/*
+===============
+UI_InitMemory
+===============
+*/
+void UI_InitMemory( void ) {
+ allocPoint = 0;
+ outOfMemory = qfalse;
+}
+
+qboolean UI_OutOfMemory( void ) {
+ return outOfMemory;
+}
+
+
+
+
+
+#define HASH_TABLE_SIZE 2048
+/*
+================
+return a hash value for the string
+================
+*/
+static unsigned hashForString(const char *str) {
+ int i;
+ unsigned hash;
+ char letter;
+
+ hash = 0;
+ i = 0;
+ while (str[i] != '\0') {
+ letter = tolower(str[i]);
+ hash+=(unsigned)(letter)*(i+119);
+ i++;
+ }
+ hash &= (HASH_TABLE_SIZE-1);
+ return hash;
+}
+
+typedef struct stringDef_s {
+ struct stringDef_s *next;
+ const char *str;
+} stringDef_t;
+
+static int strPoolIndex = 0;
+static char strPool[STRING_POOL_SIZE];
+
+static int strHandleCount = 0;
+static stringDef_t *strHandle[HASH_TABLE_SIZE];
+
+
+const char *String_Alloc(const char *p) {
+ int len;
+ unsigned hash;
+ stringDef_t *str, *last;
+ static const char *staticNULL = "";
+
+ if (p == NULL) {
+ return NULL;
+ }
+
+ if (*p == 0) {
+ return staticNULL;
+ }
+
+ hash = hashForString(p);
+
+ str = strHandle[hash];
+ while (str) {
+ if (strcmp(p, str->str) == 0) {
+ return str->str;
+ }
+ str = str->next;
+ }
+
+ len = strlen(p);
+ if (len + strPoolIndex + 1 < STRING_POOL_SIZE) {
+ int ph = strPoolIndex;
+ strcpy(&strPool[strPoolIndex], p);
+ strPoolIndex += len + 1;
+
+ str = strHandle[hash];
+ last = str;
+ while (str && str->next) {
+ last = str;
+ str = str->next;
+ }
+
+ str = UI_Alloc(sizeof(stringDef_t));
+ str->next = NULL;
+ str->str = &strPool[ph];
+ if (last) {
+ last->next = str;
+ } else {
+ strHandle[hash] = str;
+ }
+ return &strPool[ph];
+ }
+ return NULL;
+}
+
+void String_Report(void) {
+ float f;
+ Com_Printf("Memory/String Pool Info\n");
+ Com_Printf("----------------\n");
+ f = strPoolIndex;
+ f /= STRING_POOL_SIZE;
+ f *= 100;
+ Com_Printf("String Pool is %.1f%% full, %i bytes out of %i used.\n", f, strPoolIndex, STRING_POOL_SIZE);
+ f = allocPoint;
+ f /= MEM_POOL_SIZE;
+ f *= 100;
+ Com_Printf("Memory Pool is %.1f%% full, %i bytes out of %i used.\n", f, allocPoint, MEM_POOL_SIZE);
+}
+
+/*
+=================
+String_Init
+=================
+*/
+void String_Init(void) {
+ int i;
+ for (i = 0; i < HASH_TABLE_SIZE; i++) {
+ strHandle[i] = NULL;
+ }
+ strHandleCount = 0;
+ strPoolIndex = 0;
+ menuCount = 0;
+ openMenuCount = 0;
+ UI_InitMemory();
+ Item_SetupKeywordHash();
+ Menu_SetupKeywordHash();
+ if (DC && DC->getBindingBuf) {
+ Controls_GetConfig();
+ }
+}
+
+/*
+=================
+PC_SourceWarning
+=================
+*/
+void PC_SourceWarning(int handle, char *format, ...) {
+ int line;
+ char filename[128];
+ va_list argptr;
+ static char string[4096];
+
+ va_start (argptr, format);
+ Q_vsnprintf (string, sizeof(string), format, argptr);
+ va_end (argptr);
+
+ filename[0] = '\0';
+ line = 0;
+ trap_PC_SourceFileAndLine(handle, filename, &line);
+
+ Com_Printf(S_COLOR_YELLOW "WARNING: %s, line %d: %s\n", filename, line, string);
+}
+
+/*
+=================
+PC_SourceError
+=================
+*/
+void PC_SourceError(int handle, char *format, ...) {
+ int line;
+ char filename[128];
+ va_list argptr;
+ static char string[4096];
+
+ va_start (argptr, format);
+ Q_vsnprintf (string, sizeof(string), format, argptr);
+ va_end (argptr);
+
+ filename[0] = '\0';
+ line = 0;
+ trap_PC_SourceFileAndLine(handle, filename, &line);
+
+ Com_Printf(S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string);
+}
+
+/*
+=================
+LerpColor
+=================
+*/
+void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)
+{
+ int i;
+
+ // lerp and clamp each component
+ for (i=0; i<4; i++)
+ {
+ c[i] = a[i] + t*(b[i]-a[i]);
+ if (c[i] < 0)
+ c[i] = 0;
+ else if (c[i] > 1.0)
+ c[i] = 1.0;
+ }
+}
+
+/*
+=================
+Float_Parse
+=================
+*/
+qboolean Float_Parse(char **p, float *f) {
+ char *token;
+ token = COM_ParseExt(p, qfalse);
+ if (token && token[0] != 0) {
+ *f = atof(token);
+ return qtrue;
+ } else {
+ return qfalse;
+ }
+}
+
+/*
+=================
+PC_Float_Parse
+=================
+*/
+qboolean PC_Float_Parse(int handle, float *f) {
+ pc_token_t token;
+ int negative = qfalse;
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+ if (token.string[0] == '-') {
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+ negative = qtrue;
+ }
+ if (token.type != TT_NUMBER) {
+ PC_SourceError(handle, "expected float but found %s\n", token.string);
+ return qfalse;
+ }
+ if (negative)
+ *f = -token.floatvalue;
+ else
+ *f = token.floatvalue;
+ return qtrue;
+}
+
+/*
+=================
+Color_Parse
+=================
+*/
+qboolean Color_Parse(char **p, vec4_t *c) {
+ int i;
+ float f;
+
+ for (i = 0; i < 4; i++) {
+ if (!Float_Parse(p, &f)) {
+ return qfalse;
+ }
+ (*c)[i] = f;
+ }
+ return qtrue;
+}
+
+/*
+=================
+PC_Color_Parse
+=================
+*/
+qboolean PC_Color_Parse(int handle, vec4_t *c) {
+ int i;
+ float f;
+
+ for (i = 0; i < 4; i++) {
+ if (!PC_Float_Parse(handle, &f)) {
+ return qfalse;
+ }
+ (*c)[i] = f;
+ }
+ return qtrue;
+}
+
+/*
+=================
+Int_Parse
+=================
+*/
+qboolean Int_Parse(char **p, int *i) {
+ char *token;
+ token = COM_ParseExt(p, qfalse);
+
+ if (token && token[0] != 0) {
+ *i = atoi(token);
+ return qtrue;
+ } else {
+ return qfalse;
+ }
+}
+
+/*
+=================
+PC_Int_Parse
+=================
+*/
+qboolean PC_Int_Parse(int handle, int *i) {
+ pc_token_t token;
+ int negative = qfalse;
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+ if (token.string[0] == '-') {
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+ negative = qtrue;
+ }
+ if (token.type != TT_NUMBER) {
+ PC_SourceError(handle, "expected integer but found %s\n", token.string);
+ return qfalse;
+ }
+ *i = token.intvalue;
+ if (negative)
+ *i = - *i;
+ return qtrue;
+}
+
+/*
+=================
+Rect_Parse
+=================
+*/
+qboolean Rect_Parse(char **p, rectDef_t *r) {
+ if (Float_Parse(p, &r->x)) {
+ if (Float_Parse(p, &r->y)) {
+ if (Float_Parse(p, &r->w)) {
+ if (Float_Parse(p, &r->h)) {
+ return qtrue;
+ }
+ }
+ }
+ }
+ return qfalse;
+}
+
+/*
+=================
+PC_Rect_Parse
+=================
+*/
+qboolean PC_Rect_Parse(int handle, rectDef_t *r) {
+ if (PC_Float_Parse(handle, &r->x)) {
+ if (PC_Float_Parse(handle, &r->y)) {
+ if (PC_Float_Parse(handle, &r->w)) {
+ if (PC_Float_Parse(handle, &r->h)) {
+ return qtrue;
+ }
+ }
+ }
+ }
+ return qfalse;
+}
+
+/*
+=================
+String_Parse
+=================
+*/
+qboolean String_Parse(char **p, const char **out) {
+ char *token;
+
+ token = COM_ParseExt(p, qfalse);
+ if (token && token[0] != 0) {
+ *(out) = String_Alloc(token);
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+=================
+PC_String_Parse
+=================
+*/
+qboolean PC_String_Parse(int handle, const char **out) {
+ pc_token_t token;
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+
+ *(out) = String_Alloc(token.string);
+ return qtrue;
+}
+
+/*
+=================
+PC_Script_Parse
+=================
+*/
+qboolean PC_Script_Parse(int handle, const char **out) {
+ char script[1024];
+ pc_token_t token;
+
+ memset(script, 0, sizeof(script));
+ // scripts start with { and have ; separated command lists.. commands are command, arg..
+ // basically we want everything between the { } as it will be interpreted at run time
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+ if (Q_stricmp(token.string, "{") != 0) {
+ return qfalse;
+ }
+
+ while ( 1 ) {
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+
+ if (Q_stricmp(token.string, "}") == 0) {
+ *out = String_Alloc(script);
+ return qtrue;
+ }
+
+ if (token.string[1] != '\0') {
+ Q_strcat(script, 1024, va("\"%s\"", token.string));
+ } else {
+ Q_strcat(script, 1024, token.string);
+ }
+ Q_strcat(script, 1024, " ");
+ }
+ return qfalse; // bk001105 - LCC missing return value
+}
+
+// display, window, menu, item code
+//
+
+/*
+==================
+Init_Display
+
+Initializes the display with a structure to all the drawing routines
+ ==================
+*/
+void Init_Display(displayContextDef_t *dc) {
+ DC = dc;
+}
+
+
+
+// type and style painting
+
+void GradientBar_Paint(rectDef_t *rect, vec4_t color) {
+ // gradient bar takes two paints
+ DC->setColor( color );
+ DC->drawHandlePic(rect->x, rect->y, rect->w, rect->h, DC->Assets.gradientBar);
+ DC->setColor( NULL );
+}
+
+
+/*
+==================
+Window_Init
+
+Initializes a window structure ( windowDef_t ) with defaults
+
+==================
+*/
+void Window_Init(Window *w) {
+ memset(w, 0, sizeof(windowDef_t));
+ w->borderSize = 1;
+ w->foreColor[0] = w->foreColor[1] = w->foreColor[2] = w->foreColor[3] = 1.0;
+ w->cinematic = -1;
+}
+
+void Fade(int *flags, float *f, float clamp, int *nextTime, int offsetTime, qboolean bFlags, float fadeAmount) {
+ if (*flags & (WINDOW_FADINGOUT | WINDOW_FADINGIN)) {
+ if (DC->realTime > *nextTime) {
+ *nextTime = DC->realTime + offsetTime;
+ if (*flags & WINDOW_FADINGOUT) {
+ *f -= fadeAmount;
+ if (bFlags && *f <= 0.0) {
+ *flags &= ~(WINDOW_FADINGOUT | WINDOW_VISIBLE);
+ }
+ } else {
+ *f += fadeAmount;
+ if (*f >= clamp) {
+ *f = clamp;
+ if (bFlags) {
+ *flags &= ~WINDOW_FADINGIN;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+void Window_Paint(Window *w, float fadeAmount, float fadeClamp, float fadeCycle) {
+ //float bordersize = 0;
+ vec4_t color;
+ rectDef_t fillRect = w->rect;
+
+
+ color[0] = color[1] = color[2] = color[3] = 1;
+ if (debugMode) {
+ DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, 1, color);
+ }
+
+ if (w == NULL || (w->style == 0 && w->border == 0)) {
+ return;
+ }
+
+ if (w->border != 0) {
+ fillRect.x += w->borderSize;
+ fillRect.y += w->borderSize;
+ fillRect.w -= w->borderSize + 1;
+ fillRect.h -= w->borderSize + 1;
+ }
+
+ if (w->style == WINDOW_STYLE_FILLED) {
+ // box, but possible a shader that needs filled
+ if (w->background) {
+ Fade(&w->flags, &w->backColor[3], fadeClamp, &w->nextTime, fadeCycle, qtrue, fadeAmount);
+ DC->setColor(w->backColor);
+ DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
+ DC->setColor(NULL);
+ } else {
+ DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->backColor);
+ }
+ } else if (w->style == WINDOW_STYLE_GRADIENT) {
+ GradientBar_Paint(&fillRect, w->backColor);
+ // gradient bar
+ } else if (w->style == WINDOW_STYLE_SHADER) {
+ if (w->flags & WINDOW_FORECOLORSET) {
+ DC->setColor(w->foreColor);
+ }
+ DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
+ DC->setColor(NULL);
+ } else if (w->style == WINDOW_STYLE_TEAMCOLOR) {
+ if (DC->getTeamColor) {
+ DC->getTeamColor(&color);
+ DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, color);
+ }
+ } else if (w->style == WINDOW_STYLE_CINEMATIC) {
+ if (w->cinematic == -1) {
+ w->cinematic = DC->playCinematic(w->cinematicName, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
+ if (w->cinematic == -1) {
+ w->cinematic = -2;
+ }
+ }
+ if (w->cinematic >= 0) {
+ DC->runCinematicFrame(w->cinematic);
+ DC->drawCinematic(w->cinematic, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
+ }
+ }
+
+ if (w->border == WINDOW_BORDER_FULL) {
+ // full
+ // HACK HACK HACK
+ if (w->style == WINDOW_STYLE_TEAMCOLOR) {
+ if (color[0] > 0) {
+ // red
+ color[0] = 1;
+ color[1] = color[2] = .5;
+
+ } else {
+ color[2] = 1;
+ color[0] = color[1] = .5;
+ }
+ color[3] = 1;
+ DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, color);
+ } else {
+ DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, w->borderColor);
+ }
+ } else if (w->border == WINDOW_BORDER_HORZ) {
+ // top/bottom
+ DC->setColor(w->borderColor);
+ DC->drawTopBottom(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
+ DC->setColor( NULL );
+ } else if (w->border == WINDOW_BORDER_VERT) {
+ // left right
+ DC->setColor(w->borderColor);
+ DC->drawSides(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
+ DC->setColor( NULL );
+ } else if (w->border == WINDOW_BORDER_KCGRADIENT) {
+ // this is just two gradient bars along each horz edge
+ rectDef_t r = w->rect;
+ r.h = w->borderSize;
+ GradientBar_Paint(&r, w->borderColor);
+ r.y = w->rect.y + w->rect.h - 1;
+ GradientBar_Paint(&r, w->borderColor);
+ }
+
+}
+
+
+void Item_SetScreenCoords(itemDef_t *item, float x, float y) {
+
+ if (item == NULL) {
+ return;
+ }
+
+ if (item->window.border != 0) {
+ x += item->window.borderSize;
+ y += item->window.borderSize;
+ }
+
+ item->window.rect.x = x + item->window.rectClient.x;
+ item->window.rect.y = y + item->window.rectClient.y;
+ item->window.rect.w = item->window.rectClient.w;
+ item->window.rect.h = item->window.rectClient.h;
+
+ // force the text rects to recompute
+ item->textRect.w = 0;
+ item->textRect.h = 0;
+}
+
+// FIXME: consolidate this with nearby stuff
+void Item_UpdatePosition(itemDef_t *item) {
+ float x, y;
+ menuDef_t *menu;
+
+ if (item == NULL || item->parent == NULL) {
+ return;
+ }
+
+ menu = item->parent;
+
+ x = menu->window.rect.x;
+ y = menu->window.rect.y;
+
+ if (menu->window.border != 0) {
+ x += menu->window.borderSize;
+ y += menu->window.borderSize;
+ }
+
+ Item_SetScreenCoords(item, x, y);
+
+}
+
+// menus
+void Menu_UpdatePosition(menuDef_t *menu) {
+ int i;
+ float x, y;
+
+ if (menu == NULL) {
+ return;
+ }
+
+ x = menu->window.rect.x;
+ y = menu->window.rect.y;
+ if (menu->window.border != 0) {
+ x += menu->window.borderSize;
+ y += menu->window.borderSize;
+ }
+
+ for (i = 0; i < menu->itemCount; i++) {
+ Item_SetScreenCoords(menu->items[i], x, y);
+ }
+}
+
+void Menu_PostParse(menuDef_t *menu) {
+ if (menu == NULL) {
+ return;
+ }
+ if (menu->fullScreen) {
+ menu->window.rect.x = 0;
+ menu->window.rect.y = 0;
+ menu->window.rect.w = 640;
+ menu->window.rect.h = 480;
+ }
+ Menu_UpdatePosition(menu);
+}
+
+itemDef_t *Menu_ClearFocus(menuDef_t *menu) {
+ int i;
+ itemDef_t *ret = NULL;
+
+ if (menu == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < menu->itemCount; i++) {
+ if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
+ ret = menu->items[i];
+ }
+ menu->items[i]->window.flags &= ~WINDOW_HASFOCUS;
+ if (menu->items[i]->leaveFocus) {
+ Item_RunScript(menu->items[i], menu->items[i]->leaveFocus);
+ }
+ }
+
+ return ret;
+}
+
+qboolean IsVisible(int flags) {
+ return (flags & WINDOW_VISIBLE && !(flags & WINDOW_FADINGOUT));
+}
+
+qboolean Rect_ContainsPoint(rectDef_t *rect, float x, float y) {
+ if (rect) {
+ if (x > rect->x && x < rect->x + rect->w && y > rect->y && y < rect->y + rect->h) {
+ return qtrue;
+ }
+ }
+ return qfalse;
+}
+
+int Menu_ItemsMatchingGroup(menuDef_t *menu, const char *name) {
+ int i;
+ int count = 0;
+ for (i = 0; i < menu->itemCount; i++) {
+ if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
+ count++;
+ }
+ }
+ return count;
+}
+
+itemDef_t *Menu_GetMatchingItemByNumber(menuDef_t *menu, int index, const char *name) {
+ int i;
+ int count = 0;
+ for (i = 0; i < menu->itemCount; i++) {
+ if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
+ if (count == index) {
+ return menu->items[i];
+ }
+ count++;
+ }
+ }
+ return NULL;
+}
+
+
+
+void Script_SetColor(itemDef_t *item, char **args) {
+ const char *name;
+ int i;
+ float f;
+ vec4_t *out;
+ // expecting type of color to set and 4 args for the color
+ if (String_Parse(args, &name)) {
+ out = NULL;
+ if (Q_stricmp(name, "backcolor") == 0) {
+ out = &item->window.backColor;
+ item->window.flags |= WINDOW_BACKCOLORSET;
+ } else if (Q_stricmp(name, "forecolor") == 0) {
+ out = &item->window.foreColor;
+ item->window.flags |= WINDOW_FORECOLORSET;
+ } else if (Q_stricmp(name, "bordercolor") == 0) {
+ out = &item->window.borderColor;
+ }
+
+ if (out) {
+ for (i = 0; i < 4; i++) {
+ if (!Float_Parse(args, &f)) {
+ return;
+ }
+ (*out)[i] = f;
+ }
+ }
+ }
+}
+
+void Script_SetAsset(itemDef_t *item, char **args) {
+ const char *name;
+ // expecting name to set asset to
+ if (String_Parse(args, &name)) {
+ // check for a model
+ if (item->type == ITEM_TYPE_MODEL) {
+ }
+ }
+}
+
+void Script_SetBackground(itemDef_t *item, char **args) {
+ const char *name;
+ // expecting name to set asset to
+ if (String_Parse(args, &name)) {
+ item->window.background = DC->registerShaderNoMip(name);
+ }
+}
+
+
+
+
+itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p) {
+ int i;
+ if (menu == NULL || p == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < menu->itemCount; i++) {
+ if (Q_stricmp(p, menu->items[i]->window.name) == 0) {
+ return menu->items[i];
+ }
+ }
+
+ return NULL;
+}
+
+void Script_SetTeamColor(itemDef_t *item, char **args) {
+ if (DC->getTeamColor) {
+ int i;
+ vec4_t color;
+ DC->getTeamColor(&color);
+ for (i = 0; i < 4; i++) {
+ item->window.backColor[i] = color[i];
+ }
+ }
+}
+
+void Script_SetItemColor(itemDef_t *item, char **args) {
+ const char *itemname;
+ const char *name;
+ vec4_t color;
+ int i;
+ vec4_t *out;
+ // expecting type of color to set and 4 args for the color
+ if (String_Parse(args, &itemname) && String_Parse(args, &name)) {
+ itemDef_t *item2;
+ int j;
+ int count = Menu_ItemsMatchingGroup(item->parent, itemname);
+
+ if (!Color_Parse(args, &color)) {
+ return;
+ }
+
+ for (j = 0; j < count; j++) {
+ item2 = Menu_GetMatchingItemByNumber(item->parent, j, itemname);
+ if (item2 != NULL) {
+ out = NULL;
+ if (Q_stricmp(name, "backcolor") == 0) {
+ out = &item2->window.backColor;
+ } else if (Q_stricmp(name, "forecolor") == 0) {
+ out = &item2->window.foreColor;
+ item2->window.flags |= WINDOW_FORECOLORSET;
+ } else if (Q_stricmp(name, "bordercolor") == 0) {
+ out = &item2->window.borderColor;
+ }
+
+ if (out) {
+ for (i = 0; i < 4; i++) {
+ (*out)[i] = color[i];
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow) {
+ itemDef_t *item;
+ int i;
+ int count = Menu_ItemsMatchingGroup(menu, p);
+ for (i = 0; i < count; i++) {
+ item = Menu_GetMatchingItemByNumber(menu, i, p);
+ if (item != NULL) {
+ if (bShow) {
+ item->window.flags |= WINDOW_VISIBLE;
+ } else {
+ item->window.flags &= ~WINDOW_VISIBLE;
+ // stop cinematics playing in the window
+ if (item->window.cinematic >= 0) {
+ DC->stopCinematic(item->window.cinematic);
+ item->window.cinematic = -1;
+ }
+ }
+ }
+ }
+}
+
+void Menu_FadeItemByName(menuDef_t *menu, const char *p, qboolean fadeOut) {
+ itemDef_t *item;
+ int i;
+ int count = Menu_ItemsMatchingGroup(menu, p);
+ for (i = 0; i < count; i++) {
+ item = Menu_GetMatchingItemByNumber(menu, i, p);
+ if (item != NULL) {
+ if (fadeOut) {
+ item->window.flags |= (WINDOW_FADINGOUT | WINDOW_VISIBLE);
+ item->window.flags &= ~WINDOW_FADINGIN;
+ } else {
+ item->window.flags |= (WINDOW_VISIBLE | WINDOW_FADINGIN);
+ item->window.flags &= ~WINDOW_FADINGOUT;
+ }
+ }
+ }
+}
+
+menuDef_t *Menus_FindByName(const char *p) {
+ int i;
+ for (i = 0; i < menuCount; i++) {
+ if (Q_stricmp(Menus[i].window.name, p) == 0) {
+ return &Menus[i];
+ }
+ }
+ return NULL;
+}
+
+void Menus_ShowByName(const char *p) {
+ menuDef_t *menu = Menus_FindByName(p);
+ if (menu) {
+ Menus_Activate(menu);
+ }
+}
+
+void Menus_OpenByName(const char *p) {
+ Menus_ActivateByName(p);
+}
+
+static void Menu_RunCloseScript(menuDef_t *menu) {
+ if (menu && menu->window.flags & WINDOW_VISIBLE && menu->onClose) {
+ itemDef_t item;
+ item.parent = menu;
+ Item_RunScript(&item, menu->onClose);
+ }
+}
+
+void Menus_CloseByName(const char *p) {
+ menuDef_t *menu = Menus_FindByName(p);
+ if (menu != NULL) {
+ Menu_RunCloseScript(menu);
+ menu->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS);
+ }
+}
+
+void Menus_CloseAll(void) {
+ int i;
+ for (i = 0; i < menuCount; i++) {
+ Menu_RunCloseScript(&Menus[i]);
+ Menus[i].window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
+ }
+}
+
+
+void Script_Show(itemDef_t *item, char **args) {
+ const char *name;
+ if (String_Parse(args, &name)) {
+ Menu_ShowItemByName(item->parent, name, qtrue);
+ }
+}
+
+void Script_Hide(itemDef_t *item, char **args) {
+ const char *name;
+ if (String_Parse(args, &name)) {
+ Menu_ShowItemByName(item->parent, name, qfalse);
+ }
+}
+
+void Script_FadeIn(itemDef_t *item, char **args) {
+ const char *name;
+ if (String_Parse(args, &name)) {
+ Menu_FadeItemByName(item->parent, name, qfalse);
+ }
+}
+
+void Script_FadeOut(itemDef_t *item, char **args) {
+ const char *name;
+ if (String_Parse(args, &name)) {
+ Menu_FadeItemByName(item->parent, name, qtrue);
+ }
+}
+
+
+
+void Script_Open(itemDef_t *item, char **args) {
+ const char *name;
+ if (String_Parse(args, &name)) {
+ Menus_OpenByName(name);
+ }
+}
+
+void Script_ConditionalOpen(itemDef_t *item, char **args) {
+ const char *cvar;
+ const char *name1;
+ const char *name2;
+ float val;
+
+ if ( String_Parse(args, &cvar) && String_Parse(args, &name1) && String_Parse(args, &name2) ) {
+ val = DC->getCVarValue( cvar );
+ if ( val == 0.f ) {
+ Menus_OpenByName(name2);
+ } else {
+ Menus_OpenByName(name1);
+ }
+ }
+}
+
+void Script_Close(itemDef_t *item, char **args) {
+ const char *name;
+ if (String_Parse(args, &name)) {
+ Menus_CloseByName(name);
+ }
+}
+
+void Menu_TransitionItemByName(menuDef_t *menu, const char *p, rectDef_t rectFrom, rectDef_t rectTo, int time, float amt) {
+ itemDef_t *item;
+ int i;
+ int count = Menu_ItemsMatchingGroup(menu, p);
+ for (i = 0; i < count; i++) {
+ item = Menu_GetMatchingItemByNumber(menu, i, p);
+ if (item != NULL) {
+ item->window.flags |= (WINDOW_INTRANSITION | WINDOW_VISIBLE);
+ item->window.offsetTime = time;
+ memcpy(&item->window.rectClient, &rectFrom, sizeof(rectDef_t));
+ memcpy(&item->window.rectEffects, &rectTo, sizeof(rectDef_t));
+ item->window.rectEffects2.x = abs(rectTo.x - rectFrom.x) / amt;
+ item->window.rectEffects2.y = abs(rectTo.y - rectFrom.y) / amt;
+ item->window.rectEffects2.w = abs(rectTo.w - rectFrom.w) / amt;
+ item->window.rectEffects2.h = abs(rectTo.h - rectFrom.h) / amt;
+ Item_UpdatePosition(item);
+ }
+ }
+}
+
+
+void Script_Transition(itemDef_t *item, char **args) {
+ const char *name;
+ rectDef_t rectFrom, rectTo;
+ int time;
+ float amt;
+
+ if (String_Parse(args, &name)) {
+ if ( Rect_Parse(args, &rectFrom) && Rect_Parse(args, &rectTo) && Int_Parse(args, &time) && Float_Parse(args, &amt)) {
+ Menu_TransitionItemByName(item->parent, name, rectFrom, rectTo, time, amt);
+ }
+ }
+}
+
+
+void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, float cx, float cy, int time) {
+ itemDef_t *item;
+ int i;
+ int count = Menu_ItemsMatchingGroup(menu, p);
+ for (i = 0; i < count; i++) {
+ item = Menu_GetMatchingItemByNumber(menu, i, p);
+ if (item != NULL) {
+ item->window.flags |= (WINDOW_ORBITING | WINDOW_VISIBLE);
+ item->window.offsetTime = time;
+ item->window.rectEffects.x = cx;
+ item->window.rectEffects.y = cy;
+ item->window.rectClient.x = x;
+ item->window.rectClient.y = y;
+ Item_UpdatePosition(item);
+ }
+ }
+}
+
+
+void Script_Orbit(itemDef_t *item, char **args) {
+ const char *name;
+ float cx, cy, x, y;
+ int time;
+
+ if (String_Parse(args, &name)) {
+ if ( Float_Parse(args, &x) && Float_Parse(args, &y) && Float_Parse(args, &cx) && Float_Parse(args, &cy) && Int_Parse(args, &time) ) {
+ Menu_OrbitItemByName(item->parent, name, x, y, cx, cy, time);
+ }
+ }
+}
+
+
+
+void Script_SetFocus(itemDef_t *item, char **args) {
+ const char *name;
+ itemDef_t *focusItem;
+
+ if (String_Parse(args, &name)) {
+ focusItem = Menu_FindItemByName(item->parent, name);
+ if (focusItem && !(focusItem->window.flags & WINDOW_DECORATION) && !(focusItem->window.flags & WINDOW_HASFOCUS)) {
+ Menu_ClearFocus(item->parent);
+ focusItem->window.flags |= WINDOW_HASFOCUS;
+ if (focusItem->onFocus) {
+ Item_RunScript(focusItem, focusItem->onFocus);
+ }
+ if (DC->Assets.itemFocusSound) {
+ DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND );
+ }
+ }
+ }
+}
+
+void Script_SetPlayerModel(itemDef_t *item, char **args) {
+ const char *name;
+ if (String_Parse(args, &name)) {
+ DC->setCVar("team_model", name);
+ }
+}
+
+void Script_SetPlayerHead(itemDef_t *item, char **args) {
+ const char *name;
+ if (String_Parse(args, &name)) {
+ DC->setCVar("team_headmodel", name);
+ }
+}
+
+void Script_SetCvar(itemDef_t *item, char **args) {
+ const char *cvar, *val;
+ if (String_Parse(args, &cvar) && String_Parse(args, &val)) {
+ DC->setCVar(cvar, val);
+ }
+
+}
+
+void Script_Exec(itemDef_t *item, char **args) {
+ const char *val;
+ if (String_Parse(args, &val)) {
+ DC->executeText(EXEC_APPEND, va("%s ; ", val));
+ }
+}
+
+void Script_Play(itemDef_t *item, char **args) {
+ const char *val;
+ if (String_Parse(args, &val)) {
+ DC->startLocalSound(DC->registerSound(val, qfalse), CHAN_LOCAL_SOUND);
+ }
+}
+
+void Script_playLooped(itemDef_t *item, char **args) {
+ const char *val;
+ if (String_Parse(args, &val)) {
+ DC->stopBackgroundTrack();
+ DC->startBackgroundTrack(val, val);
+ }
+}
+
+
+commandDef_t commandList[] =
+{
+ {"fadein", &Script_FadeIn}, // group/name
+ {"fadeout", &Script_FadeOut}, // group/name
+ {"show", &Script_Show}, // group/name
+ {"hide", &Script_Hide}, // group/name
+ {"setcolor", &Script_SetColor}, // works on this
+ {"open", &Script_Open}, // menu
+ {"conditionalopen", &Script_ConditionalOpen}, // menu
+ {"close", &Script_Close}, // menu
+ {"setasset", &Script_SetAsset}, // works on this
+ {"setbackground", &Script_SetBackground}, // works on this
+ {"setitemcolor", &Script_SetItemColor}, // group/name
+ {"setteamcolor", &Script_SetTeamColor}, // sets this background color to team color
+ {"setfocus", &Script_SetFocus}, // sets this background color to team color
+ {"setplayermodel", &Script_SetPlayerModel}, // sets this background color to team color
+ {"setplayerhead", &Script_SetPlayerHead}, // sets this background color to team color
+ {"transition", &Script_Transition}, // group/name
+ {"setcvar", &Script_SetCvar}, // group/name
+ {"exec", &Script_Exec}, // group/name
+ {"play", &Script_Play}, // group/name
+ {"playlooped", &Script_playLooped}, // group/name
+ {"orbit", &Script_Orbit} // group/name
+};
+
+int scriptCommandCount = sizeof(commandList) / sizeof(commandDef_t);
+
+
+void Item_RunScript(itemDef_t *item, const char *s) {
+ char script[1024], *p;
+ int i;
+ qboolean bRan;
+ memset(script, 0, sizeof(script));
+ if (item && s && s[0]) {
+ Q_strcat(script, 1024, s);
+ p = script;
+ while (1) {
+ const char *command;
+ // expect command then arguments, ; ends command, NULL ends script
+ if (!String_Parse(&p, &command)) {
+ return;
+ }
+
+ if (command[0] == ';' && command[1] == '\0') {
+ continue;
+ }
+
+ bRan = qfalse;
+ for (i = 0; i < scriptCommandCount; i++) {
+ if (Q_stricmp(command, commandList[i].name) == 0) {
+ (commandList[i].handler(item, &p));
+ bRan = qtrue;
+ break;
+ }
+ }
+ // not in our auto list, pass to handler
+ if (!bRan) {
+ DC->runScript(&p);
+ }
+ }
+ }
+}
+
+
+qboolean Item_EnableShowViaCvar(itemDef_t *item, int flag) {
+ char script[1024], *p;
+ memset(script, 0, sizeof(script));
+ if (item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
+ char buff[1024];
+ DC->getCVarString(item->cvarTest, buff, sizeof(buff));
+
+ Q_strcat(script, 1024, item->enableCvar);
+ p = script;
+ while (1) {
+ const char *val;
+ // expect value then ; or NULL, NULL ends list
+ if (!String_Parse(&p, &val)) {
+ return (item->cvarFlags & flag) ? qfalse : qtrue;
+ }
+
+ if (val[0] == ';' && val[1] == '\0') {
+ continue;
+ }
+
+ // enable it if any of the values are true
+ if (item->cvarFlags & flag) {
+ if (Q_stricmp(buff, val) == 0) {
+ return qtrue;
+ }
+ } else {
+ // disable it if any of the values are true
+ if (Q_stricmp(buff, val) == 0) {
+ return qfalse;
+ }
+ }
+
+ }
+ return (item->cvarFlags & flag) ? qfalse : qtrue;
+ }
+ return qtrue;
+}
+
+
+// will optionaly set focus to this item
+qboolean Item_SetFocus(itemDef_t *item, float x, float y) {
+ int i;
+ itemDef_t *oldFocus;
+ sfxHandle_t *sfx = &DC->Assets.itemFocusSound;
+ qboolean playSound = qfalse;
+ menuDef_t *parent; // bk001206: = (menuDef_t*)item->parent;
+ // sanity check, non-null, not a decoration and does not already have the focus
+ if (item == NULL || item->window.flags & WINDOW_DECORATION || item->window.flags & WINDOW_HASFOCUS || !(item->window.flags & WINDOW_VISIBLE)) {
+ return qfalse;
+ }
+
+ // bk001206 - this can be NULL.
+ parent = (menuDef_t*)item->parent;
+
+ // items can be enabled and disabled based on cvars
+ if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
+ return qfalse;
+ }
+
+ if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
+ return qfalse;
+ }
+
+ oldFocus = Menu_ClearFocus(item->parent);
+
+ if (item->type == ITEM_TYPE_TEXT) {
+ rectDef_t r;
+ r = item->textRect;
+ r.y -= r.h;
+ if (Rect_ContainsPoint(&r, x, y)) {
+ item->window.flags |= WINDOW_HASFOCUS;
+ if (item->focusSound) {
+ sfx = &item->focusSound;
+ }
+ playSound = qtrue;
+ } else {
+ if (oldFocus) {
+ oldFocus->window.flags |= WINDOW_HASFOCUS;
+ if (oldFocus->onFocus) {
+ Item_RunScript(oldFocus, oldFocus->onFocus);
+ }
+ }
+ }
+ } else {
+ item->window.flags |= WINDOW_HASFOCUS;
+ if (item->onFocus) {
+ Item_RunScript(item, item->onFocus);
+ }
+ if (item->focusSound) {
+ sfx = &item->focusSound;
+ }
+ playSound = qtrue;
+ }
+
+ if (playSound && sfx) {
+ DC->startLocalSound( *sfx, CHAN_LOCAL_SOUND );
+ }
+
+ for (i = 0; i < parent->itemCount; i++) {
+ if (parent->items[i] == item) {
+ parent->cursorItem = i;
+ break;
+ }
+ }
+
+ return qtrue;
+}
+
+int Item_ListBox_MaxScroll(itemDef_t *item) {
+ listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
+ int count = DC->feederCount(item->special);
+ int max;
+
+ if (item->window.flags & WINDOW_HORIZONTAL) {
+ max = count - (item->window.rect.w / listPtr->elementWidth) + 1;
+ }
+ else {
+ max = count - (item->window.rect.h / listPtr->elementHeight) + 1;
+ }
+ if (max < 0) {
+ return 0;
+ }
+ return max;
+}
+
+int Item_ListBox_ThumbPosition(itemDef_t *item) {
+ float max, pos, size;
+ listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
+
+ max = Item_ListBox_MaxScroll(item);
+ if (item->window.flags & WINDOW_HORIZONTAL) {
+ size = item->window.rect.w - (SCROLLBAR_SIZE * 2) - 2;
+ if (max > 0) {
+ pos = (size-SCROLLBAR_SIZE) / (float) max;
+ } else {
+ pos = 0;
+ }
+ pos *= listPtr->startPos;
+ return item->window.rect.x + 1 + SCROLLBAR_SIZE + pos;
+ }
+ else {
+ size = item->window.rect.h - (SCROLLBAR_SIZE * 2) - 2;
+ if (max > 0) {
+ pos = (size-SCROLLBAR_SIZE) / (float) max;
+ } else {
+ pos = 0;
+ }
+ pos *= listPtr->startPos;
+ return item->window.rect.y + 1 + SCROLLBAR_SIZE + pos;
+ }
+}
+
+int Item_ListBox_ThumbDrawPosition(itemDef_t *item) {
+ int min, max;
+
+ if (itemCapture == item) {
+ if (item->window.flags & WINDOW_HORIZONTAL) {
+ min = item->window.rect.x + SCROLLBAR_SIZE + 1;
+ max = item->window.rect.x + item->window.rect.w - 2*SCROLLBAR_SIZE - 1;
+ if (DC->cursorx >= min + SCROLLBAR_SIZE/2 && DC->cursorx <= max + SCROLLBAR_SIZE/2) {
+ return DC->cursorx - SCROLLBAR_SIZE/2;
+ }
+ else {
+ return Item_ListBox_ThumbPosition(item);
+ }
+ }
+ else {
+ min = item->window.rect.y + SCROLLBAR_SIZE + 1;
+ max = item->window.rect.y + item->window.rect.h - 2*SCROLLBAR_SIZE - 1;
+ if (DC->cursory >= min + SCROLLBAR_SIZE/2 && DC->cursory <= max + SCROLLBAR_SIZE/2) {
+ return DC->cursory - SCROLLBAR_SIZE/2;
+ }
+ else {
+ return Item_ListBox_ThumbPosition(item);
+ }
+ }
+ }
+ else {
+ return Item_ListBox_ThumbPosition(item);
+ }
+}
+
+float Item_Slider_ThumbPosition(itemDef_t *item) {
+ float value, range, x;
+ editFieldDef_t *editDef = item->typeData;
+
+ if (item->text) {
+ x = item->textRect.x + item->textRect.w + 8;
+ } else {
+ x = item->window.rect.x;
+ }
+
+ if (editDef == NULL && item->cvar) {
+ return x;
+ }
+
+ value = DC->getCVarValue(item->cvar);
+
+ if (value < editDef->minVal) {
+ value = editDef->minVal;
+ } else if (value > editDef->maxVal) {
+ value = editDef->maxVal;
+ }
+
+ range = editDef->maxVal - editDef->minVal;
+ value -= editDef->minVal;
+ value /= range;
+ //value /= (editDef->maxVal - editDef->minVal);
+ value *= SLIDER_WIDTH;
+ x += value;
+ // vm fuckage
+ //x = x + (((float)value / editDef->maxVal) * SLIDER_WIDTH);
+ return x;
+}
+
+int Item_Slider_OverSlider(itemDef_t *item, float x, float y) {
+ rectDef_t r;
+
+ r.x = Item_Slider_ThumbPosition(item) - (SLIDER_THUMB_WIDTH / 2);
+ r.y = item->window.rect.y - 2;
+ r.w = SLIDER_THUMB_WIDTH;
+ r.h = SLIDER_THUMB_HEIGHT;
+
+ if (Rect_ContainsPoint(&r, x, y)) {
+ return WINDOW_LB_THUMB;
+ }
+ return 0;
+}
+
+int Item_ListBox_OverLB(itemDef_t *item, float x, float y) {
+ rectDef_t r;
+ listBoxDef_t *listPtr;
+ int thumbstart;
+ int count;
+
+ count = DC->feederCount(item->special);
+ listPtr = (listBoxDef_t*)item->typeData;
+ if (item->window.flags & WINDOW_HORIZONTAL) {
+ // check if on left arrow
+ r.x = item->window.rect.x;
+ r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
+ r.h = r.w = SCROLLBAR_SIZE;
+ if (Rect_ContainsPoint(&r, x, y)) {
+ return WINDOW_LB_LEFTARROW;
+ }
+ // check if on right arrow
+ r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
+ if (Rect_ContainsPoint(&r, x, y)) {
+ return WINDOW_LB_RIGHTARROW;
+ }
+ // check if on thumb
+ thumbstart = Item_ListBox_ThumbPosition(item);
+ r.x = thumbstart;
+ if (Rect_ContainsPoint(&r, x, y)) {
+ return WINDOW_LB_THUMB;
+ }
+ r.x = item->window.rect.x + SCROLLBAR_SIZE;
+ r.w = thumbstart - r.x;
+ if (Rect_ContainsPoint(&r, x, y)) {
+ return WINDOW_LB_PGUP;
+ }
+ r.x = thumbstart + SCROLLBAR_SIZE;
+ r.w = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
+ if (Rect_ContainsPoint(&r, x, y)) {
+ return WINDOW_LB_PGDN;
+ }
+ } else {
+ r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
+ r.y = item->window.rect.y;
+ r.h = r.w = SCROLLBAR_SIZE;
+ if (Rect_ContainsPoint(&r, x, y)) {
+ return WINDOW_LB_LEFTARROW;
+ }
+ r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
+ if (Rect_ContainsPoint(&r, x, y)) {
+ return WINDOW_LB_RIGHTARROW;
+ }
+ thumbstart = Item_ListBox_ThumbPosition(item);
+ r.y = thumbstart;
+ if (Rect_ContainsPoint(&r, x, y)) {
+ return WINDOW_LB_THUMB;
+ }
+ r.y = item->window.rect.y + SCROLLBAR_SIZE;
+ r.h = thumbstart - r.y;
+ if (Rect_ContainsPoint(&r, x, y)) {
+ return WINDOW_LB_PGUP;
+ }
+ r.y = thumbstart + SCROLLBAR_SIZE;
+ r.h = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
+ if (Rect_ContainsPoint(&r, x, y)) {
+ return WINDOW_LB_PGDN;
+ }
+ }
+ return 0;
+}
+
+
+void Item_ListBox_MouseEnter(itemDef_t *item, float x, float y)
+{
+ rectDef_t r;
+ listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
+
+ item->window.flags &= ~(WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN);
+ item->window.flags |= Item_ListBox_OverLB(item, x, y);
+
+ if (item->window.flags & WINDOW_HORIZONTAL) {
+ if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
+ // check for selection hit as we have exausted buttons and thumb
+ if (listPtr->elementStyle == LISTBOX_IMAGE) {
+ r.x = item->window.rect.x;
+ r.y = item->window.rect.y;
+ r.h = item->window.rect.h - SCROLLBAR_SIZE;
+ r.w = item->window.rect.w - listPtr->drawPadding;
+ if (Rect_ContainsPoint(&r, x, y)) {
+ listPtr->cursorPos = (int)((x - r.x) / listPtr->elementWidth) + listPtr->startPos;
+ if (listPtr->cursorPos >= listPtr->endPos) {
+ listPtr->cursorPos = listPtr->endPos;
+ }
+ }
+ } else {
+ // text hit..
+ }
+ }
+ } else if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
+ r.x = item->window.rect.x;
+ r.y = item->window.rect.y;
+ r.w = item->window.rect.w - SCROLLBAR_SIZE;
+ r.h = item->window.rect.h - listPtr->drawPadding;
+ if (Rect_ContainsPoint(&r, x, y)) {
+ listPtr->cursorPos = (int)((y - 2 - r.y) / listPtr->elementHeight) + listPtr->startPos;
+ if (listPtr->cursorPos > listPtr->endPos) {
+ listPtr->cursorPos = listPtr->endPos;
+ }
+ }
+ }
+}
+
+void Item_MouseEnter(itemDef_t *item, float x, float y) {
+ rectDef_t r;
+ if (item) {
+ r = item->textRect;
+ r.y -= r.h;
+ // in the text rect?
+
+ // items can be enabled and disabled based on cvars
+ if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
+ return;
+ }
+
+ if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
+ return;
+ }
+
+ if (Rect_ContainsPoint(&r, x, y)) {
+ if (!(item->window.flags & WINDOW_MOUSEOVERTEXT)) {
+ Item_RunScript(item, item->mouseEnterText);
+ item->window.flags |= WINDOW_MOUSEOVERTEXT;
+ }
+ if (!(item->window.flags & WINDOW_MOUSEOVER)) {
+ Item_RunScript(item, item->mouseEnter);
+ item->window.flags |= WINDOW_MOUSEOVER;
+ }
+
+ } else {
+ // not in the text rect
+ if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
+ // if we were
+ Item_RunScript(item, item->mouseExitText);
+ item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
+ }
+ if (!(item->window.flags & WINDOW_MOUSEOVER)) {
+ Item_RunScript(item, item->mouseEnter);
+ item->window.flags |= WINDOW_MOUSEOVER;
+ }
+
+ if (item->type == ITEM_TYPE_LISTBOX) {
+ Item_ListBox_MouseEnter(item, x, y);
+ }
+ }
+ }
+}
+
+void Item_MouseLeave(itemDef_t *item) {
+ if (item) {
+ if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
+ Item_RunScript(item, item->mouseExitText);
+ item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
+ }
+ Item_RunScript(item, item->mouseExit);
+ item->window.flags &= ~(WINDOW_LB_RIGHTARROW | WINDOW_LB_LEFTARROW);
+ }
+}
+
+itemDef_t *Menu_HitTest(menuDef_t *menu, float x, float y) {
+ int i;
+ for (i = 0; i < menu->itemCount; i++) {
+ if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
+ return menu->items[i];
+ }
+ }
+ return NULL;
+}
+
+void Item_SetMouseOver(itemDef_t *item, qboolean focus) {
+ if (item) {
+ if (focus) {
+ item->window.flags |= WINDOW_MOUSEOVER;
+ } else {
+ item->window.flags &= ~WINDOW_MOUSEOVER;
+ }
+ }
+}
+
+
+qboolean Item_OwnerDraw_HandleKey(itemDef_t *item, int key) {
+ if (item && DC->ownerDrawHandleKey) {
+ return DC->ownerDrawHandleKey(item->window.ownerDraw, item->window.ownerDrawFlags, &item->special, key);
+ }
+ return qfalse;
+}
+
+qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolean force) {
+ listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
+ int count = DC->feederCount(item->special);
+ int max, viewmax;
+
+ if (force || (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS)) {
+ max = Item_ListBox_MaxScroll(item);
+ if (item->window.flags & WINDOW_HORIZONTAL) {
+ viewmax = (item->window.rect.w / listPtr->elementWidth);
+ if ( key == K_LEFTARROW )
+ {
+ if (!listPtr->notselectable) {
+ listPtr->cursorPos--;
+ if (listPtr->cursorPos < 0) {
+ listPtr->cursorPos = 0;
+ }
+ if (listPtr->cursorPos < listPtr->startPos) {
+ listPtr->startPos = listPtr->cursorPos;
+ }
+ if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
+ listPtr->startPos = listPtr->cursorPos - viewmax + 1;
+ }
+ item->cursorPos = listPtr->cursorPos;
+ DC->feederSelection(item->special, item->cursorPos);
+ }
+ else {
+ listPtr->startPos--;
+ if (listPtr->startPos < 0)
+ listPtr->startPos = 0;
+ }
+ return qtrue;
+ }
+ if ( key == K_RIGHTARROW )
+ {
+ if (!listPtr->notselectable) {
+ listPtr->cursorPos++;
+ if (listPtr->cursorPos < listPtr->startPos) {
+ listPtr->startPos = listPtr->cursorPos;
+ }
+ if (listPtr->cursorPos >= count) {
+ listPtr->cursorPos = count-1;
+ }
+ if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
+ listPtr->startPos = listPtr->cursorPos - viewmax + 1;
+ }
+ item->cursorPos = listPtr->cursorPos;
+ DC->feederSelection(item->special, item->cursorPos);
+ }
+ else {
+ listPtr->startPos++;
+ if (listPtr->startPos >= count)
+ listPtr->startPos = count-1;
+ }
+ return qtrue;
+ }
+ }
+ else {
+ viewmax = (item->window.rect.h / listPtr->elementHeight);
+ if ( key == K_UPARROW )
+ {
+ if (!listPtr->notselectable) {
+ listPtr->cursorPos--;
+ if (listPtr->cursorPos < 0) {
+ listPtr->cursorPos = 0;
+ }
+ if (listPtr->cursorPos < listPtr->startPos) {
+ listPtr->startPos = listPtr->cursorPos;
+ }
+ if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
+ listPtr->startPos = listPtr->cursorPos - viewmax + 1;
+ }
+ item->cursorPos = listPtr->cursorPos;
+ DC->feederSelection(item->special, item->cursorPos);
+ }
+ else {
+ listPtr->startPos--;
+ if (listPtr->startPos < 0)
+ listPtr->startPos = 0;
+ }
+ return qtrue;
+ }
+ if ( key == K_DOWNARROW )
+ {
+ if (!listPtr->notselectable) {
+ listPtr->cursorPos++;
+ if (listPtr->cursorPos < listPtr->startPos) {
+ listPtr->startPos = listPtr->cursorPos;
+ }
+ if (listPtr->cursorPos >= count) {
+ listPtr->cursorPos = count-1;
+ }
+ if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
+ listPtr->startPos = listPtr->cursorPos - viewmax + 1;
+ }
+ item->cursorPos = listPtr->cursorPos;
+ DC->feederSelection(item->special, item->cursorPos);
+ }
+ else {
+ listPtr->startPos++;
+ if (listPtr->startPos > max)
+ listPtr->startPos = max;
+ }
+ return qtrue;
+ }
+ }
+ // mouse hit
+ if (key == K_MOUSE1 || key == K_MOUSE2) {
+ if (item->window.flags & WINDOW_LB_LEFTARROW) {
+ listPtr->startPos--;
+ if (listPtr->startPos < 0) {
+ listPtr->startPos = 0;
+ }
+ } else if (item->window.flags & WINDOW_LB_RIGHTARROW) {
+ // one down
+ listPtr->startPos++;
+ if (listPtr->startPos > max) {
+ listPtr->startPos = max;
+ }
+ } else if (item->window.flags & WINDOW_LB_PGUP) {
+ // page up
+ listPtr->startPos -= viewmax;
+ if (listPtr->startPos < 0) {
+ listPtr->startPos = 0;
+ }
+ } else if (item->window.flags & WINDOW_LB_PGDN) {
+ // page down
+ listPtr->startPos += viewmax;
+ if (listPtr->startPos > max) {
+ listPtr->startPos = max;
+ }
+ } else if (item->window.flags & WINDOW_LB_THUMB) {
+ // Display_SetCaptureItem(item);
+ } else {
+ // select an item
+ if (DC->realTime < lastListBoxClickTime && listPtr->doubleClick) {
+ Item_RunScript(item, listPtr->doubleClick);
+ }
+ lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY;
+ if (item->cursorPos != listPtr->cursorPos) {
+ item->cursorPos = listPtr->cursorPos;
+ DC->feederSelection(item->special, item->cursorPos);
+ }
+ }
+ return qtrue;
+ }
+ if ( key == K_HOME ) {
+ // home
+ listPtr->startPos = 0;
+ return qtrue;
+ }
+ if ( key == K_END ) {
+ // end
+ listPtr->startPos = max;
+ return qtrue;
+ }
+ if (key == K_PGUP ) {
+ // page up
+ if (!listPtr->notselectable) {
+ listPtr->cursorPos -= viewmax;
+ if (listPtr->cursorPos < 0) {
+ listPtr->cursorPos = 0;
+ }
+ if (listPtr->cursorPos < listPtr->startPos) {
+ listPtr->startPos = listPtr->cursorPos;
+ }
+ if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
+ listPtr->startPos = listPtr->cursorPos - viewmax + 1;
+ }
+ item->cursorPos = listPtr->cursorPos;
+ DC->feederSelection(item->special, item->cursorPos);
+ }
+ else {
+ listPtr->startPos -= viewmax;
+ if (listPtr->startPos < 0) {
+ listPtr->startPos = 0;
+ }
+ }
+ return qtrue;
+ }
+ if ( key == K_PGDN ) {
+ // page down
+ if (!listPtr->notselectable) {
+ listPtr->cursorPos += viewmax;
+ if (listPtr->cursorPos < listPtr->startPos) {
+ listPtr->startPos = listPtr->cursorPos;
+ }
+ if (listPtr->cursorPos >= count) {
+ listPtr->cursorPos = count-1;
+ }
+ if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
+ listPtr->startPos = listPtr->cursorPos - viewmax + 1;
+ }
+ item->cursorPos = listPtr->cursorPos;
+ DC->feederSelection(item->special, item->cursorPos);
+ }
+ else {
+ listPtr->startPos += viewmax;
+ if (listPtr->startPos > max) {
+ listPtr->startPos = max;
+ }
+ }
+ return qtrue;
+ }
+ }
+ return qfalse;
+}
+
+qboolean Item_YesNo_HandleKey(itemDef_t *item, int key) {
+
+ if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
+ if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
+ DC->setCVar(item->cvar, va("%i", !DC->getCVarValue(item->cvar)));
+ return qtrue;
+ }
+ }
+
+ return qfalse;
+
+}
+
+int Item_Multi_CountSettings(itemDef_t *item) {
+ multiDef_t *multiPtr = (multiDef_t*)item->typeData;
+ if (multiPtr == NULL) {
+ return 0;
+ }
+ return multiPtr->count;
+}
+
+int Item_Multi_FindCvarByValue(itemDef_t *item) {
+ char buff[1024];
+ float value = 0;
+ int i;
+ multiDef_t *multiPtr = (multiDef_t*)item->typeData;
+ if (multiPtr) {
+ if (multiPtr->strDef) {
+ DC->getCVarString(item->cvar, buff, sizeof(buff));
+ } else {
+ value = DC->getCVarValue(item->cvar);
+ }
+ for (i = 0; i < multiPtr->count; i++) {
+ if (multiPtr->strDef) {
+ if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
+ return i;
+ }
+ } else {
+ if (multiPtr->cvarValue[i] == value) {
+ return i;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+const char *Item_Multi_Setting(itemDef_t *item) {
+ char buff[1024];
+ float value = 0;
+ int i;
+ multiDef_t *multiPtr = (multiDef_t*)item->typeData;
+ if (multiPtr) {
+ if (multiPtr->strDef) {
+ DC->getCVarString(item->cvar, buff, sizeof(buff));
+ } else {
+ value = DC->getCVarValue(item->cvar);
+ }
+ for (i = 0; i < multiPtr->count; i++) {
+ if (multiPtr->strDef) {
+ if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
+ return multiPtr->cvarList[i];
+ }
+ } else {
+ if (multiPtr->cvarValue[i] == value) {
+ return multiPtr->cvarList[i];
+ }
+ }
+ }
+ }
+ return "";
+}
+
+qboolean Item_Multi_HandleKey(itemDef_t *item, int key) {
+ multiDef_t *multiPtr = (multiDef_t*)item->typeData;
+ if (multiPtr) {
+ if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
+ if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
+ int current = Item_Multi_FindCvarByValue(item) + 1;
+ int max = Item_Multi_CountSettings(item);
+ if ( current < 0 || current >= max ) {
+ current = 0;
+ }
+ if (multiPtr->strDef) {
+ DC->setCVar(item->cvar, multiPtr->cvarStr[current]);
+ } else {
+ float value = multiPtr->cvarValue[current];
+ if (((float)((int) value)) == value) {
+ DC->setCVar(item->cvar, va("%i", (int) value ));
+ }
+ else {
+ DC->setCVar(item->cvar, va("%f", value ));
+ }
+ }
+ return qtrue;
+ }
+ }
+ }
+ return qfalse;
+}
+
+qboolean Item_TextField_HandleKey(itemDef_t *item, int key) {
+ char buff[1024];
+ int len;
+ itemDef_t *newItem = NULL;
+ editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
+
+ if (item->cvar) {
+
+ memset(buff, 0, sizeof(buff));
+ DC->getCVarString(item->cvar, buff, sizeof(buff));
+ len = strlen(buff);
+ if (editPtr->maxChars && len > editPtr->maxChars) {
+ len = editPtr->maxChars;
+ }
+ if ( key & K_CHAR_FLAG ) {
+ key &= ~K_CHAR_FLAG;
+
+
+ if (key == 'h' - 'a' + 1 ) { // ctrl-h is backspace
+ if ( item->cursorPos > 0 ) {
+ memmove( &buff[item->cursorPos - 1], &buff[item->cursorPos], len + 1 - item->cursorPos);
+ item->cursorPos--;
+ if (item->cursorPos < editPtr->paintOffset) {
+ editPtr->paintOffset--;
+ }
+ }
+ DC->setCVar(item->cvar, buff);
+ return qtrue;
+ }
+
+
+ //
+ // ignore any non printable chars
+ //
+ if ( key < 32 || !item->cvar) {
+ return qtrue;
+ }
+
+ if (item->type == ITEM_TYPE_NUMERICFIELD) {
+ if (key < '0' || key > '9') {
+ return qfalse;
+ }
+ }
+
+ if (!DC->getOverstrikeMode()) {
+ if (( len == MAX_EDITFIELD - 1 ) || (editPtr->maxChars && len >= editPtr->maxChars)) {
+ return qtrue;
+ }
+ memmove( &buff[item->cursorPos + 1], &buff[item->cursorPos], len + 1 - item->cursorPos );
+ } else {
+ if (editPtr->maxChars && item->cursorPos >= editPtr->maxChars) {
+ return qtrue;
+ }
+ }
+
+ buff[item->cursorPos] = key;
+
+ DC->setCVar(item->cvar, buff);
+
+ if (item->cursorPos < len + 1) {
+ item->cursorPos++;
+ if (editPtr->maxPaintChars && item->cursorPos > editPtr->maxPaintChars) {
+ editPtr->paintOffset++;
+ }
+ }
+
+ } else {
+
+ if ( key == K_DEL ) {
+ if ( item->cursorPos < len ) {
+ memmove( buff + item->cursorPos, buff + item->cursorPos + 1, len - item->cursorPos);
+ DC->setCVar(item->cvar, buff);
+ }
+ return qtrue;
+ }
+
+ if ( key == K_RIGHTARROW )
+ {
+ if (editPtr->maxPaintChars && item->cursorPos >= editPtr->maxPaintChars && item->cursorPos < len) {
+ item->cursorPos++;
+ editPtr->paintOffset++;
+ return qtrue;
+ }
+ if (item->cursorPos < len) {
+ item->cursorPos++;
+ }
+ return qtrue;
+ }
+
+ if ( key == K_LEFTARROW )
+ {
+ if ( item->cursorPos > 0 ) {
+ item->cursorPos--;
+ }
+ if (item->cursorPos < editPtr->paintOffset) {
+ editPtr->paintOffset--;
+ }
+ return qtrue;
+ }
+
+ if ( key == K_HOME ) {// || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {
+ item->cursorPos = 0;
+ editPtr->paintOffset = 0;
+ return qtrue;
+ }
+
+ if ( key == K_END ) {// ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {
+ item->cursorPos = len;
+ if(item->cursorPos > editPtr->maxPaintChars) {
+ editPtr->paintOffset = len - editPtr->maxPaintChars;
+ }
+ return qtrue;
+ }
+
+ if ( key == K_INS ) {
+ DC->setOverstrikeMode(!DC->getOverstrikeMode());
+ return qtrue;
+ }
+ }
+
+ if (key == K_TAB || key == K_DOWNARROW ) {
+ newItem = Menu_SetNextCursorItem(item->parent);
+ if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
+ g_editItem = newItem;
+ }
+ }
+
+ if (key == K_UPARROW ) {
+ newItem = Menu_SetPrevCursorItem(item->parent);
+ if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
+ g_editItem = newItem;
+ }
+ }
+
+ if ( key == K_ENTER || key == K_KP_ENTER || key == K_ESCAPE) {
+ return qfalse;
+ }
+
+ return qtrue;
+ }
+ return qfalse;
+
+}
+
+static void Scroll_ListBox_AutoFunc(void *p) {
+ scrollInfo_t *si = (scrollInfo_t*)p;
+ if (DC->realTime > si->nextScrollTime) {
+ // need to scroll which is done by simulating a click to the item
+ // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
+ // so it calls it directly
+ Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
+ si->nextScrollTime = DC->realTime + si->adjustValue;
+ }
+
+ if (DC->realTime > si->nextAdjustTime) {
+ si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
+ if (si->adjustValue > SCROLL_TIME_FLOOR) {
+ si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
+ }
+ }
+}
+
+static void Scroll_ListBox_ThumbFunc(void *p) {
+ scrollInfo_t *si = (scrollInfo_t*)p;
+ rectDef_t r;
+ int pos, max;
+
+ listBoxDef_t *listPtr = (listBoxDef_t*)si->item->typeData;
+ if (si->item->window.flags & WINDOW_HORIZONTAL) {
+ if (DC->cursorx == si->xStart) {
+ return;
+ }
+ r.x = si->item->window.rect.x + SCROLLBAR_SIZE + 1;
+ r.y = si->item->window.rect.y + si->item->window.rect.h - SCROLLBAR_SIZE - 1;
+ r.h = SCROLLBAR_SIZE;
+ r.w = si->item->window.rect.w - (SCROLLBAR_SIZE*2) - 2;
+ max = Item_ListBox_MaxScroll(si->item);
+ //
+ pos = (DC->cursorx - r.x - SCROLLBAR_SIZE/2) * max / (r.w - SCROLLBAR_SIZE);
+ if (pos < 0) {
+ pos = 0;
+ }
+ else if (pos > max) {
+ pos = max;
+ }
+ listPtr->startPos = pos;
+ si->xStart = DC->cursorx;
+ }
+ else if (DC->cursory != si->yStart) {
+
+ r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_SIZE - 1;
+ r.y = si->item->window.rect.y + SCROLLBAR_SIZE + 1;
+ r.h = si->item->window.rect.h - (SCROLLBAR_SIZE*2) - 2;
+ r.w = SCROLLBAR_SIZE;
+ max = Item_ListBox_MaxScroll(si->item);
+ //
+ pos = (DC->cursory - r.y - SCROLLBAR_SIZE/2) * max / (r.h - SCROLLBAR_SIZE);
+ if (pos < 0) {
+ pos = 0;
+ }
+ else if (pos > max) {
+ pos = max;
+ }
+ listPtr->startPos = pos;
+ si->yStart = DC->cursory;
+ }
+
+ if (DC->realTime > si->nextScrollTime) {
+ // need to scroll which is done by simulating a click to the item
+ // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
+ // so it calls it directly
+ Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
+ si->nextScrollTime = DC->realTime + si->adjustValue;
+ }
+
+ if (DC->realTime > si->nextAdjustTime) {
+ si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
+ if (si->adjustValue > SCROLL_TIME_FLOOR) {
+ si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
+ }
+ }
+}
+
+static void Scroll_Slider_ThumbFunc(void *p) {
+ float x, value, cursorx;
+ scrollInfo_t *si = (scrollInfo_t*)p;
+ editFieldDef_t *editDef = si->item->typeData;
+
+ if (si->item->text) {
+ x = si->item->textRect.x + si->item->textRect.w + 8;
+ } else {
+ x = si->item->window.rect.x;
+ }
+
+ cursorx = DC->cursorx;
+
+ if (cursorx < x) {
+ cursorx = x;
+ } else if (cursorx > x + SLIDER_WIDTH) {
+ cursorx = x + SLIDER_WIDTH;
+ }
+ value = cursorx - x;
+ value /= SLIDER_WIDTH;
+ value *= (editDef->maxVal - editDef->minVal);
+ value += editDef->minVal;
+ DC->setCVar(si->item->cvar, va("%f", value));
+}
+
+void Item_StartCapture(itemDef_t *item, int key) {
+ int flags;
+ switch (item->type) {
+ case ITEM_TYPE_EDITFIELD:
+ case ITEM_TYPE_NUMERICFIELD:
+
+ case ITEM_TYPE_LISTBOX:
+ {
+ flags = Item_ListBox_OverLB(item, DC->cursorx, DC->cursory);
+ if (flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW)) {
+ scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START;
+ scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
+ scrollInfo.adjustValue = SCROLL_TIME_START;
+ scrollInfo.scrollKey = key;
+ scrollInfo.scrollDir = (flags & WINDOW_LB_LEFTARROW) ? qtrue : qfalse;
+ scrollInfo.item = item;
+ captureData = &scrollInfo;
+ captureFunc = &Scroll_ListBox_AutoFunc;
+ itemCapture = item;
+ } else if (flags & WINDOW_LB_THUMB) {
+ scrollInfo.scrollKey = key;
+ scrollInfo.item = item;
+ scrollInfo.xStart = DC->cursorx;
+ scrollInfo.yStart = DC->cursory;
+ captureData = &scrollInfo;
+ captureFunc = &Scroll_ListBox_ThumbFunc;
+ itemCapture = item;
+ }
+ break;
+ }
+ case ITEM_TYPE_SLIDER:
+ {
+ flags = Item_Slider_OverSlider(item, DC->cursorx, DC->cursory);
+ if (flags & WINDOW_LB_THUMB) {
+ scrollInfo.scrollKey = key;
+ scrollInfo.item = item;
+ scrollInfo.xStart = DC->cursorx;
+ scrollInfo.yStart = DC->cursory;
+ captureData = &scrollInfo;
+ captureFunc = &Scroll_Slider_ThumbFunc;
+ itemCapture = item;
+ }
+ break;
+ }
+ }
+}
+
+void Item_StopCapture(itemDef_t *item) {
+
+}
+
+qboolean Item_Slider_HandleKey(itemDef_t *item, int key, qboolean down) {
+ float x, value, width, work;
+
+ //DC->Print("slider handle key\n");
+ if (item->window.flags & WINDOW_HASFOCUS && item->cvar && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
+ if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
+ editFieldDef_t *editDef = item->typeData;
+ if (editDef) {
+ rectDef_t testRect;
+ width = SLIDER_WIDTH;
+ if (item->text) {
+ x = item->textRect.x + item->textRect.w + 8;
+ } else {
+ x = item->window.rect.x;
+ }
+
+ testRect = item->window.rect;
+ testRect.x = x;
+ value = (float)SLIDER_THUMB_WIDTH / 2;
+ testRect.x -= value;
+ //DC->Print("slider x: %f\n", testRect.x);
+ testRect.w = (SLIDER_WIDTH + (float)SLIDER_THUMB_WIDTH / 2);
+ //DC->Print("slider w: %f\n", testRect.w);
+ if (Rect_ContainsPoint(&testRect, DC->cursorx, DC->cursory)) {
+ work = DC->cursorx - x;
+ value = work / width;
+ value *= (editDef->maxVal - editDef->minVal);
+ // vm fuckage
+ // value = (((float)(DC->cursorx - x)/ SLIDER_WIDTH) * (editDef->maxVal - editDef->minVal));
+ value += editDef->minVal;
+ DC->setCVar(item->cvar, va("%f", value));
+ return qtrue;
+ }
+ }
+ }
+ }
+ DC->Print("slider handle key exit\n");
+ return qfalse;
+}
+
+
+qboolean Item_HandleKey(itemDef_t *item, int key, qboolean down) {
+
+ if (itemCapture) {
+ Item_StopCapture(itemCapture);
+ itemCapture = NULL;
+ captureFunc = 0;
+ captureData = NULL;
+ } else {
+ // bk001206 - parentheses
+ if ( down && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
+ Item_StartCapture(item, key);
+ }
+ }
+
+ if (!down) {
+ return qfalse;
+ }
+
+ switch (item->type) {
+ case ITEM_TYPE_BUTTON:
+ return qfalse;
+ break;
+ case ITEM_TYPE_RADIOBUTTON:
+ return qfalse;
+ break;
+ case ITEM_TYPE_CHECKBOX:
+ return qfalse;
+ break;
+ case ITEM_TYPE_EDITFIELD:
+ case ITEM_TYPE_NUMERICFIELD:
+ //return Item_TextField_HandleKey(item, key);
+ return qfalse;
+ break;
+ case ITEM_TYPE_COMBO:
+ return qfalse;
+ break;
+ case ITEM_TYPE_LISTBOX:
+ return Item_ListBox_HandleKey(item, key, down, qfalse);
+ break;
+ case ITEM_TYPE_YESNO:
+ return Item_YesNo_HandleKey(item, key);
+ break;
+ case ITEM_TYPE_MULTI:
+ return Item_Multi_HandleKey(item, key);
+ break;
+ case ITEM_TYPE_OWNERDRAW:
+ return Item_OwnerDraw_HandleKey(item, key);
+ break;
+ case ITEM_TYPE_BIND:
+ return Item_Bind_HandleKey(item, key, down);
+ break;
+ case ITEM_TYPE_SLIDER:
+ return Item_Slider_HandleKey(item, key, down);
+ break;
+ //case ITEM_TYPE_IMAGE:
+ // Item_Image_Paint(item);
+ // break;
+ default:
+ return qfalse;
+ break;
+ }
+
+ //return qfalse;
+}
+
+void Item_Action(itemDef_t *item) {
+ if (item) {
+ Item_RunScript(item, item->action);
+ }
+}
+
+itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu) {
+ qboolean wrapped = qfalse;
+ int oldCursor = menu->cursorItem;
+
+ if (menu->cursorItem < 0) {
+ menu->cursorItem = menu->itemCount-1;
+ wrapped = qtrue;
+ }
+
+ while (menu->cursorItem > -1) {
+
+ menu->cursorItem--;
+ if (menu->cursorItem < 0 && !wrapped) {
+ wrapped = qtrue;
+ menu->cursorItem = menu->itemCount -1;
+ }
+
+ if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
+ Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
+ return menu->items[menu->cursorItem];
+ }
+ }
+ menu->cursorItem = oldCursor;
+ return NULL;
+
+}
+
+itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu) {
+
+ qboolean wrapped = qfalse;
+ int oldCursor = menu->cursorItem;
+
+
+ if (menu->cursorItem == -1) {
+ menu->cursorItem = 0;
+ wrapped = qtrue;
+ }
+
+ while (menu->cursorItem < menu->itemCount) {
+
+ menu->cursorItem++;
+ if (menu->cursorItem >= menu->itemCount && !wrapped) {
+ wrapped = qtrue;
+ menu->cursorItem = 0;
+ }
+ if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
+ Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
+ return menu->items[menu->cursorItem];
+ }
+
+ }
+
+ menu->cursorItem = oldCursor;
+ return NULL;
+}
+
+static void Window_CloseCinematic(windowDef_t *window) {
+ if (window->style == WINDOW_STYLE_CINEMATIC && window->cinematic >= 0) {
+ DC->stopCinematic(window->cinematic);
+ window->cinematic = -1;
+ }
+}
+
+static void Menu_CloseCinematics(menuDef_t *menu) {
+ if (menu) {
+ int i;
+ Window_CloseCinematic(&menu->window);
+ for (i = 0; i < menu->itemCount; i++) {
+ Window_CloseCinematic(&menu->items[i]->window);
+ if (menu->items[i]->type == ITEM_TYPE_OWNERDRAW) {
+ DC->stopCinematic(0-menu->items[i]->window.ownerDraw);
+ }
+ }
+ }
+}
+
+static void Display_CloseCinematics( void ) {
+ int i;
+ for (i = 0; i < menuCount; i++) {
+ Menu_CloseCinematics(&Menus[i]);
+ }
+}
+
+void Menus_Activate(menuDef_t *menu) {
+ menu->window.flags |= (WINDOW_HASFOCUS | WINDOW_VISIBLE);
+ if (menu->onOpen) {
+ itemDef_t item;
+ item.parent = menu;
+ Item_RunScript(&item, menu->onOpen);
+ }
+
+ if (menu->soundName && *menu->soundName) {
+// DC->stopBackgroundTrack(); // you don't want to do this since it will reset s_rawend
+ DC->startBackgroundTrack(menu->soundName, menu->soundName);
+ }
+
+ Display_CloseCinematics();
+
+}
+
+int Display_VisibleMenuCount( void ) {
+ int i, count;
+ count = 0;
+ for (i = 0; i < menuCount; i++) {
+ if (Menus[i].window.flags & (WINDOW_FORCED | WINDOW_VISIBLE)) {
+ count++;
+ }
+ }
+ return count;
+}
+
+void Menus_HandleOOBClick(menuDef_t *menu, int key, qboolean down) {
+ if (menu) {
+ int i;
+ // basically the behaviour we are looking for is if there are windows in the stack.. see if
+ // the cursor is within any of them.. if not close them otherwise activate them and pass the
+ // key on.. force a mouse move to activate focus and script stuff
+ if (down && menu->window.flags & WINDOW_OOB_CLICK) {
+ Menu_RunCloseScript(menu);
+ menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
+ }
+
+ for (i = 0; i < menuCount; i++) {
+ if (Menu_OverActiveItem(&Menus[i], DC->cursorx, DC->cursory)) {
+ Menu_RunCloseScript(menu);
+ menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
+ Menus_Activate(&Menus[i]);
+ Menu_HandleMouseMove(&Menus[i], DC->cursorx, DC->cursory);
+ Menu_HandleKey(&Menus[i], key, down);
+ }
+ }
+
+ if (Display_VisibleMenuCount() == 0) {
+ if (DC->Pause) {
+ DC->Pause(qfalse);
+ }
+ }
+ Display_CloseCinematics();
+ }
+}
+
+static rectDef_t *Item_CorrectedTextRect(itemDef_t *item) {
+ static rectDef_t rect;
+ memset(&rect, 0, sizeof(rectDef_t));
+ if (item) {
+ rect = item->textRect;
+ if (rect.w) {
+ rect.y -= rect.h;
+ }
+ }
+ return ▭
+}
+
+void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) {
+ int i;
+ itemDef_t *item = NULL;
+ qboolean inHandler = qfalse;
+
+ if (inHandler) {
+ return;
+ }
+
+ inHandler = qtrue;
+ if (g_waitingForKey && down) {
+ Item_Bind_HandleKey(g_bindItem, key, down);
+ inHandler = qfalse;
+ return;
+ }
+
+ if (g_editingField && down) {
+ if (!Item_TextField_HandleKey(g_editItem, key)) {
+ g_editingField = qfalse;
+ g_editItem = NULL;
+ inHandler = qfalse;
+ return;
+ } else if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) {
+ g_editingField = qfalse;
+ g_editItem = NULL;
+ Display_MouseMove(NULL, DC->cursorx, DC->cursory);
+ } else if (key == K_TAB || key == K_UPARROW || key == K_DOWNARROW) {
+ return;
+ }
+ }
+
+ if (menu == NULL) {
+ inHandler = qfalse;
+ return;
+ }
+
+ // see if the mouse is within the window bounds and if so is this a mouse click
+ if (down && !(menu->window.flags & WINDOW_POPUP) && !Rect_ContainsPoint(&menu->window.rect, DC->cursorx, DC->cursory)) {
+ static qboolean inHandleKey = qfalse;
+ // bk001206 - parentheses
+ if (!inHandleKey && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
+ inHandleKey = qtrue;
+ Menus_HandleOOBClick(menu, key, down);
+ inHandleKey = qfalse;
+ inHandler = qfalse;
+ return;
+ }
+ }
+
+ // get the item with focus
+ for (i = 0; i < menu->itemCount; i++) {
+ if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
+ item = menu->items[i];
+ }
+ }
+
+ if (item != NULL) {
+ if (Item_HandleKey(item, key, down)) {
+ Item_Action(item);
+ inHandler = qfalse;
+ return;
+ }
+ }
+
+ if (!down) {
+ inHandler = qfalse;
+ return;
+ }
+
+ // default handling
+ switch ( key ) {
+
+ case K_F11:
+ if (DC->getCVarValue("developer")) {
+ debugMode ^= 1;
+ }
+ break;
+
+ case K_F12:
+ if (DC->getCVarValue("developer")) {
+ DC->executeText(EXEC_APPEND, "screenshot\n");
+ }
+ break;
+ case K_UPARROW:
+ Menu_SetPrevCursorItem(menu);
+ break;
+
+ case K_ESCAPE:
+ if (!g_waitingForKey && menu->onESC) {
+ itemDef_t it;
+ it.parent = menu;
+ Item_RunScript(&it, menu->onESC);
+ }
+ break;
+ case K_TAB:
+ case K_DOWNARROW:
+ Menu_SetNextCursorItem(menu);
+ break;
+
+ case K_MOUSE1:
+ case K_MOUSE2:
+ if (item) {
+ if (item->type == ITEM_TYPE_TEXT) {
+ if (Rect_ContainsPoint(Item_CorrectedTextRect(item), DC->cursorx, DC->cursory)) {
+ Item_Action(item);
+ }
+ } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
+ if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
+ item->cursorPos = 0;
+ g_editingField = qtrue;
+ g_editItem = item;
+ }
+ } else {
+ if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
+ Item_Action(item);
+ }
+ }
+ }
+ break;
+
+ case K_JOY1:
+ case K_JOY2:
+ case K_JOY3:
+ case K_JOY4:
+ case K_AUX1:
+ case K_AUX2:
+ case K_AUX3:
+ case K_AUX4:
+ case K_AUX5:
+ case K_AUX6:
+ case K_AUX7:
+ case K_AUX8:
+ case K_AUX9:
+ case K_AUX10:
+ case K_AUX11:
+ case K_AUX12:
+ case K_AUX13:
+ case K_AUX14:
+ case K_AUX15:
+ case K_AUX16:
+ break;
+ case K_KP_ENTER:
+ case K_ENTER:
+ if (item) {
+ if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
+ item->cursorPos = 0;
+ g_editingField = qtrue;
+ g_editItem = item;
+ } else {
+ Item_Action(item);
+ }
+ }
+ break;
+ }
+ inHandler = qfalse;
+}
+
+void ToWindowCoords(float *x, float *y, windowDef_t *window) {
+ if (window->border != 0) {
+ *x += window->borderSize;
+ *y += window->borderSize;
+ }
+ *x += window->rect.x;
+ *y += window->rect.y;
+}
+
+void Rect_ToWindowCoords(rectDef_t *rect, windowDef_t *window) {
+ ToWindowCoords(&rect->x, &rect->y, window);
+}
+
+void Item_SetTextExtents(itemDef_t *item, int *width, int *height, const char *text) {
+ const char *textPtr = (text) ? text : item->text;
+
+ if (textPtr == NULL ) {
+ return;
+ }
+
+ *width = item->textRect.w;
+ *height = item->textRect.h;
+
+ // keeps us from computing the widths and heights more than once
+ if (*width == 0 || (item->type == ITEM_TYPE_OWNERDRAW && item->textalignment == ITEM_ALIGN_CENTER)) {
+ int originalWidth = DC->textWidth(item->text, item->textscale, 0);
+
+ if (item->type == ITEM_TYPE_OWNERDRAW && (item->textalignment == ITEM_ALIGN_CENTER || item->textalignment == ITEM_ALIGN_RIGHT)) {
+ originalWidth += DC->ownerDrawWidth(item->window.ownerDraw, item->textscale);
+ } else if (item->type == ITEM_TYPE_EDITFIELD && item->textalignment == ITEM_ALIGN_CENTER && item->cvar) {
+ char buff[256];
+ DC->getCVarString(item->cvar, buff, 256);
+ originalWidth += DC->textWidth(buff, item->textscale, 0);
+ }
+
+ *width = DC->textWidth(textPtr, item->textscale, 0);
+ *height = DC->textHeight(textPtr, item->textscale, 0);
+ item->textRect.w = *width;
+ item->textRect.h = *height;
+ item->textRect.x = item->textalignx;
+ item->textRect.y = item->textaligny;
+ if (item->textalignment == ITEM_ALIGN_RIGHT) {
+ item->textRect.x = item->textalignx - originalWidth;
+ } else if (item->textalignment == ITEM_ALIGN_CENTER) {
+ item->textRect.x = item->textalignx - originalWidth / 2;
+ }
+
+ ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
+ }
+}
+
+void Item_TextColor(itemDef_t *item, vec4_t *newColor) {
+ vec4_t lowLight;
+ menuDef_t *parent = (menuDef_t*)item->parent;
+
+ Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
+
+ if (item->window.flags & WINDOW_HASFOCUS) {
+ lowLight[0] = 0.8 * parent->focusColor[0];
+ lowLight[1] = 0.8 * parent->focusColor[1];
+ lowLight[2] = 0.8 * parent->focusColor[2];
+ lowLight[3] = 0.8 * parent->focusColor[3];
+ LerpColor(parent->focusColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
+ } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
+ lowLight[0] = 0.8 * item->window.foreColor[0];
+ lowLight[1] = 0.8 * item->window.foreColor[1];
+ lowLight[2] = 0.8 * item->window.foreColor[2];
+ lowLight[3] = 0.8 * item->window.foreColor[3];
+ LerpColor(item->window.foreColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
+ } else {
+ memcpy(newColor, &item->window.foreColor, sizeof(vec4_t));
+ // items can be enabled and disabled based on cvars
+ }
+
+ if (item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
+ if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
+ memcpy(newColor, &parent->disableColor, sizeof(vec4_t));
+ }
+ }
+}
+
+void Item_Text_AutoWrapped_Paint(itemDef_t *item) {
+ char text[1024];
+ const char *p, *textPtr, *newLinePtr;
+ char buff[1024];
+ int width, height, len, textWidth, newLine, newLineWidth;
+ float y;
+ vec4_t color;
+
+ textWidth = 0;
+ newLinePtr = NULL;
+
+ if (item->text == NULL) {
+ if (item->cvar == NULL) {
+ return;
+ }
+ else {
+ DC->getCVarString(item->cvar, text, sizeof(text));
+ textPtr = text;
+ }
+ }
+ else {
+ textPtr = item->text;
+ }
+ if (*textPtr == '\0') {
+ return;
+ }
+ Item_TextColor(item, &color);
+ Item_SetTextExtents(item, &width, &height, textPtr);
+
+ y = item->textaligny;
+ len = 0;
+ buff[0] = '\0';
+ newLine = 0;
+ newLineWidth = 0;
+ p = textPtr;
+ while (p) {
+ if (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\0') {
+ newLine = len;
+ newLinePtr = p+1;
+ newLineWidth = textWidth;
+ }
+ textWidth = DC->textWidth(buff, item->textscale, 0);
+ if ( (newLine && textWidth > item->window.rect.w) || *p == '\n' || *p == '\0') {
+ if (len) {
+ if (item->textalignment == ITEM_ALIGN_LEFT) {
+ item->textRect.x = item->textalignx;
+ } else if (item->textalignment == ITEM_ALIGN_RIGHT) {
+ item->textRect.x = item->textalignx - newLineWidth;
+ } else if (item->textalignment == ITEM_ALIGN_CENTER) {
+ item->textRect.x = item->textalignx - newLineWidth / 2;
+ }
+ item->textRect.y = y;
+ ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
+ //
+ buff[newLine] = '\0';
+ DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, buff, 0, 0, item->textStyle);
+ }
+ if (*p == '\0') {
+ break;
+ }
+ //
+ y += height + 5;
+ p = newLinePtr;
+ len = 0;
+ newLine = 0;
+ newLineWidth = 0;
+ continue;
+ }
+ buff[len++] = *p++;
+ buff[len] = '\0';
+ }
+}
+
+void Item_Text_Wrapped_Paint(itemDef_t *item) {
+ char text[1024];
+ const char *p, *start, *textPtr;
+ char buff[1024];
+ int width, height;
+ float x, y;
+ vec4_t color;
+
+ // now paint the text and/or any optional images
+ // default to left
+
+ if (item->text == NULL) {
+ if (item->cvar == NULL) {
+ return;
+ }
+ else {
+ DC->getCVarString(item->cvar, text, sizeof(text));
+ textPtr = text;
+ }
+ }
+ else {
+ textPtr = item->text;
+ }
+ if (*textPtr == '\0') {
+ return;
+ }
+
+ Item_TextColor(item, &color);
+ Item_SetTextExtents(item, &width, &height, textPtr);
+
+ x = item->textRect.x;
+ y = item->textRect.y;
+ start = textPtr;
+ p = strchr(textPtr, '\r');
+ while (p && *p) {
+ strncpy(buff, start, p-start+1);
+ buff[p-start] = '\0';
+ DC->drawText(x, y, item->textscale, color, buff, 0, 0, item->textStyle);
+ y += height + 5;
+ start += p - start + 1;
+ p = strchr(p+1, '\r');
+ }
+ DC->drawText(x, y, item->textscale, color, start, 0, 0, item->textStyle);
+}
+
+void Item_Text_Paint(itemDef_t *item) {
+ char text[1024];
+ const char *textPtr;
+ int height, width;
+ vec4_t color;
+
+ if (item->window.flags & WINDOW_WRAPPED) {
+ Item_Text_Wrapped_Paint(item);
+ return;
+ }
+ if (item->window.flags & WINDOW_AUTOWRAPPED) {
+ Item_Text_AutoWrapped_Paint(item);
+ return;
+ }
+
+ if (item->text == NULL) {
+ if (item->cvar == NULL) {
+ return;
+ }
+ else {
+ DC->getCVarString(item->cvar, text, sizeof(text));
+ textPtr = text;
+ }
+ }
+ else {
+ textPtr = item->text;
+ }
+
+ // this needs to go here as it sets extents for cvar types as well
+ Item_SetTextExtents(item, &width, &height, textPtr);
+
+ if (*textPtr == '\0') {
+ return;
+ }
+
+
+ Item_TextColor(item, &color);
+
+ //FIXME: this is a fucking mess
+/*
+ adjust = 0;
+ if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
+ adjust = 0.5;
+ }
+
+ if (item->textStyle == ITEM_TEXTSTYLE_SHADOWED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
+ Fade(&item->window.flags, &DC->Assets.shadowColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
+ DC->drawText(item->textRect.x + DC->Assets.shadowX, item->textRect.y + DC->Assets.shadowY, item->textscale, DC->Assets.shadowColor, textPtr, adjust);
+ }
+*/
+
+
+// if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
+// Fade(&item->window.flags, &item->window.outlineColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
+// /*
+// Text_Paint(item->textRect.x-1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
+// Text_Paint(item->textRect.x, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
+// Text_Paint(item->textRect.x+1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
+// Text_Paint(item->textRect.x-1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
+// Text_Paint(item->textRect.x+1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
+// Text_Paint(item->textRect.x-1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
+// Text_Paint(item->textRect.x, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
+// Text_Paint(item->textRect.x+1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
+// */
+// DC->drawText(item->textRect.x - 1, item->textRect.y + 1, item->textscale * 1.02, item->window.outlineColor, textPtr, adjust);
+// }
+
+ DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, textPtr, 0, 0, item->textStyle);
+}
+
+
+
+//float trap_Cvar_VariableValue( const char *var_name );
+//void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
+
+void Item_TextField_Paint(itemDef_t *item) {
+ char buff[1024];
+ vec4_t newColor, lowLight;
+ int offset;
+ menuDef_t *parent = (menuDef_t*)item->parent;
+ editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
+
+ Item_Text_Paint(item);
+
+ buff[0] = '\0';
+
+ if (item->cvar) {
+ DC->getCVarString(item->cvar, buff, sizeof(buff));
+ }
+
+ parent = (menuDef_t*)item->parent;
+
+ if (item->window.flags & WINDOW_HASFOCUS) {
+ lowLight[0] = 0.8 * parent->focusColor[0];
+ lowLight[1] = 0.8 * parent->focusColor[1];
+ lowLight[2] = 0.8 * parent->focusColor[2];
+ lowLight[3] = 0.8 * parent->focusColor[3];
+ LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
+ } else {
+ memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
+ }
+
+ offset = (item->text && *item->text) ? 8 : 0;
+ if (item->window.flags & WINDOW_HASFOCUS && g_editingField) {
+ char cursor = DC->getOverstrikeMode() ? '_' : '|';
+ DC->drawTextWithCursor(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, item->cursorPos - editPtr->paintOffset , cursor, editPtr->maxPaintChars, item->textStyle);
+ } else {
+ DC->drawText(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, 0, editPtr->maxPaintChars, item->textStyle);
+ }
+
+}
+
+void Item_YesNo_Paint(itemDef_t *item) {
+ vec4_t newColor, lowLight;
+ float value;
+ menuDef_t *parent = (menuDef_t*)item->parent;
+
+ value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
+
+ if (item->window.flags & WINDOW_HASFOCUS) {
+ lowLight[0] = 0.8 * parent->focusColor[0];
+ lowLight[1] = 0.8 * parent->focusColor[1];
+ lowLight[2] = 0.8 * parent->focusColor[2];
+ lowLight[3] = 0.8 * parent->focusColor[3];
+ LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
+ } else {
+ memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
+ }
+
+ if (item->text) {
+ Item_Text_Paint(item);
+ DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
+ } else {
+ DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
+ }
+}
+
+void Item_Multi_Paint(itemDef_t *item) {
+ vec4_t newColor, lowLight;
+ const char *text = "";
+ menuDef_t *parent = (menuDef_t*)item->parent;
+
+ if (item->window.flags & WINDOW_HASFOCUS) {
+ lowLight[0] = 0.8 * parent->focusColor[0];
+ lowLight[1] = 0.8 * parent->focusColor[1];
+ lowLight[2] = 0.8 * parent->focusColor[2];
+ lowLight[3] = 0.8 * parent->focusColor[3];
+ LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
+ } else {
+ memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
+ }
+
+ text = Item_Multi_Setting(item);
+
+ if (item->text) {
+ Item_Text_Paint(item);
+ DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
+ } else {
+ DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
+ }
+}
+
+
+typedef struct {
+ char *command;
+ int id;
+ int defaultbind1;
+ int defaultbind2;
+ int bind1;
+ int bind2;
+} bind_t;
+
+typedef struct
+{
+ char* name;
+ float defaultvalue;
+ float value;
+} configcvar_t;
+
+
+static bind_t g_bindings[] =
+{
+ {"+scores", K_TAB, -1, -1, -1},
+ {"+button2", K_ENTER, -1, -1, -1},
+ {"+speed", K_SHIFT, -1, -1, -1},
+ {"+forward", K_UPARROW, -1, -1, -1},
+ {"+back", K_DOWNARROW, -1, -1, -1},
+ {"+moveleft", ',', -1, -1, -1},
+ {"+moveright", '.', -1, -1, -1},
+ {"+moveup", K_SPACE, -1, -1, -1},
+ {"+movedown", 'c', -1, -1, -1},
+ {"+left", K_LEFTARROW, -1, -1, -1},
+ {"+right", K_RIGHTARROW, -1, -1, -1},
+ {"+strafe", K_ALT, -1, -1, -1},
+ {"+lookup", K_PGDN, -1, -1, -1},
+ {"+lookdown", K_DEL, -1, -1, -1},
+ {"+mlook", '/', -1, -1, -1},
+ {"centerview", K_END, -1, -1, -1},
+ {"+zoom", -1, -1, -1, -1},
+ {"weapon 1", '1', -1, -1, -1},
+ {"weapon 2", '2', -1, -1, -1},
+ {"weapon 3", '3', -1, -1, -1},
+ {"weapon 4", '4', -1, -1, -1},
+ {"weapon 5", '5', -1, -1, -1},
+ {"weapon 6", '6', -1, -1, -1},
+ {"weapon 7", '7', -1, -1, -1},
+ {"weapon 8", '8', -1, -1, -1},
+ {"weapon 9", '9', -1, -1, -1},
+ {"weapon 10", '0', -1, -1, -1},
+ {"weapon 11", -1, -1, -1, -1},
+ {"weapon 12", -1, -1, -1, -1},
+ {"weapon 13", -1, -1, -1, -1},
+ {"+attack", K_CTRL, -1, -1, -1},
+ {"weapprev", '[', -1, -1, -1},
+ {"weapnext", ']', -1, -1, -1},
+ {"+button3", K_MOUSE3, -1, -1, -1},
+ {"+button4", K_MOUSE4, -1, -1, -1},
+ {"prevTeamMember", 'w', -1, -1, -1},
+ {"nextTeamMember", 'r', -1, -1, -1},
+ {"nextOrder", 't', -1, -1, -1},
+ {"confirmOrder", 'y', -1, -1, -1},
+ {"denyOrder", 'n', -1, -1, -1},
+ {"taskOffense", 'o', -1, -1, -1},
+ {"taskDefense", 'd', -1, -1, -1},
+ {"taskPatrol", 'p', -1, -1, -1},
+ {"taskCamp", 'c', -1, -1, -1},
+ {"taskFollow", 'f', -1, -1, -1},
+ {"taskRetrieve", 'v', -1, -1, -1},
+ {"taskEscort", 'e', -1, -1, -1},
+ {"taskOwnFlag", 'i', -1, -1, -1},
+ {"taskSuicide", 'k', -1, -1, -1},
+ {"tauntKillInsult", K_F1, -1, -1, -1},
+ {"tauntPraise", K_F2, -1, -1, -1},
+ {"tauntTaunt", K_F3, -1, -1, -1},
+ {"tauntDeathInsult", K_F4, -1, -1, -1},
+ {"tauntGauntlet", K_F5, -1, -1, -1},
+ {"scoresUp", K_KP_PGUP, -1, -1, -1},
+ {"scoresDown", K_KP_PGDN, -1, -1, -1},
+ // bk001205 - this one below was: '-1'
+ {"messagemode", -1, -1, -1, -1},
+ {"messagemode2", -1, -1, -1, -1},
+ {"messagemode3", -1, -1, -1, -1},
+ {"messagemode4", -1, -1, -1, -1}
+};
+
+
+static const int g_bindCount = sizeof(g_bindings) / sizeof(bind_t);
+
+#ifndef MISSIONPACK // bk001206
+static configcvar_t g_configcvars[] =
+{
+ {"cl_run", 0, 0},
+ {"m_pitch", 0, 0},
+ {"cg_autoswitch", 0, 0},
+ {"sensitivity", 0, 0},
+ {"in_joystick", 0, 0},
+ {"joy_threshold", 0, 0},
+ {"m_filter", 0, 0},
+ {"cl_freelook", 0, 0},
+ {NULL, 0, 0}
+};
+#endif
+
+/*
+=================
+Controls_GetKeyAssignment
+=================
+*/
+static void Controls_GetKeyAssignment (char *command, int *twokeys)
+{
+ int count;
+ int j;
+ char b[256];
+
+ twokeys[0] = twokeys[1] = -1;
+ count = 0;
+
+ for ( j = 0; j < 256; j++ )
+ {
+ DC->getBindingBuf( j, b, 256 );
+ if ( *b == 0 ) {
+ continue;
+ }
+ if ( !Q_stricmp( b, command ) ) {
+ twokeys[count] = j;
+ count++;
+ if (count == 2) {
+ break;
+ }
+ }
+ }
+}
+
+/*
+=================
+Controls_GetConfig
+=================
+*/
+void Controls_GetConfig( void )
+{
+ int i;
+ int twokeys[2];
+
+ // iterate each command, get its numeric binding
+ for (i=0; i < g_bindCount; i++)
+ {
+
+ Controls_GetKeyAssignment(g_bindings[i].command, twokeys);
+
+ g_bindings[i].bind1 = twokeys[0];
+ g_bindings[i].bind2 = twokeys[1];
+ }
+
+ //s_controls.invertmouse.curvalue = DC->getCVarValue( "m_pitch" ) < 0;
+ //s_controls.smoothmouse.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "m_filter" ) );
+ //s_controls.alwaysrun.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_run" ) );
+ //s_controls.autoswitch.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_autoswitch" ) );
+ //s_controls.sensitivity.curvalue = UI_ClampCvar( 2, 30, Controls_GetCvarValue( "sensitivity" ) );
+ //s_controls.joyenable.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "in_joystick" ) );
+ //s_controls.joythreshold.curvalue = UI_ClampCvar( 0.05, 0.75, Controls_GetCvarValue( "joy_threshold" ) );
+ //s_controls.freelook.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_freelook" ) );
+}
+
+/*
+=================
+Controls_SetConfig
+=================
+*/
+void Controls_SetConfig(qboolean restart)
+{
+ int i;
+
+ // iterate each command, get its numeric binding
+ for (i=0; i < g_bindCount; i++)
+ {
+
+ if (g_bindings[i].bind1 != -1)
+ {
+ DC->setBinding( g_bindings[i].bind1, g_bindings[i].command );
+
+ if (g_bindings[i].bind2 != -1)
+ DC->setBinding( g_bindings[i].bind2, g_bindings[i].command );
+ }
+ }
+
+ //if ( s_controls.invertmouse.curvalue )
+ // DC->setCVar("m_pitch", va("%f),-fabs( DC->getCVarValue( "m_pitch" ) ) );
+ //else
+ // trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
+
+ //trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue );
+ //trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue );
+ //trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue );
+ //trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue );
+ //trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue );
+ //trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue );
+ //trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue );
+ DC->executeText(EXEC_APPEND, "in_restart\n");
+ //trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" );
+}
+
+/*
+=================
+Controls_SetDefaults
+=================
+*/
+void Controls_SetDefaults( void )
+{
+ int i;
+
+ // iterate each command, set its default binding
+ for (i=0; i < g_bindCount; i++)
+ {
+ g_bindings[i].bind1 = g_bindings[i].defaultbind1;
+ g_bindings[i].bind2 = g_bindings[i].defaultbind2;
+ }
+
+ //s_controls.invertmouse.curvalue = Controls_GetCvarDefault( "m_pitch" ) < 0;
+ //s_controls.smoothmouse.curvalue = Controls_GetCvarDefault( "m_filter" );
+ //s_controls.alwaysrun.curvalue = Controls_GetCvarDefault( "cl_run" );
+ //s_controls.autoswitch.curvalue = Controls_GetCvarDefault( "cg_autoswitch" );
+ //s_controls.sensitivity.curvalue = Controls_GetCvarDefault( "sensitivity" );
+ //s_controls.joyenable.curvalue = Controls_GetCvarDefault( "in_joystick" );
+ //s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" );
+ //s_controls.freelook.curvalue = Controls_GetCvarDefault( "cl_freelook" );
+}
+
+int BindingIDFromName(const char *name) {
+ int i;
+ for (i=0; i < g_bindCount; i++)
+ {
+ if (Q_stricmp(name, g_bindings[i].command) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+char g_nameBind1[32];
+char g_nameBind2[32];
+
+void BindingFromName(const char *cvar) {
+ int i, b1, b2;
+
+ // iterate each command, set its default binding
+ for (i=0; i < g_bindCount; i++)
+ {
+ if (Q_stricmp(cvar, g_bindings[i].command) == 0) {
+ b1 = g_bindings[i].bind1;
+ if (b1 == -1) {
+ break;
+ }
+ DC->keynumToStringBuf( b1, g_nameBind1, 32 );
+ Q_strupr(g_nameBind1);
+
+ b2 = g_bindings[i].bind2;
+ if (b2 != -1)
+ {
+ DC->keynumToStringBuf( b2, g_nameBind2, 32 );
+ Q_strupr(g_nameBind2);
+ strcat( g_nameBind1, " or " );
+ strcat( g_nameBind1, g_nameBind2 );
+ }
+ return;
+ }
+ }
+ strcpy(g_nameBind1, "???");
+}
+
+void Item_Slider_Paint(itemDef_t *item) {
+ vec4_t newColor, lowLight;
+ float x, y, value;
+ menuDef_t *parent = (menuDef_t*)item->parent;
+
+ value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
+
+ if (item->window.flags & WINDOW_HASFOCUS) {
+ lowLight[0] = 0.8 * parent->focusColor[0];
+ lowLight[1] = 0.8 * parent->focusColor[1];
+ lowLight[2] = 0.8 * parent->focusColor[2];
+ lowLight[3] = 0.8 * parent->focusColor[3];
+ LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
+ } else {
+ memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
+ }
+
+ y = item->window.rect.y;
+ if (item->text) {
+ Item_Text_Paint(item);
+ x = item->textRect.x + item->textRect.w + 8;
+ } else {
+ x = item->window.rect.x;
+ }
+ DC->setColor(newColor);
+ DC->drawHandlePic( x, y, SLIDER_WIDTH, SLIDER_HEIGHT, DC->Assets.sliderBar );
+
+ x = Item_Slider_ThumbPosition(item);
+ DC->drawHandlePic( x - (SLIDER_THUMB_WIDTH / 2), y - 2, SLIDER_THUMB_WIDTH, SLIDER_THUMB_HEIGHT, DC->Assets.sliderThumb );
+
+}
+
+void Item_Bind_Paint(itemDef_t *item) {
+ vec4_t newColor, lowLight;
+ float value;
+ int maxChars = 0;
+ menuDef_t *parent = (menuDef_t*)item->parent;
+ editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
+ if (editPtr) {
+ maxChars = editPtr->maxPaintChars;
+ }
+
+ value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
+
+ if (item->window.flags & WINDOW_HASFOCUS) {
+ if (g_bindItem == item) {
+ lowLight[0] = 0.8f * 1.0f;
+ lowLight[1] = 0.8f * 0.0f;
+ lowLight[2] = 0.8f * 0.0f;
+ lowLight[3] = 0.8f * 1.0f;
+ } else {
+ lowLight[0] = 0.8f * parent->focusColor[0];
+ lowLight[1] = 0.8f * parent->focusColor[1];
+ lowLight[2] = 0.8f * parent->focusColor[2];
+ lowLight[3] = 0.8f * parent->focusColor[3];
+ }
+ LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
+ } else {
+ memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
+ }
+
+ if (item->text) {
+ Item_Text_Paint(item);
+ BindingFromName(item->cvar);
+ DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, g_nameBind1, 0, maxChars, item->textStyle);
+ } else {
+ DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "FIXME" : "FIXME", 0, maxChars, item->textStyle);
+ }
+}
+
+qboolean Display_KeyBindPending(void) {
+ return g_waitingForKey;
+}
+
+qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) {
+ int id;
+ int i;
+
+ if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey)
+ {
+ if (down && (key == K_MOUSE1 || key == K_ENTER)) {
+ g_waitingForKey = qtrue;
+ g_bindItem = item;
+ }
+ return qtrue;
+ }
+ else
+ {
+ if (!g_waitingForKey || g_bindItem == NULL) {
+ return qtrue;
+ }
+
+ if (key & K_CHAR_FLAG) {
+ return qtrue;
+ }
+
+ switch (key)
+ {
+ case K_ESCAPE:
+ g_waitingForKey = qfalse;
+ return qtrue;
+
+ case K_BACKSPACE:
+ id = BindingIDFromName(item->cvar);
+ if (id != -1) {
+ g_bindings[id].bind1 = -1;
+ g_bindings[id].bind2 = -1;
+ }
+ Controls_SetConfig(qtrue);
+ g_waitingForKey = qfalse;
+ g_bindItem = NULL;
+ return qtrue;
+
+ case '`':
+ return qtrue;
+ }
+ }
+
+ if (key != -1)
+ {
+
+ for (i=0; i < g_bindCount; i++)
+ {
+
+ if (g_bindings[i].bind2 == key) {
+ g_bindings[i].bind2 = -1;
+ }
+
+ if (g_bindings[i].bind1 == key)
+ {
+ g_bindings[i].bind1 = g_bindings[i].bind2;
+ g_bindings[i].bind2 = -1;
+ }
+ }
+ }
+
+
+ id = BindingIDFromName(item->cvar);
+
+ if (id != -1) {
+ if (key == -1) {
+ if( g_bindings[id].bind1 != -1 ) {
+ DC->setBinding( g_bindings[id].bind1, "" );
+ g_bindings[id].bind1 = -1;
+ }
+ if( g_bindings[id].bind2 != -1 ) {
+ DC->setBinding( g_bindings[id].bind2, "" );
+ g_bindings[id].bind2 = -1;
+ }
+ }
+ else if (g_bindings[id].bind1 == -1) {
+ g_bindings[id].bind1 = key;
+ }
+ else if (g_bindings[id].bind1 != key && g_bindings[id].bind2 == -1) {
+ g_bindings[id].bind2 = key;
+ }
+ else {
+ DC->setBinding( g_bindings[id].bind1, "" );
+ DC->setBinding( g_bindings[id].bind2, "" );
+ g_bindings[id].bind1 = key;
+ g_bindings[id].bind2 = -1;
+ }
+ }
+
+ Controls_SetConfig(qtrue);
+ g_waitingForKey = qfalse;
+
+ return qtrue;
+}
+
+
+
+void AdjustFrom640(float *x, float *y, float *w, float *h) {
+ //*x = *x * DC->scale + DC->bias;
+ *x *= DC->xscale;
+ *y *= DC->yscale;
+ *w *= DC->xscale;
+ *h *= DC->yscale;
+}
+
+void Item_Model_Paint(itemDef_t *item) {
+ float x, y, w, h;
+ refdef_t refdef;
+ refEntity_t ent;
+ vec3_t mins, maxs, origin;
+ vec3_t angles;
+ modelDef_t *modelPtr = (modelDef_t*)item->typeData;
+
+ if (modelPtr == NULL) {
+ return;
+ }
+
+ // setup the refdef
+ memset( &refdef, 0, sizeof( refdef ) );
+ refdef.rdflags = RDF_NOWORLDMODEL;
+ AxisClear( refdef.viewaxis );
+ x = item->window.rect.x+1;
+ y = item->window.rect.y+1;
+ w = item->window.rect.w-2;
+ h = item->window.rect.h-2;
+
+ AdjustFrom640( &x, &y, &w, &h );
+
+ refdef.x = x;
+ refdef.y = y;
+ refdef.width = w;
+ refdef.height = h;
+
+ DC->modelBounds( item->asset, mins, maxs );
+
+ origin[2] = -0.5 * ( mins[2] + maxs[2] );
+ origin[1] = 0.5 * ( mins[1] + maxs[1] );
+
+ // calculate distance so the model nearly fills the box
+ if (qtrue) {
+ float len = 0.5 * ( maxs[2] - mins[2] );
+ origin[0] = len / 0.268; // len / tan( fov/2 )
+ //origin[0] = len / tan(w/2);
+ } else {
+ origin[0] = item->textscale;
+ }
+ refdef.fov_x = (modelPtr->fov_x) ? modelPtr->fov_x : w;
+ refdef.fov_y = (modelPtr->fov_y) ? modelPtr->fov_y : h;
+
+ //refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
+ //xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
+ //refdef.fov_y = atan2( refdef.height, xx );
+ //refdef.fov_y *= ( 360 / M_PI );
+
+ DC->clearScene();
+
+ refdef.time = DC->realTime;
+
+ // add the model
+
+ memset( &ent, 0, sizeof(ent) );
+
+ //adjust = 5.0 * sin( (float)uis.realtime / 500 );
+ //adjust = 360 % (int)((float)uis.realtime / 1000);
+ //VectorSet( angles, 0, 0, 1 );
+
+ // use item storage to track
+ if (modelPtr->rotationSpeed) {
+ if (DC->realTime > item->window.nextTime) {
+ item->window.nextTime = DC->realTime + modelPtr->rotationSpeed;
+ modelPtr->angle = (int)(modelPtr->angle + 1) % 360;
+ }
+ }
+ VectorSet( angles, 0, modelPtr->angle, 0 );
+ AnglesToAxis( angles, ent.axis );
+
+ ent.hModel = item->asset;
+ VectorCopy( origin, ent.origin );
+ VectorCopy( origin, ent.lightingOrigin );
+ ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
+ VectorCopy( ent.origin, ent.oldorigin );
+
+ DC->addRefEntityToScene( &ent );
+ DC->renderScene( &refdef );
+
+}
+
+
+void Item_Image_Paint(itemDef_t *item) {
+ if (item == NULL) {
+ return;
+ }
+ DC->drawHandlePic(item->window.rect.x+1, item->window.rect.y+1, item->window.rect.w-2, item->window.rect.h-2, item->asset);
+}
+
+void Item_ListBox_Paint(itemDef_t *item) {
+ float x, y, size, thumb;
+ int count, i;
+ qhandle_t image;
+ qhandle_t optionalImage;
+ listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
+
+ // the listbox is horizontal or vertical and has a fixed size scroll bar going either direction
+ // elements are enumerated from the DC and either text or image handles are acquired from the DC as well
+ // textscale is used to size the text, textalignx and textaligny are used to size image elements
+ // there is no clipping available so only the last completely visible item is painted
+ count = DC->feederCount(item->special);
+ // default is vertical if horizontal flag is not here
+ if (item->window.flags & WINDOW_HORIZONTAL) {
+ // draw scrollbar in bottom of the window
+ // bar
+ x = item->window.rect.x + 1;
+ y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE - 1;
+ DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowLeft);
+ x += SCROLLBAR_SIZE - 1;
+ size = item->window.rect.w - (SCROLLBAR_SIZE * 2);
+ DC->drawHandlePic(x, y, size+1, SCROLLBAR_SIZE, DC->Assets.scrollBar);
+ x += size - 1;
+ DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowRight);
+ // thumb
+ thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
+ if (thumb > x - SCROLLBAR_SIZE - 1) {
+ thumb = x - SCROLLBAR_SIZE - 1;
+ }
+ DC->drawHandlePic(thumb, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
+ //
+ listPtr->endPos = listPtr->startPos;
+ size = item->window.rect.w - 2;
+ // items
+ // size contains max available space
+ if (listPtr->elementStyle == LISTBOX_IMAGE) {
+ // fit = 0;
+ x = item->window.rect.x + 1;
+ y = item->window.rect.y + 1;
+ for (i = listPtr->startPos; i < count; i++) {
+ // always draw at least one
+ // which may overdraw the box if it is too small for the element
+ image = DC->feederItemImage(item->special, i);
+ if (image) {
+ DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
+ }
+
+ if (i == item->cursorPos) {
+ DC->drawRect(x, y, listPtr->elementWidth-1, listPtr->elementHeight-1, item->window.borderSize, item->window.borderColor);
+ }
+
+ size -= listPtr->elementWidth;
+ if (size < listPtr->elementWidth) {
+ listPtr->drawPadding = size; //listPtr->elementWidth - size;
+ break;
+ }
+ x += listPtr->elementWidth;
+ listPtr->endPos++;
+ // fit++;
+ }
+ } else {
+ //
+ }
+ } else {
+ // draw scrollbar to right side of the window
+ x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE - 1;
+ y = item->window.rect.y + 1;
+ DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowUp);
+ y += SCROLLBAR_SIZE - 1;
+
+ listPtr->endPos = listPtr->startPos;
+ size = item->window.rect.h - (SCROLLBAR_SIZE * 2);
+ DC->drawHandlePic(x, y, SCROLLBAR_SIZE, size+1, DC->Assets.scrollBar);
+ y += size - 1;
+ DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowDown);
+ // thumb
+ thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
+ if (thumb > y - SCROLLBAR_SIZE - 1) {
+ thumb = y - SCROLLBAR_SIZE - 1;
+ }
+ DC->drawHandlePic(x, thumb, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
+
+ // adjust size for item painting
+ size = item->window.rect.h - 2;
+ if (listPtr->elementStyle == LISTBOX_IMAGE) {
+ // fit = 0;
+ x = item->window.rect.x + 1;
+ y = item->window.rect.y + 1;
+ for (i = listPtr->startPos; i < count; i++) {
+ // always draw at least one
+ // which may overdraw the box if it is too small for the element
+ image = DC->feederItemImage(item->special, i);
+ if (image) {
+ DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
+ }
+
+ if (i == item->cursorPos) {
+ DC->drawRect(x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, item->window.borderSize, item->window.borderColor);
+ }
+
+ listPtr->endPos++;
+ size -= listPtr->elementWidth;
+ if (size < listPtr->elementHeight) {
+ listPtr->drawPadding = listPtr->elementHeight - size;
+ break;
+ }
+ y += listPtr->elementHeight;
+ // fit++;
+ }
+ } else {
+ x = item->window.rect.x + 1;
+ y = item->window.rect.y + 1;
+ for (i = listPtr->startPos; i < count; i++) {
+ const char *text;
+ // always draw at least one
+ // which may overdraw the box if it is too small for the element
+
+ if (listPtr->numColumns > 0) {
+ int j;
+ for (j = 0; j < listPtr->numColumns; j++) {
+ text = DC->feederItemText(item->special, i, j, &optionalImage);
+ if (optionalImage >= 0) {
+ DC->drawHandlePic(x + 4 + listPtr->columnInfo[j].pos, y - 1 + listPtr->elementHeight / 2, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
+ } else if (text) {
+ DC->drawText(x + 4 + listPtr->columnInfo[j].pos, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, listPtr->columnInfo[j].maxChars, item->textStyle);
+ }
+ }
+ } else {
+ text = DC->feederItemText(item->special, i, 0, &optionalImage);
+ if (optionalImage >= 0) {
+ //DC->drawHandlePic(x + 4 + listPtr->elementHeight, y, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
+ } else if (text) {
+ DC->drawText(x + 4, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, 0, item->textStyle);
+ }
+ }
+
+ if (i == item->cursorPos) {
+ DC->fillRect(x + 2, y + 2, item->window.rect.w - SCROLLBAR_SIZE - 4, listPtr->elementHeight, item->window.outlineColor);
+ }
+
+ size -= listPtr->elementHeight;
+ if (size < listPtr->elementHeight) {
+ listPtr->drawPadding = listPtr->elementHeight - size;
+ break;
+ }
+ listPtr->endPos++;
+ y += listPtr->elementHeight;
+ // fit++;
+ }
+ }
+ }
+}
+
+
+void Item_OwnerDraw_Paint(itemDef_t *item) {
+ menuDef_t *parent;
+
+ if (item == NULL) {
+ return;
+ }
+ parent = (menuDef_t*)item->parent;
+
+ if (DC->ownerDrawItem) {
+ vec4_t color, lowLight;
+ menuDef_t *parent = (menuDef_t*)item->parent;
+ Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
+ memcpy(&color, &item->window.foreColor, sizeof(color));
+ if (item->numColors > 0 && DC->getValue) {
+ // if the value is within one of the ranges then set color to that, otherwise leave at default
+ int i;
+ float f = DC->getValue(item->window.ownerDraw);
+ for (i = 0; i < item->numColors; i++) {
+ if (f >= item->colorRanges[i].low && f <= item->colorRanges[i].high) {
+ memcpy(&color, &item->colorRanges[i].color, sizeof(color));
+ break;
+ }
+ }
+ }
+
+ if (item->window.flags & WINDOW_HASFOCUS) {
+ lowLight[0] = 0.8 * parent->focusColor[0];
+ lowLight[1] = 0.8 * parent->focusColor[1];
+ lowLight[2] = 0.8 * parent->focusColor[2];
+ lowLight[3] = 0.8 * parent->focusColor[3];
+ LerpColor(parent->focusColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
+ } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
+ lowLight[0] = 0.8 * item->window.foreColor[0];
+ lowLight[1] = 0.8 * item->window.foreColor[1];
+ lowLight[2] = 0.8 * item->window.foreColor[2];
+ lowLight[3] = 0.8 * item->window.foreColor[3];
+ LerpColor(item->window.foreColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
+ }
+
+ if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
+ Com_Memcpy(color, parent->disableColor, sizeof(vec4_t));
+ }
+
+ if (item->text) {
+ Item_Text_Paint(item);
+ if (item->text[0]) {
+ // +8 is an offset kludge to properly align owner draw items that have text combined with them
+ DC->ownerDrawItem(item->textRect.x + item->textRect.w + 8, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
+ } else {
+ DC->ownerDrawItem(item->textRect.x + item->textRect.w, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
+ }
+ } else {
+ DC->ownerDrawItem(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, item->textalignx, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
+ }
+ }
+}
+
+
+void Item_Paint(itemDef_t *item) {
+ vec4_t red;
+ menuDef_t *parent = (menuDef_t*)item->parent;
+ red[0] = red[3] = 1;
+ red[1] = red[2] = 0;
+
+ if (item == NULL) {
+ return;
+ }
+
+ if (item->window.flags & WINDOW_ORBITING) {
+ if (DC->realTime > item->window.nextTime) {
+ float rx, ry, a, c, s, w, h;
+
+ item->window.nextTime = DC->realTime + item->window.offsetTime;
+ // translate
+ w = item->window.rectClient.w / 2;
+ h = item->window.rectClient.h / 2;
+ rx = item->window.rectClient.x + w - item->window.rectEffects.x;
+ ry = item->window.rectClient.y + h - item->window.rectEffects.y;
+ a = 3 * M_PI / 180;
+ c = cos(a);
+ s = sin(a);
+ item->window.rectClient.x = (rx * c - ry * s) + item->window.rectEffects.x - w;
+ item->window.rectClient.y = (rx * s + ry * c) + item->window.rectEffects.y - h;
+ Item_UpdatePosition(item);
+
+ }
+ }
+
+
+ if (item->window.flags & WINDOW_INTRANSITION) {
+ if (DC->realTime > item->window.nextTime) {
+ int done = 0;
+ item->window.nextTime = DC->realTime + item->window.offsetTime;
+ // transition the x,y
+ if (item->window.rectClient.x == item->window.rectEffects.x) {
+ done++;
+ } else {
+ if (item->window.rectClient.x < item->window.rectEffects.x) {
+ item->window.rectClient.x += item->window.rectEffects2.x;
+ if (item->window.rectClient.x > item->window.rectEffects.x) {
+ item->window.rectClient.x = item->window.rectEffects.x;
+ done++;
+ }
+ } else {
+ item->window.rectClient.x -= item->window.rectEffects2.x;
+ if (item->window.rectClient.x < item->window.rectEffects.x) {
+ item->window.rectClient.x = item->window.rectEffects.x;
+ done++;
+ }
+ }
+ }
+ if (item->window.rectClient.y == item->window.rectEffects.y) {
+ done++;
+ } else {
+ if (item->window.rectClient.y < item->window.rectEffects.y) {
+ item->window.rectClient.y += item->window.rectEffects2.y;
+ if (item->window.rectClient.y > item->window.rectEffects.y) {
+ item->window.rectClient.y = item->window.rectEffects.y;
+ done++;
+ }
+ } else {
+ item->window.rectClient.y -= item->window.rectEffects2.y;
+ if (item->window.rectClient.y < item->window.rectEffects.y) {
+ item->window.rectClient.y = item->window.rectEffects.y;
+ done++;
+ }
+ }
+ }
+ if (item->window.rectClient.w == item->window.rectEffects.w) {
+ done++;
+ } else {
+ if (item->window.rectClient.w < item->window.rectEffects.w) {
+ item->window.rectClient.w += item->window.rectEffects2.w;
+ if (item->window.rectClient.w > item->window.rectEffects.w) {
+ item->window.rectClient.w = item->window.rectEffects.w;
+ done++;
+ }
+ } else {
+ item->window.rectClient.w -= item->window.rectEffects2.w;
+ if (item->window.rectClient.w < item->window.rectEffects.w) {
+ item->window.rectClient.w = item->window.rectEffects.w;
+ done++;
+ }
+ }
+ }
+ if (item->window.rectClient.h == item->window.rectEffects.h) {
+ done++;
+ } else {
+ if (item->window.rectClient.h < item->window.rectEffects.h) {
+ item->window.rectClient.h += item->window.rectEffects2.h;
+ if (item->window.rectClient.h > item->window.rectEffects.h) {
+ item->window.rectClient.h = item->window.rectEffects.h;
+ done++;
+ }
+ } else {
+ item->window.rectClient.h -= item->window.rectEffects2.h;
+ if (item->window.rectClient.h < item->window.rectEffects.h) {
+ item->window.rectClient.h = item->window.rectEffects.h;
+ done++;
+ }
+ }
+ }
+
+ Item_UpdatePosition(item);
+
+ if (done == 4) {
+ item->window.flags &= ~WINDOW_INTRANSITION;
+ }
+
+ }
+ }
+
+ if (item->window.ownerDrawFlags && DC->ownerDrawVisible) {
+ if (!DC->ownerDrawVisible(item->window.ownerDrawFlags)) {
+ item->window.flags &= ~WINDOW_VISIBLE;
+ } else {
+ item->window.flags |= WINDOW_VISIBLE;
+ }
+ }
+
+ if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE)) {
+ if (!Item_EnableShowViaCvar(item, CVAR_SHOW)) {
+ return;
+ }
+ }
+
+ if (item->window.flags & WINDOW_TIMEDVISIBLE) {
+
+ }
+
+ if (!(item->window.flags & WINDOW_VISIBLE)) {
+ return;
+ }
+
+ // paint the rect first..
+ Window_Paint(&item->window, parent->fadeAmount , parent->fadeClamp, parent->fadeCycle);
+
+ if (debugMode) {
+ vec4_t color;
+ rectDef_t *r = Item_CorrectedTextRect(item);
+ color[1] = color[3] = 1;
+ color[0] = color[2] = 0;
+ DC->drawRect(r->x, r->y, r->w, r->h, 1, color);
+ }
+
+ //DC->drawRect(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, 1, red);
+
+ switch (item->type) {
+ case ITEM_TYPE_OWNERDRAW:
+ Item_OwnerDraw_Paint(item);
+ break;
+ case ITEM_TYPE_TEXT:
+ case ITEM_TYPE_BUTTON:
+ Item_Text_Paint(item);
+ break;
+ case ITEM_TYPE_RADIOBUTTON:
+ break;
+ case ITEM_TYPE_CHECKBOX:
+ break;
+ case ITEM_TYPE_EDITFIELD:
+ case ITEM_TYPE_NUMERICFIELD:
+ Item_TextField_Paint(item);
+ break;
+ case ITEM_TYPE_COMBO:
+ break;
+ case ITEM_TYPE_LISTBOX:
+ Item_ListBox_Paint(item);
+ break;
+ //case ITEM_TYPE_IMAGE:
+ // Item_Image_Paint(item);
+ // break;
+ case ITEM_TYPE_MODEL:
+ Item_Model_Paint(item);
+ break;
+ case ITEM_TYPE_YESNO:
+ Item_YesNo_Paint(item);
+ break;
+ case ITEM_TYPE_MULTI:
+ Item_Multi_Paint(item);
+ break;
+ case ITEM_TYPE_BIND:
+ Item_Bind_Paint(item);
+ break;
+ case ITEM_TYPE_SLIDER:
+ Item_Slider_Paint(item);
+ break;
+ default:
+ break;
+ }
+
+}
+
+void Menu_Init(menuDef_t *menu) {
+ memset(menu, 0, sizeof(menuDef_t));
+ menu->cursorItem = -1;
+ menu->fadeAmount = DC->Assets.fadeAmount;
+ menu->fadeClamp = DC->Assets.fadeClamp;
+ menu->fadeCycle = DC->Assets.fadeCycle;
+ Window_Init(&menu->window);
+}
+
+itemDef_t *Menu_GetFocusedItem(menuDef_t *menu) {
+ int i;
+ if (menu) {
+ for (i = 0; i < menu->itemCount; i++) {
+ if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
+ return menu->items[i];
+ }
+ }
+ }
+ return NULL;
+}
+
+menuDef_t *Menu_GetFocused(void) {
+ int i;
+ for (i = 0; i < menuCount; i++) {
+ if (Menus[i].window.flags & WINDOW_HASFOCUS && Menus[i].window.flags & WINDOW_VISIBLE) {
+ return &Menus[i];
+ }
+ }
+ return NULL;
+}
+
+void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down) {
+ if (menu) {
+ int i;
+ for (i = 0; i < menu->itemCount; i++) {
+ if (menu->items[i]->special == feeder) {
+ Item_ListBox_HandleKey(menu->items[i], (down) ? K_DOWNARROW : K_UPARROW, qtrue, qtrue);
+ return;
+ }
+ }
+ }
+}
+
+
+
+void Menu_SetFeederSelection(menuDef_t *menu, int feeder, int index, const char *name) {
+ if (menu == NULL) {
+ if (name == NULL) {
+ menu = Menu_GetFocused();
+ } else {
+ menu = Menus_FindByName(name);
+ }
+ }
+
+ if (menu) {
+ int i;
+ for (i = 0; i < menu->itemCount; i++) {
+ if (menu->items[i]->special == feeder) {
+ if (index == 0) {
+ listBoxDef_t *listPtr = (listBoxDef_t*)menu->items[i]->typeData;
+ listPtr->cursorPos = 0;
+ listPtr->startPos = 0;
+ }
+ menu->items[i]->cursorPos = index;
+ DC->feederSelection(menu->items[i]->special, menu->items[i]->cursorPos);
+ return;
+ }
+ }
+ }
+}
+
+qboolean Menus_AnyFullScreenVisible(void) {
+ int i;
+ for (i = 0; i < menuCount; i++) {
+ if (Menus[i].window.flags & WINDOW_VISIBLE && Menus[i].fullScreen) {
+ return qtrue;
+ }
+ }
+ return qfalse;
+}
+
+menuDef_t *Menus_ActivateByName(const char *p) {
+ int i;
+ menuDef_t *m = NULL;
+ menuDef_t *focus = Menu_GetFocused();
+ for (i = 0; i < menuCount; i++) {
+ if (Q_stricmp(Menus[i].window.name, p) == 0) {
+ m = &Menus[i];
+ Menus_Activate(m);
+ if (openMenuCount < MAX_OPEN_MENUS && focus != NULL) {
+ menuStack[openMenuCount++] = focus;
+ }
+ } else {
+ Menus[i].window.flags &= ~WINDOW_HASFOCUS;
+ }
+ }
+ Display_CloseCinematics();
+ return m;
+}
+
+
+void Item_Init(itemDef_t *item) {
+ memset(item, 0, sizeof(itemDef_t));
+ item->textscale = 0.55f;
+ Window_Init(&item->window);
+}
+
+void Menu_HandleMouseMove(menuDef_t *menu, float x, float y) {
+ int i, pass;
+ qboolean focusSet = qfalse;
+
+ itemDef_t *overItem;
+ if (menu == NULL) {
+ return;
+ }
+
+ if (!(menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
+ return;
+ }
+
+ if (itemCapture) {
+ //Item_MouseMove(itemCapture, x, y);
+ return;
+ }
+
+ if (g_waitingForKey || g_editingField) {
+ return;
+ }
+
+ // FIXME: this is the whole issue of focus vs. mouse over..
+ // need a better overall solution as i don't like going through everything twice
+ for (pass = 0; pass < 2; pass++) {
+ for (i = 0; i < menu->itemCount; i++) {
+ // turn off focus each item
+ // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
+
+ if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
+ continue;
+ }
+
+ // items can be enabled and disabled based on cvars
+ if (menu->items[i]->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_ENABLE)) {
+ continue;
+ }
+
+ if (menu->items[i]->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_SHOW)) {
+ continue;
+ }
+
+
+
+ if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
+ if (pass == 1) {
+ overItem = menu->items[i];
+ if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
+ if (!Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
+ continue;
+ }
+ }
+ // if we are over an item
+ if (IsVisible(overItem->window.flags)) {
+ // different one
+ Item_MouseEnter(overItem, x, y);
+ // Item_SetMouseOver(overItem, qtrue);
+
+ // if item is not a decoration see if it can take focus
+ if (!focusSet) {
+ focusSet = Item_SetFocus(overItem, x, y);
+ }
+ }
+ }
+ } else if (menu->items[i]->window.flags & WINDOW_MOUSEOVER) {
+ Item_MouseLeave(menu->items[i]);
+ Item_SetMouseOver(menu->items[i], qfalse);
+ }
+ }
+ }
+
+}
+
+void Menu_Paint(menuDef_t *menu, qboolean forcePaint) {
+ int i;
+
+ if (menu == NULL) {
+ return;
+ }
+
+ if (!(menu->window.flags & WINDOW_VISIBLE) && !forcePaint) {
+ return;
+ }
+
+ if (menu->window.ownerDrawFlags && DC->ownerDrawVisible && !DC->ownerDrawVisible(menu->window.ownerDrawFlags)) {
+ return;
+ }
+
+ if (forcePaint) {
+ menu->window.flags |= WINDOW_FORCED;
+ }
+
+ // draw the background if necessary
+ if (menu->fullScreen) {
+ // implies a background shader
+ // FIXME: make sure we have a default shader if fullscreen is set with no background
+ DC->drawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, menu->window.background );
+ } else if (menu->window.background) {
+ // this allows a background shader without being full screen
+ //UI_DrawHandlePic(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, menu->backgroundShader);
+ }
+
+ // paint the background and or border
+ Window_Paint(&menu->window, menu->fadeAmount, menu->fadeClamp, menu->fadeCycle );
+
+ for (i = 0; i < menu->itemCount; i++) {
+ Item_Paint(menu->items[i]);
+ }
+
+ if (debugMode) {
+ vec4_t color;
+ color[0] = color[2] = color[3] = 1;
+ color[1] = 0;
+ DC->drawRect(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, 1, color);
+ }
+}
+
+/*
+===============
+Item_ValidateTypeData
+===============
+*/
+void Item_ValidateTypeData(itemDef_t *item) {
+ if (item->typeData) {
+ return;
+ }
+
+ if (item->type == ITEM_TYPE_LISTBOX) {
+ item->typeData = UI_Alloc(sizeof(listBoxDef_t));
+ memset(item->typeData, 0, sizeof(listBoxDef_t));
+ } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD || item->type == ITEM_TYPE_YESNO || item->type == ITEM_TYPE_BIND || item->type == ITEM_TYPE_SLIDER || item->type == ITEM_TYPE_TEXT) {
+ item->typeData = UI_Alloc(sizeof(editFieldDef_t));
+ memset(item->typeData, 0, sizeof(editFieldDef_t));
+ if (item->type == ITEM_TYPE_EDITFIELD) {
+ if (!((editFieldDef_t *) item->typeData)->maxPaintChars) {
+ ((editFieldDef_t *) item->typeData)->maxPaintChars = MAX_EDITFIELD;
+ }
+ }
+ } else if (item->type == ITEM_TYPE_MULTI) {
+ item->typeData = UI_Alloc(sizeof(multiDef_t));
+ } else if (item->type == ITEM_TYPE_MODEL) {
+ item->typeData = UI_Alloc(sizeof(modelDef_t));
+ }
+}
+
+/*
+===============
+Keyword Hash
+===============
+*/
+
+#define KEYWORDHASH_SIZE 512
+
+typedef struct keywordHash_s
+{
+ char *keyword;
+ qboolean (*func)(itemDef_t *item, int handle);
+ struct keywordHash_s *next;
+} keywordHash_t;
+
+int KeywordHash_Key(char *keyword) {
+ int register hash, i;
+
+ hash = 0;
+ for (i = 0; keyword[i] != '\0'; i++) {
+ if (keyword[i] >= 'A' && keyword[i] <= 'Z')
+ hash += (keyword[i] + ('a' - 'A')) * (119 + i);
+ else
+ hash += keyword[i] * (119 + i);
+ }
+ hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (KEYWORDHASH_SIZE-1);
+ return hash;
+}
+
+void KeywordHash_Add(keywordHash_t *table[], keywordHash_t *key) {
+ int hash;
+
+ hash = KeywordHash_Key(key->keyword);
+/*
+ if (table[hash]) {
+ int collision = qtrue;
+ }
+*/
+ key->next = table[hash];
+ table[hash] = key;
+}
+
+keywordHash_t *KeywordHash_Find(keywordHash_t *table[], char *keyword)
+{
+ keywordHash_t *key;
+ int hash;
+
+ hash = KeywordHash_Key(keyword);
+ for (key = table[hash]; key; key = key->next) {
+ if (!Q_stricmp(key->keyword, keyword))
+ return key;
+ }
+ return NULL;
+}
+
+/*
+===============
+Item Keyword Parse functions
+===============
+*/
+
+// name <string>
+qboolean ItemParse_name( itemDef_t *item, int handle ) {
+ if (!PC_String_Parse(handle, &item->window.name)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+// name <string>
+qboolean ItemParse_focusSound( itemDef_t *item, int handle ) {
+ const char *temp;
+ if (!PC_String_Parse(handle, &temp)) {
+ return qfalse;
+ }
+ item->focusSound = DC->registerSound(temp, qfalse);
+ return qtrue;
+}
+
+
+// text <string>
+qboolean ItemParse_text( itemDef_t *item, int handle ) {
+ if (!PC_String_Parse(handle, &item->text)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+// group <string>
+qboolean ItemParse_group( itemDef_t *item, int handle ) {
+ if (!PC_String_Parse(handle, &item->window.group)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+// asset_model <string>
+qboolean ItemParse_asset_model( itemDef_t *item, int handle ) {
+ const char *temp;
+ modelDef_t *modelPtr;
+ Item_ValidateTypeData(item);
+ modelPtr = (modelDef_t*)item->typeData;
+
+ if (!PC_String_Parse(handle, &temp)) {
+ return qfalse;
+ }
+ item->asset = DC->registerModel(temp);
+ modelPtr->angle = rand() % 360;
+ return qtrue;
+}
+
+// asset_shader <string>
+qboolean ItemParse_asset_shader( itemDef_t *item, int handle ) {
+ const char *temp;
+
+ if (!PC_String_Parse(handle, &temp)) {
+ return qfalse;
+ }
+ item->asset = DC->registerShaderNoMip(temp);
+ return qtrue;
+}
+
+// model_origin <number> <number> <number>
+qboolean ItemParse_model_origin( itemDef_t *item, int handle ) {
+ modelDef_t *modelPtr;
+ Item_ValidateTypeData(item);
+ modelPtr = (modelDef_t*)item->typeData;
+
+ if (PC_Float_Parse(handle, &modelPtr->origin[0])) {
+ if (PC_Float_Parse(handle, &modelPtr->origin[1])) {
+ if (PC_Float_Parse(handle, &modelPtr->origin[2])) {
+ return qtrue;
+ }
+ }
+ }
+ return qfalse;
+}
+
+// model_fovx <number>
+qboolean ItemParse_model_fovx( itemDef_t *item, int handle ) {
+ modelDef_t *modelPtr;
+ Item_ValidateTypeData(item);
+ modelPtr = (modelDef_t*)item->typeData;
+
+ if (!PC_Float_Parse(handle, &modelPtr->fov_x)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+// model_fovy <number>
+qboolean ItemParse_model_fovy( itemDef_t *item, int handle ) {
+ modelDef_t *modelPtr;
+ Item_ValidateTypeData(item);
+ modelPtr = (modelDef_t*)item->typeData;
+
+ if (!PC_Float_Parse(handle, &modelPtr->fov_y)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+// model_rotation <integer>
+qboolean ItemParse_model_rotation( itemDef_t *item, int handle ) {
+ modelDef_t *modelPtr;
+ Item_ValidateTypeData(item);
+ modelPtr = (modelDef_t*)item->typeData;
+
+ if (!PC_Int_Parse(handle, &modelPtr->rotationSpeed)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+// model_angle <integer>
+qboolean ItemParse_model_angle( itemDef_t *item, int handle ) {
+ modelDef_t *modelPtr;
+ Item_ValidateTypeData(item);
+ modelPtr = (modelDef_t*)item->typeData;
+
+ if (!PC_Int_Parse(handle, &modelPtr->angle)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+// rect <rectangle>
+qboolean ItemParse_rect( itemDef_t *item, int handle ) {
+ if (!PC_Rect_Parse(handle, &item->window.rectClient)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+// style <integer>
+qboolean ItemParse_style( itemDef_t *item, int handle ) {
+ if (!PC_Int_Parse(handle, &item->window.style)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+// decoration
+qboolean ItemParse_decoration( itemDef_t *item, int handle ) {
+ item->window.flags |= WINDOW_DECORATION;
+ return qtrue;
+}
+
+// notselectable
+qboolean ItemParse_notselectable( itemDef_t *item, int handle ) {
+ listBoxDef_t *listPtr;
+ Item_ValidateTypeData(item);
+ listPtr = (listBoxDef_t*)item->typeData;
+ if (item->type == ITEM_TYPE_LISTBOX && listPtr) {
+ listPtr->notselectable = qtrue;
+ }
+ return qtrue;
+}
+
+// manually wrapped
+qboolean ItemParse_wrapped( itemDef_t *item, int handle ) {
+ item->window.flags |= WINDOW_WRAPPED;
+ return qtrue;
+}
+
+// auto wrapped
+qboolean ItemParse_autowrapped( itemDef_t *item, int handle ) {
+ item->window.flags |= WINDOW_AUTOWRAPPED;
+ return qtrue;
+}
+
+
+// horizontalscroll
+qboolean ItemParse_horizontalscroll( itemDef_t *item, int handle ) {
+ item->window.flags |= WINDOW_HORIZONTAL;
+ return qtrue;
+}
+
+// type <integer>
+qboolean ItemParse_type( itemDef_t *item, int handle ) {
+ if (!PC_Int_Parse(handle, &item->type)) {
+ return qfalse;
+ }
+ Item_ValidateTypeData(item);
+ return qtrue;
+}
+
+// elementwidth, used for listbox image elements
+// uses textalignx for storage
+qboolean ItemParse_elementwidth( itemDef_t *item, int handle ) {
+ listBoxDef_t *listPtr;
+
+ Item_ValidateTypeData(item);
+ listPtr = (listBoxDef_t*)item->typeData;
+ if (!PC_Float_Parse(handle, &listPtr->elementWidth)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+// elementheight, used for listbox image elements
+// uses textaligny for storage
+qboolean ItemParse_elementheight( itemDef_t *item, int handle ) {
+ listBoxDef_t *listPtr;
+
+ Item_ValidateTypeData(item);
+ listPtr = (listBoxDef_t*)item->typeData;
+ if (!PC_Float_Parse(handle, &listPtr->elementHeight)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+// feeder <float>
+qboolean ItemParse_feeder( itemDef_t *item, int handle ) {
+ if (!PC_Float_Parse(handle, &item->special)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+// elementtype, used to specify what type of elements a listbox contains
+// uses textstyle for storage
+qboolean ItemParse_elementtype( itemDef_t *item, int handle ) {
+ listBoxDef_t *listPtr;
+
+ Item_ValidateTypeData(item);
+ if (!item->typeData)
+ return qfalse;
+ listPtr = (listBoxDef_t*)item->typeData;
+ if (!PC_Int_Parse(handle, &listPtr->elementStyle)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+// columns sets a number of columns and an x pos and width per..
+qboolean ItemParse_columns( itemDef_t *item, int handle ) {
+ int num, i;
+ listBoxDef_t *listPtr;
+
+ Item_ValidateTypeData(item);
+ if (!item->typeData)
+ return qfalse;
+ listPtr = (listBoxDef_t*)item->typeData;
+ if (PC_Int_Parse(handle, &num)) {
+ if (num > MAX_LB_COLUMNS) {
+ num = MAX_LB_COLUMNS;
+ }
+ listPtr->numColumns = num;
+ for (i = 0; i < num; i++) {
+ int pos, width, maxChars;
+
+ if (PC_Int_Parse(handle, &pos) && PC_Int_Parse(handle, &width) && PC_Int_Parse(handle, &maxChars)) {
+ listPtr->columnInfo[i].pos = pos;
+ listPtr->columnInfo[i].width = width;
+ listPtr->columnInfo[i].maxChars = maxChars;
+ } else {
+ return qfalse;
+ }
+ }
+ } else {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_border( itemDef_t *item, int handle ) {
+ if (!PC_Int_Parse(handle, &item->window.border)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_bordersize( itemDef_t *item, int handle ) {
+ if (!PC_Float_Parse(handle, &item->window.borderSize)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_visible( itemDef_t *item, int handle ) {
+ int i;
+
+ if (!PC_Int_Parse(handle, &i)) {
+ return qfalse;
+ }
+ if (i) {
+ item->window.flags |= WINDOW_VISIBLE;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_ownerdraw( itemDef_t *item, int handle ) {
+ if (!PC_Int_Parse(handle, &item->window.ownerDraw)) {
+ return qfalse;
+ }
+ item->type = ITEM_TYPE_OWNERDRAW;
+ return qtrue;
+}
+
+qboolean ItemParse_align( itemDef_t *item, int handle ) {
+ if (!PC_Int_Parse(handle, &item->alignment)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_textalign( itemDef_t *item, int handle ) {
+ if (!PC_Int_Parse(handle, &item->textalignment)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_textalignx( itemDef_t *item, int handle ) {
+ if (!PC_Float_Parse(handle, &item->textalignx)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_textaligny( itemDef_t *item, int handle ) {
+ if (!PC_Float_Parse(handle, &item->textaligny)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_textscale( itemDef_t *item, int handle ) {
+ if (!PC_Float_Parse(handle, &item->textscale)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_textstyle( itemDef_t *item, int handle ) {
+ if (!PC_Int_Parse(handle, &item->textStyle)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_backcolor( itemDef_t *item, int handle ) {
+ int i;
+ float f;
+
+ for (i = 0; i < 4; i++) {
+ if (!PC_Float_Parse(handle, &f)) {
+ return qfalse;
+ }
+ item->window.backColor[i] = f;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_forecolor( itemDef_t *item, int handle ) {
+ int i;
+ float f;
+
+ for (i = 0; i < 4; i++) {
+ if (!PC_Float_Parse(handle, &f)) {
+ return qfalse;
+ }
+ item->window.foreColor[i] = f;
+ item->window.flags |= WINDOW_FORECOLORSET;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_bordercolor( itemDef_t *item, int handle ) {
+ int i;
+ float f;
+
+ for (i = 0; i < 4; i++) {
+ if (!PC_Float_Parse(handle, &f)) {
+ return qfalse;
+ }
+ item->window.borderColor[i] = f;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_outlinecolor( itemDef_t *item, int handle ) {
+ if (!PC_Color_Parse(handle, &item->window.outlineColor)){
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_background( itemDef_t *item, int handle ) {
+ const char *temp;
+
+ if (!PC_String_Parse(handle, &temp)) {
+ return qfalse;
+ }
+ item->window.background = DC->registerShaderNoMip(temp);
+ return qtrue;
+}
+
+qboolean ItemParse_cinematic( itemDef_t *item, int handle ) {
+ if (!PC_String_Parse(handle, &item->window.cinematicName)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_doubleClick( itemDef_t *item, int handle ) {
+ listBoxDef_t *listPtr;
+
+ Item_ValidateTypeData(item);
+ if (!item->typeData) {
+ return qfalse;
+ }
+
+ listPtr = (listBoxDef_t*)item->typeData;
+
+ if (!PC_Script_Parse(handle, &listPtr->doubleClick)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_onFocus( itemDef_t *item, int handle ) {
+ if (!PC_Script_Parse(handle, &item->onFocus)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_leaveFocus( itemDef_t *item, int handle ) {
+ if (!PC_Script_Parse(handle, &item->leaveFocus)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_mouseEnter( itemDef_t *item, int handle ) {
+ if (!PC_Script_Parse(handle, &item->mouseEnter)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_mouseExit( itemDef_t *item, int handle ) {
+ if (!PC_Script_Parse(handle, &item->mouseExit)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_mouseEnterText( itemDef_t *item, int handle ) {
+ if (!PC_Script_Parse(handle, &item->mouseEnterText)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_mouseExitText( itemDef_t *item, int handle ) {
+ if (!PC_Script_Parse(handle, &item->mouseExitText)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_action( itemDef_t *item, int handle ) {
+ if (!PC_Script_Parse(handle, &item->action)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_special( itemDef_t *item, int handle ) {
+ if (!PC_Float_Parse(handle, &item->special)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_cvarTest( itemDef_t *item, int handle ) {
+ if (!PC_String_Parse(handle, &item->cvarTest)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_cvar( itemDef_t *item, int handle ) {
+ editFieldDef_t *editPtr;
+
+ Item_ValidateTypeData(item);
+ if (!PC_String_Parse(handle, &item->cvar)) {
+ return qfalse;
+ }
+ if (item->typeData) {
+ editPtr = (editFieldDef_t*)item->typeData;
+ editPtr->minVal = -1;
+ editPtr->maxVal = -1;
+ editPtr->defVal = -1;
+ }
+ return qtrue;
+}
+
+qboolean ItemParse_maxChars( itemDef_t *item, int handle ) {
+ editFieldDef_t *editPtr;
+ int maxChars;
+
+ Item_ValidateTypeData(item);
+ if (!item->typeData)
+ return qfalse;
+
+ if (!PC_Int_Parse(handle, &maxChars)) {
+ return qfalse;
+ }
+ editPtr = (editFieldDef_t*)item->typeData;
+ editPtr->maxChars = maxChars;
+ return qtrue;
+}
+
+qboolean ItemParse_maxPaintChars( itemDef_t *item, int handle ) {
+ editFieldDef_t *editPtr;
+ int maxChars;
+
+ Item_ValidateTypeData(item);
+ if (!item->typeData)
+ return qfalse;
+
+ if (!PC_Int_Parse(handle, &maxChars)) {
+ return qfalse;
+ }
+ editPtr = (editFieldDef_t*)item->typeData;
+ editPtr->maxPaintChars = maxChars;
+ return qtrue;
+}
+
+
+
+qboolean ItemParse_cvarFloat( itemDef_t *item, int handle ) {
+ editFieldDef_t *editPtr;
+
+ Item_ValidateTypeData(item);
+ if (!item->typeData)
+ return qfalse;
+ editPtr = (editFieldDef_t*)item->typeData;
+ if (PC_String_Parse(handle, &item->cvar) &&
+ PC_Float_Parse(handle, &editPtr->defVal) &&
+ PC_Float_Parse(handle, &editPtr->minVal) &&
+ PC_Float_Parse(handle, &editPtr->maxVal)) {
+ return qtrue;
+ }
+ return qfalse;
+}
+
+qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) {
+ pc_token_t token;
+ multiDef_t *multiPtr;
+ int pass;
+
+ Item_ValidateTypeData(item);
+ if (!item->typeData)
+ return qfalse;
+ multiPtr = (multiDef_t*)item->typeData;
+ multiPtr->count = 0;
+ multiPtr->strDef = qtrue;
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+ if (*token.string != '{') {
+ return qfalse;
+ }
+
+ pass = 0;
+ while ( 1 ) {
+ if (!trap_PC_ReadToken(handle, &token)) {
+ PC_SourceError(handle, "end of file inside menu item\n");
+ return qfalse;
+ }
+
+ if (*token.string == '}') {
+ return qtrue;
+ }
+
+ if (*token.string == ',' || *token.string == ';') {
+ continue;
+ }
+
+ if (pass == 0) {
+ multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
+ pass = 1;
+ } else {
+ multiPtr->cvarStr[multiPtr->count] = String_Alloc(token.string);
+ pass = 0;
+ multiPtr->count++;
+ if (multiPtr->count >= MAX_MULTI_CVARS) {
+ return qfalse;
+ }
+ }
+
+ }
+ return qfalse; // bk001205 - LCC missing return value
+}
+
+qboolean ItemParse_cvarFloatList( itemDef_t *item, int handle ) {
+ pc_token_t token;
+ multiDef_t *multiPtr;
+
+ Item_ValidateTypeData(item);
+ if (!item->typeData)
+ return qfalse;
+ multiPtr = (multiDef_t*)item->typeData;
+ multiPtr->count = 0;
+ multiPtr->strDef = qfalse;
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+ if (*token.string != '{') {
+ return qfalse;
+ }
+
+ while ( 1 ) {
+ if (!trap_PC_ReadToken(handle, &token)) {
+ PC_SourceError(handle, "end of file inside menu item\n");
+ return qfalse;
+ }
+
+ if (*token.string == '}') {
+ return qtrue;
+ }
+
+ if (*token.string == ',' || *token.string == ';') {
+ continue;
+ }
+
+ multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
+ if (!PC_Float_Parse(handle, &multiPtr->cvarValue[multiPtr->count])) {
+ return qfalse;
+ }
+
+ multiPtr->count++;
+ if (multiPtr->count >= MAX_MULTI_CVARS) {
+ return qfalse;
+ }
+
+ }
+ return qfalse; // bk001205 - LCC missing return value
+}
+
+
+
+qboolean ItemParse_addColorRange( itemDef_t *item, int handle ) {
+ colorRangeDef_t color;
+
+ if (PC_Float_Parse(handle, &color.low) &&
+ PC_Float_Parse(handle, &color.high) &&
+ PC_Color_Parse(handle, &color.color) ) {
+ if (item->numColors < MAX_COLOR_RANGES) {
+ memcpy(&item->colorRanges[item->numColors], &color, sizeof(color));
+ item->numColors++;
+ }
+ return qtrue;
+ }
+ return qfalse;
+}
+
+qboolean ItemParse_ownerdrawFlag( itemDef_t *item, int handle ) {
+ int i;
+ if (!PC_Int_Parse(handle, &i)) {
+ return qfalse;
+ }
+ item->window.ownerDrawFlags |= i;
+ return qtrue;
+}
+
+qboolean ItemParse_enableCvar( itemDef_t *item, int handle ) {
+ if (PC_Script_Parse(handle, &item->enableCvar)) {
+ item->cvarFlags = CVAR_ENABLE;
+ return qtrue;
+ }
+ return qfalse;
+}
+
+qboolean ItemParse_disableCvar( itemDef_t *item, int handle ) {
+ if (PC_Script_Parse(handle, &item->enableCvar)) {
+ item->cvarFlags = CVAR_DISABLE;
+ return qtrue;
+ }
+ return qfalse;
+}
+
+qboolean ItemParse_showCvar( itemDef_t *item, int handle ) {
+ if (PC_Script_Parse(handle, &item->enableCvar)) {
+ item->cvarFlags = CVAR_SHOW;
+ return qtrue;
+ }
+ return qfalse;
+}
+
+qboolean ItemParse_hideCvar( itemDef_t *item, int handle ) {
+ if (PC_Script_Parse(handle, &item->enableCvar)) {
+ item->cvarFlags = CVAR_HIDE;
+ return qtrue;
+ }
+ return qfalse;
+}
+
+
+keywordHash_t itemParseKeywords[] = {
+ {"name", ItemParse_name, NULL},
+ {"text", ItemParse_text, NULL},
+ {"group", ItemParse_group, NULL},
+ {"asset_model", ItemParse_asset_model, NULL},
+ {"asset_shader", ItemParse_asset_shader, NULL},
+ {"model_origin", ItemParse_model_origin, NULL},
+ {"model_fovx", ItemParse_model_fovx, NULL},
+ {"model_fovy", ItemParse_model_fovy, NULL},
+ {"model_rotation", ItemParse_model_rotation, NULL},
+ {"model_angle", ItemParse_model_angle, NULL},
+ {"rect", ItemParse_rect, NULL},
+ {"style", ItemParse_style, NULL},
+ {"decoration", ItemParse_decoration, NULL},
+ {"notselectable", ItemParse_notselectable, NULL},
+ {"wrapped", ItemParse_wrapped, NULL},
+ {"autowrapped", ItemParse_autowrapped, NULL},
+ {"horizontalscroll", ItemParse_horizontalscroll, NULL},
+ {"type", ItemParse_type, NULL},
+ {"elementwidth", ItemParse_elementwidth, NULL},
+ {"elementheight", ItemParse_elementheight, NULL},
+ {"feeder", ItemParse_feeder, NULL},
+ {"elementtype", ItemParse_elementtype, NULL},
+ {"columns", ItemParse_columns, NULL},
+ {"border", ItemParse_border, NULL},
+ {"bordersize", ItemParse_bordersize, NULL},
+ {"visible", ItemParse_visible, NULL},
+ {"ownerdraw", ItemParse_ownerdraw, NULL},
+ {"align", ItemParse_align, NULL},
+ {"textalign", ItemParse_textalign, NULL},
+ {"textalignx", ItemParse_textalignx, NULL},
+ {"textaligny", ItemParse_textaligny, NULL},
+ {"textscale", ItemParse_textscale, NULL},
+ {"textstyle", ItemParse_textstyle, NULL},
+ {"backcolor", ItemParse_backcolor, NULL},
+ {"forecolor", ItemParse_forecolor, NULL},
+ {"bordercolor", ItemParse_bordercolor, NULL},
+ {"outlinecolor", ItemParse_outlinecolor, NULL},
+ {"background", ItemParse_background, NULL},
+ {"onFocus", ItemParse_onFocus, NULL},
+ {"leaveFocus", ItemParse_leaveFocus, NULL},
+ {"mouseEnter", ItemParse_mouseEnter, NULL},
+ {"mouseExit", ItemParse_mouseExit, NULL},
+ {"mouseEnterText", ItemParse_mouseEnterText, NULL},
+ {"mouseExitText", ItemParse_mouseExitText, NULL},
+ {"action", ItemParse_action, NULL},
+ {"special", ItemParse_special, NULL},
+ {"cvar", ItemParse_cvar, NULL},
+ {"maxChars", ItemParse_maxChars, NULL},
+ {"maxPaintChars", ItemParse_maxPaintChars, NULL},
+ {"focusSound", ItemParse_focusSound, NULL},
+ {"cvarFloat", ItemParse_cvarFloat, NULL},
+ {"cvarStrList", ItemParse_cvarStrList, NULL},
+ {"cvarFloatList", ItemParse_cvarFloatList, NULL},
+ {"addColorRange", ItemParse_addColorRange, NULL},
+ {"ownerdrawFlag", ItemParse_ownerdrawFlag, NULL},
+ {"enableCvar", ItemParse_enableCvar, NULL},
+ {"cvarTest", ItemParse_cvarTest, NULL},
+ {"disableCvar", ItemParse_disableCvar, NULL},
+ {"showCvar", ItemParse_showCvar, NULL},
+ {"hideCvar", ItemParse_hideCvar, NULL},
+ {"cinematic", ItemParse_cinematic, NULL},
+ {"doubleclick", ItemParse_doubleClick, NULL},
+ {NULL, 0, NULL}
+};
+
+keywordHash_t *itemParseKeywordHash[KEYWORDHASH_SIZE];
+
+/*
+===============
+Item_SetupKeywordHash
+===============
+*/
+void Item_SetupKeywordHash(void) {
+ int i;
+
+ memset(itemParseKeywordHash, 0, sizeof(itemParseKeywordHash));
+ for (i = 0; itemParseKeywords[i].keyword; i++) {
+ KeywordHash_Add(itemParseKeywordHash, &itemParseKeywords[i]);
+ }
+}
+
+/*
+===============
+Item_Parse
+===============
+*/
+qboolean Item_Parse(int handle, itemDef_t *item) {
+ pc_token_t token;
+ keywordHash_t *key;
+
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+ if (*token.string != '{') {
+ return qfalse;
+ }
+ while ( 1 ) {
+ if (!trap_PC_ReadToken(handle, &token)) {
+ PC_SourceError(handle, "end of file inside menu item\n");
+ return qfalse;
+ }
+
+ if (*token.string == '}') {
+ return qtrue;
+ }
+
+ key = KeywordHash_Find(itemParseKeywordHash, token.string);
+ if (!key) {
+ PC_SourceError(handle, "unknown menu item keyword %s", token.string);
+ continue;
+ }
+ if ( !key->func(item, handle) ) {
+ PC_SourceError(handle, "couldn't parse menu item keyword %s", token.string);
+ return qfalse;
+ }
+ }
+ return qfalse; // bk001205 - LCC missing return value
+}
+
+
+// Item_InitControls
+// init's special control types
+void Item_InitControls(itemDef_t *item) {
+ if (item == NULL) {
+ return;
+ }
+ if (item->type == ITEM_TYPE_LISTBOX) {
+ listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
+ item->cursorPos = 0;
+ if (listPtr) {
+ listPtr->cursorPos = 0;
+ listPtr->startPos = 0;
+ listPtr->endPos = 0;
+ listPtr->cursorPos = 0;
+ }
+ }
+}
+
+/*
+===============
+Menu Keyword Parse functions
+===============
+*/
+
+qboolean MenuParse_font( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+ if (!PC_String_Parse(handle, &menu->font)) {
+ return qfalse;
+ }
+ if (!DC->Assets.fontRegistered) {
+ DC->registerFont(menu->font, 48, &DC->Assets.textFont);
+ DC->Assets.fontRegistered = qtrue;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_name( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+ if (!PC_String_Parse(handle, &menu->window.name)) {
+ return qfalse;
+ }
+ if (Q_stricmp(menu->window.name, "main") == 0) {
+ // default main as having focus
+ //menu->window.flags |= WINDOW_HASFOCUS;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_fullscreen( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+ if (!PC_Int_Parse(handle, (int*) &menu->fullScreen)) { // bk001206 - cast qboolean
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_rect( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+ if (!PC_Rect_Parse(handle, &menu->window.rect)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_style( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+ if (!PC_Int_Parse(handle, &menu->window.style)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_visible( itemDef_t *item, int handle ) {
+ int i;
+ menuDef_t *menu = (menuDef_t*)item;
+
+ if (!PC_Int_Parse(handle, &i)) {
+ return qfalse;
+ }
+ if (i) {
+ menu->window.flags |= WINDOW_VISIBLE;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_onOpen( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+ if (!PC_Script_Parse(handle, &menu->onOpen)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_onClose( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+ if (!PC_Script_Parse(handle, &menu->onClose)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_onESC( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+ if (!PC_Script_Parse(handle, &menu->onESC)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+
+
+qboolean MenuParse_border( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+ if (!PC_Int_Parse(handle, &menu->window.border)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_borderSize( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+ if (!PC_Float_Parse(handle, &menu->window.borderSize)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_backcolor( itemDef_t *item, int handle ) {
+ int i;
+ float f;
+ menuDef_t *menu = (menuDef_t*)item;
+
+ for (i = 0; i < 4; i++) {
+ if (!PC_Float_Parse(handle, &f)) {
+ return qfalse;
+ }
+ menu->window.backColor[i] = f;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_forecolor( itemDef_t *item, int handle ) {
+ int i;
+ float f;
+ menuDef_t *menu = (menuDef_t*)item;
+
+ for (i = 0; i < 4; i++) {
+ if (!PC_Float_Parse(handle, &f)) {
+ return qfalse;
+ }
+ menu->window.foreColor[i] = f;
+ menu->window.flags |= WINDOW_FORECOLORSET;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_bordercolor( itemDef_t *item, int handle ) {
+ int i;
+ float f;
+ menuDef_t *menu = (menuDef_t*)item;
+
+ for (i = 0; i < 4; i++) {
+ if (!PC_Float_Parse(handle, &f)) {
+ return qfalse;
+ }
+ menu->window.borderColor[i] = f;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_focuscolor( itemDef_t *item, int handle ) {
+ int i;
+ float f;
+ menuDef_t *menu = (menuDef_t*)item;
+
+ for (i = 0; i < 4; i++) {
+ if (!PC_Float_Parse(handle, &f)) {
+ return qfalse;
+ }
+ menu->focusColor[i] = f;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_disablecolor( itemDef_t *item, int handle ) {
+ int i;
+ float f;
+ menuDef_t *menu = (menuDef_t*)item;
+ for (i = 0; i < 4; i++) {
+ if (!PC_Float_Parse(handle, &f)) {
+ return qfalse;
+ }
+ menu->disableColor[i] = f;
+ }
+ return qtrue;
+}
+
+
+qboolean MenuParse_outlinecolor( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+ if (!PC_Color_Parse(handle, &menu->window.outlineColor)){
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_background( itemDef_t *item, int handle ) {
+ const char *buff;
+ menuDef_t *menu = (menuDef_t*)item;
+
+ if (!PC_String_Parse(handle, &buff)) {
+ return qfalse;
+ }
+ menu->window.background = DC->registerShaderNoMip(buff);
+ return qtrue;
+}
+
+qboolean MenuParse_cinematic( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+
+ if (!PC_String_Parse(handle, &menu->window.cinematicName)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_ownerdrawFlag( itemDef_t *item, int handle ) {
+ int i;
+ menuDef_t *menu = (menuDef_t*)item;
+
+ if (!PC_Int_Parse(handle, &i)) {
+ return qfalse;
+ }
+ menu->window.ownerDrawFlags |= i;
+ return qtrue;
+}
+
+qboolean MenuParse_ownerdraw( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+
+ if (!PC_Int_Parse(handle, &menu->window.ownerDraw)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+
+// decoration
+qboolean MenuParse_popup( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+ menu->window.flags |= WINDOW_POPUP;
+ return qtrue;
+}
+
+
+qboolean MenuParse_outOfBounds( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+
+ menu->window.flags |= WINDOW_OOB_CLICK;
+ return qtrue;
+}
+
+qboolean MenuParse_soundLoop( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+
+ if (!PC_String_Parse(handle, &menu->soundName)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_fadeClamp( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+
+ if (!PC_Float_Parse(handle, &menu->fadeClamp)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean MenuParse_fadeAmount( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+
+ if (!PC_Float_Parse(handle, &menu->fadeAmount)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+
+qboolean MenuParse_fadeCycle( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+
+ if (!PC_Int_Parse(handle, &menu->fadeCycle)) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+
+qboolean MenuParse_itemDef( itemDef_t *item, int handle ) {
+ menuDef_t *menu = (menuDef_t*)item;
+ if (menu->itemCount < MAX_MENUITEMS) {
+ menu->items[menu->itemCount] = UI_Alloc(sizeof(itemDef_t));
+ Item_Init(menu->items[menu->itemCount]);
+ if (!Item_Parse(handle, menu->items[menu->itemCount])) {
+ return qfalse;
+ }
+ Item_InitControls(menu->items[menu->itemCount]);
+ menu->items[menu->itemCount++]->parent = menu;
+ }
+ return qtrue;
+}
+
+keywordHash_t menuParseKeywords[] = {
+ {"font", MenuParse_font, NULL},
+ {"name", MenuParse_name, NULL},
+ {"fullscreen", MenuParse_fullscreen, NULL},
+ {"rect", MenuParse_rect, NULL},
+ {"style", MenuParse_style, NULL},
+ {"visible", MenuParse_visible, NULL},
+ {"onOpen", MenuParse_onOpen, NULL},
+ {"onClose", MenuParse_onClose, NULL},
+ {"onESC", MenuParse_onESC, NULL},
+ {"border", MenuParse_border, NULL},
+ {"borderSize", MenuParse_borderSize, NULL},
+ {"backcolor", MenuParse_backcolor, NULL},
+ {"forecolor", MenuParse_forecolor, NULL},
+ {"bordercolor", MenuParse_bordercolor, NULL},
+ {"focuscolor", MenuParse_focuscolor, NULL},
+ {"disablecolor", MenuParse_disablecolor, NULL},
+ {"outlinecolor", MenuParse_outlinecolor, NULL},
+ {"background", MenuParse_background, NULL},
+ {"ownerdraw", MenuParse_ownerdraw, NULL},
+ {"ownerdrawFlag", MenuParse_ownerdrawFlag, NULL},
+ {"outOfBoundsClick", MenuParse_outOfBounds, NULL},
+ {"soundLoop", MenuParse_soundLoop, NULL},
+ {"itemDef", MenuParse_itemDef, NULL},
+ {"cinematic", MenuParse_cinematic, NULL},
+ {"popup", MenuParse_popup, NULL},
+ {"fadeClamp", MenuParse_fadeClamp, NULL},
+ {"fadeCycle", MenuParse_fadeCycle, NULL},
+ {"fadeAmount", MenuParse_fadeAmount, NULL},
+ {NULL, 0, NULL}
+};
+
+keywordHash_t *menuParseKeywordHash[KEYWORDHASH_SIZE];
+
+/*
+===============
+Menu_SetupKeywordHash
+===============
+*/
+void Menu_SetupKeywordHash(void) {
+ int i;
+
+ memset(menuParseKeywordHash, 0, sizeof(menuParseKeywordHash));
+ for (i = 0; menuParseKeywords[i].keyword; i++) {
+ KeywordHash_Add(menuParseKeywordHash, &menuParseKeywords[i]);
+ }
+}
+
+/*
+===============
+Menu_Parse
+===============
+*/
+qboolean Menu_Parse(int handle, menuDef_t *menu) {
+ pc_token_t token;
+ keywordHash_t *key;
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+ if (*token.string != '{') {
+ return qfalse;
+ }
+
+ while ( 1 ) {
+
+ memset(&token, 0, sizeof(pc_token_t));
+ if (!trap_PC_ReadToken(handle, &token)) {
+ PC_SourceError(handle, "end of file inside menu\n");
+ return qfalse;
+ }
+
+ if (*token.string == '}') {
+ return qtrue;
+ }
+
+ key = KeywordHash_Find(menuParseKeywordHash, token.string);
+ if (!key) {
+ PC_SourceError(handle, "unknown menu keyword %s", token.string);
+ continue;
+ }
+ if ( !key->func((itemDef_t*)menu, handle) ) {
+ PC_SourceError(handle, "couldn't parse menu keyword %s", token.string);
+ return qfalse;
+ }
+ }
+ return qfalse; // bk001205 - LCC missing return value
+}
+
+/*
+===============
+Menu_New
+===============
+*/
+void Menu_New(int handle) {
+ menuDef_t *menu = &Menus[menuCount];
+
+ if (menuCount < MAX_MENUS) {
+ Menu_Init(menu);
+ if (Menu_Parse(handle, menu)) {
+ Menu_PostParse(menu);
+ menuCount++;
+ }
+ }
+}
+
+int Menu_Count(void) {
+ return menuCount;
+}
+
+void Menu_PaintAll(void) {
+ int i;
+ if (captureFunc) {
+ captureFunc(captureData);
+ }
+
+ for (i = 0; i < Menu_Count(); i++) {
+ Menu_Paint(&Menus[i], qfalse);
+ }
+
+ if (debugMode) {
+ vec4_t v = {1, 1, 1, 1};
+ DC->drawText(5, 25, .5, v, va("fps: %f", DC->FPS), 0, 0, 0);
+ }
+}
+
+void Menu_Reset(void) {
+ menuCount = 0;
+}
+
+displayContextDef_t *Display_GetContext(void) {
+ return DC;
+}
+
+#ifndef MISSIONPACK // bk001206
+static float captureX;
+static float captureY;
+#endif
+
+void *Display_CaptureItem(int x, int y) {
+ int i;
+
+ for (i = 0; i < menuCount; i++) {
+ // turn off focus each item
+ // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
+ if (Rect_ContainsPoint(&Menus[i].window.rect, x, y)) {
+ return &Menus[i];
+ }
+ }
+ return NULL;
+}
+
+
+// FIXME:
+qboolean Display_MouseMove(void *p, int x, int y) {
+ int i;
+ menuDef_t *menu = p;
+
+ if (menu == NULL) {
+ menu = Menu_GetFocused();
+ if (menu) {
+ if (menu->window.flags & WINDOW_POPUP) {
+ Menu_HandleMouseMove(menu, x, y);
+ return qtrue;
+ }
+ }
+ for (i = 0; i < menuCount; i++) {
+ Menu_HandleMouseMove(&Menus[i], x, y);
+ }
+ } else {
+ menu->window.rect.x += x;
+ menu->window.rect.y += y;
+ Menu_UpdatePosition(menu);
+ }
+ return qtrue;
+
+}
+
+int Display_CursorType(int x, int y) {
+ int i;
+ for (i = 0; i < menuCount; i++) {
+ rectDef_t r2;
+ r2.x = Menus[i].window.rect.x - 3;
+ r2.y = Menus[i].window.rect.y - 3;
+ r2.w = r2.h = 7;
+ if (Rect_ContainsPoint(&r2, x, y)) {
+ return CURSOR_SIZER;
+ }
+ }
+ return CURSOR_ARROW;
+}
+
+
+void Display_HandleKey(int key, qboolean down, int x, int y) {
+ menuDef_t *menu = Display_CaptureItem(x, y);
+ if (menu == NULL) {
+ menu = Menu_GetFocused();
+ }
+ if (menu) {
+ Menu_HandleKey(menu, key, down );
+ }
+}
+
+static void Window_CacheContents(windowDef_t *window) {
+ if (window) {
+ if (window->cinematicName) {
+ int cin = DC->playCinematic(window->cinematicName, 0, 0, 0, 0);
+ DC->stopCinematic(cin);
+ }
+ }
+}
+
+
+static void Item_CacheContents(itemDef_t *item) {
+ if (item) {
+ Window_CacheContents(&item->window);
+ }
+
+}
+
+static void Menu_CacheContents(menuDef_t *menu) {
+ if (menu) {
+ int i;
+ Window_CacheContents(&menu->window);
+ for (i = 0; i < menu->itemCount; i++) {
+ Item_CacheContents(menu->items[i]);
+ }
+
+ if (menu->soundName && *menu->soundName) {
+ DC->registerSound(menu->soundName, qfalse);
+ }
+ }
+
+}
+
+void Display_CacheAll(void) {
+ int i;
+ for (i = 0; i < menuCount; i++) {
+ Menu_CacheContents(&Menus[i]);
+ }
+}
+
+
+static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y) {
+ if (menu && menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED)) {
+ if (Rect_ContainsPoint(&menu->window.rect, x, y)) {
+ int i;
+ for (i = 0; i < menu->itemCount; i++) {
+ // turn off focus each item
+ // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
+
+ if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
+ continue;
+ }
+
+ if (menu->items[i]->window.flags & WINDOW_DECORATION) {
+ continue;
+ }
+
+ if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
+ itemDef_t *overItem = menu->items[i];
+ if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
+ if (Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
+ return qtrue;
+ } else {
+ continue;
+ }
+ } else {
+ return qtrue;
+ }
+ }
+ }
+
+ }
+ }
+ return qfalse;
+}
+
diff --git a/code/ui/ui_shared.h b/code/ui/ui_shared.h
new file mode 100644
index 0000000..ea383f9
--- /dev/null
+++ b/code/ui/ui_shared.h
@@ -0,0 +1,452 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#ifndef __UI_SHARED_H
+#define __UI_SHARED_H
+
+
+#include "../qcommon/q_shared.h"
+#include "../renderer/tr_types.h"
+#include "../client/keycodes.h"
+
+#include "../../ui/menudef.h"
+
+#define MAX_MENUNAME 32
+#define MAX_ITEMTEXT 64
+#define MAX_ITEMACTION 64
+#define MAX_MENUDEFFILE 4096
+#define MAX_MENUFILE 32768
+#define MAX_MENUS 64
+#define MAX_MENUITEMS 96
+#define MAX_COLOR_RANGES 10
+#define MAX_OPEN_MENUS 16
+
+#define WINDOW_MOUSEOVER 0x00000001 // mouse is over it, non exclusive
+#define WINDOW_HASFOCUS 0x00000002 // has cursor focus, exclusive
+#define WINDOW_VISIBLE 0x00000004 // is visible
+#define WINDOW_GREY 0x00000008 // is visible but grey ( non-active )
+#define WINDOW_DECORATION 0x00000010 // for decoration only, no mouse, keyboard, etc..
+#define WINDOW_FADINGOUT 0x00000020 // fading out, non-active
+#define WINDOW_FADINGIN 0x00000040 // fading in
+#define WINDOW_MOUSEOVERTEXT 0x00000080 // mouse is over it, non exclusive
+#define WINDOW_INTRANSITION 0x00000100 // window is in transition
+#define WINDOW_FORECOLORSET 0x00000200 // forecolor was explicitly set ( used to color alpha images or not )
+#define WINDOW_HORIZONTAL 0x00000400 // for list boxes and sliders, vertical is default this is set of horizontal
+#define WINDOW_LB_LEFTARROW 0x00000800 // mouse is over left/up arrow
+#define WINDOW_LB_RIGHTARROW 0x00001000 // mouse is over right/down arrow
+#define WINDOW_LB_THUMB 0x00002000 // mouse is over thumb
+#define WINDOW_LB_PGUP 0x00004000 // mouse is over page up
+#define WINDOW_LB_PGDN 0x00008000 // mouse is over page down
+#define WINDOW_ORBITING 0x00010000 // item is in orbit
+#define WINDOW_OOB_CLICK 0x00020000 // close on out of bounds click
+#define WINDOW_WRAPPED 0x00040000 // manually wrap text
+#define WINDOW_AUTOWRAPPED 0x00080000 // auto wrap text
+#define WINDOW_FORCED 0x00100000 // forced open
+#define WINDOW_POPUP 0x00200000 // popup
+#define WINDOW_BACKCOLORSET 0x00400000 // backcolor was explicitly set
+#define WINDOW_TIMEDVISIBLE 0x00800000 // visibility timing ( NOT implemented )
+
+
+// CGAME cursor type bits
+#define CURSOR_NONE 0x00000001
+#define CURSOR_ARROW 0x00000002
+#define CURSOR_SIZER 0x00000004
+
+#ifdef CGAME
+#define STRING_POOL_SIZE 128*1024
+#else
+#define STRING_POOL_SIZE 384*1024
+#endif
+#define MAX_STRING_HANDLES 4096
+
+#define MAX_SCRIPT_ARGS 12
+#define MAX_EDITFIELD 256
+
+#define ART_FX_BASE "menu/art/fx_base"
+#define ART_FX_BLUE "menu/art/fx_blue"
+#define ART_FX_CYAN "menu/art/fx_cyan"
+#define ART_FX_GREEN "menu/art/fx_grn"
+#define ART_FX_RED "menu/art/fx_red"
+#define ART_FX_TEAL "menu/art/fx_teal"
+#define ART_FX_WHITE "menu/art/fx_white"
+#define ART_FX_YELLOW "menu/art/fx_yel"
+
+#define ASSET_GRADIENTBAR "ui/assets/gradientbar2.tga"
+#define ASSET_SCROLLBAR "ui/assets/scrollbar.tga"
+#define ASSET_SCROLLBAR_ARROWDOWN "ui/assets/scrollbar_arrow_dwn_a.tga"
+#define ASSET_SCROLLBAR_ARROWUP "ui/assets/scrollbar_arrow_up_a.tga"
+#define ASSET_SCROLLBAR_ARROWLEFT "ui/assets/scrollbar_arrow_left.tga"
+#define ASSET_SCROLLBAR_ARROWRIGHT "ui/assets/scrollbar_arrow_right.tga"
+#define ASSET_SCROLL_THUMB "ui/assets/scrollbar_thumb.tga"
+#define ASSET_SLIDER_BAR "ui/assets/slider2.tga"
+#define ASSET_SLIDER_THUMB "ui/assets/sliderbutt_1.tga"
+#define SCROLLBAR_SIZE 16.0
+#define SLIDER_WIDTH 96.0
+#define SLIDER_HEIGHT 16.0
+#define SLIDER_THUMB_WIDTH 12.0
+#define SLIDER_THUMB_HEIGHT 20.0
+#define NUM_CROSSHAIRS 99
+
+typedef struct {
+ const char *command;
+ const char *args[MAX_SCRIPT_ARGS];
+} scriptDef_t;
+
+
+typedef struct {
+ float x; // horiz position
+ float y; // vert position
+ float w; // width
+ float h; // height;
+} rectDef_t;
+
+typedef rectDef_t Rectangle;
+
+// FIXME: do something to separate text vs window stuff
+typedef struct {
+ Rectangle rect; // client coord rectangle
+ Rectangle rectClient; // screen coord rectangle
+ const char *name; //
+ const char *group; // if it belongs to a group
+ const char *cinematicName; // cinematic name
+ int cinematic; // cinematic handle
+ int style; //
+ int border; //
+ int ownerDraw; // ownerDraw style
+ int ownerDrawFlags; // show flags for ownerdraw items
+ float borderSize; //
+ int flags; // visible, focus, mouseover, cursor
+ Rectangle rectEffects; // for various effects
+ Rectangle rectEffects2; // for various effects
+ int offsetTime; // time based value for various effects
+ int nextTime; // time next effect should cycle
+ vec4_t foreColor; // text color
+ vec4_t backColor; // border color
+ vec4_t borderColor; // border color
+ vec4_t outlineColor; // border color
+ qhandle_t background; // background asset
+} windowDef_t;
+
+typedef windowDef_t Window;
+
+typedef struct {
+ vec4_t color;
+ float low;
+ float high;
+} colorRangeDef_t;
+
+// FIXME: combine flags into bitfields to save space
+// FIXME: consolidate all of the common stuff in one structure for menus and items
+// THINKABOUTME: is there any compelling reason not to have items contain items
+// and do away with a menu per say.. major issue is not being able to dynamically allocate
+// and destroy stuff.. Another point to consider is adding an alloc free call for vm's and have
+// the engine just allocate the pool for it based on a cvar
+// many of the vars are re-used for different item types, as such they are not always named appropriately
+// the benefits of c++ in DOOM will greatly help crap like this
+// FIXME: need to put a type ptr that points to specific type info per type
+//
+#define MAX_LB_COLUMNS 16
+
+typedef struct columnInfo_s {
+ int pos;
+ int width;
+ int maxChars;
+} columnInfo_t;
+
+typedef struct listBoxDef_s {
+ int startPos;
+ int endPos;
+ int drawPadding;
+ int cursorPos;
+ float elementWidth;
+ float elementHeight;
+ int elementStyle;
+ int numColumns;
+ columnInfo_t columnInfo[MAX_LB_COLUMNS];
+ const char *doubleClick;
+ qboolean notselectable;
+} listBoxDef_t;
+
+typedef struct editFieldDef_s {
+ float minVal; // edit field limits
+ float maxVal; //
+ float defVal; //
+ float range; //
+ int maxChars; // for edit fields
+ int maxPaintChars; // for edit fields
+ int paintOffset; //
+} editFieldDef_t;
+
+#define MAX_MULTI_CVARS 32
+
+typedef struct multiDef_s {
+ const char *cvarList[MAX_MULTI_CVARS];
+ const char *cvarStr[MAX_MULTI_CVARS];
+ float cvarValue[MAX_MULTI_CVARS];
+ int count;
+ qboolean strDef;
+} multiDef_t;
+
+typedef struct modelDef_s {
+ int angle;
+ vec3_t origin;
+ float fov_x;
+ float fov_y;
+ int rotationSpeed;
+} modelDef_t;
+
+#define CVAR_ENABLE 0x00000001
+#define CVAR_DISABLE 0x00000002
+#define CVAR_SHOW 0x00000004
+#define CVAR_HIDE 0x00000008
+
+typedef struct itemDef_s {
+ Window window; // common positional, border, style, layout info
+ Rectangle textRect; // rectangle the text ( if any ) consumes
+ int type; // text, button, radiobutton, checkbox, textfield, listbox, combo
+ int alignment; // left center right
+ int textalignment; // ( optional ) alignment for text within rect based on text width
+ float textalignx; // ( optional ) text alignment x coord
+ float textaligny; // ( optional ) text alignment x coord
+ float textscale; // scale percentage from 72pts
+ int textStyle; // ( optional ) style, normal and shadowed are it for now
+ const char *text; // display text
+ void *parent; // menu owner
+ qhandle_t asset; // handle to asset
+ const char *mouseEnterText; // mouse enter script
+ const char *mouseExitText; // mouse exit script
+ const char *mouseEnter; // mouse enter script
+ const char *mouseExit; // mouse exit script
+ const char *action; // select script
+ const char *onFocus; // select script
+ const char *leaveFocus; // select script
+ const char *cvar; // associated cvar
+ const char *cvarTest; // associated cvar for enable actions
+ const char *enableCvar; // enable, disable, show, or hide based on value, this can contain a list
+ int cvarFlags; // what type of action to take on cvarenables
+ sfxHandle_t focusSound;
+ int numColors; // number of color ranges
+ colorRangeDef_t colorRanges[MAX_COLOR_RANGES];
+ float special; // used for feeder id's etc.. diff per type
+ int cursorPos; // cursor position in characters
+ void *typeData; // type specific data ptr's
+} itemDef_t;
+
+typedef struct {
+ Window window;
+ const char *font; // font
+ qboolean fullScreen; // covers entire screen
+ int itemCount; // number of items;
+ int fontIndex; //
+ int cursorItem; // which item as the cursor
+ int fadeCycle; //
+ float fadeClamp; //
+ float fadeAmount; //
+ const char *onOpen; // run when the menu is first opened
+ const char *onClose; // run when the menu is closed
+ const char *onESC; // run when the menu is closed
+ const char *soundName; // background loop sound for menu
+
+ vec4_t focusColor; // focus color for items
+ vec4_t disableColor; // focus color for items
+ itemDef_t *items[MAX_MENUITEMS]; // items this menu contains
+} menuDef_t;
+
+typedef struct {
+ const char *fontStr;
+ const char *cursorStr;
+ const char *gradientStr;
+ fontInfo_t textFont;
+ fontInfo_t smallFont;
+ fontInfo_t bigFont;
+ qhandle_t cursor;
+ qhandle_t gradientBar;
+ qhandle_t scrollBarArrowUp;
+ qhandle_t scrollBarArrowDown;
+ qhandle_t scrollBarArrowLeft;
+ qhandle_t scrollBarArrowRight;
+ qhandle_t scrollBar;
+ qhandle_t scrollBarThumb;
+ qhandle_t buttonMiddle;
+ qhandle_t buttonInside;
+ qhandle_t solidBox;
+ qhandle_t sliderBar;
+ qhandle_t sliderThumb;
+ sfxHandle_t menuEnterSound;
+ sfxHandle_t menuExitSound;
+ sfxHandle_t menuBuzzSound;
+ sfxHandle_t itemFocusSound;
+ float fadeClamp;
+ int fadeCycle;
+ float fadeAmount;
+ float shadowX;
+ float shadowY;
+ vec4_t shadowColor;
+ float shadowFadeClamp;
+ qboolean fontRegistered;
+
+ // player settings
+ qhandle_t fxBasePic;
+ qhandle_t fxPic[7];
+ qhandle_t crosshairShader[NUM_CROSSHAIRS];
+
+} cachedAssets_t;
+
+typedef struct {
+ const char *name;
+ void (*handler) (itemDef_t *item, char** args);
+} commandDef_t;
+
+typedef struct {
+ qhandle_t (*registerShaderNoMip) (const char *p);
+ void (*setColor) (const vec4_t v);
+ void (*drawHandlePic) (float x, float y, float w, float h, qhandle_t asset);
+ void (*drawStretchPic) (float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
+ void (*drawText) (float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style );
+ int (*textWidth) (const char *text, float scale, int limit);
+ int (*textHeight) (const char *text, float scale, int limit);
+ qhandle_t (*registerModel) (const char *p);
+ void (*modelBounds) (qhandle_t model, vec3_t min, vec3_t max);
+ void (*fillRect) ( float x, float y, float w, float h, const vec4_t color);
+ void (*drawRect) ( float x, float y, float w, float h, float size, const vec4_t color);
+ void (*drawSides) (float x, float y, float w, float h, float size);
+ void (*drawTopBottom) (float x, float y, float w, float h, float size);
+ void (*clearScene) ( void );
+ void (*addRefEntityToScene) (const refEntity_t *re );
+ void (*renderScene) ( const refdef_t *fd );
+ void (*registerFont) (const char *pFontname, int pointSize, fontInfo_t *font);
+ void (*ownerDrawItem) (float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle);
+ float (*getValue) (int ownerDraw);
+ qboolean (*ownerDrawVisible) (int flags);
+ void (*runScript)(char **p);
+ void (*getTeamColor)(vec4_t *color);
+ void (*getCVarString)(const char *cvar, char *buffer, int bufsize);
+ float (*getCVarValue)(const char *cvar);
+ void (*setCVar)(const char *cvar, const char *value);
+ void (*drawTextWithCursor)(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style);
+ void (*setOverstrikeMode)(qboolean b);
+ qboolean (*getOverstrikeMode)( void );
+ void (*startLocalSound)( sfxHandle_t sfx, int channelNum );
+ qboolean (*ownerDrawHandleKey)(int ownerDraw, int flags, float *special, int key);
+ int (*feederCount)(float feederID);
+ const char *(*feederItemText)(float feederID, int index, int column, qhandle_t *handle);
+ qhandle_t (*feederItemImage)(float feederID, int index);
+ void (*feederSelection)(float feederID, int index);
+ void (*keynumToStringBuf)( int keynum, char *buf, int buflen );
+ void (*getBindingBuf)( int keynum, char *buf, int buflen );
+ void (*setBinding)( int keynum, const char *binding );
+ void (*executeText)(int exec_when, const char *text );
+ void (*Error)(int level, const char *error, ...);
+ void (*Print)(const char *msg, ...);
+ void (*Pause)(qboolean b);
+ int (*ownerDrawWidth)(int ownerDraw, float scale);
+ sfxHandle_t (*registerSound)(const char *name, qboolean compressed);
+ void (*startBackgroundTrack)( const char *intro, const char *loop);
+ void (*stopBackgroundTrack)( void );
+ int (*playCinematic)(const char *name, float x, float y, float w, float h);
+ void (*stopCinematic)(int handle);
+ void (*drawCinematic)(int handle, float x, float y, float w, float h);
+ void (*runCinematicFrame)(int handle);
+
+ float yscale;
+ float xscale;
+ float bias;
+ int realTime;
+ int frameTime;
+ int cursorx;
+ int cursory;
+ qboolean debug;
+
+ cachedAssets_t Assets;
+
+ glconfig_t glconfig;
+ qhandle_t whiteShader;
+ qhandle_t gradientImage;
+ qhandle_t cursor;
+ float FPS;
+
+} displayContextDef_t;
+
+const char *String_Alloc(const char *p);
+void String_Init( void );
+void String_Report( void );
+void Init_Display(displayContextDef_t *dc);
+void Display_ExpandMacros(char * buff);
+void Menu_Init(menuDef_t *menu);
+void Item_Init(itemDef_t *item);
+void Menu_PostParse(menuDef_t *menu);
+menuDef_t *Menu_GetFocused( void );
+void Menu_HandleKey(menuDef_t *menu, int key, qboolean down);
+void Menu_HandleMouseMove(menuDef_t *menu, float x, float y);
+void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down);
+qboolean Float_Parse(char **p, float *f);
+qboolean Color_Parse(char **p, vec4_t *c);
+qboolean Int_Parse(char **p, int *i);
+qboolean Rect_Parse(char **p, rectDef_t *r);
+qboolean String_Parse(char **p, const char **out);
+qboolean Script_Parse(char **p, const char **out);
+qboolean PC_Float_Parse(int handle, float *f);
+qboolean PC_Color_Parse(int handle, vec4_t *c);
+qboolean PC_Int_Parse(int handle, int *i);
+qboolean PC_Rect_Parse(int handle, rectDef_t *r);
+qboolean PC_String_Parse(int handle, const char **out);
+qboolean PC_Script_Parse(int handle, const char **out);
+int Menu_Count( void );
+void Menu_New(int handle);
+void Menu_PaintAll( void );
+menuDef_t *Menus_ActivateByName(const char *p);
+void Menu_Reset( void );
+qboolean Menus_AnyFullScreenVisible( void );
+void Menus_Activate(menuDef_t *menu);
+
+displayContextDef_t *Display_GetContext( void );
+void *Display_CaptureItem(int x, int y);
+qboolean Display_MouseMove(void *p, int x, int y);
+int Display_CursorType(int x, int y);
+qboolean Display_KeyBindPending( void );
+void Menus_OpenByName(const char *p);
+menuDef_t *Menus_FindByName(const char *p);
+void Menus_ShowByName(const char *p);
+void Menus_CloseByName(const char *p);
+void Display_HandleKey(int key, qboolean down, int x, int y);
+void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t);
+void Menus_CloseAll( void );
+void Menu_Paint(menuDef_t *menu, qboolean forcePaint);
+void Menu_SetFeederSelection(menuDef_t *menu, int feeder, int index, const char *name);
+void Display_CacheAll( void );
+
+void *UI_Alloc( int size );
+void UI_InitMemory( void );
+qboolean UI_OutOfMemory( void );
+
+#ifndef BASEOA
+void Controls_GetConfig( void );
+void Controls_SetConfig(qboolean restart);
+void Controls_SetDefaults( void );
+#endif
+
+int trap_PC_AddGlobalDefine( char *define );
+int trap_PC_LoadSource( const char *filename );
+int trap_PC_FreeSource( int handle );
+int trap_PC_ReadToken( int handle, pc_token_t *pc_token );
+int trap_PC_SourceFileAndLine( int handle, char *filename, int *line );
+
+#endif
diff --git a/engine/code/ui/ui_syscalls.asm b/code/ui/ui_syscalls.asm
similarity index 100%
rename from engine/code/ui/ui_syscalls.asm
rename to code/ui/ui_syscalls.asm
diff --git a/game/code/ui/ui_syscalls.c b/code/ui/ui_syscalls.c
similarity index 100%
rename from game/code/ui/ui_syscalls.c
rename to code/ui/ui_syscalls.c
diff --git a/engine/.svnignore b/engine/.svnignore
deleted file mode 100644
index 810b319..0000000
--- a/engine/.svnignore
+++ /dev/null
@@ -1,2 +0,0 @@
-build
-Makefile.local
diff --git a/engine/BUGS b/engine/BUGS
deleted file mode 100644
index 081c55d..0000000
--- a/engine/BUGS
+++ /dev/null
@@ -1,4 +0,0 @@
-- On Solaris/SPARC gcc optimizations higher than -O0 currently lead
- to a segfault
-
-https://bugzilla.icculus.org/ for more.
diff --git a/engine/ChangeLog b/engine/ChangeLog
deleted file mode 100644
index d8f866b..0000000
--- a/engine/ChangeLog
+++ /dev/null
@@ -1,3150 +0,0 @@
-2008-04-04 Various contributors
- + Solaris fixes
- + Replace vsprintf function in bg_lib.c with vsnprintf implementation started by Patrick Powell
- + Compile bg_* files separately for each game module, as originally intended
- + Write q3config_server.cfg for the server, to avoid reseting client variables
- after running a dedicated server
- + Split image decoders into their own files
- + OS X build updates for most compatibility
- + Slackbuild
- + Detect available resolutions and offer them in the in game menus
- + A few botlib fixes
- + Fix poppy captured audio when recording videos
- + Extend console logging on crash errors
- + Merge *BSD platform definitions in q_platform.h
- + IRIX support
- + Remove all the old bat/sh QVM building scripts
- + Make master server used client configurable (cl_master)
- + Fix to QVM compilation on big endian architectures
- + OpenBSD support
- + Autocomplete key names
- + Don't build client command completion on the dedicated server
- + Don't apply colour escape chars on input fields
- + Rewrite of the win32 dedicated console
- + Improved Makefile startup time
- + Build dedicated server binary on Windows
- + Bump Q3_VERSION to 1.35
- + Replacement of platform specific backends with a generic SDL one
- + Merge win_net.c and unix_net.c to net_ip.c
- + Demote input related console information to developer only so that it doesn't
- spam the console every time input settings are changed
- + PNG texture support
- + Cleanup of tabulation in R_LoadImage
- + Fixes to console scrolling
- + New x86_64 vm that doesn't use gas
- + Early out AABB collision optimisation
- + Generate QVM dependicies in a better way
- + Build process is quieter
- + Replace horrendously long list of Makefile build rules with set of inference rules
- + Allow CC to be overridden externally to the Makefile
- + Move storage of console history from a cvar to a file in order to alleviate
- security concerns
- + Fix bug where transparent surfaces wouldn't draw over skyboxes
- + Add input sanitising to various sound playing functions called from mods
- + Explicitly set OpenAL distance attenuation model
- + Increased the number of registers used for the opStack in the PPC vm from
- 12 to 16
- + Fix endian issue in MDR loading
- + Add cURL support for HTTP/FTP downloading
- + Disable video command when not playing back a demo
- + Print the SVN version string in Com_Init()
- + OpenAL device enumeration support
- + Fix 100% CPU usage on idle dedicated servers
- + Windows home directory support
- + Improve correctness of AVI files created by video command
- + Better SDL joystick support
- + sv_minRate
- + [cl|sv]_packetdelay
- + Various security fixes
- + Fix JIT compiler code execution on NX-protected win32 OS
- + Fix r_overBrightBits variable getting ignored on Linux
- + cl_guid for semi-reliable server authentication
- + Anisotropic texture filtering
- + Video export doesn't crap out with sv_pure 1 anymore
- + Video export doesn't crap out when writing > 2Gb files anymore
- + Fix to a bug where servers with long uptimes (~27 days) would consume 100%
- CPU if the running game did not set the nextmap cvar
- + Some OSes no longer requires a vid_restart when changing r_fullscreen
-
-2006-01-24 Various contributors
- + Persistent console history
- + Added code to sleep a bit when q3 has no focus and sleep a lot when it's
- minimised (SDL only)
- + Cull excess speaker entities when using OpenAL
- + Fix the operation of the delete key in *nix
- + Only check the checksum on baseq3 pak0.pk3
- + Overhaul of console autocompletion
- - No longer does weird stuff like move the cursor inappropriately
- - Autocomplete works with compound commands
- - Special autocomplete on some commands e.g. \map, \demo
- - Removed various hacks used to counter the original autocomplete code
- + Fixed the ability to disable Ogg Vorbis
- + s/i686/i586/ - see bug #2578
- + Some sloppily coded mods call the Q3 sound API with NaNs -- sanitise this
- + Removed advertising clause from BSD license as per mailing list discussion
- + "make distclean" now does what you'd expect
- + "make clean toolsclean" now does what "make distclean" did before
- + GPL MD4 implementation
-
-2006-01-16 Various contributors
- + Move code/unix/Makefile to ./Makefile
- + x86 OS X support
- + "quake3" shell script as shipped with 1.32 (on linux) no longer needed
- + Ogg codec support from Joerg Dietrich
- + Fix to the gcc4/-O0 x86 JIT compiler bug
- + Up the defaults for zone and hunk memory since some mods (UT) have large
- memory requirements that will have increased versus 1.32b due to some of the
- alignment fixes
- + Dependency generation for the .asm files
- + Remove FS_SetRestrictions
- + Add FS_CheckPak0 for better error messages where dumb users are involved
- + Added cl_autoRecordDemo, which when enabled automatically records a new demo
- on each map change
- + Only display the g_synchronousClients warning when it's appropriate
- + Remove custom memcpy/memset code
- + AVI video output
- - Uses motion jpeg codec by default
- - Use cl_aviFrameRate to set a framerate
- - \video [filename] to start capture
- - \stopvideo to stop capture
- - Audio capture is a bit ropey
- + General Makefile improvements
- + Support for MinGW cross compilation
- + NetBSD support from optical
- + x86_64 JIT bytecode compiler no longer disabled by default
- + msvc project files updated and moved to win32/msvc
- + Various alignment fixes
- + Solaris (x86 and sparc) support from Vincent S. Cojot
- + Fixed Altivec-based mesh rendering
- + Ditch Mac OS 9 support
- + Added a Makefile option USE_LOCAL_HEADERS which can be disabled to use system
- headers if desired
- + Detection of Altivec on Mac OS X
- + SMP support with sdl_glimp.c on Mac OS X.
- + Add "very high quality" option (patch from Pascal de Bruijn)
- + Support for RIFF files with zero length data chunks (yes they exist, and yes,
- they're legal)
- + Support for ccache. If you want it, add USE_CCACHE=1 to Makefile.local
- + Mac OS X now uses SDL backend, all Objective C removed
- + Partial implementation of FS_Seek for files in pk3s
- + Implementation of r_dlightBacks from Shane Isley
- + OpenAL support, from BlackAura aka Stuart Dalton
- + An abstract codec system, simplifying support for new formats
- + Ignore in_dgamouse setting if dga isn't available
- + Removed hard coded mouse acceleration in *nix input code
- + Basically rewrote the lcc Makefile to be more sane
- + Removed various bits of lcc that weren't built/needed
- + General portability improvements
- + Various variables added that aid packaging, from vapier
- + Centralise architecture defines in q_platform.h
- + Replaced a bunch of inline and __inline with ID_INLINE
- + Replaced a bunch of __i386__ with id386
- + General tidy up of asm preprocessor decisions
- + Removed C_ONLY from the dedicated server build
- + Removed rule to build C++ (for splines) from the Makefile
- + General decrufting
- + Split USE_SDL into USE_SDL_VIDEO and USE_SDL_AUDIO
- + Various assorted bug fixes
-
-2005-10-29 Various contributors
- + nasm syntax asm ported to gas
- + Disabled-by-default MD4 support
- + cons build system removed
- + Better FreeBSD support
- + Makefile generates dependencies
- + Some SDL sound tweaks
- + qvm build tools and qvms are now built with the rest of the binaries
- + q3asm-turbo from Phaethon
- + Moved various displaced c and h files into more appropriate places
- + A shitload (can I say shit?) of bug fixes -- see the svn log for details
-
-2005-09-22 Tim Angus <tim at ngus.net>
- + MinGW port
-
-2005-09-??
- + SDL Stuff (icculus)
- + x86_64 (ludwig von angstenheimer)
- + patches from a cast of thousands
-
-2004-05-22 Timothee Besset <ttimo at idsoftware.com>
- + updated the xcode project from Apple's version
- now with the latest vm_ppc code
-
-2004-05-21 Timothee Besset <ttimo at idsoftware.com>
- + fixed the Linux build to compile again on sid (glext.h and gcc3 warnings)
- + 2 weeks ago, hacked up the source to compile on panther / xcode 1.1
- several cleanups were needed, and VM support seems broke (hangs or crashes)
- + got altivec optimisations from Apple (Kenneth Dyke)
- merged back in
- + looks like with the new code merge the VM support is back in and working
-
-2003-09-15 Timothee Besset <ttimo at idsoftware.com>
- + import Q3 java master code, cleanups on monster
-
-2003-08-31 Timothee Besset <ttimo at idsoftware.com>
- + loki_setup hell
- https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=626
- http://zerowing.idsoftware.com/linux/q3a/index.html#glibc
- text mode installer in loki_setup image built on Mandrake 7.2 crashes on
- some glibc 2.3 systems such as RH9 etc. need to move to a different
- version of the installer, and update old installers to keep them still
- 'installing' moving to build the setup binaries on Debian Woody systems
- (glibc 2.2, text mode installer will no longer work on 2.1 systems) hacked
- together a new setup, using setup tree from RTCW. would need a complete
- revamp if a new full setup with new binaries is needed
-
-2003-07-17 Timothee Besset <ttimo at idsoftware.com>
- + new cvsreport, testing per-module config
-
-2003-01-19 Timothee Besset <ttimo at idsoftware.com>
- + building on both gcc 2.x and 3.x
- added conf modules to check gcc version
- ccache support
-
-2003-01-13 Timothee Besset <ttimo at idsoftware.com>
- + tweaking around for gcc 3.x build
- edit Conscript to change the compiler
-
-2002-12-16 Timothee Besset <ttimo at idsoftware.com>
- + added pbEmit class to auth code, emit CD keys to local PB master
-
-2002-11-14 Timothee Besset <ttimo at idsoftware.com>
- + up to latest makeself.sh
- + add both quake3.x86 and quake3-smp.x86 to setup
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=573
- console setup crash / glibc 2.3 (Debian Sid)
- investigated, put together a workaround
-
-2002-11-5 Timothee Besset <ttimo at idsoftware.com>
- + Linux building both smp and non-smp again. Will have to put both in setup
- + added in_subframe to toggle X subframe event handling
- + reworked the timing code to be more reliable
- + cleaned up dgamouse/in_mouse code, removed unnecessary dgamouse var
- + made the mouse grabbing an in_nograb cvar, no longer a compile time option
- in_nograb 1 force in_dgamouse 0 and r_fullscreen 0 (any of those two will b0rk)
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=565
- mouse issues on Suze 8.1 - related to subframe event timing
- added code chunk to detect broken X timing and disable subframe
- + tweaked the subframe/X bug workaround to be less paranoid
-
-2002-10-28 Timothee Besset <ttimo at idsoftware.com>
- + no longer blocking demo recording if g_synchronous clients != 0
- only sending out a warning (everyone does g_sync 1 ; record ; g_sync 0)
-
-2002-10-21 Timothee Besset <ttimo at idsoftware.com>
- + building final mod sdk setups (added lcc bins, added link to q3asm-turbo in readme)
-
-2002-10-8 Timothee Besset <ttimo at idsoftware.com>
- + quickfix cl_maxpackets > 125 brings back to 100
-
-1.32 release ---
-
-2002-10-7 Timothee Besset <ttimo at idsoftware.com>
- + made the 'demo' command case-insensitive on extension match (it was confused by demo FOUR.DM_68)
- + mouse wheel scrolling with in_mouse 1 + window mode was not working, fixed (DI didn't catch)
- + removing on-the-fly pk3 build from Linux setup, using the finalized ones now
- added 'pk3' option to cons for toggle of pk3 building
-
-2002-10-5 Timothee Besset <ttimo at idsoftware.com>
- + updated win32 mod sdk (in win32/mod-sdk-setup)
- added q3asm and lcc source
- updated the .bat to build VMs
-
-2002-10-3 Timothee Besset <ttimo at idsoftware.com>
- + linux mod sdk, wrote the bulk of the scripts
-
-2002-9-30 Timothee Besset <ttimo at idsoftware.com>
- + ATVI Quake 3 1.32 Patch #9
- rolling back to the way it was before, leaving 1v1 force vote exploit, the fix was worse than the bug
- from comment on bug #9 in tracker:
-
- actually the fix is worse than the original bug
-
- after the fix, voting when you are alone on the server was no longer working
- it was kinda intended in the fix, that you would have to be at least two to pass a vote .. but
- it is an oversight.
-
- calling a vote in a 1v1 game against a bot fails immediately
- (calling a vote in any situation where there's only 1 live player fails)
-
- Say a server's running some lame custom map that you have but a friend doesn't. You can't go
- on the server and change it to the map you want to play, so he ends up having to auto-dl it at
- 8K a second just so you can switch from it.
-
- This particular 2 clients, vote / quit exploit would involve too many changes to fix properly.
- I am reverting back to the old version, and leaving as WNF
-
-2002-9-29 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=50
- added Wheel support to the DirectInput code IN_DIMouse (in_mouse 1)
- tweaked the Wheel mouse reading for in_mouse -1 (old win32 input code)
- handle correctly when zDelta is > 120
- provide a in_logitechbug cvar to handle buggy Logitech MouseWare driver sending wheel events twice
-
-2002-9-26 Timothee Besset <ttimo at idsoftware.com>
- + ATVI Quake 3 1.32 Patch #38
- adding trap_SetPbClStatus, reliably checks for PB presence before enabling PB in UI
-
-2002-9-25 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=551
- SVF_CLIENTMASK, fixed a typo
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=555
- pushed cl_maxpackets upper limit to 125 (from 100) per CPMA Arqon's request
-
-2002-9-24 Timothee Besset <ttimo at idsoftware.com>
- + ATVI Quake 3 1.32 Patch #33
- PB reporting sv_paused cvar hacked, fixed SV_CheckPaused to use a Cvar_Set
- + ATVI Quake 3 1.32 Patch #24
- added [skipnotify] from RTCW, use to display in the console only, but not on client screen
- (also fixes pb_msgprefix and pb_sv_msgprefix)
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=553
- using correct error message if listen server starting as cl_punkbuster 0 sv_punkbuster 1
- + ATVI Quake 3 1.32 Patch #35
- text auto wrap in UI code was eating the last word if it was wrapping
- fixed in Q3 and TA UI (this bug could have affected the server print message also)
- + some updates to the win32 cons post-build process
-
-2002-9-21 Timothee Besset <ttimo at idsoftware.com>
- + adding bspc cons build script
-
-2002-9-19 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=552
- disconnect reason is transmitted in the disconnect command and processed into com_errorMessage
- (similar to RTCW behaviour)
- added UI for com_errorMessage cvar in baseq3/, if client is kicked/dropped/disconnected for whatever reason
- (this is already functional in TA)
- + ATVI Quake 3 1.32 Patch #9
- failing vote if there's only one voting client (fixes exploit on 2-player server where one player votes then disconnects, forcing vote to pass)
- + ATVI Quake 3 1.32 Patch #5
- removed the userInfoChanged message (was a debugging leftover)
- + ATVI Quake 3 1.32 Patch #18
- rcon was not properly fixed yet, this only showed up for PB commands
- changed the rcon parsing again to be more reliable
-
-2002-9-18 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=549
- the demo command has a list of compatible protocols, it will loop through 66 67 68
- you can do '/demo four' and it will try four.dm_66 four.dm_67 four.dm_68
- or you can explicitely give a '/demo demoname.dm_??'
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=551
- added SVF_CLIENTMASK (0x00000002), works only with <= 32 players
- set bitmask of players to which send entity
-
-2002-9-17 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=550
- rcon bug fix
- + some scons updates for win32 (post build)
- + 1.32rc2
-
-2002-9-06 Timothee Besset <ttimo at idsoftware.com>
- + updated completely the setup system:
- fixed cons stuff to build setup with cons -- release setup
- working from new setup codebase with some custom patches:
- https://bugzilla.icculus.org/show_bug.cgi?id=52
- https://bugzilla.icculus.org/show_bug.cgi?id=53
- checked that BSD support was still in (brandelfing and symlinks) .. will have to get tester feedback
- bumped version to 1.32rc1
- TODO: update the windows .VCT (standalone setup and auto-update)
-
-2002-9-04 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543
- backport from RTCW 1.4 code
- rcon commands where sent after being tokenized and rebuilt
- that was breaking any quoting, for instance 'rcon g_motd "hooka pooka"'
- added Cmd_Cmd() to retrieve the un-tokenized command and transmit as is on both ends
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=542
- b0rked text wrapping in connect screen
- was a missing sizeScale in q3_ui/, and a bad param in ui/
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=540
- backport fix to pk3 reordering, happens when clearing the references, bad order from connection may break stuff
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=527
- TA ui/, quickfix to netSource (mod stuff, doesn't affect TA)
- + cleaned up broken old DO_WIN32 stuff in cons scripts
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=526
- typo in models2.shader
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=443
- Linux client: sub-frame timing of key/mouse events
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=453
- added mousewheel support: wheel to scroll, ctrl+wheel to scroll faster, shift+wheel to scroll history
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=545
- bumped server count to 4096
- + keep around: __asm__ __volatile__ ("int $0x03");
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516
- moved screenshots to backend with a new RC_SCREENSHOT render command
- fixes the r_smp 1 garbled screenshots
-
-2002-8-29 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=539
- new VM code from Raven's Sof2
- + cons / qvmtools build system fixes
- + had to get a new qe3.ico again (resource compiler error)
- http://vasin.hypermart.net/eei.htm
- + updated, basic testing on win32, merging back in trunk
- + merged bug-539 branch back into trunk, officialize the new VM code
-
-2002-8-26 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=472
- linux client: handle ctrl+space situations (could leave space locked on + space not working with ctrl on)
- + update the build system, build q3lcc and q3asm etc. on demand
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=62
- fixed invisible players/entities
-
-2002-8-23 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=536
- fixing donedl being ignored after autodl if map_restart'ed (propagate from RTCW)
- ignoring multiple map_restart (propagated from RTCW)
- + reworked the server 'client text ignored' message to only trigger when there's actually a message that doesn't get to the game VM
-
-2002-8-18 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=528
- ydnar: reorg bits in the drawsurf sort index, push MAX_SHADERS to 2^12
- + commented out some debug stuff in java auth server
- + added FAQ item with Linux & BSD patch to handle broadcast on multiple interfaces
-
-2002-8-15 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=534
- fixing rcon being broken on NT/XP with > 23 days uptime (or so)
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=525
- changed the rcon buffer size to avoid overflows and dropping part of the message
-
-2002-8-14 Timothee Besset <ttimo at idsoftware.com>
- + hacked in some experimental win32 stuff to the cons files
- (win32 recognition and pk3 installs .. very very experimental but I needed it for win32 dev)
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=521
- ui/ and q3_ui/ : added text auto wrapping in the connection screen drawing (server message)
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=531
- removed the MPlayer stuff from the server browsers
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=505
- enabled back the ignore if protocol is != (fixes Wolf servers showing in browser)
-
-2002-8-10 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=500
- propagated IP banning fix from RTCW
-
-2002-8-08 Timothee Besset <ttimo at idsoftware.com>
- + propagate additional sv_lanForceRate fix from RTCW
-
-2002-8-07 Timothee Besset <ttimo at idsoftware.com>
- + added trap_FS_Seek
-
-2002-8-05 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=50
- fixed the DI mouse init procedure
-
-2002-8-05 Timothee Besset <ttimo at idsoftware.com>
- + removed sv_allowanonymous, was dummy and polluting the serverinfo
- (sv_allowanonymous was designed to flag wether server was public or not, but that's replaced by g_needpass)
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=514
- sv_strictAuth (default 1): server variable to control wether strict CDKEY auth should be performed
- this is required if you want reliable cl_guid on the server
- extended the getIpAuthorize (server->auth message) syntax
- sending the fs_game at all times (default 'baseq3'), dummy sv_allowAnonymous 0, strict auth flag
- NOTE: 1.31 server on baseq3 sends a getIpAuthorize packet like:
- processing packet: getIpAuthorize -1230824753 217.128.77.195 0
- the auth server will mistakenly read fs_game as '0'
- + TAGGED the master / auth source as pre-1_32
- will need to go back to this to comment out all my debugging crap
-
-2002-8-04 Timothee Besset <ttimo at idsoftware.com>
- + cleaned master server stuff, client was prompting master.quake3arena.com,
- server was sending heartbeats to master3.idsoftware.com
- both point to 192.246.40.56, unified to master.quake3arena.com
- the MPlayer master, master.quake3world.com doesn't exist anymore, switched it to master.quake3arena.com
-
-2002-8-02 Timothee Besset <ttimo at idsoftware.com>
- + added auth server source, reorganized
- + auth server name / master key optionally set on command line for master and auth servers
- + auth and master config in build system
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=524
- changed default GL driver from libGL.so to libGL.so.1
- see LSB 1.2 spec: http://www.linuxbase.org/spec/refspecs/LSB_1.2.0/gLSB/libgl.html
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=480
- applying the 'no cp command' experimental fix for beta phase
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=462
- backported from RTCW, fix to packet fragmenting emission
- FIXME: there is some verbose code that we have to take out in the final version (grep for #462)
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
- backported from RTCW, don't get dropped if the server changes map while connecting (ignore outdated cp)
- + PROTOCOL BUMPED TO 68
-
-2002-8-01 Timothee Besset <ttimo at idsoftware.com>
- + Linux: dedicated build was not setting up signal handler like the full client does
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=522
- SplashDamage bugfix, now clearing client gentity before GAME_INIT call (instead of after)
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=498
- fixed NET_AdrToString to print the port as unsigned int (for ports > 1^^15, was showing negative)
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=501
- maintain IP in userinfo sent to game
- + checking in master server source
-
-2002-7-31 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=513
- https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=506
- porting fix from RTCW codebase. client re-orders it's pk3s to scan in the same order than the server
- this eliminates several 'Invalid .PK3 file referenced' situations (caused by client not referencing the same thing as server)
- + fixed border remnants in ta ui
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=517
- ERR_DROP if PB client off / server on conflict when starting local server
- + quickfix to q3 ui / punkbuster detect in server browser
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=458
- code fix, no more taunt spam
- + cons install of PB .so files
- + correct MOD_KAMIKAZE and MOD_JUICED in TA games.log
-
-2002-7-29 Timothee Besset <ttimo at idsoftware.com>
- + q3 ui: completed confirmation prompts and messages (added UI_ConfirmMenu_Style & UI_Message)
- + ta ui: backported 'conditionalopen' from RTCW (conditionalopen <cvar> <menu1> <menu2>)
- + ta ui: confirmation prompt for punkbuster enable/disable etc.
- + added the win32 DLLs to pb/win32/
-
-2002-7-28 Timothee Besset <ttimo at idsoftware.com>
- + ta ui: sv_punkbuster in StartServer menu
- + ta ui: added cl_punkbuster in server browser
- + view filters are in a modal dialog
- + new files: filter.menu menus.txt (pak3.pk3 updated)
- + fix broken link in Linux FAQ
-
-2002-7-27 Timothee Besset <ttimo at idsoftware.com>
- + ta ui: PB display in the browser, in it's additional tab, with sorting
-
-2002-7-26 Timothee Besset <ttimo at idsoftware.com>
- + PB UI: for baseq3/ AND missionpack/
- q3_ui: Punkbuster: Enable/Disable in server broswer (cl_punkbuster)
- q3_ui: PB logo, PB Yes/No in browser (TODO: validate this to be working)
- q3_ui: added sv_punkbuster toggle in start server menu
- + automated building of the new PK3s, unix/Conscript-pk3
-
-2002-7-25 Timothee Besset <ttimo at idsoftware.com>
- + added PB build scripts on Linux, fixed the Linux build
-
-2002-7-12 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=511
- fixing re.SetColor crash for widescreen displays (q3dm11)
- was calling to the renderer while not registered
-
-2002-6-19 Timothee Besset <ttimo at idsoftware.com>
- + r_roundImagesDown 0 + map q3dm16 -> tr_image.c ResampleTexture crash
- buffer overflow because of resample to 2048x..
- xian_q3dm12_leftwall4fin.jpg 1152x384
- bumped one buffer byte p1[1024] -> byte p1[2048], added a safe check
-
-2002-6-14 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
- propagate a renderer fix from RTCW. fixes a one-frame visual glitch when mod code
- registers a shader after drawsurfaces are generated but before the frame is rendered
-
-2002-6-12 Timothee Besset <ttimo at idsoftware.com>
- + added cons and pcons to unix/, updated the build script
-
-2002-5-24 Timothee Besset <ttimo at idsoftware.com>
- towards a new Q3 release?
- some bug fixes require protocol change, or mod code/mod interface change to be fixed properly
- this is a biz decision, dunno yet if we are going to want a new protocol (probably not)
- -> have to create a branch for the 1.31b, i.e. backwards compatible with 1.31 'Stable-1_31'
- and put the 1.32 specific / protocol changes on trunk
- no telling what will go in SOS in the end .. probably 1.32
-
-2002-5-5 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491
- adding a sv_lanForceRate (defaults to 1) to turn on/off server forcing rate of LAN clients
- (only affects LAN dedicated clients - dedicated 1, default behaviour forces LAN clients to 99999 rate)
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=470
- fixing potential overflows with cl_cdkey (propagated from RTCW)
- + cons-based build system (imported from Wolf, was partly written for mod tools release already)
- building with SMP on by default
- + better #ifdef SMP handling ('disabled at compile time' message)
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=494
- Q_vsnprintf for vsprintf calls in the core
- not putting this in game code as we'd need a vsnprintf implementation in bg_lib.c
-
-2002-4-5 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=462
- taking out the fix which was found broken and incomplete
-
-2002-8-4 Timothee Besset <ttimo at idsoftware.com>
- + adding NO_MOUSEGRAB define (select in the Makefile)
-
-2002-2-4 Timothee Besset <ttimo at idsoftware.com>
- + applying Gareth's SMP patch
- + count number of CPUs (Sys_ProcessorCount in unix_shared.c), default r_smp appropriately
- + bumping version to 1.32
- + if XInitThreads fails, set r_smp to zero
-
-2002-28-2 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=462
- send potential remaining fragmented packets before sending a gamestate
-
-2002-26-2 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=455
- removed old libMesaVoodooGL.so loading code
- Voodoo cards should use XF4/DRI, that load code was outdated and confusing people with broken OpenGL
-
-2002-16-1 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=441
- adding brandelf calls to the setup building process so that our binaries run on BSD
-
-2002-1-1 Timothee Besset <ttimo at idsoftware.com>
- + updated FAQ with BSD info (bug #441)
- + FAQ update on CLIENT_UNKNOWN_TO_AUTH
- + FAQ update for proper strace usage
-
-2001-12-12 Timothee Besset <ttimo at idsoftware.com>
- + Q3 1.31 point release
- updating build_setup.sh to new pk3 files
- (baseq3/pak7.pk3 missionpack/pak2.pk3)
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=395
- adding quake3.xpm icon, and modified the setup accordingly to put symlinks
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=390
- ignoring SIGTTIN SIGTTOU
-
-2001-06-12 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=402
- bug with full scene
-
-2001-04-12 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=398
- cg_bobup cheat protect
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=399
- fixed Setup > System > Driver info crash
- + checked in code/spank.sh script, perform checksuming
-
-2001-18-09 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
- propagating sound code fixes from Wolf to Q3
-
-2001-11-08 Timothee Besset <ttimo at idsoftware.com>
- + setup script was still broken, damn shell expansion
- the exit code for Q3 was always zero instead of $?
- propagating the fix to Wolf
-
-2001-11-04 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=382
- modified challenge code for motd to be truly random
-
-2001-10-31 Timothee Besset <ttimo at idsoftware.com>
- Moved updated q3asm and lcc source at the toplevel, MissionPack/q3asm
- and MissionPack/lcc
-
-2001-10-29 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=381
- build system is now functional
-
-2001-10-21 Timothee Besset <ttimo at idsoftware.com>
- + updated Sys_LoadDll code on linux to search in the following order:
- #1 current directory
- #2 fs_homepath
- #3 fs_basepath
- this was needed to make mod developement easier
-
-2001-10-09 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=51
- the code to buffer the redirection was in there but disabled? (Com_Printf)
- enabled it back
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=52
- connection issues / userinfo
- client side fix, instead of sending 'connect <userinfo>' packet
- we now send 'connect "<userinfo>"'
-
-2001-10-08 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
- added a PROT_READ to the mmap call
- this was needed to go around a bug in glibc i586 i686, memset doing read access
- since the audio_fd is opened O_RDWD this is harmless to Q3
-
-2001-10-07 Timothee Besset <ttimo at idsoftware.com>
- + updating from SOS
- S_WriteLinearBlastStereo16 C/asm is back in snd_mix.c (Graeme)
- r_showtris r_shownormal cheat protections
- + Sys_LoadDll changes:
- removing -debug search when loading native dlls
- changing the fatal aborts when not finding native from release only to debug only (was a misfeature)
- used to search in cd_path which is bogus, now searching in pwd if basepath fails
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=275
- fixed r_fullbright not being cheat protected / was a CVAR_LATCHED|CVAR_CHEAT issue
-
-2001-09-06 Timothee Besset <ttimo at idsoftware.com>
- + updated from SOS, some changes to qcommon/unzip.c (statics)
-
-2001-08-27 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=3
- Added some code in CL_InitDownloads to use FS_ComparePaks and print out information about server-referenced paks that are missing on the client. It is a first step, allows to get precise information about what can cause a connection to fail (typically when the user is sent back to the main screen).
-
-2001-08-22 Timothee Besset <ttimo at idsoftware.com>
- + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=86
- fixed sound bug (with Graeme hints)
-
-2001-08-20 Timothee Besset <ttimo at idsoftware.com>
- + made sure Sys_Printf doesn't get into an endless loop if logfile is on
- fixed qconsole.log issues, +set logfile 1 +set fs_debug 1 was crashing (any OS)
- fixed logfile 1 / ttycon 1 issue, didn't exit properly (same endless looping)
- also fixes an issue reported by q3f team
- + changed rcon commands from Com_DPrintf to Com_Printf so that they show up in the console
- (with IP information)
-
-2001-08-19 Timothee Besset <ttimo at idsoftware.com>
- + fixed https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=91
- (autodownload toggle in q3 ui)
- + fixed https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=76
- g_password issue
- + fixed https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=93
- cheat protecting r_lodCurveError
- + wontfix https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=92
-
-2001-08-18 Timothee Besset <ttimo at idsoftware.com>
- + more fixes to the 7-button mouse code (linux only)
- + updated faq about gamma slider
- + added "servers don't show up in ingame browser" to faq
- + added Alt+Enter toggle for fullscreen/windowed (linux)
-
-2001-08-16 Timothee Besset <ttimo at idsoftware.com>
- reconfiguring CVS repository to give access to Gareth
- + testin gareth's access
-
-2001-08-03 Timothee Besset <ttimo at idsoftware.com>
- * https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=85
- fixes in the setup code for older bash versions
-
-2001-08-02 Timothee Besset <ttimo at idsoftware.com>
- * commented out assembly implementation of S_WriteLinearBlastStereo16, using modified C implementation from Zaphod
- need to check performance: https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=88
- * finished const declarations in CG_Trace calls, was needed in pmove_t declaration and some other functions
- cgame/cg_local.h : CG_trace trap_CM_BoxTrace
- game/bg_public.h : using const in pmove_t trace functions prototypes
- (fixes gcc warnings: assignment from incompatible pointer type)
-
-2001-07-26 Timothee Besset <ttimo at idsoftware.com>
- * https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=78
- mapped K_MOUSE4 K_MOUSE5
-
-2001-07-23 Timothee Besset <ttimo at idsoftware.com>
- * https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=5
- more fixes, handling meta characters and various kinds of backspace
-
-2001-07-22 Timothee Besset <ttimo at idsoftware.com>
- * https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=5
- after testing feedback, fixed more stuff:
- better backspace, works with putty and potentially more terminals
- * https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=51
- band aid fix to rcon status, incresed MAX_PUSHED_EVENTS from 256 to 1024
- (adds 28kb of mem requirements)
-
-2001-07-21 Timothee Besset <ttimo at idsoftware.com>
- * https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=2
- using XF86 Gamma extension to set the gamma in game from the menus
- (previous behaviour was to set /r_gamma and restart, renderer relying on s_gammatable)
- restoring initial gamma on GLimp_ShutDown
-
-2001-07-19 Timothee Besset <ttimo at idsoftware.com>
- * https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=5
- first usable version of dedicated console
- added history and completion functionality
- ready for some testing
- still some TODOs and FIXMEs:
- keep the currently edited line when going back from history exploration
- edit the current line with cursor, insert mode etc.
-
-2001-07-18 Timothee Besset <ttimo at idsoftware.com>
- * starting TAB completion and history for the dedicated server (tty console)
- removed Sys_ConsoleOutput (unused)
- removing bogus nostdout variable
- cleanup of a big chunk of code that Bernd commented out and scheduled for deletion
- moved completion code from client/cl_keys.c stuff into qcommon/common.c, Field_CompleteCommand(field_t*)
-
-2001-07-13 Timothee Besset <ttimo at idsoftware.com>
- * fixed https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8
- screenshots overwrites
- * fixed https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=31
- DOUBLE SIGNAL FAULT
-
-2001-07-11 Timothee Besset <ttimo at idsoftware.com>
- * fix for french keybards / console toggle / bound to XK_twosuperior
-
-2001-07-10 Timothee Besset <ttimo at idsoftware.com>
- * https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=19
- cleanup of the keyboard code, adding com_developer message in case XLookupString would fail
-
-2001-07-10 Timothee Besset <ttimo at idsoftware.com>
- * https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=33
- using our custom handlers for X errors, should make things more robust
- (X docs say some X errors are not fatal, but the default X handler exits the app anyway)
-
-2001-07-08 Timothee Besset <ttimo at idsoftware.com>
- * https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=19
- keyboard state issues, fixed the sticking with ctrl key (thks relnev)
-
-2001-07-07 Timothee Besset <ttimo at idsoftware.com>
- * closing https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=13
- the fixes to bug #9 solved this one too
- * checking in to SOS
-
-2001-07-05 Timothee Besset <ttimo at idsoftware.com>
- * work on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=9
- filesystem code changes:
- updated the documentation in files.c to the current system
- added correct fs_homepath fs_basepath fs_cdpath scanning to FS_SV_FOpenFileRead
- (fixes description.txt not found, and probably a few other linux issues)
-
-2001-06-29 Timothee Besset <ttimo at idsoftware.com>
- * fixed setup issues (graphical/console)
- https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=6
-
-2001-06-26 Timothee Besset <ttimo at idsoftware.com>
- * bug tracker is online at https://zerowing.idsoftware.com/bugzilla
- authentication, use login: bugs password: b00gies
- for now, using it as the linux bug tracker, possible use for more OSes and programs if anyone is interested.
- * tweaked the graphical setup to send to bugs at idsoftware.com on errors instead of support at lokigames.com
-
-2001-06-19 Timothee Besset <ttimo at idsoftware.com>
- * fixed generated launch script /usr/local/bin/quake3, exit $* should be exit
-
-2001-06-18 Timothee Besset <ttimo at idsoftware.com>
- * rebuilt 1.29f setups, released as 1.29f-beta1 'Q3 1.29f linux-i386 Jun 19 2001'
-
-2001-06-10 Timothee Besset <ttimo at idsoftware.com>
- * rebuilt against PR source, packaged 1.29b setups
-
-2001-05-25 Timothee Besset <ttimo at idsoftware.com>
- * graphical setup, based on Loki's setup tool (GPL)
-
-2001-05-22 Timothee Besset <ttimo at idsoftware.com>
- * changed fs_basepath to fs_homepath, according to Graeme's changes (probably missed this change?)
- this fixes the q3key prompting at each game startup
-
-2001-05-20 Timothee Besset <ttimo at idsoftware.com>
- * rebuilding 1.28b, various fixes on linux build:
- - SetProgramPath was renamed to Sys_SetDefaultCDPath in unix_shared.c
- updated unix_main.c accordingly
- - some prototypes in qgl.h are guarded by #ifndef GL_VERSION_1_2 (ARB extentions)
- those prototypes are needed by linux_glimp for importing functions and casting, added a #ifdef __linux__
- (not a clean solution)
- - game/q_shared.h
- little endian / big endian functions have been added
- gcc generates warnings about functions being unused .. inlined them
- - cgame/cg_marks.c
- // TTimo
- // gcc warning: might be used uninitialized
- float sInc = 0.0;
- float s = 0.0;
-
-2001-05-15 Timothee Besset <ttimo at idsoftware.com>
- * fixes to linux Makefile for bspc 2.1h
- * various updates to 1.28b on linux
-
-2001-05-09 Timothee Besset <ttimo at idsoftware.com>
-
- * R. Duffy reverted game/bg_pmove.c PM_CheckDuck, was a merging screup on my side
- * updated setup to 1.27z, removed the .so from the setup distribution (they were in 1.27g because of issues)
- FIXME: gotta get pk3's first
-
-2001-05-04 Timothee Besset <ttimo at idsoftware.com>
-
- * fixes to gcc, building RC for 1.27s
-
-2001-05-01 Timothee Besset <ttimo at idsoftware.com>
-
- * added qcommon/huffman.c to the Makefile
- * gcc -Wall:
- commenting out
- CL_Netchan_Encode CL_Netchan_Decode (cl_net_chan.c)
- Netchan_ScramblePacket Netchan_UnScramblePacket (net_chan.c)
- SV_Netchan_Encode SV_Netchan_Decode (sv_net_chan.c)
-
-2001-04-26 Timothee Besset <ttimo at idsoftware.com>
-
- * fixed dedicated server crash when entering the VM_COMPILED qagame on a mod (some statics lacked initialization)
-
-2001-04-25 Timothee Besset <ttimo at idsoftware.com>
-
- * added $(Q3POBJ) to clean target (cleanup of platform-dependent objects)
- * more make clean improvements
-
-2001-04-23 Timothee Besset <ttimo at idsoftware.com>
-
- * cleanup the mod selection code, remove duplicates
- * some issues with release builds, my main developement box doesn't build stable binaries with release settings
- removing -fomit-frame-pointer seems to fix (there's probably a performance hit)
- see OMIT-FRAME-POINTER.txt
-
-2001-04-13 Timothee Besset <ttimo at idsoftware.com>
-
- * checked in a first set of merged files
-
-2001-04-06 Timothee Besset <ttimo at idsoftware.com>
-
- * merged back the core linux parts to make 1.27g linux build from the Source Safe tree again
-
-2001-02-27 Bernd Kreimeier <bk at lokigames.com>
-
- * CVS: tag with changes as of today
- cvs tag id1-27j-loki01027
-
- * code/qcommon/msg.c: numFields loop (SOS).
- * code/qcommon/files.c: ue Q_stricmp (SOS uses stricmp, was strcmp).
- * code/game/q_shared.h (Q3_VERSION): 1.27j. Also
- MAX_STRING_TOKENS upped from 256 to 1024 (SOS).
-
- * code/server/sv_snapshot.c (SV_AddEntitiesVisibleFromPoint): see below.
- * code/game/g_public.h (SVF_NOTSINGLECLIENT): added (SOS).
-
- * code/server/sv_ccmds.c: see below.
- * code/game/g_main.c: g_gametype cvar now userinfo (SOS).
-
- * code/game/g_active.c (SendPendingPredictableEvents): new (SOS).
- * code/game/bg_misc.c: new SOS (sos010227)
-
- * SOS: new update sos010227.
-
-2001-02-22 Bernd Kreimeier <bk at lokigames.com>
-
- * CVS: now in sync with last SOS and cleanup up
- cvs tag id1-27i-loki01022
-
- * code/ui/ui_shared.c: below.
- * code/ui/ui_main.c: leftover code!
- * code/server/sv_world.c: below.
- * code/server/sv_snapshot.c: below.
- * code/server/sv_init.c: below.
- * code/server/sv_game.c: below.
- * code/server/sv_client.c: below.
- * code/server/sv_ccmds.c: below.
- * code/server/sv_bot.c: below.
- * code/server/server.h: below.
- * code/renderer/tr_surface.c: below.
- * code/renderer/tr_shader.c: changed assert to early return.
- * code/renderer/tr_shade_calc.c: below.
- * code/renderer/tr_shade.c: below.
- * code/renderer/tr_scene.c: below.
- * code/renderer/tr_mesh.c: below.
- * code/renderer/tr_local.h: below.
- * code/qcommon/vm_x86.c: cleanup.
- * code/qcommon/vm.c: below.
- * code/qcommon/unzip.c: below.
- * code/qcommon/qcommon.h: below.
- * code/qcommon/files.c: below.
- * code/qcommon/cvar.c: cleanup.
-
-2001-02-21 Bernd Kreimeier <bk at lokigames.com>
-
- * code/qcommon/common.c: cleanup.
- * code/qcommon/cm_trace.c: cleanup.
- * code/qcommon/cm_patch.c: cleanup.
- * code/qcommon/cm_public.h: cleanup.
- * code/game/q_shared.h: cleanup.
- * code/game/q_shared.c: cleanup.
- * code/game/q_math.c: cleanup.
- * code/game/g_syscalls.asm: changed (once more) floor,ceil etc.
- * code/game/g_spawn.c: cleanup.
- * code/game/g_session.c: cleanup.
- * code/game/g_cmds.c: cleanup.
- * code/game/g_client.c: cleanup.
- * code/game/g_arenas.c: cleanup.
- * code/game/bg_slidemove.c: cleanup.
- * code/game/bg_pmove.c (PM_CheckDuck): old call to trace?
- * code/game/bg_misc.c: cleanup.
- * code/game/be_aas.h: dead code.
- * code/game/ai_dmq3.c: cleanup. One clear/copy switched?
- * code/game/ai_dmnet.c: more //*/. Why oh why not DEBUG....
-
- * code/client/snd_mix.c: below.
- * code/client/snd_dma.c: below.
- * code/client/keys.h: cleanup.
- TODO: #error in q3_ui/keycodes.h ?
-
- * code/client/client.h: cleanup.
- * code/client/cl_main.c: misplaced bracket. Cleanup.
- * code/client/cl_keys.c: below.
- * code/client/cl_cin.c: below.
- * code/client/cl_cgame.c: cleanup.
- TODO: define assert for Win32 or guard my assertions.
-
- * code/cgame/cg_syscalls.c: below.
- * code/cgame/cg_servercmds.c: below.
- * code/cgame/cg_players.c: cleanup.
-
- * code/cgame/cg_newdraw.c: remember to diff against cg_newDraw.c
- in SOS (mixed case).
- TODO: get id to use cg_newdraw.c, and to remove cg_newDraw.c/cpp.
-
- * code/cgame/cg_main.c: below.
- * code/cgame/cg_local.h: below.
- * code/cgame/cg_event.c: below.
- * code/cgame/cg_drawtools.c: below.
- * code/cgame/cg_draw.c: cleanup.
- * code/cgame/cg_consolecmds.c: dead code.
- * code/bspc/qbsp.h: below.
- * code/bspc/l_poly.c: below.
- * code/bspc/l_math.c: cleanup.
- * code/bspc/bspc.c: cleanup.
- * code/bspc/be_aas_bspc.c: cleanup.
- * code/bspc/aas_map.c: kept comments - merge loss at their end?
- * code/bspc/aas_file.c: cleanup.
-
- * code/botlib/be_interface.c: this file is plain impossible. There
- are layers of code made dead with /* */ and the resurrected by
- //* or // /* or variations of this. I reverted to exact mirror
- image of SOS to be sure - short of removing it's too easy to mistake
- live code for dead one.
- Later: have to change 5 occurences to avoid gcc complaints about
- nested comment tokens.
- TODO: somebody please get rid of the cruft in here.
-
- * code/botlib/be_ai_move.c: redundant typedef.
- * code/botlib/be_ai_chat.c: assertions on signed string index.
- Note: this is not in my ChangeLog - ouch.
- TODO: use gcc -fsigned-char on all platsforms to enforce Win32
- TODO behavior (PPC has a default unsigned char, Intel has not).
- * code/botlib/be_aas_sample.c (AAS_TraceClientBBox): one code block
- was placed in different location, and one FPE hack not used. I would
- expect that divide by zero will still occur here.
-
- * code/botlib/be_aas_reach.c: below.
- * code/botlib/be_aas_cluster.c: cleanup.
- * CVS: the last tag (below) marks the version with a lot of history
- and additional comments. I am now bringing the codebase in sync with
- SOS as of yesterday, cleaning out comments, dead code and other
- differences to minimize a diff - in a valiant if futile attempt to
- roll back changes into the id codebase.
- Note: I ignore the $SOS$ - these are unfortunate but will change
- in the same awkward way at their end.
- Note: I stick to #if 0 instead of C comments around dead code id
- kept (nested comments issue). The commentary is changed to sosYYMMDD
- and includes the token DEAD.
-
-2001-02-20 Bernd Kreimeier <bk at lokigames.com>
-
- * CVS: update, then tag current version as
- cvs tag id1-27i-loki010219
-
- * SOS: patched up to sos010219.
-
- * code/qcommon/cm_trace.c (CM_Trace): fabs on sphere offsets (SOS).
- * code/game/bg_slidemove.c (PM_StepSlideMove): stepSize vs. STEPSIZE (SOS).
- * code/game/bg_pmove.c (PM_CheckDuck): fix in stand up check (SOS).
- * code/bspc/bspc.c (main): -capsule (SOS).
- * code/bspc/qbsp.h: below (SOS).
- * code/bspc/be_aas_bspc.c (capsule_collision): added (SOS).
- * code/bspc/aas_map.c (CapsuleOriginDistanceFromPlane): added and used (SOS).
- * code/bspc/aas_file.c (AAS_WriteAASFile): removed diagnostics recently
- added. No matter how long you wait, they'll always get you ;-).
- * code/botlib/be_aas_cluster.c: enabled LogWrites, different flood (SOS).
-
- * SOS: patching up to snapshot sos010219.
- Note: For brevity, I use as marker sosYYMMDD now instead of bkYYMMDD, to
- distinguish from changes not in SOS.
-
- * CVS: tagged current version before patching up with SOS.
- cvs tag id1-27i-loki010216-bsd
-
-2001-02-16 Bernd Kreimeier <bk at lokigames.com>
-
- * code/server/sv_init.c: DLL_ONLY sets sv_pure to 0 and ROM.
- TODO: determine good sv_pure policy for DLL-only servers.
-
- * code/renderer/tr_shade_calc.c: my_ftol implementation (BSD).
-
- * code/unix/Makefile: FreeBSD sections.
- TODO: include target-specific Make-freebsd etc.,
- include a Make-local not in CVS for build preferences,
- and generally clean up this mess.
- * code/unix/unix_glw.h: guard #error
- * code/unix/linux_snd.c: soundcard.h location (BSD).
- * code/unix/linux_glimp.c: guard system headers.
- Later: added Joystick stubs.
- Note: linux_ etc. prefixes start to loose meaning as we
- re-use most of this on UNIXes anyway. I didn't use Raf's
- freebsd_joystick.c but instead put generic stubs here.
- TODO: introduce generic -DNO_JOYSTICK flag.
- * code/renderer/tr_local.h: my_ftol guard.
- * code/renderer/qgl.h: FreeBSD guards.
- * code/qcommon/vm_x86.c: sys/types include on FreeBSD.
- * code/qcommon/md4.c: Win32 pragma guard.
- * code/qcommon/common.c: Com_Memcpy/Memset external.
- * code/game/q_shared.h: added FreeBSD defines.
- * code/game/q_math.c (BoxOnPlaneSide): FreeBSD conditional.
- TODO: check whether we have/need the assembly version anyway.
- * code/client/snd_mix.c: use C fallback on FreeBSD.
- Note: all of the above changes from the original port by Rafael Barrero.
-
- * CVS: tagged current version before merging FreeBSD related changes.
- cvs tag id1-27i-loki010215-ppc
-
-2001-02-15 Bernd Kreimeier <bk at lokigames.com>
-
- * code/unix/Makefile: BSD related changes.
- * code/cgame/cg_draw.c: hacked phone jack rendering check for Debug.
- TODO: finish Debug, fix CG_DrawDisconnect !!!
-
- * code/unix/vm_x86.c: error on compile attempts. Fight redundancy!
- * code/qcommon/vm_x86.c (VM_CallCompiled): dummy for linkage on PPC.
- Note: DLL_ONLY is the global Makefile option for DLL-only builts.
- Currently only executed on Linux.
- * code/unix/unix_main.c: *ppc postfix for DLLs. Ignored the changes
- to redundant code (have to remove the unused Un/LoadDll/API calls).
- * code/server/sv_game.c (VMA): changed macro (see below). PPC.
- * code/qcommon/vm.c (VM_DllSyscall): see lengthy commentary by Ryan.
- The existing VM code makes certain assumptions about the layout of
- varargs on the stack, which fall apart with call conventions that
- don't even put all parameters on the stack (gcc on PPC, register-rich).
- Using a dedicated memory area as our own stack. This should actually
- be the default behavior.
- Later: make vm_* cvars INIT/ROM for DLL_ONLY target.
-
- * code/qcommon/common.c: PPC change (from Ryan Gordon).
-
-2001-02-07 Bernd Kreimeier <bk at lokigames.com>
-
- * code/unix/unix_main.c: disabled FPE for debug for the time
- being (that is, until I can figure out
- Program received signal SIGFPE, Arithmetic exception.
- RB_BeginSurface (shader=0x449572e0, fogNum=0) at ..//renderer/tr_shade.c:307
- 307 tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
- without any NaN's involved.
- TODO: unmask other FPE's selectively (see Mike's Tribes2, no getenv though).
-
-2001-02-06 Bernd Kreimeier <bk at lokigames.com>
-
- * SOS: up to date with todays snapshot.
- Note: got the date wrong, comment used was bk010205. Duh.
-
- * code/server/sv_snapshot.c (SV_UpdateServerCommandsToClient): below.
- * code/server/sv_main.c (SV_ReplacePendingServerCommands): new (SOS).
- * code/server/server.h: reliableSent (SOS).
-
- * code/renderer/tr_shade.c (ProjectDlightTexture): see below.
- * code/renderer/tr_scene.c: see below.
- * code/renderer/tr_public.h: see below (SOS).
- * code/renderer/tr_local.h: additive light support (SOS).
-
- * code/qcommon/cm_trace.c (CM_Trace): new tw.sphere.use branch (SOS).
-
- * code/game/g_spawn.c: notta, notq3a entities (SOS).
- * code/game/ai_dmq3.c: MAX_ACTIVATEAREAS search (SOS).
-
- * code/client/cl_cgame.c: see below.
- * code/cgame/cg_syscalls.c (trap_R_AddAdditiveLightToScene): below.
- * code/cgame/cg_syscalls.asm: see below (trap_R_AddAdditiveLightToScene).
- * code/cgame/cg_public.h: CG_R_ADDADDITIVELIGHTTOSCENE (SOS).
-
- * code/bspc/l_math.c: new VectorLengthSquared, removed rotate/matrix (SOS).
- * code/bspc/bspc.c (BSPC_VERSION): was 2.1e, now?
- * code/bspc/be_aas_bspc.c (BotImport_Trace): CM_BoxTrace sig. (SOS).
- * code/bspc/aas_file.c (AAS_WriteAASFile): SOS.
- * code/botlib/be_aas_sample.c (AAS_DeAllocAASLink): SOS.
-
- * code/unix/unix_main.c (Sys_LoadDll): do not load from installdir
- in NDEBUG (confusing relic from old Makefile). Postfix -debug.so
- for debug binaries to let both builds coexist.
-
- * code/unix/Makefile: updated install targets and VERSION.
-
- * Win32: build from SOS snapshot.
- Note: Unix CR/LF in *.dsw/*.dsp fucks up MSVC++.
-
-2001-02-02 Bernd Kreimeier <bk at lokigames.com>
-
- * SOS: all changes up to today.
-
- * code/server/sv_init.c (SV_TouchCGame): added. Also memset
- on reallocated client data (SOS).
- * code/qcommon/qcommon.h: see below.
- * code/qcommon/cvar.c (Cvar_SetLatched): new (SOS).
- * code/qcommon/cm_trace.c: more sphere test fixes (SOS).
- Note: SOS encryption key expired and updated by MrElusive.
-
- * code/qcommon/cm_patch.c (CM_TraceThroughPatchCollide):
- fix from MrElusive, fall through curved corner floors (q3dm17).
- Later: also in SOS (so is shadow FPE fix).
-
- * Win32: can't get an unadulterated SOS snapshot to build.
- First, fix CR/LF back again (Linux client converts all).
- find . -name '*.ds*' -print
- alias dos2unix='recode ibmpc..lat1'
- alias unix2dos='recode lat1..ibmpc'
- Next, find a *.dws that works? Nope, no cigar.
-
-2001-02-01 Bernd Kreimeier <bk at lokigames.com>
-
- * Win32: have to update dsp/dsw/etc. files in CVS, too.
-
- * CVS: tag previous version before update
- cvs tag id1-27h-loki010131-beta3
-
- * code/game/q_math.c (Q_rsqrt): guard, #ifndef __linux__
- for assert (for Win32 build).
- TODO: assert replacement for Win32?
- * code/q3_ui/ui_qmenu.c: see below.
- * code/q3_ui/ui_players.c: see below.
- * code/q3_ui/ui_controls2.c: float const with f postfix
- Note: Win32 C4305 warning. Somebody at id has been doing
- a lot of these recently as well...
-
- * code/cgame/cg_players.c (CG_PlayerShadow): applied fix by
- MrElusive, removed FPE hack (player shadows on zero mormals).
- Prolly in this evenings' CVS.
-
- * code/server/sv_game.c: new signatures (capsule again).
- * code/server/server.h: new signatures (SV_Trace,ClipToEntity).
- * code/server/sv_bot.c: new signatures (above).
- * code/qcommon/cm_trace.c: a truckload of changes. Math
- code added before moved upwards. Capsule traces added all
- over the place, old box traces moved in conditional
- branches, functions renamed and wrapped. Eliminated some
- of the previous' versions deadcode to keep diffs smaller.
- TODO: once a point release is out and reasonably bug
- TODO free, remove // bkYYMMDD annotations where SOS related.
-
- * code/qcommon/cm_public.h: new signatures in prototypes.
- * code/qcommon/cm_patch.c: dead code re-enabled, new
- sections (conditional branches for spheres) added to
- several trace functions.
- * code/qcommon/cm_local.h (CAPSULE_MODEL_HANDLE): added.
- * code/qcommon/cm_load.c (CM_TempBoxModel): capsules.
-
- * code/game/q_shared.h (Q3_VERSION): 1.27i now (new QVM traps).
-
- * code/game/g_syscalls.asm: see below.
- * code/game/g_public.h (SVF_CAPSULE): added (SOS). Also
- G_ entry poiints for capsule traces.
-
- * code/client/cl_cgame.c: see below.
- * code/cgame/cg_syscalls.c: see below.
- * code/cgame/cg_syscalls.asm: see below.
- * code/cgame/cg_public.h: new capsule trace code (SOS).
-
-2001-01-31 Bernd Kreimeier <bk at lokigames.com>
-
- * Win32: test compile (WinCVS, MSVC++). Have to guard isnan.
- Note: too much shit going on....
-
-2001-01-30 Bernd Kreimeier <bk at lokigames.com>
-
- * CVS: update for patching up (pre-1.27i).
-
- * SOS: new changes (new collision detection primitives).
- Now Version 1.27i.
- TODO: start testing using DLL's (QVM code is out of sync).
-
-2001-01-25 Bernd Kreimeier <bk at lokigames.com>
-
- * SOS: caught up till today (below).
- * code/qcommon/cm_trace.c: new functions added: RotatePoint,
- TransposeMatrix, CreateRotationMatrix (SOS).
- (CM_TransformedBoxTrace): new rotation code used here.
-
- * code/q3_ui/ui_demo2.c: sizeof(extension). SOS.
- * code/game/g_cmds.c (G_SayTo): CON_CONNECTED.
- * code/game/ai_main.c: HOOK added (SOS).
- * code/botlib/be_aas_move.c (AAS_HorizontalVelocityForJump):
- correct fix for FPE occuring (SOS).
- * code/game/ai_dmq3.c: initmove.viewoffset (SOS).
-
- * code/game/q_math.c: guard asser/isnan with Q3_VM (q3asm).
- TODO: define Com_Error based assert macro? NDEBUG?
-
-2001-01-24 Bernd Kreimeier <bk at lokigames.com>
-
- * code/server/sv_ccmds.c (SV_MapRestart_f): some debug.
- TODO: map_restart 0 disconnects external client in 1.27h?
-
- * code/renderer/tr_image.c (LoadTGA): added some commentary
- and dead code based on fixes from GtkRadiant (Leonardo found
- flipped TGA's).
-
-2001-01-23 Bernd Kreimeier <bk at lokigames.com>
-
- * BETA3: finished testing, ready to upload to id FTP.
- Later: neither the FreeBSD beta not the Linux Beta3
- uloaded. Beta2 not yet released, and clients get
- disconnected with Beta2 and Beta3 on SV_MapRestart_f.
-
-2001-01-22 Bernd Kreimeier <bk at lokigames.com>
-
- * code/client/cl_main.c (CL_InitDownloads): undid yesterday (SOS).
- * code/botlib/be_aas_sample.c (AAS_DeAllocAASLink): guard print (SOS).
- * code/server/sv_client.c (SV_DirectConnect): VM_Call disconnect (SOS).
- * code/qcommon/files.c (FS_ListFilteredFiles): trailing slashes (SOS).
- * code/game/g_cmds.c (SetTeam): print change (SOS).
- Note: the above plus VectorClear(v1) (below) are todays SOS changes.
-
- * code/cgame/cg_players.c (CG_PlayerShadow): ignore bogus
- (all zero) planes. This caused FPE in ProjectPointOnPlane.
- TODO: why does trace return zero normal planes?
- Note: gdb seems totally at loss with vec3_t arrays....
-
- * code/botlib/be_aas_sample.c (AAS_TraceAreas): FPE.
- NaN in uninitialized v1 that wasn't supposed to be referred
- to in this branch.
-
- * code/botlib/be_aas_move.c (AAS_HorizontalVelocityForJump):
- FPE divide by zero (zero zvel, zero t) for jump estimates.
-
- * code/client/cl_main.c (CL_Frame):1856. uivm==NULL on
- client after server crashed.
- TODO: check that uivm always non-NULL for client.
- TODO: do setenv(FX_NO_SIGNALS) to avoid exit errors...
-
- * code/unix/linux_glimp.c (GLW_SetMode): added "Indirect"
- Mesa token to software rendering detection. Reworded error
- output and added drivername.
- TODO: measure framerate instead?
-
-2001-01-21 Bernd Kreimeier <bk at lokigames.com>
-
- * SOS: caught up with changes up until today.
-
- * code/server/sv_init.c (SV_SetConfigstring): gentity != NULL
-
- * code/server/sv_client.c: connect to "{all bots" server.
- * code/renderer/tr_init.c: JPEG extension on screenshots
- * code/qcommon/files.c: modes based on mods, fs_basegame
-
- * code/q3_ui/ui_demo2.c: dm3 extension (demo names, protocol).
-
- * code/game/g_client.c: savedEvents[] removed.
- * code/game/bg_misc.c: event sequence fixes.
- * code/client/snd_dma.c (S_StopBackgroundTrack): different use.
- * code/client/cl_main.c: demo file handling changed (names).
- Also CL_InitDownloads: always next download.
-
- * code/cgame/cg_servercmds.c: cg_thirdPerson.
- * code/cgame/cg_weapons.c: see below.
- Also CG_ShotgunPattern: different call (seed parameter).
-
- * code/cgame/cg_main.c: see below.
- * code/cgame/cg_local.h: new cg_noProjectileTrail Cvar.
- * code/cgame/cg_effects.c (CG_BubbleTrail): early out (above).
-
- * code/bspc/l_poly.c (BOGUS_RANGE): increased.
- * code/bspc/bspc.c: applied patch up to "2.1e"
-
-2001-01-18 Bernd Kreimeier <bk at lokigames.com>
-
- * code/ui/ui_main.c: below.
- * code/q3_ui/ui_main.c: UI_HASUNIQUECDKEY comment.
- Note: mods have to return qfalse. See Bug #2890 in Fenris.
-
-2001-01-17 Bernd Kreimeier <bk at lokigames.com>
-
- * BETA2: finished testing, uploaded to id's FTP for release.
-
-2001-01-16 Bernd Kreimeier <bk at lokigames.com>
-
- * CVS: checking in preparation for Beta2.
- cvs tag id1-27h-loki010116-beta2
-
- * SOS: new bspc "2.1e". No change on 1.27h.
-
- * TEST: patch-up seems to work fine. No new files have been added
- to the linkage (i.e. the ft2/ files now added), so we might not be
- feature complete.
-
- * code/game/g_active.c (ClientThink_real): id MISSIONPACK
- conditional in addition to the ones I added earlier.
- * code/qcommon/files.c: REJECT. Linux hack for userdir threw it off.
- * code/qcommon/unzip.c: REJECT. CRC-32 section removed.
- Later: unused tempB
-
- * code/q3_ui/ui_syscalls.asm: REJECT. Start/StopBackgroundTrack.
- * code/ui/ui_syscalls.asm: REJECT. syscalls ids from 1.27h
- as of SOS (floor/ceil - will this ever get straightened out)
- * code/win32/win_input.c: REJECT. g_pMouse edit.
- * ui/menus.txt: REJECT. Replaced with 1.27h version.
- Note: some more due to $SOS$.
-
- * ui/: new scripts.
- cinematicmenu.menu, demo_quit.menu, ingame.txt, serverinfo_old.menu
- vid_restart.menu
-
- * code/ft2/ttconfig.h: below.
- * code/ft2/sfconfig.h: below.
- * code/ft2/pstables.h: below.
- * code/ft2/psnames.c: below.
- * code/ft2/psdriver.h/c: below.
- * code/ft2/keys.h: below.
- * code/ft2/ftbbox.c: new in 1.27h
-
- * code/cgame/cg_newdraw.c: beware: cg_newDraw.c gets lost in diff easily.
-
- * code/cgame/cg_rankings.c: file removed from SOS.
-
-2001-01-15 Bernd Kreimeier <bk at lokigames.com>
-
- * Patch-up: patching up from RC4 to 1.27h current.
- No changes since 010112 snapshot.
- ln -s sos010112/ work
- diff -urbB sos001204-rc4/ work > work.diff
- ln -s cvs-1.27g/ work
- patch -p0 < work.diff > work.patch
- find cvs1.27g/ -name '*.rej' -print
-
- * SOS: adding the remaining SOS snapshots to CVS.
- cvs import Quake3_sos sos001211 pr1-27g-win32-001211
- Note: at this point id warned about repository corruption.
- Watch out for the syscall stuff in particular.
- cvs import Quake3_sos sos010104 pr1-27g-win32-010104
- cvs import Quake3_sos sos010108 pr1-27h-win32-010108
- cvs import Quake3_sos sos010110 pr1-27h-win32-010110
- cvs import Quake3_sos sos010112 pr1-27h-win32-010112
- Note: the first 1.27h might be the public (server only)
- beta released, the second one was post release. Beware
- of source files added and removed (botlib headers, FT2).
- Note: why so late? Don't ask...
-
-2001-01-08 Bernd Kreimeier <bk at lokigames.com>
-
- * SOS: id's working up to 1.27h (server side fix for
- Guard exploit seems to force earlier release). Updating
- CVS (most of the changes are debug code put in and
- then disabled, plus some fixes as below). Next patching
- up to current SOS.
-
-2001-01-07 Bernd Kreimeier <bk at lokigames.com>
-
- * Makefile: need to rework this for multiple platforms.
- We also need null/null_vm.c for platforms where we don't
- have JIT (assembly emit).
-
-2001-01-04 Bernd Kreimeier <bk at lokigames.com>
-
- * code/q3_ui/ui_connect.c (UI_DisplayDownloadInfo): time
- information for current (vs. start of download) is wrong,
- thus negative 1 "estimated time", as well as transfer
- rate just negative downloadSize. Not fixed.
-
- * code/unix/unix_main.c (Sys_ParseArgs): added.
- Note: for support/us, to identify builts. This is only
- a skeleton right now - if I ever feel the need to support
- more than "-v" and "--version" I'll have to flesh this out.
-
- * code/unix/linux_glimp.c (signal_handler): see below.
- * code/unix/unix_main.c (Sys_Exit): added an abstraction
- layer for exit/_exit/assert/raise issues.
- Note: need both a better debug/backtrace handling, and
- have to find a way to determine why/where the alleged
- startup/exit errors happen...
-
-2001-01-03 Bernd Kreimeier <bk at lokigames.com>
-
- * code/game/g_mem.c (G_Alloc): ERR_DROP initiated by
- addbot commands for large sv_maxclients, allegedly
- caused segfaults in 1.17. Not reproducible.
- TODO: recover more gracefully from failure to add bot?
-
- * code/renderer/tr_light.c (R_LightForPoint): Tim Angus
- reports a crashbug with nolight maps. Also assertion in
- R_SetupEntityLightingGrid, might want conditional there.
- DONE: fixed crash on LightForPoint for nolight maps.
-
- * code/qcommon/qcommon.h: NUM_SERVER_PORTS. A feature
- request to increase this, or make it more flexible
- otherwise (Fenris).
- TODO: id decision on more flexible NUM_SERVER_PORTS.
-
-2001-01-02 Bernd Kreimeier <bk at lokigames.com>
-
- * code/unix/snapvector.nasm: fixed FPU bit (the current
- one had reserved bits off, behavior should not change).
- * code/qcommon/vm_x86.c: fixed symbols (below).
- * code/unix/ftol.nasm: FPU bits weren't correct (duh).
- DONE: shoot-though floor (q3dm5)
- DONE: cursor-in-rect off (TA/Player model selection)
- Note: in gdb, "disassemble <funcname>" is your friend.
-
- * code/cgame/cg_public.h: CG_MEMSET is set to 100. In
- cg_syscalls.asm it's 101. If I change it I get Bad trap 100
- from the cgame VM code, so the 1.27g "official" VM code
- uses it.
-
- * code/unix/linux_common.c: have to fall back to C, the
- current assembly is buggy...
- * code/unix/Makefile (linux_common.o): added.
- Later: also for dedicated. Less portable this way.
- TODO: C_ONLY for dedicated on non-i386 only?
-
- * code/qcommon/common.c: do not use memcpy/memset under Linux.
- * code/unix/linux_common.c: added Andrew's assembly port.
- TODO: C_ONLY for Com_Memset/Memcpy? Conditionals are fubared.
-
- * code/qcommon/vm.c (VM_Init): use Win32 defaults (do not
- use DLL's by default). This exposes DLL rounding errors
- (damage through floors), and we don't want DLL's used by
- default anyway.
- TODO: why vm_ui default of 1?
-
- * code/botlib/l_precomp.c (SourceWarning): removed assert.
-
- * code/game/bg_lib.c (acos): defined, but we don't actually
- use it except where the cg_syscalls.asm trap is used.
-
- * code/game/g_public.h: missing lots of trap tokens.
- * code/game/g_syscalls.c: missing lots of traps.
- * code/game/g_syscalls.asm: more inconsistent hooks, were:
- equ floor -111
- equ ceil -112
- equ testPrintInt -113
- equ testPrintFloat -114
- now changed to match cg_syscalls.
- Note: fixed this in UI earlier, how did this slip through
- the diffs against SOS?
-
- * code/game/g_syscalls.c: no acos hook.
- * code/cgame/cg_syscalls.c: no acos hook.
- * code/cgame/cg_syscalls.asm: has acos hook as -112
- Note: report from Tim Angus. The acos function is in bg_lib.c
- which is linked only into ui (not q3_ui). That means we are
- using libc acos right now?
- Note: QVM traps are negative?
-
- * BSD/Irix: tagged current CVS (not all of the below) as
- cvs tag id1-27g-loki010102-bsd1
- for BSD work (Rafael Barrero). Also be used for Irix update.
-
-2001-01-01 Bernd Kreimeier <bk at lokigames.com>
-
- * SOS: adding the remaining SOS snapshots to CVS.
- cvs import Quake3_sos sos001201-rc3 pr1-27f-win32-001201-rc3
- cvs import Quake3_sos sos001202 pr1-27f-win32-001202
- cvs import Quake3_sos sos001204 pr1-27g-win32-001204-rc4
- This is the codebase to which the Linux branch has been patched
- up. I can't verify whether this is identical to the RC4 codebase
- as the tag doesn't work (but can check against the ZIP file..)
- cvs import Quake3_sos sos001211 pr1-27g-win32-001211
- The above snapshot contains a (post-release?) fix to ui_syscalls
- in ui/ and q3_ui/. This change has been used in Linux (Beta1 and
- above). At this point, id discouraged further use of SOS due to
- repository corruption on their end. No further snapshots were
- taken since.
-
- * Fenris: since the release of the Beta1 bugs have been
- maintained at http://fenris.lokigames.com/. I am going to
- list issues here as they get fixed.
-
-2000-12-21 Bernd Kreimeier <bk at lokigames.com>
-
- * code/renderer/tr_font.c: graceful silence with old mods?
- * code/botlib/l_precomp.c (SourceWarning): graceful exit if old mod?
-
-2000-12-20 Bernd Kreimeier <bk at lokigames.com>
-
- * code/server/sv_ccmds.c (SV_MapRestart_f): see below.
- * code/qcommon/vm.c: currentVM is 0x0 in VM_ArgPtr.
- In VM_Call, oldVM was NULL - made conditional the
- reset of currentVM to oldVM.
-
-2000-12-18 Bernd Kreimeier <bk at lokigames.com>
-
- * BETA1: closed Linux beta release. Stripped debug
- and release binaries, DLL's, and pak4.pk3. CVS checkin,
- will be tagged as
- cvs tag id1-27g-loki001218-beta1
- Later: id added a pak5.pk3 to the Win32 point release,
- added this to the BETA1 best.
-
- * code/qcommon/vm_x86.c: C37F.
- * code/unix/snapvector.nasm: C37F.
- Note: short of any real evidence, I gamble and use max.
- precision (as well as default Linux precision, but NOT
- Win32 precision). It seems that precision change is not
- really an issue (despite Graeme's claim that the cursor
- in the menu was/is off). I also pick the roundiung behavior
- that is seemingly used by ANSI and gcc (but possibly not
- Win32 _ftol depending on build).
-
-2000-12-15 Bernd Kreimeier <bk at lokigames.com>
-
- * code/unix/Makefile: added snapvector.o
- * code/unix/unix_shared.c: #if 0'ed the old snapvector code.
- * code/unix/snapvector.nasm (Sys_SnapVectorCW): two new
- assembly functions from AndrewH that explicitely set the
- FPU control word to convert vec3_t, to ensure cross-platform
- behavior for both DLL and QVM.
-
- * code/unix/ftol.nasm (Q_ftolC37F): for globals.
-
- * code/unix/unix_main.c: took out global FPU manipulation.
- For clarity this should be VM only.
- * code/qcommon/vm_x86.c: added prototypes for the ftol
- library. To select a specific behavior for the entire VM,
- set ftolPtr accordingly.
- Later: the GCC ftol function of course affect the stack
- (there is no "declspec naked"). The problem seems to be
- that the VM never handles the stack in a way compatible
- to regular gcc C functions. For some odd reason _ftol seems
- to do the right thing under Win32. All 4 control words
- implemented at the moment work just fine with the menus.
-
- * code/unix/ftol.nasm: added a small library of "safe" qftol
- variations that explicitely set the control word to the
- relevant (4) possibilities.
-
-2000-12-13 Bernd Kreimeier <bk at lokigames.com>
-
- * code/qcommon/vm_x86.c: an entire day spent trying to nail
- the ftol issues. It breaks down like this: id used to use
- an unsafe (no setting FPU control word) fistp. That seemingly
- caused subtle physics bugs which nobody cared about in 1.17.
- They then changed the UI code, and ran into the UI bugs:
- menu entries shifted to the right, fonts vanishing. Then
- they switched to using _ftol. Then they had to reproduce
- the old behavior for the physics code due to public outrage.
- My original port used a simple (long)float cast, which gcc
- seemingly compiles to code that does OR 0C00 on whatever
- current control word (precision unchanged). This breaks the
- menus. If I use the unprotected fistp instead, which should
- (Linux 037F default) use "nearest/even", then my menus are
- correct. That would mean Win32 _ftol in id's compile does
- the same, only that would require /qifist or some equivalent
- compile flag, which I can't find. Two disassemblies of _ftol
- I got from others showed OR 0C00 as part of the default (ANSI)
- behavior.
-
-2000-12-13 Bernd Kreimeier <bk at lokigames.com>
-
- * code/game/bg_pmove.c (PmoveSingle): trap_SnapVector.
- The one true and single call to snap velocity.
- Note: bspc/map.c:void SnapVector(vec3_t normal)
- qcommon/cm_patch.c:void CM_SnapVector(vec3_t normal)
- game/q_shared.h: #define SnapVector(v) {v[0]=((int)(v[0]));...
-
- * code/client/cl_cgame.c: CG_SNAPVECTOR.
- * code/server/sv_game.c: G_SNAPVECTOR.
- Note: these go through trap_SnapVector in syscalls.
-
- * code/unix/unix_shared.c (Sys_SnapVector): sticking to
- old Linux version for now...
- * code/win32/win_shared.c (Sys_SnapVector): changed.
- Note: Graeme points out this was changed to fix ftol
- artifacts?
- TODO: calculate errors for various ftol variants...
-
- * code/qcommon/vm_x86.c: both the old fistp code (1.17)
- and the new qftol function apparatently work. Using the
- ftol.nasm code for now.
-
- * code/unix/Makefile: DO_NASM and ftol.o.
-
- * code/unix/ftol.nasm (qftol): created from Mike's SoF
- replacements, with Andrew's help to satify the VM
- stack/call requirements.
- TODO: use Q_ftol herein to replace myftol elsewhere.
-
- * code/unix/unix_main.c (Sys_ConfigureFPU): SIGFPE.
- TODO: divide by zero in botlib. Disable this for now.
- Note: we can't introduce calculation differences between
- versions, so fixing these will have to wait.
-
- * code/qcommon/vm_x86.c: two new lines in Win32 branch
- missing from Linux assembly in AsmCall:
- mov eax, dword ptr [edi]
- and eax, [callMask]
- Added, doesn't seem to affect UI etc. bugs.
- Later: no FTOL_PTR, use fistp non-IEEE assembly as in old
- version. This seems to work for Q3 and TA, while qftol
- (simple cast) does not - for Win32 Graeme says the reverse
- is true.
-
- * code/qcommon/vm_x86_old.c: used the old cvs-1.17 version.
- Two fixes (Hunk_Alloc, Com_Memcpy), and it works:
- +set vm_game 2 +set vm_ui 2 +set vm_cgame 2
- UI, cgame and game w/o apparent problems.
-
-2000-12-12 Bernd Kreimeier <bk at lokigames.com>
-
- * code/unix/Makefile: cleanup of redundant flags.
- Removed bogus MALLOC_CHECK (note to self: export MALLOC_CHECK_=2).
- Also DO_SHLIB_CC on all UI DLL's.
- Added and removed DEBUG_VM flag.
- TODO: figure out whether Zoid did UI this way intentionally.
- Note: this seemingly fixed the botimport problem, although
- most of the changes were just redundant CFLAGS removed. Given
- our wanker toolchain, should have been more paranoid. All
- DLL's can now be used w/o apparent problems.
-
- * code/server/sv_main.c: gvm init.
- * code/server/sv_game.c: gvm assertions.
- * code/unix/unix_main.c (Sys_LoadDll): print vmMain
- Note: top no avail. There is some odd ld/gdb problem here
- that prevents examining globals and obfuscates part of
- the stack between VM_Call and lower level code, through
- G_InitGame. This is not just DLL's being loaded and unloaded.
- Wromg flags during build? The vmCvar for "bot_developer"
- ends up overlapping global botimport in memory, which
- thus zero-fills part of the function pointer table.
-
- * code/server/sv_bot.c (SV_BotInitBotLib): this (by way of
- GetBotLibAPI) is responsible for setting botimport, which,
- if using the game DLL, is not properly set up. Called in
- SV_Init().
-
- * code/game/q_shared.c: Q_strncpyz does zero padding (duh).
- Note: calls strncpy, which does a zero fill up to destsize.
- If destsize exceeds memory size, zero padding will overwrite
- adjacent memory. Suspicion was this happend to botimport.
-
- * code/qcommon/cvar.c: possible problem in Q_strncpyz call.
-
- * code/botlib/be_ai_weap.c (weaponinfo_fields): made this static.
- Note: it seems that the "number" string got replaced by
- p def.fields[0]
- {name = 0x40000000 "\177ELF\001\001\001", offset = 2, type = 50, ..
- Memory corruption?
-
- * code/game/inv.h (WEAPONINDEX_GAUNTLET): defined here.
- * botfiles/weapons.c (Gauntlet): the baseq3/qagamei386.so parser
- breaks here:
- number WEAPONINDEX_GAUNTLET
- * code/botlib/l_precomp.c (SourceWarning): added assertion to
- trap botlib parsing problem..
-
- * RC1: for beta test. Using my own vm/ui.qvm files in this case.
- TODO: Setup with nouninstall.
- TODO: fix game DLL/ botlib setup problem (so all DLL's work)
- TODO: SIGFPE
- TODO: profile?
-
- * code/unix/Makefile (ai_vcmd.o): added to game DLL linkage.
- How the fuck did this happen?
- DONE: "qagamei386.so: undefined symbol: BotVoiceChat_Defend"
-
- * TEST: +set vm_ui 2 (vm_x86, not interpreter). Breaks!
- Further: qagame had undefined, but seemingly gets reloaded
- second try (I hate the Linux linker).
- * TODO: never reload fail DLL, abort engine
-
-
-2000-12-11 Bernd Kreimeier <bk at lokigames.com>
-
- * TEST: recompile QVM/DLL and executable to test new UI code.
- The UI QVMs from the paks still do not work.
-
- * SOS: changes in UI code!
- * code/q3_ui/ui_public.h: this file is deprecated
- Note: e.g. it does not contain the background track calls.
- * code/ui/ui_public.h: the uiImport_t enum here determines
- the values.
- * code/ui/ui_syscalls.asm: same as q3_ui now, were:
- equ floor -111
- equ ceil -112
- * code/q3_ui/ui_syscalls.asm: these are now switched, were:
- equ trap_S_StartBackgroundTrack -63
- equ trap_S_StopBackgroundTrack -64
- The new values match the ui/ equivalent. Also, floor (-108)
- and ceil (-109) are different in ui/.
-
- * CVS: going to check in this snapshot and tag it as
- cvs tag id1-27g-loki001209-rc4
- Presumed equivalent to SOS tag "1.27g RC4" (master). As I can't
- obtain the tagged code using SOS (neither Win32 nor Linux client)
- I can only guess.
-
- * TEST: use my own VM code, ion baseq3/vm/*.qvm and missionpack/vm/.
- This works - in other words, the menu bug seems in the UI code, and
- is fixed in my codebase.
-
- * TEST: make release.
- Note: I can postpone DLL specific problems. Bad performance is not
- as important as outright bugs. Thus the UI QVM issue is the only
- one that stops me from creating an RC.
- TODO: Q3 UI QVM code from pak file does not work (neither does TA).
- TODO: sound with video playback still awful. Threaded sound, I guess.
- TODO: ERROR: couldn't open demos/DEMO002.dm3.dm_48 (same demo001.dm3.dm_48)
-
- TODO: do not show Q3 demos in TA menu?
- TODO: new demos for Q3? Or at least error message?
-
- * code/game/bg_lib.c: itrinsics excluded by Q3_VM (another -O
- compile). Uninitialized variable.
- * code/unix/Makefile: -O for uninit on patched code. Also shortcuts.
- TODO: DC_ONLY seems an obsolete flag, used in Makefiles, not source.
-
- * TEST: +set sv_pure 0 +set vm_game 1 +set vm_cgame 1 +set vm_ui 0
- Turns out that the pak0.pk3 UI QVM code is seemingly broken in TA
- and Q3, but my UI DLL is not. In reverse, the QVM game/cgame for
- Q3 seems to work quite well (including bots). The TA game/cgame
- also works, including botlib init.
- TODO: BotLib Init using game DLL gives:
- TODO: Error: file weapons.c, line 38: unknown structure field number
- TODO: Fatal: couldn't load the weapon config
- TODO: Error: BotLoadMap: bot library used before being setup
-
- * TEST: checked the rc4winstlr.zip CD tree against
- my test install. baseq3/pak4.pl3 and missionpack/pak0.pk3
- are identical, but I finally recognized that there was
- a missionpack/pak1.pk3 not in the final install - left over
- from an earlier update from id. Doesn't seem to affect the
- DLL based runs at all.
- Note: I still do not have the final CD snapshot Robert
- promised me mid last week, they haven't even fixed the
- FTP account they took down. Communication with id is as
- abyssmal as ever.
-
-2000-12-08 Bernd Kreimeier <bk at lokigames.com>
-
- * TEST: running with RC4 data files.
- TODO: "bot library used before setup" (Q3+TA)
- TODO: Q3 old mods wreak havoc (graceful bounce)
- TODO: supress "FreeType code not available" in renderer
- TODO: can't move in Q3
- TODO: items flicker in Q3
- TODO: no decals in Q3
- TODO: VM UI code still broken (Q3+TA)
- TODO: sound code is awful
- TODO: video playback inferior to earlier builds
-
- * code/q3_ui/ui_local.h: prototype trap_VerifyCDKey(..)
- * code/game/g_active.c ( StuckInOtherClient): TA only.
- * code/cgame/cg_draw.c: 4x unbalanced `#endif' - from patch?
- * code/null/null_client.c (CL_CDKeyValidate): dummy added.
- * code/qcommon/common.c: Q_acos missing, changed conditionals
-
- * code/qcommon/vm_x86.c: unreacheable _asm instruction that
- gcc doesn't quite like... #if 0'ed for now
- TODO: understand _asm { mov eax,[ebx] }, fix it for gcc
-
- * TEST: compile...
-
- * code/ui/ui_main.c: full REJECT. Manual merge.
- Note: preserved debug_protocol lines, who knows what it's good for.
-
- * code/qcommon/files.c: REJECT. SafeMode, demo server FS_Restart.
-
- * code/client/snd_mem.c: REJECT: $SOS$.
- * code/client/snd_dma.c: REJECT: $SOS$.
- * code/client/cl_cin.c: REJECT. com_timescale, $SOS$.
-
- * code/cgame/cg_draw.c: REJECT. Lots, but virtually all either
- float postfix (on some, not all places), or #ifndef MISSIONPACK
- that I had already put in during -Werror (conditional unused).
-
- * code/cgame/cg_consolecmds.c: REJECT. id commented unused code
- that I had #if 0'ed earlier.
-
- * code/game/: three REJECT for $SOS$.
- * code/botlib/: lots REJECT for $SOS$.
-
- * Patch: patching up from demo source.
- ln -s sos001204-rc4 work
- diff -urbB sos001122-demo/ work > work.diff
- ln -s cvs-1.27b/ work
- patch -p0 < work.diff > work.patch
- find cvs1.27b/ -name '*.rej' -print
-
- * CVS: going to check in this snapshot and tag it as
- cvs tag id1-27b-loki001208-demo
- Then patching up to RC4, as of sos001204-rc4 (no changes since,
- should be equivalent to SOS tag "1.27g RC4" (raduffy), i.e. master.
-
- * TEST: installed demota/ from Win32 distribution. Binary
- fails claiming "Corrupted pak0.pk3". Abandoned.
- Note: a Linux demo for Q3TA has no priority. Most important is
- the Q3A point release in time for Q3TA hitting shelves, followed
- by testing for Q3TA. The source is in CVS and tagged (see above)
- in case a demo matching the released files has to be provided
- later.
-
-
-2000-12-07 Bernd Kreimeier <bk at lokigames.com>
-
- * TEST: compile and link - succeeds.
-
- * code/ui/ui_main.c: UI_StopServerRefresh now uaws.
- New unused variables.
-
- * code/unix/unix_main.c: added Sys_LowPhysicalMemory() stub.
- TODO: write Linux equivalent to GlobalMemoryStatus.
-
- * code/qcommon/common.c: Com_Memset/Com_Memcpy. Neither assembly
- nor C versions included if not on Win32 i386.
- TODO: using/porting assembly?
-
- * code/qcommon/files.c: unused variable.
- TODO: fs_scrambledProductId unused if 0 for now.
- Note: -DFS_MISSING for id's pak cleanup, not used.
-
- * TEST: compile and link - fails.
-
- * code/macosx/Client/Makefile.postamble: empty ORIG.
- * code/macosx/Client/Makefile.preamble: ORIG. $(BOTLIB_OBJS) added.
-
- * code/server/sv_client.c: ORIG. Com_Memset.
- * code/renderer/tr_shader.c: ORIG. Com_Memset, CIN_Shader.
- * code/qcommon/vm_x86.c: ORIG. Com_Memcpy.
- * code/qcommon/unzip.c: REJECT. Com_Memcpy, $SOS$.
- * code/qcommon/qcommon.h: ORIG. PROTOCOL 47, plus Sys_LowPhysicalMemory.
- * code/qcommon/md4.c: Com_Memset,Com_Memcpy (ORIG).
- * code/qcommon/files.c (Sys_ConcatenateFileList): REJECT.
- Our additons threw it off, plus $SOS$.
- * code/qcommon/common.c: they fixed same unused variables (REJECT).
-
- * code/ui/ui_shared.c: additions (ORIG).
- * code/ui/ui_gameinfo.c: COM_Compress added (ORIG).
- * code/ui/ui_atoms.c: print statements removed (ORIG).
- * code/ui/ui_main.c (UI_DoServerRefresh): REJECT on comment edit...
-
- * code/game/g_cmds.c (Cmd_VoiceTaunt_f): logic changed heavily. ORIG.
- * code/game/q_shared.h: Q3_VERSION "Q3 Team Arena Demo 1.27b"
- plus Com_Memset, Com_Memcpy, CIN_shader, COM_Compress.
- * code/game/g_main.c: Cvar change only
- * code/game/ai_dmq3.c: $SOS$.
-
- * code/client/snd_mix.c: Com_Memset
- * code/client/client.h: additions (ORIG).
- * code/client/snd_mem.c: see below.
- * code/client/snd_dma.c: $SOS$ (CVS keyword).
-
- * code/client/cl_cin.c: they removed unused (REJECT).
- * code/cgame/cg_servercmds.c: ORIG. compress, noTaunt etc.
- * code/cgame/cg_main.c: ORIG. Conditonal branch, COM_Compress.
- * code/cgame/cg_consolecmds.c: ORIG. Cvar values changed.
- * code/cgame/cg_draw.c (CG_DrawTeamBackground): ORIG.
- no reject but *.orig file created. I just mark spots were
- code changed after verifying the patch succeeded.
-
- * code/cgame/cg_event.c: fixed reject (REJECT).
- * code/botlib/: all *.rej here due to SOS/CVS $Keyword$.
- TODO: preserve SOS comments/rev history somehow.
-
- * Patch: patching up to demo source.
- ln -s sos001122-demo work
- diff -urbB sos001119/ work > work.diff
- ln -s cvs-1.26/ work
- patch -p0 < work.diff > work.patch
- find cvs1.26/ -name '*.rej' -print
-
- * CVS: going to check in this snapshot and tag it as
- cvs tag id1-26w-loki001207
- to prepare for upgrading to RC4. I have already made
- many more changes than I wanted to w/o getting any
- closer to pinpointing the problem, I might as well
- patch up to id's more current sources.
-
- * code/botlib/be_interface.c: initialize by memset. Turns
- out that this fails in Export_BotLibSetup on BotSetupWeaponAI
- loading "weapons.c" (from the pak, presumably) with an unknown
- structure field number. Mismatch of datafiles vs. source again.
-
- TODO: id replaced memsets in later source.
- TODO: have memsets on all exports and imports.
-
- * SOS: RC4 source should be tagged "1.27g RC4" (raduffy).
- Unfortunately the Linux client doesn't care a bit. Show
- History does work if from/to date differ by at least a
- day, and it shows the tag on code/ (only that subtree),
- but recursive get aborts halfway.
- Manual: http://www.sourcegear.com/SOS/Doc/
-
-2000-12-06 Bernd Kreimeier <bk at lokigames.com>
-
- * TEST: accepting missing shaders now. No bots, but I can
- actually enter the game and play (more than can be said for
- classic Q3 right now).
- TODO: Error: BotStartFrame: bot library used before being setup
-
- * code/renderer/tr_shader.c: took out assertion for now...
- * TEST: now missiopack/cgame loads
- TODO: tr_shader.c:2275: R_FindShaderByName: failed
- TODO: searches ui/assets/3_cursor2.TGA, has ui/assets/3_cursor3.tga
-
- * code/unix/Makefile (MPCGOBJ): ui_shared.o (duh).
- DONE: /cgamei386.so: undefined symbol: PC_Float_Parse
-
- * code/botlib/be_ai_goal.c: initialize campspots etc. This
- might or might not fix this one (didn't get back to gdb due
- to mouse-only navigation).
- DONE: 0x80d1d5b in BotFreeInfoEntities () at be_ai_goal.c:447
-
- * TEST: this time with missionpack/cgame loading... noy
- TODO: TA menu blocked after end of intro movie
- TODO: console in_mouse 1 doesn't grap pointer even on vid_start?
-
- * code/cgame/cg_newdraw.c: -Werror.
- * code/unix/Makefile (MPCGOBJ): cg_newdraw.o was missing (duh).
- DONE: missionpack/cgamei386.so: undefined symbol: CG_OwnerDrawVisible"
-
- * code/ui/ui_shared.c:1309 assign after bail on NULL.
- DONE: segfault in Item_SetFocus (item=0x0, x=0, y=0)
-
- * TEST: new set of DLL's (this time hopefully correct).
- All baseq3/ DLL's load, as does the missionpack/ UI DLL.
- The menus now work in both (TA seems mouse-only on everything
- but "Quit"). Segfault on delayed TA "Quit" (stack fubared):
- #5 0x809fc28 in VM_Call (vm=0x88408a0, callnum=3) at ..//qcommon/vm.c:617
- #6 0x805aafc in CL_KeyEvent (key=9, down=qtrue, time=128644) cl_keys.c:1194
- TODO: TA menu's w/o mouse?
- TODO: Win32 goes submenus but does not unfold
- TODO: Linux does not go submenus
-
- * code/ui/ui_main.c: see below.
- TODO: LCC gets fits - operands of = have illegal types
- TODO: 'pointer to const unsigned char' and 'pointer to const char'
- * code/ui/ui_shared.c: see below.
- * code/ui/ui_gameinfo.c: see below.
- * code/ui/ui_atoms.c: see below.
- * code/game/g_bot.c: more cruft.
- * code/cgame/cg_draw.c: loads of functions modified for
- MISSIONPACK that aren't used at all for MISSIONPACK anymore.
- Development relics.
-
- * code/cgame/cg_consolecmds.c: -Werror.
- Note: due to Makefile error never ever compiled...
-
- * code/unix/Makefile: fixed various dependency errors
- for game and ui library.
- TODO: create a new Makefile with patsubst and rules.
- TODO: why C_ONLY in the i386 dedicated server?
-
- * code/unix/unix_main.c: use dlerror() excessively.
- Littered more unused DLL related functions with assert(0).
- TODO: clean up Sys_Load/UnloadDll (a real mess)
- TODO: remove Zoid code cruft (unused per-DLL functions)
-
- * code/game/bg_misc.c: changed G_Printf for Com_Printf.
- This was undefined in baseq3/uii386.so preventing loading.
-
- * TEST: +set sv_pure 0 +set vm_game 0 +set vm_cgame 0 +set vm_ui 0
- Note: so far I used only the game DLL.. duh.
- UI DLL fails to load: missing G_Printf.
-
- * code/unix/Makefile: -DMALLOC_CHECK in addition to
- the -DZONE_DEBUG I have used since switching to calloc.
- Using MALLOC_CHECK=1 for now, might use 2 if something
- comes up.
-
- * code/renderer/tr_init.c (GL_SetDefaultState): it does get
- called, but does not show up in the log.
-
- * TEST: tried executing a script - get bounced.
- TODO: is there any way to jump into a map?
- TODO: cl_cinematics 0 (supress all fullscreen RoQ)
- Next: used r_logfile 200 in Win32 (RC4) and Linux.
- There is a buckload of setup code seemingly not done
- at all in Linux? Either that, or logging is enabled
- with a delay in Linux.
-
- * code/unix/linux_glimp.c: fixed autorepeat (H2/Fakk2 way).
-
-2000-12-05 Bernd Kreimeier <bk at lokigames.com>
-
- * code/renderer/tr_mesh.c: added assert there.
- * TEST: menus and in-game drawing are just as they were with
- the initial SOS001119 port. In addition:
- R_AddMD3Surfaces: no such frame 0 to -2147483477
- for 'models/players/xaero/upper.md3'
- R_AddMD3Surfaces: no such frame -2147483477 to 171
- R_AddMD3Surfaces: no such frame 171 to -2147483498
- ad nauseam (used as my player model).
- Triggered: haveing a trRefEntity_t *) 0x41dbbd00 with
- frame = -2147483477. Might be a red herring (PRINT_DEVELOPER),
- ignore for now.
-
- * code/ui/ui_main.c: missing return.
- * code/ui/ui_shared.c: excess byte in initializer (which gcc
- did not caught, but LCC did). Also LCC complains about
- missing returns, but gcc doesn't (neither says unreacheable
- code though). If necessary (MsVC?) guard with Q3_VM.
-
- * code/q3_ui/ui_ingame.c: see below.
- * code/q3_ui/ui_atoms.c: voidfunc_f. LCC warns about conversion
- from `pointer to void' to `pointer to void function(void)'
- being compiler dependent. Casting NULL. Guess what, doesn't fix
- it either.
- TODO: do not use these cursed scripts to generate VM code,
- we do not have proper rules for LCC/q3asm, thus the files never
- get updated.
-
- * code/unix/Makefile: for paranoia's sake recreated the 1.17
- compile for the UI DLL (where only q_shared/math were actually
- compiled as DO_SHLIB_CC.
- Later: switched to different gcc.
-
- * STATIC: remaining problems are vmMain (same entry point for all
- DLL's), could use cgMain, uiMain and gMain here for HARD_LINKED.
- Note: I don't think id has used this in ages.
- Plus all the collisions in *_syscalls.c, which simply can't be
- fixed cheaply. None is the superset of 2 others, neither seems
- w/o overlap to others. Full stop.
-
- * code/botlib/be_aas_move.c: see below.
- * code/game/ai_dmq3.c: VEC_UP/DOWN, MOVEDIR_UP/DOWN now static.
- See also game/g_utils.c for existing static duplicates.
-
- * code/game/q_shared.h: #define stricmp strcasecmp
- * code/unix/Makefile: no mo' -Dstricmp=strcasecmp, see q_shared.h
- Also: no mo' -I/usr/include/glide, no FX
- TODO: are we building against system GL headers? ../Mesa/?
-
- * code/q3_ui/ui_atoms.c: comment on duplication
- * code/cgame/cg_drawtools.c: use UI/CGAME_HARD_LINKED on UI duplicates
- TODO: does this UI_ code in cg_drawtools/ui_atoms belong into ui_shared?
-
- * code/unix/Makefile: use -DQ3_STATIC
- * code/game/q_shared.h (*_HARD_LINKED): trigger on Q3_STATIC
- Later: collision between UI and CGAME is still there. This fixed
- the Com_Error, Com_Printf issues though
-
- * code/unix/Makefile ($(B)/q3static/ai_vcmd.o): this file was
- missing, hence undefined symbol.
- ($(B)/baseq3/game/ai_vcmd.o): same here.
- ($(B)/missionpack/game/ai_vcmd.o): same here.
-
- * STATIC: cg_syscalls.c, g_syscalls.c and ui_syscalls.c alias.
- Multiply defined symbols:
- Com_Error, Com_Printf
- VEC_UP, VEC_DOWN
- MOVEDIR_UP, MOVEDIR_DOWN
- vmMain
- dllEntry
- PASSFLOAT
- trap_Error
- trap_Milliseconds
- trap_Argc
- trap_Argv
- trap_FS_FOpenFile
- trap_FS_Read
- trap_FS_Write
- trap_FS_FCloseFile
- trap_FS_GetFileList
- trap_R_RegisterModel
- trap_R_RegisterSkin
- trap_R_RegisterFont
- trap_R_RegisterShaderNoMip
- trap_R_ClearScene
- trap_R_AddRefEntityToScene
- trap_R_AddPolyToScene
- trap_R_AddLightToScene
- trap_R_RenderScene
- trap_R_SetColor
- trap_R_DrawStretchPic
- trap_R_ModelBounds
- trap_UpdateScree
- trap_S_StartLocalSound
- trap_S_RegisterSound
- trap_Key_IsDown
- trap_Key_GetCatcher
- trap_Key_SetCatcher
- trap_GetGlconfig
- trap_PC_AddGlobalDefine
- trap_PC_LoadSource
- trap_PC_FreeSource
- trap_PC_FreeSource
- trap_PC_ReadToken
- trap_PC_SourceFileAndLine
- trap_S_StopBackgroundTrack
- trap_S_StartBackgroundTrack
- trap_RealTime
- trap_CIN_PlayCinematic
- trap_CIN_StopCinematic
- trap_CIN_RunCinematic
- trap_CIN_DrawCinematic
- trap_CIN_SetExtents
- trap_MemoryRemaining
- trap_SendConsoleCommand
- trap_Cvar_Register
- trap_Cvar_Update
- trap_Cvar_Set
- trap_Cvar_VariableValue
- trap_Cvar_VariableStringBuffer
- trap_RealTime
- trap_SnapVector // used in game/bg_*.c, needs conditional
- More aliasing between ui_atoms.c and cg_drawtools.c:
- UI_DrawBannerString
- UI_ProportionalStringWidth
- UI_ProportionalSizeScale
- Undefined symbol: ai_team.o: In function `FindHumanTeamLeader':
- ai_team.c:1899: undefined reference to `BotVoiceChat_Defend'
- Note:
-
- * code/game/g_main.c: unused.
- * code/game/g_arenas.c: unused.
- * code/game/ai_team.c: init.
- * code/game/ai_dmnet.c: /* in comment (odd).
- Note: why do these come up now but not earlier?
- TODO: the make dependencies might target wrong files.
-
- * code/unix/Makefile (TARGETS): added q3static.
- Note: this is baseq3/
-
- * TEST: +set r_logfile 100. It seems that the addition of
- code (add an assertion etc.) changes the behavio of the binary.
- The intro cinematics code seems to suffer first - didn't play,
- then played, then (another assert added) doesn't play. Watch
- out for (missionpack):
- UI_CIN_PlayCinematic
- SCR_PlayCinematic( mpintro.roq )
- trFMV::play(), playing mpintro.roq
- Also fails to exit cleanly: break gives
- #0 0x401919ee in __select ()
- #1 0x400bbcb8 in __DTOR_END__ ()
- #2 0x4004baa1 in _XSend ()
- #3 0x452b009f in GLXRenderFlush ()
- #4 0x804ce0c in _XRead ()
- #5 0x40680813 in ?? ()
- Stack is corrupted.
- Note: ~/.q3a/gl.log
- TODO: write per-frame files (see Heretic2)
- TODO: add Heretic2 QGL (more detail)
-
- * code/unix/linux_qgl.c (QGL_EnableLogging): fixed countdown
- (i.e. propagated changes from win32/, see Fakk2).
-
- * code/unix/linux_glimp.c: fixed QGL_EnableLogging argument
- to avoid cast error (always qfalse).
-
- * code/unix/Makefile (DEBUG_CFLAGS): use ZONE_DEBUG.
-
- * code/qcommon/common.c: replaced malloc with calloc calls.
-
- * code/q3_ui/ui_local.h: have to use ui/ui_public.h
- * code/cgame/cg_servercmds.c: requires ../ui/menudef.h
-
- * code/cgame/cg_consolecmds.c: ui/ui_shared.h is unique.
- * code/q3_ui/ui_public.h: make sure this won't be compiled.
- * code/client/client.h: we have to include ui/ui_public.h.
- Note: id is obviously maintaing only the ui/ headers, so the
- headers in q3_ui/ are deprecated.
-
- * code/renderer/tr_shader.c: added assertions (see Ryan's Fakk2
- problems with missing shaders).
-
- * code/game/g_cmds.c: below.
- * code/game/ai_vcmd.c: below.
- * code/game/ai_team.c: below.
- * code/game/ai_dmnet.c: below.
- * code/game/ai_dmq3.c: below.
- * code/game/ai_chat.c: below.
- * code/game/ai_cmd.c: ../../ui/menudef.h (new Q3TA script directory).
-
- * code/cgame/cg_newdraw.c: make sure it won't compile w/o MISSIONPACK.
-
- * code/cgame/cg_servercmds.c: below.
- * code/cgame/cg_event.c: below.
- * code/cgame/cg_consolecmds.c: below.
- * code/client/keys.h: below.
- * code/client/client.h: below.
- * code/q3_ui/ui_local.h: include from ../q3_ui/ not ../ui/.
- Note: id seems to intentionally use the header from the new ui/.
-
- * Makefile: checked -I$(UIDIR), there is no such. That means all
- files include directly, which means all (including Q3) are using
- the new ui/ headers.
-
-2000-12-04 Bernd Kreimeier <bk at lokigames.com>
-
- * RC4: released as 362101115 Dec 4 11:40 TA_Q3A_RC4.zip
-
- * TEST: the corrupted menu problem is back :-(. Looks like I am in
- for a static link next.
-
- * code/unix/Makefile (clean2): fixed (not all new OBJ covered).
- * code/q3_ui/ui_teamorders.c: -Werror.
- * code/q3_ui/ui_team.c: -Werror.
- * code/q3_ui/ui_qmenu.c (Bitmap_Draw): -Werror.
- * code/q3_ui/ui_mods.c (UI_Mods_LoadModsFromFile): unused. -Werror.
- * code/q3_ui/ui_controls2.c: -Werror.
- * code/q3_ui/ui_atoms.c: -Werror
- * code/null/null_client.c: -Werror.
- * code/unix/linux_joystick.c: -Werror.
- * code/unix/linux_glimp.c: -Werror.
- * code/unix/linux_qgl.c: -Werror.
- * code/unix/unix_shared.c: -Werror.
- * code/unix/unix_net.c: -Werror.
- * code/unix/linux_local.h: added missing prototypes.
- * code/unix/unix_main.c: -Werror. Includes linux_local.h
- * code/jpeg-6/jdmainct.c: see below.
- * code/jpeg-6/jcmainct.c: variables called "main" (*moan*)
- * code/jpeg-6/jcdctmgr.c (forward_DCT): -Werror.
- * code/botlib/l_script.c (PS_ReadLiteral): -Werror
- * code/botlib/l_precomp.c (PC_AddBuiltinDefines): -Werror.
- * code/botlib/be_interface.c: -Werror.
- * code/botlib/be_aas_reach.c: -Werror
- * code/botlib/be_aas_cluster.c: -Werror
- * code/game/be_aas.h: -Werror.
- Note: MrElusive accumulates a lot of code history in nested comments,
- which gcc doesn't like at all. #if 0'ed to avoid.
- * code/qcommon/vm_interpreted.c: -Werror.
- * code/qcommon/unzip.c: -Werror.
- * code/cgame/cg_servercmds.c: -Werror.
- * code/cgame/cg_main.c: -Werror.
- * code/cgame/cg_drawtools.c: -Werror.
- * code/game/bg_misc.c: -Werror.
- * code/game/be_ai_move.h (bot_avoidspot_s): added.
- * code/botlib/be_ai_move.c: removed typedef struct bot_avoidspot_s
- * code/client/snd_mix.c: -Werror.
- * code/qcommon/md4.c: -Werror.
- * code/qcommon/common.c: -Werror.
- * code/client/cl_keys.c: -Werror.
- * code/client/cl_cin.c: -Werror, init local variables.
- * code/unix/Makefile: -Werror. need -O for -Wall for uninitialized
- Note: the above is the list of files that got touched during a pass
- with -g -O -Werror -Wall flags (in the hope of finding uninitialized
- memory and ambiguous statements). Most of the above are simply
- unused variables (or even code).
-
- TEST: RC3 data files, but DLL's.
- TODO: TA gets stuck in initial sound, doesn't play cinematics (sometimes)
- TODO: Q3 intro movie looses sound after Sarge gets teleported
- TODO: Q3 ingame renders world, weapon, muzzleflash, hud, can shoot,
- TODO: but no movement, hud background is fubared.
-
- * code/cgame/cg_main.c: cg_singlePlayerActive
-
- * code/q3_ui/ui_login.c: doesn't seem to be used?
- * code/game/g_rankings.c (G_RankRunFrame): doesn't seem to be used.
- * code/q3_ui/ui.sh: disabled this.
- * code/q3_ui/q3_ui.sh: changed include path to ../q3_ui/ (duh).
-
- * code/game/game.sh: changed include path to ../q3_ui/ which
- is not in the Win32 batch file.
- * code/cgame/cg_rankings.c: this does not seem to be included.
- * code/cgame/cgame_ta.sh: added -DCGAME. Also added cg_syscalls.c
- to build (also missing in Win32).
-
- * code/cgame/cgame.sh: added -DCGAME (see cgame.bat). Also
- changed include path to ../q3_ui/ which is not in the Win32
- batch file. Also added cg_syscalls.c to build (missing in
- Win32).
-
-2000-12-01 Bernd Kreimeier <bk at lokigames.com>
-
- * RC3: released as of sos001201 / Q3 1.27f
-
- * code/unix/Makefile: more fixes with clean build. The
- changes made fix the menu rendering for Q3 but not TA.
- Ingame graphics still broken.
-
- * code/game/game_ta.sh: created. Use game_ta.q3asm here.
- * code/game/game.sh: no -DMISSIONPACK
- * code/game/game_ta.q3asm: CR/LF, /.
-
- * code/cgame/cgame_ta.sh: created. Use cgame_ta.q3asm here.
- * code/cgame/cgame.sh: no -DMISSIONPACK. No cg_newdraw, ui_shared.
- * code/cgame/cgame.q3asm: No cg_newdraw, ui_shared.
- CR/LF, /, cg_newDraw, and the output path/name.
-
- * code/q3_ui/q3_ui.q3asm: output to ui not q3_ui...
-
- * code/cgame/cg_event.c: cg_singlePlayerActive used here.
- TODO: guard by MISSIONPACK
- * code/cgame/cg_local.h: named q3print_t enum. Cvar
- cg_singlePlayerActive for both Q3 and TA.
-
-
- * code/unix/Makefile: cleanly separate B/baseq3/ and
- B/missionpack/ subtrees during build. While new and old
- UI are in separate directories, the cgame/ and game/
- are shared, with conditional -DMISSIONPACK compile
- and different files includeds (cd_draw, cg_newdraw).
- That means twice the number of targets (3 DLL's, 3 QVM's,
- times two), and different build rules.
- TODO: carefully check Win32 build for (other) conditionals
- TODO: carefully check Win32 build for link lists
-
- * CVS: ui/, code/ui, botfiles/ and subdirectories are added.
- The code/macosx/ directory turned out to be a real pain that
- had to be edited manually, throwing out CVS/ directories in
- the tree that had been created by SOS as they are in id's
- repository:
- code/macosx/Client/CVS
- code/macosx/Client/PBUserInfo/CVS
- code/macosx/Client/Quake3.nib/CVS
- code/macosx/Common/CVS
- code/macosx/DedicatedServer/CVS
- code/macosx/DedicatedServer/PBUserInfo/CVS
- Now tagged
- cvs tag id1-26y-loki001119
- TODO: there are several new files not yet linked?
-
- * ChangeLog: merged the Changelog from the bk00119 working
- branch (initial Q3TA port) based on sos001119 snapshot. Also
- merged the source tree with cvs-1.17.
- In the ChangeLog below *** MISSIONPACK *** indicates work
- that was done on the branch (code-sos/ prefix in files).
- The cvs update of this will be tagged with
- cvs tag id1-26y-loki001119
- Use this tag to hunt for possible Linux fixes that got lost
- (i.e. got dropped by id since id000516 and were thus not in
- sos001119, but did not show in diff id000516 cvs1-17).
- New directories in CVS: botfiles/, ui/.
- Missing from SOS/Missionpack: SDK directories.
- common, lcc, libs, q3asm, q3data, q3map, q3radiant.
-
-
- * ssreport.txt: below.
- Note: watch for files called "ssreport.txt", that's id ChangeLog.
- * ui/ui_syscalls.asm: below.
- * q3_ui/ui_syscalls.asm: below.
- * game/g_syscalls.asm: below.
- * cgame/cg_syscalls.asm: below.
- * bspc/linux-i386.mak: below.
- * bspc/lcc.mak: below.
- * botlib/linux-i386.mak: below.
- * botlib/lcc.mak: below.
- * A3D/a3d_console_variables.txt: CR/LF issue (minimize diffs).
-
- * CVS: the checked bk001119 work copy of the sos001119 initial
- checkout (completed with everything in the SOS "Missionpack"
- tree, i.e. botfiles/ and botfiles.* added), copied over the
- cvs-1.17 checkout.
- Note: in these cases, BEWARE ui -> q3_ui/ links, and different
- ChangeLogs. Also "make clean" helps.
-
- * unix/unix_net.c: below.
- * unix/unix_main.c: below.
- * unix/matha.s: below.
- * unix/linux_qgl.c: below.
- * unix/linux_glimp.c: see also linux_joystick.c.
- * server/sv_client.c: below.
- * renderer/tr_surface.c: below.
- * renderer/qgl.h: below.
- * qcommon/qcommon.h: below.
- * qcommon/files.c: below.
- * qcommon/common.c: below.
- * q3_ui/ui_demo2.c: below.
- * mac/mac_net.c: below.
- * mac/mac_glimp2.c: below.
- * game/surfaceflags.h: below.
- * game/bg_lib.c: checked against id00516/cvs-1.17a diff.
- * bspc/bspc.c: TH_AASToTetrahedrons call removed since id000516.
- Note: our final compare of id000516 against cvs-1.17a, making sure
- that all these differences are in bk001119 (initial Q3TA port).
- If id branched the Q3TA base off before id000516 we might be screwed.
- Note: I do not diff against bk000520, which had some minor changes
- against id000516 (check VectorArrayNormalize, OTConfiguration), which
- seem consistent with me taking a pre-id000516 source snapshot for that
- working branch.
-
-2000-11-30 Bernd Kreimeier <bk at lokigames.com>
-
- * TEST: compiled using the symbolic link ui/ -> q3_ui/.
- Had to undo one CVS change, regarding
- code/cgame/cg_syscalls.asm
- code/game/g_syscalls.asm
- code/q3_ui/ui_syscalls.asm
- These files are neither generated by Win32 cgame.bat
- nor cgame.sh (etc.), thus seemingly maintained by hand.
- cvs tag pr1-17-loki001130b
- should be used if somebody needs this 1.17 snapshot
- (which, remember, is post-release, with additional fixes).
- Later:
- cvs tag pr1-17-loki001130c
- includes the full ChangeLog (duh).
-
- * CVS: up until cvs-1.17-001130, code/ui/ contained the
- Q3 code for the UI QVM/DLL. In Q3TA, this code has been
- moved to code/q3_ui/, while at the same time the new
- (scripting driven) UI code for Q3TA was maintained in
- code/ui/. To preserve the history of code/ui/, it has been
- renamed to q3/ui/ in the CVSROOT.
- Note: this will BREAK all cvs-1.17 and before checkouts.
- To compile earlier versions, move or link q3_ui/ to ui/.
- The code has been tagged
- cvs tag pr1-17-loki001130
- after the change.
- DONE: remove code/*/vm/*.asm from CVSROOT
- Note: this includes code/*/*.asm files (from *_syscalls.c).
- These were originally tracked in CVS, but if we need
- comparison of q3asm output or QVM files we can rely
- on the Win32 and Linux SDK now. These files have been
- physically removed from CVS now, followed by
- cvs tag pr1-17-loki001130a
-
-2000-11-30 Bernd Kreimeier <bk at lokigames.com> *** MISSIONPACK ***
-
- * RC2: new ZIP file (another 360M for convenience).
-
- * SOS: new CVS module, Quake3_sos. This will be used to track
- the unchanged SOS checkouts from id. As their repository
- is read-only, and there is no estimate on when changes might
- be backpropagated there, I will track their changes in a
- separate module, and update our local Quake3 module
- accordingly. This is effectively "tracking 3rd party"
- w/o import and half-automated, forced mergers - in other
- words, we now branch starting with our post-1.17 changes,
- for the benefit of moving at all.
- Baseline is a slightly changed PR-1.17 id000516 source dump
- (essentially ui/ moved to q3_ui for continuity, and CR/LF etc.).
- cvs import Quake3_sos id000516 pr1-17-win32
- cvs import Quake3_sos sos001119 pr1-26-win32
- cvs import Quake3_sos sos001120 pr1-26-win32-001120
- cvs import Quake3_sos sos001121 pr1-26-win32-001121
- cvs import Quake3_sos sos001122 pr1-26-win32-001122
- cvs import Quake3_sos sos001122-demo pr1-26-win32-demo
- This is about the 1.26w Team Arena Win32 demo release, give or
- take a couple of lines. Has Q3_VERSION "Q3 Team Arena Demo 1.27b".
- cvs import Quake3_sos sos001123 pr1-26-win32-001123
- cvs import Quake3_sos sos001126 pr1-26-win32-001126
- Now track id versions (see code/game/q_shared.h:Q3_VERSION)
- cvs import Quake3_sos sos001128 pr1-27c-win32-001128
- With 1.27d they switched from Demo to full version (RC1).
- cvs import Quake3_sos sos001129 pr1-27d-win32-001129
- cvs import Quake3_sos sos001130a pr1-27d-win32-001130a
- Now switched to 1.27e. This import is done from the SOS
- working directory.
- cvs import Quake3_sos sos001130b pr1-27e-win32-001130b
- Note: SoS created rwx attributes which are luckily fixed
- automagically during import. It is also seemingly incapable
- to compare files, and leave files that have not changed the
- hell alone. I can't do cvs update due to the $..$ tags in
- the original files (which CVS can't be told to ignore),
- so I have to do import (creating a load of vendor tagged
- branches), but at least cvsweb and cvs get the revisions
- right.
-
- * code-sos/unix/Makefile: added linux_joystick
- * code-sos/unix/linux_local.h: match mac/ and win32/, for prototypes.
-
- * code-sos/unix/linux_joystick.c: new file, code from linux_glimp.c
- Note: decided to separate this, as (a) we might edit/extend
- a lot, (b), it's not in the id tree, (c) it's not GL, (d)
- there might be even more oddball devices. Anything that
- cuts down on diffs.
-
- * code-sos/unix/linux_glimp.c (Q_stristr): const return (cvs1.17).
- Also (XLateKey): added more keyboard mappings (ASCII on
- upper row digits) (cvs1.17). Added in the minimal joystick
- hooks (cvars, function calls). Fixed joystick cvar naming
- to match win32 (kept joystick_threshold).
- TODO: joystick stubs for dedicated?
-
- * CVS: I have to move up to 1.27d (data, Win32 networking).
- With exception of linux_glimp.c (mostly joystick code),
- all cvs1.17 changes should now be in the work snapshot
- based on the first sos001119 we got from id. There are
- also some additional changes in there already, thus I'll
- move the (buggy) 1.26 snapshot into CVS before adding even
- more differences.
-
-
-2000-11-29 Bernd Kreimeier <bk at lokigames.com> *** MISSIONPACK ***
-
- * RC1: TeamArena_Q3A_RC1.zip. Source has moved from
- Q3VERSION "Q3 Team Arena Demo 1.27c" to "Q3 1.27d" now.
-
- * code-sos/qcommon/common.c: added Com_InitPushEvent(). Also
- increased MAX_PUSHED_EVENTS to 256.
- Note: this is another case of buffer memory not zero'ed.
- Com_EventLoop, fixed evTime to evType in debug print.
-
- * TEST: baseq3/
- +set sv_pure 0 +set vm_game 0 +set in_mouse 0 +set developer 2
- TODO: Team Arena in menu leads to RE_Shutdown(1) and locks
- TODO: can't play game
- TODO: shaders can't load *.tga, *.jpg files are there
- TODO: DO_CC linking for DLL's, DO_SHLIB_CC only for export?
- TODO: ERROR: Bad player movement angle
- TODO: Warning: cvar "..." given initial values: "..." and "..."
- TODO: TA demo ERROR: CL_ParseServerMessage: Illegible server message
- TODO: WARNING: Com_PushEvent overflow
-
- * code-sos/qcommon/files.c: add NULL filter for our Sys_ListFiles calls.
- * unix/unix_shared.c (Sys_ListFiles): signature has changed,
- additional Sys_ListFiles argument now.
-
- * code-sos/unix/unix_net.c (Sys_GetPacket): see below (readcount=0).
- * code-sos/unix/unix_main.c: see below (Mike's and my changes to DLL
- loading, my event buffer clear fixes).
- * code-sos/unix/linux_qgl.c (QGL_Init): see below (__FX__ guards).
- TODO: abstract WGL/GLX and end unfortunate QGL duplication.
- TODO: spice up QGL with Linux H2 full version.
- * code-sos/q3_ui/ui_demo2.c: fix on demo names - no Q_strupr(demoname).
- Note: in CVS this fix is in ui/ui_demo2.c. CVS is screwed by
- id choosing the old name for new directory...
- TODO: manual intervention on "ui goes q3_ui" in CVSROOT?
- * renderer/qgl.h: see below (__FX__ guards).
- * qcommon/files.c: migrated in the 1.17cvs changes against the
- id000516 code dump, i.e. the (not marked - boo hiss) mkv changes.
- Note: all the above is based on a diff of the last id code dump
- pre-1.17 against our CVS, with those fixes now migrated into the
- sos1.26 snapshot.
- TODO: move in joystick code.
- TODO: replace XAutoRepeatOn/Off with filter (focus).
- TODO: DGA 2.0 and such.
-
- * code-sos/game/q_shared.c: valid compare for NULL strings
- * code-sos/unix/unix_main.c: QRTLD, and now using RTLD_NOW.
- Note: it is a bad idea to load game DLL's that are missing symbols.
-
- * code-sos/ui/ui_main.c: see below.
- * code-sos/game/g_main.c: see below.
- * code-sos/q3_ui/ui_main.c: see below.
- * code-sos/cgame/cg_main.c: made cvarTable and cvarTableSize static. This resolved
- a segfault related to traversing the UI table during Init.
- Note: there is a segfault related to this variable being out of bounds.
- Different struct size in global variables possible aliasing between the
- DLL's.
-
- * code-sos/unix/unix_main.c (Sys_Error): assert(0), no exit in debug.
- * code-sos/game/q_shared.c: now aborts on NULL destination. Also DPrintf's
- on bogus excess copies.
- TODO: make all those string functions safe, at least assert.
- * code-sos/server/sv_init.c: comment in SV_Init
- // init the botlib here because we need the pre-compiler in the UI
- Called in qcommon/common.c:Com_Init, were CL_Init is called afterwards...
- * code-sos/server/sv_bot.c: the botlib_import is filled here.
- * code-sos/unix/unix_main.c (Sys_GetBotLibAPI): RTLD_NOW. Which is for naught,
- as this code is not used and has never been used. assert(0)
-
- * code-sos/botlib/be_interface.c: botimport supposed to be set here.
- * code-sos/botlib/l_memory.c: segfault with q3_ui/ DLL.
- #1 0x80e23ec in GetMemory (size=35) at ..//botlib/l_memory.c:331
- 331 ptr = botimport.GetMemory(size + sizeof(unsigned long int));
- as botimport is completely NULL'ed.
-
- * code-sos/q3_ui/q3_ui.sh: created from ui/ui.sh 1.17
-
- * code-sos/q3_ui/q3_ui.q3asm: unfubared (CR/LF, / path).
-
- * code-sos/unix/Makefile: added q3_ui/ make targets (basically
- ui/ targets from CVS 1.17 Makefile for starters).
-
- * code-sos/q3_ui/: this is the old UI code, which does not use
- ../ui/menus.txt (see ui/ui_main.c). In other words,
- the code in ui/ now has to be compiled or qvm'ed
- for missionpack/, but to create the necessary DLL or
- QVM modules for baseq3/ we need to use q3_ui/.
-
-
-2000-11-27 Bernd Kreimeier <bk at lokigames.com> *** MISSIONPACK ***
-
- * code-sos/game/bg_lib.c: ld problem with a custom "tan(..)"
- TODO: loooking forward to SIGFPE on this code base.
-
- * code-sos/ui/ui_util.c: this file is empty.
-
- * code-sos/ui/ui.sh: new files:
- ui_shared.c
- ui_util.c
- Replaced by the /ui/*.menu files:
- q3lcc: can't find `../ui_cdkey.c'
- q3lcc: can't find `../ui_ingame.c'
- etc.
-
- * code-sos/cgame/cgame.q3asm: added cg_newdraw entry.
- Also added ui_shared entry.
- * cgame/cgame.sh: added cg_newdraw.c entry.
- Also added ../ui/ui_shared.c entry.
-
- * code-sos/cgame/cg_newdraw.c: renamed (was cg_newDraw.c mixed case).
- Note: the infidels have taken over.
-
- * cgame/cgame.sh: added -DMISSIONPACK.
- Note: w/o, q3lcc complains
- ../cg_event.c:204: undeclared identifier `cg_singlePlayerActive'
- ../cg_event.c:204: left operand of . has incompatible type `int'
- which indicates that this source does not compile w/o MISSIONPACK
- anymore. The baseq3/pak4.pk3 file in the Q3TA snapshot archives
- are dated
- 284464 11-10-00 14:02 vm/cgame.qvm
- 463940 11-14-00 14:47 vm/qagame.qvm
- 271596 11-14-00 14:48 vm/ui.qvm
- the code dump is from 11-19.
- Note: Make does not abort on q3lcc complains
-
- * code-sos/game/game.sh: also added ai_vcmd.c entry.
-
- * code-sos/ui/ui.q3asm: fubared (below). In addition, this is
- the only one to have a
- -o "/tmp/quake3/missionpack/vm/ui"
- line in it. Given that the other 2 QVM modules are
- also dependend on -DMISSIONPACK, this seems a real mess.
- For now using the same path as the other 3.
- * code-sos/cgame/cgame.q3asm: below.
- * code-sos/game/game.q3asm: fubared. Fixed CR/LF and \ in paths
- again (read by q3asm called by game.sh called by make).
- * unix/Makefile: updated fpor DLL/QVM.
- Note: also shell scripts to use q3lcc not lcc.
-
-
-2000-11-27 Bernd Kreimeier <bk at lokigames.com>
-
- * code/unix/Makefile: now expects a run/ directory
- relative (between this, the Loki standards, and the
- utility code in the same repository, it's ever so
- slightly less dorky).
- TODO: fix broken copyfiles target etc.pp.
-
- * code/game/bg_lib.c: turns out the changes I
- undid 001120 were affecting original Zoid
- Linux port related defines, which break VM
- compile. Mike fixed those (which I unfixed
- when referring to the latest id code that does
- not contain these patches). However, they
- duplicate ANSI libc symbols, so the guards might
- be wrong. The symbols are missing when compiling
- for VM, so I now use the existing lcc -DQ3_VM
- flag:
- //#if !defined ( _MSC_VER ) && ! defined ( __linux__ )
- #if defined ( Q3_VM )
- This will break DLL compile on non-ANSI platforms,
- which will have to be added to the conditional then.
-
- * code/ui/ui.sh: below.
- * code/game/game.sh: below.
- * code/cgame/cgame.sh: Linux SDK installs q3lcc to
- avoid collisions with regular lcc pre-installs. The
- scripts fail with "lcc not found", but do not abort
- the Makefile.
- Note: now that VM code gets actually built, there
- are errors:
- g_main:648 ERROR: symbol vsprintf undefined
- bg_pmove:1221 ERROR: symbol abs undefined
- q_math:4309 ERROR: symbol fabs undefined
- q_shared:2801 ERROR: symbol tolower undefined
- q_shared:2862 ERROR: symbol toupper undefined
- ai_dmq3:208 ERROR: symbol atoi undefined
- ai_cmd:4951 ERROR: symbol sscanf undefined
-
-
-2000-11-20 Bernd Kreimeier <bk at lokigames.com>
-
- * TEST: test compile of pr-1.17+cvs fixes segfaults due
- to new baseq3/pak4.pk3
- Note: to self ... 1.17 is not compatible with new files.
- Checking into CVS next.
-
- * code/: changes applied by us that are not in id's code base
- affect q_shared.c (NULL in Q_stricmp), files.c (FIXME fs_cdpath,
- Sys_ConcatenateFileList, ui_demo2.c (demo no tolower on linux).
- In unix/ linux_glimp.c (joystick code), qgl.h, linux_qgl.c (__FX__),
- unix_main.c (dlopen bug and event buffers), unix_net.c (readcount),
- matha.s (assembly warning).
-
- * code/server/sv_client.c (SV_WriteDownloadToClient):
- No effective change on FS_SV_FOpenFileRead call, they reworked
- autodownload some more seemingly.
-
- * code/renderer/tr_surface.c: VectorArrayNormalize
-
- * code/qcommon/qcommon.h: see below.
- * code/qcommon/files.c: Com_ReadConfigs removed.
- * code/qcommon/common.c: removed Com_ReadConfigs,
- textual replacement of body in Com_Init.
-
- * code/mac/mac_net.c: not applied (undone by id)
- OTConfiguration *config <> OTConfigurationRef config
-
- * code/mac/mac_glimp2.c: r_colorbits->integer > 16
- * code/game/surfaceflags.h (CONTENTS_BOTCLIP): added.
-
- * code/game/q_shared.h: not applied (undone by id)
- #if defined(ppc) || defined(__ppc) || defined(__ppc__)
- #define idppc 1
- #else
- #define idppc 0
- #endif
-
- * code/game/q_math.c: added another CPP line to guard
- BoxOnPlaneSide, removed WIN32 guard.
- TODO: this could be broken code guarded in all current
- compiles...
-
- * code/game/bg_lib.c: left Q#_VM guard for typedef cmp_t
- Added !defined( __linux__ ) for tolower and atoi.
- Note: the changes above relate to the very last code update
- from id prior to the 6 month blackout, which were not in
- CVS when Michael made his updates. Needed to establish the
- baseline for the new patch. Source dump 1.17.00520, against
- SOS 1.26w-001119 version.
-
-2000-11-20 Bernd Kreimeier <bk at lokigames.com> *** MISSIONPACK ***
-
- * TEST: running against the data up to TeamArena_Q3A_001109.zip
- Hunk_Clear: reset the hunk ok
- Program received signal SIGBUS, Bus error.
- "q3dm2", killBots==qtrue
- #0 CM_ClearMap () at ..//qcommon/cm_load.c:644
- #1 0x80884a7 in SV_Map_f () at ..//server/sv_ccmds.c:159
- #2 0x8072579 in Cmd_ExecuteString (text=0xbffff4b0 "spmap q3dm2") at ..//qcommon/cmd.c:591
- #3 0x8071dfe in Cbuf_Execute () at ..//qcommon/cmd.c:190
- #4 0x80763f7 in Com_Frame () at ..//qcommon/common.c:2547
- #5 0x8130d6b in main (argc=13, argv=0xbffff984) at ..//unix/unix_main.c:953
- #6 0x40100cb3 in __libc_start_main (main=0x8130bc4 <main>
- Not reproducible (screen stayed black).
-
- * TEST: +set developer 1, same for Win32 and Linux:
- Can't find gfx/misc/flare.tga
- Can't find gfx/misc/sun.tga
- Can't find gfx/misc/console02.tga
- Can't find vm/ui.map
- Can't find textures/sfx/logo512.tga
- Can't find gfx/colors/black.tga
- Can't find models/mapobjects/banner/banner5_2.md3
- Can't find models/mapobjects/banner/banner5_1.md3
- Can't find textures/sfx/firegorre2.tga
- Can't find textures/sfx/bolts.tga
- Can't find menu/art/unknownmap.tga
-
- * Q3TA: after nearly 6 months, a code update from id. SOS access
- even. Got it to compile, link and start, but its currently broken
- (menu doesn't render in full, can't get into game etc.). Need
- a baseline 1.17 to diff against. Last code dump was May 16, with
- bspc code updated May 19. Checking working directory of bk000520
- against CVS next (Mike's fixes never made it into id's codebase
- or a post 1.17 release, neither did my fixes as released in the
- point release version 1.17).
-
-2000-11-19 Bernd Kreimeier <bk at lokigames.com> *** MISSIONPACK ***
-
- * TEST: Win32 install as tested with 1.26w. quake3.x86 (Q3A game)
- Warning: cvar "r_uifullscreen" given initial values: "1" and "0"
- Warning: cvar "r_inGameVideo" given initial values: "1" and "0"
- ^3WARNING: sound/feedback/hit.wav is a 8 bit wav file
- (on windows, sound/weapons/weapon_hover.wav is missing...)
- Menu only partially displayed in TA and baseq3 play, menu itself
- seems to work. Freetype?
- WARNING: Com_PushEvent overflow
-
- * code-sos/game/game.sh: not in SOS, moved in from CVS snapshot.
-
- * code-sos/qcommon/common.c: conditional DEDICATED to get rid off
- CL_ShutdownCGame/CL_ShutdownUI/CIN_CloseAllVideos.
- Same for UI_usesUniqueCDKey: dedicated server does not
- write CD key file.
- TODO: check whether there is an unneeded "read CD key"
- for dedicated server.
-
- * code-sos/null/null_client.c (CL_ShutdownAll): added dummy.
-
- * code-sos/unix/Makefile: server/sv_net_chan.o for dedicated server.
-
- * code-sos/null/null_snddma.c: fixed S_RegisterSound signature.
-
- * code-sos/client/snd_mix.c: snd_p, snd_linear_count, snd_out
- can't be static, as used by unix/snd_mixa.s.
-
- * code-sos/unix/Makefile: added to the executable target:
- renderer/tr_font.c
- client/cl_net_chan.c
- server/sv_net_chan.c
- Also added a lot of jc*.c files to build, to fix unresolved
- symbol errors.
- TODO: is there unused jpeg-6/jd*.o code linked in now?
-
- * code-sos/ft2/smooth.c: includes ftgrays.c, ftsmooth.c
-
- * code-sos/ft2/truetype.c: ttdriver.c, ttpload.c, ttgload.c, ttobjs.c.
- Also (see ftoption.h) TT_CONFIG_OPTION_BYTECODE_INTERPRETER ttinterp.c
-
- * code-sos/ft2/sfnt.c: includes ttload.c, ttcmap.c, sfobjs.c,
- sfdriver.c. lso (see ftoption.h)
- TT_CONFIG_OPTION_EMBEDDED_BITMAPS ttsbit.c
- TT_CONFIG_OPTION_POSTSCRIPT_NAMES ttpost.c
-
- * code-sos/ft2/ftbase.c: includes ftcalc.c, ftobjs.c, ftstream.c,
- ftlist.c, ftoutln.c, ftextend.c, ftnames.c.
-
- * code-sos/ft2/autohint.c: includes ahangles.c, ahglyph.c, ahglobal.c,
- ahhint.c, ahmodule.c.
-
- * code-sos/unix/Makefile: added ft2/ to client objects, took out
- ftraster.c/ftrend1.c (see below), added -DFT_FLAT_COMPILE.
- * ft2/ftsmooth.c: -DFT_FLAT_COMPILE required.
- * ft2/raster1.c: -DFT_FLAT_COMPILE required.
- Note: this includes ftraster.c/ftrend1.c.
-
- * code-sos/qcommon/vm_x86.c: _ftol is missing, ftolPtr only defined
- for Win32, but used in generic code. Workaround for now.
- TODO: find good Linux ftol, or use old solution.
-
- * SoS checkout. chown -R a+w * recode ibmpc:lat1 */*.h */*.c
-
-2000-06-30 Michael Vance <briraeos at lokigames.com>
-
- * misc: Spoke with Leonardo about qvm mess.
-
- * ui/ui.sh: Created to build much like the ui.bat script.
-
- * ui/ui.q3asm: Use linux style paths.
-
- * game/game.sh: Created to build much like the game.bat script.
-
- * game/game.q3asm: Use linux style paths.
-
- * cgame/cgame.sh: Created to build much like the cgame.bat script.
-
- * cgame/cgame.q3asm: Use linux systel paths.
-
- * unix/Makefile: Use the new .sh scripts to build the QVM files.
-
- * lcc/etc/linux.c: Build .asm files instead of .s files.
-
- * misc: QVMs now load properly, with minor glitches that should
- hopefully be solvable. The new build scripts conflict with the
- .asm files already in CVS, as the generated byte code is slightly
- different in some cases.
-
-2000-06-29 Michael Vance <briareos at lokigames.com>
-
- * lcc/makefile: Tweaked to automatically include the system
- compiler's header location. Added an install directory.
-
- * lcc/custom.mk: Added a build directory.
-
- * lcc/etc/linux.c: Numerous small tweaks to make compiling the VM
- code a much simpler task.
-
- * q3asm/Makefile: Created.
-
- * q3asm/q3asm.c: Fixed uninitialized variable in
- HashString(). Fixed off by one in argument parsing.
-
- * misc: Had Brian remove the Xmd.h include from glx.h so that we can
- build Quake3 on XFree86 4.0 systems.
-
- * wine: Attempted to build with lcc.exe and q3asm.exe using wine,
- also did not work. This is in contrast to MikeP's .qvms, which
- seem to work.
-
-2000-06-28 Michael Vance <briareos at lokigames.com>
-
- * common/files.c: Fixed Mods menu behaviour.
-
- * unix/linux_qgl.c: Guarded references to fxMesa.
-
- * renderer/qgl.h: Guarded references to fxMesa.
-
- * ui/ui_demo2.c: Don't convert filename to uppercase.
-
-2000-05-07 Bernd Kreimeier <bk at lokigames.com>
-
- * common/cmdlib.c: windowism, not guarded. Added WIN32 around "ATOM a".
-
- * q3map/Makefile: Linux Makefile.
-
- * q3map/Makefile.irix: "makefile" in original code, Irix-only Makefile.
- Just fixed some redundant TAB that GNU make despises about as much as I
- despise GNU Make, and changed to a relative path.
-
-2000-05-01 Bernd Kreimeier <bk at lokigames.com>
-
- * q3radiant/: updated with Q3Radiant198b3-src.zip.
- Tagged (globally) as q3radiant-198b3.
- Kept the old files
- 3DFXCamWnd.h
- 3DFXCamWnd.cpp
- MainFrm2.cpp
- New files
- Shaders.h
- misc/ (contributed special TGA resources, don't relly belong)
- Removed:
- pName
- Changed filenames to previous case:
- UNNAMED.MAP -> unnamed.map
- RES/BMP0002.BMP -> RES/bmp00002.bmp
- Changed:
- changelog.txt -> ChangeLog
-
-2000-04-28 Bernd Kreimeier <bk at lokigames.com>
-
- * CVS: bk000425 modified sources. This replaces the unix/ directory
- which is not yet in id's SourceSafe. Two check-ins, due to minor
- changes in an attempt to nail the Voodoo3 related crashes (driver
- problems, not a Q3 issue). Undid some of the QFL changes for PI
- and the log bug fix - put back in (TODO). Also includes:
- * Quake3/code/botlib/be_aas_sample.c: single file update from Robert.
-
- * CVS: id000423 code dumps (two of them). Applying Loki patches.
- Tagged for the final version (all patches).
-
- * CVS: id000422 code dump. This did not include the 1.16n fixes
- used for Linux, and was the first dump for the 1.17 security fix
- release.
- Note: forgot to check in the ft2/ headers themselves, but they
- are not used in the current codebase anyway. Are added in next
- dump. Also there is use of CVS/CVS-like $Keyword$ patterns in
- some files, and between their revisions and ours we fuck this up.
- Also, id ZIP files create write protected sources, have to do
- chmod -R a+w Quake3/ to work and overwrite files.
-
- * CVS: bk000315 modified source. This version was the 1.16n release.
- Note: the changes applied here are not in the subsequent code dumps
- of id. If you want to compile the Linux version as released you
- have to use bk-tagged versions until the patches are merged in by
- Robert Duffy.
-
- * CVS: id000314 engine code dump, same procedure as below, tag.
- Note: this version added vm/ sudirectories with assembly files
- for cgame, game, ui. CVS tag id000314.
-
- * CVS: id000304 engine code dump. Now there is a problem, as CVS
- was used in the Mac sources. Do
- find . -name 'CVS' -exec rm -r {} \;
- before cvs update, then tagged:
- cvs -d /loki/cvsroot/ tag id000304 Quake3/
-
- * CVS: checked in a source snapshot of the id00303 engine code
- and the id0003029 tools code. The tool sources are not fully in
- sync, and we have only partial source from earlier engine revisions.
- The engine source marks where Loki took over from Dave Kirsch.
- This snapshot (with all temporary and bogus files) is imported
- and tagged using:
- cvs -d /loki/cvsroot import Quake3 id000303 initial
-
- Modules:
- code: the Q3 engine code, including a jpeg-6/ copy
- common: code shared by tools
- libs: code shared by tools, inlcuding a jpeg6/ copy
- q3asm: VM bytecode assembly
- q3data: misc. Q3 data conversions
- q3map: BSP builder
- q3radiant: Win32 editor, as is
- lcc: C compiler for q3asm
-
- The sources have not been cleaned up, and binary files have not been
- removed. The Q3Radiant code base might exhibit mixed case asmbiguities
- in the future, and future source dumps might come from SourceForge
- instead.
-
-2000-04-25 Bernd Kreimeier <bk at lokigames.com>
-
- * q3code.id000425/unix/Makefile: relative path, relocatable.
- Note: first code merge with id, finally :-).
-
-2000-04-24 Bernd Kreimeier <bk at lokigames.com>
-
- * q3code.bk000422/unix/matha.s: in C(BoxOnPlaneSide)
- the following line triggers assembler warning:
- "missing prefix `*' in absolute indirect address, maybe misassembled!"
- jmp Ljmptab(,%eax,4)
-
-
- * q3code.bk000422/unix/Makefile (MOUNT_DIR): rember to change.
- TODO: fix this bloody Makefile to be relocatable, damnit.
-
- * q3code.bk000422/cgame/cg_event.c: applied JCash fix again
- (see EV_EVENT_BITS below). Send e-mail to verify.
-
- * q3code.bk000422/renderer/tr_image.c: "../jpeg-6/jpeglib.h" again.
-
- * q3code.bk000422/: created from the id dump of today, lacking
- all but one of my changes (sigh). Swapped unix/ competely, takes
- care of 90%. Submitted all changes again to Robert...
-
-2000-04-19 Bernd Kreimeier <bk at lokigames.com>
-
- * q3code.bk000315/unix/linux_glimp.c (GLimp_EndFrame):
- QGL_EnableLogging( r_logFile->value ) doesn't work?
-
- * q3code.bk000315/unix/linux_qgl.c: GLimp_LogNewFrame() is
- obsolete. QGL_EnableLogging was out of sync with Win32 and
- did not support the new framecounter decrement logic.
-
-2000-04-03 Bernd Kreimeier <bk at lokigames.com>
-
- * q3code.bk000315/server/sv_snapshot.c: svs.nextSnapshotEntities
- is a signed integer unconditionally incremented, which gets
- negative and causes a segfaulting indexing an array. Added reset
- to counter. Might fail if snapshot numbers are supposed to
- monotonically increase.
-
-2000-04-02 Bernd Kreimeier <bk at lokigames.com>
-
- * q3code.bk000315/client/cl_parse.c (CL_ParseServerMessage):
- assert(0) on Illegible message (remember to +set in_mouse 0).
- TODO: have to add a dump message function, it's unreadable.
-
- * botlib/be_ai_goal.c (InitLevelItemHeap): loop counter -2
- left -2 with uninitialized next, and -1 disconnected. Removed
- redundant memset. There is an item alloc leak I suspect, as
- max_levelitems 1024 merely delayed the overflow error.
-
-2000-04-01 Bernd Kreimeier <bk at lokigames.com>
-
- * botlib/be_ai_goal.c (InitLevelItemHeap): still segfaults.
- Not memsetting the entire item heap. As items are cleared
- on return, that leaves only memory corruption?
- Later: upped max_levelitems from 256 to 1024
- Later: client dies on connect:
- Error: CL_ParseServerMessage: Illegible server message 255
-
-
-2000-03-31 Bernd Kreimeier <bk at lokigames.com>
-
- * botlib/be_ai_goal.c: initializing global vars.
- Segfault in AllocLevelItem ()
- at /home/bk/Games/Quake3/q3code/botlib/be_ai_goal.c:364
- I suspect that the initial freelevelitems setting is at
- the end of the list and eventually exposed.
-
- * cgame/cg_event.c: according to Johmn Cash:
- itemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0
- Quote: "This causes itemNum to be invalid about half the time,
- preventing any client side effect tied to the item from occurring."
-
-2000-03-06 Bernd Kreimeier <bk at lokigames.com>
-
- * qcommon/common.c: set pushEvent buffer and indices
- to zero in Com_Init().
-
- * q3code/qcommon/qcommon.h: made SE_NONE (and for paranoia
- also NA_BOT) explicitely set to zero.
-
-2000-02-27 Bernd Kreimeier <bk at lokigames.com>
-
- * unix/Makefile: added dmalloc in an attempt to get on
- the Z_Free bug. Futile. Despite stripping dmalloc debug
- token down to essentials, I get a (seemingly bogus or
- unrelated):
- debug-malloc library: dumping program, fatal error
- Error: possibly bad .c filename pointer (err 24)
-
-
-2000-02-26 Bernd Kreimeier <bk at lokigames.com>
-
- * qcommon/common.c: various debug builts to isolate the
- Z_Free bug. It reproducibly happens on some machines
- with SE_PACKET, but the packets themselves look
- thoroughly corrupted.
-
-2000-02-21 Bernd Kreimeier <bk at lokigames.com>
-
- * qcommon/common.c (Com_EventLoop): possible problem
- here, pointer does not get cleared.
-
- * unix/linux_glimp.c (InitSig): no signal handler.
- * common/common.c: dump in Com_Error for debug.
-
-2000-02-17 Bernd Kreimeier <bk at lokigames.com>
-
- * q3code: new dump from Zoid. Repeat tr_image.c fix.
-
- * unix/Makefile: added client/snd_adpcm.c (linkage errors).
- Later: added entire JPDIR and rules, for tr_image.c.
- Later: had to fix fules for game/ai_*.c files.
- Later: removed ui/ui_quit.o (n/a)
- Later: took out -mpentiumpro -march=pentiumpro
-
- * renderer/tr_image.c: windowism in #include path (see below).
- #include "..\jpeg-6\jpeglib.h"
-
-1999-12-27 Bernd Kreimeier <bk at lokigames.com>
-
- * Alpha: tried a dedicated server compile. Segfaults in
- ../qcommon/files.c:1682, a paksort function doing pointer
- fiddling.
-
- * Makefile.alpha: created.
- Note: want to take the SDL/Setup autoconf ASAP.
-
- * unix/unix_main.c: fixed __axp__ to __alpha__, guarded
- _FPU_SETCW.
-
- * qcommon/vm_alpha.c: dummy, created.
- * qcommon/vm_null.c: dummy, created.
-
-1999-12-04 Bernd Kreimeier <bk at lokigames.com>
-
- * renderer/tr_image.c: windowism in #include path.
- #include "..\jpeg-6\jpeglib.h"
-
- * Revision 1.11: from Zoid by e-mail.
- Note: threw away my playground copy, starting with the
- ZIP file. Zoid's using CVS now, but we can't remote
- access it. Thus did the
- "find . -name 'CVS' -exec rm -rf {} \;"
- and then track it as 3rd party source by
-
-
- * ChangeLog: created. Now starting to track Q3A source.
-
---------- q3code log ---------------------------------------------
diff --git a/engine/Makefile b/engine/Makefile
deleted file mode 100644
index aa14f58..0000000
--- a/engine/Makefile
+++ /dev/null
@@ -1,2288 +0,0 @@
-#
-# ioq3 Makefile
-#
-# GNU Make required
-#
-
-COMPILE_PLATFORM=$(shell uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]')
-
-COMPILE_ARCH=$(shell uname -m | sed -e s/i.86/i386/)
-
-ifeq ($(COMPILE_PLATFORM),sunos)
- # Solaris uname and GNU uname differ
- COMPILE_ARCH=$(shell uname -p | sed -e s/i.86/i386/)
-endif
-ifeq ($(COMPILE_PLATFORM),darwin)
- # Apple does some things a little differently...
- COMPILE_ARCH=$(shell uname -p | sed -e s/i.86/i386/)
-endif
-
-ifeq ($(COMPILE_PLATFORM),mingw32)
- ifeq ($(COMPILE_ARCH),i386)
- COMPILE_ARCH=x86
- endif
-endif
-
-ifndef BUILD_STANDALONE
- BUILD_STANDALONE =
-endif
-ifndef BUILD_CLIENT
- BUILD_CLIENT =
-endif
-ifndef BUILD_CLIENT_SMP
- BUILD_CLIENT_SMP =
-endif
-ifndef BUILD_SERVER
- BUILD_SERVER =
-endif
-ifndef BUILD_GAME_SO
- BUILD_GAME_SO =
-endif
-ifndef BUILD_GAME_QVM
- BUILD_GAME_QVM =
-endif
-ifndef BUILD_MISSIONPACK
- BUILD_MISSIONPACK=
-endif
-
-ifneq ($(PLATFORM),darwin)
- BUILD_CLIENT_SMP = 0
-endif
-
-#############################################################################
-#
-# If you require a different configuration from the defaults below, create a
-# new file named "Makefile.local" in the same directory as this file and define
-# your parameters there. This allows you to change configuration without
-# causing problems with keeping up to date with the repository.
-#
-#############################################################################
--include Makefile.local
-
-ifndef PLATFORM
-PLATFORM=$(COMPILE_PLATFORM)
-endif
-export PLATFORM
-
-ifeq ($(COMPILE_ARCH),powerpc)
- COMPILE_ARCH=ppc
-endif
-ifeq ($(COMPILE_ARCH),powerpc64)
- COMPILE_ARCH=ppc64
-endif
-
-ifndef ARCH
-ARCH=$(COMPILE_ARCH)
-endif
-export ARCH
-
-ifneq ($(PLATFORM),$(COMPILE_PLATFORM))
- CROSS_COMPILING=1
-else
- CROSS_COMPILING=0
-
- ifneq ($(ARCH),$(COMPILE_ARCH))
- CROSS_COMPILING=1
- endif
-endif
-export CROSS_COMPILING
-
-ifndef COPYDIR
-COPYDIR="/usr/local/games/quake3"
-endif
-
-ifndef COPYBINDIR
-COPYBINDIR=$(COPYDIR)
-endif
-
-ifndef MOUNT_DIR
-MOUNT_DIR=code
-endif
-
-ifndef BUILD_DIR
-BUILD_DIR=build
-endif
-
-ifndef GENERATE_DEPENDENCIES
-GENERATE_DEPENDENCIES=1
-endif
-
-ifndef USE_OPENAL
-USE_OPENAL=1
-endif
-
-ifndef USE_OPENAL_DLOPEN
-USE_OPENAL_DLOPEN=1
-endif
-
-ifndef USE_CURL
-USE_CURL=1
-endif
-
-ifndef USE_CURL_DLOPEN
- ifeq ($(PLATFORM),mingw32)
- USE_CURL_DLOPEN=0
- else
- USE_CURL_DLOPEN=1
- endif
-endif
-
-ifndef USE_CODEC_VORBIS
-USE_CODEC_VORBIS=0
-endif
-
-ifndef USE_MUMBLE
-USE_MUMBLE=1
-endif
-
-ifndef USE_VOIP
-USE_VOIP=1
-endif
-
-ifndef USE_INTERNAL_SPEEX
-USE_INTERNAL_SPEEX=1
-endif
-
-ifndef USE_INTERNAL_ZLIB
-USE_INTERNAL_ZLIB=1
-endif
-
-ifndef USE_LOCAL_HEADERS
-USE_LOCAL_HEADERS=1
-endif
-
-ifndef DEBUG_CFLAGS
-DEBUG_CFLAGS=-g -O0
-endif
-
-#############################################################################
-
-BD=$(BUILD_DIR)/debug-$(PLATFORM)-$(ARCH)
-BR=$(BUILD_DIR)/release-$(PLATFORM)-$(ARCH)
-CDIR=$(MOUNT_DIR)/client
-SDIR=$(MOUNT_DIR)/server
-RDIR=$(MOUNT_DIR)/renderer
-CMDIR=$(MOUNT_DIR)/qcommon
-SDLDIR=$(MOUNT_DIR)/sdl
-ASMDIR=$(MOUNT_DIR)/asm
-SYSDIR=$(MOUNT_DIR)/sys
-GDIR=$(MOUNT_DIR)/game
-CGDIR=$(MOUNT_DIR)/cgame
-BLIBDIR=$(MOUNT_DIR)/botlib
-NDIR=$(MOUNT_DIR)/null
-UIDIR=$(MOUNT_DIR)/ui
-Q3UIDIR=$(MOUNT_DIR)/q3_ui
-JPDIR=$(MOUNT_DIR)/jpeg-6b
-SPEEXDIR=$(MOUNT_DIR)/libspeex
-ZDIR=$(MOUNT_DIR)/zlib
-Q3ASMDIR=$(MOUNT_DIR)/tools/asm
-LBURGDIR=$(MOUNT_DIR)/tools/lcc/lburg
-Q3CPPDIR=$(MOUNT_DIR)/tools/lcc/cpp
-Q3LCCETCDIR=$(MOUNT_DIR)/tools/lcc/etc
-Q3LCCSRCDIR=$(MOUNT_DIR)/tools/lcc/src
-LOKISETUPDIR=misc/setup
-NSISDIR=misc/nsis
-SDLHDIR=$(MOUNT_DIR)/SDL12
-LIBSDIR=$(MOUNT_DIR)/libs
-TEMPDIR=/tmp
-
-bin_path=$(shell which $(1) 2> /dev/null)
-
-# We won't need this if we only build the server
-ifneq ($(BUILD_CLIENT),0)
- # set PKG_CONFIG_PATH to influence this, e.g.
- # PKG_CONFIG_PATH=/opt/cross/i386-mingw32msvc/lib/pkgconfig
- ifneq ($(call bin_path, pkg-config),)
- CURL_CFLAGS=$(shell pkg-config --silence-errors --cflags libcurl)
- CURL_LIBS=$(shell pkg-config --silence-errors --libs libcurl)
- OPENAL_CFLAGS=$(shell pkg-config --silence-errors --cflags openal)
- OPENAL_LIBS=$(shell pkg-config --silence-errors --libs openal)
- SDL_CFLAGS=$(shell pkg-config --silence-errors --cflags sdl|sed 's/-Dmain=SDL_main//')
- SDL_LIBS=$(shell pkg-config --silence-errors --libs sdl)
- endif
- # Use sdl-config if all else fails
- ifeq ($(SDL_CFLAGS),)
- ifneq ($(call bin_path, sdl-config),)
- SDL_CFLAGS=$(shell sdl-config --cflags)
- SDL_LIBS=$(shell sdl-config --libs)
- endif
- endif
-endif
-
-# version info
-VERSION=1.36
-
-USE_SVN=
-ifeq ($(wildcard .svn),.svn)
- SVN_REV=$(shell LANG=C svnversion .)
- ifneq ($(SVN_REV),)
- VERSION:=$(VERSION)_SVN$(SVN_REV)
- USE_SVN=1
- endif
-else
-ifeq ($(wildcard .git/svn/.metadata),.git/svn/.metadata)
- SVN_REV=$(shell LANG=C git svn info | awk '$$1 == "Revision:" {print $$2; exit 0}')
- ifneq ($(SVN_REV),)
- VERSION:=$(VERSION)_SVN$(SVN_REV)
- endif
-endif
-endif
-
-
-#############################################################################
-# SETUP AND BUILD -- LINUX
-#############################################################################
-
-## Defaults
-LIB=lib
-
-INSTALL=install
-MKDIR=mkdir
-
-ifeq ($(PLATFORM),linux)
-
- ifeq ($(ARCH),alpha)
- ARCH=axp
- else
- ifeq ($(ARCH),x86_64)
- LIB=lib64
- else
- ifeq ($(ARCH),ppc64)
- LIB=lib64
- else
- ifeq ($(ARCH),s390x)
- LIB=lib64
- endif
- endif
- endif
- endif
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -pipe -DUSE_ICON
- CLIENT_CFLAGS = $(SDL_CFLAGS)
- SERVER_CFLAGS =
-
- ifeq ($(USE_OPENAL),1)
- CLIENT_CFLAGS += -DUSE_OPENAL
- ifeq ($(USE_OPENAL_DLOPEN),1)
- CLIENT_CFLAGS += -DUSE_OPENAL_DLOPEN
- endif
- endif
-
- ifeq ($(USE_CURL),1)
- CLIENT_CFLAGS += -DUSE_CURL
- ifeq ($(USE_CURL_DLOPEN),1)
- CLIENT_CFLAGS += -DUSE_CURL_DLOPEN
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- CLIENT_CFLAGS += -DUSE_CODEC_VORBIS
- endif
-
- OPTIMIZEVM = -O3 -funroll-loops -fomit-frame-pointer
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
-
- ifeq ($(ARCH),x86_64)
- OPTIMIZEVM = -O3 -fomit-frame-pointer -funroll-loops \
- -falign-loops=2 -falign-jumps=2 -falign-functions=2 \
- -fstrength-reduce
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
- HAVE_VM_COMPILED = true
- else
- ifeq ($(ARCH),i386)
- OPTIMIZEVM = -O3 -march=i586 -fomit-frame-pointer \
- -funroll-loops -falign-loops=2 -falign-jumps=2 \
- -falign-functions=2 -fstrength-reduce
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
- HAVE_VM_COMPILED=true
- else
- ifeq ($(ARCH),ppc)
- BASE_CFLAGS += -maltivec
- HAVE_VM_COMPILED=true
- endif
- ifeq ($(ARCH),ppc64)
- BASE_CFLAGS += -maltivec
- HAVE_VM_COMPILED=true
- endif
- ifeq ($(ARCH),sparc)
- OPTIMIZE += -mtune=ultrasparc3 -mv8plus
- OPTIMIZEVM += -mtune=ultrasparc3 -mv8plus
- HAVE_VM_COMPILED=true
- endif
- endif
- endif
-
- ifneq ($(HAVE_VM_COMPILED),true)
- BASE_CFLAGS += -DNO_VM_COMPILED
- endif
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC -fvisibility=hidden
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- THREAD_LIBS=-lpthread
- LIBS=-ldl -lm
-
- CLIENT_LIBS=$(SDL_LIBS) -lGL
-
- ifeq ($(USE_OPENAL),1)
- ifneq ($(USE_OPENAL_DLOPEN),1)
- CLIENT_LIBS += -lopenal
- endif
- endif
-
- ifeq ($(USE_CURL),1)
- ifneq ($(USE_CURL_DLOPEN),1)
- CLIENT_LIBS += -lcurl
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- CLIENT_LIBS += -lvorbisfile -lvorbis -logg
- endif
-
- ifeq ($(USE_MUMBLE),1)
- CLIENT_LIBS += -lrt
- endif
-
- ifeq ($(USE_LOCAL_HEADERS),1)
- CLIENT_CFLAGS += -I$(SDLHDIR)/include
- endif
-
- ifeq ($(ARCH),i386)
- # linux32 make ...
- BASE_CFLAGS += -m32
- else
- ifeq ($(ARCH),ppc64)
- BASE_CFLAGS += -m64
- endif
- endif
-else # ifeq Linux
-
-#############################################################################
-# SETUP AND BUILD -- MAC OS X
-#############################################################################
-
-ifeq ($(PLATFORM),darwin)
- HAVE_VM_COMPILED=true
- CLIENT_LIBS=
- OPTIMIZEVM=
-
- BASE_CFLAGS = -Wall -Wimplicit -Wstrict-prototypes
- CLIENT_CFLAGS =
- SERVER_CFLAGS =
-
- ifeq ($(ARCH),ppc)
- BASE_CFLAGS += -faltivec
- OPTIMIZEVM += -O3
- endif
- ifeq ($(ARCH),ppc64)
- BASE_CFLAGS += -faltivec
- endif
- ifeq ($(ARCH),i386)
- OPTIMIZEVM += -march=prescott -mfpmath=sse
- # x86 vm will crash without -mstackrealign since MMX instructions will be
- # used no matter what and they corrupt the frame pointer in VM calls
- BASE_CFLAGS += -mstackrealign
- endif
-
- BASE_CFLAGS += -fno-strict-aliasing -DMACOS_X -fno-common -pipe
-
- ifeq ($(USE_OPENAL),1)
- BASE_CFLAGS += -DUSE_OPENAL
- ifneq ($(USE_OPENAL_DLOPEN),1)
- CLIENT_LIBS += -framework OpenAL
- else
- CLIENT_CFLAGS += -DUSE_OPENAL_DLOPEN
- endif
- endif
-
- ifeq ($(USE_CURL),1)
- CLIENT_CFLAGS += -DUSE_CURL
- ifneq ($(USE_CURL_DLOPEN),1)
- CLIENT_LIBS += -lcurl
- else
- CLIENT_CFLAGS += -DUSE_CURL_DLOPEN
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- CLIENT_CFLAGS += -DUSE_CODEC_VORBIS
- CLIENT_LIBS += -lvorbisfile -lvorbis -logg
- endif
-
- BASE_CFLAGS += -D_THREAD_SAFE=1
-
- ifeq ($(USE_LOCAL_HEADERS),1)
- BASE_CFLAGS += -I$(SDLHDIR)/include
- endif
-
- # We copy sdlmain before ranlib'ing it so that subversion doesn't think
- # the file has been modified by each build.
- LIBSDLMAIN=$(B)/libSDLmain.a
- LIBSDLMAINSRC=$(LIBSDIR)/macosx/libSDLmain.a
- CLIENT_LIBS += -framework Cocoa -framework IOKit -framework OpenGL \
- $(LIBSDIR)/macosx/libSDL-1.2.0.dylib
-
- OPTIMIZEVM += -falign-loops=16
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
-
- ifneq ($(HAVE_VM_COMPILED),true)
- BASE_CFLAGS += -DNO_VM_COMPILED
- endif
-
- SHLIBEXT=dylib
- SHLIBCFLAGS=-fPIC -fno-common
- SHLIBLDFLAGS=-dynamiclib $(LDFLAGS)
-
- NOTSHLIBCFLAGS=-mdynamic-no-pic
-
- TOOLS_CFLAGS += -DMACOS_X
-
-else # ifeq darwin
-
-
-#############################################################################
-# SETUP AND BUILD -- MINGW32
-#############################################################################
-
-ifeq ($(PLATFORM),mingw32)
-
- # Some MinGW installations define CC to cc, but don't actually provide cc,
- # so explicitly use gcc instead (which is the only option anyway)
- ifeq ($(call bin_path, $(CC)),)
- CC=gcc
- endif
-
- ifndef WINDRES
- WINDRES=windres
- endif
-
- ARCH=x86
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -DUSE_ICON
- CLIENT_CFLAGS =
- SERVER_CFLAGS =
-
- # In the absence of wspiapi.h, require Windows XP or later
- ifeq ($(shell test -e $(CMDIR)/wspiapi.h; echo $$?),1)
- BASE_CFLAGS += -DWINVER=0x501
- endif
-
- ifeq ($(USE_OPENAL),1)
- CLIENT_CFLAGS += -DUSE_OPENAL
- CLIENT_CFLAGS += $(OPENAL_CFLAGS)
- ifeq ($(USE_OPENAL_DLOPEN),1)
- CLIENT_CFLAGS += -DUSE_OPENAL_DLOPEN
- else
- CLIENT_LDFLAGS += $(OPENAL_LDFLAGS)
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- CLIENT_CFLAGS += -DUSE_CODEC_VORBIS
- endif
-
- OPTIMIZEVM = -O3 -march=i586 -fno-omit-frame-pointer \
- -falign-loops=2 -funroll-loops -falign-jumps=2 -falign-functions=2 \
- -fstrength-reduce
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
-
- HAVE_VM_COMPILED = true
-
- SHLIBEXT=dll
- SHLIBCFLAGS=
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- BINEXT=.exe
-
- LIBS= -lws2_32 -lwinmm
- CLIENT_LDFLAGS = -mwindows
- CLIENT_LIBS = -lgdi32 -lole32 -lopengl32
-
- ifeq ($(USE_CURL),1)
- CLIENT_CFLAGS += -DUSE_CURL
- CLIENT_CFLAGS += $(CURL_CFLAGS)
- ifneq ($(USE_CURL_DLOPEN),1)
- ifeq ($(USE_LOCAL_HEADERS),1)
- CLIENT_CFLAGS += -DCURL_STATICLIB
- CLIENT_LIBS += $(LIBSDIR)/win32/libcurl.a
- else
- CLIENT_LIBS += $(CURL_LIBS)
- endif
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- CLIENT_LIBS += -lvorbisfile -lvorbis -logg
- endif
-
- ifeq ($(ARCH),x86)
- # build 32bit
- BASE_CFLAGS += -m32
- endif
-
- # libmingw32 must be linked before libSDLmain
- CLIENT_LIBS += -lmingw32
- ifeq ($(USE_LOCAL_HEADERS),1)
- CLIENT_CFLAGS += -I$(SDLHDIR)/include
- CLIENT_LIBS += $(LIBSDIR)/win32/libSDLmain.a \
- $(LIBSDIR)/win32/libSDL.dll.a
- else
- CLIENT_CFLAGS += $(SDL_CFLAGS)
- CLIENT_LIBS += $(SDL_LIBS)
- endif
-
- BUILD_CLIENT_SMP = 0
-
-else # ifeq mingw32
-
-#############################################################################
-# SETUP AND BUILD -- FREEBSD
-#############################################################################
-
-ifeq ($(PLATFORM),freebsd)
-
- ifneq (,$(findstring alpha,$(shell uname -m)))
- ARCH=axp
- else #default to i386
- ARCH=i386
- endif #alpha test
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -DUSE_ICON
- CLIENT_CFLAGS = $(SDL_CFLAGS)
- SERVER_CFLAGS =
-
- ifeq ($(USE_OPENAL),1)
- CLIENT_CFLAGS += -DUSE_OPENAL
- ifeq ($(USE_OPENAL_DLOPEN),1)
- CLIENT_CFLAGS += -DUSE_OPENAL_DLOPEN
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- CLIENT_CFLAGS += -DUSE_CODEC_VORBIS
- endif
-
- OPTIMIZEVM = -O3 -funroll-loops -fomit-frame-pointer
-
- ifeq ($(ARCH),axp)
- BASE_CFLAGS += -DNO_VM_COMPILED
- OPTIMIZEVM += -fexpensive-optimizations
- else
- ifeq ($(ARCH),i386)
- OPTIMIZEVM += -mtune=pentiumpro \
- -march=pentium -pipe -falign-loops=2 -falign-jumps=2 \
- -falign-functions=2 -funroll-loops -fstrength-reduce
- HAVE_VM_COMPILED=true
- else
- BASE_CFLAGS += -DNO_VM_COMPILED
- endif
- endif
-
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- THREAD_LIBS=-lpthread
- # don't need -ldl (FreeBSD)
- LIBS=-lm
-
- CLIENT_LIBS =
-
- CLIENT_LIBS += $(SDL_LIBS) -lGL
-
- ifeq ($(USE_OPENAL),1)
- ifneq ($(USE_OPENAL_DLOPEN),1)
- CLIENT_LIBS += $(THREAD_LIBS) -lopenal
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- CLIENT_LIBS += -lvorbisfile -lvorbis -logg
- endif
-
-else # ifeq freebsd
-
-#############################################################################
-# SETUP AND BUILD -- OPENBSD
-#############################################################################
-
-ifeq ($(PLATFORM),openbsd)
-
- #default to i386, no tests done on anything else
- ARCH=i386
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -DUSE_ICON
- CLIENT_CFLAGS = $(SDL_CFLAGS)
- SERVER_CFLAGS =
-
- ifeq ($(USE_OPENAL),1)
- CLIENT_CFLAGS += -DUSE_OPENAL
- ifeq ($(USE_OPENAL_DLOPEN),1)
- CLIENT_CFLAGS += -DUSE_OPENAL_DLOPEN
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- CLIENT_CFLAGS += -DUSE_CODEC_VORBIS
- endif
-
- ifeq ($(USE_CURL),1)
- CLIENT_CFLAGS += -DUSE_CURL $(CURL_CFLAGS)
- USE_CURL_DLOPEN=0
- endif
-
- BASE_CFLAGS += -DNO_VM_COMPILED
- HAVE_VM_COMPILED=false
-
- SHLIBEXT=so
- SHLIBNAME=.$(SHLIBEXT)
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- THREAD_LIBS=-pthread
- LIBS=-lm
-
- CLIENT_LIBS =
-
- CLIENT_LIBS += $(SDL_LIBS) -lGL
-
- ifeq ($(USE_OPENAL),1)
- ifneq ($(USE_OPENAL_DLOPEN),1)
- CLIENT_LIBS += $(THREAD_LIBS) -lossaudio -lopenal
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- CLIENT_LIBS += -lvorbisfile -lvorbis -logg
- endif
-
- ifeq ($(USE_CURL),1)
- ifneq ($(USE_CURL_DLOPEN),1)
- CLIENT_LIBS += -lcurl
- endif
- endif
-
-else # ifeq openbsd
-
-#############################################################################
-# SETUP AND BUILD -- NETBSD
-#############################################################################
-
-ifeq ($(PLATFORM),netbsd)
-
- ifeq ($(shell uname -m),i386)
- ARCH=i386
- endif
-
- LIBS=-lm
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared $(LDFLAGS)
- THREAD_LIBS=-lpthread
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes
- CLIENT_CFLAGS =
- SERVER_CFLAGS =
-
- ifneq ($(ARCH),i386)
- BASE_CFLAGS += -DNO_VM_COMPILED
- endif
-
- BUILD_CLIENT = 0
- BUILD_GAME_QVM = 0
-
-else # ifeq netbsd
-
-#############################################################################
-# SETUP AND BUILD -- IRIX
-#############################################################################
-
-ifeq ($(PLATFORM),irix64)
-
- ARCH=mips #default to MIPS
-
- CC = c99
- MKDIR = mkdir -p
-
- BASE_CFLAGS=-Dstricmp=strcasecmp -Xcpluscomm -woff 1185 \
- -I. -I$(ROOT)/usr/include -DNO_VM_COMPILED
- CLIENT_CFLAGS = $(SDL_CFLAGS)
- OPTIMIZE = -O3
-
- SHLIBEXT=so
- SHLIBCFLAGS=
- SHLIBLDFLAGS=-shared
-
- LIBS=-ldl -lm -lgen
- # FIXME: The X libraries probably aren't necessary?
- CLIENT_LIBS=-L/usr/X11/$(LIB) $(SDL_LIBS) -lGL \
- -lX11 -lXext -lm
-
-else # ifeq IRIX
-
-#############################################################################
-# SETUP AND BUILD -- SunOS
-#############################################################################
-
-ifeq ($(PLATFORM),sunos)
-
- CC=gcc
- INSTALL=ginstall
- MKDIR=gmkdir
- COPYDIR="/usr/local/share/games/quake3"
-
- ifneq (,$(findstring i86pc,$(shell uname -m)))
- ARCH=i386
- else #default to sparc
- ARCH=sparc
- endif
-
- ifneq ($(ARCH),i386)
- ifneq ($(ARCH),sparc)
- $(error arch $(ARCH) is currently not supported)
- endif
- endif
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -pipe -DUSE_ICON
- CLIENT_CFLAGS = $(SDL_CFLAGS)
- SERVER_CFLAGS =
-
- OPTIMIZEVM = -O3 -funroll-loops
-
- ifeq ($(ARCH),sparc)
- OPTIMIZEVM += -O3 \
- -fstrength-reduce -falign-functions=2 \
- -mtune=ultrasparc3 -mv8plus -mno-faster-structs
- HAVE_VM_COMPILED=true
- else
- ifeq ($(ARCH),i386)
- OPTIMIZEVM += -march=i586 -fomit-frame-pointer \
- -falign-loops=2 -falign-jumps=2 \
- -falign-functions=2 -fstrength-reduce
- HAVE_VM_COMPILED=true
- BASE_CFLAGS += -m32
- CLIENT_CFLAGS += -I/usr/X11/include/NVIDIA
- CLIENT_LDFLAGS += -L/usr/X11/lib/NVIDIA -R/usr/X11/lib/NVIDIA
- endif
- endif
-
- OPTIMIZE = $(OPTIMIZEVM) -ffast-math
-
- ifneq ($(HAVE_VM_COMPILED),true)
- BASE_CFLAGS += -DNO_VM_COMPILED
- endif
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- THREAD_LIBS=-lpthread
- LIBS=-lsocket -lnsl -ldl -lm
-
- BOTCFLAGS=-O0
-
- CLIENT_LIBS +=$(SDL_LIBS) -lGL -lX11 -lXext -liconv -lm
-
-else # ifeq sunos
-
-#############################################################################
-# SETUP AND BUILD -- GENERIC
-#############################################################################
- BASE_CFLAGS=-DNO_VM_COMPILED
- OPTIMIZE = -O3
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared
-
-endif #Linux
-endif #darwin
-endif #mingw32
-endif #FreeBSD
-endif #OpenBSD
-endif #NetBSD
-endif #IRIX
-endif #SunOS
-
-TARGETS =
-
-ifndef FULLBINEXT
- FULLBINEXT=.$(ARCH)$(BINEXT)
-endif
-
-ifndef SHLIBNAME
- SHLIBNAME=$(ARCH).$(SHLIBEXT)
-endif
-
-ifneq ($(BUILD_SERVER),0)
- TARGETS += $(B)/ioq3ded$(FULLBINEXT)
-endif
-
-ifneq ($(BUILD_CLIENT),0)
- TARGETS += $(B)/ioquake3$(FULLBINEXT)
- ifneq ($(BUILD_CLIENT_SMP),0)
- TARGETS += $(B)/ioquake3-smp$(FULLBINEXT)
- endif
-endif
-
-ifneq ($(BUILD_GAME_SO),0)
- TARGETS += \
- $(B)/baseq3/cgame$(SHLIBNAME) \
- $(B)/baseq3/qagame$(SHLIBNAME) \
- $(B)/baseq3/ui$(SHLIBNAME)
- ifneq ($(BUILD_MISSIONPACK),0)
- TARGETS += \
- $(B)/missionpack/cgame$(SHLIBNAME) \
- $(B)/missionpack/qagame$(SHLIBNAME) \
- $(B)/missionpack/ui$(SHLIBNAME)
- endif
-endif
-
-ifneq ($(BUILD_GAME_QVM),0)
- ifneq ($(CROSS_COMPILING),1)
- TARGETS += \
- $(B)/baseq3/vm/cgame.qvm \
- $(B)/baseq3/vm/qagame.qvm \
- $(B)/baseq3/vm/ui.qvm
- ifneq ($(BUILD_MISSIONPACK),0)
- TARGETS += \
- $(B)/missionpack/vm/qagame.qvm \
- $(B)/missionpack/vm/cgame.qvm \
- $(B)/missionpack/vm/ui.qvm
- endif
- endif
-endif
-
-ifeq ($(USE_MUMBLE),1)
- CLIENT_CFLAGS += -DUSE_MUMBLE
-endif
-
-ifeq ($(USE_VOIP),1)
- CLIENT_CFLAGS += -DUSE_VOIP
- SERVER_CFLAGS += -DUSE_VOIP
- ifeq ($(USE_INTERNAL_SPEEX),1)
- CLIENT_CFLAGS += -DFLOATING_POINT -DUSE_ALLOCA -I$(SPEEXDIR)/include
- else
- CLIENT_LIBS += -lspeex -lspeexdsp
- endif
-endif
-
-ifeq ($(USE_INTERNAL_ZLIB),1)
- BASE_CFLAGS += -DNO_GZIP
- ifneq ($(USE_LOCAL_HEADERS),1)
- BASE_CFLAGS += -I$(ZDIR)
- endif
-else
- LIBS += -lz
-endif
-
-ifdef DEFAULT_BASEDIR
- BASE_CFLAGS += -DDEFAULT_BASEDIR=\\\"$(DEFAULT_BASEDIR)\\\"
-endif
-
-ifeq ($(USE_LOCAL_HEADERS),1)
- BASE_CFLAGS += -DUSE_LOCAL_HEADERS
-endif
-
-ifeq ($(BUILD_STANDALONE),1)
- BASE_CFLAGS += -DSTANDALONE
-endif
-
-ifeq ($(GENERATE_DEPENDENCIES),1)
- DEPEND_CFLAGS = -MMD
-else
- DEPEND_CFLAGS =
-endif
-
-ifeq ($(NO_STRIP),1)
- STRIP_FLAG =
-else
- STRIP_FLAG = -s
-endif
-
-BASE_CFLAGS += -DPRODUCT_VERSION=\\\"$(VERSION)\\\"
-
-ifeq ($(V),1)
-echo_cmd=@:
-Q=
-else
-echo_cmd=@echo
-Q=@
-endif
-
-define DO_CC
-$(echo_cmd) "CC $<"
-$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) $(CLIENT_CFLAGS) $(OPTIMIZE) -o $@ -c $<
-endef
-
-define DO_SMP_CC
-$(echo_cmd) "SMP_CC $<"
-$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) $(CLIENT_CFLAGS) $(OPTIMIZE) -DSMP -o $@ -c $<
-endef
-
-define DO_BOT_CC
-$(echo_cmd) "BOT_CC $<"
-$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) $(BOTCFLAGS) $(OPTIMIZE) -DBOTLIB -o $@ -c $<
-endef
-
-ifeq ($(GENERATE_DEPENDENCIES),1)
- DO_QVM_DEP=cat $(@:%.o=%.d) | sed -e 's/\.o/\.asm/g' >> $(@:%.o=%.d)
-endif
-
-define DO_SHLIB_CC
-$(echo_cmd) "SHLIB_CC $<"
-$(Q)$(CC) $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_GAME_CC
-$(echo_cmd) "GAME_CC $<"
-$(Q)$(CC) -DQAGAME $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_CGAME_CC
-$(echo_cmd) "CGAME_CC $<"
-$(Q)$(CC) -DCGAME $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_UI_CC
-$(echo_cmd) "UI_CC $<"
-$(Q)$(CC) -DUI $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_SHLIB_CC_MISSIONPACK
-$(echo_cmd) "SHLIB_CC_MISSIONPACK $<"
-$(Q)$(CC) -DMISSIONPACK $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_GAME_CC_MISSIONPACK
-$(echo_cmd) "GAME_CC_MISSIONPACK $<"
-$(Q)$(CC) -DMISSIONPACK -DQAGAME $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_CGAME_CC_MISSIONPACK
-$(echo_cmd) "CGAME_CC_MISSIONPACK $<"
-$(Q)$(CC) -DMISSIONPACK -DCGAME $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_UI_CC_MISSIONPACK
-$(echo_cmd) "UI_CC_MISSIONPACK $<"
-$(Q)$(CC) -DMISSIONPACK -DUI $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_AS
-$(echo_cmd) "AS $<"
-$(Q)$(CC) $(CFLAGS) $(OPTIMIZE) -x assembler-with-cpp -o $@ -c $<
-endef
-
-define DO_DED_CC
-$(echo_cmd) "DED_CC $<"
-$(Q)$(CC) $(NOTSHLIBCFLAGS) -DDEDICATED $(CFLAGS) $(SERVER_CFLAGS) $(OPTIMIZE) -o $@ -c $<
-endef
-
-define DO_WINDRES
-$(echo_cmd) "WINDRES $<"
-$(Q)$(WINDRES) -i $< -o $@
-endef
-
-
-#############################################################################
-# MAIN TARGETS
-#############################################################################
-
-default: release
-all: debug release
-
-debug:
- @$(MAKE) targets B=$(BD) CFLAGS="$(CFLAGS) $(BASE_CFLAGS) $(DEPEND_CFLAGS)" \
- OPTIMIZE="$(DEBUG_CFLAGS)" OPTIMIZEVM="$(DEBUG_CFLAGS)" \
- CLIENT_CFLAGS="$(CLIENT_CFLAGS)" SERVER_CFLAGS="$(SERVER_CFLAGS)" V=$(V)
-
-release:
- @$(MAKE) targets B=$(BR) CFLAGS="$(CFLAGS) $(BASE_CFLAGS) $(DEPEND_CFLAGS)" \
- OPTIMIZE="-DNDEBUG $(OPTIMIZE)" OPTIMIZEVM="-DNDEBUG $(OPTIMIZEVM)" \
- CLIENT_CFLAGS="$(CLIENT_CFLAGS)" SERVER_CFLAGS="$(SERVER_CFLAGS)" V=$(V)
-
-# Create the build directories, check libraries and print out
-# an informational message, then start building
-targets: makedirs
- @echo ""
- @echo "Building ioquake3 in $(B):"
- @echo " PLATFORM: $(PLATFORM)"
- @echo " ARCH: $(ARCH)"
- @echo " VERSION: $(VERSION)"
- @echo " COMPILE_PLATFORM: $(COMPILE_PLATFORM)"
- @echo " COMPILE_ARCH: $(COMPILE_ARCH)"
- @echo " CC: $(CC)"
- @echo ""
- @echo " CFLAGS:"
- - at for i in $(CFLAGS); \
- do \
- echo " $$i"; \
- done
- - at for i in $(OPTIMIZE); \
- do \
- echo " $$i"; \
- done
- @echo ""
- @echo " CLIENT_CFLAGS:"
- - at for i in $(CLIENT_CFLAGS); \
- do \
- echo " $$i"; \
- done
- @echo ""
- @echo " SERVER_CFLAGS:"
- - at for i in $(SERVER_CFLAGS); \
- do \
- echo " $$i"; \
- done
- @echo ""
- @echo " LDFLAGS:"
- - at for i in $(LDFLAGS); \
- do \
- echo " $$i"; \
- done
- @echo ""
- @echo " LIBS:"
- - at for i in $(LIBS); \
- do \
- echo " $$i"; \
- done
- @echo ""
- @echo " CLIENT_LIBS:"
- - at for i in $(CLIENT_LIBS); \
- do \
- echo " $$i"; \
- done
- @echo ""
- @echo " Output:"
- - at for i in $(TARGETS); \
- do \
- echo " $$i"; \
- done
- @echo ""
-ifneq ($(TARGETS),)
- @$(MAKE) $(TARGETS) V=$(V)
-endif
-
-makedirs:
- @if [ ! -d $(BUILD_DIR) ];then $(MKDIR) $(BUILD_DIR);fi
- @if [ ! -d $(B) ];then $(MKDIR) $(B);fi
- @if [ ! -d $(B)/client ];then $(MKDIR) $(B)/client;fi
- @if [ ! -d $(B)/clientsmp ];then $(MKDIR) $(B)/clientsmp;fi
- @if [ ! -d $(B)/ded ];then $(MKDIR) $(B)/ded;fi
- @if [ ! -d $(B)/baseq3 ];then $(MKDIR) $(B)/baseq3;fi
- @if [ ! -d $(B)/baseq3/cgame ];then $(MKDIR) $(B)/baseq3/cgame;fi
- @if [ ! -d $(B)/baseq3/game ];then $(MKDIR) $(B)/baseq3/game;fi
- @if [ ! -d $(B)/baseq3/ui ];then $(MKDIR) $(B)/baseq3/ui;fi
- @if [ ! -d $(B)/baseq3/qcommon ];then $(MKDIR) $(B)/baseq3/qcommon;fi
- @if [ ! -d $(B)/baseq3/vm ];then $(MKDIR) $(B)/baseq3/vm;fi
- @if [ ! -d $(B)/missionpack ];then $(MKDIR) $(B)/missionpack;fi
- @if [ ! -d $(B)/missionpack/cgame ];then $(MKDIR) $(B)/missionpack/cgame;fi
- @if [ ! -d $(B)/missionpack/game ];then $(MKDIR) $(B)/missionpack/game;fi
- @if [ ! -d $(B)/missionpack/ui ];then $(MKDIR) $(B)/missionpack/ui;fi
- @if [ ! -d $(B)/missionpack/qcommon ];then $(MKDIR) $(B)/missionpack/qcommon;fi
- @if [ ! -d $(B)/missionpack/vm ];then $(MKDIR) $(B)/missionpack/vm;fi
- @if [ ! -d $(B)/tools ];then $(MKDIR) $(B)/tools;fi
- @if [ ! -d $(B)/tools/asm ];then $(MKDIR) $(B)/tools/asm;fi
- @if [ ! -d $(B)/tools/etc ];then $(MKDIR) $(B)/tools/etc;fi
- @if [ ! -d $(B)/tools/rcc ];then $(MKDIR) $(B)/tools/rcc;fi
- @if [ ! -d $(B)/tools/cpp ];then $(MKDIR) $(B)/tools/cpp;fi
- @if [ ! -d $(B)/tools/lburg ];then $(MKDIR) $(B)/tools/lburg;fi
-
-#############################################################################
-# QVM BUILD TOOLS
-#############################################################################
-
-TOOLS_OPTIMIZE = -g -O2 -Wall -fno-strict-aliasing
-TOOLS_CFLAGS += $(TOOLS_OPTIMIZE) \
- -DTEMPDIR=\"$(TEMPDIR)\" -DSYSTEM=\"\" \
- -I$(Q3LCCSRCDIR) \
- -I$(LBURGDIR)
-TOOLS_LIBS =
-TOOLS_LDFLAGS =
-
-ifeq ($(GENERATE_DEPENDENCIES),1)
- TOOLS_CFLAGS += -MMD
-endif
-
-define DO_TOOLS_CC
-$(echo_cmd) "TOOLS_CC $<"
-$(Q)$(CC) $(TOOLS_CFLAGS) -o $@ -c $<
-endef
-
-define DO_TOOLS_CC_DAGCHECK
-$(echo_cmd) "TOOLS_CC_DAGCHECK $<"
-$(Q)$(CC) $(TOOLS_CFLAGS) -Wno-unused -o $@ -c $<
-endef
-
-LBURG = $(B)/tools/lburg/lburg$(BINEXT)
-DAGCHECK_C = $(B)/tools/rcc/dagcheck.c
-Q3RCC = $(B)/tools/q3rcc$(BINEXT)
-Q3CPP = $(B)/tools/q3cpp$(BINEXT)
-Q3LCC = $(B)/tools/q3lcc$(BINEXT)
-Q3ASM = $(B)/tools/q3asm$(BINEXT)
-
-LBURGOBJ= \
- $(B)/tools/lburg/lburg.o \
- $(B)/tools/lburg/gram.o
-
-$(B)/tools/lburg/%.o: $(LBURGDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(LBURG): $(LBURGOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
-
-Q3RCCOBJ = \
- $(B)/tools/rcc/alloc.o \
- $(B)/tools/rcc/bind.o \
- $(B)/tools/rcc/bytecode.o \
- $(B)/tools/rcc/dag.o \
- $(B)/tools/rcc/dagcheck.o \
- $(B)/tools/rcc/decl.o \
- $(B)/tools/rcc/enode.o \
- $(B)/tools/rcc/error.o \
- $(B)/tools/rcc/event.o \
- $(B)/tools/rcc/expr.o \
- $(B)/tools/rcc/gen.o \
- $(B)/tools/rcc/init.o \
- $(B)/tools/rcc/inits.o \
- $(B)/tools/rcc/input.o \
- $(B)/tools/rcc/lex.o \
- $(B)/tools/rcc/list.o \
- $(B)/tools/rcc/main.o \
- $(B)/tools/rcc/null.o \
- $(B)/tools/rcc/output.o \
- $(B)/tools/rcc/prof.o \
- $(B)/tools/rcc/profio.o \
- $(B)/tools/rcc/simp.o \
- $(B)/tools/rcc/stmt.o \
- $(B)/tools/rcc/string.o \
- $(B)/tools/rcc/sym.o \
- $(B)/tools/rcc/symbolic.o \
- $(B)/tools/rcc/trace.o \
- $(B)/tools/rcc/tree.o \
- $(B)/tools/rcc/types.o
-
-$(DAGCHECK_C): $(LBURG) $(Q3LCCSRCDIR)/dagcheck.md
- $(echo_cmd) "LBURG $(Q3LCCSRCDIR)/dagcheck.md"
- $(Q)$(LBURG) $(Q3LCCSRCDIR)/dagcheck.md $@
-
-$(B)/tools/rcc/dagcheck.o: $(DAGCHECK_C)
- $(DO_TOOLS_CC_DAGCHECK)
-
-$(B)/tools/rcc/%.o: $(Q3LCCSRCDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(Q3RCC): $(Q3RCCOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
-
-Q3CPPOBJ = \
- $(B)/tools/cpp/cpp.o \
- $(B)/tools/cpp/lex.o \
- $(B)/tools/cpp/nlist.o \
- $(B)/tools/cpp/tokens.o \
- $(B)/tools/cpp/macro.o \
- $(B)/tools/cpp/eval.o \
- $(B)/tools/cpp/include.o \
- $(B)/tools/cpp/hideset.o \
- $(B)/tools/cpp/getopt.o \
- $(B)/tools/cpp/unix.o
-
-$(B)/tools/cpp/%.o: $(Q3CPPDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(Q3CPP): $(Q3CPPOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
-
-Q3LCCOBJ = \
- $(B)/tools/etc/lcc.o \
- $(B)/tools/etc/bytecode.o
-
-$(B)/tools/etc/%.o: $(Q3LCCETCDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(Q3LCC): $(Q3LCCOBJ) $(Q3RCC) $(Q3CPP)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $(Q3LCCOBJ) $(TOOLS_LIBS)
-
-define DO_Q3LCC
-$(echo_cmd) "Q3LCC $<"
-$(Q)$(Q3LCC) -o $@ $<
-endef
-
-define DO_CGAME_Q3LCC
-$(echo_cmd) "CGAME_Q3LCC $<"
-$(Q)$(Q3LCC) -DCGAME -o $@ $<
-endef
-
-define DO_GAME_Q3LCC
-$(echo_cmd) "GAME_Q3LCC $<"
-$(Q)$(Q3LCC) -DQAGAME -o $@ $<
-endef
-
-define DO_UI_Q3LCC
-$(echo_cmd) "UI_Q3LCC $<"
-$(Q)$(Q3LCC) -DUI -o $@ $<
-endef
-
-define DO_Q3LCC_MISSIONPACK
-$(echo_cmd) "Q3LCC_MISSIONPACK $<"
-$(Q)$(Q3LCC) -DMISSIONPACK -o $@ $<
-endef
-
-define DO_CGAME_Q3LCC_MISSIONPACK
-$(echo_cmd) "CGAME_Q3LCC_MISSIONPACK $<"
-$(Q)$(Q3LCC) -DMISSIONPACK -DCGAME -o $@ $<
-endef
-
-define DO_GAME_Q3LCC_MISSIONPACK
-$(echo_cmd) "GAME_Q3LCC_MISSIONPACK $<"
-$(Q)$(Q3LCC) -DMISSIONPACK -DQAGAME -o $@ $<
-endef
-
-define DO_UI_Q3LCC_MISSIONPACK
-$(echo_cmd) "UI_Q3LCC_MISSIONPACK $<"
-$(Q)$(Q3LCC) -DMISSIONPACK -DUI -o $@ $<
-endef
-
-
-Q3ASMOBJ = \
- $(B)/tools/asm/q3asm.o \
- $(B)/tools/asm/cmdlib.o
-
-$(B)/tools/asm/%.o: $(Q3ASMDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(Q3ASM): $(Q3ASMOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
-
-
-#############################################################################
-# CLIENT/SERVER
-#############################################################################
-
-Q3OBJ = \
- $(B)/client/cl_cgame.o \
- $(B)/client/cl_cin.o \
- $(B)/client/cl_console.o \
- $(B)/client/cl_input.o \
- $(B)/client/cl_keys.o \
- $(B)/client/cl_main.o \
- $(B)/client/cl_net_chan.o \
- $(B)/client/cl_parse.o \
- $(B)/client/cl_scrn.o \
- $(B)/client/cl_ui.o \
- $(B)/client/cl_avi.o \
- \
- $(B)/client/cm_load.o \
- $(B)/client/cm_patch.o \
- $(B)/client/cm_polylib.o \
- $(B)/client/cm_test.o \
- $(B)/client/cm_trace.o \
- \
- $(B)/client/cmd.o \
- $(B)/client/common.o \
- $(B)/client/cvar.o \
- $(B)/client/files.o \
- $(B)/client/md4.o \
- $(B)/client/md5.o \
- $(B)/client/msg.o \
- $(B)/client/net_chan.o \
- $(B)/client/net_ip.o \
- $(B)/client/huffman.o \
- \
- $(B)/client/snd_adpcm.o \
- $(B)/client/snd_dma.o \
- $(B)/client/snd_mem.o \
- $(B)/client/snd_mix.o \
- $(B)/client/snd_wavelet.o \
- \
- $(B)/client/snd_main.o \
- $(B)/client/snd_codec.o \
- $(B)/client/snd_codec_wav.o \
- $(B)/client/snd_codec_ogg.o \
- \
- $(B)/client/qal.o \
- $(B)/client/snd_openal.o \
- \
- $(B)/client/cl_curl.o \
- \
- $(B)/client/sv_bot.o \
- $(B)/client/sv_ccmds.o \
- $(B)/client/sv_client.o \
- $(B)/client/sv_game.o \
- $(B)/client/sv_init.o \
- $(B)/client/sv_main.o \
- $(B)/client/sv_net_chan.o \
- $(B)/client/sv_snapshot.o \
- $(B)/client/sv_world.o \
- \
- $(B)/client/q_math.o \
- $(B)/client/q_shared.o \
- \
- $(B)/client/unzip.o \
- $(B)/client/ioapi.o \
- $(B)/client/puff.o \
- $(B)/client/vm.o \
- $(B)/client/vm_interpreted.o \
- \
- $(B)/client/be_aas_bspq3.o \
- $(B)/client/be_aas_cluster.o \
- $(B)/client/be_aas_debug.o \
- $(B)/client/be_aas_entity.o \
- $(B)/client/be_aas_file.o \
- $(B)/client/be_aas_main.o \
- $(B)/client/be_aas_move.o \
- $(B)/client/be_aas_optimize.o \
- $(B)/client/be_aas_reach.o \
- $(B)/client/be_aas_route.o \
- $(B)/client/be_aas_routealt.o \
- $(B)/client/be_aas_sample.o \
- $(B)/client/be_ai_char.o \
- $(B)/client/be_ai_chat.o \
- $(B)/client/be_ai_gen.o \
- $(B)/client/be_ai_goal.o \
- $(B)/client/be_ai_move.o \
- $(B)/client/be_ai_weap.o \
- $(B)/client/be_ai_weight.o \
- $(B)/client/be_ea.o \
- $(B)/client/be_interface.o \
- $(B)/client/l_crc.o \
- $(B)/client/l_libvar.o \
- $(B)/client/l_log.o \
- $(B)/client/l_memory.o \
- $(B)/client/l_precomp.o \
- $(B)/client/l_script.o \
- $(B)/client/l_struct.o \
- \
- $(B)/client/jcapimin.o \
- $(B)/client/jcapistd.o \
- $(B)/client/jccoefct.o \
- $(B)/client/jccolor.o \
- $(B)/client/jcdctmgr.o \
- $(B)/client/jchuff.o \
- $(B)/client/jcinit.o \
- $(B)/client/jcmainct.o \
- $(B)/client/jcmarker.o \
- $(B)/client/jcmaster.o \
- $(B)/client/jcomapi.o \
- $(B)/client/jcparam.o \
- $(B)/client/jcphuff.o \
- $(B)/client/jcprepct.o \
- $(B)/client/jcsample.o \
- $(B)/client/jdapimin.o \
- $(B)/client/jdapistd.o \
- $(B)/client/jdatasrc.o \
- $(B)/client/jdcoefct.o \
- $(B)/client/jdcolor.o \
- $(B)/client/jddctmgr.o \
- $(B)/client/jdhuff.o \
- $(B)/client/jdinput.o \
- $(B)/client/jdmainct.o \
- $(B)/client/jdmarker.o \
- $(B)/client/jdmaster.o \
- $(B)/client/jdpostct.o \
- $(B)/client/jdsample.o \
- $(B)/client/jdtrans.o \
- $(B)/client/jerror.o \
- $(B)/client/jfdctflt.o \
- $(B)/client/jidctflt.o \
- $(B)/client/jmemmgr.o \
- $(B)/client/jmemnobs.o \
- $(B)/client/jutils.o \
- \
- $(B)/client/tr_animation.o \
- $(B)/client/tr_backend.o \
- $(B)/client/tr_bsp.o \
- $(B)/client/tr_cmds.o \
- $(B)/client/tr_curve.o \
- $(B)/client/tr_flares.o \
- $(B)/client/tr_font.o \
- $(B)/client/tr_image.o \
- $(B)/client/tr_image_png.o \
- $(B)/client/tr_image_jpg.o \
- $(B)/client/tr_image_bmp.o \
- $(B)/client/tr_image_tga.o \
- $(B)/client/tr_image_pcx.o \
- $(B)/client/tr_init.o \
- $(B)/client/tr_light.o \
- $(B)/client/tr_main.o \
- $(B)/client/tr_marks.o \
- $(B)/client/tr_mesh.o \
- $(B)/client/tr_model.o \
- $(B)/client/tr_noise.o \
- $(B)/client/tr_scene.o \
- $(B)/client/tr_shade.o \
- $(B)/client/tr_shade_calc.o \
- $(B)/client/tr_shader.o \
- $(B)/client/tr_shadows.o \
- $(B)/client/tr_sky.o \
- $(B)/client/tr_surface.o \
- $(B)/client/tr_world.o \
- \
- $(B)/client/sdl_gamma.o \
- $(B)/client/sdl_input.o \
- $(B)/client/sdl_snd.o \
- \
- $(B)/client/con_passive.o \
- $(B)/client/con_log.o \
- $(B)/client/sys_main.o
-
-ifeq ($(ARCH),i386)
- Q3OBJ += \
- $(B)/client/snd_mixa.o \
- $(B)/client/matha.o \
- $(B)/client/ftola.o \
- $(B)/client/snapvectora.o
-endif
-ifeq ($(ARCH),x86)
- Q3OBJ += \
- $(B)/client/snd_mixa.o \
- $(B)/client/matha.o \
- $(B)/client/ftola.o \
- $(B)/client/snapvectora.o
-endif
-
-ifeq ($(USE_VOIP),1)
-ifeq ($(USE_INTERNAL_SPEEX),1)
-Q3OBJ += \
- $(B)/client/bits.o \
- $(B)/client/buffer.o \
- $(B)/client/cb_search.o \
- $(B)/client/exc_10_16_table.o \
- $(B)/client/exc_10_32_table.o \
- $(B)/client/exc_20_32_table.o \
- $(B)/client/exc_5_256_table.o \
- $(B)/client/exc_5_64_table.o \
- $(B)/client/exc_8_128_table.o \
- $(B)/client/fftwrap.o \
- $(B)/client/filterbank.o \
- $(B)/client/filters.o \
- $(B)/client/gain_table.o \
- $(B)/client/gain_table_lbr.o \
- $(B)/client/hexc_10_32_table.o \
- $(B)/client/hexc_table.o \
- $(B)/client/high_lsp_tables.o \
- $(B)/client/jitter.o \
- $(B)/client/kiss_fft.o \
- $(B)/client/kiss_fftr.o \
- $(B)/client/lpc.o \
- $(B)/client/lsp.o \
- $(B)/client/lsp_tables_nb.o \
- $(B)/client/ltp.o \
- $(B)/client/mdf.o \
- $(B)/client/modes.o \
- $(B)/client/modes_wb.o \
- $(B)/client/nb_celp.o \
- $(B)/client/preprocess.o \
- $(B)/client/quant_lsp.o \
- $(B)/client/resample.o \
- $(B)/client/sb_celp.o \
- $(B)/client/smallft.o \
- $(B)/client/speex.o \
- $(B)/client/speex_callbacks.o \
- $(B)/client/speex_header.o \
- $(B)/client/stereo.o \
- $(B)/client/vbr.o \
- $(B)/client/vq.o \
- $(B)/client/window.o
-endif
-endif
-
-ifeq ($(USE_INTERNAL_ZLIB),1)
-Q3OBJ += \
- $(B)/client/adler32.o \
- $(B)/client/crc32.o \
- $(B)/client/inffast.o \
- $(B)/client/inflate.o \
- $(B)/client/inftrees.o \
- $(B)/client/zutil.o
-endif
-
-ifeq ($(HAVE_VM_COMPILED),true)
- ifeq ($(ARCH),i386)
- Q3OBJ += $(B)/client/vm_x86.o
- endif
- ifeq ($(ARCH),x86)
- Q3OBJ += $(B)/client/vm_x86.o
- endif
- ifeq ($(ARCH),x86_64)
- Q3OBJ += $(B)/client/vm_x86_64.o $(B)/client/vm_x86_64_assembler.o
- endif
- ifeq ($(ARCH),ppc)
- Q3OBJ += $(B)/client/vm_powerpc.o $(B)/client/vm_powerpc_asm.o
- endif
- ifeq ($(ARCH),ppc64)
- Q3OBJ += $(B)/client/vm_powerpc.o $(B)/client/vm_powerpc_asm.o
- endif
- ifeq ($(ARCH),sparc)
- Q3OBJ += $(B)/client/vm_sparc.o
- endif
-endif
-
-ifeq ($(PLATFORM),mingw32)
- Q3OBJ += \
- $(B)/client/win_resource.o \
- $(B)/client/sys_win32.o
-else
- Q3OBJ += \
- $(B)/client/sys_unix.o
-endif
-
-ifeq ($(PLATFORM),darwin)
- Q3OBJ += \
- $(B)/client/sys_cocoa.o
-endif
-
-ifeq ($(USE_MUMBLE),1)
- Q3OBJ += \
- $(B)/client/libmumblelink.o
-endif
-
-Q3POBJ += \
- $(B)/client/sdl_glimp.o
-
-Q3POBJ_SMP += \
- $(B)/clientsmp/sdl_glimp.o
-
-$(B)/ioquake3$(FULLBINEXT): $(Q3OBJ) $(Q3POBJ) $(LIBSDLMAIN)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \
- -o $@ $(Q3OBJ) $(Q3POBJ) \
- $(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS)
-
-$(B)/ioquake3-smp$(FULLBINEXT): $(Q3OBJ) $(Q3POBJ_SMP) $(LIBSDLMAIN)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(THREAD_LDFLAGS) \
- -o $@ $(Q3OBJ) $(Q3POBJ_SMP) \
- $(THREAD_LIBS) $(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS)
-
-ifneq ($(strip $(LIBSDLMAIN)),)
-ifneq ($(strip $(LIBSDLMAINSRC)),)
-$(LIBSDLMAIN) : $(LIBSDLMAINSRC)
- cp $< $@
- ranlib $@
-endif
-endif
-
-
-
-#############################################################################
-# DEDICATED SERVER
-#############################################################################
-
-Q3DOBJ = \
- $(B)/ded/sv_bot.o \
- $(B)/ded/sv_client.o \
- $(B)/ded/sv_ccmds.o \
- $(B)/ded/sv_game.o \
- $(B)/ded/sv_init.o \
- $(B)/ded/sv_main.o \
- $(B)/ded/sv_net_chan.o \
- $(B)/ded/sv_snapshot.o \
- $(B)/ded/sv_world.o \
- \
- $(B)/ded/cm_load.o \
- $(B)/ded/cm_patch.o \
- $(B)/ded/cm_polylib.o \
- $(B)/ded/cm_test.o \
- $(B)/ded/cm_trace.o \
- $(B)/ded/cmd.o \
- $(B)/ded/common.o \
- $(B)/ded/cvar.o \
- $(B)/ded/files.o \
- $(B)/ded/md4.o \
- $(B)/ded/msg.o \
- $(B)/ded/net_chan.o \
- $(B)/ded/net_ip.o \
- $(B)/ded/huffman.o \
- \
- $(B)/ded/q_math.o \
- $(B)/ded/q_shared.o \
- \
- $(B)/ded/unzip.o \
- $(B)/ded/ioapi.o \
- $(B)/ded/vm.o \
- $(B)/ded/vm_interpreted.o \
- \
- $(B)/ded/be_aas_bspq3.o \
- $(B)/ded/be_aas_cluster.o \
- $(B)/ded/be_aas_debug.o \
- $(B)/ded/be_aas_entity.o \
- $(B)/ded/be_aas_file.o \
- $(B)/ded/be_aas_main.o \
- $(B)/ded/be_aas_move.o \
- $(B)/ded/be_aas_optimize.o \
- $(B)/ded/be_aas_reach.o \
- $(B)/ded/be_aas_route.o \
- $(B)/ded/be_aas_routealt.o \
- $(B)/ded/be_aas_sample.o \
- $(B)/ded/be_ai_char.o \
- $(B)/ded/be_ai_chat.o \
- $(B)/ded/be_ai_gen.o \
- $(B)/ded/be_ai_goal.o \
- $(B)/ded/be_ai_move.o \
- $(B)/ded/be_ai_weap.o \
- $(B)/ded/be_ai_weight.o \
- $(B)/ded/be_ea.o \
- $(B)/ded/be_interface.o \
- $(B)/ded/l_crc.o \
- $(B)/ded/l_libvar.o \
- $(B)/ded/l_log.o \
- $(B)/ded/l_memory.o \
- $(B)/ded/l_precomp.o \
- $(B)/ded/l_script.o \
- $(B)/ded/l_struct.o \
- \
- $(B)/ded/null_client.o \
- $(B)/ded/null_input.o \
- $(B)/ded/null_snddma.o \
- \
- $(B)/ded/con_log.o \
- $(B)/ded/sys_main.o
-
-ifeq ($(ARCH),i386)
- Q3DOBJ += \
- $(B)/ded/ftola.o \
- $(B)/ded/snapvectora.o \
- $(B)/ded/matha.o
-endif
-ifeq ($(ARCH),x86)
- Q3DOBJ += \
- $(B)/ded/ftola.o \
- $(B)/ded/snapvectora.o \
- $(B)/ded/matha.o
-endif
-
-ifeq ($(USE_INTERNAL_ZLIB),1)
-Q3DOBJ += \
- $(B)/ded/adler32.o \
- $(B)/ded/crc32.o \
- $(B)/ded/inffast.o \
- $(B)/ded/inflate.o \
- $(B)/ded/inftrees.o \
- $(B)/ded/zutil.o
-endif
-
-ifeq ($(HAVE_VM_COMPILED),true)
- ifeq ($(ARCH),i386)
- Q3DOBJ += $(B)/ded/vm_x86.o
- endif
- ifeq ($(ARCH),x86)
- Q3DOBJ += $(B)/ded/vm_x86.o
- endif
- ifeq ($(ARCH),x86_64)
- Q3DOBJ += $(B)/ded/vm_x86_64.o $(B)/ded/vm_x86_64_assembler.o
- endif
- ifeq ($(ARCH),ppc)
- Q3DOBJ += $(B)/ded/vm_powerpc.o $(B)/ded/vm_powerpc_asm.o
- endif
- ifeq ($(ARCH),ppc64)
- Q3DOBJ += $(B)/ded/vm_powerpc.o $(B)/ded/vm_powerpc_asm.o
- endif
- ifeq ($(ARCH),sparc)
- Q3DOBJ += $(B)/ded/vm_sparc.o
- endif
-endif
-
-ifeq ($(PLATFORM),mingw32)
- Q3DOBJ += \
- $(B)/ded/win_resource.o \
- $(B)/ded/sys_win32.o \
- $(B)/ded/con_win32.o
-else
- Q3DOBJ += \
- $(B)/ded/sys_unix.o \
- $(B)/ded/con_tty.o
-endif
-
-# Not currently referenced in the dedicated server.
-#ifeq ($(PLATFORM),darwin)
-# Q3DOBJ += \
-# $(B)/ded/sys_cocoa.o
-#endif
-
-$(B)/ioq3ded$(FULLBINEXT): $(Q3DOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(Q3DOBJ) $(LIBS)
-
-
-
-#############################################################################
-## BASEQ3 CGAME
-#############################################################################
-
-Q3CGOBJ_ = \
- $(B)/baseq3/cgame/cg_main.o \
- $(B)/baseq3/cgame/bg_misc.o \
- $(B)/baseq3/cgame/bg_pmove.o \
- $(B)/baseq3/cgame/bg_slidemove.o \
- $(B)/baseq3/cgame/bg_lib.o \
- $(B)/baseq3/cgame/cg_consolecmds.o \
- $(B)/baseq3/cgame/cg_draw.o \
- $(B)/baseq3/cgame/cg_drawtools.o \
- $(B)/baseq3/cgame/cg_effects.o \
- $(B)/baseq3/cgame/cg_ents.o \
- $(B)/baseq3/cgame/cg_event.o \
- $(B)/baseq3/cgame/cg_info.o \
- $(B)/baseq3/cgame/cg_localents.o \
- $(B)/baseq3/cgame/cg_marks.o \
- $(B)/baseq3/cgame/cg_players.o \
- $(B)/baseq3/cgame/cg_playerstate.o \
- $(B)/baseq3/cgame/cg_predict.o \
- $(B)/baseq3/cgame/cg_scoreboard.o \
- $(B)/baseq3/cgame/cg_servercmds.o \
- $(B)/baseq3/cgame/cg_snapshot.o \
- $(B)/baseq3/cgame/cg_view.o \
- $(B)/baseq3/cgame/cg_weapons.o \
- \
- $(B)/baseq3/qcommon/q_math.o \
- $(B)/baseq3/qcommon/q_shared.o
-
-Q3CGOBJ = $(Q3CGOBJ_) $(B)/baseq3/cgame/cg_syscalls.o
-Q3CGVMOBJ = $(Q3CGOBJ_:%.o=%.asm)
-
-$(B)/baseq3/cgame$(SHLIBNAME): $(Q3CGOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3CGOBJ)
-
-$(B)/baseq3/vm/cgame.qvm: $(Q3CGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(Q3CGVMOBJ) $(CGDIR)/cg_syscalls.asm
-
-#############################################################################
-## MISSIONPACK CGAME
-#############################################################################
-
-MPCGOBJ_ = \
- $(B)/missionpack/cgame/cg_main.o \
- $(B)/missionpack/cgame/bg_misc.o \
- $(B)/missionpack/cgame/bg_pmove.o \
- $(B)/missionpack/cgame/bg_slidemove.o \
- $(B)/missionpack/cgame/bg_lib.o \
- $(B)/missionpack/cgame/cg_consolecmds.o \
- $(B)/missionpack/cgame/cg_newdraw.o \
- $(B)/missionpack/cgame/cg_draw.o \
- $(B)/missionpack/cgame/cg_drawtools.o \
- $(B)/missionpack/cgame/cg_effects.o \
- $(B)/missionpack/cgame/cg_ents.o \
- $(B)/missionpack/cgame/cg_event.o \
- $(B)/missionpack/cgame/cg_info.o \
- $(B)/missionpack/cgame/cg_localents.o \
- $(B)/missionpack/cgame/cg_marks.o \
- $(B)/missionpack/cgame/cg_players.o \
- $(B)/missionpack/cgame/cg_playerstate.o \
- $(B)/missionpack/cgame/cg_predict.o \
- $(B)/missionpack/cgame/cg_scoreboard.o \
- $(B)/missionpack/cgame/cg_servercmds.o \
- $(B)/missionpack/cgame/cg_snapshot.o \
- $(B)/missionpack/cgame/cg_view.o \
- $(B)/missionpack/cgame/cg_weapons.o \
- $(B)/missionpack/ui/ui_shared.o \
- \
- $(B)/missionpack/qcommon/q_math.o \
- $(B)/missionpack/qcommon/q_shared.o
-
-MPCGOBJ = $(MPCGOBJ_) $(B)/missionpack/cgame/cg_syscalls.o
-MPCGVMOBJ = $(MPCGOBJ_:%.o=%.asm)
-
-$(B)/missionpack/cgame$(SHLIBNAME): $(MPCGOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPCGOBJ)
-
-$(B)/missionpack/vm/cgame.qvm: $(MPCGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(MPCGVMOBJ) $(CGDIR)/cg_syscalls.asm
-
-
-
-#############################################################################
-## BASEQ3 GAME
-#############################################################################
-
-Q3GOBJ_ = \
- $(B)/baseq3/game/g_main.o \
- $(B)/baseq3/game/ai_chat.o \
- $(B)/baseq3/game/ai_cmd.o \
- $(B)/baseq3/game/ai_dmnet.o \
- $(B)/baseq3/game/ai_dmq3.o \
- $(B)/baseq3/game/ai_main.o \
- $(B)/baseq3/game/ai_team.o \
- $(B)/baseq3/game/ai_vcmd.o \
- $(B)/baseq3/game/bg_misc.o \
- $(B)/baseq3/game/bg_pmove.o \
- $(B)/baseq3/game/bg_slidemove.o \
- $(B)/baseq3/game/bg_lib.o \
- $(B)/baseq3/game/g_active.o \
- $(B)/baseq3/game/g_arenas.o \
- $(B)/baseq3/game/g_bot.o \
- $(B)/baseq3/game/g_client.o \
- $(B)/baseq3/game/g_cmds.o \
- $(B)/baseq3/game/g_combat.o \
- $(B)/baseq3/game/g_items.o \
- $(B)/baseq3/game/g_mem.o \
- $(B)/baseq3/game/g_misc.o \
- $(B)/baseq3/game/g_missile.o \
- $(B)/baseq3/game/g_mover.o \
- $(B)/baseq3/game/g_session.o \
- $(B)/baseq3/game/g_spawn.o \
- $(B)/baseq3/game/g_svcmds.o \
- $(B)/baseq3/game/g_target.o \
- $(B)/baseq3/game/g_team.o \
- $(B)/baseq3/game/g_trigger.o \
- $(B)/baseq3/game/g_utils.o \
- $(B)/baseq3/game/g_weapon.o \
- \
- $(B)/baseq3/qcommon/q_math.o \
- $(B)/baseq3/qcommon/q_shared.o
-
-Q3GOBJ = $(Q3GOBJ_) $(B)/baseq3/game/g_syscalls.o
-Q3GVMOBJ = $(Q3GOBJ_:%.o=%.asm)
-
-$(B)/baseq3/qagame$(SHLIBNAME): $(Q3GOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3GOBJ)
-
-$(B)/baseq3/vm/qagame.qvm: $(Q3GVMOBJ) $(GDIR)/g_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(Q3GVMOBJ) $(GDIR)/g_syscalls.asm
-
-#############################################################################
-## MISSIONPACK GAME
-#############################################################################
-
-MPGOBJ_ = \
- $(B)/missionpack/game/g_main.o \
- $(B)/missionpack/game/ai_chat.o \
- $(B)/missionpack/game/ai_cmd.o \
- $(B)/missionpack/game/ai_dmnet.o \
- $(B)/missionpack/game/ai_dmq3.o \
- $(B)/missionpack/game/ai_main.o \
- $(B)/missionpack/game/ai_team.o \
- $(B)/missionpack/game/ai_vcmd.o \
- $(B)/missionpack/game/bg_misc.o \
- $(B)/missionpack/game/bg_pmove.o \
- $(B)/missionpack/game/bg_slidemove.o \
- $(B)/missionpack/game/bg_lib.o \
- $(B)/missionpack/game/g_active.o \
- $(B)/missionpack/game/g_arenas.o \
- $(B)/missionpack/game/g_bot.o \
- $(B)/missionpack/game/g_client.o \
- $(B)/missionpack/game/g_cmds.o \
- $(B)/missionpack/game/g_combat.o \
- $(B)/missionpack/game/g_items.o \
- $(B)/missionpack/game/g_mem.o \
- $(B)/missionpack/game/g_misc.o \
- $(B)/missionpack/game/g_missile.o \
- $(B)/missionpack/game/g_mover.o \
- $(B)/missionpack/game/g_session.o \
- $(B)/missionpack/game/g_spawn.o \
- $(B)/missionpack/game/g_svcmds.o \
- $(B)/missionpack/game/g_target.o \
- $(B)/missionpack/game/g_team.o \
- $(B)/missionpack/game/g_trigger.o \
- $(B)/missionpack/game/g_utils.o \
- $(B)/missionpack/game/g_weapon.o \
- \
- $(B)/missionpack/qcommon/q_math.o \
- $(B)/missionpack/qcommon/q_shared.o
-
-MPGOBJ = $(MPGOBJ_) $(B)/missionpack/game/g_syscalls.o
-MPGVMOBJ = $(MPGOBJ_:%.o=%.asm)
-
-$(B)/missionpack/qagame$(SHLIBNAME): $(MPGOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPGOBJ)
-
-$(B)/missionpack/vm/qagame.qvm: $(MPGVMOBJ) $(GDIR)/g_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(MPGVMOBJ) $(GDIR)/g_syscalls.asm
-
-
-
-#############################################################################
-## BASEQ3 UI
-#############################################################################
-
-Q3UIOBJ_ = \
- $(B)/baseq3/ui/ui_main.o \
- $(B)/baseq3/ui/bg_misc.o \
- $(B)/baseq3/ui/bg_lib.o \
- $(B)/baseq3/ui/ui_addbots.o \
- $(B)/baseq3/ui/ui_atoms.o \
- $(B)/baseq3/ui/ui_cdkey.o \
- $(B)/baseq3/ui/ui_cinematics.o \
- $(B)/baseq3/ui/ui_confirm.o \
- $(B)/baseq3/ui/ui_connect.o \
- $(B)/baseq3/ui/ui_controls2.o \
- $(B)/baseq3/ui/ui_credits.o \
- $(B)/baseq3/ui/ui_demo2.o \
- $(B)/baseq3/ui/ui_display.o \
- $(B)/baseq3/ui/ui_gameinfo.o \
- $(B)/baseq3/ui/ui_ingame.o \
- $(B)/baseq3/ui/ui_loadconfig.o \
- $(B)/baseq3/ui/ui_menu.o \
- $(B)/baseq3/ui/ui_mfield.o \
- $(B)/baseq3/ui/ui_mods.o \
- $(B)/baseq3/ui/ui_network.o \
- $(B)/baseq3/ui/ui_options.o \
- $(B)/baseq3/ui/ui_playermodel.o \
- $(B)/baseq3/ui/ui_players.o \
- $(B)/baseq3/ui/ui_playersettings.o \
- $(B)/baseq3/ui/ui_preferences.o \
- $(B)/baseq3/ui/ui_qmenu.o \
- $(B)/baseq3/ui/ui_removebots.o \
- $(B)/baseq3/ui/ui_saveconfig.o \
- $(B)/baseq3/ui/ui_serverinfo.o \
- $(B)/baseq3/ui/ui_servers2.o \
- $(B)/baseq3/ui/ui_setup.o \
- $(B)/baseq3/ui/ui_sound.o \
- $(B)/baseq3/ui/ui_sparena.o \
- $(B)/baseq3/ui/ui_specifyserver.o \
- $(B)/baseq3/ui/ui_splevel.o \
- $(B)/baseq3/ui/ui_sppostgame.o \
- $(B)/baseq3/ui/ui_spskill.o \
- $(B)/baseq3/ui/ui_startserver.o \
- $(B)/baseq3/ui/ui_team.o \
- $(B)/baseq3/ui/ui_teamorders.o \
- $(B)/baseq3/ui/ui_video.o \
- \
- $(B)/baseq3/qcommon/q_math.o \
- $(B)/baseq3/qcommon/q_shared.o
-
-Q3UIOBJ = $(Q3UIOBJ_) $(B)/missionpack/ui/ui_syscalls.o
-Q3UIVMOBJ = $(Q3UIOBJ_:%.o=%.asm)
-
-$(B)/baseq3/ui$(SHLIBNAME): $(Q3UIOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3UIOBJ)
-
-$(B)/baseq3/vm/ui.qvm: $(Q3UIVMOBJ) $(UIDIR)/ui_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(Q3UIVMOBJ) $(UIDIR)/ui_syscalls.asm
-
-#############################################################################
-## MISSIONPACK UI
-#############################################################################
-
-MPUIOBJ_ = \
- $(B)/missionpack/ui/ui_main.o \
- $(B)/missionpack/ui/ui_atoms.o \
- $(B)/missionpack/ui/ui_gameinfo.o \
- $(B)/missionpack/ui/ui_players.o \
- $(B)/missionpack/ui/ui_shared.o \
- \
- $(B)/missionpack/ui/bg_misc.o \
- $(B)/missionpack/ui/bg_lib.o \
- \
- $(B)/missionpack/qcommon/q_math.o \
- $(B)/missionpack/qcommon/q_shared.o
-
-MPUIOBJ = $(MPUIOBJ_) $(B)/missionpack/ui/ui_syscalls.o
-MPUIVMOBJ = $(MPUIOBJ_:%.o=%.asm)
-
-$(B)/missionpack/ui$(SHLIBNAME): $(MPUIOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPUIOBJ)
-
-$(B)/missionpack/vm/ui.qvm: $(MPUIVMOBJ) $(UIDIR)/ui_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(MPUIVMOBJ) $(UIDIR)/ui_syscalls.asm
-
-
-
-#############################################################################
-## CLIENT/SERVER RULES
-#############################################################################
-
-$(B)/client/%.o: $(ASMDIR)/%.s
- $(DO_AS)
-
-$(B)/client/%.o: $(CDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(SDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(CMDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(BLIBDIR)/%.c
- $(DO_BOT_CC)
-
-$(B)/client/%.o: $(JPDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(SPEEXDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(ZDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(RDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(SDLDIR)/%.c
- $(DO_CC)
-
-$(B)/clientsmp/%.o: $(SDLDIR)/%.c
- $(DO_SMP_CC)
-
-$(B)/client/%.o: $(SYSDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(SYSDIR)/%.m
- $(DO_CC)
-
-$(B)/client/%.o: $(SYSDIR)/%.rc
- $(DO_WINDRES)
-
-
-$(B)/ded/%.o: $(ASMDIR)/%.s
- $(DO_AS)
-
-$(B)/ded/%.o: $(SDIR)/%.c
- $(DO_DED_CC)
-
-$(B)/ded/%.o: $(CMDIR)/%.c
- $(DO_DED_CC)
-
-$(B)/ded/%.o: $(ZDIR)/%.c
- $(DO_DED_CC)
-
-$(B)/ded/%.o: $(BLIBDIR)/%.c
- $(DO_BOT_CC)
-
-$(B)/ded/%.o: $(SYSDIR)/%.c
- $(DO_DED_CC)
-
-$(B)/ded/%.o: $(SYSDIR)/%.m
- $(DO_DED_CC)
-
-$(B)/ded/%.o: $(SYSDIR)/%.rc
- $(DO_WINDRES)
-
-$(B)/ded/%.o: $(NDIR)/%.c
- $(DO_DED_CC)
-
-# Extra dependencies to ensure the SVN version is incorporated
-ifeq ($(USE_SVN),1)
- $(B)/client/cl_console.o : .svn/entries
- $(B)/client/common.o : .svn/entries
- $(B)/ded/common.o : .svn/entries
-endif
-
-
-#############################################################################
-## GAME MODULE RULES
-#############################################################################
-
-$(B)/baseq3/cgame/bg_%.o: $(GDIR)/bg_%.c
- $(DO_CGAME_CC)
-
-$(B)/baseq3/cgame/%.o: $(CGDIR)/%.c
- $(DO_CGAME_CC)
-
-$(B)/baseq3/cgame/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
- $(DO_CGAME_Q3LCC)
-
-$(B)/baseq3/cgame/%.asm: $(CGDIR)/%.c $(Q3LCC)
- $(DO_CGAME_Q3LCC)
-
-$(B)/missionpack/cgame/bg_%.o: $(GDIR)/bg_%.c
- $(DO_CGAME_CC_MISSIONPACK)
-
-$(B)/missionpack/cgame/%.o: $(CGDIR)/%.c
- $(DO_CGAME_CC_MISSIONPACK)
-
-$(B)/missionpack/cgame/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
- $(DO_CGAME_Q3LCC_MISSIONPACK)
-
-$(B)/missionpack/cgame/%.asm: $(CGDIR)/%.c $(Q3LCC)
- $(DO_CGAME_Q3LCC_MISSIONPACK)
-
-
-$(B)/baseq3/game/%.o: $(GDIR)/%.c
- $(DO_GAME_CC)
-
-$(B)/baseq3/game/%.asm: $(GDIR)/%.c $(Q3LCC)
- $(DO_GAME_Q3LCC)
-
-$(B)/missionpack/game/%.o: $(GDIR)/%.c
- $(DO_GAME_CC_MISSIONPACK)
-
-$(B)/missionpack/game/%.asm: $(GDIR)/%.c $(Q3LCC)
- $(DO_GAME_Q3LCC_MISSIONPACK)
-
-
-$(B)/baseq3/ui/bg_%.o: $(GDIR)/bg_%.c
- $(DO_UI_CC)
-
-$(B)/baseq3/ui/%.o: $(Q3UIDIR)/%.c
- $(DO_UI_CC)
-
-$(B)/baseq3/ui/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
- $(DO_UI_Q3LCC)
-
-$(B)/baseq3/ui/%.asm: $(Q3UIDIR)/%.c $(Q3LCC)
- $(DO_UI_Q3LCC)
-
-$(B)/missionpack/ui/bg_%.o: $(GDIR)/bg_%.c
- $(DO_UI_CC_MISSIONPACK)
-
-$(B)/missionpack/ui/%.o: $(UIDIR)/%.c
- $(DO_UI_CC_MISSIONPACK)
-
-$(B)/missionpack/ui/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
- $(DO_UI_Q3LCC_MISSIONPACK)
-
-$(B)/missionpack/ui/%.asm: $(UIDIR)/%.c $(Q3LCC)
- $(DO_UI_Q3LCC_MISSIONPACK)
-
-
-$(B)/baseq3/qcommon/%.o: $(CMDIR)/%.c
- $(DO_SHLIB_CC)
-
-$(B)/baseq3/qcommon/%.asm: $(CMDIR)/%.c $(Q3LCC)
- $(DO_Q3LCC)
-
-$(B)/missionpack/qcommon/%.o: $(CMDIR)/%.c
- $(DO_SHLIB_CC_MISSIONPACK)
-
-$(B)/missionpack/qcommon/%.asm: $(CMDIR)/%.c $(Q3LCC)
- $(DO_Q3LCC_MISSIONPACK)
-
-
-#############################################################################
-# MISC
-#############################################################################
-
-OBJ = $(Q3OBJ) $(Q3POBJ) $(Q3POBJ_SMP) $(Q3DOBJ) \
- $(MPGOBJ) $(Q3GOBJ) $(Q3CGOBJ) $(MPCGOBJ) $(Q3UIOBJ) $(MPUIOBJ) \
- $(MPGVMOBJ) $(Q3GVMOBJ) $(Q3CGVMOBJ) $(MPCGVMOBJ) $(Q3UIVMOBJ) $(MPUIVMOBJ)
-TOOLSOBJ = $(LBURGOBJ) $(Q3CPPOBJ) $(Q3RCCOBJ) $(Q3LCCOBJ) $(Q3ASMOBJ)
-
-
-copyfiles: release
- @if [ ! -d $(COPYDIR)/baseq3 ]; then echo "You need to set COPYDIR to where your Quake3 data is!"; fi
- -$(MKDIR) -p -m 0755 $(COPYDIR)/baseq3
- -$(MKDIR) -p -m 0755 $(COPYDIR)/missionpack
-
-ifneq ($(BUILD_CLIENT),0)
- $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/ioquake3$(FULLBINEXT) $(COPYBINDIR)/ioquake3$(FULLBINEXT)
-endif
-
-# Don't copy the SMP until it's working together with SDL.
-#ifneq ($(BUILD_CLIENT_SMP),0)
-# $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/ioquake3-smp$(FULLBINEXT) $(COPYBINDIR)/ioquake3-smp$(FULLBINEXT)
-#endif
-
-ifneq ($(BUILD_SERVER),0)
- @if [ -f $(BR)/ioq3ded$(FULLBINEXT) ]; then \
- $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/ioq3ded$(FULLBINEXT) $(COPYBINDIR)/ioq3ded$(FULLBINEXT); \
- fi
-endif
-
-ifneq ($(BUILD_GAME_SO),0)
- $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/baseq3/cgame$(SHLIBNAME) \
- $(COPYDIR)/baseq3/.
- $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/baseq3/qagame$(SHLIBNAME) \
- $(COPYDIR)/baseq3/.
- $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/baseq3/ui$(SHLIBNAME) \
- $(COPYDIR)/baseq3/.
- ifneq ($(BUILD_MISSIONPACK),0)
- -$(MKDIR) -p -m 0755 $(COPYDIR)/missionpack
- $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/missionpack/cgame$(SHLIBNAME) \
- $(COPYDIR)/missionpack/.
- $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/missionpack/qagame$(SHLIBNAME) \
- $(COPYDIR)/missionpack/.
- $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/missionpack/ui$(SHLIBNAME) \
- $(COPYDIR)/missionpack/.
- endif
-endif
-
-clean: clean-debug clean-release
-ifeq ($(PLATFORM),mingw32)
- @$(MAKE) -C $(NSISDIR) clean
-else
- @$(MAKE) -C $(LOKISETUPDIR) clean
-endif
-
-clean-debug:
- @$(MAKE) clean2 B=$(BD)
-
-clean-release:
- @$(MAKE) clean2 B=$(BR)
-
-clean2:
- @echo "CLEAN $(B)"
- @rm -f $(OBJ)
- @rm -f $(OBJ_D_FILES)
- @rm -f $(TARGETS)
-
-toolsclean: toolsclean-debug toolsclean-release
-
-toolsclean-debug:
- @$(MAKE) toolsclean2 B=$(BD)
-
-toolsclean-release:
- @$(MAKE) toolsclean2 B=$(BR)
-
-toolsclean2:
- @echo "TOOLS_CLEAN $(B)"
- @rm -f $(TOOLSOBJ)
- @rm -f $(TOOLSOBJ_D_FILES)
- @rm -f $(LBURG) $(DAGCHECK_C) $(Q3RCC) $(Q3CPP) $(Q3LCC) $(Q3ASM)
-
-distclean: clean toolsclean
- @rm -rf $(BUILD_DIR)
-
-installer: release
-ifeq ($(PLATFORM),mingw32)
- @$(MAKE) VERSION=$(VERSION) -C $(NSISDIR) V=$(V)
-else
- @$(MAKE) VERSION=$(VERSION) -C $(LOKISETUPDIR) V=$(V)
-endif
-
-dist:
- rm -rf ioquake3-$(VERSION)
- svn export . ioquake3-$(VERSION)
- tar --owner=root --group=root --force-local -cjf ioquake3-$(VERSION).tar.bz2 ioquake3-$(VERSION)
- rm -rf ioquake3-$(VERSION)
-
-#############################################################################
-# DEPENDENCIES
-#############################################################################
-
-ifneq ($(B),)
- OBJ_D_FILES=$(filter %.d,$(OBJ:%.o=%.d))
- TOOLSOBJ_D_FILES=$(filter %.d,$(TOOLSOBJ:%.o=%.d))
- -include $(OBJ_D_FILES) $(TOOLSOBJ_D_FILES)
-endif
-
-.PHONY: all clean clean2 clean-debug clean-release copyfiles \
- debug default dist distclean installer makedirs \
- release targets \
- toolsclean toolsclean2 toolsclean-debug toolsclean-release \
- $(OBJ_D_FILES) $(TOOLSOBJ_D_FILES)
diff --git a/engine/NOTTODO b/engine/NOTTODO
deleted file mode 100644
index 0db1547..0000000
--- a/engine/NOTTODO
+++ /dev/null
@@ -1 +0,0 @@
-http://wiki.ioquake3.org/NotToDo
diff --git a/engine/README b/engine/README
deleted file mode 100644
index d776efc..0000000
--- a/engine/README
+++ /dev/null
@@ -1,575 +0,0 @@
- ,---------------------------------------.
- | _ _ ____ |
- | (_)___ __ _ _ _ __ _| |_____|__ / |
- | | / _ \/ _` | || / _` | / / -_)|_ \ |
- | |_\___/\__, |\_,_\__,_|_\_\___|___/ |
- | |_| |
- | |
- `---------- http://ioquake3.org --------'
-
-The intent of this project is to provide a baseline Quake 3 which may be used
-for further development and baseq3 fun.
-Some of the major features currently implemented are:
-
- * SDL backend
- * OpenAL sound API support (multiple speaker support and better sound
- quality)
- * Full x86_64 support on Linux
- * VoIP support, both in-game and external support through Mumble.
- * MinGW compilation support on Windows and cross compilation support on Linux
- * AVI video capture of demos
- * Much improved console autocompletion
- * Persistent console history
- * Colorized terminal output
- * Optional Ogg Vorbis support
- * Much improved QVM tools
- * Support for various esoteric operating systems
- * cl_guid support
- * HTTP/FTP download redirection (using cURL)
- * Multiuser support on Windows systems (user specific game data
- is stored in "%APPDATA%\Quake3")
- * PNG support
- * Many, many bug fixes
-
-The map editor and associated compiling tools are not included. We suggest you
-use a modern copy from http://www.qeradiant.com/.
-
-The original id software readme that accompanied the Q3 source release has been
-renamed to id-readme.txt so as to prevent confusion. Please refer to the
-web-site for updated status.
-
-
---------------------------------------------- Compilation and installation -----
-
-For *nix
- 1. Change to the directory containing this readme.
- 2. Run 'make'.
-
-For Windows,
- 1. Please refer to the excellent instructions here:
- http://wiki.ioquake3.org/Building_ioquake3
-
-For Mac OS X, building a Universal Binary
- 1. Install MacOSX SDK packages from XCode. For maximum compatibility,
- install MacOSX10.4u.sdk and MacOSX10.3.9.sdk, and MacOSX10.2.8.sdk.
- 2. Change to the directory containing this README file.
- 3. Run './make-macosx-ub.sh'
- 4. Copy the resulting ioquake3.app in /build/release-darwin-ub to your
- /Applications/ioquake3 folder.
-
-Installation, for *nix
- 1. Set the COPYDIR variable in the shell to be where you installed Quake 3
- to. By default it will be /usr/local/games/quake3 if you haven't set it.
- This is the path as used by the original Linux Q3 installer and subsequent
- point releases.
- 2. Run 'make copyfiles'.
-
-It is also possible to cross compile for Windows under *nix using MinGW. A
-script is available to build a cross compilation environment from
-http://www.libsdl.org/extras/win32/cross/build-cross.sh. The gcc/binutils
-version numbers that the script downloads may need to be altered.
-Alternatively, your distribution may have mingw32 packages available. On
-debian/Ubuntu, these are mingw32, mingw32-runtime and mingw32-binutils. Cross
-compiling is simply a case of using './cross-make-mingw.sh' in place of 'make',
-though you may find you need to change the value of the variables in this
-script to match your environment.
-
-The following variables may be set, either on the command line or in
-Makefile.local:
-
- CFLAGS - use this for custom CFLAGS
- V - set to show cc command line when building
- DEFAULT_BASEDIR - extra path to search for baseq3 and such
- BUILD_SERVER - build the 'ioq3ded' server binary
- BUILD_CLIENT - build the 'ioquake3' client binary
- BUILD_CLIENT_SMP - build the 'ioquake3-smp' client binary
- BUILD_GAME_SO - build the game shared libraries
- BUILD_GAME_QVM - build the game qvms
- BUILD_STANDALONE - build binaries suited for stand-alone games
- USE_OPENAL - use OpenAL where available
- USE_OPENAL_DLOPEN - link with OpenAL at runtime
- USE_CURL - use libcurl for http/ftp download support
- USE_CURL_DLOPEN - link with libcurl at runtime
- USE_CODEC_VORBIS - enable Ogg Vorbis support
- USE_LOCAL_HEADERS - use headers local to ioq3 instead of system ones
- COPYDIR - the target installation directory
-
-The defaults for these variables differ depending on the target platform.
-
-
------------------------------------------------------------------- Console -----
-
-New cvars
- cl_autoRecordDemo - record a new demo on each map change
- cl_aviFrameRate - the framerate to use when capturing video
- cl_aviMotionJpeg - use the mjpeg codec when capturing video
- cl_guidServerUniq - makes cl_guid unique for each server
- cl_cURLLib - filename of cURL library to load
- cl_consoleKeys - space delimited list of key names or
- characters that toggle the console
- cl_mouseAccelStyle - Set to 1 for QuakeLive mouse acceleration
- behaviour, 0 for standard q3
- cl_mouseAccelOffset - Tuning the acceleration curve, see below
-
- s_useOpenAL - use the OpenAL sound backend if available
- s_alPrecache - cache OpenAL sounds before use
- s_alGain - the value of AL_GAIN for each source
- s_alSources - the total number of sources (memory) to
- allocate
- s_alDopplerFactor - the value passed to alDopplerFactor
- s_alDopplerSpeed - the value passed to alDopplerVelocity
- s_alMinDistance - the value of AL_REFERENCE_DISTANCE for
- each source
- s_alMaxDistance - the maximum distance before sounds start
- to become inaudible.
- s_alRolloff - the value of AL_ROLLOFF_FACTOR for each
- source
- s_alGraceDistance - after having passed MaxDistance, length
- until sounds are completely inaudible
- s_alDriver - which OpenAL library to use
- s_alDevice - which OpenAL device to use
- s_alAvailableDevices - list of available OpenAL devices
- s_sdlBits - SDL bit resolution
- s_sdlSpeed - SDL sample rate
- s_sdlChannels - SDL number of channels
- s_sdlDevSamps - SDL DMA buffer size override
- s_sdlMixSamps - SDL mix buffer size override
- s_backend - read only, indicates the current sound
- backend
- s_muteWhenMinimized - mute sound when minimized
- s_muteWhenUnfocused - mute sound when window is unfocused
-
- com_ansiColor - enable use of ANSI escape codes in the tty
- com_altivec - enable use of altivec on PowerPC systems
- com_standalone - Run in standalone mode
- com_maxfpsUnfocused - Maximum frames per second when unfocused
- com_maxfpsMinimized - Maximum frames per second when minimized
-
- in_joystickNo - select which joystick to use
- in_keyboardDebug - print keyboard debug info
-
- sv_dlURL - the base of the HTTP or FTP site that
- holds custom pk3 files for your server
- sv_banFile - Name of the file that is used for storing
- the server bans.
-
- net_ip6 - IPv6 address to bind to
- net_port6 - port to bind to using the ipv6 address
- net_enabled - enable networking, bitmask. Add up
- number for option to enable it:
- enable ipv4 networking: 1
- enable ipv6 networking: 2
- prioritise ipv6 over ipv4: 4
- disable multicast support: 8
- net_mcast6addr - multicast address to use for scanning for
- ipv6 servers on the local network
- net_mcastiface - outgoing interface to use for scan
-
- r_allowResize - make window resizable (SDL only)
- r_ext_texture_filter_anisotropic - anisotropic texture filtering
- r_zProj - distance of observer camera to projection
- plane in quake3 standard units
- r_greyscale - render black and white images
- r_stereoEnabled - enable stereo rendering for techniques
- like shutter glasses (untested)
- r_anaglyphMode - Enable rendering of anaglyph images
- red-cyan glasses: 1
- red-blue: 2
- red-green: 3
- To swap the colors for left and right eye
- just add 3 to the value for the wanted
- color combination. For red-blue and
- red-green you probably want to enable
- r_greyscale
- r_stereoSeparation - Control eye separation. Resulting
- separation is r_zProj divided by this
- value in quake3 standard units.
- See also
- http://wiki.ioquake3.org/Stereo_Rendering
- for more information
- r_marksOnTriangleMeshes - Support impact marks on md3 models, MOD
- developers should increase the mark
- triangle limits in cg_marks.c if they
- intend to use this.
- r_sdlDriver - read only, indicates the SDL driver
- backend being used
- r_noborder - Remove window decoration from window
- managers, like borders and titlebar.
-
-New commands
- video [filename] - start video capture (use with demo command)
- stopvideo - stop video capture
- stopmusic - stop background music
-
- print - print out the contents of a cvar
- unset - unset a user created cvar
-
- banaddr <range> - ban an ip address range from joining a game on this
- server, valid <range> is either playernum or CIDR
- notation address range.
- exceptaddr <range> - exempt an ip address range from a ban.
- bandel <range> - delete ban (either range or ban number)
- exceptdel <range> - delete exception (either range or exception number)
- listbans - list all currently active bans and exceptions
- rehashbans - reload the banlist from serverbans.dat
- flushbans - delete all bans
-
- net_restart - restart network subsystem to change latched settings
- game_restart <fs_game> - Switch to another mod
-
------------------------------------------------------------- Miscellaneous -----
-
-Using shared libraries instead of qvm
- To force Q3 to use shared libraries instead of qvms run it with the following
- parameters: +set sv_pure 0 +set vm_cgame 0 +set vm_game 0 +set vm_ui 0
-
-Using Demo Data Files
- Copy demoq3/pak0.pk3 from the demo installer to your baseq3 directory. The
- qvm files in this pak0.pk3 will not work, so you have to use the native
- shared libraries or qvms from this project. To use the new qvms, they must be
- put into a pk3 file. A pk3 file is just a zip file, so any compression tool
- that can create such files will work. The shared libraries should already be
- in the correct place. Use the instructions above to use them.
-
- Please bear in mind that you will not be able to play online using the demo
- data, nor is it something that we like to spend much time maintaining or
- supporting.
-
-QuakeLive mouse acceleration (patch and this text written by TTimo from id)
- I've been using an experimental mouse acceleration code for a while, and
- decided to make it available to everyone. Don't be too worried if you don't
- understand the explanations below, this is mostly intended for advanced
- players:
- To enable it, set cl_mouseAccelStyle 1 (0 is the default/legacy behavior)
-
- New style is controlled with 3 cvars:
-
- sensitivity
- cl_mouseAccel
- cl_mouseAccelOffset
-
- The old code (cl_mouseAccelStyle 0) can be difficult to calibrate because if
- you have a base sensitivity setup, as soon as you set a non zero acceleration
- your base sensitivity at low speeds will change as well. The other problem
- with style 0 is that you are stuck on a square (power of two) acceleration
- curve.
-
- The new code tries to solve both problems:
-
- Once you setup your sensitivity to feel comfortable and accurate enough for
- low mouse deltas with no acceleration (cl_mouseAccel 0), you can start
- increasing cl_mouseAccel and tweaking cl_mouseAccelOffset to get the
- amplification you want for high deltas with little effect on low mouse deltas.
-
- cl_mouseAccel is a power value. Should be >= 1, 2 will be the same power curve
- as style 0. The higher the value, the faster the amplification grows with the
- mouse delta.
-
- cl_mouseAccelOffset sets how much base mouse delta will be doubled by
- acceleration. The closer to zero you bring it, the more acceleration will
- happen at low speeds. This is also very useful if you are changing to a new
- mouse with higher dpi, if you go from 500 to 1000 dpi, you can divide your
- cl_mouseAccelOffset by two to keep the same overall 'feel' (you will likely
- gain in precision when you do that, but that is not related to mouse
- acceleration).
-
- Mouse acceleration is tricky to configure, and when you do you'll have to
- re-learn your aiming. But you will find that it's very much forth it in the
- long run.
-
- If you try the new acceleration code and start using it, I'd be very
- interested by your feedback.
-
-64bit mods
- If you wish to compile external mods as shared libraries on a 64bit platform,
- and the mod source is derived from the id Q3 SDK, you will need to modify the
- interface code a little. Open the files ending in _syscalls.c and change
- every instance of int to intptr_t in the declaration of the syscall function
- pointer and the dllEntry function. Also find the vmMain function for each
- module (usually in cg_main.c g_main.c etc.) and similarly replace the return
- value in the prototype with intptr_t (arg0, arg1, ...stay int).
-
- Add the following code snippet to q_shared.h:
-
- #ifdef Q3_VM
- typedef int intptr_t;
- #else
- #include <stdint.h>
- #endif
-
- Note if you simply wish to run mods on a 64bit platform you do not need to
- recompile anything since by default Q3 uses a virtual machine system.
-
-Creating mods compatible with Q3 1.32b
- If you're using this package to create mods for the last official release of
- Q3, it is necessary to pass the commandline option '-vq3' to your invocation
- of q3asm. This is because by default q3asm outputs an updated qvm format that
- is necessary to fix a bug involving the optimizing pass of the x86 vm JIT
- compiler.
-
-Creating standalone games
- Have you finished the daunting task of removing all dependencies on the Q3
- game data? You probably now want to give your users the opportunity to play
- the game without owning a copy of Q3, which consequently means removing cd-key
- and authentication server checks. In addition to being a straightforward Q3
- client, ioquake3 also purports to be a reliable and stable code base on which
- to base your game project.
-
- However, before you start compiling your own version of ioquake3, you have to
- ask yourself: Have we changed or will we need to change anything of importance
- in the engine?
-
- If your answer to this question is "no", it probably makes no sense to build
- your own binaries. Instead, you can just use the pre-built binaries on the
- website. Just make sure the game is called with:
-
- +set com_standalone 1 +set fs_game <yourgamedir>
-
- in any links/scripts you install for your users to start the game. Note that
- the com_standalone setting is rendered ineffective, if the binary detects pk3
- files in the directory "baseq3", so you cannot use that one as game dir.
-
- If you really changed parts that would make vanilla ioquake3 incompatible with
- your mod, we have included another way to conveniently build a stand-alone
- binary. Just run make with the option BUILD_STANDALONE=1. Don't forget to edit
- the PRODUCT_NAME and subsequent #defines in qcommon/q_shared.h with
- information appropriate for your project.
-
- While a lot of work has been put into ioquake3 that you can benefit from free
- of charge, it does not mean that you have no obligations to fulfil. Please be
- aware that as soon as you start distributing your game with an engine based on
- our sources we expect you to fully comply with the requirements as stated in
- the GPL. That includes making sources and modifications you made to the
- ioquake3 engine as well as the game-code used to compile the .qvm files for
- the game logic freely available to everyone. Furthermore, note that the "QIIIA
- Game Source License" prohibits distribution of mods that are intended to
- operate on a version of Q3 not sanctioned by id software:
-
- "with this Agreement, ID grants to you the non-exclusive and limited right
- to distribute copies of the Software ... for operation only with the full
- version of the software game QUAKE III ARENA"
-
- This means that if you're creating a standalone game, you cannot use said
- license on any portion of the product. As the only other license this code has
- been released under is the GPL, this is the only option.
-
- This does NOT mean that you cannot market this game commercially. The GPL does
- not prohibit commercial exploitation and all assets (e.g. textures, sounds,
- maps) created by yourself are your property and can be sold like every other
- game you find in stores.
-
-cl_guid Support
- cl_guid is a cvar which is part of the client's USERINFO string. Its value
- is a 32 character string made up of [a-f] and [0-9] characters. This
- value is pseudo-unique for every player. Id's Quake 3 Arena client also
- sets cl_guid, but only if Punkbuster is enabled on the client.
-
- If cl_guidServerUniq is non-zero (the default), then this value is also
- pseudo-unique for each server a client connects to (based on IP:PORT of
- the server).
-
- The purpose of cl_guid is to add an identifier for each player on
- a server. This value can be reset by the client at any time so it's not
- useful for blocking access. However, it can have at least two uses in
- your mod's game code:
- 1) improve logging to allow statistical tools to index players by more
- than just name
- 2) granting some weak admin rights to players without requiring passwords
-
-Using HTTP/FTP Download Support (Server)
- You can enable redirected downloads on your server even if it's not
- an ioquake3 server. You simply need to use the 'sets' command to put
- the sv_dlURL cvar into your SERVERINFO string and ensure sv_allowDownloads
- is set to 1
-
- sv_dlURL is the base of the URL that contains your custom .pk3 files
- the client will append both fs_game and the filename to the end of
- this value. For example, if you have sv_dlURL set to
- "http://ioquake3.org", fs_game is "baseq3", and the client is
- missing "test.pk3", it will attempt to download from the URL
- "http://ioquake3.org/baseq3/test.pk3"
-
- sv_allowDownload's value is now a bitmask made up of the following
- flags:
- 1 - ENABLE
- 4 - do not use UDP downloads
- 8 - do not ask the client to disconnect when using HTTP/FTP
-
- Server operators who are concerned about potential "leeching" from their
- HTTP servers from other ioquake3 servers can make use of the HTTP_REFERER
- that ioquake3 sets which is "ioQ3://{SERVER_IP}:{SERVER_PORT}". For,
- example, Apache's mod_rewrite can restrict access based on HTTP_REFERER.
-
-Using HTTP/FTP Download Support (Client)
- Simply setting cl_allowDownload to 1 will enable HTTP/FTP downloads
- assuming ioquake3 was compiled with USE_CURL=1 (the default).
- like sv_allowDownload, cl_allowDownload also uses a bitmask value
- supporting the following flags:
- 1 - ENABLE
- 2 - do not use HTTP/FTP downloads
- 4 - do not use UDP downloads
-
- When ioquake3 is built with USE_CURL_DLOPEN=1 (default on some platforms),
- it will use the value of the cvar cl_cURLLib as the filename of the cURL
- library to dynamically load.
-
-Multiuser Support on Windows systems
- On Windows, all user specific files such as autogenerated configuration,
- demos, videos, screenshots, and autodownloaded pk3s are now saved in a
- directory specific to the user who is running ioquake3.
-
- On NT-based such as Windows XP, this is usually a directory named:
- "C:\Documents and Settings\%USERNAME%\Application Data\Quake3\"
-
- Windows 95, Windows 98, and Windows ME will use a directory like:
- "C:\Windows\Application Data\Quake3"
- in single-user mode, or:
- "C:\Windows\Profiles\%USERNAME%\Application Data\Quake3"
- if multiple logins have been enabled.
-
- In order to access this directory more easily, the installer may create a
- Shortcut which has its target set to:
- "%APPDATA%\Quake3\"
- This Shortcut would work for all users on the system regardless of the
- locale settings. Unfortunately, this environment variable is only
- present on Windows NT based systems.
-
- You can revert to the old single-user behaviour by setting the fs_homepath
- cvar to the directory where ioquake3 is installed. For example:
- ioquake3.exe +set fs_homepath "c:\ioquake3"
- Note that this cvar MUST be set as a command line parameter.
-
-SDL Keyboard Differences
- ioquake3 clients have different keyboard behaviour compared to the original
- Quake3 clients.
-
- * "Caps Lock" and "Num Lock" can not be used as normal binds since they
- do not send a KEYUP event until the key is pressed again.
-
- * SDL > 1.2.9 does not support disabling dead key recognition. In order to
- send dead key characters (e.g. ~, ', `, and ^), you must key a Space (or
- sometimes the same character again) after the character to send it on
- many international keyboard layouts.
-
- * The SDL client supports many more keys than the original Quake3 client.
- For example the keys: "Windows", "SysReq", "ScrollLock", and "Break".
- For non-US keyboards, all of the so called "World" keys are now supported
- as well as F13, F14, F15, and the country-specific mode/meta keys.
-
- On many international layouts the default console toggle keys are also dead
- keys, meaning that dropping the console potentially results in
- unintentionally initiating the keying of a dead key. Futhermore SDL 1.2's
- dead key support is broken by design and Q3 doesn't support non-ASCII text
- entry, so the chances are you won't get the correct character anyway.
-
- If you use such a keyboard layout, you can set the cvar cl_consoleKeys. This
- is a space delimited list of key names that will toggle the console. The key
- names are the usual Q3 names e.g. "~", "`", "c", "BACKSPACE", "PAUSE",
- "WINDOWS" etc. It's also possible to use ASCII characters, by hexadecimal
- number. Some example values for cl_consoleKeys:
-
- "~ ` 0x7e 0x60" Toggle on ~ or ` (the default)
- "WINDOWS" Toggle on the Windows key
- "c" Toggle on the c key
- "0x43" Toggle on the C character (Shift-c)
- "PAUSE F1 PGUP" Toggle on the Pause, F1 or Page Up keys
-
- Note that when you elect a set of console keys or characters, they cannot
- then be used for binding, nor will they generate characters when entering
- text. Also, in addition to the nominated console keys, Shift-ESC is hard
- coded to always toggle the console.
-
-PNG support
- ioquake3 supports the use of PNG (Portable Network Graphic) images as
- textures. It should be noted that the use of such images in a map will
- result in missing placeholder textures where the map is used with the id
- Quake 3 client or earlier versions of ioquake3.
-
- Recent versions of GtkRadiant and q3map2 support PNG images without
- modification. However GtkRadiant is not aware that PNG textures are supported
- by ioquake3. To change this behaviour open the file 'q3.game' in the 'games'
- directory of the GtkRadiant base directory with an editor and change the
- line:
-
- texturetypes="tga jpg"
-
- to
-
- texturetypes="tga jpg png"
-
- Restart GtkRadiant and PNG textures are now available.
-
-Building with MinGW for pre Windows XP
- IPv6 support requires a header named "wspiapi.h" to abstract away from
- differences in earlier versions of Windows' IPv6 stack. There is no MinGW
- equivalent of this header and the Microsoft version is obviously not
- redistributable, so in its absence we're forced to require Windows XP.
- However if this header is acquired separately and placed in the qcommon/
- directory, this restriction is lifted.
-
-
-------------------------------------------------------------- Contributing -----
-
-Please send all patches to bugzilla (https://bugzilla.icculus.org), or join the
-mailing list (quake3-subscribe at icculus.org) and submit your patch there. The
-best case scenario is that you submit your patch to bugzilla, and then post the
-URL to the mailing list.
-
-The focus for ioq3 is to develop a stable base suitable for further development
-and provide players with the same Quake 3 experience they've had for years. As
-such ioq3 does not have any significant graphical enhancements and none are
-planned at this time. However, improved graphics and sound patches will be
-accepted as long as they are entirely optional, do not require new media and
-are off by default.
-
-
---------------------------------------------- Building Official Installers -----
-
-We need help getting automated installers on all the platforms that ioquake3
-supports. We don't neccesarily care about all the installers being identical,
-but we have some general guidelines:
-
- * Please include the id patch pk3s in your installer, which are available
- from http://ioquake3.org/patch-data/ subject to agreement to the id
- EULA. Your installer shall also ask the user to agree to this EULA (which
- is in the /web/include directory for your convenience) and subsequently
- refuse to continue the installation of the patch pk3s and pak0.pk3 if they
- do not.
-
- * Please don't require pak0.pk3, since not everyone using the engine
- plans on playing Quake 3 Arena on it. It's fine to (optionally) assist the
- user in copying the file or tell them how.
-
- * It is fine to just install the binaries without requiring id EULA agreement,
- providing pak0.pk3 and the patch pk3s are not refered to or included in the
- installer.
-
- * Please include at least an SDL so/dylib/dll on every platform.
-
- * Please include an OpenAL so/dylib/dll, since every platform should be using
- it by now.
-
- * Please contact the mailing list when you've made your installer.
-
- * Please be prepared to alter your installer on the whim of the maintainers.
-
- * Your installer will be mirrored to an "official" directory, thus making it
- a done deal.
-
------------------------------------------------------------------- Credits -----
-
-Maintainers
- Ludwig Nussel <ludwig.nussel at suse.de>
- Thilo Schulz <arny at ats.s.bawue.de>
- Tim Angus <tim at ngus.net>
- Tony J. White <tjw at tjw.org>
- Zachary J. Slater <zachary at ioquake.org>
-
-Significant contributions from
- Ryan C. Gordon <icculus at icculus.org>
- Andreas Kohn <andreas at syndrom23.de>
- Joerg Dietrich <Dietrich_Joerg at t-online.de>
- Stuart Dalton <badcdev at gmail.com>
- Vincent S. Cojot <vincent at cojot dot name>
- optical <alex at rigbo.se>
- Aaron Gyes <floam at aaron.gy>
diff --git a/engine/TODO b/engine/TODO
deleted file mode 100644
index 5a3b545..0000000
--- a/engine/TODO
+++ /dev/null
@@ -1 +0,0 @@
-http://wiki.ioquake3.org/Ioquake3_Road_Map
diff --git a/engine/code/asm/ftola.s b/engine/code/asm/ftola.s
deleted file mode 100644
index 7e9c523..0000000
--- a/engine/code/asm/ftola.s
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-//
-// qftol -- fast floating point to long conversion.
-//
-
-// 23/09/05 Ported to gas by intel2gas, best supporting actor Tim Angus
-// <tim at ngus.net>
-
-#include "qasm.h"
-
-#if id386
-
-.data
-
-temp: .single 0.0
-fpucw: .long 0
-
-// Precision Control Field , 2 bits / 0x0300
-// PC24 0x0000 Single precision (24 bits).
-// PC53 0x0200 Double precision (53 bits).
-// PC64 0x0300 Extended precision (64 bits).
-
-// Rounding Control Field, 2 bits / 0x0C00
-// RCN 0x0000 Rounding to nearest (even).
-// RCD 0x0400 Rounding down (directed, minus).
-// RCU 0x0800 Rounding up (directed plus).
-// RC0 0x0C00 Rounding towards zero (chop mode).
-
-
-// rounding towards nearest (even)
-cw027F: .long 0x027F
-cw037F: .long 0x037F
-
-// rounding towards zero (chop mode)
-cw0E7F: .long 0x0E7F
-cw0F7F: .long 0x0F7F
-
-
-.text
-
-//
-// int qftol( void ) - default control word
-//
-
-.globl C(qftol)
-
-C(qftol):
- fistpl temp
- movl temp,%eax
- ret
-
-
-//
-// int qftol027F( void ) - DirectX FPU
-//
-
-.globl C(qftol027F)
-
-C(qftol027F):
- fnstcw fpucw
- fldcw cw027F
- fistpl temp
- fldcw fpucw
- movl temp,%eax
- ret
-
-//
-// int qftol037F( void ) - Linux FPU
-//
-
-.globl C(qftol037F)
-
-C(qftol037F):
- fnstcw fpucw
- fldcw cw037F
- fistpl temp
- fldcw fpucw
- movl temp,%eax
- ret
-
-
-//
-// int qftol0F7F( void ) - ANSI
-//
-
-.globl C(qftol0F7F)
-
-C(qftol0F7F):
- fnstcw fpucw
- fldcw cw0F7F
- fistpl temp
- fldcw fpucw
- movl temp,%eax
- ret
-
-//
-// int qftol0E7F( void )
-//
-
-.globl C(qftol0E7F)
-
-C(qftol0E7F):
- fnstcw fpucw
- fldcw cw0E7F
- fistpl temp
- fldcw fpucw
- movl temp,%eax
- ret
-
-
-
-//
-// long Q_ftol( float q )
-//
-
-.globl C(Q_ftol)
-
-C(Q_ftol):
- flds 4(%esp)
- fistpl temp
- movl temp,%eax
- ret
-
-
-//
-// long qftol0F7F( float q ) - Linux FPU
-//
-
-.globl C(Q_ftol0F7F)
-
-C(Q_ftol0F7F):
- fnstcw fpucw
- flds 4(%esp)
- fldcw cw0F7F
- fistpl temp
- fldcw fpucw
- movl temp,%eax
- ret
-#endif
diff --git a/engine/code/asm/matha.s b/engine/code/asm/matha.s
deleted file mode 100644
index e4770d3..0000000
--- a/engine/code/asm/matha.s
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// math.s
-// x86 assembly-language math routines.
-
-#include "qasm.h"
-
-
-#if id386
-
- .text
-
-// TODO: rounding needed?
-// stack parameter offset
-#define val 4
-
-.globl C(Invert24To16)
-C(Invert24To16):
-
- movl val(%esp),%ecx
- movl $0x100,%edx // 0x10000000000 as dividend
- cmpl %edx,%ecx
- jle LOutOfRange
-
- subl %eax,%eax
- divl %ecx
-
- ret
-
-LOutOfRange:
- movl $0xFFFFFFFF,%eax
- ret
-
-#endif // id386
diff --git a/engine/code/asm/qasm.h b/engine/code/asm/qasm.h
deleted file mode 100644
index f38acb5..0000000
--- a/engine/code/asm/qasm.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#ifndef __ASM_I386__
-#define __ASM_I386__
-
-#include "../qcommon/q_platform.h"
-
-#ifdef __ELF__
-.section .note.GNU-stack,"", at progbits
-#endif
-
-#ifdef __ELF__
-#define C(label) label
-#else
-#define C(label) _##label
-#endif
-
-#endif
diff --git a/engine/code/asm/snapvectora.s b/engine/code/asm/snapvectora.s
deleted file mode 100644
index 11294a0..0000000
--- a/engine/code/asm/snapvectora.s
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-//
-// Sys_SnapVector NASM code (Andrew Henderson)
-// See win32/win_shared.c for the Win32 equivalent
-// This code is provided to ensure that the
-// rounding behavior (and, if necessary, the
-// precision) of DLL and QVM code are identical
-// e.g. for network-visible operations.
-// See ftol.nasm for operations on a single float,
-// as used in compiled VM and DLL code that does
-// not use this system trap.
-//
-
-// 23/09/05 Ported to gas by intel2gas, best supporting actor Tim Angus
-// <tim at ngus.net>
-
-#include "qasm.h"
-
-#if id386
-.data
-
-fpucw: .long 0
-cw037F: .long 0x037F
-
-.text
-
-// void Sys_SnapVector( float *v )
-.globl C(Sys_SnapVector)
-C(Sys_SnapVector):
- pushl %eax
- pushl %ebp
- movl %esp,%ebp
-
- fnstcw fpucw
- movl 12(%ebp),%eax
- fldcw cw037F
- flds (%eax)
- fistpl (%eax)
- fildl (%eax)
- fstps (%eax)
- flds 4(%eax)
- fistpl 4(%eax)
- fildl 4(%eax)
- fstps 4(%eax)
- flds 8(%eax)
- fistpl 8(%eax)
- fildl 8(%eax)
- fstps 8(%eax)
- fldcw fpucw
-
- popl %ebp
- popl %eax
- ret
-
-// void Sys_SnapVectorCW( float *v, unsigned short int cw )
-.globl C(Sys_SnapVectorCW)
-C(Sys_SnapVectorCW):
- pushl %eax
- pushl %ebp
- movl %esp,%ebp
-
- fnstcw fpucw
- movl 12(%ebp),%eax
- fldcw 16(%ebp)
- flds (%eax)
- fistpl (%eax)
- fildl (%eax)
- fstps (%eax)
- flds 4(%eax)
- fistpl 4(%eax)
- fildl 4(%eax)
- fstps 4(%eax)
- flds 8(%eax)
- fistpl 8(%eax)
- fildl 8(%eax)
- fstps 8(%eax)
- fldcw fpucw
-
- popl %ebp
- popl %eax
- ret
-#endif
diff --git a/engine/code/asm/snd_mixa.s b/engine/code/asm/snd_mixa.s
deleted file mode 100644
index 4c6be5b..0000000
--- a/engine/code/asm/snd_mixa.s
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// snd_mixa.s
-// x86 assembly-language sound code
-//
-
-#include "qasm.h"
-
-#if id386
-
- .text
-
-#if 0
-//----------------------------------------------------------------------
-// 8-bit sound-mixing code
-//----------------------------------------------------------------------
-
-#define ch 4+16
-#define sc 8+16
-#define count 12+16
-
-.globl C(S_PaintChannelFrom8)
-C(S_PaintChannelFrom8):
- pushl %esi // preserve register variables
- pushl %edi
- pushl %ebx
- pushl %ebp
-
-// int data;
-// short *lscale, *rscale;
-// unsigned char *sfx;
-// int i;
-
- movl ch(%esp),%ebx
- movl sc(%esp),%esi
-
-// if (ch->leftvol > 255)
-// ch->leftvol = 255;
-// if (ch->rightvol > 255)
-// ch->rightvol = 255;
- movl ch_leftvol(%ebx),%eax
- movl ch_rightvol(%ebx),%edx
- cmpl $255,%eax
- jna LLeftSet
- movl $255,%eax
-LLeftSet:
- cmpl $255,%edx
- jna LRightSet
- movl $255,%edx
-LRightSet:
-
-// lscale = snd_scaletable[ch->leftvol >> 3];
-// rscale = snd_scaletable[ch->rightvol >> 3];
-// sfx = (signed char *)sc->data + ch->pos;
-// ch->pos += count;
- andl $0xF8,%eax
- addl $20,%esi
- movl (%esi),%esi
- andl $0xF8,%edx
- movl ch_pos(%ebx),%edi
- movl count(%esp),%ecx
- addl %edi,%esi
- shll $7,%eax
- addl %ecx,%edi
- shll $7,%edx
- movl %edi,ch_pos(%ebx)
- addl $(C(snd_scaletable)),%eax
- addl $(C(snd_scaletable)),%edx
- subl %ebx,%ebx
- movb -1(%esi,%ecx,1),%bl
-
- testl $1,%ecx
- jz LMix8Loop
-
- movl (%eax,%ebx,4),%edi
- movl (%edx,%ebx,4),%ebp
- addl C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size),%edi
- addl C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size),%ebp
- movl %edi,C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size)
- movl %ebp,C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size)
- movb -2(%esi,%ecx,1),%bl
-
- decl %ecx
- jz LDone
-
-// for (i=0 ; i<count ; i++)
-// {
-LMix8Loop:
-
-// data = sfx[i];
-// paintbuffer[i].left += lscale[data];
-// paintbuffer[i].right += rscale[data];
- movl (%eax,%ebx,4),%edi
- movl (%edx,%ebx,4),%ebp
- addl C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size),%edi
- addl C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size),%ebp
- movb -2(%esi,%ecx,1),%bl
- movl %edi,C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size)
- movl %ebp,C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size)
-
- movl (%eax,%ebx,4),%edi
- movl (%edx,%ebx,4),%ebp
- movb -3(%esi,%ecx,1),%bl
- addl C(paintbuffer)+psp_left-psp_size*2(,%ecx,psp_size),%edi
- addl C(paintbuffer)+psp_right-psp_size*2(,%ecx,psp_size),%ebp
- movl %edi,C(paintbuffer)+psp_left-psp_size*2(,%ecx,psp_size)
- movl %ebp,C(paintbuffer)+psp_right-psp_size*2(,%ecx,psp_size)
-
-// }
- subl $2,%ecx
- jnz LMix8Loop
-
-LDone:
- popl %ebp
- popl %ebx
- popl %edi
- popl %esi
-
- ret
-
-
-#endif
-
-//----------------------------------------------------------------------
-// Transfer of stereo buffer to 16-bit DMA buffer code
-//----------------------------------------------------------------------
-
-.globl C(S_WriteLinearBlastStereo16)
-C(S_WriteLinearBlastStereo16):
- pushl %edi
- pushl %ebx
-
-// int i;
-// int val;
- movl C(snd_linear_count),%ecx
- movl C(snd_p),%ebx
- movl C(snd_out),%edi
-
-// for (i=0 ; i<snd_linear_count ; i+=2)
-// {
-LWLBLoopTop:
-
-// val = (snd_p[i]*snd_vol)>>8;
-// if (val > 0x7fff)
-// snd_out[i] = 0x7fff;
-// else if (val < (short)0x8000)
-// snd_out[i] = (short)0x8000;
-// else
-// snd_out[i] = val;
- movl -8(%ebx,%ecx,4),%eax
- sarl $8,%eax
- cmpl $0x7FFF,%eax
- jg LClampHigh
- cmpl $0xFFFF8000,%eax
- jnl LClampDone
- movl $0xFFFF8000,%eax
- jmp LClampDone
-LClampHigh:
- movl $0x7FFF,%eax
-LClampDone:
-
-// val = (snd_p[i+1]*snd_vol)>>8;
-// if (val > 0x7fff)
-// snd_out[i+1] = 0x7fff;
-// else if (val < (short)0x8000)
-// snd_out[i+1] = (short)0x8000;
-// else
-// snd_out[i+1] = val;
- movl -4(%ebx,%ecx,4),%edx
- sarl $8,%edx
- cmpl $0x7FFF,%edx
- jg LClampHigh2
- cmpl $0xFFFF8000,%edx
- jnl LClampDone2
- movl $0xFFFF8000,%edx
- jmp LClampDone2
-LClampHigh2:
- movl $0x7FFF,%edx
-LClampDone2:
- shll $16,%edx
- andl $0xFFFF,%eax
- orl %eax,%edx
- movl %edx,-4(%edi,%ecx,2)
-
-// }
- subl $2,%ecx
- jnz LWLBLoopTop
-
-// snd_p += snd_linear_count;
-
- popl %ebx
- popl %edi
-
- ret
-
-#endif // id386
-
diff --git a/engine/code/botlib/be_aas_bspq3.c b/engine/code/botlib/be_aas_bspq3.c
deleted file mode 100644
index 9bfc824..0000000
--- a/engine/code/botlib/be_aas_bspq3.c
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_bspq3.c
- *
- * desc: BSP, Environment Sampling
- *
- * $Archive: /MissionPack/code/botlib/be_aas_bspq3.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_aas_def.h"
-
-extern botlib_import_t botimport;
-
-//#define TRACE_DEBUG
-
-#define ON_EPSILON 0.005
-//#define DEG2RAD( a ) (( a * M_PI ) / 180.0F)
-
-#define MAX_BSPENTITIES 2048
-
-typedef struct rgb_s
-{
- int red;
- int green;
- int blue;
-} rgb_t;
-
-//bsp entity epair
-typedef struct bsp_epair_s
-{
- char *key;
- char *value;
- struct bsp_epair_s *next;
-} bsp_epair_t;
-
-//bsp data entity
-typedef struct bsp_entity_s
-{
- bsp_epair_t *epairs;
-} bsp_entity_t;
-
-//id Sofware BSP data
-typedef struct bsp_s
-{
- //true when bsp file is loaded
- int loaded;
- //entity data
- int entdatasize;
- char *dentdata;
- //bsp entities
- int numentities;
- bsp_entity_t entities[MAX_BSPENTITIES];
-} bsp_t;
-
-//global bsp
-bsp_t bspworld;
-
-
-#ifdef BSP_DEBUG
-typedef struct cname_s
-{
- int value;
- char *name;
-} cname_t;
-
-cname_t contentnames[] =
-{
- {CONTENTS_SOLID,"CONTENTS_SOLID"},
- {CONTENTS_WINDOW,"CONTENTS_WINDOW"},
- {CONTENTS_AUX,"CONTENTS_AUX"},
- {CONTENTS_LAVA,"CONTENTS_LAVA"},
- {CONTENTS_SLIME,"CONTENTS_SLIME"},
- {CONTENTS_WATER,"CONTENTS_WATER"},
- {CONTENTS_MIST,"CONTENTS_MIST"},
- {LAST_VISIBLE_CONTENTS,"LAST_VISIBLE_CONTENTS"},
-
- {CONTENTS_AREAPORTAL,"CONTENTS_AREAPORTAL"},
- {CONTENTS_PLAYERCLIP,"CONTENTS_PLAYERCLIP"},
- {CONTENTS_MONSTERCLIP,"CONTENTS_MONSTERCLIP"},
- {CONTENTS_CURRENT_0,"CONTENTS_CURRENT_0"},
- {CONTENTS_CURRENT_90,"CONTENTS_CURRENT_90"},
- {CONTENTS_CURRENT_180,"CONTENTS_CURRENT_180"},
- {CONTENTS_CURRENT_270,"CONTENTS_CURRENT_270"},
- {CONTENTS_CURRENT_UP,"CONTENTS_CURRENT_UP"},
- {CONTENTS_CURRENT_DOWN,"CONTENTS_CURRENT_DOWN"},
- {CONTENTS_ORIGIN,"CONTENTS_ORIGIN"},
- {CONTENTS_MONSTER,"CONTENTS_MONSTER"},
- {CONTENTS_DEADMONSTER,"CONTENTS_DEADMONSTER"},
- {CONTENTS_DETAIL,"CONTENTS_DETAIL"},
- {CONTENTS_TRANSLUCENT,"CONTENTS_TRANSLUCENT"},
- {CONTENTS_LADDER,"CONTENTS_LADDER"},
- {0, 0}
-};
-
-void PrintContents(int contents)
-{
- int i;
-
- for (i = 0; contentnames[i].value; i++)
- {
- if (contents & contentnames[i].value)
- {
- botimport.Print(PRT_MESSAGE, "%s\n", contentnames[i].name);
- } //end if
- } //end for
-} //end of the function PrintContents
-
-#endif // BSP_DEBUG
-//===========================================================================
-// traces axial boxes of any size through the world
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bsp_trace_t AAS_Trace(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask)
-{
- bsp_trace_t bsptrace;
- botimport.Trace(&bsptrace, start, mins, maxs, end, passent, contentmask);
- return bsptrace;
-} //end of the function AAS_Trace
-//===========================================================================
-// returns the contents at the given point
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_PointContents(vec3_t point)
-{
- return botimport.PointContents(point);
-} //end of the function AAS_PointContents
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_EntityCollision(int entnum,
- vec3_t start, vec3_t boxmins, vec3_t boxmaxs, vec3_t end,
- int contentmask, bsp_trace_t *trace)
-{
- bsp_trace_t enttrace;
-
- botimport.EntityTrace(&enttrace, start, boxmins, boxmaxs, end, entnum, contentmask);
- if (enttrace.fraction < trace->fraction)
- {
- Com_Memcpy(trace, &enttrace, sizeof(bsp_trace_t));
- return qtrue;
- } //end if
- return qfalse;
-} //end of the function AAS_EntityCollision
-//===========================================================================
-// returns true if in Potentially Hearable Set
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_inPVS(vec3_t p1, vec3_t p2)
-{
- return botimport.inPVS(p1, p2);
-} //end of the function AAS_InPVS
-//===========================================================================
-// returns true if in Potentially Visible Set
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_inPHS(vec3_t p1, vec3_t p2)
-{
- return qtrue;
-} //end of the function AAS_inPHS
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin)
-{
- botimport.BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);
-} //end of the function AAS_BSPModelMinsMaxs
-//===========================================================================
-// unlinks the entity from all leaves
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_UnlinkFromBSPLeaves(bsp_link_t *leaves)
-{
-} //end of the function AAS_UnlinkFromBSPLeaves
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bsp_link_t *AAS_BSPLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum, int modelnum)
-{
- return NULL;
-} //end of the function AAS_BSPLinkEntity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_BoxEntities(vec3_t absmins, vec3_t absmaxs, int *list, int maxcount)
-{
- return 0;
-} //end of the function AAS_BoxEntities
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_NextBSPEntity(int ent)
-{
- ent++;
- if (ent >= 1 && ent < bspworld.numentities) return ent;
- return 0;
-} //end of the function AAS_NextBSPEntity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_BSPEntityInRange(int ent)
-{
- if (ent <= 0 || ent >= bspworld.numentities)
- {
- botimport.Print(PRT_MESSAGE, "bsp entity out of range\n");
- return qfalse;
- } //end if
- return qtrue;
-} //end of the function AAS_BSPEntityInRange
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size)
-{
- bsp_epair_t *epair;
-
- value[0] = '\0';
- if (!AAS_BSPEntityInRange(ent)) return qfalse;
- for (epair = bspworld.entities[ent].epairs; epair; epair = epair->next)
- {
- if (!strcmp(epair->key, key))
- {
- strncpy(value, epair->value, size-1);
- value[size-1] = '\0';
- return qtrue;
- } //end if
- } //end for
- return qfalse;
-} //end of the function AAS_FindBSPEpair
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v)
-{
- char buf[MAX_EPAIRKEY];
- double v1, v2, v3;
-
- VectorClear(v);
- if (!AAS_ValueForBSPEpairKey(ent, key, buf, MAX_EPAIRKEY)) return qfalse;
- //scanf into doubles, then assign, so it is vec_t size independent
- v1 = v2 = v3 = 0;
- sscanf(buf, "%lf %lf %lf", &v1, &v2, &v3);
- v[0] = v1;
- v[1] = v2;
- v[2] = v3;
- return qtrue;
-} //end of the function AAS_VectorForBSPEpairKey
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_FloatForBSPEpairKey(int ent, char *key, float *value)
-{
- char buf[MAX_EPAIRKEY];
-
- *value = 0;
- if (!AAS_ValueForBSPEpairKey(ent, key, buf, MAX_EPAIRKEY)) return qfalse;
- *value = atof(buf);
- return qtrue;
-} //end of the function AAS_FloatForBSPEpairKey
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_IntForBSPEpairKey(int ent, char *key, int *value)
-{
- char buf[MAX_EPAIRKEY];
-
- *value = 0;
- if (!AAS_ValueForBSPEpairKey(ent, key, buf, MAX_EPAIRKEY)) return qfalse;
- *value = atoi(buf);
- return qtrue;
-} //end of the function AAS_IntForBSPEpairKey
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FreeBSPEntities(void)
-{
- int i;
- bsp_entity_t *ent;
- bsp_epair_t *epair, *nextepair;
-
- for (i = 1; i < bspworld.numentities; i++)
- {
- ent = &bspworld.entities[i];
- for (epair = ent->epairs; epair; epair = nextepair)
- {
- nextepair = epair->next;
- //
- if (epair->key) FreeMemory(epair->key);
- if (epair->value) FreeMemory(epair->value);
- FreeMemory(epair);
- } //end for
- } //end for
- bspworld.numentities = 0;
-} //end of the function AAS_FreeBSPEntities
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ParseBSPEntities(void)
-{
- script_t *script;
- token_t token;
- bsp_entity_t *ent;
- bsp_epair_t *epair;
-
- script = LoadScriptMemory(bspworld.dentdata, bspworld.entdatasize, "entdata");
- SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES|SCFL_NOSTRINGESCAPECHARS);//SCFL_PRIMITIVE);
-
- bspworld.numentities = 1;
-
- while(PS_ReadToken(script, &token))
- {
- if (strcmp(token.string, "{"))
- {
- ScriptError(script, "invalid %s\n", token.string);
- AAS_FreeBSPEntities();
- FreeScript(script);
- return;
- } //end if
- if (bspworld.numentities >= MAX_BSPENTITIES)
- {
- botimport.Print(PRT_MESSAGE, "too many entities in BSP file\n");
- break;
- } //end if
- ent = &bspworld.entities[bspworld.numentities];
- bspworld.numentities++;
- ent->epairs = NULL;
- while(PS_ReadToken(script, &token))
- {
- if (!strcmp(token.string, "}")) break;
- epair = (bsp_epair_t *) GetClearedHunkMemory(sizeof(bsp_epair_t));
- epair->next = ent->epairs;
- ent->epairs = epair;
- if (token.type != TT_STRING)
- {
- ScriptError(script, "invalid %s\n", token.string);
- AAS_FreeBSPEntities();
- FreeScript(script);
- return;
- } //end if
- StripDoubleQuotes(token.string);
- epair->key = (char *) GetHunkMemory(strlen(token.string) + 1);
- strcpy(epair->key, token.string);
- if (!PS_ExpectTokenType(script, TT_STRING, 0, &token))
- {
- AAS_FreeBSPEntities();
- FreeScript(script);
- return;
- } //end if
- StripDoubleQuotes(token.string);
- epair->value = (char *) GetHunkMemory(strlen(token.string) + 1);
- strcpy(epair->value, token.string);
- } //end while
- if (strcmp(token.string, "}"))
- {
- ScriptError(script, "missing }\n");
- AAS_FreeBSPEntities();
- FreeScript(script);
- return;
- } //end if
- } //end while
- FreeScript(script);
-} //end of the function AAS_ParseBSPEntities
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_BSPTraceLight(vec3_t start, vec3_t end, vec3_t endpos, int *red, int *green, int *blue)
-{
- return 0;
-} //end of the function AAS_BSPTraceLight
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_DumpBSPData(void)
-{
- AAS_FreeBSPEntities();
-
- if (bspworld.dentdata) FreeMemory(bspworld.dentdata);
- bspworld.dentdata = NULL;
- bspworld.entdatasize = 0;
- //
- bspworld.loaded = qfalse;
- Com_Memset( &bspworld, 0, sizeof(bspworld) );
-} //end of the function AAS_DumpBSPData
-//===========================================================================
-// load an bsp file
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_LoadBSPFile(void)
-{
- AAS_DumpBSPData();
- bspworld.entdatasize = strlen(botimport.BSPEntityData()) + 1;
- bspworld.dentdata = (char *) GetClearedHunkMemory(bspworld.entdatasize);
- Com_Memcpy(bspworld.dentdata, botimport.BSPEntityData(), bspworld.entdatasize);
- AAS_ParseBSPEntities();
- bspworld.loaded = qtrue;
- return BLERR_NOERROR;
-} //end of the function AAS_LoadBSPFile
diff --git a/engine/code/botlib/be_aas_cluster.c b/engine/code/botlib/be_aas_cluster.c
deleted file mode 100644
index e2b86d5..0000000
--- a/engine/code/botlib/be_aas_cluster.c
+++ /dev/null
@@ -1,1546 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_cluster.c
- *
- * desc: area clustering
- *
- * $Archive: /MissionPack/code/botlib/be_aas_cluster.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "l_log.h"
-#include "l_memory.h"
-#include "l_libvar.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_aas_def.h"
-#include "be_aas_cluster.h"
-
-extern botlib_import_t botimport;
-
-#define AAS_MAX_PORTALS 65536
-#define AAS_MAX_PORTALINDEXSIZE 65536
-#define AAS_MAX_CLUSTERS 65536
-//
-#define MAX_PORTALAREAS 1024
-
-// do not flood through area faces, only use reachabilities
-int nofaceflood = qtrue;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_RemoveClusterAreas(void)
-{
- int i;
-
- for (i = 1; i < aasworld.numareas; i++)
- {
- aasworld.areasettings[i].cluster = 0;
- } //end for
-} //end of the function AAS_RemoveClusterAreas
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ClearCluster(int clusternum)
-{
- int i;
-
- for (i = 1; i < aasworld.numareas; i++)
- {
- if (aasworld.areasettings[i].cluster == clusternum)
- {
- aasworld.areasettings[i].cluster = 0;
- } //end if
- } //end for
-} //end of the function AAS_ClearCluster
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_RemovePortalsClusterReference(int clusternum)
-{
- int portalnum;
-
- for (portalnum = 1; portalnum < aasworld.numportals; portalnum++)
- {
- if (aasworld.portals[portalnum].frontcluster == clusternum)
- {
- aasworld.portals[portalnum].frontcluster = 0;
- } //end if
- if (aasworld.portals[portalnum].backcluster == clusternum)
- {
- aasworld.portals[portalnum].backcluster = 0;
- } //end if
- } //end for
-} //end of the function AAS_RemovePortalsClusterReference
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_UpdatePortal(int areanum, int clusternum)
-{
- int portalnum;
- aas_portal_t *portal;
- aas_cluster_t *cluster;
-
- //find the portal of the area
- for (portalnum = 1; portalnum < aasworld.numportals; portalnum++)
- {
- if (aasworld.portals[portalnum].areanum == areanum) break;
- } //end for
- //
- if (portalnum == aasworld.numportals)
- {
- AAS_Error("no portal of area %d", areanum);
- return qtrue;
- } //end if
- //
- portal = &aasworld.portals[portalnum];
- //if the portal is already fully updated
- if (portal->frontcluster == clusternum) return qtrue;
- if (portal->backcluster == clusternum) return qtrue;
- //if the portal has no front cluster yet
- if (!portal->frontcluster)
- {
- portal->frontcluster = clusternum;
- } //end if
- //if the portal has no back cluster yet
- else if (!portal->backcluster)
- {
- portal->backcluster = clusternum;
- } //end else if
- else
- {
- //remove the cluster portal flag contents
- aasworld.areasettings[areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL;
- Log_Write("portal area %d is seperating more than two clusters\r\n", areanum);
- return qfalse;
- } //end else
- if (aasworld.portalindexsize >= AAS_MAX_PORTALINDEXSIZE)
- {
- AAS_Error("AAS_MAX_PORTALINDEXSIZE");
- return qtrue;
- } //end if
- //set the area cluster number to the negative portal number
- aasworld.areasettings[areanum].cluster = -portalnum;
- //add the portal to the cluster using the portal index
- cluster = &aasworld.clusters[clusternum];
- aasworld.portalindex[cluster->firstportal + cluster->numportals] = portalnum;
- aasworld.portalindexsize++;
- cluster->numportals++;
- return qtrue;
-} //end of the function AAS_UpdatePortal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_FloodClusterAreas_r(int areanum, int clusternum)
-{
- aas_area_t *area;
- aas_face_t *face;
- int facenum, i;
-
- //
- if (areanum <= 0 || areanum >= aasworld.numareas)
- {
- AAS_Error("AAS_FloodClusterAreas_r: areanum out of range");
- return qfalse;
- } //end if
- //if the area is already part of a cluster
- if (aasworld.areasettings[areanum].cluster > 0)
- {
- if (aasworld.areasettings[areanum].cluster == clusternum) return qtrue;
- //
- //there's a reachability going from one cluster to another only in one direction
- //
- AAS_Error("cluster %d touched cluster %d at area %d\r\n",
- clusternum, aasworld.areasettings[areanum].cluster, areanum);
- return qfalse;
- } //end if
- //don't add the cluster portal areas to the clusters
- if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL)
- {
- return AAS_UpdatePortal(areanum, clusternum);
- } //end if
- //set the area cluster number
- aasworld.areasettings[areanum].cluster = clusternum;
- aasworld.areasettings[areanum].clusterareanum =
- aasworld.clusters[clusternum].numareas;
- //the cluster has an extra area
- aasworld.clusters[clusternum].numareas++;
-
- area = &aasworld.areas[areanum];
- //use area faces to flood into adjacent areas
- if (!nofaceflood)
- {
- for (i = 0; i < area->numfaces; i++)
- {
- facenum = abs(aasworld.faceindex[area->firstface + i]);
- face = &aasworld.faces[facenum];
- if (face->frontarea == areanum)
- {
- if (face->backarea) if (!AAS_FloodClusterAreas_r(face->backarea, clusternum)) return qfalse;
- } //end if
- else
- {
- if (face->frontarea) if (!AAS_FloodClusterAreas_r(face->frontarea, clusternum)) return qfalse;
- } //end else
- } //end for
- } //end if
- //use the reachabilities to flood into other areas
- for (i = 0; i < aasworld.areasettings[areanum].numreachableareas; i++)
- {
- if (!aasworld.reachability[
- aasworld.areasettings[areanum].firstreachablearea + i].areanum)
- {
- continue;
- } //end if
- if (!AAS_FloodClusterAreas_r(aasworld.reachability[
- aasworld.areasettings[areanum].firstreachablearea + i].areanum, clusternum)) return qfalse;
- } //end for
- return qtrue;
-} //end of the function AAS_FloodClusterAreas_r
-//===========================================================================
-// try to flood from all areas without cluster into areas with a cluster set
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_FloodClusterAreasUsingReachabilities(int clusternum)
-{
- int i, j, areanum;
-
- for (i = 1; i < aasworld.numareas; i++)
- {
- //if this area already has a cluster set
- if (aasworld.areasettings[i].cluster)
- continue;
- //if this area is a cluster portal
- if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)
- continue;
- //loop over the reachable areas from this area
- for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++)
- {
- //the reachable area
- areanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum;
- //if this area is a cluster portal
- if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL)
- continue;
- //if this area has a cluster set
- if (aasworld.areasettings[areanum].cluster)
- {
- if (!AAS_FloodClusterAreas_r(i, clusternum))
- return qfalse;
- i = 0;
- break;
- } //end if
- } //end for
- } //end for
- return qtrue;
-} //end of the function AAS_FloodClusterAreasUsingReachabilities
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_NumberClusterPortals(int clusternum)
-{
- int i, portalnum;
- aas_cluster_t *cluster;
- aas_portal_t *portal;
-
- cluster = &aasworld.clusters[clusternum];
- for (i = 0; i < cluster->numportals; i++)
- {
- portalnum = aasworld.portalindex[cluster->firstportal + i];
- portal = &aasworld.portals[portalnum];
- if (portal->frontcluster == clusternum)
- {
- portal->clusterareanum[0] = cluster->numareas++;
- } //end if
- else
- {
- portal->clusterareanum[1] = cluster->numareas++;
- } //end else
- } //end for
-} //end of the function AAS_NumberClusterPortals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_NumberClusterAreas(int clusternum)
-{
- int i, portalnum;
- aas_cluster_t *cluster;
- aas_portal_t *portal;
-
- aasworld.clusters[clusternum].numareas = 0;
- aasworld.clusters[clusternum].numreachabilityareas = 0;
- //number all areas in this cluster WITH reachabilities
- for (i = 1; i < aasworld.numareas; i++)
- {
- //
- if (aasworld.areasettings[i].cluster != clusternum) continue;
- //
- if (!AAS_AreaReachability(i)) continue;
- //
- aasworld.areasettings[i].clusterareanum = aasworld.clusters[clusternum].numareas;
- //the cluster has an extra area
- aasworld.clusters[clusternum].numareas++;
- aasworld.clusters[clusternum].numreachabilityareas++;
- } //end for
- //number all portals in this cluster WITH reachabilities
- cluster = &aasworld.clusters[clusternum];
- for (i = 0; i < cluster->numportals; i++)
- {
- portalnum = aasworld.portalindex[cluster->firstportal + i];
- portal = &aasworld.portals[portalnum];
- if (!AAS_AreaReachability(portal->areanum)) continue;
- if (portal->frontcluster == clusternum)
- {
- portal->clusterareanum[0] = cluster->numareas++;
- aasworld.clusters[clusternum].numreachabilityareas++;
- } //end if
- else
- {
- portal->clusterareanum[1] = cluster->numareas++;
- aasworld.clusters[clusternum].numreachabilityareas++;
- } //end else
- } //end for
- //number all areas in this cluster WITHOUT reachabilities
- for (i = 1; i < aasworld.numareas; i++)
- {
- //
- if (aasworld.areasettings[i].cluster != clusternum) continue;
- //
- if (AAS_AreaReachability(i)) continue;
- //
- aasworld.areasettings[i].clusterareanum = aasworld.clusters[clusternum].numareas;
- //the cluster has an extra area
- aasworld.clusters[clusternum].numareas++;
- } //end for
- //number all portals in this cluster WITHOUT reachabilities
- cluster = &aasworld.clusters[clusternum];
- for (i = 0; i < cluster->numportals; i++)
- {
- portalnum = aasworld.portalindex[cluster->firstportal + i];
- portal = &aasworld.portals[portalnum];
- if (AAS_AreaReachability(portal->areanum)) continue;
- if (portal->frontcluster == clusternum)
- {
- portal->clusterareanum[0] = cluster->numareas++;
- } //end if
- else
- {
- portal->clusterareanum[1] = cluster->numareas++;
- } //end else
- } //end for
-} //end of the function AAS_NumberClusterAreas
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_FindClusters(void)
-{
- int i;
- aas_cluster_t *cluster;
-
- AAS_RemoveClusterAreas();
- //
- for (i = 1; i < aasworld.numareas; i++)
- {
- //if the area is already part of a cluster
- if (aasworld.areasettings[i].cluster)
- continue;
- // if not flooding through faces only use areas that have reachabilities
- if (nofaceflood)
- {
- if (!aasworld.areasettings[i].numreachableareas)
- continue;
- } //end if
- //if the area is a cluster portal
- if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)
- continue;
- if (aasworld.numclusters >= AAS_MAX_CLUSTERS)
- {
- AAS_Error("AAS_MAX_CLUSTERS");
- return qfalse;
- } //end if
- cluster = &aasworld.clusters[aasworld.numclusters];
- cluster->numareas = 0;
- cluster->numreachabilityareas = 0;
- cluster->firstportal = aasworld.portalindexsize;
- cluster->numportals = 0;
- //flood the areas in this cluster
- if (!AAS_FloodClusterAreas_r(i, aasworld.numclusters))
- return qfalse;
- if (!AAS_FloodClusterAreasUsingReachabilities(aasworld.numclusters))
- return qfalse;
- //number the cluster areas
- //AAS_NumberClusterPortals(aasworld.numclusters);
- AAS_NumberClusterAreas(aasworld.numclusters);
- //Log_Write("cluster %d has %d areas\r\n", aasworld.numclusters, cluster->numareas);
- aasworld.numclusters++;
- } //end for
- return qtrue;
-} //end of the function AAS_FindClusters
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_CreatePortals(void)
-{
- int i;
- aas_portal_t *portal;
-
- for (i = 1; i < aasworld.numareas; i++)
- {
- //if the area is a cluster portal
- if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)
- {
- if (aasworld.numportals >= AAS_MAX_PORTALS)
- {
- AAS_Error("AAS_MAX_PORTALS");
- return;
- } //end if
- portal = &aasworld.portals[aasworld.numportals];
- portal->areanum = i;
- portal->frontcluster = 0;
- portal->backcluster = 0;
- aasworld.numportals++;
- } //end if
- } //end for
-} //end of the function AAS_CreatePortals
-/*
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_MapContainsTeleporters(void)
-{
- bsp_entity_t *entities, *ent;
- char *classname;
-
- entities = AAS_ParseBSPEntities();
-
- for (ent = entities; ent; ent = ent->next)
- {
- classname = AAS_ValueForBSPEpairKey(ent, "classname");
- if (classname && !strcmp(classname, "misc_teleporter"))
- {
- AAS_FreeBSPEntities(entities);
- return qtrue;
- } //end if
- } //end for
- return qfalse;
-} //end of the function AAS_MapContainsTeleporters
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_NonConvexFaces(aas_face_t *face1, aas_face_t *face2, int side1, int side2)
-{
- int i, j, edgenum;
- aas_plane_t *plane1, *plane2;
- aas_edge_t *edge;
-
-
- plane1 = &aasworld.planes[face1->planenum ^ side1];
- plane2 = &aasworld.planes[face2->planenum ^ side2];
-
- //check if one of the points of face1 is at the back of the plane of face2
- for (i = 0; i < face1->numedges; i++)
- {
- edgenum = abs(aasworld.edgeindex[face1->firstedge + i]);
- edge = &aasworld.edges[edgenum];
- for (j = 0; j < 2; j++)
- {
- if (DotProduct(plane2->normal, aasworld.vertexes[edge->v[j]]) -
- plane2->dist < -0.01) return qtrue;
- } //end for
- } //end for
- for (i = 0; i < face2->numedges; i++)
- {
- edgenum = abs(aasworld.edgeindex[face2->firstedge + i]);
- edge = &aasworld.edges[edgenum];
- for (j = 0; j < 2; j++)
- {
- if (DotProduct(plane1->normal, aasworld.vertexes[edge->v[j]]) -
- plane1->dist < -0.01) return qtrue;
- } //end for
- } //end for
-
- return qfalse;
-} //end of the function AAS_NonConvexFaces
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_CanMergeAreas(int *areanums, int numareas)
-{
- int i, j, s, face1num, face2num, side1, side2, fn1, fn2;
- aas_face_t *face1, *face2;
- aas_area_t *area1, *area2;
-
- for (i = 0; i < numareas; i++)
- {
- area1 = &aasworld.areas[areanums[i]];
- for (fn1 = 0; fn1 < area1->numfaces; fn1++)
- {
- face1num = abs(aasworld.faceindex[area1->firstface + fn1]);
- face1 = &aasworld.faces[face1num];
- side1 = face1->frontarea != areanums[i];
- //check if the face isn't a shared one with one of the other areas
- for (s = 0; s < numareas; s++)
- {
- if (s == i) continue;
- if (face1->frontarea == s || face1->backarea == s) break;
- } //end for
- //if the face was a shared one
- if (s != numareas) continue;
- //
- for (j = 0; j < numareas; j++)
- {
- if (j == i) continue;
- area2 = &aasworld.areas[areanums[j]];
- for (fn2 = 0; fn2 < area2->numfaces; fn2++)
- {
- face2num = abs(aasworld.faceindex[area2->firstface + fn2]);
- face2 = &aasworld.faces[face2num];
- side2 = face2->frontarea != areanums[j];
- //check if the face isn't a shared one with one of the other areas
- for (s = 0; s < numareas; s++)
- {
- if (s == j) continue;
- if (face2->frontarea == s || face2->backarea == s) break;
- } //end for
- //if the face was a shared one
- if (s != numareas) continue;
- //
- if (AAS_NonConvexFaces(face1, face2, side1, side2)) return qfalse;
- } //end for
- } //end for
- } //end for
- } //end for
- return qtrue;
-} //end of the function AAS_CanMergeAreas
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_NonConvexEdges(aas_edge_t *edge1, aas_edge_t *edge2, int side1, int side2, int planenum)
-{
- int i;
- vec3_t edgevec1, edgevec2, normal1, normal2;
- float dist1, dist2;
- aas_plane_t *plane;
-
- plane = &aasworld.planes[planenum];
- VectorSubtract(aasworld.vertexes[edge1->v[1]], aasworld.vertexes[edge1->v[0]], edgevec1);
- VectorSubtract(aasworld.vertexes[edge2->v[1]], aasworld.vertexes[edge2->v[0]], edgevec2);
- if (side1) VectorInverse(edgevec1);
- if (side2) VectorInverse(edgevec2);
- //
- CrossProduct(edgevec1, plane->normal, normal1);
- dist1 = DotProduct(normal1, aasworld.vertexes[edge1->v[0]]);
- CrossProduct(edgevec2, plane->normal, normal2);
- dist2 = DotProduct(normal2, aasworld.vertexes[edge2->v[0]]);
-
- for (i = 0; i < 2; i++)
- {
- if (DotProduct(aasworld.vertexes[edge1->v[i]], normal2) - dist2 < -0.01) return qfalse;
- } //end for
- for (i = 0; i < 2; i++)
- {
- if (DotProduct(aasworld.vertexes[edge2->v[i]], normal1) - dist1 < -0.01) return qfalse;
- } //end for
- return qtrue;
-} //end of the function AAS_NonConvexEdges
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_CanMergeFaces(int *facenums, int numfaces, int planenum)
-{
- int i, j, s, edgenum1, edgenum2, side1, side2, en1, en2, ens;
- aas_face_t *face1, *face2, *otherface;
- aas_edge_t *edge1, *edge2;
-
- for (i = 0; i < numfaces; i++)
- {
- face1 = &aasworld.faces[facenums[i]];
- for (en1 = 0; en1 < face1->numedges; en1++)
- {
- edgenum1 = aasworld.edgeindex[face1->firstedge + en1];
- side1 = (edgenum1 < 0) ^ (face1->planenum != planenum);
- edgenum1 = abs(edgenum1);
- edge1 = &aasworld.edges[edgenum1];
- //check if the edge is shared with another face
- for (s = 0; s < numfaces; s++)
- {
- if (s == i) continue;
- otherface = &aasworld.faces[facenums[s]];
- for (ens = 0; ens < otherface->numedges; ens++)
- {
- if (edgenum1 == abs(aasworld.edgeindex[otherface->firstedge + ens])) break;
- } //end for
- if (ens != otherface->numedges) break;
- } //end for
- //if the edge was shared
- if (s != numfaces) continue;
- //
- for (j = 0; j < numfaces; j++)
- {
- if (j == i) continue;
- face2 = &aasworld.faces[facenums[j]];
- for (en2 = 0; en2 < face2->numedges; en2++)
- {
- edgenum2 = aasworld.edgeindex[face2->firstedge + en2];
- side2 = (edgenum2 < 0) ^ (face2->planenum != planenum);
- edgenum2 = abs(edgenum2);
- edge2 = &aasworld.edges[edgenum2];
- //check if the edge is shared with another face
- for (s = 0; s < numfaces; s++)
- {
- if (s == i) continue;
- otherface = &aasworld.faces[facenums[s]];
- for (ens = 0; ens < otherface->numedges; ens++)
- {
- if (edgenum2 == abs(aasworld.edgeindex[otherface->firstedge + ens])) break;
- } //end for
- if (ens != otherface->numedges) break;
- } //end for
- //if the edge was shared
- if (s != numfaces) continue;
- //
- if (AAS_NonConvexEdges(edge1, edge2, side1, side2, planenum)) return qfalse;
- } //end for
- } //end for
- } //end for
- } //end for
- return qtrue;
-} //end of the function AAS_CanMergeFaces*/
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ConnectedAreas_r(int *areanums, int numareas, int *connectedareas, int curarea)
-{
- int i, j, otherareanum, facenum;
- aas_area_t *area;
- aas_face_t *face;
-
- connectedareas[curarea] = qtrue;
- area = &aasworld.areas[areanums[curarea]];
- for (i = 0; i < area->numfaces; i++)
- {
- facenum = abs(aasworld.faceindex[area->firstface + i]);
- face = &aasworld.faces[facenum];
- //if the face is solid
- if (face->faceflags & FACE_SOLID) continue;
- //get the area at the other side of the face
- if (face->frontarea != areanums[curarea]) otherareanum = face->frontarea;
- else otherareanum = face->backarea;
- //check if the face is leading to one of the other areas
- for (j = 0; j < numareas; j++)
- {
- if (areanums[j] == otherareanum) break;
- } //end for
- //if the face isn't leading to one of the other areas
- if (j == numareas) continue;
- //if the other area is already connected
- if (connectedareas[j]) continue;
- //recursively proceed with the other area
- AAS_ConnectedAreas_r(areanums, numareas, connectedareas, j);
- } //end for
-} //end of the function AAS_ConnectedAreas_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_ConnectedAreas(int *areanums, int numareas)
-{
- int connectedareas[MAX_PORTALAREAS], i;
-
- Com_Memset(connectedareas, 0, sizeof(connectedareas));
- if (numareas < 1) return qfalse;
- if (numareas == 1) return qtrue;
- AAS_ConnectedAreas_r(areanums, numareas, connectedareas, 0);
- for (i = 0; i < numareas; i++)
- {
- if (!connectedareas[i]) return qfalse;
- } //end for
- return qtrue;
-} //end of the function AAS_ConnectedAreas
-//===========================================================================
-// gets adjacent areas with less presence types recursively
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_GetAdjacentAreasWithLessPresenceTypes_r(int *areanums, int numareas, int curareanum)
-{
- int i, j, presencetype, otherpresencetype, otherareanum, facenum;
- aas_area_t *area;
- aas_face_t *face;
-
- areanums[numareas++] = curareanum;
- area = &aasworld.areas[curareanum];
- presencetype = aasworld.areasettings[curareanum].presencetype;
- for (i = 0; i < area->numfaces; i++)
- {
- facenum = abs(aasworld.faceindex[area->firstface + i]);
- face = &aasworld.faces[facenum];
- //if the face is solid
- if (face->faceflags & FACE_SOLID) continue;
- //the area at the other side of the face
- if (face->frontarea != curareanum) otherareanum = face->frontarea;
- else otherareanum = face->backarea;
- //
- otherpresencetype = aasworld.areasettings[otherareanum].presencetype;
- //if the other area has less presence types
- if ((presencetype & ~otherpresencetype) &&
- !(otherpresencetype & ~presencetype))
- {
- //check if the other area isn't already in the list
- for (j = 0; j < numareas; j++)
- {
- if (otherareanum == areanums[j]) break;
- } //end for
- //if the other area isn't already in the list
- if (j == numareas)
- {
- if (numareas >= MAX_PORTALAREAS)
- {
- AAS_Error("MAX_PORTALAREAS");
- return numareas;
- } //end if
- numareas = AAS_GetAdjacentAreasWithLessPresenceTypes_r(areanums, numareas, otherareanum);
- } //end if
- } //end if
- } //end for
- return numareas;
-} //end of the function AAS_GetAdjacentAreasWithLessPresenceTypes_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_CheckAreaForPossiblePortals(int areanum)
-{
- int i, j, k, fen, ben, frontedgenum, backedgenum, facenum;
- int areanums[MAX_PORTALAREAS], numareas, otherareanum;
- int numareafrontfaces[MAX_PORTALAREAS], numareabackfaces[MAX_PORTALAREAS];
- int frontfacenums[MAX_PORTALAREAS], backfacenums[MAX_PORTALAREAS];
- int numfrontfaces, numbackfaces;
- int frontareanums[MAX_PORTALAREAS], backareanums[MAX_PORTALAREAS];
- int numfrontareas, numbackareas;
- int frontplanenum, backplanenum, faceplanenum;
- aas_area_t *area;
- aas_face_t *frontface, *backface, *face;
-
- //if it isn't already a portal
- if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) return 0;
- //it must be a grounded area
- if (!(aasworld.areasettings[areanum].areaflags & AREA_GROUNDED)) return 0;
- //
- Com_Memset(numareafrontfaces, 0, sizeof(numareafrontfaces));
- Com_Memset(numareabackfaces, 0, sizeof(numareabackfaces));
- numareas = numfrontfaces = numbackfaces = 0;
- numfrontareas = numbackareas = 0;
- frontplanenum = backplanenum = -1;
- //add any adjacent areas with less presence types
- numareas = AAS_GetAdjacentAreasWithLessPresenceTypes_r(areanums, 0, areanum);
- //
- for (i = 0; i < numareas; i++)
- {
- area = &aasworld.areas[areanums[i]];
- for (j = 0; j < area->numfaces; j++)
- {
- facenum = abs(aasworld.faceindex[area->firstface + j]);
- face = &aasworld.faces[facenum];
- //if the face is solid
- if (face->faceflags & FACE_SOLID) continue;
- //check if the face is shared with one of the other areas
- for (k = 0; k < numareas; k++)
- {
- if (k == i) continue;
- if (face->frontarea == areanums[k] || face->backarea == areanums[k]) break;
- } //end for
- //if the face is shared
- if (k != numareas) continue;
- //the number of the area at the other side of the face
- if (face->frontarea == areanums[i]) otherareanum = face->backarea;
- else otherareanum = face->frontarea;
- //if the other area already is a cluter portal
- if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) return 0;
- //number of the plane of the area
- faceplanenum = face->planenum & ~1;
- //
- if (frontplanenum < 0 || faceplanenum == frontplanenum)
- {
- frontplanenum = faceplanenum;
- frontfacenums[numfrontfaces++] = facenum;
- for (k = 0; k < numfrontareas; k++)
- {
- if (frontareanums[k] == otherareanum) break;
- } //end for
- if (k == numfrontareas) frontareanums[numfrontareas++] = otherareanum;
- numareafrontfaces[i]++;
- } //end if
- else if (backplanenum < 0 || faceplanenum == backplanenum)
- {
- backplanenum = faceplanenum;
- backfacenums[numbackfaces++] = facenum;
- for (k = 0; k < numbackareas; k++)
- {
- if (backareanums[k] == otherareanum) break;
- } //end for
- if (k == numbackareas) backareanums[numbackareas++] = otherareanum;
- numareabackfaces[i]++;
- } //end else
- else
- {
- return 0;
- } //end else
- } //end for
- } //end for
- //every area should have at least one front face and one back face
- for (i = 0; i < numareas; i++)
- {
- if (!numareafrontfaces[i] || !numareabackfaces[i]) return 0;
- } //end for
- //the front areas should all be connected
- if (!AAS_ConnectedAreas(frontareanums, numfrontareas)) return 0;
- //the back areas should all be connected
- if (!AAS_ConnectedAreas(backareanums, numbackareas)) return 0;
- //none of the front faces should have a shared edge with a back face
- for (i = 0; i < numfrontfaces; i++)
- {
- frontface = &aasworld.faces[frontfacenums[i]];
- for (fen = 0; fen < frontface->numedges; fen++)
- {
- frontedgenum = abs(aasworld.edgeindex[frontface->firstedge + fen]);
- for (j = 0; j < numbackfaces; j++)
- {
- backface = &aasworld.faces[backfacenums[j]];
- for (ben = 0; ben < backface->numedges; ben++)
- {
- backedgenum = abs(aasworld.edgeindex[backface->firstedge + ben]);
- if (frontedgenum == backedgenum) break;
- } //end for
- if (ben != backface->numedges) break;
- } //end for
- if (j != numbackfaces) break;
- } //end for
- if (fen != frontface->numedges) break;
- } //end for
- if (i != numfrontfaces) return 0;
- //set the cluster portal contents
- for (i = 0; i < numareas; i++)
- {
- aasworld.areasettings[areanums[i]].contents |= AREACONTENTS_CLUSTERPORTAL;
- //this area can be used as a route portal
- aasworld.areasettings[areanums[i]].contents |= AREACONTENTS_ROUTEPORTAL;
- Log_Write("possible portal: %d\r\n", areanums[i]);
- } //end for
- //
- return numareas;
-} //end of the function AAS_CheckAreaForPossiblePortals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FindPossiblePortals(void)
-{
- int i, numpossibleportals;
-
- numpossibleportals = 0;
- for (i = 1; i < aasworld.numareas; i++)
- {
- numpossibleportals += AAS_CheckAreaForPossiblePortals(i);
- } //end for
- botimport.Print(PRT_MESSAGE, "\r%6d possible portal areas\n", numpossibleportals);
-} //end of the function AAS_FindPossiblePortals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_RemoveAllPortals(void)
-{
- int i;
-
- for (i = 1; i < aasworld.numareas; i++)
- {
- aasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL;
- } //end for
-} //end of the function AAS_RemoveAllPortals
-
-#if 0
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FloodCluster_r(int areanum, int clusternum)
-{
- int i, otherareanum;
- aas_face_t *face;
- aas_area_t *area;
-
- //set cluster mark
- aasworld.areasettings[areanum].cluster = clusternum;
- //if the area is a portal
- //if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) return;
- //
- area = &aasworld.areas[areanum];
- //use area faces to flood into adjacent areas
- for (i = 0; i < area->numfaces; i++)
- {
- face = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])];
- //
- if (face->frontarea != areanum) otherareanum = face->frontarea;
- else otherareanum = face->backarea;
- //if there's no area at the other side
- if (!otherareanum) continue;
- //if the area is a portal
- if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue;
- //if the area is already marked
- if (aasworld.areasettings[otherareanum].cluster) continue;
- //
- AAS_FloodCluster_r(otherareanum, clusternum);
- } //end for
- //use the reachabilities to flood into other areas
- for (i = 0; i < aasworld.areasettings[areanum].numreachableareas; i++)
- {
- otherareanum = aasworld.reachability[
- aasworld.areasettings[areanum].firstreachablearea + i].areanum;
- if (!otherareanum)
- {
- continue;
- AAS_Error("reachability %d has zero area\n", aasworld.areasettings[areanum].firstreachablearea + i);
- } //end if
- //if the area is a portal
- if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue;
- //if the area is already marked
- if (aasworld.areasettings[otherareanum].cluster) continue;
- //
- AAS_FloodCluster_r(otherareanum, clusternum);
- } //end for
-} //end of the function AAS_FloodCluster_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_RemoveTeleporterPortals(void)
-{
- int i, j, areanum;
-
- for (i = 1; i < aasworld.numareas; i++)
- {
- for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++)
- {
- areanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum;
- if (aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].traveltype == TRAVEL_TELEPORT)
- {
- aasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL;
- aasworld.areasettings[areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL;
- break;
- } //end if
- } //end for
- } //end for
-} //end of the function AAS_RemoveTeleporterPortals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FloodClusterReachabilities(int clusternum)
-{
- int i, j, areanum;
-
- for (i = 1; i < aasworld.numareas; i++)
- {
- //if this area already has a cluster set
- if (aasworld.areasettings[i].cluster) continue;
- //if this area is a cluster portal
- if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) continue;
- //loop over the reachable areas from this area
- for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++)
- {
- //the reachable area
- areanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum;
- //if this area is a cluster portal
- if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) continue;
- //if this area has a cluster set
- if (aasworld.areasettings[areanum].cluster == clusternum)
- {
- AAS_FloodCluster_r(i, clusternum);
- i = 0;
- break;
- } //end if
- } //end for
- } //end for
-} //end of the function AAS_FloodClusterReachabilities
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_RemoveNotClusterClosingPortals(void)
-{
- int i, j, k, facenum, otherareanum, nonclosingportals;
- aas_area_t *area;
- aas_face_t *face;
-
- AAS_RemoveTeleporterPortals();
- //
- nonclosingportals = 0;
- for (i = 1; i < aasworld.numareas; i++)
- {
- if (!(aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)) continue;
- //find a non-portal area adjacent to the portal area and flood
- //the cluster from there
- area = &aasworld.areas[i];
- for (j = 0; j < area->numfaces; j++)
- {
- facenum = abs(aasworld.faceindex[area->firstface + j]);
- face = &aasworld.faces[facenum];
- //
- if (face->frontarea != i) otherareanum = face->frontarea;
- else otherareanum = face->backarea;
- //
- if (!otherareanum) continue;
- //
- if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL)
- {
- continue;
- } //end if
- //reset all cluster fields
- AAS_RemoveClusterAreas();
- //
- AAS_FloodCluster_r(otherareanum, 1);
- AAS_FloodClusterReachabilities(1);
- //check if all adjacent non-portal areas have a cluster set
- for (k = 0; k < area->numfaces; k++)
- {
- facenum = abs(aasworld.faceindex[area->firstface + k]);
- face = &aasworld.faces[facenum];
- //
- if (face->frontarea != i) otherareanum = face->frontarea;
- else otherareanum = face->backarea;
- //
- if (!otherareanum) continue;
- //
- if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL)
- {
- continue;
- } //end if
- //
- if (!aasworld.areasettings[otherareanum].cluster) break;
- } //end for
- //if all adjacent non-portal areas have a cluster set then the portal
- //didn't seal a cluster
- if (k >= area->numfaces)
- {
- aasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL;
- nonclosingportals++;
- //recheck all the other portals again
- i = 0;
- break;
- } //end if
- } //end for
- } //end for
- botimport.Print(PRT_MESSAGE, "\r%6d non closing portals removed\n", nonclosingportals);
-} //end of the function AAS_RemoveNotClusterClosingPortals
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-
-void AAS_RemoveNotClusterClosingPortals(void)
-{
- int i, j, facenum, otherareanum, nonclosingportals, numseperatedclusters;
- aas_area_t *area;
- aas_face_t *face;
-
- AAS_RemoveTeleporterPortals();
- //
- nonclosingportals = 0;
- for (i = 1; i < aasworld.numareas; i++)
- {
- if (!(aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)) continue;
- //
- numseperatedclusters = 0;
- //reset all cluster fields
- AAS_RemoveClusterAreas();
- //find a non-portal area adjacent to the portal area and flood
- //the cluster from there
- area = &aasworld.areas[i];
- for (j = 0; j < area->numfaces; j++)
- {
- facenum = abs(aasworld.faceindex[area->firstface + j]);
- face = &aasworld.faces[facenum];
- //
- if (face->frontarea != i) otherareanum = face->frontarea;
- else otherareanum = face->backarea;
- //if not solid at the other side of the face
- if (!otherareanum) continue;
- //don't flood into other portals
- if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue;
- //if the area already has a cluster set
- if (aasworld.areasettings[otherareanum].cluster) continue;
- //another cluster is seperated by this portal
- numseperatedclusters++;
- //flood the cluster
- AAS_FloodCluster_r(otherareanum, numseperatedclusters);
- AAS_FloodClusterReachabilities(numseperatedclusters);
- } //end for
- //use the reachabilities to flood into other areas
- for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++)
- {
- otherareanum = aasworld.reachability[
- aasworld.areasettings[i].firstreachablearea + j].areanum;
- //this should never be qtrue but we check anyway
- if (!otherareanum) continue;
- //don't flood into other portals
- if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue;
- //if the area already has a cluster set
- if (aasworld.areasettings[otherareanum].cluster) continue;
- //another cluster is seperated by this portal
- numseperatedclusters++;
- //flood the cluster
- AAS_FloodCluster_r(otherareanum, numseperatedclusters);
- AAS_FloodClusterReachabilities(numseperatedclusters);
- } //end for
- //a portal must seperate no more and no less than 2 clusters
- if (numseperatedclusters != 2)
- {
- aasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL;
- nonclosingportals++;
- //recheck all the other portals again
- i = 0;
- } //end if
- } //end for
- botimport.Print(PRT_MESSAGE, "\r%6d non closing portals removed\n", nonclosingportals);
-} //end of the function AAS_RemoveNotClusterClosingPortals
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-
-void AAS_AddTeleporterPortals(void)
-{
- int j, area2num, facenum, otherareanum;
- char *target, *targetname, *classname;
- bsp_entity_t *entities, *ent, *dest;
- vec3_t origin, destorigin, mins, maxs, end;
- vec3_t bbmins, bbmaxs;
- aas_area_t *area;
- aas_face_t *face;
- aas_trace_t trace;
- aas_link_t *areas, *link;
-
- entities = AAS_ParseBSPEntities();
-
- for (ent = entities; ent; ent = ent->next)
- {
- classname = AAS_ValueForBSPEpairKey(ent, "classname");
- if (classname && !strcmp(classname, "misc_teleporter"))
- {
- if (!AAS_VectorForBSPEpairKey(ent, "origin", origin))
- {
- botimport.Print(PRT_ERROR, "teleporter (%s) without origin\n", target);
- continue;
- } //end if
- //
- target = AAS_ValueForBSPEpairKey(ent, "target");
- if (!target)
- {
- botimport.Print(PRT_ERROR, "teleporter (%s) without target\n", target);
- continue;
- } //end if
- for (dest = entities; dest; dest = dest->next)
- {
- classname = AAS_ValueForBSPEpairKey(dest, "classname");
- if (classname && !strcmp(classname, "misc_teleporter_dest"))
- {
- targetname = AAS_ValueForBSPEpairKey(dest, "targetname");
- if (targetname && !strcmp(targetname, target))
- {
- break;
- } //end if
- } //end if
- } //end for
- if (!dest)
- {
- botimport.Print(PRT_ERROR, "teleporter without destination (%s)\n", target);
- continue;
- } //end if
- if (!AAS_VectorForBSPEpairKey(dest, "origin", destorigin))
- {
- botimport.Print(PRT_ERROR, "teleporter destination (%s) without origin\n", target);
- continue;
- } //end if
- destorigin[2] += 24; //just for q2e1m2, the dork has put the telepads in the ground
- VectorCopy(destorigin, end);
- end[2] -= 100;
- trace = AAS_TraceClientBBox(destorigin, end, PRESENCE_CROUCH, -1);
- if (trace.startsolid)
- {
- botimport.Print(PRT_ERROR, "teleporter destination (%s) in solid\n", target);
- continue;
- } //end if
- VectorCopy(trace.endpos, destorigin);
- area2num = AAS_PointAreaNum(destorigin);
- //reset all cluster fields
- for (j = 0; j < aasworld.numareas; j++)
- {
- aasworld.areasettings[j].cluster = 0;
- } //end for
- //
- VectorSet(mins, -8, -8, 8);
- VectorSet(maxs, 8, 8, 24);
- //
- AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bbmins, bbmaxs);
- //
- VectorAdd(origin, mins, mins);
- VectorAdd(origin, maxs, maxs);
- //add bounding box size
- VectorSubtract(mins, bbmaxs, mins);
- VectorSubtract(maxs, bbmins, maxs);
- //link an invalid (-1) entity
- areas = AAS_AASLinkEntity(mins, maxs, -1);
- //
- for (link = areas; link; link = link->next_area)
- {
- if (!AAS_AreaGrounded(link->areanum)) continue;
- //add the teleporter portal mark
- aasworld.areasettings[link->areanum].contents |= AREACONTENTS_CLUSTERPORTAL |
- AREACONTENTS_TELEPORTAL;
- } //end for
- //
- for (link = areas; link; link = link->next_area)
- {
- if (!AAS_AreaGrounded(link->areanum)) continue;
- //find a non-portal area adjacent to the portal area and flood
- //the cluster from there
- area = &aasworld.areas[link->areanum];
- for (j = 0; j < area->numfaces; j++)
- {
- facenum = abs(aasworld.faceindex[area->firstface + j]);
- face = &aasworld.faces[facenum];
- //
- if (face->frontarea != link->areanum) otherareanum = face->frontarea;
- else otherareanum = face->backarea;
- //
- if (!otherareanum) continue;
- //
- if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL)
- {
- continue;
- } //end if
- //
- AAS_FloodCluster_r(otherareanum, 1);
- } //end for
- } //end for
- //if the teleport destination IS in the same cluster
- if (aasworld.areasettings[area2num].cluster)
- {
- for (link = areas; link; link = link->next_area)
- {
- if (!AAS_AreaGrounded(link->areanum)) continue;
- //add the teleporter portal mark
- aasworld.areasettings[link->areanum].contents &= ~(AREACONTENTS_CLUSTERPORTAL |
- AREACONTENTS_TELEPORTAL);
- } //end for
- } //end if
- } //end if
- } //end for
- AAS_FreeBSPEntities(entities);
-} //end of the function AAS_AddTeleporterPortals
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_AddTeleporterPortals(void)
-{
- int i, j, areanum;
-
- for (i = 1; i < aasworld.numareas; i++)
- {
- for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++)
- {
- if (aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].traveltype != TRAVEL_TELEPORT) continue;
- areanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum;
- aasworld.areasettings[areanum].contents |= AREACONTENTS_CLUSTERPORTAL;
- } //end for
- } //end for
-} //end of the function AAS_AddTeleporterPortals
-
-#endif
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_TestPortals(void)
-{
- int i;
- aas_portal_t *portal;
-
- for (i = 1; i < aasworld.numportals; i++)
- {
- portal = &aasworld.portals[i];
- if (!portal->frontcluster)
- {
- aasworld.areasettings[portal->areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL;
- Log_Write("portal area %d has no front cluster\r\n", portal->areanum);
- return qfalse;
- } //end if
- if (!portal->backcluster)
- {
- aasworld.areasettings[portal->areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL;
- Log_Write("portal area %d has no back cluster\r\n", portal->areanum);
- return qfalse;
- } //end if
- } //end for
- return qtrue;
-} //end of the function
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_CountForcedClusterPortals(void)
-{
- int num, i;
-
- num = 0;
- for (i = 1; i < aasworld.numareas; i++)
- {
- if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)
- {
- Log_Write("area %d is a forced portal area\r\n", i);
- num++;
- } //end if
- } //end for
- botimport.Print(PRT_MESSAGE, "%6d forced portal areas\n", num);
-} //end of the function AAS_CountForcedClusterPortals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_CreateViewPortals(void)
-{
- int i;
-
- for (i = 1; i < aasworld.numareas; i++)
- {
- if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)
- {
- aasworld.areasettings[i].contents |= AREACONTENTS_VIEWPORTAL;
- } //end if
- } //end for
-} //end of the function AAS_CreateViewPortals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_SetViewPortalsAsClusterPortals(void)
-{
- int i;
-
- for (i = 1; i < aasworld.numareas; i++)
- {
- if (aasworld.areasettings[i].contents & AREACONTENTS_VIEWPORTAL)
- {
- aasworld.areasettings[i].contents |= AREACONTENTS_CLUSTERPORTAL;
- } //end if
- } //end for
-} //end of the function AAS_SetViewPortalsAsClusterPortals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitClustering(void)
-{
- int i, removedPortalAreas;
- int n, total, numreachabilityareas;
-
- if (!aasworld.loaded) return;
- //if there are clusters
- if (aasworld.numclusters >= 1)
- {
-#ifndef BSPC
- //if clustering isn't forced
- if (!((int)LibVarGetValue("forceclustering")) &&
- !((int)LibVarGetValue("forcereachability"))) return;
-#endif
- } //end if
- //set all view portals as cluster portals in case we re-calculate the reachabilities and clusters (with -reach)
- AAS_SetViewPortalsAsClusterPortals();
- //count the number of forced cluster portals
- AAS_CountForcedClusterPortals();
- //remove all area cluster marks
- AAS_RemoveClusterAreas();
- //find possible cluster portals
- AAS_FindPossiblePortals();
- //craete portals to for the bot view
- AAS_CreateViewPortals();
- //remove all portals that are not closing a cluster
- //AAS_RemoveNotClusterClosingPortals();
- //initialize portal memory
- if (aasworld.portals) FreeMemory(aasworld.portals);
- aasworld.portals = (aas_portal_t *) GetClearedMemory(AAS_MAX_PORTALS * sizeof(aas_portal_t));
- //initialize portal index memory
- if (aasworld.portalindex) FreeMemory(aasworld.portalindex);
- aasworld.portalindex = (aas_portalindex_t *) GetClearedMemory(AAS_MAX_PORTALINDEXSIZE * sizeof(aas_portalindex_t));
- //initialize cluster memory
- if (aasworld.clusters) FreeMemory(aasworld.clusters);
- aasworld.clusters = (aas_cluster_t *) GetClearedMemory(AAS_MAX_CLUSTERS * sizeof(aas_cluster_t));
- //
- removedPortalAreas = 0;
- botimport.Print(PRT_MESSAGE, "\r%6d removed portal areas", removedPortalAreas);
- while(1)
- {
- botimport.Print(PRT_MESSAGE, "\r%6d", removedPortalAreas);
- //initialize the number of portals and clusters
- aasworld.numportals = 1; //portal 0 is a dummy
- aasworld.portalindexsize = 0;
- aasworld.numclusters = 1; //cluster 0 is a dummy
- //create the portals from the portal areas
- AAS_CreatePortals();
- //
- removedPortalAreas++;
- //find the clusters
- if (!AAS_FindClusters())
- continue;
- //test the portals
- if (!AAS_TestPortals())
- continue;
- //
- break;
- } //end while
- botimport.Print(PRT_MESSAGE, "\n");
- //the AAS file should be saved
- aasworld.savefile = qtrue;
- //write the portal areas to the log file
- for (i = 1; i < aasworld.numportals; i++)
- {
- Log_Write("portal %d: area %d\r\n", i, aasworld.portals[i].areanum);
- } //end for
- // report cluster info
- botimport.Print(PRT_MESSAGE, "%6d portals created\n", aasworld.numportals);
- botimport.Print(PRT_MESSAGE, "%6d clusters created\n", aasworld.numclusters);
- for (i = 1; i < aasworld.numclusters; i++)
- {
- botimport.Print(PRT_MESSAGE, "cluster %d has %d reachability areas\n", i,
- aasworld.clusters[i].numreachabilityareas);
- } //end for
- // report AAS file efficiency
- numreachabilityareas = 0;
- total = 0;
- for (i = 0; i < aasworld.numclusters; i++) {
- n = aasworld.clusters[i].numreachabilityareas;
- numreachabilityareas += n;
- total += n * n;
- }
- total += numreachabilityareas * aasworld.numportals;
- //
- botimport.Print(PRT_MESSAGE, "%6i total reachability areas\n", numreachabilityareas);
- botimport.Print(PRT_MESSAGE, "%6i AAS memory/CPU usage (the lower the better)\n", total * 3);
-} //end of the function AAS_InitClustering
diff --git a/engine/code/botlib/be_aas_debug.c b/engine/code/botlib/be_aas_debug.c
deleted file mode 100644
index ab44bc0..0000000
--- a/engine/code/botlib/be_aas_debug.c
+++ /dev/null
@@ -1,777 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_debug.c
- *
- * desc: AAS debug code
- *
- * $Archive: /MissionPack/code/botlib/be_aas_debug.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "l_libvar.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_interface.h"
-#include "be_aas_funcs.h"
-#include "be_aas_def.h"
-
-#define MAX_DEBUGLINES 1024
-#define MAX_DEBUGPOLYGONS 8192
-
-int debuglines[MAX_DEBUGLINES];
-int debuglinevisible[MAX_DEBUGLINES];
-int numdebuglines;
-
-static int debugpolygons[MAX_DEBUGPOLYGONS];
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ClearShownPolygons(void)
-{
- int i;
-//*
- for (i = 0; i < MAX_DEBUGPOLYGONS; i++)
- {
- if (debugpolygons[i]) botimport.DebugPolygonDelete(debugpolygons[i]);
- debugpolygons[i] = 0;
- } //end for
-//*/
-/*
- for (i = 0; i < MAX_DEBUGPOLYGONS; i++)
- {
- botimport.DebugPolygonDelete(i);
- debugpolygons[i] = 0;
- } //end for
-*/
-} //end of the function AAS_ClearShownPolygons
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ShowPolygon(int color, int numpoints, vec3_t *points)
-{
- int i;
-
- for (i = 0; i < MAX_DEBUGPOLYGONS; i++)
- {
- if (!debugpolygons[i])
- {
- debugpolygons[i] = botimport.DebugPolygonCreate(color, numpoints, points);
- break;
- } //end if
- } //end for
-} //end of the function AAS_ShowPolygon
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ClearShownDebugLines(void)
-{
- int i;
-
- //make all lines invisible
- for (i = 0; i < MAX_DEBUGLINES; i++)
- {
- if (debuglines[i])
- {
- //botimport.DebugLineShow(debuglines[i], NULL, NULL, LINECOLOR_NONE);
- botimport.DebugLineDelete(debuglines[i]);
- debuglines[i] = 0;
- debuglinevisible[i] = qfalse;
- } //end if
- } //end for
-} //end of the function AAS_ClearShownDebugLines
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_DebugLine(vec3_t start, vec3_t end, int color)
-{
- int line;
-
- for (line = 0; line < MAX_DEBUGLINES; line++)
- {
- if (!debuglines[line])
- {
- debuglines[line] = botimport.DebugLineCreate();
- debuglinevisible[line] = qfalse;
- numdebuglines++;
- } //end if
- if (!debuglinevisible[line])
- {
- botimport.DebugLineShow(debuglines[line], start, end, color);
- debuglinevisible[line] = qtrue;
- return;
- } //end else
- } //end for
-} //end of the function AAS_DebugLine
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_PermanentLine(vec3_t start, vec3_t end, int color)
-{
- int line;
-
- line = botimport.DebugLineCreate();
- botimport.DebugLineShow(line, start, end, color);
-} //end of the function AAS_PermenentLine
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_DrawPermanentCross(vec3_t origin, float size, int color)
-{
- int i, debugline;
- vec3_t start, end;
-
- for (i = 0; i < 3; i++)
- {
- VectorCopy(origin, start);
- start[i] += size;
- VectorCopy(origin, end);
- end[i] -= size;
- AAS_DebugLine(start, end, color);
- debugline = botimport.DebugLineCreate();
- botimport.DebugLineShow(debugline, start, end, color);
- } //end for
-} //end of the function AAS_DrawPermanentCross
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_DrawPlaneCross(vec3_t point, vec3_t normal, float dist, int type, int color)
-{
- int n0, n1, n2, j, line, lines[2];
- vec3_t start1, end1, start2, end2;
-
- //make a cross in the hit plane at the hit point
- VectorCopy(point, start1);
- VectorCopy(point, end1);
- VectorCopy(point, start2);
- VectorCopy(point, end2);
-
- n0 = type % 3;
- n1 = (type + 1) % 3;
- n2 = (type + 2) % 3;
- start1[n1] -= 6;
- start1[n2] -= 6;
- end1[n1] += 6;
- end1[n2] += 6;
- start2[n1] += 6;
- start2[n2] -= 6;
- end2[n1] -= 6;
- end2[n2] += 6;
-
- start1[n0] = (dist - (start1[n1] * normal[n1] +
- start1[n2] * normal[n2])) / normal[n0];
- end1[n0] = (dist - (end1[n1] * normal[n1] +
- end1[n2] * normal[n2])) / normal[n0];
- start2[n0] = (dist - (start2[n1] * normal[n1] +
- start2[n2] * normal[n2])) / normal[n0];
- end2[n0] = (dist - (end2[n1] * normal[n1] +
- end2[n2] * normal[n2])) / normal[n0];
-
- for (j = 0, line = 0; j < 2 && line < MAX_DEBUGLINES; line++)
- {
- if (!debuglines[line])
- {
- debuglines[line] = botimport.DebugLineCreate();
- lines[j++] = debuglines[line];
- debuglinevisible[line] = qtrue;
- numdebuglines++;
- } //end if
- else if (!debuglinevisible[line])
- {
- lines[j++] = debuglines[line];
- debuglinevisible[line] = qtrue;
- } //end else
- } //end for
- botimport.DebugLineShow(lines[0], start1, end1, color);
- botimport.DebugLineShow(lines[1], start2, end2, color);
-} //end of the function AAS_DrawPlaneCross
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ShowBoundingBox(vec3_t origin, vec3_t mins, vec3_t maxs)
-{
- vec3_t bboxcorners[8];
- int lines[3];
- int i, j, line;
-
- //upper corners
- bboxcorners[0][0] = origin[0] + maxs[0];
- bboxcorners[0][1] = origin[1] + maxs[1];
- bboxcorners[0][2] = origin[2] + maxs[2];
- //
- bboxcorners[1][0] = origin[0] + mins[0];
- bboxcorners[1][1] = origin[1] + maxs[1];
- bboxcorners[1][2] = origin[2] + maxs[2];
- //
- bboxcorners[2][0] = origin[0] + mins[0];
- bboxcorners[2][1] = origin[1] + mins[1];
- bboxcorners[2][2] = origin[2] + maxs[2];
- //
- bboxcorners[3][0] = origin[0] + maxs[0];
- bboxcorners[3][1] = origin[1] + mins[1];
- bboxcorners[3][2] = origin[2] + maxs[2];
- //lower corners
- Com_Memcpy(bboxcorners[4], bboxcorners[0], sizeof(vec3_t) * 4);
- for (i = 0; i < 4; i++) bboxcorners[4 + i][2] = origin[2] + mins[2];
- //draw bounding box
- for (i = 0; i < 4; i++)
- {
- for (j = 0, line = 0; j < 3 && line < MAX_DEBUGLINES; line++)
- {
- if (!debuglines[line])
- {
- debuglines[line] = botimport.DebugLineCreate();
- lines[j++] = debuglines[line];
- debuglinevisible[line] = qtrue;
- numdebuglines++;
- } //end if
- else if (!debuglinevisible[line])
- {
- lines[j++] = debuglines[line];
- debuglinevisible[line] = qtrue;
- } //end else
- } //end for
- //top plane
- botimport.DebugLineShow(lines[0], bboxcorners[i],
- bboxcorners[(i+1)&3], LINECOLOR_RED);
- //bottom plane
- botimport.DebugLineShow(lines[1], bboxcorners[4+i],
- bboxcorners[4+((i+1)&3)], LINECOLOR_RED);
- //vertical lines
- botimport.DebugLineShow(lines[2], bboxcorners[i],
- bboxcorners[4+i], LINECOLOR_RED);
- } //end for
-} //end of the function AAS_ShowBoundingBox
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ShowFace(int facenum)
-{
- int i, color, edgenum;
- aas_edge_t *edge;
- aas_face_t *face;
- aas_plane_t *plane;
- vec3_t start, end;
-
- color = LINECOLOR_YELLOW;
- //check if face number is in range
- if (facenum >= aasworld.numfaces)
- {
- botimport.Print(PRT_ERROR, "facenum %d out of range\n", facenum);
- } //end if
- face = &aasworld.faces[facenum];
- //walk through the edges of the face
- for (i = 0; i < face->numedges; i++)
- {
- //edge number
- edgenum = abs(aasworld.edgeindex[face->firstedge + i]);
- //check if edge number is in range
- if (edgenum >= aasworld.numedges)
- {
- botimport.Print(PRT_ERROR, "edgenum %d out of range\n", edgenum);
- } //end if
- edge = &aasworld.edges[edgenum];
- if (color == LINECOLOR_RED) color = LINECOLOR_GREEN;
- else if (color == LINECOLOR_GREEN) color = LINECOLOR_BLUE;
- else if (color == LINECOLOR_BLUE) color = LINECOLOR_YELLOW;
- else color = LINECOLOR_RED;
- AAS_DebugLine(aasworld.vertexes[edge->v[0]],
- aasworld.vertexes[edge->v[1]],
- color);
- } //end for
- plane = &aasworld.planes[face->planenum];
- edgenum = abs(aasworld.edgeindex[face->firstedge]);
- edge = &aasworld.edges[edgenum];
- VectorCopy(aasworld.vertexes[edge->v[0]], start);
- VectorMA(start, 20, plane->normal, end);
- AAS_DebugLine(start, end, LINECOLOR_RED);
-} //end of the function AAS_ShowFace
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ShowFacePolygon(int facenum, int color, int flip)
-{
- int i, edgenum, numpoints;
- vec3_t points[128];
- aas_edge_t *edge;
- aas_face_t *face;
-
- //check if face number is in range
- if (facenum >= aasworld.numfaces)
- {
- botimport.Print(PRT_ERROR, "facenum %d out of range\n", facenum);
- } //end if
- face = &aasworld.faces[facenum];
- //walk through the edges of the face
- numpoints = 0;
- if (flip)
- {
- for (i = face->numedges-1; i >= 0; i--)
- {
- //edge number
- edgenum = aasworld.edgeindex[face->firstedge + i];
- edge = &aasworld.edges[abs(edgenum)];
- VectorCopy(aasworld.vertexes[edge->v[edgenum < 0]], points[numpoints]);
- numpoints++;
- } //end for
- } //end if
- else
- {
- for (i = 0; i < face->numedges; i++)
- {
- //edge number
- edgenum = aasworld.edgeindex[face->firstedge + i];
- edge = &aasworld.edges[abs(edgenum)];
- VectorCopy(aasworld.vertexes[edge->v[edgenum < 0]], points[numpoints]);
- numpoints++;
- } //end for
- } //end else
- AAS_ShowPolygon(color, numpoints, points);
-} //end of the function AAS_ShowFacePolygon
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ShowArea(int areanum, int groundfacesonly)
-{
- int areaedges[MAX_DEBUGLINES];
- int numareaedges, i, j, n, color = 0, line;
- int facenum, edgenum;
- aas_area_t *area;
- aas_face_t *face;
- aas_edge_t *edge;
-
- //
- numareaedges = 0;
- //
- if (areanum < 0 || areanum >= aasworld.numareas)
- {
- botimport.Print(PRT_ERROR, "area %d out of range [0, %d]\n",
- areanum, aasworld.numareas);
- return;
- } //end if
- //pointer to the convex area
- area = &aasworld.areas[areanum];
- //walk through the faces of the area
- for (i = 0; i < area->numfaces; i++)
- {
- facenum = abs(aasworld.faceindex[area->firstface + i]);
- //check if face number is in range
- if (facenum >= aasworld.numfaces)
- {
- botimport.Print(PRT_ERROR, "facenum %d out of range\n", facenum);
- } //end if
- face = &aasworld.faces[facenum];
- //ground faces only
- if (groundfacesonly)
- {
- if (!(face->faceflags & (FACE_GROUND | FACE_LADDER))) continue;
- } //end if
- //walk through the edges of the face
- for (j = 0; j < face->numedges; j++)
- {
- //edge number
- edgenum = abs(aasworld.edgeindex[face->firstedge + j]);
- //check if edge number is in range
- if (edgenum >= aasworld.numedges)
- {
- botimport.Print(PRT_ERROR, "edgenum %d out of range\n", edgenum);
- } //end if
- //check if the edge is stored already
- for (n = 0; n < numareaedges; n++)
- {
- if (areaedges[n] == edgenum) break;
- } //end for
- if (n == numareaedges && numareaedges < MAX_DEBUGLINES)
- {
- areaedges[numareaedges++] = edgenum;
- } //end if
- } //end for
- //AAS_ShowFace(facenum);
- } //end for
- //draw all the edges
- for (n = 0; n < numareaedges; n++)
- {
- for (line = 0; line < MAX_DEBUGLINES; line++)
- {
- if (!debuglines[line])
- {
- debuglines[line] = botimport.DebugLineCreate();
- debuglinevisible[line] = qfalse;
- numdebuglines++;
- } //end if
- if (!debuglinevisible[line])
- {
- break;
- } //end else
- } //end for
- if (line >= MAX_DEBUGLINES) return;
- edge = &aasworld.edges[areaedges[n]];
- if (color == LINECOLOR_RED) color = LINECOLOR_BLUE;
- else if (color == LINECOLOR_BLUE) color = LINECOLOR_GREEN;
- else if (color == LINECOLOR_GREEN) color = LINECOLOR_YELLOW;
- else color = LINECOLOR_RED;
- botimport.DebugLineShow(debuglines[line],
- aasworld.vertexes[edge->v[0]],
- aasworld.vertexes[edge->v[1]],
- color);
- debuglinevisible[line] = qtrue;
- } //end for*/
-} //end of the function AAS_ShowArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ShowAreaPolygons(int areanum, int color, int groundfacesonly)
-{
- int i, facenum;
- aas_area_t *area;
- aas_face_t *face;
-
- //
- if (areanum < 0 || areanum >= aasworld.numareas)
- {
- botimport.Print(PRT_ERROR, "area %d out of range [0, %d]\n",
- areanum, aasworld.numareas);
- return;
- } //end if
- //pointer to the convex area
- area = &aasworld.areas[areanum];
- //walk through the faces of the area
- for (i = 0; i < area->numfaces; i++)
- {
- facenum = abs(aasworld.faceindex[area->firstface + i]);
- //check if face number is in range
- if (facenum >= aasworld.numfaces)
- {
- botimport.Print(PRT_ERROR, "facenum %d out of range\n", facenum);
- } //end if
- face = &aasworld.faces[facenum];
- //ground faces only
- if (groundfacesonly)
- {
- if (!(face->faceflags & (FACE_GROUND | FACE_LADDER))) continue;
- } //end if
- AAS_ShowFacePolygon(facenum, color, face->frontarea != areanum);
- } //end for
-} //end of the function AAS_ShowAreaPolygons
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_DrawCross(vec3_t origin, float size, int color)
-{
- int i;
- vec3_t start, end;
-
- for (i = 0; i < 3; i++)
- {
- VectorCopy(origin, start);
- start[i] += size;
- VectorCopy(origin, end);
- end[i] -= size;
- AAS_DebugLine(start, end, color);
- } //end for
-} //end of the function AAS_DrawCross
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_PrintTravelType(int traveltype)
-{
-#ifdef DEBUG
- char *str;
- //
- switch(traveltype & TRAVELTYPE_MASK)
- {
- case TRAVEL_INVALID: str = "TRAVEL_INVALID"; break;
- case TRAVEL_WALK: str = "TRAVEL_WALK"; break;
- case TRAVEL_CROUCH: str = "TRAVEL_CROUCH"; break;
- case TRAVEL_BARRIERJUMP: str = "TRAVEL_BARRIERJUMP"; break;
- case TRAVEL_JUMP: str = "TRAVEL_JUMP"; break;
- case TRAVEL_LADDER: str = "TRAVEL_LADDER"; break;
- case TRAVEL_WALKOFFLEDGE: str = "TRAVEL_WALKOFFLEDGE"; break;
- case TRAVEL_SWIM: str = "TRAVEL_SWIM"; break;
- case TRAVEL_WATERJUMP: str = "TRAVEL_WATERJUMP"; break;
- case TRAVEL_TELEPORT: str = "TRAVEL_TELEPORT"; break;
- case TRAVEL_ELEVATOR: str = "TRAVEL_ELEVATOR"; break;
- case TRAVEL_ROCKETJUMP: str = "TRAVEL_ROCKETJUMP"; break;
- case TRAVEL_BFGJUMP: str = "TRAVEL_BFGJUMP"; break;
- case TRAVEL_GRAPPLEHOOK: str = "TRAVEL_GRAPPLEHOOK"; break;
- case TRAVEL_JUMPPAD: str = "TRAVEL_JUMPPAD"; break;
- case TRAVEL_FUNCBOB: str = "TRAVEL_FUNCBOB"; break;
- default: str = "UNKNOWN TRAVEL TYPE"; break;
- } //end switch
- botimport.Print(PRT_MESSAGE, "%s", str);
-#endif
-} //end of the function AAS_PrintTravelType
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_DrawArrow(vec3_t start, vec3_t end, int linecolor, int arrowcolor)
-{
- vec3_t dir, cross, p1, p2, up = {0, 0, 1};
- float dot;
-
- VectorSubtract(end, start, dir);
- VectorNormalize(dir);
- dot = DotProduct(dir, up);
- if (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0);
- else CrossProduct(dir, up, cross);
-
- VectorMA(end, -6, dir, p1);
- VectorCopy(p1, p2);
- VectorMA(p1, 6, cross, p1);
- VectorMA(p2, -6, cross, p2);
-
- AAS_DebugLine(start, end, linecolor);
- AAS_DebugLine(p1, end, arrowcolor);
- AAS_DebugLine(p2, end, arrowcolor);
-} //end of the function AAS_DrawArrow
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ShowReachability(aas_reachability_t *reach)
-{
- vec3_t dir, cmdmove, velocity;
- float speed, zvel;
- aas_clientmove_t move;
-
- AAS_ShowAreaPolygons(reach->areanum, 5, qtrue);
- //AAS_ShowArea(reach->areanum, qtrue);
- AAS_DrawArrow(reach->start, reach->end, LINECOLOR_BLUE, LINECOLOR_YELLOW);
- //
- if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP ||
- (reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE)
- {
- AAS_HorizontalVelocityForJump(aassettings.phys_jumpvel, reach->start, reach->end, &speed);
- //
- VectorSubtract(reach->end, reach->start, dir);
- dir[2] = 0;
- VectorNormalize(dir);
- //set the velocity
- VectorScale(dir, speed, velocity);
- //set the command movement
- VectorClear(cmdmove);
- cmdmove[2] = aassettings.phys_jumpvel;
- //
- AAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue,
- velocity, cmdmove, 3, 30, 0.1f,
- SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME|
- SE_ENTERLAVA|SE_HITGROUNDDAMAGE, 0, qtrue);
- //
- if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP)
- {
- AAS_JumpReachRunStart(reach, dir);
- AAS_DrawCross(dir, 4, LINECOLOR_BLUE);
- } //end if
- } //end if
- else if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP)
- {
- zvel = AAS_RocketJumpZVelocity(reach->start);
- AAS_HorizontalVelocityForJump(zvel, reach->start, reach->end, &speed);
- //
- VectorSubtract(reach->end, reach->start, dir);
- dir[2] = 0;
- VectorNormalize(dir);
- //get command movement
- VectorScale(dir, speed, cmdmove);
- VectorSet(velocity, 0, 0, zvel);
- //
- AAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue,
- velocity, cmdmove, 30, 30, 0.1f,
- SE_ENTERWATER|SE_ENTERSLIME|
- SE_ENTERLAVA|SE_HITGROUNDDAMAGE|
- SE_TOUCHJUMPPAD|SE_HITGROUNDAREA, reach->areanum, qtrue);
- } //end else if
- else if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD)
- {
- VectorSet(cmdmove, 0, 0, 0);
- //
- VectorSubtract(reach->end, reach->start, dir);
- dir[2] = 0;
- VectorNormalize(dir);
- //set the velocity
- //NOTE: the edgenum is the horizontal velocity
- VectorScale(dir, reach->edgenum, velocity);
- //NOTE: the facenum is the Z velocity
- velocity[2] = reach->facenum;
- //
- AAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue,
- velocity, cmdmove, 30, 30, 0.1f,
- SE_ENTERWATER|SE_ENTERSLIME|
- SE_ENTERLAVA|SE_HITGROUNDDAMAGE|
- SE_TOUCHJUMPPAD|SE_HITGROUNDAREA, reach->areanum, qtrue);
- } //end else if
-} //end of the function AAS_ShowReachability
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ShowReachableAreas(int areanum)
-{
- aas_areasettings_t *settings;
- static aas_reachability_t reach;
- static int index, lastareanum;
- static float lasttime;
-
- if (areanum != lastareanum)
- {
- index = 0;
- lastareanum = areanum;
- } //end if
- settings = &aasworld.areasettings[areanum];
- //
- if (!settings->numreachableareas) return;
- //
- if (index >= settings->numreachableareas) index = 0;
- //
- if (AAS_Time() - lasttime > 1.5)
- {
- Com_Memcpy(&reach, &aasworld.reachability[settings->firstreachablearea + index], sizeof(aas_reachability_t));
- index++;
- lasttime = AAS_Time();
- AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
- botimport.Print(PRT_MESSAGE, "\n");
- } //end if
- AAS_ShowReachability(&reach);
-} //end of the function ShowReachableAreas
-
-void AAS_FloodAreas_r(int areanum, int cluster, int *done)
-{
- int nextareanum, i, facenum;
- aas_area_t *area;
- aas_face_t *face;
- aas_areasettings_t *settings;
- aas_reachability_t *reach;
-
- AAS_ShowAreaPolygons(areanum, 1, qtrue);
- //pointer to the convex area
- area = &aasworld.areas[areanum];
- settings = &aasworld.areasettings[areanum];
- //walk through the faces of the area
- for (i = 0; i < area->numfaces; i++)
- {
- facenum = abs(aasworld.faceindex[area->firstface + i]);
- face = &aasworld.faces[facenum];
- if (face->frontarea == areanum)
- nextareanum = face->backarea;
- else
- nextareanum = face->frontarea;
- if (!nextareanum)
- continue;
- if (done[nextareanum])
- continue;
- done[nextareanum] = qtrue;
- if (aasworld.areasettings[nextareanum].contents & AREACONTENTS_VIEWPORTAL)
- continue;
- if (AAS_AreaCluster(nextareanum) != cluster)
- continue;
- AAS_FloodAreas_r(nextareanum, cluster, done);
- } //end for
- //
- for (i = 0; i < settings->numreachableareas; i++)
- {
- reach = &aasworld.reachability[settings->firstreachablearea + i];
- nextareanum = reach->areanum;
- if (!nextareanum)
- continue;
- if (done[nextareanum])
- continue;
- done[nextareanum] = qtrue;
- if (aasworld.areasettings[nextareanum].contents & AREACONTENTS_VIEWPORTAL)
- continue;
- if (AAS_AreaCluster(nextareanum) != cluster)
- continue;
- /*
- if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE)
- {
- AAS_DebugLine(reach->start, reach->end, 1);
- }
- */
- AAS_FloodAreas_r(nextareanum, cluster, done);
- }
-}
-
-void AAS_FloodAreas(vec3_t origin)
-{
- int areanum, cluster, *done;
-
- done = (int *) GetClearedMemory(aasworld.numareas * sizeof(int));
- areanum = AAS_PointAreaNum(origin);
- cluster = AAS_AreaCluster(areanum);
- AAS_FloodAreas_r(areanum, cluster, done);
-}
diff --git a/engine/code/botlib/be_aas_entity.c b/engine/code/botlib/be_aas_entity.c
deleted file mode 100644
index 02699bd..0000000
--- a/engine/code/botlib/be_aas_entity.c
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_entity.c
- *
- * desc: AAS entities
- *
- * $Archive: /MissionPack/code/botlib/be_aas_entity.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "l_utils.h"
-#include "l_log.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-#include "be_aas_def.h"
-
-#define MASK_SOLID CONTENTS_PLAYERCLIP
-
-//FIXME: these might change
-enum {
- ET_GENERAL,
- ET_PLAYER,
- ET_ITEM,
- ET_MISSILE,
- ET_MOVER
-};
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_UpdateEntity(int entnum, bot_entitystate_t *state)
-{
- int relink;
- aas_entity_t *ent;
- vec3_t absmins, absmaxs;
-
- if (!aasworld.loaded)
- {
- botimport.Print(PRT_MESSAGE, "AAS_UpdateEntity: not loaded\n");
- return BLERR_NOAASFILE;
- } //end if
-
- ent = &aasworld.entities[entnum];
-
- if (!state) {
- //unlink the entity
- AAS_UnlinkFromAreas(ent->areas);
- //unlink the entity from the BSP leaves
- AAS_UnlinkFromBSPLeaves(ent->leaves);
- //
- ent->areas = NULL;
- //
- ent->leaves = NULL;
- return BLERR_NOERROR;
- }
-
- ent->i.update_time = AAS_Time() - ent->i.ltime;
- ent->i.type = state->type;
- ent->i.flags = state->flags;
- ent->i.ltime = AAS_Time();
- VectorCopy(ent->i.origin, ent->i.lastvisorigin);
- VectorCopy(state->old_origin, ent->i.old_origin);
- ent->i.solid = state->solid;
- ent->i.groundent = state->groundent;
- ent->i.modelindex = state->modelindex;
- ent->i.modelindex2 = state->modelindex2;
- ent->i.frame = state->frame;
- ent->i.event = state->event;
- ent->i.eventParm = state->eventParm;
- ent->i.powerups = state->powerups;
- ent->i.weapon = state->weapon;
- ent->i.legsAnim = state->legsAnim;
- ent->i.torsoAnim = state->torsoAnim;
- //number of the entity
- ent->i.number = entnum;
- //updated so set valid flag
- ent->i.valid = qtrue;
- //link everything the first frame
- if (aasworld.numframes == 1) relink = qtrue;
- else relink = qfalse;
- //
- if (ent->i.solid == SOLID_BSP)
- {
- //if the angles of the model changed
- if (!VectorCompare(state->angles, ent->i.angles))
- {
- VectorCopy(state->angles, ent->i.angles);
- relink = qtrue;
- } //end if
- //get the mins and maxs of the model
- //FIXME: rotate mins and maxs
- AAS_BSPModelMinsMaxsOrigin(ent->i.modelindex, ent->i.angles, ent->i.mins, ent->i.maxs, NULL);
- } //end if
- else if (ent->i.solid == SOLID_BBOX)
- {
- //if the bounding box size changed
- if (!VectorCompare(state->mins, ent->i.mins) ||
- !VectorCompare(state->maxs, ent->i.maxs))
- {
- VectorCopy(state->mins, ent->i.mins);
- VectorCopy(state->maxs, ent->i.maxs);
- relink = qtrue;
- } //end if
- VectorCopy(state->angles, ent->i.angles);
- } //end if
- //if the origin changed
- if (!VectorCompare(state->origin, ent->i.origin))
- {
- VectorCopy(state->origin, ent->i.origin);
- relink = qtrue;
- } //end if
- //if the entity should be relinked
- if (relink)
- {
- //don't link the world model
- if (entnum != ENTITYNUM_WORLD)
- {
- //absolute mins and maxs
- VectorAdd(ent->i.mins, ent->i.origin, absmins);
- VectorAdd(ent->i.maxs, ent->i.origin, absmaxs);
- //unlink the entity
- AAS_UnlinkFromAreas(ent->areas);
- //relink the entity to the AAS areas (use the larges bbox)
- ent->areas = AAS_LinkEntityClientBBox(absmins, absmaxs, entnum, PRESENCE_NORMAL);
- //unlink the entity from the BSP leaves
- AAS_UnlinkFromBSPLeaves(ent->leaves);
- //link the entity to the world BSP tree
- ent->leaves = AAS_BSPLinkEntity(absmins, absmaxs, entnum, 0);
- } //end if
- } //end if
- return BLERR_NOERROR;
-} //end of the function AAS_UpdateEntity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_EntityInfo(int entnum, aas_entityinfo_t *info)
-{
- if (!aasworld.initialized)
- {
- botimport.Print(PRT_FATAL, "AAS_EntityInfo: aasworld not initialized\n");
- Com_Memset(info, 0, sizeof(aas_entityinfo_t));
- return;
- } //end if
-
- if (entnum < 0 || entnum >= aasworld.maxentities)
- {
- botimport.Print(PRT_FATAL, "AAS_EntityInfo: entnum %d out of range\n", entnum);
- Com_Memset(info, 0, sizeof(aas_entityinfo_t));
- return;
- } //end if
-
- Com_Memcpy(info, &aasworld.entities[entnum].i, sizeof(aas_entityinfo_t));
-} //end of the function AAS_EntityInfo
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_EntityOrigin(int entnum, vec3_t origin)
-{
- if (entnum < 0 || entnum >= aasworld.maxentities)
- {
- botimport.Print(PRT_FATAL, "AAS_EntityOrigin: entnum %d out of range\n", entnum);
- VectorClear(origin);
- return;
- } //end if
-
- VectorCopy(aasworld.entities[entnum].i.origin, origin);
-} //end of the function AAS_EntityOrigin
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_EntityModelindex(int entnum)
-{
- if (entnum < 0 || entnum >= aasworld.maxentities)
- {
- botimport.Print(PRT_FATAL, "AAS_EntityModelindex: entnum %d out of range\n", entnum);
- return 0;
- } //end if
- return aasworld.entities[entnum].i.modelindex;
-} //end of the function AAS_EntityModelindex
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_EntityType(int entnum)
-{
- if (!aasworld.initialized) return 0;
-
- if (entnum < 0 || entnum >= aasworld.maxentities)
- {
- botimport.Print(PRT_FATAL, "AAS_EntityType: entnum %d out of range\n", entnum);
- return 0;
- } //end if
- return aasworld.entities[entnum].i.type;
-} //end of the AAS_EntityType
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_EntityModelNum(int entnum)
-{
- if (!aasworld.initialized) return 0;
-
- if (entnum < 0 || entnum >= aasworld.maxentities)
- {
- botimport.Print(PRT_FATAL, "AAS_EntityModelNum: entnum %d out of range\n", entnum);
- return 0;
- } //end if
- return aasworld.entities[entnum].i.modelindex;
-} //end of the function AAS_EntityModelNum
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_OriginOfMoverWithModelNum(int modelnum, vec3_t origin)
-{
- int i;
- aas_entity_t *ent;
-
- for (i = 0; i < aasworld.maxentities; i++)
- {
- ent = &aasworld.entities[i];
- if (ent->i.type == ET_MOVER)
- {
- if (ent->i.modelindex == modelnum)
- {
- VectorCopy(ent->i.origin, origin);
- return qtrue;
- } //end if
- } //end if
- } //end for
- return qfalse;
-} //end of the function AAS_OriginOfMoverWithModelNum
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_EntitySize(int entnum, vec3_t mins, vec3_t maxs)
-{
- aas_entity_t *ent;
-
- if (!aasworld.initialized) return;
-
- if (entnum < 0 || entnum >= aasworld.maxentities)
- {
- botimport.Print(PRT_FATAL, "AAS_EntitySize: entnum %d out of range\n", entnum);
- return;
- } //end if
-
- ent = &aasworld.entities[entnum];
- VectorCopy(ent->i.mins, mins);
- VectorCopy(ent->i.maxs, maxs);
-} //end of the function AAS_EntitySize
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_EntityBSPData(int entnum, bsp_entdata_t *entdata)
-{
- aas_entity_t *ent;
-
- ent = &aasworld.entities[entnum];
- VectorCopy(ent->i.origin, entdata->origin);
- VectorCopy(ent->i.angles, entdata->angles);
- VectorAdd(ent->i.origin, ent->i.mins, entdata->absmins);
- VectorAdd(ent->i.origin, ent->i.maxs, entdata->absmaxs);
- entdata->solid = ent->i.solid;
- entdata->modelnum = ent->i.modelindex - 1;
-} //end of the function AAS_EntityBSPData
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ResetEntityLinks(void)
-{
- int i;
- for (i = 0; i < aasworld.maxentities; i++)
- {
- aasworld.entities[i].areas = NULL;
- aasworld.entities[i].leaves = NULL;
- } //end for
-} //end of the function AAS_ResetEntityLinks
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InvalidateEntities(void)
-{
- int i;
- for (i = 0; i < aasworld.maxentities; i++)
- {
- aasworld.entities[i].i.valid = qfalse;
- aasworld.entities[i].i.number = i;
- } //end for
-} //end of the function AAS_InvalidateEntities
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_UnlinkInvalidEntities(void)
-{
- int i;
- aas_entity_t *ent;
-
- for (i = 0; i < aasworld.maxentities; i++)
- {
- ent = &aasworld.entities[i];
- if (!ent->i.valid)
- {
- AAS_UnlinkFromAreas( ent->areas );
- ent->areas = NULL;
- AAS_UnlinkFromBSPLeaves( ent->leaves );
- ent->leaves = NULL;
- } //end for
- } //end for
-} //end of the function AAS_UnlinkInvalidEntities
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_NearestEntity(vec3_t origin, int modelindex)
-{
- int i, bestentnum;
- float dist, bestdist;
- aas_entity_t *ent;
- vec3_t dir;
-
- bestentnum = 0;
- bestdist = 99999;
- for (i = 0; i < aasworld.maxentities; i++)
- {
- ent = &aasworld.entities[i];
- if (ent->i.modelindex != modelindex) continue;
- VectorSubtract(ent->i.origin, origin, dir);
- if (abs(dir[0]) < 40)
- {
- if (abs(dir[1]) < 40)
- {
- dist = VectorLength(dir);
- if (dist < bestdist)
- {
- bestdist = dist;
- bestentnum = i;
- } //end if
- } //end if
- } //end if
- } //end for
- return bestentnum;
-} //end of the function AAS_NearestEntity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_BestReachableEntityArea(int entnum)
-{
- aas_entity_t *ent;
-
- ent = &aasworld.entities[entnum];
- return AAS_BestReachableLinkArea(ent->areas);
-} //end of the function AAS_BestReachableEntityArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_NextEntity(int entnum)
-{
- if (!aasworld.loaded) return 0;
-
- if (entnum < 0) entnum = -1;
- while(++entnum < aasworld.maxentities)
- {
- if (aasworld.entities[entnum].i.valid) return entnum;
- } //end while
- return 0;
-} //end of the function AAS_NextEntity
diff --git a/engine/code/botlib/be_aas_file.c b/engine/code/botlib/be_aas_file.c
deleted file mode 100644
index 9395b1d..0000000
--- a/engine/code/botlib/be_aas_file.c
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_file.c
- *
- * desc: AAS file loading/writing
- *
- * $Archive: /MissionPack/code/botlib/be_aas_file.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "l_libvar.h"
-#include "l_utils.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-#include "be_aas_def.h"
-
-//#define AASFILEDEBUG
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_SwapAASData(void)
-{
- int i, j;
- //bounding boxes
- for (i = 0; i < aasworld.numbboxes; i++)
- {
- aasworld.bboxes[i].presencetype = LittleLong(aasworld.bboxes[i].presencetype);
- aasworld.bboxes[i].flags = LittleLong(aasworld.bboxes[i].flags);
- for (j = 0; j < 3; j++)
- {
- aasworld.bboxes[i].mins[j] = LittleLong(aasworld.bboxes[i].mins[j]);
- aasworld.bboxes[i].maxs[j] = LittleLong(aasworld.bboxes[i].maxs[j]);
- } //end for
- } //end for
- //vertexes
- for (i = 0; i < aasworld.numvertexes; i++)
- {
- for (j = 0; j < 3; j++)
- aasworld.vertexes[i][j] = LittleFloat(aasworld.vertexes[i][j]);
- } //end for
- //planes
- for (i = 0; i < aasworld.numplanes; i++)
- {
- for (j = 0; j < 3; j++)
- aasworld.planes[i].normal[j] = LittleFloat(aasworld.planes[i].normal[j]);
- aasworld.planes[i].dist = LittleFloat(aasworld.planes[i].dist);
- aasworld.planes[i].type = LittleLong(aasworld.planes[i].type);
- } //end for
- //edges
- for (i = 0; i < aasworld.numedges; i++)
- {
- aasworld.edges[i].v[0] = LittleLong(aasworld.edges[i].v[0]);
- aasworld.edges[i].v[1] = LittleLong(aasworld.edges[i].v[1]);
- } //end for
- //edgeindex
- for (i = 0; i < aasworld.edgeindexsize; i++)
- {
- aasworld.edgeindex[i] = LittleLong(aasworld.edgeindex[i]);
- } //end for
- //faces
- for (i = 0; i < aasworld.numfaces; i++)
- {
- aasworld.faces[i].planenum = LittleLong(aasworld.faces[i].planenum);
- aasworld.faces[i].faceflags = LittleLong(aasworld.faces[i].faceflags);
- aasworld.faces[i].numedges = LittleLong(aasworld.faces[i].numedges);
- aasworld.faces[i].firstedge = LittleLong(aasworld.faces[i].firstedge);
- aasworld.faces[i].frontarea = LittleLong(aasworld.faces[i].frontarea);
- aasworld.faces[i].backarea = LittleLong(aasworld.faces[i].backarea);
- } //end for
- //face index
- for (i = 0; i < aasworld.faceindexsize; i++)
- {
- aasworld.faceindex[i] = LittleLong(aasworld.faceindex[i]);
- } //end for
- //convex areas
- for (i = 0; i < aasworld.numareas; i++)
- {
- aasworld.areas[i].areanum = LittleLong(aasworld.areas[i].areanum);
- aasworld.areas[i].numfaces = LittleLong(aasworld.areas[i].numfaces);
- aasworld.areas[i].firstface = LittleLong(aasworld.areas[i].firstface);
- for (j = 0; j < 3; j++)
- {
- aasworld.areas[i].mins[j] = LittleFloat(aasworld.areas[i].mins[j]);
- aasworld.areas[i].maxs[j] = LittleFloat(aasworld.areas[i].maxs[j]);
- aasworld.areas[i].center[j] = LittleFloat(aasworld.areas[i].center[j]);
- } //end for
- } //end for
- //area settings
- for (i = 0; i < aasworld.numareasettings; i++)
- {
- aasworld.areasettings[i].contents = LittleLong(aasworld.areasettings[i].contents);
- aasworld.areasettings[i].areaflags = LittleLong(aasworld.areasettings[i].areaflags);
- aasworld.areasettings[i].presencetype = LittleLong(aasworld.areasettings[i].presencetype);
- aasworld.areasettings[i].cluster = LittleLong(aasworld.areasettings[i].cluster);
- aasworld.areasettings[i].clusterareanum = LittleLong(aasworld.areasettings[i].clusterareanum);
- aasworld.areasettings[i].numreachableareas = LittleLong(aasworld.areasettings[i].numreachableareas);
- aasworld.areasettings[i].firstreachablearea = LittleLong(aasworld.areasettings[i].firstreachablearea);
- } //end for
- //area reachability
- for (i = 0; i < aasworld.reachabilitysize; i++)
- {
- aasworld.reachability[i].areanum = LittleLong(aasworld.reachability[i].areanum);
- aasworld.reachability[i].facenum = LittleLong(aasworld.reachability[i].facenum);
- aasworld.reachability[i].edgenum = LittleLong(aasworld.reachability[i].edgenum);
- for (j = 0; j < 3; j++)
- {
- aasworld.reachability[i].start[j] = LittleFloat(aasworld.reachability[i].start[j]);
- aasworld.reachability[i].end[j] = LittleFloat(aasworld.reachability[i].end[j]);
- } //end for
- aasworld.reachability[i].traveltype = LittleLong(aasworld.reachability[i].traveltype);
- aasworld.reachability[i].traveltime = LittleShort(aasworld.reachability[i].traveltime);
- } //end for
- //nodes
- for (i = 0; i < aasworld.numnodes; i++)
- {
- aasworld.nodes[i].planenum = LittleLong(aasworld.nodes[i].planenum);
- aasworld.nodes[i].children[0] = LittleLong(aasworld.nodes[i].children[0]);
- aasworld.nodes[i].children[1] = LittleLong(aasworld.nodes[i].children[1]);
- } //end for
- //cluster portals
- for (i = 0; i < aasworld.numportals; i++)
- {
- aasworld.portals[i].areanum = LittleLong(aasworld.portals[i].areanum);
- aasworld.portals[i].frontcluster = LittleLong(aasworld.portals[i].frontcluster);
- aasworld.portals[i].backcluster = LittleLong(aasworld.portals[i].backcluster);
- aasworld.portals[i].clusterareanum[0] = LittleLong(aasworld.portals[i].clusterareanum[0]);
- aasworld.portals[i].clusterareanum[1] = LittleLong(aasworld.portals[i].clusterareanum[1]);
- } //end for
- //cluster portal index
- for (i = 0; i < aasworld.portalindexsize; i++)
- {
- aasworld.portalindex[i] = LittleLong(aasworld.portalindex[i]);
- } //end for
- //cluster
- for (i = 0; i < aasworld.numclusters; i++)
- {
- aasworld.clusters[i].numareas = LittleLong(aasworld.clusters[i].numareas);
- aasworld.clusters[i].numreachabilityareas = LittleLong(aasworld.clusters[i].numreachabilityareas);
- aasworld.clusters[i].numportals = LittleLong(aasworld.clusters[i].numportals);
- aasworld.clusters[i].firstportal = LittleLong(aasworld.clusters[i].firstportal);
- } //end for
-} //end of the function AAS_SwapAASData
-//===========================================================================
-// dump the current loaded aas file
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_DumpAASData(void)
-{
- aasworld.numbboxes = 0;
- if (aasworld.bboxes) FreeMemory(aasworld.bboxes);
- aasworld.bboxes = NULL;
- aasworld.numvertexes = 0;
- if (aasworld.vertexes) FreeMemory(aasworld.vertexes);
- aasworld.vertexes = NULL;
- aasworld.numplanes = 0;
- if (aasworld.planes) FreeMemory(aasworld.planes);
- aasworld.planes = NULL;
- aasworld.numedges = 0;
- if (aasworld.edges) FreeMemory(aasworld.edges);
- aasworld.edges = NULL;
- aasworld.edgeindexsize = 0;
- if (aasworld.edgeindex) FreeMemory(aasworld.edgeindex);
- aasworld.edgeindex = NULL;
- aasworld.numfaces = 0;
- if (aasworld.faces) FreeMemory(aasworld.faces);
- aasworld.faces = NULL;
- aasworld.faceindexsize = 0;
- if (aasworld.faceindex) FreeMemory(aasworld.faceindex);
- aasworld.faceindex = NULL;
- aasworld.numareas = 0;
- if (aasworld.areas) FreeMemory(aasworld.areas);
- aasworld.areas = NULL;
- aasworld.numareasettings = 0;
- if (aasworld.areasettings) FreeMemory(aasworld.areasettings);
- aasworld.areasettings = NULL;
- aasworld.reachabilitysize = 0;
- if (aasworld.reachability) FreeMemory(aasworld.reachability);
- aasworld.reachability = NULL;
- aasworld.numnodes = 0;
- if (aasworld.nodes) FreeMemory(aasworld.nodes);
- aasworld.nodes = NULL;
- aasworld.numportals = 0;
- if (aasworld.portals) FreeMemory(aasworld.portals);
- aasworld.portals = NULL;
- aasworld.numportals = 0;
- if (aasworld.portalindex) FreeMemory(aasworld.portalindex);
- aasworld.portalindex = NULL;
- aasworld.portalindexsize = 0;
- if (aasworld.clusters) FreeMemory(aasworld.clusters);
- aasworld.clusters = NULL;
- aasworld.numclusters = 0;
- //
- aasworld.loaded = qfalse;
- aasworld.initialized = qfalse;
- aasworld.savefile = qfalse;
-} //end of the function AAS_DumpAASData
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef AASFILEDEBUG
-void AAS_FileInfo(void)
-{
- int i, n, optimized;
-
- botimport.Print(PRT_MESSAGE, "version = %d\n", AASVERSION);
- botimport.Print(PRT_MESSAGE, "numvertexes = %d\n", aasworld.numvertexes);
- botimport.Print(PRT_MESSAGE, "numplanes = %d\n", aasworld.numplanes);
- botimport.Print(PRT_MESSAGE, "numedges = %d\n", aasworld.numedges);
- botimport.Print(PRT_MESSAGE, "edgeindexsize = %d\n", aasworld.edgeindexsize);
- botimport.Print(PRT_MESSAGE, "numfaces = %d\n", aasworld.numfaces);
- botimport.Print(PRT_MESSAGE, "faceindexsize = %d\n", aasworld.faceindexsize);
- botimport.Print(PRT_MESSAGE, "numareas = %d\n", aasworld.numareas);
- botimport.Print(PRT_MESSAGE, "numareasettings = %d\n", aasworld.numareasettings);
- botimport.Print(PRT_MESSAGE, "reachabilitysize = %d\n", aasworld.reachabilitysize);
- botimport.Print(PRT_MESSAGE, "numnodes = %d\n", aasworld.numnodes);
- botimport.Print(PRT_MESSAGE, "numportals = %d\n", aasworld.numportals);
- botimport.Print(PRT_MESSAGE, "portalindexsize = %d\n", aasworld.portalindexsize);
- botimport.Print(PRT_MESSAGE, "numclusters = %d\n", aasworld.numclusters);
- //
- for (n = 0, i = 0; i < aasworld.numareasettings; i++)
- {
- if (aasworld.areasettings[i].areaflags & AREA_GROUNDED) n++;
- } //end for
- botimport.Print(PRT_MESSAGE, "num grounded areas = %d\n", n);
- //
- botimport.Print(PRT_MESSAGE, "planes size %d bytes\n", aasworld.numplanes * sizeof(aas_plane_t));
- botimport.Print(PRT_MESSAGE, "areas size %d bytes\n", aasworld.numareas * sizeof(aas_area_t));
- botimport.Print(PRT_MESSAGE, "areasettings size %d bytes\n", aasworld.numareasettings * sizeof(aas_areasettings_t));
- botimport.Print(PRT_MESSAGE, "nodes size %d bytes\n", aasworld.numnodes * sizeof(aas_node_t));
- botimport.Print(PRT_MESSAGE, "reachability size %d bytes\n", aasworld.reachabilitysize * sizeof(aas_reachability_t));
- botimport.Print(PRT_MESSAGE, "portals size %d bytes\n", aasworld.numportals * sizeof(aas_portal_t));
- botimport.Print(PRT_MESSAGE, "clusters size %d bytes\n", aasworld.numclusters * sizeof(aas_cluster_t));
-
- optimized = aasworld.numplanes * sizeof(aas_plane_t) +
- aasworld.numareas * sizeof(aas_area_t) +
- aasworld.numareasettings * sizeof(aas_areasettings_t) +
- aasworld.numnodes * sizeof(aas_node_t) +
- aasworld.reachabilitysize * sizeof(aas_reachability_t) +
- aasworld.numportals * sizeof(aas_portal_t) +
- aasworld.numclusters * sizeof(aas_cluster_t);
- botimport.Print(PRT_MESSAGE, "optimzed size %d KB\n", optimized >> 10);
-} //end of the function AAS_FileInfo
-#endif //AASFILEDEBUG
-//===========================================================================
-// allocate memory and read a lump of a AAS file
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *AAS_LoadAASLump(fileHandle_t fp, int offset, int length, int *lastoffset, int size)
-{
- char *buf;
- //
- if (!length)
- {
- //just alloc a dummy
- return (char *) GetClearedHunkMemory(size+1);
- } //end if
- //seek to the data
- if (offset != *lastoffset)
- {
- botimport.Print(PRT_WARNING, "AAS file not sequentially read\n");
- if (botimport.FS_Seek(fp, offset, FS_SEEK_SET))
- {
- AAS_Error("can't seek to aas lump\n");
- AAS_DumpAASData();
- botimport.FS_FCloseFile(fp);
- return NULL;
- } //end if
- } //end if
- //allocate memory
- buf = (char *) GetClearedHunkMemory(length+1);
- //read the data
- if (length)
- {
- botimport.FS_Read(buf, length, fp );
- *lastoffset += length;
- } //end if
- return buf;
-} //end of the function AAS_LoadAASLump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_DData(unsigned char *data, int size)
-{
- int i;
-
- for (i = 0; i < size; i++)
- {
- data[i] ^= (unsigned char) i * 119;
- } //end for
-} //end of the function AAS_DData
-//===========================================================================
-// load an aas file
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_LoadAASFile(char *filename)
-{
- fileHandle_t fp;
- aas_header_t header;
- int offset, length, lastoffset;
-
- botimport.Print(PRT_MESSAGE, "trying to load %s\n", filename);
- //dump current loaded aas file
- AAS_DumpAASData();
- //open the file
- botimport.FS_FOpenFile( filename, &fp, FS_READ );
- if (!fp)
- {
- AAS_Error("can't open %s\n", filename);
- return BLERR_CANNOTOPENAASFILE;
- } //end if
- //read the header
- botimport.FS_Read(&header, sizeof(aas_header_t), fp );
- lastoffset = sizeof(aas_header_t);
- //check header identification
- header.ident = LittleLong(header.ident);
- if (header.ident != AASID)
- {
- AAS_Error("%s is not an AAS file\n", filename);
- botimport.FS_FCloseFile(fp);
- return BLERR_WRONGAASFILEID;
- } //end if
- //check the version
- header.version = LittleLong(header.version);
- //
- if (header.version != AASVERSION_OLD && header.version != AASVERSION)
- {
- AAS_Error("aas file %s is version %i, not %i\n", filename, header.version, AASVERSION);
- botimport.FS_FCloseFile(fp);
- return BLERR_WRONGAASFILEVERSION;
- } //end if
- //
- if (header.version == AASVERSION)
- {
- AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);
- } //end if
- //
- aasworld.bspchecksum = atoi(LibVarGetString( "sv_mapChecksum"));
- if (LittleLong(header.bspchecksum) != aasworld.bspchecksum)
- {
- AAS_Error("aas file %s is out of date\n", filename);
- botimport.FS_FCloseFile(fp);
- return BLERR_WRONGAASFILEVERSION;
- } //end if
- //load the lumps:
- //bounding boxes
- offset = LittleLong(header.lumps[AASLUMP_BBOXES].fileofs);
- length = LittleLong(header.lumps[AASLUMP_BBOXES].filelen);
- aasworld.bboxes = (aas_bbox_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_bbox_t));
- aasworld.numbboxes = length / sizeof(aas_bbox_t);
- if (aasworld.numbboxes && !aasworld.bboxes) return BLERR_CANNOTREADAASLUMP;
- //vertexes
- offset = LittleLong(header.lumps[AASLUMP_VERTEXES].fileofs);
- length = LittleLong(header.lumps[AASLUMP_VERTEXES].filelen);
- aasworld.vertexes = (aas_vertex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_vertex_t));
- aasworld.numvertexes = length / sizeof(aas_vertex_t);
- if (aasworld.numvertexes && !aasworld.vertexes) return BLERR_CANNOTREADAASLUMP;
- //planes
- offset = LittleLong(header.lumps[AASLUMP_PLANES].fileofs);
- length = LittleLong(header.lumps[AASLUMP_PLANES].filelen);
- aasworld.planes = (aas_plane_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_plane_t));
- aasworld.numplanes = length / sizeof(aas_plane_t);
- if (aasworld.numplanes && !aasworld.planes) return BLERR_CANNOTREADAASLUMP;
- //edges
- offset = LittleLong(header.lumps[AASLUMP_EDGES].fileofs);
- length = LittleLong(header.lumps[AASLUMP_EDGES].filelen);
- aasworld.edges = (aas_edge_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_edge_t));
- aasworld.numedges = length / sizeof(aas_edge_t);
- if (aasworld.numedges && !aasworld.edges) return BLERR_CANNOTREADAASLUMP;
- //edgeindex
- offset = LittleLong(header.lumps[AASLUMP_EDGEINDEX].fileofs);
- length = LittleLong(header.lumps[AASLUMP_EDGEINDEX].filelen);
- aasworld.edgeindex = (aas_edgeindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_edgeindex_t));
- aasworld.edgeindexsize = length / sizeof(aas_edgeindex_t);
- if (aasworld.edgeindexsize && !aasworld.edgeindex) return BLERR_CANNOTREADAASLUMP;
- //faces
- offset = LittleLong(header.lumps[AASLUMP_FACES].fileofs);
- length = LittleLong(header.lumps[AASLUMP_FACES].filelen);
- aasworld.faces = (aas_face_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_face_t));
- aasworld.numfaces = length / sizeof(aas_face_t);
- if (aasworld.numfaces && !aasworld.faces) return BLERR_CANNOTREADAASLUMP;
- //faceindex
- offset = LittleLong(header.lumps[AASLUMP_FACEINDEX].fileofs);
- length = LittleLong(header.lumps[AASLUMP_FACEINDEX].filelen);
- aasworld.faceindex = (aas_faceindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_faceindex_t));
- aasworld.faceindexsize = length / sizeof(aas_faceindex_t);
- if (aasworld.faceindexsize && !aasworld.faceindex) return BLERR_CANNOTREADAASLUMP;
- //convex areas
- offset = LittleLong(header.lumps[AASLUMP_AREAS].fileofs);
- length = LittleLong(header.lumps[AASLUMP_AREAS].filelen);
- aasworld.areas = (aas_area_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_area_t));
- aasworld.numareas = length / sizeof(aas_area_t);
- if (aasworld.numareas && !aasworld.areas) return BLERR_CANNOTREADAASLUMP;
- //area settings
- offset = LittleLong(header.lumps[AASLUMP_AREASETTINGS].fileofs);
- length = LittleLong(header.lumps[AASLUMP_AREASETTINGS].filelen);
- aasworld.areasettings = (aas_areasettings_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_areasettings_t));
- aasworld.numareasettings = length / sizeof(aas_areasettings_t);
- if (aasworld.numareasettings && !aasworld.areasettings) return BLERR_CANNOTREADAASLUMP;
- //reachability list
- offset = LittleLong(header.lumps[AASLUMP_REACHABILITY].fileofs);
- length = LittleLong(header.lumps[AASLUMP_REACHABILITY].filelen);
- aasworld.reachability = (aas_reachability_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_reachability_t));
- aasworld.reachabilitysize = length / sizeof(aas_reachability_t);
- if (aasworld.reachabilitysize && !aasworld.reachability) return BLERR_CANNOTREADAASLUMP;
- //nodes
- offset = LittleLong(header.lumps[AASLUMP_NODES].fileofs);
- length = LittleLong(header.lumps[AASLUMP_NODES].filelen);
- aasworld.nodes = (aas_node_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_node_t));
- aasworld.numnodes = length / sizeof(aas_node_t);
- if (aasworld.numnodes && !aasworld.nodes) return BLERR_CANNOTREADAASLUMP;
- //cluster portals
- offset = LittleLong(header.lumps[AASLUMP_PORTALS].fileofs);
- length = LittleLong(header.lumps[AASLUMP_PORTALS].filelen);
- aasworld.portals = (aas_portal_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_portal_t));
- aasworld.numportals = length / sizeof(aas_portal_t);
- if (aasworld.numportals && !aasworld.portals) return BLERR_CANNOTREADAASLUMP;
- //cluster portal index
- offset = LittleLong(header.lumps[AASLUMP_PORTALINDEX].fileofs);
- length = LittleLong(header.lumps[AASLUMP_PORTALINDEX].filelen);
- aasworld.portalindex = (aas_portalindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_portalindex_t));
- aasworld.portalindexsize = length / sizeof(aas_portalindex_t);
- if (aasworld.portalindexsize && !aasworld.portalindex) return BLERR_CANNOTREADAASLUMP;
- //clusters
- offset = LittleLong(header.lumps[AASLUMP_CLUSTERS].fileofs);
- length = LittleLong(header.lumps[AASLUMP_CLUSTERS].filelen);
- aasworld.clusters = (aas_cluster_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_cluster_t));
- aasworld.numclusters = length / sizeof(aas_cluster_t);
- if (aasworld.numclusters && !aasworld.clusters) return BLERR_CANNOTREADAASLUMP;
- //swap everything
- AAS_SwapAASData();
- //aas file is loaded
- aasworld.loaded = qtrue;
- //close the file
- botimport.FS_FCloseFile(fp);
- //
-#ifdef AASFILEDEBUG
- AAS_FileInfo();
-#endif //AASFILEDEBUG
- //
- return BLERR_NOERROR;
-} //end of the function AAS_LoadAASFile
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-static int AAS_WriteAASLump_offset;
-
-int AAS_WriteAASLump(fileHandle_t fp, aas_header_t *h, int lumpnum, void *data, int length)
-{
- aas_lump_t *lump;
-
- lump = &h->lumps[lumpnum];
-
- lump->fileofs = LittleLong(AAS_WriteAASLump_offset); //LittleLong(ftell(fp));
- lump->filelen = LittleLong(length);
-
- if (length > 0)
- {
- botimport.FS_Write(data, length, fp );
- } //end if
-
- AAS_WriteAASLump_offset += length;
-
- return qtrue;
-} //end of the function AAS_WriteAASLump
-//===========================================================================
-// aas data is useless after writing to file because it is byte swapped
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_WriteAASFile(char *filename)
-{
- aas_header_t header;
- fileHandle_t fp;
-
- botimport.Print(PRT_MESSAGE, "writing %s\n", filename);
- //swap the aas data
- AAS_SwapAASData();
- //initialize the file header
- Com_Memset(&header, 0, sizeof(aas_header_t));
- header.ident = LittleLong(AASID);
- header.version = LittleLong(AASVERSION);
- header.bspchecksum = LittleLong(aasworld.bspchecksum);
- //open a new file
- botimport.FS_FOpenFile( filename, &fp, FS_WRITE );
- if (!fp)
- {
- botimport.Print(PRT_ERROR, "error opening %s\n", filename);
- return qfalse;
- } //end if
- //write the header
- botimport.FS_Write(&header, sizeof(aas_header_t), fp);
- AAS_WriteAASLump_offset = sizeof(aas_header_t);
- //add the data lumps to the file
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_BBOXES, aasworld.bboxes,
- aasworld.numbboxes * sizeof(aas_bbox_t))) return qfalse;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_VERTEXES, aasworld.vertexes,
- aasworld.numvertexes * sizeof(aas_vertex_t))) return qfalse;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_PLANES, aasworld.planes,
- aasworld.numplanes * sizeof(aas_plane_t))) return qfalse;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGES, aasworld.edges,
- aasworld.numedges * sizeof(aas_edge_t))) return qfalse;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGEINDEX, aasworld.edgeindex,
- aasworld.edgeindexsize * sizeof(aas_edgeindex_t))) return qfalse;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACES, aasworld.faces,
- aasworld.numfaces * sizeof(aas_face_t))) return qfalse;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACEINDEX, aasworld.faceindex,
- aasworld.faceindexsize * sizeof(aas_faceindex_t))) return qfalse;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREAS, aasworld.areas,
- aasworld.numareas * sizeof(aas_area_t))) return qfalse;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREASETTINGS, aasworld.areasettings,
- aasworld.numareasettings * sizeof(aas_areasettings_t))) return qfalse;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_REACHABILITY, aasworld.reachability,
- aasworld.reachabilitysize * sizeof(aas_reachability_t))) return qfalse;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_NODES, aasworld.nodes,
- aasworld.numnodes * sizeof(aas_node_t))) return qfalse;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALS, aasworld.portals,
- aasworld.numportals * sizeof(aas_portal_t))) return qfalse;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALINDEX, aasworld.portalindex,
- aasworld.portalindexsize * sizeof(aas_portalindex_t))) return qfalse;
- if (!AAS_WriteAASLump(fp, &header, AASLUMP_CLUSTERS, aasworld.clusters,
- aasworld.numclusters * sizeof(aas_cluster_t))) return qfalse;
- //rewrite the header with the added lumps
- botimport.FS_Seek(fp, 0, FS_SEEK_SET);
- AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);
- botimport.FS_Write(&header, sizeof(aas_header_t), fp);
- //close the file
- botimport.FS_FCloseFile(fp);
- return qtrue;
-} //end of the function AAS_WriteAASFile
diff --git a/engine/code/botlib/be_aas_main.c b/engine/code/botlib/be_aas_main.c
deleted file mode 100644
index 99a183a..0000000
--- a/engine/code/botlib/be_aas_main.c
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_main.c
- *
- * desc: AAS
- *
- * $Archive: /MissionPack/code/botlib/be_aas_main.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_libvar.h"
-#include "l_utils.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "l_log.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-#include "be_aas_def.h"
-
-aas_t aasworld;
-
-libvar_t *saveroutingcache;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void QDECL AAS_Error(char *fmt, ...)
-{
- char str[1024];
- va_list arglist;
-
- va_start(arglist, fmt);
- Q_vsnprintf(str, sizeof(str), fmt, arglist);
- va_end(arglist);
- botimport.Print(PRT_FATAL, "%s", str);
-} //end of the function AAS_Error
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *AAS_StringFromIndex(char *indexname, char *stringindex[], int numindexes, int index)
-{
- if (!aasworld.indexessetup)
- {
- botimport.Print(PRT_ERROR, "%s: index %d not setup\n", indexname, index);
- return "";
- } //end if
- if (index < 0 || index >= numindexes)
- {
- botimport.Print(PRT_ERROR, "%s: index %d out of range\n", indexname, index);
- return "";
- } //end if
- if (!stringindex[index])
- {
- if (index)
- {
- botimport.Print(PRT_ERROR, "%s: reference to unused index %d\n", indexname, index);
- } //end if
- return "";
- } //end if
- return stringindex[index];
-} //end of the function AAS_StringFromIndex
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_IndexFromString(char *indexname, char *stringindex[], int numindexes, char *string)
-{
- int i;
- if (!aasworld.indexessetup)
- {
- botimport.Print(PRT_ERROR, "%s: index not setup \"%s\"\n", indexname, string);
- return 0;
- } //end if
- for (i = 0; i < numindexes; i++)
- {
- if (!stringindex[i]) continue;
- if (!Q_stricmp(stringindex[i], string)) return i;
- } //end for
- return 0;
-} //end of the function AAS_IndexFromString
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *AAS_ModelFromIndex(int index)
-{
- return AAS_StringFromIndex("ModelFromIndex", &aasworld.configstrings[CS_MODELS], MAX_MODELS, index);
-} //end of the function AAS_ModelFromIndex
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_IndexFromModel(char *modelname)
-{
- return AAS_IndexFromString("IndexFromModel", &aasworld.configstrings[CS_MODELS], MAX_MODELS, modelname);
-} //end of the function AAS_IndexFromModel
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_UpdateStringIndexes(int numconfigstrings, char *configstrings[])
-{
- int i;
- //set string pointers and copy the strings
- for (i = 0; i < numconfigstrings; i++)
- {
- if (configstrings[i])
- {
- //if (aasworld.configstrings[i]) FreeMemory(aasworld.configstrings[i]);
- aasworld.configstrings[i] = (char *) GetMemory(strlen(configstrings[i]) + 1);
- strcpy(aasworld.configstrings[i], configstrings[i]);
- } //end if
- } //end for
- aasworld.indexessetup = qtrue;
-} //end of the function AAS_UpdateStringIndexes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_Loaded(void)
-{
- return aasworld.loaded;
-} //end of the function AAS_Loaded
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_Initialized(void)
-{
- return aasworld.initialized;
-} //end of the function AAS_Initialized
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_SetInitialized(void)
-{
- aasworld.initialized = qtrue;
- botimport.Print(PRT_MESSAGE, "AAS initialized.\n");
-#ifdef DEBUG
- //create all the routing cache
- //AAS_CreateAllRoutingCache();
- //
- //AAS_RoutingInfo();
-#endif
-} //end of the function AAS_SetInitialized
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ContinueInit(float time)
-{
- //if no AAS file loaded
- if (!aasworld.loaded) return;
- //if AAS is already initialized
- if (aasworld.initialized) return;
- //calculate reachability, if not finished return
- if (AAS_ContinueInitReachability(time)) return;
- //initialize clustering for the new map
- AAS_InitClustering();
- //if reachability has been calculated and an AAS file should be written
- //or there is a forced data optimization
- if (aasworld.savefile || ((int)LibVarGetValue("forcewrite")))
- {
- //optimize the AAS data
- if ((int)LibVarValue("aasoptimize", "0")) AAS_Optimize();
- //save the AAS file
- if (AAS_WriteAASFile(aasworld.filename))
- {
- botimport.Print(PRT_MESSAGE, "%s written succesfully\n", aasworld.filename);
- } //end if
- else
- {
- botimport.Print(PRT_ERROR, "couldn't write %s\n", aasworld.filename);
- } //end else
- } //end if
- //initialize the routing
- AAS_InitRouting();
- //at this point AAS is initialized
- AAS_SetInitialized();
-} //end of the function AAS_ContinueInit
-//===========================================================================
-// called at the start of every frame
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_StartFrame(float time)
-{
- aasworld.time = time;
- //unlink all entities that were not updated last frame
- AAS_UnlinkInvalidEntities();
- //invalidate the entities
- AAS_InvalidateEntities();
- //initialize AAS
- AAS_ContinueInit(time);
- //
- aasworld.frameroutingupdates = 0;
- //
- if (botDeveloper)
- {
- if (LibVarGetValue("showcacheupdates"))
- {
- AAS_RoutingInfo();
- LibVarSet("showcacheupdates", "0");
- } //end if
- if (LibVarGetValue("showmemoryusage"))
- {
- PrintUsedMemorySize();
- LibVarSet("showmemoryusage", "0");
- } //end if
- if (LibVarGetValue("memorydump"))
- {
- PrintMemoryLabels();
- LibVarSet("memorydump", "0");
- } //end if
- } //end if
- //
- if (saveroutingcache->value)
- {
- AAS_WriteRouteCache();
- LibVarSet("saveroutingcache", "0");
- } //end if
- //
- aasworld.numframes++;
- return BLERR_NOERROR;
-} //end of the function AAS_StartFrame
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float AAS_Time(void)
-{
- return aasworld.time;
-} //end of the function AAS_Time
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj )
-{
- vec3_t pVec, vec;
-
- VectorSubtract( point, vStart, pVec );
- VectorSubtract( vEnd, vStart, vec );
- VectorNormalize( vec );
- // project onto the directional vector for this segment
- VectorMA( vStart, DotProduct( pVec, vec ), vec, vProj );
-} //end of the function AAS_ProjectPointOntoVector
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_LoadFiles(const char *mapname)
-{
- int errnum;
- char aasfile[MAX_PATH];
-// char bspfile[MAX_PATH];
-
- strcpy(aasworld.mapname, mapname);
- //NOTE: first reset the entity links into the AAS areas and BSP leaves
- // the AAS link heap and BSP link heap are reset after respectively the
- // AAS file and BSP file are loaded
- AAS_ResetEntityLinks();
- // load bsp info
- AAS_LoadBSPFile();
-
- //load the aas file
- Com_sprintf(aasfile, MAX_PATH, "maps/%s.aas", mapname);
- errnum = AAS_LoadAASFile(aasfile);
- if (errnum != BLERR_NOERROR)
- return errnum;
-
- botimport.Print(PRT_MESSAGE, "loaded %s\n", aasfile);
- strncpy(aasworld.filename, aasfile, MAX_PATH);
- return BLERR_NOERROR;
-} //end of the function AAS_LoadFiles
-//===========================================================================
-// called everytime a map changes
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_LoadMap(const char *mapname)
-{
- int errnum;
-
- //if no mapname is provided then the string indexes are updated
- if (!mapname)
- {
- return 0;
- } //end if
- //
- aasworld.initialized = qfalse;
- //NOTE: free the routing caches before loading a new map because
- // to free the caches the old number of areas, number of clusters
- // and number of areas in a clusters must be available
- AAS_FreeRoutingCaches();
- //load the map
- errnum = AAS_LoadFiles(mapname);
- if (errnum != BLERR_NOERROR)
- {
- aasworld.loaded = qfalse;
- return errnum;
- } //end if
- //
- AAS_InitSettings();
- //initialize the AAS link heap for the new map
- AAS_InitAASLinkHeap();
- //initialize the AAS linked entities for the new map
- AAS_InitAASLinkedEntities();
- //initialize reachability for the new map
- AAS_InitReachability();
- //initialize the alternative routing
- AAS_InitAlternativeRouting();
- //everything went ok
- return 0;
-} //end of the function AAS_LoadMap
-//===========================================================================
-// called when the library is first loaded
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_Setup(void)
-{
- aasworld.maxclients = (int) LibVarValue("maxclients", "128");
- aasworld.maxentities = (int) LibVarValue("maxentities", "1024");
- // as soon as it's set to 1 the routing cache will be saved
- saveroutingcache = LibVar("saveroutingcache", "0");
- //allocate memory for the entities
- if (aasworld.entities) FreeMemory(aasworld.entities);
- aasworld.entities = (aas_entity_t *) GetClearedHunkMemory(aasworld.maxentities * sizeof(aas_entity_t));
- //invalidate all the entities
- AAS_InvalidateEntities();
- //force some recalculations
- //LibVarSet("forceclustering", "1"); //force clustering calculation
- //LibVarSet("forcereachability", "1"); //force reachability calculation
- aasworld.numframes = 0;
- return BLERR_NOERROR;
-} //end of the function AAS_Setup
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_Shutdown(void)
-{
- AAS_ShutdownAlternativeRouting();
- //
- AAS_DumpBSPData();
- //free routing caches
- AAS_FreeRoutingCaches();
- //free aas link heap
- AAS_FreeAASLinkHeap();
- //free aas linked entities
- AAS_FreeAASLinkedEntities();
- //free the aas data
- AAS_DumpAASData();
- //free the entities
- if (aasworld.entities) FreeMemory(aasworld.entities);
- //clear the aasworld structure
- Com_Memset(&aasworld, 0, sizeof(aas_t));
- //aas has not been initialized
- aasworld.initialized = qfalse;
- //NOTE: as soon as a new .bsp file is loaded the .bsp file memory is
- // freed an reallocated, so there's no need to free that memory here
- //print shutdown
- botimport.Print(PRT_MESSAGE, "AAS shutdown.\n");
-} //end of the function AAS_Shutdown
diff --git a/engine/code/botlib/be_aas_move.c b/engine/code/botlib/be_aas_move.c
deleted file mode 100644
index fded262..0000000
--- a/engine/code/botlib/be_aas_move.c
+++ /dev/null
@@ -1,1101 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_move.c
- *
- * desc: AAS
- *
- * $Archive: /MissionPack/code/botlib/be_aas_move.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "l_libvar.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_aas_def.h"
-
-extern botlib_import_t botimport;
-
-aas_settings_t aassettings;
-
-//#define AAS_MOVE_DEBUG
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_DropToFloor(vec3_t origin, vec3_t mins, vec3_t maxs)
-{
- vec3_t end;
- bsp_trace_t trace;
-
- VectorCopy(origin, end);
- end[2] -= 100;
- trace = AAS_Trace(origin, mins, maxs, end, 0, CONTENTS_SOLID);
- if (trace.startsolid) return qfalse;
- VectorCopy(trace.endpos, origin);
- return qtrue;
-} //end of the function AAS_DropToFloor
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitSettings(void)
-{
- aassettings.phys_gravitydirection[0] = 0;
- aassettings.phys_gravitydirection[1] = 0;
- aassettings.phys_gravitydirection[2] = -1;
- aassettings.phys_friction = LibVarValue("phys_friction", "6");
- aassettings.phys_stopspeed = LibVarValue("phys_stopspeed", "100");
- aassettings.phys_gravity = LibVarValue("phys_gravity", "800");
- aassettings.phys_waterfriction = LibVarValue("phys_waterfriction", "1");
- aassettings.phys_watergravity = LibVarValue("phys_watergravity", "400");
- aassettings.phys_maxvelocity = LibVarValue("phys_maxvelocity", "320");
- aassettings.phys_maxwalkvelocity = LibVarValue("phys_maxwalkvelocity", "320");
- aassettings.phys_maxcrouchvelocity = LibVarValue("phys_maxcrouchvelocity", "100");
- aassettings.phys_maxswimvelocity = LibVarValue("phys_maxswimvelocity", "150");
- aassettings.phys_walkaccelerate = LibVarValue("phys_walkaccelerate", "10");
- aassettings.phys_airaccelerate = LibVarValue("phys_airaccelerate", "1");
- aassettings.phys_swimaccelerate = LibVarValue("phys_swimaccelerate", "4");
- aassettings.phys_maxstep = LibVarValue("phys_maxstep", "19");
- aassettings.phys_maxsteepness = LibVarValue("phys_maxsteepness", "0.7");
- aassettings.phys_maxwaterjump = LibVarValue("phys_maxwaterjump", "18");
- aassettings.phys_maxbarrier = LibVarValue("phys_maxbarrier", "33");
- aassettings.phys_jumpvel = LibVarValue("phys_jumpvel", "270");
- aassettings.phys_falldelta5 = LibVarValue("phys_falldelta5", "40");
- aassettings.phys_falldelta10 = LibVarValue("phys_falldelta10", "60");
- aassettings.rs_waterjump = LibVarValue("rs_waterjump", "400");
- aassettings.rs_teleport = LibVarValue("rs_teleport", "50");
- aassettings.rs_barrierjump = LibVarValue("rs_barrierjump", "100");
- aassettings.rs_startcrouch = LibVarValue("rs_startcrouch", "300");
- aassettings.rs_startgrapple = LibVarValue("rs_startgrapple", "500");
- aassettings.rs_startwalkoffledge = LibVarValue("rs_startwalkoffledge", "70");
- aassettings.rs_startjump = LibVarValue("rs_startjump", "300");
- aassettings.rs_rocketjump = LibVarValue("rs_rocketjump", "500");
- aassettings.rs_bfgjump = LibVarValue("rs_bfgjump", "500");
- aassettings.rs_jumppad = LibVarValue("rs_jumppad", "250");
- aassettings.rs_aircontrolledjumppad = LibVarValue("rs_aircontrolledjumppad", "300");
- aassettings.rs_funcbob = LibVarValue("rs_funcbob", "300");
- aassettings.rs_startelevator = LibVarValue("rs_startelevator", "50");
- aassettings.rs_falldamage5 = LibVarValue("rs_falldamage5", "300");
- aassettings.rs_falldamage10 = LibVarValue("rs_falldamage10", "500");
- aassettings.rs_maxfallheight = LibVarValue("rs_maxfallheight", "0");
- aassettings.rs_maxjumpfallheight = LibVarValue("rs_maxjumpfallheight", "450");
-} //end of the function AAS_InitSettings
-//===========================================================================
-// returns qtrue if the bot is against a ladder
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AgainstLadder(vec3_t origin)
-{
- int areanum, i, facenum, side;
- vec3_t org;
- aas_plane_t *plane;
- aas_face_t *face;
- aas_area_t *area;
-
- VectorCopy(origin, org);
- areanum = AAS_PointAreaNum(org);
- if (!areanum)
- {
- org[0] += 1;
- areanum = AAS_PointAreaNum(org);
- if (!areanum)
- {
- org[1] += 1;
- areanum = AAS_PointAreaNum(org);
- if (!areanum)
- {
- org[0] -= 2;
- areanum = AAS_PointAreaNum(org);
- if (!areanum)
- {
- org[1] -= 2;
- areanum = AAS_PointAreaNum(org);
- } //end if
- } //end if
- } //end if
- } //end if
- //if in solid... wrrr shouldn't happen
- if (!areanum) return qfalse;
- //if not in a ladder area
- if (!(aasworld.areasettings[areanum].areaflags & AREA_LADDER)) return qfalse;
- //if a crouch only area
- if (!(aasworld.areasettings[areanum].presencetype & PRESENCE_NORMAL)) return qfalse;
- //
- area = &aasworld.areas[areanum];
- for (i = 0; i < area->numfaces; i++)
- {
- facenum = aasworld.faceindex[area->firstface + i];
- side = facenum < 0;
- face = &aasworld.faces[abs(facenum)];
- //if the face isn't a ladder face
- if (!(face->faceflags & FACE_LADDER)) continue;
- //get the plane the face is in
- plane = &aasworld.planes[face->planenum ^ side];
- //if the origin is pretty close to the plane
- if (abs(DotProduct(plane->normal, origin) - plane->dist) < 3)
- {
- if (AAS_PointInsideFace(abs(facenum), origin, 0.1f)) return qtrue;
- } //end if
- } //end for
- return qfalse;
-} //end of the function AAS_AgainstLadder
-//===========================================================================
-// returns qtrue if the bot is on the ground
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_OnGround(vec3_t origin, int presencetype, int passent)
-{
- aas_trace_t trace;
- vec3_t end, up = {0, 0, 1};
- aas_plane_t *plane;
-
- VectorCopy(origin, end);
- end[2] -= 10;
-
- trace = AAS_TraceClientBBox(origin, end, presencetype, passent);
-
- //if in solid
- if (trace.startsolid) return qfalse;
- //if nothing hit at all
- if (trace.fraction >= 1.0) return qfalse;
- //if too far from the hit plane
- if (origin[2] - trace.endpos[2] > 10) return qfalse;
- //check if the plane isn't too steep
- plane = AAS_PlaneFromNum(trace.planenum);
- if (DotProduct(plane->normal, up) < aassettings.phys_maxsteepness) return qfalse;
- //the bot is on the ground
- return qtrue;
-} //end of the function AAS_OnGround
-//===========================================================================
-// returns qtrue if a bot at the given position is swimming
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_Swimming(vec3_t origin)
-{
- vec3_t testorg;
-
- VectorCopy(origin, testorg);
- testorg[2] -= 2;
- if (AAS_PointContents(testorg) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) return qtrue;
- return qfalse;
-} //end of the function AAS_Swimming
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-static vec3_t VEC_UP = {0, -1, 0};
-static vec3_t MOVEDIR_UP = {0, 0, 1};
-static vec3_t VEC_DOWN = {0, -2, 0};
-static vec3_t MOVEDIR_DOWN = {0, 0, -1};
-
-void AAS_SetMovedir(vec3_t angles, vec3_t movedir)
-{
- if (VectorCompare(angles, VEC_UP))
- {
- VectorCopy(MOVEDIR_UP, movedir);
- } //end if
- else if (VectorCompare(angles, VEC_DOWN))
- {
- VectorCopy(MOVEDIR_DOWN, movedir);
- } //end else if
- else
- {
- AngleVectors(angles, movedir, NULL, NULL);
- } //end else
-} //end of the function AAS_SetMovedir
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_JumpReachRunStart(aas_reachability_t *reach, vec3_t runstart)
-{
- vec3_t hordir, start, cmdmove;
- aas_clientmove_t move;
-
- //
- hordir[0] = reach->start[0] - reach->end[0];
- hordir[1] = reach->start[1] - reach->end[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //start point
- VectorCopy(reach->start, start);
- start[2] += 1;
- //get command movement
- VectorScale(hordir, 400, cmdmove);
- //
- AAS_PredictClientMovement(&move, -1, start, PRESENCE_NORMAL, qtrue,
- vec3_origin, cmdmove, 1, 2, 0.1f,
- SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA|
- SE_HITGROUNDDAMAGE|SE_GAP, 0, qfalse);
- VectorCopy(move.endpos, runstart);
- //don't enter slime or lava and don't fall from too high
- if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))
- {
- VectorCopy(start, runstart);
- } //end if
-} //end of the function AAS_JumpReachRunStart
-//===========================================================================
-// returns the Z velocity when rocket jumping at the origin
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float AAS_WeaponJumpZVelocity(vec3_t origin, float radiusdamage)
-{
- vec3_t kvel, v, start, end, forward, right, viewangles, dir;
- float mass, knockback, points;
- vec3_t rocketoffset = {8, 8, -8};
- vec3_t botmins = {-16, -16, -24};
- vec3_t botmaxs = {16, 16, 32};
- bsp_trace_t bsptrace;
-
- //look down (90 degrees)
- viewangles[PITCH] = 90;
- viewangles[YAW] = 0;
- viewangles[ROLL] = 0;
- //get the start point shooting from
- VectorCopy(origin, start);
- start[2] += 8; //view offset Z
- AngleVectors(viewangles, forward, right, NULL);
- start[0] += forward[0] * rocketoffset[0] + right[0] * rocketoffset[1];
- start[1] += forward[1] * rocketoffset[0] + right[1] * rocketoffset[1];
- start[2] += forward[2] * rocketoffset[0] + right[2] * rocketoffset[1] + rocketoffset[2];
- //end point of the trace
- VectorMA(start, 500, forward, end);
- //trace a line to get the impact point
- bsptrace = AAS_Trace(start, NULL, NULL, end, 1, CONTENTS_SOLID);
- //calculate the damage the bot will get from the rocket impact
- VectorAdd(botmins, botmaxs, v);
- VectorMA(origin, 0.5, v, v);
- VectorSubtract(bsptrace.endpos, v, v);
- //
- points = radiusdamage - 0.5 * VectorLength(v);
- if (points < 0) points = 0;
- //the owner of the rocket gets half the damage
- points *= 0.5;
- //mass of the bot (p_client.c: PutClientInServer)
- mass = 200;
- //knockback is the same as the damage points
- knockback = points;
- //direction of the damage (from trace.endpos to bot origin)
- VectorSubtract(origin, bsptrace.endpos, dir);
- VectorNormalize(dir);
- //damage velocity
- VectorScale(dir, 1600.0 * (float)knockback / mass, kvel); //the rocket jump hack...
- //rocket impact velocity + jump velocity
- return kvel[2] + aassettings.phys_jumpvel;
-} //end of the function AAS_WeaponJumpZVelocity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float AAS_RocketJumpZVelocity(vec3_t origin)
-{
- //rocket radius damage is 120 (p_weapon.c: Weapon_RocketLauncher_Fire)
- return AAS_WeaponJumpZVelocity(origin, 120);
-} //end of the function AAS_RocketJumpZVelocity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float AAS_BFGJumpZVelocity(vec3_t origin)
-{
- //bfg radius damage is 1000 (p_weapon.c: weapon_bfg_fire)
- return AAS_WeaponJumpZVelocity(origin, 120);
-} //end of the function AAS_BFGJumpZVelocity
-//===========================================================================
-// applies ground friction to the given velocity
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_Accelerate(vec3_t velocity, float frametime, vec3_t wishdir, float wishspeed, float accel)
-{
- // q2 style
- int i;
- float addspeed, accelspeed, currentspeed;
-
- currentspeed = DotProduct(velocity, wishdir);
- addspeed = wishspeed - currentspeed;
- if (addspeed <= 0) {
- return;
- }
- accelspeed = accel*frametime*wishspeed;
- if (accelspeed > addspeed) {
- accelspeed = addspeed;
- }
-
- for (i=0 ; i<3 ; i++) {
- velocity[i] += accelspeed*wishdir[i];
- }
-} //end of the function AAS_Accelerate
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_AirControl(vec3_t start, vec3_t end, vec3_t velocity, vec3_t cmdmove)
-{
- vec3_t dir;
-
- VectorSubtract(end, start, dir);
-} //end of the function AAS_AirControl
-//===========================================================================
-// applies ground friction to the given velocity
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ApplyFriction(vec3_t vel, float friction, float stopspeed,
- float frametime)
-{
- float speed, control, newspeed;
-
- //horizontal speed
- speed = sqrt(vel[0] * vel[0] + vel[1] * vel[1]);
- if (speed)
- {
- control = speed < stopspeed ? stopspeed : speed;
- newspeed = speed - frametime * control * friction;
- if (newspeed < 0) newspeed = 0;
- newspeed /= speed;
- vel[0] *= newspeed;
- vel[1] *= newspeed;
- } //end if
-} //end of the function AAS_ApplyFriction
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_ClipToBBox(aas_trace_t *trace, vec3_t start, vec3_t end, int presencetype, vec3_t mins, vec3_t maxs)
-{
- int i, j, side;
- float front, back, frac, planedist;
- vec3_t bboxmins, bboxmaxs, absmins, absmaxs, dir, mid;
-
- AAS_PresenceTypeBoundingBox(presencetype, bboxmins, bboxmaxs);
- VectorSubtract(mins, bboxmaxs, absmins);
- VectorSubtract(maxs, bboxmins, absmaxs);
- //
- VectorCopy(end, trace->endpos);
- trace->fraction = 1;
- for (i = 0; i < 3; i++)
- {
- if (start[i] < absmins[i] && end[i] < absmins[i]) return qfalse;
- if (start[i] > absmaxs[i] && end[i] > absmaxs[i]) return qfalse;
- } //end for
- //check bounding box collision
- VectorSubtract(end, start, dir);
- frac = 1;
- for (i = 0; i < 3; i++)
- {
- //get plane to test collision with for the current axis direction
- if (dir[i] > 0) planedist = absmins[i];
- else planedist = absmaxs[i];
- //calculate collision fraction
- front = start[i] - planedist;
- back = end[i] - planedist;
- frac = front / (front-back);
- //check if between bounding planes of next axis
- side = i + 1;
- if (side > 2) side = 0;
- mid[side] = start[side] + dir[side] * frac;
- if (mid[side] > absmins[side] && mid[side] < absmaxs[side])
- {
- //check if between bounding planes of next axis
- side++;
- if (side > 2) side = 0;
- mid[side] = start[side] + dir[side] * frac;
- if (mid[side] > absmins[side] && mid[side] < absmaxs[side])
- {
- mid[i] = planedist;
- break;
- } //end if
- } //end if
- } //end for
- //if there was a collision
- if (i != 3)
- {
- trace->startsolid = qfalse;
- trace->fraction = frac;
- trace->ent = 0;
- trace->planenum = 0;
- trace->area = 0;
- trace->lastarea = 0;
- //trace endpos
- for (j = 0; j < 3; j++) trace->endpos[j] = start[j] + dir[j] * frac;
- return qtrue;
- } //end if
- return qfalse;
-} //end of the function AAS_ClipToBBox
-//===========================================================================
-// predicts the movement
-// assumes regular bounding box sizes
-// NOTE: out of water jumping is not included
-// NOTE: grappling hook is not included
-//
-// Parameter: origin : origin to start with
-// presencetype : presence type to start with
-// velocity : velocity to start with
-// cmdmove : client command movement
-// cmdframes : number of frame cmdmove is valid
-// maxframes : maximum number of predicted frames
-// frametime : duration of one predicted frame
-// stopevent : events that stop the prediction
-// stopareanum : stop as soon as entered this area
-// Returns: aas_clientmove_t
-// Changes Globals: -
-//===========================================================================
-int AAS_ClientMovementPrediction(struct aas_clientmove_s *move,
- int entnum, vec3_t origin,
- int presencetype, int onground,
- vec3_t velocity, vec3_t cmdmove,
- int cmdframes,
- int maxframes, float frametime,
- int stopevent, int stopareanum,
- vec3_t mins, vec3_t maxs, int visualize)
-{
- float phys_friction, phys_stopspeed, phys_gravity, phys_waterfriction;
- float phys_watergravity;
- float phys_walkaccelerate, phys_airaccelerate, phys_swimaccelerate;
- float phys_maxwalkvelocity, phys_maxcrouchvelocity, phys_maxswimvelocity;
- float phys_maxstep, phys_maxsteepness, phys_jumpvel, friction;
- float gravity, delta, maxvel, wishspeed, accelerate;
- //float velchange, newvel;
- int n, i, j, pc, step, swimming, ax, crouch, event, jump_frame, areanum;
- int areas[20], numareas;
- vec3_t points[20];
- vec3_t org, end, feet, start, stepend, lastorg, wishdir;
- vec3_t frame_test_vel, old_frame_test_vel, left_test_vel;
- vec3_t up = {0, 0, 1};
- aas_plane_t *plane, *plane2;
- aas_trace_t trace, steptrace;
-
- if (frametime <= 0) frametime = 0.1f;
- //
- phys_friction = aassettings.phys_friction;
- phys_stopspeed = aassettings.phys_stopspeed;
- phys_gravity = aassettings.phys_gravity;
- phys_waterfriction = aassettings.phys_waterfriction;
- phys_watergravity = aassettings.phys_watergravity;
- phys_maxwalkvelocity = aassettings.phys_maxwalkvelocity;// * frametime;
- phys_maxcrouchvelocity = aassettings.phys_maxcrouchvelocity;// * frametime;
- phys_maxswimvelocity = aassettings.phys_maxswimvelocity;// * frametime;
- phys_walkaccelerate = aassettings.phys_walkaccelerate;
- phys_airaccelerate = aassettings.phys_airaccelerate;
- phys_swimaccelerate = aassettings.phys_swimaccelerate;
- phys_maxstep = aassettings.phys_maxstep;
- phys_maxsteepness = aassettings.phys_maxsteepness;
- phys_jumpvel = aassettings.phys_jumpvel * frametime;
- //
- Com_Memset(move, 0, sizeof(aas_clientmove_t));
- Com_Memset(&trace, 0, sizeof(aas_trace_t));
- //start at the current origin
- VectorCopy(origin, org);
- org[2] += 0.25;
- //velocity to test for the first frame
- VectorScale(velocity, frametime, frame_test_vel);
- //
- jump_frame = -1;
- //predict a maximum of 'maxframes' ahead
- for (n = 0; n < maxframes; n++)
- {
- swimming = AAS_Swimming(org);
- //get gravity depending on swimming or not
- gravity = swimming ? phys_watergravity : phys_gravity;
- //apply gravity at the START of the frame
- frame_test_vel[2] = frame_test_vel[2] - (gravity * 0.1 * frametime);
- //if on the ground or swimming
- if (onground || swimming)
- {
- friction = swimming ? phys_friction : phys_waterfriction;
- //apply friction
- VectorScale(frame_test_vel, 1/frametime, frame_test_vel);
- AAS_ApplyFriction(frame_test_vel, friction, phys_stopspeed, frametime);
- VectorScale(frame_test_vel, frametime, frame_test_vel);
- } //end if
- crouch = qfalse;
- //apply command movement
- if (n < cmdframes)
- {
- ax = 0;
- maxvel = phys_maxwalkvelocity;
- accelerate = phys_airaccelerate;
- VectorCopy(cmdmove, wishdir);
- if (onground)
- {
- if (cmdmove[2] < -300)
- {
- crouch = qtrue;
- maxvel = phys_maxcrouchvelocity;
- } //end if
- //if not swimming and upmove is positive then jump
- if (!swimming && cmdmove[2] > 1)
- {
- //jump velocity minus the gravity for one frame + 5 for safety
- frame_test_vel[2] = phys_jumpvel - (gravity * 0.1 * frametime) + 5;
- jump_frame = n;
- //jumping so air accelerate
- accelerate = phys_airaccelerate;
- } //end if
- else
- {
- accelerate = phys_walkaccelerate;
- } //end else
- ax = 2;
- } //end if
- if (swimming)
- {
- maxvel = phys_maxswimvelocity;
- accelerate = phys_swimaccelerate;
- ax = 3;
- } //end if
- else
- {
- wishdir[2] = 0;
- } //end else
- //
- wishspeed = VectorNormalize(wishdir);
- if (wishspeed > maxvel) wishspeed = maxvel;
- VectorScale(frame_test_vel, 1/frametime, frame_test_vel);
- AAS_Accelerate(frame_test_vel, frametime, wishdir, wishspeed, accelerate);
- VectorScale(frame_test_vel, frametime, frame_test_vel);
- /*
- for (i = 0; i < ax; i++)
- {
- velchange = (cmdmove[i] * frametime) - frame_test_vel[i];
- if (velchange > phys_maxacceleration) velchange = phys_maxacceleration;
- else if (velchange < -phys_maxacceleration) velchange = -phys_maxacceleration;
- newvel = frame_test_vel[i] + velchange;
- //
- if (frame_test_vel[i] <= maxvel && newvel > maxvel) frame_test_vel[i] = maxvel;
- else if (frame_test_vel[i] >= -maxvel && newvel < -maxvel) frame_test_vel[i] = -maxvel;
- else frame_test_vel[i] = newvel;
- } //end for
- */
- } //end if
- if (crouch)
- {
- presencetype = PRESENCE_CROUCH;
- } //end if
- else if (presencetype == PRESENCE_CROUCH)
- {
- if (AAS_PointPresenceType(org) & PRESENCE_NORMAL)
- {
- presencetype = PRESENCE_NORMAL;
- } //end if
- } //end else
- //save the current origin
- VectorCopy(org, lastorg);
- //move linear during one frame
- VectorCopy(frame_test_vel, left_test_vel);
- j = 0;
- do
- {
- VectorAdd(org, left_test_vel, end);
- //trace a bounding box
- trace = AAS_TraceClientBBox(org, end, presencetype, entnum);
- //
-//#ifdef AAS_MOVE_DEBUG
- if (visualize)
- {
- if (trace.startsolid) botimport.Print(PRT_MESSAGE, "PredictMovement: start solid\n");
- AAS_DebugLine(org, trace.endpos, LINECOLOR_RED);
- } //end if
-//#endif //AAS_MOVE_DEBUG
- //
- if (stopevent & (SE_ENTERAREA|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER|SE_TOUCHCLUSTERPORTAL))
- {
- numareas = AAS_TraceAreas(org, trace.endpos, areas, points, 20);
- for (i = 0; i < numareas; i++)
- {
- if (stopevent & SE_ENTERAREA)
- {
- if (areas[i] == stopareanum)
- {
- VectorCopy(points[i], move->endpos);
- VectorScale(frame_test_vel, 1/frametime, move->velocity);
- move->endarea = areas[i];
- move->trace = trace;
- move->stopevent = SE_ENTERAREA;
- move->presencetype = presencetype;
- move->endcontents = 0;
- move->time = n * frametime;
- move->frames = n;
- return qtrue;
- } //end if
- } //end if
- //NOTE: if not the first frame
- if ((stopevent & SE_TOUCHJUMPPAD) && n)
- {
- if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_JUMPPAD)
- {
- VectorCopy(points[i], move->endpos);
- VectorScale(frame_test_vel, 1/frametime, move->velocity);
- move->endarea = areas[i];
- move->trace = trace;
- move->stopevent = SE_TOUCHJUMPPAD;
- move->presencetype = presencetype;
- move->endcontents = 0;
- move->time = n * frametime;
- move->frames = n;
- return qtrue;
- } //end if
- } //end if
- if (stopevent & SE_TOUCHTELEPORTER)
- {
- if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_TELEPORTER)
- {
- VectorCopy(points[i], move->endpos);
- move->endarea = areas[i];
- VectorScale(frame_test_vel, 1/frametime, move->velocity);
- move->trace = trace;
- move->stopevent = SE_TOUCHTELEPORTER;
- move->presencetype = presencetype;
- move->endcontents = 0;
- move->time = n * frametime;
- move->frames = n;
- return qtrue;
- } //end if
- } //end if
- if (stopevent & SE_TOUCHCLUSTERPORTAL)
- {
- if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_CLUSTERPORTAL)
- {
- VectorCopy(points[i], move->endpos);
- move->endarea = areas[i];
- VectorScale(frame_test_vel, 1/frametime, move->velocity);
- move->trace = trace;
- move->stopevent = SE_TOUCHCLUSTERPORTAL;
- move->presencetype = presencetype;
- move->endcontents = 0;
- move->time = n * frametime;
- move->frames = n;
- return qtrue;
- } //end if
- } //end if
- } //end for
- } //end if
- //
- if (stopevent & SE_HITBOUNDINGBOX)
- {
- if (AAS_ClipToBBox(&trace, org, trace.endpos, presencetype, mins, maxs))
- {
- VectorCopy(trace.endpos, move->endpos);
- move->endarea = AAS_PointAreaNum(move->endpos);
- VectorScale(frame_test_vel, 1/frametime, move->velocity);
- move->trace = trace;
- move->stopevent = SE_HITBOUNDINGBOX;
- move->presencetype = presencetype;
- move->endcontents = 0;
- move->time = n * frametime;
- move->frames = n;
- return qtrue;
- } //end if
- } //end if
- //move the entity to the trace end point
- VectorCopy(trace.endpos, org);
- //if there was a collision
- if (trace.fraction < 1.0)
- {
- //get the plane the bounding box collided with
- plane = AAS_PlaneFromNum(trace.planenum);
- //
- if (stopevent & SE_HITGROUNDAREA)
- {
- if (DotProduct(plane->normal, up) > phys_maxsteepness)
- {
- VectorCopy(org, start);
- start[2] += 0.5;
- if (AAS_PointAreaNum(start) == stopareanum)
- {
- VectorCopy(start, move->endpos);
- move->endarea = stopareanum;
- VectorScale(frame_test_vel, 1/frametime, move->velocity);
- move->trace = trace;
- move->stopevent = SE_HITGROUNDAREA;
- move->presencetype = presencetype;
- move->endcontents = 0;
- move->time = n * frametime;
- move->frames = n;
- return qtrue;
- } //end if
- } //end if
- } //end if
- //assume there's no step
- step = qfalse;
- //if it is a vertical plane and the bot didn't jump recently
- if (plane->normal[2] == 0 && (jump_frame < 0 || n - jump_frame > 2))
- {
- //check for a step
- VectorMA(org, -0.25, plane->normal, start);
- VectorCopy(start, stepend);
- start[2] += phys_maxstep;
- steptrace = AAS_TraceClientBBox(start, stepend, presencetype, entnum);
- //
- if (!steptrace.startsolid)
- {
- plane2 = AAS_PlaneFromNum(steptrace.planenum);
- if (DotProduct(plane2->normal, up) > phys_maxsteepness)
- {
- VectorSubtract(end, steptrace.endpos, left_test_vel);
- left_test_vel[2] = 0;
- frame_test_vel[2] = 0;
-//#ifdef AAS_MOVE_DEBUG
- if (visualize)
- {
- if (steptrace.endpos[2] - org[2] > 0.125)
- {
- VectorCopy(org, start);
- start[2] = steptrace.endpos[2];
- AAS_DebugLine(org, start, LINECOLOR_BLUE);
- } //end if
- } //end if
-//#endif //AAS_MOVE_DEBUG
- org[2] = steptrace.endpos[2];
- step = qtrue;
- } //end if
- } //end if
- } //end if
- //
- if (!step)
- {
- //velocity left to test for this frame is the projection
- //of the current test velocity into the hit plane
- VectorMA(left_test_vel, -DotProduct(left_test_vel, plane->normal),
- plane->normal, left_test_vel);
- //store the old velocity for landing check
- VectorCopy(frame_test_vel, old_frame_test_vel);
- //test velocity for the next frame is the projection
- //of the velocity of the current frame into the hit plane
- VectorMA(frame_test_vel, -DotProduct(frame_test_vel, plane->normal),
- plane->normal, frame_test_vel);
- //check for a landing on an almost horizontal floor
- if (DotProduct(plane->normal, up) > phys_maxsteepness)
- {
- onground = qtrue;
- } //end if
- if (stopevent & SE_HITGROUNDDAMAGE)
- {
- delta = 0;
- if (old_frame_test_vel[2] < 0 &&
- frame_test_vel[2] > old_frame_test_vel[2] &&
- !onground)
- {
- delta = old_frame_test_vel[2];
- } //end if
- else if (onground)
- {
- delta = frame_test_vel[2] - old_frame_test_vel[2];
- } //end else
- if (delta)
- {
- delta = delta * 10;
- delta = delta * delta * 0.0001;
- if (swimming) delta = 0;
- // never take falling damage if completely underwater
- /*
- if (ent->waterlevel == 3) return;
- if (ent->waterlevel == 2) delta *= 0.25;
- if (ent->waterlevel == 1) delta *= 0.5;
- */
- if (delta > 40)
- {
- VectorCopy(org, move->endpos);
- move->endarea = AAS_PointAreaNum(org);
- VectorCopy(frame_test_vel, move->velocity);
- move->trace = trace;
- move->stopevent = SE_HITGROUNDDAMAGE;
- move->presencetype = presencetype;
- move->endcontents = 0;
- move->time = n * frametime;
- move->frames = n;
- return qtrue;
- } //end if
- } //end if
- } //end if
- } //end if
- } //end if
- //extra check to prevent endless loop
- if (++j > 20) return qfalse;
- //while there is a plane hit
- } while(trace.fraction < 1.0);
- //if going down
- if (frame_test_vel[2] <= 10)
- {
- //check for a liquid at the feet of the bot
- VectorCopy(org, feet);
- feet[2] -= 22;
- pc = AAS_PointContents(feet);
- //get event from pc
- event = SE_NONE;
- if (pc & CONTENTS_LAVA) event |= SE_ENTERLAVA;
- if (pc & CONTENTS_SLIME) event |= SE_ENTERSLIME;
- if (pc & CONTENTS_WATER) event |= SE_ENTERWATER;
- //
- areanum = AAS_PointAreaNum(org);
- if (aasworld.areasettings[areanum].contents & AREACONTENTS_LAVA)
- event |= SE_ENTERLAVA;
- if (aasworld.areasettings[areanum].contents & AREACONTENTS_SLIME)
- event |= SE_ENTERSLIME;
- if (aasworld.areasettings[areanum].contents & AREACONTENTS_WATER)
- event |= SE_ENTERWATER;
- //if in lava or slime
- if (event & stopevent)
- {
- VectorCopy(org, move->endpos);
- move->endarea = areanum;
- VectorScale(frame_test_vel, 1/frametime, move->velocity);
- move->stopevent = event & stopevent;
- move->presencetype = presencetype;
- move->endcontents = pc;
- move->time = n * frametime;
- move->frames = n;
- return qtrue;
- } //end if
- } //end if
- //
- onground = AAS_OnGround(org, presencetype, entnum);
- //if onground and on the ground for at least one whole frame
- if (onground)
- {
- if (stopevent & SE_HITGROUND)
- {
- VectorCopy(org, move->endpos);
- move->endarea = AAS_PointAreaNum(org);
- VectorScale(frame_test_vel, 1/frametime, move->velocity);
- move->trace = trace;
- move->stopevent = SE_HITGROUND;
- move->presencetype = presencetype;
- move->endcontents = 0;
- move->time = n * frametime;
- move->frames = n;
- return qtrue;
- } //end if
- } //end if
- else if (stopevent & SE_LEAVEGROUND)
- {
- VectorCopy(org, move->endpos);
- move->endarea = AAS_PointAreaNum(org);
- VectorScale(frame_test_vel, 1/frametime, move->velocity);
- move->trace = trace;
- move->stopevent = SE_LEAVEGROUND;
- move->presencetype = presencetype;
- move->endcontents = 0;
- move->time = n * frametime;
- move->frames = n;
- return qtrue;
- } //end else if
- else if (stopevent & SE_GAP)
- {
- aas_trace_t gaptrace;
-
- VectorCopy(org, start);
- VectorCopy(start, end);
- end[2] -= 48 + aassettings.phys_maxbarrier;
- gaptrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);
- //if solid is found the bot cannot walk any further and will not fall into a gap
- if (!gaptrace.startsolid)
- {
- //if it is a gap (lower than one step height)
- if (gaptrace.endpos[2] < org[2] - aassettings.phys_maxstep - 1)
- {
- if (!(AAS_PointContents(end) & CONTENTS_WATER))
- {
- VectorCopy(lastorg, move->endpos);
- move->endarea = AAS_PointAreaNum(lastorg);
- VectorScale(frame_test_vel, 1/frametime, move->velocity);
- move->trace = trace;
- move->stopevent = SE_GAP;
- move->presencetype = presencetype;
- move->endcontents = 0;
- move->time = n * frametime;
- move->frames = n;
- return qtrue;
- } //end if
- } //end if
- } //end if
- } //end else if
- } //end for
- //
- VectorCopy(org, move->endpos);
- move->endarea = AAS_PointAreaNum(org);
- VectorScale(frame_test_vel, 1/frametime, move->velocity);
- move->stopevent = SE_NONE;
- move->presencetype = presencetype;
- move->endcontents = 0;
- move->time = n * frametime;
- move->frames = n;
- //
- return qtrue;
-} //end of the function AAS_ClientMovementPrediction
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_PredictClientMovement(struct aas_clientmove_s *move,
- int entnum, vec3_t origin,
- int presencetype, int onground,
- vec3_t velocity, vec3_t cmdmove,
- int cmdframes,
- int maxframes, float frametime,
- int stopevent, int stopareanum, int visualize)
-{
- vec3_t mins, maxs;
- return AAS_ClientMovementPrediction(move, entnum, origin, presencetype, onground,
- velocity, cmdmove, cmdframes, maxframes,
- frametime, stopevent, stopareanum,
- mins, maxs, visualize);
-} //end of the function AAS_PredictClientMovement
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_ClientMovementHitBBox(struct aas_clientmove_s *move,
- int entnum, vec3_t origin,
- int presencetype, int onground,
- vec3_t velocity, vec3_t cmdmove,
- int cmdframes,
- int maxframes, float frametime,
- vec3_t mins, vec3_t maxs, int visualize)
-{
- return AAS_ClientMovementPrediction(move, entnum, origin, presencetype, onground,
- velocity, cmdmove, cmdframes, maxframes,
- frametime, SE_HITBOUNDINGBOX, 0,
- mins, maxs, visualize);
-} //end of the function AAS_ClientMovementHitBBox
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_TestMovementPrediction(int entnum, vec3_t origin, vec3_t dir)
-{
- vec3_t velocity, cmdmove;
- aas_clientmove_t move;
-
- VectorClear(velocity);
- if (!AAS_Swimming(origin)) dir[2] = 0;
- VectorNormalize(dir);
- VectorScale(dir, 400, cmdmove);
- cmdmove[2] = 224;
- AAS_ClearShownDebugLines();
- AAS_PredictClientMovement(&move, entnum, origin, PRESENCE_NORMAL, qtrue,
- velocity, cmdmove, 13, 13, 0.1f, SE_HITGROUND, 0, qtrue);//SE_LEAVEGROUND);
- if (move.stopevent & SE_LEAVEGROUND)
- {
- botimport.Print(PRT_MESSAGE, "leave ground\n");
- } //end if
-} //end of the function TestMovementPrediction
-//===========================================================================
-// calculates the horizontal velocity needed to perform a jump from start
-// to end
-//
-// Parameter: zvel : z velocity for jump
-// start : start position of jump
-// end : end position of jump
-// *speed : returned speed for jump
-// Returns: qfalse if too high or too far from start to end
-// Changes Globals: -
-//===========================================================================
-int AAS_HorizontalVelocityForJump(float zvel, vec3_t start, vec3_t end, float *velocity)
-{
- float phys_gravity, phys_maxvelocity;
- float maxjump, height2fall, t, top;
- vec3_t dir;
-
- phys_gravity = aassettings.phys_gravity;
- phys_maxvelocity = aassettings.phys_maxvelocity;
-
- //maximum height a player can jump with the given initial z velocity
- maxjump = 0.5 * phys_gravity * (zvel / phys_gravity) * (zvel / phys_gravity);
- //top of the parabolic jump
- top = start[2] + maxjump;
- //height the bot will fall from the top
- height2fall = top - end[2];
- //if the goal is to high to jump to
- if (height2fall < 0)
- {
- *velocity = phys_maxvelocity;
- return 0;
- } //end if
- //time a player takes to fall the height
- t = sqrt(height2fall / (0.5 * phys_gravity));
- //direction from start to end
- VectorSubtract(end, start, dir);
- //
- if ( (t + zvel / phys_gravity) == 0.0f ) {
- *velocity = phys_maxvelocity;
- return 0;
- }
- //calculate horizontal speed
- *velocity = sqrt(dir[0]*dir[0] + dir[1]*dir[1]) / (t + zvel / phys_gravity);
- //the horizontal speed must be lower than the max speed
- if (*velocity > phys_maxvelocity)
- {
- *velocity = phys_maxvelocity;
- return 0;
- } //end if
- return 1;
-} //end of the function AAS_HorizontalVelocityForJump
diff --git a/engine/code/botlib/be_aas_optimize.c b/engine/code/botlib/be_aas_optimize.c
deleted file mode 100644
index ea0d2da..0000000
--- a/engine/code/botlib/be_aas_optimize.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_optimize.c
- *
- * desc: decreases the .aas file size after the reachabilities have
- * been calculated, just dumps all the faces, edges and vertexes
- *
- * $Archive: /MissionPack/code/botlib/be_aas_optimize.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_libvar.h"
-#include "l_memory.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-#include "be_aas_def.h"
-
-typedef struct optimized_s
-{
- //vertexes
- int numvertexes;
- aas_vertex_t *vertexes;
- //edges
- int numedges;
- aas_edge_t *edges;
- //edge index
- int edgeindexsize;
- aas_edgeindex_t *edgeindex;
- //faces
- int numfaces;
- aas_face_t *faces;
- //face index
- int faceindexsize;
- aas_faceindex_t *faceindex;
- //convex areas
- int numareas;
- aas_area_t *areas;
- //
- int *vertexoptimizeindex;
- int *edgeoptimizeindex;
- int *faceoptimizeindex;
-} optimized_t;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_KeepEdge(aas_edge_t *edge)
-{
- return 1;
-} //end of the function AAS_KeepFace
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_OptimizeEdge(optimized_t *optimized, int edgenum)
-{
- int i, optedgenum;
- aas_edge_t *edge, *optedge;
-
- edge = &aasworld.edges[abs(edgenum)];
- if (!AAS_KeepEdge(edge)) return 0;
-
- optedgenum = optimized->edgeoptimizeindex[abs(edgenum)];
- if (optedgenum)
- {
- //keep the edge reversed sign
- if (edgenum > 0) return optedgenum;
- else return -optedgenum;
- } //end if
-
- optedge = &optimized->edges[optimized->numedges];
-
- for (i = 0; i < 2; i++)
- {
- if (optimized->vertexoptimizeindex[edge->v[i]])
- {
- optedge->v[i] = optimized->vertexoptimizeindex[edge->v[i]];
- } //end if
- else
- {
- VectorCopy(aasworld.vertexes[edge->v[i]], optimized->vertexes[optimized->numvertexes]);
- optedge->v[i] = optimized->numvertexes;
- optimized->vertexoptimizeindex[edge->v[i]] = optimized->numvertexes;
- optimized->numvertexes++;
- } //end else
- } //end for
- optimized->edgeoptimizeindex[abs(edgenum)] = optimized->numedges;
- optedgenum = optimized->numedges;
- optimized->numedges++;
- //keep the edge reversed sign
- if (edgenum > 0) return optedgenum;
- else return -optedgenum;
-} //end of the function AAS_OptimizeEdge
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_KeepFace(aas_face_t *face)
-{
- if (!(face->faceflags & FACE_LADDER)) return 0;
- else return 1;
-} //end of the function AAS_KeepFace
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_OptimizeFace(optimized_t *optimized, int facenum)
-{
- int i, edgenum, optedgenum, optfacenum;
- aas_face_t *face, *optface;
-
- face = &aasworld.faces[abs(facenum)];
- if (!AAS_KeepFace(face)) return 0;
-
- optfacenum = optimized->faceoptimizeindex[abs(facenum)];
- if (optfacenum)
- {
- //keep the face side sign
- if (facenum > 0) return optfacenum;
- else return -optfacenum;
- } //end if
-
- optface = &optimized->faces[optimized->numfaces];
- Com_Memcpy(optface, face, sizeof(aas_face_t));
-
- optface->numedges = 0;
- optface->firstedge = optimized->edgeindexsize;
- for (i = 0; i < face->numedges; i++)
- {
- edgenum = aasworld.edgeindex[face->firstedge + i];
- optedgenum = AAS_OptimizeEdge(optimized, edgenum);
- if (optedgenum)
- {
- optimized->edgeindex[optface->firstedge + optface->numedges] = optedgenum;
- optface->numedges++;
- optimized->edgeindexsize++;
- } //end if
- } //end for
- optimized->faceoptimizeindex[abs(facenum)] = optimized->numfaces;
- optfacenum = optimized->numfaces;
- optimized->numfaces++;
- //keep the face side sign
- if (facenum > 0) return optfacenum;
- else return -optfacenum;
-} //end of the function AAS_OptimizeFace
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_OptimizeArea(optimized_t *optimized, int areanum)
-{
- int i, facenum, optfacenum;
- aas_area_t *area, *optarea;
-
- area = &aasworld.areas[areanum];
- optarea = &optimized->areas[areanum];
- Com_Memcpy(optarea, area, sizeof(aas_area_t));
-
- optarea->numfaces = 0;
- optarea->firstface = optimized->faceindexsize;
- for (i = 0; i < area->numfaces; i++)
- {
- facenum = aasworld.faceindex[area->firstface + i];
- optfacenum = AAS_OptimizeFace(optimized, facenum);
- if (optfacenum)
- {
- optimized->faceindex[optarea->firstface + optarea->numfaces] = optfacenum;
- optarea->numfaces++;
- optimized->faceindexsize++;
- } //end if
- } //end for
-} //end of the function AAS_OptimizeArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_OptimizeAlloc(optimized_t *optimized)
-{
- optimized->vertexes = (aas_vertex_t *) GetClearedMemory(aasworld.numvertexes * sizeof(aas_vertex_t));
- optimized->numvertexes = 0;
- optimized->edges = (aas_edge_t *) GetClearedMemory(aasworld.numedges * sizeof(aas_edge_t));
- optimized->numedges = 1; //edge zero is a dummy
- optimized->edgeindex = (aas_edgeindex_t *) GetClearedMemory(aasworld.edgeindexsize * sizeof(aas_edgeindex_t));
- optimized->edgeindexsize = 0;
- optimized->faces = (aas_face_t *) GetClearedMemory(aasworld.numfaces * sizeof(aas_face_t));
- optimized->numfaces = 1; //face zero is a dummy
- optimized->faceindex = (aas_faceindex_t *) GetClearedMemory(aasworld.faceindexsize * sizeof(aas_faceindex_t));
- optimized->faceindexsize = 0;
- optimized->areas = (aas_area_t *) GetClearedMemory(aasworld.numareas * sizeof(aas_area_t));
- optimized->numareas = aasworld.numareas;
- //
- optimized->vertexoptimizeindex = (int *) GetClearedMemory(aasworld.numvertexes * sizeof(int));
- optimized->edgeoptimizeindex = (int *) GetClearedMemory(aasworld.numedges * sizeof(int));
- optimized->faceoptimizeindex = (int *) GetClearedMemory(aasworld.numfaces * sizeof(int));
-} //end of the function AAS_OptimizeAlloc
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_OptimizeStore(optimized_t *optimized)
-{
- //store the optimized vertexes
- if (aasworld.vertexes) FreeMemory(aasworld.vertexes);
- aasworld.vertexes = optimized->vertexes;
- aasworld.numvertexes = optimized->numvertexes;
- //store the optimized edges
- if (aasworld.edges) FreeMemory(aasworld.edges);
- aasworld.edges = optimized->edges;
- aasworld.numedges = optimized->numedges;
- //store the optimized edge index
- if (aasworld.edgeindex) FreeMemory(aasworld.edgeindex);
- aasworld.edgeindex = optimized->edgeindex;
- aasworld.edgeindexsize = optimized->edgeindexsize;
- //store the optimized faces
- if (aasworld.faces) FreeMemory(aasworld.faces);
- aasworld.faces = optimized->faces;
- aasworld.numfaces = optimized->numfaces;
- //store the optimized face index
- if (aasworld.faceindex) FreeMemory(aasworld.faceindex);
- aasworld.faceindex = optimized->faceindex;
- aasworld.faceindexsize = optimized->faceindexsize;
- //store the optimized areas
- if (aasworld.areas) FreeMemory(aasworld.areas);
- aasworld.areas = optimized->areas;
- aasworld.numareas = optimized->numareas;
- //free optimize indexes
- FreeMemory(optimized->vertexoptimizeindex);
- FreeMemory(optimized->edgeoptimizeindex);
- FreeMemory(optimized->faceoptimizeindex);
-} //end of the function AAS_OptimizeStore
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_Optimize(void)
-{
- int i, sign;
- optimized_t optimized;
-
- AAS_OptimizeAlloc(&optimized);
- for (i = 1; i < aasworld.numareas; i++)
- {
- AAS_OptimizeArea(&optimized, i);
- } //end for
- //reset the reachability face pointers
- for (i = 0; i < aasworld.reachabilitysize; i++)
- {
- //NOTE: for TRAVEL_ELEVATOR the facenum is the model number of
- // the elevator
- if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR) continue;
- //NOTE: for TRAVEL_JUMPPAD the facenum is the Z velocity and the edgenum is the hor velocity
- if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD) continue;
- //NOTE: for TRAVEL_FUNCBOB the facenum and edgenum contain other coded information
- if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB) continue;
- //
- sign = aasworld.reachability[i].facenum;
- aasworld.reachability[i].facenum = optimized.faceoptimizeindex[abs(aasworld.reachability[i].facenum)];
- if (sign < 0) aasworld.reachability[i].facenum = -aasworld.reachability[i].facenum;
- sign = aasworld.reachability[i].edgenum;
- aasworld.reachability[i].edgenum = optimized.edgeoptimizeindex[abs(aasworld.reachability[i].edgenum)];
- if (sign < 0) aasworld.reachability[i].edgenum = -aasworld.reachability[i].edgenum;
- } //end for
- //store the optimized AAS data into aasworld
- AAS_OptimizeStore(&optimized);
- //print some nice stuff :)
- botimport.Print(PRT_MESSAGE, "AAS data optimized.\n");
-} //end of the function AAS_Optimize
diff --git a/engine/code/botlib/be_aas_reach.c b/engine/code/botlib/be_aas_reach.c
deleted file mode 100644
index 95ead20..0000000
--- a/engine/code/botlib/be_aas_reach.c
+++ /dev/null
@@ -1,4538 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_reach.c
- *
- * desc: reachability calculations
- *
- * $Archive: /MissionPack/code/botlib/be_aas_reach.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_log.h"
-#include "l_memory.h"
-#include "l_script.h"
-#include "l_libvar.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_aas_def.h"
-
-extern int Sys_MilliSeconds(void);
-
-
-extern botlib_import_t botimport;
-
-//#define REACH_DEBUG
-
-//NOTE: all travel times are in hundreth of a second
-//maximum number of reachability links
-#define AAS_MAX_REACHABILITYSIZE 65536
-//number of areas reachability is calculated for each frame
-#define REACHABILITYAREASPERCYCLE 15
-//number of units reachability points are placed inside the areas
-#define INSIDEUNITS 2
-#define INSIDEUNITS_WALKEND 5
-#define INSIDEUNITS_WALKSTART 0.1
-#define INSIDEUNITS_WATERJUMP 15
-//area flag used for weapon jumping
-#define AREA_WEAPONJUMP 8192 //valid area to weapon jump to
-//number of reachabilities of each type
-int reach_swim; //swim
-int reach_equalfloor; //walk on floors with equal height
-int reach_step; //step up
-int reach_walk; //walk of step
-int reach_barrier; //jump up to a barrier
-int reach_waterjump; //jump out of water
-int reach_walkoffledge; //walk of a ledge
-int reach_jump; //jump
-int reach_ladder; //climb or descent a ladder
-int reach_teleport; //teleport
-int reach_elevator; //use an elevator
-int reach_funcbob; //use a func bob
-int reach_grapple; //grapple hook
-int reach_doublejump; //double jump
-int reach_rampjump; //ramp jump
-int reach_strafejump; //strafe jump (just normal jump but further)
-int reach_rocketjump; //rocket jump
-int reach_bfgjump; //bfg jump
-int reach_jumppad; //jump pads
-//if true grapple reachabilities are skipped
-int calcgrapplereach;
-//linked reachability
-typedef struct aas_lreachability_s
-{
- int areanum; //number of the reachable area
- int facenum; //number of the face towards the other area
- int edgenum; //number of the edge towards the other area
- vec3_t start; //start point of inter area movement
- vec3_t end; //end point of inter area movement
- int traveltype; //type of travel required to get to the area
- unsigned short int traveltime; //travel time of the inter area movement
- //
- struct aas_lreachability_s *next;
-} aas_lreachability_t;
-//temporary reachabilities
-aas_lreachability_t *reachabilityheap; //heap with reachabilities
-aas_lreachability_t *nextreachability; //next free reachability from the heap
-aas_lreachability_t **areareachability; //reachability links for every area
-int numlreachabilities;
-
-//===========================================================================
-// returns the surface area of the given face
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float AAS_FaceArea(aas_face_t *face)
-{
- int i, edgenum, side;
- float total;
- vec_t *v;
- vec3_t d1, d2, cross;
- aas_edge_t *edge;
-
- edgenum = aasworld.edgeindex[face->firstedge];
- side = edgenum < 0;
- edge = &aasworld.edges[abs(edgenum)];
- v = aasworld.vertexes[edge->v[side]];
-
- total = 0;
- for (i = 1; i < face->numedges - 1; i++)
- {
- edgenum = aasworld.edgeindex[face->firstedge + i];
- side = edgenum < 0;
- edge = &aasworld.edges[abs(edgenum)];
- VectorSubtract(aasworld.vertexes[edge->v[side]], v, d1);
- VectorSubtract(aasworld.vertexes[edge->v[!side]], v, d2);
- CrossProduct(d1, d2, cross);
- total += 0.5 * VectorLength(cross);
- } //end for
- return total;
-} //end of the function AAS_FaceArea
-//===========================================================================
-// returns the volume of an area
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float AAS_AreaVolume(int areanum)
-{
- int i, edgenum, facenum, side;
- vec_t d, a, volume;
- vec3_t corner;
- aas_plane_t *plane;
- aas_edge_t *edge;
- aas_face_t *face;
- aas_area_t *area;
-
- area = &aasworld.areas[areanum];
- facenum = aasworld.faceindex[area->firstface];
- face = &aasworld.faces[abs(facenum)];
- edgenum = aasworld.edgeindex[face->firstedge];
- edge = &aasworld.edges[abs(edgenum)];
- //
- VectorCopy(aasworld.vertexes[edge->v[0]], corner);
-
- //make tetrahedrons to all other faces
- volume = 0;
- for (i = 0; i < area->numfaces; i++)
- {
- facenum = abs(aasworld.faceindex[area->firstface + i]);
- face = &aasworld.faces[facenum];
- side = face->backarea != areanum;
- plane = &aasworld.planes[face->planenum ^ side];
- d = -(DotProduct (corner, plane->normal) - plane->dist);
- a = AAS_FaceArea(face);
- volume += d * a;
- } //end for
-
- volume /= 3;
- return volume;
-} //end of the function AAS_AreaVolume
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_BestReachableLinkArea(aas_link_t *areas)
-{
- aas_link_t *link;
-
- for (link = areas; link; link = link->next_area)
- {
- if (AAS_AreaGrounded(link->areanum) || AAS_AreaSwim(link->areanum))
- {
- return link->areanum;
- } //end if
- } //end for
- //
- for (link = areas; link; link = link->next_area)
- {
- if (link->areanum) return link->areanum;
- //FIXME: this is a bad idea when the reachability is not yet
- // calculated when the level items are loaded
- if (AAS_AreaReachability(link->areanum))
- return link->areanum;
- } //end for
- return 0;
-} //end of the function AAS_BestReachableLinkArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_GetJumpPadInfo(int ent, vec3_t areastart, vec3_t absmins, vec3_t absmaxs, vec3_t velocity)
-{
- int modelnum, ent2;
- float speed, height, gravity, time, dist, forward;
- vec3_t origin, angles, teststart, ent2origin;
- aas_trace_t trace;
- char model[MAX_EPAIRKEY];
- char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY];
-
- //
- AAS_FloatForBSPEpairKey(ent, "speed", &speed);
- if (!speed) speed = 1000;
- VectorClear(angles);
- //get the mins, maxs and origin of the model
- AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY);
- if (model[0]) modelnum = atoi(model+1);
- else modelnum = 0;
- AAS_BSPModelMinsMaxsOrigin(modelnum, angles, absmins, absmaxs, origin);
- VectorAdd(origin, absmins, absmins);
- VectorAdd(origin, absmaxs, absmaxs);
- VectorAdd(absmins, absmaxs, origin);
- VectorScale (origin, 0.5, origin);
-
- //get the start areas
- VectorCopy(origin, teststart);
- teststart[2] += 64;
- trace = AAS_TraceClientBBox(teststart, origin, PRESENCE_CROUCH, -1);
- if (trace.startsolid)
- {
- botimport.Print(PRT_MESSAGE, "trigger_push start solid\n");
- VectorCopy(origin, areastart);
- } //end if
- else
- {
- VectorCopy(trace.endpos, areastart);
- } //end else
- areastart[2] += 0.125;
- //
- //AAS_DrawPermanentCross(origin, 4, 4);
- //get the target entity
- AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY);
- for (ent2 = AAS_NextBSPEntity(0); ent2; ent2 = AAS_NextBSPEntity(ent2))
- {
- if (!AAS_ValueForBSPEpairKey(ent2, "targetname", targetname, MAX_EPAIRKEY)) continue;
- if (!strcmp(targetname, target)) break;
- } //end for
- if (!ent2)
- {
- botimport.Print(PRT_MESSAGE, "trigger_push without target entity %s\n", target);
- return qfalse;
- } //end if
- AAS_VectorForBSPEpairKey(ent2, "origin", ent2origin);
- //
- height = ent2origin[2] - origin[2];
- gravity = aassettings.phys_gravity;
- time = sqrt( height / ( 0.5 * gravity ) );
- if (!time)
- {
- botimport.Print(PRT_MESSAGE, "trigger_push without time\n");
- return qfalse;
- } //end if
- // set s.origin2 to the push velocity
- VectorSubtract ( ent2origin, origin, velocity);
- dist = VectorNormalize( velocity);
- forward = dist / time;
- //FIXME: why multiply by 1.1
- forward *= 1.1f;
- VectorScale(velocity, forward, velocity);
- velocity[2] = time * gravity;
- return qtrue;
-} //end of the function AAS_GetJumpPadInfo
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_BestReachableFromJumpPadArea(vec3_t origin, vec3_t mins, vec3_t maxs)
-{
- int area2num, ent, bot_visualizejumppads, bestareanum;
- float volume, bestareavolume;
- vec3_t areastart, cmdmove, bboxmins, bboxmaxs;
- vec3_t absmins, absmaxs, velocity;
- aas_clientmove_t move;
- aas_link_t *areas, *link;
- char classname[MAX_EPAIRKEY];
-
-#ifdef BSPC
- bot_visualizejumppads = 0;
-#else
- bot_visualizejumppads = LibVarValue("bot_visualizejumppads", "0");
-#endif
- VectorAdd(origin, mins, bboxmins);
- VectorAdd(origin, maxs, bboxmaxs);
- for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
- {
- if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
- if (strcmp(classname, "trigger_push")) continue;
- //
- if (!AAS_GetJumpPadInfo(ent, areastart, absmins, absmaxs, velocity)) continue;
- //get the areas the jump pad brush is in
- areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH);
- for (link = areas; link; link = link->next_area)
- {
- if (AAS_AreaJumpPad(link->areanum)) break;
- } //end for
- if (!link)
- {
- botimport.Print(PRT_MESSAGE, "trigger_push not in any jump pad area\n");
- AAS_UnlinkFromAreas(areas);
- continue;
- } //end if
- //
- //botimport.Print(PRT_MESSAGE, "found a trigger_push with velocity %f %f %f\n", velocity[0], velocity[1], velocity[2]);
- //
- VectorSet(cmdmove, 0, 0, 0);
- Com_Memset(&move, 0, sizeof(aas_clientmove_t));
- area2num = 0;
- AAS_ClientMovementHitBBox(&move, -1, areastart, PRESENCE_NORMAL, qfalse,
- velocity, cmdmove, 0, 30, 0.1f, bboxmins, bboxmaxs, bot_visualizejumppads);
- if (move.frames < 30)
- {
- bestareanum = 0;
- bestareavolume = 0;
- for (link = areas; link; link = link->next_area)
- {
- if (!AAS_AreaJumpPad(link->areanum)) continue;
- volume = AAS_AreaVolume(link->areanum);
- if (volume >= bestareavolume)
- {
- bestareanum = link->areanum;
- bestareavolume = volume;
- } //end if
- } //end if
- AAS_UnlinkFromAreas(areas);
- return bestareanum;
- } //end if
- AAS_UnlinkFromAreas(areas);
- } //end for
- return 0;
-} //end of the function AAS_BestReachableFromJumpPadArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_BestReachableArea(vec3_t origin, vec3_t mins, vec3_t maxs, vec3_t goalorigin)
-{
- int areanum, i, j, k, l;
- aas_link_t *areas;
- vec3_t absmins, absmaxs;
- //vec3_t bbmins, bbmaxs;
- vec3_t start, end;
- aas_trace_t trace;
-
- if (!aasworld.loaded)
- {
- botimport.Print(PRT_ERROR, "AAS_BestReachableArea: aas not loaded\n");
- return 0;
- } //end if
- //find a point in an area
- VectorCopy(origin, start);
- areanum = AAS_PointAreaNum(start);
- //while no area found fudge around a little
- for (i = 0; i < 5 && !areanum; i++)
- {
- for (j = 0; j < 5 && !areanum; j++)
- {
- for (k = -1; k <= 1 && !areanum; k++)
- {
- for (l = -1; l <= 1 && !areanum; l++)
- {
- VectorCopy(origin, start);
- start[0] += (float) j * 4 * k;
- start[1] += (float) j * 4 * l;
- start[2] += (float) i * 4;
- areanum = AAS_PointAreaNum(start);
- } //end for
- } //end for
- } //end for
- } //end for
- //if an area was found
- if (areanum)
- {
- //drop client bbox down and try again
- VectorCopy(start, end);
- start[2] += 0.25;
- end[2] -= 50;
- trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);
- if (!trace.startsolid)
- {
- areanum = AAS_PointAreaNum(trace.endpos);
- VectorCopy(trace.endpos, goalorigin);
- //FIXME: cannot enable next line right now because the reachability
- // does not have to be calculated when the level items are loaded
- //if the origin is in an area with reachability
- //if (AAS_AreaReachability(areanum)) return areanum;
- if (areanum) return areanum;
- } //end if
- else
- {
- //it can very well happen that the AAS_PointAreaNum function tells that
- //a point is in an area and that starting a AAS_TraceClientBBox from that
- //point will return trace.startsolid qtrue
-#if 0
- if (AAS_PointAreaNum(start))
- {
- Log_Write("point %f %f %f in area %d but trace startsolid", start[0], start[1], start[2], areanum);
- AAS_DrawPermanentCross(start, 4, LINECOLOR_RED);
- } //end if
- botimport.Print(PRT_MESSAGE, "AAS_BestReachableArea: start solid\n");
-#endif
- VectorCopy(start, goalorigin);
- return areanum;
- } //end else
- } //end if
- //
- //AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bbmins, bbmaxs);
- //NOTE: the goal origin does not have to be in the goal area
- // because the bot will have to move towards the item origin anyway
- VectorCopy(origin, goalorigin);
- //
- VectorAdd(origin, mins, absmins);
- VectorAdd(origin, maxs, absmaxs);
- //add bounding box size
- //VectorSubtract(absmins, bbmaxs, absmins);
- //VectorSubtract(absmaxs, bbmins, absmaxs);
- //link an invalid (-1) entity
- areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH);
- //get the reachable link arae
- areanum = AAS_BestReachableLinkArea(areas);
- //unlink the invalid entity
- AAS_UnlinkFromAreas(areas);
- //
- return areanum;
-} //end of the function AAS_BestReachableArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_SetupReachabilityHeap(void)
-{
- int i;
-
- reachabilityheap = (aas_lreachability_t *) GetClearedMemory(
- AAS_MAX_REACHABILITYSIZE * sizeof(aas_lreachability_t));
- for (i = 0; i < AAS_MAX_REACHABILITYSIZE-1; i++)
- {
- reachabilityheap[i].next = &reachabilityheap[i+1];
- } //end for
- reachabilityheap[AAS_MAX_REACHABILITYSIZE-1].next = NULL;
- nextreachability = reachabilityheap;
- numlreachabilities = 0;
-} //end of the function AAS_InitReachabilityHeap
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ShutDownReachabilityHeap(void)
-{
- FreeMemory(reachabilityheap);
- numlreachabilities = 0;
-} //end of the function AAS_ShutDownReachabilityHeap
-//===========================================================================
-// returns a reachability link
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-aas_lreachability_t *AAS_AllocReachability(void)
-{
- aas_lreachability_t *r;
-
- if (!nextreachability) return NULL;
- //make sure the error message only shows up once
- if (!nextreachability->next) AAS_Error("AAS_MAX_REACHABILITYSIZE");
- //
- r = nextreachability;
- nextreachability = nextreachability->next;
- numlreachabilities++;
- return r;
-} //end of the function AAS_AllocReachability
-//===========================================================================
-// frees a reachability link
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FreeReachability(aas_lreachability_t *lreach)
-{
- Com_Memset(lreach, 0, sizeof(aas_lreachability_t));
-
- lreach->next = nextreachability;
- nextreachability = lreach;
- numlreachabilities--;
-} //end of the function AAS_FreeReachability
-//===========================================================================
-// returns qtrue if the area has reachability links
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaReachability(int areanum)
-{
- if (areanum < 0 || areanum >= aasworld.numareas)
- {
- AAS_Error("AAS_AreaReachability: areanum %d out of range", areanum);
- return 0;
- } //end if
- return aasworld.areasettings[areanum].numreachableareas;
-} //end of the function AAS_AreaReachability
-//===========================================================================
-// returns the surface area of all ground faces together of the area
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float AAS_AreaGroundFaceArea(int areanum)
-{
- int i;
- float total;
- aas_area_t *area;
- aas_face_t *face;
-
- total = 0;
- area = &aasworld.areas[areanum];
- for (i = 0; i < area->numfaces; i++)
- {
- face = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])];
- if (!(face->faceflags & FACE_GROUND)) continue;
- //
- total += AAS_FaceArea(face);
- } //end for
- return total;
-} //end of the function AAS_AreaGroundFaceArea
-//===========================================================================
-// returns the center of a face
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FaceCenter(int facenum, vec3_t center)
-{
- int i;
- float scale;
- aas_face_t *face;
- aas_edge_t *edge;
-
- face = &aasworld.faces[facenum];
-
- VectorClear(center);
- for (i = 0; i < face->numedges; i++)
- {
- edge = &aasworld.edges[abs(aasworld.edgeindex[face->firstedge + i])];
- VectorAdd(center, aasworld.vertexes[edge->v[0]], center);
- VectorAdd(center, aasworld.vertexes[edge->v[1]], center);
- } //end for
- scale = 0.5 / face->numedges;
- VectorScale(center, scale, center);
-} //end of the function AAS_FaceCenter
-//===========================================================================
-// returns the maximum distance a player can fall before being damaged
-// damage = deltavelocity*deltavelocity * 0.0001
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_FallDamageDistance(void)
-{
- float maxzvelocity, gravity, t;
-
- maxzvelocity = sqrt(30 * 10000);
- gravity = aassettings.phys_gravity;
- t = maxzvelocity / gravity;
- return 0.5 * gravity * t * t;
-} //end of the function AAS_FallDamageDistance
-//===========================================================================
-// distance = 0.5 * gravity * t * t
-// vel = t * gravity
-// damage = vel * vel * 0.0001
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float AAS_FallDelta(float distance)
-{
- float t, delta, gravity;
-
- gravity = aassettings.phys_gravity;
- t = sqrt(fabs(distance) * 2 / gravity);
- delta = t * gravity;
- return delta * delta * 0.0001;
-} //end of the function AAS_FallDelta
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float AAS_MaxJumpHeight(float phys_jumpvel)
-{
- float phys_gravity;
-
- phys_gravity = aassettings.phys_gravity;
- //maximum height a player can jump with the given initial z velocity
- return 0.5 * phys_gravity * (phys_jumpvel / phys_gravity) * (phys_jumpvel / phys_gravity);
-} //end of the function MaxJumpHeight
-//===========================================================================
-// returns true if a player can only crouch in the area
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float AAS_MaxJumpDistance(float phys_jumpvel)
-{
- float phys_gravity, phys_maxvelocity, t;
-
- phys_gravity = aassettings.phys_gravity;
- phys_maxvelocity = aassettings.phys_maxvelocity;
- //time a player takes to fall the height
- t = sqrt(aassettings.rs_maxjumpfallheight / (0.5 * phys_gravity));
- //maximum distance
- return phys_maxvelocity * (t + phys_jumpvel / phys_gravity);
-} //end of the function AAS_MaxJumpDistance
-//===========================================================================
-// returns true if a player can only crouch in the area
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaCrouch(int areanum)
-{
- if (!(aasworld.areasettings[areanum].presencetype & PRESENCE_NORMAL)) return qtrue;
- else return qfalse;
-} //end of the function AAS_AreaCrouch
-//===========================================================================
-// returns qtrue if it is possible to swim in the area
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaSwim(int areanum)
-{
- if (aasworld.areasettings[areanum].areaflags & AREA_LIQUID) return qtrue;
- else return qfalse;
-} //end of the function AAS_AreaSwim
-//===========================================================================
-// returns qtrue if the area contains a liquid
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaLiquid(int areanum)
-{
- if (aasworld.areasettings[areanum].areaflags & AREA_LIQUID) return qtrue;
- else return qfalse;
-} //end of the function AAS_AreaLiquid
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaLava(int areanum)
-{
- return (aasworld.areasettings[areanum].contents & AREACONTENTS_LAVA);
-} //end of the function AAS_AreaLava
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaSlime(int areanum)
-{
- return (aasworld.areasettings[areanum].contents & AREACONTENTS_SLIME);
-} //end of the function AAS_AreaSlime
-//===========================================================================
-// returns qtrue if the area contains ground faces
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaGrounded(int areanum)
-{
- return (aasworld.areasettings[areanum].areaflags & AREA_GROUNDED);
-} //end of the function AAS_AreaGround
-//===========================================================================
-// returns true if the area contains ladder faces
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaLadder(int areanum)
-{
- return (aasworld.areasettings[areanum].areaflags & AREA_LADDER);
-} //end of the function AAS_AreaLadder
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaJumpPad(int areanum)
-{
- return (aasworld.areasettings[areanum].contents & AREACONTENTS_JUMPPAD);
-} //end of the function AAS_AreaJumpPad
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaTeleporter(int areanum)
-{
- return (aasworld.areasettings[areanum].contents & AREACONTENTS_TELEPORTER);
-} //end of the function AAS_AreaTeleporter
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaClusterPortal(int areanum)
-{
- return (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL);
-} //end of the function AAS_AreaClusterPortal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaDoNotEnter(int areanum)
-{
- return (aasworld.areasettings[areanum].contents & AREACONTENTS_DONOTENTER);
-} //end of the function AAS_AreaDoNotEnter
-//===========================================================================
-// returns the time it takes perform a barrier jump
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-unsigned short int AAS_BarrierJumpTravelTime(void)
-{
- return aassettings.phys_jumpvel / (aassettings.phys_gravity * 0.1);
-} //end op the function AAS_BarrierJumpTravelTime
-//===========================================================================
-// returns true if there already exists a reachability from area1 to area2
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_ReachabilityExists(int area1num, int area2num)
-{
- aas_lreachability_t *r;
-
- for (r = areareachability[area1num]; r; r = r->next)
- {
- if (r->areanum == area2num) return qtrue;
- } //end for
- return qfalse;
-} //end of the function AAS_ReachabilityExists
-//===========================================================================
-// returns true if there is a solid just after the end point when going
-// from start to end
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_NearbySolidOrGap(vec3_t start, vec3_t end)
-{
- vec3_t dir, testpoint;
- int areanum;
-
- VectorSubtract(end, start, dir);
- dir[2] = 0;
- VectorNormalize(dir);
- VectorMA(end, 48, dir, testpoint);
-
- areanum = AAS_PointAreaNum(testpoint);
- if (!areanum)
- {
- testpoint[2] += 16;
- areanum = AAS_PointAreaNum(testpoint);
- if (!areanum) return qtrue;
- } //end if
- VectorMA(end, 64, dir, testpoint);
- areanum = AAS_PointAreaNum(testpoint);
- if (areanum)
- {
- if (!AAS_AreaSwim(areanum) && !AAS_AreaGrounded(areanum)) return qtrue;
- } //end if
- return qfalse;
-} //end of the function AAS_SolidGapTime
-//===========================================================================
-// searches for swim reachabilities between adjacent areas
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_Reachability_Swim(int area1num, int area2num)
-{
- int i, j, face1num, face2num, side1;
- aas_area_t *area1, *area2;
- aas_areasettings_t *areasettings;
- aas_lreachability_t *lreach;
- aas_face_t *face1;
- aas_plane_t *plane;
- vec3_t start;
-
- if (!AAS_AreaSwim(area1num) || !AAS_AreaSwim(area2num)) return qfalse;
- //if the second area is crouch only
- if (!(aasworld.areasettings[area2num].presencetype & PRESENCE_NORMAL)) return qfalse;
-
- area1 = &aasworld.areas[area1num];
- area2 = &aasworld.areas[area2num];
-
- //if the areas are not near anough
- for (i = 0; i < 3; i++)
- {
- if (area1->mins[i] > area2->maxs[i] + 10) return qfalse;
- if (area1->maxs[i] < area2->mins[i] - 10) return qfalse;
- } //end for
- //find a shared face and create a reachability link
- for (i = 0; i < area1->numfaces; i++)
- {
- face1num = aasworld.faceindex[area1->firstface + i];
- side1 = face1num < 0;
- face1num = abs(face1num);
- //
- for (j = 0; j < area2->numfaces; j++)
- {
- face2num = abs(aasworld.faceindex[area2->firstface + j]);
- //
- if (face1num == face2num)
- {
- AAS_FaceCenter(face1num, start);
- //
- if (AAS_PointContents(start) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))
- {
- //
- face1 = &aasworld.faces[face1num];
- areasettings = &aasworld.areasettings[area1num];
- //create a new reachability link
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area2num;
- lreach->facenum = face1num;
- lreach->edgenum = 0;
- VectorCopy(start, lreach->start);
- plane = &aasworld.planes[face1->planenum ^ side1];
- VectorMA(lreach->start, -INSIDEUNITS, plane->normal, lreach->end);
- lreach->traveltype = TRAVEL_SWIM;
- lreach->traveltime = 1;
- //if the volume of the area is rather small
- if (AAS_AreaVolume(area2num) < 800)
- lreach->traveltime += 200;
- //if (!(AAS_PointContents(start) & MASK_WATER)) lreach->traveltime += 500;
- //link the reachability
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- reach_swim++;
- return qtrue;
- } //end if
- } //end if
- } //end for
- } //end for
- return qfalse;
-} //end of the function AAS_Reachability_Swim
-//===========================================================================
-// searches for reachabilities between adjacent areas with equal floor
-// heights
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_Reachability_EqualFloorHeight(int area1num, int area2num)
-{
- int i, j, edgenum, edgenum1, edgenum2, foundreach, side;
- float height, bestheight, length, bestlength;
- vec3_t dir, start, end, normal, invgravity, gravitydirection = {0, 0, -1};
- vec3_t edgevec;
- aas_area_t *area1, *area2;
- aas_face_t *face1, *face2;
- aas_edge_t *edge;
- aas_plane_t *plane2;
- aas_lreachability_t lr, *lreach;
-
- if (!AAS_AreaGrounded(area1num) || !AAS_AreaGrounded(area2num)) return qfalse;
-
- area1 = &aasworld.areas[area1num];
- area2 = &aasworld.areas[area2num];
- //if the areas are not near anough in the x-y direction
- for (i = 0; i < 2; i++)
- {
- if (area1->mins[i] > area2->maxs[i] + 10) return qfalse;
- if (area1->maxs[i] < area2->mins[i] - 10) return qfalse;
- } //end for
- //if area 2 is too high above area 1
- if (area2->mins[2] > area1->maxs[2]) return qfalse;
- //
- VectorCopy(gravitydirection, invgravity);
- VectorInverse(invgravity);
- //
- bestheight = 99999;
- bestlength = 0;
- foundreach = qfalse;
- Com_Memset(&lr, 0, sizeof(aas_lreachability_t)); //make the compiler happy
- //
- //check if the areas have ground faces with a common edge
- //if existing use the lowest common edge for a reachability link
- for (i = 0; i < area1->numfaces; i++)
- {
- face1 = &aasworld.faces[abs(aasworld.faceindex[area1->firstface + i])];
- if (!(face1->faceflags & FACE_GROUND)) continue;
- //
- for (j = 0; j < area2->numfaces; j++)
- {
- face2 = &aasworld.faces[abs(aasworld.faceindex[area2->firstface + j])];
- if (!(face2->faceflags & FACE_GROUND)) continue;
- //if there is a common edge
- for (edgenum1 = 0; edgenum1 < face1->numedges; edgenum1++)
- {
- for (edgenum2 = 0; edgenum2 < face2->numedges; edgenum2++)
- {
- if (abs(aasworld.edgeindex[face1->firstedge + edgenum1]) !=
- abs(aasworld.edgeindex[face2->firstedge + edgenum2]))
- continue;
- edgenum = aasworld.edgeindex[face1->firstedge + edgenum1];
- side = edgenum < 0;
- edge = &aasworld.edges[abs(edgenum)];
- //get the length of the edge
- VectorSubtract(aasworld.vertexes[edge->v[1]],
- aasworld.vertexes[edge->v[0]], dir);
- length = VectorLength(dir);
- //get the start point
- VectorAdd(aasworld.vertexes[edge->v[0]],
- aasworld.vertexes[edge->v[1]], start);
- VectorScale(start, 0.5, start);
- VectorCopy(start, end);
- //get the end point several units inside area2
- //and the start point several units inside area1
- //NOTE: normal is pointing into area2 because the
- //face edges are stored counter clockwise
- VectorSubtract(aasworld.vertexes[edge->v[side]],
- aasworld.vertexes[edge->v[!side]], edgevec);
- plane2 = &aasworld.planes[face2->planenum];
- CrossProduct(edgevec, plane2->normal, normal);
- VectorNormalize(normal);
- //
- //VectorMA(start, -1, normal, start);
- VectorMA(end, INSIDEUNITS_WALKEND, normal, end);
- VectorMA(start, INSIDEUNITS_WALKSTART, normal, start);
- end[2] += 0.125;
- //
- height = DotProduct(invgravity, start);
- //NOTE: if there's nearby solid or a gap area after this area
- //disabled this crap
- //if (AAS_NearbySolidOrGap(start, end)) height += 200;
- //NOTE: disabled because it disables reachabilities to very small areas
- //if (AAS_PointAreaNum(end) != area2num) continue;
- //get the longest lowest edge
- if (height < bestheight ||
- (height < bestheight + 1 && length > bestlength))
- {
- bestheight = height;
- bestlength = length;
- //create a new reachability link
- lr.areanum = area2num;
- lr.facenum = 0;
- lr.edgenum = edgenum;
- VectorCopy(start, lr.start);
- VectorCopy(end, lr.end);
- lr.traveltype = TRAVEL_WALK;
- lr.traveltime = 1;
- foundreach = qtrue;
- } //end if
- } //end for
- } //end for
- } //end for
- } //end for
- if (foundreach)
- {
- //create a new reachability link
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = lr.areanum;
- lreach->facenum = lr.facenum;
- lreach->edgenum = lr.edgenum;
- VectorCopy(lr.start, lreach->start);
- VectorCopy(lr.end, lreach->end);
- lreach->traveltype = lr.traveltype;
- lreach->traveltime = lr.traveltime;
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //if going into a crouch area
- if (!AAS_AreaCrouch(area1num) && AAS_AreaCrouch(area2num))
- {
- lreach->traveltime += aassettings.rs_startcrouch;
- } //end if
- /*
- //NOTE: if there's nearby solid or a gap area after this area
- if (!AAS_NearbySolidOrGap(lreach->start, lreach->end))
- {
- lreach->traveltime += 100;
- } //end if
- */
- //avoid rather small areas
- //if (AAS_AreaGroundFaceArea(lreach->areanum) < 500) lreach->traveltime += 100;
- //
- reach_equalfloor++;
- return qtrue;
- } //end if
- return qfalse;
-} //end of the function AAS_Reachability_EqualFloorHeight
-//===========================================================================
-// searches step, barrier, waterjump and walk off ledge reachabilities
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge(int area1num, int area2num)
-{
- int i, j, k, l, edge1num, edge2num, areas[10], numareas;
- int ground_bestarea2groundedgenum, ground_foundreach;
- int water_bestarea2groundedgenum, water_foundreach;
- int side1, area1swim, faceside1, groundface1num;
- float dist, dist1, dist2, diff, invgravitydot, ortdot;
- float x1, x2, x3, x4, y1, y2, y3, y4, tmp, y;
- float length, ground_bestlength, water_bestlength, ground_bestdist, water_bestdist;
- vec3_t v1, v2, v3, v4, tmpv, p1area1, p1area2, p2area1, p2area2;
- vec3_t normal, ort, edgevec, start, end, dir;
- vec3_t ground_beststart = {0, 0, 0}, ground_bestend = {0, 0, 0}, ground_bestnormal = {0, 0, 0};
- vec3_t water_beststart = {0, 0, 0}, water_bestend = {0, 0, 0}, water_bestnormal = {0, 0, 0};
- vec3_t invgravity = {0, 0, 1};
- vec3_t testpoint;
- aas_plane_t *plane;
- aas_area_t *area1, *area2;
- aas_face_t *groundface1, *groundface2, *ground_bestface1, *water_bestface1;
- aas_edge_t *edge1, *edge2;
- aas_lreachability_t *lreach;
- aas_trace_t trace;
-
- //must be able to walk or swim in the first area
- if (!AAS_AreaGrounded(area1num) && !AAS_AreaSwim(area1num)) return qfalse;
- //
- if (!AAS_AreaGrounded(area2num) && !AAS_AreaSwim(area2num)) return qfalse;
- //
- area1 = &aasworld.areas[area1num];
- area2 = &aasworld.areas[area2num];
- //if the first area contains a liquid
- area1swim = AAS_AreaSwim(area1num);
- //if the areas are not near anough in the x-y direction
- for (i = 0; i < 2; i++)
- {
- if (area1->mins[i] > area2->maxs[i] + 10) return qfalse;
- if (area1->maxs[i] < area2->mins[i] - 10) return qfalse;
- } //end for
- //
- ground_foundreach = qfalse;
- ground_bestdist = 99999;
- ground_bestlength = 0;
- ground_bestarea2groundedgenum = 0;
- //
- water_foundreach = qfalse;
- water_bestdist = 99999;
- water_bestlength = 0;
- water_bestarea2groundedgenum = 0;
- //
- for (i = 0; i < area1->numfaces; i++)
- {
- groundface1num = aasworld.faceindex[area1->firstface + i];
- faceside1 = groundface1num < 0;
- groundface1 = &aasworld.faces[abs(groundface1num)];
- //if this isn't a ground face
- if (!(groundface1->faceflags & FACE_GROUND))
- {
- //if we can swim in the first area
- if (area1swim)
- {
- //face plane must be more or less horizontal
- plane = &aasworld.planes[groundface1->planenum ^ (!faceside1)];
- if (DotProduct(plane->normal, invgravity) < 0.7) continue;
- } //end if
- else
- {
- //if we can't swim in the area it must be a ground face
- continue;
- } //end else
- } //end if
- //
- for (k = 0; k < groundface1->numedges; k++)
- {
- edge1num = aasworld.edgeindex[groundface1->firstedge + k];
- side1 = (edge1num < 0);
- //NOTE: for water faces we must take the side area 1 is
- // on into account because the face is shared and doesn't
- // have to be oriented correctly
- if (!(groundface1->faceflags & FACE_GROUND)) side1 = (side1 == faceside1);
- edge1num = abs(edge1num);
- edge1 = &aasworld.edges[edge1num];
- //vertexes of the edge
- VectorCopy(aasworld.vertexes[edge1->v[!side1]], v1);
- VectorCopy(aasworld.vertexes[edge1->v[side1]], v2);
- //get a vertical plane through the edge
- //NOTE: normal is pointing into area 2 because the
- //face edges are stored counter clockwise
- VectorSubtract(v2, v1, edgevec);
- CrossProduct(edgevec, invgravity, normal);
- VectorNormalize(normal);
- dist = DotProduct(normal, v1);
- //check the faces from the second area
- for (j = 0; j < area2->numfaces; j++)
- {
- groundface2 = &aasworld.faces[abs(aasworld.faceindex[area2->firstface + j])];
- //must be a ground face
- if (!(groundface2->faceflags & FACE_GROUND)) continue;
- //check the edges of this ground face
- for (l = 0; l < groundface2->numedges; l++)
- {
- edge2num = abs(aasworld.edgeindex[groundface2->firstedge + l]);
- edge2 = &aasworld.edges[edge2num];
- //vertexes of the edge
- VectorCopy(aasworld.vertexes[edge2->v[0]], v3);
- VectorCopy(aasworld.vertexes[edge2->v[1]], v4);
- //check the distance between the two points and the vertical plane
- //through the edge of area1
- diff = DotProduct(normal, v3) - dist;
- if (diff < -0.1 || diff > 0.1) continue;
- diff = DotProduct(normal, v4) - dist;
- if (diff < -0.1 || diff > 0.1) continue;
- //
- //project the two ground edges into the step side plane
- //and calculate the shortest distance between the two
- //edges if they overlap in the direction orthogonal to
- //the gravity direction
- CrossProduct(invgravity, normal, ort);
- invgravitydot = DotProduct(invgravity, invgravity);
- ortdot = DotProduct(ort, ort);
- //projection into the step plane
- //NOTE: since gravity is vertical this is just the z coordinate
- y1 = v1[2];//DotProduct(v1, invgravity) / invgravitydot;
- y2 = v2[2];//DotProduct(v2, invgravity) / invgravitydot;
- y3 = v3[2];//DotProduct(v3, invgravity) / invgravitydot;
- y4 = v4[2];//DotProduct(v4, invgravity) / invgravitydot;
- //
- x1 = DotProduct(v1, ort) / ortdot;
- x2 = DotProduct(v2, ort) / ortdot;
- x3 = DotProduct(v3, ort) / ortdot;
- x4 = DotProduct(v4, ort) / ortdot;
- //
- if (x1 > x2)
- {
- tmp = x1; x1 = x2; x2 = tmp;
- tmp = y1; y1 = y2; y2 = tmp;
- VectorCopy(v1, tmpv); VectorCopy(v2, v1); VectorCopy(tmpv, v2);
- } //end if
- if (x3 > x4)
- {
- tmp = x3; x3 = x4; x4 = tmp;
- tmp = y3; y3 = y4; y4 = tmp;
- VectorCopy(v3, tmpv); VectorCopy(v4, v3); VectorCopy(tmpv, v4);
- } //end if
- //if the two projected edge lines have no overlap
- if (x2 <= x3 || x4 <= x1)
- {
-// Log_Write("lines no overlap: from area %d to %d\r\n", area1num, area2num);
- continue;
- } //end if
- //if the two lines fully overlap
- if ((x1 - 0.5 < x3 && x4 < x2 + 0.5) &&
- (x3 - 0.5 < x1 && x2 < x4 + 0.5))
- {
- dist1 = y3 - y1;
- dist2 = y4 - y2;
- VectorCopy(v1, p1area1);
- VectorCopy(v2, p2area1);
- VectorCopy(v3, p1area2);
- VectorCopy(v4, p2area2);
- } //end if
- else
- {
- //if the points are equal
- if (x1 > x3 - 0.1 && x1 < x3 + 0.1)
- {
- dist1 = y3 - y1;
- VectorCopy(v1, p1area1);
- VectorCopy(v3, p1area2);
- } //end if
- else if (x1 < x3)
- {
- y = y1 + (x3 - x1) * (y2 - y1) / (x2 - x1);
- dist1 = y3 - y;
- VectorCopy(v3, p1area1);
- p1area1[2] = y;
- VectorCopy(v3, p1area2);
- } //end if
- else
- {
- y = y3 + (x1 - x3) * (y4 - y3) / (x4 - x3);
- dist1 = y - y1;
- VectorCopy(v1, p1area1);
- VectorCopy(v1, p1area2);
- p1area2[2] = y;
- } //end if
- //if the points are equal
- if (x2 > x4 - 0.1 && x2 < x4 + 0.1)
- {
- dist2 = y4 - y2;
- VectorCopy(v2, p2area1);
- VectorCopy(v4, p2area2);
- } //end if
- else if (x2 < x4)
- {
- y = y3 + (x2 - x3) * (y4 - y3) / (x4 - x3);
- dist2 = y - y2;
- VectorCopy(v2, p2area1);
- VectorCopy(v2, p2area2);
- p2area2[2] = y;
- } //end if
- else
- {
- y = y1 + (x4 - x1) * (y2 - y1) / (x2 - x1);
- dist2 = y4 - y;
- VectorCopy(v4, p2area1);
- p2area1[2] = y;
- VectorCopy(v4, p2area2);
- } //end else
- } //end else
- //if both distances are pretty much equal
- //then we take the middle of the points
- if (dist1 > dist2 - 1 && dist1 < dist2 + 1)
- {
- dist = dist1;
- VectorAdd(p1area1, p2area1, start);
- VectorScale(start, 0.5, start);
- VectorAdd(p1area2, p2area2, end);
- VectorScale(end, 0.5, end);
- } //end if
- else if (dist1 < dist2)
- {
- dist = dist1;
- VectorCopy(p1area1, start);
- VectorCopy(p1area2, end);
- } //end else if
- else
- {
- dist = dist2;
- VectorCopy(p2area1, start);
- VectorCopy(p2area2, end);
- } //end else
- //get the length of the overlapping part of the edges of the two areas
- VectorSubtract(p2area2, p1area2, dir);
- length = VectorLength(dir);
- //
- if (groundface1->faceflags & FACE_GROUND)
- {
- //if the vertical distance is smaller
- if (dist < ground_bestdist ||
- //or the vertical distance is pretty much the same
- //but the overlapping part of the edges is longer
- (dist < ground_bestdist + 1 && length > ground_bestlength))
- {
- ground_bestdist = dist;
- ground_bestlength = length;
- ground_foundreach = qtrue;
- ground_bestarea2groundedgenum = edge1num;
- ground_bestface1 = groundface1;
- //best point towards area1
- VectorCopy(start, ground_beststart);
- //normal is pointing into area2
- VectorCopy(normal, ground_bestnormal);
- //best point towards area2
- VectorCopy(end, ground_bestend);
- } //end if
- } //end if
- else
- {
- //if the vertical distance is smaller
- if (dist < water_bestdist ||
- //or the vertical distance is pretty much the same
- //but the overlapping part of the edges is longer
- (dist < water_bestdist + 1 && length > water_bestlength))
- {
- water_bestdist = dist;
- water_bestlength = length;
- water_foundreach = qtrue;
- water_bestarea2groundedgenum = edge1num;
- water_bestface1 = groundface1;
- //best point towards area1
- VectorCopy(start, water_beststart);
- //normal is pointing into area2
- VectorCopy(normal, water_bestnormal);
- //best point towards area2
- VectorCopy(end, water_bestend);
- } //end if
- } //end else
- } //end for
- } //end for
- } //end for
- } //end for
- //
- // NOTE: swim reachabilities are already filtered out
- //
- // Steps
- //
- // ---------
- // | step height -> TRAVEL_WALK
- //--------|
- //
- // ---------
- //~~~~~~~~| step height and low water -> TRAVEL_WALK
- //--------|
- //
- //~~~~~~~~~~~~~~~~~~
- // ---------
- // | step height and low water up to the step -> TRAVEL_WALK
- //--------|
- //
- //check for a step reachability
- if (ground_foundreach)
- {
- //if area2 is higher but lower than the maximum step height
- //NOTE: ground_bestdist >= 0 also catches equal floor reachabilities
- if (ground_bestdist >= 0 && ground_bestdist < aassettings.phys_maxstep)
- {
- //create walk reachability from area1 to area2
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area2num;
- lreach->facenum = 0;
- lreach->edgenum = ground_bestarea2groundedgenum;
- VectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start);
- VectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end);
- lreach->traveltype = TRAVEL_WALK;
- lreach->traveltime = 0;//1;
- //if going into a crouch area
- if (!AAS_AreaCrouch(area1num) && AAS_AreaCrouch(area2num))
- {
- lreach->traveltime += aassettings.rs_startcrouch;
- } //end if
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //NOTE: if there's nearby solid or a gap area after this area
- /*
- if (!AAS_NearbySolidOrGap(lreach->start, lreach->end))
- {
- lreach->traveltime += 100;
- } //end if
- */
- //avoid rather small areas
- //if (AAS_AreaGroundFaceArea(lreach->areanum) < 500) lreach->traveltime += 100;
- //
- reach_step++;
- return qtrue;
- } //end if
- } //end if
- //
- // Water Jumps
- //
- // ---------
- // |
- //~~~~~~~~|
- // |
- // | higher than step height and water up to waterjump height -> TRAVEL_WATERJUMP
- //--------|
- //
- //~~~~~~~~~~~~~~~~~~
- // ---------
- // |
- // |
- // |
- // | higher than step height and low water up to the step -> TRAVEL_WATERJUMP
- //--------|
- //
- //check for a waterjump reachability
- if (water_foundreach)
- {
- //get a test point a little bit towards area1
- VectorMA(water_bestend, -INSIDEUNITS, water_bestnormal, testpoint);
- //go down the maximum waterjump height
- testpoint[2] -= aassettings.phys_maxwaterjump;
- //if there IS water the sv_maxwaterjump height below the bestend point
- if (aasworld.areasettings[AAS_PointAreaNum(testpoint)].areaflags & AREA_LIQUID)
- {
- //don't create rediculous water jump reachabilities from areas very far below
- //the water surface
- if (water_bestdist < aassettings.phys_maxwaterjump + 24)
- {
- //waterjumping from or towards a crouch only area is not possible in Quake2
- if ((aasworld.areasettings[area1num].presencetype & PRESENCE_NORMAL) &&
- (aasworld.areasettings[area2num].presencetype & PRESENCE_NORMAL))
- {
- //create water jump reachability from area1 to area2
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area2num;
- lreach->facenum = 0;
- lreach->edgenum = water_bestarea2groundedgenum;
- VectorCopy(water_beststart, lreach->start);
- VectorMA(water_bestend, INSIDEUNITS_WATERJUMP, water_bestnormal, lreach->end);
- lreach->traveltype = TRAVEL_WATERJUMP;
- lreach->traveltime = aassettings.rs_waterjump;
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //we've got another waterjump reachability
- reach_waterjump++;
- return qtrue;
- } //end if
- } //end if
- } //end if
- } //end if
- //
- // Barrier Jumps
- //
- // ---------
- // |
- // |
- // |
- // | higher than step height lower than barrier height -> TRAVEL_BARRIERJUMP
- //--------|
- //
- // ---------
- // |
- // |
- // |
- //~~~~~~~~| higher than step height lower than barrier height
- //--------| and a thin layer of water in the area to jump from -> TRAVEL_BARRIERJUMP
- //
- //check for a barrier jump reachability
- if (ground_foundreach)
- {
- //if area2 is higher but lower than the maximum barrier jump height
- if (ground_bestdist > 0 && ground_bestdist < aassettings.phys_maxbarrier)
- {
- //if no water in area1 or a very thin layer of water on the ground
- if (!water_foundreach || (ground_bestdist - water_bestdist < 16))
- {
- //cannot perform a barrier jump towards or from a crouch area in Quake2
- if (!AAS_AreaCrouch(area1num) && !AAS_AreaCrouch(area2num))
- {
- //create barrier jump reachability from area1 to area2
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area2num;
- lreach->facenum = 0;
- lreach->edgenum = ground_bestarea2groundedgenum;
- VectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start);
- VectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end);
- lreach->traveltype = TRAVEL_BARRIERJUMP;
- lreach->traveltime = aassettings.rs_barrierjump;//AAS_BarrierJumpTravelTime();
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //we've got another barrierjump reachability
- reach_barrier++;
- return qtrue;
- } //end if
- } //end if
- } //end if
- } //end if
- //
- // Walk and Walk Off Ledge
- //
- //--------|
- // | can walk or step back -> TRAVEL_WALK
- // ---------
- //
- //--------|
- // |
- // |
- // |
- // | cannot walk/step back -> TRAVEL_WALKOFFLEDGE
- // ---------
- //
- //--------|
- // |
- // |~~~~~~~~
- // |
- // | cannot step back but can waterjump back -> TRAVEL_WALKOFFLEDGE
- // --------- FIXME: create TRAVEL_WALK reach??
- //
- //check for a walk or walk off ledge reachability
- if (ground_foundreach)
- {
- if (ground_bestdist < 0)
- {
- if (ground_bestdist > -aassettings.phys_maxstep)
- {
- //create walk reachability from area1 to area2
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area2num;
- lreach->facenum = 0;
- lreach->edgenum = ground_bestarea2groundedgenum;
- VectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start);
- VectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end);
- lreach->traveltype = TRAVEL_WALK;
- lreach->traveltime = 1;
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //we've got another walk reachability
- reach_walk++;
- return qtrue;
- } //end if
- // if no maximum fall height set or less than the max
- if (!aassettings.rs_maxfallheight || fabs(ground_bestdist) < aassettings.rs_maxfallheight) {
- //trace a bounding box vertically to check for solids
- VectorMA(ground_bestend, INSIDEUNITS, ground_bestnormal, ground_bestend);
- VectorCopy(ground_bestend, start);
- start[2] = ground_beststart[2];
- VectorCopy(ground_bestend, end);
- end[2] += 4;
- trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1);
- //if no solids were found
- if (!trace.startsolid && trace.fraction >= 1.0)
- {
- //the trace end point must be in the goal area
- trace.endpos[2] += 1;
- if (AAS_PointAreaNum(trace.endpos) == area2num)
- {
- //if not going through a cluster portal
- numareas = AAS_TraceAreas(start, end, areas, NULL, sizeof(areas) / sizeof(int));
- for (i = 0; i < numareas; i++)
- if (AAS_AreaClusterPortal(areas[i]))
- break;
- if (i >= numareas)
- {
- //create a walk off ledge reachability from area1 to area2
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area2num;
- lreach->facenum = 0;
- lreach->edgenum = ground_bestarea2groundedgenum;
- VectorCopy(ground_beststart, lreach->start);
- VectorCopy(ground_bestend, lreach->end);
- lreach->traveltype = TRAVEL_WALKOFFLEDGE;
- lreach->traveltime = aassettings.rs_startwalkoffledge + fabs(ground_bestdist) * 50 / aassettings.phys_gravity;
- //if falling from too high and not falling into water
- if (!AAS_AreaSwim(area2num) && !AAS_AreaJumpPad(area2num))
- {
- if (AAS_FallDelta(ground_bestdist) > aassettings.phys_falldelta5)
- {
- lreach->traveltime += aassettings.rs_falldamage5;
- } //end if
- if (AAS_FallDelta(ground_bestdist) > aassettings.phys_falldelta10)
- {
- lreach->traveltime += aassettings.rs_falldamage10;
- } //end if
- } //end if
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //
- reach_walkoffledge++;
- //NOTE: don't create a weapon (rl, bfg) jump reachability here
- //because it interferes with other reachabilities
- //like the ladder reachability
- return qtrue;
- } //end if
- } //end if
- } //end if
- } //end if
- } //end else
- } //end if
- return qfalse;
-} //end of the function AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge
-//===========================================================================
-// returns the distance between the two vectors
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float VectorDistance(vec3_t v1, vec3_t v2)
-{
- vec3_t dir;
-
- VectorSubtract(v2, v1, dir);
- return VectorLength(dir);
-} //end of the function VectorDistance
-//===========================================================================
-// returns true if the first vector is between the last two vectors
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int VectorBetweenVectors(vec3_t v, vec3_t v1, vec3_t v2)
-{
- vec3_t dir1, dir2;
-
- VectorSubtract(v, v1, dir1);
- VectorSubtract(v, v2, dir2);
- return (DotProduct(dir1, dir2) <= 0);
-} //end of the function VectorBetweenVectors
-//===========================================================================
-// returns the mid point between the two vectors
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void VectorMiddle(vec3_t v1, vec3_t v2, vec3_t middle)
-{
- VectorAdd(v1, v2, middle);
- VectorScale(middle, 0.5, middle);
-} //end of the function VectorMiddle
-//===========================================================================
-// calculate a range of points closest to each other on both edges
-//
-// Parameter: beststart1 start of the range of points on edge v1-v2
-// beststart2 end of the range of points on edge v1-v2
-// bestend1 start of the range of points on edge v3-v4
-// bestend2 end of the range of points on edge v3-v4
-// bestdist best distance so far
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-/*
-float AAS_ClosestEdgePoints(vec3_t v1, vec3_t v2, vec3_t v3, vec3_t v4,
- aas_plane_t *plane1, aas_plane_t *plane2,
- vec3_t beststart, vec3_t bestend, float bestdist)
-{
- vec3_t dir1, dir2, p1, p2, p3, p4;
- float a1, a2, b1, b2, dist;
- int founddist;
-
- //edge vectors
- VectorSubtract(v2, v1, dir1);
- VectorSubtract(v4, v3, dir2);
- //get the horizontal directions
- dir1[2] = 0;
- dir2[2] = 0;
- //
- // p1 = point on an edge vector of area2 closest to v1
- // p2 = point on an edge vector of area2 closest to v2
- // p3 = point on an edge vector of area1 closest to v3
- // p4 = point on an edge vector of area1 closest to v4
- //
- if (dir2[0])
- {
- a2 = dir2[1] / dir2[0];
- b2 = v3[1] - a2 * v3[0];
- //point on the edge vector of area2 closest to v1
- p1[0] = (DotProduct(v1, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0];
- p1[1] = a2 * p1[0] + b2;
- //point on the edge vector of area2 closest to v2
- p2[0] = (DotProduct(v2, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0];
- p2[1] = a2 * p2[0] + b2;
- } //end if
- else
- {
- //point on the edge vector of area2 closest to v1
- p1[0] = v3[0];
- p1[1] = v1[1];
- //point on the edge vector of area2 closest to v2
- p2[0] = v3[0];
- p2[1] = v2[1];
- } //end else
- //
- if (dir1[0])
- {
- //
- a1 = dir1[1] / dir1[0];
- b1 = v1[1] - a1 * v1[0];
- //point on the edge vector of area1 closest to v3
- p3[0] = (DotProduct(v3, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0];
- p3[1] = a1 * p3[0] + b1;
- //point on the edge vector of area1 closest to v4
- p4[0] = (DotProduct(v4, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0];
- p4[1] = a1 * p4[0] + b1;
- } //end if
- else
- {
- //point on the edge vector of area1 closest to v3
- p3[0] = v1[0];
- p3[1] = v3[1];
- //point on the edge vector of area1 closest to v4
- p4[0] = v1[0];
- p4[1] = v4[1];
- } //end else
- //start with zero z-coordinates
- p1[2] = 0;
- p2[2] = 0;
- p3[2] = 0;
- p4[2] = 0;
- //calculate the z-coordinates from the ground planes
- p1[2] = (plane2->dist - DotProduct(plane2->normal, p1)) / plane2->normal[2];
- p2[2] = (plane2->dist - DotProduct(plane2->normal, p2)) / plane2->normal[2];
- p3[2] = (plane1->dist - DotProduct(plane1->normal, p3)) / plane1->normal[2];
- p4[2] = (plane1->dist - DotProduct(plane1->normal, p4)) / plane1->normal[2];
- //
- founddist = qfalse;
- //
- if (VectorBetweenVectors(p1, v3, v4))
- {
- dist = VectorDistance(v1, p1);
- if (dist > bestdist - 0.5 && dist < bestdist + 0.5)
- {
- VectorMiddle(beststart, v1, beststart);
- VectorMiddle(bestend, p1, bestend);
- } //end if
- else if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(v1, beststart);
- VectorCopy(p1, bestend);
- } //end if
- founddist = qtrue;
- } //end if
- if (VectorBetweenVectors(p2, v3, v4))
- {
- dist = VectorDistance(v2, p2);
- if (dist > bestdist - 0.5 && dist < bestdist + 0.5)
- {
- VectorMiddle(beststart, v2, beststart);
- VectorMiddle(bestend, p2, bestend);
- } //end if
- else if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(v2, beststart);
- VectorCopy(p2, bestend);
- } //end if
- founddist = qtrue;
- } //end else if
- if (VectorBetweenVectors(p3, v1, v2))
- {
- dist = VectorDistance(v3, p3);
- if (dist > bestdist - 0.5 && dist < bestdist + 0.5)
- {
- VectorMiddle(beststart, p3, beststart);
- VectorMiddle(bestend, v3, bestend);
- } //end if
- else if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(p3, beststart);
- VectorCopy(v3, bestend);
- } //end if
- founddist = qtrue;
- } //end else if
- if (VectorBetweenVectors(p4, v1, v2))
- {
- dist = VectorDistance(v4, p4);
- if (dist > bestdist - 0.5 && dist < bestdist + 0.5)
- {
- VectorMiddle(beststart, p4, beststart);
- VectorMiddle(bestend, v4, bestend);
- } //end if
- else if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(p4, beststart);
- VectorCopy(v4, bestend);
- } //end if
- founddist = qtrue;
- } //end else if
- //if no shortest distance was found the shortest distance
- //is between one of the vertexes of edge1 and one of edge2
- if (!founddist)
- {
- dist = VectorDistance(v1, v3);
- if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(v1, beststart);
- VectorCopy(v3, bestend);
- } //end if
- dist = VectorDistance(v1, v4);
- if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(v1, beststart);
- VectorCopy(v4, bestend);
- } //end if
- dist = VectorDistance(v2, v3);
- if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(v2, beststart);
- VectorCopy(v3, bestend);
- } //end if
- dist = VectorDistance(v2, v4);
- if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(v2, beststart);
- VectorCopy(v4, bestend);
- } //end if
- } //end if
- return bestdist;
-} //end of the function AAS_ClosestEdgePoints*/
-
-float AAS_ClosestEdgePoints(vec3_t v1, vec3_t v2, vec3_t v3, vec3_t v4,
- aas_plane_t *plane1, aas_plane_t *plane2,
- vec3_t beststart1, vec3_t bestend1,
- vec3_t beststart2, vec3_t bestend2, float bestdist)
-{
- vec3_t dir1, dir2, p1, p2, p3, p4;
- float a1, a2, b1, b2, dist, dist1, dist2;
- int founddist;
-
- //edge vectors
- VectorSubtract(v2, v1, dir1);
- VectorSubtract(v4, v3, dir2);
- //get the horizontal directions
- dir1[2] = 0;
- dir2[2] = 0;
- //
- // p1 = point on an edge vector of area2 closest to v1
- // p2 = point on an edge vector of area2 closest to v2
- // p3 = point on an edge vector of area1 closest to v3
- // p4 = point on an edge vector of area1 closest to v4
- //
- if (dir2[0])
- {
- a2 = dir2[1] / dir2[0];
- b2 = v3[1] - a2 * v3[0];
- //point on the edge vector of area2 closest to v1
- p1[0] = (DotProduct(v1, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0];
- p1[1] = a2 * p1[0] + b2;
- //point on the edge vector of area2 closest to v2
- p2[0] = (DotProduct(v2, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0];
- p2[1] = a2 * p2[0] + b2;
- } //end if
- else
- {
- //point on the edge vector of area2 closest to v1
- p1[0] = v3[0];
- p1[1] = v1[1];
- //point on the edge vector of area2 closest to v2
- p2[0] = v3[0];
- p2[1] = v2[1];
- } //end else
- //
- if (dir1[0])
- {
- //
- a1 = dir1[1] / dir1[0];
- b1 = v1[1] - a1 * v1[0];
- //point on the edge vector of area1 closest to v3
- p3[0] = (DotProduct(v3, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0];
- p3[1] = a1 * p3[0] + b1;
- //point on the edge vector of area1 closest to v4
- p4[0] = (DotProduct(v4, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0];
- p4[1] = a1 * p4[0] + b1;
- } //end if
- else
- {
- //point on the edge vector of area1 closest to v3
- p3[0] = v1[0];
- p3[1] = v3[1];
- //point on the edge vector of area1 closest to v4
- p4[0] = v1[0];
- p4[1] = v4[1];
- } //end else
- //start with zero z-coordinates
- p1[2] = 0;
- p2[2] = 0;
- p3[2] = 0;
- p4[2] = 0;
- //calculate the z-coordinates from the ground planes
- p1[2] = (plane2->dist - DotProduct(plane2->normal, p1)) / plane2->normal[2];
- p2[2] = (plane2->dist - DotProduct(plane2->normal, p2)) / plane2->normal[2];
- p3[2] = (plane1->dist - DotProduct(plane1->normal, p3)) / plane1->normal[2];
- p4[2] = (plane1->dist - DotProduct(plane1->normal, p4)) / plane1->normal[2];
- //
- founddist = qfalse;
- //
- if (VectorBetweenVectors(p1, v3, v4))
- {
- dist = VectorDistance(v1, p1);
- if (dist > bestdist - 0.5 && dist < bestdist + 0.5)
- {
- dist1 = VectorDistance(beststart1, v1);
- dist2 = VectorDistance(beststart2, v1);
- if (dist1 > dist2)
- {
- if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(v1, beststart2);
- } //end if
- else
- {
- if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(v1, beststart1);
- } //end else
- dist1 = VectorDistance(bestend1, p1);
- dist2 = VectorDistance(bestend2, p1);
- if (dist1 > dist2)
- {
- if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(p1, bestend2);
- } //end if
- else
- {
- if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(p1, bestend1);
- } //end else
- } //end if
- else if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(v1, beststart1);
- VectorCopy(v1, beststart2);
- VectorCopy(p1, bestend1);
- VectorCopy(p1, bestend2);
- } //end if
- founddist = qtrue;
- } //end if
- if (VectorBetweenVectors(p2, v3, v4))
- {
- dist = VectorDistance(v2, p2);
- if (dist > bestdist - 0.5 && dist < bestdist + 0.5)
- {
- dist1 = VectorDistance(beststart1, v2);
- dist2 = VectorDistance(beststart2, v2);
- if (dist1 > dist2)
- {
- if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(v2, beststart2);
- } //end if
- else
- {
- if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(v2, beststart1);
- } //end else
- dist1 = VectorDistance(bestend1, p2);
- dist2 = VectorDistance(bestend2, p2);
- if (dist1 > dist2)
- {
- if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(p2, bestend2);
- } //end if
- else
- {
- if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(p2, bestend1);
- } //end else
- } //end if
- else if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(v2, beststart1);
- VectorCopy(v2, beststart2);
- VectorCopy(p2, bestend1);
- VectorCopy(p2, bestend2);
- } //end if
- founddist = qtrue;
- } //end else if
- if (VectorBetweenVectors(p3, v1, v2))
- {
- dist = VectorDistance(v3, p3);
- if (dist > bestdist - 0.5 && dist < bestdist + 0.5)
- {
- dist1 = VectorDistance(beststart1, p3);
- dist2 = VectorDistance(beststart2, p3);
- if (dist1 > dist2)
- {
- if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(p3, beststart2);
- } //end if
- else
- {
- if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(p3, beststart1);
- } //end else
- dist1 = VectorDistance(bestend1, v3);
- dist2 = VectorDistance(bestend2, v3);
- if (dist1 > dist2)
- {
- if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(v3, bestend2);
- } //end if
- else
- {
- if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(v3, bestend1);
- } //end else
- } //end if
- else if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(p3, beststart1);
- VectorCopy(p3, beststart2);
- VectorCopy(v3, bestend1);
- VectorCopy(v3, bestend2);
- } //end if
- founddist = qtrue;
- } //end else if
- if (VectorBetweenVectors(p4, v1, v2))
- {
- dist = VectorDistance(v4, p4);
- if (dist > bestdist - 0.5 && dist < bestdist + 0.5)
- {
- dist1 = VectorDistance(beststart1, p4);
- dist2 = VectorDistance(beststart2, p4);
- if (dist1 > dist2)
- {
- if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(p4, beststart2);
- } //end if
- else
- {
- if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(p4, beststart1);
- } //end else
- dist1 = VectorDistance(bestend1, v4);
- dist2 = VectorDistance(bestend2, v4);
- if (dist1 > dist2)
- {
- if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(v4, bestend2);
- } //end if
- else
- {
- if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(v4, bestend1);
- } //end else
- } //end if
- else if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(p4, beststart1);
- VectorCopy(p4, beststart2);
- VectorCopy(v4, bestend1);
- VectorCopy(v4, bestend2);
- } //end if
- founddist = qtrue;
- } //end else if
- //if no shortest distance was found the shortest distance
- //is between one of the vertexes of edge1 and one of edge2
- if (!founddist)
- {
- dist = VectorDistance(v1, v3);
- if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(v1, beststart1);
- VectorCopy(v1, beststart2);
- VectorCopy(v3, bestend1);
- VectorCopy(v3, bestend2);
- } //end if
- dist = VectorDistance(v1, v4);
- if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(v1, beststart1);
- VectorCopy(v1, beststart2);
- VectorCopy(v4, bestend1);
- VectorCopy(v4, bestend2);
- } //end if
- dist = VectorDistance(v2, v3);
- if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(v2, beststart1);
- VectorCopy(v2, beststart2);
- VectorCopy(v3, bestend1);
- VectorCopy(v3, bestend2);
- } //end if
- dist = VectorDistance(v2, v4);
- if (dist < bestdist)
- {
- bestdist = dist;
- VectorCopy(v2, beststart1);
- VectorCopy(v2, beststart2);
- VectorCopy(v4, bestend1);
- VectorCopy(v4, bestend2);
- } //end if
- } //end if
- return bestdist;
-} //end of the function AAS_ClosestEdgePoints
-//===========================================================================
-// creates possible jump reachabilities between the areas
-//
-// The two closest points on the ground of the areas are calculated
-// One of the points will be on an edge of a ground face of area1 and
-// one on an edge of a ground face of area2.
-// If there is a range of closest points the point in the middle of this range
-// is selected.
-// Between these two points there must be one or more gaps.
-// If the gaps exist a potential jump is predicted.
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_Reachability_Jump(int area1num, int area2num)
-{
- int i, j, k, l, face1num, face2num, edge1num, edge2num, traveltype;
- int stopevent, areas[10], numareas;
- float phys_jumpvel, maxjumpdistance, maxjumpheight, height, bestdist, speed;
- vec_t *v1, *v2, *v3, *v4;
- vec3_t beststart, beststart2, bestend, bestend2;
- vec3_t teststart, testend, dir, velocity, cmdmove, up = {0, 0, 1}, sidewards;
- aas_area_t *area1, *area2;
- aas_face_t *face1, *face2;
- aas_edge_t *edge1, *edge2;
- aas_plane_t *plane1, *plane2, *plane;
- aas_trace_t trace;
- aas_clientmove_t move;
- aas_lreachability_t *lreach;
-
- if (!AAS_AreaGrounded(area1num) || !AAS_AreaGrounded(area2num)) return qfalse;
- //cannot jump from or to a crouch area
- if (AAS_AreaCrouch(area1num) || AAS_AreaCrouch(area2num)) return qfalse;
- //
- area1 = &aasworld.areas[area1num];
- area2 = &aasworld.areas[area2num];
- //
- phys_jumpvel = aassettings.phys_jumpvel;
- //maximum distance a player can jump
- maxjumpdistance = 2 * AAS_MaxJumpDistance(phys_jumpvel);
- //maximum height a player can jump with the given initial z velocity
- maxjumpheight = AAS_MaxJumpHeight(phys_jumpvel);
-
- //if the areas are not near anough in the x-y direction
- for (i = 0; i < 2; i++)
- {
- if (area1->mins[i] > area2->maxs[i] + maxjumpdistance) return qfalse;
- if (area1->maxs[i] < area2->mins[i] - maxjumpdistance) return qfalse;
- } //end for
- //if area2 is way to high to jump up to
- if (area2->mins[2] > area1->maxs[2] + maxjumpheight) return qfalse;
- //
- bestdist = 999999;
- //
- for (i = 0; i < area1->numfaces; i++)
- {
- face1num = aasworld.faceindex[area1->firstface + i];
- face1 = &aasworld.faces[abs(face1num)];
- //if not a ground face
- if (!(face1->faceflags & FACE_GROUND)) continue;
- //
- for (j = 0; j < area2->numfaces; j++)
- {
- face2num = aasworld.faceindex[area2->firstface + j];
- face2 = &aasworld.faces[abs(face2num)];
- //if not a ground face
- if (!(face2->faceflags & FACE_GROUND)) continue;
- //
- for (k = 0; k < face1->numedges; k++)
- {
- edge1num = abs(aasworld.edgeindex[face1->firstedge + k]);
- edge1 = &aasworld.edges[edge1num];
- for (l = 0; l < face2->numedges; l++)
- {
- edge2num = abs(aasworld.edgeindex[face2->firstedge + l]);
- edge2 = &aasworld.edges[edge2num];
- //calculate the minimum distance between the two edges
- v1 = aasworld.vertexes[edge1->v[0]];
- v2 = aasworld.vertexes[edge1->v[1]];
- v3 = aasworld.vertexes[edge2->v[0]];
- v4 = aasworld.vertexes[edge2->v[1]];
- //get the ground planes
- plane1 = &aasworld.planes[face1->planenum];
- plane2 = &aasworld.planes[face2->planenum];
- //
- bestdist = AAS_ClosestEdgePoints(v1, v2, v3, v4, plane1, plane2,
- beststart, bestend,
- beststart2, bestend2, bestdist);
- } //end for
- } //end for
- } //end for
- } //end for
- VectorMiddle(beststart, beststart2, beststart);
- VectorMiddle(bestend, bestend2, bestend);
- if (bestdist > 4 && bestdist < maxjumpdistance)
- {
-// Log_Write("shortest distance between %d and %d is %f\r\n", area1num, area2num, bestdist);
- // if very close and almost no height difference then the bot can walk
- if (bestdist <= 48 && fabs(beststart[2] - bestend[2]) < 8)
- {
- speed = 400;
- traveltype = TRAVEL_WALKOFFLEDGE;
- } //end if
- else if (AAS_HorizontalVelocityForJump(0, beststart, bestend, &speed))
- {
- //FIXME: why multiply with 1.2???
- speed *= 1.2f;
- traveltype = TRAVEL_WALKOFFLEDGE;
- } //end else if
- else
- {
- //get the horizontal speed for the jump, if it isn't possible to calculate this
- //speed (the jump is not possible) then there's no jump reachability created
- if (!AAS_HorizontalVelocityForJump(phys_jumpvel, beststart, bestend, &speed))
- return qfalse;
- speed *= 1.05f;
- traveltype = TRAVEL_JUMP;
- //
- //NOTE: test if the horizontal distance isn't too small
- VectorSubtract(bestend, beststart, dir);
- dir[2] = 0;
- if (VectorLength(dir) < 10)
- return qfalse;
- } //end if
- //
- VectorSubtract(bestend, beststart, dir);
- VectorNormalize(dir);
- VectorMA(beststart, 1, dir, teststart);
- //
- VectorCopy(teststart, testend);
- testend[2] -= 100;
- trace = AAS_TraceClientBBox(teststart, testend, PRESENCE_NORMAL, -1);
- //
- if (trace.startsolid)
- return qfalse;
- if (trace.fraction < 1)
- {
- plane = &aasworld.planes[trace.planenum];
- // if the bot can stand on the surface
- if (DotProduct(plane->normal, up) >= 0.7)
- {
- // if no lava or slime below
- if (!(AAS_PointContents(trace.endpos) & (CONTENTS_LAVA|CONTENTS_SLIME)))
- {
- if (teststart[2] - trace.endpos[2] <= aassettings.phys_maxbarrier)
- return qfalse;
- } //end if
- } //end if
- } //end if
- //
- VectorMA(bestend, -1, dir, teststart);
- //
- VectorCopy(teststart, testend);
- testend[2] -= 100;
- trace = AAS_TraceClientBBox(teststart, testend, PRESENCE_NORMAL, -1);
- //
- if (trace.startsolid)
- return qfalse;
- if (trace.fraction < 1)
- {
- plane = &aasworld.planes[trace.planenum];
- // if the bot can stand on the surface
- if (DotProduct(plane->normal, up) >= 0.7)
- {
- // if no lava or slime below
- if (!(AAS_PointContents(trace.endpos) & (CONTENTS_LAVA|CONTENTS_SLIME)))
- {
- if (teststart[2] - trace.endpos[2] <= aassettings.phys_maxbarrier)
- return qfalse;
- } //end if
- } //end if
- } //end if
- //
- // get command movement
- VectorClear(cmdmove);
- if ((traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP)
- cmdmove[2] = aassettings.phys_jumpvel;
- else
- cmdmove[2] = 0;
- //
- VectorSubtract(bestend, beststart, dir);
- dir[2] = 0;
- VectorNormalize(dir);
- CrossProduct(dir, up, sidewards);
- //
- stopevent = SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE;
- if (!AAS_AreaClusterPortal(area1num) && !AAS_AreaClusterPortal(area2num))
- stopevent |= SE_TOUCHCLUSTERPORTAL;
- //
- for (i = 0; i < 3; i++)
- {
- //
- if (i == 1)
- VectorAdd(testend, sidewards, testend);
- else if (i == 2)
- VectorSubtract(bestend, sidewards, testend);
- else
- VectorCopy(bestend, testend);
- VectorSubtract(testend, beststart, dir);
- dir[2] = 0;
- VectorNormalize(dir);
- VectorScale(dir, speed, velocity);
- //
- AAS_PredictClientMovement(&move, -1, beststart, PRESENCE_NORMAL, qtrue,
- velocity, cmdmove, 3, 30, 0.1f,
- stopevent, 0, qfalse);
- // if prediction time wasn't enough to fully predict the movement
- if (move.frames >= 30)
- return qfalse;
- // don't enter slime or lava and don't fall from too high
- if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA))
- return qfalse;
- // never jump or fall through a cluster portal
- if (move.stopevent & SE_TOUCHCLUSTERPORTAL)
- return qfalse;
- //the end position should be in area2, also test a little bit back
- //because the predicted jump could have rushed through the area
- VectorMA(move.endpos, -64, dir, teststart);
- teststart[2] += 1;
- numareas = AAS_TraceAreas(move.endpos, teststart, areas, NULL, sizeof(areas) / sizeof(int));
- for (j = 0; j < numareas; j++)
- {
- if (areas[j] == area2num)
- break;
- } //end for
- if (j < numareas)
- break;
- }
- if (i >= 3)
- return qfalse;
- //
-#ifdef REACH_DEBUG
- //create the reachability
- Log_Write("jump reachability between %d and %d\r\n", area1num, area2num);
-#endif //REACH_DEBUG
- //create a new reachability link
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area2num;
- lreach->facenum = 0;
- lreach->edgenum = 0;
- VectorCopy(beststart, lreach->start);
- VectorCopy(bestend, lreach->end);
- lreach->traveltype = traveltype;
-
- VectorSubtract(bestend, beststart, dir);
- height = dir[2];
- dir[2] = 0;
- if ((traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE && height > VectorLength(dir))
- {
- lreach->traveltime = aassettings.rs_startwalkoffledge + height * 50 / aassettings.phys_gravity;
- }
- else
- {
- lreach->traveltime = aassettings.rs_startjump + VectorDistance(bestend, beststart) * 240 / aassettings.phys_maxwalkvelocity;
- } //end if
- //
- if (!AAS_AreaJumpPad(area2num))
- {
- if (AAS_FallDelta(beststart[2] - bestend[2]) > aassettings.phys_falldelta5)
- {
- lreach->traveltime += aassettings.rs_falldamage5;
- } //end if
- else if (AAS_FallDelta(beststart[2] - bestend[2]) > aassettings.phys_falldelta10)
- {
- lreach->traveltime += aassettings.rs_falldamage10;
- } //end if
- } //end if
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //
- if ((traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP)
- reach_jump++;
- else
- reach_walkoffledge++;
- } //end if
- return qfalse;
-} //end of the function AAS_Reachability_Jump
-//===========================================================================
-// create a possible ladder reachability from area1 to area2
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_Reachability_Ladder(int area1num, int area2num)
-{
- int i, j, k, l, edge1num, edge2num, sharededgenum = 0, lowestedgenum = 0;
- int face1num, face2num, ladderface1num = 0, ladderface2num = 0;
- int ladderface1vertical, ladderface2vertical, firstv;
- float face1area, face2area, bestface1area = -9999, bestface2area = -9999;
- float phys_jumpvel, maxjumpheight;
- vec3_t area1point, area2point, v1, v2, up = {0, 0, 1};
- vec3_t mid, lowestpoint = {0, 0}, start, end, sharededgevec, dir;
- aas_area_t *area1, *area2;
- aas_face_t *face1, *face2, *ladderface1 = NULL, *ladderface2 = NULL;
- aas_plane_t *plane1, *plane2;
- aas_edge_t *sharededge, *edge1;
- aas_lreachability_t *lreach;
- aas_trace_t trace;
-
- if (!AAS_AreaLadder(area1num) || !AAS_AreaLadder(area2num)) return qfalse;
- //
- phys_jumpvel = aassettings.phys_jumpvel;
- //maximum height a player can jump with the given initial z velocity
- maxjumpheight = AAS_MaxJumpHeight(phys_jumpvel);
-
- area1 = &aasworld.areas[area1num];
- area2 = &aasworld.areas[area2num];
-
- for (i = 0; i < area1->numfaces; i++)
- {
- face1num = aasworld.faceindex[area1->firstface + i];
- face1 = &aasworld.faces[abs(face1num)];
- //if not a ladder face
- if (!(face1->faceflags & FACE_LADDER)) continue;
- //
- for (j = 0; j < area2->numfaces; j++)
- {
- face2num = aasworld.faceindex[area2->firstface + j];
- face2 = &aasworld.faces[abs(face2num)];
- //if not a ladder face
- if (!(face2->faceflags & FACE_LADDER)) continue;
- //check if the faces share an edge
- for (k = 0; k < face1->numedges; k++)
- {
- edge1num = aasworld.edgeindex[face1->firstedge + k];
- for (l = 0; l < face2->numedges; l++)
- {
- edge2num = aasworld.edgeindex[face2->firstedge + l];
- if (abs(edge1num) == abs(edge2num))
- {
- //get the face with the largest area
- face1area = AAS_FaceArea(face1);
- face2area = AAS_FaceArea(face2);
- if (face1area > bestface1area && face2area > bestface2area)
- {
- bestface1area = face1area;
- bestface2area = face2area;
- ladderface1 = face1;
- ladderface2 = face2;
- ladderface1num = face1num;
- ladderface2num = face2num;
- sharededgenum = edge1num;
- } //end if
- break;
- } //end if
- } //end for
- if (l != face2->numedges) break;
- } //end for
- } //end for
- } //end for
- //
- if (ladderface1 && ladderface2)
- {
- //get the middle of the shared edge
- sharededge = &aasworld.edges[abs(sharededgenum)];
- firstv = sharededgenum < 0;
- //
- VectorCopy(aasworld.vertexes[sharededge->v[firstv]], v1);
- VectorCopy(aasworld.vertexes[sharededge->v[!firstv]], v2);
- VectorAdd(v1, v2, area1point);
- VectorScale(area1point, 0.5, area1point);
- VectorCopy(area1point, area2point);
- //
- //if the face plane in area 1 is pretty much vertical
- plane1 = &aasworld.planes[ladderface1->planenum ^ (ladderface1num < 0)];
- plane2 = &aasworld.planes[ladderface2->planenum ^ (ladderface2num < 0)];
- //
- //get the points really into the areas
- VectorSubtract(v2, v1, sharededgevec);
- CrossProduct(plane1->normal, sharededgevec, dir);
- VectorNormalize(dir);
- //NOTE: 32 because that's larger than 16 (bot bbox x,y)
- VectorMA(area1point, -32, dir, area1point);
- VectorMA(area2point, 32, dir, area2point);
- //
- ladderface1vertical = abs(DotProduct(plane1->normal, up)) < 0.1;
- ladderface2vertical = abs(DotProduct(plane2->normal, up)) < 0.1;
- //there's only reachability between vertical ladder faces
- if (!ladderface1vertical && !ladderface2vertical) return qfalse;
- //if both vertical ladder faces
- if (ladderface1vertical && ladderface2vertical
- //and the ladder faces do not make a sharp corner
- && DotProduct(plane1->normal, plane2->normal) > 0.7
- //and the shared edge is not too vertical
- && abs(DotProduct(sharededgevec, up)) < 0.7)
- {
- //create a new reachability link
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area2num;
- lreach->facenum = ladderface1num;
- lreach->edgenum = abs(sharededgenum);
- VectorCopy(area1point, lreach->start);
- //VectorCopy(area2point, lreach->end);
- VectorMA(area2point, -3, plane1->normal, lreach->end);
- lreach->traveltype = TRAVEL_LADDER;
- lreach->traveltime = 10;
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //
- reach_ladder++;
- //create a new reachability link
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area1num;
- lreach->facenum = ladderface2num;
- lreach->edgenum = abs(sharededgenum);
- VectorCopy(area2point, lreach->start);
- //VectorCopy(area1point, lreach->end);
- VectorMA(area1point, -3, plane1->normal, lreach->end);
- lreach->traveltype = TRAVEL_LADDER;
- lreach->traveltime = 10;
- lreach->next = areareachability[area2num];
- areareachability[area2num] = lreach;
- //
- reach_ladder++;
- //
- return qtrue;
- } //end if
- //if the second ladder face is also a ground face
- //create ladder end (just ladder) reachability and
- //walk off a ladder (ledge) reachability
- if (ladderface1vertical && (ladderface2->faceflags & FACE_GROUND))
- {
- //create a new reachability link
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area2num;
- lreach->facenum = ladderface1num;
- lreach->edgenum = abs(sharededgenum);
- VectorCopy(area1point, lreach->start);
- VectorCopy(area2point, lreach->end);
- lreach->end[2] += 16;
- VectorMA(lreach->end, -15, plane1->normal, lreach->end);
- lreach->traveltype = TRAVEL_LADDER;
- lreach->traveltime = 10;
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //
- reach_ladder++;
- //create a new reachability link
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area1num;
- lreach->facenum = ladderface2num;
- lreach->edgenum = abs(sharededgenum);
- VectorCopy(area2point, lreach->start);
- VectorCopy(area1point, lreach->end);
- lreach->traveltype = TRAVEL_WALKOFFLEDGE;
- lreach->traveltime = 10;
- lreach->next = areareachability[area2num];
- areareachability[area2num] = lreach;
- //
- reach_walkoffledge++;
- //
- return qtrue;
- } //end if
- //
- if (ladderface1vertical)
- {
- //find lowest edge of the ladder face
- lowestpoint[2] = 99999;
- for (i = 0; i < ladderface1->numedges; i++)
- {
- edge1num = abs(aasworld.edgeindex[ladderface1->firstedge + i]);
- edge1 = &aasworld.edges[edge1num];
- //
- VectorCopy(aasworld.vertexes[edge1->v[0]], v1);
- VectorCopy(aasworld.vertexes[edge1->v[1]], v2);
- //
- VectorAdd(v1, v2, mid);
- VectorScale(mid, 0.5, mid);
- //
- if (mid[2] < lowestpoint[2])
- {
- VectorCopy(mid, lowestpoint);
- lowestedgenum = edge1num;
- } //end if
- } //end for
- //
- plane1 = &aasworld.planes[ladderface1->planenum];
- //trace down in the middle of this edge
- VectorMA(lowestpoint, 5, plane1->normal, start);
- VectorCopy(start, end);
- start[2] += 5;
- end[2] -= 100;
- //trace without entity collision
- trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1);
- //
- //
-#ifdef REACH_DEBUG
- if (trace.startsolid)
- {
- Log_Write("trace from area %d started in solid\r\n", area1num);
- } //end if
-#endif //REACH_DEBUG
- //
- trace.endpos[2] += 1;
- area2num = AAS_PointAreaNum(trace.endpos);
- //
- area2 = &aasworld.areas[area2num];
- for (i = 0; i < area2->numfaces; i++)
- {
- face2num = aasworld.faceindex[area2->firstface + i];
- face2 = &aasworld.faces[abs(face2num)];
- //
- if (face2->faceflags & FACE_LADDER)
- {
- plane2 = &aasworld.planes[face2->planenum];
- if (abs(DotProduct(plane2->normal, up)) < 0.1) break;
- } //end if
- } //end for
- //if from another area without vertical ladder faces
- if (i >= area2->numfaces && area2num != area1num &&
- //the reachabilities shouldn't exist already
- !AAS_ReachabilityExists(area1num, area2num) &&
- !AAS_ReachabilityExists(area2num, area1num))
- {
- //if the height is jumpable
- if (start[2] - trace.endpos[2] < maxjumpheight)
- {
- //create a new reachability link
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area2num;
- lreach->facenum = ladderface1num;
- lreach->edgenum = lowestedgenum;
- VectorCopy(lowestpoint, lreach->start);
- VectorCopy(trace.endpos, lreach->end);
- lreach->traveltype = TRAVEL_LADDER;
- lreach->traveltime = 10;
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //
- reach_ladder++;
- //create a new reachability link
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area1num;
- lreach->facenum = ladderface1num;
- lreach->edgenum = lowestedgenum;
- VectorCopy(trace.endpos, lreach->start);
- //get the end point a little bit into the ladder
- VectorMA(lowestpoint, -5, plane1->normal, lreach->end);
- //get the end point a little higher
- lreach->end[2] += 10;
- lreach->traveltype = TRAVEL_JUMP;
- lreach->traveltime = 10;
- lreach->next = areareachability[area2num];
- areareachability[area2num] = lreach;
- //
- reach_jump++;
- //
- return qtrue;
-#ifdef REACH_DEBUG
- Log_Write("jump up to ladder reach between %d and %d\r\n", area2num, area1num);
-#endif //REACH_DEBUG
- } //end if
-#ifdef REACH_DEBUG
- else Log_Write("jump too high between area %d and %d\r\n", area2num, area1num);
-#endif //REACH_DEBUG
- } //end if
- /*//if slime or lava below the ladder
- //try jump reachability from far towards the ladder
- if (aasworld.areasettings[area2num].contents & (AREACONTENTS_SLIME
- | AREACONTENTS_LAVA))
- {
- for (i = 20; i <= 120; i += 20)
- {
- //trace down in the middle of this edge
- VectorMA(lowestpoint, i, plane1->normal, start);
- VectorCopy(start, end);
- start[2] += 5;
- end[2] -= 100;
- //trace without entity collision
- trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1);
- //
- if (trace.startsolid) break;
- trace.endpos[2] += 1;
- area2num = AAS_PointAreaNum(trace.endpos);
- if (area2num == area1num) continue;
- //
- if (start[2] - trace.endpos[2] > maxjumpheight) continue;
- if (aasworld.areasettings[area2num].contents & (AREACONTENTS_SLIME
- | AREACONTENTS_LAVA)) continue;
- //
- //create a new reachability link
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area1num;
- lreach->facenum = ladderface1num;
- lreach->edgenum = lowestedgenum;
- VectorCopy(trace.endpos, lreach->start);
- VectorCopy(lowestpoint, lreach->end);
- lreach->end[2] += 5;
- lreach->traveltype = TRAVEL_JUMP;
- lreach->traveltime = 10;
- lreach->next = areareachability[area2num];
- areareachability[area2num] = lreach;
- //
- reach_jump++;
- //
- Log_Write("jump far to ladder reach between %d and %d\r\n", area2num, area1num);
- //
- break;
- } //end for
- } //end if*/
- } //end if
- } //end if
- return qfalse;
-} //end of the function AAS_Reachability_Ladder
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_TravelFlagsForTeam(int ent)
-{
- int notteam;
-
- if (!AAS_IntForBSPEpairKey(ent, "bot_notteam", ¬team))
- return 0;
- if (notteam == 1)
- return TRAVELFLAG_NOTTEAM1;
- if (notteam == 2)
- return TRAVELFLAG_NOTTEAM2;
- return 0;
-} //end of the function AAS_TravelFlagsForTeam
-//===========================================================================
-// create possible teleporter reachabilities
-// this is very game dependent.... :(
-//
-// classname = trigger_multiple or trigger_teleport
-// target = "t1"
-//
-// classname = target_teleporter
-// targetname = "t1"
-// target = "t2"
-//
-// classname = misc_teleporter_dest
-// targetname = "t2"
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_Reachability_Teleport(void)
-{
- int area1num, area2num;
- char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY];
- char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY];
- int ent, dest;
- float angle;
- vec3_t origin, destorigin, mins, maxs, end, angles;
- vec3_t mid, velocity, cmdmove;
- aas_lreachability_t *lreach;
- aas_clientmove_t move;
- aas_trace_t trace;
- aas_link_t *areas, *link;
-
- for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
- {
- if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
- if (!strcmp(classname, "trigger_multiple"))
- {
- AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY);
-//#ifdef REACH_DEBUG
- botimport.Print(PRT_MESSAGE, "trigger_multiple model = \"%s\"\n", model);
-//#endif REACH_DEBUG
- VectorClear(angles);
- AAS_BSPModelMinsMaxsOrigin(atoi(model+1), angles, mins, maxs, origin);
- //
- if (!AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY))
- {
- botimport.Print(PRT_ERROR, "trigger_multiple at %1.0f %1.0f %1.0f without target\n",
- origin[0], origin[1], origin[2]);
- continue;
- } //end if
- for (dest = AAS_NextBSPEntity(0); dest; dest = AAS_NextBSPEntity(dest))
- {
- if (!AAS_ValueForBSPEpairKey(dest, "classname", classname, MAX_EPAIRKEY)) continue;
- if (!strcmp(classname, "target_teleporter"))
- {
- if (!AAS_ValueForBSPEpairKey(dest, "targetname", targetname, MAX_EPAIRKEY)) continue;
- if (!strcmp(targetname, target))
- {
- break;
- } //end if
- } //end if
- } //end for
- if (!dest)
- {
- continue;
- } //end if
- if (!AAS_ValueForBSPEpairKey(dest, "target", target, MAX_EPAIRKEY))
- {
- botimport.Print(PRT_ERROR, "target_teleporter without target\n");
- continue;
- } //end if
- } //end else
- else if (!strcmp(classname, "trigger_teleport"))
- {
- AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY);
-//#ifdef REACH_DEBUG
- botimport.Print(PRT_MESSAGE, "trigger_teleport model = \"%s\"\n", model);
-//#endif REACH_DEBUG
- VectorClear(angles);
- AAS_BSPModelMinsMaxsOrigin(atoi(model+1), angles, mins, maxs, origin);
- //
- if (!AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY))
- {
- botimport.Print(PRT_ERROR, "trigger_teleport at %1.0f %1.0f %1.0f without target\n",
- origin[0], origin[1], origin[2]);
- continue;
- } //end if
- } //end if
- else
- {
- continue;
- } //end else
- //
- for (dest = AAS_NextBSPEntity(0); dest; dest = AAS_NextBSPEntity(dest))
- {
- //classname should be misc_teleporter_dest
- //but I've also seen target_position and actually any
- //entity could be used... burp
- if (AAS_ValueForBSPEpairKey(dest, "targetname", targetname, MAX_EPAIRKEY))
- {
- if (!strcmp(targetname, target))
- {
- break;
- } //end if
- } //end if
- } //end for
- if (!dest)
- {
- botimport.Print(PRT_ERROR, "teleporter without misc_teleporter_dest (%s)\n", target);
- continue;
- } //end if
- if (!AAS_VectorForBSPEpairKey(dest, "origin", destorigin))
- {
- botimport.Print(PRT_ERROR, "teleporter destination (%s) without origin\n", target);
- continue;
- } //end if
- //
- area2num = AAS_PointAreaNum(destorigin);
- //if not teleported into a teleporter or into a jumppad
- if (!AAS_AreaTeleporter(area2num) && !AAS_AreaJumpPad(area2num))
- {
- VectorCopy(destorigin, end);
- end[2] -= 64;
- trace = AAS_TraceClientBBox(destorigin, end, PRESENCE_CROUCH, -1);
- if (trace.startsolid)
- {
- botimport.Print(PRT_ERROR, "teleporter destination (%s) in solid\n", target);
- continue;
- } //end if
- area2num = AAS_PointAreaNum(trace.endpos);
- //
- /*
- if (!AAS_AreaTeleporter(area2num) &&
- !AAS_AreaJumpPad(area2num) &&
- !AAS_AreaGrounded(area2num))
- {
- VectorCopy(trace.endpos, destorigin);
- }
- else*/
- {
- //predict where you'll end up
- AAS_FloatForBSPEpairKey(dest, "angle", &angle);
- if (angle)
- {
- VectorSet(angles, 0, angle, 0);
- AngleVectors(angles, velocity, NULL, NULL);
- VectorScale(velocity, 400, velocity);
- } //end if
- else
- {
- VectorClear(velocity);
- } //end else
- VectorClear(cmdmove);
- AAS_PredictClientMovement(&move, -1, destorigin, PRESENCE_NORMAL, qfalse,
- velocity, cmdmove, 0, 30, 0.1f,
- SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME|
- SE_ENTERLAVA|SE_HITGROUNDDAMAGE|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER, 0, qfalse); //qtrue);
- area2num = AAS_PointAreaNum(move.endpos);
- if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA))
- {
- botimport.Print(PRT_WARNING, "teleported into slime or lava at dest %s\n", target);
- } //end if
- VectorCopy(move.endpos, destorigin);
- } //end else
- } //end if
- //
- //botimport.Print(PRT_MESSAGE, "teleporter brush origin at %f %f %f\n", origin[0], origin[1], origin[2]);
- //botimport.Print(PRT_MESSAGE, "teleporter brush mins = %f %f %f\n", mins[0], mins[1], mins[2]);
- //botimport.Print(PRT_MESSAGE, "teleporter brush maxs = %f %f %f\n", maxs[0], maxs[1], maxs[2]);
- VectorAdd(origin, mins, mins);
- VectorAdd(origin, maxs, maxs);
- //
- VectorAdd(mins, maxs, mid);
- VectorScale(mid, 0.5, mid);
- //link an invalid (-1) entity
- areas = AAS_LinkEntityClientBBox(mins, maxs, -1, PRESENCE_CROUCH);
- if (!areas) botimport.Print(PRT_MESSAGE, "trigger_multiple not in any area\n");
- //
- for (link = areas; link; link = link->next_area)
- {
- //if (!AAS_AreaGrounded(link->areanum)) continue;
- if (!AAS_AreaTeleporter(link->areanum)) continue;
- //
- area1num = link->areanum;
- //create a new reachability link
- lreach = AAS_AllocReachability();
- if (!lreach) break;
- lreach->areanum = area2num;
- lreach->facenum = 0;
- lreach->edgenum = 0;
- VectorCopy(mid, lreach->start);
- VectorCopy(destorigin, lreach->end);
- lreach->traveltype = TRAVEL_TELEPORT;
- lreach->traveltype |= AAS_TravelFlagsForTeam(ent);
- lreach->traveltime = aassettings.rs_teleport;
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //
- reach_teleport++;
- } //end for
- //unlink the invalid entity
- AAS_UnlinkFromAreas(areas);
- } //end for
-} //end of the function AAS_Reachability_Teleport
-//===========================================================================
-// create possible elevator (func_plat) reachabilities
-// this is very game dependent.... :(
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_Reachability_Elevator(void)
-{
- int area1num, area2num, modelnum, i, j, k, l, n, p;
- float lip, height, speed;
- char model[MAX_EPAIRKEY], classname[MAX_EPAIRKEY];
- int ent;
- vec3_t mins, maxs, origin, angles = {0, 0, 0};
- vec3_t pos1, pos2, mids, platbottom, plattop;
- vec3_t bottomorg, toporg, start, end, dir;
- vec_t xvals[8], yvals[8], xvals_top[8], yvals_top[8];
- aas_lreachability_t *lreach;
- aas_trace_t trace;
-
-#ifdef REACH_DEBUG
- Log_Write("AAS_Reachability_Elevator\r\n");
-#endif //REACH_DEBUG
- for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
- {
- if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
- if (!strcmp(classname, "func_plat"))
- {
-#ifdef REACH_DEBUG
- Log_Write("found func plat\r\n");
-#endif //REACH_DEBUG
- if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY))
- {
- botimport.Print(PRT_ERROR, "func_plat without model\n");
- continue;
- } //end if
- //get the model number, and skip the leading *
- modelnum = atoi(model+1);
- if (modelnum <= 0)
- {
- botimport.Print(PRT_ERROR, "func_plat with invalid model number\n");
- continue;
- } //end if
- //get the mins, maxs and origin of the model
- //NOTE: the origin is usually (0,0,0) and the mins and maxs
- // are the absolute mins and maxs
- AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);
- //
- AAS_VectorForBSPEpairKey(ent, "origin", origin);
- //pos1 is the top position, pos2 is the bottom
- VectorCopy(origin, pos1);
- VectorCopy(origin, pos2);
- //get the lip of the plat
- AAS_FloatForBSPEpairKey(ent, "lip", &lip);
- if (!lip) lip = 8;
- //get the movement height of the plat
- AAS_FloatForBSPEpairKey(ent, "height", &height);
- if (!height) height = (maxs[2] - mins[2]) - lip;
- //get the speed of the plat
- AAS_FloatForBSPEpairKey(ent, "speed", &speed);
- if (!speed) speed = 200;
- //get bottom position below pos1
- pos2[2] -= height;
- //
- //get a point just above the plat in the bottom position
- VectorAdd(mins, maxs, mids);
- VectorMA(pos2, 0.5, mids, platbottom);
- platbottom[2] = maxs[2] - (pos1[2] - pos2[2]) + 2;
- //get a point just above the plat in the top position
- VectorAdd(mins, maxs, mids);
- VectorMA(pos2, 0.5, mids, plattop);
- plattop[2] = maxs[2] + 2;
- //
- /*if (!area1num)
- {
- Log_Write("no grounded area near plat bottom\r\n");
- continue;
- } //end if*/
- //get the mins and maxs a little larger
- for (i = 0; i < 3; i++)
- {
- mins[i] -= 1;
- maxs[i] += 1;
- } //end for
- //
- //botimport.Print(PRT_MESSAGE, "platbottom[2] = %1.1f plattop[2] = %1.1f\n", platbottom[2], plattop[2]);
- //
- VectorAdd(mins, maxs, mids);
- VectorScale(mids, 0.5, mids);
- //
- xvals[0] = mins[0]; xvals[1] = mids[0]; xvals[2] = maxs[0]; xvals[3] = mids[0];
- yvals[0] = mids[1]; yvals[1] = maxs[1]; yvals[2] = mids[1]; yvals[3] = mins[1];
- //
- xvals[4] = mins[0]; xvals[5] = maxs[0]; xvals[6] = maxs[0]; xvals[7] = mins[0];
- yvals[4] = maxs[1]; yvals[5] = maxs[1]; yvals[6] = mins[1]; yvals[7] = mins[1];
- //find adjacent areas around the bottom of the plat
- for (i = 0; i < 9; i++)
- {
- if (i < 8) //check at the sides of the plat
- {
- bottomorg[0] = origin[0] + xvals[i];
- bottomorg[1] = origin[1] + yvals[i];
- bottomorg[2] = platbottom[2] + 16;
- //get a grounded or swim area near the plat in the bottom position
- area1num = AAS_PointAreaNum(bottomorg);
- for (k = 0; k < 16; k++)
- {
- if (area1num)
- {
- if (AAS_AreaGrounded(area1num) || AAS_AreaSwim(area1num)) break;
- } //end if
- bottomorg[2] += 4;
- area1num = AAS_PointAreaNum(bottomorg);
- } //end if
- //if in solid
- if (k >= 16)
- {
- continue;
- } //end if
- } //end if
- else //at the middle of the plat
- {
- VectorCopy(plattop, bottomorg);
- bottomorg[2] += 24;
- area1num = AAS_PointAreaNum(bottomorg);
- if (!area1num) continue;
- VectorCopy(platbottom, bottomorg);
- bottomorg[2] += 24;
- } //end else
- //look at adjacent areas around the top of the plat
- //make larger steps to outside the plat everytime
- for (n = 0; n < 3; n++)
- {
- for (k = 0; k < 3; k++)
- {
- mins[k] -= 4;
- maxs[k] += 4;
- } //end for
- xvals_top[0] = mins[0]; xvals_top[1] = mids[0]; xvals_top[2] = maxs[0]; xvals_top[3] = mids[0];
- yvals_top[0] = mids[1]; yvals_top[1] = maxs[1]; yvals_top[2] = mids[1]; yvals_top[3] = mins[1];
- //
- xvals_top[4] = mins[0]; xvals_top[5] = maxs[0]; xvals_top[6] = maxs[0]; xvals_top[7] = mins[0];
- yvals_top[4] = maxs[1]; yvals_top[5] = maxs[1]; yvals_top[6] = mins[1]; yvals_top[7] = mins[1];
- //
- for (j = 0; j < 8; j++)
- {
- toporg[0] = origin[0] + xvals_top[j];
- toporg[1] = origin[1] + yvals_top[j];
- toporg[2] = plattop[2] + 16;
- //get a grounded or swim area near the plat in the top position
- area2num = AAS_PointAreaNum(toporg);
- for (l = 0; l < 16; l++)
- {
- if (area2num)
- {
- if (AAS_AreaGrounded(area2num) || AAS_AreaSwim(area2num))
- {
- VectorCopy(plattop, start);
- start[2] += 32;
- VectorCopy(toporg, end);
- end[2] += 1;
- trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);
- if (trace.fraction >= 1) break;
- } //end if
- } //end if
- toporg[2] += 4;
- area2num = AAS_PointAreaNum(toporg);
- } //end if
- //if in solid
- if (l >= 16) continue;
- //never create a reachability in the same area
- if (area2num == area1num) continue;
- //if the area isn't grounded
- if (!AAS_AreaGrounded(area2num)) continue;
- //if there already exists reachability between the areas
- if (AAS_ReachabilityExists(area1num, area2num)) continue;
- //if the reachability start is within the elevator bounding box
- VectorSubtract(bottomorg, platbottom, dir);
- VectorNormalize(dir);
- dir[0] = bottomorg[0] + 24 * dir[0];
- dir[1] = bottomorg[1] + 24 * dir[1];
- dir[2] = bottomorg[2];
- //
- for (p = 0; p < 3; p++)
- if (dir[p] < origin[p] + mins[p] || dir[p] > origin[p] + maxs[p]) break;
- if (p >= 3) continue;
- //create a new reachability link
- lreach = AAS_AllocReachability();
- if (!lreach) continue;
- lreach->areanum = area2num;
- //the facenum is the model number
- lreach->facenum = modelnum;
- //the edgenum is the height
- lreach->edgenum = (int) height;
- //
- VectorCopy(dir, lreach->start);
- VectorCopy(toporg, lreach->end);
- lreach->traveltype = TRAVEL_ELEVATOR;
- lreach->traveltype |= AAS_TravelFlagsForTeam(ent);
- lreach->traveltime = aassettings.rs_startelevator + height * 100 / speed;
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //don't go any further to the outside
- n = 9999;
- //
-#ifdef REACH_DEBUG
- Log_Write("elevator reach from %d to %d\r\n", area1num, area2num);
-#endif //REACH_DEBUG
- //
- reach_elevator++;
- } //end for
- } //end for
- } //end for
- } //end if
- } //end for
-} //end of the function AAS_Reachability_Elevator
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-aas_lreachability_t *AAS_FindFaceReachabilities(vec3_t *facepoints, int numpoints, aas_plane_t *plane, int towardsface)
-{
- int i, j, k, l;
- int facenum, edgenum, bestfacenum;
- float *v1, *v2, *v3, *v4;
- float bestdist, speed, hordist, dist;
- vec3_t beststart, beststart2, bestend, bestend2, tmp, hordir, testpoint;
- aas_lreachability_t *lreach, *lreachabilities;
- aas_area_t *area;
- aas_face_t *face;
- aas_edge_t *edge;
- aas_plane_t *faceplane, *bestfaceplane;
-
- //
- lreachabilities = NULL;
- bestfacenum = 0;
- bestfaceplane = NULL;
- //
- for (i = 1; i < aasworld.numareas; i++)
- {
- area = &aasworld.areas[i];
- // get the shortest distance between one of the func_bob start edges and
- // one of the face edges of area1
- bestdist = 999999;
- for (j = 0; j < area->numfaces; j++)
- {
- facenum = aasworld.faceindex[area->firstface + j];
- face = &aasworld.faces[abs(facenum)];
- //if not a ground face
- if (!(face->faceflags & FACE_GROUND)) continue;
- //get the ground planes
- faceplane = &aasworld.planes[face->planenum];
- //
- for (k = 0; k < face->numedges; k++)
- {
- edgenum = abs(aasworld.edgeindex[face->firstedge + k]);
- edge = &aasworld.edges[edgenum];
- //calculate the minimum distance between the two edges
- v1 = aasworld.vertexes[edge->v[0]];
- v2 = aasworld.vertexes[edge->v[1]];
- //
- for (l = 0; l < numpoints; l++)
- {
- v3 = facepoints[l];
- v4 = facepoints[(l+1) % numpoints];
- dist = AAS_ClosestEdgePoints(v1, v2, v3, v4, faceplane, plane,
- beststart, bestend,
- beststart2, bestend2, bestdist);
- if (dist < bestdist)
- {
- bestfacenum = facenum;
- bestfaceplane = faceplane;
- bestdist = dist;
- } //end if
- } //end for
- } //end for
- } //end for
- //
- if (bestdist > 192) continue;
- //
- VectorMiddle(beststart, beststart2, beststart);
- VectorMiddle(bestend, bestend2, bestend);
- //
- if (!towardsface)
- {
- VectorCopy(beststart, tmp);
- VectorCopy(bestend, beststart);
- VectorCopy(tmp, bestend);
- } //end if
- //
- VectorSubtract(bestend, beststart, hordir);
- hordir[2] = 0;
- hordist = VectorLength(hordir);
- //
- if (hordist > 2 * AAS_MaxJumpDistance(aassettings.phys_jumpvel)) continue;
- //the end point should not be significantly higher than the start point
- if (bestend[2] - 32 > beststart[2]) continue;
- //don't fall down too far
- if (bestend[2] < beststart[2] - 128) continue;
- //the distance should not be too far
- if (hordist > 32)
- {
- //check for walk off ledge
- if (!AAS_HorizontalVelocityForJump(0, beststart, bestend, &speed)) continue;
- } //end if
- //
- beststart[2] += 1;
- bestend[2] += 1;
- //
- if (towardsface) VectorCopy(bestend, testpoint);
- else VectorCopy(beststart, testpoint);
- testpoint[2] = 0;
- testpoint[2] = (bestfaceplane->dist - DotProduct(bestfaceplane->normal, testpoint)) / bestfaceplane->normal[2];
- //
- if (!AAS_PointInsideFace(bestfacenum, testpoint, 0.1f))
- {
- //if the faces are not overlapping then only go down
- if (bestend[2] - 16 > beststart[2]) continue;
- } //end if
- lreach = AAS_AllocReachability();
- if (!lreach) return lreachabilities;
- lreach->areanum = i;
- lreach->facenum = 0;
- lreach->edgenum = 0;
- VectorCopy(beststart, lreach->start);
- VectorCopy(bestend, lreach->end);
- lreach->traveltype = 0;
- lreach->traveltime = 0;
- lreach->next = lreachabilities;
- lreachabilities = lreach;
-#ifndef BSPC
- if (towardsface) AAS_PermanentLine(lreach->start, lreach->end, 1);
- else AAS_PermanentLine(lreach->start, lreach->end, 2);
-#endif
- } //end for
- return lreachabilities;
-} //end of the function AAS_FindFaceReachabilities
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_Reachability_FuncBobbing(void)
-{
- int ent, spawnflags, modelnum, axis;
- int i, numareas, areas[10];
- char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY];
- vec3_t origin, move_end, move_start, move_start_top, move_end_top;
- vec3_t mins, maxs, angles = {0, 0, 0};
- vec3_t start_edgeverts[4], end_edgeverts[4], mid;
- vec3_t org, start, end, dir, points[10];
- float height;
- aas_plane_t start_plane, end_plane;
- aas_lreachability_t *startreach, *endreach, *nextstartreach, *nextendreach, *lreach;
- aas_lreachability_t *firststartreach, *firstendreach;
-
- for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
- {
- if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
- if (strcmp(classname, "func_bobbing")) continue;
- AAS_FloatForBSPEpairKey(ent, "height", &height);
- if (!height) height = 32;
- //
- if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY))
- {
- botimport.Print(PRT_ERROR, "func_bobbing without model\n");
- continue;
- } //end if
- //get the model number, and skip the leading *
- modelnum = atoi(model+1);
- if (modelnum <= 0)
- {
- botimport.Print(PRT_ERROR, "func_bobbing with invalid model number\n");
- continue;
- } //end if
- //if the entity has an origin set then use it
- if (!AAS_VectorForBSPEpairKey(ent, "origin", origin))
- VectorSet(origin, 0, 0, 0);
- //
- AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);
- //
- VectorAdd(mins, origin, mins);
- VectorAdd(maxs, origin, maxs);
- //
- VectorAdd(mins, maxs, mid);
- VectorScale(mid, 0.5, mid);
- VectorCopy(mid, origin);
- //
- VectorCopy(origin, move_end);
- VectorCopy(origin, move_start);
- //
- AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags);
- // set the axis of bobbing
- if (spawnflags & 1) axis = 0;
- else if (spawnflags & 2) axis = 1;
- else axis = 2;
- //
- move_start[axis] -= height;
- move_end[axis] += height;
- //
- Log_Write("funcbob model %d, start = {%1.1f, %1.1f, %1.1f} end = {%1.1f, %1.1f, %1.1f}\n",
- modelnum, move_start[0], move_start[1], move_start[2], move_end[0], move_end[1], move_end[2]);
- //
-#ifndef BSPC
- /*
- AAS_DrawPermanentCross(move_start, 4, 1);
- AAS_DrawPermanentCross(move_end, 4, 2);
- */
-#endif
- //
- for (i = 0; i < 4; i++)
- {
- VectorCopy(move_start, start_edgeverts[i]);
- start_edgeverts[i][2] += maxs[2] - mid[2]; //+ bbox maxs z
- start_edgeverts[i][2] += 24; //+ player origin to ground dist
- } //end for
- start_edgeverts[0][0] += maxs[0] - mid[0];
- start_edgeverts[0][1] += maxs[1] - mid[1];
- start_edgeverts[1][0] += maxs[0] - mid[0];
- start_edgeverts[1][1] += mins[1] - mid[1];
- start_edgeverts[2][0] += mins[0] - mid[0];
- start_edgeverts[2][1] += mins[1] - mid[1];
- start_edgeverts[3][0] += mins[0] - mid[0];
- start_edgeverts[3][1] += maxs[1] - mid[1];
- //
- start_plane.dist = start_edgeverts[0][2];
- VectorSet(start_plane.normal, 0, 0, 1);
- //
- for (i = 0; i < 4; i++)
- {
- VectorCopy(move_end, end_edgeverts[i]);
- end_edgeverts[i][2] += maxs[2] - mid[2]; //+ bbox maxs z
- end_edgeverts[i][2] += 24; //+ player origin to ground dist
- } //end for
- end_edgeverts[0][0] += maxs[0] - mid[0];
- end_edgeverts[0][1] += maxs[1] - mid[1];
- end_edgeverts[1][0] += maxs[0] - mid[0];
- end_edgeverts[1][1] += mins[1] - mid[1];
- end_edgeverts[2][0] += mins[0] - mid[0];
- end_edgeverts[2][1] += mins[1] - mid[1];
- end_edgeverts[3][0] += mins[0] - mid[0];
- end_edgeverts[3][1] += maxs[1] - mid[1];
- //
- end_plane.dist = end_edgeverts[0][2];
- VectorSet(end_plane.normal, 0, 0, 1);
- //
-#ifndef BSPC
-#if 0
- for (i = 0; i < 4; i++)
- {
- AAS_PermanentLine(start_edgeverts[i], start_edgeverts[(i+1)%4], 1);
- AAS_PermanentLine(end_edgeverts[i], end_edgeverts[(i+1)%4], 1);
- } //end for
-#endif
-#endif
- VectorCopy(move_start, move_start_top);
- move_start_top[2] += maxs[2] - mid[2] + 24; //+ bbox maxs z
- VectorCopy(move_end, move_end_top);
- move_end_top[2] += maxs[2] - mid[2] + 24; //+ bbox maxs z
- //
- if (!AAS_PointAreaNum(move_start_top)) continue;
- if (!AAS_PointAreaNum(move_end_top)) continue;
- //
- for (i = 0; i < 2; i++)
- {
- firststartreach = firstendreach = NULL;
- //
- if (i == 0)
- {
- firststartreach = AAS_FindFaceReachabilities(start_edgeverts, 4, &start_plane, qtrue);
- firstendreach = AAS_FindFaceReachabilities(end_edgeverts, 4, &end_plane, qfalse);
- } //end if
- else
- {
- firststartreach = AAS_FindFaceReachabilities(end_edgeverts, 4, &end_plane, qtrue);
- firstendreach = AAS_FindFaceReachabilities(start_edgeverts, 4, &start_plane, qfalse);
- } //end else
- //
- //create reachabilities from start to end
- for (startreach = firststartreach; startreach; startreach = nextstartreach)
- {
- nextstartreach = startreach->next;
- //
- //trace = AAS_TraceClientBBox(startreach->start, move_start_top, PRESENCE_NORMAL, -1);
- //if (trace.fraction < 1) continue;
- //
- for (endreach = firstendreach; endreach; endreach = nextendreach)
- {
- nextendreach = endreach->next;
- //
- //trace = AAS_TraceClientBBox(endreach->end, move_end_top, PRESENCE_NORMAL, -1);
- //if (trace.fraction < 1) continue;
- //
- Log_Write("funcbob reach from area %d to %d\n", startreach->areanum, endreach->areanum);
- //
- //
- if (i == 0) VectorCopy(move_start_top, org);
- else VectorCopy(move_end_top, org);
- VectorSubtract(startreach->start, org, dir);
- dir[2] = 0;
- VectorNormalize(dir);
- VectorCopy(startreach->start, start);
- VectorMA(startreach->start, 1, dir, start);
- start[2] += 1;
- VectorMA(startreach->start, 16, dir, end);
- end[2] += 1;
- //
- numareas = AAS_TraceAreas(start, end, areas, points, 10);
- if (numareas <= 0) continue;
- if (numareas > 1) VectorCopy(points[1], startreach->start);
- else VectorCopy(end, startreach->start);
- //
- if (!AAS_PointAreaNum(startreach->start)) continue;
- if (!AAS_PointAreaNum(endreach->end)) continue;
- //
- lreach = AAS_AllocReachability();
- lreach->areanum = endreach->areanum;
- if (i == 0) lreach->edgenum = ((int)move_start[axis] << 16) | ((int) move_end[axis] & 0x0000ffff);
- else lreach->edgenum = ((int)move_end[axis] << 16) | ((int) move_start[axis] & 0x0000ffff);
- lreach->facenum = (spawnflags << 16) | modelnum;
- VectorCopy(startreach->start, lreach->start);
- VectorCopy(endreach->end, lreach->end);
-#ifndef BSPC
-// AAS_DrawArrow(lreach->start, lreach->end, LINECOLOR_BLUE, LINECOLOR_YELLOW);
-// AAS_PermanentLine(lreach->start, lreach->end, 1);
-#endif
- lreach->traveltype = TRAVEL_FUNCBOB;
- lreach->traveltype |= AAS_TravelFlagsForTeam(ent);
- lreach->traveltime = aassettings.rs_funcbob;
- reach_funcbob++;
- lreach->next = areareachability[startreach->areanum];
- areareachability[startreach->areanum] = lreach;
- //
- } //end for
- } //end for
- for (startreach = firststartreach; startreach; startreach = nextstartreach)
- {
- nextstartreach = startreach->next;
- AAS_FreeReachability(startreach);
- } //end for
- for (endreach = firstendreach; endreach; endreach = nextendreach)
- {
- nextendreach = endreach->next;
- AAS_FreeReachability(endreach);
- } //end for
- //only go up with func_bobbing entities that go up and down
- if (!(spawnflags & 1) && !(spawnflags & 2)) break;
- } //end for
- } //end for
-} //end of the function AAS_Reachability_FuncBobbing
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_Reachability_JumpPad(void)
-{
- int face2num, i, ret, area2num, visualize, ent, bot_visualizejumppads;
- //int modelnum, ent2;
- //float dist, time, height, gravity, forward;
- float speed, zvel, hordist;
- aas_face_t *face2;
- aas_area_t *area2;
- aas_lreachability_t *lreach;
- vec3_t areastart, facecenter, dir, cmdmove;
- vec3_t velocity, absmins, absmaxs;
- //vec3_t origin, ent2origin, angles, teststart;
- aas_clientmove_t move;
- //aas_trace_t trace;
- aas_link_t *areas, *link;
- //char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY], model[MAX_EPAIRKEY];
- char classname[MAX_EPAIRKEY];
-
-#ifdef BSPC
- bot_visualizejumppads = 0;
-#else
- bot_visualizejumppads = LibVarValue("bot_visualizejumppads", "0");
-#endif
- for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
- {
- if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
- if (strcmp(classname, "trigger_push")) continue;
- //
- if (!AAS_GetJumpPadInfo(ent, areastart, absmins, absmaxs, velocity)) continue;
- /*
- //
- AAS_FloatForBSPEpairKey(ent, "speed", &speed);
- if (!speed) speed = 1000;
-// AAS_VectorForBSPEpairKey(ent, "angles", angles);
-// AAS_SetMovedir(angles, velocity);
-// VectorScale(velocity, speed, velocity);
- VectorClear(angles);
- //get the mins, maxs and origin of the model
- AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY);
- if (model[0]) modelnum = atoi(model+1);
- else modelnum = 0;
- AAS_BSPModelMinsMaxsOrigin(modelnum, angles, absmins, absmaxs, origin);
- VectorAdd(origin, absmins, absmins);
- VectorAdd(origin, absmaxs, absmaxs);
- //
-#ifdef REACH_DEBUG
- botimport.Print(PRT_MESSAGE, "absmins = %f %f %f\n", absmins[0], absmins[1], absmins[2]);
- botimport.Print(PRT_MESSAGE, "absmaxs = %f %f %f\n", absmaxs[0], absmaxs[1], absmaxs[2]);
-#endif REACH_DEBUG
- VectorAdd(absmins, absmaxs, origin);
- VectorScale (origin, 0.5, origin);
-
- //get the start areas
- VectorCopy(origin, teststart);
- teststart[2] += 64;
- trace = AAS_TraceClientBBox(teststart, origin, PRESENCE_CROUCH, -1);
- if (trace.startsolid)
- {
- botimport.Print(PRT_MESSAGE, "trigger_push start solid\n");
- VectorCopy(origin, areastart);
- } //end if
- else
- {
- VectorCopy(trace.endpos, areastart);
- } //end else
- areastart[2] += 0.125;
- //
- //AAS_DrawPermanentCross(origin, 4, 4);
- //get the target entity
- AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY);
- for (ent2 = AAS_NextBSPEntity(0); ent2; ent2 = AAS_NextBSPEntity(ent2))
- {
- if (!AAS_ValueForBSPEpairKey(ent2, "targetname", targetname, MAX_EPAIRKEY)) continue;
- if (!strcmp(targetname, target)) break;
- } //end for
- if (!ent2)
- {
- botimport.Print(PRT_MESSAGE, "trigger_push without target entity %s\n", target);
- continue;
- } //end if
- AAS_VectorForBSPEpairKey(ent2, "origin", ent2origin);
- //
- height = ent2origin[2] - origin[2];
- gravity = aassettings.sv_gravity;
- time = sqrt( height / ( 0.5 * gravity ) );
- if (!time)
- {
- botimport.Print(PRT_MESSAGE, "trigger_push without time\n");
- continue;
- } //end if
- // set s.origin2 to the push velocity
- VectorSubtract ( ent2origin, origin, velocity);
- dist = VectorNormalize( velocity);
- forward = dist / time;
- //FIXME: why multiply by 1.1
- forward *= 1.1;
- VectorScale(velocity, forward, velocity);
- velocity[2] = time * gravity;
- */
- //get the areas the jump pad brush is in
- areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH);
- /*
- for (link = areas; link; link = link->next_area)
- {
- if (link->areanum == 563)
- {
- ret = qfalse;
- }
- }
- */
- for (link = areas; link; link = link->next_area)
- {
- if (AAS_AreaJumpPad(link->areanum)) break;
- } //end for
- if (!link)
- {
- botimport.Print(PRT_MESSAGE, "trigger_push not in any jump pad area\n");
- AAS_UnlinkFromAreas(areas);
- continue;
- } //end if
- //
- botimport.Print(PRT_MESSAGE, "found a trigger_push with velocity %f %f %f\n", velocity[0], velocity[1], velocity[2]);
- //if there is a horizontal velocity check for a reachability without air control
- if (velocity[0] || velocity[1])
- {
- VectorSet(cmdmove, 0, 0, 0);
- //VectorCopy(velocity, cmdmove);
- //cmdmove[2] = 0;
- Com_Memset(&move, 0, sizeof(aas_clientmove_t));
- area2num = 0;
- for (i = 0; i < 20; i++)
- {
- AAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qfalse,
- velocity, cmdmove, 0, 30, 0.1f,
- SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME|
- SE_ENTERLAVA|SE_HITGROUNDDAMAGE|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER, 0, bot_visualizejumppads);
- area2num = move.endarea;
- for (link = areas; link; link = link->next_area)
- {
- if (!AAS_AreaJumpPad(link->areanum)) continue;
- if (link->areanum == area2num) break;
- } //end if
- if (!link) break;
- VectorCopy(move.endpos, areastart);
- VectorCopy(move.velocity, velocity);
- } //end for
- if (area2num && i < 20)
- {
- for (link = areas; link; link = link->next_area)
- {
- if (!AAS_AreaJumpPad(link->areanum)) continue;
- if (AAS_ReachabilityExists(link->areanum, area2num)) continue;
- //create a rocket or bfg jump reachability from area1 to area2
- lreach = AAS_AllocReachability();
- if (!lreach)
- {
- AAS_UnlinkFromAreas(areas);
- return;
- } //end if
- lreach->areanum = area2num;
- //NOTE: the facenum is the Z velocity
- lreach->facenum = velocity[2];
- //NOTE: the edgenum is the horizontal velocity
- lreach->edgenum = sqrt(velocity[0] * velocity[0] + velocity[1] * velocity[1]);
- VectorCopy(areastart, lreach->start);
- VectorCopy(move.endpos, lreach->end);
- lreach->traveltype = TRAVEL_JUMPPAD;
- lreach->traveltype |= AAS_TravelFlagsForTeam(ent);
- lreach->traveltime = aassettings.rs_jumppad;
- lreach->next = areareachability[link->areanum];
- areareachability[link->areanum] = lreach;
- //
- reach_jumppad++;
- } //end for
- } //end if
- } //end if
- //
- if (fabs(velocity[0]) > 100 || fabs(velocity[1]) > 100) continue;
- //check for areas we can reach with air control
- for (area2num = 1; area2num < aasworld.numareas; area2num++)
- {
- visualize = qfalse;
- /*
- if (area2num == 3568)
- {
- for (link = areas; link; link = link->next_area)
- {
- if (link->areanum == 3380)
- {
- visualize = qtrue;
- botimport.Print(PRT_MESSAGE, "bah\n");
- } //end if
- } //end for
- } //end if*/
- //never try to go back to one of the original jumppad areas
- //and don't create reachabilities if they already exist
- for (link = areas; link; link = link->next_area)
- {
- if (AAS_ReachabilityExists(link->areanum, area2num)) break;
- if (AAS_AreaJumpPad(link->areanum))
- {
- if (link->areanum == area2num) break;
- } //end if
- } //end if
- if (link) continue;
- //
- area2 = &aasworld.areas[area2num];
- for (i = 0; i < area2->numfaces; i++)
- {
- face2num = aasworld.faceindex[area2->firstface + i];
- face2 = &aasworld.faces[abs(face2num)];
- //if it is not a ground face
- if (!(face2->faceflags & FACE_GROUND)) continue;
- //get the center of the face
- AAS_FaceCenter(face2num, facecenter);
- //only go higher up
- if (facecenter[2] < areastart[2]) continue;
- //get the jumppad jump z velocity
- zvel = velocity[2];
- //get the horizontal speed for the jump, if it isn't possible to calculate this
- //speed
- ret = AAS_HorizontalVelocityForJump(zvel, areastart, facecenter, &speed);
- if (ret && speed < 150)
- {
- //direction towards the face center
- VectorSubtract(facecenter, areastart, dir);
- dir[2] = 0;
- hordist = VectorNormalize(dir);
- //if (hordist < 1.6 * facecenter[2] - areastart[2])
- {
- //get command movement
- VectorScale(dir, speed, cmdmove);
- //
- AAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qfalse,
- velocity, cmdmove, 30, 30, 0.1f,
- SE_ENTERWATER|SE_ENTERSLIME|
- SE_ENTERLAVA|SE_HITGROUNDDAMAGE|
- SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER|SE_HITGROUNDAREA, area2num, visualize);
- //if prediction time wasn't enough to fully predict the movement
- //don't enter slime or lava and don't fall from too high
- if (move.frames < 30 &&
- !(move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))
- && (move.stopevent & (SE_HITGROUNDAREA|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER)))
- {
- //never go back to the same jumppad
- for (link = areas; link; link = link->next_area)
- {
- if (link->areanum == move.endarea) break;
- }
- if (!link)
- {
- for (link = areas; link; link = link->next_area)
- {
- if (!AAS_AreaJumpPad(link->areanum)) continue;
- if (AAS_ReachabilityExists(link->areanum, area2num)) continue;
- //create a jumppad reachability from area1 to area2
- lreach = AAS_AllocReachability();
- if (!lreach)
- {
- AAS_UnlinkFromAreas(areas);
- return;
- } //end if
- lreach->areanum = move.endarea;
- //NOTE: the facenum is the Z velocity
- lreach->facenum = velocity[2];
- //NOTE: the edgenum is the horizontal velocity
- lreach->edgenum = sqrt(cmdmove[0] * cmdmove[0] + cmdmove[1] * cmdmove[1]);
- VectorCopy(areastart, lreach->start);
- VectorCopy(facecenter, lreach->end);
- lreach->traveltype = TRAVEL_JUMPPAD;
- lreach->traveltype |= AAS_TravelFlagsForTeam(ent);
- lreach->traveltime = aassettings.rs_aircontrolledjumppad;
- lreach->next = areareachability[link->areanum];
- areareachability[link->areanum] = lreach;
- //
- reach_jumppad++;
- } //end for
- }
- } //end if
- } //end if
- } //end for
- } //end for
- } //end for
- AAS_UnlinkFromAreas(areas);
- } //end for
-} //end of the function AAS_Reachability_JumpPad
-//===========================================================================
-// never point at ground faces
-// always a higher and pretty far area
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_Reachability_Grapple(int area1num, int area2num)
-{
- int face2num, i, j, areanum, numareas, areas[20];
- float mingrappleangle, z, hordist;
- bsp_trace_t bsptrace;
- aas_trace_t trace;
- aas_face_t *face2;
- aas_area_t *area1, *area2;
- aas_lreachability_t *lreach;
- vec3_t areastart, facecenter, start, end, dir, down = {0, 0, -1};
- vec_t *v;
-
- //only grapple when on the ground or swimming
- if (!AAS_AreaGrounded(area1num) && !AAS_AreaSwim(area1num)) return qfalse;
- //don't grapple from a crouch area
- if (!(AAS_AreaPresenceType(area1num) & PRESENCE_NORMAL)) return qfalse;
- //NOTE: disabled area swim it doesn't work right
- if (AAS_AreaSwim(area1num)) return qfalse;
- //
- area1 = &aasworld.areas[area1num];
- area2 = &aasworld.areas[area2num];
- //don't grapple towards way lower areas
- if (area2->maxs[2] < area1->mins[2]) return qfalse;
- //
- VectorCopy(aasworld.areas[area1num].center, start);
- //if not a swim area
- if (!AAS_AreaSwim(area1num))
- {
- if (!AAS_PointAreaNum(start)) Log_Write("area %d center %f %f %f in solid?\r\n", area1num,
- start[0], start[1], start[2]);
- VectorCopy(start, end);
- end[2] -= 1000;
- trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);
- if (trace.startsolid) return qfalse;
- VectorCopy(trace.endpos, areastart);
- } //end if
- else
- {
- if (!(AAS_PointContents(start) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return qfalse;
- } //end else
- //
- //start is now the start point
- //
- for (i = 0; i < area2->numfaces; i++)
- {
- face2num = aasworld.faceindex[area2->firstface + i];
- face2 = &aasworld.faces[abs(face2num)];
- //if it is not a solid face
- if (!(face2->faceflags & FACE_SOLID)) continue;
- //direction towards the first vertex of the face
- v = aasworld.vertexes[aasworld.edges[abs(aasworld.edgeindex[face2->firstedge])].v[0]];
- VectorSubtract(v, areastart, dir);
- //if the face plane is facing away
- if (DotProduct(aasworld.planes[face2->planenum].normal, dir) > 0) continue;
- //get the center of the face
- AAS_FaceCenter(face2num, facecenter);
- //only go higher up with the grapple
- if (facecenter[2] < areastart[2] + 64) continue;
- //only use vertical faces or downward facing faces
- if (DotProduct(aasworld.planes[face2->planenum].normal, down) < 0) continue;
- //direction towards the face center
- VectorSubtract(facecenter, areastart, dir);
- //
- z = dir[2];
- dir[2] = 0;
- hordist = VectorLength(dir);
- if (!hordist) continue;
- //if too far
- if (hordist > 2000) continue;
- //check the minimal angle of the movement
- mingrappleangle = 15; //15 degrees
- if (z / hordist < tan(2 * M_PI * mingrappleangle / 360)) continue;
- //
- VectorCopy(facecenter, start);
- VectorMA(facecenter, -500, aasworld.planes[face2->planenum].normal, end);
- //
- bsptrace = AAS_Trace(start, NULL, NULL, end, 0, CONTENTS_SOLID);
- //the grapple won't stick to the sky and the grapple point should be near the AAS wall
- if ((bsptrace.surface.flags & SURF_SKY) || (bsptrace.fraction * 500 > 32)) continue;
- //trace a full bounding box from the area center on the ground to
- //the center of the face
- VectorSubtract(facecenter, areastart, dir);
- VectorNormalize(dir);
- VectorMA(areastart, 4, dir, start);
- VectorCopy(bsptrace.endpos, end);
- trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1);
- VectorSubtract(trace.endpos, facecenter, dir);
- if (VectorLength(dir) > 24) continue;
- //
- VectorCopy(trace.endpos, start);
- VectorCopy(trace.endpos, end);
- end[2] -= AAS_FallDamageDistance();
- trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1);
- if (trace.fraction >= 1) continue;
- //area to end in
- areanum = AAS_PointAreaNum(trace.endpos);
- //if not in lava or slime
- if (aasworld.areasettings[areanum].contents & (AREACONTENTS_SLIME|AREACONTENTS_LAVA))
- {
- continue;
- } //end if
- //do not go the the source area
- if (areanum == area1num) continue;
- //don't create reachabilities if they already exist
- if (AAS_ReachabilityExists(area1num, areanum)) continue;
- //only end in areas we can stand
- if (!AAS_AreaGrounded(areanum)) continue;
- //never go through cluster portals!!
- numareas = AAS_TraceAreas(areastart, bsptrace.endpos, areas, NULL, 20);
- if (numareas >= 20) continue;
- for (j = 0; j < numareas; j++)
- {
- if (aasworld.areasettings[areas[j]].contents & AREACONTENTS_CLUSTERPORTAL) break;
- } //end for
- if (j < numareas) continue;
- //create a new reachability link
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = areanum;
- lreach->facenum = face2num;
- lreach->edgenum = 0;
- VectorCopy(areastart, lreach->start);
- //VectorCopy(facecenter, lreach->end);
- VectorCopy(bsptrace.endpos, lreach->end);
- lreach->traveltype = TRAVEL_GRAPPLEHOOK;
- VectorSubtract(lreach->end, lreach->start, dir);
- lreach->traveltime = aassettings.rs_startgrapple + VectorLength(dir) * 0.25;
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //
- reach_grapple++;
- } //end for
- //
- return qfalse;
-} //end of the function AAS_Reachability_Grapple
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_SetWeaponJumpAreaFlags(void)
-{
- int ent, i;
- vec3_t mins = {-15, -15, -15}, maxs = {15, 15, 15};
- vec3_t origin;
- int areanum, weaponjumpareas, spawnflags;
- char classname[MAX_EPAIRKEY];
-
- weaponjumpareas = 0;
- for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
- {
- if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
- if (
- !strcmp(classname, "item_armor_body") ||
- !strcmp(classname, "item_armor_combat") ||
- !strcmp(classname, "item_health_mega") ||
- !strcmp(classname, "weapon_grenadelauncher") ||
- !strcmp(classname, "weapon_rocketlauncher") ||
- !strcmp(classname, "weapon_lightning") ||
- !strcmp(classname, "weapon_plasmagun") ||
- !strcmp(classname, "weapon_railgun") ||
- !strcmp(classname, "weapon_bfg") ||
- !strcmp(classname, "item_quad") ||
- !strcmp(classname, "item_regen") ||
- !strcmp(classname, "item_invulnerability"))
- {
- if (AAS_VectorForBSPEpairKey(ent, "origin", origin))
- {
- spawnflags = 0;
- AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags);
- //if not a stationary item
- if (!(spawnflags & 1))
- {
- if (!AAS_DropToFloor(origin, mins, maxs))
- {
- botimport.Print(PRT_MESSAGE, "%s in solid at (%1.1f %1.1f %1.1f)\n",
- classname, origin[0], origin[1], origin[2]);
- } //end if
- } //end if
- //areanum = AAS_PointAreaNum(origin);
- areanum = AAS_BestReachableArea(origin, mins, maxs, origin);
- //the bot may rocket jump towards this area
- aasworld.areasettings[areanum].areaflags |= AREA_WEAPONJUMP;
- //
- //if (!AAS_AreaGrounded(areanum))
- // botimport.Print(PRT_MESSAGE, "area not grounded\n");
- //
- weaponjumpareas++;
- } //end if
- } //end if
- } //end for
- for (i = 1; i < aasworld.numareas; i++)
- {
- if (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD)
- {
- aasworld.areasettings[i].areaflags |= AREA_WEAPONJUMP;
- weaponjumpareas++;
- } //end if
- } //end for
- botimport.Print(PRT_MESSAGE, "%d weapon jump areas\n", weaponjumpareas);
-} //end of the function AAS_SetWeaponJumpAreaFlags
-//===========================================================================
-// create a possible weapon jump reachability from area1 to area2
-//
-// check if there's a cool item in the second area
-// check if area1 is lower than area2
-// check if the bot can rocketjump from area1 to area2
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_Reachability_WeaponJump(int area1num, int area2num)
-{
- int face2num, i, n, ret, visualize;
- float speed, zvel, hordist;
- aas_face_t *face2;
- aas_area_t *area1, *area2;
- aas_lreachability_t *lreach;
- vec3_t areastart, facecenter, start, end, dir, cmdmove;// teststart;
- vec3_t velocity;
- aas_clientmove_t move;
- aas_trace_t trace;
-
- visualize = qfalse;
-// if (area1num == 4436 && area2num == 4318)
-// {
-// visualize = qtrue;
-// }
- if (!AAS_AreaGrounded(area1num) || AAS_AreaSwim(area1num)) return qfalse;
- if (!AAS_AreaGrounded(area2num)) return qfalse;
- //NOTE: only weapon jump towards areas with an interesting item in it??
- if (!(aasworld.areasettings[area2num].areaflags & AREA_WEAPONJUMP)) return qfalse;
- //
- area1 = &aasworld.areas[area1num];
- area2 = &aasworld.areas[area2num];
- //don't weapon jump towards way lower areas
- if (area2->maxs[2] < area1->mins[2]) return qfalse;
- //
- VectorCopy(aasworld.areas[area1num].center, start);
- //if not a swim area
- if (!AAS_PointAreaNum(start)) Log_Write("area %d center %f %f %f in solid?\r\n", area1num,
- start[0], start[1], start[2]);
- VectorCopy(start, end);
- end[2] -= 1000;
- trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);
- if (trace.startsolid) return qfalse;
- VectorCopy(trace.endpos, areastart);
- //
- //areastart is now the start point
- //
- for (i = 0; i < area2->numfaces; i++)
- {
- face2num = aasworld.faceindex[area2->firstface + i];
- face2 = &aasworld.faces[abs(face2num)];
- //if it is not a solid face
- if (!(face2->faceflags & FACE_GROUND)) continue;
- //get the center of the face
- AAS_FaceCenter(face2num, facecenter);
- //only go higher up with weapon jumps
- if (facecenter[2] < areastart[2] + 64) continue;
- //NOTE: set to 2 to allow bfg jump reachabilities
- for (n = 0; n < 1/*2*/; n++)
- {
- //get the rocket jump z velocity
- if (n) zvel = AAS_BFGJumpZVelocity(areastart);
- else zvel = AAS_RocketJumpZVelocity(areastart);
- //get the horizontal speed for the jump, if it isn't possible to calculate this
- //speed (the jump is not possible) then there's no jump reachability created
- ret = AAS_HorizontalVelocityForJump(zvel, areastart, facecenter, &speed);
- if (ret && speed < 300)
- {
- //direction towards the face center
- VectorSubtract(facecenter, areastart, dir);
- dir[2] = 0;
- hordist = VectorNormalize(dir);
- //if (hordist < 1.6 * (facecenter[2] - areastart[2]))
- {
- //get command movement
- VectorScale(dir, speed, cmdmove);
- VectorSet(velocity, 0, 0, zvel);
- /*
- //get command movement
- VectorScale(dir, speed, velocity);
- velocity[2] = zvel;
- VectorSet(cmdmove, 0, 0, 0);
- */
- //
- AAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qtrue,
- velocity, cmdmove, 30, 30, 0.1f,
- SE_ENTERWATER|SE_ENTERSLIME|
- SE_ENTERLAVA|SE_HITGROUNDDAMAGE|
- SE_TOUCHJUMPPAD|SE_HITGROUND|SE_HITGROUNDAREA, area2num, visualize);
- //if prediction time wasn't enough to fully predict the movement
- //don't enter slime or lava and don't fall from too high
- if (move.frames < 30 &&
- !(move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))
- && (move.stopevent & (SE_HITGROUNDAREA|SE_TOUCHJUMPPAD)))
- {
- //create a rocket or bfg jump reachability from area1 to area2
- lreach = AAS_AllocReachability();
- if (!lreach) return qfalse;
- lreach->areanum = area2num;
- lreach->facenum = 0;
- lreach->edgenum = 0;
- VectorCopy(areastart, lreach->start);
- VectorCopy(facecenter, lreach->end);
- if (n)
- {
- lreach->traveltype = TRAVEL_BFGJUMP;
- lreach->traveltime = aassettings.rs_bfgjump;
- } //end if
- else
- {
- lreach->traveltype = TRAVEL_ROCKETJUMP;
- lreach->traveltime = aassettings.rs_rocketjump;
- } //end else
- lreach->next = areareachability[area1num];
- areareachability[area1num] = lreach;
- //
- reach_rocketjump++;
- return qtrue;
- } //end if
- } //end if
- } //end if
- } //end for
- } //end for
- //
- return qfalse;
-} //end of the function AAS_Reachability_WeaponJump
-//===========================================================================
-// calculates additional walk off ledge reachabilities for the given area
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_Reachability_WalkOffLedge(int areanum)
-{
- int i, j, k, l, m, n, p, areas[10], numareas;
- int face1num, face2num, face3num, edge1num, edge2num, edge3num;
- int otherareanum, gap, reachareanum, side;
- aas_area_t *area, *area2;
- aas_face_t *face1, *face2, *face3;
- aas_edge_t *edge;
- aas_plane_t *plane;
- vec_t *v1, *v2;
- vec3_t sharededgevec, mid, dir, testend;
- aas_lreachability_t *lreach;
- aas_trace_t trace;
-
- if (!AAS_AreaGrounded(areanum) || AAS_AreaSwim(areanum)) return;
- //
- area = &aasworld.areas[areanum];
- //
- for (i = 0; i < area->numfaces; i++)
- {
- face1num = aasworld.faceindex[area->firstface + i];
- face1 = &aasworld.faces[abs(face1num)];
- //face 1 must be a ground face
- if (!(face1->faceflags & FACE_GROUND)) continue;
- //go through all the edges of this ground face
- for (k = 0; k < face1->numedges; k++)
- {
- edge1num = aasworld.edgeindex[face1->firstedge + k];
- //find another not ground face using this same edge
- for (j = 0; j < area->numfaces; j++)
- {
- face2num = aasworld.faceindex[area->firstface + j];
- face2 = &aasworld.faces[abs(face2num)];
- //face 2 may not be a ground face
- if (face2->faceflags & FACE_GROUND) continue;
- //compare all the edges
- for (l = 0; l < face2->numedges; l++)
- {
- edge2num = aasworld.edgeindex[face2->firstedge + l];
- if (abs(edge1num) == abs(edge2num))
- {
- //get the area at the other side of the face
- if (face2->frontarea == areanum) otherareanum = face2->backarea;
- else otherareanum = face2->frontarea;
- //
- area2 = &aasworld.areas[otherareanum];
- //if the other area is grounded!
- if (aasworld.areasettings[otherareanum].areaflags & AREA_GROUNDED)
- {
- //check for a possible gap
- gap = qfalse;
- for (n = 0; n < area2->numfaces; n++)
- {
- face3num = aasworld.faceindex[area2->firstface + n];
- //may not be the shared face of the two areas
- if (abs(face3num) == abs(face2num)) continue;
- //
- face3 = &aasworld.faces[abs(face3num)];
- //find an edge shared by all three faces
- for (m = 0; m < face3->numedges; m++)
- {
- edge3num = aasworld.edgeindex[face3->firstedge + m];
- //but the edge should be shared by all three faces
- if (abs(edge3num) == abs(edge1num))
- {
- if (!(face3->faceflags & FACE_SOLID))
- {
- gap = qtrue;
- break;
- } //end if
- //
- if (face3->faceflags & FACE_GROUND)
- {
- gap = qfalse;
- break;
- } //end if
- //FIXME: there are more situations to be handled
- gap = qtrue;
- break;
- } //end if
- } //end for
- if (m < face3->numedges) break;
- } //end for
- if (!gap) break;
- } //end if
- //check for a walk off ledge reachability
- edge = &aasworld.edges[abs(edge1num)];
- side = edge1num < 0;
- //
- v1 = aasworld.vertexes[edge->v[side]];
- v2 = aasworld.vertexes[edge->v[!side]];
- //
- plane = &aasworld.planes[face1->planenum];
- //get the points really into the areas
- VectorSubtract(v2, v1, sharededgevec);
- CrossProduct(plane->normal, sharededgevec, dir);
- VectorNormalize(dir);
- //
- VectorAdd(v1, v2, mid);
- VectorScale(mid, 0.5, mid);
- VectorMA(mid, 8, dir, mid);
- //
- VectorCopy(mid, testend);
- testend[2] -= 1000;
- trace = AAS_TraceClientBBox(mid, testend, PRESENCE_CROUCH, -1);
- //
- if (trace.startsolid)
- {
- //Log_Write("area %d: trace.startsolid\r\n", areanum);
- break;
- } //end if
- reachareanum = AAS_PointAreaNum(trace.endpos);
- if (reachareanum == areanum)
- {
- //Log_Write("area %d: same area\r\n", areanum);
- break;
- } //end if
- if (AAS_ReachabilityExists(areanum, reachareanum))
- {
- //Log_Write("area %d: reachability already exists\r\n", areanum);
- break;
- } //end if
- if (!AAS_AreaGrounded(reachareanum) && !AAS_AreaSwim(reachareanum))
- {
- //Log_Write("area %d, reach area %d: not grounded and not swim\r\n", areanum, reachareanum);
- break;
- } //end if
- //
- if (aasworld.areasettings[reachareanum].contents & (AREACONTENTS_SLIME
- | AREACONTENTS_LAVA))
- {
- //Log_Write("area %d, reach area %d: lava or slime\r\n", areanum, reachareanum);
- break;
- } //end if
- //if not going through a cluster portal
- numareas = AAS_TraceAreas(mid, testend, areas, NULL, sizeof(areas) / sizeof(int));
- for (p = 0; p < numareas; p++)
- if (AAS_AreaClusterPortal(areas[p]))
- break;
- if (p < numareas)
- break;
- // if a maximum fall height is set and the bot would fall down further
- if (aassettings.rs_maxfallheight && fabs(mid[2] - trace.endpos[2]) > aassettings.rs_maxfallheight)
- break;
- //
- lreach = AAS_AllocReachability();
- if (!lreach) break;
- lreach->areanum = reachareanum;
- lreach->facenum = 0;
- lreach->edgenum = edge1num;
- VectorCopy(mid, lreach->start);
- VectorCopy(trace.endpos, lreach->end);
- lreach->traveltype = TRAVEL_WALKOFFLEDGE;
- lreach->traveltime = aassettings.rs_startwalkoffledge + fabs(mid[2] - trace.endpos[2]) * 50 / aassettings.phys_gravity;
- if (!AAS_AreaSwim(reachareanum) && !AAS_AreaJumpPad(reachareanum))
- {
- if (AAS_FallDelta(mid[2] - trace.endpos[2]) > aassettings.phys_falldelta5)
- {
- lreach->traveltime += aassettings.rs_falldamage5;
- } //end if
- else if (AAS_FallDelta(mid[2] - trace.endpos[2]) > aassettings.phys_falldelta10)
- {
- lreach->traveltime += aassettings.rs_falldamage10;
- } //end if
- } //end if
- lreach->next = areareachability[areanum];
- areareachability[areanum] = lreach;
- //we've got another walk off ledge reachability
- reach_walkoffledge++;
- } //end if
- } //end for
- } //end for
- } //end for
- } //end for
-} //end of the function AAS_Reachability_WalkOffLedge
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_StoreReachability(void)
-{
- int i;
- aas_areasettings_t *areasettings;
- aas_lreachability_t *lreach;
- aas_reachability_t *reach;
-
- if (aasworld.reachability) FreeMemory(aasworld.reachability);
- aasworld.reachability = (aas_reachability_t *) GetClearedMemory((numlreachabilities + 10) * sizeof(aas_reachability_t));
- aasworld.reachabilitysize = 1;
- for (i = 0; i < aasworld.numareas; i++)
- {
- areasettings = &aasworld.areasettings[i];
- areasettings->firstreachablearea = aasworld.reachabilitysize;
- areasettings->numreachableareas = 0;
- for (lreach = areareachability[i]; lreach; lreach = lreach->next)
- {
- reach = &aasworld.reachability[areasettings->firstreachablearea +
- areasettings->numreachableareas];
- reach->areanum = lreach->areanum;
- reach->facenum = lreach->facenum;
- reach->edgenum = lreach->edgenum;
- VectorCopy(lreach->start, reach->start);
- VectorCopy(lreach->end, reach->end);
- reach->traveltype = lreach->traveltype;
- reach->traveltime = lreach->traveltime;
- //
- areasettings->numreachableareas++;
- } //end for
- aasworld.reachabilitysize += areasettings->numreachableareas;
- } //end for
-} //end of the function AAS_StoreReachability
-//===========================================================================
-//
-// TRAVEL_WALK 100% equal floor height + steps
-// TRAVEL_CROUCH 100%
-// TRAVEL_BARRIERJUMP 100%
-// TRAVEL_JUMP 80%
-// TRAVEL_LADDER 100% + fall down from ladder + jump up to ladder
-// TRAVEL_WALKOFFLEDGE 90% walk off very steep walls?
-// TRAVEL_SWIM 100%
-// TRAVEL_WATERJUMP 100%
-// TRAVEL_TELEPORT 100%
-// TRAVEL_ELEVATOR 100%
-// TRAVEL_GRAPPLEHOOK 100%
-// TRAVEL_DOUBLEJUMP 0%
-// TRAVEL_RAMPJUMP 0%
-// TRAVEL_STRAFEJUMP 0%
-// TRAVEL_ROCKETJUMP 100% (currently limited towards areas with items)
-// TRAVEL_BFGJUMP 0% (currently disabled)
-// TRAVEL_JUMPPAD 100%
-// TRAVEL_FUNCBOB 100%
-//
-// Parameter: -
-// Returns: true if NOT finished
-// Changes Globals: -
-//===========================================================================
-int AAS_ContinueInitReachability(float time)
-{
- int i, j, todo, start_time;
- static float framereachability, reachability_delay;
- static int lastpercentage;
-
- if (!aasworld.loaded) return qfalse;
- //if reachability is calculated for all areas
- if (aasworld.numreachabilityareas >= aasworld.numareas + 2) return qfalse;
- //if starting with area 1 (area 0 is a dummy)
- if (aasworld.numreachabilityareas == 1)
- {
- botimport.Print(PRT_MESSAGE, "calculating reachability...\n");
- lastpercentage = 0;
- framereachability = 2000;
- reachability_delay = 1000;
- } //end if
- //number of areas to calculate reachability for this cycle
- todo = aasworld.numreachabilityareas + (int) framereachability;
- start_time = Sys_MilliSeconds();
- //loop over the areas
- for (i = aasworld.numreachabilityareas; i < aasworld.numareas && i < todo; i++)
- {
- aasworld.numreachabilityareas++;
- //only create jumppad reachabilities from jumppad areas
- if (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD)
- {
- continue;
- } //end if
- //loop over the areas
- for (j = 1; j < aasworld.numareas; j++)
- {
- if (i == j) continue;
- //never create reachabilities from teleporter or jumppad areas to regular areas
- if (aasworld.areasettings[i].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD))
- {
- if (!(aasworld.areasettings[j].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD)))
- {
- continue;
- } //end if
- } //end if
- //if there already is a reachability link from area i to j
- if (AAS_ReachabilityExists(i, j)) continue;
- //check for a swim reachability
- if (AAS_Reachability_Swim(i, j)) continue;
- //check for a simple walk on equal floor height reachability
- if (AAS_Reachability_EqualFloorHeight(i, j)) continue;
- //check for step, barrier, waterjump and walk off ledge reachabilities
- if (AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge(i, j)) continue;
- //check for ladder reachabilities
- if (AAS_Reachability_Ladder(i, j)) continue;
- //check for a jump reachability
- if (AAS_Reachability_Jump(i, j)) continue;
- } //end for
- //never create these reachabilities from teleporter or jumppad areas
- if (aasworld.areasettings[i].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD))
- {
- continue;
- } //end if
- //loop over the areas
- for (j = 1; j < aasworld.numareas; j++)
- {
- if (i == j) continue;
- //
- if (AAS_ReachabilityExists(i, j)) continue;
- //check for a grapple hook reachability
- if (calcgrapplereach) AAS_Reachability_Grapple(i, j);
- //check for a weapon jump reachability
- AAS_Reachability_WeaponJump(i, j);
- } //end for
- //if the calculation took more time than the max reachability delay
- if (Sys_MilliSeconds() - start_time > (int) reachability_delay) break;
- //
- if (aasworld.numreachabilityareas * 1000 / aasworld.numareas > lastpercentage) break;
- } //end for
- //
- if (aasworld.numreachabilityareas == aasworld.numareas)
- {
- botimport.Print(PRT_MESSAGE, "\r%6.1f%%", (float) 100.0);
- botimport.Print(PRT_MESSAGE, "\nplease wait while storing reachability...\n");
- aasworld.numreachabilityareas++;
- } //end if
- //if this is the last step in the reachability calculations
- else if (aasworld.numreachabilityareas == aasworld.numareas + 1)
- {
- //create additional walk off ledge reachabilities for every area
- for (i = 1; i < aasworld.numareas; i++)
- {
- //only create jumppad reachabilities from jumppad areas
- if (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD)
- {
- continue;
- } //end if
- AAS_Reachability_WalkOffLedge(i);
- } //end for
- //create jump pad reachabilities
- AAS_Reachability_JumpPad();
- //create teleporter reachabilities
- AAS_Reachability_Teleport();
- //create elevator (func_plat) reachabilities
- AAS_Reachability_Elevator();
- //create func_bobbing reachabilities
- AAS_Reachability_FuncBobbing();
- //
-#ifdef DEBUG
- botimport.Print(PRT_MESSAGE, "%6d reach swim\n", reach_swim);
- botimport.Print(PRT_MESSAGE, "%6d reach equal floor\n", reach_equalfloor);
- botimport.Print(PRT_MESSAGE, "%6d reach step\n", reach_step);
- botimport.Print(PRT_MESSAGE, "%6d reach barrier\n", reach_barrier);
- botimport.Print(PRT_MESSAGE, "%6d reach waterjump\n", reach_waterjump);
- botimport.Print(PRT_MESSAGE, "%6d reach walkoffledge\n", reach_walkoffledge);
- botimport.Print(PRT_MESSAGE, "%6d reach jump\n", reach_jump);
- botimport.Print(PRT_MESSAGE, "%6d reach ladder\n", reach_ladder);
- botimport.Print(PRT_MESSAGE, "%6d reach walk\n", reach_walk);
- botimport.Print(PRT_MESSAGE, "%6d reach teleport\n", reach_teleport);
- botimport.Print(PRT_MESSAGE, "%6d reach funcbob\n", reach_funcbob);
- botimport.Print(PRT_MESSAGE, "%6d reach elevator\n", reach_elevator);
- botimport.Print(PRT_MESSAGE, "%6d reach grapple\n", reach_grapple);
- botimport.Print(PRT_MESSAGE, "%6d reach rocketjump\n", reach_rocketjump);
- botimport.Print(PRT_MESSAGE, "%6d reach jumppad\n", reach_jumppad);
-#endif
- //*/
- //store all the reachabilities
- AAS_StoreReachability();
- //free the reachability link heap
- AAS_ShutDownReachabilityHeap();
- //
- FreeMemory(areareachability);
- //
- aasworld.numreachabilityareas++;
- //
- botimport.Print(PRT_MESSAGE, "calculating clusters...\n");
- } //end if
- else
- {
- lastpercentage = aasworld.numreachabilityareas * 1000 / aasworld.numareas;
- botimport.Print(PRT_MESSAGE, "\r%6.1f%%", (float) lastpercentage / 10);
- } //end else
- //not yet finished
- return qtrue;
-} //end of the function AAS_ContinueInitReachability
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitReachability(void)
-{
- if (!aasworld.loaded) return;
-
- if (aasworld.reachabilitysize)
- {
-#ifndef BSPC
- if (!((int)LibVarGetValue("forcereachability")))
- {
- aasworld.numreachabilityareas = aasworld.numareas + 2;
- return;
- } //end if
-#else
- aasworld.numreachabilityareas = aasworld.numareas + 2;
- return;
-#endif //BSPC
- } //end if
-#ifndef BSPC
- calcgrapplereach = LibVarGetValue("grapplereach");
-#endif
- aasworld.savefile = qtrue;
- //start with area 1 because area zero is a dummy
- aasworld.numreachabilityareas = 1;
- ////aasworld.numreachabilityareas = aasworld.numareas + 1; //only calculate entity reachabilities
- //setup the heap with reachability links
- AAS_SetupReachabilityHeap();
- //allocate area reachability link array
- areareachability = (aas_lreachability_t **) GetClearedMemory(
- aasworld.numareas * sizeof(aas_lreachability_t *));
- //
- AAS_SetWeaponJumpAreaFlags();
-} //end of the function AAS_InitReachable
diff --git a/engine/code/botlib/be_aas_route.c b/engine/code/botlib/be_aas_route.c
deleted file mode 100644
index 0d240dc..0000000
--- a/engine/code/botlib/be_aas_route.c
+++ /dev/null
@@ -1,2210 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_route.c
- *
- * desc: AAS
- *
- * $Archive: /MissionPack/code/botlib/be_aas_route.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_utils.h"
-#include "l_memory.h"
-#include "l_log.h"
-#include "l_crc.h"
-#include "l_libvar.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-#include "be_aas_def.h"
-
-#define ROUTING_DEBUG
-
-//travel time in hundreths of a second = distance * 100 / speed
-#define DISTANCEFACTOR_CROUCH 1.3f //crouch speed = 100
-#define DISTANCEFACTOR_SWIM 1 //should be 0.66, swim speed = 150
-#define DISTANCEFACTOR_WALK 0.33f //walk speed = 300
-
-//cache refresh time
-#define CACHE_REFRESHTIME 15.0f //15 seconds refresh time
-
-//maximum number of routing updates each frame
-#define MAX_FRAMEROUTINGUPDATES 10
-
-
-/*
-
- area routing cache:
- stores the distances within one cluster to a specific goal area
- this goal area is in this same cluster and could be a cluster portal
- for every cluster there's a list with routing cache for every area
- in that cluster (including the portals of that cluster)
- area cache stores aasworld.clusters[?].numreachabilityareas travel times
-
- portal routing cache:
- stores the distances of all portals to a specific goal area
- this goal area could be in any cluster and could also be a cluster portal
- for every area (aasworld.numareas) the portal cache stores
- aasworld.numportals travel times
-
-*/
-
-#ifdef ROUTING_DEBUG
-int numareacacheupdates;
-int numportalcacheupdates;
-#endif //ROUTING_DEBUG
-
-int routingcachesize;
-int max_routingcachesize;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef ROUTING_DEBUG
-void AAS_RoutingInfo(void)
-{
- botimport.Print(PRT_MESSAGE, "%d area cache updates\n", numareacacheupdates);
- botimport.Print(PRT_MESSAGE, "%d portal cache updates\n", numportalcacheupdates);
- botimport.Print(PRT_MESSAGE, "%d bytes routing cache\n", routingcachesize);
-} //end of the function AAS_RoutingInfo
-#endif //ROUTING_DEBUG
-//===========================================================================
-// returns the number of the area in the cluster
-// assumes the given area is in the given cluster or a portal of the cluster
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-ID_INLINE int AAS_ClusterAreaNum(int cluster, int areanum)
-{
- int side, areacluster;
-
- areacluster = aasworld.areasettings[areanum].cluster;
- if (areacluster > 0) return aasworld.areasettings[areanum].clusterareanum;
- else
- {
-/*#ifdef ROUTING_DEBUG
- if (aasworld.portals[-areacluster].frontcluster != cluster &&
- aasworld.portals[-areacluster].backcluster != cluster)
- {
- botimport.Print(PRT_ERROR, "portal %d: does not belong to cluster %d\n"
- , -areacluster, cluster);
- } //end if
-#endif //ROUTING_DEBUG*/
- side = aasworld.portals[-areacluster].frontcluster != cluster;
- return aasworld.portals[-areacluster].clusterareanum[side];
- } //end else
-} //end of the function AAS_ClusterAreaNum
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitTravelFlagFromType(void)
-{
- int i;
-
- for (i = 0; i < MAX_TRAVELTYPES; i++)
- {
- aasworld.travelflagfortype[i] = TFL_INVALID;
- } //end for
- aasworld.travelflagfortype[TRAVEL_INVALID] = TFL_INVALID;
- aasworld.travelflagfortype[TRAVEL_WALK] = TFL_WALK;
- aasworld.travelflagfortype[TRAVEL_CROUCH] = TFL_CROUCH;
- aasworld.travelflagfortype[TRAVEL_BARRIERJUMP] = TFL_BARRIERJUMP;
- aasworld.travelflagfortype[TRAVEL_JUMP] = TFL_JUMP;
- aasworld.travelflagfortype[TRAVEL_LADDER] = TFL_LADDER;
- aasworld.travelflagfortype[TRAVEL_WALKOFFLEDGE] = TFL_WALKOFFLEDGE;
- aasworld.travelflagfortype[TRAVEL_SWIM] = TFL_SWIM;
- aasworld.travelflagfortype[TRAVEL_WATERJUMP] = TFL_WATERJUMP;
- aasworld.travelflagfortype[TRAVEL_TELEPORT] = TFL_TELEPORT;
- aasworld.travelflagfortype[TRAVEL_ELEVATOR] = TFL_ELEVATOR;
- aasworld.travelflagfortype[TRAVEL_ROCKETJUMP] = TFL_ROCKETJUMP;
- aasworld.travelflagfortype[TRAVEL_BFGJUMP] = TFL_BFGJUMP;
- aasworld.travelflagfortype[TRAVEL_GRAPPLEHOOK] = TFL_GRAPPLEHOOK;
- aasworld.travelflagfortype[TRAVEL_DOUBLEJUMP] = TFL_DOUBLEJUMP;
- aasworld.travelflagfortype[TRAVEL_RAMPJUMP] = TFL_RAMPJUMP;
- aasworld.travelflagfortype[TRAVEL_STRAFEJUMP] = TFL_STRAFEJUMP;
- aasworld.travelflagfortype[TRAVEL_JUMPPAD] = TFL_JUMPPAD;
- aasworld.travelflagfortype[TRAVEL_FUNCBOB] = TFL_FUNCBOB;
-} //end of the function AAS_InitTravelFlagFromType
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-ID_INLINE int AAS_TravelFlagForType_inline(int traveltype)
-{
- int tfl;
-
- tfl = 0;
- if (tfl & TRAVELFLAG_NOTTEAM1)
- tfl |= TFL_NOTTEAM1;
- if (tfl & TRAVELFLAG_NOTTEAM2)
- tfl |= TFL_NOTTEAM2;
- traveltype &= TRAVELTYPE_MASK;
- if (traveltype < 0 || traveltype >= MAX_TRAVELTYPES)
- return TFL_INVALID;
- tfl |= aasworld.travelflagfortype[traveltype];
- return tfl;
-} //end of the function AAS_TravelFlagForType_inline
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_TravelFlagForType(int traveltype)
-{
- return AAS_TravelFlagForType_inline(traveltype);
-} //end of the function AAS_TravelFlagForType_inline
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_UnlinkCache(aas_routingcache_t *cache)
-{
- if (cache->time_next) cache->time_next->time_prev = cache->time_prev;
- else aasworld.newestcache = cache->time_prev;
- if (cache->time_prev) cache->time_prev->time_next = cache->time_next;
- else aasworld.oldestcache = cache->time_next;
- cache->time_next = NULL;
- cache->time_prev = NULL;
-} //end of the function AAS_UnlinkCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_LinkCache(aas_routingcache_t *cache)
-{
- if (aasworld.newestcache)
- {
- aasworld.newestcache->time_next = cache;
- cache->time_prev = aasworld.newestcache;
- } //end if
- else
- {
- aasworld.oldestcache = cache;
- cache->time_prev = NULL;
- } //end else
- cache->time_next = NULL;
- aasworld.newestcache = cache;
-} //end of the function AAS_LinkCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FreeRoutingCache(aas_routingcache_t *cache)
-{
- AAS_UnlinkCache(cache);
- routingcachesize -= cache->size;
- FreeMemory(cache);
-} //end of the function AAS_FreeRoutingCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_RemoveRoutingCacheInCluster( int clusternum )
-{
- int i;
- aas_routingcache_t *cache, *nextcache;
- aas_cluster_t *cluster;
-
- if (!aasworld.clusterareacache)
- return;
- cluster = &aasworld.clusters[clusternum];
- for (i = 0; i < cluster->numareas; i++)
- {
- for (cache = aasworld.clusterareacache[clusternum][i]; cache; cache = nextcache)
- {
- nextcache = cache->next;
- AAS_FreeRoutingCache(cache);
- } //end for
- aasworld.clusterareacache[clusternum][i] = NULL;
- } //end for
-} //end of the function AAS_RemoveRoutingCacheInCluster
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_RemoveRoutingCacheUsingArea( int areanum )
-{
- int i, clusternum;
- aas_routingcache_t *cache, *nextcache;
-
- clusternum = aasworld.areasettings[areanum].cluster;
- if (clusternum > 0)
- {
- //remove all the cache in the cluster the area is in
- AAS_RemoveRoutingCacheInCluster( clusternum );
- } //end if
- else
- {
- // if this is a portal remove all cache in both the front and back cluster
- AAS_RemoveRoutingCacheInCluster( aasworld.portals[-clusternum].frontcluster );
- AAS_RemoveRoutingCacheInCluster( aasworld.portals[-clusternum].backcluster );
- } //end else
- // remove all portal cache
- for (i = 0; i < aasworld.numareas; i++)
- {
- //refresh portal cache
- for (cache = aasworld.portalcache[i]; cache; cache = nextcache)
- {
- nextcache = cache->next;
- AAS_FreeRoutingCache(cache);
- } //end for
- aasworld.portalcache[i] = NULL;
- } //end for
-} //end of the function AAS_RemoveRoutingCacheUsingArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_EnableRoutingArea(int areanum, int enable)
-{
- int flags;
-
- if (areanum <= 0 || areanum >= aasworld.numareas)
- {
- if (botDeveloper)
- {
- botimport.Print(PRT_ERROR, "AAS_EnableRoutingArea: areanum %d out of range\n", areanum);
- } //end if
- return 0;
- } //end if
- flags = aasworld.areasettings[areanum].areaflags & AREA_DISABLED;
- if (enable < 0)
- return !flags;
-
- if (enable)
- aasworld.areasettings[areanum].areaflags &= ~AREA_DISABLED;
- else
- aasworld.areasettings[areanum].areaflags |= AREA_DISABLED;
- // if the status of the area changed
- if ( (flags & AREA_DISABLED) != (aasworld.areasettings[areanum].areaflags & AREA_DISABLED) )
- {
- //remove all routing cache involving this area
- AAS_RemoveRoutingCacheUsingArea( areanum );
- } //end if
- return !flags;
-} //end of the function AAS_EnableRoutingArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-ID_INLINE float AAS_RoutingTime(void)
-{
- return AAS_Time();
-} //end of the function AAS_RoutingTime
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_GetAreaContentsTravelFlags(int areanum)
-{
- int contents, tfl;
-
- contents = aasworld.areasettings[areanum].contents;
- tfl = 0;
- if (contents & AREACONTENTS_WATER)
- tfl |= TFL_WATER;
- else if (contents & AREACONTENTS_SLIME)
- tfl |= TFL_SLIME;
- else if (contents & AREACONTENTS_LAVA)
- tfl |= TFL_LAVA;
- else
- tfl |= TFL_AIR;
- if (contents & AREACONTENTS_DONOTENTER)
- tfl |= TFL_DONOTENTER;
- if (contents & AREACONTENTS_NOTTEAM1)
- tfl |= TFL_NOTTEAM1;
- if (contents & AREACONTENTS_NOTTEAM2)
- tfl |= TFL_NOTTEAM2;
- if (aasworld.areasettings[areanum].areaflags & AREA_BRIDGE)
- tfl |= TFL_BRIDGE;
- return tfl;
-} //end of the function AAS_GetAreaContentsTravelFlags
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-ID_INLINE int AAS_AreaContentsTravelFlags_inline(int areanum)
-{
- return aasworld.areacontentstravelflags[areanum];
-} //end of the function AAS_AreaContentsTravelFlags
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaContentsTravelFlags(int areanum)
-{
- return aasworld.areacontentstravelflags[areanum];
-} //end of the function AAS_AreaContentsTravelFlags
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitAreaContentsTravelFlags(void)
-{
- int i;
-
- if (aasworld.areacontentstravelflags) FreeMemory(aasworld.areacontentstravelflags);
- aasworld.areacontentstravelflags = (int *) GetClearedMemory(aasworld.numareas * sizeof(int));
- //
- for (i = 0; i < aasworld.numareas; i++) {
- aasworld.areacontentstravelflags[i] = AAS_GetAreaContentsTravelFlags(i);
- }
-} //end of the function AAS_InitAreaContentsTravelFlags
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_CreateReversedReachability(void)
-{
- int i, n;
- aas_reversedlink_t *revlink;
- aas_reachability_t *reach;
- aas_areasettings_t *settings;
- char *ptr;
-#ifdef DEBUG
- int starttime;
-
- starttime = Sys_MilliSeconds();
-#endif
- //free reversed links that have already been created
- if (aasworld.reversedreachability) FreeMemory(aasworld.reversedreachability);
- //allocate memory for the reversed reachability links
- ptr = (char *) GetClearedMemory(aasworld.numareas * sizeof(aas_reversedreachability_t) +
- aasworld.reachabilitysize * sizeof(aas_reversedlink_t));
- //
- aasworld.reversedreachability = (aas_reversedreachability_t *) ptr;
- //pointer to the memory for the reversed links
- ptr += aasworld.numareas * sizeof(aas_reversedreachability_t);
- //check all reachabilities of all areas
- for (i = 1; i < aasworld.numareas; i++)
- {
- //settings of the area
- settings = &aasworld.areasettings[i];
- //
- if (settings->numreachableareas >= 128)
- botimport.Print(PRT_WARNING, "area %d has more than 128 reachabilities\n", i);
- //create reversed links for the reachabilities
- for (n = 0; n < settings->numreachableareas && n < 128; n++)
- {
- //reachability link
- reach = &aasworld.reachability[settings->firstreachablearea + n];
- //
- revlink = (aas_reversedlink_t *) ptr;
- ptr += sizeof(aas_reversedlink_t);
- //
- revlink->areanum = i;
- revlink->linknum = settings->firstreachablearea + n;
- revlink->next = aasworld.reversedreachability[reach->areanum].first;
- aasworld.reversedreachability[reach->areanum].first = revlink;
- aasworld.reversedreachability[reach->areanum].numlinks++;
- } //end for
- } //end for
-#ifdef DEBUG
- botimport.Print(PRT_MESSAGE, "reversed reachability %d msec\n", Sys_MilliSeconds() - starttime);
-#endif
-} //end of the function AAS_CreateReversedReachability
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-unsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end)
-{
- int intdist;
- float dist;
- vec3_t dir;
-
- VectorSubtract(start, end, dir);
- dist = VectorLength(dir);
- //if crouch only area
- if (AAS_AreaCrouch(areanum)) dist *= DISTANCEFACTOR_CROUCH;
- //if swim area
- else if (AAS_AreaSwim(areanum)) dist *= DISTANCEFACTOR_SWIM;
- //normal walk area
- else dist *= DISTANCEFACTOR_WALK;
- //
- intdist = (int) dist;
- //make sure the distance isn't zero
- if (intdist <= 0) intdist = 1;
- return intdist;
-} //end of the function AAS_AreaTravelTime
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_CalculateAreaTravelTimes(void)
-{
- int i, l, n, size;
- char *ptr;
- vec3_t end;
- aas_reversedreachability_t *revreach;
- aas_reversedlink_t *revlink;
- aas_reachability_t *reach;
- aas_areasettings_t *settings;
- int starttime;
-
- starttime = Sys_MilliSeconds();
- //if there are still area travel times, free the memory
- if (aasworld.areatraveltimes) FreeMemory(aasworld.areatraveltimes);
- //get the total size of all the area travel times
- size = aasworld.numareas * sizeof(unsigned short **);
- for (i = 0; i < aasworld.numareas; i++)
- {
- revreach = &aasworld.reversedreachability[i];
- //settings of the area
- settings = &aasworld.areasettings[i];
- //
- size += settings->numreachableareas * sizeof(unsigned short *);
- //
- size += settings->numreachableareas *
- PAD(revreach->numlinks, sizeof(long)) * sizeof(unsigned short);
- } //end for
- //allocate memory for the area travel times
- ptr = (char *) GetClearedMemory(size);
- aasworld.areatraveltimes = (unsigned short ***) ptr;
- ptr += aasworld.numareas * sizeof(unsigned short **);
- //calcluate the travel times for all the areas
- for (i = 0; i < aasworld.numareas; i++)
- {
- //reversed reachabilities of this area
- revreach = &aasworld.reversedreachability[i];
- //settings of the area
- settings = &aasworld.areasettings[i];
- //
- aasworld.areatraveltimes[i] = (unsigned short **) ptr;
- ptr += settings->numreachableareas * sizeof(unsigned short *);
- //
- for (l = 0; l < settings->numreachableareas; l++)
- {
- aasworld.areatraveltimes[i][l] = (unsigned short *) ptr;
- ptr += PAD(revreach->numlinks, sizeof(long)) * sizeof(unsigned short);
- //reachability link
- reach = &aasworld.reachability[settings->firstreachablearea + l];
- //
- for (n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++)
- {
- VectorCopy(aasworld.reachability[revlink->linknum].end, end);
- //
- aasworld.areatraveltimes[i][l][n] = AAS_AreaTravelTime(i, end, reach->start);
- } //end for
- } //end for
- } //end for
-#ifdef DEBUG
- botimport.Print(PRT_MESSAGE, "area travel times %d msec\n", Sys_MilliSeconds() - starttime);
-#endif
-} //end of the function AAS_CalculateAreaTravelTimes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_PortalMaxTravelTime(int portalnum)
-{
- int l, n, t, maxt;
- aas_portal_t *portal;
- aas_reversedreachability_t *revreach;
- aas_reversedlink_t *revlink;
- aas_areasettings_t *settings;
-
- portal = &aasworld.portals[portalnum];
- //reversed reachabilities of this portal area
- revreach = &aasworld.reversedreachability[portal->areanum];
- //settings of the portal area
- settings = &aasworld.areasettings[portal->areanum];
- //
- maxt = 0;
- for (l = 0; l < settings->numreachableareas; l++)
- {
- for (n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++)
- {
- t = aasworld.areatraveltimes[portal->areanum][l][n];
- if (t > maxt)
- {
- maxt = t;
- } //end if
- } //end for
- } //end for
- return maxt;
-} //end of the function AAS_PortalMaxTravelTime
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitPortalMaxTravelTimes(void)
-{
- int i;
-
- if (aasworld.portalmaxtraveltimes) FreeMemory(aasworld.portalmaxtraveltimes);
-
- aasworld.portalmaxtraveltimes = (int *) GetClearedMemory(aasworld.numportals * sizeof(int));
-
- for (i = 0; i < aasworld.numportals; i++)
- {
- aasworld.portalmaxtraveltimes[i] = AAS_PortalMaxTravelTime(i);
- //botimport.Print(PRT_MESSAGE, "portal %d max tt = %d\n", i, aasworld.portalmaxtraveltimes[i]);
- } //end for
-} //end of the function AAS_InitPortalMaxTravelTimes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-/*
-int AAS_FreeOldestCache(void)
-{
- int i, j, bestcluster, bestarea, freed;
- float besttime;
- aas_routingcache_t *cache, *bestcache;
-
- freed = qfalse;
- besttime = 999999999;
- bestcache = NULL;
- bestcluster = 0;
- bestarea = 0;
- //refresh cluster cache
- for (i = 0; i < aasworld.numclusters; i++)
- {
- for (j = 0; j < aasworld.clusters[i].numareas; j++)
- {
- for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next)
- {
- //never remove cache leading towards a portal
- if (aasworld.areasettings[cache->areanum].cluster < 0) continue;
- //if this cache is older than the cache we found so far
- if (cache->time < besttime)
- {
- bestcache = cache;
- bestcluster = i;
- bestarea = j;
- besttime = cache->time;
- } //end if
- } //end for
- } //end for
- } //end for
- if (bestcache)
- {
- cache = bestcache;
- if (cache->prev) cache->prev->next = cache->next;
- else aasworld.clusterareacache[bestcluster][bestarea] = cache->next;
- if (cache->next) cache->next->prev = cache->prev;
- AAS_FreeRoutingCache(cache);
- freed = qtrue;
- } //end if
- besttime = 999999999;
- bestcache = NULL;
- bestarea = 0;
- for (i = 0; i < aasworld.numareas; i++)
- {
- //refresh portal cache
- for (cache = aasworld.portalcache[i]; cache; cache = cache->next)
- {
- if (cache->time < besttime)
- {
- bestcache = cache;
- bestarea = i;
- besttime = cache->time;
- } //end if
- } //end for
- } //end for
- if (bestcache)
- {
- cache = bestcache;
- if (cache->prev) cache->prev->next = cache->next;
- else aasworld.portalcache[bestarea] = cache->next;
- if (cache->next) cache->next->prev = cache->prev;
- AAS_FreeRoutingCache(cache);
- freed = qtrue;
- } //end if
- return freed;
-} //end of the function AAS_FreeOldestCache
-*/
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_FreeOldestCache(void)
-{
- int clusterareanum;
- aas_routingcache_t *cache;
-
- for (cache = aasworld.oldestcache; cache; cache = cache->time_next) {
- // never free area cache leading towards a portal
- if (cache->type == CACHETYPE_AREA && aasworld.areasettings[cache->areanum].cluster < 0) {
- continue;
- }
- break;
- }
- if (cache) {
- // unlink the cache
- if (cache->type == CACHETYPE_AREA) {
- //number of the area in the cluster
- clusterareanum = AAS_ClusterAreaNum(cache->cluster, cache->areanum);
- // unlink from cluster area cache
- if (cache->prev) cache->prev->next = cache->next;
- else aasworld.clusterareacache[cache->cluster][clusterareanum] = cache->next;
- if (cache->next) cache->next->prev = cache->prev;
- }
- else {
- // unlink from portal cache
- if (cache->prev) cache->prev->next = cache->next;
- else aasworld.portalcache[cache->areanum] = cache->next;
- if (cache->next) cache->next->prev = cache->prev;
- }
- AAS_FreeRoutingCache(cache);
- return qtrue;
- }
- return qfalse;
-} //end of the function AAS_FreeOldestCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-aas_routingcache_t *AAS_AllocRoutingCache(int numtraveltimes)
-{
- aas_routingcache_t *cache;
- int size;
-
- //
- size = sizeof(aas_routingcache_t)
- + numtraveltimes * sizeof(unsigned short int)
- + numtraveltimes * sizeof(unsigned char);
- //
- routingcachesize += size;
- //
- cache = (aas_routingcache_t *) GetClearedMemory(size);
- cache->reachabilities = (unsigned char *) cache + sizeof(aas_routingcache_t)
- + numtraveltimes * sizeof(unsigned short int);
- cache->size = size;
- return cache;
-} //end of the function AAS_AllocRoutingCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FreeAllClusterAreaCache(void)
-{
- int i, j;
- aas_routingcache_t *cache, *nextcache;
- aas_cluster_t *cluster;
-
- //free all cluster cache if existing
- if (!aasworld.clusterareacache) return;
- //free caches
- for (i = 0; i < aasworld.numclusters; i++)
- {
- cluster = &aasworld.clusters[i];
- for (j = 0; j < cluster->numareas; j++)
- {
- for (cache = aasworld.clusterareacache[i][j]; cache; cache = nextcache)
- {
- nextcache = cache->next;
- AAS_FreeRoutingCache(cache);
- } //end for
- aasworld.clusterareacache[i][j] = NULL;
- } //end for
- } //end for
- //free the cluster cache array
- FreeMemory(aasworld.clusterareacache);
- aasworld.clusterareacache = NULL;
-} //end of the function AAS_FreeAllClusterAreaCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitClusterAreaCache(void)
-{
- int i, size;
- char *ptr;
-
- //
- for (size = 0, i = 0; i < aasworld.numclusters; i++)
- {
- size += aasworld.clusters[i].numareas;
- } //end for
- //two dimensional array with pointers for every cluster to routing cache
- //for every area in that cluster
- ptr = (char *) GetClearedMemory(
- aasworld.numclusters * sizeof(aas_routingcache_t **) +
- size * sizeof(aas_routingcache_t *));
- aasworld.clusterareacache = (aas_routingcache_t ***) ptr;
- ptr += aasworld.numclusters * sizeof(aas_routingcache_t **);
- for (i = 0; i < aasworld.numclusters; i++)
- {
- aasworld.clusterareacache[i] = (aas_routingcache_t **) ptr;
- ptr += aasworld.clusters[i].numareas * sizeof(aas_routingcache_t *);
- } //end for
-} //end of the function AAS_InitClusterAreaCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FreeAllPortalCache(void)
-{
- int i;
- aas_routingcache_t *cache, *nextcache;
-
- //free all portal cache if existing
- if (!aasworld.portalcache) return;
- //free portal caches
- for (i = 0; i < aasworld.numareas; i++)
- {
- for (cache = aasworld.portalcache[i]; cache; cache = nextcache)
- {
- nextcache = cache->next;
- AAS_FreeRoutingCache(cache);
- } //end for
- aasworld.portalcache[i] = NULL;
- } //end for
- FreeMemory(aasworld.portalcache);
- aasworld.portalcache = NULL;
-} //end of the function AAS_FreeAllPortalCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitPortalCache(void)
-{
- //
- aasworld.portalcache = (aas_routingcache_t **) GetClearedMemory(
- aasworld.numareas * sizeof(aas_routingcache_t *));
-} //end of the function AAS_InitPortalCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitRoutingUpdate(void)
-{
- int i, maxreachabilityareas;
-
- //free routing update fields if already existing
- if (aasworld.areaupdate) FreeMemory(aasworld.areaupdate);
- //
- maxreachabilityareas = 0;
- for (i = 0; i < aasworld.numclusters; i++)
- {
- if (aasworld.clusters[i].numreachabilityareas > maxreachabilityareas)
- {
- maxreachabilityareas = aasworld.clusters[i].numreachabilityareas;
- } //end if
- } //end for
- //allocate memory for the routing update fields
- aasworld.areaupdate = (aas_routingupdate_t *) GetClearedMemory(
- maxreachabilityareas * sizeof(aas_routingupdate_t));
- //
- if (aasworld.portalupdate) FreeMemory(aasworld.portalupdate);
- //allocate memory for the portal update fields
- aasworld.portalupdate = (aas_routingupdate_t *) GetClearedMemory(
- (aasworld.numportals+1) * sizeof(aas_routingupdate_t));
-} //end of the function AAS_InitRoutingUpdate
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_CreateAllRoutingCache(void)
-{
- int i, j, t;
-
- aasworld.initialized = qtrue;
- botimport.Print(PRT_MESSAGE, "AAS_CreateAllRoutingCache\n");
- for (i = 1; i < aasworld.numareas; i++)
- {
- if (!AAS_AreaReachability(i)) continue;
- for (j = 1; j < aasworld.numareas; j++)
- {
- if (i == j) continue;
- if (!AAS_AreaReachability(j)) continue;
- t = AAS_AreaTravelTimeToGoalArea(i, aasworld.areas[i].center, j, TFL_DEFAULT);
- //Log_Write("traveltime from %d to %d is %d", i, j, t);
- } //end for
- } //end for
- aasworld.initialized = qfalse;
-} //end of the function AAS_CreateAllRoutingCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-
-//the route cache header
-//this header is followed by numportalcache + numareacache aas_routingcache_t
-//structures that store routing cache
-typedef struct routecacheheader_s
-{
- int ident;
- int version;
- int numareas;
- int numclusters;
- int areacrc;
- int clustercrc;
- int numportalcache;
- int numareacache;
-} routecacheheader_t;
-
-#define RCID (('C'<<24)+('R'<<16)+('E'<<8)+'M')
-#define RCVERSION 2
-
-//void AAS_DecompressVis(byte *in, int numareas, byte *decompressed);
-//int AAS_CompressVis(byte *vis, int numareas, byte *dest);
-
-void AAS_WriteRouteCache(void)
-{
- int i, j, numportalcache, numareacache, totalsize;
- aas_routingcache_t *cache;
- aas_cluster_t *cluster;
- fileHandle_t fp;
- char filename[MAX_QPATH];
- routecacheheader_t routecacheheader;
-
- numportalcache = 0;
- for (i = 0; i < aasworld.numareas; i++)
- {
- for (cache = aasworld.portalcache[i]; cache; cache = cache->next)
- {
- numportalcache++;
- } //end for
- } //end for
- numareacache = 0;
- for (i = 0; i < aasworld.numclusters; i++)
- {
- cluster = &aasworld.clusters[i];
- for (j = 0; j < cluster->numareas; j++)
- {
- for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next)
- {
- numareacache++;
- } //end for
- } //end for
- } //end for
- // open the file for writing
- Com_sprintf(filename, MAX_QPATH, "maps/%s.rcd", aasworld.mapname);
- botimport.FS_FOpenFile( filename, &fp, FS_WRITE );
- if (!fp)
- {
- AAS_Error("Unable to open file: %s\n", filename);
- return;
- } //end if
- //create the header
- routecacheheader.ident = RCID;
- routecacheheader.version = RCVERSION;
- routecacheheader.numareas = aasworld.numareas;
- routecacheheader.numclusters = aasworld.numclusters;
- routecacheheader.areacrc = CRC_ProcessString( (unsigned char *)aasworld.areas, sizeof(aas_area_t) * aasworld.numareas );
- routecacheheader.clustercrc = CRC_ProcessString( (unsigned char *)aasworld.clusters, sizeof(aas_cluster_t) * aasworld.numclusters );
- routecacheheader.numportalcache = numportalcache;
- routecacheheader.numareacache = numareacache;
- //write the header
- botimport.FS_Write(&routecacheheader, sizeof(routecacheheader_t), fp);
- //
- totalsize = 0;
- //write all the cache
- for (i = 0; i < aasworld.numareas; i++)
- {
- for (cache = aasworld.portalcache[i]; cache; cache = cache->next)
- {
- botimport.FS_Write(cache, cache->size, fp);
- totalsize += cache->size;
- } //end for
- } //end for
- for (i = 0; i < aasworld.numclusters; i++)
- {
- cluster = &aasworld.clusters[i];
- for (j = 0; j < cluster->numareas; j++)
- {
- for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next)
- {
- botimport.FS_Write(cache, cache->size, fp);
- totalsize += cache->size;
- } //end for
- } //end for
- } //end for
- // write the visareas
- /*
- for (i = 0; i < aasworld.numareas; i++)
- {
- if (!aasworld.areavisibility[i]) {
- size = 0;
- botimport.FS_Write(&size, sizeof(int), fp);
- continue;
- }
- AAS_DecompressVis( aasworld.areavisibility[i], aasworld.numareas, aasworld.decompressedvis );
- size = AAS_CompressVis( aasworld.decompressedvis, aasworld.numareas, aasworld.decompressedvis );
- botimport.FS_Write(&size, sizeof(int), fp);
- botimport.FS_Write(aasworld.decompressedvis, size, fp);
- }
- */
- //
- botimport.FS_FCloseFile(fp);
- botimport.Print(PRT_MESSAGE, "\nroute cache written to %s\n", filename);
- botimport.Print(PRT_MESSAGE, "written %d bytes of routing cache\n", totalsize);
-} //end of the function AAS_WriteRouteCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-aas_routingcache_t *AAS_ReadCache(fileHandle_t fp)
-{
- int size;
- aas_routingcache_t *cache;
-
- botimport.FS_Read(&size, sizeof(size), fp);
- cache = (aas_routingcache_t *) GetMemory(size);
- cache->size = size;
- botimport.FS_Read((unsigned char *)cache + sizeof(size), size - sizeof(size), fp);
- cache->reachabilities = (unsigned char *) cache + sizeof(aas_routingcache_t) - sizeof(unsigned short) +
- (size - sizeof(aas_routingcache_t) + sizeof(unsigned short)) / 3 * 2;
- return cache;
-} //end of the function AAS_ReadCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_ReadRouteCache(void)
-{
- int i, clusterareanum;//, size;
- fileHandle_t fp;
- char filename[MAX_QPATH];
- routecacheheader_t routecacheheader;
- aas_routingcache_t *cache;
-
- Com_sprintf(filename, MAX_QPATH, "maps/%s.rcd", aasworld.mapname);
- botimport.FS_FOpenFile( filename, &fp, FS_READ );
- if (!fp)
- {
- return qfalse;
- } //end if
- botimport.FS_Read(&routecacheheader, sizeof(routecacheheader_t), fp );
- if (routecacheheader.ident != RCID)
- {
- AAS_Error("%s is not a route cache dump\n");
- return qfalse;
- } //end if
- if (routecacheheader.version != RCVERSION)
- {
- AAS_Error("route cache dump has wrong version %d, should be %d", routecacheheader.version, RCVERSION);
- return qfalse;
- } //end if
- if (routecacheheader.numareas != aasworld.numareas)
- {
- //AAS_Error("route cache dump has wrong number of areas\n");
- return qfalse;
- } //end if
- if (routecacheheader.numclusters != aasworld.numclusters)
- {
- //AAS_Error("route cache dump has wrong number of clusters\n");
- return qfalse;
- } //end if
- if (routecacheheader.areacrc !=
- CRC_ProcessString( (unsigned char *)aasworld.areas, sizeof(aas_area_t) * aasworld.numareas ))
- {
- //AAS_Error("route cache dump area CRC incorrect\n");
- return qfalse;
- } //end if
- if (routecacheheader.clustercrc !=
- CRC_ProcessString( (unsigned char *)aasworld.clusters, sizeof(aas_cluster_t) * aasworld.numclusters ))
- {
- //AAS_Error("route cache dump cluster CRC incorrect\n");
- return qfalse;
- } //end if
- //read all the portal cache
- for (i = 0; i < routecacheheader.numportalcache; i++)
- {
- cache = AAS_ReadCache(fp);
- cache->next = aasworld.portalcache[cache->areanum];
- cache->prev = NULL;
- if (aasworld.portalcache[cache->areanum])
- aasworld.portalcache[cache->areanum]->prev = cache;
- aasworld.portalcache[cache->areanum] = cache;
- } //end for
- //read all the cluster area cache
- for (i = 0; i < routecacheheader.numareacache; i++)
- {
- cache = AAS_ReadCache(fp);
- clusterareanum = AAS_ClusterAreaNum(cache->cluster, cache->areanum);
- cache->next = aasworld.clusterareacache[cache->cluster][clusterareanum];
- cache->prev = NULL;
- if (aasworld.clusterareacache[cache->cluster][clusterareanum])
- aasworld.clusterareacache[cache->cluster][clusterareanum]->prev = cache;
- aasworld.clusterareacache[cache->cluster][clusterareanum] = cache;
- } //end for
- // read the visareas
- /*
- aasworld.areavisibility = (byte **) GetClearedMemory(aasworld.numareas * sizeof(byte *));
- aasworld.decompressedvis = (byte *) GetClearedMemory(aasworld.numareas * sizeof(byte));
- for (i = 0; i < aasworld.numareas; i++)
- {
- botimport.FS_Read(&size, sizeof(size), fp );
- if (size) {
- aasworld.areavisibility[i] = (byte *) GetMemory(size);
- botimport.FS_Read(aasworld.areavisibility[i], size, fp );
- }
- }
- */
- //
- botimport.FS_FCloseFile(fp);
- return qtrue;
-} //end of the function AAS_ReadRouteCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#define MAX_REACHABILITYPASSAREAS 32
-
-void AAS_InitReachabilityAreas(void)
-{
- int i, j, numareas, areas[MAX_REACHABILITYPASSAREAS];
- int numreachareas;
- aas_reachability_t *reach;
- vec3_t start, end;
-
- if (aasworld.reachabilityareas)
- FreeMemory(aasworld.reachabilityareas);
- if (aasworld.reachabilityareaindex)
- FreeMemory(aasworld.reachabilityareaindex);
-
- aasworld.reachabilityareas = (aas_reachabilityareas_t *)
- GetClearedMemory(aasworld.reachabilitysize * sizeof(aas_reachabilityareas_t));
- aasworld.reachabilityareaindex = (int *)
- GetClearedMemory(aasworld.reachabilitysize * MAX_REACHABILITYPASSAREAS * sizeof(int));
- numreachareas = 0;
- for (i = 0; i < aasworld.reachabilitysize; i++)
- {
- reach = &aasworld.reachability[i];
- numareas = 0;
- switch(reach->traveltype & TRAVELTYPE_MASK)
- {
- //trace areas from start to end
- case TRAVEL_BARRIERJUMP:
- case TRAVEL_WATERJUMP:
- VectorCopy(reach->start, end);
- end[2] = reach->end[2];
- numareas = AAS_TraceAreas(reach->start, end, areas, NULL, MAX_REACHABILITYPASSAREAS);
- break;
- case TRAVEL_WALKOFFLEDGE:
- VectorCopy(reach->end, start);
- start[2] = reach->start[2];
- numareas = AAS_TraceAreas(start, reach->end, areas, NULL, MAX_REACHABILITYPASSAREAS);
- break;
- case TRAVEL_GRAPPLEHOOK:
- numareas = AAS_TraceAreas(reach->start, reach->end, areas, NULL, MAX_REACHABILITYPASSAREAS);
- break;
-
- //trace arch
- case TRAVEL_JUMP: break;
- case TRAVEL_ROCKETJUMP: break;
- case TRAVEL_BFGJUMP: break;
- case TRAVEL_JUMPPAD: break;
-
- //trace from reach->start to entity center, along entity movement
- //and from entity center to reach->end
- case TRAVEL_ELEVATOR: break;
- case TRAVEL_FUNCBOB: break;
-
- //no areas in between
- case TRAVEL_WALK: break;
- case TRAVEL_CROUCH: break;
- case TRAVEL_LADDER: break;
- case TRAVEL_SWIM: break;
- case TRAVEL_TELEPORT: break;
- default: break;
- } //end switch
- aasworld.reachabilityareas[i].firstarea = numreachareas;
- aasworld.reachabilityareas[i].numareas = numareas;
- for (j = 0; j < numareas; j++)
- {
- aasworld.reachabilityareaindex[numreachareas++] = areas[j];
- } //end for
- } //end for
-} //end of the function AAS_InitReachabilityAreas
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitRouting(void)
-{
- AAS_InitTravelFlagFromType();
- //
- AAS_InitAreaContentsTravelFlags();
- //initialize the routing update fields
- AAS_InitRoutingUpdate();
- //create reversed reachability links used by the routing update algorithm
- AAS_CreateReversedReachability();
- //initialize the cluster cache
- AAS_InitClusterAreaCache();
- //initialize portal cache
- AAS_InitPortalCache();
- //initialize the area travel times
- AAS_CalculateAreaTravelTimes();
- //calculate the maximum travel times through portals
- AAS_InitPortalMaxTravelTimes();
- //get the areas reachabilities go through
- AAS_InitReachabilityAreas();
- //
-#ifdef ROUTING_DEBUG
- numareacacheupdates = 0;
- numportalcacheupdates = 0;
-#endif //ROUTING_DEBUG
- //
- routingcachesize = 0;
- max_routingcachesize = 1024 * (int) LibVarValue("max_routingcache", "4096");
- // read any routing cache if available
- AAS_ReadRouteCache();
-} //end of the function AAS_InitRouting
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FreeRoutingCaches(void)
-{
- // free all the existing cluster area cache
- AAS_FreeAllClusterAreaCache();
- // free all the existing portal cache
- AAS_FreeAllPortalCache();
- // free cached travel times within areas
- if (aasworld.areatraveltimes) FreeMemory(aasworld.areatraveltimes);
- aasworld.areatraveltimes = NULL;
- // free cached maximum travel time through cluster portals
- if (aasworld.portalmaxtraveltimes) FreeMemory(aasworld.portalmaxtraveltimes);
- aasworld.portalmaxtraveltimes = NULL;
- // free reversed reachability links
- if (aasworld.reversedreachability) FreeMemory(aasworld.reversedreachability);
- aasworld.reversedreachability = NULL;
- // free routing algorithm memory
- if (aasworld.areaupdate) FreeMemory(aasworld.areaupdate);
- aasworld.areaupdate = NULL;
- if (aasworld.portalupdate) FreeMemory(aasworld.portalupdate);
- aasworld.portalupdate = NULL;
- // free lists with areas the reachabilities go through
- if (aasworld.reachabilityareas) FreeMemory(aasworld.reachabilityareas);
- aasworld.reachabilityareas = NULL;
- // free the reachability area index
- if (aasworld.reachabilityareaindex) FreeMemory(aasworld.reachabilityareaindex);
- aasworld.reachabilityareaindex = NULL;
- // free area contents travel flags look up table
- if (aasworld.areacontentstravelflags) FreeMemory(aasworld.areacontentstravelflags);
- aasworld.areacontentstravelflags = NULL;
-} //end of the function AAS_FreeRoutingCaches
-//===========================================================================
-// update the given routing cache
-//
-// Parameter: areacache : routing cache to update
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_UpdateAreaRoutingCache(aas_routingcache_t *areacache)
-{
- int i, nextareanum, cluster, badtravelflags, clusterareanum, linknum;
- int numreachabilityareas;
- unsigned short int t, startareatraveltimes[128]; //NOTE: not more than 128 reachabilities per area allowed
- aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;
- aas_reachability_t *reach;
- aas_reversedreachability_t *revreach;
- aas_reversedlink_t *revlink;
-
-#ifdef ROUTING_DEBUG
- numareacacheupdates++;
-#endif //ROUTING_DEBUG
- //number of reachability areas within this cluster
- numreachabilityareas = aasworld.clusters[areacache->cluster].numreachabilityareas;
- //
- aasworld.frameroutingupdates++;
- //clear the routing update fields
-// Com_Memset(aasworld.areaupdate, 0, aasworld.numareas * sizeof(aas_routingupdate_t));
- //
- badtravelflags = ~areacache->travelflags;
- //
- clusterareanum = AAS_ClusterAreaNum(areacache->cluster, areacache->areanum);
- if (clusterareanum >= numreachabilityareas) return;
- //
- Com_Memset(startareatraveltimes, 0, sizeof(startareatraveltimes));
- //
- curupdate = &aasworld.areaupdate[clusterareanum];
- curupdate->areanum = areacache->areanum;
- //VectorCopy(areacache->origin, curupdate->start);
- curupdate->areatraveltimes = startareatraveltimes;
- curupdate->tmptraveltime = areacache->starttraveltime;
- //
- areacache->traveltimes[clusterareanum] = areacache->starttraveltime;
- //put the area to start with in the current read list
- curupdate->next = NULL;
- curupdate->prev = NULL;
- updateliststart = curupdate;
- updatelistend = curupdate;
- //while there are updates in the current list
- while (updateliststart)
- {
- curupdate = updateliststart;
- //
- if (curupdate->next) curupdate->next->prev = NULL;
- else updatelistend = NULL;
- updateliststart = curupdate->next;
- //
- curupdate->inlist = qfalse;
- //check all reversed reachability links
- revreach = &aasworld.reversedreachability[curupdate->areanum];
- //
- for (i = 0, revlink = revreach->first; revlink; revlink = revlink->next, i++)
- {
- linknum = revlink->linknum;
- reach = &aasworld.reachability[linknum];
- //if there is used an undesired travel type
- if (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue;
- //if not allowed to enter the next area
- if (aasworld.areasettings[reach->areanum].areaflags & AREA_DISABLED) continue;
- //if the next area has a not allowed travel flag
- if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue;
- //number of the area the reversed reachability leads to
- nextareanum = revlink->areanum;
- //get the cluster number of the area
- cluster = aasworld.areasettings[nextareanum].cluster;
- //don't leave the cluster
- if (cluster > 0 && cluster != areacache->cluster) continue;
- //get the number of the area in the cluster
- clusterareanum = AAS_ClusterAreaNum(areacache->cluster, nextareanum);
- if (clusterareanum >= numreachabilityareas) continue;
- //time already travelled plus the traveltime through
- //the current area plus the travel time from the reachability
- t = curupdate->tmptraveltime +
- //AAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->end) +
- curupdate->areatraveltimes[i] +
- reach->traveltime;
- //
- if (!areacache->traveltimes[clusterareanum] ||
- areacache->traveltimes[clusterareanum] > t)
- {
- areacache->traveltimes[clusterareanum] = t;
- areacache->reachabilities[clusterareanum] = linknum - aasworld.areasettings[nextareanum].firstreachablearea;
- nextupdate = &aasworld.areaupdate[clusterareanum];
- nextupdate->areanum = nextareanum;
- nextupdate->tmptraveltime = t;
- //VectorCopy(reach->start, nextupdate->start);
- nextupdate->areatraveltimes = aasworld.areatraveltimes[nextareanum][linknum -
- aasworld.areasettings[nextareanum].firstreachablearea];
- if (!nextupdate->inlist)
- {
- // we add the update to the end of the list
- // we could also use a B+ tree to have a real sorted list
- // on travel time which makes for faster routing updates
- nextupdate->next = NULL;
- nextupdate->prev = updatelistend;
- if (updatelistend) updatelistend->next = nextupdate;
- else updateliststart = nextupdate;
- updatelistend = nextupdate;
- nextupdate->inlist = qtrue;
- } //end if
- } //end if
- } //end for
- } //end while
-} //end of the function AAS_UpdateAreaRoutingCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-aas_routingcache_t *AAS_GetAreaRoutingCache(int clusternum, int areanum, int travelflags)
-{
- int clusterareanum;
- aas_routingcache_t *cache, *clustercache;
-
- //number of the area in the cluster
- clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
- //pointer to the cache for the area in the cluster
- clustercache = aasworld.clusterareacache[clusternum][clusterareanum];
- //find the cache without undesired travel flags
- for (cache = clustercache; cache; cache = cache->next)
- {
- //if there aren't used any undesired travel types for the cache
- if (cache->travelflags == travelflags) break;
- } //end for
- //if there was no cache
- if (!cache)
- {
- cache = AAS_AllocRoutingCache(aasworld.clusters[clusternum].numreachabilityareas);
- cache->cluster = clusternum;
- cache->areanum = areanum;
- VectorCopy(aasworld.areas[areanum].center, cache->origin);
- cache->starttraveltime = 1;
- cache->travelflags = travelflags;
- cache->prev = NULL;
- cache->next = clustercache;
- if (clustercache) clustercache->prev = cache;
- aasworld.clusterareacache[clusternum][clusterareanum] = cache;
- AAS_UpdateAreaRoutingCache(cache);
- } //end if
- else
- {
- AAS_UnlinkCache(cache);
- } //end else
- //the cache has been accessed
- cache->time = AAS_RoutingTime();
- cache->type = CACHETYPE_AREA;
- AAS_LinkCache(cache);
- return cache;
-} //end of the function AAS_GetAreaRoutingCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_UpdatePortalRoutingCache(aas_routingcache_t *portalcache)
-{
- int i, portalnum, clusterareanum, clusternum;
- unsigned short int t;
- aas_portal_t *portal;
- aas_cluster_t *cluster;
- aas_routingcache_t *cache;
- aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;
-
-#ifdef ROUTING_DEBUG
- numportalcacheupdates++;
-#endif //ROUTING_DEBUG
- //clear the routing update fields
-// Com_Memset(aasworld.portalupdate, 0, (aasworld.numportals+1) * sizeof(aas_routingupdate_t));
- //
- curupdate = &aasworld.portalupdate[aasworld.numportals];
- curupdate->cluster = portalcache->cluster;
- curupdate->areanum = portalcache->areanum;
- curupdate->tmptraveltime = portalcache->starttraveltime;
- //if the start area is a cluster portal, store the travel time for that portal
- clusternum = aasworld.areasettings[portalcache->areanum].cluster;
- if (clusternum < 0)
- {
- portalcache->traveltimes[-clusternum] = portalcache->starttraveltime;
- } //end if
- //put the area to start with in the current read list
- curupdate->next = NULL;
- curupdate->prev = NULL;
- updateliststart = curupdate;
- updatelistend = curupdate;
- //while there are updates in the current list
- while (updateliststart)
- {
- curupdate = updateliststart;
- //remove the current update from the list
- if (curupdate->next) curupdate->next->prev = NULL;
- else updatelistend = NULL;
- updateliststart = curupdate->next;
- //current update is removed from the list
- curupdate->inlist = qfalse;
- //
- cluster = &aasworld.clusters[curupdate->cluster];
- //
- cache = AAS_GetAreaRoutingCache(curupdate->cluster,
- curupdate->areanum, portalcache->travelflags);
- //take all portals of the cluster
- for (i = 0; i < cluster->numportals; i++)
- {
- portalnum = aasworld.portalindex[cluster->firstportal + i];
- portal = &aasworld.portals[portalnum];
- //if this is the portal of the current update continue
- if (portal->areanum == curupdate->areanum) continue;
- //
- clusterareanum = AAS_ClusterAreaNum(curupdate->cluster, portal->areanum);
- if (clusterareanum >= cluster->numreachabilityareas) continue;
- //
- t = cache->traveltimes[clusterareanum];
- if (!t) continue;
- t += curupdate->tmptraveltime;
- //
- if (!portalcache->traveltimes[portalnum] ||
- portalcache->traveltimes[portalnum] > t)
- {
- portalcache->traveltimes[portalnum] = t;
- nextupdate = &aasworld.portalupdate[portalnum];
- if (portal->frontcluster == curupdate->cluster)
- {
- nextupdate->cluster = portal->backcluster;
- } //end if
- else
- {
- nextupdate->cluster = portal->frontcluster;
- } //end else
- nextupdate->areanum = portal->areanum;
- //add travel time through the actual portal area for the next update
- nextupdate->tmptraveltime = t + aasworld.portalmaxtraveltimes[portalnum];
- if (!nextupdate->inlist)
- {
- // we add the update to the end of the list
- // we could also use a B+ tree to have a real sorted list
- // on travel time which makes for faster routing updates
- nextupdate->next = NULL;
- nextupdate->prev = updatelistend;
- if (updatelistend) updatelistend->next = nextupdate;
- else updateliststart = nextupdate;
- updatelistend = nextupdate;
- nextupdate->inlist = qtrue;
- } //end if
- } //end if
- } //end for
- } //end while
-} //end of the function AAS_UpdatePortalRoutingCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-aas_routingcache_t *AAS_GetPortalRoutingCache(int clusternum, int areanum, int travelflags)
-{
- aas_routingcache_t *cache;
-
- //find the cached portal routing if existing
- for (cache = aasworld.portalcache[areanum]; cache; cache = cache->next)
- {
- if (cache->travelflags == travelflags) break;
- } //end for
- //if the portal routing isn't cached
- if (!cache)
- {
- cache = AAS_AllocRoutingCache(aasworld.numportals);
- cache->cluster = clusternum;
- cache->areanum = areanum;
- VectorCopy(aasworld.areas[areanum].center, cache->origin);
- cache->starttraveltime = 1;
- cache->travelflags = travelflags;
- //add the cache to the cache list
- cache->prev = NULL;
- cache->next = aasworld.portalcache[areanum];
- if (aasworld.portalcache[areanum]) aasworld.portalcache[areanum]->prev = cache;
- aasworld.portalcache[areanum] = cache;
- //update the cache
- AAS_UpdatePortalRoutingCache(cache);
- } //end if
- else
- {
- AAS_UnlinkCache(cache);
- } //end else
- //the cache has been accessed
- cache->time = AAS_RoutingTime();
- cache->type = CACHETYPE_PORTAL;
- AAS_LinkCache(cache);
- return cache;
-} //end of the function AAS_GetPortalRoutingCache
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaRouteToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags, int *traveltime, int *reachnum)
-{
- int clusternum, goalclusternum, portalnum, i, clusterareanum, bestreachnum;
- unsigned short int t, besttime;
- aas_portal_t *portal;
- aas_cluster_t *cluster;
- aas_routingcache_t *areacache, *portalcache;
- aas_reachability_t *reach;
-
- if (!aasworld.initialized) return qfalse;
-
- if (areanum == goalareanum)
- {
- *traveltime = 1;
- *reachnum = 0;
- return qtrue;
- }
- //
- if (areanum <= 0 || areanum >= aasworld.numareas)
- {
- if (botDeveloper)
- {
- botimport.Print(PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: areanum %d out of range\n", areanum);
- } //end if
- return qfalse;
- } //end if
- if (goalareanum <= 0 || goalareanum >= aasworld.numareas)
- {
- if (botDeveloper)
- {
- botimport.Print(PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: goalareanum %d out of range\n", goalareanum);
- } //end if
- return qfalse;
- } //end if
- // make sure the routing cache doesn't grow to large
- while(AvailableMemory() < 1 * 1024 * 1024) {
- if (!AAS_FreeOldestCache()) break;
- }
- //
- if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goalareanum))
- {
- travelflags |= TFL_DONOTENTER;
- } //end if
- //NOTE: the number of routing updates is limited per frame
- /*
- if (aasworld.frameroutingupdates > MAX_FRAMEROUTINGUPDATES)
- {
-#ifdef DEBUG
- //Log_Write("WARNING: AAS_AreaTravelTimeToGoalArea: frame routing updates overflowed");
-#endif
- return 0;
- } //end if
- */
- //
- clusternum = aasworld.areasettings[areanum].cluster;
- goalclusternum = aasworld.areasettings[goalareanum].cluster;
- //check if the area is a portal of the goal area cluster
- if (clusternum < 0 && goalclusternum > 0)
- {
- portal = &aasworld.portals[-clusternum];
- if (portal->frontcluster == goalclusternum ||
- portal->backcluster == goalclusternum)
- {
- clusternum = goalclusternum;
- } //end if
- } //end if
- //check if the goalarea is a portal of the area cluster
- else if (clusternum > 0 && goalclusternum < 0)
- {
- portal = &aasworld.portals[-goalclusternum];
- if (portal->frontcluster == clusternum ||
- portal->backcluster == clusternum)
- {
- goalclusternum = clusternum;
- } //end if
- } //end if
- //if both areas are in the same cluster
- //NOTE: there might be a shorter route via another cluster!!! but we don't care
- if (clusternum > 0 && goalclusternum > 0 && clusternum == goalclusternum)
- {
- //
- areacache = AAS_GetAreaRoutingCache(clusternum, goalareanum, travelflags);
- //the number of the area in the cluster
- clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
- //the cluster the area is in
- cluster = &aasworld.clusters[clusternum];
- //if the area is NOT a reachability area
- if (clusterareanum >= cluster->numreachabilityareas) return 0;
- //if it is possible to travel to the goal area through this cluster
- if (areacache->traveltimes[clusterareanum] != 0)
- {
- *reachnum = aasworld.areasettings[areanum].firstreachablearea +
- areacache->reachabilities[clusterareanum];
- if (!origin) {
- *traveltime = areacache->traveltimes[clusterareanum];
- return qtrue;
- }
- reach = &aasworld.reachability[*reachnum];
- *traveltime = areacache->traveltimes[clusterareanum] +
- AAS_AreaTravelTime(areanum, origin, reach->start);
- //
- return qtrue;
- } //end if
- } //end if
- //
- clusternum = aasworld.areasettings[areanum].cluster;
- goalclusternum = aasworld.areasettings[goalareanum].cluster;
- //if the goal area is a portal
- if (goalclusternum < 0)
- {
- //just assume the goal area is part of the front cluster
- portal = &aasworld.portals[-goalclusternum];
- goalclusternum = portal->frontcluster;
- } //end if
- //get the portal routing cache
- portalcache = AAS_GetPortalRoutingCache(goalclusternum, goalareanum, travelflags);
- //if the area is a cluster portal, read directly from the portal cache
- if (clusternum < 0)
- {
- *traveltime = portalcache->traveltimes[-clusternum];
- *reachnum = aasworld.areasettings[areanum].firstreachablearea +
- portalcache->reachabilities[-clusternum];
- return qtrue;
- } //end if
- //
- besttime = 0;
- bestreachnum = -1;
- //the cluster the area is in
- cluster = &aasworld.clusters[clusternum];
- //find the portal of the area cluster leading towards the goal area
- for (i = 0; i < cluster->numportals; i++)
- {
- portalnum = aasworld.portalindex[cluster->firstportal + i];
- //if the goal area isn't reachable from the portal
- if (!portalcache->traveltimes[portalnum]) continue;
- //
- portal = &aasworld.portals[portalnum];
- //get the cache of the portal area
- areacache = AAS_GetAreaRoutingCache(clusternum, portal->areanum, travelflags);
- //current area inside the current cluster
- clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
- //if the area is NOT a reachability area
- if (clusterareanum >= cluster->numreachabilityareas) continue;
- //if the portal is NOT reachable from this area
- if (!areacache->traveltimes[clusterareanum]) continue;
- //total travel time is the travel time the portal area is from
- //the goal area plus the travel time towards the portal area
- t = portalcache->traveltimes[portalnum] + areacache->traveltimes[clusterareanum];
- //FIXME: add the exact travel time through the actual portal area
- //NOTE: for now we just add the largest travel time through the portal area
- // because we can't directly calculate the exact travel time
- // to be more specific we don't know which reachability was used to travel
- // into the portal area
- t += aasworld.portalmaxtraveltimes[portalnum];
- //
- if (origin)
- {
- *reachnum = aasworld.areasettings[areanum].firstreachablearea +
- areacache->reachabilities[clusterareanum];
- reach = aasworld.reachability + *reachnum;
- t += AAS_AreaTravelTime(areanum, origin, reach->start);
- } //end if
- //if the time is better than the one already found
- if (!besttime || t < besttime)
- {
- bestreachnum = *reachnum;
- besttime = t;
- } //end if
- } //end for
- if (bestreachnum < 0) {
- return qfalse;
- }
- *reachnum = bestreachnum;
- *traveltime = besttime;
- return qtrue;
-} //end of the function AAS_AreaRouteToGoalArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags)
-{
- int traveltime, reachnum;
-
- if (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum))
- {
- return traveltime;
- }
- return 0;
-} //end of the function AAS_AreaTravelTimeToGoalArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaReachabilityToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags)
-{
- int traveltime, reachnum;
-
- if (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum))
- {
- return reachnum;
- }
- return 0;
-} //end of the function AAS_AreaReachabilityToGoalArea
-//===========================================================================
-// predict the route and stop on one of the stop events
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_PredictRoute(struct aas_predictroute_s *route, int areanum, vec3_t origin,
- int goalareanum, int travelflags, int maxareas, int maxtime,
- int stopevent, int stopcontents, int stoptfl, int stopareanum)
-{
- int curareanum, reachnum, i, j, testareanum;
- vec3_t curorigin;
- aas_reachability_t *reach;
- aas_reachabilityareas_t *reachareas;
-
- //init output
- route->stopevent = RSE_NONE;
- route->endarea = goalareanum;
- route->endcontents = 0;
- route->endtravelflags = 0;
- VectorCopy(origin, route->endpos);
- route->time = 0;
-
- curareanum = areanum;
- VectorCopy(origin, curorigin);
-
- for (i = 0; curareanum != goalareanum && (!maxareas || i < maxareas) && i < aasworld.numareas; i++)
- {
- reachnum = AAS_AreaReachabilityToGoalArea(curareanum, curorigin, goalareanum, travelflags);
- if (!reachnum)
- {
- route->stopevent = RSE_NOROUTE;
- return qfalse;
- } //end if
- reach = &aasworld.reachability[reachnum];
- //
- if (stopevent & RSE_USETRAVELTYPE)
- {
- if (AAS_TravelFlagForType_inline(reach->traveltype) & stoptfl)
- {
- route->stopevent = RSE_USETRAVELTYPE;
- route->endarea = curareanum;
- route->endcontents = aasworld.areasettings[curareanum].contents;
- route->endtravelflags = AAS_TravelFlagForType_inline(reach->traveltype);
- VectorCopy(reach->start, route->endpos);
- return qtrue;
- } //end if
- if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & stoptfl)
- {
- route->stopevent = RSE_USETRAVELTYPE;
- route->endarea = reach->areanum;
- route->endcontents = aasworld.areasettings[reach->areanum].contents;
- route->endtravelflags = AAS_AreaContentsTravelFlags_inline(reach->areanum);
- VectorCopy(reach->end, route->endpos);
- route->time += AAS_AreaTravelTime(areanum, origin, reach->start);
- route->time += reach->traveltime;
- return qtrue;
- } //end if
- } //end if
- reachareas = &aasworld.reachabilityareas[reachnum];
- for (j = 0; j < reachareas->numareas + 1; j++)
- {
- if (j >= reachareas->numareas)
- testareanum = reach->areanum;
- else
- testareanum = aasworld.reachabilityareaindex[reachareas->firstarea + j];
- if (stopevent & RSE_ENTERCONTENTS)
- {
- if (aasworld.areasettings[testareanum].contents & stopcontents)
- {
- route->stopevent = RSE_ENTERCONTENTS;
- route->endarea = testareanum;
- route->endcontents = aasworld.areasettings[testareanum].contents;
- VectorCopy(reach->end, route->endpos);
- route->time += AAS_AreaTravelTime(areanum, origin, reach->start);
- route->time += reach->traveltime;
- return qtrue;
- } //end if
- } //end if
- if (stopevent & RSE_ENTERAREA)
- {
- if (testareanum == stopareanum)
- {
- route->stopevent = RSE_ENTERAREA;
- route->endarea = testareanum;
- route->endcontents = aasworld.areasettings[testareanum].contents;
- VectorCopy(reach->start, route->endpos);
- return qtrue;
- } //end if
- } //end if
- } //end for
-
- route->time += AAS_AreaTravelTime(areanum, origin, reach->start);
- route->time += reach->traveltime;
- route->endarea = reach->areanum;
- route->endcontents = aasworld.areasettings[reach->areanum].contents;
- route->endtravelflags = AAS_TravelFlagForType_inline(reach->traveltype);
- VectorCopy(reach->end, route->endpos);
- //
- curareanum = reach->areanum;
- VectorCopy(reach->end, curorigin);
- //
- if (maxtime && route->time > maxtime)
- break;
- } //end while
- if (curareanum != goalareanum)
- return qfalse;
- return qtrue;
-} //end of the function AAS_PredictRoute
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_BridgeWalkable(int areanum)
-{
- return qfalse;
-} //end of the function AAS_BridgeWalkable
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ReachabilityFromNum(int num, struct aas_reachability_s *reach)
-{
- if (!aasworld.initialized)
- {
- Com_Memset(reach, 0, sizeof(aas_reachability_t));
- return;
- } //end if
- if (num < 0 || num >= aasworld.reachabilitysize)
- {
- Com_Memset(reach, 0, sizeof(aas_reachability_t));
- return;
- } //end if
- Com_Memcpy(reach, &aasworld.reachability[num], sizeof(aas_reachability_t));;
-} //end of the function AAS_ReachabilityFromNum
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_NextAreaReachability(int areanum, int reachnum)
-{
- aas_areasettings_t *settings;
-
- if (!aasworld.initialized) return 0;
-
- if (areanum <= 0 || areanum >= aasworld.numareas)
- {
- botimport.Print(PRT_ERROR, "AAS_NextAreaReachability: areanum %d out of range\n", areanum);
- return 0;
- } //end if
-
- settings = &aasworld.areasettings[areanum];
- if (!reachnum)
- {
- return settings->firstreachablearea;
- } //end if
- if (reachnum < settings->firstreachablearea)
- {
- botimport.Print(PRT_FATAL, "AAS_NextAreaReachability: reachnum < settings->firstreachableara");
- return 0;
- } //end if
- reachnum++;
- if (reachnum >= settings->firstreachablearea + settings->numreachableareas)
- {
- return 0;
- } //end if
- return reachnum;
-} //end of the function AAS_NextAreaReachability
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_NextModelReachability(int num, int modelnum)
-{
- int i;
-
- if (num <= 0) num = 1;
- else if (num >= aasworld.reachabilitysize) return 0;
- else num++;
- //
- for (i = num; i < aasworld.reachabilitysize; i++)
- {
- if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR)
- {
- if (aasworld.reachability[i].facenum == modelnum) return i;
- } //end if
- else if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB)
- {
- if ((aasworld.reachability[i].facenum & 0x0000FFFF) == modelnum) return i;
- } //end if
- } //end for
- return 0;
-} //end of the function AAS_NextModelReachability
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_RandomGoalArea(int areanum, int travelflags, int *goalareanum, vec3_t goalorigin)
-{
- int i, n, t;
- vec3_t start, end;
- aas_trace_t trace;
-
- //if the area has no reachabilities
- if (!AAS_AreaReachability(areanum)) return qfalse;
- //
- n = aasworld.numareas * random();
- for (i = 0; i < aasworld.numareas; i++)
- {
- if (n <= 0) n = 1;
- if (n >= aasworld.numareas) n = 1;
- if (AAS_AreaReachability(n))
- {
- t = AAS_AreaTravelTimeToGoalArea(areanum, aasworld.areas[areanum].center, n, travelflags);
- //if the goal is reachable
- if (t > 0)
- {
- if (AAS_AreaSwim(n))
- {
- *goalareanum = n;
- VectorCopy(aasworld.areas[n].center, goalorigin);
- //botimport.Print(PRT_MESSAGE, "found random goal area %d\n", *goalareanum);
- return qtrue;
- } //end if
- VectorCopy(aasworld.areas[n].center, start);
- if (!AAS_PointAreaNum(start))
- Log_Write("area %d center %f %f %f in solid?", n, start[0], start[1], start[2]);
- VectorCopy(start, end);
- end[2] -= 300;
- trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);
- if (!trace.startsolid && trace.fraction < 1 && AAS_PointAreaNum(trace.endpos) == n)
- {
- if (AAS_AreaGroundFaceArea(n) > 300)
- {
- *goalareanum = n;
- VectorCopy(trace.endpos, goalorigin);
- //botimport.Print(PRT_MESSAGE, "found random goal area %d\n", *goalareanum);
- return qtrue;
- } //end if
- } //end if
- } //end if
- } //end if
- n++;
- } //end for
- return qfalse;
-} //end of the function AAS_RandomGoalArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaVisible(int srcarea, int destarea)
-{
- return qfalse;
-} //end of the function AAS_AreaVisible
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float DistancePointToLine(vec3_t v1, vec3_t v2, vec3_t point)
-{
- vec3_t vec, p2;
-
- AAS_ProjectPointOntoVector(point, v1, v2, p2);
- VectorSubtract(point, p2, vec);
- return VectorLength(vec);
-} //end of the function DistancePointToLine
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_NearestHideArea(int srcnum, vec3_t origin, int areanum, int enemynum, vec3_t enemyorigin, int enemyareanum, int travelflags)
-{
- int i, j, nextareanum, badtravelflags, numreach, bestarea;
- unsigned short int t, besttraveltime;
- static unsigned short int *hidetraveltimes;
- aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;
- aas_reachability_t *reach;
- float dist1, dist2;
- vec3_t v1, v2, p;
- qboolean startVisible;
-
- //
- if (!hidetraveltimes)
- {
- hidetraveltimes = (unsigned short int *) GetClearedMemory(aasworld.numareas * sizeof(unsigned short int));
- } //end if
- else
- {
- Com_Memset(hidetraveltimes, 0, aasworld.numareas * sizeof(unsigned short int));
- } //end else
- besttraveltime = 0;
- bestarea = 0;
- //assume visible
- startVisible = qtrue;
- //
- badtravelflags = ~travelflags;
- //
- curupdate = &aasworld.areaupdate[areanum];
- curupdate->areanum = areanum;
- VectorCopy(origin, curupdate->start);
- curupdate->areatraveltimes = aasworld.areatraveltimes[areanum][0];
- curupdate->tmptraveltime = 0;
- //put the area to start with in the current read list
- curupdate->next = NULL;
- curupdate->prev = NULL;
- updateliststart = curupdate;
- updatelistend = curupdate;
- //while there are updates in the list
- while (updateliststart)
- {
- curupdate = updateliststart;
- //
- if (curupdate->next) curupdate->next->prev = NULL;
- else updatelistend = NULL;
- updateliststart = curupdate->next;
- //
- curupdate->inlist = qfalse;
- //check all reversed reachability links
- numreach = aasworld.areasettings[curupdate->areanum].numreachableareas;
- reach = &aasworld.reachability[aasworld.areasettings[curupdate->areanum].firstreachablearea];
- //
- for (i = 0; i < numreach; i++, reach++)
- {
- //if an undesired travel type is used
- if (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue;
- //
- if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue;
- //number of the area the reachability leads to
- nextareanum = reach->areanum;
- // if this moves us into the enemies area, skip it
- if (nextareanum == enemyareanum) continue;
- //time already travelled plus the traveltime through
- //the current area plus the travel time from the reachability
- t = curupdate->tmptraveltime +
- AAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->start) +
- reach->traveltime;
-
- //avoid going near the enemy
- AAS_ProjectPointOntoVector(enemyorigin, curupdate->start, reach->end, p);
- for (j = 0; j < 3; j++)
- if ((p[j] > curupdate->start[j] && p[j] > reach->end[j]) ||
- (p[j] < curupdate->start[j] && p[j] < reach->end[j]))
- break;
- if (j < 3)
- {
- VectorSubtract(enemyorigin, reach->end, v2);
- } //end if
- else
- {
- VectorSubtract(enemyorigin, p, v2);
- } //end else
- dist2 = VectorLength(v2);
- //never go through the enemy
- if (dist2 < 40) continue;
- //
- VectorSubtract(enemyorigin, curupdate->start, v1);
- dist1 = VectorLength(v1);
- //
- if (dist2 < dist1)
- {
- t += (dist1 - dist2) * 10;
- }
- // if we weren't visible when starting, make sure we don't move into their view
- if (!startVisible && AAS_AreaVisible(enemyareanum, nextareanum)) {
- continue;
- }
- //
- if (besttraveltime && t >= besttraveltime) continue;
- //
- if (!hidetraveltimes[nextareanum] ||
- hidetraveltimes[nextareanum] > t)
- {
- //if the nextarea is not visible from the enemy area
- if (!AAS_AreaVisible(enemyareanum, nextareanum))
- {
- besttraveltime = t;
- bestarea = nextareanum;
- } //end if
- hidetraveltimes[nextareanum] = t;
- nextupdate = &aasworld.areaupdate[nextareanum];
- nextupdate->areanum = nextareanum;
- nextupdate->tmptraveltime = t;
- //remember where we entered this area
- VectorCopy(reach->end, nextupdate->start);
- //if this update is not in the list yet
- if (!nextupdate->inlist)
- {
- //add the new update to the end of the list
- nextupdate->next = NULL;
- nextupdate->prev = updatelistend;
- if (updatelistend) updatelistend->next = nextupdate;
- else updateliststart = nextupdate;
- updatelistend = nextupdate;
- nextupdate->inlist = qtrue;
- } //end if
- } //end if
- } //end for
- } //end while
- return bestarea;
-} //end of the function AAS_NearestHideArea
diff --git a/engine/code/botlib/be_aas_routealt.c b/engine/code/botlib/be_aas_routealt.c
deleted file mode 100644
index e4f79ee..0000000
--- a/engine/code/botlib/be_aas_routealt.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_routealt.c
- *
- * desc: AAS
- *
- * $Archive: /MissionPack/code/botlib/be_aas_routealt.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_utils.h"
-#include "l_memory.h"
-#include "l_log.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-#include "be_aas_def.h"
-
-#define ENABLE_ALTROUTING
-//#define ALTROUTE_DEBUG
-
-typedef struct midrangearea_s
-{
- int valid;
- unsigned short starttime;
- unsigned short goaltime;
-} midrangearea_t;
-
-midrangearea_t *midrangeareas;
-int *clusterareas;
-int numclusterareas;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_AltRoutingFloodCluster_r(int areanum)
-{
- int i, otherareanum;
- aas_area_t *area;
- aas_face_t *face;
-
- //add the current area to the areas of the current cluster
- clusterareas[numclusterareas] = areanum;
- numclusterareas++;
- //remove the area from the mid range areas
- midrangeareas[areanum].valid = qfalse;
- //flood to other areas through the faces of this area
- area = &aasworld.areas[areanum];
- for (i = 0; i < area->numfaces; i++)
- {
- face = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])];
- //get the area at the other side of the face
- if (face->frontarea == areanum) otherareanum = face->backarea;
- else otherareanum = face->frontarea;
- //if there is an area at the other side of this face
- if (!otherareanum) continue;
- //if the other area is not a midrange area
- if (!midrangeareas[otherareanum].valid) continue;
- //
- AAS_AltRoutingFloodCluster_r(otherareanum);
- } //end for
-} //end of the function AAS_AltRoutingFloodCluster_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,
- aas_altroutegoal_t *altroutegoals, int maxaltroutegoals,
- int type)
-{
-#ifndef ENABLE_ALTROUTING
- return 0;
-#else
- int i, j, bestareanum;
- int numaltroutegoals, nummidrangeareas;
- int starttime, goaltime, goaltraveltime;
- float dist, bestdist;
- vec3_t mid, dir;
-#ifdef ALTROUTE_DEBUG
- int startmillisecs;
-
- startmillisecs = Sys_MilliSeconds();
-#endif
-
- if (!startareanum || !goalareanum)
- return 0;
- //travel time towards the goal area
- goaltraveltime = AAS_AreaTravelTimeToGoalArea(startareanum, start, goalareanum, travelflags);
- //clear the midrange areas
- Com_Memset(midrangeareas, 0, aasworld.numareas * sizeof(midrangearea_t));
- numaltroutegoals = 0;
- //
- nummidrangeareas = 0;
- //
- for (i = 1; i < aasworld.numareas; i++)
- {
- //
- if (!(type & ALTROUTEGOAL_ALL))
- {
- if (!(type & ALTROUTEGOAL_CLUSTERPORTALS && (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)))
- {
- if (!(type & ALTROUTEGOAL_VIEWPORTALS && (aasworld.areasettings[i].contents & AREACONTENTS_VIEWPORTAL)))
- {
- continue;
- } //end if
- } //end if
- } //end if
- //if the area has no reachabilities
- if (!AAS_AreaReachability(i)) continue;
- //tavel time from the area to the start area
- starttime = AAS_AreaTravelTimeToGoalArea(startareanum, start, i, travelflags);
- if (!starttime) continue;
- //if the travel time from the start to the area is greater than the shortest goal travel time
- if (starttime > (float) 1.1 * goaltraveltime) continue;
- //travel time from the area to the goal area
- goaltime = AAS_AreaTravelTimeToGoalArea(i, NULL, goalareanum, travelflags);
- if (!goaltime) continue;
- //if the travel time from the area to the goal is greater than the shortest goal travel time
- if (goaltime > (float) 0.8 * goaltraveltime) continue;
- //this is a mid range area
- midrangeareas[i].valid = qtrue;
- midrangeareas[i].starttime = starttime;
- midrangeareas[i].goaltime = goaltime;
- Log_Write("%d midrange area %d", nummidrangeareas, i);
- nummidrangeareas++;
- } //end for
- //
- for (i = 1; i < aasworld.numareas; i++)
- {
- if (!midrangeareas[i].valid) continue;
- //get the areas in one cluster
- numclusterareas = 0;
- AAS_AltRoutingFloodCluster_r(i);
- //now we've got a cluster with areas through which an alternative route could go
- //get the 'center' of the cluster
- VectorClear(mid);
- for (j = 0; j < numclusterareas; j++)
- {
- VectorAdd(mid, aasworld.areas[clusterareas[j]].center, mid);
- } //end for
- VectorScale(mid, 1.0 / numclusterareas, mid);
- //get the area closest to the center of the cluster
- bestdist = 999999;
- bestareanum = 0;
- for (j = 0; j < numclusterareas; j++)
- {
- VectorSubtract(mid, aasworld.areas[clusterareas[j]].center, dir);
- dist = VectorLength(dir);
- if (dist < bestdist)
- {
- bestdist = dist;
- bestareanum = clusterareas[j];
- } //end if
- } //end for
- //now we've got an area for an alternative route
- //FIXME: add alternative goal origin
- VectorCopy(aasworld.areas[bestareanum].center, altroutegoals[numaltroutegoals].origin);
- altroutegoals[numaltroutegoals].areanum = bestareanum;
- altroutegoals[numaltroutegoals].starttraveltime = midrangeareas[bestareanum].starttime;
- altroutegoals[numaltroutegoals].goaltraveltime = midrangeareas[bestareanum].goaltime;
- altroutegoals[numaltroutegoals].extratraveltime =
- (midrangeareas[bestareanum].starttime + midrangeareas[bestareanum].goaltime) -
- goaltraveltime;
- numaltroutegoals++;
- //
-#ifdef ALTROUTE_DEBUG
- AAS_ShowAreaPolygons(bestareanum, 1, qtrue);
-#endif
- //don't return more than the maximum alternative route goals
- if (numaltroutegoals >= maxaltroutegoals) break;
- } //end for
-#ifdef ALTROUTE_DEBUG
- botimport.Print(PRT_MESSAGE, "alternative route goals in %d msec\n", Sys_MilliSeconds() - startmillisecs);
-#endif
- return numaltroutegoals;
-#endif
-} //end of the function AAS_AlternativeRouteGoals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitAlternativeRouting(void)
-{
-#ifdef ENABLE_ALTROUTING
- if (midrangeareas) FreeMemory(midrangeareas);
- midrangeareas = (midrangearea_t *) GetMemory(aasworld.numareas * sizeof(midrangearea_t));
- if (clusterareas) FreeMemory(clusterareas);
- clusterareas = (int *) GetMemory(aasworld.numareas * sizeof(int));
-#endif
-} //end of the function AAS_InitAlternativeRouting
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_ShutdownAlternativeRouting(void)
-{
-#ifdef ENABLE_ALTROUTING
- if (midrangeareas) FreeMemory(midrangeareas);
- midrangeareas = NULL;
- if (clusterareas) FreeMemory(clusterareas);
- clusterareas = NULL;
- numclusterareas = 0;
-#endif
-} //end of the function AAS_ShutdownAlternativeRouting
diff --git a/engine/code/botlib/be_aas_sample.c b/engine/code/botlib/be_aas_sample.c
deleted file mode 100644
index 095641a..0000000
--- a/engine/code/botlib/be_aas_sample.c
+++ /dev/null
@@ -1,1393 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_sample.c
- *
- * desc: AAS environment sampling
- *
- * $Archive: /MissionPack/code/botlib/be_aas_sample.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#ifndef BSPC
-#include "l_libvar.h"
-#endif
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_interface.h"
-#include "be_aas_funcs.h"
-#include "be_aas_def.h"
-
-
-//#define AAS_SAMPLE_DEBUG
-
-#define BBOX_NORMAL_EPSILON 0.001
-
-#define ON_EPSILON 0 //0.0005
-
-#define TRACEPLANE_EPSILON 0.125
-
-typedef struct aas_tracestack_s
-{
- vec3_t start; //start point of the piece of line to trace
- vec3_t end; //end point of the piece of line to trace
- int planenum; //last plane used as splitter
- int nodenum; //node found after splitting with planenum
-} aas_tracestack_t;
-
-int numaaslinks;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs)
-{
- int index;
- //bounding box size for each presence type
- vec3_t boxmins[3] = {{0, 0, 0}, {-15, -15, -24}, {-15, -15, -24}};
- vec3_t boxmaxs[3] = {{0, 0, 0}, { 15, 15, 32}, { 15, 15, 8}};
-
- if (presencetype == PRESENCE_NORMAL) index = 1;
- else if (presencetype == PRESENCE_CROUCH) index = 2;
- else
- {
- botimport.Print(PRT_FATAL, "AAS_PresenceTypeBoundingBox: unknown presence type\n");
- index = 2;
- } //end if
- VectorCopy(boxmins[index], mins);
- VectorCopy(boxmaxs[index], maxs);
-} //end of the function AAS_PresenceTypeBoundingBox
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitAASLinkHeap(void)
-{
- int i, max_aaslinks;
-
- max_aaslinks = aasworld.linkheapsize;
- //if there's no link heap present
- if (!aasworld.linkheap)
- {
-#ifdef BSPC
- max_aaslinks = 6144;
-#else
- max_aaslinks = (int) LibVarValue("max_aaslinks", "6144");
-#endif
- if (max_aaslinks < 0) max_aaslinks = 0;
- aasworld.linkheapsize = max_aaslinks;
- aasworld.linkheap = (aas_link_t *) GetHunkMemory(max_aaslinks * sizeof(aas_link_t));
- } //end if
- //link the links on the heap
- aasworld.linkheap[0].prev_ent = NULL;
- aasworld.linkheap[0].next_ent = &aasworld.linkheap[1];
- for (i = 1; i < max_aaslinks-1; i++)
- {
- aasworld.linkheap[i].prev_ent = &aasworld.linkheap[i - 1];
- aasworld.linkheap[i].next_ent = &aasworld.linkheap[i + 1];
- } //end for
- aasworld.linkheap[max_aaslinks-1].prev_ent = &aasworld.linkheap[max_aaslinks-2];
- aasworld.linkheap[max_aaslinks-1].next_ent = NULL;
- //pointer to the first free link
- aasworld.freelinks = &aasworld.linkheap[0];
- //
- numaaslinks = max_aaslinks;
-} //end of the function AAS_InitAASLinkHeap
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FreeAASLinkHeap(void)
-{
- if (aasworld.linkheap) FreeMemory(aasworld.linkheap);
- aasworld.linkheap = NULL;
- aasworld.linkheapsize = 0;
-} //end of the function AAS_FreeAASLinkHeap
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-aas_link_t *AAS_AllocAASLink(void)
-{
- aas_link_t *link;
-
- link = aasworld.freelinks;
- if (!link)
- {
-#ifndef BSPC
- if (botDeveloper)
-#endif
- {
- botimport.Print(PRT_FATAL, "empty aas link heap\n");
- } //end if
- return NULL;
- } //end if
- if (aasworld.freelinks) aasworld.freelinks = aasworld.freelinks->next_ent;
- if (aasworld.freelinks) aasworld.freelinks->prev_ent = NULL;
- numaaslinks--;
- return link;
-} //end of the function AAS_AllocAASLink
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_DeAllocAASLink(aas_link_t *link)
-{
- if (aasworld.freelinks) aasworld.freelinks->prev_ent = link;
- link->prev_ent = NULL;
- link->next_ent = aasworld.freelinks;
- link->prev_area = NULL;
- link->next_area = NULL;
- aasworld.freelinks = link;
- numaaslinks++;
-} //end of the function AAS_DeAllocAASLink
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_InitAASLinkedEntities(void)
-{
- if (!aasworld.loaded) return;
- if (aasworld.arealinkedentities) FreeMemory(aasworld.arealinkedentities);
- aasworld.arealinkedentities = (aas_link_t **) GetClearedHunkMemory(
- aasworld.numareas * sizeof(aas_link_t *));
-} //end of the function AAS_InitAASLinkedEntities
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FreeAASLinkedEntities(void)
-{
- if (aasworld.arealinkedentities) FreeMemory(aasworld.arealinkedentities);
- aasworld.arealinkedentities = NULL;
-} //end of the function AAS_InitAASLinkedEntities
-//===========================================================================
-// returns the AAS area the point is in
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_PointAreaNum(vec3_t point)
-{
- int nodenum;
- vec_t dist;
- aas_node_t *node;
- aas_plane_t *plane;
-
- if (!aasworld.loaded)
- {
- botimport.Print(PRT_ERROR, "AAS_PointAreaNum: aas not loaded\n");
- return 0;
- } //end if
-
- //start with node 1 because node zero is a dummy used for solid leafs
- nodenum = 1;
- while (nodenum > 0)
- {
-// botimport.Print(PRT_MESSAGE, "[%d]", nodenum);
-#ifdef AAS_SAMPLE_DEBUG
- if (nodenum >= aasworld.numnodes)
- {
- botimport.Print(PRT_ERROR, "nodenum = %d >= aasworld.numnodes = %d\n", nodenum, aasworld.numnodes);
- return 0;
- } //end if
-#endif //AAS_SAMPLE_DEBUG
- node = &aasworld.nodes[nodenum];
-#ifdef AAS_SAMPLE_DEBUG
- if (node->planenum < 0 || node->planenum >= aasworld.numplanes)
- {
- botimport.Print(PRT_ERROR, "node->planenum = %d >= aasworld.numplanes = %d\n", node->planenum, aasworld.numplanes);
- return 0;
- } //end if
-#endif //AAS_SAMPLE_DEBUG
- plane = &aasworld.planes[node->planenum];
- dist = DotProduct(point, plane->normal) - plane->dist;
- if (dist > 0) nodenum = node->children[0];
- else nodenum = node->children[1];
- } //end while
- if (!nodenum)
- {
-#ifdef AAS_SAMPLE_DEBUG
- botimport.Print(PRT_MESSAGE, "in solid\n");
-#endif //AAS_SAMPLE_DEBUG
- return 0;
- } //end if
- return -nodenum;
-} //end of the function AAS_PointAreaNum
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_PointReachabilityAreaIndex( vec3_t origin )
-{
- int areanum, cluster, i, index;
-
- if (!aasworld.initialized)
- return 0;
-
- if ( !origin )
- {
- index = 0;
- for (i = 0; i < aasworld.numclusters; i++)
- {
- index += aasworld.clusters[i].numreachabilityareas;
- } //end for
- return index;
- } //end if
-
- areanum = AAS_PointAreaNum( origin );
- if ( !areanum || !AAS_AreaReachability(areanum) )
- return 0;
- cluster = aasworld.areasettings[areanum].cluster;
- areanum = aasworld.areasettings[areanum].clusterareanum;
- if (cluster < 0)
- {
- cluster = aasworld.portals[-cluster].frontcluster;
- areanum = aasworld.portals[-cluster].clusterareanum[0];
- } //end if
-
- index = 0;
- for (i = 0; i < cluster; i++)
- {
- index += aasworld.clusters[i].numreachabilityareas;
- } //end for
- index += areanum;
- return index;
-} //end of the function AAS_PointReachabilityAreaIndex
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaCluster(int areanum)
-{
- if (areanum <= 0 || areanum >= aasworld.numareas)
- {
- botimport.Print(PRT_ERROR, "AAS_AreaCluster: invalid area number\n");
- return 0;
- } //end if
- return aasworld.areasettings[areanum].cluster;
-} //end of the function AAS_AreaCluster
-//===========================================================================
-// returns the presence types of the given area
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaPresenceType(int areanum)
-{
- if (!aasworld.loaded) return 0;
- if (areanum <= 0 || areanum >= aasworld.numareas)
- {
- botimport.Print(PRT_ERROR, "AAS_AreaPresenceType: invalid area number\n");
- return 0;
- } //end if
- return aasworld.areasettings[areanum].presencetype;
-} //end of the function AAS_AreaPresenceType
-//===========================================================================
-// returns the presence type at the given point
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_PointPresenceType(vec3_t point)
-{
- int areanum;
-
- if (!aasworld.loaded) return 0;
-
- areanum = AAS_PointAreaNum(point);
- if (!areanum) return PRESENCE_NONE;
- return aasworld.areasettings[areanum].presencetype;
-} //end of the function AAS_PointPresenceType
-//===========================================================================
-// calculates the minimum distance between the origin of the box and the
-// given plane when both will collide on the given side of the plane
-//
-// normal = normal vector of plane to calculate distance from
-// mins = minimums of box relative to origin
-// maxs = maximums of box relative to origin
-// side = side of the plane we want to calculate the distance from
-// 0 normal vector side
-// 1 not normal vector side
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-vec_t AAS_BoxOriginDistanceFromPlane(vec3_t normal, vec3_t mins, vec3_t maxs, int side)
-{
- vec3_t v1, v2;
- int i;
-
- //swap maxs and mins when on the other side of the plane
- if (side)
- {
- //get a point of the box that would be one of the first
- //to collide with the plane
- for (i = 0; i < 3; i++)
- {
- if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = maxs[i];
- else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = mins[i];
- else v1[i] = 0;
- } //end for
- } //end if
- else
- {
- //get a point of the box that would be one of the first
- //to collide with the plane
- for (i = 0; i < 3; i++)
- {
- if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = mins[i];
- else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = maxs[i];
- else v1[i] = 0;
- } //end for
- } //end else
- //
- VectorCopy(normal, v2);
- VectorInverse(v2);
-// VectorNegate(normal, v2);
- return DotProduct(v1, v2);
-} //end of the function AAS_BoxOriginDistanceFromPlane
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_AreaEntityCollision(int areanum, vec3_t start, vec3_t end,
- int presencetype, int passent, aas_trace_t *trace)
-{
- int collision;
- vec3_t boxmins, boxmaxs;
- aas_link_t *link;
- bsp_trace_t bsptrace;
-
- AAS_PresenceTypeBoundingBox(presencetype, boxmins, boxmaxs);
-
- Com_Memset(&bsptrace, 0, sizeof(bsp_trace_t)); //make compiler happy
- //assume no collision
- bsptrace.fraction = 1;
- collision = qfalse;
- for (link = aasworld.arealinkedentities[areanum]; link; link = link->next_ent)
- {
- //ignore the pass entity
- if (link->entnum == passent) continue;
- //
- if (AAS_EntityCollision(link->entnum, start, boxmins, boxmaxs, end,
- CONTENTS_SOLID|CONTENTS_PLAYERCLIP, &bsptrace))
- {
- collision = qtrue;
- } //end if
- } //end for
- if (collision)
- {
- trace->startsolid = bsptrace.startsolid;
- trace->ent = bsptrace.ent;
- VectorCopy(bsptrace.endpos, trace->endpos);
- trace->area = 0;
- trace->planenum = 0;
- return qtrue;
- } //end if
- return qfalse;
-} //end of the function AAS_AreaEntityCollision
-//===========================================================================
-// recursive subdivision of the line by the BSP tree.
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-aas_trace_t AAS_TraceClientBBox(vec3_t start, vec3_t end, int presencetype,
- int passent)
-{
- int side, nodenum, tmpplanenum;
- float front, back, frac;
- vec3_t cur_start, cur_end, cur_mid, v1, v2;
- aas_tracestack_t tracestack[127];
- aas_tracestack_t *tstack_p;
- aas_node_t *aasnode;
- aas_plane_t *plane;
- aas_trace_t trace;
-
- //clear the trace structure
- Com_Memset(&trace, 0, sizeof(aas_trace_t));
-
- if (!aasworld.loaded) return trace;
-
- tstack_p = tracestack;
- //we start with the whole line on the stack
- VectorCopy(start, tstack_p->start);
- VectorCopy(end, tstack_p->end);
- tstack_p->planenum = 0;
- //start with node 1 because node zero is a dummy for a solid leaf
- tstack_p->nodenum = 1; //starting at the root of the tree
- tstack_p++;
-
- while (1)
- {
- //pop up the stack
- tstack_p--;
- //if the trace stack is empty (ended up with a piece of the
- //line to be traced in an area)
- if (tstack_p < tracestack)
- {
- tstack_p++;
- //nothing was hit
- trace.startsolid = qfalse;
- trace.fraction = 1.0;
- //endpos is the end of the line
- VectorCopy(end, trace.endpos);
- //nothing hit
- trace.ent = 0;
- trace.area = 0;
- trace.planenum = 0;
- return trace;
- } //end if
- //number of the current node to test the line against
- nodenum = tstack_p->nodenum;
- //if it is an area
- if (nodenum < 0)
- {
-#ifdef AAS_SAMPLE_DEBUG
- if (-nodenum > aasworld.numareasettings)
- {
- botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: -nodenum out of range\n");
- return trace;
- } //end if
-#endif //AAS_SAMPLE_DEBUG
- //botimport.Print(PRT_MESSAGE, "areanum = %d, must be %d\n", -nodenum, AAS_PointAreaNum(start));
- //if can't enter the area because it hasn't got the right presence type
- if (!(aasworld.areasettings[-nodenum].presencetype & presencetype))
- {
- //if the start point is still the initial start point
- //NOTE: no need for epsilons because the points will be
- //exactly the same when they're both the start point
- if (tstack_p->start[0] == start[0] &&
- tstack_p->start[1] == start[1] &&
- tstack_p->start[2] == start[2])
- {
- trace.startsolid = qtrue;
- trace.fraction = 0.0;
- VectorClear(v1);
- } //end if
- else
- {
- trace.startsolid = qfalse;
- VectorSubtract(end, start, v1);
- VectorSubtract(tstack_p->start, start, v2);
- trace.fraction = VectorLength(v2) / VectorNormalize(v1);
- VectorMA(tstack_p->start, -0.125, v1, tstack_p->start);
- } //end else
- VectorCopy(tstack_p->start, trace.endpos);
- trace.ent = 0;
- trace.area = -nodenum;
-// VectorSubtract(end, start, v1);
- trace.planenum = tstack_p->planenum;
- //always take the plane with normal facing towards the trace start
- plane = &aasworld.planes[trace.planenum];
- if (DotProduct(v1, plane->normal) > 0) trace.planenum ^= 1;
- return trace;
- } //end if
- else
- {
- if (passent >= 0)
- {
- if (AAS_AreaEntityCollision(-nodenum, tstack_p->start,
- tstack_p->end, presencetype, passent,
- &trace))
- {
- if (!trace.startsolid)
- {
- VectorSubtract(end, start, v1);
- VectorSubtract(trace.endpos, start, v2);
- trace.fraction = VectorLength(v2) / VectorLength(v1);
- } //end if
- return trace;
- } //end if
- } //end if
- } //end else
- trace.lastarea = -nodenum;
- continue;
- } //end if
- //if it is a solid leaf
- if (!nodenum)
- {
- //if the start point is still the initial start point
- //NOTE: no need for epsilons because the points will be
- //exactly the same when they're both the start point
- if (tstack_p->start[0] == start[0] &&
- tstack_p->start[1] == start[1] &&
- tstack_p->start[2] == start[2])
- {
- trace.startsolid = qtrue;
- trace.fraction = 0.0;
- VectorClear(v1);
- } //end if
- else
- {
- trace.startsolid = qfalse;
- VectorSubtract(end, start, v1);
- VectorSubtract(tstack_p->start, start, v2);
- trace.fraction = VectorLength(v2) / VectorNormalize(v1);
- VectorMA(tstack_p->start, -0.125, v1, tstack_p->start);
- } //end else
- VectorCopy(tstack_p->start, trace.endpos);
- trace.ent = 0;
- trace.area = 0; //hit solid leaf
-// VectorSubtract(end, start, v1);
- trace.planenum = tstack_p->planenum;
- //always take the plane with normal facing towards the trace start
- plane = &aasworld.planes[trace.planenum];
- if (DotProduct(v1, plane->normal) > 0) trace.planenum ^= 1;
- return trace;
- } //end if
-#ifdef AAS_SAMPLE_DEBUG
- if (nodenum > aasworld.numnodes)
- {
- botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: nodenum out of range\n");
- return trace;
- } //end if
-#endif //AAS_SAMPLE_DEBUG
- //the node to test against
- aasnode = &aasworld.nodes[nodenum];
- //start point of current line to test against node
- VectorCopy(tstack_p->start, cur_start);
- //end point of the current line to test against node
- VectorCopy(tstack_p->end, cur_end);
- //the current node plane
- plane = &aasworld.planes[aasnode->planenum];
-
- switch(plane->type)
- {/*FIXME: wtf doesn't this work? obviously the axial node planes aren't always facing positive!!!
- //check for axial planes
- case PLANE_X:
- {
- front = cur_start[0] - plane->dist;
- back = cur_end[0] - plane->dist;
- break;
- } //end case
- case PLANE_Y:
- {
- front = cur_start[1] - plane->dist;
- back = cur_end[1] - plane->dist;
- break;
- } //end case
- case PLANE_Z:
- {
- front = cur_start[2] - plane->dist;
- back = cur_end[2] - plane->dist;
- break;
- } //end case*/
- default: //gee it's not an axial plane
- {
- front = DotProduct(cur_start, plane->normal) - plane->dist;
- back = DotProduct(cur_end, plane->normal) - plane->dist;
- break;
- } //end default
- } //end switch
- // bk010221 - old location of FPE hack and divide by zero expression
- //if the whole to be traced line is totally at the front of this node
- //only go down the tree with the front child
- if ((front >= -ON_EPSILON && back >= -ON_EPSILON))
- {
- //keep the current start and end point on the stack
- //and go down the tree with the front child
- tstack_p->nodenum = aasnode->children[0];
- tstack_p++;
- if (tstack_p >= &tracestack[127])
- {
- botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n");
- return trace;
- } //end if
- } //end if
- //if the whole to be traced line is totally at the back of this node
- //only go down the tree with the back child
- else if ((front < ON_EPSILON && back < ON_EPSILON))
- {
- //keep the current start and end point on the stack
- //and go down the tree with the back child
- tstack_p->nodenum = aasnode->children[1];
- tstack_p++;
- if (tstack_p >= &tracestack[127])
- {
- botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n");
- return trace;
- } //end if
- } //end if
- //go down the tree both at the front and back of the node
- else
- {
- tmpplanenum = tstack_p->planenum;
- // bk010221 - new location of divide by zero (see above)
- if ( front == back ) front -= 0.001f; // bk0101022 - hack/FPE
- //calculate the hitpoint with the node (split point of the line)
- //put the crosspoint TRACEPLANE_EPSILON pixels on the near side
- if (front < 0) frac = (front + TRACEPLANE_EPSILON)/(front-back);
- else frac = (front - TRACEPLANE_EPSILON)/(front-back); // bk010221
- //
- if (frac < 0)
- frac = 0.001f; //0
- else if (frac > 1)
- frac = 0.999f; //1
- //frac = front / (front-back);
- //
- cur_mid[0] = cur_start[0] + (cur_end[0] - cur_start[0]) * frac;
- cur_mid[1] = cur_start[1] + (cur_end[1] - cur_start[1]) * frac;
- cur_mid[2] = cur_start[2] + (cur_end[2] - cur_start[2]) * frac;
-
-// AAS_DrawPlaneCross(cur_mid, plane->normal, plane->dist, plane->type, LINECOLOR_RED);
- //side the front part of the line is on
- side = front < 0;
- //first put the end part of the line on the stack (back side)
- VectorCopy(cur_mid, tstack_p->start);
- //not necesary to store because still on stack
- //VectorCopy(cur_end, tstack_p->end);
- tstack_p->planenum = aasnode->planenum;
- tstack_p->nodenum = aasnode->children[!side];
- tstack_p++;
- if (tstack_p >= &tracestack[127])
- {
- botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n");
- return trace;
- } //end if
- //now put the part near the start of the line on the stack so we will
- //continue with thats part first. This way we'll find the first
- //hit of the bbox
- VectorCopy(cur_start, tstack_p->start);
- VectorCopy(cur_mid, tstack_p->end);
- tstack_p->planenum = tmpplanenum;
- tstack_p->nodenum = aasnode->children[side];
- tstack_p++;
- if (tstack_p >= &tracestack[127])
- {
- botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n");
- return trace;
- } //end if
- } //end else
- } //end while
-// return trace;
-} //end of the function AAS_TraceClientBBox
-//===========================================================================
-// recursive subdivision of the line by the BSP tree.
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas)
-{
- int side, nodenum, tmpplanenum;
- int numareas;
- float front, back, frac;
- vec3_t cur_start, cur_end, cur_mid;
- aas_tracestack_t tracestack[127];
- aas_tracestack_t *tstack_p;
- aas_node_t *aasnode;
- aas_plane_t *plane;
-
- numareas = 0;
- areas[0] = 0;
- if (!aasworld.loaded) return numareas;
-
- tstack_p = tracestack;
- //we start with the whole line on the stack
- VectorCopy(start, tstack_p->start);
- VectorCopy(end, tstack_p->end);
- tstack_p->planenum = 0;
- //start with node 1 because node zero is a dummy for a solid leaf
- tstack_p->nodenum = 1; //starting at the root of the tree
- tstack_p++;
-
- while (1)
- {
- //pop up the stack
- tstack_p--;
- //if the trace stack is empty (ended up with a piece of the
- //line to be traced in an area)
- if (tstack_p < tracestack)
- {
- return numareas;
- } //end if
- //number of the current node to test the line against
- nodenum = tstack_p->nodenum;
- //if it is an area
- if (nodenum < 0)
- {
-#ifdef AAS_SAMPLE_DEBUG
- if (-nodenum > aasworld.numareasettings)
- {
- botimport.Print(PRT_ERROR, "AAS_TraceAreas: -nodenum = %d out of range\n", -nodenum);
- return numareas;
- } //end if
-#endif //AAS_SAMPLE_DEBUG
- //botimport.Print(PRT_MESSAGE, "areanum = %d, must be %d\n", -nodenum, AAS_PointAreaNum(start));
- areas[numareas] = -nodenum;
- if (points) VectorCopy(tstack_p->start, points[numareas]);
- numareas++;
- if (numareas >= maxareas) return numareas;
- continue;
- } //end if
- //if it is a solid leaf
- if (!nodenum)
- {
- continue;
- } //end if
-#ifdef AAS_SAMPLE_DEBUG
- if (nodenum > aasworld.numnodes)
- {
- botimport.Print(PRT_ERROR, "AAS_TraceAreas: nodenum out of range\n");
- return numareas;
- } //end if
-#endif //AAS_SAMPLE_DEBUG
- //the node to test against
- aasnode = &aasworld.nodes[nodenum];
- //start point of current line to test against node
- VectorCopy(tstack_p->start, cur_start);
- //end point of the current line to test against node
- VectorCopy(tstack_p->end, cur_end);
- //the current node plane
- plane = &aasworld.planes[aasnode->planenum];
-
- switch(plane->type)
- {/*FIXME: wtf doesn't this work? obviously the node planes aren't always facing positive!!!
- //check for axial planes
- case PLANE_X:
- {
- front = cur_start[0] - plane->dist;
- back = cur_end[0] - plane->dist;
- break;
- } //end case
- case PLANE_Y:
- {
- front = cur_start[1] - plane->dist;
- back = cur_end[1] - plane->dist;
- break;
- } //end case
- case PLANE_Z:
- {
- front = cur_start[2] - plane->dist;
- back = cur_end[2] - plane->dist;
- break;
- } //end case*/
- default: //gee it's not an axial plane
- {
- front = DotProduct(cur_start, plane->normal) - plane->dist;
- back = DotProduct(cur_end, plane->normal) - plane->dist;
- break;
- } //end default
- } //end switch
-
- //if the whole to be traced line is totally at the front of this node
- //only go down the tree with the front child
- if (front > 0 && back > 0)
- {
- //keep the current start and end point on the stack
- //and go down the tree with the front child
- tstack_p->nodenum = aasnode->children[0];
- tstack_p++;
- if (tstack_p >= &tracestack[127])
- {
- botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n");
- return numareas;
- } //end if
- } //end if
- //if the whole to be traced line is totally at the back of this node
- //only go down the tree with the back child
- else if (front <= 0 && back <= 0)
- {
- //keep the current start and end point on the stack
- //and go down the tree with the back child
- tstack_p->nodenum = aasnode->children[1];
- tstack_p++;
- if (tstack_p >= &tracestack[127])
- {
- botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n");
- return numareas;
- } //end if
- } //end if
- //go down the tree both at the front and back of the node
- else
- {
- tmpplanenum = tstack_p->planenum;
- //calculate the hitpoint with the node (split point of the line)
- //put the crosspoint TRACEPLANE_EPSILON pixels on the near side
- if (front < 0) frac = (front)/(front-back);
- else frac = (front)/(front-back);
- if (frac < 0) frac = 0;
- else if (frac > 1) frac = 1;
- //frac = front / (front-back);
- //
- cur_mid[0] = cur_start[0] + (cur_end[0] - cur_start[0]) * frac;
- cur_mid[1] = cur_start[1] + (cur_end[1] - cur_start[1]) * frac;
- cur_mid[2] = cur_start[2] + (cur_end[2] - cur_start[2]) * frac;
-
-// AAS_DrawPlaneCross(cur_mid, plane->normal, plane->dist, plane->type, LINECOLOR_RED);
- //side the front part of the line is on
- side = front < 0;
- //first put the end part of the line on the stack (back side)
- VectorCopy(cur_mid, tstack_p->start);
- //not necesary to store because still on stack
- //VectorCopy(cur_end, tstack_p->end);
- tstack_p->planenum = aasnode->planenum;
- tstack_p->nodenum = aasnode->children[!side];
- tstack_p++;
- if (tstack_p >= &tracestack[127])
- {
- botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n");
- return numareas;
- } //end if
- //now put the part near the start of the line on the stack so we will
- //continue with thats part first. This way we'll find the first
- //hit of the bbox
- VectorCopy(cur_start, tstack_p->start);
- VectorCopy(cur_mid, tstack_p->end);
- tstack_p->planenum = tmpplanenum;
- tstack_p->nodenum = aasnode->children[side];
- tstack_p++;
- if (tstack_p >= &tracestack[127])
- {
- botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n");
- return numareas;
- } //end if
- } //end else
- } //end while
-// return numareas;
-} //end of the function AAS_TraceAreas
-//===========================================================================
-// a simple cross product
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-// void AAS_OrthogonalToVectors(vec3_t v1, vec3_t v2, vec3_t res)
-#define AAS_OrthogonalToVectors(v1, v2, res) \
- (res)[0] = ((v1)[1] * (v2)[2]) - ((v1)[2] * (v2)[1]);\
- (res)[1] = ((v1)[2] * (v2)[0]) - ((v1)[0] * (v2)[2]);\
- (res)[2] = ((v1)[0] * (v2)[1]) - ((v1)[1] * (v2)[0]);
-//===========================================================================
-// tests if the given point is within the face boundaries
-//
-// Parameter: face : face to test if the point is in it
-// pnormal : normal of the plane to use for the face
-// point : point to test if inside face boundaries
-// Returns: qtrue if the point is within the face boundaries
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_InsideFace(aas_face_t *face, vec3_t pnormal, vec3_t point, float epsilon)
-{
- int i, firstvertex, edgenum;
- vec3_t v0;
- vec3_t edgevec, pointvec, sepnormal;
- aas_edge_t *edge;
-#ifdef AAS_SAMPLE_DEBUG
- int lastvertex = 0;
-#endif //AAS_SAMPLE_DEBUG
-
- if (!aasworld.loaded) return qfalse;
-
- for (i = 0; i < face->numedges; i++)
- {
- edgenum = aasworld.edgeindex[face->firstedge + i];
- edge = &aasworld.edges[abs(edgenum)];
- //get the first vertex of the edge
- firstvertex = edgenum < 0;
- VectorCopy(aasworld.vertexes[edge->v[firstvertex]], v0);
- //edge vector
- VectorSubtract(aasworld.vertexes[edge->v[!firstvertex]], v0, edgevec);
- //
-#ifdef AAS_SAMPLE_DEBUG
- if (lastvertex && lastvertex != edge->v[firstvertex])
- {
- botimport.Print(PRT_MESSAGE, "winding not counter clockwise\n");
- } //end if
- lastvertex = edge->v[!firstvertex];
-#endif //AAS_SAMPLE_DEBUG
- //vector from first edge point to point possible in face
- VectorSubtract(point, v0, pointvec);
- //get a vector pointing inside the face orthogonal to both the
- //edge vector and the normal vector of the plane the face is in
- //this vector defines a plane through the origin (first vertex of
- //edge) and through both the edge vector and the normal vector
- //of the plane
- AAS_OrthogonalToVectors(edgevec, pnormal, sepnormal);
- //check on wich side of the above plane the point is
- //this is done by checking the sign of the dot product of the
- //vector orthogonal vector from above and the vector from the
- //origin (first vertex of edge) to the point
- //if the dotproduct is smaller than zero the point is outside the face
- if (DotProduct(pointvec, sepnormal) < -epsilon) return qfalse;
- } //end for
- return qtrue;
-} //end of the function AAS_InsideFace
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean AAS_PointInsideFace(int facenum, vec3_t point, float epsilon)
-{
- int i, firstvertex, edgenum;
- vec_t *v1, *v2;
- vec3_t edgevec, pointvec, sepnormal;
- aas_edge_t *edge;
- aas_plane_t *plane;
- aas_face_t *face;
-
- if (!aasworld.loaded) return qfalse;
-
- face = &aasworld.faces[facenum];
- plane = &aasworld.planes[face->planenum];
- //
- for (i = 0; i < face->numedges; i++)
- {
- edgenum = aasworld.edgeindex[face->firstedge + i];
- edge = &aasworld.edges[abs(edgenum)];
- //get the first vertex of the edge
- firstvertex = edgenum < 0;
- v1 = aasworld.vertexes[edge->v[firstvertex]];
- v2 = aasworld.vertexes[edge->v[!firstvertex]];
- //edge vector
- VectorSubtract(v2, v1, edgevec);
- //vector from first edge point to point possible in face
- VectorSubtract(point, v1, pointvec);
- //
- CrossProduct(edgevec, plane->normal, sepnormal);
- //
- if (DotProduct(pointvec, sepnormal) < -epsilon) return qfalse;
- } //end for
- return qtrue;
-} //end of the function AAS_PointInsideFace
-//===========================================================================
-// returns the ground face the given point is above in the given area
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-aas_face_t *AAS_AreaGroundFace(int areanum, vec3_t point)
-{
- int i, facenum;
- vec3_t up = {0, 0, 1};
- vec3_t normal;
- aas_area_t *area;
- aas_face_t *face;
-
- if (!aasworld.loaded) return NULL;
-
- area = &aasworld.areas[areanum];
- for (i = 0; i < area->numfaces; i++)
- {
- facenum = aasworld.faceindex[area->firstface + i];
- face = &aasworld.faces[abs(facenum)];
- //if this is a ground face
- if (face->faceflags & FACE_GROUND)
- {
- //get the up or down normal
- if (aasworld.planes[face->planenum].normal[2] < 0) VectorNegate(up, normal);
- else VectorCopy(up, normal);
- //check if the point is in the face
- if (AAS_InsideFace(face, normal, point, 0.01f)) return face;
- } //end if
- } //end for
- return NULL;
-} //end of the function AAS_AreaGroundFace
-//===========================================================================
-// returns the face the trace end position is situated in
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_FacePlane(int facenum, vec3_t normal, float *dist)
-{
- aas_plane_t *plane;
-
- plane = &aasworld.planes[aasworld.faces[facenum].planenum];
- VectorCopy(plane->normal, normal);
- *dist = plane->dist;
-} //end of the function AAS_FacePlane
-//===========================================================================
-// returns the face the trace end position is situated in
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-aas_face_t *AAS_TraceEndFace(aas_trace_t *trace)
-{
- int i, facenum;
- aas_area_t *area;
- aas_face_t *face, *firstface = NULL;
-
- if (!aasworld.loaded) return NULL;
-
- //if started in solid no face was hit
- if (trace->startsolid) return NULL;
- //trace->lastarea is the last area the trace was in
- area = &aasworld.areas[trace->lastarea];
- //check which face the trace.endpos was in
- for (i = 0; i < area->numfaces; i++)
- {
- facenum = aasworld.faceindex[area->firstface + i];
- face = &aasworld.faces[abs(facenum)];
- //if the face is in the same plane as the trace end point
- if ((face->planenum & ~1) == (trace->planenum & ~1))
- {
- //firstface is used for optimization, if theres only one
- //face in the plane then it has to be the good one
- //if there are more faces in the same plane then always
- //check the one with the fewest edges first
-/* if (firstface)
- {
- if (firstface->numedges < face->numedges)
- {
- if (AAS_InsideFace(firstface,
- aasworld.planes[face->planenum].normal, trace->endpos))
- {
- return firstface;
- } //end if
- firstface = face;
- } //end if
- else
- {
- if (AAS_InsideFace(face,
- aasworld.planes[face->planenum].normal, trace->endpos))
- {
- return face;
- } //end if
- } //end else
- } //end if
- else
- {
- firstface = face;
- } //end else*/
- if (AAS_InsideFace(face,
- aasworld.planes[face->planenum].normal, trace->endpos, 0.01f)) return face;
- } //end if
- } //end for
- return firstface;
-} //end of the function AAS_TraceEndFace
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_BoxOnPlaneSide2(vec3_t absmins, vec3_t absmaxs, aas_plane_t *p)
-{
- int i, sides;
- float dist1, dist2;
- vec3_t corners[2];
-
- for (i = 0; i < 3; i++)
- {
- if (p->normal[i] < 0)
- {
- corners[0][i] = absmins[i];
- corners[1][i] = absmaxs[i];
- } //end if
- else
- {
- corners[1][i] = absmins[i];
- corners[0][i] = absmaxs[i];
- } //end else
- } //end for
- dist1 = DotProduct(p->normal, corners[0]) - p->dist;
- dist2 = DotProduct(p->normal, corners[1]) - p->dist;
- sides = 0;
- if (dist1 >= 0) sides = 1;
- if (dist2 < 0) sides |= 2;
-
- return sides;
-} //end of the function AAS_BoxOnPlaneSide2
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-//int AAS_BoxOnPlaneSide(vec3_t absmins, vec3_t absmaxs, aas_plane_t *p)
-#define AAS_BoxOnPlaneSide(absmins, absmaxs, p) (\
- ( (p)->type < 3) ?\
- (\
- ( (p)->dist <= (absmins)[(p)->type]) ?\
- (\
- 1\
- )\
- :\
- (\
- ( (p)->dist >= (absmaxs)[(p)->type]) ?\
- (\
- 2\
- )\
- :\
- (\
- 3\
- )\
- )\
- )\
- :\
- (\
- AAS_BoxOnPlaneSide2((absmins), (absmaxs), (p))\
- )\
-) //end of the function AAS_BoxOnPlaneSide
-//===========================================================================
-// remove the links to this entity from all areas
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_UnlinkFromAreas(aas_link_t *areas)
-{
- aas_link_t *link, *nextlink;
-
- for (link = areas; link; link = nextlink)
- {
- //next area the entity is linked in
- nextlink = link->next_area;
- //remove the entity from the linked list of this area
- if (link->prev_ent) link->prev_ent->next_ent = link->next_ent;
- else aasworld.arealinkedentities[link->areanum] = link->next_ent;
- if (link->next_ent) link->next_ent->prev_ent = link->prev_ent;
- //deallocate the link structure
- AAS_DeAllocAASLink(link);
- } //end for
-} //end of the function AAS_UnlinkFromAreas
-//===========================================================================
-// link the entity to the areas the bounding box is totally or partly
-// situated in. This is done with recursion down the tree using the
-// bounding box to test for plane sides
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-
-typedef struct
-{
- int nodenum; //node found after splitting
-} aas_linkstack_t;
-
-aas_link_t *AAS_AASLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum)
-{
- int side, nodenum;
- aas_linkstack_t linkstack[128];
- aas_linkstack_t *lstack_p;
- aas_node_t *aasnode;
- aas_plane_t *plane;
- aas_link_t *link, *areas;
-
- if (!aasworld.loaded)
- {
- botimport.Print(PRT_ERROR, "AAS_LinkEntity: aas not loaded\n");
- return NULL;
- } //end if
-
- areas = NULL;
- //
- lstack_p = linkstack;
- //we start with the whole line on the stack
- //start with node 1 because node zero is a dummy used for solid leafs
- lstack_p->nodenum = 1; //starting at the root of the tree
- lstack_p++;
-
- while (1)
- {
- //pop up the stack
- lstack_p--;
- //if the trace stack is empty (ended up with a piece of the
- //line to be traced in an area)
- if (lstack_p < linkstack) break;
- //number of the current node to test the line against
- nodenum = lstack_p->nodenum;
- //if it is an area
- if (nodenum < 0)
- {
- //NOTE: the entity might have already been linked into this area
- // because several node children can point to the same area
- for (link = aasworld.arealinkedentities[-nodenum]; link; link = link->next_ent)
- {
- if (link->entnum == entnum) break;
- } //end for
- if (link) continue;
- //
- link = AAS_AllocAASLink();
- if (!link) return areas;
- link->entnum = entnum;
- link->areanum = -nodenum;
- //put the link into the double linked area list of the entity
- link->prev_area = NULL;
- link->next_area = areas;
- if (areas) areas->prev_area = link;
- areas = link;
- //put the link into the double linked entity list of the area
- link->prev_ent = NULL;
- link->next_ent = aasworld.arealinkedentities[-nodenum];
- if (aasworld.arealinkedentities[-nodenum])
- aasworld.arealinkedentities[-nodenum]->prev_ent = link;
- aasworld.arealinkedentities[-nodenum] = link;
- //
- continue;
- } //end if
- //if solid leaf
- if (!nodenum) continue;
- //the node to test against
- aasnode = &aasworld.nodes[nodenum];
- //the current node plane
- plane = &aasworld.planes[aasnode->planenum];
- //get the side(s) the box is situated relative to the plane
- side = AAS_BoxOnPlaneSide2(absmins, absmaxs, plane);
- //if on the front side of the node
- if (side & 1)
- {
- lstack_p->nodenum = aasnode->children[0];
- lstack_p++;
- } //end if
- if (lstack_p >= &linkstack[127])
- {
- botimport.Print(PRT_ERROR, "AAS_LinkEntity: stack overflow\n");
- break;
- } //end if
- //if on the back side of the node
- if (side & 2)
- {
- lstack_p->nodenum = aasnode->children[1];
- lstack_p++;
- } //end if
- if (lstack_p >= &linkstack[127])
- {
- botimport.Print(PRT_ERROR, "AAS_LinkEntity: stack overflow\n");
- break;
- } //end if
- } //end while
- return areas;
-} //end of the function AAS_AASLinkEntity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-aas_link_t *AAS_LinkEntityClientBBox(vec3_t absmins, vec3_t absmaxs, int entnum, int presencetype)
-{
- vec3_t mins, maxs;
- vec3_t newabsmins, newabsmaxs;
-
- AAS_PresenceTypeBoundingBox(presencetype, mins, maxs);
- VectorSubtract(absmins, maxs, newabsmins);
- VectorSubtract(absmaxs, mins, newabsmaxs);
- //relink the entity
- return AAS_AASLinkEntity(newabsmins, newabsmaxs, entnum);
-} //end of the function AAS_LinkEntityClientBBox
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas)
-{
- aas_link_t *linkedareas, *link;
- int num;
-
- linkedareas = AAS_AASLinkEntity(absmins, absmaxs, -1);
- num = 0;
- for (link = linkedareas; link; link = link->next_area)
- {
- areas[num] = link->areanum;
- num++;
- if (num >= maxareas)
- break;
- } //end for
- AAS_UnlinkFromAreas(linkedareas);
- return num;
-} //end of the function AAS_BBoxAreas
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AAS_AreaInfo( int areanum, aas_areainfo_t *info )
-{
- aas_areasettings_t *settings;
- if (!info)
- return 0;
- if (areanum <= 0 || areanum >= aasworld.numareas)
- {
- botimport.Print(PRT_ERROR, "AAS_AreaInfo: areanum %d out of range\n", areanum);
- return 0;
- } //end if
- settings = &aasworld.areasettings[areanum];
- info->cluster = settings->cluster;
- info->contents = settings->contents;
- info->flags = settings->areaflags;
- info->presencetype = settings->presencetype;
- VectorCopy(aasworld.areas[areanum].mins, info->mins);
- VectorCopy(aasworld.areas[areanum].maxs, info->maxs);
- VectorCopy(aasworld.areas[areanum].center, info->center);
- return sizeof(aas_areainfo_t);
-} //end of the function AAS_AreaInfo
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-aas_plane_t *AAS_PlaneFromNum(int planenum)
-{
- if (!aasworld.loaded) return NULL;
-
- return &aasworld.planes[planenum];
-} //end of the function AAS_PlaneFromNum
diff --git a/engine/code/botlib/be_ai_char.c b/engine/code/botlib/be_ai_char.c
deleted file mode 100644
index d360886..0000000
--- a/engine/code/botlib/be_ai_char.c
+++ /dev/null
@@ -1,790 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_ai_char.c
- *
- * desc: bot characters
- *
- * $Archive: /MissionPack/code/botlib/be_ai_char.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_log.h"
-#include "l_memory.h"
-#include "l_utils.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "l_libvar.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-#include "be_ai_char.h"
-
-#define MAX_CHARACTERISTICS 80
-
-#define CT_INTEGER 1
-#define CT_FLOAT 2
-#define CT_STRING 3
-
-#define DEFAULT_CHARACTER "bots/default_c.c"
-
-//characteristic value
-union cvalue
-{
- int integer;
- float _float;
- char *string;
-};
-//a characteristic
-typedef struct bot_characteristic_s
-{
- char type; //characteristic type
- union cvalue value; //characteristic value
-} bot_characteristic_t;
-
-//a bot character
-typedef struct bot_character_s
-{
- char filename[MAX_QPATH];
- float skill;
- bot_characteristic_t c[1]; //variable sized
-} bot_character_t;
-
-bot_character_t *botcharacters[MAX_CLIENTS + 1];
-
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-bot_character_t *BotCharacterFromHandle(int handle)
-{
- if (handle <= 0 || handle > MAX_CLIENTS)
- {
- botimport.Print(PRT_FATAL, "character handle %d out of range\n", handle);
- return NULL;
- } //end if
- if (!botcharacters[handle])
- {
- botimport.Print(PRT_FATAL, "invalid character %d\n", handle);
- return NULL;
- } //end if
- return botcharacters[handle];
-} //end of the function BotCharacterFromHandle
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotDumpCharacter(bot_character_t *ch)
-{
- int i;
-
- Log_Write("%s", ch->filename);
- Log_Write("skill %d\n", ch->skill);
- Log_Write("{\n");
- for (i = 0; i < MAX_CHARACTERISTICS; i++)
- {
- switch(ch->c[i].type)
- {
- case CT_INTEGER: Log_Write(" %4d %d\n", i, ch->c[i].value.integer); break;
- case CT_FLOAT: Log_Write(" %4d %f\n", i, ch->c[i].value._float); break;
- case CT_STRING: Log_Write(" %4d %s\n", i, ch->c[i].value.string); break;
- } //end case
- } //end for
- Log_Write("}\n");
-} //end of the function BotDumpCharacter
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-void BotFreeCharacterStrings(bot_character_t *ch)
-{
- int i;
-
- for (i = 0; i < MAX_CHARACTERISTICS; i++)
- {
- if (ch->c[i].type == CT_STRING)
- {
- FreeMemory(ch->c[i].value.string);
- } //end if
- } //end for
-} //end of the function BotFreeCharacterStrings
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-void BotFreeCharacter2(int handle)
-{
- if (handle <= 0 || handle > MAX_CLIENTS)
- {
- botimport.Print(PRT_FATAL, "character handle %d out of range\n", handle);
- return;
- } //end if
- if (!botcharacters[handle])
- {
- botimport.Print(PRT_FATAL, "invalid character %d\n", handle);
- return;
- } //end if
- BotFreeCharacterStrings(botcharacters[handle]);
- FreeMemory(botcharacters[handle]);
- botcharacters[handle] = NULL;
-} //end of the function BotFreeCharacter2
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-void BotFreeCharacter(int handle)
-{
- if (!LibVarGetValue("bot_reloadcharacters")) return;
- BotFreeCharacter2(handle);
-} //end of the function BotFreeCharacter
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotDefaultCharacteristics(bot_character_t *ch, bot_character_t *defaultch)
-{
- int i;
-
- for (i = 0; i < MAX_CHARACTERISTICS; i++)
- {
- if (ch->c[i].type) continue;
- //
- if (defaultch->c[i].type == CT_FLOAT)
- {
- ch->c[i].type = CT_FLOAT;
- ch->c[i].value._float = defaultch->c[i].value._float;
- } //end if
- else if (defaultch->c[i].type == CT_INTEGER)
- {
- ch->c[i].type = CT_INTEGER;
- ch->c[i].value.integer = defaultch->c[i].value.integer;
- } //end else if
- else if (defaultch->c[i].type == CT_STRING)
- {
- ch->c[i].type = CT_STRING;
- ch->c[i].value.string = (char *) GetMemory(strlen(defaultch->c[i].value.string)+1);
- strcpy(ch->c[i].value.string, defaultch->c[i].value.string);
- } //end else if
- } //end for
-} //end of the function BotDefaultCharacteristics
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_character_t *BotLoadCharacterFromFile(char *charfile, int skill)
-{
- int indent, index, foundcharacter;
- bot_character_t *ch;
- source_t *source;
- token_t token;
-
- foundcharacter = qfalse;
- //a bot character is parsed in two phases
- PC_SetBaseFolder(BOTFILESBASEFOLDER);
- source = LoadSourceFile(charfile);
- if (!source)
- {
- botimport.Print(PRT_ERROR, "counldn't load %s\n", charfile);
- return NULL;
- } //end if
- ch = (bot_character_t *) GetClearedMemory(sizeof(bot_character_t) +
- MAX_CHARACTERISTICS * sizeof(bot_characteristic_t));
- strcpy(ch->filename, charfile);
- while(PC_ReadToken(source, &token))
- {
- if (!strcmp(token.string, "skill"))
- {
- if (!PC_ExpectTokenType(source, TT_NUMBER, 0, &token))
- {
- FreeSource(source);
- BotFreeCharacterStrings(ch);
- FreeMemory(ch);
- return NULL;
- } //end if
- if (!PC_ExpectTokenString(source, "{"))
- {
- FreeSource(source);
- BotFreeCharacterStrings(ch);
- FreeMemory(ch);
- return NULL;
- } //end if
- //if it's the correct skill
- if (skill < 0 || token.intvalue == skill)
- {
- foundcharacter = qtrue;
- ch->skill = token.intvalue;
- while(PC_ExpectAnyToken(source, &token))
- {
- if (!strcmp(token.string, "}")) break;
- if (token.type != TT_NUMBER || !(token.subtype & TT_INTEGER))
- {
- SourceError(source, "expected integer index, found %s\n", token.string);
- FreeSource(source);
- BotFreeCharacterStrings(ch);
- FreeMemory(ch);
- return NULL;
- } //end if
- index = token.intvalue;
- if (index < 0 || index > MAX_CHARACTERISTICS)
- {
- SourceError(source, "characteristic index out of range [0, %d]\n", MAX_CHARACTERISTICS);
- FreeSource(source);
- BotFreeCharacterStrings(ch);
- FreeMemory(ch);
- return NULL;
- } //end if
- if (ch->c[index].type)
- {
- SourceError(source, "characteristic %d already initialized\n", index);
- FreeSource(source);
- BotFreeCharacterStrings(ch);
- FreeMemory(ch);
- return NULL;
- } //end if
- if (!PC_ExpectAnyToken(source, &token))
- {
- FreeSource(source);
- BotFreeCharacterStrings(ch);
- FreeMemory(ch);
- return NULL;
- } //end if
- if (token.type == TT_NUMBER)
- {
- if (token.subtype & TT_FLOAT)
- {
- ch->c[index].value._float = token.floatvalue;
- ch->c[index].type = CT_FLOAT;
- } //end if
- else
- {
- ch->c[index].value.integer = token.intvalue;
- ch->c[index].type = CT_INTEGER;
- } //end else
- } //end if
- else if (token.type == TT_STRING)
- {
- StripDoubleQuotes(token.string);
- ch->c[index].value.string = GetMemory(strlen(token.string)+1);
- strcpy(ch->c[index].value.string, token.string);
- ch->c[index].type = CT_STRING;
- } //end else if
- else
- {
- SourceError(source, "expected integer, float or string, found %s\n", token.string);
- FreeSource(source);
- BotFreeCharacterStrings(ch);
- FreeMemory(ch);
- return NULL;
- } //end else
- } //end if
- break;
- } //end if
- else
- {
- indent = 1;
- while(indent)
- {
- if (!PC_ExpectAnyToken(source, &token))
- {
- FreeSource(source);
- BotFreeCharacterStrings(ch);
- FreeMemory(ch);
- return NULL;
- } //end if
- if (!strcmp(token.string, "{")) indent++;
- else if (!strcmp(token.string, "}")) indent--;
- } //end while
- } //end else
- } //end if
- else
- {
- SourceError(source, "unknown definition %s\n", token.string);
- FreeSource(source);
- BotFreeCharacterStrings(ch);
- FreeMemory(ch);
- return NULL;
- } //end else
- } //end while
- FreeSource(source);
- //
- if (!foundcharacter)
- {
- BotFreeCharacterStrings(ch);
- FreeMemory(ch);
- return NULL;
- } //end if
- return ch;
-} //end of the function BotLoadCharacterFromFile
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotFindCachedCharacter(char *charfile, float skill)
-{
- int handle;
-
- for (handle = 1; handle <= MAX_CLIENTS; handle++)
- {
- if ( !botcharacters[handle] ) continue;
- if ( strcmp( botcharacters[handle]->filename, charfile ) == 0 &&
- (skill < 0 || fabs(botcharacters[handle]->skill - skill) < 0.01) )
- {
- return handle;
- } //end if
- } //end for
- return 0;
-} //end of the function BotFindCachedCharacter
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotLoadCachedCharacter(char *charfile, float skill, int reload)
-{
- int handle, cachedhandle, intskill;
- bot_character_t *ch = NULL;
-#ifdef DEBUG
- int starttime;
-
- starttime = Sys_MilliSeconds();
-#endif //DEBUG
-
- //find a free spot for a character
- for (handle = 1; handle <= MAX_CLIENTS; handle++)
- {
- if (!botcharacters[handle]) break;
- } //end for
- if (handle > MAX_CLIENTS) return 0;
- //try to load a cached character with the given skill
- if (!reload)
- {
- cachedhandle = BotFindCachedCharacter(charfile, skill);
- if (cachedhandle)
- {
- botimport.Print(PRT_MESSAGE, "loaded cached skill %f from %s\n", skill, charfile);
- return cachedhandle;
- } //end if
- } //end else
- //
- intskill = (int) (skill + 0.5);
- //try to load the character with the given skill
- ch = BotLoadCharacterFromFile(charfile, intskill);
- if (ch)
- {
- botcharacters[handle] = ch;
- //
- botimport.Print(PRT_MESSAGE, "loaded skill %d from %s\n", intskill, charfile);
-#ifdef DEBUG
- if (botDeveloper)
- {
- botimport.Print(PRT_MESSAGE, "skill %d loaded in %d msec from %s\n", intskill, Sys_MilliSeconds() - starttime, charfile);
- } //end if
-#endif //DEBUG
- return handle;
- } //end if
- //
- botimport.Print(PRT_WARNING, "couldn't find skill %d in %s\n", intskill, charfile);
- //
- if (!reload)
- {
- //try to load a cached default character with the given skill
- cachedhandle = BotFindCachedCharacter(DEFAULT_CHARACTER, skill);
- if (cachedhandle)
- {
- botimport.Print(PRT_MESSAGE, "loaded cached default skill %d from %s\n", intskill, charfile);
- return cachedhandle;
- } //end if
- } //end if
- //try to load the default character with the given skill
- ch = BotLoadCharacterFromFile(DEFAULT_CHARACTER, intskill);
- if (ch)
- {
- botcharacters[handle] = ch;
- botimport.Print(PRT_MESSAGE, "loaded default skill %d from %s\n", intskill, charfile);
- return handle;
- } //end if
- //
- if (!reload)
- {
- //try to load a cached character with any skill
- cachedhandle = BotFindCachedCharacter(charfile, -1);
- if (cachedhandle)
- {
- botimport.Print(PRT_MESSAGE, "loaded cached skill %f from %s\n", botcharacters[cachedhandle]->skill, charfile);
- return cachedhandle;
- } //end if
- } //end if
- //try to load a character with any skill
- ch = BotLoadCharacterFromFile(charfile, -1);
- if (ch)
- {
- botcharacters[handle] = ch;
- botimport.Print(PRT_MESSAGE, "loaded skill %f from %s\n", ch->skill, charfile);
- return handle;
- } //end if
- //
- if (!reload)
- {
- //try to load a cached character with any skill
- cachedhandle = BotFindCachedCharacter(DEFAULT_CHARACTER, -1);
- if (cachedhandle)
- {
- botimport.Print(PRT_MESSAGE, "loaded cached default skill %f from %s\n", botcharacters[cachedhandle]->skill, charfile);
- return cachedhandle;
- } //end if
- } //end if
- //try to load a character with any skill
- ch = BotLoadCharacterFromFile(DEFAULT_CHARACTER, -1);
- if (ch)
- {
- botcharacters[handle] = ch;
- botimport.Print(PRT_MESSAGE, "loaded default skill %f from %s\n", ch->skill, charfile);
- return handle;
- } //end if
- //
- botimport.Print(PRT_WARNING, "couldn't load any skill from %s\n", charfile);
- //couldn't load any character
- return 0;
-} //end of the function BotLoadCachedCharacter
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotLoadCharacterSkill(char *charfile, float skill)
-{
- int ch, defaultch;
-
- defaultch = BotLoadCachedCharacter(DEFAULT_CHARACTER, skill, qfalse);
- ch = BotLoadCachedCharacter(charfile, skill, LibVarGetValue("bot_reloadcharacters"));
-
- if (defaultch && ch)
- {
- BotDefaultCharacteristics(botcharacters[ch], botcharacters[defaultch]);
- } //end if
-
- return ch;
-} //end of the function BotLoadCharacterSkill
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotInterpolateCharacters(int handle1, int handle2, float desiredskill)
-{
- bot_character_t *ch1, *ch2, *out;
- int i, handle;
- float scale;
-
- ch1 = BotCharacterFromHandle(handle1);
- ch2 = BotCharacterFromHandle(handle2);
- if (!ch1 || !ch2)
- return 0;
- //find a free spot for a character
- for (handle = 1; handle <= MAX_CLIENTS; handle++)
- {
- if (!botcharacters[handle]) break;
- } //end for
- if (handle > MAX_CLIENTS) return 0;
- out = (bot_character_t *) GetClearedMemory(sizeof(bot_character_t) +
- MAX_CHARACTERISTICS * sizeof(bot_characteristic_t));
- out->skill = desiredskill;
- strcpy(out->filename, ch1->filename);
- botcharacters[handle] = out;
-
- scale = (float) (desiredskill - ch1->skill) / (ch2->skill - ch1->skill);
- for (i = 0; i < MAX_CHARACTERISTICS; i++)
- {
- //
- if (ch1->c[i].type == CT_FLOAT && ch2->c[i].type == CT_FLOAT)
- {
- out->c[i].type = CT_FLOAT;
- out->c[i].value._float = ch1->c[i].value._float +
- (ch2->c[i].value._float - ch1->c[i].value._float) * scale;
- } //end if
- else if (ch1->c[i].type == CT_INTEGER)
- {
- out->c[i].type = CT_INTEGER;
- out->c[i].value.integer = ch1->c[i].value.integer;
- } //end else if
- else if (ch1->c[i].type == CT_STRING)
- {
- out->c[i].type = CT_STRING;
- out->c[i].value.string = (char *) GetMemory(strlen(ch1->c[i].value.string)+1);
- strcpy(out->c[i].value.string, ch1->c[i].value.string);
- } //end else if
- } //end for
- return handle;
-} //end of the function BotInterpolateCharacters
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotLoadCharacter(char *charfile, float skill)
-{
- int firstskill, secondskill, handle;
-
- //make sure the skill is in the valid range
- if (skill < 1.0) skill = 1.0;
- else if (skill > 5.0) skill = 5.0;
- //skill 1, 4 and 5 should be available in the character files
- if (skill == 1.0 || skill == 4.0 || skill == 5.0)
- {
- return BotLoadCharacterSkill(charfile, skill);
- } //end if
- //check if there's a cached skill
- handle = BotFindCachedCharacter(charfile, skill);
- if (handle)
- {
- botimport.Print(PRT_MESSAGE, "loaded cached skill %f from %s\n", skill, charfile);
- return handle;
- } //end if
- if (skill < 4.0)
- {
- //load skill 1 and 4
- firstskill = BotLoadCharacterSkill(charfile, 1);
- if (!firstskill) return 0;
- secondskill = BotLoadCharacterSkill(charfile, 4);
- if (!secondskill) return firstskill;
- } //end if
- else
- {
- //load skill 4 and 5
- firstskill = BotLoadCharacterSkill(charfile, 4);
- if (!firstskill) return 0;
- secondskill = BotLoadCharacterSkill(charfile, 5);
- if (!secondskill) return firstskill;
- } //end else
- //interpolate between the two skills
- handle = BotInterpolateCharacters(firstskill, secondskill, skill);
- if (!handle) return 0;
- //write the character to the log file
- BotDumpCharacter(botcharacters[handle]);
- //
- return handle;
-} //end of the function BotLoadCharacter
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int CheckCharacteristicIndex(int character, int index)
-{
- bot_character_t *ch;
-
- ch = BotCharacterFromHandle(character);
- if (!ch) return qfalse;
- if (index < 0 || index >= MAX_CHARACTERISTICS)
- {
- botimport.Print(PRT_ERROR, "characteristic %d does not exist\n", index);
- return qfalse;
- } //end if
- if (!ch->c[index].type)
- {
- botimport.Print(PRT_ERROR, "characteristic %d is not initialized\n", index);
- return qfalse;
- } //end if
- return qtrue;
-} //end of the function CheckCharacteristicIndex
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float Characteristic_Float(int character, int index)
-{
- bot_character_t *ch;
-
- ch = BotCharacterFromHandle(character);
- if (!ch) return 0;
- //check if the index is in range
- if (!CheckCharacteristicIndex(character, index)) return 0;
- //an integer will be converted to a float
- if (ch->c[index].type == CT_INTEGER)
- {
- return (float) ch->c[index].value.integer;
- } //end if
- //floats are just returned
- else if (ch->c[index].type == CT_FLOAT)
- {
- return ch->c[index].value._float;
- } //end else if
- //cannot convert a string pointer to a float
- else
- {
- botimport.Print(PRT_ERROR, "characteristic %d is not a float\n", index);
- return 0;
- } //end else if
-// return 0;
-} //end of the function Characteristic_Float
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float Characteristic_BFloat(int character, int index, float min, float max)
-{
- float value;
- bot_character_t *ch;
-
- ch = BotCharacterFromHandle(character);
- if (!ch) return 0;
- if (min > max)
- {
- botimport.Print(PRT_ERROR, "cannot bound characteristic %d between %f and %f\n", index, min, max);
- return 0;
- } //end if
- value = Characteristic_Float(character, index);
- if (value < min) return min;
- if (value > max) return max;
- return value;
-} //end of the function Characteristic_BFloat
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Characteristic_Integer(int character, int index)
-{
- bot_character_t *ch;
-
- ch = BotCharacterFromHandle(character);
- if (!ch) return 0;
- //check if the index is in range
- if (!CheckCharacteristicIndex(character, index)) return 0;
- //an integer will just be returned
- if (ch->c[index].type == CT_INTEGER)
- {
- return ch->c[index].value.integer;
- } //end if
- //floats are casted to integers
- else if (ch->c[index].type == CT_FLOAT)
- {
- return (int) ch->c[index].value._float;
- } //end else if
- else
- {
- botimport.Print(PRT_ERROR, "characteristic %d is not a integer\n", index);
- return 0;
- } //end else if
-// return 0;
-} //end of the function Characteristic_Integer
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Characteristic_BInteger(int character, int index, int min, int max)
-{
- int value;
- bot_character_t *ch;
-
- ch = BotCharacterFromHandle(character);
- if (!ch) return 0;
- if (min > max)
- {
- botimport.Print(PRT_ERROR, "cannot bound characteristic %d between %d and %d\n", index, min, max);
- return 0;
- } //end if
- value = Characteristic_Integer(character, index);
- if (value < min) return min;
- if (value > max) return max;
- return value;
-} //end of the function Characteristic_BInteger
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Characteristic_String(int character, int index, char *buf, int size)
-{
- bot_character_t *ch;
-
- ch = BotCharacterFromHandle(character);
- if (!ch) return;
- //check if the index is in range
- if (!CheckCharacteristicIndex(character, index)) return;
- //an integer will be converted to a float
- if (ch->c[index].type == CT_STRING)
- {
- strncpy(buf, ch->c[index].value.string, size-1);
- buf[size-1] = '\0';
- return;
- } //end if
- else
- {
- botimport.Print(PRT_ERROR, "characteristic %d is not a string\n", index);
- return;
- } //end else if
- return;
-} //end of the function Characteristic_String
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotShutdownCharacters(void)
-{
- int handle;
-
- for (handle = 1; handle <= MAX_CLIENTS; handle++)
- {
- if (botcharacters[handle])
- {
- BotFreeCharacter2(handle);
- } //end if
- } //end for
-} //end of the function BotShutdownCharacters
-
diff --git a/engine/code/botlib/be_ai_chat.c b/engine/code/botlib/be_ai_chat.c
deleted file mode 100644
index 5092cec..0000000
--- a/engine/code/botlib/be_ai_chat.c
+++ /dev/null
@@ -1,3042 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_ai_chat.c
- *
- * desc: bot chat AI
- *
- * $Archive: /MissionPack/code/botlib/be_ai_chat.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_libvar.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "l_utils.h"
-#include "l_log.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-#include "be_ea.h"
-#include "be_ai_chat.h"
-
-
-//escape character
-#define ESCAPE_CHAR 0x01 //'_'
-//
-// "hi ", people, " ", 0, " entered the game"
-//becomes:
-// "hi _rpeople_ _v0_ entered the game"
-//
-
-//match piece types
-#define MT_VARIABLE 1 //variable match piece
-#define MT_STRING 2 //string match piece
-//reply chat key flags
-#define RCKFL_AND 1 //key must be present
-#define RCKFL_NOT 2 //key must be absent
-#define RCKFL_NAME 4 //name of bot must be present
-#define RCKFL_STRING 8 //key is a string
-#define RCKFL_VARIABLES 16 //key is a match template
-#define RCKFL_BOTNAMES 32 //key is a series of botnames
-#define RCKFL_GENDERFEMALE 64 //bot must be female
-#define RCKFL_GENDERMALE 128 //bot must be male
-#define RCKFL_GENDERLESS 256 //bot must be genderless
-//time to ignore a chat message after using it
-#define CHATMESSAGE_RECENTTIME 20
-
-//the actuall chat messages
-typedef struct bot_chatmessage_s
-{
- char *chatmessage; //chat message string
- float time; //last time used
- struct bot_chatmessage_s *next; //next chat message in a list
-} bot_chatmessage_t;
-//bot chat type with chat lines
-typedef struct bot_chattype_s
-{
- char name[MAX_CHATTYPE_NAME];
- int numchatmessages;
- bot_chatmessage_t *firstchatmessage;
- struct bot_chattype_s *next;
-} bot_chattype_t;
-//bot chat lines
-typedef struct bot_chat_s
-{
- bot_chattype_t *types;
-} bot_chat_t;
-
-//random string
-typedef struct bot_randomstring_s
-{
- char *string;
- struct bot_randomstring_s *next;
-} bot_randomstring_t;
-//list with random strings
-typedef struct bot_randomlist_s
-{
- char *string;
- int numstrings;
- bot_randomstring_t *firstrandomstring;
- struct bot_randomlist_s *next;
-} bot_randomlist_t;
-
-//synonym
-typedef struct bot_synonym_s
-{
- char *string;
- float weight;
- struct bot_synonym_s *next;
-} bot_synonym_t;
-//list with synonyms
-typedef struct bot_synonymlist_s
-{
- unsigned long int context;
- float totalweight;
- bot_synonym_t *firstsynonym;
- struct bot_synonymlist_s *next;
-} bot_synonymlist_t;
-
-//fixed match string
-typedef struct bot_matchstring_s
-{
- char *string;
- struct bot_matchstring_s *next;
-} bot_matchstring_t;
-
-//piece of a match template
-typedef struct bot_matchpiece_s
-{
- int type;
- bot_matchstring_t *firststring;
- int variable;
- struct bot_matchpiece_s *next;
-} bot_matchpiece_t;
-//match template
-typedef struct bot_matchtemplate_s
-{
- unsigned long int context;
- int type;
- int subtype;
- bot_matchpiece_t *first;
- struct bot_matchtemplate_s *next;
-} bot_matchtemplate_t;
-
-//reply chat key
-typedef struct bot_replychatkey_s
-{
- int flags;
- char *string;
- bot_matchpiece_t *match;
- struct bot_replychatkey_s *next;
-} bot_replychatkey_t;
-//reply chat
-typedef struct bot_replychat_s
-{
- bot_replychatkey_t *keys;
- float priority;
- int numchatmessages;
- bot_chatmessage_t *firstchatmessage;
- struct bot_replychat_s *next;
-} bot_replychat_t;
-
-//string list
-typedef struct bot_stringlist_s
-{
- char *string;
- struct bot_stringlist_s *next;
-} bot_stringlist_t;
-
-//chat state of a bot
-typedef struct bot_chatstate_s
-{
- int gender; //0=it, 1=female, 2=male
- int client; //client number
- char name[32]; //name of the bot
- char chatmessage[MAX_MESSAGE_SIZE];
- int handle;
- //the console messages visible to the bot
- bot_consolemessage_t *firstmessage; //first message is the first typed message
- bot_consolemessage_t *lastmessage; //last message is the last typed message, bottom of console
- //number of console messages stored in the state
- int numconsolemessages;
- //the bot chat lines
- bot_chat_t *chat;
-} bot_chatstate_t;
-
-typedef struct {
- bot_chat_t *chat;
- char filename[MAX_QPATH];
- char chatname[MAX_QPATH];
-} bot_ichatdata_t;
-
-bot_ichatdata_t *ichatdata[MAX_CLIENTS];
-
-bot_chatstate_t *botchatstates[MAX_CLIENTS+1];
-//console message heap
-bot_consolemessage_t *consolemessageheap = NULL;
-bot_consolemessage_t *freeconsolemessages = NULL;
-//list with match strings
-bot_matchtemplate_t *matchtemplates = NULL;
-//list with synonyms
-bot_synonymlist_t *synonyms = NULL;
-//list with random strings
-bot_randomlist_t *randomstrings = NULL;
-//reply chats
-bot_replychat_t *replychats = NULL;
-
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-bot_chatstate_t *BotChatStateFromHandle(int handle)
-{
- if (handle <= 0 || handle > MAX_CLIENTS)
- {
- botimport.Print(PRT_FATAL, "chat state handle %d out of range\n", handle);
- return NULL;
- } //end if
- if (!botchatstates[handle])
- {
- botimport.Print(PRT_FATAL, "invalid chat state %d\n", handle);
- return NULL;
- } //end if
- return botchatstates[handle];
-} //end of the function BotChatStateFromHandle
-//===========================================================================
-// initialize the heap with unused console messages
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void InitConsoleMessageHeap(void)
-{
- int i, max_messages;
-
- if (consolemessageheap) FreeMemory(consolemessageheap);
- //
- max_messages = (int) LibVarValue("max_messages", "1024");
- consolemessageheap = (bot_consolemessage_t *) GetClearedHunkMemory(max_messages *
- sizeof(bot_consolemessage_t));
- consolemessageheap[0].prev = NULL;
- consolemessageheap[0].next = &consolemessageheap[1];
- for (i = 1; i < max_messages-1; i++)
- {
- consolemessageheap[i].prev = &consolemessageheap[i - 1];
- consolemessageheap[i].next = &consolemessageheap[i + 1];
- } //end for
- consolemessageheap[max_messages-1].prev = &consolemessageheap[max_messages-2];
- consolemessageheap[max_messages-1].next = NULL;
- //pointer to the free console messages
- freeconsolemessages = consolemessageheap;
-} //end of the function InitConsoleMessageHeap
-//===========================================================================
-// allocate one console message from the heap
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_consolemessage_t *AllocConsoleMessage(void)
-{
- bot_consolemessage_t *message;
- message = freeconsolemessages;
- if (freeconsolemessages) freeconsolemessages = freeconsolemessages->next;
- if (freeconsolemessages) freeconsolemessages->prev = NULL;
- return message;
-} //end of the function AllocConsoleMessage
-//===========================================================================
-// deallocate one console message from the heap
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FreeConsoleMessage(bot_consolemessage_t *message)
-{
- if (freeconsolemessages) freeconsolemessages->prev = message;
- message->prev = NULL;
- message->next = freeconsolemessages;
- freeconsolemessages = message;
-} //end of the function FreeConsoleMessage
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotRemoveConsoleMessage(int chatstate, int handle)
-{
- bot_consolemessage_t *m, *nextm;
- bot_chatstate_t *cs;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return;
-
- for (m = cs->firstmessage; m; m = nextm)
- {
- nextm = m->next;
- if (m->handle == handle)
- {
- if (m->next) m->next->prev = m->prev;
- else cs->lastmessage = m->prev;
- if (m->prev) m->prev->next = m->next;
- else cs->firstmessage = m->next;
-
- FreeConsoleMessage(m);
- cs->numconsolemessages--;
- break;
- } //end if
- } //end for
-} //end of the function BotRemoveConsoleMessage
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotQueueConsoleMessage(int chatstate, int type, char *message)
-{
- bot_consolemessage_t *m;
- bot_chatstate_t *cs;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return;
-
- m = AllocConsoleMessage();
- if (!m)
- {
- botimport.Print(PRT_ERROR, "empty console message heap\n");
- return;
- } //end if
- cs->handle++;
- if (cs->handle <= 0 || cs->handle > 8192) cs->handle = 1;
- m->handle = cs->handle;
- m->time = AAS_Time();
- m->type = type;
- strncpy(m->message, message, MAX_MESSAGE_SIZE);
- m->next = NULL;
- if (cs->lastmessage)
- {
- cs->lastmessage->next = m;
- m->prev = cs->lastmessage;
- cs->lastmessage = m;
- } //end if
- else
- {
- cs->lastmessage = m;
- cs->firstmessage = m;
- m->prev = NULL;
- } //end if
- cs->numconsolemessages++;
-} //end of the function BotQueueConsoleMessage
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotNextConsoleMessage(int chatstate, bot_consolemessage_t *cm)
-{
- bot_chatstate_t *cs;
- bot_consolemessage_t *firstmsg;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return 0;
- if ((firstmsg = cs->firstmessage))
- {
- cm->handle = firstmsg->handle;
- cm->time = firstmsg->time;
- cm->type = firstmsg->type;
- Q_strncpyz(cm->message, firstmsg->message,
- sizeof(cm->message));
-
- /* We omit setting the two pointers in cm because pointer
- * size in the VM differs between the size in the engine on
- * 64 bit machines, which would lead to a buffer overflow if
- * this functions is called from the VM. The pointers are
- * of no interest to functions calling
- * BotNextConsoleMessage anyways.
- */
-
- return cm->handle;
- } //end if
- return 0;
-} //end of the function BotConsoleMessage
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotNumConsoleMessages(int chatstate)
-{
- bot_chatstate_t *cs;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return 0;
- return cs->numconsolemessages;
-} //end of the function BotNumConsoleMessages
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int IsWhiteSpace(char c)
-{
- if ((c >= 'a' && c <= 'z')
- || (c >= 'A' && c <= 'Z')
- || (c >= '0' && c <= '9')
- || c == '(' || c == ')'
- || c == '?' || c == ':'
- || c == '\''|| c == '/'
- || c == ',' || c == '.'
- || c == '[' || c == ']'
- || c == '-' || c == '_'
- || c == '+' || c == '=') return qfalse;
- return qtrue;
-} //end of the function IsWhiteSpace
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotRemoveTildes(char *message)
-{
- int i;
-
- //remove all tildes from the chat message
- for (i = 0; message[i]; i++)
- {
- if (message[i] == '~')
- {
- memmove(&message[i], &message[i+1], strlen(&message[i+1])+1);
- } //end if
- } //end for
-} //end of the function BotRemoveTildes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void UnifyWhiteSpaces(char *string)
-{
- char *ptr, *oldptr;
-
- for (ptr = oldptr = string; *ptr; oldptr = ptr)
- {
- while(*ptr && IsWhiteSpace(*ptr)) ptr++;
- if (ptr > oldptr)
- {
- //if not at the start and not at the end of the string
- //write only one space
- if (oldptr > string && *ptr) *oldptr++ = ' ';
- //remove all other white spaces
- if (ptr > oldptr) memmove(oldptr, ptr, strlen(ptr)+1);
- } //end if
- while(*ptr && !IsWhiteSpace(*ptr)) ptr++;
- } //end while
-} //end of the function UnifyWhiteSpaces
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int StringContains(char *str1, char *str2, int casesensitive)
-{
- int len, i, j, index;
-
- if (str1 == NULL || str2 == NULL) return -1;
-
- len = strlen(str1) - strlen(str2);
- index = 0;
- for (i = 0; i <= len; i++, str1++, index++)
- {
- for (j = 0; str2[j]; j++)
- {
- if (casesensitive)
- {
- if (str1[j] != str2[j]) break;
- } //end if
- else
- {
- if (toupper(str1[j]) != toupper(str2[j])) break;
- } //end else
- } //end for
- if (!str2[j]) return index;
- } //end for
- return -1;
-} //end of the function StringContains
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *StringContainsWord(char *str1, char *str2, int casesensitive)
-{
- int len, i, j;
-
- len = strlen(str1) - strlen(str2);
- for (i = 0; i <= len; i++, str1++)
- {
- //if not at the start of the string
- if (i)
- {
- //skip to the start of the next word
- while(*str1 && *str1 != ' ' && *str1 != '.' && *str1 != ',' && *str1 != '!') str1++;
- if (!*str1) break;
- str1++;
- } //end for
- //compare the word
- for (j = 0; str2[j]; j++)
- {
- if (casesensitive)
- {
- if (str1[j] != str2[j]) break;
- } //end if
- else
- {
- if (toupper(str1[j]) != toupper(str2[j])) break;
- } //end else
- } //end for
- //if there was a word match
- if (!str2[j])
- {
- //if the first string has an end of word
- if (!str1[j] || str1[j] == ' ' || str1[j] == '.' || str1[j] == ',' || str1[j] == '!') return str1;
- } //end if
- } //end for
- return NULL;
-} //end of the function StringContainsWord
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void StringReplaceWords(char *string, char *synonym, char *replacement)
-{
- char *str, *str2;
-
- //find the synonym in the string
- str = StringContainsWord(string, synonym, qfalse);
- //if the synonym occured in the string
- while(str)
- {
- //if the synonym isn't part of the replacement which is already in the string
- //usefull for abreviations
- str2 = StringContainsWord(string, replacement, qfalse);
- while(str2)
- {
- if (str2 <= str && str < str2 + strlen(replacement)) break;
- str2 = StringContainsWord(str2+1, replacement, qfalse);
- } //end while
- if (!str2)
- {
- memmove(str + strlen(replacement), str+strlen(synonym), strlen(str+strlen(synonym))+1);
- //append the synonum replacement
- Com_Memcpy(str, replacement, strlen(replacement));
- } //end if
- //find the next synonym in the string
- str = StringContainsWord(str+strlen(replacement), synonym, qfalse);
- } //end if
-} //end of the function StringReplaceWords
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotDumpSynonymList(bot_synonymlist_t *synlist)
-{
- FILE *fp;
- bot_synonymlist_t *syn;
- bot_synonym_t *synonym;
-
- fp = Log_FilePointer();
- if (!fp) return;
- for (syn = synlist; syn; syn = syn->next)
- {
- fprintf(fp, "%ld : [", syn->context);
- for (synonym = syn->firstsynonym; synonym; synonym = synonym->next)
- {
- fprintf(fp, "(\"%s\", %1.2f)", synonym->string, synonym->weight);
- if (synonym->next) fprintf(fp, ", ");
- } //end for
- fprintf(fp, "]\n");
- } //end for
-} //end of the function BotDumpSynonymList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_synonymlist_t *BotLoadSynonyms(char *filename)
-{
- int pass, size, contextlevel, numsynonyms;
- unsigned long int context, contextstack[32];
- char *ptr = NULL;
- source_t *source;
- token_t token;
- bot_synonymlist_t *synlist, *lastsyn, *syn;
- bot_synonym_t *synonym, *lastsynonym;
-
- size = 0;
- synlist = NULL; //make compiler happy
- syn = NULL; //make compiler happy
- synonym = NULL; //make compiler happy
- //the synonyms are parsed in two phases
- for (pass = 0; pass < 2; pass++)
- {
- //
- if (pass && size) ptr = (char *) GetClearedHunkMemory(size);
- //
- PC_SetBaseFolder(BOTFILESBASEFOLDER);
- source = LoadSourceFile(filename);
- if (!source)
- {
- botimport.Print(PRT_ERROR, "counldn't load %s\n", filename);
- return NULL;
- } //end if
- //
- context = 0;
- contextlevel = 0;
- synlist = NULL; //list synonyms
- lastsyn = NULL; //last synonym in the list
- //
- while(PC_ReadToken(source, &token))
- {
- if (token.type == TT_NUMBER)
- {
- context |= token.intvalue;
- contextstack[contextlevel] = token.intvalue;
- contextlevel++;
- if (contextlevel >= 32)
- {
- SourceError(source, "more than 32 context levels");
- FreeSource(source);
- return NULL;
- } //end if
- if (!PC_ExpectTokenString(source, "{"))
- {
- FreeSource(source);
- return NULL;
- } //end if
- } //end if
- else if (token.type == TT_PUNCTUATION)
- {
- if (!strcmp(token.string, "}"))
- {
- contextlevel--;
- if (contextlevel < 0)
- {
- SourceError(source, "too many }");
- FreeSource(source);
- return NULL;
- } //end if
- context &= ~contextstack[contextlevel];
- } //end if
- else if (!strcmp(token.string, "["))
- {
- size += sizeof(bot_synonymlist_t);
- if (pass)
- {
- syn = (bot_synonymlist_t *) ptr;
- ptr += sizeof(bot_synonymlist_t);
- syn->context = context;
- syn->firstsynonym = NULL;
- syn->next = NULL;
- if (lastsyn) lastsyn->next = syn;
- else synlist = syn;
- lastsyn = syn;
- } //end if
- numsynonyms = 0;
- lastsynonym = NULL;
- while(1)
- {
- size_t len;
- if (!PC_ExpectTokenString(source, "(") ||
- !PC_ExpectTokenType(source, TT_STRING, 0, &token))
- {
- FreeSource(source);
- return NULL;
- } //end if
- StripDoubleQuotes(token.string);
- if (strlen(token.string) <= 0)
- {
- SourceError(source, "empty string", token.string);
- FreeSource(source);
- return NULL;
- } //end if
- len = strlen(token.string) + 1;
- len = PAD(len, sizeof(long));
- size += sizeof(bot_synonym_t) + len;
- if (pass)
- {
- synonym = (bot_synonym_t *) ptr;
- ptr += sizeof(bot_synonym_t);
- synonym->string = ptr;
- ptr += len;
- strcpy(synonym->string, token.string);
- //
- if (lastsynonym) lastsynonym->next = synonym;
- else syn->firstsynonym = synonym;
- lastsynonym = synonym;
- } //end if
- numsynonyms++;
- if (!PC_ExpectTokenString(source, ",") ||
- !PC_ExpectTokenType(source, TT_NUMBER, 0, &token) ||
- !PC_ExpectTokenString(source, ")"))
- {
- FreeSource(source);
- return NULL;
- } //end if
- if (pass)
- {
- synonym->weight = token.floatvalue;
- syn->totalweight += synonym->weight;
- } //end if
- if (PC_CheckTokenString(source, "]")) break;
- if (!PC_ExpectTokenString(source, ","))
- {
- FreeSource(source);
- return NULL;
- } //end if
- } //end while
- if (numsynonyms < 2)
- {
- SourceError(source, "synonym must have at least two entries\n");
- FreeSource(source);
- return NULL;
- } //end if
- } //end else
- else
- {
- SourceError(source, "unexpected %s", token.string);
- FreeSource(source);
- return NULL;
- } //end if
- } //end else if
- } //end while
- //
- FreeSource(source);
- //
- if (contextlevel > 0)
- {
- SourceError(source, "missing }");
- return NULL;
- } //end if
- } //end for
- botimport.Print(PRT_MESSAGE, "loaded %s\n", filename);
- //
- //BotDumpSynonymList(synlist);
- //
- return synlist;
-} //end of the function BotLoadSynonyms
-//===========================================================================
-// replace all the synonyms in the string
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotReplaceSynonyms(char *string, unsigned long int context)
-{
- bot_synonymlist_t *syn;
- bot_synonym_t *synonym;
-
- for (syn = synonyms; syn; syn = syn->next)
- {
- if (!(syn->context & context)) continue;
- for (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next)
- {
- StringReplaceWords(string, synonym->string, syn->firstsynonym->string);
- } //end for
- } //end for
-} //end of the function BotReplaceSynonyms
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotReplaceWeightedSynonyms(char *string, unsigned long int context)
-{
- bot_synonymlist_t *syn;
- bot_synonym_t *synonym, *replacement;
- float weight, curweight;
-
- for (syn = synonyms; syn; syn = syn->next)
- {
- if (!(syn->context & context)) continue;
- //choose a weighted random replacement synonym
- weight = random() * syn->totalweight;
- if (!weight) continue;
- curweight = 0;
- for (replacement = syn->firstsynonym; replacement; replacement = replacement->next)
- {
- curweight += replacement->weight;
- if (weight < curweight) break;
- } //end for
- if (!replacement) continue;
- //replace all synonyms with the replacement
- for (synonym = syn->firstsynonym; synonym; synonym = synonym->next)
- {
- if (synonym == replacement) continue;
- StringReplaceWords(string, synonym->string, replacement->string);
- } //end for
- } //end for
-} //end of the function BotReplaceWeightedSynonyms
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotReplaceReplySynonyms(char *string, unsigned long int context)
-{
- char *str1, *str2, *replacement;
- bot_synonymlist_t *syn;
- bot_synonym_t *synonym;
-
- for (str1 = string; *str1; )
- {
- //go to the start of the next word
- while(*str1 && *str1 <= ' ') str1++;
- if (!*str1) break;
- //
- for (syn = synonyms; syn; syn = syn->next)
- {
- if (!(syn->context & context)) continue;
- for (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next)
- {
- str2 = synonym->string;
- //if the synonym is not at the front of the string continue
- str2 = StringContainsWord(str1, synonym->string, qfalse);
- if (!str2 || str2 != str1) continue;
- //
- replacement = syn->firstsynonym->string;
- //if the replacement IS in front of the string continue
- str2 = StringContainsWord(str1, replacement, qfalse);
- if (str2 && str2 == str1) continue;
- //
- memmove(str1 + strlen(replacement), str1+strlen(synonym->string),
- strlen(str1+strlen(synonym->string)) + 1);
- //append the synonum replacement
- Com_Memcpy(str1, replacement, strlen(replacement));
- //
- break;
- } //end for
- //if a synonym has been replaced
- if (synonym) break;
- } //end for
- //skip over this word
- while(*str1 && *str1 > ' ') str1++;
- if (!*str1) break;
- } //end while
-} //end of the function BotReplaceReplySynonyms
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotLoadChatMessage(source_t *source, char *chatmessagestring)
-{
- char *ptr;
- token_t token;
-
- ptr = chatmessagestring;
- *ptr = 0;
- //
- while(1)
- {
- if (!PC_ExpectAnyToken(source, &token)) return qfalse;
- //fixed string
- if (token.type == TT_STRING)
- {
- StripDoubleQuotes(token.string);
- if (strlen(ptr) + strlen(token.string) + 1 > MAX_MESSAGE_SIZE)
- {
- SourceError(source, "chat message too long\n");
- return qfalse;
- } //end if
- strcat(ptr, token.string);
- } //end else if
- //variable string
- else if (token.type == TT_NUMBER && (token.subtype & TT_INTEGER))
- {
- if (strlen(ptr) + 7 > MAX_MESSAGE_SIZE)
- {
- SourceError(source, "chat message too long\n");
- return qfalse;
- } //end if
- sprintf(&ptr[strlen(ptr)], "%cv%ld%c", ESCAPE_CHAR, token.intvalue, ESCAPE_CHAR);
- } //end if
- //random string
- else if (token.type == TT_NAME)
- {
- if (strlen(ptr) + 7 > MAX_MESSAGE_SIZE)
- {
- SourceError(source, "chat message too long\n");
- return qfalse;
- } //end if
- sprintf(&ptr[strlen(ptr)], "%cr%s%c", ESCAPE_CHAR, token.string, ESCAPE_CHAR);
- } //end else if
- else
- {
- SourceError(source, "unknown message component %s\n", token.string);
- return qfalse;
- } //end else
- if (PC_CheckTokenString(source, ";")) break;
- if (!PC_ExpectTokenString(source, ",")) return qfalse;
- } //end while
- //
- return qtrue;
-} //end of the function BotLoadChatMessage
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotDumpRandomStringList(bot_randomlist_t *randomlist)
-{
- FILE *fp;
- bot_randomlist_t *random;
- bot_randomstring_t *rs;
-
- fp = Log_FilePointer();
- if (!fp) return;
- for (random = randomlist; random; random = random->next)
- {
- fprintf(fp, "%s = {", random->string);
- for (rs = random->firstrandomstring; rs; rs = rs->next)
- {
- fprintf(fp, "\"%s\"", rs->string);
- if (rs->next) fprintf(fp, ", ");
- else fprintf(fp, "}\n");
- } //end for
- } //end for
-} //end of the function BotDumpRandomStringList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_randomlist_t *BotLoadRandomStrings(char *filename)
-{
- int pass, size;
- char *ptr = NULL, chatmessagestring[MAX_MESSAGE_SIZE];
- source_t *source;
- token_t token;
- bot_randomlist_t *randomlist, *lastrandom, *random;
- bot_randomstring_t *randomstring;
-
-#ifdef DEBUG
- int starttime = Sys_MilliSeconds();
-#endif //DEBUG
-
- size = 0;
- randomlist = NULL;
- random = NULL;
- //the synonyms are parsed in two phases
- for (pass = 0; pass < 2; pass++)
- {
- //
- if (pass && size) ptr = (char *) GetClearedHunkMemory(size);
- //
- PC_SetBaseFolder(BOTFILESBASEFOLDER);
- source = LoadSourceFile(filename);
- if (!source)
- {
- botimport.Print(PRT_ERROR, "counldn't load %s\n", filename);
- return NULL;
- } //end if
- //
- randomlist = NULL; //list
- lastrandom = NULL; //last
- //
- while(PC_ReadToken(source, &token))
- {
- size_t len;
- if (token.type != TT_NAME)
- {
- SourceError(source, "unknown random %s", token.string);
- FreeSource(source);
- return NULL;
- } //end if
- len = strlen(token.string) + 1;
- len = PAD(len, sizeof(long));
- size += sizeof(bot_randomlist_t) + len;
- if (pass)
- {
- random = (bot_randomlist_t *) ptr;
- ptr += sizeof(bot_randomlist_t);
- random->string = ptr;
- ptr += len;
- strcpy(random->string, token.string);
- random->firstrandomstring = NULL;
- random->numstrings = 0;
- //
- if (lastrandom) lastrandom->next = random;
- else randomlist = random;
- lastrandom = random;
- } //end if
- if (!PC_ExpectTokenString(source, "=") ||
- !PC_ExpectTokenString(source, "{"))
- {
- FreeSource(source);
- return NULL;
- } //end if
- while(!PC_CheckTokenString(source, "}"))
- {
- size_t len;
- if (!BotLoadChatMessage(source, chatmessagestring))
- {
- FreeSource(source);
- return NULL;
- } //end if
- len = strlen(chatmessagestring) + 1;
- len = PAD(len, sizeof(long));
- size += sizeof(bot_randomstring_t) + len;
- if (pass)
- {
- randomstring = (bot_randomstring_t *) ptr;
- ptr += sizeof(bot_randomstring_t);
- randomstring->string = ptr;
- ptr += len;
- strcpy(randomstring->string, chatmessagestring);
- //
- random->numstrings++;
- randomstring->next = random->firstrandomstring;
- random->firstrandomstring = randomstring;
- } //end if
- } //end while
- } //end while
- //free the source after one pass
- FreeSource(source);
- } //end for
- botimport.Print(PRT_MESSAGE, "loaded %s\n", filename);
- //
-#ifdef DEBUG
- botimport.Print(PRT_MESSAGE, "random strings %d msec\n", Sys_MilliSeconds() - starttime);
- //BotDumpRandomStringList(randomlist);
-#endif //DEBUG
- //
- return randomlist;
-} //end of the function BotLoadRandomStrings
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *RandomString(char *name)
-{
- bot_randomlist_t *random;
- bot_randomstring_t *rs;
- int i;
-
- for (random = randomstrings; random; random = random->next)
- {
- if (!strcmp(random->string, name))
- {
- i = random() * random->numstrings;
- for (rs = random->firstrandomstring; rs; rs = rs->next)
- {
- if (--i < 0) break;
- } //end for
- if (rs)
- {
- return rs->string;
- } //end if
- } //end for
- } //end for
- return NULL;
-} //end of the function RandomString
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotDumpMatchTemplates(bot_matchtemplate_t *matches)
-{
- FILE *fp;
- bot_matchtemplate_t *mt;
- bot_matchpiece_t *mp;
- bot_matchstring_t *ms;
-
- fp = Log_FilePointer();
- if (!fp) return;
- for (mt = matches; mt; mt = mt->next)
- {
- fprintf(fp, "{ " );
- for (mp = mt->first; mp; mp = mp->next)
- {
- if (mp->type == MT_STRING)
- {
- for (ms = mp->firststring; ms; ms = ms->next)
- {
- fprintf(fp, "\"%s\"", ms->string);
- if (ms->next) fprintf(fp, "|");
- } //end for
- } //end if
- else if (mp->type == MT_VARIABLE)
- {
- fprintf(fp, "%d", mp->variable);
- } //end else if
- if (mp->next) fprintf(fp, ", ");
- } //end for
- fprintf(fp, " = (%d, %d);}\n", mt->type, mt->subtype);
- } //end for
-} //end of the function BotDumpMatchTemplates
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotFreeMatchPieces(bot_matchpiece_t *matchpieces)
-{
- bot_matchpiece_t *mp, *nextmp;
- bot_matchstring_t *ms, *nextms;
-
- for (mp = matchpieces; mp; mp = nextmp)
- {
- nextmp = mp->next;
- if (mp->type == MT_STRING)
- {
- for (ms = mp->firststring; ms; ms = nextms)
- {
- nextms = ms->next;
- FreeMemory(ms);
- } //end for
- } //end if
- FreeMemory(mp);
- } //end for
-} //end of the function BotFreeMatchPieces
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_matchpiece_t *BotLoadMatchPieces(source_t *source, char *endtoken)
-{
- int lastwasvariable, emptystring;
- token_t token;
- bot_matchpiece_t *matchpiece, *firstpiece, *lastpiece;
- bot_matchstring_t *matchstring, *lastmatchstring;
-
- firstpiece = NULL;
- lastpiece = NULL;
- //
- lastwasvariable = qfalse;
- //
- while(PC_ReadToken(source, &token))
- {
- if (token.type == TT_NUMBER && (token.subtype & TT_INTEGER))
- {
- if (token.intvalue < 0 || token.intvalue >= MAX_MATCHVARIABLES)
- {
- SourceError(source, "can't have more than %d match variables\n", MAX_MATCHVARIABLES);
- FreeSource(source);
- BotFreeMatchPieces(firstpiece);
- return NULL;
- } //end if
- if (lastwasvariable)
- {
- SourceError(source, "not allowed to have adjacent variables\n");
- FreeSource(source);
- BotFreeMatchPieces(firstpiece);
- return NULL;
- } //end if
- lastwasvariable = qtrue;
- //
- matchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t));
- matchpiece->type = MT_VARIABLE;
- matchpiece->variable = token.intvalue;
- matchpiece->next = NULL;
- if (lastpiece) lastpiece->next = matchpiece;
- else firstpiece = matchpiece;
- lastpiece = matchpiece;
- } //end if
- else if (token.type == TT_STRING)
- {
- //
- matchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t));
- matchpiece->firststring = NULL;
- matchpiece->type = MT_STRING;
- matchpiece->variable = 0;
- matchpiece->next = NULL;
- if (lastpiece) lastpiece->next = matchpiece;
- else firstpiece = matchpiece;
- lastpiece = matchpiece;
- //
- lastmatchstring = NULL;
- emptystring = qfalse;
- //
- do
- {
- if (matchpiece->firststring)
- {
- if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
- {
- FreeSource(source);
- BotFreeMatchPieces(firstpiece);
- return NULL;
- } //end if
- } //end if
- StripDoubleQuotes(token.string);
- matchstring = (bot_matchstring_t *) GetClearedHunkMemory(sizeof(bot_matchstring_t) + strlen(token.string) + 1);
- matchstring->string = (char *) matchstring + sizeof(bot_matchstring_t);
- strcpy(matchstring->string, token.string);
- if (!strlen(token.string)) emptystring = qtrue;
- matchstring->next = NULL;
- if (lastmatchstring) lastmatchstring->next = matchstring;
- else matchpiece->firststring = matchstring;
- lastmatchstring = matchstring;
- } while(PC_CheckTokenString(source, "|"));
- //if there was no empty string found
- if (!emptystring) lastwasvariable = qfalse;
- } //end if
- else
- {
- SourceError(source, "invalid token %s\n", token.string);
- FreeSource(source);
- BotFreeMatchPieces(firstpiece);
- return NULL;
- } //end else
- if (PC_CheckTokenString(source, endtoken)) break;
- if (!PC_ExpectTokenString(source, ","))
- {
- FreeSource(source);
- BotFreeMatchPieces(firstpiece);
- return NULL;
- } //end if
- } //end while
- return firstpiece;
-} //end of the function BotLoadMatchPieces
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotFreeMatchTemplates(bot_matchtemplate_t *mt)
-{
- bot_matchtemplate_t *nextmt;
-
- for (; mt; mt = nextmt)
- {
- nextmt = mt->next;
- BotFreeMatchPieces(mt->first);
- FreeMemory(mt);
- } //end for
-} //end of the function BotFreeMatchTemplates
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_matchtemplate_t *BotLoadMatchTemplates(char *matchfile)
-{
- source_t *source;
- token_t token;
- bot_matchtemplate_t *matchtemplate, *matches, *lastmatch;
- unsigned long int context;
-
- PC_SetBaseFolder(BOTFILESBASEFOLDER);
- source = LoadSourceFile(matchfile);
- if (!source)
- {
- botimport.Print(PRT_ERROR, "counldn't load %s\n", matchfile);
- return NULL;
- } //end if
- //
- matches = NULL; //list with matches
- lastmatch = NULL; //last match in the list
-
- while(PC_ReadToken(source, &token))
- {
- if (token.type != TT_NUMBER || !(token.subtype & TT_INTEGER))
- {
- SourceError(source, "expected integer, found %s\n", token.string);
- BotFreeMatchTemplates(matches);
- FreeSource(source);
- return NULL;
- } //end if
- //the context
- context = token.intvalue;
- //
- if (!PC_ExpectTokenString(source, "{"))
- {
- BotFreeMatchTemplates(matches);
- FreeSource(source);
- return NULL;
- } //end if
- //
- while(PC_ReadToken(source, &token))
- {
- if (!strcmp(token.string, "}")) break;
- //
- PC_UnreadLastToken(source);
- //
- matchtemplate = (bot_matchtemplate_t *) GetClearedHunkMemory(sizeof(bot_matchtemplate_t));
- matchtemplate->context = context;
- matchtemplate->next = NULL;
- //add the match template to the list
- if (lastmatch) lastmatch->next = matchtemplate;
- else matches = matchtemplate;
- lastmatch = matchtemplate;
- //load the match template
- matchtemplate->first = BotLoadMatchPieces(source, "=");
- if (!matchtemplate->first)
- {
- BotFreeMatchTemplates(matches);
- return NULL;
- } //end if
- //read the match type
- if (!PC_ExpectTokenString(source, "(") ||
- !PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token))
- {
- BotFreeMatchTemplates(matches);
- FreeSource(source);
- return NULL;
- } //end if
- matchtemplate->type = token.intvalue;
- //read the match subtype
- if (!PC_ExpectTokenString(source, ",") ||
- !PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token))
- {
- BotFreeMatchTemplates(matches);
- FreeSource(source);
- return NULL;
- } //end if
- matchtemplate->subtype = token.intvalue;
- //read trailing punctuations
- if (!PC_ExpectTokenString(source, ")") ||
- !PC_ExpectTokenString(source, ";"))
- {
- BotFreeMatchTemplates(matches);
- FreeSource(source);
- return NULL;
- } //end if
- } //end while
- } //end while
- //free the source
- FreeSource(source);
- botimport.Print(PRT_MESSAGE, "loaded %s\n", matchfile);
- //
- //BotDumpMatchTemplates(matches);
- //
- return matches;
-} //end of the function BotLoadMatchTemplates
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int StringsMatch(bot_matchpiece_t *pieces, bot_match_t *match)
-{
- int lastvariable, index;
- char *strptr, *newstrptr;
- bot_matchpiece_t *mp;
- bot_matchstring_t *ms;
-
- //no last variable
- lastvariable = -1;
- //pointer to the string to compare the match string with
- strptr = match->string;
- //Log_Write("match: %s", strptr);
- //compare the string with the current match string
- for (mp = pieces; mp; mp = mp->next)
- {
- //if it is a piece of string
- if (mp->type == MT_STRING)
- {
- newstrptr = NULL;
- for (ms = mp->firststring; ms; ms = ms->next)
- {
- if (!strlen(ms->string))
- {
- newstrptr = strptr;
- break;
- } //end if
- //Log_Write("MT_STRING: %s", mp->string);
- index = StringContains(strptr, ms->string, qfalse);
- if (index >= 0)
- {
- newstrptr = strptr + index;
- if (lastvariable >= 0)
- {
- match->variables[lastvariable].length =
- (newstrptr - match->string) - match->variables[lastvariable].offset;
- //newstrptr - match->variables[lastvariable].ptr;
- lastvariable = -1;
- break;
- } //end if
- else if (index == 0)
- {
- break;
- } //end else
- newstrptr = NULL;
- } //end if
- } //end for
- if (!newstrptr) return qfalse;
- strptr = newstrptr + strlen(ms->string);
- } //end if
- //if it is a variable piece of string
- else if (mp->type == MT_VARIABLE)
- {
- //Log_Write("MT_VARIABLE");
- match->variables[mp->variable].offset = strptr - match->string;
- lastvariable = mp->variable;
- } //end else if
- } //end for
- //if a match was found
- if (!mp && (lastvariable >= 0 || !strlen(strptr)))
- {
- //if the last piece was a variable string
- if (lastvariable >= 0)
- {
- assert( match->variables[lastvariable].offset >= 0 );
- match->variables[lastvariable].length =
- strlen(&match->string[ (int) match->variables[lastvariable].offset]);
- } //end if
- return qtrue;
- } //end if
- return qfalse;
-} //end of the function StringsMatch
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotFindMatch(char *str, bot_match_t *match, unsigned long int context)
-{
- int i;
- bot_matchtemplate_t *ms;
-
- strncpy(match->string, str, MAX_MESSAGE_SIZE);
- //remove any trailing enters
- while(strlen(match->string) &&
- match->string[strlen(match->string)-1] == '\n')
- {
- match->string[strlen(match->string)-1] = '\0';
- } //end while
- //compare the string with all the match strings
- for (ms = matchtemplates; ms; ms = ms->next)
- {
- if (!(ms->context & context)) continue;
- //reset the match variable offsets
- for (i = 0; i < MAX_MATCHVARIABLES; i++) match->variables[i].offset = -1;
- //
- if (StringsMatch(ms->first, match))
- {
- match->type = ms->type;
- match->subtype = ms->subtype;
- return qtrue;
- } //end if
- } //end for
- return qfalse;
-} //end of the function BotFindMatch
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotMatchVariable(bot_match_t *match, int variable, char *buf, int size)
-{
- if (variable < 0 || variable >= MAX_MATCHVARIABLES)
- {
- botimport.Print(PRT_FATAL, "BotMatchVariable: variable out of range\n");
- strcpy(buf, "");
- return;
- } //end if
-
- if (match->variables[variable].offset >= 0)
- {
- if (match->variables[variable].length < size)
- size = match->variables[variable].length+1;
- assert( match->variables[variable].offset >= 0 );
- strncpy(buf, &match->string[ (int) match->variables[variable].offset], size-1);
- buf[size-1] = '\0';
- } //end if
- else
- {
- strcpy(buf, "");
- } //end else
- return;
-} //end of the function BotMatchVariable
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_stringlist_t *BotFindStringInList(bot_stringlist_t *list, char *string)
-{
- bot_stringlist_t *s;
-
- for (s = list; s; s = s->next)
- {
- if (!strcmp(s->string, string)) return s;
- } //end for
- return NULL;
-} //end of the function BotFindStringInList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_stringlist_t *BotCheckChatMessageIntegrety(char *message, bot_stringlist_t *stringlist)
-{
- int i;
- char *msgptr;
- char temp[MAX_MESSAGE_SIZE];
- bot_stringlist_t *s;
-
- msgptr = message;
- //
- while(*msgptr)
- {
- if (*msgptr == ESCAPE_CHAR)
- {
- msgptr++;
- switch(*msgptr)
- {
- case 'v': //variable
- {
- //step over the 'v'
- msgptr++;
- while(*msgptr && *msgptr != ESCAPE_CHAR) msgptr++;
- //step over the trailing escape char
- if (*msgptr) msgptr++;
- break;
- } //end case
- case 'r': //random
- {
- //step over the 'r'
- msgptr++;
- for (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++)
- {
- temp[i] = *msgptr++;
- } //end while
- temp[i] = '\0';
- //step over the trailing escape char
- if (*msgptr) msgptr++;
- //find the random keyword
- if (!RandomString(temp))
- {
- if (!BotFindStringInList(stringlist, temp))
- {
- Log_Write("%s = {\"%s\"} //MISSING RANDOM\r\n", temp, temp);
- s = GetClearedMemory(sizeof(bot_stringlist_t) + strlen(temp) + 1);
- s->string = (char *) s + sizeof(bot_stringlist_t);
- strcpy(s->string, temp);
- s->next = stringlist;
- stringlist = s;
- } //end if
- } //end if
- break;
- } //end case
- default:
- {
- botimport.Print(PRT_FATAL, "BotCheckChatMessageIntegrety: message \"%s\" invalid escape char\n", message);
- break;
- } //end default
- } //end switch
- } //end if
- else
- {
- msgptr++;
- } //end else
- } //end while
- return stringlist;
-} //end of the function BotCheckChatMessageIntegrety
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotCheckInitialChatIntegrety(bot_chat_t *chat)
-{
- bot_chattype_t *t;
- bot_chatmessage_t *cm;
- bot_stringlist_t *stringlist, *s, *nexts;
-
- stringlist = NULL;
- for (t = chat->types; t; t = t->next)
- {
- for (cm = t->firstchatmessage; cm; cm = cm->next)
- {
- stringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist);
- } //end for
- } //end for
- for (s = stringlist; s; s = nexts)
- {
- nexts = s->next;
- FreeMemory(s);
- } //end for
-} //end of the function BotCheckInitialChatIntegrety
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotCheckReplyChatIntegrety(bot_replychat_t *replychat)
-{
- bot_replychat_t *rp;
- bot_chatmessage_t *cm;
- bot_stringlist_t *stringlist, *s, *nexts;
-
- stringlist = NULL;
- for (rp = replychat; rp; rp = rp->next)
- {
- for (cm = rp->firstchatmessage; cm; cm = cm->next)
- {
- stringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist);
- } //end for
- } //end for
- for (s = stringlist; s; s = nexts)
- {
- nexts = s->next;
- FreeMemory(s);
- } //end for
-} //end of the function BotCheckReplyChatIntegrety
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotDumpReplyChat(bot_replychat_t *replychat)
-{
- FILE *fp;
- bot_replychat_t *rp;
- bot_replychatkey_t *key;
- bot_chatmessage_t *cm;
- bot_matchpiece_t *mp;
-
- fp = Log_FilePointer();
- if (!fp) return;
- fprintf(fp, "BotDumpReplyChat:\n");
- for (rp = replychat; rp; rp = rp->next)
- {
- fprintf(fp, "[");
- for (key = rp->keys; key; key = key->next)
- {
- if (key->flags & RCKFL_AND) fprintf(fp, "&");
- else if (key->flags & RCKFL_NOT) fprintf(fp, "!");
- //
- if (key->flags & RCKFL_NAME) fprintf(fp, "name");
- else if (key->flags & RCKFL_GENDERFEMALE) fprintf(fp, "female");
- else if (key->flags & RCKFL_GENDERMALE) fprintf(fp, "male");
- else if (key->flags & RCKFL_GENDERLESS) fprintf(fp, "it");
- else if (key->flags & RCKFL_VARIABLES)
- {
- fprintf(fp, "(");
- for (mp = key->match; mp; mp = mp->next)
- {
- if (mp->type == MT_STRING) fprintf(fp, "\"%s\"", mp->firststring->string);
- else fprintf(fp, "%d", mp->variable);
- if (mp->next) fprintf(fp, ", ");
- } //end for
- fprintf(fp, ")");
- } //end if
- else if (key->flags & RCKFL_STRING)
- {
- fprintf(fp, "\"%s\"", key->string);
- } //end if
- if (key->next) fprintf(fp, ", ");
- else fprintf(fp, "] = %1.0f\n", rp->priority);
- } //end for
- fprintf(fp, "{\n");
- for (cm = rp->firstchatmessage; cm; cm = cm->next)
- {
- fprintf(fp, "\t\"%s\";\n", cm->chatmessage);
- } //end for
- fprintf(fp, "}\n");
- } //end for
-} //end of the function BotDumpReplyChat
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotFreeReplyChat(bot_replychat_t *replychat)
-{
- bot_replychat_t *rp, *nextrp;
- bot_replychatkey_t *key, *nextkey;
- bot_chatmessage_t *cm, *nextcm;
-
- for (rp = replychat; rp; rp = nextrp)
- {
- nextrp = rp->next;
- for (key = rp->keys; key; key = nextkey)
- {
- nextkey = key->next;
- if (key->match) BotFreeMatchPieces(key->match);
- if (key->string) FreeMemory(key->string);
- FreeMemory(key);
- } //end for
- for (cm = rp->firstchatmessage; cm; cm = nextcm)
- {
- nextcm = cm->next;
- FreeMemory(cm);
- } //end for
- FreeMemory(rp);
- } //end for
-} //end of the function BotFreeReplyChat
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotCheckValidReplyChatKeySet(source_t *source, bot_replychatkey_t *keys)
-{
- int allprefixed, hasvariableskey, hasstringkey;
- bot_matchpiece_t *m;
- bot_matchstring_t *ms;
- bot_replychatkey_t *key, *key2;
-
- //
- allprefixed = qtrue;
- hasvariableskey = hasstringkey = qfalse;
- for (key = keys; key; key = key->next)
- {
- if (!(key->flags & (RCKFL_AND|RCKFL_NOT)))
- {
- allprefixed = qfalse;
- if (key->flags & RCKFL_VARIABLES)
- {
- for (m = key->match; m; m = m->next)
- {
- if (m->type == MT_VARIABLE) hasvariableskey = qtrue;
- } //end for
- } //end if
- else if (key->flags & RCKFL_STRING)
- {
- hasstringkey = qtrue;
- } //end else if
- } //end if
- else if ((key->flags & RCKFL_AND) && (key->flags & RCKFL_STRING))
- {
- for (key2 = keys; key2; key2 = key2->next)
- {
- if (key2 == key) continue;
- if (key2->flags & RCKFL_NOT) continue;
- if (key2->flags & RCKFL_VARIABLES)
- {
- for (m = key2->match; m; m = m->next)
- {
- if (m->type == MT_STRING)
- {
- for (ms = m->firststring; ms; ms = ms->next)
- {
- if (StringContains(ms->string, key->string, qfalse) != -1)
- {
- break;
- } //end if
- } //end for
- if (ms) break;
- } //end if
- else if (m->type == MT_VARIABLE)
- {
- break;
- } //end if
- } //end for
- if (!m)
- {
- SourceWarning(source, "one of the match templates does not "
- "leave space for the key %s with the & prefix", key->string);
- } //end if
- } //end if
- } //end for
- } //end else
- if ((key->flags & RCKFL_NOT) && (key->flags & RCKFL_STRING))
- {
- for (key2 = keys; key2; key2 = key2->next)
- {
- if (key2 == key) continue;
- if (key2->flags & RCKFL_NOT) continue;
- if (key2->flags & RCKFL_STRING)
- {
- if (StringContains(key2->string, key->string, qfalse) != -1)
- {
- SourceWarning(source, "the key %s with prefix ! is inside the key %s", key->string, key2->string);
- } //end if
- } //end if
- else if (key2->flags & RCKFL_VARIABLES)
- {
- for (m = key2->match; m; m = m->next)
- {
- if (m->type == MT_STRING)
- {
- for (ms = m->firststring; ms; ms = ms->next)
- {
- if (StringContains(ms->string, key->string, qfalse) != -1)
- {
- SourceWarning(source, "the key %s with prefix ! is inside "
- "the match template string %s", key->string, ms->string);
- } //end if
- } //end for
- } //end if
- } //end for
- } //end else if
- } //end for
- } //end if
- } //end for
- if (allprefixed) SourceWarning(source, "all keys have a & or ! prefix");
- if (hasvariableskey && hasstringkey)
- {
- SourceWarning(source, "variables from the match template(s) could be "
- "invalid when outputting one of the chat messages");
- } //end if
-} //end of the function BotCheckValidReplyChatKeySet
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_replychat_t *BotLoadReplyChat(char *filename)
-{
- char chatmessagestring[MAX_MESSAGE_SIZE];
- char namebuffer[MAX_MESSAGE_SIZE];
- source_t *source;
- token_t token;
- bot_chatmessage_t *chatmessage = NULL;
- bot_replychat_t *replychat, *replychatlist;
- bot_replychatkey_t *key;
-
- PC_SetBaseFolder(BOTFILESBASEFOLDER);
- source = LoadSourceFile(filename);
- if (!source)
- {
- botimport.Print(PRT_ERROR, "counldn't load %s\n", filename);
- return NULL;
- } //end if
- //
- replychatlist = NULL;
- //
- while(PC_ReadToken(source, &token))
- {
- if (strcmp(token.string, "["))
- {
- SourceError(source, "expected [, found %s", token.string);
- BotFreeReplyChat(replychatlist);
- FreeSource(source);
- return NULL;
- } //end if
- //
- replychat = GetClearedHunkMemory(sizeof(bot_replychat_t));
- replychat->keys = NULL;
- replychat->next = replychatlist;
- replychatlist = replychat;
- //read the keys, there must be at least one key
- do
- {
- //allocate a key
- key = (bot_replychatkey_t *) GetClearedHunkMemory(sizeof(bot_replychatkey_t));
- key->flags = 0;
- key->string = NULL;
- key->match = NULL;
- key->next = replychat->keys;
- replychat->keys = key;
- //check for MUST BE PRESENT and MUST BE ABSENT keys
- if (PC_CheckTokenString(source, "&")) key->flags |= RCKFL_AND;
- else if (PC_CheckTokenString(source, "!")) key->flags |= RCKFL_NOT;
- //special keys
- if (PC_CheckTokenString(source, "name")) key->flags |= RCKFL_NAME;
- else if (PC_CheckTokenString(source, "female")) key->flags |= RCKFL_GENDERFEMALE;
- else if (PC_CheckTokenString(source, "male")) key->flags |= RCKFL_GENDERMALE;
- else if (PC_CheckTokenString(source, "it")) key->flags |= RCKFL_GENDERLESS;
- else if (PC_CheckTokenString(source, "(")) //match key
- {
- key->flags |= RCKFL_VARIABLES;
- key->match = BotLoadMatchPieces(source, ")");
- if (!key->match)
- {
- BotFreeReplyChat(replychatlist);
- return NULL;
- } //end if
- } //end else if
- else if (PC_CheckTokenString(source, "<")) //bot names
- {
- key->flags |= RCKFL_BOTNAMES;
- strcpy(namebuffer, "");
- do
- {
- if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
- {
- BotFreeReplyChat(replychatlist);
- FreeSource(source);
- return NULL;
- } //end if
- StripDoubleQuotes(token.string);
- if (strlen(namebuffer)) strcat(namebuffer, "\\");
- strcat(namebuffer, token.string);
- } while(PC_CheckTokenString(source, ","));
- if (!PC_ExpectTokenString(source, ">"))
- {
- BotFreeReplyChat(replychatlist);
- FreeSource(source);
- return NULL;
- } //end if
- key->string = (char *) GetClearedHunkMemory(strlen(namebuffer) + 1);
- strcpy(key->string, namebuffer);
- } //end else if
- else //normal string key
- {
- key->flags |= RCKFL_STRING;
- if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
- {
- BotFreeReplyChat(replychatlist);
- FreeSource(source);
- return NULL;
- } //end if
- StripDoubleQuotes(token.string);
- key->string = (char *) GetClearedHunkMemory(strlen(token.string) + 1);
- strcpy(key->string, token.string);
- } //end else
- //
- PC_CheckTokenString(source, ",");
- } while(!PC_CheckTokenString(source, "]"));
- //
- BotCheckValidReplyChatKeySet(source, replychat->keys);
- //read the = sign and the priority
- if (!PC_ExpectTokenString(source, "=") ||
- !PC_ExpectTokenType(source, TT_NUMBER, 0, &token))
- {
- BotFreeReplyChat(replychatlist);
- FreeSource(source);
- return NULL;
- } //end if
- replychat->priority = token.floatvalue;
- //read the leading {
- if (!PC_ExpectTokenString(source, "{"))
- {
- BotFreeReplyChat(replychatlist);
- FreeSource(source);
- return NULL;
- } //end if
- replychat->numchatmessages = 0;
- //while the trailing } is not found
- while(!PC_CheckTokenString(source, "}"))
- {
- if (!BotLoadChatMessage(source, chatmessagestring))
- {
- BotFreeReplyChat(replychatlist);
- FreeSource(source);
- return NULL;
- } //end if
- chatmessage = (bot_chatmessage_t *) GetClearedHunkMemory(sizeof(bot_chatmessage_t) + strlen(chatmessagestring) + 1);
- chatmessage->chatmessage = (char *) chatmessage + sizeof(bot_chatmessage_t);
- strcpy(chatmessage->chatmessage, chatmessagestring);
- chatmessage->time = -2*CHATMESSAGE_RECENTTIME;
- chatmessage->next = replychat->firstchatmessage;
- //add the chat message to the reply chat
- replychat->firstchatmessage = chatmessage;
- replychat->numchatmessages++;
- } //end while
- } //end while
- FreeSource(source);
- botimport.Print(PRT_MESSAGE, "loaded %s\n", filename);
- //
- //BotDumpReplyChat(replychatlist);
- if (botDeveloper)
- {
- BotCheckReplyChatIntegrety(replychatlist);
- } //end if
- //
- if (!replychatlist) botimport.Print(PRT_MESSAGE, "no rchats\n");
- //
- return replychatlist;
-} //end of the function BotLoadReplyChat
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotDumpInitialChat(bot_chat_t *chat)
-{
- bot_chattype_t *t;
- bot_chatmessage_t *m;
-
- Log_Write("{");
- for (t = chat->types; t; t = t->next)
- {
- Log_Write(" type \"%s\"", t->name);
- Log_Write(" {");
- Log_Write(" numchatmessages = %d", t->numchatmessages);
- for (m = t->firstchatmessage; m; m = m->next)
- {
- Log_Write(" \"%s\"", m->chatmessage);
- } //end for
- Log_Write(" }");
- } //end for
- Log_Write("}");
-} //end of the function BotDumpInitialChat
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_chat_t *BotLoadInitialChat(char *chatfile, char *chatname)
-{
- int pass, foundchat, indent, size;
- char *ptr = NULL;
- char chatmessagestring[MAX_MESSAGE_SIZE];
- source_t *source;
- token_t token;
- bot_chat_t *chat = NULL;
- bot_chattype_t *chattype = NULL;
- bot_chatmessage_t *chatmessage = NULL;
-#ifdef DEBUG
- int starttime;
-
- starttime = Sys_MilliSeconds();
-#endif //DEBUG
- //
- size = 0;
- foundchat = qfalse;
- //a bot chat is parsed in two phases
- for (pass = 0; pass < 2; pass++)
- {
- //allocate memory
- if (pass && size) ptr = (char *) GetClearedMemory(size);
- //load the source file
- PC_SetBaseFolder(BOTFILESBASEFOLDER);
- source = LoadSourceFile(chatfile);
- if (!source)
- {
- botimport.Print(PRT_ERROR, "counldn't load %s\n", chatfile);
- return NULL;
- } //end if
- //chat structure
- if (pass)
- {
- chat = (bot_chat_t *) ptr;
- ptr += sizeof(bot_chat_t);
- } //end if
- size = sizeof(bot_chat_t);
- //
- while(PC_ReadToken(source, &token))
- {
- if (!strcmp(token.string, "chat"))
- {
- if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
- {
- FreeSource(source);
- return NULL;
- } //end if
- StripDoubleQuotes(token.string);
- //after the chat name we expect a opening brace
- if (!PC_ExpectTokenString(source, "{"))
- {
- FreeSource(source);
- return NULL;
- } //end if
- //if the chat name is found
- if (!Q_stricmp(token.string, chatname))
- {
- foundchat = qtrue;
- //read the chat types
- while(1)
- {
- if (!PC_ExpectAnyToken(source, &token))
- {
- FreeSource(source);
- return NULL;
- } //end if
- if (!strcmp(token.string, "}")) break;
- if (strcmp(token.string, "type"))
- {
- SourceError(source, "expected type found %s\n", token.string);
- FreeSource(source);
- return NULL;
- } //end if
- //expect the chat type name
- if (!PC_ExpectTokenType(source, TT_STRING, 0, &token) ||
- !PC_ExpectTokenString(source, "{"))
- {
- FreeSource(source);
- return NULL;
- } //end if
- StripDoubleQuotes(token.string);
- if (pass)
- {
- chattype = (bot_chattype_t *) ptr;
- strncpy(chattype->name, token.string, MAX_CHATTYPE_NAME);
- chattype->firstchatmessage = NULL;
- //add the chat type to the chat
- chattype->next = chat->types;
- chat->types = chattype;
- //
- ptr += sizeof(bot_chattype_t);
- } //end if
- size += sizeof(bot_chattype_t);
- //read the chat messages
- while(!PC_CheckTokenString(source, "}"))
- {
- size_t len;
- if (!BotLoadChatMessage(source, chatmessagestring))
- {
- FreeSource(source);
- return NULL;
- } //end if
- len = strlen(chatmessagestring) + 1;
- len = PAD(len, sizeof(long));
- if (pass)
- {
- chatmessage = (bot_chatmessage_t *) ptr;
- chatmessage->time = -2*CHATMESSAGE_RECENTTIME;
- //put the chat message in the list
- chatmessage->next = chattype->firstchatmessage;
- chattype->firstchatmessage = chatmessage;
- //store the chat message
- ptr += sizeof(bot_chatmessage_t);
- chatmessage->chatmessage = ptr;
- strcpy(chatmessage->chatmessage, chatmessagestring);
- ptr += len;
- //the number of chat messages increased
- chattype->numchatmessages++;
- } //end if
- size += sizeof(bot_chatmessage_t) + len;
- } //end if
- } //end while
- } //end if
- else //skip the bot chat
- {
- indent = 1;
- while(indent)
- {
- if (!PC_ExpectAnyToken(source, &token))
- {
- FreeSource(source);
- return NULL;
- } //end if
- if (!strcmp(token.string, "{")) indent++;
- else if (!strcmp(token.string, "}")) indent--;
- } //end while
- } //end else
- } //end if
- else
- {
- SourceError(source, "unknown definition %s\n", token.string);
- FreeSource(source);
- return NULL;
- } //end else
- } //end while
- //free the source
- FreeSource(source);
- //if the requested character is not found
- if (!foundchat)
- {
- botimport.Print(PRT_ERROR, "couldn't find chat %s in %s\n", chatname, chatfile);
- return NULL;
- } //end if
- } //end for
- //
- botimport.Print(PRT_MESSAGE, "loaded %s from %s\n", chatname, chatfile);
- //
- //BotDumpInitialChat(chat);
- if (botDeveloper)
- {
- BotCheckInitialChatIntegrety(chat);
- } //end if
-#ifdef DEBUG
- botimport.Print(PRT_MESSAGE, "initial chats loaded in %d msec\n", Sys_MilliSeconds() - starttime);
-#endif //DEBUG
- //character was read succesfully
- return chat;
-} //end of the function BotLoadInitialChat
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotFreeChatFile(int chatstate)
-{
- bot_chatstate_t *cs;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return;
- if (cs->chat) FreeMemory(cs->chat);
- cs->chat = NULL;
-} //end of the function BotFreeChatFile
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotLoadChatFile(int chatstate, char *chatfile, char *chatname)
-{
- bot_chatstate_t *cs;
- int n, avail = 0;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return BLERR_CANNOTLOADICHAT;
- BotFreeChatFile(chatstate);
-
- if (!LibVarGetValue("bot_reloadcharacters"))
- {
- avail = -1;
- for( n = 0; n < MAX_CLIENTS; n++ ) {
- if( !ichatdata[n] ) {
- if( avail == -1 ) {
- avail = n;
- }
- continue;
- }
- if( strcmp( chatfile, ichatdata[n]->filename ) != 0 ) {
- continue;
- }
- if( strcmp( chatname, ichatdata[n]->chatname ) != 0 ) {
- continue;
- }
- cs->chat = ichatdata[n]->chat;
- // botimport.Print( PRT_MESSAGE, "retained %s from %s\n", chatname, chatfile );
- return BLERR_NOERROR;
- }
-
- if( avail == -1 ) {
- botimport.Print(PRT_FATAL, "ichatdata table full; couldn't load chat %s from %s\n", chatname, chatfile);
- return BLERR_CANNOTLOADICHAT;
- }
- }
-
- cs->chat = BotLoadInitialChat(chatfile, chatname);
- if (!cs->chat)
- {
- botimport.Print(PRT_FATAL, "couldn't load chat %s from %s\n", chatname, chatfile);
- return BLERR_CANNOTLOADICHAT;
- } //end if
- if (!LibVarGetValue("bot_reloadcharacters"))
- {
- ichatdata[avail] = GetClearedMemory( sizeof(bot_ichatdata_t) );
- ichatdata[avail]->chat = cs->chat;
- Q_strncpyz( ichatdata[avail]->chatname, chatname, sizeof(ichatdata[avail]->chatname) );
- Q_strncpyz( ichatdata[avail]->filename, chatfile, sizeof(ichatdata[avail]->filename) );
- } //end if
-
- return BLERR_NOERROR;
-} //end of the function BotLoadChatFile
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotExpandChatMessage(char *outmessage, char *message, unsigned long mcontext,
- bot_match_t *match, unsigned long vcontext, int reply)
-{
- int num, len, i, expansion;
- char *outputbuf, *ptr, *msgptr;
- char temp[MAX_MESSAGE_SIZE];
-
- expansion = qfalse;
- msgptr = message;
- outputbuf = outmessage;
- len = 0;
- //
- while(*msgptr)
- {
- if (*msgptr == ESCAPE_CHAR)
- {
- msgptr++;
- switch(*msgptr)
- {
- case 'v': //variable
- {
- msgptr++;
- num = 0;
- while(*msgptr && *msgptr != ESCAPE_CHAR)
- {
- num = num * 10 + (*msgptr++) - '0';
- } //end while
- //step over the trailing escape char
- if (*msgptr) msgptr++;
- if (num > MAX_MATCHVARIABLES)
- {
- botimport.Print(PRT_ERROR, "BotConstructChat: message %s variable %d out of range\n", message, num);
- return qfalse;
- } //end if
- if (match->variables[num].offset >= 0)
- {
- assert( match->variables[num].offset >= 0 );
- ptr = &match->string[ (int) match->variables[num].offset];
- for (i = 0; i < match->variables[num].length; i++)
- {
- temp[i] = ptr[i];
- } //end for
- temp[i] = 0;
- //if it's a reply message
- if (reply)
- {
- //replace the reply synonyms in the variables
- BotReplaceReplySynonyms(temp, vcontext);
- } //end if
- else
- {
- //replace synonyms in the variable context
- BotReplaceSynonyms(temp, vcontext);
- } //end else
- //
- if (len + strlen(temp) >= MAX_MESSAGE_SIZE)
- {
- botimport.Print(PRT_ERROR, "BotConstructChat: message %s too long\n", message);
- return qfalse;
- } //end if
- strcpy(&outputbuf[len], temp);
- len += strlen(temp);
- } //end if
- break;
- } //end case
- case 'r': //random
- {
- msgptr++;
- for (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++)
- {
- temp[i] = *msgptr++;
- } //end while
- temp[i] = '\0';
- //step over the trailing escape char
- if (*msgptr) msgptr++;
- //find the random keyword
- ptr = RandomString(temp);
- if (!ptr)
- {
- botimport.Print(PRT_ERROR, "BotConstructChat: unknown random string %s\n", temp);
- return qfalse;
- } //end if
- if (len + strlen(ptr) >= MAX_MESSAGE_SIZE)
- {
- botimport.Print(PRT_ERROR, "BotConstructChat: message \"%s\" too long\n", message);
- return qfalse;
- } //end if
- strcpy(&outputbuf[len], ptr);
- len += strlen(ptr);
- expansion = qtrue;
- break;
- } //end case
- default:
- {
- botimport.Print(PRT_FATAL, "BotConstructChat: message \"%s\" invalid escape char\n", message);
- break;
- } //end default
- } //end switch
- } //end if
- else
- {
- outputbuf[len++] = *msgptr++;
- if (len >= MAX_MESSAGE_SIZE)
- {
- botimport.Print(PRT_ERROR, "BotConstructChat: message \"%s\" too long\n", message);
- break;
- } //end if
- } //end else
- } //end while
- outputbuf[len] = '\0';
- //replace synonyms weighted in the message context
- BotReplaceWeightedSynonyms(outputbuf, mcontext);
- //return true if a random was expanded
- return expansion;
-} //end of the function BotExpandChatMessage
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotConstructChatMessage(bot_chatstate_t *chatstate, char *message, unsigned long mcontext,
- bot_match_t *match, unsigned long vcontext, int reply)
-{
- int i;
- char srcmessage[MAX_MESSAGE_SIZE];
-
- strcpy(srcmessage, message);
- for (i = 0; i < 10; i++)
- {
- if (!BotExpandChatMessage(chatstate->chatmessage, srcmessage, mcontext, match, vcontext, reply))
- {
- break;
- } //end if
- strcpy(srcmessage, chatstate->chatmessage);
- } //end for
- if (i >= 10)
- {
- botimport.Print(PRT_WARNING, "too many expansions in chat message\n");
- botimport.Print(PRT_WARNING, "%s\n", chatstate->chatmessage);
- } //end if
-} //end of the function BotConstructChatMessage
-//===========================================================================
-// randomly chooses one of the chat message of the given type
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *BotChooseInitialChatMessage(bot_chatstate_t *cs, char *type)
-{
- int n, numchatmessages;
- float besttime;
- bot_chattype_t *t;
- bot_chatmessage_t *m, *bestchatmessage;
- bot_chat_t *chat;
-
- chat = cs->chat;
- for (t = chat->types; t; t = t->next)
- {
- if (!Q_stricmp(t->name, type))
- {
- numchatmessages = 0;
- for (m = t->firstchatmessage; m; m = m->next)
- {
- if (m->time > AAS_Time()) continue;
- numchatmessages++;
- } //end if
- //if all chat messages have been used recently
- if (numchatmessages <= 0)
- {
- besttime = 0;
- bestchatmessage = NULL;
- for (m = t->firstchatmessage; m; m = m->next)
- {
- if (!besttime || m->time < besttime)
- {
- bestchatmessage = m;
- besttime = m->time;
- } //end if
- } //end for
- if (bestchatmessage) return bestchatmessage->chatmessage;
- } //end if
- else //choose a chat message randomly
- {
- n = random() * numchatmessages;
- for (m = t->firstchatmessage; m; m = m->next)
- {
- if (m->time > AAS_Time()) continue;
- if (--n < 0)
- {
- m->time = AAS_Time() + CHATMESSAGE_RECENTTIME;
- return m->chatmessage;
- } //end if
- } //end for
- } //end else
- return NULL;
- } //end if
- } //end for
- return NULL;
-} //end of the function BotChooseInitialChatMessage
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotNumInitialChats(int chatstate, char *type)
-{
- bot_chatstate_t *cs;
- bot_chattype_t *t;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return 0;
-
- for (t = cs->chat->types; t; t = t->next)
- {
- if (!Q_stricmp(t->name, type))
- {
- if (LibVarGetValue("bot_testichat")) {
- botimport.Print(PRT_MESSAGE, "%s has %d chat lines\n", type, t->numchatmessages);
- botimport.Print(PRT_MESSAGE, "-------------------\n");
- }
- return t->numchatmessages;
- } //end if
- } //end for
- return 0;
-} //end of the function BotNumInitialChats
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7)
-{
- char *message;
- int index;
- bot_match_t match;
- bot_chatstate_t *cs;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return;
- //if no chat file is loaded
- if (!cs->chat) return;
- //choose a chat message randomly of the given type
- message = BotChooseInitialChatMessage(cs, type);
- //if there's no message of the given type
- if (!message)
- {
-#ifdef DEBUG
- botimport.Print(PRT_MESSAGE, "no chat messages of type %s\n", type);
-#endif //DEBUG
- return;
- } //end if
- //
- Com_Memset(&match, 0, sizeof(match));
- index = 0;
- if( var0 ) {
- strcat(match.string, var0);
- match.variables[0].offset = index;
- match.variables[0].length = strlen(var0);
- index += strlen(var0);
- }
- if( var1 ) {
- strcat(match.string, var1);
- match.variables[1].offset = index;
- match.variables[1].length = strlen(var1);
- index += strlen(var1);
- }
- if( var2 ) {
- strcat(match.string, var2);
- match.variables[2].offset = index;
- match.variables[2].length = strlen(var2);
- index += strlen(var2);
- }
- if( var3 ) {
- strcat(match.string, var3);
- match.variables[3].offset = index;
- match.variables[3].length = strlen(var3);
- index += strlen(var3);
- }
- if( var4 ) {
- strcat(match.string, var4);
- match.variables[4].offset = index;
- match.variables[4].length = strlen(var4);
- index += strlen(var4);
- }
- if( var5 ) {
- strcat(match.string, var5);
- match.variables[5].offset = index;
- match.variables[5].length = strlen(var5);
- index += strlen(var5);
- }
- if( var6 ) {
- strcat(match.string, var6);
- match.variables[6].offset = index;
- match.variables[6].length = strlen(var6);
- index += strlen(var6);
- }
- if( var7 ) {
- strcat(match.string, var7);
- match.variables[7].offset = index;
- match.variables[7].length = strlen(var7);
- index += strlen(var7);
- }
- //
- BotConstructChatMessage(cs, message, mcontext, &match, 0, qfalse);
-} //end of the function BotInitialChat
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotPrintReplyChatKeys(bot_replychat_t *replychat)
-{
- bot_replychatkey_t *key;
- bot_matchpiece_t *mp;
-
- botimport.Print(PRT_MESSAGE, "[");
- for (key = replychat->keys; key; key = key->next)
- {
- if (key->flags & RCKFL_AND) botimport.Print(PRT_MESSAGE, "&");
- else if (key->flags & RCKFL_NOT) botimport.Print(PRT_MESSAGE, "!");
- //
- if (key->flags & RCKFL_NAME) botimport.Print(PRT_MESSAGE, "name");
- else if (key->flags & RCKFL_GENDERFEMALE) botimport.Print(PRT_MESSAGE, "female");
- else if (key->flags & RCKFL_GENDERMALE) botimport.Print(PRT_MESSAGE, "male");
- else if (key->flags & RCKFL_GENDERLESS) botimport.Print(PRT_MESSAGE, "it");
- else if (key->flags & RCKFL_VARIABLES)
- {
- botimport.Print(PRT_MESSAGE, "(");
- for (mp = key->match; mp; mp = mp->next)
- {
- if (mp->type == MT_STRING) botimport.Print(PRT_MESSAGE, "\"%s\"", mp->firststring->string);
- else botimport.Print(PRT_MESSAGE, "%d", mp->variable);
- if (mp->next) botimport.Print(PRT_MESSAGE, ", ");
- } //end for
- botimport.Print(PRT_MESSAGE, ")");
- } //end if
- else if (key->flags & RCKFL_STRING)
- {
- botimport.Print(PRT_MESSAGE, "\"%s\"", key->string);
- } //end if
- if (key->next) botimport.Print(PRT_MESSAGE, ", ");
- else botimport.Print(PRT_MESSAGE, "] = %1.0f\n", replychat->priority);
- } //end for
- botimport.Print(PRT_MESSAGE, "{\n");
-} //end of the function BotPrintReplyChatKeys
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7)
-{
- bot_replychat_t *rchat, *bestrchat;
- bot_replychatkey_t *key;
- bot_chatmessage_t *m, *bestchatmessage;
- bot_match_t match, bestmatch;
- int bestpriority, num, found, res, numchatmessages, index;
- bot_chatstate_t *cs;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return qfalse;
- Com_Memset(&match, 0, sizeof(bot_match_t));
- strcpy(match.string, message);
- bestpriority = -1;
- bestchatmessage = NULL;
- bestrchat = NULL;
- //go through all the reply chats
- for (rchat = replychats; rchat; rchat = rchat->next)
- {
- found = qfalse;
- for (key = rchat->keys; key; key = key->next)
- {
- res = qfalse;
- //get the match result
- if (key->flags & RCKFL_NAME) res = (StringContains(message, cs->name, qfalse) != -1);
- else if (key->flags & RCKFL_BOTNAMES) res = (StringContains(key->string, cs->name, qfalse) != -1);
- else if (key->flags & RCKFL_GENDERFEMALE) res = (cs->gender == CHAT_GENDERFEMALE);
- else if (key->flags & RCKFL_GENDERMALE) res = (cs->gender == CHAT_GENDERMALE);
- else if (key->flags & RCKFL_GENDERLESS) res = (cs->gender == CHAT_GENDERLESS);
- else if (key->flags & RCKFL_VARIABLES) res = StringsMatch(key->match, &match);
- else if (key->flags & RCKFL_STRING) res = (StringContainsWord(message, key->string, qfalse) != NULL);
- //if the key must be present
- if (key->flags & RCKFL_AND)
- {
- if (!res)
- {
- found = qfalse;
- break;
- } //end if
- } //end else if
- //if the key must be absent
- else if (key->flags & RCKFL_NOT)
- {
- if (res)
- {
- found = qfalse;
- break;
- } //end if
- } //end if
- else if (res)
- {
- found = qtrue;
- } //end else
- } //end for
- //
- if (found)
- {
- if (rchat->priority > bestpriority)
- {
- numchatmessages = 0;
- for (m = rchat->firstchatmessage; m; m = m->next)
- {
- if (m->time > AAS_Time()) continue;
- numchatmessages++;
- } //end if
- num = random() * numchatmessages;
- for (m = rchat->firstchatmessage; m; m = m->next)
- {
- if (--num < 0) break;
- if (m->time > AAS_Time()) continue;
- } //end for
- //if the reply chat has a message
- if (m)
- {
- Com_Memcpy(&bestmatch, &match, sizeof(bot_match_t));
- bestchatmessage = m;
- bestrchat = rchat;
- bestpriority = rchat->priority;
- } //end if
- } //end if
- } //end if
- } //end for
- if (bestchatmessage)
- {
- index = strlen(bestmatch.string);
- if( var0 ) {
- strcat(bestmatch.string, var0);
- bestmatch.variables[0].offset = index;
- bestmatch.variables[0].length = strlen(var0);
- index += strlen(var0);
- }
- if( var1 ) {
- strcat(bestmatch.string, var1);
- bestmatch.variables[1].offset = index;
- bestmatch.variables[1].length = strlen(var1);
- index += strlen(var1);
- }
- if( var2 ) {
- strcat(bestmatch.string, var2);
- bestmatch.variables[2].offset = index;
- bestmatch.variables[2].length = strlen(var2);
- index += strlen(var2);
- }
- if( var3 ) {
- strcat(bestmatch.string, var3);
- bestmatch.variables[3].offset = index;
- bestmatch.variables[3].length = strlen(var3);
- index += strlen(var3);
- }
- if( var4 ) {
- strcat(bestmatch.string, var4);
- bestmatch.variables[4].offset = index;
- bestmatch.variables[4].length = strlen(var4);
- index += strlen(var4);
- }
- if( var5 ) {
- strcat(bestmatch.string, var5);
- bestmatch.variables[5].offset = index;
- bestmatch.variables[5].length = strlen(var5);
- index += strlen(var5);
- }
- if( var6 ) {
- strcat(bestmatch.string, var6);
- bestmatch.variables[6].offset = index;
- bestmatch.variables[6].length = strlen(var6);
- index += strlen(var6);
- }
- if( var7 ) {
- strcat(bestmatch.string, var7);
- bestmatch.variables[7].offset = index;
- bestmatch.variables[7].length = strlen(var7);
- index += strlen(var7);
- }
- if (LibVarGetValue("bot_testrchat"))
- {
- for (m = bestrchat->firstchatmessage; m; m = m->next)
- {
- BotConstructChatMessage(cs, m->chatmessage, mcontext, &bestmatch, vcontext, qtrue);
- BotRemoveTildes(cs->chatmessage);
- botimport.Print(PRT_MESSAGE, "%s\n", cs->chatmessage);
- } //end if
- } //end if
- else
- {
- bestchatmessage->time = AAS_Time() + CHATMESSAGE_RECENTTIME;
- BotConstructChatMessage(cs, bestchatmessage->chatmessage, mcontext, &bestmatch, vcontext, qtrue);
- } //end else
- return qtrue;
- } //end if
- return qfalse;
-} //end of the function BotReplyChat
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotChatLength(int chatstate)
-{
- bot_chatstate_t *cs;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return 0;
- return strlen(cs->chatmessage);
-} //end of the function BotChatLength
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotEnterChat(int chatstate, int clientto, int sendto)
-{
- bot_chatstate_t *cs;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return;
-
- if (strlen(cs->chatmessage))
- {
- BotRemoveTildes(cs->chatmessage);
- if (LibVarGetValue("bot_testichat")) {
- botimport.Print(PRT_MESSAGE, "%s\n", cs->chatmessage);
- }
- else {
- switch(sendto) {
- case CHAT_TEAM:
- EA_Command(cs->client, va("say_team %s", cs->chatmessage));
- break;
- case CHAT_TELL:
- EA_Command(cs->client, va("tell %d %s", clientto, cs->chatmessage));
- break;
- default: //CHAT_ALL
- EA_Command(cs->client, va("say %s", cs->chatmessage));
- break;
- }
- }
- //clear the chat message from the state
- strcpy(cs->chatmessage, "");
- } //end if
-} //end of the function BotEnterChat
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotGetChatMessage(int chatstate, char *buf, int size)
-{
- bot_chatstate_t *cs;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return;
-
- BotRemoveTildes(cs->chatmessage);
- strncpy(buf, cs->chatmessage, size-1);
- buf[size-1] = '\0';
- //clear the chat message from the state
- strcpy(cs->chatmessage, "");
-} //end of the function BotGetChatMessage
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotSetChatGender(int chatstate, int gender)
-{
- bot_chatstate_t *cs;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return;
- switch(gender)
- {
- case CHAT_GENDERFEMALE: cs->gender = CHAT_GENDERFEMALE; break;
- case CHAT_GENDERMALE: cs->gender = CHAT_GENDERMALE; break;
- default: cs->gender = CHAT_GENDERLESS; break;
- } //end switch
-} //end of the function BotSetChatGender
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotSetChatName(int chatstate, char *name, int client)
-{
- bot_chatstate_t *cs;
-
- cs = BotChatStateFromHandle(chatstate);
- if (!cs) return;
- cs->client = client;
- Com_Memset(cs->name, 0, sizeof(cs->name));
- strncpy(cs->name, name, sizeof(cs->name));
- cs->name[sizeof(cs->name)-1] = '\0';
-} //end of the function BotSetChatName
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotResetChatAI(void)
-{
- bot_replychat_t *rchat;
- bot_chatmessage_t *m;
-
- for (rchat = replychats; rchat; rchat = rchat->next)
- {
- for (m = rchat->firstchatmessage; m; m = m->next)
- {
- m->time = 0;
- } //end for
- } //end for
-} //end of the function BotResetChatAI
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-int BotAllocChatState(void)
-{
- int i;
-
- for (i = 1; i <= MAX_CLIENTS; i++)
- {
- if (!botchatstates[i])
- {
- botchatstates[i] = GetClearedMemory(sizeof(bot_chatstate_t));
- return i;
- } //end if
- } //end for
- return 0;
-} //end of the function BotAllocChatState
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-void BotFreeChatState(int handle)
-{
- bot_chatstate_t *cs;
- bot_consolemessage_t m;
- int h;
-
- if (handle <= 0 || handle > MAX_CLIENTS)
- {
- botimport.Print(PRT_FATAL, "chat state handle %d out of range\n", handle);
- return;
- } //end if
- if (!botchatstates[handle])
- {
- botimport.Print(PRT_FATAL, "invalid chat state %d\n", handle);
- return;
- } //end if
- cs = botchatstates[handle];
- if (LibVarGetValue("bot_reloadcharacters"))
- {
- BotFreeChatFile(handle);
- } //end if
- //free all the console messages left in the chat state
- for (h = BotNextConsoleMessage(handle, &m); h; h = BotNextConsoleMessage(handle, &m))
- {
- //remove the console message
- BotRemoveConsoleMessage(handle, h);
- } //end for
- FreeMemory(botchatstates[handle]);
- botchatstates[handle] = NULL;
-} //end of the function BotFreeChatState
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotSetupChatAI(void)
-{
- char *file;
-
-#ifdef DEBUG
- int starttime = Sys_MilliSeconds();
-#endif //DEBUG
-
- file = LibVarString("synfile", "syn.c");
- synonyms = BotLoadSynonyms(file);
- file = LibVarString("rndfile", "rnd.c");
- randomstrings = BotLoadRandomStrings(file);
- file = LibVarString("matchfile", "match.c");
- matchtemplates = BotLoadMatchTemplates(file);
- //
- if (!LibVarValue("nochat", "0"))
- {
- file = LibVarString("rchatfile", "rchat.c");
- replychats = BotLoadReplyChat(file);
- } //end if
-
- InitConsoleMessageHeap();
-
-#ifdef DEBUG
- botimport.Print(PRT_MESSAGE, "setup chat AI %d msec\n", Sys_MilliSeconds() - starttime);
-#endif //DEBUG
- return BLERR_NOERROR;
-} //end of the function BotSetupChatAI
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotShutdownChatAI(void)
-{
- int i;
-
- //free all remaining chat states
- for(i = 0; i < MAX_CLIENTS; i++)
- {
- if (botchatstates[i])
- {
- BotFreeChatState(i);
- } //end if
- } //end for
- //free all cached chats
- for(i = 0; i < MAX_CLIENTS; i++)
- {
- if (ichatdata[i])
- {
- FreeMemory(ichatdata[i]->chat);
- FreeMemory(ichatdata[i]);
- ichatdata[i] = NULL;
- } //end if
- } //end for
- if (consolemessageheap) FreeMemory(consolemessageheap);
- consolemessageheap = NULL;
- if (matchtemplates) BotFreeMatchTemplates(matchtemplates);
- matchtemplates = NULL;
- if (randomstrings) FreeMemory(randomstrings);
- randomstrings = NULL;
- if (synonyms) FreeMemory(synonyms);
- synonyms = NULL;
- if (replychats) BotFreeReplyChat(replychats);
- replychats = NULL;
-} //end of the function BotShutdownChatAI
diff --git a/engine/code/botlib/be_ai_gen.c b/engine/code/botlib/be_ai_gen.c
deleted file mode 100644
index d7bb221..0000000
--- a/engine/code/botlib/be_ai_gen.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_ai_gen.c
- *
- * desc: genetic selection
- *
- * $Archive: /MissionPack/code/botlib/be_ai_gen.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_log.h"
-#include "l_utils.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-#include "be_ai_gen.h"
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int GeneticSelection(int numranks, float *rankings)
-{
- float sum, select;
- int i, index;
-
- sum = 0;
- for (i = 0; i < numranks; i++)
- {
- if (rankings[i] < 0) continue;
- sum += rankings[i];
- } //end for
- if (sum > 0)
- {
- //select a bot where the ones with the higest rankings have
- //the highest chance of being selected
- select = random() * sum;
- for (i = 0; i < numranks; i++)
- {
- if (rankings[i] < 0) continue;
- sum -= rankings[i];
- if (sum <= 0) return i;
- } //end for
- } //end if
- //select a bot randomly
- index = random() * numranks;
- for (i = 0; i < numranks; i++)
- {
- if (rankings[index] >= 0) return index;
- index = (index + 1) % numranks;
- } //end for
- return 0;
-} //end of the function GeneticSelection
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child)
-{
- float rankings[256], max;
- int i;
-
- if (numranks > 256)
- {
- botimport.Print(PRT_WARNING, "GeneticParentsAndChildSelection: too many bots\n");
- *parent1 = *parent2 = *child = 0;
- return qfalse;
- } //end if
- for (max = 0, i = 0; i < numranks; i++)
- {
- if (ranks[i] < 0) continue;
- max++;
- } //end for
- if (max < 3)
- {
- botimport.Print(PRT_WARNING, "GeneticParentsAndChildSelection: too few valid bots\n");
- *parent1 = *parent2 = *child = 0;
- return qfalse;
- } //end if
- Com_Memcpy(rankings, ranks, sizeof(float) * numranks);
- //select first parent
- *parent1 = GeneticSelection(numranks, rankings);
- rankings[*parent1] = -1;
- //select second parent
- *parent2 = GeneticSelection(numranks, rankings);
- rankings[*parent2] = -1;
- //reverse the rankings
- max = 0;
- for (i = 0; i < numranks; i++)
- {
- if (rankings[i] < 0) continue;
- if (rankings[i] > max) max = rankings[i];
- } //end for
- for (i = 0; i < numranks; i++)
- {
- if (rankings[i] < 0) continue;
- rankings[i] = max - rankings[i];
- } //end for
- //select child
- *child = GeneticSelection(numranks, rankings);
- return qtrue;
-} //end of the function GeneticParentsAndChildSelection
diff --git a/engine/code/botlib/be_ai_goal.c b/engine/code/botlib/be_ai_goal.c
deleted file mode 100644
index 8fb7de9..0000000
--- a/engine/code/botlib/be_ai_goal.c
+++ /dev/null
@@ -1,1821 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_ai_goal.c
- *
- * desc: goal AI
- *
- * $Archive: /MissionPack/code/botlib/be_ai_goal.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_utils.h"
-#include "l_libvar.h"
-#include "l_memory.h"
-#include "l_log.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-#include "be_ai_weight.h"
-#include "be_ai_goal.h"
-#include "be_ai_move.h"
-
-//#define DEBUG_AI_GOAL
-#ifdef RANDOMIZE
-#define UNDECIDEDFUZZY
-#endif //RANDOMIZE
-#define DROPPEDWEIGHT
-//minimum avoid goal time
-#define AVOID_MINIMUM_TIME 10
-//default avoid goal time
-#define AVOID_DEFAULT_TIME 30
-//avoid dropped goal time
-#define AVOID_DROPPED_TIME 10
-//
-#define TRAVELTIME_SCALE 0.01
-//item flags
-#define IFL_NOTFREE 1 //not in free for all
-#define IFL_NOTTEAM 2 //not in team play
-#define IFL_NOTSINGLE 4 //not in single player
-#define IFL_NOTBOT 8 //bot should never go for this
-#define IFL_ROAM 16 //bot roam goal
-
-//location in the map "target_location"
-typedef struct maplocation_s
-{
- vec3_t origin;
- int areanum;
- char name[MAX_EPAIRKEY];
- struct maplocation_s *next;
-} maplocation_t;
-
-//camp spots "info_camp"
-typedef struct campspot_s
-{
- vec3_t origin;
- int areanum;
- char name[MAX_EPAIRKEY];
- float range;
- float weight;
- float wait;
- float random;
- struct campspot_s *next;
-} campspot_t;
-
-//FIXME: these are game specific
-typedef enum {
- GT_FFA, // free for all
- GT_TOURNAMENT, // one on one tournament
- GT_SINGLE_PLAYER, // single player tournament
-
- //-- team games go after this --
-
- GT_TEAM, // team deathmatch
- GT_CTF, // capture the flag
-#ifdef MISSIONPACK
- GT_1FCTF,
- GT_OBELISK,
- GT_HARVESTER,
-#endif
- GT_MAX_GAME_TYPE
-} gametype_t;
-
-typedef struct levelitem_s
-{
- int number; //number of the level item
- int iteminfo; //index into the item info
- int flags; //item flags
- float weight; //fixed roam weight
- vec3_t origin; //origin of the item
- int goalareanum; //area the item is in
- vec3_t goalorigin; //goal origin within the area
- int entitynum; //entity number
- float timeout; //item is removed after this time
- struct levelitem_s *prev, *next;
-} levelitem_t;
-
-typedef struct iteminfo_s
-{
- char classname[32]; //classname of the item
- char name[MAX_STRINGFIELD]; //name of the item
- char model[MAX_STRINGFIELD]; //model of the item
- int modelindex; //model index
- int type; //item type
- int index; //index in the inventory
- float respawntime; //respawn time
- vec3_t mins; //mins of the item
- vec3_t maxs; //maxs of the item
- int number; //number of the item info
-} iteminfo_t;
-
-#define ITEMINFO_OFS(x) (size_t)&(((iteminfo_t *)0)->x)
-
-fielddef_t iteminfo_fields[] =
-{
-{"name", ITEMINFO_OFS(name), FT_STRING},
-{"model", ITEMINFO_OFS(model), FT_STRING},
-{"modelindex", ITEMINFO_OFS(modelindex), FT_INT},
-{"type", ITEMINFO_OFS(type), FT_INT},
-{"index", ITEMINFO_OFS(index), FT_INT},
-{"respawntime", ITEMINFO_OFS(respawntime), FT_FLOAT},
-{"mins", ITEMINFO_OFS(mins), FT_FLOAT|FT_ARRAY, 3},
-{"maxs", ITEMINFO_OFS(maxs), FT_FLOAT|FT_ARRAY, 3},
-{NULL, 0, 0}
-};
-
-structdef_t iteminfo_struct =
-{
- sizeof(iteminfo_t), iteminfo_fields
-};
-
-typedef struct itemconfig_s
-{
- int numiteminfo;
- iteminfo_t *iteminfo;
-} itemconfig_t;
-
-//goal state
-typedef struct bot_goalstate_s
-{
- struct weightconfig_s *itemweightconfig; //weight config
- int *itemweightindex; //index from item to weight
- //
- int client; //client using this goal state
- int lastreachabilityarea; //last area with reachabilities the bot was in
- //
- bot_goal_t goalstack[MAX_GOALSTACK]; //goal stack
- int goalstacktop; //the top of the goal stack
- //
- int avoidgoals[MAX_AVOIDGOALS]; //goals to avoid
- float avoidgoaltimes[MAX_AVOIDGOALS]; //times to avoid the goals
-} bot_goalstate_t;
-
-bot_goalstate_t *botgoalstates[MAX_CLIENTS + 1]; // FIXME: init?
-//item configuration
-itemconfig_t *itemconfig = NULL;
-//level items
-levelitem_t *levelitemheap = NULL;
-levelitem_t *freelevelitems = NULL;
-levelitem_t *levelitems = NULL;
-int numlevelitems = 0;
-//map locations
-maplocation_t *maplocations = NULL;
-//camp spots
-campspot_t *campspots = NULL;
-//the game type
-int g_gametype = 0;
-//additional dropped item weight
-libvar_t *droppedweight = NULL;
-
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-bot_goalstate_t *BotGoalStateFromHandle(int handle)
-{
- if (handle <= 0 || handle > MAX_CLIENTS)
- {
- botimport.Print(PRT_FATAL, "goal state handle %d out of range\n", handle);
- return NULL;
- } //end if
- if (!botgoalstates[handle])
- {
- botimport.Print(PRT_FATAL, "invalid goal state %d\n", handle);
- return NULL;
- } //end if
- return botgoalstates[handle];
-} //end of the function BotGoalStateFromHandle
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child)
-{
- bot_goalstate_t *p1, *p2, *c;
-
- p1 = BotGoalStateFromHandle(parent1);
- p2 = BotGoalStateFromHandle(parent2);
- c = BotGoalStateFromHandle(child);
-
- InterbreedWeightConfigs(p1->itemweightconfig, p2->itemweightconfig,
- c->itemweightconfig);
-} //end of the function BotInterbreedingGoalFuzzyLogic
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotSaveGoalFuzzyLogic(int goalstate, char *filename)
-{
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
-
- //WriteWeightConfig(filename, gs->itemweightconfig);
-} //end of the function BotSaveGoalFuzzyLogic
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotMutateGoalFuzzyLogic(int goalstate, float range)
-{
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
-
- EvolveWeightConfig(gs->itemweightconfig);
-} //end of the function BotMutateGoalFuzzyLogic
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-itemconfig_t *LoadItemConfig(char *filename)
-{
- int max_iteminfo;
- token_t token;
- char path[MAX_PATH];
- source_t *source;
- itemconfig_t *ic;
- iteminfo_t *ii;
-
- max_iteminfo = (int) LibVarValue("max_iteminfo", "256");
- if (max_iteminfo < 0)
- {
- botimport.Print(PRT_ERROR, "max_iteminfo = %d\n", max_iteminfo);
- max_iteminfo = 256;
- LibVarSet( "max_iteminfo", "256" );
- }
-
- strncpy( path, filename, MAX_PATH );
- PC_SetBaseFolder(BOTFILESBASEFOLDER);
- source = LoadSourceFile( path );
- if( !source ) {
- botimport.Print( PRT_ERROR, "counldn't load %s\n", path );
- return NULL;
- } //end if
- //initialize item config
- ic = (itemconfig_t *) GetClearedHunkMemory(sizeof(itemconfig_t) +
- max_iteminfo * sizeof(iteminfo_t));
- ic->iteminfo = (iteminfo_t *) ((char *) ic + sizeof(itemconfig_t));
- ic->numiteminfo = 0;
- //parse the item config file
- while(PC_ReadToken(source, &token))
- {
- if (!strcmp(token.string, "iteminfo"))
- {
- if (ic->numiteminfo >= max_iteminfo)
- {
- SourceError(source, "more than %d item info defined\n", max_iteminfo);
- FreeMemory(ic);
- FreeSource(source);
- return NULL;
- } //end if
- ii = &ic->iteminfo[ic->numiteminfo];
- Com_Memset(ii, 0, sizeof(iteminfo_t));
- if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
- {
- FreeMemory(ic);
- FreeMemory(source);
- return NULL;
- } //end if
- StripDoubleQuotes(token.string);
- strncpy(ii->classname, token.string, sizeof(ii->classname)-1);
- if (!ReadStructure(source, &iteminfo_struct, (char *) ii))
- {
- FreeMemory(ic);
- FreeSource(source);
- return NULL;
- } //end if
- ii->number = ic->numiteminfo;
- ic->numiteminfo++;
- } //end if
- else
- {
- SourceError(source, "unknown definition %s\n", token.string);
- FreeMemory(ic);
- FreeSource(source);
- return NULL;
- } //end else
- } //end while
- FreeSource(source);
- //
- if (!ic->numiteminfo) botimport.Print(PRT_WARNING, "no item info loaded\n");
- botimport.Print(PRT_MESSAGE, "loaded %s\n", path);
- return ic;
-} //end of the function LoadItemConfig
-//===========================================================================
-// index to find the weight function of an iteminfo
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int *ItemWeightIndex(weightconfig_t *iwc, itemconfig_t *ic)
-{
- int *index, i;
-
- //initialize item weight index
- index = (int *) GetClearedMemory(sizeof(int) * ic->numiteminfo);
-
- for (i = 0; i < ic->numiteminfo; i++)
- {
- index[i] = FindFuzzyWeight(iwc, ic->iteminfo[i].classname);
- if (index[i] < 0)
- {
- Log_Write("item info %d \"%s\" has no fuzzy weight\r\n", i, ic->iteminfo[i].classname);
- } //end if
- } //end for
- return index;
-} //end of the function ItemWeightIndex
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void InitLevelItemHeap(void)
-{
- int i, max_levelitems;
-
- if (levelitemheap) FreeMemory(levelitemheap);
-
- max_levelitems = (int) LibVarValue("max_levelitems", "256");
- levelitemheap = (levelitem_t *) GetClearedMemory(max_levelitems * sizeof(levelitem_t));
-
- for (i = 0; i < max_levelitems-1; i++)
- {
- levelitemheap[i].next = &levelitemheap[i + 1];
- } //end for
- levelitemheap[max_levelitems-1].next = NULL;
- //
- freelevelitems = levelitemheap;
-} //end of the function InitLevelItemHeap
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-levelitem_t *AllocLevelItem(void)
-{
- levelitem_t *li;
-
- li = freelevelitems;
- if (!li)
- {
- botimport.Print(PRT_FATAL, "out of level items\n");
- return NULL;
- } //end if
- //
- freelevelitems = freelevelitems->next;
- Com_Memset(li, 0, sizeof(levelitem_t));
- return li;
-} //end of the function AllocLevelItem
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FreeLevelItem(levelitem_t *li)
-{
- li->next = freelevelitems;
- freelevelitems = li;
-} //end of the function FreeLevelItem
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AddLevelItemToList(levelitem_t *li)
-{
- if (levelitems) levelitems->prev = li;
- li->prev = NULL;
- li->next = levelitems;
- levelitems = li;
-} //end of the function AddLevelItemToList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void RemoveLevelItemFromList(levelitem_t *li)
-{
- if (li->prev) li->prev->next = li->next;
- else levelitems = li->next;
- if (li->next) li->next->prev = li->prev;
-} //end of the function RemoveLevelItemFromList
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotFreeInfoEntities(void)
-{
- maplocation_t *ml, *nextml;
- campspot_t *cs, *nextcs;
-
- for (ml = maplocations; ml; ml = nextml)
- {
- nextml = ml->next;
- FreeMemory(ml);
- } //end for
- maplocations = NULL;
- for (cs = campspots; cs; cs = nextcs)
- {
- nextcs = cs->next;
- FreeMemory(cs);
- } //end for
- campspots = NULL;
-} //end of the function BotFreeInfoEntities
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotInitInfoEntities(void)
-{
- char classname[MAX_EPAIRKEY];
- maplocation_t *ml;
- campspot_t *cs;
- int ent, numlocations, numcampspots;
-
- BotFreeInfoEntities();
- //
- numlocations = 0;
- numcampspots = 0;
- for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
- {
- if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
-
- //map locations
- if (!strcmp(classname, "target_location"))
- {
- ml = (maplocation_t *) GetClearedMemory(sizeof(maplocation_t));
- AAS_VectorForBSPEpairKey(ent, "origin", ml->origin);
- AAS_ValueForBSPEpairKey(ent, "message", ml->name, sizeof(ml->name));
- ml->areanum = AAS_PointAreaNum(ml->origin);
- ml->next = maplocations;
- maplocations = ml;
- numlocations++;
- } //end if
- //camp spots
- else if (!strcmp(classname, "info_camp"))
- {
- cs = (campspot_t *) GetClearedMemory(sizeof(campspot_t));
- AAS_VectorForBSPEpairKey(ent, "origin", cs->origin);
- //cs->origin[2] += 16;
- AAS_ValueForBSPEpairKey(ent, "message", cs->name, sizeof(cs->name));
- AAS_FloatForBSPEpairKey(ent, "range", &cs->range);
- AAS_FloatForBSPEpairKey(ent, "weight", &cs->weight);
- AAS_FloatForBSPEpairKey(ent, "wait", &cs->wait);
- AAS_FloatForBSPEpairKey(ent, "random", &cs->random);
- cs->areanum = AAS_PointAreaNum(cs->origin);
- if (!cs->areanum)
- {
- botimport.Print(PRT_MESSAGE, "camp spot at %1.1f %1.1f %1.1f in solid\n", cs->origin[0], cs->origin[1], cs->origin[2]);
- FreeMemory(cs);
- continue;
- } //end if
- cs->next = campspots;
- campspots = cs;
- //AAS_DrawPermanentCross(cs->origin, 4, LINECOLOR_YELLOW);
- numcampspots++;
- } //end else if
- } //end for
- if (botDeveloper)
- {
- botimport.Print(PRT_MESSAGE, "%d map locations\n", numlocations);
- botimport.Print(PRT_MESSAGE, "%d camp spots\n", numcampspots);
- } //end if
-} //end of the function BotInitInfoEntities
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotInitLevelItems(void)
-{
- int i, spawnflags, value;
- char classname[MAX_EPAIRKEY];
- vec3_t origin, end;
- int ent, goalareanum;
- itemconfig_t *ic;
- levelitem_t *li;
- bsp_trace_t trace;
-
- //initialize the map locations and camp spots
- BotInitInfoEntities();
-
- //initialize the level item heap
- InitLevelItemHeap();
- levelitems = NULL;
- numlevelitems = 0;
- //
- ic = itemconfig;
- if (!ic) return;
-
- //if there's no AAS file loaded
- if (!AAS_Loaded()) return;
-
- //update the modelindexes of the item info
- for (i = 0; i < ic->numiteminfo; i++)
- {
- //ic->iteminfo[i].modelindex = AAS_IndexFromModel(ic->iteminfo[i].model);
- if (!ic->iteminfo[i].modelindex)
- {
- Log_Write("item %s has modelindex 0", ic->iteminfo[i].classname);
- } //end if
- } //end for
-
- for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
- {
- if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
- //
- spawnflags = 0;
- AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags);
- //
- for (i = 0; i < ic->numiteminfo; i++)
- {
- if (!strcmp(classname, ic->iteminfo[i].classname)) break;
- } //end for
- if (i >= ic->numiteminfo)
- {
- Log_Write("entity %s unknown item\r\n", classname);
- continue;
- } //end if
- //get the origin of the item
- if (!AAS_VectorForBSPEpairKey(ent, "origin", origin))
- {
- botimport.Print(PRT_ERROR, "item %s without origin\n", classname);
- continue;
- } //end else
- //
- goalareanum = 0;
- //if it is a floating item
- if (spawnflags & 1)
- {
- //if the item is not floating in water
- if (!(AAS_PointContents(origin) & CONTENTS_WATER))
- {
- VectorCopy(origin, end);
- end[2] -= 32;
- trace = AAS_Trace(origin, ic->iteminfo[i].mins, ic->iteminfo[i].maxs, end, -1, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- //if the item not near the ground
- if (trace.fraction >= 1)
- {
- //if the item is not reachable from a jumppad
- goalareanum = AAS_BestReachableFromJumpPadArea(origin, ic->iteminfo[i].mins, ic->iteminfo[i].maxs);
- Log_Write("item %s reachable from jumppad area %d\r\n", ic->iteminfo[i].classname, goalareanum);
- //botimport.Print(PRT_MESSAGE, "item %s reachable from jumppad area %d\r\n", ic->iteminfo[i].classname, goalareanum);
- if (!goalareanum) continue;
- } //end if
- } //end if
- } //end if
-
- li = AllocLevelItem();
- if (!li) return;
- //
- li->number = ++numlevelitems;
- li->timeout = 0;
- li->entitynum = 0;
- //
- li->flags = 0;
- AAS_IntForBSPEpairKey(ent, "notfree", &value);
- if (value) li->flags |= IFL_NOTFREE;
- AAS_IntForBSPEpairKey(ent, "notteam", &value);
- if (value) li->flags |= IFL_NOTTEAM;
- AAS_IntForBSPEpairKey(ent, "notsingle", &value);
- if (value) li->flags |= IFL_NOTSINGLE;
- AAS_IntForBSPEpairKey(ent, "notbot", &value);
- if (value) li->flags |= IFL_NOTBOT;
- if (!strcmp(classname, "item_botroam"))
- {
- li->flags |= IFL_ROAM;
- AAS_FloatForBSPEpairKey(ent, "weight", &li->weight);
- } //end if
- //if not a stationary item
- if (!(spawnflags & 1))
- {
- if (!AAS_DropToFloor(origin, ic->iteminfo[i].mins, ic->iteminfo[i].maxs))
- {
- botimport.Print(PRT_MESSAGE, "%s in solid at (%1.1f %1.1f %1.1f)\n",
- classname, origin[0], origin[1], origin[2]);
- } //end if
- } //end if
- //item info of the level item
- li->iteminfo = i;
- //origin of the item
- VectorCopy(origin, li->origin);
- //
- if (goalareanum)
- {
- li->goalareanum = goalareanum;
- VectorCopy(origin, li->goalorigin);
- } //end if
- else
- {
- //get the item goal area and goal origin
- li->goalareanum = AAS_BestReachableArea(origin,
- ic->iteminfo[i].mins, ic->iteminfo[i].maxs,
- li->goalorigin);
- if (!li->goalareanum)
- {
- botimport.Print(PRT_MESSAGE, "%s not reachable for bots at (%1.1f %1.1f %1.1f)\n",
- classname, origin[0], origin[1], origin[2]);
- } //end if
- } //end else
- //
- AddLevelItemToList(li);
- } //end for
- botimport.Print(PRT_MESSAGE, "found %d level items\n", numlevelitems);
-} //end of the function BotInitLevelItems
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotGoalName(int number, char *name, int size)
-{
- levelitem_t *li;
-
- if (!itemconfig) return;
- //
- for (li = levelitems; li; li = li->next)
- {
- if (li->number == number)
- {
- strncpy(name, itemconfig->iteminfo[li->iteminfo].name, size-1);
- name[size-1] = '\0';
- return;
- } //end for
- } //end for
- strcpy(name, "");
- return;
-} //end of the function BotGoalName
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotResetAvoidGoals(int goalstate)
-{
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs) return;
- Com_Memset(gs->avoidgoals, 0, MAX_AVOIDGOALS * sizeof(int));
- Com_Memset(gs->avoidgoaltimes, 0, MAX_AVOIDGOALS * sizeof(float));
-} //end of the function BotResetAvoidGoals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotDumpAvoidGoals(int goalstate)
-{
- int i;
- bot_goalstate_t *gs;
- char name[32];
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs) return;
- for (i = 0; i < MAX_AVOIDGOALS; i++)
- {
- if (gs->avoidgoaltimes[i] >= AAS_Time())
- {
- BotGoalName(gs->avoidgoals[i], name, 32);
- Log_Write("avoid goal %s, number %d for %f seconds", name,
- gs->avoidgoals[i], gs->avoidgoaltimes[i] - AAS_Time());
- } //end if
- } //end for
-} //end of the function BotDumpAvoidGoals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotAddToAvoidGoals(bot_goalstate_t *gs, int number, float avoidtime)
-{
- int i;
-
- for (i = 0; i < MAX_AVOIDGOALS; i++)
- {
- //if the avoid goal is already stored
- if (gs->avoidgoals[i] == number)
- {
- gs->avoidgoals[i] = number;
- gs->avoidgoaltimes[i] = AAS_Time() + avoidtime;
- return;
- } //end if
- } //end for
-
- for (i = 0; i < MAX_AVOIDGOALS; i++)
- {
- //if this avoid goal has expired
- if (gs->avoidgoaltimes[i] < AAS_Time())
- {
- gs->avoidgoals[i] = number;
- gs->avoidgoaltimes[i] = AAS_Time() + avoidtime;
- return;
- } //end if
- } //end for
-} //end of the function BotAddToAvoidGoals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotRemoveFromAvoidGoals(int goalstate, int number)
-{
- int i;
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs) return;
- //don't use the goals the bot wants to avoid
- for (i = 0; i < MAX_AVOIDGOALS; i++)
- {
- if (gs->avoidgoals[i] == number && gs->avoidgoaltimes[i] >= AAS_Time())
- {
- gs->avoidgoaltimes[i] = 0;
- return;
- } //end if
- } //end for
-} //end of the function BotRemoveFromAvoidGoals
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float BotAvoidGoalTime(int goalstate, int number)
-{
- int i;
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs) return 0;
- //don't use the goals the bot wants to avoid
- for (i = 0; i < MAX_AVOIDGOALS; i++)
- {
- if (gs->avoidgoals[i] == number && gs->avoidgoaltimes[i] >= AAS_Time())
- {
- return gs->avoidgoaltimes[i] - AAS_Time();
- } //end if
- } //end for
- return 0;
-} //end of the function BotAvoidGoalTime
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotSetAvoidGoalTime(int goalstate, int number, float avoidtime)
-{
- bot_goalstate_t *gs;
- levelitem_t *li;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs)
- return;
- if (avoidtime < 0)
- {
- if (!itemconfig)
- return;
- //
- for (li = levelitems; li; li = li->next)
- {
- if (li->number == number)
- {
- avoidtime = itemconfig->iteminfo[li->iteminfo].respawntime;
- if (!avoidtime)
- avoidtime = AVOID_DEFAULT_TIME;
- if (avoidtime < AVOID_MINIMUM_TIME)
- avoidtime = AVOID_MINIMUM_TIME;
- BotAddToAvoidGoals(gs, number, avoidtime);
- return;
- } //end for
- } //end for
- return;
- } //end if
- else
- {
- BotAddToAvoidGoals(gs, number, avoidtime);
- } //end else
-} //end of the function BotSetAvoidGoalTime
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotGetLevelItemGoal(int index, char *name, bot_goal_t *goal)
-{
- levelitem_t *li;
-
- if (!itemconfig) return -1;
- li = levelitems;
- if (index >= 0)
- {
- for (; li; li = li->next)
- {
- if (li->number == index)
- {
- li = li->next;
- break;
- } //end if
- } //end for
- } //end for
- for (; li; li = li->next)
- {
- //
- if (g_gametype == GT_SINGLE_PLAYER) {
- if (li->flags & IFL_NOTSINGLE) continue;
- }
- else if (g_gametype >= GT_TEAM) {
- if (li->flags & IFL_NOTTEAM) continue;
- }
- else {
- if (li->flags & IFL_NOTFREE) continue;
- }
- if (li->flags & IFL_NOTBOT) continue;
- //
- if (!Q_stricmp(name, itemconfig->iteminfo[li->iteminfo].name))
- {
- goal->areanum = li->goalareanum;
- VectorCopy(li->goalorigin, goal->origin);
- goal->entitynum = li->entitynum;
- VectorCopy(itemconfig->iteminfo[li->iteminfo].mins, goal->mins);
- VectorCopy(itemconfig->iteminfo[li->iteminfo].maxs, goal->maxs);
- goal->number = li->number;
- goal->flags = GFL_ITEM;
- if (li->timeout) goal->flags |= GFL_DROPPED;
- //botimport.Print(PRT_MESSAGE, "found li %s\n", itemconfig->iteminfo[li->iteminfo].name);
- return li->number;
- } //end if
- } //end for
- return -1;
-} //end of the function BotGetLevelItemGoal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotGetMapLocationGoal(char *name, bot_goal_t *goal)
-{
- maplocation_t *ml;
- vec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8};
-
- for (ml = maplocations; ml; ml = ml->next)
- {
- if (!Q_stricmp(ml->name, name))
- {
- goal->areanum = ml->areanum;
- VectorCopy(ml->origin, goal->origin);
- goal->entitynum = 0;
- VectorCopy(mins, goal->mins);
- VectorCopy(maxs, goal->maxs);
- return qtrue;
- } //end if
- } //end for
- return qfalse;
-} //end of the function BotGetMapLocationGoal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotGetNextCampSpotGoal(int num, bot_goal_t *goal)
-{
- int i;
- campspot_t *cs;
- vec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8};
-
- if (num < 0) num = 0;
- i = num;
- for (cs = campspots; cs; cs = cs->next)
- {
- if (--i < 0)
- {
- goal->areanum = cs->areanum;
- VectorCopy(cs->origin, goal->origin);
- goal->entitynum = 0;
- VectorCopy(mins, goal->mins);
- VectorCopy(maxs, goal->maxs);
- return num+1;
- } //end if
- } //end for
- return 0;
-} //end of the function BotGetNextCampSpotGoal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotFindEntityForLevelItem(levelitem_t *li)
-{
- int ent, modelindex;
- itemconfig_t *ic;
- aas_entityinfo_t entinfo;
- vec3_t dir;
-
- ic = itemconfig;
- if (!itemconfig) return;
- for (ent = AAS_NextEntity(0); ent; ent = AAS_NextEntity(ent))
- {
- //get the model index of the entity
- modelindex = AAS_EntityModelindex(ent);
- //
- if (!modelindex) continue;
- //get info about the entity
- AAS_EntityInfo(ent, &entinfo);
- //if the entity is still moving
- if (entinfo.origin[0] != entinfo.lastvisorigin[0] ||
- entinfo.origin[1] != entinfo.lastvisorigin[1] ||
- entinfo.origin[2] != entinfo.lastvisorigin[2]) continue;
- //
- if (ic->iteminfo[li->iteminfo].modelindex == modelindex)
- {
- //check if the entity is very close
- VectorSubtract(li->origin, entinfo.origin, dir);
- if (VectorLength(dir) < 30)
- {
- //found an entity for this level item
- li->entitynum = ent;
- } //end if
- } //end if
- } //end for
-} //end of the function BotFindEntityForLevelItem
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-
-//NOTE: enum entityType_t in bg_public.h
-#define ET_ITEM 2
-
-void BotUpdateEntityItems(void)
-{
- int ent, i, modelindex;
- vec3_t dir;
- levelitem_t *li, *nextli;
- aas_entityinfo_t entinfo;
- itemconfig_t *ic;
-
- //timeout current entity items if necessary
- for (li = levelitems; li; li = nextli)
- {
- nextli = li->next;
- //if it is a item that will time out
- if (li->timeout)
- {
- //timeout the item
- if (li->timeout < AAS_Time())
- {
- RemoveLevelItemFromList(li);
- FreeLevelItem(li);
- } //end if
- } //end if
- } //end for
- //find new entity items
- ic = itemconfig;
- if (!itemconfig) return;
- //
- for (ent = AAS_NextEntity(0); ent; ent = AAS_NextEntity(ent))
- {
- if (AAS_EntityType(ent) != ET_ITEM) continue;
- //get the model index of the entity
- modelindex = AAS_EntityModelindex(ent);
- //
- if (!modelindex) continue;
- //get info about the entity
- AAS_EntityInfo(ent, &entinfo);
- //FIXME: don't do this
- //skip all floating items for now
- //if (entinfo.groundent != ENTITYNUM_WORLD) continue;
- //if the entity is still moving
- if (entinfo.origin[0] != entinfo.lastvisorigin[0] ||
- entinfo.origin[1] != entinfo.lastvisorigin[1] ||
- entinfo.origin[2] != entinfo.lastvisorigin[2]) continue;
- //check if the entity is already stored as a level item
- for (li = levelitems; li; li = li->next)
- {
- //if the level item is linked to an entity
- if (li->entitynum && li->entitynum == ent)
- {
- //the entity is re-used if the models are different
- if (ic->iteminfo[li->iteminfo].modelindex != modelindex)
- {
- //remove this level item
- RemoveLevelItemFromList(li);
- FreeLevelItem(li);
- li = NULL;
- break;
- } //end if
- else
- {
- if (entinfo.origin[0] != li->origin[0] ||
- entinfo.origin[1] != li->origin[1] ||
- entinfo.origin[2] != li->origin[2])
- {
- VectorCopy(entinfo.origin, li->origin);
- //also update the goal area number
- li->goalareanum = AAS_BestReachableArea(li->origin,
- ic->iteminfo[li->iteminfo].mins, ic->iteminfo[li->iteminfo].maxs,
- li->goalorigin);
- } //end if
- break;
- } //end else
- } //end if
- } //end for
- if (li) continue;
- //try to link the entity to a level item
- for (li = levelitems; li; li = li->next)
- {
- //if this level item is already linked
- if (li->entitynum) continue;
- //
- if (g_gametype == GT_SINGLE_PLAYER) {
- if (li->flags & IFL_NOTSINGLE) continue;
- }
- else if (g_gametype >= GT_TEAM) {
- if (li->flags & IFL_NOTTEAM) continue;
- }
- else {
- if (li->flags & IFL_NOTFREE) continue;
- }
- //if the model of the level item and the entity are the same
- if (ic->iteminfo[li->iteminfo].modelindex == modelindex)
- {
- //check if the entity is very close
- VectorSubtract(li->origin, entinfo.origin, dir);
- if (VectorLength(dir) < 30)
- {
- //found an entity for this level item
- li->entitynum = ent;
- //if the origin is different
- if (entinfo.origin[0] != li->origin[0] ||
- entinfo.origin[1] != li->origin[1] ||
- entinfo.origin[2] != li->origin[2])
- {
- //update the level item origin
- VectorCopy(entinfo.origin, li->origin);
- //also update the goal area number
- li->goalareanum = AAS_BestReachableArea(li->origin,
- ic->iteminfo[li->iteminfo].mins, ic->iteminfo[li->iteminfo].maxs,
- li->goalorigin);
- } //end if
-#ifdef DEBUG
- Log_Write("linked item %s to an entity", ic->iteminfo[li->iteminfo].classname);
-#endif //DEBUG
- break;
- } //end if
- } //end else
- } //end for
- if (li) continue;
- //check if the model is from a known item
- for (i = 0; i < ic->numiteminfo; i++)
- {
- if (ic->iteminfo[i].modelindex == modelindex)
- {
- break;
- } //end if
- } //end for
- //if the model is not from a known item
- if (i >= ic->numiteminfo) continue;
- //allocate a new level item
- li = AllocLevelItem();
- //
- if (!li) continue;
- //entity number of the level item
- li->entitynum = ent;
- //number for the level item
- li->number = numlevelitems + ent;
- //set the item info index for the level item
- li->iteminfo = i;
- //origin of the item
- VectorCopy(entinfo.origin, li->origin);
- //get the item goal area and goal origin
- li->goalareanum = AAS_BestReachableArea(li->origin,
- ic->iteminfo[i].mins, ic->iteminfo[i].maxs,
- li->goalorigin);
- //never go for items dropped into jumppads
- if (AAS_AreaJumpPad(li->goalareanum))
- {
- FreeLevelItem(li);
- continue;
- } //end if
- //time this item out after 30 seconds
- //dropped items disappear after 30 seconds
- li->timeout = AAS_Time() + 30;
- //add the level item to the list
- AddLevelItemToList(li);
- //botimport.Print(PRT_MESSAGE, "found new level item %s\n", ic->iteminfo[i].classname);
- } //end for
- /*
- for (li = levelitems; li; li = li->next)
- {
- if (!li->entitynum)
- {
- BotFindEntityForLevelItem(li);
- } //end if
- } //end for*/
-} //end of the function BotUpdateEntityItems
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotDumpGoalStack(int goalstate)
-{
- int i;
- bot_goalstate_t *gs;
- char name[32];
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs) return;
- for (i = 1; i <= gs->goalstacktop; i++)
- {
- BotGoalName(gs->goalstack[i].number, name, 32);
- Log_Write("%d: %s", i, name);
- } //end for
-} //end of the function BotDumpGoalStack
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotPushGoal(int goalstate, bot_goal_t *goal)
-{
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs) return;
- if (gs->goalstacktop >= MAX_GOALSTACK-1)
- {
- botimport.Print(PRT_ERROR, "goal heap overflow\n");
- BotDumpGoalStack(goalstate);
- return;
- } //end if
- gs->goalstacktop++;
- Com_Memcpy(&gs->goalstack[gs->goalstacktop], goal, sizeof(bot_goal_t));
-} //end of the function BotPushGoal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotPopGoal(int goalstate)
-{
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs) return;
- if (gs->goalstacktop > 0) gs->goalstacktop--;
-} //end of the function BotPopGoal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotEmptyGoalStack(int goalstate)
-{
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs) return;
- gs->goalstacktop = 0;
-} //end of the function BotEmptyGoalStack
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotGetTopGoal(int goalstate, bot_goal_t *goal)
-{
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs) return qfalse;
- if (!gs->goalstacktop) return qfalse;
- Com_Memcpy(goal, &gs->goalstack[gs->goalstacktop], sizeof(bot_goal_t));
- return qtrue;
-} //end of the function BotGetTopGoal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotGetSecondGoal(int goalstate, bot_goal_t *goal)
-{
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs) return qfalse;
- if (gs->goalstacktop <= 1) return qfalse;
- Com_Memcpy(goal, &gs->goalstack[gs->goalstacktop-1], sizeof(bot_goal_t));
- return qtrue;
-} //end of the function BotGetSecondGoal
-//===========================================================================
-// pops a new long term goal on the goal stack in the goalstate
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags)
-{
- int areanum, t, weightnum;
- float weight, bestweight, avoidtime;
- iteminfo_t *iteminfo;
- itemconfig_t *ic;
- levelitem_t *li, *bestitem;
- bot_goal_t goal;
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs)
- return qfalse;
- if (!gs->itemweightconfig)
- return qfalse;
- //get the area the bot is in
- areanum = BotReachabilityArea(origin, gs->client);
- //if the bot is in solid or if the area the bot is in has no reachability links
- if (!areanum || !AAS_AreaReachability(areanum))
- {
- //use the last valid area the bot was in
- areanum = gs->lastreachabilityarea;
- } //end if
- //remember the last area with reachabilities the bot was in
- gs->lastreachabilityarea = areanum;
- //if still in solid
- if (!areanum)
- return qfalse;
- //the item configuration
- ic = itemconfig;
- if (!itemconfig)
- return qfalse;
- //best weight and item so far
- bestweight = 0;
- bestitem = NULL;
- Com_Memset(&goal, 0, sizeof(bot_goal_t));
- //go through the items in the level
- for (li = levelitems; li; li = li->next)
- {
- if (g_gametype == GT_SINGLE_PLAYER) {
- if (li->flags & IFL_NOTSINGLE)
- continue;
- }
- else if (g_gametype >= GT_TEAM) {
- if (li->flags & IFL_NOTTEAM)
- continue;
- }
- else {
- if (li->flags & IFL_NOTFREE)
- continue;
- }
- if (li->flags & IFL_NOTBOT)
- continue;
- //if the item is not in a possible goal area
- if (!li->goalareanum)
- continue;
- //FIXME: is this a good thing? added this for items that never spawned into the game (f.i. CTF flags in obelisk)
- if (!li->entitynum && !(li->flags & IFL_ROAM))
- continue;
- //get the fuzzy weight function for this item
- iteminfo = &ic->iteminfo[li->iteminfo];
- weightnum = gs->itemweightindex[iteminfo->number];
- if (weightnum < 0)
- continue;
-
-#ifdef UNDECIDEDFUZZY
- weight = FuzzyWeightUndecided(inventory, gs->itemweightconfig, weightnum);
-#else
- weight = FuzzyWeight(inventory, gs->itemweightconfig, weightnum);
-#endif //UNDECIDEDFUZZY
-#ifdef DROPPEDWEIGHT
- //HACK: to make dropped items more attractive
- if (li->timeout)
- weight += droppedweight->value;
-#endif //DROPPEDWEIGHT
- //use weight scale for item_botroam
- if (li->flags & IFL_ROAM) weight *= li->weight;
- //
- if (weight > 0)
- {
- //get the travel time towards the goal area
- t = AAS_AreaTravelTimeToGoalArea(areanum, origin, li->goalareanum, travelflags);
- //if the goal is reachable
- if (t > 0)
- {
- //if this item won't respawn before we get there
- avoidtime = BotAvoidGoalTime(goalstate, li->number);
- if (avoidtime - t * 0.009 > 0)
- continue;
- //
- weight /= (float) t * TRAVELTIME_SCALE;
- //
- if (weight > bestweight)
- {
- bestweight = weight;
- bestitem = li;
- } //end if
- } //end if
- } //end if
- } //end for
- //if no goal item found
- if (!bestitem)
- {
- /*
- //if not in lava or slime
- if (!AAS_AreaLava(areanum) && !AAS_AreaSlime(areanum))
- {
- if (AAS_RandomGoalArea(areanum, travelflags, &goal.areanum, goal.origin))
- {
- VectorSet(goal.mins, -15, -15, -15);
- VectorSet(goal.maxs, 15, 15, 15);
- goal.entitynum = 0;
- goal.number = 0;
- goal.flags = GFL_ROAM;
- goal.iteminfo = 0;
- //push the goal on the stack
- BotPushGoal(goalstate, &goal);
- //
-#ifdef DEBUG
- botimport.Print(PRT_MESSAGE, "chosen roam goal area %d\n", goal.areanum);
-#endif //DEBUG
- return qtrue;
- } //end if
- } //end if
- */
- return qfalse;
- } //end if
- //create a bot goal for this item
- iteminfo = &ic->iteminfo[bestitem->iteminfo];
- VectorCopy(bestitem->goalorigin, goal.origin);
- VectorCopy(iteminfo->mins, goal.mins);
- VectorCopy(iteminfo->maxs, goal.maxs);
- goal.areanum = bestitem->goalareanum;
- goal.entitynum = bestitem->entitynum;
- goal.number = bestitem->number;
- goal.flags = GFL_ITEM;
- if (bestitem->timeout)
- goal.flags |= GFL_DROPPED;
- if (bestitem->flags & IFL_ROAM)
- goal.flags |= GFL_ROAM;
- goal.iteminfo = bestitem->iteminfo;
- //if it's a dropped item
- if (bestitem->timeout)
- {
- avoidtime = AVOID_DROPPED_TIME;
- } //end if
- else
- {
- avoidtime = iteminfo->respawntime;
- if (!avoidtime)
- avoidtime = AVOID_DEFAULT_TIME;
- if (avoidtime < AVOID_MINIMUM_TIME)
- avoidtime = AVOID_MINIMUM_TIME;
- } //end else
- //add the chosen goal to the goals to avoid for a while
- BotAddToAvoidGoals(gs, bestitem->number, avoidtime);
- //push the goal on the stack
- BotPushGoal(goalstate, &goal);
- //
- return qtrue;
-} //end of the function BotChooseLTGItem
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags,
- bot_goal_t *ltg, float maxtime)
-{
- int areanum, t, weightnum, ltg_time;
- float weight, bestweight, avoidtime;
- iteminfo_t *iteminfo;
- itemconfig_t *ic;
- levelitem_t *li, *bestitem;
- bot_goal_t goal;
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs)
- return qfalse;
- if (!gs->itemweightconfig)
- return qfalse;
- //get the area the bot is in
- areanum = BotReachabilityArea(origin, gs->client);
- //if the bot is in solid or if the area the bot is in has no reachability links
- if (!areanum || !AAS_AreaReachability(areanum))
- {
- //use the last valid area the bot was in
- areanum = gs->lastreachabilityarea;
- } //end if
- //remember the last area with reachabilities the bot was in
- gs->lastreachabilityarea = areanum;
- //if still in solid
- if (!areanum)
- return qfalse;
- //
- if (ltg) ltg_time = AAS_AreaTravelTimeToGoalArea(areanum, origin, ltg->areanum, travelflags);
- else ltg_time = 99999;
- //the item configuration
- ic = itemconfig;
- if (!itemconfig)
- return qfalse;
- //best weight and item so far
- bestweight = 0;
- bestitem = NULL;
- Com_Memset(&goal, 0, sizeof(bot_goal_t));
- //go through the items in the level
- for (li = levelitems; li; li = li->next)
- {
- if (g_gametype == GT_SINGLE_PLAYER) {
- if (li->flags & IFL_NOTSINGLE)
- continue;
- }
- else if (g_gametype >= GT_TEAM) {
- if (li->flags & IFL_NOTTEAM)
- continue;
- }
- else {
- if (li->flags & IFL_NOTFREE)
- continue;
- }
- if (li->flags & IFL_NOTBOT)
- continue;
- //if the item is in a possible goal area
- if (!li->goalareanum)
- continue;
- //FIXME: is this a good thing? added this for items that never spawned into the game (f.i. CTF flags in obelisk)
- if (!li->entitynum && !(li->flags & IFL_ROAM))
- continue;
- //get the fuzzy weight function for this item
- iteminfo = &ic->iteminfo[li->iteminfo];
- weightnum = gs->itemweightindex[iteminfo->number];
- if (weightnum < 0)
- continue;
- //
-#ifdef UNDECIDEDFUZZY
- weight = FuzzyWeightUndecided(inventory, gs->itemweightconfig, weightnum);
-#else
- weight = FuzzyWeight(inventory, gs->itemweightconfig, weightnum);
-#endif //UNDECIDEDFUZZY
-#ifdef DROPPEDWEIGHT
- //HACK: to make dropped items more attractive
- if (li->timeout)
- weight += droppedweight->value;
-#endif //DROPPEDWEIGHT
- //use weight scale for item_botroam
- if (li->flags & IFL_ROAM) weight *= li->weight;
- //
- if (weight > 0)
- {
- //get the travel time towards the goal area
- t = AAS_AreaTravelTimeToGoalArea(areanum, origin, li->goalareanum, travelflags);
- //if the goal is reachable
- if (t > 0 && t < maxtime)
- {
- //if this item won't respawn before we get there
- avoidtime = BotAvoidGoalTime(goalstate, li->number);
- if (avoidtime - t * 0.009 > 0)
- continue;
- //
- weight /= (float) t * TRAVELTIME_SCALE;
- //
- if (weight > bestweight)
- {
- t = 0;
- if (ltg && !li->timeout)
- {
- //get the travel time from the goal to the long term goal
- t = AAS_AreaTravelTimeToGoalArea(li->goalareanum, li->goalorigin, ltg->areanum, travelflags);
- } //end if
- //if the travel back is possible and doesn't take too long
- if (t <= ltg_time)
- {
- bestweight = weight;
- bestitem = li;
- } //end if
- } //end if
- } //end if
- } //end if
- } //end for
- //if no goal item found
- if (!bestitem)
- return qfalse;
- //create a bot goal for this item
- iteminfo = &ic->iteminfo[bestitem->iteminfo];
- VectorCopy(bestitem->goalorigin, goal.origin);
- VectorCopy(iteminfo->mins, goal.mins);
- VectorCopy(iteminfo->maxs, goal.maxs);
- goal.areanum = bestitem->goalareanum;
- goal.entitynum = bestitem->entitynum;
- goal.number = bestitem->number;
- goal.flags = GFL_ITEM;
- if (bestitem->timeout)
- goal.flags |= GFL_DROPPED;
- if (bestitem->flags & IFL_ROAM)
- goal.flags |= GFL_ROAM;
- goal.iteminfo = bestitem->iteminfo;
- //if it's a dropped item
- if (bestitem->timeout)
- {
- avoidtime = AVOID_DROPPED_TIME;
- } //end if
- else
- {
- avoidtime = iteminfo->respawntime;
- if (!avoidtime)
- avoidtime = AVOID_DEFAULT_TIME;
- if (avoidtime < AVOID_MINIMUM_TIME)
- avoidtime = AVOID_MINIMUM_TIME;
- } //end else
- //add the chosen goal to the goals to avoid for a while
- BotAddToAvoidGoals(gs, bestitem->number, avoidtime);
- //push the goal on the stack
- BotPushGoal(goalstate, &goal);
- //
- return qtrue;
-} //end of the function BotChooseNBGItem
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotTouchingGoal(vec3_t origin, bot_goal_t *goal)
-{
- int i;
- vec3_t boxmins, boxmaxs;
- vec3_t absmins, absmaxs;
- vec3_t safety_maxs = {0, 0, 0}; //{4, 4, 10};
- vec3_t safety_mins = {0, 0, 0}; //{-4, -4, 0};
-
- AAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, boxmins, boxmaxs);
- VectorSubtract(goal->mins, boxmaxs, absmins);
- VectorSubtract(goal->maxs, boxmins, absmaxs);
- VectorAdd(absmins, goal->origin, absmins);
- VectorAdd(absmaxs, goal->origin, absmaxs);
- //make the box a little smaller for safety
- VectorSubtract(absmaxs, safety_maxs, absmaxs);
- VectorSubtract(absmins, safety_mins, absmins);
-
- for (i = 0; i < 3; i++)
- {
- if (origin[i] < absmins[i] || origin[i] > absmaxs[i]) return qfalse;
- } //end for
- return qtrue;
-} //end of the function BotTouchingGoal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, bot_goal_t *goal)
-{
- aas_entityinfo_t entinfo;
- bsp_trace_t trace;
- vec3_t middle;
-
- if (!(goal->flags & GFL_ITEM)) return qfalse;
- //
- VectorAdd(goal->mins, goal->mins, middle);
- VectorScale(middle, 0.5, middle);
- VectorAdd(goal->origin, middle, middle);
- //
- trace = AAS_Trace(eye, NULL, NULL, middle, viewer, CONTENTS_SOLID);
- //if the goal middle point is visible
- if (trace.fraction >= 1)
- {
- //the goal entity number doesn't have to be valid
- //just assume it's valid
- if (goal->entitynum <= 0)
- return qfalse;
- //
- //if the entity data isn't valid
- AAS_EntityInfo(goal->entitynum, &entinfo);
- //NOTE: for some wacko reason entities are sometimes
- // not updated
- //if (!entinfo.valid) return qtrue;
- if (entinfo.ltime < AAS_Time() - 0.5)
- return qtrue;
- } //end if
- return qfalse;
-} //end of the function BotItemGoalInVisButNotVisible
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotResetGoalState(int goalstate)
-{
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs) return;
- Com_Memset(gs->goalstack, 0, MAX_GOALSTACK * sizeof(bot_goal_t));
- gs->goalstacktop = 0;
- BotResetAvoidGoals(goalstate);
-} //end of the function BotResetGoalState
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotLoadItemWeights(int goalstate, char *filename)
-{
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs) return BLERR_CANNOTLOADITEMWEIGHTS;
- //load the weight configuration
- gs->itemweightconfig = ReadWeightConfig(filename);
- if (!gs->itemweightconfig)
- {
- botimport.Print(PRT_FATAL, "couldn't load weights\n");
- return BLERR_CANNOTLOADITEMWEIGHTS;
- } //end if
- //if there's no item configuration
- if (!itemconfig) return BLERR_CANNOTLOADITEMWEIGHTS;
- //create the item weight index
- gs->itemweightindex = ItemWeightIndex(gs->itemweightconfig, itemconfig);
- //everything went ok
- return BLERR_NOERROR;
-} //end of the function BotLoadItemWeights
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotFreeItemWeights(int goalstate)
-{
- bot_goalstate_t *gs;
-
- gs = BotGoalStateFromHandle(goalstate);
- if (!gs) return;
- if (gs->itemweightconfig) FreeWeightConfig(gs->itemweightconfig);
- if (gs->itemweightindex) FreeMemory(gs->itemweightindex);
-} //end of the function BotFreeItemWeights
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotAllocGoalState(int client)
-{
- int i;
-
- for (i = 1; i <= MAX_CLIENTS; i++)
- {
- if (!botgoalstates[i])
- {
- botgoalstates[i] = GetClearedMemory(sizeof(bot_goalstate_t));
- botgoalstates[i]->client = client;
- return i;
- } //end if
- } //end for
- return 0;
-} //end of the function BotAllocGoalState
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-void BotFreeGoalState(int handle)
-{
- if (handle <= 0 || handle > MAX_CLIENTS)
- {
- botimport.Print(PRT_FATAL, "goal state handle %d out of range\n", handle);
- return;
- } //end if
- if (!botgoalstates[handle])
- {
- botimport.Print(PRT_FATAL, "invalid goal state handle %d\n", handle);
- return;
- } //end if
- BotFreeItemWeights(handle);
- FreeMemory(botgoalstates[handle]);
- botgoalstates[handle] = NULL;
-} //end of the function BotFreeGoalState
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotSetupGoalAI(void)
-{
- char *filename;
-
- //check if teamplay is on
- g_gametype = LibVarValue("g_gametype", "0");
- //item configuration file
- filename = LibVarString("itemconfig", "items.c");
- //load the item configuration
- itemconfig = LoadItemConfig(filename);
- if (!itemconfig)
- {
- botimport.Print(PRT_FATAL, "couldn't load item config\n");
- return BLERR_CANNOTLOADITEMCONFIG;
- } //end if
- //
- droppedweight = LibVar("droppedweight", "1000");
- //everything went ok
- return BLERR_NOERROR;
-} //end of the function BotSetupGoalAI
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotShutdownGoalAI(void)
-{
- int i;
-
- if (itemconfig) FreeMemory(itemconfig);
- itemconfig = NULL;
- if (levelitemheap) FreeMemory(levelitemheap);
- levelitemheap = NULL;
- freelevelitems = NULL;
- levelitems = NULL;
- numlevelitems = 0;
-
- BotFreeInfoEntities();
-
- for (i = 1; i <= MAX_CLIENTS; i++)
- {
- if (botgoalstates[i])
- {
- BotFreeGoalState(i);
- } //end if
- } //end for
-} //end of the function BotShutdownGoalAI
diff --git a/engine/code/botlib/be_ai_move.c b/engine/code/botlib/be_ai_move.c
deleted file mode 100644
index 2840830..0000000
--- a/engine/code/botlib/be_ai_move.c
+++ /dev/null
@@ -1,3570 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_ai_move.c
- *
- * desc: bot movement AI
- *
- * $Archive: /MissionPack/code/botlib/be_ai_move.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_libvar.h"
-#include "l_utils.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-
-#include "be_ea.h"
-#include "be_ai_goal.h"
-#include "be_ai_move.h"
-
-
-//#define DEBUG_AI_MOVE
-//#define DEBUG_ELEVATOR
-//#define DEBUG_GRAPPLE
-
-//movement state
-//NOTE: the moveflags MFL_ONGROUND, MFL_TELEPORTED, MFL_WATERJUMP and
-// MFL_GRAPPLEPULL must be set outside the movement code
-typedef struct bot_movestate_s
-{
- //input vars (all set outside the movement code)
- vec3_t origin; //origin of the bot
- vec3_t velocity; //velocity of the bot
- vec3_t viewoffset; //view offset
- int entitynum; //entity number of the bot
- int client; //client number of the bot
- float thinktime; //time the bot thinks
- int presencetype; //presencetype of the bot
- vec3_t viewangles; //view angles of the bot
- //state vars
- int areanum; //area the bot is in
- int lastareanum; //last area the bot was in
- int lastgoalareanum; //last goal area number
- int lastreachnum; //last reachability number
- vec3_t lastorigin; //origin previous cycle
- int reachareanum; //area number of the reachabilty
- int moveflags; //movement flags
- int jumpreach; //set when jumped
- float grapplevisible_time; //last time the grapple was visible
- float lastgrappledist; //last distance to the grapple end
- float reachability_time; //time to use current reachability
- int avoidreach[MAX_AVOIDREACH]; //reachabilities to avoid
- float avoidreachtimes[MAX_AVOIDREACH]; //times to avoid the reachabilities
- int avoidreachtries[MAX_AVOIDREACH]; //number of tries before avoiding
- //
- bot_avoidspot_t avoidspots[MAX_AVOIDSPOTS]; //spots to avoid
- int numavoidspots;
-} bot_movestate_t;
-
-//used to avoid reachability links for some time after being used
-#define AVOIDREACH
-#define AVOIDREACH_TIME 6 //avoid links for 6 seconds after use
-#define AVOIDREACH_TRIES 4
-//prediction times
-#define PREDICTIONTIME_JUMP 3 //in seconds
-#define PREDICTIONTIME_MOVE 2 //in seconds
-//weapon indexes for weapon jumping
-#define WEAPONINDEX_ROCKET_LAUNCHER 5
-#define WEAPONINDEX_BFG 9
-
-#define MODELTYPE_FUNC_PLAT 1
-#define MODELTYPE_FUNC_BOB 2
-#define MODELTYPE_FUNC_DOOR 3
-#define MODELTYPE_FUNC_STATIC 4
-
-libvar_t *sv_maxstep;
-libvar_t *sv_maxbarrier;
-libvar_t *sv_gravity;
-libvar_t *weapindex_rocketlauncher;
-libvar_t *weapindex_bfg10k;
-libvar_t *weapindex_grapple;
-libvar_t *entitytypemissile;
-libvar_t *offhandgrapple;
-libvar_t *cmd_grappleoff;
-libvar_t *cmd_grappleon;
-//type of model, func_plat or func_bobbing
-int modeltypes[MAX_MODELS];
-
-bot_movestate_t *botmovestates[MAX_CLIENTS+1];
-
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-int BotAllocMoveState(void)
-{
- int i;
-
- for (i = 1; i <= MAX_CLIENTS; i++)
- {
- if (!botmovestates[i])
- {
- botmovestates[i] = GetClearedMemory(sizeof(bot_movestate_t));
- return i;
- } //end if
- } //end for
- return 0;
-} //end of the function BotAllocMoveState
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-void BotFreeMoveState(int handle)
-{
- if (handle <= 0 || handle > MAX_CLIENTS)
- {
- botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
- return;
- } //end if
- if (!botmovestates[handle])
- {
- botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
- return;
- } //end if
- FreeMemory(botmovestates[handle]);
- botmovestates[handle] = NULL;
-} //end of the function BotFreeMoveState
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-bot_movestate_t *BotMoveStateFromHandle(int handle)
-{
- if (handle <= 0 || handle > MAX_CLIENTS)
- {
- botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
- return NULL;
- } //end if
- if (!botmovestates[handle])
- {
- botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
- return NULL;
- } //end if
- return botmovestates[handle];
-} //end of the function BotMoveStateFromHandle
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-void BotInitMoveState(int handle, bot_initmove_t *initmove)
-{
- bot_movestate_t *ms;
-
- ms = BotMoveStateFromHandle(handle);
- if (!ms) return;
- VectorCopy(initmove->origin, ms->origin);
- VectorCopy(initmove->velocity, ms->velocity);
- VectorCopy(initmove->viewoffset, ms->viewoffset);
- ms->entitynum = initmove->entitynum;
- ms->client = initmove->client;
- ms->thinktime = initmove->thinktime;
- ms->presencetype = initmove->presencetype;
- VectorCopy(initmove->viewangles, ms->viewangles);
- //
- ms->moveflags &= ~MFL_ONGROUND;
- if (initmove->or_moveflags & MFL_ONGROUND) ms->moveflags |= MFL_ONGROUND;
- ms->moveflags &= ~MFL_TELEPORTED;
- if (initmove->or_moveflags & MFL_TELEPORTED) ms->moveflags |= MFL_TELEPORTED;
- ms->moveflags &= ~MFL_WATERJUMP;
- if (initmove->or_moveflags & MFL_WATERJUMP) ms->moveflags |= MFL_WATERJUMP;
- ms->moveflags &= ~MFL_WALK;
- if (initmove->or_moveflags & MFL_WALK) ms->moveflags |= MFL_WALK;
- ms->moveflags &= ~MFL_GRAPPLEPULL;
- if (initmove->or_moveflags & MFL_GRAPPLEPULL) ms->moveflags |= MFL_GRAPPLEPULL;
-} //end of the function BotInitMoveState
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-float AngleDiff(float ang1, float ang2)
-{
- float diff;
-
- diff = ang1 - ang2;
- if (ang1 > ang2)
- {
- if (diff > 180.0) diff -= 360.0;
- } //end if
- else
- {
- if (diff < -180.0) diff += 360.0;
- } //end else
- return diff;
-} //end of the function AngleDiff
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotFuzzyPointReachabilityArea(vec3_t origin)
-{
- int firstareanum, j, x, y, z;
- int areas[10], numareas, areanum, bestareanum;
- float dist, bestdist;
- vec3_t points[10], v, end;
-
- firstareanum = 0;
- areanum = AAS_PointAreaNum(origin);
- if (areanum)
- {
- firstareanum = areanum;
- if (AAS_AreaReachability(areanum)) return areanum;
- } //end if
- VectorCopy(origin, end);
- end[2] += 4;
- numareas = AAS_TraceAreas(origin, end, areas, points, 10);
- for (j = 0; j < numareas; j++)
- {
- if (AAS_AreaReachability(areas[j])) return areas[j];
- } //end for
- bestdist = 999999;
- bestareanum = 0;
- for (z = 1; z >= -1; z -= 1)
- {
- for (x = 1; x >= -1; x -= 1)
- {
- for (y = 1; y >= -1; y -= 1)
- {
- VectorCopy(origin, end);
- end[0] += x * 8;
- end[1] += y * 8;
- end[2] += z * 12;
- numareas = AAS_TraceAreas(origin, end, areas, points, 10);
- for (j = 0; j < numareas; j++)
- {
- if (AAS_AreaReachability(areas[j]))
- {
- VectorSubtract(points[j], origin, v);
- dist = VectorLength(v);
- if (dist < bestdist)
- {
- bestareanum = areas[j];
- bestdist = dist;
- } //end if
- } //end if
- if (!firstareanum) firstareanum = areas[j];
- } //end for
- } //end for
- } //end for
- if (bestareanum) return bestareanum;
- } //end for
- return firstareanum;
-} //end of the function BotFuzzyPointReachabilityArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotReachabilityArea(vec3_t origin, int client)
-{
- int modelnum, modeltype, reachnum, areanum;
- aas_reachability_t reach;
- vec3_t org, end, mins, maxs, up = {0, 0, 1};
- bsp_trace_t bsptrace;
- aas_trace_t trace;
-
- //check if the bot is standing on something
- AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs);
- VectorMA(origin, -3, up, end);
- bsptrace = AAS_Trace(origin, mins, maxs, end, client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- if (!bsptrace.startsolid && bsptrace.fraction < 1 && bsptrace.ent != ENTITYNUM_NONE)
- {
- //if standing on the world the bot should be in a valid area
- if (bsptrace.ent == ENTITYNUM_WORLD)
- {
- return BotFuzzyPointReachabilityArea(origin);
- } //end if
-
- modelnum = AAS_EntityModelindex(bsptrace.ent);
- modeltype = modeltypes[modelnum];
-
- //if standing on a func_plat or func_bobbing then the bot is assumed to be
- //in the area the reachability points to
- if (modeltype == MODELTYPE_FUNC_PLAT || modeltype == MODELTYPE_FUNC_BOB)
- {
- reachnum = AAS_NextModelReachability(0, modelnum);
- if (reachnum)
- {
- AAS_ReachabilityFromNum(reachnum, &reach);
- return reach.areanum;
- } //end if
- } //end else if
-
- //if the bot is swimming the bot should be in a valid area
- if (AAS_Swimming(origin))
- {
- return BotFuzzyPointReachabilityArea(origin);
- } //end if
- //
- areanum = BotFuzzyPointReachabilityArea(origin);
- //if the bot is in an area with reachabilities
- if (areanum && AAS_AreaReachability(areanum)) return areanum;
- //trace down till the ground is hit because the bot is standing on some other entity
- VectorCopy(origin, org);
- VectorCopy(org, end);
- end[2] -= 800;
- trace = AAS_TraceClientBBox(org, end, PRESENCE_CROUCH, -1);
- if (!trace.startsolid)
- {
- VectorCopy(trace.endpos, org);
- } //end if
- //
- return BotFuzzyPointReachabilityArea(org);
- } //end if
- //
- return BotFuzzyPointReachabilityArea(origin);
-} //end of the function BotReachabilityArea
-//===========================================================================
-// returns the reachability area the bot is in
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-/*
-int BotReachabilityArea(vec3_t origin, int testground)
-{
- int firstareanum, i, j, x, y, z;
- int areas[10], numareas, areanum, bestareanum;
- float dist, bestdist;
- vec3_t org, end, points[10], v;
- aas_trace_t trace;
-
- firstareanum = 0;
- for (i = 0; i < 2; i++)
- {
- VectorCopy(origin, org);
- //if test at the ground (used when bot is standing on an entity)
- if (i > 0)
- {
- VectorCopy(origin, end);
- end[2] -= 800;
- trace = AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1);
- if (!trace.startsolid)
- {
- VectorCopy(trace.endpos, org);
- } //end if
- } //end if
-
- firstareanum = 0;
- areanum = AAS_PointAreaNum(org);
- if (areanum)
- {
- firstareanum = areanum;
- if (AAS_AreaReachability(areanum)) return areanum;
- } //end if
- bestdist = 999999;
- bestareanum = 0;
- for (z = 1; z >= -1; z -= 1)
- {
- for (x = 1; x >= -1; x -= 1)
- {
- for (y = 1; y >= -1; y -= 1)
- {
- VectorCopy(org, end);
- end[0] += x * 8;
- end[1] += y * 8;
- end[2] += z * 12;
- numareas = AAS_TraceAreas(org, end, areas, points, 10);
- for (j = 0; j < numareas; j++)
- {
- if (AAS_AreaReachability(areas[j]))
- {
- VectorSubtract(points[j], org, v);
- dist = VectorLength(v);
- if (dist < bestdist)
- {
- bestareanum = areas[j];
- bestdist = dist;
- } //end if
- } //end if
- } //end for
- } //end for
- } //end for
- if (bestareanum) return bestareanum;
- } //end for
- if (!testground) break;
- } //end for
-//#ifdef DEBUG
- //botimport.Print(PRT_MESSAGE, "no reachability area\n");
-//#endif //DEBUG
- return firstareanum;
-} //end of the function BotReachabilityArea*/
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotOnMover(vec3_t origin, int entnum, aas_reachability_t *reach)
-{
- int i, modelnum;
- vec3_t mins, maxs, modelorigin, org, end;
- vec3_t angles = {0, 0, 0};
- vec3_t boxmins = {-16, -16, -8}, boxmaxs = {16, 16, 8};
- bsp_trace_t trace;
-
- modelnum = reach->facenum & 0x0000FFFF;
- //get some bsp model info
- AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);
- //
- if (!AAS_OriginOfMoverWithModelNum(modelnum, modelorigin))
- {
- botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
- return qfalse;
- } //end if
- //
- for (i = 0; i < 2; i++)
- {
- if (origin[i] > modelorigin[i] + maxs[i] + 16) return qfalse;
- if (origin[i] < modelorigin[i] + mins[i] - 16) return qfalse;
- } //end for
- //
- VectorCopy(origin, org);
- org[2] += 24;
- VectorCopy(origin, end);
- end[2] -= 48;
- //
- trace = AAS_Trace(org, boxmins, boxmaxs, end, entnum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- if (!trace.startsolid && !trace.allsolid)
- {
- //NOTE: the reachability face number is the model number of the elevator
- if (trace.ent != ENTITYNUM_NONE && AAS_EntityModelNum(trace.ent) == modelnum)
- {
- return qtrue;
- } //end if
- } //end if
- return qfalse;
-} //end of the function BotOnMover
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int MoverDown(aas_reachability_t *reach)
-{
- int modelnum;
- vec3_t mins, maxs, origin;
- vec3_t angles = {0, 0, 0};
-
- modelnum = reach->facenum & 0x0000FFFF;
- //get some bsp model info
- AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);
- //
- if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
- {
- botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
- return qfalse;
- } //end if
- //if the top of the plat is below the reachability start point
- if (origin[2] + maxs[2] < reach->start[2]) return qtrue;
- return qfalse;
-} //end of the function MoverDown
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-void BotSetBrushModelTypes(void)
-{
- int ent, modelnum;
- char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY];
-
- Com_Memset(modeltypes, 0, MAX_MODELS * sizeof(int));
- //
- for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
- {
- if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
- if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) continue;
- if (model[0]) modelnum = atoi(model+1);
- else modelnum = 0;
-
- if (modelnum < 0 || modelnum > MAX_MODELS)
- {
- botimport.Print(PRT_MESSAGE, "entity %s model number out of range\n", classname);
- continue;
- } //end if
-
- if (!Q_stricmp(classname, "func_bobbing"))
- modeltypes[modelnum] = MODELTYPE_FUNC_BOB;
- else if (!Q_stricmp(classname, "func_plat"))
- modeltypes[modelnum] = MODELTYPE_FUNC_PLAT;
- else if (!Q_stricmp(classname, "func_door"))
- modeltypes[modelnum] = MODELTYPE_FUNC_DOOR;
- else if (!Q_stricmp(classname, "func_static"))
- modeltypes[modelnum] = MODELTYPE_FUNC_STATIC;
- } //end for
-} //end of the function BotSetBrushModelTypes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotOnTopOfEntity(bot_movestate_t *ms)
-{
- vec3_t mins, maxs, end, up = {0, 0, 1};
- bsp_trace_t trace;
-
- AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
- VectorMA(ms->origin, -3, up, end);
- trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
- {
- return trace.ent;
- } //end if
- return -1;
-} //end of the function BotOnTopOfEntity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotValidTravel(vec3_t origin, aas_reachability_t *reach, int travelflags)
-{
- //if the reachability uses an unwanted travel type
- if (AAS_TravelFlagForType(reach->traveltype) & ~travelflags) return qfalse;
- //don't go into areas with bad travel types
- if (AAS_AreaContentsTravelFlags(reach->areanum) & ~travelflags) return qfalse;
- return qtrue;
-} //end of the function BotValidTravel
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotAddToAvoidReach(bot_movestate_t *ms, int number, float avoidtime)
-{
- int i;
-
- for (i = 0; i < MAX_AVOIDREACH; i++)
- {
- if (ms->avoidreach[i] == number)
- {
- if (ms->avoidreachtimes[i] > AAS_Time()) ms->avoidreachtries[i]++;
- else ms->avoidreachtries[i] = 1;
- ms->avoidreachtimes[i] = AAS_Time() + avoidtime;
- return;
- } //end if
- } //end for
- //add the reachability to the reachabilities to avoid for a while
- for (i = 0; i < MAX_AVOIDREACH; i++)
- {
- if (ms->avoidreachtimes[i] < AAS_Time())
- {
- ms->avoidreach[i] = number;
- ms->avoidreachtimes[i] = AAS_Time() + avoidtime;
- ms->avoidreachtries[i] = 1;
- return;
- } //end if
- } //end for
-} //end of the function BotAddToAvoidReach
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2)
-{
- vec3_t proj, dir;
- int j;
-
- AAS_ProjectPointOntoVector(p, lp1, lp2, proj);
- for (j = 0; j < 3; j++)
- if ((proj[j] > lp1[j] && proj[j] > lp2[j]) ||
- (proj[j] < lp1[j] && proj[j] < lp2[j]))
- break;
- if (j < 3) {
- if (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j]))
- VectorSubtract(p, lp1, dir);
- else
- VectorSubtract(p, lp2, dir);
- return VectorLengthSquared(dir);
- }
- VectorSubtract(p, proj, dir);
- return VectorLengthSquared(dir);
-} //end of the function DistanceFromLineSquared
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float VectorDistanceSquared(vec3_t p1, vec3_t p2)
-{
- vec3_t dir;
- VectorSubtract(p2, p1, dir);
- return VectorLengthSquared(dir);
-} //end of the function VectorDistanceSquared
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotAvoidSpots(vec3_t origin, aas_reachability_t *reach, bot_avoidspot_t *avoidspots, int numavoidspots)
-{
- int checkbetween, i, type;
- float squareddist, squaredradius;
-
- switch(reach->traveltype & TRAVELTYPE_MASK)
- {
- case TRAVEL_WALK: checkbetween = qtrue; break;
- case TRAVEL_CROUCH: checkbetween = qtrue; break;
- case TRAVEL_BARRIERJUMP: checkbetween = qtrue; break;
- case TRAVEL_LADDER: checkbetween = qtrue; break;
- case TRAVEL_WALKOFFLEDGE: checkbetween = qfalse; break;
- case TRAVEL_JUMP: checkbetween = qfalse; break;
- case TRAVEL_SWIM: checkbetween = qtrue; break;
- case TRAVEL_WATERJUMP: checkbetween = qtrue; break;
- case TRAVEL_TELEPORT: checkbetween = qfalse; break;
- case TRAVEL_ELEVATOR: checkbetween = qfalse; break;
- case TRAVEL_GRAPPLEHOOK: checkbetween = qfalse; break;
- case TRAVEL_ROCKETJUMP: checkbetween = qfalse; break;
- case TRAVEL_BFGJUMP: checkbetween = qfalse; break;
- case TRAVEL_JUMPPAD: checkbetween = qfalse; break;
- case TRAVEL_FUNCBOB: checkbetween = qfalse; break;
- default: checkbetween = qtrue; break;
- } //end switch
-
- type = AVOID_CLEAR;
- for (i = 0; i < numavoidspots; i++)
- {
- squaredradius = Square(avoidspots[i].radius);
- squareddist = DistanceFromLineSquared(avoidspots[i].origin, origin, reach->start);
- // if moving towards the avoid spot
- if (squareddist < squaredradius &&
- VectorDistanceSquared(avoidspots[i].origin, origin) > squareddist)
- {
- type = avoidspots[i].type;
- } //end if
- else if (checkbetween) {
- squareddist = DistanceFromLineSquared(avoidspots[i].origin, reach->start, reach->end);
- // if moving towards the avoid spot
- if (squareddist < squaredradius &&
- VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist)
- {
- type = avoidspots[i].type;
- } //end if
- } //end if
- else
- {
- VectorDistanceSquared(avoidspots[i].origin, reach->end);
- // if the reachability leads closer to the avoid spot
- if (squareddist < squaredradius &&
- VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist)
- {
- type = avoidspots[i].type;
- } //end if
- } //end else
- if (type == AVOID_ALWAYS)
- return type;
- } //end for
- return type;
-} //end of the function BotAvoidSpots
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type)
-{
- bot_movestate_t *ms;
-
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return;
- if (type == AVOID_CLEAR)
- {
- ms->numavoidspots = 0;
- return;
- } //end if
-
- if (ms->numavoidspots >= MAX_AVOIDSPOTS)
- return;
- VectorCopy(origin, ms->avoidspots[ms->numavoidspots].origin);
- ms->avoidspots[ms->numavoidspots].radius = radius;
- ms->avoidspots[ms->numavoidspots].type = type;
- ms->numavoidspots++;
-} //end of the function BotAddAvoidSpot
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotGetReachabilityToGoal(vec3_t origin, int areanum,
- int lastgoalareanum, int lastareanum,
- int *avoidreach, float *avoidreachtimes, int *avoidreachtries,
- bot_goal_t *goal, int travelflags, int movetravelflags,
- struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags)
-{
- int i, t, besttime, bestreachnum, reachnum;
- aas_reachability_t reach;
-
- //if not in a valid area
- if (!areanum) return 0;
- //
- if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goal->areanum))
- {
- travelflags |= TFL_DONOTENTER;
- movetravelflags |= TFL_DONOTENTER;
- } //end if
- //use the routing to find the next area to go to
- besttime = 0;
- bestreachnum = 0;
- //
- for (reachnum = AAS_NextAreaReachability(areanum, 0); reachnum;
- reachnum = AAS_NextAreaReachability(areanum, reachnum))
- {
-#ifdef AVOIDREACH
- //check if it isn't an reachability to avoid
- for (i = 0; i < MAX_AVOIDREACH; i++)
- {
- if (avoidreach[i] == reachnum && avoidreachtimes[i] >= AAS_Time()) break;
- } //end for
- if (i != MAX_AVOIDREACH && avoidreachtries[i] > AVOIDREACH_TRIES)
- {
-#ifdef DEBUG
- if (botDeveloper)
- {
- botimport.Print(PRT_MESSAGE, "avoiding reachability %d\n", avoidreach[i]);
- } //end if
-#endif //DEBUG
- continue;
- } //end if
-#endif //AVOIDREACH
- //get the reachability from the number
- AAS_ReachabilityFromNum(reachnum, &reach);
- //NOTE: do not go back to the previous area if the goal didn't change
- //NOTE: is this actually avoidance of local routing minima between two areas???
- if (lastgoalareanum == goal->areanum && reach.areanum == lastareanum) continue;
- //if (AAS_AreaContentsTravelFlags(reach.areanum) & ~travelflags) continue;
- //if the travel isn't valid
- if (!BotValidTravel(origin, &reach, movetravelflags)) continue;
- //get the travel time
- t = AAS_AreaTravelTimeToGoalArea(reach.areanum, reach.end, goal->areanum, travelflags);
- //if the goal area isn't reachable from the reachable area
- if (!t) continue;
- //if the bot should not use this reachability to avoid bad spots
- if (BotAvoidSpots(origin, &reach, avoidspots, numavoidspots)) {
- if (flags) {
- *flags |= MOVERESULT_BLOCKEDBYAVOIDSPOT;
- }
- continue;
- }
- //add the travel time towards the area
- t += reach.traveltime;// + AAS_AreaTravelTime(areanum, origin, reach.start);
- //if the travel time is better than the ones already found
- if (!besttime || t < besttime)
- {
- besttime = t;
- bestreachnum = reachnum;
- } //end if
- } //end for
- //
- return bestreachnum;
-} //end of the function BotGetReachabilityToGoal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotAddToTarget(vec3_t start, vec3_t end, float maxdist, float *dist, vec3_t target)
-{
- vec3_t dir;
- float curdist;
-
- VectorSubtract(end, start, dir);
- curdist = VectorNormalize(dir);
- if (*dist + curdist < maxdist)
- {
- VectorCopy(end, target);
- *dist += curdist;
- return qfalse;
- } //end if
- else
- {
- VectorMA(start, maxdist - *dist, dir, target);
- *dist = maxdist;
- return qtrue;
- } //end else
-} //end of the function BotAddToTarget
-
-int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target)
-{
- aas_reachability_t reach;
- int reachnum, lastareanum;
- bot_movestate_t *ms;
- vec3_t end;
- float dist;
-
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return qfalse;
- reachnum = 0;
- //if the bot has no goal or no last reachability
- if (!ms->lastreachnum || !goal) return qfalse;
-
- reachnum = ms->lastreachnum;
- VectorCopy(ms->origin, end);
- lastareanum = ms->lastareanum;
- dist = 0;
- while(reachnum && dist < lookahead)
- {
- AAS_ReachabilityFromNum(reachnum, &reach);
- if (BotAddToTarget(end, reach.start, lookahead, &dist, target)) return qtrue;
- //never look beyond teleporters
- if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_TELEPORT) return qtrue;
- //never look beyond the weapon jump point
- if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP) return qtrue;
- if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_BFGJUMP) return qtrue;
- //don't add jump pad distances
- if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_JUMPPAD &&
- (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR &&
- (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB)
- {
- if (BotAddToTarget(reach.start, reach.end, lookahead, &dist, target)) return qtrue;
- } //end if
- reachnum = BotGetReachabilityToGoal(reach.end, reach.areanum,
- ms->lastgoalareanum, lastareanum,
- ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
- goal, travelflags, travelflags, NULL, 0, NULL);
- VectorCopy(reach.end, end);
- lastareanum = reach.areanum;
- if (lastareanum == goal->areanum)
- {
- BotAddToTarget(reach.end, goal->origin, lookahead, &dist, target);
- return qtrue;
- } //end if
- } //end while
- //
- return qfalse;
-} //end of the function BotMovementViewTarget
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotVisible(int ent, vec3_t eye, vec3_t target)
-{
- bsp_trace_t trace;
-
- trace = AAS_Trace(eye, NULL, NULL, target, ent, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- if (trace.fraction >= 1) return qtrue;
- return qfalse;
-} //end of the function BotVisible
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target)
-{
- aas_reachability_t reach;
- int reachnum, lastgoalareanum, lastareanum, i;
- int avoidreach[MAX_AVOIDREACH];
- float avoidreachtimes[MAX_AVOIDREACH];
- int avoidreachtries[MAX_AVOIDREACH];
- vec3_t end;
-
- //if the bot has no goal or no last reachability
- if (!goal) return qfalse;
- //if the areanum is not valid
- if (!areanum) return qfalse;
- //if the goal areanum is not valid
- if (!goal->areanum) return qfalse;
-
- Com_Memset(avoidreach, 0, MAX_AVOIDREACH * sizeof(int));
- lastgoalareanum = goal->areanum;
- lastareanum = areanum;
- VectorCopy(origin, end);
- //only do 20 hops
- for (i = 0; i < 20 && (areanum != goal->areanum); i++)
- {
- //
- reachnum = BotGetReachabilityToGoal(end, areanum,
- lastgoalareanum, lastareanum,
- avoidreach, avoidreachtimes, avoidreachtries,
- goal, travelflags, travelflags, NULL, 0, NULL);
- if (!reachnum) return qfalse;
- AAS_ReachabilityFromNum(reachnum, &reach);
- //
- if (BotVisible(goal->entitynum, goal->origin, reach.start))
- {
- VectorCopy(reach.start, target);
- return qtrue;
- } //end if
- //
- if (BotVisible(goal->entitynum, goal->origin, reach.end))
- {
- VectorCopy(reach.end, target);
- return qtrue;
- } //end if
- //
- if (reach.areanum == goal->areanum)
- {
- VectorCopy(reach.end, target);
- return qtrue;
- } //end if
- //
- lastareanum = areanum;
- areanum = reach.areanum;
- VectorCopy(reach.end, end);
- //
- } //end while
- //
- return qfalse;
-} //end of the function BotPredictVisiblePosition
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void MoverBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter)
-{
- int modelnum;
- vec3_t mins, maxs, origin, mids;
- vec3_t angles = {0, 0, 0};
-
- modelnum = reach->facenum & 0x0000FFFF;
- //get some bsp model info
- AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);
- //
- if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
- {
- botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
- } //end if
- //get a point just above the plat in the bottom position
- VectorAdd(mins, maxs, mids);
- VectorMA(origin, 0.5, mids, bottomcenter);
- bottomcenter[2] = reach->start[2];
-} //end of the function MoverBottomCenter
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float BotGapDistance(vec3_t origin, vec3_t hordir, int entnum)
-{
- float dist, startz;
- vec3_t start, end;
- aas_trace_t trace;
-
- //do gap checking
- startz = origin[2];
- //this enables walking down stairs more fluidly
- {
- VectorCopy(origin, start);
- VectorCopy(origin, end);
- end[2] -= 60;
- trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum);
- if (trace.fraction >= 1) return 1;
- startz = trace.endpos[2] + 1;
- }
- //
- for (dist = 8; dist <= 100; dist += 8)
- {
- VectorMA(origin, dist, hordir, start);
- start[2] = startz + 24;
- VectorCopy(start, end);
- end[2] -= 48 + sv_maxbarrier->value;
- trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum);
- //if solid is found the bot can't walk any further and fall into a gap
- if (!trace.startsolid)
- {
- //if it is a gap
- if (trace.endpos[2] < startz - sv_maxstep->value - 8)
- {
- VectorCopy(trace.endpos, end);
- end[2] -= 20;
- if (AAS_PointContents(end) & CONTENTS_WATER) break;
- //if a gap is found slow down
- //botimport.Print(PRT_MESSAGE, "gap at %f\n", dist);
- return dist;
- } //end if
- startz = trace.endpos[2];
- } //end if
- } //end for
- return 0;
-} //end of the function BotGapDistance
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotCheckBarrierJump(bot_movestate_t *ms, vec3_t dir, float speed)
-{
- vec3_t start, hordir, end;
- aas_trace_t trace;
-
- VectorCopy(ms->origin, end);
- end[2] += sv_maxbarrier->value;
- //trace right up
- trace = AAS_TraceClientBBox(ms->origin, end, PRESENCE_NORMAL, ms->entitynum);
- //this shouldn't happen... but we check anyway
- if (trace.startsolid) return qfalse;
- //if very low ceiling it isn't possible to jump up to a barrier
- if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse;
- //
- hordir[0] = dir[0];
- hordir[1] = dir[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- VectorMA(ms->origin, ms->thinktime * speed * 0.5, hordir, end);
- VectorCopy(trace.endpos, start);
- end[2] = trace.endpos[2];
- //trace from previous trace end pos horizontally in the move direction
- trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum);
- //again this shouldn't happen
- if (trace.startsolid) return qfalse;
- //
- VectorCopy(trace.endpos, start);
- VectorCopy(trace.endpos, end);
- end[2] = ms->origin[2];
- //trace down from the previous trace end pos
- trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum);
- //if solid
- if (trace.startsolid) return qfalse;
- //if no obstacle at all
- if (trace.fraction >= 1.0) return qfalse;
- //if less than the maximum step height
- if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse;
- //
- EA_Jump(ms->client);
- EA_Move(ms->client, hordir, speed);
- ms->moveflags |= MFL_BARRIERJUMP;
- //there is a barrier
- return qtrue;
-} //end of the function BotCheckBarrierJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotSwimInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type)
-{
- vec3_t normdir;
-
- VectorCopy(dir, normdir);
- VectorNormalize(normdir);
- EA_Move(ms->client, normdir, speed);
- return qtrue;
-} //end of the function BotSwimInDirection
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotWalkInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type)
-{
- vec3_t hordir, cmdmove, velocity, tmpdir, origin;
- int presencetype, maxframes, cmdframes, stopevent;
- aas_clientmove_t move;
- float dist;
-
- if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND;
- //if the bot is on the ground
- if (ms->moveflags & MFL_ONGROUND)
- {
- //if there is a barrier the bot can jump on
- if (BotCheckBarrierJump(ms, dir, speed)) return qtrue;
- //remove barrier jump flag
- ms->moveflags &= ~MFL_BARRIERJUMP;
- //get the presence type for the movement
- if ((type & MOVE_CROUCH) && !(type & MOVE_JUMP)) presencetype = PRESENCE_CROUCH;
- else presencetype = PRESENCE_NORMAL;
- //horizontal direction
- hordir[0] = dir[0];
- hordir[1] = dir[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //if the bot is not supposed to jump
- if (!(type & MOVE_JUMP))
- {
- //if there is a gap, try to jump over it
- if (BotGapDistance(ms->origin, hordir, ms->entitynum) > 0) type |= MOVE_JUMP;
- } //end if
- //get command movement
- VectorScale(hordir, speed, cmdmove);
- VectorCopy(ms->velocity, velocity);
- //
- if (type & MOVE_JUMP)
- {
- //botimport.Print(PRT_MESSAGE, "trying jump\n");
- cmdmove[2] = 400;
- maxframes = PREDICTIONTIME_JUMP / 0.1;
- cmdframes = 1;
- stopevent = SE_HITGROUND|SE_HITGROUNDDAMAGE|
- SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA;
- } //end if
- else
- {
- maxframes = 2;
- cmdframes = 2;
- stopevent = SE_HITGROUNDDAMAGE|
- SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA;
- } //end else
- //AAS_ClearShownDebugLines();
- //
- VectorCopy(ms->origin, origin);
- origin[2] += 0.5;
- AAS_PredictClientMovement(&move, ms->entitynum, origin, presencetype, qtrue,
- velocity, cmdmove, cmdframes, maxframes, 0.1f,
- stopevent, 0, qfalse);//qtrue);
- //if prediction time wasn't enough to fully predict the movement
- if (move.frames >= maxframes && (type & MOVE_JUMP))
- {
- //botimport.Print(PRT_MESSAGE, "client %d: max prediction frames\n", ms->client);
- return qfalse;
- } //end if
- //don't enter slime or lava and don't fall from too high
- if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))
- {
- //botimport.Print(PRT_MESSAGE, "client %d: would be hurt ", ms->client);
- //if (move.stopevent & SE_ENTERSLIME) botimport.Print(PRT_MESSAGE, "slime\n");
- //if (move.stopevent & SE_ENTERLAVA) botimport.Print(PRT_MESSAGE, "lava\n");
- //if (move.stopevent & SE_HITGROUNDDAMAGE) botimport.Print(PRT_MESSAGE, "hitground\n");
- return qfalse;
- } //end if
- //if ground was hit
- if (move.stopevent & SE_HITGROUND)
- {
- //check for nearby gap
- VectorNormalize2(move.velocity, tmpdir);
- dist = BotGapDistance(move.endpos, tmpdir, ms->entitynum);
- if (dist > 0) return qfalse;
- //
- dist = BotGapDistance(move.endpos, hordir, ms->entitynum);
- if (dist > 0) return qfalse;
- } //end if
- //get horizontal movement
- tmpdir[0] = move.endpos[0] - ms->origin[0];
- tmpdir[1] = move.endpos[1] - ms->origin[1];
- tmpdir[2] = 0;
- //
- //AAS_DrawCross(move.endpos, 4, LINECOLOR_BLUE);
- //the bot is blocked by something
- if (VectorLength(tmpdir) < speed * ms->thinktime * 0.5) return qfalse;
- //perform the movement
- if (type & MOVE_JUMP) EA_Jump(ms->client);
- if (type & MOVE_CROUCH) EA_Crouch(ms->client);
- EA_Move(ms->client, hordir, speed);
- //movement was succesfull
- return qtrue;
- } //end if
- else
- {
- if (ms->moveflags & MFL_BARRIERJUMP)
- {
- //if near the top or going down
- if (ms->velocity[2] < 50)
- {
- EA_Move(ms->client, dir, speed);
- } //end if
- } //end if
- //FIXME: do air control to avoid hazards
- return qtrue;
- } //end else
-} //end of the function BotWalkInDirection
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type)
-{
- bot_movestate_t *ms;
-
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return qfalse;
- //if swimming
- if (AAS_Swimming(ms->origin))
- {
- return BotSwimInDirection(ms, dir, speed, type);
- } //end if
- else
- {
- return BotWalkInDirection(ms, dir, speed, type);
- } //end else
-} //end of the function BotMoveInDirection
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Intersection(vec2_t p1, vec2_t p2, vec2_t p3, vec2_t p4, vec2_t out)
-{
- float x1, dx1, dy1, x2, dx2, dy2, d;
-
- dx1 = p2[0] - p1[0];
- dy1 = p2[1] - p1[1];
- dx2 = p4[0] - p3[0];
- dy2 = p4[1] - p3[1];
-
- d = dy1 * dx2 - dx1 * dy2;
- if (d != 0)
- {
- x1 = p1[1] * dx1 - p1[0] * dy1;
- x2 = p3[1] * dx2 - p3[0] * dy2;
- out[0] = (int) ((dx1 * x2 - dx2 * x1) / d);
- out[1] = (int) ((dy1 * x2 - dy2 * x1) / d);
- return qtrue;
- } //end if
- else
- {
- return qfalse;
- } //end else
-} //end of the function Intersection
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotCheckBlocked(bot_movestate_t *ms, vec3_t dir, int checkbottom, bot_moveresult_t *result)
-{
- vec3_t mins, maxs, end, up = {0, 0, 1};
- bsp_trace_t trace;
-
- //test for entities obstructing the bot's path
- AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
- //
- if (fabs(DotProduct(dir, up)) < 0.7)
- {
- mins[2] += sv_maxstep->value; //if the bot can step on
- maxs[2] -= 10; //a little lower to avoid low ceiling
- } //end if
- VectorMA(ms->origin, 3, dir, end);
- trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY);
- //if not started in solid and not hitting the world entity
- if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
- {
- result->blocked = qtrue;
- result->blockentity = trace.ent;
-#ifdef DEBUG
- //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client);
-#endif //DEBUG
- } //end if
- //if not in an area with reachability
- else if (checkbottom && !AAS_AreaReachability(ms->areanum))
- {
- //check if the bot is standing on something
- AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
- VectorMA(ms->origin, -3, up, end);
- trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
- {
- result->blocked = qtrue;
- result->blockentity = trace.ent;
- result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
-#ifdef DEBUG
- //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client);
-#endif //DEBUG
- } //end if
- } //end else
-} //end of the function BotCheckBlocked
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- float dist, speed;
- vec3_t hordir;
- bot_moveresult_t_cleared( result );
-
- //first walk straight to the reachability start
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
- //
- if (dist < 10)
- {
- //walk straight to the reachability end
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- } //end if
- //if going towards a crouch area
- if (!(AAS_AreaPresenceType(reach->areanum) & PRESENCE_NORMAL))
- {
- //if pretty close to the reachable area
- if (dist < 20) EA_Crouch(ms->client);
- } //end if
- //
- dist = BotGapDistance(ms->origin, hordir, ms->entitynum);
- //
- if (ms->moveflags & MFL_WALK)
- {
- if (dist > 0) speed = 200 - (180 - 1 * dist);
- else speed = 200;
- EA_Walk(ms->client);
- } //end if
- else
- {
- if (dist > 0) speed = 400 - (360 - 2 * dist);
- else speed = 400;
- } //end else
- //elemantary action move in direction
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_Walk
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir;
- float dist, speed;
- bot_moveresult_t_cleared( result );
- //if not on the ground and changed areas... don't walk back!!
- //(doesn't seem to help)
- /*
- ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
- if (ms->areanum == reach->areanum)
- {
-#ifdef DEBUG
- botimport.Print(PRT_MESSAGE, "BotFinishTravel_Walk: already in reach area\n");
-#endif //DEBUG
- return result;
- } //end if*/
- //go straight to the reachability end
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- if (dist > 100) dist = 100;
- speed = 400 - (400 - 3 * dist);
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotFinishTravel_Walk
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Crouch(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- float speed;
- vec3_t hordir;
- bot_moveresult_t_cleared( result );
-
- //
- speed = 400;
- //walk straight to reachability end
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
- //elemantary actions
- EA_Crouch(ms->client);
- EA_Move(ms->client, hordir, speed);
- //
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_Crouch
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- float dist, speed;
- vec3_t hordir;
- bot_moveresult_t_cleared( result );
-
- //walk straight to reachability start
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
- //if pretty close to the barrier
- if (dist < 9)
- {
- EA_Jump(ms->client);
- } //end if
- else
- {
- if (dist > 60) dist = 60;
- speed = 360 - (360 - 6 * dist);
- EA_Move(ms->client, hordir, speed);
- } //end else
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_BarrierJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- float dist;
- vec3_t hordir;
- bot_moveresult_t_cleared( result );
-
- //if near the top or going down
- if (ms->velocity[2] < 250)
- {
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
- //
- EA_Move(ms->client, hordir, 400);
- VectorCopy(hordir, result.movedir);
- } //end if
- //
- return result;
-} //end of the function BotFinishTravel_BarrierJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Swim(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t dir;
- bot_moveresult_t_cleared( result );
-
- //swim straight to reachability end
- VectorSubtract(reach->start, ms->origin, dir);
- VectorNormalize(dir);
- //
- BotCheckBlocked(ms, dir, qtrue, &result);
- //elemantary actions
- EA_Move(ms->client, dir, 400);
- //
- VectorCopy(dir, result.movedir);
- Vector2Angles(dir, result.ideal_viewangles);
- result.flags |= MOVERESULT_SWIMVIEW;
- //
- return result;
-} //end of the function BotTravel_Swim
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t dir, hordir;
- float dist;
- bot_moveresult_t_cleared( result );
-
- //swim straight to reachability end
- VectorSubtract(reach->end, ms->origin, dir);
- VectorCopy(dir, hordir);
- hordir[2] = 0;
- dir[2] += 15 + crandom() * 40;
- //botimport.Print(PRT_MESSAGE, "BotTravel_WaterJump: dir[2] = %f\n", dir[2]);
- VectorNormalize(dir);
- dist = VectorNormalize(hordir);
- //elemantary actions
- //EA_Move(ms->client, dir, 400);
- EA_MoveForward(ms->client);
- //move up if close to the actual out of water jump spot
- if (dist < 40) EA_MoveUp(ms->client);
- //set the ideal view angles
- Vector2Angles(dir, result.ideal_viewangles);
- result.flags |= MOVERESULT_MOVEMENTVIEW;
- //
- VectorCopy(dir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_WaterJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t dir, pnt;
- float dist;
- bot_moveresult_t_cleared( result );
-
- //botimport.Print(PRT_MESSAGE, "BotFinishTravel_WaterJump\n");
- //if waterjumping there's nothing to do
- if (ms->moveflags & MFL_WATERJUMP) return result;
- //if not touching any water anymore don't do anything
- //otherwise the bot sometimes keeps jumping?
- VectorCopy(ms->origin, pnt);
- pnt[2] -= 32; //extra for q2dm4 near red armor/mega health
- if (!(AAS_PointContents(pnt) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return result;
- //swim straight to reachability end
- VectorSubtract(reach->end, ms->origin, dir);
- dir[0] += crandom() * 10;
- dir[1] += crandom() * 10;
- dir[2] += 70 + crandom() * 10;
- dist = VectorNormalize(dir);
- //elemantary actions
- EA_Move(ms->client, dir, 400);
- //set the ideal view angles
- Vector2Angles(dir, result.ideal_viewangles);
- result.flags |= MOVERESULT_MOVEMENTVIEW;
- //
- VectorCopy(dir, result.movedir);
- //
- return result;
-} //end of the function BotFinishTravel_WaterJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir, dir;
- float dist, speed, reachhordist;
- bot_moveresult_t_cleared( result );
-
- //check if the bot is blocked by anything
- VectorSubtract(reach->start, ms->origin, dir);
- VectorNormalize(dir);
- BotCheckBlocked(ms, dir, qtrue, &result);
- //if the reachability start and end are practially above each other
- VectorSubtract(reach->end, reach->start, dir);
- dir[2] = 0;
- reachhordist = VectorLength(dir);
- //walk straight to the reachability start
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //if pretty close to the start focus on the reachability end
- if (dist < 48)
- {
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //
- if (reachhordist < 20)
- {
- speed = 100;
- } //end if
- else if (!AAS_HorizontalVelocityForJump(0, reach->start, reach->end, &speed))
- {
- speed = 400;
- } //end if
- } //end if
- else
- {
- if (reachhordist < 20)
- {
- if (dist > 64) dist = 64;
- speed = 400 - (256 - 4 * dist);
- } //end if
- else
- {
- speed = 400;
- } //end else
- } //end else
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
- //elemantary action
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_WalkOffLedge
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotAirControl(vec3_t origin, vec3_t velocity, vec3_t goal, vec3_t dir, float *speed)
-{
- vec3_t org, vel;
- float dist;
- int i;
-
- VectorCopy(origin, org);
- VectorScale(velocity, 0.1, vel);
- for (i = 0; i < 50; i++)
- {
- vel[2] -= sv_gravity->value * 0.01;
- //if going down and next position would be below the goal
- if (vel[2] < 0 && org[2] + vel[2] < goal[2])
- {
- VectorScale(vel, (goal[2] - org[2]) / vel[2], vel);
- VectorAdd(org, vel, org);
- VectorSubtract(goal, org, dir);
- dist = VectorNormalize(dir);
- if (dist > 32) dist = 32;
- *speed = 400 - (400 - 13 * dist);
- return qtrue;
- } //end if
- else
- {
- VectorAdd(org, vel, org);
- } //end else
- } //end for
- VectorSet(dir, 0, 0, 0);
- *speed = 400;
- return qfalse;
-} //end of the function BotAirControl
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t dir, hordir, end, v;
- float dist, speed;
- bot_moveresult_t_cleared( result );
-
- //
- VectorSubtract(reach->end, ms->origin, dir);
- BotCheckBlocked(ms, dir, qtrue, &result);
- //
- VectorSubtract(reach->end, ms->origin, v);
- v[2] = 0;
- dist = VectorNormalize(v);
- if (dist > 16) VectorMA(reach->end, 16, v, end);
- else VectorCopy(reach->end, end);
- //
- if (!BotAirControl(ms->origin, ms->velocity, end, hordir, &speed))
- {
- //go straight to the reachability end
- VectorCopy(dir, hordir);
- hordir[2] = 0;
- //
- dist = VectorNormalize(hordir);
- speed = 400;
- } //end if
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotFinishTravel_WalkOffLedge
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-/*
-bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir;
- float dist, gapdist, speed, horspeed, sv_jumpvel;
- bot_moveresult_t_cleared( result );
-
- //
- sv_jumpvel = botlibglobals.sv_jumpvel->value;
- //walk straight to the reachability start
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- speed = 350;
- //
- gapdist = BotGapDistance(ms, hordir, ms->entitynum);
- //if pretty close to the start focus on the reachability end
- if (dist < 50 || (gapdist && gapdist < 50))
- {
- //NOTE: using max speed (400) works best
- //if (AAS_HorizontalVelocityForJump(sv_jumpvel, ms->origin, reach->end, &horspeed))
- //{
- // speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value;
- //} //end if
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- VectorNormalize(hordir);
- //elemantary action jump
- EA_Jump(ms->client);
- //
- ms->jumpreach = ms->lastreachnum;
- speed = 600;
- } //end if
- else
- {
- if (AAS_HorizontalVelocityForJump(sv_jumpvel, reach->start, reach->end, &horspeed))
- {
- speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value;
- } //end if
- } //end else
- //elemantary action
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_Jump*/
-/*
-bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir, dir1, dir2, mins, maxs, start, end;
- float dist1, dist2, speed;
- bot_moveresult_t_cleared( result );
- bsp_trace_t trace;
-
- //
- hordir[0] = reach->start[0] - reach->end[0];
- hordir[1] = reach->start[1] - reach->end[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //
- VectorCopy(reach->start, start);
- start[2] += 1;
- //minus back the bouding box size plus 16
- VectorMA(reach->start, 80, hordir, end);
- //
- AAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, mins, maxs);
- //check for solids
- trace = AAS_Trace(start, mins, maxs, end, ms->entitynum, MASK_PLAYERSOLID);
- if (trace.startsolid) VectorCopy(start, trace.endpos);
- //check for a gap
- for (dist1 = 0; dist1 < 80; dist1 += 10)
- {
- VectorMA(start, dist1+10, hordir, end);
- end[2] += 1;
- if (AAS_PointAreaNum(end) != ms->reachareanum) break;
- } //end for
- if (dist1 < 80) VectorMA(reach->start, dist1, hordir, trace.endpos);
-// dist1 = BotGapDistance(start, hordir, ms->entitynum);
-// if (dist1 && dist1 <= trace.fraction * 80) VectorMA(reach->start, dist1-20, hordir, trace.endpos);
- //
- VectorSubtract(ms->origin, reach->start, dir1);
- dir1[2] = 0;
- dist1 = VectorNormalize(dir1);
- VectorSubtract(ms->origin, trace.endpos, dir2);
- dir2[2] = 0;
- dist2 = VectorNormalize(dir2);
- //if just before the reachability start
- if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5)
- {
- //botimport.Print(PRT_MESSAGE, "between jump start and run to point\n");
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //elemantary action jump
- if (dist1 < 24) EA_Jump(ms->client);
- else if (dist1 < 32) EA_DelayedJump(ms->client);
- EA_Move(ms->client, hordir, 600);
- //
- ms->jumpreach = ms->lastreachnum;
- } //end if
- else
- {
- //botimport.Print(PRT_MESSAGE, "going towards run to point\n");
- hordir[0] = trace.endpos[0] - ms->origin[0];
- hordir[1] = trace.endpos[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //
- if (dist2 > 80) dist2 = 80;
- speed = 400 - (400 - 5 * dist2);
- EA_Move(ms->client, hordir, speed);
- } //end else
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_Jump*/
-//*
-bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir, dir1, dir2, start, end, runstart;
-// vec3_t runstart, dir1, dir2, hordir;
- float dist1, dist2, speed;
- bot_moveresult_t_cleared( result );
-
- //
- AAS_JumpReachRunStart(reach, runstart);
- //*
- hordir[0] = runstart[0] - reach->start[0];
- hordir[1] = runstart[1] - reach->start[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //
- VectorCopy(reach->start, start);
- start[2] += 1;
- VectorMA(reach->start, 80, hordir, runstart);
- //check for a gap
- for (dist1 = 0; dist1 < 80; dist1 += 10)
- {
- VectorMA(start, dist1+10, hordir, end);
- end[2] += 1;
- if (AAS_PointAreaNum(end) != ms->reachareanum) break;
- } //end for
- if (dist1 < 80) VectorMA(reach->start, dist1, hordir, runstart);
- //
- VectorSubtract(ms->origin, reach->start, dir1);
- dir1[2] = 0;
- dist1 = VectorNormalize(dir1);
- VectorSubtract(ms->origin, runstart, dir2);
- dir2[2] = 0;
- dist2 = VectorNormalize(dir2);
- //if just before the reachability start
- if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5)
- {
-// botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //elemantary action jump
- if (dist1 < 24) EA_Jump(ms->client);
- else if (dist1 < 32) EA_DelayedJump(ms->client);
- EA_Move(ms->client, hordir, 600);
- //
- ms->jumpreach = ms->lastreachnum;
- } //end if
- else
- {
-// botimport.Print(PRT_MESSAGE, "going towards run start point\n");
- hordir[0] = runstart[0] - ms->origin[0];
- hordir[1] = runstart[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //
- if (dist2 > 80) dist2 = 80;
- speed = 400 - (400 - 5 * dist2);
- EA_Move(ms->client, hordir, speed);
- } //end else
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_Jump*/
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir, hordir2;
- float speed, dist;
- bot_moveresult_t_cleared( result );
-
- //if not jumped yet
- if (!ms->jumpreach) return result;
- //go straight to the reachability end
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- hordir2[0] = reach->end[0] - reach->start[0];
- hordir2[1] = reach->end[1] - reach->start[1];
- hordir2[2] = 0;
- VectorNormalize(hordir2);
- //
- if (DotProduct(hordir, hordir2) < -0.5 && dist < 24) return result;
- //always use max speed when traveling through the air
- speed = 800;
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotFinishTravel_Jump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Ladder(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- //float dist, speed;
- vec3_t dir, viewdir;//, hordir;
- vec3_t origin = {0, 0, 0};
-// vec3_t up = {0, 0, 1};
- bot_moveresult_t_cleared( result );
-
- //
-// if ((ms->moveflags & MFL_AGAINSTLADDER))
- //NOTE: not a good idea for ladders starting in water
- // || !(ms->moveflags & MFL_ONGROUND))
- {
- //botimport.Print(PRT_MESSAGE, "against ladder or not on ground\n");
- VectorSubtract(reach->end, ms->origin, dir);
- VectorNormalize(dir);
- //set the ideal view angles, facing the ladder up or down
- viewdir[0] = dir[0];
- viewdir[1] = dir[1];
- viewdir[2] = 3 * dir[2];
- Vector2Angles(viewdir, result.ideal_viewangles);
- //elemantary action
- EA_Move(ms->client, origin, 0);
- EA_MoveForward(ms->client);
- //set movement view flag so the AI can see the view is focussed
- result.flags |= MOVERESULT_MOVEMENTVIEW;
- } //end if
-/* else
- {
- //botimport.Print(PRT_MESSAGE, "moving towards ladder\n");
- VectorSubtract(reach->end, ms->origin, dir);
- //make sure the horizontal movement is large anough
- VectorCopy(dir, hordir);
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- dir[0] = hordir[0];
- dir[1] = hordir[1];
- if (dir[2] > 0) dir[2] = 1;
- else dir[2] = -1;
- if (dist > 50) dist = 50;
- speed = 400 - (200 - 4 * dist);
- EA_Move(ms->client, dir, speed);
- } //end else*/
- //save the movement direction
- VectorCopy(dir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_Ladder
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Teleport(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir;
- float dist;
- bot_moveresult_t_cleared( result );
-
- //if the bot is being teleported
- if (ms->moveflags & MFL_TELEPORTED) return result;
-
- //walk straight to center of the teleporter
- VectorSubtract(reach->start, ms->origin, hordir);
- if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
-
- if (dist < 30) EA_Move(ms->client, hordir, 200);
- else EA_Move(ms->client, hordir, 400);
-
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
-
- VectorCopy(hordir, result.movedir);
- return result;
-} //end of the function BotTravel_Teleport
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t dir, dir1, dir2, hordir, bottomcenter;
- float dist, dist1, dist2, speed;
- bot_moveresult_t_cleared( result );
-
- //if standing on the plat
- if (BotOnMover(ms->origin, ms->entitynum, reach))
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "bot on elevator\n");
-#endif //DEBUG_ELEVATOR
- //if vertically not too far from the end point
- if (abs(ms->origin[2] - reach->end[2]) < sv_maxbarrier->value)
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "bot moving to end\n");
-#endif //DEBUG_ELEVATOR
- //move to the end point
- VectorSubtract(reach->end, ms->origin, hordir);
- hordir[2] = 0;
- VectorNormalize(hordir);
- if (!BotCheckBarrierJump(ms, hordir, 100))
- {
- EA_Move(ms->client, hordir, 400);
- } //end if
- VectorCopy(hordir, result.movedir);
- } //end else
- //if not really close to the center of the elevator
- else
- {
- MoverBottomCenter(reach, bottomcenter);
- VectorSubtract(bottomcenter, ms->origin, hordir);
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- if (dist > 10)
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "bot moving to center\n");
-#endif //DEBUG_ELEVATOR
- //move to the center of the plat
- if (dist > 100) dist = 100;
- speed = 400 - (400 - 4 * dist);
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- } //end if
- } //end else
- } //end if
- else
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "bot not on elevator\n");
-#endif //DEBUG_ELEVATOR
- //if very near the reachability end
- VectorSubtract(reach->end, ms->origin, dir);
- dist = VectorLength(dir);
- if (dist < 64)
- {
- if (dist > 60) dist = 60;
- speed = 360 - (360 - 6 * dist);
- //
- if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50))
- {
- if (speed > 5) EA_Move(ms->client, dir, speed);
- } //end if
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- //stop using this reachability
- ms->reachability_time = 0;
- return result;
- } //end if
- //get direction and distance to reachability start
- VectorSubtract(reach->start, ms->origin, dir1);
- if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0;
- dist1 = VectorNormalize(dir1);
- //if the elevator isn't down
- if (!MoverDown(reach))
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "elevator not down\n");
-#endif //DEBUG_ELEVATOR
- dist = dist1;
- VectorCopy(dir1, dir);
- //
- BotCheckBlocked(ms, dir, qfalse, &result);
- //
- if (dist > 60) dist = 60;
- speed = 360 - (360 - 6 * dist);
- //
- if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
- {
- if (speed > 5) EA_Move(ms->client, dir, speed);
- } //end if
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- //this isn't a failure... just wait till the elevator comes down
- result.type = RESULTTYPE_ELEVATORUP;
- result.flags |= MOVERESULT_WAITING;
- return result;
- } //end if
- //get direction and distance to elevator bottom center
- MoverBottomCenter(reach, bottomcenter);
- VectorSubtract(bottomcenter, ms->origin, dir2);
- if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0;
- dist2 = VectorNormalize(dir2);
- //if very close to the reachability start or
- //closer to the elevator center or
- //between reachability start and elevator center
- if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0)
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "bot moving to center\n");
-#endif //DEBUG_ELEVATOR
- dist = dist2;
- VectorCopy(dir2, dir);
- } //end if
- else //closer to the reachability start
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "bot moving to start\n");
-#endif //DEBUG_ELEVATOR
- dist = dist1;
- VectorCopy(dir1, dir);
- } //end else
- //
- BotCheckBlocked(ms, dir, qfalse, &result);
- //
- if (dist > 60) dist = 60;
- speed = 400 - (400 - 6 * dist);
- //
- if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
- {
- EA_Move(ms->client, dir, speed);
- } //end if
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- } //end else
- return result;
-} //end of the function BotTravel_Elevator
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t bottomcenter, bottomdir, topdir;
- bot_moveresult_t_cleared( result );
-
- //
- MoverBottomCenter(reach, bottomcenter);
- VectorSubtract(bottomcenter, ms->origin, bottomdir);
- //
- VectorSubtract(reach->end, ms->origin, topdir);
- //
- if (fabs(bottomdir[2]) < fabs(topdir[2]))
- {
- VectorNormalize(bottomdir);
- EA_Move(ms->client, bottomdir, 300);
- } //end if
- else
- {
- VectorNormalize(topdir);
- EA_Move(ms->client, topdir, 300);
- } //end else
- return result;
-} //end of the function BotFinishTravel_Elevator
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotFuncBobStartEnd(aas_reachability_t *reach, vec3_t start, vec3_t end, vec3_t origin)
-{
- int spawnflags, modelnum;
- vec3_t mins, maxs, mid, angles = {0, 0, 0};
- int num0, num1;
-
- modelnum = reach->facenum & 0x0000FFFF;
- if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
- {
- botimport.Print(PRT_MESSAGE, "BotFuncBobStartEnd: no entity with model %d\n", modelnum);
- VectorSet(start, 0, 0, 0);
- VectorSet(end, 0, 0, 0);
- return;
- } //end if
- AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);
- VectorAdd(mins, maxs, mid);
- VectorScale(mid, 0.5, mid);
- VectorCopy(mid, start);
- VectorCopy(mid, end);
- spawnflags = reach->facenum >> 16;
- num0 = reach->edgenum >> 16;
- if (num0 > 0x00007FFF) num0 |= 0xFFFF0000;
- num1 = reach->edgenum & 0x0000FFFF;
- if (num1 > 0x00007FFF) num1 |= 0xFFFF0000;
- if (spawnflags & 1)
- {
- start[0] = num0;
- end[0] = num1;
- //
- origin[0] += mid[0];
- origin[1] = mid[1];
- origin[2] = mid[2];
- } //end if
- else if (spawnflags & 2)
- {
- start[1] = num0;
- end[1] = num1;
- //
- origin[0] = mid[0];
- origin[1] += mid[1];
- origin[2] = mid[2];
- } //end else if
- else
- {
- start[2] = num0;
- end[2] = num1;
- //
- origin[0] = mid[0];
- origin[1] = mid[1];
- origin[2] += mid[2];
- } //end else
-} //end of the function BotFuncBobStartEnd
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t dir, dir1, dir2, hordir, bottomcenter, bob_start, bob_end, bob_origin;
- float dist, dist1, dist2, speed;
- bot_moveresult_t_cleared( result );
-
- //
- BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin);
- //if standing ontop of the func_bobbing
- if (BotOnMover(ms->origin, ms->entitynum, reach))
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot on func_bobbing\n");
-#endif
- //if near end point of reachability
- VectorSubtract(bob_origin, bob_end, dir);
- if (VectorLength(dir) < 24)
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot moving to reachability end\n");
-#endif
- //move to the end point
- VectorSubtract(reach->end, ms->origin, hordir);
- hordir[2] = 0;
- VectorNormalize(hordir);
- if (!BotCheckBarrierJump(ms, hordir, 100))
- {
- EA_Move(ms->client, hordir, 400);
- } //end if
- VectorCopy(hordir, result.movedir);
- } //end else
- //if not really close to the center of the elevator
- else
- {
- MoverBottomCenter(reach, bottomcenter);
- VectorSubtract(bottomcenter, ms->origin, hordir);
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- if (dist > 10)
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n");
-#endif
- //move to the center of the plat
- if (dist > 100) dist = 100;
- speed = 400 - (400 - 4 * dist);
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- } //end if
- } //end else
- } //end if
- else
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot not ontop of func_bobbing\n");
-#endif
- //if very near the reachability end
- VectorSubtract(reach->end, ms->origin, dir);
- dist = VectorLength(dir);
- if (dist < 64)
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot moving to end\n");
-#endif
- if (dist > 60) dist = 60;
- speed = 360 - (360 - 6 * dist);
- //if swimming or no barrier jump
- if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50))
- {
- if (speed > 5) EA_Move(ms->client, dir, speed);
- } //end if
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- //stop using this reachability
- ms->reachability_time = 0;
- return result;
- } //end if
- //get direction and distance to reachability start
- VectorSubtract(reach->start, ms->origin, dir1);
- if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0;
- dist1 = VectorNormalize(dir1);
- //if func_bobbing is Not it's start position
- VectorSubtract(bob_origin, bob_start, dir);
- if (VectorLength(dir) > 16)
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "func_bobbing not at start\n");
-#endif
- dist = dist1;
- VectorCopy(dir1, dir);
- //
- BotCheckBlocked(ms, dir, qfalse, &result);
- //
- if (dist > 60) dist = 60;
- speed = 360 - (360 - 6 * dist);
- //
- if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
- {
- if (speed > 5) EA_Move(ms->client, dir, speed);
- } //end if
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- //this isn't a failure... just wait till the func_bobbing arrives
- result.type = RESULTTYPE_WAITFORFUNCBOBBING;
- result.flags |= MOVERESULT_WAITING;
- return result;
- } //end if
- //get direction and distance to func_bob bottom center
- MoverBottomCenter(reach, bottomcenter);
- VectorSubtract(bottomcenter, ms->origin, dir2);
- if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0;
- dist2 = VectorNormalize(dir2);
- //if very close to the reachability start or
- //closer to the elevator center or
- //between reachability start and func_bobbing center
- if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0)
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n");
-#endif
- dist = dist2;
- VectorCopy(dir2, dir);
- } //end if
- else //closer to the reachability start
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot moving to reachability start\n");
-#endif
- dist = dist1;
- VectorCopy(dir1, dir);
- } //end else
- //
- BotCheckBlocked(ms, dir, qfalse, &result);
- //
- if (dist > 60) dist = 60;
- speed = 400 - (400 - 6 * dist);
- //
- if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
- {
- EA_Move(ms->client, dir, speed);
- } //end if
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- } //end else
- return result;
-} //end of the function BotTravel_FuncBobbing
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t bob_origin, bob_start, bob_end, dir, hordir, bottomcenter;
- bot_moveresult_t_cleared( result );
- float dist, speed;
-
- //
- BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin);
- //
- VectorSubtract(bob_origin, bob_end, dir);
- dist = VectorLength(dir);
- //if the func_bobbing is near the end
- if (dist < 16)
- {
- VectorSubtract(reach->end, ms->origin, hordir);
- if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- if (dist > 60) dist = 60;
- speed = 360 - (360 - 6 * dist);
- //
- if (speed > 5) EA_Move(ms->client, dir, speed);
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- } //end if
- else
- {
- MoverBottomCenter(reach, bottomcenter);
- VectorSubtract(bottomcenter, ms->origin, hordir);
- if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- if (dist > 5)
- {
- //move to the center of the plat
- if (dist > 100) dist = 100;
- speed = 400 - (400 - 4 * dist);
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- } //end if
- } //end else
- return result;
-} //end of the function BotFinishTravel_FuncBobbing
-//===========================================================================
-// 0 no valid grapple hook visible
-// 1 the grapple hook is still flying
-// 2 the grapple hooked into a wall
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int GrappleState(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- int i;
- aas_entityinfo_t entinfo;
-
- //if the grapple hook is pulling
- if (ms->moveflags & MFL_GRAPPLEPULL)
- return 2;
- //check for a visible grapple missile entity
- //or visible grapple entity
- for (i = AAS_NextEntity(0); i; i = AAS_NextEntity(i))
- {
- if (AAS_EntityType(i) == (int) entitytypemissile->value)
- {
- AAS_EntityInfo(i, &entinfo);
- if (entinfo.weapon == (int) weapindex_grapple->value)
- {
- return 1;
- } //end if
- } //end if
- } //end for
- //no valid grapple at all
- return 0;
-} //end of the function GrappleState
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotResetGrapple(bot_movestate_t *ms)
-{
- aas_reachability_t reach;
-
- AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
- //if not using the grapple hook reachability anymore
- if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_GRAPPLEHOOK)
- {
- if ((ms->moveflags & MFL_ACTIVEGRAPPLE) || ms->grapplevisible_time)
- {
- if (offhandgrapple->value)
- EA_Command(ms->client, cmd_grappleoff->string);
- ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
- ms->grapplevisible_time = 0;
-#ifdef DEBUG_GRAPPLE
- botimport.Print(PRT_MESSAGE, "reset grapple\n");
-#endif //DEBUG_GRAPPLE
- } //end if
- } //end if
-} //end of the function BotResetGrapple
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Grapple(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- bot_moveresult_t_cleared( result );
- float dist, speed;
- vec3_t dir, viewdir, org;
- int state, areanum;
- bsp_trace_t trace;
-
-#ifdef DEBUG_GRAPPLE
- static int debugline;
- if (!debugline) debugline = botimport.DebugLineCreate();
- botimport.DebugLineShow(debugline, reach->start, reach->end, LINECOLOR_BLUE);
-#endif //DEBUG_GRAPPLE
-
- //
- if (ms->moveflags & MFL_GRAPPLERESET)
- {
- if (offhandgrapple->value)
- EA_Command(ms->client, cmd_grappleoff->string);
- ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
- return result;
- } //end if
- //
- if (!(int) offhandgrapple->value)
- {
- result.weapon = weapindex_grapple->value;
- result.flags |= MOVERESULT_MOVEMENTWEAPON;
- } //end if
- //
- if (ms->moveflags & MFL_ACTIVEGRAPPLE)
- {
-#ifdef DEBUG_GRAPPLE
- botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: active grapple\n");
-#endif //DEBUG_GRAPPLE
- //
- state = GrappleState(ms, reach);
- //
- VectorSubtract(reach->end, ms->origin, dir);
- dir[2] = 0;
- dist = VectorLength(dir);
- //if very close to the grapple end or the grappled is hooked and
- //the bot doesn't get any closer
- if (state && dist < 48)
- {
- if (ms->lastgrappledist - dist < 1)
- {
-#ifdef DEBUG_GRAPPLE
- botimport.Print(PRT_ERROR, "grapple normal end\n");
-#endif //DEBUG_GRAPPLE
- if (offhandgrapple->value)
- EA_Command(ms->client, cmd_grappleoff->string);
- ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
- ms->moveflags |= MFL_GRAPPLERESET;
- ms->reachability_time = 0; //end the reachability
- return result;
- } //end if
- } //end if
- //if no valid grapple at all, or the grapple hooked and the bot
- //isn't moving anymore
- else if (!state || (state == 2 && dist > ms->lastgrappledist - 2))
- {
- if (ms->grapplevisible_time < AAS_Time() - 0.4)
- {
-#ifdef DEBUG_GRAPPLE
- botimport.Print(PRT_ERROR, "grapple not visible\n");
-#endif //DEBUG_GRAPPLE
- if (offhandgrapple->value)
- EA_Command(ms->client, cmd_grappleoff->string);
- ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
- ms->moveflags |= MFL_GRAPPLERESET;
- ms->reachability_time = 0; //end the reachability
- return result;
- } //end if
- } //end if
- else
- {
- ms->grapplevisible_time = AAS_Time();
- } //end else
- //
- if (!(int) offhandgrapple->value)
- {
- EA_Attack(ms->client);
- } //end if
- //remember the current grapple distance
- ms->lastgrappledist = dist;
- } //end if
- else
- {
-#ifdef DEBUG_GRAPPLE
- botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: inactive grapple\n");
-#endif //DEBUG_GRAPPLE
- //
- ms->grapplevisible_time = AAS_Time();
- //
- VectorSubtract(reach->start, ms->origin, dir);
- if (!(ms->moveflags & MFL_SWIMMING)) dir[2] = 0;
- VectorAdd(ms->origin, ms->viewoffset, org);
- VectorSubtract(reach->end, org, viewdir);
- //
- dist = VectorNormalize(dir);
- Vector2Angles(viewdir, result.ideal_viewangles);
- result.flags |= MOVERESULT_MOVEMENTVIEW;
- //
- if (dist < 5 &&
- fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 2 &&
- fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 2)
- {
-#ifdef DEBUG_GRAPPLE
- botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: activating grapple\n");
-#endif //DEBUG_GRAPPLE
- //check if the grapple missile path is clear
- VectorAdd(ms->origin, ms->viewoffset, org);
- trace = AAS_Trace(org, NULL, NULL, reach->end, ms->entitynum, CONTENTS_SOLID);
- VectorSubtract(reach->end, trace.endpos, dir);
- if (VectorLength(dir) > 16)
- {
- result.failure = qtrue;
- return result;
- } //end if
- //activate the grapple
- if (offhandgrapple->value)
- {
- EA_Command(ms->client, cmd_grappleon->string);
- } //end if
- else
- {
- EA_Attack(ms->client);
- } //end else
- ms->moveflags |= MFL_ACTIVEGRAPPLE;
- ms->lastgrappledist = 999999;
- } //end if
- else
- {
- if (dist < 70) speed = 300 - (300 - 4 * dist);
- else speed = 400;
- //
- BotCheckBlocked(ms, dir, qtrue, &result);
- //elemantary action move in direction
- EA_Move(ms->client, dir, speed);
- VectorCopy(dir, result.movedir);
- } //end else
- //if in another area before actually grappling
- areanum = AAS_PointAreaNum(ms->origin);
- if (areanum && areanum != ms->reachareanum) ms->reachability_time = 0;
- } //end else
- return result;
-} //end of the function BotTravel_Grapple
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_RocketJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir;
- float dist, speed;
- bot_moveresult_t_cleared( result );
-
- //botimport.Print(PRT_MESSAGE, "BotTravel_RocketJump: bah\n");
- //
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- //
- dist = VectorNormalize(hordir);
- //look in the movement direction
- Vector2Angles(hordir, result.ideal_viewangles);
- //look straight down
- result.ideal_viewangles[PITCH] = 90;
- //
- if (dist < 5 &&
- fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 &&
- fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5)
- {
- //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //elemantary action jump
- EA_Jump(ms->client);
- EA_Attack(ms->client);
- EA_Move(ms->client, hordir, 800);
- //
- ms->jumpreach = ms->lastreachnum;
- } //end if
- else
- {
- if (dist > 80) dist = 80;
- speed = 400 - (400 - 5 * dist);
- EA_Move(ms->client, hordir, speed);
- } //end else
- //look in the movement direction
- Vector2Angles(hordir, result.ideal_viewangles);
- //look straight down
- result.ideal_viewangles[PITCH] = 90;
- //set the view angles directly
- EA_View(ms->client, result.ideal_viewangles);
- //view is important for the movment
- result.flags |= MOVERESULT_MOVEMENTVIEWSET;
- //select the rocket launcher
- EA_SelectWeapon(ms->client, (int) weapindex_rocketlauncher->value);
- //weapon is used for movement
- result.weapon = (int) weapindex_rocketlauncher->value;
- result.flags |= MOVERESULT_MOVEMENTWEAPON;
- //
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_RocketJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_BFGJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir;
- float dist, speed;
- bot_moveresult_t_cleared( result );
-
- //botimport.Print(PRT_MESSAGE, "BotTravel_BFGJump: bah\n");
- //
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- //
- dist = VectorNormalize(hordir);
- //
- if (dist < 5 &&
- fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 &&
- fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5)
- {
- //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //elemantary action jump
- EA_Jump(ms->client);
- EA_Attack(ms->client);
- EA_Move(ms->client, hordir, 800);
- //
- ms->jumpreach = ms->lastreachnum;
- } //end if
- else
- {
- if (dist > 80) dist = 80;
- speed = 400 - (400 - 5 * dist);
- EA_Move(ms->client, hordir, speed);
- } //end else
- //look in the movement direction
- Vector2Angles(hordir, result.ideal_viewangles);
- //look straight down
- result.ideal_viewangles[PITCH] = 90;
- //set the view angles directly
- EA_View(ms->client, result.ideal_viewangles);
- //view is important for the movment
- result.flags |= MOVERESULT_MOVEMENTVIEWSET;
- //select the rocket launcher
- EA_SelectWeapon(ms->client, (int) weapindex_bfg10k->value);
- //weapon is used for movement
- result.weapon = (int) weapindex_bfg10k->value;
- result.flags |= MOVERESULT_MOVEMENTWEAPON;
- //
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_BFGJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_WeaponJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir;
- float speed;
- bot_moveresult_t_cleared( result );
-
- //if not jumped yet
- if (!ms->jumpreach) return result;
- /*
- //go straight to the reachability end
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //always use max speed when traveling through the air
- EA_Move(ms->client, hordir, 800);
- VectorCopy(hordir, result.movedir);
- */
- //
- if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed))
- {
- //go straight to the reachability end
- VectorSubtract(reach->end, ms->origin, hordir);
- hordir[2] = 0;
- VectorNormalize(hordir);
- speed = 400;
- } //end if
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotFinishTravel_WeaponJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- float dist, speed;
- vec3_t hordir;
- bot_moveresult_t_cleared( result );
-
- //first walk straight to the reachability start
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
- speed = 400;
- //elemantary action move in direction
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_JumpPad
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- float speed;
- vec3_t hordir;
- bot_moveresult_t_cleared( result );
-
- if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed))
- {
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- speed = 400;
- } //end if
- BotCheckBlocked(ms, hordir, qtrue, &result);
- //elemantary action move in direction
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotFinishTravel_JumpPad
-//===========================================================================
-// time before the reachability times out
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotReachabilityTime(aas_reachability_t *reach)
-{
- switch(reach->traveltype & TRAVELTYPE_MASK)
- {
- case TRAVEL_WALK: return 5;
- case TRAVEL_CROUCH: return 5;
- case TRAVEL_BARRIERJUMP: return 5;
- case TRAVEL_LADDER: return 6;
- case TRAVEL_WALKOFFLEDGE: return 5;
- case TRAVEL_JUMP: return 5;
- case TRAVEL_SWIM: return 5;
- case TRAVEL_WATERJUMP: return 5;
- case TRAVEL_TELEPORT: return 5;
- case TRAVEL_ELEVATOR: return 10;
- case TRAVEL_GRAPPLEHOOK: return 8;
- case TRAVEL_ROCKETJUMP: return 6;
- case TRAVEL_BFGJUMP: return 6;
- case TRAVEL_JUMPPAD: return 10;
- case TRAVEL_FUNCBOB: return 10;
- default:
- {
- botimport.Print(PRT_ERROR, "travel type %d not implemented yet\n", reach->traveltype);
- return 8;
- } //end case
- } //end switch
-} //end of the function BotReachabilityTime
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotMoveInGoalArea(bot_movestate_t *ms, bot_goal_t *goal)
-{
- bot_moveresult_t_cleared( result );
- vec3_t dir;
- float dist, speed;
-
-#ifdef DEBUG
- //botimport.Print(PRT_MESSAGE, "%s: moving straight to goal\n", ClientName(ms->entitynum-1));
- //AAS_ClearShownDebugLines();
- //AAS_DebugLine(ms->origin, goal->origin, LINECOLOR_RED);
-#endif //DEBUG
- //walk straight to the goal origin
- dir[0] = goal->origin[0] - ms->origin[0];
- dir[1] = goal->origin[1] - ms->origin[1];
- if (ms->moveflags & MFL_SWIMMING)
- {
- dir[2] = goal->origin[2] - ms->origin[2];
- result.traveltype = TRAVEL_SWIM;
- } //end if
- else
- {
- dir[2] = 0;
- result.traveltype = TRAVEL_WALK;
- } //endif
- //
- dist = VectorNormalize(dir);
- if (dist > 100) dist = 100;
- speed = 400 - (400 - 4 * dist);
- if (speed < 10) speed = 0;
- //
- BotCheckBlocked(ms, dir, qtrue, &result);
- //elemantary action move in direction
- EA_Move(ms->client, dir, speed);
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING)
- {
- Vector2Angles(dir, result.ideal_viewangles);
- result.flags |= MOVERESULT_SWIMVIEW;
- } //end if
- //if (!debugline) debugline = botimport.DebugLineCreate();
- //botimport.DebugLineShow(debugline, ms->origin, goal->origin, LINECOLOR_BLUE);
- //
- ms->lastreachnum = 0;
- ms->lastareanum = 0;
- ms->lastgoalareanum = goal->areanum;
- VectorCopy(ms->origin, ms->lastorigin);
- //
- return result;
-} //end of the function BotMoveInGoalArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags)
-{
- int reachnum, lastreachnum, foundjumppad, ent, resultflags;
- aas_reachability_t reach, lastreach;
- bot_movestate_t *ms;
- //vec3_t mins, maxs, up = {0, 0, 1};
- //bsp_trace_t trace;
- //static int debugline;
-
- result->failure = qfalse;
- result->type = 0;
- result->blocked = qfalse;
- result->blockentity = 0;
- result->traveltype = 0;
- result->flags = 0;
-
- //
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return;
- //reset the grapple before testing if the bot has a valid goal
- //because the bot could loose all it's goals when stuck to a wall
- BotResetGrapple(ms);
- //
- if (!goal)
- {
-#ifdef DEBUG
- botimport.Print(PRT_MESSAGE, "client %d: movetogoal -> no goal\n", ms->client);
-#endif //DEBUG
- result->failure = qtrue;
- return;
- } //end if
- //botimport.Print(PRT_MESSAGE, "numavoidreach = %d\n", ms->numavoidreach);
- //remove some of the move flags
- ms->moveflags &= ~(MFL_SWIMMING|MFL_AGAINSTLADDER);
- //set some of the move flags
- //NOTE: the MFL_ONGROUND flag is also set in the higher AI
- if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND;
- //
- if (ms->moveflags & MFL_ONGROUND)
- {
- int modeltype, modelnum;
-
- ent = BotOnTopOfEntity(ms);
-
- if (ent != -1)
- {
- modelnum = AAS_EntityModelindex(ent);
- if (modelnum >= 0 && modelnum < MAX_MODELS)
- {
- modeltype = modeltypes[modelnum];
-
- if (modeltype == MODELTYPE_FUNC_PLAT)
- {
- AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
- //if the bot is Not using the elevator
- if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR ||
- //NOTE: the face number is the plat model number
- (reach.facenum & 0x0000FFFF) != modelnum)
- {
- reachnum = AAS_NextModelReachability(0, modelnum);
- if (reachnum)
- {
- //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_plat\n", ms->client);
- AAS_ReachabilityFromNum(reachnum, &reach);
- ms->lastreachnum = reachnum;
- ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
- } //end if
- else
- {
- if (botDeveloper)
- {
- botimport.Print(PRT_MESSAGE, "client %d: on func_plat without reachability\n", ms->client);
- } //end if
- result->blocked = qtrue;
- result->blockentity = ent;
- result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
- return;
- } //end else
- } //end if
- result->flags |= MOVERESULT_ONTOPOF_ELEVATOR;
- } //end if
- else if (modeltype == MODELTYPE_FUNC_BOB)
- {
- AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
- //if the bot is Not using the func bobbing
- if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB ||
- //NOTE: the face number is the func_bobbing model number
- (reach.facenum & 0x0000FFFF) != modelnum)
- {
- reachnum = AAS_NextModelReachability(0, modelnum);
- if (reachnum)
- {
- //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_bobbing\n", ms->client);
- AAS_ReachabilityFromNum(reachnum, &reach);
- ms->lastreachnum = reachnum;
- ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
- } //end if
- else
- {
- if (botDeveloper)
- {
- botimport.Print(PRT_MESSAGE, "client %d: on func_bobbing without reachability\n", ms->client);
- } //end if
- result->blocked = qtrue;
- result->blockentity = ent;
- result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
- return;
- } //end else
- } //end if
- result->flags |= MOVERESULT_ONTOPOF_FUNCBOB;
- } //end if
- else if (modeltype == MODELTYPE_FUNC_STATIC || modeltype == MODELTYPE_FUNC_DOOR)
- {
- // check if ontop of a door bridge ?
- ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
- // if not in a reachability area
- if (!AAS_AreaReachability(ms->areanum))
- {
- result->blocked = qtrue;
- result->blockentity = ent;
- result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
- return;
- } //end if
- } //end else if
- else
- {
- result->blocked = qtrue;
- result->blockentity = ent;
- result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
- return;
- } //end else
- } //end if
- } //end if
- } //end if
- //if swimming
- if (AAS_Swimming(ms->origin)) ms->moveflags |= MFL_SWIMMING;
- //if against a ladder
- if (AAS_AgainstLadder(ms->origin)) ms->moveflags |= MFL_AGAINSTLADDER;
- //if the bot is on the ground, swimming or against a ladder
- if (ms->moveflags & (MFL_ONGROUND|MFL_SWIMMING|MFL_AGAINSTLADDER))
- {
- //botimport.Print(PRT_MESSAGE, "%s: onground, swimming or against ladder\n", ClientName(ms->entitynum-1));
- //
- AAS_ReachabilityFromNum(ms->lastreachnum, &lastreach);
- //reachability area the bot is in
- //ms->areanum = BotReachabilityArea(ms->origin, ((lastreach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR));
- ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
- //
- if ( !ms->areanum )
- {
- result->failure = qtrue;
- result->blocked = qtrue;
- result->blockentity = 0;
- result->type = RESULTTYPE_INSOLIDAREA;
- return;
- } //end if
- //if the bot is in the goal area
- if (ms->areanum == goal->areanum)
- {
- *result = BotMoveInGoalArea(ms, goal);
- return;
- } //end if
- //assume we can use the reachability from the last frame
- reachnum = ms->lastreachnum;
- //if there is a last reachability
- if (reachnum)
- {
- AAS_ReachabilityFromNum(reachnum, &reach);
- //check if the reachability is still valid
- if (!(AAS_TravelFlagForType(reach.traveltype) & travelflags))
- {
- reachnum = 0;
- } //end if
- //special grapple hook case
- else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_GRAPPLEHOOK)
- {
- if (ms->reachability_time < AAS_Time() ||
- (ms->moveflags & MFL_GRAPPLERESET))
- {
- reachnum = 0;
- } //end if
- } //end if
- //special elevator case
- else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR ||
- (reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB)
- {
- if ((result->flags & MOVERESULT_ONTOPOF_FUNCBOB) ||
- (result->flags & MOVERESULT_ONTOPOF_FUNCBOB))
- {
- ms->reachability_time = AAS_Time() + 5;
- } //end if
- //if the bot was going for an elevator and reached the reachability area
- if (ms->areanum == reach.areanum ||
- ms->reachability_time < AAS_Time())
- {
- reachnum = 0;
- } //end if
- } //end if
- else
- {
-#ifdef DEBUG
- if (botDeveloper)
- {
- if (ms->reachability_time < AAS_Time())
- {
- botimport.Print(PRT_MESSAGE, "client %d: reachability timeout in ", ms->client);
- AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
- botimport.Print(PRT_MESSAGE, "\n");
- } //end if
- /*
- if (ms->lastareanum != ms->areanum)
- {
- botimport.Print(PRT_MESSAGE, "changed from area %d to %d\n", ms->lastareanum, ms->areanum);
- } //end if*/
- } //end if
-#endif //DEBUG
- //if the goal area changed or the reachability timed out
- //or the area changed
- if (ms->lastgoalareanum != goal->areanum ||
- ms->reachability_time < AAS_Time() ||
- ms->lastareanum != ms->areanum)
- {
- reachnum = 0;
- //botimport.Print(PRT_MESSAGE, "area change or timeout\n");
- } //end else if
- } //end else
- } //end if
- resultflags = 0;
- //if the bot needs a new reachability
- if (!reachnum)
- {
- //if the area has no reachability links
- if (!AAS_AreaReachability(ms->areanum))
- {
-#ifdef DEBUG
- if (botDeveloper)
- {
- botimport.Print(PRT_MESSAGE, "area %d no reachability\n", ms->areanum);
- } //end if
-#endif //DEBUG
- } //end if
- //get a new reachability leading towards the goal
- reachnum = BotGetReachabilityToGoal(ms->origin, ms->areanum,
- ms->lastgoalareanum, ms->lastareanum,
- ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
- goal, travelflags, travelflags,
- ms->avoidspots, ms->numavoidspots, &resultflags);
- //the area number the reachability starts in
- ms->reachareanum = ms->areanum;
- //reset some state variables
- ms->jumpreach = 0; //for TRAVEL_JUMP
- ms->moveflags &= ~MFL_GRAPPLERESET; //for TRAVEL_GRAPPLEHOOK
- //if there is a reachability to the goal
- if (reachnum)
- {
- AAS_ReachabilityFromNum(reachnum, &reach);
- //set a timeout for this reachability
- ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
- //
-#ifdef AVOIDREACH
- //add the reachability to the reachabilities to avoid for a while
- BotAddToAvoidReach(ms, reachnum, AVOIDREACH_TIME);
-#endif //AVOIDREACH
- } //end if
-#ifdef DEBUG
-
- else if (botDeveloper)
- {
- botimport.Print(PRT_MESSAGE, "goal not reachable\n");
- Com_Memset(&reach, 0, sizeof(aas_reachability_t)); //make compiler happy
- } //end else
- if (botDeveloper)
- {
- //if still going for the same goal
- if (ms->lastgoalareanum == goal->areanum)
- {
- if (ms->lastareanum == reach.areanum)
- {
- botimport.Print(PRT_MESSAGE, "same goal, going back to previous area\n");
- } //end if
- } //end if
- } //end if
-#endif //DEBUG
- } //end else
- //
- ms->lastreachnum = reachnum;
- ms->lastgoalareanum = goal->areanum;
- ms->lastareanum = ms->areanum;
- //if the bot has a reachability
- if (reachnum)
- {
- //get the reachability from the number
- AAS_ReachabilityFromNum(reachnum, &reach);
- result->traveltype = reach.traveltype;
- //
-#ifdef DEBUG_AI_MOVE
- AAS_ClearShownDebugLines();
- AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
- AAS_ShowReachability(&reach);
-#endif //DEBUG_AI_MOVE
- //
-#ifdef DEBUG
- //botimport.Print(PRT_MESSAGE, "client %d: ", ms->client);
- //AAS_PrintTravelType(reach.traveltype);
- //botimport.Print(PRT_MESSAGE, "\n");
-#endif //DEBUG
- switch(reach.traveltype & TRAVELTYPE_MASK)
- {
- case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;
- case TRAVEL_CROUCH: *result = BotTravel_Crouch(ms, &reach); break;
- case TRAVEL_BARRIERJUMP: *result = BotTravel_BarrierJump(ms, &reach); break;
- case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break;
- case TRAVEL_WALKOFFLEDGE: *result = BotTravel_WalkOffLedge(ms, &reach); break;
- case TRAVEL_JUMP: *result = BotTravel_Jump(ms, &reach); break;
- case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break;
- case TRAVEL_WATERJUMP: *result = BotTravel_WaterJump(ms, &reach); break;
- case TRAVEL_TELEPORT: *result = BotTravel_Teleport(ms, &reach); break;
- case TRAVEL_ELEVATOR: *result = BotTravel_Elevator(ms, &reach); break;
- case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break;
- case TRAVEL_ROCKETJUMP: *result = BotTravel_RocketJump(ms, &reach); break;
- case TRAVEL_BFGJUMP: *result = BotTravel_BFGJump(ms, &reach); break;
- case TRAVEL_JUMPPAD: *result = BotTravel_JumpPad(ms, &reach); break;
- case TRAVEL_FUNCBOB: *result = BotTravel_FuncBobbing(ms, &reach); break;
- default:
- {
- botimport.Print(PRT_FATAL, "travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK));
- break;
- } //end case
- } //end switch
- result->traveltype = reach.traveltype;
- result->flags |= resultflags;
- } //end if
- else
- {
- result->failure = qtrue;
- result->flags |= resultflags;
- Com_Memset(&reach, 0, sizeof(aas_reachability_t));
- } //end else
-#ifdef DEBUG
- if (botDeveloper)
- {
- if (result->failure)
- {
- botimport.Print(PRT_MESSAGE, "client %d: movement failure in ", ms->client);
- AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
- botimport.Print(PRT_MESSAGE, "\n");
- } //end if
- } //end if
-#endif //DEBUG
- } //end if
- else
- {
- int i, numareas, areas[16];
- vec3_t end;
-
- //special handling of jump pads when the bot uses a jump pad without knowing it
- foundjumppad = qfalse;
- VectorMA(ms->origin, -2 * ms->thinktime, ms->velocity, end);
- numareas = AAS_TraceAreas(ms->origin, end, areas, NULL, 16);
- for (i = numareas-1; i >= 0; i--)
- {
- if (AAS_AreaJumpPad(areas[i]))
- {
- //botimport.Print(PRT_MESSAGE, "client %d used a jumppad without knowing, area %d\n", ms->client, areas[i]);
- foundjumppad = qtrue;
- lastreachnum = BotGetReachabilityToGoal(end, areas[i],
- ms->lastgoalareanum, ms->lastareanum,
- ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
- goal, travelflags, TFL_JUMPPAD, ms->avoidspots, ms->numavoidspots, NULL);
- if (lastreachnum)
- {
- ms->lastreachnum = lastreachnum;
- ms->lastareanum = areas[i];
- //botimport.Print(PRT_MESSAGE, "found jumppad reachability\n");
- break;
- } //end if
- else
- {
- for (lastreachnum = AAS_NextAreaReachability(areas[i], 0); lastreachnum;
- lastreachnum = AAS_NextAreaReachability(areas[i], lastreachnum))
- {
- //get the reachability from the number
- AAS_ReachabilityFromNum(lastreachnum, &reach);
- if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD)
- {
- ms->lastreachnum = lastreachnum;
- ms->lastareanum = areas[i];
- //botimport.Print(PRT_MESSAGE, "found jumppad reachability hard!!\n");
- break;
- } //end if
- } //end for
- if (lastreachnum) break;
- } //end else
- } //end if
- } //end for
- if (botDeveloper)
- {
- //if a jumppad is found with the trace but no reachability is found
- if (foundjumppad && !ms->lastreachnum)
- {
- botimport.Print(PRT_MESSAGE, "client %d didn't find jumppad reachability\n", ms->client);
- } //end if
- } //end if
- //
- if (ms->lastreachnum)
- {
- //botimport.Print(PRT_MESSAGE, "%s: NOT onground, swimming or against ladder\n", ClientName(ms->entitynum-1));
- AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
- result->traveltype = reach.traveltype;
-#ifdef DEBUG
- //botimport.Print(PRT_MESSAGE, "client %d finish: ", ms->client);
- //AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
- //botimport.Print(PRT_MESSAGE, "\n");
-#endif //DEBUG
- //
- switch(reach.traveltype & TRAVELTYPE_MASK)
- {
- case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;//BotFinishTravel_Walk(ms, &reach); break;
- case TRAVEL_CROUCH: /*do nothing*/ break;
- case TRAVEL_BARRIERJUMP: *result = BotFinishTravel_BarrierJump(ms, &reach); break;
- case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break;
- case TRAVEL_WALKOFFLEDGE: *result = BotFinishTravel_WalkOffLedge(ms, &reach); break;
- case TRAVEL_JUMP: *result = BotFinishTravel_Jump(ms, &reach); break;
- case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break;
- case TRAVEL_WATERJUMP: *result = BotFinishTravel_WaterJump(ms, &reach); break;
- case TRAVEL_TELEPORT: /*do nothing*/ break;
- case TRAVEL_ELEVATOR: *result = BotFinishTravel_Elevator(ms, &reach); break;
- case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break;
- case TRAVEL_ROCKETJUMP:
- case TRAVEL_BFGJUMP: *result = BotFinishTravel_WeaponJump(ms, &reach); break;
- case TRAVEL_JUMPPAD: *result = BotFinishTravel_JumpPad(ms, &reach); break;
- case TRAVEL_FUNCBOB: *result = BotFinishTravel_FuncBobbing(ms, &reach); break;
- default:
- {
- botimport.Print(PRT_FATAL, "(last) travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK));
- break;
- } //end case
- } //end switch
- result->traveltype = reach.traveltype;
-#ifdef DEBUG
- if (botDeveloper)
- {
- if (result->failure)
- {
- botimport.Print(PRT_MESSAGE, "client %d: movement failure in finish ", ms->client);
- AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
- botimport.Print(PRT_MESSAGE, "\n");
- } //end if
- } //end if
-#endif //DEBUG
- } //end if
- } //end else
- //FIXME: is it right to do this here?
- if (result->blocked) ms->reachability_time -= 10 * ms->thinktime;
- //copy the last origin
- VectorCopy(ms->origin, ms->lastorigin);
- //return the movement result
- return;
-} //end of the function BotMoveToGoal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotResetAvoidReach(int movestate)
-{
- bot_movestate_t *ms;
-
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return;
- Com_Memset(ms->avoidreach, 0, MAX_AVOIDREACH * sizeof(int));
- Com_Memset(ms->avoidreachtimes, 0, MAX_AVOIDREACH * sizeof(float));
- Com_Memset(ms->avoidreachtries, 0, MAX_AVOIDREACH * sizeof(int));
-} //end of the function BotResetAvoidReach
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotResetLastAvoidReach(int movestate)
-{
- int i, latest;
- float latesttime;
- bot_movestate_t *ms;
-
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return;
- latesttime = 0;
- latest = 0;
- for (i = 0; i < MAX_AVOIDREACH; i++)
- {
- if (ms->avoidreachtimes[i] > latesttime)
- {
- latesttime = ms->avoidreachtimes[i];
- latest = i;
- } //end if
- } //end for
- if (latesttime)
- {
- ms->avoidreachtimes[latest] = 0;
- if (ms->avoidreachtries[i] > 0) ms->avoidreachtries[latest]--;
- } //end if
-} //end of the function BotResetLastAvoidReach
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotResetMoveState(int movestate)
-{
- bot_movestate_t *ms;
-
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return;
- Com_Memset(ms, 0, sizeof(bot_movestate_t));
-} //end of the function BotResetMoveState
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotSetupMoveAI(void)
-{
- BotSetBrushModelTypes();
- sv_maxstep = LibVar("sv_step", "18");
- sv_maxbarrier = LibVar("sv_maxbarrier", "32");
- sv_gravity = LibVar("sv_gravity", "800");
- weapindex_rocketlauncher = LibVar("weapindex_rocketlauncher", "5");
- weapindex_bfg10k = LibVar("weapindex_bfg10k", "9");
- weapindex_grapple = LibVar("weapindex_grapple", "10");
- entitytypemissile = LibVar("entitytypemissile", "3");
- offhandgrapple = LibVar("offhandgrapple", "0");
- cmd_grappleon = LibVar("cmd_grappleon", "grappleon");
- cmd_grappleoff = LibVar("cmd_grappleoff", "grappleoff");
- return BLERR_NOERROR;
-} //end of the function BotSetupMoveAI
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotShutdownMoveAI(void)
-{
- int i;
-
- for (i = 1; i <= MAX_CLIENTS; i++)
- {
- if (botmovestates[i])
- {
- FreeMemory(botmovestates[i]);
- botmovestates[i] = NULL;
- } //end if
- } //end for
-} //end of the function BotShutdownMoveAI
-
-
diff --git a/engine/code/botlib/be_ai_weap.c b/engine/code/botlib/be_ai_weap.c
deleted file mode 100644
index 0aab5e8..0000000
--- a/engine/code/botlib/be_ai_weap.c
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_ai_weap.c
- *
- * desc: weapon AI
- *
- * $Archive: /MissionPack/code/botlib/be_ai_weap.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_libvar.h"
-#include "l_log.h"
-#include "l_memory.h"
-#include "l_utils.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-#include "be_ai_weight.h" //fuzzy weights
-#include "be_ai_weap.h"
-
-//#define DEBUG_AI_WEAP
-
-//structure field offsets
-#define WEAPON_OFS(x) (size_t)&(((weaponinfo_t *)0)->x)
-#define PROJECTILE_OFS(x) (size_t)&(((projectileinfo_t *)0)->x)
-
-//weapon definition
-static fielddef_t weaponinfo_fields[] =
-{
-{"number", WEAPON_OFS(number), FT_INT}, //weapon number
-{"name", WEAPON_OFS(name), FT_STRING}, //name of the weapon
-{"level", WEAPON_OFS(level), FT_INT},
-{"model", WEAPON_OFS(model), FT_STRING}, //model of the weapon
-{"weaponindex", WEAPON_OFS(weaponindex), FT_INT}, //index of weapon in inventory
-{"flags", WEAPON_OFS(flags), FT_INT}, //special flags
-{"projectile", WEAPON_OFS(projectile), FT_STRING}, //projectile used by the weapon
-{"numprojectiles", WEAPON_OFS(numprojectiles), FT_INT}, //number of projectiles
-{"hspread", WEAPON_OFS(hspread), FT_FLOAT}, //horizontal spread of projectiles (degrees from middle)
-{"vspread", WEAPON_OFS(vspread), FT_FLOAT}, //vertical spread of projectiles (degrees from middle)
-{"speed", WEAPON_OFS(speed), FT_FLOAT}, //speed of the projectile (0 = instant hit)
-{"acceleration", WEAPON_OFS(acceleration), FT_FLOAT}, //"acceleration" * time (in seconds) + "speed" = projectile speed
-{"recoil", WEAPON_OFS(recoil), FT_FLOAT|FT_ARRAY, 3}, //amount of recoil the player gets from the weapon
-{"offset", WEAPON_OFS(offset), FT_FLOAT|FT_ARRAY, 3}, //projectile start offset relative to eye and view angles
-{"angleoffset", WEAPON_OFS(angleoffset), FT_FLOAT|FT_ARRAY, 3},//offset of the shoot angles relative to the view angles
-{"extrazvelocity", WEAPON_OFS(extrazvelocity), FT_FLOAT},//extra z velocity the projectile gets
-{"ammoamount", WEAPON_OFS(ammoamount), FT_INT}, //ammo amount used per shot
-{"ammoindex", WEAPON_OFS(ammoindex), FT_INT}, //index of ammo in inventory
-{"activate", WEAPON_OFS(activate), FT_FLOAT}, //time it takes to select the weapon
-{"reload", WEAPON_OFS(reload), FT_FLOAT}, //time it takes to reload the weapon
-{"spinup", WEAPON_OFS(spinup), FT_FLOAT}, //time it takes before first shot
-{"spindown", WEAPON_OFS(spindown), FT_FLOAT}, //time it takes before weapon stops firing
-{NULL, 0, 0, 0}
-};
-
-//projectile definition
-static fielddef_t projectileinfo_fields[] =
-{
-{"name", PROJECTILE_OFS(name), FT_STRING}, //name of the projectile
-{"model", WEAPON_OFS(model), FT_STRING}, //model of the projectile
-{"flags", PROJECTILE_OFS(flags), FT_INT}, //special flags
-{"gravity", PROJECTILE_OFS(gravity), FT_FLOAT}, //amount of gravity applied to the projectile [0,1]
-{"damage", PROJECTILE_OFS(damage), FT_INT}, //damage of the projectile
-{"radius", PROJECTILE_OFS(radius), FT_FLOAT}, //radius of damage
-{"visdamage", PROJECTILE_OFS(visdamage), FT_INT}, //damage of the projectile to visible entities
-{"damagetype", PROJECTILE_OFS(damagetype), FT_INT}, //type of damage (combination of the DAMAGETYPE_? flags)
-{"healthinc", PROJECTILE_OFS(healthinc), FT_INT}, //health increase the owner gets
-{"push", PROJECTILE_OFS(push), FT_FLOAT}, //amount a player is pushed away from the projectile impact
-{"detonation", PROJECTILE_OFS(detonation), FT_FLOAT}, //time before projectile explodes after fire pressed
-{"bounce", PROJECTILE_OFS(bounce), FT_FLOAT}, //amount the projectile bounces
-{"bouncefric", PROJECTILE_OFS(bouncefric), FT_FLOAT}, //amount the bounce decreases per bounce
-{"bouncestop", PROJECTILE_OFS(bouncestop), FT_FLOAT}, //minimum bounce value before bouncing stops
-//recurive projectile definition??
-{NULL, 0, 0, 0}
-};
-
-static structdef_t weaponinfo_struct =
-{
- sizeof(weaponinfo_t), weaponinfo_fields
-};
-static structdef_t projectileinfo_struct =
-{
- sizeof(projectileinfo_t), projectileinfo_fields
-};
-
-//weapon configuration: set of weapons with projectiles
-typedef struct weaponconfig_s
-{
- int numweapons;
- int numprojectiles;
- projectileinfo_t *projectileinfo;
- weaponinfo_t *weaponinfo;
-} weaponconfig_t;
-
-//the bot weapon state
-typedef struct bot_weaponstate_s
-{
- struct weightconfig_s *weaponweightconfig; //weapon weight configuration
- int *weaponweightindex; //weapon weight index
-} bot_weaponstate_t;
-
-static bot_weaponstate_t *botweaponstates[MAX_CLIENTS+1];
-static weaponconfig_t *weaponconfig;
-
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-int BotValidWeaponNumber(int weaponnum)
-{
- if (weaponnum <= 0 || weaponnum > weaponconfig->numweapons)
- {
- botimport.Print(PRT_ERROR, "weapon number out of range\n");
- return qfalse;
- } //end if
- return qtrue;
-} //end of the function BotValidWeaponNumber
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-bot_weaponstate_t *BotWeaponStateFromHandle(int handle)
-{
- if (handle <= 0 || handle > MAX_CLIENTS)
- {
- botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
- return NULL;
- } //end if
- if (!botweaponstates[handle])
- {
- botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
- return NULL;
- } //end if
- return botweaponstates[handle];
-} //end of the function BotWeaponStateFromHandle
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef DEBUG_AI_WEAP
-void DumpWeaponConfig(weaponconfig_t *wc)
-{
- FILE *fp;
- int i;
-
- fp = Log_FileStruct();
- if (!fp) return;
- for (i = 0; i < wc->numprojectiles; i++)
- {
- WriteStructure(fp, &projectileinfo_struct, (char *) &wc->projectileinfo[i]);
- Log_Flush();
- } //end for
- for (i = 0; i < wc->numweapons; i++)
- {
- WriteStructure(fp, &weaponinfo_struct, (char *) &wc->weaponinfo[i]);
- Log_Flush();
- } //end for
-} //end of the function DumpWeaponConfig
-#endif //DEBUG_AI_WEAP
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-weaponconfig_t *LoadWeaponConfig(char *filename)
-{
- int max_weaponinfo, max_projectileinfo;
- token_t token;
- char path[MAX_PATH];
- int i, j;
- source_t *source;
- weaponconfig_t *wc;
- weaponinfo_t weaponinfo;
-
- max_weaponinfo = (int) LibVarValue("max_weaponinfo", "32");
- if (max_weaponinfo < 0)
- {
- botimport.Print(PRT_ERROR, "max_weaponinfo = %d\n", max_weaponinfo);
- max_weaponinfo = 32;
- LibVarSet("max_weaponinfo", "32");
- } //end if
- max_projectileinfo = (int) LibVarValue("max_projectileinfo", "32");
- if (max_projectileinfo < 0)
- {
- botimport.Print(PRT_ERROR, "max_projectileinfo = %d\n", max_projectileinfo);
- max_projectileinfo = 32;
- LibVarSet("max_projectileinfo", "32");
- } //end if
- strncpy(path, filename, MAX_PATH);
- PC_SetBaseFolder(BOTFILESBASEFOLDER);
- source = LoadSourceFile(path);
- if (!source)
- {
- botimport.Print(PRT_ERROR, "counldn't load %s\n", path);
- return NULL;
- } //end if
- //initialize weapon config
- wc = (weaponconfig_t *) GetClearedHunkMemory(sizeof(weaponconfig_t) +
- max_weaponinfo * sizeof(weaponinfo_t) +
- max_projectileinfo * sizeof(projectileinfo_t));
- wc->weaponinfo = (weaponinfo_t *) ((char *) wc + sizeof(weaponconfig_t));
- wc->projectileinfo = (projectileinfo_t *) ((char *) wc->weaponinfo +
- max_weaponinfo * sizeof(weaponinfo_t));
- wc->numweapons = max_weaponinfo;
- wc->numprojectiles = 0;
- //parse the source file
- while(PC_ReadToken(source, &token))
- {
- if (!strcmp(token.string, "weaponinfo"))
- {
- Com_Memset(&weaponinfo, 0, sizeof(weaponinfo_t));
- if (!ReadStructure(source, &weaponinfo_struct, (char *) &weaponinfo))
- {
- FreeMemory(wc);
- FreeSource(source);
- return NULL;
- } //end if
- if (weaponinfo.number < 0 || weaponinfo.number >= max_weaponinfo)
- {
- botimport.Print(PRT_ERROR, "weapon info number %d out of range in %s\n", weaponinfo.number, path);
- FreeMemory(wc);
- FreeSource(source);
- return NULL;
- } //end if
- Com_Memcpy(&wc->weaponinfo[weaponinfo.number], &weaponinfo, sizeof(weaponinfo_t));
- wc->weaponinfo[weaponinfo.number].valid = qtrue;
- } //end if
- else if (!strcmp(token.string, "projectileinfo"))
- {
- if (wc->numprojectiles >= max_projectileinfo)
- {
- botimport.Print(PRT_ERROR, "more than %d projectiles defined in %s\n", max_projectileinfo, path);
- FreeMemory(wc);
- FreeSource(source);
- return NULL;
- } //end if
- Com_Memset(&wc->projectileinfo[wc->numprojectiles], 0, sizeof(projectileinfo_t));
- if (!ReadStructure(source, &projectileinfo_struct, (char *) &wc->projectileinfo[wc->numprojectiles]))
- {
- FreeMemory(wc);
- FreeSource(source);
- return NULL;
- } //end if
- wc->numprojectiles++;
- } //end if
- else
- {
- botimport.Print(PRT_ERROR, "unknown definition %s in %s\n", token.string, path);
- FreeMemory(wc);
- FreeSource(source);
- return NULL;
- } //end else
- } //end while
- FreeSource(source);
- //fix up weapons
- for (i = 0; i < wc->numweapons; i++)
- {
- if (!wc->weaponinfo[i].valid) continue;
- if (!wc->weaponinfo[i].name[0])
- {
- botimport.Print(PRT_ERROR, "weapon %d has no name in %s\n", i, path);
- FreeMemory(wc);
- return NULL;
- } //end if
- if (!wc->weaponinfo[i].projectile[0])
- {
- botimport.Print(PRT_ERROR, "weapon %s has no projectile in %s\n", wc->weaponinfo[i].name, path);
- FreeMemory(wc);
- return NULL;
- } //end if
- //find the projectile info and copy it to the weapon info
- for (j = 0; j < wc->numprojectiles; j++)
- {
- if (!strcmp(wc->projectileinfo[j].name, wc->weaponinfo[i].projectile))
- {
- Com_Memcpy(&wc->weaponinfo[i].proj, &wc->projectileinfo[j], sizeof(projectileinfo_t));
- break;
- } //end if
- } //end for
- if (j == wc->numprojectiles)
- {
- botimport.Print(PRT_ERROR, "weapon %s uses undefined projectile in %s\n", wc->weaponinfo[i].name, path);
- FreeMemory(wc);
- return NULL;
- } //end if
- } //end for
- if (!wc->numweapons) botimport.Print(PRT_WARNING, "no weapon info loaded\n");
- botimport.Print(PRT_MESSAGE, "loaded %s\n", path);
- return wc;
-} //end of the function LoadWeaponConfig
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int *WeaponWeightIndex(weightconfig_t *wwc, weaponconfig_t *wc)
-{
- int *index, i;
-
- //initialize item weight index
- index = (int *) GetClearedMemory(sizeof(int) * wc->numweapons);
-
- for (i = 0; i < wc->numweapons; i++)
- {
- index[i] = FindFuzzyWeight(wwc, wc->weaponinfo[i].name);
- } //end for
- return index;
-} //end of the function WeaponWeightIndex
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotFreeWeaponWeights(int weaponstate)
-{
- bot_weaponstate_t *ws;
-
- ws = BotWeaponStateFromHandle(weaponstate);
- if (!ws) return;
- if (ws->weaponweightconfig) FreeWeightConfig(ws->weaponweightconfig);
- if (ws->weaponweightindex) FreeMemory(ws->weaponweightindex);
-} //end of the function BotFreeWeaponWeights
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotLoadWeaponWeights(int weaponstate, char *filename)
-{
- bot_weaponstate_t *ws;
-
- ws = BotWeaponStateFromHandle(weaponstate);
- if (!ws) return BLERR_CANNOTLOADWEAPONWEIGHTS;
- BotFreeWeaponWeights(weaponstate);
- //
- ws->weaponweightconfig = ReadWeightConfig(filename);
- if (!ws->weaponweightconfig)
- {
- botimport.Print(PRT_FATAL, "couldn't load weapon config %s\n", filename);
- return BLERR_CANNOTLOADWEAPONWEIGHTS;
- } //end if
- if (!weaponconfig) return BLERR_CANNOTLOADWEAPONCONFIG;
- ws->weaponweightindex = WeaponWeightIndex(ws->weaponweightconfig, weaponconfig);
- return BLERR_NOERROR;
-} //end of the function BotLoadWeaponWeights
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotGetWeaponInfo(int weaponstate, int weapon, weaponinfo_t *weaponinfo)
-{
- bot_weaponstate_t *ws;
-
- if (!BotValidWeaponNumber(weapon)) return;
- ws = BotWeaponStateFromHandle(weaponstate);
- if (!ws) return;
- if (!weaponconfig) return;
- Com_Memcpy(weaponinfo, &weaponconfig->weaponinfo[weapon], sizeof(weaponinfo_t));
-} //end of the function BotGetWeaponInfo
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotChooseBestFightWeapon(int weaponstate, int *inventory)
-{
- int i, index, bestweapon;
- float weight, bestweight;
- weaponconfig_t *wc;
- bot_weaponstate_t *ws;
-
- ws = BotWeaponStateFromHandle(weaponstate);
- if (!ws) return 0;
- wc = weaponconfig;
- if (!weaponconfig) return 0;
-
- //if the bot has no weapon weight configuration
- if (!ws->weaponweightconfig) return 0;
-
- bestweight = 0;
- bestweapon = 0;
- for (i = 0; i < wc->numweapons; i++)
- {
- if (!wc->weaponinfo[i].valid) continue;
- index = ws->weaponweightindex[i];
- if (index < 0) continue;
- weight = FuzzyWeight(inventory, ws->weaponweightconfig, index);
- if (weight > bestweight)
- {
- bestweight = weight;
- bestweapon = i;
- } //end if
- } //end for
- return bestweapon;
-} //end of the function BotChooseBestFightWeapon
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotResetWeaponState(int weaponstate)
-{
- struct weightconfig_s *weaponweightconfig;
- int *weaponweightindex;
- bot_weaponstate_t *ws;
-
- ws = BotWeaponStateFromHandle(weaponstate);
- if (!ws) return;
- weaponweightconfig = ws->weaponweightconfig;
- weaponweightindex = ws->weaponweightindex;
-
- //Com_Memset(ws, 0, sizeof(bot_weaponstate_t));
- ws->weaponweightconfig = weaponweightconfig;
- ws->weaponweightindex = weaponweightindex;
-} //end of the function BotResetWeaponState
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-int BotAllocWeaponState(void)
-{
- int i;
-
- for (i = 1; i <= MAX_CLIENTS; i++)
- {
- if (!botweaponstates[i])
- {
- botweaponstates[i] = GetClearedMemory(sizeof(bot_weaponstate_t));
- return i;
- } //end if
- } //end for
- return 0;
-} //end of the function BotAllocWeaponState
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-void BotFreeWeaponState(int handle)
-{
- if (handle <= 0 || handle > MAX_CLIENTS)
- {
- botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
- return;
- } //end if
- if (!botweaponstates[handle])
- {
- botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
- return;
- } //end if
- BotFreeWeaponWeights(handle);
- FreeMemory(botweaponstates[handle]);
- botweaponstates[handle] = NULL;
-} //end of the function BotFreeWeaponState
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotSetupWeaponAI(void)
-{
- char *file;
-
- file = LibVarString("weaponconfig", "weapons.c");
- weaponconfig = LoadWeaponConfig(file);
- if (!weaponconfig)
- {
- botimport.Print(PRT_FATAL, "couldn't load the weapon config\n");
- return BLERR_CANNOTLOADWEAPONCONFIG;
- } //end if
-
-#ifdef DEBUG_AI_WEAP
- DumpWeaponConfig(weaponconfig);
-#endif //DEBUG_AI_WEAP
- //
- return BLERR_NOERROR;
-} //end of the function BotSetupWeaponAI
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotShutdownWeaponAI(void)
-{
- int i;
-
- if (weaponconfig) FreeMemory(weaponconfig);
- weaponconfig = NULL;
-
- for (i = 1; i <= MAX_CLIENTS; i++)
- {
- if (botweaponstates[i])
- {
- BotFreeWeaponState(i);
- } //end if
- } //end for
-} //end of the function BotShutdownWeaponAI
-
diff --git a/engine/code/botlib/be_ai_weight.c b/engine/code/botlib/be_ai_weight.c
deleted file mode 100644
index 17216ab..0000000
--- a/engine/code/botlib/be_ai_weight.c
+++ /dev/null
@@ -1,925 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_ai_weight.c
- *
- * desc: fuzzy logic
- *
- * $Archive: /MissionPack/code/botlib/be_ai_weight.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_log.h"
-#include "l_utils.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "l_libvar.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-#include "be_ai_weight.h"
-
-#define MAX_INVENTORYVALUE 999999
-#define EVALUATERECURSIVELY
-
-#define MAX_WEIGHT_FILES 128
-weightconfig_t *weightFileList[MAX_WEIGHT_FILES];
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int ReadValue(source_t *source, float *value)
-{
- token_t token;
-
- if (!PC_ExpectAnyToken(source, &token)) return qfalse;
- if (!strcmp(token.string, "-"))
- {
- SourceWarning(source, "negative value set to zero\n");
-
- if(!PC_ExpectAnyToken(source, &token))
- {
- SourceError(source, "Missing return value\n");
- return qfalse;
- }
- }
-
- if (token.type != TT_NUMBER)
- {
- SourceError(source, "invalid return value %s\n", token.string);
- return qfalse;
- }
-
- *value = token.floatvalue;
- return qtrue;
-} //end of the function ReadValue
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int ReadFuzzyWeight(source_t *source, fuzzyseperator_t *fs)
-{
- if (PC_CheckTokenString(source, "balance"))
- {
- fs->type = WT_BALANCE;
- if (!PC_ExpectTokenString(source, "(")) return qfalse;
- if (!ReadValue(source, &fs->weight)) return qfalse;
- if (!PC_ExpectTokenString(source, ",")) return qfalse;
- if (!ReadValue(source, &fs->minweight)) return qfalse;
- if (!PC_ExpectTokenString(source, ",")) return qfalse;
- if (!ReadValue(source, &fs->maxweight)) return qfalse;
- if (!PC_ExpectTokenString(source, ")")) return qfalse;
- } //end if
- else
- {
- fs->type = 0;
- if (!ReadValue(source, &fs->weight)) return qfalse;
- fs->minweight = fs->weight;
- fs->maxweight = fs->weight;
- } //end if
- if (!PC_ExpectTokenString(source, ";")) return qfalse;
- return qtrue;
-} //end of the function ReadFuzzyWeight
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FreeFuzzySeperators_r(fuzzyseperator_t *fs)
-{
- if (!fs) return;
- if (fs->child) FreeFuzzySeperators_r(fs->child);
- if (fs->next) FreeFuzzySeperators_r(fs->next);
- FreeMemory(fs);
-} //end of the function FreeFuzzySeperators
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FreeWeightConfig2(weightconfig_t *config)
-{
- int i;
-
- for (i = 0; i < config->numweights; i++)
- {
- FreeFuzzySeperators_r(config->weights[i].firstseperator);
- if (config->weights[i].name) FreeMemory(config->weights[i].name);
- } //end for
- FreeMemory(config);
-} //end of the function FreeWeightConfig2
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FreeWeightConfig(weightconfig_t *config)
-{
- if (!LibVarGetValue("bot_reloadcharacters")) return;
- FreeWeightConfig2(config);
-} //end of the function FreeWeightConfig
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-fuzzyseperator_t *ReadFuzzySeperators_r(source_t *source)
-{
- int newindent, index, def, founddefault;
- token_t token;
- fuzzyseperator_t *fs, *lastfs, *firstfs;
-
- founddefault = qfalse;
- firstfs = NULL;
- lastfs = NULL;
- if (!PC_ExpectTokenString(source, "(")) return NULL;
- if (!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token)) return NULL;
- index = token.intvalue;
- if (!PC_ExpectTokenString(source, ")")) return NULL;
- if (!PC_ExpectTokenString(source, "{")) return NULL;
- if (!PC_ExpectAnyToken(source, &token)) return NULL;
- do
- {
- def = !strcmp(token.string, "default");
- if (def || !strcmp(token.string, "case"))
- {
- fs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t));
- fs->index = index;
- if (lastfs) lastfs->next = fs;
- else firstfs = fs;
- lastfs = fs;
- if (def)
- {
- if (founddefault)
- {
- SourceError(source, "switch already has a default\n");
- FreeFuzzySeperators_r(firstfs);
- return NULL;
- } //end if
- fs->value = MAX_INVENTORYVALUE;
- founddefault = qtrue;
- } //end if
- else
- {
- if (!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token))
- {
- FreeFuzzySeperators_r(firstfs);
- return NULL;
- } //end if
- fs->value = token.intvalue;
- } //end else
- if (!PC_ExpectTokenString(source, ":") || !PC_ExpectAnyToken(source, &token))
- {
- FreeFuzzySeperators_r(firstfs);
- return NULL;
- } //end if
- newindent = qfalse;
- if (!strcmp(token.string, "{"))
- {
- newindent = qtrue;
- if (!PC_ExpectAnyToken(source, &token))
- {
- FreeFuzzySeperators_r(firstfs);
- return NULL;
- } //end if
- } //end if
- if (!strcmp(token.string, "return"))
- {
- if (!ReadFuzzyWeight(source, fs))
- {
- FreeFuzzySeperators_r(firstfs);
- return NULL;
- } //end if
- } //end if
- else if (!strcmp(token.string, "switch"))
- {
- fs->child = ReadFuzzySeperators_r(source);
- if (!fs->child)
- {
- FreeFuzzySeperators_r(firstfs);
- return NULL;
- } //end if
- } //end else if
- else
- {
- SourceError(source, "invalid name %s\n", token.string);
- return NULL;
- } //end else
- if (newindent)
- {
- if (!PC_ExpectTokenString(source, "}"))
- {
- FreeFuzzySeperators_r(firstfs);
- return NULL;
- } //end if
- } //end if
- } //end if
- else
- {
- FreeFuzzySeperators_r(firstfs);
- SourceError(source, "invalid name %s\n", token.string);
- return NULL;
- } //end else
- if (!PC_ExpectAnyToken(source, &token))
- {
- FreeFuzzySeperators_r(firstfs);
- return NULL;
- } //end if
- } while(strcmp(token.string, "}"));
- //
- if (!founddefault)
- {
- SourceWarning(source, "switch without default\n");
- fs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t));
- fs->index = index;
- fs->value = MAX_INVENTORYVALUE;
- fs->weight = 0;
- fs->next = NULL;
- fs->child = NULL;
- if (lastfs) lastfs->next = fs;
- else firstfs = fs;
- lastfs = fs;
- } //end if
- //
- return firstfs;
-} //end of the function ReadFuzzySeperators_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-weightconfig_t *ReadWeightConfig(char *filename)
-{
- int newindent, avail = 0, n;
- token_t token;
- source_t *source;
- fuzzyseperator_t *fs;
- weightconfig_t *config = NULL;
-#ifdef DEBUG
- int starttime;
-
- starttime = Sys_MilliSeconds();
-#endif //DEBUG
-
- if (!LibVarGetValue("bot_reloadcharacters"))
- {
- avail = -1;
- for( n = 0; n < MAX_WEIGHT_FILES; n++ )
- {
- config = weightFileList[n];
- if( !config )
- {
- if( avail == -1 )
- {
- avail = n;
- } //end if
- continue;
- } //end if
- if( strcmp( filename, config->filename ) == 0 )
- {
- //botimport.Print( PRT_MESSAGE, "retained %s\n", filename );
- return config;
- } //end if
- } //end for
-
- if( avail == -1 )
- {
- botimport.Print( PRT_ERROR, "weightFileList was full trying to load %s\n", filename );
- return NULL;
- } //end if
- } //end if
-
- PC_SetBaseFolder(BOTFILESBASEFOLDER);
- source = LoadSourceFile(filename);
- if (!source)
- {
- botimport.Print(PRT_ERROR, "counldn't load %s\n", filename);
- return NULL;
- } //end if
- //
- config = (weightconfig_t *) GetClearedMemory(sizeof(weightconfig_t));
- config->numweights = 0;
- Q_strncpyz( config->filename, filename, sizeof(config->filename) );
- //parse the item config file
- while(PC_ReadToken(source, &token))
- {
- if (!strcmp(token.string, "weight"))
- {
- if (config->numweights >= MAX_WEIGHTS)
- {
- SourceWarning(source, "too many fuzzy weights\n");
- break;
- } //end if
- if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
- {
- FreeWeightConfig(config);
- FreeSource(source);
- return NULL;
- } //end if
- StripDoubleQuotes(token.string);
- config->weights[config->numweights].name = (char *) GetClearedMemory(strlen(token.string) + 1);
- strcpy(config->weights[config->numweights].name, token.string);
- if (!PC_ExpectAnyToken(source, &token))
- {
- FreeWeightConfig(config);
- FreeSource(source);
- return NULL;
- } //end if
- newindent = qfalse;
- if (!strcmp(token.string, "{"))
- {
- newindent = qtrue;
- if (!PC_ExpectAnyToken(source, &token))
- {
- FreeWeightConfig(config);
- FreeSource(source);
- return NULL;
- } //end if
- } //end if
- if (!strcmp(token.string, "switch"))
- {
- fs = ReadFuzzySeperators_r(source);
- if (!fs)
- {
- FreeWeightConfig(config);
- FreeSource(source);
- return NULL;
- } //end if
- config->weights[config->numweights].firstseperator = fs;
- } //end if
- else if (!strcmp(token.string, "return"))
- {
- fs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t));
- fs->index = 0;
- fs->value = MAX_INVENTORYVALUE;
- fs->next = NULL;
- fs->child = NULL;
- if (!ReadFuzzyWeight(source, fs))
- {
- FreeMemory(fs);
- FreeWeightConfig(config);
- FreeSource(source);
- return NULL;
- } //end if
- config->weights[config->numweights].firstseperator = fs;
- } //end else if
- else
- {
- SourceError(source, "invalid name %s\n", token.string);
- FreeWeightConfig(config);
- FreeSource(source);
- return NULL;
- } //end else
- if (newindent)
- {
- if (!PC_ExpectTokenString(source, "}"))
- {
- FreeWeightConfig(config);
- FreeSource(source);
- return NULL;
- } //end if
- } //end if
- config->numweights++;
- } //end if
- else
- {
- SourceError(source, "invalid name %s\n", token.string);
- FreeWeightConfig(config);
- FreeSource(source);
- return NULL;
- } //end else
- } //end while
- //free the source at the end of a pass
- FreeSource(source);
- //if the file was located in a pak file
- botimport.Print(PRT_MESSAGE, "loaded %s\n", filename);
-#ifdef DEBUG
- if (botDeveloper)
- {
- botimport.Print(PRT_MESSAGE, "weights loaded in %d msec\n", Sys_MilliSeconds() - starttime);
- } //end if
-#endif //DEBUG
- //
- if (!LibVarGetValue("bot_reloadcharacters"))
- {
- weightFileList[avail] = config;
- } //end if
- //
- return config;
-} //end of the function ReadWeightConfig
-#if 0
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean WriteFuzzyWeight(FILE *fp, fuzzyseperator_t *fs)
-{
- if (fs->type == WT_BALANCE)
- {
- if (fprintf(fp, " return balance(") < 0) return qfalse;
- if (!WriteFloat(fp, fs->weight)) return qfalse;
- if (fprintf(fp, ",") < 0) return qfalse;
- if (!WriteFloat(fp, fs->minweight)) return qfalse;
- if (fprintf(fp, ",") < 0) return qfalse;
- if (!WriteFloat(fp, fs->maxweight)) return qfalse;
- if (fprintf(fp, ");\n") < 0) return qfalse;
- } //end if
- else
- {
- if (fprintf(fp, " return ") < 0) return qfalse;
- if (!WriteFloat(fp, fs->weight)) return qfalse;
- if (fprintf(fp, ";\n") < 0) return qfalse;
- } //end else
- return qtrue;
-} //end of the function WriteFuzzyWeight
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean WriteFuzzySeperators_r(FILE *fp, fuzzyseperator_t *fs, int indent)
-{
- if (!WriteIndent(fp, indent)) return qfalse;
- if (fprintf(fp, "switch(%d)\n", fs->index) < 0) return qfalse;
- if (!WriteIndent(fp, indent)) return qfalse;
- if (fprintf(fp, "{\n") < 0) return qfalse;
- indent++;
- do
- {
- if (!WriteIndent(fp, indent)) return qfalse;
- if (fs->next)
- {
- if (fprintf(fp, "case %d:", fs->value) < 0) return qfalse;
- } //end if
- else
- {
- if (fprintf(fp, "default:") < 0) return qfalse;
- } //end else
- if (fs->child)
- {
- if (fprintf(fp, "\n") < 0) return qfalse;
- if (!WriteIndent(fp, indent)) return qfalse;
- if (fprintf(fp, "{\n") < 0) return qfalse;
- if (!WriteFuzzySeperators_r(fp, fs->child, indent + 1)) return qfalse;
- if (!WriteIndent(fp, indent)) return qfalse;
- if (fs->next)
- {
- if (fprintf(fp, "} //end case\n") < 0) return qfalse;
- } //end if
- else
- {
- if (fprintf(fp, "} //end default\n") < 0) return qfalse;
- } //end else
- } //end if
- else
- {
- if (!WriteFuzzyWeight(fp, fs)) return qfalse;
- } //end else
- fs = fs->next;
- } while(fs);
- indent--;
- if (!WriteIndent(fp, indent)) return qfalse;
- if (fprintf(fp, "} //end switch\n") < 0) return qfalse;
- return qtrue;
-} //end of the function WriteItemFuzzyWeights_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean WriteWeightConfig(char *filename, weightconfig_t *config)
-{
- int i;
- FILE *fp;
- weight_t *ifw;
-
- fp = fopen(filename, "wb");
- if (!fp) return qfalse;
-
- for (i = 0; i < config->numweights; i++)
- {
- ifw = &config->weights[i];
- if (fprintf(fp, "\nweight \"%s\"\n", ifw->name) < 0) return qfalse;
- if (fprintf(fp, "{\n") < 0) return qfalse;
- if (ifw->firstseperator->index > 0)
- {
- if (!WriteFuzzySeperators_r(fp, ifw->firstseperator, 1)) return qfalse;
- } //end if
- else
- {
- if (!WriteIndent(fp, 1)) return qfalse;
- if (!WriteFuzzyWeight(fp, ifw->firstseperator)) return qfalse;
- } //end else
- if (fprintf(fp, "} //end weight\n") < 0) return qfalse;
- } //end for
- fclose(fp);
- return qtrue;
-} //end of the function WriteWeightConfig
-#endif
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int FindFuzzyWeight(weightconfig_t *wc, char *name)
-{
- int i;
-
- for (i = 0; i < wc->numweights; i++)
- {
- if (!strcmp(wc->weights[i].name, name))
- {
- return i;
- } //end if
- } //end if
- return -1;
-} //end of the function FindFuzzyWeight
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float FuzzyWeight_r(int *inventory, fuzzyseperator_t *fs)
-{
- float scale, w1, w2;
-
- if (inventory[fs->index] < fs->value)
- {
- if (fs->child) return FuzzyWeight_r(inventory, fs->child);
- else return fs->weight;
- } //end if
- else if (fs->next)
- {
- if (inventory[fs->index] < fs->next->value)
- {
- //first weight
- if (fs->child) w1 = FuzzyWeight_r(inventory, fs->child);
- else w1 = fs->weight;
- //second weight
- if (fs->next->child) w2 = FuzzyWeight_r(inventory, fs->next->child);
- else w2 = fs->next->weight;
- //the scale factor
- if(fs->next->value == MAX_INVENTORYVALUE) // is fs->next the default case?
- return w2; // can't interpolate, return default weight
- else
- scale = (float) (inventory[fs->index] - fs->value) / (fs->next->value - fs->value);
- //scale between the two weights
- return (1 - scale) * w1 + scale * w2;
- } //end if
- return FuzzyWeight_r(inventory, fs->next);
- } //end else if
- return fs->weight;
-} //end of the function FuzzyWeight_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float FuzzyWeightUndecided_r(int *inventory, fuzzyseperator_t *fs)
-{
- float scale, w1, w2;
-
- if (inventory[fs->index] < fs->value)
- {
- if (fs->child) return FuzzyWeightUndecided_r(inventory, fs->child);
- else return fs->minweight + random() * (fs->maxweight - fs->minweight);
- } //end if
- else if (fs->next)
- {
- if (inventory[fs->index] < fs->next->value)
- {
- //first weight
- if (fs->child) w1 = FuzzyWeightUndecided_r(inventory, fs->child);
- else w1 = fs->minweight + random() * (fs->maxweight - fs->minweight);
- //second weight
- if (fs->next->child) w2 = FuzzyWeight_r(inventory, fs->next->child);
- else w2 = fs->next->minweight + random() * (fs->next->maxweight - fs->next->minweight);
- //the scale factor
- if(fs->next->value == MAX_INVENTORYVALUE) // is fs->next the default case?
- return w2; // can't interpolate, return default weight
- else
- scale = (float) (inventory[fs->index] - fs->value) / (fs->next->value - fs->value);
- //scale between the two weights
- return (1 - scale) * w1 + scale * w2;
- } //end if
- return FuzzyWeightUndecided_r(inventory, fs->next);
- } //end else if
- return fs->weight;
-} //end of the function FuzzyWeightUndecided_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float FuzzyWeight(int *inventory, weightconfig_t *wc, int weightnum)
-{
-#ifdef EVALUATERECURSIVELY
- return FuzzyWeight_r(inventory, wc->weights[weightnum].firstseperator);
-#else
- fuzzyseperator_t *s;
-
- s = wc->weights[weightnum].firstseperator;
- if (!s) return 0;
- while(1)
- {
- if (inventory[s->index] < s->value)
- {
- if (s->child) s = s->child;
- else return s->weight;
- } //end if
- else
- {
- if (s->next) s = s->next;
- else return s->weight;
- } //end else
- } //end if
- return 0;
-#endif
-} //end of the function FuzzyWeight
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float FuzzyWeightUndecided(int *inventory, weightconfig_t *wc, int weightnum)
-{
-#ifdef EVALUATERECURSIVELY
- return FuzzyWeightUndecided_r(inventory, wc->weights[weightnum].firstseperator);
-#else
- fuzzyseperator_t *s;
-
- s = wc->weights[weightnum].firstseperator;
- if (!s) return 0;
- while(1)
- {
- if (inventory[s->index] < s->value)
- {
- if (s->child) s = s->child;
- else return s->minweight + random() * (s->maxweight - s->minweight);
- } //end if
- else
- {
- if (s->next) s = s->next;
- else return s->minweight + random() * (s->maxweight - s->minweight);
- } //end else
- } //end if
- return 0;
-#endif
-} //end of the function FuzzyWeightUndecided
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EvolveFuzzySeperator_r(fuzzyseperator_t *fs)
-{
- if (fs->child)
- {
- EvolveFuzzySeperator_r(fs->child);
- } //end if
- else if (fs->type == WT_BALANCE)
- {
- //every once in a while an evolution leap occurs, mutation
- if (random() < 0.01) fs->weight += crandom() * (fs->maxweight - fs->minweight);
- else fs->weight += crandom() * (fs->maxweight - fs->minweight) * 0.5;
- //modify bounds if necesary because of mutation
- if (fs->weight < fs->minweight) fs->minweight = fs->weight;
- else if (fs->weight > fs->maxweight) fs->maxweight = fs->weight;
- } //end else if
- if (fs->next) EvolveFuzzySeperator_r(fs->next);
-} //end of the function EvolveFuzzySeperator_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EvolveWeightConfig(weightconfig_t *config)
-{
- int i;
-
- for (i = 0; i < config->numweights; i++)
- {
- EvolveFuzzySeperator_r(config->weights[i].firstseperator);
- } //end for
-} //end of the function EvolveWeightConfig
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ScaleFuzzySeperator_r(fuzzyseperator_t *fs, float scale)
-{
- if (fs->child)
- {
- ScaleFuzzySeperator_r(fs->child, scale);
- } //end if
- else if (fs->type == WT_BALANCE)
- {
- //
- fs->weight = (float) (fs->maxweight + fs->minweight) * scale;
- //get the weight between bounds
- if (fs->weight < fs->minweight) fs->weight = fs->minweight;
- else if (fs->weight > fs->maxweight) fs->weight = fs->maxweight;
- } //end else if
- if (fs->next) ScaleFuzzySeperator_r(fs->next, scale);
-} //end of the function ScaleFuzzySeperator_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ScaleWeight(weightconfig_t *config, char *name, float scale)
-{
- int i;
-
- if (scale < 0) scale = 0;
- else if (scale > 1) scale = 1;
- for (i = 0; i < config->numweights; i++)
- {
- if (!strcmp(name, config->weights[i].name))
- {
- ScaleFuzzySeperator_r(config->weights[i].firstseperator, scale);
- break;
- } //end if
- } //end for
-} //end of the function ScaleWeight
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ScaleFuzzySeperatorBalanceRange_r(fuzzyseperator_t *fs, float scale)
-{
- if (fs->child)
- {
- ScaleFuzzySeperatorBalanceRange_r(fs->child, scale);
- } //end if
- else if (fs->type == WT_BALANCE)
- {
- float mid = (fs->minweight + fs->maxweight) * 0.5;
- //get the weight between bounds
- fs->maxweight = mid + (fs->maxweight - mid) * scale;
- fs->minweight = mid + (fs->minweight - mid) * scale;
- if (fs->maxweight < fs->minweight)
- {
- fs->maxweight = fs->minweight;
- } //end if
- } //end else if
- if (fs->next) ScaleFuzzySeperatorBalanceRange_r(fs->next, scale);
-} //end of the function ScaleFuzzySeperatorBalanceRange_r
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void ScaleFuzzyBalanceRange(weightconfig_t *config, float scale)
-{
- int i;
-
- if (scale < 0) scale = 0;
- else if (scale > 100) scale = 100;
- for (i = 0; i < config->numweights; i++)
- {
- ScaleFuzzySeperatorBalanceRange_r(config->weights[i].firstseperator, scale);
- } //end for
-} //end of the function ScaleFuzzyBalanceRange
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int InterbreedFuzzySeperator_r(fuzzyseperator_t *fs1, fuzzyseperator_t *fs2,
- fuzzyseperator_t *fsout)
-{
- if (fs1->child)
- {
- if (!fs2->child || !fsout->child)
- {
- botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal child\n");
- return qfalse;
- } //end if
- if (!InterbreedFuzzySeperator_r(fs2->child, fs2->child, fsout->child))
- {
- return qfalse;
- } //end if
- } //end if
- else if (fs1->type == WT_BALANCE)
- {
- if (fs2->type != WT_BALANCE || fsout->type != WT_BALANCE)
- {
- botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal balance\n");
- return qfalse;
- } //end if
- fsout->weight = (fs1->weight + fs2->weight) / 2;
- if (fsout->weight > fsout->maxweight) fsout->maxweight = fsout->weight;
- if (fsout->weight > fsout->minweight) fsout->minweight = fsout->weight;
- } //end else if
- if (fs1->next)
- {
- if (!fs2->next || !fsout->next)
- {
- botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal next\n");
- return qfalse;
- } //end if
- if (!InterbreedFuzzySeperator_r(fs1->next, fs2->next, fsout->next))
- {
- return qfalse;
- } //end if
- } //end if
- return qtrue;
-} //end of the function InterbreedFuzzySeperator_r
-//===========================================================================
-// config1 and config2 are interbreeded and stored in configout
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void InterbreedWeightConfigs(weightconfig_t *config1, weightconfig_t *config2,
- weightconfig_t *configout)
-{
- int i;
-
- if (config1->numweights != config2->numweights ||
- config1->numweights != configout->numweights)
- {
- botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal numweights\n");
- return;
- } //end if
- for (i = 0; i < config1->numweights; i++)
- {
- InterbreedFuzzySeperator_r(config1->weights[i].firstseperator,
- config2->weights[i].firstseperator,
- configout->weights[i].firstseperator);
- } //end for
-} //end of the function InterbreedWeightConfigs
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotShutdownWeights(void)
-{
- int i;
-
- for( i = 0; i < MAX_WEIGHT_FILES; i++ )
- {
- if (weightFileList[i])
- {
- FreeWeightConfig2(weightFileList[i]);
- weightFileList[i] = NULL;
- } //end if
- } //end for
-} //end of the function BotShutdownWeights
diff --git a/engine/code/botlib/be_ea.c b/engine/code/botlib/be_ea.c
deleted file mode 100644
index c357b11..0000000
--- a/engine/code/botlib/be_ea.c
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_ea.c
- *
- * desc: elementary actions
- *
- * $Archive: /MissionPack/code/botlib/be_ea.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "botlib.h"
-#include "be_interface.h"
-#include "be_ea.h"
-
-#define MAX_USERMOVE 400
-#define MAX_COMMANDARGUMENTS 10
-#define ACTION_JUMPEDLASTFRAME 128
-
-bot_input_t *botinputs;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Say(int client, char *str)
-{
- botimport.BotClientCommand(client, va("say %s", str) );
-} //end of the function EA_Say
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_SayTeam(int client, char *str)
-{
- botimport.BotClientCommand(client, va("say_team %s", str));
-} //end of the function EA_SayTeam
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Tell(int client, int clientto, char *str)
-{
- botimport.BotClientCommand(client, va("tell %d, %s", clientto, str));
-} //end of the function EA_SayTeam
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_UseItem(int client, char *it)
-{
- botimport.BotClientCommand(client, va("use %s", it));
-} //end of the function EA_UseItem
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_DropItem(int client, char *it)
-{
- botimport.BotClientCommand(client, va("drop %s", it));
-} //end of the function EA_DropItem
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_UseInv(int client, char *inv)
-{
- botimport.BotClientCommand(client, va("invuse %s", inv));
-} //end of the function EA_UseInv
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_DropInv(int client, char *inv)
-{
- botimport.BotClientCommand(client, va("invdrop %s", inv));
-} //end of the function EA_DropInv
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Gesture(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= ACTION_GESTURE;
-} //end of the function EA_Gesture
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Command(int client, char *command)
-{
- botimport.BotClientCommand(client, command);
-} //end of the function EA_Command
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_SelectWeapon(int client, int weapon)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->weapon = weapon;
-} //end of the function EA_SelectWeapon
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Attack(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= ACTION_ATTACK;
-} //end of the function EA_Attack
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Talk(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= ACTION_TALK;
-} //end of the function EA_Talk
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Use(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= ACTION_USE;
-} //end of the function EA_Use
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Respawn(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= ACTION_RESPAWN;
-} //end of the function EA_Respawn
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Jump(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- if (bi->actionflags & ACTION_JUMPEDLASTFRAME)
- {
- bi->actionflags &= ~ACTION_JUMP;
- } //end if
- else
- {
- bi->actionflags |= ACTION_JUMP;
- } //end if
-} //end of the function EA_Jump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_DelayedJump(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- if (bi->actionflags & ACTION_JUMPEDLASTFRAME)
- {
- bi->actionflags &= ~ACTION_DELAYEDJUMP;
- } //end if
- else
- {
- bi->actionflags |= ACTION_DELAYEDJUMP;
- } //end if
-} //end of the function EA_DelayedJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Crouch(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= ACTION_CROUCH;
-} //end of the function EA_Crouch
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Walk(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= ACTION_WALK;
-} //end of the function EA_Walk
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Action(int client, int action)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= action;
-} //end of function EA_Action
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_MoveUp(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= ACTION_MOVEUP;
-} //end of the function EA_MoveUp
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_MoveDown(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= ACTION_MOVEDOWN;
-} //end of the function EA_MoveDown
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_MoveForward(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= ACTION_MOVEFORWARD;
-} //end of the function EA_MoveForward
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_MoveBack(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= ACTION_MOVEBACK;
-} //end of the function EA_MoveBack
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_MoveLeft(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= ACTION_MOVELEFT;
-} //end of the function EA_MoveLeft
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_MoveRight(int client)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- bi->actionflags |= ACTION_MOVERIGHT;
-} //end of the function EA_MoveRight
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Move(int client, vec3_t dir, float speed)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- VectorCopy(dir, bi->dir);
- //cap speed
- if (speed > MAX_USERMOVE) speed = MAX_USERMOVE;
- else if (speed < -MAX_USERMOVE) speed = -MAX_USERMOVE;
- bi->speed = speed;
-} //end of the function EA_Move
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_View(int client, vec3_t viewangles)
-{
- bot_input_t *bi;
-
- bi = &botinputs[client];
-
- VectorCopy(viewangles, bi->viewangles);
-} //end of the function EA_View
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_EndRegular(int client, float thinktime)
-{
-/*
- bot_input_t *bi;
- int jumped = qfalse;
-
- bi = &botinputs[client];
-
- bi->actionflags &= ~ACTION_JUMPEDLASTFRAME;
-
- bi->thinktime = thinktime;
- botimport.BotInput(client, bi);
-
- bi->thinktime = 0;
- VectorClear(bi->dir);
- bi->speed = 0;
- jumped = bi->actionflags & ACTION_JUMP;
- bi->actionflags = 0;
- if (jumped) bi->actionflags |= ACTION_JUMPEDLASTFRAME;
-*/
-} //end of the function EA_EndRegular
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_GetInput(int client, float thinktime, bot_input_t *input)
-{
- bot_input_t *bi;
-// int jumped = qfalse;
-
- bi = &botinputs[client];
-
-// bi->actionflags &= ~ACTION_JUMPEDLASTFRAME;
-
- bi->thinktime = thinktime;
- Com_Memcpy(input, bi, sizeof(bot_input_t));
-
- /*
- bi->thinktime = 0;
- VectorClear(bi->dir);
- bi->speed = 0;
- jumped = bi->actionflags & ACTION_JUMP;
- bi->actionflags = 0;
- if (jumped) bi->actionflags |= ACTION_JUMPEDLASTFRAME;
- */
-} //end of the function EA_GetInput
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_ResetInput(int client)
-{
- bot_input_t *bi;
- int jumped = qfalse;
-
- bi = &botinputs[client];
- bi->actionflags &= ~ACTION_JUMPEDLASTFRAME;
-
- bi->thinktime = 0;
- VectorClear(bi->dir);
- bi->speed = 0;
- jumped = bi->actionflags & ACTION_JUMP;
- bi->actionflags = 0;
- if (jumped) bi->actionflags |= ACTION_JUMPEDLASTFRAME;
-} //end of the function EA_ResetInput
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int EA_Setup(void)
-{
- //initialize the bot inputs
- botinputs = (bot_input_t *) GetClearedHunkMemory(
- botlibglobals.maxclients * sizeof(bot_input_t));
- return BLERR_NOERROR;
-} //end of the function EA_Setup
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void EA_Shutdown(void)
-{
- FreeMemory(botinputs);
- botinputs = NULL;
-} //end of the function EA_Shutdown
diff --git a/engine/code/botlib/be_interface.c b/engine/code/botlib/be_interface.c
deleted file mode 100644
index 3f57df5..0000000
--- a/engine/code/botlib/be_interface.c
+++ /dev/null
@@ -1,901 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_interface.c
- *
- * desc: bot library interface
- *
- * $Archive: /MissionPack/code/botlib/be_interface.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_log.h"
-#include "l_libvar.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "aasfile.h"
-#include "botlib.h"
-#include "be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_aas_def.h"
-#include "be_interface.h"
-
-#include "be_ea.h"
-#include "be_ai_weight.h"
-#include "be_ai_goal.h"
-#include "be_ai_move.h"
-#include "be_ai_weap.h"
-#include "be_ai_chat.h"
-#include "be_ai_char.h"
-#include "be_ai_gen.h"
-
-//library globals in a structure
-botlib_globals_t botlibglobals;
-
-botlib_export_t be_botlib_export;
-botlib_import_t botimport;
-//
-int botDeveloper;
-//qtrue if the library is setup
-int botlibsetup = qfalse;
-
-//===========================================================================
-//
-// several functions used by the exported functions
-//
-//===========================================================================
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Sys_MilliSeconds(void)
-{
- return clock() * 1000 / CLOCKS_PER_SEC;
-} //end of the function Sys_MilliSeconds
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean ValidClientNumber(int num, char *str)
-{
- if (num < 0 || num > botlibglobals.maxclients)
- {
- //weird: the disabled stuff results in a crash
- botimport.Print(PRT_ERROR, "%s: invalid client number %d, [0, %d]\n",
- str, num, botlibglobals.maxclients);
- return qfalse;
- } //end if
- return qtrue;
-} //end of the function BotValidateClientNumber
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean ValidEntityNumber(int num, char *str)
-{
- if (num < 0 || num > botlibglobals.maxentities)
- {
- botimport.Print(PRT_ERROR, "%s: invalid entity number %d, [0, %d]\n",
- str, num, botlibglobals.maxentities);
- return qfalse;
- } //end if
- return qtrue;
-} //end of the function BotValidateClientNumber
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean BotLibSetup(char *str)
-{
- if (!botlibglobals.botlibsetup)
- {
- botimport.Print(PRT_ERROR, "%s: bot library used before being setup\n", str);
- return qfalse;
- } //end if
- return qtrue;
-} //end of the function BotLibSetup
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Export_BotLibSetup(void)
-{
- int errnum;
-
- botDeveloper = LibVarGetValue("bot_developer");
- memset( &botlibglobals, 0, sizeof(botlibglobals) );
- //initialize byte swapping (litte endian etc.)
-// Swap_Init();
-
- if(botDeveloper)
- {
- char *homedir, *gamedir;
- char logfilename[MAX_OSPATH];
-
- homedir = LibVarGetString("homedir");
- gamedir = LibVarGetString("gamedir");
-
- if (*homedir)
- {
- if(*gamedir)
- Com_sprintf(logfilename, sizeof(logfilename), "%s%c%s%cbotlib.log", homedir, PATH_SEP, gamedir, PATH_SEP);
- else
- Com_sprintf(logfilename, sizeof(logfilename), "%s%c" BASEGAME "%cbotlib.log", homedir, PATH_SEP, PATH_SEP);
- }
- else
- Com_sprintf(logfilename, sizeof(logfilename), "botlib.log");
-
- Log_Open(logfilename);
- }
-
- botimport.Print(PRT_MESSAGE, "------- BotLib Initialization -------\n");
-
- botlibglobals.maxclients = (int) LibVarValue("maxclients", "128");
- botlibglobals.maxentities = (int) LibVarValue("maxentities", "1024");
-
- errnum = AAS_Setup(); //be_aas_main.c
- if (errnum != BLERR_NOERROR) return errnum;
- errnum = EA_Setup(); //be_ea.c
- if (errnum != BLERR_NOERROR) return errnum;
- errnum = BotSetupWeaponAI(); //be_ai_weap.c
- if (errnum != BLERR_NOERROR)return errnum;
- errnum = BotSetupGoalAI(); //be_ai_goal.c
- if (errnum != BLERR_NOERROR) return errnum;
- errnum = BotSetupChatAI(); //be_ai_chat.c
- if (errnum != BLERR_NOERROR) return errnum;
- errnum = BotSetupMoveAI(); //be_ai_move.c
- if (errnum != BLERR_NOERROR) return errnum;
-
- botlibsetup = qtrue;
- botlibglobals.botlibsetup = qtrue;
-
- return BLERR_NOERROR;
-} //end of the function Export_BotLibSetup
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Export_BotLibShutdown(void)
-{
- if (!BotLibSetup("BotLibShutdown")) return BLERR_LIBRARYNOTSETUP;
-#ifndef DEMO
- //DumpFileCRCs();
-#endif //DEMO
- //
- BotShutdownChatAI(); //be_ai_chat.c
- BotShutdownMoveAI(); //be_ai_move.c
- BotShutdownGoalAI(); //be_ai_goal.c
- BotShutdownWeaponAI(); //be_ai_weap.c
- BotShutdownWeights(); //be_ai_weight.c
- BotShutdownCharacters(); //be_ai_char.c
- //shud down aas
- AAS_Shutdown();
- //shut down bot elemantary actions
- EA_Shutdown();
- //free all libvars
- LibVarDeAllocAll();
- //remove all global defines from the pre compiler
- PC_RemoveAllGlobalDefines();
-
- //dump all allocated memory
-// DumpMemory();
-#ifdef DEBUG
- PrintMemoryLabels();
-#endif
- //shut down library log file
- Log_Shutdown();
- //
- botlibsetup = qfalse;
- botlibglobals.botlibsetup = qfalse;
- // print any files still open
- PC_CheckOpenSourceHandles();
- //
- return BLERR_NOERROR;
-} //end of the function Export_BotLibShutdown
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Export_BotLibVarSet(char *var_name, char *value)
-{
- LibVarSet(var_name, value);
- return BLERR_NOERROR;
-} //end of the function Export_BotLibVarSet
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Export_BotLibVarGet(char *var_name, char *value, int size)
-{
- char *varvalue;
-
- varvalue = LibVarGetString(var_name);
- strncpy(value, varvalue, size-1);
- value[size-1] = '\0';
- return BLERR_NOERROR;
-} //end of the function Export_BotLibVarGet
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Export_BotLibStartFrame(float time)
-{
- if (!BotLibSetup("BotStartFrame")) return BLERR_LIBRARYNOTSETUP;
- return AAS_StartFrame(time);
-} //end of the function Export_BotLibStartFrame
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Export_BotLibLoadMap(const char *mapname)
-{
-#ifdef DEBUG
- int starttime = Sys_MilliSeconds();
-#endif
- int errnum;
-
- if (!BotLibSetup("BotLoadMap")) return BLERR_LIBRARYNOTSETUP;
- //
- botimport.Print(PRT_MESSAGE, "------------ Map Loading ------------\n");
- //startup AAS for the current map, model and sound index
- errnum = AAS_LoadMap(mapname);
- if (errnum != BLERR_NOERROR) return errnum;
- //initialize the items in the level
- BotInitLevelItems(); //be_ai_goal.h
- BotSetBrushModelTypes(); //be_ai_move.h
- //
- botimport.Print(PRT_MESSAGE, "-------------------------------------\n");
-#ifdef DEBUG
- botimport.Print(PRT_MESSAGE, "map loaded in %d msec\n", Sys_MilliSeconds() - starttime);
-#endif
- //
- return BLERR_NOERROR;
-} //end of the function Export_BotLibLoadMap
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Export_BotLibUpdateEntity(int ent, bot_entitystate_t *state)
-{
- if (!BotLibSetup("BotUpdateEntity")) return BLERR_LIBRARYNOTSETUP;
- if (!ValidEntityNumber(ent, "BotUpdateEntity")) return BLERR_INVALIDENTITYNUMBER;
-
- return AAS_UpdateEntity(ent, state);
-} //end of the function Export_BotLibUpdateEntity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void AAS_TestMovementPrediction(int entnum, vec3_t origin, vec3_t dir);
-void ElevatorBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter);
-int BotGetReachabilityToGoal(vec3_t origin, int areanum,
- int lastgoalareanum, int lastareanum,
- int *avoidreach, float *avoidreachtimes, int *avoidreachtries,
- bot_goal_t *goal, int travelflags, int movetravelflags,
- struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags);
-
-int AAS_PointLight(vec3_t origin, int *red, int *green, int *blue);
-
-int AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas);
-
-int AAS_Reachability_WeaponJump(int area1num, int area2num);
-
-int BotFuzzyPointReachabilityArea(vec3_t origin);
-
-float BotGapDistance(vec3_t origin, vec3_t hordir, int entnum);
-
-void AAS_FloodAreas(vec3_t origin);
-
-int BotExportTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3)
-{
-
-// return AAS_PointLight(parm2, NULL, NULL, NULL);
-
-#ifdef DEBUG
- static int area = -1;
- static int line[2];
- int newarea, i, highlightarea, flood;
-// int reachnum;
- vec3_t eye, forward, right, end, origin;
-// vec3_t bottomcenter;
-// aas_trace_t trace;
-// aas_face_t *face;
-// aas_entity_t *ent;
-// bsp_trace_t bsptrace;
-// aas_reachability_t reach;
-// bot_goal_t goal;
-
- // clock_t start_time, end_time;
- vec3_t mins = {-16, -16, -24};
- vec3_t maxs = {16, 16, 32};
-
-// int areas[10], numareas;
-
-
- //return 0;
-
- if (!aasworld.loaded) return 0;
-
- /*
- if (parm0 & 1)
- {
- AAS_ClearShownPolygons();
- AAS_FloodAreas(parm2);
- } //end if
- return 0;
- */
- for (i = 0; i < 2; i++) if (!line[i]) line[i] = botimport.DebugLineCreate();
-
-// AAS_ClearShownDebugLines();
-
- //if (AAS_AgainstLadder(parm2)) botimport.Print(PRT_MESSAGE, "against ladder\n");
- //BotOnGround(parm2, PRESENCE_NORMAL, 1, &newarea, &newarea);
- //botimport.Print(PRT_MESSAGE, "%f %f %f\n", parm2[0], parm2[1], parm2[2]);
- //*
- highlightarea = LibVarGetValue("bot_highlightarea");
- if (highlightarea > 0)
- {
- newarea = highlightarea;
- } //end if
- else
- {
- VectorCopy(parm2, origin);
- origin[2] += 0.5;
- //newarea = AAS_PointAreaNum(origin);
- newarea = BotFuzzyPointReachabilityArea(origin);
- } //end else
-
- botimport.Print(PRT_MESSAGE, "\rtravel time to goal (%d) = %d ", botlibglobals.goalareanum,
- AAS_AreaTravelTimeToGoalArea(newarea, origin, botlibglobals.goalareanum, TFL_DEFAULT));
- //newarea = BotReachabilityArea(origin, qtrue);
- if (newarea != area)
- {
- botimport.Print(PRT_MESSAGE, "origin = %f, %f, %f\n", origin[0], origin[1], origin[2]);
- area = newarea;
- botimport.Print(PRT_MESSAGE, "new area %d, cluster %d, presence type %d\n",
- area, AAS_AreaCluster(area), AAS_PointPresenceType(origin));
- botimport.Print(PRT_MESSAGE, "area contents: ");
- if (aasworld.areasettings[area].contents & AREACONTENTS_WATER)
- {
- botimport.Print(PRT_MESSAGE, "water &");
- } //end if
- if (aasworld.areasettings[area].contents & AREACONTENTS_LAVA)
- {
- botimport.Print(PRT_MESSAGE, "lava &");
- } //end if
- if (aasworld.areasettings[area].contents & AREACONTENTS_SLIME)
- {
- botimport.Print(PRT_MESSAGE, "slime &");
- } //end if
- if (aasworld.areasettings[area].contents & AREACONTENTS_JUMPPAD)
- {
- botimport.Print(PRT_MESSAGE, "jump pad &");
- } //end if
- if (aasworld.areasettings[area].contents & AREACONTENTS_CLUSTERPORTAL)
- {
- botimport.Print(PRT_MESSAGE, "cluster portal &");
- } //end if
- if (aasworld.areasettings[area].contents & AREACONTENTS_VIEWPORTAL)
- {
- botimport.Print(PRT_MESSAGE, "view portal &");
- } //end if
- if (aasworld.areasettings[area].contents & AREACONTENTS_DONOTENTER)
- {
- botimport.Print(PRT_MESSAGE, "do not enter &");
- } //end if
- if (aasworld.areasettings[area].contents & AREACONTENTS_MOVER)
- {
- botimport.Print(PRT_MESSAGE, "mover &");
- } //end if
- if (!aasworld.areasettings[area].contents)
- {
- botimport.Print(PRT_MESSAGE, "empty");
- } //end if
- botimport.Print(PRT_MESSAGE, "\n");
- botimport.Print(PRT_MESSAGE, "travel time to goal (%d) = %d\n", botlibglobals.goalareanum,
- AAS_AreaTravelTimeToGoalArea(newarea, origin, botlibglobals.goalareanum, TFL_DEFAULT|TFL_ROCKETJUMP));
- /*
- VectorCopy(origin, end);
- end[2] += 5;
- numareas = AAS_TraceAreas(origin, end, areas, NULL, 10);
- AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1);
- botimport.Print(PRT_MESSAGE, "num areas = %d, area = %d\n", numareas, areas[0]);
- */
- /*
- botlibglobals.goalareanum = newarea;
- VectorCopy(parm2, botlibglobals.goalorigin);
- botimport.Print(PRT_MESSAGE, "new goal %2.1f %2.1f %2.1f area %d\n",
- origin[0], origin[1], origin[2], newarea);
- */
- } //end if
- //*
- flood = LibVarGetValue("bot_flood");
- if (parm0 & 1)
- {
- if (flood)
- {
- AAS_ClearShownPolygons();
- AAS_ClearShownDebugLines();
- AAS_FloodAreas(parm2);
- }
- else
- {
- botlibglobals.goalareanum = newarea;
- VectorCopy(parm2, botlibglobals.goalorigin);
- botimport.Print(PRT_MESSAGE, "new goal %2.1f %2.1f %2.1f area %d\n",
- origin[0], origin[1], origin[2], newarea);
- }
- } //end if*/
- if (flood)
- return 0;
-// if (parm0 & BUTTON_USE)
-// {
-// botlibglobals.runai = !botlibglobals.runai;
-// if (botlibglobals.runai) botimport.Print(PRT_MESSAGE, "started AI\n");
-// else botimport.Print(PRT_MESSAGE, "stopped AI\n");
- //* /
- /*
- goal.areanum = botlibglobals.goalareanum;
- reachnum = BotGetReachabilityToGoal(parm2, newarea, 1,
- ms.avoidreach, ms.avoidreachtimes,
- &goal, TFL_DEFAULT);
- if (!reachnum)
- {
- botimport.Print(PRT_MESSAGE, "goal not reachable\n");
- } //end if
- else
- {
- AAS_ReachabilityFromNum(reachnum, &reach);
- AAS_ClearShownDebugLines();
- AAS_ShowArea(area, qtrue);
- AAS_ShowArea(reach.areanum, qtrue);
- AAS_DrawCross(reach.start, 6, LINECOLOR_BLUE);
- AAS_DrawCross(reach.end, 6, LINECOLOR_RED);
- //
- if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR)
- {
- ElevatorBottomCenter(&reach, bottomcenter);
- AAS_DrawCross(bottomcenter, 10, LINECOLOR_GREEN);
- } //end if
- } //end else*/
-// botimport.Print(PRT_MESSAGE, "travel time to goal = %d\n",
-// AAS_AreaTravelTimeToGoalArea(area, origin, botlibglobals.goalareanum, TFL_DEFAULT));
-// botimport.Print(PRT_MESSAGE, "test rj from 703 to 716\n");
-// AAS_Reachability_WeaponJump(703, 716);
-// } //end if*/
-
-/* face = AAS_AreaGroundFace(newarea, parm2);
- if (face)
- {
- AAS_ShowFace(face - aasworld.faces);
- } //end if*/
- /*
- AAS_ClearShownDebugLines();
- AAS_ShowArea(newarea, parm0 & BUTTON_USE);
- AAS_ShowReachableAreas(area);
- */
- AAS_ClearShownPolygons();
- AAS_ClearShownDebugLines();
- AAS_ShowAreaPolygons(newarea, 1, parm0 & 4);
- if (parm0 & 2) AAS_ShowReachableAreas(area);
- else
- {
- static int lastgoalareanum, lastareanum;
- static int avoidreach[MAX_AVOIDREACH];
- static float avoidreachtimes[MAX_AVOIDREACH];
- static int avoidreachtries[MAX_AVOIDREACH];
- int reachnum, resultFlags;
- bot_goal_t goal;
- aas_reachability_t reach;
-
- /*
- goal.areanum = botlibglobals.goalareanum;
- VectorCopy(botlibglobals.goalorigin, goal.origin);
- reachnum = BotGetReachabilityToGoal(origin, newarea,
- lastgoalareanum, lastareanum,
- avoidreach, avoidreachtimes, avoidreachtries,
- &goal, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP,
- NULL, 0, &resultFlags);
- AAS_ReachabilityFromNum(reachnum, &reach);
- AAS_ShowReachability(&reach);
- */
- int curarea;
- vec3_t curorigin;
-
- goal.areanum = botlibglobals.goalareanum;
- VectorCopy(botlibglobals.goalorigin, goal.origin);
- VectorCopy(origin, curorigin);
- curarea = newarea;
- for ( i = 0; i < 100; i++ ) {
- if ( curarea == goal.areanum ) {
- break;
- }
- reachnum = BotGetReachabilityToGoal(curorigin, curarea,
- lastgoalareanum, lastareanum,
- avoidreach, avoidreachtimes, avoidreachtries,
- &goal, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP,
- NULL, 0, &resultFlags);
- AAS_ReachabilityFromNum(reachnum, &reach);
- AAS_ShowReachability(&reach);
- VectorCopy(reach.end, origin);
- lastareanum = curarea;
- curarea = reach.areanum;
- }
- } //end else
- VectorClear(forward);
- //BotGapDistance(origin, forward, 0);
- /*
- if (parm0 & BUTTON_USE)
- {
- botimport.Print(PRT_MESSAGE, "test rj from 703 to 716\n");
- AAS_Reachability_WeaponJump(703, 716);
- } //end if*/
-
- AngleVectors(parm3, forward, right, NULL);
- //get the eye 16 units to the right of the origin
- VectorMA(parm2, 8, right, eye);
- //get the eye 24 units up
- eye[2] += 24;
- //get the end point for the line to be traced
- VectorMA(eye, 800, forward, end);
-
-// AAS_TestMovementPrediction(1, parm2, forward);
-/*
- //trace the line to find the hit point
- trace = AAS_TraceClientBBox(eye, end, PRESENCE_NORMAL, 1);
- if (!line[0]) line[0] = botimport.DebugLineCreate();
- botimport.DebugLineShow(line[0], eye, trace.endpos, LINECOLOR_BLUE);
- //
- AAS_ClearShownDebugLines();
- if (trace.ent)
- {
- ent = &aasworld.entities[trace.ent];
- AAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs);
- } //end if
-*/
-
-/*
- start_time = clock();
- for (i = 0; i < 2000; i++)
- {
- AAS_Trace2(eye, mins, maxs, end, 1, MASK_PLAYERSOLID);
-// AAS_TraceClientBBox(eye, end, PRESENCE_NORMAL, 1);
- } //end for
- end_time = clock();
- botimport.Print(PRT_MESSAGE, "me %lu clocks, %lu CLOCKS_PER_SEC\n", end_time - start_time, CLOCKS_PER_SEC);
- start_time = clock();
- for (i = 0; i < 2000; i++)
- {
- AAS_Trace(eye, mins, maxs, end, 1, MASK_PLAYERSOLID);
- } //end for
- end_time = clock();
- botimport.Print(PRT_MESSAGE, "id %lu clocks, %lu CLOCKS_PER_SEC\n", end_time - start_time, CLOCKS_PER_SEC);
-*/
-
- // TTimo: nested comments are BAD for gcc -Werror, use #if 0 instead..
-#if 0
- AAS_ClearShownDebugLines();
- //bsptrace = AAS_Trace(eye, NULL, NULL, end, 1, MASK_PLAYERSOLID);
- bsptrace = AAS_Trace(eye, mins, maxs, end, 1, MASK_PLAYERSOLID);
- if (!line[0]) line[0] = botimport.DebugLineCreate();
- botimport.DebugLineShow(line[0], eye, bsptrace.endpos, LINECOLOR_YELLOW);
- if (bsptrace.fraction < 1.0)
- {
- face = AAS_TraceEndFace(&trace);
- if (face)
- {
- AAS_ShowFace(face - aasworld.faces);
- } //end if
-
- AAS_DrawPlaneCross(bsptrace.endpos,
- bsptrace.plane.normal,
- bsptrace.plane.dist + bsptrace.exp_dist,
- bsptrace.plane.type, LINECOLOR_GREEN);
- if (trace.ent)
- {
- ent = &aasworld.entities[trace.ent];
- AAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs);
- } //end if
- } //end if
- //bsptrace = AAS_Trace2(eye, NULL, NULL, end, 1, MASK_PLAYERSOLID);
- bsptrace = AAS_Trace2(eye, mins, maxs, end, 1, MASK_PLAYERSOLID);
- botimport.DebugLineShow(line[1], eye, bsptrace.endpos, LINECOLOR_BLUE);
- if (bsptrace.fraction < 1.0)
- {
- AAS_DrawPlaneCross(bsptrace.endpos,
- bsptrace.plane.normal,
- bsptrace.plane.dist,// + bsptrace.exp_dist,
- bsptrace.plane.type, LINECOLOR_RED);
- if (bsptrace.ent)
- {
- ent = &aasworld.entities[bsptrace.ent];
- AAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs);
- } //end if
- } //end if
-#endif
-#endif
- return 0;
-} //end of the function BotExportTest
-
-
-/*
-============
-Init_AAS_Export
-============
-*/
-static void Init_AAS_Export( aas_export_t *aas ) {
- //--------------------------------------------
- // be_aas_entity.c
- //--------------------------------------------
- aas->AAS_EntityInfo = AAS_EntityInfo;
- //--------------------------------------------
- // be_aas_main.c
- //--------------------------------------------
- aas->AAS_Initialized = AAS_Initialized;
- aas->AAS_PresenceTypeBoundingBox = AAS_PresenceTypeBoundingBox;
- aas->AAS_Time = AAS_Time;
- //--------------------------------------------
- // be_aas_sample.c
- //--------------------------------------------
- aas->AAS_PointAreaNum = AAS_PointAreaNum;
- aas->AAS_PointReachabilityAreaIndex = AAS_PointReachabilityAreaIndex;
- aas->AAS_TraceAreas = AAS_TraceAreas;
- aas->AAS_BBoxAreas = AAS_BBoxAreas;
- aas->AAS_AreaInfo = AAS_AreaInfo;
- //--------------------------------------------
- // be_aas_bspq3.c
- //--------------------------------------------
- aas->AAS_PointContents = AAS_PointContents;
- aas->AAS_NextBSPEntity = AAS_NextBSPEntity;
- aas->AAS_ValueForBSPEpairKey = AAS_ValueForBSPEpairKey;
- aas->AAS_VectorForBSPEpairKey = AAS_VectorForBSPEpairKey;
- aas->AAS_FloatForBSPEpairKey = AAS_FloatForBSPEpairKey;
- aas->AAS_IntForBSPEpairKey = AAS_IntForBSPEpairKey;
- //--------------------------------------------
- // be_aas_reach.c
- //--------------------------------------------
- aas->AAS_AreaReachability = AAS_AreaReachability;
- //--------------------------------------------
- // be_aas_route.c
- //--------------------------------------------
- aas->AAS_AreaTravelTimeToGoalArea = AAS_AreaTravelTimeToGoalArea;
- aas->AAS_EnableRoutingArea = AAS_EnableRoutingArea;
- aas->AAS_PredictRoute = AAS_PredictRoute;
- //--------------------------------------------
- // be_aas_altroute.c
- //--------------------------------------------
- aas->AAS_AlternativeRouteGoals = AAS_AlternativeRouteGoals;
- //--------------------------------------------
- // be_aas_move.c
- //--------------------------------------------
- aas->AAS_Swimming = AAS_Swimming;
- aas->AAS_PredictClientMovement = AAS_PredictClientMovement;
-}
-
-
-/*
-============
-Init_EA_Export
-============
-*/
-static void Init_EA_Export( ea_export_t *ea ) {
- //ClientCommand elementary actions
- ea->EA_Command = EA_Command;
- ea->EA_Say = EA_Say;
- ea->EA_SayTeam = EA_SayTeam;
-
- ea->EA_Action = EA_Action;
- ea->EA_Gesture = EA_Gesture;
- ea->EA_Talk = EA_Talk;
- ea->EA_Attack = EA_Attack;
- ea->EA_Use = EA_Use;
- ea->EA_Respawn = EA_Respawn;
- ea->EA_Crouch = EA_Crouch;
- ea->EA_MoveUp = EA_MoveUp;
- ea->EA_MoveDown = EA_MoveDown;
- ea->EA_MoveForward = EA_MoveForward;
- ea->EA_MoveBack = EA_MoveBack;
- ea->EA_MoveLeft = EA_MoveLeft;
- ea->EA_MoveRight = EA_MoveRight;
-
- ea->EA_SelectWeapon = EA_SelectWeapon;
- ea->EA_Jump = EA_Jump;
- ea->EA_DelayedJump = EA_DelayedJump;
- ea->EA_Move = EA_Move;
- ea->EA_View = EA_View;
- ea->EA_GetInput = EA_GetInput;
- ea->EA_EndRegular = EA_EndRegular;
- ea->EA_ResetInput = EA_ResetInput;
-}
-
-
-/*
-============
-Init_AI_Export
-============
-*/
-static void Init_AI_Export( ai_export_t *ai ) {
- //-----------------------------------
- // be_ai_char.h
- //-----------------------------------
- ai->BotLoadCharacter = BotLoadCharacter;
- ai->BotFreeCharacter = BotFreeCharacter;
- ai->Characteristic_Float = Characteristic_Float;
- ai->Characteristic_BFloat = Characteristic_BFloat;
- ai->Characteristic_Integer = Characteristic_Integer;
- ai->Characteristic_BInteger = Characteristic_BInteger;
- ai->Characteristic_String = Characteristic_String;
- //-----------------------------------
- // be_ai_chat.h
- //-----------------------------------
- ai->BotAllocChatState = BotAllocChatState;
- ai->BotFreeChatState = BotFreeChatState;
- ai->BotQueueConsoleMessage = BotQueueConsoleMessage;
- ai->BotRemoveConsoleMessage = BotRemoveConsoleMessage;
- ai->BotNextConsoleMessage = BotNextConsoleMessage;
- ai->BotNumConsoleMessages = BotNumConsoleMessages;
- ai->BotInitialChat = BotInitialChat;
- ai->BotNumInitialChats = BotNumInitialChats;
- ai->BotReplyChat = BotReplyChat;
- ai->BotChatLength = BotChatLength;
- ai->BotEnterChat = BotEnterChat;
- ai->BotGetChatMessage = BotGetChatMessage;
- ai->StringContains = StringContains;
- ai->BotFindMatch = BotFindMatch;
- ai->BotMatchVariable = BotMatchVariable;
- ai->UnifyWhiteSpaces = UnifyWhiteSpaces;
- ai->BotReplaceSynonyms = BotReplaceSynonyms;
- ai->BotLoadChatFile = BotLoadChatFile;
- ai->BotSetChatGender = BotSetChatGender;
- ai->BotSetChatName = BotSetChatName;
- //-----------------------------------
- // be_ai_goal.h
- //-----------------------------------
- ai->BotResetGoalState = BotResetGoalState;
- ai->BotResetAvoidGoals = BotResetAvoidGoals;
- ai->BotRemoveFromAvoidGoals = BotRemoveFromAvoidGoals;
- ai->BotPushGoal = BotPushGoal;
- ai->BotPopGoal = BotPopGoal;
- ai->BotEmptyGoalStack = BotEmptyGoalStack;
- ai->BotDumpAvoidGoals = BotDumpAvoidGoals;
- ai->BotDumpGoalStack = BotDumpGoalStack;
- ai->BotGoalName = BotGoalName;
- ai->BotGetTopGoal = BotGetTopGoal;
- ai->BotGetSecondGoal = BotGetSecondGoal;
- ai->BotChooseLTGItem = BotChooseLTGItem;
- ai->BotChooseNBGItem = BotChooseNBGItem;
- ai->BotTouchingGoal = BotTouchingGoal;
- ai->BotItemGoalInVisButNotVisible = BotItemGoalInVisButNotVisible;
- ai->BotGetLevelItemGoal = BotGetLevelItemGoal;
- ai->BotGetNextCampSpotGoal = BotGetNextCampSpotGoal;
- ai->BotGetMapLocationGoal = BotGetMapLocationGoal;
- ai->BotAvoidGoalTime = BotAvoidGoalTime;
- ai->BotSetAvoidGoalTime = BotSetAvoidGoalTime;
- ai->BotInitLevelItems = BotInitLevelItems;
- ai->BotUpdateEntityItems = BotUpdateEntityItems;
- ai->BotLoadItemWeights = BotLoadItemWeights;
- ai->BotFreeItemWeights = BotFreeItemWeights;
- ai->BotInterbreedGoalFuzzyLogic = BotInterbreedGoalFuzzyLogic;
- ai->BotSaveGoalFuzzyLogic = BotSaveGoalFuzzyLogic;
- ai->BotMutateGoalFuzzyLogic = BotMutateGoalFuzzyLogic;
- ai->BotAllocGoalState = BotAllocGoalState;
- ai->BotFreeGoalState = BotFreeGoalState;
- //-----------------------------------
- // be_ai_move.h
- //-----------------------------------
- ai->BotResetMoveState = BotResetMoveState;
- ai->BotMoveToGoal = BotMoveToGoal;
- ai->BotMoveInDirection = BotMoveInDirection;
- ai->BotResetAvoidReach = BotResetAvoidReach;
- ai->BotResetLastAvoidReach = BotResetLastAvoidReach;
- ai->BotReachabilityArea = BotReachabilityArea;
- ai->BotMovementViewTarget = BotMovementViewTarget;
- ai->BotPredictVisiblePosition = BotPredictVisiblePosition;
- ai->BotAllocMoveState = BotAllocMoveState;
- ai->BotFreeMoveState = BotFreeMoveState;
- ai->BotInitMoveState = BotInitMoveState;
- ai->BotAddAvoidSpot = BotAddAvoidSpot;
- //-----------------------------------
- // be_ai_weap.h
- //-----------------------------------
- ai->BotChooseBestFightWeapon = BotChooseBestFightWeapon;
- ai->BotGetWeaponInfo = BotGetWeaponInfo;
- ai->BotLoadWeaponWeights = BotLoadWeaponWeights;
- ai->BotAllocWeaponState = BotAllocWeaponState;
- ai->BotFreeWeaponState = BotFreeWeaponState;
- ai->BotResetWeaponState = BotResetWeaponState;
- //-----------------------------------
- // be_ai_gen.h
- //-----------------------------------
- ai->GeneticParentsAndChildSelection = GeneticParentsAndChildSelection;
-}
-
-
-/*
-============
-GetBotLibAPI
-============
-*/
-botlib_export_t *GetBotLibAPI(int apiVersion, botlib_import_t *import) {
- assert(import);
- botimport = *import;
- assert(botimport.Print);
-
- Com_Memset( &be_botlib_export, 0, sizeof( be_botlib_export ) );
-
- if ( apiVersion != BOTLIB_API_VERSION ) {
- botimport.Print( PRT_ERROR, "Mismatched BOTLIB_API_VERSION: expected %i, got %i\n", BOTLIB_API_VERSION, apiVersion );
- return NULL;
- }
-
- Init_AAS_Export(&be_botlib_export.aas);
- Init_EA_Export(&be_botlib_export.ea);
- Init_AI_Export(&be_botlib_export.ai);
-
- be_botlib_export.BotLibSetup = Export_BotLibSetup;
- be_botlib_export.BotLibShutdown = Export_BotLibShutdown;
- be_botlib_export.BotLibVarSet = Export_BotLibVarSet;
- be_botlib_export.BotLibVarGet = Export_BotLibVarGet;
-
- be_botlib_export.PC_AddGlobalDefine = PC_AddGlobalDefine;
- be_botlib_export.PC_LoadSourceHandle = PC_LoadSourceHandle;
- be_botlib_export.PC_FreeSourceHandle = PC_FreeSourceHandle;
- be_botlib_export.PC_ReadTokenHandle = PC_ReadTokenHandle;
- be_botlib_export.PC_SourceFileAndLine = PC_SourceFileAndLine;
-
- be_botlib_export.BotLibStartFrame = Export_BotLibStartFrame;
- be_botlib_export.BotLibLoadMap = Export_BotLibLoadMap;
- be_botlib_export.BotLibUpdateEntity = Export_BotLibUpdateEntity;
- be_botlib_export.Test = BotExportTest;
-
- return &be_botlib_export;
-}
diff --git a/engine/code/botlib/be_interface.h b/engine/code/botlib/be_interface.h
deleted file mode 100644
index c3cdf08..0000000
--- a/engine/code/botlib/be_interface.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_interface.h
- *
- * desc: botlib interface
- *
- * $Archive: /source/code/botlib/be_interface.h $
- *
- *****************************************************************************/
-
-//#define DEBUG //debug code
-#define RANDOMIZE //randomize bot behaviour
-
-//FIXME: get rid of this global structure
-typedef struct botlib_globals_s
-{
- int botlibsetup; //true when the bot library has been setup
- int maxentities; //maximum number of entities
- int maxclients; //maximum number of clients
- float time; //the global time
-#ifdef DEBUG
- qboolean debug; //true if debug is on
- int goalareanum;
- vec3_t goalorigin;
- int runai;
-#endif
-} botlib_globals_t;
-
-
-extern botlib_globals_t botlibglobals;
-extern botlib_import_t botimport;
-extern int botDeveloper; //true if developer is on
-
-//
-int Sys_MilliSeconds(void);
-
diff --git a/engine/code/botlib/botlib.h b/engine/code/botlib/botlib.h
deleted file mode 100644
index 5fb1855..0000000
--- a/engine/code/botlib/botlib.h
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*****************************************************************************
- * name: botlib.h
- *
- * desc: bot AI library
- *
- * $Archive: /source/code/game/botai.h $
- *
- *****************************************************************************/
-
-#define BOTLIB_API_VERSION 2
-
-struct aas_clientmove_s;
-struct aas_entityinfo_s;
-struct aas_areainfo_s;
-struct aas_altroutegoal_s;
-struct aas_predictroute_s;
-struct bot_consolemessage_s;
-struct bot_match_s;
-struct bot_goal_s;
-struct bot_moveresult_s;
-struct bot_initmove_s;
-struct weaponinfo_s;
-
-#define BOTFILESBASEFOLDER "botfiles"
-//debug line colors
-#define LINECOLOR_NONE -1
-#define LINECOLOR_RED 1//0xf2f2f0f0L
-#define LINECOLOR_GREEN 2//0xd0d1d2d3L
-#define LINECOLOR_BLUE 3//0xf3f3f1f1L
-#define LINECOLOR_YELLOW 4//0xdcdddedfL
-#define LINECOLOR_ORANGE 5//0xe0e1e2e3L
-
-//Print types
-#define PRT_MESSAGE 1
-#define PRT_WARNING 2
-#define PRT_ERROR 3
-#define PRT_FATAL 4
-#define PRT_EXIT 5
-
-//console message types
-#define CMS_NORMAL 0
-#define CMS_CHAT 1
-
-//botlib error codes
-#define BLERR_NOERROR 0 //no error
-#define BLERR_LIBRARYNOTSETUP 1 //library not setup
-#define BLERR_INVALIDENTITYNUMBER 2 //invalid entity number
-#define BLERR_NOAASFILE 3 //no AAS file available
-#define BLERR_CANNOTOPENAASFILE 4 //cannot open AAS file
-#define BLERR_WRONGAASFILEID 5 //incorrect AAS file id
-#define BLERR_WRONGAASFILEVERSION 6 //incorrect AAS file version
-#define BLERR_CANNOTREADAASLUMP 7 //cannot read AAS file lump
-#define BLERR_CANNOTLOADICHAT 8 //cannot load initial chats
-#define BLERR_CANNOTLOADITEMWEIGHTS 9 //cannot load item weights
-#define BLERR_CANNOTLOADITEMCONFIG 10 //cannot load item config
-#define BLERR_CANNOTLOADWEAPONWEIGHTS 11 //cannot load weapon weights
-#define BLERR_CANNOTLOADWEAPONCONFIG 12 //cannot load weapon config
-
-//action flags
-#define ACTION_ATTACK 0x0000001
-#define ACTION_USE 0x0000002
-#define ACTION_RESPAWN 0x0000008
-#define ACTION_JUMP 0x0000010
-#define ACTION_MOVEUP 0x0000020
-#define ACTION_CROUCH 0x0000080
-#define ACTION_MOVEDOWN 0x0000100
-#define ACTION_MOVEFORWARD 0x0000200
-#define ACTION_MOVEBACK 0x0000800
-#define ACTION_MOVELEFT 0x0001000
-#define ACTION_MOVERIGHT 0x0002000
-#define ACTION_DELAYEDJUMP 0x0008000
-#define ACTION_TALK 0x0010000
-#define ACTION_GESTURE 0x0020000
-#define ACTION_WALK 0x0080000
-#define ACTION_AFFIRMATIVE 0x0100000
-#define ACTION_NEGATIVE 0x0200000
-#define ACTION_GETFLAG 0x0800000
-#define ACTION_GUARDBASE 0x1000000
-#define ACTION_PATROL 0x2000000
-#define ACTION_FOLLOWME 0x8000000
-
-//the bot input, will be converted to an usercmd_t
-typedef struct bot_input_s
-{
- float thinktime; //time since last output (in seconds)
- vec3_t dir; //movement direction
- float speed; //speed in the range [0, 400]
- vec3_t viewangles; //the view angles
- int actionflags; //one of the ACTION_? flags
- int weapon; //weapon to use
-} bot_input_t;
-
-#ifndef BSPTRACE
-
-#define BSPTRACE
-
-//bsp_trace_t hit surface
-typedef struct bsp_surface_s
-{
- char name[16];
- int flags;
- int value;
-} bsp_surface_t;
-
-//remove the bsp_trace_s structure definition l8r on
-//a trace is returned when a box is swept through the world
-typedef struct bsp_trace_s
-{
- qboolean allsolid; // if true, plane is not valid
- qboolean startsolid; // if true, the initial point was in a solid area
- float fraction; // time completed, 1.0 = didn't hit anything
- vec3_t endpos; // final position
- cplane_t plane; // surface normal at impact
- float exp_dist; // expanded plane distance
- int sidenum; // number of the brush side hit
- bsp_surface_t surface; // the hit point surface
- int contents; // contents on other side of surface hit
- int ent; // number of entity hit
-} bsp_trace_t;
-
-#endif // BSPTRACE
-
-//entity state
-typedef struct bot_entitystate_s
-{
- int type; // entity type
- int flags; // entity flags
- vec3_t origin; // origin of the entity
- vec3_t angles; // angles of the model
- vec3_t old_origin; // for lerping
- vec3_t mins; // bounding box minimums
- vec3_t maxs; // bounding box maximums
- int groundent; // ground entity
- int solid; // solid type
- int modelindex; // model used
- int modelindex2; // weapons, CTF flags, etc
- int frame; // model frame number
- int event; // impulse events -- muzzle flashes, footsteps, etc
- int eventParm; // even parameter
- int powerups; // bit flags
- int weapon; // determines weapon and flash model, etc
- int legsAnim; // mask off ANIM_TOGGLEBIT
- int torsoAnim; // mask off ANIM_TOGGLEBIT
-} bot_entitystate_t;
-
-//bot AI library exported functions
-typedef struct botlib_import_s
-{
- //print messages from the bot library
- void (QDECL *Print)(int type, char *fmt, ...);
- //trace a bbox through the world
- void (*Trace)(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask);
- //trace a bbox against a specific entity
- void (*EntityTrace)(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask);
- //retrieve the contents at the given point
- int (*PointContents)(vec3_t point);
- //check if the point is in potential visible sight
- int (*inPVS)(vec3_t p1, vec3_t p2);
- //retrieve the BSP entity data lump
- char *(*BSPEntityData)(void);
- //
- void (*BSPModelMinsMaxsOrigin)(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin);
- //send a bot client command
- void (*BotClientCommand)(int client, char *command);
- //memory allocation
- void *(*GetMemory)(int size); // allocate from Zone
- void (*FreeMemory)(void *ptr); // free memory from Zone
- int (*AvailableMemory)(void); // available Zone memory
- void *(*HunkAlloc)(int size); // allocate from hunk
- //file system access
- int (*FS_FOpenFile)( const char *qpath, fileHandle_t *file, fsMode_t mode );
- int (*FS_Read)( void *buffer, int len, fileHandle_t f );
- int (*FS_Write)( const void *buffer, int len, fileHandle_t f );
- void (*FS_FCloseFile)( fileHandle_t f );
- int (*FS_Seek)( fileHandle_t f, long offset, int origin );
- //debug visualisation stuff
- int (*DebugLineCreate)(void);
- void (*DebugLineDelete)(int line);
- void (*DebugLineShow)(int line, vec3_t start, vec3_t end, int color);
- //
- int (*DebugPolygonCreate)(int color, int numPoints, vec3_t *points);
- void (*DebugPolygonDelete)(int id);
-} botlib_import_t;
-
-typedef struct aas_export_s
-{
- //-----------------------------------
- // be_aas_entity.h
- //-----------------------------------
- void (*AAS_EntityInfo)(int entnum, struct aas_entityinfo_s *info);
- //-----------------------------------
- // be_aas_main.h
- //-----------------------------------
- int (*AAS_Initialized)(void);
- void (*AAS_PresenceTypeBoundingBox)(int presencetype, vec3_t mins, vec3_t maxs);
- float (*AAS_Time)(void);
- //--------------------------------------------
- // be_aas_sample.c
- //--------------------------------------------
- int (*AAS_PointAreaNum)(vec3_t point);
- int (*AAS_PointReachabilityAreaIndex)( vec3_t point );
- int (*AAS_TraceAreas)(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas);
- int (*AAS_BBoxAreas)(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas);
- int (*AAS_AreaInfo)( int areanum, struct aas_areainfo_s *info );
- //--------------------------------------------
- // be_aas_bspq3.c
- //--------------------------------------------
- int (*AAS_PointContents)(vec3_t point);
- int (*AAS_NextBSPEntity)(int ent);
- int (*AAS_ValueForBSPEpairKey)(int ent, char *key, char *value, int size);
- int (*AAS_VectorForBSPEpairKey)(int ent, char *key, vec3_t v);
- int (*AAS_FloatForBSPEpairKey)(int ent, char *key, float *value);
- int (*AAS_IntForBSPEpairKey)(int ent, char *key, int *value);
- //--------------------------------------------
- // be_aas_reach.c
- //--------------------------------------------
- int (*AAS_AreaReachability)(int areanum);
- //--------------------------------------------
- // be_aas_route.c
- //--------------------------------------------
- int (*AAS_AreaTravelTimeToGoalArea)(int areanum, vec3_t origin, int goalareanum, int travelflags);
- int (*AAS_EnableRoutingArea)(int areanum, int enable);
- int (*AAS_PredictRoute)(struct aas_predictroute_s *route, int areanum, vec3_t origin,
- int goalareanum, int travelflags, int maxareas, int maxtime,
- int stopevent, int stopcontents, int stoptfl, int stopareanum);
- //--------------------------------------------
- // be_aas_altroute.c
- //--------------------------------------------
- int (*AAS_AlternativeRouteGoals)(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,
- struct aas_altroutegoal_s *altroutegoals, int maxaltroutegoals,
- int type);
- //--------------------------------------------
- // be_aas_move.c
- //--------------------------------------------
- int (*AAS_Swimming)(vec3_t origin);
- int (*AAS_PredictClientMovement)(struct aas_clientmove_s *move,
- int entnum, vec3_t origin,
- int presencetype, int onground,
- vec3_t velocity, vec3_t cmdmove,
- int cmdframes,
- int maxframes, float frametime,
- int stopevent, int stopareanum, int visualize);
-} aas_export_t;
-
-typedef struct ea_export_s
-{
- //ClientCommand elementary actions
- void (*EA_Command)(int client, char *command );
- void (*EA_Say)(int client, char *str);
- void (*EA_SayTeam)(int client, char *str);
- //
- void (*EA_Action)(int client, int action);
- void (*EA_Gesture)(int client);
- void (*EA_Talk)(int client);
- void (*EA_Attack)(int client);
- void (*EA_Use)(int client);
- void (*EA_Respawn)(int client);
- void (*EA_MoveUp)(int client);
- void (*EA_MoveDown)(int client);
- void (*EA_MoveForward)(int client);
- void (*EA_MoveBack)(int client);
- void (*EA_MoveLeft)(int client);
- void (*EA_MoveRight)(int client);
- void (*EA_Crouch)(int client);
-
- void (*EA_SelectWeapon)(int client, int weapon);
- void (*EA_Jump)(int client);
- void (*EA_DelayedJump)(int client);
- void (*EA_Move)(int client, vec3_t dir, float speed);
- void (*EA_View)(int client, vec3_t viewangles);
- //send regular input to the server
- void (*EA_EndRegular)(int client, float thinktime);
- void (*EA_GetInput)(int client, float thinktime, bot_input_t *input);
- void (*EA_ResetInput)(int client);
-} ea_export_t;
-
-typedef struct ai_export_s
-{
- //-----------------------------------
- // be_ai_char.h
- //-----------------------------------
- int (*BotLoadCharacter)(char *charfile, float skill);
- void (*BotFreeCharacter)(int character);
- float (*Characteristic_Float)(int character, int index);
- float (*Characteristic_BFloat)(int character, int index, float min, float max);
- int (*Characteristic_Integer)(int character, int index);
- int (*Characteristic_BInteger)(int character, int index, int min, int max);
- void (*Characteristic_String)(int character, int index, char *buf, int size);
- //-----------------------------------
- // be_ai_chat.h
- //-----------------------------------
- int (*BotAllocChatState)(void);
- void (*BotFreeChatState)(int handle);
- void (*BotQueueConsoleMessage)(int chatstate, int type, char *message);
- void (*BotRemoveConsoleMessage)(int chatstate, int handle);
- int (*BotNextConsoleMessage)(int chatstate, struct bot_consolemessage_s *cm);
- int (*BotNumConsoleMessages)(int chatstate);
- void (*BotInitialChat)(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7);
- int (*BotNumInitialChats)(int chatstate, char *type);
- int (*BotReplyChat)(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7);
- int (*BotChatLength)(int chatstate);
- void (*BotEnterChat)(int chatstate, int client, int sendto);
- void (*BotGetChatMessage)(int chatstate, char *buf, int size);
- int (*StringContains)(char *str1, char *str2, int casesensitive);
- int (*BotFindMatch)(char *str, struct bot_match_s *match, unsigned long int context);
- void (*BotMatchVariable)(struct bot_match_s *match, int variable, char *buf, int size);
- void (*UnifyWhiteSpaces)(char *string);
- void (*BotReplaceSynonyms)(char *string, unsigned long int context);
- int (*BotLoadChatFile)(int chatstate, char *chatfile, char *chatname);
- void (*BotSetChatGender)(int chatstate, int gender);
- void (*BotSetChatName)(int chatstate, char *name, int client);
- //-----------------------------------
- // be_ai_goal.h
- //-----------------------------------
- void (*BotResetGoalState)(int goalstate);
- void (*BotResetAvoidGoals)(int goalstate);
- void (*BotRemoveFromAvoidGoals)(int goalstate, int number);
- void (*BotPushGoal)(int goalstate, struct bot_goal_s *goal);
- void (*BotPopGoal)(int goalstate);
- void (*BotEmptyGoalStack)(int goalstate);
- void (*BotDumpAvoidGoals)(int goalstate);
- void (*BotDumpGoalStack)(int goalstate);
- void (*BotGoalName)(int number, char *name, int size);
- int (*BotGetTopGoal)(int goalstate, struct bot_goal_s *goal);
- int (*BotGetSecondGoal)(int goalstate, struct bot_goal_s *goal);
- int (*BotChooseLTGItem)(int goalstate, vec3_t origin, int *inventory, int travelflags);
- int (*BotChooseNBGItem)(int goalstate, vec3_t origin, int *inventory, int travelflags,
- struct bot_goal_s *ltg, float maxtime);
- int (*BotTouchingGoal)(vec3_t origin, struct bot_goal_s *goal);
- int (*BotItemGoalInVisButNotVisible)(int viewer, vec3_t eye, vec3_t viewangles, struct bot_goal_s *goal);
- int (*BotGetLevelItemGoal)(int index, char *classname, struct bot_goal_s *goal);
- int (*BotGetNextCampSpotGoal)(int num, struct bot_goal_s *goal);
- int (*BotGetMapLocationGoal)(char *name, struct bot_goal_s *goal);
- float (*BotAvoidGoalTime)(int goalstate, int number);
- void (*BotSetAvoidGoalTime)(int goalstate, int number, float avoidtime);
- void (*BotInitLevelItems)(void);
- void (*BotUpdateEntityItems)(void);
- int (*BotLoadItemWeights)(int goalstate, char *filename);
- void (*BotFreeItemWeights)(int goalstate);
- void (*BotInterbreedGoalFuzzyLogic)(int parent1, int parent2, int child);
- void (*BotSaveGoalFuzzyLogic)(int goalstate, char *filename);
- void (*BotMutateGoalFuzzyLogic)(int goalstate, float range);
- int (*BotAllocGoalState)(int client);
- void (*BotFreeGoalState)(int handle);
- //-----------------------------------
- // be_ai_move.h
- //-----------------------------------
- void (*BotResetMoveState)(int movestate);
- void (*BotMoveToGoal)(struct bot_moveresult_s *result, int movestate, struct bot_goal_s *goal, int travelflags);
- int (*BotMoveInDirection)(int movestate, vec3_t dir, float speed, int type);
- void (*BotResetAvoidReach)(int movestate);
- void (*BotResetLastAvoidReach)(int movestate);
- int (*BotReachabilityArea)(vec3_t origin, int testground);
- int (*BotMovementViewTarget)(int movestate, struct bot_goal_s *goal, int travelflags, float lookahead, vec3_t target);
- int (*BotPredictVisiblePosition)(vec3_t origin, int areanum, struct bot_goal_s *goal, int travelflags, vec3_t target);
- int (*BotAllocMoveState)(void);
- void (*BotFreeMoveState)(int handle);
- void (*BotInitMoveState)(int handle, struct bot_initmove_s *initmove);
- void (*BotAddAvoidSpot)(int movestate, vec3_t origin, float radius, int type);
- //-----------------------------------
- // be_ai_weap.h
- //-----------------------------------
- int (*BotChooseBestFightWeapon)(int weaponstate, int *inventory);
- void (*BotGetWeaponInfo)(int weaponstate, int weapon, struct weaponinfo_s *weaponinfo);
- int (*BotLoadWeaponWeights)(int weaponstate, char *filename);
- int (*BotAllocWeaponState)(void);
- void (*BotFreeWeaponState)(int weaponstate);
- void (*BotResetWeaponState)(int weaponstate);
- //-----------------------------------
- // be_ai_gen.h
- //-----------------------------------
- int (*GeneticParentsAndChildSelection)(int numranks, float *ranks, int *parent1, int *parent2, int *child);
-} ai_export_t;
-
-//bot AI library imported functions
-typedef struct botlib_export_s
-{
- //Area Awareness System functions
- aas_export_t aas;
- //Elementary Action functions
- ea_export_t ea;
- //AI functions
- ai_export_t ai;
- //setup the bot library, returns BLERR_
- int (*BotLibSetup)(void);
- //shutdown the bot library, returns BLERR_
- int (*BotLibShutdown)(void);
- //sets a library variable returns BLERR_
- int (*BotLibVarSet)(char *var_name, char *value);
- //gets a library variable returns BLERR_
- int (*BotLibVarGet)(char *var_name, char *value, int size);
-
- //sets a C-like define returns BLERR_
- int (*PC_AddGlobalDefine)(char *string);
- int (*PC_LoadSourceHandle)(const char *filename);
- int (*PC_FreeSourceHandle)(int handle);
- int (*PC_ReadTokenHandle)(int handle, pc_token_t *pc_token);
- int (*PC_SourceFileAndLine)(int handle, char *filename, int *line);
-
- //start a frame in the bot library
- int (*BotLibStartFrame)(float time);
- //load a new map in the bot library
- int (*BotLibLoadMap)(const char *mapname);
- //entity updates
- int (*BotLibUpdateEntity)(int ent, bot_entitystate_t *state);
- //just for testing
- int (*Test)(int parm0, char *parm1, vec3_t parm2, vec3_t parm3);
-} botlib_export_t;
-
-//linking of bot library
-botlib_export_t *GetBotLibAPI( int apiVersion, botlib_import_t *import );
-
-/* Library variables:
-
-name: default: module(s): description:
-
-"basedir" "" l_utils.c base directory
-"gamedir" "" l_utils.c game directory
-"cddir" "" l_utils.c CD directory
-
-"log" "0" l_log.c enable/disable creating a log file
-"maxclients" "4" be_interface.c maximum number of clients
-"maxentities" "1024" be_interface.c maximum number of entities
-"bot_developer" "0" be_interface.c bot developer mode (it's "botDeveloper" in C to prevent symbol clash).
-
-"phys_friction" "6" be_aas_move.c ground friction
-"phys_stopspeed" "100" be_aas_move.c stop speed
-"phys_gravity" "800" be_aas_move.c gravity value
-"phys_waterfriction" "1" be_aas_move.c water friction
-"phys_watergravity" "400" be_aas_move.c gravity in water
-"phys_maxvelocity" "320" be_aas_move.c maximum velocity
-"phys_maxwalkvelocity" "320" be_aas_move.c maximum walk velocity
-"phys_maxcrouchvelocity" "100" be_aas_move.c maximum crouch velocity
-"phys_maxswimvelocity" "150" be_aas_move.c maximum swim velocity
-"phys_walkaccelerate" "10" be_aas_move.c walk acceleration
-"phys_airaccelerate" "1" be_aas_move.c air acceleration
-"phys_swimaccelerate" "4" be_aas_move.c swim acceleration
-"phys_maxstep" "18" be_aas_move.c maximum step height
-"phys_maxsteepness" "0.7" be_aas_move.c maximum floor steepness
-"phys_maxbarrier" "32" be_aas_move.c maximum barrier height
-"phys_maxwaterjump" "19" be_aas_move.c maximum waterjump height
-"phys_jumpvel" "270" be_aas_move.c jump z velocity
-"phys_falldelta5" "40" be_aas_move.c
-"phys_falldelta10" "60" be_aas_move.c
-"rs_waterjump" "400" be_aas_move.c
-"rs_teleport" "50" be_aas_move.c
-"rs_barrierjump" "100" be_aas_move.c
-"rs_startcrouch" "300" be_aas_move.c
-"rs_startgrapple" "500" be_aas_move.c
-"rs_startwalkoffledge" "70" be_aas_move.c
-"rs_startjump" "300" be_aas_move.c
-"rs_rocketjump" "500" be_aas_move.c
-"rs_bfgjump" "500" be_aas_move.c
-"rs_jumppad" "250" be_aas_move.c
-"rs_aircontrolledjumppad" "300" be_aas_move.c
-"rs_funcbob" "300" be_aas_move.c
-"rs_startelevator" "50" be_aas_move.c
-"rs_falldamage5" "300" be_aas_move.c
-"rs_falldamage10" "500" be_aas_move.c
-"rs_maxjumpfallheight" "450" be_aas_move.c
-
-"max_aaslinks" "4096" be_aas_sample.c maximum links in the AAS
-"max_routingcache" "4096" be_aas_route.c maximum routing cache size in KB
-"forceclustering" "0" be_aas_main.c force recalculation of clusters
-"forcereachability" "0" be_aas_main.c force recalculation of reachabilities
-"forcewrite" "0" be_aas_main.c force writing of aas file
-"aasoptimize" "0" be_aas_main.c enable aas optimization
-"sv_mapChecksum" "0" be_aas_main.c BSP file checksum
-"bot_visualizejumppads" "0" be_aas_reach.c visualize jump pads
-
-"bot_reloadcharacters" "0" - reload bot character files
-"ai_gametype" "0" be_ai_goal.c game type
-"droppedweight" "1000" be_ai_goal.c additional dropped item weight
-"weapindex_rocketlauncher" "5" be_ai_move.c rl weapon index for rocket jumping
-"weapindex_bfg10k" "9" be_ai_move.c bfg weapon index for bfg jumping
-"weapindex_grapple" "10" be_ai_move.c grapple weapon index for grappling
-"entitytypemissile" "3" be_ai_move.c ET_MISSILE
-"offhandgrapple" "0" be_ai_move.c enable off hand grapple hook
-"cmd_grappleon" "grappleon" be_ai_move.c command to activate off hand grapple
-"cmd_grappleoff" "grappleoff" be_ai_move.c command to deactivate off hand grapple
-"itemconfig" "items.c" be_ai_goal.c item configuration file
-"weaponconfig" "weapons.c" be_ai_weap.c weapon configuration file
-"synfile" "syn.c" be_ai_chat.c file with synonyms
-"rndfile" "rnd.c" be_ai_chat.c file with random strings
-"matchfile" "match.c" be_ai_chat.c file with match strings
-"nochat" "0" be_ai_chat.c disable chats
-"max_messages" "1024" be_ai_chat.c console message heap size
-"max_weaponinfo" "32" be_ai_weap.c maximum number of weapon info
-"max_projectileinfo" "32" be_ai_weap.c maximum number of projectile info
-"max_iteminfo" "256" be_ai_goal.c maximum number of item info
-"max_levelitems" "256" be_ai_goal.c maximum number of level items
-
-*/
-
diff --git a/engine/code/botlib/l_crc.c b/engine/code/botlib/l_crc.c
deleted file mode 100644
index 1fbb152..0000000
--- a/engine/code/botlib/l_crc.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: l_crc.c
- *
- * desc: CRC calculation
- *
- * $Archive: /MissionPack/CODE/botlib/l_crc.c $
- *
- *****************************************************************************/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "../qcommon/q_shared.h"
-#include "botlib.h"
-#include "be_interface.h" //for botimport.Print
-#include "l_crc.h"
-
-
-// FIXME: byte swap?
-
-// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
-// and the initial and final xor values shown below... in other words, the
-// CCITT standard CRC used by XMODEM
-
-#define CRC_INIT_VALUE 0xffff
-#define CRC_XOR_VALUE 0x0000
-
-unsigned short crctable[257] =
-{
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
- 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
- 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
- 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
- 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
- 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
- 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
- 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
- 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
- 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
- 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
- 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
- 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
- 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
- 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
- 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
- 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
- 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
- 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
- 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
- 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
- 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
- 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
- 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
- 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
- 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
- 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
- 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
- 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
- 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
- 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
- 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
-};
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void CRC_Init(unsigned short *crcvalue)
-{
- *crcvalue = CRC_INIT_VALUE;
-} //end of the function CRC_Init
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void CRC_ProcessByte(unsigned short *crcvalue, byte data)
-{
- *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
-} //end of the function CRC_ProcessByte
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-unsigned short CRC_Value(unsigned short crcvalue)
-{
- return crcvalue ^ CRC_XOR_VALUE;
-} //end of the function CRC_Value
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-unsigned short CRC_ProcessString(unsigned char *data, int length)
-{
- unsigned short crcvalue;
- int i, ind;
-
- CRC_Init(&crcvalue);
-
- for (i = 0; i < length; i++)
- {
- ind = (crcvalue >> 8) ^ data[i];
- if (ind < 0 || ind > 256) ind = 0;
- crcvalue = (crcvalue << 8) ^ crctable[ind];
- } //end for
- return CRC_Value(crcvalue);
-} //end of the function CRC_ProcessString
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void CRC_ContinueProcessString(unsigned short *crc, char *data, int length)
-{
- int i;
-
- for (i = 0; i < length; i++)
- {
- *crc = (*crc << 8) ^ crctable[(*crc >> 8) ^ data[i]];
- } //end for
-} //end of the function CRC_ProcessString
diff --git a/engine/code/botlib/l_libvar.c b/engine/code/botlib/l_libvar.c
deleted file mode 100644
index 0270781..0000000
--- a/engine/code/botlib/l_libvar.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: l_libvar.c
- *
- * desc: bot library variables
- *
- * $Archive: /MissionPack/code/botlib/l_libvar.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "l_memory.h"
-#include "l_libvar.h"
-
-//list with library variables
-libvar_t *libvarlist = NULL;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float LibVarStringValue(char *string)
-{
- int dotfound = 0;
- float value = 0;
-
- while(*string)
- {
- if (*string < '0' || *string > '9')
- {
- if (dotfound || *string != '.')
- {
- return 0;
- } //end if
- else
- {
- dotfound = 10;
- string++;
- } //end if
- } //end if
- if (dotfound)
- {
- value = value + (float) (*string - '0') / (float) dotfound;
- dotfound *= 10;
- } //end if
- else
- {
- value = value * 10.0 + (float) (*string - '0');
- } //end else
- string++;
- } //end while
- return value;
-} //end of the function LibVarStringValue
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-libvar_t *LibVarAlloc(char *var_name)
-{
- libvar_t *v;
-
- v = (libvar_t *) GetMemory(sizeof(libvar_t));
- Com_Memset(v, 0, sizeof(libvar_t));
- v->name = (char *) GetMemory(strlen(var_name)+1);
- strcpy(v->name, var_name);
- //add the variable in the list
- v->next = libvarlist;
- libvarlist = v;
- return v;
-} //end of the function LibVarAlloc
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void LibVarDeAlloc(libvar_t *v)
-{
- if (v->string) FreeMemory(v->string);
- FreeMemory(v->name);
- FreeMemory(v);
-} //end of the function LibVarDeAlloc
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void LibVarDeAllocAll(void)
-{
- libvar_t *v;
-
- for (v = libvarlist; v; v = libvarlist)
- {
- libvarlist = libvarlist->next;
- LibVarDeAlloc(v);
- } //end for
- libvarlist = NULL;
-} //end of the function LibVarDeAllocAll
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-libvar_t *LibVarGet(char *var_name)
-{
- libvar_t *v;
-
- for (v = libvarlist; v; v = v->next)
- {
- if (!Q_stricmp(v->name, var_name))
- {
- return v;
- } //end if
- } //end for
- return NULL;
-} //end of the function LibVarGet
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *LibVarGetString(char *var_name)
-{
- libvar_t *v;
-
- v = LibVarGet(var_name);
- if (v)
- {
- return v->string;
- } //end if
- else
- {
- return "";
- } //end else
-} //end of the function LibVarGetString
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float LibVarGetValue(char *var_name)
-{
- libvar_t *v;
-
- v = LibVarGet(var_name);
- if (v)
- {
- return v->value;
- } //end if
- else
- {
- return 0;
- } //end else
-} //end of the function LibVarGetValue
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-libvar_t *LibVar(char *var_name, char *value)
-{
- libvar_t *v;
- v = LibVarGet(var_name);
- if (v) return v;
- //create new variable
- v = LibVarAlloc(var_name);
- //variable string
- v->string = (char *) GetMemory(strlen(value) + 1);
- strcpy(v->string, value);
- //the value
- v->value = LibVarStringValue(v->string);
- //variable is modified
- v->modified = qtrue;
- //
- return v;
-} //end of the function LibVar
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *LibVarString(char *var_name, char *value)
-{
- libvar_t *v;
-
- v = LibVar(var_name, value);
- return v->string;
-} //end of the function LibVarString
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float LibVarValue(char *var_name, char *value)
-{
- libvar_t *v;
-
- v = LibVar(var_name, value);
- return v->value;
-} //end of the function LibVarValue
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void LibVarSet(char *var_name, char *value)
-{
- libvar_t *v;
-
- v = LibVarGet(var_name);
- if (v)
- {
- FreeMemory(v->string);
- } //end if
- else
- {
- v = LibVarAlloc(var_name);
- } //end else
- //variable string
- v->string = (char *) GetMemory(strlen(value) + 1);
- strcpy(v->string, value);
- //the value
- v->value = LibVarStringValue(v->string);
- //variable is modified
- v->modified = qtrue;
-} //end of the function LibVarSet
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean LibVarChanged(char *var_name)
-{
- libvar_t *v;
-
- v = LibVarGet(var_name);
- if (v)
- {
- return v->modified;
- } //end if
- else
- {
- return qfalse;
- } //end else
-} //end of the function LibVarChanged
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void LibVarSetNotModified(char *var_name)
-{
- libvar_t *v;
-
- v = LibVarGet(var_name);
- if (v)
- {
- v->modified = qfalse;
- } //end if
-} //end of the function LibVarSetNotModified
diff --git a/engine/code/botlib/l_log.c b/engine/code/botlib/l_log.c
deleted file mode 100644
index ee25604..0000000
--- a/engine/code/botlib/l_log.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: l_log.c
- *
- * desc: log file
- *
- * $Archive: /MissionPack/CODE/botlib/l_log.c $
- *
- *****************************************************************************/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "../qcommon/q_shared.h"
-#include "botlib.h"
-#include "be_interface.h" //for botimport.Print
-#include "l_libvar.h"
-#include "l_log.h"
-
-#define MAX_LOGFILENAMESIZE 1024
-
-typedef struct logfile_s
-{
- char filename[MAX_LOGFILENAMESIZE];
- FILE *fp;
- int numwrites;
-} logfile_t;
-
-static logfile_t logfile;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Log_Open(char *filename)
-{
- if (!LibVarValue("log", "0")) return;
- if (!filename || !strlen(filename))
- {
- botimport.Print(PRT_MESSAGE, "openlog <filename>\n");
- return;
- } //end if
- if (logfile.fp)
- {
- botimport.Print(PRT_ERROR, "log file %s is already opened\n", logfile.filename);
- return;
- } //end if
- logfile.fp = fopen(filename, "wb");
- if (!logfile.fp)
- {
- botimport.Print(PRT_ERROR, "can't open the log file %s\n", filename);
- return;
- } //end if
- strncpy(logfile.filename, filename, MAX_LOGFILENAMESIZE);
- botimport.Print(PRT_MESSAGE, "Opened log %s\n", logfile.filename);
-} //end of the function Log_Create
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Log_Close(void)
-{
- if (!logfile.fp) return;
- if (fclose(logfile.fp))
- {
- botimport.Print(PRT_ERROR, "can't close log file %s\n", logfile.filename);
- return;
- } //end if
- logfile.fp = NULL;
- botimport.Print(PRT_MESSAGE, "Closed log %s\n", logfile.filename);
-} //end of the function Log_Close
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Log_Shutdown(void)
-{
- if (logfile.fp) Log_Close();
-} //end of the function Log_Shutdown
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void QDECL Log_Write(char *fmt, ...)
-{
- va_list ap;
-
- if (!logfile.fp) return;
- va_start(ap, fmt);
- vfprintf(logfile.fp, fmt, ap);
- va_end(ap);
- //fprintf(logfile.fp, "\r\n");
- fflush(logfile.fp);
-} //end of the function Log_Write
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void QDECL Log_WriteTimeStamped(char *fmt, ...)
-{
- va_list ap;
-
- if (!logfile.fp) return;
- fprintf(logfile.fp, "%d %02d:%02d:%02d:%02d ",
- logfile.numwrites,
- (int) (botlibglobals.time / 60 / 60),
- (int) (botlibglobals.time / 60),
- (int) (botlibglobals.time),
- (int) ((int) (botlibglobals.time * 100)) -
- ((int) botlibglobals.time) * 100);
- va_start(ap, fmt);
- vfprintf(logfile.fp, fmt, ap);
- va_end(ap);
- fprintf(logfile.fp, "\r\n");
- logfile.numwrites++;
- fflush(logfile.fp);
-} //end of the function Log_Write
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-FILE *Log_FilePointer(void)
-{
- return logfile.fp;
-} //end of the function Log_FilePointer
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Log_Flush(void)
-{
- if (logfile.fp) fflush(logfile.fp);
-} //end of the function Log_Flush
-
diff --git a/engine/code/botlib/l_memory.c b/engine/code/botlib/l_memory.c
deleted file mode 100644
index e67c43c..0000000
--- a/engine/code/botlib/l_memory.c
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: l_memory.c
- *
- * desc: memory allocation
- *
- * $Archive: /MissionPack/code/botlib/l_memory.c $
- *
- *****************************************************************************/
-
-#include "../qcommon/q_shared.h"
-#include "botlib.h"
-#include "l_log.h"
-#include "l_memory.h"
-#include "be_interface.h"
-
-//#define MEMDEBUG
-//#define MEMORYMANEGER
-
-#define MEM_ID 0x12345678l
-#define HUNK_ID 0x87654321l
-
-int allocatedmemory;
-int totalmemorysize;
-int numblocks;
-
-#ifdef MEMORYMANEGER
-
-typedef struct memoryblock_s
-{
- unsigned long int id;
- void *ptr;
- int size;
-#ifdef MEMDEBUG
- char *label;
- char *file;
- int line;
-#endif //MEMDEBUG
- struct memoryblock_s *prev, *next;
-} memoryblock_t;
-
-memoryblock_t *memory;
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void LinkMemoryBlock(memoryblock_t *block)
-{
- block->prev = NULL;
- block->next = memory;
- if (memory) memory->prev = block;
- memory = block;
-} //end of the function LinkMemoryBlock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void UnlinkMemoryBlock(memoryblock_t *block)
-{
- if (block->prev) block->prev->next = block->next;
- else memory = block->next;
- if (block->next) block->next->prev = block->prev;
-} //end of the function UnlinkMemoryBlock
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef MEMDEBUG
-void *GetMemoryDebug(unsigned long size, char *label, char *file, int line)
-#else
-void *GetMemory(unsigned long size)
-#endif //MEMDEBUG
-{
- void *ptr;
- memoryblock_t *block;
- assert(botimport.GetMemory);
- ptr = botimport.GetMemory(size + sizeof(memoryblock_t));
- block = (memoryblock_t *) ptr;
- block->id = MEM_ID;
- block->ptr = (char *) ptr + sizeof(memoryblock_t);
- block->size = size + sizeof(memoryblock_t);
-#ifdef MEMDEBUG
- block->label = label;
- block->file = file;
- block->line = line;
-#endif //MEMDEBUG
- LinkMemoryBlock(block);
- allocatedmemory += block->size;
- totalmemorysize += block->size + sizeof(memoryblock_t);
- numblocks++;
- return block->ptr;
-} //end of the function GetMemoryDebug
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef MEMDEBUG
-void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line)
-#else
-void *GetClearedMemory(unsigned long size)
-#endif //MEMDEBUG
-{
- void *ptr;
-#ifdef MEMDEBUG
- ptr = GetMemoryDebug(size, label, file, line);
-#else
- ptr = GetMemory(size);
-#endif //MEMDEBUG
- Com_Memset(ptr, 0, size);
- return ptr;
-} //end of the function GetClearedMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef MEMDEBUG
-void *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line)
-#else
-void *GetHunkMemory(unsigned long size)
-#endif //MEMDEBUG
-{
- void *ptr;
- memoryblock_t *block;
-
- ptr = botimport.HunkAlloc(size + sizeof(memoryblock_t));
- block = (memoryblock_t *) ptr;
- block->id = HUNK_ID;
- block->ptr = (char *) ptr + sizeof(memoryblock_t);
- block->size = size + sizeof(memoryblock_t);
-#ifdef MEMDEBUG
- block->label = label;
- block->file = file;
- block->line = line;
-#endif //MEMDEBUG
- LinkMemoryBlock(block);
- allocatedmemory += block->size;
- totalmemorysize += block->size + sizeof(memoryblock_t);
- numblocks++;
- return block->ptr;
-} //end of the function GetHunkMemoryDebug
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef MEMDEBUG
-void *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line)
-#else
-void *GetClearedHunkMemory(unsigned long size)
-#endif //MEMDEBUG
-{
- void *ptr;
-#ifdef MEMDEBUG
- ptr = GetHunkMemoryDebug(size, label, file, line);
-#else
- ptr = GetHunkMemory(size);
-#endif //MEMDEBUG
- Com_Memset(ptr, 0, size);
- return ptr;
-} //end of the function GetClearedHunkMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-memoryblock_t *BlockFromPointer(void *ptr, char *str)
-{
- memoryblock_t *block;
-
- if (!ptr)
- {
-#ifdef MEMDEBUG
- //char *crash = (char *) NULL;
- //crash[0] = 1;
- botimport.Print(PRT_FATAL, "%s: NULL pointer\n", str);
-#endif // MEMDEBUG
- return NULL;
- } //end if
- block = (memoryblock_t *) ((char *) ptr - sizeof(memoryblock_t));
- if (block->id != MEM_ID && block->id != HUNK_ID)
- {
- botimport.Print(PRT_FATAL, "%s: invalid memory block\n", str);
- return NULL;
- } //end if
- if (block->ptr != ptr)
- {
- botimport.Print(PRT_FATAL, "%s: memory block pointer invalid\n", str);
- return NULL;
- } //end if
- return block;
-} //end of the function BlockFromPointer
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FreeMemory(void *ptr)
-{
- memoryblock_t *block;
-
- block = BlockFromPointer(ptr, "FreeMemory");
- if (!block) return;
- UnlinkMemoryBlock(block);
- allocatedmemory -= block->size;
- totalmemorysize -= block->size + sizeof(memoryblock_t);
- numblocks--;
- //
- if (block->id == MEM_ID)
- {
- botimport.FreeMemory(block);
- } //end if
-} //end of the function FreeMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AvailableMemory(void)
-{
- return botimport.AvailableMemory();
-} //end of the function AvailableMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int MemoryByteSize(void *ptr)
-{
- memoryblock_t *block;
-
- block = BlockFromPointer(ptr, "MemoryByteSize");
- if (!block) return 0;
- return block->size;
-} //end of the function MemoryByteSize
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void PrintUsedMemorySize(void)
-{
- botimport.Print(PRT_MESSAGE, "total allocated memory: %d KB\n", allocatedmemory >> 10);
- botimport.Print(PRT_MESSAGE, "total botlib memory: %d KB\n", totalmemorysize >> 10);
- botimport.Print(PRT_MESSAGE, "total memory blocks: %d\n", numblocks);
-} //end of the function PrintUsedMemorySize
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void PrintMemoryLabels(void)
-{
- memoryblock_t *block;
- int i;
-
- PrintUsedMemorySize();
- i = 0;
- Log_Write("============= Botlib memory log ==============\r\n");
- Log_Write("\r\n");
- for (block = memory; block; block = block->next)
- {
-#ifdef MEMDEBUG
- if (block->id == HUNK_ID)
- {
- Log_Write("%6d, hunk %p, %8d: %24s line %6d: %s\r\n", i, block->ptr, block->size, block->file, block->line, block->label);
- } //end if
- else
- {
- Log_Write("%6d, %p, %8d: %24s line %6d: %s\r\n", i, block->ptr, block->size, block->file, block->line, block->label);
- } //end else
-#endif //MEMDEBUG
- i++;
- } //end for
-} //end of the function PrintMemoryLabels
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void DumpMemory(void)
-{
- memoryblock_t *block;
-
- for (block = memory; block; block = memory)
- {
- FreeMemory(block->ptr);
- } //end for
- totalmemorysize = 0;
- allocatedmemory = 0;
-} //end of the function DumpMemory
-
-#else
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef MEMDEBUG
-void *GetMemoryDebug(unsigned long size, char *label, char *file, int line)
-#else
-void *GetMemory(unsigned long size)
-#endif //MEMDEBUG
-{
- void *ptr;
- unsigned long int *memid;
-
- ptr = botimport.GetMemory(size + sizeof(unsigned long int));
- if (!ptr) return NULL;
- memid = (unsigned long int *) ptr;
- *memid = MEM_ID;
- return (unsigned long int *) ((char *) ptr + sizeof(unsigned long int));
-} //end of the function GetMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef MEMDEBUG
-void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line)
-#else
-void *GetClearedMemory(unsigned long size)
-#endif //MEMDEBUG
-{
- void *ptr;
-#ifdef MEMDEBUG
- ptr = GetMemoryDebug(size, label, file, line);
-#else
- ptr = GetMemory(size);
-#endif //MEMDEBUG
- Com_Memset(ptr, 0, size);
- return ptr;
-} //end of the function GetClearedMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef MEMDEBUG
-void *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line)
-#else
-void *GetHunkMemory(unsigned long size)
-#endif //MEMDEBUG
-{
- void *ptr;
- unsigned long int *memid;
-
- ptr = botimport.HunkAlloc(size + sizeof(unsigned long int));
- if (!ptr) return NULL;
- memid = (unsigned long int *) ptr;
- *memid = HUNK_ID;
- return (unsigned long int *) ((char *) ptr + sizeof(unsigned long int));
-} //end of the function GetHunkMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-#ifdef MEMDEBUG
-void *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line)
-#else
-void *GetClearedHunkMemory(unsigned long size)
-#endif //MEMDEBUG
-{
- void *ptr;
-#ifdef MEMDEBUG
- ptr = GetHunkMemoryDebug(size, label, file, line);
-#else
- ptr = GetHunkMemory(size);
-#endif //MEMDEBUG
- Com_Memset(ptr, 0, size);
- return ptr;
-} //end of the function GetClearedHunkMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void FreeMemory(void *ptr)
-{
- unsigned long int *memid;
-
- memid = (unsigned long int *) ((char *) ptr - sizeof(unsigned long int));
-
- if (*memid == MEM_ID)
- {
- botimport.FreeMemory(memid);
- } //end if
-} //end of the function FreeMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int AvailableMemory(void)
-{
- return botimport.AvailableMemory();
-} //end of the function AvailableMemory
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void PrintUsedMemorySize(void)
-{
-} //end of the function PrintUsedMemorySize
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void PrintMemoryLabels(void)
-{
-} //end of the function PrintMemoryLabels
-
-#endif
diff --git a/engine/code/botlib/l_precomp.c b/engine/code/botlib/l_precomp.c
deleted file mode 100644
index 1fe7c14..0000000
--- a/engine/code/botlib/l_precomp.c
+++ /dev/null
@@ -1,3238 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: l_precomp.c
- *
- * desc: pre compiler
- *
- * $Archive: /MissionPack/code/botlib/l_precomp.c $
- *
- *****************************************************************************/
-
-//Notes: fix: PC_StringizeTokens
-
-//#define SCREWUP
-//#define BOTLIB
-//#define QUAKE
-//#define QUAKEC
-//#define MEQCC
-
-#ifdef SCREWUP
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <string.h>
-#include <stdarg.h>
-#include <time.h>
-#include "l_memory.h"
-#include "l_script.h"
-#include "l_precomp.h"
-
-typedef enum {qfalse, qtrue} qboolean;
-#endif //SCREWUP
-
-#ifdef BOTLIB
-#include "../qcommon/q_shared.h"
-#include "botlib.h"
-#include "be_interface.h"
-#include "l_memory.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_log.h"
-#endif //BOTLIB
-
-#ifdef MEQCC
-#include "qcc.h"
-#include "time.h" //time & ctime
-#include "math.h" //fabs
-#include "l_memory.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_log.h"
-
-#define qtrue true
-#define qfalse false
-#endif //MEQCC
-
-#ifdef BSPC
-//include files for usage in the BSP Converter
-#include "../bspc/qbsp.h"
-#include "../bspc/l_log.h"
-#include "../bspc/l_mem.h"
-#include "l_precomp.h"
-
-#define qtrue true
-#define qfalse false
-#define Q_stricmp stricmp
-
-#endif //BSPC
-
-#if defined(QUAKE) && !defined(BSPC)
-#include "l_utils.h"
-#endif //QUAKE
-
-//#define DEBUG_EVAL
-
-#define MAX_DEFINEPARMS 128
-
-#define DEFINEHASHING 1
-
-//directive name with parse function
-typedef struct directive_s
-{
- char *name;
- int (*func)(source_t *source);
-} directive_t;
-
-#define DEFINEHASHSIZE 1024
-
-#define TOKEN_HEAP_SIZE 4096
-
-int numtokens;
-/*
-int tokenheapinitialized; //true when the token heap is initialized
-token_t token_heap[TOKEN_HEAP_SIZE]; //heap with tokens
-token_t *freetokens; //free tokens from the heap
-*/
-
-//list with global defines added to every source loaded
-define_t *globaldefines;
-
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void QDECL SourceError(source_t *source, char *str, ...)
-{
- char text[1024];
- va_list ap;
-
- va_start(ap, str);
- Q_vsnprintf(text, sizeof(text), str, ap);
- va_end(ap);
-#ifdef BOTLIB
- botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
-#endif //BOTLIB
-#ifdef MEQCC
- printf("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
-#endif //MEQCC
-#ifdef BSPC
- Log_Print("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
-#endif //BSPC
-} //end of the function SourceError
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void QDECL SourceWarning(source_t *source, char *str, ...)
-{
- char text[1024];
- va_list ap;
-
- va_start(ap, str);
- Q_vsnprintf(text, sizeof(text), str, ap);
- va_end(ap);
-#ifdef BOTLIB
- botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
-#endif //BOTLIB
-#ifdef MEQCC
- printf("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
-#endif //MEQCC
-#ifdef BSPC
- Log_Print("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
-#endif //BSPC
-} //end of the function ScriptWarning
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_PushIndent(source_t *source, int type, int skip)
-{
- indent_t *indent;
-
- indent = (indent_t *) GetMemory(sizeof(indent_t));
- indent->type = type;
- indent->script = source->scriptstack;
- indent->skip = (skip != 0);
- source->skip += indent->skip;
- indent->next = source->indentstack;
- source->indentstack = indent;
-} //end of the function PC_PushIndent
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_PopIndent(source_t *source, int *type, int *skip)
-{
- indent_t *indent;
-
- *type = 0;
- *skip = 0;
-
- indent = source->indentstack;
- if (!indent) return;
-
- //must be an indent from the current script
- if (source->indentstack->script != source->scriptstack) return;
-
- *type = indent->type;
- *skip = indent->skip;
- source->indentstack = source->indentstack->next;
- source->skip -= indent->skip;
- FreeMemory(indent);
-} //end of the function PC_PopIndent
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_PushScript(source_t *source, script_t *script)
-{
- script_t *s;
-
- for (s = source->scriptstack; s; s = s->next)
- {
- if (!Q_stricmp(s->filename, script->filename))
- {
- SourceError(source, "%s recursively included", script->filename);
- return;
- } //end if
- } //end for
- //push the script on the script stack
- script->next = source->scriptstack;
- source->scriptstack = script;
-} //end of the function PC_PushScript
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_InitTokenHeap(void)
-{
- /*
- int i;
-
- if (tokenheapinitialized) return;
- freetokens = NULL;
- for (i = 0; i < TOKEN_HEAP_SIZE; i++)
- {
- token_heap[i].next = freetokens;
- freetokens = &token_heap[i];
- } //end for
- tokenheapinitialized = qtrue;
- */
-} //end of the function PC_InitTokenHeap
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-token_t *PC_CopyToken(token_t *token)
-{
- token_t *t;
-
-// t = (token_t *) malloc(sizeof(token_t));
- t = (token_t *) GetMemory(sizeof(token_t));
-// t = freetokens;
- if (!t)
- {
-#ifdef BSPC
- Error("out of token space\n");
-#else
- Com_Error(ERR_FATAL, "out of token space\n");
-#endif
- return NULL;
- } //end if
-// freetokens = freetokens->next;
- Com_Memcpy(t, token, sizeof(token_t));
- t->next = NULL;
- numtokens++;
- return t;
-} //end of the function PC_CopyToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_FreeToken(token_t *token)
-{
- //free(token);
- FreeMemory(token);
-// token->next = freetokens;
-// freetokens = token;
- numtokens--;
-} //end of the function PC_FreeToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_ReadSourceToken(source_t *source, token_t *token)
-{
- token_t *t;
- script_t *script;
- int type, skip;
-
- //if there's no token already available
- while(!source->tokens)
- {
- //if there's a token to read from the script
- if (PS_ReadToken(source->scriptstack, token)) return qtrue;
- //if at the end of the script
- if (EndOfScript(source->scriptstack))
- {
- //remove all indents of the script
- while(source->indentstack &&
- source->indentstack->script == source->scriptstack)
- {
- SourceWarning(source, "missing #endif");
- PC_PopIndent(source, &type, &skip);
- } //end if
- } //end if
- //if this was the initial script
- if (!source->scriptstack->next) return qfalse;
- //remove the script and return to the last one
- script = source->scriptstack;
- source->scriptstack = source->scriptstack->next;
- FreeScript(script);
- } //end while
- //copy the already available token
- Com_Memcpy(token, source->tokens, sizeof(token_t));
- //free the read token
- t = source->tokens;
- source->tokens = source->tokens->next;
- PC_FreeToken(t);
- return qtrue;
-} //end of the function PC_ReadSourceToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_UnreadSourceToken(source_t *source, token_t *token)
-{
- token_t *t;
-
- t = PC_CopyToken(token);
- t->next = source->tokens;
- source->tokens = t;
- return qtrue;
-} //end of the function PC_UnreadSourceToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_ReadDefineParms(source_t *source, define_t *define, token_t **parms, int maxparms)
-{
- token_t token, *t, *last;
- int i, done, lastcomma, numparms, indent;
-
- if (!PC_ReadSourceToken(source, &token))
- {
- SourceError(source, "define %s missing parms", define->name);
- return qfalse;
- } //end if
- //
- if (define->numparms > maxparms)
- {
- SourceError(source, "define with more than %d parameters", maxparms);
- return qfalse;
- } //end if
- //
- for (i = 0; i < define->numparms; i++) parms[i] = NULL;
- //if no leading "("
- if (strcmp(token.string, "("))
- {
- PC_UnreadSourceToken(source, &token);
- SourceError(source, "define %s missing parms", define->name);
- return qfalse;
- } //end if
- //read the define parameters
- for (done = 0, numparms = 0, indent = 0; !done;)
- {
- if (numparms >= maxparms)
- {
- SourceError(source, "define %s with too many parms", define->name);
- return qfalse;
- } //end if
- if (numparms >= define->numparms)
- {
- SourceWarning(source, "define %s has too many parms", define->name);
- return qfalse;
- } //end if
- parms[numparms] = NULL;
- lastcomma = 1;
- last = NULL;
- while(!done)
- {
- //
- if (!PC_ReadSourceToken(source, &token))
- {
- SourceError(source, "define %s incomplete", define->name);
- return qfalse;
- } //end if
- //
- if (!strcmp(token.string, ","))
- {
- if (indent <= 0)
- {
- if (lastcomma) SourceWarning(source, "too many comma's");
- lastcomma = 1;
- break;
- } //end if
- } //end if
- lastcomma = 0;
- //
- if (!strcmp(token.string, "("))
- {
- indent++;
- continue;
- } //end if
- else if (!strcmp(token.string, ")"))
- {
- if (--indent <= 0)
- {
- if (!parms[define->numparms-1])
- {
- SourceWarning(source, "too few define parms");
- } //end if
- done = 1;
- break;
- } //end if
- } //end if
- //
- if (numparms < define->numparms)
- {
- //
- t = PC_CopyToken(&token);
- t->next = NULL;
- if (last) last->next = t;
- else parms[numparms] = t;
- last = t;
- } //end if
- } //end while
- numparms++;
- } //end for
- return qtrue;
-} //end of the function PC_ReadDefineParms
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_StringizeTokens(token_t *tokens, token_t *token)
-{
- token_t *t;
-
- token->type = TT_STRING;
- token->whitespace_p = NULL;
- token->endwhitespace_p = NULL;
- token->string[0] = '\0';
- strcat(token->string, "\"");
- for (t = tokens; t; t = t->next)
- {
- strncat(token->string, t->string, MAX_TOKEN - strlen(token->string) - 1);
- } //end for
- strncat(token->string, "\"", MAX_TOKEN - strlen(token->string) - 1);
- return qtrue;
-} //end of the function PC_StringizeTokens
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_MergeTokens(token_t *t1, token_t *t2)
-{
- //merging of a name with a name or number
- if (t1->type == TT_NAME && (t2->type == TT_NAME || t2->type == TT_NUMBER))
- {
- strcat(t1->string, t2->string);
- return qtrue;
- } //end if
- //merging of two strings
- if (t1->type == TT_STRING && t2->type == TT_STRING)
- {
- //remove trailing double quote
- t1->string[strlen(t1->string)-1] = '\0';
- //concat without leading double quote
- strcat(t1->string, &t2->string[1]);
- return qtrue;
- } //end if
- //FIXME: merging of two number of the same sub type
- return qfalse;
-} //end of the function PC_MergeTokens
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-/*
-void PC_PrintDefine(define_t *define)
-{
- printf("define->name = %s\n", define->name);
- printf("define->flags = %d\n", define->flags);
- printf("define->builtin = %d\n", define->builtin);
- printf("define->numparms = %d\n", define->numparms);
-// token_t *parms; //define parameters
-// token_t *tokens; //macro tokens (possibly containing parm tokens)
-// struct define_s *next; //next defined macro in a list
-} //end of the function PC_PrintDefine*/
-#if DEFINEHASHING
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_PrintDefineHashTable(define_t **definehash)
-{
- int i;
- define_t *d;
-
- for (i = 0; i < DEFINEHASHSIZE; i++)
- {
- Log_Write("%4d:", i);
- for (d = definehash[i]; d; d = d->hashnext)
- {
- Log_Write(" %s", d->name);
- } //end for
- Log_Write("\n");
- } //end for
-} //end of the function PC_PrintDefineHashTable
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-//char primes[16] = {1, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47};
-
-int PC_NameHash(char *name)
-{
- int register hash, i;
-
- hash = 0;
- for (i = 0; name[i] != '\0'; i++)
- {
- hash += name[i] * (119 + i);
- //hash += (name[i] << 7) + i;
- //hash += (name[i] << (i&15));
- } //end while
- hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1);
- return hash;
-} //end of the function PC_NameHash
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_AddDefineToHash(define_t *define, define_t **definehash)
-{
- int hash;
-
- hash = PC_NameHash(define->name);
- define->hashnext = definehash[hash];
- definehash[hash] = define;
-} //end of the function PC_AddDefineToHash
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-define_t *PC_FindHashedDefine(define_t **definehash, char *name)
-{
- define_t *d;
- int hash;
-
- hash = PC_NameHash(name);
- for (d = definehash[hash]; d; d = d->hashnext)
- {
- if (!strcmp(d->name, name)) return d;
- } //end for
- return NULL;
-} //end of the function PC_FindHashedDefine
-#endif //DEFINEHASHING
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-define_t *PC_FindDefine(define_t *defines, char *name)
-{
- define_t *d;
-
- for (d = defines; d; d = d->next)
- {
- if (!strcmp(d->name, name)) return d;
- } //end for
- return NULL;
-} //end of the function PC_FindDefine
-//============================================================================
-//
-// Parameter: -
-// Returns: number of the parm
-// if no parm found with the given name -1 is returned
-// Changes Globals: -
-//============================================================================
-int PC_FindDefineParm(define_t *define, char *name)
-{
- token_t *p;
- int i;
-
- i = 0;
- for (p = define->parms; p; p = p->next)
- {
- if (!strcmp(p->string, name)) return i;
- i++;
- } //end for
- return -1;
-} //end of the function PC_FindDefineParm
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_FreeDefine(define_t *define)
-{
- token_t *t, *next;
-
- //free the define parameters
- for (t = define->parms; t; t = next)
- {
- next = t->next;
- PC_FreeToken(t);
- } //end for
- //free the define tokens
- for (t = define->tokens; t; t = next)
- {
- next = t->next;
- PC_FreeToken(t);
- } //end for
- //free the define
- FreeMemory(define->name);
- FreeMemory(define);
-} //end of the function PC_FreeDefine
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_AddBuiltinDefines(source_t *source)
-{
- int i;
- define_t *define;
- struct builtin
- {
- char *string;
- int builtin;
- } builtin[] = {
- { "__LINE__", BUILTIN_LINE },
- { "__FILE__", BUILTIN_FILE },
- { "__DATE__", BUILTIN_DATE },
- { "__TIME__", BUILTIN_TIME },
-// { "__STDC__", BUILTIN_STDC },
- { NULL, 0 }
- };
-
- for (i = 0; builtin[i].string; i++)
- {
- define = (define_t *) GetMemory(sizeof(define_t));
- Com_Memset(define, 0, sizeof(define_t));
- define->name = (char *) GetMemory(strlen(builtin[i].string) + 1);
- strcpy(define->name, builtin[i].string);
- define->flags |= DEFINE_FIXED;
- define->builtin = builtin[i].builtin;
- //add the define to the source
-#if DEFINEHASHING
- PC_AddDefineToHash(define, source->definehash);
-#else
- define->next = source->defines;
- source->defines = define;
-#endif //DEFINEHASHING
- } //end for
-} //end of the function PC_AddBuiltinDefines
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_ExpandBuiltinDefine(source_t *source, token_t *deftoken, define_t *define,
- token_t **firsttoken, token_t **lasttoken)
-{
- token_t *token;
- time_t t;
-
- char *curtime;
-
- token = PC_CopyToken(deftoken);
- switch(define->builtin)
- {
- case BUILTIN_LINE:
- {
- sprintf(token->string, "%d", deftoken->line);
-#ifdef NUMBERVALUE
- token->intvalue = deftoken->line;
- token->floatvalue = deftoken->line;
-#endif //NUMBERVALUE
- token->type = TT_NUMBER;
- token->subtype = TT_DECIMAL | TT_INTEGER;
- *firsttoken = token;
- *lasttoken = token;
- break;
- } //end case
- case BUILTIN_FILE:
- {
- strcpy(token->string, source->scriptstack->filename);
- token->type = TT_NAME;
- token->subtype = strlen(token->string);
- *firsttoken = token;
- *lasttoken = token;
- break;
- } //end case
- case BUILTIN_DATE:
- {
- t = time(NULL);
- curtime = ctime(&t);
- strcpy(token->string, "\"");
- strncat(token->string, curtime+4, 7);
- strncat(token->string+7, curtime+20, 4);
- strcat(token->string, "\"");
- free(curtime);
- token->type = TT_NAME;
- token->subtype = strlen(token->string);
- *firsttoken = token;
- *lasttoken = token;
- break;
- } //end case
- case BUILTIN_TIME:
- {
- t = time(NULL);
- curtime = ctime(&t);
- strcpy(token->string, "\"");
- strncat(token->string, curtime+11, 8);
- strcat(token->string, "\"");
- free(curtime);
- token->type = TT_NAME;
- token->subtype = strlen(token->string);
- *firsttoken = token;
- *lasttoken = token;
- break;
- } //end case
- case BUILTIN_STDC:
- default:
- {
- *firsttoken = NULL;
- *lasttoken = NULL;
- break;
- } //end case
- } //end switch
- return qtrue;
-} //end of the function PC_ExpandBuiltinDefine
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_ExpandDefine(source_t *source, token_t *deftoken, define_t *define,
- token_t **firsttoken, token_t **lasttoken)
-{
- token_t *parms[MAX_DEFINEPARMS], *dt, *pt, *t;
- token_t *t1, *t2, *first, *last, *nextpt, token;
- int parmnum, i;
-
- //if it is a builtin define
- if (define->builtin)
- {
- return PC_ExpandBuiltinDefine(source, deftoken, define, firsttoken, lasttoken);
- } //end if
- //if the define has parameters
- if (define->numparms)
- {
- if (!PC_ReadDefineParms(source, define, parms, MAX_DEFINEPARMS)) return qfalse;
-#ifdef DEBUG_EVAL
- for (i = 0; i < define->numparms; i++)
- {
- Log_Write("define parms %d:", i);
- for (pt = parms[i]; pt; pt = pt->next)
- {
- Log_Write("%s", pt->string);
- } //end for
- } //end for
-#endif //DEBUG_EVAL
- } //end if
- //empty list at first
- first = NULL;
- last = NULL;
- //create a list with tokens of the expanded define
- for (dt = define->tokens; dt; dt = dt->next)
- {
- parmnum = -1;
- //if the token is a name, it could be a define parameter
- if (dt->type == TT_NAME)
- {
- parmnum = PC_FindDefineParm(define, dt->string);
- } //end if
- //if it is a define parameter
- if (parmnum >= 0)
- {
- for (pt = parms[parmnum]; pt; pt = pt->next)
- {
- t = PC_CopyToken(pt);
- //add the token to the list
- t->next = NULL;
- if (last) last->next = t;
- else first = t;
- last = t;
- } //end for
- } //end if
- else
- {
- //if stringizing operator
- if (dt->string[0] == '#' && dt->string[1] == '\0')
- {
- //the stringizing operator must be followed by a define parameter
- if (dt->next) parmnum = PC_FindDefineParm(define, dt->next->string);
- else parmnum = -1;
- //
- if (parmnum >= 0)
- {
- //step over the stringizing operator
- dt = dt->next;
- //stringize the define parameter tokens
- if (!PC_StringizeTokens(parms[parmnum], &token))
- {
- SourceError(source, "can't stringize tokens");
- return qfalse;
- } //end if
- t = PC_CopyToken(&token);
- } //end if
- else
- {
- SourceWarning(source, "stringizing operator without define parameter");
- continue;
- } //end if
- } //end if
- else
- {
- t = PC_CopyToken(dt);
- } //end else
- //add the token to the list
- t->next = NULL;
- if (last) last->next = t;
- else first = t;
- last = t;
- } //end else
- } //end for
- //check for the merging operator
- for (t = first; t; )
- {
- if (t->next)
- {
- //if the merging operator
- if (t->next->string[0] == '#' && t->next->string[1] == '#')
- {
- t1 = t;
- t2 = t->next->next;
- if (t2)
- {
- if (!PC_MergeTokens(t1, t2))
- {
- SourceError(source, "can't merge %s with %s", t1->string, t2->string);
- return qfalse;
- } //end if
- PC_FreeToken(t1->next);
- t1->next = t2->next;
- if (t2 == last) last = t1;
- PC_FreeToken(t2);
- continue;
- } //end if
- } //end if
- } //end if
- t = t->next;
- } //end for
- //store the first and last token of the list
- *firsttoken = first;
- *lasttoken = last;
- //free all the parameter tokens
- for (i = 0; i < define->numparms; i++)
- {
- for (pt = parms[i]; pt; pt = nextpt)
- {
- nextpt = pt->next;
- PC_FreeToken(pt);
- } //end for
- } //end for
- //
- return qtrue;
-} //end of the function PC_ExpandDefine
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_ExpandDefineIntoSource(source_t *source, token_t *deftoken, define_t *define)
-{
- token_t *firsttoken, *lasttoken;
-
- if (!PC_ExpandDefine(source, deftoken, define, &firsttoken, &lasttoken)) return qfalse;
-
- if (firsttoken && lasttoken)
- {
- lasttoken->next = source->tokens;
- source->tokens = firsttoken;
- return qtrue;
- } //end if
- return qfalse;
-} //end of the function PC_ExpandDefineIntoSource
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_ConvertPath(char *path)
-{
- char *ptr;
-
- //remove double path seperators
- for (ptr = path; *ptr;)
- {
- if ((*ptr == '\\' || *ptr == '/') &&
- (*(ptr+1) == '\\' || *(ptr+1) == '/'))
- {
- memmove(ptr, ptr+1, strlen(ptr));
- } //end if
- else
- {
- ptr++;
- } //end else
- } //end while
- //set OS dependent path seperators
- for (ptr = path; *ptr;)
- {
- if (*ptr == '/' || *ptr == '\\') *ptr = PATHSEPERATOR_CHAR;
- ptr++;
- } //end while
-} //end of the function PC_ConvertPath
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_include(source_t *source)
-{
- script_t *script;
- token_t token;
- char path[MAX_PATH];
-#ifdef QUAKE
- foundfile_t file;
-#endif //QUAKE
-
- if (source->skip > 0) return qtrue;
- //
- if (!PC_ReadSourceToken(source, &token))
- {
- SourceError(source, "#include without file name");
- return qfalse;
- } //end if
- if (token.linescrossed > 0)
- {
- SourceError(source, "#include without file name");
- return qfalse;
- } //end if
- if (token.type == TT_STRING)
- {
- StripDoubleQuotes(token.string);
- PC_ConvertPath(token.string);
- script = LoadScriptFile(token.string);
- if (!script)
- {
- strcpy(path, source->includepath);
- strcat(path, token.string);
- script = LoadScriptFile(path);
- } //end if
- } //end if
- else if (token.type == TT_PUNCTUATION && *token.string == '<')
- {
- strcpy(path, source->includepath);
- while(PC_ReadSourceToken(source, &token))
- {
- if (token.linescrossed > 0)
- {
- PC_UnreadSourceToken(source, &token);
- break;
- } //end if
- if (token.type == TT_PUNCTUATION && *token.string == '>') break;
- strncat(path, token.string, MAX_PATH - 1);
- } //end while
- if (*token.string != '>')
- {
- SourceWarning(source, "#include missing trailing >");
- } //end if
- if (!strlen(path))
- {
- SourceError(source, "#include without file name between < >");
- return qfalse;
- } //end if
- PC_ConvertPath(path);
- script = LoadScriptFile(path);
- } //end if
- else
- {
- SourceError(source, "#include without file name");
- return qfalse;
- } //end else
-#ifdef QUAKE
- if (!script)
- {
- Com_Memset(&file, 0, sizeof(foundfile_t));
- script = LoadScriptFile(path);
- if (script) strncpy(script->filename, path, MAX_PATH);
- } //end if
-#endif //QUAKE
- if (!script)
- {
-#ifdef SCREWUP
- SourceWarning(source, "file %s not found", path);
- return qtrue;
-#else
- SourceError(source, "file %s not found", path);
- return qfalse;
-#endif //SCREWUP
- } //end if
- PC_PushScript(source, script);
- return qtrue;
-} //end of the function PC_Directive_include
-//============================================================================
-// reads a token from the current line, continues reading on the next
-// line only if a backslash '\' is encountered.
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_ReadLine(source_t *source, token_t *token)
-{
- int crossline;
-
- crossline = 0;
- do
- {
- if (!PC_ReadSourceToken(source, token)) return qfalse;
-
- if (token->linescrossed > crossline)
- {
- PC_UnreadSourceToken(source, token);
- return qfalse;
- } //end if
- crossline = 1;
- } while(!strcmp(token->string, "\\"));
- return qtrue;
-} //end of the function PC_ReadLine
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_WhiteSpaceBeforeToken(token_t *token)
-{
- return token->endwhitespace_p - token->whitespace_p > 0;
-} //end of the function PC_WhiteSpaceBeforeToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_ClearTokenWhiteSpace(token_t *token)
-{
- token->whitespace_p = NULL;
- token->endwhitespace_p = NULL;
- token->linescrossed = 0;
-} //end of the function PC_ClearTokenWhiteSpace
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_undef(source_t *source)
-{
- token_t token;
- define_t *define, *lastdefine;
- int hash;
-
- if (source->skip > 0) return qtrue;
- //
- if (!PC_ReadLine(source, &token))
- {
- SourceError(source, "undef without name");
- return qfalse;
- } //end if
- if (token.type != TT_NAME)
- {
- PC_UnreadSourceToken(source, &token);
- SourceError(source, "expected name, found %s", token.string);
- return qfalse;
- } //end if
-#if DEFINEHASHING
-
- hash = PC_NameHash(token.string);
- for (lastdefine = NULL, define = source->definehash[hash]; define; define = define->hashnext)
- {
- if (!strcmp(define->name, token.string))
- {
- if (define->flags & DEFINE_FIXED)
- {
- SourceWarning(source, "can't undef %s", token.string);
- } //end if
- else
- {
- if (lastdefine) lastdefine->hashnext = define->hashnext;
- else source->definehash[hash] = define->hashnext;
- PC_FreeDefine(define);
- } //end else
- break;
- } //end if
- lastdefine = define;
- } //end for
-#else //DEFINEHASHING
- for (lastdefine = NULL, define = source->defines; define; define = define->next)
- {
- if (!strcmp(define->name, token.string))
- {
- if (define->flags & DEFINE_FIXED)
- {
- SourceWarning(source, "can't undef %s", token.string);
- } //end if
- else
- {
- if (lastdefine) lastdefine->next = define->next;
- else source->defines = define->next;
- PC_FreeDefine(define);
- } //end else
- break;
- } //end if
- lastdefine = define;
- } //end for
-#endif //DEFINEHASHING
- return qtrue;
-} //end of the function PC_Directive_undef
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_define(source_t *source)
-{
- token_t token, *t, *last;
- define_t *define;
-
- if (source->skip > 0) return qtrue;
- //
- if (!PC_ReadLine(source, &token))
- {
- SourceError(source, "#define without name");
- return qfalse;
- } //end if
- if (token.type != TT_NAME)
- {
- PC_UnreadSourceToken(source, &token);
- SourceError(source, "expected name after #define, found %s", token.string);
- return qfalse;
- } //end if
- //check if the define already exists
-#if DEFINEHASHING
- define = PC_FindHashedDefine(source->definehash, token.string);
-#else
- define = PC_FindDefine(source->defines, token.string);
-#endif //DEFINEHASHING
- if (define)
- {
- if (define->flags & DEFINE_FIXED)
- {
- SourceError(source, "can't redefine %s", token.string);
- return qfalse;
- } //end if
- SourceWarning(source, "redefinition of %s", token.string);
- //unread the define name before executing the #undef directive
- PC_UnreadSourceToken(source, &token);
- if (!PC_Directive_undef(source)) return qfalse;
- //if the define was not removed (define->flags & DEFINE_FIXED)
-#if DEFINEHASHING
- define = PC_FindHashedDefine(source->definehash, token.string);
-#else
- define = PC_FindDefine(source->defines, token.string);
-#endif //DEFINEHASHING
- } //end if
- //allocate define
- define = (define_t *) GetMemory(sizeof(define_t));
- Com_Memset(define, 0, sizeof(define_t));
- define->name = (char *) GetMemory(strlen(token.string) + 1);
- strcpy(define->name, token.string);
- //add the define to the source
-#if DEFINEHASHING
- PC_AddDefineToHash(define, source->definehash);
-#else //DEFINEHASHING
- define->next = source->defines;
- source->defines = define;
-#endif //DEFINEHASHING
- //if nothing is defined, just return
- if (!PC_ReadLine(source, &token)) return qtrue;
- //if it is a define with parameters
- if (!PC_WhiteSpaceBeforeToken(&token) && !strcmp(token.string, "("))
- {
- //read the define parameters
- last = NULL;
- if (!PC_CheckTokenString(source, ")"))
- {
- while(1)
- {
- if (!PC_ReadLine(source, &token))
- {
- SourceError(source, "expected define parameter");
- return qfalse;
- } //end if
- //if it isn't a name
- if (token.type != TT_NAME)
- {
- SourceError(source, "invalid define parameter");
- return qfalse;
- } //end if
- //
- if (PC_FindDefineParm(define, token.string) >= 0)
- {
- SourceError(source, "two the same define parameters");
- return qfalse;
- } //end if
- //add the define parm
- t = PC_CopyToken(&token);
- PC_ClearTokenWhiteSpace(t);
- t->next = NULL;
- if (last) last->next = t;
- else define->parms = t;
- last = t;
- define->numparms++;
- //read next token
- if (!PC_ReadLine(source, &token))
- {
- SourceError(source, "define parameters not terminated");
- return qfalse;
- } //end if
- //
- if (!strcmp(token.string, ")")) break;
- //then it must be a comma
- if (strcmp(token.string, ","))
- {
- SourceError(source, "define not terminated");
- return qfalse;
- } //end if
- } //end while
- } //end if
- if (!PC_ReadLine(source, &token)) return qtrue;
- } //end if
- //read the defined stuff
- last = NULL;
- do
- {
- t = PC_CopyToken(&token);
- if (t->type == TT_NAME && !strcmp(t->string, define->name))
- {
- SourceError(source, "recursive define (removed recursion)");
- continue;
- } //end if
- PC_ClearTokenWhiteSpace(t);
- t->next = NULL;
- if (last) last->next = t;
- else define->tokens = t;
- last = t;
- } while(PC_ReadLine(source, &token));
- //
- if (last)
- {
- //check for merge operators at the beginning or end
- if (!strcmp(define->tokens->string, "##") ||
- !strcmp(last->string, "##"))
- {
- SourceError(source, "define with misplaced ##");
- return qfalse;
- } //end if
- } //end if
- return qtrue;
-} //end of the function PC_Directive_define
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-define_t *PC_DefineFromString(char *string)
-{
- script_t *script;
- source_t src;
- token_t *t;
- int res, i;
- define_t *def;
-
- PC_InitTokenHeap();
-
- script = LoadScriptMemory(string, strlen(string), "*extern");
- //create a new source
- Com_Memset(&src, 0, sizeof(source_t));
- strncpy(src.filename, "*extern", MAX_PATH);
- src.scriptstack = script;
-#if DEFINEHASHING
- src.definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));
-#endif //DEFINEHASHING
- //create a define from the source
- res = PC_Directive_define(&src);
- //free any tokens if left
- for (t = src.tokens; t; t = src.tokens)
- {
- src.tokens = src.tokens->next;
- PC_FreeToken(t);
- } //end for
-#ifdef DEFINEHASHING
- def = NULL;
- for (i = 0; i < DEFINEHASHSIZE; i++)
- {
- if (src.definehash[i])
- {
- def = src.definehash[i];
- break;
- } //end if
- } //end for
-#else
- def = src.defines;
-#endif //DEFINEHASHING
- //
-#if DEFINEHASHING
- FreeMemory(src.definehash);
-#endif //DEFINEHASHING
- //
- FreeScript(script);
- //if the define was created succesfully
- if (res > 0) return def;
- //free the define is created
- if (src.defines) PC_FreeDefine(def);
- //
- return NULL;
-} //end of the function PC_DefineFromString
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_AddDefine(source_t *source, char *string)
-{
- define_t *define;
-
- define = PC_DefineFromString(string);
- if (!define) return qfalse;
-#if DEFINEHASHING
- PC_AddDefineToHash(define, source->definehash);
-#else //DEFINEHASHING
- define->next = source->defines;
- source->defines = define;
-#endif //DEFINEHASHING
- return qtrue;
-} //end of the function PC_AddDefine
-//============================================================================
-// add a globals define that will be added to all opened sources
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_AddGlobalDefine(char *string)
-{
- define_t *define;
-
- define = PC_DefineFromString(string);
- if (!define) return qfalse;
- define->next = globaldefines;
- globaldefines = define;
- return qtrue;
-} //end of the function PC_AddGlobalDefine
-//============================================================================
-// remove the given global define
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_RemoveGlobalDefine(char *name)
-{
- define_t *define;
-
- define = PC_FindDefine(globaldefines, name);
- if (define)
- {
- PC_FreeDefine(define);
- return qtrue;
- } //end if
- return qfalse;
-} //end of the function PC_RemoveGlobalDefine
-//============================================================================
-// remove all globals defines
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_RemoveAllGlobalDefines(void)
-{
- define_t *define;
-
- for (define = globaldefines; define; define = globaldefines)
- {
- globaldefines = globaldefines->next;
- PC_FreeDefine(define);
- } //end for
-} //end of the function PC_RemoveAllGlobalDefines
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-define_t *PC_CopyDefine(source_t *source, define_t *define)
-{
- define_t *newdefine;
- token_t *token, *newtoken, *lasttoken;
-
- newdefine = (define_t *) GetMemory(sizeof(define_t));
- //copy the define name
- newdefine->name = (char *) GetMemory(strlen(define->name) + 1);
- strcpy(newdefine->name, define->name);
- newdefine->flags = define->flags;
- newdefine->builtin = define->builtin;
- newdefine->numparms = define->numparms;
- //the define is not linked
- newdefine->next = NULL;
- newdefine->hashnext = NULL;
- //copy the define tokens
- newdefine->tokens = NULL;
- for (lasttoken = NULL, token = define->tokens; token; token = token->next)
- {
- newtoken = PC_CopyToken(token);
- newtoken->next = NULL;
- if (lasttoken) lasttoken->next = newtoken;
- else newdefine->tokens = newtoken;
- lasttoken = newtoken;
- } //end for
- //copy the define parameters
- newdefine->parms = NULL;
- for (lasttoken = NULL, token = define->parms; token; token = token->next)
- {
- newtoken = PC_CopyToken(token);
- newtoken->next = NULL;
- if (lasttoken) lasttoken->next = newtoken;
- else newdefine->parms = newtoken;
- lasttoken = newtoken;
- } //end for
- return newdefine;
-} //end of the function PC_CopyDefine
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_AddGlobalDefinesToSource(source_t *source)
-{
- define_t *define, *newdefine;
-
- for (define = globaldefines; define; define = define->next)
- {
- newdefine = PC_CopyDefine(source, define);
-#if DEFINEHASHING
- PC_AddDefineToHash(newdefine, source->definehash);
-#else //DEFINEHASHING
- newdefine->next = source->defines;
- source->defines = newdefine;
-#endif //DEFINEHASHING
- } //end for
-} //end of the function PC_AddGlobalDefinesToSource
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_if_def(source_t *source, int type)
-{
- token_t token;
- define_t *d;
- int skip;
-
- if (!PC_ReadLine(source, &token))
- {
- SourceError(source, "#ifdef without name");
- return qfalse;
- } //end if
- if (token.type != TT_NAME)
- {
- PC_UnreadSourceToken(source, &token);
- SourceError(source, "expected name after #ifdef, found %s", token.string);
- return qfalse;
- } //end if
-#if DEFINEHASHING
- d = PC_FindHashedDefine(source->definehash, token.string);
-#else
- d = PC_FindDefine(source->defines, token.string);
-#endif //DEFINEHASHING
- skip = (type == INDENT_IFDEF) == (d == NULL);
- PC_PushIndent(source, type, skip);
- return qtrue;
-} //end of the function PC_Directiveif_def
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_ifdef(source_t *source)
-{
- return PC_Directive_if_def(source, INDENT_IFDEF);
-} //end of the function PC_Directive_ifdef
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_ifndef(source_t *source)
-{
- return PC_Directive_if_def(source, INDENT_IFNDEF);
-} //end of the function PC_Directive_ifndef
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_else(source_t *source)
-{
- int type, skip;
-
- PC_PopIndent(source, &type, &skip);
- if (!type)
- {
- SourceError(source, "misplaced #else");
- return qfalse;
- } //end if
- if (type == INDENT_ELSE)
- {
- SourceError(source, "#else after #else");
- return qfalse;
- } //end if
- PC_PushIndent(source, INDENT_ELSE, !skip);
- return qtrue;
-} //end of the function PC_Directive_else
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_endif(source_t *source)
-{
- int type, skip;
-
- PC_PopIndent(source, &type, &skip);
- if (!type)
- {
- SourceError(source, "misplaced #endif");
- return qfalse;
- } //end if
- return qtrue;
-} //end of the function PC_Directive_endif
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-typedef struct operator_s
-{
- int operator;
- int priority;
- int parentheses;
- struct operator_s *prev, *next;
-} operator_t;
-
-typedef struct value_s
-{
- signed long int intvalue;
- float floatvalue;
- int parentheses;
- struct value_s *prev, *next;
-} value_t;
-
-int PC_OperatorPriority(int op)
-{
- switch(op)
- {
- case P_MUL: return 15;
- case P_DIV: return 15;
- case P_MOD: return 15;
- case P_ADD: return 14;
- case P_SUB: return 14;
-
- case P_LOGIC_AND: return 7;
- case P_LOGIC_OR: return 6;
- case P_LOGIC_GEQ: return 12;
- case P_LOGIC_LEQ: return 12;
- case P_LOGIC_EQ: return 11;
- case P_LOGIC_UNEQ: return 11;
-
- case P_LOGIC_NOT: return 16;
- case P_LOGIC_GREATER: return 12;
- case P_LOGIC_LESS: return 12;
-
- case P_RSHIFT: return 13;
- case P_LSHIFT: return 13;
-
- case P_BIN_AND: return 10;
- case P_BIN_OR: return 8;
- case P_BIN_XOR: return 9;
- case P_BIN_NOT: return 16;
-
- case P_COLON: return 5;
- case P_QUESTIONMARK: return 5;
- } //end switch
- return qfalse;
-} //end of the function PC_OperatorPriority
-
-//#define AllocValue() GetClearedMemory(sizeof(value_t));
-//#define FreeValue(val) FreeMemory(val)
-//#define AllocOperator(op) op = (operator_t *) GetClearedMemory(sizeof(operator_t));
-//#define FreeOperator(op) FreeMemory(op);
-
-#define MAX_VALUES 64
-#define MAX_OPERATORS 64
-#define AllocValue(val) \
- if (numvalues >= MAX_VALUES) { \
- SourceError(source, "out of value space\n"); \
- error = 1; \
- break; \
- } \
- else \
- val = &value_heap[numvalues++];
-#define FreeValue(val)
-//
-#define AllocOperator(op) \
- if (numoperators >= MAX_OPERATORS) { \
- SourceError(source, "out of operator space\n"); \
- error = 1; \
- break; \
- } \
- else \
- op = &operator_heap[numoperators++];
-#define FreeOperator(op)
-
-int PC_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intvalue,
- float *floatvalue, int integer)
-{
- operator_t *o, *firstoperator, *lastoperator;
- value_t *v, *firstvalue, *lastvalue, *v1, *v2;
- token_t *t;
- int brace = 0;
- int parentheses = 0;
- int error = 0;
- int lastwasvalue = 0;
- int negativevalue = 0;
- int questmarkintvalue = 0;
- float questmarkfloatvalue = 0;
- int gotquestmarkvalue = qfalse;
- int lastoperatortype = 0;
- //
- operator_t operator_heap[MAX_OPERATORS];
- int numoperators = 0;
- value_t value_heap[MAX_VALUES];
- int numvalues = 0;
-
- firstoperator = lastoperator = NULL;
- firstvalue = lastvalue = NULL;
- if (intvalue) *intvalue = 0;
- if (floatvalue) *floatvalue = 0;
- for (t = tokens; t; t = t->next)
- {
- switch(t->type)
- {
- case TT_NAME:
- {
- if (lastwasvalue || negativevalue)
- {
- SourceError(source, "syntax error in #if/#elif");
- error = 1;
- break;
- } //end if
- if (strcmp(t->string, "defined"))
- {
- SourceError(source, "undefined name %s in #if/#elif", t->string);
- error = 1;
- break;
- } //end if
- t = t->next;
- if (!strcmp(t->string, "("))
- {
- brace = qtrue;
- t = t->next;
- } //end if
- if (!t || t->type != TT_NAME)
- {
- SourceError(source, "defined without name in #if/#elif");
- error = 1;
- break;
- } //end if
- //v = (value_t *) GetClearedMemory(sizeof(value_t));
- AllocValue(v);
-#if DEFINEHASHING
- if (PC_FindHashedDefine(source->definehash, t->string))
-#else
- if (PC_FindDefine(source->defines, t->string))
-#endif //DEFINEHASHING
- {
- v->intvalue = 1;
- v->floatvalue = 1;
- } //end if
- else
- {
- v->intvalue = 0;
- v->floatvalue = 0;
- } //end else
- v->parentheses = parentheses;
- v->next = NULL;
- v->prev = lastvalue;
- if (lastvalue) lastvalue->next = v;
- else firstvalue = v;
- lastvalue = v;
- if (brace)
- {
- t = t->next;
- if (!t || strcmp(t->string, ")"))
- {
- SourceError(source, "defined without ) in #if/#elif");
- error = 1;
- break;
- } //end if
- } //end if
- brace = qfalse;
- // defined() creates a value
- lastwasvalue = 1;
- break;
- } //end case
- case TT_NUMBER:
- {
- if (lastwasvalue)
- {
- SourceError(source, "syntax error in #if/#elif");
- error = 1;
- break;
- } //end if
- //v = (value_t *) GetClearedMemory(sizeof(value_t));
- AllocValue(v);
- if (negativevalue)
- {
- v->intvalue = - (signed int) t->intvalue;
- v->floatvalue = - t->floatvalue;
- } //end if
- else
- {
- v->intvalue = t->intvalue;
- v->floatvalue = t->floatvalue;
- } //end else
- v->parentheses = parentheses;
- v->next = NULL;
- v->prev = lastvalue;
- if (lastvalue) lastvalue->next = v;
- else firstvalue = v;
- lastvalue = v;
- //last token was a value
- lastwasvalue = 1;
- //
- negativevalue = 0;
- break;
- } //end case
- case TT_PUNCTUATION:
- {
- if (negativevalue)
- {
- SourceError(source, "misplaced minus sign in #if/#elif");
- error = 1;
- break;
- } //end if
- if (t->subtype == P_PARENTHESESOPEN)
- {
- parentheses++;
- break;
- } //end if
- else if (t->subtype == P_PARENTHESESCLOSE)
- {
- parentheses--;
- if (parentheses < 0)
- {
- SourceError(source, "too many ) in #if/#elsif");
- error = 1;
- } //end if
- break;
- } //end else if
- //check for invalid operators on floating point values
- if (!integer)
- {
- if (t->subtype == P_BIN_NOT || t->subtype == P_MOD ||
- t->subtype == P_RSHIFT || t->subtype == P_LSHIFT ||
- t->subtype == P_BIN_AND || t->subtype == P_BIN_OR ||
- t->subtype == P_BIN_XOR)
- {
- SourceError(source, "illigal operator %s on floating point operands\n", t->string);
- error = 1;
- break;
- } //end if
- } //end if
- switch(t->subtype)
- {
- case P_LOGIC_NOT:
- case P_BIN_NOT:
- {
- if (lastwasvalue)
- {
- SourceError(source, "! or ~ after value in #if/#elif");
- error = 1;
- break;
- } //end if
- break;
- } //end case
- case P_INC:
- case P_DEC:
- {
- SourceError(source, "++ or -- used in #if/#elif");
- break;
- } //end case
- case P_SUB:
- {
- if (!lastwasvalue)
- {
- negativevalue = 1;
- break;
- } //end if
- } //end case
-
- case P_MUL:
- case P_DIV:
- case P_MOD:
- case P_ADD:
-
- case P_LOGIC_AND:
- case P_LOGIC_OR:
- case P_LOGIC_GEQ:
- case P_LOGIC_LEQ:
- case P_LOGIC_EQ:
- case P_LOGIC_UNEQ:
-
- case P_LOGIC_GREATER:
- case P_LOGIC_LESS:
-
- case P_RSHIFT:
- case P_LSHIFT:
-
- case P_BIN_AND:
- case P_BIN_OR:
- case P_BIN_XOR:
-
- case P_COLON:
- case P_QUESTIONMARK:
- {
- if (!lastwasvalue)
- {
- SourceError(source, "operator %s after operator in #if/#elif", t->string);
- error = 1;
- break;
- } //end if
- break;
- } //end case
- default:
- {
- SourceError(source, "invalid operator %s in #if/#elif", t->string);
- error = 1;
- break;
- } //end default
- } //end switch
- if (!error && !negativevalue)
- {
- //o = (operator_t *) GetClearedMemory(sizeof(operator_t));
- AllocOperator(o);
- o->operator = t->subtype;
- o->priority = PC_OperatorPriority(t->subtype);
- o->parentheses = parentheses;
- o->next = NULL;
- o->prev = lastoperator;
- if (lastoperator) lastoperator->next = o;
- else firstoperator = o;
- lastoperator = o;
- lastwasvalue = 0;
- } //end if
- break;
- } //end case
- default:
- {
- SourceError(source, "unknown %s in #if/#elif", t->string);
- error = 1;
- break;
- } //end default
- } //end switch
- if (error) break;
- } //end for
- if (!error)
- {
- if (!lastwasvalue)
- {
- SourceError(source, "trailing operator in #if/#elif");
- error = 1;
- } //end if
- else if (parentheses)
- {
- SourceError(source, "too many ( in #if/#elif");
- error = 1;
- } //end else if
- } //end if
- //
- gotquestmarkvalue = qfalse;
- questmarkintvalue = 0;
- questmarkfloatvalue = 0;
- //while there are operators
- while(!error && firstoperator)
- {
- v = firstvalue;
- for (o = firstoperator; o->next; o = o->next)
- {
- //if the current operator is nested deeper in parentheses
- //than the next operator
- if (o->parentheses > o->next->parentheses) break;
- //if the current and next operator are nested equally deep in parentheses
- if (o->parentheses == o->next->parentheses)
- {
- //if the priority of the current operator is equal or higher
- //than the priority of the next operator
- if (o->priority >= o->next->priority) break;
- } //end if
- //if the arity of the operator isn't equal to 1
- if (o->operator != P_LOGIC_NOT
- && o->operator != P_BIN_NOT) v = v->next;
- //if there's no value or no next value
- if (!v)
- {
- SourceError(source, "mising values in #if/#elif");
- error = 1;
- break;
- } //end if
- } //end for
- if (error) break;
- v1 = v;
- v2 = v->next;
-#ifdef DEBUG_EVAL
- if (integer)
- {
- Log_Write("operator %s, value1 = %d", PunctuationFromNum(source->scriptstack, o->operator), v1->intvalue);
- if (v2) Log_Write("value2 = %d", v2->intvalue);
- } //end if
- else
- {
- Log_Write("operator %s, value1 = %f", PunctuationFromNum(source->scriptstack, o->operator), v1->floatvalue);
- if (v2) Log_Write("value2 = %f", v2->floatvalue);
- } //end else
-#endif //DEBUG_EVAL
- switch(o->operator)
- {
- case P_LOGIC_NOT: v1->intvalue = !v1->intvalue;
- v1->floatvalue = !v1->floatvalue; break;
- case P_BIN_NOT: v1->intvalue = ~v1->intvalue;
- break;
- case P_MUL: v1->intvalue *= v2->intvalue;
- v1->floatvalue *= v2->floatvalue; break;
- case P_DIV: if (!v2->intvalue || !v2->floatvalue)
- {
- SourceError(source, "divide by zero in #if/#elif\n");
- error = 1;
- break;
- }
- v1->intvalue /= v2->intvalue;
- v1->floatvalue /= v2->floatvalue; break;
- case P_MOD: if (!v2->intvalue)
- {
- SourceError(source, "divide by zero in #if/#elif\n");
- error = 1;
- break;
- }
- v1->intvalue %= v2->intvalue; break;
- case P_ADD: v1->intvalue += v2->intvalue;
- v1->floatvalue += v2->floatvalue; break;
- case P_SUB: v1->intvalue -= v2->intvalue;
- v1->floatvalue -= v2->floatvalue; break;
- case P_LOGIC_AND: v1->intvalue = v1->intvalue && v2->intvalue;
- v1->floatvalue = v1->floatvalue && v2->floatvalue; break;
- case P_LOGIC_OR: v1->intvalue = v1->intvalue || v2->intvalue;
- v1->floatvalue = v1->floatvalue || v2->floatvalue; break;
- case P_LOGIC_GEQ: v1->intvalue = v1->intvalue >= v2->intvalue;
- v1->floatvalue = v1->floatvalue >= v2->floatvalue; break;
- case P_LOGIC_LEQ: v1->intvalue = v1->intvalue <= v2->intvalue;
- v1->floatvalue = v1->floatvalue <= v2->floatvalue; break;
- case P_LOGIC_EQ: v1->intvalue = v1->intvalue == v2->intvalue;
- v1->floatvalue = v1->floatvalue == v2->floatvalue; break;
- case P_LOGIC_UNEQ: v1->intvalue = v1->intvalue != v2->intvalue;
- v1->floatvalue = v1->floatvalue != v2->floatvalue; break;
- case P_LOGIC_GREATER: v1->intvalue = v1->intvalue > v2->intvalue;
- v1->floatvalue = v1->floatvalue > v2->floatvalue; break;
- case P_LOGIC_LESS: v1->intvalue = v1->intvalue < v2->intvalue;
- v1->floatvalue = v1->floatvalue < v2->floatvalue; break;
- case P_RSHIFT: v1->intvalue >>= v2->intvalue;
- break;
- case P_LSHIFT: v1->intvalue <<= v2->intvalue;
- break;
- case P_BIN_AND: v1->intvalue &= v2->intvalue;
- break;
- case P_BIN_OR: v1->intvalue |= v2->intvalue;
- break;
- case P_BIN_XOR: v1->intvalue ^= v2->intvalue;
- break;
- case P_COLON:
- {
- if (!gotquestmarkvalue)
- {
- SourceError(source, ": without ? in #if/#elif");
- error = 1;
- break;
- } //end if
- if (integer)
- {
- if (!questmarkintvalue) v1->intvalue = v2->intvalue;
- } //end if
- else
- {
- if (!questmarkfloatvalue) v1->floatvalue = v2->floatvalue;
- } //end else
- gotquestmarkvalue = qfalse;
- break;
- } //end case
- case P_QUESTIONMARK:
- {
- if (gotquestmarkvalue)
- {
- SourceError(source, "? after ? in #if/#elif");
- error = 1;
- break;
- } //end if
- questmarkintvalue = v1->intvalue;
- questmarkfloatvalue = v1->floatvalue;
- gotquestmarkvalue = qtrue;
- break;
- } //end if
- } //end switch
-#ifdef DEBUG_EVAL
- if (integer) Log_Write("result value = %d", v1->intvalue);
- else Log_Write("result value = %f", v1->floatvalue);
-#endif //DEBUG_EVAL
- if (error) break;
- lastoperatortype = o->operator;
- //if not an operator with arity 1
- if (o->operator != P_LOGIC_NOT
- && o->operator != P_BIN_NOT)
- {
- //remove the second value if not question mark operator
- if (o->operator != P_QUESTIONMARK) v = v->next;
- //
- if (v->prev) v->prev->next = v->next;
- else firstvalue = v->next;
- if (v->next) v->next->prev = v->prev;
- else lastvalue = v->prev;
- //FreeMemory(v);
- FreeValue(v);
- } //end if
- //remove the operator
- if (o->prev) o->prev->next = o->next;
- else firstoperator = o->next;
- if (o->next) o->next->prev = o->prev;
- else lastoperator = o->prev;
- //FreeMemory(o);
- FreeOperator(o);
- } //end while
- if (firstvalue)
- {
- if (intvalue) *intvalue = firstvalue->intvalue;
- if (floatvalue) *floatvalue = firstvalue->floatvalue;
- } //end if
- for (o = firstoperator; o; o = lastoperator)
- {
- lastoperator = o->next;
- //FreeMemory(o);
- FreeOperator(o);
- } //end for
- for (v = firstvalue; v; v = lastvalue)
- {
- lastvalue = v->next;
- //FreeMemory(v);
- FreeValue(v);
- } //end for
- if (!error) return qtrue;
- if (intvalue) *intvalue = 0;
- if (floatvalue) *floatvalue = 0;
- return qfalse;
-} //end of the function PC_EvaluateTokens
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Evaluate(source_t *source, signed long int *intvalue,
- float *floatvalue, int integer)
-{
- token_t token, *firsttoken, *lasttoken;
- token_t *t, *nexttoken;
- define_t *define;
- int defined = qfalse;
-
- if (intvalue) *intvalue = 0;
- if (floatvalue) *floatvalue = 0;
- //
- if (!PC_ReadLine(source, &token))
- {
- SourceError(source, "no value after #if/#elif");
- return qfalse;
- } //end if
- firsttoken = NULL;
- lasttoken = NULL;
- do
- {
- //if the token is a name
- if (token.type == TT_NAME)
- {
- if (defined)
- {
- defined = qfalse;
- t = PC_CopyToken(&token);
- t->next = NULL;
- if (lasttoken) lasttoken->next = t;
- else firsttoken = t;
- lasttoken = t;
- } //end if
- else if (!strcmp(token.string, "defined"))
- {
- defined = qtrue;
- t = PC_CopyToken(&token);
- t->next = NULL;
- if (lasttoken) lasttoken->next = t;
- else firsttoken = t;
- lasttoken = t;
- } //end if
- else
- {
- //then it must be a define
-#if DEFINEHASHING
- define = PC_FindHashedDefine(source->definehash, token.string);
-#else
- define = PC_FindDefine(source->defines, token.string);
-#endif //DEFINEHASHING
- if (!define)
- {
- SourceError(source, "can't evaluate %s, not defined", token.string);
- return qfalse;
- } //end if
- if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse;
- } //end else
- } //end if
- //if the token is a number or a punctuation
- else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION)
- {
- t = PC_CopyToken(&token);
- t->next = NULL;
- if (lasttoken) lasttoken->next = t;
- else firsttoken = t;
- lasttoken = t;
- } //end else
- else //can't evaluate the token
- {
- SourceError(source, "can't evaluate %s", token.string);
- return qfalse;
- } //end else
- } while(PC_ReadLine(source, &token));
- //
- if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse;
- //
-#ifdef DEBUG_EVAL
- Log_Write("eval:");
-#endif //DEBUG_EVAL
- for (t = firsttoken; t; t = nexttoken)
- {
-#ifdef DEBUG_EVAL
- Log_Write(" %s", t->string);
-#endif //DEBUG_EVAL
- nexttoken = t->next;
- PC_FreeToken(t);
- } //end for
-#ifdef DEBUG_EVAL
- if (integer) Log_Write("eval result: %d", *intvalue);
- else Log_Write("eval result: %f", *floatvalue);
-#endif //DEBUG_EVAL
- //
- return qtrue;
-} //end of the function PC_Evaluate
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_DollarEvaluate(source_t *source, signed long int *intvalue,
- float *floatvalue, int integer)
-{
- int indent, defined = qfalse;
- token_t token, *firsttoken, *lasttoken;
- token_t *t, *nexttoken;
- define_t *define;
-
- if (intvalue) *intvalue = 0;
- if (floatvalue) *floatvalue = 0;
- //
- if (!PC_ReadSourceToken(source, &token))
- {
- SourceError(source, "no leading ( after $evalint/$evalfloat");
- return qfalse;
- } //end if
- if (!PC_ReadSourceToken(source, &token))
- {
- SourceError(source, "nothing to evaluate");
- return qfalse;
- } //end if
- indent = 1;
- firsttoken = NULL;
- lasttoken = NULL;
- do
- {
- //if the token is a name
- if (token.type == TT_NAME)
- {
- if (defined)
- {
- defined = qfalse;
- t = PC_CopyToken(&token);
- t->next = NULL;
- if (lasttoken) lasttoken->next = t;
- else firsttoken = t;
- lasttoken = t;
- } //end if
- else if (!strcmp(token.string, "defined"))
- {
- defined = qtrue;
- t = PC_CopyToken(&token);
- t->next = NULL;
- if (lasttoken) lasttoken->next = t;
- else firsttoken = t;
- lasttoken = t;
- } //end if
- else
- {
- //then it must be a define
-#if DEFINEHASHING
- define = PC_FindHashedDefine(source->definehash, token.string);
-#else
- define = PC_FindDefine(source->defines, token.string);
-#endif //DEFINEHASHING
- if (!define)
- {
- SourceError(source, "can't evaluate %s, not defined", token.string);
- return qfalse;
- } //end if
- if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse;
- } //end else
- } //end if
- //if the token is a number or a punctuation
- else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION)
- {
- if (*token.string == '(') indent++;
- else if (*token.string == ')') indent--;
- if (indent <= 0) break;
- t = PC_CopyToken(&token);
- t->next = NULL;
- if (lasttoken) lasttoken->next = t;
- else firsttoken = t;
- lasttoken = t;
- } //end else
- else //can't evaluate the token
- {
- SourceError(source, "can't evaluate %s", token.string);
- return qfalse;
- } //end else
- } while(PC_ReadSourceToken(source, &token));
- //
- if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse;
- //
-#ifdef DEBUG_EVAL
- Log_Write("$eval:");
-#endif //DEBUG_EVAL
- for (t = firsttoken; t; t = nexttoken)
- {
-#ifdef DEBUG_EVAL
- Log_Write(" %s", t->string);
-#endif //DEBUG_EVAL
- nexttoken = t->next;
- PC_FreeToken(t);
- } //end for
-#ifdef DEBUG_EVAL
- if (integer) Log_Write("$eval result: %d", *intvalue);
- else Log_Write("$eval result: %f", *floatvalue);
-#endif //DEBUG_EVAL
- //
- return qtrue;
-} //end of the function PC_DollarEvaluate
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_elif(source_t *source)
-{
- signed long int value;
- int type, skip;
-
- PC_PopIndent(source, &type, &skip);
- if (!type || type == INDENT_ELSE)
- {
- SourceError(source, "misplaced #elif");
- return qfalse;
- } //end if
- if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;
- skip = (value == 0);
- PC_PushIndent(source, INDENT_ELIF, skip);
- return qtrue;
-} //end of the function PC_Directive_elif
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_if(source_t *source)
-{
- signed long int value;
- int skip;
-
- if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;
- skip = (value == 0);
- PC_PushIndent(source, INDENT_IF, skip);
- return qtrue;
-} //end of the function PC_Directive
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_line(source_t *source)
-{
- SourceError(source, "#line directive not supported");
- return qfalse;
-} //end of the function PC_Directive_line
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_error(source_t *source)
-{
- token_t token;
-
- strcpy(token.string, "");
- PC_ReadSourceToken(source, &token);
- SourceError(source, "#error directive: %s", token.string);
- return qfalse;
-} //end of the function PC_Directive_error
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_pragma(source_t *source)
-{
- token_t token;
-
- SourceWarning(source, "#pragma directive not supported");
- while(PC_ReadLine(source, &token)) ;
- return qtrue;
-} //end of the function PC_Directive_pragma
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void UnreadSignToken(source_t *source)
-{
- token_t token;
-
- token.line = source->scriptstack->line;
- token.whitespace_p = source->scriptstack->script_p;
- token.endwhitespace_p = source->scriptstack->script_p;
- token.linescrossed = 0;
- strcpy(token.string, "-");
- token.type = TT_PUNCTUATION;
- token.subtype = P_SUB;
- PC_UnreadSourceToken(source, &token);
-} //end of the function UnreadSignToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_eval(source_t *source)
-{
- signed long int value;
- token_t token;
-
- if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;
- //
- token.line = source->scriptstack->line;
- token.whitespace_p = source->scriptstack->script_p;
- token.endwhitespace_p = source->scriptstack->script_p;
- token.linescrossed = 0;
- sprintf(token.string, "%d", abs(value));
- token.type = TT_NUMBER;
- token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;
- PC_UnreadSourceToken(source, &token);
- if (value < 0) UnreadSignToken(source);
- return qtrue;
-} //end of the function PC_Directive_eval
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_Directive_evalfloat(source_t *source)
-{
- float value;
- token_t token;
-
- if (!PC_Evaluate(source, NULL, &value, qfalse)) return qfalse;
- token.line = source->scriptstack->line;
- token.whitespace_p = source->scriptstack->script_p;
- token.endwhitespace_p = source->scriptstack->script_p;
- token.linescrossed = 0;
- sprintf(token.string, "%1.2f", fabs(value));
- token.type = TT_NUMBER;
- token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;
- PC_UnreadSourceToken(source, &token);
- if (value < 0) UnreadSignToken(source);
- return qtrue;
-} //end of the function PC_Directive_evalfloat
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-directive_t directives[20] =
-{
- {"if", PC_Directive_if},
- {"ifdef", PC_Directive_ifdef},
- {"ifndef", PC_Directive_ifndef},
- {"elif", PC_Directive_elif},
- {"else", PC_Directive_else},
- {"endif", PC_Directive_endif},
- {"include", PC_Directive_include},
- {"define", PC_Directive_define},
- {"undef", PC_Directive_undef},
- {"line", PC_Directive_line},
- {"error", PC_Directive_error},
- {"pragma", PC_Directive_pragma},
- {"eval", PC_Directive_eval},
- {"evalfloat", PC_Directive_evalfloat},
- {NULL, NULL}
-};
-
-int PC_ReadDirective(source_t *source)
-{
- token_t token;
- int i;
-
- //read the directive name
- if (!PC_ReadSourceToken(source, &token))
- {
- SourceError(source, "found # without name");
- return qfalse;
- } //end if
- //directive name must be on the same line
- if (token.linescrossed > 0)
- {
- PC_UnreadSourceToken(source, &token);
- SourceError(source, "found # at end of line");
- return qfalse;
- } //end if
- //if if is a name
- if (token.type == TT_NAME)
- {
- //find the precompiler directive
- for (i = 0; directives[i].name; i++)
- {
- if (!strcmp(directives[i].name, token.string))
- {
- return directives[i].func(source);
- } //end if
- } //end for
- } //end if
- SourceError(source, "unknown precompiler directive %s", token.string);
- return qfalse;
-} //end of the function PC_ReadDirective
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_DollarDirective_evalint(source_t *source)
-{
- signed long int value;
- token_t token;
-
- if (!PC_DollarEvaluate(source, &value, NULL, qtrue)) return qfalse;
- //
- token.line = source->scriptstack->line;
- token.whitespace_p = source->scriptstack->script_p;
- token.endwhitespace_p = source->scriptstack->script_p;
- token.linescrossed = 0;
- sprintf(token.string, "%d", abs(value));
- token.type = TT_NUMBER;
- token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;
-
-#ifdef NUMBERVALUE
- token.intvalue = abs(value);
- token.floatvalue = token.intvalue;
-#endif //NUMBERVALUE
-
- PC_UnreadSourceToken(source, &token);
- if (value < 0)
- UnreadSignToken(source);
-
- return qtrue;
-} //end of the function PC_DollarDirective_evalint
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_DollarDirective_evalfloat(source_t *source)
-{
- float value;
- token_t token;
-
- if (!PC_DollarEvaluate(source, NULL, &value, qfalse)) return qfalse;
- token.line = source->scriptstack->line;
- token.whitespace_p = source->scriptstack->script_p;
- token.endwhitespace_p = source->scriptstack->script_p;
- token.linescrossed = 0;
- sprintf(token.string, "%1.2f", fabs(value));
- token.type = TT_NUMBER;
- token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;
-
-#ifdef NUMBERVALUE
- token.floatvalue = fabs(value);
- token.intvalue = (unsigned long) token.floatvalue;
-#endif //NUMBERVALUE
-
- PC_UnreadSourceToken(source, &token);
- if (value < 0)
- UnreadSignToken(source);
-
- return qtrue;
-} //end of the function PC_DollarDirective_evalfloat
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-directive_t dollardirectives[20] =
-{
- {"evalint", PC_DollarDirective_evalint},
- {"evalfloat", PC_DollarDirective_evalfloat},
- {NULL, NULL}
-};
-
-int PC_ReadDollarDirective(source_t *source)
-{
- token_t token;
- int i;
-
- //read the directive name
- if (!PC_ReadSourceToken(source, &token))
- {
- SourceError(source, "found $ without name");
- return qfalse;
- } //end if
- //directive name must be on the same line
- if (token.linescrossed > 0)
- {
- PC_UnreadSourceToken(source, &token);
- SourceError(source, "found $ at end of line");
- return qfalse;
- } //end if
- //if if is a name
- if (token.type == TT_NAME)
- {
- //find the precompiler directive
- for (i = 0; dollardirectives[i].name; i++)
- {
- if (!strcmp(dollardirectives[i].name, token.string))
- {
- return dollardirectives[i].func(source);
- } //end if
- } //end for
- } //end if
- PC_UnreadSourceToken(source, &token);
- SourceError(source, "unknown precompiler directive %s", token.string);
- return qfalse;
-} //end of the function PC_ReadDirective
-
-#ifdef QUAKEC
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int BuiltinFunction(source_t *source)
-{
- token_t token;
-
- if (!PC_ReadSourceToken(source, &token)) return qfalse;
- if (token.type == TT_NUMBER)
- {
- PC_UnreadSourceToken(source, &token);
- return qtrue;
- } //end if
- else
- {
- PC_UnreadSourceToken(source, &token);
- return qfalse;
- } //end else
-} //end of the function BuiltinFunction
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int QuakeCMacro(source_t *source)
-{
- int i;
- token_t token;
-
- if (!PC_ReadSourceToken(source, &token)) return qtrue;
- if (token.type != TT_NAME)
- {
- PC_UnreadSourceToken(source, &token);
- return qtrue;
- } //end if
- //find the precompiler directive
- for (i = 0; dollardirectives[i].name; i++)
- {
- if (!strcmp(dollardirectives[i].name, token.string))
- {
- PC_UnreadSourceToken(source, &token);
- return qfalse;
- } //end if
- } //end for
- PC_UnreadSourceToken(source, &token);
- return qtrue;
-} //end of the function QuakeCMacro
-#endif //QUAKEC
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_ReadToken(source_t *source, token_t *token)
-{
- define_t *define;
-
- while(1)
- {
- if (!PC_ReadSourceToken(source, token)) return qfalse;
- //check for precompiler directives
- if (token->type == TT_PUNCTUATION && *token->string == '#')
- {
-#ifdef QUAKEC
- if (!BuiltinFunction(source))
-#endif //QUAKC
- {
- //read the precompiler directive
- if (!PC_ReadDirective(source)) return qfalse;
- continue;
- } //end if
- } //end if
- if (token->type == TT_PUNCTUATION && *token->string == '$')
- {
-#ifdef QUAKEC
- if (!QuakeCMacro(source))
-#endif //QUAKEC
- {
- //read the precompiler directive
- if (!PC_ReadDollarDirective(source)) return qfalse;
- continue;
- } //end if
- } //end if
- // recursively concatenate strings that are behind each other still resolving defines
- if (token->type == TT_STRING)
- {
- token_t newtoken;
- if (PC_ReadToken(source, &newtoken))
- {
- if (newtoken.type == TT_STRING)
- {
- token->string[strlen(token->string)-1] = '\0';
- if (strlen(token->string) + strlen(newtoken.string+1) + 1 >= MAX_TOKEN)
- {
- SourceError(source, "string longer than MAX_TOKEN %d\n", MAX_TOKEN);
- return qfalse;
- }
- strcat(token->string, newtoken.string+1);
- }
- else
- {
- PC_UnreadToken(source, &newtoken);
- }
- }
- } //end if
- //if skipping source because of conditional compilation
- if (source->skip) continue;
- //if the token is a name
- if (token->type == TT_NAME)
- {
- //check if the name is a define macro
-#if DEFINEHASHING
- define = PC_FindHashedDefine(source->definehash, token->string);
-#else
- define = PC_FindDefine(source->defines, token->string);
-#endif //DEFINEHASHING
- //if it is a define macro
- if (define)
- {
- //expand the defined macro
- if (!PC_ExpandDefineIntoSource(source, token, define)) return qfalse;
- continue;
- } //end if
- } //end if
- //copy token for unreading
- Com_Memcpy(&source->token, token, sizeof(token_t));
- //found a token
- return qtrue;
- } //end while
-} //end of the function PC_ReadToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_ExpectTokenString(source_t *source, char *string)
-{
- token_t token;
-
- if (!PC_ReadToken(source, &token))
- {
- SourceError(source, "couldn't find expected %s", string);
- return qfalse;
- } //end if
-
- if (strcmp(token.string, string))
- {
- SourceError(source, "expected %s, found %s", string, token.string);
- return qfalse;
- } //end if
- return qtrue;
-} //end of the function PC_ExpectTokenString
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token)
-{
- char str[MAX_TOKEN];
-
- if (!PC_ReadToken(source, token))
- {
- SourceError(source, "couldn't read expected token");
- return qfalse;
- } //end if
-
- if (token->type != type)
- {
- strcpy(str, "");
- if (type == TT_STRING) strcpy(str, "string");
- if (type == TT_LITERAL) strcpy(str, "literal");
- if (type == TT_NUMBER) strcpy(str, "number");
- if (type == TT_NAME) strcpy(str, "name");
- if (type == TT_PUNCTUATION) strcpy(str, "punctuation");
- SourceError(source, "expected a %s, found %s", str, token->string);
- return qfalse;
- } //end if
- if (token->type == TT_NUMBER)
- {
- if ((token->subtype & subtype) != subtype)
- {
- if (subtype & TT_DECIMAL) strcpy(str, "decimal");
- if (subtype & TT_HEX) strcpy(str, "hex");
- if (subtype & TT_OCTAL) strcpy(str, "octal");
- if (subtype & TT_BINARY) strcpy(str, "binary");
- if (subtype & TT_LONG) strcat(str, " long");
- if (subtype & TT_UNSIGNED) strcat(str, " unsigned");
- if (subtype & TT_FLOAT) strcat(str, " float");
- if (subtype & TT_INTEGER) strcat(str, " integer");
- SourceError(source, "expected %s, found %s", str, token->string);
- return qfalse;
- } //end if
- } //end if
- else if (token->type == TT_PUNCTUATION)
- {
- if (token->subtype != subtype)
- {
- SourceError(source, "found %s", token->string);
- return qfalse;
- } //end if
- } //end else if
- return qtrue;
-} //end of the function PC_ExpectTokenType
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_ExpectAnyToken(source_t *source, token_t *token)
-{
- if (!PC_ReadToken(source, token))
- {
- SourceError(source, "couldn't read expected token");
- return qfalse;
- } //end if
- else
- {
- return qtrue;
- } //end else
-} //end of the function PC_ExpectAnyToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_CheckTokenString(source_t *source, char *string)
-{
- token_t tok;
-
- if (!PC_ReadToken(source, &tok)) return qfalse;
- //if the token is available
- if (!strcmp(tok.string, string)) return qtrue;
- //
- PC_UnreadSourceToken(source, &tok);
- return qfalse;
-} //end of the function PC_CheckTokenString
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token)
-{
- token_t tok;
-
- if (!PC_ReadToken(source, &tok)) return qfalse;
- //if the type matches
- if (tok.type == type &&
- (tok.subtype & subtype) == subtype)
- {
- Com_Memcpy(token, &tok, sizeof(token_t));
- return qtrue;
- } //end if
- //
- PC_UnreadSourceToken(source, &tok);
- return qfalse;
-} //end of the function PC_CheckTokenType
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_SkipUntilString(source_t *source, char *string)
-{
- token_t token;
-
- while(PC_ReadToken(source, &token))
- {
- if (!strcmp(token.string, string)) return qtrue;
- } //end while
- return qfalse;
-} //end of the function PC_SkipUntilString
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_UnreadLastToken(source_t *source)
-{
- PC_UnreadSourceToken(source, &source->token);
-} //end of the function PC_UnreadLastToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_UnreadToken(source_t *source, token_t *token)
-{
- PC_UnreadSourceToken(source, token);
-} //end of the function PC_UnreadToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_SetIncludePath(source_t *source, char *path)
-{
- strncpy(source->includepath, path, MAX_PATH);
- //add trailing path seperator
- if (source->includepath[strlen(source->includepath)-1] != '\\' &&
- source->includepath[strlen(source->includepath)-1] != '/')
- {
- strcat(source->includepath, PATHSEPERATOR_STR);
- } //end if
-} //end of the function PC_SetIncludePath
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_SetPunctuations(source_t *source, punctuation_t *p)
-{
- source->punctuations = p;
-} //end of the function PC_SetPunctuations
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-source_t *LoadSourceFile(const char *filename)
-{
- source_t *source;
- script_t *script;
-
- PC_InitTokenHeap();
-
- script = LoadScriptFile(filename);
- if (!script) return NULL;
-
- script->next = NULL;
-
- source = (source_t *) GetMemory(sizeof(source_t));
- Com_Memset(source, 0, sizeof(source_t));
-
- strncpy(source->filename, filename, MAX_PATH);
- source->scriptstack = script;
- source->tokens = NULL;
- source->defines = NULL;
- source->indentstack = NULL;
- source->skip = 0;
-
-#if DEFINEHASHING
- source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));
-#endif //DEFINEHASHING
- PC_AddGlobalDefinesToSource(source);
- return source;
-} //end of the function LoadSourceFile
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-source_t *LoadSourceMemory(char *ptr, int length, char *name)
-{
- source_t *source;
- script_t *script;
-
- PC_InitTokenHeap();
-
- script = LoadScriptMemory(ptr, length, name);
- if (!script) return NULL;
- script->next = NULL;
-
- source = (source_t *) GetMemory(sizeof(source_t));
- Com_Memset(source, 0, sizeof(source_t));
-
- strncpy(source->filename, name, MAX_PATH);
- source->scriptstack = script;
- source->tokens = NULL;
- source->defines = NULL;
- source->indentstack = NULL;
- source->skip = 0;
-
-#if DEFINEHASHING
- source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));
-#endif //DEFINEHASHING
- PC_AddGlobalDefinesToSource(source);
- return source;
-} //end of the function LoadSourceMemory
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void FreeSource(source_t *source)
-{
- script_t *script;
- token_t *token;
- define_t *define;
- indent_t *indent;
- int i;
-
- //PC_PrintDefineHashTable(source->definehash);
- //free all the scripts
- while(source->scriptstack)
- {
- script = source->scriptstack;
- source->scriptstack = source->scriptstack->next;
- FreeScript(script);
- } //end for
- //free all the tokens
- while(source->tokens)
- {
- token = source->tokens;
- source->tokens = source->tokens->next;
- PC_FreeToken(token);
- } //end for
-#if DEFINEHASHING
- for (i = 0; i < DEFINEHASHSIZE; i++)
- {
- while(source->definehash[i])
- {
- define = source->definehash[i];
- source->definehash[i] = source->definehash[i]->hashnext;
- PC_FreeDefine(define);
- } //end while
- } //end for
-#else //DEFINEHASHING
- //free all defines
- while(source->defines)
- {
- define = source->defines;
- source->defines = source->defines->next;
- PC_FreeDefine(define);
- } //end for
-#endif //DEFINEHASHING
- //free all indents
- while(source->indentstack)
- {
- indent = source->indentstack;
- source->indentstack = source->indentstack->next;
- FreeMemory(indent);
- } //end for
-#if DEFINEHASHING
- //
- if (source->definehash) FreeMemory(source->definehash);
-#endif //DEFINEHASHING
- //free the source itself
- FreeMemory(source);
-} //end of the function FreeSource
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-
-#define MAX_SOURCEFILES 64
-
-source_t *sourceFiles[MAX_SOURCEFILES];
-
-int PC_LoadSourceHandle(const char *filename)
-{
- source_t *source;
- int i;
-
- for (i = 1; i < MAX_SOURCEFILES; i++)
- {
- if (!sourceFiles[i])
- break;
- } //end for
- if (i >= MAX_SOURCEFILES)
- return 0;
- PS_SetBaseFolder("");
- source = LoadSourceFile(filename);
- if (!source)
- return 0;
- sourceFiles[i] = source;
- return i;
-} //end of the function PC_LoadSourceHandle
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_FreeSourceHandle(int handle)
-{
- if (handle < 1 || handle >= MAX_SOURCEFILES)
- return qfalse;
- if (!sourceFiles[handle])
- return qfalse;
-
- FreeSource(sourceFiles[handle]);
- sourceFiles[handle] = NULL;
- return qtrue;
-} //end of the function PC_FreeSourceHandle
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_ReadTokenHandle(int handle, pc_token_t *pc_token)
-{
- token_t token;
- int ret;
-
- if (handle < 1 || handle >= MAX_SOURCEFILES)
- return 0;
- if (!sourceFiles[handle])
- return 0;
-
- ret = PC_ReadToken(sourceFiles[handle], &token);
- strcpy(pc_token->string, token.string);
- pc_token->type = token.type;
- pc_token->subtype = token.subtype;
- pc_token->intvalue = token.intvalue;
- pc_token->floatvalue = token.floatvalue;
- if (pc_token->type == TT_STRING)
- StripDoubleQuotes(pc_token->string);
- return ret;
-} //end of the function PC_ReadTokenHandle
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PC_SourceFileAndLine(int handle, char *filename, int *line)
-{
- if (handle < 1 || handle >= MAX_SOURCEFILES)
- return qfalse;
- if (!sourceFiles[handle])
- return qfalse;
-
- strcpy(filename, sourceFiles[handle]->filename);
- if (sourceFiles[handle]->scriptstack)
- *line = sourceFiles[handle]->scriptstack->line;
- else
- *line = 0;
- return qtrue;
-} //end of the function PC_SourceFileAndLine
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_SetBaseFolder(char *path)
-{
- PS_SetBaseFolder(path);
-} //end of the function PC_SetBaseFolder
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PC_CheckOpenSourceHandles(void)
-{
- int i;
-
- for (i = 1; i < MAX_SOURCEFILES; i++)
- {
- if (sourceFiles[i])
- {
-#ifdef BOTLIB
- botimport.Print(PRT_ERROR, "file %s still open in precompiler\n", sourceFiles[i]->scriptstack->filename);
-#endif //BOTLIB
- } //end if
- } //end for
-} //end of the function PC_CheckOpenSourceHandles
-
diff --git a/engine/code/botlib/l_script.c b/engine/code/botlib/l_script.c
deleted file mode 100644
index 2fe628d..0000000
--- a/engine/code/botlib/l_script.c
+++ /dev/null
@@ -1,1447 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: l_script.c
- *
- * desc: lexicographical parser
- *
- * $Archive: /MissionPack/code/botlib/l_script.c $
- *
- *****************************************************************************/
-
-//#define SCREWUP
-//#define BOTLIB
-//#define MEQCC
-//#define BSPC
-
-#ifdef SCREWUP
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <string.h>
-#include <stdarg.h>
-#include "l_memory.h"
-#include "l_script.h"
-
-typedef enum {qfalse, qtrue} qboolean;
-
-#endif //SCREWUP
-
-#ifdef BOTLIB
-//include files for usage in the bot library
-#include "../qcommon/q_shared.h"
-#include "botlib.h"
-#include "be_interface.h"
-#include "l_script.h"
-#include "l_memory.h"
-#include "l_log.h"
-#include "l_libvar.h"
-#endif //BOTLIB
-
-#ifdef MEQCC
-//include files for usage in MrElusive's QuakeC Compiler
-#include "qcc.h"
-#include "l_script.h"
-#include "l_memory.h"
-#include "l_log.h"
-
-#define qtrue true
-#define qfalse false
-#endif //MEQCC
-
-#ifdef BSPC
-//include files for usage in the BSP Converter
-#include "../bspc/qbsp.h"
-#include "../bspc/l_log.h"
-#include "../bspc/l_mem.h"
-
-#define qtrue true
-#define qfalse false
-#endif //BSPC
-
-
-#define PUNCTABLE
-
-//longer punctuations first
-punctuation_t default_punctuations[] =
-{
- //binary operators
- {">>=",P_RSHIFT_ASSIGN, NULL},
- {"<<=",P_LSHIFT_ASSIGN, NULL},
- //
- {"...",P_PARMS, NULL},
- //define merge operator
- {"##",P_PRECOMPMERGE, NULL},
- //logic operators
- {"&&",P_LOGIC_AND, NULL},
- {"||",P_LOGIC_OR, NULL},
- {">=",P_LOGIC_GEQ, NULL},
- {"<=",P_LOGIC_LEQ, NULL},
- {"==",P_LOGIC_EQ, NULL},
- {"!=",P_LOGIC_UNEQ, NULL},
- //arithmatic operators
- {"*=",P_MUL_ASSIGN, NULL},
- {"/=",P_DIV_ASSIGN, NULL},
- {"%=",P_MOD_ASSIGN, NULL},
- {"+=",P_ADD_ASSIGN, NULL},
- {"-=",P_SUB_ASSIGN, NULL},
- {"++",P_INC, NULL},
- {"--",P_DEC, NULL},
- //binary operators
- {"&=",P_BIN_AND_ASSIGN, NULL},
- {"|=",P_BIN_OR_ASSIGN, NULL},
- {"^=",P_BIN_XOR_ASSIGN, NULL},
- {">>",P_RSHIFT, NULL},
- {"<<",P_LSHIFT, NULL},
- //reference operators
- {"->",P_POINTERREF, NULL},
- //C++
- {"::",P_CPP1, NULL},
- {".*",P_CPP2, NULL},
- //arithmatic operators
- {"*",P_MUL, NULL},
- {"/",P_DIV, NULL},
- {"%",P_MOD, NULL},
- {"+",P_ADD, NULL},
- {"-",P_SUB, NULL},
- {"=",P_ASSIGN, NULL},
- //binary operators
- {"&",P_BIN_AND, NULL},
- {"|",P_BIN_OR, NULL},
- {"^",P_BIN_XOR, NULL},
- {"~",P_BIN_NOT, NULL},
- //logic operators
- {"!",P_LOGIC_NOT, NULL},
- {">",P_LOGIC_GREATER, NULL},
- {"<",P_LOGIC_LESS, NULL},
- //reference operator
- {".",P_REF, NULL},
- //seperators
- {",",P_COMMA, NULL},
- {";",P_SEMICOLON, NULL},
- //label indication
- {":",P_COLON, NULL},
- //if statement
- {"?",P_QUESTIONMARK, NULL},
- //embracements
- {"(",P_PARENTHESESOPEN, NULL},
- {")",P_PARENTHESESCLOSE, NULL},
- {"{",P_BRACEOPEN, NULL},
- {"}",P_BRACECLOSE, NULL},
- {"[",P_SQBRACKETOPEN, NULL},
- {"]",P_SQBRACKETCLOSE, NULL},
- //
- {"\\",P_BACKSLASH, NULL},
- //precompiler operator
- {"#",P_PRECOMP, NULL},
-#ifdef DOLLAR
- {"$",P_DOLLAR, NULL},
-#endif //DOLLAR
- {NULL, 0}
-};
-
-#ifdef BSPC
-char basefolder[MAX_PATH];
-#else
-char basefolder[MAX_QPATH];
-#endif
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void PS_CreatePunctuationTable(script_t *script, punctuation_t *punctuations)
-{
- int i;
- punctuation_t *p, *lastp, *newp;
-
- //get memory for the table
- if (!script->punctuationtable) script->punctuationtable = (punctuation_t **)
- GetMemory(256 * sizeof(punctuation_t *));
- Com_Memset(script->punctuationtable, 0, 256 * sizeof(punctuation_t *));
- //add the punctuations in the list to the punctuation table
- for (i = 0; punctuations[i].p; i++)
- {
- newp = &punctuations[i];
- lastp = NULL;
- //sort the punctuations in this table entry on length (longer punctuations first)
- for (p = script->punctuationtable[(unsigned int) newp->p[0]]; p; p = p->next)
- {
- if (strlen(p->p) < strlen(newp->p))
- {
- newp->next = p;
- if (lastp) lastp->next = newp;
- else script->punctuationtable[(unsigned int) newp->p[0]] = newp;
- break;
- } //end if
- lastp = p;
- } //end for
- if (!p)
- {
- newp->next = NULL;
- if (lastp) lastp->next = newp;
- else script->punctuationtable[(unsigned int) newp->p[0]] = newp;
- } //end if
- } //end for
-} //end of the function PS_CreatePunctuationTable
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-char *PunctuationFromNum(script_t *script, int num)
-{
- int i;
-
- for (i = 0; script->punctuations[i].p; i++)
- {
- if (script->punctuations[i].n == num) return script->punctuations[i].p;
- } //end for
- return "unkown punctuation";
-} //end of the function PunctuationFromNum
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void QDECL ScriptError(script_t *script, char *str, ...)
-{
- char text[1024];
- va_list ap;
-
- if (script->flags & SCFL_NOERRORS) return;
-
- va_start(ap, str);
- Q_vsnprintf(text, sizeof(text), str, ap);
- va_end(ap);
-#ifdef BOTLIB
- botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", script->filename, script->line, text);
-#endif //BOTLIB
-#ifdef MEQCC
- printf("error: file %s, line %d: %s\n", script->filename, script->line, text);
-#endif //MEQCC
-#ifdef BSPC
- Log_Print("error: file %s, line %d: %s\n", script->filename, script->line, text);
-#endif //BSPC
-} //end of the function ScriptError
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void QDECL ScriptWarning(script_t *script, char *str, ...)
-{
- char text[1024];
- va_list ap;
-
- if (script->flags & SCFL_NOWARNINGS) return;
-
- va_start(ap, str);
- Q_vsnprintf(text, sizeof(text), str, ap);
- va_end(ap);
-#ifdef BOTLIB
- botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", script->filename, script->line, text);
-#endif //BOTLIB
-#ifdef MEQCC
- printf("warning: file %s, line %d: %s\n", script->filename, script->line, text);
-#endif //MEQCC
-#ifdef BSPC
- Log_Print("warning: file %s, line %d: %s\n", script->filename, script->line, text);
-#endif //BSPC
-} //end of the function ScriptWarning
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void SetScriptPunctuations(script_t *script, punctuation_t *p)
-{
-#ifdef PUNCTABLE
- if (p) PS_CreatePunctuationTable(script, p);
- else PS_CreatePunctuationTable(script, default_punctuations);
-#endif //PUNCTABLE
- if (p) script->punctuations = p;
- else script->punctuations = default_punctuations;
-} //end of the function SetScriptPunctuations
-//============================================================================
-// Reads spaces, tabs, C-like comments etc.
-// When a newline character is found the scripts line counter is increased.
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_ReadWhiteSpace(script_t *script)
-{
- while(1)
- {
- //skip white space
- while(*script->script_p <= ' ')
- {
- if (!*script->script_p) return 0;
- if (*script->script_p == '\n') script->line++;
- script->script_p++;
- } //end while
- //skip comments
- if (*script->script_p == '/')
- {
- //comments //
- if (*(script->script_p+1) == '/')
- {
- script->script_p++;
- do
- {
- script->script_p++;
- if (!*script->script_p) return 0;
- } //end do
- while(*script->script_p != '\n');
- script->line++;
- script->script_p++;
- if (!*script->script_p) return 0;
- continue;
- } //end if
- //comments /* */
- else if (*(script->script_p+1) == '*')
- {
- script->script_p++;
- do
- {
- script->script_p++;
- if (!*script->script_p) return 0;
- if (*script->script_p == '\n') script->line++;
- } //end do
- while(!(*script->script_p == '*' && *(script->script_p+1) == '/'));
- script->script_p++;
- if (!*script->script_p) return 0;
- script->script_p++;
- if (!*script->script_p) return 0;
- continue;
- } //end if
- } //end if
- break;
- } //end while
- return 1;
-} //end of the function PS_ReadWhiteSpace
-//============================================================================
-// Reads an escape character.
-//
-// Parameter: script : script to read from
-// ch : place to store the read escape character
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_ReadEscapeCharacter(script_t *script, char *ch)
-{
- int c, val, i;
-
- //step over the leading '\\'
- script->script_p++;
- //determine the escape character
- switch(*script->script_p)
- {
- case '\\': c = '\\'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case 'v': c = '\v'; break;
- case 'b': c = '\b'; break;
- case 'f': c = '\f'; break;
- case 'a': c = '\a'; break;
- case '\'': c = '\''; break;
- case '\"': c = '\"'; break;
- case '\?': c = '\?'; break;
- case 'x':
- {
- script->script_p++;
- for (i = 0, val = 0; ; i++, script->script_p++)
- {
- c = *script->script_p;
- if (c >= '0' && c <= '9') c = c - '0';
- else if (c >= 'A' && c <= 'Z') c = c - 'A' + 10;
- else if (c >= 'a' && c <= 'z') c = c - 'a' + 10;
- else break;
- val = (val << 4) + c;
- } //end for
- script->script_p--;
- if (val > 0xFF)
- {
- ScriptWarning(script, "too large value in escape character");
- val = 0xFF;
- } //end if
- c = val;
- break;
- } //end case
- default: //NOTE: decimal ASCII code, NOT octal
- {
- if (*script->script_p < '0' || *script->script_p > '9') ScriptError(script, "unknown escape char");
- for (i = 0, val = 0; ; i++, script->script_p++)
- {
- c = *script->script_p;
- if (c >= '0' && c <= '9') c = c - '0';
- else break;
- val = val * 10 + c;
- } //end for
- script->script_p--;
- if (val > 0xFF)
- {
- ScriptWarning(script, "too large value in escape character");
- val = 0xFF;
- } //end if
- c = val;
- break;
- } //end default
- } //end switch
- //step over the escape character or the last digit of the number
- script->script_p++;
- //store the escape character
- *ch = c;
- //succesfully read escape character
- return 1;
-} //end of the function PS_ReadEscapeCharacter
-//============================================================================
-// Reads C-like string. Escape characters are interpretted.
-// Quotes are included with the string.
-// Reads two strings with a white space between them as one string.
-//
-// Parameter: script : script to read from
-// token : buffer to store the string
-// Returns: qtrue when a string was read succesfully
-// Changes Globals: -
-//============================================================================
-int PS_ReadString(script_t *script, token_t *token, int quote)
-{
- int len, tmpline;
- char *tmpscript_p;
-
- if (quote == '\"') token->type = TT_STRING;
- else token->type = TT_LITERAL;
-
- len = 0;
- //leading quote
- token->string[len++] = *script->script_p++;
- //
- while(1)
- {
- //minus 2 because trailing double quote and zero have to be appended
- if (len >= MAX_TOKEN - 2)
- {
- ScriptError(script, "string longer than MAX_TOKEN = %d", MAX_TOKEN);
- return 0;
- } //end if
- //if there is an escape character and
- //if escape characters inside a string are allowed
- if (*script->script_p == '\\' && !(script->flags & SCFL_NOSTRINGESCAPECHARS))
- {
- if (!PS_ReadEscapeCharacter(script, &token->string[len]))
- {
- token->string[len] = 0;
- return 0;
- } //end if
- len++;
- } //end if
- //if a trailing quote
- else if (*script->script_p == quote)
- {
- //step over the double quote
- script->script_p++;
- //if white spaces in a string are not allowed
- if (script->flags & SCFL_NOSTRINGWHITESPACES) break;
- //
- tmpscript_p = script->script_p;
- tmpline = script->line;
- //read unusefull stuff between possible two following strings
- if (!PS_ReadWhiteSpace(script))
- {
- script->script_p = tmpscript_p;
- script->line = tmpline;
- break;
- } //end if
- //if there's no leading double qoute
- if (*script->script_p != quote)
- {
- script->script_p = tmpscript_p;
- script->line = tmpline;
- break;
- } //end if
- //step over the new leading double quote
- script->script_p++;
- } //end if
- else
- {
- if (*script->script_p == '\0')
- {
- token->string[len] = 0;
- ScriptError(script, "missing trailing quote");
- return 0;
- } //end if
- if (*script->script_p == '\n')
- {
- token->string[len] = 0;
- ScriptError(script, "newline inside string %s", token->string);
- return 0;
- } //end if
- token->string[len++] = *script->script_p++;
- } //end else
- } //end while
- //trailing quote
- token->string[len++] = quote;
- //end string with a zero
- token->string[len] = '\0';
- //the sub type is the length of the string
- token->subtype = len;
- return 1;
-} //end of the function PS_ReadString
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_ReadName(script_t *script, token_t *token)
-{
- int len = 0;
- char c;
-
- token->type = TT_NAME;
- do
- {
- token->string[len++] = *script->script_p++;
- if (len >= MAX_TOKEN)
- {
- ScriptError(script, "name longer than MAX_TOKEN = %d", MAX_TOKEN);
- return 0;
- } //end if
- c = *script->script_p;
- } while ((c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- (c >= '0' && c <= '9') ||
- c == '_');
- token->string[len] = '\0';
- //the sub type is the length of the name
- token->subtype = len;
- return 1;
-} //end of the function PS_ReadName
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void NumberValue(char *string, int subtype, unsigned long int *intvalue,
- float *floatvalue)
-{
- unsigned long int dotfound = 0;
-
- *intvalue = 0;
- *floatvalue = 0;
- //floating point number
- if (subtype & TT_FLOAT)
- {
- while(*string)
- {
- if (*string == '.')
- {
- if (dotfound) return;
- dotfound = 10;
- string++;
- } //end if
- if (dotfound)
- {
- *floatvalue = *floatvalue + (float) (*string - '0') /
- (float) dotfound;
- dotfound *= 10;
- } //end if
- else
- {
- *floatvalue = *floatvalue * 10.0 + (float) (*string - '0');
- } //end else
- string++;
- } //end while
- *intvalue = (unsigned long) *floatvalue;
- } //end if
- else if (subtype & TT_DECIMAL)
- {
- while(*string) *intvalue = *intvalue * 10 + (*string++ - '0');
- *floatvalue = *intvalue;
- } //end else if
- else if (subtype & TT_HEX)
- {
- //step over the leading 0x or 0X
- string += 2;
- while(*string)
- {
- *intvalue <<= 4;
- if (*string >= 'a' && *string <= 'f') *intvalue += *string - 'a' + 10;
- else if (*string >= 'A' && *string <= 'F') *intvalue += *string - 'A' + 10;
- else *intvalue += *string - '0';
- string++;
- } //end while
- *floatvalue = *intvalue;
- } //end else if
- else if (subtype & TT_OCTAL)
- {
- //step over the first zero
- string += 1;
- while(*string) *intvalue = (*intvalue << 3) + (*string++ - '0');
- *floatvalue = *intvalue;
- } //end else if
- else if (subtype & TT_BINARY)
- {
- //step over the leading 0b or 0B
- string += 2;
- while(*string) *intvalue = (*intvalue << 1) + (*string++ - '0');
- *floatvalue = *intvalue;
- } //end else if
-} //end of the function NumberValue
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_ReadNumber(script_t *script, token_t *token)
-{
- int len = 0, i;
- int octal, dot;
- char c;
-// unsigned long int intvalue = 0;
-// double floatvalue = 0;
-
- token->type = TT_NUMBER;
- //check for a hexadecimal number
- if (*script->script_p == '0' &&
- (*(script->script_p + 1) == 'x' ||
- *(script->script_p + 1) == 'X'))
- {
- token->string[len++] = *script->script_p++;
- token->string[len++] = *script->script_p++;
- c = *script->script_p;
- //hexadecimal
- while((c >= '0' && c <= '9') ||
- (c >= 'a' && c <= 'f') ||
- (c >= 'A' && c <= 'A'))
- {
- token->string[len++] = *script->script_p++;
- if (len >= MAX_TOKEN)
- {
- ScriptError(script, "hexadecimal number longer than MAX_TOKEN = %d", MAX_TOKEN);
- return 0;
- } //end if
- c = *script->script_p;
- } //end while
- token->subtype |= TT_HEX;
- } //end if
-#ifdef BINARYNUMBERS
- //check for a binary number
- else if (*script->script_p == '0' &&
- (*(script->script_p + 1) == 'b' ||
- *(script->script_p + 1) == 'B'))
- {
- token->string[len++] = *script->script_p++;
- token->string[len++] = *script->script_p++;
- c = *script->script_p;
- //binary
- while(c == '0' || c == '1')
- {
- token->string[len++] = *script->script_p++;
- if (len >= MAX_TOKEN)
- {
- ScriptError(script, "binary number longer than MAX_TOKEN = %d", MAX_TOKEN);
- return 0;
- } //end if
- c = *script->script_p;
- } //end while
- token->subtype |= TT_BINARY;
- } //end if
-#endif //BINARYNUMBERS
- else //decimal or octal integer or floating point number
- {
- octal = qfalse;
- dot = qfalse;
- if (*script->script_p == '0') octal = qtrue;
- while(1)
- {
- c = *script->script_p;
- if (c == '.') dot = qtrue;
- else if (c == '8' || c == '9') octal = qfalse;
- else if (c < '0' || c > '9') break;
- token->string[len++] = *script->script_p++;
- if (len >= MAX_TOKEN - 1)
- {
- ScriptError(script, "number longer than MAX_TOKEN = %d", MAX_TOKEN);
- return 0;
- } //end if
- } //end while
- if (octal) token->subtype |= TT_OCTAL;
- else token->subtype |= TT_DECIMAL;
- if (dot) token->subtype |= TT_FLOAT;
- } //end else
- for (i = 0; i < 2; i++)
- {
- c = *script->script_p;
- //check for a LONG number
- if ( (c == 'l' || c == 'L')
- && !(token->subtype & TT_LONG))
- {
- script->script_p++;
- token->subtype |= TT_LONG;
- } //end if
- //check for an UNSIGNED number
- else if ( (c == 'u' || c == 'U')
- && !(token->subtype & (TT_UNSIGNED | TT_FLOAT)))
- {
- script->script_p++;
- token->subtype |= TT_UNSIGNED;
- } //end if
- } //end for
- token->string[len] = '\0';
-#ifdef NUMBERVALUE
- NumberValue(token->string, token->subtype, &token->intvalue, &token->floatvalue);
-#endif //NUMBERVALUE
- if (!(token->subtype & TT_FLOAT)) token->subtype |= TT_INTEGER;
- return 1;
-} //end of the function PS_ReadNumber
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_ReadLiteral(script_t *script, token_t *token)
-{
- token->type = TT_LITERAL;
- //first quote
- token->string[0] = *script->script_p++;
- //check for end of file
- if (!*script->script_p)
- {
- ScriptError(script, "end of file before trailing \'");
- return 0;
- } //end if
- //if it is an escape character
- if (*script->script_p == '\\')
- {
- if (!PS_ReadEscapeCharacter(script, &token->string[1])) return 0;
- } //end if
- else
- {
- token->string[1] = *script->script_p++;
- } //end else
- //check for trailing quote
- if (*script->script_p != '\'')
- {
- ScriptWarning(script, "too many characters in literal, ignored");
- while(*script->script_p &&
- *script->script_p != '\'' &&
- *script->script_p != '\n')
- {
- script->script_p++;
- } //end while
- if (*script->script_p == '\'') script->script_p++;
- } //end if
- //store the trailing quote
- token->string[2] = *script->script_p++;
- //store trailing zero to end the string
- token->string[3] = '\0';
- //the sub type is the integer literal value
- token->subtype = token->string[1];
- //
- return 1;
-} //end of the function PS_ReadLiteral
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_ReadPunctuation(script_t *script, token_t *token)
-{
- int len;
- char *p;
- punctuation_t *punc;
-
-#ifdef PUNCTABLE
- for (punc = script->punctuationtable[(unsigned int)*script->script_p]; punc; punc = punc->next)
- {
-#else
- int i;
-
- for (i = 0; script->punctuations[i].p; i++)
- {
- punc = &script->punctuations[i];
-#endif //PUNCTABLE
- p = punc->p;
- len = strlen(p);
- //if the script contains at least as much characters as the punctuation
- if (script->script_p + len <= script->end_p)
- {
- //if the script contains the punctuation
- if (!strncmp(script->script_p, p, len))
- {
- strncpy(token->string, p, MAX_TOKEN);
- script->script_p += len;
- token->type = TT_PUNCTUATION;
- //sub type is the number of the punctuation
- token->subtype = punc->n;
- return 1;
- } //end if
- } //end if
- } //end for
- return 0;
-} //end of the function PS_ReadPunctuation
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_ReadPrimitive(script_t *script, token_t *token)
-{
- int len;
-
- len = 0;
- while(*script->script_p > ' ' && *script->script_p != ';')
- {
- if (len >= MAX_TOKEN)
- {
- ScriptError(script, "primitive token longer than MAX_TOKEN = %d", MAX_TOKEN);
- return 0;
- } //end if
- token->string[len++] = *script->script_p++;
- } //end while
- token->string[len] = 0;
- //copy the token into the script structure
- Com_Memcpy(&script->token, token, sizeof(token_t));
- //primitive reading successfull
- return 1;
-} //end of the function PS_ReadPrimitive
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_ReadToken(script_t *script, token_t *token)
-{
- //if there is a token available (from UnreadToken)
- if (script->tokenavailable)
- {
- script->tokenavailable = 0;
- Com_Memcpy(token, &script->token, sizeof(token_t));
- return 1;
- } //end if
- //save script pointer
- script->lastscript_p = script->script_p;
- //save line counter
- script->lastline = script->line;
- //clear the token stuff
- Com_Memset(token, 0, sizeof(token_t));
- //start of the white space
- script->whitespace_p = script->script_p;
- token->whitespace_p = script->script_p;
- //read unusefull stuff
- if (!PS_ReadWhiteSpace(script)) return 0;
- //end of the white space
- script->endwhitespace_p = script->script_p;
- token->endwhitespace_p = script->script_p;
- //line the token is on
- token->line = script->line;
- //number of lines crossed before token
- token->linescrossed = script->line - script->lastline;
- //if there is a leading double quote
- if (*script->script_p == '\"')
- {
- if (!PS_ReadString(script, token, '\"')) return 0;
- } //end if
- //if an literal
- else if (*script->script_p == '\'')
- {
- //if (!PS_ReadLiteral(script, token)) return 0;
- if (!PS_ReadString(script, token, '\'')) return 0;
- } //end if
- //if there is a number
- else if ((*script->script_p >= '0' && *script->script_p <= '9') ||
- (*script->script_p == '.' &&
- (*(script->script_p + 1) >= '0' && *(script->script_p + 1) <= '9')))
- {
- if (!PS_ReadNumber(script, token)) return 0;
- } //end if
- //if this is a primitive script
- else if (script->flags & SCFL_PRIMITIVE)
- {
- return PS_ReadPrimitive(script, token);
- } //end else if
- //if there is a name
- else if ((*script->script_p >= 'a' && *script->script_p <= 'z') ||
- (*script->script_p >= 'A' && *script->script_p <= 'Z') ||
- *script->script_p == '_')
- {
- if (!PS_ReadName(script, token)) return 0;
- } //end if
- //check for punctuations
- else if (!PS_ReadPunctuation(script, token))
- {
- ScriptError(script, "can't read token");
- return 0;
- } //end if
- //copy the token into the script structure
- Com_Memcpy(&script->token, token, sizeof(token_t));
- //succesfully read a token
- return 1;
-} //end of the function PS_ReadToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_ExpectTokenString(script_t *script, char *string)
-{
- token_t token;
-
- if (!PS_ReadToken(script, &token))
- {
- ScriptError(script, "couldn't find expected %s", string);
- return 0;
- } //end if
-
- if (strcmp(token.string, string))
- {
- ScriptError(script, "expected %s, found %s", string, token.string);
- return 0;
- } //end if
- return 1;
-} //end of the function PS_ExpectToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_ExpectTokenType(script_t *script, int type, int subtype, token_t *token)
-{
- char str[MAX_TOKEN];
-
- if (!PS_ReadToken(script, token))
- {
- ScriptError(script, "couldn't read expected token");
- return 0;
- } //end if
-
- if (token->type != type)
- {
- if (type == TT_STRING) strcpy(str, "string");
- if (type == TT_LITERAL) strcpy(str, "literal");
- if (type == TT_NUMBER) strcpy(str, "number");
- if (type == TT_NAME) strcpy(str, "name");
- if (type == TT_PUNCTUATION) strcpy(str, "punctuation");
- ScriptError(script, "expected a %s, found %s", str, token->string);
- return 0;
- } //end if
- if (token->type == TT_NUMBER)
- {
- if ((token->subtype & subtype) != subtype)
- {
- if (subtype & TT_DECIMAL) strcpy(str, "decimal");
- if (subtype & TT_HEX) strcpy(str, "hex");
- if (subtype & TT_OCTAL) strcpy(str, "octal");
- if (subtype & TT_BINARY) strcpy(str, "binary");
- if (subtype & TT_LONG) strcat(str, " long");
- if (subtype & TT_UNSIGNED) strcat(str, " unsigned");
- if (subtype & TT_FLOAT) strcat(str, " float");
- if (subtype & TT_INTEGER) strcat(str, " integer");
- ScriptError(script, "expected %s, found %s", str, token->string);
- return 0;
- } //end if
- } //end if
- else if (token->type == TT_PUNCTUATION)
- {
- if (subtype < 0)
- {
- ScriptError(script, "BUG: wrong punctuation subtype");
- return 0;
- } //end if
- if (token->subtype != subtype)
- {
- ScriptError(script, "expected %s, found %s",
- script->punctuations[subtype], token->string);
- return 0;
- } //end if
- } //end else if
- return 1;
-} //end of the function PS_ExpectTokenType
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_ExpectAnyToken(script_t *script, token_t *token)
-{
- if (!PS_ReadToken(script, token))
- {
- ScriptError(script, "couldn't read expected token");
- return 0;
- } //end if
- else
- {
- return 1;
- } //end else
-} //end of the function PS_ExpectAnyToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_CheckTokenString(script_t *script, char *string)
-{
- token_t tok;
-
- if (!PS_ReadToken(script, &tok)) return 0;
- //if the token is available
- if (!strcmp(tok.string, string)) return 1;
- //token not available
- script->script_p = script->lastscript_p;
- return 0;
-} //end of the function PS_CheckTokenString
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_CheckTokenType(script_t *script, int type, int subtype, token_t *token)
-{
- token_t tok;
-
- if (!PS_ReadToken(script, &tok)) return 0;
- //if the type matches
- if (tok.type == type &&
- (tok.subtype & subtype) == subtype)
- {
- Com_Memcpy(token, &tok, sizeof(token_t));
- return 1;
- } //end if
- //token is not available
- script->script_p = script->lastscript_p;
- return 0;
-} //end of the function PS_CheckTokenType
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int PS_SkipUntilString(script_t *script, char *string)
-{
- token_t token;
-
- while(PS_ReadToken(script, &token))
- {
- if (!strcmp(token.string, string)) return 1;
- } //end while
- return 0;
-} //end of the function PS_SkipUntilString
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PS_UnreadLastToken(script_t *script)
-{
- script->tokenavailable = 1;
-} //end of the function UnreadLastToken
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PS_UnreadToken(script_t *script, token_t *token)
-{
- Com_Memcpy(&script->token, token, sizeof(token_t));
- script->tokenavailable = 1;
-} //end of the function UnreadToken
-//============================================================================
-// returns the next character of the read white space, returns NULL if none
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-char PS_NextWhiteSpaceChar(script_t *script)
-{
- if (script->whitespace_p != script->endwhitespace_p)
- {
- return *script->whitespace_p++;
- } //end if
- else
- {
- return 0;
- } //end else
-} //end of the function PS_NextWhiteSpaceChar
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void StripDoubleQuotes(char *string)
-{
- if (*string == '\"')
- {
- memmove(string, string+1, strlen(string));
- } //end if
- if (string[strlen(string)-1] == '\"')
- {
- string[strlen(string)-1] = '\0';
- } //end if
-} //end of the function StripDoubleQuotes
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void StripSingleQuotes(char *string)
-{
- if (*string == '\'')
- {
- memmove(string, string+1, strlen(string));
- } //end if
- if (string[strlen(string)-1] == '\'')
- {
- string[strlen(string)-1] = '\0';
- } //end if
-} //end of the function StripSingleQuotes
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-float ReadSignedFloat(script_t *script)
-{
- token_t token;
- float sign = 1.0;
-
- PS_ExpectAnyToken(script, &token);
- if (!strcmp(token.string, "-"))
- {
- if(!PS_ExpectAnyToken(script, &token))
- {
- ScriptError(script, "Missing float value\n", token.string);
- return 0;
- }
-
- sign = -1.0;
- }
-
- if (token.type != TT_NUMBER)
- {
- ScriptError(script, "expected float value, found %s\n", token.string);
- return 0;
- }
-
- return sign * token.floatvalue;
-} //end of the function ReadSignedFloat
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-signed long int ReadSignedInt(script_t *script)
-{
- token_t token;
- signed long int sign = 1;
-
- PS_ExpectAnyToken(script, &token);
- if (!strcmp(token.string, "-"))
- {
- if(!PS_ExpectAnyToken(script, &token))
- {
- ScriptError(script, "Missing integer value\n", token.string);
- return 0;
- }
-
- sign = -1;
- }
-
- if (token.type != TT_NUMBER || token.subtype == TT_FLOAT)
- {
- ScriptError(script, "expected integer value, found %s\n", token.string);
- return 0;
- }
-
- return sign * token.intvalue;
-} //end of the function ReadSignedInt
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void SetScriptFlags(script_t *script, int flags)
-{
- script->flags = flags;
-} //end of the function SetScriptFlags
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int GetScriptFlags(script_t *script)
-{
- return script->flags;
-} //end of the function GetScriptFlags
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void ResetScript(script_t *script)
-{
- //pointer in script buffer
- script->script_p = script->buffer;
- //pointer in script buffer before reading token
- script->lastscript_p = script->buffer;
- //begin of white space
- script->whitespace_p = NULL;
- //end of white space
- script->endwhitespace_p = NULL;
- //set if there's a token available in script->token
- script->tokenavailable = 0;
- //
- script->line = 1;
- script->lastline = 1;
- //clear the saved token
- Com_Memset(&script->token, 0, sizeof(token_t));
-} //end of the function ResetScript
-//============================================================================
-// returns true if at the end of the script
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int EndOfScript(script_t *script)
-{
- return script->script_p >= script->end_p;
-} //end of the function EndOfScript
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int NumLinesCrossed(script_t *script)
-{
- return script->line - script->lastline;
-} //end of the function NumLinesCrossed
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int ScriptSkipTo(script_t *script, char *value)
-{
- int len;
- char firstchar;
-
- firstchar = *value;
- len = strlen(value);
- do
- {
- if (!PS_ReadWhiteSpace(script)) return 0;
- if (*script->script_p == firstchar)
- {
- if (!strncmp(script->script_p, value, len))
- {
- return 1;
- } //end if
- } //end if
- script->script_p++;
- } while(1);
-} //end of the function ScriptSkipTo
-#ifndef BOTLIB
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-int FileLength(FILE *fp)
-{
- int pos;
- int end;
-
- pos = ftell(fp);
- fseek(fp, 0, SEEK_END);
- end = ftell(fp);
- fseek(fp, pos, SEEK_SET);
-
- return end;
-} //end of the function FileLength
-#endif
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-script_t *LoadScriptFile(const char *filename)
-{
-#ifdef BOTLIB
- fileHandle_t fp;
- char pathname[MAX_QPATH];
-#else
- FILE *fp;
-#endif
- int length;
- void *buffer;
- script_t *script;
-
-#ifdef BOTLIB
- if (strlen(basefolder))
- Com_sprintf(pathname, sizeof(pathname), "%s/%s", basefolder, filename);
- else
- Com_sprintf(pathname, sizeof(pathname), "%s", filename);
- length = botimport.FS_FOpenFile( pathname, &fp, FS_READ );
- if (!fp) return NULL;
-#else
- fp = fopen(filename, "rb");
- if (!fp) return NULL;
-
- length = FileLength(fp);
-#endif
-
- buffer = GetClearedMemory(sizeof(script_t) + length + 1);
- script = (script_t *) buffer;
- Com_Memset(script, 0, sizeof(script_t));
- strcpy(script->filename, filename);
- script->buffer = (char *) buffer + sizeof(script_t);
- script->buffer[length] = 0;
- script->length = length;
- //pointer in script buffer
- script->script_p = script->buffer;
- //pointer in script buffer before reading token
- script->lastscript_p = script->buffer;
- //pointer to end of script buffer
- script->end_p = &script->buffer[length];
- //set if there's a token available in script->token
- script->tokenavailable = 0;
- //
- script->line = 1;
- script->lastline = 1;
- //
- SetScriptPunctuations(script, NULL);
- //
-#ifdef BOTLIB
- botimport.FS_Read(script->buffer, length, fp);
- botimport.FS_FCloseFile(fp);
-#else
- if (fread(script->buffer, length, 1, fp) != 1)
- {
- FreeMemory(buffer);
- script = NULL;
- } //end if
- fclose(fp);
-#endif
-
- return script;
-} //end of the function LoadScriptFile
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-script_t *LoadScriptMemory(char *ptr, int length, char *name)
-{
- void *buffer;
- script_t *script;
-
- buffer = GetClearedMemory(sizeof(script_t) + length + 1);
- script = (script_t *) buffer;
- Com_Memset(script, 0, sizeof(script_t));
- strcpy(script->filename, name);
- script->buffer = (char *) buffer + sizeof(script_t);
- script->buffer[length] = 0;
- script->length = length;
- //pointer in script buffer
- script->script_p = script->buffer;
- //pointer in script buffer before reading token
- script->lastscript_p = script->buffer;
- //pointer to end of script buffer
- script->end_p = &script->buffer[length];
- //set if there's a token available in script->token
- script->tokenavailable = 0;
- //
- script->line = 1;
- script->lastline = 1;
- //
- SetScriptPunctuations(script, NULL);
- //
- Com_Memcpy(script->buffer, ptr, length);
- //
- return script;
-} //end of the function LoadScriptMemory
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void FreeScript(script_t *script)
-{
-#ifdef PUNCTABLE
- if (script->punctuationtable) FreeMemory(script->punctuationtable);
-#endif //PUNCTABLE
- FreeMemory(script);
-} //end of the function FreeScript
-//============================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//============================================================================
-void PS_SetBaseFolder(char *path)
-{
-#ifdef BSPC
- sprintf(basefolder, path);
-#else
- Com_sprintf(basefolder, sizeof(basefolder), "%s", path);
-#endif
-} //end of the function PS_SetBaseFolder
diff --git a/engine/code/botlib/l_struct.c b/engine/code/botlib/l_struct.c
deleted file mode 100644
index d948dc3..0000000
--- a/engine/code/botlib/l_struct.c
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: l_struct.c
- *
- * desc: structure reading / writing
- *
- * $Archive: /MissionPack/CODE/botlib/l_struct.c $
- *
- *****************************************************************************/
-
-#ifdef BOTLIB
-#include "../qcommon/q_shared.h"
-#include "botlib.h" //for the include of be_interface.h
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "l_utils.h"
-#include "be_interface.h"
-#endif //BOTLIB
-
-#ifdef BSPC
-//include files for usage in the BSP Converter
-#include "../bspc/qbsp.h"
-#include "../bspc/l_log.h"
-#include "../bspc/l_mem.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-
-#define qtrue true
-#define qfalse false
-#endif //BSPC
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-fielddef_t *FindField(fielddef_t *defs, char *name)
-{
- int i;
-
- for (i = 0; defs[i].name; i++)
- {
- if (!strcmp(defs[i].name, name)) return &defs[i];
- } //end for
- return NULL;
-} //end of the function FindField
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean ReadNumber(source_t *source, fielddef_t *fd, void *p)
-{
- token_t token;
- int negative = qfalse;
- long int intval, intmin = 0, intmax = 0;
- double floatval;
-
- if (!PC_ExpectAnyToken(source, &token)) return 0;
-
- //check for minus sign
- if (token.type == TT_PUNCTUATION)
- {
- if (fd->type & FT_UNSIGNED)
- {
- SourceError(source, "expected unsigned value, found %s", token.string);
- return 0;
- } //end if
- //if not a minus sign
- if (strcmp(token.string, "-"))
- {
- SourceError(source, "unexpected punctuation %s", token.string);
- return 0;
- } //end if
- negative = qtrue;
- //read the number
- if (!PC_ExpectAnyToken(source, &token)) return 0;
- } //end if
- //check if it is a number
- if (token.type != TT_NUMBER)
- {
- SourceError(source, "expected number, found %s", token.string);
- return 0;
- } //end if
- //check for a float value
- if (token.subtype & TT_FLOAT)
- {
- if ((fd->type & FT_TYPE) != FT_FLOAT)
- {
- SourceError(source, "unexpected float");
- return 0;
- } //end if
- floatval = token.floatvalue;
- if (negative) floatval = -floatval;
- if (fd->type & FT_BOUNDED)
- {
- if (floatval < fd->floatmin || floatval > fd->floatmax)
- {
- SourceError(source, "float out of range [%f, %f]", fd->floatmin, fd->floatmax);
- return 0;
- } //end if
- } //end if
- *(float *) p = (float) floatval;
- return 1;
- } //end if
- //
- intval = token.intvalue;
- if (negative) intval = -intval;
- //check bounds
- if ((fd->type & FT_TYPE) == FT_CHAR)
- {
- if (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 255;}
- else {intmin = -128; intmax = 127;}
- } //end if
- if ((fd->type & FT_TYPE) == FT_INT)
- {
- if (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 65535;}
- else {intmin = -32768; intmax = 32767;}
- } //end else if
- if ((fd->type & FT_TYPE) == FT_CHAR || (fd->type & FT_TYPE) == FT_INT)
- {
- if (fd->type & FT_BOUNDED)
- {
- intmin = Maximum(intmin, fd->floatmin);
- intmax = Minimum(intmax, fd->floatmax);
- } //end if
- if (intval < intmin || intval > intmax)
- {
- SourceError(source, "value %d out of range [%d, %d]", intval, intmin, intmax);
- return 0;
- } //end if
- } //end if
- else if ((fd->type & FT_TYPE) == FT_FLOAT)
- {
- if (fd->type & FT_BOUNDED)
- {
- if (intval < fd->floatmin || intval > fd->floatmax)
- {
- SourceError(source, "value %d out of range [%f, %f]", intval, fd->floatmin, fd->floatmax);
- return 0;
- } //end if
- } //end if
- } //end else if
- //store the value
- if ((fd->type & FT_TYPE) == FT_CHAR)
- {
- if (fd->type & FT_UNSIGNED) *(unsigned char *) p = (unsigned char) intval;
- else *(char *) p = (char) intval;
- } //end if
- else if ((fd->type & FT_TYPE) == FT_INT)
- {
- if (fd->type & FT_UNSIGNED) *(unsigned int *) p = (unsigned int) intval;
- else *(int *) p = (int) intval;
- } //end else
- else if ((fd->type & FT_TYPE) == FT_FLOAT)
- {
- *(float *) p = (float) intval;
- } //end else
- return 1;
-} //end of the function ReadNumber
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-qboolean ReadChar(source_t *source, fielddef_t *fd, void *p)
-{
- token_t token;
-
- if (!PC_ExpectAnyToken(source, &token)) return 0;
-
- //take literals into account
- if (token.type == TT_LITERAL)
- {
- StripSingleQuotes(token.string);
- *(char *) p = token.string[0];
- } //end if
- else
- {
- PC_UnreadLastToken(source);
- if (!ReadNumber(source, fd, p)) return 0;
- } //end if
- return 1;
-} //end of the function ReadChar
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int ReadString(source_t *source, fielddef_t *fd, void *p)
-{
- token_t token;
-
- if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) return 0;
- //remove the double quotes
- StripDoubleQuotes(token.string);
- //copy the string
- strncpy((char *) p, token.string, MAX_STRINGFIELD);
- //make sure the string is closed with a zero
- ((char *)p)[MAX_STRINGFIELD-1] = '\0';
- //
- return 1;
-} //end of the function ReadString
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int ReadStructure(source_t *source, structdef_t *def, char *structure)
-{
- token_t token;
- fielddef_t *fd;
- void *p;
- int num;
-
- if (!PC_ExpectTokenString(source, "{")) return 0;
- while(1)
- {
- if (!PC_ExpectAnyToken(source, &token)) return qfalse;
- //if end of structure
- if (!strcmp(token.string, "}")) break;
- //find the field with the name
- fd = FindField(def->fields, token.string);
- if (!fd)
- {
- SourceError(source, "unknown structure field %s", token.string);
- return qfalse;
- } //end if
- if (fd->type & FT_ARRAY)
- {
- num = fd->maxarray;
- if (!PC_ExpectTokenString(source, "{")) return qfalse;
- } //end if
- else
- {
- num = 1;
- } //end else
- p = (void *)(structure + fd->offset);
- while (num-- > 0)
- {
- if (fd->type & FT_ARRAY)
- {
- if (PC_CheckTokenString(source, "}")) break;
- } //end if
- switch(fd->type & FT_TYPE)
- {
- case FT_CHAR:
- {
- if (!ReadChar(source, fd, p)) return qfalse;
- p = (char *) p + sizeof(char);
- break;
- } //end case
- case FT_INT:
- {
- if (!ReadNumber(source, fd, p)) return qfalse;
- p = (char *) p + sizeof(int);
- break;
- } //end case
- case FT_FLOAT:
- {
- if (!ReadNumber(source, fd, p)) return qfalse;
- p = (char *) p + sizeof(float);
- break;
- } //end case
- case FT_STRING:
- {
- if (!ReadString(source, fd, p)) return qfalse;
- p = (char *) p + MAX_STRINGFIELD;
- break;
- } //end case
- case FT_STRUCT:
- {
- if (!fd->substruct)
- {
- SourceError(source, "BUG: no sub structure defined");
- return qfalse;
- } //end if
- ReadStructure(source, fd->substruct, (char *) p);
- p = (char *) p + fd->substruct->size;
- break;
- } //end case
- } //end switch
- if (fd->type & FT_ARRAY)
- {
- if (!PC_ExpectAnyToken(source, &token)) return qfalse;
- if (!strcmp(token.string, "}")) break;
- if (strcmp(token.string, ","))
- {
- SourceError(source, "expected a comma, found %s", token.string);
- return qfalse;
- } //end if
- } //end if
- } //end while
- } //end while
- return qtrue;
-} //end of the function ReadStructure
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int WriteIndent(FILE *fp, int indent)
-{
- while(indent-- > 0)
- {
- if (fprintf(fp, "\t") < 0) return qfalse;
- } //end while
- return qtrue;
-} //end of the function WriteIndent
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int WriteFloat(FILE *fp, float value)
-{
- char buf[128];
- int l;
-
- Com_sprintf(buf, sizeof(buf), "%f", value);
- l = strlen(buf);
- //strip any trailing zeros
- while(l-- > 1)
- {
- if (buf[l] != '0' && buf[l] != '.') break;
- if (buf[l] == '.')
- {
- buf[l] = 0;
- break;
- } //end if
- buf[l] = 0;
- } //end while
- //write the float to file
- if (fprintf(fp, "%s", buf) < 0) return 0;
- return 1;
-} //end of the function WriteFloat
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int WriteStructWithIndent(FILE *fp, structdef_t *def, char *structure, int indent)
-{
- int i, num;
- void *p;
- fielddef_t *fd;
-
- if (!WriteIndent(fp, indent)) return qfalse;
- if (fprintf(fp, "{\r\n") < 0) return qfalse;
-
- indent++;
- for (i = 0; def->fields[i].name; i++)
- {
- fd = &def->fields[i];
- if (!WriteIndent(fp, indent)) return qfalse;
- if (fprintf(fp, "%s\t", fd->name) < 0) return qfalse;
- p = (void *)(structure + fd->offset);
- if (fd->type & FT_ARRAY)
- {
- num = fd->maxarray;
- if (fprintf(fp, "{") < 0) return qfalse;
- } //end if
- else
- {
- num = 1;
- } //end else
- while(num-- > 0)
- {
- switch(fd->type & FT_TYPE)
- {
- case FT_CHAR:
- {
- if (fprintf(fp, "%d", *(char *) p) < 0) return qfalse;
- p = (char *) p + sizeof(char);
- break;
- } //end case
- case FT_INT:
- {
- if (fprintf(fp, "%d", *(int *) p) < 0) return qfalse;
- p = (char *) p + sizeof(int);
- break;
- } //end case
- case FT_FLOAT:
- {
- if (!WriteFloat(fp, *(float *)p)) return qfalse;
- p = (char *) p + sizeof(float);
- break;
- } //end case
- case FT_STRING:
- {
- if (fprintf(fp, "\"%s\"", (char *) p) < 0) return qfalse;
- p = (char *) p + MAX_STRINGFIELD;
- break;
- } //end case
- case FT_STRUCT:
- {
- if (!WriteStructWithIndent(fp, fd->substruct, structure, indent)) return qfalse;
- p = (char *) p + fd->substruct->size;
- break;
- } //end case
- } //end switch
- if (fd->type & FT_ARRAY)
- {
- if (num > 0)
- {
- if (fprintf(fp, ",") < 0) return qfalse;
- } //end if
- else
- {
- if (fprintf(fp, "}") < 0) return qfalse;
- } //end else
- } //end if
- } //end while
- if (fprintf(fp, "\r\n") < 0) return qfalse;
- } //end for
- indent--;
-
- if (!WriteIndent(fp, indent)) return qfalse;
- if (fprintf(fp, "}\r\n") < 0) return qfalse;
- return qtrue;
-} //end of the function WriteStructWithIndent
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int WriteStructure(FILE *fp, structdef_t *def, char *structure)
-{
- return WriteStructWithIndent(fp, def, structure, 0);
-} //end of the function WriteStructure
-
diff --git a/engine/code/cgame/cg_consolecmds.c b/engine/code/cgame/cg_consolecmds.c
deleted file mode 100644
index c8f8019..0000000
--- a/engine/code/cgame/cg_consolecmds.c
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_consolecmds.c -- text commands typed in at the local console, or
-// executed by a key binding
-
-#include "cg_local.h"
-#include "../ui/ui_shared.h"
-#ifdef MISSIONPACK
-extern menuDef_t *menuScoreboard;
-#endif
-
-
-
-void CG_TargetCommand_f( void ) {
- int targetNum;
- char test[4];
-
- targetNum = CG_CrosshairPlayer();
- if (!targetNum ) {
- return;
- }
-
- trap_Argv( 1, test, 4 );
- trap_SendConsoleCommand( va( "gc %i %i", targetNum, atoi( test ) ) );
-}
-
-
-
-/*
-=================
-CG_SizeUp_f
-
-Keybinding command
-=================
-*/
-static void CG_SizeUp_f (void) {
- trap_Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize.integer+10)));
-}
-
-
-/*
-=================
-CG_SizeDown_f
-
-Keybinding command
-=================
-*/
-static void CG_SizeDown_f (void) {
- trap_Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize.integer-10)));
-}
-
-
-/*
-=============
-CG_Viewpos_f
-
-Debugging command to print the current position
-=============
-*/
-static void CG_Viewpos_f (void) {
- CG_Printf ("(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0],
- (int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2],
- (int)cg.refdefViewAngles[YAW]);
-}
-
-
-static void CG_ScoresDown_f( void ) {
-
-#ifdef MISSIONPACK
- CG_BuildSpectatorString();
-#endif
- if ( cg.scoresRequestTime + 2000 < cg.time ) {
- // the scores are more than two seconds out of data,
- // so request new ones
- cg.scoresRequestTime = cg.time;
- trap_SendClientCommand( "score" );
-
- // leave the current scores up if they were already
- // displayed, but if this is the first hit, clear them out
- if ( !cg.showScores ) {
- cg.showScores = qtrue;
- cg.numScores = 0;
- }
- } else {
- // show the cached contents even if they just pressed if it
- // is within two seconds
- cg.showScores = qtrue;
- }
-}
-
-static void CG_ScoresUp_f( void ) {
- if ( cg.showScores ) {
- cg.showScores = qfalse;
- cg.scoreFadeTime = cg.time;
- }
-}
-
-#ifdef MISSIONPACK
-extern menuDef_t *menuScoreboard;
-void Menu_Reset( void ); // FIXME: add to right include file
-
-static void CG_LoadHud_f( void) {
- char buff[1024];
- const char *hudSet;
- memset(buff, 0, sizeof(buff));
-
- String_Init();
- Menu_Reset();
-
- trap_Cvar_VariableStringBuffer("cg_hudFiles", buff, sizeof(buff));
- hudSet = buff;
- if (hudSet[0] == '\0') {
- hudSet = "ui/hud.txt";
- }
-
- CG_LoadMenus(hudSet);
- menuScoreboard = NULL;
-}
-
-
-static void CG_scrollScoresDown_f( void) {
- if (menuScoreboard && cg.scoreBoardShowing) {
- Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qtrue);
- Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qtrue);
- Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qtrue);
- }
-}
-
-
-static void CG_scrollScoresUp_f( void) {
- if (menuScoreboard && cg.scoreBoardShowing) {
- Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qfalse);
- Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qfalse);
- Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qfalse);
- }
-}
-
-
-static void CG_spWin_f( void) {
- trap_Cvar_Set("cg_cameraOrbit", "2");
- trap_Cvar_Set("cg_cameraOrbitDelay", "35");
- trap_Cvar_Set("cg_thirdPerson", "1");
- trap_Cvar_Set("cg_thirdPersonAngle", "0");
- trap_Cvar_Set("cg_thirdPersonRange", "100");
- CG_AddBufferedSound(cgs.media.winnerSound);
- //trap_S_StartLocalSound(cgs.media.winnerSound, CHAN_ANNOUNCER);
- CG_CenterPrint("YOU WIN!", SCREEN_HEIGHT * .30, 0);
-}
-
-static void CG_spLose_f( void) {
- trap_Cvar_Set("cg_cameraOrbit", "2");
- trap_Cvar_Set("cg_cameraOrbitDelay", "35");
- trap_Cvar_Set("cg_thirdPerson", "1");
- trap_Cvar_Set("cg_thirdPersonAngle", "0");
- trap_Cvar_Set("cg_thirdPersonRange", "100");
- CG_AddBufferedSound(cgs.media.loserSound);
- //trap_S_StartLocalSound(cgs.media.loserSound, CHAN_ANNOUNCER);
- CG_CenterPrint("YOU LOSE...", SCREEN_HEIGHT * .30, 0);
-}
-
-#endif
-
-static void CG_TellTarget_f( void ) {
- int clientNum;
- char command[128];
- char message[128];
-
- clientNum = CG_CrosshairPlayer();
- if ( clientNum == -1 ) {
- return;
- }
-
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "tell %i %s", clientNum, message );
- trap_SendClientCommand( command );
-}
-
-static void CG_TellAttacker_f( void ) {
- int clientNum;
- char command[128];
- char message[128];
-
- clientNum = CG_LastAttacker();
- if ( clientNum == -1 ) {
- return;
- }
-
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "tell %i %s", clientNum, message );
- trap_SendClientCommand( command );
-}
-
-static void CG_VoiceTellTarget_f( void ) {
- int clientNum;
- char command[128];
- char message[128];
-
- clientNum = CG_CrosshairPlayer();
- if ( clientNum == -1 ) {
- return;
- }
-
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "vtell %i %s", clientNum, message );
- trap_SendClientCommand( command );
-}
-
-static void CG_VoiceTellAttacker_f( void ) {
- int clientNum;
- char command[128];
- char message[128];
-
- clientNum = CG_LastAttacker();
- if ( clientNum == -1 ) {
- return;
- }
-
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "vtell %i %s", clientNum, message );
- trap_SendClientCommand( command );
-}
-
-#ifdef MISSIONPACK
-static void CG_NextTeamMember_f( void ) {
- CG_SelectNextPlayer();
-}
-
-static void CG_PrevTeamMember_f( void ) {
- CG_SelectPrevPlayer();
-}
-
-// ASS U ME's enumeration order as far as task specific orders, OFFENSE is zero, CAMP is last
-//
-static void CG_NextOrder_f( void ) {
- clientInfo_t *ci = cgs.clientinfo + cg.snap->ps.clientNum;
- if (ci) {
- if (!ci->teamLeader && sortedTeamPlayers[cg_currentSelectedPlayer.integer] != cg.snap->ps.clientNum) {
- return;
- }
- }
- if (cgs.currentOrder < TEAMTASK_CAMP) {
- cgs.currentOrder++;
-
- if (cgs.currentOrder == TEAMTASK_RETRIEVE) {
- if (!CG_OtherTeamHasFlag()) {
- cgs.currentOrder++;
- }
- }
-
- if (cgs.currentOrder == TEAMTASK_ESCORT) {
- if (!CG_YourTeamHasFlag()) {
- cgs.currentOrder++;
- }
- }
-
- } else {
- cgs.currentOrder = TEAMTASK_OFFENSE;
- }
- cgs.orderPending = qtrue;
- cgs.orderTime = cg.time + 3000;
-}
-
-
-static void CG_ConfirmOrder_f (void ) {
- trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_YES));
- trap_SendConsoleCommand("+button5; wait; -button5");
- if (cg.time < cgs.acceptOrderTime) {
- trap_SendClientCommand(va("teamtask %d\n", cgs.acceptTask));
- cgs.acceptOrderTime = 0;
- }
-}
-
-static void CG_DenyOrder_f (void ) {
- trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_NO));
- trap_SendConsoleCommand("+button6; wait; -button6");
- if (cg.time < cgs.acceptOrderTime) {
- cgs.acceptOrderTime = 0;
- }
-}
-
-static void CG_TaskOffense_f (void ) {
- if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONGETFLAG));
- } else {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONOFFENSE));
- }
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_OFFENSE));
-}
-
-static void CG_TaskDefense_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONDEFENSE));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_DEFENSE));
-}
-
-static void CG_TaskPatrol_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONPATROL));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_PATROL));
-}
-
-static void CG_TaskCamp_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONCAMPING));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_CAMP));
-}
-
-static void CG_TaskFollow_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOW));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_FOLLOW));
-}
-
-static void CG_TaskRetrieve_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONRETURNFLAG));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_RETRIEVE));
-}
-
-static void CG_TaskEscort_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOWCARRIER));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_ESCORT));
-}
-
-static void CG_TaskOwnFlag_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_IHAVEFLAG));
-}
-
-static void CG_TauntKillInsult_f (void ) {
- trap_SendConsoleCommand("cmd vsay kill_insult\n");
-}
-
-static void CG_TauntPraise_f (void ) {
- trap_SendConsoleCommand("cmd vsay praise\n");
-}
-
-static void CG_TauntTaunt_f (void ) {
- trap_SendConsoleCommand("cmd vtaunt\n");
-}
-
-static void CG_TauntDeathInsult_f (void ) {
- trap_SendConsoleCommand("cmd vsay death_insult\n");
-}
-
-static void CG_TauntGauntlet_f (void ) {
- trap_SendConsoleCommand("cmd vsay kill_guantlet\n");
-}
-
-static void CG_TaskSuicide_f (void ) {
- int clientNum;
- char command[128];
-
- clientNum = CG_CrosshairPlayer();
- if ( clientNum == -1 ) {
- return;
- }
-
- Com_sprintf( command, 128, "tell %i suicide", clientNum );
- trap_SendClientCommand( command );
-}
-
-
-
-/*
-==================
-CG_TeamMenu_f
-==================
-*/
-/*
-static void CG_TeamMenu_f( void ) {
- if (trap_Key_GetCatcher() & KEYCATCH_CGAME) {
- CG_EventHandling(CGAME_EVENT_NONE);
- trap_Key_SetCatcher(0);
- } else {
- CG_EventHandling(CGAME_EVENT_TEAMMENU);
- //trap_Key_SetCatcher(KEYCATCH_CGAME);
- }
-}
-*/
-
-/*
-==================
-CG_EditHud_f
-==================
-*/
-/*
-static void CG_EditHud_f( void ) {
- //cls.keyCatchers ^= KEYCATCH_CGAME;
- //VM_Call (cgvm, CG_EVENT_HANDLING, (cls.keyCatchers & KEYCATCH_CGAME) ? CGAME_EVENT_EDITHUD : CGAME_EVENT_NONE);
-}
-*/
-
-#endif
-
-/*
-==================
-CG_StartOrbit_f
-==================
-*/
-
-static void CG_StartOrbit_f( void ) {
- char var[MAX_TOKEN_CHARS];
-
- trap_Cvar_VariableStringBuffer( "developer", var, sizeof( var ) );
- if ( !atoi(var) ) {
- return;
- }
- if (cg_cameraOrbit.value != 0) {
- trap_Cvar_Set ("cg_cameraOrbit", "0");
- trap_Cvar_Set("cg_thirdPerson", "0");
- } else {
- trap_Cvar_Set("cg_cameraOrbit", "5");
- trap_Cvar_Set("cg_thirdPerson", "1");
- trap_Cvar_Set("cg_thirdPersonAngle", "0");
- trap_Cvar_Set("cg_thirdPersonRange", "100");
- }
-}
-
-/*
-static void CG_Camera_f( void ) {
- char name[1024];
- trap_Argv( 1, name, sizeof(name));
- if (trap_loadCamera(name)) {
- cg.cameraMode = qtrue;
- trap_startCamera(cg.time);
- } else {
- CG_Printf ("Unable to load camera %s\n",name);
- }
-}
-*/
-
-
-typedef struct {
- char *cmd;
- void (*function)(void);
-} consoleCommand_t;
-
-static consoleCommand_t commands[] = {
- { "testgun", CG_TestGun_f },
- { "testmodel", CG_TestModel_f },
- { "nextframe", CG_TestModelNextFrame_f },
- { "prevframe", CG_TestModelPrevFrame_f },
- { "nextskin", CG_TestModelNextSkin_f },
- { "prevskin", CG_TestModelPrevSkin_f },
- { "viewpos", CG_Viewpos_f },
- { "+scores", CG_ScoresDown_f },
- { "-scores", CG_ScoresUp_f },
- { "+zoom", CG_ZoomDown_f },
- { "-zoom", CG_ZoomUp_f },
- { "sizeup", CG_SizeUp_f },
- { "sizedown", CG_SizeDown_f },
- { "weapnext", CG_NextWeapon_f },
- { "weapprev", CG_PrevWeapon_f },
- { "weapon", CG_Weapon_f },
- { "tell_target", CG_TellTarget_f },
- { "tell_attacker", CG_TellAttacker_f },
- { "vtell_target", CG_VoiceTellTarget_f },
- { "vtell_attacker", CG_VoiceTellAttacker_f },
- { "tcmd", CG_TargetCommand_f },
-#ifdef MISSIONPACK
- { "loadhud", CG_LoadHud_f },
- { "nextTeamMember", CG_NextTeamMember_f },
- { "prevTeamMember", CG_PrevTeamMember_f },
- { "nextOrder", CG_NextOrder_f },
- { "confirmOrder", CG_ConfirmOrder_f },
- { "denyOrder", CG_DenyOrder_f },
- { "taskOffense", CG_TaskOffense_f },
- { "taskDefense", CG_TaskDefense_f },
- { "taskPatrol", CG_TaskPatrol_f },
- { "taskCamp", CG_TaskCamp_f },
- { "taskFollow", CG_TaskFollow_f },
- { "taskRetrieve", CG_TaskRetrieve_f },
- { "taskEscort", CG_TaskEscort_f },
- { "taskSuicide", CG_TaskSuicide_f },
- { "taskOwnFlag", CG_TaskOwnFlag_f },
- { "tauntKillInsult", CG_TauntKillInsult_f },
- { "tauntPraise", CG_TauntPraise_f },
- { "tauntTaunt", CG_TauntTaunt_f },
- { "tauntDeathInsult", CG_TauntDeathInsult_f },
- { "tauntGauntlet", CG_TauntGauntlet_f },
- { "spWin", CG_spWin_f },
- { "spLose", CG_spLose_f },
- { "scoresDown", CG_scrollScoresDown_f },
- { "scoresUp", CG_scrollScoresUp_f },
-#endif
- { "startOrbit", CG_StartOrbit_f },
- //{ "camera", CG_Camera_f },
- { "loaddeferred", CG_LoadDeferredPlayers }
-};
-
-
-/*
-=================
-CG_ConsoleCommand
-
-The string has been tokenized and can be retrieved with
-Cmd_Argc() / Cmd_Argv()
-=================
-*/
-qboolean CG_ConsoleCommand( void ) {
- const char *cmd;
- int i;
-
- cmd = CG_Argv(0);
-
- for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
- if ( !Q_stricmp( cmd, commands[i].cmd ) ) {
- commands[i].function();
- return qtrue;
- }
- }
-
- return qfalse;
-}
-
-
-/*
-=================
-CG_InitConsoleCommands
-
-Let the client system know about all of our commands
-so it can perform tab completion
-=================
-*/
-void CG_InitConsoleCommands( void ) {
- int i;
-
- for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
- trap_AddCommand( commands[i].cmd );
- }
-
- //
- // the game server will interpret these commands, which will be automatically
- // forwarded to the server after they are not recognized locally
- //
- trap_AddCommand ("kill");
- trap_AddCommand ("say");
- trap_AddCommand ("say_team");
- trap_AddCommand ("tell");
- trap_AddCommand ("vsay");
- trap_AddCommand ("vsay_team");
- trap_AddCommand ("vtell");
- trap_AddCommand ("vtaunt");
- trap_AddCommand ("vosay");
- trap_AddCommand ("vosay_team");
- trap_AddCommand ("votell");
- trap_AddCommand ("give");
- trap_AddCommand ("god");
- trap_AddCommand ("notarget");
- trap_AddCommand ("noclip");
- trap_AddCommand ("team");
- trap_AddCommand ("follow");
- trap_AddCommand ("levelshot");
- trap_AddCommand ("addbot");
- trap_AddCommand ("setviewpos");
- trap_AddCommand ("callvote");
- trap_AddCommand ("vote");
- trap_AddCommand ("callteamvote");
- trap_AddCommand ("teamvote");
- trap_AddCommand ("stats");
- trap_AddCommand ("teamtask");
- trap_AddCommand ("loaddefered"); // spelled wrong, but not changing for demo
-}
diff --git a/engine/code/cgame/cg_draw.c b/engine/code/cgame/cg_draw.c
deleted file mode 100644
index 554f4f1..0000000
--- a/engine/code/cgame/cg_draw.c
+++ /dev/null
@@ -1,2663 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_draw.c -- draw all of the graphical elements during
-// active (after loading) gameplay
-
-#include "cg_local.h"
-
-#ifdef MISSIONPACK
-#include "../ui/ui_shared.h"
-
-// used for scoreboard
-extern displayContextDef_t cgDC;
-menuDef_t *menuScoreboard = NULL;
-#else
-int drawTeamOverlayModificationCount = -1;
-#endif
-
-int sortedTeamPlayers[TEAM_MAXOVERLAY];
-int numSortedTeamPlayers;
-
-char systemChat[256];
-char teamChat1[256];
-char teamChat2[256];
-
-#ifdef MISSIONPACK
-
-int CG_Text_Width(const char *text, float scale, int limit) {
- int count,len;
- float out;
- glyphInfo_t *glyph;
- float useScale;
-// FIXME: see ui_main.c, same problem
-// const unsigned char *s = text;
- const char *s = text;
- fontInfo_t *font = &cgDC.Assets.textFont;
- if (scale <= cg_smallFont.value) {
- font = &cgDC.Assets.smallFont;
- } else if (scale > cg_bigFont.value) {
- font = &cgDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- out = 0;
- if (text) {
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- if ( Q_IsColorString(s) ) {
- s += 2;
- continue;
- } else {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- out += glyph->xSkip;
- s++;
- count++;
- }
- }
- }
- return out * useScale;
-}
-
-int CG_Text_Height(const char *text, float scale, int limit) {
- int len, count;
- float max;
- glyphInfo_t *glyph;
- float useScale;
-// TTimo: FIXME
-// const unsigned char *s = text;
- const char *s = text;
- fontInfo_t *font = &cgDC.Assets.textFont;
- if (scale <= cg_smallFont.value) {
- font = &cgDC.Assets.smallFont;
- } else if (scale > cg_bigFont.value) {
- font = &cgDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- max = 0;
- if (text) {
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- if ( Q_IsColorString(s) ) {
- s += 2;
- continue;
- } else {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- if (max < glyph->height) {
- max = glyph->height;
- }
- s++;
- count++;
- }
- }
- }
- return max * useScale;
-}
-
-void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
- float w, h;
- w = width * scale;
- h = height * scale;
- CG_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
-}
-
-void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph;
- float useScale;
- fontInfo_t *font = &cgDC.Assets.textFont;
- if (scale <= cg_smallFont.value) {
- font = &cgDC.Assets.smallFont;
- } else if (scale > cg_bigFont.value) {
- font = &cgDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- if (text) {
-// TTimo: FIXME
-// const unsigned char *s = text;
- const char *s = text;
- trap_R_SetColor( color );
- memcpy(&newColor[0], &color[0], sizeof(vec4_t));
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
- //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- float yadj = useScale * glyph->top;
- if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
- int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
- colorBlack[3] = newColor[3];
- trap_R_SetColor( colorBlack );
- CG_Text_PaintChar(x + ofs, y - yadj + ofs,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- colorBlack[3] = 1.0;
- trap_R_SetColor( newColor );
- }
- CG_Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- // CG_DrawPic(x, y - yadj, scale * cgDC.Assets.textFont.glyphs[text[i]].imageWidth, scale * cgDC.Assets.textFont.glyphs[text[i]].imageHeight, cgDC.Assets.textFont.glyphs[text[i]].glyph);
- x += (glyph->xSkip * useScale) + adjust;
- s++;
- count++;
- }
- }
- trap_R_SetColor( NULL );
- }
-}
-
-
-#endif
-
-/*
-==============
-CG_DrawField
-
-Draws large numbers for status bar and powerups
-==============
-*/
-#ifndef MISSIONPACK
-static void CG_DrawField (int x, int y, int width, int value) {
- char num[16], *ptr;
- int l;
- int frame;
-
- if ( width < 1 ) {
- return;
- }
-
- // draw number string
- if ( width > 5 ) {
- width = 5;
- }
-
- switch ( width ) {
- case 1:
- value = value > 9 ? 9 : value;
- value = value < 0 ? 0 : value;
- break;
- case 2:
- value = value > 99 ? 99 : value;
- value = value < -9 ? -9 : value;
- break;
- case 3:
- value = value > 999 ? 999 : value;
- value = value < -99 ? -99 : value;
- break;
- case 4:
- value = value > 9999 ? 9999 : value;
- value = value < -999 ? -999 : value;
- break;
- }
-
- Com_sprintf (num, sizeof(num), "%i", value);
- l = strlen(num);
- if (l > width)
- l = width;
- x += 2 + CHAR_WIDTH*(width - l);
-
- ptr = num;
- while (*ptr && l)
- {
- if (*ptr == '-')
- frame = STAT_MINUS;
- else
- frame = *ptr -'0';
-
- CG_DrawPic( x,y, CHAR_WIDTH, CHAR_HEIGHT, cgs.media.numberShaders[frame] );
- x += CHAR_WIDTH;
- ptr++;
- l--;
- }
-}
-#endif // MISSIONPACK
-
-/*
-================
-CG_Draw3DModel
-
-================
-*/
-void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles ) {
- refdef_t refdef;
- refEntity_t ent;
-
- if ( !cg_draw3dIcons.integer || !cg_drawIcons.integer ) {
- return;
- }
-
- CG_AdjustFrom640( &x, &y, &w, &h );
-
- memset( &refdef, 0, sizeof( refdef ) );
-
- memset( &ent, 0, sizeof( ent ) );
- AnglesToAxis( angles, ent.axis );
- VectorCopy( origin, ent.origin );
- ent.hModel = model;
- ent.customSkin = skin;
- ent.renderfx = RF_NOSHADOW; // no stencil shadows
-
- refdef.rdflags = RDF_NOWORLDMODEL;
-
- AxisClear( refdef.viewaxis );
-
- refdef.fov_x = 30;
- refdef.fov_y = 30;
-
- refdef.x = x;
- refdef.y = y;
- refdef.width = w;
- refdef.height = h;
-
- refdef.time = cg.time;
-
- trap_R_ClearScene();
- trap_R_AddRefEntityToScene( &ent );
- trap_R_RenderScene( &refdef );
-}
-
-/*
-================
-CG_DrawHead
-
-Used for both the status bar and the scoreboard
-================
-*/
-void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles ) {
- clipHandle_t cm;
- clientInfo_t *ci;
- float len;
- vec3_t origin;
- vec3_t mins, maxs;
-
- ci = &cgs.clientinfo[ clientNum ];
-
- if ( cg_draw3dIcons.integer ) {
- cm = ci->headModel;
- if ( !cm ) {
- return;
- }
-
- // offset the origin y and z to center the head
- trap_R_ModelBounds( cm, mins, maxs );
-
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
-
- // calculate distance so the head nearly fills the box
- // assume heads are taller than wide
- len = 0.7 * ( maxs[2] - mins[2] );
- origin[0] = len / 0.268; // len / tan( fov/2 )
-
- // allow per-model tweaking
- VectorAdd( origin, ci->headOffset, origin );
-
- CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, origin, headAngles );
- } else if ( cg_drawIcons.integer ) {
- CG_DrawPic( x, y, w, h, ci->modelIcon );
- }
-
- // if they are deferred, draw a cross out
- if ( ci->deferred ) {
- CG_DrawPic( x, y, w, h, cgs.media.deferShader );
- }
-}
-
-/*
-================
-CG_DrawFlagModel
-
-Used for both the status bar and the scoreboard
-================
-*/
-void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D ) {
- qhandle_t cm;
- float len;
- vec3_t origin, angles;
- vec3_t mins, maxs;
- qhandle_t handle;
-
- if ( !force2D && cg_draw3dIcons.integer ) {
-
- VectorClear( angles );
-
- cm = cgs.media.redFlagModel;
-
- // offset the origin y and z to center the flag
- trap_R_ModelBounds( cm, mins, maxs );
-
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
-
- // calculate distance so the flag nearly fills the box
- // assume heads are taller than wide
- len = 0.5 * ( maxs[2] - mins[2] );
- origin[0] = len / 0.268; // len / tan( fov/2 )
-
- angles[YAW] = 60 * sin( cg.time / 2000.0 );;
-
- if( team == TEAM_RED ) {
- handle = cgs.media.redFlagModel;
- } else if( team == TEAM_BLUE ) {
- handle = cgs.media.blueFlagModel;
- } else if( team == TEAM_FREE ) {
- handle = cgs.media.neutralFlagModel;
- } else {
- return;
- }
- CG_Draw3DModel( x, y, w, h, handle, 0, origin, angles );
- } else if ( cg_drawIcons.integer ) {
- gitem_t *item;
-
- if( team == TEAM_RED ) {
- item = BG_FindItemForPowerup( PW_REDFLAG );
- } else if( team == TEAM_BLUE ) {
- item = BG_FindItemForPowerup( PW_BLUEFLAG );
- } else if( team == TEAM_FREE ) {
- item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
- } else {
- return;
- }
- if (item) {
- CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon );
- }
- }
-}
-
-/*
-================
-CG_DrawStatusBarHead
-
-================
-*/
-#ifndef MISSIONPACK
-
-static void CG_DrawStatusBarHead( float x ) {
- vec3_t angles;
- float size, stretch;
- float frac;
-
- VectorClear( angles );
-
- if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) {
- frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME;
- size = ICON_SIZE * 1.25 * ( 1.5 - frac * 0.5 );
-
- stretch = size - ICON_SIZE * 1.25;
- // kick in the direction of damage
- x -= stretch * 0.5 + cg.damageX * stretch * 0.5;
-
- cg.headStartYaw = 180 + cg.damageX * 45;
-
- cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
- cg.headEndPitch = 5 * cos( crandom()*M_PI );
-
- cg.headStartTime = cg.time;
- cg.headEndTime = cg.time + 100 + random() * 2000;
- } else {
- if ( cg.time >= cg.headEndTime ) {
- // select a new head angle
- cg.headStartYaw = cg.headEndYaw;
- cg.headStartPitch = cg.headEndPitch;
- cg.headStartTime = cg.headEndTime;
- cg.headEndTime = cg.time + 100 + random() * 2000;
-
- cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
- cg.headEndPitch = 5 * cos( crandom()*M_PI );
- }
-
- size = ICON_SIZE * 1.25;
- }
-
- // if the server was frozen for a while we may have a bad head start time
- if ( cg.headStartTime > cg.time ) {
- cg.headStartTime = cg.time;
- }
-
- frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime );
- frac = frac * frac * ( 3 - 2 * frac );
- angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac;
- angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac;
-
- CG_DrawHead( x, 480 - size, size, size,
- cg.snap->ps.clientNum, angles );
-}
-#endif // MISSIONPACK
-
-/*
-================
-CG_DrawStatusBarFlag
-
-================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawStatusBarFlag( float x, int team ) {
- CG_DrawFlagModel( x, 480 - ICON_SIZE, ICON_SIZE, ICON_SIZE, team, qfalse );
-}
-#endif // MISSIONPACK
-
-/*
-================
-CG_DrawTeamBackground
-
-================
-*/
-void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team )
-{
- vec4_t hcolor;
-
- hcolor[3] = alpha;
- if ( team == TEAM_RED ) {
- hcolor[0] = 1;
- hcolor[1] = 0;
- hcolor[2] = 0;
- } else if ( team == TEAM_BLUE ) {
- hcolor[0] = 0;
- hcolor[1] = 0;
- hcolor[2] = 1;
- } else {
- return;
- }
- trap_R_SetColor( hcolor );
- CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
- trap_R_SetColor( NULL );
-}
-
-/*
-================
-CG_DrawStatusBar
-
-================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawStatusBar( void ) {
- int color;
- centity_t *cent;
- playerState_t *ps;
- int value;
- vec4_t hcolor;
- vec3_t angles;
- vec3_t origin;
-
- static float colors[4][4] = {
-// { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} };
- { 1.0f, 0.69f, 0.0f, 1.0f }, // normal
- { 1.0f, 0.2f, 0.2f, 1.0f }, // low health
- { 0.5f, 0.5f, 0.5f, 1.0f }, // weapon firing
- { 1.0f, 1.0f, 1.0f, 1.0f } }; // health > 100
-
- if ( cg_drawStatus.integer == 0 ) {
- return;
- }
-
- // draw the team background
- CG_DrawTeamBackground( 0, 420, 640, 60, 0.33f, cg.snap->ps.persistant[PERS_TEAM] );
-
- cent = &cg_entities[cg.snap->ps.clientNum];
- ps = &cg.snap->ps;
-
- VectorClear( angles );
-
- // draw any 3D icons first, so the changes back to 2D are minimized
- if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) {
- origin[0] = 70;
- origin[1] = 0;
- origin[2] = 0;
- angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 );
- CG_Draw3DModel( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
- cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles );
- }
-
- CG_DrawStatusBarHead( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE );
-
- if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) {
- CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_RED );
- } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) {
- CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_BLUE );
- } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) {
- CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_FREE );
- }
-
- if ( ps->stats[ STAT_ARMOR ] ) {
- origin[0] = 90;
- origin[1] = 0;
- origin[2] = -10;
- angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
- CG_Draw3DModel( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
- cgs.media.armorModel, 0, origin, angles );
- }
- //
- // ammo
- //
- if ( cent->currentState.weapon ) {
- value = ps->ammo[cent->currentState.weapon];
- if ( value > -1 ) {
- if ( cg.predictedPlayerState.weaponstate == WEAPON_FIRING
- && cg.predictedPlayerState.weaponTime > 100 ) {
- // draw as dark grey when reloading
- color = 2; // dark grey
- } else {
- if ( value >= 0 ) {
- color = 0; // green
- } else {
- color = 1; // red
- }
- }
- trap_R_SetColor( colors[color] );
-
- CG_DrawField (0, 432, 3, value);
- trap_R_SetColor( NULL );
-
- // if we didn't draw a 3D icon, draw a 2D icon for ammo
- if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
- qhandle_t icon;
-
- icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon;
- if ( icon ) {
- CG_DrawPic( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, icon );
- }
- }
- }
- }
-
- //
- // health
- //
- value = ps->stats[STAT_HEALTH];
- if ( value > 100 ) {
- trap_R_SetColor( colors[3] ); // white
- } else if (value > 25) {
- trap_R_SetColor( colors[0] ); // green
- } else if (value > 0) {
- color = (cg.time >> 8) & 1; // flash
- trap_R_SetColor( colors[color] );
- } else {
- trap_R_SetColor( colors[1] ); // red
- }
-
- // stretch the health up when taking damage
- CG_DrawField ( 185, 432, 3, value);
- CG_ColorForHealth( hcolor );
- trap_R_SetColor( hcolor );
-
-
- //
- // armor
- //
- value = ps->stats[STAT_ARMOR];
- if (value > 0 ) {
- trap_R_SetColor( colors[0] );
- CG_DrawField (370, 432, 3, value);
- trap_R_SetColor( NULL );
- // if we didn't draw a 3D icon, draw a 2D icon for armor
- if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
- CG_DrawPic( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, cgs.media.armorIcon );
- }
-
- }
-}
-#endif
-
-/*
-===========================================================================================
-
- UPPER RIGHT CORNER
-
-===========================================================================================
-*/
-
-/*
-================
-CG_DrawAttacker
-
-================
-*/
-static float CG_DrawAttacker( float y ) {
- int t;
- float size;
- vec3_t angles;
- const char *info;
- const char *name;
- int clientNum;
-
- if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
- return y;
- }
-
- if ( !cg.attackerTime ) {
- return y;
- }
-
- clientNum = cg.predictedPlayerState.persistant[PERS_ATTACKER];
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS || clientNum == cg.snap->ps.clientNum ) {
- return y;
- }
-
- t = cg.time - cg.attackerTime;
- if ( t > ATTACKER_HEAD_TIME ) {
- cg.attackerTime = 0;
- return y;
- }
-
- size = ICON_SIZE * 1.25;
-
- angles[PITCH] = 0;
- angles[YAW] = 180;
- angles[ROLL] = 0;
- CG_DrawHead( 640 - size, y, size, size, clientNum, angles );
-
- info = CG_ConfigString( CS_PLAYERS + clientNum );
- name = Info_ValueForKey( info, "n" );
- y += size;
- CG_DrawBigString( 640 - ( Q_PrintStrlen( name ) * BIGCHAR_WIDTH), y, name, 0.5 );
-
- return y + BIGCHAR_HEIGHT + 2;
-}
-
-/*
-==================
-CG_DrawSnapshot
-==================
-*/
-static float CG_DrawSnapshot( float y ) {
- char *s;
- int w;
-
- s = va( "time:%i snap:%i cmd:%i", cg.snap->serverTime,
- cg.latestSnapshotNum, cgs.serverCommandSequence );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
-
- CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
-
- return y + BIGCHAR_HEIGHT + 4;
-}
-
-/*
-==================
-CG_DrawFPS
-==================
-*/
-#define FPS_FRAMES 4
-static float CG_DrawFPS( float y ) {
- char *s;
- int w;
- static int previousTimes[FPS_FRAMES];
- static int index;
- int i, total;
- int fps;
- static int previous;
- int t, frameTime;
-
- // don't use serverTime, because that will be drifting to
- // correct for internet lag changes, timescales, timedemos, etc
- t = trap_Milliseconds();
- frameTime = t - previous;
- previous = t;
-
- previousTimes[index % FPS_FRAMES] = frameTime;
- index++;
- if ( index > FPS_FRAMES ) {
- // average multiple frames together to smooth changes out a bit
- total = 0;
- for ( i = 0 ; i < FPS_FRAMES ; i++ ) {
- total += previousTimes[i];
- }
- if ( !total ) {
- total = 1;
- }
- fps = 1000 * FPS_FRAMES / total;
-
- s = va( "%ifps", fps );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
-
- CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
- }
-
- return y + BIGCHAR_HEIGHT + 4;
-}
-
-/*
-=================
-CG_DrawTimer
-=================
-*/
-static float CG_DrawTimer( float y ) {
- char *s;
- int w;
- int mins, seconds, tens;
- int msec;
-
- msec = cg.time - cgs.levelStartTime;
-
- seconds = msec / 1000;
- mins = seconds / 60;
- seconds -= mins * 60;
- tens = seconds / 10;
- seconds -= tens * 10;
-
- s = va( "%i:%i%i", mins, tens, seconds );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
-
- CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
-
- return y + BIGCHAR_HEIGHT + 4;
-}
-
-
-/*
-=================
-CG_DrawTeamOverlay
-=================
-*/
-
-static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) {
- int x, w, h, xx;
- int i, j, len;
- const char *p;
- vec4_t hcolor;
- int pwidth, lwidth;
- int plyrs;
- char st[16];
- clientInfo_t *ci;
- gitem_t *item;
- int ret_y, count;
-
- if ( !cg_drawTeamOverlay.integer ) {
- return y;
- }
-
- if ( cg.snap->ps.persistant[PERS_TEAM] != TEAM_RED && cg.snap->ps.persistant[PERS_TEAM] != TEAM_BLUE ) {
- return y; // Not on any team
- }
-
- plyrs = 0;
-
- // max player name width
- pwidth = 0;
- count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers;
- for (i = 0; i < count; i++) {
- ci = cgs.clientinfo + sortedTeamPlayers[i];
- if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
- plyrs++;
- len = CG_DrawStrlen(ci->name);
- if (len > pwidth)
- pwidth = len;
- }
- }
-
- if (!plyrs)
- return y;
-
- if (pwidth > TEAM_OVERLAY_MAXNAME_WIDTH)
- pwidth = TEAM_OVERLAY_MAXNAME_WIDTH;
-
- // max location name width
- lwidth = 0;
- for (i = 1; i < MAX_LOCATIONS; i++) {
- p = CG_ConfigString(CS_LOCATIONS + i);
- if (p && *p) {
- len = CG_DrawStrlen(p);
- if (len > lwidth)
- lwidth = len;
- }
- }
-
- if (lwidth > TEAM_OVERLAY_MAXLOCATION_WIDTH)
- lwidth = TEAM_OVERLAY_MAXLOCATION_WIDTH;
-
- w = (pwidth + lwidth + 4 + 7) * TINYCHAR_WIDTH;
-
- if ( right )
- x = 640 - w;
- else
- x = 0;
-
- h = plyrs * TINYCHAR_HEIGHT;
-
- if ( upper ) {
- ret_y = y + h;
- } else {
- y -= h;
- ret_y = y;
- }
-
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
- hcolor[0] = 1.0f;
- hcolor[1] = 0.0f;
- hcolor[2] = 0.0f;
- hcolor[3] = 0.33f;
- } else { // if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE )
- hcolor[0] = 0.0f;
- hcolor[1] = 0.0f;
- hcolor[2] = 1.0f;
- hcolor[3] = 0.33f;
- }
- trap_R_SetColor( hcolor );
- CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
- trap_R_SetColor( NULL );
-
- for (i = 0; i < count; i++) {
- ci = cgs.clientinfo + sortedTeamPlayers[i];
- if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
-
- hcolor[0] = hcolor[1] = hcolor[2] = hcolor[3] = 1.0;
-
- xx = x + TINYCHAR_WIDTH;
-
- CG_DrawStringExt( xx, y,
- ci->name, hcolor, qfalse, qfalse,
- TINYCHAR_WIDTH, TINYCHAR_HEIGHT, TEAM_OVERLAY_MAXNAME_WIDTH);
-
- if (lwidth) {
- p = CG_ConfigString(CS_LOCATIONS + ci->location);
- if (!p || !*p)
- p = "unknown";
- len = CG_DrawStrlen(p);
- if (len > lwidth)
- len = lwidth;
-
-// xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth +
-// ((lwidth/2 - len/2) * TINYCHAR_WIDTH);
- xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth;
- CG_DrawStringExt( xx, y,
- p, hcolor, qfalse, qfalse, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
- TEAM_OVERLAY_MAXLOCATION_WIDTH);
- }
-
- CG_GetColorForHealth( ci->health, ci->armor, hcolor );
-
- Com_sprintf (st, sizeof(st), "%3i %3i", ci->health, ci->armor);
-
- xx = x + TINYCHAR_WIDTH * 3 +
- TINYCHAR_WIDTH * pwidth + TINYCHAR_WIDTH * lwidth;
-
- CG_DrawStringExt( xx, y,
- st, hcolor, qfalse, qfalse,
- TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
-
- // draw weapon icon
- xx += TINYCHAR_WIDTH * 3;
-
- if ( cg_weapons[ci->curWeapon].weaponIcon ) {
- CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
- cg_weapons[ci->curWeapon].weaponIcon );
- } else {
- CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
- cgs.media.deferShader );
- }
-
- // Draw powerup icons
- if (right) {
- xx = x;
- } else {
- xx = x + w - TINYCHAR_WIDTH;
- }
- for (j = 0; j <= PW_NUM_POWERUPS; j++) {
- if (ci->powerups & (1 << j)) {
-
- item = BG_FindItemForPowerup( j );
-
- if (item) {
- CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
- trap_R_RegisterShader( item->icon ) );
- if (right) {
- xx -= TINYCHAR_WIDTH;
- } else {
- xx += TINYCHAR_WIDTH;
- }
- }
- }
- }
-
- y += TINYCHAR_HEIGHT;
- }
- }
-
- return ret_y;
-//#endif
-}
-
-
-/*
-=====================
-CG_DrawUpperRight
-
-=====================
-*/
-static void CG_DrawUpperRight(stereoFrame_t stereoFrame)
-{
- float y;
-
- y = 0;
-
- if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 1 ) {
- y = CG_DrawTeamOverlay( y, qtrue, qtrue );
- }
- if ( cg_drawSnapshot.integer ) {
- y = CG_DrawSnapshot( y );
- }
- if (cg_drawFPS.integer && (stereoFrame == STEREO_CENTER || stereoFrame == STEREO_RIGHT)) {
- y = CG_DrawFPS( y );
- }
- if ( cg_drawTimer.integer ) {
- y = CG_DrawTimer( y );
- }
- if ( cg_drawAttacker.integer ) {
- y = CG_DrawAttacker( y );
- }
-
-}
-
-/*
-===========================================================================================
-
- LOWER RIGHT CORNER
-
-===========================================================================================
-*/
-
-/*
-=================
-CG_DrawScores
-
-Draw the small two score display
-=================
-*/
-#ifndef MISSIONPACK
-static float CG_DrawScores( float y ) {
- const char *s;
- int s1, s2, score;
- int x, w;
- int v;
- vec4_t color;
- float y1;
- gitem_t *item;
-
- s1 = cgs.scores1;
- s2 = cgs.scores2;
-
- y -= BIGCHAR_HEIGHT + 8;
-
- y1 = y;
-
- // draw from the right side to left
- if ( cgs.gametype >= GT_TEAM ) {
- x = 640;
- color[0] = 0.0f;
- color[1] = 0.0f;
- color[2] = 1.0f;
- color[3] = 0.33f;
- s = va( "%2i", s2 );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
- }
- CG_DrawBigString( x + 4, y, s, 1.0F);
-
- if ( cgs.gametype == GT_CTF ) {
- // Display flag status
- item = BG_FindItemForPowerup( PW_BLUEFLAG );
-
- if (item) {
- y1 = y - BIGCHAR_HEIGHT - 8;
- if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) {
- CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.blueFlagShader[cgs.blueflag] );
- }
- }
- }
- color[0] = 1.0f;
- color[1] = 0.0f;
- color[2] = 0.0f;
- color[3] = 0.33f;
- s = va( "%2i", s1 );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
- CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
- }
- CG_DrawBigString( x + 4, y, s, 1.0F);
-
- if ( cgs.gametype == GT_CTF ) {
- // Display flag status
- item = BG_FindItemForPowerup( PW_REDFLAG );
-
- if (item) {
- y1 = y - BIGCHAR_HEIGHT - 8;
- if( cgs.redflag >= 0 && cgs.redflag <= 2 ) {
- CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.redFlagShader[cgs.redflag] );
- }
- }
- }
-
- if ( cgs.gametype >= GT_CTF ) {
- v = cgs.capturelimit;
- } else {
- v = cgs.fraglimit;
- }
- if ( v ) {
- s = va( "%2i", v );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- CG_DrawBigString( x + 4, y, s, 1.0F);
- }
-
- } else {
- qboolean spectator;
-
- x = 640;
- score = cg.snap->ps.persistant[PERS_SCORE];
- spectator = ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR );
-
- // always show your score in the second box if not in first place
- if ( s1 != score ) {
- s2 = score;
- }
- if ( s2 != SCORE_NOT_PRESENT ) {
- s = va( "%2i", s2 );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- if ( !spectator && score == s2 && score != s1 ) {
- color[0] = 1.0f;
- color[1] = 0.0f;
- color[2] = 0.0f;
- color[3] = 0.33f;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
- } else {
- color[0] = 0.5f;
- color[1] = 0.5f;
- color[2] = 0.5f;
- color[3] = 0.33f;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- }
- CG_DrawBigString( x + 4, y, s, 1.0F);
- }
-
- // first place
- if ( s1 != SCORE_NOT_PRESENT ) {
- s = va( "%2i", s1 );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- if ( !spectator && score == s1 ) {
- color[0] = 0.0f;
- color[1] = 0.0f;
- color[2] = 1.0f;
- color[3] = 0.33f;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
- } else {
- color[0] = 0.5f;
- color[1] = 0.5f;
- color[2] = 0.5f;
- color[3] = 0.33f;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- }
- CG_DrawBigString( x + 4, y, s, 1.0F);
- }
-
- if ( cgs.fraglimit ) {
- s = va( "%2i", cgs.fraglimit );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- CG_DrawBigString( x + 4, y, s, 1.0F);
- }
-
- }
-
- return y1 - 8;
-}
-#endif // MISSIONPACK
-
-/*
-================
-CG_DrawPowerups
-================
-*/
-#ifndef MISSIONPACK
-static float CG_DrawPowerups( float y ) {
- int sorted[MAX_POWERUPS];
- int sortedTime[MAX_POWERUPS];
- int i, j, k;
- int active;
- playerState_t *ps;
- int t;
- gitem_t *item;
- int x;
- int color;
- float size;
- float f;
- static float colors[2][4] = {
- { 0.2f, 1.0f, 0.2f, 1.0f } ,
- { 1.0f, 0.2f, 0.2f, 1.0f }
- };
-
- ps = &cg.snap->ps;
-
- if ( ps->stats[STAT_HEALTH] <= 0 ) {
- return y;
- }
-
- // sort the list by time remaining
- active = 0;
- for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
- if ( !ps->powerups[ i ] ) {
- continue;
- }
- t = ps->powerups[ i ] - cg.time;
- // ZOID--don't draw if the power up has unlimited time (999 seconds)
- // This is true of the CTF flags
- if ( t < 0 || t > 999000) {
- continue;
- }
-
- // insert into the list
- for ( j = 0 ; j < active ; j++ ) {
- if ( sortedTime[j] >= t ) {
- for ( k = active - 1 ; k >= j ; k-- ) {
- sorted[k+1] = sorted[k];
- sortedTime[k+1] = sortedTime[k];
- }
- break;
- }
- }
- sorted[j] = i;
- sortedTime[j] = t;
- active++;
- }
-
- // draw the icons and timers
- x = 640 - ICON_SIZE - CHAR_WIDTH * 2;
- for ( i = 0 ; i < active ; i++ ) {
- item = BG_FindItemForPowerup( sorted[i] );
-
- if (item) {
-
- color = 1;
-
- y -= ICON_SIZE;
-
- trap_R_SetColor( colors[color] );
- CG_DrawField( x, y, 2, sortedTime[ i ] / 1000 );
-
- t = ps->powerups[ sorted[i] ];
- if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
- trap_R_SetColor( NULL );
- } else {
- vec4_t modulate;
-
- f = (float)( t - cg.time ) / POWERUP_BLINK_TIME;
- f -= (int)f;
- modulate[0] = modulate[1] = modulate[2] = modulate[3] = f;
- trap_R_SetColor( modulate );
- }
-
- if ( cg.powerupActive == sorted[i] &&
- cg.time - cg.powerupTime < PULSE_TIME ) {
- f = 1.0 - ( ( (float)cg.time - cg.powerupTime ) / PULSE_TIME );
- size = ICON_SIZE * ( 1.0 + ( PULSE_SCALE - 1.0 ) * f );
- } else {
- size = ICON_SIZE;
- }
-
- CG_DrawPic( 640 - size, y + ICON_SIZE / 2 - size / 2,
- size, size, trap_R_RegisterShader( item->icon ) );
- }
- }
- trap_R_SetColor( NULL );
-
- return y;
-}
-#endif // MISSIONPACK
-
-/*
-=====================
-CG_DrawLowerRight
-
-=====================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawLowerRight( void ) {
- float y;
-
- y = 480 - ICON_SIZE;
-
- if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 2 ) {
- y = CG_DrawTeamOverlay( y, qtrue, qfalse );
- }
-
- y = CG_DrawScores( y );
- y = CG_DrawPowerups( y );
-}
-#endif // MISSIONPACK
-
-/*
-===================
-CG_DrawPickupItem
-===================
-*/
-#ifndef MISSIONPACK
-static int CG_DrawPickupItem( int y ) {
- int value;
- float *fadeColor;
-
- if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
- return y;
- }
-
- y -= ICON_SIZE;
-
- value = cg.itemPickup;
- if ( value ) {
- fadeColor = CG_FadeColor( cg.itemPickupTime, 3000 );
- if ( fadeColor ) {
- CG_RegisterItemVisuals( value );
- trap_R_SetColor( fadeColor );
- CG_DrawPic( 8, y, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
- CG_DrawBigString( ICON_SIZE + 16, y + (ICON_SIZE/2 - BIGCHAR_HEIGHT/2), bg_itemlist[ value ].pickup_name, fadeColor[0] );
- trap_R_SetColor( NULL );
- }
- }
-
- return y;
-}
-#endif // MISSIONPACK
-
-/*
-=====================
-CG_DrawLowerLeft
-
-=====================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawLowerLeft( void ) {
- float y;
-
- y = 480 - ICON_SIZE;
-
- if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 3 ) {
- y = CG_DrawTeamOverlay( y, qfalse, qfalse );
- }
-
-
- y = CG_DrawPickupItem( y );
-}
-#endif // MISSIONPACK
-
-
-//===========================================================================================
-
-/*
-=================
-CG_DrawTeamInfo
-=================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawTeamInfo( void ) {
- int w, h;
- int i, len;
- vec4_t hcolor;
- int chatHeight;
-
-#define CHATLOC_Y 420 // bottom end
-#define CHATLOC_X 0
-
- if (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT)
- chatHeight = cg_teamChatHeight.integer;
- else
- chatHeight = TEAMCHAT_HEIGHT;
- if (chatHeight <= 0)
- return; // disabled
-
- if (cgs.teamLastChatPos != cgs.teamChatPos) {
- if (cg.time - cgs.teamChatMsgTimes[cgs.teamLastChatPos % chatHeight] > cg_teamChatTime.integer) {
- cgs.teamLastChatPos++;
- }
-
- h = (cgs.teamChatPos - cgs.teamLastChatPos) * TINYCHAR_HEIGHT;
-
- w = 0;
-
- for (i = cgs.teamLastChatPos; i < cgs.teamChatPos; i++) {
- len = CG_DrawStrlen(cgs.teamChatMsgs[i % chatHeight]);
- if (len > w)
- w = len;
- }
- w *= TINYCHAR_WIDTH;
- w += TINYCHAR_WIDTH * 2;
-
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
- hcolor[0] = 1.0f;
- hcolor[1] = 0.0f;
- hcolor[2] = 0.0f;
- hcolor[3] = 0.33f;
- } else if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- hcolor[0] = 0.0f;
- hcolor[1] = 0.0f;
- hcolor[2] = 1.0f;
- hcolor[3] = 0.33f;
- } else {
- hcolor[0] = 0.0f;
- hcolor[1] = 1.0f;
- hcolor[2] = 0.0f;
- hcolor[3] = 0.33f;
- }
-
- trap_R_SetColor( hcolor );
- CG_DrawPic( CHATLOC_X, CHATLOC_Y - h, 640, h, cgs.media.teamStatusBar );
- trap_R_SetColor( NULL );
-
- hcolor[0] = hcolor[1] = hcolor[2] = 1.0f;
- hcolor[3] = 1.0f;
-
- for (i = cgs.teamChatPos - 1; i >= cgs.teamLastChatPos; i--) {
- CG_DrawStringExt( CHATLOC_X + TINYCHAR_WIDTH,
- CHATLOC_Y - (cgs.teamChatPos - i)*TINYCHAR_HEIGHT,
- cgs.teamChatMsgs[i % chatHeight], hcolor, qfalse, qfalse,
- TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
- }
- }
-}
-#endif // MISSIONPACK
-
-/*
-===================
-CG_DrawHoldableItem
-===================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawHoldableItem( void ) {
- int value;
-
- value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM];
- if ( value ) {
- CG_RegisterItemVisuals( value );
- CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
- }
-
-}
-#endif // MISSIONPACK
-
-#ifdef MISSIONPACK
-/*
-===================
-CG_DrawPersistantPowerup
-===================
-*/
-#if 0 // sos001208 - DEAD
-static void CG_DrawPersistantPowerup( void ) {
- int value;
-
- value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP];
- if ( value ) {
- CG_RegisterItemVisuals( value );
- CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2 - ICON_SIZE, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
- }
-}
-#endif
-#endif // MISSIONPACK
-
-
-/*
-===================
-CG_DrawReward
-===================
-*/
-static void CG_DrawReward( void ) {
- float *color;
- int i, count;
- float x, y;
- char buf[32];
-
- if ( !cg_drawRewards.integer ) {
- return;
- }
-
- color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
- if ( !color ) {
- if (cg.rewardStack > 0) {
- for(i = 0; i < cg.rewardStack; i++) {
- cg.rewardSound[i] = cg.rewardSound[i+1];
- cg.rewardShader[i] = cg.rewardShader[i+1];
- cg.rewardCount[i] = cg.rewardCount[i+1];
- }
- cg.rewardTime = cg.time;
- cg.rewardStack--;
- color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
- trap_S_StartLocalSound(cg.rewardSound[0], CHAN_ANNOUNCER);
- } else {
- return;
- }
- }
-
- trap_R_SetColor( color );
-
- /*
- count = cg.rewardCount[0]/10; // number of big rewards to draw
-
- if (count) {
- y = 4;
- x = 320 - count * ICON_SIZE;
- for ( i = 0 ; i < count ; i++ ) {
- CG_DrawPic( x, y, (ICON_SIZE*2)-4, (ICON_SIZE*2)-4, cg.rewardShader[0] );
- x += (ICON_SIZE*2);
- }
- }
-
- count = cg.rewardCount[0] - count*10; // number of small rewards to draw
- */
-
- if ( cg.rewardCount[0] >= 10 ) {
- y = 56;
- x = 320 - ICON_SIZE/2;
- CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
- Com_sprintf(buf, sizeof(buf), "%d", cg.rewardCount[0]);
- x = ( SCREEN_WIDTH - SMALLCHAR_WIDTH * CG_DrawStrlen( buf ) ) / 2;
- CG_DrawStringExt( x, y+ICON_SIZE, buf, color, qfalse, qtrue,
- SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
- }
- else {
-
- count = cg.rewardCount[0];
-
- y = 56;
- x = 320 - count * ICON_SIZE/2;
- for ( i = 0 ; i < count ; i++ ) {
- CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
- x += ICON_SIZE;
- }
- }
- trap_R_SetColor( NULL );
-}
-
-
-/*
-===============================================================================
-
-LAGOMETER
-
-===============================================================================
-*/
-
-#define LAG_SAMPLES 128
-
-
-typedef struct {
- int frameSamples[LAG_SAMPLES];
- int frameCount;
- int snapshotFlags[LAG_SAMPLES];
- int snapshotSamples[LAG_SAMPLES];
- int snapshotCount;
-} lagometer_t;
-
-lagometer_t lagometer;
-
-/*
-==============
-CG_AddLagometerFrameInfo
-
-Adds the current interpolate / extrapolate bar for this frame
-==============
-*/
-void CG_AddLagometerFrameInfo( void ) {
- int offset;
-
- offset = cg.time - cg.latestSnapshotTime;
- lagometer.frameSamples[ lagometer.frameCount & ( LAG_SAMPLES - 1) ] = offset;
- lagometer.frameCount++;
-}
-
-/*
-==============
-CG_AddLagometerSnapshotInfo
-
-Each time a snapshot is received, log its ping time and
-the number of snapshots that were dropped before it.
-
-Pass NULL for a dropped packet.
-==============
-*/
-void CG_AddLagometerSnapshotInfo( snapshot_t *snap ) {
- // dropped packet
- if ( !snap ) {
- lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = -1;
- lagometer.snapshotCount++;
- return;
- }
-
- // add this snapshot's info
- lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->ping;
- lagometer.snapshotFlags[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->snapFlags;
- lagometer.snapshotCount++;
-}
-
-/*
-==============
-CG_DrawDisconnect
-
-Should we draw something differnet for long lag vs no packets?
-==============
-*/
-static void CG_DrawDisconnect( void ) {
- float x, y;
- int cmdNum;
- usercmd_t cmd;
- const char *s;
- int w;
-
- // draw the phone jack if we are completely past our buffers
- cmdNum = trap_GetCurrentCmdNumber() - CMD_BACKUP + 1;
- trap_GetUserCmd( cmdNum, &cmd );
- if ( cmd.serverTime <= cg.snap->ps.commandTime
- || cmd.serverTime > cg.time ) { // special check for map_restart
- return;
- }
-
- // also add text in center of screen
- s = "Connection Interrupted";
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- CG_DrawBigString( 320 - w/2, 100, s, 1.0F);
-
- // blink the icon
- if ( ( cg.time >> 9 ) & 1 ) {
- return;
- }
-
- x = 640 - 48;
- y = 480 - 48;
-
- CG_DrawPic( x, y, 48, 48, trap_R_RegisterShader("gfx/2d/net.tga" ) );
-}
-
-
-#define MAX_LAGOMETER_PING 900
-#define MAX_LAGOMETER_RANGE 300
-
-/*
-==============
-CG_DrawLagometer
-==============
-*/
-static void CG_DrawLagometer( void ) {
- int a, x, y, i;
- float v;
- float ax, ay, aw, ah, mid, range;
- int color;
- float vscale;
-
- if ( !cg_lagometer.integer || cgs.localServer ) {
- CG_DrawDisconnect();
- return;
- }
-
- //
- // draw the graph
- //
-#ifdef MISSIONPACK
- x = 640 - 48;
- y = 480 - 144;
-#else
- x = 640 - 48;
- y = 480 - 48;
-#endif
-
- trap_R_SetColor( NULL );
- CG_DrawPic( x, y, 48, 48, cgs.media.lagometerShader );
-
- ax = x;
- ay = y;
- aw = 48;
- ah = 48;
- CG_AdjustFrom640( &ax, &ay, &aw, &ah );
-
- color = -1;
- range = ah / 3;
- mid = ay + range;
-
- vscale = range / MAX_LAGOMETER_RANGE;
-
- // draw the frame interpoalte / extrapolate graph
- for ( a = 0 ; a < aw ; a++ ) {
- i = ( lagometer.frameCount - 1 - a ) & (LAG_SAMPLES - 1);
- v = lagometer.frameSamples[i];
- v *= vscale;
- if ( v > 0 ) {
- if ( color != 1 ) {
- color = 1;
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
- }
- if ( v > range ) {
- v = range;
- }
- trap_R_DrawStretchPic ( ax + aw - a, mid - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
- } else if ( v < 0 ) {
- if ( color != 2 ) {
- color = 2;
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_BLUE)] );
- }
- v = -v;
- if ( v > range ) {
- v = range;
- }
- trap_R_DrawStretchPic( ax + aw - a, mid, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
- }
- }
-
- // draw the snapshot latency / drop graph
- range = ah / 2;
- vscale = range / MAX_LAGOMETER_PING;
-
- for ( a = 0 ; a < aw ; a++ ) {
- i = ( lagometer.snapshotCount - 1 - a ) & (LAG_SAMPLES - 1);
- v = lagometer.snapshotSamples[i];
- if ( v > 0 ) {
- if ( lagometer.snapshotFlags[i] & SNAPFLAG_RATE_DELAYED ) {
- if ( color != 5 ) {
- color = 5; // YELLOW for rate delay
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
- }
- } else {
- if ( color != 3 ) {
- color = 3;
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_GREEN)] );
- }
- }
- v = v * vscale;
- if ( v > range ) {
- v = range;
- }
- trap_R_DrawStretchPic( ax + aw - a, ay + ah - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
- } else if ( v < 0 ) {
- if ( color != 4 ) {
- color = 4; // RED for dropped snapshots
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_RED)] );
- }
- trap_R_DrawStretchPic( ax + aw - a, ay + ah - range, 1, range, 0, 0, 0, 0, cgs.media.whiteShader );
- }
- }
-
- trap_R_SetColor( NULL );
-
- if ( cg_nopredict.integer || cg_synchronousClients.integer ) {
- CG_DrawBigString( ax, ay, "snc", 1.0 );
- }
-
- CG_DrawDisconnect();
-}
-
-
-
-/*
-===============================================================================
-
-CENTER PRINTING
-
-===============================================================================
-*/
-
-
-/*
-==============
-CG_CenterPrint
-
-Called for important messages that should stay in the center of the screen
-for a few moments
-==============
-*/
-void CG_CenterPrint( const char *str, int y, int charWidth ) {
- char *s;
-
- Q_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) );
-
- cg.centerPrintTime = cg.time;
- cg.centerPrintY = y;
- cg.centerPrintCharWidth = charWidth;
-
- // count the number of lines for centering
- cg.centerPrintLines = 1;
- s = cg.centerPrint;
- while( *s ) {
- if (*s == '\n')
- cg.centerPrintLines++;
- s++;
- }
-}
-
-
-/*
-===================
-CG_DrawCenterString
-===================
-*/
-static void CG_DrawCenterString( void ) {
- char *start;
- int l;
- int x, y, w;
-#ifdef MISSIONPACK
- int h;
-#endif
- float *color;
-
- if ( !cg.centerPrintTime ) {
- return;
- }
-
- color = CG_FadeColor( cg.centerPrintTime, 1000 * cg_centertime.value );
- if ( !color ) {
- return;
- }
-
- trap_R_SetColor( color );
-
- start = cg.centerPrint;
-
- y = cg.centerPrintY - cg.centerPrintLines * BIGCHAR_HEIGHT / 2;
-
- while ( 1 ) {
- char linebuffer[1024];
-
- for ( l = 0; l < 50; l++ ) {
- if ( !start[l] || start[l] == '\n' ) {
- break;
- }
- linebuffer[l] = start[l];
- }
- linebuffer[l] = 0;
-
-#ifdef MISSIONPACK
- w = CG_Text_Width(linebuffer, 0.5, 0);
- h = CG_Text_Height(linebuffer, 0.5, 0);
- x = (SCREEN_WIDTH - w) / 2;
- CG_Text_Paint(x, y + h, 0.5, color, linebuffer, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
- y += h + 6;
-#else
- w = cg.centerPrintCharWidth * CG_DrawStrlen( linebuffer );
-
- x = ( SCREEN_WIDTH - w ) / 2;
-
- CG_DrawStringExt( x, y, linebuffer, color, qfalse, qtrue,
- cg.centerPrintCharWidth, (int)(cg.centerPrintCharWidth * 1.5), 0 );
-
- y += cg.centerPrintCharWidth * 1.5;
-#endif
- while ( *start && ( *start != '\n' ) ) {
- start++;
- }
- if ( !*start ) {
- break;
- }
- start++;
- }
-
- trap_R_SetColor( NULL );
-}
-
-
-
-/*
-================================================================================
-
-CROSSHAIR
-
-================================================================================
-*/
-
-
-/*
-=================
-CG_DrawCrosshair
-=================
-*/
-static void CG_DrawCrosshair(void)
-{
- float w, h;
- qhandle_t hShader;
- float f;
- float x, y;
- int ca;
-
- if ( !cg_drawCrosshair.integer ) {
- return;
- }
-
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) {
- return;
- }
-
- if ( cg.renderingThirdPerson ) {
- return;
- }
-
- // set color based on health
- if ( cg_crosshairHealth.integer ) {
- vec4_t hcolor;
-
- CG_ColorForHealth( hcolor );
- trap_R_SetColor( hcolor );
- } else {
- trap_R_SetColor( NULL );
- }
-
- w = h = cg_crosshairSize.value;
-
- // pulse the size of the crosshair when picking up items
- f = cg.time - cg.itemPickupBlendTime;
- if ( f > 0 && f < ITEM_BLOB_TIME ) {
- f /= ITEM_BLOB_TIME;
- w *= ( 1 + f );
- h *= ( 1 + f );
- }
-
- x = cg_crosshairX.integer;
- y = cg_crosshairY.integer;
- CG_AdjustFrom640( &x, &y, &w, &h );
-
- ca = cg_drawCrosshair.integer;
- if (ca < 0) {
- ca = 0;
- }
- hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ];
-
- trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (cg.refdef.width - w),
- y + cg.refdef.y + 0.5 * (cg.refdef.height - h),
- w, h, 0, 0, 1, 1, hShader );
-}
-
-/*
-=================
-CG_DrawCrosshair3D
-=================
-*/
-static void CG_DrawCrosshair3D(void)
-{
- float w, h;
- qhandle_t hShader;
- float f;
- int ca;
-
- trace_t trace;
- vec3_t endpos;
- float stereoSep, zProj, maxdist, xmax;
- char rendererinfos[128];
- refEntity_t ent;
-
- if ( !cg_drawCrosshair.integer ) {
- return;
- }
-
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) {
- return;
- }
-
- if ( cg.renderingThirdPerson ) {
- return;
- }
-
- w = h = cg_crosshairSize.value;
-
- // pulse the size of the crosshair when picking up items
- f = cg.time - cg.itemPickupBlendTime;
- if ( f > 0 && f < ITEM_BLOB_TIME ) {
- f /= ITEM_BLOB_TIME;
- w *= ( 1 + f );
- h *= ( 1 + f );
- }
-
- ca = cg_drawCrosshair.integer;
- if (ca < 0) {
- ca = 0;
- }
- hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ];
-
- // Use a different method rendering the crosshair so players don't see two of them when
- // focusing their eyes at distant objects with high stereo separation
- // We are going to trace to the next shootable object and place the crosshair in front of it.
-
- // first get all the important renderer information
- trap_Cvar_VariableStringBuffer("r_zProj", rendererinfos, sizeof(rendererinfos));
- zProj = atof(rendererinfos);
- trap_Cvar_VariableStringBuffer("r_stereoSeparation", rendererinfos, sizeof(rendererinfos));
- stereoSep = zProj / atof(rendererinfos);
-
- xmax = zProj * tan(cg.refdef.fov_x * M_PI / 360.0f);
-
- // let the trace run through until a change in stereo separation of the crosshair becomes less than one pixel.
- maxdist = cgs.glconfig.vidWidth * stereoSep * zProj / (2 * xmax);
- VectorMA(cg.refdef.vieworg, maxdist, cg.refdef.viewaxis[0], endpos);
- CG_Trace(&trace, cg.refdef.vieworg, NULL, NULL, endpos, 0, MASK_SHOT);
-
- memset(&ent, 0, sizeof(ent));
- ent.reType = RT_SPRITE;
- ent.renderfx = RF_DEPTHHACK | RF_CROSSHAIR;
-
- VectorCopy(trace.endpos, ent.origin);
-
- // scale the crosshair so it appears the same size for all distances
- ent.radius = w / 640 * xmax * trace.fraction * maxdist / zProj;
- ent.customShader = hShader;
-
- trap_R_AddRefEntityToScene(&ent);
-}
-
-
-
-/*
-=================
-CG_ScanForCrosshairEntity
-=================
-*/
-static void CG_ScanForCrosshairEntity( void ) {
- trace_t trace;
- vec3_t start, end;
- int content;
-
- VectorCopy( cg.refdef.vieworg, start );
- VectorMA( start, 131072, cg.refdef.viewaxis[0], end );
-
- CG_Trace( &trace, start, vec3_origin, vec3_origin, end,
- cg.snap->ps.clientNum, CONTENTS_SOLID|CONTENTS_BODY );
- if ( trace.entityNum >= MAX_CLIENTS ) {
- return;
- }
-
- // if the player is in fog, don't show it
- content = trap_CM_PointContents( trace.endpos, 0 );
- if ( content & CONTENTS_FOG ) {
- return;
- }
-
- // if the player is invisible, don't show it
- if ( cg_entities[ trace.entityNum ].currentState.powerups & ( 1 << PW_INVIS ) ) {
- return;
- }
-
- // update the fade timer
- cg.crosshairClientNum = trace.entityNum;
- cg.crosshairClientTime = cg.time;
-}
-
-
-/*
-=====================
-CG_DrawCrosshairNames
-=====================
-*/
-static void CG_DrawCrosshairNames( void ) {
- float *color;
- char *name;
- float w;
-
- if ( !cg_drawCrosshair.integer ) {
- return;
- }
- if ( !cg_drawCrosshairNames.integer ) {
- return;
- }
- if ( cg.renderingThirdPerson ) {
- return;
- }
-
- // scan the known entities to see if the crosshair is sighted on one
- CG_ScanForCrosshairEntity();
-
- // draw the name of the player being looked at
- color = CG_FadeColor( cg.crosshairClientTime, 1000 );
- if ( !color ) {
- trap_R_SetColor( NULL );
- return;
- }
-
- name = cgs.clientinfo[ cg.crosshairClientNum ].name;
-#ifdef MISSIONPACK
- color[3] *= 0.5f;
- w = CG_Text_Width(name, 0.3f, 0);
- CG_Text_Paint( 320 - w / 2, 190, 0.3f, color, name, 0, 0, ITEM_TEXTSTYLE_SHADOWED);
-#else
- w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH;
- CG_DrawBigString( 320 - w / 2, 170, name, color[3] * 0.5f );
-#endif
- trap_R_SetColor( NULL );
-}
-
-
-//==============================================================================
-
-/*
-=================
-CG_DrawSpectator
-=================
-*/
-static void CG_DrawSpectator(void) {
- CG_DrawBigString(320 - 9 * 8, 440, "SPECTATOR", 1.0F);
- if ( cgs.gametype == GT_TOURNAMENT ) {
- CG_DrawBigString(320 - 15 * 8, 460, "waiting to play", 1.0F);
- }
- else if ( cgs.gametype >= GT_TEAM ) {
- CG_DrawBigString(320 - 39 * 8, 460, "press ESC and use the JOIN menu to play", 1.0F);
- }
-}
-
-/*
-=================
-CG_DrawVote
-=================
-*/
-static void CG_DrawVote(void) {
- char *s;
- int sec;
-
- if ( !cgs.voteTime ) {
- return;
- }
-
- // play a talk beep whenever it is modified
- if ( cgs.voteModified ) {
- cgs.voteModified = qfalse;
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- }
-
- sec = ( VOTE_TIME - ( cg.time - cgs.voteTime ) ) / 1000;
- if ( sec < 0 ) {
- sec = 0;
- }
-#ifdef MISSIONPACK
- s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo);
- CG_DrawSmallString( 0, 58, s, 1.0F );
- s = "or press ESC then click Vote";
- CG_DrawSmallString( 0, 58 + SMALLCHAR_HEIGHT + 2, s, 1.0F );
-#else
- s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo );
- CG_DrawSmallString( 0, 58, s, 1.0F );
-#endif
-}
-
-/*
-=================
-CG_DrawTeamVote
-=================
-*/
-static void CG_DrawTeamVote(void) {
- char *s;
- int sec, cs_offset;
-
- if ( cgs.clientinfo->team == TEAM_RED )
- cs_offset = 0;
- else if ( cgs.clientinfo->team == TEAM_BLUE )
- cs_offset = 1;
- else
- return;
-
- if ( !cgs.teamVoteTime[cs_offset] ) {
- return;
- }
-
- // play a talk beep whenever it is modified
- if ( cgs.teamVoteModified[cs_offset] ) {
- cgs.teamVoteModified[cs_offset] = qfalse;
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- }
-
- sec = ( VOTE_TIME - ( cg.time - cgs.teamVoteTime[cs_offset] ) ) / 1000;
- if ( sec < 0 ) {
- sec = 0;
- }
- s = va("TEAMVOTE(%i):%s yes:%i no:%i", sec, cgs.teamVoteString[cs_offset],
- cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] );
- CG_DrawSmallString( 0, 90, s, 1.0F );
-}
-
-
-static qboolean CG_DrawScoreboard( void ) {
-#ifdef MISSIONPACK
- static qboolean firstTime = qtrue;
- float fade, *fadeColor;
-
- if (menuScoreboard) {
- menuScoreboard->window.flags &= ~WINDOW_FORCED;
- }
- if (cg_paused.integer) {
- cg.deferredPlayerLoading = 0;
- firstTime = qtrue;
- return qfalse;
- }
-
- // should never happen in Team Arena
- if (cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- cg.deferredPlayerLoading = 0;
- firstTime = qtrue;
- return qfalse;
- }
-
- // don't draw scoreboard during death while warmup up
- if ( cg.warmup && !cg.showScores ) {
- return qfalse;
- }
-
- if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD || cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- fade = 1.0;
- fadeColor = colorWhite;
- } else {
- fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
- if ( !fadeColor ) {
- // next time scoreboard comes up, don't print killer
- cg.deferredPlayerLoading = 0;
- cg.killerName[0] = 0;
- firstTime = qtrue;
- return qfalse;
- }
- fade = *fadeColor;
- }
-
-
- if (menuScoreboard == NULL) {
- if ( cgs.gametype >= GT_TEAM ) {
- menuScoreboard = Menus_FindByName("teamscore_menu");
- } else {
- menuScoreboard = Menus_FindByName("score_menu");
- }
- }
-
- if (menuScoreboard) {
- if (firstTime) {
- CG_SetScoreSelection(menuScoreboard);
- firstTime = qfalse;
- }
- Menu_Paint(menuScoreboard, qtrue);
- }
-
- // load any models that have been deferred
- if ( ++cg.deferredPlayerLoading > 10 ) {
- CG_LoadDeferredPlayers();
- }
-
- return qtrue;
-#else
- return CG_DrawOldScoreboard();
-#endif
-}
-
-/*
-=================
-CG_DrawIntermission
-=================
-*/
-static void CG_DrawIntermission( void ) {
-// int key;
-#ifdef MISSIONPACK
- //if (cg_singlePlayer.integer) {
- // CG_DrawCenterString();
- // return;
- //}
-#else
- if ( cgs.gametype == GT_SINGLE_PLAYER ) {
- CG_DrawCenterString();
- return;
- }
-#endif
- cg.scoreFadeTime = cg.time;
- cg.scoreBoardShowing = CG_DrawScoreboard();
-}
-
-/*
-=================
-CG_DrawFollow
-=================
-*/
-static qboolean CG_DrawFollow( void ) {
- float x;
- vec4_t color;
- const char *name;
-
- if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
- return qfalse;
- }
- color[0] = 1;
- color[1] = 1;
- color[2] = 1;
- color[3] = 1;
-
-
- CG_DrawBigString( 320 - 9 * 8, 24, "following", 1.0F );
-
- name = cgs.clientinfo[ cg.snap->ps.clientNum ].name;
-
- x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( name ) );
-
- CG_DrawStringExt( x, 40, name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
-
- return qtrue;
-}
-
-
-
-/*
-=================
-CG_DrawAmmoWarning
-=================
-*/
-static void CG_DrawAmmoWarning( void ) {
- const char *s;
- int w;
-
- if ( cg_drawAmmoWarning.integer == 0 ) {
- return;
- }
-
- if ( !cg.lowAmmoWarning ) {
- return;
- }
-
- if ( cg.lowAmmoWarning == 2 ) {
- s = "OUT OF AMMO";
- } else {
- s = "LOW AMMO WARNING";
- }
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- CG_DrawBigString(320 - w / 2, 64, s, 1.0F);
-}
-
-
-#ifdef MISSIONPACK
-/*
-=================
-CG_DrawProxWarning
-=================
-*/
-static void CG_DrawProxWarning( void ) {
- char s [32];
- int w;
- static int proxTime;
- static int proxCounter;
- static int proxTick;
-
- if( !(cg.snap->ps.eFlags & EF_TICKING ) ) {
- proxTime = 0;
- return;
- }
-
- if (proxTime == 0) {
- proxTime = cg.time + 5000;
- proxCounter = 5;
- proxTick = 0;
- }
-
- if (cg.time > proxTime) {
- proxTick = proxCounter--;
- proxTime = cg.time + 1000;
- }
-
- if (proxTick != 0) {
- Com_sprintf(s, sizeof(s), "INTERNAL COMBUSTION IN: %i", proxTick);
- } else {
- Com_sprintf(s, sizeof(s), "YOU HAVE BEEN MINED");
- }
-
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- CG_DrawBigStringColor( 320 - w / 2, 64 + BIGCHAR_HEIGHT, s, g_color_table[ColorIndex(COLOR_RED)] );
-}
-#endif
-
-
-/*
-=================
-CG_DrawWarmup
-=================
-*/
-static void CG_DrawWarmup( void ) {
- int w;
- int sec;
- int i;
- float scale;
- clientInfo_t *ci1, *ci2;
- int cw;
- const char *s;
-
- sec = cg.warmup;
- if ( !sec ) {
- return;
- }
-
- if ( sec < 0 ) {
- s = "Waiting for players";
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- CG_DrawBigString(320 - w / 2, 24, s, 1.0F);
- cg.warmupCount = 0;
- return;
- }
-
- if (cgs.gametype == GT_TOURNAMENT) {
- // find the two active players
- ci1 = NULL;
- ci2 = NULL;
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_FREE ) {
- if ( !ci1 ) {
- ci1 = &cgs.clientinfo[i];
- } else {
- ci2 = &cgs.clientinfo[i];
- }
- }
- }
-
- if ( ci1 && ci2 ) {
- s = va( "%s vs %s", ci1->name, ci2->name );
-#ifdef MISSIONPACK
- w = CG_Text_Width(s, 0.6f, 0);
- CG_Text_Paint(320 - w / 2, 60, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
-#else
- w = CG_DrawStrlen( s );
- if ( w > 640 / GIANT_WIDTH ) {
- cw = 640 / w;
- } else {
- cw = GIANT_WIDTH;
- }
- CG_DrawStringExt( 320 - w * cw/2, 20,s, colorWhite,
- qfalse, qtrue, cw, (int)(cw * 1.5f), 0 );
-#endif
- }
- } else {
- if ( cgs.gametype == GT_FFA ) {
- s = "Free For All";
- } else if ( cgs.gametype == GT_TEAM ) {
- s = "Team Deathmatch";
- } else if ( cgs.gametype == GT_CTF ) {
- s = "Capture the Flag";
-#ifdef MISSIONPACK
- } else if ( cgs.gametype == GT_1FCTF ) {
- s = "One Flag CTF";
- } else if ( cgs.gametype == GT_OBELISK ) {
- s = "Overload";
- } else if ( cgs.gametype == GT_HARVESTER ) {
- s = "Harvester";
-#endif
- } else {
- s = "";
- }
-#ifdef MISSIONPACK
- w = CG_Text_Width(s, 0.6f, 0);
- CG_Text_Paint(320 - w / 2, 90, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
-#else
- w = CG_DrawStrlen( s );
- if ( w > 640 / GIANT_WIDTH ) {
- cw = 640 / w;
- } else {
- cw = GIANT_WIDTH;
- }
- CG_DrawStringExt( 320 - w * cw/2, 25,s, colorWhite,
- qfalse, qtrue, cw, (int)(cw * 1.1f), 0 );
-#endif
- }
-
- sec = ( sec - cg.time ) / 1000;
- if ( sec < 0 ) {
- cg.warmup = 0;
- sec = 0;
- }
- s = va( "Starts in: %i", sec + 1 );
- if ( sec != cg.warmupCount ) {
- cg.warmupCount = sec;
- switch ( sec ) {
- case 0:
- trap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER );
- break;
- case 1:
- trap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER );
- break;
- case 2:
- trap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER );
- break;
- default:
- break;
- }
- }
- scale = 0.45f;
- switch ( cg.warmupCount ) {
- case 0:
- cw = 28;
- scale = 0.54f;
- break;
- case 1:
- cw = 24;
- scale = 0.51f;
- break;
- case 2:
- cw = 20;
- scale = 0.48f;
- break;
- default:
- cw = 16;
- scale = 0.45f;
- break;
- }
-
-#ifdef MISSIONPACK
- w = CG_Text_Width(s, scale, 0);
- CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
-#else
- w = CG_DrawStrlen( s );
- CG_DrawStringExt( 320 - w * cw/2, 70, s, colorWhite,
- qfalse, qtrue, cw, (int)(cw * 1.5), 0 );
-#endif
-}
-
-//==================================================================================
-#ifdef MISSIONPACK
-/*
-=================
-CG_DrawTimedMenus
-=================
-*/
-void CG_DrawTimedMenus( void ) {
- if (cg.voiceTime) {
- int t = cg.time - cg.voiceTime;
- if ( t > 2500 ) {
- Menus_CloseByName("voiceMenu");
- trap_Cvar_Set("cl_conXOffset", "0");
- cg.voiceTime = 0;
- }
- }
-}
-#endif
-/*
-=================
-CG_Draw2D
-=================
-*/
-static void CG_Draw2D(stereoFrame_t stereoFrame)
-{
-#ifdef MISSIONPACK
- if (cgs.orderPending && cg.time > cgs.orderTime) {
- CG_CheckOrderPending();
- }
-#endif
- // if we are taking a levelshot for the menu, don't draw anything
- if ( cg.levelShot ) {
- return;
- }
-
- if ( cg_draw2D.integer == 0 ) {
- return;
- }
-
- if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
- CG_DrawIntermission();
- return;
- }
-
-/*
- if (cg.cameraMode) {
- return;
- }
-*/
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
- CG_DrawSpectator();
-
- if(stereoFrame == STEREO_CENTER)
- CG_DrawCrosshair();
-
- CG_DrawCrosshairNames();
- } else {
- // don't draw any status if dead or the scoreboard is being explicitly shown
- if ( !cg.showScores && cg.snap->ps.stats[STAT_HEALTH] > 0 ) {
-
-#ifdef MISSIONPACK
- if ( cg_drawStatus.integer ) {
- Menu_PaintAll();
- CG_DrawTimedMenus();
- }
-#else
- CG_DrawStatusBar();
-#endif
-
- CG_DrawAmmoWarning();
-
-#ifdef MISSIONPACK
- CG_DrawProxWarning();
-#endif
- if(stereoFrame == STEREO_CENTER)
- CG_DrawCrosshair();
- CG_DrawCrosshairNames();
- CG_DrawWeaponSelect();
-
-#ifndef MISSIONPACK
- CG_DrawHoldableItem();
-#else
- //CG_DrawPersistantPowerup();
-#endif
- CG_DrawReward();
- }
-
- if ( cgs.gametype >= GT_TEAM ) {
-#ifndef MISSIONPACK
- CG_DrawTeamInfo();
-#endif
- }
- }
-
- CG_DrawVote();
- CG_DrawTeamVote();
-
- CG_DrawLagometer();
-
-#ifdef MISSIONPACK
- if (!cg_paused.integer) {
- CG_DrawUpperRight(stereoFrame);
- }
-#else
- CG_DrawUpperRight(stereoFrame);
-#endif
-
-#ifndef MISSIONPACK
- CG_DrawLowerRight();
- CG_DrawLowerLeft();
-#endif
-
- if ( !CG_DrawFollow() ) {
- CG_DrawWarmup();
- }
-
- // don't draw center string if scoreboard is up
- cg.scoreBoardShowing = CG_DrawScoreboard();
- if ( !cg.scoreBoardShowing) {
- CG_DrawCenterString();
- }
-}
-
-
-static void CG_DrawTourneyScoreboard( void ) {
-#ifdef MISSIONPACK
-#else
- CG_DrawOldTourneyScoreboard();
-#endif
-}
-
-/*
-=====================
-CG_DrawActive
-
-Perform all drawing needed to completely fill the screen
-=====================
-*/
-void CG_DrawActive( stereoFrame_t stereoView ) {
- // optionally draw the info screen instead
- if ( !cg.snap ) {
- CG_DrawInformation();
- return;
- }
-
- // optionally draw the tournement scoreboard instead
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR &&
- ( cg.snap->ps.pm_flags & PMF_SCOREBOARD ) ) {
- CG_DrawTourneyScoreboard();
- return;
- }
-
- // clear around the rendered view if sized down
- CG_TileClear();
-
- if(stereoView != STEREO_CENTER)
- CG_DrawCrosshair3D();
-
- // draw 3D view
- trap_R_RenderScene( &cg.refdef );
-
- // draw status bar and other floating elements
- CG_Draw2D(stereoView);
-}
-
-
-
diff --git a/engine/code/cgame/cg_drawtools.c b/engine/code/cgame/cg_drawtools.c
deleted file mode 100644
index df4188f..0000000
--- a/engine/code/cgame/cg_drawtools.c
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc
-#include "cg_local.h"
-
-/*
-================
-CG_AdjustFrom640
-
-Adjusted for resolution and screen aspect ratio
-================
-*/
-void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) {
-#if 0
- // adjust for wide screens
- if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) {
- *x += 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * 640 / 480 ) );
- }
-#endif
- // scale for screen sizes
- *x *= cgs.screenXScale;
- *y *= cgs.screenYScale;
- *w *= cgs.screenXScale;
- *h *= cgs.screenYScale;
-}
-
-/*
-================
-CG_FillRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void CG_FillRect( float x, float y, float width, float height, const float *color ) {
- trap_R_SetColor( color );
-
- CG_AdjustFrom640( &x, &y, &width, &height );
- trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cgs.media.whiteShader );
-
- trap_R_SetColor( NULL );
-}
-
-/*
-================
-CG_DrawSides
-
-Coords are virtual 640x480
-================
-*/
-void CG_DrawSides(float x, float y, float w, float h, float size) {
- CG_AdjustFrom640( &x, &y, &w, &h );
- size *= cgs.screenXScale;
- trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
- trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
-}
-
-void CG_DrawTopBottom(float x, float y, float w, float h, float size) {
- CG_AdjustFrom640( &x, &y, &w, &h );
- size *= cgs.screenYScale;
- trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
- trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
-}
-/*
-================
-UI_DrawRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void CG_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
- trap_R_SetColor( color );
-
- CG_DrawTopBottom(x, y, width, height, size);
- CG_DrawSides(x, y, width, height, size);
-
- trap_R_SetColor( NULL );
-}
-
-
-
-/*
-================
-CG_DrawPic
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {
- CG_AdjustFrom640( &x, &y, &width, &height );
- trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
-}
-
-
-
-/*
-===============
-CG_DrawChar
-
-Coordinates and size in 640*480 virtual screen size
-===============
-*/
-void CG_DrawChar( int x, int y, int width, int height, int ch ) {
- int row, col;
- float frow, fcol;
- float size;
- float ax, ay, aw, ah;
-
- ch &= 255;
-
- if ( ch == ' ' ) {
- return;
- }
-
- ax = x;
- ay = y;
- aw = width;
- ah = height;
- CG_AdjustFrom640( &ax, &ay, &aw, &ah );
-
- row = ch>>4;
- col = ch&15;
-
- frow = row*0.0625;
- fcol = col*0.0625;
- size = 0.0625;
-
- trap_R_DrawStretchPic( ax, ay, aw, ah,
- fcol, frow,
- fcol + size, frow + size,
- cgs.media.charsetShader );
-}
-
-
-/*
-==================
-CG_DrawStringExt
-
-Draws a multi-colored string with a drop shadow, optionally forcing
-to a fixed color.
-
-Coordinates are at 640 by 480 virtual resolution
-==================
-*/
-void CG_DrawStringExt( int x, int y, const char *string, const float *setColor,
- qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars ) {
- vec4_t color;
- const char *s;
- int xx;
- int cnt;
-
- if (maxChars <= 0)
- maxChars = 32767; // do them all!
-
- // draw the drop shadow
- if (shadow) {
- color[0] = color[1] = color[2] = 0;
- color[3] = setColor[3];
- trap_R_SetColor( color );
- s = string;
- xx = x;
- cnt = 0;
- while ( *s && cnt < maxChars) {
- if ( Q_IsColorString( s ) ) {
- s += 2;
- continue;
- }
- CG_DrawChar( xx + 2, y + 2, charWidth, charHeight, *s );
- cnt++;
- xx += charWidth;
- s++;
- }
- }
-
- // draw the colored text
- s = string;
- xx = x;
- cnt = 0;
- trap_R_SetColor( setColor );
- while ( *s && cnt < maxChars) {
- if ( Q_IsColorString( s ) ) {
- if ( !forceColor ) {
- memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
- color[3] = setColor[3];
- trap_R_SetColor( color );
- }
- s += 2;
- continue;
- }
- CG_DrawChar( xx, y, charWidth, charHeight, *s );
- xx += charWidth;
- cnt++;
- s++;
- }
- trap_R_SetColor( NULL );
-}
-
-void CG_DrawBigString( int x, int y, const char *s, float alpha ) {
- float color[4];
-
- color[0] = color[1] = color[2] = 1.0;
- color[3] = alpha;
- CG_DrawStringExt( x, y, s, color, qfalse, qtrue, BIGCHAR_WIDTH, BIGCHAR_HEIGHT, 0 );
-}
-
-void CG_DrawBigStringColor( int x, int y, const char *s, vec4_t color ) {
- CG_DrawStringExt( x, y, s, color, qtrue, qtrue, BIGCHAR_WIDTH, BIGCHAR_HEIGHT, 0 );
-}
-
-void CG_DrawSmallString( int x, int y, const char *s, float alpha ) {
- float color[4];
-
- color[0] = color[1] = color[2] = 1.0;
- color[3] = alpha;
- CG_DrawStringExt( x, y, s, color, qfalse, qfalse, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
-}
-
-void CG_DrawSmallStringColor( int x, int y, const char *s, vec4_t color ) {
- CG_DrawStringExt( x, y, s, color, qtrue, qfalse, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
-}
-
-/*
-=================
-CG_DrawStrlen
-
-Returns character count, skiping color escape codes
-=================
-*/
-int CG_DrawStrlen( const char *str ) {
- const char *s = str;
- int count = 0;
-
- while ( *s ) {
- if ( Q_IsColorString( s ) ) {
- s += 2;
- } else {
- count++;
- s++;
- }
- }
-
- return count;
-}
-
-/*
-=============
-CG_TileClearBox
-
-This repeats a 64*64 tile graphic to fill the screen around a sized down
-refresh window.
-=============
-*/
-static void CG_TileClearBox( int x, int y, int w, int h, qhandle_t hShader ) {
- float s1, t1, s2, t2;
-
- s1 = x/64.0;
- t1 = y/64.0;
- s2 = (x+w)/64.0;
- t2 = (y+h)/64.0;
- trap_R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, hShader );
-}
-
-
-
-/*
-==============
-CG_TileClear
-
-Clear around a sized down screen
-==============
-*/
-void CG_TileClear( void ) {
- int top, bottom, left, right;
- int w, h;
-
- w = cgs.glconfig.vidWidth;
- h = cgs.glconfig.vidHeight;
-
- if ( cg.refdef.x == 0 && cg.refdef.y == 0 &&
- cg.refdef.width == w && cg.refdef.height == h ) {
- return; // full screen rendering
- }
-
- top = cg.refdef.y;
- bottom = top + cg.refdef.height-1;
- left = cg.refdef.x;
- right = left + cg.refdef.width-1;
-
- // clear above view screen
- CG_TileClearBox( 0, 0, w, top, cgs.media.backTileShader );
-
- // clear below view screen
- CG_TileClearBox( 0, bottom, w, h - bottom, cgs.media.backTileShader );
-
- // clear left of view screen
- CG_TileClearBox( 0, top, left, bottom - top + 1, cgs.media.backTileShader );
-
- // clear right of view screen
- CG_TileClearBox( right, top, w - right, bottom - top + 1, cgs.media.backTileShader );
-}
-
-
-
-/*
-================
-CG_FadeColor
-================
-*/
-float *CG_FadeColor( int startMsec, int totalMsec ) {
- static vec4_t color;
- int t;
-
- if ( startMsec == 0 ) {
- return NULL;
- }
-
- t = cg.time - startMsec;
-
- if ( t >= totalMsec ) {
- return NULL;
- }
-
- // fade out
- if ( totalMsec - t < FADE_TIME ) {
- color[3] = ( totalMsec - t ) * 1.0/FADE_TIME;
- } else {
- color[3] = 1.0;
- }
- color[0] = color[1] = color[2] = 1;
-
- return color;
-}
-
-
-/*
-================
-CG_TeamColor
-================
-*/
-float *CG_TeamColor( int team ) {
- static vec4_t red = {1, 0.2f, 0.2f, 1};
- static vec4_t blue = {0.2f, 0.2f, 1, 1};
- static vec4_t other = {1, 1, 1, 1};
- static vec4_t spectator = {0.7f, 0.7f, 0.7f, 1};
-
- switch ( team ) {
- case TEAM_RED:
- return red;
- case TEAM_BLUE:
- return blue;
- case TEAM_SPECTATOR:
- return spectator;
- default:
- return other;
- }
-}
-
-
-
-/*
-=================
-CG_GetColorForHealth
-=================
-*/
-void CG_GetColorForHealth( int health, int armor, vec4_t hcolor ) {
- int count;
- int max;
-
- // calculate the total points of damage that can
- // be sustained at the current health / armor level
- if ( health <= 0 ) {
- VectorClear( hcolor ); // black
- hcolor[3] = 1;
- return;
- }
- count = armor;
- max = health * ARMOR_PROTECTION / ( 1.0 - ARMOR_PROTECTION );
- if ( max < count ) {
- count = max;
- }
- health += count;
-
- // set the color based on health
- hcolor[0] = 1.0;
- hcolor[3] = 1.0;
- if ( health >= 100 ) {
- hcolor[2] = 1.0;
- } else if ( health < 66 ) {
- hcolor[2] = 0;
- } else {
- hcolor[2] = ( health - 66 ) / 33.0;
- }
-
- if ( health > 60 ) {
- hcolor[1] = 1.0;
- } else if ( health < 30 ) {
- hcolor[1] = 0;
- } else {
- hcolor[1] = ( health - 30 ) / 30.0;
- }
-}
-
-/*
-=================
-CG_ColorForHealth
-=================
-*/
-void CG_ColorForHealth( vec4_t hcolor ) {
-
- CG_GetColorForHealth( cg.snap->ps.stats[STAT_HEALTH],
- cg.snap->ps.stats[STAT_ARMOR], hcolor );
-}
-
-
-/*
-=================
-UI_DrawProportionalString2
-=================
-*/
-static int propMap[128][3] = {
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-
-{0, 0, PROP_SPACE_WIDTH}, // SPACE
-{11, 122, 7}, // !
-{154, 181, 14}, // "
-{55, 122, 17}, // #
-{79, 122, 18}, // $
-{101, 122, 23}, // %
-{153, 122, 18}, // &
-{9, 93, 7}, // '
-{207, 122, 8}, // (
-{230, 122, 9}, // )
-{177, 122, 18}, // *
-{30, 152, 18}, // +
-{85, 181, 7}, // ,
-{34, 93, 11}, // -
-{110, 181, 6}, // .
-{130, 152, 14}, // /
-
-{22, 64, 17}, // 0
-{41, 64, 12}, // 1
-{58, 64, 17}, // 2
-{78, 64, 18}, // 3
-{98, 64, 19}, // 4
-{120, 64, 18}, // 5
-{141, 64, 18}, // 6
-{204, 64, 16}, // 7
-{162, 64, 17}, // 8
-{182, 64, 18}, // 9
-{59, 181, 7}, // :
-{35,181, 7}, // ;
-{203, 152, 14}, // <
-{56, 93, 14}, // =
-{228, 152, 14}, // >
-{177, 181, 18}, // ?
-
-{28, 122, 22}, // @
-{5, 4, 18}, // A
-{27, 4, 18}, // B
-{48, 4, 18}, // C
-{69, 4, 17}, // D
-{90, 4, 13}, // E
-{106, 4, 13}, // F
-{121, 4, 18}, // G
-{143, 4, 17}, // H
-{164, 4, 8}, // I
-{175, 4, 16}, // J
-{195, 4, 18}, // K
-{216, 4, 12}, // L
-{230, 4, 23}, // M
-{6, 34, 18}, // N
-{27, 34, 18}, // O
-
-{48, 34, 18}, // P
-{68, 34, 18}, // Q
-{90, 34, 17}, // R
-{110, 34, 18}, // S
-{130, 34, 14}, // T
-{146, 34, 18}, // U
-{166, 34, 19}, // V
-{185, 34, 29}, // W
-{215, 34, 18}, // X
-{234, 34, 18}, // Y
-{5, 64, 14}, // Z
-{60, 152, 7}, // [
-{106, 151, 13}, // '\'
-{83, 152, 7}, // ]
-{128, 122, 17}, // ^
-{4, 152, 21}, // _
-
-{134, 181, 5}, // '
-{5, 4, 18}, // A
-{27, 4, 18}, // B
-{48, 4, 18}, // C
-{69, 4, 17}, // D
-{90, 4, 13}, // E
-{106, 4, 13}, // F
-{121, 4, 18}, // G
-{143, 4, 17}, // H
-{164, 4, 8}, // I
-{175, 4, 16}, // J
-{195, 4, 18}, // K
-{216, 4, 12}, // L
-{230, 4, 23}, // M
-{6, 34, 18}, // N
-{27, 34, 18}, // O
-
-{48, 34, 18}, // P
-{68, 34, 18}, // Q
-{90, 34, 17}, // R
-{110, 34, 18}, // S
-{130, 34, 14}, // T
-{146, 34, 18}, // U
-{166, 34, 19}, // V
-{185, 34, 29}, // W
-{215, 34, 18}, // X
-{234, 34, 18}, // Y
-{5, 64, 14}, // Z
-{153, 152, 13}, // {
-{11, 181, 5}, // |
-{180, 152, 13}, // }
-{79, 93, 17}, // ~
-{0, 0, -1} // DEL
-};
-
-static int propMapB[26][3] = {
-{11, 12, 33},
-{49, 12, 31},
-{85, 12, 31},
-{120, 12, 30},
-{156, 12, 21},
-{183, 12, 21},
-{207, 12, 32},
-
-{13, 55, 30},
-{49, 55, 13},
-{66, 55, 29},
-{101, 55, 31},
-{135, 55, 21},
-{158, 55, 40},
-{204, 55, 32},
-
-{12, 97, 31},
-{48, 97, 31},
-{82, 97, 30},
-{118, 97, 30},
-{153, 97, 30},
-{185, 97, 25},
-{213, 97, 30},
-
-{11, 139, 32},
-{42, 139, 51},
-{93, 139, 32},
-{126, 139, 31},
-{158, 139, 25},
-};
-
-#define PROPB_GAP_WIDTH 4
-#define PROPB_SPACE_WIDTH 12
-#define PROPB_HEIGHT 36
-
-/*
-=================
-UI_DrawBannerString
-=================
-*/
-static void UI_DrawBannerString2( int x, int y, const char* str, vec4_t color )
-{
- const char* s;
- unsigned char ch;
- float ax;
- float ay;
- float aw;
- float ah;
- float frow;
- float fcol;
- float fwidth;
- float fheight;
-
- // draw the colored text
- trap_R_SetColor( color );
-
- ax = x * cgs.screenXScale + cgs.screenXBias;
- ay = y * cgs.screenXScale;
-
- s = str;
- while ( *s )
- {
- ch = *s & 127;
- if ( ch == ' ' ) {
- ax += ((float)PROPB_SPACE_WIDTH + (float)PROPB_GAP_WIDTH)* cgs.screenXScale;
- }
- else if ( ch >= 'A' && ch <= 'Z' ) {
- ch -= 'A';
- fcol = (float)propMapB[ch][0] / 256.0f;
- frow = (float)propMapB[ch][1] / 256.0f;
- fwidth = (float)propMapB[ch][2] / 256.0f;
- fheight = (float)PROPB_HEIGHT / 256.0f;
- aw = (float)propMapB[ch][2] * cgs.screenXScale;
- ah = (float)PROPB_HEIGHT * cgs.screenXScale;
- trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, cgs.media.charsetPropB );
- ax += (aw + (float)PROPB_GAP_WIDTH * cgs.screenXScale);
- }
- s++;
- }
-
- trap_R_SetColor( NULL );
-}
-
-void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color ) {
- const char * s;
- int ch;
- int width;
- vec4_t drawcolor;
-
- // find the width of the drawn text
- s = str;
- width = 0;
- while ( *s ) {
- ch = *s;
- if ( ch == ' ' ) {
- width += PROPB_SPACE_WIDTH;
- }
- else if ( ch >= 'A' && ch <= 'Z' ) {
- width += propMapB[ch - 'A'][2] + PROPB_GAP_WIDTH;
- }
- s++;
- }
- width -= PROPB_GAP_WIDTH;
-
- switch( style & UI_FORMATMASK ) {
- case UI_CENTER:
- x -= width / 2;
- break;
-
- case UI_RIGHT:
- x -= width;
- break;
-
- case UI_LEFT:
- default:
- break;
- }
-
- if ( style & UI_DROPSHADOW ) {
- drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
- drawcolor[3] = color[3];
- UI_DrawBannerString2( x+2, y+2, str, drawcolor );
- }
-
- UI_DrawBannerString2( x, y, str, color );
-}
-
-
-int UI_ProportionalStringWidth( const char* str ) {
- const char * s;
- int ch;
- int charWidth;
- int width;
-
- s = str;
- width = 0;
- while ( *s ) {
- ch = *s & 127;
- charWidth = propMap[ch][2];
- if ( charWidth != -1 ) {
- width += charWidth;
- width += PROP_GAP_WIDTH;
- }
- s++;
- }
-
- width -= PROP_GAP_WIDTH;
- return width;
-}
-
-static void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t color, float sizeScale, qhandle_t charset )
-{
- const char* s;
- unsigned char ch;
- float ax;
- float ay;
- float aw;
- float ah;
- float frow;
- float fcol;
- float fwidth;
- float fheight;
-
- // draw the colored text
- trap_R_SetColor( color );
-
- ax = x * cgs.screenXScale + cgs.screenXBias;
- ay = y * cgs.screenYScale;
-
- s = str;
- while ( *s )
- {
- ch = *s & 127;
- if ( ch == ' ' ) {
- aw = (float)PROP_SPACE_WIDTH * cgs.screenXScale * sizeScale;
- } else if ( propMap[ch][2] != -1 ) {
- fcol = (float)propMap[ch][0] / 256.0f;
- frow = (float)propMap[ch][1] / 256.0f;
- fwidth = (float)propMap[ch][2] / 256.0f;
- fheight = (float)PROP_HEIGHT / 256.0f;
- aw = (float)propMap[ch][2] * cgs.screenXScale * sizeScale;
- ah = (float)PROP_HEIGHT * cgs.screenXScale * sizeScale;
- trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, charset );
- } else {
- aw = 0;
- }
-
- ax += (aw + (float)PROP_GAP_WIDTH * cgs.screenXScale * sizeScale);
- s++;
- }
-
- trap_R_SetColor( NULL );
-}
-
-/*
-=================
-UI_ProportionalSizeScale
-=================
-*/
-float UI_ProportionalSizeScale( int style ) {
- if( style & UI_SMALLFONT ) {
- return 0.75;
- }
-
- return 1.00;
-}
-
-
-/*
-=================
-UI_DrawProportionalString
-=================
-*/
-void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ) {
- vec4_t drawcolor;
- int width;
- float sizeScale;
-
- sizeScale = UI_ProportionalSizeScale( style );
-
- switch( style & UI_FORMATMASK ) {
- case UI_CENTER:
- width = UI_ProportionalStringWidth( str ) * sizeScale;
- x -= width / 2;
- break;
-
- case UI_RIGHT:
- width = UI_ProportionalStringWidth( str ) * sizeScale;
- x -= width;
- break;
-
- case UI_LEFT:
- default:
- break;
- }
-
- if ( style & UI_DROPSHADOW ) {
- drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
- drawcolor[3] = color[3];
- UI_DrawProportionalString2( x+2, y+2, str, drawcolor, sizeScale, cgs.media.charsetProp );
- }
-
- if ( style & UI_INVERSE ) {
- drawcolor[0] = color[0] * 0.8;
- drawcolor[1] = color[1] * 0.8;
- drawcolor[2] = color[2] * 0.8;
- drawcolor[3] = color[3];
- UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, cgs.media.charsetProp );
- return;
- }
-
- if ( style & UI_PULSE ) {
- drawcolor[0] = color[0] * 0.8;
- drawcolor[1] = color[1] * 0.8;
- drawcolor[2] = color[2] * 0.8;
- drawcolor[3] = color[3];
- UI_DrawProportionalString2( x, y, str, color, sizeScale, cgs.media.charsetProp );
-
- drawcolor[0] = color[0];
- drawcolor[1] = color[1];
- drawcolor[2] = color[2];
- drawcolor[3] = 0.5 + 0.5 * sin( cg.time / PULSE_DIVISOR );
- UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, cgs.media.charsetPropGlow );
- return;
- }
-
- UI_DrawProportionalString2( x, y, str, color, sizeScale, cgs.media.charsetProp );
-}
diff --git a/engine/code/cgame/cg_effects.c b/engine/code/cgame/cg_effects.c
deleted file mode 100644
index 99f6499..0000000
--- a/engine/code/cgame/cg_effects.c
+++ /dev/null
@@ -1,718 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_effects.c -- these functions generate localentities, usually as a result
-// of event processing
-
-#include "cg_local.h"
-
-
-/*
-==================
-CG_BubbleTrail
-
-Bullets shot underwater
-==================
-*/
-void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ) {
- vec3_t move;
- vec3_t vec;
- float len;
- int i;
-
- if ( cg_noProjectileTrail.integer ) {
- return;
- }
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- // advance a random amount first
- i = rand() % (int)spacing;
- VectorMA( move, i, vec, move );
-
- VectorScale (vec, spacing, vec);
-
- for ( ; i < len; i += spacing ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- le->leFlags = LEF_PUFF_DONT_SCALE;
- le->leType = LE_MOVE_SCALE_FADE;
- le->startTime = cg.time;
- le->endTime = cg.time + 1000 + random() * 250;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- re = &le->refEntity;
- re->shaderTime = cg.time / 1000.0f;
-
- re->reType = RT_SPRITE;
- re->rotation = 0;
- re->radius = 3;
- re->customShader = cgs.media.waterBubbleShader;
- re->shaderRGBA[0] = 0xff;
- re->shaderRGBA[1] = 0xff;
- re->shaderRGBA[2] = 0xff;
- re->shaderRGBA[3] = 0xff;
-
- le->color[3] = 1.0;
-
- le->pos.trType = TR_LINEAR;
- le->pos.trTime = cg.time;
- VectorCopy( move, le->pos.trBase );
- le->pos.trDelta[0] = crandom()*5;
- le->pos.trDelta[1] = crandom()*5;
- le->pos.trDelta[2] = crandom()*5 + 6;
-
- VectorAdd (move, vec, move);
- }
-}
-
-/*
-=====================
-CG_SmokePuff
-
-Adds a smoke puff or blood trail localEntity.
-=====================
-*/
-localEntity_t *CG_SmokePuff( const vec3_t p, const vec3_t vel,
- float radius,
- float r, float g, float b, float a,
- float duration,
- int startTime,
- int fadeInTime,
- int leFlags,
- qhandle_t hShader ) {
- static int seed = 0x92;
- localEntity_t *le;
- refEntity_t *re;
-// int fadeInTime = startTime + duration / 2;
-
- le = CG_AllocLocalEntity();
- le->leFlags = leFlags;
- le->radius = radius;
-
- re = &le->refEntity;
- re->rotation = Q_random( &seed ) * 360;
- re->radius = radius;
- re->shaderTime = startTime / 1000.0f;
-
- le->leType = LE_MOVE_SCALE_FADE;
- le->startTime = startTime;
- le->fadeInTime = fadeInTime;
- le->endTime = startTime + duration;
- if ( fadeInTime > startTime ) {
- le->lifeRate = 1.0 / ( le->endTime - le->fadeInTime );
- }
- else {
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
- }
- le->color[0] = r;
- le->color[1] = g;
- le->color[2] = b;
- le->color[3] = a;
-
-
- le->pos.trType = TR_LINEAR;
- le->pos.trTime = startTime;
- VectorCopy( vel, le->pos.trDelta );
- VectorCopy( p, le->pos.trBase );
-
- VectorCopy( p, re->origin );
- re->customShader = hShader;
-
- // rage pro can't alpha fade, so use a different shader
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
- re->customShader = cgs.media.smokePuffRageProShader;
- re->shaderRGBA[0] = 0xff;
- re->shaderRGBA[1] = 0xff;
- re->shaderRGBA[2] = 0xff;
- re->shaderRGBA[3] = 0xff;
- } else {
- re->shaderRGBA[0] = le->color[0] * 0xff;
- re->shaderRGBA[1] = le->color[1] * 0xff;
- re->shaderRGBA[2] = le->color[2] * 0xff;
- re->shaderRGBA[3] = 0xff;
- }
-
- re->reType = RT_SPRITE;
- re->radius = le->radius;
-
- return le;
-}
-
-/*
-==================
-CG_SpawnEffect
-
-Player teleporting in or out
-==================
-*/
-void CG_SpawnEffect( vec3_t org ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_FADE_RGB;
- le->startTime = cg.time;
- le->endTime = cg.time + 500;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
-
- re = &le->refEntity;
-
- re->reType = RT_MODEL;
- re->shaderTime = cg.time / 1000.0f;
-
-#ifndef MISSIONPACK
- re->customShader = cgs.media.teleportEffectShader;
-#endif
- re->hModel = cgs.media.teleportEffectModel;
- AxisClear( re->axis );
-
- VectorCopy( org, re->origin );
-#ifdef MISSIONPACK
- re->origin[2] += 16;
-#else
- re->origin[2] -= 24;
-#endif
-}
-
-
-#ifdef MISSIONPACK
-/*
-===============
-CG_LightningBoltBeam
-===============
-*/
-void CG_LightningBoltBeam( vec3_t start, vec3_t end ) {
- localEntity_t *le;
- refEntity_t *beam;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_SHOWREFENTITY;
- le->startTime = cg.time;
- le->endTime = cg.time + 50;
-
- beam = &le->refEntity;
-
- VectorCopy( start, beam->origin );
- // this is the end point
- VectorCopy( end, beam->oldorigin );
-
- beam->reType = RT_LIGHTNING;
- beam->customShader = cgs.media.lightningShader;
-}
-
-/*
-==================
-CG_KamikazeEffect
-==================
-*/
-void CG_KamikazeEffect( vec3_t org ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_KAMIKAZE;
- le->startTime = cg.time;
- le->endTime = cg.time + 3000;//2250;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
-
- VectorClear(le->angles.trBase);
-
- re = &le->refEntity;
-
- re->reType = RT_MODEL;
- re->shaderTime = cg.time / 1000.0f;
-
- re->hModel = cgs.media.kamikazeEffectModel;
-
- VectorCopy( org, re->origin );
-
-}
-
-/*
-==================
-CG_ObeliskExplode
-==================
-*/
-void CG_ObeliskExplode( vec3_t org, int entityNum ) {
- localEntity_t *le;
- vec3_t origin;
-
- // create an explosion
- VectorCopy( org, origin );
- origin[2] += 64;
- le = CG_MakeExplosion( origin, vec3_origin,
- cgs.media.dishFlashModel,
- cgs.media.rocketExplosionShader,
- 600, qtrue );
- le->light = 300;
- le->lightColor[0] = 1;
- le->lightColor[1] = 0.75;
- le->lightColor[2] = 0.0;
-}
-
-/*
-==================
-CG_ObeliskPain
-==================
-*/
-void CG_ObeliskPain( vec3_t org ) {
- float r;
- sfxHandle_t sfx;
-
- // hit sound
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.obeliskHitSound1;
- } else if ( r == 2 ) {
- sfx = cgs.media.obeliskHitSound2;
- } else {
- sfx = cgs.media.obeliskHitSound3;
- }
- trap_S_StartSound ( org, ENTITYNUM_NONE, CHAN_BODY, sfx );
-}
-
-
-/*
-==================
-CG_InvulnerabilityImpact
-==================
-*/
-void CG_InvulnerabilityImpact( vec3_t org, vec3_t angles ) {
- localEntity_t *le;
- refEntity_t *re;
- int r;
- sfxHandle_t sfx;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_INVULIMPACT;
- le->startTime = cg.time;
- le->endTime = cg.time + 1000;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
-
- re = &le->refEntity;
-
- re->reType = RT_MODEL;
- re->shaderTime = cg.time / 1000.0f;
-
- re->hModel = cgs.media.invulnerabilityImpactModel;
-
- VectorCopy( org, re->origin );
- AnglesToAxis( angles, re->axis );
-
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.invulnerabilityImpactSound1;
- } else if ( r == 2 ) {
- sfx = cgs.media.invulnerabilityImpactSound2;
- } else {
- sfx = cgs.media.invulnerabilityImpactSound3;
- }
- trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, sfx );
-}
-
-/*
-==================
-CG_InvulnerabilityJuiced
-==================
-*/
-void CG_InvulnerabilityJuiced( vec3_t org ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t angles;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_INVULJUICED;
- le->startTime = cg.time;
- le->endTime = cg.time + 10000;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
-
- re = &le->refEntity;
-
- re->reType = RT_MODEL;
- re->shaderTime = cg.time / 1000.0f;
-
- re->hModel = cgs.media.invulnerabilityJuicedModel;
-
- VectorCopy( org, re->origin );
- VectorClear(angles);
- AnglesToAxis( angles, re->axis );
-
- trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, cgs.media.invulnerabilityJuicedSound );
-}
-
-#endif
-
-/*
-==================
-CG_ScorePlum
-==================
-*/
-void CG_ScorePlum( int client, vec3_t org, int score ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t angles;
- static vec3_t lastPos;
-
- // only visualize for the client that scored
- if (client != cg.predictedPlayerState.clientNum || cg_scorePlum.integer == 0) {
- return;
- }
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_SCOREPLUM;
- le->startTime = cg.time;
- le->endTime = cg.time + 4000;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
- le->radius = score;
-
- VectorCopy( org, le->pos.trBase );
- if (org[2] >= lastPos[2] - 20 && org[2] <= lastPos[2] + 20) {
- le->pos.trBase[2] -= 20;
- }
-
- //CG_Printf( "Plum origin %i %i %i -- %i\n", (int)org[0], (int)org[1], (int)org[2], (int)Distance(org, lastPos));
- VectorCopy(org, lastPos);
-
-
- re = &le->refEntity;
-
- re->reType = RT_SPRITE;
- re->radius = 16;
-
- VectorClear(angles);
- AnglesToAxis( angles, re->axis );
-}
-
-
-/*
-====================
-CG_MakeExplosion
-====================
-*/
-localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
- qhandle_t hModel, qhandle_t shader,
- int msec, qboolean isSprite ) {
- float ang;
- localEntity_t *ex;
- int offset;
- vec3_t tmpVec, newOrigin;
-
- if ( msec <= 0 ) {
- CG_Error( "CG_MakeExplosion: msec = %i", msec );
- }
-
- // skew the time a bit so they aren't all in sync
- offset = rand() & 63;
-
- ex = CG_AllocLocalEntity();
- if ( isSprite ) {
- ex->leType = LE_SPRITE_EXPLOSION;
-
- // randomly rotate sprite orientation
- ex->refEntity.rotation = rand() % 360;
- VectorScale( dir, 16, tmpVec );
- VectorAdd( tmpVec, origin, newOrigin );
- } else {
- ex->leType = LE_EXPLOSION;
- VectorCopy( origin, newOrigin );
-
- // set axis with random rotate
- if ( !dir ) {
- AxisClear( ex->refEntity.axis );
- } else {
- ang = rand() % 360;
- VectorCopy( dir, ex->refEntity.axis[0] );
- RotateAroundDirection( ex->refEntity.axis, ang );
- }
- }
-
- ex->startTime = cg.time - offset;
- ex->endTime = ex->startTime + msec;
-
- // bias the time so all shader effects start correctly
- ex->refEntity.shaderTime = ex->startTime / 1000.0f;
-
- ex->refEntity.hModel = hModel;
- ex->refEntity.customShader = shader;
-
- // set origin
- VectorCopy( newOrigin, ex->refEntity.origin );
- VectorCopy( newOrigin, ex->refEntity.oldorigin );
-
- ex->color[0] = ex->color[1] = ex->color[2] = 1.0;
-
- return ex;
-}
-
-
-/*
-=================
-CG_Bleed
-
-This is the spurt of blood when a character gets hit
-=================
-*/
-void CG_Bleed( vec3_t origin, int entityNum ) {
- localEntity_t *ex;
-
- if ( !cg_blood.integer ) {
- return;
- }
-
- ex = CG_AllocLocalEntity();
- ex->leType = LE_EXPLOSION;
-
- ex->startTime = cg.time;
- ex->endTime = ex->startTime + 500;
-
- VectorCopy ( origin, ex->refEntity.origin);
- ex->refEntity.reType = RT_SPRITE;
- ex->refEntity.rotation = rand() % 360;
- ex->refEntity.radius = 24;
-
- ex->refEntity.customShader = cgs.media.bloodExplosionShader;
-
- // don't show player's own blood in view
- if ( entityNum == cg.snap->ps.clientNum ) {
- ex->refEntity.renderfx |= RF_THIRD_PERSON;
- }
-}
-
-
-
-/*
-==================
-CG_LaunchGib
-==================
-*/
-void CG_LaunchGib( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + 5000 + random() * 3000;
-
- VectorCopy( origin, re->origin );
- AxisCopy( axisDefault, re->axis );
- re->hModel = hModel;
-
- le->pos.trType = TR_GRAVITY;
- VectorCopy( origin, le->pos.trBase );
- VectorCopy( velocity, le->pos.trDelta );
- le->pos.trTime = cg.time;
-
- le->bounceFactor = 0.6f;
-
- le->leBounceSoundType = LEBS_BLOOD;
- le->leMarkType = LEMT_BLOOD;
-}
-
-/*
-===================
-CG_GibPlayer
-
-Generated a bunch of gibs launching out from the bodies location
-===================
-*/
-#define GIB_VELOCITY 250
-#define GIB_JUMP 250
-void CG_GibPlayer( vec3_t playerOrigin ) {
- vec3_t origin, velocity;
-
- if ( !cg_blood.integer ) {
- return;
- }
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- if ( rand() & 1 ) {
- CG_LaunchGib( origin, velocity, cgs.media.gibSkull );
- } else {
- CG_LaunchGib( origin, velocity, cgs.media.gibBrain );
- }
-
- // allow gibs to be turned off for speed
- if ( !cg_gibs.integer ) {
- return;
- }
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibAbdomen );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibArm );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibChest );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibFist );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibFoot );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibForearm );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibIntestine );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
-}
-
-/*
-==================
-CG_LaunchGib
-==================
-*/
-void CG_LaunchExplode( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + 10000 + random() * 6000;
-
- VectorCopy( origin, re->origin );
- AxisCopy( axisDefault, re->axis );
- re->hModel = hModel;
-
- le->pos.trType = TR_GRAVITY;
- VectorCopy( origin, le->pos.trBase );
- VectorCopy( velocity, le->pos.trDelta );
- le->pos.trTime = cg.time;
-
- le->bounceFactor = 0.1f;
-
- le->leBounceSoundType = LEBS_BRASS;
- le->leMarkType = LEMT_NONE;
-}
-
-#define EXP_VELOCITY 100
-#define EXP_JUMP 150
-/*
-===================
-CG_GibPlayer
-
-Generated a bunch of gibs launching out from the bodies location
-===================
-*/
-void CG_BigExplode( vec3_t playerOrigin ) {
- vec3_t origin, velocity;
-
- if ( !cg_blood.integer ) {
- return;
- }
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY;
- velocity[1] = crandom()*EXP_VELOCITY;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY;
- velocity[1] = crandom()*EXP_VELOCITY;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY*1.5;
- velocity[1] = crandom()*EXP_VELOCITY*1.5;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY*2.0;
- velocity[1] = crandom()*EXP_VELOCITY*2.0;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY*2.5;
- velocity[1] = crandom()*EXP_VELOCITY*2.5;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-}
-
diff --git a/engine/code/cgame/cg_ents.c b/engine/code/cgame/cg_ents.c
deleted file mode 100644
index a6a5c2a..0000000
--- a/engine/code/cgame/cg_ents.c
+++ /dev/null
@@ -1,1037 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_ents.c -- present snapshot entities, happens every single frame
-
-#include "cg_local.h"
-
-
-/*
-======================
-CG_PositionEntityOnTag
-
-Modifies the entities position and axis by the given
-tag location
-======================
-*/
-void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- qhandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
-
- // lerp the tag
- trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // had to cast away the const to avoid compiler problems...
- MatrixMultiply( lerped.axis, ((refEntity_t *)parent)->axis, entity->axis );
- entity->backlerp = parent->backlerp;
-}
-
-
-/*
-======================
-CG_PositionRotatedEntityOnTag
-
-Modifies the entities position and axis by the given
-tag location
-======================
-*/
-void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- qhandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
- vec3_t tempAxis[3];
-
-//AxisClear( entity->axis );
- // lerp the tag
- trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // had to cast away the const to avoid compiler problems...
- MatrixMultiply( entity->axis, lerped.axis, tempAxis );
- MatrixMultiply( tempAxis, ((refEntity_t *)parent)->axis, entity->axis );
-}
-
-
-
-/*
-==========================================================================
-
-FUNCTIONS CALLED EACH FRAME
-
-==========================================================================
-*/
-
-/*
-======================
-CG_SetEntitySoundPosition
-
-Also called by event processing code
-======================
-*/
-void CG_SetEntitySoundPosition( centity_t *cent ) {
- if ( cent->currentState.solid == SOLID_BMODEL ) {
- vec3_t origin;
- float *v;
-
- v = cgs.inlineModelMidpoints[ cent->currentState.modelindex ];
- VectorAdd( cent->lerpOrigin, v, origin );
- trap_S_UpdateEntityPosition( cent->currentState.number, origin );
- } else {
- trap_S_UpdateEntityPosition( cent->currentState.number, cent->lerpOrigin );
- }
-}
-
-/*
-==================
-CG_EntityEffects
-
-Add continuous entity effects, like local entity emission and lighting
-==================
-*/
-static void CG_EntityEffects( centity_t *cent ) {
-
- // update sound origins
- CG_SetEntitySoundPosition( cent );
-
- // add loop sound
- if ( cent->currentState.loopSound ) {
- if (cent->currentState.eType != ET_SPEAKER) {
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin,
- cgs.gameSounds[ cent->currentState.loopSound ] );
- } else {
- trap_S_AddRealLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin,
- cgs.gameSounds[ cent->currentState.loopSound ] );
- }
- }
-
-
- // constant light glow
- if ( cent->currentState.constantLight ) {
- int cl;
- int i, r, g, b;
-
- cl = cent->currentState.constantLight;
- r = cl & 255;
- g = ( cl >> 8 ) & 255;
- b = ( cl >> 16 ) & 255;
- i = ( ( cl >> 24 ) & 255 ) * 4;
- trap_R_AddLightToScene( cent->lerpOrigin, i, r, g, b );
- }
-
-}
-
-
-/*
-==================
-CG_General
-==================
-*/
-static void CG_General( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
-
- s1 = ¢->currentState;
-
- // if set to invisible, skip
- if (!s1->modelindex) {
- return;
- }
-
- memset (&ent, 0, sizeof(ent));
-
- // set frame
-
- ent.frame = s1->frame;
- ent.oldframe = ent.frame;
- ent.backlerp = 0;
-
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
-
- ent.hModel = cgs.gameModels[s1->modelindex];
-
- // player model
- if (s1->number == cg.snap->ps.clientNum) {
- ent.renderfx |= RF_THIRD_PERSON; // only draw from mirrors
- }
-
- // convert angles to axis
- AnglesToAxis( cent->lerpAngles, ent.axis );
-
- // add to refresh list
- trap_R_AddRefEntityToScene (&ent);
-}
-
-/*
-==================
-CG_Speaker
-
-Speaker entities can automatically play sounds
-==================
-*/
-static void CG_Speaker( centity_t *cent ) {
- if ( ! cent->currentState.clientNum ) { // FIXME: use something other than clientNum...
- return; // not auto triggering
- }
-
- if ( cg.time < cent->miscTime ) {
- return;
- }
-
- trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.gameSounds[cent->currentState.eventParm] );
-
- // ent->s.frame = ent->wait * 10;
- // ent->s.clientNum = ent->random * 10;
- cent->miscTime = cg.time + cent->currentState.frame * 100 + cent->currentState.clientNum * 100 * crandom();
-}
-
-/*
-==================
-CG_Item
-==================
-*/
-static void CG_Item( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *es;
- gitem_t *item;
- int msec;
- float frac;
- float scale;
- weaponInfo_t *wi;
-
- es = ¢->currentState;
- if ( es->modelindex >= bg_numItems ) {
- CG_Error( "Bad item index %i on entity", es->modelindex );
- }
-
- // if set to invisible, skip
- if ( !es->modelindex || ( es->eFlags & EF_NODRAW ) ) {
- return;
- }
-
- item = &bg_itemlist[ es->modelindex ];
- if ( cg_simpleItems.integer && item->giType != IT_TEAM ) {
- memset( &ent, 0, sizeof( ent ) );
- ent.reType = RT_SPRITE;
- VectorCopy( cent->lerpOrigin, ent.origin );
- ent.radius = 14;
- ent.customShader = cg_items[es->modelindex].icon;
- ent.shaderRGBA[0] = 255;
- ent.shaderRGBA[1] = 255;
- ent.shaderRGBA[2] = 255;
- ent.shaderRGBA[3] = 255;
- trap_R_AddRefEntityToScene(&ent);
- return;
- }
-
- // items bob up and down continuously
- scale = 0.005 + cent->currentState.number * 0.00001;
- cent->lerpOrigin[2] += 4 + cos( ( cg.time + 1000 ) * scale ) * 4;
-
- memset (&ent, 0, sizeof(ent));
-
- // autorotate at one of two speeds
- if ( item->giType == IT_HEALTH ) {
- VectorCopy( cg.autoAnglesFast, cent->lerpAngles );
- AxisCopy( cg.autoAxisFast, ent.axis );
- } else {
- VectorCopy( cg.autoAngles, cent->lerpAngles );
- AxisCopy( cg.autoAxis, ent.axis );
- }
-
- wi = NULL;
- // the weapons have their origin where they attatch to player
- // models, so we need to offset them or they will rotate
- // eccentricly
- if ( item->giType == IT_WEAPON ) {
- wi = &cg_weapons[item->giTag];
- cent->lerpOrigin[0] -=
- wi->weaponMidpoint[0] * ent.axis[0][0] +
- wi->weaponMidpoint[1] * ent.axis[1][0] +
- wi->weaponMidpoint[2] * ent.axis[2][0];
- cent->lerpOrigin[1] -=
- wi->weaponMidpoint[0] * ent.axis[0][1] +
- wi->weaponMidpoint[1] * ent.axis[1][1] +
- wi->weaponMidpoint[2] * ent.axis[2][1];
- cent->lerpOrigin[2] -=
- wi->weaponMidpoint[0] * ent.axis[0][2] +
- wi->weaponMidpoint[1] * ent.axis[1][2] +
- wi->weaponMidpoint[2] * ent.axis[2][2];
-
- cent->lerpOrigin[2] += 8; // an extra height boost
- }
-
- ent.hModel = cg_items[es->modelindex].models[0];
-
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
-
- ent.nonNormalizedAxes = qfalse;
-
- // if just respawned, slowly scale up
- msec = cg.time - cent->miscTime;
- if ( msec >= 0 && msec < ITEM_SCALEUP_TIME ) {
- frac = (float)msec / ITEM_SCALEUP_TIME;
- VectorScale( ent.axis[0], frac, ent.axis[0] );
- VectorScale( ent.axis[1], frac, ent.axis[1] );
- VectorScale( ent.axis[2], frac, ent.axis[2] );
- ent.nonNormalizedAxes = qtrue;
- } else {
- frac = 1.0;
- }
-
- // items without glow textures need to keep a minimum light value
- // so they are always visible
- if ( ( item->giType == IT_WEAPON ) ||
- ( item->giType == IT_ARMOR ) ) {
- ent.renderfx |= RF_MINLIGHT;
- }
-
- // increase the size of the weapons when they are presented as items
- if ( item->giType == IT_WEAPON ) {
- VectorScale( ent.axis[0], 1.5, ent.axis[0] );
- VectorScale( ent.axis[1], 1.5, ent.axis[1] );
- VectorScale( ent.axis[2], 1.5, ent.axis[2] );
- ent.nonNormalizedAxes = qtrue;
-#ifdef MISSIONPACK
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.weaponHoverSound );
-#endif
- }
-
-#ifdef MISSIONPACK
- if ( item->giType == IT_HOLDABLE && item->giTag == HI_KAMIKAZE ) {
- VectorScale( ent.axis[0], 2, ent.axis[0] );
- VectorScale( ent.axis[1], 2, ent.axis[1] );
- VectorScale( ent.axis[2], 2, ent.axis[2] );
- ent.nonNormalizedAxes = qtrue;
- }
-#endif
-
- // add to refresh list
- trap_R_AddRefEntityToScene(&ent);
-
-#ifdef MISSIONPACK
- if ( item->giType == IT_WEAPON && wi->barrelModel ) {
- refEntity_t barrel;
-
- memset( &barrel, 0, sizeof( barrel ) );
-
- barrel.hModel = wi->barrelModel;
-
- VectorCopy( ent.lightingOrigin, barrel.lightingOrigin );
- barrel.shadowPlane = ent.shadowPlane;
- barrel.renderfx = ent.renderfx;
-
- CG_PositionRotatedEntityOnTag( &barrel, &ent, wi->weaponModel, "tag_barrel" );
-
- AxisCopy( ent.axis, barrel.axis );
- barrel.nonNormalizedAxes = ent.nonNormalizedAxes;
-
- trap_R_AddRefEntityToScene( &barrel );
- }
-#endif
-
- // accompanying rings / spheres for powerups
- if ( !cg_simpleItems.integer )
- {
- vec3_t spinAngles;
-
- VectorClear( spinAngles );
-
- if ( item->giType == IT_HEALTH || item->giType == IT_POWERUP )
- {
- if ( ( ent.hModel = cg_items[es->modelindex].models[1] ) != 0 )
- {
- if ( item->giType == IT_POWERUP )
- {
- ent.origin[2] += 12;
- spinAngles[1] = ( cg.time & 1023 ) * 360 / -1024.0f;
- }
- AnglesToAxis( spinAngles, ent.axis );
-
- // scale up if respawning
- if ( frac != 1.0 ) {
- VectorScale( ent.axis[0], frac, ent.axis[0] );
- VectorScale( ent.axis[1], frac, ent.axis[1] );
- VectorScale( ent.axis[2], frac, ent.axis[2] );
- ent.nonNormalizedAxes = qtrue;
- }
- trap_R_AddRefEntityToScene( &ent );
- }
- }
- }
-}
-
-//============================================================================
-
-/*
-===============
-CG_Missile
-===============
-*/
-static void CG_Missile( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
- const weaponInfo_t *weapon;
-// int col;
-
- s1 = ¢->currentState;
- if ( s1->weapon > WP_NUM_WEAPONS ) {
- s1->weapon = 0;
- }
- weapon = &cg_weapons[s1->weapon];
-
- // calculate the axis
- VectorCopy( s1->angles, cent->lerpAngles);
-
- // add trails
- if ( weapon->missileTrailFunc )
- {
- weapon->missileTrailFunc( cent, weapon );
- }
-/*
- if ( cent->currentState.modelindex == TEAM_RED ) {
- col = 1;
- }
- else if ( cent->currentState.modelindex == TEAM_BLUE ) {
- col = 2;
- }
- else {
- col = 0;
- }
-
- // add dynamic light
- if ( weapon->missileDlight ) {
- trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight,
- weapon->missileDlightColor[col][0], weapon->missileDlightColor[col][1], weapon->missileDlightColor[col][2] );
- }
-*/
- // add dynamic light
- if ( weapon->missileDlight ) {
- trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight,
- weapon->missileDlightColor[0], weapon->missileDlightColor[1], weapon->missileDlightColor[2] );
- }
-
- // add missile sound
- if ( weapon->missileSound ) {
- vec3_t velocity;
-
- BG_EvaluateTrajectoryDelta( ¢->currentState.pos, cg.time, velocity );
-
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, weapon->missileSound );
- }
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
-
- if ( cent->currentState.weapon == WP_PLASMAGUN ) {
- ent.reType = RT_SPRITE;
- ent.radius = 16;
- ent.rotation = 0;
- ent.customShader = cgs.media.plasmaBallShader;
- trap_R_AddRefEntityToScene( &ent );
- return;
- }
-
- // flicker between two skins
- ent.skinNum = cg.clientFrame & 1;
- ent.hModel = weapon->missileModel;
- ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
-
-#ifdef MISSIONPACK
- if ( cent->currentState.weapon == WP_PROX_LAUNCHER ) {
- if (s1->generic1 == TEAM_BLUE) {
- ent.hModel = cgs.media.blueProxMine;
- }
- }
-#endif
-
- // convert direction of travel into axis
- if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {
- ent.axis[0][2] = 1;
- }
-
- // spin as it moves
- if ( s1->pos.trType != TR_STATIONARY ) {
- RotateAroundDirection( ent.axis, cg.time / 4 );
- } else {
-#ifdef MISSIONPACK
- if ( s1->weapon == WP_PROX_LAUNCHER ) {
- AnglesToAxis( cent->lerpAngles, ent.axis );
- }
- else
-#endif
- {
- RotateAroundDirection( ent.axis, s1->time );
- }
- }
-
- // add to refresh list, possibly with quad glow
- CG_AddRefEntityWithPowerups( &ent, s1, TEAM_FREE );
-}
-
-/*
-===============
-CG_Grapple
-
-This is called when the grapple is sitting up against the wall
-===============
-*/
-static void CG_Grapple( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
- const weaponInfo_t *weapon;
-
- s1 = ¢->currentState;
- if ( s1->weapon > WP_NUM_WEAPONS ) {
- s1->weapon = 0;
- }
- weapon = &cg_weapons[s1->weapon];
-
- // calculate the axis
- VectorCopy( s1->angles, cent->lerpAngles);
-
-#if 0 // FIXME add grapple pull sound here..?
- // add missile sound
- if ( weapon->missileSound ) {
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->missileSound );
- }
-#endif
-
- // Will draw cable if needed
- CG_GrappleTrail ( cent, weapon );
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
-
- // flicker between two skins
- ent.skinNum = cg.clientFrame & 1;
- ent.hModel = weapon->missileModel;
- ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
-
- // convert direction of travel into axis
- if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {
- ent.axis[0][2] = 1;
- }
-
- trap_R_AddRefEntityToScene( &ent );
-}
-
-/*
-===============
-CG_Mover
-===============
-*/
-static void CG_Mover( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
-
- s1 = ¢->currentState;
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
- AnglesToAxis( cent->lerpAngles, ent.axis );
-
- ent.renderfx = RF_NOSHADOW;
-
- // flicker between two skins (FIXME?)
- ent.skinNum = ( cg.time >> 6 ) & 1;
-
- // get the model, either as a bmodel or a modelindex
- if ( s1->solid == SOLID_BMODEL ) {
- ent.hModel = cgs.inlineDrawModel[s1->modelindex];
- } else {
- ent.hModel = cgs.gameModels[s1->modelindex];
- }
-
- // add to refresh list
- trap_R_AddRefEntityToScene(&ent);
-
- // add the secondary model
- if ( s1->modelindex2 ) {
- ent.skinNum = 0;
- ent.hModel = cgs.gameModels[s1->modelindex2];
- trap_R_AddRefEntityToScene(&ent);
- }
-
-}
-
-/*
-===============
-CG_Beam
-
-Also called as an event
-===============
-*/
-void CG_Beam( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
-
- s1 = ¢->currentState;
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( s1->pos.trBase, ent.origin );
- VectorCopy( s1->origin2, ent.oldorigin );
- AxisClear( ent.axis );
- ent.reType = RT_BEAM;
-
- ent.renderfx = RF_NOSHADOW;
-
- // add to refresh list
- trap_R_AddRefEntityToScene(&ent);
-}
-
-
-/*
-===============
-CG_Portal
-===============
-*/
-static void CG_Portal( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
-
- s1 = ¢->currentState;
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( cent->lerpOrigin, ent.origin );
- VectorCopy( s1->origin2, ent.oldorigin );
- ByteToDir( s1->eventParm, ent.axis[0] );
- PerpendicularVector( ent.axis[1], ent.axis[0] );
-
- // negating this tends to get the directions like they want
- // we really should have a camera roll value
- VectorSubtract( vec3_origin, ent.axis[1], ent.axis[1] );
-
- CrossProduct( ent.axis[0], ent.axis[1], ent.axis[2] );
- ent.reType = RT_PORTALSURFACE;
- ent.oldframe = s1->powerups;
- ent.frame = s1->frame; // rotation speed
- ent.skinNum = s1->clientNum/256.0 * 360; // roll offset
-
- // add to refresh list
- trap_R_AddRefEntityToScene(&ent);
-}
-
-
-/*
-=========================
-CG_AdjustPositionForMover
-
-Also called by client movement prediction code
-=========================
-*/
-void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out ) {
- centity_t *cent;
- vec3_t oldOrigin, origin, deltaOrigin;
- vec3_t oldAngles, angles, deltaAngles;
-
- if ( moverNum <= 0 || moverNum >= ENTITYNUM_MAX_NORMAL ) {
- VectorCopy( in, out );
- return;
- }
-
- cent = &cg_entities[ moverNum ];
- if ( cent->currentState.eType != ET_MOVER ) {
- VectorCopy( in, out );
- return;
- }
-
- BG_EvaluateTrajectory( ¢->currentState.pos, fromTime, oldOrigin );
- BG_EvaluateTrajectory( ¢->currentState.apos, fromTime, oldAngles );
-
- BG_EvaluateTrajectory( ¢->currentState.pos, toTime, origin );
- BG_EvaluateTrajectory( ¢->currentState.apos, toTime, angles );
-
- VectorSubtract( origin, oldOrigin, deltaOrigin );
- VectorSubtract( angles, oldAngles, deltaAngles );
-
- VectorAdd( in, deltaOrigin, out );
-
- // FIXME: origin change when on a rotating object
-}
-
-
-/*
-=============================
-CG_InterpolateEntityPosition
-=============================
-*/
-static void CG_InterpolateEntityPosition( centity_t *cent ) {
- vec3_t current, next;
- float f;
-
- // it would be an internal error to find an entity that interpolates without
- // a snapshot ahead of the current one
- if ( cg.nextSnap == NULL ) {
- CG_Error( "CG_InterpoateEntityPosition: cg.nextSnap == NULL" );
- }
-
- f = cg.frameInterpolation;
-
- // this will linearize a sine or parabolic curve, but it is important
- // to not extrapolate player positions if more recent data is available
- BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, current );
- BG_EvaluateTrajectory( ¢->nextState.pos, cg.nextSnap->serverTime, next );
-
- cent->lerpOrigin[0] = current[0] + f * ( next[0] - current[0] );
- cent->lerpOrigin[1] = current[1] + f * ( next[1] - current[1] );
- cent->lerpOrigin[2] = current[2] + f * ( next[2] - current[2] );
-
- BG_EvaluateTrajectory( ¢->currentState.apos, cg.snap->serverTime, current );
- BG_EvaluateTrajectory( ¢->nextState.apos, cg.nextSnap->serverTime, next );
-
- cent->lerpAngles[0] = LerpAngle( current[0], next[0], f );
- cent->lerpAngles[1] = LerpAngle( current[1], next[1], f );
- cent->lerpAngles[2] = LerpAngle( current[2], next[2], f );
-
-}
-
-/*
-===============
-CG_CalcEntityLerpPositions
-
-===============
-*/
-static void CG_CalcEntityLerpPositions( centity_t *cent ) {
-
- // if this player does not want to see extrapolated players
- if ( !cg_smoothClients.integer ) {
- // make sure the clients use TR_INTERPOLATE
- if ( cent->currentState.number < MAX_CLIENTS ) {
- cent->currentState.pos.trType = TR_INTERPOLATE;
- cent->nextState.pos.trType = TR_INTERPOLATE;
- }
- }
-
- if ( cent->interpolate && cent->currentState.pos.trType == TR_INTERPOLATE ) {
- CG_InterpolateEntityPosition( cent );
- return;
- }
-
- // first see if we can interpolate between two snaps for
- // linear extrapolated clients
- if ( cent->interpolate && cent->currentState.pos.trType == TR_LINEAR_STOP &&
- cent->currentState.number < MAX_CLIENTS) {
- CG_InterpolateEntityPosition( cent );
- return;
- }
-
- // just use the current frame and evaluate as best we can
- BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin );
- BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles );
-
- // adjust for riding a mover if it wasn't rolled into the predicted
- // player state
- if ( cent != &cg.predictedPlayerEntity ) {
- CG_AdjustPositionForMover( cent->lerpOrigin, cent->currentState.groundEntityNum,
- cg.snap->serverTime, cg.time, cent->lerpOrigin );
- }
-}
-
-/*
-===============
-CG_TeamBase
-===============
-*/
-static void CG_TeamBase( centity_t *cent ) {
- refEntity_t model;
-#ifdef MISSIONPACK
- vec3_t angles;
- int t, h;
- float c;
-
- if ( cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF ) {
-#else
- if ( cgs.gametype == GT_CTF) {
-#endif
- // show the flag base
- memset(&model, 0, sizeof(model));
- model.reType = RT_MODEL;
- VectorCopy( cent->lerpOrigin, model.lightingOrigin );
- VectorCopy( cent->lerpOrigin, model.origin );
- AnglesToAxis( cent->currentState.angles, model.axis );
- if ( cent->currentState.modelindex == TEAM_RED ) {
- model.hModel = cgs.media.redFlagBaseModel;
- }
- else if ( cent->currentState.modelindex == TEAM_BLUE ) {
- model.hModel = cgs.media.blueFlagBaseModel;
- }
- else {
- model.hModel = cgs.media.neutralFlagBaseModel;
- }
- trap_R_AddRefEntityToScene( &model );
- }
-#ifdef MISSIONPACK
- else if ( cgs.gametype == GT_OBELISK ) {
- // show the obelisk
- memset(&model, 0, sizeof(model));
- model.reType = RT_MODEL;
- VectorCopy( cent->lerpOrigin, model.lightingOrigin );
- VectorCopy( cent->lerpOrigin, model.origin );
- AnglesToAxis( cent->currentState.angles, model.axis );
-
- model.hModel = cgs.media.overloadBaseModel;
- trap_R_AddRefEntityToScene( &model );
- // if hit
- if ( cent->currentState.frame == 1) {
- // show hit model
- // modelindex2 is the health value of the obelisk
- c = cent->currentState.modelindex2;
- model.shaderRGBA[0] = 0xff;
- model.shaderRGBA[1] = c;
- model.shaderRGBA[2] = c;
- model.shaderRGBA[3] = 0xff;
- //
- model.hModel = cgs.media.overloadEnergyModel;
- trap_R_AddRefEntityToScene( &model );
- }
- // if respawning
- if ( cent->currentState.frame == 2) {
- if ( !cent->miscTime ) {
- cent->miscTime = cg.time;
- }
- t = cg.time - cent->miscTime;
- h = (cg_obeliskRespawnDelay.integer - 5) * 1000;
- //
- if (t > h) {
- c = (float) (t - h) / h;
- if (c > 1)
- c = 1;
- }
- else {
- c = 0;
- }
- // show the lights
- AnglesToAxis( cent->currentState.angles, model.axis );
- //
- model.shaderRGBA[0] = c * 0xff;
- model.shaderRGBA[1] = c * 0xff;
- model.shaderRGBA[2] = c * 0xff;
- model.shaderRGBA[3] = c * 0xff;
-
- model.hModel = cgs.media.overloadLightsModel;
- trap_R_AddRefEntityToScene( &model );
- // show the target
- if (t > h) {
- if ( !cent->muzzleFlashTime ) {
- trap_S_StartSound (cent->lerpOrigin, ENTITYNUM_NONE, CHAN_BODY, cgs.media.obeliskRespawnSound);
- cent->muzzleFlashTime = 1;
- }
- VectorCopy(cent->currentState.angles, angles);
- angles[YAW] += (float) 16 * acos(1-c) * 180 / M_PI;
- AnglesToAxis( angles, model.axis );
-
- VectorScale( model.axis[0], c, model.axis[0]);
- VectorScale( model.axis[1], c, model.axis[1]);
- VectorScale( model.axis[2], c, model.axis[2]);
-
- model.shaderRGBA[0] = 0xff;
- model.shaderRGBA[1] = 0xff;
- model.shaderRGBA[2] = 0xff;
- model.shaderRGBA[3] = 0xff;
- //
- model.origin[2] += 56;
- model.hModel = cgs.media.overloadTargetModel;
- trap_R_AddRefEntityToScene( &model );
- }
- else {
- //FIXME: show animated smoke
- }
- }
- else {
- cent->miscTime = 0;
- cent->muzzleFlashTime = 0;
- // modelindex2 is the health value of the obelisk
- c = cent->currentState.modelindex2;
- model.shaderRGBA[0] = 0xff;
- model.shaderRGBA[1] = c;
- model.shaderRGBA[2] = c;
- model.shaderRGBA[3] = 0xff;
- // show the lights
- model.hModel = cgs.media.overloadLightsModel;
- trap_R_AddRefEntityToScene( &model );
- // show the target
- model.origin[2] += 56;
- model.hModel = cgs.media.overloadTargetModel;
- trap_R_AddRefEntityToScene( &model );
- }
- }
- else if ( cgs.gametype == GT_HARVESTER ) {
- // show harvester model
- memset(&model, 0, sizeof(model));
- model.reType = RT_MODEL;
- VectorCopy( cent->lerpOrigin, model.lightingOrigin );
- VectorCopy( cent->lerpOrigin, model.origin );
- AnglesToAxis( cent->currentState.angles, model.axis );
-
- if ( cent->currentState.modelindex == TEAM_RED ) {
- model.hModel = cgs.media.harvesterModel;
- model.customSkin = cgs.media.harvesterRedSkin;
- }
- else if ( cent->currentState.modelindex == TEAM_BLUE ) {
- model.hModel = cgs.media.harvesterModel;
- model.customSkin = cgs.media.harvesterBlueSkin;
- }
- else {
- model.hModel = cgs.media.harvesterNeutralModel;
- model.customSkin = 0;
- }
- trap_R_AddRefEntityToScene( &model );
- }
-#endif
-}
-
-/*
-===============
-CG_AddCEntity
-
-===============
-*/
-static void CG_AddCEntity( centity_t *cent ) {
- // event-only entities will have been dealt with already
- if ( cent->currentState.eType >= ET_EVENTS ) {
- return;
- }
-
- // calculate the current origin
- CG_CalcEntityLerpPositions( cent );
-
- // add automatic effects
- CG_EntityEffects( cent );
-
- switch ( cent->currentState.eType ) {
- default:
- CG_Error( "Bad entity type: %i\n", cent->currentState.eType );
- break;
- case ET_INVISIBLE:
- case ET_PUSH_TRIGGER:
- case ET_TELEPORT_TRIGGER:
- break;
- case ET_GENERAL:
- CG_General( cent );
- break;
- case ET_PLAYER:
- CG_Player( cent );
- break;
- case ET_ITEM:
- CG_Item( cent );
- break;
- case ET_MISSILE:
- CG_Missile( cent );
- break;
- case ET_MOVER:
- CG_Mover( cent );
- break;
- case ET_BEAM:
- CG_Beam( cent );
- break;
- case ET_PORTAL:
- CG_Portal( cent );
- break;
- case ET_SPEAKER:
- CG_Speaker( cent );
- break;
- case ET_GRAPPLE:
- CG_Grapple( cent );
- break;
- case ET_TEAM:
- CG_TeamBase( cent );
- break;
- }
-}
-
-/*
-===============
-CG_AddPacketEntities
-
-===============
-*/
-void CG_AddPacketEntities( void ) {
- int num;
- centity_t *cent;
- playerState_t *ps;
-
- // set cg.frameInterpolation
- if ( cg.nextSnap ) {
- int delta;
-
- delta = (cg.nextSnap->serverTime - cg.snap->serverTime);
- if ( delta == 0 ) {
- cg.frameInterpolation = 0;
- } else {
- cg.frameInterpolation = (float)( cg.time - cg.snap->serverTime ) / delta;
- }
- } else {
- cg.frameInterpolation = 0; // actually, it should never be used, because
- // no entities should be marked as interpolating
- }
-
- // the auto-rotating items will all have the same axis
- cg.autoAngles[0] = 0;
- cg.autoAngles[1] = ( cg.time & 2047 ) * 360 / 2048.0;
- cg.autoAngles[2] = 0;
-
- cg.autoAnglesFast[0] = 0;
- cg.autoAnglesFast[1] = ( cg.time & 1023 ) * 360 / 1024.0f;
- cg.autoAnglesFast[2] = 0;
-
- AnglesToAxis( cg.autoAngles, cg.autoAxis );
- AnglesToAxis( cg.autoAnglesFast, cg.autoAxisFast );
-
- // generate and add the entity from the playerstate
- ps = &cg.predictedPlayerState;
- BG_PlayerStateToEntityState( ps, &cg.predictedPlayerEntity.currentState, qfalse );
- CG_AddCEntity( &cg.predictedPlayerEntity );
-
- // lerp the non-predicted value for lightning gun origins
- CG_CalcEntityLerpPositions( &cg_entities[ cg.snap->ps.clientNum ] );
-
- // add each entity sent over by the server
- for ( num = 0 ; num < cg.snap->numEntities ; num++ ) {
- cent = &cg_entities[ cg.snap->entities[ num ].number ];
- CG_AddCEntity( cent );
- }
-}
-
diff --git a/engine/code/cgame/cg_event.c b/engine/code/cgame/cg_event.c
deleted file mode 100644
index 8700b44..0000000
--- a/engine/code/cgame/cg_event.c
+++ /dev/null
@@ -1,1215 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_event.c -- handle entity events at snapshot or playerstate transitions
-
-#include "cg_local.h"
-
-// for the voice chats
-#ifdef MISSIONPACK
-#include "../../ui/menudef.h"
-#endif
-//==========================================================================
-
-/*
-===================
-CG_PlaceString
-
-Also called by scoreboard drawing
-===================
-*/
-const char *CG_PlaceString( int rank ) {
- static char str[64];
- char *s, *t;
-
- if ( rank & RANK_TIED_FLAG ) {
- rank &= ~RANK_TIED_FLAG;
- t = "Tied for ";
- } else {
- t = "";
- }
-
- if ( rank == 1 ) {
- s = S_COLOR_BLUE "1st" S_COLOR_WHITE; // draw in blue
- } else if ( rank == 2 ) {
- s = S_COLOR_RED "2nd" S_COLOR_WHITE; // draw in red
- } else if ( rank == 3 ) {
- s = S_COLOR_YELLOW "3rd" S_COLOR_WHITE; // draw in yellow
- } else if ( rank == 11 ) {
- s = "11th";
- } else if ( rank == 12 ) {
- s = "12th";
- } else if ( rank == 13 ) {
- s = "13th";
- } else if ( rank % 10 == 1 ) {
- s = va("%ist", rank);
- } else if ( rank % 10 == 2 ) {
- s = va("%ind", rank);
- } else if ( rank % 10 == 3 ) {
- s = va("%ird", rank);
- } else {
- s = va("%ith", rank);
- }
-
- Com_sprintf( str, sizeof( str ), "%s%s", t, s );
- return str;
-}
-
-/*
-=============
-CG_Obituary
-=============
-*/
-static void CG_Obituary( entityState_t *ent ) {
- int mod;
- int target, attacker;
- char *message;
- char *message2;
- const char *targetInfo;
- const char *attackerInfo;
- char targetName[32];
- char attackerName[32];
- gender_t gender;
- clientInfo_t *ci;
-
- target = ent->otherEntityNum;
- attacker = ent->otherEntityNum2;
- mod = ent->eventParm;
-
- if ( target < 0 || target >= MAX_CLIENTS ) {
- CG_Error( "CG_Obituary: target out of range" );
- }
- ci = &cgs.clientinfo[target];
-
- if ( attacker < 0 || attacker >= MAX_CLIENTS ) {
- attacker = ENTITYNUM_WORLD;
- attackerInfo = NULL;
- } else {
- attackerInfo = CG_ConfigString( CS_PLAYERS + attacker );
- }
-
- targetInfo = CG_ConfigString( CS_PLAYERS + target );
- if ( !targetInfo ) {
- return;
- }
- Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof(targetName) - 2);
- strcat( targetName, S_COLOR_WHITE );
-
- message2 = "";
-
- // check for single client messages
-
- switch( mod ) {
- case MOD_SUICIDE:
- message = "suicides";
- break;
- case MOD_FALLING:
- message = "cratered";
- break;
- case MOD_CRUSH:
- message = "was squished";
- break;
- case MOD_WATER:
- message = "sank like a rock";
- break;
- case MOD_SLIME:
- message = "melted";
- break;
- case MOD_LAVA:
- message = "does a back flip into the lava";
- break;
- case MOD_TARGET_LASER:
- message = "saw the light";
- break;
- case MOD_TRIGGER_HURT:
- message = "was in the wrong place";
- break;
- default:
- message = NULL;
- break;
- }
-
- if (attacker == target) {
- gender = ci->gender;
- switch (mod) {
-#ifdef MISSIONPACK
- case MOD_KAMIKAZE:
- message = "goes out with a bang";
- break;
-#endif
- case MOD_GRENADE_SPLASH:
- if ( gender == GENDER_FEMALE )
- message = "tripped on her own grenade";
- else if ( gender == GENDER_NEUTER )
- message = "tripped on its own grenade";
- else
- message = "tripped on his own grenade";
- break;
- case MOD_ROCKET_SPLASH:
- if ( gender == GENDER_FEMALE )
- message = "blew herself up";
- else if ( gender == GENDER_NEUTER )
- message = "blew itself up";
- else
- message = "blew himself up";
- break;
- case MOD_PLASMA_SPLASH:
- if ( gender == GENDER_FEMALE )
- message = "melted herself";
- else if ( gender == GENDER_NEUTER )
- message = "melted itself";
- else
- message = "melted himself";
- break;
- case MOD_BFG_SPLASH:
- message = "should have used a smaller gun";
- break;
-#ifdef MISSIONPACK
- case MOD_PROXIMITY_MINE:
- if( gender == GENDER_FEMALE ) {
- message = "found her prox mine";
- } else if ( gender == GENDER_NEUTER ) {
- message = "found it's prox mine";
- } else {
- message = "found his prox mine";
- }
- break;
-#endif
- default:
- if ( gender == GENDER_FEMALE )
- message = "killed herself";
- else if ( gender == GENDER_NEUTER )
- message = "killed itself";
- else
- message = "killed himself";
- break;
- }
- }
-
- if (message) {
- CG_Printf( "%s %s.\n", targetName, message);
- return;
- }
-
- // check for kill messages from the current clientNum
- if ( attacker == cg.snap->ps.clientNum ) {
- char *s;
-
- if ( cgs.gametype < GT_TEAM ) {
- s = va("You fragged %s\n%s place with %i", targetName,
- CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
- cg.snap->ps.persistant[PERS_SCORE] );
- } else {
- s = va("You fragged %s", targetName );
- }
-#ifdef MISSIONPACK
- if (!(cg_singlePlayerActive.integer && cg_cameraOrbit.integer)) {
- CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
- }
-#else
- CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
-#endif
-
- // print the text message as well
- }
-
- // check for double client messages
- if ( !attackerInfo ) {
- attacker = ENTITYNUM_WORLD;
- strcpy( attackerName, "noname" );
- } else {
- Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof(attackerName) - 2);
- strcat( attackerName, S_COLOR_WHITE );
- // check for kill messages about the current clientNum
- if ( target == cg.snap->ps.clientNum ) {
- Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) );
- }
- }
-
- if ( attacker != ENTITYNUM_WORLD ) {
- switch (mod) {
- case MOD_GRAPPLE:
- message = "was caught by";
- break;
- case MOD_GAUNTLET:
- message = "was pummeled by";
- break;
- case MOD_MACHINEGUN:
- message = "was machinegunned by";
- break;
- case MOD_SHOTGUN:
- message = "was gunned down by";
- break;
- case MOD_GRENADE:
- message = "ate";
- message2 = "'s grenade";
- break;
- case MOD_GRENADE_SPLASH:
- message = "was shredded by";
- message2 = "'s shrapnel";
- break;
- case MOD_ROCKET:
- message = "ate";
- message2 = "'s rocket";
- break;
- case MOD_ROCKET_SPLASH:
- message = "almost dodged";
- message2 = "'s rocket";
- break;
- case MOD_PLASMA:
- message = "was melted by";
- message2 = "'s plasmagun";
- break;
- case MOD_PLASMA_SPLASH:
- message = "was melted by";
- message2 = "'s plasmagun";
- break;
- case MOD_RAILGUN:
- message = "was railed by";
- break;
- case MOD_LIGHTNING:
- message = "was electrocuted by";
- break;
- case MOD_BFG:
- case MOD_BFG_SPLASH:
- message = "was blasted by";
- message2 = "'s BFG";
- break;
-#ifdef MISSIONPACK
- case MOD_NAIL:
- message = "was nailed by";
- break;
- case MOD_CHAINGUN:
- message = "got lead poisoning from";
- message2 = "'s Chaingun";
- break;
- case MOD_PROXIMITY_MINE:
- message = "was too close to";
- message2 = "'s Prox Mine";
- break;
- case MOD_KAMIKAZE:
- message = "falls to";
- message2 = "'s Kamikaze blast";
- break;
- case MOD_JUICED:
- message = "was juiced by";
- break;
-#endif
- case MOD_TELEFRAG:
- message = "tried to invade";
- message2 = "'s personal space";
- break;
- default:
- message = "was killed by";
- break;
- }
-
- if (message) {
- CG_Printf( "%s %s %s%s\n",
- targetName, message, attackerName, message2);
- return;
- }
- }
-
- // we don't know what it was
- CG_Printf( "%s died.\n", targetName );
-}
-
-//==========================================================================
-
-/*
-===============
-CG_UseItem
-===============
-*/
-static void CG_UseItem( centity_t *cent ) {
- clientInfo_t *ci;
- int itemNum, clientNum;
- gitem_t *item;
- entityState_t *es;
-
- es = ¢->currentState;
-
- itemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0;
- if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) {
- itemNum = 0;
- }
-
- // print a message if the local player
- if ( es->number == cg.snap->ps.clientNum ) {
- if ( !itemNum ) {
- CG_CenterPrint( "No item to use", SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
- } else {
- item = BG_FindItemForHoldable( itemNum );
- CG_CenterPrint( va("Use %s", item->pickup_name), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
- }
- }
-
- switch ( itemNum ) {
- default:
- case HI_NONE:
- trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound );
- break;
-
- case HI_TELEPORTER:
- break;
-
- case HI_MEDKIT:
- clientNum = cent->currentState.clientNum;
- if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
- ci = &cgs.clientinfo[ clientNum ];
- ci->medkitUsageTime = cg.time;
- }
- trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.medkitSound );
- break;
-
-#ifdef MISSIONPACK
- case HI_KAMIKAZE:
- break;
-
- case HI_PORTAL:
- break;
- case HI_INVULNERABILITY:
- trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useInvulnerabilitySound );
- break;
-#endif
- }
-
-}
-
-/*
-================
-CG_ItemPickup
-
-A new item was picked up this frame
-================
-*/
-static void CG_ItemPickup( int itemNum ) {
- cg.itemPickup = itemNum;
- cg.itemPickupTime = cg.time;
- cg.itemPickupBlendTime = cg.time;
- // see if it should be the grabbed weapon
- if ( bg_itemlist[itemNum].giType == IT_WEAPON ) {
- // select it immediately
- if ( cg_autoswitch.integer && bg_itemlist[itemNum].giTag != WP_MACHINEGUN ) {
- cg.weaponSelectTime = cg.time;
- cg.weaponSelect = bg_itemlist[itemNum].giTag;
- }
- }
-
-}
-
-
-/*
-================
-CG_PainEvent
-
-Also called by playerstate transition
-================
-*/
-void CG_PainEvent( centity_t *cent, int health ) {
- char *snd;
-
- // don't do more than two pain sounds a second
- if ( cg.time - cent->pe.painTime < 500 ) {
- return;
- }
-
- if ( health < 25 ) {
- snd = "*pain25_1.wav";
- } else if ( health < 50 ) {
- snd = "*pain50_1.wav";
- } else if ( health < 75 ) {
- snd = "*pain75_1.wav";
- } else {
- snd = "*pain100_1.wav";
- }
- trap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE,
- CG_CustomSound( cent->currentState.number, snd ) );
-
- // save pain time for programitic twitch animation
- cent->pe.painTime = cg.time;
- cent->pe.painDirection ^= 1;
-}
-
-
-
-/*
-==============
-CG_EntityEvent
-
-An entity has an event value
-also called by CG_CheckPlayerstateEvents
-==============
-*/
-#define DEBUGNAME(x) if(cg_debugEvents.integer){CG_Printf(x"\n");}
-void CG_EntityEvent( centity_t *cent, vec3_t position ) {
- entityState_t *es;
- int event;
- vec3_t dir;
- const char *s;
- int clientNum;
- clientInfo_t *ci;
-
- es = ¢->currentState;
- event = es->event & ~EV_EVENT_BITS;
-
- if ( cg_debugEvents.integer ) {
- CG_Printf( "ent:%3i event:%3i ", es->number, event );
- }
-
- if ( !event ) {
- DEBUGNAME("ZEROEVENT");
- return;
- }
-
- clientNum = es->clientNum;
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- clientNum = 0;
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- switch ( event ) {
- //
- // movement generated events
- //
- case EV_FOOTSTEP:
- DEBUGNAME("EV_FOOTSTEP");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ ci->footsteps ][rand()&3] );
- }
- break;
- case EV_FOOTSTEP_METAL:
- DEBUGNAME("EV_FOOTSTEP_METAL");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] );
- }
- break;
- case EV_FOOTSPLASH:
- DEBUGNAME("EV_FOOTSPLASH");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
- }
- break;
- case EV_FOOTWADE:
- DEBUGNAME("EV_FOOTWADE");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
- }
- break;
- case EV_SWIM:
- DEBUGNAME("EV_SWIM");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
- }
- break;
-
-
- case EV_FALL_SHORT:
- DEBUGNAME("EV_FALL_SHORT");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound );
- if ( clientNum == cg.predictedPlayerState.clientNum ) {
- // smooth landing z changes
- cg.landChange = -8;
- cg.landTime = cg.time;
- }
- break;
- case EV_FALL_MEDIUM:
- DEBUGNAME("EV_FALL_MEDIUM");
- // use normal pain sound
- trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) );
- if ( clientNum == cg.predictedPlayerState.clientNum ) {
- // smooth landing z changes
- cg.landChange = -16;
- cg.landTime = cg.time;
- }
- break;
- case EV_FALL_FAR:
- DEBUGNAME("EV_FALL_FAR");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) );
- cent->pe.painTime = cg.time; // don't play a pain sound right after this
- if ( clientNum == cg.predictedPlayerState.clientNum ) {
- // smooth landing z changes
- cg.landChange = -24;
- cg.landTime = cg.time;
- }
- break;
-
- case EV_STEP_4:
- case EV_STEP_8:
- case EV_STEP_12:
- case EV_STEP_16: // smooth out step up transitions
- DEBUGNAME("EV_STEP");
- {
- float oldStep;
- int delta;
- int step;
-
- if ( clientNum != cg.predictedPlayerState.clientNum ) {
- break;
- }
- // if we are interpolating, we don't need to smooth steps
- if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ||
- cg_nopredict.integer || cg_synchronousClients.integer ) {
- break;
- }
- // check for stepping up before a previous step is completed
- delta = cg.time - cg.stepTime;
- if (delta < STEP_TIME) {
- oldStep = cg.stepChange * (STEP_TIME - delta) / STEP_TIME;
- } else {
- oldStep = 0;
- }
-
- // add this amount
- step = 4 * (event - EV_STEP_4 + 1 );
- cg.stepChange = oldStep + step;
- if ( cg.stepChange > MAX_STEP_CHANGE ) {
- cg.stepChange = MAX_STEP_CHANGE;
- }
- cg.stepTime = cg.time;
- break;
- }
-
- case EV_JUMP_PAD:
- DEBUGNAME("EV_JUMP_PAD");
-// CG_Printf( "EV_JUMP_PAD w/effect #%i\n", es->eventParm );
- {
- localEntity_t *smoke;
- vec3_t up = {0, 0, 1};
-
-
- smoke = CG_SmokePuff( cent->lerpOrigin, up,
- 32,
- 1, 1, 1, 0.33f,
- 1000,
- cg.time, 0,
- LEF_PUFF_DONT_SCALE,
- cgs.media.smokePuffShader );
- }
-
- // boing sound at origin, jump sound on player
- trap_S_StartSound ( cent->lerpOrigin, -1, CHAN_VOICE, cgs.media.jumpPadSound );
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
- break;
-
- case EV_JUMP:
- DEBUGNAME("EV_JUMP");
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
- break;
- case EV_TAUNT:
- DEBUGNAME("EV_TAUNT");
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) );
- break;
-#ifdef MISSIONPACK
- case EV_TAUNT_YES:
- DEBUGNAME("EV_TAUNT_YES");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_YES);
- break;
- case EV_TAUNT_NO:
- DEBUGNAME("EV_TAUNT_NO");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_NO);
- break;
- case EV_TAUNT_FOLLOWME:
- DEBUGNAME("EV_TAUNT_FOLLOWME");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_FOLLOWME);
- break;
- case EV_TAUNT_GETFLAG:
- DEBUGNAME("EV_TAUNT_GETFLAG");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONGETFLAG);
- break;
- case EV_TAUNT_GUARDBASE:
- DEBUGNAME("EV_TAUNT_GUARDBASE");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONDEFENSE);
- break;
- case EV_TAUNT_PATROL:
- DEBUGNAME("EV_TAUNT_PATROL");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONPATROL);
- break;
-#endif
- case EV_WATER_TOUCH:
- DEBUGNAME("EV_WATER_TOUCH");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound );
- break;
- case EV_WATER_LEAVE:
- DEBUGNAME("EV_WATER_LEAVE");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );
- break;
- case EV_WATER_UNDER:
- DEBUGNAME("EV_WATER_UNDER");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound );
- break;
- case EV_WATER_CLEAR:
- DEBUGNAME("EV_WATER_CLEAR");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) );
- break;
-
- case EV_ITEM_PICKUP:
- DEBUGNAME("EV_ITEM_PICKUP");
- {
- gitem_t *item;
- int index;
-
- index = es->eventParm; // player predicted
-
- if ( index < 1 || index >= bg_numItems ) {
- break;
- }
- item = &bg_itemlist[ index ];
-
- // powerups and team items will have a separate global sound, this one
- // will be played at prediction time
- if ( item->giType == IT_POWERUP || item->giType == IT_TEAM) {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.n_healthSound );
- } else if (item->giType == IT_PERSISTANT_POWERUP) {
-#ifdef MISSIONPACK
- switch (item->giTag ) {
- case PW_SCOUT:
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.scoutSound );
- break;
- case PW_GUARD:
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.guardSound );
- break;
- case PW_DOUBLER:
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.doublerSound );
- break;
- case PW_AMMOREGEN:
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.ammoregenSound );
- break;
- }
-#endif
- } else {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );
- }
-
- // show icon and name on status bar
- if ( es->number == cg.snap->ps.clientNum ) {
- CG_ItemPickup( index );
- }
- }
- break;
-
- case EV_GLOBAL_ITEM_PICKUP:
- DEBUGNAME("EV_GLOBAL_ITEM_PICKUP");
- {
- gitem_t *item;
- int index;
-
- index = es->eventParm; // player predicted
-
- if ( index < 1 || index >= bg_numItems ) {
- break;
- }
- item = &bg_itemlist[ index ];
- // powerup pickups are global
- if( item->pickup_sound ) {
- trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );
- }
-
- // show icon and name on status bar
- if ( es->number == cg.snap->ps.clientNum ) {
- CG_ItemPickup( index );
- }
- }
- break;
-
- //
- // weapon events
- //
- case EV_NOAMMO:
- DEBUGNAME("EV_NOAMMO");
-// trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound );
- if ( es->number == cg.snap->ps.clientNum ) {
- CG_OutOfAmmoChange();
- }
- break;
- case EV_CHANGE_WEAPON:
- DEBUGNAME("EV_CHANGE_WEAPON");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
- break;
- case EV_FIRE_WEAPON:
- DEBUGNAME("EV_FIRE_WEAPON");
- CG_FireWeapon( cent );
- break;
-
- case EV_USE_ITEM0:
- DEBUGNAME("EV_USE_ITEM0");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM1:
- DEBUGNAME("EV_USE_ITEM1");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM2:
- DEBUGNAME("EV_USE_ITEM2");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM3:
- DEBUGNAME("EV_USE_ITEM3");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM4:
- DEBUGNAME("EV_USE_ITEM4");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM5:
- DEBUGNAME("EV_USE_ITEM5");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM6:
- DEBUGNAME("EV_USE_ITEM6");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM7:
- DEBUGNAME("EV_USE_ITEM7");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM8:
- DEBUGNAME("EV_USE_ITEM8");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM9:
- DEBUGNAME("EV_USE_ITEM9");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM10:
- DEBUGNAME("EV_USE_ITEM10");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM11:
- DEBUGNAME("EV_USE_ITEM11");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM12:
- DEBUGNAME("EV_USE_ITEM12");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM13:
- DEBUGNAME("EV_USE_ITEM13");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM14:
- DEBUGNAME("EV_USE_ITEM14");
- CG_UseItem( cent );
- break;
-
- //=================================================================
-
- //
- // other events
- //
- case EV_PLAYER_TELEPORT_IN:
- DEBUGNAME("EV_PLAYER_TELEPORT_IN");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleInSound );
- CG_SpawnEffect( position);
- break;
-
- case EV_PLAYER_TELEPORT_OUT:
- DEBUGNAME("EV_PLAYER_TELEPORT_OUT");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleOutSound );
- CG_SpawnEffect( position);
- break;
-
- case EV_ITEM_POP:
- DEBUGNAME("EV_ITEM_POP");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
- break;
- case EV_ITEM_RESPAWN:
- DEBUGNAME("EV_ITEM_RESPAWN");
- cent->miscTime = cg.time; // scale up from this
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
- break;
-
- case EV_GRENADE_BOUNCE:
- DEBUGNAME("EV_GRENADE_BOUNCE");
- if ( rand() & 1 ) {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb1aSound );
- } else {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb2aSound );
- }
- break;
-
-#ifdef MISSIONPACK
- case EV_PROXIMITY_MINE_STICK:
- DEBUGNAME("EV_PROXIMITY_MINE_STICK");
- if( es->eventParm & SURF_FLESH ) {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimplSound );
- } else if( es->eventParm & SURF_METALSTEPS ) {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpmSound );
- } else {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpdSound );
- }
- break;
-
- case EV_PROXIMITY_MINE_TRIGGER:
- DEBUGNAME("EV_PROXIMITY_MINE_TRIGGER");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbactvSound );
- break;
- case EV_KAMIKAZE:
- DEBUGNAME("EV_KAMIKAZE");
- CG_KamikazeEffect( cent->lerpOrigin );
- break;
- case EV_OBELISKEXPLODE:
- DEBUGNAME("EV_OBELISKEXPLODE");
- CG_ObeliskExplode( cent->lerpOrigin, es->eventParm );
- break;
- case EV_OBELISKPAIN:
- DEBUGNAME("EV_OBELISKPAIN");
- CG_ObeliskPain( cent->lerpOrigin );
- break;
- case EV_INVUL_IMPACT:
- DEBUGNAME("EV_INVUL_IMPACT");
- CG_InvulnerabilityImpact( cent->lerpOrigin, cent->currentState.angles );
- break;
- case EV_JUICED:
- DEBUGNAME("EV_JUICED");
- CG_InvulnerabilityJuiced( cent->lerpOrigin );
- break;
- case EV_LIGHTNINGBOLT:
- DEBUGNAME("EV_LIGHTNINGBOLT");
- CG_LightningBoltBeam(es->origin2, es->pos.trBase);
- break;
-#endif
- case EV_SCOREPLUM:
- DEBUGNAME("EV_SCOREPLUM");
- CG_ScorePlum( cent->currentState.otherEntityNum, cent->lerpOrigin, cent->currentState.time );
- break;
-
- //
- // missile impacts
- //
- case EV_MISSILE_HIT:
- DEBUGNAME("EV_MISSILE_HIT");
- ByteToDir( es->eventParm, dir );
- CG_MissileHitPlayer( es->weapon, position, dir, es->otherEntityNum );
- break;
-
- case EV_MISSILE_MISS:
- DEBUGNAME("EV_MISSILE_MISS");
- ByteToDir( es->eventParm, dir );
- CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_DEFAULT );
- break;
-
- case EV_MISSILE_MISS_METAL:
- DEBUGNAME("EV_MISSILE_MISS_METAL");
- ByteToDir( es->eventParm, dir );
- CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_METAL );
- break;
-
- case EV_RAILTRAIL:
- DEBUGNAME("EV_RAILTRAIL");
- cent->currentState.weapon = WP_RAILGUN;
-
- if(es->clientNum == cg.snap->ps.clientNum && !cg.renderingThirdPerson)
- {
- if(cg_drawGun.integer == 2)
- VectorMA(es->origin2, 8, cg.refdef.viewaxis[1], es->origin2);
- else if(cg_drawGun.integer == 3)
- VectorMA(es->origin2, 4, cg.refdef.viewaxis[1], es->origin2);
- }
-
- CG_RailTrail(ci, es->origin2, es->pos.trBase);
-
- // if the end was on a nomark surface, don't make an explosion
- if ( es->eventParm != 255 ) {
- ByteToDir( es->eventParm, dir );
- CG_MissileHitWall( es->weapon, es->clientNum, position, dir, IMPACTSOUND_DEFAULT );
- }
- break;
-
- case EV_BULLET_HIT_WALL:
- DEBUGNAME("EV_BULLET_HIT_WALL");
- ByteToDir( es->eventParm, dir );
- CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD );
- break;
-
- case EV_BULLET_HIT_FLESH:
- DEBUGNAME("EV_BULLET_HIT_FLESH");
- CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );
- break;
-
- case EV_SHOTGUN:
- DEBUGNAME("EV_SHOTGUN");
- CG_ShotgunFire( es );
- break;
-
- case EV_GENERAL_SOUND:
- DEBUGNAME("EV_GENERAL_SOUND");
- if ( cgs.gameSounds[ es->eventParm ] ) {
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] );
- } else {
- s = CG_ConfigString( CS_SOUNDS + es->eventParm );
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) );
- }
- break;
-
- case EV_GLOBAL_SOUND: // play from the player's head so it never diminishes
- DEBUGNAME("EV_GLOBAL_SOUND");
- if ( cgs.gameSounds[ es->eventParm ] ) {
- trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
- } else {
- s = CG_ConfigString( CS_SOUNDS + es->eventParm );
- trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
- }
- break;
-
- case EV_GLOBAL_TEAM_SOUND: // play from the player's head so it never diminishes
- {
- DEBUGNAME("EV_GLOBAL_TEAM_SOUND");
- switch( es->eventParm ) {
- case GTS_RED_CAPTURE: // CTF: red team captured the blue flag, 1FCTF: red team captured the neutral flag
- if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
- CG_AddBufferedSound( cgs.media.captureYourTeamSound );
- else
- CG_AddBufferedSound( cgs.media.captureOpponentSound );
- break;
- case GTS_BLUE_CAPTURE: // CTF: blue team captured the red flag, 1FCTF: blue team captured the neutral flag
- if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )
- CG_AddBufferedSound( cgs.media.captureYourTeamSound );
- else
- CG_AddBufferedSound( cgs.media.captureOpponentSound );
- break;
- case GTS_RED_RETURN: // CTF: blue flag returned, 1FCTF: never used
- if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
- CG_AddBufferedSound( cgs.media.returnYourTeamSound );
- else
- CG_AddBufferedSound( cgs.media.returnOpponentSound );
- //
- CG_AddBufferedSound( cgs.media.blueFlagReturnedSound );
- break;
- case GTS_BLUE_RETURN: // CTF red flag returned, 1FCTF: neutral flag returned
- if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )
- CG_AddBufferedSound( cgs.media.returnYourTeamSound );
- else
- CG_AddBufferedSound( cgs.media.returnOpponentSound );
- //
- CG_AddBufferedSound( cgs.media.redFlagReturnedSound );
- break;
-
- case GTS_RED_TAKEN: // CTF: red team took blue flag, 1FCTF: blue team took the neutral flag
- // if this player picked up the flag then a sound is played in CG_CheckLocalSounds
- if (cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
- }
- else {
- if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
-#ifdef MISSIONPACK
- if (cgs.gametype == GT_1FCTF)
- CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
- else
-#endif
- CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
- }
- else if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
-#ifdef MISSIONPACK
- if (cgs.gametype == GT_1FCTF)
- CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
- else
-#endif
- CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
- }
- }
- break;
- case GTS_BLUE_TAKEN: // CTF: blue team took the red flag, 1FCTF red team took the neutral flag
- // if this player picked up the flag then a sound is played in CG_CheckLocalSounds
- if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
- }
- else {
- if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
-#ifdef MISSIONPACK
- if (cgs.gametype == GT_1FCTF)
- CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
- else
-#endif
- CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
- }
- else if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
-#ifdef MISSIONPACK
- if (cgs.gametype == GT_1FCTF)
- CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
- else
-#endif
- CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
- }
- }
- break;
- case GTS_REDOBELISK_ATTACKED: // Overload: red obelisk is being attacked
- if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
- CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );
- }
- break;
- case GTS_BLUEOBELISK_ATTACKED: // Overload: blue obelisk is being attacked
- if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
- CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );
- }
- break;
-
- case GTS_REDTEAM_SCORED:
- CG_AddBufferedSound(cgs.media.redScoredSound);
- break;
- case GTS_BLUETEAM_SCORED:
- CG_AddBufferedSound(cgs.media.blueScoredSound);
- break;
- case GTS_REDTEAM_TOOK_LEAD:
- CG_AddBufferedSound(cgs.media.redLeadsSound);
- break;
- case GTS_BLUETEAM_TOOK_LEAD:
- CG_AddBufferedSound(cgs.media.blueLeadsSound);
- break;
- case GTS_TEAMS_ARE_TIED:
- CG_AddBufferedSound( cgs.media.teamsTiedSound );
- break;
-#ifdef MISSIONPACK
- case GTS_KAMIKAZE:
- trap_S_StartLocalSound(cgs.media.kamikazeFarSound, CHAN_ANNOUNCER);
- break;
-#endif
- default:
- break;
- }
- break;
- }
-
- case EV_PAIN:
- // local player sounds are triggered in CG_CheckLocalSounds,
- // so ignore events on the player
- DEBUGNAME("EV_PAIN");
- if ( cent->currentState.number != cg.snap->ps.clientNum ) {
- CG_PainEvent( cent, es->eventParm );
- }
- break;
-
- case EV_DEATH1:
- case EV_DEATH2:
- case EV_DEATH3:
- DEBUGNAME("EV_DEATHx");
- trap_S_StartSound( NULL, es->number, CHAN_VOICE,
- CG_CustomSound( es->number, va("*death%i.wav", event - EV_DEATH1 + 1) ) );
- break;
-
-
- case EV_OBITUARY:
- DEBUGNAME("EV_OBITUARY");
- CG_Obituary( es );
- break;
-
- //
- // powerup events
- //
- case EV_POWERUP_QUAD:
- DEBUGNAME("EV_POWERUP_QUAD");
- if ( es->number == cg.snap->ps.clientNum ) {
- cg.powerupActive = PW_QUAD;
- cg.powerupTime = cg.time;
- }
- trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.quadSound );
- break;
- case EV_POWERUP_BATTLESUIT:
- DEBUGNAME("EV_POWERUP_BATTLESUIT");
- if ( es->number == cg.snap->ps.clientNum ) {
- cg.powerupActive = PW_BATTLESUIT;
- cg.powerupTime = cg.time;
- }
- trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.protectSound );
- break;
- case EV_POWERUP_REGEN:
- DEBUGNAME("EV_POWERUP_REGEN");
- if ( es->number == cg.snap->ps.clientNum ) {
- cg.powerupActive = PW_REGEN;
- cg.powerupTime = cg.time;
- }
- trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.regenSound );
- break;
-
- case EV_GIB_PLAYER:
- DEBUGNAME("EV_GIB_PLAYER");
- // don't play gib sound when using the kamikaze because it interferes
- // with the kamikaze sound, downside is that the gib sound will also
- // not be played when someone is gibbed while just carrying the kamikaze
- if ( !(es->eFlags & EF_KAMIKAZE) ) {
- trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound );
- }
- CG_GibPlayer( cent->lerpOrigin );
- break;
-
- case EV_STOPLOOPINGSOUND:
- DEBUGNAME("EV_STOPLOOPINGSOUND");
- trap_S_StopLoopingSound( es->number );
- es->loopSound = 0;
- break;
-
- case EV_DEBUG_LINE:
- DEBUGNAME("EV_DEBUG_LINE");
- CG_Beam( cent );
- break;
-
- default:
- DEBUGNAME("UNKNOWN");
- CG_Error( "Unknown event: %i", event );
- break;
- }
-
-}
-
-
-/*
-==============
-CG_CheckEvents
-
-==============
-*/
-void CG_CheckEvents( centity_t *cent ) {
- // check for event-only entities
- if ( cent->currentState.eType > ET_EVENTS ) {
- if ( cent->previousEvent ) {
- return; // already fired
- }
- // if this is a player event set the entity number of the client entity number
- if ( cent->currentState.eFlags & EF_PLAYER_EVENT ) {
- cent->currentState.number = cent->currentState.otherEntityNum;
- }
-
- cent->previousEvent = 1;
-
- cent->currentState.event = cent->currentState.eType - ET_EVENTS;
- } else {
- // check for events riding with another entity
- if ( cent->currentState.event == cent->previousEvent ) {
- return;
- }
- cent->previousEvent = cent->currentState.event;
- if ( ( cent->currentState.event & ~EV_EVENT_BITS ) == 0 ) {
- return;
- }
- }
-
- // calculate the position at exactly the frame time
- BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, cent->lerpOrigin );
- CG_SetEntitySoundPosition( cent );
-
- CG_EntityEvent( cent, cent->lerpOrigin );
-}
-
diff --git a/engine/code/cgame/cg_info.c b/engine/code/cgame/cg_info.c
deleted file mode 100644
index fba60fb..0000000
--- a/engine/code/cgame/cg_info.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_info.c -- display information while data is being loading
-
-#include "cg_local.h"
-
-#define MAX_LOADING_PLAYER_ICONS 16
-#define MAX_LOADING_ITEM_ICONS 26
-
-static int loadingPlayerIconCount;
-static int loadingItemIconCount;
-static qhandle_t loadingPlayerIcons[MAX_LOADING_PLAYER_ICONS];
-static qhandle_t loadingItemIcons[MAX_LOADING_ITEM_ICONS];
-
-
-/*
-===================
-CG_DrawLoadingIcons
-===================
-*/
-static void CG_DrawLoadingIcons( void ) {
- int n;
- int x, y;
-
- for( n = 0; n < loadingPlayerIconCount; n++ ) {
- x = 16 + n * 78;
- y = 324-40;
- CG_DrawPic( x, y, 64, 64, loadingPlayerIcons[n] );
- }
-
- for( n = 0; n < loadingItemIconCount; n++ ) {
- y = 400-40;
- if( n >= 13 ) {
- y += 40;
- }
- x = 16 + n % 13 * 48;
- CG_DrawPic( x, y, 32, 32, loadingItemIcons[n] );
- }
-}
-
-
-/*
-======================
-CG_LoadingString
-
-======================
-*/
-void CG_LoadingString( const char *s ) {
- Q_strncpyz( cg.infoScreenText, s, sizeof( cg.infoScreenText ) );
-
- trap_UpdateScreen();
-}
-
-/*
-===================
-CG_LoadingItem
-===================
-*/
-void CG_LoadingItem( int itemNum ) {
- gitem_t *item;
-
- item = &bg_itemlist[itemNum];
-
- if ( item->icon && loadingItemIconCount < MAX_LOADING_ITEM_ICONS ) {
- loadingItemIcons[loadingItemIconCount++] = trap_R_RegisterShaderNoMip( item->icon );
- }
-
- CG_LoadingString( item->pickup_name );
-}
-
-/*
-===================
-CG_LoadingClient
-===================
-*/
-void CG_LoadingClient( int clientNum ) {
- const char *info;
- char *skin;
- char personality[MAX_QPATH];
- char model[MAX_QPATH];
- char iconName[MAX_QPATH];
-
- info = CG_ConfigString( CS_PLAYERS + clientNum );
-
- if ( loadingPlayerIconCount < MAX_LOADING_PLAYER_ICONS ) {
- Q_strncpyz( model, Info_ValueForKey( info, "model" ), sizeof( model ) );
- skin = Q_strrchr( model, '/' );
- if ( skin ) {
- *skin++ = '\0';
- } else {
- skin = "default";
- }
-
- Com_sprintf( iconName, MAX_QPATH, "models/players/%s/icon_%s.tga", model, skin );
-
- loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
- if ( !loadingPlayerIcons[loadingPlayerIconCount] ) {
- Com_sprintf( iconName, MAX_QPATH, "models/players/characters/%s/icon_%s.tga", model, skin );
- loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
- }
- if ( !loadingPlayerIcons[loadingPlayerIconCount] ) {
- Com_sprintf( iconName, MAX_QPATH, "models/players/%s/icon_%s.tga", DEFAULT_MODEL, "default" );
- loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
- }
- if ( loadingPlayerIcons[loadingPlayerIconCount] ) {
- loadingPlayerIconCount++;
- }
- }
-
- Q_strncpyz( personality, Info_ValueForKey( info, "n" ), sizeof(personality) );
- Q_CleanStr( personality );
-
- if( cgs.gametype == GT_SINGLE_PLAYER ) {
- trap_S_RegisterSound( va( "sound/player/announce/%s.wav", personality ), qtrue );
- }
-
- CG_LoadingString( personality );
-}
-
-
-/*
-====================
-CG_DrawInformation
-
-Draw all the status / pacifier stuff during level loading
-====================
-*/
-void CG_DrawInformation( void ) {
- const char *s;
- const char *info;
- const char *sysInfo;
- int y;
- int value;
- qhandle_t levelshot;
- qhandle_t detail;
- char buf[1024];
-
- info = CG_ConfigString( CS_SERVERINFO );
- sysInfo = CG_ConfigString( CS_SYSTEMINFO );
-
- s = Info_ValueForKey( info, "mapname" );
- levelshot = trap_R_RegisterShaderNoMip( va( "levelshots/%s.tga", s ) );
- if ( !levelshot ) {
- levelshot = trap_R_RegisterShaderNoMip( "menu/art/unknownmap" );
- }
- trap_R_SetColor( NULL );
- CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, levelshot );
-
- // blend a detail texture over it
- detail = trap_R_RegisterShader( "levelShotDetail" );
- trap_R_DrawStretchPic( 0, 0, cgs.glconfig.vidWidth, cgs.glconfig.vidHeight, 0, 0, 2.5, 2, detail );
-
- // draw the icons of things as they are loaded
- CG_DrawLoadingIcons();
-
- // the first 150 rows are reserved for the client connection
- // screen to write into
- if ( cg.infoScreenText[0] ) {
- UI_DrawProportionalString( 320, 128-32, va("Loading... %s", cg.infoScreenText),
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- } else {
- UI_DrawProportionalString( 320, 128-32, "Awaiting snapshot...",
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- }
-
- // draw info string information
-
- y = 180-32;
-
- // don't print server lines if playing a local game
- trap_Cvar_VariableStringBuffer( "sv_running", buf, sizeof( buf ) );
- if ( !atoi( buf ) ) {
- // server hostname
- Q_strncpyz(buf, Info_ValueForKey( info, "sv_hostname" ), 1024);
- Q_CleanStr(buf);
- UI_DrawProportionalString( 320, y, buf,
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
-
- // pure server
- s = Info_ValueForKey( sysInfo, "sv_pure" );
- if ( s[0] == '1' ) {
- UI_DrawProportionalString( 320, y, "Pure Server",
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- // server-specific message of the day
- s = CG_ConfigString( CS_MOTD );
- if ( s[0] ) {
- UI_DrawProportionalString( 320, y, s,
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- // some extra space after hostname and motd
- y += 10;
- }
-
- // map-specific message (long map name)
- s = CG_ConfigString( CS_MESSAGE );
- if ( s[0] ) {
- UI_DrawProportionalString( 320, y, s,
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- // cheats warning
- s = Info_ValueForKey( sysInfo, "sv_cheats" );
- if ( s[0] == '1' ) {
- UI_DrawProportionalString( 320, y, "CHEATS ARE ENABLED",
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- // game type
- switch ( cgs.gametype ) {
- case GT_FFA:
- s = "Free For All";
- break;
- case GT_SINGLE_PLAYER:
- s = "Single Player";
- break;
- case GT_TOURNAMENT:
- s = "Tournament";
- break;
- case GT_TEAM:
- s = "Team Deathmatch";
- break;
- case GT_CTF:
- s = "Capture The Flag";
- break;
-#ifdef MISSIONPACK
- case GT_1FCTF:
- s = "One Flag CTF";
- break;
- case GT_OBELISK:
- s = "Overload";
- break;
- case GT_HARVESTER:
- s = "Harvester";
- break;
-#endif
- default:
- s = "Unknown Gametype";
- break;
- }
- UI_DrawProportionalString( 320, y, s,
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
-
- value = atoi( Info_ValueForKey( info, "timelimit" ) );
- if ( value ) {
- UI_DrawProportionalString( 320, y, va( "timelimit %i", value ),
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- if (cgs.gametype < GT_CTF ) {
- value = atoi( Info_ValueForKey( info, "fraglimit" ) );
- if ( value ) {
- UI_DrawProportionalString( 320, y, va( "fraglimit %i", value ),
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
- }
-
- if (cgs.gametype >= GT_CTF) {
- value = atoi( Info_ValueForKey( info, "capturelimit" ) );
- if ( value ) {
- UI_DrawProportionalString( 320, y, va( "capturelimit %i", value ),
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
- }
-}
-
diff --git a/engine/code/cgame/cg_local.h b/engine/code/cgame/cg_local.h
deleted file mode 100644
index d000916..0000000
--- a/engine/code/cgame/cg_local.h
+++ /dev/null
@@ -1,1668 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "../qcommon/q_shared.h"
-#include "../renderer/tr_types.h"
-#include "../game/bg_public.h"
-#include "cg_public.h"
-
-
-// The entire cgame module is unloaded and reloaded on each level change,
-// so there is NO persistant data between levels on the client side.
-// If you absolutely need something stored, it can either be kept
-// by the server in the server stored userinfos, or stashed in a cvar.
-
-#ifdef MISSIONPACK
-#define CG_FONT_THRESHOLD 0.1
-#endif
-
-#define POWERUP_BLINKS 5
-
-#define POWERUP_BLINK_TIME 1000
-#define FADE_TIME 200
-#define PULSE_TIME 200
-#define DAMAGE_DEFLECT_TIME 100
-#define DAMAGE_RETURN_TIME 400
-#define DAMAGE_TIME 500
-#define LAND_DEFLECT_TIME 150
-#define LAND_RETURN_TIME 300
-#define STEP_TIME 200
-#define DUCK_TIME 100
-#define PAIN_TWITCH_TIME 200
-#define WEAPON_SELECT_TIME 1400
-#define ITEM_SCALEUP_TIME 1000
-#define ZOOM_TIME 150
-#define ITEM_BLOB_TIME 200
-#define MUZZLE_FLASH_TIME 20
-#define SINK_TIME 1000 // time for fragments to sink into ground before going away
-#define ATTACKER_HEAD_TIME 10000
-#define REWARD_TIME 3000
-
-#define PULSE_SCALE 1.5 // amount to scale up the icons when activating
-
-#define MAX_STEP_CHANGE 32
-
-#define MAX_VERTS_ON_POLY 10
-#define MAX_MARK_POLYS 256
-
-#define STAT_MINUS 10 // num frame for '-' stats digit
-
-#define ICON_SIZE 48
-#define CHAR_WIDTH 32
-#define CHAR_HEIGHT 48
-#define TEXT_ICON_SPACE 4
-
-#define TEAMCHAT_WIDTH 80
-#define TEAMCHAT_HEIGHT 8
-
-// very large characters
-#define GIANT_WIDTH 32
-#define GIANT_HEIGHT 48
-
-#define NUM_CROSSHAIRS 10
-
-#define TEAM_OVERLAY_MAXNAME_WIDTH 12
-#define TEAM_OVERLAY_MAXLOCATION_WIDTH 16
-
-#define DEFAULT_MODEL "sarge"
-#ifdef MISSIONPACK
-#define DEFAULT_TEAM_MODEL "james"
-#define DEFAULT_TEAM_HEAD "*james"
-#else
-#define DEFAULT_TEAM_MODEL "sarge"
-#define DEFAULT_TEAM_HEAD "sarge"
-#endif
-
-#define DEFAULT_REDTEAM_NAME "Stroggs"
-#define DEFAULT_BLUETEAM_NAME "Pagans"
-
-typedef enum {
- FOOTSTEP_NORMAL,
- FOOTSTEP_BOOT,
- FOOTSTEP_FLESH,
- FOOTSTEP_MECH,
- FOOTSTEP_ENERGY,
- FOOTSTEP_METAL,
- FOOTSTEP_SPLASH,
-
- FOOTSTEP_TOTAL
-} footstep_t;
-
-typedef enum {
- IMPACTSOUND_DEFAULT,
- IMPACTSOUND_METAL,
- IMPACTSOUND_FLESH
-} impactSound_t;
-
-//=================================================
-
-// player entities need to track more information
-// than any other type of entity.
-
-// note that not every player entity is a client entity,
-// because corpses after respawn are outside the normal
-// client numbering range
-
-// when changing animation, set animationTime to frameTime + lerping time
-// The current lerp will finish out, then it will lerp to the new animation
-typedef struct {
- int oldFrame;
- int oldFrameTime; // time when ->oldFrame was exactly on
-
- int frame;
- int frameTime; // time when ->frame will be exactly on
-
- float backlerp;
-
- float yawAngle;
- qboolean yawing;
- float pitchAngle;
- qboolean pitching;
-
- int animationNumber; // may include ANIM_TOGGLEBIT
- animation_t *animation;
- int animationTime; // time when the first frame of the animation will be exact
-} lerpFrame_t;
-
-
-typedef struct {
- lerpFrame_t legs, torso, flag;
- int painTime;
- int painDirection; // flip from 0 to 1
- int lightningFiring;
-
- // railgun trail spawning
- vec3_t railgunImpact;
- qboolean railgunFlash;
-
- // machinegun spinning
- float barrelAngle;
- int barrelTime;
- qboolean barrelSpinning;
-} playerEntity_t;
-
-//=================================================
-
-
-
-// centity_t have a direct corespondence with gentity_t in the game, but
-// only the entityState_t is directly communicated to the cgame
-typedef struct centity_s {
- entityState_t currentState; // from cg.frame
- entityState_t nextState; // from cg.nextFrame, if available
- qboolean interpolate; // true if next is valid to interpolate to
- qboolean currentValid; // true if cg.frame holds this entity
-
- int muzzleFlashTime; // move to playerEntity?
- int previousEvent;
- int teleportFlag;
-
- int trailTime; // so missile trails can handle dropped initial packets
- int dustTrailTime;
- int miscTime;
-
- int snapShotTime; // last time this entity was found in a snapshot
-
- playerEntity_t pe;
-
- int errorTime; // decay the error from this time
- vec3_t errorOrigin;
- vec3_t errorAngles;
-
- qboolean extrapolated; // false if origin / angles is an interpolation
- vec3_t rawOrigin;
- vec3_t rawAngles;
-
- vec3_t beamEnd;
-
- // exact interpolated position of entity on this frame
- vec3_t lerpOrigin;
- vec3_t lerpAngles;
-} centity_t;
-
-
-//======================================================================
-
-// local entities are created as a result of events or predicted actions,
-// and live independantly from all server transmitted entities
-
-typedef struct markPoly_s {
- struct markPoly_s *prevMark, *nextMark;
- int time;
- qhandle_t markShader;
- qboolean alphaFade; // fade alpha instead of rgb
- float color[4];
- poly_t poly;
- polyVert_t verts[MAX_VERTS_ON_POLY];
-} markPoly_t;
-
-
-typedef enum {
- LE_MARK,
- LE_EXPLOSION,
- LE_SPRITE_EXPLOSION,
- LE_FRAGMENT,
- LE_MOVE_SCALE_FADE,
- LE_FALL_SCALE_FADE,
- LE_FADE_RGB,
- LE_SCALE_FADE,
- LE_SCOREPLUM,
-#ifdef MISSIONPACK
- LE_KAMIKAZE,
- LE_INVULIMPACT,
- LE_INVULJUICED,
- LE_SHOWREFENTITY
-#endif
-} leType_t;
-
-typedef enum {
- LEF_PUFF_DONT_SCALE = 0x0001, // do not scale size over time
- LEF_TUMBLE = 0x0002, // tumble over time, used for ejecting shells
- LEF_SOUND1 = 0x0004, // sound 1 for kamikaze
- LEF_SOUND2 = 0x0008 // sound 2 for kamikaze
-} leFlag_t;
-
-typedef enum {
- LEMT_NONE,
- LEMT_BURN,
- LEMT_BLOOD
-} leMarkType_t; // fragment local entities can leave marks on walls
-
-typedef enum {
- LEBS_NONE,
- LEBS_BLOOD,
- LEBS_BRASS
-} leBounceSoundType_t; // fragment local entities can make sounds on impacts
-
-typedef struct localEntity_s {
- struct localEntity_s *prev, *next;
- leType_t leType;
- int leFlags;
-
- int startTime;
- int endTime;
- int fadeInTime;
-
- float lifeRate; // 1.0 / (endTime - startTime)
-
- trajectory_t pos;
- trajectory_t angles;
-
- float bounceFactor; // 0.0 = no bounce, 1.0 = perfect
-
- float color[4];
-
- float radius;
-
- float light;
- vec3_t lightColor;
-
- leMarkType_t leMarkType; // mark to leave on fragment impact
- leBounceSoundType_t leBounceSoundType;
-
- refEntity_t refEntity;
-} localEntity_t;
-
-//======================================================================
-
-
-typedef struct {
- int client;
- int score;
- int ping;
- int time;
- int scoreFlags;
- int powerUps;
- int accuracy;
- int impressiveCount;
- int excellentCount;
- int guantletCount;
- int defendCount;
- int assistCount;
- int captures;
- qboolean perfect;
- int team;
-} score_t;
-
-// each client has an associated clientInfo_t
-// that contains media references necessary to present the
-// client model and other color coded effects
-// this is regenerated each time a client's configstring changes,
-// usually as a result of a userinfo (name, model, etc) change
-#define MAX_CUSTOM_SOUNDS 32
-
-typedef struct {
- qboolean infoValid;
-
- char name[MAX_QPATH];
- team_t team;
-
- int botSkill; // 0 = not bot, 1-5 = bot
-
- vec3_t color1;
- vec3_t color2;
-
- int score; // updated by score servercmds
- int location; // location index for team mode
- int health; // you only get this info about your teammates
- int armor;
- int curWeapon;
-
- int handicap;
- int wins, losses; // in tourney mode
-
- int teamTask; // task in teamplay (offence/defence)
- qboolean teamLeader; // true when this is a team leader
-
- int powerups; // so can display quad/flag status
-
- int medkitUsageTime;
- int invulnerabilityStartTime;
- int invulnerabilityStopTime;
-
- int breathPuffTime;
-
- // when clientinfo is changed, the loading of models/skins/sounds
- // can be deferred until you are dead, to prevent hitches in
- // gameplay
- char modelName[MAX_QPATH];
- char skinName[MAX_QPATH];
- char headModelName[MAX_QPATH];
- char headSkinName[MAX_QPATH];
- char redTeam[MAX_TEAMNAME];
- char blueTeam[MAX_TEAMNAME];
- qboolean deferred;
-
- qboolean newAnims; // true if using the new mission pack animations
- qboolean fixedlegs; // true if legs yaw is always the same as torso yaw
- qboolean fixedtorso; // true if torso never changes yaw
-
- vec3_t headOffset; // move head in icon views
- footstep_t footsteps;
- gender_t gender; // from model
-
- qhandle_t legsModel;
- qhandle_t legsSkin;
-
- qhandle_t torsoModel;
- qhandle_t torsoSkin;
-
- qhandle_t headModel;
- qhandle_t headSkin;
-
- qhandle_t modelIcon;
-
- animation_t animations[MAX_TOTALANIMATIONS];
-
- sfxHandle_t sounds[MAX_CUSTOM_SOUNDS];
-} clientInfo_t;
-
-
-// each WP_* weapon enum has an associated weaponInfo_t
-// that contains media references necessary to present the
-// weapon and its effects
-typedef struct weaponInfo_s {
- qboolean registered;
- gitem_t *item;
-
- qhandle_t handsModel; // the hands don't actually draw, they just position the weapon
- qhandle_t weaponModel;
- qhandle_t barrelModel;
- qhandle_t flashModel;
-
- vec3_t weaponMidpoint; // so it will rotate centered instead of by tag
-
- float flashDlight;
- vec3_t flashDlightColor;
- sfxHandle_t flashSound[4]; // fast firing weapons randomly choose
-
- qhandle_t weaponIcon;
- qhandle_t ammoIcon;
-
- qhandle_t ammoModel;
-
- qhandle_t missileModel;
- sfxHandle_t missileSound;
- void (*missileTrailFunc)( centity_t *, const struct weaponInfo_s *wi );
- float missileDlight;
- vec3_t missileDlightColor;
- int missileRenderfx;
-
- void (*ejectBrassFunc)( centity_t * );
-
- float trailRadius;
- float wiTrailTime;
-
- sfxHandle_t readySound;
- sfxHandle_t firingSound;
- qboolean loopFireSound;
-} weaponInfo_t;
-
-
-// each IT_* item has an associated itemInfo_t
-// that constains media references necessary to present the
-// item and its effects
-typedef struct {
- qboolean registered;
- qhandle_t models[MAX_ITEM_MODELS];
- qhandle_t icon;
-} itemInfo_t;
-
-
-typedef struct {
- int itemNum;
-} powerupInfo_t;
-
-
-#define MAX_SKULLTRAIL 10
-
-typedef struct {
- vec3_t positions[MAX_SKULLTRAIL];
- int numpositions;
-} skulltrail_t;
-
-
-#define MAX_REWARDSTACK 10
-#define MAX_SOUNDBUFFER 20
-
-//======================================================================
-
-// all cg.stepTime, cg.duckTime, cg.landTime, etc are set to cg.time when the action
-// occurs, and they will have visible effects for #define STEP_TIME or whatever msec after
-
-#define MAX_PREDICTED_EVENTS 16
-
-typedef struct {
- int clientFrame; // incremented each frame
-
- int clientNum;
-
- qboolean demoPlayback;
- qboolean levelShot; // taking a level menu screenshot
- int deferredPlayerLoading;
- qboolean loading; // don't defer players at initial startup
- qboolean intermissionStarted; // don't play voice rewards, because game will end shortly
-
- // there are only one or two snapshot_t that are relevent at a time
- int latestSnapshotNum; // the number of snapshots the client system has received
- int latestSnapshotTime; // the time from latestSnapshotNum, so we don't need to read the snapshot yet
-
- snapshot_t *snap; // cg.snap->serverTime <= cg.time
- snapshot_t *nextSnap; // cg.nextSnap->serverTime > cg.time, or NULL
- snapshot_t activeSnapshots[2];
-
- float frameInterpolation; // (float)( cg.time - cg.frame->serverTime ) / (cg.nextFrame->serverTime - cg.frame->serverTime)
-
- qboolean thisFrameTeleport;
- qboolean nextFrameTeleport;
-
- int frametime; // cg.time - cg.oldTime
-
- int time; // this is the time value that the client
- // is rendering at.
- int oldTime; // time at last frame, used for missile trails and prediction checking
-
- int physicsTime; // either cg.snap->time or cg.nextSnap->time
-
- int timelimitWarnings; // 5 min, 1 min, overtime
- int fraglimitWarnings;
-
- qboolean mapRestart; // set on a map restart to set back the weapon
-
- qboolean renderingThirdPerson; // during deaths, chasecams, etc
-
- // prediction state
- qboolean hyperspace; // true if prediction has hit a trigger_teleport
- playerState_t predictedPlayerState;
- centity_t predictedPlayerEntity;
- qboolean validPPS; // clear until the first call to CG_PredictPlayerState
- int predictedErrorTime;
- vec3_t predictedError;
-
- int eventSequence;
- int predictableEvents[MAX_PREDICTED_EVENTS];
-
- float stepChange; // for stair up smoothing
- int stepTime;
-
- float duckChange; // for duck viewheight smoothing
- int duckTime;
-
- float landChange; // for landing hard
- int landTime;
-
- // input state sent to server
- int weaponSelect;
-
- // auto rotating items
- vec3_t autoAngles;
- vec3_t autoAxis[3];
- vec3_t autoAnglesFast;
- vec3_t autoAxisFast[3];
-
- // view rendering
- refdef_t refdef;
- vec3_t refdefViewAngles; // will be converted to refdef.viewaxis
-
- // zoom key
- qboolean zoomed;
- int zoomTime;
- float zoomSensitivity;
-
- // information screen text during loading
- char infoScreenText[MAX_STRING_CHARS];
-
- // scoreboard
- int scoresRequestTime;
- int numScores;
- int selectedScore;
- int teamScores[2];
- score_t scores[MAX_CLIENTS];
- qboolean showScores;
- qboolean scoreBoardShowing;
- int scoreFadeTime;
- char killerName[MAX_NAME_LENGTH];
- char spectatorList[MAX_STRING_CHARS]; // list of names
- int spectatorLen; // length of list
- float spectatorWidth; // width in device units
- int spectatorTime; // next time to offset
- int spectatorPaintX; // current paint x
- int spectatorPaintX2; // current paint x
- int spectatorOffset; // current offset from start
- int spectatorPaintLen; // current offset from start
-
- // skull trails
- skulltrail_t skulltrails[MAX_CLIENTS];
-
- // centerprinting
- int centerPrintTime;
- int centerPrintCharWidth;
- int centerPrintY;
- char centerPrint[1024];
- int centerPrintLines;
-
- // low ammo warning state
- int lowAmmoWarning; // 1 = low, 2 = empty
-
- // kill timers for carnage reward
- int lastKillTime;
-
- // crosshair client ID
- int crosshairClientNum;
- int crosshairClientTime;
-
- // powerup active flashing
- int powerupActive;
- int powerupTime;
-
- // attacking player
- int attackerTime;
- int voiceTime;
-
- // reward medals
- int rewardStack;
- int rewardTime;
- int rewardCount[MAX_REWARDSTACK];
- qhandle_t rewardShader[MAX_REWARDSTACK];
- qhandle_t rewardSound[MAX_REWARDSTACK];
-
- // sound buffer mainly for announcer sounds
- int soundBufferIn;
- int soundBufferOut;
- int soundTime;
- qhandle_t soundBuffer[MAX_SOUNDBUFFER];
-
- // for voice chat buffer
- int voiceChatTime;
- int voiceChatBufferIn;
- int voiceChatBufferOut;
-
- // warmup countdown
- int warmup;
- int warmupCount;
-
- //==========================
-
- int itemPickup;
- int itemPickupTime;
- int itemPickupBlendTime; // the pulse around the crosshair is timed seperately
-
- int weaponSelectTime;
- int weaponAnimation;
- int weaponAnimationTime;
-
- // blend blobs
- float damageTime;
- float damageX, damageY, damageValue;
-
- // status bar head
- float headYaw;
- float headEndPitch;
- float headEndYaw;
- int headEndTime;
- float headStartPitch;
- float headStartYaw;
- int headStartTime;
-
- // view movement
- float v_dmg_time;
- float v_dmg_pitch;
- float v_dmg_roll;
-
- vec3_t kick_angles; // weapon kicks
- vec3_t kick_origin;
-
- // temp working variables for player view
- float bobfracsin;
- int bobcycle;
- float xyspeed;
- int nextOrbitTime;
-
- //qboolean cameraMode; // if rendering from a loaded camera
-
-
- // development tool
- refEntity_t testModelEntity;
- char testModelName[MAX_QPATH];
- qboolean testGun;
-
-} cg_t;
-
-
-// all of the model, shader, and sound references that are
-// loaded at gamestate time are stored in cgMedia_t
-// Other media that can be tied to clients, weapons, or items are
-// stored in the clientInfo_t, itemInfo_t, weaponInfo_t, and powerupInfo_t
-typedef struct {
- qhandle_t charsetShader;
- qhandle_t charsetProp;
- qhandle_t charsetPropGlow;
- qhandle_t charsetPropB;
- qhandle_t whiteShader;
-
- qhandle_t redCubeModel;
- qhandle_t blueCubeModel;
- qhandle_t redCubeIcon;
- qhandle_t blueCubeIcon;
- qhandle_t redFlagModel;
- qhandle_t blueFlagModel;
- qhandle_t neutralFlagModel;
- qhandle_t redFlagShader[3];
- qhandle_t blueFlagShader[3];
- qhandle_t flagShader[4];
-
- qhandle_t flagPoleModel;
- qhandle_t flagFlapModel;
-
- qhandle_t redFlagFlapSkin;
- qhandle_t blueFlagFlapSkin;
- qhandle_t neutralFlagFlapSkin;
-
- qhandle_t redFlagBaseModel;
- qhandle_t blueFlagBaseModel;
- qhandle_t neutralFlagBaseModel;
-
-#ifdef MISSIONPACK
- qhandle_t overloadBaseModel;
- qhandle_t overloadTargetModel;
- qhandle_t overloadLightsModel;
- qhandle_t overloadEnergyModel;
-
- qhandle_t harvesterModel;
- qhandle_t harvesterRedSkin;
- qhandle_t harvesterBlueSkin;
- qhandle_t harvesterNeutralModel;
-#endif
-
- qhandle_t armorModel;
- qhandle_t armorIcon;
-
- qhandle_t teamStatusBar;
-
- qhandle_t deferShader;
-
- // gib explosions
- qhandle_t gibAbdomen;
- qhandle_t gibArm;
- qhandle_t gibChest;
- qhandle_t gibFist;
- qhandle_t gibFoot;
- qhandle_t gibForearm;
- qhandle_t gibIntestine;
- qhandle_t gibLeg;
- qhandle_t gibSkull;
- qhandle_t gibBrain;
-
- qhandle_t smoke2;
-
- qhandle_t machinegunBrassModel;
- qhandle_t shotgunBrassModel;
-
- qhandle_t railRingsShader;
- qhandle_t railCoreShader;
-
- qhandle_t lightningShader;
-
- qhandle_t friendShader;
-
- qhandle_t balloonShader;
- qhandle_t connectionShader;
-
- qhandle_t selectShader;
- qhandle_t viewBloodShader;
- qhandle_t tracerShader;
- qhandle_t crosshairShader[NUM_CROSSHAIRS];
- qhandle_t lagometerShader;
- qhandle_t backTileShader;
- qhandle_t noammoShader;
-
- qhandle_t smokePuffShader;
- qhandle_t smokePuffRageProShader;
- qhandle_t shotgunSmokePuffShader;
- qhandle_t plasmaBallShader;
- qhandle_t waterBubbleShader;
- qhandle_t bloodTrailShader;
-#ifdef MISSIONPACK
- qhandle_t nailPuffShader;
- qhandle_t blueProxMine;
-#endif
-
- qhandle_t numberShaders[11];
-
- qhandle_t shadowMarkShader;
-
- qhandle_t botSkillShaders[5];
-
- // wall mark shaders
- qhandle_t wakeMarkShader;
- qhandle_t bloodMarkShader;
- qhandle_t bulletMarkShader;
- qhandle_t burnMarkShader;
- qhandle_t holeMarkShader;
- qhandle_t energyMarkShader;
-
- // powerup shaders
- qhandle_t quadShader;
- qhandle_t redQuadShader;
- qhandle_t quadWeaponShader;
- qhandle_t invisShader;
- qhandle_t regenShader;
- qhandle_t battleSuitShader;
- qhandle_t battleWeaponShader;
- qhandle_t hastePuffShader;
- qhandle_t redKamikazeShader;
- qhandle_t blueKamikazeShader;
-
- // weapon effect models
- qhandle_t bulletFlashModel;
- qhandle_t ringFlashModel;
- qhandle_t dishFlashModel;
- qhandle_t lightningExplosionModel;
-
- // weapon effect shaders
- qhandle_t railExplosionShader;
- qhandle_t plasmaExplosionShader;
- qhandle_t bulletExplosionShader;
- qhandle_t rocketExplosionShader;
- qhandle_t grenadeExplosionShader;
- qhandle_t bfgExplosionShader;
- qhandle_t bloodExplosionShader;
-
- // special effects models
- qhandle_t teleportEffectModel;
- qhandle_t teleportEffectShader;
-#ifdef MISSIONPACK
- qhandle_t kamikazeEffectModel;
- qhandle_t kamikazeShockWave;
- qhandle_t kamikazeHeadModel;
- qhandle_t kamikazeHeadTrail;
- qhandle_t guardPowerupModel;
- qhandle_t scoutPowerupModel;
- qhandle_t doublerPowerupModel;
- qhandle_t ammoRegenPowerupModel;
- qhandle_t invulnerabilityImpactModel;
- qhandle_t invulnerabilityJuicedModel;
- qhandle_t medkitUsageModel;
- qhandle_t dustPuffShader;
- qhandle_t heartShader;
-#endif
- qhandle_t invulnerabilityPowerupModel;
-
- // scoreboard headers
- qhandle_t scoreboardName;
- qhandle_t scoreboardPing;
- qhandle_t scoreboardScore;
- qhandle_t scoreboardTime;
-
- // medals shown during gameplay
- qhandle_t medalImpressive;
- qhandle_t medalExcellent;
- qhandle_t medalGauntlet;
- qhandle_t medalDefend;
- qhandle_t medalAssist;
- qhandle_t medalCapture;
-
- // sounds
- sfxHandle_t quadSound;
- sfxHandle_t tracerSound;
- sfxHandle_t selectSound;
- sfxHandle_t useNothingSound;
- sfxHandle_t wearOffSound;
- sfxHandle_t footsteps[FOOTSTEP_TOTAL][4];
- sfxHandle_t sfx_lghit1;
- sfxHandle_t sfx_lghit2;
- sfxHandle_t sfx_lghit3;
- sfxHandle_t sfx_ric1;
- sfxHandle_t sfx_ric2;
- sfxHandle_t sfx_ric3;
- sfxHandle_t sfx_railg;
- sfxHandle_t sfx_rockexp;
- sfxHandle_t sfx_plasmaexp;
-#ifdef MISSIONPACK
- sfxHandle_t sfx_proxexp;
- sfxHandle_t sfx_nghit;
- sfxHandle_t sfx_nghitflesh;
- sfxHandle_t sfx_nghitmetal;
- sfxHandle_t sfx_chghit;
- sfxHandle_t sfx_chghitflesh;
- sfxHandle_t sfx_chghitmetal;
- sfxHandle_t kamikazeExplodeSound;
- sfxHandle_t kamikazeImplodeSound;
- sfxHandle_t kamikazeFarSound;
- sfxHandle_t useInvulnerabilitySound;
- sfxHandle_t invulnerabilityImpactSound1;
- sfxHandle_t invulnerabilityImpactSound2;
- sfxHandle_t invulnerabilityImpactSound3;
- sfxHandle_t invulnerabilityJuicedSound;
- sfxHandle_t obeliskHitSound1;
- sfxHandle_t obeliskHitSound2;
- sfxHandle_t obeliskHitSound3;
- sfxHandle_t obeliskRespawnSound;
- sfxHandle_t winnerSound;
- sfxHandle_t loserSound;
- sfxHandle_t youSuckSound;
-#endif
- sfxHandle_t gibSound;
- sfxHandle_t gibBounce1Sound;
- sfxHandle_t gibBounce2Sound;
- sfxHandle_t gibBounce3Sound;
- sfxHandle_t teleInSound;
- sfxHandle_t teleOutSound;
- sfxHandle_t noAmmoSound;
- sfxHandle_t respawnSound;
- sfxHandle_t talkSound;
- sfxHandle_t landSound;
- sfxHandle_t fallSound;
- sfxHandle_t jumpPadSound;
-
- sfxHandle_t oneMinuteSound;
- sfxHandle_t fiveMinuteSound;
- sfxHandle_t suddenDeathSound;
-
- sfxHandle_t threeFragSound;
- sfxHandle_t twoFragSound;
- sfxHandle_t oneFragSound;
-
- sfxHandle_t hitSound;
- sfxHandle_t hitSoundHighArmor;
- sfxHandle_t hitSoundLowArmor;
- sfxHandle_t hitTeamSound;
- sfxHandle_t impressiveSound;
- sfxHandle_t excellentSound;
- sfxHandle_t deniedSound;
- sfxHandle_t humiliationSound;
- sfxHandle_t assistSound;
- sfxHandle_t defendSound;
- sfxHandle_t firstImpressiveSound;
- sfxHandle_t firstExcellentSound;
- sfxHandle_t firstHumiliationSound;
-
- sfxHandle_t takenLeadSound;
- sfxHandle_t tiedLeadSound;
- sfxHandle_t lostLeadSound;
-
- sfxHandle_t voteNow;
- sfxHandle_t votePassed;
- sfxHandle_t voteFailed;
-
- sfxHandle_t watrInSound;
- sfxHandle_t watrOutSound;
- sfxHandle_t watrUnSound;
-
- sfxHandle_t flightSound;
- sfxHandle_t medkitSound;
-
- sfxHandle_t weaponHoverSound;
-
- // teamplay sounds
- sfxHandle_t captureAwardSound;
- sfxHandle_t redScoredSound;
- sfxHandle_t blueScoredSound;
- sfxHandle_t redLeadsSound;
- sfxHandle_t blueLeadsSound;
- sfxHandle_t teamsTiedSound;
-
- sfxHandle_t captureYourTeamSound;
- sfxHandle_t captureOpponentSound;
- sfxHandle_t returnYourTeamSound;
- sfxHandle_t returnOpponentSound;
- sfxHandle_t takenYourTeamSound;
- sfxHandle_t takenOpponentSound;
-
- sfxHandle_t redFlagReturnedSound;
- sfxHandle_t blueFlagReturnedSound;
- sfxHandle_t neutralFlagReturnedSound;
- sfxHandle_t enemyTookYourFlagSound;
- sfxHandle_t enemyTookTheFlagSound;
- sfxHandle_t yourTeamTookEnemyFlagSound;
- sfxHandle_t yourTeamTookTheFlagSound;
- sfxHandle_t youHaveFlagSound;
- sfxHandle_t yourBaseIsUnderAttackSound;
- sfxHandle_t holyShitSound;
-
- // tournament sounds
- sfxHandle_t count3Sound;
- sfxHandle_t count2Sound;
- sfxHandle_t count1Sound;
- sfxHandle_t countFightSound;
- sfxHandle_t countPrepareSound;
-
-#ifdef MISSIONPACK
- // new stuff
- qhandle_t patrolShader;
- qhandle_t assaultShader;
- qhandle_t campShader;
- qhandle_t followShader;
- qhandle_t defendShader;
- qhandle_t teamLeaderShader;
- qhandle_t retrieveShader;
- qhandle_t escortShader;
- qhandle_t flagShaders[3];
- sfxHandle_t countPrepareTeamSound;
-
- sfxHandle_t ammoregenSound;
- sfxHandle_t doublerSound;
- sfxHandle_t guardSound;
- sfxHandle_t scoutSound;
-#endif
- qhandle_t cursor;
- qhandle_t selectCursor;
- qhandle_t sizeCursor;
-
- sfxHandle_t regenSound;
- sfxHandle_t protectSound;
- sfxHandle_t n_healthSound;
- sfxHandle_t hgrenb1aSound;
- sfxHandle_t hgrenb2aSound;
- sfxHandle_t wstbimplSound;
- sfxHandle_t wstbimpmSound;
- sfxHandle_t wstbimpdSound;
- sfxHandle_t wstbactvSound;
-
-} cgMedia_t;
-
-
-// The client game static (cgs) structure hold everything
-// loaded or calculated from the gamestate. It will NOT
-// be cleared when a tournement restart is done, allowing
-// all clients to begin playing instantly
-typedef struct {
- gameState_t gameState; // gamestate from server
- glconfig_t glconfig; // rendering configuration
- float screenXScale; // derived from glconfig
- float screenYScale;
- float screenXBias;
-
- int serverCommandSequence; // reliable command stream counter
- int processedSnapshotNum;// the number of snapshots cgame has requested
-
- qboolean localServer; // detected on startup by checking sv_running
-
- // parsed from serverinfo
- gametype_t gametype;
- int dmflags;
- int teamflags;
- int fraglimit;
- int capturelimit;
- int timelimit;
- int maxclients;
- char mapname[MAX_QPATH];
- char redTeam[MAX_QPATH];
- char blueTeam[MAX_QPATH];
-
- int voteTime;
- int voteYes;
- int voteNo;
- qboolean voteModified; // beep whenever changed
- char voteString[MAX_STRING_TOKENS];
-
- int teamVoteTime[2];
- int teamVoteYes[2];
- int teamVoteNo[2];
- qboolean teamVoteModified[2]; // beep whenever changed
- char teamVoteString[2][MAX_STRING_TOKENS];
-
- int levelStartTime;
-
- int scores1, scores2; // from configstrings
- int redflag, blueflag; // flag status from configstrings
- int flagStatus;
-
- qboolean newHud;
-
- //
- // locally derived information from gamestate
- //
- qhandle_t gameModels[MAX_MODELS];
- sfxHandle_t gameSounds[MAX_SOUNDS];
-
- int numInlineModels;
- qhandle_t inlineDrawModel[MAX_MODELS];
- vec3_t inlineModelMidpoints[MAX_MODELS];
-
- clientInfo_t clientinfo[MAX_CLIENTS];
-
- // teamchat width is *3 because of embedded color codes
- char teamChatMsgs[TEAMCHAT_HEIGHT][TEAMCHAT_WIDTH*3+1];
- int teamChatMsgTimes[TEAMCHAT_HEIGHT];
- int teamChatPos;
- int teamLastChatPos;
-
- int cursorX;
- int cursorY;
- qboolean eventHandling;
- qboolean mouseCaptured;
- qboolean sizingHud;
- void *capturedItem;
- qhandle_t activeCursor;
-
- // orders
- int currentOrder;
- qboolean orderPending;
- int orderTime;
- int currentVoiceClient;
- int acceptOrderTime;
- int acceptTask;
- int acceptLeader;
- char acceptVoice[MAX_NAME_LENGTH];
-
- // media
- cgMedia_t media;
-
-} cgs_t;
-
-//==============================================================================
-
-extern cgs_t cgs;
-extern cg_t cg;
-extern centity_t cg_entities[MAX_GENTITIES];
-extern weaponInfo_t cg_weapons[MAX_WEAPONS];
-extern itemInfo_t cg_items[MAX_ITEMS];
-extern markPoly_t cg_markPolys[MAX_MARK_POLYS];
-
-extern vmCvar_t cg_centertime;
-extern vmCvar_t cg_runpitch;
-extern vmCvar_t cg_runroll;
-extern vmCvar_t cg_bobup;
-extern vmCvar_t cg_bobpitch;
-extern vmCvar_t cg_bobroll;
-extern vmCvar_t cg_swingSpeed;
-extern vmCvar_t cg_shadows;
-extern vmCvar_t cg_gibs;
-extern vmCvar_t cg_drawTimer;
-extern vmCvar_t cg_drawFPS;
-extern vmCvar_t cg_drawSnapshot;
-extern vmCvar_t cg_draw3dIcons;
-extern vmCvar_t cg_drawIcons;
-extern vmCvar_t cg_drawAmmoWarning;
-extern vmCvar_t cg_drawCrosshair;
-extern vmCvar_t cg_drawCrosshairNames;
-extern vmCvar_t cg_drawRewards;
-extern vmCvar_t cg_drawTeamOverlay;
-extern vmCvar_t cg_teamOverlayUserinfo;
-extern vmCvar_t cg_crosshairX;
-extern vmCvar_t cg_crosshairY;
-extern vmCvar_t cg_crosshairSize;
-extern vmCvar_t cg_crosshairHealth;
-extern vmCvar_t cg_drawStatus;
-extern vmCvar_t cg_draw2D;
-extern vmCvar_t cg_animSpeed;
-extern vmCvar_t cg_debugAnim;
-extern vmCvar_t cg_debugPosition;
-extern vmCvar_t cg_debugEvents;
-extern vmCvar_t cg_railTrailTime;
-extern vmCvar_t cg_errorDecay;
-extern vmCvar_t cg_nopredict;
-extern vmCvar_t cg_noPlayerAnims;
-extern vmCvar_t cg_showmiss;
-extern vmCvar_t cg_footsteps;
-extern vmCvar_t cg_addMarks;
-extern vmCvar_t cg_brassTime;
-extern vmCvar_t cg_gun_frame;
-extern vmCvar_t cg_gun_x;
-extern vmCvar_t cg_gun_y;
-extern vmCvar_t cg_gun_z;
-extern vmCvar_t cg_drawGun;
-extern vmCvar_t cg_viewsize;
-extern vmCvar_t cg_tracerChance;
-extern vmCvar_t cg_tracerWidth;
-extern vmCvar_t cg_tracerLength;
-extern vmCvar_t cg_autoswitch;
-extern vmCvar_t cg_ignore;
-extern vmCvar_t cg_simpleItems;
-extern vmCvar_t cg_fov;
-extern vmCvar_t cg_zoomFov;
-extern vmCvar_t cg_thirdPersonRange;
-extern vmCvar_t cg_thirdPersonAngle;
-extern vmCvar_t cg_thirdPerson;
-extern vmCvar_t cg_lagometer;
-extern vmCvar_t cg_drawAttacker;
-extern vmCvar_t cg_synchronousClients;
-extern vmCvar_t cg_teamChatTime;
-extern vmCvar_t cg_teamChatHeight;
-extern vmCvar_t cg_stats;
-extern vmCvar_t cg_forceModel;
-extern vmCvar_t cg_buildScript;
-extern vmCvar_t cg_paused;
-extern vmCvar_t cg_blood;
-extern vmCvar_t cg_predictItems;
-extern vmCvar_t cg_deferPlayers;
-extern vmCvar_t cg_drawFriend;
-extern vmCvar_t cg_teamChatsOnly;
-extern vmCvar_t cg_noVoiceChats;
-extern vmCvar_t cg_noVoiceText;
-extern vmCvar_t cg_scorePlum;
-extern vmCvar_t cg_smoothClients;
-extern vmCvar_t pmove_fixed;
-extern vmCvar_t pmove_msec;
-//extern vmCvar_t cg_pmove_fixed;
-extern vmCvar_t cg_cameraOrbit;
-extern vmCvar_t cg_cameraOrbitDelay;
-extern vmCvar_t cg_timescaleFadeEnd;
-extern vmCvar_t cg_timescaleFadeSpeed;
-extern vmCvar_t cg_timescale;
-extern vmCvar_t cg_cameraMode;
-extern vmCvar_t cg_smallFont;
-extern vmCvar_t cg_bigFont;
-extern vmCvar_t cg_noTaunt;
-extern vmCvar_t cg_noProjectileTrail;
-extern vmCvar_t cg_oldRail;
-extern vmCvar_t cg_oldRocket;
-extern vmCvar_t cg_oldPlasma;
-extern vmCvar_t cg_trueLightning;
-#ifdef MISSIONPACK
-extern vmCvar_t cg_redTeamName;
-extern vmCvar_t cg_blueTeamName;
-extern vmCvar_t cg_currentSelectedPlayer;
-extern vmCvar_t cg_currentSelectedPlayerName;
-extern vmCvar_t cg_singlePlayer;
-extern vmCvar_t cg_enableDust;
-extern vmCvar_t cg_enableBreath;
-extern vmCvar_t cg_singlePlayerActive;
-extern vmCvar_t cg_recordSPDemo;
-extern vmCvar_t cg_recordSPDemoName;
-extern vmCvar_t cg_obeliskRespawnDelay;
-#endif
-
-//
-// cg_main.c
-//
-const char *CG_ConfigString( int index );
-const char *CG_Argv( int arg );
-
-void QDECL CG_Printf( const char *msg, ... );
-void QDECL CG_Error( const char *msg, ... );
-
-void CG_StartMusic( void );
-
-void CG_UpdateCvars( void );
-
-int CG_CrosshairPlayer( void );
-int CG_LastAttacker( void );
-void CG_LoadMenus(const char *menuFile);
-void CG_KeyEvent(int key, qboolean down);
-void CG_MouseEvent(int x, int y);
-void CG_EventHandling(int type);
-void CG_RankRunFrame( void );
-void CG_SetScoreSelection(void *menu);
-score_t *CG_GetSelectedScore( void );
-void CG_BuildSpectatorString( void );
-
-
-//
-// cg_view.c
-//
-void CG_TestModel_f (void);
-void CG_TestGun_f (void);
-void CG_TestModelNextFrame_f (void);
-void CG_TestModelPrevFrame_f (void);
-void CG_TestModelNextSkin_f (void);
-void CG_TestModelPrevSkin_f (void);
-void CG_ZoomDown_f( void );
-void CG_ZoomUp_f( void );
-void CG_AddBufferedSound( sfxHandle_t sfx);
-
-void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
-
-
-//
-// cg_drawtools.c
-//
-void CG_AdjustFrom640( float *x, float *y, float *w, float *h );
-void CG_FillRect( float x, float y, float width, float height, const float *color );
-void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader );
-void CG_DrawString( float x, float y, const char *string,
- float charWidth, float charHeight, const float *modulate );
-
-
-void CG_DrawStringExt( int x, int y, const char *string, const float *setColor,
- qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars );
-void CG_DrawBigString( int x, int y, const char *s, float alpha );
-void CG_DrawBigStringColor( int x, int y, const char *s, vec4_t color );
-void CG_DrawSmallString( int x, int y, const char *s, float alpha );
-void CG_DrawSmallStringColor( int x, int y, const char *s, vec4_t color );
-
-int CG_DrawStrlen( const char *str );
-
-float *CG_FadeColor( int startMsec, int totalMsec );
-float *CG_TeamColor( int team );
-void CG_TileClear( void );
-void CG_ColorForHealth( vec4_t hcolor );
-void CG_GetColorForHealth( int health, int armor, vec4_t hcolor );
-
-void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );
-void CG_DrawRect( float x, float y, float width, float height, float size, const float *color );
-void CG_DrawSides(float x, float y, float w, float h, float size);
-void CG_DrawTopBottom(float x, float y, float w, float h, float size);
-
-
-//
-// cg_draw.c, cg_newDraw.c
-//
-extern int sortedTeamPlayers[TEAM_MAXOVERLAY];
-extern int numSortedTeamPlayers;
-extern int drawTeamOverlayModificationCount;
-extern char systemChat[256];
-extern char teamChat1[256];
-extern char teamChat2[256];
-
-void CG_AddLagometerFrameInfo( void );
-void CG_AddLagometerSnapshotInfo( snapshot_t *snap );
-void CG_CenterPrint( const char *str, int y, int charWidth );
-void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles );
-void CG_DrawActive( stereoFrame_t stereoView );
-void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D );
-void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team );
-void CG_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle);
-void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style);
-int CG_Text_Width(const char *text, float scale, int limit);
-int CG_Text_Height(const char *text, float scale, int limit);
-void CG_SelectPrevPlayer( void );
-void CG_SelectNextPlayer( void );
-float CG_GetValue(int ownerDraw);
-qboolean CG_OwnerDrawVisible(int flags);
-void CG_RunMenuScript(char **args);
-void CG_ShowResponseHead( void );
-void CG_SetPrintString(int type, const char *p);
-void CG_InitTeamChat( void );
-void CG_GetTeamColor(vec4_t *color);
-const char *CG_GetGameStatusText( void );
-const char *CG_GetKillerText( void );
-void CG_Draw3DModel(float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles);
-void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader);
-void CG_CheckOrderPending( void );
-const char *CG_GameTypeString( void );
-qboolean CG_YourTeamHasFlag( void );
-qboolean CG_OtherTeamHasFlag( void );
-qhandle_t CG_StatusHandle(int task);
-
-
-
-//
-// cg_player.c
-//
-void CG_Player( centity_t *cent );
-void CG_ResetPlayerEntity( centity_t *cent );
-void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team );
-void CG_NewClientInfo( int clientNum );
-sfxHandle_t CG_CustomSound( int clientNum, const char *soundName );
-
-//
-// cg_predict.c
-//
-void CG_BuildSolidList( void );
-int CG_PointContents( const vec3_t point, int passEntityNum );
-void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
- int skipNumber, int mask );
-void CG_PredictPlayerState( void );
-void CG_LoadDeferredPlayers( void );
-
-
-//
-// cg_events.c
-//
-void CG_CheckEvents( centity_t *cent );
-const char *CG_PlaceString( int rank );
-void CG_EntityEvent( centity_t *cent, vec3_t position );
-void CG_PainEvent( centity_t *cent, int health );
-
-
-//
-// cg_ents.c
-//
-void CG_SetEntitySoundPosition( centity_t *cent );
-void CG_AddPacketEntities( void );
-void CG_Beam( centity_t *cent );
-void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out );
-
-void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- qhandle_t parentModel, char *tagName );
-void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- qhandle_t parentModel, char *tagName );
-
-
-
-//
-// cg_weapons.c
-//
-void CG_NextWeapon_f( void );
-void CG_PrevWeapon_f( void );
-void CG_Weapon_f( void );
-
-void CG_RegisterWeapon( int weaponNum );
-void CG_RegisterItemVisuals( int itemNum );
-
-void CG_FireWeapon( centity_t *cent );
-void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType );
-void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum );
-void CG_ShotgunFire( entityState_t *es );
-void CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum );
-
-void CG_RailTrail( clientInfo_t *ci, vec3_t start, vec3_t end );
-void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi );
-void CG_AddViewWeapon (playerState_t *ps);
-void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team );
-void CG_DrawWeaponSelect( void );
-
-void CG_OutOfAmmoChange( void ); // should this be in pmove?
-
-//
-// cg_marks.c
-//
-void CG_InitMarkPolys( void );
-void CG_AddMarks( void );
-void CG_ImpactMark( qhandle_t markShader,
- const vec3_t origin, const vec3_t dir,
- float orientation,
- float r, float g, float b, float a,
- qboolean alphaFade,
- float radius, qboolean temporary );
-
-//
-// cg_localents.c
-//
-void CG_InitLocalEntities( void );
-localEntity_t *CG_AllocLocalEntity( void );
-void CG_AddLocalEntities( void );
-
-//
-// cg_effects.c
-//
-localEntity_t *CG_SmokePuff( const vec3_t p,
- const vec3_t vel,
- float radius,
- float r, float g, float b, float a,
- float duration,
- int startTime,
- int fadeInTime,
- int leFlags,
- qhandle_t hShader );
-void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing );
-void CG_SpawnEffect( vec3_t org );
-#ifdef MISSIONPACK
-void CG_KamikazeEffect( vec3_t org );
-void CG_ObeliskExplode( vec3_t org, int entityNum );
-void CG_ObeliskPain( vec3_t org );
-void CG_InvulnerabilityImpact( vec3_t org, vec3_t angles );
-void CG_InvulnerabilityJuiced( vec3_t org );
-void CG_LightningBoltBeam( vec3_t start, vec3_t end );
-#endif
-void CG_ScorePlum( int client, vec3_t org, int score );
-
-void CG_GibPlayer( vec3_t playerOrigin );
-void CG_BigExplode( vec3_t playerOrigin );
-
-void CG_Bleed( vec3_t origin, int entityNum );
-
-localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
- qhandle_t hModel, qhandle_t shader, int msec,
- qboolean isSprite );
-
-//
-// cg_snapshot.c
-//
-void CG_ProcessSnapshots( void );
-
-//
-// cg_info.c
-//
-void CG_LoadingString( const char *s );
-void CG_LoadingItem( int itemNum );
-void CG_LoadingClient( int clientNum );
-void CG_DrawInformation( void );
-
-//
-// cg_scoreboard.c
-//
-qboolean CG_DrawOldScoreboard( void );
-void CG_DrawOldTourneyScoreboard( void );
-
-//
-// cg_consolecmds.c
-//
-qboolean CG_ConsoleCommand( void );
-void CG_InitConsoleCommands( void );
-
-//
-// cg_servercmds.c
-//
-void CG_ExecuteNewServerCommands( int latestSequence );
-void CG_ParseServerinfo( void );
-void CG_SetConfigValues( void );
-void CG_LoadVoiceChats( void );
-void CG_ShaderStateChanged(void);
-void CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd );
-void CG_PlayBufferedVoiceChats( void );
-
-//
-// cg_playerstate.c
-//
-void CG_Respawn( void );
-void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops );
-void CG_CheckChangedPredictableEvents( playerState_t *ps );
-
-
-//===============================================
-
-//
-// system traps
-// These functions are how the cgame communicates with the main game system
-//
-
-// print message on the local console
-void trap_Print( const char *fmt );
-
-// abort the game
-void trap_Error( const char *fmt );
-
-// milliseconds should only be used for performance tuning, never
-// for anything game related. Get time from the CG_DrawActiveFrame parameter
-int trap_Milliseconds( void );
-
-// console variable interaction
-void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
-void trap_Cvar_Update( vmCvar_t *vmCvar );
-void trap_Cvar_Set( const char *var_name, const char *value );
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-
-// ServerCommand and ConsoleCommand parameter access
-int trap_Argc( void );
-void trap_Argv( int n, char *buffer, int bufferLength );
-void trap_Args( char *buffer, int bufferLength );
-
-// filesystem access
-// returns length of file
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
-void trap_FS_Read( void *buffer, int len, fileHandle_t f );
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
-void trap_FS_FCloseFile( fileHandle_t f );
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
-
-// add commands to the local console as if they were typed in
-// for map changing, etc. The command is not executed immediately,
-// but will be executed in order the next time console commands
-// are processed
-void trap_SendConsoleCommand( const char *text );
-
-// register a command name so the console can perform command completion.
-// FIXME: replace this with a normal console command "defineCommand"?
-void trap_AddCommand( const char *cmdName );
-
-// send a string to the server over the network
-void trap_SendClientCommand( const char *s );
-
-// force a screen update, only used during gamestate load
-void trap_UpdateScreen( void );
-
-// model collision
-void trap_CM_LoadMap( const char *mapname );
-int trap_CM_NumInlineModels( void );
-clipHandle_t trap_CM_InlineModel( int index ); // 0 = world, 1+ = bmodels
-clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs );
-int trap_CM_PointContents( const vec3_t p, clipHandle_t model );
-int trap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles );
-void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask );
-void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask,
- const vec3_t origin, const vec3_t angles );
-
-// Returns the projection of a polygon onto the solid brushes in the world
-int trap_CM_MarkFragments( int numPoints, const vec3_t *points,
- const vec3_t projection,
- int maxPoints, vec3_t pointBuffer,
- int maxFragments, markFragment_t *fragmentBuffer );
-
-// normal sounds will have their volume dynamically changed as their entity
-// moves and the listener moves
-void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx );
-void trap_S_StopLoopingSound(int entnum);
-
-// a local sound is always played full volume
-void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );
-void trap_S_ClearLoopingSounds( qboolean killall );
-void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
-void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
-void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin );
-
-// respatialize recalculates the volumes of sound as they should be heard by the
-// given entityNum and position
-void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
-sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ); // returns buzz if not found
-void trap_S_StartBackgroundTrack( const char *intro, const char *loop ); // empty name stops music
-void trap_S_StopBackgroundTrack( void );
-
-
-void trap_R_LoadWorldMap( const char *mapname );
-
-// all media should be registered during level startup to prevent
-// hitches during gameplay
-qhandle_t trap_R_RegisterModel( const char *name ); // returns rgb axis if not found
-qhandle_t trap_R_RegisterSkin( const char *name ); // returns all white if not found
-qhandle_t trap_R_RegisterShader( const char *name ); // returns all white if not found
-qhandle_t trap_R_RegisterShaderNoMip( const char *name ); // returns all white if not found
-
-// a scene is built up by calls to R_ClearScene and the various R_Add functions.
-// Nothing is drawn until R_RenderScene is called.
-void trap_R_ClearScene( void );
-void trap_R_AddRefEntityToScene( const refEntity_t *re );
-
-// polys are intended for simple wall marks, not really for doing
-// significant construction
-void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );
-void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int numPolys );
-void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
-int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
-void trap_R_RenderScene( const refdef_t *fd );
-void trap_R_SetColor( const float *rgba ); // NULL = 1,1,1,1
-void trap_R_DrawStretchPic( float x, float y, float w, float h,
- float s1, float t1, float s2, float t2, qhandle_t hShader );
-void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );
-int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame,
- float frac, const char *tagName );
-void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset );
-
-// The glconfig_t will not change during the life of a cgame.
-// If it needs to change, the entire cgame will be restarted, because
-// all the qhandle_t are then invalid.
-void trap_GetGlconfig( glconfig_t *glconfig );
-
-// the gamestate should be grabbed at startup, and whenever a
-// configstring changes
-void trap_GetGameState( gameState_t *gamestate );
-
-// cgame will poll each frame to see if a newer snapshot has arrived
-// that it is interested in. The time is returned seperately so that
-// snapshot latency can be calculated.
-void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime );
-
-// a snapshot get can fail if the snapshot (or the entties it holds) is so
-// old that it has fallen out of the client system queue
-qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot );
-
-// retrieve a text command from the server stream
-// the current snapshot will hold the number of the most recent command
-// qfalse can be returned if the client system handled the command
-// argc() / argv() can be used to examine the parameters of the command
-qboolean trap_GetServerCommand( int serverCommandNumber );
-
-// returns the most recent command number that can be passed to GetUserCmd
-// this will always be at least one higher than the number in the current
-// snapshot, and it may be quite a few higher if it is a fast computer on
-// a lagged connection
-int trap_GetCurrentCmdNumber( void );
-
-qboolean trap_GetUserCmd( int cmdNumber, usercmd_t *ucmd );
-
-// used for the weapon select and zoom
-void trap_SetUserCmdValue( int stateValue, float sensitivityScale );
-
-// aids for VM testing
-void testPrintInt( char *string, int i );
-void testPrintFloat( char *string, float f );
-
-int trap_MemoryRemaining( void );
-void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font);
-qboolean trap_Key_IsDown( int keynum );
-int trap_Key_GetCatcher( void );
-void trap_Key_SetCatcher( int catcher );
-int trap_Key_GetKey( const char *binding );
-
-
-typedef enum {
- SYSTEM_PRINT,
- CHAT_PRINT,
- TEAMCHAT_PRINT
-} q3print_t;
-
-
-int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits);
-e_status trap_CIN_StopCinematic(int handle);
-e_status trap_CIN_RunCinematic (int handle);
-void trap_CIN_DrawCinematic (int handle);
-void trap_CIN_SetExtents (int handle, int x, int y, int w, int h);
-
-void trap_SnapVector( float *v );
-
-qboolean trap_loadCamera(const char *name);
-void trap_startCamera(int time);
-qboolean trap_getCameraInfo(int time, vec3_t *origin, vec3_t *angles);
-
-qboolean trap_GetEntityToken( char *buffer, int bufferSize );
-
-void CG_ClearParticles (void);
-void CG_AddParticles (void);
-void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum);
-void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent);
-void CG_AddParticleShrapnel (localEntity_t *le);
-void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent);
-void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration);
-void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed);
-void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir);
-void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha);
-void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd);
-extern qboolean initparticles;
-int CG_NewParticleArea ( int num );
-
-
diff --git a/engine/code/cgame/cg_localents.c b/engine/code/cgame/cg_localents.c
deleted file mode 100644
index 8077cbd..0000000
--- a/engine/code/cgame/cg_localents.c
+++ /dev/null
@@ -1,886 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-// cg_localents.c -- every frame, generate renderer commands for locally
-// processed entities, like smoke puffs, gibs, shells, etc.
-
-#include "cg_local.h"
-
-#define MAX_LOCAL_ENTITIES 512
-localEntity_t cg_localEntities[MAX_LOCAL_ENTITIES];
-localEntity_t cg_activeLocalEntities; // double linked list
-localEntity_t *cg_freeLocalEntities; // single linked list
-
-/*
-===================
-CG_InitLocalEntities
-
-This is called at startup and for tournement restarts
-===================
-*/
-void CG_InitLocalEntities( void ) {
- int i;
-
- memset( cg_localEntities, 0, sizeof( cg_localEntities ) );
- cg_activeLocalEntities.next = &cg_activeLocalEntities;
- cg_activeLocalEntities.prev = &cg_activeLocalEntities;
- cg_freeLocalEntities = cg_localEntities;
- for ( i = 0 ; i < MAX_LOCAL_ENTITIES - 1 ; i++ ) {
- cg_localEntities[i].next = &cg_localEntities[i+1];
- }
-}
-
-
-/*
-==================
-CG_FreeLocalEntity
-==================
-*/
-void CG_FreeLocalEntity( localEntity_t *le ) {
- if ( !le->prev ) {
- CG_Error( "CG_FreeLocalEntity: not active" );
- }
-
- // remove from the doubly linked active list
- le->prev->next = le->next;
- le->next->prev = le->prev;
-
- // the free list is only singly linked
- le->next = cg_freeLocalEntities;
- cg_freeLocalEntities = le;
-}
-
-/*
-===================
-CG_AllocLocalEntity
-
-Will allways succeed, even if it requires freeing an old active entity
-===================
-*/
-localEntity_t *CG_AllocLocalEntity( void ) {
- localEntity_t *le;
-
- if ( !cg_freeLocalEntities ) {
- // no free entities, so free the one at the end of the chain
- // remove the oldest active entity
- CG_FreeLocalEntity( cg_activeLocalEntities.prev );
- }
-
- le = cg_freeLocalEntities;
- cg_freeLocalEntities = cg_freeLocalEntities->next;
-
- memset( le, 0, sizeof( *le ) );
-
- // link into the active list
- le->next = cg_activeLocalEntities.next;
- le->prev = &cg_activeLocalEntities;
- cg_activeLocalEntities.next->prev = le;
- cg_activeLocalEntities.next = le;
- return le;
-}
-
-
-/*
-====================================================================================
-
-FRAGMENT PROCESSING
-
-A fragment localentity interacts with the environment in some way (hitting walls),
-or generates more localentities along a trail.
-
-====================================================================================
-*/
-
-/*
-================
-CG_BloodTrail
-
-Leave expanding blood puffs behind gibs
-================
-*/
-void CG_BloodTrail( localEntity_t *le ) {
- int t;
- int t2;
- int step;
- vec3_t newOrigin;
- localEntity_t *blood;
-
- step = 150;
- t = step * ( (cg.time - cg.frametime + step ) / step );
- t2 = step * ( cg.time / step );
-
- for ( ; t <= t2; t += step ) {
- BG_EvaluateTrajectory( &le->pos, t, newOrigin );
-
- blood = CG_SmokePuff( newOrigin, vec3_origin,
- 20, // radius
- 1, 1, 1, 1, // color
- 2000, // trailTime
- t, // startTime
- 0, // fadeInTime
- 0, // flags
- cgs.media.bloodTrailShader );
- // use the optimized version
- blood->leType = LE_FALL_SCALE_FADE;
- // drop a total of 40 units over its lifetime
- blood->pos.trDelta[2] = 40;
- }
-}
-
-
-/*
-================
-CG_FragmentBounceMark
-================
-*/
-void CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) {
- int radius;
-
- if ( le->leMarkType == LEMT_BLOOD ) {
-
- radius = 16 + (rand()&31);
- CG_ImpactMark( cgs.media.bloodMarkShader, trace->endpos, trace->plane.normal, random()*360,
- 1,1,1,1, qtrue, radius, qfalse );
- } else if ( le->leMarkType == LEMT_BURN ) {
-
- radius = 8 + (rand()&15);
- CG_ImpactMark( cgs.media.burnMarkShader, trace->endpos, trace->plane.normal, random()*360,
- 1,1,1,1, qtrue, radius, qfalse );
- }
-
-
- // don't allow a fragment to make multiple marks, or they
- // pile up while settling
- le->leMarkType = LEMT_NONE;
-}
-
-/*
-================
-CG_FragmentBounceSound
-================
-*/
-void CG_FragmentBounceSound( localEntity_t *le, trace_t *trace ) {
- if ( le->leBounceSoundType == LEBS_BLOOD ) {
- // half the gibs will make splat sounds
- if ( rand() & 1 ) {
- int r = rand()&3;
- sfxHandle_t s;
-
- if ( r == 0 ) {
- s = cgs.media.gibBounce1Sound;
- } else if ( r == 1 ) {
- s = cgs.media.gibBounce2Sound;
- } else {
- s = cgs.media.gibBounce3Sound;
- }
- trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );
- }
- } else if ( le->leBounceSoundType == LEBS_BRASS ) {
-
- }
-
- // don't allow a fragment to make multiple bounce sounds,
- // or it gets too noisy as they settle
- le->leBounceSoundType = LEBS_NONE;
-}
-
-
-/*
-================
-CG_ReflectVelocity
-================
-*/
-void CG_ReflectVelocity( localEntity_t *le, trace_t *trace ) {
- vec3_t velocity;
- float dot;
- int hitTime;
-
- // reflect the velocity on the trace plane
- hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction;
- BG_EvaluateTrajectoryDelta( &le->pos, hitTime, velocity );
- dot = DotProduct( velocity, trace->plane.normal );
- VectorMA( velocity, -2*dot, trace->plane.normal, le->pos.trDelta );
-
- VectorScale( le->pos.trDelta, le->bounceFactor, le->pos.trDelta );
-
- VectorCopy( trace->endpos, le->pos.trBase );
- le->pos.trTime = cg.time;
-
-
- // check for stop, making sure that even on low FPS systems it doesn't bobble
- if ( trace->allsolid ||
- ( trace->plane.normal[2] > 0 &&
- ( le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2] ) ) ) {
- le->pos.trType = TR_STATIONARY;
- } else {
-
- }
-}
-
-/*
-================
-CG_AddFragment
-================
-*/
-void CG_AddFragment( localEntity_t *le ) {
- vec3_t newOrigin;
- trace_t trace;
-
- if ( le->pos.trType == TR_STATIONARY ) {
- // sink into the ground if near the removal time
- int t;
- float oldZ;
-
- t = le->endTime - cg.time;
- if ( t < SINK_TIME ) {
- // we must use an explicit lighting origin, otherwise the
- // lighting would be lost as soon as the origin went
- // into the ground
- VectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin );
- le->refEntity.renderfx |= RF_LIGHTING_ORIGIN;
- oldZ = le->refEntity.origin[2];
- le->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME );
- trap_R_AddRefEntityToScene( &le->refEntity );
- le->refEntity.origin[2] = oldZ;
- } else {
- trap_R_AddRefEntityToScene( &le->refEntity );
- }
-
- return;
- }
-
- // calculate new position
- BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );
-
- // trace a line from previous position to new position
- CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
- if ( trace.fraction == 1.0 ) {
- // still in free fall
- VectorCopy( newOrigin, le->refEntity.origin );
-
- if ( le->leFlags & LEF_TUMBLE ) {
- vec3_t angles;
-
- BG_EvaluateTrajectory( &le->angles, cg.time, angles );
- AnglesToAxis( angles, le->refEntity.axis );
- }
-
- trap_R_AddRefEntityToScene( &le->refEntity );
-
- // add a blood trail
- if ( le->leBounceSoundType == LEBS_BLOOD ) {
- CG_BloodTrail( le );
- }
-
- return;
- }
-
- // if it is in a nodrop zone, remove it
- // this keeps gibs from waiting at the bottom of pits of death
- // and floating levels
- if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- // leave a mark
- CG_FragmentBounceMark( le, &trace );
-
- // do a bouncy sound
- CG_FragmentBounceSound( le, &trace );
-
- // reflect the velocity on the trace plane
- CG_ReflectVelocity( le, &trace );
-
- trap_R_AddRefEntityToScene( &le->refEntity );
-}
-
-/*
-=====================================================================
-
-TRIVIAL LOCAL ENTITIES
-
-These only do simple scaling or modulation before passing to the renderer
-=====================================================================
-*/
-
-/*
-====================
-CG_AddFadeRGB
-====================
-*/
-void CG_AddFadeRGB( localEntity_t *le ) {
- refEntity_t *re;
- float c;
-
- re = &le->refEntity;
-
- c = ( le->endTime - cg.time ) * le->lifeRate;
- c *= 0xff;
-
- re->shaderRGBA[0] = le->color[0] * c;
- re->shaderRGBA[1] = le->color[1] * c;
- re->shaderRGBA[2] = le->color[2] * c;
- re->shaderRGBA[3] = le->color[3] * c;
-
- trap_R_AddRefEntityToScene( re );
-}
-
-/*
-==================
-CG_AddMoveScaleFade
-==================
-*/
-static void CG_AddMoveScaleFade( localEntity_t *le ) {
- refEntity_t *re;
- float c;
- vec3_t delta;
- float len;
-
- re = &le->refEntity;
-
- if ( le->fadeInTime > le->startTime && cg.time < le->fadeInTime ) {
- // fade / grow time
- c = 1.0 - (float) ( le->fadeInTime - cg.time ) / ( le->fadeInTime - le->startTime );
- }
- else {
- // fade / grow time
- c = ( le->endTime - cg.time ) * le->lifeRate;
- }
-
- re->shaderRGBA[3] = 0xff * c * le->color[3];
-
- if ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) {
- re->radius = le->radius * ( 1.0 - c ) + 8;
- }
-
- BG_EvaluateTrajectory( &le->pos, cg.time, re->origin );
-
- // if the view would be "inside" the sprite, kill the sprite
- // so it doesn't add too much overdraw
- VectorSubtract( re->origin, cg.refdef.vieworg, delta );
- len = VectorLength( delta );
- if ( len < le->radius ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- trap_R_AddRefEntityToScene( re );
-}
-
-
-/*
-===================
-CG_AddScaleFade
-
-For rocket smokes that hang in place, fade out, and are
-removed if the view passes through them.
-There are often many of these, so it needs to be simple.
-===================
-*/
-static void CG_AddScaleFade( localEntity_t *le ) {
- refEntity_t *re;
- float c;
- vec3_t delta;
- float len;
-
- re = &le->refEntity;
-
- // fade / grow time
- c = ( le->endTime - cg.time ) * le->lifeRate;
-
- re->shaderRGBA[3] = 0xff * c * le->color[3];
- re->radius = le->radius * ( 1.0 - c ) + 8;
-
- // if the view would be "inside" the sprite, kill the sprite
- // so it doesn't add too much overdraw
- VectorSubtract( re->origin, cg.refdef.vieworg, delta );
- len = VectorLength( delta );
- if ( len < le->radius ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- trap_R_AddRefEntityToScene( re );
-}
-
-
-/*
-=================
-CG_AddFallScaleFade
-
-This is just an optimized CG_AddMoveScaleFade
-For blood mists that drift down, fade out, and are
-removed if the view passes through them.
-There are often 100+ of these, so it needs to be simple.
-=================
-*/
-static void CG_AddFallScaleFade( localEntity_t *le ) {
- refEntity_t *re;
- float c;
- vec3_t delta;
- float len;
-
- re = &le->refEntity;
-
- // fade time
- c = ( le->endTime - cg.time ) * le->lifeRate;
-
- re->shaderRGBA[3] = 0xff * c * le->color[3];
-
- re->origin[2] = le->pos.trBase[2] - ( 1.0 - c ) * le->pos.trDelta[2];
-
- re->radius = le->radius * ( 1.0 - c ) + 16;
-
- // if the view would be "inside" the sprite, kill the sprite
- // so it doesn't add too much overdraw
- VectorSubtract( re->origin, cg.refdef.vieworg, delta );
- len = VectorLength( delta );
- if ( len < le->radius ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- trap_R_AddRefEntityToScene( re );
-}
-
-
-
-/*
-================
-CG_AddExplosion
-================
-*/
-static void CG_AddExplosion( localEntity_t *ex ) {
- refEntity_t *ent;
-
- ent = &ex->refEntity;
-
- // add the entity
- trap_R_AddRefEntityToScene(ent);
-
- // add the dlight
- if ( ex->light ) {
- float light;
-
- light = (float)( cg.time - ex->startTime ) / ( ex->endTime - ex->startTime );
- if ( light < 0.5 ) {
- light = 1.0;
- } else {
- light = 1.0 - ( light - 0.5 ) * 2;
- }
- light = ex->light * light;
- trap_R_AddLightToScene(ent->origin, light, ex->lightColor[0], ex->lightColor[1], ex->lightColor[2] );
- }
-}
-
-/*
-================
-CG_AddSpriteExplosion
-================
-*/
-static void CG_AddSpriteExplosion( localEntity_t *le ) {
- refEntity_t re;
- float c;
-
- re = le->refEntity;
-
- c = ( le->endTime - cg.time ) / ( float ) ( le->endTime - le->startTime );
- if ( c > 1 ) {
- c = 1.0; // can happen during connection problems
- }
-
- re.shaderRGBA[0] = 0xff;
- re.shaderRGBA[1] = 0xff;
- re.shaderRGBA[2] = 0xff;
- re.shaderRGBA[3] = 0xff * c * 0.33;
-
- re.reType = RT_SPRITE;
- re.radius = 42 * ( 1.0 - c ) + 30;
-
- trap_R_AddRefEntityToScene( &re );
-
- // add the dlight
- if ( le->light ) {
- float light;
-
- light = (float)( cg.time - le->startTime ) / ( le->endTime - le->startTime );
- if ( light < 0.5 ) {
- light = 1.0;
- } else {
- light = 1.0 - ( light - 0.5 ) * 2;
- }
- light = le->light * light;
- trap_R_AddLightToScene(re.origin, light, le->lightColor[0], le->lightColor[1], le->lightColor[2] );
- }
-}
-
-
-#ifdef MISSIONPACK
-/*
-====================
-CG_AddKamikaze
-====================
-*/
-void CG_AddKamikaze( localEntity_t *le ) {
- refEntity_t *re;
- refEntity_t shockwave;
- float c;
- vec3_t test, axis[3];
- int t;
-
- re = &le->refEntity;
-
- t = cg.time - le->startTime;
- VectorClear( test );
- AnglesToAxis( test, axis );
-
- if (t > KAMI_SHOCKWAVE_STARTTIME && t < KAMI_SHOCKWAVE_ENDTIME) {
-
- if (!(le->leFlags & LEF_SOUND1)) {
-// trap_S_StartSound (re->origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.kamikazeExplodeSound );
- trap_S_StartLocalSound(cgs.media.kamikazeExplodeSound, CHAN_AUTO);
- le->leFlags |= LEF_SOUND1;
- }
- // 1st kamikaze shockwave
- memset(&shockwave, 0, sizeof(shockwave));
- shockwave.hModel = cgs.media.kamikazeShockWave;
- shockwave.reType = RT_MODEL;
- shockwave.shaderTime = re->shaderTime;
- VectorCopy(re->origin, shockwave.origin);
-
- c = (float)(t - KAMI_SHOCKWAVE_STARTTIME) / (float)(KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVE_STARTTIME);
- VectorScale( axis[0], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[0] );
- VectorScale( axis[1], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[1] );
- VectorScale( axis[2], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[2] );
- shockwave.nonNormalizedAxes = qtrue;
-
- if (t > KAMI_SHOCKWAVEFADE_STARTTIME) {
- c = (float)(t - KAMI_SHOCKWAVEFADE_STARTTIME) / (float)(KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVEFADE_STARTTIME);
- }
- else {
- c = 0;
- }
- c *= 0xff;
- shockwave.shaderRGBA[0] = 0xff - c;
- shockwave.shaderRGBA[1] = 0xff - c;
- shockwave.shaderRGBA[2] = 0xff - c;
- shockwave.shaderRGBA[3] = 0xff - c;
-
- trap_R_AddRefEntityToScene( &shockwave );
- }
-
- if (t > KAMI_EXPLODE_STARTTIME && t < KAMI_IMPLODE_ENDTIME) {
- // explosion and implosion
- c = ( le->endTime - cg.time ) * le->lifeRate;
- c *= 0xff;
- re->shaderRGBA[0] = le->color[0] * c;
- re->shaderRGBA[1] = le->color[1] * c;
- re->shaderRGBA[2] = le->color[2] * c;
- re->shaderRGBA[3] = le->color[3] * c;
-
- if( t < KAMI_IMPLODE_STARTTIME ) {
- c = (float)(t - KAMI_EXPLODE_STARTTIME) / (float)(KAMI_IMPLODE_STARTTIME - KAMI_EXPLODE_STARTTIME);
- }
- else {
- if (!(le->leFlags & LEF_SOUND2)) {
-// trap_S_StartSound (re->origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.kamikazeImplodeSound );
- trap_S_StartLocalSound(cgs.media.kamikazeImplodeSound, CHAN_AUTO);
- le->leFlags |= LEF_SOUND2;
- }
- c = (float)(KAMI_IMPLODE_ENDTIME - t) / (float) (KAMI_IMPLODE_ENDTIME - KAMI_IMPLODE_STARTTIME);
- }
- VectorScale( axis[0], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[0] );
- VectorScale( axis[1], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[1] );
- VectorScale( axis[2], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[2] );
- re->nonNormalizedAxes = qtrue;
-
- trap_R_AddRefEntityToScene( re );
- // add the dlight
- trap_R_AddLightToScene( re->origin, c * 1000.0, 1.0, 1.0, c );
- }
-
- if (t > KAMI_SHOCKWAVE2_STARTTIME && t < KAMI_SHOCKWAVE2_ENDTIME) {
- // 2nd kamikaze shockwave
- if (le->angles.trBase[0] == 0 &&
- le->angles.trBase[1] == 0 &&
- le->angles.trBase[2] == 0) {
- le->angles.trBase[0] = random() * 360;
- le->angles.trBase[1] = random() * 360;
- le->angles.trBase[2] = random() * 360;
- }
- else {
- c = 0;
- }
- memset(&shockwave, 0, sizeof(shockwave));
- shockwave.hModel = cgs.media.kamikazeShockWave;
- shockwave.reType = RT_MODEL;
- shockwave.shaderTime = re->shaderTime;
- VectorCopy(re->origin, shockwave.origin);
-
- test[0] = le->angles.trBase[0];
- test[1] = le->angles.trBase[1];
- test[2] = le->angles.trBase[2];
- AnglesToAxis( test, axis );
-
- c = (float)(t - KAMI_SHOCKWAVE2_STARTTIME) / (float)(KAMI_SHOCKWAVE2_ENDTIME - KAMI_SHOCKWAVE2_STARTTIME);
- VectorScale( axis[0], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[0] );
- VectorScale( axis[1], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[1] );
- VectorScale( axis[2], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[2] );
- shockwave.nonNormalizedAxes = qtrue;
-
- if (t > KAMI_SHOCKWAVE2FADE_STARTTIME) {
- c = (float)(t - KAMI_SHOCKWAVE2FADE_STARTTIME) / (float)(KAMI_SHOCKWAVE2_ENDTIME - KAMI_SHOCKWAVE2FADE_STARTTIME);
- }
- else {
- c = 0;
- }
- c *= 0xff;
- shockwave.shaderRGBA[0] = 0xff - c;
- shockwave.shaderRGBA[1] = 0xff - c;
- shockwave.shaderRGBA[2] = 0xff - c;
- shockwave.shaderRGBA[3] = 0xff - c;
-
- trap_R_AddRefEntityToScene( &shockwave );
- }
-}
-
-/*
-===================
-CG_AddInvulnerabilityImpact
-===================
-*/
-void CG_AddInvulnerabilityImpact( localEntity_t *le ) {
- trap_R_AddRefEntityToScene( &le->refEntity );
-}
-
-/*
-===================
-CG_AddInvulnerabilityJuiced
-===================
-*/
-void CG_AddInvulnerabilityJuiced( localEntity_t *le ) {
- int t;
-
- t = cg.time - le->startTime;
- if ( t > 3000 ) {
- le->refEntity.axis[0][0] = (float) 1.0 + 0.3 * (t - 3000) / 2000;
- le->refEntity.axis[1][1] = (float) 1.0 + 0.3 * (t - 3000) / 2000;
- le->refEntity.axis[2][2] = (float) 0.7 + 0.3 * (2000 - (t - 3000)) / 2000;
- }
- if ( t > 5000 ) {
- le->endTime = 0;
- CG_GibPlayer( le->refEntity.origin );
- }
- else {
- trap_R_AddRefEntityToScene( &le->refEntity );
- }
-}
-
-/*
-===================
-CG_AddRefEntity
-===================
-*/
-void CG_AddRefEntity( localEntity_t *le ) {
- if (le->endTime < cg.time) {
- CG_FreeLocalEntity( le );
- return;
- }
- trap_R_AddRefEntityToScene( &le->refEntity );
-}
-
-#endif
-/*
-===================
-CG_AddScorePlum
-===================
-*/
-#define NUMBER_SIZE 8
-
-void CG_AddScorePlum( localEntity_t *le ) {
- refEntity_t *re;
- vec3_t origin, delta, dir, vec, up = {0, 0, 1};
- float c, len;
- int i, score, digits[10], numdigits, negative;
-
- re = &le->refEntity;
-
- c = ( le->endTime - cg.time ) * le->lifeRate;
-
- score = le->radius;
- if (score < 0) {
- re->shaderRGBA[0] = 0xff;
- re->shaderRGBA[1] = 0x11;
- re->shaderRGBA[2] = 0x11;
- }
- else {
- re->shaderRGBA[0] = 0xff;
- re->shaderRGBA[1] = 0xff;
- re->shaderRGBA[2] = 0xff;
- if (score >= 50) {
- re->shaderRGBA[1] = 0;
- } else if (score >= 20) {
- re->shaderRGBA[0] = re->shaderRGBA[1] = 0;
- } else if (score >= 10) {
- re->shaderRGBA[2] = 0;
- } else if (score >= 2) {
- re->shaderRGBA[0] = re->shaderRGBA[2] = 0;
- }
-
- }
- if (c < 0.25)
- re->shaderRGBA[3] = 0xff * 4 * c;
- else
- re->shaderRGBA[3] = 0xff;
-
- re->radius = NUMBER_SIZE / 2;
-
- VectorCopy(le->pos.trBase, origin);
- origin[2] += 110 - c * 100;
-
- VectorSubtract(cg.refdef.vieworg, origin, dir);
- CrossProduct(dir, up, vec);
- VectorNormalize(vec);
-
- VectorMA(origin, -10 + 20 * sin(c * 2 * M_PI), vec, origin);
-
- // if the view would be "inside" the sprite, kill the sprite
- // so it doesn't add too much overdraw
- VectorSubtract( origin, cg.refdef.vieworg, delta );
- len = VectorLength( delta );
- if ( len < 20 ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- negative = qfalse;
- if (score < 0) {
- negative = qtrue;
- score = -score;
- }
-
- for (numdigits = 0; !(numdigits && !score); numdigits++) {
- digits[numdigits] = score % 10;
- score = score / 10;
- }
-
- if (negative) {
- digits[numdigits] = 10;
- numdigits++;
- }
-
- for (i = 0; i < numdigits; i++) {
- VectorMA(origin, (float) (((float) numdigits / 2) - i) * NUMBER_SIZE, vec, re->origin);
- re->customShader = cgs.media.numberShaders[digits[numdigits-1-i]];
- trap_R_AddRefEntityToScene( re );
- }
-}
-
-
-
-
-//==============================================================================
-
-/*
-===================
-CG_AddLocalEntities
-
-===================
-*/
-void CG_AddLocalEntities( void ) {
- localEntity_t *le, *next;
-
- // walk the list backwards, so any new local entities generated
- // (trails, marks, etc) will be present this frame
- le = cg_activeLocalEntities.prev;
- for ( ; le != &cg_activeLocalEntities ; le = next ) {
- // grab next now, so if the local entity is freed we
- // still have it
- next = le->prev;
-
- if ( cg.time >= le->endTime ) {
- CG_FreeLocalEntity( le );
- continue;
- }
- switch ( le->leType ) {
- default:
- CG_Error( "Bad leType: %i", le->leType );
- break;
-
- case LE_MARK:
- break;
-
- case LE_SPRITE_EXPLOSION:
- CG_AddSpriteExplosion( le );
- break;
-
- case LE_EXPLOSION:
- CG_AddExplosion( le );
- break;
-
- case LE_FRAGMENT: // gibs and brass
- CG_AddFragment( le );
- break;
-
- case LE_MOVE_SCALE_FADE: // water bubbles
- CG_AddMoveScaleFade( le );
- break;
-
- case LE_FADE_RGB: // teleporters, railtrails
- CG_AddFadeRGB( le );
- break;
-
- case LE_FALL_SCALE_FADE: // gib blood trails
- CG_AddFallScaleFade( le );
- break;
-
- case LE_SCALE_FADE: // rocket trails
- CG_AddScaleFade( le );
- break;
-
- case LE_SCOREPLUM:
- CG_AddScorePlum( le );
- break;
-
-#ifdef MISSIONPACK
- case LE_KAMIKAZE:
- CG_AddKamikaze( le );
- break;
- case LE_INVULIMPACT:
- CG_AddInvulnerabilityImpact( le );
- break;
- case LE_INVULJUICED:
- CG_AddInvulnerabilityJuiced( le );
- break;
- case LE_SHOWREFENTITY:
- CG_AddRefEntity( le );
- break;
-#endif
- }
- }
-}
-
-
-
-
diff --git a/engine/code/cgame/cg_main.c b/engine/code/cgame/cg_main.c
deleted file mode 100644
index b5670c5..0000000
--- a/engine/code/cgame/cg_main.c
+++ /dev/null
@@ -1,1988 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_main.c -- initialization and primary entry point for cgame
-#include "cg_local.h"
-
-#ifdef MISSIONPACK
-#include "../ui/ui_shared.h"
-// display context for new ui stuff
-displayContextDef_t cgDC;
-#endif
-
-int forceModelModificationCount = -1;
-
-void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum );
-void CG_Shutdown( void );
-
-
-/*
-================
-vmMain
-
-This is the only way control passes into the module.
-This must be the very first function compiled into the .q3vm file
-================
-*/
-Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
-
- switch ( command ) {
- case CG_INIT:
- CG_Init( arg0, arg1, arg2 );
- return 0;
- case CG_SHUTDOWN:
- CG_Shutdown();
- return 0;
- case CG_CONSOLE_COMMAND:
- return CG_ConsoleCommand();
- case CG_DRAW_ACTIVE_FRAME:
- CG_DrawActiveFrame( arg0, arg1, arg2 );
- return 0;
- case CG_CROSSHAIR_PLAYER:
- return CG_CrosshairPlayer();
- case CG_LAST_ATTACKER:
- return CG_LastAttacker();
- case CG_KEY_EVENT:
- CG_KeyEvent(arg0, arg1);
- return 0;
- case CG_MOUSE_EVENT:
-#ifdef MISSIONPACK
- cgDC.cursorx = cgs.cursorX;
- cgDC.cursory = cgs.cursorY;
-#endif
- CG_MouseEvent(arg0, arg1);
- return 0;
- case CG_EVENT_HANDLING:
- CG_EventHandling(arg0);
- return 0;
- default:
- CG_Error( "vmMain: unknown command %i", command );
- break;
- }
- return -1;
-}
-
-
-cg_t cg;
-cgs_t cgs;
-centity_t cg_entities[MAX_GENTITIES];
-weaponInfo_t cg_weapons[MAX_WEAPONS];
-itemInfo_t cg_items[MAX_ITEMS];
-
-
-vmCvar_t cg_railTrailTime;
-vmCvar_t cg_centertime;
-vmCvar_t cg_runpitch;
-vmCvar_t cg_runroll;
-vmCvar_t cg_bobup;
-vmCvar_t cg_bobpitch;
-vmCvar_t cg_bobroll;
-vmCvar_t cg_swingSpeed;
-vmCvar_t cg_shadows;
-vmCvar_t cg_gibs;
-vmCvar_t cg_drawTimer;
-vmCvar_t cg_drawFPS;
-vmCvar_t cg_drawSnapshot;
-vmCvar_t cg_draw3dIcons;
-vmCvar_t cg_drawIcons;
-vmCvar_t cg_drawAmmoWarning;
-vmCvar_t cg_drawCrosshair;
-vmCvar_t cg_drawCrosshairNames;
-vmCvar_t cg_drawRewards;
-vmCvar_t cg_crosshairSize;
-vmCvar_t cg_crosshairX;
-vmCvar_t cg_crosshairY;
-vmCvar_t cg_crosshairHealth;
-vmCvar_t cg_draw2D;
-vmCvar_t cg_drawStatus;
-vmCvar_t cg_animSpeed;
-vmCvar_t cg_debugAnim;
-vmCvar_t cg_debugPosition;
-vmCvar_t cg_debugEvents;
-vmCvar_t cg_errorDecay;
-vmCvar_t cg_nopredict;
-vmCvar_t cg_noPlayerAnims;
-vmCvar_t cg_showmiss;
-vmCvar_t cg_footsteps;
-vmCvar_t cg_addMarks;
-vmCvar_t cg_brassTime;
-vmCvar_t cg_viewsize;
-vmCvar_t cg_drawGun;
-vmCvar_t cg_gun_frame;
-vmCvar_t cg_gun_x;
-vmCvar_t cg_gun_y;
-vmCvar_t cg_gun_z;
-vmCvar_t cg_tracerChance;
-vmCvar_t cg_tracerWidth;
-vmCvar_t cg_tracerLength;
-vmCvar_t cg_autoswitch;
-vmCvar_t cg_ignore;
-vmCvar_t cg_simpleItems;
-vmCvar_t cg_fov;
-vmCvar_t cg_zoomFov;
-vmCvar_t cg_thirdPerson;
-vmCvar_t cg_thirdPersonRange;
-vmCvar_t cg_thirdPersonAngle;
-vmCvar_t cg_lagometer;
-vmCvar_t cg_drawAttacker;
-vmCvar_t cg_synchronousClients;
-vmCvar_t cg_teamChatTime;
-vmCvar_t cg_teamChatHeight;
-vmCvar_t cg_stats;
-vmCvar_t cg_buildScript;
-vmCvar_t cg_forceModel;
-vmCvar_t cg_paused;
-vmCvar_t cg_blood;
-vmCvar_t cg_predictItems;
-vmCvar_t cg_deferPlayers;
-vmCvar_t cg_drawTeamOverlay;
-vmCvar_t cg_teamOverlayUserinfo;
-vmCvar_t cg_drawFriend;
-vmCvar_t cg_teamChatsOnly;
-vmCvar_t cg_noVoiceChats;
-vmCvar_t cg_noVoiceText;
-vmCvar_t cg_hudFiles;
-vmCvar_t cg_scorePlum;
-vmCvar_t cg_smoothClients;
-vmCvar_t pmove_fixed;
-//vmCvar_t cg_pmove_fixed;
-vmCvar_t pmove_msec;
-vmCvar_t cg_pmove_msec;
-vmCvar_t cg_cameraMode;
-vmCvar_t cg_cameraOrbit;
-vmCvar_t cg_cameraOrbitDelay;
-vmCvar_t cg_timescaleFadeEnd;
-vmCvar_t cg_timescaleFadeSpeed;
-vmCvar_t cg_timescale;
-vmCvar_t cg_smallFont;
-vmCvar_t cg_bigFont;
-vmCvar_t cg_noTaunt;
-vmCvar_t cg_noProjectileTrail;
-vmCvar_t cg_oldRail;
-vmCvar_t cg_oldRocket;
-vmCvar_t cg_oldPlasma;
-vmCvar_t cg_trueLightning;
-
-#ifdef MISSIONPACK
-vmCvar_t cg_redTeamName;
-vmCvar_t cg_blueTeamName;
-vmCvar_t cg_currentSelectedPlayer;
-vmCvar_t cg_currentSelectedPlayerName;
-vmCvar_t cg_singlePlayer;
-vmCvar_t cg_enableDust;
-vmCvar_t cg_enableBreath;
-vmCvar_t cg_singlePlayerActive;
-vmCvar_t cg_recordSPDemo;
-vmCvar_t cg_recordSPDemoName;
-vmCvar_t cg_obeliskRespawnDelay;
-#endif
-
-typedef struct {
- vmCvar_t *vmCvar;
- char *cvarName;
- char *defaultString;
- int cvarFlags;
-} cvarTable_t;
-
-static cvarTable_t cvarTable[] = {
- { &cg_ignore, "cg_ignore", "0", 0 }, // used for debugging
- { &cg_autoswitch, "cg_autoswitch", "1", CVAR_ARCHIVE },
- { &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE },
- { &cg_zoomFov, "cg_zoomfov", "22.5", CVAR_ARCHIVE },
- { &cg_fov, "cg_fov", "90", CVAR_ARCHIVE },
- { &cg_viewsize, "cg_viewsize", "100", CVAR_ARCHIVE },
- { &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE },
- { &cg_gibs, "cg_gibs", "1", CVAR_ARCHIVE },
- { &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE },
- { &cg_drawStatus, "cg_drawStatus", "1", CVAR_ARCHIVE },
- { &cg_drawTimer, "cg_drawTimer", "0", CVAR_ARCHIVE },
- { &cg_drawFPS, "cg_drawFPS", "0", CVAR_ARCHIVE },
- { &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE },
- { &cg_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE },
- { &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE },
- { &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE },
- { &cg_drawAttacker, "cg_drawAttacker", "1", CVAR_ARCHIVE },
- { &cg_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
- { &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
- { &cg_drawRewards, "cg_drawRewards", "1", CVAR_ARCHIVE },
- { &cg_crosshairSize, "cg_crosshairSize", "24", CVAR_ARCHIVE },
- { &cg_crosshairHealth, "cg_crosshairHealth", "1", CVAR_ARCHIVE },
- { &cg_crosshairX, "cg_crosshairX", "0", CVAR_ARCHIVE },
- { &cg_crosshairY, "cg_crosshairY", "0", CVAR_ARCHIVE },
- { &cg_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
- { &cg_simpleItems, "cg_simpleItems", "0", CVAR_ARCHIVE },
- { &cg_addMarks, "cg_marks", "1", CVAR_ARCHIVE },
- { &cg_lagometer, "cg_lagometer", "1", CVAR_ARCHIVE },
- { &cg_railTrailTime, "cg_railTrailTime", "400", CVAR_ARCHIVE },
- { &cg_gun_x, "cg_gunX", "0", CVAR_CHEAT },
- { &cg_gun_y, "cg_gunY", "0", CVAR_CHEAT },
- { &cg_gun_z, "cg_gunZ", "0", CVAR_CHEAT },
- { &cg_centertime, "cg_centertime", "3", CVAR_CHEAT },
- { &cg_runpitch, "cg_runpitch", "0.002", CVAR_ARCHIVE},
- { &cg_runroll, "cg_runroll", "0.005", CVAR_ARCHIVE },
- { &cg_bobup , "cg_bobup", "0.005", CVAR_CHEAT },
- { &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE },
- { &cg_bobroll, "cg_bobroll", "0.002", CVAR_ARCHIVE },
- { &cg_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT },
- { &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT },
- { &cg_debugAnim, "cg_debuganim", "0", CVAR_CHEAT },
- { &cg_debugPosition, "cg_debugposition", "0", CVAR_CHEAT },
- { &cg_debugEvents, "cg_debugevents", "0", CVAR_CHEAT },
- { &cg_errorDecay, "cg_errordecay", "100", 0 },
- { &cg_nopredict, "cg_nopredict", "0", 0 },
- { &cg_noPlayerAnims, "cg_noplayeranims", "0", CVAR_CHEAT },
- { &cg_showmiss, "cg_showmiss", "0", 0 },
- { &cg_footsteps, "cg_footsteps", "1", CVAR_CHEAT },
- { &cg_tracerChance, "cg_tracerchance", "0.4", CVAR_CHEAT },
- { &cg_tracerWidth, "cg_tracerwidth", "1", CVAR_CHEAT },
- { &cg_tracerLength, "cg_tracerlength", "100", CVAR_CHEAT },
- { &cg_thirdPersonRange, "cg_thirdPersonRange", "40", CVAR_CHEAT },
- { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", CVAR_CHEAT },
- { &cg_thirdPerson, "cg_thirdPerson", "0", 0 },
- { &cg_teamChatTime, "cg_teamChatTime", "3000", CVAR_ARCHIVE },
- { &cg_teamChatHeight, "cg_teamChatHeight", "0", CVAR_ARCHIVE },
- { &cg_forceModel, "cg_forceModel", "0", CVAR_ARCHIVE },
- { &cg_predictItems, "cg_predictItems", "1", CVAR_ARCHIVE },
-#ifdef MISSIONPACK
- { &cg_deferPlayers, "cg_deferPlayers", "0", CVAR_ARCHIVE },
-#else
- { &cg_deferPlayers, "cg_deferPlayers", "1", CVAR_ARCHIVE },
-#endif
- { &cg_drawTeamOverlay, "cg_drawTeamOverlay", "0", CVAR_ARCHIVE },
- { &cg_teamOverlayUserinfo, "teamoverlay", "0", CVAR_ROM | CVAR_USERINFO },
- { &cg_stats, "cg_stats", "0", 0 },
- { &cg_drawFriend, "cg_drawFriend", "1", CVAR_ARCHIVE },
- { &cg_teamChatsOnly, "cg_teamChatsOnly", "0", CVAR_ARCHIVE },
- { &cg_noVoiceChats, "cg_noVoiceChats", "0", CVAR_ARCHIVE },
- { &cg_noVoiceText, "cg_noVoiceText", "0", CVAR_ARCHIVE },
- // the following variables are created in other parts of the system,
- // but we also reference them here
- { &cg_buildScript, "com_buildScript", "0", 0 }, // force loading of all possible data amd error on failures
- { &cg_paused, "cl_paused", "0", CVAR_ROM },
- { &cg_blood, "com_blood", "1", CVAR_ARCHIVE },
- { &cg_synchronousClients, "g_synchronousClients", "0", 0 }, // communicated by systeminfo
-#ifdef MISSIONPACK
- { &cg_redTeamName, "g_redteam", DEFAULT_REDTEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO },
- { &cg_blueTeamName, "g_blueteam", DEFAULT_BLUETEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO },
- { &cg_currentSelectedPlayer, "cg_currentSelectedPlayer", "0", CVAR_ARCHIVE},
- { &cg_currentSelectedPlayerName, "cg_currentSelectedPlayerName", "", CVAR_ARCHIVE},
- { &cg_singlePlayer, "ui_singlePlayerActive", "0", CVAR_USERINFO},
- { &cg_enableDust, "g_enableDust", "0", CVAR_SERVERINFO},
- { &cg_enableBreath, "g_enableBreath", "0", CVAR_SERVERINFO},
- { &cg_singlePlayerActive, "ui_singlePlayerActive", "0", CVAR_USERINFO},
- { &cg_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE},
- { &cg_recordSPDemoName, "ui_recordSPDemoName", "", CVAR_ARCHIVE},
- { &cg_obeliskRespawnDelay, "g_obeliskRespawnDelay", "10", CVAR_SERVERINFO},
- { &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
-#endif
- { &cg_cameraOrbit, "cg_cameraOrbit", "0", CVAR_CHEAT},
- { &cg_cameraOrbitDelay, "cg_cameraOrbitDelay", "50", CVAR_ARCHIVE},
- { &cg_timescaleFadeEnd, "cg_timescaleFadeEnd", "1", 0},
- { &cg_timescaleFadeSpeed, "cg_timescaleFadeSpeed", "0", 0},
- { &cg_timescale, "timescale", "1", 0},
- { &cg_scorePlum, "cg_scorePlums", "1", CVAR_USERINFO | CVAR_ARCHIVE},
- { &cg_smoothClients, "cg_smoothClients", "0", CVAR_USERINFO | CVAR_ARCHIVE},
- { &cg_cameraMode, "com_cameraMode", "0", CVAR_CHEAT},
-
- { &pmove_fixed, "pmove_fixed", "0", 0},
- { &pmove_msec, "pmove_msec", "8", 0},
- { &cg_noTaunt, "cg_noTaunt", "0", CVAR_ARCHIVE},
- { &cg_noProjectileTrail, "cg_noProjectileTrail", "0", CVAR_ARCHIVE},
- { &cg_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE},
- { &cg_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE},
- { &cg_oldRail, "cg_oldRail", "1", CVAR_ARCHIVE},
- { &cg_oldRocket, "cg_oldRocket", "1", CVAR_ARCHIVE},
- { &cg_oldPlasma, "cg_oldPlasma", "1", CVAR_ARCHIVE},
- { &cg_trueLightning, "cg_trueLightning", "0.0", CVAR_ARCHIVE}
-// { &cg_pmove_fixed, "cg_pmove_fixed", "0", CVAR_USERINFO | CVAR_ARCHIVE }
-};
-
-static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] );
-
-/*
-=================
-CG_RegisterCvars
-=================
-*/
-void CG_RegisterCvars( void ) {
- int i;
- cvarTable_t *cv;
- char var[MAX_TOKEN_CHARS];
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Register( cv->vmCvar, cv->cvarName,
- cv->defaultString, cv->cvarFlags );
- }
-
- // see if we are also running the server on this machine
- trap_Cvar_VariableStringBuffer( "sv_running", var, sizeof( var ) );
- cgs.localServer = atoi( var );
-
- forceModelModificationCount = cg_forceModel.modificationCount;
-
- trap_Cvar_Register(NULL, "model", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
- trap_Cvar_Register(NULL, "headmodel", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
- trap_Cvar_Register(NULL, "team_model", DEFAULT_TEAM_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
- trap_Cvar_Register(NULL, "team_headmodel", DEFAULT_TEAM_HEAD, CVAR_USERINFO | CVAR_ARCHIVE );
-}
-
-/*
-===================
-CG_ForceModelChange
-===================
-*/
-static void CG_ForceModelChange( void ) {
- int i;
-
- for (i=0 ; i<MAX_CLIENTS ; i++) {
- const char *clientInfo;
-
- clientInfo = CG_ConfigString( CS_PLAYERS+i );
- if ( !clientInfo[0] ) {
- continue;
- }
- CG_NewClientInfo( i );
- }
-}
-
-/*
-=================
-CG_UpdateCvars
-=================
-*/
-void CG_UpdateCvars( void ) {
- int i;
- cvarTable_t *cv;
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Update( cv->vmCvar );
- }
-
- // check for modications here
-
- // If team overlay is on, ask for updates from the server. If its off,
- // let the server know so we don't receive it
- if ( drawTeamOverlayModificationCount != cg_drawTeamOverlay.modificationCount ) {
- drawTeamOverlayModificationCount = cg_drawTeamOverlay.modificationCount;
-
- if ( cg_drawTeamOverlay.integer > 0 ) {
- trap_Cvar_Set( "teamoverlay", "1" );
- } else {
- trap_Cvar_Set( "teamoverlay", "0" );
- }
- }
-
- // if force model changed
- if ( forceModelModificationCount != cg_forceModel.modificationCount ) {
- forceModelModificationCount = cg_forceModel.modificationCount;
- CG_ForceModelChange();
- }
-}
-
-int CG_CrosshairPlayer( void ) {
- if ( cg.time > ( cg.crosshairClientTime + 1000 ) ) {
- return -1;
- }
- return cg.crosshairClientNum;
-}
-
-int CG_LastAttacker( void ) {
- if ( !cg.attackerTime ) {
- return -1;
- }
- return cg.snap->ps.persistant[PERS_ATTACKER];
-}
-
-void QDECL CG_Printf( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- Q_vsnprintf (text, sizeof(text), msg, argptr);
- va_end (argptr);
-
- trap_Print( text );
-}
-
-void QDECL CG_Error( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- Q_vsnprintf (text, sizeof(text), msg, argptr);
- va_end (argptr);
-
- trap_Error( text );
-}
-
-void QDECL Com_Error( int level, const char *error, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, error);
- Q_vsnprintf (text, sizeof(text), error, argptr);
- va_end (argptr);
-
- CG_Error( "%s", text);
-}
-
-void QDECL Com_Printf( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- Q_vsnprintf (text, sizeof(text), msg, argptr);
- va_end (argptr);
-
- CG_Printf ("%s", text);
-}
-
-/*
-================
-CG_Argv
-================
-*/
-const char *CG_Argv( int arg ) {
- static char buffer[MAX_STRING_CHARS];
-
- trap_Argv( arg, buffer, sizeof( buffer ) );
-
- return buffer;
-}
-
-
-//========================================================================
-
-/*
-=================
-CG_RegisterItemSounds
-
-The server says this item is used on this level
-=================
-*/
-static void CG_RegisterItemSounds( int itemNum ) {
- gitem_t *item;
- char data[MAX_QPATH];
- char *s, *start;
- int len;
-
- item = &bg_itemlist[ itemNum ];
-
- if( item->pickup_sound ) {
- trap_S_RegisterSound( item->pickup_sound, qfalse );
- }
-
- // parse the space seperated precache string for other media
- s = item->sounds;
- if (!s || !s[0])
- return;
-
- while (*s) {
- start = s;
- while (*s && *s != ' ') {
- s++;
- }
-
- len = s-start;
- if (len >= MAX_QPATH || len < 5) {
- CG_Error( "PrecacheItem: %s has bad precache string",
- item->classname);
- return;
- }
- memcpy (data, start, len);
- data[len] = 0;
- if ( *s ) {
- s++;
- }
-
- if ( !strcmp(data+len-3, "wav" )) {
- trap_S_RegisterSound( data, qfalse );
- }
- }
-}
-
-
-/*
-=================
-CG_RegisterSounds
-
-called during a precache command
-=================
-*/
-static void CG_RegisterSounds( void ) {
- int i;
- char items[MAX_ITEMS+1];
- char name[MAX_QPATH];
- const char *soundName;
-
- // voice commands
-#ifdef MISSIONPACK
- CG_LoadVoiceChats();
-#endif
-
- cgs.media.oneMinuteSound = trap_S_RegisterSound( "sound/feedback/1_minute.wav", qtrue );
- cgs.media.fiveMinuteSound = trap_S_RegisterSound( "sound/feedback/5_minute.wav", qtrue );
- cgs.media.suddenDeathSound = trap_S_RegisterSound( "sound/feedback/sudden_death.wav", qtrue );
- cgs.media.oneFragSound = trap_S_RegisterSound( "sound/feedback/1_frag.wav", qtrue );
- cgs.media.twoFragSound = trap_S_RegisterSound( "sound/feedback/2_frags.wav", qtrue );
- cgs.media.threeFragSound = trap_S_RegisterSound( "sound/feedback/3_frags.wav", qtrue );
- cgs.media.count3Sound = trap_S_RegisterSound( "sound/feedback/three.wav", qtrue );
- cgs.media.count2Sound = trap_S_RegisterSound( "sound/feedback/two.wav", qtrue );
- cgs.media.count1Sound = trap_S_RegisterSound( "sound/feedback/one.wav", qtrue );
- cgs.media.countFightSound = trap_S_RegisterSound( "sound/feedback/fight.wav", qtrue );
- cgs.media.countPrepareSound = trap_S_RegisterSound( "sound/feedback/prepare.wav", qtrue );
-#ifdef MISSIONPACK
- cgs.media.countPrepareTeamSound = trap_S_RegisterSound( "sound/feedback/prepare_team.wav", qtrue );
-#endif
-
- if ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) {
-
- cgs.media.captureAwardSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qtrue );
- cgs.media.redLeadsSound = trap_S_RegisterSound( "sound/feedback/redleads.wav", qtrue );
- cgs.media.blueLeadsSound = trap_S_RegisterSound( "sound/feedback/blueleads.wav", qtrue );
- cgs.media.teamsTiedSound = trap_S_RegisterSound( "sound/feedback/teamstied.wav", qtrue );
- cgs.media.hitTeamSound = trap_S_RegisterSound( "sound/feedback/hit_teammate.wav", qtrue );
-
- cgs.media.redScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_red_scores.wav", qtrue );
- cgs.media.blueScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_scores.wav", qtrue );
-
- cgs.media.captureYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qtrue );
- cgs.media.captureOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_opponent.wav", qtrue );
-
- cgs.media.returnYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_yourteam.wav", qtrue );
- cgs.media.returnOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue );
-
- cgs.media.takenYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_yourteam.wav", qtrue );
- cgs.media.takenOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_opponent.wav", qtrue );
-
- if ( cgs.gametype == GT_CTF || cg_buildScript.integer ) {
- cgs.media.redFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_red_returned.wav", qtrue );
- cgs.media.blueFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_returned.wav", qtrue );
- cgs.media.enemyTookYourFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_flag.wav", qtrue );
- cgs.media.yourTeamTookEnemyFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_flag.wav", qtrue );
- }
-
-#ifdef MISSIONPACK
- if ( cgs.gametype == GT_1FCTF || cg_buildScript.integer ) {
- // FIXME: get a replacement for this sound ?
- cgs.media.neutralFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue );
- cgs.media.yourTeamTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_1flag.wav", qtrue );
- cgs.media.enemyTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_1flag.wav", qtrue );
- }
-
- if ( cgs.gametype == GT_1FCTF || cgs.gametype == GT_CTF || cg_buildScript.integer ) {
- cgs.media.youHaveFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_you_flag.wav", qtrue );
- cgs.media.holyShitSound = trap_S_RegisterSound("sound/feedback/voc_holyshit.wav", qtrue);
- }
-
- if ( cgs.gametype == GT_OBELISK || cg_buildScript.integer ) {
- cgs.media.yourBaseIsUnderAttackSound = trap_S_RegisterSound( "sound/teamplay/voc_base_attack.wav", qtrue );
- }
-#else
- cgs.media.youHaveFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_you_flag.wav", qtrue );
- cgs.media.holyShitSound = trap_S_RegisterSound("sound/feedback/voc_holyshit.wav", qtrue);
- cgs.media.neutralFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue );
- cgs.media.yourTeamTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_1flag.wav", qtrue );
- cgs.media.enemyTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_1flag.wav", qtrue );
-#endif
- }
-
- cgs.media.tracerSound = trap_S_RegisterSound( "sound/weapons/machinegun/buletby1.wav", qfalse );
- cgs.media.selectSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse );
- cgs.media.wearOffSound = trap_S_RegisterSound( "sound/items/wearoff.wav", qfalse );
- cgs.media.useNothingSound = trap_S_RegisterSound( "sound/items/use_nothing.wav", qfalse );
- cgs.media.gibSound = trap_S_RegisterSound( "sound/player/gibsplt1.wav", qfalse );
- cgs.media.gibBounce1Sound = trap_S_RegisterSound( "sound/player/gibimp1.wav", qfalse );
- cgs.media.gibBounce2Sound = trap_S_RegisterSound( "sound/player/gibimp2.wav", qfalse );
- cgs.media.gibBounce3Sound = trap_S_RegisterSound( "sound/player/gibimp3.wav", qfalse );
-
-#ifdef MISSIONPACK
- cgs.media.useInvulnerabilitySound = trap_S_RegisterSound( "sound/items/invul_activate.wav", qfalse );
- cgs.media.invulnerabilityImpactSound1 = trap_S_RegisterSound( "sound/items/invul_impact_01.wav", qfalse );
- cgs.media.invulnerabilityImpactSound2 = trap_S_RegisterSound( "sound/items/invul_impact_02.wav", qfalse );
- cgs.media.invulnerabilityImpactSound3 = trap_S_RegisterSound( "sound/items/invul_impact_03.wav", qfalse );
- cgs.media.invulnerabilityJuicedSound = trap_S_RegisterSound( "sound/items/invul_juiced.wav", qfalse );
- cgs.media.obeliskHitSound1 = trap_S_RegisterSound( "sound/items/obelisk_hit_01.wav", qfalse );
- cgs.media.obeliskHitSound2 = trap_S_RegisterSound( "sound/items/obelisk_hit_02.wav", qfalse );
- cgs.media.obeliskHitSound3 = trap_S_RegisterSound( "sound/items/obelisk_hit_03.wav", qfalse );
- cgs.media.obeliskRespawnSound = trap_S_RegisterSound( "sound/items/obelisk_respawn.wav", qfalse );
-
- cgs.media.ammoregenSound = trap_S_RegisterSound("sound/items/cl_ammoregen.wav", qfalse);
- cgs.media.doublerSound = trap_S_RegisterSound("sound/items/cl_doubler.wav", qfalse);
- cgs.media.guardSound = trap_S_RegisterSound("sound/items/cl_guard.wav", qfalse);
- cgs.media.scoutSound = trap_S_RegisterSound("sound/items/cl_scout.wav", qfalse);
-#endif
-
- cgs.media.teleInSound = trap_S_RegisterSound( "sound/world/telein.wav", qfalse );
- cgs.media.teleOutSound = trap_S_RegisterSound( "sound/world/teleout.wav", qfalse );
- cgs.media.respawnSound = trap_S_RegisterSound( "sound/items/respawn1.wav", qfalse );
-
- cgs.media.noAmmoSound = trap_S_RegisterSound( "sound/weapons/noammo.wav", qfalse );
-
- cgs.media.talkSound = trap_S_RegisterSound( "sound/player/talk.wav", qfalse );
- cgs.media.landSound = trap_S_RegisterSound( "sound/player/land1.wav", qfalse);
-
- cgs.media.hitSound = trap_S_RegisterSound( "sound/feedback/hit.wav", qfalse );
-#ifdef MISSIONPACK
- cgs.media.hitSoundHighArmor = trap_S_RegisterSound( "sound/feedback/hithi.wav", qfalse );
- cgs.media.hitSoundLowArmor = trap_S_RegisterSound( "sound/feedback/hitlo.wav", qfalse );
-#endif
-
- cgs.media.impressiveSound = trap_S_RegisterSound( "sound/feedback/impressive.wav", qtrue );
- cgs.media.excellentSound = trap_S_RegisterSound( "sound/feedback/excellent.wav", qtrue );
- cgs.media.deniedSound = trap_S_RegisterSound( "sound/feedback/denied.wav", qtrue );
- cgs.media.humiliationSound = trap_S_RegisterSound( "sound/feedback/humiliation.wav", qtrue );
- cgs.media.assistSound = trap_S_RegisterSound( "sound/feedback/assist.wav", qtrue );
- cgs.media.defendSound = trap_S_RegisterSound( "sound/feedback/defense.wav", qtrue );
-#ifdef MISSIONPACK
- cgs.media.firstImpressiveSound = trap_S_RegisterSound( "sound/feedback/first_impressive.wav", qtrue );
- cgs.media.firstExcellentSound = trap_S_RegisterSound( "sound/feedback/first_excellent.wav", qtrue );
- cgs.media.firstHumiliationSound = trap_S_RegisterSound( "sound/feedback/first_gauntlet.wav", qtrue );
-#endif
-
- cgs.media.takenLeadSound = trap_S_RegisterSound( "sound/feedback/takenlead.wav", qtrue);
- cgs.media.tiedLeadSound = trap_S_RegisterSound( "sound/feedback/tiedlead.wav", qtrue);
- cgs.media.lostLeadSound = trap_S_RegisterSound( "sound/feedback/lostlead.wav", qtrue);
-
-#ifdef MISSIONPACK
- cgs.media.voteNow = trap_S_RegisterSound( "sound/feedback/vote_now.wav", qtrue);
- cgs.media.votePassed = trap_S_RegisterSound( "sound/feedback/vote_passed.wav", qtrue);
- cgs.media.voteFailed = trap_S_RegisterSound( "sound/feedback/vote_failed.wav", qtrue);
-#endif
-
- cgs.media.watrInSound = trap_S_RegisterSound( "sound/player/watr_in.wav", qfalse);
- cgs.media.watrOutSound = trap_S_RegisterSound( "sound/player/watr_out.wav", qfalse);
- cgs.media.watrUnSound = trap_S_RegisterSound( "sound/player/watr_un.wav", qfalse);
-
- cgs.media.jumpPadSound = trap_S_RegisterSound ("sound/world/jumppad.wav", qfalse );
-
- for (i=0 ; i<4 ; i++) {
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/step%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_NORMAL][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/boot%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_BOOT][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/flesh%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_FLESH][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/mech%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_MECH][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/energy%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_ENERGY][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/splash%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_SPLASH][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/clank%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_METAL][i] = trap_S_RegisterSound (name, qfalse);
- }
-
- // only register the items that the server says we need
- Q_strncpyz(items, CG_ConfigString(CS_ITEMS), sizeof(items));
-
- for ( i = 1 ; i < bg_numItems ; i++ ) {
-// if ( items[ i ] == '1' || cg_buildScript.integer ) {
- CG_RegisterItemSounds( i );
-// }
- }
-
- for ( i = 1 ; i < MAX_SOUNDS ; i++ ) {
- soundName = CG_ConfigString( CS_SOUNDS+i );
- if ( !soundName[0] ) {
- break;
- }
- if ( soundName[0] == '*' ) {
- continue; // custom sound
- }
- cgs.gameSounds[i] = trap_S_RegisterSound( soundName, qfalse );
- }
-
- // FIXME: only needed with item
- cgs.media.flightSound = trap_S_RegisterSound( "sound/items/flight.wav", qfalse );
- cgs.media.medkitSound = trap_S_RegisterSound ("sound/items/use_medkit.wav", qfalse);
- cgs.media.quadSound = trap_S_RegisterSound("sound/items/damage3.wav", qfalse);
- cgs.media.sfx_ric1 = trap_S_RegisterSound ("sound/weapons/machinegun/ric1.wav", qfalse);
- cgs.media.sfx_ric2 = trap_S_RegisterSound ("sound/weapons/machinegun/ric2.wav", qfalse);
- cgs.media.sfx_ric3 = trap_S_RegisterSound ("sound/weapons/machinegun/ric3.wav", qfalse);
- cgs.media.sfx_railg = trap_S_RegisterSound ("sound/weapons/railgun/railgf1a.wav", qfalse);
- cgs.media.sfx_rockexp = trap_S_RegisterSound ("sound/weapons/rocket/rocklx1a.wav", qfalse);
- cgs.media.sfx_plasmaexp = trap_S_RegisterSound ("sound/weapons/plasma/plasmx1a.wav", qfalse);
-#ifdef MISSIONPACK
- cgs.media.sfx_proxexp = trap_S_RegisterSound( "sound/weapons/proxmine/wstbexpl.wav" , qfalse);
- cgs.media.sfx_nghit = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpd.wav" , qfalse);
- cgs.media.sfx_nghitflesh = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpl.wav" , qfalse);
- cgs.media.sfx_nghitmetal = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpm.wav", qfalse );
- cgs.media.sfx_chghit = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpd.wav", qfalse );
- cgs.media.sfx_chghitflesh = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpl.wav", qfalse );
- cgs.media.sfx_chghitmetal = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpm.wav", qfalse );
- cgs.media.weaponHoverSound = trap_S_RegisterSound( "sound/weapons/weapon_hover.wav", qfalse );
- cgs.media.kamikazeExplodeSound = trap_S_RegisterSound( "sound/items/kam_explode.wav", qfalse );
- cgs.media.kamikazeImplodeSound = trap_S_RegisterSound( "sound/items/kam_implode.wav", qfalse );
- cgs.media.kamikazeFarSound = trap_S_RegisterSound( "sound/items/kam_explode_far.wav", qfalse );
- cgs.media.winnerSound = trap_S_RegisterSound( "sound/feedback/voc_youwin.wav", qfalse );
- cgs.media.loserSound = trap_S_RegisterSound( "sound/feedback/voc_youlose.wav", qfalse );
- cgs.media.youSuckSound = trap_S_RegisterSound( "sound/misc/yousuck.wav", qfalse );
-
- cgs.media.wstbimplSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpl.wav", qfalse);
- cgs.media.wstbimpmSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpm.wav", qfalse);
- cgs.media.wstbimpdSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpd.wav", qfalse);
- cgs.media.wstbactvSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbactv.wav", qfalse);
-#endif
-
- cgs.media.regenSound = trap_S_RegisterSound("sound/items/regen.wav", qfalse);
- cgs.media.protectSound = trap_S_RegisterSound("sound/items/protect3.wav", qfalse);
- cgs.media.n_healthSound = trap_S_RegisterSound("sound/items/n_health.wav", qfalse );
- cgs.media.hgrenb1aSound = trap_S_RegisterSound("sound/weapons/grenade/hgrenb1a.wav", qfalse);
- cgs.media.hgrenb2aSound = trap_S_RegisterSound("sound/weapons/grenade/hgrenb2a.wav", qfalse);
-
-#ifdef MISSIONPACK
- trap_S_RegisterSound("sound/player/james/death1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/death2.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/death3.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/jump1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/pain25_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/pain75_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/pain100_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/falling1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/gasp.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/drown.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/fall1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/taunt.wav", qfalse );
-
- trap_S_RegisterSound("sound/player/janet/death1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/death2.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/death3.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/jump1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/pain25_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/pain75_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/pain100_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/falling1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/gasp.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/drown.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/fall1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/taunt.wav", qfalse );
-#endif
-
-}
-
-
-//===================================================================================
-
-
-/*
-=================
-CG_RegisterGraphics
-
-This function may execute for a couple of minutes with a slow disk.
-=================
-*/
-static void CG_RegisterGraphics( void ) {
- int i;
- char items[MAX_ITEMS+1];
- static char *sb_nums[11] = {
- "gfx/2d/numbers/zero_32b",
- "gfx/2d/numbers/one_32b",
- "gfx/2d/numbers/two_32b",
- "gfx/2d/numbers/three_32b",
- "gfx/2d/numbers/four_32b",
- "gfx/2d/numbers/five_32b",
- "gfx/2d/numbers/six_32b",
- "gfx/2d/numbers/seven_32b",
- "gfx/2d/numbers/eight_32b",
- "gfx/2d/numbers/nine_32b",
- "gfx/2d/numbers/minus_32b",
- };
-
- // clear any references to old media
- memset( &cg.refdef, 0, sizeof( cg.refdef ) );
- trap_R_ClearScene();
-
- CG_LoadingString( cgs.mapname );
-
- trap_R_LoadWorldMap( cgs.mapname );
-
- // precache status bar pics
- CG_LoadingString( "game media" );
-
- for ( i=0 ; i<11 ; i++) {
- cgs.media.numberShaders[i] = trap_R_RegisterShader( sb_nums[i] );
- }
-
- cgs.media.botSkillShaders[0] = trap_R_RegisterShader( "menu/art/skill1.tga" );
- cgs.media.botSkillShaders[1] = trap_R_RegisterShader( "menu/art/skill2.tga" );
- cgs.media.botSkillShaders[2] = trap_R_RegisterShader( "menu/art/skill3.tga" );
- cgs.media.botSkillShaders[3] = trap_R_RegisterShader( "menu/art/skill4.tga" );
- cgs.media.botSkillShaders[4] = trap_R_RegisterShader( "menu/art/skill5.tga" );
-
- cgs.media.viewBloodShader = trap_R_RegisterShader( "viewBloodBlend" );
-
- cgs.media.deferShader = trap_R_RegisterShaderNoMip( "gfx/2d/defer.tga" );
-
- cgs.media.scoreboardName = trap_R_RegisterShaderNoMip( "menu/tab/name.tga" );
- cgs.media.scoreboardPing = trap_R_RegisterShaderNoMip( "menu/tab/ping.tga" );
- cgs.media.scoreboardScore = trap_R_RegisterShaderNoMip( "menu/tab/score.tga" );
- cgs.media.scoreboardTime = trap_R_RegisterShaderNoMip( "menu/tab/time.tga" );
-
- cgs.media.smokePuffShader = trap_R_RegisterShader( "smokePuff" );
- cgs.media.smokePuffRageProShader = trap_R_RegisterShader( "smokePuffRagePro" );
- cgs.media.shotgunSmokePuffShader = trap_R_RegisterShader( "shotgunSmokePuff" );
-#ifdef MISSIONPACK
- cgs.media.nailPuffShader = trap_R_RegisterShader( "nailtrail" );
- cgs.media.blueProxMine = trap_R_RegisterModel( "models/weaphits/proxmineb.md3" );
-#endif
- cgs.media.plasmaBallShader = trap_R_RegisterShader( "sprites/plasma1" );
- cgs.media.bloodTrailShader = trap_R_RegisterShader( "bloodTrail" );
- cgs.media.lagometerShader = trap_R_RegisterShader("lagometer" );
- cgs.media.connectionShader = trap_R_RegisterShader( "disconnected" );
-
- cgs.media.waterBubbleShader = trap_R_RegisterShader( "waterBubble" );
-
- cgs.media.tracerShader = trap_R_RegisterShader( "gfx/misc/tracer" );
- cgs.media.selectShader = trap_R_RegisterShader( "gfx/2d/select" );
-
- for ( i = 0 ; i < NUM_CROSSHAIRS ; i++ ) {
- cgs.media.crosshairShader[i] = trap_R_RegisterShader( va("gfx/2d/crosshair%c", 'a'+i) );
- }
-
- cgs.media.backTileShader = trap_R_RegisterShader( "gfx/2d/backtile" );
- cgs.media.noammoShader = trap_R_RegisterShader( "icons/noammo" );
-
- // powerup shaders
- cgs.media.quadShader = trap_R_RegisterShader("powerups/quad" );
- cgs.media.quadWeaponShader = trap_R_RegisterShader("powerups/quadWeapon" );
- cgs.media.battleSuitShader = trap_R_RegisterShader("powerups/battleSuit" );
- cgs.media.battleWeaponShader = trap_R_RegisterShader("powerups/battleWeapon" );
- cgs.media.invisShader = trap_R_RegisterShader("powerups/invisibility" );
- cgs.media.regenShader = trap_R_RegisterShader("powerups/regen" );
- cgs.media.hastePuffShader = trap_R_RegisterShader("hasteSmokePuff" );
-
-#ifdef MISSIONPACK
- if ( cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF || cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
-#else
- if ( cgs.gametype == GT_CTF || cg_buildScript.integer ) {
-#endif
- cgs.media.redCubeModel = trap_R_RegisterModel( "models/powerups/orb/r_orb.md3" );
- cgs.media.blueCubeModel = trap_R_RegisterModel( "models/powerups/orb/b_orb.md3" );
- cgs.media.redCubeIcon = trap_R_RegisterShader( "icons/skull_red" );
- cgs.media.blueCubeIcon = trap_R_RegisterShader( "icons/skull_blue" );
- }
-
-#ifdef MISSIONPACK
- if ( cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF || cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
-#else
- if ( cgs.gametype == GT_CTF || cg_buildScript.integer ) {
-#endif
- cgs.media.redFlagModel = trap_R_RegisterModel( "models/flags/r_flag.md3" );
- cgs.media.blueFlagModel = trap_R_RegisterModel( "models/flags/b_flag.md3" );
- cgs.media.redFlagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_red1" );
- cgs.media.redFlagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_red2" );
- cgs.media.redFlagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_red3" );
- cgs.media.blueFlagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_blu1" );
- cgs.media.blueFlagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_blu2" );
- cgs.media.blueFlagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_blu3" );
-#ifdef MISSIONPACK
- cgs.media.flagPoleModel = trap_R_RegisterModel( "models/flag2/flagpole.md3" );
- cgs.media.flagFlapModel = trap_R_RegisterModel( "models/flag2/flagflap3.md3" );
-
- cgs.media.redFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/red.skin" );
- cgs.media.blueFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/blue.skin" );
- cgs.media.neutralFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/white.skin" );
-
- cgs.media.redFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/red_base.md3" );
- cgs.media.blueFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/blue_base.md3" );
- cgs.media.neutralFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/ntrl_base.md3" );
-#endif
- }
-
-#ifdef MISSIONPACK
- if ( cgs.gametype == GT_1FCTF || cg_buildScript.integer ) {
- cgs.media.neutralFlagModel = trap_R_RegisterModel( "models/flags/n_flag.md3" );
- cgs.media.flagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_neutral1" );
- cgs.media.flagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_red2" );
- cgs.media.flagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_blu2" );
- cgs.media.flagShader[3] = trap_R_RegisterShaderNoMip( "icons/iconf_neutral3" );
- }
-
- if ( cgs.gametype == GT_OBELISK || cg_buildScript.integer ) {
- cgs.media.overloadBaseModel = trap_R_RegisterModel( "models/powerups/overload_base.md3" );
- cgs.media.overloadTargetModel = trap_R_RegisterModel( "models/powerups/overload_target.md3" );
- cgs.media.overloadLightsModel = trap_R_RegisterModel( "models/powerups/overload_lights.md3" );
- cgs.media.overloadEnergyModel = trap_R_RegisterModel( "models/powerups/overload_energy.md3" );
- }
-
- if ( cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
- cgs.media.harvesterModel = trap_R_RegisterModel( "models/powerups/harvester/harvester.md3" );
- cgs.media.harvesterRedSkin = trap_R_RegisterSkin( "models/powerups/harvester/red.skin" );
- cgs.media.harvesterBlueSkin = trap_R_RegisterSkin( "models/powerups/harvester/blue.skin" );
- cgs.media.harvesterNeutralModel = trap_R_RegisterModel( "models/powerups/obelisk/obelisk.md3" );
- }
-
- cgs.media.redKamikazeShader = trap_R_RegisterShader( "models/weaphits/kamikred" );
- cgs.media.dustPuffShader = trap_R_RegisterShader("hasteSmokePuff" );
-#endif
-
- if ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) {
- cgs.media.friendShader = trap_R_RegisterShader( "sprites/foe" );
- cgs.media.redQuadShader = trap_R_RegisterShader("powerups/blueflag" );
- cgs.media.teamStatusBar = trap_R_RegisterShader( "gfx/2d/colorbar.tga" );
-#ifdef MISSIONPACK
- cgs.media.blueKamikazeShader = trap_R_RegisterShader( "models/weaphits/kamikblu" );
-#endif
- }
-
- cgs.media.armorModel = trap_R_RegisterModel( "models/powerups/armor/armor_yel.md3" );
- cgs.media.armorIcon = trap_R_RegisterShaderNoMip( "icons/iconr_yellow" );
-
- cgs.media.machinegunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/m_shell.md3" );
- cgs.media.shotgunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/s_shell.md3" );
-
- cgs.media.gibAbdomen = trap_R_RegisterModel( "models/gibs/abdomen.md3" );
- cgs.media.gibArm = trap_R_RegisterModel( "models/gibs/arm.md3" );
- cgs.media.gibChest = trap_R_RegisterModel( "models/gibs/chest.md3" );
- cgs.media.gibFist = trap_R_RegisterModel( "models/gibs/fist.md3" );
- cgs.media.gibFoot = trap_R_RegisterModel( "models/gibs/foot.md3" );
- cgs.media.gibForearm = trap_R_RegisterModel( "models/gibs/forearm.md3" );
- cgs.media.gibIntestine = trap_R_RegisterModel( "models/gibs/intestine.md3" );
- cgs.media.gibLeg = trap_R_RegisterModel( "models/gibs/leg.md3" );
- cgs.media.gibSkull = trap_R_RegisterModel( "models/gibs/skull.md3" );
- cgs.media.gibBrain = trap_R_RegisterModel( "models/gibs/brain.md3" );
-
- cgs.media.smoke2 = trap_R_RegisterModel( "models/weapons2/shells/s_shell.md3" );
-
- cgs.media.balloonShader = trap_R_RegisterShader( "sprites/balloon3" );
-
- cgs.media.bloodExplosionShader = trap_R_RegisterShader( "bloodExplosion" );
-
- cgs.media.bulletFlashModel = trap_R_RegisterModel("models/weaphits/bullet.md3");
- cgs.media.ringFlashModel = trap_R_RegisterModel("models/weaphits/ring02.md3");
- cgs.media.dishFlashModel = trap_R_RegisterModel("models/weaphits/boom01.md3");
-#ifdef MISSIONPACK
- cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/powerups/pop.md3" );
-#else
- cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/misc/telep.md3" );
- cgs.media.teleportEffectShader = trap_R_RegisterShader( "teleportEffect" );
-#endif
-#ifdef MISSIONPACK
- cgs.media.kamikazeEffectModel = trap_R_RegisterModel( "models/weaphits/kamboom2.md3" );
- cgs.media.kamikazeShockWave = trap_R_RegisterModel( "models/weaphits/kamwave.md3" );
- cgs.media.kamikazeHeadModel = trap_R_RegisterModel( "models/powerups/kamikazi.md3" );
- cgs.media.kamikazeHeadTrail = trap_R_RegisterModel( "models/powerups/trailtest.md3" );
- cgs.media.guardPowerupModel = trap_R_RegisterModel( "models/powerups/guard_player.md3" );
- cgs.media.scoutPowerupModel = trap_R_RegisterModel( "models/powerups/scout_player.md3" );
- cgs.media.doublerPowerupModel = trap_R_RegisterModel( "models/powerups/doubler_player.md3" );
- cgs.media.ammoRegenPowerupModel = trap_R_RegisterModel( "models/powerups/ammo_player.md3" );
- cgs.media.invulnerabilityImpactModel = trap_R_RegisterModel( "models/powerups/shield/impact.md3" );
- cgs.media.invulnerabilityJuicedModel = trap_R_RegisterModel( "models/powerups/shield/juicer.md3" );
- cgs.media.medkitUsageModel = trap_R_RegisterModel( "models/powerups/regen.md3" );
- cgs.media.heartShader = trap_R_RegisterShaderNoMip( "ui/assets/statusbar/selectedhealth.tga" );
-
-#endif
-
- cgs.media.invulnerabilityPowerupModel = trap_R_RegisterModel( "models/powerups/shield/shield.md3" );
- cgs.media.medalImpressive = trap_R_RegisterShaderNoMip( "medal_impressive" );
- cgs.media.medalExcellent = trap_R_RegisterShaderNoMip( "medal_excellent" );
- cgs.media.medalGauntlet = trap_R_RegisterShaderNoMip( "medal_gauntlet" );
- cgs.media.medalDefend = trap_R_RegisterShaderNoMip( "medal_defend" );
- cgs.media.medalAssist = trap_R_RegisterShaderNoMip( "medal_assist" );
- cgs.media.medalCapture = trap_R_RegisterShaderNoMip( "medal_capture" );
-
-
- memset( cg_items, 0, sizeof( cg_items ) );
- memset( cg_weapons, 0, sizeof( cg_weapons ) );
-
- // only register the items that the server says we need
- Q_strncpyz(items, CG_ConfigString(CS_ITEMS), sizeof(items));
-
- for ( i = 1 ; i < bg_numItems ; i++ ) {
- if ( items[ i ] == '1' || cg_buildScript.integer ) {
- CG_LoadingItem( i );
- CG_RegisterItemVisuals( i );
- }
- }
-
- // wall marks
- cgs.media.bulletMarkShader = trap_R_RegisterShader( "gfx/damage/bullet_mrk" );
- cgs.media.burnMarkShader = trap_R_RegisterShader( "gfx/damage/burn_med_mrk" );
- cgs.media.holeMarkShader = trap_R_RegisterShader( "gfx/damage/hole_lg_mrk" );
- cgs.media.energyMarkShader = trap_R_RegisterShader( "gfx/damage/plasma_mrk" );
- cgs.media.shadowMarkShader = trap_R_RegisterShader( "markShadow" );
- cgs.media.wakeMarkShader = trap_R_RegisterShader( "wake" );
- cgs.media.bloodMarkShader = trap_R_RegisterShader( "bloodMark" );
-
- // register the inline models
- cgs.numInlineModels = trap_CM_NumInlineModels();
- for ( i = 1 ; i < cgs.numInlineModels ; i++ ) {
- char name[10];
- vec3_t mins, maxs;
- int j;
-
- Com_sprintf( name, sizeof(name), "*%i", i );
- cgs.inlineDrawModel[i] = trap_R_RegisterModel( name );
- trap_R_ModelBounds( cgs.inlineDrawModel[i], mins, maxs );
- for ( j = 0 ; j < 3 ; j++ ) {
- cgs.inlineModelMidpoints[i][j] = mins[j] + 0.5 * ( maxs[j] - mins[j] );
- }
- }
-
- // register all the server specified models
- for (i=1 ; i<MAX_MODELS ; i++) {
- const char *modelName;
-
- modelName = CG_ConfigString( CS_MODELS+i );
- if ( !modelName[0] ) {
- break;
- }
- cgs.gameModels[i] = trap_R_RegisterModel( modelName );
- }
-
-#ifdef MISSIONPACK
- // new stuff
- cgs.media.patrolShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/patrol.tga");
- cgs.media.assaultShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/assault.tga");
- cgs.media.campShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/camp.tga");
- cgs.media.followShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/follow.tga");
- cgs.media.defendShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/defend.tga");
- cgs.media.teamLeaderShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/team_leader.tga");
- cgs.media.retrieveShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/retrieve.tga");
- cgs.media.escortShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/escort.tga");
- cgs.media.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
- cgs.media.sizeCursor = trap_R_RegisterShaderNoMip( "ui/assets/sizecursor.tga" );
- cgs.media.selectCursor = trap_R_RegisterShaderNoMip( "ui/assets/selectcursor.tga" );
- cgs.media.flagShaders[0] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_in_base.tga");
- cgs.media.flagShaders[1] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_capture.tga");
- cgs.media.flagShaders[2] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_missing.tga");
-
- trap_R_RegisterModel( "models/players/james/lower.md3" );
- trap_R_RegisterModel( "models/players/james/upper.md3" );
- trap_R_RegisterModel( "models/players/heads/james/james.md3" );
-
- trap_R_RegisterModel( "models/players/janet/lower.md3" );
- trap_R_RegisterModel( "models/players/janet/upper.md3" );
- trap_R_RegisterModel( "models/players/heads/janet/janet.md3" );
-
-#endif
- CG_ClearParticles ();
-/*
- for (i=1; i<MAX_PARTICLES_AREAS; i++)
- {
- {
- int rval;
-
- rval = CG_NewParticleArea ( CS_PARTICLES + i);
- if (!rval)
- break;
- }
- }
-*/
-}
-
-
-
-/*
-=======================
-CG_BuildSpectatorString
-
-=======================
-*/
-void CG_BuildSpectatorString(void) {
- int i;
- cg.spectatorList[0] = 0;
- for (i = 0; i < MAX_CLIENTS; i++) {
- if (cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_SPECTATOR ) {
- Q_strcat(cg.spectatorList, sizeof(cg.spectatorList), va("%s ", cgs.clientinfo[i].name));
- }
- }
- i = strlen(cg.spectatorList);
- if (i != cg.spectatorLen) {
- cg.spectatorLen = i;
- cg.spectatorWidth = -1;
- }
-}
-
-
-/*
-===================
-CG_RegisterClients
-===================
-*/
-static void CG_RegisterClients( void ) {
- int i;
-
- CG_LoadingClient(cg.clientNum);
- CG_NewClientInfo(cg.clientNum);
-
- for (i=0 ; i<MAX_CLIENTS ; i++) {
- const char *clientInfo;
-
- if (cg.clientNum == i) {
- continue;
- }
-
- clientInfo = CG_ConfigString( CS_PLAYERS+i );
- if ( !clientInfo[0]) {
- continue;
- }
- CG_LoadingClient( i );
- CG_NewClientInfo( i );
- }
- CG_BuildSpectatorString();
-}
-
-//===========================================================================
-
-/*
-=================
-CG_ConfigString
-=================
-*/
-const char *CG_ConfigString( int index ) {
- if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
- CG_Error( "CG_ConfigString: bad index: %i", index );
- }
- return cgs.gameState.stringData + cgs.gameState.stringOffsets[ index ];
-}
-
-//==================================================================
-
-/*
-======================
-CG_StartMusic
-
-======================
-*/
-void CG_StartMusic( void ) {
- char *s;
- char parm1[MAX_QPATH], parm2[MAX_QPATH];
-
- // start the background music
- s = (char *)CG_ConfigString( CS_MUSIC );
- Q_strncpyz( parm1, COM_Parse( &s ), sizeof( parm1 ) );
- Q_strncpyz( parm2, COM_Parse( &s ), sizeof( parm2 ) );
-
- trap_S_StartBackgroundTrack( parm1, parm2 );
-}
-#ifdef MISSIONPACK
-char *CG_GetMenuBuffer(const char *filename) {
- int len;
- fileHandle_t f;
- static char buf[MAX_MENUFILE];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
- return NULL;
- }
- if ( len >= MAX_MENUFILE ) {
- trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", filename, len, MAX_MENUFILE ) );
- trap_FS_FCloseFile( f );
- return NULL;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- return buf;
-}
-
-//
-// ==============================
-// new hud stuff ( mission pack )
-// ==============================
-//
-qboolean CG_Asset_Parse(int handle) {
- pc_token_t token;
- const char *tempStr;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (Q_stricmp(token.string, "{") != 0) {
- return qfalse;
- }
-
- while ( 1 ) {
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
-
- if (Q_stricmp(token.string, "}") == 0) {
- return qtrue;
- }
-
- // font
- if (Q_stricmp(token.string, "font") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
- return qfalse;
- }
- cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.textFont);
- continue;
- }
-
- // smallFont
- if (Q_stricmp(token.string, "smallFont") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
- return qfalse;
- }
- cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.smallFont);
- continue;
- }
-
- // font
- if (Q_stricmp(token.string, "bigfont") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
- return qfalse;
- }
- cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.bigFont);
- continue;
- }
-
- // gradientbar
- if (Q_stricmp(token.string, "gradientbar") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
- continue;
- }
-
- // enterMenuSound
- if (Q_stricmp(token.string, "menuEnterSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // exitMenuSound
- if (Q_stricmp(token.string, "menuExitSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // itemFocusSound
- if (Q_stricmp(token.string, "itemFocusSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // menuBuzzSound
- if (Q_stricmp(token.string, "menuBuzzSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- if (Q_stricmp(token.string, "cursor") == 0) {
- if (!PC_String_Parse(handle, &cgDC.Assets.cursorStr)) {
- return qfalse;
- }
- cgDC.Assets.cursor = trap_R_RegisterShaderNoMip( cgDC.Assets.cursorStr);
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeClamp") == 0) {
- if (!PC_Float_Parse(handle, &cgDC.Assets.fadeClamp)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeCycle") == 0) {
- if (!PC_Int_Parse(handle, &cgDC.Assets.fadeCycle)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeAmount") == 0) {
- if (!PC_Float_Parse(handle, &cgDC.Assets.fadeAmount)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowX") == 0) {
- if (!PC_Float_Parse(handle, &cgDC.Assets.shadowX)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowY") == 0) {
- if (!PC_Float_Parse(handle, &cgDC.Assets.shadowY)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowColor") == 0) {
- if (!PC_Color_Parse(handle, &cgDC.Assets.shadowColor)) {
- return qfalse;
- }
- cgDC.Assets.shadowFadeClamp = cgDC.Assets.shadowColor[3];
- continue;
- }
- }
- return qfalse;
-}
-
-void CG_ParseMenu(const char *menuFile) {
- pc_token_t token;
- int handle;
-
- handle = trap_PC_LoadSource(menuFile);
- if (!handle)
- handle = trap_PC_LoadSource("ui/testhud.menu");
- if (!handle)
- return;
-
- while ( 1 ) {
- if (!trap_PC_ReadToken( handle, &token )) {
- break;
- }
-
- //if ( Q_stricmp( token, "{" ) ) {
- // Com_Printf( "Missing { in menu file\n" );
- // break;
- //}
-
- //if ( menuCount == MAX_MENUS ) {
- // Com_Printf( "Too many menus!\n" );
- // break;
- //}
-
- if ( token.string[0] == '}' ) {
- break;
- }
-
- if (Q_stricmp(token.string, "assetGlobalDef") == 0) {
- if (CG_Asset_Parse(handle)) {
- continue;
- } else {
- break;
- }
- }
-
-
- if (Q_stricmp(token.string, "menudef") == 0) {
- // start a new menu
- Menu_New(handle);
- }
- }
- trap_PC_FreeSource(handle);
-}
-
-qboolean CG_Load_Menu(char **p) {
- char *token;
-
- token = COM_ParseExt(p, qtrue);
-
- if (token[0] != '{') {
- return qfalse;
- }
-
- while ( 1 ) {
-
- token = COM_ParseExt(p, qtrue);
-
- if (Q_stricmp(token, "}") == 0) {
- return qtrue;
- }
-
- if ( !token || token[0] == 0 ) {
- return qfalse;
- }
-
- CG_ParseMenu(token);
- }
- return qfalse;
-}
-
-
-
-void CG_LoadMenus(const char *menuFile) {
- char *token;
- char *p;
- int len, start;
- fileHandle_t f;
- static char buf[MAX_MENUDEFFILE];
-
- start = trap_Milliseconds();
-
- len = trap_FS_FOpenFile( menuFile, &f, FS_READ );
- if ( !f ) {
- trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );
- len = trap_FS_FOpenFile( "ui/hud.txt", &f, FS_READ );
- if (!f) {
- trap_Error( va( S_COLOR_RED "default menu file not found: ui/hud.txt, unable to continue!\n") );
- }
- }
-
- if ( len >= MAX_MENUDEFFILE ) {
- trap_Error( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", menuFile, len, MAX_MENUDEFFILE ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- COM_Compress(buf);
-
- Menu_Reset();
-
- p = buf;
-
- while ( 1 ) {
- token = COM_ParseExt( &p, qtrue );
- if( !token || token[0] == 0 || token[0] == '}') {
- break;
- }
-
- //if ( Q_stricmp( token, "{" ) ) {
- // Com_Printf( "Missing { in menu file\n" );
- // break;
- //}
-
- //if ( menuCount == MAX_MENUS ) {
- // Com_Printf( "Too many menus!\n" );
- // break;
- //}
-
- if ( Q_stricmp( token, "}" ) == 0 ) {
- break;
- }
-
- if (Q_stricmp(token, "loadmenu") == 0) {
- if (CG_Load_Menu(&p)) {
- continue;
- } else {
- break;
- }
- }
- }
-
- Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start);
-
-}
-
-
-
-static qboolean CG_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) {
- return qfalse;
-}
-
-
-static int CG_FeederCount(float feederID) {
- int i, count;
- count = 0;
- if (feederID == FEEDER_REDTEAM_LIST) {
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == TEAM_RED) {
- count++;
- }
- }
- } else if (feederID == FEEDER_BLUETEAM_LIST) {
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == TEAM_BLUE) {
- count++;
- }
- }
- } else if (feederID == FEEDER_SCOREBOARD) {
- return cg.numScores;
- }
- return count;
-}
-
-
-void CG_SetScoreSelection(void *p) {
- menuDef_t *menu = (menuDef_t*)p;
- playerState_t *ps = &cg.snap->ps;
- int i, red, blue;
- red = blue = 0;
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == TEAM_RED) {
- red++;
- } else if (cg.scores[i].team == TEAM_BLUE) {
- blue++;
- }
- if (ps->clientNum == cg.scores[i].client) {
- cg.selectedScore = i;
- }
- }
-
- if (menu == NULL) {
- // just interested in setting the selected score
- return;
- }
-
- if ( cgs.gametype >= GT_TEAM ) {
- int feeder = FEEDER_REDTEAM_LIST;
- i = red;
- if (cg.scores[cg.selectedScore].team == TEAM_BLUE) {
- feeder = FEEDER_BLUETEAM_LIST;
- i = blue;
- }
- Menu_SetFeederSelection(menu, feeder, i, NULL);
- } else {
- Menu_SetFeederSelection(menu, FEEDER_SCOREBOARD, cg.selectedScore, NULL);
- }
-}
-
-// FIXME: might need to cache this info
-static clientInfo_t * CG_InfoFromScoreIndex(int index, int team, int *scoreIndex) {
- int i, count;
- if ( cgs.gametype >= GT_TEAM ) {
- count = 0;
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == team) {
- if (count == index) {
- *scoreIndex = i;
- return &cgs.clientinfo[cg.scores[i].client];
- }
- count++;
- }
- }
- }
- *scoreIndex = index;
- return &cgs.clientinfo[ cg.scores[index].client ];
-}
-
-static const char *CG_FeederItemText(float feederID, int index, int column, qhandle_t *handle) {
- gitem_t *item;
- int scoreIndex = 0;
- clientInfo_t *info = NULL;
- int team = -1;
- score_t *sp = NULL;
-
- *handle = -1;
-
- if (feederID == FEEDER_REDTEAM_LIST) {
- team = TEAM_RED;
- } else if (feederID == FEEDER_BLUETEAM_LIST) {
- team = TEAM_BLUE;
- }
-
- info = CG_InfoFromScoreIndex(index, team, &scoreIndex);
- sp = &cg.scores[scoreIndex];
-
- if (info && info->infoValid) {
- switch (column) {
- case 0:
- if ( info->powerups & ( 1 << PW_NEUTRALFLAG ) ) {
- item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
- *handle = cg_items[ ITEM_INDEX(item) ].icon;
- } else if ( info->powerups & ( 1 << PW_REDFLAG ) ) {
- item = BG_FindItemForPowerup( PW_REDFLAG );
- *handle = cg_items[ ITEM_INDEX(item) ].icon;
- } else if ( info->powerups & ( 1 << PW_BLUEFLAG ) ) {
- item = BG_FindItemForPowerup( PW_BLUEFLAG );
- *handle = cg_items[ ITEM_INDEX(item) ].icon;
- } else {
- if ( info->botSkill > 0 && info->botSkill <= 5 ) {
- *handle = cgs.media.botSkillShaders[ info->botSkill - 1 ];
- } else if ( info->handicap < 100 ) {
- return va("%i", info->handicap );
- }
- }
- break;
- case 1:
- if (team == -1) {
- return "";
- } else {
- *handle = CG_StatusHandle(info->teamTask);
- }
- break;
- case 2:
- if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << sp->client ) ) {
- return "Ready";
- }
- if (team == -1) {
- if (cgs.gametype == GT_TOURNAMENT) {
- return va("%i/%i", info->wins, info->losses);
- } else if (info->infoValid && info->team == TEAM_SPECTATOR ) {
- return "Spectator";
- } else {
- return "";
- }
- } else {
- if (info->teamLeader) {
- return "Leader";
- }
- }
- break;
- case 3:
- return info->name;
- break;
- case 4:
- return va("%i", info->score);
- break;
- case 5:
- return va("%4i", sp->time);
- break;
- case 6:
- if ( sp->ping == -1 ) {
- return "connecting";
- }
- return va("%4i", sp->ping);
- break;
- }
- }
-
- return "";
-}
-
-static qhandle_t CG_FeederItemImage(float feederID, int index) {
- return 0;
-}
-
-static void CG_FeederSelection(float feederID, int index) {
- if ( cgs.gametype >= GT_TEAM ) {
- int i, count;
- int team = (feederID == FEEDER_REDTEAM_LIST) ? TEAM_RED : TEAM_BLUE;
- count = 0;
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == team) {
- if (index == count) {
- cg.selectedScore = i;
- }
- count++;
- }
- }
- } else {
- cg.selectedScore = index;
- }
-}
-#endif
-
-#ifdef MISSIONPACK
-static float CG_Cvar_Get(const char *cvar) {
- char buff[128];
- memset(buff, 0, sizeof(buff));
- trap_Cvar_VariableStringBuffer(cvar, buff, sizeof(buff));
- return atof(buff);
-}
-#endif
-
-#ifdef MISSIONPACK
-void CG_Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) {
- CG_Text_Paint(x, y, scale, color, text, 0, limit, style);
-}
-
-static int CG_OwnerDrawWidth(int ownerDraw, float scale) {
- switch (ownerDraw) {
- case CG_GAME_TYPE:
- return CG_Text_Width(CG_GameTypeString(), scale, 0);
- case CG_GAME_STATUS:
- return CG_Text_Width(CG_GetGameStatusText(), scale, 0);
- break;
- case CG_KILLER:
- return CG_Text_Width(CG_GetKillerText(), scale, 0);
- break;
- case CG_RED_NAME:
- return CG_Text_Width(cg_redTeamName.string, scale, 0);
- break;
- case CG_BLUE_NAME:
- return CG_Text_Width(cg_blueTeamName.string, scale, 0);
- break;
-
-
- }
- return 0;
-}
-
-static int CG_PlayCinematic(const char *name, float x, float y, float w, float h) {
- return trap_CIN_PlayCinematic(name, x, y, w, h, CIN_loop);
-}
-
-static void CG_StopCinematic(int handle) {
- trap_CIN_StopCinematic(handle);
-}
-
-static void CG_DrawCinematic(int handle, float x, float y, float w, float h) {
- trap_CIN_SetExtents(handle, x, y, w, h);
- trap_CIN_DrawCinematic(handle);
-}
-
-static void CG_RunCinematicFrame(int handle) {
- trap_CIN_RunCinematic(handle);
-}
-
-/*
-=================
-CG_LoadHudMenu();
-
-=================
-*/
-void CG_LoadHudMenu( void ) {
- char buff[1024];
- const char *hudSet;
-
- cgDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
- cgDC.setColor = &trap_R_SetColor;
- cgDC.drawHandlePic = &CG_DrawPic;
- cgDC.drawStretchPic = &trap_R_DrawStretchPic;
- cgDC.drawText = &CG_Text_Paint;
- cgDC.textWidth = &CG_Text_Width;
- cgDC.textHeight = &CG_Text_Height;
- cgDC.registerModel = &trap_R_RegisterModel;
- cgDC.modelBounds = &trap_R_ModelBounds;
- cgDC.fillRect = &CG_FillRect;
- cgDC.drawRect = &CG_DrawRect;
- cgDC.drawSides = &CG_DrawSides;
- cgDC.drawTopBottom = &CG_DrawTopBottom;
- cgDC.clearScene = &trap_R_ClearScene;
- cgDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
- cgDC.renderScene = &trap_R_RenderScene;
- cgDC.registerFont = &trap_R_RegisterFont;
- cgDC.ownerDrawItem = &CG_OwnerDraw;
- cgDC.getValue = &CG_GetValue;
- cgDC.ownerDrawVisible = &CG_OwnerDrawVisible;
- cgDC.runScript = &CG_RunMenuScript;
- cgDC.getTeamColor = &CG_GetTeamColor;
- cgDC.setCVar = trap_Cvar_Set;
- cgDC.getCVarString = trap_Cvar_VariableStringBuffer;
- cgDC.getCVarValue = CG_Cvar_Get;
- cgDC.drawTextWithCursor = &CG_Text_PaintWithCursor;
- //cgDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
- //cgDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
- cgDC.startLocalSound = &trap_S_StartLocalSound;
- cgDC.ownerDrawHandleKey = &CG_OwnerDrawHandleKey;
- cgDC.feederCount = &CG_FeederCount;
- cgDC.feederItemImage = &CG_FeederItemImage;
- cgDC.feederItemText = &CG_FeederItemText;
- cgDC.feederSelection = &CG_FeederSelection;
- //cgDC.setBinding = &trap_Key_SetBinding;
- //cgDC.getBindingBuf = &trap_Key_GetBindingBuf;
- //cgDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
- //cgDC.executeText = &trap_Cmd_ExecuteText;
- cgDC.Error = &Com_Error;
- cgDC.Print = &Com_Printf;
- cgDC.ownerDrawWidth = &CG_OwnerDrawWidth;
- //cgDC.Pause = &CG_Pause;
- cgDC.registerSound = &trap_S_RegisterSound;
- cgDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
- cgDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
- cgDC.playCinematic = &CG_PlayCinematic;
- cgDC.stopCinematic = &CG_StopCinematic;
- cgDC.drawCinematic = &CG_DrawCinematic;
- cgDC.runCinematicFrame = &CG_RunCinematicFrame;
-
- Init_Display(&cgDC);
-
- Menu_Reset();
-
- trap_Cvar_VariableStringBuffer("cg_hudFiles", buff, sizeof(buff));
- hudSet = buff;
- if (hudSet[0] == '\0') {
- hudSet = "ui/hud.txt";
- }
-
- CG_LoadMenus(hudSet);
-}
-
-void CG_AssetCache( void ) {
- //if (Assets.textFont == NULL) {
- // trap_R_RegisterFont("fonts/arial.ttf", 72, &Assets.textFont);
- //}
- //Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND );
- //Com_Printf("Menu Size: %i bytes\n", sizeof(Menus));
- cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
- cgDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
- cgDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
- cgDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
- cgDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
- cgDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
- cgDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
- cgDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
- cgDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
- cgDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
- cgDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
- cgDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
- cgDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
- cgDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
- cgDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
- cgDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
- cgDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
-}
-#endif
-/*
-=================
-CG_Init
-
-Called after every level change or subsystem restart
-Will perform callbacks to make the loading info screen update.
-=================
-*/
-void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) {
- const char *s;
-
- // clear everything
- memset( &cgs, 0, sizeof( cgs ) );
- memset( &cg, 0, sizeof( cg ) );
- memset( cg_entities, 0, sizeof(cg_entities) );
- memset( cg_weapons, 0, sizeof(cg_weapons) );
- memset( cg_items, 0, sizeof(cg_items) );
-
- cg.clientNum = clientNum;
-
- cgs.processedSnapshotNum = serverMessageNum;
- cgs.serverCommandSequence = serverCommandSequence;
-
- // load a few needed things before we do any screen updates
- cgs.media.charsetShader = trap_R_RegisterShader( "gfx/2d/bigchars" );
- cgs.media.whiteShader = trap_R_RegisterShader( "white" );
- cgs.media.charsetProp = trap_R_RegisterShaderNoMip( "menu/art/font1_prop.tga" );
- cgs.media.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" );
- cgs.media.charsetPropB = trap_R_RegisterShaderNoMip( "menu/art/font2_prop.tga" );
-
- CG_RegisterCvars();
-
- CG_InitConsoleCommands();
-
- cg.weaponSelect = WP_MACHINEGUN;
-
- cgs.redflag = cgs.blueflag = -1; // For compatibily, default to unset for
- cgs.flagStatus = -1;
- // old servers
-
- // get the rendering configuration from the client system
- trap_GetGlconfig( &cgs.glconfig );
- cgs.screenXScale = cgs.glconfig.vidWidth / 640.0;
- cgs.screenYScale = cgs.glconfig.vidHeight / 480.0;
-
- // get the gamestate from the client system
- trap_GetGameState( &cgs.gameState );
-
- // check version
- s = CG_ConfigString( CS_GAME_VERSION );
- if ( strcmp( s, GAME_VERSION ) ) {
- CG_Error( "Client/Server game mismatch: %s/%s", GAME_VERSION, s );
- }
-
- s = CG_ConfigString( CS_LEVEL_START_TIME );
- cgs.levelStartTime = atoi( s );
-
- CG_ParseServerinfo();
-
- // load the new map
- CG_LoadingString( "collision map" );
-
- trap_CM_LoadMap( cgs.mapname );
-
-#ifdef MISSIONPACK
- String_Init();
-#endif
-
- cg.loading = qtrue; // force players to load instead of defer
-
- CG_LoadingString( "sounds" );
-
- CG_RegisterSounds();
-
- CG_LoadingString( "graphics" );
-
- CG_RegisterGraphics();
-
- CG_LoadingString( "clients" );
-
- CG_RegisterClients(); // if low on memory, some clients will be deferred
-
-#ifdef MISSIONPACK
- CG_AssetCache();
- CG_LoadHudMenu(); // load new hud stuff
-#endif
-
- cg.loading = qfalse; // future players will be deferred
-
- CG_InitLocalEntities();
-
- CG_InitMarkPolys();
-
- // remove the last loading update
- cg.infoScreenText[0] = 0;
-
- // Make sure we have update values (scores)
- CG_SetConfigValues();
-
- CG_StartMusic();
-
- CG_LoadingString( "" );
-
-#ifdef MISSIONPACK
- CG_InitTeamChat();
-#endif
-
- CG_ShaderStateChanged();
-
- trap_S_ClearLoopingSounds( qtrue );
-}
-
-/*
-=================
-CG_Shutdown
-
-Called before every level change or subsystem restart
-=================
-*/
-void CG_Shutdown( void ) {
- // some mods may need to do cleanup work here,
- // like closing files or archiving session data
-}
-
-
-/*
-==================
-CG_EventHandling
-==================
- type 0 - no event handling
- 1 - team menu
- 2 - hud editor
-
-*/
-#ifndef MISSIONPACK
-void CG_EventHandling(int type) {
-}
-
-
-
-void CG_KeyEvent(int key, qboolean down) {
-}
-
-void CG_MouseEvent(int x, int y) {
-}
-#endif
-
diff --git a/engine/code/cgame/cg_marks.c b/engine/code/cgame/cg_marks.c
deleted file mode 100644
index 71f74b1..0000000
--- a/engine/code/cgame/cg_marks.c
+++ /dev/null
@@ -1,2274 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_marks.c -- wall marks
-
-#include "cg_local.h"
-
-/*
-===================================================================
-
-MARK POLYS
-
-===================================================================
-*/
-
-
-markPoly_t cg_activeMarkPolys; // double linked list
-markPoly_t *cg_freeMarkPolys; // single linked list
-markPoly_t cg_markPolys[MAX_MARK_POLYS];
-static int markTotal;
-
-/*
-===================
-CG_InitMarkPolys
-
-This is called at startup and for tournement restarts
-===================
-*/
-void CG_InitMarkPolys( void ) {
- int i;
-
- memset( cg_markPolys, 0, sizeof(cg_markPolys) );
-
- cg_activeMarkPolys.nextMark = &cg_activeMarkPolys;
- cg_activeMarkPolys.prevMark = &cg_activeMarkPolys;
- cg_freeMarkPolys = cg_markPolys;
- for ( i = 0 ; i < MAX_MARK_POLYS - 1 ; i++ ) {
- cg_markPolys[i].nextMark = &cg_markPolys[i+1];
- }
-}
-
-
-/*
-==================
-CG_FreeMarkPoly
-==================
-*/
-void CG_FreeMarkPoly( markPoly_t *le ) {
- if ( !le->prevMark ) {
- CG_Error( "CG_FreeLocalEntity: not active" );
- }
-
- // remove from the doubly linked active list
- le->prevMark->nextMark = le->nextMark;
- le->nextMark->prevMark = le->prevMark;
-
- // the free list is only singly linked
- le->nextMark = cg_freeMarkPolys;
- cg_freeMarkPolys = le;
-}
-
-/*
-===================
-CG_AllocMark
-
-Will allways succeed, even if it requires freeing an old active mark
-===================
-*/
-markPoly_t *CG_AllocMark( void ) {
- markPoly_t *le;
- int time;
-
- if ( !cg_freeMarkPolys ) {
- // no free entities, so free the one at the end of the chain
- // remove the oldest active entity
- time = cg_activeMarkPolys.prevMark->time;
- while (cg_activeMarkPolys.prevMark && time == cg_activeMarkPolys.prevMark->time) {
- CG_FreeMarkPoly( cg_activeMarkPolys.prevMark );
- }
- }
-
- le = cg_freeMarkPolys;
- cg_freeMarkPolys = cg_freeMarkPolys->nextMark;
-
- memset( le, 0, sizeof( *le ) );
-
- // link into the active list
- le->nextMark = cg_activeMarkPolys.nextMark;
- le->prevMark = &cg_activeMarkPolys;
- cg_activeMarkPolys.nextMark->prevMark = le;
- cg_activeMarkPolys.nextMark = le;
- return le;
-}
-
-
-
-/*
-=================
-CG_ImpactMark
-
-origin should be a point within a unit of the plane
-dir should be the plane normal
-
-temporary marks will not be stored or randomly oriented, but immediately
-passed to the renderer.
-=================
-*/
-#define MAX_MARK_FRAGMENTS 128
-#define MAX_MARK_POINTS 384
-
-void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir,
- float orientation, float red, float green, float blue, float alpha,
- qboolean alphaFade, float radius, qboolean temporary ) {
- vec3_t axis[3];
- float texCoordScale;
- vec3_t originalPoints[4];
- byte colors[4];
- int i, j;
- int numFragments;
- markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf;
- vec3_t markPoints[MAX_MARK_POINTS];
- vec3_t projection;
-
- if ( !cg_addMarks.integer ) {
- return;
- }
-
- if ( radius <= 0 ) {
- CG_Error( "CG_ImpactMark called with <= 0 radius" );
- }
-
- //if ( markTotal >= MAX_MARK_POLYS ) {
- // return;
- //}
-
- // create the texture axis
- VectorNormalize2( dir, axis[0] );
- PerpendicularVector( axis[1], axis[0] );
- RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
- CrossProduct( axis[0], axis[2], axis[1] );
-
- texCoordScale = 0.5 * 1.0 / radius;
-
- // create the full polygon
- for ( i = 0 ; i < 3 ; i++ ) {
- originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
- originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
- originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
- originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
- }
-
- // get the fragments
- VectorScale( dir, -20, projection );
- numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints,
- projection, MAX_MARK_POINTS, markPoints[0],
- MAX_MARK_FRAGMENTS, markFragments );
-
- colors[0] = red * 255;
- colors[1] = green * 255;
- colors[2] = blue * 255;
- colors[3] = alpha * 255;
-
- for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
- polyVert_t *v;
- polyVert_t verts[MAX_VERTS_ON_POLY];
- markPoly_t *mark;
-
- // we have an upper limit on the complexity of polygons
- // that we store persistantly
- if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
- mf->numPoints = MAX_VERTS_ON_POLY;
- }
- for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
- vec3_t delta;
-
- VectorCopy( markPoints[mf->firstPoint + j], v->xyz );
-
- VectorSubtract( v->xyz, origin, delta );
- v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
- v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
- *(int *)v->modulate = *(int *)colors;
- }
-
- // if it is a temporary (shadow) mark, add it immediately and forget about it
- if ( temporary ) {
- trap_R_AddPolyToScene( markShader, mf->numPoints, verts );
- continue;
- }
-
- // otherwise save it persistantly
- mark = CG_AllocMark();
- mark->time = cg.time;
- mark->alphaFade = alphaFade;
- mark->markShader = markShader;
- mark->poly.numVerts = mf->numPoints;
- mark->color[0] = red;
- mark->color[1] = green;
- mark->color[2] = blue;
- mark->color[3] = alpha;
- memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
- markTotal++;
- }
-}
-
-
-/*
-===============
-CG_AddMarks
-===============
-*/
-#define MARK_TOTAL_TIME 10000
-#define MARK_FADE_TIME 1000
-
-void CG_AddMarks( void ) {
- int j;
- markPoly_t *mp, *next;
- int t;
- int fade;
-
- if ( !cg_addMarks.integer ) {
- return;
- }
-
- mp = cg_activeMarkPolys.nextMark;
- for ( ; mp != &cg_activeMarkPolys ; mp = next ) {
- // grab next now, so if the local entity is freed we
- // still have it
- next = mp->nextMark;
-
- // see if it is time to completely remove it
- if ( cg.time > mp->time + MARK_TOTAL_TIME ) {
- CG_FreeMarkPoly( mp );
- continue;
- }
-
- // fade out the energy bursts
- if ( mp->markShader == cgs.media.energyMarkShader ) {
-
- fade = 450 - 450 * ( (cg.time - mp->time ) / 3000.0 );
- if ( fade < 255 ) {
- if ( fade < 0 ) {
- fade = 0;
- }
- if ( mp->verts[0].modulate[0] != 0 ) {
- for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
- mp->verts[j].modulate[0] = mp->color[0] * fade;
- mp->verts[j].modulate[1] = mp->color[1] * fade;
- mp->verts[j].modulate[2] = mp->color[2] * fade;
- }
- }
- }
- }
-
- // fade all marks out with time
- t = mp->time + MARK_TOTAL_TIME - cg.time;
- if ( t < MARK_FADE_TIME ) {
- fade = 255 * t / MARK_FADE_TIME;
- if ( mp->alphaFade ) {
- for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
- mp->verts[j].modulate[3] = fade;
- }
- } else {
- for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
- mp->verts[j].modulate[0] = mp->color[0] * fade;
- mp->verts[j].modulate[1] = mp->color[1] * fade;
- mp->verts[j].modulate[2] = mp->color[2] * fade;
- }
- }
- }
-
-
- trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts );
- }
-}
-
-// cg_particles.c
-
-#define BLOODRED 2
-#define EMISIVEFADE 3
-#define GREY75 4
-
-typedef struct particle_s
-{
- struct particle_s *next;
-
- float time;
- float endtime;
-
- vec3_t org;
- vec3_t vel;
- vec3_t accel;
- int color;
- float colorvel;
- float alpha;
- float alphavel;
- int type;
- qhandle_t pshader;
-
- float height;
- float width;
-
- float endheight;
- float endwidth;
-
- float start;
- float end;
-
- float startfade;
- qboolean rotate;
- int snum;
-
- qboolean link;
-
- // Ridah
- int shaderAnim;
- int roll;
-
- int accumroll;
-
-} cparticle_t;
-
-typedef enum
-{
- P_NONE,
- P_WEATHER,
- P_FLAT,
- P_SMOKE,
- P_ROTATE,
- P_WEATHER_TURBULENT,
- P_ANIM, // Ridah
- P_BAT,
- P_BLEED,
- P_FLAT_SCALEUP,
- P_FLAT_SCALEUP_FADE,
- P_WEATHER_FLURRY,
- P_SMOKE_IMPACT,
- P_BUBBLE,
- P_BUBBLE_TURBULENT,
- P_SPRITE
-} particle_type_t;
-
-#define MAX_SHADER_ANIMS 32
-#define MAX_SHADER_ANIM_FRAMES 64
-
-static char *shaderAnimNames[MAX_SHADER_ANIMS] = {
- "explode1",
- NULL
-};
-static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];
-static int shaderAnimCounts[MAX_SHADER_ANIMS] = {
- 23
-};
-static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = {
- 1.0f
-};
-static int numShaderAnims;
-// done.
-
-#define PARTICLE_GRAVITY 40
-#define MAX_PARTICLES 1024
-
-cparticle_t *active_particles, *free_particles;
-cparticle_t particles[MAX_PARTICLES];
-int cl_numparticles = MAX_PARTICLES;
-
-qboolean initparticles = qfalse;
-vec3_t pvforward, pvright, pvup;
-vec3_t rforward, rright, rup;
-
-float oldtime;
-
-/*
-===============
-CL_ClearParticles
-===============
-*/
-void CG_ClearParticles (void)
-{
- int i;
-
- memset( particles, 0, sizeof(particles) );
-
- free_particles = &particles[0];
- active_particles = NULL;
-
- for (i=0 ;i<cl_numparticles ; i++)
- {
- particles[i].next = &particles[i+1];
- particles[i].type = 0;
- }
- particles[cl_numparticles-1].next = NULL;
-
- oldtime = cg.time;
-
- // Ridah, init the shaderAnims
- for (i=0; shaderAnimNames[i]; i++) {
- int j;
-
- for (j=0; j<shaderAnimCounts[i]; j++) {
- shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) );
- }
- }
- numShaderAnims = i;
- // done.
-
- initparticles = qtrue;
-}
-
-
-/*
-=====================
-CG_AddParticleToScene
-=====================
-*/
-void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)
-{
-
- vec3_t point;
- polyVert_t verts[4];
- float width;
- float height;
- float time, time2;
- float ratio;
- float invratio;
- vec3_t color;
- polyVert_t TRIverts[3];
- vec3_t rright2, rup2;
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY
- || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {// create a front facing polygon
-
- if (p->type != P_WEATHER_FLURRY)
- {
- if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {
- if (org[2] > p->end)
- {
- p->time = cg.time;
- VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
-
- p->org[2] = ( p->start + crandom () * 4 );
-
-
- if (p->type == P_BUBBLE_TURBULENT)
- {
- p->vel[0] = crandom() * 4;
- p->vel[1] = crandom() * 4;
- }
-
- }
- }
- else
- {
- if (org[2] < p->end)
- {
- p->time = cg.time;
- VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
-
- while (p->org[2] < p->end)
- {
- p->org[2] += (p->start - p->end);
- }
-
-
- if (p->type == P_WEATHER_TURBULENT)
- {
- p->vel[0] = crandom() * 16;
- p->vel[1] = crandom() * 16;
- }
-
- }
- }
-
-
- // Rafael snow pvs check
- if (!p->link)
- return;
-
- p->alpha = 1;
- }
-
- // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp
- if (Distance( cg.snap->ps.origin, org ) > 1024) {
- return;
- }
- // done.
-
- if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255 * p->alpha;
- }
- else
- {
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- VectorCopy( point, TRIverts[0].xyz );
- TRIverts[0].st[0] = 1;
- TRIverts[0].st[1] = 0;
- TRIverts[0].modulate[0] = 255;
- TRIverts[0].modulate[1] = 255;
- TRIverts[0].modulate[2] = 255;
- TRIverts[0].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- VectorCopy (point, TRIverts[1].xyz);
- TRIverts[1].st[0] = 0;
- TRIverts[1].st[1] = 0;
- TRIverts[1].modulate[0] = 255;
- TRIverts[1].modulate[1] = 255;
- TRIverts[1].modulate[2] = 255;
- TRIverts[1].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- VectorCopy (point, TRIverts[2].xyz);
- TRIverts[2].st[0] = 0;
- TRIverts[2].st[1] = 1;
- TRIverts[2].modulate[0] = 255;
- TRIverts[2].modulate[1] = 255;
- TRIverts[2].modulate[2] = 255;
- TRIverts[2].modulate[3] = 255 * p->alpha;
- }
-
- }
- else if (p->type == P_SPRITE)
- {
- vec3_t rr, ru;
- vec3_t rotate_ang;
-
- VectorSet (color, 1.0, 1.0, 0.5);
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (p->roll) {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
-
- if (p->roll) {
- VectorMA (org, -height, ru, point);
- VectorMA (point, -width, rr, point);
- } else {
- VectorMA (org, -height, pvup, point);
- VectorMA (point, -width, pvright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*height, ru, point);
- } else {
- VectorMA (point, 2*height, pvup, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*width, rr, point);
- } else {
- VectorMA (point, 2*width, pvright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, -2*height, ru, point);
- } else {
- VectorMA (point, -2*height, pvup, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
- }
- else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)
- {// create a front rotating facing polygon
-
- if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {
- return;
- }
-
- if (p->color == BLOODRED)
- VectorSet (color, 0.22f, 0.0f, 0.0f);
- else if (p->color == GREY75)
- {
- float len;
- float greyit;
- float val;
- len = Distance (cg.snap->ps.origin, org);
- if (!len)
- len = 1;
-
- val = 4096/len;
- greyit = 0.25 * val;
- if (greyit > 0.5)
- greyit = 0.5;
-
- VectorSet (color, greyit, greyit, greyit);
- }
- else
- VectorSet (color, 1.0, 1.0, 1.0);
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- if (cg.time > p->startfade)
- {
- invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );
-
- if (p->color == EMISIVEFADE)
- {
- float fval;
- fval = (invratio * invratio);
- if (fval < 0)
- fval = 0;
- VectorSet (color, fval , fval , fval );
- }
- invratio *= p->alpha;
- }
- else
- invratio = 1 * p->alpha;
-
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
- invratio = 1;
-
- if (invratio > 1)
- invratio = 1;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (p->type != P_SMOKE_IMPACT)
- {
- vec3_t temp;
-
- vectoangles (rforward, temp);
- p->accumroll += p->roll;
- temp[ROLL] += p->accumroll * 0.1;
- AngleVectors ( temp, NULL, rright2, rup2);
- }
- else
- {
- VectorCopy (rright, rright2);
- VectorCopy (rup, rup2);
- }
-
- if (p->rotate)
- {
- VectorMA (org, -height, rup2, point);
- VectorMA (point, -width, rright2, point);
- }
- else
- {
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255 * color[0];
- verts[0].modulate[1] = 255 * color[1];
- verts[0].modulate[2] = 255 * color[2];
- verts[0].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, -height, rup2, point);
- VectorMA (point, width, rright2, point);
- }
- else
- {
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255 * color[0];
- verts[1].modulate[1] = 255 * color[1];
- verts[1].modulate[2] = 255 * color[2];
- verts[1].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, height, rup2, point);
- VectorMA (point, width, rright2, point);
- }
- else
- {
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255 * color[0];
- verts[2].modulate[1] = 255 * color[1];
- verts[2].modulate[2] = 255 * color[2];
- verts[2].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, height, rup2, point);
- VectorMA (point, -width, rright2, point);
- }
- else
- {
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255 * color[0];
- verts[3].modulate[1] = 255 * color[1];
- verts[3].modulate[2] = 255 * color[2];
- verts[3].modulate[3] = 255 * invratio;
-
- }
- else if (p->type == P_BLEED)
- {
- vec3_t rr, ru;
- vec3_t rotate_ang;
- float alpha;
-
- alpha = p->alpha;
-
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
- alpha = 1;
-
- if (p->roll)
- {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
- else
- {
- VectorCopy (pvup, ru);
- VectorCopy (pvright, rr);
- }
-
- VectorMA (org, -p->height, ru, point);
- VectorMA (point, -p->width, rr, point);
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 111;
- verts[0].modulate[1] = 19;
- verts[0].modulate[2] = 9;
- verts[0].modulate[3] = 255 * alpha;
-
- VectorMA (org, -p->height, ru, point);
- VectorMA (point, p->width, rr, point);
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 111;
- verts[1].modulate[1] = 19;
- verts[1].modulate[2] = 9;
- verts[1].modulate[3] = 255 * alpha;
-
- VectorMA (org, p->height, ru, point);
- VectorMA (point, p->width, rr, point);
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 111;
- verts[2].modulate[1] = 19;
- verts[2].modulate[2] = 9;
- verts[2].modulate[3] = 255 * alpha;
-
- VectorMA (org, p->height, ru, point);
- VectorMA (point, -p->width, rr, point);
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 111;
- verts[3].modulate[1] = 19;
- verts[3].modulate[2] = 9;
- verts[3].modulate[3] = 255 * alpha;
-
- }
- else if (p->type == P_FLAT_SCALEUP)
- {
- float width, height;
- float sinR, cosR;
-
- if (p->color == BLOODRED)
- VectorSet (color, 1, 1, 1);
- else
- VectorSet (color, 0.5, 0.5, 0.5);
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (width > p->endwidth)
- width = p->endwidth;
-
- if (height > p->endheight)
- height = p->endheight;
-
- sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);
- cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);
-
- VectorCopy (org, verts[0].xyz);
- verts[0].xyz[0] -= sinR;
- verts[0].xyz[1] -= cosR;
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255 * color[0];
- verts[0].modulate[1] = 255 * color[1];
- verts[0].modulate[2] = 255 * color[2];
- verts[0].modulate[3] = 255;
-
- VectorCopy (org, verts[1].xyz);
- verts[1].xyz[0] -= cosR;
- verts[1].xyz[1] += sinR;
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255 * color[0];
- verts[1].modulate[1] = 255 * color[1];
- verts[1].modulate[2] = 255 * color[2];
- verts[1].modulate[3] = 255;
-
- VectorCopy (org, verts[2].xyz);
- verts[2].xyz[0] += sinR;
- verts[2].xyz[1] += cosR;
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255 * color[0];
- verts[2].modulate[1] = 255 * color[1];
- verts[2].modulate[2] = 255 * color[2];
- verts[2].modulate[3] = 255;
-
- VectorCopy (org, verts[3].xyz);
- verts[3].xyz[0] += cosR;
- verts[3].xyz[1] -= sinR;
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255 * color[0];
- verts[3].modulate[1] = 255 * color[1];
- verts[3].modulate[2] = 255 * color[2];
- verts[3].modulate[3] = 255;
- }
- else if (p->type == P_FLAT)
- {
-
- VectorCopy (org, verts[0].xyz);
- verts[0].xyz[0] -= p->height;
- verts[0].xyz[1] -= p->width;
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- VectorCopy (org, verts[1].xyz);
- verts[1].xyz[0] -= p->height;
- verts[1].xyz[1] += p->width;
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- VectorCopy (org, verts[2].xyz);
- verts[2].xyz[0] += p->height;
- verts[2].xyz[1] += p->width;
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- VectorCopy (org, verts[3].xyz);
- verts[3].xyz[0] += p->height;
- verts[3].xyz[1] -= p->width;
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
-
- }
- // Ridah
- else if (p->type == P_ANIM) {
- vec3_t rr, ru;
- vec3_t rotate_ang;
- int i, j;
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
- if (ratio >= 1.0f) {
- ratio = 0.9999f;
- }
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- // if we are "inside" this sprite, don't draw
- if (Distance( cg.snap->ps.origin, org ) < width/1.5) {
- return;
- }
-
- i = p->shaderAnim;
- j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);
- p->pshader = shaderAnims[i][j];
-
- if (p->roll) {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
-
- if (p->roll) {
- VectorMA (org, -height, ru, point);
- VectorMA (point, -width, rr, point);
- } else {
- VectorMA (org, -height, pvup, point);
- VectorMA (point, -width, pvright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*height, ru, point);
- } else {
- VectorMA (point, 2*height, pvup, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*width, rr, point);
- } else {
- VectorMA (point, 2*width, pvright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, -2*height, ru, point);
- } else {
- VectorMA (point, -2*height, pvup, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
- }
- // done.
-
- if (!p->pshader) {
-// (SA) temp commented out for DM
-// CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type);
- return;
- }
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)
- trap_R_AddPolyToScene( p->pshader, 3, TRIverts );
- else
- trap_R_AddPolyToScene( p->pshader, 4, verts );
-
-}
-
-// Ridah, made this static so it doesn't interfere with other files
-static float roll = 0.0;
-
-/*
-===============
-CG_AddParticles
-===============
-*/
-void CG_AddParticles (void)
-{
- cparticle_t *p, *next;
- float alpha;
- float time, time2;
- vec3_t org;
- int color;
- cparticle_t *active, *tail;
- int type;
- vec3_t rotate_ang;
-
- if (!initparticles)
- CG_ClearParticles ();
-
- VectorCopy( cg.refdef.viewaxis[0], pvforward );
- VectorCopy( cg.refdef.viewaxis[1], pvright );
- VectorCopy( cg.refdef.viewaxis[2], pvup );
-
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- roll += ((cg.time - oldtime) * 0.1) ;
- rotate_ang[ROLL] += (roll*0.9);
- AngleVectors ( rotate_ang, rforward, rright, rup);
-
- oldtime = cg.time;
-
- active = NULL;
- tail = NULL;
-
- for (p=active_particles ; p ; p=next)
- {
-
- next = p->next;
-
- time = (cg.time - p->time)*0.001;
-
- alpha = p->alpha + time*p->alphavel;
- if (alpha <= 0)
- { // faded out
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
-
- continue;
- }
-
- }
-
- if (p->type == P_WEATHER_FLURRY)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
-
- continue;
- }
- }
-
-
- if (p->type == P_FLAT_SCALEUP_FADE)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- }
-
- if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {
- // temporary sprite
- CG_AddParticleToScene (p, p->org, alpha);
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- p->next = NULL;
- if (!tail)
- active = tail = p;
- else
- {
- tail->next = p;
- tail = p;
- }
-
- if (alpha > 1.0)
- alpha = 1;
-
- color = p->color;
-
- time2 = time*time;
-
- org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
- org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
- org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
-
- type = p->type;
-
- CG_AddParticleToScene (p, org, alpha);
- }
-
- active_particles = active;
-}
-
-/*
-======================
-CG_AddParticles
-======================
-*/
-void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
- qboolean turb = qtrue;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.90f;
- p->alphavel = 0;
-
- p->start = cent->currentState.origin2[0];
- p->end = cent->currentState.origin2[1];
-
- p->endtime = cg.time + cent->currentState.time;
- p->startfade = cg.time + cent->currentState.time2;
-
- p->pshader = pshader;
-
- if (rand()%100 > 90)
- {
- p->height = 32;
- p->width = 32;
- p->alpha = 0.10f;
- }
- else
- {
- p->height = 1;
- p->width = 1;
- }
-
- p->vel[2] = -20;
-
- p->type = P_WEATHER_FLURRY;
-
- if (turb)
- p->vel[2] = -10;
-
- VectorCopy(cent->currentState.origin, p->org);
-
- p->org[0] = p->org[0];
- p->org[1] = p->org[1];
- p->org[2] = p->org[2];
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16);
- p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16);
- p->vel[2] += cent->currentState.angles[2];
-
- if (turb)
- {
- p->accel[0] = crandom () * 16;
- p->accel[1] = crandom () * 16;
- }
-
-}
-
-void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.40f;
- p->alphavel = 0;
- p->start = origin[2];
- p->end = origin2[2];
- p->pshader = pshader;
- p->height = 1;
- p->width = 1;
-
- p->vel[2] = -50;
-
- if (turb)
- {
- p->type = P_WEATHER_TURBULENT;
- p->vel[2] = -50 * 1.3;
- }
- else
- {
- p->type = P_WEATHER;
- }
-
- VectorCopy(origin, p->org);
-
- p->org[0] = p->org[0] + ( crandom() * range);
- p->org[1] = p->org[1] + ( crandom() * range);
- p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- if (turb)
- {
- p->vel[0] = crandom() * 16;
- p->vel[1] = crandom() * 16;
- }
-
- // Rafael snow pvs check
- p->snum = snum;
- p->link = qtrue;
-
-}
-
-void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
-{
- cparticle_t *p;
- float randsize;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.40f;
- p->alphavel = 0;
- p->start = origin[2];
- p->end = origin2[2];
- p->pshader = pshader;
-
- randsize = 1 + (crandom() * 0.5);
-
- p->height = randsize;
- p->width = randsize;
-
- p->vel[2] = 50 + ( crandom() * 10 );
-
- if (turb)
- {
- p->type = P_BUBBLE_TURBULENT;
- p->vel[2] = 50 * 1.3;
- }
- else
- {
- p->type = P_BUBBLE;
- }
-
- VectorCopy(origin, p->org);
-
- p->org[0] = p->org[0] + ( crandom() * range);
- p->org[1] = p->org[1] + ( crandom() * range);
- p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- if (turb)
- {
- p->vel[0] = crandom() * 4;
- p->vel[1] = crandom() * 4;
- }
-
- // Rafael snow pvs check
- p->snum = snum;
- p->link = qtrue;
-
-}
-
-void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent)
-{
-
- // using cent->density = enttime
- // cent->frame = startfade
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSmoke == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + cent->currentState.time;
- p->startfade = cg.time + cent->currentState.time2;
-
- p->color = 0;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->start = cent->currentState.origin[2];
- p->end = cent->currentState.origin2[2];
- p->pshader = pshader;
- p->rotate = qfalse;
- p->height = 8;
- p->width = 8;
- p->endheight = 32;
- p->endwidth = 32;
- p->type = P_SMOKE;
-
- VectorCopy(cent->currentState.origin, p->org);
-
- p->vel[0] = p->vel[1] = 0;
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[2] = 5;
-
- if (cent->currentState.frame == 1)// reverse gravity
- p->vel[2] *= -1;
-
- p->roll = 8 + (crandom() * 4);
-}
-
-
-void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration)
-{
-
- cparticle_t *p;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + duration;
- p->startfade = cg.time + duration/2;
-
- p->color = EMISIVEFADE;
- p->alpha = 1.0;
- p->alphavel = 0;
-
- p->height = 0.5;
- p->width = 0.5;
- p->endheight = 0.5;
- p->endwidth = 0.5;
-
- p->pshader = cgs.media.tracerShader;
-
- p->type = P_SMOKE;
-
- VectorCopy(org, p->org);
-
- p->vel[0] = vel[0];
- p->vel[1] = vel[1];
- p->vel[2] = vel[2];
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->accel[2] = -60;
- p->vel[2] += -20;
-
-}
-
-/*
-======================
-CG_ParticleExplosion
-======================
-*/
-
-void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd)
-{
- cparticle_t *p;
- int anim;
-
- if (animStr < (char *)10)
- CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" );
-
- // find the animation string
- for (anim=0; shaderAnimNames[anim]; anim++) {
- if (!Q_stricmp( animStr, shaderAnimNames[anim] ))
- break;
- }
- if (!shaderAnimNames[anim]) {
- CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr);
- return;
- }
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 0.5;
- p->alphavel = 0;
-
- if (duration < 0) {
- duration *= -1;
- p->roll = 0;
- } else {
- p->roll = crandom()*179;
- }
-
- p->shaderAnim = anim;
-
- p->width = sizeStart;
- p->height = sizeStart*shaderAnimSTRatio[anim]; // for sprites that are stretch in either direction
-
- p->endheight = sizeEnd;
- p->endwidth = sizeEnd*shaderAnimSTRatio[anim];
-
- p->endtime = cg.time + duration;
-
- p->type = P_ANIM;
-
- VectorCopy( origin, p->org );
- VectorCopy( vel, p->vel );
- VectorClear( p->accel );
-
-}
-
-// Rafael Shrapnel
-void CG_AddParticleShrapnel (localEntity_t *le)
-{
- return;
-}
-// done.
-
-int CG_NewParticleArea (int num)
-{
- // const char *str;
- char *str;
- char *token;
- int type;
- vec3_t origin, origin2;
- int i;
- float range = 0;
- int turb;
- int numparticles;
- int snum;
-
- str = (char *) CG_ConfigString (num);
- if (!str[0])
- return (0);
-
- // returns type 128 64 or 32
- token = COM_Parse (&str);
- type = atoi (token);
-
- if (type == 1)
- range = 128;
- else if (type == 2)
- range = 64;
- else if (type == 3)
- range = 32;
- else if (type == 0)
- range = 256;
- else if (type == 4)
- range = 8;
- else if (type == 5)
- range = 16;
- else if (type == 6)
- range = 32;
- else if (type == 7)
- range = 64;
-
-
- for (i=0; i<3; i++)
- {
- token = COM_Parse (&str);
- origin[i] = atof (token);
- }
-
- for (i=0; i<3; i++)
- {
- token = COM_Parse (&str);
- origin2[i] = atof (token);
- }
-
- token = COM_Parse (&str);
- numparticles = atoi (token);
-
- token = COM_Parse (&str);
- turb = atoi (token);
-
- token = COM_Parse (&str);
- snum = atoi (token);
-
- for (i=0; i<numparticles; i++)
- {
- if (type >= 4)
- CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
- else
- CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
- }
-
- return (1);
-}
-
-void CG_SnowLink (centity_t *cent, qboolean particleOn)
-{
- cparticle_t *p, *next;
- int id;
-
- id = cent->currentState.frame;
-
- for (p=active_particles ; p ; p=next)
- {
- next = p->next;
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT)
- {
- if (p->snum == id)
- {
- if (particleOn)
- p->link = qtrue;
- else
- p->link = qfalse;
- }
- }
-
- }
-}
-
-void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 0.25;
- p->alphavel = 0;
- p->roll = crandom()*179;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + 1000;
- p->startfade = cg.time + 100;
-
- p->width = rand()%4 + 8;
- p->height = rand()%4 + 8;
-
- p->endheight = p->height *2;
- p->endwidth = p->width * 2;
-
- p->endtime = cg.time + 500;
-
- p->type = P_SMOKE_IMPACT;
-
- VectorCopy( origin, p->org );
- VectorSet(p->vel, 0, 0, 20);
- VectorSet(p->accel, 0, 0, 20);
-
- p->rotate = qtrue;
-}
-
-void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + duration;
-
- if (fleshEntityNum)
- p->startfade = cg.time;
- else
- p->startfade = cg.time + 100;
-
- p->width = 4;
- p->height = 4;
-
- p->endheight = 4+rand()%3;
- p->endwidth = p->endheight;
-
- p->type = P_SMOKE;
-
- VectorCopy( start, p->org );
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = -20;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->color = BLOODRED;
- p->alpha = 0.75;
-
-}
-
-void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
-
- int time;
- int time2;
- float ratio;
-
- float duration = 1500;
-
- time = cg.time;
- time2 = cg.time + cent->currentState.time;
-
- ratio =(float)1 - ((float)time / (float)time2);
-
- if (!pshader)
- CG_Printf ("CG_Particle_OilParticle == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + duration;
-
- p->startfade = p->endtime;
-
- p->width = 1;
- p->height = 3;
-
- p->endheight = 3;
- p->endwidth = 1;
-
- p->type = P_SMOKE;
-
- VectorCopy(cent->currentState.origin, p->org );
-
- p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio));
- p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio));
- p->vel[2] = (cent->currentState.origin2[2]);
-
- p->snum = 1.0f;
-
- VectorClear( p->accel );
-
- p->accel[2] = -20;
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
-}
-
-
-void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_Particle_OilSlick == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- if (cent->currentState.angles2[2])
- p->endtime = cg.time + cent->currentState.angles2[2];
- else
- p->endtime = cg.time + 60000;
-
- p->startfade = p->endtime;
-
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- if (cent->currentState.angles2[0] || cent->currentState.angles2[1])
- {
- p->width = cent->currentState.angles2[0];
- p->height = cent->currentState.angles2[0];
-
- p->endheight = cent->currentState.angles2[1];
- p->endwidth = cent->currentState.angles2[1];
- }
- else
- {
- p->width = 8;
- p->height = 8;
-
- p->endheight = 16;
- p->endwidth = 16;
- }
-
- p->type = P_FLAT_SCALEUP;
-
- p->snum = 1.0;
-
- VectorCopy(cent->currentState.origin, p->org );
-
- p->org[2]+= 0.55 + (crandom() * 0.5);
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = 0;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
-}
-
-void CG_OilSlickRemove (centity_t *cent)
-{
- cparticle_t *p, *next;
- int id;
-
- id = 1.0f;
-
- if (!id)
- CG_Printf ("CG_OilSlickRevove NULL id\n");
-
- for (p=active_particles ; p ; p=next)
- {
- next = p->next;
-
- if (p->type == P_FLAT_SCALEUP)
- {
- if (p->snum == id)
- {
- p->endtime = cg.time + 100;
- p->startfade = p->endtime;
- p->type = P_FLAT_SCALEUP_FADE;
-
- }
- }
-
- }
-}
-
-qboolean ValidBloodPool (vec3_t start)
-{
-#define EXTRUDE_DIST 0.5
-
- vec3_t angles;
- vec3_t right, up;
- vec3_t this_pos, x_pos, center_pos, end_pos;
- float x, y;
- float fwidth, fheight;
- trace_t trace;
- vec3_t normal;
-
- fwidth = 16;
- fheight = 16;
-
- VectorSet (normal, 0, 0, 1);
-
- vectoangles (normal, angles);
- AngleVectors (angles, NULL, right, up);
-
- VectorMA (start, EXTRUDE_DIST, normal, center_pos);
-
- for (x= -fwidth/2; x<fwidth; x+= fwidth)
- {
- VectorMA (center_pos, x, right, x_pos);
-
- for (y= -fheight/2; y<fheight; y+= fheight)
- {
- VectorMA (x_pos, y, up, this_pos);
- VectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos);
-
- CG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID);
-
-
- if (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world
- return qfalse;
-
- if (!(!trace.startsolid && trace.fraction < 1))
- return qfalse;
-
- }
- }
-
- return qtrue;
-}
-
-void CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr)
-{
- cparticle_t *p;
- qboolean legit;
- vec3_t start;
- float rndSize;
-
- if (!pshader)
- CG_Printf ("CG_BloodPool pshader == ZERO!\n");
-
- if (!free_particles)
- return;
-
- VectorCopy (tr->endpos, start);
- legit = ValidBloodPool (start);
-
- if (!legit)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + 3000;
- p->startfade = p->endtime;
-
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- rndSize = 0.4 + random()*0.6;
-
- p->width = 8*rndSize;
- p->height = 8*rndSize;
-
- p->endheight = 16*rndSize;
- p->endwidth = 16*rndSize;
-
- p->type = P_FLAT_SCALEUP;
-
- VectorCopy(start, p->org );
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = 0;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
- p->color = BLOODRED;
-}
-
-#define NORMALSIZE 16
-#define LARGESIZE 32
-
-void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir)
-{
- float length;
- float dist;
- float crittersize;
- vec3_t angles, forward;
- vec3_t point;
- cparticle_t *p;
- int i;
-
- dist = 0;
-
- length = VectorLength (dir);
- vectoangles (dir, angles);
- AngleVectors (angles, forward, NULL, NULL);
-
- crittersize = LARGESIZE;
-
- if (length)
- dist = length / crittersize;
-
- if (dist < 1)
- dist = 1;
-
- VectorCopy (origin, point);
-
- for (i=0; i<dist; i++)
- {
- VectorMA (point, crittersize, forward, point);
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = cgs.media.smokePuffShader;
-
- p->endtime = cg.time + 350 + (crandom() * 100);
-
- p->startfade = cg.time;
-
- p->width = LARGESIZE;
- p->height = LARGESIZE;
- p->endheight = LARGESIZE;
- p->endwidth = LARGESIZE;
-
- p->type = P_SMOKE;
-
- VectorCopy( origin, p->org );
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = -1;
-
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->color = BLOODRED;
-
- p->alpha = 0.75;
-
- }
-
-
-}
-
-void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
-{
- cparticle_t *p;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + duration;
- p->startfade = cg.time + duration/2;
-
- p->color = EMISIVEFADE;
- p->alpha = 0.4f;
- p->alphavel = 0;
-
- p->height = 0.5;
- p->width = 0.5;
- p->endheight = 0.5;
- p->endwidth = 0.5;
-
- p->pshader = cgs.media.tracerShader;
-
- p->type = P_SMOKE;
-
- VectorCopy(org, p->org);
-
- p->org[0] += (crandom() * x);
- p->org[1] += (crandom() * y);
-
- p->vel[0] = vel[0];
- p->vel[1] = vel[1];
- p->vel[2] = vel[2];
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[0] += (crandom() * 4);
- p->vel[1] += (crandom() * 4);
- p->vel[2] += (20 + (crandom() * 10)) * speed;
-
- p->accel[0] = crandom () * 4;
- p->accel[1] = crandom () * 4;
-
-}
-
-void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir)
-{
- float length;
- float dist;
- float crittersize;
- vec3_t angles, forward;
- vec3_t point;
- cparticle_t *p;
- int i;
-
- dist = 0;
-
- VectorNegate (dir, dir);
- length = VectorLength (dir);
- vectoangles (dir, angles);
- AngleVectors (angles, forward, NULL, NULL);
-
- crittersize = LARGESIZE;
-
- if (length)
- dist = length / crittersize;
-
- if (dist < 1)
- dist = 1;
-
- VectorCopy (origin, point);
-
- for (i=0; i<dist; i++)
- {
- VectorMA (point, crittersize, forward, point);
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cg.time;
- p->alpha = 5.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = cgs.media.smokePuffShader;
-
- // RF, stay around for long enough to expand and dissipate naturally
- if (length)
- p->endtime = cg.time + 4500 + (crandom() * 3500);
- else
- p->endtime = cg.time + 750 + (crandom() * 500);
-
- p->startfade = cg.time;
-
- p->width = LARGESIZE;
- p->height = LARGESIZE;
-
- // RF, expand while falling
- p->endheight = LARGESIZE*3.0;
- p->endwidth = LARGESIZE*3.0;
-
- if (!length)
- {
- p->width *= 0.2f;
- p->height *= 0.2f;
-
- p->endheight = NORMALSIZE;
- p->endwidth = NORMALSIZE;
- }
-
- p->type = P_SMOKE;
-
- VectorCopy( point, p->org );
-
- p->vel[0] = crandom()*6;
- p->vel[1] = crandom()*6;
- p->vel[2] = random()*20;
-
- // RF, add some gravity/randomness
- p->accel[0] = crandom()*3;
- p->accel[1] = crandom()*3;
- p->accel[2] = -PARTICLE_GRAVITY*0.4;
-
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
- }
-
-
-}
-
-void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = rand()%179;
-
- p->pshader = pshader;
-
- if (duration > 0)
- p->endtime = cg.time + duration;
- else
- p->endtime = duration;
-
- p->startfade = cg.time;
-
- p->width = size;
- p->height = size;
-
- p->endheight = size;
- p->endwidth = size;
-
- p->type = P_SPRITE;
-
- VectorCopy( origin, p->org );
-
- p->rotate = qfalse;
-}
-
diff --git a/engine/code/cgame/cg_newdraw.c b/engine/code/cgame/cg_newdraw.c
deleted file mode 100644
index 25dc342..0000000
--- a/engine/code/cgame/cg_newdraw.c
+++ /dev/null
@@ -1,1849 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#ifndef MISSIONPACK
-#error This file not be used for classic Q3A.
-#endif
-
-#include "cg_local.h"
-#include "../ui/ui_shared.h"
-
-extern displayContextDef_t cgDC;
-
-
-// set in CG_ParseTeamInfo
-
-//static int sortedTeamPlayers[TEAM_MAXOVERLAY];
-//static int numSortedTeamPlayers;
-int drawTeamOverlayModificationCount = -1;
-
-//static char systemChat[256];
-//static char teamChat1[256];
-//static char teamChat2[256];
-
-void CG_InitTeamChat(void) {
- memset(teamChat1, 0, sizeof(teamChat1));
- memset(teamChat2, 0, sizeof(teamChat2));
- memset(systemChat, 0, sizeof(systemChat));
-}
-
-void CG_SetPrintString(int type, const char *p) {
- if (type == SYSTEM_PRINT) {
- strcpy(systemChat, p);
- } else {
- strcpy(teamChat2, teamChat1);
- strcpy(teamChat1, p);
- }
-}
-
-void CG_CheckOrderPending(void) {
- if (cgs.gametype < GT_CTF) {
- return;
- }
- if (cgs.orderPending) {
- //clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[cg_currentSelectedPlayer.integer];
- const char *p1, *p2, *b;
- p1 = p2 = b = NULL;
- switch (cgs.currentOrder) {
- case TEAMTASK_OFFENSE:
- p1 = VOICECHAT_ONOFFENSE;
- p2 = VOICECHAT_OFFENSE;
- b = "+button7; wait; -button7";
- break;
- case TEAMTASK_DEFENSE:
- p1 = VOICECHAT_ONDEFENSE;
- p2 = VOICECHAT_DEFEND;
- b = "+button8; wait; -button8";
- break;
- case TEAMTASK_PATROL:
- p1 = VOICECHAT_ONPATROL;
- p2 = VOICECHAT_PATROL;
- b = "+button9; wait; -button9";
- break;
- case TEAMTASK_FOLLOW:
- p1 = VOICECHAT_ONFOLLOW;
- p2 = VOICECHAT_FOLLOWME;
- b = "+button10; wait; -button10";
- break;
- case TEAMTASK_CAMP:
- p1 = VOICECHAT_ONCAMPING;
- p2 = VOICECHAT_CAMP;
- break;
- case TEAMTASK_RETRIEVE:
- p1 = VOICECHAT_ONGETFLAG;
- p2 = VOICECHAT_RETURNFLAG;
- break;
- case TEAMTASK_ESCORT:
- p1 = VOICECHAT_ONFOLLOWCARRIER;
- p2 = VOICECHAT_FOLLOWFLAGCARRIER;
- break;
- }
-
- if (cg_currentSelectedPlayer.integer == numSortedTeamPlayers) {
- // to everyone
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", p2));
- } else {
- // for the player self
- if (sortedTeamPlayers[cg_currentSelectedPlayer.integer] == cg.snap->ps.clientNum && p1) {
- trap_SendConsoleCommand(va("teamtask %i\n", cgs.currentOrder));
- //trap_SendConsoleCommand(va("cmd say_team %s\n", p2));
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", p1));
- } else if (p2) {
- //trap_SendConsoleCommand(va("cmd say_team %s, %s\n", ci->name,p));
- trap_SendConsoleCommand(va("cmd vtell %d %s\n", sortedTeamPlayers[cg_currentSelectedPlayer.integer], p2));
- }
- }
- if (b) {
- trap_SendConsoleCommand(b);
- }
- cgs.orderPending = qfalse;
- }
-}
-
-static void CG_SetSelectedPlayerName( void ) {
- if (cg_currentSelectedPlayer.integer >= 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) {
- clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[cg_currentSelectedPlayer.integer];
- if (ci) {
- trap_Cvar_Set("cg_selectedPlayerName", ci->name);
- trap_Cvar_Set("cg_selectedPlayer", va("%d", sortedTeamPlayers[cg_currentSelectedPlayer.integer]));
- cgs.currentOrder = ci->teamTask;
- }
- } else {
- trap_Cvar_Set("cg_selectedPlayerName", "Everyone");
- }
-}
-int CG_GetSelectedPlayer( void ) {
- if (cg_currentSelectedPlayer.integer < 0 || cg_currentSelectedPlayer.integer >= numSortedTeamPlayers) {
- cg_currentSelectedPlayer.integer = 0;
- }
- return cg_currentSelectedPlayer.integer;
-}
-
-void CG_SelectNextPlayer( void ) {
- CG_CheckOrderPending();
- if (cg_currentSelectedPlayer.integer >= 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) {
- cg_currentSelectedPlayer.integer++;
- } else {
- cg_currentSelectedPlayer.integer = 0;
- }
- CG_SetSelectedPlayerName();
-}
-
-void CG_SelectPrevPlayer( void ) {
- CG_CheckOrderPending();
- if (cg_currentSelectedPlayer.integer > 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) {
- cg_currentSelectedPlayer.integer--;
- } else {
- cg_currentSelectedPlayer.integer = numSortedTeamPlayers;
- }
- CG_SetSelectedPlayerName();
-}
-
-
-static void CG_DrawPlayerArmorIcon( rectDef_t *rect, qboolean draw2D ) {
- centity_t *cent;
- playerState_t *ps;
- vec3_t angles;
- vec3_t origin;
-
- if ( cg_drawStatus.integer == 0 ) {
- return;
- }
-
- cent = &cg_entities[cg.snap->ps.clientNum];
- ps = &cg.snap->ps;
-
- if ( draw2D || ( !cg_draw3dIcons.integer && cg_drawIcons.integer) ) {
- CG_DrawPic( rect->x, rect->y + rect->h/2 + 1, rect->w, rect->h, cgs.media.armorIcon );
- } else if (cg_draw3dIcons.integer) {
- VectorClear( angles );
- origin[0] = 90;
- origin[1] = 0;
- origin[2] = -10;
- angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
-
- CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cgs.media.armorModel, 0, origin, angles );
- }
-
-}
-
-static void CG_DrawPlayerArmorValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- char num[16];
- int value;
- centity_t *cent;
- playerState_t *ps;
-
- cent = &cg_entities[cg.snap->ps.clientNum];
- ps = &cg.snap->ps;
-
- value = ps->stats[STAT_ARMOR];
-
-
- if (shader) {
- trap_R_SetColor( color );
- CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
- trap_R_SetColor( NULL );
- } else {
- Com_sprintf (num, sizeof(num), "%i", value);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
- }
-}
-
-#ifndef MISSIONPACK
-static float healthColors[4][4] = {
-// { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} };
- { 1.0f, 0.69f, 0.0f, 1.0f } , // normal
- { 1.0f, 0.2f, 0.2f, 1.0f }, // low health
- { 0.5f, 0.5f, 0.5f, 1.0f}, // weapon firing
- { 1.0f, 1.0f, 1.0f, 1.0f } }; // health > 100
-#endif
-
-static void CG_DrawPlayerAmmoIcon( rectDef_t *rect, qboolean draw2D ) {
- centity_t *cent;
- playerState_t *ps;
- vec3_t angles;
- vec3_t origin;
-
- cent = &cg_entities[cg.snap->ps.clientNum];
- ps = &cg.snap->ps;
-
- if ( draw2D || (!cg_draw3dIcons.integer && cg_drawIcons.integer) ) {
- qhandle_t icon;
- icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon;
- if ( icon ) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, icon );
- }
- } else if (cg_draw3dIcons.integer) {
- if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) {
- VectorClear( angles );
- origin[0] = 70;
- origin[1] = 0;
- origin[2] = 0;
- angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 );
- CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles );
- }
- }
-}
-
-static void CG_DrawPlayerAmmoValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- char num[16];
- int value;
- centity_t *cent;
- playerState_t *ps;
-
- cent = &cg_entities[cg.snap->ps.clientNum];
- ps = &cg.snap->ps;
-
- if ( cent->currentState.weapon ) {
- value = ps->ammo[cent->currentState.weapon];
- if ( value > -1 ) {
- if (shader) {
- trap_R_SetColor( color );
- CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
- trap_R_SetColor( NULL );
- } else {
- Com_sprintf (num, sizeof(num), "%i", value);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
- }
- }
- }
-
-}
-
-
-
-static void CG_DrawPlayerHead(rectDef_t *rect, qboolean draw2D) {
- vec3_t angles;
- float size, stretch;
- float frac;
- float x = rect->x;
-
- VectorClear( angles );
-
- if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) {
- frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME;
- size = rect->w * 1.25 * ( 1.5 - frac * 0.5 );
-
- stretch = size - rect->w * 1.25;
- // kick in the direction of damage
- x -= stretch * 0.5 + cg.damageX * stretch * 0.5;
-
- cg.headStartYaw = 180 + cg.damageX * 45;
-
- cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
- cg.headEndPitch = 5 * cos( crandom()*M_PI );
-
- cg.headStartTime = cg.time;
- cg.headEndTime = cg.time + 100 + random() * 2000;
- } else {
- if ( cg.time >= cg.headEndTime ) {
- // select a new head angle
- cg.headStartYaw = cg.headEndYaw;
- cg.headStartPitch = cg.headEndPitch;
- cg.headStartTime = cg.headEndTime;
- cg.headEndTime = cg.time + 100 + random() * 2000;
-
- cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
- cg.headEndPitch = 5 * cos( crandom()*M_PI );
- }
-
- size = rect->w * 1.25;
- }
-
- // if the server was frozen for a while we may have a bad head start time
- if ( cg.headStartTime > cg.time ) {
- cg.headStartTime = cg.time;
- }
-
- frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime );
- frac = frac * frac * ( 3 - 2 * frac );
- angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac;
- angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac;
-
- CG_DrawHead( x, rect->y, rect->w, rect->h, cg.snap->ps.clientNum, angles );
-}
-
-static void CG_DrawSelectedPlayerHealth( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- clientInfo_t *ci;
- int value;
- char num[16];
-
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- if (ci) {
- if (shader) {
- trap_R_SetColor( color );
- CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
- trap_R_SetColor( NULL );
- } else {
- Com_sprintf (num, sizeof(num), "%i", ci->health);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
- }
- }
-}
-
-static void CG_DrawSelectedPlayerArmor( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- clientInfo_t *ci;
- int value;
- char num[16];
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- if (ci) {
- if (ci->armor > 0) {
- if (shader) {
- trap_R_SetColor( color );
- CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
- trap_R_SetColor( NULL );
- } else {
- Com_sprintf (num, sizeof(num), "%i", ci->armor);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
- }
- }
- }
-}
-
-qhandle_t CG_StatusHandle(int task) {
- qhandle_t h = cgs.media.assaultShader;
- switch (task) {
- case TEAMTASK_OFFENSE :
- h = cgs.media.assaultShader;
- break;
- case TEAMTASK_DEFENSE :
- h = cgs.media.defendShader;
- break;
- case TEAMTASK_PATROL :
- h = cgs.media.patrolShader;
- break;
- case TEAMTASK_FOLLOW :
- h = cgs.media.followShader;
- break;
- case TEAMTASK_CAMP :
- h = cgs.media.campShader;
- break;
- case TEAMTASK_RETRIEVE :
- h = cgs.media.retrieveShader;
- break;
- case TEAMTASK_ESCORT :
- h = cgs.media.escortShader;
- break;
- default :
- h = cgs.media.assaultShader;
- break;
- }
- return h;
-}
-
-static void CG_DrawSelectedPlayerStatus( rectDef_t *rect ) {
- clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- if (ci) {
- qhandle_t h;
- if (cgs.orderPending) {
- // blink the icon
- if ( cg.time > cgs.orderTime - 2500 && (cg.time >> 9 ) & 1 ) {
- return;
- }
- h = CG_StatusHandle(cgs.currentOrder);
- } else {
- h = CG_StatusHandle(ci->teamTask);
- }
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, h );
- }
-}
-
-
-static void CG_DrawPlayerStatus( rectDef_t *rect ) {
- clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum];
- if (ci) {
- qhandle_t h = CG_StatusHandle(ci->teamTask);
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, h);
- }
-}
-
-
-static void CG_DrawSelectedPlayerName( rectDef_t *rect, float scale, vec4_t color, qboolean voice, int textStyle) {
- clientInfo_t *ci;
- ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]);
- if (ci) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, ci->name, 0, 0, textStyle);
- }
-}
-
-static void CG_DrawSelectedPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
- clientInfo_t *ci;
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- if (ci) {
- const char *p = CG_ConfigString(CS_LOCATIONS + ci->location);
- if (!p || !*p) {
- p = "unknown";
- }
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle);
- }
-}
-
-static void CG_DrawPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
- clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum];
- if (ci) {
- const char *p = CG_ConfigString(CS_LOCATIONS + ci->location);
- if (!p || !*p) {
- p = "unknown";
- }
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle);
- }
-}
-
-
-
-static void CG_DrawSelectedPlayerWeapon( rectDef_t *rect ) {
- clientInfo_t *ci;
-
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- if (ci) {
- if ( cg_weapons[ci->curWeapon].weaponIcon ) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_weapons[ci->curWeapon].weaponIcon );
- } else {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader);
- }
- }
-}
-
-static void CG_DrawPlayerScore( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- char num[16];
- int value = cg.snap->ps.persistant[PERS_SCORE];
-
- if (shader) {
- trap_R_SetColor( color );
- CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
- trap_R_SetColor( NULL );
- } else {
- Com_sprintf (num, sizeof(num), "%i", value);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
- }
-}
-
-static void CG_DrawPlayerItem( rectDef_t *rect, float scale, qboolean draw2D) {
- int value;
- vec3_t origin, angles;
-
- value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM];
- if ( value ) {
- CG_RegisterItemVisuals( value );
-
- if (qtrue) {
- CG_RegisterItemVisuals( value );
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_items[ value ].icon );
- } else {
- VectorClear( angles );
- origin[0] = 90;
- origin[1] = 0;
- origin[2] = -10;
- angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
- CG_Draw3DModel(rect->x, rect->y, rect->w, rect->h, cg_items[ value ].models[0], 0, origin, angles );
- }
- }
-
-}
-
-
-static void CG_DrawSelectedPlayerPowerup( rectDef_t *rect, qboolean draw2D ) {
- clientInfo_t *ci;
- int j;
- float x, y;
-
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- if (ci) {
- x = rect->x;
- y = rect->y;
-
- for (j = 0; j < PW_NUM_POWERUPS; j++) {
- if (ci->powerups & (1 << j)) {
- gitem_t *item;
- item = BG_FindItemForPowerup( j );
- if (item) {
- CG_DrawPic( x, y, rect->w, rect->h, trap_R_RegisterShader( item->icon ) );
- x += 3;
- y += 3;
- return;
- }
- }
- }
-
- }
-}
-
-
-static void CG_DrawSelectedPlayerHead( rectDef_t *rect, qboolean draw2D, qboolean voice ) {
- clipHandle_t cm;
- clientInfo_t *ci;
- float len;
- vec3_t origin;
- vec3_t mins, maxs, angles;
-
-
- ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]);
-
- if (ci) {
- if ( cg_draw3dIcons.integer ) {
- cm = ci->headModel;
- if ( !cm ) {
- return;
- }
-
- // offset the origin y and z to center the head
- trap_R_ModelBounds( cm, mins, maxs );
-
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
-
- // calculate distance so the head nearly fills the box
- // assume heads are taller than wide
- len = 0.7 * ( maxs[2] - mins[2] );
- origin[0] = len / 0.268; // len / tan( fov/2 )
-
- // allow per-model tweaking
- VectorAdd( origin, ci->headOffset, origin );
-
- angles[PITCH] = 0;
- angles[YAW] = 180;
- angles[ROLL] = 0;
-
- CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, ci->headModel, ci->headSkin, origin, angles );
- } else if ( cg_drawIcons.integer ) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, ci->modelIcon );
- }
-
- // if they are deferred, draw a cross out
- if ( ci->deferred ) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader );
- }
- }
-
-}
-
-
-static void CG_DrawPlayerHealth(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- playerState_t *ps;
- int value;
- char num[16];
-
- ps = &cg.snap->ps;
-
- value = ps->stats[STAT_HEALTH];
-
- if (shader) {
- trap_R_SetColor( color );
- CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
- trap_R_SetColor( NULL );
- } else {
- Com_sprintf (num, sizeof(num), "%i", value);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
- }
-}
-
-
-static void CG_DrawRedScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- int value;
- char num[16];
- if ( cgs.scores1 == SCORE_NOT_PRESENT ) {
- Com_sprintf (num, sizeof(num), "-");
- }
- else {
- Com_sprintf (num, sizeof(num), "%i", cgs.scores1);
- }
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
-}
-
-static void CG_DrawBlueScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- int value;
- char num[16];
-
- if ( cgs.scores2 == SCORE_NOT_PRESENT ) {
- Com_sprintf (num, sizeof(num), "-");
- }
- else {
- Com_sprintf (num, sizeof(num), "%i", cgs.scores2);
- }
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
-}
-
-// FIXME: team name support
-static void CG_DrawRedName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_redTeamName.string , 0, 0, textStyle);
-}
-
-static void CG_DrawBlueName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_blueTeamName.string, 0, 0, textStyle);
-}
-
-static void CG_DrawBlueFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
- int i;
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle);
- return;
- }
- }
-}
-
-static void CG_DrawBlueFlagStatus(rectDef_t *rect, qhandle_t shader) {
- if (cgs.gametype != GT_CTF && cgs.gametype != GT_1FCTF) {
- if (cgs.gametype == GT_HARVESTER) {
- vec4_t color = {0, 0, 1, 1};
- trap_R_SetColor(color);
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.blueCubeIcon );
- trap_R_SetColor(NULL);
- }
- return;
- }
- if (shader) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
- } else {
- gitem_t *item = BG_FindItemForPowerup( PW_BLUEFLAG );
- if (item) {
- vec4_t color = {0, 0, 1, 1};
- trap_R_SetColor(color);
- if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.blueflag] );
- } else {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] );
- }
- trap_R_SetColor(NULL);
- }
- }
-}
-
-static void CG_DrawBlueFlagHead(rectDef_t *rect) {
- int i;
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) {
- vec3_t angles;
- VectorClear( angles );
- angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );;
- CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles );
- return;
- }
- }
-}
-
-static void CG_DrawRedFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
- int i;
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle);
- return;
- }
- }
-}
-
-static void CG_DrawRedFlagStatus(rectDef_t *rect, qhandle_t shader) {
- if (cgs.gametype != GT_CTF && cgs.gametype != GT_1FCTF) {
- if (cgs.gametype == GT_HARVESTER) {
- vec4_t color = {1, 0, 0, 1};
- trap_R_SetColor(color);
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.redCubeIcon );
- trap_R_SetColor(NULL);
- }
- return;
- }
- if (shader) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
- } else {
- gitem_t *item = BG_FindItemForPowerup( PW_REDFLAG );
- if (item) {
- vec4_t color = {1, 0, 0, 1};
- trap_R_SetColor(color);
- if( cgs.redflag >= 0 && cgs.redflag <= 2) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.redflag] );
- } else {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] );
- }
- trap_R_SetColor(NULL);
- }
- }
-}
-
-static void CG_DrawRedFlagHead(rectDef_t *rect) {
- int i;
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) {
- vec3_t angles;
- VectorClear( angles );
- angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );;
- CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles );
- return;
- }
- }
-}
-
-static void CG_HarvesterSkulls(rectDef_t *rect, float scale, vec4_t color, qboolean force2D, int textStyle ) {
- char num[16];
- vec3_t origin, angles;
- qhandle_t handle;
- int value = cg.snap->ps.generic1;
-
- if (cgs.gametype != GT_HARVESTER) {
- return;
- }
-
- if( value > 99 ) {
- value = 99;
- }
-
- Com_sprintf (num, sizeof(num), "%i", value);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value), rect->y + rect->h, scale, color, num, 0, 0, textStyle);
-
- if (cg_drawIcons.integer) {
- if (!force2D && cg_draw3dIcons.integer) {
- VectorClear(angles);
- origin[0] = 90;
- origin[1] = 0;
- origin[2] = -10;
- angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
- if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- handle = cgs.media.redCubeModel;
- } else {
- handle = cgs.media.blueCubeModel;
- }
- CG_Draw3DModel( rect->x, rect->y, 35, 35, handle, 0, origin, angles );
- } else {
- if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- handle = cgs.media.redCubeIcon;
- } else {
- handle = cgs.media.blueCubeIcon;
- }
- CG_DrawPic( rect->x + 3, rect->y + 16, 20, 20, handle );
- }
- }
-}
-
-static void CG_OneFlagStatus(rectDef_t *rect) {
- if (cgs.gametype != GT_1FCTF) {
- return;
- } else {
- gitem_t *item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
- if (item) {
- if( cgs.flagStatus >= 0 && cgs.flagStatus <= 4 ) {
- vec4_t color = {1, 1, 1, 1};
- int index = 0;
- if (cgs.flagStatus == FLAG_TAKEN_RED) {
- color[1] = color[2] = 0;
- index = 1;
- } else if (cgs.flagStatus == FLAG_TAKEN_BLUE) {
- color[0] = color[1] = 0;
- index = 1;
- } else if (cgs.flagStatus == FLAG_DROPPED) {
- index = 2;
- }
- trap_R_SetColor(color);
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[index] );
- }
- }
- }
-}
-
-
-static void CG_DrawCTFPowerUp(rectDef_t *rect) {
- int value;
-
- if (cgs.gametype < GT_CTF) {
- return;
- }
- value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP];
- if ( value ) {
- CG_RegisterItemVisuals( value );
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_items[ value ].icon );
- }
-}
-
-
-
-static void CG_DrawTeamColor(rectDef_t *rect, vec4_t color) {
- CG_DrawTeamBackground(rect->x, rect->y, rect->w, rect->h, color[3], cg.snap->ps.persistant[PERS_TEAM]);
-}
-
-static void CG_DrawAreaPowerUp(rectDef_t *rect, int align, float special, float scale, vec4_t color) {
- char num[16];
- int sorted[MAX_POWERUPS];
- int sortedTime[MAX_POWERUPS];
- int i, j, k;
- int active;
- playerState_t *ps;
- int t;
- gitem_t *item;
- float f;
- rectDef_t r2;
- float *inc;
- r2.x = rect->x;
- r2.y = rect->y;
- r2.w = rect->w;
- r2.h = rect->h;
-
- inc = (align == HUD_VERTICAL) ? &r2.y : &r2.x;
-
- ps = &cg.snap->ps;
-
- if ( ps->stats[STAT_HEALTH] <= 0 ) {
- return;
- }
-
- // sort the list by time remaining
- active = 0;
- for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
- if ( !ps->powerups[ i ] ) {
- continue;
- }
- t = ps->powerups[ i ] - cg.time;
- // ZOID--don't draw if the power up has unlimited time (999 seconds)
- // This is true of the CTF flags
- if ( t <= 0 || t >= 999000) {
- continue;
- }
-
- // insert into the list
- for ( j = 0 ; j < active ; j++ ) {
- if ( sortedTime[j] >= t ) {
- for ( k = active - 1 ; k >= j ; k-- ) {
- sorted[k+1] = sorted[k];
- sortedTime[k+1] = sortedTime[k];
- }
- break;
- }
- }
- sorted[j] = i;
- sortedTime[j] = t;
- active++;
- }
-
- // draw the icons and timers
- for ( i = 0 ; i < active ; i++ ) {
- item = BG_FindItemForPowerup( sorted[i] );
-
- if (item) {
- t = ps->powerups[ sorted[i] ];
- if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
- trap_R_SetColor( NULL );
- } else {
- vec4_t modulate;
-
- f = (float)( t - cg.time ) / POWERUP_BLINK_TIME;
- f -= (int)f;
- modulate[0] = modulate[1] = modulate[2] = modulate[3] = f;
- trap_R_SetColor( modulate );
- }
-
- CG_DrawPic( r2.x, r2.y, r2.w * .75, r2.h, trap_R_RegisterShader( item->icon ) );
-
- Com_sprintf (num, sizeof(num), "%i", sortedTime[i] / 1000);
- CG_Text_Paint(r2.x + (r2.w * .75) + 3 , r2.y + r2.h, scale, color, num, 0, 0, 0);
- *inc += r2.w + special;
- }
-
- }
- trap_R_SetColor( NULL );
-
-}
-
-float CG_GetValue(int ownerDraw) {
- centity_t *cent;
- clientInfo_t *ci;
- playerState_t *ps;
-
- cent = &cg_entities[cg.snap->ps.clientNum];
- ps = &cg.snap->ps;
-
- switch (ownerDraw) {
- case CG_SELECTEDPLAYER_ARMOR:
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- return ci->armor;
- break;
- case CG_SELECTEDPLAYER_HEALTH:
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- return ci->health;
- break;
- case CG_PLAYER_ARMOR_VALUE:
- return ps->stats[STAT_ARMOR];
- break;
- case CG_PLAYER_AMMO_VALUE:
- if ( cent->currentState.weapon ) {
- return ps->ammo[cent->currentState.weapon];
- }
- break;
- case CG_PLAYER_SCORE:
- return cg.snap->ps.persistant[PERS_SCORE];
- break;
- case CG_PLAYER_HEALTH:
- return ps->stats[STAT_HEALTH];
- break;
- case CG_RED_SCORE:
- return cgs.scores1;
- break;
- case CG_BLUE_SCORE:
- return cgs.scores2;
- break;
- default:
- break;
- }
- return -1;
-}
-
-qboolean CG_OtherTeamHasFlag(void) {
- if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) {
- int team = cg.snap->ps.persistant[PERS_TEAM];
- if (cgs.gametype == GT_1FCTF) {
- if (team == TEAM_RED && cgs.flagStatus == FLAG_TAKEN_BLUE) {
- return qtrue;
- } else if (team == TEAM_BLUE && cgs.flagStatus == FLAG_TAKEN_RED) {
- return qtrue;
- } else {
- return qfalse;
- }
- } else {
- if (team == TEAM_RED && cgs.redflag == FLAG_TAKEN) {
- return qtrue;
- } else if (team == TEAM_BLUE && cgs.blueflag == FLAG_TAKEN) {
- return qtrue;
- } else {
- return qfalse;
- }
- }
- }
- return qfalse;
-}
-
-qboolean CG_YourTeamHasFlag(void) {
- if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) {
- int team = cg.snap->ps.persistant[PERS_TEAM];
- if (cgs.gametype == GT_1FCTF) {
- if (team == TEAM_RED && cgs.flagStatus == FLAG_TAKEN_RED) {
- return qtrue;
- } else if (team == TEAM_BLUE && cgs.flagStatus == FLAG_TAKEN_BLUE) {
- return qtrue;
- } else {
- return qfalse;
- }
- } else {
- if (team == TEAM_RED && cgs.blueflag == FLAG_TAKEN) {
- return qtrue;
- } else if (team == TEAM_BLUE && cgs.redflag == FLAG_TAKEN) {
- return qtrue;
- } else {
- return qfalse;
- }
- }
- }
- return qfalse;
-}
-
-// THINKABOUTME: should these be exclusive or inclusive..
-//
-qboolean CG_OwnerDrawVisible(int flags) {
-
- if (flags & CG_SHOW_TEAMINFO) {
- return (cg_currentSelectedPlayer.integer == numSortedTeamPlayers);
- }
-
- if (flags & CG_SHOW_NOTEAMINFO) {
- return !(cg_currentSelectedPlayer.integer == numSortedTeamPlayers);
- }
-
- if (flags & CG_SHOW_OTHERTEAMHASFLAG) {
- return CG_OtherTeamHasFlag();
- }
-
- if (flags & CG_SHOW_YOURTEAMHASENEMYFLAG) {
- return CG_YourTeamHasFlag();
- }
-
- if (flags & (CG_SHOW_BLUE_TEAM_HAS_REDFLAG | CG_SHOW_RED_TEAM_HAS_BLUEFLAG)) {
- if (flags & CG_SHOW_BLUE_TEAM_HAS_REDFLAG && (cgs.redflag == FLAG_TAKEN || cgs.flagStatus == FLAG_TAKEN_RED)) {
- return qtrue;
- } else if (flags & CG_SHOW_RED_TEAM_HAS_BLUEFLAG && (cgs.blueflag == FLAG_TAKEN || cgs.flagStatus == FLAG_TAKEN_BLUE)) {
- return qtrue;
- }
- return qfalse;
- }
-
- if (flags & CG_SHOW_ANYTEAMGAME) {
- if( cgs.gametype >= GT_TEAM) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_ANYNONTEAMGAME) {
- if( cgs.gametype < GT_TEAM) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_HARVESTER) {
- if( cgs.gametype == GT_HARVESTER ) {
- return qtrue;
- } else {
- return qfalse;
- }
- }
-
- if (flags & CG_SHOW_ONEFLAG) {
- if( cgs.gametype == GT_1FCTF ) {
- return qtrue;
- } else {
- return qfalse;
- }
- }
-
- if (flags & CG_SHOW_CTF) {
- if( cgs.gametype == GT_CTF ) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_OBELISK) {
- if( cgs.gametype == GT_OBELISK ) {
- return qtrue;
- } else {
- return qfalse;
- }
- }
-
- if (flags & CG_SHOW_HEALTHCRITICAL) {
- if (cg.snap->ps.stats[STAT_HEALTH] < 25) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_HEALTHOK) {
- if (cg.snap->ps.stats[STAT_HEALTH] >= 25) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_SINGLEPLAYER) {
- if( cgs.gametype == GT_SINGLE_PLAYER ) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_TOURNAMENT) {
- if( cgs.gametype == GT_TOURNAMENT ) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_DURINGINCOMINGVOICE) {
- }
-
- if (flags & CG_SHOW_IF_PLAYER_HAS_FLAG) {
- if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
- return qtrue;
- }
- }
- return qfalse;
-}
-
-
-
-static void CG_DrawPlayerHasFlag(rectDef_t *rect, qboolean force2D) {
- int adj = (force2D) ? 0 : 2;
- if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) {
- CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_RED, force2D);
- } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) {
- CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_BLUE, force2D);
- } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) {
- CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_FREE, force2D);
- }
-}
-
-static void CG_DrawAreaSystemChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, systemChat, 0, 0, 0);
-}
-
-static void CG_DrawAreaTeamChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color,teamChat1, 0, 0, 0);
-}
-
-static void CG_DrawAreaChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, teamChat2, 0, 0, 0);
-}
-
-const char *CG_GetKillerText(void) {
- const char *s = "";
- if ( cg.killerName[0] ) {
- s = va("Fragged by %s", cg.killerName );
- }
- return s;
-}
-
-
-static void CG_DrawKiller(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- // fragged by ... line
- if ( cg.killerName[0] ) {
- int x = rect->x + rect->w / 2;
- CG_Text_Paint(x - CG_Text_Width(CG_GetKillerText(), scale, 0) / 2, rect->y + rect->h, scale, color, CG_GetKillerText(), 0, 0, textStyle);
- }
-
-}
-
-
-static void CG_DrawCapFragLimit(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- int limit = (cgs.gametype >= GT_CTF) ? cgs.capturelimit : cgs.fraglimit;
- CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", limit),0, 0, textStyle);
-}
-
-static void CG_Draw1stPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- if (cgs.scores1 != SCORE_NOT_PRESENT) {
- CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores1),0, 0, textStyle);
- }
-}
-
-static void CG_Draw2ndPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- if (cgs.scores2 != SCORE_NOT_PRESENT) {
- CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores2),0, 0, textStyle);
- }
-}
-
-const char *CG_GetGameStatusText(void) {
- const char *s = "";
- if ( cgs.gametype < GT_TEAM) {
- if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
- s = va("%s place with %i",CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),cg.snap->ps.persistant[PERS_SCORE] );
- }
- } else {
- if ( cg.teamScores[0] == cg.teamScores[1] ) {
- s = va("Teams are tied at %i", cg.teamScores[0] );
- } else if ( cg.teamScores[0] >= cg.teamScores[1] ) {
- s = va("Red leads Blue, %i to %i", cg.teamScores[0], cg.teamScores[1] );
- } else {
- s = va("Blue leads Red, %i to %i", cg.teamScores[1], cg.teamScores[0] );
- }
- }
- return s;
-}
-
-static void CG_DrawGameStatus(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GetGameStatusText(), 0, 0, textStyle);
-}
-
-const char *CG_GameTypeString(void) {
- if ( cgs.gametype == GT_FFA ) {
- return "Free For All";
- } else if ( cgs.gametype == GT_TEAM ) {
- return "Team Deathmatch";
- } else if ( cgs.gametype == GT_CTF ) {
- return "Capture the Flag";
- } else if ( cgs.gametype == GT_1FCTF ) {
- return "One Flag CTF";
- } else if ( cgs.gametype == GT_OBELISK ) {
- return "Overload";
- } else if ( cgs.gametype == GT_HARVESTER ) {
- return "Harvester";
- }
- return "";
-}
-static void CG_DrawGameType(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GameTypeString(), 0, 0, textStyle);
-}
-
-static void CG_Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph;
- if (text) {
- const char *s = text;
- float max = *maxX;
- float useScale;
- fontInfo_t *font = &cgDC.Assets.textFont;
- if (scale <= cg_smallFont.value) {
- font = &cgDC.Assets.smallFont;
- } else if (scale > cg_bigFont.value) {
- font = &cgDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- trap_R_SetColor( color );
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- float yadj = useScale * glyph->top;
- if (CG_Text_Width(s, useScale, 1) + x > max) {
- *maxX = 0;
- break;
- }
- CG_Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- x += (glyph->xSkip * useScale) + adjust;
- *maxX = x;
- count++;
- s++;
- }
- }
- trap_R_SetColor( NULL );
- }
-
-}
-
-
-
-#define PIC_WIDTH 12
-
-void CG_DrawNewTeamInfo(rectDef_t *rect, float text_x, float text_y, float scale, vec4_t color, qhandle_t shader) {
- int xx;
- float y;
- int i, j, len, count;
- const char *p;
- vec4_t hcolor;
- float pwidth, lwidth, maxx, leftOver;
- clientInfo_t *ci;
- gitem_t *item;
- qhandle_t h;
-
- // max player name width
- pwidth = 0;
- count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers;
- for (i = 0; i < count; i++) {
- ci = cgs.clientinfo + sortedTeamPlayers[i];
- if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
- len = CG_Text_Width( ci->name, scale, 0);
- if (len > pwidth)
- pwidth = len;
- }
- }
-
- // max location name width
- lwidth = 0;
- for (i = 1; i < MAX_LOCATIONS; i++) {
- p = CG_ConfigString(CS_LOCATIONS + i);
- if (p && *p) {
- len = CG_Text_Width(p, scale, 0);
- if (len > lwidth)
- lwidth = len;
- }
- }
-
- y = rect->y;
-
- for (i = 0; i < count; i++) {
- ci = cgs.clientinfo + sortedTeamPlayers[i];
- if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
-
- xx = rect->x + 1;
- for (j = 0; j <= PW_NUM_POWERUPS; j++) {
- if (ci->powerups & (1 << j)) {
-
- item = BG_FindItemForPowerup( j );
-
- if (item) {
- CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, trap_R_RegisterShader( item->icon ) );
- xx += PIC_WIDTH;
- }
- }
- }
-
- // FIXME: max of 3 powerups shown properly
- xx = rect->x + (PIC_WIDTH * 3) + 2;
-
- CG_GetColorForHealth( ci->health, ci->armor, hcolor );
- trap_R_SetColor(hcolor);
- CG_DrawPic( xx, y + 1, PIC_WIDTH - 2, PIC_WIDTH - 2, cgs.media.heartShader );
-
- //Com_sprintf (st, sizeof(st), "%3i %3i", ci->health, ci->armor);
- //CG_Text_Paint(xx, y + text_y, scale, hcolor, st, 0, 0);
-
- // draw weapon icon
- xx += PIC_WIDTH + 1;
-
-// weapon used is not that useful, use the space for task
-#if 0
- if ( cg_weapons[ci->curWeapon].weaponIcon ) {
- CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, cg_weapons[ci->curWeapon].weaponIcon );
- } else {
- CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, cgs.media.deferShader );
- }
-#endif
-
- trap_R_SetColor(NULL);
- if (cgs.orderPending) {
- // blink the icon
- if ( cg.time > cgs.orderTime - 2500 && (cg.time >> 9 ) & 1 ) {
- h = 0;
- } else {
- h = CG_StatusHandle(cgs.currentOrder);
- }
- } else {
- h = CG_StatusHandle(ci->teamTask);
- }
-
- if (h) {
- CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, h);
- }
-
- xx += PIC_WIDTH + 1;
-
- leftOver = rect->w - xx;
- maxx = xx + leftOver / 3;
-
-
-
- CG_Text_Paint_Limit(&maxx, xx, y + text_y, scale, color, ci->name, 0, 0);
-
- p = CG_ConfigString(CS_LOCATIONS + ci->location);
- if (!p || !*p) {
- p = "unknown";
- }
-
- xx += leftOver / 3 + 2;
- maxx = rect->w - 4;
-
- CG_Text_Paint_Limit(&maxx, xx, y + text_y, scale, color, p, 0, 0);
- y += text_y + 2;
- if ( y + text_y + 2 > rect->y + rect->h ) {
- break;
- }
-
- }
- }
-}
-
-
-void CG_DrawTeamSpectators(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
- if (cg.spectatorLen) {
- float maxX;
-
- if (cg.spectatorWidth == -1) {
- cg.spectatorWidth = 0;
- cg.spectatorPaintX = rect->x + 1;
- cg.spectatorPaintX2 = -1;
- }
-
- if (cg.spectatorOffset > cg.spectatorLen) {
- cg.spectatorOffset = 0;
- cg.spectatorPaintX = rect->x + 1;
- cg.spectatorPaintX2 = -1;
- }
-
- if (cg.time > cg.spectatorTime) {
- cg.spectatorTime = cg.time + 10;
- if (cg.spectatorPaintX <= rect->x + 2) {
- if (cg.spectatorOffset < cg.spectatorLen) {
- cg.spectatorPaintX += CG_Text_Width(&cg.spectatorList[cg.spectatorOffset], scale, 1) - 1;
- cg.spectatorOffset++;
- } else {
- cg.spectatorOffset = 0;
- if (cg.spectatorPaintX2 >= 0) {
- cg.spectatorPaintX = cg.spectatorPaintX2;
- } else {
- cg.spectatorPaintX = rect->x + rect->w - 2;
- }
- cg.spectatorPaintX2 = -1;
- }
- } else {
- cg.spectatorPaintX--;
- if (cg.spectatorPaintX2 >= 0) {
- cg.spectatorPaintX2--;
- }
- }
- }
-
- maxX = rect->x + rect->w - 2;
- CG_Text_Paint_Limit(&maxX, cg.spectatorPaintX, rect->y + rect->h - 3, scale, color, &cg.spectatorList[cg.spectatorOffset], 0, 0);
- if (cg.spectatorPaintX2 >= 0) {
- float maxX2 = rect->x + rect->w - 2;
- CG_Text_Paint_Limit(&maxX2, cg.spectatorPaintX2, rect->y + rect->h - 3, scale, color, cg.spectatorList, 0, cg.spectatorOffset);
- }
- if (cg.spectatorOffset && maxX > 0) {
- // if we have an offset ( we are skipping the first part of the string ) and we fit the string
- if (cg.spectatorPaintX2 == -1) {
- cg.spectatorPaintX2 = rect->x + rect->w - 2;
- }
- } else {
- cg.spectatorPaintX2 = -1;
- }
-
- }
-}
-
-
-
-void CG_DrawMedal(int ownerDraw, rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
- score_t *score = &cg.scores[cg.selectedScore];
- float value = 0;
- char *text = NULL;
- color[3] = 0.25;
-
- switch (ownerDraw) {
- case CG_ACCURACY:
- value = score->accuracy;
- break;
- case CG_ASSISTS:
- value = score->assistCount;
- break;
- case CG_DEFEND:
- value = score->defendCount;
- break;
- case CG_EXCELLENT:
- value = score->excellentCount;
- break;
- case CG_IMPRESSIVE:
- value = score->impressiveCount;
- break;
- case CG_PERFECT:
- value = score->perfect;
- break;
- case CG_GAUNTLET:
- value = score->guantletCount;
- break;
- case CG_CAPTURES:
- value = score->captures;
- break;
- }
-
- if (value > 0) {
- if (ownerDraw != CG_PERFECT) {
- if (ownerDraw == CG_ACCURACY) {
- text = va("%i%%", (int)value);
- if (value > 50) {
- color[3] = 1.0;
- }
- } else {
- text = va("%i", (int)value);
- color[3] = 1.0;
- }
- } else {
- if (value) {
- color[3] = 1.0;
- }
- text = "Wow";
- }
- }
-
- trap_R_SetColor(color);
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
-
- if (text) {
- color[3] = 1.0;
- value = CG_Text_Width(text, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h + 10 , scale, color, text, 0, 0, 0);
- }
- trap_R_SetColor(NULL);
-
-}
-
-
-//
-void CG_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- rectDef_t rect;
-
- if ( cg_drawStatus.integer == 0 ) {
- return;
- }
-
- //if (ownerDrawFlags != 0 && !CG_OwnerDrawVisible(ownerDrawFlags)) {
- // return;
- //}
-
- rect.x = x;
- rect.y = y;
- rect.w = w;
- rect.h = h;
-
- switch (ownerDraw) {
- case CG_PLAYER_ARMOR_ICON:
- CG_DrawPlayerArmorIcon(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
- break;
- case CG_PLAYER_ARMOR_ICON2D:
- CG_DrawPlayerArmorIcon(&rect, qtrue);
- break;
- case CG_PLAYER_ARMOR_VALUE:
- CG_DrawPlayerArmorValue(&rect, scale, color, shader, textStyle);
- break;
- case CG_PLAYER_AMMO_ICON:
- CG_DrawPlayerAmmoIcon(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
- break;
- case CG_PLAYER_AMMO_ICON2D:
- CG_DrawPlayerAmmoIcon(&rect, qtrue);
- break;
- case CG_PLAYER_AMMO_VALUE:
- CG_DrawPlayerAmmoValue(&rect, scale, color, shader, textStyle);
- break;
- case CG_SELECTEDPLAYER_HEAD:
- CG_DrawSelectedPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY, qfalse);
- break;
- case CG_VOICE_HEAD:
- CG_DrawSelectedPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY, qtrue);
- break;
- case CG_VOICE_NAME:
- CG_DrawSelectedPlayerName(&rect, scale, color, qtrue, textStyle);
- break;
- case CG_SELECTEDPLAYER_STATUS:
- CG_DrawSelectedPlayerStatus(&rect);
- break;
- case CG_SELECTEDPLAYER_ARMOR:
- CG_DrawSelectedPlayerArmor(&rect, scale, color, shader, textStyle);
- break;
- case CG_SELECTEDPLAYER_HEALTH:
- CG_DrawSelectedPlayerHealth(&rect, scale, color, shader, textStyle);
- break;
- case CG_SELECTEDPLAYER_NAME:
- CG_DrawSelectedPlayerName(&rect, scale, color, qfalse, textStyle);
- break;
- case CG_SELECTEDPLAYER_LOCATION:
- CG_DrawSelectedPlayerLocation(&rect, scale, color, textStyle);
- break;
- case CG_SELECTEDPLAYER_WEAPON:
- CG_DrawSelectedPlayerWeapon(&rect);
- break;
- case CG_SELECTEDPLAYER_POWERUP:
- CG_DrawSelectedPlayerPowerup(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
- break;
- case CG_PLAYER_HEAD:
- CG_DrawPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
- break;
- case CG_PLAYER_ITEM:
- CG_DrawPlayerItem(&rect, scale, ownerDrawFlags & CG_SHOW_2DONLY);
- break;
- case CG_PLAYER_SCORE:
- CG_DrawPlayerScore(&rect, scale, color, shader, textStyle);
- break;
- case CG_PLAYER_HEALTH:
- CG_DrawPlayerHealth(&rect, scale, color, shader, textStyle);
- break;
- case CG_RED_SCORE:
- CG_DrawRedScore(&rect, scale, color, shader, textStyle);
- break;
- case CG_BLUE_SCORE:
- CG_DrawBlueScore(&rect, scale, color, shader, textStyle);
- break;
- case CG_RED_NAME:
- CG_DrawRedName(&rect, scale, color, textStyle);
- break;
- case CG_BLUE_NAME:
- CG_DrawBlueName(&rect, scale, color, textStyle);
- break;
- case CG_BLUE_FLAGHEAD:
- CG_DrawBlueFlagHead(&rect);
- break;
- case CG_BLUE_FLAGSTATUS:
- CG_DrawBlueFlagStatus(&rect, shader);
- break;
- case CG_BLUE_FLAGNAME:
- CG_DrawBlueFlagName(&rect, scale, color, textStyle);
- break;
- case CG_RED_FLAGHEAD:
- CG_DrawRedFlagHead(&rect);
- break;
- case CG_RED_FLAGSTATUS:
- CG_DrawRedFlagStatus(&rect, shader);
- break;
- case CG_RED_FLAGNAME:
- CG_DrawRedFlagName(&rect, scale, color, textStyle);
- break;
- case CG_HARVESTER_SKULLS:
- CG_HarvesterSkulls(&rect, scale, color, qfalse, textStyle);
- break;
- case CG_HARVESTER_SKULLS2D:
- CG_HarvesterSkulls(&rect, scale, color, qtrue, textStyle);
- break;
- case CG_ONEFLAG_STATUS:
- CG_OneFlagStatus(&rect);
- break;
- case CG_PLAYER_LOCATION:
- CG_DrawPlayerLocation(&rect, scale, color, textStyle);
- break;
- case CG_TEAM_COLOR:
- CG_DrawTeamColor(&rect, color);
- break;
- case CG_CTF_POWERUP:
- CG_DrawCTFPowerUp(&rect);
- break;
- case CG_AREA_POWERUP:
- CG_DrawAreaPowerUp(&rect, align, special, scale, color);
- break;
- case CG_PLAYER_STATUS:
- CG_DrawPlayerStatus(&rect);
- break;
- case CG_PLAYER_HASFLAG:
- CG_DrawPlayerHasFlag(&rect, qfalse);
- break;
- case CG_PLAYER_HASFLAG2D:
- CG_DrawPlayerHasFlag(&rect, qtrue);
- break;
- case CG_AREA_SYSTEMCHAT:
- CG_DrawAreaSystemChat(&rect, scale, color, shader);
- break;
- case CG_AREA_TEAMCHAT:
- CG_DrawAreaTeamChat(&rect, scale, color, shader);
- break;
- case CG_AREA_CHAT:
- CG_DrawAreaChat(&rect, scale, color, shader);
- break;
- case CG_GAME_TYPE:
- CG_DrawGameType(&rect, scale, color, shader, textStyle);
- break;
- case CG_GAME_STATUS:
- CG_DrawGameStatus(&rect, scale, color, shader, textStyle);
- break;
- case CG_KILLER:
- CG_DrawKiller(&rect, scale, color, shader, textStyle);
- break;
- case CG_ACCURACY:
- case CG_ASSISTS:
- case CG_DEFEND:
- case CG_EXCELLENT:
- case CG_IMPRESSIVE:
- case CG_PERFECT:
- case CG_GAUNTLET:
- case CG_CAPTURES:
- CG_DrawMedal(ownerDraw, &rect, scale, color, shader);
- break;
- case CG_SPECTATORS:
- CG_DrawTeamSpectators(&rect, scale, color, shader);
- break;
- case CG_TEAMINFO:
- if (cg_currentSelectedPlayer.integer == numSortedTeamPlayers) {
- CG_DrawNewTeamInfo(&rect, text_x, text_y, scale, color, shader);
- }
- break;
- case CG_CAPFRAGLIMIT:
- CG_DrawCapFragLimit(&rect, scale, color, shader, textStyle);
- break;
- case CG_1STPLACE:
- CG_Draw1stPlace(&rect, scale, color, shader, textStyle);
- break;
- case CG_2NDPLACE:
- CG_Draw2ndPlace(&rect, scale, color, shader, textStyle);
- break;
- default:
- break;
- }
-}
-
-void CG_MouseEvent(int x, int y) {
- int n;
-
- if ( (cg.predictedPlayerState.pm_type == PM_NORMAL || cg.predictedPlayerState.pm_type == PM_SPECTATOR) && cg.showScores == qfalse) {
- trap_Key_SetCatcher(0);
- return;
- }
-
- cgs.cursorX+= x;
- if (cgs.cursorX < 0)
- cgs.cursorX = 0;
- else if (cgs.cursorX > 640)
- cgs.cursorX = 640;
-
- cgs.cursorY += y;
- if (cgs.cursorY < 0)
- cgs.cursorY = 0;
- else if (cgs.cursorY > 480)
- cgs.cursorY = 480;
-
- n = Display_CursorType(cgs.cursorX, cgs.cursorY);
- cgs.activeCursor = 0;
- if (n == CURSOR_ARROW) {
- cgs.activeCursor = cgs.media.selectCursor;
- } else if (n == CURSOR_SIZER) {
- cgs.activeCursor = cgs.media.sizeCursor;
- }
-
- if (cgs.capturedItem) {
- Display_MouseMove(cgs.capturedItem, x, y);
- } else {
- Display_MouseMove(NULL, cgs.cursorX, cgs.cursorY);
- }
-
-}
-
-/*
-==================
-CG_HideTeamMenus
-==================
-
-*/
-void CG_HideTeamMenu( void ) {
- Menus_CloseByName("teamMenu");
- Menus_CloseByName("getMenu");
-}
-
-/*
-==================
-CG_ShowTeamMenus
-==================
-
-*/
-void CG_ShowTeamMenu( void ) {
- Menus_OpenByName("teamMenu");
-}
-
-
-
-
-/*
-==================
-CG_EventHandling
-==================
- type 0 - no event handling
- 1 - team menu
- 2 - hud editor
-
-*/
-void CG_EventHandling(int type) {
- cgs.eventHandling = type;
- if (type == CGAME_EVENT_NONE) {
- CG_HideTeamMenu();
- } else if (type == CGAME_EVENT_TEAMMENU) {
- //CG_ShowTeamMenu();
- } else if (type == CGAME_EVENT_SCOREBOARD) {
- }
-
-}
-
-
-
-void CG_KeyEvent(int key, qboolean down) {
-
- if (!down) {
- return;
- }
-
- if ( cg.predictedPlayerState.pm_type == PM_NORMAL || (cg.predictedPlayerState.pm_type == PM_SPECTATOR && cg.showScores == qfalse)) {
- CG_EventHandling(CGAME_EVENT_NONE);
- trap_Key_SetCatcher(0);
- return;
- }
-
- //if (key == trap_Key_GetKey("teamMenu") || !Display_CaptureItem(cgs.cursorX, cgs.cursorY)) {
- // if we see this then we should always be visible
- // CG_EventHandling(CGAME_EVENT_NONE);
- // trap_Key_SetCatcher(0);
- //}
-
-
-
- Display_HandleKey(key, down, cgs.cursorX, cgs.cursorY);
-
- if (cgs.capturedItem) {
- cgs.capturedItem = NULL;
- } else {
- if (key == K_MOUSE2 && down) {
- cgs.capturedItem = Display_CaptureItem(cgs.cursorX, cgs.cursorY);
- }
- }
-}
-
-int CG_ClientNumFromName(const char *p) {
- int i;
- for (i = 0; i < cgs.maxclients; i++) {
- if (cgs.clientinfo[i].infoValid && Q_stricmp(cgs.clientinfo[i].name, p) == 0) {
- return i;
- }
- }
- return -1;
-}
-
-void CG_ShowResponseHead(void) {
- Menus_OpenByName("voiceMenu");
- trap_Cvar_Set("cl_conXOffset", "72");
- cg.voiceTime = cg.time;
-}
-
-void CG_RunMenuScript(char **args) {
-}
-
-
-void CG_GetTeamColor(vec4_t *color) {
- if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED) {
- (*color)[0] = 1.0f;
- (*color)[3] = 0.25f;
- (*color)[1] = (*color)[2] = 0.0f;
- } else if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE) {
- (*color)[0] = (*color)[1] = 0.0f;
- (*color)[2] = 1.0f;
- (*color)[3] = 0.25f;
- } else {
- (*color)[0] = (*color)[2] = 0.0f;
- (*color)[1] = 0.17f;
- (*color)[3] = 0.25f;
- }
-}
-
diff --git a/engine/code/cgame/cg_particles.c b/engine/code/cgame/cg_particles.c
deleted file mode 100644
index 72c077f..0000000
--- a/engine/code/cgame/cg_particles.c
+++ /dev/null
@@ -1,2018 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// Rafael particles
-// cg_particles.c
-
-#include "cg_local.h"
-
-#define BLOODRED 2
-#define EMISIVEFADE 3
-#define GREY75 4
-
-typedef struct particle_s
-{
- struct particle_s *next;
-
- float time;
- float endtime;
-
- vec3_t org;
- vec3_t vel;
- vec3_t accel;
- int color;
- float colorvel;
- float alpha;
- float alphavel;
- int type;
- qhandle_t pshader;
-
- float height;
- float width;
-
- float endheight;
- float endwidth;
-
- float start;
- float end;
-
- float startfade;
- qboolean rotate;
- int snum;
-
- qboolean link;
-
- // Ridah
- int shaderAnim;
- int roll;
-
- int accumroll;
-
-} cparticle_t;
-
-typedef enum
-{
- P_NONE,
- P_WEATHER,
- P_FLAT,
- P_SMOKE,
- P_ROTATE,
- P_WEATHER_TURBULENT,
- P_ANIM, // Ridah
- P_BAT,
- P_BLEED,
- P_FLAT_SCALEUP,
- P_FLAT_SCALEUP_FADE,
- P_WEATHER_FLURRY,
- P_SMOKE_IMPACT,
- P_BUBBLE,
- P_BUBBLE_TURBULENT,
- P_SPRITE
-} particle_type_t;
-
-#define MAX_SHADER_ANIMS 32
-#define MAX_SHADER_ANIM_FRAMES 64
-
-static char *shaderAnimNames[MAX_SHADER_ANIMS] = {
- "explode1",
- "blacksmokeanim",
- "twiltb2",
- "expblue",
- "blacksmokeanimb", // uses 'explode1' sequence
- "blood",
- NULL
-};
-static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];
-static int shaderAnimCounts[MAX_SHADER_ANIMS] = {
- 23,
- 25,
- 45,
- 25,
- 23,
- 5,
-};
-static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = {
- 1.405f,
- 1.0f,
- 1.0f,
- 1.0f,
- 1.0f,
- 1.0f,
-};
-static int numShaderAnims;
-// done.
-
-#define PARTICLE_GRAVITY 40
-#define MAX_PARTICLES 1024 * 8
-
-cparticle_t *active_particles, *free_particles;
-cparticle_t particles[MAX_PARTICLES];
-int cl_numparticles = MAX_PARTICLES;
-
-qboolean initparticles = qfalse;
-vec3_t vforward, vright, vup;
-vec3_t rforward, rright, rup;
-
-float oldtime;
-
-/*
-===============
-CL_ClearParticles
-===============
-*/
-void CG_ClearParticles (void)
-{
- int i;
-
- memset( particles, 0, sizeof(particles) );
-
- free_particles = &particles[0];
- active_particles = NULL;
-
- for (i=0 ;i<cl_numparticles ; i++)
- {
- particles[i].next = &particles[i+1];
- particles[i].type = 0;
- }
- particles[cl_numparticles-1].next = NULL;
-
- oldtime = cg.time;
-
- // Ridah, init the shaderAnims
- for (i=0; shaderAnimNames[i]; i++) {
- int j;
-
- for (j=0; j<shaderAnimCounts[i]; j++) {
- shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) );
- }
- }
- numShaderAnims = i;
- // done.
-
- initparticles = qtrue;
-}
-
-
-/*
-=====================
-CG_AddParticleToScene
-=====================
-*/
-void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)
-{
-
- vec3_t point;
- polyVert_t verts[4];
- float width;
- float height;
- float time, time2;
- float ratio;
- float invratio;
- vec3_t color;
- polyVert_t TRIverts[3];
- vec3_t rright2, rup2;
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY
- || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {// create a front facing polygon
-
- if (p->type != P_WEATHER_FLURRY)
- {
- if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {
- if (org[2] > p->end)
- {
- p->time = cg.time;
- VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
-
- p->org[2] = ( p->start + crandom () * 4 );
-
-
- if (p->type == P_BUBBLE_TURBULENT)
- {
- p->vel[0] = crandom() * 4;
- p->vel[1] = crandom() * 4;
- }
-
- }
- }
- else
- {
- if (org[2] < p->end)
- {
- p->time = cg.time;
- VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
-
- while (p->org[2] < p->end)
- {
- p->org[2] += (p->start - p->end);
- }
-
-
- if (p->type == P_WEATHER_TURBULENT)
- {
- p->vel[0] = crandom() * 16;
- p->vel[1] = crandom() * 16;
- }
-
- }
- }
-
-
- // Rafael snow pvs check
- if (!p->link)
- return;
-
- p->alpha = 1;
- }
-
- // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp
- if (Distance( cg.snap->ps.origin, org ) > 1024) {
- return;
- }
- // done.
-
- if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {
- VectorMA (org, -p->height, vup, point);
- VectorMA (point, -p->width, vright, point);
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, -p->height, vup, point);
- VectorMA (point, p->width, vright, point);
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, vup, point);
- VectorMA (point, p->width, vright, point);
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, vup, point);
- VectorMA (point, -p->width, vright, point);
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255 * p->alpha;
- }
- else
- {
- VectorMA (org, -p->height, vup, point);
- VectorMA (point, -p->width, vright, point);
- VectorCopy( point, TRIverts[0].xyz );
- TRIverts[0].st[0] = 1;
- TRIverts[0].st[1] = 0;
- TRIverts[0].modulate[0] = 255;
- TRIverts[0].modulate[1] = 255;
- TRIverts[0].modulate[2] = 255;
- TRIverts[0].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, vup, point);
- VectorMA (point, -p->width, vright, point);
- VectorCopy (point, TRIverts[1].xyz);
- TRIverts[1].st[0] = 0;
- TRIverts[1].st[1] = 0;
- TRIverts[1].modulate[0] = 255;
- TRIverts[1].modulate[1] = 255;
- TRIverts[1].modulate[2] = 255;
- TRIverts[1].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, vup, point);
- VectorMA (point, p->width, vright, point);
- VectorCopy (point, TRIverts[2].xyz);
- TRIverts[2].st[0] = 0;
- TRIverts[2].st[1] = 1;
- TRIverts[2].modulate[0] = 255;
- TRIverts[2].modulate[1] = 255;
- TRIverts[2].modulate[2] = 255;
- TRIverts[2].modulate[3] = 255 * p->alpha;
- }
-
- }
- else if (p->type == P_SPRITE)
- {
- vec3_t rr, ru;
- vec3_t rotate_ang;
-
- VectorSet (color, 1.0, 1.0, 1.0);
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (p->roll) {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
-
- if (p->roll) {
- VectorMA (org, -height, ru, point);
- VectorMA (point, -width, rr, point);
- } else {
- VectorMA (org, -height, vup, point);
- VectorMA (point, -width, vright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*height, ru, point);
- } else {
- VectorMA (point, 2*height, vup, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*width, rr, point);
- } else {
- VectorMA (point, 2*width, vright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, -2*height, ru, point);
- } else {
- VectorMA (point, -2*height, vup, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
- }
- else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)
- {// create a front rotating facing polygon
-
- if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {
- return;
- }
-
- if (p->color == BLOODRED)
- VectorSet (color, 0.22f, 0.0f, 0.0f);
- else if (p->color == GREY75)
- {
- float len;
- float greyit;
- float val;
- len = Distance (cg.snap->ps.origin, org);
- if (!len)
- len = 1;
-
- val = 4096/len;
- greyit = 0.25 * val;
- if (greyit > 0.5)
- greyit = 0.5;
-
- VectorSet (color, greyit, greyit, greyit);
- }
- else
- VectorSet (color, 1.0, 1.0, 1.0);
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- if (cg.time > p->startfade)
- {
- invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );
-
- if (p->color == EMISIVEFADE)
- {
- float fval;
- fval = (invratio * invratio);
- if (fval < 0)
- fval = 0;
- VectorSet (color, fval , fval , fval );
- }
- invratio *= p->alpha;
- }
- else
- invratio = 1 * p->alpha;
-
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
- invratio = 1;
-
- if (invratio > 1)
- invratio = 1;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (p->type != P_SMOKE_IMPACT)
- {
- vec3_t temp;
-
- vectoangles (rforward, temp);
- p->accumroll += p->roll;
- temp[ROLL] += p->accumroll * 0.1;
- AngleVectors ( temp, NULL, rright2, rup2);
- }
- else
- {
- VectorCopy (rright, rright2);
- VectorCopy (rup, rup2);
- }
-
- if (p->rotate)
- {
- VectorMA (org, -height, rup2, point);
- VectorMA (point, -width, rright2, point);
- }
- else
- {
- VectorMA (org, -p->height, vup, point);
- VectorMA (point, -p->width, vright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255 * color[0];
- verts[0].modulate[1] = 255 * color[1];
- verts[0].modulate[2] = 255 * color[2];
- verts[0].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, -height, rup2, point);
- VectorMA (point, width, rright2, point);
- }
- else
- {
- VectorMA (org, -p->height, vup, point);
- VectorMA (point, p->width, vright, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255 * color[0];
- verts[1].modulate[1] = 255 * color[1];
- verts[1].modulate[2] = 255 * color[2];
- verts[1].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, height, rup2, point);
- VectorMA (point, width, rright2, point);
- }
- else
- {
- VectorMA (org, p->height, vup, point);
- VectorMA (point, p->width, vright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255 * color[0];
- verts[2].modulate[1] = 255 * color[1];
- verts[2].modulate[2] = 255 * color[2];
- verts[2].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, height, rup2, point);
- VectorMA (point, -width, rright2, point);
- }
- else
- {
- VectorMA (org, p->height, vup, point);
- VectorMA (point, -p->width, vright, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255 * color[0];
- verts[3].modulate[1] = 255 * color[1];
- verts[3].modulate[2] = 255 * color[2];
- verts[3].modulate[3] = 255 * invratio;
-
- }
- else if (p->type == P_BLEED)
- {
- vec3_t rr, ru;
- vec3_t rotate_ang;
- float alpha;
-
- alpha = p->alpha;
-
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
- alpha = 1;
-
- if (p->roll)
- {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
- else
- {
- VectorCopy (vup, ru);
- VectorCopy (vright, rr);
- }
-
- VectorMA (org, -p->height, ru, point);
- VectorMA (point, -p->width, rr, point);
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 111;
- verts[0].modulate[1] = 19;
- verts[0].modulate[2] = 9;
- verts[0].modulate[3] = 255 * alpha;
-
- VectorMA (org, -p->height, ru, point);
- VectorMA (point, p->width, rr, point);
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 111;
- verts[1].modulate[1] = 19;
- verts[1].modulate[2] = 9;
- verts[1].modulate[3] = 255 * alpha;
-
- VectorMA (org, p->height, ru, point);
- VectorMA (point, p->width, rr, point);
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 111;
- verts[2].modulate[1] = 19;
- verts[2].modulate[2] = 9;
- verts[2].modulate[3] = 255 * alpha;
-
- VectorMA (org, p->height, ru, point);
- VectorMA (point, -p->width, rr, point);
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 111;
- verts[3].modulate[1] = 19;
- verts[3].modulate[2] = 9;
- verts[3].modulate[3] = 255 * alpha;
-
- }
- else if (p->type == P_FLAT_SCALEUP)
- {
- float width, height;
- float sinR, cosR;
-
- if (p->color == BLOODRED)
- VectorSet (color, 1, 1, 1);
- else
- VectorSet (color, 0.5, 0.5, 0.5);
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (width > p->endwidth)
- width = p->endwidth;
-
- if (height > p->endheight)
- height = p->endheight;
-
- sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);
- cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);
-
- VectorCopy (org, verts[0].xyz);
- verts[0].xyz[0] -= sinR;
- verts[0].xyz[1] -= cosR;
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255 * color[0];
- verts[0].modulate[1] = 255 * color[1];
- verts[0].modulate[2] = 255 * color[2];
- verts[0].modulate[3] = 255;
-
- VectorCopy (org, verts[1].xyz);
- verts[1].xyz[0] -= cosR;
- verts[1].xyz[1] += sinR;
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255 * color[0];
- verts[1].modulate[1] = 255 * color[1];
- verts[1].modulate[2] = 255 * color[2];
- verts[1].modulate[3] = 255;
-
- VectorCopy (org, verts[2].xyz);
- verts[2].xyz[0] += sinR;
- verts[2].xyz[1] += cosR;
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255 * color[0];
- verts[2].modulate[1] = 255 * color[1];
- verts[2].modulate[2] = 255 * color[2];
- verts[2].modulate[3] = 255;
-
- VectorCopy (org, verts[3].xyz);
- verts[3].xyz[0] += cosR;
- verts[3].xyz[1] -= sinR;
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255 * color[0];
- verts[3].modulate[1] = 255 * color[1];
- verts[3].modulate[2] = 255 * color[2];
- verts[3].modulate[3] = 255;
- }
- else if (p->type == P_FLAT)
- {
-
- VectorCopy (org, verts[0].xyz);
- verts[0].xyz[0] -= p->height;
- verts[0].xyz[1] -= p->width;
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- VectorCopy (org, verts[1].xyz);
- verts[1].xyz[0] -= p->height;
- verts[1].xyz[1] += p->width;
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- VectorCopy (org, verts[2].xyz);
- verts[2].xyz[0] += p->height;
- verts[2].xyz[1] += p->width;
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- VectorCopy (org, verts[3].xyz);
- verts[3].xyz[0] += p->height;
- verts[3].xyz[1] -= p->width;
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
-
- }
- // Ridah
- else if (p->type == P_ANIM) {
- vec3_t rr, ru;
- vec3_t rotate_ang;
- int i, j;
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
- if (ratio >= 1.0f) {
- ratio = 0.9999f;
- }
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- // if we are "inside" this sprite, don't draw
- if (Distance( cg.snap->ps.origin, org ) < width/1.5) {
- return;
- }
-
- i = p->shaderAnim;
- j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);
- p->pshader = shaderAnims[i][j];
-
- if (p->roll) {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
-
- if (p->roll) {
- VectorMA (org, -height, ru, point);
- VectorMA (point, -width, rr, point);
- } else {
- VectorMA (org, -height, vup, point);
- VectorMA (point, -width, vright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*height, ru, point);
- } else {
- VectorMA (point, 2*height, vup, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*width, rr, point);
- } else {
- VectorMA (point, 2*width, vright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, -2*height, ru, point);
- } else {
- VectorMA (point, -2*height, vup, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
- }
- // done.
-
- if (!p->pshader) {
-// (SA) temp commented out for DM
-// CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type);
- return;
- }
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)
- trap_R_AddPolyToScene( p->pshader, 3, TRIverts );
- else
- trap_R_AddPolyToScene( p->pshader, 4, verts );
-
-}
-
-// Ridah, made this static so it doesn't interfere with other files
-static float roll = 0.0;
-
-/*
-===============
-CG_AddParticles
-===============
-*/
-void CG_AddParticles (void)
-{
- cparticle_t *p, *next;
- float alpha;
- float time, time2;
- vec3_t org;
- int color;
- cparticle_t *active, *tail;
- int type;
- vec3_t rotate_ang;
-
- if (!initparticles)
- CG_ClearParticles ();
-
- VectorCopy( cg.refdef.viewaxis[0], vforward );
- VectorCopy( cg.refdef.viewaxis[1], vright );
- VectorCopy( cg.refdef.viewaxis[2], vup );
-
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- roll += ((cg.time - oldtime) * 0.1) ;
- rotate_ang[ROLL] += (roll*0.9);
- AngleVectors ( rotate_ang, rforward, rright, rup);
-
- oldtime = cg.time;
-
- active = NULL;
- tail = NULL;
-
- for (p=active_particles ; p ; p=next)
- {
-
- next = p->next;
-
- time = (cg.time - p->time)*0.001;
-
- alpha = p->alpha + time*p->alphavel;
- if (alpha <= 0)
- { // faded out
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
-
- continue;
- }
-
- }
-
- if (p->type == P_WEATHER_FLURRY)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
-
- continue;
- }
- }
-
-
- if (p->type == P_FLAT_SCALEUP_FADE)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- }
-
- if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {
- // temporary sprite
- CG_AddParticleToScene (p, p->org, alpha);
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- p->next = NULL;
- if (!tail)
- active = tail = p;
- else
- {
- tail->next = p;
- tail = p;
- }
-
- if (alpha > 1.0)
- alpha = 1;
-
- color = p->color;
-
- time2 = time*time;
-
- org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
- org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
- org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
-
- type = p->type;
-
- CG_AddParticleToScene (p, org, alpha);
- }
-
- active_particles = active;
-}
-
-/*
-======================
-CG_AddParticles
-======================
-*/
-void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
- qboolean turb = qtrue;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.90f;
- p->alphavel = 0;
-
- p->start = cent->currentState.origin2[0];
- p->end = cent->currentState.origin2[1];
-
- p->endtime = cg.time + cent->currentState.time;
- p->startfade = cg.time + cent->currentState.time2;
-
- p->pshader = pshader;
-
- if (rand()%100 > 90)
- {
- p->height = 32;
- p->width = 32;
- p->alpha = 0.10f;
- }
- else
- {
- p->height = 1;
- p->width = 1;
- }
-
- p->vel[2] = -20;
-
- p->type = P_WEATHER_FLURRY;
-
- if (turb)
- p->vel[2] = -10;
-
- VectorCopy(cent->currentState.origin, p->org);
-
- p->org[0] = p->org[0];
- p->org[1] = p->org[1];
- p->org[2] = p->org[2];
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16);
- p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16);
- p->vel[2] += cent->currentState.angles[2];
-
- if (turb)
- {
- p->accel[0] = crandom () * 16;
- p->accel[1] = crandom () * 16;
- }
-
-}
-
-void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.40f;
- p->alphavel = 0;
- p->start = origin[2];
- p->end = origin2[2];
- p->pshader = pshader;
- p->height = 1;
- p->width = 1;
-
- p->vel[2] = -50;
-
- if (turb)
- {
- p->type = P_WEATHER_TURBULENT;
- p->vel[2] = -50 * 1.3;
- }
- else
- {
- p->type = P_WEATHER;
- }
-
- VectorCopy(origin, p->org);
-
- p->org[0] = p->org[0] + ( crandom() * range);
- p->org[1] = p->org[1] + ( crandom() * range);
- p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- if (turb)
- {
- p->vel[0] = crandom() * 16;
- p->vel[1] = crandom() * 16;
- }
-
- // Rafael snow pvs check
- p->snum = snum;
- p->link = qtrue;
-
-}
-
-void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
-{
- cparticle_t *p;
- float randsize;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.40f;
- p->alphavel = 0;
- p->start = origin[2];
- p->end = origin2[2];
- p->pshader = pshader;
-
- randsize = 1 + (crandom() * 0.5);
-
- p->height = randsize;
- p->width = randsize;
-
- p->vel[2] = 50 + ( crandom() * 10 );
-
- if (turb)
- {
- p->type = P_BUBBLE_TURBULENT;
- p->vel[2] = 50 * 1.3;
- }
- else
- {
- p->type = P_BUBBLE;
- }
-
- VectorCopy(origin, p->org);
-
- p->org[0] = p->org[0] + ( crandom() * range);
- p->org[1] = p->org[1] + ( crandom() * range);
- p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- if (turb)
- {
- p->vel[0] = crandom() * 4;
- p->vel[1] = crandom() * 4;
- }
-
- // Rafael snow pvs check
- p->snum = snum;
- p->link = qtrue;
-
-}
-
-void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent)
-{
-
- // using cent->density = enttime
- // cent->frame = startfade
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSmoke == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + cent->currentState.time;
- p->startfade = cg.time + cent->currentState.time2;
-
- p->color = 0;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->start = cent->currentState.origin[2];
- p->end = cent->currentState.origin2[2];
- p->pshader = pshader;
- p->rotate = qfalse;
- p->height = 8;
- p->width = 8;
- p->endheight = 32;
- p->endwidth = 32;
- p->type = P_SMOKE;
-
- VectorCopy(cent->currentState.origin, p->org);
-
- p->vel[0] = p->vel[1] = 0;
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[2] = 5;
-
- if (cent->currentState.frame == 1)// reverse gravity
- p->vel[2] *= -1;
-
- p->roll = 8 + (crandom() * 4);
-}
-
-
-void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration)
-{
-
- cparticle_t *p;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + duration;
- p->startfade = cg.time + duration/2;
-
- p->color = EMISIVEFADE;
- p->alpha = 1.0;
- p->alphavel = 0;
-
- p->height = 0.5;
- p->width = 0.5;
- p->endheight = 0.5;
- p->endwidth = 0.5;
-
- p->pshader = cgs.media.tracerShader;
-
- p->type = P_SMOKE;
-
- VectorCopy(org, p->org);
-
- p->vel[0] = vel[0];
- p->vel[1] = vel[1];
- p->vel[2] = vel[2];
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->accel[2] = -60;
- p->vel[2] += -20;
-
-}
-
-/*
-======================
-CG_ParticleExplosion
-======================
-*/
-
-void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd)
-{
- cparticle_t *p;
- int anim;
-
- if (animStr < (char *)10)
- CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" );
-
- // find the animation string
- for (anim=0; shaderAnimNames[anim]; anim++) {
- if (!Q_stricmp( animStr, shaderAnimNames[anim] ))
- break;
- }
- if (!shaderAnimNames[anim]) {
- CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr);
- return;
- }
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
-
- if (duration < 0) {
- duration *= -1;
- p->roll = 0;
- } else {
- p->roll = crandom()*179;
- }
-
- p->shaderAnim = anim;
-
- p->width = sizeStart;
- p->height = sizeStart*shaderAnimSTRatio[anim]; // for sprites that are stretch in either direction
-
- p->endheight = sizeEnd;
- p->endwidth = sizeEnd*shaderAnimSTRatio[anim];
-
- p->endtime = cg.time + duration;
-
- p->type = P_ANIM;
-
- VectorCopy( origin, p->org );
- VectorCopy( vel, p->vel );
- VectorClear( p->accel );
-
-}
-
-// Rafael Shrapnel
-void CG_AddParticleShrapnel (localEntity_t *le)
-{
- return;
-}
-// done.
-
-int CG_NewParticleArea (int num)
-{
- // const char *str;
- char *str;
- char *token;
- int type;
- vec3_t origin, origin2;
- int i;
- float range = 0;
- int turb;
- int numparticles;
- int snum;
-
- str = (char *) CG_ConfigString (num);
- if (!str[0])
- return (0);
-
- // returns type 128 64 or 32
- token = COM_Parse (&str);
- type = atoi (token);
-
- if (type == 1)
- range = 128;
- else if (type == 2)
- range = 64;
- else if (type == 3)
- range = 32;
- else if (type == 0)
- range = 256;
- else if (type == 4)
- range = 8;
- else if (type == 5)
- range = 16;
- else if (type == 6)
- range = 32;
- else if (type == 7)
- range = 64;
-
-
- for (i=0; i<3; i++)
- {
- token = COM_Parse (&str);
- origin[i] = atof (token);
- }
-
- for (i=0; i<3; i++)
- {
- token = COM_Parse (&str);
- origin2[i] = atof (token);
- }
-
- token = COM_Parse (&str);
- numparticles = atoi (token);
-
- token = COM_Parse (&str);
- turb = atoi (token);
-
- token = COM_Parse (&str);
- snum = atoi (token);
-
- for (i=0; i<numparticles; i++)
- {
- if (type >= 4)
- CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
- else
- CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
- }
-
- return (1);
-}
-
-void CG_SnowLink (centity_t *cent, qboolean particleOn)
-{
- cparticle_t *p, *next;
- int id;
-
- id = cent->currentState.frame;
-
- for (p=active_particles ; p ; p=next)
- {
- next = p->next;
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT)
- {
- if (p->snum == id)
- {
- if (particleOn)
- p->link = qtrue;
- else
- p->link = qfalse;
- }
- }
-
- }
-}
-
-void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 0.25;
- p->alphavel = 0;
- p->roll = crandom()*179;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + 1000;
- p->startfade = cg.time + 100;
-
- p->width = rand()%4 + 8;
- p->height = rand()%4 + 8;
-
- p->endheight = p->height *2;
- p->endwidth = p->width * 2;
-
- p->endtime = cg.time + 500;
-
- p->type = P_SMOKE_IMPACT;
-
- VectorCopy( origin, p->org );
- VectorSet(p->vel, 0, 0, 20);
- VectorSet(p->accel, 0, 0, 20);
-
- p->rotate = qtrue;
-}
-
-void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + duration;
-
- if (fleshEntityNum)
- p->startfade = cg.time;
- else
- p->startfade = cg.time + 100;
-
- p->width = 4;
- p->height = 4;
-
- p->endheight = 4+rand()%3;
- p->endwidth = p->endheight;
-
- p->type = P_SMOKE;
-
- VectorCopy( start, p->org );
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = -20;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->color = BLOODRED;
- p->alpha = 0.75;
-
-}
-
-void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
-
- int time;
- int time2;
- float ratio;
-
- float duration = 1500;
-
- time = cg.time;
- time2 = cg.time + cent->currentState.time;
-
- ratio =(float)1 - ((float)time / (float)time2);
-
- if (!pshader)
- CG_Printf ("CG_Particle_OilParticle == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + duration;
-
- p->startfade = p->endtime;
-
- p->width = 1;
- p->height = 3;
-
- p->endheight = 3;
- p->endwidth = 1;
-
- p->type = P_SMOKE;
-
- VectorCopy(cent->currentState.origin, p->org );
-
- p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio));
- p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio));
- p->vel[2] = (cent->currentState.origin2[2]);
-
- p->snum = 1.0f;
-
- VectorClear( p->accel );
-
- p->accel[2] = -20;
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
-}
-
-
-void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_Particle_OilSlick == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- if (cent->currentState.angles2[2])
- p->endtime = cg.time + cent->currentState.angles2[2];
- else
- p->endtime = cg.time + 60000;
-
- p->startfade = p->endtime;
-
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- if (cent->currentState.angles2[0] || cent->currentState.angles2[1])
- {
- p->width = cent->currentState.angles2[0];
- p->height = cent->currentState.angles2[0];
-
- p->endheight = cent->currentState.angles2[1];
- p->endwidth = cent->currentState.angles2[1];
- }
- else
- {
- p->width = 8;
- p->height = 8;
-
- p->endheight = 16;
- p->endwidth = 16;
- }
-
- p->type = P_FLAT_SCALEUP;
-
- p->snum = 1.0;
-
- VectorCopy(cent->currentState.origin, p->org );
-
- p->org[2]+= 0.55 + (crandom() * 0.5);
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = 0;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
-}
-
-void CG_OilSlickRemove (centity_t *cent)
-{
- cparticle_t *p, *next;
- int id;
-
- id = 1.0f;
-
- if (!id)
- CG_Printf ("CG_OilSlickRevove NULL id\n");
-
- for (p=active_particles ; p ; p=next)
- {
- next = p->next;
-
- if (p->type == P_FLAT_SCALEUP)
- {
- if (p->snum == id)
- {
- p->endtime = cg.time + 100;
- p->startfade = p->endtime;
- p->type = P_FLAT_SCALEUP_FADE;
-
- }
- }
-
- }
-}
-
-qboolean ValidBloodPool (vec3_t start)
-{
-#define EXTRUDE_DIST 0.5
-
- vec3_t angles;
- vec3_t right, up;
- vec3_t this_pos, x_pos, center_pos, end_pos;
- float x, y;
- float fwidth, fheight;
- trace_t trace;
- vec3_t normal;
-
- fwidth = 16;
- fheight = 16;
-
- VectorSet (normal, 0, 0, 1);
-
- vectoangles (normal, angles);
- AngleVectors (angles, NULL, right, up);
-
- VectorMA (start, EXTRUDE_DIST, normal, center_pos);
-
- for (x= -fwidth/2; x<fwidth; x+= fwidth)
- {
- VectorMA (center_pos, x, right, x_pos);
-
- for (y= -fheight/2; y<fheight; y+= fheight)
- {
- VectorMA (x_pos, y, up, this_pos);
- VectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos);
-
- CG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID);
-
-
- if (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world
- return qfalse;
-
- if (!(!trace.startsolid && trace.fraction < 1))
- return qfalse;
-
- }
- }
-
- return qtrue;
-}
-
-void CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr)
-{
- cparticle_t *p;
- qboolean legit;
- vec3_t start;
- float rndSize;
-
- if (!pshader)
- CG_Printf ("CG_BloodPool pshader == ZERO!\n");
-
- if (!free_particles)
- return;
-
- VectorCopy (tr->endpos, start);
- legit = ValidBloodPool (start);
-
- if (!legit)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + 3000;
- p->startfade = p->endtime;
-
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- rndSize = 0.4 + random()*0.6;
-
- p->width = 8*rndSize;
- p->height = 8*rndSize;
-
- p->endheight = 16*rndSize;
- p->endwidth = 16*rndSize;
-
- p->type = P_FLAT_SCALEUP;
-
- VectorCopy(start, p->org );
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = 0;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
- p->color = BLOODRED;
-}
-
-#define NORMALSIZE 16
-#define LARGESIZE 32
-
-void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir)
-{
- float length;
- float dist;
- float crittersize;
- vec3_t angles, forward;
- vec3_t point;
- cparticle_t *p;
- int i;
-
- dist = 0;
-
- length = VectorLength (dir);
- vectoangles (dir, angles);
- AngleVectors (angles, forward, NULL, NULL);
-
- crittersize = LARGESIZE;
-
- if (length)
- dist = length / crittersize;
-
- if (dist < 1)
- dist = 1;
-
- VectorCopy (origin, point);
-
- for (i=0; i<dist; i++)
- {
- VectorMA (point, crittersize, forward, point);
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = cgs.media.smokePuffShader;
-
- p->endtime = cg.time + 350 + (crandom() * 100);
-
- p->startfade = cg.time;
-
- p->width = LARGESIZE;
- p->height = LARGESIZE;
- p->endheight = LARGESIZE;
- p->endwidth = LARGESIZE;
-
- p->type = P_SMOKE;
-
- VectorCopy( origin, p->org );
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = -1;
-
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->color = BLOODRED;
-
- p->alpha = 0.75;
-
- }
-
-
-}
-
-void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
-{
- cparticle_t *p;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + duration;
- p->startfade = cg.time + duration/2;
-
- p->color = EMISIVEFADE;
- p->alpha = 0.4f;
- p->alphavel = 0;
-
- p->height = 0.5;
- p->width = 0.5;
- p->endheight = 0.5;
- p->endwidth = 0.5;
-
- p->pshader = cgs.media.tracerShader;
-
- p->type = P_SMOKE;
-
- VectorCopy(org, p->org);
-
- p->org[0] += (crandom() * x);
- p->org[1] += (crandom() * y);
-
- p->vel[0] = vel[0];
- p->vel[1] = vel[1];
- p->vel[2] = vel[2];
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[0] += (crandom() * 4);
- p->vel[1] += (crandom() * 4);
- p->vel[2] += (20 + (crandom() * 10)) * speed;
-
- p->accel[0] = crandom () * 4;
- p->accel[1] = crandom () * 4;
-
-}
-
-void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir)
-{
- float length;
- float dist;
- float crittersize;
- vec3_t angles, forward;
- vec3_t point;
- cparticle_t *p;
- int i;
-
- dist = 0;
-
- VectorNegate (dir, dir);
- length = VectorLength (dir);
- vectoangles (dir, angles);
- AngleVectors (angles, forward, NULL, NULL);
-
- crittersize = LARGESIZE;
-
- if (length)
- dist = length / crittersize;
-
- if (dist < 1)
- dist = 1;
-
- VectorCopy (origin, point);
-
- for (i=0; i<dist; i++)
- {
- VectorMA (point, crittersize, forward, point);
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cg.time;
- p->alpha = 5.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = cgs.media.smokePuffShader;
-
- // RF, stay around for long enough to expand and dissipate naturally
- if (length)
- p->endtime = cg.time + 4500 + (crandom() * 3500);
- else
- p->endtime = cg.time + 750 + (crandom() * 500);
-
- p->startfade = cg.time;
-
- p->width = LARGESIZE;
- p->height = LARGESIZE;
-
- // RF, expand while falling
- p->endheight = LARGESIZE*3.0;
- p->endwidth = LARGESIZE*3.0;
-
- if (!length)
- {
- p->width *= 0.2f;
- p->height *= 0.2f;
-
- p->endheight = NORMALSIZE;
- p->endwidth = NORMALSIZE;
- }
-
- p->type = P_SMOKE;
-
- VectorCopy( point, p->org );
-
- p->vel[0] = crandom()*6;
- p->vel[1] = crandom()*6;
- p->vel[2] = random()*20;
-
- // RF, add some gravity/randomness
- p->accel[0] = crandom()*3;
- p->accel[1] = crandom()*3;
- p->accel[2] = -PARTICLE_GRAVITY*0.4;
-
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
- }
-
-
-}
-
-void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = rand()%179;
-
- p->pshader = pshader;
-
- if (duration > 0)
- p->endtime = cg.time + duration;
- else
- p->endtime = duration;
-
- p->startfade = cg.time;
-
- p->width = size;
- p->height = size;
-
- p->endheight = size;
- p->endwidth = size;
-
- p->type = P_SPRITE;
-
- VectorCopy( origin, p->org );
-
- p->rotate = qfalse;
-}
diff --git a/engine/code/cgame/cg_players.c b/engine/code/cgame/cg_players.c
deleted file mode 100644
index 61e26c7..0000000
--- a/engine/code/cgame/cg_players.c
+++ /dev/null
@@ -1,2618 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_players.c -- handle the media and animation for player entities
-#include "cg_local.h"
-
-char *cg_customSoundNames[MAX_CUSTOM_SOUNDS] = {
- "*death1.wav",
- "*death2.wav",
- "*death3.wav",
- "*jump1.wav",
- "*pain25_1.wav",
- "*pain50_1.wav",
- "*pain75_1.wav",
- "*pain100_1.wav",
- "*falling1.wav",
- "*gasp.wav",
- "*drown.wav",
- "*fall1.wav",
- "*taunt.wav"
-};
-
-
-/*
-================
-CG_CustomSound
-
-================
-*/
-sfxHandle_t CG_CustomSound( int clientNum, const char *soundName ) {
- clientInfo_t *ci;
- int i;
-
- if ( soundName[0] != '*' ) {
- return trap_S_RegisterSound( soundName, qfalse );
- }
-
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- clientNum = 0;
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- for ( i = 0 ; i < MAX_CUSTOM_SOUNDS && cg_customSoundNames[i] ; i++ ) {
- if ( !strcmp( soundName, cg_customSoundNames[i] ) ) {
- return ci->sounds[i];
- }
- }
-
- CG_Error( "Unknown custom sound: %s", soundName );
- return 0;
-}
-
-
-
-/*
-=============================================================================
-
-CLIENT INFO
-
-=============================================================================
-*/
-
-/*
-======================
-CG_ParseAnimationFile
-
-Read a configuration file containing animation coutns and rates
-models/players/visor/animation.cfg, etc
-======================
-*/
-static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) {
- char *text_p, *prev;
- int len;
- int i;
- char *token;
- float fps;
- int skip;
- char text[20000];
- fileHandle_t f;
- animation_t *animations;
-
- animations = ci->animations;
-
- // load the file
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( len <= 0 ) {
- return qfalse;
- }
- if ( len >= sizeof( text ) - 1 ) {
- CG_Printf( "File %s too long\n", filename );
- trap_FS_FCloseFile( f );
- return qfalse;
- }
- trap_FS_Read( text, len, f );
- text[len] = 0;
- trap_FS_FCloseFile( f );
-
- // parse the text
- text_p = text;
- skip = 0; // quite the compiler warning
-
- ci->footsteps = FOOTSTEP_NORMAL;
- VectorClear( ci->headOffset );
- ci->gender = GENDER_MALE;
- ci->fixedlegs = qfalse;
- ci->fixedtorso = qfalse;
-
- // read optional parameters
- while ( 1 ) {
- prev = text_p; // so we can unget
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( !Q_stricmp( token, "footsteps" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( !Q_stricmp( token, "default" ) || !Q_stricmp( token, "normal" ) ) {
- ci->footsteps = FOOTSTEP_NORMAL;
- } else if ( !Q_stricmp( token, "boot" ) ) {
- ci->footsteps = FOOTSTEP_BOOT;
- } else if ( !Q_stricmp( token, "flesh" ) ) {
- ci->footsteps = FOOTSTEP_FLESH;
- } else if ( !Q_stricmp( token, "mech" ) ) {
- ci->footsteps = FOOTSTEP_MECH;
- } else if ( !Q_stricmp( token, "energy" ) ) {
- ci->footsteps = FOOTSTEP_ENERGY;
- } else {
- CG_Printf( "Bad footsteps parm in %s: %s\n", filename, token );
- }
- continue;
- } else if ( !Q_stricmp( token, "headoffset" ) ) {
- for ( i = 0 ; i < 3 ; i++ ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- ci->headOffset[i] = atof( token );
- }
- continue;
- } else if ( !Q_stricmp( token, "sex" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( token[0] == 'f' || token[0] == 'F' ) {
- ci->gender = GENDER_FEMALE;
- } else if ( token[0] == 'n' || token[0] == 'N' ) {
- ci->gender = GENDER_NEUTER;
- } else {
- ci->gender = GENDER_MALE;
- }
- continue;
- } else if ( !Q_stricmp( token, "fixedlegs" ) ) {
- ci->fixedlegs = qtrue;
- continue;
- } else if ( !Q_stricmp( token, "fixedtorso" ) ) {
- ci->fixedtorso = qtrue;
- continue;
- }
-
- // if it is a number, start parsing animations
- if ( token[0] >= '0' && token[0] <= '9' ) {
- text_p = prev; // unget the token
- break;
- }
- Com_Printf( "unknown token '%s' is %s\n", token, filename );
- }
-
- // read information for each frame
- for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
-
- token = COM_Parse( &text_p );
- if ( !*token ) {
- if( i >= TORSO_GETFLAG && i <= TORSO_NEGATIVE ) {
- animations[i].firstFrame = animations[TORSO_GESTURE].firstFrame;
- animations[i].frameLerp = animations[TORSO_GESTURE].frameLerp;
- animations[i].initialLerp = animations[TORSO_GESTURE].initialLerp;
- animations[i].loopFrames = animations[TORSO_GESTURE].loopFrames;
- animations[i].numFrames = animations[TORSO_GESTURE].numFrames;
- animations[i].reversed = qfalse;
- animations[i].flipflop = qfalse;
- continue;
- }
- break;
- }
- animations[i].firstFrame = atoi( token );
- // leg only frames are adjusted to not count the upper body only frames
- if ( i == LEGS_WALKCR ) {
- skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
- }
- if ( i >= LEGS_WALKCR && i<TORSO_GETFLAG) {
- animations[i].firstFrame -= skip;
- }
-
- token = COM_Parse( &text_p );
- if ( !*token ) {
- break;
- }
- animations[i].numFrames = atoi( token );
-
- animations[i].reversed = qfalse;
- animations[i].flipflop = qfalse;
- // if numFrames is negative the animation is reversed
- if (animations[i].numFrames < 0) {
- animations[i].numFrames = -animations[i].numFrames;
- animations[i].reversed = qtrue;
- }
-
- token = COM_Parse( &text_p );
- if ( !*token ) {
- break;
- }
- animations[i].loopFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !*token ) {
- break;
- }
- fps = atof( token );
- if ( fps == 0 ) {
- fps = 1;
- }
- animations[i].frameLerp = 1000 / fps;
- animations[i].initialLerp = 1000 / fps;
- }
-
- if ( i != MAX_ANIMATIONS ) {
- CG_Printf( "Error parsing animation file: %s", filename );
- return qfalse;
- }
-
- // crouch backward animation
- memcpy(&animations[LEGS_BACKCR], &animations[LEGS_WALKCR], sizeof(animation_t));
- animations[LEGS_BACKCR].reversed = qtrue;
- // walk backward animation
- memcpy(&animations[LEGS_BACKWALK], &animations[LEGS_WALK], sizeof(animation_t));
- animations[LEGS_BACKWALK].reversed = qtrue;
- // flag moving fast
- animations[FLAG_RUN].firstFrame = 0;
- animations[FLAG_RUN].numFrames = 16;
- animations[FLAG_RUN].loopFrames = 16;
- animations[FLAG_RUN].frameLerp = 1000 / 15;
- animations[FLAG_RUN].initialLerp = 1000 / 15;
- animations[FLAG_RUN].reversed = qfalse;
- // flag not moving or moving slowly
- animations[FLAG_STAND].firstFrame = 16;
- animations[FLAG_STAND].numFrames = 5;
- animations[FLAG_STAND].loopFrames = 0;
- animations[FLAG_STAND].frameLerp = 1000 / 20;
- animations[FLAG_STAND].initialLerp = 1000 / 20;
- animations[FLAG_STAND].reversed = qfalse;
- // flag speeding up
- animations[FLAG_STAND2RUN].firstFrame = 16;
- animations[FLAG_STAND2RUN].numFrames = 5;
- animations[FLAG_STAND2RUN].loopFrames = 1;
- animations[FLAG_STAND2RUN].frameLerp = 1000 / 15;
- animations[FLAG_STAND2RUN].initialLerp = 1000 / 15;
- animations[FLAG_STAND2RUN].reversed = qtrue;
- //
- // new anims changes
- //
-// animations[TORSO_GETFLAG].flipflop = qtrue;
-// animations[TORSO_GUARDBASE].flipflop = qtrue;
-// animations[TORSO_PATROL].flipflop = qtrue;
-// animations[TORSO_AFFIRMATIVE].flipflop = qtrue;
-// animations[TORSO_NEGATIVE].flipflop = qtrue;
- //
- return qtrue;
-}
-
-/*
-==========================
-CG_FileExists
-==========================
-*/
-static qboolean CG_FileExists(const char *filename) {
- int len;
-
- len = trap_FS_FOpenFile( filename, NULL, FS_READ );
- if (len>0) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==========================
-CG_FindClientModelFile
-==========================
-*/
-static qboolean CG_FindClientModelFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *base, const char *ext ) {
- char *team, *charactersFolder;
- int i;
-
- if ( cgs.gametype >= GT_TEAM ) {
- switch ( ci->team ) {
- case TEAM_BLUE: {
- team = "blue";
- break;
- }
- default: {
- team = "red";
- break;
- }
- }
- }
- else {
- team = "default";
- }
- charactersFolder = "";
- while(1) {
- for ( i = 0; i < 2; i++ ) {
- if ( i == 0 && teamName && *teamName ) {
- // "models/players/characters/james/stroggs/lower_lily_red.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, team, ext );
- }
- else {
- // "models/players/characters/james/lower_lily_red.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s_%s.%s", charactersFolder, modelName, base, skinName, team, ext );
- }
- if ( CG_FileExists( filename ) ) {
- return qtrue;
- }
- if ( cgs.gametype >= GT_TEAM ) {
- if ( i == 0 && teamName && *teamName ) {
- // "models/players/characters/james/stroggs/lower_red.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, team, ext );
- }
- else {
- // "models/players/characters/james/lower_red.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, team, ext );
- }
- }
- else {
- if ( i == 0 && teamName && *teamName ) {
- // "models/players/characters/james/stroggs/lower_lily.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, ext );
- }
- else {
- // "models/players/characters/james/lower_lily.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, skinName, ext );
- }
- }
- if ( CG_FileExists( filename ) ) {
- return qtrue;
- }
- if ( !teamName || !*teamName ) {
- break;
- }
- }
- // if tried the heads folder first
- if ( charactersFolder[0] ) {
- break;
- }
- charactersFolder = "characters/";
- }
-
- return qfalse;
-}
-
-/*
-==========================
-CG_FindClientHeadFile
-==========================
-*/
-static qboolean CG_FindClientHeadFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) {
- char *team, *headsFolder;
- int i;
-
- if ( cgs.gametype >= GT_TEAM ) {
- switch ( ci->team ) {
- case TEAM_BLUE: {
- team = "blue";
- break;
- }
- default: {
- team = "red";
- break;
- }
- }
- }
- else {
- team = "default";
- }
-
- if ( headModelName[0] == '*' ) {
- headsFolder = "heads/";
- headModelName++;
- }
- else {
- headsFolder = "";
- }
- while(1) {
- for ( i = 0; i < 2; i++ ) {
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s/%s%s_%s.%s", headsFolder, headModelName, headSkinName, teamName, base, team, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s/%s_%s.%s", headsFolder, headModelName, headSkinName, base, team, ext );
- }
- if ( CG_FileExists( filename ) ) {
- return qtrue;
- }
- if ( cgs.gametype >= GT_TEAM ) {
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, team, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, team, ext );
- }
- }
- else {
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, headSkinName, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, headSkinName, ext );
- }
- }
- if ( CG_FileExists( filename ) ) {
- return qtrue;
- }
- if ( !teamName || !*teamName ) {
- break;
- }
- }
- // if tried the heads folder first
- if ( headsFolder[0] ) {
- break;
- }
- headsFolder = "heads/";
- }
-
- return qfalse;
-}
-
-/*
-==========================
-CG_RegisterClientSkin
-==========================
-*/
-static qboolean CG_RegisterClientSkin( clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName ) {
- char filename[MAX_QPATH];
-
- /*
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/%slower_%s.skin", modelName, teamName, skinName );
- ci->legsSkin = trap_R_RegisterSkin( filename );
- if (!ci->legsSkin) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%slower_%s.skin", modelName, teamName, skinName );
- ci->legsSkin = trap_R_RegisterSkin( filename );
- if (!ci->legsSkin) {
- Com_Printf( "Leg skin load failure: %s\n", filename );
- }
- }
-
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/%supper_%s.skin", modelName, teamName, skinName );
- ci->torsoSkin = trap_R_RegisterSkin( filename );
- if (!ci->torsoSkin) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%supper_%s.skin", modelName, teamName, skinName );
- ci->torsoSkin = trap_R_RegisterSkin( filename );
- if (!ci->torsoSkin) {
- Com_Printf( "Torso skin load failure: %s\n", filename );
- }
- }
- */
- if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "lower", "skin" ) ) {
- ci->legsSkin = trap_R_RegisterSkin( filename );
- }
- if (!ci->legsSkin) {
- Com_Printf( "Leg skin load failure: %s\n", filename );
- }
-
- if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "upper", "skin" ) ) {
- ci->torsoSkin = trap_R_RegisterSkin( filename );
- }
- if (!ci->torsoSkin) {
- Com_Printf( "Torso skin load failure: %s\n", filename );
- }
-
- if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headModelName, headSkinName, "head", "skin" ) ) {
- ci->headSkin = trap_R_RegisterSkin( filename );
- }
- if (!ci->headSkin) {
- Com_Printf( "Head skin load failure: %s\n", filename );
- }
-
- // if any skins failed to load
- if ( !ci->legsSkin || !ci->torsoSkin || !ci->headSkin ) {
- return qfalse;
- }
- return qtrue;
-}
-
-/*
-==========================
-CG_RegisterClientModelname
-==========================
-*/
-static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName, const char *teamName ) {
- char filename[MAX_QPATH*2];
- const char *headName;
- char newTeamName[MAX_QPATH*2];
-
- if ( headModelName[0] == '\0' ) {
- headName = modelName;
- }
- else {
- headName = headModelName;
- }
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
- ci->legsModel = trap_R_RegisterModel( filename );
- if ( !ci->legsModel ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower.md3", modelName );
- ci->legsModel = trap_R_RegisterModel( filename );
- if ( !ci->legsModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
- }
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
- ci->torsoModel = trap_R_RegisterModel( filename );
- if ( !ci->torsoModel ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper.md3", modelName );
- ci->torsoModel = trap_R_RegisterModel( filename );
- if ( !ci->torsoModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
- }
-
- if( headName[0] == '*' ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", &headModelName[1], &headModelName[1] );
- }
- else {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headName );
- }
- ci->headModel = trap_R_RegisterModel( filename );
- // if the head model could not be found and we didn't load from the heads folder try to load from there
- if ( !ci->headModel && headName[0] != '*' ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", headModelName, headModelName );
- ci->headModel = trap_R_RegisterModel( filename );
- }
- if ( !ci->headModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
-
- // if any skins failed to load, return failure
- if ( !CG_RegisterClientSkin( ci, teamName, modelName, skinName, headName, headSkinName ) ) {
- if ( teamName && *teamName) {
- Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", teamName, modelName, skinName, headName, headSkinName );
- if( ci->team == TEAM_BLUE ) {
- Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_BLUETEAM_NAME);
- }
- else {
- Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_REDTEAM_NAME);
- }
- if ( !CG_RegisterClientSkin( ci, newTeamName, modelName, skinName, headName, headSkinName ) ) {
- Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", newTeamName, modelName, skinName, headName, headSkinName );
- return qfalse;
- }
- } else {
- Com_Printf( "Failed to load skin file: %s : %s, %s : %s\n", modelName, skinName, headName, headSkinName );
- return qfalse;
- }
- }
-
- // load the animations
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
- if ( !CG_ParseAnimationFile( filename, ci ) ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName );
- if ( !CG_ParseAnimationFile( filename, ci ) ) {
- Com_Printf( "Failed to load animation file %s\n", filename );
- return qfalse;
- }
- }
-
- if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "skin" ) ) {
- ci->modelIcon = trap_R_RegisterShaderNoMip( filename );
- }
- else if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "tga" ) ) {
- ci->modelIcon = trap_R_RegisterShaderNoMip( filename );
- }
-
- if ( !ci->modelIcon ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-====================
-CG_ColorFromString
-====================
-*/
-static void CG_ColorFromString( const char *v, vec3_t color ) {
- int val;
-
- VectorClear( color );
-
- val = atoi( v );
-
- if ( val < 1 || val > 7 ) {
- VectorSet( color, 1, 1, 1 );
- return;
- }
-
- if ( val & 1 ) {
- color[2] = 1.0f;
- }
- if ( val & 2 ) {
- color[1] = 1.0f;
- }
- if ( val & 4 ) {
- color[0] = 1.0f;
- }
-}
-
-/*
-===================
-CG_LoadClientInfo
-
-Load it now, taking the disk hits.
-This will usually be deferred to a safe time
-===================
-*/
-static void CG_LoadClientInfo( int clientNum, clientInfo_t *ci ) {
- const char *dir, *fallback;
- int i, modelloaded;
- const char *s;
- char teamname[MAX_QPATH];
-
- teamname[0] = 0;
-#ifdef MISSIONPACK
- if( cgs.gametype >= GT_TEAM) {
- if( ci->team == TEAM_BLUE ) {
- Q_strncpyz(teamname, cg_blueTeamName.string, sizeof(teamname) );
- } else {
- Q_strncpyz(teamname, cg_redTeamName.string, sizeof(teamname) );
- }
- }
- if( teamname[0] ) {
- strcat( teamname, "/" );
- }
-#endif
- modelloaded = qtrue;
- if ( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname ) ) {
- if ( cg_buildScript.integer ) {
- CG_Error( "CG_RegisterClientModelname( %s, %s, %s, %s %s ) failed", ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname );
- }
-
- // fall back to default team name
- if( cgs.gametype >= GT_TEAM) {
- // keep skin name
- if( ci->team == TEAM_BLUE ) {
- Q_strncpyz(teamname, DEFAULT_BLUETEAM_NAME, sizeof(teamname) );
- } else {
- Q_strncpyz(teamname, DEFAULT_REDTEAM_NAME, sizeof(teamname) );
- }
- if ( !CG_RegisterClientModelname( ci, DEFAULT_TEAM_MODEL, ci->skinName, DEFAULT_TEAM_HEAD, ci->skinName, teamname ) ) {
- CG_Error( "DEFAULT_TEAM_MODEL / skin (%s/%s) failed to register", DEFAULT_TEAM_MODEL, ci->skinName );
- }
- } else {
- if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default", DEFAULT_MODEL, "default", teamname ) ) {
- CG_Error( "DEFAULT_MODEL (%s) failed to register", DEFAULT_MODEL );
- }
- }
- modelloaded = qfalse;
- }
-
- ci->newAnims = qfalse;
- if ( ci->torsoModel ) {
- orientation_t tag;
- // if the torso model has the "tag_flag"
- if ( trap_R_LerpTag( &tag, ci->torsoModel, 0, 0, 1, "tag_flag" ) ) {
- ci->newAnims = qtrue;
- }
- }
-
- // sounds
- dir = ci->modelName;
- fallback = (cgs.gametype >= GT_TEAM) ? DEFAULT_TEAM_MODEL : DEFAULT_MODEL;
-
- for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i++ ) {
- s = cg_customSoundNames[i];
- if ( !s ) {
- break;
- }
- ci->sounds[i] = 0;
- // if the model didn't load use the sounds of the default model
- if (modelloaded) {
- ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", dir, s + 1), qfalse );
- }
- if ( !ci->sounds[i] ) {
- ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", fallback, s + 1), qfalse );
- }
- }
-
- ci->deferred = qfalse;
-
- // reset any existing players and bodies, because they might be in bad
- // frames for this new model
- for ( i = 0 ; i < MAX_GENTITIES ; i++ ) {
- if ( cg_entities[i].currentState.clientNum == clientNum
- && cg_entities[i].currentState.eType == ET_PLAYER ) {
- CG_ResetPlayerEntity( &cg_entities[i] );
- }
- }
-}
-
-/*
-======================
-CG_CopyClientInfoModel
-======================
-*/
-static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to ) {
- VectorCopy( from->headOffset, to->headOffset );
- to->footsteps = from->footsteps;
- to->gender = from->gender;
-
- to->legsModel = from->legsModel;
- to->legsSkin = from->legsSkin;
- to->torsoModel = from->torsoModel;
- to->torsoSkin = from->torsoSkin;
- to->headModel = from->headModel;
- to->headSkin = from->headSkin;
- to->modelIcon = from->modelIcon;
-
- to->newAnims = from->newAnims;
-
- memcpy( to->animations, from->animations, sizeof( to->animations ) );
- memcpy( to->sounds, from->sounds, sizeof( to->sounds ) );
-}
-
-/*
-======================
-CG_ScanForExistingClientInfo
-======================
-*/
-static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci ) {
- int i;
- clientInfo_t *match;
-
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- match = &cgs.clientinfo[ i ];
- if ( !match->infoValid ) {
- continue;
- }
- if ( match->deferred ) {
- continue;
- }
- if ( !Q_stricmp( ci->modelName, match->modelName )
- && !Q_stricmp( ci->skinName, match->skinName )
- && !Q_stricmp( ci->headModelName, match->headModelName )
- && !Q_stricmp( ci->headSkinName, match->headSkinName )
- && !Q_stricmp( ci->blueTeam, match->blueTeam )
- && !Q_stricmp( ci->redTeam, match->redTeam )
- && (cgs.gametype < GT_TEAM || ci->team == match->team) ) {
- // this clientinfo is identical, so use it's handles
-
- ci->deferred = qfalse;
-
- CG_CopyClientInfoModel( match, ci );
-
- return qtrue;
- }
- }
-
- // nothing matches, so defer the load
- return qfalse;
-}
-
-/*
-======================
-CG_SetDeferredClientInfo
-
-We aren't going to load it now, so grab some other
-client's info to use until we have some spare time.
-======================
-*/
-static void CG_SetDeferredClientInfo( int clientNum, clientInfo_t *ci ) {
- int i;
- clientInfo_t *match;
-
- // if someone else is already the same models and skins we
- // can just load the client info
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- match = &cgs.clientinfo[ i ];
- if ( !match->infoValid || match->deferred ) {
- continue;
- }
- if ( Q_stricmp( ci->skinName, match->skinName ) ||
- Q_stricmp( ci->modelName, match->modelName ) ||
-// Q_stricmp( ci->headModelName, match->headModelName ) ||
-// Q_stricmp( ci->headSkinName, match->headSkinName ) ||
- (cgs.gametype >= GT_TEAM && ci->team != match->team) ) {
- continue;
- }
- // just load the real info cause it uses the same models and skins
- CG_LoadClientInfo( clientNum, ci );
- return;
- }
-
- // if we are in teamplay, only grab a model if the skin is correct
- if ( cgs.gametype >= GT_TEAM ) {
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- match = &cgs.clientinfo[ i ];
- if ( !match->infoValid || match->deferred ) {
- continue;
- }
- if ( Q_stricmp( ci->skinName, match->skinName ) ||
- (cgs.gametype >= GT_TEAM && ci->team != match->team) ) {
- continue;
- }
- ci->deferred = qtrue;
- CG_CopyClientInfoModel( match, ci );
- return;
- }
- // load the full model, because we don't ever want to show
- // an improper team skin. This will cause a hitch for the first
- // player, when the second enters. Combat shouldn't be going on
- // yet, so it shouldn't matter
- CG_LoadClientInfo( clientNum, ci );
- return;
- }
-
- // find the first valid clientinfo and grab its stuff
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- match = &cgs.clientinfo[ i ];
- if ( !match->infoValid ) {
- continue;
- }
-
- ci->deferred = qtrue;
- CG_CopyClientInfoModel( match, ci );
- return;
- }
-
- // we should never get here...
- CG_Printf( "CG_SetDeferredClientInfo: no valid clients!\n" );
-
- CG_LoadClientInfo( clientNum, ci );
-}
-
-
-/*
-======================
-CG_NewClientInfo
-======================
-*/
-void CG_NewClientInfo( int clientNum ) {
- clientInfo_t *ci;
- clientInfo_t newInfo;
- const char *configstring;
- const char *v;
- char *slash;
-
- ci = &cgs.clientinfo[clientNum];
-
- configstring = CG_ConfigString( clientNum + CS_PLAYERS );
- if ( !configstring[0] ) {
- memset( ci, 0, sizeof( *ci ) );
- return; // player just left
- }
-
- // build into a temp buffer so the defer checks can use
- // the old value
- memset( &newInfo, 0, sizeof( newInfo ) );
-
- // isolate the player's name
- v = Info_ValueForKey(configstring, "n");
- Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) );
-
- // colors
- v = Info_ValueForKey( configstring, "c1" );
- CG_ColorFromString( v, newInfo.color1 );
-
- v = Info_ValueForKey( configstring, "c2" );
- CG_ColorFromString( v, newInfo.color2 );
-
- // bot skill
- v = Info_ValueForKey( configstring, "skill" );
- newInfo.botSkill = atoi( v );
-
- // handicap
- v = Info_ValueForKey( configstring, "hc" );
- newInfo.handicap = atoi( v );
-
- // wins
- v = Info_ValueForKey( configstring, "w" );
- newInfo.wins = atoi( v );
-
- // losses
- v = Info_ValueForKey( configstring, "l" );
- newInfo.losses = atoi( v );
-
- // team
- v = Info_ValueForKey( configstring, "t" );
- newInfo.team = atoi( v );
-
- // team task
- v = Info_ValueForKey( configstring, "tt" );
- newInfo.teamTask = atoi(v);
-
- // team leader
- v = Info_ValueForKey( configstring, "tl" );
- newInfo.teamLeader = atoi(v);
-
- v = Info_ValueForKey( configstring, "g_redteam" );
- Q_strncpyz(newInfo.redTeam, v, MAX_TEAMNAME);
-
- v = Info_ValueForKey( configstring, "g_blueteam" );
- Q_strncpyz(newInfo.blueTeam, v, MAX_TEAMNAME);
-
- // model
- v = Info_ValueForKey( configstring, "model" );
- if ( cg_forceModel.integer ) {
- // forcemodel makes everyone use a single model
- // to prevent load hitches
- char modelStr[MAX_QPATH];
- char *skin;
-
- if( cgs.gametype >= GT_TEAM ) {
- Q_strncpyz( newInfo.modelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.modelName ) );
- Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
- } else {
- trap_Cvar_VariableStringBuffer( "model", modelStr, sizeof( modelStr ) );
- if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
- skin = "default";
- } else {
- *skin++ = 0;
- }
-
- Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) );
- Q_strncpyz( newInfo.modelName, modelStr, sizeof( newInfo.modelName ) );
- }
-
- if ( cgs.gametype >= GT_TEAM ) {
- // keep skin name
- slash = strchr( v, '/' );
- if ( slash ) {
- Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
- }
- }
- } else {
- Q_strncpyz( newInfo.modelName, v, sizeof( newInfo.modelName ) );
-
- slash = strchr( newInfo.modelName, '/' );
- if ( !slash ) {
- // modelName didn not include a skin name
- Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
- } else {
- Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
- // truncate modelName
- *slash = 0;
- }
- }
-
- // head model
- v = Info_ValueForKey( configstring, "hmodel" );
- if ( cg_forceModel.integer ) {
- // forcemodel makes everyone use a single model
- // to prevent load hitches
- char modelStr[MAX_QPATH];
- char *skin;
-
- if( cgs.gametype >= GT_TEAM ) {
- Q_strncpyz( newInfo.headModelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.headModelName ) );
- Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) );
- } else {
- trap_Cvar_VariableStringBuffer( "headmodel", modelStr, sizeof( modelStr ) );
- if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
- skin = "default";
- } else {
- *skin++ = 0;
- }
-
- Q_strncpyz( newInfo.headSkinName, skin, sizeof( newInfo.headSkinName ) );
- Q_strncpyz( newInfo.headModelName, modelStr, sizeof( newInfo.headModelName ) );
- }
-
- if ( cgs.gametype >= GT_TEAM ) {
- // keep skin name
- slash = strchr( v, '/' );
- if ( slash ) {
- Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) );
- }
- }
- } else {
- Q_strncpyz( newInfo.headModelName, v, sizeof( newInfo.headModelName ) );
-
- slash = strchr( newInfo.headModelName, '/' );
- if ( !slash ) {
- // modelName didn not include a skin name
- Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) );
- } else {
- Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) );
- // truncate modelName
- *slash = 0;
- }
- }
-
- // scan for an existing clientinfo that matches this modelname
- // so we can avoid loading checks if possible
- if ( !CG_ScanForExistingClientInfo( &newInfo ) ) {
- qboolean forceDefer;
-
- forceDefer = trap_MemoryRemaining() < 4000000;
-
- // if we are defering loads, just have it pick the first valid
- if ( forceDefer || (cg_deferPlayers.integer && !cg_buildScript.integer && !cg.loading ) ) {
- // keep whatever they had if it won't violate team skins
- CG_SetDeferredClientInfo( clientNum, &newInfo );
- // if we are low on memory, leave them with this model
- if ( forceDefer ) {
- CG_Printf( "Memory is low. Using deferred model.\n" );
- newInfo.deferred = qfalse;
- }
- } else {
- CG_LoadClientInfo( clientNum, &newInfo );
- }
- }
-
- // replace whatever was there with the new one
- newInfo.infoValid = qtrue;
- *ci = newInfo;
-}
-
-
-
-/*
-======================
-CG_LoadDeferredPlayers
-
-Called each frame when a player is dead
-and the scoreboard is up
-so deferred players can be loaded
-======================
-*/
-void CG_LoadDeferredPlayers( void ) {
- int i;
- clientInfo_t *ci;
-
- // scan for a deferred player to load
- for ( i = 0, ci = cgs.clientinfo ; i < cgs.maxclients ; i++, ci++ ) {
- if ( ci->infoValid && ci->deferred ) {
- // if we are low on memory, leave it deferred
- if ( trap_MemoryRemaining() < 4000000 ) {
- CG_Printf( "Memory is low. Using deferred model.\n" );
- ci->deferred = qfalse;
- continue;
- }
- CG_LoadClientInfo( i, ci );
-// break;
- }
- }
-}
-
-/*
-=============================================================================
-
-PLAYER ANIMATION
-
-=============================================================================
-*/
-
-
-/*
-===============
-CG_SetLerpFrameAnimation
-
-may include ANIM_TOGGLEBIT
-===============
-*/
-static void CG_SetLerpFrameAnimation( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
- animation_t *anim;
-
- lf->animationNumber = newAnimation;
- newAnimation &= ~ANIM_TOGGLEBIT;
-
- if ( newAnimation < 0 || newAnimation >= MAX_TOTALANIMATIONS ) {
- CG_Error( "Bad animation number: %i", newAnimation );
- }
-
- anim = &ci->animations[ newAnimation ];
-
- lf->animation = anim;
- lf->animationTime = lf->frameTime + anim->initialLerp;
-
- if ( cg_debugAnim.integer ) {
- CG_Printf( "Anim: %i\n", newAnimation );
- }
-}
-
-/*
-===============
-CG_RunLerpFrame
-
-Sets cg.snap, cg.oldFrame, and cg.backlerp
-cg.time should be between oldFrameTime and frameTime after exit
-===============
-*/
-static void CG_RunLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation, float speedScale ) {
- int f, numFrames;
- animation_t *anim;
-
- // debugging tool to get no animations
- if ( cg_animSpeed.integer == 0 ) {
- lf->oldFrame = lf->frame = lf->backlerp = 0;
- return;
- }
-
- // see if the animation sequence is switching
- if ( newAnimation != lf->animationNumber || !lf->animation ) {
- CG_SetLerpFrameAnimation( ci, lf, newAnimation );
- }
-
- // if we have passed the current frame, move it to
- // oldFrame and calculate a new frame
- if ( cg.time >= lf->frameTime ) {
- lf->oldFrame = lf->frame;
- lf->oldFrameTime = lf->frameTime;
-
- // get the next frame based on the animation
- anim = lf->animation;
- if ( !anim->frameLerp ) {
- return; // shouldn't happen
- }
- if ( cg.time < lf->animationTime ) {
- lf->frameTime = lf->animationTime; // initial lerp
- } else {
- lf->frameTime = lf->oldFrameTime + anim->frameLerp;
- }
- f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
- f *= speedScale; // adjust for haste, etc
-
- numFrames = anim->numFrames;
- if (anim->flipflop) {
- numFrames *= 2;
- }
- if ( f >= numFrames ) {
- f -= numFrames;
- if ( anim->loopFrames ) {
- f %= anim->loopFrames;
- f += anim->numFrames - anim->loopFrames;
- } else {
- f = numFrames - 1;
- // the animation is stuck at the end, so it
- // can immediately transition to another sequence
- lf->frameTime = cg.time;
- }
- }
- if ( anim->reversed ) {
- lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
- }
- else if (anim->flipflop && f>=anim->numFrames) {
- lf->frame = anim->firstFrame + anim->numFrames - 1 - (f%anim->numFrames);
- }
- else {
- lf->frame = anim->firstFrame + f;
- }
- if ( cg.time > lf->frameTime ) {
- lf->frameTime = cg.time;
- if ( cg_debugAnim.integer ) {
- CG_Printf( "Clamp lf->frameTime\n");
- }
- }
- }
-
- if ( lf->frameTime > cg.time + 200 ) {
- lf->frameTime = cg.time;
- }
-
- if ( lf->oldFrameTime > cg.time ) {
- lf->oldFrameTime = cg.time;
- }
- // calculate current lerp value
- if ( lf->frameTime == lf->oldFrameTime ) {
- lf->backlerp = 0;
- } else {
- lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
- }
-}
-
-
-/*
-===============
-CG_ClearLerpFrame
-===============
-*/
-static void CG_ClearLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int animationNumber ) {
- lf->frameTime = lf->oldFrameTime = cg.time;
- CG_SetLerpFrameAnimation( ci, lf, animationNumber );
- lf->oldFrame = lf->frame = lf->animation->firstFrame;
-}
-
-
-/*
-===============
-CG_PlayerAnimation
-===============
-*/
-static void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float *legsBackLerp,
- int *torsoOld, int *torso, float *torsoBackLerp ) {
- clientInfo_t *ci;
- int clientNum;
- float speedScale;
-
- clientNum = cent->currentState.clientNum;
-
- if ( cg_noPlayerAnims.integer ) {
- *legsOld = *legs = *torsoOld = *torso = 0;
- return;
- }
-
- if ( cent->currentState.powerups & ( 1 << PW_HASTE ) ) {
- speedScale = 1.5;
- } else {
- speedScale = 1;
- }
-
- ci = &cgs.clientinfo[ clientNum ];
-
- // do the shuffle turn frames locally
- if ( cent->pe.legs.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {
- CG_RunLerpFrame( ci, ¢->pe.legs, LEGS_TURN, speedScale );
- } else {
- CG_RunLerpFrame( ci, ¢->pe.legs, cent->currentState.legsAnim, speedScale );
- }
-
- *legsOld = cent->pe.legs.oldFrame;
- *legs = cent->pe.legs.frame;
- *legsBackLerp = cent->pe.legs.backlerp;
-
- CG_RunLerpFrame( ci, ¢->pe.torso, cent->currentState.torsoAnim, speedScale );
-
- *torsoOld = cent->pe.torso.oldFrame;
- *torso = cent->pe.torso.frame;
- *torsoBackLerp = cent->pe.torso.backlerp;
-}
-
-/*
-=============================================================================
-
-PLAYER ANGLES
-
-=============================================================================
-*/
-
-/*
-==================
-CG_SwingAngles
-==================
-*/
-static void CG_SwingAngles( float destination, float swingTolerance, float clampTolerance,
- float speed, float *angle, qboolean *swinging ) {
- float swing;
- float move;
- float scale;
-
- if ( !*swinging ) {
- // see if a swing should be started
- swing = AngleSubtract( *angle, destination );
- if ( swing > swingTolerance || swing < -swingTolerance ) {
- *swinging = qtrue;
- }
- }
-
- if ( !*swinging ) {
- return;
- }
-
- // modify the speed depending on the delta
- // so it doesn't seem so linear
- swing = AngleSubtract( destination, *angle );
- scale = fabs( swing );
- if ( scale < swingTolerance * 0.5 ) {
- scale = 0.5;
- } else if ( scale < swingTolerance ) {
- scale = 1.0;
- } else {
- scale = 2.0;
- }
-
- // swing towards the destination angle
- if ( swing >= 0 ) {
- move = cg.frametime * scale * speed;
- if ( move >= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- } else if ( swing < 0 ) {
- move = cg.frametime * scale * -speed;
- if ( move <= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- }
-
- // clamp to no more than tolerance
- swing = AngleSubtract( destination, *angle );
- if ( swing > clampTolerance ) {
- *angle = AngleMod( destination - (clampTolerance - 1) );
- } else if ( swing < -clampTolerance ) {
- *angle = AngleMod( destination + (clampTolerance - 1) );
- }
-}
-
-/*
-=================
-CG_AddPainTwitch
-=================
-*/
-static void CG_AddPainTwitch( centity_t *cent, vec3_t torsoAngles ) {
- int t;
- float f;
-
- t = cg.time - cent->pe.painTime;
- if ( t >= PAIN_TWITCH_TIME ) {
- return;
- }
-
- f = 1.0 - (float)t / PAIN_TWITCH_TIME;
-
- if ( cent->pe.painDirection ) {
- torsoAngles[ROLL] += 20 * f;
- } else {
- torsoAngles[ROLL] -= 20 * f;
- }
-}
-
-
-/*
-===============
-CG_PlayerAngles
-
-Handles seperate torso motion
-
- legs pivot based on direction of movement
-
- head always looks exactly at cent->lerpAngles
-
- if motion < 20 degrees, show in head only
- if < 45 degrees, also show in torso
-===============
-*/
-static void CG_PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {
- vec3_t legsAngles, torsoAngles, headAngles;
- float dest;
- static int movementOffsets[8] = { 0, 22, 45, -22, 0, 22, -45, -22 };
- vec3_t velocity;
- float speed;
- int dir, clientNum;
- clientInfo_t *ci;
-
- VectorCopy( cent->lerpAngles, headAngles );
- headAngles[YAW] = AngleMod( headAngles[YAW] );
- VectorClear( legsAngles );
- VectorClear( torsoAngles );
-
- // --------- yaw -------------
-
- // allow yaw to drift a bit
- if ( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE
- || ( cent->currentState.torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) {
- // if not standing still, always point all in the same direction
- cent->pe.torso.yawing = qtrue; // always center
- cent->pe.torso.pitching = qtrue; // always center
- cent->pe.legs.yawing = qtrue; // always center
- }
-
- // adjust legs for movement dir
- if ( cent->currentState.eFlags & EF_DEAD ) {
- // don't let dead bodies twitch
- dir = 0;
- } else {
- dir = cent->currentState.angles2[YAW];
- if ( dir < 0 || dir > 7 ) {
- CG_Error( "Bad player movement angle" );
- }
- }
- legsAngles[YAW] = headAngles[YAW] + movementOffsets[ dir ];
- torsoAngles[YAW] = headAngles[YAW] + 0.25 * movementOffsets[ dir ];
-
- // torso
- CG_SwingAngles( torsoAngles[YAW], 25, 90, cg_swingSpeed.value, ¢->pe.torso.yawAngle, ¢->pe.torso.yawing );
- CG_SwingAngles( legsAngles[YAW], 40, 90, cg_swingSpeed.value, ¢->pe.legs.yawAngle, ¢->pe.legs.yawing );
-
- torsoAngles[YAW] = cent->pe.torso.yawAngle;
- legsAngles[YAW] = cent->pe.legs.yawAngle;
-
-
- // --------- pitch -------------
-
- // only show a fraction of the pitch angle in the torso
- if ( headAngles[PITCH] > 180 ) {
- dest = (-360 + headAngles[PITCH]) * 0.75f;
- } else {
- dest = headAngles[PITCH] * 0.75f;
- }
- CG_SwingAngles( dest, 15, 30, 0.1f, ¢->pe.torso.pitchAngle, ¢->pe.torso.pitching );
- torsoAngles[PITCH] = cent->pe.torso.pitchAngle;
-
- //
- clientNum = cent->currentState.clientNum;
- if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
- ci = &cgs.clientinfo[ clientNum ];
- if ( ci->fixedtorso ) {
- torsoAngles[PITCH] = 0.0f;
- }
- }
-
- // --------- roll -------------
-
-
- // lean towards the direction of travel
- VectorCopy( cent->currentState.pos.trDelta, velocity );
- speed = VectorNormalize( velocity );
- if ( speed ) {
- vec3_t axis[3];
- float side;
-
- speed *= 0.05f;
-
- AnglesToAxis( legsAngles, axis );
- side = speed * DotProduct( velocity, axis[1] );
- legsAngles[ROLL] -= side;
-
- side = speed * DotProduct( velocity, axis[0] );
- legsAngles[PITCH] += side;
- }
-
- //
- clientNum = cent->currentState.clientNum;
- if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
- ci = &cgs.clientinfo[ clientNum ];
- if ( ci->fixedlegs ) {
- legsAngles[YAW] = torsoAngles[YAW];
- legsAngles[PITCH] = 0.0f;
- legsAngles[ROLL] = 0.0f;
- }
- }
-
- // pain twitch
- CG_AddPainTwitch( cent, torsoAngles );
-
- // pull the angles back out of the hierarchial chain
- AnglesSubtract( headAngles, torsoAngles, headAngles );
- AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
- AnglesToAxis( legsAngles, legs );
- AnglesToAxis( torsoAngles, torso );
- AnglesToAxis( headAngles, head );
-}
-
-
-//==========================================================================
-
-/*
-===============
-CG_HasteTrail
-===============
-*/
-static void CG_HasteTrail( centity_t *cent ) {
- localEntity_t *smoke;
- vec3_t origin;
- int anim;
-
- if ( cent->trailTime > cg.time ) {
- return;
- }
- anim = cent->pe.legs.animationNumber & ~ANIM_TOGGLEBIT;
- if ( anim != LEGS_RUN && anim != LEGS_BACK ) {
- return;
- }
-
- cent->trailTime += 100;
- if ( cent->trailTime < cg.time ) {
- cent->trailTime = cg.time;
- }
-
- VectorCopy( cent->lerpOrigin, origin );
- origin[2] -= 16;
-
- smoke = CG_SmokePuff( origin, vec3_origin,
- 8,
- 1, 1, 1, 1,
- 500,
- cg.time,
- 0,
- 0,
- cgs.media.hastePuffShader );
-
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
-}
-
-#ifdef MISSIONPACK
-/*
-===============
-CG_BreathPuffs
-===============
-*/
-static void CG_BreathPuffs( centity_t *cent, refEntity_t *head) {
- clientInfo_t *ci;
- vec3_t up, origin;
- int contents;
-
- ci = &cgs.clientinfo[ cent->currentState.number ];
-
- if (!cg_enableBreath.integer) {
- return;
- }
- if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson) {
- return;
- }
- if ( cent->currentState.eFlags & EF_DEAD ) {
- return;
- }
- contents = trap_CM_PointContents( head->origin, 0 );
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- return;
- }
- if ( ci->breathPuffTime > cg.time ) {
- return;
- }
-
- VectorSet( up, 0, 0, 8 );
- VectorMA(head->origin, 8, head->axis[0], origin);
- VectorMA(origin, -4, head->axis[2], origin);
- CG_SmokePuff( origin, up, 16, 1, 1, 1, 0.66f, 1500, cg.time, cg.time + 400, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
- ci->breathPuffTime = cg.time + 2000;
-}
-
-/*
-===============
-CG_DustTrail
-===============
-*/
-static void CG_DustTrail( centity_t *cent ) {
- int anim;
- localEntity_t *dust;
- vec3_t end, vel;
- trace_t tr;
-
- if (!cg_enableDust.integer)
- return;
-
- if ( cent->dustTrailTime > cg.time ) {
- return;
- }
-
- anim = cent->pe.legs.animationNumber & ~ANIM_TOGGLEBIT;
- if ( anim != LEGS_LANDB && anim != LEGS_LAND ) {
- return;
- }
-
- cent->dustTrailTime += 40;
- if ( cent->dustTrailTime < cg.time ) {
- cent->dustTrailTime = cg.time;
- }
-
- VectorCopy(cent->currentState.pos.trBase, end);
- end[2] -= 64;
- CG_Trace( &tr, cent->currentState.pos.trBase, NULL, NULL, end, cent->currentState.number, MASK_PLAYERSOLID );
-
- if ( !(tr.surfaceFlags & SURF_DUST) )
- return;
-
- VectorCopy( cent->currentState.pos.trBase, end );
- end[2] -= 16;
-
- VectorSet(vel, 0, 0, -30);
- dust = CG_SmokePuff( end, vel,
- 24,
- .8f, .8f, 0.7f, 0.33f,
- 500,
- cg.time,
- 0,
- 0,
- cgs.media.dustPuffShader );
-}
-
-#endif
-
-/*
-===============
-CG_TrailItem
-===============
-*/
-static void CG_TrailItem( centity_t *cent, qhandle_t hModel ) {
- refEntity_t ent;
- vec3_t angles;
- vec3_t axis[3];
-
- VectorCopy( cent->lerpAngles, angles );
- angles[PITCH] = 0;
- angles[ROLL] = 0;
- AnglesToAxis( angles, axis );
-
- memset( &ent, 0, sizeof( ent ) );
- VectorMA( cent->lerpOrigin, -16, axis[0], ent.origin );
- ent.origin[2] += 16;
- angles[YAW] += 90;
- AnglesToAxis( angles, ent.axis );
-
- ent.hModel = hModel;
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-/*
-===============
-CG_PlayerFlag
-===============
-*/
-static void CG_PlayerFlag( centity_t *cent, qhandle_t hSkin, refEntity_t *torso ) {
- clientInfo_t *ci;
- refEntity_t pole;
- refEntity_t flag;
- vec3_t angles, dir;
- int legsAnim, flagAnim, updateangles;
- float angle, d;
-
- // show the flag pole model
- memset( &pole, 0, sizeof(pole) );
- pole.hModel = cgs.media.flagPoleModel;
- VectorCopy( torso->lightingOrigin, pole.lightingOrigin );
- pole.shadowPlane = torso->shadowPlane;
- pole.renderfx = torso->renderfx;
- CG_PositionEntityOnTag( &pole, torso, torso->hModel, "tag_flag" );
- trap_R_AddRefEntityToScene( &pole );
-
- // show the flag model
- memset( &flag, 0, sizeof(flag) );
- flag.hModel = cgs.media.flagFlapModel;
- flag.customSkin = hSkin;
- VectorCopy( torso->lightingOrigin, flag.lightingOrigin );
- flag.shadowPlane = torso->shadowPlane;
- flag.renderfx = torso->renderfx;
-
- VectorClear(angles);
-
- updateangles = qfalse;
- legsAnim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
- if( legsAnim == LEGS_IDLE || legsAnim == LEGS_IDLECR ) {
- flagAnim = FLAG_STAND;
- } else if ( legsAnim == LEGS_WALK || legsAnim == LEGS_WALKCR ) {
- flagAnim = FLAG_STAND;
- updateangles = qtrue;
- } else {
- flagAnim = FLAG_RUN;
- updateangles = qtrue;
- }
-
- if ( updateangles ) {
-
- VectorCopy( cent->currentState.pos.trDelta, dir );
- // add gravity
- dir[2] += 100;
- VectorNormalize( dir );
- d = DotProduct(pole.axis[2], dir);
- // if there is anough movement orthogonal to the flag pole
- if (fabs(d) < 0.9) {
- //
- d = DotProduct(pole.axis[0], dir);
- if (d > 1.0f) {
- d = 1.0f;
- }
- else if (d < -1.0f) {
- d = -1.0f;
- }
- angle = acos(d);
-
- d = DotProduct(pole.axis[1], dir);
- if (d < 0) {
- angles[YAW] = 360 - angle * 180 / M_PI;
- }
- else {
- angles[YAW] = angle * 180 / M_PI;
- }
- if (angles[YAW] < 0)
- angles[YAW] += 360;
- if (angles[YAW] > 360)
- angles[YAW] -= 360;
-
- //vectoangles( cent->currentState.pos.trDelta, tmpangles );
- //angles[YAW] = tmpangles[YAW] + 45 - cent->pe.torso.yawAngle;
- // change the yaw angle
- CG_SwingAngles( angles[YAW], 25, 90, 0.15f, ¢->pe.flag.yawAngle, ¢->pe.flag.yawing );
- }
-
- /*
- d = DotProduct(pole.axis[2], dir);
- angle = Q_acos(d);
-
- d = DotProduct(pole.axis[1], dir);
- if (d < 0) {
- angle = 360 - angle * 180 / M_PI;
- }
- else {
- angle = angle * 180 / M_PI;
- }
- if (angle > 340 && angle < 20) {
- flagAnim = FLAG_RUNUP;
- }
- if (angle > 160 && angle < 200) {
- flagAnim = FLAG_RUNDOWN;
- }
- */
- }
-
- // set the yaw angle
- angles[YAW] = cent->pe.flag.yawAngle;
- // lerp the flag animation frames
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- CG_RunLerpFrame( ci, ¢->pe.flag, flagAnim, 1 );
- flag.oldframe = cent->pe.flag.oldFrame;
- flag.frame = cent->pe.flag.frame;
- flag.backlerp = cent->pe.flag.backlerp;
-
- AnglesToAxis( angles, flag.axis );
- CG_PositionRotatedEntityOnTag( &flag, &pole, pole.hModel, "tag_flag" );
-
- trap_R_AddRefEntityToScene( &flag );
-}
-
-
-#ifdef MISSIONPACK
-/*
-===============
-CG_PlayerTokens
-===============
-*/
-static void CG_PlayerTokens( centity_t *cent, int renderfx ) {
- int tokens, i, j;
- float angle;
- refEntity_t ent;
- vec3_t dir, origin;
- skulltrail_t *trail;
- trail = &cg.skulltrails[cent->currentState.number];
- tokens = cent->currentState.generic1;
- if ( !tokens ) {
- trail->numpositions = 0;
- return;
- }
-
- if ( tokens > MAX_SKULLTRAIL ) {
- tokens = MAX_SKULLTRAIL;
- }
-
- // add skulls if there are more than last time
- for (i = 0; i < tokens - trail->numpositions; i++) {
- for (j = trail->numpositions; j > 0; j--) {
- VectorCopy(trail->positions[j-1], trail->positions[j]);
- }
- VectorCopy(cent->lerpOrigin, trail->positions[0]);
- }
- trail->numpositions = tokens;
-
- // move all the skulls along the trail
- VectorCopy(cent->lerpOrigin, origin);
- for (i = 0; i < trail->numpositions; i++) {
- VectorSubtract(trail->positions[i], origin, dir);
- if (VectorNormalize(dir) > 30) {
- VectorMA(origin, 30, dir, trail->positions[i]);
- }
- VectorCopy(trail->positions[i], origin);
- }
-
- memset( &ent, 0, sizeof( ent ) );
- if( cgs.clientinfo[ cent->currentState.clientNum ].team == TEAM_BLUE ) {
- ent.hModel = cgs.media.redCubeModel;
- } else {
- ent.hModel = cgs.media.blueCubeModel;
- }
- ent.renderfx = renderfx;
-
- VectorCopy(cent->lerpOrigin, origin);
- for (i = 0; i < trail->numpositions; i++) {
- VectorSubtract(origin, trail->positions[i], ent.axis[0]);
- ent.axis[0][2] = 0;
- VectorNormalize(ent.axis[0]);
- VectorSet(ent.axis[2], 0, 0, 1);
- CrossProduct(ent.axis[0], ent.axis[2], ent.axis[1]);
-
- VectorCopy(trail->positions[i], ent.origin);
- angle = (((cg.time + 500 * MAX_SKULLTRAIL - 500 * i) / 16) & 255) * (M_PI * 2) / 255;
- ent.origin[2] += sin(angle) * 10;
- trap_R_AddRefEntityToScene( &ent );
- VectorCopy(trail->positions[i], origin);
- }
-}
-#endif
-
-
-/*
-===============
-CG_PlayerPowerups
-===============
-*/
-static void CG_PlayerPowerups( centity_t *cent, refEntity_t *torso ) {
- int powerups;
- clientInfo_t *ci;
-
- powerups = cent->currentState.powerups;
- if ( !powerups ) {
- return;
- }
-
- // quad gives a dlight
- if ( powerups & ( 1 << PW_QUAD ) ) {
- trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1 );
- }
-
- // flight plays a looped sound
- if ( powerups & ( 1 << PW_FLIGHT ) ) {
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.flightSound );
- }
-
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- // redflag
- if ( powerups & ( 1 << PW_REDFLAG ) ) {
- if (ci->newAnims) {
- CG_PlayerFlag( cent, cgs.media.redFlagFlapSkin, torso );
- }
- else {
- CG_TrailItem( cent, cgs.media.redFlagModel );
- }
- trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 0.2f, 0.2f );
- }
-
- // blueflag
- if ( powerups & ( 1 << PW_BLUEFLAG ) ) {
- if (ci->newAnims){
- CG_PlayerFlag( cent, cgs.media.blueFlagFlapSkin, torso );
- }
- else {
- CG_TrailItem( cent, cgs.media.blueFlagModel );
- }
- trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1.0 );
- }
-
- // neutralflag
- if ( powerups & ( 1 << PW_NEUTRALFLAG ) ) {
- if (ci->newAnims) {
- CG_PlayerFlag( cent, cgs.media.neutralFlagFlapSkin, torso );
- }
- else {
- CG_TrailItem( cent, cgs.media.neutralFlagModel );
- }
- trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 1.0, 1.0 );
- }
-
- // haste leaves smoke trails
- if ( powerups & ( 1 << PW_HASTE ) ) {
- CG_HasteTrail( cent );
- }
-}
-
-
-/*
-===============
-CG_PlayerFloatSprite
-
-Float a sprite over the player's head
-===============
-*/
-static void CG_PlayerFloatSprite( centity_t *cent, qhandle_t shader ) {
- int rf;
- refEntity_t ent;
-
- if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) {
- rf = RF_THIRD_PERSON; // only show in mirrors
- } else {
- rf = 0;
- }
-
- memset( &ent, 0, sizeof( ent ) );
- VectorCopy( cent->lerpOrigin, ent.origin );
- ent.origin[2] += 48;
- ent.reType = RT_SPRITE;
- ent.customShader = shader;
- ent.radius = 10;
- ent.renderfx = rf;
- ent.shaderRGBA[0] = 255;
- ent.shaderRGBA[1] = 255;
- ent.shaderRGBA[2] = 255;
- ent.shaderRGBA[3] = 255;
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-
-/*
-===============
-CG_PlayerSprites
-
-Float sprites over the player's head
-===============
-*/
-static void CG_PlayerSprites( centity_t *cent ) {
- int team;
-
- if ( cent->currentState.eFlags & EF_CONNECTION ) {
- CG_PlayerFloatSprite( cent, cgs.media.connectionShader );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_TALK ) {
- CG_PlayerFloatSprite( cent, cgs.media.balloonShader );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_IMPRESSIVE ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalImpressive );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_EXCELLENT ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalExcellent );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_GAUNTLET ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalGauntlet );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_DEFEND ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalDefend );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_ASSIST ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalAssist );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_CAP ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalCapture );
- return;
- }
-
- team = cgs.clientinfo[ cent->currentState.clientNum ].team;
- if ( !(cent->currentState.eFlags & EF_DEAD) &&
- cg.snap->ps.persistant[PERS_TEAM] == team &&
- cgs.gametype >= GT_TEAM) {
- if (cg_drawFriend.integer) {
- CG_PlayerFloatSprite( cent, cgs.media.friendShader );
- }
- return;
- }
-}
-
-/*
-===============
-CG_PlayerShadow
-
-Returns the Z component of the surface being shadowed
-
- should it return a full plane instead of a Z?
-===============
-*/
-#define SHADOW_DISTANCE 128
-static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane ) {
- vec3_t end, mins = {-15, -15, 0}, maxs = {15, 15, 2};
- trace_t trace;
- float alpha;
-
- *shadowPlane = 0;
-
- if ( cg_shadows.integer == 0 ) {
- return qfalse;
- }
-
- // no shadows when invisible
- if ( cent->currentState.powerups & ( 1 << PW_INVIS ) ) {
- return qfalse;
- }
-
- // send a trace down from the player to the ground
- VectorCopy( cent->lerpOrigin, end );
- end[2] -= SHADOW_DISTANCE;
-
- trap_CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID );
-
- // no shadow if too high
- if ( trace.fraction == 1.0 || trace.startsolid || trace.allsolid ) {
- return qfalse;
- }
-
- *shadowPlane = trace.endpos[2] + 1;
-
- if ( cg_shadows.integer != 1 ) { // no mark for stencil or projection shadows
- return qtrue;
- }
-
- // fade the shadow out with height
- alpha = 1.0 - trace.fraction;
-
- // hack / FPE - bogus planes?
- //assert( DotProduct( trace.plane.normal, trace.plane.normal ) != 0.0f )
-
- // add the mark as a temporary, so it goes directly to the renderer
- // without taking a spot in the cg_marks array
- CG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal,
- cent->pe.legs.yawAngle, alpha,alpha,alpha,1, qfalse, 24, qtrue );
-
- return qtrue;
-}
-
-
-/*
-===============
-CG_PlayerSplash
-
-Draw a mark at the water surface
-===============
-*/
-static void CG_PlayerSplash( centity_t *cent ) {
- vec3_t start, end;
- trace_t trace;
- int contents;
- polyVert_t verts[4];
-
- if ( !cg_shadows.integer ) {
- return;
- }
-
- VectorCopy( cent->lerpOrigin, end );
- end[2] -= 24;
-
- // if the feet aren't in liquid, don't make a mark
- // this won't handle moving water brushes, but they wouldn't draw right anyway...
- contents = trap_CM_PointContents( end, 0 );
- if ( !( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) ) {
- return;
- }
-
- VectorCopy( cent->lerpOrigin, start );
- start[2] += 32;
-
- // if the head isn't out of liquid, don't make a mark
- contents = trap_CM_PointContents( start, 0 );
- if ( contents & ( CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- return;
- }
-
- // trace down to find the surface
- trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) );
-
- if ( trace.fraction == 1.0 ) {
- return;
- }
-
- // create a mark polygon
- VectorCopy( trace.endpos, verts[0].xyz );
- verts[0].xyz[0] -= 32;
- verts[0].xyz[1] -= 32;
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- VectorCopy( trace.endpos, verts[1].xyz );
- verts[1].xyz[0] -= 32;
- verts[1].xyz[1] += 32;
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- VectorCopy( trace.endpos, verts[2].xyz );
- verts[2].xyz[0] += 32;
- verts[2].xyz[1] += 32;
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- VectorCopy( trace.endpos, verts[3].xyz );
- verts[3].xyz[0] += 32;
- verts[3].xyz[1] -= 32;
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
-
- trap_R_AddPolyToScene( cgs.media.wakeMarkShader, 4, verts );
-}
-
-
-
-/*
-===============
-CG_AddRefEntityWithPowerups
-
-Adds a piece with modifications or duplications for powerups
-Also called by CG_Missile for quad rockets, but nobody can tell...
-===============
-*/
-void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team ) {
-
- if ( state->powerups & ( 1 << PW_INVIS ) ) {
- ent->customShader = cgs.media.invisShader;
- trap_R_AddRefEntityToScene( ent );
- } else {
- /*
- if ( state->eFlags & EF_KAMIKAZE ) {
- if (team == TEAM_BLUE)
- ent->customShader = cgs.media.blueKamikazeShader;
- else
- ent->customShader = cgs.media.redKamikazeShader;
- trap_R_AddRefEntityToScene( ent );
- }
- else {*/
- trap_R_AddRefEntityToScene( ent );
- //}
-
- if ( state->powerups & ( 1 << PW_QUAD ) )
- {
- if (team == TEAM_RED)
- ent->customShader = cgs.media.redQuadShader;
- else
- ent->customShader = cgs.media.quadShader;
- trap_R_AddRefEntityToScene( ent );
- }
- if ( state->powerups & ( 1 << PW_REGEN ) ) {
- if ( ( ( cg.time / 100 ) % 10 ) == 1 ) {
- ent->customShader = cgs.media.regenShader;
- trap_R_AddRefEntityToScene( ent );
- }
- }
- if ( state->powerups & ( 1 << PW_BATTLESUIT ) ) {
- ent->customShader = cgs.media.battleSuitShader;
- trap_R_AddRefEntityToScene( ent );
- }
- }
-}
-
-/*
-=================
-CG_LightVerts
-=================
-*/
-int CG_LightVerts( vec3_t normal, int numVerts, polyVert_t *verts )
-{
- int i, j;
- float incoming;
- vec3_t ambientLight;
- vec3_t lightDir;
- vec3_t directedLight;
-
- trap_R_LightForPoint( verts[0].xyz, ambientLight, directedLight, lightDir );
-
- for (i = 0; i < numVerts; i++) {
- incoming = DotProduct (normal, lightDir);
- if ( incoming <= 0 ) {
- verts[i].modulate[0] = ambientLight[0];
- verts[i].modulate[1] = ambientLight[1];
- verts[i].modulate[2] = ambientLight[2];
- verts[i].modulate[3] = 255;
- continue;
- }
- j = ( ambientLight[0] + incoming * directedLight[0] );
- if ( j > 255 ) {
- j = 255;
- }
- verts[i].modulate[0] = j;
-
- j = ( ambientLight[1] + incoming * directedLight[1] );
- if ( j > 255 ) {
- j = 255;
- }
- verts[i].modulate[1] = j;
-
- j = ( ambientLight[2] + incoming * directedLight[2] );
- if ( j > 255 ) {
- j = 255;
- }
- verts[i].modulate[2] = j;
-
- verts[i].modulate[3] = 255;
- }
- return qtrue;
-}
-
-/*
-===============
-CG_Player
-===============
-*/
-void CG_Player( centity_t *cent ) {
- clientInfo_t *ci;
- refEntity_t legs;
- refEntity_t torso;
- refEntity_t head;
- int clientNum;
- int renderfx;
- qboolean shadow;
- float shadowPlane;
-#ifdef MISSIONPACK
- refEntity_t skull;
- refEntity_t powerup;
- int t;
- float c;
- float angle;
- vec3_t dir, angles;
-#endif
-
- // the client number is stored in clientNum. It can't be derived
- // from the entity number, because a single client may have
- // multiple corpses on the level using the same clientinfo
- clientNum = cent->currentState.clientNum;
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- CG_Error( "Bad clientNum on player entity");
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- // it is possible to see corpses from disconnected players that may
- // not have valid clientinfo
- if ( !ci->infoValid ) {
- return;
- }
-
- // get the player model information
- renderfx = 0;
- if ( cent->currentState.number == cg.snap->ps.clientNum) {
- if (!cg.renderingThirdPerson) {
- renderfx = RF_THIRD_PERSON; // only draw in mirrors
- } else {
- if (cg_cameraMode.integer) {
- return;
- }
- }
- }
-
-
- memset( &legs, 0, sizeof(legs) );
- memset( &torso, 0, sizeof(torso) );
- memset( &head, 0, sizeof(head) );
-
- // get the rotation information
- CG_PlayerAngles( cent, legs.axis, torso.axis, head.axis );
-
- // get the animation state (after rotation, to allow feet shuffle)
- CG_PlayerAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp,
- &torso.oldframe, &torso.frame, &torso.backlerp );
-
- // add the talk baloon or disconnect icon
- CG_PlayerSprites( cent );
-
- // add the shadow
- shadow = CG_PlayerShadow( cent, &shadowPlane );
-
- // add a water splash if partially in and out of water
- CG_PlayerSplash( cent );
-
- if ( cg_shadows.integer == 3 && shadow ) {
- renderfx |= RF_SHADOW_PLANE;
- }
- renderfx |= RF_LIGHTING_ORIGIN; // use the same origin for all
-#ifdef MISSIONPACK
- if( cgs.gametype == GT_HARVESTER ) {
- CG_PlayerTokens( cent, renderfx );
- }
-#endif
- //
- // add the legs
- //
- legs.hModel = ci->legsModel;
- legs.customSkin = ci->legsSkin;
-
- VectorCopy( cent->lerpOrigin, legs.origin );
-
- VectorCopy( cent->lerpOrigin, legs.lightingOrigin );
- legs.shadowPlane = shadowPlane;
- legs.renderfx = renderfx;
- VectorCopy (legs.origin, legs.oldorigin); // don't positionally lerp at all
-
- CG_AddRefEntityWithPowerups( &legs, ¢->currentState, ci->team );
-
- // if the model failed, allow the default nullmodel to be displayed
- if (!legs.hModel) {
- return;
- }
-
- //
- // add the torso
- //
- torso.hModel = ci->torsoModel;
- if (!torso.hModel) {
- return;
- }
-
- torso.customSkin = ci->torsoSkin;
-
- VectorCopy( cent->lerpOrigin, torso.lightingOrigin );
-
- CG_PositionRotatedEntityOnTag( &torso, &legs, ci->legsModel, "tag_torso");
-
- torso.shadowPlane = shadowPlane;
- torso.renderfx = renderfx;
-
- CG_AddRefEntityWithPowerups( &torso, ¢->currentState, ci->team );
-
-#ifdef MISSIONPACK
- if ( cent->currentState.eFlags & EF_KAMIKAZE ) {
-
- memset( &skull, 0, sizeof(skull) );
-
- VectorCopy( cent->lerpOrigin, skull.lightingOrigin );
- skull.shadowPlane = shadowPlane;
- skull.renderfx = renderfx;
-
- if ( cent->currentState.eFlags & EF_DEAD ) {
- // one skull bobbing above the dead body
- angle = ((cg.time / 7) & 255) * (M_PI * 2) / 255;
- if (angle > M_PI * 2)
- angle -= (float)M_PI * 2;
- dir[0] = sin(angle) * 20;
- dir[1] = cos(angle) * 20;
- angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255;
- dir[2] = 15 + sin(angle) * 8;
- VectorAdd(torso.origin, dir, skull.origin);
-
- dir[2] = 0;
- VectorCopy(dir, skull.axis[1]);
- VectorNormalize(skull.axis[1]);
- VectorSet(skull.axis[2], 0, 0, 1);
- CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
-
- skull.hModel = cgs.media.kamikazeHeadModel;
- trap_R_AddRefEntityToScene( &skull );
- skull.hModel = cgs.media.kamikazeHeadTrail;
- trap_R_AddRefEntityToScene( &skull );
- }
- else {
- // three skulls spinning around the player
- angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255;
- dir[0] = cos(angle) * 20;
- dir[1] = sin(angle) * 20;
- dir[2] = cos(angle) * 20;
- VectorAdd(torso.origin, dir, skull.origin);
-
- angles[0] = sin(angle) * 30;
- angles[1] = (angle * 180 / M_PI) + 90;
- if (angles[1] > 360)
- angles[1] -= 360;
- angles[2] = 0;
- AnglesToAxis( angles, skull.axis );
-
- /*
- dir[2] = 0;
- VectorInverse(dir);
- VectorCopy(dir, skull.axis[1]);
- VectorNormalize(skull.axis[1]);
- VectorSet(skull.axis[2], 0, 0, 1);
- CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
- */
-
- skull.hModel = cgs.media.kamikazeHeadModel;
- trap_R_AddRefEntityToScene( &skull );
- // flip the trail because this skull is spinning in the other direction
- VectorInverse(skull.axis[1]);
- skull.hModel = cgs.media.kamikazeHeadTrail;
- trap_R_AddRefEntityToScene( &skull );
-
- angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255 + M_PI;
- if (angle > M_PI * 2)
- angle -= (float)M_PI * 2;
- dir[0] = sin(angle) * 20;
- dir[1] = cos(angle) * 20;
- dir[2] = cos(angle) * 20;
- VectorAdd(torso.origin, dir, skull.origin);
-
- angles[0] = cos(angle - 0.5 * M_PI) * 30;
- angles[1] = 360 - (angle * 180 / M_PI);
- if (angles[1] > 360)
- angles[1] -= 360;
- angles[2] = 0;
- AnglesToAxis( angles, skull.axis );
-
- /*
- dir[2] = 0;
- VectorCopy(dir, skull.axis[1]);
- VectorNormalize(skull.axis[1]);
- VectorSet(skull.axis[2], 0, 0, 1);
- CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
- */
-
- skull.hModel = cgs.media.kamikazeHeadModel;
- trap_R_AddRefEntityToScene( &skull );
- skull.hModel = cgs.media.kamikazeHeadTrail;
- trap_R_AddRefEntityToScene( &skull );
-
- angle = ((cg.time / 3) & 255) * (M_PI * 2) / 255 + 0.5 * M_PI;
- if (angle > M_PI * 2)
- angle -= (float)M_PI * 2;
- dir[0] = sin(angle) * 20;
- dir[1] = cos(angle) * 20;
- dir[2] = 0;
- VectorAdd(torso.origin, dir, skull.origin);
-
- VectorCopy(dir, skull.axis[1]);
- VectorNormalize(skull.axis[1]);
- VectorSet(skull.axis[2], 0, 0, 1);
- CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
-
- skull.hModel = cgs.media.kamikazeHeadModel;
- trap_R_AddRefEntityToScene( &skull );
- skull.hModel = cgs.media.kamikazeHeadTrail;
- trap_R_AddRefEntityToScene( &skull );
- }
- }
-
- if ( cent->currentState.powerups & ( 1 << PW_GUARD ) ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.guardPowerupModel;
- powerup.frame = 0;
- powerup.oldframe = 0;
- powerup.customSkin = 0;
- trap_R_AddRefEntityToScene( &powerup );
- }
- if ( cent->currentState.powerups & ( 1 << PW_SCOUT ) ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.scoutPowerupModel;
- powerup.frame = 0;
- powerup.oldframe = 0;
- powerup.customSkin = 0;
- trap_R_AddRefEntityToScene( &powerup );
- }
- if ( cent->currentState.powerups & ( 1 << PW_DOUBLER ) ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.doublerPowerupModel;
- powerup.frame = 0;
- powerup.oldframe = 0;
- powerup.customSkin = 0;
- trap_R_AddRefEntityToScene( &powerup );
- }
- if ( cent->currentState.powerups & ( 1 << PW_AMMOREGEN ) ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.ammoRegenPowerupModel;
- powerup.frame = 0;
- powerup.oldframe = 0;
- powerup.customSkin = 0;
- trap_R_AddRefEntityToScene( &powerup );
- }
- if ( cent->currentState.powerups & ( 1 << PW_INVULNERABILITY ) ) {
- if ( !ci->invulnerabilityStartTime ) {
- ci->invulnerabilityStartTime = cg.time;
- }
- ci->invulnerabilityStopTime = cg.time;
- }
- else {
- ci->invulnerabilityStartTime = 0;
- }
- if ( (cent->currentState.powerups & ( 1 << PW_INVULNERABILITY ) ) ||
- cg.time - ci->invulnerabilityStopTime < 250 ) {
-
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.invulnerabilityPowerupModel;
- powerup.customSkin = 0;
- // always draw
- powerup.renderfx &= ~RF_THIRD_PERSON;
- VectorCopy(cent->lerpOrigin, powerup.origin);
-
- if ( cg.time - ci->invulnerabilityStartTime < 250 ) {
- c = (float) (cg.time - ci->invulnerabilityStartTime) / 250;
- }
- else if (cg.time - ci->invulnerabilityStopTime < 250 ) {
- c = (float) (250 - (cg.time - ci->invulnerabilityStopTime)) / 250;
- }
- else {
- c = 1;
- }
- VectorSet( powerup.axis[0], c, 0, 0 );
- VectorSet( powerup.axis[1], 0, c, 0 );
- VectorSet( powerup.axis[2], 0, 0, c );
- trap_R_AddRefEntityToScene( &powerup );
- }
-
- t = cg.time - ci->medkitUsageTime;
- if ( ci->medkitUsageTime && t < 500 ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.medkitUsageModel;
- powerup.customSkin = 0;
- // always draw
- powerup.renderfx &= ~RF_THIRD_PERSON;
- VectorClear(angles);
- AnglesToAxis(angles, powerup.axis);
- VectorCopy(cent->lerpOrigin, powerup.origin);
- powerup.origin[2] += -24 + (float) t * 80 / 500;
- if ( t > 400 ) {
- c = (float) (t - 1000) * 0xff / 100;
- powerup.shaderRGBA[0] = 0xff - c;
- powerup.shaderRGBA[1] = 0xff - c;
- powerup.shaderRGBA[2] = 0xff - c;
- powerup.shaderRGBA[3] = 0xff - c;
- }
- else {
- powerup.shaderRGBA[0] = 0xff;
- powerup.shaderRGBA[1] = 0xff;
- powerup.shaderRGBA[2] = 0xff;
- powerup.shaderRGBA[3] = 0xff;
- }
- trap_R_AddRefEntityToScene( &powerup );
- }
-#endif // MISSIONPACK
-
- //
- // add the head
- //
- head.hModel = ci->headModel;
- if (!head.hModel) {
- return;
- }
- head.customSkin = ci->headSkin;
-
- VectorCopy( cent->lerpOrigin, head.lightingOrigin );
-
- CG_PositionRotatedEntityOnTag( &head, &torso, ci->torsoModel, "tag_head");
-
- head.shadowPlane = shadowPlane;
- head.renderfx = renderfx;
-
- CG_AddRefEntityWithPowerups( &head, ¢->currentState, ci->team );
-
-#ifdef MISSIONPACK
- CG_BreathPuffs(cent, &head);
-
- CG_DustTrail(cent);
-#endif
-
- //
- // add the gun / barrel / flash
- //
- CG_AddPlayerWeapon( &torso, NULL, cent, ci->team );
-
- // add powerups floating behind the player
- CG_PlayerPowerups( cent, &torso );
-}
-
-
-//=====================================================================
-
-/*
-===============
-CG_ResetPlayerEntity
-
-A player just came into view or teleported, so reset all animation info
-===============
-*/
-void CG_ResetPlayerEntity( centity_t *cent ) {
- cent->errorTime = -99999; // guarantee no error decay added
- cent->extrapolated = qfalse;
-
- CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.legs, cent->currentState.legsAnim );
- CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.torso, cent->currentState.torsoAnim );
-
- BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin );
- BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles );
-
- VectorCopy( cent->lerpOrigin, cent->rawOrigin );
- VectorCopy( cent->lerpAngles, cent->rawAngles );
-
- memset( ¢->pe.legs, 0, sizeof( cent->pe.legs ) );
- cent->pe.legs.yawAngle = cent->rawAngles[YAW];
- cent->pe.legs.yawing = qfalse;
- cent->pe.legs.pitchAngle = 0;
- cent->pe.legs.pitching = qfalse;
-
- memset( ¢->pe.torso, 0, sizeof( cent->pe.legs ) );
- cent->pe.torso.yawAngle = cent->rawAngles[YAW];
- cent->pe.torso.yawing = qfalse;
- cent->pe.torso.pitchAngle = cent->rawAngles[PITCH];
- cent->pe.torso.pitching = qfalse;
-
- if ( cg_debugPosition.integer ) {
- CG_Printf("%i ResetPlayerEntity yaw=%i\n", cent->currentState.number, cent->pe.torso.yawAngle );
- }
-}
-
diff --git a/engine/code/cgame/cg_playerstate.c b/engine/code/cgame/cg_playerstate.c
deleted file mode 100644
index 4df2da6..0000000
--- a/engine/code/cgame/cg_playerstate.c
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_playerstate.c -- this file acts on changes in a new playerState_t
-// With normal play, this will be done after local prediction, but when
-// following another player or playing back a demo, it will be checked
-// when the snapshot transitions like all the other entities
-
-#include "cg_local.h"
-
-/*
-==============
-CG_CheckAmmo
-
-If the ammo has gone low enough to generate the warning, play a sound
-==============
-*/
-void CG_CheckAmmo( void ) {
- int i;
- int total;
- int previous;
- int weapons;
-
- // see about how many seconds of ammo we have remaining
- weapons = cg.snap->ps.stats[ STAT_WEAPONS ];
- total = 0;
- for ( i = WP_MACHINEGUN ; i < WP_NUM_WEAPONS ; i++ ) {
- if ( ! ( weapons & ( 1 << i ) ) ) {
- continue;
- }
- switch ( i ) {
- case WP_ROCKET_LAUNCHER:
- case WP_GRENADE_LAUNCHER:
- case WP_RAILGUN:
- case WP_SHOTGUN:
-#ifdef MISSIONPACK
- case WP_PROX_LAUNCHER:
-#endif
- total += cg.snap->ps.ammo[i] * 1000;
- break;
- default:
- total += cg.snap->ps.ammo[i] * 200;
- break;
- }
- if ( total >= 5000 ) {
- cg.lowAmmoWarning = 0;
- return;
- }
- }
-
- previous = cg.lowAmmoWarning;
-
- if ( total == 0 ) {
- cg.lowAmmoWarning = 2;
- } else {
- cg.lowAmmoWarning = 1;
- }
-
- // play a sound on transitions
- if ( cg.lowAmmoWarning != previous ) {
- trap_S_StartLocalSound( cgs.media.noAmmoSound, CHAN_LOCAL_SOUND );
- }
-}
-
-/*
-==============
-CG_DamageFeedback
-==============
-*/
-void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) {
- float left, front, up;
- float kick;
- int health;
- float scale;
- vec3_t dir;
- vec3_t angles;
- float dist;
- float yaw, pitch;
-
- // show the attacking player's head and name in corner
- cg.attackerTime = cg.time;
-
- // the lower on health you are, the greater the view kick will be
- health = cg.snap->ps.stats[STAT_HEALTH];
- if ( health < 40 ) {
- scale = 1;
- } else {
- scale = 40.0 / health;
- }
- kick = damage * scale;
-
- if (kick < 5)
- kick = 5;
- if (kick > 10)
- kick = 10;
-
- // if yaw and pitch are both 255, make the damage always centered (falling, etc)
- if ( yawByte == 255 && pitchByte == 255 ) {
- cg.damageX = 0;
- cg.damageY = 0;
- cg.v_dmg_roll = 0;
- cg.v_dmg_pitch = -kick;
- } else {
- // positional
- pitch = pitchByte / 255.0 * 360;
- yaw = yawByte / 255.0 * 360;
-
- angles[PITCH] = pitch;
- angles[YAW] = yaw;
- angles[ROLL] = 0;
-
- AngleVectors( angles, dir, NULL, NULL );
- VectorSubtract( vec3_origin, dir, dir );
-
- front = DotProduct (dir, cg.refdef.viewaxis[0] );
- left = DotProduct (dir, cg.refdef.viewaxis[1] );
- up = DotProduct (dir, cg.refdef.viewaxis[2] );
-
- dir[0] = front;
- dir[1] = left;
- dir[2] = 0;
- dist = VectorLength( dir );
- if ( dist < 0.1 ) {
- dist = 0.1f;
- }
-
- cg.v_dmg_roll = kick * left;
-
- cg.v_dmg_pitch = -kick * front;
-
- if ( front <= 0.1 ) {
- front = 0.1f;
- }
- cg.damageX = -left / front;
- cg.damageY = up / dist;
- }
-
- // clamp the position
- if ( cg.damageX > 1.0 ) {
- cg.damageX = 1.0;
- }
- if ( cg.damageX < - 1.0 ) {
- cg.damageX = -1.0;
- }
-
- if ( cg.damageY > 1.0 ) {
- cg.damageY = 1.0;
- }
- if ( cg.damageY < - 1.0 ) {
- cg.damageY = -1.0;
- }
-
- // don't let the screen flashes vary as much
- if ( kick > 10 ) {
- kick = 10;
- }
- cg.damageValue = kick;
- cg.v_dmg_time = cg.time + DAMAGE_TIME;
- cg.damageTime = cg.snap->serverTime;
-}
-
-
-
-
-/*
-================
-CG_Respawn
-
-A respawn happened this snapshot
-================
-*/
-void CG_Respawn( void ) {
- // no error decay on player movement
- cg.thisFrameTeleport = qtrue;
-
- // display weapons available
- cg.weaponSelectTime = cg.time;
-
- // select the weapon the server says we are using
- cg.weaponSelect = cg.snap->ps.weapon;
-}
-
-extern char *eventnames[];
-
-/*
-==============
-CG_CheckPlayerstateEvents
-==============
-*/
-void CG_CheckPlayerstateEvents( playerState_t *ps, playerState_t *ops ) {
- int i;
- int event;
- centity_t *cent;
-
- if ( ps->externalEvent && ps->externalEvent != ops->externalEvent ) {
- cent = &cg_entities[ ps->clientNum ];
- cent->currentState.event = ps->externalEvent;
- cent->currentState.eventParm = ps->externalEventParm;
- CG_EntityEvent( cent, cent->lerpOrigin );
- }
-
- cent = &cg.predictedPlayerEntity; // cg_entities[ ps->clientNum ];
- // go through the predictable events buffer
- for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {
- // if we have a new predictable event
- if ( i >= ops->eventSequence
- // or the server told us to play another event instead of a predicted event we already issued
- // or something the server told us changed our prediction causing a different event
- || (i > ops->eventSequence - MAX_PS_EVENTS && ps->events[i & (MAX_PS_EVENTS-1)] != ops->events[i & (MAX_PS_EVENTS-1)]) ) {
-
- event = ps->events[ i & (MAX_PS_EVENTS-1) ];
- cent->currentState.event = event;
- cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];
- CG_EntityEvent( cent, cent->lerpOrigin );
-
- cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event;
-
- cg.eventSequence++;
- }
- }
-}
-
-/*
-==================
-CG_CheckChangedPredictableEvents
-==================
-*/
-void CG_CheckChangedPredictableEvents( playerState_t *ps ) {
- int i;
- int event;
- centity_t *cent;
-
- cent = &cg.predictedPlayerEntity;
- for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {
- //
- if (i >= cg.eventSequence) {
- continue;
- }
- // if this event is not further back in than the maximum predictable events we remember
- if (i > cg.eventSequence - MAX_PREDICTED_EVENTS) {
- // if the new playerstate event is different from a previously predicted one
- if ( ps->events[i & (MAX_PS_EVENTS-1)] != cg.predictableEvents[i & (MAX_PREDICTED_EVENTS-1) ] ) {
-
- event = ps->events[ i & (MAX_PS_EVENTS-1) ];
- cent->currentState.event = event;
- cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];
- CG_EntityEvent( cent, cent->lerpOrigin );
-
- cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event;
-
- if ( cg_showmiss.integer ) {
- CG_Printf("WARNING: changed predicted event\n");
- }
- }
- }
- }
-}
-
-/*
-==================
-pushReward
-==================
-*/
-static void pushReward(sfxHandle_t sfx, qhandle_t shader, int rewardCount) {
- if (cg.rewardStack < (MAX_REWARDSTACK-1)) {
- cg.rewardStack++;
- cg.rewardSound[cg.rewardStack] = sfx;
- cg.rewardShader[cg.rewardStack] = shader;
- cg.rewardCount[cg.rewardStack] = rewardCount;
- }
-}
-
-/*
-==================
-CG_CheckLocalSounds
-==================
-*/
-void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) {
- int highScore, health, armor, reward;
- sfxHandle_t sfx;
-
- // don't play the sounds if the player just changed teams
- if ( ps->persistant[PERS_TEAM] != ops->persistant[PERS_TEAM] ) {
- return;
- }
-
- // hit changes
- if ( ps->persistant[PERS_HITS] > ops->persistant[PERS_HITS] ) {
- armor = ps->persistant[PERS_ATTACKEE_ARMOR] & 0xff;
- health = ps->persistant[PERS_ATTACKEE_ARMOR] >> 8;
-#ifdef MISSIONPACK
- if (armor > 50 ) {
- trap_S_StartLocalSound( cgs.media.hitSoundHighArmor, CHAN_LOCAL_SOUND );
- } else if (armor || health > 100) {
- trap_S_StartLocalSound( cgs.media.hitSoundLowArmor, CHAN_LOCAL_SOUND );
- } else {
- trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND );
- }
-#else
- trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND );
-#endif
- } else if ( ps->persistant[PERS_HITS] < ops->persistant[PERS_HITS] ) {
- trap_S_StartLocalSound( cgs.media.hitTeamSound, CHAN_LOCAL_SOUND );
- }
-
- // health changes of more than -1 should make pain sounds
- if ( ps->stats[STAT_HEALTH] < ops->stats[STAT_HEALTH] - 1 ) {
- if ( ps->stats[STAT_HEALTH] > 0 ) {
- CG_PainEvent( &cg.predictedPlayerEntity, ps->stats[STAT_HEALTH] );
- }
- }
-
-
- // if we are going into the intermission, don't start any voices
- if ( cg.intermissionStarted ) {
- return;
- }
-
- // reward sounds
- reward = qfalse;
- if (ps->persistant[PERS_CAPTURES] != ops->persistant[PERS_CAPTURES]) {
- pushReward(cgs.media.captureAwardSound, cgs.media.medalCapture, ps->persistant[PERS_CAPTURES]);
- reward = qtrue;
- //Com_Printf("capture\n");
- }
- if (ps->persistant[PERS_IMPRESSIVE_COUNT] != ops->persistant[PERS_IMPRESSIVE_COUNT]) {
-#ifdef MISSIONPACK
- if (ps->persistant[PERS_IMPRESSIVE_COUNT] == 1) {
- sfx = cgs.media.firstImpressiveSound;
- } else {
- sfx = cgs.media.impressiveSound;
- }
-#else
- sfx = cgs.media.impressiveSound;
-#endif
- pushReward(sfx, cgs.media.medalImpressive, ps->persistant[PERS_IMPRESSIVE_COUNT]);
- reward = qtrue;
- //Com_Printf("impressive\n");
- }
- if (ps->persistant[PERS_EXCELLENT_COUNT] != ops->persistant[PERS_EXCELLENT_COUNT]) {
-#ifdef MISSIONPACK
- if (ps->persistant[PERS_EXCELLENT_COUNT] == 1) {
- sfx = cgs.media.firstExcellentSound;
- } else {
- sfx = cgs.media.excellentSound;
- }
-#else
- sfx = cgs.media.excellentSound;
-#endif
- pushReward(sfx, cgs.media.medalExcellent, ps->persistant[PERS_EXCELLENT_COUNT]);
- reward = qtrue;
- //Com_Printf("excellent\n");
- }
- if (ps->persistant[PERS_GAUNTLET_FRAG_COUNT] != ops->persistant[PERS_GAUNTLET_FRAG_COUNT]) {
-#ifdef MISSIONPACK
- if (ops->persistant[PERS_GAUNTLET_FRAG_COUNT] == 1) {
- sfx = cgs.media.firstHumiliationSound;
- } else {
- sfx = cgs.media.humiliationSound;
- }
-#else
- sfx = cgs.media.humiliationSound;
-#endif
- pushReward(sfx, cgs.media.medalGauntlet, ps->persistant[PERS_GAUNTLET_FRAG_COUNT]);
- reward = qtrue;
- //Com_Printf("guantlet frag\n");
- }
- if (ps->persistant[PERS_DEFEND_COUNT] != ops->persistant[PERS_DEFEND_COUNT]) {
- pushReward(cgs.media.defendSound, cgs.media.medalDefend, ps->persistant[PERS_DEFEND_COUNT]);
- reward = qtrue;
- //Com_Printf("defend\n");
- }
- if (ps->persistant[PERS_ASSIST_COUNT] != ops->persistant[PERS_ASSIST_COUNT]) {
- pushReward(cgs.media.assistSound, cgs.media.medalAssist, ps->persistant[PERS_ASSIST_COUNT]);
- reward = qtrue;
- //Com_Printf("assist\n");
- }
- // if any of the player event bits changed
- if (ps->persistant[PERS_PLAYEREVENTS] != ops->persistant[PERS_PLAYEREVENTS]) {
- if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD) !=
- (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD)) {
- trap_S_StartLocalSound( cgs.media.deniedSound, CHAN_ANNOUNCER );
- }
- else if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD) !=
- (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD)) {
- trap_S_StartLocalSound( cgs.media.humiliationSound, CHAN_ANNOUNCER );
- }
- else if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT) !=
- (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT)) {
- trap_S_StartLocalSound( cgs.media.holyShitSound, CHAN_ANNOUNCER );
- }
- reward = qtrue;
- }
-
- // check for flag pickup
- if ( cgs.gametype >= GT_TEAM ) {
- if ((ps->powerups[PW_REDFLAG] != ops->powerups[PW_REDFLAG] && ps->powerups[PW_REDFLAG]) ||
- (ps->powerups[PW_BLUEFLAG] != ops->powerups[PW_BLUEFLAG] && ps->powerups[PW_BLUEFLAG]) ||
- (ps->powerups[PW_NEUTRALFLAG] != ops->powerups[PW_NEUTRALFLAG] && ps->powerups[PW_NEUTRALFLAG]) )
- {
- trap_S_StartLocalSound( cgs.media.youHaveFlagSound, CHAN_ANNOUNCER );
- }
- }
-
- // lead changes
- if (!reward) {
- //
- if ( !cg.warmup ) {
- // never play lead changes during warmup
- if ( ps->persistant[PERS_RANK] != ops->persistant[PERS_RANK] ) {
- if ( cgs.gametype < GT_TEAM) {
- if ( ps->persistant[PERS_RANK] == 0 ) {
- CG_AddBufferedSound(cgs.media.takenLeadSound);
- } else if ( ps->persistant[PERS_RANK] == RANK_TIED_FLAG ) {
- CG_AddBufferedSound(cgs.media.tiedLeadSound);
- } else if ( ( ops->persistant[PERS_RANK] & ~RANK_TIED_FLAG ) == 0 ) {
- CG_AddBufferedSound(cgs.media.lostLeadSound);
- }
- }
- }
- }
- }
-
- // timelimit warnings
- if ( cgs.timelimit > 0 ) {
- int msec;
-
- msec = cg.time - cgs.levelStartTime;
- if ( !( cg.timelimitWarnings & 4 ) && msec > ( cgs.timelimit * 60 + 2 ) * 1000 ) {
- cg.timelimitWarnings |= 1 | 2 | 4;
- trap_S_StartLocalSound( cgs.media.suddenDeathSound, CHAN_ANNOUNCER );
- }
- else if ( !( cg.timelimitWarnings & 2 ) && msec > (cgs.timelimit - 1) * 60 * 1000 ) {
- cg.timelimitWarnings |= 1 | 2;
- trap_S_StartLocalSound( cgs.media.oneMinuteSound, CHAN_ANNOUNCER );
- }
- else if ( cgs.timelimit > 5 && !( cg.timelimitWarnings & 1 ) && msec > (cgs.timelimit - 5) * 60 * 1000 ) {
- cg.timelimitWarnings |= 1;
- trap_S_StartLocalSound( cgs.media.fiveMinuteSound, CHAN_ANNOUNCER );
- }
- }
-
- // fraglimit warnings
- if ( cgs.fraglimit > 0 && cgs.gametype < GT_CTF) {
- highScore = cgs.scores1;
- if ( !( cg.fraglimitWarnings & 4 ) && highScore == (cgs.fraglimit - 1) ) {
- cg.fraglimitWarnings |= 1 | 2 | 4;
- CG_AddBufferedSound(cgs.media.oneFragSound);
- }
- else if ( cgs.fraglimit > 2 && !( cg.fraglimitWarnings & 2 ) && highScore == (cgs.fraglimit - 2) ) {
- cg.fraglimitWarnings |= 1 | 2;
- CG_AddBufferedSound(cgs.media.twoFragSound);
- }
- else if ( cgs.fraglimit > 3 && !( cg.fraglimitWarnings & 1 ) && highScore == (cgs.fraglimit - 3) ) {
- cg.fraglimitWarnings |= 1;
- CG_AddBufferedSound(cgs.media.threeFragSound);
- }
- }
-}
-
-/*
-===============
-CG_TransitionPlayerState
-
-===============
-*/
-void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) {
- // check for changing follow mode
- if ( ps->clientNum != ops->clientNum ) {
- cg.thisFrameTeleport = qtrue;
- // make sure we don't get any unwanted transition effects
- *ops = *ps;
- }
-
- // damage events (player is getting wounded)
- if ( ps->damageEvent != ops->damageEvent && ps->damageCount ) {
- CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount );
- }
-
- // respawning
- if ( ps->persistant[PERS_SPAWN_COUNT] != ops->persistant[PERS_SPAWN_COUNT] ) {
- CG_Respawn();
- }
-
- if ( cg.mapRestart ) {
- CG_Respawn();
- cg.mapRestart = qfalse;
- }
-
- if ( cg.snap->ps.pm_type != PM_INTERMISSION
- && ps->persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
- CG_CheckLocalSounds( ps, ops );
- }
-
- // check for going low on ammo
- CG_CheckAmmo();
-
- // run events
- CG_CheckPlayerstateEvents( ps, ops );
-
- // smooth the ducking viewheight change
- if ( ps->viewheight != ops->viewheight ) {
- cg.duckChange = ps->viewheight - ops->viewheight;
- cg.duckTime = cg.time;
- }
-}
-
diff --git a/engine/code/cgame/cg_predict.c b/engine/code/cgame/cg_predict.c
deleted file mode 100644
index 46bd633..0000000
--- a/engine/code/cgame/cg_predict.c
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_predict.c -- this file generates cg.predictedPlayerState by either
-// interpolating between snapshots from the server or locally predicting
-// ahead the client's movement.
-// It also handles local physics interaction, like fragments bouncing off walls
-
-#include "cg_local.h"
-
-static pmove_t cg_pmove;
-
-static int cg_numSolidEntities;
-static centity_t *cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT];
-static int cg_numTriggerEntities;
-static centity_t *cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT];
-
-/*
-====================
-CG_BuildSolidList
-
-When a new cg.snap has been set, this function builds a sublist
-of the entities that are actually solid, to make for more
-efficient collision detection
-====================
-*/
-void CG_BuildSolidList( void ) {
- int i;
- centity_t *cent;
- snapshot_t *snap;
- entityState_t *ent;
-
- cg_numSolidEntities = 0;
- cg_numTriggerEntities = 0;
-
- if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
- snap = cg.nextSnap;
- } else {
- snap = cg.snap;
- }
-
- for ( i = 0 ; i < snap->numEntities ; i++ ) {
- cent = &cg_entities[ snap->entities[ i ].number ];
- ent = ¢->currentState;
-
- if ( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) {
- cg_triggerEntities[cg_numTriggerEntities] = cent;
- cg_numTriggerEntities++;
- continue;
- }
-
- if ( cent->nextState.solid ) {
- cg_solidEntities[cg_numSolidEntities] = cent;
- cg_numSolidEntities++;
- continue;
- }
- }
-}
-
-/*
-====================
-CG_ClipMoveToEntities
-
-====================
-*/
-static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
- int skipNumber, int mask, trace_t *tr ) {
- int i, x, zd, zu;
- trace_t trace;
- entityState_t *ent;
- clipHandle_t cmodel;
- vec3_t bmins, bmaxs;
- vec3_t origin, angles;
- centity_t *cent;
-
- for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
- cent = cg_solidEntities[ i ];
- ent = ¢->currentState;
-
- if ( ent->number == skipNumber ) {
- continue;
- }
-
- if ( ent->solid == SOLID_BMODEL ) {
- // special value for bmodel
- cmodel = trap_CM_InlineModel( ent->modelindex );
- VectorCopy( cent->lerpAngles, angles );
- BG_EvaluateTrajectory( ¢->currentState.pos, cg.physicsTime, origin );
- } else {
- // encoded bbox
- x = (ent->solid & 255);
- zd = ((ent->solid>>8) & 255);
- zu = ((ent->solid>>16) & 255) - 32;
-
- bmins[0] = bmins[1] = -x;
- bmaxs[0] = bmaxs[1] = x;
- bmins[2] = -zd;
- bmaxs[2] = zu;
-
- cmodel = trap_CM_TempBoxModel( bmins, bmaxs );
- VectorCopy( vec3_origin, angles );
- VectorCopy( cent->lerpOrigin, origin );
- }
-
-
- trap_CM_TransformedBoxTrace ( &trace, start, end,
- mins, maxs, cmodel, mask, origin, angles);
-
- if (trace.allsolid || trace.fraction < tr->fraction) {
- trace.entityNum = ent->number;
- *tr = trace;
- } else if (trace.startsolid) {
- tr->startsolid = qtrue;
- }
- if ( tr->allsolid ) {
- return;
- }
- }
-}
-
-/*
-================
-CG_Trace
-================
-*/
-void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
- int skipNumber, int mask ) {
- trace_t t;
-
- trap_CM_BoxTrace ( &t, start, end, mins, maxs, 0, mask);
- t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
- // check all other solid models
- CG_ClipMoveToEntities (start, mins, maxs, end, skipNumber, mask, &t);
-
- *result = t;
-}
-
-/*
-================
-CG_PointContents
-================
-*/
-int CG_PointContents( const vec3_t point, int passEntityNum ) {
- int i;
- entityState_t *ent;
- centity_t *cent;
- clipHandle_t cmodel;
- int contents;
-
- contents = trap_CM_PointContents (point, 0);
-
- for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
- cent = cg_solidEntities[ i ];
-
- ent = ¢->currentState;
-
- if ( ent->number == passEntityNum ) {
- continue;
- }
-
- if (ent->solid != SOLID_BMODEL) { // special value for bmodel
- continue;
- }
-
- cmodel = trap_CM_InlineModel( ent->modelindex );
- if ( !cmodel ) {
- continue;
- }
-
- contents |= trap_CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles );
- }
-
- return contents;
-}
-
-
-/*
-========================
-CG_InterpolatePlayerState
-
-Generates cg.predictedPlayerState by interpolating between
-cg.snap->player_state and cg.nextFrame->player_state
-========================
-*/
-static void CG_InterpolatePlayerState( qboolean grabAngles ) {
- float f;
- int i;
- playerState_t *out;
- snapshot_t *prev, *next;
-
- out = &cg.predictedPlayerState;
- prev = cg.snap;
- next = cg.nextSnap;
-
- *out = cg.snap->ps;
-
- // if we are still allowing local input, short circuit the view angles
- if ( grabAngles ) {
- usercmd_t cmd;
- int cmdNum;
-
- cmdNum = trap_GetCurrentCmdNumber();
- trap_GetUserCmd( cmdNum, &cmd );
-
- PM_UpdateViewAngles( out, &cmd );
- }
-
- // if the next frame is a teleport, we can't lerp to it
- if ( cg.nextFrameTeleport ) {
- return;
- }
-
- if ( !next || next->serverTime <= prev->serverTime ) {
- return;
- }
-
- f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime );
-
- i = next->ps.bobCycle;
- if ( i < prev->ps.bobCycle ) {
- i += 256; // handle wraparound
- }
- out->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle );
-
- for ( i = 0 ; i < 3 ; i++ ) {
- out->origin[i] = prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i] );
- if ( !grabAngles ) {
- out->viewangles[i] = LerpAngle(
- prev->ps.viewangles[i], next->ps.viewangles[i], f );
- }
- out->velocity[i] = prev->ps.velocity[i] +
- f * (next->ps.velocity[i] - prev->ps.velocity[i] );
- }
-
-}
-
-/*
-===================
-CG_TouchItem
-===================
-*/
-static void CG_TouchItem( centity_t *cent ) {
- gitem_t *item;
-
- if ( !cg_predictItems.integer ) {
- return;
- }
- if ( !BG_PlayerTouchesItem( &cg.predictedPlayerState, ¢->currentState, cg.time ) ) {
- return;
- }
-
- // never pick an item up twice in a prediction
- if ( cent->miscTime == cg.time ) {
- return;
- }
-
- if ( !BG_CanItemBeGrabbed( cgs.gametype, ¢->currentState, &cg.predictedPlayerState ) ) {
- return; // can't hold it
- }
-
- item = &bg_itemlist[ cent->currentState.modelindex ];
-
- // Special case for flags.
- // We don't predict touching our own flag
-#ifdef MISSIONPACK
- if( cgs.gametype == GT_1FCTF ) {
- if( item->giTag != PW_NEUTRALFLAG ) {
- return;
- }
- }
- if( cgs.gametype == GT_CTF || cgs.gametype == GT_HARVESTER ) {
-#else
- if( cgs.gametype == GT_CTF ) {
-#endif
- if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_RED &&
- item->giTag == PW_REDFLAG)
- return;
- if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_BLUE &&
- item->giTag == PW_BLUEFLAG)
- return;
- }
-
- // grab it
- BG_AddPredictableEventToPlayerstate( EV_ITEM_PICKUP, cent->currentState.modelindex , &cg.predictedPlayerState);
-
- // remove it from the frame so it won't be drawn
- cent->currentState.eFlags |= EF_NODRAW;
-
- // don't touch it again this prediction
- cent->miscTime = cg.time;
-
- // if its a weapon, give them some predicted ammo so the autoswitch will work
- if ( item->giType == IT_WEAPON ) {
- cg.predictedPlayerState.stats[ STAT_WEAPONS ] |= 1 << item->giTag;
- if ( !cg.predictedPlayerState.ammo[ item->giTag ] ) {
- cg.predictedPlayerState.ammo[ item->giTag ] = 1;
- }
- }
-}
-
-
-/*
-=========================
-CG_TouchTriggerPrediction
-
-Predict push triggers and items
-=========================
-*/
-static void CG_TouchTriggerPrediction( void ) {
- int i;
- trace_t trace;
- entityState_t *ent;
- clipHandle_t cmodel;
- centity_t *cent;
- qboolean spectator;
-
- // dead clients don't activate triggers
- if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
- return;
- }
-
- spectator = ( cg.predictedPlayerState.pm_type == PM_SPECTATOR );
-
- if ( cg.predictedPlayerState.pm_type != PM_NORMAL && !spectator ) {
- return;
- }
-
- for ( i = 0 ; i < cg_numTriggerEntities ; i++ ) {
- cent = cg_triggerEntities[ i ];
- ent = ¢->currentState;
-
- if ( ent->eType == ET_ITEM && !spectator ) {
- CG_TouchItem( cent );
- continue;
- }
-
- if ( ent->solid != SOLID_BMODEL ) {
- continue;
- }
-
- cmodel = trap_CM_InlineModel( ent->modelindex );
- if ( !cmodel ) {
- continue;
- }
-
- trap_CM_BoxTrace( &trace, cg.predictedPlayerState.origin, cg.predictedPlayerState.origin,
- cg_pmove.mins, cg_pmove.maxs, cmodel, -1 );
-
- if ( !trace.startsolid ) {
- continue;
- }
-
- if ( ent->eType == ET_TELEPORT_TRIGGER ) {
- cg.hyperspace = qtrue;
- } else if ( ent->eType == ET_PUSH_TRIGGER ) {
- BG_TouchJumpPad( &cg.predictedPlayerState, ent );
- }
- }
-
- // if we didn't touch a jump pad this pmove frame
- if ( cg.predictedPlayerState.jumppad_frame != cg.predictedPlayerState.pmove_framecount ) {
- cg.predictedPlayerState.jumppad_frame = 0;
- cg.predictedPlayerState.jumppad_ent = 0;
- }
-}
-
-
-
-/*
-=================
-CG_PredictPlayerState
-
-Generates cg.predictedPlayerState for the current cg.time
-cg.predictedPlayerState is guaranteed to be valid after exiting.
-
-For demo playback, this will be an interpolation between two valid
-playerState_t.
-
-For normal gameplay, it will be the result of predicted usercmd_t on
-top of the most recent playerState_t received from the server.
-
-Each new snapshot will usually have one or more new usercmd over the last,
-but we simulate all unacknowledged commands each time, not just the new ones.
-This means that on an internet connection, quite a few pmoves may be issued
-each frame.
-
-OPTIMIZE: don't re-simulate unless the newly arrived snapshot playerState_t
-differs from the predicted one. Would require saving all intermediate
-playerState_t during prediction.
-
-We detect prediction errors and allow them to be decayed off over several frames
-to ease the jerk.
-=================
-*/
-void CG_PredictPlayerState( void ) {
- int cmdNum, current;
- playerState_t oldPlayerState;
- qboolean moved;
- usercmd_t oldestCmd;
- usercmd_t latestCmd;
-
- cg.hyperspace = qfalse; // will be set if touching a trigger_teleport
-
- // if this is the first frame we must guarantee
- // predictedPlayerState is valid even if there is some
- // other error condition
- if ( !cg.validPPS ) {
- cg.validPPS = qtrue;
- cg.predictedPlayerState = cg.snap->ps;
- }
-
-
- // demo playback just copies the moves
- if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
- CG_InterpolatePlayerState( qfalse );
- return;
- }
-
- // non-predicting local movement will grab the latest angles
- if ( cg_nopredict.integer || cg_synchronousClients.integer ) {
- CG_InterpolatePlayerState( qtrue );
- return;
- }
-
- // prepare for pmove
- cg_pmove.ps = &cg.predictedPlayerState;
- cg_pmove.trace = CG_Trace;
- cg_pmove.pointcontents = CG_PointContents;
- if ( cg_pmove.ps->pm_type == PM_DEAD ) {
- cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
- }
- else {
- cg_pmove.tracemask = MASK_PLAYERSOLID;
- }
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
- cg_pmove.tracemask &= ~CONTENTS_BODY; // spectators can fly through bodies
- }
- cg_pmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0;
-
- // save the state before the pmove so we can detect transitions
- oldPlayerState = cg.predictedPlayerState;
-
- current = trap_GetCurrentCmdNumber();
-
- // if we don't have the commands right after the snapshot, we
- // can't accurately predict a current position, so just freeze at
- // the last good position we had
- cmdNum = current - CMD_BACKUP + 1;
- trap_GetUserCmd( cmdNum, &oldestCmd );
- if ( oldestCmd.serverTime > cg.snap->ps.commandTime
- && oldestCmd.serverTime < cg.time ) { // special check for map_restart
- if ( cg_showmiss.integer ) {
- CG_Printf ("exceeded PACKET_BACKUP on commands\n");
- }
- return;
- }
-
- // get the latest command so we can know which commands are from previous map_restarts
- trap_GetUserCmd( current, &latestCmd );
-
- // get the most recent information we have, even if
- // the server time is beyond our current cg.time,
- // because predicted player positions are going to
- // be ahead of everything else anyway
- if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
- cg.predictedPlayerState = cg.nextSnap->ps;
- cg.physicsTime = cg.nextSnap->serverTime;
- } else {
- cg.predictedPlayerState = cg.snap->ps;
- cg.physicsTime = cg.snap->serverTime;
- }
-
- if ( pmove_msec.integer < 8 ) {
- trap_Cvar_Set("pmove_msec", "8");
- }
- else if (pmove_msec.integer > 33) {
- trap_Cvar_Set("pmove_msec", "33");
- }
-
- cg_pmove.pmove_fixed = pmove_fixed.integer;// | cg_pmove_fixed.integer;
- cg_pmove.pmove_msec = pmove_msec.integer;
-
- // run cmds
- moved = qfalse;
- for ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) {
- // get the command
- trap_GetUserCmd( cmdNum, &cg_pmove.cmd );
-
- if ( cg_pmove.pmove_fixed ) {
- PM_UpdateViewAngles( cg_pmove.ps, &cg_pmove.cmd );
- }
-
- // don't do anything if the time is before the snapshot player time
- if ( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime ) {
- continue;
- }
-
- // don't do anything if the command was from a previous map_restart
- if ( cg_pmove.cmd.serverTime > latestCmd.serverTime ) {
- continue;
- }
-
- // check for a prediction error from last frame
- // on a lan, this will often be the exact value
- // from the snapshot, but on a wan we will have
- // to predict several commands to get to the point
- // we want to compare
- if ( cg.predictedPlayerState.commandTime == oldPlayerState.commandTime ) {
- vec3_t delta;
- float len;
-
- if ( cg.thisFrameTeleport ) {
- // a teleport will not cause an error decay
- VectorClear( cg.predictedError );
- if ( cg_showmiss.integer ) {
- CG_Printf( "PredictionTeleport\n" );
- }
- cg.thisFrameTeleport = qfalse;
- } else {
- vec3_t adjusted;
- CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
- cg.predictedPlayerState.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted );
-
- if ( cg_showmiss.integer ) {
- if (!VectorCompare( oldPlayerState.origin, adjusted )) {
- CG_Printf("prediction error\n");
- }
- }
- VectorSubtract( oldPlayerState.origin, adjusted, delta );
- len = VectorLength( delta );
- if ( len > 0.1 ) {
- if ( cg_showmiss.integer ) {
- CG_Printf("Prediction miss: %f\n", len);
- }
- if ( cg_errorDecay.integer ) {
- int t;
- float f;
-
- t = cg.time - cg.predictedErrorTime;
- f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
- if ( f < 0 ) {
- f = 0;
- }
- if ( f > 0 && cg_showmiss.integer ) {
- CG_Printf("Double prediction decay: %f\n", f);
- }
- VectorScale( cg.predictedError, f, cg.predictedError );
- } else {
- VectorClear( cg.predictedError );
- }
- VectorAdd( delta, cg.predictedError, cg.predictedError );
- cg.predictedErrorTime = cg.oldTime;
- }
- }
- }
-
- // don't predict gauntlet firing, which is only supposed to happen
- // when it actually inflicts damage
- cg_pmove.gauntletHit = qfalse;
-
- if ( cg_pmove.pmove_fixed ) {
- cg_pmove.cmd.serverTime = ((cg_pmove.cmd.serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;
- }
-
- Pmove (&cg_pmove);
-
- moved = qtrue;
-
- // add push trigger movement effects
- CG_TouchTriggerPrediction();
-
- // check for predictable events that changed from previous predictions
- //CG_CheckChangedPredictableEvents(&cg.predictedPlayerState);
- }
-
- if ( cg_showmiss.integer > 1 ) {
- CG_Printf( "[%i : %i] ", cg_pmove.cmd.serverTime, cg.time );
- }
-
- if ( !moved ) {
- if ( cg_showmiss.integer ) {
- CG_Printf( "not moved\n" );
- }
- return;
- }
-
- // adjust for the movement of the groundentity
- CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
- cg.predictedPlayerState.groundEntityNum,
- cg.physicsTime, cg.time, cg.predictedPlayerState.origin );
-
- if ( cg_showmiss.integer ) {
- if (cg.predictedPlayerState.eventSequence > oldPlayerState.eventSequence + MAX_PS_EVENTS) {
- CG_Printf("WARNING: dropped event\n");
- }
- }
-
- // fire events and other transition triggered things
- CG_TransitionPlayerState( &cg.predictedPlayerState, &oldPlayerState );
-
- if ( cg_showmiss.integer ) {
- if (cg.eventSequence > cg.predictedPlayerState.eventSequence) {
- CG_Printf("WARNING: double event\n");
- cg.eventSequence = cg.predictedPlayerState.eventSequence;
- }
- }
-}
-
-
diff --git a/engine/code/cgame/cg_scoreboard.c b/engine/code/cgame/cg_scoreboard.c
deleted file mode 100644
index 0011658..0000000
--- a/engine/code/cgame/cg_scoreboard.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_scoreboard -- draw the scoreboard on top of the game screen
-#include "cg_local.h"
-
-
-#define SCOREBOARD_X (0)
-
-#define SB_HEADER 86
-#define SB_TOP (SB_HEADER+32)
-
-// Where the status bar starts, so we don't overwrite it
-#define SB_STATUSBAR 420
-
-#define SB_NORMAL_HEIGHT 40
-#define SB_INTER_HEIGHT 16 // interleaved height
-
-#define SB_MAXCLIENTS_NORMAL ((SB_STATUSBAR - SB_TOP) / SB_NORMAL_HEIGHT)
-#define SB_MAXCLIENTS_INTER ((SB_STATUSBAR - SB_TOP) / SB_INTER_HEIGHT - 1)
-
-// Used when interleaved
-
-
-
-#define SB_LEFT_BOTICON_X (SCOREBOARD_X+0)
-#define SB_LEFT_HEAD_X (SCOREBOARD_X+32)
-#define SB_RIGHT_BOTICON_X (SCOREBOARD_X+64)
-#define SB_RIGHT_HEAD_X (SCOREBOARD_X+96)
-// Normal
-#define SB_BOTICON_X (SCOREBOARD_X+32)
-#define SB_HEAD_X (SCOREBOARD_X+64)
-
-#define SB_SCORELINE_X 112
-
-#define SB_RATING_WIDTH (6 * BIGCHAR_WIDTH) // width 6
-#define SB_SCORE_X (SB_SCORELINE_X + BIGCHAR_WIDTH) // width 6
-#define SB_RATING_X (SB_SCORELINE_X + 6 * BIGCHAR_WIDTH) // width 6
-#define SB_PING_X (SB_SCORELINE_X + 12 * BIGCHAR_WIDTH + 8) // width 5
-#define SB_TIME_X (SB_SCORELINE_X + 17 * BIGCHAR_WIDTH + 8) // width 5
-#define SB_NAME_X (SB_SCORELINE_X + 22 * BIGCHAR_WIDTH) // width 15
-
-// The new and improved score board
-//
-// In cases where the number of clients is high, the score board heads are interleaved
-// here's the layout
-
-//
-// 0 32 80 112 144 240 320 400 <-- pixel position
-// bot head bot head score ping time name
-//
-// wins/losses are drawn on bot icon now
-
-static qboolean localClient; // true if local client has been displayed
-
-
- /*
-=================
-CG_DrawScoreboard
-=================
-*/
-static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) {
- char string[1024];
- vec3_t headAngles;
- clientInfo_t *ci;
- int iconx, headx;
-
- if ( score->client < 0 || score->client >= cgs.maxclients ) {
- Com_Printf( "Bad score->client: %i\n", score->client );
- return;
- }
-
- ci = &cgs.clientinfo[score->client];
-
- iconx = SB_BOTICON_X + (SB_RATING_WIDTH / 2);
- headx = SB_HEAD_X + (SB_RATING_WIDTH / 2);
-
- // draw the handicap or bot skill marker (unless player has flag)
- if ( ci->powerups & ( 1 << PW_NEUTRALFLAG ) ) {
- if( largeFormat ) {
- CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_FREE, qfalse );
- }
- else {
- CG_DrawFlagModel( iconx, y, 16, 16, TEAM_FREE, qfalse );
- }
- } else if ( ci->powerups & ( 1 << PW_REDFLAG ) ) {
- if( largeFormat ) {
- CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_RED, qfalse );
- }
- else {
- CG_DrawFlagModel( iconx, y, 16, 16, TEAM_RED, qfalse );
- }
- } else if ( ci->powerups & ( 1 << PW_BLUEFLAG ) ) {
- if( largeFormat ) {
- CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_BLUE, qfalse );
- }
- else {
- CG_DrawFlagModel( iconx, y, 16, 16, TEAM_BLUE, qfalse );
- }
- } else {
- if ( ci->botSkill > 0 && ci->botSkill <= 5 ) {
- if ( cg_drawIcons.integer ) {
- if( largeFormat ) {
- CG_DrawPic( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
- }
- else {
- CG_DrawPic( iconx, y, 16, 16, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
- }
- }
- } else if ( ci->handicap < 100 ) {
- Com_sprintf( string, sizeof( string ), "%i", ci->handicap );
- if ( cgs.gametype == GT_TOURNAMENT )
- CG_DrawSmallStringColor( iconx, y - SMALLCHAR_HEIGHT/2, string, color );
- else
- CG_DrawSmallStringColor( iconx, y, string, color );
- }
-
- // draw the wins / losses
- if ( cgs.gametype == GT_TOURNAMENT ) {
- Com_sprintf( string, sizeof( string ), "%i/%i", ci->wins, ci->losses );
- if( ci->handicap < 100 && !ci->botSkill ) {
- CG_DrawSmallStringColor( iconx, y + SMALLCHAR_HEIGHT/2, string, color );
- }
- else {
- CG_DrawSmallStringColor( iconx, y, string, color );
- }
- }
- }
-
- // draw the face
- VectorClear( headAngles );
- headAngles[YAW] = 180;
- if( largeFormat ) {
- CG_DrawHead( headx, y - ( ICON_SIZE - BIGCHAR_HEIGHT ) / 2, ICON_SIZE, ICON_SIZE,
- score->client, headAngles );
- }
- else {
- CG_DrawHead( headx, y, 16, 16, score->client, headAngles );
- }
-
-#ifdef MISSIONPACK
- // draw the team task
- if ( ci->teamTask != TEAMTASK_NONE ) {
- if ( ci->teamTask == TEAMTASK_OFFENSE ) {
- CG_DrawPic( headx + 48, y, 16, 16, cgs.media.assaultShader );
- }
- else if ( ci->teamTask == TEAMTASK_DEFENSE ) {
- CG_DrawPic( headx + 48, y, 16, 16, cgs.media.defendShader );
- }
- }
-#endif
- // draw the score line
- if ( score->ping == -1 ) {
- Com_sprintf(string, sizeof(string),
- " connecting %s", ci->name);
- } else if ( ci->team == TEAM_SPECTATOR ) {
- Com_sprintf(string, sizeof(string),
- " SPECT %3i %4i %s", score->ping, score->time, ci->name);
- } else {
- Com_sprintf(string, sizeof(string),
- "%5i %4i %4i %s", score->score, score->ping, score->time, ci->name);
- }
-
- // highlight your position
- if ( score->client == cg.snap->ps.clientNum ) {
- float hcolor[4];
- int rank;
-
- localClient = qtrue;
-
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR
- || cgs.gametype >= GT_TEAM ) {
- rank = -1;
- } else {
- rank = cg.snap->ps.persistant[PERS_RANK] & ~RANK_TIED_FLAG;
- }
- if ( rank == 0 ) {
- hcolor[0] = 0;
- hcolor[1] = 0;
- hcolor[2] = 0.7f;
- } else if ( rank == 1 ) {
- hcolor[0] = 0.7f;
- hcolor[1] = 0;
- hcolor[2] = 0;
- } else if ( rank == 2 ) {
- hcolor[0] = 0.7f;
- hcolor[1] = 0.7f;
- hcolor[2] = 0;
- } else {
- hcolor[0] = 0.7f;
- hcolor[1] = 0.7f;
- hcolor[2] = 0.7f;
- }
-
- hcolor[3] = fade * 0.7;
- CG_FillRect( SB_SCORELINE_X + BIGCHAR_WIDTH + (SB_RATING_WIDTH / 2), y,
- 640 - SB_SCORELINE_X - BIGCHAR_WIDTH, BIGCHAR_HEIGHT+1, hcolor );
- }
-
- CG_DrawBigString( SB_SCORELINE_X + (SB_RATING_WIDTH / 2), y, string, fade );
-
- // add the "ready" marker for intermission exiting
- if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) ) {
- CG_DrawBigStringColor( iconx, y, "READY", color );
- }
-}
-
-/*
-=================
-CG_TeamScoreboard
-=================
-*/
-static int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, int lineHeight ) {
- int i;
- score_t *score;
- float color[4];
- int count;
- clientInfo_t *ci;
-
- color[0] = color[1] = color[2] = 1.0;
- color[3] = fade;
-
- count = 0;
- for ( i = 0 ; i < cg.numScores && count < maxClients ; i++ ) {
- score = &cg.scores[i];
- ci = &cgs.clientinfo[ score->client ];
-
- if ( team != ci->team ) {
- continue;
- }
-
- CG_DrawClientScore( y + lineHeight * count, score, color, fade, lineHeight == SB_NORMAL_HEIGHT );
-
- count++;
- }
-
- return count;
-}
-
-/*
-=================
-CG_DrawScoreboard
-
-Draw the normal in-game scoreboard
-=================
-*/
-qboolean CG_DrawOldScoreboard( void ) {
- int x, y, w, i, n1, n2;
- float fade;
- float *fadeColor;
- char *s;
- int maxClients;
- int lineHeight;
- int topBorderSize, bottomBorderSize;
-
- // don't draw amuthing if the menu or console is up
- if ( cg_paused.integer ) {
- cg.deferredPlayerLoading = 0;
- return qfalse;
- }
-
- if ( cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- cg.deferredPlayerLoading = 0;
- return qfalse;
- }
-
- // don't draw scoreboard during death while warmup up
- if ( cg.warmup && !cg.showScores ) {
- return qfalse;
- }
-
- if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD ||
- cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- fade = 1.0;
- fadeColor = colorWhite;
- } else {
- fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
-
- if ( !fadeColor ) {
- // next time scoreboard comes up, don't print killer
- cg.deferredPlayerLoading = 0;
- cg.killerName[0] = 0;
- return qfalse;
- }
- fade = *fadeColor;
- }
-
-
- // fragged by ... line
- if ( cg.killerName[0] ) {
- s = va("Fragged by %s", cg.killerName );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- x = ( SCREEN_WIDTH - w ) / 2;
- y = 40;
- CG_DrawBigString( x, y, s, fade );
- }
-
- // current rank
- if ( cgs.gametype < GT_TEAM) {
- if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
- s = va("%s place with %i",
- CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
- cg.snap->ps.persistant[PERS_SCORE] );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- x = ( SCREEN_WIDTH - w ) / 2;
- y = 60;
- CG_DrawBigString( x, y, s, fade );
- }
- } else {
- if ( cg.teamScores[0] == cg.teamScores[1] ) {
- s = va("Teams are tied at %i", cg.teamScores[0] );
- } else if ( cg.teamScores[0] >= cg.teamScores[1] ) {
- s = va("Red leads %i to %i",cg.teamScores[0], cg.teamScores[1] );
- } else {
- s = va("Blue leads %i to %i",cg.teamScores[1], cg.teamScores[0] );
- }
-
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- x = ( SCREEN_WIDTH - w ) / 2;
- y = 60;
- CG_DrawBigString( x, y, s, fade );
- }
-
- // scoreboard
- y = SB_HEADER;
-
- CG_DrawPic( SB_SCORE_X + (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardScore );
- CG_DrawPic( SB_PING_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardPing );
- CG_DrawPic( SB_TIME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardTime );
- CG_DrawPic( SB_NAME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardName );
-
- y = SB_TOP;
-
- // If there are more than SB_MAXCLIENTS_NORMAL, use the interleaved scores
- if ( cg.numScores > SB_MAXCLIENTS_NORMAL ) {
- maxClients = SB_MAXCLIENTS_INTER;
- lineHeight = SB_INTER_HEIGHT;
- topBorderSize = 8;
- bottomBorderSize = 16;
- } else {
- maxClients = SB_MAXCLIENTS_NORMAL;
- lineHeight = SB_NORMAL_HEIGHT;
- topBorderSize = 16;
- bottomBorderSize = 16;
- }
-
- localClient = qfalse;
-
- if ( cgs.gametype >= GT_TEAM ) {
- //
- // teamplay scoreboard
- //
- y += lineHeight/2;
-
- if ( cg.teamScores[0] >= cg.teamScores[1] ) {
- n1 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
- CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );
- y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
- maxClients -= n1;
- n2 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
- CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );
- y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
- maxClients -= n2;
- } else {
- n1 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
- CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );
- y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
- maxClients -= n1;
- n2 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
- CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );
- y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
- maxClients -= n2;
- }
- n1 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients, lineHeight );
- y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
-
- } else {
- //
- // free for all scoreboard
- //
- n1 = CG_TeamScoreboard( y, TEAM_FREE, fade, maxClients, lineHeight );
- y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
- n2 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients - n1, lineHeight );
- y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
- }
-
- if (!localClient) {
- // draw local client at the bottom
- for ( i = 0 ; i < cg.numScores ; i++ ) {
- if ( cg.scores[i].client == cg.snap->ps.clientNum ) {
- CG_DrawClientScore( y, &cg.scores[i], fadeColor, fade, lineHeight == SB_NORMAL_HEIGHT );
- break;
- }
- }
- }
-
- // load any models that have been deferred
- if ( ++cg.deferredPlayerLoading > 10 ) {
- CG_LoadDeferredPlayers();
- }
-
- return qtrue;
-}
-
-//================================================================================
-
-/*
-================
-CG_CenterGiantLine
-================
-*/
-static void CG_CenterGiantLine( float y, const char *string ) {
- float x;
- vec4_t color;
-
- color[0] = 1;
- color[1] = 1;
- color[2] = 1;
- color[3] = 1;
-
- x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( string ) );
-
- CG_DrawStringExt( x, y, string, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
-}
-
-/*
-=================
-CG_DrawTourneyScoreboard
-
-Draw the oversize scoreboard for tournements
-=================
-*/
-void CG_DrawOldTourneyScoreboard( void ) {
- const char *s;
- vec4_t color;
- int min, tens, ones;
- clientInfo_t *ci;
- int y;
- int i;
-
- // request more scores regularly
- if ( cg.scoresRequestTime + 2000 < cg.time ) {
- cg.scoresRequestTime = cg.time;
- trap_SendClientCommand( "score" );
- }
-
- color[0] = 1;
- color[1] = 1;
- color[2] = 1;
- color[3] = 1;
-
- // draw the dialog background
- color[0] = color[1] = color[2] = 0;
- color[3] = 1;
- CG_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, color );
-
- // print the mesage of the day
- s = CG_ConfigString( CS_MOTD );
- if ( !s[0] ) {
- s = "Scoreboard";
- }
-
- // print optional title
- CG_CenterGiantLine( 8, s );
-
- // print server time
- ones = cg.time / 1000;
- min = ones / 60;
- ones %= 60;
- tens = ones / 10;
- ones %= 10;
- s = va("%i:%i%i", min, tens, ones );
-
- CG_CenterGiantLine( 64, s );
-
-
- // print the two scores
-
- y = 160;
- if ( cgs.gametype >= GT_TEAM ) {
- //
- // teamplay scoreboard
- //
- CG_DrawStringExt( 8, y, "Red Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- s = va("%i", cg.teamScores[0] );
- CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
-
- y += 64;
-
- CG_DrawStringExt( 8, y, "Blue Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- s = va("%i", cg.teamScores[1] );
- CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- } else {
- //
- // free for all scoreboard
- //
- for ( i = 0 ; i < MAX_CLIENTS ; i++ ) {
- ci = &cgs.clientinfo[i];
- if ( !ci->infoValid ) {
- continue;
- }
- if ( ci->team != TEAM_FREE ) {
- continue;
- }
-
- CG_DrawStringExt( 8, y, ci->name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- s = va("%i", ci->score );
- CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- y += 64;
- }
- }
-
-
-}
-
diff --git a/engine/code/cgame/cg_servercmds.c b/engine/code/cgame/cg_servercmds.c
deleted file mode 100644
index 7761646..0000000
--- a/engine/code/cgame/cg_servercmds.c
+++ /dev/null
@@ -1,1121 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_servercmds.c -- reliably sequenced text commands sent by the server
-// these are processed at snapshot transition time, so there will definately
-// be a valid snapshot this frame
-
-#include "cg_local.h"
-#include "../../ui/menudef.h"
-
-typedef struct {
- const char *order;
- int taskNum;
-} orderTask_t;
-
-static const orderTask_t validOrders[] = {
- { VOICECHAT_GETFLAG, TEAMTASK_OFFENSE },
- { VOICECHAT_OFFENSE, TEAMTASK_OFFENSE },
- { VOICECHAT_DEFEND, TEAMTASK_DEFENSE },
- { VOICECHAT_DEFENDFLAG, TEAMTASK_DEFENSE },
- { VOICECHAT_PATROL, TEAMTASK_PATROL },
- { VOICECHAT_CAMP, TEAMTASK_CAMP },
- { VOICECHAT_FOLLOWME, TEAMTASK_FOLLOW },
- { VOICECHAT_RETURNFLAG, TEAMTASK_RETRIEVE },
- { VOICECHAT_FOLLOWFLAGCARRIER, TEAMTASK_ESCORT }
-};
-
-static const int numValidOrders = sizeof(validOrders) / sizeof(orderTask_t);
-
-#ifdef MISSIONPACK
-static int CG_ValidOrder(const char *p) {
- int i;
- for (i = 0; i < numValidOrders; i++) {
- if (Q_stricmp(p, validOrders[i].order) == 0) {
- return validOrders[i].taskNum;
- }
- }
- return -1;
-}
-#endif
-
-/*
-=================
-CG_ParseScores
-
-=================
-*/
-static void CG_ParseScores( void ) {
- int i, powerups;
-
- cg.numScores = atoi( CG_Argv( 1 ) );
- if ( cg.numScores > MAX_CLIENTS ) {
- cg.numScores = MAX_CLIENTS;
- }
-
- cg.teamScores[0] = atoi( CG_Argv( 2 ) );
- cg.teamScores[1] = atoi( CG_Argv( 3 ) );
-
- memset( cg.scores, 0, sizeof( cg.scores ) );
- for ( i = 0 ; i < cg.numScores ; i++ ) {
- //
- cg.scores[i].client = atoi( CG_Argv( i * 14 + 4 ) );
- cg.scores[i].score = atoi( CG_Argv( i * 14 + 5 ) );
- cg.scores[i].ping = atoi( CG_Argv( i * 14 + 6 ) );
- cg.scores[i].time = atoi( CG_Argv( i * 14 + 7 ) );
- cg.scores[i].scoreFlags = atoi( CG_Argv( i * 14 + 8 ) );
- powerups = atoi( CG_Argv( i * 14 + 9 ) );
- cg.scores[i].accuracy = atoi(CG_Argv(i * 14 + 10));
- cg.scores[i].impressiveCount = atoi(CG_Argv(i * 14 + 11));
- cg.scores[i].excellentCount = atoi(CG_Argv(i * 14 + 12));
- cg.scores[i].guantletCount = atoi(CG_Argv(i * 14 + 13));
- cg.scores[i].defendCount = atoi(CG_Argv(i * 14 + 14));
- cg.scores[i].assistCount = atoi(CG_Argv(i * 14 + 15));
- cg.scores[i].perfect = atoi(CG_Argv(i * 14 + 16));
- cg.scores[i].captures = atoi(CG_Argv(i * 14 + 17));
-
- if ( cg.scores[i].client < 0 || cg.scores[i].client >= MAX_CLIENTS ) {
- cg.scores[i].client = 0;
- }
- cgs.clientinfo[ cg.scores[i].client ].score = cg.scores[i].score;
- cgs.clientinfo[ cg.scores[i].client ].powerups = powerups;
-
- cg.scores[i].team = cgs.clientinfo[cg.scores[i].client].team;
- }
-#ifdef MISSIONPACK
- CG_SetScoreSelection(NULL);
-#endif
-
-}
-
-/*
-=================
-CG_ParseTeamInfo
-
-=================
-*/
-static void CG_ParseTeamInfo( void ) {
- int i;
- int client;
-
- numSortedTeamPlayers = atoi( CG_Argv( 1 ) );
- if( numSortedTeamPlayers < 0 || numSortedTeamPlayers > TEAM_MAXOVERLAY )
- {
- CG_Error( "CG_ParseTeamInfo: numSortedTeamPlayers out of range (%d)",
- numSortedTeamPlayers );
- return;
- }
-
- for ( i = 0 ; i < numSortedTeamPlayers ; i++ ) {
- client = atoi( CG_Argv( i * 6 + 2 ) );
- if( client < 0 || client >= MAX_CLIENTS )
- {
- CG_Error( "CG_ParseTeamInfo: bad client number: %d", client );
- return;
- }
-
- sortedTeamPlayers[i] = client;
-
- cgs.clientinfo[ client ].location = atoi( CG_Argv( i * 6 + 3 ) );
- cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 6 + 4 ) );
- cgs.clientinfo[ client ].armor = atoi( CG_Argv( i * 6 + 5 ) );
- cgs.clientinfo[ client ].curWeapon = atoi( CG_Argv( i * 6 + 6 ) );
- cgs.clientinfo[ client ].powerups = atoi( CG_Argv( i * 6 + 7 ) );
- }
-}
-
-
-/*
-================
-CG_ParseServerinfo
-
-This is called explicitly when the gamestate is first received,
-and whenever the server updates any serverinfo flagged cvars
-================
-*/
-void CG_ParseServerinfo( void ) {
- const char *info;
- char *mapname;
-
- info = CG_ConfigString( CS_SERVERINFO );
- cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
- trap_Cvar_Set("g_gametype", va("%i", cgs.gametype));
- cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) );
- cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) );
- cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) );
- cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) );
- cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) );
- cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
- mapname = Info_ValueForKey( info, "mapname" );
- Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname );
- Q_strncpyz( cgs.redTeam, Info_ValueForKey( info, "g_redTeam" ), sizeof(cgs.redTeam) );
- trap_Cvar_Set("g_redTeam", cgs.redTeam);
- Q_strncpyz( cgs.blueTeam, Info_ValueForKey( info, "g_blueTeam" ), sizeof(cgs.blueTeam) );
- trap_Cvar_Set("g_blueTeam", cgs.blueTeam);
-}
-
-/*
-==================
-CG_ParseWarmup
-==================
-*/
-static void CG_ParseWarmup( void ) {
- const char *info;
- int warmup;
-
- info = CG_ConfigString( CS_WARMUP );
-
- warmup = atoi( info );
- cg.warmupCount = -1;
-
- if ( warmup == 0 && cg.warmup ) {
-
- } else if ( warmup > 0 && cg.warmup <= 0 ) {
-#ifdef MISSIONPACK
- if (cgs.gametype >= GT_CTF && cgs.gametype <= GT_HARVESTER) {
- trap_S_StartLocalSound( cgs.media.countPrepareTeamSound, CHAN_ANNOUNCER );
- } else
-#endif
- {
- trap_S_StartLocalSound( cgs.media.countPrepareSound, CHAN_ANNOUNCER );
- }
- }
-
- cg.warmup = warmup;
-}
-
-/*
-================
-CG_SetConfigValues
-
-Called on load to set the initial values from configure strings
-================
-*/
-void CG_SetConfigValues( void ) {
- const char *s;
-
- cgs.scores1 = atoi( CG_ConfigString( CS_SCORES1 ) );
- cgs.scores2 = atoi( CG_ConfigString( CS_SCORES2 ) );
- cgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) );
- if( cgs.gametype == GT_CTF ) {
- s = CG_ConfigString( CS_FLAGSTATUS );
- cgs.redflag = s[0] - '0';
- cgs.blueflag = s[1] - '0';
- }
-#ifdef MISSIONPACK
- else if( cgs.gametype == GT_1FCTF ) {
- s = CG_ConfigString( CS_FLAGSTATUS );
- cgs.flagStatus = s[0] - '0';
- }
-#endif
- cg.warmup = atoi( CG_ConfigString( CS_WARMUP ) );
-}
-
-/*
-=====================
-CG_ShaderStateChanged
-=====================
-*/
-void CG_ShaderStateChanged(void) {
- char originalShader[MAX_QPATH];
- char newShader[MAX_QPATH];
- char timeOffset[16];
- const char *o;
- char *n,*t;
-
- o = CG_ConfigString( CS_SHADERSTATE );
- while (o && *o) {
- n = strstr(o, "=");
- if (n && *n) {
- strncpy(originalShader, o, n-o);
- originalShader[n-o] = 0;
- n++;
- t = strstr(n, ":");
- if (t && *t) {
- strncpy(newShader, n, t-n);
- newShader[t-n] = 0;
- } else {
- break;
- }
- t++;
- o = strstr(t, "@");
- if (o) {
- strncpy(timeOffset, t, o-t);
- timeOffset[o-t] = 0;
- o++;
- trap_R_RemapShader( originalShader, newShader, timeOffset );
- }
- } else {
- break;
- }
- }
-}
-
-/*
-================
-CG_ConfigStringModified
-
-================
-*/
-static void CG_ConfigStringModified( void ) {
- const char *str;
- int num;
-
- num = atoi( CG_Argv( 1 ) );
-
- // get the gamestate from the client system, which will have the
- // new configstring already integrated
- trap_GetGameState( &cgs.gameState );
-
- // look up the individual string that was modified
- str = CG_ConfigString( num );
-
- // do something with it if necessary
- if ( num == CS_MUSIC ) {
- CG_StartMusic();
- } else if ( num == CS_SERVERINFO ) {
- CG_ParseServerinfo();
- } else if ( num == CS_WARMUP ) {
- CG_ParseWarmup();
- } else if ( num == CS_SCORES1 ) {
- cgs.scores1 = atoi( str );
- } else if ( num == CS_SCORES2 ) {
- cgs.scores2 = atoi( str );
- } else if ( num == CS_LEVEL_START_TIME ) {
- cgs.levelStartTime = atoi( str );
- } else if ( num == CS_VOTE_TIME ) {
- cgs.voteTime = atoi( str );
- cgs.voteModified = qtrue;
- } else if ( num == CS_VOTE_YES ) {
- cgs.voteYes = atoi( str );
- cgs.voteModified = qtrue;
- } else if ( num == CS_VOTE_NO ) {
- cgs.voteNo = atoi( str );
- cgs.voteModified = qtrue;
- } else if ( num == CS_VOTE_STRING ) {
- Q_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) );
-#ifdef MISSIONPACK
- trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER );
-#endif //MISSIONPACK
- } else if ( num >= CS_TEAMVOTE_TIME && num <= CS_TEAMVOTE_TIME + 1) {
- cgs.teamVoteTime[num-CS_TEAMVOTE_TIME] = atoi( str );
- cgs.teamVoteModified[num-CS_TEAMVOTE_TIME] = qtrue;
- } else if ( num >= CS_TEAMVOTE_YES && num <= CS_TEAMVOTE_YES + 1) {
- cgs.teamVoteYes[num-CS_TEAMVOTE_YES] = atoi( str );
- cgs.teamVoteModified[num-CS_TEAMVOTE_YES] = qtrue;
- } else if ( num >= CS_TEAMVOTE_NO && num <= CS_TEAMVOTE_NO + 1) {
- cgs.teamVoteNo[num-CS_TEAMVOTE_NO] = atoi( str );
- cgs.teamVoteModified[num-CS_TEAMVOTE_NO] = qtrue;
- } else if ( num >= CS_TEAMVOTE_STRING && num <= CS_TEAMVOTE_STRING + 1) {
- Q_strncpyz( cgs.teamVoteString[num-CS_TEAMVOTE_STRING], str, sizeof( cgs.teamVoteString ) );
-#ifdef MISSIONPACK
- trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER );
-#endif
- } else if ( num == CS_INTERMISSION ) {
- cg.intermissionStarted = atoi( str );
- } else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) {
- cgs.gameModels[ num-CS_MODELS ] = trap_R_RegisterModel( str );
- } else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_SOUNDS ) {
- if ( str[0] != '*' ) { // player specific sounds don't register here
- cgs.gameSounds[ num-CS_SOUNDS] = trap_S_RegisterSound( str, qfalse );
- }
- } else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) {
- CG_NewClientInfo( num - CS_PLAYERS );
- CG_BuildSpectatorString();
- } else if ( num == CS_FLAGSTATUS ) {
- if( cgs.gametype == GT_CTF ) {
- // format is rb where its red/blue, 0 is at base, 1 is taken, 2 is dropped
- cgs.redflag = str[0] - '0';
- cgs.blueflag = str[1] - '0';
- }
-#ifdef MISSIONPACK
- else if( cgs.gametype == GT_1FCTF ) {
- cgs.flagStatus = str[0] - '0';
- }
-#endif
- }
- else if ( num == CS_SHADERSTATE ) {
- CG_ShaderStateChanged();
- }
-
-}
-
-
-/*
-=======================
-CG_AddToTeamChat
-
-=======================
-*/
-static void CG_AddToTeamChat( const char *str ) {
- int len;
- char *p, *ls;
- int lastcolor;
- int chatHeight;
-
- if (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT) {
- chatHeight = cg_teamChatHeight.integer;
- } else {
- chatHeight = TEAMCHAT_HEIGHT;
- }
-
- if (chatHeight <= 0 || cg_teamChatTime.integer <= 0) {
- // team chat disabled, dump into normal chat
- cgs.teamChatPos = cgs.teamLastChatPos = 0;
- return;
- }
-
- len = 0;
-
- p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
- *p = 0;
-
- lastcolor = '7';
-
- ls = NULL;
- while (*str) {
- if (len > TEAMCHAT_WIDTH - 1) {
- if (ls) {
- str -= (p - ls);
- str++;
- p -= (p - ls);
- }
- *p = 0;
-
- cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
-
- cgs.teamChatPos++;
- p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
- *p = 0;
- *p++ = Q_COLOR_ESCAPE;
- *p++ = lastcolor;
- len = 0;
- ls = NULL;
- }
-
- if ( Q_IsColorString( str ) ) {
- *p++ = *str++;
- lastcolor = *str;
- *p++ = *str++;
- continue;
- }
- if (*str == ' ') {
- ls = p;
- }
- *p++ = *str++;
- len++;
- }
- *p = 0;
-
- cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
- cgs.teamChatPos++;
-
- if (cgs.teamChatPos - cgs.teamLastChatPos > chatHeight)
- cgs.teamLastChatPos = cgs.teamChatPos - chatHeight;
-}
-
-/*
-===============
-CG_MapRestart
-
-The server has issued a map_restart, so the next snapshot
-is completely new and should not be interpolated to.
-
-A tournement restart will clear everything, but doesn't
-require a reload of all the media
-===============
-*/
-static void CG_MapRestart( void ) {
- if ( cg_showmiss.integer ) {
- CG_Printf( "CG_MapRestart\n" );
- }
-
- CG_InitLocalEntities();
- CG_InitMarkPolys();
- CG_ClearParticles ();
-
- // make sure the "3 frags left" warnings play again
- cg.fraglimitWarnings = 0;
-
- cg.timelimitWarnings = 0;
-
- cg.intermissionStarted = qfalse;
-
- cgs.voteTime = 0;
-
- cg.mapRestart = qtrue;
-
- CG_StartMusic();
-
- trap_S_ClearLoopingSounds(qtrue);
-
- // we really should clear more parts of cg here and stop sounds
-
- // play the "fight" sound if this is a restart without warmup
- if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) {
- trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER );
- CG_CenterPrint( "FIGHT!", 120, GIANTCHAR_WIDTH*2 );
- }
-#ifdef MISSIONPACK
- if (cg_singlePlayerActive.integer) {
- trap_Cvar_Set("ui_matchStartTime", va("%i", cg.time));
- if (cg_recordSPDemo.integer && cg_recordSPDemoName.string && *cg_recordSPDemoName.string) {
- trap_SendConsoleCommand(va("set g_synchronousclients 1 ; record %s \n", cg_recordSPDemoName.string));
- }
- }
-#endif
- trap_Cvar_Set("cg_thirdPerson", "0");
-}
-
-#define MAX_VOICEFILESIZE 16384
-#define MAX_VOICEFILES 8
-#define MAX_VOICECHATS 64
-#define MAX_VOICESOUNDS 64
-#define MAX_CHATSIZE 64
-#define MAX_HEADMODELS 64
-
-typedef struct voiceChat_s
-{
- char id[64];
- int numSounds;
- sfxHandle_t sounds[MAX_VOICESOUNDS];
- char chats[MAX_VOICESOUNDS][MAX_CHATSIZE];
-} voiceChat_t;
-
-typedef struct voiceChatList_s
-{
- char name[64];
- int gender;
- int numVoiceChats;
- voiceChat_t voiceChats[MAX_VOICECHATS];
-} voiceChatList_t;
-
-typedef struct headModelVoiceChat_s
-{
- char headmodel[64];
- int voiceChatNum;
-} headModelVoiceChat_t;
-
-voiceChatList_t voiceChatLists[MAX_VOICEFILES];
-headModelVoiceChat_t headModelVoiceChat[MAX_HEADMODELS];
-
-/*
-=================
-CG_ParseVoiceChats
-=================
-*/
-int CG_ParseVoiceChats( const char *filename, voiceChatList_t *voiceChatList, int maxVoiceChats ) {
- int len, i;
- fileHandle_t f;
- char buf[MAX_VOICEFILESIZE];
- char **p, *ptr;
- char *token;
- voiceChat_t *voiceChats;
- qboolean compress;
- sfxHandle_t sound;
-
- compress = qtrue;
- if (cg_buildScript.integer) {
- compress = qfalse;
- }
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "voice chat file not found: %s\n", filename ) );
- return qfalse;
- }
- if ( len >= MAX_VOICEFILESIZE ) {
- trap_Print( va( S_COLOR_RED "voice chat file too large: %s is %i, max allowed is %i", filename, len, MAX_VOICEFILESIZE ) );
- trap_FS_FCloseFile( f );
- return qfalse;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- ptr = buf;
- p = &ptr;
-
- Com_sprintf(voiceChatList->name, sizeof(voiceChatList->name), "%s", filename);
- voiceChats = voiceChatList->voiceChats;
- for ( i = 0; i < maxVoiceChats; i++ ) {
- voiceChats[i].id[0] = 0;
- }
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return qtrue;
- }
- if (!Q_stricmp(token, "female")) {
- voiceChatList->gender = GENDER_FEMALE;
- }
- else if (!Q_stricmp(token, "male")) {
- voiceChatList->gender = GENDER_MALE;
- }
- else if (!Q_stricmp(token, "neuter")) {
- voiceChatList->gender = GENDER_NEUTER;
- }
- else {
- trap_Print( va( S_COLOR_RED "expected gender not found in voice chat file: %s\n", filename ) );
- return qfalse;
- }
-
- voiceChatList->numVoiceChats = 0;
- while ( 1 ) {
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return qtrue;
- }
- Com_sprintf(voiceChats[voiceChatList->numVoiceChats].id, sizeof( voiceChats[voiceChatList->numVoiceChats].id ), "%s", token);
- token = COM_ParseExt(p, qtrue);
- if (Q_stricmp(token, "{")) {
- trap_Print( va( S_COLOR_RED "expected { found %s in voice chat file: %s\n", token, filename ) );
- return qfalse;
- }
- voiceChats[voiceChatList->numVoiceChats].numSounds = 0;
- while(1) {
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return qtrue;
- }
- if (!Q_stricmp(token, "}"))
- break;
- sound = trap_S_RegisterSound( token, compress );
- voiceChats[voiceChatList->numVoiceChats].sounds[voiceChats[voiceChatList->numVoiceChats].numSounds] = sound;
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return qtrue;
- }
- Com_sprintf(voiceChats[voiceChatList->numVoiceChats].chats[
- voiceChats[voiceChatList->numVoiceChats].numSounds], MAX_CHATSIZE, "%s", token);
- if (sound)
- voiceChats[voiceChatList->numVoiceChats].numSounds++;
- if (voiceChats[voiceChatList->numVoiceChats].numSounds >= MAX_VOICESOUNDS)
- break;
- }
- voiceChatList->numVoiceChats++;
- if (voiceChatList->numVoiceChats >= maxVoiceChats)
- return qtrue;
- }
- return qtrue;
-}
-
-/*
-=================
-CG_LoadVoiceChats
-=================
-*/
-void CG_LoadVoiceChats( void ) {
- int size;
-
- size = trap_MemoryRemaining();
- CG_ParseVoiceChats( "scripts/female1.voice", &voiceChatLists[0], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/female2.voice", &voiceChatLists[1], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/female3.voice", &voiceChatLists[2], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male1.voice", &voiceChatLists[3], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male2.voice", &voiceChatLists[4], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male3.voice", &voiceChatLists[5], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male4.voice", &voiceChatLists[6], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male5.voice", &voiceChatLists[7], MAX_VOICECHATS );
- CG_Printf("voice chat memory size = %d\n", size - trap_MemoryRemaining());
-}
-
-/*
-=================
-CG_HeadModelVoiceChats
-=================
-*/
-int CG_HeadModelVoiceChats( char *filename ) {
- int len, i;
- fileHandle_t f;
- char buf[MAX_VOICEFILESIZE];
- char **p, *ptr;
- char *token;
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- //trap_Print( va( "voice chat file not found: %s\n", filename ) );
- return -1;
- }
- if ( len >= MAX_VOICEFILESIZE ) {
- trap_Print( va( S_COLOR_RED "voice chat file too large: %s is %i, max allowed is %i", filename, len, MAX_VOICEFILESIZE ) );
- trap_FS_FCloseFile( f );
- return -1;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- ptr = buf;
- p = &ptr;
-
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return -1;
- }
-
- for ( i = 0; i < MAX_VOICEFILES; i++ ) {
- if ( !Q_stricmp(token, voiceChatLists[i].name) ) {
- return i;
- }
- }
-
- //FIXME: maybe try to load the .voice file which name is stored in token?
-
- return -1;
-}
-
-
-/*
-=================
-CG_GetVoiceChat
-=================
-*/
-int CG_GetVoiceChat( voiceChatList_t *voiceChatList, const char *id, sfxHandle_t *snd, char **chat) {
- int i, rnd;
-
- for ( i = 0; i < voiceChatList->numVoiceChats; i++ ) {
- if ( !Q_stricmp( id, voiceChatList->voiceChats[i].id ) ) {
- rnd = random() * voiceChatList->voiceChats[i].numSounds;
- *snd = voiceChatList->voiceChats[i].sounds[rnd];
- *chat = voiceChatList->voiceChats[i].chats[rnd];
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-=================
-CG_VoiceChatListForClient
-=================
-*/
-voiceChatList_t *CG_VoiceChatListForClient( int clientNum ) {
- clientInfo_t *ci;
- int voiceChatNum, i, j, k, gender;
- char filename[MAX_QPATH], headModelName[MAX_QPATH];
-
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- clientNum = 0;
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- for ( k = 0; k < 2; k++ ) {
- if ( k == 0 ) {
- if (ci->headModelName[0] == '*') {
- Com_sprintf( headModelName, sizeof(headModelName), "%s/%s", ci->headModelName+1, ci->headSkinName );
- }
- else {
- Com_sprintf( headModelName, sizeof(headModelName), "%s/%s", ci->headModelName, ci->headSkinName );
- }
- }
- else {
- if (ci->headModelName[0] == '*') {
- Com_sprintf( headModelName, sizeof(headModelName), "%s", ci->headModelName+1 );
- }
- else {
- Com_sprintf( headModelName, sizeof(headModelName), "%s", ci->headModelName );
- }
- }
- // find the voice file for the head model the client uses
- for ( i = 0; i < MAX_HEADMODELS; i++ ) {
- if (!Q_stricmp(headModelVoiceChat[i].headmodel, headModelName)) {
- break;
- }
- }
- if (i < MAX_HEADMODELS) {
- return &voiceChatLists[headModelVoiceChat[i].voiceChatNum];
- }
- // find a <headmodelname>.vc file
- for ( i = 0; i < MAX_HEADMODELS; i++ ) {
- if (!strlen(headModelVoiceChat[i].headmodel)) {
- Com_sprintf(filename, sizeof(filename), "scripts/%s.vc", headModelName);
- voiceChatNum = CG_HeadModelVoiceChats(filename);
- if (voiceChatNum == -1)
- break;
- Com_sprintf(headModelVoiceChat[i].headmodel, sizeof ( headModelVoiceChat[i].headmodel ),
- "%s", headModelName);
- headModelVoiceChat[i].voiceChatNum = voiceChatNum;
- return &voiceChatLists[headModelVoiceChat[i].voiceChatNum];
- }
- }
- }
- gender = ci->gender;
- for (k = 0; k < 2; k++) {
- // just pick the first with the right gender
- for ( i = 0; i < MAX_VOICEFILES; i++ ) {
- if (strlen(voiceChatLists[i].name)) {
- if (voiceChatLists[i].gender == gender) {
- // store this head model with voice chat for future reference
- for ( j = 0; j < MAX_HEADMODELS; j++ ) {
- if (!strlen(headModelVoiceChat[j].headmodel)) {
- Com_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ),
- "%s", headModelName);
- headModelVoiceChat[j].voiceChatNum = i;
- break;
- }
- }
- return &voiceChatLists[i];
- }
- }
- }
- // fall back to male gender because we don't have neuter in the mission pack
- if (gender == GENDER_MALE)
- break;
- gender = GENDER_MALE;
- }
- // store this head model with voice chat for future reference
- for ( j = 0; j < MAX_HEADMODELS; j++ ) {
- if (!strlen(headModelVoiceChat[j].headmodel)) {
- Com_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ),
- "%s", headModelName);
- headModelVoiceChat[j].voiceChatNum = 0;
- break;
- }
- }
- // just return the first voice chat list
- return &voiceChatLists[0];
-}
-
-#define MAX_VOICECHATBUFFER 32
-
-typedef struct bufferedVoiceChat_s
-{
- int clientNum;
- sfxHandle_t snd;
- int voiceOnly;
- char cmd[MAX_SAY_TEXT];
- char message[MAX_SAY_TEXT];
-} bufferedVoiceChat_t;
-
-bufferedVoiceChat_t voiceChatBuffer[MAX_VOICECHATBUFFER];
-
-/*
-=================
-CG_PlayVoiceChat
-=================
-*/
-void CG_PlayVoiceChat( bufferedVoiceChat_t *vchat ) {
-#ifdef MISSIONPACK
- // if we are going into the intermission, don't start any voices
- if ( cg.intermissionStarted ) {
- return;
- }
-
- if ( !cg_noVoiceChats.integer ) {
- trap_S_StartLocalSound( vchat->snd, CHAN_VOICE);
- if (vchat->clientNum != cg.snap->ps.clientNum) {
- int orderTask = CG_ValidOrder(vchat->cmd);
- if (orderTask > 0) {
- cgs.acceptOrderTime = cg.time + 5000;
- Q_strncpyz(cgs.acceptVoice, vchat->cmd, sizeof(cgs.acceptVoice));
- cgs.acceptTask = orderTask;
- cgs.acceptLeader = vchat->clientNum;
- }
- // see if this was an order
- CG_ShowResponseHead();
- }
- }
- if (!vchat->voiceOnly && !cg_noVoiceText.integer) {
- CG_AddToTeamChat( vchat->message );
- CG_Printf( "%s\n", vchat->message );
- }
- voiceChatBuffer[cg.voiceChatBufferOut].snd = 0;
-#endif
-}
-
-/*
-=====================
-CG_PlayBufferedVoieChats
-=====================
-*/
-void CG_PlayBufferedVoiceChats( void ) {
-#ifdef MISSIONPACK
- if ( cg.voiceChatTime < cg.time ) {
- if (cg.voiceChatBufferOut != cg.voiceChatBufferIn && voiceChatBuffer[cg.voiceChatBufferOut].snd) {
- //
- CG_PlayVoiceChat(&voiceChatBuffer[cg.voiceChatBufferOut]);
- //
- cg.voiceChatBufferOut = (cg.voiceChatBufferOut + 1) % MAX_VOICECHATBUFFER;
- cg.voiceChatTime = cg.time + 1000;
- }
- }
-#endif
-}
-
-/*
-=====================
-CG_AddBufferedVoiceChat
-=====================
-*/
-void CG_AddBufferedVoiceChat( bufferedVoiceChat_t *vchat ) {
-#ifdef MISSIONPACK
- // if we are going into the intermission, don't start any voices
- if ( cg.intermissionStarted ) {
- return;
- }
-
- memcpy(&voiceChatBuffer[cg.voiceChatBufferIn], vchat, sizeof(bufferedVoiceChat_t));
- cg.voiceChatBufferIn = (cg.voiceChatBufferIn + 1) % MAX_VOICECHATBUFFER;
- if (cg.voiceChatBufferIn == cg.voiceChatBufferOut) {
- CG_PlayVoiceChat( &voiceChatBuffer[cg.voiceChatBufferOut] );
- cg.voiceChatBufferOut++;
- }
-#endif
-}
-
-/*
-=================
-CG_VoiceChatLocal
-=================
-*/
-void CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd ) {
-#ifdef MISSIONPACK
- char *chat;
- voiceChatList_t *voiceChatList;
- clientInfo_t *ci;
- sfxHandle_t snd;
- bufferedVoiceChat_t vchat;
-
- // if we are going into the intermission, don't start any voices
- if ( cg.intermissionStarted ) {
- return;
- }
-
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- clientNum = 0;
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- cgs.currentVoiceClient = clientNum;
-
- voiceChatList = CG_VoiceChatListForClient( clientNum );
-
- if ( CG_GetVoiceChat( voiceChatList, cmd, &snd, &chat ) ) {
- //
- if ( mode == SAY_TEAM || !cg_teamChatsOnly.integer ) {
- vchat.clientNum = clientNum;
- vchat.snd = snd;
- vchat.voiceOnly = voiceOnly;
- Q_strncpyz(vchat.cmd, cmd, sizeof(vchat.cmd));
- if ( mode == SAY_TELL ) {
- Com_sprintf(vchat.message, sizeof(vchat.message), "[%s]: %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
- }
- else if ( mode == SAY_TEAM ) {
- Com_sprintf(vchat.message, sizeof(vchat.message), "(%s): %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
- }
- else {
- Com_sprintf(vchat.message, sizeof(vchat.message), "%s: %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
- }
- CG_AddBufferedVoiceChat(&vchat);
- }
- }
-#endif
-}
-
-/*
-=================
-CG_VoiceChat
-=================
-*/
-void CG_VoiceChat( int mode ) {
-#ifdef MISSIONPACK
- const char *cmd;
- int clientNum, color;
- qboolean voiceOnly;
-
- voiceOnly = atoi(CG_Argv(1));
- clientNum = atoi(CG_Argv(2));
- color = atoi(CG_Argv(3));
- cmd = CG_Argv(4);
-
- if (cg_noTaunt.integer != 0) {
- if (!strcmp(cmd, VOICECHAT_KILLINSULT) || !strcmp(cmd, VOICECHAT_TAUNT) || \
- !strcmp(cmd, VOICECHAT_DEATHINSULT) || !strcmp(cmd, VOICECHAT_KILLGAUNTLET) || \
- !strcmp(cmd, VOICECHAT_PRAISE)) {
- return;
- }
- }
-
- CG_VoiceChatLocal( mode, voiceOnly, clientNum, color, cmd );
-#endif
-}
-
-/*
-=================
-CG_RemoveChatEscapeChar
-=================
-*/
-static void CG_RemoveChatEscapeChar( char *text ) {
- int i, l;
-
- l = 0;
- for ( i = 0; text[i]; i++ ) {
- if (text[i] == '\x19')
- continue;
- text[l++] = text[i];
- }
- text[l] = '\0';
-}
-
-/*
-=================
-CG_ServerCommand
-
-The string has been tokenized and can be retrieved with
-Cmd_Argc() / Cmd_Argv()
-=================
-*/
-static void CG_ServerCommand( void ) {
- const char *cmd;
- char text[MAX_SAY_TEXT];
-
- cmd = CG_Argv(0);
-
- if ( !cmd[0] ) {
- // server claimed the command
- return;
- }
-
- if ( !strcmp( cmd, "cp" ) ) {
- CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
- return;
- }
-
- if ( !strcmp( cmd, "cs" ) ) {
- CG_ConfigStringModified();
- return;
- }
-
- if ( !strcmp( cmd, "print" ) ) {
- CG_Printf( "%s", CG_Argv(1) );
-#ifdef MISSIONPACK
- cmd = CG_Argv(1); // yes, this is obviously a hack, but so is the way we hear about
- // votes passing or failing
- if ( !Q_stricmpn( cmd, "vote failed", 11 ) || !Q_stricmpn( cmd, "team vote failed", 16 )) {
- trap_S_StartLocalSound( cgs.media.voteFailed, CHAN_ANNOUNCER );
- } else if ( !Q_stricmpn( cmd, "vote passed", 11 ) || !Q_stricmpn( cmd, "team vote passed", 16 ) ) {
- trap_S_StartLocalSound( cgs.media.votePassed, CHAN_ANNOUNCER );
- }
-#endif
- return;
- }
-
- if ( !strcmp( cmd, "chat" ) ) {
- if ( !cg_teamChatsOnly.integer ) {
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
- CG_RemoveChatEscapeChar( text );
- CG_Printf( "%s\n", text );
- }
- return;
- }
-
- if ( !strcmp( cmd, "tchat" ) ) {
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
- CG_RemoveChatEscapeChar( text );
- CG_AddToTeamChat( text );
- CG_Printf( "%s\n", text );
- return;
- }
- if ( !strcmp( cmd, "vchat" ) ) {
- CG_VoiceChat( SAY_ALL );
- return;
- }
-
- if ( !strcmp( cmd, "vtchat" ) ) {
- CG_VoiceChat( SAY_TEAM );
- return;
- }
-
- if ( !strcmp( cmd, "vtell" ) ) {
- CG_VoiceChat( SAY_TELL );
- return;
- }
-
- if ( !strcmp( cmd, "scores" ) ) {
- CG_ParseScores();
- return;
- }
-
- if ( !strcmp( cmd, "tinfo" ) ) {
- CG_ParseTeamInfo();
- return;
- }
-
- if ( !strcmp( cmd, "map_restart" ) ) {
- CG_MapRestart();
- return;
- }
-
- if ( Q_stricmp (cmd, "remapShader") == 0 )
- {
- if (trap_Argc() == 4)
- {
- char shader1[MAX_QPATH];
- char shader2[MAX_QPATH];
- char shader3[MAX_QPATH];
-
- Q_strncpyz(shader1, CG_Argv(1), sizeof(shader1));
- Q_strncpyz(shader2, CG_Argv(2), sizeof(shader2));
- Q_strncpyz(shader3, CG_Argv(3), sizeof(shader3));
-
- trap_R_RemapShader(shader1, shader2, shader3);
- }
-
- return;
- }
-
- // loaddeferred can be both a servercmd and a consolecmd
- if ( !strcmp( cmd, "loaddefered" ) ) { // FIXME: spelled wrong, but not changing for demo
- CG_LoadDeferredPlayers();
- return;
- }
-
- // clientLevelShot is sent before taking a special screenshot for
- // the menu system during development
- if ( !strcmp( cmd, "clientLevelShot" ) ) {
- cg.levelShot = qtrue;
- return;
- }
-
- CG_Printf( "Unknown client game command: %s\n", cmd );
-}
-
-
-/*
-====================
-CG_ExecuteNewServerCommands
-
-Execute all of the server commands that were received along
-with this this snapshot.
-====================
-*/
-void CG_ExecuteNewServerCommands( int latestSequence ) {
- while ( cgs.serverCommandSequence < latestSequence ) {
- if ( trap_GetServerCommand( ++cgs.serverCommandSequence ) ) {
- CG_ServerCommand();
- }
- }
-}
diff --git a/engine/code/cgame/cg_snapshot.c b/engine/code/cgame/cg_snapshot.c
deleted file mode 100644
index 07b005e..0000000
--- a/engine/code/cgame/cg_snapshot.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_snapshot.c -- things that happen on snapshot transition,
-// not necessarily every single rendered frame
-
-#include "cg_local.h"
-
-
-
-/*
-==================
-CG_ResetEntity
-==================
-*/
-static void CG_ResetEntity( centity_t *cent ) {
- // if the previous snapshot this entity was updated in is at least
- // an event window back in time then we can reset the previous event
- if ( cent->snapShotTime < cg.time - EVENT_VALID_MSEC ) {
- cent->previousEvent = 0;
- }
-
- cent->trailTime = cg.snap->serverTime;
-
- VectorCopy (cent->currentState.origin, cent->lerpOrigin);
- VectorCopy (cent->currentState.angles, cent->lerpAngles);
- if ( cent->currentState.eType == ET_PLAYER ) {
- CG_ResetPlayerEntity( cent );
- }
-}
-
-/*
-===============
-CG_TransitionEntity
-
-cent->nextState is moved to cent->currentState and events are fired
-===============
-*/
-static void CG_TransitionEntity( centity_t *cent ) {
- cent->currentState = cent->nextState;
- cent->currentValid = qtrue;
-
- // reset if the entity wasn't in the last frame or was teleported
- if ( !cent->interpolate ) {
- CG_ResetEntity( cent );
- }
-
- // clear the next state. if will be set by the next CG_SetNextSnap
- cent->interpolate = qfalse;
-
- // check for events
- CG_CheckEvents( cent );
-}
-
-
-/*
-==================
-CG_SetInitialSnapshot
-
-This will only happen on the very first snapshot, or
-on tourney restarts. All other times will use
-CG_TransitionSnapshot instead.
-
-FIXME: Also called by map_restart?
-==================
-*/
-void CG_SetInitialSnapshot( snapshot_t *snap ) {
- int i;
- centity_t *cent;
- entityState_t *state;
-
- cg.snap = snap;
-
- BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse );
-
- // sort out solid entities
- CG_BuildSolidList();
-
- CG_ExecuteNewServerCommands( snap->serverCommandSequence );
-
- // set our local weapon selection pointer to
- // what the server has indicated the current weapon is
- CG_Respawn();
-
- for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
- state = &cg.snap->entities[ i ];
- cent = &cg_entities[ state->number ];
-
- memcpy(¢->currentState, state, sizeof(entityState_t));
- //cent->currentState = *state;
- cent->interpolate = qfalse;
- cent->currentValid = qtrue;
-
- CG_ResetEntity( cent );
-
- // check for events
- CG_CheckEvents( cent );
- }
-}
-
-
-/*
-===================
-CG_TransitionSnapshot
-
-The transition point from snap to nextSnap has passed
-===================
-*/
-static void CG_TransitionSnapshot( void ) {
- centity_t *cent;
- snapshot_t *oldFrame;
- int i;
-
- if ( !cg.snap ) {
- CG_Error( "CG_TransitionSnapshot: NULL cg.snap" );
- }
- if ( !cg.nextSnap ) {
- CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" );
- }
-
- // execute any server string commands before transitioning entities
- CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence );
-
- // if we had a map_restart, set everthing with initial
- if ( !cg.snap ) {
- }
-
- // clear the currentValid flag for all entities in the existing snapshot
- for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
- cent = &cg_entities[ cg.snap->entities[ i ].number ];
- cent->currentValid = qfalse;
- }
-
- // move nextSnap to snap and do the transitions
- oldFrame = cg.snap;
- cg.snap = cg.nextSnap;
-
- BG_PlayerStateToEntityState( &cg.snap->ps, &cg_entities[ cg.snap->ps.clientNum ].currentState, qfalse );
- cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse;
-
- for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
- cent = &cg_entities[ cg.snap->entities[ i ].number ];
- CG_TransitionEntity( cent );
-
- // remember time of snapshot this entity was last updated in
- cent->snapShotTime = cg.snap->serverTime;
- }
-
- cg.nextSnap = NULL;
-
- // check for playerstate transition events
- if ( oldFrame ) {
- playerState_t *ops, *ps;
-
- ops = &oldFrame->ps;
- ps = &cg.snap->ps;
- // teleporting checks are irrespective of prediction
- if ( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT ) {
- cg.thisFrameTeleport = qtrue; // will be cleared by prediction code
- }
-
- // if we are not doing client side movement prediction for any
- // reason, then the client events and view changes will be issued now
- if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW)
- || cg_nopredict.integer || cg_synchronousClients.integer ) {
- CG_TransitionPlayerState( ps, ops );
- }
- }
-
-}
-
-
-/*
-===================
-CG_SetNextSnap
-
-A new snapshot has just been read in from the client system.
-===================
-*/
-static void CG_SetNextSnap( snapshot_t *snap ) {
- int num;
- entityState_t *es;
- centity_t *cent;
-
- cg.nextSnap = snap;
-
- BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse );
- cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue;
-
- // check for extrapolation errors
- for ( num = 0 ; num < snap->numEntities ; num++ ) {
- es = &snap->entities[num];
- cent = &cg_entities[ es->number ];
-
- memcpy(¢->nextState, es, sizeof(entityState_t));
- //cent->nextState = *es;
-
- // if this frame is a teleport, or the entity wasn't in the
- // previous frame, don't interpolate
- if ( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) ) {
- cent->interpolate = qfalse;
- } else {
- cent->interpolate = qtrue;
- }
- }
-
- // if the next frame is a teleport for the playerstate, we
- // can't interpolate during demos
- if ( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) ) {
- cg.nextFrameTeleport = qtrue;
- } else {
- cg.nextFrameTeleport = qfalse;
- }
-
- // if changing follow mode, don't interpolate
- if ( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum ) {
- cg.nextFrameTeleport = qtrue;
- }
-
- // if changing server restarts, don't interpolate
- if ( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) {
- cg.nextFrameTeleport = qtrue;
- }
-
- // sort out solid entities
- CG_BuildSolidList();
-}
-
-
-/*
-========================
-CG_ReadNextSnapshot
-
-This is the only place new snapshots are requested
-This may increment cgs.processedSnapshotNum multiple
-times if the client system fails to return a
-valid snapshot.
-========================
-*/
-static snapshot_t *CG_ReadNextSnapshot( void ) {
- qboolean r;
- snapshot_t *dest;
-
- if ( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 ) {
- CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i",
- cg.latestSnapshotNum, cgs.processedSnapshotNum );
- }
-
- while ( cgs.processedSnapshotNum < cg.latestSnapshotNum ) {
- // decide which of the two slots to load it into
- if ( cg.snap == &cg.activeSnapshots[0] ) {
- dest = &cg.activeSnapshots[1];
- } else {
- dest = &cg.activeSnapshots[0];
- }
-
- // try to read the snapshot from the client system
- cgs.processedSnapshotNum++;
- r = trap_GetSnapshot( cgs.processedSnapshotNum, dest );
-
- // FIXME: why would trap_GetSnapshot return a snapshot with the same server time
- if ( cg.snap && r && dest->serverTime == cg.snap->serverTime ) {
- //continue;
- }
-
- // if it succeeded, return
- if ( r ) {
- CG_AddLagometerSnapshotInfo( dest );
- return dest;
- }
-
- // a GetSnapshot will return failure if the snapshot
- // never arrived, or is so old that its entities
- // have been shoved off the end of the circular
- // buffer in the client system.
-
- // record as a dropped packet
- CG_AddLagometerSnapshotInfo( NULL );
-
- // If there are additional snapshots, continue trying to
- // read them.
- }
-
- // nothing left to read
- return NULL;
-}
-
-
-/*
-============
-CG_ProcessSnapshots
-
-We are trying to set up a renderable view, so determine
-what the simulated time is, and try to get snapshots
-both before and after that time if available.
-
-If we don't have a valid cg.snap after exiting this function,
-then a 3D game view cannot be rendered. This should only happen
-right after the initial connection. After cg.snap has been valid
-once, it will never turn invalid.
-
-Even if cg.snap is valid, cg.nextSnap may not be, if the snapshot
-hasn't arrived yet (it becomes an extrapolating situation instead
-of an interpolating one)
-
-============
-*/
-void CG_ProcessSnapshots( void ) {
- snapshot_t *snap;
- int n;
-
- // see what the latest snapshot the client system has is
- trap_GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime );
- if ( n != cg.latestSnapshotNum ) {
- if ( n < cg.latestSnapshotNum ) {
- // this should never happen
- CG_Error( "CG_ProcessSnapshots: n < cg.latestSnapshotNum" );
- }
- cg.latestSnapshotNum = n;
- }
-
- // If we have yet to receive a snapshot, check for it.
- // Once we have gotten the first snapshot, cg.snap will
- // always have valid data for the rest of the game
- while ( !cg.snap ) {
- snap = CG_ReadNextSnapshot();
- if ( !snap ) {
- // we can't continue until we get a snapshot
- return;
- }
-
- // set our weapon selection to what
- // the playerstate is currently using
- if ( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
- CG_SetInitialSnapshot( snap );
- }
- }
-
- // loop until we either have a valid nextSnap with a serverTime
- // greater than cg.time to interpolate towards, or we run
- // out of available snapshots
- do {
- // if we don't have a nextframe, try and read a new one in
- if ( !cg.nextSnap ) {
- snap = CG_ReadNextSnapshot();
-
- // if we still don't have a nextframe, we will just have to
- // extrapolate
- if ( !snap ) {
- break;
- }
-
- CG_SetNextSnap( snap );
-
-
- // if time went backwards, we have a level restart
- if ( cg.nextSnap->serverTime < cg.snap->serverTime ) {
- CG_Error( "CG_ProcessSnapshots: Server time went backwards" );
- }
- }
-
- // if our time is < nextFrame's, we have a nice interpolating state
- if ( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime ) {
- break;
- }
-
- // we have passed the transition from nextFrame to frame
- CG_TransitionSnapshot();
- } while ( 1 );
-
- // assert our valid conditions upon exiting
- if ( cg.snap == NULL ) {
- CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" );
- }
- if ( cg.time < cg.snap->serverTime ) {
- // this can happen right after a vid_restart
- cg.time = cg.snap->serverTime;
- }
- if ( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time ) {
- CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" );
- }
-
-}
-
diff --git a/engine/code/cgame/cg_syscalls.c b/engine/code/cgame/cg_syscalls.c
deleted file mode 100644
index 83606ac..0000000
--- a/engine/code/cgame/cg_syscalls.c
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_syscalls.c -- this file is only included when building a dll
-// cg_syscalls.asm is included instead when building a qvm
-#ifdef Q3_VM
-#error "Do not use in VM build"
-#endif
-
-#include "cg_local.h"
-
-static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;
-
-
-Q_EXPORT void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) {
- syscall = syscallptr;
-}
-
-
-int PASSFLOAT( float x ) {
- floatint_t fi;
- fi.f = x;
- return fi.i;
-}
-
-void trap_Print( const char *fmt ) {
- syscall( CG_PRINT, fmt );
-}
-
-void trap_Error( const char *fmt ) {
- syscall( CG_ERROR, fmt );
-}
-
-int trap_Milliseconds( void ) {
- return syscall( CG_MILLISECONDS );
-}
-
-void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) {
- syscall( CG_CVAR_REGISTER, vmCvar, varName, defaultValue, flags );
-}
-
-void trap_Cvar_Update( vmCvar_t *vmCvar ) {
- syscall( CG_CVAR_UPDATE, vmCvar );
-}
-
-void trap_Cvar_Set( const char *var_name, const char *value ) {
- syscall( CG_CVAR_SET, var_name, value );
-}
-
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
- syscall( CG_CVAR_VARIABLESTRINGBUFFER, var_name, buffer, bufsize );
-}
-
-int trap_Argc( void ) {
- return syscall( CG_ARGC );
-}
-
-void trap_Argv( int n, char *buffer, int bufferLength ) {
- syscall( CG_ARGV, n, buffer, bufferLength );
-}
-
-void trap_Args( char *buffer, int bufferLength ) {
- syscall( CG_ARGS, buffer, bufferLength );
-}
-
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
- return syscall( CG_FS_FOPENFILE, qpath, f, mode );
-}
-
-void trap_FS_Read( void *buffer, int len, fileHandle_t f ) {
- syscall( CG_FS_READ, buffer, len, f );
-}
-
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f ) {
- syscall( CG_FS_WRITE, buffer, len, f );
-}
-
-void trap_FS_FCloseFile( fileHandle_t f ) {
- syscall( CG_FS_FCLOSEFILE, f );
-}
-
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ) {
- return syscall( CG_FS_SEEK, f, offset, origin );
-}
-
-void trap_SendConsoleCommand( const char *text ) {
- syscall( CG_SENDCONSOLECOMMAND, text );
-}
-
-void trap_AddCommand( const char *cmdName ) {
- syscall( CG_ADDCOMMAND, cmdName );
-}
-
-void trap_RemoveCommand( const char *cmdName ) {
- syscall( CG_REMOVECOMMAND, cmdName );
-}
-
-void trap_SendClientCommand( const char *s ) {
- syscall( CG_SENDCLIENTCOMMAND, s );
-}
-
-void trap_UpdateScreen( void ) {
- syscall( CG_UPDATESCREEN );
-}
-
-void trap_CM_LoadMap( const char *mapname ) {
- syscall( CG_CM_LOADMAP, mapname );
-}
-
-int trap_CM_NumInlineModels( void ) {
- return syscall( CG_CM_NUMINLINEMODELS );
-}
-
-clipHandle_t trap_CM_InlineModel( int index ) {
- return syscall( CG_CM_INLINEMODEL, index );
-}
-
-clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) {
- return syscall( CG_CM_TEMPBOXMODEL, mins, maxs );
-}
-
-clipHandle_t trap_CM_TempCapsuleModel( const vec3_t mins, const vec3_t maxs ) {
- return syscall( CG_CM_TEMPCAPSULEMODEL, mins, maxs );
-}
-
-int trap_CM_PointContents( const vec3_t p, clipHandle_t model ) {
- return syscall( CG_CM_POINTCONTENTS, p, model );
-}
-
-int trap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles ) {
- return syscall( CG_CM_TRANSFORMEDPOINTCONTENTS, p, model, origin, angles );
-}
-
-void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask ) {
- syscall( CG_CM_BOXTRACE, results, start, end, mins, maxs, model, brushmask );
-}
-
-void trap_CM_CapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask ) {
- syscall( CG_CM_CAPSULETRACE, results, start, end, mins, maxs, model, brushmask );
-}
-
-void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask,
- const vec3_t origin, const vec3_t angles ) {
- syscall( CG_CM_TRANSFORMEDBOXTRACE, results, start, end, mins, maxs, model, brushmask, origin, angles );
-}
-
-void trap_CM_TransformedCapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask,
- const vec3_t origin, const vec3_t angles ) {
- syscall( CG_CM_TRANSFORMEDCAPSULETRACE, results, start, end, mins, maxs, model, brushmask, origin, angles );
-}
-
-int trap_CM_MarkFragments( int numPoints, const vec3_t *points,
- const vec3_t projection,
- int maxPoints, vec3_t pointBuffer,
- int maxFragments, markFragment_t *fragmentBuffer ) {
- return syscall( CG_CM_MARKFRAGMENTS, numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer );
-}
-
-void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ) {
- syscall( CG_S_STARTSOUND, origin, entityNum, entchannel, sfx );
-}
-
-void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ) {
- syscall( CG_S_STARTLOCALSOUND, sfx, channelNum );
-}
-
-void trap_S_ClearLoopingSounds( qboolean killall ) {
- syscall( CG_S_CLEARLOOPINGSOUNDS, killall );
-}
-
-void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) {
- syscall( CG_S_ADDLOOPINGSOUND, entityNum, origin, velocity, sfx );
-}
-
-void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) {
- syscall( CG_S_ADDREALLOOPINGSOUND, entityNum, origin, velocity, sfx );
-}
-
-void trap_S_StopLoopingSound( int entityNum ) {
- syscall( CG_S_STOPLOOPINGSOUND, entityNum );
-}
-
-void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin ) {
- syscall( CG_S_UPDATEENTITYPOSITION, entityNum, origin );
-}
-
-void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater ) {
- syscall( CG_S_RESPATIALIZE, entityNum, origin, axis, inwater );
-}
-
-sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ) {
- return syscall( CG_S_REGISTERSOUND, sample, compressed );
-}
-
-void trap_S_StartBackgroundTrack( const char *intro, const char *loop ) {
- syscall( CG_S_STARTBACKGROUNDTRACK, intro, loop );
-}
-
-void trap_R_LoadWorldMap( const char *mapname ) {
- syscall( CG_R_LOADWORLDMAP, mapname );
-}
-
-qhandle_t trap_R_RegisterModel( const char *name ) {
- return syscall( CG_R_REGISTERMODEL, name );
-}
-
-qhandle_t trap_R_RegisterSkin( const char *name ) {
- return syscall( CG_R_REGISTERSKIN, name );
-}
-
-qhandle_t trap_R_RegisterShader( const char *name ) {
- return syscall( CG_R_REGISTERSHADER, name );
-}
-
-qhandle_t trap_R_RegisterShaderNoMip( const char *name ) {
- return syscall( CG_R_REGISTERSHADERNOMIP, name );
-}
-
-void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {
- syscall(CG_R_REGISTERFONT, fontName, pointSize, font );
-}
-
-void trap_R_ClearScene( void ) {
- syscall( CG_R_CLEARSCENE );
-}
-
-void trap_R_AddRefEntityToScene( const refEntity_t *re ) {
- syscall( CG_R_ADDREFENTITYTOSCENE, re );
-}
-
-void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ) {
- syscall( CG_R_ADDPOLYTOSCENE, hShader, numVerts, verts );
-}
-
-void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ) {
- syscall( CG_R_ADDPOLYSTOSCENE, hShader, numVerts, verts, num );
-}
-
-int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) {
- return syscall( CG_R_LIGHTFORPOINT, point, ambientLight, directedLight, lightDir );
-}
-
-void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
- syscall( CG_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );
-}
-
-void trap_R_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
- syscall( CG_R_ADDADDITIVELIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );
-}
-
-void trap_R_RenderScene( const refdef_t *fd ) {
- syscall( CG_R_RENDERSCENE, fd );
-}
-
-void trap_R_SetColor( const float *rgba ) {
- syscall( CG_R_SETCOLOR, rgba );
-}
-
-void trap_R_DrawStretchPic( float x, float y, float w, float h,
- float s1, float t1, float s2, float t2, qhandle_t hShader ) {
- syscall( CG_R_DRAWSTRETCHPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), hShader );
-}
-
-void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {
- syscall( CG_R_MODELBOUNDS, model, mins, maxs );
-}
-
-int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame,
- float frac, const char *tagName ) {
- return syscall( CG_R_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName );
-}
-
-void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) {
- syscall( CG_R_REMAP_SHADER, oldShader, newShader, timeOffset );
-}
-
-void trap_GetGlconfig( glconfig_t *glconfig ) {
- syscall( CG_GETGLCONFIG, glconfig );
-}
-
-void trap_GetGameState( gameState_t *gamestate ) {
- syscall( CG_GETGAMESTATE, gamestate );
-}
-
-void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) {
- syscall( CG_GETCURRENTSNAPSHOTNUMBER, snapshotNumber, serverTime );
-}
-
-qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {
- return syscall( CG_GETSNAPSHOT, snapshotNumber, snapshot );
-}
-
-qboolean trap_GetServerCommand( int serverCommandNumber ) {
- return syscall( CG_GETSERVERCOMMAND, serverCommandNumber );
-}
-
-int trap_GetCurrentCmdNumber( void ) {
- return syscall( CG_GETCURRENTCMDNUMBER );
-}
-
-qboolean trap_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) {
- return syscall( CG_GETUSERCMD, cmdNumber, ucmd );
-}
-
-void trap_SetUserCmdValue( int stateValue, float sensitivityScale ) {
- syscall( CG_SETUSERCMDVALUE, stateValue, PASSFLOAT(sensitivityScale) );
-}
-
-void testPrintInt( char *string, int i ) {
- syscall( CG_TESTPRINTINT, string, i );
-}
-
-void testPrintFloat( char *string, float f ) {
- syscall( CG_TESTPRINTFLOAT, string, PASSFLOAT(f) );
-}
-
-int trap_MemoryRemaining( void ) {
- return syscall( CG_MEMORY_REMAINING );
-}
-
-qboolean trap_Key_IsDown( int keynum ) {
- return syscall( CG_KEY_ISDOWN, keynum );
-}
-
-int trap_Key_GetCatcher( void ) {
- return syscall( CG_KEY_GETCATCHER );
-}
-
-void trap_Key_SetCatcher( int catcher ) {
- syscall( CG_KEY_SETCATCHER, catcher );
-}
-
-int trap_Key_GetKey( const char *binding ) {
- return syscall( CG_KEY_GETKEY, binding );
-}
-
-int trap_PC_AddGlobalDefine( char *define ) {
- return syscall( CG_PC_ADD_GLOBAL_DEFINE, define );
-}
-
-int trap_PC_LoadSource( const char *filename ) {
- return syscall( CG_PC_LOAD_SOURCE, filename );
-}
-
-int trap_PC_FreeSource( int handle ) {
- return syscall( CG_PC_FREE_SOURCE, handle );
-}
-
-int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) {
- return syscall( CG_PC_READ_TOKEN, handle, pc_token );
-}
-
-int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) {
- return syscall( CG_PC_SOURCE_FILE_AND_LINE, handle, filename, line );
-}
-
-void trap_S_StopBackgroundTrack( void ) {
- syscall( CG_S_STOPBACKGROUNDTRACK );
-}
-
-int trap_RealTime(qtime_t *qtime) {
- return syscall( CG_REAL_TIME, qtime );
-}
-
-void trap_SnapVector( float *v ) {
- syscall( CG_SNAPVECTOR, v );
-}
-
-// this returns a handle. arg0 is the name in the format "idlogo.roq", set arg1 to NULL, alteredstates to qfalse (do not alter gamestate)
-int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits) {
- return syscall(CG_CIN_PLAYCINEMATIC, arg0, xpos, ypos, width, height, bits);
-}
-
-// stops playing the cinematic and ends it. should always return FMV_EOF
-// cinematics must be stopped in reverse order of when they are started
-e_status trap_CIN_StopCinematic(int handle) {
- return syscall(CG_CIN_STOPCINEMATIC, handle);
-}
-
-
-// will run a frame of the cinematic but will not draw it. Will return FMV_EOF if the end of the cinematic has been reached.
-e_status trap_CIN_RunCinematic (int handle) {
- return syscall(CG_CIN_RUNCINEMATIC, handle);
-}
-
-
-// draws the current frame
-void trap_CIN_DrawCinematic (int handle) {
- syscall(CG_CIN_DRAWCINEMATIC, handle);
-}
-
-
-// allows you to resize the animation dynamically
-void trap_CIN_SetExtents (int handle, int x, int y, int w, int h) {
- syscall(CG_CIN_SETEXTENTS, handle, x, y, w, h);
-}
-
-/*
-qboolean trap_loadCamera( const char *name ) {
- return syscall( CG_LOADCAMERA, name );
-}
-
-void trap_startCamera(int time) {
- syscall(CG_STARTCAMERA, time);
-}
-
-qboolean trap_getCameraInfo( int time, vec3_t *origin, vec3_t *angles) {
- return syscall( CG_GETCAMERAINFO, time, origin, angles );
-}
-*/
-
-qboolean trap_GetEntityToken( char *buffer, int bufferSize ) {
- return syscall( CG_GET_ENTITY_TOKEN, buffer, bufferSize );
-}
-
-qboolean trap_R_inPVS( const vec3_t p1, const vec3_t p2 ) {
- return syscall( CG_R_INPVS, p1, p2 );
-}
diff --git a/engine/code/cgame/cg_view.c b/engine/code/cgame/cg_view.c
deleted file mode 100644
index f61bbf9..0000000
--- a/engine/code/cgame/cg_view.c
+++ /dev/null
@@ -1,876 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_view.c -- setup all the parameters (position, angle, etc)
-// for a 3D rendering
-#include "cg_local.h"
-
-
-/*
-=============================================================================
-
- MODEL TESTING
-
-The viewthing and gun positioning tools from Q2 have been integrated and
-enhanced into a single model testing facility.
-
-Model viewing can begin with either "testmodel <modelname>" or "testgun <modelname>".
-
-The names must be the full pathname after the basedir, like
-"models/weapons/v_launch/tris.md3" or "players/male/tris.md3"
-
-Testmodel will create a fake entity 100 units in front of the current view
-position, directly facing the viewer. It will remain immobile, so you can
-move around it to view it from different angles.
-
-Testgun will cause the model to follow the player around and supress the real
-view weapon model. The default frame 0 of most guns is completely off screen,
-so you will probably have to cycle a couple frames to see it.
-
-"nextframe", "prevframe", "nextskin", and "prevskin" commands will change the
-frame or skin of the testmodel. These are bound to F5, F6, F7, and F8 in
-q3default.cfg.
-
-If a gun is being tested, the "gun_x", "gun_y", and "gun_z" variables will let
-you adjust the positioning.
-
-Note that none of the model testing features update while the game is paused, so
-it may be convenient to test with deathmatch set to 1 so that bringing down the
-console doesn't pause the game.
-
-=============================================================================
-*/
-
-/*
-=================
-CG_TestModel_f
-
-Creates an entity in front of the current position, which
-can then be moved around
-=================
-*/
-void CG_TestModel_f (void) {
- vec3_t angles;
-
- memset( &cg.testModelEntity, 0, sizeof(cg.testModelEntity) );
- if ( trap_Argc() < 2 ) {
- return;
- }
-
- Q_strncpyz (cg.testModelName, CG_Argv( 1 ), MAX_QPATH );
- cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
-
- if ( trap_Argc() == 3 ) {
- cg.testModelEntity.backlerp = atof( CG_Argv( 2 ) );
- cg.testModelEntity.frame = 1;
- cg.testModelEntity.oldframe = 0;
- }
- if (! cg.testModelEntity.hModel ) {
- CG_Printf( "Can't register model\n" );
- return;
- }
-
- VectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[0], cg.testModelEntity.origin );
-
- angles[PITCH] = 0;
- angles[YAW] = 180 + cg.refdefViewAngles[1];
- angles[ROLL] = 0;
-
- AnglesToAxis( angles, cg.testModelEntity.axis );
- cg.testGun = qfalse;
-}
-
-/*
-=================
-CG_TestGun_f
-
-Replaces the current view weapon with the given model
-=================
-*/
-void CG_TestGun_f (void) {
- CG_TestModel_f();
- cg.testGun = qtrue;
- cg.testModelEntity.renderfx = RF_MINLIGHT | RF_DEPTHHACK | RF_FIRST_PERSON;
-}
-
-
-void CG_TestModelNextFrame_f (void) {
- cg.testModelEntity.frame++;
- CG_Printf( "frame %i\n", cg.testModelEntity.frame );
-}
-
-void CG_TestModelPrevFrame_f (void) {
- cg.testModelEntity.frame--;
- if ( cg.testModelEntity.frame < 0 ) {
- cg.testModelEntity.frame = 0;
- }
- CG_Printf( "frame %i\n", cg.testModelEntity.frame );
-}
-
-void CG_TestModelNextSkin_f (void) {
- cg.testModelEntity.skinNum++;
- CG_Printf( "skin %i\n", cg.testModelEntity.skinNum );
-}
-
-void CG_TestModelPrevSkin_f (void) {
- cg.testModelEntity.skinNum--;
- if ( cg.testModelEntity.skinNum < 0 ) {
- cg.testModelEntity.skinNum = 0;
- }
- CG_Printf( "skin %i\n", cg.testModelEntity.skinNum );
-}
-
-static void CG_AddTestModel (void) {
- int i;
-
- // re-register the model, because the level may have changed
- cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
- if (! cg.testModelEntity.hModel ) {
- CG_Printf ("Can't register model\n");
- return;
- }
-
- // if testing a gun, set the origin reletive to the view origin
- if ( cg.testGun ) {
- VectorCopy( cg.refdef.vieworg, cg.testModelEntity.origin );
- VectorCopy( cg.refdef.viewaxis[0], cg.testModelEntity.axis[0] );
- VectorCopy( cg.refdef.viewaxis[1], cg.testModelEntity.axis[1] );
- VectorCopy( cg.refdef.viewaxis[2], cg.testModelEntity.axis[2] );
-
- // allow the position to be adjusted
- for (i=0 ; i<3 ; i++) {
- cg.testModelEntity.origin[i] += cg.refdef.viewaxis[0][i] * cg_gun_x.value;
- cg.testModelEntity.origin[i] += cg.refdef.viewaxis[1][i] * cg_gun_y.value;
- cg.testModelEntity.origin[i] += cg.refdef.viewaxis[2][i] * cg_gun_z.value;
- }
- }
-
- trap_R_AddRefEntityToScene( &cg.testModelEntity );
-}
-
-
-
-//============================================================================
-
-
-/*
-=================
-CG_CalcVrect
-
-Sets the coordinates of the rendered window
-=================
-*/
-static void CG_CalcVrect (void) {
- int size;
-
- // the intermission should allways be full screen
- if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
- size = 100;
- } else {
- // bound normal viewsize
- if (cg_viewsize.integer < 30) {
- trap_Cvar_Set ("cg_viewsize","30");
- size = 30;
- } else if (cg_viewsize.integer > 100) {
- trap_Cvar_Set ("cg_viewsize","100");
- size = 100;
- } else {
- size = cg_viewsize.integer;
- }
-
- }
- cg.refdef.width = cgs.glconfig.vidWidth*size/100;
- cg.refdef.width &= ~1;
-
- cg.refdef.height = cgs.glconfig.vidHeight*size/100;
- cg.refdef.height &= ~1;
-
- cg.refdef.x = (cgs.glconfig.vidWidth - cg.refdef.width)/2;
- cg.refdef.y = (cgs.glconfig.vidHeight - cg.refdef.height)/2;
-}
-
-//==============================================================================
-
-
-/*
-===============
-CG_OffsetThirdPersonView
-
-===============
-*/
-#define FOCUS_DISTANCE 512
-static void CG_OffsetThirdPersonView( void ) {
- vec3_t forward, right, up;
- vec3_t view;
- vec3_t focusAngles;
- trace_t trace;
- static vec3_t mins = { -4, -4, -4 };
- static vec3_t maxs = { 4, 4, 4 };
- vec3_t focusPoint;
- float focusDist;
- float forwardScale, sideScale;
-
- cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight;
-
- VectorCopy( cg.refdefViewAngles, focusAngles );
-
- // if dead, look at killer
- if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
- focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
- cg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
- }
-
- if ( focusAngles[PITCH] > 45 ) {
- focusAngles[PITCH] = 45; // don't go too far overhead
- }
- AngleVectors( focusAngles, forward, NULL, NULL );
-
- VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint );
-
- VectorCopy( cg.refdef.vieworg, view );
-
- view[2] += 8;
-
- cg.refdefViewAngles[PITCH] *= 0.5;
-
- AngleVectors( cg.refdefViewAngles, forward, right, up );
-
- forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI );
- sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI );
- VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view );
- VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view );
-
- // trace a ray from the origin to the viewpoint to make sure the view isn't
- // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything
-
- if (!cg_cameraMode.integer) {
- CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
-
- if ( trace.fraction != 1.0 ) {
- VectorCopy( trace.endpos, view );
- view[2] += (1.0 - trace.fraction) * 32;
- // try another trace to this position, because a tunnel may have the ceiling
- // close enogh that this is poking out
-
- CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
- VectorCopy( trace.endpos, view );
- }
- }
-
-
- VectorCopy( view, cg.refdef.vieworg );
-
- // select pitch to look at focus point from vieword
- VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
- focusDist = sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] );
- if ( focusDist < 1 ) {
- focusDist = 1; // should never happen
- }
- cg.refdefViewAngles[PITCH] = -180 / M_PI * atan2( focusPoint[2], focusDist );
- cg.refdefViewAngles[YAW] -= cg_thirdPersonAngle.value;
-}
-
-
-// this causes a compiler bug on mac MrC compiler
-static void CG_StepOffset( void ) {
- int timeDelta;
-
- // smooth out stair climbing
- timeDelta = cg.time - cg.stepTime;
- if ( timeDelta < STEP_TIME ) {
- cg.refdef.vieworg[2] -= cg.stepChange
- * (STEP_TIME - timeDelta) / STEP_TIME;
- }
-}
-
-/*
-===============
-CG_OffsetFirstPersonView
-
-===============
-*/
-static void CG_OffsetFirstPersonView( void ) {
- float *origin;
- float *angles;
- float bob;
- float ratio;
- float delta;
- float speed;
- float f;
- vec3_t predictedVelocity;
- int timeDelta;
-
- if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
- return;
- }
-
- origin = cg.refdef.vieworg;
- angles = cg.refdefViewAngles;
-
- // if dead, fix the angle and don't add any kick
- if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
- angles[ROLL] = 40;
- angles[PITCH] = -15;
- angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW];
- origin[2] += cg.predictedPlayerState.viewheight;
- return;
- }
-
- // add angles based on weapon kick
- VectorAdd (angles, cg.kick_angles, angles);
-
- // add angles based on damage kick
- if ( cg.damageTime ) {
- ratio = cg.time - cg.damageTime;
- if ( ratio < DAMAGE_DEFLECT_TIME ) {
- ratio /= DAMAGE_DEFLECT_TIME;
- angles[PITCH] += ratio * cg.v_dmg_pitch;
- angles[ROLL] += ratio * cg.v_dmg_roll;
- } else {
- ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME;
- if ( ratio > 0 ) {
- angles[PITCH] += ratio * cg.v_dmg_pitch;
- angles[ROLL] += ratio * cg.v_dmg_roll;
- }
- }
- }
-
- // add pitch based on fall kick
-#if 0
- ratio = ( cg.time - cg.landTime) / FALL_TIME;
- if (ratio < 0)
- ratio = 0;
- angles[PITCH] += ratio * cg.fall_value;
-#endif
-
- // add angles based on velocity
- VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity );
-
- delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[0]);
- angles[PITCH] += delta * cg_runpitch.value;
-
- delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[1]);
- angles[ROLL] -= delta * cg_runroll.value;
-
- // add angles based on bob
-
- // make sure the bob is visible even at low speeds
- speed = cg.xyspeed > 200 ? cg.xyspeed : 200;
-
- delta = cg.bobfracsin * cg_bobpitch.value * speed;
- if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
- delta *= 3; // crouching
- angles[PITCH] += delta;
- delta = cg.bobfracsin * cg_bobroll.value * speed;
- if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
- delta *= 3; // crouching accentuates roll
- if (cg.bobcycle & 1)
- delta = -delta;
- angles[ROLL] += delta;
-
-//===================================
-
- // add view height
- origin[2] += cg.predictedPlayerState.viewheight;
-
- // smooth out duck height changes
- timeDelta = cg.time - cg.duckTime;
- if ( timeDelta < DUCK_TIME) {
- cg.refdef.vieworg[2] -= cg.duckChange
- * (DUCK_TIME - timeDelta) / DUCK_TIME;
- }
-
- // add bob height
- bob = cg.bobfracsin * cg.xyspeed * cg_bobup.value;
- if (bob > 6) {
- bob = 6;
- }
-
- origin[2] += bob;
-
-
- // add fall height
- delta = cg.time - cg.landTime;
- if ( delta < LAND_DEFLECT_TIME ) {
- f = delta / LAND_DEFLECT_TIME;
- cg.refdef.vieworg[2] += cg.landChange * f;
- } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
- delta -= LAND_DEFLECT_TIME;
- f = 1.0 - ( delta / LAND_RETURN_TIME );
- cg.refdef.vieworg[2] += cg.landChange * f;
- }
-
- // add step offset
- CG_StepOffset();
-
- // add kick offset
-
- VectorAdd (origin, cg.kick_origin, origin);
-
- // pivot the eye based on a neck length
-#if 0
- {
-#define NECK_LENGTH 8
- vec3_t forward, up;
-
- cg.refdef.vieworg[2] -= NECK_LENGTH;
- AngleVectors( cg.refdefViewAngles, forward, NULL, up );
- VectorMA( cg.refdef.vieworg, 3, forward, cg.refdef.vieworg );
- VectorMA( cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg );
- }
-#endif
-}
-
-//======================================================================
-
-void CG_ZoomDown_f( void ) {
- if ( cg.zoomed ) {
- return;
- }
- cg.zoomed = qtrue;
- cg.zoomTime = cg.time;
-}
-
-void CG_ZoomUp_f( void ) {
- if ( !cg.zoomed ) {
- return;
- }
- cg.zoomed = qfalse;
- cg.zoomTime = cg.time;
-}
-
-
-/*
-====================
-CG_CalcFov
-
-Fixed fov at intermissions, otherwise account for fov variable and zooms.
-====================
-*/
-#define WAVE_AMPLITUDE 1
-#define WAVE_FREQUENCY 0.4
-
-static int CG_CalcFov( void ) {
- float x;
- float phase;
- float v;
- int contents;
- float fov_x, fov_y;
- float zoomFov;
- float f;
- int inwater;
-
- if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- // if in intermission, use a fixed value
- fov_x = 90;
- } else {
- // user selectable
- if ( cgs.dmflags & DF_FIXED_FOV ) {
- // dmflag to prevent wide fov for all clients
- fov_x = 90;
- } else {
- fov_x = cg_fov.value;
- if ( fov_x < 1 ) {
- fov_x = 1;
- } else if ( fov_x > 160 ) {
- fov_x = 160;
- }
- }
-
- // account for zooms
- zoomFov = cg_zoomFov.value;
- if ( zoomFov < 1 ) {
- zoomFov = 1;
- } else if ( zoomFov > 160 ) {
- zoomFov = 160;
- }
-
- if ( cg.zoomed ) {
- f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
- if ( f > 1.0 ) {
- fov_x = zoomFov;
- } else {
- fov_x = fov_x + f * ( zoomFov - fov_x );
- }
- } else {
- f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
- if ( f > 1.0 ) {
- fov_x = fov_x;
- } else {
- fov_x = zoomFov + f * ( fov_x - zoomFov );
- }
- }
- }
-
- x = cg.refdef.width / tan( fov_x / 360 * M_PI );
- fov_y = atan2( cg.refdef.height, x );
- fov_y = fov_y * 360 / M_PI;
-
- // warp if underwater
- contents = CG_PointContents( cg.refdef.vieworg, -1 );
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ){
- phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
- v = WAVE_AMPLITUDE * sin( phase );
- fov_x += v;
- fov_y -= v;
- inwater = qtrue;
- }
- else {
- inwater = qfalse;
- }
-
-
- // set it
- cg.refdef.fov_x = fov_x;
- cg.refdef.fov_y = fov_y;
-
- if ( !cg.zoomed ) {
- cg.zoomSensitivity = 1;
- } else {
- cg.zoomSensitivity = cg.refdef.fov_y / 75.0;
- }
-
- return inwater;
-}
-
-
-
-/*
-===============
-CG_DamageBlendBlob
-
-===============
-*/
-static void CG_DamageBlendBlob( void ) {
- int t;
- int maxTime;
- refEntity_t ent;
-
- if ( !cg.damageValue ) {
- return;
- }
-
- //if (cg.cameraMode) {
- // return;
- //}
-
- // ragePro systems can't fade blends, so don't obscure the screen
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
- return;
- }
-
- maxTime = DAMAGE_TIME;
- t = cg.time - cg.damageTime;
- if ( t <= 0 || t >= maxTime ) {
- return;
- }
-
-
- memset( &ent, 0, sizeof( ent ) );
- ent.reType = RT_SPRITE;
- ent.renderfx = RF_FIRST_PERSON;
-
- VectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], ent.origin );
- VectorMA( ent.origin, cg.damageX * -8, cg.refdef.viewaxis[1], ent.origin );
- VectorMA( ent.origin, cg.damageY * 8, cg.refdef.viewaxis[2], ent.origin );
-
- ent.radius = cg.damageValue * 3;
- ent.customShader = cgs.media.viewBloodShader;
- ent.shaderRGBA[0] = 255;
- ent.shaderRGBA[1] = 255;
- ent.shaderRGBA[2] = 255;
- ent.shaderRGBA[3] = 200 * ( 1.0 - ((float)t / maxTime) );
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-/*
-===============
-CG_CalcViewValues
-
-Sets cg.refdef view values
-===============
-*/
-static int CG_CalcViewValues( void ) {
- playerState_t *ps;
-
- memset( &cg.refdef, 0, sizeof( cg.refdef ) );
-
- // strings for in game rendering
- // Q_strncpyz( cg.refdef.text[0], "Park Ranger", sizeof(cg.refdef.text[0]) );
- // Q_strncpyz( cg.refdef.text[1], "19", sizeof(cg.refdef.text[1]) );
-
- // calculate size of 3D view
- CG_CalcVrect();
-
- ps = &cg.predictedPlayerState;
-/*
- if (cg.cameraMode) {
- vec3_t origin, angles;
- if (trap_getCameraInfo(cg.time, &origin, &angles)) {
- VectorCopy(origin, cg.refdef.vieworg);
- angles[ROLL] = 0;
- VectorCopy(angles, cg.refdefViewAngles);
- AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
- return CG_CalcFov();
- } else {
- cg.cameraMode = qfalse;
- }
- }
-*/
- // intermission view
- if ( ps->pm_type == PM_INTERMISSION ) {
- VectorCopy( ps->origin, cg.refdef.vieworg );
- VectorCopy( ps->viewangles, cg.refdefViewAngles );
- AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
- return CG_CalcFov();
- }
-
- cg.bobcycle = ( ps->bobCycle & 128 ) >> 7;
- cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) );
- cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] +
- ps->velocity[1] * ps->velocity[1] );
-
-
- VectorCopy( ps->origin, cg.refdef.vieworg );
- VectorCopy( ps->viewangles, cg.refdefViewAngles );
-
- if (cg_cameraOrbit.integer) {
- if (cg.time > cg.nextOrbitTime) {
- cg.nextOrbitTime = cg.time + cg_cameraOrbitDelay.integer;
- cg_thirdPersonAngle.value += cg_cameraOrbit.value;
- }
- }
- // add error decay
- if ( cg_errorDecay.value > 0 ) {
- int t;
- float f;
-
- t = cg.time - cg.predictedErrorTime;
- f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
- if ( f > 0 && f < 1 ) {
- VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg );
- } else {
- cg.predictedErrorTime = 0;
- }
- }
-
- if ( cg.renderingThirdPerson ) {
- // back away from character
- CG_OffsetThirdPersonView();
- } else {
- // offset for local bobbing and kicks
- CG_OffsetFirstPersonView();
- }
-
- // position eye reletive to origin
- AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
-
- if ( cg.hyperspace ) {
- cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE;
- }
-
- // field of view
- return CG_CalcFov();
-}
-
-
-/*
-=====================
-CG_PowerupTimerSounds
-=====================
-*/
-static void CG_PowerupTimerSounds( void ) {
- int i;
- int t;
-
- // powerup timers going away
- for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
- t = cg.snap->ps.powerups[i];
- if ( t <= cg.time ) {
- continue;
- }
- if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
- continue;
- }
- if ( ( t - cg.time ) / POWERUP_BLINK_TIME != ( t - cg.oldTime ) / POWERUP_BLINK_TIME ) {
- trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_ITEM, cgs.media.wearOffSound );
- }
- }
-}
-
-/*
-=====================
-CG_AddBufferedSound
-=====================
-*/
-void CG_AddBufferedSound( sfxHandle_t sfx ) {
- if ( !sfx )
- return;
- cg.soundBuffer[cg.soundBufferIn] = sfx;
- cg.soundBufferIn = (cg.soundBufferIn + 1) % MAX_SOUNDBUFFER;
- if (cg.soundBufferIn == cg.soundBufferOut) {
- cg.soundBufferOut++;
- }
-}
-
-/*
-=====================
-CG_PlayBufferedSounds
-=====================
-*/
-static void CG_PlayBufferedSounds( void ) {
- if ( cg.soundTime < cg.time ) {
- if (cg.soundBufferOut != cg.soundBufferIn && cg.soundBuffer[cg.soundBufferOut]) {
- trap_S_StartLocalSound(cg.soundBuffer[cg.soundBufferOut], CHAN_ANNOUNCER);
- cg.soundBuffer[cg.soundBufferOut] = 0;
- cg.soundBufferOut = (cg.soundBufferOut + 1) % MAX_SOUNDBUFFER;
- cg.soundTime = cg.time + 750;
- }
- }
-}
-
-//=========================================================================
-
-/*
-=================
-CG_DrawActiveFrame
-
-Generates and draws a game scene and status information at the given time.
-=================
-*/
-void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) {
- int inwater;
-
- cg.time = serverTime;
- cg.demoPlayback = demoPlayback;
-
- // update cvars
- CG_UpdateCvars();
-
- // if we are only updating the screen as a loading
- // pacifier, don't even try to read snapshots
- if ( cg.infoScreenText[0] != 0 ) {
- CG_DrawInformation();
- return;
- }
-
- // any looped sounds will be respecified as entities
- // are added to the render list
- trap_S_ClearLoopingSounds(qfalse);
-
- // clear all the render lists
- trap_R_ClearScene();
-
- // set up cg.snap and possibly cg.nextSnap
- CG_ProcessSnapshots();
-
- // if we haven't received any snapshots yet, all
- // we can draw is the information screen
- if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
- CG_DrawInformation();
- return;
- }
-
- // let the client system know what our weapon and zoom settings are
- trap_SetUserCmdValue( cg.weaponSelect, cg.zoomSensitivity );
-
- // this counter will be bumped for every valid scene we generate
- cg.clientFrame++;
-
- // update cg.predictedPlayerState
- CG_PredictPlayerState();
-
- // decide on third person view
- cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0);
-
- // build cg.refdef
- inwater = CG_CalcViewValues();
-
- // first person blend blobs, done after AnglesToAxis
- if ( !cg.renderingThirdPerson ) {
- CG_DamageBlendBlob();
- }
-
- // build the render lists
- if ( !cg.hyperspace ) {
- CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct
- CG_AddMarks();
- CG_AddParticles ();
- CG_AddLocalEntities();
- }
- CG_AddViewWeapon( &cg.predictedPlayerState );
-
- // add buffered sounds
- CG_PlayBufferedSounds();
-
- // play buffered voice chats
- CG_PlayBufferedVoiceChats();
-
- // finish up the rest of the refdef
- if ( cg.testModelEntity.hModel ) {
- CG_AddTestModel();
- }
- cg.refdef.time = cg.time;
- memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) );
-
- // warning sounds when powerup is wearing off
- CG_PowerupTimerSounds();
-
- // update audio positions
- trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater );
-
- // make sure the lagometerSample and frame timing isn't done twice when in stereo
- if ( stereoView != STEREO_RIGHT ) {
- cg.frametime = cg.time - cg.oldTime;
- if ( cg.frametime < 0 ) {
- cg.frametime = 0;
- }
- cg.oldTime = cg.time;
- CG_AddLagometerFrameInfo();
- }
- if (cg_timescale.value != cg_timescaleFadeEnd.value) {
- if (cg_timescale.value < cg_timescaleFadeEnd.value) {
- cg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;
- if (cg_timescale.value > cg_timescaleFadeEnd.value)
- cg_timescale.value = cg_timescaleFadeEnd.value;
- }
- else {
- cg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;
- if (cg_timescale.value < cg_timescaleFadeEnd.value)
- cg_timescale.value = cg_timescaleFadeEnd.value;
- }
- if (cg_timescaleFadeSpeed.value) {
- trap_Cvar_Set("timescale", va("%f", cg_timescale.value));
- }
- }
-
- // actually issue the rendering calls
- CG_DrawActive( stereoView );
-
- if ( cg_stats.integer ) {
- CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame );
- }
-
-
-}
-
diff --git a/engine/code/cgame/cg_weapons.c b/engine/code/cgame/cg_weapons.c
deleted file mode 100644
index 0877f11..0000000
--- a/engine/code/cgame/cg_weapons.c
+++ /dev/null
@@ -1,2298 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_weapons.c -- events and effects dealing with weapons
-#include "cg_local.h"
-
-/*
-==========================
-CG_MachineGunEjectBrass
-==========================
-*/
-static void CG_MachineGunEjectBrass( centity_t *cent ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t velocity, xvelocity;
- vec3_t offset, xoffset;
- float waterScale = 1.0f;
- vec3_t v[3];
-
- if ( cg_brassTime.integer <= 0 ) {
- return;
- }
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- velocity[0] = 0;
- velocity[1] = -50 + 40 * crandom();
- velocity[2] = 100 + 50 * crandom();
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random();
-
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time - (rand()&15);
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[0] = 8;
- offset[1] = -4;
- offset[2] = 24;
-
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( cent->lerpOrigin, xoffset, re->origin );
-
- VectorCopy( re->origin, le->pos.trBase );
-
- if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
- waterScale = 0.10f;
- }
-
- xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
- xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
- xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
-
- AxisCopy( axisDefault, re->axis );
- re->hModel = cgs.media.machinegunBrassModel;
-
- le->bounceFactor = 0.4 * waterScale;
-
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[0] = rand()&31;
- le->angles.trBase[1] = rand()&31;
- le->angles.trBase[2] = rand()&31;
- le->angles.trDelta[0] = 2;
- le->angles.trDelta[1] = 1;
- le->angles.trDelta[2] = 0;
-
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_BRASS;
- le->leMarkType = LEMT_NONE;
-}
-
-/*
-==========================
-CG_ShotgunEjectBrass
-==========================
-*/
-static void CG_ShotgunEjectBrass( centity_t *cent ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t velocity, xvelocity;
- vec3_t offset, xoffset;
- vec3_t v[3];
- int i;
-
- if ( cg_brassTime.integer <= 0 ) {
- return;
- }
-
- for ( i = 0; i < 2; i++ ) {
- float waterScale = 1.0f;
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- velocity[0] = 60 + 60 * crandom();
- if ( i == 0 ) {
- velocity[1] = 40 + 10 * crandom();
- } else {
- velocity[1] = -40 + 10 * crandom();
- }
- velocity[2] = 100 + 50 * crandom();
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + cg_brassTime.integer*3 + cg_brassTime.integer * random();
-
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time;
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[0] = 8;
- offset[1] = 0;
- offset[2] = 24;
-
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( cent->lerpOrigin, xoffset, re->origin );
- VectorCopy( re->origin, le->pos.trBase );
- if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
- waterScale = 0.10f;
- }
-
- xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
- xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
- xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
-
- AxisCopy( axisDefault, re->axis );
- re->hModel = cgs.media.shotgunBrassModel;
- le->bounceFactor = 0.3f;
-
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[0] = rand()&31;
- le->angles.trBase[1] = rand()&31;
- le->angles.trBase[2] = rand()&31;
- le->angles.trDelta[0] = 1;
- le->angles.trDelta[1] = 0.5;
- le->angles.trDelta[2] = 0;
-
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_BRASS;
- le->leMarkType = LEMT_NONE;
- }
-}
-
-
-#ifdef MISSIONPACK
-/*
-==========================
-CG_NailgunEjectBrass
-==========================
-*/
-static void CG_NailgunEjectBrass( centity_t *cent ) {
- localEntity_t *smoke;
- vec3_t origin;
- vec3_t v[3];
- vec3_t offset;
- vec3_t xoffset;
- vec3_t up;
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[0] = 0;
- offset[1] = -12;
- offset[2] = 24;
-
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( cent->lerpOrigin, xoffset, origin );
-
- VectorSet( up, 0, 0, 64 );
-
- smoke = CG_SmokePuff( origin, up, 32, 1, 1, 1, 0.33f, 700, cg.time, 0, 0, cgs.media.smokePuffShader );
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
-}
-#endif
-
-
-/*
-==========================
-CG_RailTrail
-==========================
-*/
-void CG_RailTrail (clientInfo_t *ci, vec3_t start, vec3_t end) {
- vec3_t axis[36], move, move2, next_move, vec, temp;
- float len;
- int i, j, skip;
-
- localEntity_t *le;
- refEntity_t *re;
-
-#define RADIUS 4
-#define ROTATION 1
-#define SPACING 5
-
- start[2] -= 4;
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- le->leType = LE_FADE_RGB;
- le->startTime = cg.time;
- le->endTime = cg.time + cg_railTrailTime.value;
- le->lifeRate = 1.0 / (le->endTime - le->startTime);
-
- re->shaderTime = cg.time / 1000.0f;
- re->reType = RT_RAIL_CORE;
- re->customShader = cgs.media.railCoreShader;
-
- VectorCopy(start, re->origin);
- VectorCopy(end, re->oldorigin);
-
- re->shaderRGBA[0] = ci->color1[0] * 255;
- re->shaderRGBA[1] = ci->color1[1] * 255;
- re->shaderRGBA[2] = ci->color1[2] * 255;
- re->shaderRGBA[3] = 255;
-
- le->color[0] = ci->color1[0] * 0.75;
- le->color[1] = ci->color1[1] * 0.75;
- le->color[2] = ci->color1[2] * 0.75;
- le->color[3] = 1.0f;
-
- AxisClear( re->axis );
-
- if (cg_oldRail.integer)
- {
- // nudge down a bit so it isn't exactly in center
- re->origin[2] -= 8;
- re->oldorigin[2] -= 8;
- return;
- }
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
- PerpendicularVector(temp, vec);
- for (i = 0 ; i < 36; i++)
- {
- RotatePointAroundVector(axis[i], vec, temp, i * 10);//banshee 2.4 was 10
- }
-
- VectorMA(move, 20, vec, move);
- VectorCopy(move, next_move);
- VectorScale (vec, SPACING, vec);
-
- skip = -1;
-
- j = 18;
- for (i = 0; i < len; i += SPACING)
- {
- if (i != skip)
- {
- skip = i + SPACING;
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
- le->leFlags = LEF_PUFF_DONT_SCALE;
- le->leType = LE_MOVE_SCALE_FADE;
- le->startTime = cg.time;
- le->endTime = cg.time + (i>>1) + 600;
- le->lifeRate = 1.0 / (le->endTime - le->startTime);
-
- re->shaderTime = cg.time / 1000.0f;
- re->reType = RT_SPRITE;
- re->radius = 1.1f;
- re->customShader = cgs.media.railRingsShader;
-
- re->shaderRGBA[0] = ci->color2[0] * 255;
- re->shaderRGBA[1] = ci->color2[1] * 255;
- re->shaderRGBA[2] = ci->color2[2] * 255;
- re->shaderRGBA[3] = 255;
-
- le->color[0] = ci->color2[0] * 0.75;
- le->color[1] = ci->color2[1] * 0.75;
- le->color[2] = ci->color2[2] * 0.75;
- le->color[3] = 1.0f;
-
- le->pos.trType = TR_LINEAR;
- le->pos.trTime = cg.time;
-
- VectorCopy( move, move2);
- VectorMA(move2, RADIUS , axis[j], move2);
- VectorCopy(move2, le->pos.trBase);
-
- le->pos.trDelta[0] = axis[j][0]*6;
- le->pos.trDelta[1] = axis[j][1]*6;
- le->pos.trDelta[2] = axis[j][2]*6;
- }
-
- VectorAdd (move, vec, move);
-
- j = (j + ROTATION) % 36;
- }
-}
-
-/*
-==========================
-CG_RocketTrail
-==========================
-*/
-static void CG_RocketTrail( centity_t *ent, const weaponInfo_t *wi ) {
- int step;
- vec3_t origin, lastPos;
- int t;
- int startTime, contents;
- int lastContents;
- entityState_t *es;
- vec3_t up;
- localEntity_t *smoke;
-
- if ( cg_noProjectileTrail.integer ) {
- return;
- }
-
- up[0] = 0;
- up[1] = 0;
- up[2] = 0;
-
- step = 50;
-
- es = &ent->currentState;
- startTime = ent->trailTime;
- t = step * ( (startTime + step) / step );
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- contents = CG_PointContents( origin, -1 );
-
- // if object (e.g. grenade) is stationary, don't toss up smoke
- if ( es->pos.trType == TR_STATIONARY ) {
- ent->trailTime = cg.time;
- return;
- }
-
- BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
- lastContents = CG_PointContents( lastPos, -1 );
-
- ent->trailTime = cg.time;
-
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- if ( contents & lastContents & CONTENTS_WATER ) {
- CG_BubbleTrail( lastPos, origin, 8 );
- }
- return;
- }
-
- for ( ; t <= ent->trailTime ; t += step ) {
- BG_EvaluateTrajectory( &es->pos, t, lastPos );
-
- smoke = CG_SmokePuff( lastPos, up,
- wi->trailRadius,
- 1, 1, 1, 0.33f,
- wi->wiTrailTime,
- t,
- 0,
- 0,
- cgs.media.smokePuffShader );
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
- }
-
-}
-
-#ifdef MISSIONPACK
-/*
-==========================
-CG_NailTrail
-==========================
-*/
-static void CG_NailTrail( centity_t *ent, const weaponInfo_t *wi ) {
- int step;
- vec3_t origin, lastPos;
- int t;
- int startTime, contents;
- int lastContents;
- entityState_t *es;
- vec3_t up;
- localEntity_t *smoke;
-
- if ( cg_noProjectileTrail.integer ) {
- return;
- }
-
- up[0] = 0;
- up[1] = 0;
- up[2] = 0;
-
- step = 50;
-
- es = &ent->currentState;
- startTime = ent->trailTime;
- t = step * ( (startTime + step) / step );
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- contents = CG_PointContents( origin, -1 );
-
- // if object (e.g. grenade) is stationary, don't toss up smoke
- if ( es->pos.trType == TR_STATIONARY ) {
- ent->trailTime = cg.time;
- return;
- }
-
- BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
- lastContents = CG_PointContents( lastPos, -1 );
-
- ent->trailTime = cg.time;
-
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- if ( contents & lastContents & CONTENTS_WATER ) {
- CG_BubbleTrail( lastPos, origin, 8 );
- }
- return;
- }
-
- for ( ; t <= ent->trailTime ; t += step ) {
- BG_EvaluateTrajectory( &es->pos, t, lastPos );
-
- smoke = CG_SmokePuff( lastPos, up,
- wi->trailRadius,
- 1, 1, 1, 0.33f,
- wi->wiTrailTime,
- t,
- 0,
- 0,
- cgs.media.nailPuffShader );
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
- }
-
-}
-#endif
-
-/*
-==========================
-CG_NailTrail
-==========================
-*/
-static void CG_PlasmaTrail( centity_t *cent, const weaponInfo_t *wi ) {
- localEntity_t *le;
- refEntity_t *re;
- entityState_t *es;
- vec3_t velocity, xvelocity, origin;
- vec3_t offset, xoffset;
- vec3_t v[3];
- int t, startTime, step;
-
- float waterScale = 1.0f;
-
- if ( cg_noProjectileTrail.integer || cg_oldPlasma.integer ) {
- return;
- }
-
- step = 50;
-
- es = ¢->currentState;
- startTime = cent->trailTime;
- t = step * ( (startTime + step) / step );
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- velocity[0] = 60 - 120 * crandom();
- velocity[1] = 40 - 80 * crandom();
- velocity[2] = 100 - 200 * crandom();
-
- le->leType = LE_MOVE_SCALE_FADE;
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_NONE;
- le->leMarkType = LEMT_NONE;
-
- le->startTime = cg.time;
- le->endTime = le->startTime + 600;
-
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time;
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[0] = 2;
- offset[1] = 2;
- offset[2] = 2;
-
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
-
- VectorAdd( origin, xoffset, re->origin );
- VectorCopy( re->origin, le->pos.trBase );
-
- if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
- waterScale = 0.10f;
- }
-
- xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
- xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
- xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
-
- AxisCopy( axisDefault, re->axis );
- re->shaderTime = cg.time / 1000.0f;
- re->reType = RT_SPRITE;
- re->radius = 0.25f;
- re->customShader = cgs.media.railRingsShader;
- le->bounceFactor = 0.3f;
-
- re->shaderRGBA[0] = wi->flashDlightColor[0] * 63;
- re->shaderRGBA[1] = wi->flashDlightColor[1] * 63;
- re->shaderRGBA[2] = wi->flashDlightColor[2] * 63;
- re->shaderRGBA[3] = 63;
-
- le->color[0] = wi->flashDlightColor[0] * 0.2;
- le->color[1] = wi->flashDlightColor[1] * 0.2;
- le->color[2] = wi->flashDlightColor[2] * 0.2;
- le->color[3] = 0.25f;
-
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[0] = rand()&31;
- le->angles.trBase[1] = rand()&31;
- le->angles.trBase[2] = rand()&31;
- le->angles.trDelta[0] = 1;
- le->angles.trDelta[1] = 0.5;
- le->angles.trDelta[2] = 0;
-
-}
-/*
-==========================
-CG_GrappleTrail
-==========================
-*/
-void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi ) {
- vec3_t origin;
- entityState_t *es;
- vec3_t forward, up;
- refEntity_t beam;
-
- es = &ent->currentState;
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- ent->trailTime = cg.time;
-
- memset( &beam, 0, sizeof( beam ) );
- //FIXME adjust for muzzle position
- VectorCopy ( cg_entities[ ent->currentState.otherEntityNum ].lerpOrigin, beam.origin );
- beam.origin[2] += 26;
- AngleVectors( cg_entities[ ent->currentState.otherEntityNum ].lerpAngles, forward, NULL, up );
- VectorMA( beam.origin, -6, up, beam.origin );
- VectorCopy( origin, beam.oldorigin );
-
- if (Distance( beam.origin, beam.oldorigin ) < 64 )
- return; // Don't draw if close
-
- beam.reType = RT_LIGHTNING;
- beam.customShader = cgs.media.lightningShader;
-
- AxisClear( beam.axis );
- beam.shaderRGBA[0] = 0xff;
- beam.shaderRGBA[1] = 0xff;
- beam.shaderRGBA[2] = 0xff;
- beam.shaderRGBA[3] = 0xff;
- trap_R_AddRefEntityToScene( &beam );
-}
-
-/*
-==========================
-CG_GrenadeTrail
-==========================
-*/
-static void CG_GrenadeTrail( centity_t *ent, const weaponInfo_t *wi ) {
- CG_RocketTrail( ent, wi );
-}
-
-
-/*
-=================
-CG_RegisterWeapon
-
-The server says this item is used on this level
-=================
-*/
-void CG_RegisterWeapon( int weaponNum ) {
- weaponInfo_t *weaponInfo;
- gitem_t *item, *ammo;
- char path[MAX_QPATH];
- vec3_t mins, maxs;
- int i;
-
- weaponInfo = &cg_weapons[weaponNum];
-
- if ( weaponNum == 0 ) {
- return;
- }
-
- if ( weaponInfo->registered ) {
- return;
- }
-
- memset( weaponInfo, 0, sizeof( *weaponInfo ) );
- weaponInfo->registered = qtrue;
-
- for ( item = bg_itemlist + 1 ; item->classname ; item++ ) {
- if ( item->giType == IT_WEAPON && item->giTag == weaponNum ) {
- weaponInfo->item = item;
- break;
- }
- }
- if ( !item->classname ) {
- CG_Error( "Couldn't find weapon %i", weaponNum );
- }
- CG_RegisterItemVisuals( item - bg_itemlist );
-
- // load cmodel before model so filecache works
- weaponInfo->weaponModel = trap_R_RegisterModel( item->world_model[0] );
-
- // calc midpoint for rotation
- trap_R_ModelBounds( weaponInfo->weaponModel, mins, maxs );
- for ( i = 0 ; i < 3 ; i++ ) {
- weaponInfo->weaponMidpoint[i] = mins[i] + 0.5 * ( maxs[i] - mins[i] );
- }
-
- weaponInfo->weaponIcon = trap_R_RegisterShader( item->icon );
- weaponInfo->ammoIcon = trap_R_RegisterShader( item->icon );
-
- for ( ammo = bg_itemlist + 1 ; ammo->classname ; ammo++ ) {
- if ( ammo->giType == IT_AMMO && ammo->giTag == weaponNum ) {
- break;
- }
- }
- if ( ammo->classname && ammo->world_model[0] ) {
- weaponInfo->ammoModel = trap_R_RegisterModel( ammo->world_model[0] );
- }
-
- strcpy( path, item->world_model[0] );
- COM_StripExtension(path, path, sizeof(path));
- strcat( path, "_flash.md3" );
- weaponInfo->flashModel = trap_R_RegisterModel( path );
-
- strcpy( path, item->world_model[0] );
- COM_StripExtension(path, path, sizeof(path));
- strcat( path, "_barrel.md3" );
- weaponInfo->barrelModel = trap_R_RegisterModel( path );
-
- strcpy( path, item->world_model[0] );
- COM_StripExtension(path, path, sizeof(path));
- strcat( path, "_hand.md3" );
- weaponInfo->handsModel = trap_R_RegisterModel( path );
-
- if ( !weaponInfo->handsModel ) {
- weaponInfo->handsModel = trap_R_RegisterModel( "models/weapons2/shotgun/shotgun_hand.md3" );
- }
-
- weaponInfo->loopFireSound = qfalse;
-
- switch ( weaponNum ) {
- case WP_GAUNTLET:
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/melee/fstatck.wav", qfalse );
- break;
-
- case WP_LIGHTNING:
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse );
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/lightning/lg_hum.wav", qfalse );
-
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/lightning/lg_fire.wav", qfalse );
- cgs.media.lightningShader = trap_R_RegisterShader( "lightningBoltNew");
- cgs.media.lightningExplosionModel = trap_R_RegisterModel( "models/weaphits/crackle.md3" );
- cgs.media.sfx_lghit1 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit.wav", qfalse );
- cgs.media.sfx_lghit2 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit2.wav", qfalse );
- cgs.media.sfx_lghit3 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit3.wav", qfalse );
-
- break;
-
- case WP_GRAPPLING_HOOK:
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" );
- weaponInfo->missileTrailFunc = CG_GrappleTrail;
- weaponInfo->missileDlight = 200;
- weaponInfo->wiTrailTime = 2000;
- weaponInfo->trailRadius = 64;
- MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse );
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse );
- break;
-
-#ifdef MISSIONPACK
- case WP_CHAINGUN:
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/vulcan/wvulfire.wav", qfalse );
- weaponInfo->loopFireSound = qtrue;
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf1b.wav", qfalse );
- weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf2b.wav", qfalse );
- weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf3b.wav", qfalse );
- weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf4b.wav", qfalse );
- weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;
- cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
- break;
-#endif
-
- case WP_MACHINEGUN:
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf1b.wav", qfalse );
- weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf2b.wav", qfalse );
- weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf3b.wav", qfalse );
- weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf4b.wav", qfalse );
- weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;
- cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
- break;
-
- case WP_SHOTGUN:
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/shotgun/sshotf1b.wav", qfalse );
- weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass;
- break;
-
- case WP_ROCKET_LAUNCHER:
- weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" );
- weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse );
- weaponInfo->missileTrailFunc = CG_RocketTrail;
- weaponInfo->missileDlight = 200;
- weaponInfo->wiTrailTime = 2000;
- weaponInfo->trailRadius = 64;
-
- MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 );
-
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse );
- cgs.media.rocketExplosionShader = trap_R_RegisterShader( "rocketExplosion" );
- break;
-
-#ifdef MISSIONPACK
- case WP_PROX_LAUNCHER:
- weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/proxmine.md3" );
- weaponInfo->missileTrailFunc = CG_GrenadeTrail;
- weaponInfo->wiTrailTime = 700;
- weaponInfo->trailRadius = 32;
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/proxmine/wstbfire.wav", qfalse );
- cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" );
- break;
-#endif
-
- case WP_GRENADE_LAUNCHER:
- weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/grenade1.md3" );
- weaponInfo->missileTrailFunc = CG_GrenadeTrail;
- weaponInfo->wiTrailTime = 700;
- weaponInfo->trailRadius = 32;
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/grenade/grenlf1a.wav", qfalse );
- cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" );
- break;
-
-#ifdef MISSIONPACK
- case WP_NAILGUN:
- weaponInfo->ejectBrassFunc = CG_NailgunEjectBrass;
- weaponInfo->missileTrailFunc = CG_NailTrail;
-// weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/nailgun/wnalflit.wav", qfalse );
- weaponInfo->trailRadius = 16;
- weaponInfo->wiTrailTime = 250;
- weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/nail.md3" );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/nailgun/wnalfire.wav", qfalse );
- break;
-#endif
-
- case WP_PLASMAGUN:
-// weaponInfo->missileModel = cgs.media.invulnerabilityPowerupModel;
- weaponInfo->missileTrailFunc = CG_PlasmaTrail;
- weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/plasma/lasfly.wav", qfalse );
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/plasma/hyprbf1a.wav", qfalse );
- cgs.media.plasmaExplosionShader = trap_R_RegisterShader( "plasmaExplosion" );
- cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" );
- break;
-
- case WP_RAILGUN:
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/railgun/rg_hum.wav", qfalse );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.5f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/railgun/railgf1a.wav", qfalse );
- cgs.media.railExplosionShader = trap_R_RegisterShader( "railExplosion" );
- cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" );
- cgs.media.railCoreShader = trap_R_RegisterShader( "railCore" );
- break;
-
- case WP_BFG:
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/bfg/bfg_hum.wav", qfalse );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.7f, 1 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/bfg/bfg_fire.wav", qfalse );
- cgs.media.bfgExplosionShader = trap_R_RegisterShader( "bfgExplosion" );
- weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/bfg.md3" );
- weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse );
- break;
-
- default:
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 1 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse );
- break;
- }
-}
-
-/*
-=================
-CG_RegisterItemVisuals
-
-The server says this item is used on this level
-=================
-*/
-void CG_RegisterItemVisuals( int itemNum ) {
- itemInfo_t *itemInfo;
- gitem_t *item;
-
- if ( itemNum < 0 || itemNum >= bg_numItems ) {
- CG_Error( "CG_RegisterItemVisuals: itemNum %d out of range [0-%d]", itemNum, bg_numItems-1 );
- }
-
- itemInfo = &cg_items[ itemNum ];
- if ( itemInfo->registered ) {
- return;
- }
-
- item = &bg_itemlist[ itemNum ];
-
- memset( itemInfo, 0, sizeof( &itemInfo ) );
- itemInfo->registered = qtrue;
-
- itemInfo->models[0] = trap_R_RegisterModel( item->world_model[0] );
-
- itemInfo->icon = trap_R_RegisterShader( item->icon );
-
- if ( item->giType == IT_WEAPON ) {
- CG_RegisterWeapon( item->giTag );
- }
-
- //
- // powerups have an accompanying ring or sphere
- //
- if ( item->giType == IT_POWERUP || item->giType == IT_HEALTH ||
- item->giType == IT_ARMOR || item->giType == IT_HOLDABLE ) {
- if ( item->world_model[1] ) {
- itemInfo->models[1] = trap_R_RegisterModel( item->world_model[1] );
- }
- }
-}
-
-
-/*
-========================================================================================
-
-VIEW WEAPON
-
-========================================================================================
-*/
-
-/*
-=================
-CG_MapTorsoToWeaponFrame
-
-=================
-*/
-static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame ) {
-
- // change weapon
- if ( frame >= ci->animations[TORSO_DROP].firstFrame
- && frame < ci->animations[TORSO_DROP].firstFrame + 9 ) {
- return frame - ci->animations[TORSO_DROP].firstFrame + 6;
- }
-
- // stand attack
- if ( frame >= ci->animations[TORSO_ATTACK].firstFrame
- && frame < ci->animations[TORSO_ATTACK].firstFrame + 6 ) {
- return 1 + frame - ci->animations[TORSO_ATTACK].firstFrame;
- }
-
- // stand attack 2
- if ( frame >= ci->animations[TORSO_ATTACK2].firstFrame
- && frame < ci->animations[TORSO_ATTACK2].firstFrame + 6 ) {
- return 1 + frame - ci->animations[TORSO_ATTACK2].firstFrame;
- }
-
- return 0;
-}
-
-
-/*
-==============
-CG_CalculateWeaponPosition
-==============
-*/
-static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) {
- float scale;
- int delta;
- float fracsin;
-
- VectorCopy( cg.refdef.vieworg, origin );
- VectorCopy( cg.refdefViewAngles, angles );
-
- // on odd legs, invert some angles
- if ( cg.bobcycle & 1 ) {
- scale = -cg.xyspeed;
- } else {
- scale = cg.xyspeed;
- }
-
- // gun angles from bobbing
- angles[ROLL] += scale * cg.bobfracsin * 0.005;
- angles[YAW] += scale * cg.bobfracsin * 0.01;
- angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005;
-
- // drop the weapon when landing
- delta = cg.time - cg.landTime;
- if ( delta < LAND_DEFLECT_TIME ) {
- origin[2] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME;
- } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
- origin[2] += cg.landChange*0.25 *
- (LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME;
- }
-
-#if 0
- // drop the weapon when stair climbing
- delta = cg.time - cg.stepTime;
- if ( delta < STEP_TIME/2 ) {
- origin[2] -= cg.stepChange*0.25 * delta / (STEP_TIME/2);
- } else if ( delta < STEP_TIME ) {
- origin[2] -= cg.stepChange*0.25 * (STEP_TIME - delta) / (STEP_TIME/2);
- }
-#endif
-
- // idle drift
- scale = cg.xyspeed + 40;
- fracsin = sin( cg.time * 0.001 );
- angles[ROLL] += scale * fracsin * 0.01;
- angles[YAW] += scale * fracsin * 0.01;
- angles[PITCH] += scale * fracsin * 0.01;
-}
-
-
-/*
-===============
-CG_LightningBolt
-
-Origin will be the exact tag point, which is slightly
-different than the muzzle point used for determining hits.
-The cent should be the non-predicted cent if it is from the player,
-so the endpoint will reflect the simulated strike (lagging the predicted
-angle)
-===============
-*/
-static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
- trace_t trace;
- refEntity_t beam;
- vec3_t forward;
- vec3_t muzzlePoint, endPoint;
-
- if (cent->currentState.weapon != WP_LIGHTNING) {
- return;
- }
-
- memset( &beam, 0, sizeof( beam ) );
-
- // CPMA "true" lightning
- if ((cent->currentState.number == cg.predictedPlayerState.clientNum) && (cg_trueLightning.value != 0)) {
- vec3_t angle;
- int i;
-
- for (i = 0; i < 3; i++) {
- float a = cent->lerpAngles[i] - cg.refdefViewAngles[i];
- if (a > 180) {
- a -= 360;
- }
- if (a < -180) {
- a += 360;
- }
-
- angle[i] = cg.refdefViewAngles[i] + a * (1.0 - cg_trueLightning.value);
- if (angle[i] < 0) {
- angle[i] += 360;
- }
- if (angle[i] > 360) {
- angle[i] -= 360;
- }
- }
-
- AngleVectors(angle, forward, NULL, NULL );
- VectorCopy(cent->lerpOrigin, muzzlePoint );
-// VectorCopy(cg.refdef.vieworg, muzzlePoint );
- } else {
- // !CPMA
- AngleVectors( cent->lerpAngles, forward, NULL, NULL );
- VectorCopy(cent->lerpOrigin, muzzlePoint );
- }
-
- // FIXME: crouch
- muzzlePoint[2] += DEFAULT_VIEWHEIGHT;
-
- VectorMA( muzzlePoint, 14, forward, muzzlePoint );
-
- // project forward by the lightning range
- VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );
-
- // see if it hit a wall
- CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint,
- cent->currentState.number, MASK_SHOT );
-
- // this is the endpoint
- VectorCopy( trace.endpos, beam.oldorigin );
-
- // use the provided origin, even though it may be slightly
- // different than the muzzle origin
- VectorCopy( origin, beam.origin );
-
- beam.reType = RT_LIGHTNING;
- beam.customShader = cgs.media.lightningShader;
- trap_R_AddRefEntityToScene( &beam );
-
- // add the impact flare if it hit something
- if ( trace.fraction < 1.0 ) {
- vec3_t angles;
- vec3_t dir;
-
- VectorSubtract( beam.oldorigin, beam.origin, dir );
- VectorNormalize( dir );
-
- memset( &beam, 0, sizeof( beam ) );
- beam.hModel = cgs.media.lightningExplosionModel;
-
- VectorMA( trace.endpos, -16, dir, beam.origin );
-
- // make a random orientation
- angles[0] = rand() % 360;
- angles[1] = rand() % 360;
- angles[2] = rand() % 360;
- AnglesToAxis( angles, beam.axis );
- trap_R_AddRefEntityToScene( &beam );
- }
-}
-/*
-
-static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
- trace_t trace;
- refEntity_t beam;
- vec3_t forward;
- vec3_t muzzlePoint, endPoint;
-
- if ( cent->currentState.weapon != WP_LIGHTNING ) {
- return;
- }
-
- memset( &beam, 0, sizeof( beam ) );
-
- // find muzzle point for this frame
- VectorCopy( cent->lerpOrigin, muzzlePoint );
- AngleVectors( cent->lerpAngles, forward, NULL, NULL );
-
- // FIXME: crouch
- muzzlePoint[2] += DEFAULT_VIEWHEIGHT;
-
- VectorMA( muzzlePoint, 14, forward, muzzlePoint );
-
- // project forward by the lightning range
- VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );
-
- // see if it hit a wall
- CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint,
- cent->currentState.number, MASK_SHOT );
-
- // this is the endpoint
- VectorCopy( trace.endpos, beam.oldorigin );
-
- // use the provided origin, even though it may be slightly
- // different than the muzzle origin
- VectorCopy( origin, beam.origin );
-
- beam.reType = RT_LIGHTNING;
- beam.customShader = cgs.media.lightningShader;
- trap_R_AddRefEntityToScene( &beam );
-
- // add the impact flare if it hit something
- if ( trace.fraction < 1.0 ) {
- vec3_t angles;
- vec3_t dir;
-
- VectorSubtract( beam.oldorigin, beam.origin, dir );
- VectorNormalize( dir );
-
- memset( &beam, 0, sizeof( beam ) );
- beam.hModel = cgs.media.lightningExplosionModel;
-
- VectorMA( trace.endpos, -16, dir, beam.origin );
-
- // make a random orientation
- angles[0] = rand() % 360;
- angles[1] = rand() % 360;
- angles[2] = rand() % 360;
- AnglesToAxis( angles, beam.axis );
- trap_R_AddRefEntityToScene( &beam );
- }
-}
-*/
-
-/*
-===============
-CG_SpawnRailTrail
-
-Origin will be the exact tag point, which is slightly
-different than the muzzle point used for determining hits.
-===============
-*/
-static void CG_SpawnRailTrail( centity_t *cent, vec3_t origin ) {
- clientInfo_t *ci;
-
- if ( cent->currentState.weapon != WP_RAILGUN ) {
- return;
- }
- if ( !cent->pe.railgunFlash ) {
- return;
- }
- cent->pe.railgunFlash = qtrue;
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- CG_RailTrail( ci, origin, cent->pe.railgunImpact );
-}
-
-
-/*
-======================
-CG_MachinegunSpinAngle
-======================
-*/
-#define SPIN_SPEED 0.9
-#define COAST_TIME 1000
-static float CG_MachinegunSpinAngle( centity_t *cent ) {
- int delta;
- float angle;
- float speed;
-
- delta = cg.time - cent->pe.barrelTime;
- if ( cent->pe.barrelSpinning ) {
- angle = cent->pe.barrelAngle + delta * SPIN_SPEED;
- } else {
- if ( delta > COAST_TIME ) {
- delta = COAST_TIME;
- }
-
- speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
- angle = cent->pe.barrelAngle + delta * speed;
- }
-
- if ( cent->pe.barrelSpinning == !(cent->currentState.eFlags & EF_FIRING) ) {
- cent->pe.barrelTime = cg.time;
- cent->pe.barrelAngle = AngleMod( angle );
- cent->pe.barrelSpinning = !!(cent->currentState.eFlags & EF_FIRING);
-#ifdef MISSIONPACK
- if ( cent->currentState.weapon == WP_CHAINGUN && !cent->pe.barrelSpinning ) {
- trap_S_StartSound( NULL, cent->currentState.number, CHAN_WEAPON, trap_S_RegisterSound( "sound/weapons/vulcan/wvulwind.wav", qfalse ) );
- }
-#endif
- }
-
- return angle;
-}
-
-
-/*
-========================
-CG_AddWeaponWithPowerups
-========================
-*/
-static void CG_AddWeaponWithPowerups( refEntity_t *gun, int powerups ) {
- // add powerup effects
- if ( powerups & ( 1 << PW_INVIS ) ) {
- gun->customShader = cgs.media.invisShader;
- trap_R_AddRefEntityToScene( gun );
- } else {
- trap_R_AddRefEntityToScene( gun );
-
- if ( powerups & ( 1 << PW_BATTLESUIT ) ) {
- gun->customShader = cgs.media.battleWeaponShader;
- trap_R_AddRefEntityToScene( gun );
- }
- if ( powerups & ( 1 << PW_QUAD ) ) {
- gun->customShader = cgs.media.quadWeaponShader;
- trap_R_AddRefEntityToScene( gun );
- }
- }
-}
-
-
-/*
-=============
-CG_AddPlayerWeapon
-
-Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL)
-The main player will have this called for BOTH cases, so effects like light and
-sound should only be done on the world model case.
-=============
-*/
-void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team ) {
- refEntity_t gun;
- refEntity_t barrel;
- refEntity_t flash;
- vec3_t angles;
- weapon_t weaponNum;
- weaponInfo_t *weapon;
- centity_t *nonPredictedCent;
- orientation_t lerped;
-
- weaponNum = cent->currentState.weapon;
-
- CG_RegisterWeapon( weaponNum );
- weapon = &cg_weapons[weaponNum];
-
- // add the weapon
- memset( &gun, 0, sizeof( gun ) );
- VectorCopy( parent->lightingOrigin, gun.lightingOrigin );
- gun.shadowPlane = parent->shadowPlane;
- gun.renderfx = parent->renderfx;
-
- // set custom shading for railgun refire rate
- if ( ps ) {
- if ( cg.predictedPlayerState.weapon == WP_RAILGUN
- && cg.predictedPlayerState.weaponstate == WEAPON_FIRING ) {
- float f;
-
- f = (float)cg.predictedPlayerState.weaponTime / 1500;
- gun.shaderRGBA[1] = 0;
- gun.shaderRGBA[0] =
- gun.shaderRGBA[2] = 255 * ( 1.0 - f );
- } else {
- gun.shaderRGBA[0] = 255;
- gun.shaderRGBA[1] = 255;
- gun.shaderRGBA[2] = 255;
- gun.shaderRGBA[3] = 255;
- }
- }
-
- gun.hModel = weapon->weaponModel;
- if (!gun.hModel) {
- return;
- }
-
- if ( !ps ) {
- // add weapon ready sound
- cent->pe.lightningFiring = qfalse;
- if ( ( cent->currentState.eFlags & EF_FIRING ) && weapon->firingSound ) {
- // lightning gun and guantlet make a different sound when fire is held down
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound );
- cent->pe.lightningFiring = qtrue;
- } else if ( weapon->readySound ) {
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound );
- }
- }
-
- trap_R_LerpTag(&lerped, parent->hModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, "tag_weapon");
- VectorCopy(parent->origin, gun.origin);
-
- VectorMA(gun.origin, lerped.origin[0], parent->axis[0], gun.origin);
-
- // Make weapon appear left-handed for 2 and centered for 3
- if(ps && cg_drawGun.integer == 2)
- VectorMA(gun.origin, -lerped.origin[1], parent->axis[1], gun.origin);
- else if(!ps || cg_drawGun.integer != 3)
- VectorMA(gun.origin, lerped.origin[1], parent->axis[1], gun.origin);
-
- VectorMA(gun.origin, lerped.origin[2], parent->axis[2], gun.origin);
-
- MatrixMultiply(lerped.axis, ((refEntity_t *)parent)->axis, gun.axis);
- gun.backlerp = parent->backlerp;
-
- CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups );
-
- // add the spinning barrel
- if ( weapon->barrelModel ) {
- memset( &barrel, 0, sizeof( barrel ) );
- VectorCopy( parent->lightingOrigin, barrel.lightingOrigin );
- barrel.shadowPlane = parent->shadowPlane;
- barrel.renderfx = parent->renderfx;
-
- barrel.hModel = weapon->barrelModel;
- angles[YAW] = 0;
- angles[PITCH] = 0;
- angles[ROLL] = CG_MachinegunSpinAngle( cent );
- AnglesToAxis( angles, barrel.axis );
-
- CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" );
-
- CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups );
- }
-
- // make sure we aren't looking at cg.predictedPlayerEntity for LG
- nonPredictedCent = &cg_entities[cent->currentState.clientNum];
-
- // if the index of the nonPredictedCent is not the same as the clientNum
- // then this is a fake player (like on teh single player podiums), so
- // go ahead and use the cent
- if( ( nonPredictedCent - cg_entities ) != cent->currentState.clientNum ) {
- nonPredictedCent = cent;
- }
-
- // add the flash
- if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK )
- && ( nonPredictedCent->currentState.eFlags & EF_FIRING ) )
- {
- // continuous flash
- } else {
- // impulse flash
- if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash ) {
- return;
- }
- }
-
- memset( &flash, 0, sizeof( flash ) );
- VectorCopy( parent->lightingOrigin, flash.lightingOrigin );
- flash.shadowPlane = parent->shadowPlane;
- flash.renderfx = parent->renderfx;
-
- flash.hModel = weapon->flashModel;
- if (!flash.hModel) {
- return;
- }
- angles[YAW] = 0;
- angles[PITCH] = 0;
- angles[ROLL] = crandom() * 10;
- AnglesToAxis( angles, flash.axis );
-
- // colorize the railgun blast
- if ( weaponNum == WP_RAILGUN ) {
- clientInfo_t *ci;
-
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- flash.shaderRGBA[0] = 255 * ci->color1[0];
- flash.shaderRGBA[1] = 255 * ci->color1[1];
- flash.shaderRGBA[2] = 255 * ci->color1[2];
- }
-
- CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash");
- trap_R_AddRefEntityToScene( &flash );
-
- if ( ps || cg.renderingThirdPerson ||
- cent->currentState.number != cg.predictedPlayerState.clientNum ) {
- // add lightning bolt
- CG_LightningBolt( nonPredictedCent, flash.origin );
-
- // add rail trail
- CG_SpawnRailTrail( cent, flash.origin );
-
- if ( weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2] ) {
- trap_R_AddLightToScene( flash.origin, 300 + (rand()&31), weapon->flashDlightColor[0],
- weapon->flashDlightColor[1], weapon->flashDlightColor[2] );
- }
- }
-}
-
-/*
-==============
-CG_AddViewWeapon
-
-Add the weapon, and flash for the player's view
-==============
-*/
-void CG_AddViewWeapon( playerState_t *ps ) {
- refEntity_t hand;
- centity_t *cent;
- clientInfo_t *ci;
- float fovOffset;
- vec3_t angles;
- weaponInfo_t *weapon;
-
- if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
- return;
- }
-
- if ( ps->pm_type == PM_INTERMISSION ) {
- return;
- }
-
- // no gun if in third person view or a camera is active
- //if ( cg.renderingThirdPerson || cg.cameraMode) {
- if ( cg.renderingThirdPerson ) {
- return;
- }
-
-
- // allow the gun to be completely removed
- if ( !cg_drawGun.integer ) {
- vec3_t origin;
-
- if ( cg.predictedPlayerState.eFlags & EF_FIRING ) {
- // special hack for lightning gun...
- VectorCopy( cg.refdef.vieworg, origin );
- VectorMA( origin, -8, cg.refdef.viewaxis[2], origin );
- CG_LightningBolt( &cg_entities[ps->clientNum], origin );
- }
- return;
- }
-
- // don't draw if testing a gun model
- if ( cg.testGun ) {
- return;
- }
-
- // drop gun lower at higher fov
- if ( cg_fov.integer > 90 ) {
- fovOffset = -0.2 * ( cg_fov.integer - 90 );
- } else {
- fovOffset = 0;
- }
-
- cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum];
- CG_RegisterWeapon( ps->weapon );
- weapon = &cg_weapons[ ps->weapon ];
-
- memset (&hand, 0, sizeof(hand));
-
- // set up gun position
- CG_CalculateWeaponPosition( hand.origin, angles );
-
- VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin );
- VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin );
- VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin );
-
- AnglesToAxis( angles, hand.axis );
-
- // map torso animations to weapon animations
- if ( cg_gun_frame.integer ) {
- // development tool
- hand.frame = hand.oldframe = cg_gun_frame.integer;
- hand.backlerp = 0;
- } else {
- // get clientinfo for animation map
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame );
- hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame );
- hand.backlerp = cent->pe.torso.backlerp;
- }
-
- hand.hModel = weapon->handsModel;
- hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT;
-
- // add everything onto the hand
- CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->persistant[PERS_TEAM] );
-}
-
-/*
-==============================================================================
-
-WEAPON SELECTION
-
-==============================================================================
-*/
-
-/*
-===================
-CG_DrawWeaponSelect
-===================
-*/
-void CG_DrawWeaponSelect( void ) {
- int i;
- int bits;
- int count;
- int x, y, w;
- char *name;
- float *color;
-
- // don't display if dead
- if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
- return;
- }
-
- color = CG_FadeColor( cg.weaponSelectTime, WEAPON_SELECT_TIME );
- if ( !color ) {
- return;
- }
- trap_R_SetColor( color );
-
- // showing weapon select clears pickup item display, but not the blend blob
- cg.itemPickupTime = 0;
-
- // count the number of weapons owned
- bits = cg.snap->ps.stats[ STAT_WEAPONS ];
- count = 0;
- for ( i = 1 ; i < MAX_WEAPONS ; i++ ) {
- if ( bits & ( 1 << i ) ) {
- count++;
- }
- }
-
- x = 320 - count * 20;
- y = 380;
-
- for ( i = 1 ; i < MAX_WEAPONS ; i++ ) {
- if ( !( bits & ( 1 << i ) ) ) {
- continue;
- }
-
- CG_RegisterWeapon( i );
-
- // draw weapon icon
- CG_DrawPic( x, y, 32, 32, cg_weapons[i].weaponIcon );
-
- // draw selection marker
- if ( i == cg.weaponSelect ) {
- CG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader );
- }
-
- // no ammo cross on top
- if ( !cg.snap->ps.ammo[ i ] ) {
- CG_DrawPic( x, y, 32, 32, cgs.media.noammoShader );
- }
-
- x += 40;
- }
-
- // draw the selected name
- if ( cg_weapons[ cg.weaponSelect ].item ) {
- name = cg_weapons[ cg.weaponSelect ].item->pickup_name;
- if ( name ) {
- w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH;
- x = ( SCREEN_WIDTH - w ) / 2;
- CG_DrawBigStringColor(x, y - 22, name, color);
- }
- }
-
- trap_R_SetColor( NULL );
-}
-
-
-/*
-===============
-CG_WeaponSelectable
-===============
-*/
-static qboolean CG_WeaponSelectable( int i ) {
- if ( !cg.snap->ps.ammo[i] ) {
- return qfalse;
- }
- if ( ! (cg.snap->ps.stats[ STAT_WEAPONS ] & ( 1 << i ) ) ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-===============
-CG_NextWeapon_f
-===============
-*/
-void CG_NextWeapon_f( void ) {
- int i;
- int original;
-
- if ( !cg.snap ) {
- return;
- }
- if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
- return;
- }
-
- cg.weaponSelectTime = cg.time;
- original = cg.weaponSelect;
-
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- cg.weaponSelect++;
- if ( cg.weaponSelect == MAX_WEAPONS ) {
- cg.weaponSelect = 0;
- }
- if ( cg.weaponSelect == WP_GAUNTLET ) {
- continue; // never cycle to gauntlet
- }
- if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
- break;
- }
- }
- if ( i == MAX_WEAPONS ) {
- cg.weaponSelect = original;
- }
-}
-
-/*
-===============
-CG_PrevWeapon_f
-===============
-*/
-void CG_PrevWeapon_f( void ) {
- int i;
- int original;
-
- if ( !cg.snap ) {
- return;
- }
- if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
- return;
- }
-
- cg.weaponSelectTime = cg.time;
- original = cg.weaponSelect;
-
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- cg.weaponSelect--;
- if ( cg.weaponSelect == -1 ) {
- cg.weaponSelect = MAX_WEAPONS - 1;
- }
- if ( cg.weaponSelect == WP_GAUNTLET ) {
- continue; // never cycle to gauntlet
- }
- if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
- break;
- }
- }
- if ( i == MAX_WEAPONS ) {
- cg.weaponSelect = original;
- }
-}
-
-/*
-===============
-CG_Weapon_f
-===============
-*/
-void CG_Weapon_f( void ) {
- int num;
-
- if ( !cg.snap ) {
- return;
- }
- if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
- return;
- }
-
- num = atoi( CG_Argv( 1 ) );
-
- if ( num < 1 || num > MAX_WEAPONS-1 ) {
- return;
- }
-
- cg.weaponSelectTime = cg.time;
-
- if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) ) {
- return; // don't have the weapon
- }
-
- cg.weaponSelect = num;
-}
-
-/*
-===================
-CG_OutOfAmmoChange
-
-The current weapon has just run out of ammo
-===================
-*/
-void CG_OutOfAmmoChange( void ) {
- int i;
-
- cg.weaponSelectTime = cg.time;
-
- for ( i = MAX_WEAPONS-1 ; i > 0 ; i-- ) {
- if ( CG_WeaponSelectable( i ) ) {
- cg.weaponSelect = i;
- break;
- }
- }
-}
-
-
-
-/*
-===================================================================================================
-
-WEAPON EVENTS
-
-===================================================================================================
-*/
-
-/*
-================
-CG_FireWeapon
-
-Caused by an EV_FIRE_WEAPON event
-================
-*/
-void CG_FireWeapon( centity_t *cent ) {
- entityState_t *ent;
- int c;
- weaponInfo_t *weap;
-
- ent = ¢->currentState;
- if ( ent->weapon == WP_NONE ) {
- return;
- }
- if ( ent->weapon >= WP_NUM_WEAPONS ) {
- CG_Error( "CG_FireWeapon: ent->weapon >= WP_NUM_WEAPONS" );
- return;
- }
- weap = &cg_weapons[ ent->weapon ];
-
- // mark the entity as muzzle flashing, so when it is added it will
- // append the flash to the weapon model
- cent->muzzleFlashTime = cg.time;
-
- // lightning gun only does this this on initial press
- if ( ent->weapon == WP_LIGHTNING ) {
- if ( cent->pe.lightningFiring ) {
- return;
- }
- }
-
- // play quad sound if needed
- if ( cent->currentState.powerups & ( 1 << PW_QUAD ) ) {
- trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.media.quadSound );
- }
-
- // play a sound
- for ( c = 0 ; c < 4 ; c++ ) {
- if ( !weap->flashSound[c] ) {
- break;
- }
- }
- if ( c > 0 ) {
- c = rand() % c;
- if ( weap->flashSound[c] )
- {
- trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound[c] );
- }
- }
-
- // do brass ejection
- if ( weap->ejectBrassFunc && cg_brassTime.integer > 0 ) {
- weap->ejectBrassFunc( cent );
- }
-}
-
-
-/*
-=================
-CG_MissileHitWall
-
-Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing
-=================
-*/
-void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType ) {
- qhandle_t mod;
- qhandle_t mark;
- qhandle_t shader;
- sfxHandle_t sfx;
- float radius;
- float light;
- vec3_t lightColor;
- localEntity_t *le;
- int r;
- qboolean alphaFade;
- qboolean isSprite;
- int duration;
- vec3_t sprOrg;
- vec3_t sprVel;
-
- mark = 0;
- radius = 32;
- sfx = 0;
- mod = 0;
- shader = 0;
- light = 0;
- lightColor[0] = 1;
- lightColor[1] = 1;
- lightColor[2] = 0;
-
- // set defaults
- isSprite = qfalse;
- duration = 600;
-
- switch ( weapon ) {
- default:
-#ifdef MISSIONPACK
- case WP_NAILGUN:
- if( soundType == IMPACTSOUND_FLESH ) {
- sfx = cgs.media.sfx_nghitflesh;
- } else if( soundType == IMPACTSOUND_METAL ) {
- sfx = cgs.media.sfx_nghitmetal;
- } else {
- sfx = cgs.media.sfx_nghit;
- }
- mark = cgs.media.holeMarkShader;
- radius = 12;
- break;
-#endif
- case WP_LIGHTNING:
- // no explosion at LG impact, it is added with the beam
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.sfx_lghit2;
- } else if ( r == 2 ) {
- sfx = cgs.media.sfx_lghit1;
- } else {
- sfx = cgs.media.sfx_lghit3;
- }
- mark = cgs.media.holeMarkShader;
- radius = 12;
- break;
-#ifdef MISSIONPACK
- case WP_PROX_LAUNCHER:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.grenadeExplosionShader;
- sfx = cgs.media.sfx_proxexp;
- mark = cgs.media.burnMarkShader;
- radius = 64;
- light = 300;
- isSprite = qtrue;
- break;
-#endif
- case WP_GRENADE_LAUNCHER:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.grenadeExplosionShader;
- sfx = cgs.media.sfx_rockexp;
- mark = cgs.media.burnMarkShader;
- radius = 64;
- light = 300;
- isSprite = qtrue;
- break;
- case WP_ROCKET_LAUNCHER:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.rocketExplosionShader;
- sfx = cgs.media.sfx_rockexp;
- mark = cgs.media.burnMarkShader;
- radius = 64;
- light = 300;
- isSprite = qtrue;
- duration = 1000;
- lightColor[0] = 1;
- lightColor[1] = 0.75;
- lightColor[2] = 0.0;
- if (cg_oldRocket.integer == 0) {
- // explosion sprite animation
- VectorMA( origin, 24, dir, sprOrg );
- VectorScale( dir, 64, sprVel );
-
- CG_ParticleExplosion( "explode1", sprOrg, sprVel, 1400, 20, 30 );
- }
- break;
- case WP_RAILGUN:
- mod = cgs.media.ringFlashModel;
- shader = cgs.media.railExplosionShader;
- sfx = cgs.media.sfx_plasmaexp;
- mark = cgs.media.energyMarkShader;
- radius = 24;
- break;
- case WP_PLASMAGUN:
- mod = cgs.media.ringFlashModel;
- shader = cgs.media.plasmaExplosionShader;
- sfx = cgs.media.sfx_plasmaexp;
- mark = cgs.media.energyMarkShader;
- radius = 16;
- break;
- case WP_BFG:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.bfgExplosionShader;
- sfx = cgs.media.sfx_rockexp;
- mark = cgs.media.burnMarkShader;
- radius = 32;
- isSprite = qtrue;
- break;
- case WP_SHOTGUN:
- mod = cgs.media.bulletFlashModel;
- shader = cgs.media.bulletExplosionShader;
- mark = cgs.media.bulletMarkShader;
- sfx = 0;
- radius = 4;
- break;
-
-#ifdef MISSIONPACK
- case WP_CHAINGUN:
- mod = cgs.media.bulletFlashModel;
- if( soundType == IMPACTSOUND_FLESH ) {
- sfx = cgs.media.sfx_chghitflesh;
- } else if( soundType == IMPACTSOUND_METAL ) {
- sfx = cgs.media.sfx_chghitmetal;
- } else {
- sfx = cgs.media.sfx_chghit;
- }
- mark = cgs.media.bulletMarkShader;
-
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.sfx_ric1;
- } else if ( r == 2 ) {
- sfx = cgs.media.sfx_ric2;
- } else {
- sfx = cgs.media.sfx_ric3;
- }
-
- radius = 8;
- break;
-#endif
-
- case WP_MACHINEGUN:
- mod = cgs.media.bulletFlashModel;
- shader = cgs.media.bulletExplosionShader;
- mark = cgs.media.bulletMarkShader;
-
- r = rand() & 3;
- if ( r == 0 ) {
- sfx = cgs.media.sfx_ric1;
- } else if ( r == 1 ) {
- sfx = cgs.media.sfx_ric2;
- } else {
- sfx = cgs.media.sfx_ric3;
- }
-
- radius = 8;
- break;
- }
-
- if ( sfx ) {
- trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, sfx );
- }
-
- //
- // create the explosion
- //
- if ( mod ) {
- le = CG_MakeExplosion( origin, dir,
- mod, shader,
- duration, isSprite );
- le->light = light;
- VectorCopy( lightColor, le->lightColor );
- if ( weapon == WP_RAILGUN ) {
- // colorize with client color
- VectorCopy( cgs.clientinfo[clientNum].color1, le->color );
- }
- }
-
- //
- // impact mark
- //
- alphaFade = (mark == cgs.media.energyMarkShader); // plasma fades alpha, all others fade color
- if ( weapon == WP_RAILGUN ) {
- float *color;
-
- // colorize with client color
- color = cgs.clientinfo[clientNum].color2;
- CG_ImpactMark( mark, origin, dir, random()*360, color[0],color[1], color[2],1, alphaFade, radius, qfalse );
- } else {
- CG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse );
- }
-}
-
-
-/*
-=================
-CG_MissileHitPlayer
-=================
-*/
-void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum ) {
- CG_Bleed( origin, entityNum );
-
- // some weapons will make an explosion with the blood, while
- // others will just make the blood
- switch ( weapon ) {
- case WP_GRENADE_LAUNCHER:
- case WP_ROCKET_LAUNCHER:
-#ifdef MISSIONPACK
- case WP_NAILGUN:
- case WP_CHAINGUN:
- case WP_PROX_LAUNCHER:
-#endif
- CG_MissileHitWall( weapon, 0, origin, dir, IMPACTSOUND_FLESH );
- break;
- default:
- break;
- }
-}
-
-
-
-/*
-============================================================================
-
-SHOTGUN TRACING
-
-============================================================================
-*/
-
-/*
-================
-CG_ShotgunPellet
-================
-*/
-static void CG_ShotgunPellet( vec3_t start, vec3_t end, int skipNum ) {
- trace_t tr;
- int sourceContentType, destContentType;
-
- CG_Trace( &tr, start, NULL, NULL, end, skipNum, MASK_SHOT );
-
- sourceContentType = trap_CM_PointContents( start, 0 );
- destContentType = trap_CM_PointContents( tr.endpos, 0 );
-
- // FIXME: should probably move this cruft into CG_BubbleTrail
- if ( sourceContentType == destContentType ) {
- if ( sourceContentType & CONTENTS_WATER ) {
- CG_BubbleTrail( start, tr.endpos, 32 );
- }
- } else if ( sourceContentType & CONTENTS_WATER ) {
- trace_t trace;
-
- trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( start, trace.endpos, 32 );
- } else if ( destContentType & CONTENTS_WATER ) {
- trace_t trace;
-
- trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( tr.endpos, trace.endpos, 32 );
- }
-
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- return;
- }
-
- if ( cg_entities[tr.entityNum].currentState.eType == ET_PLAYER ) {
- CG_MissileHitPlayer( WP_SHOTGUN, tr.endpos, tr.plane.normal, tr.entityNum );
- } else {
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- // SURF_NOIMPACT will not make a flame puff or a mark
- return;
- }
- if ( tr.surfaceFlags & SURF_METALSTEPS ) {
- CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL );
- } else {
- CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT );
- }
- }
-}
-
-/*
-================
-CG_ShotgunPattern
-
-Perform the same traces the server did to locate the
-hit splashes
-================
-*/
-static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) {
- int i;
- float r, u;
- vec3_t end;
- vec3_t forward, right, up;
-
- // derive the right and up vectors from the forward vector, because
- // the client won't have any other information
- VectorNormalize2( origin2, forward );
- PerpendicularVector( right, forward );
- CrossProduct( forward, right, up );
-
- // generate the "random" spread pattern
- for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {
- r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
- u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
- VectorMA( origin, 8192 * 16, forward, end);
- VectorMA (end, r, right, end);
- VectorMA (end, u, up, end);
-
- CG_ShotgunPellet( origin, end, otherEntNum );
- }
-}
-
-/*
-==============
-CG_ShotgunFire
-==============
-*/
-void CG_ShotgunFire( entityState_t *es ) {
- vec3_t v;
- int contents;
-
- VectorSubtract( es->origin2, es->pos.trBase, v );
- VectorNormalize( v );
- VectorScale( v, 32, v );
- VectorAdd( es->pos.trBase, v, v );
- if ( cgs.glconfig.hardwareType != GLHW_RAGEPRO ) {
- // ragepro can't alpha fade, so don't even bother with smoke
- vec3_t up;
-
- contents = trap_CM_PointContents( es->pos.trBase, 0 );
- if ( !( contents & CONTENTS_WATER ) ) {
- VectorSet( up, 0, 0, 8 );
- CG_SmokePuff( v, up, 32, 1, 1, 1, 0.33f, 900, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
- }
- }
- CG_ShotgunPattern( es->pos.trBase, es->origin2, es->eventParm, es->otherEntityNum );
-}
-
-/*
-============================================================================
-
-BULLETS
-
-============================================================================
-*/
-
-
-/*
-===============
-CG_Tracer
-===============
-*/
-void CG_Tracer( vec3_t source, vec3_t dest ) {
- vec3_t forward, right;
- polyVert_t verts[4];
- vec3_t line;
- float len, begin, end;
- vec3_t start, finish;
- vec3_t midpoint;
-
- // tracer
- VectorSubtract( dest, source, forward );
- len = VectorNormalize( forward );
-
- // start at least a little ways from the muzzle
- if ( len < 100 ) {
- return;
- }
- begin = 50 + random() * (len - 60);
- end = begin + cg_tracerLength.value;
- if ( end > len ) {
- end = len;
- }
- VectorMA( source, begin, forward, start );
- VectorMA( source, end, forward, finish );
-
- line[0] = DotProduct( forward, cg.refdef.viewaxis[1] );
- line[1] = DotProduct( forward, cg.refdef.viewaxis[2] );
-
- VectorScale( cg.refdef.viewaxis[1], line[1], right );
- VectorMA( right, -line[0], cg.refdef.viewaxis[2], right );
- VectorNormalize( right );
-
- VectorMA( finish, cg_tracerWidth.value, right, verts[0].xyz );
- verts[0].st[0] = 0;
- verts[0].st[1] = 1;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- VectorMA( finish, -cg_tracerWidth.value, right, verts[1].xyz );
- verts[1].st[0] = 1;
- verts[1].st[1] = 0;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- VectorMA( start, -cg_tracerWidth.value, right, verts[2].xyz );
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- VectorMA( start, cg_tracerWidth.value, right, verts[3].xyz );
- verts[3].st[0] = 0;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
-
- trap_R_AddPolyToScene( cgs.media.tracerShader, 4, verts );
-
- midpoint[0] = ( start[0] + finish[0] ) * 0.5;
- midpoint[1] = ( start[1] + finish[1] ) * 0.5;
- midpoint[2] = ( start[2] + finish[2] ) * 0.5;
-
- // add the tracer sound
- trap_S_StartSound( midpoint, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.tracerSound );
-
-}
-
-
-/*
-======================
-CG_CalcMuzzlePoint
-======================
-*/
-static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) {
- vec3_t forward;
- centity_t *cent;
- int anim;
-
- if ( entityNum == cg.snap->ps.clientNum ) {
- VectorCopy( cg.snap->ps.origin, muzzle );
- muzzle[2] += cg.snap->ps.viewheight;
- AngleVectors( cg.snap->ps.viewangles, forward, NULL, NULL );
- VectorMA( muzzle, 14, forward, muzzle );
- return qtrue;
- }
-
- cent = &cg_entities[entityNum];
- if ( !cent->currentValid ) {
- return qfalse;
- }
-
- VectorCopy( cent->currentState.pos.trBase, muzzle );
-
- AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL );
- anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
- if ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) {
- muzzle[2] += CROUCH_VIEWHEIGHT;
- } else {
- muzzle[2] += DEFAULT_VIEWHEIGHT;
- }
-
- VectorMA( muzzle, 14, forward, muzzle );
-
- return qtrue;
-
-}
-
-/*
-======================
-CG_Bullet
-
-Renders bullet effects.
-======================
-*/
-void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ) {
- trace_t trace;
- int sourceContentType, destContentType;
- vec3_t start;
-
- // if the shooter is currently valid, calc a source point and possibly
- // do trail effects
- if ( sourceEntityNum >= 0 && cg_tracerChance.value > 0 ) {
- if ( CG_CalcMuzzlePoint( sourceEntityNum, start ) ) {
- sourceContentType = trap_CM_PointContents( start, 0 );
- destContentType = trap_CM_PointContents( end, 0 );
-
- // do a complete bubble trail if necessary
- if ( ( sourceContentType == destContentType ) && ( sourceContentType & CONTENTS_WATER ) ) {
- CG_BubbleTrail( start, end, 32 );
- }
- // bubble trail from water into air
- else if ( ( sourceContentType & CONTENTS_WATER ) ) {
- trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( start, trace.endpos, 32 );
- }
- // bubble trail from air into water
- else if ( ( destContentType & CONTENTS_WATER ) ) {
- trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( trace.endpos, end, 32 );
- }
-
- // draw a tracer
- if ( random() < cg_tracerChance.value ) {
- CG_Tracer( start, end );
- }
- }
- }
-
- // impact splash and mark
- if ( flesh ) {
- CG_Bleed( end, fleshEntityNum );
- } else {
- CG_MissileHitWall( WP_MACHINEGUN, 0, end, normal, IMPACTSOUND_DEFAULT );
- }
-
-}
diff --git a/engine/code/client/cl_avi.c b/engine/code/client/cl_avi.c
deleted file mode 100644
index b03adea..0000000
--- a/engine/code/client/cl_avi.c
+++ /dev/null
@@ -1,671 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 2005-2006 Tim Angus
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "client.h"
-#include "snd_local.h"
-
-#define INDEX_FILE_EXTENSION ".index.dat"
-
-#define MAX_RIFF_CHUNKS 16
-
-typedef struct audioFormat_s
-{
- int rate;
- int format;
- int channels;
- int bits;
-
- int sampleSize;
- int totalBytes;
-} audioFormat_t;
-
-typedef struct aviFileData_s
-{
- qboolean fileOpen;
- fileHandle_t f;
- char fileName[ MAX_QPATH ];
- int fileSize;
- int moviOffset;
- int moviSize;
-
- fileHandle_t idxF;
- int numIndices;
-
- int frameRate;
- int framePeriod;
- int width, height;
- int numVideoFrames;
- int maxRecordSize;
- qboolean motionJpeg;
-
- qboolean audio;
- audioFormat_t a;
- int numAudioFrames;
-
- int chunkStack[ MAX_RIFF_CHUNKS ];
- int chunkStackTop;
-
- byte *cBuffer, *eBuffer;
-} aviFileData_t;
-
-static aviFileData_t afd;
-
-#define MAX_AVI_BUFFER 2048
-
-static byte buffer[ MAX_AVI_BUFFER ];
-static int bufIndex;
-
-/*
-===============
-SafeFS_Write
-===============
-*/
-static ID_INLINE void SafeFS_Write( const void *buffer, int len, fileHandle_t f )
-{
- if( FS_Write( buffer, len, f ) < len )
- Com_Error( ERR_DROP, "Failed to write avi file\n" );
-}
-
-/*
-===============
-WRITE_STRING
-===============
-*/
-static ID_INLINE void WRITE_STRING( const char *s )
-{
- Com_Memcpy( &buffer[ bufIndex ], s, strlen( s ) );
- bufIndex += strlen( s );
-}
-
-/*
-===============
-WRITE_4BYTES
-===============
-*/
-static ID_INLINE void WRITE_4BYTES( int x )
-{
- buffer[ bufIndex + 0 ] = (byte)( ( x >> 0 ) & 0xFF );
- buffer[ bufIndex + 1 ] = (byte)( ( x >> 8 ) & 0xFF );
- buffer[ bufIndex + 2 ] = (byte)( ( x >> 16 ) & 0xFF );
- buffer[ bufIndex + 3 ] = (byte)( ( x >> 24 ) & 0xFF );
- bufIndex += 4;
-}
-
-/*
-===============
-WRITE_2BYTES
-===============
-*/
-static ID_INLINE void WRITE_2BYTES( int x )
-{
- buffer[ bufIndex + 0 ] = (byte)( ( x >> 0 ) & 0xFF );
- buffer[ bufIndex + 1 ] = (byte)( ( x >> 8 ) & 0xFF );
- bufIndex += 2;
-}
-
-/*
-===============
-WRITE_1BYTES
-===============
-*/
-static ID_INLINE void WRITE_1BYTES( int x )
-{
- buffer[ bufIndex ] = x;
- bufIndex += 1;
-}
-
-/*
-===============
-START_CHUNK
-===============
-*/
-static ID_INLINE void START_CHUNK( const char *s )
-{
- if( afd.chunkStackTop == MAX_RIFF_CHUNKS )
- {
- Com_Error( ERR_DROP, "ERROR: Top of chunkstack breached\n" );
- }
-
- afd.chunkStack[ afd.chunkStackTop ] = bufIndex;
- afd.chunkStackTop++;
- WRITE_STRING( s );
- WRITE_4BYTES( 0 );
-}
-
-/*
-===============
-END_CHUNK
-===============
-*/
-static ID_INLINE void END_CHUNK( void )
-{
- int endIndex = bufIndex;
-
- if( afd.chunkStackTop <= 0 )
- {
- Com_Error( ERR_DROP, "ERROR: Bottom of chunkstack breached\n" );
- }
-
- afd.chunkStackTop--;
- bufIndex = afd.chunkStack[ afd.chunkStackTop ];
- bufIndex += 4;
- WRITE_4BYTES( endIndex - bufIndex - 4 );
- bufIndex = endIndex;
- bufIndex = PAD( bufIndex, 2 );
-}
-
-/*
-===============
-CL_WriteAVIHeader
-===============
-*/
-void CL_WriteAVIHeader( void )
-{
- bufIndex = 0;
- afd.chunkStackTop = 0;
-
- START_CHUNK( "RIFF" );
- {
- WRITE_STRING( "AVI " );
- {
- START_CHUNK( "LIST" );
- {
- WRITE_STRING( "hdrl" );
- WRITE_STRING( "avih" );
- WRITE_4BYTES( 56 ); //"avih" "chunk" size
- WRITE_4BYTES( afd.framePeriod ); //dwMicroSecPerFrame
- WRITE_4BYTES( afd.maxRecordSize *
- afd.frameRate ); //dwMaxBytesPerSec
- WRITE_4BYTES( 0 ); //dwReserved1
- WRITE_4BYTES( 0x110 ); //dwFlags bits HAS_INDEX and IS_INTERLEAVED
- WRITE_4BYTES( afd.numVideoFrames ); //dwTotalFrames
- WRITE_4BYTES( 0 ); //dwInitialFrame
-
- if( afd.audio ) //dwStreams
- WRITE_4BYTES( 2 );
- else
- WRITE_4BYTES( 1 );
-
- WRITE_4BYTES( afd.maxRecordSize ); //dwSuggestedBufferSize
- WRITE_4BYTES( afd.width ); //dwWidth
- WRITE_4BYTES( afd.height ); //dwHeight
- WRITE_4BYTES( 0 ); //dwReserved[ 0 ]
- WRITE_4BYTES( 0 ); //dwReserved[ 1 ]
- WRITE_4BYTES( 0 ); //dwReserved[ 2 ]
- WRITE_4BYTES( 0 ); //dwReserved[ 3 ]
-
- START_CHUNK( "LIST" );
- {
- WRITE_STRING( "strl" );
- WRITE_STRING( "strh" );
- WRITE_4BYTES( 56 ); //"strh" "chunk" size
- WRITE_STRING( "vids" );
-
- if( afd.motionJpeg )
- WRITE_STRING( "MJPG" );
- else
- WRITE_4BYTES( 0 ); // BI_RGB
-
- WRITE_4BYTES( 0 ); //dwFlags
- WRITE_4BYTES( 0 ); //dwPriority
- WRITE_4BYTES( 0 ); //dwInitialFrame
-
- WRITE_4BYTES( 1 ); //dwTimescale
- WRITE_4BYTES( afd.frameRate ); //dwDataRate
- WRITE_4BYTES( 0 ); //dwStartTime
- WRITE_4BYTES( afd.numVideoFrames ); //dwDataLength
-
- WRITE_4BYTES( afd.maxRecordSize ); //dwSuggestedBufferSize
- WRITE_4BYTES( -1 ); //dwQuality
- WRITE_4BYTES( 0 ); //dwSampleSize
- WRITE_2BYTES( 0 ); //rcFrame
- WRITE_2BYTES( 0 ); //rcFrame
- WRITE_2BYTES( afd.width ); //rcFrame
- WRITE_2BYTES( afd.height ); //rcFrame
-
- WRITE_STRING( "strf" );
- WRITE_4BYTES( 40 ); //"strf" "chunk" size
- WRITE_4BYTES( 40 ); //biSize
- WRITE_4BYTES( afd.width ); //biWidth
- WRITE_4BYTES( afd.height ); //biHeight
- WRITE_2BYTES( 1 ); //biPlanes
- WRITE_2BYTES( 24 ); //biBitCount
-
- if( afd.motionJpeg ) //biCompression
- {
- WRITE_STRING( "MJPG" );
- WRITE_4BYTES( afd.width *
- afd.height ); //biSizeImage
- }
- else
- {
- WRITE_4BYTES( 0 ); // BI_RGB
- WRITE_4BYTES( afd.width *
- afd.height * 3 ); //biSizeImage
- }
-
- WRITE_4BYTES( 0 ); //biXPelsPetMeter
- WRITE_4BYTES( 0 ); //biYPelsPetMeter
- WRITE_4BYTES( 0 ); //biClrUsed
- WRITE_4BYTES( 0 ); //biClrImportant
- }
- END_CHUNK( );
-
- if( afd.audio )
- {
- START_CHUNK( "LIST" );
- {
- WRITE_STRING( "strl" );
- WRITE_STRING( "strh" );
- WRITE_4BYTES( 56 ); //"strh" "chunk" size
- WRITE_STRING( "auds" );
- WRITE_4BYTES( 0 ); //FCC
- WRITE_4BYTES( 0 ); //dwFlags
- WRITE_4BYTES( 0 ); //dwPriority
- WRITE_4BYTES( 0 ); //dwInitialFrame
-
- WRITE_4BYTES( afd.a.sampleSize ); //dwTimescale
- WRITE_4BYTES( afd.a.sampleSize *
- afd.a.rate ); //dwDataRate
- WRITE_4BYTES( 0 ); //dwStartTime
- WRITE_4BYTES( afd.a.totalBytes /
- afd.a.sampleSize ); //dwDataLength
-
- WRITE_4BYTES( 0 ); //dwSuggestedBufferSize
- WRITE_4BYTES( -1 ); //dwQuality
- WRITE_4BYTES( afd.a.sampleSize ); //dwSampleSize
- WRITE_2BYTES( 0 ); //rcFrame
- WRITE_2BYTES( 0 ); //rcFrame
- WRITE_2BYTES( 0 ); //rcFrame
- WRITE_2BYTES( 0 ); //rcFrame
-
- WRITE_STRING( "strf" );
- WRITE_4BYTES( 18 ); //"strf" "chunk" size
- WRITE_2BYTES( afd.a.format ); //wFormatTag
- WRITE_2BYTES( afd.a.channels ); //nChannels
- WRITE_4BYTES( afd.a.rate ); //nSamplesPerSec
- WRITE_4BYTES( afd.a.sampleSize *
- afd.a.rate ); //nAvgBytesPerSec
- WRITE_2BYTES( afd.a.sampleSize ); //nBlockAlign
- WRITE_2BYTES( afd.a.bits ); //wBitsPerSample
- WRITE_2BYTES( 0 ); //cbSize
- }
- END_CHUNK( );
- }
- }
- END_CHUNK( );
-
- afd.moviOffset = bufIndex;
-
- START_CHUNK( "LIST" );
- {
- WRITE_STRING( "movi" );
- }
- }
- }
-}
-
-/*
-===============
-CL_OpenAVIForWriting
-
-Creates an AVI file and gets it into a state where
-writing the actual data can begin
-===============
-*/
-qboolean CL_OpenAVIForWriting( const char *fileName )
-{
- if( afd.fileOpen )
- return qfalse;
-
- Com_Memset( &afd, 0, sizeof( aviFileData_t ) );
-
- // Don't start if a framerate has not been chosen
- if( cl_aviFrameRate->integer <= 0 )
- {
- Com_Printf( S_COLOR_RED "cl_aviFrameRate must be >= 1\n" );
- return qfalse;
- }
-
- if( ( afd.f = FS_FOpenFileWrite( fileName ) ) <= 0 )
- return qfalse;
-
- if( ( afd.idxF = FS_FOpenFileWrite(
- va( "%s" INDEX_FILE_EXTENSION, fileName ) ) ) <= 0 )
- {
- FS_FCloseFile( afd.f );
- return qfalse;
- }
-
- Q_strncpyz( afd.fileName, fileName, MAX_QPATH );
-
- afd.frameRate = cl_aviFrameRate->integer;
- afd.framePeriod = (int)( 1000000.0f / afd.frameRate );
- afd.width = cls.glconfig.vidWidth;
- afd.height = cls.glconfig.vidHeight;
-
- if( cl_aviMotionJpeg->integer )
- afd.motionJpeg = qtrue;
- else
- afd.motionJpeg = qfalse;
-
- afd.cBuffer = Z_Malloc( afd.width * afd.height * 4 );
- afd.eBuffer = Z_Malloc( afd.width * afd.height * 4 );
-
- afd.a.rate = dma.speed;
- afd.a.format = WAV_FORMAT_PCM;
- afd.a.channels = dma.channels;
- afd.a.bits = dma.samplebits;
- afd.a.sampleSize = ( afd.a.bits / 8 ) * afd.a.channels;
-
- if( afd.a.rate % afd.frameRate )
- {
- int suggestRate = afd.frameRate;
-
- while( ( afd.a.rate % suggestRate ) && suggestRate >= 1 )
- suggestRate--;
-
- Com_Printf( S_COLOR_YELLOW "WARNING: cl_aviFrameRate is not a divisor "
- "of the audio rate, suggest %d\n", suggestRate );
- }
-
- if( !Cvar_VariableIntegerValue( "s_initsound" ) )
- {
- afd.audio = qfalse;
- }
- else if( Q_stricmp( Cvar_VariableString( "s_backend" ), "OpenAL" ) )
- {
- if( afd.a.bits != 16 || afd.a.channels != 2 )
- {
- Com_Printf( S_COLOR_YELLOW "WARNING: Audio format of %d bit/%d channels not supported",
- afd.a.bits, afd.a.channels );
- afd.audio = qfalse;
- }
- else
- afd.audio = qtrue;
- }
- else
- {
- afd.audio = qfalse;
- Com_Printf( S_COLOR_YELLOW "WARNING: Audio capture is not supported "
- "with OpenAL. Set s_useOpenAL to 0 for audio capture\n" );
- }
-
- // This doesn't write a real header, but allocates the
- // correct amount of space at the beginning of the file
- CL_WriteAVIHeader( );
-
- SafeFS_Write( buffer, bufIndex, afd.f );
- afd.fileSize = bufIndex;
-
- bufIndex = 0;
- START_CHUNK( "idx1" );
- SafeFS_Write( buffer, bufIndex, afd.idxF );
-
- afd.moviSize = 4; // For the "movi"
- afd.fileOpen = qtrue;
-
- return qtrue;
-}
-
-/*
-===============
-CL_CheckFileSize
-===============
-*/
-static qboolean CL_CheckFileSize( int bytesToAdd )
-{
- unsigned int newFileSize;
-
- newFileSize =
- afd.fileSize + // Current file size
- bytesToAdd + // What we want to add
- ( afd.numIndices * 16 ) + // The index
- 4; // The index size
-
- // I assume all the operating systems
- // we target can handle a 2Gb file
- if( newFileSize > INT_MAX )
- {
- // Close the current file...
- CL_CloseAVI( );
-
- // ...And open a new one
- CL_OpenAVIForWriting( va( "%s_", afd.fileName ) );
-
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-===============
-CL_WriteAVIVideoFrame
-===============
-*/
-void CL_WriteAVIVideoFrame( const byte *imageBuffer, int size )
-{
- int chunkOffset = afd.fileSize - afd.moviOffset - 8;
- int chunkSize = 8 + size;
- int paddingSize = PAD( size, 2 ) - size;
- byte padding[ 4 ] = { 0 };
-
- if( !afd.fileOpen )
- return;
-
- // Chunk header + contents + padding
- if( CL_CheckFileSize( 8 + size + 2 ) )
- return;
-
- bufIndex = 0;
- WRITE_STRING( "00dc" );
- WRITE_4BYTES( size );
-
- SafeFS_Write( buffer, 8, afd.f );
- SafeFS_Write( imageBuffer, size, afd.f );
- SafeFS_Write( padding, paddingSize, afd.f );
- afd.fileSize += ( chunkSize + paddingSize );
-
- afd.numVideoFrames++;
- afd.moviSize += ( chunkSize + paddingSize );
-
- if( size > afd.maxRecordSize )
- afd.maxRecordSize = size;
-
- // Index
- bufIndex = 0;
- WRITE_STRING( "00dc" ); //dwIdentifier
- WRITE_4BYTES( 0x00000010 ); //dwFlags (all frames are KeyFrames)
- WRITE_4BYTES( chunkOffset ); //dwOffset
- WRITE_4BYTES( size ); //dwLength
- SafeFS_Write( buffer, 16, afd.idxF );
-
- afd.numIndices++;
-}
-
-#define PCM_BUFFER_SIZE 44100
-
-/*
-===============
-CL_WriteAVIAudioFrame
-===============
-*/
-void CL_WriteAVIAudioFrame( const byte *pcmBuffer, int size )
-{
- static byte pcmCaptureBuffer[ PCM_BUFFER_SIZE ] = { 0 };
- static int bytesInBuffer = 0;
-
- if( !afd.audio )
- return;
-
- if( !afd.fileOpen )
- return;
-
- // Chunk header + contents + padding
- if( CL_CheckFileSize( 8 + bytesInBuffer + size + 2 ) )
- return;
-
- if( bytesInBuffer + size > PCM_BUFFER_SIZE )
- {
- Com_Printf( S_COLOR_YELLOW
- "WARNING: Audio capture buffer overflow -- truncating\n" );
- size = PCM_BUFFER_SIZE - bytesInBuffer;
- }
-
- Com_Memcpy( &pcmCaptureBuffer[ bytesInBuffer ], pcmBuffer, size );
- bytesInBuffer += size;
-
- // Only write if we have a frame's worth of audio
- if( bytesInBuffer >= (int)ceil( (float)afd.a.rate / (float)afd.frameRate ) *
- afd.a.sampleSize )
- {
- int chunkOffset = afd.fileSize - afd.moviOffset - 8;
- int chunkSize = 8 + bytesInBuffer;
- int paddingSize = PAD( bytesInBuffer, 2 ) - bytesInBuffer;
- byte padding[ 4 ] = { 0 };
-
- bufIndex = 0;
- WRITE_STRING( "01wb" );
- WRITE_4BYTES( bytesInBuffer );
-
- SafeFS_Write( buffer, 8, afd.f );
- SafeFS_Write( pcmCaptureBuffer, bytesInBuffer, afd.f );
- SafeFS_Write( padding, paddingSize, afd.f );
- afd.fileSize += ( chunkSize + paddingSize );
-
- afd.numAudioFrames++;
- afd.moviSize += ( chunkSize + paddingSize );
- afd.a.totalBytes += bytesInBuffer;
-
- // Index
- bufIndex = 0;
- WRITE_STRING( "01wb" ); //dwIdentifier
- WRITE_4BYTES( 0 ); //dwFlags
- WRITE_4BYTES( chunkOffset ); //dwOffset
- WRITE_4BYTES( bytesInBuffer ); //dwLength
- SafeFS_Write( buffer, 16, afd.idxF );
-
- afd.numIndices++;
-
- bytesInBuffer = 0;
- }
-}
-
-/*
-===============
-CL_TakeVideoFrame
-===============
-*/
-void CL_TakeVideoFrame( void )
-{
- // AVI file isn't open
- if( !afd.fileOpen )
- return;
-
- re.TakeVideoFrame( afd.width, afd.height,
- afd.cBuffer, afd.eBuffer, afd.motionJpeg );
-}
-
-/*
-===============
-CL_CloseAVI
-
-Closes the AVI file and writes an index chunk
-===============
-*/
-qboolean CL_CloseAVI( void )
-{
- int indexRemainder;
- int indexSize = afd.numIndices * 16;
- const char *idxFileName = va( "%s" INDEX_FILE_EXTENSION, afd.fileName );
-
- // AVI file isn't open
- if( !afd.fileOpen )
- return qfalse;
-
- afd.fileOpen = qfalse;
-
- FS_Seek( afd.idxF, 4, FS_SEEK_SET );
- bufIndex = 0;
- WRITE_4BYTES( indexSize );
- SafeFS_Write( buffer, bufIndex, afd.idxF );
- FS_FCloseFile( afd.idxF );
-
- // Write index
-
- // Open the temp index file
- if( ( indexSize = FS_FOpenFileRead( idxFileName,
- &afd.idxF, qtrue ) ) <= 0 )
- {
- FS_FCloseFile( afd.f );
- return qfalse;
- }
-
- indexRemainder = indexSize;
-
- // Append index to end of avi file
- while( indexRemainder > MAX_AVI_BUFFER )
- {
- FS_Read( buffer, MAX_AVI_BUFFER, afd.idxF );
- SafeFS_Write( buffer, MAX_AVI_BUFFER, afd.f );
- afd.fileSize += MAX_AVI_BUFFER;
- indexRemainder -= MAX_AVI_BUFFER;
- }
- FS_Read( buffer, indexRemainder, afd.idxF );
- SafeFS_Write( buffer, indexRemainder, afd.f );
- afd.fileSize += indexRemainder;
- FS_FCloseFile( afd.idxF );
-
- // Remove temp index file
- FS_HomeRemove( idxFileName );
-
- // Write the real header
- FS_Seek( afd.f, 0, FS_SEEK_SET );
- CL_WriteAVIHeader( );
-
- bufIndex = 4;
- WRITE_4BYTES( afd.fileSize - 8 ); // "RIFF" size
-
- bufIndex = afd.moviOffset + 4; // Skip "LIST"
- WRITE_4BYTES( afd.moviSize );
-
- SafeFS_Write( buffer, bufIndex, afd.f );
-
- Z_Free( afd.cBuffer );
- Z_Free( afd.eBuffer );
- FS_FCloseFile( afd.f );
-
- Com_Printf( "Wrote %d:%d frames to %s\n", afd.numVideoFrames, afd.numAudioFrames, afd.fileName );
-
- return qtrue;
-}
-
-/*
-===============
-CL_VideoRecording
-===============
-*/
-qboolean CL_VideoRecording( void )
-{
- return afd.fileOpen;
-}
diff --git a/engine/code/client/cl_cgame.c b/engine/code/client/cl_cgame.c
deleted file mode 100644
index 3c351a1..0000000
--- a/engine/code/client/cl_cgame.c
+++ /dev/null
@@ -1,1105 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// cl_cgame.c -- client system interaction with client game
-
-#include "client.h"
-
-#include "../botlib/botlib.h"
-
-#include "libmumblelink.h"
-
-extern botlib_export_t *botlib_export;
-
-extern qboolean loadCamera(const char *name);
-extern void startCamera(int time);
-extern qboolean getCameraInfo(int time, vec3_t *origin, vec3_t *angles);
-
-/*
-====================
-CL_GetGameState
-====================
-*/
-void CL_GetGameState( gameState_t *gs ) {
- *gs = cl.gameState;
-}
-
-/*
-====================
-CL_GetGlconfig
-====================
-*/
-void CL_GetGlconfig( glconfig_t *glconfig ) {
- *glconfig = cls.glconfig;
-}
-
-
-/*
-====================
-CL_GetUserCmd
-====================
-*/
-qboolean CL_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) {
- // cmds[cmdNumber] is the last properly generated command
-
- // can't return anything that we haven't created yet
- if ( cmdNumber > cl.cmdNumber ) {
- Com_Error( ERR_DROP, "CL_GetUserCmd: %i >= %i", cmdNumber, cl.cmdNumber );
- }
-
- // the usercmd has been overwritten in the wrapping
- // buffer because it is too far out of date
- if ( cmdNumber <= cl.cmdNumber - CMD_BACKUP ) {
- return qfalse;
- }
-
- *ucmd = cl.cmds[ cmdNumber & CMD_MASK ];
-
- return qtrue;
-}
-
-int CL_GetCurrentCmdNumber( void ) {
- return cl.cmdNumber;
-}
-
-
-/*
-====================
-CL_GetParseEntityState
-====================
-*/
-qboolean CL_GetParseEntityState( int parseEntityNumber, entityState_t *state ) {
- // can't return anything that hasn't been parsed yet
- if ( parseEntityNumber >= cl.parseEntitiesNum ) {
- Com_Error( ERR_DROP, "CL_GetParseEntityState: %i >= %i",
- parseEntityNumber, cl.parseEntitiesNum );
- }
-
- // can't return anything that has been overwritten in the circular buffer
- if ( parseEntityNumber <= cl.parseEntitiesNum - MAX_PARSE_ENTITIES ) {
- return qfalse;
- }
-
- *state = cl.parseEntities[ parseEntityNumber & ( MAX_PARSE_ENTITIES - 1 ) ];
- return qtrue;
-}
-
-/*
-====================
-CL_GetCurrentSnapshotNumber
-====================
-*/
-void CL_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) {
- *snapshotNumber = cl.snap.messageNum;
- *serverTime = cl.snap.serverTime;
-}
-
-/*
-====================
-CL_GetSnapshot
-====================
-*/
-qboolean CL_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {
- clSnapshot_t *clSnap;
- int i, count;
-
- if ( snapshotNumber > cl.snap.messageNum ) {
- Com_Error( ERR_DROP, "CL_GetSnapshot: snapshotNumber > cl.snapshot.messageNum" );
- }
-
- // if the frame has fallen out of the circular buffer, we can't return it
- if ( cl.snap.messageNum - snapshotNumber >= PACKET_BACKUP ) {
- return qfalse;
- }
-
- // if the frame is not valid, we can't return it
- clSnap = &cl.snapshots[snapshotNumber & PACKET_MASK];
- if ( !clSnap->valid ) {
- return qfalse;
- }
-
- // if the entities in the frame have fallen out of their
- // circular buffer, we can't return it
- if ( cl.parseEntitiesNum - clSnap->parseEntitiesNum >= MAX_PARSE_ENTITIES ) {
- return qfalse;
- }
-
- // write the snapshot
- snapshot->snapFlags = clSnap->snapFlags;
- snapshot->serverCommandSequence = clSnap->serverCommandNum;
- snapshot->ping = clSnap->ping;
- snapshot->serverTime = clSnap->serverTime;
- Com_Memcpy( snapshot->areamask, clSnap->areamask, sizeof( snapshot->areamask ) );
- snapshot->ps = clSnap->ps;
- count = clSnap->numEntities;
- if ( count > MAX_ENTITIES_IN_SNAPSHOT ) {
- Com_DPrintf( "CL_GetSnapshot: truncated %i entities to %i\n", count, MAX_ENTITIES_IN_SNAPSHOT );
- count = MAX_ENTITIES_IN_SNAPSHOT;
- }
- snapshot->numEntities = count;
- for ( i = 0 ; i < count ; i++ ) {
- snapshot->entities[i] =
- cl.parseEntities[ ( clSnap->parseEntitiesNum + i ) & (MAX_PARSE_ENTITIES-1) ];
- }
-
- // FIXME: configstring changes and server commands!!!
-
- return qtrue;
-}
-
-/*
-=====================
-CL_SetUserCmdValue
-=====================
-*/
-void CL_SetUserCmdValue( int userCmdValue, float sensitivityScale ) {
- cl.cgameUserCmdValue = userCmdValue;
- cl.cgameSensitivity = sensitivityScale;
-}
-
-/*
-=====================
-CL_AddCgameCommand
-=====================
-*/
-void CL_AddCgameCommand( const char *cmdName ) {
- Cmd_AddCommand( cmdName, NULL );
-}
-
-/*
-=====================
-CL_CgameError
-=====================
-*/
-void CL_CgameError( const char *string ) {
- Com_Error( ERR_DROP, "%s", string );
-}
-
-
-/*
-=====================
-CL_ConfigstringModified
-=====================
-*/
-void CL_ConfigstringModified( void ) {
- char *old, *s;
- int i, index;
- char *dup;
- gameState_t oldGs;
- int len;
-
- index = atoi( Cmd_Argv(1) );
- if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
- Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" );
- }
- // get everything after "cs <num>"
- s = Cmd_ArgsFrom(2);
-
- old = cl.gameState.stringData + cl.gameState.stringOffsets[ index ];
- if ( !strcmp( old, s ) ) {
- return; // unchanged
- }
-
- // build the new gameState_t
- oldGs = cl.gameState;
-
- Com_Memset( &cl.gameState, 0, sizeof( cl.gameState ) );
-
- // leave the first 0 for uninitialized strings
- cl.gameState.dataCount = 1;
-
- for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
- if ( i == index ) {
- dup = s;
- } else {
- dup = oldGs.stringData + oldGs.stringOffsets[ i ];
- }
- if ( !dup[0] ) {
- continue; // leave with the default empty string
- }
-
- len = strlen( dup );
-
- if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {
- Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" );
- }
-
- // append it to the gameState string buffer
- cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;
- Com_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, dup, len + 1 );
- cl.gameState.dataCount += len + 1;
- }
-
- if ( index == CS_SYSTEMINFO ) {
- // parse serverId and other cvars
- CL_SystemInfoChanged();
- }
-
-}
-
-
-/*
-===================
-CL_GetServerCommand
-
-Set up argc/argv for the given command
-===================
-*/
-qboolean CL_GetServerCommand( int serverCommandNumber ) {
- char *s;
- char *cmd;
- static char bigConfigString[BIG_INFO_STRING];
- int argc;
-
- // if we have irretrievably lost a reliable command, drop the connection
- if ( serverCommandNumber <= clc.serverCommandSequence - MAX_RELIABLE_COMMANDS ) {
- // when a demo record was started after the client got a whole bunch of
- // reliable commands then the client never got those first reliable commands
- if ( clc.demoplaying )
- return qfalse;
- Com_Error( ERR_DROP, "CL_GetServerCommand: a reliable command was cycled out" );
- return qfalse;
- }
-
- if ( serverCommandNumber > clc.serverCommandSequence ) {
- Com_Error( ERR_DROP, "CL_GetServerCommand: requested a command not received" );
- return qfalse;
- }
-
- s = clc.serverCommands[ serverCommandNumber & ( MAX_RELIABLE_COMMANDS - 1 ) ];
- clc.lastExecutedServerCommand = serverCommandNumber;
-
- Com_DPrintf( "serverCommand: %i : %s\n", serverCommandNumber, s );
-
-rescan:
- Cmd_TokenizeString( s );
- cmd = Cmd_Argv(0);
- argc = Cmd_Argc();
-
- if ( !strcmp( cmd, "disconnect" ) ) {
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=552
- // allow server to indicate why they were disconnected
- if ( argc >= 2 )
- Com_Error( ERR_SERVERDISCONNECT, "Server disconnected - %s", Cmd_Argv( 1 ) );
- else
- Com_Error( ERR_SERVERDISCONNECT, "Server disconnected\n" );
- }
-
- if ( !strcmp( cmd, "bcs0" ) ) {
- Com_sprintf( bigConfigString, BIG_INFO_STRING, "cs %s \"%s", Cmd_Argv(1), Cmd_Argv(2) );
- return qfalse;
- }
-
- if ( !strcmp( cmd, "bcs1" ) ) {
- s = Cmd_Argv(2);
- if( strlen(bigConfigString) + strlen(s) >= BIG_INFO_STRING ) {
- Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" );
- }
- strcat( bigConfigString, s );
- return qfalse;
- }
-
- if ( !strcmp( cmd, "bcs2" ) ) {
- s = Cmd_Argv(2);
- if( strlen(bigConfigString) + strlen(s) + 1 >= BIG_INFO_STRING ) {
- Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" );
- }
- strcat( bigConfigString, s );
- strcat( bigConfigString, "\"" );
- s = bigConfigString;
- goto rescan;
- }
-
- if ( !strcmp( cmd, "cs" ) ) {
- CL_ConfigstringModified();
- // reparse the string, because CL_ConfigstringModified may have done another Cmd_TokenizeString()
- Cmd_TokenizeString( s );
- return qtrue;
- }
-
- if ( !strcmp( cmd, "map_restart" ) ) {
- // clear notify lines and outgoing commands before passing
- // the restart to the cgame
- Con_ClearNotify();
- // reparse the string, because Con_ClearNotify() may have done another Cmd_TokenizeString()
- Cmd_TokenizeString( s );
- Com_Memset( cl.cmds, 0, sizeof( cl.cmds ) );
- return qtrue;
- }
-
- // the clientLevelShot command is used during development
- // to generate 128*128 screenshots from the intermission
- // point of levels for the menu system to use
- // we pass it along to the cgame to make apropriate adjustments,
- // but we also clear the console and notify lines here
- if ( !strcmp( cmd, "clientLevelShot" ) ) {
- // don't do it if we aren't running the server locally,
- // otherwise malicious remote servers could overwrite
- // the existing thumbnails
- if ( !com_sv_running->integer ) {
- return qfalse;
- }
- // close the console
- Con_Close();
- // take a special screenshot next frame
- Cbuf_AddText( "wait ; wait ; wait ; wait ; screenshot levelshot\n" );
- return qtrue;
- }
-
- // we may want to put a "connect to other server" command here
-
- // cgame can now act on the command
- return qtrue;
-}
-
-
-/*
-====================
-CL_CM_LoadMap
-
-Just adds default parameters that cgame doesn't need to know about
-====================
-*/
-void CL_CM_LoadMap( const char *mapname ) {
- int checksum;
-
- CM_LoadMap( mapname, qtrue, &checksum );
-}
-
-/*
-====================
-CL_ShutdonwCGame
-
-====================
-*/
-void CL_ShutdownCGame( void ) {
- Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CGAME );
- cls.cgameStarted = qfalse;
- if ( !cgvm ) {
- return;
- }
- VM_Call( cgvm, CG_SHUTDOWN );
- VM_Free( cgvm );
- cgvm = NULL;
-}
-
-static int FloatAsInt( float f ) {
- floatint_t fi;
- fi.f = f;
- return fi.i;
-}
-
-/*
-====================
-CL_CgameSystemCalls
-
-The cgame module is making a system call
-====================
-*/
-intptr_t CL_CgameSystemCalls( intptr_t *args ) {
- switch( args[0] ) {
- case CG_PRINT:
- Com_Printf( "%s", (const char*)VMA(1) );
- return 0;
- case CG_ERROR:
- Com_Error( ERR_DROP, "%s", (const char*)VMA(1) );
- return 0;
- case CG_MILLISECONDS:
- return Sys_Milliseconds();
- case CG_CVAR_REGISTER:
- Cvar_Register( VMA(1), VMA(2), VMA(3), args[4] );
- return 0;
- case CG_CVAR_UPDATE:
- Cvar_Update( VMA(1) );
- return 0;
- case CG_CVAR_SET:
- Cvar_Set( VMA(1), VMA(2) );
- return 0;
- case CG_CVAR_VARIABLESTRINGBUFFER:
- Cvar_VariableStringBuffer( VMA(1), VMA(2), args[3] );
- return 0;
- case CG_ARGC:
- return Cmd_Argc();
- case CG_ARGV:
- Cmd_ArgvBuffer( args[1], VMA(2), args[3] );
- return 0;
- case CG_ARGS:
- Cmd_ArgsBuffer( VMA(1), args[2] );
- return 0;
- case CG_FS_FOPENFILE:
- return FS_FOpenFileByMode( VMA(1), VMA(2), args[3] );
- case CG_FS_READ:
- FS_Read2( VMA(1), args[2], args[3] );
- return 0;
- case CG_FS_WRITE:
- FS_Write( VMA(1), args[2], args[3] );
- return 0;
- case CG_FS_FCLOSEFILE:
- FS_FCloseFile( args[1] );
- return 0;
- case CG_FS_SEEK:
- return FS_Seek( args[1], args[2], args[3] );
- case CG_SENDCONSOLECOMMAND:
- Cbuf_AddText( VMA(1) );
- return 0;
- case CG_ADDCOMMAND:
- CL_AddCgameCommand( VMA(1) );
- return 0;
- case CG_REMOVECOMMAND:
- Cmd_RemoveCommand( VMA(1) );
- return 0;
- case CG_SENDCLIENTCOMMAND:
- CL_AddReliableCommand(VMA(1), qfalse);
- return 0;
- case CG_UPDATESCREEN:
- // this is used during lengthy level loading, so pump message loop
-// Com_EventLoop(); // FIXME: if a server restarts here, BAD THINGS HAPPEN!
-// We can't call Com_EventLoop here, a restart will crash and this _does_ happen
-// if there is a map change while we are downloading at pk3.
-// ZOID
- SCR_UpdateScreen();
- return 0;
- case CG_CM_LOADMAP:
- CL_CM_LoadMap( VMA(1) );
- return 0;
- case CG_CM_NUMINLINEMODELS:
- return CM_NumInlineModels();
- case CG_CM_INLINEMODEL:
- return CM_InlineModel( args[1] );
- case CG_CM_TEMPBOXMODEL:
- return CM_TempBoxModel( VMA(1), VMA(2), /*int capsule*/ qfalse );
- case CG_CM_TEMPCAPSULEMODEL:
- return CM_TempBoxModel( VMA(1), VMA(2), /*int capsule*/ qtrue );
- case CG_CM_POINTCONTENTS:
- return CM_PointContents( VMA(1), args[2] );
- case CG_CM_TRANSFORMEDPOINTCONTENTS:
- return CM_TransformedPointContents( VMA(1), args[2], VMA(3), VMA(4) );
- case CG_CM_BOXTRACE:
- CM_BoxTrace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], /*int capsule*/ qfalse );
- return 0;
- case CG_CM_CAPSULETRACE:
- CM_BoxTrace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], /*int capsule*/ qtrue );
- return 0;
- case CG_CM_TRANSFORMEDBOXTRACE:
- CM_TransformedBoxTrace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], VMA(8), VMA(9), /*int capsule*/ qfalse );
- return 0;
- case CG_CM_TRANSFORMEDCAPSULETRACE:
- CM_TransformedBoxTrace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], VMA(8), VMA(9), /*int capsule*/ qtrue );
- return 0;
- case CG_CM_MARKFRAGMENTS:
- return re.MarkFragments( args[1], VMA(2), VMA(3), args[4], VMA(5), args[6], VMA(7) );
- case CG_S_STARTSOUND:
- S_StartSound( VMA(1), args[2], args[3], args[4] );
- return 0;
- case CG_S_STARTLOCALSOUND:
- S_StartLocalSound( args[1], args[2] );
- return 0;
- case CG_S_CLEARLOOPINGSOUNDS:
- S_ClearLoopingSounds(args[1]);
- return 0;
- case CG_S_ADDLOOPINGSOUND:
- S_AddLoopingSound( args[1], VMA(2), VMA(3), args[4] );
- return 0;
- case CG_S_ADDREALLOOPINGSOUND:
- S_AddRealLoopingSound( args[1], VMA(2), VMA(3), args[4] );
- return 0;
- case CG_S_STOPLOOPINGSOUND:
- S_StopLoopingSound( args[1] );
- return 0;
- case CG_S_UPDATEENTITYPOSITION:
- S_UpdateEntityPosition( args[1], VMA(2) );
- return 0;
- case CG_S_RESPATIALIZE:
- S_Respatialize( args[1], VMA(2), VMA(3), args[4] );
- return 0;
- case CG_S_REGISTERSOUND:
- return S_RegisterSound( VMA(1), args[2] );
- case CG_S_STARTBACKGROUNDTRACK:
- S_StartBackgroundTrack( VMA(1), VMA(2) );
- return 0;
- case CG_R_LOADWORLDMAP:
- re.LoadWorld( VMA(1) );
- return 0;
- case CG_R_REGISTERMODEL:
- return re.RegisterModel( VMA(1) );
- case CG_R_REGISTERSKIN:
- return re.RegisterSkin( VMA(1) );
- case CG_R_REGISTERSHADER:
- return re.RegisterShader( VMA(1) );
- case CG_R_REGISTERSHADERNOMIP:
- return re.RegisterShaderNoMip( VMA(1) );
- case CG_R_REGISTERFONT:
- re.RegisterFont( VMA(1), args[2], VMA(3));
- case CG_R_CLEARSCENE:
- re.ClearScene();
- return 0;
- case CG_R_ADDREFENTITYTOSCENE:
- re.AddRefEntityToScene( VMA(1) );
- return 0;
- case CG_R_ADDPOLYTOSCENE:
- re.AddPolyToScene( args[1], args[2], VMA(3), 1 );
- return 0;
- case CG_R_ADDPOLYSTOSCENE:
- re.AddPolyToScene( args[1], args[2], VMA(3), args[4] );
- return 0;
- case CG_R_LIGHTFORPOINT:
- return re.LightForPoint( VMA(1), VMA(2), VMA(3), VMA(4) );
- case CG_R_ADDLIGHTTOSCENE:
- re.AddLightToScene( VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) );
- return 0;
- case CG_R_ADDADDITIVELIGHTTOSCENE:
- re.AddAdditiveLightToScene( VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) );
- return 0;
- case CG_R_RENDERSCENE:
- re.RenderScene( VMA(1) );
- return 0;
- case CG_R_SETCOLOR:
- re.SetColor( VMA(1) );
- return 0;
- case CG_R_DRAWSTRETCHPIC:
- re.DrawStretchPic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), args[9] );
- return 0;
- case CG_R_MODELBOUNDS:
- re.ModelBounds( args[1], VMA(2), VMA(3) );
- return 0;
- case CG_R_LERPTAG:
- return re.LerpTag( VMA(1), args[2], args[3], args[4], VMF(5), VMA(6) );
- case CG_GETGLCONFIG:
- CL_GetGlconfig( VMA(1) );
- return 0;
- case CG_GETGAMESTATE:
- CL_GetGameState( VMA(1) );
- return 0;
- case CG_GETCURRENTSNAPSHOTNUMBER:
- CL_GetCurrentSnapshotNumber( VMA(1), VMA(2) );
- return 0;
- case CG_GETSNAPSHOT:
- return CL_GetSnapshot( args[1], VMA(2) );
- case CG_GETSERVERCOMMAND:
- return CL_GetServerCommand( args[1] );
- case CG_GETCURRENTCMDNUMBER:
- return CL_GetCurrentCmdNumber();
- case CG_GETUSERCMD:
- return CL_GetUserCmd( args[1], VMA(2) );
- case CG_SETUSERCMDVALUE:
- CL_SetUserCmdValue( args[1], VMF(2) );
- return 0;
- case CG_MEMORY_REMAINING:
- return Hunk_MemoryRemaining();
- case CG_KEY_ISDOWN:
- return Key_IsDown( args[1] );
- case CG_KEY_GETCATCHER:
- return Key_GetCatcher();
- case CG_KEY_SETCATCHER:
- // Don't allow the cgame module to close the console
- Key_SetCatcher( args[1] | ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) );
- return 0;
- case CG_KEY_GETKEY:
- return Key_GetKey( VMA(1) );
-
-
-
- case CG_MEMSET:
- Com_Memset( VMA(1), args[2], args[3] );
- return 0;
- case CG_MEMCPY:
- Com_Memcpy( VMA(1), VMA(2), args[3] );
- return 0;
- case CG_STRNCPY:
- strncpy( VMA(1), VMA(2), args[3] );
- return args[1];
- case CG_SIN:
- return FloatAsInt( sin( VMF(1) ) );
- case CG_COS:
- return FloatAsInt( cos( VMF(1) ) );
- case CG_ATAN2:
- return FloatAsInt( atan2( VMF(1), VMF(2) ) );
- case CG_SQRT:
- return FloatAsInt( sqrt( VMF(1) ) );
- case CG_FLOOR:
- return FloatAsInt( floor( VMF(1) ) );
- case CG_CEIL:
- return FloatAsInt( ceil( VMF(1) ) );
- case CG_ACOS:
- return FloatAsInt( Q_acos( VMF(1) ) );
-
- case CG_PC_ADD_GLOBAL_DEFINE:
- return botlib_export->PC_AddGlobalDefine( VMA(1) );
- case CG_PC_LOAD_SOURCE:
- return botlib_export->PC_LoadSourceHandle( VMA(1) );
- case CG_PC_FREE_SOURCE:
- return botlib_export->PC_FreeSourceHandle( args[1] );
- case CG_PC_READ_TOKEN:
- return botlib_export->PC_ReadTokenHandle( args[1], VMA(2) );
- case CG_PC_SOURCE_FILE_AND_LINE:
- return botlib_export->PC_SourceFileAndLine( args[1], VMA(2), VMA(3) );
-
- case CG_S_STOPBACKGROUNDTRACK:
- S_StopBackgroundTrack();
- return 0;
-
- case CG_REAL_TIME:
- return Com_RealTime( VMA(1) );
- case CG_SNAPVECTOR:
- Sys_SnapVector( VMA(1) );
- return 0;
-
- case CG_CIN_PLAYCINEMATIC:
- return CIN_PlayCinematic(VMA(1), args[2], args[3], args[4], args[5], args[6]);
-
- case CG_CIN_STOPCINEMATIC:
- return CIN_StopCinematic(args[1]);
-
- case CG_CIN_RUNCINEMATIC:
- return CIN_RunCinematic(args[1]);
-
- case CG_CIN_DRAWCINEMATIC:
- CIN_DrawCinematic(args[1]);
- return 0;
-
- case CG_CIN_SETEXTENTS:
- CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]);
- return 0;
-
- case CG_R_REMAP_SHADER:
- re.RemapShader( VMA(1), VMA(2), VMA(3) );
- return 0;
-
-/*
- case CG_LOADCAMERA:
- return loadCamera(VMA(1));
-
- case CG_STARTCAMERA:
- startCamera(args[1]);
- return 0;
-
- case CG_GETCAMERAINFO:
- return getCameraInfo(args[1], VMA(2), VMA(3));
-*/
- case CG_GET_ENTITY_TOKEN:
- return re.GetEntityToken( VMA(1), args[2] );
- case CG_R_INPVS:
- return re.inPVS( VMA(1), VMA(2) );
-
- default:
- assert(0);
- Com_Error( ERR_DROP, "Bad cgame system trap: %ld", (long int) args[0] );
- }
- return 0;
-}
-
-
-/*
-====================
-CL_InitCGame
-
-Should only be called by CL_StartHunkUsers
-====================
-*/
-void CL_InitCGame( void ) {
- const char *info;
- const char *mapname;
- int t1, t2;
- vmInterpret_t interpret;
-
- t1 = Sys_Milliseconds();
-
- // put away the console
- Con_Close();
-
- // find the current mapname
- info = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SERVERINFO ];
- mapname = Info_ValueForKey( info, "mapname" );
- Com_sprintf( cl.mapname, sizeof( cl.mapname ), "maps/%s.bsp", mapname );
-
- // load the dll or bytecode
- if ( cl_connectedToPureServer != 0 ) {
- // if sv_pure is set we only allow qvms to be loaded
- interpret = VMI_COMPILED;
- }
- else {
- interpret = Cvar_VariableValue( "vm_cgame" );
- }
- cgvm = VM_Create( "cgame", CL_CgameSystemCalls, interpret );
- if ( !cgvm ) {
- Com_Error( ERR_DROP, "VM_Create on cgame failed" );
- }
- cls.state = CA_LOADING;
-
- // init for this gamestate
- // use the lastExecutedServerCommand instead of the serverCommandSequence
- // otherwise server commands sent just before a gamestate are dropped
- VM_Call( cgvm, CG_INIT, clc.serverMessageSequence, clc.lastExecutedServerCommand, clc.clientNum );
-
- // reset any CVAR_CHEAT cvars registered by cgame
- if ( !clc.demoplaying && !cl_connectedToCheatServer )
- Cvar_SetCheatState();
-
- // we will send a usercmd this frame, which
- // will cause the server to send us the first snapshot
- cls.state = CA_PRIMED;
-
- t2 = Sys_Milliseconds();
-
- Com_Printf( "CL_InitCGame: %5.2f seconds\n", (t2-t1)/1000.0 );
-
- // have the renderer touch all its images, so they are present
- // on the card even if the driver does deferred loading
- re.EndRegistration();
-
- // make sure everything is paged in
- if (!Sys_LowPhysicalMemory()) {
- Com_TouchMemory();
- }
-
- // clear anything that got printed
- Con_ClearNotify ();
-}
-
-
-/*
-====================
-CL_GameCommand
-
-See if the current console command is claimed by the cgame
-====================
-*/
-qboolean CL_GameCommand( void ) {
- if ( !cgvm ) {
- return qfalse;
- }
-
- return VM_Call( cgvm, CG_CONSOLE_COMMAND );
-}
-
-
-
-/*
-=====================
-CL_CGameRendering
-=====================
-*/
-void CL_CGameRendering( stereoFrame_t stereo ) {
- VM_Call( cgvm, CG_DRAW_ACTIVE_FRAME, cl.serverTime, stereo, clc.demoplaying );
- VM_Debug( 0 );
-}
-
-
-/*
-=================
-CL_AdjustTimeDelta
-
-Adjust the clients view of server time.
-
-We attempt to have cl.serverTime exactly equal the server's view
-of time plus the timeNudge, but with variable latencies over
-the internet it will often need to drift a bit to match conditions.
-
-Our ideal time would be to have the adjusted time approach, but not pass,
-the very latest snapshot.
-
-Adjustments are only made when a new snapshot arrives with a rational
-latency, which keeps the adjustment process framerate independent and
-prevents massive overadjustment during times of significant packet loss
-or bursted delayed packets.
-=================
-*/
-
-#define RESET_TIME 500
-
-void CL_AdjustTimeDelta( void ) {
- int resetTime;
- int newDelta;
- int deltaDelta;
-
- cl.newSnapshots = qfalse;
-
- // the delta never drifts when replaying a demo
- if ( clc.demoplaying ) {
- return;
- }
-
- // if the current time is WAY off, just correct to the current value
- if ( com_sv_running->integer ) {
- resetTime = 100;
- } else {
- resetTime = RESET_TIME;
- }
-
- newDelta = cl.snap.serverTime - cls.realtime;
- deltaDelta = abs( newDelta - cl.serverTimeDelta );
-
- if ( deltaDelta > RESET_TIME ) {
- cl.serverTimeDelta = newDelta;
- cl.oldServerTime = cl.snap.serverTime; // FIXME: is this a problem for cgame?
- cl.serverTime = cl.snap.serverTime;
- if ( cl_showTimeDelta->integer ) {
- Com_Printf( "<RESET> " );
- }
- } else if ( deltaDelta > 100 ) {
- // fast adjust, cut the difference in half
- if ( cl_showTimeDelta->integer ) {
- Com_Printf( "<FAST> " );
- }
- cl.serverTimeDelta = ( cl.serverTimeDelta + newDelta ) >> 1;
- } else {
- // slow drift adjust, only move 1 or 2 msec
-
- // if any of the frames between this and the previous snapshot
- // had to be extrapolated, nudge our sense of time back a little
- // the granularity of +1 / -2 is too high for timescale modified frametimes
- if ( com_timescale->value == 0 || com_timescale->value == 1 ) {
- if ( cl.extrapolatedSnapshot ) {
- cl.extrapolatedSnapshot = qfalse;
- cl.serverTimeDelta -= 2;
- } else {
- // otherwise, move our sense of time forward to minimize total latency
- cl.serverTimeDelta++;
- }
- }
- }
-
- if ( cl_showTimeDelta->integer ) {
- Com_Printf( "%i ", cl.serverTimeDelta );
- }
-}
-
-
-/*
-==================
-CL_FirstSnapshot
-==================
-*/
-void CL_FirstSnapshot( void ) {
- // ignore snapshots that don't have entities
- if ( cl.snap.snapFlags & SNAPFLAG_NOT_ACTIVE ) {
- return;
- }
- cls.state = CA_ACTIVE;
-
- // set the timedelta so we are exactly on this first frame
- cl.serverTimeDelta = cl.snap.serverTime - cls.realtime;
- cl.oldServerTime = cl.snap.serverTime;
-
- clc.timeDemoBaseTime = cl.snap.serverTime;
-
- // if this is the first frame of active play,
- // execute the contents of activeAction now
- // this is to allow scripting a timedemo to start right
- // after loading
- if ( cl_activeAction->string[0] ) {
- Cbuf_AddText( cl_activeAction->string );
- Cvar_Set( "activeAction", "" );
- }
-
-#ifdef USE_MUMBLE
- if ((cl_useMumble->integer) && !mumble_islinked()) {
- int ret = mumble_link(CLIENT_WINDOW_TITLE);
- Com_Printf("Mumble: Linking to Mumble application %s\n", ret==0?"ok":"failed");
- }
-#endif
-
-#ifdef USE_VOIP
- if (!clc.speexInitialized) {
- int i;
- speex_bits_init(&clc.speexEncoderBits);
- speex_bits_reset(&clc.speexEncoderBits);
-
- clc.speexEncoder = speex_encoder_init(&speex_nb_mode);
-
- speex_encoder_ctl(clc.speexEncoder, SPEEX_GET_FRAME_SIZE,
- &clc.speexFrameSize);
- speex_encoder_ctl(clc.speexEncoder, SPEEX_GET_SAMPLING_RATE,
- &clc.speexSampleRate);
-
- clc.speexPreprocessor = speex_preprocess_state_init(clc.speexFrameSize,
- clc.speexSampleRate);
-
- i = 1;
- speex_preprocess_ctl(clc.speexPreprocessor,
- SPEEX_PREPROCESS_SET_DENOISE, &i);
-
- i = 1;
- speex_preprocess_ctl(clc.speexPreprocessor,
- SPEEX_PREPROCESS_SET_AGC, &i);
-
- for (i = 0; i < MAX_CLIENTS; i++) {
- speex_bits_init(&clc.speexDecoderBits[i]);
- speex_bits_reset(&clc.speexDecoderBits[i]);
- clc.speexDecoder[i] = speex_decoder_init(&speex_nb_mode);
- clc.voipIgnore[i] = qfalse;
- clc.voipGain[i] = 1.0f;
- }
- clc.speexInitialized = qtrue;
- clc.voipMuteAll = qfalse;
- Cmd_AddCommand ("voip", CL_Voip_f);
- Cvar_Set("cl_voipSendTarget", "all");
- clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0x7FFFFFFF;
- }
-#endif
-}
-
-/*
-==================
-CL_SetCGameTime
-==================
-*/
-void CL_SetCGameTime( void ) {
- // getting a valid frame message ends the connection process
- if ( cls.state != CA_ACTIVE ) {
- if ( cls.state != CA_PRIMED ) {
- return;
- }
- if ( clc.demoplaying ) {
- // we shouldn't get the first snapshot on the same frame
- // as the gamestate, because it causes a bad time skip
- if ( !clc.firstDemoFrameSkipped ) {
- clc.firstDemoFrameSkipped = qtrue;
- return;
- }
- CL_ReadDemoMessage();
- }
- if ( cl.newSnapshots ) {
- cl.newSnapshots = qfalse;
- CL_FirstSnapshot();
- }
- if ( cls.state != CA_ACTIVE ) {
- return;
- }
- }
-
- // if we have gotten to this point, cl.snap is guaranteed to be valid
- if ( !cl.snap.valid ) {
- Com_Error( ERR_DROP, "CL_SetCGameTime: !cl.snap.valid" );
- }
-
- // allow pause in single player
- if ( sv_paused->integer && CL_CheckPaused() && com_sv_running->integer ) {
- // paused
- return;
- }
-
- if ( cl.snap.serverTime < cl.oldFrameServerTime ) {
- Com_Error( ERR_DROP, "cl.snap.serverTime < cl.oldFrameServerTime" );
- }
- cl.oldFrameServerTime = cl.snap.serverTime;
-
-
- // get our current view of time
-
- if ( clc.demoplaying && cl_freezeDemo->integer ) {
- // cl_freezeDemo is used to lock a demo in place for single frame advances
-
- } else {
- // cl_timeNudge is a user adjustable cvar that allows more
- // or less latency to be added in the interest of better
- // smoothness or better responsiveness.
- int tn;
-
- tn = cl_timeNudge->integer;
- if (tn<-30) {
- tn = -30;
- } else if (tn>30) {
- tn = 30;
- }
-
- cl.serverTime = cls.realtime + cl.serverTimeDelta - tn;
-
- // guarantee that time will never flow backwards, even if
- // serverTimeDelta made an adjustment or cl_timeNudge was changed
- if ( cl.serverTime < cl.oldServerTime ) {
- cl.serverTime = cl.oldServerTime;
- }
- cl.oldServerTime = cl.serverTime;
-
- // note if we are almost past the latest frame (without timeNudge),
- // so we will try and adjust back a bit when the next snapshot arrives
- if ( cls.realtime + cl.serverTimeDelta >= cl.snap.serverTime - 5 ) {
- cl.extrapolatedSnapshot = qtrue;
- }
- }
-
- // if we have gotten new snapshots, drift serverTimeDelta
- // don't do this every frame, or a period of packet loss would
- // make a huge adjustment
- if ( cl.newSnapshots ) {
- CL_AdjustTimeDelta();
- }
-
- if ( !clc.demoplaying ) {
- return;
- }
-
- // if we are playing a demo back, we can just keep reading
- // messages from the demo file until the cgame definately
- // has valid snapshots to interpolate between
-
- // a timedemo will always use a deterministic set of time samples
- // no matter what speed machine it is run on,
- // while a normal demo may have different time samples
- // each time it is played back
- if ( cl_timedemo->integer ) {
- int now = Sys_Milliseconds( );
- int frameDuration;
-
- if (!clc.timeDemoStart) {
- clc.timeDemoStart = clc.timeDemoLastFrame = now;
- clc.timeDemoMinDuration = INT_MAX;
- clc.timeDemoMaxDuration = 0;
- }
-
- frameDuration = now - clc.timeDemoLastFrame;
- clc.timeDemoLastFrame = now;
-
- // Ignore the first measurement as it'll always be 0
- if( clc.timeDemoFrames > 0 )
- {
- if( frameDuration > clc.timeDemoMaxDuration )
- clc.timeDemoMaxDuration = frameDuration;
-
- if( frameDuration < clc.timeDemoMinDuration )
- clc.timeDemoMinDuration = frameDuration;
-
- // 255 ms = about 4fps
- if( frameDuration > UCHAR_MAX )
- frameDuration = UCHAR_MAX;
-
- clc.timeDemoDurations[ ( clc.timeDemoFrames - 1 ) %
- MAX_TIMEDEMO_DURATIONS ] = frameDuration;
- }
-
- clc.timeDemoFrames++;
- cl.serverTime = clc.timeDemoBaseTime + clc.timeDemoFrames * 50;
- }
-
- while ( cl.serverTime >= cl.snap.serverTime ) {
- // feed another messag, which should change
- // the contents of cl.snap
- CL_ReadDemoMessage();
- if ( cls.state != CA_ACTIVE ) {
- return; // end of demo
- }
- }
-
-}
-
-
-
diff --git a/engine/code/client/cl_cin.c b/engine/code/client/cl_cin.c
deleted file mode 100644
index 1fc5520..0000000
--- a/engine/code/client/cl_cin.c
+++ /dev/null
@@ -1,1668 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: cl_cin.c
- *
- * desc: video and cinematic playback
- *
- * $Archive: /MissionPack/code/client/cl_cin.c $
- *
- * cl_glconfig.hwtype trtypes 3dfx/ragepro need 256x256
- *
- *****************************************************************************/
-
-#include "client.h"
-#include "snd_local.h"
-
-#define MAXSIZE 8
-#define MINSIZE 4
-
-#define DEFAULT_CIN_WIDTH 512
-#define DEFAULT_CIN_HEIGHT 512
-
-#define ROQ_QUAD 0x1000
-#define ROQ_QUAD_INFO 0x1001
-#define ROQ_CODEBOOK 0x1002
-#define ROQ_QUAD_VQ 0x1011
-#define ROQ_QUAD_JPEG 0x1012
-#define ROQ_QUAD_HANG 0x1013
-#define ROQ_PACKET 0x1030
-#define ZA_SOUND_MONO 0x1020
-#define ZA_SOUND_STEREO 0x1021
-
-#define MAX_VIDEO_HANDLES 16
-
-extern glconfig_t glConfig;
-
-
-static void RoQ_init( void );
-
-/******************************************************************************
-*
-* Class: trFMV
-*
-* Description: RoQ/RnR manipulation routines
-* not entirely complete for first run
-*
-******************************************************************************/
-
-static long ROQ_YY_tab[256];
-static long ROQ_UB_tab[256];
-static long ROQ_UG_tab[256];
-static long ROQ_VG_tab[256];
-static long ROQ_VR_tab[256];
-static unsigned short vq2[256*16*4];
-static unsigned short vq4[256*64*4];
-static unsigned short vq8[256*256*4];
-
-
-typedef struct {
- byte linbuf[DEFAULT_CIN_WIDTH*DEFAULT_CIN_HEIGHT*4*2];
- byte file[65536];
- short sqrTable[256];
-
- int mcomp[256];
- byte *qStatus[2][32768];
-
- long oldXOff, oldYOff, oldysize, oldxsize;
-
- int currentHandle;
-} cinematics_t;
-
-typedef struct {
- char fileName[MAX_OSPATH];
- int CIN_WIDTH, CIN_HEIGHT;
- int xpos, ypos, width, height;
- qboolean looping, holdAtEnd, dirty, alterGameState, silent, shader;
- fileHandle_t iFile;
- e_status status;
- unsigned int startTime;
- unsigned int lastTime;
- long tfps;
- long RoQPlayed;
- long ROQSize;
- unsigned int RoQFrameSize;
- long onQuad;
- long numQuads;
- long samplesPerLine;
- unsigned int roq_id;
- long screenDelta;
-
- void ( *VQ0)(byte *status, void *qdata );
- void ( *VQ1)(byte *status, void *qdata );
- void ( *VQNormal)(byte *status, void *qdata );
- void ( *VQBuffer)(byte *status, void *qdata );
-
- long samplesPerPixel; // defaults to 2
- byte* gray;
- unsigned int xsize, ysize, maxsize, minsize;
-
- qboolean half, smootheddouble, inMemory;
- long normalBuffer0;
- long roq_flags;
- long roqF0;
- long roqF1;
- long t[2];
- long roqFPS;
- int playonwalls;
- byte* buf;
- long drawX, drawY;
-} cin_cache;
-
-static cinematics_t cin;
-static cin_cache cinTable[MAX_VIDEO_HANDLES];
-static int currentHandle = -1;
-static int CL_handle = -1;
-
-extern int s_soundtime; // sample PAIRS
-
-
-void CIN_CloseAllVideos(void) {
- int i;
-
- for ( i = 0 ; i < MAX_VIDEO_HANDLES ; i++ ) {
- if (cinTable[i].fileName[0] != 0 ) {
- CIN_StopCinematic(i);
- }
- }
-}
-
-
-static int CIN_HandleForVideo(void) {
- int i;
-
- for ( i = 0 ; i < MAX_VIDEO_HANDLES ; i++ ) {
- if ( cinTable[i].fileName[0] == 0 ) {
- return i;
- }
- }
- Com_Error( ERR_DROP, "CIN_HandleForVideo: none free" );
- return -1;
-}
-
-
-extern int CL_ScaledMilliseconds(void);
-
-//-----------------------------------------------------------------------------
-// RllSetupTable
-//
-// Allocates and initializes the square table.
-//
-// Parameters: None
-//
-// Returns: Nothing
-//-----------------------------------------------------------------------------
-static void RllSetupTable( void )
-{
- int z;
-
- for (z=0;z<128;z++) {
- cin.sqrTable[z] = (short)(z*z);
- cin.sqrTable[z+128] = (short)(-cin.sqrTable[z]);
- }
-}
-
-
-
-//-----------------------------------------------------------------------------
-// RllDecodeMonoToMono
-//
-// Decode mono source data into a mono buffer.
-//
-// Parameters: from -> buffer holding encoded data
-// to -> buffer to hold decoded data
-// size = number of bytes of input (= # of shorts of output)
-// signedOutput = 0 for unsigned output, non-zero for signed output
-// flag = flags from asset header
-//
-// Returns: Number of samples placed in output buffer
-//-----------------------------------------------------------------------------
-long RllDecodeMonoToMono(unsigned char *from,short *to,unsigned int size,char signedOutput ,unsigned short flag)
-{
- unsigned int z;
- int prev;
-
- if (signedOutput)
- prev = flag - 0x8000;
- else
- prev = flag;
-
- for (z=0;z<size;z++) {
- prev = to[z] = (short)(prev + cin.sqrTable[from[z]]);
- }
- return size; //*sizeof(short));
-}
-
-
-//-----------------------------------------------------------------------------
-// RllDecodeMonoToStereo
-//
-// Decode mono source data into a stereo buffer. Output is 4 times the number
-// of bytes in the input.
-//
-// Parameters: from -> buffer holding encoded data
-// to -> buffer to hold decoded data
-// size = number of bytes of input (= 1/4 # of bytes of output)
-// signedOutput = 0 for unsigned output, non-zero for signed output
-// flag = flags from asset header
-//
-// Returns: Number of samples placed in output buffer
-//-----------------------------------------------------------------------------
-long RllDecodeMonoToStereo(unsigned char *from,short *to,unsigned int size,char signedOutput,unsigned short flag)
-{
- unsigned int z;
- int prev;
-
- if (signedOutput)
- prev = flag - 0x8000;
- else
- prev = flag;
-
- for (z = 0; z < size; z++) {
- prev = (short)(prev + cin.sqrTable[from[z]]);
- to[z*2+0] = to[z*2+1] = (short)(prev);
- }
-
- return size; // * 2 * sizeof(short));
-}
-
-
-//-----------------------------------------------------------------------------
-// RllDecodeStereoToStereo
-//
-// Decode stereo source data into a stereo buffer.
-//
-// Parameters: from -> buffer holding encoded data
-// to -> buffer to hold decoded data
-// size = number of bytes of input (= 1/2 # of bytes of output)
-// signedOutput = 0 for unsigned output, non-zero for signed output
-// flag = flags from asset header
-//
-// Returns: Number of samples placed in output buffer
-//-----------------------------------------------------------------------------
-long RllDecodeStereoToStereo(unsigned char *from,short *to,unsigned int size,char signedOutput, unsigned short flag)
-{
- unsigned int z;
- unsigned char *zz = from;
- int prevL, prevR;
-
- if (signedOutput) {
- prevL = (flag & 0xff00) - 0x8000;
- prevR = ((flag & 0x00ff) << 8) - 0x8000;
- } else {
- prevL = flag & 0xff00;
- prevR = (flag & 0x00ff) << 8;
- }
-
- for (z=0;z<size;z+=2) {
- prevL = (short)(prevL + cin.sqrTable[*zz++]);
- prevR = (short)(prevR + cin.sqrTable[*zz++]);
- to[z+0] = (short)(prevL);
- to[z+1] = (short)(prevR);
- }
-
- return (size>>1); //*sizeof(short));
-}
-
-
-//-----------------------------------------------------------------------------
-// RllDecodeStereoToMono
-//
-// Decode stereo source data into a mono buffer.
-//
-// Parameters: from -> buffer holding encoded data
-// to -> buffer to hold decoded data
-// size = number of bytes of input (= # of bytes of output)
-// signedOutput = 0 for unsigned output, non-zero for signed output
-// flag = flags from asset header
-//
-// Returns: Number of samples placed in output buffer
-//-----------------------------------------------------------------------------
-long RllDecodeStereoToMono(unsigned char *from,short *to,unsigned int size,char signedOutput, unsigned short flag)
-{
- unsigned int z;
- int prevL,prevR;
-
- if (signedOutput) {
- prevL = (flag & 0xff00) - 0x8000;
- prevR = ((flag & 0x00ff) << 8) -0x8000;
- } else {
- prevL = flag & 0xff00;
- prevR = (flag & 0x00ff) << 8;
- }
-
- for (z=0;z<size;z+=1) {
- prevL= prevL + cin.sqrTable[from[z*2]];
- prevR = prevR + cin.sqrTable[from[z*2+1]];
- to[z] = (short)((prevL + prevR)/2);
- }
-
- return size;
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void move8_32( byte *src, byte *dst, int spl )
-{
- int i;
-
- for(i = 0; i < 8; ++i)
- {
- memcpy(dst, src, 32);
- src += spl;
- dst += spl;
- }
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void move4_32( byte *src, byte *dst, int spl )
-{
- int i;
-
- for(i = 0; i < 4; ++i)
- {
- memcpy(dst, src, 16);
- src += spl;
- dst += spl;
- }
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void blit8_32( byte *src, byte *dst, int spl )
-{
- int i;
-
- for(i = 0; i < 8; ++i)
- {
- memcpy(dst, src, 32);
- src += 32;
- dst += spl;
- }
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-static void blit4_32( byte *src, byte *dst, int spl )
-{
- int i;
-
- for(i = 0; i < 4; ++i)
- {
- memmove(dst, src, 16);
- src += 16;
- dst += spl;
- }
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void blit2_32( byte *src, byte *dst, int spl )
-{
- memcpy(dst, src, 8);
- memcpy(dst+spl, src+8, 8);
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void blitVQQuad32fs( byte **status, unsigned char *data )
-{
-unsigned short newd, celdata, code;
-unsigned int index, i;
-int spl;
-
- newd = 0;
- celdata = 0;
- index = 0;
-
- spl = cinTable[currentHandle].samplesPerLine;
-
- do {
- if (!newd) {
- newd = 7;
- celdata = data[0] + data[1]*256;
- data += 2;
- } else {
- newd--;
- }
-
- code = (unsigned short)(celdata&0xc000);
- celdata <<= 2;
-
- switch (code) {
- case 0x8000: // vq code
- blit8_32( (byte *)&vq8[(*data)*128], status[index], spl );
- data++;
- index += 5;
- break;
- case 0xc000: // drop
- index++; // skip 8x8
- for(i=0;i<4;i++) {
- if (!newd) {
- newd = 7;
- celdata = data[0] + data[1]*256;
- data += 2;
- } else {
- newd--;
- }
-
- code = (unsigned short)(celdata&0xc000); celdata <<= 2;
-
- switch (code) { // code in top two bits of code
- case 0x8000: // 4x4 vq code
- blit4_32( (byte *)&vq4[(*data)*32], status[index], spl );
- data++;
- break;
- case 0xc000: // 2x2 vq code
- blit2_32( (byte *)&vq2[(*data)*8], status[index], spl );
- data++;
- blit2_32( (byte *)&vq2[(*data)*8], status[index]+8, spl );
- data++;
- blit2_32( (byte *)&vq2[(*data)*8], status[index]+spl*2, spl );
- data++;
- blit2_32( (byte *)&vq2[(*data)*8], status[index]+spl*2+8, spl );
- data++;
- break;
- case 0x4000: // motion compensation
- move4_32( status[index] + cin.mcomp[(*data)], status[index], spl );
- data++;
- break;
- }
- index++;
- }
- break;
- case 0x4000: // motion compensation
- move8_32( status[index] + cin.mcomp[(*data)], status[index], spl );
- data++;
- index += 5;
- break;
- case 0x0000:
- index += 5;
- break;
- }
- } while ( status[index] != NULL );
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void ROQ_GenYUVTables( void )
-{
- float t_ub,t_vr,t_ug,t_vg;
- long i;
-
- t_ub = (1.77200f/2.0f) * (float)(1<<6) + 0.5f;
- t_vr = (1.40200f/2.0f) * (float)(1<<6) + 0.5f;
- t_ug = (0.34414f/2.0f) * (float)(1<<6) + 0.5f;
- t_vg = (0.71414f/2.0f) * (float)(1<<6) + 0.5f;
- for(i=0;i<256;i++) {
- float x = (float)(2 * i - 255);
-
- ROQ_UB_tab[i] = (long)( ( t_ub * x) + (1<<5));
- ROQ_VR_tab[i] = (long)( ( t_vr * x) + (1<<5));
- ROQ_UG_tab[i] = (long)( (-t_ug * x) );
- ROQ_VG_tab[i] = (long)( (-t_vg * x) + (1<<5));
- ROQ_YY_tab[i] = (long)( (i << 6) | (i >> 2) );
- }
-}
-
-#define VQ2TO4(a,b,c,d) { \
- *c++ = a[0]; \
- *d++ = a[0]; \
- *d++ = a[0]; \
- *c++ = a[1]; \
- *d++ = a[1]; \
- *d++ = a[1]; \
- *c++ = b[0]; \
- *d++ = b[0]; \
- *d++ = b[0]; \
- *c++ = b[1]; \
- *d++ = b[1]; \
- *d++ = b[1]; \
- *d++ = a[0]; \
- *d++ = a[0]; \
- *d++ = a[1]; \
- *d++ = a[1]; \
- *d++ = b[0]; \
- *d++ = b[0]; \
- *d++ = b[1]; \
- *d++ = b[1]; \
- a += 2; b += 2; }
-
-#define VQ2TO2(a,b,c,d) { \
- *c++ = *a; \
- *d++ = *a; \
- *d++ = *a; \
- *c++ = *b; \
- *d++ = *b; \
- *d++ = *b; \
- *d++ = *a; \
- *d++ = *a; \
- *d++ = *b; \
- *d++ = *b; \
- a++; b++; }
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static unsigned short yuv_to_rgb( long y, long u, long v )
-{
- long r,g,b,YY = (long)(ROQ_YY_tab[(y)]);
-
- r = (YY + ROQ_VR_tab[v]) >> 9;
- g = (YY + ROQ_UG_tab[u] + ROQ_VG_tab[v]) >> 8;
- b = (YY + ROQ_UB_tab[u]) >> 9;
-
- if (r<0) r = 0; if (g<0) g = 0; if (b<0) b = 0;
- if (r > 31) r = 31; if (g > 63) g = 63; if (b > 31) b = 31;
-
- return (unsigned short)((r<<11)+(g<<5)+(b));
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-static unsigned int yuv_to_rgb24( long y, long u, long v )
-{
- long r,g,b,YY = (long)(ROQ_YY_tab[(y)]);
-
- r = (YY + ROQ_VR_tab[v]) >> 6;
- g = (YY + ROQ_UG_tab[u] + ROQ_VG_tab[v]) >> 6;
- b = (YY + ROQ_UB_tab[u]) >> 6;
-
- if (r<0) r = 0; if (g<0) g = 0; if (b<0) b = 0;
- if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;
-
- return LittleLong ((r)|(g<<8)|(b<<16)|(255<<24));
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void decodeCodeBook( byte *input, unsigned short roq_flags )
-{
- long i, j, two, four;
- unsigned short *aptr, *bptr, *cptr, *dptr;
- long y0,y1,y2,y3,cr,cb;
- byte *bbptr, *baptr, *bcptr, *bdptr;
- union {
- unsigned int *i;
- unsigned short *s;
- } iaptr, ibptr, icptr, idptr;
-
- if (!roq_flags) {
- two = four = 256;
- } else {
- two = roq_flags>>8;
- if (!two) two = 256;
- four = roq_flags&0xff;
- }
-
- four *= 2;
-
- bptr = (unsigned short *)vq2;
-
- if (!cinTable[currentHandle].half) {
- if (!cinTable[currentHandle].smootheddouble) {
-//
-// normal height
-//
- if (cinTable[currentHandle].samplesPerPixel==2) {
- for(i=0;i<two;i++) {
- y0 = (long)*input++;
- y1 = (long)*input++;
- y2 = (long)*input++;
- y3 = (long)*input++;
- cr = (long)*input++;
- cb = (long)*input++;
- *bptr++ = yuv_to_rgb( y0, cr, cb );
- *bptr++ = yuv_to_rgb( y1, cr, cb );
- *bptr++ = yuv_to_rgb( y2, cr, cb );
- *bptr++ = yuv_to_rgb( y3, cr, cb );
- }
-
- cptr = (unsigned short *)vq4;
- dptr = (unsigned short *)vq8;
-
- for(i=0;i<four;i++) {
- aptr = (unsigned short *)vq2 + (*input++)*4;
- bptr = (unsigned short *)vq2 + (*input++)*4;
- for(j=0;j<2;j++)
- VQ2TO4(aptr,bptr,cptr,dptr);
- }
- } else if (cinTable[currentHandle].samplesPerPixel==4) {
- ibptr.s = bptr;
- for(i=0;i<two;i++) {
- y0 = (long)*input++;
- y1 = (long)*input++;
- y2 = (long)*input++;
- y3 = (long)*input++;
- cr = (long)*input++;
- cb = (long)*input++;
- *ibptr.i++ = yuv_to_rgb24( y0, cr, cb );
- *ibptr.i++ = yuv_to_rgb24( y1, cr, cb );
- *ibptr.i++ = yuv_to_rgb24( y2, cr, cb );
- *ibptr.i++ = yuv_to_rgb24( y3, cr, cb );
- }
-
- icptr.s = vq4;
- idptr.s = vq8;
-
- for(i=0;i<four;i++) {
- iaptr.s = vq2;
- iaptr.i += (*input++)*4;
- ibptr.s = vq2;
- ibptr.i += (*input++)*4;
- for(j=0;j<2;j++)
- VQ2TO4(iaptr.i, ibptr.i, icptr.i, idptr.i);
- }
- } else if (cinTable[currentHandle].samplesPerPixel==1) {
- bbptr = (byte *)bptr;
- for(i=0;i<two;i++) {
- *bbptr++ = cinTable[currentHandle].gray[*input++];
- *bbptr++ = cinTable[currentHandle].gray[*input++];
- *bbptr++ = cinTable[currentHandle].gray[*input++];
- *bbptr++ = cinTable[currentHandle].gray[*input]; input +=3;
- }
-
- bcptr = (byte *)vq4;
- bdptr = (byte *)vq8;
-
- for(i=0;i<four;i++) {
- baptr = (byte *)vq2 + (*input++)*4;
- bbptr = (byte *)vq2 + (*input++)*4;
- for(j=0;j<2;j++)
- VQ2TO4(baptr,bbptr,bcptr,bdptr);
- }
- }
- } else {
-//
-// double height, smoothed
-//
- if (cinTable[currentHandle].samplesPerPixel==2) {
- for(i=0;i<two;i++) {
- y0 = (long)*input++;
- y1 = (long)*input++;
- y2 = (long)*input++;
- y3 = (long)*input++;
- cr = (long)*input++;
- cb = (long)*input++;
- *bptr++ = yuv_to_rgb( y0, cr, cb );
- *bptr++ = yuv_to_rgb( y1, cr, cb );
- *bptr++ = yuv_to_rgb( ((y0*3)+y2)/4, cr, cb );
- *bptr++ = yuv_to_rgb( ((y1*3)+y3)/4, cr, cb );
- *bptr++ = yuv_to_rgb( (y0+(y2*3))/4, cr, cb );
- *bptr++ = yuv_to_rgb( (y1+(y3*3))/4, cr, cb );
- *bptr++ = yuv_to_rgb( y2, cr, cb );
- *bptr++ = yuv_to_rgb( y3, cr, cb );
- }
-
- cptr = (unsigned short *)vq4;
- dptr = (unsigned short *)vq8;
-
- for(i=0;i<four;i++) {
- aptr = (unsigned short *)vq2 + (*input++)*8;
- bptr = (unsigned short *)vq2 + (*input++)*8;
- for(j=0;j<2;j++) {
- VQ2TO4(aptr,bptr,cptr,dptr);
- VQ2TO4(aptr,bptr,cptr,dptr);
- }
- }
- } else if (cinTable[currentHandle].samplesPerPixel==4) {
- ibptr.s = bptr;
- for(i=0;i<two;i++) {
- y0 = (long)*input++;
- y1 = (long)*input++;
- y2 = (long)*input++;
- y3 = (long)*input++;
- cr = (long)*input++;
- cb = (long)*input++;
- *ibptr.i++ = yuv_to_rgb24( y0, cr, cb );
- *ibptr.i++ = yuv_to_rgb24( y1, cr, cb );
- *ibptr.i++ = yuv_to_rgb24( ((y0*3)+y2)/4, cr, cb );
- *ibptr.i++ = yuv_to_rgb24( ((y1*3)+y3)/4, cr, cb );
- *ibptr.i++ = yuv_to_rgb24( (y0+(y2*3))/4, cr, cb );
- *ibptr.i++ = yuv_to_rgb24( (y1+(y3*3))/4, cr, cb );
- *ibptr.i++ = yuv_to_rgb24( y2, cr, cb );
- *ibptr.i++ = yuv_to_rgb24( y3, cr, cb );
- }
-
- icptr.s = vq4;
- idptr.s = vq8;
-
- for(i=0;i<four;i++) {
- iaptr.s = vq2;
- iaptr.i += (*input++)*8;
- ibptr.s = vq2;
- ibptr.i += (*input++)*8;
- for(j=0;j<2;j++) {
- VQ2TO4(iaptr.i, ibptr.i, icptr.i, idptr.i);
- VQ2TO4(iaptr.i, ibptr.i, icptr.i, idptr.i);
- }
- }
- } else if (cinTable[currentHandle].samplesPerPixel==1) {
- bbptr = (byte *)bptr;
- for(i=0;i<two;i++) {
- y0 = (long)*input++;
- y1 = (long)*input++;
- y2 = (long)*input++;
- y3 = (long)*input; input+= 3;
- *bbptr++ = cinTable[currentHandle].gray[y0];
- *bbptr++ = cinTable[currentHandle].gray[y1];
- *bbptr++ = cinTable[currentHandle].gray[((y0*3)+y2)/4];
- *bbptr++ = cinTable[currentHandle].gray[((y1*3)+y3)/4];
- *bbptr++ = cinTable[currentHandle].gray[(y0+(y2*3))/4];
- *bbptr++ = cinTable[currentHandle].gray[(y1+(y3*3))/4];
- *bbptr++ = cinTable[currentHandle].gray[y2];
- *bbptr++ = cinTable[currentHandle].gray[y3];
- }
-
- bcptr = (byte *)vq4;
- bdptr = (byte *)vq8;
-
- for(i=0;i<four;i++) {
- baptr = (byte *)vq2 + (*input++)*8;
- bbptr = (byte *)vq2 + (*input++)*8;
- for(j=0;j<2;j++) {
- VQ2TO4(baptr,bbptr,bcptr,bdptr);
- VQ2TO4(baptr,bbptr,bcptr,bdptr);
- }
- }
- }
- }
- } else {
-//
-// 1/4 screen
-//
- if (cinTable[currentHandle].samplesPerPixel==2) {
- for(i=0;i<two;i++) {
- y0 = (long)*input; input+=2;
- y2 = (long)*input; input+=2;
- cr = (long)*input++;
- cb = (long)*input++;
- *bptr++ = yuv_to_rgb( y0, cr, cb );
- *bptr++ = yuv_to_rgb( y2, cr, cb );
- }
-
- cptr = (unsigned short *)vq4;
- dptr = (unsigned short *)vq8;
-
- for(i=0;i<four;i++) {
- aptr = (unsigned short *)vq2 + (*input++)*2;
- bptr = (unsigned short *)vq2 + (*input++)*2;
- for(j=0;j<2;j++) {
- VQ2TO2(aptr,bptr,cptr,dptr);
- }
- }
- } else if (cinTable[currentHandle].samplesPerPixel == 1) {
- bbptr = (byte *)bptr;
-
- for(i=0;i<two;i++) {
- *bbptr++ = cinTable[currentHandle].gray[*input]; input+=2;
- *bbptr++ = cinTable[currentHandle].gray[*input]; input+=4;
- }
-
- bcptr = (byte *)vq4;
- bdptr = (byte *)vq8;
-
- for(i=0;i<four;i++) {
- baptr = (byte *)vq2 + (*input++)*2;
- bbptr = (byte *)vq2 + (*input++)*2;
- for(j=0;j<2;j++) {
- VQ2TO2(baptr,bbptr,bcptr,bdptr);
- }
- }
- } else if (cinTable[currentHandle].samplesPerPixel == 4) {
- ibptr.s = bptr;
- for(i=0;i<two;i++) {
- y0 = (long)*input; input+=2;
- y2 = (long)*input; input+=2;
- cr = (long)*input++;
- cb = (long)*input++;
- *ibptr.i++ = yuv_to_rgb24( y0, cr, cb );
- *ibptr.i++ = yuv_to_rgb24( y2, cr, cb );
- }
-
- icptr.s = vq4;
- idptr.s = vq8;
-
- for(i=0;i<four;i++) {
- iaptr.s = vq2;
- iaptr.i += (*input++)*2;
- ibptr.s = vq2 + (*input++)*2;
- ibptr.i += (*input++)*2;
- for(j=0;j<2;j++) {
- VQ2TO2(iaptr.i,ibptr.i,icptr.i,idptr.i);
- }
- }
- }
- }
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void recurseQuad( long startX, long startY, long quadSize, long xOff, long yOff )
-{
- byte *scroff;
- long bigx, bigy, lowx, lowy, useY;
- long offset;
-
- offset = cinTable[currentHandle].screenDelta;
-
- lowx = lowy = 0;
- bigx = cinTable[currentHandle].xsize;
- bigy = cinTable[currentHandle].ysize;
-
- if (bigx > cinTable[currentHandle].CIN_WIDTH) bigx = cinTable[currentHandle].CIN_WIDTH;
- if (bigy > cinTable[currentHandle].CIN_HEIGHT) bigy = cinTable[currentHandle].CIN_HEIGHT;
-
- if ( (startX >= lowx) && (startX+quadSize) <= (bigx) && (startY+quadSize) <= (bigy) && (startY >= lowy) && quadSize <= MAXSIZE) {
- useY = startY;
- scroff = cin.linbuf + (useY+((cinTable[currentHandle].CIN_HEIGHT-bigy)>>1)+yOff)*(cinTable[currentHandle].samplesPerLine) + (((startX+xOff))*cinTable[currentHandle].samplesPerPixel);
-
- cin.qStatus[0][cinTable[currentHandle].onQuad ] = scroff;
- cin.qStatus[1][cinTable[currentHandle].onQuad++] = scroff+offset;
- }
-
- if ( quadSize != MINSIZE ) {
- quadSize >>= 1;
- recurseQuad( startX, startY , quadSize, xOff, yOff );
- recurseQuad( startX+quadSize, startY , quadSize, xOff, yOff );
- recurseQuad( startX, startY+quadSize , quadSize, xOff, yOff );
- recurseQuad( startX+quadSize, startY+quadSize , quadSize, xOff, yOff );
- }
-}
-
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void setupQuad( long xOff, long yOff )
-{
- long numQuadCels, i,x,y;
- byte *temp;
-
- if (xOff == cin.oldXOff && yOff == cin.oldYOff && cinTable[currentHandle].ysize == cin.oldysize && cinTable[currentHandle].xsize == cin.oldxsize) {
- return;
- }
-
- cin.oldXOff = xOff;
- cin.oldYOff = yOff;
- cin.oldysize = cinTable[currentHandle].ysize;
- cin.oldxsize = cinTable[currentHandle].xsize;
-
- numQuadCels = (cinTable[currentHandle].CIN_WIDTH*cinTable[currentHandle].CIN_HEIGHT) / (16);
- numQuadCels += numQuadCels/4 + numQuadCels/16;
- numQuadCels += 64; // for overflow
-
- numQuadCels = (cinTable[currentHandle].xsize*cinTable[currentHandle].ysize) / (16);
- numQuadCels += numQuadCels/4;
- numQuadCels += 64; // for overflow
-
- cinTable[currentHandle].onQuad = 0;
-
- for(y=0;y<(long)cinTable[currentHandle].ysize;y+=16)
- for(x=0;x<(long)cinTable[currentHandle].xsize;x+=16)
- recurseQuad( x, y, 16, xOff, yOff );
-
- temp = NULL;
-
- for(i=(numQuadCels-64);i<numQuadCels;i++) {
- cin.qStatus[0][i] = temp; // eoq
- cin.qStatus[1][i] = temp; // eoq
- }
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void readQuadInfo( byte *qData )
-{
- if (currentHandle < 0) return;
-
- cinTable[currentHandle].xsize = qData[0]+qData[1]*256;
- cinTable[currentHandle].ysize = qData[2]+qData[3]*256;
- cinTable[currentHandle].maxsize = qData[4]+qData[5]*256;
- cinTable[currentHandle].minsize = qData[6]+qData[7]*256;
-
- cinTable[currentHandle].CIN_HEIGHT = cinTable[currentHandle].ysize;
- cinTable[currentHandle].CIN_WIDTH = cinTable[currentHandle].xsize;
-
- cinTable[currentHandle].samplesPerLine = cinTable[currentHandle].CIN_WIDTH*cinTable[currentHandle].samplesPerPixel;
- cinTable[currentHandle].screenDelta = cinTable[currentHandle].CIN_HEIGHT*cinTable[currentHandle].samplesPerLine;
-
- cinTable[currentHandle].half = qfalse;
- cinTable[currentHandle].smootheddouble = qfalse;
-
- cinTable[currentHandle].VQ0 = cinTable[currentHandle].VQNormal;
- cinTable[currentHandle].VQ1 = cinTable[currentHandle].VQBuffer;
-
- cinTable[currentHandle].t[0] = cinTable[currentHandle].screenDelta;
- cinTable[currentHandle].t[1] = -cinTable[currentHandle].screenDelta;
-
- cinTable[currentHandle].drawX = cinTable[currentHandle].CIN_WIDTH;
- cinTable[currentHandle].drawY = cinTable[currentHandle].CIN_HEIGHT;
-
- // rage pro is very slow at 512 wide textures, voodoo can't do it at all
- if ( glConfig.hardwareType == GLHW_RAGEPRO || glConfig.maxTextureSize <= 256) {
- if (cinTable[currentHandle].drawX>256) {
- cinTable[currentHandle].drawX = 256;
- }
- if (cinTable[currentHandle].drawY>256) {
- cinTable[currentHandle].drawY = 256;
- }
- if (cinTable[currentHandle].CIN_WIDTH != 256 || cinTable[currentHandle].CIN_HEIGHT != 256) {
- Com_Printf("HACK: approxmimating cinematic for Rage Pro or Voodoo\n");
- }
- }
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void RoQPrepMcomp( long xoff, long yoff )
-{
- long i, j, x, y, temp, temp2;
-
- i=cinTable[currentHandle].samplesPerLine; j=cinTable[currentHandle].samplesPerPixel;
- if ( cinTable[currentHandle].xsize == (cinTable[currentHandle].ysize*4) && !cinTable[currentHandle].half ) { j = j+j; i = i+i; }
-
- for(y=0;y<16;y++) {
- temp2 = (y+yoff-8)*i;
- for(x=0;x<16;x++) {
- temp = (x+xoff-8)*j;
- cin.mcomp[(x*16)+y] = cinTable[currentHandle].normalBuffer0-(temp2+temp);
- }
- }
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void initRoQ( void )
-{
- if (currentHandle < 0) return;
-
- cinTable[currentHandle].VQNormal = (void (*)(byte *, void *))blitVQQuad32fs;
- cinTable[currentHandle].VQBuffer = (void (*)(byte *, void *))blitVQQuad32fs;
- cinTable[currentHandle].samplesPerPixel = 4;
- ROQ_GenYUVTables();
- RllSetupTable();
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-/*
-static byte* RoQFetchInterlaced( byte *source ) {
- int x, *src, *dst;
-
- if (currentHandle < 0) return NULL;
-
- src = (int *)source;
- dst = (int *)cinTable[currentHandle].buf2;
-
- for(x=0;x<256*256;x++) {
- *dst = *src;
- dst++; src += 2;
- }
- return cinTable[currentHandle].buf2;
-}
-*/
-static void RoQReset( void ) {
-
- if (currentHandle < 0) return;
-
- FS_FCloseFile( cinTable[currentHandle].iFile );
- FS_FOpenFileRead (cinTable[currentHandle].fileName, &cinTable[currentHandle].iFile, qtrue);
- // let the background thread start reading ahead
- FS_Read (cin.file, 16, cinTable[currentHandle].iFile);
- RoQ_init();
- cinTable[currentHandle].status = FMV_LOOPED;
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void RoQInterrupt(void)
-{
- byte *framedata;
- short sbuf[32768];
- int ssize;
-
- if (currentHandle < 0) return;
-
- FS_Read( cin.file, cinTable[currentHandle].RoQFrameSize+8, cinTable[currentHandle].iFile );
- if ( cinTable[currentHandle].RoQPlayed >= cinTable[currentHandle].ROQSize ) {
- if (cinTable[currentHandle].holdAtEnd==qfalse) {
- if (cinTable[currentHandle].looping) {
- RoQReset();
- } else {
- cinTable[currentHandle].status = FMV_EOF;
- }
- } else {
- cinTable[currentHandle].status = FMV_IDLE;
- }
- return;
- }
-
- framedata = cin.file;
-//
-// new frame is ready
-//
-redump:
- switch(cinTable[currentHandle].roq_id)
- {
- case ROQ_QUAD_VQ:
- if ((cinTable[currentHandle].numQuads&1)) {
- cinTable[currentHandle].normalBuffer0 = cinTable[currentHandle].t[1];
- RoQPrepMcomp( cinTable[currentHandle].roqF0, cinTable[currentHandle].roqF1 );
- cinTable[currentHandle].VQ1( (byte *)cin.qStatus[1], framedata);
- cinTable[currentHandle].buf = cin.linbuf + cinTable[currentHandle].screenDelta;
- } else {
- cinTable[currentHandle].normalBuffer0 = cinTable[currentHandle].t[0];
- RoQPrepMcomp( cinTable[currentHandle].roqF0, cinTable[currentHandle].roqF1 );
- cinTable[currentHandle].VQ0( (byte *)cin.qStatus[0], framedata );
- cinTable[currentHandle].buf = cin.linbuf;
- }
- if (cinTable[currentHandle].numQuads == 0) { // first frame
- Com_Memcpy(cin.linbuf+cinTable[currentHandle].screenDelta, cin.linbuf, cinTable[currentHandle].samplesPerLine*cinTable[currentHandle].ysize);
- }
- cinTable[currentHandle].numQuads++;
- cinTable[currentHandle].dirty = qtrue;
- break;
- case ROQ_CODEBOOK:
- decodeCodeBook( framedata, (unsigned short)cinTable[currentHandle].roq_flags );
- break;
- case ZA_SOUND_MONO:
- if (!cinTable[currentHandle].silent) {
- ssize = RllDecodeMonoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);
- S_RawSamples( 0, ssize, 22050, 2, 1, (byte *)sbuf, 1.0f );
- }
- break;
- case ZA_SOUND_STEREO:
- if (!cinTable[currentHandle].silent) {
- if (cinTable[currentHandle].numQuads == -1) {
- S_Update();
- s_rawend[0] = s_soundtime;
- }
- ssize = RllDecodeStereoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);
- S_RawSamples( 0, ssize, 22050, 2, 2, (byte *)sbuf, 1.0f );
- }
- break;
- case ROQ_QUAD_INFO:
- if (cinTable[currentHandle].numQuads == -1) {
- readQuadInfo( framedata );
- setupQuad( 0, 0 );
- // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer
- cinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = CL_ScaledMilliseconds()*com_timescale->value;
- }
- if (cinTable[currentHandle].numQuads != 1) cinTable[currentHandle].numQuads = 0;
- break;
- case ROQ_PACKET:
- cinTable[currentHandle].inMemory = cinTable[currentHandle].roq_flags;
- cinTable[currentHandle].RoQFrameSize = 0; // for header
- break;
- case ROQ_QUAD_HANG:
- cinTable[currentHandle].RoQFrameSize = 0;
- break;
- case ROQ_QUAD_JPEG:
- break;
- default:
- cinTable[currentHandle].status = FMV_EOF;
- break;
- }
-//
-// read in next frame data
-//
- if ( cinTable[currentHandle].RoQPlayed >= cinTable[currentHandle].ROQSize ) {
- if (cinTable[currentHandle].holdAtEnd==qfalse) {
- if (cinTable[currentHandle].looping) {
- RoQReset();
- } else {
- cinTable[currentHandle].status = FMV_EOF;
- }
- } else {
- cinTable[currentHandle].status = FMV_IDLE;
- }
- return;
- }
-
- framedata += cinTable[currentHandle].RoQFrameSize;
- cinTable[currentHandle].roq_id = framedata[0] + framedata[1]*256;
- cinTable[currentHandle].RoQFrameSize = framedata[2] + framedata[3]*256 + framedata[4]*65536;
- cinTable[currentHandle].roq_flags = framedata[6] + framedata[7]*256;
- cinTable[currentHandle].roqF0 = (signed char)framedata[7];
- cinTable[currentHandle].roqF1 = (signed char)framedata[6];
-
- if (cinTable[currentHandle].RoQFrameSize>65536||cinTable[currentHandle].roq_id==0x1084) {
- Com_DPrintf("roq_size>65536||roq_id==0x1084\n");
- cinTable[currentHandle].status = FMV_EOF;
- if (cinTable[currentHandle].looping) {
- RoQReset();
- }
- return;
- }
- if (cinTable[currentHandle].inMemory && (cinTable[currentHandle].status != FMV_EOF)) { cinTable[currentHandle].inMemory--; framedata += 8; goto redump; }
-//
-// one more frame hits the dust
-//
-// assert(cinTable[currentHandle].RoQFrameSize <= 65536);
-// r = FS_Read( cin.file, cinTable[currentHandle].RoQFrameSize+8, cinTable[currentHandle].iFile );
- cinTable[currentHandle].RoQPlayed += cinTable[currentHandle].RoQFrameSize+8;
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void RoQ_init( void )
-{
- // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer
- cinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = CL_ScaledMilliseconds()*com_timescale->value;
-
- cinTable[currentHandle].RoQPlayed = 24;
-
-/* get frame rate */
- cinTable[currentHandle].roqFPS = cin.file[ 6] + cin.file[ 7]*256;
-
- if (!cinTable[currentHandle].roqFPS) cinTable[currentHandle].roqFPS = 30;
-
- cinTable[currentHandle].numQuads = -1;
-
- cinTable[currentHandle].roq_id = cin.file[ 8] + cin.file[ 9]*256;
- cinTable[currentHandle].RoQFrameSize = cin.file[10] + cin.file[11]*256 + cin.file[12]*65536;
- cinTable[currentHandle].roq_flags = cin.file[14] + cin.file[15]*256;
-
- if (cinTable[currentHandle].RoQFrameSize > 65536 || !cinTable[currentHandle].RoQFrameSize) {
- return;
- }
-
-}
-
-/******************************************************************************
-*
-* Function:
-*
-* Description:
-*
-******************************************************************************/
-
-static void RoQShutdown( void ) {
- const char *s;
-
- if (!cinTable[currentHandle].buf) {
- return;
- }
-
- if ( cinTable[currentHandle].status == FMV_IDLE ) {
- return;
- }
- Com_DPrintf("finished cinematic\n");
- cinTable[currentHandle].status = FMV_IDLE;
-
- if (cinTable[currentHandle].iFile) {
- FS_FCloseFile( cinTable[currentHandle].iFile );
- cinTable[currentHandle].iFile = 0;
- }
-
- if (cinTable[currentHandle].alterGameState) {
- cls.state = CA_DISCONNECTED;
- // we can't just do a vstr nextmap, because
- // if we are aborting the intro cinematic with
- // a devmap command, nextmap would be valid by
- // the time it was referenced
- s = Cvar_VariableString( "nextmap" );
- if ( s[0] ) {
- Cbuf_ExecuteText( EXEC_APPEND, va("%s\n", s) );
- Cvar_Set( "nextmap", "" );
- }
- CL_handle = -1;
- }
- cinTable[currentHandle].fileName[0] = 0;
- currentHandle = -1;
-}
-
-/*
-==================
-SCR_StopCinematic
-==================
-*/
-e_status CIN_StopCinematic(int handle) {
-
- if (handle < 0 || handle>= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return FMV_EOF;
- currentHandle = handle;
-
- Com_DPrintf("trFMV::stop(), closing %s\n", cinTable[currentHandle].fileName);
-
- if (!cinTable[currentHandle].buf) {
- return FMV_EOF;
- }
-
- if (cinTable[currentHandle].alterGameState) {
- if ( cls.state != CA_CINEMATIC ) {
- return cinTable[currentHandle].status;
- }
- }
- cinTable[currentHandle].status = FMV_EOF;
- RoQShutdown();
-
- return FMV_EOF;
-}
-
-/*
-==================
-SCR_RunCinematic
-
-Fetch and decompress the pending frame
-==================
-*/
-
-
-e_status CIN_RunCinematic (int handle)
-{
- int start = 0;
- int thisTime = 0;
-
- if (handle < 0 || handle>= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return FMV_EOF;
-
- if (cin.currentHandle != handle) {
- currentHandle = handle;
- cin.currentHandle = currentHandle;
- cinTable[currentHandle].status = FMV_EOF;
- RoQReset();
- }
-
- if (cinTable[handle].playonwalls < -1)
- {
- return cinTable[handle].status;
- }
-
- currentHandle = handle;
-
- if (cinTable[currentHandle].alterGameState) {
- if ( cls.state != CA_CINEMATIC ) {
- return cinTable[currentHandle].status;
- }
- }
-
- if (cinTable[currentHandle].status == FMV_IDLE) {
- return cinTable[currentHandle].status;
- }
-
- // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer
- thisTime = CL_ScaledMilliseconds()*com_timescale->value;
- if (cinTable[currentHandle].shader && (abs(thisTime - cinTable[currentHandle].lastTime))>100) {
- cinTable[currentHandle].startTime += thisTime - cinTable[currentHandle].lastTime;
- }
- // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer
- cinTable[currentHandle].tfps = ((((CL_ScaledMilliseconds()*com_timescale->value) - cinTable[currentHandle].startTime)*3)/100);
-
- start = cinTable[currentHandle].startTime;
- while( (cinTable[currentHandle].tfps != cinTable[currentHandle].numQuads)
- && (cinTable[currentHandle].status == FMV_PLAY) )
- {
- RoQInterrupt();
- if (start != cinTable[currentHandle].startTime) {
- // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer
- cinTable[currentHandle].tfps = ((((CL_ScaledMilliseconds()*com_timescale->value)
- - cinTable[currentHandle].startTime)*3)/100);
- start = cinTable[currentHandle].startTime;
- }
- }
-
- cinTable[currentHandle].lastTime = thisTime;
-
- if (cinTable[currentHandle].status == FMV_LOOPED) {
- cinTable[currentHandle].status = FMV_PLAY;
- }
-
- if (cinTable[currentHandle].status == FMV_EOF) {
- if (cinTable[currentHandle].looping) {
- RoQReset();
- } else {
- RoQShutdown();
- }
- }
-
- return cinTable[currentHandle].status;
-}
-
-/*
-==================
-CL_PlayCinematic
-
-==================
-*/
-int CIN_PlayCinematic( const char *arg, int x, int y, int w, int h, int systemBits ) {
- unsigned short RoQID;
- char name[MAX_OSPATH];
- int i;
-
- if (strstr(arg, "/") == NULL && strstr(arg, "\\") == NULL) {
- Com_sprintf (name, sizeof(name), "video/%s", arg);
- } else {
- Com_sprintf (name, sizeof(name), "%s", arg);
- }
-
- if (!(systemBits & CIN_system)) {
- for ( i = 0 ; i < MAX_VIDEO_HANDLES ; i++ ) {
- if (!strcmp(cinTable[i].fileName, name) ) {
- return i;
- }
- }
- }
-
- Com_DPrintf("SCR_PlayCinematic( %s )\n", arg);
-
- Com_Memset(&cin, 0, sizeof(cinematics_t) );
- currentHandle = CIN_HandleForVideo();
-
- cin.currentHandle = currentHandle;
-
- strcpy(cinTable[currentHandle].fileName, name);
-
- cinTable[currentHandle].ROQSize = 0;
- cinTable[currentHandle].ROQSize = FS_FOpenFileRead (cinTable[currentHandle].fileName, &cinTable[currentHandle].iFile, qtrue);
-
- if (cinTable[currentHandle].ROQSize<=0) {
- Com_DPrintf("play(%s), ROQSize<=0\n", arg);
- cinTable[currentHandle].fileName[0] = 0;
- return -1;
- }
-
- CIN_SetExtents(currentHandle, x, y, w, h);
- CIN_SetLooping(currentHandle, (systemBits & CIN_loop)!=0);
-
- cinTable[currentHandle].CIN_HEIGHT = DEFAULT_CIN_HEIGHT;
- cinTable[currentHandle].CIN_WIDTH = DEFAULT_CIN_WIDTH;
- cinTable[currentHandle].holdAtEnd = (systemBits & CIN_hold) != 0;
- cinTable[currentHandle].alterGameState = (systemBits & CIN_system) != 0;
- cinTable[currentHandle].playonwalls = 1;
- cinTable[currentHandle].silent = (systemBits & CIN_silent) != 0;
- cinTable[currentHandle].shader = (systemBits & CIN_shader) != 0;
-
- if (cinTable[currentHandle].alterGameState) {
- // close the menu
- if ( uivm ) {
- VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_NONE );
- }
- } else {
- cinTable[currentHandle].playonwalls = cl_inGameVideo->integer;
- }
-
- initRoQ();
-
- FS_Read (cin.file, 16, cinTable[currentHandle].iFile);
-
- RoQID = (unsigned short)(cin.file[0]) + (unsigned short)(cin.file[1])*256;
- if (RoQID == 0x1084)
- {
- RoQ_init();
-// FS_Read (cin.file, cinTable[currentHandle].RoQFrameSize+8, cinTable[currentHandle].iFile);
-
- cinTable[currentHandle].status = FMV_PLAY;
- Com_DPrintf("trFMV::play(), playing %s\n", arg);
-
- if (cinTable[currentHandle].alterGameState) {
- cls.state = CA_CINEMATIC;
- }
-
- Con_Close();
-
- s_rawend[0] = s_soundtime;
-
- return currentHandle;
- }
- Com_DPrintf("trFMV::play(), invalid RoQ ID\n");
-
- RoQShutdown();
- return -1;
-}
-
-void CIN_SetExtents (int handle, int x, int y, int w, int h) {
- if (handle < 0 || handle>= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return;
- cinTable[handle].xpos = x;
- cinTable[handle].ypos = y;
- cinTable[handle].width = w;
- cinTable[handle].height = h;
- cinTable[handle].dirty = qtrue;
-}
-
-void CIN_SetLooping(int handle, qboolean loop) {
- if (handle < 0 || handle>= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return;
- cinTable[handle].looping = loop;
-}
-
-/*
-==================
-SCR_DrawCinematic
-
-==================
-*/
-void CIN_DrawCinematic (int handle) {
- float x, y, w, h;
- byte *buf;
-
- if (handle < 0 || handle>= MAX_VIDEO_HANDLES || cinTable[handle].status == FMV_EOF) return;
-
- if (!cinTable[handle].buf) {
- return;
- }
-
- x = cinTable[handle].xpos;
- y = cinTable[handle].ypos;
- w = cinTable[handle].width;
- h = cinTable[handle].height;
- buf = cinTable[handle].buf;
- SCR_AdjustFrom640( &x, &y, &w, &h );
-
- if (cinTable[handle].dirty && (cinTable[handle].CIN_WIDTH != cinTable[handle].drawX || cinTable[handle].CIN_HEIGHT != cinTable[handle].drawY)) {
- int ix, iy, *buf2, *buf3, xm, ym, ll;
-
- xm = cinTable[handle].CIN_WIDTH/256;
- ym = cinTable[handle].CIN_HEIGHT/256;
- ll = 8;
- if (cinTable[handle].CIN_WIDTH==512) {
- ll = 9;
- }
-
- buf3 = (int*)buf;
- buf2 = Hunk_AllocateTempMemory( 256*256*4 );
- if (xm==2 && ym==2) {
- byte *bc2, *bc3;
- int ic, iiy;
-
- bc2 = (byte *)buf2;
- bc3 = (byte *)buf3;
- for (iy = 0; iy<256; iy++) {
- iiy = iy<<12;
- for (ix = 0; ix<2048; ix+=8) {
- for(ic = ix;ic<(ix+4);ic++) {
- *bc2=(bc3[iiy+ic]+bc3[iiy+4+ic]+bc3[iiy+2048+ic]+bc3[iiy+2048+4+ic])>>2;
- bc2++;
- }
- }
- }
- } else if (xm==2 && ym==1) {
- byte *bc2, *bc3;
- int ic, iiy;
-
- bc2 = (byte *)buf2;
- bc3 = (byte *)buf3;
- for (iy = 0; iy<256; iy++) {
- iiy = iy<<11;
- for (ix = 0; ix<2048; ix+=8) {
- for(ic = ix;ic<(ix+4);ic++) {
- *bc2=(bc3[iiy+ic]+bc3[iiy+4+ic])>>1;
- bc2++;
- }
- }
- }
- } else {
- for (iy = 0; iy<256; iy++) {
- for (ix = 0; ix<256; ix++) {
- buf2[(iy<<8)+ix] = buf3[((iy*ym)<<ll) + (ix*xm)];
- }
- }
- }
- re.DrawStretchRaw( x, y, w, h, 256, 256, (byte *)buf2, handle, qtrue);
- cinTable[handle].dirty = qfalse;
- Hunk_FreeTempMemory(buf2);
- return;
- }
-
- re.DrawStretchRaw( x, y, w, h, cinTable[handle].drawX, cinTable[handle].drawY, buf, handle, cinTable[handle].dirty);
- cinTable[handle].dirty = qfalse;
-}
-
-void CL_PlayCinematic_f(void) {
- char *arg, *s;
- qboolean holdatend;
- int bits = CIN_system;
-
- Com_DPrintf("CL_PlayCinematic_f\n");
- if (cls.state == CA_CINEMATIC) {
- SCR_StopCinematic();
- }
-
- arg = Cmd_Argv( 1 );
- s = Cmd_Argv(2);
-
- holdatend = qfalse;
- if ((s && s[0] == '1') || Q_stricmp(arg,"demoend.roq")==0 || Q_stricmp(arg,"end.roq")==0) {
- bits |= CIN_hold;
- }
- if (s && s[0] == '2') {
- bits |= CIN_loop;
- }
-
- S_StopAllSounds ();
-
- CL_handle = CIN_PlayCinematic( arg, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, bits );
- if (CL_handle >= 0) {
- do {
- SCR_RunCinematic();
- } while (cinTable[currentHandle].buf == NULL && cinTable[currentHandle].status == FMV_PLAY); // wait for first frame (load codebook and sound)
- }
-}
-
-
-void SCR_DrawCinematic (void) {
- if (CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES) {
- CIN_DrawCinematic(CL_handle);
- }
-}
-
-void SCR_RunCinematic (void)
-{
- if (CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES) {
- CIN_RunCinematic(CL_handle);
- }
-}
-
-void SCR_StopCinematic(void) {
- if (CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES) {
- CIN_StopCinematic(CL_handle);
- S_StopAllSounds ();
- CL_handle = -1;
- }
-}
-
-void CIN_UploadCinematic(int handle) {
- if (handle >= 0 && handle < MAX_VIDEO_HANDLES) {
- if (!cinTable[handle].buf) {
- return;
- }
- if (cinTable[handle].playonwalls <= 0 && cinTable[handle].dirty) {
- if (cinTable[handle].playonwalls == 0) {
- cinTable[handle].playonwalls = -1;
- } else {
- if (cinTable[handle].playonwalls == -1) {
- cinTable[handle].playonwalls = -2;
- } else {
- cinTable[handle].dirty = qfalse;
- }
- }
- }
- re.UploadCinematic( 256, 256, 256, 256, cinTable[handle].buf, handle, cinTable[handle].dirty);
- if (cl_inGameVideo->integer == 0 && cinTable[handle].playonwalls == 1) {
- cinTable[handle].playonwalls--;
- }
- }
-}
-
diff --git a/engine/code/client/cl_console.c b/engine/code/client/cl_console.c
deleted file mode 100644
index da575a3..0000000
--- a/engine/code/client/cl_console.c
+++ /dev/null
@@ -1,795 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// console.c
-
-#include "client.h"
-
-
-int g_console_field_width = 78;
-
-
-#define NUM_CON_TIMES 4
-
-#define CON_TEXTSIZE 32768
-typedef struct {
- qboolean initialized;
-
- short text[CON_TEXTSIZE];
- int current; // line where next message will be printed
- int x; // offset in current line for next print
- int display; // bottom of console displays this line
-
- int linewidth; // characters across screen
- int totallines; // total lines in console scrollback
-
- float xadjust; // for wide aspect screens
-
- float displayFrac; // aproaches finalFrac at scr_conspeed
- float finalFrac; // 0.0 to 1.0 lines of console to display
-
- int vislines; // in scanlines
-
- int times[NUM_CON_TIMES]; // cls.realtime time the line was generated
- // for transparent notify lines
- vec4_t color;
-} console_t;
-
-extern console_t con;
-
-console_t con;
-
-cvar_t *con_conspeed;
-cvar_t *con_notifytime;
-
-#define DEFAULT_CONSOLE_WIDTH 78
-
-vec4_t console_color = {1.0, 1.0, 1.0, 1.0};
-
-
-/*
-================
-Con_ToggleConsole_f
-================
-*/
-void Con_ToggleConsole_f (void) {
- // Can't toggle the console when it's the only thing available
- if ( cls.state == CA_DISCONNECTED && Key_GetCatcher( ) == KEYCATCH_CONSOLE ) {
- return;
- }
-
- Field_Clear( &g_consoleField );
- g_consoleField.widthInChars = g_console_field_width;
-
- Con_ClearNotify ();
- Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_CONSOLE );
-}
-
-/*
-================
-Con_MessageMode_f
-================
-*/
-void Con_MessageMode_f (void) {
- chat_playerNum = -1;
- chat_team = qfalse;
- Field_Clear( &chatField );
- chatField.widthInChars = 30;
-
- Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
-}
-
-/*
-================
-Con_MessageMode2_f
-================
-*/
-void Con_MessageMode2_f (void) {
- chat_playerNum = -1;
- chat_team = qtrue;
- Field_Clear( &chatField );
- chatField.widthInChars = 25;
- Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
-}
-
-/*
-================
-Con_MessageMode3_f
-================
-*/
-void Con_MessageMode3_f (void) {
- chat_playerNum = VM_Call( cgvm, CG_CROSSHAIR_PLAYER );
- if ( chat_playerNum < 0 || chat_playerNum >= MAX_CLIENTS ) {
- chat_playerNum = -1;
- return;
- }
- chat_team = qfalse;
- Field_Clear( &chatField );
- chatField.widthInChars = 30;
- Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
-}
-
-/*
-================
-Con_MessageMode4_f
-================
-*/
-void Con_MessageMode4_f (void) {
- chat_playerNum = VM_Call( cgvm, CG_LAST_ATTACKER );
- if ( chat_playerNum < 0 || chat_playerNum >= MAX_CLIENTS ) {
- chat_playerNum = -1;
- return;
- }
- chat_team = qfalse;
- Field_Clear( &chatField );
- chatField.widthInChars = 30;
- Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
-}
-
-/*
-================
-Con_Clear_f
-================
-*/
-void Con_Clear_f (void) {
- int i;
-
- for ( i = 0 ; i < CON_TEXTSIZE ; i++ ) {
- con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
- }
-
- Con_Bottom(); // go to end
-}
-
-
-/*
-================
-Con_Dump_f
-
-Save the console contents out to a file
-================
-*/
-void Con_Dump_f (void)
-{
- int l, x, i;
- short *line;
- fileHandle_t f;
- char buffer[1024];
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("usage: condump <filename>\n");
- return;
- }
-
- Com_Printf ("Dumped console text to %s.\n", Cmd_Argv(1) );
-
- f = FS_FOpenFileWrite( Cmd_Argv( 1 ) );
- if (!f)
- {
- Com_Printf ("ERROR: couldn't open.\n");
- return;
- }
-
- // skip empty lines
- for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
- {
- line = con.text + (l%con.totallines)*con.linewidth;
- for (x=0 ; x<con.linewidth ; x++)
- if ((line[x] & 0xff) != ' ')
- break;
- if (x != con.linewidth)
- break;
- }
-
- // write the remaining lines
- buffer[con.linewidth] = 0;
- for ( ; l <= con.current ; l++)
- {
- line = con.text + (l%con.totallines)*con.linewidth;
- for(i=0; i<con.linewidth; i++)
- buffer[i] = line[i] & 0xff;
- for (x=con.linewidth-1 ; x>=0 ; x--)
- {
- if (buffer[x] == ' ')
- buffer[x] = 0;
- else
- break;
- }
- strcat( buffer, "\n" );
- FS_Write(buffer, strlen(buffer), f);
- }
-
- FS_FCloseFile( f );
-}
-
-
-/*
-================
-Con_ClearNotify
-================
-*/
-void Con_ClearNotify( void ) {
- int i;
-
- for ( i = 0 ; i < NUM_CON_TIMES ; i++ ) {
- con.times[i] = 0;
- }
-}
-
-
-
-/*
-================
-Con_CheckResize
-
-If the line width has changed, reformat the buffer.
-================
-*/
-void Con_CheckResize (void)
-{
- int i, j, width, oldwidth, oldtotallines, numlines, numchars;
- short tbuf[CON_TEXTSIZE];
-
- width = (SCREEN_WIDTH / SMALLCHAR_WIDTH) - 2;
-
- if (width == con.linewidth)
- return;
-
- if (width < 1) // video hasn't been initialized yet
- {
- width = DEFAULT_CONSOLE_WIDTH;
- con.linewidth = width;
- con.totallines = CON_TEXTSIZE / con.linewidth;
- for(i=0; i<CON_TEXTSIZE; i++)
-
- con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
- }
- else
- {
- oldwidth = con.linewidth;
- con.linewidth = width;
- oldtotallines = con.totallines;
- con.totallines = CON_TEXTSIZE / con.linewidth;
- numlines = oldtotallines;
-
- if (con.totallines < numlines)
- numlines = con.totallines;
-
- numchars = oldwidth;
-
- if (con.linewidth < numchars)
- numchars = con.linewidth;
-
- Com_Memcpy (tbuf, con.text, CON_TEXTSIZE * sizeof(short));
- for(i=0; i<CON_TEXTSIZE; i++)
-
- con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
-
-
- for (i=0 ; i<numlines ; i++)
- {
- for (j=0 ; j<numchars ; j++)
- {
- con.text[(con.totallines - 1 - i) * con.linewidth + j] =
- tbuf[((con.current - i + oldtotallines) %
- oldtotallines) * oldwidth + j];
- }
- }
-
- Con_ClearNotify ();
- }
-
- con.current = con.totallines - 1;
- con.display = con.current;
-}
-
-/*
-==================
-Cmd_CompleteTxtName
-==================
-*/
-void Cmd_CompleteTxtName( char *args, int argNum ) {
- if( argNum == 2 ) {
- Field_CompleteFilename( "", "txt", qfalse );
- }
-}
-
-
-/*
-================
-Con_Init
-================
-*/
-void Con_Init (void) {
- int i;
-
- con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
- con_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
-
- Field_Clear( &g_consoleField );
- g_consoleField.widthInChars = g_console_field_width;
- for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) {
- Field_Clear( &historyEditLines[i] );
- historyEditLines[i].widthInChars = g_console_field_width;
- }
- CL_LoadConsoleHistory( );
-
- Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
- Cmd_AddCommand ("messagemode", Con_MessageMode_f);
- Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
- Cmd_AddCommand ("messagemode3", Con_MessageMode3_f);
- Cmd_AddCommand ("messagemode4", Con_MessageMode4_f);
- Cmd_AddCommand ("clear", Con_Clear_f);
- Cmd_AddCommand ("condump", Con_Dump_f);
- Cmd_SetCommandCompletionFunc( "condump", Cmd_CompleteTxtName );
-}
-
-
-/*
-===============
-Con_Linefeed
-===============
-*/
-void Con_Linefeed (qboolean skipnotify)
-{
- int i;
-
- // mark time for transparent overlay
- if (con.current >= 0)
- {
- if (skipnotify)
- con.times[con.current % NUM_CON_TIMES] = 0;
- else
- con.times[con.current % NUM_CON_TIMES] = cls.realtime;
- }
-
- con.x = 0;
- if (con.display == con.current)
- con.display++;
- con.current++;
- for(i=0; i<con.linewidth; i++)
- con.text[(con.current%con.totallines)*con.linewidth+i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
-}
-
-/*
-================
-CL_ConsolePrint
-
-Handles cursor positioning, line wrapping, etc
-All console printing must go through this in order to be logged to disk
-If no console is visible, the text will appear at the top of the game window
-================
-*/
-void CL_ConsolePrint( char *txt ) {
- int y;
- int c, l;
- int color;
- qboolean skipnotify = qfalse; // NERVE - SMF
- int prev; // NERVE - SMF
-
- // TTimo - prefix for text that shows up in console but not in notify
- // backported from RTCW
- if ( !Q_strncmp( txt, "[skipnotify]", 12 ) ) {
- skipnotify = qtrue;
- txt += 12;
- }
-
- // for some demos we don't want to ever show anything on the console
- if ( cl_noprint && cl_noprint->integer ) {
- return;
- }
-
- if (!con.initialized) {
- con.color[0] =
- con.color[1] =
- con.color[2] =
- con.color[3] = 1.0f;
- con.linewidth = -1;
- Con_CheckResize ();
- con.initialized = qtrue;
- }
-
- color = ColorIndex(COLOR_WHITE);
-
- while ( (c = *txt) != 0 ) {
- if ( Q_IsColorString( txt ) ) {
- color = ColorIndex( *(txt+1) );
- txt += 2;
- continue;
- }
-
- // count word length
- for (l=0 ; l< con.linewidth ; l++) {
- if ( txt[l] <= ' ') {
- break;
- }
-
- }
-
- // word wrap
- if (l != con.linewidth && (con.x + l >= con.linewidth) ) {
- Con_Linefeed(skipnotify);
-
- }
-
- txt++;
-
- switch (c)
- {
- case '\n':
- Con_Linefeed (skipnotify);
- break;
- case '\r':
- con.x = 0;
- break;
- default: // display character and advance
- y = con.current % con.totallines;
- con.text[y*con.linewidth+con.x] = (color << 8) | c;
- con.x++;
- if (con.x >= con.linewidth) {
- Con_Linefeed(skipnotify);
- con.x = 0;
- }
- break;
- }
- }
-
-
- // mark time for transparent overlay
- if (con.current >= 0) {
- // NERVE - SMF
- if ( skipnotify ) {
- prev = con.current % NUM_CON_TIMES - 1;
- if ( prev < 0 )
- prev = NUM_CON_TIMES - 1;
- con.times[prev] = 0;
- }
- else
- // -NERVE - SMF
- con.times[con.current % NUM_CON_TIMES] = cls.realtime;
- }
-}
-
-
-/*
-==============================================================================
-
-DRAWING
-
-==============================================================================
-*/
-
-
-/*
-================
-Con_DrawInput
-
-Draw the editline after a ] prompt
-================
-*/
-void Con_DrawInput (void) {
- int y;
-
- if ( cls.state != CA_DISCONNECTED && !(Key_GetCatcher( ) & KEYCATCH_CONSOLE ) ) {
- return;
- }
-
- y = con.vislines - ( SMALLCHAR_HEIGHT * 2 );
-
- re.SetColor( con.color );
-
- SCR_DrawSmallChar( con.xadjust + 1 * SMALLCHAR_WIDTH, y, ']' );
-
- Field_Draw( &g_consoleField, con.xadjust + 2 * SMALLCHAR_WIDTH, y,
- SCREEN_WIDTH - 3 * SMALLCHAR_WIDTH, qtrue, qtrue );
-}
-
-
-/*
-================
-Con_DrawNotify
-
-Draws the last few lines of output transparently over the game top
-================
-*/
-void Con_DrawNotify (void)
-{
- int x, v;
- short *text;
- int i;
- int time;
- int skip;
- int currentColor;
-
- currentColor = 7;
- re.SetColor( g_color_table[currentColor] );
-
- v = 0;
- for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
- {
- if (i < 0)
- continue;
- time = con.times[i % NUM_CON_TIMES];
- if (time == 0)
- continue;
- time = cls.realtime - time;
- if (time > con_notifytime->value*1000)
- continue;
- text = con.text + (i % con.totallines)*con.linewidth;
-
- if (cl.snap.ps.pm_type != PM_INTERMISSION && Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME) ) {
- continue;
- }
-
- for (x = 0 ; x < con.linewidth ; x++) {
- if ( ( text[x] & 0xff ) == ' ' ) {
- continue;
- }
- if ( ( (text[x]>>8)&7 ) != currentColor ) {
- currentColor = (text[x]>>8)&7;
- re.SetColor( g_color_table[currentColor] );
- }
- SCR_DrawSmallChar( cl_conXOffset->integer + con.xadjust + (x+1)*SMALLCHAR_WIDTH, v, text[x] & 0xff );
- }
-
- v += SMALLCHAR_HEIGHT;
- }
-
- re.SetColor( NULL );
-
- if (Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME) ) {
- return;
- }
-
- // draw the chat line
- if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE )
- {
- if (chat_team)
- {
- SCR_DrawBigString (8, v, "say_team:", 1.0f, qfalse );
- skip = 10;
- }
- else
- {
- SCR_DrawBigString (8, v, "say:", 1.0f, qfalse );
- skip = 5;
- }
-
- Field_BigDraw( &chatField, skip * BIGCHAR_WIDTH, v,
- SCREEN_WIDTH - ( skip + 1 ) * BIGCHAR_WIDTH, qtrue, qtrue );
-
- v += BIGCHAR_HEIGHT;
- }
-
-}
-
-/*
-================
-Con_DrawSolidConsole
-
-Draws the console with the solid background
-================
-*/
-void Con_DrawSolidConsole( float frac ) {
- int i, x, y;
- int rows;
- short *text;
- int row;
- int lines;
-// qhandle_t conShader;
- int currentColor;
- vec4_t color;
-
- lines = cls.glconfig.vidHeight * frac;
- if (lines <= 0)
- return;
-
- if (lines > cls.glconfig.vidHeight )
- lines = cls.glconfig.vidHeight;
-
- // on wide screens, we will center the text
- con.xadjust = 0;
- SCR_AdjustFrom640( &con.xadjust, NULL, NULL, NULL );
-
- // draw the background
- y = frac * SCREEN_HEIGHT;
- if ( y < 1 ) {
- y = 0;
- }
- else {
- SCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.consoleShader );
- }
-
- color[0] = 1;
- color[1] = 0;
- color[2] = 0;
- color[3] = 1;
- SCR_FillRect( 0, y, SCREEN_WIDTH, 2, color );
-
-
- // draw the version number
-
- re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );
-
- i = strlen( Q3_VERSION );
-
- for (x=0 ; x<i ; x++) {
- SCR_DrawSmallChar( cls.glconfig.vidWidth - ( i - x + 1 ) * SMALLCHAR_WIDTH,
- lines - SMALLCHAR_HEIGHT, Q3_VERSION[x] );
- }
-
-
- // draw the text
- con.vislines = lines;
- rows = (lines-SMALLCHAR_WIDTH)/SMALLCHAR_WIDTH; // rows of text to draw
-
- y = lines - (SMALLCHAR_HEIGHT*3);
-
- // draw from the bottom up
- if (con.display != con.current)
- {
- // draw arrows to show the buffer is backscrolled
- re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );
- for (x=0 ; x<con.linewidth ; x+=4)
- SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, '^' );
- y -= SMALLCHAR_HEIGHT;
- rows--;
- }
-
- row = con.display;
-
- if ( con.x == 0 ) {
- row--;
- }
-
- currentColor = 7;
- re.SetColor( g_color_table[currentColor] );
-
- for (i=0 ; i<rows ; i++, y -= SMALLCHAR_HEIGHT, row--)
- {
- if (row < 0)
- break;
- if (con.current - row >= con.totallines) {
- // past scrollback wrap point
- continue;
- }
-
- text = con.text + (row % con.totallines)*con.linewidth;
-
- for (x=0 ; x<con.linewidth ; x++) {
- if ( ( text[x] & 0xff ) == ' ' ) {
- continue;
- }
-
- if ( ( (text[x]>>8)&7 ) != currentColor ) {
- currentColor = (text[x]>>8)&7;
- re.SetColor( g_color_table[currentColor] );
- }
- SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, text[x] & 0xff );
- }
- }
-
- // draw the input prompt, user text, and cursor if desired
- Con_DrawInput ();
-
- re.SetColor( NULL );
-}
-
-
-
-/*
-==================
-Con_DrawConsole
-==================
-*/
-void Con_DrawConsole( void ) {
- // check for console width changes from a vid mode change
- Con_CheckResize ();
-
- // if disconnected, render console full screen
- if ( cls.state == CA_DISCONNECTED ) {
- if ( !( Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME)) ) {
- Con_DrawSolidConsole( 1.0 );
- return;
- }
- }
-
- if ( con.displayFrac ) {
- Con_DrawSolidConsole( con.displayFrac );
- } else {
- // draw notify lines
- if ( cls.state == CA_ACTIVE ) {
- Con_DrawNotify ();
- }
- }
-}
-
-//================================================================
-
-/*
-==================
-Con_RunConsole
-
-Scroll it up or down
-==================
-*/
-void Con_RunConsole (void) {
- // decide on the destination height of the console
- if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE )
- con.finalFrac = 0.5; // half screen
- else
- con.finalFrac = 0; // none visible
-
- // scroll towards the destination height
- if (con.finalFrac < con.displayFrac)
- {
- con.displayFrac -= con_conspeed->value*cls.realFrametime*0.001;
- if (con.finalFrac > con.displayFrac)
- con.displayFrac = con.finalFrac;
-
- }
- else if (con.finalFrac > con.displayFrac)
- {
- con.displayFrac += con_conspeed->value*cls.realFrametime*0.001;
- if (con.finalFrac < con.displayFrac)
- con.displayFrac = con.finalFrac;
- }
-
-}
-
-
-void Con_PageUp( void ) {
- con.display -= 2;
- if ( con.current - con.display >= con.totallines ) {
- con.display = con.current - con.totallines + 1;
- }
-}
-
-void Con_PageDown( void ) {
- con.display += 2;
- if (con.display > con.current) {
- con.display = con.current;
- }
-}
-
-void Con_Top( void ) {
- con.display = con.totallines;
- if ( con.current - con.display >= con.totallines ) {
- con.display = con.current - con.totallines + 1;
- }
-}
-
-void Con_Bottom( void ) {
- con.display = con.current;
-}
-
-
-void Con_Close( void ) {
- if ( !com_cl_running->integer ) {
- return;
- }
- Field_Clear( &g_consoleField );
- Con_ClearNotify ();
- Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CONSOLE );
- con.finalFrac = 0; // none visible
- con.displayFrac = 0;
-}
diff --git a/engine/code/client/cl_curl.c b/engine/code/client/cl_curl.c
deleted file mode 100644
index 170e97b..0000000
--- a/engine/code/client/cl_curl.c
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 2006 Tony J. White (tjw at tjw.org)
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#ifdef USE_CURL
-#include "client.h"
-cvar_t *cl_cURLLib;
-
-#ifdef USE_CURL_DLOPEN
-#include "../sys/sys_loadlib.h"
-
-char* (*qcurl_version)(void);
-
-CURL* (*qcurl_easy_init)(void);
-CURLcode (*qcurl_easy_setopt)(CURL *curl, CURLoption option, ...);
-CURLcode (*qcurl_easy_perform)(CURL *curl);
-void (*qcurl_easy_cleanup)(CURL *curl);
-CURLcode (*qcurl_easy_getinfo)(CURL *curl, CURLINFO info, ...);
-CURL* (*qcurl_easy_duphandle)(CURL *curl);
-void (*qcurl_easy_reset)(CURL *curl);
-const char *(*qcurl_easy_strerror)(CURLcode);
-
-CURLM* (*qcurl_multi_init)(void);
-CURLMcode (*qcurl_multi_add_handle)(CURLM *multi_handle,
- CURL *curl_handle);
-CURLMcode (*qcurl_multi_remove_handle)(CURLM *multi_handle,
- CURL *curl_handle);
-CURLMcode (*qcurl_multi_fdset)(CURLM *multi_handle,
- fd_set *read_fd_set,
- fd_set *write_fd_set,
- fd_set *exc_fd_set,
- int *max_fd);
-CURLMcode (*qcurl_multi_perform)(CURLM *multi_handle,
- int *running_handles);
-CURLMcode (*qcurl_multi_cleanup)(CURLM *multi_handle);
-CURLMsg *(*qcurl_multi_info_read)(CURLM *multi_handle,
- int *msgs_in_queue);
-const char *(*qcurl_multi_strerror)(CURLMcode);
-
-static void *cURLLib = NULL;
-
-/*
-=================
-GPA
-=================
-*/
-static void *GPA(char *str)
-{
- void *rv;
-
- rv = Sys_LoadFunction(cURLLib, str);
- if(!rv)
- {
- Com_Printf("Can't load symbol %s\n", str);
- clc.cURLEnabled = qfalse;
- return NULL;
- }
- else
- {
- Com_DPrintf("Loaded symbol %s (0x%p)\n", str, rv);
- return rv;
- }
-}
-#endif /* USE_CURL_DLOPEN */
-
-/*
-=================
-CL_cURL_Init
-=================
-*/
-qboolean CL_cURL_Init()
-{
-#ifdef USE_CURL_DLOPEN
- if(cURLLib)
- return qtrue;
-
-
- Com_Printf("Loading \"%s\"...", cl_cURLLib->string);
- if( (cURLLib = Sys_LoadLibrary(cl_cURLLib->string)) == 0 )
- {
-#ifdef _WIN32
- return qfalse;
-#else
- char fn[1024];
-
- Q_strncpyz( fn, Sys_Cwd( ), sizeof( fn ) );
- strncat(fn, "/", sizeof(fn)-strlen(fn)-1);
- strncat(fn, cl_cURLLib->string, sizeof(fn)-strlen(fn)-1);
-
- if((cURLLib = Sys_LoadLibrary(fn)) == 0)
- {
-#ifdef ALTERNATE_CURL_LIB
- // On some linux distributions there is no libcurl.so.3, but only libcurl.so.4. That one works too.
- if( (cURLLib = Sys_LoadLibrary(ALTERNATE_CURL_LIB)) == 0 )
- {
- return qfalse;
- }
-#else
- return qfalse;
-#endif
- }
-#endif /* _WIN32 */
- }
-
- clc.cURLEnabled = qtrue;
-
- qcurl_version = GPA("curl_version");
-
- qcurl_easy_init = GPA("curl_easy_init");
- qcurl_easy_setopt = GPA("curl_easy_setopt");
- qcurl_easy_perform = GPA("curl_easy_perform");
- qcurl_easy_cleanup = GPA("curl_easy_cleanup");
- qcurl_easy_getinfo = GPA("curl_easy_getinfo");
- qcurl_easy_duphandle = GPA("curl_easy_duphandle");
- qcurl_easy_reset = GPA("curl_easy_reset");
- qcurl_easy_strerror = GPA("curl_easy_strerror");
-
- qcurl_multi_init = GPA("curl_multi_init");
- qcurl_multi_add_handle = GPA("curl_multi_add_handle");
- qcurl_multi_remove_handle = GPA("curl_multi_remove_handle");
- qcurl_multi_fdset = GPA("curl_multi_fdset");
- qcurl_multi_perform = GPA("curl_multi_perform");
- qcurl_multi_cleanup = GPA("curl_multi_cleanup");
- qcurl_multi_info_read = GPA("curl_multi_info_read");
- qcurl_multi_strerror = GPA("curl_multi_strerror");
-
- if(!clc.cURLEnabled)
- {
- CL_cURL_Shutdown();
- Com_Printf("FAIL One or more symbols not found\n");
- return qfalse;
- }
- Com_Printf("OK\n");
-
- return qtrue;
-#else
- clc.cURLEnabled = qtrue;
- return qtrue;
-#endif /* USE_CURL_DLOPEN */
-}
-
-/*
-=================
-CL_cURL_Shutdown
-=================
-*/
-void CL_cURL_Shutdown( void )
-{
- CL_cURL_Cleanup();
-#ifdef USE_CURL_DLOPEN
- if(cURLLib)
- {
- Sys_UnloadLibrary(cURLLib);
- cURLLib = NULL;
- }
- qcurl_easy_init = NULL;
- qcurl_easy_setopt = NULL;
- qcurl_easy_perform = NULL;
- qcurl_easy_cleanup = NULL;
- qcurl_easy_getinfo = NULL;
- qcurl_easy_duphandle = NULL;
- qcurl_easy_reset = NULL;
-
- qcurl_multi_init = NULL;
- qcurl_multi_add_handle = NULL;
- qcurl_multi_remove_handle = NULL;
- qcurl_multi_fdset = NULL;
- qcurl_multi_perform = NULL;
- qcurl_multi_cleanup = NULL;
- qcurl_multi_info_read = NULL;
- qcurl_multi_strerror = NULL;
-#endif /* USE_CURL_DLOPEN */
-}
-
-void CL_cURL_Cleanup(void)
-{
- if(clc.downloadCURLM) {
- if(clc.downloadCURL) {
- qcurl_multi_remove_handle(clc.downloadCURLM,
- clc.downloadCURL);
- qcurl_easy_cleanup(clc.downloadCURL);
- }
- qcurl_multi_cleanup(clc.downloadCURLM);
- clc.downloadCURLM = NULL;
- clc.downloadCURL = NULL;
- }
- else if(clc.downloadCURL) {
- qcurl_easy_cleanup(clc.downloadCURL);
- clc.downloadCURL = NULL;
- }
-}
-
-static int CL_cURL_CallbackProgress( void *dummy, double dltotal, double dlnow,
- double ultotal, double ulnow )
-{
- clc.downloadSize = (int)dltotal;
- Cvar_SetValue( "cl_downloadSize", clc.downloadSize );
- clc.downloadCount = (int)dlnow;
- Cvar_SetValue( "cl_downloadCount", clc.downloadCount );
- return 0;
-}
-
-static size_t CL_cURL_CallbackWrite(void *buffer, size_t size, size_t nmemb,
- void *stream)
-{
- FS_Write( buffer, size*nmemb, ((fileHandle_t*)stream)[0] );
- return size*nmemb;
-}
-
-void CL_cURL_BeginDownload( const char *localName, const char *remoteURL )
-{
- clc.cURLUsed = qtrue;
- Com_Printf("URL: %s\n", remoteURL);
- Com_DPrintf("***** CL_cURL_BeginDownload *****\n"
- "Localname: %s\n"
- "RemoteURL: %s\n"
- "****************************\n", localName, remoteURL);
- CL_cURL_Cleanup();
- Q_strncpyz(clc.downloadURL, remoteURL, sizeof(clc.downloadURL));
- Q_strncpyz(clc.downloadName, localName, sizeof(clc.downloadName));
- Com_sprintf(clc.downloadTempName, sizeof(clc.downloadTempName),
- "%s.tmp", localName);
-
- // Set so UI gets access to it
- Cvar_Set("cl_downloadName", localName);
- Cvar_Set("cl_downloadSize", "0");
- Cvar_Set("cl_downloadCount", "0");
- Cvar_SetValue("cl_downloadTime", cls.realtime);
-
- clc.downloadBlock = 0; // Starting new file
- clc.downloadCount = 0;
-
- clc.downloadCURL = qcurl_easy_init();
- if(!clc.downloadCURL) {
- Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_easy_init() "
- "failed\n");
- return;
- }
- clc.download = FS_SV_FOpenFileWrite(clc.downloadTempName);
- if(!clc.download) {
- Com_Error(ERR_DROP, "CL_cURL_BeginDownload: failed to open "
- "%s for writing\n", clc.downloadTempName);
- return;
- }
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEDATA, clc.download);
- if(com_developer->integer)
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_VERBOSE, 1);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_URL, clc.downloadURL);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_TRANSFERTEXT, 0);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_REFERER, va("ioQ3://%s",
- NET_AdrToString(clc.serverAddress)));
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_USERAGENT, va("%s %s",
- Q3_VERSION, qcurl_version()));
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEFUNCTION,
- CL_cURL_CallbackWrite);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEDATA, &clc.download);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_NOPROGRESS, 0);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_PROGRESSFUNCTION,
- CL_cURL_CallbackProgress);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_PROGRESSDATA, NULL);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_FAILONERROR, 1);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_FOLLOWLOCATION, 1);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_MAXREDIRS, 5);
- clc.downloadCURLM = qcurl_multi_init();
- if(!clc.downloadCURLM) {
- qcurl_easy_cleanup(clc.downloadCURL);
- clc.downloadCURL = NULL;
- Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_multi_init() "
- "failed\n");
- return;
- }
- qcurl_multi_add_handle(clc.downloadCURLM, clc.downloadCURL);
-
- if(!(clc.sv_allowDownload & DLF_NO_DISCONNECT) &&
- !clc.cURLDisconnected) {
-
- CL_AddReliableCommand("disconnect", qtrue);
- CL_WritePacket();
- CL_WritePacket();
- CL_WritePacket();
- clc.cURLDisconnected = qtrue;
- }
-}
-
-void CL_cURL_PerformDownload(void)
-{
- CURLMcode res;
- CURLMsg *msg;
- int c;
- int i = 0;
-
- res = qcurl_multi_perform(clc.downloadCURLM, &c);
- while(res == CURLM_CALL_MULTI_PERFORM && i < 100) {
- res = qcurl_multi_perform(clc.downloadCURLM, &c);
- i++;
- }
- if(res == CURLM_CALL_MULTI_PERFORM)
- return;
- msg = qcurl_multi_info_read(clc.downloadCURLM, &c);
- if(msg == NULL) {
- return;
- }
- FS_FCloseFile(clc.download);
- if(msg->msg == CURLMSG_DONE && msg->data.result == CURLE_OK) {
- FS_SV_Rename(clc.downloadTempName, clc.downloadName);
- clc.downloadRestart = qtrue;
- }
- else {
- long code;
-
- qcurl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE,
- &code);
- Com_Error(ERR_DROP, "Download Error: %s Code: %ld URL: %s",
- qcurl_easy_strerror(msg->data.result),
- code, clc.downloadURL);
- }
-
- CL_NextDownload();
-}
-#endif /* USE_CURL */
diff --git a/engine/code/client/cl_curl.h b/engine/code/client/cl_curl.h
deleted file mode 100644
index c8d3006..0000000
--- a/engine/code/client/cl_curl.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 2006 Tony J. White (tjw at tjw.org)
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-
-#ifndef __QCURL_H__
-#define __QCURL_H__
-
-extern cvar_t *cl_cURLLib;
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-
-#ifdef WIN32
-#define DEFAULT_CURL_LIB "libcurl-3.dll"
-#elif defined(MACOS_X)
-#define DEFAULT_CURL_LIB "libcurl.dylib"
-#else
-#define DEFAULT_CURL_LIB "libcurl.so.4"
-#define ALTERNATE_CURL_LIB "libcurl.so.3"
-#endif
-
-#ifdef USE_LOCAL_HEADERS
- #include "../libcurl/curl/curl.h"
-#else
- #include <curl/curl.h>
-#endif
-
-
-#ifdef USE_CURL_DLOPEN
-extern char* (*qcurl_version)(void);
-
-extern CURL* (*qcurl_easy_init)(void);
-extern CURLcode (*qcurl_easy_setopt)(CURL *curl, CURLoption option, ...);
-extern CURLcode (*qcurl_easy_perform)(CURL *curl);
-extern void (*qcurl_easy_cleanup)(CURL *curl);
-extern CURLcode (*qcurl_easy_getinfo)(CURL *curl, CURLINFO info, ...);
-extern void (*qcurl_easy_reset)(CURL *curl);
-extern const char *(*qcurl_easy_strerror)(CURLcode);
-
-extern CURLM* (*qcurl_multi_init)(void);
-extern CURLMcode (*qcurl_multi_add_handle)(CURLM *multi_handle,
- CURL *curl_handle);
-extern CURLMcode (*qcurl_multi_remove_handle)(CURLM *multi_handle,
- CURL *curl_handle);
-extern CURLMcode (*qcurl_multi_fdset)(CURLM *multi_handle,
- fd_set *read_fd_set,
- fd_set *write_fd_set,
- fd_set *exc_fd_set,
- int *max_fd);
-extern CURLMcode (*qcurl_multi_perform)(CURLM *multi_handle,
- int *running_handles);
-extern CURLMcode (*qcurl_multi_cleanup)(CURLM *multi_handle);
-extern CURLMsg *(*qcurl_multi_info_read)(CURLM *multi_handle,
- int *msgs_in_queue);
-extern const char *(*qcurl_multi_strerror)(CURLMcode);
-#else
-#define qcurl_version curl_version
-
-#define qcurl_easy_init curl_easy_init
-#define qcurl_easy_setopt curl_easy_setopt
-#define qcurl_easy_perform curl_easy_perform
-#define qcurl_easy_cleanup curl_easy_cleanup
-#define qcurl_easy_getinfo curl_easy_getinfo
-#define qcurl_easy_duphandle curl_easy_duphandle
-#define qcurl_easy_reset curl_easy_reset
-#define qcurl_easy_strerror curl_easy_strerror
-
-#define qcurl_multi_init curl_multi_init
-#define qcurl_multi_add_handle curl_multi_add_handle
-#define qcurl_multi_remove_handle curl_multi_remove_handle
-#define qcurl_multi_fdset curl_multi_fdset
-#define qcurl_multi_perform curl_multi_perform
-#define qcurl_multi_cleanup curl_multi_cleanup
-#define qcurl_multi_info_read curl_multi_info_read
-#define qcurl_multi_strerror curl_multi_strerror
-#endif
-
-qboolean CL_cURL_Init( void );
-void CL_cURL_Shutdown( void );
-void CL_cURL_BeginDownload( const char *localName, const char *remoteURL );
-void CL_cURL_PerformDownload( void );
-void CL_cURL_Cleanup( void );
-#endif // __QCURL_H__
diff --git a/engine/code/client/cl_input.c b/engine/code/client/cl_input.c
deleted file mode 100644
index a42030d..0000000
--- a/engine/code/client/cl_input.c
+++ /dev/null
@@ -1,1045 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// cl.input.c -- builds an intended movement command to send to the server
-
-#include "client.h"
-
-unsigned frame_msec;
-int old_com_frameTime;
-
-/*
-===============================================================================
-
-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 argv(1) so it can be matched up with the release.
-
-argv(2) will be set to the time the event happened, which allows exact
-control even at low framerates when the down and up events may both get qued
-at the same time.
-
-===============================================================================
-*/
-
-
-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;
-kbutton_t in_up, in_down;
-
-#ifdef USE_VOIP
-kbutton_t in_voiprecord;
-#endif
-
-kbutton_t in_buttons[16];
-
-
-qboolean in_mlooking;
-
-
-void IN_MLookDown( void ) {
- in_mlooking = qtrue;
-}
-
-void IN_MLookUp( void ) {
- in_mlooking = qfalse;
- if ( !cl_freelook->integer ) {
- IN_CenterView ();
- }
-}
-
-void IN_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 {
- Com_Printf ("Three keys down for a button!\n");
- return;
- }
-
- if ( b->active ) {
- return; // still down
- }
-
- // save timestamp for partial frame summing
- c = Cmd_Argv(2);
- b->downtime = atoi(c);
-
- b->active = qtrue;
- b->wasPressed = qtrue;
-}
-
-void IN_KeyUp( kbutton_t *b ) {
- int k;
- char *c;
- unsigned uptime;
-
- 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->active = qfalse;
- 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
- }
-
- b->active = qfalse;
-
- // save timestamp for partial frame summing
- c = Cmd_Argv(2);
- uptime = atoi(c);
- if ( uptime ) {
- b->msec += uptime - b->downtime;
- } else {
- b->msec += frame_msec / 2;
- }
-
- b->active = qfalse;
-}
-
-
-
-/*
-===============
-CL_KeyState
-
-Returns the fraction of the frame that the key was down
-===============
-*/
-float CL_KeyState( kbutton_t *key ) {
- float val;
- int msec;
-
- msec = key->msec;
- key->msec = 0;
-
- if ( key->active ) {
- // still down
- if ( !key->downtime ) {
- msec = com_frameTime;
- } else {
- msec += com_frameTime - key->downtime;
- }
- key->downtime = com_frameTime;
- }
-
-#if 0
- if (msec) {
- Com_Printf ("%i ", msec);
- }
-#endif
-
- val = (float)msec / frame_msec;
- if ( val < 0 ) {
- val = 0;
- }
- if ( val > 1 ) {
- val = 1;
- }
-
- return val;
-}
-
-
-
-void IN_UpDown(void) {IN_KeyDown(&in_up);}
-void IN_UpUp(void) {IN_KeyUp(&in_up);}
-void IN_DownDown(void) {IN_KeyDown(&in_down);}
-void IN_DownUp(void) {IN_KeyUp(&in_down);}
-void IN_LeftDown(void) {IN_KeyDown(&in_left);}
-void IN_LeftUp(void) {IN_KeyUp(&in_left);}
-void IN_RightDown(void) {IN_KeyDown(&in_right);}
-void IN_RightUp(void) {IN_KeyUp(&in_right);}
-void IN_ForwardDown(void) {IN_KeyDown(&in_forward);}
-void IN_ForwardUp(void) {IN_KeyUp(&in_forward);}
-void IN_BackDown(void) {IN_KeyDown(&in_back);}
-void IN_BackUp(void) {IN_KeyUp(&in_back);}
-void IN_LookupDown(void) {IN_KeyDown(&in_lookup);}
-void IN_LookupUp(void) {IN_KeyUp(&in_lookup);}
-void IN_LookdownDown(void) {IN_KeyDown(&in_lookdown);}
-void IN_LookdownUp(void) {IN_KeyUp(&in_lookdown);}
-void IN_MoveleftDown(void) {IN_KeyDown(&in_moveleft);}
-void IN_MoveleftUp(void) {IN_KeyUp(&in_moveleft);}
-void IN_MoverightDown(void) {IN_KeyDown(&in_moveright);}
-void IN_MoverightUp(void) {IN_KeyUp(&in_moveright);}
-
-void IN_SpeedDown(void) {IN_KeyDown(&in_speed);}
-void IN_SpeedUp(void) {IN_KeyUp(&in_speed);}
-void IN_StrafeDown(void) {IN_KeyDown(&in_strafe);}
-void IN_StrafeUp(void) {IN_KeyUp(&in_strafe);}
-
-#ifdef USE_VOIP
-void IN_VoipRecordDown(void)
-{
- IN_KeyDown(&in_voiprecord);
- Cvar_Set("cl_voipSend", "1");
-}
-
-void IN_VoipRecordUp(void)
-{
- IN_KeyUp(&in_voiprecord);
- Cvar_Set("cl_voipSend", "0");
-}
-#endif
-
-void IN_Button0Down(void) {IN_KeyDown(&in_buttons[0]);}
-void IN_Button0Up(void) {IN_KeyUp(&in_buttons[0]);}
-void IN_Button1Down(void) {IN_KeyDown(&in_buttons[1]);}
-void IN_Button1Up(void) {IN_KeyUp(&in_buttons[1]);}
-void IN_Button2Down(void) {IN_KeyDown(&in_buttons[2]);}
-void IN_Button2Up(void) {IN_KeyUp(&in_buttons[2]);}
-void IN_Button3Down(void) {IN_KeyDown(&in_buttons[3]);}
-void IN_Button3Up(void) {IN_KeyUp(&in_buttons[3]);}
-void IN_Button4Down(void) {IN_KeyDown(&in_buttons[4]);}
-void IN_Button4Up(void) {IN_KeyUp(&in_buttons[4]);}
-void IN_Button5Down(void) {IN_KeyDown(&in_buttons[5]);}
-void IN_Button5Up(void) {IN_KeyUp(&in_buttons[5]);}
-void IN_Button6Down(void) {IN_KeyDown(&in_buttons[6]);}
-void IN_Button6Up(void) {IN_KeyUp(&in_buttons[6]);}
-void IN_Button7Down(void) {IN_KeyDown(&in_buttons[7]);}
-void IN_Button7Up(void) {IN_KeyUp(&in_buttons[7]);}
-void IN_Button8Down(void) {IN_KeyDown(&in_buttons[8]);}
-void IN_Button8Up(void) {IN_KeyUp(&in_buttons[8]);}
-void IN_Button9Down(void) {IN_KeyDown(&in_buttons[9]);}
-void IN_Button9Up(void) {IN_KeyUp(&in_buttons[9]);}
-void IN_Button10Down(void) {IN_KeyDown(&in_buttons[10]);}
-void IN_Button10Up(void) {IN_KeyUp(&in_buttons[10]);}
-void IN_Button11Down(void) {IN_KeyDown(&in_buttons[11]);}
-void IN_Button11Up(void) {IN_KeyUp(&in_buttons[11]);}
-void IN_Button12Down(void) {IN_KeyDown(&in_buttons[12]);}
-void IN_Button12Up(void) {IN_KeyUp(&in_buttons[12]);}
-void IN_Button13Down(void) {IN_KeyDown(&in_buttons[13]);}
-void IN_Button13Up(void) {IN_KeyUp(&in_buttons[13]);}
-void IN_Button14Down(void) {IN_KeyDown(&in_buttons[14]);}
-void IN_Button14Up(void) {IN_KeyUp(&in_buttons[14]);}
-void IN_Button15Down(void) {IN_KeyDown(&in_buttons[15]);}
-void IN_Button15Up(void) {IN_KeyUp(&in_buttons[15]);}
-
-void IN_ButtonDown (void) {
- IN_KeyDown(&in_buttons[1]);}
-void IN_ButtonUp (void) {
- IN_KeyUp(&in_buttons[1]);}
-
-void IN_CenterView (void) {
- cl.viewangles[PITCH] = -SHORT2ANGLE(cl.snap.ps.delta_angles[PITCH]);
-}
-
-
-//==========================================================================
-
-cvar_t *cl_upspeed;
-cvar_t *cl_forwardspeed;
-cvar_t *cl_sidespeed;
-
-cvar_t *cl_yawspeed;
-cvar_t *cl_pitchspeed;
-
-cvar_t *cl_run;
-
-cvar_t *cl_anglespeedkey;
-
-
-/*
-================
-CL_AdjustAngles
-
-Moves the local angle positions
-================
-*/
-void CL_AdjustAngles( void ) {
- float speed;
-
- if ( in_speed.active ) {
- speed = 0.001 * cls.frametime * cl_anglespeedkey->value;
- } else {
- speed = 0.001 * cls.frametime;
- }
-
- if ( !in_strafe.active ) {
- cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
- cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
- }
-
- cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_lookup);
- cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_lookdown);
-}
-
-/*
-================
-CL_KeyMove
-
-Sets the usercmd_t based on key states
-================
-*/
-void CL_KeyMove( usercmd_t *cmd ) {
- int movespeed;
- int forward, side, up;
-
- //
- // adjust for speed key / running
- // the walking flag is to keep animations consistant
- // even during acceleration and develeration
- //
- if ( in_speed.active ^ cl_run->integer ) {
- movespeed = 127;
- cmd->buttons &= ~BUTTON_WALKING;
- } else {
- cmd->buttons |= BUTTON_WALKING;
- movespeed = 64;
- }
-
- forward = 0;
- side = 0;
- up = 0;
- if ( in_strafe.active ) {
- side += movespeed * CL_KeyState (&in_right);
- side -= movespeed * CL_KeyState (&in_left);
- }
-
- side += movespeed * CL_KeyState (&in_moveright);
- side -= movespeed * CL_KeyState (&in_moveleft);
-
-
- up += movespeed * CL_KeyState (&in_up);
- up -= movespeed * CL_KeyState (&in_down);
-
- forward += movespeed * CL_KeyState (&in_forward);
- forward -= movespeed * CL_KeyState (&in_back);
-
- cmd->forwardmove = ClampChar( forward );
- cmd->rightmove = ClampChar( side );
- cmd->upmove = ClampChar( up );
-}
-
-/*
-=================
-CL_MouseEvent
-=================
-*/
-void CL_MouseEvent( int dx, int dy, int time ) {
- if ( Key_GetCatcher( ) & KEYCATCH_UI ) {
- VM_Call( uivm, UI_MOUSE_EVENT, dx, dy );
- } else if (Key_GetCatcher( ) & KEYCATCH_CGAME) {
- VM_Call (cgvm, CG_MOUSE_EVENT, dx, dy);
- } else {
- cl.mouseDx[cl.mouseIndex] += dx;
- cl.mouseDy[cl.mouseIndex] += dy;
- }
-}
-
-/*
-=================
-CL_JoystickEvent
-
-Joystick values stay set until changed
-=================
-*/
-void CL_JoystickEvent( int axis, int value, int time ) {
- if ( axis < 0 || axis >= MAX_JOYSTICK_AXIS ) {
- Com_Error( ERR_DROP, "CL_JoystickEvent: bad axis %i", axis );
- }
- cl.joystickAxis[axis] = value;
-}
-
-/*
-=================
-CL_JoystickMove
-=================
-*/
-void CL_JoystickMove( usercmd_t *cmd ) {
- int movespeed;
- float anglespeed;
-
- if ( in_speed.active ^ cl_run->integer ) {
- movespeed = 2;
- } else {
- movespeed = 1;
- cmd->buttons |= BUTTON_WALKING;
- }
-
- if ( in_speed.active ) {
- anglespeed = 0.001 * cls.frametime * cl_anglespeedkey->value;
- } else {
- anglespeed = 0.001 * cls.frametime;
- }
-
- if ( !in_strafe.active ) {
- cl.viewangles[YAW] += anglespeed * cl_yawspeed->value * cl.joystickAxis[AXIS_SIDE];
- } else {
- cmd->rightmove = ClampChar( cmd->rightmove + cl.joystickAxis[AXIS_SIDE] );
- }
-
- if ( in_mlooking ) {
- cl.viewangles[PITCH] += anglespeed * cl_pitchspeed->value * cl.joystickAxis[AXIS_FORWARD];
- } else {
- cmd->forwardmove = ClampChar( cmd->forwardmove + cl.joystickAxis[AXIS_FORWARD] );
- }
-
- cmd->upmove = ClampChar( cmd->upmove + cl.joystickAxis[AXIS_UP] );
-}
-
-/*
-=================
-CL_MouseMove
-=================
-*/
-
-void CL_MouseMove(usercmd_t *cmd)
-{
- float mx, my;
-
- // allow mouse smoothing
- if (m_filter->integer)
- {
- mx = (cl.mouseDx[0] + cl.mouseDx[1]) * 0.5f;
- my = (cl.mouseDy[0] + cl.mouseDy[1]) * 0.5f;
- }
- else
- {
- mx = cl.mouseDx[cl.mouseIndex];
- my = cl.mouseDy[cl.mouseIndex];
- }
-
- cl.mouseIndex ^= 1;
- cl.mouseDx[cl.mouseIndex] = 0;
- cl.mouseDy[cl.mouseIndex] = 0;
-
- if (mx == 0.0f && my == 0.0f)
- return;
-
- if (cl_mouseAccel->value != 0.0f)
- {
- if(cl_mouseAccelStyle->integer == 0)
- {
- float accelSensitivity;
- float rate;
-
- rate = sqrt(mx * mx + my * my) / (float) frame_msec;
-
- accelSensitivity = cl_sensitivity->value + rate * cl_mouseAccel->value;
- mx *= accelSensitivity;
- my *= accelSensitivity;
-
- if(cl_showMouseRate->integer)
- Com_Printf("rate: %f, accelSensitivity: %f\n", rate, accelSensitivity);
- }
- else
- {
- float rate[2];
- float power[2];
-
- // sensitivity remains pretty much unchanged at low speeds
- // cl_mouseAccel is a power value to how the acceleration is shaped
- // cl_mouseAccelOffset is the rate for which the acceleration will have doubled the non accelerated amplification
- // NOTE: decouple the config cvars for independent acceleration setup along X and Y?
-
- rate[0] = fabs(mx) / (float) frame_msec;
- rate[1] = fabs(my) / (float) frame_msec;
- power[0] = powf(rate[0] / cl_mouseAccelOffset->value, cl_mouseAccel->value);
- power[1] = powf(rate[1] / cl_mouseAccelOffset->value, cl_mouseAccel->value);
-
- mx = cl_sensitivity->value * (mx + ((mx < 0) ? -power[0] : power[0]) * cl_mouseAccelOffset->value);
- my = cl_sensitivity->value * (my + ((my < 0) ? -power[1] : power[1]) * cl_mouseAccelOffset->value);
-
- if(cl_showMouseRate->integer)
- Com_Printf("ratex: %f, ratey: %f, powx: %f, powy: %f\n", rate[0], rate[1], power[0], power[1]);
- }
- }
- else
- {
- mx *= cl_sensitivity->value;
- my *= cl_sensitivity->value;
- }
-
- // ingame FOV
- mx *= cl.cgameSensitivity;
- my *= cl.cgameSensitivity;
-
- // add mouse X/Y movement to cmd
- if(in_strafe.active)
- cmd->rightmove = ClampChar(cmd->rightmove + m_side->value * mx);
- else
- cl.viewangles[YAW] -= m_yaw->value * mx;
-
- if ((in_mlooking || cl_freelook->integer) && !in_strafe.active)
- cl.viewangles[PITCH] += m_pitch->value * my;
- else
- cmd->forwardmove = ClampChar(cmd->forwardmove - m_forward->value * my);
-}
-
-
-/*
-==============
-CL_CmdButtons
-==============
-*/
-void CL_CmdButtons( usercmd_t *cmd ) {
- int i;
-
- //
- // figure button bits
- // send a button bit even if the key was pressed and released in
- // less than a frame
- //
- for (i = 0 ; i < 15 ; i++) {
- if ( in_buttons[i].active || in_buttons[i].wasPressed ) {
- cmd->buttons |= 1 << i;
- }
- in_buttons[i].wasPressed = qfalse;
- }
-
- if ( Key_GetCatcher( ) ) {
- cmd->buttons |= BUTTON_TALK;
- }
-
- // allow the game to know if any key at all is
- // currently pressed, even if it isn't bound to anything
- if ( anykeydown && Key_GetCatcher( ) == 0 ) {
- cmd->buttons |= BUTTON_ANY;
- }
-}
-
-
-/*
-==============
-CL_FinishMove
-==============
-*/
-void CL_FinishMove( usercmd_t *cmd ) {
- int i;
-
- // copy the state that the cgame is currently sending
- cmd->weapon = cl.cgameUserCmdValue;
-
- // send the current server time so the amount of movement
- // can be determined without allowing cheating
- cmd->serverTime = cl.serverTime;
-
- for (i=0 ; i<3 ; i++) {
- cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
- }
-}
-
-
-/*
-=================
-CL_CreateCmd
-=================
-*/
-usercmd_t CL_CreateCmd( void ) {
- usercmd_t cmd;
- vec3_t oldAngles;
-
- VectorCopy( cl.viewangles, oldAngles );
-
- // keyboard angle adjustment
- CL_AdjustAngles ();
-
- Com_Memset( &cmd, 0, sizeof( cmd ) );
-
- CL_CmdButtons( &cmd );
-
- // get basic movement from keyboard
- CL_KeyMove( &cmd );
-
- // get basic movement from mouse
- CL_MouseMove( &cmd );
-
- // get basic movement from joystick
- CL_JoystickMove( &cmd );
-
- // check to make sure the angles haven't wrapped
- if ( cl.viewangles[PITCH] - oldAngles[PITCH] > 90 ) {
- cl.viewangles[PITCH] = oldAngles[PITCH] + 90;
- } else if ( oldAngles[PITCH] - cl.viewangles[PITCH] > 90 ) {
- cl.viewangles[PITCH] = oldAngles[PITCH] - 90;
- }
-
- // store out the final values
- CL_FinishMove( &cmd );
-
- // draw debug graphs of turning for mouse testing
- if ( cl_debugMove->integer ) {
- if ( cl_debugMove->integer == 1 ) {
- SCR_DebugGraph( abs(cl.viewangles[YAW] - oldAngles[YAW]), 0 );
- }
- if ( cl_debugMove->integer == 2 ) {
- SCR_DebugGraph( abs(cl.viewangles[PITCH] - oldAngles[PITCH]), 0 );
- }
- }
-
- return cmd;
-}
-
-
-/*
-=================
-CL_CreateNewCommands
-
-Create a new usercmd_t structure for this frame
-=================
-*/
-void CL_CreateNewCommands( void ) {
- usercmd_t *cmd;
- int cmdNum;
-
- // no need to create usercmds until we have a gamestate
- if ( cls.state < CA_PRIMED ) {
- return;
- }
-
- frame_msec = com_frameTime - old_com_frameTime;
-
- // if running less than 5fps, truncate the extra time to prevent
- // unexpected moves after a hitch
- if ( frame_msec > 200 ) {
- frame_msec = 200;
- }
- old_com_frameTime = com_frameTime;
-
-
- // generate a command for this frame
- cl.cmdNumber++;
- cmdNum = cl.cmdNumber & CMD_MASK;
- cl.cmds[cmdNum] = CL_CreateCmd ();
- cmd = &cl.cmds[cmdNum];
-}
-
-/*
-=================
-CL_ReadyToSendPacket
-
-Returns qfalse if we are over the maxpackets limit
-and should choke back the bandwidth a bit by not sending
-a packet this frame. All the commands will still get
-delivered in the next packet, but saving a header and
-getting more delta compression will reduce total bandwidth.
-=================
-*/
-qboolean CL_ReadyToSendPacket( void ) {
- int oldPacketNum;
- int delta;
-
- // don't send anything if playing back a demo
- if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
- return qfalse;
- }
-
- // If we are downloading, we send no less than 50ms between packets
- if ( *clc.downloadTempName &&
- cls.realtime - clc.lastPacketSentTime < 50 ) {
- return qfalse;
- }
-
- // if we don't have a valid gamestate yet, only send
- // one packet a second
- if ( cls.state != CA_ACTIVE &&
- cls.state != CA_PRIMED &&
- !*clc.downloadTempName &&
- cls.realtime - clc.lastPacketSentTime < 1000 ) {
- return qfalse;
- }
-
- // send every frame for loopbacks
- if ( clc.netchan.remoteAddress.type == NA_LOOPBACK ) {
- return qtrue;
- }
-
- // send every frame for LAN
- if ( cl_lanForcePackets->integer && Sys_IsLANAddress( clc.netchan.remoteAddress ) ) {
- return qtrue;
- }
-
- // check for exceeding cl_maxpackets
- if ( cl_maxpackets->integer < 15 ) {
- Cvar_Set( "cl_maxpackets", "15" );
- } else if ( cl_maxpackets->integer > 125 ) {
- Cvar_Set( "cl_maxpackets", "125" );
- }
- oldPacketNum = (clc.netchan.outgoingSequence - 1) & PACKET_MASK;
- delta = cls.realtime - cl.outPackets[ oldPacketNum ].p_realtime;
- if ( delta < 1000 / cl_maxpackets->integer ) {
- // the accumulated commands will go out in the next packet
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-===================
-CL_WritePacket
-
-Create and send the command packet to the server
-Including both the reliable commands and the usercmds
-
-During normal gameplay, a client packet will contain something like:
-
-4 sequence number
-2 qport
-4 serverid
-4 acknowledged sequence number
-4 clc.serverCommandSequence
-<optional reliable commands>
-1 clc_move or clc_moveNoDelta
-1 command count
-<count * usercmds>
-
-===================
-*/
-void CL_WritePacket( void ) {
- msg_t buf;
- byte data[MAX_MSGLEN];
- int i, j;
- usercmd_t *cmd, *oldcmd;
- usercmd_t nullcmd;
- int packetNum;
- int oldPacketNum;
- int count, key;
-
- // don't send anything if playing back a demo
- if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
- return;
- }
-
- Com_Memset( &nullcmd, 0, sizeof(nullcmd) );
- oldcmd = &nullcmd;
-
- MSG_Init( &buf, data, sizeof(data) );
-
- MSG_Bitstream( &buf );
- // write the current serverId so the server
- // can tell if this is from the current gameState
- MSG_WriteLong( &buf, cl.serverId );
-
- // write the last message we received, which can
- // be used for delta compression, and is also used
- // to tell if we dropped a gamestate
- MSG_WriteLong( &buf, clc.serverMessageSequence );
-
- // write the last reliable message we received
- MSG_WriteLong( &buf, clc.serverCommandSequence );
-
- // write any unacknowledged clientCommands
- for ( i = clc.reliableAcknowledge + 1 ; i <= clc.reliableSequence ; i++ ) {
- MSG_WriteByte( &buf, clc_clientCommand );
- MSG_WriteLong( &buf, i );
- MSG_WriteString( &buf, clc.reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
- }
-
- // we want to send all the usercmds that were generated in the last
- // few packet, so even if a couple packets are dropped in a row,
- // all the cmds will make it to the server
- if ( cl_packetdup->integer < 0 ) {
- Cvar_Set( "cl_packetdup", "0" );
- } else if ( cl_packetdup->integer > 5 ) {
- Cvar_Set( "cl_packetdup", "5" );
- }
- oldPacketNum = (clc.netchan.outgoingSequence - 1 - cl_packetdup->integer) & PACKET_MASK;
- count = cl.cmdNumber - cl.outPackets[ oldPacketNum ].p_cmdNumber;
- if ( count > MAX_PACKET_USERCMDS ) {
- count = MAX_PACKET_USERCMDS;
- Com_Printf("MAX_PACKET_USERCMDS\n");
- }
-
-#ifdef USE_VOIP
- if (clc.voipOutgoingDataSize > 0) { // only send if data.
- // Move cl_voipSendTarget from a string to the bitmasks if needed.
- if (cl_voipSendTarget->modified) {
- char buffer[32];
- const char *target = cl_voipSendTarget->string;
-
- if (Q_stricmp(target, "attacker") == 0) {
- int player = VM_Call( cgvm, CG_LAST_ATTACKER );
- Com_sprintf(buffer, sizeof (buffer), "%d", player);
- target = buffer;
- } else if (Q_stricmp(target, "crosshair") == 0) {
- int player = VM_Call( cgvm, CG_CROSSHAIR_PLAYER );
- Com_sprintf(buffer, sizeof (buffer), "%d", player);
- target = buffer;
- }
-
- if ((*target == '\0') || (Q_stricmp(target, "all") == 0)) {
- const int all = 0x7FFFFFFF;
- clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = all;
- } else if (Q_stricmp(target, "none") == 0) {
- clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0;
- } else {
- const char *ptr = target;
- clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0;
- do {
- if ((*ptr == ',') || (*ptr == '\0')) {
- const int val = atoi(target);
- target = ptr + 1;
- if ((val >= 0) && (val < 31)) {
- clc.voipTarget1 |= (1 << (val-0));
- } else if ((val >= 31) && (val < 62)) {
- clc.voipTarget2 |= (1 << (val-31));
- } else if ((val >= 62) && (val < 93)) {
- clc.voipTarget3 |= (1 << (val-62));
- }
- }
- } while (*(ptr++));
- }
- cl_voipSendTarget->modified = qfalse;
- }
-
- MSG_WriteByte (&buf, clc_EOF); // placate legacy servers.
- MSG_WriteByte (&buf, clc_extension);
- MSG_WriteByte (&buf, clc_voip);
- MSG_WriteByte (&buf, clc.voipOutgoingGeneration);
- MSG_WriteLong (&buf, clc.voipOutgoingSequence);
- MSG_WriteByte (&buf, clc.voipOutgoingDataFrames);
- MSG_WriteLong (&buf, clc.voipTarget1);
- MSG_WriteLong (&buf, clc.voipTarget2);
- MSG_WriteLong (&buf, clc.voipTarget3);
- MSG_WriteShort (&buf, clc.voipOutgoingDataSize);
- MSG_WriteData (&buf, clc.voipOutgoingData, clc.voipOutgoingDataSize);
-
- // If we're recording a demo, we have to fake a server packet with
- // this VoIP data so it gets to disk; the server doesn't send it
- // back to us, and we might as well eliminate concerns about dropped
- // and misordered packets here.
- if ( clc.demorecording && !clc.demowaiting ) {
- const int voipSize = clc.voipOutgoingDataSize;
- msg_t fakemsg;
- byte fakedata[MAX_MSGLEN];
- MSG_Init (&fakemsg, fakedata, sizeof (fakedata));
- MSG_Bitstream (&fakemsg);
- MSG_WriteLong (&fakemsg, clc.reliableAcknowledge);
- MSG_WriteByte (&fakemsg, svc_EOF);
- MSG_WriteByte (&fakemsg, svc_extension);
- MSG_WriteByte (&fakemsg, svc_voip);
- MSG_WriteShort (&fakemsg, clc.clientNum);
- MSG_WriteByte (&fakemsg, clc.voipOutgoingGeneration);
- MSG_WriteLong (&fakemsg, clc.voipOutgoingSequence);
- MSG_WriteByte (&fakemsg, clc.voipOutgoingDataFrames);
- MSG_WriteShort (&fakemsg, clc.voipOutgoingDataSize );
- MSG_WriteData (&fakemsg, clc.voipOutgoingData, voipSize);
- MSG_WriteByte (&fakemsg, svc_EOF);
- CL_WriteDemoMessage (&fakemsg, 0);
- }
-
- clc.voipOutgoingSequence += clc.voipOutgoingDataFrames;
- clc.voipOutgoingDataSize = 0;
- clc.voipOutgoingDataFrames = 0;
- } else
-#endif
-
- if ( count >= 1 ) {
- if ( cl_showSend->integer ) {
- Com_Printf( "(%i)", count );
- }
-
- // begin a client move command
- if ( cl_nodelta->integer || !cl.snap.valid || clc.demowaiting
- || clc.serverMessageSequence != cl.snap.messageNum ) {
- MSG_WriteByte (&buf, clc_moveNoDelta);
- } else {
- MSG_WriteByte (&buf, clc_move);
- }
-
- // write the command count
- MSG_WriteByte( &buf, count );
-
- // use the checksum feed in the key
- key = clc.checksumFeed;
- // also use the message acknowledge
- key ^= clc.serverMessageSequence;
- // also use the last acknowledged server command in the key
- key ^= MSG_HashKey(clc.serverCommands[ clc.serverCommandSequence & (MAX_RELIABLE_COMMANDS-1) ], 32);
-
- // write all the commands, including the predicted command
- for ( i = 0 ; i < count ; i++ ) {
- j = (cl.cmdNumber - count + i + 1) & CMD_MASK;
- cmd = &cl.cmds[j];
- MSG_WriteDeltaUsercmdKey (&buf, key, oldcmd, cmd);
- oldcmd = cmd;
- }
- }
-
- //
- // deliver the message
- //
- packetNum = clc.netchan.outgoingSequence & PACKET_MASK;
- cl.outPackets[ packetNum ].p_realtime = cls.realtime;
- cl.outPackets[ packetNum ].p_serverTime = oldcmd->serverTime;
- cl.outPackets[ packetNum ].p_cmdNumber = cl.cmdNumber;
- clc.lastPacketSentTime = cls.realtime;
-
- if ( cl_showSend->integer ) {
- Com_Printf( "%i ", buf.cursize );
- }
-
- CL_Netchan_Transmit (&clc.netchan, &buf);
-
- // clients never really should have messages large enough
- // to fragment, but in case they do, fire them all off
- // at once
- // TTimo: this causes a packet burst, which is bad karma for winsock
- // added a WARNING message, we'll see if there are legit situations where this happens
- while ( clc.netchan.unsentFragments ) {
- Com_DPrintf( "WARNING: #462 unsent fragments (not supposed to happen!)\n" );
- CL_Netchan_TransmitNextFragment( &clc.netchan );
- }
-}
-
-/*
-=================
-CL_SendCmd
-
-Called every frame to builds and sends a command packet to the server.
-=================
-*/
-void CL_SendCmd( void ) {
- // don't send any message if not connected
- if ( cls.state < CA_CONNECTED ) {
- return;
- }
-
- // don't send commands if paused
- if ( com_sv_running->integer && sv_paused->integer && cl_paused->integer ) {
- return;
- }
-
- // we create commands even if a demo is playing,
- CL_CreateNewCommands();
-
- // don't send a packet if the last packet was sent too recently
- if ( !CL_ReadyToSendPacket() ) {
- if ( cl_showSend->integer ) {
- Com_Printf( ". " );
- }
- return;
- }
-
- CL_WritePacket();
-}
-
-/*
-============
-CL_InitInput
-============
-*/
-void CL_InitInput( void ) {
- Cmd_AddCommand ("centerview",IN_CenterView);
-
- 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_Button0Down);
- Cmd_AddCommand ("-attack", IN_Button0Up);
- Cmd_AddCommand ("+button0", IN_Button0Down);
- Cmd_AddCommand ("-button0", IN_Button0Up);
- Cmd_AddCommand ("+button1", IN_Button1Down);
- Cmd_AddCommand ("-button1", IN_Button1Up);
- Cmd_AddCommand ("+button2", IN_Button2Down);
- Cmd_AddCommand ("-button2", IN_Button2Up);
- Cmd_AddCommand ("+button3", IN_Button3Down);
- Cmd_AddCommand ("-button3", IN_Button3Up);
- Cmd_AddCommand ("+button4", IN_Button4Down);
- Cmd_AddCommand ("-button4", IN_Button4Up);
- Cmd_AddCommand ("+button5", IN_Button5Down);
- Cmd_AddCommand ("-button5", IN_Button5Up);
- Cmd_AddCommand ("+button6", IN_Button6Down);
- Cmd_AddCommand ("-button6", IN_Button6Up);
- Cmd_AddCommand ("+button7", IN_Button7Down);
- Cmd_AddCommand ("-button7", IN_Button7Up);
- Cmd_AddCommand ("+button8", IN_Button8Down);
- Cmd_AddCommand ("-button8", IN_Button8Up);
- Cmd_AddCommand ("+button9", IN_Button9Down);
- Cmd_AddCommand ("-button9", IN_Button9Up);
- Cmd_AddCommand ("+button10", IN_Button10Down);
- Cmd_AddCommand ("-button10", IN_Button10Up);
- Cmd_AddCommand ("+button11", IN_Button11Down);
- Cmd_AddCommand ("-button11", IN_Button11Up);
- Cmd_AddCommand ("+button12", IN_Button12Down);
- Cmd_AddCommand ("-button12", IN_Button12Up);
- Cmd_AddCommand ("+button13", IN_Button13Down);
- Cmd_AddCommand ("-button13", IN_Button13Up);
- Cmd_AddCommand ("+button14", IN_Button14Down);
- Cmd_AddCommand ("-button14", IN_Button14Up);
- Cmd_AddCommand ("+mlook", IN_MLookDown);
- Cmd_AddCommand ("-mlook", IN_MLookUp);
-
-#ifdef USE_VOIP
- Cmd_AddCommand ("+voiprecord", IN_VoipRecordDown);
- Cmd_AddCommand ("-voiprecord", IN_VoipRecordUp);
-#endif
-
- cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
- cl_debugMove = Cvar_Get ("cl_debugMove", "0", 0);
-}
diff --git a/engine/code/client/cl_keys.c b/engine/code/client/cl_keys.c
deleted file mode 100644
index 0f72795..0000000
--- a/engine/code/client/cl_keys.c
+++ /dev/null
@@ -1,1515 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "client.h"
-
-/*
-
-key up events are sent even if in console mode
-
-*/
-
-field_t historyEditLines[COMMAND_HISTORY];
-
-int nextHistoryLine; // the last line in the history buffer, not masked
-int historyLine; // the line being displayed from history buffer
- // will be <= nextHistoryLine
-
-field_t g_consoleField;
-field_t chatField;
-qboolean chat_team;
-
-int chat_playerNum;
-
-
-qboolean key_overstrikeMode;
-
-int anykeydown;
-qkey_t keys[MAX_KEYS];
-
-
-typedef struct {
- char *name;
- int keynum;
-} keyname_t;
-
-
-// names not in this list can either be lowercase ascii, or '0xnn' hex sequences
-keyname_t keynames[] =
-{
- {"TAB", K_TAB},
- {"ENTER", K_ENTER},
- {"ESCAPE", K_ESCAPE},
- {"SPACE", K_SPACE},
- {"BACKSPACE", K_BACKSPACE},
- {"UPARROW", K_UPARROW},
- {"DOWNARROW", K_DOWNARROW},
- {"LEFTARROW", K_LEFTARROW},
- {"RIGHTARROW", K_RIGHTARROW},
-
- {"ALT", K_ALT},
- {"CTRL", K_CTRL},
- {"SHIFT", K_SHIFT},
-
- {"COMMAND", K_COMMAND},
-
- {"CAPSLOCK", K_CAPSLOCK},
-
-
- {"F1", K_F1},
- {"F2", K_F2},
- {"F3", K_F3},
- {"F4", K_F4},
- {"F5", K_F5},
- {"F6", K_F6},
- {"F7", K_F7},
- {"F8", K_F8},
- {"F9", K_F9},
- {"F10", K_F10},
- {"F11", K_F11},
- {"F12", K_F12},
- {"F13", K_F13},
- {"F14", K_F14},
- {"F15", K_F15},
-
- {"INS", K_INS},
- {"DEL", K_DEL},
- {"PGDN", K_PGDN},
- {"PGUP", K_PGUP},
- {"HOME", K_HOME},
- {"END", K_END},
-
- {"MOUSE1", K_MOUSE1},
- {"MOUSE2", K_MOUSE2},
- {"MOUSE3", K_MOUSE3},
- {"MOUSE4", K_MOUSE4},
- {"MOUSE5", K_MOUSE5},
-
- {"MWHEELUP", K_MWHEELUP },
- {"MWHEELDOWN", K_MWHEELDOWN },
-
- {"JOY1", K_JOY1},
- {"JOY2", K_JOY2},
- {"JOY3", K_JOY3},
- {"JOY4", K_JOY4},
- {"JOY5", K_JOY5},
- {"JOY6", K_JOY6},
- {"JOY7", K_JOY7},
- {"JOY8", K_JOY8},
- {"JOY9", K_JOY9},
- {"JOY10", K_JOY10},
- {"JOY11", K_JOY11},
- {"JOY12", K_JOY12},
- {"JOY13", K_JOY13},
- {"JOY14", K_JOY14},
- {"JOY15", K_JOY15},
- {"JOY16", K_JOY16},
- {"JOY17", K_JOY17},
- {"JOY18", K_JOY18},
- {"JOY19", K_JOY19},
- {"JOY20", K_JOY20},
- {"JOY21", K_JOY21},
- {"JOY22", K_JOY22},
- {"JOY23", K_JOY23},
- {"JOY24", K_JOY24},
- {"JOY25", K_JOY25},
- {"JOY26", K_JOY26},
- {"JOY27", K_JOY27},
- {"JOY28", K_JOY28},
- {"JOY29", K_JOY29},
- {"JOY30", K_JOY30},
- {"JOY31", K_JOY31},
- {"JOY32", K_JOY32},
-
- {"AUX1", K_AUX1},
- {"AUX2", K_AUX2},
- {"AUX3", K_AUX3},
- {"AUX4", K_AUX4},
- {"AUX5", K_AUX5},
- {"AUX6", K_AUX6},
- {"AUX7", K_AUX7},
- {"AUX8", K_AUX8},
- {"AUX9", K_AUX9},
- {"AUX10", K_AUX10},
- {"AUX11", K_AUX11},
- {"AUX12", K_AUX12},
- {"AUX13", K_AUX13},
- {"AUX14", K_AUX14},
- {"AUX15", K_AUX15},
- {"AUX16", K_AUX16},
-
- {"KP_HOME", K_KP_HOME },
- {"KP_UPARROW", K_KP_UPARROW },
- {"KP_PGUP", K_KP_PGUP },
- {"KP_LEFTARROW", K_KP_LEFTARROW },
- {"KP_5", K_KP_5 },
- {"KP_RIGHTARROW", K_KP_RIGHTARROW },
- {"KP_END", K_KP_END },
- {"KP_DOWNARROW", K_KP_DOWNARROW },
- {"KP_PGDN", K_KP_PGDN },
- {"KP_ENTER", K_KP_ENTER },
- {"KP_INS", K_KP_INS },
- {"KP_DEL", K_KP_DEL },
- {"KP_SLASH", K_KP_SLASH },
- {"KP_MINUS", K_KP_MINUS },
- {"KP_PLUS", K_KP_PLUS },
- {"KP_NUMLOCK", K_KP_NUMLOCK },
- {"KP_STAR", K_KP_STAR },
- {"KP_EQUALS", K_KP_EQUALS },
-
- {"PAUSE", K_PAUSE},
-
- {"SEMICOLON", ';'}, // because a raw semicolon seperates commands
-
- {"WORLD_0", K_WORLD_0},
- {"WORLD_1", K_WORLD_1},
- {"WORLD_2", K_WORLD_2},
- {"WORLD_3", K_WORLD_3},
- {"WORLD_4", K_WORLD_4},
- {"WORLD_5", K_WORLD_5},
- {"WORLD_6", K_WORLD_6},
- {"WORLD_7", K_WORLD_7},
- {"WORLD_8", K_WORLD_8},
- {"WORLD_9", K_WORLD_9},
- {"WORLD_10", K_WORLD_10},
- {"WORLD_11", K_WORLD_11},
- {"WORLD_12", K_WORLD_12},
- {"WORLD_13", K_WORLD_13},
- {"WORLD_14", K_WORLD_14},
- {"WORLD_15", K_WORLD_15},
- {"WORLD_16", K_WORLD_16},
- {"WORLD_17", K_WORLD_17},
- {"WORLD_18", K_WORLD_18},
- {"WORLD_19", K_WORLD_19},
- {"WORLD_20", K_WORLD_20},
- {"WORLD_21", K_WORLD_21},
- {"WORLD_22", K_WORLD_22},
- {"WORLD_23", K_WORLD_23},
- {"WORLD_24", K_WORLD_24},
- {"WORLD_25", K_WORLD_25},
- {"WORLD_26", K_WORLD_26},
- {"WORLD_27", K_WORLD_27},
- {"WORLD_28", K_WORLD_28},
- {"WORLD_29", K_WORLD_29},
- {"WORLD_30", K_WORLD_30},
- {"WORLD_31", K_WORLD_31},
- {"WORLD_32", K_WORLD_32},
- {"WORLD_33", K_WORLD_33},
- {"WORLD_34", K_WORLD_34},
- {"WORLD_35", K_WORLD_35},
- {"WORLD_36", K_WORLD_36},
- {"WORLD_37", K_WORLD_37},
- {"WORLD_38", K_WORLD_38},
- {"WORLD_39", K_WORLD_39},
- {"WORLD_40", K_WORLD_40},
- {"WORLD_41", K_WORLD_41},
- {"WORLD_42", K_WORLD_42},
- {"WORLD_43", K_WORLD_43},
- {"WORLD_44", K_WORLD_44},
- {"WORLD_45", K_WORLD_45},
- {"WORLD_46", K_WORLD_46},
- {"WORLD_47", K_WORLD_47},
- {"WORLD_48", K_WORLD_48},
- {"WORLD_49", K_WORLD_49},
- {"WORLD_50", K_WORLD_50},
- {"WORLD_51", K_WORLD_51},
- {"WORLD_52", K_WORLD_52},
- {"WORLD_53", K_WORLD_53},
- {"WORLD_54", K_WORLD_54},
- {"WORLD_55", K_WORLD_55},
- {"WORLD_56", K_WORLD_56},
- {"WORLD_57", K_WORLD_57},
- {"WORLD_58", K_WORLD_58},
- {"WORLD_59", K_WORLD_59},
- {"WORLD_60", K_WORLD_60},
- {"WORLD_61", K_WORLD_61},
- {"WORLD_62", K_WORLD_62},
- {"WORLD_63", K_WORLD_63},
- {"WORLD_64", K_WORLD_64},
- {"WORLD_65", K_WORLD_65},
- {"WORLD_66", K_WORLD_66},
- {"WORLD_67", K_WORLD_67},
- {"WORLD_68", K_WORLD_68},
- {"WORLD_69", K_WORLD_69},
- {"WORLD_70", K_WORLD_70},
- {"WORLD_71", K_WORLD_71},
- {"WORLD_72", K_WORLD_72},
- {"WORLD_73", K_WORLD_73},
- {"WORLD_74", K_WORLD_74},
- {"WORLD_75", K_WORLD_75},
- {"WORLD_76", K_WORLD_76},
- {"WORLD_77", K_WORLD_77},
- {"WORLD_78", K_WORLD_78},
- {"WORLD_79", K_WORLD_79},
- {"WORLD_80", K_WORLD_80},
- {"WORLD_81", K_WORLD_81},
- {"WORLD_82", K_WORLD_82},
- {"WORLD_83", K_WORLD_83},
- {"WORLD_84", K_WORLD_84},
- {"WORLD_85", K_WORLD_85},
- {"WORLD_86", K_WORLD_86},
- {"WORLD_87", K_WORLD_87},
- {"WORLD_88", K_WORLD_88},
- {"WORLD_89", K_WORLD_89},
- {"WORLD_90", K_WORLD_90},
- {"WORLD_91", K_WORLD_91},
- {"WORLD_92", K_WORLD_92},
- {"WORLD_93", K_WORLD_93},
- {"WORLD_94", K_WORLD_94},
- {"WORLD_95", K_WORLD_95},
-
- {"WINDOWS", K_SUPER},
- {"COMPOSE", K_COMPOSE},
- {"MODE", K_MODE},
- {"HELP", K_HELP},
- {"PRINT", K_PRINT},
- {"SYSREQ", K_SYSREQ},
- {"SCROLLOCK", K_SCROLLOCK },
- {"BREAK", K_BREAK},
- {"MENU", K_MENU},
- {"POWER", K_POWER},
- {"EURO", K_EURO},
- {"UNDO", K_UNDO},
-
- {NULL,0}
-};
-
-/*
-=============================================================================
-
-EDIT FIELDS
-
-=============================================================================
-*/
-
-
-/*
-===================
-Field_Draw
-
-Handles horizontal scrolling and cursor blinking
-x, y, and width are in pixels
-===================
-*/
-void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, qboolean showCursor,
- qboolean noColorEscape ) {
- int len;
- int drawLen;
- int prestep;
- int cursorChar;
- char str[MAX_STRING_CHARS];
- int i;
-
- drawLen = edit->widthInChars - 1; // - 1 so there is always a space for the cursor
- len = strlen( edit->buffer );
-
- // guarantee that cursor will be visible
- if ( len <= drawLen ) {
- prestep = 0;
- } else {
- if ( edit->scroll + drawLen > len ) {
- edit->scroll = len - drawLen;
- if ( edit->scroll < 0 ) {
- edit->scroll = 0;
- }
- }
- prestep = edit->scroll;
- }
-
- if ( prestep + drawLen > len ) {
- drawLen = len - prestep;
- }
-
- // extract <drawLen> characters from the field at <prestep>
- if ( drawLen >= MAX_STRING_CHARS ) {
- Com_Error( ERR_DROP, "drawLen >= MAX_STRING_CHARS" );
- }
-
- Com_Memcpy( str, edit->buffer + prestep, drawLen );
- str[ drawLen ] = 0;
-
- // draw it
- if ( size == SMALLCHAR_WIDTH ) {
- float color[4];
-
- color[0] = color[1] = color[2] = color[3] = 1.0;
- SCR_DrawSmallStringExt( x, y, str, color, qfalse, noColorEscape );
- } else {
- // draw big string with drop shadow
- SCR_DrawBigString( x, y, str, 1.0, noColorEscape );
- }
-
- // draw the cursor
- if ( showCursor ) {
- if ( (int)( cls.realtime >> 8 ) & 1 ) {
- return; // off blink
- }
-
- if ( key_overstrikeMode ) {
- cursorChar = 11;
- } else {
- cursorChar = 10;
- }
-
- i = drawLen - strlen( str );
-
- if ( size == SMALLCHAR_WIDTH ) {
- SCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar );
- } else {
- str[0] = cursorChar;
- str[1] = 0;
- SCR_DrawBigString( x + ( edit->cursor - prestep - i ) * size, y, str, 1.0, qfalse );
-
- }
- }
-}
-
-void Field_Draw( field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape )
-{
- Field_VariableSizeDraw( edit, x, y, width, SMALLCHAR_WIDTH, showCursor, noColorEscape );
-}
-
-void Field_BigDraw( field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape )
-{
- Field_VariableSizeDraw( edit, x, y, width, BIGCHAR_WIDTH, showCursor, noColorEscape );
-}
-
-/*
-================
-Field_Paste
-================
-*/
-void Field_Paste( field_t *edit ) {
- char *cbd;
- int pasteLen, i;
-
- cbd = Sys_GetClipboardData();
-
- if ( !cbd ) {
- return;
- }
-
- // send as if typed, so insert / overstrike works properly
- pasteLen = strlen( cbd );
- for ( i = 0 ; i < pasteLen ; i++ ) {
- Field_CharEvent( edit, cbd[i] );
- }
-
- Z_Free( cbd );
-}
-
-/*
-=================
-Field_KeyDownEvent
-
-Performs the basic line editing functions for the console,
-in-game talk, and menu fields
-
-Key events are used for non-printable characters, others are gotten from char events.
-=================
-*/
-void Field_KeyDownEvent( field_t *edit, int key ) {
- int len;
-
- // shift-insert is paste
- if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keys[K_SHIFT].down ) {
- Field_Paste( edit );
- return;
- }
-
- key = tolower( key );
- len = strlen( edit->buffer );
-
- switch ( key ) {
- case K_DEL:
- if ( edit->cursor < len ) {
- memmove( edit->buffer + edit->cursor,
- edit->buffer + edit->cursor + 1, len - edit->cursor );
- }
- break;
-
- case K_RIGHTARROW:
- if ( edit->cursor < len ) {
- edit->cursor++;
- }
- break;
-
- case K_LEFTARROW:
- if ( edit->cursor > 0 ) {
- edit->cursor--;
- }
- break;
-
- case K_HOME:
- edit->cursor = 0;
- break;
-
- case K_END:
- edit->cursor = len;
- break;
-
- case K_INS:
- key_overstrikeMode = !key_overstrikeMode;
- break;
-
- default:
- break;
- }
-
- // Change scroll if cursor is no longer visible
- if ( edit->cursor < edit->scroll ) {
- edit->scroll = edit->cursor;
- } else if ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len ) {
- edit->scroll = edit->cursor - edit->widthInChars + 1;
- }
-}
-
-/*
-==================
-Field_CharEvent
-==================
-*/
-void Field_CharEvent( field_t *edit, int ch ) {
- int len;
-
- if ( ch == 'v' - 'a' + 1 ) { // ctrl-v is paste
- Field_Paste( edit );
- return;
- }
-
- if ( ch == 'c' - 'a' + 1 ) { // ctrl-c clears the field
- Field_Clear( edit );
- return;
- }
-
- len = strlen( edit->buffer );
-
- if ( ch == 'h' - 'a' + 1 ) { // ctrl-h is backspace
- if ( edit->cursor > 0 ) {
- memmove( edit->buffer + edit->cursor - 1,
- edit->buffer + edit->cursor, len + 1 - edit->cursor );
- edit->cursor--;
- if ( edit->cursor < edit->scroll )
- {
- edit->scroll--;
- }
- }
- return;
- }
-
- if ( ch == 'a' - 'a' + 1 ) { // ctrl-a is home
- edit->cursor = 0;
- edit->scroll = 0;
- return;
- }
-
- if ( ch == 'e' - 'a' + 1 ) { // ctrl-e is end
- edit->cursor = len;
- edit->scroll = edit->cursor - edit->widthInChars;
- return;
- }
-
- //
- // ignore any other non printable chars
- //
- if ( ch < 32 ) {
- return;
- }
-
- if ( key_overstrikeMode ) {
- if ( edit->cursor == MAX_EDIT_LINE - 1 )
- return;
- edit->buffer[edit->cursor] = ch;
- edit->cursor++;
- } else { // insert mode
- if ( len == MAX_EDIT_LINE - 1 ) {
- return; // all full
- }
- memmove( edit->buffer + edit->cursor + 1,
- edit->buffer + edit->cursor, len + 1 - edit->cursor );
- edit->buffer[edit->cursor] = ch;
- edit->cursor++;
- }
-
-
- if ( edit->cursor >= edit->widthInChars ) {
- edit->scroll++;
- }
-
- if ( edit->cursor == len + 1) {
- edit->buffer[edit->cursor] = 0;
- }
-}
-
-/*
-=============================================================================
-
-CONSOLE LINE EDITING
-
-==============================================================================
-*/
-
-/*
-====================
-Console_Key
-
-Handles history and console scrollback
-====================
-*/
-void Console_Key (int key) {
- // ctrl-L clears screen
- if ( key == 'l' && keys[K_CTRL].down ) {
- Cbuf_AddText ("clear\n");
- return;
- }
-
- // enter finishes the line
- if ( key == K_ENTER || key == K_KP_ENTER ) {
- // if not in the game explicitly prepend a slash if needed
- if ( cls.state != CA_ACTIVE && g_consoleField.buffer[0] != '\\'
- && g_consoleField.buffer[0] != '/' ) {
- char temp[MAX_EDIT_LINE-1];
-
- Q_strncpyz( temp, g_consoleField.buffer, sizeof( temp ) );
- Com_sprintf( g_consoleField.buffer, sizeof( g_consoleField.buffer ), "\\%s", temp );
- g_consoleField.cursor++;
- }
-
- Com_Printf ( "]%s\n", g_consoleField.buffer );
-
- // leading slash is an explicit command
- if ( g_consoleField.buffer[0] == '\\' || g_consoleField.buffer[0] == '/' ) {
- Cbuf_AddText( g_consoleField.buffer+1 ); // valid command
- Cbuf_AddText ("\n");
- } else {
- // other text will be chat messages
- if ( !g_consoleField.buffer[0] ) {
- return; // empty lines just scroll the console without adding to history
- } else {
- Cbuf_AddText ("cmd say ");
- Cbuf_AddText( g_consoleField.buffer );
- Cbuf_AddText ("\n");
- }
- }
-
- // copy line to history buffer
- historyEditLines[nextHistoryLine % COMMAND_HISTORY] = g_consoleField;
- nextHistoryLine++;
- historyLine = nextHistoryLine;
-
- Field_Clear( &g_consoleField );
-
- g_consoleField.widthInChars = g_console_field_width;
-
- CL_SaveConsoleHistory( );
-
- if ( cls.state == CA_DISCONNECTED ) {
- SCR_UpdateScreen (); // force an update, because the command
- } // may take some time
- return;
- }
-
- // command completion
-
- if (key == K_TAB) {
- Field_AutoComplete(&g_consoleField);
- return;
- }
-
- // command history (ctrl-p ctrl-n for unix style)
-
- if ( (key == K_MWHEELUP && keys[K_SHIFT].down) || ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
- ( ( tolower(key) == 'p' ) && keys[K_CTRL].down ) ) {
- if ( nextHistoryLine - historyLine < COMMAND_HISTORY
- && historyLine > 0 ) {
- historyLine--;
- }
- g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
- return;
- }
-
- if ( (key == K_MWHEELDOWN && keys[K_SHIFT].down) || ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
- ( ( tolower(key) == 'n' ) && keys[K_CTRL].down ) ) {
- historyLine++;
- if (historyLine >= nextHistoryLine) {
- historyLine = nextHistoryLine;
- Field_Clear( &g_consoleField );
- g_consoleField.widthInChars = g_console_field_width;
- return;
- }
- g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
- return;
- }
-
- // console scrolling
- if ( key == K_PGUP ) {
- Con_PageUp();
- return;
- }
-
- if ( key == K_PGDN) {
- Con_PageDown();
- return;
- }
-
- if ( key == K_MWHEELUP) { //----(SA) added some mousewheel functionality to the console
- Con_PageUp();
- if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling
- Con_PageUp();
- Con_PageUp();
- }
- return;
- }
-
- if ( key == K_MWHEELDOWN) { //----(SA) added some mousewheel functionality to the console
- Con_PageDown();
- if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling
- Con_PageDown();
- Con_PageDown();
- }
- return;
- }
-
- // ctrl-home = top of console
- if ( key == K_HOME && keys[K_CTRL].down ) {
- Con_Top();
- return;
- }
-
- // ctrl-end = bottom of console
- if ( key == K_END && keys[K_CTRL].down ) {
- Con_Bottom();
- return;
- }
-
- // pass to the normal editline routine
- Field_KeyDownEvent( &g_consoleField, key );
-}
-
-//============================================================================
-
-
-/*
-================
-Message_Key
-
-In game talk message
-================
-*/
-void Message_Key( int key ) {
-
- char buffer[MAX_STRING_CHARS];
-
-
- if (key == K_ESCAPE) {
- Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_MESSAGE );
- Field_Clear( &chatField );
- return;
- }
-
- if ( key == K_ENTER || key == K_KP_ENTER )
- {
- if ( chatField.buffer[0] && cls.state == CA_ACTIVE ) {
- if (chat_playerNum != -1 )
-
- Com_sprintf( buffer, sizeof( buffer ), "tell %i \"%s\"\n", chat_playerNum, chatField.buffer );
-
- else if (chat_team)
-
- Com_sprintf( buffer, sizeof( buffer ), "say_team \"%s\"\n", chatField.buffer );
- else
- Com_sprintf( buffer, sizeof( buffer ), "say \"%s\"\n", chatField.buffer );
-
-
-
- CL_AddReliableCommand(buffer, qfalse);
- }
- Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_MESSAGE );
- Field_Clear( &chatField );
- return;
- }
-
- Field_KeyDownEvent( &chatField, key );
-}
-
-//============================================================================
-
-
-qboolean Key_GetOverstrikeMode( void ) {
- return key_overstrikeMode;
-}
-
-
-void Key_SetOverstrikeMode( qboolean state ) {
- key_overstrikeMode = state;
-}
-
-
-/*
-===================
-Key_IsDown
-===================
-*/
-qboolean Key_IsDown( int keynum ) {
- if ( keynum < 0 || keynum >= MAX_KEYS ) {
- return qfalse;
- }
-
- return keys[keynum].down;
-}
-
-/*
-===================
-Key_StringToKeynum
-
-Returns a key number to be used to index keys[] by looking at
-the given string. Single ascii characters return themselves, while
-the K_* names are matched up.
-
-0x11 will be interpreted as raw hex, which will allow new controlers
-
-to be configured even if they don't have defined names.
-===================
-*/
-int Key_StringToKeynum( char *str ) {
- keyname_t *kn;
-
- if ( !str || !str[0] ) {
- return -1;
- }
- if ( !str[1] ) {
- return str[0];
- }
-
- // check for hex code
- if ( strlen( str ) == 4 ) {
- int n = Com_HexStrToInt( str );
-
- if ( n >= 0 ) {
- return n;
- }
- }
-
- // scan for a text match
- for ( kn=keynames ; kn->name ; kn++ ) {
- if ( !Q_stricmp( str,kn->name ) )
- return kn->keynum;
- }
-
- return -1;
-}
-
-/*
-===================
-Key_KeynumToString
-
-Returns a string (either a single ascii char, a K_* name, or a 0x11 hex string) for the
-given keynum.
-===================
-*/
-char *Key_KeynumToString( int keynum ) {
- keyname_t *kn;
- static char tinystr[5];
- int i, j;
-
- if ( keynum == -1 ) {
- return "<KEY NOT FOUND>";
- }
-
- if ( keynum < 0 || keynum >= MAX_KEYS ) {
- return "<OUT OF RANGE>";
- }
-
- // check for printable ascii (don't use quote)
- if ( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' ) {
- tinystr[0] = keynum;
- tinystr[1] = 0;
- return tinystr;
- }
-
- // check for a key string
- for ( kn=keynames ; kn->name ; kn++ ) {
- if (keynum == kn->keynum) {
- return kn->name;
- }
- }
-
- // make a hex string
- i = keynum >> 4;
- j = keynum & 15;
-
- tinystr[0] = '0';
- tinystr[1] = 'x';
- tinystr[2] = i > 9 ? i - 10 + 'a' : i + '0';
- tinystr[3] = j > 9 ? j - 10 + 'a' : j + '0';
- tinystr[4] = 0;
-
- return tinystr;
-}
-
-
-/*
-===================
-Key_SetBinding
-===================
-*/
-void Key_SetBinding( int keynum, const char *binding ) {
- if ( keynum < 0 || keynum >= MAX_KEYS ) {
- return;
- }
-
- // free old bindings
- if ( keys[ keynum ].binding ) {
- Z_Free( keys[ keynum ].binding );
- }
-
- // allocate memory for new binding
- keys[keynum].binding = CopyString( binding );
-
- // consider this like modifying an archived cvar, so the
- // file write will be triggered at the next oportunity
- cvar_modifiedFlags |= CVAR_ARCHIVE;
-}
-
-
-/*
-===================
-Key_GetBinding
-===================
-*/
-char *Key_GetBinding( int keynum ) {
- if ( keynum < 0 || keynum >= MAX_KEYS ) {
- return "";
- }
-
- return keys[ keynum ].binding;
-}
-
-/*
-===================
-Key_GetKey
-===================
-*/
-
-int Key_GetKey(const char *binding) {
- int i;
-
- if (binding) {
- for (i=0 ; i < MAX_KEYS ; i++) {
- if (keys[i].binding && Q_stricmp(binding, keys[i].binding) == 0) {
- return i;
- }
- }
- }
- return -1;
-}
-
-/*
-===================
-Key_Unbind_f
-===================
-*/
-void Key_Unbind_f (void)
-{
- int b;
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("unbind <key> : remove commands from a key\n");
- return;
- }
-
- b = Key_StringToKeynum (Cmd_Argv(1));
- if (b==-1)
- {
- Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
- return;
- }
-
- Key_SetBinding (b, "");
-}
-
-/*
-===================
-Key_Unbindall_f
-===================
-*/
-void Key_Unbindall_f (void)
-{
- int i;
-
- for (i=0 ; i < MAX_KEYS; i++)
- if (keys[i].binding)
- Key_SetBinding (i, "");
-}
-
-
-/*
-===================
-Key_Bind_f
-===================
-*/
-void Key_Bind_f (void)
-{
- int i, c, b;
- char cmd[1024];
-
- c = Cmd_Argc();
-
- if (c < 2)
- {
- Com_Printf ("bind <key> [command] : attach a command to a key\n");
- return;
- }
- b = Key_StringToKeynum (Cmd_Argv(1));
- if (b==-1)
- {
- Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
- return;
- }
-
- if (c == 2)
- {
- if (keys[b].binding)
- Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keys[b].binding );
- else
- Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
- return;
- }
-
-// copy the rest of the command line
- cmd[0] = 0; // start out with a null string
- for (i=2 ; i< c ; i++)
- {
- strcat (cmd, Cmd_Argv(i));
- if (i != (c-1))
- strcat (cmd, " ");
- }
-
- Key_SetBinding (b, cmd);
-}
-
-/*
-============
-Key_WriteBindings
-
-Writes lines containing "bind key value"
-============
-*/
-void Key_WriteBindings( fileHandle_t f ) {
- int i;
-
- FS_Printf (f, "unbindall\n" );
-
- for (i=0 ; i<MAX_KEYS ; i++) {
- if (keys[i].binding && keys[i].binding[0] ) {
- FS_Printf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keys[i].binding);
-
- }
-
- }
-}
-
-
-/*
-============
-Key_Bindlist_f
-
-============
-*/
-void Key_Bindlist_f( void ) {
- int i;
-
- for ( i = 0 ; i < MAX_KEYS ; i++ ) {
- if ( keys[i].binding && keys[i].binding[0] ) {
- Com_Printf( "%s \"%s\"\n", Key_KeynumToString(i), keys[i].binding );
- }
- }
-}
-
-/*
-============
-Key_KeynameCompletion
-============
-*/
-void Key_KeynameCompletion( void(*callback)(const char *s) ) {
- int i;
-
- for( i = 0; keynames[ i ].name != NULL; i++ )
- callback( keynames[ i ].name );
-}
-
-/*
-====================
-Key_CompleteUnbind
-====================
-*/
-static void Key_CompleteUnbind( char *args, int argNum )
-{
- if( argNum == 2 )
- {
- // Skip "unbind "
- char *p = Com_SkipTokens( args, 1, " " );
-
- if( p > args )
- Field_CompleteKeyname( );
- }
-}
-
-/*
-====================
-Key_CompleteBind
-====================
-*/
-static void Key_CompleteBind( char *args, int argNum )
-{
- char *p;
-
- if( argNum == 2 )
- {
- // Skip "bind "
- p = Com_SkipTokens( args, 1, " " );
-
- if( p > args )
- Field_CompleteKeyname( );
- }
- else if( argNum >= 3 )
- {
- // Skip "bind <key> "
- p = Com_SkipTokens( args, 2, " " );
-
- if( p > args )
- Field_CompleteCommand( p, qtrue, qtrue );
- }
-}
-
-/*
-===================
-CL_InitKeyCommands
-===================
-*/
-void CL_InitKeyCommands( void ) {
- // register our functions
- Cmd_AddCommand ("bind",Key_Bind_f);
- Cmd_SetCommandCompletionFunc( "bind", Key_CompleteBind );
- Cmd_AddCommand ("unbind",Key_Unbind_f);
- Cmd_SetCommandCompletionFunc( "unbind", Key_CompleteUnbind );
- Cmd_AddCommand ("unbindall",Key_Unbindall_f);
- Cmd_AddCommand ("bindlist",Key_Bindlist_f);
-}
-
-/*
-===================
-CL_ParseBinding
-
-Execute the commands in the bind string
-===================
-*/
-void CL_ParseBinding( int key, qboolean down, unsigned time )
-{
- char buf[ MAX_STRING_CHARS ], *p = buf, *end;
-
- if( !keys[key].binding || !keys[key].binding[0] )
- return;
- Q_strncpyz( buf, keys[key].binding, sizeof( buf ) );
-
- while( 1 )
- {
- while( isspace( *p ) )
- p++;
- end = strchr( p, ';' );
- if( end )
- *end = '\0';
- if( *p == '+' )
- {
- // button commands add keynum and time as parameters
- // so that multiple sources can be discriminated and
- // subframe corrected
- char cmd[1024];
- Com_sprintf( cmd, sizeof( cmd ), "%c%s %d %d\n",
- ( down ) ? '+' : '-', p + 1, key, time );
- Cbuf_AddText( cmd );
- }
- else if( down )
- {
- // normal commands only execute on key press
- Cbuf_AddText( p );
- Cbuf_AddText( "\n" );
- }
- if( !end )
- break;
- p = end + 1;
- }
-}
-
-/*
-===================
-CL_KeyDownEvent
-
-Called by CL_KeyEvent to handle a keypress
-===================
-*/
-void CL_KeyDownEvent( int key, unsigned time )
-{
- keys[key].down = qtrue;
- keys[key].repeats++;
- if( keys[key].repeats == 1 )
- anykeydown++;
-
- if( keys[K_ALT].down && key == K_ENTER )
- {
- Cvar_SetValue( "r_fullscreen",
- !Cvar_VariableIntegerValue( "r_fullscreen" ) );
- return;
- }
-
- // console key is hardcoded, so the user can never unbind it
- if( key == K_CONSOLE || ( keys[K_SHIFT].down && key == K_ESCAPE ) )
- {
- Con_ToggleConsole_f ();
- Key_ClearStates ();
- return;
- }
-
-
- // keys can still be used for bound actions
- if ( ( key < 128 || key == K_MOUSE1 ) &&
- ( clc.demoplaying || cls.state == CA_CINEMATIC ) && Key_GetCatcher( ) == 0 ) {
-
- if (Cvar_VariableValue ("com_cameraMode") == 0) {
- Cvar_Set ("nextdemo","");
- key = K_ESCAPE;
- }
- }
-
- // escape is always handled special
- if ( key == K_ESCAPE ) {
- if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) {
- // clear message mode
- Message_Key( key );
- return;
- }
-
- // escape always gets out of CGAME stuff
- if (Key_GetCatcher( ) & KEYCATCH_CGAME) {
- Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CGAME );
- VM_Call (cgvm, CG_EVENT_HANDLING, CGAME_EVENT_NONE);
- return;
- }
-
- if ( !( Key_GetCatcher( ) & KEYCATCH_UI ) ) {
- if ( cls.state == CA_ACTIVE && !clc.demoplaying ) {
- VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_INGAME );
- }
- else if ( cls.state != CA_DISCONNECTED ) {
- CL_Disconnect_f();
- S_StopAllSounds();
- VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN );
- }
- return;
- }
-
- VM_Call( uivm, UI_KEY_EVENT, key, qtrue );
- return;
- }
-
- // distribute the key down event to the apropriate handler
- if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) {
- Console_Key( key );
- } else if ( Key_GetCatcher( ) & KEYCATCH_UI ) {
- if ( uivm ) {
- VM_Call( uivm, UI_KEY_EVENT, key, qtrue );
- }
- } else if ( Key_GetCatcher( ) & KEYCATCH_CGAME ) {
- if ( cgvm ) {
- VM_Call( cgvm, CG_KEY_EVENT, key, qtrue );
- }
- } else if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) {
- Message_Key( key );
- } else if ( cls.state == CA_DISCONNECTED ) {
- Console_Key( key );
- } else {
- // send the bound action
- CL_ParseBinding( key, qtrue, time );
- }
- return;
-}
-
-/*
-===================
-CL_KeyUpEvent
-
-Called by CL_KeyEvent to handle a keyrelease
-===================
-*/
-void CL_KeyUpEvent( int key, unsigned time )
-{
- keys[key].repeats = 0;
- keys[key].down = qfalse;
- anykeydown--;
- if (anykeydown < 0) {
- anykeydown = 0;
- }
-
- // don't process key-up events for the console key
- if ( key == K_CONSOLE || ( key == K_ESCAPE && keys[K_SHIFT].down ) )
- return;
-
- //
- // key up events only perform actions if the game key binding is
- // a button command (leading + sign). These will be processed even in
- // console mode and menu mode, to keep the character from continuing
- // an action started before a mode switch.
- //
- if( cls.state != CA_DISCONNECTED )
- CL_ParseBinding( key, qfalse, time );
-
- if ( Key_GetCatcher( ) & KEYCATCH_UI && uivm ) {
- VM_Call( uivm, UI_KEY_EVENT, key, qfalse );
- } else if ( Key_GetCatcher( ) & KEYCATCH_CGAME && cgvm ) {
- VM_Call( cgvm, CG_KEY_EVENT, key, qfalse );
- }
-}
-
-/*
-===================
-CL_KeyEvent
-
-Called by the system for both key up and key down events
-===================
-*/
-void CL_KeyEvent (int key, qboolean down, unsigned time) {
- if( down )
- CL_KeyDownEvent( key, time );
- else
- CL_KeyUpEvent( key, time );
-}
-
-/*
-===================
-CL_CharEvent
-
-Normal keyboard characters, already shifted / capslocked / etc
-===================
-*/
-void CL_CharEvent( int key ) {
- // delete is not a printable character and is
- // otherwise handled by Field_KeyDownEvent
- if ( key == 127 ) {
- return;
- }
-
- // distribute the key down event to the apropriate handler
- if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE )
- {
- Field_CharEvent( &g_consoleField, key );
- }
- else if ( Key_GetCatcher( ) & KEYCATCH_UI )
- {
- VM_Call( uivm, UI_KEY_EVENT, key | K_CHAR_FLAG, qtrue );
- }
- else if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE )
- {
- Field_CharEvent( &chatField, key );
- }
- else if ( cls.state == CA_DISCONNECTED )
- {
- Field_CharEvent( &g_consoleField, key );
- }
-}
-
-
-/*
-===================
-Key_ClearStates
-===================
-*/
-void Key_ClearStates (void)
-{
- int i;
-
- anykeydown = 0;
-
- for ( i=0 ; i < MAX_KEYS ; i++ ) {
- if ( keys[i].down ) {
- CL_KeyEvent( i, qfalse, 0 );
-
- }
- keys[i].down = 0;
- keys[i].repeats = 0;
- }
-}
-
-static int keyCatchers = 0;
-
-/*
-====================
-Key_GetCatcher
-====================
-*/
-int Key_GetCatcher( void ) {
- return keyCatchers;
-}
-
-/*
-====================
-Key_SetCatcher
-====================
-*/
-void Key_SetCatcher( int catcher ) {
- // If the catcher state is changing, clear all key states
- if( catcher != keyCatchers )
- Key_ClearStates( );
-
- keyCatchers = catcher;
-}
-
-// This must not exceed MAX_CMD_LINE
-#define MAX_CONSOLE_SAVE_BUFFER 1024
-#define CONSOLE_HISTORY_FILE "q3history"
-static char consoleSaveBuffer[ MAX_CONSOLE_SAVE_BUFFER ];
-static int consoleSaveBufferSize = 0;
-
-/*
-================
-CL_LoadConsoleHistory
-
-Load the console history from cl_consoleHistory
-================
-*/
-void CL_LoadConsoleHistory( void )
-{
- char *token, *text_p;
- int i, numChars, numLines = 0;
- fileHandle_t f;
-
- consoleSaveBufferSize = FS_FOpenFileRead( CONSOLE_HISTORY_FILE, &f, qfalse );
- if( !f )
- {
- Com_Printf( "Couldn't read %s.\n", CONSOLE_HISTORY_FILE );
- return;
- }
-
- if( consoleSaveBufferSize <= MAX_CONSOLE_SAVE_BUFFER &&
- FS_Read( consoleSaveBuffer, consoleSaveBufferSize, f ) == consoleSaveBufferSize )
- {
- text_p = consoleSaveBuffer;
-
- for( i = COMMAND_HISTORY - 1; i >= 0; i-- )
- {
- if( !*( token = COM_Parse( &text_p ) ) )
- break;
-
- historyEditLines[ i ].cursor = atoi( token );
-
- if( !*( token = COM_Parse( &text_p ) ) )
- break;
-
- historyEditLines[ i ].scroll = atoi( token );
-
- if( !*( token = COM_Parse( &text_p ) ) )
- break;
-
- numChars = atoi( token );
- text_p++;
- if( numChars > ( strlen( consoleSaveBuffer ) - ( text_p - consoleSaveBuffer ) ) )
- {
- Com_DPrintf( S_COLOR_YELLOW "WARNING: probable corrupt history\n" );
- break;
- }
- Com_Memcpy( historyEditLines[ i ].buffer,
- text_p, numChars );
- historyEditLines[ i ].buffer[ numChars ] = '\0';
- text_p += numChars;
-
- numLines++;
- }
-
- memmove( &historyEditLines[ 0 ], &historyEditLines[ i + 1 ],
- numLines * sizeof( field_t ) );
- for( i = numLines; i < COMMAND_HISTORY; i++ )
- Field_Clear( &historyEditLines[ i ] );
-
- historyLine = nextHistoryLine = numLines;
- }
- else
- Com_Printf( "Couldn't read %s.\n", CONSOLE_HISTORY_FILE );
-
- FS_FCloseFile( f );
-}
-
-/*
-================
-CL_SaveConsoleHistory
-
-Save the console history into the cvar cl_consoleHistory
-so that it persists across invocations of q3
-================
-*/
-void CL_SaveConsoleHistory( void )
-{
- int i;
- int lineLength, saveBufferLength, additionalLength;
- fileHandle_t f;
-
- consoleSaveBuffer[ 0 ] = '\0';
-
- i = ( nextHistoryLine - 1 ) % COMMAND_HISTORY;
- do
- {
- if( historyEditLines[ i ].buffer[ 0 ] )
- {
- lineLength = strlen( historyEditLines[ i ].buffer );
- saveBufferLength = strlen( consoleSaveBuffer );
-
- //ICK
- additionalLength = lineLength + strlen( "999 999 999 " );
-
- if( saveBufferLength + additionalLength < MAX_CONSOLE_SAVE_BUFFER )
- {
- Q_strcat( consoleSaveBuffer, MAX_CONSOLE_SAVE_BUFFER,
- va( "%d %d %d %s ",
- historyEditLines[ i ].cursor,
- historyEditLines[ i ].scroll,
- lineLength,
- historyEditLines[ i ].buffer ) );
- }
- else
- break;
- }
- i = ( i - 1 + COMMAND_HISTORY ) % COMMAND_HISTORY;
- }
- while( i != ( nextHistoryLine - 1 ) % COMMAND_HISTORY );
-
- consoleSaveBufferSize = strlen( consoleSaveBuffer );
-
- f = FS_FOpenFileWrite( CONSOLE_HISTORY_FILE );
- if( !f )
- {
- Com_Printf( "Couldn't write %s.\n", CONSOLE_HISTORY_FILE );
- return;
- }
-
- if( FS_Write( consoleSaveBuffer, consoleSaveBufferSize, f ) < consoleSaveBufferSize )
- Com_Printf( "Couldn't write %s.\n", CONSOLE_HISTORY_FILE );
-
- FS_FCloseFile( f );
-}
diff --git a/engine/code/client/cl_main.c b/engine/code/client/cl_main.c
deleted file mode 100644
index 8695d57..0000000
--- a/engine/code/client/cl_main.c
+++ /dev/null
@@ -1,4231 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// cl_main.c -- client main loop
-
-#include "client.h"
-#include <limits.h>
-
-#ifdef USE_MUMBLE
-#include "libmumblelink.h"
-#endif
-
-#ifdef USE_MUMBLE
-cvar_t *cl_useMumble;
-cvar_t *cl_mumbleScale;
-#endif
-
-#ifdef USE_VOIP
-cvar_t *cl_voipUseVAD;
-cvar_t *cl_voipVADThreshold;
-cvar_t *cl_voipSend;
-cvar_t *cl_voipSendTarget;
-cvar_t *cl_voipGainDuringCapture;
-cvar_t *cl_voipCaptureMult;
-cvar_t *cl_voipShowMeter;
-cvar_t *cl_voip;
-#endif
-
-cvar_t *cl_nodelta;
-cvar_t *cl_debugMove;
-
-cvar_t *cl_noprint;
-cvar_t *cl_motd;
-
-cvar_t *rcon_client_password;
-cvar_t *rconAddress;
-
-cvar_t *cl_timeout;
-cvar_t *cl_maxpackets;
-cvar_t *cl_packetdup;
-cvar_t *cl_timeNudge;
-cvar_t *cl_showTimeDelta;
-cvar_t *cl_freezeDemo;
-
-cvar_t *cl_shownet;
-cvar_t *cl_showSend;
-cvar_t *cl_timedemo;
-cvar_t *cl_timedemoLog;
-cvar_t *cl_autoRecordDemo;
-cvar_t *cl_aviFrameRate;
-cvar_t *cl_aviMotionJpeg;
-cvar_t *cl_forceavidemo;
-
-cvar_t *cl_freelook;
-cvar_t *cl_sensitivity;
-
-cvar_t *cl_mouseAccel;
-cvar_t *cl_mouseAccelOffset;
-cvar_t *cl_mouseAccelStyle;
-cvar_t *cl_showMouseRate;
-
-cvar_t *m_pitch;
-cvar_t *m_yaw;
-cvar_t *m_forward;
-cvar_t *m_side;
-cvar_t *m_filter;
-
-cvar_t *cl_activeAction;
-
-cvar_t *cl_motdString;
-
-cvar_t *cl_allowDownload;
-cvar_t *cl_conXOffset;
-cvar_t *cl_inGameVideo;
-
-cvar_t *cl_serverStatusResendTime;
-cvar_t *cl_trn;
-
-cvar_t *cl_lanForcePackets;
-
-cvar_t *cl_guidServerUniq;
-
-cvar_t *cl_consoleKeys;
-
-clientActive_t cl;
-clientConnection_t clc;
-clientStatic_t cls;
-vm_t *cgvm;
-
-// Structure containing functions exported from refresh DLL
-refexport_t re;
-
-ping_t cl_pinglist[MAX_PINGREQUESTS];
-
-typedef struct serverStatus_s
-{
- char string[BIG_INFO_STRING];
- netadr_t address;
- int time, startTime;
- qboolean pending;
- qboolean print;
- qboolean retrieved;
-} serverStatus_t;
-
-serverStatus_t cl_serverStatusList[MAX_SERVERSTATUSREQUESTS];
-int serverStatusCount;
-
-#if defined __USEA3D && defined __A3D_GEOM
- void hA3Dg_ExportRenderGeom (refexport_t *incoming_re);
-#endif
-
-extern void SV_BotFrame( int time );
-void CL_CheckForResend( void );
-void CL_ShowIP_f(void);
-void CL_ServerStatus_f(void);
-void CL_ServerStatusResponse( netadr_t from, msg_t *msg );
-
-/*
-===============
-CL_CDDialog
-
-Called by Com_Error when a cd is needed
-===============
-*/
-void CL_CDDialog( void ) {
- cls.cddialog = qtrue; // start it next frame
-}
-
-#ifdef USE_MUMBLE
-static
-void CL_UpdateMumble(void)
-{
- vec3_t pos, forward, up;
- float scale = cl_mumbleScale->value;
- float tmp;
-
- if(!cl_useMumble->integer)
- return;
-
- // !!! FIXME: not sure if this is even close to correct.
- AngleVectors( cl.snap.ps.viewangles, forward, NULL, up);
-
- pos[0] = cl.snap.ps.origin[0] * scale;
- pos[1] = cl.snap.ps.origin[2] * scale;
- pos[2] = cl.snap.ps.origin[1] * scale;
-
- tmp = forward[1];
- forward[1] = forward[2];
- forward[2] = tmp;
-
- tmp = up[1];
- up[1] = up[2];
- up[2] = tmp;
-
- if(cl_useMumble->integer > 1) {
- fprintf(stderr, "%f %f %f, %f %f %f, %f %f %f\n",
- pos[0], pos[1], pos[2],
- forward[0], forward[1], forward[2],
- up[0], up[1], up[2]);
- }
-
- mumble_update_coordinates(pos, forward, up);
-}
-#endif
-
-
-#ifdef USE_VOIP
-static
-void CL_UpdateVoipIgnore(const char *idstr, qboolean ignore)
-{
- if ((*idstr >= '0') && (*idstr <= '9')) {
- const int id = atoi(idstr);
- if ((id >= 0) && (id < MAX_CLIENTS)) {
- clc.voipIgnore[id] = ignore;
- CL_AddReliableCommand(va("voip %s %d",
- ignore ? "ignore" : "unignore", id), qfalse);
- Com_Printf("VoIP: %s ignoring player #%d\n",
- ignore ? "Now" : "No longer", id);
- return;
- }
- }
- Com_Printf("VoIP: invalid player ID#\n");
-}
-
-static
-void CL_UpdateVoipGain(const char *idstr, float gain)
-{
- if ((*idstr >= '0') && (*idstr <= '9')) {
- const int id = atoi(idstr);
- if (gain < 0.0f)
- gain = 0.0f;
- if ((id >= 0) && (id < MAX_CLIENTS)) {
- clc.voipGain[id] = gain;
- Com_Printf("VoIP: player #%d gain now set to %f\n", id, gain);
- }
- }
-}
-
-void CL_Voip_f( void )
-{
- const char *cmd = Cmd_Argv(1);
- const char *reason = NULL;
-
- if (cls.state != CA_ACTIVE)
- reason = "Not connected to a server";
- else if (!clc.speexInitialized)
- reason = "Speex not initialized";
- else if (!cl_connectedToVoipServer)
- reason = "Server doesn't support VoIP";
- else if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive"))
- reason = "running in single-player mode";
-
- if (reason != NULL) {
- Com_Printf("VoIP: command ignored: %s\n", reason);
- return;
- }
-
- if (strcmp(cmd, "ignore") == 0) {
- CL_UpdateVoipIgnore(Cmd_Argv(2), qtrue);
- } else if (strcmp(cmd, "unignore") == 0) {
- CL_UpdateVoipIgnore(Cmd_Argv(2), qfalse);
- } else if (strcmp(cmd, "gain") == 0) {
- if (Cmd_Argc() > 3) {
- CL_UpdateVoipGain(Cmd_Argv(2), atof(Cmd_Argv(3)));
- } else if (Q_isanumber(Cmd_Argv(2))) {
- int id = atoi(Cmd_Argv(2));
- if (id >= 0 && id < MAX_CLIENTS) {
- Com_Printf("VoIP: current gain for player #%d "
- "is %f\n", id, clc.voipGain[id]);
- } else {
- Com_Printf("VoIP: invalid player ID#\n");
- }
- } else {
- Com_Printf("usage: voip gain <playerID#> [value]\n");
- }
- } else if (strcmp(cmd, "muteall") == 0) {
- Com_Printf("VoIP: muting incoming voice\n");
- CL_AddReliableCommand("voip muteall", qfalse);
- clc.voipMuteAll = qtrue;
- } else if (strcmp(cmd, "unmuteall") == 0) {
- Com_Printf("VoIP: unmuting incoming voice\n");
- CL_AddReliableCommand("voip unmuteall", qfalse);
- clc.voipMuteAll = qfalse;
- } else {
- Com_Printf("usage: voip [un]ignore <playerID#>\n"
- " voip [un]muteall\n"
- " voip gain <playerID#> [value]\n");
- }
-}
-
-
-static
-void CL_VoipNewGeneration(void)
-{
- // don't have a zero generation so new clients won't match, and don't
- // wrap to negative so MSG_ReadLong() doesn't "fail."
- clc.voipOutgoingGeneration++;
- if (clc.voipOutgoingGeneration <= 0)
- clc.voipOutgoingGeneration = 1;
- clc.voipPower = 0.0f;
- clc.voipOutgoingSequence = 0;
-}
-
-/*
-===============
-CL_CaptureVoip
-
-Record more audio from the hardware if required and encode it into Speex
- data for later transmission.
-===============
-*/
-static
-void CL_CaptureVoip(void)
-{
- const float audioMult = cl_voipCaptureMult->value;
- const qboolean useVad = (cl_voipUseVAD->integer != 0);
- qboolean initialFrame = qfalse;
- qboolean finalFrame = qfalse;
-
-#if USE_MUMBLE
- // if we're using Mumble, don't try to handle VoIP transmission ourselves.
- if (cl_useMumble->integer)
- return;
-#endif
-
- if (!clc.speexInitialized)
- return; // just in case this gets called at a bad time.
-
- if (clc.voipOutgoingDataSize > 0)
- return; // packet is pending transmission, don't record more yet.
-
- if (cl_voipUseVAD->modified) {
- Cvar_Set("cl_voipSend", (useVad) ? "1" : "0");
- cl_voipUseVAD->modified = qfalse;
- }
-
- if ((useVad) && (!cl_voipSend->integer))
- Cvar_Set("cl_voipSend", "1"); // lots of things reset this.
-
- if (cl_voipSend->modified) {
- qboolean dontCapture = qfalse;
- if (cls.state != CA_ACTIVE)
- dontCapture = qtrue; // not connected to a server.
- else if (!cl_connectedToVoipServer)
- dontCapture = qtrue; // server doesn't support VoIP.
- else if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive"))
- dontCapture = qtrue; // single player game.
- else if (clc.demoplaying)
- dontCapture = qtrue; // playing back a demo.
- else if ( cl_voip->integer == 0 )
- dontCapture = qtrue; // client has VoIP support disabled.
- else if ( audioMult == 0.0f )
- dontCapture = qtrue; // basically silenced incoming audio.
-
- cl_voipSend->modified = qfalse;
-
- if (dontCapture) {
- cl_voipSend->integer = 0;
- return;
- }
-
- if (cl_voipSend->integer) {
- initialFrame = qtrue;
- } else {
- finalFrame = qtrue;
- }
- }
-
- // try to get more audio data from the sound card...
-
- if (initialFrame) {
- float gain = cl_voipGainDuringCapture->value;
- if (gain < 0.0f) gain = 0.0f; else if (gain >= 1.0f) gain = 1.0f;
- S_MasterGain(cl_voipGainDuringCapture->value);
- S_StartCapture();
- CL_VoipNewGeneration();
- }
-
- if ((cl_voipSend->integer) || (finalFrame)) { // user wants to capture audio?
- int samples = S_AvailableCaptureSamples();
- const int mult = (finalFrame) ? 1 : 12; // 12 == 240ms of audio.
-
- // enough data buffered in audio hardware to process yet?
- if (samples >= (clc.speexFrameSize * mult)) {
- // audio capture is always MONO16 (and that's what speex wants!).
- // 2048 will cover 12 uncompressed frames in narrowband mode.
- static int16_t sampbuffer[2048];
- float voipPower = 0.0f;
- int speexFrames = 0;
- int wpos = 0;
- int pos = 0;
-
- if (samples > (clc.speexFrameSize * 12))
- samples = (clc.speexFrameSize * 12);
-
- // !!! FIXME: maybe separate recording from encoding, so voipPower
- // !!! FIXME: updates faster than 4Hz?
-
- samples -= samples % clc.speexFrameSize;
- S_Capture(samples, (byte *) sampbuffer); // grab from audio card.
-
- // this will probably generate multiple speex packets each time.
- while (samples > 0) {
- int16_t *sampptr = &sampbuffer[pos];
- int i, bytes;
-
- // preprocess samples to remove noise...
- speex_preprocess_run(clc.speexPreprocessor, sampptr);
-
- // check the "power" of this packet...
- for (i = 0; i < clc.speexFrameSize; i++) {
- const float flsamp = (float) sampptr[i];
- const float s = fabs(flsamp);
- voipPower += s * s;
- sampptr[i] = (int16_t) ((flsamp) * audioMult);
- }
-
- // encode raw audio samples into Speex data...
- speex_bits_reset(&clc.speexEncoderBits);
- speex_encode_int(clc.speexEncoder, sampptr,
- &clc.speexEncoderBits);
- bytes = speex_bits_write(&clc.speexEncoderBits,
- (char *) &clc.voipOutgoingData[wpos+1],
- sizeof (clc.voipOutgoingData) - (wpos+1));
- assert((bytes > 0) && (bytes < 256));
- clc.voipOutgoingData[wpos] = (byte) bytes;
- wpos += bytes + 1;
-
- // look at the data for the next packet...
- pos += clc.speexFrameSize;
- samples -= clc.speexFrameSize;
- speexFrames++;
- }
-
- clc.voipPower = (voipPower / (32768.0f * 32768.0f *
- ((float) (clc.speexFrameSize * speexFrames)))) *
- 100.0f;
-
- if ((useVad) && (clc.voipPower < cl_voipVADThreshold->value)) {
- CL_VoipNewGeneration(); // no "talk" for at least 1/4 second.
- } else {
- clc.voipOutgoingDataSize = wpos;
- clc.voipOutgoingDataFrames = speexFrames;
-
- Com_DPrintf("VoIP: Send %d frames, %d bytes, %f power\n",
- speexFrames, wpos, clc.voipPower);
-
- #if 0
- static FILE *encio = NULL;
- if (encio == NULL) encio = fopen("voip-outgoing-encoded.bin", "wb");
- if (encio != NULL) { fwrite(clc.voipOutgoingData, wpos, 1, encio); fflush(encio); }
- static FILE *decio = NULL;
- if (decio == NULL) decio = fopen("voip-outgoing-decoded.bin", "wb");
- if (decio != NULL) { fwrite(sampbuffer, speexFrames * clc.speexFrameSize * 2, 1, decio); fflush(decio); }
- #endif
- }
- }
- }
-
- // User requested we stop recording, and we've now processed the last of
- // any previously-buffered data. Pause the capture device, etc.
- if (finalFrame) {
- S_StopCapture();
- S_MasterGain(1.0f);
- clc.voipPower = 0.0f; // force this value so it doesn't linger.
- }
-}
-#endif
-
-/*
-=======================================================================
-
-CLIENT RELIABLE COMMAND COMMUNICATION
-
-=======================================================================
-*/
-
-/*
-======================
-CL_AddReliableCommand
-
-The given command will be transmitted to the server, and is gauranteed to
-not have future usercmd_t executed before it is executed
-======================
-*/
-void CL_AddReliableCommand(const char *cmd, qboolean isDisconnectCmd)
-{
- int unacknowledged = clc.reliableSequence - clc.reliableAcknowledge;
-
- // if we would be losing an old command that hasn't been acknowledged,
- // we must drop the connection
- // also leave one slot open for the disconnect command in this case.
-
- if ((isDisconnectCmd && unacknowledged > MAX_RELIABLE_COMMANDS) ||
- (!isDisconnectCmd && unacknowledged >= MAX_RELIABLE_COMMANDS))
- {
- if(com_errorEntered)
- return;
- else
- Com_Error(ERR_DROP, "Client command overflow");
- }
-
- Q_strncpyz(clc.reliableCommands[++clc.reliableSequence & (MAX_RELIABLE_COMMANDS - 1)],
- cmd, sizeof(*clc.reliableCommands));
-}
-
-/*
-======================
-CL_ChangeReliableCommand
-======================
-*/
-void CL_ChangeReliableCommand( void ) {
- int r, index, l;
-
- r = clc.reliableSequence - (random() * 5);
- index = clc.reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );
- l = strlen(clc.reliableCommands[ index ]);
- if ( l >= MAX_STRING_CHARS - 1 ) {
- l = MAX_STRING_CHARS - 2;
- }
- clc.reliableCommands[ index ][ l ] = '\n';
- clc.reliableCommands[ index ][ l+1 ] = '\0';
-}
-
-/*
-=======================================================================
-
-CLIENT SIDE DEMO RECORDING
-
-=======================================================================
-*/
-
-/*
-====================
-CL_WriteDemoMessage
-
-Dumps the current net message, prefixed by the length
-====================
-*/
-
-void CL_WriteDemoMessage ( msg_t *msg, int headerBytes ) {
- int len, swlen;
-
- // write the packet sequence
- len = clc.serverMessageSequence;
- swlen = LittleLong( len );
- FS_Write (&swlen, 4, clc.demofile);
-
- // skip the packet sequencing information
- len = msg->cursize - headerBytes;
- swlen = LittleLong(len);
- FS_Write (&swlen, 4, clc.demofile);
- FS_Write ( msg->data + headerBytes, len, clc.demofile );
-}
-
-
-/*
-====================
-CL_StopRecording_f
-
-stop recording a demo
-====================
-*/
-void CL_StopRecord_f( void ) {
- int len;
-
- if ( !clc.demorecording ) {
- Com_Printf ("Not recording a demo.\n");
- return;
- }
-
- // finish up
- len = -1;
- FS_Write (&len, 4, clc.demofile);
- FS_Write (&len, 4, clc.demofile);
- FS_FCloseFile (clc.demofile);
- clc.demofile = 0;
- clc.demorecording = qfalse;
- clc.spDemoRecording = qfalse;
- Com_Printf ("Stopped demo.\n");
-}
-
-/*
-==================
-CL_DemoFilename
-==================
-*/
-void CL_DemoFilename( int number, char *fileName ) {
- int a,b,c,d;
-
- if(number < 0 || number > 9999)
- number = 9999;
-
- a = number / 1000;
- number -= a*1000;
- b = number / 100;
- number -= b*100;
- c = number / 10;
- number -= c*10;
- d = number;
-
- Com_sprintf( fileName, MAX_OSPATH, "demo%i%i%i%i"
- , a, b, c, d );
-}
-
-/*
-====================
-CL_Record_f
-
-record <demoname>
-
-Begins recording a demo from the current position
-====================
-*/
-static char demoName[MAX_QPATH]; // compiler bug workaround
-void CL_Record_f( void ) {
- char name[MAX_OSPATH];
- byte bufData[MAX_MSGLEN];
- msg_t buf;
- int i;
- int len;
- entityState_t *ent;
- entityState_t nullstate;
- char *s;
-
- if ( Cmd_Argc() > 2 ) {
- Com_Printf ("record <demoname>\n");
- return;
- }
-
- if ( clc.demorecording ) {
- if (!clc.spDemoRecording) {
- Com_Printf ("Already recording.\n");
- }
- return;
- }
-
- if ( cls.state != CA_ACTIVE ) {
- Com_Printf ("You must be in a level to record.\n");
- return;
- }
-
- // sync 0 doesn't prevent recording, so not forcing it off .. everyone does g_sync 1 ; record ; g_sync 0 ..
- if ( NET_IsLocalAddress( clc.serverAddress ) && !Cvar_VariableValue( "g_synchronousClients" ) ) {
- Com_Printf (S_COLOR_YELLOW "WARNING: You should set 'g_synchronousClients 1' for smoother demo recording\n");
- }
-
- if ( Cmd_Argc() == 2 ) {
- s = Cmd_Argv(1);
- Q_strncpyz( demoName, s, sizeof( demoName ) );
- Com_sprintf (name, sizeof(name), "demos/%s.dm_%d", demoName, PROTOCOL_VERSION );
- } else {
- int number;
-
- // scan for a free demo name
- for ( number = 0 ; number <= 9999 ; number++ ) {
- CL_DemoFilename( number, demoName );
- Com_sprintf (name, sizeof(name), "demos/%s.dm_%d", demoName, PROTOCOL_VERSION );
-
- if (!FS_FileExists(name))
- break; // file doesn't exist
- }
- }
-
- // open the demo file
-
- Com_Printf ("recording to %s.\n", name);
- clc.demofile = FS_FOpenFileWrite( name );
- if ( !clc.demofile ) {
- Com_Printf ("ERROR: couldn't open.\n");
- return;
- }
- clc.demorecording = qtrue;
- if (Cvar_VariableValue("ui_recordSPDemo")) {
- clc.spDemoRecording = qtrue;
- } else {
- clc.spDemoRecording = qfalse;
- }
-
-
- Q_strncpyz( clc.demoName, demoName, sizeof( clc.demoName ) );
-
- // don't start saving messages until a non-delta compressed message is received
- clc.demowaiting = qtrue;
-
- // write out the gamestate message
- MSG_Init (&buf, bufData, sizeof(bufData));
- MSG_Bitstream(&buf);
-
- // NOTE, MRE: all server->client messages now acknowledge
- MSG_WriteLong( &buf, clc.reliableSequence );
-
- MSG_WriteByte (&buf, svc_gamestate);
- MSG_WriteLong (&buf, clc.serverCommandSequence );
-
- // configstrings
- for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
- if ( !cl.gameState.stringOffsets[i] ) {
- continue;
- }
- s = cl.gameState.stringData + cl.gameState.stringOffsets[i];
- MSG_WriteByte (&buf, svc_configstring);
- MSG_WriteShort (&buf, i);
- MSG_WriteBigString (&buf, s);
- }
-
- // baselines
- Com_Memset (&nullstate, 0, sizeof(nullstate));
- for ( i = 0; i < MAX_GENTITIES ; i++ ) {
- ent = &cl.entityBaselines[i];
- if ( !ent->number ) {
- continue;
- }
- MSG_WriteByte (&buf, svc_baseline);
- MSG_WriteDeltaEntity (&buf, &nullstate, ent, qtrue );
- }
-
- MSG_WriteByte( &buf, svc_EOF );
-
- // finished writing the gamestate stuff
-
- // write the client num
- MSG_WriteLong(&buf, clc.clientNum);
- // write the checksum feed
- MSG_WriteLong(&buf, clc.checksumFeed);
-
- // finished writing the client packet
- MSG_WriteByte( &buf, svc_EOF );
-
- // write it to the demo file
- len = LittleLong( clc.serverMessageSequence - 1 );
- FS_Write (&len, 4, clc.demofile);
-
- len = LittleLong (buf.cursize);
- FS_Write (&len, 4, clc.demofile);
- FS_Write (buf.data, buf.cursize, clc.demofile);
-
- // the rest of the demo file will be copied from net messages
-}
-
-/*
-=======================================================================
-
-CLIENT SIDE DEMO PLAYBACK
-
-=======================================================================
-*/
-
-/*
-=================
-CL_DemoFrameDurationSDev
-=================
-*/
-static float CL_DemoFrameDurationSDev( void )
-{
- int i;
- int numFrames;
- float mean = 0.0f;
- float variance = 0.0f;
-
- if( ( clc.timeDemoFrames - 1 ) > MAX_TIMEDEMO_DURATIONS )
- numFrames = MAX_TIMEDEMO_DURATIONS;
- else
- numFrames = clc.timeDemoFrames - 1;
-
- for( i = 0; i < numFrames; i++ )
- mean += clc.timeDemoDurations[ i ];
- mean /= numFrames;
-
- for( i = 0; i < numFrames; i++ )
- {
- float x = clc.timeDemoDurations[ i ];
-
- variance += ( ( x - mean ) * ( x - mean ) );
- }
- variance /= numFrames;
-
- return sqrt( variance );
-}
-
-/*
-=================
-CL_DemoCompleted
-=================
-*/
-void CL_DemoCompleted( void )
-{
- char buffer[ MAX_STRING_CHARS ];
-
- if( cl_timedemo && cl_timedemo->integer )
- {
- int time;
-
- time = Sys_Milliseconds() - clc.timeDemoStart;
- if( time > 0 )
- {
- // Millisecond times are frame durations:
- // minimum/average/maximum/std deviation
- Com_sprintf( buffer, sizeof( buffer ),
- "%i frames %3.1f seconds %3.1f fps %d.0/%.1f/%d.0/%.1f ms\n",
- clc.timeDemoFrames,
- time/1000.0,
- clc.timeDemoFrames*1000.0 / time,
- clc.timeDemoMinDuration,
- time / (float)clc.timeDemoFrames,
- clc.timeDemoMaxDuration,
- CL_DemoFrameDurationSDev( ) );
- Com_Printf( "%s", buffer );
-
- // Write a log of all the frame durations
- if( cl_timedemoLog && strlen( cl_timedemoLog->string ) > 0 )
- {
- int i;
- int numFrames;
- fileHandle_t f;
-
- if( ( clc.timeDemoFrames - 1 ) > MAX_TIMEDEMO_DURATIONS )
- numFrames = MAX_TIMEDEMO_DURATIONS;
- else
- numFrames = clc.timeDemoFrames - 1;
-
- f = FS_FOpenFileWrite( cl_timedemoLog->string );
- if( f )
- {
- FS_Printf( f, "# %s", buffer );
-
- for( i = 0; i < numFrames; i++ )
- FS_Printf( f, "%d\n", clc.timeDemoDurations[ i ] );
-
- FS_FCloseFile( f );
- Com_Printf( "%s written\n", cl_timedemoLog->string );
- }
- else
- {
- Com_Printf( "Couldn't open %s for writing\n",
- cl_timedemoLog->string );
- }
- }
- }
- }
-
- CL_Disconnect( qtrue );
- CL_NextDemo();
-}
-
-/*
-=================
-CL_ReadDemoMessage
-=================
-*/
-void CL_ReadDemoMessage( void ) {
- int r;
- msg_t buf;
- byte bufData[ MAX_MSGLEN ];
- int s;
-
- if ( !clc.demofile ) {
- CL_DemoCompleted ();
- return;
- }
-
- // get the sequence number
- r = FS_Read( &s, 4, clc.demofile);
- if ( r != 4 ) {
- CL_DemoCompleted ();
- return;
- }
- clc.serverMessageSequence = LittleLong( s );
-
- // init the message
- MSG_Init( &buf, bufData, sizeof( bufData ) );
-
- // get the length
- r = FS_Read (&buf.cursize, 4, clc.demofile);
- if ( r != 4 ) {
- CL_DemoCompleted ();
- return;
- }
- buf.cursize = LittleLong( buf.cursize );
- if ( buf.cursize == -1 ) {
- CL_DemoCompleted ();
- return;
- }
- if ( buf.cursize > buf.maxsize ) {
- Com_Error (ERR_DROP, "CL_ReadDemoMessage: demoMsglen > MAX_MSGLEN");
- }
- r = FS_Read( buf.data, buf.cursize, clc.demofile );
- if ( r != buf.cursize ) {
- Com_Printf( "Demo file was truncated.\n");
- CL_DemoCompleted ();
- return;
- }
-
- clc.lastPacketTime = cls.realtime;
- buf.readcount = 0;
- CL_ParseServerMessage( &buf );
-}
-
-/*
-====================
-CL_WalkDemoExt
-====================
-*/
-static void CL_WalkDemoExt(char *arg, char *name, int *demofile)
-{
- int i = 0;
- *demofile = 0;
- while(demo_protocols[i])
- {
- Com_sprintf (name, MAX_OSPATH, "demos/%s.dm_%d", arg, demo_protocols[i]);
- FS_FOpenFileRead( name, demofile, qtrue );
- if (*demofile)
- {
- Com_Printf("Demo file: %s\n", name);
- break;
- }
- else
- Com_Printf("Not found: %s\n", name);
- i++;
- }
-}
-
-/*
-====================
-CL_CompleteDemoName
-====================
-*/
-static void CL_CompleteDemoName( char *args, int argNum )
-{
- if( argNum == 2 )
- {
- char demoExt[ 16 ];
-
- Com_sprintf( demoExt, sizeof( demoExt ), ".dm_%d", PROTOCOL_VERSION );
- Field_CompleteFilename( "demos", demoExt, qtrue );
- }
-}
-
-/*
-====================
-CL_PlayDemo_f
-
-demo <demoname>
-
-====================
-*/
-void CL_PlayDemo_f( void ) {
- char name[MAX_OSPATH];
- char *arg, *ext_test;
- int protocol, i;
- char retry[MAX_OSPATH];
-
- if (Cmd_Argc() != 2) {
- Com_Printf ("demo <demoname>\n");
- return;
- }
-
- // make sure a local server is killed
- // 2 means don't force disconnect of local client
- Cvar_Set( "sv_killserver", "2" );
-
- // open the demo file
- arg = Cmd_Argv(1);
-
- CL_Disconnect( qtrue );
-
- // check for an extension .dm_?? (?? is protocol)
- ext_test = arg + strlen(arg) - 6;
- if ((strlen(arg) > 6) && (ext_test[0] == '.') &&
- ((ext_test[1] == 'd') || (ext_test[1] == 'D')) &&
- ((ext_test[2] == 'm') || (ext_test[2] == 'M')) &&
- (ext_test[3] == '_'))
- {
- protocol = atoi(ext_test+4);
- i=0;
- while(demo_protocols[i])
- {
- if (demo_protocols[i] == protocol)
- break;
- i++;
- }
- if (demo_protocols[i])
- {
- Com_sprintf (name, sizeof(name), "demos/%s", arg);
- FS_FOpenFileRead( name, &clc.demofile, qtrue );
- } else {
- Com_Printf("Protocol %d not supported for demos\n", protocol);
- Q_strncpyz(retry, arg, sizeof(retry));
- retry[strlen(retry)-6] = 0;
- CL_WalkDemoExt( retry, name, &clc.demofile );
- }
- } else {
- CL_WalkDemoExt( arg, name, &clc.demofile );
- }
-
- if (!clc.demofile) {
- Com_Error( ERR_DROP, "couldn't open %s", name);
- return;
- }
- Q_strncpyz( clc.demoName, Cmd_Argv(1), sizeof( clc.demoName ) );
-
- Con_Close();
-
- cls.state = CA_CONNECTED;
- clc.demoplaying = qtrue;
- Q_strncpyz( cls.servername, Cmd_Argv(1), sizeof( cls.servername ) );
-
- // read demo messages until connected
- while ( cls.state >= CA_CONNECTED && cls.state < CA_PRIMED ) {
- CL_ReadDemoMessage();
- }
- // don't get the first snapshot this frame, to prevent the long
- // time from the gamestate load from messing causing a time skip
- clc.firstDemoFrameSkipped = qfalse;
-}
-
-
-/*
-====================
-CL_StartDemoLoop
-
-Closing the main menu will restart the demo loop
-====================
-*/
-void CL_StartDemoLoop( void ) {
- // start the demo loop again
- Cbuf_AddText ("d1\n");
- Key_SetCatcher( 0 );
-}
-
-/*
-==================
-CL_NextDemo
-
-Called when a demo or cinematic finishes
-If the "nextdemo" cvar is set, that command will be issued
-==================
-*/
-void CL_NextDemo( void ) {
- char v[MAX_STRING_CHARS];
-
- Q_strncpyz( v, Cvar_VariableString ("nextdemo"), sizeof(v) );
- v[MAX_STRING_CHARS-1] = 0;
- Com_DPrintf("CL_NextDemo: %s\n", v );
- if (!v[0]) {
- return;
- }
-
- Cvar_Set ("nextdemo","");
- Cbuf_AddText (v);
- Cbuf_AddText ("\n");
- Cbuf_Execute();
-}
-
-
-//======================================================================
-
-/*
-=====================
-CL_ShutdownAll
-=====================
-*/
-void CL_ShutdownAll(void) {
-
-#ifdef USE_CURL
- CL_cURL_Shutdown();
-#endif
- // clear sounds
- S_DisableSounds();
- // shutdown CGame
- CL_ShutdownCGame();
- // shutdown UI
- CL_ShutdownUI();
-
- // shutdown the renderer
- if ( re.Shutdown ) {
- re.Shutdown( qfalse ); // don't destroy window or context
- }
-
- cls.uiStarted = qfalse;
- cls.cgameStarted = qfalse;
- cls.rendererStarted = qfalse;
- cls.soundRegistered = qfalse;
-}
-
-/*
-=================
-CL_FlushMemory
-
-Called by CL_MapLoading, CL_Connect_f, CL_PlayDemo_f, and CL_ParseGamestate the only
-ways a client gets into a game
-Also called by Com_Error
-=================
-*/
-void CL_FlushMemory( void ) {
-
- // shutdown all the client stuff
- CL_ShutdownAll();
-
- // if not running a server clear the whole hunk
- if ( !com_sv_running->integer ) {
- // clear the whole hunk
- Hunk_Clear();
- // clear collision map data
- CM_ClearMap();
- }
- else {
- // clear all the client data on the hunk
- Hunk_ClearToMark();
- }
-
- CL_StartHunkUsers( qfalse );
-}
-
-/*
-=====================
-CL_MapLoading
-
-A local server is starting to load a map, so update the
-screen to let the user know about it, then dump all client
-memory on the hunk from cgame, ui, and renderer
-=====================
-*/
-void CL_MapLoading( void ) {
- if ( com_dedicated->integer ) {
- cls.state = CA_DISCONNECTED;
- Key_SetCatcher( KEYCATCH_CONSOLE );
- return;
- }
-
- if ( !com_cl_running->integer ) {
- return;
- }
-
- Con_Close();
- Key_SetCatcher( 0 );
-
- // if we are already connected to the local host, stay connected
- if ( cls.state >= CA_CONNECTED && !Q_stricmp( cls.servername, "localhost" ) ) {
- cls.state = CA_CONNECTED; // so the connect screen is drawn
- Com_Memset( cls.updateInfoString, 0, sizeof( cls.updateInfoString ) );
- Com_Memset( clc.serverMessage, 0, sizeof( clc.serverMessage ) );
- Com_Memset( &cl.gameState, 0, sizeof( cl.gameState ) );
- clc.lastPacketSentTime = -9999;
- SCR_UpdateScreen();
- } else {
- // clear nextmap so the cinematic shutdown doesn't execute it
- Cvar_Set( "nextmap", "" );
- CL_Disconnect( qtrue );
- Q_strncpyz( cls.servername, "localhost", sizeof(cls.servername) );
- cls.state = CA_CHALLENGING; // so the connect screen is drawn
- Key_SetCatcher( 0 );
- SCR_UpdateScreen();
- clc.connectTime = -RETRANSMIT_TIMEOUT;
- NET_StringToAdr( cls.servername, &clc.serverAddress, NA_UNSPEC);
- // we don't need a challenge on the localhost
-
- CL_CheckForResend();
- }
-}
-
-/*
-=====================
-CL_ClearState
-
-Called before parsing a gamestate
-=====================
-*/
-void CL_ClearState (void) {
-
-// S_StopAllSounds();
-
- Com_Memset( &cl, 0, sizeof( cl ) );
-}
-
-/*
-====================
-CL_UpdateGUID
-
-update cl_guid using QKEY_FILE and optional prefix
-====================
-*/
-static void CL_UpdateGUID( const char *prefix, int prefix_len )
-{
- fileHandle_t f;
- int len;
-
- len = FS_SV_FOpenFileRead( QKEY_FILE, &f );
- FS_FCloseFile( f );
-
- if( len != QKEY_SIZE )
- Cvar_Set( "cl_guid", "" );
- else
- Cvar_Set( "cl_guid", Com_MD5File( QKEY_FILE, QKEY_SIZE,
- prefix, prefix_len ) );
-}
-
-
-/*
-=====================
-CL_Disconnect
-
-Called when a connection, demo, or cinematic is being terminated.
-Goes from a connected state to either a menu state or a console state
-Sends a disconnect message to the server
-This is also called on Com_Error and Com_Quit, so it shouldn't cause any errors
-=====================
-*/
-void CL_Disconnect( qboolean showMainMenu ) {
- if ( !com_cl_running || !com_cl_running->integer ) {
- return;
- }
-
- // shutting down the client so enter full screen ui mode
- Cvar_Set("r_uiFullScreen", "1");
-
- if ( clc.demorecording ) {
- CL_StopRecord_f ();
- }
-
- if (clc.download) {
- FS_FCloseFile( clc.download );
- clc.download = 0;
- }
- *clc.downloadTempName = *clc.downloadName = 0;
- Cvar_Set( "cl_downloadName", "" );
-
-#ifdef USE_MUMBLE
- if (cl_useMumble->integer && mumble_islinked()) {
- Com_Printf("Mumble: Unlinking from Mumble application\n");
- mumble_unlink();
- }
-#endif
-
-#ifdef USE_VOIP
- if (cl_voipSend->integer) {
- int tmp = cl_voipUseVAD->integer;
- cl_voipUseVAD->integer = 0; // disable this for a moment.
- clc.voipOutgoingDataSize = 0; // dump any pending VoIP transmission.
- Cvar_Set("cl_voipSend", "0");
- CL_CaptureVoip(); // clean up any state...
- cl_voipUseVAD->integer = tmp;
- }
-
- if (clc.speexInitialized) {
- int i;
- speex_bits_destroy(&clc.speexEncoderBits);
- speex_encoder_destroy(clc.speexEncoder);
- speex_preprocess_state_destroy(clc.speexPreprocessor);
- for (i = 0; i < MAX_CLIENTS; i++) {
- speex_bits_destroy(&clc.speexDecoderBits[i]);
- speex_decoder_destroy(clc.speexDecoder[i]);
- }
- }
- Cmd_RemoveCommand ("voip");
-#endif
-
- if ( clc.demofile ) {
- FS_FCloseFile( clc.demofile );
- clc.demofile = 0;
- }
-
- if ( uivm && showMainMenu ) {
- VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_NONE );
- }
-
- SCR_StopCinematic ();
- S_ClearSoundBuffer();
-
- // send a disconnect message to the server
- // send it a few times in case one is dropped
- if ( cls.state >= CA_CONNECTED ) {
- CL_AddReliableCommand("disconnect", qtrue);
- CL_WritePacket();
- CL_WritePacket();
- CL_WritePacket();
- }
-
- // Remove pure paks
- FS_PureServerSetLoadedPaks("", "");
-
- CL_ClearState ();
-
- // wipe the client connection
- Com_Memset( &clc, 0, sizeof( clc ) );
-
- cls.state = CA_DISCONNECTED;
-
- // allow cheats locally
- Cvar_Set( "sv_cheats", "1" );
-
- // not connected to a pure server anymore
- cl_connectedToPureServer = qfalse;
-
-#ifdef USE_VOIP
- // not connected to voip server anymore.
- cl_connectedToVoipServer = qfalse;
-#endif
-
- // Stop recording any video
- if( CL_VideoRecording( ) ) {
- // Finish rendering current frame
- SCR_UpdateScreen( );
- CL_CloseAVI( );
- }
- CL_UpdateGUID( NULL, 0 );
-}
-
-
-/*
-===================
-CL_ForwardCommandToServer
-
-adds the current command line as a clientCommand
-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 CL_ForwardCommandToServer( const char *string ) {
- char *cmd;
-
- cmd = Cmd_Argv(0);
-
- // ignore key up commands
- if ( cmd[0] == '-' ) {
- return;
- }
-
- if ( clc.demoplaying || cls.state < CA_CONNECTED || cmd[0] == '+' ) {
- Com_Printf ("Unknown command \"%s" S_COLOR_WHITE "\"\n", cmd);
- return;
- }
-
- if ( Cmd_Argc() > 1 ) {
- CL_AddReliableCommand(string, qfalse);
- } else {
- CL_AddReliableCommand(cmd, qfalse);
- }
-}
-
-/*
-===================
-CL_RequestMotd
-
-===================
-*/
-void CL_RequestMotd( void ) {
- char info[MAX_INFO_STRING];
-
- if ( !cl_motd->integer ) {
- return;
- }
- Com_Printf( "Resolving %s\n", UPDATE_SERVER_NAME );
- if ( !NET_StringToAdr( UPDATE_SERVER_NAME, &cls.updateServer, NA_IP ) ) {
- Com_Printf( "Couldn't resolve address\n" );
- return;
- }
- cls.updateServer.port = BigShort( PORT_UPDATE );
- Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", UPDATE_SERVER_NAME,
- cls.updateServer.ip[0], cls.updateServer.ip[1],
- cls.updateServer.ip[2], cls.updateServer.ip[3],
- BigShort( cls.updateServer.port ) );
-
- info[0] = 0;
-
- Com_sprintf( cls.updateChallenge, sizeof( cls.updateChallenge ), "%i", ((rand() << 16) ^ rand()) ^ Com_Milliseconds());
-
- Info_SetValueForKey( info, "challenge", cls.updateChallenge );
- Info_SetValueForKey( info, "renderer", cls.glconfig.renderer_string );
- Info_SetValueForKey( info, "version", com_version->string );
-
- NET_OutOfBandPrint( NS_CLIENT, cls.updateServer, "getmotd \"%s\"\n", info );
-}
-
-/*
-===================
-CL_RequestAuthorization
-
-Authorization server protocol
------------------------------
-
-All commands are text in Q3 out of band packets (leading 0xff 0xff 0xff 0xff).
-
-Whenever the client tries to get a challenge from the server it wants to
-connect to, it also blindly fires off a packet to the authorize server:
-
-getKeyAuthorize <challenge> <cdkey>
-
-cdkey may be "demo"
-
-
-#OLD The authorize server returns a:
-#OLD
-#OLD keyAthorize <challenge> <accept | deny>
-#OLD
-#OLD A client will be accepted if the cdkey is valid and it has not been used by any other IP
-#OLD address in the last 15 minutes.
-
-
-The server sends a:
-
-getIpAuthorize <challenge> <ip>
-
-The authorize server returns a:
-
-ipAuthorize <challenge> <accept | deny | demo | unknown >
-
-A client will be accepted if a valid cdkey was sent by that ip (only) in the last 15 minutes.
-If no response is received from the authorize server after two tries, the client will be let
-in anyway.
-===================
-*/
-#ifndef STANDALONE
-void CL_RequestAuthorization( void ) {
- char nums[64];
- int i, j, l;
- cvar_t *fs;
-
- if ( !cls.authorizeServer.port ) {
- Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
- if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &cls.authorizeServer, NA_IP ) ) {
- Com_Printf( "Couldn't resolve address\n" );
- return;
- }
-
- cls.authorizeServer.port = BigShort( PORT_AUTHORIZE );
- Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
- cls.authorizeServer.ip[0], cls.authorizeServer.ip[1],
- cls.authorizeServer.ip[2], cls.authorizeServer.ip[3],
- BigShort( cls.authorizeServer.port ) );
- }
- if ( cls.authorizeServer.type == NA_BAD ) {
- return;
- }
-
- // only grab the alphanumeric values from the cdkey, to avoid any dashes or spaces
- j = 0;
- l = strlen( cl_cdkey );
- if ( l > 32 ) {
- l = 32;
- }
- for ( i = 0 ; i < l ; i++ ) {
- if ( ( cl_cdkey[i] >= '0' && cl_cdkey[i] <= '9' )
- || ( cl_cdkey[i] >= 'a' && cl_cdkey[i] <= 'z' )
- || ( cl_cdkey[i] >= 'A' && cl_cdkey[i] <= 'Z' )
- ) {
- nums[j] = cl_cdkey[i];
- j++;
- }
- }
- nums[j] = 0;
-
- fs = Cvar_Get ("cl_anonymous", "0", CVAR_INIT|CVAR_SYSTEMINFO );
-
- NET_OutOfBandPrint(NS_CLIENT, cls.authorizeServer, "getKeyAuthorize %i %s", fs->integer, nums );
-}
-#endif
-/*
-======================================================================
-
-CONSOLE COMMANDS
-
-======================================================================
-*/
-
-/*
-==================
-CL_ForwardToServer_f
-==================
-*/
-void CL_ForwardToServer_f( void ) {
- if ( cls.state != CA_ACTIVE || clc.demoplaying ) {
- Com_Printf ("Not connected to a server.\n");
- return;
- }
-
- // don't forward the first argument
- if ( Cmd_Argc() > 1 ) {
- CL_AddReliableCommand(Cmd_Args(), qfalse);
- }
-}
-
-/*
-==================
-CL_Disconnect_f
-==================
-*/
-void CL_Disconnect_f( void ) {
- SCR_StopCinematic();
- Cvar_Set("ui_singlePlayerActive", "0");
- if ( cls.state != CA_DISCONNECTED && cls.state != CA_CINEMATIC ) {
- Com_Error (ERR_DISCONNECT, "Disconnected from server");
- }
-}
-
-
-/*
-================
-CL_Reconnect_f
-
-================
-*/
-void CL_Reconnect_f( void ) {
- if ( !strlen( cls.servername ) || !strcmp( cls.servername, "localhost" ) ) {
- Com_Printf( "Can't reconnect to localhost.\n" );
- return;
- }
- Cvar_Set("ui_singlePlayerActive", "0");
- Cbuf_AddText( va("connect %s\n", cls.servername ) );
-}
-
-/*
-================
-CL_Connect_f
-
-================
-*/
-void CL_Connect_f( void ) {
- char *server;
- const char *serverString;
- int argc = Cmd_Argc();
- netadrtype_t family = NA_UNSPEC;
-
- if ( argc != 2 && argc != 3 ) {
- Com_Printf( "usage: connect [-4|-6] server\n");
- return;
- }
-
- if(argc == 2)
- server = Cmd_Argv(1);
- else
- {
- if(!strcmp(Cmd_Argv(1), "-4"))
- family = NA_IP;
- else if(!strcmp(Cmd_Argv(1), "-6"))
- family = NA_IP6;
- else
- Com_Printf( "warning: only -4 or -6 as address type understood.\n");
-
- server = Cmd_Argv(2);
- }
-
- Cvar_Set("ui_singlePlayerActive", "0");
-
- // fire a message off to the motd server
- CL_RequestMotd();
-
- // clear any previous "server full" type messages
- clc.serverMessage[0] = 0;
-
- if ( com_sv_running->integer && !strcmp( server, "localhost" ) ) {
- // if running a local server, kill it
- SV_Shutdown( "Server quit" );
- }
-
- // make sure a local server is killed
- Cvar_Set( "sv_killserver", "1" );
- SV_Frame( 0 );
-
- CL_Disconnect( qtrue );
- Con_Close();
-
- Q_strncpyz( cls.servername, server, sizeof(cls.servername) );
-
- if (!NET_StringToAdr(cls.servername, &clc.serverAddress, family) ) {
- Com_Printf ("Bad server address\n");
- cls.state = CA_DISCONNECTED;
- return;
- }
- if (clc.serverAddress.port == 0) {
- clc.serverAddress.port = BigShort( PORT_SERVER );
- }
-
- serverString = NET_AdrToStringwPort(clc.serverAddress);
-
- Com_Printf( "%s resolved to %s\n", cls.servername, serverString);
-
- if( cl_guidServerUniq->integer )
- CL_UpdateGUID( serverString, strlen( serverString ) );
- else
- CL_UpdateGUID( NULL, 0 );
-
- // if we aren't playing on a lan, we need to authenticate
- // with the cd key
- if(NET_IsLocalAddress(clc.serverAddress))
- cls.state = CA_CHALLENGING;
- else
- {
- cls.state = CA_CONNECTING;
-
- // Set a client challenge number that ideally is mirrored back by the server.
- clc.challenge = ((rand() << 16) ^ rand()) ^ Com_Milliseconds();
- }
-
- Key_SetCatcher( 0 );
- clc.connectTime = -99999; // CL_CheckForResend() will fire immediately
- clc.connectPacketCount = 0;
-
- // server connection string
- Cvar_Set( "cl_currentServerAddress", server );
-}
-
-#define MAX_RCON_MESSAGE 1024
-
-/*
-==================
-CL_CompleteRcon
-==================
-*/
-static void CL_CompleteRcon( char *args, int argNum )
-{
- if( argNum == 2 )
- {
- // Skip "rcon "
- char *p = Com_SkipTokens( args, 1, " " );
-
- if( p > args )
- Field_CompleteCommand( p, qtrue, qtrue );
- }
-}
-
-/*
-=====================
-CL_Rcon_f
-
- Send the rest of the command line over as
- an unconnected command.
-=====================
-*/
-void CL_Rcon_f( void ) {
- char message[MAX_RCON_MESSAGE];
- netadr_t to;
-
- if ( !rcon_client_password->string ) {
- Com_Printf ("You must set 'rconpassword' before\n"
- "issuing an rcon command.\n");
- return;
- }
-
- message[0] = -1;
- message[1] = -1;
- message[2] = -1;
- message[3] = -1;
- message[4] = 0;
-
- Q_strcat (message, MAX_RCON_MESSAGE, "rcon ");
-
- Q_strcat (message, MAX_RCON_MESSAGE, rcon_client_password->string);
- Q_strcat (message, MAX_RCON_MESSAGE, " ");
-
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543
- Q_strcat (message, MAX_RCON_MESSAGE, Cmd_Cmd()+5);
-
- if ( cls.state >= CA_CONNECTED ) {
- to = clc.netchan.remoteAddress;
- } else {
- if (!strlen(rconAddress->string)) {
- Com_Printf ("You must either be connected,\n"
- "or set the 'rconAddress' cvar\n"
- "to issue rcon commands\n");
-
- return;
- }
- NET_StringToAdr (rconAddress->string, &to, NA_UNSPEC);
- if (to.port == 0) {
- to.port = BigShort (PORT_SERVER);
- }
- }
-
- NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
-}
-
-/*
-=================
-CL_SendPureChecksums
-=================
-*/
-void CL_SendPureChecksums( void ) {
- char cMsg[MAX_INFO_VALUE];
-
- // if we are pure we need to send back a command with our referenced pk3 checksums
- Com_sprintf(cMsg, sizeof(cMsg), "cp %d %s", cl.serverId, FS_ReferencedPakPureChecksums());
-
- CL_AddReliableCommand(cMsg, qfalse);
-}
-
-/*
-=================
-CL_ResetPureClientAtServer
-=================
-*/
-void CL_ResetPureClientAtServer( void ) {
- CL_AddReliableCommand("vdr", qfalse);
-}
-
-/*
-=================
-CL_Vid_Restart_f
-
-Restart the video subsystem
-
-we also have to reload the UI and CGame because the renderer
-doesn't know what graphics to reload
-=================
-*/
-void CL_Vid_Restart_f( void ) {
-
- // Settings may have changed so stop recording now
- if( CL_VideoRecording( ) ) {
- CL_CloseAVI( );
- }
-
- if(clc.demorecording)
- CL_StopRecord_f();
-
- // don't let them loop during the restart
- S_StopAllSounds();
- // shutdown the UI
- CL_ShutdownUI();
- // shutdown the CGame
- CL_ShutdownCGame();
- // shutdown the renderer and clear the renderer interface
- CL_ShutdownRef();
- // client is no longer pure untill new checksums are sent
- CL_ResetPureClientAtServer();
- // clear pak references
- FS_ClearPakReferences( FS_UI_REF | FS_CGAME_REF );
- // reinitialize the filesystem if the game directory or checksum has changed
- FS_ConditionalRestart( clc.checksumFeed );
-
- cls.rendererStarted = qfalse;
- cls.uiStarted = qfalse;
- cls.cgameStarted = qfalse;
- cls.soundRegistered = qfalse;
-
- // unpause so the cgame definately gets a snapshot and renders a frame
- Cvar_Set( "cl_paused", "0" );
-
- // if not running a server clear the whole hunk
- if ( !com_sv_running->integer ) {
- // clear the whole hunk
- Hunk_Clear();
- }
- else {
- // clear all the client data on the hunk
- Hunk_ClearToMark();
- }
-
- // initialize the renderer interface
- CL_InitRef();
-
- // startup all the client stuff
- CL_StartHunkUsers( qfalse );
-
- // start the cgame if connected
- if ( cls.state > CA_CONNECTED && cls.state != CA_CINEMATIC ) {
- cls.cgameStarted = qtrue;
- CL_InitCGame();
- // send pure checksums
- CL_SendPureChecksums();
- }
-}
-
-/*
-=================
-CL_Snd_Restart
-
-Restart the sound subsystem
-=================
-*/
-void CL_Snd_Restart(void)
-{
- S_Shutdown();
- S_Init();
-}
-
-/*
-=================
-CL_Snd_Restart_f
-
-Restart the sound subsystem
-The cgame and game must also be forced to restart because
-handles will be invalid
-=================
-*/
-void CL_Snd_Restart_f(void)
-{
- CL_Snd_Restart();
- CL_Vid_Restart_f();
-}
-
-
-/*
-==================
-CL_PK3List_f
-==================
-*/
-void CL_OpenedPK3List_f( void ) {
- Com_Printf("Opened PK3 Names: %s\n", FS_LoadedPakNames());
-}
-
-/*
-==================
-CL_PureList_f
-==================
-*/
-void CL_ReferencedPK3List_f( void ) {
- Com_Printf("Referenced PK3 Names: %s\n", FS_ReferencedPakNames());
-}
-
-/*
-==================
-CL_Configstrings_f
-==================
-*/
-void CL_Configstrings_f( void ) {
- int i;
- int ofs;
-
- if ( cls.state != CA_ACTIVE ) {
- Com_Printf( "Not connected to a server.\n");
- return;
- }
-
- for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
- ofs = cl.gameState.stringOffsets[ i ];
- if ( !ofs ) {
- continue;
- }
- Com_Printf( "%4i: %s\n", i, cl.gameState.stringData + ofs );
- }
-}
-
-/*
-==============
-CL_Clientinfo_f
-==============
-*/
-void CL_Clientinfo_f( void ) {
- Com_Printf( "--------- Client Information ---------\n" );
- Com_Printf( "state: %i\n", cls.state );
- Com_Printf( "Server: %s\n", cls.servername );
- Com_Printf ("User info settings:\n");
- Info_Print( Cvar_InfoString( CVAR_USERINFO ) );
- Com_Printf( "--------------------------------------\n" );
-}
-
-
-//====================================================================
-
-/*
-=================
-CL_DownloadsComplete
-
-Called when all downloading has been completed
-=================
-*/
-void CL_DownloadsComplete( void ) {
-
-#ifdef USE_CURL
- // if we downloaded with cURL
- if(clc.cURLUsed) {
- clc.cURLUsed = qfalse;
- CL_cURL_Shutdown();
- if( clc.cURLDisconnected ) {
- if(clc.downloadRestart) {
- FS_Restart(clc.checksumFeed);
- clc.downloadRestart = qfalse;
- }
- clc.cURLDisconnected = qfalse;
- CL_Reconnect_f();
- return;
- }
- }
-#endif
-
- // if we downloaded files we need to restart the file system
- if (clc.downloadRestart) {
- clc.downloadRestart = qfalse;
-
- FS_Restart(clc.checksumFeed); // We possibly downloaded a pak, restart the file system to load it
-
- // inform the server so we get new gamestate info
- CL_AddReliableCommand("donedl", qfalse);
-
- // by sending the donedl command we request a new gamestate
- // so we don't want to load stuff yet
- return;
- }
-
- // let the client game init and load data
- cls.state = CA_LOADING;
-
- // Pump the loop, this may change gamestate!
- Com_EventLoop();
-
- // if the gamestate was changed by calling Com_EventLoop
- // then we loaded everything already and we don't want to do it again.
- if ( cls.state != CA_LOADING ) {
- return;
- }
-
- // starting to load a map so we get out of full screen ui mode
- Cvar_Set("r_uiFullScreen", "0");
-
- // flush client memory and start loading stuff
- // this will also (re)load the UI
- // if this is a local client then only the client part of the hunk
- // will be cleared, note that this is done after the hunk mark has been set
- CL_FlushMemory();
-
- // initialize the CGame
- cls.cgameStarted = qtrue;
- CL_InitCGame();
-
- // set pure checksums
- CL_SendPureChecksums();
-
- CL_WritePacket();
- CL_WritePacket();
- CL_WritePacket();
-}
-
-/*
-=================
-CL_BeginDownload
-
-Requests a file to download from the server. Stores it in the current
-game directory.
-=================
-*/
-void CL_BeginDownload( const char *localName, const char *remoteName ) {
-
- Com_DPrintf("***** CL_BeginDownload *****\n"
- "Localname: %s\n"
- "Remotename: %s\n"
- "****************************\n", localName, remoteName);
-
- Q_strncpyz ( clc.downloadName, localName, sizeof(clc.downloadName) );
- Com_sprintf( clc.downloadTempName, sizeof(clc.downloadTempName), "%s.tmp", localName );
-
- // Set so UI gets access to it
- Cvar_Set( "cl_downloadName", remoteName );
- Cvar_Set( "cl_downloadSize", "0" );
- Cvar_Set( "cl_downloadCount", "0" );
- Cvar_SetValue( "cl_downloadTime", cls.realtime );
-
- clc.downloadBlock = 0; // Starting new file
- clc.downloadCount = 0;
-
- CL_AddReliableCommand(va("download %s", remoteName), qfalse);
-}
-
-/*
-=================
-CL_NextDownload
-
-A download completed or failed
-=================
-*/
-void CL_NextDownload(void)
-{
- char *s;
- char *remoteName, *localName;
- qboolean useCURL = qfalse;
-
- // A download has finished, check whether this matches a referenced checksum
- if(*clc.downloadName)
- {
- char *zippath = FS_BuildOSPath(Cvar_VariableString("fs_homepath"), clc.downloadName, "");
- zippath[strlen(zippath)-1] = '\0';
-
- if(!FS_CompareZipChecksum(zippath))
- Com_Error(ERR_DROP, "Incorrect checksum for file: %s", clc.downloadName);
- }
-
- *clc.downloadTempName = *clc.downloadName = 0;
- Cvar_Set("cl_downloadName", "");
-
- // We are looking to start a download here
- if (*clc.downloadList) {
- s = clc.downloadList;
-
- // format is:
- // @remotename at localname@remotename at localname, etc.
-
- if (*s == '@')
- s++;
- remoteName = s;
-
- if ( (s = strchr(s, '@')) == NULL ) {
- CL_DownloadsComplete();
- return;
- }
-
- *s++ = 0;
- localName = s;
- if ( (s = strchr(s, '@')) != NULL )
- *s++ = 0;
- else
- s = localName + strlen(localName); // point at the nul byte
-#ifdef USE_CURL
- if(!(cl_allowDownload->integer & DLF_NO_REDIRECT)) {
- if(clc.sv_allowDownload & DLF_NO_REDIRECT) {
- Com_Printf("WARNING: server does not "
- "allow download redirection "
- "(sv_allowDownload is %d)\n",
- clc.sv_allowDownload);
- }
- else if(!*clc.sv_dlURL) {
- Com_Printf("WARNING: server allows "
- "download redirection, but does not "
- "have sv_dlURL set\n");
- }
- else if(!CL_cURL_Init()) {
- Com_Printf("WARNING: could not load "
- "cURL library\n");
- }
- else {
- CL_cURL_BeginDownload(localName, va("%s/%s",
- clc.sv_dlURL, remoteName));
- useCURL = qtrue;
- }
- }
- else if(!(clc.sv_allowDownload & DLF_NO_REDIRECT)) {
- Com_Printf("WARNING: server allows download "
- "redirection, but it disabled by client "
- "configuration (cl_allowDownload is %d)\n",
- cl_allowDownload->integer);
- }
-#endif /* USE_CURL */
- if(!useCURL) {
- if((cl_allowDownload->integer & DLF_NO_UDP)) {
- Com_Error(ERR_DROP, "UDP Downloads are "
- "disabled on your client. "
- "(cl_allowDownload is %d)",
- cl_allowDownload->integer);
- return;
- }
- else {
- CL_BeginDownload( localName, remoteName );
- }
- }
- clc.downloadRestart = qtrue;
-
- // move over the rest
- memmove( clc.downloadList, s, strlen(s) + 1);
-
- return;
- }
-
- CL_DownloadsComplete();
-}
-
-/*
-=================
-CL_InitDownloads
-
-After receiving a valid game state, we valid the cgame and local zip files here
-and determine if we need to download them
-=================
-*/
-void CL_InitDownloads(void) {
- char missingfiles[1024];
-
- if ( !(cl_allowDownload->integer & DLF_ENABLE) )
- {
- // autodownload is disabled on the client
- // but it's possible that some referenced files on the server are missing
- if (FS_ComparePaks( missingfiles, sizeof( missingfiles ), qfalse ) )
- {
- // NOTE TTimo I would rather have that printed as a modal message box
- // but at this point while joining the game we don't know wether we will successfully join or not
- Com_Printf( "\nWARNING: You are missing some files referenced by the server:\n%s"
- "You might not be able to join the game\n"
- "Go to the setting menu to turn on autodownload, or get the file elsewhere\n\n", missingfiles );
- }
- }
- else if ( FS_ComparePaks( clc.downloadList, sizeof( clc.downloadList ) , qtrue ) ) {
-
- Com_Printf("Need paks: %s\n", clc.downloadList );
-
- if ( *clc.downloadList ) {
- // if autodownloading is not enabled on the server
- cls.state = CA_CONNECTED;
-
- *clc.downloadTempName = *clc.downloadName = 0;
- Cvar_Set( "cl_downloadName", "" );
-
- CL_NextDownload();
- return;
- }
-
- }
-
- CL_DownloadsComplete();
-}
-
-/*
-=================
-CL_CheckForResend
-
-Resend a connect message if the last one has timed out
-=================
-*/
-void CL_CheckForResend( void ) {
- int port, i;
- char info[MAX_INFO_STRING];
- char data[MAX_INFO_STRING];
-
- // don't send anything if playing back a demo
- if ( clc.demoplaying ) {
- return;
- }
-
- // resend if we haven't gotten a reply yet
- if ( cls.state != CA_CONNECTING && cls.state != CA_CHALLENGING ) {
- return;
- }
-
- if ( cls.realtime - clc.connectTime < RETRANSMIT_TIMEOUT ) {
- return;
- }
-
- clc.connectTime = cls.realtime; // for retransmit requests
- clc.connectPacketCount++;
-
-
- switch ( cls.state ) {
- case CA_CONNECTING:
- // requesting a challenge .. IPv6 users always get in as authorize server supports no ipv6.
-#ifndef STANDALONE
- if (!Cvar_VariableIntegerValue("com_standalone") && clc.serverAddress.type == NA_IP && !Sys_IsLANAddress( clc.serverAddress ) )
- CL_RequestAuthorization();
-#endif
-
- // The challenge request shall be followed by a client challenge so no malicious server can hijack this connection.
- Com_sprintf(data, sizeof(data), "getchallenge %d", clc.challenge);
-
- NET_OutOfBandPrint(NS_CLIENT, clc.serverAddress, "%s", data);
- break;
-
- case CA_CHALLENGING:
- // sending back the challenge
- port = Cvar_VariableValue ("net_qport");
-
- Q_strncpyz( info, Cvar_InfoString( CVAR_USERINFO ), sizeof( info ) );
- Info_SetValueForKey( info, "protocol", va("%i", PROTOCOL_VERSION ) );
- Info_SetValueForKey( info, "qport", va("%i", port ) );
- Info_SetValueForKey( info, "challenge", va("%i", clc.challenge ) );
-
- strcpy(data, "connect ");
- // TTimo adding " " around the userinfo string to avoid truncated userinfo on the server
- // (Com_TokenizeString tokenizes around spaces)
- data[8] = '"';
-
- for(i=0;i<strlen(info);i++) {
- data[9+i] = info[i]; // + (clc.challenge)&0x3;
- }
- data[9+i] = '"';
- data[10+i] = 0;
-
- // NOTE TTimo don't forget to set the right data length!
- NET_OutOfBandData( NS_CLIENT, clc.serverAddress, (byte *) &data[0], i+10 );
- // the most current userinfo has been sent, so watch for any
- // newer changes to userinfo variables
- cvar_modifiedFlags &= ~CVAR_USERINFO;
- break;
-
- default:
- Com_Error( ERR_FATAL, "CL_CheckForResend: bad cls.state" );
- }
-}
-
-/*
-===================
-CL_DisconnectPacket
-
-Sometimes the server can drop the client and the netchan based
-disconnect can be lost. If the client continues to send packets
-to the server, the server will send out of band disconnect packets
-to the client so it doesn't have to wait for the full timeout period.
-===================
-*/
-void CL_DisconnectPacket( netadr_t from ) {
- if ( cls.state < CA_AUTHORIZING ) {
- return;
- }
-
- // if not from our server, ignore it
- if ( !NET_CompareAdr( from, clc.netchan.remoteAddress ) ) {
- return;
- }
-
- // if we have received packets within three seconds, ignore it
- // (it might be a malicious spoof)
- if ( cls.realtime - clc.lastPacketTime < 3000 ) {
- return;
- }
-
- // drop the connection
- Com_Printf( "Server disconnected for unknown reason\n" );
- Cvar_Set("com_errorMessage", "Server disconnected for unknown reason\n" );
- CL_Disconnect( qtrue );
-}
-
-
-/*
-===================
-CL_MotdPacket
-
-===================
-*/
-void CL_MotdPacket( netadr_t from ) {
- char *challenge;
- char *info;
-
- // if not from our server, ignore it
- if ( !NET_CompareAdr( from, cls.updateServer ) ) {
- return;
- }
-
- info = Cmd_Argv(1);
-
- // check challenge
- challenge = Info_ValueForKey( info, "challenge" );
- if ( strcmp( challenge, cls.updateChallenge ) ) {
- return;
- }
-
- challenge = Info_ValueForKey( info, "motd" );
-
- Q_strncpyz( cls.updateInfoString, info, sizeof( cls.updateInfoString ) );
- Cvar_Set( "cl_motdString", challenge );
-}
-
-/*
-===================
-CL_InitServerInfo
-===================
-*/
-void CL_InitServerInfo( serverInfo_t *server, netadr_t *address ) {
- server->adr = *address;
- server->clients = 0;
- server->hostName[0] = '\0';
- server->mapName[0] = '\0';
- server->maxClients = 0;
- server->maxPing = 0;
- server->minPing = 0;
- server->ping = -1;
- server->game[0] = '\0';
- server->gameType = 0;
- server->netType = 0;
-}
-
-#define MAX_SERVERSPERPACKET 256
-
-/*
-===================
-CL_ServersResponsePacket
-===================
-*/
-void CL_ServersResponsePacket( const netadr_t* from, msg_t *msg, qboolean extended ) {
- int i, count, total;
- netadr_t addresses[MAX_SERVERSPERPACKET];
- int numservers;
- byte* buffptr;
- byte* buffend;
-
- Com_Printf("CL_ServersResponsePacket\n");
-
- if (cls.numglobalservers == -1) {
- // state to detect lack of servers or lack of response
- cls.numglobalservers = 0;
- cls.numGlobalServerAddresses = 0;
- }
-
- // parse through server response string
- numservers = 0;
- buffptr = msg->data;
- buffend = buffptr + msg->cursize;
-
- // advance to initial token
- do
- {
- if(*buffptr == '\\' || (extended && *buffptr == '/'))
- break;
-
- buffptr++;
- } while (buffptr < buffend);
-
- while (buffptr + 1 < buffend)
- {
- // IPv4 address
- if (*buffptr == '\\')
- {
- buffptr++;
-
- if (buffend - buffptr < sizeof(addresses[numservers].ip) + sizeof(addresses[numservers].port) + 1)
- break;
-
- for(i = 0; i < sizeof(addresses[numservers].ip); i++)
- addresses[numservers].ip[i] = *buffptr++;
-
- addresses[numservers].type = NA_IP;
- }
- // IPv6 address, if it's an extended response
- else if (extended && *buffptr == '/')
- {
- buffptr++;
-
- if (buffend - buffptr < sizeof(addresses[numservers].ip6) + sizeof(addresses[numservers].port) + 1)
- break;
-
- for(i = 0; i < sizeof(addresses[numservers].ip6); i++)
- addresses[numservers].ip6[i] = *buffptr++;
-
- addresses[numservers].type = NA_IP6;
- addresses[numservers].scope_id = from->scope_id;
- }
- else
- // syntax error!
- break;
-
- // parse out port
- addresses[numservers].port = (*buffptr++) << 8;
- addresses[numservers].port += *buffptr++;
- addresses[numservers].port = BigShort( addresses[numservers].port );
-
- // syntax check
- if (*buffptr != '\\' && *buffptr != '/')
- break;
-
- numservers++;
- if (numservers >= MAX_SERVERSPERPACKET)
- break;
- }
-
- count = cls.numglobalservers;
-
- for (i = 0; i < numservers && count < MAX_GLOBAL_SERVERS; i++) {
- // build net address
- serverInfo_t *server = &cls.globalServers[count];
-
- CL_InitServerInfo( server, &addresses[i] );
- // advance to next slot
- count++;
- }
-
- // if getting the global list
- if ( count >= MAX_GLOBAL_SERVERS && cls.numGlobalServerAddresses < MAX_GLOBAL_SERVERS )
- {
- // if we couldn't store the servers in the main list anymore
- for (; i < numservers && cls.numGlobalServerAddresses < MAX_GLOBAL_SERVERS; i++)
- {
- // just store the addresses in an additional list
- cls.globalServerAddresses[cls.numGlobalServerAddresses++] = addresses[i];
- }
- }
-
- cls.numglobalservers = count;
- total = count + cls.numGlobalServerAddresses;
-
- Com_Printf("%d servers parsed (total %d)\n", numservers, total);
-}
-
-/*
-=================
-CL_ConnectionlessPacket
-
-Responses to broadcasts, etc
-=================
-*/
-void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
- char *s;
- char *c;
-
- MSG_BeginReadingOOB( msg );
- MSG_ReadLong( msg ); // skip the -1
-
- s = MSG_ReadStringLine( msg );
-
- Cmd_TokenizeString( s );
-
- c = Cmd_Argv(0);
-
- Com_DPrintf ("CL packet %s: %s\n", NET_AdrToStringwPort(from), c);
-
- // challenge from the server we are connecting to
- if (!Q_stricmp(c, "challengeResponse"))
- {
- if (cls.state != CA_CONNECTING)
- {
- Com_DPrintf("Unwanted challenge response received. Ignored.\n");
- return;
- }
-
- if(!NET_CompareAdr(from, clc.serverAddress))
- {
- // This challenge response is not coming from the expected address.
- // Check whether we have a matching client challenge to prevent
- // connection hi-jacking.
-
- c = Cmd_Argv(2);
-
- if(!*c || atoi(c) != clc.challenge)
- {
- Com_DPrintf("Challenge response received from unexpected source. Ignored.\n");
- return;
- }
- }
-
- // start sending challenge response instead of challenge request packets
- clc.challenge = atoi(Cmd_Argv(1));
- cls.state = CA_CHALLENGING;
- clc.connectPacketCount = 0;
- clc.connectTime = -99999;
-
- // take this address as the new server address. This allows
- // a server proxy to hand off connections to multiple servers
- clc.serverAddress = from;
- Com_DPrintf ("challengeResponse: %d\n", clc.challenge);
- return;
- }
-
- // server connection
- if ( !Q_stricmp(c, "connectResponse") ) {
- if ( cls.state >= CA_CONNECTED ) {
- Com_Printf ("Dup connect received. Ignored.\n");
- return;
- }
- if ( cls.state != CA_CHALLENGING ) {
- Com_Printf ("connectResponse packet while not connecting. Ignored.\n");
- return;
- }
- if ( !NET_CompareAdr( from, clc.serverAddress ) ) {
- Com_Printf( "connectResponse from wrong address. Ignored.\n" );
- return;
- }
- Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableValue( "net_qport" ) );
- cls.state = CA_CONNECTED;
- clc.lastPacketSentTime = -9999; // send first packet immediately
- return;
- }
-
- // server responding to an info broadcast
- if ( !Q_stricmp(c, "infoResponse") ) {
- CL_ServerInfoPacket( from, msg );
- return;
- }
-
- // server responding to a get playerlist
- if ( !Q_stricmp(c, "statusResponse") ) {
- CL_ServerStatusResponse( from, msg );
- return;
- }
-
- // a disconnect message from the server, which will happen if the server
- // dropped the connection but it is still getting packets from us
- if (!Q_stricmp(c, "disconnect")) {
- CL_DisconnectPacket( from );
- return;
- }
-
- // echo request from server
- if ( !Q_stricmp(c, "echo") ) {
- NET_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv(1) );
- return;
- }
-
- // cd check
- if ( !Q_stricmp(c, "keyAuthorize") ) {
- // we don't use these now, so dump them on the floor
- return;
- }
-
- // global MOTD from id
- if ( !Q_stricmp(c, "motd") ) {
- CL_MotdPacket( from );
- return;
- }
-
- // echo request from server
- if ( !Q_stricmp(c, "print") ) {
- s = MSG_ReadString( msg );
- Q_strncpyz( clc.serverMessage, s, sizeof( clc.serverMessage ) );
- Com_Printf( "%s", s );
- return;
- }
-
- // list of servers sent back by a master server (classic)
- if ( !Q_strncmp(c, "getserversResponse", 18) ) {
- CL_ServersResponsePacket( &from, msg, qfalse );
- return;
- }
-
- // list of servers sent back by a master server (extended)
- if ( !Q_strncmp(c, "getserversExtResponse", 21) ) {
- CL_ServersResponsePacket( &from, msg, qtrue );
- return;
- }
-
- Com_DPrintf ("Unknown connectionless packet command.\n");
-}
-
-
-/*
-=================
-CL_PacketEvent
-
-A packet has arrived from the main event loop
-=================
-*/
-void CL_PacketEvent( netadr_t from, msg_t *msg ) {
- int headerBytes;
-
- clc.lastPacketTime = cls.realtime;
-
- if ( msg->cursize >= 4 && *(int *)msg->data == -1 ) {
- CL_ConnectionlessPacket( from, msg );
- return;
- }
-
- if ( cls.state < CA_CONNECTED ) {
- return; // can't be a valid sequenced packet
- }
-
- if ( msg->cursize < 4 ) {
- Com_Printf ("%s: Runt packet\n", NET_AdrToStringwPort( from ));
- return;
- }
-
- //
- // packet from server
- //
- if ( !NET_CompareAdr( from, clc.netchan.remoteAddress ) ) {
- Com_DPrintf ("%s:sequenced packet without connection\n"
- , NET_AdrToStringwPort( from ) );
- // FIXME: send a client disconnect?
- return;
- }
-
- if (!CL_Netchan_Process( &clc.netchan, msg) ) {
- return; // out of order, duplicated, etc
- }
-
- // the header is different lengths for reliable and unreliable messages
- headerBytes = msg->readcount;
-
- // track the last message received so it can be returned in
- // client messages, allowing the server to detect a dropped
- // gamestate
- clc.serverMessageSequence = LittleLong( *(int *)msg->data );
-
- clc.lastPacketTime = cls.realtime;
- CL_ParseServerMessage( msg );
-
- //
- // we don't know if it is ok to save a demo message until
- // after we have parsed the frame
- //
- if ( clc.demorecording && !clc.demowaiting ) {
- CL_WriteDemoMessage( msg, headerBytes );
- }
-}
-
-/*
-==================
-CL_CheckTimeout
-
-==================
-*/
-void CL_CheckTimeout( void ) {
- //
- // check timeout
- //
- if ( ( !CL_CheckPaused() || !sv_paused->integer )
- && cls.state >= CA_CONNECTED && cls.state != CA_CINEMATIC
- && cls.realtime - clc.lastPacketTime > cl_timeout->value*1000) {
- if (++cl.timeoutcount > 5) { // timeoutcount saves debugger
- Com_Printf ("\nServer connection timed out.\n");
- CL_Disconnect( qtrue );
- return;
- }
- } else {
- cl.timeoutcount = 0;
- }
-}
-
-/*
-==================
-CL_CheckPaused
-Check whether client has been paused.
-==================
-*/
-qboolean CL_CheckPaused(void)
-{
- // if cl_paused->modified is set, the cvar has only been changed in
- // this frame. Keep paused in this frame to ensure the server doesn't
- // lag behind.
- if(cl_paused->integer || cl_paused->modified)
- return qtrue;
-
- return qfalse;
-}
-
-//============================================================================
-
-/*
-==================
-CL_CheckUserinfo
-
-==================
-*/
-void CL_CheckUserinfo( void ) {
- // don't add reliable commands when not yet connected
- if(cls.state < CA_CHALLENGING)
- return;
-
- // don't overflow the reliable command buffer when paused
- if(CL_CheckPaused())
- return;
-
- // send a reliable userinfo update if needed
- if(cvar_modifiedFlags & CVAR_USERINFO)
- {
- cvar_modifiedFlags &= ~CVAR_USERINFO;
- CL_AddReliableCommand(va("userinfo \"%s\"", Cvar_InfoString( CVAR_USERINFO ) ), qfalse);
- }
-}
-
-/*
-==================
-CL_Frame
-
-==================
-*/
-void CL_Frame ( int msec ) {
-
- if ( !com_cl_running->integer ) {
- return;
- }
-
-#ifdef USE_CURL
- if(clc.downloadCURLM) {
- CL_cURL_PerformDownload();
- // we can't process frames normally when in disconnected
- // download mode since the ui vm expects cls.state to be
- // CA_CONNECTED
- if(clc.cURLDisconnected) {
- cls.realFrametime = msec;
- cls.frametime = msec;
- cls.realtime += cls.frametime;
- SCR_UpdateScreen();
- S_Update();
- Con_RunConsole();
- cls.framecount++;
- return;
- }
- }
-#endif
-
- if ( cls.cddialog ) {
- // bring up the cd error dialog if needed
- cls.cddialog = qfalse;
- VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_NEED_CD );
- } else if ( cls.state == CA_DISCONNECTED && !( Key_GetCatcher( ) & KEYCATCH_UI )
- && !com_sv_running->integer && uivm ) {
- // if disconnected, bring up the menu
- S_StopAllSounds();
- VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN );
- }
-
- // if recording an avi, lock to a fixed fps
- if ( CL_VideoRecording( ) && cl_aviFrameRate->integer && msec) {
- // save the current screen
- if ( cls.state == CA_ACTIVE || cl_forceavidemo->integer) {
- CL_TakeVideoFrame( );
-
- // fixed time for next frame'
- msec = (int)ceil( (1000.0f / cl_aviFrameRate->value) * com_timescale->value );
- if (msec == 0) {
- msec = 1;
- }
- }
- }
-
- if( cl_autoRecordDemo->integer ) {
- if( cls.state == CA_ACTIVE && !clc.demorecording && !clc.demoplaying ) {
- // If not recording a demo, and we should be, start one
- qtime_t now;
- char *nowString;
- char *p;
- char mapName[ MAX_QPATH ];
- char serverName[ MAX_OSPATH ];
-
- Com_RealTime( &now );
- nowString = va( "%04d%02d%02d%02d%02d%02d",
- 1900 + now.tm_year,
- 1 + now.tm_mon,
- now.tm_mday,
- now.tm_hour,
- now.tm_min,
- now.tm_sec );
-
- Q_strncpyz( serverName, cls.servername, MAX_OSPATH );
- // Replace the ":" in the address as it is not a valid
- // file name character
- p = strstr( serverName, ":" );
- if( p ) {
- *p = '.';
- }
-
- Q_strncpyz( mapName, COM_SkipPath( cl.mapname ), sizeof( cl.mapname ) );
- COM_StripExtension(mapName, mapName, sizeof(mapName));
-
- Cbuf_ExecuteText( EXEC_NOW,
- va( "record %s-%s-%s", nowString, serverName, mapName ) );
- }
- else if( cls.state != CA_ACTIVE && clc.demorecording ) {
- // Recording, but not CA_ACTIVE, so stop recording
- CL_StopRecord_f( );
- }
- }
-
- // save the msec before checking pause
- cls.realFrametime = msec;
-
- // decide the simulation time
- cls.frametime = msec;
-
- cls.realtime += cls.frametime;
-
- if ( cl_timegraph->integer ) {
- SCR_DebugGraph ( cls.realFrametime * 0.25, 0 );
- }
-
- // see if we need to update any userinfo
- CL_CheckUserinfo();
-
- // if we haven't gotten a packet in a long time,
- // drop the connection
- CL_CheckTimeout();
-
- // send intentions now
- CL_SendCmd();
-
- // resend a connection request if necessary
- CL_CheckForResend();
-
- // decide on the serverTime to render
- CL_SetCGameTime();
-
- // update the screen
- SCR_UpdateScreen();
-
- // update audio
- S_Update();
-
-#ifdef USE_VOIP
- CL_CaptureVoip();
-#endif
-
-#ifdef USE_MUMBLE
- CL_UpdateMumble();
-#endif
-
- // advance local effects for next frame
- SCR_RunCinematic();
-
- Con_RunConsole();
-
- cls.framecount++;
-}
-
-
-//============================================================================
-
-/*
-================
-CL_RefPrintf
-
-DLL glue
-================
-*/
-void QDECL CL_RefPrintf( int print_level, const char *fmt, ...) {
- va_list argptr;
- char msg[MAXPRINTMSG];
-
- va_start (argptr,fmt);
- Q_vsnprintf (msg, sizeof(msg), fmt, argptr);
- va_end (argptr);
-
- if ( print_level == PRINT_ALL ) {
- Com_Printf ("%s", msg);
- } else if ( print_level == PRINT_WARNING ) {
- Com_Printf (S_COLOR_YELLOW "%s", msg); // yellow
- } else if ( print_level == PRINT_DEVELOPER ) {
- Com_DPrintf (S_COLOR_RED "%s", msg); // red
- }
-}
-
-
-
-/*
-============
-CL_ShutdownRef
-============
-*/
-void CL_ShutdownRef( void ) {
- if ( !re.Shutdown ) {
- return;
- }
- re.Shutdown( qtrue );
- Com_Memset( &re, 0, sizeof( re ) );
-}
-
-/*
-============
-CL_InitRenderer
-============
-*/
-void CL_InitRenderer( void ) {
- // this sets up the renderer and calls R_Init
- re.BeginRegistration( &cls.glconfig );
-
- // load character sets
- cls.charSetShader = re.RegisterShader( "gfx/2d/bigchars" );
- cls.whiteShader = re.RegisterShader( "white" );
- cls.consoleShader = re.RegisterShader( "console" );
- g_console_field_width = cls.glconfig.vidWidth / SMALLCHAR_WIDTH - 2;
- g_consoleField.widthInChars = g_console_field_width;
-}
-
-/*
-============================
-CL_StartHunkUsers
-
-After the server has cleared the hunk, these will need to be restarted
-This is the only place that any of these functions are called from
-============================
-*/
-void CL_StartHunkUsers( qboolean rendererOnly ) {
- if (!com_cl_running) {
- return;
- }
-
- if ( !com_cl_running->integer ) {
- return;
- }
-
- if ( !cls.rendererStarted ) {
- cls.rendererStarted = qtrue;
- CL_InitRenderer();
- }
-
- if ( rendererOnly ) {
- return;
- }
-
- if ( !cls.soundStarted ) {
- cls.soundStarted = qtrue;
- S_Init();
- }
-
- if ( !cls.soundRegistered ) {
- cls.soundRegistered = qtrue;
- S_BeginRegistration();
- }
-
- if( com_dedicated->integer ) {
- return;
- }
-
- if ( !cls.uiStarted ) {
- cls.uiStarted = qtrue;
- CL_InitUI();
- }
-}
-
-/*
-============
-CL_RefMalloc
-============
-*/
-void *CL_RefMalloc( int size ) {
- return Z_TagMalloc( size, TAG_RENDERER );
-}
-
-int CL_ScaledMilliseconds(void) {
- return Sys_Milliseconds()*com_timescale->value;
-}
-
-/*
-============
-CL_InitRef
-============
-*/
-void CL_InitRef( void ) {
- refimport_t ri;
- refexport_t *ret;
-
- Com_Printf( "----- Initializing Renderer ----\n" );
-
- ri.Cmd_AddCommand = Cmd_AddCommand;
- ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
- ri.Cmd_Argc = Cmd_Argc;
- ri.Cmd_Argv = Cmd_Argv;
- ri.Cmd_ExecuteText = Cbuf_ExecuteText;
- ri.Printf = CL_RefPrintf;
- ri.Error = Com_Error;
- ri.Milliseconds = CL_ScaledMilliseconds;
- ri.Malloc = CL_RefMalloc;
- ri.Free = Z_Free;
-#ifdef HUNK_DEBUG
- ri.Hunk_AllocDebug = Hunk_AllocDebug;
-#else
- ri.Hunk_Alloc = Hunk_Alloc;
-#endif
- ri.Hunk_AllocateTempMemory = Hunk_AllocateTempMemory;
- ri.Hunk_FreeTempMemory = Hunk_FreeTempMemory;
- ri.CM_DrawDebugSurface = CM_DrawDebugSurface;
- ri.FS_ReadFile = FS_ReadFile;
- ri.FS_FreeFile = FS_FreeFile;
- ri.FS_WriteFile = FS_WriteFile;
- ri.FS_FreeFileList = FS_FreeFileList;
- ri.FS_ListFiles = FS_ListFiles;
- ri.FS_FileIsInPAK = FS_FileIsInPAK;
- ri.FS_FileExists = FS_FileExists;
- ri.Cvar_Get = Cvar_Get;
- ri.Cvar_Set = Cvar_Set;
- ri.Cvar_CheckRange = Cvar_CheckRange;
-
- // cinematic stuff
-
- ri.CIN_UploadCinematic = CIN_UploadCinematic;
- ri.CIN_PlayCinematic = CIN_PlayCinematic;
- ri.CIN_RunCinematic = CIN_RunCinematic;
-
- ri.CL_WriteAVIVideoFrame = CL_WriteAVIVideoFrame;
-
- ret = GetRefAPI( REF_API_VERSION, &ri );
-
-#if defined __USEA3D && defined __A3D_GEOM
- hA3Dg_ExportRenderGeom (ret);
-#endif
-
- Com_Printf( "-------------------------------\n");
-
- if ( !ret ) {
- Com_Error (ERR_FATAL, "Couldn't initialize refresh" );
- }
-
- re = *ret;
-
- // unpause so the cgame definately gets a snapshot and renders a frame
- Cvar_Set( "cl_paused", "0" );
-}
-
-
-//===========================================================================================
-
-
-void CL_SetModel_f( void ) {
- char *arg;
- char name[256];
-
- arg = Cmd_Argv( 1 );
- if (arg[0]) {
- Cvar_Set( "model", arg );
- Cvar_Set( "headmodel", arg );
- } else {
- Cvar_VariableStringBuffer( "model", name, sizeof(name) );
- Com_Printf("model is set to %s\n", name);
- }
-}
-
-
-//===========================================================================================
-
-
-/*
-===============
-CL_Video_f
-
-video
-video [filename]
-===============
-*/
-void CL_Video_f( void )
-{
- char filename[ MAX_OSPATH ];
- int i, last;
-
- if( !clc.demoplaying )
- {
- Com_Printf( "The video command can only be used when playing back demos\n" );
- return;
- }
-
- if( Cmd_Argc( ) == 2 )
- {
- // explicit filename
- Com_sprintf( filename, MAX_OSPATH, "videos/%s.avi", Cmd_Argv( 1 ) );
- }
- else
- {
- // scan for a free filename
- for( i = 0; i <= 9999; i++ )
- {
- int a, b, c, d;
-
- last = i;
-
- a = last / 1000;
- last -= a * 1000;
- b = last / 100;
- last -= b * 100;
- c = last / 10;
- last -= c * 10;
- d = last;
-
- Com_sprintf( filename, MAX_OSPATH, "videos/video%d%d%d%d.avi",
- a, b, c, d );
-
- if( !FS_FileExists( filename ) )
- break; // file doesn't exist
- }
-
- if( i > 9999 )
- {
- Com_Printf( S_COLOR_RED "ERROR: no free file names to create video\n" );
- return;
- }
- }
-
- CL_OpenAVIForWriting( filename );
-}
-
-/*
-===============
-CL_StopVideo_f
-===============
-*/
-void CL_StopVideo_f( void )
-{
- CL_CloseAVI( );
-}
-
-/*
-===============
-CL_GenerateQKey
-
-test to see if a valid QKEY_FILE exists. If one does not, try to generate
-it by filling it with 2048 bytes of random data.
-===============
-*/
-static void CL_GenerateQKey(void)
-{
- int len = 0;
- unsigned char buff[ QKEY_SIZE ];
- fileHandle_t f;
-
- len = FS_SV_FOpenFileRead( QKEY_FILE, &f );
- FS_FCloseFile( f );
- if( len == QKEY_SIZE ) {
- Com_Printf( "QKEY found.\n" );
- return;
- }
- else {
- if( len > 0 ) {
- Com_Printf( "QKEY file size != %d, regenerating\n",
- QKEY_SIZE );
- }
-
- Com_Printf( "QKEY building random string\n" );
- Com_RandomBytes( buff, sizeof(buff) );
-
- f = FS_SV_FOpenFileWrite( QKEY_FILE );
- if( !f ) {
- Com_Printf( "QKEY could not open %s for write\n",
- QKEY_FILE );
- return;
- }
- FS_Write( buff, sizeof(buff), f );
- FS_FCloseFile( f );
- Com_Printf( "QKEY generated\n" );
- }
-}
-
-/*
-====================
-CL_Init
-====================
-*/
-void CL_Init( void ) {
- Com_Printf( "----- Client Initialization -----\n" );
-
- Con_Init ();
-
- CL_ClearState ();
-
- cls.state = CA_DISCONNECTED; // no longer CA_UNINITIALIZED
-
- cls.realtime = 0;
-
- CL_InitInput ();
-
- //
- // register our variables
- //
- cl_noprint = Cvar_Get( "cl_noprint", "0", 0 );
- cl_motd = Cvar_Get ("cl_motd", "1", 0);
-
- cl_timeout = Cvar_Get ("cl_timeout", "200", 0);
-
- cl_timeNudge = Cvar_Get ("cl_timeNudge", "0", CVAR_TEMP );
- cl_shownet = Cvar_Get ("cl_shownet", "0", CVAR_TEMP );
- cl_showSend = Cvar_Get ("cl_showSend", "0", CVAR_TEMP );
- cl_showTimeDelta = Cvar_Get ("cl_showTimeDelta", "0", CVAR_TEMP );
- cl_freezeDemo = Cvar_Get ("cl_freezeDemo", "0", CVAR_TEMP );
- rcon_client_password = Cvar_Get ("rconPassword", "", CVAR_TEMP );
- cl_activeAction = Cvar_Get( "activeAction", "", CVAR_TEMP );
-
- cl_timedemo = Cvar_Get ("timedemo", "0", 0);
- cl_timedemoLog = Cvar_Get ("cl_timedemoLog", "", CVAR_ARCHIVE);
- cl_autoRecordDemo = Cvar_Get ("cl_autoRecordDemo", "0", CVAR_ARCHIVE);
- cl_aviFrameRate = Cvar_Get ("cl_aviFrameRate", "25", CVAR_ARCHIVE);
- cl_aviMotionJpeg = Cvar_Get ("cl_aviMotionJpeg", "1", CVAR_ARCHIVE);
- cl_forceavidemo = Cvar_Get ("cl_forceavidemo", "0", 0);
-
- rconAddress = Cvar_Get ("rconAddress", "", 0);
-
- cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", CVAR_ARCHIVE);
- cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "140", CVAR_ARCHIVE);
- cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
-
- cl_maxpackets = Cvar_Get ("cl_maxpackets", "30", CVAR_ARCHIVE );
- cl_packetdup = Cvar_Get ("cl_packetdup", "1", CVAR_ARCHIVE );
-
- cl_run = Cvar_Get ("cl_run", "1", CVAR_ARCHIVE);
- cl_sensitivity = Cvar_Get ("sensitivity", "5", CVAR_ARCHIVE);
- cl_mouseAccel = Cvar_Get ("cl_mouseAccel", "0", CVAR_ARCHIVE);
- cl_freelook = Cvar_Get( "cl_freelook", "1", CVAR_ARCHIVE );
-
- // 0: legacy mouse acceleration
- // 1: new implementation
- cl_mouseAccelStyle = Cvar_Get( "cl_mouseAccelStyle", "0", CVAR_ARCHIVE );
- // offset for the power function (for style 1, ignored otherwise)
- // this should be set to the max rate value
- cl_mouseAccelOffset = Cvar_Get( "cl_mouseAccelOffset", "5", CVAR_ARCHIVE );
-
- cl_showMouseRate = Cvar_Get ("cl_showmouserate", "0", 0);
-
- cl_allowDownload = Cvar_Get ("cl_allowDownload", "0", CVAR_ARCHIVE);
-#ifdef USE_CURL
- cl_cURLLib = Cvar_Get("cl_cURLLib", DEFAULT_CURL_LIB, CVAR_ARCHIVE);
-#endif
-
- cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0);
-#ifdef MACOS_X
- // In game video is REALLY slow in Mac OS X right now due to driver slowness
- cl_inGameVideo = Cvar_Get ("r_inGameVideo", "0", CVAR_ARCHIVE);
-#else
- cl_inGameVideo = Cvar_Get ("r_inGameVideo", "1", CVAR_ARCHIVE);
-#endif
-
- cl_serverStatusResendTime = Cvar_Get ("cl_serverStatusResendTime", "750", 0);
-
- // init autoswitch so the ui will have it correctly even
- // if the cgame hasn't been started
- Cvar_Get ("cg_autoswitch", "1", CVAR_ARCHIVE);
-
- m_pitch = Cvar_Get ("m_pitch", "0.022", CVAR_ARCHIVE);
- m_yaw = Cvar_Get ("m_yaw", "0.022", CVAR_ARCHIVE);
- m_forward = Cvar_Get ("m_forward", "0.25", CVAR_ARCHIVE);
- m_side = Cvar_Get ("m_side", "0.25", CVAR_ARCHIVE);
-#ifdef MACOS_X
- // Input is jittery on OS X w/o this
- m_filter = Cvar_Get ("m_filter", "1", CVAR_ARCHIVE);
-#else
- m_filter = Cvar_Get ("m_filter", "0", CVAR_ARCHIVE);
-#endif
-
- cl_motdString = Cvar_Get( "cl_motdString", "", CVAR_ROM );
-
- Cvar_Get( "cl_maxPing", "800", CVAR_ARCHIVE );
-
- cl_lanForcePackets = Cvar_Get ("cl_lanForcePackets", "1", CVAR_ARCHIVE);
-
- cl_guidServerUniq = Cvar_Get ("cl_guidServerUniq", "1", CVAR_ARCHIVE);
-
- // ~ and `, as keys and characters
- cl_consoleKeys = Cvar_Get( "cl_consoleKeys", "~ ` 0x7e 0x60", CVAR_ARCHIVE);
-
- // userinfo
- Cvar_Get ("name", "UnnamedPlayer", CVAR_USERINFO | CVAR_ARCHIVE );
- Cvar_Get ("rate", "3000", CVAR_USERINFO | CVAR_ARCHIVE );
- Cvar_Get ("snaps", "20", CVAR_USERINFO | CVAR_ARCHIVE );
- Cvar_Get ("model", "sarge", CVAR_USERINFO | CVAR_ARCHIVE );
- Cvar_Get ("headmodel", "sarge", CVAR_USERINFO | CVAR_ARCHIVE );
- Cvar_Get ("team_model", "james", CVAR_USERINFO | CVAR_ARCHIVE );
- Cvar_Get ("team_headmodel", "*james", CVAR_USERINFO | CVAR_ARCHIVE );
- Cvar_Get ("g_redTeam", "Stroggs", CVAR_SERVERINFO | CVAR_ARCHIVE);
- Cvar_Get ("g_blueTeam", "Pagans", CVAR_SERVERINFO | CVAR_ARCHIVE);
- Cvar_Get ("color1", "4", CVAR_USERINFO | CVAR_ARCHIVE );
- Cvar_Get ("color2", "5", CVAR_USERINFO | CVAR_ARCHIVE );
- Cvar_Get ("handicap", "100", CVAR_USERINFO | CVAR_ARCHIVE );
- Cvar_Get ("teamtask", "0", CVAR_USERINFO );
- Cvar_Get ("sex", "male", CVAR_USERINFO | CVAR_ARCHIVE );
- Cvar_Get ("cl_anonymous", "0", CVAR_USERINFO | CVAR_ARCHIVE );
-
- Cvar_Get ("password", "", CVAR_USERINFO);
- Cvar_Get ("cg_predictItems", "1", CVAR_USERINFO | CVAR_ARCHIVE );
-
-#ifdef USE_MUMBLE
- cl_useMumble = Cvar_Get ("cl_useMumble", "0", CVAR_ARCHIVE | CVAR_LATCH);
- cl_mumbleScale = Cvar_Get ("cl_mumbleScale", "0.0254", CVAR_ARCHIVE);
-#endif
-
-#ifdef USE_VOIP
- cl_voipSend = Cvar_Get ("cl_voipSend", "0", 0);
- cl_voipSendTarget = Cvar_Get ("cl_voipSendTarget", "all", 0);
- cl_voipGainDuringCapture = Cvar_Get ("cl_voipGainDuringCapture", "0.2", CVAR_ARCHIVE);
- cl_voipCaptureMult = Cvar_Get ("cl_voipCaptureMult", "2.0", CVAR_ARCHIVE);
- cl_voipUseVAD = Cvar_Get ("cl_voipUseVAD", "0", CVAR_ARCHIVE);
- cl_voipVADThreshold = Cvar_Get ("cl_voipVADThreshold", "0.25", CVAR_ARCHIVE);
- cl_voipShowMeter = Cvar_Get ("cl_voipShowMeter", "1", CVAR_ARCHIVE);
-
- // This is a protocol version number.
- cl_voip = Cvar_Get ("cl_voip", "1", CVAR_USERINFO | CVAR_ARCHIVE | CVAR_LATCH);
- Cvar_CheckRange( cl_voip, 0, 1, qtrue );
-
- // If your data rate is too low, you'll get Connection Interrupted warnings
- // when VoIP packets arrive, even if you have a broadband connection.
- // This might work on rates lower than 25000, but for safety's sake, we'll
- // just demand it. Who doesn't have at least a DSL line now, anyhow? If
- // you don't, you don't need VoIP. :)
- if ((cl_voip->integer) && (Cvar_VariableIntegerValue("rate") < 25000)) {
- Com_Printf("Your network rate is too slow for VoIP.\n");
- Com_Printf("Set 'Data Rate' to 'LAN/Cable/xDSL' in 'Setup/System/Network' and restart.\n");
- Com_Printf("Until then, VoIP is disabled.\n");
- Cvar_Set("cl_voip", "0");
- }
-#endif
-
-
- // cgame might not be initialized before menu is used
- Cvar_Get ("cg_viewsize", "100", CVAR_ARCHIVE );
- // Make sure cg_stereoSeparation is zero as that variable is deprecated and should not be used anymore.
- Cvar_Get ("cg_stereoSeparation", "0", CVAR_ROM);
-
- //
- // register our commands
- //
- Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
- Cmd_AddCommand ("configstrings", CL_Configstrings_f);
- Cmd_AddCommand ("clientinfo", CL_Clientinfo_f);
- Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
- Cmd_AddCommand ("vid_restart", CL_Vid_Restart_f);
- Cmd_AddCommand ("disconnect", CL_Disconnect_f);
- Cmd_AddCommand ("record", CL_Record_f);
- Cmd_AddCommand ("demo", CL_PlayDemo_f);
- Cmd_SetCommandCompletionFunc( "demo", CL_CompleteDemoName );
- Cmd_AddCommand ("cinematic", CL_PlayCinematic_f);
- Cmd_AddCommand ("stoprecord", CL_StopRecord_f);
- Cmd_AddCommand ("connect", CL_Connect_f);
- Cmd_AddCommand ("reconnect", CL_Reconnect_f);
- Cmd_AddCommand ("localservers", CL_LocalServers_f);
- Cmd_AddCommand ("globalservers", CL_GlobalServers_f);
- Cmd_AddCommand ("rcon", CL_Rcon_f);
- Cmd_SetCommandCompletionFunc( "rcon", CL_CompleteRcon );
- Cmd_AddCommand ("ping", CL_Ping_f );
- Cmd_AddCommand ("serverstatus", CL_ServerStatus_f );
- Cmd_AddCommand ("showip", CL_ShowIP_f );
- Cmd_AddCommand ("fs_openedList", CL_OpenedPK3List_f );
- Cmd_AddCommand ("fs_referencedList", CL_ReferencedPK3List_f );
- Cmd_AddCommand ("model", CL_SetModel_f );
- Cmd_AddCommand ("video", CL_Video_f );
- Cmd_AddCommand ("stopvideo", CL_StopVideo_f );
- CL_InitRef();
-
- SCR_Init ();
-
-// Cbuf_Execute ();
-
- Cvar_Set( "cl_running", "1" );
-
- CL_GenerateQKey();
- Cvar_Get( "cl_guid", "", CVAR_USERINFO | CVAR_ROM );
- CL_UpdateGUID( NULL, 0 );
-
- Com_Printf( "----- Client Initialization Complete -----\n" );
-}
-
-
-/*
-===============
-CL_Shutdown
-
-===============
-*/
-void CL_Shutdown( void ) {
- static qboolean recursive = qfalse;
-
- // check whether the client is running at all.
- if(!(com_cl_running && com_cl_running->integer))
- return;
-
- Com_Printf( "----- CL_Shutdown -----\n" );
-
- if ( recursive ) {
- Com_Printf( "WARNING: Recursive shutdown\n" );
- return;
- }
- recursive = qtrue;
-
- CL_Disconnect( qtrue );
-
- S_Shutdown();
- CL_ShutdownRef();
-
- CL_ShutdownUI();
-
- Cmd_RemoveCommand ("cmd");
- Cmd_RemoveCommand ("configstrings");
- Cmd_RemoveCommand ("userinfo");
- Cmd_RemoveCommand ("snd_restart");
- Cmd_RemoveCommand ("vid_restart");
- Cmd_RemoveCommand ("disconnect");
- Cmd_RemoveCommand ("record");
- Cmd_RemoveCommand ("demo");
- Cmd_RemoveCommand ("cinematic");
- Cmd_RemoveCommand ("stoprecord");
- Cmd_RemoveCommand ("connect");
- Cmd_RemoveCommand ("localservers");
- Cmd_RemoveCommand ("globalservers");
- Cmd_RemoveCommand ("rcon");
- Cmd_RemoveCommand ("ping");
- Cmd_RemoveCommand ("serverstatus");
- Cmd_RemoveCommand ("showip");
- Cmd_RemoveCommand ("model");
- Cmd_RemoveCommand ("video");
- Cmd_RemoveCommand ("stopvideo");
-
- Cvar_Set( "cl_running", "0" );
-
- recursive = qfalse;
-
- Com_Memset( &cls, 0, sizeof( cls ) );
- Key_SetCatcher( 0 );
-
- Com_Printf( "-----------------------\n" );
-
-}
-
-static void CL_SetServerInfo(serverInfo_t *server, const char *info, int ping) {
- if (server) {
- if (info) {
- server->clients = atoi(Info_ValueForKey(info, "clients"));
- Q_strncpyz(server->hostName,Info_ValueForKey(info, "hostname"), MAX_NAME_LENGTH);
- Q_strncpyz(server->mapName, Info_ValueForKey(info, "mapname"), MAX_NAME_LENGTH);
- server->maxClients = atoi(Info_ValueForKey(info, "sv_maxclients"));
- Q_strncpyz(server->game,Info_ValueForKey(info, "game"), MAX_NAME_LENGTH);
- server->gameType = atoi(Info_ValueForKey(info, "gametype"));
- server->netType = atoi(Info_ValueForKey(info, "nettype"));
- server->minPing = atoi(Info_ValueForKey(info, "minping"));
- server->maxPing = atoi(Info_ValueForKey(info, "maxping"));
- server->punkbuster = atoi(Info_ValueForKey(info, "punkbuster"));
- }
- server->ping = ping;
- }
-}
-
-static void CL_SetServerInfoByAddress(netadr_t from, const char *info, int ping) {
- int i;
-
- for (i = 0; i < MAX_OTHER_SERVERS; i++) {
- if (NET_CompareAdr(from, cls.localServers[i].adr)) {
- CL_SetServerInfo(&cls.localServers[i], info, ping);
- }
- }
-
- for (i = 0; i < MAX_GLOBAL_SERVERS; i++) {
- if (NET_CompareAdr(from, cls.globalServers[i].adr)) {
- CL_SetServerInfo(&cls.globalServers[i], info, ping);
- }
- }
-
- for (i = 0; i < MAX_OTHER_SERVERS; i++) {
- if (NET_CompareAdr(from, cls.favoriteServers[i].adr)) {
- CL_SetServerInfo(&cls.favoriteServers[i], info, ping);
- }
- }
-
-}
-
-/*
-===================
-CL_ServerInfoPacket
-===================
-*/
-void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) {
- int i, type;
- char info[MAX_INFO_STRING];
- char *infoString;
- int prot;
-
- infoString = MSG_ReadString( msg );
-
- // if this isn't the correct protocol version, ignore it
- prot = atoi( Info_ValueForKey( infoString, "protocol" ) );
- if ( prot != PROTOCOL_VERSION ) {
- Com_DPrintf( "Different protocol info packet: %s\n", infoString );
- return;
- }
-
- // iterate servers waiting for ping response
- for (i=0; i<MAX_PINGREQUESTS; i++)
- {
- if ( cl_pinglist[i].adr.port && !cl_pinglist[i].time && NET_CompareAdr( from, cl_pinglist[i].adr ) )
- {
- // calc ping time
- cl_pinglist[i].time = Sys_Milliseconds() - cl_pinglist[i].start;
- Com_DPrintf( "ping time %dms from %s\n", cl_pinglist[i].time, NET_AdrToString( from ) );
-
- // save of info
- Q_strncpyz( cl_pinglist[i].info, infoString, sizeof( cl_pinglist[i].info ) );
-
- // tack on the net type
- // NOTE: make sure these types are in sync with the netnames strings in the UI
- switch (from.type)
- {
- case NA_BROADCAST:
- case NA_IP:
- type = 1;
- break;
- case NA_IP6:
- type = 2;
- break;
- default:
- type = 0;
- break;
- }
- Info_SetValueForKey( cl_pinglist[i].info, "nettype", va("%d", type) );
- CL_SetServerInfoByAddress(from, infoString, cl_pinglist[i].time);
-
- return;
- }
- }
-
- // if not just sent a local broadcast or pinging local servers
- if (cls.pingUpdateSource != AS_LOCAL) {
- return;
- }
-
- for ( i = 0 ; i < MAX_OTHER_SERVERS ; i++ ) {
- // empty slot
- if ( cls.localServers[i].adr.port == 0 ) {
- break;
- }
-
- // avoid duplicate
- if ( NET_CompareAdr( from, cls.localServers[i].adr ) ) {
- return;
- }
- }
-
- if ( i == MAX_OTHER_SERVERS ) {
- Com_DPrintf( "MAX_OTHER_SERVERS hit, dropping infoResponse\n" );
- return;
- }
-
- // add this to the list
- cls.numlocalservers = i+1;
- cls.localServers[i].adr = from;
- cls.localServers[i].clients = 0;
- cls.localServers[i].hostName[0] = '\0';
- cls.localServers[i].mapName[0] = '\0';
- cls.localServers[i].maxClients = 0;
- cls.localServers[i].maxPing = 0;
- cls.localServers[i].minPing = 0;
- cls.localServers[i].ping = -1;
- cls.localServers[i].game[0] = '\0';
- cls.localServers[i].gameType = 0;
- cls.localServers[i].netType = from.type;
- cls.localServers[i].punkbuster = 0;
-
- Q_strncpyz( info, MSG_ReadString( msg ), MAX_INFO_STRING );
- if (strlen(info)) {
- if (info[strlen(info)-1] != '\n') {
- strncat(info, "\n", sizeof(info) - 1);
- }
- Com_Printf( "%s: %s", NET_AdrToStringwPort( from ), info );
- }
-}
-
-/*
-===================
-CL_GetServerStatus
-===================
-*/
-serverStatus_t *CL_GetServerStatus( netadr_t from ) {
- serverStatus_t *serverStatus;
- int i, oldest, oldestTime;
-
- serverStatus = NULL;
- for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
- if ( NET_CompareAdr( from, cl_serverStatusList[i].address ) ) {
- return &cl_serverStatusList[i];
- }
- }
- for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
- if ( cl_serverStatusList[i].retrieved ) {
- return &cl_serverStatusList[i];
- }
- }
- oldest = -1;
- oldestTime = 0;
- for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
- if (oldest == -1 || cl_serverStatusList[i].startTime < oldestTime) {
- oldest = i;
- oldestTime = cl_serverStatusList[i].startTime;
- }
- }
- if (oldest != -1) {
- return &cl_serverStatusList[oldest];
- }
- serverStatusCount++;
- return &cl_serverStatusList[serverStatusCount & (MAX_SERVERSTATUSREQUESTS-1)];
-}
-
-/*
-===================
-CL_ServerStatus
-===================
-*/
-int CL_ServerStatus( char *serverAddress, char *serverStatusString, int maxLen ) {
- int i;
- netadr_t to;
- serverStatus_t *serverStatus;
-
- // if no server address then reset all server status requests
- if ( !serverAddress ) {
- for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
- cl_serverStatusList[i].address.port = 0;
- cl_serverStatusList[i].retrieved = qtrue;
- }
- return qfalse;
- }
- // get the address
- if ( !NET_StringToAdr( serverAddress, &to, NA_UNSPEC) ) {
- return qfalse;
- }
- serverStatus = CL_GetServerStatus( to );
- // if no server status string then reset the server status request for this address
- if ( !serverStatusString ) {
- serverStatus->retrieved = qtrue;
- return qfalse;
- }
-
- // if this server status request has the same address
- if ( NET_CompareAdr( to, serverStatus->address) ) {
- // if we recieved an response for this server status request
- if (!serverStatus->pending) {
- Q_strncpyz(serverStatusString, serverStatus->string, maxLen);
- serverStatus->retrieved = qtrue;
- serverStatus->startTime = 0;
- return qtrue;
- }
- // resend the request regularly
- else if ( serverStatus->startTime < Com_Milliseconds() - cl_serverStatusResendTime->integer ) {
- serverStatus->print = qfalse;
- serverStatus->pending = qtrue;
- serverStatus->retrieved = qfalse;
- serverStatus->time = 0;
- serverStatus->startTime = Com_Milliseconds();
- NET_OutOfBandPrint( NS_CLIENT, to, "getstatus" );
- return qfalse;
- }
- }
- // if retrieved
- else if ( serverStatus->retrieved ) {
- serverStatus->address = to;
- serverStatus->print = qfalse;
- serverStatus->pending = qtrue;
- serverStatus->retrieved = qfalse;
- serverStatus->startTime = Com_Milliseconds();
- serverStatus->time = 0;
- NET_OutOfBandPrint( NS_CLIENT, to, "getstatus" );
- return qfalse;
- }
- return qfalse;
-}
-
-/*
-===================
-CL_ServerStatusResponse
-===================
-*/
-void CL_ServerStatusResponse( netadr_t from, msg_t *msg ) {
- char *s;
- char info[MAX_INFO_STRING];
- int i, l, score, ping;
- int len;
- serverStatus_t *serverStatus;
-
- serverStatus = NULL;
- for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
- if ( NET_CompareAdr( from, cl_serverStatusList[i].address ) ) {
- serverStatus = &cl_serverStatusList[i];
- break;
- }
- }
- // if we didn't request this server status
- if (!serverStatus) {
- return;
- }
-
- s = MSG_ReadStringLine( msg );
-
- len = 0;
- Com_sprintf(&serverStatus->string[len], sizeof(serverStatus->string)-len, "%s", s);
-
- if (serverStatus->print) {
- Com_Printf("Server settings:\n");
- // print cvars
- while (*s) {
- for (i = 0; i < 2 && *s; i++) {
- if (*s == '\\')
- s++;
- l = 0;
- while (*s) {
- info[l++] = *s;
- if (l >= MAX_INFO_STRING-1)
- break;
- s++;
- if (*s == '\\') {
- break;
- }
- }
- info[l] = '\0';
- if (i) {
- Com_Printf("%s\n", info);
- }
- else {
- Com_Printf("%-24s", info);
- }
- }
- }
- }
-
- len = strlen(serverStatus->string);
- Com_sprintf(&serverStatus->string[len], sizeof(serverStatus->string)-len, "\\");
-
- if (serverStatus->print) {
- Com_Printf("\nPlayers:\n");
- Com_Printf("num: score: ping: name:\n");
- }
- for (i = 0, s = MSG_ReadStringLine( msg ); *s; s = MSG_ReadStringLine( msg ), i++) {
-
- len = strlen(serverStatus->string);
- Com_sprintf(&serverStatus->string[len], sizeof(serverStatus->string)-len, "\\%s", s);
-
- if (serverStatus->print) {
- score = ping = 0;
- sscanf(s, "%d %d", &score, &ping);
- s = strchr(s, ' ');
- if (s)
- s = strchr(s+1, ' ');
- if (s)
- s++;
- else
- s = "unknown";
- Com_Printf("%-2d %-3d %-3d %s\n", i, score, ping, s );
- }
- }
- len = strlen(serverStatus->string);
- Com_sprintf(&serverStatus->string[len], sizeof(serverStatus->string)-len, "\\");
-
- serverStatus->time = Com_Milliseconds();
- serverStatus->address = from;
- serverStatus->pending = qfalse;
- if (serverStatus->print) {
- serverStatus->retrieved = qtrue;
- }
-}
-
-/*
-==================
-CL_LocalServers_f
-==================
-*/
-void CL_LocalServers_f( void ) {
- char *message;
- int i, j;
- netadr_t to;
-
- Com_Printf( "Scanning for servers on the local network...\n");
-
- // reset the list, waiting for response
- cls.numlocalservers = 0;
- cls.pingUpdateSource = AS_LOCAL;
-
- for (i = 0; i < MAX_OTHER_SERVERS; i++) {
- qboolean b = cls.localServers[i].visible;
- Com_Memset(&cls.localServers[i], 0, sizeof(cls.localServers[i]));
- cls.localServers[i].visible = b;
- }
- Com_Memset( &to, 0, sizeof( to ) );
-
- // The 'xxx' in the message is a challenge that will be echoed back
- // by the server. We don't care about that here, but master servers
- // can use that to prevent spoofed server responses from invalid ip
- message = "\377\377\377\377getinfo xxx";
-
- // send each message twice in case one is dropped
- for ( i = 0 ; i < 2 ; i++ ) {
- // send a broadcast packet on each server port
- // we support multiple server ports so a single machine
- // can nicely run multiple servers
- for ( j = 0 ; j < NUM_SERVER_PORTS ; j++ ) {
- to.port = BigShort( (short)(PORT_SERVER + j) );
-
- to.type = NA_BROADCAST;
- NET_SendPacket( NS_CLIENT, strlen( message ), message, to );
- to.type = NA_MULTICAST6;
- NET_SendPacket( NS_CLIENT, strlen( message ), message, to );
- }
- }
-}
-
-/*
-==================
-CL_GlobalServers_f
-==================
-*/
-void CL_GlobalServers_f( void ) {
- netadr_t to;
- int count, i, masterNum;
- char command[1024], *masteraddress;
- char *cmdname;
-
- if ((count = Cmd_Argc()) < 3 || (masterNum = atoi(Cmd_Argv(1))) < 0 || masterNum > 4)
- {
- Com_Printf( "usage: globalservers <master# 0-4> <protocol> [keywords]\n");
- return;
- }
-
- sprintf(command, "sv_master%d", masterNum + 1);
- masteraddress = Cvar_VariableString(command);
-
- if(!*masteraddress)
- {
- Com_Printf( "CL_GlobalServers_f: Error: No master server address given.\n");
- return;
- }
-
- // reset the list, waiting for response
- // -1 is used to distinguish a "no response"
-
- i = NET_StringToAdr(masteraddress, &to, NA_UNSPEC);
-
- if(!i)
- {
- Com_Printf( "CL_GlobalServers_f: Error: could not resolve address of master %s\n", masteraddress);
- return;
- }
- else if(i == 2)
- to.port = BigShort(PORT_MASTER);
-
- Com_Printf("Requesting servers from master %s...\n", masteraddress);
-
- cls.numglobalservers = -1;
- cls.pingUpdateSource = AS_GLOBAL;
-
- // Use the extended query for IPv6 masters
- if (to.type == NA_IP6 || to.type == NA_MULTICAST6)
- {
- cmdname = "getserversExt " GAMENAME_FOR_MASTER;
-
- // TODO: test if we only have an IPv6 connection. If it's the case,
- // request IPv6 servers only by appending " ipv6" to the command
- }
- else
- cmdname = "getservers";
- Com_sprintf( command, sizeof(command), "%s %s", cmdname, Cmd_Argv(2) );
-
- for (i=3; i < count; i++)
- {
- Q_strcat(command, sizeof(command), " ");
- Q_strcat(command, sizeof(command), Cmd_Argv(i));
- }
-
- NET_OutOfBandPrint( NS_SERVER, to, "%s", command );
-}
-
-
-/*
-==================
-CL_GetPing
-==================
-*/
-void CL_GetPing( int n, char *buf, int buflen, int *pingtime )
-{
- const char *str;
- int time;
- int maxPing;
-
- if (!cl_pinglist[n].adr.port)
- {
- // empty slot
- buf[0] = '\0';
- *pingtime = 0;
- return;
- }
-
- str = NET_AdrToStringwPort( cl_pinglist[n].adr );
- Q_strncpyz( buf, str, buflen );
-
- time = cl_pinglist[n].time;
- if (!time)
- {
- // check for timeout
- time = Sys_Milliseconds() - cl_pinglist[n].start;
- maxPing = Cvar_VariableIntegerValue( "cl_maxPing" );
- if( maxPing < 100 ) {
- maxPing = 100;
- }
- if (time < maxPing)
- {
- // not timed out yet
- time = 0;
- }
- }
-
- CL_SetServerInfoByAddress(cl_pinglist[n].adr, cl_pinglist[n].info, cl_pinglist[n].time);
-
- *pingtime = time;
-}
-
-/*
-==================
-CL_UpdateServerInfo
-==================
-*/
-void CL_UpdateServerInfo( int n )
-{
- if (!cl_pinglist[n].adr.port)
- {
- return;
- }
-
- CL_SetServerInfoByAddress(cl_pinglist[n].adr, cl_pinglist[n].info, cl_pinglist[n].time );
-}
-
-/*
-==================
-CL_GetPingInfo
-==================
-*/
-void CL_GetPingInfo( int n, char *buf, int buflen )
-{
- if (!cl_pinglist[n].adr.port)
- {
- // empty slot
- if (buflen)
- buf[0] = '\0';
- return;
- }
-
- Q_strncpyz( buf, cl_pinglist[n].info, buflen );
-}
-
-/*
-==================
-CL_ClearPing
-==================
-*/
-void CL_ClearPing( int n )
-{
- if (n < 0 || n >= MAX_PINGREQUESTS)
- return;
-
- cl_pinglist[n].adr.port = 0;
-}
-
-/*
-==================
-CL_GetPingQueueCount
-==================
-*/
-int CL_GetPingQueueCount( void )
-{
- int i;
- int count;
- ping_t* pingptr;
-
- count = 0;
- pingptr = cl_pinglist;
-
- for (i=0; i<MAX_PINGREQUESTS; i++, pingptr++ ) {
- if (pingptr->adr.port) {
- count++;
- }
- }
-
- return (count);
-}
-
-/*
-==================
-CL_GetFreePing
-==================
-*/
-ping_t* CL_GetFreePing( void )
-{
- ping_t* pingptr;
- ping_t* best;
- int oldest;
- int i;
- int time;
-
- pingptr = cl_pinglist;
- for (i=0; i<MAX_PINGREQUESTS; i++, pingptr++ )
- {
- // find free ping slot
- if (pingptr->adr.port)
- {
- if (!pingptr->time)
- {
- if (Sys_Milliseconds() - pingptr->start < 500)
- {
- // still waiting for response
- continue;
- }
- }
- else if (pingptr->time < 500)
- {
- // results have not been queried
- continue;
- }
- }
-
- // clear it
- pingptr->adr.port = 0;
- return (pingptr);
- }
-
- // use oldest entry
- pingptr = cl_pinglist;
- best = cl_pinglist;
- oldest = INT_MIN;
- for (i=0; i<MAX_PINGREQUESTS; i++, pingptr++ )
- {
- // scan for oldest
- time = Sys_Milliseconds() - pingptr->start;
- if (time > oldest)
- {
- oldest = time;
- best = pingptr;
- }
- }
-
- return (best);
-}
-
-/*
-==================
-CL_Ping_f
-==================
-*/
-void CL_Ping_f( void ) {
- netadr_t to;
- ping_t* pingptr;
- char* server;
- int argc;
- netadrtype_t family = NA_UNSPEC;
-
- argc = Cmd_Argc();
-
- if ( argc != 2 && argc != 3 ) {
- Com_Printf( "usage: ping [-4|-6] server\n");
- return;
- }
-
- if(argc == 2)
- server = Cmd_Argv(1);
- else
- {
- if(!strcmp(Cmd_Argv(1), "-4"))
- family = NA_IP;
- else if(!strcmp(Cmd_Argv(1), "-6"))
- family = NA_IP6;
- else
- Com_Printf( "warning: only -4 or -6 as address type understood.\n");
-
- server = Cmd_Argv(2);
- }
-
- Com_Memset( &to, 0, sizeof(netadr_t) );
-
- if ( !NET_StringToAdr( server, &to, family ) ) {
- return;
- }
-
- pingptr = CL_GetFreePing();
-
- memcpy( &pingptr->adr, &to, sizeof (netadr_t) );
- pingptr->start = Sys_Milliseconds();
- pingptr->time = 0;
-
- CL_SetServerInfoByAddress(pingptr->adr, NULL, 0);
-
- NET_OutOfBandPrint( NS_CLIENT, to, "getinfo xxx" );
-}
-
-/*
-==================
-CL_UpdateVisiblePings_f
-==================
-*/
-qboolean CL_UpdateVisiblePings_f(int source) {
- int slots, i;
- char buff[MAX_STRING_CHARS];
- int pingTime;
- int max;
- qboolean status = qfalse;
-
- if (source < 0 || source > AS_FAVORITES) {
- return qfalse;
- }
-
- cls.pingUpdateSource = source;
-
- slots = CL_GetPingQueueCount();
- if (slots < MAX_PINGREQUESTS) {
- serverInfo_t *server = NULL;
-
- max = (source == AS_GLOBAL) ? MAX_GLOBAL_SERVERS : MAX_OTHER_SERVERS;
- switch (source) {
- case AS_LOCAL :
- server = &cls.localServers[0];
- max = cls.numlocalservers;
- break;
- case AS_GLOBAL :
- server = &cls.globalServers[0];
- max = cls.numglobalservers;
- break;
- case AS_FAVORITES :
- server = &cls.favoriteServers[0];
- max = cls.numfavoriteservers;
- break;
- default:
- return qfalse;
- }
- for (i = 0; i < max; i++) {
- if (server[i].visible) {
- if (server[i].ping == -1) {
- int j;
-
- if (slots >= MAX_PINGREQUESTS) {
- break;
- }
- for (j = 0; j < MAX_PINGREQUESTS; j++) {
- if (!cl_pinglist[j].adr.port) {
- continue;
- }
- if (NET_CompareAdr( cl_pinglist[j].adr, server[i].adr)) {
- // already on the list
- break;
- }
- }
- if (j >= MAX_PINGREQUESTS) {
- status = qtrue;
- for (j = 0; j < MAX_PINGREQUESTS; j++) {
- if (!cl_pinglist[j].adr.port) {
- break;
- }
- }
- memcpy(&cl_pinglist[j].adr, &server[i].adr, sizeof(netadr_t));
- cl_pinglist[j].start = Sys_Milliseconds();
- cl_pinglist[j].time = 0;
- NET_OutOfBandPrint( NS_CLIENT, cl_pinglist[j].adr, "getinfo xxx" );
- slots++;
- }
- }
- // if the server has a ping higher than cl_maxPing or
- // the ping packet got lost
- else if (server[i].ping == 0) {
- // if we are updating global servers
- if (source == AS_GLOBAL) {
- //
- if ( cls.numGlobalServerAddresses > 0 ) {
- // overwrite this server with one from the additional global servers
- cls.numGlobalServerAddresses--;
- CL_InitServerInfo(&server[i], &cls.globalServerAddresses[cls.numGlobalServerAddresses]);
- // NOTE: the server[i].visible flag stays untouched
- }
- }
- }
- }
- }
- }
-
- if (slots) {
- status = qtrue;
- }
- for (i = 0; i < MAX_PINGREQUESTS; i++) {
- if (!cl_pinglist[i].adr.port) {
- continue;
- }
- CL_GetPing( i, buff, MAX_STRING_CHARS, &pingTime );
- if (pingTime != 0) {
- CL_ClearPing(i);
- status = qtrue;
- }
- }
-
- return status;
-}
-
-/*
-==================
-CL_ServerStatus_f
-==================
-*/
-void CL_ServerStatus_f(void) {
- netadr_t to, *toptr = NULL;
- char *server;
- serverStatus_t *serverStatus;
- int argc;
- netadrtype_t family = NA_UNSPEC;
-
- argc = Cmd_Argc();
-
- if ( argc != 2 && argc != 3 )
- {
- if (cls.state != CA_ACTIVE || clc.demoplaying)
- {
- Com_Printf ("Not connected to a server.\n");
- Com_Printf( "usage: serverstatus [-4|-6] server\n");
- return;
- }
-
- toptr = &clc.serverAddress;
- }
-
- if(!toptr)
- {
- Com_Memset( &to, 0, sizeof(netadr_t) );
-
- if(argc == 2)
- server = Cmd_Argv(1);
- else
- {
- if(!strcmp(Cmd_Argv(1), "-4"))
- family = NA_IP;
- else if(!strcmp(Cmd_Argv(1), "-6"))
- family = NA_IP6;
- else
- Com_Printf( "warning: only -4 or -6 as address type understood.\n");
-
- server = Cmd_Argv(2);
- }
-
- toptr = &to;
- if ( !NET_StringToAdr( server, toptr, family ) )
- return;
- }
-
- NET_OutOfBandPrint( NS_CLIENT, *toptr, "getstatus" );
-
- serverStatus = CL_GetServerStatus( *toptr );
- serverStatus->address = *toptr;
- serverStatus->print = qtrue;
- serverStatus->pending = qtrue;
-}
-
-/*
-==================
-CL_ShowIP_f
-==================
-*/
-void CL_ShowIP_f(void) {
- Sys_ShowIP();
-}
-
-#ifndef STANDALONE
-/*
-=================
-bool CL_CDKeyValidate
-=================
-*/
-qboolean CL_CDKeyValidate( const char *key, const char *checksum ) {
- char ch;
- byte sum;
- char chs[3];
- int i, len;
-
- len = strlen(key);
- if( len != CDKEY_LEN ) {
- return qfalse;
- }
-
- if( checksum && strlen( checksum ) != CDCHKSUM_LEN ) {
- return qfalse;
- }
-
- sum = 0;
- // for loop gets rid of conditional assignment warning
- for (i = 0; i < len; i++) {
- ch = *key++;
- if (ch>='a' && ch<='z') {
- ch -= 32;
- }
- switch( ch ) {
- case '2':
- case '3':
- case '7':
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'G':
- case 'H':
- case 'J':
- case 'L':
- case 'P':
- case 'R':
- case 'S':
- case 'T':
- case 'W':
- sum += ch;
- continue;
- default:
- return qfalse;
- }
- }
-
- sprintf(chs, "%02x", sum);
-
- if (checksum && !Q_stricmp(chs, checksum)) {
- return qtrue;
- }
-
- if (!checksum) {
- return qtrue;
- }
-
- return qfalse;
-}
-#endif
diff --git a/engine/code/client/cl_net_chan.c b/engine/code/client/cl_net_chan.c
deleted file mode 100644
index 1433c43..0000000
--- a/engine/code/client/cl_net_chan.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-#include "client.h"
-
-/*
-==============
-CL_Netchan_Encode
-
- // first 12 bytes of the data are always:
- long serverId;
- long messageAcknowledge;
- long reliableAcknowledge;
-
-==============
-*/
-static void CL_Netchan_Encode( msg_t *msg ) {
- int serverId, messageAcknowledge, reliableAcknowledge;
- int i, index, srdc, sbit, soob;
- byte key, *string;
-
- if ( msg->cursize <= CL_ENCODE_START ) {
- return;
- }
-
- srdc = msg->readcount;
- sbit = msg->bit;
- soob = msg->oob;
-
- msg->bit = 0;
- msg->readcount = 0;
- msg->oob = 0;
-
- serverId = MSG_ReadLong(msg);
- messageAcknowledge = MSG_ReadLong(msg);
- reliableAcknowledge = MSG_ReadLong(msg);
-
- msg->oob = soob;
- msg->bit = sbit;
- msg->readcount = srdc;
-
- string = (byte *)clc.serverCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ];
- index = 0;
- //
- key = clc.challenge ^ serverId ^ messageAcknowledge;
- for (i = CL_ENCODE_START; i < msg->cursize; i++) {
- // modify the key with the last received now acknowledged server command
- if (!string[index])
- index = 0;
- if (string[index] > 127 || string[index] == '%') {
- key ^= '.' << (i & 1);
- }
- else {
- key ^= string[index] << (i & 1);
- }
- index++;
- // encode the data with this key
- *(msg->data + i) = (*(msg->data + i)) ^ key;
- }
-}
-
-/*
-==============
-CL_Netchan_Decode
-
- // first four bytes of the data are always:
- long reliableAcknowledge;
-
-==============
-*/
-static void CL_Netchan_Decode( msg_t *msg ) {
- long reliableAcknowledge, i, index;
- byte key, *string;
- int srdc, sbit, soob;
-
- srdc = msg->readcount;
- sbit = msg->bit;
- soob = msg->oob;
-
- msg->oob = 0;
-
- reliableAcknowledge = MSG_ReadLong(msg);
-
- msg->oob = soob;
- msg->bit = sbit;
- msg->readcount = srdc;
-
- string = (byte *) clc.reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ];
- index = 0;
- // xor the client challenge with the netchan sequence number (need something that changes every message)
- key = clc.challenge ^ LittleLong( *(unsigned *)msg->data );
- for (i = msg->readcount + CL_DECODE_START; i < msg->cursize; i++) {
- // modify the key with the last sent and with this message acknowledged client command
- if (!string[index])
- index = 0;
- if (string[index] > 127 || string[index] == '%') {
- key ^= '.' << (i & 1);
- }
- else {
- key ^= string[index] << (i & 1);
- }
- index++;
- // decode the data with this key
- *(msg->data + i) = *(msg->data + i) ^ key;
- }
-}
-
-/*
-=================
-CL_Netchan_TransmitNextFragment
-=================
-*/
-void CL_Netchan_TransmitNextFragment( netchan_t *chan ) {
- Netchan_TransmitNextFragment( chan );
-}
-
-/*
-===============
-CL_Netchan_Transmit
-================
-*/
-void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg ) {
- MSG_WriteByte( msg, clc_EOF );
-
- CL_Netchan_Encode( msg );
- Netchan_Transmit( chan, msg->cursize, msg->data );
-}
-
-extern int oldsize;
-int newsize = 0;
-
-/*
-=================
-CL_Netchan_Process
-=================
-*/
-qboolean CL_Netchan_Process( netchan_t *chan, msg_t *msg ) {
- int ret;
-
- ret = Netchan_Process( chan, msg );
- if (!ret)
- return qfalse;
- CL_Netchan_Decode( msg );
- newsize += msg->cursize;
- return qtrue;
-}
diff --git a/engine/code/client/cl_parse.c b/engine/code/client/cl_parse.c
deleted file mode 100644
index 687cb5f..0000000
--- a/engine/code/client/cl_parse.c
+++ /dev/null
@@ -1,909 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// cl_parse.c -- parse a message received from the server
-
-#include "client.h"
-
-char *svc_strings[256] = {
- "svc_bad",
-
- "svc_nop",
- "svc_gamestate",
- "svc_configstring",
- "svc_baseline",
- "svc_serverCommand",
- "svc_download",
- "svc_snapshot",
- "svc_EOF",
- "svc_extension",
- "svc_voip",
-};
-
-void SHOWNET( msg_t *msg, char *s) {
- if ( cl_shownet->integer >= 2) {
- Com_Printf ("%3i:%s\n", msg->readcount-1, s);
- }
-}
-
-
-/*
-=========================================================================
-
-MESSAGE PARSING
-
-=========================================================================
-*/
-
-/*
-==================
-CL_DeltaEntity
-
-Parses deltas from the given base and adds the resulting entity
-to the current frame
-==================
-*/
-void CL_DeltaEntity (msg_t *msg, clSnapshot_t *frame, int newnum, entityState_t *old,
- qboolean unchanged) {
- entityState_t *state;
-
- // save the parsed entity state into the big circular buffer so
- // it can be used as the source for a later delta
- state = &cl.parseEntities[cl.parseEntitiesNum & (MAX_PARSE_ENTITIES-1)];
-
- if ( unchanged ) {
- *state = *old;
- } else {
- MSG_ReadDeltaEntity( msg, old, state, newnum );
- }
-
- if ( state->number == (MAX_GENTITIES-1) ) {
- return; // entity was delta removed
- }
- cl.parseEntitiesNum++;
- frame->numEntities++;
-}
-
-/*
-==================
-CL_ParsePacketEntities
-
-==================
-*/
-void CL_ParsePacketEntities( msg_t *msg, clSnapshot_t *oldframe, clSnapshot_t *newframe) {
- int newnum;
- entityState_t *oldstate;
- int oldindex, oldnum;
-
- newframe->parseEntitiesNum = cl.parseEntitiesNum;
- newframe->numEntities = 0;
-
- // delta from the entities present in oldframe
- oldindex = 0;
- oldstate = NULL;
- if (!oldframe) {
- oldnum = 99999;
- } else {
- if ( oldindex >= oldframe->numEntities ) {
- oldnum = 99999;
- } else {
- oldstate = &cl.parseEntities[
- (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- }
-
- while ( 1 ) {
- // read the entity index number
- newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
-
- if ( newnum == (MAX_GENTITIES-1) ) {
- break;
- }
-
- if ( msg->readcount > msg->cursize ) {
- Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
- }
-
- while ( oldnum < newnum ) {
- // one or more entities from the old packet are unchanged
- if ( cl_shownet->integer == 3 ) {
- Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
- }
- CL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );
-
- oldindex++;
-
- if ( oldindex >= oldframe->numEntities ) {
- oldnum = 99999;
- } else {
- oldstate = &cl.parseEntities[
- (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- }
- if (oldnum == newnum) {
- // delta from previous state
- if ( cl_shownet->integer == 3 ) {
- Com_Printf ("%3i: delta: %i\n", msg->readcount, newnum);
- }
- CL_DeltaEntity( msg, newframe, newnum, oldstate, qfalse );
-
- oldindex++;
-
- if ( oldindex >= oldframe->numEntities ) {
- oldnum = 99999;
- } else {
- oldstate = &cl.parseEntities[
- (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- continue;
- }
-
- if ( oldnum > newnum ) {
- // delta from baseline
- if ( cl_shownet->integer == 3 ) {
- Com_Printf ("%3i: baseline: %i\n", msg->readcount, newnum);
- }
- CL_DeltaEntity( msg, newframe, newnum, &cl.entityBaselines[newnum], qfalse );
- continue;
- }
-
- }
-
- // any remaining entities in the old frame are copied over
- while ( oldnum != 99999 ) {
- // one or more entities from the old packet are unchanged
- if ( cl_shownet->integer == 3 ) {
- Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
- }
- CL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );
-
- oldindex++;
-
- if ( oldindex >= oldframe->numEntities ) {
- oldnum = 99999;
- } else {
- oldstate = &cl.parseEntities[
- (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- }
-}
-
-
-/*
-================
-CL_ParseSnapshot
-
-If the snapshot is parsed properly, it will be copied to
-cl.snap and saved in cl.snapshots[]. If the snapshot is invalid
-for any reason, no changes to the state will be made at all.
-================
-*/
-void CL_ParseSnapshot( msg_t *msg ) {
- int len;
- clSnapshot_t *old;
- clSnapshot_t newSnap;
- int deltaNum;
- int oldMessageNum;
- int i, packetNum;
-
- // get the reliable sequence acknowledge number
- // NOTE: now sent with all server to client messages
- //clc.reliableAcknowledge = MSG_ReadLong( msg );
-
- // read in the new snapshot to a temporary buffer
- // we will only copy to cl.snap if it is valid
- Com_Memset (&newSnap, 0, sizeof(newSnap));
-
- // we will have read any new server commands in this
- // message before we got to svc_snapshot
- newSnap.serverCommandNum = clc.serverCommandSequence;
-
- newSnap.serverTime = MSG_ReadLong( msg );
-
- // if we were just unpaused, we can only *now* really let the
- // change come into effect or the client hangs.
- cl_paused->modified = 0;
-
- newSnap.messageNum = clc.serverMessageSequence;
-
- deltaNum = MSG_ReadByte( msg );
- if ( !deltaNum ) {
- newSnap.deltaNum = -1;
- } else {
- newSnap.deltaNum = newSnap.messageNum - deltaNum;
- }
- newSnap.snapFlags = MSG_ReadByte( msg );
-
- // If the frame is delta compressed from data that we
- // no longer have available, we must suck up the rest of
- // the frame, but not use it, then ask for a non-compressed
- // message
- if ( newSnap.deltaNum <= 0 ) {
- newSnap.valid = qtrue; // uncompressed frame
- old = NULL;
- clc.demowaiting = qfalse; // we can start recording now
- } else {
- old = &cl.snapshots[newSnap.deltaNum & PACKET_MASK];
- if ( !old->valid ) {
- // should never happen
- Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
- } else if ( old->messageNum != newSnap.deltaNum ) {
- // The frame that the server did the delta from
- // is too old, so we can't reconstruct it properly.
- Com_Printf ("Delta frame too old.\n");
- } else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) {
- Com_Printf ("Delta parseEntitiesNum too old.\n");
- } else {
- newSnap.valid = qtrue; // valid delta parse
- }
- }
-
- // read areamask
- len = MSG_ReadByte( msg );
-
- if(len > sizeof(newSnap.areamask))
- {
- Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask.", len);
- return;
- }
-
- MSG_ReadData( msg, &newSnap.areamask, len);
-
- // read playerinfo
- SHOWNET( msg, "playerstate" );
- if ( old ) {
- MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
- } else {
- MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );
- }
-
- // read packet entities
- SHOWNET( msg, "packet entities" );
- CL_ParsePacketEntities( msg, old, &newSnap );
-
- // if not valid, dump the entire thing now that it has
- // been properly read
- if ( !newSnap.valid ) {
- return;
- }
-
- // clear the valid flags of any snapshots between the last
- // received and this one, so if there was a dropped packet
- // it won't look like something valid to delta from next
- // time we wrap around in the buffer
- oldMessageNum = cl.snap.messageNum + 1;
-
- if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP ) {
- oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 );
- }
- for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) {
- cl.snapshots[oldMessageNum & PACKET_MASK].valid = qfalse;
- }
-
- // copy to the current good spot
- cl.snap = newSnap;
- cl.snap.ping = 999;
- // calculate ping time
- for ( i = 0 ; i < PACKET_BACKUP ; i++ ) {
- packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;
- if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime ) {
- cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime;
- break;
- }
- }
- // save the frame off in the backup array for later delta comparisons
- cl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap;
-
- if (cl_shownet->integer == 3) {
- Com_Printf( " snapshot:%i delta:%i ping:%i\n", cl.snap.messageNum,
- cl.snap.deltaNum, cl.snap.ping );
- }
-
- cl.newSnapshots = qtrue;
-}
-
-
-//=====================================================================
-
-int cl_connectedToPureServer;
-int cl_connectedToCheatServer;
-
-#ifdef USE_VOIP
-int cl_connectedToVoipServer;
-#endif
-
-/*
-==================
-CL_SystemInfoChanged
-
-The systeminfo configstring has been changed, so parse
-new information out of it. This will happen at every
-gamestate, and possibly during gameplay.
-==================
-*/
-void CL_SystemInfoChanged( void ) {
- char *systemInfo;
- const char *s, *t;
- char key[BIG_INFO_KEY];
- char value[BIG_INFO_VALUE];
- qboolean gameSet;
-
- systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SYSTEMINFO ];
- // NOTE TTimo:
- // when the serverId changes, any further messages we send to the server will use this new serverId
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
- // in some cases, outdated cp commands might get sent with this news serverId
- cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) );
-
- // don't set any vars when playing a demo
- if ( clc.demoplaying ) {
- return;
- }
-
-#ifdef USE_VOIP
- // in the future, (val) will be a protocol version string, so only
- // accept explicitly 1, not generally non-zero.
- s = Info_ValueForKey( systemInfo, "sv_voip" );
- cl_connectedToVoipServer = (atoi( s ) == 1);
-#endif
-
- s = Info_ValueForKey( systemInfo, "sv_cheats" );
- cl_connectedToCheatServer = atoi( s );
- if ( !cl_connectedToCheatServer ) {
- Cvar_SetCheatState();
- }
-
- // check pure server string
- s = Info_ValueForKey( systemInfo, "sv_paks" );
- t = Info_ValueForKey( systemInfo, "sv_pakNames" );
- FS_PureServerSetLoadedPaks( s, t );
-
- s = Info_ValueForKey( systemInfo, "sv_referencedPaks" );
- t = Info_ValueForKey( systemInfo, "sv_referencedPakNames" );
- FS_PureServerSetReferencedPaks( s, t );
-
- gameSet = qfalse;
- // scan through all the variables in the systeminfo and locally set cvars to match
- s = systemInfo;
- while ( s ) {
- int cvar_flags;
-
- Info_NextPair( &s, key, value );
- if ( !key[0] ) {
- break;
- }
-
- // ehw!
- if (!Q_stricmp(key, "fs_game"))
- {
- if(FS_CheckDirTraversal(value))
- {
- Com_Printf(S_COLOR_YELLOW "WARNING: Server sent invalid fs_game value %s\n", value);
- continue;
- }
-
- gameSet = qtrue;
- }
-
- if((cvar_flags = Cvar_Flags(key)) == CVAR_NONEXISTENT)
- Cvar_Get(key, value, CVAR_SERVER_CREATED | CVAR_ROM);
- else
- {
- // If this cvar may not be modified by a server discard the value.
- if(!(cvar_flags & (CVAR_SYSTEMINFO | CVAR_SERVER_CREATED)))
- {
- Com_Printf(S_COLOR_YELLOW "WARNING: server is not allowed to set %s=%s\n", key, value);
- continue;
- }
-
- Cvar_Set(key, value);
- }
- }
- // if game folder should not be set and it is set at the client side
- if ( !gameSet && *Cvar_VariableString("fs_game") ) {
- Cvar_Set( "fs_game", "" );
- }
- cl_connectedToPureServer = Cvar_VariableValue( "sv_pure" );
-}
-
-/*
-==================
-CL_ParseServerInfo
-==================
-*/
-static void CL_ParseServerInfo(void)
-{
- const char *serverInfo;
-
- serverInfo = cl.gameState.stringData
- + cl.gameState.stringOffsets[ CS_SERVERINFO ];
-
- clc.sv_allowDownload = atoi(Info_ValueForKey(serverInfo,
- "sv_allowDownload"));
- Q_strncpyz(clc.sv_dlURL,
- Info_ValueForKey(serverInfo, "sv_dlURL"),
- sizeof(clc.sv_dlURL));
-}
-
-/*
-==================
-CL_ParseGamestate
-==================
-*/
-void CL_ParseGamestate( msg_t *msg ) {
- int i;
- entityState_t *es;
- int newnum;
- entityState_t nullstate;
- int cmd;
- char *s;
-
- Con_Close();
-
- clc.connectPacketCount = 0;
-
- // wipe local client state
- CL_ClearState();
-
- // a gamestate always marks a server command sequence
- clc.serverCommandSequence = MSG_ReadLong( msg );
-
- // parse all the configstrings and baselines
- cl.gameState.dataCount = 1; // leave a 0 at the beginning for uninitialized configstrings
- while ( 1 ) {
- cmd = MSG_ReadByte( msg );
-
- if ( cmd == svc_EOF ) {
- break;
- }
-
- if ( cmd == svc_configstring ) {
- int len;
-
- i = MSG_ReadShort( msg );
- if ( i < 0 || i >= MAX_CONFIGSTRINGS ) {
- Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" );
- }
- s = MSG_ReadBigString( msg );
- len = strlen( s );
-
- if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {
- Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" );
- }
-
- // append it to the gameState string buffer
- cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;
- Com_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, s, len + 1 );
- cl.gameState.dataCount += len + 1;
- } else if ( cmd == svc_baseline ) {
- newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
- if ( newnum < 0 || newnum >= MAX_GENTITIES ) {
- Com_Error( ERR_DROP, "Baseline number out of range: %i", newnum );
- }
- Com_Memset (&nullstate, 0, sizeof(nullstate));
- es = &cl.entityBaselines[ newnum ];
- MSG_ReadDeltaEntity( msg, &nullstate, es, newnum );
- } else {
- Com_Error( ERR_DROP, "CL_ParseGamestate: bad command byte" );
- }
- }
-
- clc.clientNum = MSG_ReadLong(msg);
- // read the checksum feed
- clc.checksumFeed = MSG_ReadLong( msg );
-
- // parse useful values out of CS_SERVERINFO
- CL_ParseServerInfo();
-
- // parse serverId and other cvars
- CL_SystemInfoChanged();
-
- // stop recording now so the demo won't have an unnecessary level load at the end.
- if(cl_autoRecordDemo->integer && clc.demorecording)
- CL_StopRecord_f();
-
- // reinitialize the filesystem if the game directory has changed
- FS_ConditionalRestart( clc.checksumFeed );
-
- // This used to call CL_StartHunkUsers, but now we enter the download state before loading the
- // cgame
- CL_InitDownloads();
-
- // make sure the game starts
- Cvar_Set( "cl_paused", "0" );
-}
-
-
-//=====================================================================
-
-/*
-=====================
-CL_ParseDownload
-
-A download message has been received from the server
-=====================
-*/
-void CL_ParseDownload ( msg_t *msg ) {
- int size;
- unsigned char data[MAX_MSGLEN];
- int block;
-
- if (!*clc.downloadTempName) {
- Com_Printf("Server sending download, but no download was requested\n");
- CL_AddReliableCommand("stopdl", qfalse);
- return;
- }
-
- // read the data
- block = MSG_ReadShort ( msg );
-
- if ( !block )
- {
- // block zero is special, contains file size
- clc.downloadSize = MSG_ReadLong ( msg );
-
- Cvar_SetValue( "cl_downloadSize", clc.downloadSize );
-
- if (clc.downloadSize < 0)
- {
- Com_Error( ERR_DROP, "%s", MSG_ReadString( msg ) );
- return;
- }
- }
-
- size = MSG_ReadShort ( msg );
- if (size < 0 || size > sizeof(data))
- {
- Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size);
- return;
- }
-
- MSG_ReadData(msg, data, size);
-
- if (clc.downloadBlock != block) {
- Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", clc.downloadBlock, block);
- return;
- }
-
- // open the file if not opened yet
- if (!clc.download)
- {
- clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName );
-
- if (!clc.download) {
- Com_Printf( "Could not create %s\n", clc.downloadTempName );
- CL_AddReliableCommand("stopdl", qfalse);
- CL_NextDownload();
- return;
- }
- }
-
- if (size)
- FS_Write( data, size, clc.download );
-
- CL_AddReliableCommand(va("nextdl %d", clc.downloadBlock), qfalse);
- clc.downloadBlock++;
-
- clc.downloadCount += size;
-
- // So UI gets access to it
- Cvar_SetValue( "cl_downloadCount", clc.downloadCount );
-
- if (!size) { // A zero length block means EOF
- if (clc.download) {
- FS_FCloseFile( clc.download );
- clc.download = 0;
-
- // rename the file
- FS_SV_Rename ( clc.downloadTempName, clc.downloadName );
- }
-
- // send intentions now
- // We need this because without it, we would hold the last nextdl and then start
- // loading right away. If we take a while to load, the server is happily trying
- // to send us that last block over and over.
- // Write it twice to help make sure we acknowledge the download
- CL_WritePacket();
- CL_WritePacket();
-
- // get another file if needed
- CL_NextDownload ();
- }
-}
-
-#ifdef USE_VOIP
-static
-qboolean CL_ShouldIgnoreVoipSender(int sender)
-{
- if (!cl_voip->integer)
- return qtrue; // VoIP is disabled.
- else if ((sender == clc.clientNum) && (!clc.demoplaying))
- return qtrue; // ignore own voice (unless playing back a demo).
- else if (clc.voipMuteAll)
- return qtrue; // all channels are muted with extreme prejudice.
- else if (clc.voipIgnore[sender])
- return qtrue; // just ignoring this guy.
- else if (clc.voipGain[sender] == 0.0f)
- return qtrue; // too quiet to play.
-
- return qfalse;
-}
-
-/*
-=====================
-CL_ParseVoip
-
-A VoIP message has been received from the server
-=====================
-*/
-static
-void CL_ParseVoip ( msg_t *msg ) {
- static short decoded[4096]; // !!! FIXME: don't hardcode.
-
- const int sender = MSG_ReadShort(msg);
- const int generation = MSG_ReadByte(msg);
- const int sequence = MSG_ReadLong(msg);
- const int frames = MSG_ReadByte(msg);
- const int packetsize = MSG_ReadShort(msg);
- char encoded[1024];
- int seqdiff = sequence - clc.voipIncomingSequence[sender];
- int written = 0;
- int i;
-
- Com_DPrintf("VoIP: %d-byte packet from client %d\n", packetsize, sender);
-
- if (sender < 0)
- return; // short/invalid packet, bail.
- else if (generation < 0)
- return; // short/invalid packet, bail.
- else if (sequence < 0)
- return; // short/invalid packet, bail.
- else if (frames < 0)
- return; // short/invalid packet, bail.
- else if (packetsize < 0)
- return; // short/invalid packet, bail.
-
- if (packetsize > sizeof (encoded)) { // overlarge packet?
- int bytesleft = packetsize;
- while (bytesleft) {
- int br = bytesleft;
- if (br > sizeof (encoded))
- br = sizeof (encoded);
- MSG_ReadData(msg, encoded, br);
- bytesleft -= br;
- }
- return; // overlarge packet, bail.
- }
-
- if (!clc.speexInitialized) {
- MSG_ReadData(msg, encoded, packetsize); // skip payload.
- return; // can't handle VoIP without libspeex!
- } else if (sender >= MAX_CLIENTS) {
- MSG_ReadData(msg, encoded, packetsize); // skip payload.
- return; // bogus sender.
- } else if (CL_ShouldIgnoreVoipSender(sender)) {
- MSG_ReadData(msg, encoded, packetsize); // skip payload.
- return; // Channel is muted, bail.
- }
-
- // !!! FIXME: make sure data is narrowband? Does decoder handle this?
-
- Com_DPrintf("VoIP: packet accepted!\n");
-
- // This is a new "generation" ... a new recording started, reset the bits.
- if (generation != clc.voipIncomingGeneration[sender]) {
- Com_DPrintf("VoIP: new generation %d!\n", generation);
- speex_bits_reset(&clc.speexDecoderBits[sender]);
- clc.voipIncomingGeneration[sender] = generation;
- seqdiff = 0;
- } else if (seqdiff < 0) { // we're ahead of the sequence?!
- // This shouldn't happen unless the packet is corrupted or something.
- Com_DPrintf("VoIP: misordered sequence! %d < %d!\n",
- sequence, clc.voipIncomingSequence[sender]);
- // reset the bits just in case.
- speex_bits_reset(&clc.speexDecoderBits[sender]);
- seqdiff = 0;
- } else if (seqdiff > 100) { // more than 2 seconds of audio dropped?
- // just start over.
- Com_DPrintf("VoIP: Dropped way too many (%d) frames from client #%d\n",
- seqdiff, sender);
- speex_bits_reset(&clc.speexDecoderBits[sender]);
- seqdiff = 0;
- }
-
- if (seqdiff != 0) {
- Com_DPrintf("VoIP: Dropped %d frames from client #%d\n",
- seqdiff, sender);
- // tell speex that we're missing frames...
- for (i = 0; i < seqdiff; i++) {
- assert((written + clc.speexFrameSize) * 2 < sizeof (decoded));
- speex_decode_int(clc.speexDecoder[sender], NULL, decoded + written);
- written += clc.speexFrameSize;
- }
- }
-
- for (i = 0; i < frames; i++) {
- char encoded[256];
- const int len = MSG_ReadByte(msg);
- if (len < 0) {
- Com_DPrintf("VoIP: Short packet!\n");
- break;
- }
- MSG_ReadData(msg, encoded, len);
-
- // shouldn't happen, but just in case...
- if ((written + clc.speexFrameSize) * 2 > sizeof (decoded)) {
- Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
- written * 2, written, i);
- S_RawSamples(sender + 1, written, clc.speexSampleRate, 2, 1,
- (const byte *) decoded, clc.voipGain[sender]);
- written = 0;
- }
-
- speex_bits_read_from(&clc.speexDecoderBits[sender], encoded, len);
- speex_decode_int(clc.speexDecoder[sender],
- &clc.speexDecoderBits[sender], decoded + written);
-
- #if 0
- static FILE *encio = NULL;
- if (encio == NULL) encio = fopen("voip-incoming-encoded.bin", "wb");
- if (encio != NULL) { fwrite(encoded, len, 1, encio); fflush(encio); }
- static FILE *decio = NULL;
- if (decio == NULL) decio = fopen("voip-incoming-decoded.bin", "wb");
- if (decio != NULL) { fwrite(decoded+written, clc.speexFrameSize*2, 1, decio); fflush(decio); }
- #endif
-
- written += clc.speexFrameSize;
- }
-
- Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
- written * 2, written, i);
-
- if (written > 0) {
- S_RawSamples(sender + 1, written, clc.speexSampleRate, 2, 1,
- (const byte *) decoded, clc.voipGain[sender]);
- }
-
- clc.voipIncomingSequence[sender] = sequence + frames;
-}
-#endif
-
-
-/*
-=====================
-CL_ParseCommandString
-
-Command strings are just saved off until cgame asks for them
-when it transitions a snapshot
-=====================
-*/
-void CL_ParseCommandString( msg_t *msg ) {
- char *s;
- int seq;
- int index;
-
- seq = MSG_ReadLong( msg );
- s = MSG_ReadString( msg );
-
- // see if we have already executed stored it off
- if ( clc.serverCommandSequence >= seq ) {
- return;
- }
- clc.serverCommandSequence = seq;
-
- index = seq & (MAX_RELIABLE_COMMANDS-1);
- Q_strncpyz( clc.serverCommands[ index ], s, sizeof( clc.serverCommands[ index ] ) );
-}
-
-
-/*
-=====================
-CL_ParseServerMessage
-=====================
-*/
-void CL_ParseServerMessage( msg_t *msg ) {
- int cmd;
-
- if ( cl_shownet->integer == 1 ) {
- Com_Printf ("%i ",msg->cursize);
- } else if ( cl_shownet->integer >= 2 ) {
- Com_Printf ("------------------\n");
- }
-
- MSG_Bitstream(msg);
-
- // get the reliable sequence acknowledge number
- clc.reliableAcknowledge = MSG_ReadLong( msg );
- //
- if ( clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS ) {
- clc.reliableAcknowledge = clc.reliableSequence;
- }
-
- //
- // parse the message
- //
- while ( 1 ) {
- if ( msg->readcount > msg->cursize ) {
- Com_Error (ERR_DROP,"CL_ParseServerMessage: read past end of server message");
- break;
- }
-
- cmd = MSG_ReadByte( msg );
-
- // See if this is an extension command after the EOF, which means we
- // got data that a legacy client should ignore.
- if ((cmd == svc_EOF) && (MSG_LookaheadByte( msg ) == svc_extension)) {
- SHOWNET( msg, "EXTENSION" );
- MSG_ReadByte( msg ); // throw the svc_extension byte away.
- cmd = MSG_ReadByte( msg ); // something legacy clients can't do!
- // sometimes you get a svc_extension at end of stream...dangling
- // bits in the huffman decoder giving a bogus value?
- if (cmd == -1) {
- cmd = svc_EOF;
- }
- }
-
- if (cmd == svc_EOF) {
- SHOWNET( msg, "END OF MESSAGE" );
- break;
- }
-
- if ( cl_shownet->integer >= 2 ) {
- if ( (cmd < 0) || (!svc_strings[cmd]) ) {
- Com_Printf( "%3i:BAD CMD %i\n", msg->readcount-1, cmd );
- } else {
- SHOWNET( msg, svc_strings[cmd] );
- }
- }
-
- // other commands
- switch ( cmd ) {
- default:
- Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
- break;
- case svc_nop:
- break;
- case svc_serverCommand:
- CL_ParseCommandString( msg );
- break;
- case svc_gamestate:
- CL_ParseGamestate( msg );
- break;
- case svc_snapshot:
- CL_ParseSnapshot( msg );
- break;
- case svc_download:
- CL_ParseDownload( msg );
- break;
- case svc_voip:
-#ifdef USE_VOIP
- CL_ParseVoip( msg );
-#endif
- break;
- }
- }
-}
-
-
diff --git a/engine/code/client/cl_scrn.c b/engine/code/client/cl_scrn.c
deleted file mode 100644
index 568d684..0000000
--- a/engine/code/client/cl_scrn.c
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
-
-#include "client.h"
-
-qboolean scr_initialized; // ready to draw
-
-cvar_t *cl_timegraph;
-cvar_t *cl_debuggraph;
-cvar_t *cl_graphheight;
-cvar_t *cl_graphscale;
-cvar_t *cl_graphshift;
-
-/*
-================
-SCR_DrawNamedPic
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void SCR_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {
- qhandle_t hShader;
-
- assert( width != 0 );
-
- hShader = re.RegisterShader( picname );
- SCR_AdjustFrom640( &x, &y, &width, &height );
- re.DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
-}
-
-
-/*
-================
-SCR_AdjustFrom640
-
-Adjusted for resolution and screen aspect ratio
-================
-*/
-void SCR_AdjustFrom640( float *x, float *y, float *w, float *h ) {
- float xscale;
- float yscale;
-
-#if 0
- // adjust for wide screens
- if ( cls.glconfig.vidWidth * 480 > cls.glconfig.vidHeight * 640 ) {
- *x += 0.5 * ( cls.glconfig.vidWidth - ( cls.glconfig.vidHeight * 640 / 480 ) );
- }
-#endif
-
- // scale for screen sizes
- xscale = cls.glconfig.vidWidth / 640.0;
- yscale = cls.glconfig.vidHeight / 480.0;
- if ( x ) {
- *x *= xscale;
- }
- if ( y ) {
- *y *= yscale;
- }
- if ( w ) {
- *w *= xscale;
- }
- if ( h ) {
- *h *= yscale;
- }
-}
-
-/*
-================
-SCR_FillRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void SCR_FillRect( float x, float y, float width, float height, const float *color ) {
- re.SetColor( color );
-
- SCR_AdjustFrom640( &x, &y, &width, &height );
- re.DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cls.whiteShader );
-
- re.SetColor( NULL );
-}
-
-
-/*
-================
-SCR_DrawPic
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void SCR_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {
- SCR_AdjustFrom640( &x, &y, &width, &height );
- re.DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
-}
-
-
-
-/*
-** SCR_DrawChar
-** chars are drawn at 640*480 virtual screen size
-*/
-static void SCR_DrawChar( int x, int y, float size, int ch ) {
- int row, col;
- float frow, fcol;
- float ax, ay, aw, ah;
-
- ch &= 255;
-
- if ( ch == ' ' ) {
- return;
- }
-
- if ( y < -size ) {
- return;
- }
-
- ax = x;
- ay = y;
- aw = size;
- ah = size;
- SCR_AdjustFrom640( &ax, &ay, &aw, &ah );
-
- row = ch>>4;
- col = ch&15;
-
- frow = row*0.0625;
- fcol = col*0.0625;
- size = 0.0625;
-
- re.DrawStretchPic( ax, ay, aw, ah,
- fcol, frow,
- fcol + size, frow + size,
- cls.charSetShader );
-}
-
-/*
-** SCR_DrawSmallChar
-** small chars are drawn at native screen resolution
-*/
-void SCR_DrawSmallChar( int x, int y, int ch ) {
- int row, col;
- float frow, fcol;
- float size;
-
- ch &= 255;
-
- if ( ch == ' ' ) {
- return;
- }
-
- if ( y < -SMALLCHAR_HEIGHT ) {
- return;
- }
-
- row = ch>>4;
- col = ch&15;
-
- frow = row*0.0625;
- fcol = col*0.0625;
- size = 0.0625;
-
- re.DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT,
- fcol, frow,
- fcol + size, frow + size,
- cls.charSetShader );
-}
-
-
-/*
-==================
-SCR_DrawBigString[Color]
-
-Draws a multi-colored string with a drop shadow, optionally forcing
-to a fixed color.
-
-Coordinates are at 640 by 480 virtual resolution
-==================
-*/
-void SCR_DrawStringExt( int x, int y, float size, const char *string, float *setColor, qboolean forceColor,
- qboolean noColorEscape ) {
- vec4_t color;
- const char *s;
- int xx;
-
- // draw the drop shadow
- color[0] = color[1] = color[2] = 0;
- color[3] = setColor[3];
- re.SetColor( color );
- s = string;
- xx = x;
- while ( *s ) {
- if ( !noColorEscape && Q_IsColorString( s ) ) {
- s += 2;
- continue;
- }
- SCR_DrawChar( xx+2, y+2, size, *s );
- xx += size;
- s++;
- }
-
-
- // draw the colored text
- s = string;
- xx = x;
- re.SetColor( setColor );
- while ( *s ) {
- if ( !noColorEscape && Q_IsColorString( s ) ) {
- if ( !forceColor ) {
- Com_Memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
- color[3] = setColor[3];
- re.SetColor( color );
- }
- s += 2;
- continue;
- }
- SCR_DrawChar( xx, y, size, *s );
- xx += size;
- s++;
- }
- re.SetColor( NULL );
-}
-
-
-void SCR_DrawBigString( int x, int y, const char *s, float alpha, qboolean noColorEscape ) {
- float color[4];
-
- color[0] = color[1] = color[2] = 1.0;
- color[3] = alpha;
- SCR_DrawStringExt( x, y, BIGCHAR_WIDTH, s, color, qfalse, noColorEscape );
-}
-
-void SCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color, qboolean noColorEscape ) {
- SCR_DrawStringExt( x, y, BIGCHAR_WIDTH, s, color, qtrue, noColorEscape );
-}
-
-
-/*
-==================
-SCR_DrawSmallString[Color]
-
-Draws a multi-colored string with a drop shadow, optionally forcing
-to a fixed color.
-==================
-*/
-void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor,
- qboolean noColorEscape ) {
- vec4_t color;
- const char *s;
- int xx;
-
- // draw the colored text
- s = string;
- xx = x;
- re.SetColor( setColor );
- while ( *s ) {
- if ( Q_IsColorString( s ) ) {
- if ( !forceColor ) {
- Com_Memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
- color[3] = setColor[3];
- re.SetColor( color );
- }
- if ( !noColorEscape ) {
- s += 2;
- continue;
- }
- }
- SCR_DrawSmallChar( xx, y, *s );
- xx += SMALLCHAR_WIDTH;
- s++;
- }
- re.SetColor( NULL );
-}
-
-
-
-/*
-** SCR_Strlen -- skips color escape codes
-*/
-static int SCR_Strlen( const char *str ) {
- const char *s = str;
- int count = 0;
-
- while ( *s ) {
- if ( Q_IsColorString( s ) ) {
- s += 2;
- } else {
- count++;
- s++;
- }
- }
-
- return count;
-}
-
-/*
-** SCR_GetBigStringWidth
-*/
-int SCR_GetBigStringWidth( const char *str ) {
- return SCR_Strlen( str ) * 16;
-}
-
-
-//===============================================================================
-
-/*
-=================
-SCR_DrawDemoRecording
-=================
-*/
-void SCR_DrawDemoRecording( void ) {
- char string[1024];
- int pos;
-
- if ( !clc.demorecording ) {
- return;
- }
- if ( clc.spDemoRecording ) {
- return;
- }
-
- pos = FS_FTell( clc.demofile );
- sprintf( string, "RECORDING %s: %ik", clc.demoName, pos / 1024 );
-
- SCR_DrawStringExt( 320 - strlen( string ) * 4, 20, 8, string, g_color_table[7], qtrue, qfalse );
-}
-
-
-#ifdef USE_VOIP
-/*
-=================
-SCR_DrawVoipMeter
-=================
-*/
-void SCR_DrawVoipMeter( void ) {
- char buffer[16];
- char string[256];
- int limit, i;
-
- if (!cl_voipShowMeter->integer)
- return; // player doesn't want to show meter at all.
- else if (!cl_voipSend->integer)
- return; // not recording at the moment.
- else if (cls.state != CA_ACTIVE)
- return; // not connected to a server.
- else if (!cl_connectedToVoipServer)
- return; // server doesn't support VoIP.
- else if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive"))
- return; // single player game.
- else if (clc.demoplaying)
- return; // playing back a demo.
- else if (!cl_voip->integer)
- return; // client has VoIP support disabled.
-
- limit = (int) (clc.voipPower * 10.0f);
- if (limit > 10)
- limit = 10;
-
- for (i = 0; i < limit; i++)
- buffer[i] = '*';
- while (i < 10)
- buffer[i++] = ' ';
- buffer[i] = '\0';
-
- sprintf( string, "VoIP: [%s]", buffer );
- SCR_DrawStringExt( 320 - strlen( string ) * 4, 10, 8, string, g_color_table[7], qtrue, qfalse );
-}
-#endif
-
-
-
-
-/*
-===============================================================================
-
-DEBUG GRAPH
-
-===============================================================================
-*/
-
-typedef struct
-{
- float value;
- int color;
-} graphsamp_t;
-
-static int current;
-static graphsamp_t values[1024];
-
-/*
-==============
-SCR_DebugGraph
-==============
-*/
-void SCR_DebugGraph (float value, int color)
-{
- values[current&1023].value = value;
- values[current&1023].color = color;
- current++;
-}
-
-/*
-==============
-SCR_DrawDebugGraph
-==============
-*/
-void SCR_DrawDebugGraph (void)
-{
- int a, x, y, w, i, h;
- float v;
- int color;
-
- //
- // draw the graph
- //
- w = cls.glconfig.vidWidth;
- x = 0;
- y = cls.glconfig.vidHeight;
- re.SetColor( g_color_table[0] );
- re.DrawStretchPic(x, y - cl_graphheight->integer,
- w, cl_graphheight->integer, 0, 0, 0, 0, cls.whiteShader );
- re.SetColor( NULL );
-
- for (a=0 ; a<w ; a++)
- {
- i = (current-1-a+1024) & 1023;
- v = values[i].value;
- color = values[i].color;
- v = v * cl_graphscale->integer + cl_graphshift->integer;
-
- if (v < 0)
- v += cl_graphheight->integer * (1+(int)(-v / cl_graphheight->integer));
- h = (int)v % cl_graphheight->integer;
- re.DrawStretchPic( x+w-1-a, y - h, 1, h, 0, 0, 0, 0, cls.whiteShader );
- }
-}
-
-//=============================================================================
-
-/*
-==================
-SCR_Init
-==================
-*/
-void SCR_Init( void ) {
- cl_timegraph = Cvar_Get ("timegraph", "0", CVAR_CHEAT);
- cl_debuggraph = Cvar_Get ("debuggraph", "0", CVAR_CHEAT);
- cl_graphheight = Cvar_Get ("graphheight", "32", CVAR_CHEAT);
- cl_graphscale = Cvar_Get ("graphscale", "1", CVAR_CHEAT);
- cl_graphshift = Cvar_Get ("graphshift", "0", CVAR_CHEAT);
-
- scr_initialized = qtrue;
-}
-
-
-//=======================================================
-
-/*
-==================
-SCR_DrawScreenField
-
-This will be called twice if rendering in stereo mode
-==================
-*/
-void SCR_DrawScreenField( stereoFrame_t stereoFrame ) {
- re.BeginFrame( stereoFrame );
-
- // wide aspect ratio screens need to have the sides cleared
- // unless they are displaying game renderings
- if ( cls.state != CA_ACTIVE && cls.state != CA_CINEMATIC ) {
- if ( cls.glconfig.vidWidth * 480 > cls.glconfig.vidHeight * 640 ) {
- re.SetColor( g_color_table[0] );
- re.DrawStretchPic( 0, 0, cls.glconfig.vidWidth, cls.glconfig.vidHeight, 0, 0, 0, 0, cls.whiteShader );
- re.SetColor( NULL );
- }
- }
-
- // if the menu is going to cover the entire screen, we
- // don't need to render anything under it
- if ( uivm && !VM_Call( uivm, UI_IS_FULLSCREEN )) {
- switch( cls.state ) {
- default:
- Com_Error( ERR_FATAL, "SCR_DrawScreenField: bad cls.state" );
- break;
- case CA_CINEMATIC:
- SCR_DrawCinematic();
- break;
- case CA_DISCONNECTED:
- // force menu up
- S_StopAllSounds();
- VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN );
- break;
- case CA_CONNECTING:
- case CA_CHALLENGING:
- case CA_CONNECTED:
- // connecting clients will only show the connection dialog
- // refresh to update the time
- VM_Call( uivm, UI_REFRESH, cls.realtime );
- VM_Call( uivm, UI_DRAW_CONNECT_SCREEN, qfalse );
- break;
- case CA_LOADING:
- case CA_PRIMED:
- // draw the game information screen and loading progress
- CL_CGameRendering(stereoFrame);
-
- // also draw the connection information, so it doesn't
- // flash away too briefly on local or lan games
- // refresh to update the time
- VM_Call( uivm, UI_REFRESH, cls.realtime );
- VM_Call( uivm, UI_DRAW_CONNECT_SCREEN, qtrue );
- break;
- case CA_ACTIVE:
- // always supply STEREO_CENTER as vieworg offset is now done by the engine.
- CL_CGameRendering(stereoFrame);
- SCR_DrawDemoRecording();
-#ifdef USE_VOIP
- SCR_DrawVoipMeter();
-#endif
- break;
- }
- }
-
- // the menu draws next
- if ( Key_GetCatcher( ) & KEYCATCH_UI && uivm ) {
- VM_Call( uivm, UI_REFRESH, cls.realtime );
- }
-
- // console draws next
- Con_DrawConsole ();
-
- // debug graph can be drawn on top of anything
- if ( cl_debuggraph->integer || cl_timegraph->integer || cl_debugMove->integer ) {
- SCR_DrawDebugGraph ();
- }
-}
-
-/*
-==================
-SCR_UpdateScreen
-
-This is called every frame, and can also be called explicitly to flush
-text to the screen.
-==================
-*/
-void SCR_UpdateScreen( void ) {
- static int recursive;
-
- if ( !scr_initialized ) {
- return; // not initialized yet
- }
-
- if ( ++recursive > 2 ) {
- Com_Error( ERR_FATAL, "SCR_UpdateScreen: recursively called" );
- }
- recursive = 1;
-
- // If there is no VM, there are also no rendering commands issued. Stop the renderer in
- // that case.
- if( uivm || com_dedicated->integer )
- {
- // if running in stereo, we need to draw the frame twice
- if ( cls.glconfig.stereoEnabled || Cvar_VariableIntegerValue("r_anaglyphMode")) {
- SCR_DrawScreenField( STEREO_LEFT );
- SCR_DrawScreenField( STEREO_RIGHT );
- } else {
- SCR_DrawScreenField( STEREO_CENTER );
- }
-
- if ( com_speeds->integer ) {
- re.EndFrame( &time_frontend, &time_backend );
- } else {
- re.EndFrame( NULL, NULL );
- }
- }
-
- recursive = 0;
-}
-
diff --git a/engine/code/client/cl_ui.c b/engine/code/client/cl_ui.c
deleted file mode 100644
index ed32313..0000000
--- a/engine/code/client/cl_ui.c
+++ /dev/null
@@ -1,1154 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "client.h"
-
-#include "../botlib/botlib.h"
-
-extern botlib_export_t *botlib_export;
-
-vm_t *uivm;
-
-/*
-====================
-GetClientState
-====================
-*/
-static void GetClientState( uiClientState_t *state ) {
- state->connectPacketCount = clc.connectPacketCount;
- state->connState = cls.state;
- Q_strncpyz( state->servername, cls.servername, sizeof( state->servername ) );
- Q_strncpyz( state->updateInfoString, cls.updateInfoString, sizeof( state->updateInfoString ) );
- Q_strncpyz( state->messageString, clc.serverMessage, sizeof( state->messageString ) );
- state->clientNum = cl.snap.ps.clientNum;
-}
-
-/*
-====================
-LAN_LoadCachedServers
-====================
-*/
-void LAN_LoadCachedServers( void ) {
- int size;
- fileHandle_t fileIn;
- cls.numglobalservers = cls.numfavoriteservers = 0;
- cls.numGlobalServerAddresses = 0;
- if (FS_SV_FOpenFileRead("servercache.dat", &fileIn)) {
- FS_Read(&cls.numglobalservers, sizeof(int), fileIn);
- FS_Read(&cls.numfavoriteservers, sizeof(int), fileIn);
- FS_Read(&size, sizeof(int), fileIn);
- if (size == sizeof(cls.globalServers) + sizeof(cls.favoriteServers)) {
- FS_Read(&cls.globalServers, sizeof(cls.globalServers), fileIn);
- FS_Read(&cls.favoriteServers, sizeof(cls.favoriteServers), fileIn);
- } else {
- cls.numglobalservers = cls.numfavoriteservers = 0;
- cls.numGlobalServerAddresses = 0;
- }
- FS_FCloseFile(fileIn);
- }
-}
-
-/*
-====================
-LAN_SaveServersToCache
-====================
-*/
-void LAN_SaveServersToCache( void ) {
- int size;
- fileHandle_t fileOut = FS_SV_FOpenFileWrite("servercache.dat");
- FS_Write(&cls.numglobalservers, sizeof(int), fileOut);
- FS_Write(&cls.numfavoriteservers, sizeof(int), fileOut);
- size = sizeof(cls.globalServers) + sizeof(cls.favoriteServers);
- FS_Write(&size, sizeof(int), fileOut);
- FS_Write(&cls.globalServers, sizeof(cls.globalServers), fileOut);
- FS_Write(&cls.favoriteServers, sizeof(cls.favoriteServers), fileOut);
- FS_FCloseFile(fileOut);
-}
-
-
-/*
-====================
-LAN_ResetPings
-====================
-*/
-static void LAN_ResetPings(int source) {
- int count,i;
- serverInfo_t *servers = NULL;
- count = 0;
-
- switch (source) {
- case AS_LOCAL :
- servers = &cls.localServers[0];
- count = MAX_OTHER_SERVERS;
- break;
- case AS_MPLAYER:
- case AS_GLOBAL :
- servers = &cls.globalServers[0];
- count = MAX_GLOBAL_SERVERS;
- break;
- case AS_FAVORITES :
- servers = &cls.favoriteServers[0];
- count = MAX_OTHER_SERVERS;
- break;
- }
- if (servers) {
- for (i = 0; i < count; i++) {
- servers[i].ping = -1;
- }
- }
-}
-
-/*
-====================
-LAN_AddServer
-====================
-*/
-static int LAN_AddServer(int source, const char *name, const char *address) {
- int max, *count, i;
- netadr_t adr;
- serverInfo_t *servers = NULL;
- max = MAX_OTHER_SERVERS;
- count = NULL;
-
- switch (source) {
- case AS_LOCAL :
- count = &cls.numlocalservers;
- servers = &cls.localServers[0];
- break;
- case AS_MPLAYER:
- case AS_GLOBAL :
- max = MAX_GLOBAL_SERVERS;
- count = &cls.numglobalservers;
- servers = &cls.globalServers[0];
- break;
- case AS_FAVORITES :
- count = &cls.numfavoriteservers;
- servers = &cls.favoriteServers[0];
- break;
- }
- if (servers && *count < max) {
- NET_StringToAdr( address, &adr, NA_IP );
- for ( i = 0; i < *count; i++ ) {
- if (NET_CompareAdr(servers[i].adr, adr)) {
- break;
- }
- }
- if (i >= *count) {
- servers[*count].adr = adr;
- Q_strncpyz(servers[*count].hostName, name, sizeof(servers[*count].hostName));
- servers[*count].visible = qtrue;
- (*count)++;
- return 1;
- }
- return 0;
- }
- return -1;
-}
-
-/*
-====================
-LAN_RemoveServer
-====================
-*/
-static void LAN_RemoveServer(int source, const char *addr) {
- int *count, i;
- serverInfo_t *servers = NULL;
- count = NULL;
- switch (source) {
- case AS_LOCAL :
- count = &cls.numlocalservers;
- servers = &cls.localServers[0];
- break;
- case AS_MPLAYER:
- case AS_GLOBAL :
- count = &cls.numglobalservers;
- servers = &cls.globalServers[0];
- break;
- case AS_FAVORITES :
- count = &cls.numfavoriteservers;
- servers = &cls.favoriteServers[0];
- break;
- }
- if (servers) {
- netadr_t comp;
- NET_StringToAdr( addr, &comp, NA_IP );
- for (i = 0; i < *count; i++) {
- if (NET_CompareAdr( comp, servers[i].adr)) {
- int j = i;
- while (j < *count - 1) {
- Com_Memcpy(&servers[j], &servers[j+1], sizeof(servers[j]));
- j++;
- }
- (*count)--;
- break;
- }
- }
- }
-}
-
-
-/*
-====================
-LAN_GetServerCount
-====================
-*/
-static int LAN_GetServerCount( int source ) {
- switch (source) {
- case AS_LOCAL :
- return cls.numlocalservers;
- break;
- case AS_MPLAYER:
- case AS_GLOBAL :
- return cls.numglobalservers;
- break;
- case AS_FAVORITES :
- return cls.numfavoriteservers;
- break;
- }
- return 0;
-}
-
-/*
-====================
-LAN_GetLocalServerAddressString
-====================
-*/
-static void LAN_GetServerAddressString( int source, int n, char *buf, int buflen ) {
- switch (source) {
- case AS_LOCAL :
- if (n >= 0 && n < MAX_OTHER_SERVERS) {
- Q_strncpyz(buf, NET_AdrToStringwPort( cls.localServers[n].adr) , buflen );
- return;
- }
- break;
- case AS_MPLAYER:
- case AS_GLOBAL :
- if (n >= 0 && n < MAX_GLOBAL_SERVERS) {
- Q_strncpyz(buf, NET_AdrToStringwPort( cls.globalServers[n].adr) , buflen );
- return;
- }
- break;
- case AS_FAVORITES :
- if (n >= 0 && n < MAX_OTHER_SERVERS) {
- Q_strncpyz(buf, NET_AdrToStringwPort( cls.favoriteServers[n].adr) , buflen );
- return;
- }
- break;
- }
- buf[0] = '\0';
-}
-
-/*
-====================
-LAN_GetServerInfo
-====================
-*/
-static void LAN_GetServerInfo( int source, int n, char *buf, int buflen ) {
- char info[MAX_STRING_CHARS];
- serverInfo_t *server = NULL;
- info[0] = '\0';
- switch (source) {
- case AS_LOCAL :
- if (n >= 0 && n < MAX_OTHER_SERVERS) {
- server = &cls.localServers[n];
- }
- break;
- case AS_MPLAYER:
- case AS_GLOBAL :
- if (n >= 0 && n < MAX_GLOBAL_SERVERS) {
- server = &cls.globalServers[n];
- }
- break;
- case AS_FAVORITES :
- if (n >= 0 && n < MAX_OTHER_SERVERS) {
- server = &cls.favoriteServers[n];
- }
- break;
- }
- if (server && buf) {
- buf[0] = '\0';
- Info_SetValueForKey( info, "hostname", server->hostName);
- Info_SetValueForKey( info, "mapname", server->mapName);
- Info_SetValueForKey( info, "clients", va("%i",server->clients));
- Info_SetValueForKey( info, "sv_maxclients", va("%i",server->maxClients));
- Info_SetValueForKey( info, "ping", va("%i",server->ping));
- Info_SetValueForKey( info, "minping", va("%i",server->minPing));
- Info_SetValueForKey( info, "maxping", va("%i",server->maxPing));
- Info_SetValueForKey( info, "game", server->game);
- Info_SetValueForKey( info, "gametype", va("%i",server->gameType));
- Info_SetValueForKey( info, "nettype", va("%i",server->netType));
- Info_SetValueForKey( info, "addr", NET_AdrToStringwPort(server->adr));
- Info_SetValueForKey( info, "punkbuster", va("%i", server->punkbuster));
- Q_strncpyz(buf, info, buflen);
- } else {
- if (buf) {
- buf[0] = '\0';
- }
- }
-}
-
-/*
-====================
-LAN_GetServerPing
-====================
-*/
-static int LAN_GetServerPing( int source, int n ) {
- serverInfo_t *server = NULL;
- switch (source) {
- case AS_LOCAL :
- if (n >= 0 && n < MAX_OTHER_SERVERS) {
- server = &cls.localServers[n];
- }
- break;
- case AS_MPLAYER:
- case AS_GLOBAL :
- if (n >= 0 && n < MAX_GLOBAL_SERVERS) {
- server = &cls.globalServers[n];
- }
- break;
- case AS_FAVORITES :
- if (n >= 0 && n < MAX_OTHER_SERVERS) {
- server = &cls.favoriteServers[n];
- }
- break;
- }
- if (server) {
- return server->ping;
- }
- return -1;
-}
-
-/*
-====================
-LAN_GetServerPtr
-====================
-*/
-static serverInfo_t *LAN_GetServerPtr( int source, int n ) {
- switch (source) {
- case AS_LOCAL :
- if (n >= 0 && n < MAX_OTHER_SERVERS) {
- return &cls.localServers[n];
- }
- break;
- case AS_MPLAYER:
- case AS_GLOBAL :
- if (n >= 0 && n < MAX_GLOBAL_SERVERS) {
- return &cls.globalServers[n];
- }
- break;
- case AS_FAVORITES :
- if (n >= 0 && n < MAX_OTHER_SERVERS) {
- return &cls.favoriteServers[n];
- }
- break;
- }
- return NULL;
-}
-
-/*
-====================
-LAN_CompareServers
-====================
-*/
-static int LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 ) {
- int res;
- serverInfo_t *server1, *server2;
-
- server1 = LAN_GetServerPtr(source, s1);
- server2 = LAN_GetServerPtr(source, s2);
- if (!server1 || !server2) {
- return 0;
- }
-
- res = 0;
- switch( sortKey ) {
- case SORT_HOST:
- res = Q_stricmp( server1->hostName, server2->hostName );
- break;
-
- case SORT_MAP:
- res = Q_stricmp( server1->mapName, server2->mapName );
- break;
- case SORT_CLIENTS:
- if (server1->clients < server2->clients) {
- res = -1;
- }
- else if (server1->clients > server2->clients) {
- res = 1;
- }
- else {
- res = 0;
- }
- break;
- case SORT_GAME:
- if (server1->gameType < server2->gameType) {
- res = -1;
- }
- else if (server1->gameType > server2->gameType) {
- res = 1;
- }
- else {
- res = 0;
- }
- break;
- case SORT_PING:
- if (server1->ping < server2->ping) {
- res = -1;
- }
- else if (server1->ping > server2->ping) {
- res = 1;
- }
- else {
- res = 0;
- }
- break;
- }
-
- if (sortDir) {
- if (res < 0)
- return 1;
- if (res > 0)
- return -1;
- return 0;
- }
- return res;
-}
-
-/*
-====================
-LAN_GetPingQueueCount
-====================
-*/
-static int LAN_GetPingQueueCount( void ) {
- return (CL_GetPingQueueCount());
-}
-
-/*
-====================
-LAN_ClearPing
-====================
-*/
-static void LAN_ClearPing( int n ) {
- CL_ClearPing( n );
-}
-
-/*
-====================
-LAN_GetPing
-====================
-*/
-static void LAN_GetPing( int n, char *buf, int buflen, int *pingtime ) {
- CL_GetPing( n, buf, buflen, pingtime );
-}
-
-/*
-====================
-LAN_GetPingInfo
-====================
-*/
-static void LAN_GetPingInfo( int n, char *buf, int buflen ) {
- CL_GetPingInfo( n, buf, buflen );
-}
-
-/*
-====================
-LAN_MarkServerVisible
-====================
-*/
-static void LAN_MarkServerVisible(int source, int n, qboolean visible ) {
- if (n == -1) {
- int count = MAX_OTHER_SERVERS;
- serverInfo_t *server = NULL;
- switch (source) {
- case AS_LOCAL :
- server = &cls.localServers[0];
- break;
- case AS_MPLAYER:
- case AS_GLOBAL :
- server = &cls.globalServers[0];
- count = MAX_GLOBAL_SERVERS;
- break;
- case AS_FAVORITES :
- server = &cls.favoriteServers[0];
- break;
- }
- if (server) {
- for (n = 0; n < count; n++) {
- server[n].visible = visible;
- }
- }
-
- } else {
- switch (source) {
- case AS_LOCAL :
- if (n >= 0 && n < MAX_OTHER_SERVERS) {
- cls.localServers[n].visible = visible;
- }
- break;
- case AS_MPLAYER:
- case AS_GLOBAL :
- if (n >= 0 && n < MAX_GLOBAL_SERVERS) {
- cls.globalServers[n].visible = visible;
- }
- break;
- case AS_FAVORITES :
- if (n >= 0 && n < MAX_OTHER_SERVERS) {
- cls.favoriteServers[n].visible = visible;
- }
- break;
- }
- }
-}
-
-
-/*
-=======================
-LAN_ServerIsVisible
-=======================
-*/
-static int LAN_ServerIsVisible(int source, int n ) {
- switch (source) {
- case AS_LOCAL :
- if (n >= 0 && n < MAX_OTHER_SERVERS) {
- return cls.localServers[n].visible;
- }
- break;
- case AS_MPLAYER:
- case AS_GLOBAL :
- if (n >= 0 && n < MAX_GLOBAL_SERVERS) {
- return cls.globalServers[n].visible;
- }
- break;
- case AS_FAVORITES :
- if (n >= 0 && n < MAX_OTHER_SERVERS) {
- return cls.favoriteServers[n].visible;
- }
- break;
- }
- return qfalse;
-}
-
-/*
-=======================
-LAN_UpdateVisiblePings
-=======================
-*/
-qboolean LAN_UpdateVisiblePings(int source ) {
- return CL_UpdateVisiblePings_f(source);
-}
-
-/*
-====================
-LAN_GetServerStatus
-====================
-*/
-int LAN_GetServerStatus( char *serverAddress, char *serverStatus, int maxLen ) {
- return CL_ServerStatus( serverAddress, serverStatus, maxLen );
-}
-
-/*
-====================
-CL_GetGlConfig
-====================
-*/
-static void CL_GetGlconfig( glconfig_t *config ) {
- *config = cls.glconfig;
-}
-
-/*
-====================
-CL_GetClipboardData
-====================
-*/
-static void CL_GetClipboardData( char *buf, int buflen ) {
- char *cbd;
-
- cbd = Sys_GetClipboardData();
-
- if ( !cbd ) {
- *buf = 0;
- return;
- }
-
- Q_strncpyz( buf, cbd, buflen );
-
- Z_Free( cbd );
-}
-
-/*
-====================
-Key_KeynumToStringBuf
-====================
-*/
-static void Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) {
- Q_strncpyz( buf, Key_KeynumToString( keynum ), buflen );
-}
-
-/*
-====================
-Key_GetBindingBuf
-====================
-*/
-static void Key_GetBindingBuf( int keynum, char *buf, int buflen ) {
- char *value;
-
- value = Key_GetBinding( keynum );
- if ( value ) {
- Q_strncpyz( buf, value, buflen );
- }
- else {
- *buf = 0;
- }
-}
-
-/*
-====================
-CLUI_GetCDKey
-====================
-*/
-#ifndef STANDALONE
-static void CLUI_GetCDKey( char *buf, int buflen ) {
- cvar_t *fs;
- fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
- if (UI_usesUniqueCDKey() && fs && fs->string[0] != 0) {
- Com_Memcpy( buf, &cl_cdkey[16], 16);
- buf[16] = 0;
- } else {
- Com_Memcpy( buf, cl_cdkey, 16);
- buf[16] = 0;
- }
-}
-
-
-/*
-====================
-CLUI_SetCDKey
-====================
-*/
-static void CLUI_SetCDKey( char *buf ) {
- cvar_t *fs;
- fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
- if (UI_usesUniqueCDKey() && fs && fs->string[0] != 0) {
- Com_Memcpy( &cl_cdkey[16], buf, 16 );
- cl_cdkey[32] = 0;
- // set the flag so the fle will be written at the next opportunity
- cvar_modifiedFlags |= CVAR_ARCHIVE;
- } else {
- Com_Memcpy( cl_cdkey, buf, 16 );
- // set the flag so the fle will be written at the next opportunity
- cvar_modifiedFlags |= CVAR_ARCHIVE;
- }
-}
-#endif
-
-/*
-====================
-GetConfigString
-====================
-*/
-static int GetConfigString(int index, char *buf, int size)
-{
- int offset;
-
- if (index < 0 || index >= MAX_CONFIGSTRINGS)
- return qfalse;
-
- offset = cl.gameState.stringOffsets[index];
- if (!offset) {
- if( size ) {
- buf[0] = 0;
- }
- return qfalse;
- }
-
- Q_strncpyz( buf, cl.gameState.stringData+offset, size);
-
- return qtrue;
-}
-
-/*
-====================
-FloatAsInt
-====================
-*/
-static int FloatAsInt( float f ) {
- floatint_t fi;
- fi.f = f;
- return fi.i;
-}
-
-/*
-====================
-CL_UISystemCalls
-
-The ui module is making a system call
-====================
-*/
-intptr_t CL_UISystemCalls( intptr_t *args ) {
- switch( args[0] ) {
- case UI_ERROR:
- Com_Error( ERR_DROP, "%s", (const char*)VMA(1) );
- return 0;
-
- case UI_PRINT:
- Com_Printf( "%s", (const char*)VMA(1) );
- return 0;
-
- case UI_MILLISECONDS:
- return Sys_Milliseconds();
-
- case UI_CVAR_REGISTER:
- Cvar_Register( VMA(1), VMA(2), VMA(3), args[4] );
- return 0;
-
- case UI_CVAR_UPDATE:
- Cvar_Update( VMA(1) );
- return 0;
-
- case UI_CVAR_SET:
- Cvar_Set( VMA(1), VMA(2) );
- return 0;
-
- case UI_CVAR_VARIABLEVALUE:
- return FloatAsInt( Cvar_VariableValue( VMA(1) ) );
-
- case UI_CVAR_VARIABLESTRINGBUFFER:
- Cvar_VariableStringBuffer( VMA(1), VMA(2), args[3] );
- return 0;
-
- case UI_CVAR_SETVALUE:
- Cvar_SetValue( VMA(1), VMF(2) );
- return 0;
-
- case UI_CVAR_RESET:
- Cvar_Reset( VMA(1) );
- return 0;
-
- case UI_CVAR_CREATE:
- Cvar_Get( VMA(1), VMA(2), args[3] );
- return 0;
-
- case UI_CVAR_INFOSTRINGBUFFER:
- Cvar_InfoStringBuffer( args[1], VMA(2), args[3] );
- return 0;
-
- case UI_ARGC:
- return Cmd_Argc();
-
- case UI_ARGV:
- Cmd_ArgvBuffer( args[1], VMA(2), args[3] );
- return 0;
-
- case UI_CMD_EXECUTETEXT:
- if(args[1] == 0
- && (!strncmp(VMA(2), "snd_restart", 11)
- || !strncmp(VMA(2), "vid_restart", 11)
- || !strncmp(VMA(2), "quit", 5)))
- {
- Com_Printf (S_COLOR_YELLOW "turning EXEC_NOW '%.11s' into EXEC_INSERT\n", (const char*)VMA(2));
- args[1] = EXEC_INSERT;
- }
- Cbuf_ExecuteText( args[1], VMA(2) );
- return 0;
-
- case UI_FS_FOPENFILE:
- return FS_FOpenFileByMode( VMA(1), VMA(2), args[3] );
-
- case UI_FS_READ:
- FS_Read2( VMA(1), args[2], args[3] );
- return 0;
-
- case UI_FS_WRITE:
- FS_Write( VMA(1), args[2], args[3] );
- return 0;
-
- case UI_FS_FCLOSEFILE:
- FS_FCloseFile( args[1] );
- return 0;
-
- case UI_FS_GETFILELIST:
- return FS_GetFileList( VMA(1), VMA(2), VMA(3), args[4] );
-
- case UI_FS_SEEK:
- return FS_Seek( args[1], args[2], args[3] );
-
- case UI_R_REGISTERMODEL:
- return re.RegisterModel( VMA(1) );
-
- case UI_R_REGISTERSKIN:
- return re.RegisterSkin( VMA(1) );
-
- case UI_R_REGISTERSHADERNOMIP:
- return re.RegisterShaderNoMip( VMA(1) );
-
- case UI_R_CLEARSCENE:
- re.ClearScene();
- return 0;
-
- case UI_R_ADDREFENTITYTOSCENE:
- re.AddRefEntityToScene( VMA(1) );
- return 0;
-
- case UI_R_ADDPOLYTOSCENE:
- re.AddPolyToScene( args[1], args[2], VMA(3), 1 );
- return 0;
-
- case UI_R_ADDLIGHTTOSCENE:
- re.AddLightToScene( VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) );
- return 0;
-
- case UI_R_RENDERSCENE:
- re.RenderScene( VMA(1) );
- return 0;
-
- case UI_R_SETCOLOR:
- re.SetColor( VMA(1) );
- return 0;
-
- case UI_R_DRAWSTRETCHPIC:
- re.DrawStretchPic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), args[9] );
- return 0;
-
- case UI_R_MODELBOUNDS:
- re.ModelBounds( args[1], VMA(2), VMA(3) );
- return 0;
-
- case UI_UPDATESCREEN:
- SCR_UpdateScreen();
- return 0;
-
- case UI_CM_LERPTAG:
- re.LerpTag( VMA(1), args[2], args[3], args[4], VMF(5), VMA(6) );
- return 0;
-
- case UI_S_REGISTERSOUND:
- return S_RegisterSound( VMA(1), args[2] );
-
- case UI_S_STARTLOCALSOUND:
- S_StartLocalSound( args[1], args[2] );
- return 0;
-
- case UI_KEY_KEYNUMTOSTRINGBUF:
- Key_KeynumToStringBuf( args[1], VMA(2), args[3] );
- return 0;
-
- case UI_KEY_GETBINDINGBUF:
- Key_GetBindingBuf( args[1], VMA(2), args[3] );
- return 0;
-
- case UI_KEY_SETBINDING:
- Key_SetBinding( args[1], VMA(2) );
- return 0;
-
- case UI_KEY_ISDOWN:
- return Key_IsDown( args[1] );
-
- case UI_KEY_GETOVERSTRIKEMODE:
- return Key_GetOverstrikeMode();
-
- case UI_KEY_SETOVERSTRIKEMODE:
- Key_SetOverstrikeMode( args[1] );
- return 0;
-
- case UI_KEY_CLEARSTATES:
- Key_ClearStates();
- return 0;
-
- case UI_KEY_GETCATCHER:
- return Key_GetCatcher();
-
- case UI_KEY_SETCATCHER:
- // Don't allow the ui module to close the console
- Key_SetCatcher( args[1] | ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) );
- return 0;
-
- case UI_GETCLIPBOARDDATA:
- CL_GetClipboardData( VMA(1), args[2] );
- return 0;
-
- case UI_GETCLIENTSTATE:
- GetClientState( VMA(1) );
- return 0;
-
- case UI_GETGLCONFIG:
- CL_GetGlconfig( VMA(1) );
- return 0;
-
- case UI_GETCONFIGSTRING:
- return GetConfigString( args[1], VMA(2), args[3] );
-
- case UI_LAN_LOADCACHEDSERVERS:
- LAN_LoadCachedServers();
- return 0;
-
- case UI_LAN_SAVECACHEDSERVERS:
- LAN_SaveServersToCache();
- return 0;
-
- case UI_LAN_ADDSERVER:
- return LAN_AddServer(args[1], VMA(2), VMA(3));
-
- case UI_LAN_REMOVESERVER:
- LAN_RemoveServer(args[1], VMA(2));
- return 0;
-
- case UI_LAN_GETPINGQUEUECOUNT:
- return LAN_GetPingQueueCount();
-
- case UI_LAN_CLEARPING:
- LAN_ClearPing( args[1] );
- return 0;
-
- case UI_LAN_GETPING:
- LAN_GetPing( args[1], VMA(2), args[3], VMA(4) );
- return 0;
-
- case UI_LAN_GETPINGINFO:
- LAN_GetPingInfo( args[1], VMA(2), args[3] );
- return 0;
-
- case UI_LAN_GETSERVERCOUNT:
- return LAN_GetServerCount(args[1]);
-
- case UI_LAN_GETSERVERADDRESSSTRING:
- LAN_GetServerAddressString( args[1], args[2], VMA(3), args[4] );
- return 0;
-
- case UI_LAN_GETSERVERINFO:
- LAN_GetServerInfo( args[1], args[2], VMA(3), args[4] );
- return 0;
-
- case UI_LAN_GETSERVERPING:
- return LAN_GetServerPing( args[1], args[2] );
-
- case UI_LAN_MARKSERVERVISIBLE:
- LAN_MarkServerVisible( args[1], args[2], args[3] );
- return 0;
-
- case UI_LAN_SERVERISVISIBLE:
- return LAN_ServerIsVisible( args[1], args[2] );
-
- case UI_LAN_UPDATEVISIBLEPINGS:
- return LAN_UpdateVisiblePings( args[1] );
-
- case UI_LAN_RESETPINGS:
- LAN_ResetPings( args[1] );
- return 0;
-
- case UI_LAN_SERVERSTATUS:
- return LAN_GetServerStatus( VMA(1), VMA(2), args[3] );
-
- case UI_LAN_COMPARESERVERS:
- return LAN_CompareServers( args[1], args[2], args[3], args[4], args[5] );
-
- case UI_MEMORY_REMAINING:
- return Hunk_MemoryRemaining();
-
-#ifndef STANDALONE
- case UI_GET_CDKEY:
- CLUI_GetCDKey( VMA(1), args[2] );
- return 0;
-
- case UI_SET_CDKEY:
- CLUI_SetCDKey( VMA(1) );
- return 0;
-#endif
-
- case UI_SET_PBCLSTATUS:
- return 0;
-
- case UI_R_REGISTERFONT:
- re.RegisterFont( VMA(1), args[2], VMA(3));
- return 0;
-
- case UI_MEMSET:
- Com_Memset( VMA(1), args[2], args[3] );
- return 0;
-
- case UI_MEMCPY:
- Com_Memcpy( VMA(1), VMA(2), args[3] );
- return 0;
-
- case UI_STRNCPY:
- strncpy( VMA(1), VMA(2), args[3] );
- return args[1];
-
- case UI_SIN:
- return FloatAsInt( sin( VMF(1) ) );
-
- case UI_COS:
- return FloatAsInt( cos( VMF(1) ) );
-
- case UI_ATAN2:
- return FloatAsInt( atan2( VMF(1), VMF(2) ) );
-
- case UI_SQRT:
- return FloatAsInt( sqrt( VMF(1) ) );
-
- case UI_FLOOR:
- return FloatAsInt( floor( VMF(1) ) );
-
- case UI_CEIL:
- return FloatAsInt( ceil( VMF(1) ) );
-
- case UI_PC_ADD_GLOBAL_DEFINE:
- return botlib_export->PC_AddGlobalDefine( VMA(1) );
- case UI_PC_LOAD_SOURCE:
- return botlib_export->PC_LoadSourceHandle( VMA(1) );
- case UI_PC_FREE_SOURCE:
- return botlib_export->PC_FreeSourceHandle( args[1] );
- case UI_PC_READ_TOKEN:
- return botlib_export->PC_ReadTokenHandle( args[1], VMA(2) );
- case UI_PC_SOURCE_FILE_AND_LINE:
- return botlib_export->PC_SourceFileAndLine( args[1], VMA(2), VMA(3) );
-
- case UI_S_STOPBACKGROUNDTRACK:
- S_StopBackgroundTrack();
- return 0;
- case UI_S_STARTBACKGROUNDTRACK:
- S_StartBackgroundTrack( VMA(1), VMA(2));
- return 0;
-
- case UI_REAL_TIME:
- return Com_RealTime( VMA(1) );
-
- case UI_CIN_PLAYCINEMATIC:
- Com_DPrintf("UI_CIN_PlayCinematic\n");
- return CIN_PlayCinematic(VMA(1), args[2], args[3], args[4], args[5], args[6]);
-
- case UI_CIN_STOPCINEMATIC:
- return CIN_StopCinematic(args[1]);
-
- case UI_CIN_RUNCINEMATIC:
- return CIN_RunCinematic(args[1]);
-
- case UI_CIN_DRAWCINEMATIC:
- CIN_DrawCinematic(args[1]);
- return 0;
-
- case UI_CIN_SETEXTENTS:
- CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]);
- return 0;
-
- case UI_R_REMAP_SHADER:
- re.RemapShader( VMA(1), VMA(2), VMA(3) );
- return 0;
-
-#ifndef STANDALONE
- case UI_VERIFY_CDKEY:
- return CL_CDKeyValidate(VMA(1), VMA(2));
-#endif
-
-
- default:
- Com_Error( ERR_DROP, "Bad UI system trap: %ld", (long int) args[0] );
-
- }
-
- return 0;
-}
-
-/*
-====================
-CL_ShutdownUI
-====================
-*/
-void CL_ShutdownUI( void ) {
- Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_UI );
- cls.uiStarted = qfalse;
- if ( !uivm ) {
- return;
- }
- VM_Call( uivm, UI_SHUTDOWN );
- VM_Free( uivm );
- uivm = NULL;
-}
-
-/*
-====================
-CL_InitUI
-====================
-*/
-#define UI_OLD_API_VERSION 4
-
-void CL_InitUI( void ) {
- int v;
- vmInterpret_t interpret;
-
- // load the dll or bytecode
- if ( cl_connectedToPureServer != 0 ) {
- // if sv_pure is set we only allow qvms to be loaded
- interpret = VMI_COMPILED;
- }
- else {
- interpret = Cvar_VariableValue( "vm_ui" );
- }
- uivm = VM_Create( "ui", CL_UISystemCalls, interpret );
- if ( !uivm ) {
- Com_Error( ERR_FATAL, "VM_Create on UI failed" );
- }
-
- // sanity check
- v = VM_Call( uivm, UI_GETAPIVERSION );
- if (v == UI_OLD_API_VERSION) {
-// Com_Printf(S_COLOR_YELLOW "WARNING: loading old Quake III Arena User Interface version %d\n", v );
- // init for this gamestate
- VM_Call( uivm, UI_INIT, (cls.state >= CA_AUTHORIZING && cls.state < CA_ACTIVE));
- }
- else if (v != UI_API_VERSION) {
- Com_Error( ERR_DROP, "User Interface is version %d, expected %d", v, UI_API_VERSION );
- cls.uiStarted = qfalse;
- }
- else {
- // init for this gamestate
- VM_Call( uivm, UI_INIT, (cls.state >= CA_AUTHORIZING && cls.state < CA_ACTIVE) );
- }
-
- // reset any CVAR_CHEAT cvars registered by ui
- if ( !clc.demoplaying && !cl_connectedToCheatServer )
- Cvar_SetCheatState();
-}
-
-#ifndef STANDALONE
-qboolean UI_usesUniqueCDKey( void ) {
- if (uivm) {
- return (VM_Call( uivm, UI_HASUNIQUECDKEY) == qtrue);
- } else {
- return qfalse;
- }
-}
-#endif
-
-/*
-====================
-UI_GameCommand
-
-See if the current console command is claimed by the ui
-====================
-*/
-qboolean UI_GameCommand( void ) {
- if ( !uivm ) {
- return qfalse;
- }
-
- return VM_Call( uivm, UI_CONSOLE_COMMAND, cls.realtime );
-}
diff --git a/engine/code/client/client.h b/engine/code/client/client.h
deleted file mode 100644
index 7891a83..0000000
--- a/engine/code/client/client.h
+++ /dev/null
@@ -1,627 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// client.h -- primary header for client
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-#include "../renderer/tr_public.h"
-#include "../ui/ui_public.h"
-#include "keys.h"
-#include "snd_public.h"
-#include "../cgame/cg_public.h"
-#include "../game/bg_public.h"
-
-#ifdef USE_CURL
-#include "cl_curl.h"
-#endif /* USE_CURL */
-
-#ifdef USE_VOIP
-#include "speex/speex.h"
-#include "speex/speex_preprocess.h"
-#endif
-
-// file full of random crap that gets used to create cl_guid
-#define QKEY_FILE "qkey"
-#define QKEY_SIZE 2048
-
-#define RETRANSMIT_TIMEOUT 3000 // time between connection packet retransmits
-
-// snapshots are a view of the server at a given time
-typedef struct {
- qboolean valid; // cleared if delta parsing was invalid
- int snapFlags; // rate delayed and dropped commands
-
- int serverTime; // server time the message is valid for (in msec)
-
- int messageNum; // copied from netchan->incoming_sequence
- int deltaNum; // messageNum the delta is from
- int ping; // time from when cmdNum-1 was sent to time packet was reeceived
- byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
-
- int cmdNum; // the next cmdNum the server is expecting
- playerState_t ps; // complete information about the current player at this time
-
- int numEntities; // all of the entities that need to be presented
- int parseEntitiesNum; // at the time of this snapshot
-
- int serverCommandNum; // execute all commands up to this before
- // making the snapshot current
-} clSnapshot_t;
-
-
-
-/*
-=============================================================================
-
-the clientActive_t structure is wiped completely at every
-new gamestate_t, potentially several times during an established connection
-
-=============================================================================
-*/
-
-typedef struct {
- int p_cmdNumber; // cl.cmdNumber when packet was sent
- int p_serverTime; // usercmd->serverTime when packet was sent
- int p_realtime; // cls.realtime when packet was sent
-} outPacket_t;
-
-// the parseEntities array must be large enough to hold PACKET_BACKUP frames of
-// entities, so that when a delta compressed message arives from the server
-// it can be un-deltad from the original
-#define MAX_PARSE_ENTITIES 2048
-
-extern int g_console_field_width;
-
-typedef struct {
- int timeoutcount; // it requres several frames in a timeout condition
- // to disconnect, preventing debugging breaks from
- // causing immediate disconnects on continue
- clSnapshot_t snap; // latest received from server
-
- int serverTime; // may be paused during play
- int oldServerTime; // to prevent time from flowing bakcwards
- int oldFrameServerTime; // to check tournament restarts
- int serverTimeDelta; // cl.serverTime = cls.realtime + cl.serverTimeDelta
- // this value changes as net lag varies
- qboolean extrapolatedSnapshot; // set if any cgame frame has been forced to extrapolate
- // cleared when CL_AdjustTimeDelta looks at it
- qboolean newSnapshots; // set on parse of any valid packet
-
- gameState_t gameState; // configstrings
- char mapname[MAX_QPATH]; // extracted from CS_SERVERINFO
-
- int parseEntitiesNum; // index (not anded off) into cl_parse_entities[]
-
- int mouseDx[2], mouseDy[2]; // added to by mouse events
- int mouseIndex;
- int joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events
-
- // cgame communicates a few values to the client system
- int cgameUserCmdValue; // current weapon to add to usercmd_t
- float cgameSensitivity;
-
- // cmds[cmdNumber] is the predicted command, [cmdNumber-1] is the last
- // properly generated command
- usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds
- int cmdNumber; // incremented each frame, because multiple
- // frames may need to be packed into a single packet
-
- outPacket_t outPackets[PACKET_BACKUP]; // information about each packet we have sent out
-
- // the client maintains its own idea of view angles, which are
- // sent to the server each frame. It is cleared to 0 upon entering each level.
- // the server sends a delta each frame which is added to the locally
- // tracked view angles to account for standing on rotating objects,
- // and teleport direction changes
- vec3_t viewangles;
-
- int serverId; // included in each client message so the server
- // can tell if it is for a prior map_restart
- // big stuff at end of structure so most offsets are 15 bits or less
- clSnapshot_t snapshots[PACKET_BACKUP];
-
- entityState_t entityBaselines[MAX_GENTITIES]; // for delta compression when not in previous frame
-
- entityState_t parseEntities[MAX_PARSE_ENTITIES];
-} clientActive_t;
-
-extern clientActive_t cl;
-
-/*
-=============================================================================
-
-the clientConnection_t structure is wiped when disconnecting from a server,
-either to go to a full screen console, play a demo, or connect to a different server
-
-A connection can be to either a server through the network layer or a
-demo through a file.
-
-=============================================================================
-*/
-
-#define MAX_TIMEDEMO_DURATIONS 4096
-
-typedef struct {
-
- int clientNum;
- int lastPacketSentTime; // for retransmits during connection
- int lastPacketTime; // for timeouts
-
- netadr_t serverAddress;
- int connectTime; // for connection retransmits
- int connectPacketCount; // for display on connection dialog
- char serverMessage[MAX_STRING_TOKENS]; // for display on connection dialog
-
- int challenge; // from the server to use for connecting
- int checksumFeed; // from the server for checksum calculations
-
- // these are our reliable messages that go to the server
- int reliableSequence;
- int reliableAcknowledge; // the last one the server has executed
- char reliableCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS];
-
- // server message (unreliable) and command (reliable) sequence
- // numbers are NOT cleared at level changes, but continue to
- // increase as long as the connection is valid
-
- // message sequence is used by both the network layer and the
- // delta compression layer
- int serverMessageSequence;
-
- // reliable messages received from server
- int serverCommandSequence;
- int lastExecutedServerCommand; // last server command grabbed or executed with CL_GetServerCommand
- char serverCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS];
-
- // file transfer from server
- fileHandle_t download;
- char downloadTempName[MAX_OSPATH];
- char downloadName[MAX_OSPATH];
-#ifdef USE_CURL
- qboolean cURLEnabled;
- qboolean cURLUsed;
- qboolean cURLDisconnected;
- char downloadURL[MAX_OSPATH];
- CURL *downloadCURL;
- CURLM *downloadCURLM;
-#endif /* USE_CURL */
- int sv_allowDownload;
- char sv_dlURL[MAX_CVAR_VALUE_STRING];
- int downloadNumber;
- int downloadBlock; // block we are waiting for
- int downloadCount; // how many bytes we got
- int downloadSize; // how many bytes we got
- char downloadList[MAX_INFO_STRING]; // list of paks we need to download
- qboolean downloadRestart; // if true, we need to do another FS_Restart because we downloaded a pak
-
- // demo information
- char demoName[MAX_QPATH];
- qboolean spDemoRecording;
- qboolean demorecording;
- qboolean demoplaying;
- qboolean demowaiting; // don't record until a non-delta message is received
- qboolean firstDemoFrameSkipped;
- fileHandle_t demofile;
-
- int timeDemoFrames; // counter of rendered frames
- int timeDemoStart; // cls.realtime before first frame
- int timeDemoBaseTime; // each frame will be at this time + frameNum * 50
- int timeDemoLastFrame;// time the last frame was rendered
- int timeDemoMinDuration; // minimum frame duration
- int timeDemoMaxDuration; // maximum frame duration
- unsigned char timeDemoDurations[ MAX_TIMEDEMO_DURATIONS ]; // log of frame durations
-
-#ifdef USE_VOIP
- qboolean speexInitialized;
- int speexFrameSize;
- int speexSampleRate;
-
- // incoming data...
- // !!! FIXME: convert from parallel arrays to array of a struct.
- SpeexBits speexDecoderBits[MAX_CLIENTS];
- void *speexDecoder[MAX_CLIENTS];
- byte voipIncomingGeneration[MAX_CLIENTS];
- int voipIncomingSequence[MAX_CLIENTS];
- float voipGain[MAX_CLIENTS];
- qboolean voipIgnore[MAX_CLIENTS];
- qboolean voipMuteAll;
-
- // outgoing data...
- int voipTarget1; // these three ints make up a bit mask of 92 bits.
- int voipTarget2; // the bits say who a VoIP pack is addressed to:
- int voipTarget3; // (1 << clientnum). See cl_voipSendTarget cvar.
- SpeexPreprocessState *speexPreprocessor;
- SpeexBits speexEncoderBits;
- void *speexEncoder;
- int voipOutgoingDataSize;
- int voipOutgoingDataFrames;
- int voipOutgoingSequence;
- byte voipOutgoingGeneration;
- byte voipOutgoingData[1024];
- float voipPower;
-#endif
-
- // big stuff at end of structure so most offsets are 15 bits or less
- netchan_t netchan;
-} clientConnection_t;
-
-extern clientConnection_t clc;
-
-/*
-==================================================================
-
-the clientStatic_t structure is never wiped, and is used even when
-no client connection is active at all
-
-==================================================================
-*/
-
-typedef struct {
- netadr_t adr;
- int start;
- int time;
- char info[MAX_INFO_STRING];
-} ping_t;
-
-typedef struct {
- netadr_t adr;
- char hostName[MAX_NAME_LENGTH];
- char mapName[MAX_NAME_LENGTH];
- char game[MAX_NAME_LENGTH];
- int netType;
- int gameType;
- int clients;
- int maxClients;
- int minPing;
- int maxPing;
- int ping;
- qboolean visible;
- int punkbuster;
-} serverInfo_t;
-
-typedef struct {
- connstate_t state; // connection status
-
- qboolean cddialog; // bring up the cd needed dialog next frame
-
- char servername[MAX_OSPATH]; // name of server from original connect (used by reconnect)
-
- // when the server clears the hunk, all of these must be restarted
- qboolean rendererStarted;
- qboolean soundStarted;
- qboolean soundRegistered;
- qboolean uiStarted;
- qboolean cgameStarted;
-
- int framecount;
- int frametime; // msec since last frame
-
- int realtime; // ignores pause
- int realFrametime; // ignoring pause, so console always works
-
- int numlocalservers;
- serverInfo_t localServers[MAX_OTHER_SERVERS];
-
- int numglobalservers;
- serverInfo_t globalServers[MAX_GLOBAL_SERVERS];
- // additional global servers
- int numGlobalServerAddresses;
- netadr_t globalServerAddresses[MAX_GLOBAL_SERVERS];
-
- int numfavoriteservers;
- serverInfo_t favoriteServers[MAX_OTHER_SERVERS];
-
- int pingUpdateSource; // source currently pinging or updating
-
- // update server info
- netadr_t updateServer;
- char updateChallenge[MAX_TOKEN_CHARS];
- char updateInfoString[MAX_INFO_STRING];
-
- netadr_t authorizeServer;
-
- // rendering info
- glconfig_t glconfig;
- qhandle_t charSetShader;
- qhandle_t whiteShader;
- qhandle_t consoleShader;
-} clientStatic_t;
-
-extern clientStatic_t cls;
-
-//=============================================================================
-
-extern vm_t *cgvm; // interface to cgame dll or vm
-extern vm_t *uivm; // interface to ui dll or vm
-extern refexport_t re; // interface to refresh .dll
-
-
-//
-// cvars
-//
-extern cvar_t *cl_nodelta;
-extern cvar_t *cl_debugMove;
-extern cvar_t *cl_noprint;
-extern cvar_t *cl_timegraph;
-extern cvar_t *cl_maxpackets;
-extern cvar_t *cl_packetdup;
-extern cvar_t *cl_shownet;
-extern cvar_t *cl_showSend;
-extern cvar_t *cl_timeNudge;
-extern cvar_t *cl_showTimeDelta;
-extern cvar_t *cl_freezeDemo;
-
-extern cvar_t *cl_yawspeed;
-extern cvar_t *cl_pitchspeed;
-extern cvar_t *cl_run;
-extern cvar_t *cl_anglespeedkey;
-
-extern cvar_t *cl_sensitivity;
-extern cvar_t *cl_freelook;
-
-extern cvar_t *cl_mouseAccel;
-extern cvar_t *cl_mouseAccelOffset;
-extern cvar_t *cl_mouseAccelStyle;
-extern cvar_t *cl_showMouseRate;
-
-extern cvar_t *m_pitch;
-extern cvar_t *m_yaw;
-extern cvar_t *m_forward;
-extern cvar_t *m_side;
-extern cvar_t *m_filter;
-
-extern cvar_t *cl_timedemo;
-extern cvar_t *cl_aviFrameRate;
-extern cvar_t *cl_aviMotionJpeg;
-
-extern cvar_t *cl_activeAction;
-
-extern cvar_t *cl_allowDownload;
-extern cvar_t *cl_downloadMethod;
-extern cvar_t *cl_conXOffset;
-extern cvar_t *cl_inGameVideo;
-
-extern cvar_t *cl_lanForcePackets;
-extern cvar_t *cl_autoRecordDemo;
-
-extern cvar_t *cl_consoleKeys;
-
-#ifdef USE_MUMBLE
-extern cvar_t *cl_useMumble;
-extern cvar_t *cl_mumbleScale;
-#endif
-
-#ifdef USE_VOIP
-// cl_voipSendTarget is a string: "all" to broadcast to everyone, "none" to
-// send to no one, or a comma-separated list of client numbers:
-// "0,7,2,23" ... an empty string is treated like "all".
-extern cvar_t *cl_voipUseVAD;
-extern cvar_t *cl_voipVADThreshold;
-extern cvar_t *cl_voipSend;
-extern cvar_t *cl_voipSendTarget;
-extern cvar_t *cl_voipGainDuringCapture;
-extern cvar_t *cl_voipCaptureMult;
-extern cvar_t *cl_voipShowMeter;
-extern cvar_t *cl_voip;
-#endif
-
-//=================================================
-
-//
-// cl_main
-//
-
-void CL_Init (void);
-void CL_FlushMemory(void);
-void CL_ShutdownAll(void);
-void CL_AddReliableCommand(const char *cmd, qboolean isDisconnectCmd);
-
-void CL_StartHunkUsers( qboolean rendererOnly );
-
-void CL_Disconnect_f (void);
-void CL_GetChallengePacket (void);
-void CL_Vid_Restart_f( void );
-void CL_Snd_Restart_f (void);
-void CL_StartDemoLoop( void );
-void CL_NextDemo( void );
-void CL_ReadDemoMessage( void );
-void CL_StopRecord_f(void);
-
-void CL_InitDownloads(void);
-void CL_NextDownload(void);
-
-void CL_GetPing( int n, char *buf, int buflen, int *pingtime );
-void CL_GetPingInfo( int n, char *buf, int buflen );
-void CL_ClearPing( int n );
-int CL_GetPingQueueCount( void );
-
-void CL_ShutdownRef( void );
-void CL_InitRef( void );
-#ifndef STANDALONE
-qboolean CL_CDKeyValidate( const char *key, const char *checksum );
-#endif
-int CL_ServerStatus( char *serverAddress, char *serverStatusString, int maxLen );
-
-qboolean CL_CheckPaused(void);
-
-//
-// cl_input
-//
-typedef struct {
- int down[2]; // key nums holding it down
- unsigned downtime; // msec timestamp
- unsigned msec; // msec down this frame if both a down and up happened
- qboolean active; // current state
- qboolean wasPressed; // set when down, not cleared when up
-} kbutton_t;
-
-extern kbutton_t in_mlook, in_klook;
-extern kbutton_t in_strafe;
-extern kbutton_t in_speed;
-
-#ifdef USE_VOIP
-extern kbutton_t in_voiprecord;
-#endif
-
-void CL_InitInput (void);
-void CL_SendCmd (void);
-void CL_ClearState (void);
-void CL_ReadPackets (void);
-
-void CL_WritePacket( void );
-void IN_CenterView (void);
-
-void CL_VerifyCode( void );
-
-float CL_KeyState (kbutton_t *key);
-int Key_StringToKeynum( char *str );
-char *Key_KeynumToString (int keynum);
-
-//
-// cl_parse.c
-//
-extern int cl_connectedToPureServer;
-extern int cl_connectedToCheatServer;
-
-#ifdef USE_VOIP
-extern int cl_connectedToVoipServer;
-void CL_Voip_f( void );
-#endif
-
-void CL_SystemInfoChanged( void );
-void CL_ParseServerMessage( msg_t *msg );
-
-//====================================================================
-
-void CL_ServerInfoPacket( netadr_t from, msg_t *msg );
-void CL_LocalServers_f( void );
-void CL_GlobalServers_f( void );
-void CL_FavoriteServers_f( void );
-void CL_Ping_f( void );
-qboolean CL_UpdateVisiblePings_f( int source );
-
-
-//
-// console
-//
-void Con_DrawCharacter (int cx, int line, int num);
-
-void Con_CheckResize (void);
-void Con_Init (void);
-void Con_Clear_f (void);
-void Con_ToggleConsole_f (void);
-void Con_DrawNotify (void);
-void Con_ClearNotify (void);
-void Con_RunConsole (void);
-void Con_DrawConsole (void);
-void Con_PageUp( void );
-void Con_PageDown( void );
-void Con_Top( void );
-void Con_Bottom( void );
-void Con_Close( void );
-
-void CL_LoadConsoleHistory( void );
-void CL_SaveConsoleHistory( void );
-
-//
-// cl_scrn.c
-//
-void SCR_Init (void);
-void SCR_UpdateScreen (void);
-
-void SCR_DebugGraph (float value, int color);
-
-int SCR_GetBigStringWidth( const char *str ); // returns in virtual 640x480 coordinates
-
-void SCR_AdjustFrom640( float *x, float *y, float *w, float *h );
-void SCR_FillRect( float x, float y, float width, float height,
- const float *color );
-void SCR_DrawPic( float x, float y, float width, float height, qhandle_t hShader );
-void SCR_DrawNamedPic( float x, float y, float width, float height, const char *picname );
-
-void SCR_DrawBigString( int x, int y, const char *s, float alpha, qboolean noColorEscape ); // draws a string with embedded color control characters with fade
-void SCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color, qboolean noColorEscape ); // ignores embedded color control characters
-void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor, qboolean noColorEscape );
-void SCR_DrawSmallChar( int x, int y, int ch );
-
-
-//
-// cl_cin.c
-//
-
-void CL_PlayCinematic_f( void );
-void SCR_DrawCinematic (void);
-void SCR_RunCinematic (void);
-void SCR_StopCinematic (void);
-int CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits);
-e_status CIN_StopCinematic(int handle);
-e_status CIN_RunCinematic (int handle);
-void CIN_DrawCinematic (int handle);
-void CIN_SetExtents (int handle, int x, int y, int w, int h);
-void CIN_SetLooping (int handle, qboolean loop);
-void CIN_UploadCinematic(int handle);
-void CIN_CloseAllVideos(void);
-
-//
-// cl_cgame.c
-//
-void CL_InitCGame( void );
-void CL_ShutdownCGame( void );
-qboolean CL_GameCommand( void );
-void CL_CGameRendering( stereoFrame_t stereo );
-void CL_SetCGameTime( void );
-void CL_FirstSnapshot( void );
-void CL_ShaderStateChanged(void);
-
-//
-// cl_ui.c
-//
-void CL_InitUI( void );
-void CL_ShutdownUI( void );
-int Key_GetCatcher( void );
-void Key_SetCatcher( int catcher );
-void LAN_LoadCachedServers( void );
-void LAN_SaveServersToCache( void );
-
-
-//
-// cl_net_chan.c
-//
-void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg); //int length, const byte *data );
-void CL_Netchan_TransmitNextFragment( netchan_t *chan );
-qboolean CL_Netchan_Process( netchan_t *chan, msg_t *msg );
-
-//
-// cl_avi.c
-//
-qboolean CL_OpenAVIForWriting( const char *filename );
-void CL_TakeVideoFrame( void );
-void CL_WriteAVIVideoFrame( const byte *imageBuffer, int size );
-void CL_WriteAVIAudioFrame( const byte *pcmBuffer, int size );
-qboolean CL_CloseAVI( void );
-qboolean CL_VideoRecording( void );
-
-//
-// cl_main.c
-//
-void CL_WriteDemoMessage ( msg_t *msg, int headerBytes );
-
diff --git a/engine/code/client/keycodes.h b/engine/code/client/keycodes.h
deleted file mode 100644
index 706ca1b..0000000
--- a/engine/code/client/keycodes.h
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#ifndef __KEYCODES_H__
-#define __KEYCODES_H__
-
-//
-// these are the key numbers that should be passed to KeyEvent
-//
-
-// normal keys should be passed as lowercased ascii
-
-typedef enum {
- K_TAB = 9,
- K_ENTER = 13,
- K_ESCAPE = 27,
- K_SPACE = 32,
-
- K_BACKSPACE = 127,
-
- K_COMMAND = 128,
- K_CAPSLOCK,
- K_POWER,
- K_PAUSE,
-
- K_UPARROW,
- K_DOWNARROW,
- K_LEFTARROW,
- K_RIGHTARROW,
-
- K_ALT,
- K_CTRL,
- K_SHIFT,
- K_INS,
- K_DEL,
- K_PGDN,
- K_PGUP,
- K_HOME,
- K_END,
-
- K_F1,
- K_F2,
- K_F3,
- K_F4,
- K_F5,
- K_F6,
- K_F7,
- K_F8,
- K_F9,
- K_F10,
- K_F11,
- K_F12,
- K_F13,
- K_F14,
- K_F15,
-
- K_KP_HOME,
- K_KP_UPARROW,
- K_KP_PGUP,
- K_KP_LEFTARROW,
- K_KP_5,
- K_KP_RIGHTARROW,
- K_KP_END,
- K_KP_DOWNARROW,
- K_KP_PGDN,
- K_KP_ENTER,
- K_KP_INS,
- K_KP_DEL,
- K_KP_SLASH,
- K_KP_MINUS,
- K_KP_PLUS,
- K_KP_NUMLOCK,
- K_KP_STAR,
- K_KP_EQUALS,
-
- K_MOUSE1,
- K_MOUSE2,
- K_MOUSE3,
- K_MOUSE4,
- K_MOUSE5,
-
- K_MWHEELDOWN,
- K_MWHEELUP,
-
- K_JOY1,
- K_JOY2,
- K_JOY3,
- K_JOY4,
- K_JOY5,
- K_JOY6,
- K_JOY7,
- K_JOY8,
- K_JOY9,
- K_JOY10,
- K_JOY11,
- K_JOY12,
- K_JOY13,
- K_JOY14,
- K_JOY15,
- K_JOY16,
- K_JOY17,
- K_JOY18,
- K_JOY19,
- K_JOY20,
- K_JOY21,
- K_JOY22,
- K_JOY23,
- K_JOY24,
- K_JOY25,
- K_JOY26,
- K_JOY27,
- K_JOY28,
- K_JOY29,
- K_JOY30,
- K_JOY31,
- K_JOY32,
-
- K_AUX1,
- K_AUX2,
- K_AUX3,
- K_AUX4,
- K_AUX5,
- K_AUX6,
- K_AUX7,
- K_AUX8,
- K_AUX9,
- K_AUX10,
- K_AUX11,
- K_AUX12,
- K_AUX13,
- K_AUX14,
- K_AUX15,
- K_AUX16,
-
- K_WORLD_0,
- K_WORLD_1,
- K_WORLD_2,
- K_WORLD_3,
- K_WORLD_4,
- K_WORLD_5,
- K_WORLD_6,
- K_WORLD_7,
- K_WORLD_8,
- K_WORLD_9,
- K_WORLD_10,
- K_WORLD_11,
- K_WORLD_12,
- K_WORLD_13,
- K_WORLD_14,
- K_WORLD_15,
- K_WORLD_16,
- K_WORLD_17,
- K_WORLD_18,
- K_WORLD_19,
- K_WORLD_20,
- K_WORLD_21,
- K_WORLD_22,
- K_WORLD_23,
- K_WORLD_24,
- K_WORLD_25,
- K_WORLD_26,
- K_WORLD_27,
- K_WORLD_28,
- K_WORLD_29,
- K_WORLD_30,
- K_WORLD_31,
- K_WORLD_32,
- K_WORLD_33,
- K_WORLD_34,
- K_WORLD_35,
- K_WORLD_36,
- K_WORLD_37,
- K_WORLD_38,
- K_WORLD_39,
- K_WORLD_40,
- K_WORLD_41,
- K_WORLD_42,
- K_WORLD_43,
- K_WORLD_44,
- K_WORLD_45,
- K_WORLD_46,
- K_WORLD_47,
- K_WORLD_48,
- K_WORLD_49,
- K_WORLD_50,
- K_WORLD_51,
- K_WORLD_52,
- K_WORLD_53,
- K_WORLD_54,
- K_WORLD_55,
- K_WORLD_56,
- K_WORLD_57,
- K_WORLD_58,
- K_WORLD_59,
- K_WORLD_60,
- K_WORLD_61,
- K_WORLD_62,
- K_WORLD_63,
- K_WORLD_64,
- K_WORLD_65,
- K_WORLD_66,
- K_WORLD_67,
- K_WORLD_68,
- K_WORLD_69,
- K_WORLD_70,
- K_WORLD_71,
- K_WORLD_72,
- K_WORLD_73,
- K_WORLD_74,
- K_WORLD_75,
- K_WORLD_76,
- K_WORLD_77,
- K_WORLD_78,
- K_WORLD_79,
- K_WORLD_80,
- K_WORLD_81,
- K_WORLD_82,
- K_WORLD_83,
- K_WORLD_84,
- K_WORLD_85,
- K_WORLD_86,
- K_WORLD_87,
- K_WORLD_88,
- K_WORLD_89,
- K_WORLD_90,
- K_WORLD_91,
- K_WORLD_92,
- K_WORLD_93,
- K_WORLD_94,
- K_WORLD_95,
-
- K_SUPER,
- K_COMPOSE,
- K_MODE,
- K_HELP,
- K_PRINT,
- K_SYSREQ,
- K_SCROLLOCK,
- K_BREAK,
- K_MENU,
- K_EURO,
- K_UNDO,
-
- // Pseudo-key that brings the console down
- K_CONSOLE,
-
- MAX_KEYS
-} keyNum_t;
-
-// MAX_KEYS replaces K_LAST_KEY, however some mods may have used K_LAST_KEY
-// in detecting binds, so we leave it defined to the old hardcoded value
-// of maxiumum keys to prevent mods from crashing older versions of the engine
-#define K_LAST_KEY 256
-
-// The menu code needs to get both key and char events, but
-// to avoid duplicating the paths, the char events are just
-// distinguished by or'ing in K_CHAR_FLAG (ugly)
-#define K_CHAR_FLAG 1024
-
-#endif
diff --git a/engine/code/client/keys.h b/engine/code/client/keys.h
deleted file mode 100644
index 0168468..0000000
--- a/engine/code/client/keys.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "keycodes.h"
-
-typedef struct {
- qboolean down;
- int repeats; // if > 1, it is autorepeating
- char *binding;
-} qkey_t;
-
-extern qboolean key_overstrikeMode;
-extern qkey_t keys[MAX_KEYS];
-
-// NOTE TTimo the declaration of field_t and Field_Clear is now in qcommon/qcommon.h
-void Field_KeyDownEvent( field_t *edit, int key );
-void Field_CharEvent( field_t *edit, int ch );
-void Field_Draw( field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape );
-void Field_BigDraw( field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape );
-
-#define COMMAND_HISTORY 32
-extern field_t historyEditLines[COMMAND_HISTORY];
-
-extern field_t g_consoleField;
-extern field_t chatField;
-extern int anykeydown;
-extern qboolean chat_team;
-extern int chat_playerNum;
-
-void Key_WriteBindings( fileHandle_t f );
-void Key_SetBinding( int keynum, const char *binding );
-char *Key_GetBinding( int keynum );
-qboolean Key_IsDown( int keynum );
-qboolean Key_GetOverstrikeMode( void );
-void Key_SetOverstrikeMode( qboolean state );
-void Key_ClearStates( void );
-int Key_GetKey(const char *binding);
diff --git a/engine/code/client/libmumblelink.c b/engine/code/client/libmumblelink.c
deleted file mode 100644
index c45e6a1..0000000
--- a/engine/code/client/libmumblelink.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/* libmumblelink.c -- mumble link interface
-
- Copyright (C) 2008 Ludwig Nussel <ludwig.nussel at suse.de>
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-
-*/
-
-#ifdef WIN32
-#include <windows.h>
-#define uint32_t UINT32
-#else
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#endif
-
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "libmumblelink.h"
-
-typedef struct
-{
- uint32_t uiVersion;
- uint32_t uiTick;
- float fPosition[3];
- float fFront[3];
- float fTop[3];
- wchar_t name[256];
-} LinkedMem;
-
-static LinkedMem *lm = NULL;
-
-#ifdef WIN32
-static HANDLE hMapObject = NULL;
-#else
-static int32_t GetTickCount(void)
-{
- struct timeval tv;
- gettimeofday(&tv,NULL);
-
- return tv.tv_usec / 1000 + tv.tv_sec * 1000;
-}
-#endif
-
-int mumble_link(const char* name)
-{
-#ifdef WIN32
- if(lm)
- return 0;
-
- hMapObject = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"MumbleLink");
- if (hMapObject == NULL)
- return -1;
-
- lm = (LinkedMem *) MapViewOfFile(hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(LinkedMem));
- if (lm == NULL) {
- CloseHandle(hMapObject);
- hMapObject = NULL;
- return -1;
- }
-#else
- char file[256];
- int shmfd;
- if(lm)
- return 0;
-
- snprintf(file, sizeof (file), "/MumbleLink.%d", getuid());
- shmfd = shm_open(file, O_RDWR, S_IRUSR | S_IWUSR);
- if(shmfd < 0) {
- return -1;
- }
-
- lm = (LinkedMem *) (mmap(NULL, sizeof(LinkedMem), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd,0));
- if (lm == (void *) (-1)) {
- lm = NULL;
- }
- close(shmfd);
-#endif
- mbstowcs(lm->name, name, sizeof(lm->name));
-
- return 0;
-}
-
-void mumble_update_coordinates(float fPosition[3], float fFront[3], float fTop[3])
-{
- if (!lm)
- return;
-
- memcpy(lm->fPosition, fPosition, sizeof(fPosition));
- memcpy(lm->fFront, fFront, sizeof(fFront));
- memcpy(lm->fTop, fTop, sizeof(fTop));
- lm->uiVersion = 1;
- lm->uiTick = GetTickCount();
-}
-
-void mumble_unlink()
-{
- if(!lm)
- return;
-#ifdef WIN32
- UnmapViewOfFile(lm);
- CloseHandle(hMapObject);
- hMapObject = NULL;
-#else
- munmap(lm, sizeof(LinkedMem));
-#endif
- lm = NULL;
-}
-
-int mumble_islinked(void)
-{
- return lm != NULL;
-}
diff --git a/engine/code/client/libmumblelink.h b/engine/code/client/libmumblelink.h
deleted file mode 100644
index 0623931..0000000
--- a/engine/code/client/libmumblelink.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* libmumblelink.h -- mumble link interface
-
- Copyright (C) 2008 Ludwig Nussel <ludwig.nussel at suse.de>
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-
-*/
-
-int mumble_link(const char* name);
-int mumble_islinked(void);
-void mumble_update_coordinates(float fPosition[3], float fFront[3], float fTop[3]);
-void mumble_unlink(void);
diff --git a/engine/code/client/qal.c b/engine/code/client/qal.c
deleted file mode 100644
index 5ddd67f..0000000
--- a/engine/code/client/qal.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-// Dynamically loads OpenAL
-
-#ifdef USE_OPENAL
-
-#include "qal.h"
-
-#ifdef USE_OPENAL_DLOPEN
-
-#include "../sys/sys_loadlib.h"
-
-LPALENABLE qalEnable;
-LPALDISABLE qalDisable;
-LPALISENABLED qalIsEnabled;
-LPALGETSTRING qalGetString;
-LPALGETBOOLEANV qalGetBooleanv;
-LPALGETINTEGERV qalGetIntegerv;
-LPALGETFLOATV qalGetFloatv;
-LPALGETDOUBLEV qalGetDoublev;
-LPALGETBOOLEAN qalGetBoolean;
-LPALGETINTEGER qalGetInteger;
-LPALGETFLOAT qalGetFloat;
-LPALGETDOUBLE qalGetDouble;
-LPALGETERROR qalGetError;
-LPALISEXTENSIONPRESENT qalIsExtensionPresent;
-LPALGETPROCADDRESS qalGetProcAddress;
-LPALGETENUMVALUE qalGetEnumValue;
-LPALLISTENERF qalListenerf;
-LPALLISTENER3F qalListener3f;
-LPALLISTENERFV qalListenerfv;
-LPALLISTENERI qalListeneri;
-LPALGETLISTENERF qalGetListenerf;
-LPALGETLISTENER3F qalGetListener3f;
-LPALGETLISTENERFV qalGetListenerfv;
-LPALGETLISTENERI qalGetListeneri;
-LPALGENSOURCES qalGenSources;
-LPALDELETESOURCES qalDeleteSources;
-LPALISSOURCE qalIsSource;
-LPALSOURCEF qalSourcef;
-LPALSOURCE3F qalSource3f;
-LPALSOURCEFV qalSourcefv;
-LPALSOURCEI qalSourcei;
-LPALGETSOURCEF qalGetSourcef;
-LPALGETSOURCE3F qalGetSource3f;
-LPALGETSOURCEFV qalGetSourcefv;
-LPALGETSOURCEI qalGetSourcei;
-LPALSOURCEPLAYV qalSourcePlayv;
-LPALSOURCESTOPV qalSourceStopv;
-LPALSOURCEREWINDV qalSourceRewindv;
-LPALSOURCEPAUSEV qalSourcePausev;
-LPALSOURCEPLAY qalSourcePlay;
-LPALSOURCESTOP qalSourceStop;
-LPALSOURCEREWIND qalSourceRewind;
-LPALSOURCEPAUSE qalSourcePause;
-LPALSOURCEQUEUEBUFFERS qalSourceQueueBuffers;
-LPALSOURCEUNQUEUEBUFFERS qalSourceUnqueueBuffers;
-LPALGENBUFFERS qalGenBuffers;
-LPALDELETEBUFFERS qalDeleteBuffers;
-LPALISBUFFER qalIsBuffer;
-LPALBUFFERDATA qalBufferData;
-LPALGETBUFFERF qalGetBufferf;
-LPALGETBUFFERI qalGetBufferi;
-LPALDOPPLERFACTOR qalDopplerFactor;
-LPALDOPPLERVELOCITY qalDopplerVelocity;
-LPALDISTANCEMODEL qalDistanceModel;
-
-LPALCCREATECONTEXT qalcCreateContext;
-LPALCMAKECONTEXTCURRENT qalcMakeContextCurrent;
-LPALCPROCESSCONTEXT qalcProcessContext;
-LPALCSUSPENDCONTEXT qalcSuspendContext;
-LPALCDESTROYCONTEXT qalcDestroyContext;
-LPALCGETCURRENTCONTEXT qalcGetCurrentContext;
-LPALCGETCONTEXTSDEVICE qalcGetContextsDevice;
-LPALCOPENDEVICE qalcOpenDevice;
-LPALCCLOSEDEVICE qalcCloseDevice;
-LPALCGETERROR qalcGetError;
-LPALCISEXTENSIONPRESENT qalcIsExtensionPresent;
-LPALCGETPROCADDRESS qalcGetProcAddress;
-LPALCGETENUMVALUE qalcGetEnumValue;
-LPALCGETSTRING qalcGetString;
-LPALCGETINTEGERV qalcGetIntegerv;
-LPALCCAPTUREOPENDEVICE qalcCaptureOpenDevice;
-LPALCCAPTURECLOSEDEVICE qalcCaptureCloseDevice;
-LPALCCAPTURESTART qalcCaptureStart;
-LPALCCAPTURESTOP qalcCaptureStop;
-LPALCCAPTURESAMPLES qalcCaptureSamples;
-
-static void *OpenALLib = NULL;
-
-static qboolean alinit_fail = qfalse;
-
-/*
-=================
-GPA
-=================
-*/
-static void *GPA(char *str)
-{
- void *rv;
-
- rv = Sys_LoadFunction(OpenALLib, str);
- if(!rv)
- {
- Com_Printf( " Can't load symbol %s\n", str);
- alinit_fail = qtrue;
- return NULL;
- }
- else
- {
- Com_DPrintf( " Loaded symbol %s (%p)\n", str, rv);
- return rv;
- }
-}
-
-/*
-=================
-QAL_Init
-=================
-*/
-qboolean QAL_Init(const char *libname)
-{
- if(OpenALLib)
- return qtrue;
-
- Com_Printf( "Loading \"%s\"...\n", libname);
- if( (OpenALLib = Sys_LoadLibrary(libname)) == 0 )
- {
-#ifdef _WIN32
- return qfalse;
-#else
- char fn[1024];
- Q_strncpyz( fn, Sys_Cwd( ), sizeof( fn ) );
- strncat(fn, "/", sizeof(fn) - strlen(fn) - 1);
- strncat(fn, libname, sizeof(fn) - strlen(fn) - 1);
-
- if( (OpenALLib = Sys_LoadLibrary(fn)) == 0 )
- {
- return qfalse;
- }
-#endif
- }
-
- alinit_fail = qfalse;
-
- qalEnable = GPA("alEnable");
- qalDisable = GPA("alDisable");
- qalIsEnabled = GPA("alIsEnabled");
- qalGetString = GPA("alGetString");
- qalGetBooleanv = GPA("alGetBooleanv");
- qalGetIntegerv = GPA("alGetIntegerv");
- qalGetFloatv = GPA("alGetFloatv");
- qalGetDoublev = GPA("alGetDoublev");
- qalGetBoolean = GPA("alGetBoolean");
- qalGetInteger = GPA("alGetInteger");
- qalGetFloat = GPA("alGetFloat");
- qalGetDouble = GPA("alGetDouble");
- qalGetError = GPA("alGetError");
- qalIsExtensionPresent = GPA("alIsExtensionPresent");
- qalGetProcAddress = GPA("alGetProcAddress");
- qalGetEnumValue = GPA("alGetEnumValue");
- qalListenerf = GPA("alListenerf");
- qalListener3f = GPA("alListener3f");
- qalListenerfv = GPA("alListenerfv");
- qalListeneri = GPA("alListeneri");
- qalGetListenerf = GPA("alGetListenerf");
- qalGetListener3f = GPA("alGetListener3f");
- qalGetListenerfv = GPA("alGetListenerfv");
- qalGetListeneri = GPA("alGetListeneri");
- qalGenSources = GPA("alGenSources");
- qalDeleteSources = GPA("alDeleteSources");
- qalIsSource = GPA("alIsSource");
- qalSourcef = GPA("alSourcef");
- qalSource3f = GPA("alSource3f");
- qalSourcefv = GPA("alSourcefv");
- qalSourcei = GPA("alSourcei");
- qalGetSourcef = GPA("alGetSourcef");
- qalGetSource3f = GPA("alGetSource3f");
- qalGetSourcefv = GPA("alGetSourcefv");
- qalGetSourcei = GPA("alGetSourcei");
- qalSourcePlayv = GPA("alSourcePlayv");
- qalSourceStopv = GPA("alSourceStopv");
- qalSourceRewindv = GPA("alSourceRewindv");
- qalSourcePausev = GPA("alSourcePausev");
- qalSourcePlay = GPA("alSourcePlay");
- qalSourceStop = GPA("alSourceStop");
- qalSourceRewind = GPA("alSourceRewind");
- qalSourcePause = GPA("alSourcePause");
- qalSourceQueueBuffers = GPA("alSourceQueueBuffers");
- qalSourceUnqueueBuffers = GPA("alSourceUnqueueBuffers");
- qalGenBuffers = GPA("alGenBuffers");
- qalDeleteBuffers = GPA("alDeleteBuffers");
- qalIsBuffer = GPA("alIsBuffer");
- qalBufferData = GPA("alBufferData");
- qalGetBufferf = GPA("alGetBufferf");
- qalGetBufferi = GPA("alGetBufferi");
- qalDopplerFactor = GPA("alDopplerFactor");
- qalDopplerVelocity = GPA("alDopplerVelocity");
- qalDistanceModel = GPA("alDistanceModel");
-
- qalcCreateContext = GPA("alcCreateContext");
- qalcMakeContextCurrent = GPA("alcMakeContextCurrent");
- qalcProcessContext = GPA("alcProcessContext");
- qalcSuspendContext = GPA("alcSuspendContext");
- qalcDestroyContext = GPA("alcDestroyContext");
- qalcGetCurrentContext = GPA("alcGetCurrentContext");
- qalcGetContextsDevice = GPA("alcGetContextsDevice");
- qalcOpenDevice = GPA("alcOpenDevice");
- qalcCloseDevice = GPA("alcCloseDevice");
- qalcGetError = GPA("alcGetError");
- qalcIsExtensionPresent = GPA("alcIsExtensionPresent");
- qalcGetProcAddress = GPA("alcGetProcAddress");
- qalcGetEnumValue = GPA("alcGetEnumValue");
- qalcGetString = GPA("alcGetString");
- qalcGetIntegerv = GPA("alcGetIntegerv");
- qalcCaptureOpenDevice = GPA("alcCaptureOpenDevice");
- qalcCaptureCloseDevice = GPA("alcCaptureCloseDevice");
- qalcCaptureStart = GPA("alcCaptureStart");
- qalcCaptureStop = GPA("alcCaptureStop");
- qalcCaptureSamples = GPA("alcCaptureSamples");
-
- if(alinit_fail)
- {
- QAL_Shutdown();
- Com_Printf( " One or more symbols not found\n");
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-=================
-QAL_Shutdown
-=================
-*/
-void QAL_Shutdown( void )
-{
- if(OpenALLib)
- {
- Sys_UnloadLibrary(OpenALLib);
- OpenALLib = NULL;
- }
-
- qalEnable = NULL;
- qalDisable = NULL;
- qalIsEnabled = NULL;
- qalGetString = NULL;
- qalGetBooleanv = NULL;
- qalGetIntegerv = NULL;
- qalGetFloatv = NULL;
- qalGetDoublev = NULL;
- qalGetBoolean = NULL;
- qalGetInteger = NULL;
- qalGetFloat = NULL;
- qalGetDouble = NULL;
- qalGetError = NULL;
- qalIsExtensionPresent = NULL;
- qalGetProcAddress = NULL;
- qalGetEnumValue = NULL;
- qalListenerf = NULL;
- qalListener3f = NULL;
- qalListenerfv = NULL;
- qalListeneri = NULL;
- qalGetListenerf = NULL;
- qalGetListener3f = NULL;
- qalGetListenerfv = NULL;
- qalGetListeneri = NULL;
- qalGenSources = NULL;
- qalDeleteSources = NULL;
- qalIsSource = NULL;
- qalSourcef = NULL;
- qalSource3f = NULL;
- qalSourcefv = NULL;
- qalSourcei = NULL;
- qalGetSourcef = NULL;
- qalGetSource3f = NULL;
- qalGetSourcefv = NULL;
- qalGetSourcei = NULL;
- qalSourcePlayv = NULL;
- qalSourceStopv = NULL;
- qalSourceRewindv = NULL;
- qalSourcePausev = NULL;
- qalSourcePlay = NULL;
- qalSourceStop = NULL;
- qalSourceRewind = NULL;
- qalSourcePause = NULL;
- qalSourceQueueBuffers = NULL;
- qalSourceUnqueueBuffers = NULL;
- qalGenBuffers = NULL;
- qalDeleteBuffers = NULL;
- qalIsBuffer = NULL;
- qalBufferData = NULL;
- qalGetBufferf = NULL;
- qalGetBufferi = NULL;
- qalDopplerFactor = NULL;
- qalDopplerVelocity = NULL;
- qalDistanceModel = NULL;
-
- qalcCreateContext = NULL;
- qalcMakeContextCurrent = NULL;
- qalcProcessContext = NULL;
- qalcSuspendContext = NULL;
- qalcDestroyContext = NULL;
- qalcGetCurrentContext = NULL;
- qalcGetContextsDevice = NULL;
- qalcOpenDevice = NULL;
- qalcCloseDevice = NULL;
- qalcGetError = NULL;
- qalcIsExtensionPresent = NULL;
- qalcGetProcAddress = NULL;
- qalcGetEnumValue = NULL;
- qalcGetString = NULL;
- qalcGetIntegerv = NULL;
- qalcCaptureOpenDevice = NULL;
- qalcCaptureCloseDevice = NULL;
- qalcCaptureStart = NULL;
- qalcCaptureStop = NULL;
- qalcCaptureSamples = NULL;
-}
-#else
-qboolean QAL_Init(const char *libname)
-{
- return qtrue;
-}
-void QAL_Shutdown( void )
-{
-}
-#endif
-#endif
diff --git a/engine/code/client/qal.h b/engine/code/client/qal.h
deleted file mode 100644
index 1a2284a..0000000
--- a/engine/code/client/qal.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-
-#ifndef __QAL_H__
-#define __QAL_H__
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-
-#ifdef USE_OPENAL_DLOPEN
-#define AL_NO_PROTOTYPES
-#define ALC_NO_PROTOTYPES
-#endif
-
-#ifdef USE_LOCAL_HEADERS
-#include "../AL/al.h"
-#include "../AL/alc.h"
-#else
-#ifdef _MSC_VER
- // MSVC users must install the OpenAL SDK which doesn't use the AL/*.h scheme.
- #include <al.h>
- #include <alc.h>
-#else
- #include <AL/al.h>
- #include <AL/alc.h>
-#endif
-#endif
-
-#ifdef USE_OPENAL_DLOPEN
-extern LPALENABLE qalEnable;
-extern LPALDISABLE qalDisable;
-extern LPALISENABLED qalIsEnabled;
-extern LPALGETSTRING qalGetString;
-extern LPALGETBOOLEANV qalGetBooleanv;
-extern LPALGETINTEGERV qalGetIntegerv;
-extern LPALGETFLOATV qalGetFloatv;
-extern LPALGETDOUBLEV qalGetDoublev;
-extern LPALGETBOOLEAN qalGetBoolean;
-extern LPALGETINTEGER qalGetInteger;
-extern LPALGETFLOAT qalGetFloat;
-extern LPALGETDOUBLE qalGetDouble;
-extern LPALGETERROR qalGetError;
-extern LPALISEXTENSIONPRESENT qalIsExtensionPresent;
-extern LPALGETPROCADDRESS qalGetProcAddress;
-extern LPALGETENUMVALUE qalGetEnumValue;
-extern LPALLISTENERF qalListenerf;
-extern LPALLISTENER3F qalListener3f;
-extern LPALLISTENERFV qalListenerfv;
-extern LPALLISTENERI qalListeneri;
-extern LPALLISTENER3I qalListener3i;
-extern LPALLISTENERIV qalListeneriv;
-extern LPALGETLISTENERF qalGetListenerf;
-extern LPALGETLISTENER3F qalGetListener3f;
-extern LPALGETLISTENERFV qalGetListenerfv;
-extern LPALGETLISTENERI qalGetListeneri;
-extern LPALGETLISTENER3I qalGetListener3i;
-extern LPALGETLISTENERIV qalGetListeneriv;
-extern LPALGENSOURCES qalGenSources;
-extern LPALDELETESOURCES qalDeleteSources;
-extern LPALISSOURCE qalIsSource;
-extern LPALSOURCEF qalSourcef;
-extern LPALSOURCE3F qalSource3f;
-extern LPALSOURCEFV qalSourcefv;
-extern LPALSOURCEI qalSourcei;
-extern LPALSOURCE3I qalSource3i;
-extern LPALSOURCEIV qalSourceiv;
-extern LPALGETSOURCEF qalGetSourcef;
-extern LPALGETSOURCE3F qalGetSource3f;
-extern LPALGETSOURCEFV qalGetSourcefv;
-extern LPALGETSOURCEI qalGetSourcei;
-extern LPALGETSOURCE3I qalGetSource3i;
-extern LPALGETSOURCEIV qalGetSourceiv;
-extern LPALSOURCEPLAYV qalSourcePlayv;
-extern LPALSOURCESTOPV qalSourceStopv;
-extern LPALSOURCEREWINDV qalSourceRewindv;
-extern LPALSOURCEPAUSEV qalSourcePausev;
-extern LPALSOURCEPLAY qalSourcePlay;
-extern LPALSOURCESTOP qalSourceStop;
-extern LPALSOURCEREWIND qalSourceRewind;
-extern LPALSOURCEPAUSE qalSourcePause;
-extern LPALSOURCEQUEUEBUFFERS qalSourceQueueBuffers;
-extern LPALSOURCEUNQUEUEBUFFERS qalSourceUnqueueBuffers;
-extern LPALGENBUFFERS qalGenBuffers;
-extern LPALDELETEBUFFERS qalDeleteBuffers;
-extern LPALISBUFFER qalIsBuffer;
-extern LPALBUFFERDATA qalBufferData;
-extern LPALBUFFERF qalBufferf;
-extern LPALBUFFER3F qalBuffer3f;
-extern LPALBUFFERFV qalBufferfv;
-extern LPALBUFFERF qalBufferi;
-extern LPALBUFFER3F qalBuffer3i;
-extern LPALBUFFERFV qalBufferiv;
-extern LPALGETBUFFERF qalGetBufferf;
-extern LPALGETBUFFER3F qalGetBuffer3f;
-extern LPALGETBUFFERFV qalGetBufferfv;
-extern LPALGETBUFFERI qalGetBufferi;
-extern LPALGETBUFFER3I qalGetBuffer3i;
-extern LPALGETBUFFERIV qalGetBufferiv;
-extern LPALDOPPLERFACTOR qalDopplerFactor;
-extern LPALDOPPLERVELOCITY qalDopplerVelocity;
-extern LPALSPEEDOFSOUND qalSpeedOfSound;
-extern LPALDISTANCEMODEL qalDistanceModel;
-
-extern LPALCCREATECONTEXT qalcCreateContext;
-extern LPALCMAKECONTEXTCURRENT qalcMakeContextCurrent;
-extern LPALCPROCESSCONTEXT qalcProcessContext;
-extern LPALCSUSPENDCONTEXT qalcSuspendContext;
-extern LPALCDESTROYCONTEXT qalcDestroyContext;
-extern LPALCGETCURRENTCONTEXT qalcGetCurrentContext;
-extern LPALCGETCONTEXTSDEVICE qalcGetContextsDevice;
-extern LPALCOPENDEVICE qalcOpenDevice;
-extern LPALCCLOSEDEVICE qalcCloseDevice;
-extern LPALCGETERROR qalcGetError;
-extern LPALCISEXTENSIONPRESENT qalcIsExtensionPresent;
-extern LPALCGETPROCADDRESS qalcGetProcAddress;
-extern LPALCGETENUMVALUE qalcGetEnumValue;
-extern LPALCGETSTRING qalcGetString;
-extern LPALCGETINTEGERV qalcGetIntegerv;
-extern LPALCCAPTUREOPENDEVICE qalcCaptureOpenDevice;
-extern LPALCCAPTURECLOSEDEVICE qalcCaptureCloseDevice;
-extern LPALCCAPTURESTART qalcCaptureStart;
-extern LPALCCAPTURESTOP qalcCaptureStop;
-extern LPALCCAPTURESAMPLES qalcCaptureSamples;
-#else
-#define qalEnable alEnable
-#define qalDisable alDisable
-#define qalIsEnabled alIsEnabled
-#define qalGetString alGetString
-#define qalGetBooleanv alGetBooleanv
-#define qalGetIntegerv alGetIntegerv
-#define qalGetFloatv alGetFloatv
-#define qalGetDoublev alGetDoublev
-#define qalGetBoolean alGetBoolean
-#define qalGetInteger alGetInteger
-#define qalGetFloat alGetFloat
-#define qalGetDouble alGetDouble
-#define qalGetError alGetError
-#define qalIsExtensionPresent alIsExtensionPresent
-#define qalGetProcAddress alGetProcAddress
-#define qalGetEnumValue alGetEnumValue
-#define qalListenerf alListenerf
-#define qalListener3f alListener3f
-#define qalListenerfv alListenerfv
-#define qalListeneri alListeneri
-#define qalListener3i alListener3i
-#define qalListeneriv alListeneriv
-#define qalGetListenerf alGetListenerf
-#define qalGetListener3f alGetListener3f
-#define qalGetListenerfv alGetListenerfv
-#define qalGetListeneri alGetListeneri
-#define qalGetListener3i alGetListener3i
-#define qalGetListeneriv alGetListeneriv
-#define qalGenSources alGenSources
-#define qalDeleteSources alDeleteSources
-#define qalIsSource alIsSource
-#define qalSourcef alSourcef
-#define qalSource3f alSource3f
-#define qalSourcefv alSourcefv
-#define qalSourcei alSourcei
-#define qalSource3i alSource3i
-#define qalSourceiv alSourceiv
-#define qalGetSourcef alGetSourcef
-#define qalGetSource3f alGetSource3f
-#define qalGetSourcefv alGetSourcefv
-#define qalGetSourcei alGetSourcei
-#define qalGetSource3i alGetSource3i
-#define qalGetSourceiv alGetSourceiv
-#define qalSourcePlayv alSourcePlayv
-#define qalSourceStopv alSourceStopv
-#define qalSourceRewindv alSourceRewindv
-#define qalSourcePausev alSourcePausev
-#define qalSourcePlay alSourcePlay
-#define qalSourceStop alSourceStop
-#define qalSourceRewind alSourceRewind
-#define qalSourcePause alSourcePause
-#define qalSourceQueueBuffers alSourceQueueBuffers
-#define qalSourceUnqueueBuffers alSourceUnqueueBuffers
-#define qalGenBuffers alGenBuffers
-#define qalDeleteBuffers alDeleteBuffers
-#define qalIsBuffer alIsBuffer
-#define qalBufferData alBufferData
-#define qalBufferf alBufferf
-#define qalBuffer3f alBuffer3f
-#define qalBufferfv alBufferfv
-#define qalBufferi alBufferi
-#define qalBuffer3i alBuffer3i
-#define qalBufferiv alBufferiv
-#define qalGetBufferf alGetBufferf
-#define qalGetBuffer3f alGetBuffer3f
-#define qalGetBufferfv alGetBufferfv
-#define qalGetBufferi alGetBufferi
-#define qalGetBuffer3i alGetBuffer3i
-#define qalGetBufferiv alGetBufferiv
-#define qalDopplerFactor alDopplerFactor
-#define qalDopplerVelocity alDopplerVelocity
-#define qalSpeedOfSound alSpeedOfSound
-#define qalDistanceModel alDistanceModel
-
-#define qalcCreateContext alcCreateContext
-#define qalcMakeContextCurrent alcMakeContextCurrent
-#define qalcProcessContext alcProcessContext
-#define qalcSuspendContext alcSuspendContext
-#define qalcDestroyContext alcDestroyContext
-#define qalcGetCurrentContext alcGetCurrentContext
-#define qalcGetContextsDevice alcGetContextsDevice
-#define qalcOpenDevice alcOpenDevice
-#define qalcCloseDevice alcCloseDevice
-#define qalcGetError alcGetError
-#define qalcIsExtensionPresent alcIsExtensionPresent
-#define qalcGetProcAddress alcGetProcAddress
-#define qalcGetEnumValue alcGetEnumValue
-#define qalcGetString alcGetString
-#define qalcGetIntegerv alcGetIntegerv
-#define qalcCaptureOpenDevice alcCaptureOpenDevice
-#define qalcCaptureCloseDevice alcCaptureCloseDevice
-#define qalcCaptureStart alcCaptureStart
-#define qalcCaptureStop alcCaptureStop
-#define qalcCaptureSamples alcCaptureSamples
-#endif
-
-qboolean QAL_Init(const char *libname);
-void QAL_Shutdown( void );
-
-#endif // __QAL_H__
diff --git a/engine/code/client/snd_adpcm.c b/engine/code/client/snd_adpcm.c
deleted file mode 100644
index 89e68f4..0000000
--- a/engine/code/client/snd_adpcm.c
+++ /dev/null
@@ -1,330 +0,0 @@
-/***********************************************************
-Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
-Netherlands.
-
- All Rights Reserved
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in
-supporting documentation, and that the names of Stichting Mathematisch
-Centrum or CWI not be used in advertising or publicity pertaining to
-distribution of the software without specific, written prior permission.
-
-STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
-THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
-FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-******************************************************************/
-
-/*
-** Intel/DVI ADPCM coder/decoder.
-**
-** The algorithm for this coder was taken from the IMA Compatability Project
-** proceedings, Vol 2, Number 2; May 1992.
-**
-** Version 1.2, 18-Dec-92.
-*/
-
-#include "snd_local.h"
-
-
-/* Intel ADPCM step variation table */
-static int indexTable[16] = {
- -1, -1, -1, -1, 2, 4, 6, 8,
- -1, -1, -1, -1, 2, 4, 6, 8,
-};
-
-static int stepsizeTable[89] = {
- 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
- 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
- 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
- 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
- 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
- 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
- 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
- 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
- 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
-};
-
-
-void S_AdpcmEncode( short indata[], char outdata[], int len, struct adpcm_state *state ) {
- short *inp; /* Input buffer pointer */
- signed char *outp; /* output buffer pointer */
- int val; /* Current input sample value */
- int sign; /* Current adpcm sign bit */
- int delta; /* Current adpcm output value */
- int diff; /* Difference between val and sample */
- int step; /* Stepsize */
- int valpred; /* Predicted output value */
- int vpdiff; /* Current change to valpred */
- int index; /* Current step change index */
- int outputbuffer; /* place to keep previous 4-bit value */
- int bufferstep; /* toggle between outputbuffer/output */
-
- outp = (signed char *)outdata;
- inp = indata;
-
- valpred = state->sample;
- index = state->index;
- step = stepsizeTable[index];
-
- outputbuffer = 0; // quiet a compiler warning
- bufferstep = 1;
-
- for ( ; len > 0 ; len-- ) {
- val = *inp++;
-
- /* Step 1 - compute difference with previous value */
- diff = val - valpred;
- sign = (diff < 0) ? 8 : 0;
- if ( sign ) diff = (-diff);
-
- /* Step 2 - Divide and clamp */
- /* Note:
- ** This code *approximately* computes:
- ** delta = diff*4/step;
- ** vpdiff = (delta+0.5)*step/4;
- ** but in shift step bits are dropped. The net result of this is
- ** that even if you have fast mul/div hardware you cannot put it to
- ** good use since the fixup would be too expensive.
- */
- delta = 0;
- vpdiff = (step >> 3);
-
- if ( diff >= step ) {
- delta = 4;
- diff -= step;
- vpdiff += step;
- }
- step >>= 1;
- if ( diff >= step ) {
- delta |= 2;
- diff -= step;
- vpdiff += step;
- }
- step >>= 1;
- if ( diff >= step ) {
- delta |= 1;
- vpdiff += step;
- }
-
- /* Step 3 - Update previous value */
- if ( sign )
- valpred -= vpdiff;
- else
- valpred += vpdiff;
-
- /* Step 4 - Clamp previous value to 16 bits */
- if ( valpred > 32767 )
- valpred = 32767;
- else if ( valpred < -32768 )
- valpred = -32768;
-
- /* Step 5 - Assemble value, update index and step values */
- delta |= sign;
-
- index += indexTable[delta];
- if ( index < 0 ) index = 0;
- if ( index > 88 ) index = 88;
- step = stepsizeTable[index];
-
- /* Step 6 - Output value */
- if ( bufferstep ) {
- outputbuffer = (delta << 4) & 0xf0;
- } else {
- *outp++ = (delta & 0x0f) | outputbuffer;
- }
- bufferstep = !bufferstep;
- }
-
- /* Output last step, if needed */
- if ( !bufferstep )
- *outp++ = outputbuffer;
-
- state->sample = valpred;
- state->index = index;
-}
-
-
-/* static */ void S_AdpcmDecode( const char indata[], short *outdata, int len, struct adpcm_state *state ) {
- signed char *inp; /* Input buffer pointer */
- int outp; /* output buffer pointer */
- int sign; /* Current adpcm sign bit */
- int delta; /* Current adpcm output value */
- int step; /* Stepsize */
- int valpred; /* Predicted value */
- int vpdiff; /* Current change to valpred */
- int index; /* Current step change index */
- int inputbuffer; /* place to keep next 4-bit value */
- int bufferstep; /* toggle between inputbuffer/input */
-
- outp = 0;
- inp = (signed char *)indata;
-
- valpred = state->sample;
- index = state->index;
- step = stepsizeTable[index];
-
- bufferstep = 0;
- inputbuffer = 0; // quiet a compiler warning
- for ( ; len > 0 ; len-- ) {
-
- /* Step 1 - get the delta value */
- if ( bufferstep ) {
- delta = inputbuffer & 0xf;
- } else {
- inputbuffer = *inp++;
- delta = (inputbuffer >> 4) & 0xf;
- }
- bufferstep = !bufferstep;
-
- /* Step 2 - Find new index value (for later) */
- index += indexTable[delta];
- if ( index < 0 ) index = 0;
- if ( index > 88 ) index = 88;
-
- /* Step 3 - Separate sign and magnitude */
- sign = delta & 8;
- delta = delta & 7;
-
- /* Step 4 - Compute difference and new predicted value */
- /*
- ** Computes 'vpdiff = (delta+0.5)*step/4', but see comment
- ** in adpcm_coder.
- */
- vpdiff = step >> 3;
- if ( delta & 4 ) vpdiff += step;
- if ( delta & 2 ) vpdiff += step>>1;
- if ( delta & 1 ) vpdiff += step>>2;
-
- if ( sign )
- valpred -= vpdiff;
- else
- valpred += vpdiff;
-
- /* Step 5 - clamp output value */
- if ( valpred > 32767 )
- valpred = 32767;
- else if ( valpred < -32768 )
- valpred = -32768;
-
- /* Step 6 - Update step value */
- step = stepsizeTable[index];
-
- /* Step 7 - Output value */
- outdata[outp] = valpred;
- outp++;
- }
-
- state->sample = valpred;
- state->index = index;
-}
-
-
-/*
-====================
-S_AdpcmMemoryNeeded
-
-Returns the amount of memory (in bytes) needed to store the samples in out internal adpcm format
-====================
-*/
-int S_AdpcmMemoryNeeded( const wavinfo_t *info ) {
- float scale;
- int scaledSampleCount;
- int sampleMemory;
- int blockCount;
- int headerMemory;
-
- // determine scale to convert from input sampling rate to desired sampling rate
- scale = (float)info->rate / dma.speed;
-
- // calc number of samples at playback sampling rate
- scaledSampleCount = info->samples / scale;
-
- // calc memory need to store those samples using ADPCM at 4 bits per sample
- sampleMemory = scaledSampleCount / 2;
-
- // calc number of sample blocks needed of PAINTBUFFER_SIZE
- blockCount = scaledSampleCount / PAINTBUFFER_SIZE;
- if( scaledSampleCount % PAINTBUFFER_SIZE ) {
- blockCount++;
- }
-
- // calc memory needed to store the block headers
- headerMemory = blockCount * sizeof(adpcm_state_t);
-
- return sampleMemory + headerMemory;
-}
-
-
-/*
-====================
-S_AdpcmGetSamples
-====================
-*/
-void S_AdpcmGetSamples(sndBuffer *chunk, short *to) {
- adpcm_state_t state;
- byte *out;
-
- // get the starting state from the block header
- state.index = chunk->adpcm.index;
- state.sample = chunk->adpcm.sample;
-
- out = (byte *)chunk->sndChunk;
- // get samples
- S_AdpcmDecode((char *) out, to, SND_CHUNK_SIZE_BYTE*2, &state );
-}
-
-
-/*
-====================
-S_AdpcmEncodeSound
-====================
-*/
-void S_AdpcmEncodeSound( sfx_t *sfx, short *samples ) {
- adpcm_state_t state;
- int inOffset;
- int count;
- int n;
- sndBuffer *newchunk, *chunk;
- byte *out;
-
- inOffset = 0;
- count = sfx->soundLength;
- state.index = 0;
- state.sample = samples[0];
-
- chunk = NULL;
- while( count ) {
- n = count;
- if( n > SND_CHUNK_SIZE_BYTE*2 ) {
- n = SND_CHUNK_SIZE_BYTE*2;
- }
-
- newchunk = SND_malloc();
- if (sfx->soundData == NULL) {
- sfx->soundData = newchunk;
- } else {
- chunk->next = newchunk;
- }
- chunk = newchunk;
-
- // output the header
- chunk->adpcm.index = state.index;
- chunk->adpcm.sample = state.sample;
-
- out = (byte *)chunk->sndChunk;
-
- // encode the samples
- S_AdpcmEncode( samples + inOffset, (char *) out, n, &state );
-
- inOffset += n;
- count -= n;
- }
-}
diff --git a/engine/code/client/snd_codec.c b/engine/code/client/snd_codec.c
deleted file mode 100644
index 0483e8d..0000000
--- a/engine/code/client/snd_codec.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "client.h"
-#include "snd_codec.h"
-
-static snd_codec_t *codecs;
-
-/*
-=================
-S_FileExtension
-=================
-*/
-static char *S_FileExtension(const char *fni)
-{
- // we should search from the ending to the last '/'
-
- char *fn = (char *) fni + strlen(fni) - 1;
- char *eptr = NULL;
-
- while(*fn != '/' && fn != fni)
- {
- if(*fn == '.')
- {
- eptr = fn;
- break;
- }
- fn--;
- }
-
- return eptr;
-}
-
-/*
-=================
-S_FindCodecForFile
-
-Select an appropriate codec for a file based on its extension
-=================
-*/
-static snd_codec_t *S_FindCodecForFile(const char *filename)
-{
- char *ext = S_FileExtension(filename);
- snd_codec_t *codec = codecs;
-
- if(!ext)
- {
- // No extension - auto-detect
- while(codec)
- {
- char fn[MAX_QPATH];
-
- // there is no extension so we do not need to subtract 4 chars
- Q_strncpyz(fn, filename, MAX_QPATH);
- COM_DefaultExtension(fn, MAX_QPATH, codec->ext);
-
- // Check it exists
- if(FS_ReadFile(fn, NULL) != -1)
- return codec;
-
- // Nope. Next!
- codec = codec->next;
- }
-
- // Nothin'
- return NULL;
- }
-
- while(codec)
- {
- if(!Q_stricmp(ext, codec->ext))
- return codec;
- codec = codec->next;
- }
-
- return NULL;
-}
-
-/*
-=================
-S_CodecInit
-=================
-*/
-void S_CodecInit()
-{
- codecs = NULL;
- S_CodecRegister(&wav_codec);
-#ifdef USE_CODEC_VORBIS
- S_CodecRegister(&ogg_codec);
-#endif
-}
-
-/*
-=================
-S_CodecShutdown
-=================
-*/
-void S_CodecShutdown()
-{
- codecs = NULL;
-}
-
-/*
-=================
-S_CodecRegister
-=================
-*/
-void S_CodecRegister(snd_codec_t *codec)
-{
- codec->next = codecs;
- codecs = codec;
-}
-
-/*
-=================
-S_CodecLoad
-=================
-*/
-void *S_CodecLoad(const char *filename, snd_info_t *info)
-{
- snd_codec_t *codec;
- char fn[MAX_QPATH];
-
- codec = S_FindCodecForFile(filename);
- if(!codec)
- {
- Com_Printf("Unknown extension for %s\n", filename);
- return NULL;
- }
-
- strncpy(fn, filename, sizeof(fn));
- COM_DefaultExtension(fn, sizeof(fn), codec->ext);
-
- return codec->load(fn, info);
-}
-
-/*
-=================
-S_CodecOpenStream
-=================
-*/
-snd_stream_t *S_CodecOpenStream(const char *filename)
-{
- snd_codec_t *codec;
- char fn[MAX_QPATH];
-
- codec = S_FindCodecForFile(filename);
- if(!codec)
- {
- Com_Printf("Unknown extension for %s\n", filename);
- return NULL;
- }
-
- strncpy(fn, filename, sizeof(fn));
- COM_DefaultExtension(fn, sizeof(fn), codec->ext);
-
- return codec->open(fn);
-}
-
-void S_CodecCloseStream(snd_stream_t *stream)
-{
- stream->codec->close(stream);
-}
-
-int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
-{
- return stream->codec->read(stream, bytes, buffer);
-}
-
-//=======================================================================
-// Util functions (used by codecs)
-
-/*
-=================
-S_CodecUtilOpen
-=================
-*/
-snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec)
-{
- snd_stream_t *stream;
- fileHandle_t hnd;
- int length;
-
- // Try to open the file
- length = FS_FOpenFileRead(filename, &hnd, qtrue);
- if(!hnd)
- {
- Com_Printf("Can't read sound file %s\n", filename);
- return NULL;
- }
-
- // Allocate a stream
- stream = Z_Malloc(sizeof(snd_stream_t));
- if(!stream)
- {
- FS_FCloseFile(hnd);
- return NULL;
- }
-
- // Copy over, return
- stream->codec = codec;
- stream->file = hnd;
- stream->length = length;
- return stream;
-}
-
-/*
-=================
-S_CodecUtilClose
-=================
-*/
-void S_CodecUtilClose(snd_stream_t **stream)
-{
- FS_FCloseFile((*stream)->file);
- Z_Free(*stream);
- *stream = NULL;
-}
diff --git a/engine/code/client/snd_codec.h b/engine/code/client/snd_codec.h
deleted file mode 100644
index 03fcaa2..0000000
--- a/engine/code/client/snd_codec.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#ifndef _SND_CODEC_H_
-#define _SND_CODEC_H_
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-
-typedef struct snd_info_s
-{
- int rate;
- int width;
- int channels;
- int samples;
- int size;
- int dataofs;
-} snd_info_t;
-
-typedef struct snd_codec_s snd_codec_t;
-
-typedef struct snd_stream_s
-{
- snd_codec_t *codec;
- fileHandle_t file;
- snd_info_t info;
- int length;
- int pos;
- void *ptr;
-} snd_stream_t;
-
-// Codec functions
-typedef void *(*CODEC_LOAD)(const char *filename, snd_info_t *info);
-typedef snd_stream_t *(*CODEC_OPEN)(const char *filename);
-typedef int (*CODEC_READ)(snd_stream_t *stream, int bytes, void *buffer);
-typedef void (*CODEC_CLOSE)(snd_stream_t *stream);
-
-// Codec data structure
-struct snd_codec_s
-{
- char *ext;
- CODEC_LOAD load;
- CODEC_OPEN open;
- CODEC_READ read;
- CODEC_CLOSE close;
- snd_codec_t *next;
-};
-
-// Codec management
-void S_CodecInit( void );
-void S_CodecShutdown( void );
-void S_CodecRegister(snd_codec_t *codec);
-void *S_CodecLoad(const char *filename, snd_info_t *info);
-snd_stream_t *S_CodecOpenStream(const char *filename);
-void S_CodecCloseStream(snd_stream_t *stream);
-int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
-
-// Util functions (used by codecs)
-snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec);
-void S_CodecUtilClose(snd_stream_t **stream);
-
-// WAV Codec
-extern snd_codec_t wav_codec;
-void *S_WAV_CodecLoad(const char *filename, snd_info_t *info);
-snd_stream_t *S_WAV_CodecOpenStream(const char *filename);
-void S_WAV_CodecCloseStream(snd_stream_t *stream);
-int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
-
-// Ogg Vorbis codec
-#ifdef USE_CODEC_VORBIS
-extern snd_codec_t ogg_codec;
-void *S_OGG_CodecLoad(const char *filename, snd_info_t *info);
-snd_stream_t *S_OGG_CodecOpenStream(const char *filename);
-void S_OGG_CodecCloseStream(snd_stream_t *stream);
-int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
-#endif // USE_CODEC_VORBIS
-
-#endif // !_SND_CODEC_H_
diff --git a/engine/code/client/snd_codec_ogg.c b/engine/code/client/snd_codec_ogg.c
deleted file mode 100644
index 48da5d7..0000000
--- a/engine/code/client/snd_codec_ogg.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
-Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg at gmx.de>
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-// OGG support is enabled by this define
-#ifdef USE_CODEC_VORBIS
-
-// includes for the Q3 sound system
-#include "client.h"
-#include "snd_codec.h"
-
-// includes for the OGG codec
-#include <errno.h>
-#include <vorbis/vorbisfile.h>
-
-// The OGG codec can return the samples in a number of different formats,
-// we use the standard signed short format.
-#define OGG_SAMPLEWIDTH 2
-
-// Q3 OGG codec
-snd_codec_t ogg_codec =
-{
- ".ogg",
- S_OGG_CodecLoad,
- S_OGG_CodecOpenStream,
- S_OGG_CodecReadStream,
- S_OGG_CodecCloseStream,
- NULL
-};
-
-// callbacks for vobisfile
-
-// fread() replacement
-size_t S_OGG_Callback_read(void *ptr, size_t size, size_t nmemb, void *datasource)
-{
- snd_stream_t *stream;
- int byteSize = 0;
- int bytesRead = 0;
- size_t nMembRead = 0;
-
- // check if input is valid
- if(!ptr)
- {
- errno = EFAULT;
- return 0;
- }
-
- if(!(size && nmemb))
- {
- // It's not an error, caller just wants zero bytes!
- errno = 0;
- return 0;
- }
-
- if(!datasource)
- {
- errno = EBADF;
- return 0;
- }
-
- // we use a snd_stream_t in the generic pointer to pass around
- stream = (snd_stream_t *) datasource;
-
- // FS_Read does not support multi-byte elements
- byteSize = nmemb * size;
-
- // read it with the Q3 function FS_Read()
- bytesRead = FS_Read(ptr, byteSize, stream->file);
-
- // update the file position
- stream->pos += bytesRead;
-
- // this function returns the number of elements read not the number of bytes
- nMembRead = bytesRead / size;
-
- // even if the last member is only read partially
- // it is counted as a whole in the return value
- if(bytesRead % size)
- {
- nMembRead++;
- }
-
- return nMembRead;
-}
-
-// fseek() replacement
-int S_OGG_Callback_seek(void *datasource, ogg_int64_t offset, int whence)
-{
- snd_stream_t *stream;
- int retVal = 0;
-
- // check if input is valid
- if(!datasource)
- {
- errno = EBADF;
- return -1;
- }
-
- // snd_stream_t in the generic pointer
- stream = (snd_stream_t *) datasource;
-
- // we must map the whence to its Q3 counterpart
- switch(whence)
- {
- case SEEK_SET :
- {
- // set the file position in the actual file with the Q3 function
- retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_SET);
-
- // something has gone wrong, so we return here
- if(retVal < 0)
- {
- return retVal;
- }
-
- // keep track of file position
- stream->pos = (int) offset;
- break;
- }
-
- case SEEK_CUR :
- {
- // set the file position in the actual file with the Q3 function
- retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_CUR);
-
- // something has gone wrong, so we return here
- if(retVal < 0)
- {
- return retVal;
- }
-
- // keep track of file position
- stream->pos += (int) offset;
- break;
- }
-
- case SEEK_END :
- {
- // Quake 3 seems to have trouble with FS_SEEK_END
- // so we use the file length and FS_SEEK_SET
-
- // set the file position in the actual file with the Q3 function
- retVal = FS_Seek(stream->file, (long) stream->length + (long) offset, FS_SEEK_SET);
-
- // something has gone wrong, so we return here
- if(retVal < 0)
- {
- return retVal;
- }
-
- // keep track of file position
- stream->pos = stream->length + (int) offset;
- break;
- }
-
- default :
- {
- // unknown whence, so we return an error
- errno = EINVAL;
- return -1;
- }
- }
-
- // stream->pos shouldn't be smaller than zero or bigger than the filesize
- stream->pos = (stream->pos < 0) ? 0 : stream->pos;
- stream->pos = (stream->pos > stream->length) ? stream->length : stream->pos;
-
- return 0;
-}
-
-// fclose() replacement
-int S_OGG_Callback_close(void *datasource)
-{
- // we do nothing here and close all things manually in S_OGG_CodecCloseStream()
- return 0;
-}
-
-// ftell() replacement
-long S_OGG_Callback_tell(void *datasource)
-{
- snd_stream_t *stream;
-
- // check if input is valid
- if(!datasource)
- {
- errno = EBADF;
- return -1;
- }
-
- // snd_stream_t in the generic pointer
- stream = (snd_stream_t *) datasource;
-
- return (long) FS_FTell(stream->file);
-}
-
-// the callback structure
-const ov_callbacks S_OGG_Callbacks =
-{
- &S_OGG_Callback_read,
- &S_OGG_Callback_seek,
- &S_OGG_Callback_close,
- &S_OGG_Callback_tell
-};
-
-/*
-=================
-S_OGG_CodecOpenStream
-=================
-*/
-snd_stream_t *S_OGG_CodecOpenStream(const char *filename)
-{
- snd_stream_t *stream;
-
- // OGG codec control structure
- OggVorbis_File *vf;
-
- // some variables used to get informations about the OGG
- vorbis_info *OGGInfo;
- ogg_int64_t numSamples;
-
- // check if input is valid
- if(!filename)
- {
- return NULL;
- }
-
- // Open the stream
- stream = S_CodecUtilOpen(filename, &ogg_codec);
- if(!stream)
- {
- return NULL;
- }
-
- // alloctate the OggVorbis_File
- vf = Z_Malloc(sizeof(OggVorbis_File));
- if(!vf)
- {
- S_CodecUtilClose(&stream);
-
- return NULL;
- }
-
- // open the codec with our callbacks and stream as the generic pointer
- if(ov_open_callbacks(stream, vf, NULL, 0, S_OGG_Callbacks) != 0)
- {
- Z_Free(vf);
-
- S_CodecUtilClose(&stream);
-
- return NULL;
- }
-
- // the stream must be seekable
- if(!ov_seekable(vf))
- {
- ov_clear(vf);
-
- Z_Free(vf);
-
- S_CodecUtilClose(&stream);
-
- return NULL;
- }
-
- // we only support OGGs with one substream
- if(ov_streams(vf) != 1)
- {
- ov_clear(vf);
-
- Z_Free(vf);
-
- S_CodecUtilClose(&stream);
-
- return NULL;
- }
-
- // get the info about channels and rate
- OGGInfo = ov_info(vf, 0);
- if(!OGGInfo)
- {
- ov_clear(vf);
-
- Z_Free(vf);
-
- S_CodecUtilClose(&stream);
-
- return NULL;
- }
-
- // get the number of sample-frames in the OGG
- numSamples = ov_pcm_total(vf, 0);
-
- // fill in the info-structure in the stream
- stream->info.rate = OGGInfo->rate;
- stream->info.width = OGG_SAMPLEWIDTH;
- stream->info.channels = OGGInfo->channels;
- stream->info.samples = numSamples;
- stream->info.size = stream->info.samples * stream->info.channels * stream->info.width;
- stream->info.dataofs = 0;
-
- // We use stream->pos for the file pointer in the compressed ogg file
- stream->pos = 0;
-
- // We use the generic pointer in stream for the OGG codec control structure
- stream->ptr = vf;
-
- return stream;
-}
-
-/*
-=================
-S_OGG_CodecCloseStream
-=================
-*/
-void S_OGG_CodecCloseStream(snd_stream_t *stream)
-{
- // check if input is valid
- if(!stream)
- {
- return;
- }
-
- // let the OGG codec cleanup its stuff
- ov_clear((OggVorbis_File *) stream->ptr);
-
- // free the OGG codec control struct
- Z_Free(stream->ptr);
-
- // close the stream
- S_CodecUtilClose(&stream);
-}
-
-/*
-=================
-S_OGG_CodecReadStream
-=================
-*/
-int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
-{
- // buffer handling
- int bytesRead, bytesLeft, c;
- char *bufPtr;
-
- // Bitstream for the decoder
- int BS = 0;
-
- // big endian machines want their samples in big endian order
- int IsBigEndian = 0;
-
-# ifdef Q3_BIG_ENDIAN
- IsBigEndian = 1;
-# endif // Q3_BIG_ENDIAN
-
- // check if input is valid
- if(!(stream && buffer))
- {
- return 0;
- }
-
- if(bytes <= 0)
- {
- return 0;
- }
-
- bytesRead = 0;
- bytesLeft = bytes;
- bufPtr = buffer;
-
- // cycle until we have the requested or all available bytes read
- while(-1)
- {
- // read some bytes from the OGG codec
- c = ov_read((OggVorbis_File *) stream->ptr, bufPtr, bytesLeft, IsBigEndian, OGG_SAMPLEWIDTH, 1, &BS);
-
- // no more bytes are left
- if(c <= 0)
- {
- break;
- }
-
- bytesRead += c;
- bytesLeft -= c;
- bufPtr += c;
-
- // we have enough bytes
- if(bytesLeft <= 0)
- {
- break;
- }
- }
-
- return bytesRead;
-}
-
-/*
-=====================================================================
-S_OGG_CodecLoad
-
-We handle S_OGG_CodecLoad as a special case of the streaming functions
-where we read the whole stream at once.
-======================================================================
-*/
-void *S_OGG_CodecLoad(const char *filename, snd_info_t *info)
-{
- snd_stream_t *stream;
- byte *buffer;
- int bytesRead;
-
- // check if input is valid
- if(!(filename && info))
- {
- return NULL;
- }
-
- // open the file as a stream
- stream = S_OGG_CodecOpenStream(filename);
- if(!stream)
- {
- return NULL;
- }
-
- // copy over the info
- info->rate = stream->info.rate;
- info->width = stream->info.width;
- info->channels = stream->info.channels;
- info->samples = stream->info.samples;
- info->size = stream->info.size;
- info->dataofs = stream->info.dataofs;
-
- // allocate a buffer
- // this buffer must be free-ed by the caller of this function
- buffer = Z_Malloc(info->size);
- if(!buffer)
- {
- S_OGG_CodecCloseStream(stream);
-
- return NULL;
- }
-
- // fill the buffer
- bytesRead = S_OGG_CodecReadStream(stream, info->size, buffer);
-
- // we don't even have read a single byte
- if(bytesRead <= 0)
- {
- Z_Free(buffer);
- S_OGG_CodecCloseStream(stream);
-
- return NULL;
- }
-
- S_OGG_CodecCloseStream(stream);
-
- return buffer;
-}
-
-#endif // USE_CODEC_VORBIS
diff --git a/engine/code/client/snd_codec_wav.c b/engine/code/client/snd_codec_wav.c
deleted file mode 100644
index c0b2e2e..0000000
--- a/engine/code/client/snd_codec_wav.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "client.h"
-#include "snd_codec.h"
-
-/*
-=================
-FGetLittleLong
-=================
-*/
-static int FGetLittleLong( fileHandle_t f ) {
- int v;
-
- FS_Read( &v, sizeof(v), f );
-
- return LittleLong( v);
-}
-
-/*
-=================
-FGetLittleShort
-=================
-*/
-static short FGetLittleShort( fileHandle_t f ) {
- short v;
-
- FS_Read( &v, sizeof(v), f );
-
- return LittleShort( v);
-}
-
-/*
-=================
-S_ReadChunkInfo
-=================
-*/
-static int S_ReadChunkInfo(fileHandle_t f, char *name)
-{
- int len, r;
-
- name[4] = 0;
-
- r = FS_Read(name, 4, f);
- if(r != 4)
- return -1;
-
- len = FGetLittleLong(f);
- if( len < 0 ) {
- Com_Printf( S_COLOR_YELLOW "WARNING: Negative chunk length\n" );
- return -1;
- }
-
- return len;
-}
-
-/*
-=================
-S_FindRIFFChunk
-
-Returns the length of the data in the chunk, or -1 if not found
-=================
-*/
-static int S_FindRIFFChunk( fileHandle_t f, char *chunk ) {
- char name[5];
- int len;
-
- while( ( len = S_ReadChunkInfo(f, name) ) >= 0 )
- {
- // If this is the right chunk, return
- if( !Q_strncmp( name, chunk, 4 ) )
- return len;
-
- len = PAD( len, 2 );
-
- // Not the right chunk - skip it
- FS_Seek( f, len, FS_SEEK_CUR );
- }
-
- return -1;
-}
-
-/*
-=================
-S_ByteSwapRawSamples
-=================
-*/
-static void S_ByteSwapRawSamples( int samples, int width, int s_channels, const byte *data ) {
- int i;
-
- if ( width != 2 ) {
- return;
- }
- if ( LittleShort( 256 ) == 256 ) {
- return;
- }
-
- if ( s_channels == 2 ) {
- samples <<= 1;
- }
- for ( i = 0 ; i < samples ; i++ ) {
- ((short *)data)[i] = LittleShort( ((short *)data)[i] );
- }
-}
-
-/*
-=================
-S_ReadRIFFHeader
-=================
-*/
-static qboolean S_ReadRIFFHeader(fileHandle_t file, snd_info_t *info)
-{
- char dump[16];
- int wav_format;
- int bits;
- int fmtlen = 0;
-
- // skip the riff wav header
- FS_Read(dump, 12, file);
-
- // Scan for the format chunk
- if((fmtlen = S_FindRIFFChunk(file, "fmt ")) < 0)
- {
- Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"fmt\" chunk\n");
- return qfalse;
- }
-
- // Save the parameters
- wav_format = FGetLittleShort(file);
- info->channels = FGetLittleShort(file);
- info->rate = FGetLittleLong(file);
- FGetLittleLong(file);
- FGetLittleShort(file);
- bits = FGetLittleShort(file);
-
- if( bits < 8 )
- {
- Com_Printf( S_COLOR_RED "ERROR: Less than 8 bit sound is not supported\n");
- return qfalse;
- }
-
- info->width = bits / 8;
- info->dataofs = 0;
-
- // Skip the rest of the format chunk if required
- if(fmtlen > 16)
- {
- fmtlen -= 16;
- FS_Seek( file, fmtlen, FS_SEEK_CUR );
- }
-
- // Scan for the data chunk
- if( (info->size = S_FindRIFFChunk(file, "data")) < 0)
- {
- Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"data\" chunk\n");
- return qfalse;
- }
- info->samples = (info->size / info->width) / info->channels;
-
- return qtrue;
-}
-
-// WAV codec
-snd_codec_t wav_codec =
-{
- ".wav",
- S_WAV_CodecLoad,
- S_WAV_CodecOpenStream,
- S_WAV_CodecReadStream,
- S_WAV_CodecCloseStream,
- NULL
-};
-
-/*
-=================
-S_WAV_CodecLoad
-=================
-*/
-void *S_WAV_CodecLoad(const char *filename, snd_info_t *info)
-{
- fileHandle_t file;
- void *buffer;
-
- // Try to open the file
- FS_FOpenFileRead(filename, &file, qtrue);
- if(!file)
- {
- Com_Printf( S_COLOR_RED "ERROR: Could not open \"%s\"\n",
- filename);
- return NULL;
- }
-
- // Read the RIFF header
- if(!S_ReadRIFFHeader(file, info))
- {
- FS_FCloseFile(file);
- Com_Printf( S_COLOR_RED "ERROR: Incorrect/unsupported format in \"%s\"\n",
- filename);
- return NULL;
- }
-
- // Allocate some memory
- buffer = Z_Malloc(info->size);
- if(!buffer)
- {
- FS_FCloseFile(file);
- Com_Printf( S_COLOR_RED "ERROR: Out of memory reading \"%s\"\n",
- filename);
- return NULL;
- }
-
- // Read, byteswap
- FS_Read(buffer, info->size, file);
- S_ByteSwapRawSamples(info->samples, info->width, info->channels, (byte *)buffer);
-
- // Close and return
- FS_FCloseFile(file);
- return buffer;
-}
-
-/*
-=================
-S_WAV_CodecOpenStream
-=================
-*/
-snd_stream_t *S_WAV_CodecOpenStream(const char *filename)
-{
- snd_stream_t *rv;
-
- // Open
- rv = S_CodecUtilOpen(filename, &wav_codec);
- if(!rv)
- return NULL;
-
- // Read the RIFF header
- if(!S_ReadRIFFHeader(rv->file, &rv->info))
- {
- S_CodecUtilClose(&rv);
- return NULL;
- }
-
- return rv;
-}
-
-/*
-=================
-S_WAV_CodecCloseStream
-=================
-*/
-void S_WAV_CodecCloseStream(snd_stream_t *stream)
-{
- S_CodecUtilClose(&stream);
-}
-
-/*
-=================
-S_WAV_CodecReadStream
-=================
-*/
-int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
-{
- int remaining = stream->info.size - stream->pos;
- int samples;
-
- if(remaining <= 0)
- return 0;
- if(bytes > remaining)
- bytes = remaining;
- stream->pos += bytes;
- samples = (bytes / stream->info.width) / stream->info.channels;
- FS_Read(buffer, bytes, stream->file);
- S_ByteSwapRawSamples(samples, stream->info.width, stream->info.channels, buffer);
- return bytes;
-}
diff --git a/engine/code/client/snd_dma.c b/engine/code/client/snd_dma.c
deleted file mode 100644
index 428d1d4..0000000
--- a/engine/code/client/snd_dma.c
+++ /dev/null
@@ -1,1541 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: snd_dma.c
- *
- * desc: main control for any streaming sound output device
- *
- * $Archive: /MissionPack/code/client/snd_dma.c $
- *
- *****************************************************************************/
-
-#include "snd_local.h"
-#include "snd_codec.h"
-#include "client.h"
-
-void S_Update_( void );
-void S_Base_StopAllSounds(void);
-void S_Base_StopBackgroundTrack( void );
-
-snd_stream_t *s_backgroundStream = NULL;
-static char s_backgroundLoop[MAX_QPATH];
-//static char s_backgroundMusic[MAX_QPATH]; //TTimo: unused
-
-
-// =======================================================================
-// Internal sound data & structures
-// =======================================================================
-
-// only begin attenuating sound volumes when outside the FULLVOLUME range
-#define SOUND_FULLVOLUME 80
-
-#define SOUND_ATTENUATE 0.0008f
-
-channel_t s_channels[MAX_CHANNELS];
-channel_t loop_channels[MAX_CHANNELS];
-int numLoopChannels;
-
-static int s_soundStarted;
-static qboolean s_soundMuted;
-
-dma_t dma;
-
-static int listener_number;
-static vec3_t listener_origin;
-static vec3_t listener_axis[3];
-
-int s_soundtime; // sample PAIRS
-int s_paintedtime; // sample PAIRS
-
-// MAX_SFX may be larger than MAX_SOUNDS because
-// of custom player sounds
-#define MAX_SFX 4096
-sfx_t s_knownSfx[MAX_SFX];
-int s_numSfx = 0;
-
-#define LOOP_HASH 128
-static sfx_t *sfxHash[LOOP_HASH];
-
-cvar_t *s_testsound;
-cvar_t *s_khz;
-cvar_t *s_show;
-cvar_t *s_mixahead;
-cvar_t *s_mixPreStep;
-
-static loopSound_t loopSounds[MAX_GENTITIES];
-static channel_t *freelist = NULL;
-
-int s_rawend[MAX_RAW_STREAMS];
-portable_samplepair_t s_rawsamples[MAX_RAW_STREAMS][MAX_RAW_SAMPLES];
-
-
-// ====================================================================
-// User-setable variables
-// ====================================================================
-
-
-void S_Base_SoundInfo(void) {
- Com_Printf("----- Sound Info -----\n" );
- if (!s_soundStarted) {
- Com_Printf ("sound system not started\n");
- } else {
- Com_Printf("%5d stereo\n", dma.channels - 1);
- Com_Printf("%5d samples\n", dma.samples);
- Com_Printf("%5d samplebits\n", dma.samplebits);
- Com_Printf("%5d submission_chunk\n", dma.submission_chunk);
- Com_Printf("%5d speed\n", dma.speed);
- Com_Printf("%p dma buffer\n", dma.buffer);
- if ( s_backgroundStream ) {
- Com_Printf("Background file: %s\n", s_backgroundLoop );
- } else {
- Com_Printf("No background file.\n" );
- }
-
- }
- Com_Printf("----------------------\n" );
-}
-
-
-#ifdef USE_VOIP
-static
-void S_Base_StartCapture( void )
-{
- // !!! FIXME: write me.
-}
-
-static
-int S_Base_AvailableCaptureSamples( void )
-{
- // !!! FIXME: write me.
- return 0;
-}
-
-static
-void S_Base_Capture( int samples, byte *data )
-{
- // !!! FIXME: write me.
-}
-
-static
-void S_Base_StopCapture( void )
-{
- // !!! FIXME: write me.
-}
-
-static
-void S_Base_MasterGain( float val )
-{
- // !!! FIXME: write me.
-}
-#endif
-
-
-
-/*
-=================
-S_Base_SoundList
-=================
-*/
-void S_Base_SoundList( void ) {
- int i;
- sfx_t *sfx;
- int size, total;
- char type[4][16];
- char mem[2][16];
-
- strcpy(type[0], "16bit");
- strcpy(type[1], "adpcm");
- strcpy(type[2], "daub4");
- strcpy(type[3], "mulaw");
- strcpy(mem[0], "paged out");
- strcpy(mem[1], "resident ");
- total = 0;
- for (sfx=s_knownSfx, i=0 ; i<s_numSfx ; i++, sfx++) {
- size = sfx->soundLength;
- total += size;
- Com_Printf("%6i[%s] : %s[%s]\n", size, type[sfx->soundCompressionMethod],
- sfx->soundName, mem[sfx->inMemory] );
- }
- Com_Printf ("Total resident: %i\n", total);
- S_DisplayFreeMemory();
-}
-
-
-
-void S_ChannelFree(channel_t *v) {
- v->thesfx = NULL;
- *(channel_t **)v = freelist;
- freelist = (channel_t*)v;
-}
-
-channel_t* S_ChannelMalloc( void ) {
- channel_t *v;
- if (freelist == NULL) {
- return NULL;
- }
- v = freelist;
- freelist = *(channel_t **)freelist;
- v->allocTime = Com_Milliseconds();
- return v;
-}
-
-void S_ChannelSetup( void ) {
- channel_t *p, *q;
-
- // clear all the sounds so they don't
- Com_Memset( s_channels, 0, sizeof( s_channels ) );
-
- p = s_channels;;
- q = p + MAX_CHANNELS;
- while (--q > p) {
- *(channel_t **)q = q-1;
- }
-
- *(channel_t **)q = NULL;
- freelist = p + MAX_CHANNELS - 1;
- Com_DPrintf("Channel memory manager started\n");
-}
-
-
-
-// =======================================================================
-// Load a sound
-// =======================================================================
-
-/*
-================
-return a hash value for the sfx name
-================
-*/
-static long S_HashSFXName(const char *name) {
- int i;
- long hash;
- char letter;
-
- hash = 0;
- i = 0;
- while (name[i] != '\0') {
- letter = tolower(name[i]);
- if (letter =='.') break; // don't include extension
- if (letter =='\\') letter = '/'; // damn path names
- hash+=(long)(letter)*(i+119);
- i++;
- }
- hash &= (LOOP_HASH-1);
- return hash;
-}
-
-/*
-==================
-S_FindName
-
-Will allocate a new sfx if it isn't found
-==================
-*/
-static sfx_t *S_FindName( const char *name ) {
- int i;
- int hash;
-
- sfx_t *sfx;
-
- if (!name) {
- Com_Error (ERR_FATAL, "S_FindName: NULL\n");
- }
- if (!name[0]) {
- Com_Error (ERR_FATAL, "S_FindName: empty name\n");
- }
-
- if (strlen(name) >= MAX_QPATH) {
- Com_Error (ERR_FATAL, "Sound name too long: %s", name);
- }
-
- hash = S_HashSFXName(name);
-
- sfx = sfxHash[hash];
- // see if already loaded
- while (sfx) {
- if (!Q_stricmp(sfx->soundName, name) ) {
- return sfx;
- }
- sfx = sfx->next;
- }
-
- // find a free sfx
- for (i=0 ; i < s_numSfx ; i++) {
- if (!s_knownSfx[i].soundName[0]) {
- break;
- }
- }
-
- if (i == s_numSfx) {
- if (s_numSfx == MAX_SFX) {
- Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
- }
- s_numSfx++;
- }
-
- sfx = &s_knownSfx[i];
- Com_Memset (sfx, 0, sizeof(*sfx));
- strcpy (sfx->soundName, name);
-
- sfx->next = sfxHash[hash];
- sfxHash[hash] = sfx;
-
- return sfx;
-}
-
-/*
-=================
-S_DefaultSound
-=================
-*/
-void S_DefaultSound( sfx_t *sfx ) {
-
- int i;
-
- sfx->soundLength = 512;
- sfx->soundData = SND_malloc();
- sfx->soundData->next = NULL;
-
-
- for ( i = 0 ; i < sfx->soundLength ; i++ ) {
- sfx->soundData->sndChunk[i] = i;
- }
-}
-
-/*
-===================
-S_DisableSounds
-
-Disables sounds until the next S_BeginRegistration.
-This is called when the hunk is cleared and the sounds
-are no longer valid.
-===================
-*/
-void S_Base_DisableSounds( void ) {
- S_Base_StopAllSounds();
- s_soundMuted = qtrue;
-}
-
-/*
-==================
-S_RegisterSound
-
-Creates a default buzz sound if the file can't be loaded
-==================
-*/
-sfxHandle_t S_Base_RegisterSound( const char *name, qboolean compressed ) {
- sfx_t *sfx;
-
- compressed = qfalse;
- if (!s_soundStarted) {
- return 0;
- }
-
- if ( strlen( name ) >= MAX_QPATH ) {
- Com_Printf( "Sound name exceeds MAX_QPATH\n" );
- return 0;
- }
-
- sfx = S_FindName( name );
- if ( sfx->soundData ) {
- if ( sfx->defaultSound ) {
- Com_Printf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->soundName );
- return 0;
- }
- return sfx - s_knownSfx;
- }
-
- sfx->inMemory = qfalse;
- sfx->soundCompressed = compressed;
-
- S_memoryLoad(sfx);
-
- if ( sfx->defaultSound ) {
- Com_Printf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->soundName );
- return 0;
- }
-
- return sfx - s_knownSfx;
-}
-
-/*
-=====================
-S_BeginRegistration
-
-=====================
-*/
-void S_Base_BeginRegistration( void ) {
- s_soundMuted = qfalse; // we can play again
-
- if (s_numSfx == 0) {
- SND_setup();
-
- s_numSfx = 0;
- Com_Memset( s_knownSfx, 0, sizeof( s_knownSfx ) );
- Com_Memset(sfxHash, 0, sizeof(sfx_t *)*LOOP_HASH);
-
- S_Base_RegisterSound("sound/feedback/hit.wav", qfalse); // changed to a sound in baseq3
- }
-}
-
-void S_memoryLoad(sfx_t *sfx) {
- // load the sound file
- if ( !S_LoadSound ( sfx ) ) {
-// Com_Printf( S_COLOR_YELLOW "WARNING: couldn't load sound: %s\n", sfx->soundName );
- sfx->defaultSound = qtrue;
- }
- sfx->inMemory = qtrue;
-}
-
-//=============================================================================
-
-/*
-=================
-S_SpatializeOrigin
-
-Used for spatializing s_channels
-=================
-*/
-void S_SpatializeOrigin (vec3_t origin, int master_vol, int *left_vol, int *right_vol)
-{
- vec_t dot;
- vec_t dist;
- vec_t lscale, rscale, scale;
- vec3_t source_vec;
- vec3_t vec;
-
- const float dist_mult = SOUND_ATTENUATE;
-
- // calculate stereo seperation and distance attenuation
- VectorSubtract(origin, listener_origin, source_vec);
-
- dist = VectorNormalize(source_vec);
- dist -= SOUND_FULLVOLUME;
- if (dist < 0)
- dist = 0; // close enough to be at full volume
- dist *= dist_mult; // different attenuation levels
-
- VectorRotate( source_vec, listener_axis, vec );
-
- dot = -vec[1];
-
- if (dma.channels == 1)
- { // no attenuation = no spatialization
- rscale = 1.0;
- lscale = 1.0;
- }
- else
- {
- rscale = 0.5 * (1.0 + dot);
- lscale = 0.5 * (1.0 - dot);
- if ( rscale < 0 ) {
- rscale = 0;
- }
- if ( lscale < 0 ) {
- lscale = 0;
- }
- }
-
- // add in distance effect
- scale = (1.0 - dist) * rscale;
- *right_vol = (master_vol * scale);
- if (*right_vol < 0)
- *right_vol = 0;
-
- scale = (1.0 - dist) * lscale;
- *left_vol = (master_vol * scale);
- if (*left_vol < 0)
- *left_vol = 0;
-}
-
-// =======================================================================
-// Start a sound effect
-// =======================================================================
-
-/*
-====================
-S_StartSound
-
-Validates the parms and ques the sound up
-if pos is NULL, the sound will be dynamically sourced from the entity
-Entchannel 0 will never override a playing sound
-====================
-*/
-void S_Base_StartSound(vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfxHandle ) {
- channel_t *ch;
- sfx_t *sfx;
- int i, oldest, chosen, time;
- int inplay, allowed;
-
- if ( !s_soundStarted || s_soundMuted ) {
- return;
- }
-
- if ( !origin && ( entityNum < 0 || entityNum > MAX_GENTITIES ) ) {
- Com_Error( ERR_DROP, "S_StartSound: bad entitynum %i", entityNum );
- }
-
- if ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {
- Com_Printf( S_COLOR_YELLOW "S_StartSound: handle %i out of range\n", sfxHandle );
- return;
- }
-
- sfx = &s_knownSfx[ sfxHandle ];
-
- if (sfx->inMemory == qfalse) {
- S_memoryLoad(sfx);
- }
-
- if ( s_show->integer == 1 ) {
- Com_Printf( "%i : %s\n", s_paintedtime, sfx->soundName );
- }
-
- time = Com_Milliseconds();
-
-// Com_Printf("playing %s\n", sfx->soundName);
- // pick a channel to play on
-
- allowed = 4;
- if (entityNum == listener_number) {
- allowed = 8;
- }
-
- ch = s_channels;
- inplay = 0;
- for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {
- if (ch->entnum == entityNum && ch->thesfx == sfx) {
- if (time - ch->allocTime < 50) {
-// if (Cvar_VariableValue( "cg_showmiss" )) {
-// Com_Printf("double sound start\n");
-// }
- return;
- }
- inplay++;
- }
- }
-
- if (inplay>allowed) {
- return;
- }
-
- sfx->lastTimeUsed = time;
-
- ch = S_ChannelMalloc(); // entityNum, entchannel);
- if (!ch) {
- ch = s_channels;
-
- oldest = sfx->lastTimeUsed;
- chosen = -1;
- for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {
- if (ch->entnum != listener_number && ch->entnum == entityNum && ch->allocTime<oldest && ch->entchannel != CHAN_ANNOUNCER) {
- oldest = ch->allocTime;
- chosen = i;
- }
- }
- if (chosen == -1) {
- ch = s_channels;
- for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {
- if (ch->entnum != listener_number && ch->allocTime<oldest && ch->entchannel != CHAN_ANNOUNCER) {
- oldest = ch->allocTime;
- chosen = i;
- }
- }
- if (chosen == -1) {
- ch = s_channels;
- if (ch->entnum == listener_number) {
- for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {
- if (ch->allocTime<oldest) {
- oldest = ch->allocTime;
- chosen = i;
- }
- }
- }
- if (chosen == -1) {
- Com_Printf("dropping sound\n");
- return;
- }
- }
- }
- ch = &s_channels[chosen];
- ch->allocTime = sfx->lastTimeUsed;
- }
-
- if (origin) {
- VectorCopy (origin, ch->origin);
- ch->fixed_origin = qtrue;
- } else {
- ch->fixed_origin = qfalse;
- }
-
- ch->master_vol = 127;
- ch->entnum = entityNum;
- ch->thesfx = sfx;
- ch->startSample = START_SAMPLE_IMMEDIATE;
- ch->entchannel = entchannel;
- ch->leftvol = ch->master_vol; // these will get calced at next spatialize
- ch->rightvol = ch->master_vol; // unless the game isn't running
- ch->doppler = qfalse;
-}
-
-
-/*
-==================
-S_StartLocalSound
-==================
-*/
-void S_Base_StartLocalSound( sfxHandle_t sfxHandle, int channelNum ) {
- if ( !s_soundStarted || s_soundMuted ) {
- return;
- }
-
- if ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {
- Com_Printf( S_COLOR_YELLOW "S_StartLocalSound: handle %i out of range\n", sfxHandle );
- return;
- }
-
- S_Base_StartSound (NULL, listener_number, channelNum, sfxHandle );
-}
-
-
-/*
-==================
-S_ClearSoundBuffer
-
-If we are about to perform file access, clear the buffer
-so sound doesn't stutter.
-==================
-*/
-void S_Base_ClearSoundBuffer( void ) {
- int clear;
-
- if (!s_soundStarted)
- return;
-
- // stop looping sounds
- Com_Memset(loopSounds, 0, MAX_GENTITIES*sizeof(loopSound_t));
- Com_Memset(loop_channels, 0, MAX_CHANNELS*sizeof(channel_t));
- numLoopChannels = 0;
-
- S_ChannelSetup();
-
- Com_Memset(s_rawend, '\0', sizeof (s_rawend));
-
- if (dma.samplebits == 8)
- clear = 0x80;
- else
- clear = 0;
-
- SNDDMA_BeginPainting ();
- if (dma.buffer)
- Com_Memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
- SNDDMA_Submit ();
-}
-
-/*
-==================
-S_StopAllSounds
-==================
-*/
-void S_Base_StopAllSounds(void) {
- if ( !s_soundStarted ) {
- return;
- }
-
- // stop the background music
- S_Base_StopBackgroundTrack();
-
- S_Base_ClearSoundBuffer ();
-}
-
-/*
-==============================================================
-
-continuous looping sounds are added each frame
-
-==============================================================
-*/
-
-void S_Base_StopLoopingSound(int entityNum) {
- loopSounds[entityNum].active = qfalse;
-// loopSounds[entityNum].sfx = 0;
- loopSounds[entityNum].kill = qfalse;
-}
-
-/*
-==================
-S_ClearLoopingSounds
-
-==================
-*/
-void S_Base_ClearLoopingSounds( qboolean killall ) {
- int i;
- for ( i = 0 ; i < MAX_GENTITIES ; i++) {
- if (killall || loopSounds[i].kill == qtrue || (loopSounds[i].sfx && loopSounds[i].sfx->soundLength == 0)) {
- loopSounds[i].kill = qfalse;
- S_Base_StopLoopingSound(i);
- }
- }
- numLoopChannels = 0;
-}
-
-/*
-==================
-S_AddLoopingSound
-
-Called during entity generation for a frame
-Include velocity in case I get around to doing doppler...
-==================
-*/
-void S_Base_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle ) {
- sfx_t *sfx;
-
- if ( !s_soundStarted || s_soundMuted ) {
- return;
- }
-
- if ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {
- Com_Printf( S_COLOR_YELLOW "S_AddLoopingSound: handle %i out of range\n", sfxHandle );
- return;
- }
-
- sfx = &s_knownSfx[ sfxHandle ];
-
- if (sfx->inMemory == qfalse) {
- S_memoryLoad(sfx);
- }
-
- if ( !sfx->soundLength ) {
- Com_Error( ERR_DROP, "%s has length 0", sfx->soundName );
- }
-
- VectorCopy( origin, loopSounds[entityNum].origin );
- VectorCopy( velocity, loopSounds[entityNum].velocity );
- loopSounds[entityNum].active = qtrue;
- loopSounds[entityNum].kill = qtrue;
- loopSounds[entityNum].doppler = qfalse;
- loopSounds[entityNum].oldDopplerScale = 1.0;
- loopSounds[entityNum].dopplerScale = 1.0;
- loopSounds[entityNum].sfx = sfx;
-
- if (s_doppler->integer && VectorLengthSquared(velocity)>0.0) {
- vec3_t out;
- float lena, lenb;
-
- loopSounds[entityNum].doppler = qtrue;
- lena = DistanceSquared(loopSounds[listener_number].origin, loopSounds[entityNum].origin);
- VectorAdd(loopSounds[entityNum].origin, loopSounds[entityNum].velocity, out);
- lenb = DistanceSquared(loopSounds[listener_number].origin, out);
- if ((loopSounds[entityNum].framenum+1) != cls.framecount) {
- loopSounds[entityNum].oldDopplerScale = 1.0;
- } else {
- loopSounds[entityNum].oldDopplerScale = loopSounds[entityNum].dopplerScale;
- }
- loopSounds[entityNum].dopplerScale = lenb/(lena*100);
- if (loopSounds[entityNum].dopplerScale<=1.0) {
- loopSounds[entityNum].doppler = qfalse; // don't bother doing the math
- } else if (loopSounds[entityNum].dopplerScale>MAX_DOPPLER_SCALE) {
- loopSounds[entityNum].dopplerScale = MAX_DOPPLER_SCALE;
- }
- }
-
- loopSounds[entityNum].framenum = cls.framecount;
-}
-
-/*
-==================
-S_AddLoopingSound
-
-Called during entity generation for a frame
-Include velocity in case I get around to doing doppler...
-==================
-*/
-void S_Base_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle ) {
- sfx_t *sfx;
-
- if ( !s_soundStarted || s_soundMuted ) {
- return;
- }
-
- if ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {
- Com_Printf( S_COLOR_YELLOW "S_AddRealLoopingSound: handle %i out of range\n", sfxHandle );
- return;
- }
-
- sfx = &s_knownSfx[ sfxHandle ];
-
- if (sfx->inMemory == qfalse) {
- S_memoryLoad(sfx);
- }
-
- if ( !sfx->soundLength ) {
- Com_Error( ERR_DROP, "%s has length 0", sfx->soundName );
- }
- VectorCopy( origin, loopSounds[entityNum].origin );
- VectorCopy( velocity, loopSounds[entityNum].velocity );
- loopSounds[entityNum].sfx = sfx;
- loopSounds[entityNum].active = qtrue;
- loopSounds[entityNum].kill = qfalse;
- loopSounds[entityNum].doppler = qfalse;
-}
-
-
-
-/*
-==================
-S_AddLoopSounds
-
-Spatialize all of the looping sounds.
-All sounds are on the same cycle, so any duplicates can just
-sum up the channel multipliers.
-==================
-*/
-void S_AddLoopSounds (void) {
- int i, j, time;
- int left_total, right_total, left, right;
- channel_t *ch;
- loopSound_t *loop, *loop2;
- static int loopFrame;
-
-
- numLoopChannels = 0;
-
- time = Com_Milliseconds();
-
- loopFrame++;
- for ( i = 0 ; i < MAX_GENTITIES ; i++) {
- loop = &loopSounds[i];
- if ( !loop->active || loop->mergeFrame == loopFrame ) {
- continue; // already merged into an earlier sound
- }
-
- if (loop->kill) {
- S_SpatializeOrigin( loop->origin, 127, &left_total, &right_total); // 3d
- } else {
- S_SpatializeOrigin( loop->origin, 90, &left_total, &right_total); // sphere
- }
-
- loop->sfx->lastTimeUsed = time;
-
- for (j=(i+1); j< MAX_GENTITIES ; j++) {
- loop2 = &loopSounds[j];
- if ( !loop2->active || loop2->doppler || loop2->sfx != loop->sfx) {
- continue;
- }
- loop2->mergeFrame = loopFrame;
-
- if (loop2->kill) {
- S_SpatializeOrigin( loop2->origin, 127, &left, &right); // 3d
- } else {
- S_SpatializeOrigin( loop2->origin, 90, &left, &right); // sphere
- }
-
- loop2->sfx->lastTimeUsed = time;
- left_total += left;
- right_total += right;
- }
- if (left_total == 0 && right_total == 0) {
- continue; // not audible
- }
-
- // allocate a channel
- ch = &loop_channels[numLoopChannels];
-
- if (left_total > 255) {
- left_total = 255;
- }
- if (right_total > 255) {
- right_total = 255;
- }
-
- ch->master_vol = 127;
- ch->leftvol = left_total;
- ch->rightvol = right_total;
- ch->thesfx = loop->sfx;
- ch->doppler = loop->doppler;
- ch->dopplerScale = loop->dopplerScale;
- ch->oldDopplerScale = loop->oldDopplerScale;
- numLoopChannels++;
- if (numLoopChannels == MAX_CHANNELS) {
- return;
- }
- }
-}
-
-//=============================================================================
-
-/*
-=================
-S_ByteSwapRawSamples
-
-If raw data has been loaded in little endien binary form, this must be done.
-If raw data was calculated, as with ADPCM, this should not be called.
-=================
-*/
-void S_ByteSwapRawSamples( int samples, int width, int s_channels, const byte *data ) {
- int i;
-
- if ( width != 2 ) {
- return;
- }
- if ( LittleShort( 256 ) == 256 ) {
- return;
- }
-
- if ( s_channels == 2 ) {
- samples <<= 1;
- }
- for ( i = 0 ; i < samples ; i++ ) {
- ((short *)data)[i] = LittleShort( ((short *)data)[i] );
- }
-}
-
-/*
-============
-S_Base_RawSamples
-
-Music streaming
-============
-*/
-void S_Base_RawSamples( int stream, int samples, int rate, int width, int s_channels, const byte *data, float volume ) {
- int i;
- int src, dst;
- float scale;
- int intVolume;
- portable_samplepair_t *rawsamples;
-
- if ( !s_soundStarted || s_soundMuted ) {
- return;
- }
-
- if ( (stream < 0) || (stream >= MAX_RAW_STREAMS) ) {
- return;
- }
- rawsamples = s_rawsamples[stream];
-
- if(s_muted->integer)
- intVolume = 0;
- else
- intVolume = 256 * volume * s_volume->value;
-
- if ( s_rawend[stream] < s_soundtime ) {
- Com_DPrintf( "S_Base_RawSamples: resetting minimum: %i < %i\n", s_rawend[stream], s_soundtime );
- s_rawend[stream] = s_soundtime;
- }
-
- scale = (float)rate / dma.speed;
-
-//Com_Printf ("%i < %i < %i\n", s_soundtime, s_paintedtime, s_rawend[stream]);
- if (s_channels == 2 && width == 2)
- {
- if (scale == 1.0)
- { // optimized case
- for (i=0 ; i<samples ; i++)
- {
- dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1);
- s_rawend[stream]++;
- rawsamples[dst].left = ((short *)data)[i*2] * intVolume;
- rawsamples[dst].right = ((short *)data)[i*2+1] * intVolume;
- }
- }
- else
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1);
- s_rawend[stream]++;
- rawsamples[dst].left = ((short *)data)[src*2] * intVolume;
- rawsamples[dst].right = ((short *)data)[src*2+1] * intVolume;
- }
- }
- }
- else if (s_channels == 1 && width == 2)
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1);
- s_rawend[stream]++;
- rawsamples[dst].left = ((short *)data)[src] * intVolume;
- rawsamples[dst].right = ((short *)data)[src] * intVolume;
- }
- }
- else if (s_channels == 2 && width == 1)
- {
- intVolume *= 256;
-
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1);
- s_rawend[stream]++;
- rawsamples[dst].left = ((char *)data)[src*2] * intVolume;
- rawsamples[dst].right = ((char *)data)[src*2+1] * intVolume;
- }
- }
- else if (s_channels == 1 && width == 1)
- {
- intVolume *= 256;
-
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1);
- s_rawend[stream]++;
- rawsamples[dst].left = (((byte *)data)[src]-128) * intVolume;
- rawsamples[dst].right = (((byte *)data)[src]-128) * intVolume;
- }
- }
-
- if ( s_rawend[stream] > s_soundtime + MAX_RAW_SAMPLES ) {
- Com_DPrintf( "S_Base_RawSamples: overflowed %i > %i\n", s_rawend[stream], s_soundtime );
- }
-}
-
-//=============================================================================
-
-/*
-=====================
-S_UpdateEntityPosition
-
-let the sound system know where an entity currently is
-======================
-*/
-void S_Base_UpdateEntityPosition( int entityNum, const vec3_t origin ) {
- if ( entityNum < 0 || entityNum > MAX_GENTITIES ) {
- Com_Error( ERR_DROP, "S_UpdateEntityPosition: bad entitynum %i", entityNum );
- }
- VectorCopy( origin, loopSounds[entityNum].origin );
-}
-
-
-/*
-============
-S_Respatialize
-
-Change the volumes of all the playing sounds for changes in their positions
-============
-*/
-void S_Base_Respatialize( int entityNum, const vec3_t head, vec3_t axis[3], int inwater ) {
- int i;
- channel_t *ch;
- vec3_t origin;
-
- if ( !s_soundStarted || s_soundMuted ) {
- return;
- }
-
- listener_number = entityNum;
- VectorCopy(head, listener_origin);
- VectorCopy(axis[0], listener_axis[0]);
- VectorCopy(axis[1], listener_axis[1]);
- VectorCopy(axis[2], listener_axis[2]);
-
- // update spatialization for dynamic sounds
- ch = s_channels;
- for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {
- if ( !ch->thesfx ) {
- continue;
- }
- // anything coming from the view entity will always be full volume
- if (ch->entnum == listener_number) {
- ch->leftvol = ch->master_vol;
- ch->rightvol = ch->master_vol;
- } else {
- if (ch->fixed_origin) {
- VectorCopy( ch->origin, origin );
- } else {
- VectorCopy( loopSounds[ ch->entnum ].origin, origin );
- }
-
- S_SpatializeOrigin (origin, ch->master_vol, &ch->leftvol, &ch->rightvol);
- }
- }
-
- // add loopsounds
- S_AddLoopSounds ();
-}
-
-
-/*
-========================
-S_ScanChannelStarts
-
-Returns qtrue if any new sounds were started since the last mix
-========================
-*/
-qboolean S_ScanChannelStarts( void ) {
- channel_t *ch;
- int i;
- qboolean newSamples;
-
- newSamples = qfalse;
- ch = s_channels;
-
- for (i=0; i<MAX_CHANNELS ; i++, ch++) {
- if ( !ch->thesfx ) {
- continue;
- }
- // if this channel was just started this frame,
- // set the sample count to it begins mixing
- // into the very first sample
- if ( ch->startSample == START_SAMPLE_IMMEDIATE ) {
- ch->startSample = s_paintedtime;
- newSamples = qtrue;
- continue;
- }
-
- // if it is completely finished by now, clear it
- if ( ch->startSample + (ch->thesfx->soundLength) <= s_paintedtime ) {
- S_ChannelFree(ch);
- }
- }
-
- return newSamples;
-}
-
-/*
-============
-S_Update
-
-Called once each time through the main loop
-============
-*/
-void S_Base_Update( void ) {
- int i;
- int total;
- channel_t *ch;
-
- if ( !s_soundStarted || s_soundMuted ) {
-// Com_DPrintf ("not started or muted\n");
- return;
- }
-
- //
- // debugging output
- //
- if ( s_show->integer == 2 ) {
- total = 0;
- ch = s_channels;
- for (i=0 ; i<MAX_CHANNELS; i++, ch++) {
- if (ch->thesfx && (ch->leftvol || ch->rightvol) ) {
- Com_Printf ("%d %d %s\n", ch->leftvol, ch->rightvol, ch->thesfx->soundName);
- total++;
- }
- }
-
- Com_Printf ("----(%i)---- painted: %i\n", total, s_paintedtime);
- }
-
- // add raw data from streamed samples
- S_UpdateBackgroundTrack();
-
- // mix some sound
- S_Update_();
-}
-
-void S_GetSoundtime(void)
-{
- int samplepos;
- static int buffers;
- static int oldsamplepos;
- int fullsamples;
-
- fullsamples = dma.samples / dma.channels;
-
- if( CL_VideoRecording( ) )
- {
- s_soundtime += (int)ceil( dma.speed / cl_aviFrameRate->value );
- return;
- }
-
- // it is possible to miscount buffers if it has wrapped twice between
- // calls to S_Update. Oh well.
- samplepos = SNDDMA_GetDMAPos();
- if (samplepos < oldsamplepos)
- {
- buffers++; // buffer wrapped
-
- if (s_paintedtime > 0x40000000)
- { // time to chop things off to avoid 32 bit limits
- buffers = 0;
- s_paintedtime = fullsamples;
- S_Base_StopAllSounds ();
- }
- }
- oldsamplepos = samplepos;
-
- s_soundtime = buffers*fullsamples + samplepos/dma.channels;
-
-#if 0
-// check to make sure that we haven't overshot
- if (s_paintedtime < s_soundtime)
- {
- Com_DPrintf ("S_Update_ : overflow\n");
- s_paintedtime = s_soundtime;
- }
-#endif
-
- if ( dma.submission_chunk < 256 ) {
- s_paintedtime = s_soundtime + s_mixPreStep->value * dma.speed;
- } else {
- s_paintedtime = s_soundtime + dma.submission_chunk;
- }
-}
-
-
-void S_Update_(void) {
- unsigned endtime;
- int samps;
- static float lastTime = 0.0f;
- float ma, op;
- float thisTime, sane;
- static int ot = -1;
-
- if ( !s_soundStarted || s_soundMuted ) {
- return;
- }
-
- thisTime = Com_Milliseconds();
-
- // Updates s_soundtime
- S_GetSoundtime();
-
- if (s_soundtime == ot) {
- return;
- }
- ot = s_soundtime;
-
- // clear any sound effects that end before the current time,
- // and start any new sounds
- S_ScanChannelStarts();
-
- sane = thisTime - lastTime;
- if (sane<11) {
- sane = 11; // 85hz
- }
-
- ma = s_mixahead->value * dma.speed;
- op = s_mixPreStep->value + sane*dma.speed*0.01;
-
- if (op < ma) {
- ma = op;
- }
-
- // mix ahead of current position
- endtime = s_soundtime + ma;
-
- // mix to an even submission block size
- endtime = (endtime + dma.submission_chunk-1)
- & ~(dma.submission_chunk-1);
-
- // never mix more than the complete buffer
- samps = dma.samples >> (dma.channels-1);
- if (endtime - s_soundtime > samps)
- endtime = s_soundtime + samps;
-
-
-
- SNDDMA_BeginPainting ();
-
- S_PaintChannels (endtime);
-
- SNDDMA_Submit ();
-
- lastTime = thisTime;
-}
-
-
-
-/*
-===============================================================================
-
-background music functions
-
-===============================================================================
-*/
-
-/*
-======================
-S_StopBackgroundTrack
-======================
-*/
-void S_Base_StopBackgroundTrack( void ) {
- if(!s_backgroundStream)
- return;
- S_CodecCloseStream(s_backgroundStream);
- s_backgroundStream = NULL;
- s_rawend[0] = 0;
-}
-
-/*
-======================
-S_StartBackgroundTrack
-======================
-*/
-void S_Base_StartBackgroundTrack( const char *intro, const char *loop ){
- if ( !intro ) {
- intro = "";
- }
- if ( !loop || !loop[0] ) {
- loop = intro;
- }
- Com_DPrintf( "S_StartBackgroundTrack( %s, %s )\n", intro, loop );
-
- if(!*intro)
- {
- S_Base_StopBackgroundTrack();
- return;
- }
-
- if( !loop ) {
- s_backgroundLoop[0] = 0;
- } else {
- Q_strncpyz( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) );
- }
-
- // close the background track, but DON'T reset s_rawend
- // if restarting the same back ground track
- if(s_backgroundStream)
- {
- S_CodecCloseStream(s_backgroundStream);
- s_backgroundStream = NULL;
- }
-
- // Open stream
- s_backgroundStream = S_CodecOpenStream(intro);
- if(!s_backgroundStream) {
- Com_Printf( S_COLOR_YELLOW "WARNING: couldn't open music file %s\n", intro );
- return;
- }
-
- if(s_backgroundStream->info.channels != 2 || s_backgroundStream->info.rate != 22050) {
- Com_Printf(S_COLOR_YELLOW "WARNING: music file %s is not 22k stereo\n", intro );
- }
-}
-
-/*
-======================
-S_UpdateBackgroundTrack
-======================
-*/
-void S_UpdateBackgroundTrack( void ) {
- int bufferSamples;
- int fileSamples;
- byte raw[30000]; // just enough to fit in a mac stack frame
- int fileBytes;
- int r;
-
- if(!s_backgroundStream) {
- return;
- }
-
- // don't bother playing anything if musicvolume is 0
- if ( s_musicVolume->value <= 0 ) {
- return;
- }
-
- // see how many samples should be copied into the raw buffer
- if ( s_rawend[0] < s_soundtime ) {
- s_rawend[0] = s_soundtime;
- }
-
- while ( s_rawend[0] < s_soundtime + MAX_RAW_SAMPLES ) {
- bufferSamples = MAX_RAW_SAMPLES - (s_rawend[0] - s_soundtime);
-
- // decide how much data needs to be read from the file
- fileSamples = bufferSamples * s_backgroundStream->info.rate / dma.speed;
-
- if (!fileSamples)
- return;
-
- // our max buffer size
- fileBytes = fileSamples * (s_backgroundStream->info.width * s_backgroundStream->info.channels);
- if ( fileBytes > sizeof(raw) ) {
- fileBytes = sizeof(raw);
- fileSamples = fileBytes / (s_backgroundStream->info.width * s_backgroundStream->info.channels);
- }
-
- // Read
- r = S_CodecReadStream(s_backgroundStream, fileBytes, raw);
- if(r < fileBytes)
- {
- fileBytes = r;
- fileSamples = r / (s_backgroundStream->info.width * s_backgroundStream->info.channels);
- }
-
- if(r > 0)
- {
- // add to raw buffer
- S_Base_RawSamples( 0, fileSamples, s_backgroundStream->info.rate,
- s_backgroundStream->info.width, s_backgroundStream->info.channels, raw, s_musicVolume->value );
- }
- else
- {
- // loop
- if(s_backgroundLoop[0])
- {
- S_CodecCloseStream(s_backgroundStream);
- s_backgroundStream = NULL;
- S_Base_StartBackgroundTrack( s_backgroundLoop, s_backgroundLoop );
- if(!s_backgroundStream)
- return;
- }
- else
- {
- S_Base_StopBackgroundTrack();
- return;
- }
- }
-
- }
-}
-
-
-/*
-======================
-S_FreeOldestSound
-======================
-*/
-
-void S_FreeOldestSound( void ) {
- int i, oldest, used;
- sfx_t *sfx;
- sndBuffer *buffer, *nbuffer;
-
- oldest = Com_Milliseconds();
- used = 0;
-
- for (i=1 ; i < s_numSfx ; i++) {
- sfx = &s_knownSfx[i];
- if (sfx->inMemory && sfx->lastTimeUsed<oldest) {
- used = i;
- oldest = sfx->lastTimeUsed;
- }
- }
-
- sfx = &s_knownSfx[used];
-
- Com_DPrintf("S_FreeOldestSound: freeing sound %s\n", sfx->soundName);
-
- buffer = sfx->soundData;
- while(buffer != NULL) {
- nbuffer = buffer->next;
- SND_free(buffer);
- buffer = nbuffer;
- }
- sfx->inMemory = qfalse;
- sfx->soundData = NULL;
-}
-
-// =======================================================================
-// Shutdown sound engine
-// =======================================================================
-
-void S_Base_Shutdown( void ) {
- if ( !s_soundStarted ) {
- return;
- }
-
- SNDDMA_Shutdown();
-
- s_soundStarted = 0;
-
- Cmd_RemoveCommand("s_info");
-}
-
-/*
-================
-S_Init
-================
-*/
-qboolean S_Base_Init( soundInterface_t *si ) {
- qboolean r;
-
- if( !si ) {
- return qfalse;
- }
-
- s_khz = Cvar_Get ("s_khz", "22", CVAR_ARCHIVE);
- s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
- s_mixPreStep = Cvar_Get ("s_mixPreStep", "0.05", CVAR_ARCHIVE);
- s_show = Cvar_Get ("s_show", "0", CVAR_CHEAT);
- s_testsound = Cvar_Get ("s_testsound", "0", CVAR_CHEAT);
-
- r = SNDDMA_Init();
-
- if ( r ) {
- s_soundStarted = 1;
- s_soundMuted = 1;
-// s_numSfx = 0;
-
- Com_Memset(sfxHash, 0, sizeof(sfx_t *)*LOOP_HASH);
-
- s_soundtime = 0;
- s_paintedtime = 0;
-
- S_Base_StopAllSounds( );
- } else {
- return qfalse;
- }
-
- si->Shutdown = S_Base_Shutdown;
- si->StartSound = S_Base_StartSound;
- si->StartLocalSound = S_Base_StartLocalSound;
- si->StartBackgroundTrack = S_Base_StartBackgroundTrack;
- si->StopBackgroundTrack = S_Base_StopBackgroundTrack;
- si->RawSamples = S_Base_RawSamples;
- si->StopAllSounds = S_Base_StopAllSounds;
- si->ClearLoopingSounds = S_Base_ClearLoopingSounds;
- si->AddLoopingSound = S_Base_AddLoopingSound;
- si->AddRealLoopingSound = S_Base_AddRealLoopingSound;
- si->StopLoopingSound = S_Base_StopLoopingSound;
- si->Respatialize = S_Base_Respatialize;
- si->UpdateEntityPosition = S_Base_UpdateEntityPosition;
- si->Update = S_Base_Update;
- si->DisableSounds = S_Base_DisableSounds;
- si->BeginRegistration = S_Base_BeginRegistration;
- si->RegisterSound = S_Base_RegisterSound;
- si->ClearSoundBuffer = S_Base_ClearSoundBuffer;
- si->SoundInfo = S_Base_SoundInfo;
- si->SoundList = S_Base_SoundList;
-
-#ifdef USE_VOIP
- si->StartCapture = S_Base_StartCapture;
- si->AvailableCaptureSamples = S_Base_AvailableCaptureSamples;
- si->Capture = S_Base_Capture;
- si->StopCapture = S_Base_StopCapture;
- si->MasterGain = S_Base_MasterGain;
-#endif
-
- return qtrue;
-}
diff --git a/engine/code/client/snd_local.h b/engine/code/client/snd_local.h
deleted file mode 100644
index 775e576..0000000
--- a/engine/code/client/snd_local.h
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// snd_local.h -- private sound definations
-
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-#include "snd_public.h"
-
-#define PAINTBUFFER_SIZE 4096 // this is in samples
-
-#define SND_CHUNK_SIZE 1024 // samples
-#define SND_CHUNK_SIZE_FLOAT (SND_CHUNK_SIZE/2) // floats
-#define SND_CHUNK_SIZE_BYTE (SND_CHUNK_SIZE*2) // floats
-
-typedef struct {
- int left; // the final values will be clamped to +/- 0x00ffff00 and shifted down
- int right;
-} portable_samplepair_t;
-
-typedef struct adpcm_state {
- short sample; /* Previous output value */
- char index; /* Index into stepsize table */
-} adpcm_state_t;
-
-typedef struct sndBuffer_s {
- short sndChunk[SND_CHUNK_SIZE];
- struct sndBuffer_s *next;
- int size;
- adpcm_state_t adpcm;
-} sndBuffer;
-
-typedef struct sfx_s {
- sndBuffer *soundData;
- qboolean defaultSound; // couldn't be loaded, so use buzz
- qboolean inMemory; // not in Memory
- qboolean soundCompressed; // not in Memory
- int soundCompressionMethod;
- int soundLength;
- char soundName[MAX_QPATH];
- int lastTimeUsed;
- struct sfx_s *next;
-} sfx_t;
-
-typedef struct {
- int channels;
- int samples; // mono samples in buffer
- int submission_chunk; // don't mix less than this #
- int samplebits;
- int speed;
- byte *buffer;
-} dma_t;
-
-#define START_SAMPLE_IMMEDIATE 0x7fffffff
-
-#define MAX_DOPPLER_SCALE 50.0f //arbitrary
-
-typedef struct loopSound_s {
- vec3_t origin;
- vec3_t velocity;
- sfx_t *sfx;
- int mergeFrame;
- qboolean active;
- qboolean kill;
- qboolean doppler;
- float dopplerScale;
- float oldDopplerScale;
- int framenum;
-} loopSound_t;
-
-typedef struct
-{
- int allocTime;
- int startSample; // START_SAMPLE_IMMEDIATE = set immediately on next mix
- int entnum; // to allow overriding a specific sound
- int entchannel; // to allow overriding a specific sound
- int leftvol; // 0-255 volume after spatialization
- int rightvol; // 0-255 volume after spatialization
- int master_vol; // 0-255 volume before spatialization
- float dopplerScale;
- float oldDopplerScale;
- vec3_t origin; // only use if fixed_origin is set
- qboolean fixed_origin; // use origin instead of fetching entnum's origin
- sfx_t *thesfx; // sfx structure
- qboolean doppler;
-} channel_t;
-
-
-#define WAV_FORMAT_PCM 1
-
-
-typedef struct {
- int format;
- int rate;
- int width;
- int channels;
- int samples;
- int dataofs; // chunk starts this many bytes from file start
-} wavinfo_t;
-
-// Interface between Q3 sound "api" and the sound backend
-typedef struct
-{
- void (*Shutdown)(void);
- void (*StartSound)( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx );
- void (*StartLocalSound)( sfxHandle_t sfx, int channelNum );
- void (*StartBackgroundTrack)( const char *intro, const char *loop );
- void (*StopBackgroundTrack)( void );
- void (*RawSamples)(int stream, int samples, int rate, int width, int channels, const byte *data, float volume);
- void (*StopAllSounds)( void );
- void (*ClearLoopingSounds)( qboolean killall );
- void (*AddLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
- void (*AddRealLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
- void (*StopLoopingSound)(int entityNum );
- void (*Respatialize)( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
- void (*UpdateEntityPosition)( int entityNum, const vec3_t origin );
- void (*Update)( void );
- void (*DisableSounds)( void );
- void (*BeginRegistration)( void );
- sfxHandle_t (*RegisterSound)( const char *sample, qboolean compressed );
- void (*ClearSoundBuffer)( void );
- void (*SoundInfo)( void );
- void (*SoundList)( void );
-#ifdef USE_VOIP
- void (*StartCapture)( void );
- int (*AvailableCaptureSamples)( void );
- void (*Capture)( int samples, byte *data );
- void (*StopCapture)( void );
- void (*MasterGain)( float gain );
-#endif
-} soundInterface_t;
-
-
-/*
-====================================================================
-
- SYSTEM SPECIFIC FUNCTIONS
-
-====================================================================
-*/
-
-// initializes cycling through a DMA buffer and returns information on it
-qboolean SNDDMA_Init(void);
-
-// gets the current DMA position
-int SNDDMA_GetDMAPos(void);
-
-// shutdown the DMA xfer.
-void SNDDMA_Shutdown(void);
-
-void SNDDMA_BeginPainting (void);
-
-void SNDDMA_Submit(void);
-
-//====================================================================
-
-#define MAX_CHANNELS 96
-
-extern channel_t s_channels[MAX_CHANNELS];
-extern channel_t loop_channels[MAX_CHANNELS];
-extern int numLoopChannels;
-
-extern int s_paintedtime;
-extern vec3_t listener_forward;
-extern vec3_t listener_right;
-extern vec3_t listener_up;
-extern dma_t dma;
-
-#define MAX_RAW_SAMPLES 16384
-#define MAX_RAW_STREAMS 128
-extern portable_samplepair_t s_rawsamples[MAX_RAW_STREAMS][MAX_RAW_SAMPLES];
-extern int s_rawend[MAX_RAW_STREAMS];
-
-extern cvar_t *s_volume;
-extern cvar_t *s_musicVolume;
-extern cvar_t *s_muted;
-extern cvar_t *s_doppler;
-
-extern cvar_t *s_testsound;
-
-qboolean S_LoadSound( sfx_t *sfx );
-
-void SND_free(sndBuffer *v);
-sndBuffer* SND_malloc( void );
-void SND_setup( void );
-
-void S_PaintChannels(int endtime);
-
-void S_memoryLoad(sfx_t *sfx);
-
-// spatializes a channel
-void S_Spatialize(channel_t *ch);
-
-// adpcm functions
-int S_AdpcmMemoryNeeded( const wavinfo_t *info );
-void S_AdpcmEncodeSound( sfx_t *sfx, short *samples );
-void S_AdpcmGetSamples(sndBuffer *chunk, short *to);
-
-// wavelet function
-
-#define SENTINEL_MULAW_ZERO_RUN 127
-#define SENTINEL_MULAW_FOUR_BIT_RUN 126
-
-void S_FreeOldestSound( void );
-
-#define NXStream byte
-
-void encodeWavelet(sfx_t *sfx, short *packets);
-void decodeWavelet( sndBuffer *stream, short *packets);
-
-void encodeMuLaw( sfx_t *sfx, short *packets);
-extern short mulawToShort[256];
-
-extern short *sfxScratchBuffer;
-extern sfx_t *sfxScratchPointer;
-extern int sfxScratchIndex;
-
-qboolean S_Base_Init( soundInterface_t *si );
-
-// OpenAL stuff
-typedef enum
-{
- SRCPRI_AMBIENT = 0, // Ambient sound effects
- SRCPRI_ENTITY, // Entity sound effects
- SRCPRI_ONESHOT, // One-shot sounds
- SRCPRI_LOCAL, // Local sounds
- SRCPRI_STREAM // Streams (music, cutscenes)
-} alSrcPriority_t;
-
-typedef int srcHandle_t;
-
-qboolean S_AL_Init( soundInterface_t *si );
diff --git a/engine/code/client/snd_main.c b/engine/code/client/snd_main.c
deleted file mode 100644
index 7d4ed68..0000000
--- a/engine/code/client/snd_main.c
+++ /dev/null
@@ -1,550 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "client.h"
-#include "snd_codec.h"
-#include "snd_local.h"
-#include "snd_public.h"
-
-cvar_t *s_volume;
-cvar_t *s_muted;
-cvar_t *s_musicVolume;
-cvar_t *s_doppler;
-cvar_t *s_backend;
-cvar_t *s_muteWhenMinimized;
-cvar_t *s_muteWhenUnfocused;
-
-static soundInterface_t si;
-
-/*
-=================
-S_ValidateInterface
-=================
-*/
-static qboolean S_ValidSoundInterface( soundInterface_t *si )
-{
- if( !si->Shutdown ) return qfalse;
- if( !si->StartSound ) return qfalse;
- if( !si->StartLocalSound ) return qfalse;
- if( !si->StartBackgroundTrack ) return qfalse;
- if( !si->StopBackgroundTrack ) return qfalse;
- if( !si->RawSamples ) return qfalse;
- if( !si->StopAllSounds ) return qfalse;
- if( !si->ClearLoopingSounds ) return qfalse;
- if( !si->AddLoopingSound ) return qfalse;
- if( !si->AddRealLoopingSound ) return qfalse;
- if( !si->StopLoopingSound ) return qfalse;
- if( !si->Respatialize ) return qfalse;
- if( !si->UpdateEntityPosition ) return qfalse;
- if( !si->Update ) return qfalse;
- if( !si->DisableSounds ) return qfalse;
- if( !si->BeginRegistration ) return qfalse;
- if( !si->RegisterSound ) return qfalse;
- if( !si->ClearSoundBuffer ) return qfalse;
- if( !si->SoundInfo ) return qfalse;
- if( !si->SoundList ) return qfalse;
-
-#ifdef USE_VOIP
- if( !si->StartCapture ) return qfalse;
- if( !si->AvailableCaptureSamples ) return qfalse;
- if( !si->Capture ) return qfalse;
- if( !si->StopCapture ) return qfalse;
- if( !si->MasterGain ) return qfalse;
-#endif
-
- return qtrue;
-}
-
-/*
-=================
-S_StartSound
-=================
-*/
-void S_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx )
-{
- if( si.StartSound ) {
- si.StartSound( origin, entnum, entchannel, sfx );
- }
-}
-
-/*
-=================
-S_StartLocalSound
-=================
-*/
-void S_StartLocalSound( sfxHandle_t sfx, int channelNum )
-{
- if( si.StartLocalSound ) {
- si.StartLocalSound( sfx, channelNum );
- }
-}
-
-/*
-=================
-S_StartBackgroundTrack
-=================
-*/
-void S_StartBackgroundTrack( const char *intro, const char *loop )
-{
- if( si.StartBackgroundTrack ) {
- si.StartBackgroundTrack( intro, loop );
- }
-}
-
-/*
-=================
-S_StopBackgroundTrack
-=================
-*/
-void S_StopBackgroundTrack( void )
-{
- if( si.StopBackgroundTrack ) {
- si.StopBackgroundTrack( );
- }
-}
-
-/*
-=================
-S_RawSamples
-=================
-*/
-void S_RawSamples (int stream, int samples, int rate, int width, int channels,
- const byte *data, float volume)
-{
- if( si.RawSamples ) {
- si.RawSamples( stream, samples, rate, width, channels, data, volume );
- }
-}
-
-/*
-=================
-S_StopAllSounds
-=================
-*/
-void S_StopAllSounds( void )
-{
- if( si.StopAllSounds ) {
- si.StopAllSounds( );
- }
-}
-
-/*
-=================
-S_ClearLoopingSounds
-=================
-*/
-void S_ClearLoopingSounds( qboolean killall )
-{
- if( si.ClearLoopingSounds ) {
- si.ClearLoopingSounds( killall );
- }
-}
-
-/*
-=================
-S_AddLoopingSound
-=================
-*/
-void S_AddLoopingSound( int entityNum, const vec3_t origin,
- const vec3_t velocity, sfxHandle_t sfx )
-{
- if( si.AddLoopingSound ) {
- si.AddLoopingSound( entityNum, origin, velocity, sfx );
- }
-}
-
-/*
-=================
-S_AddRealLoopingSound
-=================
-*/
-void S_AddRealLoopingSound( int entityNum, const vec3_t origin,
- const vec3_t velocity, sfxHandle_t sfx )
-{
- if( si.AddRealLoopingSound ) {
- si.AddRealLoopingSound( entityNum, origin, velocity, sfx );
- }
-}
-
-/*
-=================
-S_StopLoopingSound
-=================
-*/
-void S_StopLoopingSound( int entityNum )
-{
- if( si.StopLoopingSound ) {
- si.StopLoopingSound( entityNum );
- }
-}
-
-/*
-=================
-S_Respatialize
-=================
-*/
-void S_Respatialize( int entityNum, const vec3_t origin,
- vec3_t axis[3], int inwater )
-{
- if( si.Respatialize ) {
- si.Respatialize( entityNum, origin, axis, inwater );
- }
-}
-
-/*
-=================
-S_UpdateEntityPosition
-=================
-*/
-void S_UpdateEntityPosition( int entityNum, const vec3_t origin )
-{
- if( si.UpdateEntityPosition ) {
- si.UpdateEntityPosition( entityNum, origin );
- }
-}
-
-/*
-=================
-S_Update
-=================
-*/
-void S_Update( void )
-{
- if(s_muted->integer)
- {
- if(!(s_muteWhenMinimized->integer && com_minimized->integer) &&
- !(s_muteWhenUnfocused->integer && com_unfocused->integer))
- {
- s_muted->integer = qfalse;
- s_muted->modified = qtrue;
- }
- }
- else
- {
- if((s_muteWhenMinimized->integer && com_minimized->integer) ||
- (s_muteWhenUnfocused->integer && com_unfocused->integer))
- {
- s_muted->integer = qtrue;
- s_muted->modified = qtrue;
- }
- }
-
- if( si.Update ) {
- si.Update( );
- }
-}
-
-/*
-=================
-S_DisableSounds
-=================
-*/
-void S_DisableSounds( void )
-{
- if( si.DisableSounds ) {
- si.DisableSounds( );
- }
-}
-
-/*
-=================
-S_BeginRegistration
-=================
-*/
-void S_BeginRegistration( void )
-{
- if( si.BeginRegistration ) {
- si.BeginRegistration( );
- }
-}
-
-/*
-=================
-S_RegisterSound
-=================
-*/
-sfxHandle_t S_RegisterSound( const char *sample, qboolean compressed )
-{
- if( si.RegisterSound ) {
- return si.RegisterSound( sample, compressed );
- } else {
- return 0;
- }
-}
-
-/*
-=================
-S_ClearSoundBuffer
-=================
-*/
-void S_ClearSoundBuffer( void )
-{
- if( si.ClearSoundBuffer ) {
- si.ClearSoundBuffer( );
- }
-}
-
-/*
-=================
-S_SoundInfo
-=================
-*/
-void S_SoundInfo( void )
-{
- if( si.SoundInfo ) {
- si.SoundInfo( );
- }
-}
-
-/*
-=================
-S_SoundList
-=================
-*/
-void S_SoundList( void )
-{
- if( si.SoundList ) {
- si.SoundList( );
- }
-}
-
-
-#ifdef USE_VOIP
-/*
-=================
-S_StartCapture
-=================
-*/
-void S_StartCapture( void )
-{
- if( si.StartCapture ) {
- si.StartCapture( );
- }
-}
-
-/*
-=================
-S_AvailableCaptureSamples
-=================
-*/
-int S_AvailableCaptureSamples( void )
-{
- if( si.AvailableCaptureSamples ) {
- return si.AvailableCaptureSamples( );
- }
- return 0;
-}
-
-/*
-=================
-S_Capture
-=================
-*/
-void S_Capture( int samples, byte *data )
-{
- if( si.Capture ) {
- si.Capture( samples, data );
- }
-}
-
-/*
-=================
-S_StopCapture
-=================
-*/
-void S_StopCapture( void )
-{
- if( si.StopCapture ) {
- si.StopCapture( );
- }
-}
-
-/*
-=================
-S_MasterGain
-=================
-*/
-void S_MasterGain( float gain )
-{
- if( si.MasterGain ) {
- si.MasterGain( gain );
- }
-}
-#endif
-
-//=============================================================================
-
-/*
-=================
-S_Play_f
-=================
-*/
-void S_Play_f( void ) {
- int i;
- sfxHandle_t h;
- char name[256];
-
- if( !si.RegisterSound || !si.StartLocalSound ) {
- return;
- }
-
- i = 1;
- while ( i<Cmd_Argc() ) {
- if ( !Q_strrchr(Cmd_Argv(i), '.') ) {
- Com_sprintf( name, sizeof(name), "%s.wav", Cmd_Argv(1) );
- } else {
- Q_strncpyz( name, Cmd_Argv(i), sizeof(name) );
- }
- h = si.RegisterSound( name, qfalse );
- if( h ) {
- si.StartLocalSound( h, CHAN_LOCAL_SOUND );
- }
- i++;
- }
-}
-
-/*
-=================
-S_Music_f
-=================
-*/
-void S_Music_f( void ) {
- int c;
-
- if( !si.StartBackgroundTrack ) {
- return;
- }
-
- c = Cmd_Argc();
-
- if ( c == 2 ) {
- si.StartBackgroundTrack( Cmd_Argv(1), NULL );
- } else if ( c == 3 ) {
- si.StartBackgroundTrack( Cmd_Argv(1), Cmd_Argv(2) );
- } else {
- Com_Printf ("music <musicfile> [loopfile]\n");
- return;
- }
-
-}
-
-/*
-=================
-S_Music_f
-=================
-*/
-void S_StopMusic_f( void )
-{
- if(!si.StopBackgroundTrack)
- return;
-
- si.StopBackgroundTrack();
-}
-
-
-//=============================================================================
-
-/*
-=================
-S_Init
-=================
-*/
-void S_Init( void )
-{
- cvar_t *cv;
- qboolean started = qfalse;
-
- Com_Printf( "------ Initializing Sound ------\n" );
-
- s_volume = Cvar_Get( "s_volume", "0.8", CVAR_ARCHIVE );
- s_musicVolume = Cvar_Get( "s_musicvolume", "0.25", CVAR_ARCHIVE );
- s_muted = Cvar_Get("s_muted", "0", CVAR_ROM);
- s_doppler = Cvar_Get( "s_doppler", "1", CVAR_ARCHIVE );
- s_backend = Cvar_Get( "s_backend", "", CVAR_ROM );
- s_muteWhenMinimized = Cvar_Get( "s_muteWhenMinimized", "0", CVAR_ARCHIVE );
- s_muteWhenUnfocused = Cvar_Get( "s_muteWhenUnfocused", "0", CVAR_ARCHIVE );
-
- cv = Cvar_Get( "s_initsound", "1", 0 );
- if( !cv->integer ) {
- Com_Printf( "Sound disabled.\n" );
- } else {
-
- S_CodecInit( );
-
- Cmd_AddCommand( "play", S_Play_f );
- Cmd_AddCommand( "music", S_Music_f );
- Cmd_AddCommand( "stopmusic", S_StopMusic_f );
- Cmd_AddCommand( "s_list", S_SoundList );
- Cmd_AddCommand( "s_stop", S_StopAllSounds );
- Cmd_AddCommand( "s_info", S_SoundInfo );
-
- cv = Cvar_Get( "s_useOpenAL", "1", CVAR_ARCHIVE );
- if( cv->integer ) {
- //OpenAL
- started = S_AL_Init( &si );
- Cvar_Set( "s_backend", "OpenAL" );
- }
-
- if( !started ) {
- started = S_Base_Init( &si );
- Cvar_Set( "s_backend", "base" );
- }
-
- if( started ) {
- if( !S_ValidSoundInterface( &si ) ) {
- Com_Error( ERR_FATAL, "Sound interface invalid." );
- }
-
- S_SoundInfo( );
- Com_Printf( "Sound initialization successful.\n" );
- } else {
- Com_Printf( "Sound initialization failed.\n" );
- }
- }
-
- Com_Printf( "--------------------------------\n");
-}
-
-/*
-=================
-S_Shutdown
-=================
-*/
-void S_Shutdown( void )
-{
- if( si.Shutdown ) {
- si.Shutdown( );
- }
-
- Com_Memset( &si, 0, sizeof( soundInterface_t ) );
-
- Cmd_RemoveCommand( "play" );
- Cmd_RemoveCommand( "music");
- Cmd_RemoveCommand( "stopmusic");
- Cmd_RemoveCommand( "s_list" );
- Cmd_RemoveCommand( "s_stop" );
- Cmd_RemoveCommand( "s_info" );
-
- S_CodecShutdown( );
-}
-
diff --git a/engine/code/client/snd_mem.c b/engine/code/client/snd_mem.c
deleted file mode 100644
index 8c3f98e..0000000
--- a/engine/code/client/snd_mem.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: snd_mem.c
- *
- * desc: sound caching
- *
- * $Archive: /MissionPack/code/client/snd_mem.c $
- *
- *****************************************************************************/
-
-#include "snd_local.h"
-#include "snd_codec.h"
-
-#define DEF_COMSOUNDMEGS "8"
-
-/*
-===============================================================================
-
-memory management
-
-===============================================================================
-*/
-
-static sndBuffer *buffer = NULL;
-static sndBuffer *freelist = NULL;
-static int inUse = 0;
-static int totalInUse = 0;
-
-short *sfxScratchBuffer = NULL;
-sfx_t *sfxScratchPointer = NULL;
-int sfxScratchIndex = 0;
-
-void SND_free(sndBuffer *v) {
- *(sndBuffer **)v = freelist;
- freelist = (sndBuffer*)v;
- inUse += sizeof(sndBuffer);
-}
-
-sndBuffer* SND_malloc(void) {
- sndBuffer *v;
-redo:
- if (freelist == NULL) {
- S_FreeOldestSound();
- goto redo;
- }
-
- inUse -= sizeof(sndBuffer);
- totalInUse += sizeof(sndBuffer);
-
- v = freelist;
- freelist = *(sndBuffer **)freelist;
- v->next = NULL;
- return v;
-}
-
-void SND_setup(void) {
- sndBuffer *p, *q;
- cvar_t *cv;
- int scs;
-
- cv = Cvar_Get( "com_soundMegs", DEF_COMSOUNDMEGS, CVAR_LATCH | CVAR_ARCHIVE );
-
- scs = (cv->integer*1536);
-
- buffer = malloc(scs*sizeof(sndBuffer) );
- // allocate the stack based hunk allocator
- sfxScratchBuffer = malloc(SND_CHUNK_SIZE * sizeof(short) * 4); //Hunk_Alloc(SND_CHUNK_SIZE * sizeof(short) * 4);
- sfxScratchPointer = NULL;
-
- inUse = scs*sizeof(sndBuffer);
- p = buffer;;
- q = p + scs;
- while (--q > p)
- *(sndBuffer **)q = q-1;
-
- *(sndBuffer **)q = NULL;
- freelist = p + scs - 1;
-
- Com_Printf("Sound memory manager started\n");
-}
-
-/*
-================
-ResampleSfx
-
-resample / decimate to the current source rate
-================
-*/
-static void ResampleSfx( sfx_t *sfx, int inrate, int inwidth, byte *data, qboolean compressed ) {
- int outcount;
- int srcsample;
- float stepscale;
- int i;
- int sample, samplefrac, fracstep;
- int part;
- sndBuffer *chunk;
-
- stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
-
- outcount = sfx->soundLength / stepscale;
- sfx->soundLength = outcount;
-
- samplefrac = 0;
- fracstep = stepscale * 256;
- chunk = sfx->soundData;
-
- for (i=0 ; i<outcount ; i++)
- {
- srcsample = samplefrac >> 8;
- samplefrac += fracstep;
- if( inwidth == 2 ) {
- sample = ( ((short *)data)[srcsample] );
- } else {
- sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
- }
- part = (i&(SND_CHUNK_SIZE-1));
- if (part == 0) {
- sndBuffer *newchunk;
- newchunk = SND_malloc();
- if (chunk == NULL) {
- sfx->soundData = newchunk;
- } else {
- chunk->next = newchunk;
- }
- chunk = newchunk;
- }
-
- chunk->sndChunk[part] = sample;
- }
-}
-
-/*
-================
-ResampleSfx
-
-resample / decimate to the current source rate
-================
-*/
-static int ResampleSfxRaw( short *sfx, int inrate, int inwidth, int samples, byte *data ) {
- int outcount;
- int srcsample;
- float stepscale;
- int i;
- int sample, samplefrac, fracstep;
-
- stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
-
- outcount = samples / stepscale;
-
- samplefrac = 0;
- fracstep = stepscale * 256;
-
- for (i=0 ; i<outcount ; i++)
- {
- srcsample = samplefrac >> 8;
- samplefrac += fracstep;
- if( inwidth == 2 ) {
- sample = LittleShort ( ((short *)data)[srcsample] );
- } else {
- sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
- }
- sfx[i] = sample;
- }
- return outcount;
-}
-
-//=============================================================================
-
-/*
-==============
-S_LoadSound
-
-The filename may be different than sfx->name in the case
-of a forced fallback of a player specific sound
-==============
-*/
-qboolean S_LoadSound( sfx_t *sfx )
-{
- byte *data;
- short *samples;
- snd_info_t info;
-// int size;
-
- // player specific sounds are never directly loaded
- if ( sfx->soundName[0] == '*') {
- return qfalse;
- }
-
- // load it in
- data = S_CodecLoad(sfx->soundName, &info);
- if(!data)
- return qfalse;
-
- if ( info.width == 1 ) {
- Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sfx->soundName);
- }
-
- if ( info.rate != 22050 ) {
- Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz wav file\n", sfx->soundName);
- }
-
- samples = Hunk_AllocateTempMemory(info.samples * sizeof(short) * 2);
-
- sfx->lastTimeUsed = Com_Milliseconds()+1;
-
- // each of these compression schemes works just fine
- // but the 16bit quality is much nicer and with a local
- // install assured we can rely upon the sound memory
- // manager to do the right thing for us and page
- // sound in as needed
-
- if( sfx->soundCompressed == qtrue) {
- sfx->soundCompressionMethod = 1;
- sfx->soundData = NULL;
- sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, data + info.dataofs );
- S_AdpcmEncodeSound(sfx, samples);
-#if 0
- } else if (info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {
- sfx->soundCompressionMethod = 3;
- sfx->soundData = NULL;
- sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
- encodeMuLaw( sfx, samples);
- } else if (info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) {
- sfx->soundCompressionMethod = 2;
- sfx->soundData = NULL;
- sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
- encodeWavelet( sfx, samples);
-#endif
- } else {
- sfx->soundCompressionMethod = 0;
- sfx->soundLength = info.samples;
- sfx->soundData = NULL;
- ResampleSfx( sfx, info.rate, info.width, data + info.dataofs, qfalse );
- }
-
- Hunk_FreeTempMemory(samples);
- Z_Free(data);
-
- return qtrue;
-}
-
-void S_DisplayFreeMemory(void) {
- Com_Printf("%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse);
-}
diff --git a/engine/code/client/snd_mix.c b/engine/code/client/snd_mix.c
deleted file mode 100644
index 11de66d..0000000
--- a/engine/code/client/snd_mix.c
+++ /dev/null
@@ -1,741 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// snd_mix.c -- portable code to mix sounds for snd_dma.c
-
-#include "client.h"
-#include "snd_local.h"
-#if idppc_altivec && !defined(MACOS_X)
-#include <altivec.h>
-#endif
-
-static portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
-static int snd_vol;
-
-int* snd_p;
-int snd_linear_count;
-short* snd_out;
-
-#if !id386 // if configured not to use asm
-
-void S_WriteLinearBlastStereo16 (void)
-{
- int i;
- int val;
-
- for (i=0 ; i<snd_linear_count ; i+=2)
- {
- val = snd_p[i]>>8;
- if (val > 0x7fff)
- snd_out[i] = 0x7fff;
- else if (val < -32768)
- snd_out[i] = -32768;
- else
- snd_out[i] = val;
-
- val = snd_p[i+1]>>8;
- if (val > 0x7fff)
- snd_out[i+1] = 0x7fff;
- else if (val < -32768)
- snd_out[i+1] = -32768;
- else
- snd_out[i+1] = val;
- }
-}
-#elif defined(__GNUC__)
-// uses snd_mixa.s
-void S_WriteLinearBlastStereo16 (void);
-#else
-
-__declspec( naked ) void S_WriteLinearBlastStereo16 (void)
-{
- __asm {
-
- push edi
- push ebx
- mov ecx,ds:dword ptr[snd_linear_count]
- mov ebx,ds:dword ptr[snd_p]
- mov edi,ds:dword ptr[snd_out]
-LWLBLoopTop:
- mov eax,ds:dword ptr[-8+ebx+ecx*4]
- sar eax,8
- cmp eax,07FFFh
- jg LClampHigh
- cmp eax,0FFFF8000h
- jnl LClampDone
- mov eax,0FFFF8000h
- jmp LClampDone
-LClampHigh:
- mov eax,07FFFh
-LClampDone:
- mov edx,ds:dword ptr[-4+ebx+ecx*4]
- sar edx,8
- cmp edx,07FFFh
- jg LClampHigh2
- cmp edx,0FFFF8000h
- jnl LClampDone2
- mov edx,0FFFF8000h
- jmp LClampDone2
-LClampHigh2:
- mov edx,07FFFh
-LClampDone2:
- shl edx,16
- and eax,0FFFFh
- or edx,eax
- mov ds:dword ptr[-4+edi+ecx*2],edx
- sub ecx,2
- jnz LWLBLoopTop
- pop ebx
- pop edi
- ret
- }
-}
-
-#endif
-
-void S_TransferStereo16 (unsigned long *pbuf, int endtime)
-{
- int lpos;
- int ls_paintedtime;
-
- snd_p = (int *) paintbuffer;
- ls_paintedtime = s_paintedtime;
-
- while (ls_paintedtime < endtime)
- {
- // handle recirculating buffer issues
- lpos = ls_paintedtime & ((dma.samples>>1)-1);
-
- snd_out = (short *) pbuf + (lpos<<1);
-
- snd_linear_count = (dma.samples>>1) - lpos;
- if (ls_paintedtime + snd_linear_count > endtime)
- snd_linear_count = endtime - ls_paintedtime;
-
- snd_linear_count <<= 1;
-
- // write a linear blast of samples
- S_WriteLinearBlastStereo16 ();
-
- snd_p += snd_linear_count;
- ls_paintedtime += (snd_linear_count>>1);
-
- if( CL_VideoRecording( ) )
- CL_WriteAVIAudioFrame( (byte *)snd_out, snd_linear_count << 1 );
- }
-}
-
-/*
-===================
-S_TransferPaintBuffer
-
-===================
-*/
-void S_TransferPaintBuffer(int endtime)
-{
- int out_idx;
- int count;
- int out_mask;
- int *p;
- int step;
- int val;
- unsigned long *pbuf;
-
- pbuf = (unsigned long *)dma.buffer;
-
-
- if ( s_testsound->integer ) {
- int i;
- int count;
-
- // write a fixed sine wave
- count = (endtime - s_paintedtime);
- for (i=0 ; i<count ; i++)
- paintbuffer[i].left = paintbuffer[i].right = sin((s_paintedtime+i)*0.1)*20000*256;
- }
-
-
- if (dma.samplebits == 16 && dma.channels == 2)
- { // optimized case
- S_TransferStereo16 (pbuf, endtime);
- }
- else
- { // general case
- p = (int *) paintbuffer;
- count = (endtime - s_paintedtime) * dma.channels;
- out_mask = dma.samples - 1;
- out_idx = s_paintedtime * dma.channels & out_mask;
- step = 3 - dma.channels;
-
- if (dma.samplebits == 16)
- {
- short *out = (short *) pbuf;
- while (count--)
- {
- val = *p >> 8;
- p+= step;
- if (val > 0x7fff)
- val = 0x7fff;
- else if (val < -32768)
- val = -32768;
- out[out_idx] = val;
- out_idx = (out_idx + 1) & out_mask;
- }
- }
- else if (dma.samplebits == 8)
- {
- unsigned char *out = (unsigned char *) pbuf;
- while (count--)
- {
- val = *p >> 8;
- p+= step;
- if (val > 0x7fff)
- val = 0x7fff;
- else if (val < -32768)
- val = -32768;
- out[out_idx] = (val>>8) + 128;
- out_idx = (out_idx + 1) & out_mask;
- }
- }
- }
-}
-
-
-/*
-===============================================================================
-
-CHANNEL MIXING
-
-===============================================================================
-*/
-
-#if idppc_altivec
-static void S_PaintChannelFrom16_altivec( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
- int data, aoff, boff;
- int leftvol, rightvol;
- int i, j;
- portable_samplepair_t *samp;
- sndBuffer *chunk;
- short *samples;
- float ooff, fdata, fdiv, fleftvol, frightvol;
-
- samp = &paintbuffer[ bufferOffset ];
-
- if (ch->doppler) {
- sampleOffset = sampleOffset*ch->oldDopplerScale;
- }
-
- chunk = sc->soundData;
- while (sampleOffset>=SND_CHUNK_SIZE) {
- chunk = chunk->next;
- sampleOffset -= SND_CHUNK_SIZE;
- if (!chunk) {
- chunk = sc->soundData;
- }
- }
-
- if (!ch->doppler || ch->dopplerScale==1.0f) {
- vector signed short volume_vec;
- vector unsigned int volume_shift;
- int vectorCount, samplesLeft, chunkSamplesLeft;
- leftvol = ch->leftvol*snd_vol;
- rightvol = ch->rightvol*snd_vol;
- samples = chunk->sndChunk;
- ((short *)&volume_vec)[0] = leftvol;
- ((short *)&volume_vec)[1] = leftvol;
- ((short *)&volume_vec)[4] = leftvol;
- ((short *)&volume_vec)[5] = leftvol;
- ((short *)&volume_vec)[2] = rightvol;
- ((short *)&volume_vec)[3] = rightvol;
- ((short *)&volume_vec)[6] = rightvol;
- ((short *)&volume_vec)[7] = rightvol;
- volume_shift = vec_splat_u32(8);
- i = 0;
-
- while(i < count) {
- /* Try to align destination to 16-byte boundary */
- while(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) {
- data = samples[sampleOffset++];
- samp[i].left += (data * leftvol)>>8;
- samp[i].right += (data * rightvol)>>8;
-
- if (sampleOffset == SND_CHUNK_SIZE) {
- chunk = chunk->next;
- samples = chunk->sndChunk;
- sampleOffset = 0;
- }
- i++;
- }
- /* Destination is now aligned. Process as many 8-sample
- chunks as we can before we run out of room from the current
- sound chunk. We do 8 per loop to avoid extra source data reads. */
- samplesLeft = count - i;
- chunkSamplesLeft = SND_CHUNK_SIZE - sampleOffset;
- if(samplesLeft > chunkSamplesLeft)
- samplesLeft = chunkSamplesLeft;
-
- vectorCount = samplesLeft / 8;
-
- if(vectorCount)
- {
- vector unsigned char tmp;
- vector short s0, s1, sampleData0, sampleData1;
- vector signed int merge0, merge1;
- vector signed int d0, d1, d2, d3;
- vector unsigned char samplePermute0 =
- VECCONST_UINT8(0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7);
- vector unsigned char samplePermute1 =
- VECCONST_UINT8(8, 9, 12, 13, 8, 9, 12, 13, 10, 11, 14, 15, 10, 11, 14, 15);
- vector unsigned char loadPermute0, loadPermute1;
-
- // Rather than permute the vectors after we load them to do the sample
- // replication and rearrangement, we permute the alignment vector so
- // we do everything in one step below and avoid data shuffling.
- tmp = vec_lvsl(0,&samples[sampleOffset]);
- loadPermute0 = vec_perm(tmp,tmp,samplePermute0);
- loadPermute1 = vec_perm(tmp,tmp,samplePermute1);
-
- s0 = *(vector short *)&samples[sampleOffset];
- while(vectorCount)
- {
- /* Load up source (16-bit) sample data */
- s1 = *(vector short *)&samples[sampleOffset+7];
-
- /* Load up destination sample data */
- d0 = *(vector signed int *)&samp[i];
- d1 = *(vector signed int *)&samp[i+2];
- d2 = *(vector signed int *)&samp[i+4];
- d3 = *(vector signed int *)&samp[i+6];
-
- sampleData0 = vec_perm(s0,s1,loadPermute0);
- sampleData1 = vec_perm(s0,s1,loadPermute1);
-
- merge0 = vec_mule(sampleData0,volume_vec);
- merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
-
- merge1 = vec_mulo(sampleData0,volume_vec);
- merge1 = vec_sra(merge1,volume_shift);
-
- d0 = vec_add(merge0,d0);
- d1 = vec_add(merge1,d1);
-
- merge0 = vec_mule(sampleData1,volume_vec);
- merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
-
- merge1 = vec_mulo(sampleData1,volume_vec);
- merge1 = vec_sra(merge1,volume_shift);
-
- d2 = vec_add(merge0,d2);
- d3 = vec_add(merge1,d3);
-
- /* Store destination sample data */
- *(vector signed int *)&samp[i] = d0;
- *(vector signed int *)&samp[i+2] = d1;
- *(vector signed int *)&samp[i+4] = d2;
- *(vector signed int *)&samp[i+6] = d3;
-
- i += 8;
- vectorCount--;
- s0 = s1;
- sampleOffset += 8;
- }
- if (sampleOffset == SND_CHUNK_SIZE) {
- chunk = chunk->next;
- samples = chunk->sndChunk;
- sampleOffset = 0;
- }
- }
- }
- } else {
- fleftvol = ch->leftvol*snd_vol;
- frightvol = ch->rightvol*snd_vol;
-
- ooff = sampleOffset;
- samples = chunk->sndChunk;
-
- for ( i=0 ; i<count ; i++ ) {
-
- aoff = ooff;
- ooff = ooff + ch->dopplerScale;
- boff = ooff;
- fdata = 0;
- for (j=aoff; j<boff; j++) {
- if (j == SND_CHUNK_SIZE) {
- chunk = chunk->next;
- if (!chunk) {
- chunk = sc->soundData;
- }
- samples = chunk->sndChunk;
- ooff -= SND_CHUNK_SIZE;
- }
- fdata += samples[j&(SND_CHUNK_SIZE-1)];
- }
- fdiv = 256 * (boff-aoff);
- samp[i].left += (fdata * fleftvol)/fdiv;
- samp[i].right += (fdata * frightvol)/fdiv;
- }
- }
-}
-#endif
-
-static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
- int data, aoff, boff;
- int leftvol, rightvol;
- int i, j;
- portable_samplepair_t *samp;
- sndBuffer *chunk;
- short *samples;
- float ooff, fdata, fdiv, fleftvol, frightvol;
-
- samp = &paintbuffer[ bufferOffset ];
-
- if (ch->doppler) {
- sampleOffset = sampleOffset*ch->oldDopplerScale;
- }
-
- chunk = sc->soundData;
- while (sampleOffset>=SND_CHUNK_SIZE) {
- chunk = chunk->next;
- sampleOffset -= SND_CHUNK_SIZE;
- if (!chunk) {
- chunk = sc->soundData;
- }
- }
-
- if (!ch->doppler || ch->dopplerScale==1.0f) {
- leftvol = ch->leftvol*snd_vol;
- rightvol = ch->rightvol*snd_vol;
- samples = chunk->sndChunk;
- for ( i=0 ; i<count ; i++ ) {
- data = samples[sampleOffset++];
- samp[i].left += (data * leftvol)>>8;
- samp[i].right += (data * rightvol)>>8;
-
- if (sampleOffset == SND_CHUNK_SIZE) {
- chunk = chunk->next;
- samples = chunk->sndChunk;
- sampleOffset = 0;
- }
- }
- } else {
- fleftvol = ch->leftvol*snd_vol;
- frightvol = ch->rightvol*snd_vol;
-
- ooff = sampleOffset;
- samples = chunk->sndChunk;
-
-
-
-
- for ( i=0 ; i<count ; i++ ) {
-
- aoff = ooff;
- ooff = ooff + ch->dopplerScale;
- boff = ooff;
- fdata = 0;
- for (j=aoff; j<boff; j++) {
- if (j == SND_CHUNK_SIZE) {
- chunk = chunk->next;
- if (!chunk) {
- chunk = sc->soundData;
- }
- samples = chunk->sndChunk;
- ooff -= SND_CHUNK_SIZE;
- }
- fdata += samples[j&(SND_CHUNK_SIZE-1)];
- }
- fdiv = 256 * (boff-aoff);
- samp[i].left += (fdata * fleftvol)/fdiv;
- samp[i].right += (fdata * frightvol)/fdiv;
- }
- }
-}
-
-static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
-#if idppc_altivec
- if (com_altivec->integer) {
- // must be in a seperate function or G3 systems will crash.
- S_PaintChannelFrom16_altivec( ch, sc, count, sampleOffset, bufferOffset );
- return;
- }
-#endif
- S_PaintChannelFrom16_scalar( ch, sc, count, sampleOffset, bufferOffset );
-}
-
-void S_PaintChannelFromWavelet( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
- int data;
- int leftvol, rightvol;
- int i;
- portable_samplepair_t *samp;
- sndBuffer *chunk;
- short *samples;
-
- leftvol = ch->leftvol*snd_vol;
- rightvol = ch->rightvol*snd_vol;
-
- i = 0;
- samp = &paintbuffer[ bufferOffset ];
- chunk = sc->soundData;
- while (sampleOffset>=(SND_CHUNK_SIZE_FLOAT*4)) {
- chunk = chunk->next;
- sampleOffset -= (SND_CHUNK_SIZE_FLOAT*4);
- i++;
- }
-
- if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
- S_AdpcmGetSamples( chunk, sfxScratchBuffer );
- sfxScratchIndex = i;
- sfxScratchPointer = sc;
- }
-
- samples = sfxScratchBuffer;
-
- for ( i=0 ; i<count ; i++ ) {
- data = samples[sampleOffset++];
- samp[i].left += (data * leftvol)>>8;
- samp[i].right += (data * rightvol)>>8;
-
- if (sampleOffset == SND_CHUNK_SIZE*2) {
- chunk = chunk->next;
- decodeWavelet(chunk, sfxScratchBuffer);
- sfxScratchIndex++;
- sampleOffset = 0;
- }
- }
-}
-
-void S_PaintChannelFromADPCM( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
- int data;
- int leftvol, rightvol;
- int i;
- portable_samplepair_t *samp;
- sndBuffer *chunk;
- short *samples;
-
- leftvol = ch->leftvol*snd_vol;
- rightvol = ch->rightvol*snd_vol;
-
- i = 0;
- samp = &paintbuffer[ bufferOffset ];
- chunk = sc->soundData;
-
- if (ch->doppler) {
- sampleOffset = sampleOffset*ch->oldDopplerScale;
- }
-
- while (sampleOffset>=(SND_CHUNK_SIZE*4)) {
- chunk = chunk->next;
- sampleOffset -= (SND_CHUNK_SIZE*4);
- i++;
- }
-
- if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
- S_AdpcmGetSamples( chunk, sfxScratchBuffer );
- sfxScratchIndex = i;
- sfxScratchPointer = sc;
- }
-
- samples = sfxScratchBuffer;
-
- for ( i=0 ; i<count ; i++ ) {
- data = samples[sampleOffset++];
- samp[i].left += (data * leftvol)>>8;
- samp[i].right += (data * rightvol)>>8;
-
- if (sampleOffset == SND_CHUNK_SIZE*4) {
- chunk = chunk->next;
- S_AdpcmGetSamples( chunk, sfxScratchBuffer);
- sampleOffset = 0;
- sfxScratchIndex++;
- }
- }
-}
-
-void S_PaintChannelFromMuLaw( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
- int data;
- int leftvol, rightvol;
- int i;
- portable_samplepair_t *samp;
- sndBuffer *chunk;
- byte *samples;
- float ooff;
-
- leftvol = ch->leftvol*snd_vol;
- rightvol = ch->rightvol*snd_vol;
-
- samp = &paintbuffer[ bufferOffset ];
- chunk = sc->soundData;
- while (sampleOffset>=(SND_CHUNK_SIZE*2)) {
- chunk = chunk->next;
- sampleOffset -= (SND_CHUNK_SIZE*2);
- if (!chunk) {
- chunk = sc->soundData;
- }
- }
-
- if (!ch->doppler) {
- samples = (byte *)chunk->sndChunk + sampleOffset;
- for ( i=0 ; i<count ; i++ ) {
- data = mulawToShort[*samples];
- samp[i].left += (data * leftvol)>>8;
- samp[i].right += (data * rightvol)>>8;
- samples++;
- if (samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) {
- chunk = chunk->next;
- samples = (byte *)chunk->sndChunk;
- }
- }
- } else {
- ooff = sampleOffset;
- samples = (byte *)chunk->sndChunk;
- for ( i=0 ; i<count ; i++ ) {
- data = mulawToShort[samples[(int)(ooff)]];
- ooff = ooff + ch->dopplerScale;
- samp[i].left += (data * leftvol)>>8;
- samp[i].right += (data * rightvol)>>8;
- if (ooff >= SND_CHUNK_SIZE*2) {
- chunk = chunk->next;
- if (!chunk) {
- chunk = sc->soundData;
- }
- samples = (byte *)chunk->sndChunk;
- ooff = 0.0;
- }
- }
- }
-}
-
-/*
-===================
-S_PaintChannels
-===================
-*/
-void S_PaintChannels( int endtime ) {
- int i;
- int end;
- int stream;
- channel_t *ch;
- sfx_t *sc;
- int ltime, count;
- int sampleOffset;
-
- if(s_muted->integer)
- snd_vol = 0;
- else
- snd_vol = s_volume->value*255;
-
-//Com_Printf ("%i to %i\n", s_paintedtime, endtime);
- while ( s_paintedtime < endtime ) {
- // if paintbuffer is smaller than DMA buffer
- // we may need to fill it multiple times
- end = endtime;
- if ( endtime - s_paintedtime > PAINTBUFFER_SIZE ) {
- end = s_paintedtime + PAINTBUFFER_SIZE;
- }
-
- // clear the paint buffer and mix any raw samples...
- Com_Memset(paintbuffer, 0, sizeof (paintbuffer));
- for (stream = 0; stream < MAX_RAW_STREAMS; stream++) {
- if ( s_rawend[stream] >= s_paintedtime ) {
- // copy from the streaming sound source
- const portable_samplepair_t *rawsamples = s_rawsamples[stream];
- const int stop = (end < s_rawend[stream]) ? end : s_rawend[stream];
- for ( i = s_paintedtime ; i < stop ; i++ ) {
- const int s = i&(MAX_RAW_SAMPLES-1);
- paintbuffer[i-s_paintedtime].left += rawsamples[s].left;
- paintbuffer[i-s_paintedtime].right += rawsamples[s].right;
- }
- }
- }
-
- // paint in the channels.
- ch = s_channels;
- for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {
- if ( !ch->thesfx || (ch->leftvol<0.25 && ch->rightvol<0.25 )) {
- continue;
- }
-
- ltime = s_paintedtime;
- sc = ch->thesfx;
-
- sampleOffset = ltime - ch->startSample;
- count = end - ltime;
- if ( sampleOffset + count > sc->soundLength ) {
- count = sc->soundLength - sampleOffset;
- }
-
- if ( count > 0 ) {
- if( sc->soundCompressionMethod == 1) {
- S_PaintChannelFromADPCM (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- } else if( sc->soundCompressionMethod == 2) {
- S_PaintChannelFromWavelet (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- } else if( sc->soundCompressionMethod == 3) {
- S_PaintChannelFromMuLaw (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- } else {
- S_PaintChannelFrom16 (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- }
- }
- }
-
- // paint in the looped channels.
- ch = loop_channels;
- for ( i = 0; i < numLoopChannels ; i++, ch++ ) {
- if ( !ch->thesfx || (!ch->leftvol && !ch->rightvol )) {
- continue;
- }
-
- ltime = s_paintedtime;
- sc = ch->thesfx;
-
- if (sc->soundData==NULL || sc->soundLength==0) {
- continue;
- }
- // we might have to make two passes if it
- // is a looping sound effect and the end of
- // the sample is hit
- do {
- sampleOffset = (ltime % sc->soundLength);
-
- count = end - ltime;
- if ( sampleOffset + count > sc->soundLength ) {
- count = sc->soundLength - sampleOffset;
- }
-
- if ( count > 0 ) {
- if( sc->soundCompressionMethod == 1) {
- S_PaintChannelFromADPCM (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- } else if( sc->soundCompressionMethod == 2) {
- S_PaintChannelFromWavelet (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- } else if( sc->soundCompressionMethod == 3) {
- S_PaintChannelFromMuLaw (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- } else {
- S_PaintChannelFrom16 (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- }
- ltime += count;
- }
- } while ( ltime < end);
- }
-
- // transfer out according to DMA format
- S_TransferPaintBuffer( end );
- s_paintedtime = end;
- }
-}
diff --git a/engine/code/client/snd_openal.c b/engine/code/client/snd_openal.c
deleted file mode 100644
index b635989..0000000
--- a/engine/code/client/snd_openal.c
+++ /dev/null
@@ -1,2504 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "snd_local.h"
-#include "snd_codec.h"
-#include "client.h"
-
-#ifdef USE_OPENAL
-
-#include "qal.h"
-
-// Console variables specific to OpenAL
-cvar_t *s_alPrecache;
-cvar_t *s_alGain;
-cvar_t *s_alSources;
-cvar_t *s_alDopplerFactor;
-cvar_t *s_alDopplerSpeed;
-cvar_t *s_alMinDistance;
-cvar_t *s_alMaxDistance;
-cvar_t *s_alRolloff;
-cvar_t *s_alGraceDistance;
-cvar_t *s_alDriver;
-cvar_t *s_alDevice;
-cvar_t *s_alAvailableDevices;
-
-/*
-=================
-S_AL_Format
-=================
-*/
-static
-ALuint S_AL_Format(int width, int channels)
-{
- ALuint format = AL_FORMAT_MONO16;
-
- // Work out format
- if(width == 1)
- {
- if(channels == 1)
- format = AL_FORMAT_MONO8;
- else if(channels == 2)
- format = AL_FORMAT_STEREO8;
- }
- else if(width == 2)
- {
- if(channels == 1)
- format = AL_FORMAT_MONO16;
- else if(channels == 2)
- format = AL_FORMAT_STEREO16;
- }
-
- return format;
-}
-
-/*
-=================
-S_AL_ErrorMsg
-=================
-*/
-static const char *S_AL_ErrorMsg(ALenum error)
-{
- switch(error)
- {
- case AL_NO_ERROR:
- return "No error";
- case AL_INVALID_NAME:
- return "Invalid name";
- case AL_INVALID_ENUM:
- return "Invalid enumerator";
- case AL_INVALID_VALUE:
- return "Invalid value";
- case AL_INVALID_OPERATION:
- return "Invalid operation";
- case AL_OUT_OF_MEMORY:
- return "Out of memory";
- default:
- return "Unknown error";
- }
-}
-
-/*
-=================
-S_AL_ClearError
-=================
-*/
-static void S_AL_ClearError( qboolean quiet )
-{
- int error = qalGetError();
-
- if( quiet )
- return;
- if(error != AL_NO_ERROR)
- {
- Com_Printf(S_COLOR_YELLOW "WARNING: unhandled AL error: %s\n",
- S_AL_ErrorMsg(error));
- }
-}
-
-
-//===========================================================================
-
-
-typedef struct alSfx_s
-{
- char filename[MAX_QPATH];
- ALuint buffer; // OpenAL buffer
- snd_info_t info; // information for this sound like rate, sample count..
-
- qboolean isDefault; // Couldn't be loaded - use default FX
- qboolean inMemory; // Sound is stored in memory
- qboolean isLocked; // Sound is locked (can not be unloaded)
- int lastUsedTime; // Time last used
-
- int loopCnt; // number of loops using this sfx
- int loopActiveCnt; // number of playing loops using this sfx
- int masterLoopSrc; // All other sources looping this buffer are synced to this master src
-} alSfx_t;
-
-static qboolean alBuffersInitialised = qfalse;
-
-// Sound effect storage, data structures
-#define MAX_SFX 4096
-static alSfx_t knownSfx[MAX_SFX];
-static int numSfx = 0;
-
-static sfxHandle_t default_sfx;
-
-/*
-=================
-S_AL_BufferFindFree
-
-Find a free handle
-=================
-*/
-static sfxHandle_t S_AL_BufferFindFree( void )
-{
- int i;
-
- for(i = 0; i < MAX_SFX; i++)
- {
- // Got one
- if(knownSfx[i].filename[0] == '\0')
- {
- if(i >= numSfx)
- numSfx = i + 1;
- return i;
- }
- }
-
- // Shit...
- Com_Error(ERR_FATAL, "S_AL_BufferFindFree: No free sound handles");
- return -1;
-}
-
-/*
-=================
-S_AL_BufferFind
-
-Find a sound effect if loaded, set up a handle otherwise
-=================
-*/
-static sfxHandle_t S_AL_BufferFind(const char *filename)
-{
- // Look it up in the table
- sfxHandle_t sfx = -1;
- int i;
-
- for(i = 0; i < numSfx; i++)
- {
- if(!Q_stricmp(knownSfx[i].filename, filename))
- {
- sfx = i;
- break;
- }
- }
-
- // Not found in table?
- if(sfx == -1)
- {
- alSfx_t *ptr;
-
- sfx = S_AL_BufferFindFree();
-
- // Clear and copy the filename over
- ptr = &knownSfx[sfx];
- memset(ptr, 0, sizeof(*ptr));
- ptr->masterLoopSrc = -1;
- strcpy(ptr->filename, filename);
- }
-
- // Return the handle
- return sfx;
-}
-
-/*
-=================
-S_AL_BufferUseDefault
-=================
-*/
-static void S_AL_BufferUseDefault(sfxHandle_t sfx)
-{
- if(sfx == default_sfx)
- Com_Error(ERR_FATAL, "Can't load default sound effect %s\n", knownSfx[sfx].filename);
-
- Com_Printf( S_COLOR_YELLOW "WARNING: Using default sound for %s\n", knownSfx[sfx].filename);
- knownSfx[sfx].isDefault = qtrue;
- knownSfx[sfx].buffer = knownSfx[default_sfx].buffer;
-}
-
-/*
-=================
-S_AL_BufferUnload
-=================
-*/
-static void S_AL_BufferUnload(sfxHandle_t sfx)
-{
- ALenum error;
-
- if(knownSfx[sfx].filename[0] == '\0')
- return;
-
- if(!knownSfx[sfx].inMemory)
- return;
-
- // Delete it
- S_AL_ClearError( qfalse );
- qalDeleteBuffers(1, &knownSfx[sfx].buffer);
- if((error = qalGetError()) != AL_NO_ERROR)
- Com_Printf( S_COLOR_RED "ERROR: Can't delete sound buffer for %s\n",
- knownSfx[sfx].filename);
-
- knownSfx[sfx].inMemory = qfalse;
-}
-
-/*
-=================
-S_AL_BufferEvict
-=================
-*/
-static qboolean S_AL_BufferEvict( void )
-{
- int i, oldestBuffer = -1;
- int oldestTime = Sys_Milliseconds( );
-
- for( i = 0; i < numSfx; i++ )
- {
- if( !knownSfx[ i ].filename[ 0 ] )
- continue;
-
- if( !knownSfx[ i ].inMemory )
- continue;
-
- if( knownSfx[ i ].lastUsedTime < oldestTime )
- {
- oldestTime = knownSfx[ i ].lastUsedTime;
- oldestBuffer = i;
- }
- }
-
- if( oldestBuffer >= 0 )
- {
- S_AL_BufferUnload( oldestBuffer );
- return qtrue;
- }
- else
- return qfalse;
-}
-
-/*
-=================
-S_AL_BufferLoad
-=================
-*/
-static void S_AL_BufferLoad(sfxHandle_t sfx)
-{
- ALenum error;
- ALuint format;
-
- void *data;
- snd_info_t info;
- alSfx_t *curSfx = &knownSfx[sfx];
-
- // Nothing?
- if(curSfx->filename[0] == '\0')
- return;
-
- // Player SFX
- if(curSfx->filename[0] == '*')
- return;
-
- // Already done?
- if((curSfx->inMemory) || (curSfx->isDefault))
- return;
-
- // Try to load
- data = S_CodecLoad(curSfx->filename, &info);
- if(!data)
- {
- S_AL_BufferUseDefault(sfx);
- return;
- }
-
- format = S_AL_Format(info.width, info.channels);
-
- // Create a buffer
- S_AL_ClearError( qfalse );
- qalGenBuffers(1, &curSfx->buffer);
- if((error = qalGetError()) != AL_NO_ERROR)
- {
- S_AL_BufferUseDefault(sfx);
- Z_Free(data);
- Com_Printf( S_COLOR_RED "ERROR: Can't create a sound buffer for %s - %s\n",
- curSfx->filename, S_AL_ErrorMsg(error));
- return;
- }
-
- // Fill the buffer
- if( info.size == 0 )
- {
- // We have no data to buffer, so buffer silence
- byte dummyData[ 2 ] = { 0 };
-
- qalBufferData(curSfx->buffer, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050);
- }
- else
- qalBufferData(curSfx->buffer, format, data, info.size, info.rate);
-
- error = qalGetError();
-
- // If we ran out of memory, start evicting the least recently used sounds
- while(error == AL_OUT_OF_MEMORY)
- {
- if( !S_AL_BufferEvict( ) )
- {
- S_AL_BufferUseDefault(sfx);
- Z_Free(data);
- Com_Printf( S_COLOR_RED "ERROR: Out of memory loading %s\n", curSfx->filename);
- return;
- }
-
- // Try load it again
- qalBufferData(curSfx->buffer, format, data, info.size, info.rate);
- error = qalGetError();
- }
-
- // Some other error condition
- if(error != AL_NO_ERROR)
- {
- S_AL_BufferUseDefault(sfx);
- Z_Free(data);
- Com_Printf( S_COLOR_RED "ERROR: Can't fill sound buffer for %s - %s\n",
- curSfx->filename, S_AL_ErrorMsg(error));
- return;
- }
-
- curSfx->info = info;
-
- // Free the memory
- Z_Free(data);
-
- // Woo!
- curSfx->inMemory = qtrue;
-}
-
-/*
-=================
-S_AL_BufferUse
-=================
-*/
-static
-void S_AL_BufferUse(sfxHandle_t sfx)
-{
- if(knownSfx[sfx].filename[0] == '\0')
- return;
-
- if((!knownSfx[sfx].inMemory) && (!knownSfx[sfx].isDefault))
- S_AL_BufferLoad(sfx);
- knownSfx[sfx].lastUsedTime = Sys_Milliseconds();
-}
-
-/*
-=================
-S_AL_BufferInit
-=================
-*/
-static
-qboolean S_AL_BufferInit( void )
-{
- if(alBuffersInitialised)
- return qtrue;
-
- // Clear the hash table, and SFX table
- memset(knownSfx, 0, sizeof(knownSfx));
- numSfx = 0;
-
- // Load the default sound, and lock it
- default_sfx = S_AL_BufferFind("sound/feedback/hit.wav");
- S_AL_BufferUse(default_sfx);
- knownSfx[default_sfx].isLocked = qtrue;
-
- // All done
- alBuffersInitialised = qtrue;
- return qtrue;
-}
-
-/*
-=================
-S_AL_BufferShutdown
-=================
-*/
-static
-void S_AL_BufferShutdown( void )
-{
- int i;
-
- if(!alBuffersInitialised)
- return;
-
- // Unlock the default sound effect
- knownSfx[default_sfx].isLocked = qfalse;
-
- // Free all used effects
- for(i = 0; i < numSfx; i++)
- S_AL_BufferUnload(i);
-
- // Clear the tables
- memset(knownSfx, 0, sizeof(knownSfx));
-
- // All undone
- alBuffersInitialised = qfalse;
-}
-
-/*
-=================
-S_AL_RegisterSound
-=================
-*/
-static
-sfxHandle_t S_AL_RegisterSound( const char *sample, qboolean compressed )
-{
- sfxHandle_t sfx = S_AL_BufferFind(sample);
-
- if( s_alPrecache->integer && (!knownSfx[sfx].inMemory) && (!knownSfx[sfx].isDefault))
- S_AL_BufferLoad(sfx);
- knownSfx[sfx].lastUsedTime = Com_Milliseconds();
-
- return sfx;
-}
-
-/*
-=================
-S_AL_BufferGet
-
-Return's an sfx's buffer
-=================
-*/
-static
-ALuint S_AL_BufferGet(sfxHandle_t sfx)
-{
- return knownSfx[sfx].buffer;
-}
-
-
-//===========================================================================
-
-
-typedef struct src_s
-{
- ALuint alSource; // OpenAL source object
- sfxHandle_t sfx; // Sound effect in use
-
- int lastUsedTime; // Last time used
- alSrcPriority_t priority; // Priority
- int entity; // Owning entity (-1 if none)
- int channel; // Associated channel (-1 if none)
-
- qboolean isActive; // Is this source currently in use?
- qboolean isPlaying; // Is this source currently playing, or stopped?
- qboolean isLocked; // This is locked (un-allocatable)
- qboolean isLooping; // Is this a looping effect (attached to an entity)
- qboolean isTracking; // Is this object tracking its owner
-
- float curGain; // gain employed if source is within maxdistance.
- float scaleGain; // Last gain value for this source. 0 if muted.
-
- float lastTimePos; // On stopped loops, the last position in the buffer
- int lastSampleTime; // Time when this was stopped
- vec3_t loopSpeakerPos; // Origin of the loop speaker
-
- qboolean local; // Is this local (relative to the cam)
-} src_t;
-
-#ifdef MACOS_X
- #define MAX_SRC 64
-#else
- #define MAX_SRC 128
-#endif
-static src_t srcList[MAX_SRC];
-static int srcCount = 0;
-static int srcActiveCnt = 0;
-static qboolean alSourcesInitialised = qfalse;
-static vec3_t lastListenerOrigin = { 0.0f, 0.0f, 0.0f };
-
-typedef struct sentity_s
-{
- vec3_t origin;
-
- qboolean srcAllocated; // If a src_t has been allocated to this entity
- int srcIndex;
-
- qboolean loopAddedThisFrame;
- alSrcPriority_t loopPriority;
- sfxHandle_t loopSfx;
- qboolean startLoopingSound;
-} sentity_t;
-
-static sentity_t entityList[MAX_GENTITIES];
-
-/*
-=================
-S_AL_SanitiseVector
-=================
-*/
-#define S_AL_SanitiseVector(v) _S_AL_SanitiseVector(v,__LINE__)
-static void _S_AL_SanitiseVector( vec3_t v, int line )
-{
- if( Q_isnan( v[ 0 ] ) || Q_isnan( v[ 1 ] ) || Q_isnan( v[ 2 ] ) )
- {
- Com_DPrintf( S_COLOR_YELLOW "WARNING: vector with one or more NaN components "
- "being passed to OpenAL at %s:%d -- zeroing\n", __FILE__, line );
- VectorClear( v );
- }
-}
-
-
-#define AL_THIRD_PERSON_THRESHOLD_SQ (48.0f*48.0f)
-
-/*
-=================
-S_AL_Gain
-Set gain to 0 if muted, otherwise set it to given value.
-=================
-*/
-
-static void S_AL_Gain(ALuint source, float gainval)
-{
- if(s_muted->integer)
- qalSourcef(source, AL_GAIN, 0.0f);
- else
- qalSourcef(source, AL_GAIN, gainval);
-}
-
-/*
-=================
-S_AL_ScaleGain
-Adapt the gain if necessary to get a quicker fadeout when the source is too far away.
-=================
-*/
-
-static void S_AL_ScaleGain(src_t *chksrc, vec3_t origin)
-{
- float distance;
-
- if(!chksrc->local)
- distance = Distance(origin, lastListenerOrigin);
-
- // If we exceed a certain distance, scale the gain linearly until the sound
- // vanishes into nothingness.
- if(!chksrc->local && (distance -= s_alMaxDistance->value) > 0)
- {
- float scaleFactor;
-
- if(distance >= s_alGraceDistance->value)
- scaleFactor = 0.0f;
- else
- scaleFactor = 1.0f - distance / s_alGraceDistance->value;
-
- scaleFactor *= chksrc->curGain;
-
- if(chksrc->scaleGain != scaleFactor);
- {
- chksrc->scaleGain = scaleFactor;
- S_AL_Gain(chksrc->alSource, chksrc->scaleGain);
- }
- }
- else if(chksrc->scaleGain != chksrc->curGain)
- {
- chksrc->scaleGain = chksrc->curGain;
- S_AL_Gain(chksrc->alSource, chksrc->scaleGain);
- }
-}
-
-/*
-=================
-S_AL_HearingThroughEntity
-=================
-*/
-static qboolean S_AL_HearingThroughEntity( int entityNum )
-{
- float distanceSq;
-
- if( clc.clientNum == entityNum )
- {
- // FIXME: <tim at ngus.net> 28/02/06 This is an outrageous hack to detect
- // whether or not the player is rendering in third person or not. We can't
- // ask the renderer because the renderer has no notion of entities and we
- // can't ask cgame since that would involve changing the API and hence mod
- // compatibility. I don't think there is any way around this, but I'll leave
- // the FIXME just in case anyone has a bright idea.
- distanceSq = DistanceSquared(
- entityList[ entityNum ].origin,
- lastListenerOrigin );
-
- if( distanceSq > AL_THIRD_PERSON_THRESHOLD_SQ )
- return qfalse; //we're the player, but third person
- else
- return qtrue; //we're the player
- }
- else
- return qfalse; //not the player
-}
-
-/*
-=================
-S_AL_SrcInit
-=================
-*/
-static
-qboolean S_AL_SrcInit( void )
-{
- int i;
- int limit;
- ALenum error;
-
- // Clear the sources data structure
- memset(srcList, 0, sizeof(srcList));
- srcCount = 0;
- srcActiveCnt = 0;
-
- // Cap s_alSources to MAX_SRC
- limit = s_alSources->integer;
- if(limit > MAX_SRC)
- limit = MAX_SRC;
- else if(limit < 16)
- limit = 16;
-
- S_AL_ClearError( qfalse );
- // Allocate as many sources as possible
- for(i = 0; i < limit; i++)
- {
- qalGenSources(1, &srcList[i].alSource);
- if((error = qalGetError()) != AL_NO_ERROR)
- break;
- srcCount++;
- }
-
- // All done. Print this for informational purposes
- Com_Printf( "Allocated %d sources.\n", srcCount);
- alSourcesInitialised = qtrue;
- return qtrue;
-}
-
-/*
-=================
-S_AL_SrcShutdown
-=================
-*/
-static
-void S_AL_SrcShutdown( void )
-{
- int i;
- src_t *curSource;
-
- if(!alSourcesInitialised)
- return;
-
- // Destroy all the sources
- for(i = 0; i < srcCount; i++)
- {
- curSource = &srcList[i];
-
- if(curSource->isLocked)
- Com_DPrintf( S_COLOR_YELLOW "WARNING: Source %d is locked\n", i);
-
- if(curSource->entity > 0)
- entityList[curSource->entity].srcAllocated = qfalse;
-
- qalSourceStop(srcList[i].alSource);
- qalDeleteSources(1, &srcList[i].alSource);
- }
-
- memset(srcList, 0, sizeof(srcList));
-
- alSourcesInitialised = qfalse;
-}
-
-/*
-=================
-S_AL_SrcSetup
-=================
-*/
-static void S_AL_SrcSetup(srcHandle_t src, sfxHandle_t sfx, alSrcPriority_t priority,
- int entity, int channel, qboolean local)
-{
- ALuint buffer;
- src_t *curSource;
-
- // Mark the SFX as used, and grab the raw AL buffer
- S_AL_BufferUse(sfx);
- buffer = S_AL_BufferGet(sfx);
-
- // Set up src struct
- curSource = &srcList[src];
-
- curSource->lastUsedTime = Sys_Milliseconds();
- curSource->sfx = sfx;
- curSource->priority = priority;
- curSource->entity = entity;
- curSource->channel = channel;
- curSource->isPlaying = qfalse;
- curSource->isLocked = qfalse;
- curSource->isLooping = qfalse;
- curSource->isTracking = qfalse;
- curSource->curGain = s_alGain->value * s_volume->value;
- curSource->scaleGain = curSource->curGain;
- curSource->local = local;
-
- // Set up OpenAL source
- qalSourcei(curSource->alSource, AL_BUFFER, buffer);
- qalSourcef(curSource->alSource, AL_PITCH, 1.0f);
- S_AL_Gain(curSource->alSource, curSource->curGain);
- qalSourcefv(curSource->alSource, AL_POSITION, vec3_origin);
- qalSourcefv(curSource->alSource, AL_VELOCITY, vec3_origin);
- qalSourcei(curSource->alSource, AL_LOOPING, AL_FALSE);
- qalSourcef(curSource->alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
-
- if(local)
- {
- qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_TRUE);
- qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, 0.0f);
- }
- else
- {
- qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_FALSE);
- qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
- }
-}
-
-/*
-=================
-S_AL_NewLoopMaster
-Remove given source as loop master if it is the master and hand off master status to another source in this case.
-=================
-*/
-
-static void S_AL_SaveLoopPos(src_t *dest, ALuint alSource)
-{
- int error;
-
- S_AL_ClearError(qfalse);
-
- qalGetSourcef(alSource, AL_SEC_OFFSET, &dest->lastTimePos);
- if((error = qalGetError()) != AL_NO_ERROR)
- {
- // Old OpenAL implementations don't support AL_SEC_OFFSET
-
- if(error != AL_INVALID_ENUM)
- {
- Com_Printf(S_COLOR_YELLOW "WARNING: Could not get time offset for alSource %d: %s\n",
- alSource, S_AL_ErrorMsg(error));
- }
-
- dest->lastTimePos = -1;
- }
- else
- dest->lastSampleTime = Sys_Milliseconds();
-}
-
-/*
-=================
-S_AL_NewLoopMaster
-Remove given source as loop master if it is the master and hand off master status to another source in this case.
-=================
-*/
-
-static void S_AL_NewLoopMaster(src_t *rmSource, qboolean iskilled)
-{
- int index;
- src_t *curSource = NULL;
- alSfx_t *curSfx;
-
- curSfx = &knownSfx[rmSource->sfx];
-
- if(rmSource->isPlaying)
- curSfx->loopActiveCnt--;
- if(iskilled)
- curSfx->loopCnt--;
-
- if(curSfx->loopCnt)
- {
- if(rmSource->priority == SRCPRI_ENTITY)
- {
- if(!iskilled && rmSource->isPlaying)
- {
- // only sync ambient loops...
- // It makes more sense to have sounds for weapons/projectiles unsynced
- S_AL_SaveLoopPos(rmSource, rmSource->alSource);
- }
- }
- else if(rmSource == &srcList[curSfx->masterLoopSrc])
- {
- int firstInactive = -1;
-
- // Only if rmSource was the master and if there are still playing loops for
- // this sound will we need to find a new master.
-
- if(iskilled || curSfx->loopActiveCnt)
- {
- for(index = 0; index < srcCount; index++)
- {
- curSource = &srcList[index];
-
- if(curSource->sfx == rmSource->sfx && curSource != rmSource &&
- curSource->isActive && curSource->isLooping && curSource->priority == SRCPRI_AMBIENT)
- {
- if(curSource->isPlaying)
- {
- curSfx->masterLoopSrc = index;
- break;
- }
- else if(firstInactive < 0)
- firstInactive = index;
- }
- }
- }
-
- if(!curSfx->loopActiveCnt)
- {
- if(firstInactive < 0)
- {
- if(iskilled)
- {
- curSfx->masterLoopSrc = -1;
- return;
- }
- else
- curSource = rmSource;
- }
- else
- curSource = &srcList[firstInactive];
-
- if(rmSource->isPlaying)
- {
- // this was the last not stopped source, save last sample position + time
- S_AL_SaveLoopPos(curSource, rmSource->alSource);
- }
- else
- {
- // second case: all loops using this sound have stopped due to listener being of of range,
- // and now the inactive master gets deleted. Just move over the soundpos settings to the
- // new master.
- curSource->lastTimePos = rmSource->lastTimePos;
- curSource->lastSampleTime = rmSource->lastSampleTime;
- }
- }
- }
- }
- else
- curSfx->masterLoopSrc = -1;
-}
-
-/*
-=================
-S_AL_SrcKill
-=================
-*/
-static void S_AL_SrcKill(srcHandle_t src)
-{
- src_t *curSource = &srcList[src];
-
- // I'm not touching it. Unlock it first.
- if(curSource->isLocked)
- return;
-
- // Remove the entity association and loop master status
- if(curSource->isLooping)
- {
- curSource->isLooping = qfalse;
-
- if(curSource->entity != -1)
- {
- sentity_t *curEnt = &entityList[curSource->entity];
-
- curEnt->srcAllocated = qfalse;
- curEnt->srcIndex = -1;
- curEnt->loopAddedThisFrame = qfalse;
- curEnt->startLoopingSound = qfalse;
- }
-
- S_AL_NewLoopMaster(curSource, qtrue);
- }
-
- // Stop it if it's playing
- if(curSource->isPlaying)
- {
- qalSourceStop(curSource->alSource);
- curSource->isPlaying = qfalse;
- }
-
- // Remove the buffer
- qalSourcei(curSource->alSource, AL_BUFFER, 0);
-
- curSource->sfx = 0;
- curSource->lastUsedTime = 0;
- curSource->priority = 0;
- curSource->entity = -1;
- curSource->channel = -1;
- if(curSource->isActive)
- {
- curSource->isActive = qfalse;
- srcActiveCnt--;
- }
- curSource->isLocked = qfalse;
- curSource->isTracking = qfalse;
- curSource->local = qfalse;
-}
-
-/*
-=================
-S_AL_SrcAlloc
-=================
-*/
-static
-srcHandle_t S_AL_SrcAlloc( alSrcPriority_t priority, int entnum, int channel )
-{
- int i;
- int empty = -1;
- int weakest = -1;
- int weakest_time = Sys_Milliseconds();
- int weakest_pri = 999;
- float weakest_gain = 1000.0;
- qboolean weakest_isplaying = qtrue;
- int weakest_numloops = 0;
- src_t *curSource;
-
- for(i = 0; i < srcCount; i++)
- {
- curSource = &srcList[i];
-
- // If it's locked, we aren't even going to look at it
- if(curSource->isLocked)
- continue;
-
- // Is it empty or not?
- if(!curSource->isActive)
- {
- empty = i;
- break;
- }
-
- if(curSource->isPlaying)
- {
- if(weakest_isplaying && curSource->priority < priority &&
- (curSource->priority < weakest_pri ||
- (!curSource->isLooping && (curSource->scaleGain < weakest_gain || curSource->lastUsedTime < weakest_time))))
- {
- // If it has lower priority, is fainter or older, flag it as weak
- // the last two values are only compared if it's not a looping sound, because we want to prevent two
- // loops (loops are added EVERY frame) fighting for a slot
- weakest_pri = curSource->priority;
- weakest_time = curSource->lastUsedTime;
- weakest_gain = curSource->scaleGain;
- weakest = i;
- }
- }
- else
- {
- weakest_isplaying = qfalse;
-
- if(weakest < 0 ||
- knownSfx[curSource->sfx].loopCnt > weakest_numloops ||
- curSource->priority < weakest_pri ||
- curSource->lastUsedTime < weakest_time)
- {
- // Sources currently not playing of course have lowest priority
- // also try to always keep at least one loop master for every loop sound
- weakest_pri = curSource->priority;
- weakest_time = curSource->lastUsedTime;
- weakest_numloops = knownSfx[curSource->sfx].loopCnt;
- weakest = i;
- }
- }
-
- // The channel system is not actually adhered to by baseq3, and not
- // implemented in snd_dma.c, so while the following is strictly correct, it
- // causes incorrect behaviour versus defacto baseq3
-#if 0
- // Is it an exact match, and not on channel 0?
- if((curSource->entity == entnum) && (curSource->channel == channel) && (channel != 0))
- {
- S_AL_SrcKill(i);
- return i;
- }
-#endif
- }
-
- if(empty == -1)
- empty = weakest;
-
- if(empty >= 0)
- {
- S_AL_SrcKill(empty);
- srcList[empty].isActive = qtrue;
- srcActiveCnt++;
- }
-
- return empty;
-}
-
-/*
-=================
-S_AL_SrcFind
-
-Finds an active source with matching entity and channel numbers
-Returns -1 if there isn't one
-=================
-*/
-#if 0
-static
-srcHandle_t S_AL_SrcFind(int entnum, int channel)
-{
- int i;
- for(i = 0; i < srcCount; i++)
- {
- if(!srcList[i].isActive)
- continue;
- if((srcList[i].entity == entnum) && (srcList[i].channel == channel))
- return i;
- }
- return -1;
-}
-#endif
-
-/*
-=================
-S_AL_SrcLock
-
-Locked sources will not be automatically reallocated or managed
-=================
-*/
-static
-void S_AL_SrcLock(srcHandle_t src)
-{
- srcList[src].isLocked = qtrue;
-}
-
-/*
-=================
-S_AL_SrcUnlock
-
-Once unlocked, the source may be reallocated again
-=================
-*/
-static
-void S_AL_SrcUnlock(srcHandle_t src)
-{
- srcList[src].isLocked = qfalse;
-}
-
-/*
-=================
-S_AL_UpdateEntityPosition
-=================
-*/
-static
-void S_AL_UpdateEntityPosition( int entityNum, const vec3_t origin )
-{
- vec3_t sanOrigin;
-
- VectorCopy( origin, sanOrigin );
- S_AL_SanitiseVector( sanOrigin );
- if ( entityNum < 0 || entityNum > MAX_GENTITIES )
- Com_Error( ERR_DROP, "S_UpdateEntityPosition: bad entitynum %i", entityNum );
- VectorCopy( sanOrigin, entityList[entityNum].origin );
-}
-
-/*
-=================
-S_AL_CheckInput
-Check whether input values from mods are out of range.
-Necessary for i.g. Western Quake3 mod which is buggy.
-=================
-*/
-static qboolean S_AL_CheckInput(int entityNum, sfxHandle_t sfx)
-{
- if (entityNum < 0 || entityNum > MAX_GENTITIES)
- Com_Error(ERR_DROP, "ERROR: S_AL_CheckInput: bad entitynum %i", entityNum);
-
- if (sfx < 0 || sfx >= numSfx)
- {
- Com_Printf(S_COLOR_RED "ERROR: S_AL_CheckInput: handle %i out of range\n", sfx);
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-=================
-S_AL_StartLocalSound
-
-Play a local (non-spatialized) sound effect
-=================
-*/
-static
-void S_AL_StartLocalSound(sfxHandle_t sfx, int channel)
-{
- srcHandle_t src;
-
- if(S_AL_CheckInput(0, sfx))
- return;
-
- // Try to grab a source
- src = S_AL_SrcAlloc(SRCPRI_LOCAL, -1, channel);
-
- if(src == -1)
- return;
-
- // Set up the effect
- S_AL_SrcSetup(src, sfx, SRCPRI_LOCAL, -1, channel, qtrue);
-
- // Start it playing
- srcList[src].isPlaying = qtrue;
- qalSourcePlay(srcList[src].alSource);
-}
-
-/*
-=================
-S_AL_StartSound
-
-Play a one-shot sound effect
-=================
-*/
-static void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx )
-{
- vec3_t sorigin;
- srcHandle_t src;
- src_t *curSource;
-
- if(origin)
- {
- if(S_AL_CheckInput(0, sfx))
- return;
-
- VectorCopy(origin, sorigin);
- }
- else
- {
- if(S_AL_CheckInput(entnum, sfx))
- return;
-
- if(S_AL_HearingThroughEntity(entnum))
- {
- S_AL_StartLocalSound(sfx, entchannel);
- return;
- }
-
- VectorCopy(entityList[entnum].origin, sorigin);
- }
-
- S_AL_SanitiseVector(sorigin);
-
- if((srcActiveCnt > 5 * srcCount / 3) &&
- (DistanceSquared(sorigin, lastListenerOrigin) >=
- (s_alMaxDistance->value + s_alGraceDistance->value) * (s_alMaxDistance->value + s_alGraceDistance->value)))
- {
- // We're getting tight on sources and source is not within hearing distance so don't add it
- return;
- }
-
- // Try to grab a source
- src = S_AL_SrcAlloc(SRCPRI_ONESHOT, entnum, entchannel);
- if(src == -1)
- return;
-
- S_AL_SrcSetup(src, sfx, SRCPRI_ONESHOT, entnum, entchannel, qfalse);
-
- curSource = &srcList[src];
-
- if(!origin)
- curSource->isTracking = qtrue;
-
- qalSourcefv(curSource->alSource, AL_POSITION, sorigin );
- S_AL_ScaleGain(curSource, sorigin);
-
- // Start it playing
- curSource->isPlaying = qtrue;
- qalSourcePlay(curSource->alSource);
-}
-
-/*
-=================
-S_AL_ClearLoopingSounds
-=================
-*/
-static
-void S_AL_ClearLoopingSounds( qboolean killall )
-{
- int i;
- for(i = 0; i < srcCount; i++)
- {
- if((srcList[i].isLooping) && (srcList[i].entity != -1))
- entityList[srcList[i].entity].loopAddedThisFrame = qfalse;
- }
-}
-
-/*
-=================
-S_AL_SrcLoop
-=================
-*/
-static void S_AL_SrcLoop( alSrcPriority_t priority, sfxHandle_t sfx,
- const vec3_t origin, const vec3_t velocity, int entityNum )
-{
- int src;
- sentity_t *sent = &entityList[ entityNum ];
- src_t *curSource;
- vec3_t sorigin, svelocity;
-
- if(S_AL_CheckInput(entityNum, sfx))
- return;
-
- // Do we need to allocate a new source for this entity
- if( !sent->srcAllocated )
- {
- // Try to get a channel
- src = S_AL_SrcAlloc( priority, entityNum, -1 );
- if( src == -1 )
- {
- Com_DPrintf( S_COLOR_YELLOW "WARNING: Failed to allocate source "
- "for loop sfx %d on entity %d\n", sfx, entityNum );
- return;
- }
-
- curSource = &srcList[src];
-
- sent->startLoopingSound = qtrue;
-
- curSource->lastTimePos = -1.0;
- curSource->lastSampleTime = Sys_Milliseconds();
- }
- else
- {
- src = sent->srcIndex;
- curSource = &srcList[src];
- }
-
- sent->srcAllocated = qtrue;
- sent->srcIndex = src;
-
- sent->loopPriority = priority;
- sent->loopSfx = sfx;
-
- // If this is not set then the looping sound is stopped.
- sent->loopAddedThisFrame = qtrue;
-
- // UGH
- // These lines should be called via S_AL_SrcSetup, but we
- // can't call that yet as it buffers sfxes that may change
- // with subsequent calls to S_AL_SrcLoop
- curSource->entity = entityNum;
- curSource->isLooping = qtrue;
-
- if( S_AL_HearingThroughEntity( entityNum ) )
- {
- curSource->local = qtrue;
-
- VectorClear(sorigin);
-
- qalSourcefv(curSource->alSource, AL_POSITION, sorigin);
- qalSourcefv(curSource->alSource, AL_VELOCITY, sorigin);
- }
- else
- {
- curSource->local = qfalse;
-
- if(origin)
- VectorCopy(origin, sorigin);
- else
- VectorCopy(sent->origin, sorigin);
-
- S_AL_SanitiseVector(sorigin);
-
- VectorCopy(sorigin, curSource->loopSpeakerPos);
-
- if(velocity)
- {
- VectorCopy(velocity, svelocity);
- S_AL_SanitiseVector(svelocity);
- }
- else
- VectorClear(svelocity);
-
- qalSourcefv( curSource->alSource, AL_POSITION, (ALfloat *)sorigin );
- qalSourcefv( curSource->alSource, AL_VELOCITY, (ALfloat *)velocity );
- }
-}
-
-/*
-=================
-S_AL_AddLoopingSound
-=================
-*/
-static void S_AL_AddLoopingSound(int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx)
-{
- S_AL_SrcLoop(SRCPRI_ENTITY, sfx, origin, velocity, entityNum);
-}
-
-/*
-=================
-S_AL_AddRealLoopingSound
-=================
-*/
-static void S_AL_AddRealLoopingSound(int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx)
-{
- S_AL_SrcLoop(SRCPRI_AMBIENT, sfx, origin, velocity, entityNum);
-}
-
-/*
-=================
-S_AL_StopLoopingSound
-=================
-*/
-static
-void S_AL_StopLoopingSound(int entityNum )
-{
- if(entityList[entityNum].srcAllocated)
- S_AL_SrcKill(entityList[entityNum].srcIndex);
-}
-
-/*
-=================
-S_AL_SrcUpdate
-
-Update state (move things around, manage sources, and so on)
-=================
-*/
-static
-void S_AL_SrcUpdate( void )
-{
- int i;
- int entityNum;
- ALint state;
- src_t *curSource;
-
- for(i = 0; i < srcCount; i++)
- {
- entityNum = srcList[i].entity;
- curSource = &srcList[i];
-
- if(curSource->isLocked)
- continue;
-
- if(!curSource->isActive)
- continue;
-
- // Update source parameters
- if((s_alGain->modified) || (s_volume->modified))
- curSource->curGain = s_alGain->value * s_volume->value;
- if((s_alRolloff->modified) && (!curSource->local))
- qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
- if(s_alMinDistance->modified)
- qalSourcef(curSource->alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
-
- if(curSource->isLooping)
- {
- sentity_t *sent = &entityList[ entityNum ];
-
- // If a looping effect hasn't been touched this frame, pause or kill it
- if(sent->loopAddedThisFrame)
- {
- alSfx_t *curSfx;
-
- // The sound has changed without an intervening removal
- if(curSource->isActive && !sent->startLoopingSound &&
- curSource->sfx != sent->loopSfx)
- {
- S_AL_NewLoopMaster(curSource, qtrue);
-
- curSource->isPlaying = qfalse;
- qalSourceStop(curSource->alSource);
- qalSourcei(curSource->alSource, AL_BUFFER, 0);
- sent->startLoopingSound = qtrue;
- }
-
- // The sound hasn't been started yet
- if(sent->startLoopingSound)
- {
- S_AL_SrcSetup(i, sent->loopSfx, sent->loopPriority,
- entityNum, -1, curSource->local);
- curSource->isLooping = qtrue;
-
- knownSfx[curSource->sfx].loopCnt++;
- sent->startLoopingSound = qfalse;
- }
-
- curSfx = &knownSfx[curSource->sfx];
-
- S_AL_ScaleGain(curSource, curSource->loopSpeakerPos);
- if(!curSource->scaleGain)
- {
- if(curSource->isPlaying)
- {
- // Sound is mute, stop playback until we are in range again
- S_AL_NewLoopMaster(curSource, qfalse);
- qalSourceStop(curSource->alSource);
- curSource->isPlaying = qfalse;
- }
- else if(!curSfx->loopActiveCnt && curSfx->masterLoopSrc < 0)
- curSfx->masterLoopSrc = i;
-
- continue;
- }
-
- if(!curSource->isPlaying)
- {
- if(curSource->priority == SRCPRI_AMBIENT)
- {
- // If there are other ambient looping sources with the same sound,
- // make sure the sound of these sources are in sync.
-
- if(curSfx->loopActiveCnt)
- {
- int offset, error;
-
- // we already have a master loop playing, get buffer position.
- S_AL_ClearError(qfalse);
- qalGetSourcei(srcList[curSfx->masterLoopSrc].alSource, AL_SAMPLE_OFFSET, &offset);
- if((error = qalGetError()) != AL_NO_ERROR)
- {
- if(error != AL_INVALID_ENUM)
- {
- Com_Printf(S_COLOR_YELLOW "WARNING: Cannot get sample offset from source %d: "
- "%s\n", i, S_AL_ErrorMsg(error));
- }
- }
- else
- qalSourcei(curSource->alSource, AL_SAMPLE_OFFSET, offset);
- }
- else if(curSfx->loopCnt && curSfx->masterLoopSrc >= 0)
- {
- float secofs;
-
- src_t *master = &srcList[curSfx->masterLoopSrc];
- // This loop sound used to be played, but all sources are stopped. Use last sample position/time
- // to calculate offset so the player thinks the sources continued playing while they were inaudible.
-
- if(master->lastTimePos >= 0)
- {
- secofs = master->lastTimePos + (Sys_Milliseconds() - master->lastSampleTime) / 1000.0f;
- secofs = fmodf(secofs, (float) curSfx->info.samples / curSfx->info.rate);
-
- qalSourcef(curSource->alSource, AL_SEC_OFFSET, secofs);
- }
-
- // I be the master now
- curSfx->masterLoopSrc = i;
- }
- else
- curSfx->masterLoopSrc = i;
- }
- else if(curSource->lastTimePos >= 0)
- {
- float secofs;
-
- // For unsynced loops (SRCPRI_ENTITY) just carry on playing as if the sound was never stopped
-
- secofs = curSource->lastTimePos + (Sys_Milliseconds() - curSource->lastSampleTime) / 1000.0f;
- secofs = fmodf(secofs, (float) curSfx->info.samples / curSfx->info.rate);
- qalSourcef(curSource->alSource, AL_SEC_OFFSET, secofs);
- }
-
- curSfx->loopActiveCnt++;
-
- qalSourcei(curSource->alSource, AL_LOOPING, AL_TRUE);
- curSource->isPlaying = qtrue;
- qalSourcePlay(curSource->alSource);
- }
-
- // Update locality
- if(curSource->local)
- {
- qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_TRUE);
- qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, 0.0f);
- }
- else
- {
- qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_FALSE);
- qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
- }
-
- }
- else if(curSource->priority == SRCPRI_AMBIENT)
- {
- if(curSource->isPlaying)
- {
- S_AL_NewLoopMaster(curSource, qfalse);
- qalSourceStop(curSource->alSource);
- curSource->isPlaying = qfalse;
- }
- }
- else
- S_AL_SrcKill(i);
-
- continue;
- }
-
- // Check if it's done, and flag it
- qalGetSourcei(curSource->alSource, AL_SOURCE_STATE, &state);
- if(state == AL_STOPPED)
- {
- curSource->isPlaying = qfalse;
- S_AL_SrcKill(i);
- continue;
- }
-
- // Query relativity of source, don't move if it's true
- qalGetSourcei(curSource->alSource, AL_SOURCE_RELATIVE, &state);
-
- // See if it needs to be moved
- if(curSource->isTracking && !state)
- {
- qalSourcefv(curSource->alSource, AL_POSITION, entityList[entityNum].origin);
- S_AL_ScaleGain(curSource, entityList[entityNum].origin);
- }
- }
-}
-
-/*
-=================
-S_AL_SrcShutup
-=================
-*/
-static
-void S_AL_SrcShutup( void )
-{
- int i;
- for(i = 0; i < srcCount; i++)
- S_AL_SrcKill(i);
-}
-
-/*
-=================
-S_AL_SrcGet
-=================
-*/
-static
-ALuint S_AL_SrcGet(srcHandle_t src)
-{
- return srcList[src].alSource;
-}
-
-
-//===========================================================================
-
-static srcHandle_t streamSourceHandles[MAX_RAW_STREAMS];
-static qboolean streamPlaying[MAX_RAW_STREAMS];
-static ALuint streamSources[MAX_RAW_STREAMS];
-
-/*
-=================
-S_AL_AllocateStreamChannel
-=================
-*/
-static void S_AL_AllocateStreamChannel( int stream )
-{
- if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
- return;
-
- // Allocate a streamSource at high priority
- streamSourceHandles[stream] = S_AL_SrcAlloc(SRCPRI_STREAM, -2, 0);
- if(streamSourceHandles[stream] == -1)
- return;
-
- // Lock the streamSource so nobody else can use it, and get the raw streamSource
- S_AL_SrcLock(streamSourceHandles[stream]);
- streamSources[stream] = S_AL_SrcGet(streamSourceHandles[stream]);
-
- // make sure that after unmuting the S_AL_Gain in S_Update() does not turn
- // volume up prematurely for this source
- srcList[streamSourceHandles[stream]].scaleGain = 0.0f;
-
- // Set some streamSource parameters
- qalSourcei (streamSources[stream], AL_BUFFER, 0 );
- qalSourcei (streamSources[stream], AL_LOOPING, AL_FALSE );
- qalSource3f(streamSources[stream], AL_POSITION, 0.0, 0.0, 0.0);
- qalSource3f(streamSources[stream], AL_VELOCITY, 0.0, 0.0, 0.0);
- qalSource3f(streamSources[stream], AL_DIRECTION, 0.0, 0.0, 0.0);
- qalSourcef (streamSources[stream], AL_ROLLOFF_FACTOR, 0.0 );
- qalSourcei (streamSources[stream], AL_SOURCE_RELATIVE, AL_TRUE );
-}
-
-/*
-=================
-S_AL_FreeStreamChannel
-=================
-*/
-static void S_AL_FreeStreamChannel( int stream )
-{
- if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
- return;
-
- // Release the output streamSource
- S_AL_SrcUnlock(streamSourceHandles[stream]);
- streamSources[stream] = 0;
- streamSourceHandles[stream] = -1;
-}
-
-/*
-=================
-S_AL_RawSamples
-=================
-*/
-static
-void S_AL_RawSamples(int stream, int samples, int rate, int width, int channels, const byte *data, float volume)
-{
- ALuint buffer;
- ALuint format;
-
- if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
- return;
-
- format = S_AL_Format( width, channels );
-
- // Create the streamSource if necessary
- if(streamSourceHandles[stream] == -1)
- {
- S_AL_AllocateStreamChannel(stream);
-
- // Failed?
- if(streamSourceHandles[stream] == -1)
- {
- Com_Printf( S_COLOR_RED "ERROR: Can't allocate streaming streamSource\n");
- return;
- }
- }
-
- // Create a buffer, and stuff the data into it
- qalGenBuffers(1, &buffer);
- qalBufferData(buffer, format, (ALvoid *)data, (samples * width * channels), rate);
-
- // Shove the data onto the streamSource
- qalSourceQueueBuffers(streamSources[stream], 1, &buffer);
-
- // Volume
- S_AL_Gain (streamSources[stream], volume * s_volume->value * s_alGain->value);
-}
-
-/*
-=================
-S_AL_StreamUpdate
-=================
-*/
-static
-void S_AL_StreamUpdate( int stream )
-{
- int numBuffers;
- ALint state;
-
- if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
- return;
-
- if(streamSourceHandles[stream] == -1)
- return;
-
- // Un-queue any buffers, and delete them
- qalGetSourcei( streamSources[stream], AL_BUFFERS_PROCESSED, &numBuffers );
- while( numBuffers-- )
- {
- ALuint buffer;
- qalSourceUnqueueBuffers(streamSources[stream], 1, &buffer);
- qalDeleteBuffers(1, &buffer);
- }
-
- // Start the streamSource playing if necessary
- qalGetSourcei( streamSources[stream], AL_BUFFERS_QUEUED, &numBuffers );
-
- qalGetSourcei(streamSources[stream], AL_SOURCE_STATE, &state);
- if(state == AL_STOPPED)
- {
- streamPlaying[stream] = qfalse;
-
- // If there are no buffers queued up, release the streamSource
- if( !numBuffers )
- S_AL_FreeStreamChannel( stream );
- }
-
- if( !streamPlaying[stream] && numBuffers )
- {
- qalSourcePlay( streamSources[stream] );
- streamPlaying[stream] = qtrue;
- }
-}
-
-/*
-=================
-S_AL_StreamDie
-=================
-*/
-static
-void S_AL_StreamDie( int stream )
-{
- int numBuffers;
-
- if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
- return;
-
- if(streamSourceHandles[stream] == -1)
- return;
-
- streamPlaying[stream] = qfalse;
- qalSourceStop(streamSources[stream]);
-
- // Un-queue any buffers, and delete them
- qalGetSourcei( streamSources[stream], AL_BUFFERS_PROCESSED, &numBuffers );
- while( numBuffers-- )
- {
- ALuint buffer;
- qalSourceUnqueueBuffers(streamSources[stream], 1, &buffer);
- qalDeleteBuffers(1, &buffer);
- }
-
- S_AL_FreeStreamChannel(stream);
-}
-
-
-//===========================================================================
-
-
-#define NUM_MUSIC_BUFFERS 4
-#define MUSIC_BUFFER_SIZE 4096
-
-static qboolean musicPlaying = qfalse;
-static srcHandle_t musicSourceHandle = -1;
-static ALuint musicSource;
-static ALuint musicBuffers[NUM_MUSIC_BUFFERS];
-
-static snd_stream_t *mus_stream;
-static snd_stream_t *intro_stream;
-static char s_backgroundLoop[MAX_QPATH];
-
-static byte decode_buffer[MUSIC_BUFFER_SIZE];
-
-/*
-=================
-S_AL_MusicSourceGet
-=================
-*/
-static void S_AL_MusicSourceGet( void )
-{
- // Allocate a musicSource at high priority
- musicSourceHandle = S_AL_SrcAlloc(SRCPRI_STREAM, -2, 0);
- if(musicSourceHandle == -1)
- return;
-
- // Lock the musicSource so nobody else can use it, and get the raw musicSource
- S_AL_SrcLock(musicSourceHandle);
- musicSource = S_AL_SrcGet(musicSourceHandle);
-
- // make sure that after unmuting the S_AL_Gain in S_Update() does not turn
- // volume up prematurely for this source
- srcList[musicSourceHandle].scaleGain = 0.0f;
-
- // Set some musicSource parameters
- qalSource3f(musicSource, AL_POSITION, 0.0, 0.0, 0.0);
- qalSource3f(musicSource, AL_VELOCITY, 0.0, 0.0, 0.0);
- qalSource3f(musicSource, AL_DIRECTION, 0.0, 0.0, 0.0);
- qalSourcef (musicSource, AL_ROLLOFF_FACTOR, 0.0 );
- qalSourcei (musicSource, AL_SOURCE_RELATIVE, AL_TRUE );
-}
-
-/*
-=================
-S_AL_MusicSourceFree
-=================
-*/
-static void S_AL_MusicSourceFree( void )
-{
- // Release the output musicSource
- S_AL_SrcUnlock(musicSourceHandle);
- musicSource = 0;
- musicSourceHandle = -1;
-}
-
-/*
-=================
-S_AL_CloseMusicFiles
-=================
-*/
-static void S_AL_CloseMusicFiles(void)
-{
- if(intro_stream)
- {
- S_CodecCloseStream(intro_stream);
- intro_stream = NULL;
- }
-
- if(mus_stream)
- {
- S_CodecCloseStream(mus_stream);
- mus_stream = NULL;
- }
-}
-
-/*
-=================
-S_AL_StopBackgroundTrack
-=================
-*/
-static
-void S_AL_StopBackgroundTrack( void )
-{
- if(!musicPlaying)
- return;
-
- // Stop playing
- qalSourceStop(musicSource);
-
- // De-queue the musicBuffers
- qalSourceUnqueueBuffers(musicSource, NUM_MUSIC_BUFFERS, musicBuffers);
-
- // Destroy the musicBuffers
- qalDeleteBuffers(NUM_MUSIC_BUFFERS, musicBuffers);
-
- // Free the musicSource
- S_AL_MusicSourceFree();
-
- // Unload the stream
- S_AL_CloseMusicFiles();
-
- musicPlaying = qfalse;
-}
-
-/*
-=================
-S_AL_MusicProcess
-=================
-*/
-static
-void S_AL_MusicProcess(ALuint b)
-{
- ALenum error;
- int l;
- ALuint format;
- snd_stream_t *curstream;
-
- S_AL_ClearError( qfalse );
-
- if(intro_stream)
- curstream = intro_stream;
- else
- curstream = mus_stream;
-
- if(!curstream)
- return;
-
- l = S_CodecReadStream(curstream, MUSIC_BUFFER_SIZE, decode_buffer);
-
- // Run out data to read, start at the beginning again
- if(l == 0)
- {
- S_CodecCloseStream(curstream);
-
- // the intro stream just finished playing so we don't need to reopen
- // the music stream.
- if(intro_stream)
- intro_stream = NULL;
- else
- mus_stream = S_CodecOpenStream(s_backgroundLoop);
-
- curstream = mus_stream;
-
- if(!curstream)
- {
- S_AL_StopBackgroundTrack();
- return;
- }
-
- l = S_CodecReadStream(curstream, MUSIC_BUFFER_SIZE, decode_buffer);
- }
-
- format = S_AL_Format(curstream->info.width, curstream->info.channels);
-
- if( l == 0 )
- {
- // We have no data to buffer, so buffer silence
- byte dummyData[ 2 ] = { 0 };
-
- qalBufferData( b, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050 );
- }
- else
- qalBufferData(b, format, decode_buffer, l, curstream->info.rate);
-
- if( ( error = qalGetError( ) ) != AL_NO_ERROR )
- {
- S_AL_StopBackgroundTrack( );
- Com_Printf( S_COLOR_RED "ERROR: while buffering data for music stream - %s\n",
- S_AL_ErrorMsg( error ) );
- return;
- }
-}
-
-/*
-=================
-S_AL_StartBackgroundTrack
-=================
-*/
-static
-void S_AL_StartBackgroundTrack( const char *intro, const char *loop )
-{
- int i;
- qboolean issame;
-
- // Stop any existing music that might be playing
- S_AL_StopBackgroundTrack();
-
- if((!intro || !*intro) && (!loop || !*loop))
- return;
-
- // Allocate a musicSource
- S_AL_MusicSourceGet();
- if(musicSourceHandle == -1)
- return;
-
- if (!loop || !*loop)
- {
- loop = intro;
- issame = qtrue;
- }
- else if(intro && *intro && !strcmp(intro, loop))
- issame = qtrue;
- else
- issame = qfalse;
-
- // Copy the loop over
- strncpy( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) );
-
- if(!issame)
- {
- // Open the intro and don't mind whether it succeeds.
- // The important part is the loop.
- intro_stream = S_CodecOpenStream(intro);
- }
- else
- intro_stream = NULL;
-
- mus_stream = S_CodecOpenStream(s_backgroundLoop);
- if(!mus_stream)
- {
- S_AL_CloseMusicFiles();
- S_AL_MusicSourceFree();
- return;
- }
-
- // Generate the musicBuffers
- qalGenBuffers(NUM_MUSIC_BUFFERS, musicBuffers);
-
- // Queue the musicBuffers up
- for(i = 0; i < NUM_MUSIC_BUFFERS; i++)
- {
- S_AL_MusicProcess(musicBuffers[i]);
- }
-
- qalSourceQueueBuffers(musicSource, NUM_MUSIC_BUFFERS, musicBuffers);
-
- // Set the initial gain property
- S_AL_Gain(musicSource, s_alGain->value * s_musicVolume->value);
-
- // Start playing
- qalSourcePlay(musicSource);
-
- musicPlaying = qtrue;
-}
-
-/*
-=================
-S_AL_MusicUpdate
-=================
-*/
-static
-void S_AL_MusicUpdate( void )
-{
- int numBuffers;
- ALint state;
-
- if(!musicPlaying)
- return;
-
- qalGetSourcei( musicSource, AL_BUFFERS_PROCESSED, &numBuffers );
- while( numBuffers-- )
- {
- ALuint b;
- qalSourceUnqueueBuffers(musicSource, 1, &b);
- S_AL_MusicProcess(b);
- qalSourceQueueBuffers(musicSource, 1, &b);
- }
-
- // Hitches can cause OpenAL to be starved of buffers when streaming.
- // If this happens, it will stop playback. This restarts the source if
- // it is no longer playing, and if there are buffers available
- qalGetSourcei( musicSource, AL_SOURCE_STATE, &state );
- qalGetSourcei( musicSource, AL_BUFFERS_QUEUED, &numBuffers );
- if( state == AL_STOPPED && numBuffers )
- {
- Com_DPrintf( S_COLOR_YELLOW "Restarted OpenAL music\n" );
- qalSourcePlay(musicSource);
- }
-
- // Set the gain property
- S_AL_Gain(musicSource, s_alGain->value * s_musicVolume->value);
-}
-
-
-//===========================================================================
-
-
-// Local state variables
-static ALCdevice *alDevice;
-static ALCcontext *alContext;
-
-#ifdef USE_VOIP
-static ALCdevice *alCaptureDevice;
-static cvar_t *s_alCapture;
-#endif
-
-#ifdef _WIN32
-#define ALDRIVER_DEFAULT "OpenAL32.dll"
-#elif defined(MACOS_X)
-#define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL"
-#else
-#define ALDRIVER_DEFAULT "libopenal.so.1"
-#endif
-
-/*
-=================
-S_AL_StopAllSounds
-=================
-*/
-static
-void S_AL_StopAllSounds( void )
-{
- int i;
- S_AL_SrcShutup();
- S_AL_StopBackgroundTrack();
- for (i = 0; i < MAX_RAW_STREAMS; i++)
- S_AL_StreamDie(i);
-}
-
-/*
-=================
-S_AL_Respatialize
-=================
-*/
-static
-void S_AL_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater )
-{
- float velocity[3] = {0.0f, 0.0f, 0.0f};
- float orientation[6];
- vec3_t sorigin;
-
- VectorCopy( origin, sorigin );
- S_AL_SanitiseVector( sorigin );
-
- S_AL_SanitiseVector( axis[ 0 ] );
- S_AL_SanitiseVector( axis[ 1 ] );
- S_AL_SanitiseVector( axis[ 2 ] );
-
- orientation[0] = axis[0][0]; orientation[1] = axis[0][1]; orientation[2] = axis[0][2];
- orientation[3] = axis[2][0]; orientation[4] = axis[2][1]; orientation[5] = axis[2][2];
-
- VectorCopy( sorigin, lastListenerOrigin );
-
- // Set OpenAL listener paramaters
- qalListenerfv(AL_POSITION, (ALfloat *)sorigin);
- qalListenerfv(AL_VELOCITY, velocity);
- qalListenerfv(AL_ORIENTATION, orientation);
-}
-
-/*
-=================
-S_AL_Update
-=================
-*/
-static
-void S_AL_Update( void )
-{
- int i;
-
- if(s_muted->modified)
- {
- // muted state changed. Let S_AL_Gain turn up all sources again.
- for(i = 0; i < srcCount; i++)
- {
- if(srcList[i].isActive)
- S_AL_Gain(srcList[i].alSource, srcList[i].scaleGain);
- }
-
- s_muted->modified = qfalse;
- }
-
- // Update SFX channels
- S_AL_SrcUpdate();
-
- // Update streams
- for (i = 0; i < MAX_RAW_STREAMS; i++)
- S_AL_StreamUpdate(i);
- S_AL_MusicUpdate();
-
- // Doppler
- if(s_doppler->modified)
- {
- s_alDopplerFactor->modified = qtrue;
- s_doppler->modified = qfalse;
- }
-
- // Doppler parameters
- if(s_alDopplerFactor->modified)
- {
- if(s_doppler->integer)
- qalDopplerFactor(s_alDopplerFactor->value);
- else
- qalDopplerFactor(0.0f);
- s_alDopplerFactor->modified = qfalse;
- }
- if(s_alDopplerSpeed->modified)
- {
- qalDopplerVelocity(s_alDopplerSpeed->value);
- s_alDopplerSpeed->modified = qfalse;
- }
-
- // Clear the modified flags on the other cvars
- s_alGain->modified = qfalse;
- s_volume->modified = qfalse;
- s_musicVolume->modified = qfalse;
- s_alMinDistance->modified = qfalse;
- s_alRolloff->modified = qfalse;
-}
-
-/*
-=================
-S_AL_DisableSounds
-=================
-*/
-static
-void S_AL_DisableSounds( void )
-{
- S_AL_StopAllSounds();
-}
-
-/*
-=================
-S_AL_BeginRegistration
-=================
-*/
-static
-void S_AL_BeginRegistration( void )
-{
-}
-
-/*
-=================
-S_AL_ClearSoundBuffer
-=================
-*/
-static
-void S_AL_ClearSoundBuffer( void )
-{
-}
-
-/*
-=================
-S_AL_SoundList
-=================
-*/
-static
-void S_AL_SoundList( void )
-{
-}
-
-#ifdef USE_VOIP
-static
-void S_AL_StartCapture( void )
-{
- if (alCaptureDevice != NULL)
- qalcCaptureStart(alCaptureDevice);
-}
-
-static
-int S_AL_AvailableCaptureSamples( void )
-{
- int retval = 0;
- if (alCaptureDevice != NULL)
- {
- ALint samples = 0;
- qalcGetIntegerv(alCaptureDevice, ALC_CAPTURE_SAMPLES, sizeof (samples), &samples);
- retval = (int) samples;
- }
- return retval;
-}
-
-static
-void S_AL_Capture( int samples, byte *data )
-{
- if (alCaptureDevice != NULL)
- qalcCaptureSamples(alCaptureDevice, data, samples);
-}
-
-void S_AL_StopCapture( void )
-{
- if (alCaptureDevice != NULL)
- qalcCaptureStop(alCaptureDevice);
-}
-
-void S_AL_MasterGain( float gain )
-{
- qalListenerf(AL_GAIN, gain);
-}
-#endif
-
-
-/*
-=================
-S_AL_SoundInfo
-=================
-*/
-static
-void S_AL_SoundInfo( void )
-{
- Com_Printf( "OpenAL info:\n" );
- Com_Printf( " Vendor: %s\n", qalGetString( AL_VENDOR ) );
- Com_Printf( " Version: %s\n", qalGetString( AL_VERSION ) );
- Com_Printf( " Renderer: %s\n", qalGetString( AL_RENDERER ) );
- Com_Printf( " AL Extensions: %s\n", qalGetString( AL_EXTENSIONS ) );
- Com_Printf( " ALC Extensions: %s\n", qalcGetString( alDevice, ALC_EXTENSIONS ) );
- if(qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
- {
- Com_Printf(" Device: %s\n", qalcGetString(alDevice, ALC_DEVICE_SPECIFIER));
- Com_Printf("Available Devices:\n%s", s_alAvailableDevices->string);
- }
-}
-
-/*
-=================
-S_AL_Shutdown
-=================
-*/
-static
-void S_AL_Shutdown( void )
-{
- // Shut down everything
- int i;
- for (i = 0; i < MAX_RAW_STREAMS; i++)
- S_AL_StreamDie(i);
- S_AL_StopBackgroundTrack( );
- S_AL_SrcShutdown( );
- S_AL_BufferShutdown( );
-
- qalcDestroyContext(alContext);
- qalcCloseDevice(alDevice);
-
-#ifdef USE_VOIP
- if (alCaptureDevice != NULL) {
- qalcCaptureStop(alCaptureDevice);
- qalcCaptureCloseDevice(alCaptureDevice);
- alCaptureDevice = NULL;
- Com_Printf( "OpenAL capture device closed.\n" );
- }
-#endif
-
- for (i = 0; i < MAX_RAW_STREAMS; i++) {
- streamSourceHandles[i] = -1;
- streamPlaying[i] = qfalse;
- streamSources[i] = 0;
- }
-
- QAL_Shutdown();
-}
-
-#endif
-
-/*
-=================
-S_AL_Init
-=================
-*/
-qboolean S_AL_Init( soundInterface_t *si )
-{
-#ifdef USE_OPENAL
- const char* device = NULL;
- int i;
-
- if( !si ) {
- return qfalse;
- }
-
- for (i = 0; i < MAX_RAW_STREAMS; i++) {
- streamSourceHandles[i] = -1;
- streamPlaying[i] = qfalse;
- streamSources[i] = 0;
- }
-
- // New console variables
- s_alPrecache = Cvar_Get( "s_alPrecache", "1", CVAR_ARCHIVE );
- s_alGain = Cvar_Get( "s_alGain", "1.0", CVAR_ARCHIVE );
- s_alSources = Cvar_Get( "s_alSources", "96", CVAR_ARCHIVE );
- s_alDopplerFactor = Cvar_Get( "s_alDopplerFactor", "1.0", CVAR_ARCHIVE );
- s_alDopplerSpeed = Cvar_Get( "s_alDopplerSpeed", "2200", CVAR_ARCHIVE );
- s_alMinDistance = Cvar_Get( "s_alMinDistance", "120", CVAR_CHEAT );
- s_alMaxDistance = Cvar_Get("s_alMaxDistance", "1024", CVAR_CHEAT);
- s_alRolloff = Cvar_Get( "s_alRolloff", "2", CVAR_CHEAT);
- s_alGraceDistance = Cvar_Get("s_alGraceDistance", "512", CVAR_CHEAT);
-
- s_alDriver = Cvar_Get( "s_alDriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH );
-
- s_alDevice = Cvar_Get("s_alDevice", "", CVAR_ARCHIVE | CVAR_LATCH);
-
- // Load QAL
- if( !QAL_Init( s_alDriver->string ) )
- {
- Com_Printf( "Failed to load library: \"%s\".\n", s_alDriver->string );
- return qfalse;
- }
-
- device = s_alDevice->string;
- if(device && !*device)
- device = NULL;
-
- // Device enumeration support (extension is implemented reasonably only on Windows right now).
- if(qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
- {
- char devicenames[1024] = "";
- const char *devicelist;
- const char *defaultdevice;
- int curlen;
-
- // get all available devices + the default device name.
- devicelist = qalcGetString(NULL, ALC_DEVICE_SPECIFIER);
- defaultdevice = qalcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
-
-#ifdef _WIN32
- // check whether the default device is generic hardware. If it is, change to
- // Generic Software as that one works more reliably with various sound systems.
- // If it's not, use OpenAL's default selection as we don't want to ignore
- // native hardware acceleration.
- if(!device && !strcmp(defaultdevice, "Generic Hardware"))
- device = "Generic Software";
-#endif
-
- // dump a list of available devices to a cvar for the user to see.
- while((curlen = strlen(devicelist)))
- {
- Q_strcat(devicenames, sizeof(devicenames), devicelist);
- Q_strcat(devicenames, sizeof(devicenames), "\n");
-
- devicelist += curlen + 1;
- }
-
- s_alAvailableDevices = Cvar_Get("s_alAvailableDevices", devicenames, CVAR_ROM | CVAR_NORESTART);
- }
-
- alDevice = qalcOpenDevice(device);
- if( !alDevice && device )
- {
- Com_Printf( "Failed to open OpenAL device '%s', trying default.\n", device );
- alDevice = qalcOpenDevice(NULL);
- }
-
- if( !alDevice )
- {
- QAL_Shutdown( );
- Com_Printf( "Failed to open OpenAL device.\n" );
- return qfalse;
- }
-
- // Create OpenAL context
- alContext = qalcCreateContext( alDevice, NULL );
- if( !alContext )
- {
- QAL_Shutdown( );
- qalcCloseDevice( alDevice );
- Com_Printf( "Failed to create OpenAL context.\n" );
- return qfalse;
- }
- qalcMakeContextCurrent( alContext );
-
- // Initialize sources, buffers, music
- S_AL_BufferInit( );
- S_AL_SrcInit( );
-
- // Set up OpenAL parameters (doppler, etc)
- qalDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
- qalDopplerFactor( s_alDopplerFactor->value );
- qalDopplerVelocity( s_alDopplerSpeed->value );
-
-#ifdef USE_VOIP
- // !!! FIXME: some of these alcCaptureOpenDevice() values should be cvars.
- // !!! FIXME: add support for capture device enumeration.
- // !!! FIXME: add some better error reporting.
- s_alCapture = Cvar_Get( "s_alCapture", "1", CVAR_ARCHIVE | CVAR_LATCH );
- if (!s_alCapture->integer)
- {
- Com_Printf("OpenAL capture support disabled by user ('+set s_alCapture 1' to enable)\n");
- }
-#if USE_MUMBLE
- else if (cl_useMumble->integer)
- {
- Com_Printf("OpenAL capture support disabled for Mumble support\n");
- }
-#endif
- else
- {
-#ifdef MACOS_X
- // !!! FIXME: Apple has a 1.1-compliant OpenAL, which includes
- // !!! FIXME: capture support, but they don't list it in the
- // !!! FIXME: extension string. We need to check the version string,
- // !!! FIXME: then the extension string, but that's too much trouble,
- // !!! FIXME: so we'll just check the function pointer for now.
- if (qalcCaptureOpenDevice == NULL)
-#else
- if (!qalcIsExtensionPresent(NULL, "ALC_EXT_capture"))
-#endif
- {
- Com_Printf("No ALC_EXT_capture support, can't record audio.\n");
- }
- else
- {
- // !!! FIXME: 8000Hz is what Speex narrowband mode needs, but we
- // !!! FIXME: should probably open the capture device after
- // !!! FIXME: initializing Speex so we can change to wideband
- // !!! FIXME: if we like.
- Com_Printf("OpenAL default capture device is '%s'\n",
- qalcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
- alCaptureDevice = qalcCaptureOpenDevice(NULL, 8000, AL_FORMAT_MONO16, 4096);
- Com_Printf( "OpenAL capture device %s.\n",
- (alCaptureDevice == NULL) ? "failed to open" : "opened");
- }
- }
-#endif
-
- si->Shutdown = S_AL_Shutdown;
- si->StartSound = S_AL_StartSound;
- si->StartLocalSound = S_AL_StartLocalSound;
- si->StartBackgroundTrack = S_AL_StartBackgroundTrack;
- si->StopBackgroundTrack = S_AL_StopBackgroundTrack;
- si->RawSamples = S_AL_RawSamples;
- si->StopAllSounds = S_AL_StopAllSounds;
- si->ClearLoopingSounds = S_AL_ClearLoopingSounds;
- si->AddLoopingSound = S_AL_AddLoopingSound;
- si->AddRealLoopingSound = S_AL_AddRealLoopingSound;
- si->StopLoopingSound = S_AL_StopLoopingSound;
- si->Respatialize = S_AL_Respatialize;
- si->UpdateEntityPosition = S_AL_UpdateEntityPosition;
- si->Update = S_AL_Update;
- si->DisableSounds = S_AL_DisableSounds;
- si->BeginRegistration = S_AL_BeginRegistration;
- si->RegisterSound = S_AL_RegisterSound;
- si->ClearSoundBuffer = S_AL_ClearSoundBuffer;
- si->SoundInfo = S_AL_SoundInfo;
- si->SoundList = S_AL_SoundList;
-
-#ifdef USE_VOIP
- si->StartCapture = S_AL_StartCapture;
- si->AvailableCaptureSamples = S_AL_AvailableCaptureSamples;
- si->Capture = S_AL_Capture;
- si->StopCapture = S_AL_StopCapture;
- si->MasterGain = S_AL_MasterGain;
-#endif
-
- return qtrue;
-#else
- return qfalse;
-#endif
-}
-
diff --git a/engine/code/client/snd_public.h b/engine/code/client/snd_public.h
deleted file mode 100644
index 1587f33..0000000
--- a/engine/code/client/snd_public.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-
-void S_Init( void );
-void S_Shutdown( void );
-
-// if origin is NULL, the sound will be dynamically sourced from the entity
-void S_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx );
-void S_StartLocalSound( sfxHandle_t sfx, int channelNum );
-
-void S_StartBackgroundTrack( const char *intro, const char *loop );
-void S_StopBackgroundTrack( void );
-
-// cinematics and voice-over-network will send raw samples
-// 1.0 volume will be direct output of source samples
-void S_RawSamples (int stream, int samples, int rate, int width, int channels,
- const byte *data, float volume);
-
-// stop all sounds and the background track
-void S_StopAllSounds( void );
-
-// all continuous looping sounds must be added before calling S_Update
-void S_ClearLoopingSounds( qboolean killall );
-void S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
-void S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
-void S_StopLoopingSound(int entityNum );
-
-// recompute the reletive volumes for all running sounds
-// reletive to the given entityNum / orientation
-void S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
-
-// let the sound system know where an entity currently is
-void S_UpdateEntityPosition( int entityNum, const vec3_t origin );
-
-void S_Update( void );
-
-void S_DisableSounds( void );
-
-void S_BeginRegistration( void );
-
-// RegisterSound will allways return a valid sample, even if it
-// has to create a placeholder. This prevents continuous filesystem
-// checks for missing files
-sfxHandle_t S_RegisterSound( const char *sample, qboolean compressed );
-
-void S_DisplayFreeMemory(void);
-
-void S_ClearSoundBuffer( void );
-
-void SNDDMA_Activate( void );
-
-void S_UpdateBackgroundTrack( void );
-
-
-#ifdef USE_VOIP
-void S_StartCapture( void );
-int S_AvailableCaptureSamples( void );
-void S_Capture( int samples, byte *data );
-void S_StopCapture( void );
-void S_MasterGain( float gain );
-#endif
-
diff --git a/engine/code/client/snd_wavelet.c b/engine/code/client/snd_wavelet.c
deleted file mode 100644
index 41b5723..0000000
--- a/engine/code/client/snd_wavelet.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "snd_local.h"
-
-long myftol( float f );
-
-#define C0 0.4829629131445341
-#define C1 0.8365163037378079
-#define C2 0.2241438680420134
-#define C3 -0.1294095225512604
-
-void daub4(float b[], unsigned long n, int isign)
-{
- float wksp[4097];
- float *a=b-1; // numerical recipies so a[1] = b[0]
-
- unsigned long nh,nh1,i,j;
-
- if (n < 4) return;
-
- nh1=(nh=n >> 1)+1;
- if (isign >= 0) {
- for (i=1,j=1;j<=n-3;j+=2,i++) {
- wksp[i] = C0*a[j]+C1*a[j+1]+C2*a[j+2]+C3*a[j+3];
- wksp[i+nh] = C3*a[j]-C2*a[j+1]+C1*a[j+2]-C0*a[j+3];
- }
- wksp[i ] = C0*a[n-1]+C1*a[n]+C2*a[1]+C3*a[2];
- wksp[i+nh] = C3*a[n-1]-C2*a[n]+C1*a[1]-C0*a[2];
- } else {
- wksp[1] = C2*a[nh]+C1*a[n]+C0*a[1]+C3*a[nh1];
- wksp[2] = C3*a[nh]-C0*a[n]+C1*a[1]-C2*a[nh1];
- for (i=1,j=3;i<nh;i++) {
- wksp[j++] = C2*a[i]+C1*a[i+nh]+C0*a[i+1]+C3*a[i+nh1];
- wksp[j++] = C3*a[i]-C0*a[i+nh]+C1*a[i+1]-C2*a[i+nh1];
- }
- }
- for (i=1;i<=n;i++) {
- a[i]=wksp[i];
- }
-}
-
-void wt1(float a[], unsigned long n, int isign)
-{
- unsigned long nn;
- int inverseStartLength = n/4;
- if (n < inverseStartLength) return;
- if (isign >= 0) {
- for (nn=n;nn>=inverseStartLength;nn>>=1) daub4(a,nn,isign);
- } else {
- for (nn=inverseStartLength;nn<=n;nn<<=1) daub4(a,nn,isign);
- }
-}
-
-/* The number of bits required by each value */
-static unsigned char numBits[] = {
- 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
-};
-
-byte MuLawEncode(short s) {
- unsigned long adjusted;
- byte sign, exponent, mantissa;
-
- sign = (s<0)?0:0x80;
-
- if (s<0) s=-s;
- adjusted = (long)s << (16-sizeof(short)*8);
- adjusted += 128L + 4L;
- if (adjusted > 32767) adjusted = 32767;
- exponent = numBits[(adjusted>>7)&0xff] - 1;
- mantissa = (adjusted>>(exponent+3))&0xf;
- return ~(sign | (exponent<<4) | mantissa);
-}
-
-short MuLawDecode(byte uLaw) {
- signed long adjusted;
- byte exponent, mantissa;
-
- uLaw = ~uLaw;
- exponent = (uLaw>>4) & 0x7;
- mantissa = (uLaw&0xf) + 16;
- adjusted = (mantissa << (exponent +3)) - 128 - 4;
-
- return (uLaw & 0x80)? adjusted : -adjusted;
-}
-
-short mulawToShort[256];
-static qboolean madeTable = qfalse;
-
-static int NXStreamCount;
-
-void NXPutc(NXStream *stream, char out) {
- stream[NXStreamCount++] = out;
-}
-
-
-void encodeWavelet( sfx_t *sfx, short *packets) {
- float wksp[4097], temp;
- int i, samples, size;
- sndBuffer *newchunk, *chunk;
- byte *out;
-
- if (!madeTable) {
- for (i=0;i<256;i++) {
- mulawToShort[i] = (float)MuLawDecode((byte)i);
- }
- madeTable = qtrue;
- }
- chunk = NULL;
-
- samples = sfx->soundLength;
- while(samples>0) {
- size = samples;
- if (size>(SND_CHUNK_SIZE*2)) {
- size = (SND_CHUNK_SIZE*2);
- }
-
- if (size<4) {
- size = 4;
- }
-
- newchunk = SND_malloc();
- if (sfx->soundData == NULL) {
- sfx->soundData = newchunk;
- } else {
- chunk->next = newchunk;
- }
- chunk = newchunk;
- for(i=0; i<size; i++) {
- wksp[i] = *packets;
- packets++;
- }
- wt1(wksp, size, 1);
- out = (byte *)chunk->sndChunk;
-
- for(i=0;i<size;i++) {
- temp = wksp[i];
- if (temp > 32767) temp = 32767; else if (temp<-32768) temp = -32768;
- out[i] = MuLawEncode((short)temp);
- }
-
- chunk->size = size;
- samples -= size;
- }
-}
-
-void decodeWavelet(sndBuffer *chunk, short *to) {
- float wksp[4097];
- int i;
- byte *out;
-
- int size = chunk->size;
-
- out = (byte *)chunk->sndChunk;
- for(i=0;i<size;i++) {
- wksp[i] = mulawToShort[out[i]];
- }
-
- wt1(wksp, size, -1);
-
- if (!to) return;
-
- for(i=0; i<size; i++) {
- to[i] = wksp[i];
- }
-}
-
-
-void encodeMuLaw( sfx_t *sfx, short *packets) {
- int i, samples, size, grade, poop;
- sndBuffer *newchunk, *chunk;
- byte *out;
-
- if (!madeTable) {
- for (i=0;i<256;i++) {
- mulawToShort[i] = (float)MuLawDecode((byte)i);
- }
- madeTable = qtrue;
- }
-
- chunk = NULL;
- samples = sfx->soundLength;
- grade = 0;
-
- while(samples>0) {
- size = samples;
- if (size>(SND_CHUNK_SIZE*2)) {
- size = (SND_CHUNK_SIZE*2);
- }
-
- newchunk = SND_malloc();
- if (sfx->soundData == NULL) {
- sfx->soundData = newchunk;
- } else {
- chunk->next = newchunk;
- }
- chunk = newchunk;
- out = (byte *)chunk->sndChunk;
- for(i=0; i<size; i++) {
- poop = packets[0]+grade;
- if (poop>32767) {
- poop = 32767;
- } else if (poop<-32768) {
- poop = -32768;
- }
- out[i] = MuLawEncode((short)poop);
- grade = poop - mulawToShort[out[i]];
- packets++;
- }
- chunk->size = size;
- samples -= size;
- }
-}
-
-void decodeMuLaw(sndBuffer *chunk, short *to) {
- int i;
- byte *out;
-
- int size = chunk->size;
-
- out = (byte *)chunk->sndChunk;
- for(i=0;i<size;i++) {
- to[i] = mulawToShort[out[i]];
- }
-}
-
-
diff --git a/engine/code/game/ai_chat.c b/engine/code/game/ai_chat.c
deleted file mode 100644
index a55cbea..0000000
--- a/engine/code/game/ai_chat.c
+++ /dev/null
@@ -1,1226 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_chat.c
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /MissionPack/code/game/ai_chat.c $
- *
- *****************************************************************************/
-
-#include "g_local.h"
-#include "../botlib/botlib.h"
-#include "../botlib/be_aas.h"
-#include "../botlib/be_ea.h"
-#include "../botlib/be_ai_char.h"
-#include "../botlib/be_ai_chat.h"
-#include "../botlib/be_ai_gen.h"
-#include "../botlib/be_ai_goal.h"
-#include "../botlib/be_ai_move.h"
-#include "../botlib/be_ai_weap.h"
-//
-#include "ai_main.h"
-#include "ai_dmq3.h"
-#include "ai_chat.h"
-#include "ai_cmd.h"
-#include "ai_dmnet.h"
-//
-#include "chars.h" //characteristics
-#include "inv.h" //indexes into the inventory
-#include "syn.h" //synonyms
-#include "match.h" //string matching types and vars
-
-// for the voice chats
-#ifdef MISSIONPACK
-#include "../../ui/menudef.h"
-#endif
-
-#define TIME_BETWEENCHATTING 25
-
-
-/*
-==================
-BotNumActivePlayers
-==================
-*/
-int BotNumActivePlayers(void) {
- int i, num;
- char buf[MAX_INFO_STRING];
- static int maxclients;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- num = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- num++;
- }
- return num;
-}
-
-/*
-==================
-BotIsFirstInRankings
-==================
-*/
-int BotIsFirstInRankings(bot_state_t *bs) {
- int i, score;
- char buf[MAX_INFO_STRING];
- static int maxclients;
- playerState_t ps;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- score = bs->cur_ps.persistant[PERS_SCORE];
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- BotAI_GetClientState(i, &ps);
- if (score < ps.persistant[PERS_SCORE]) return qfalse;
- }
- return qtrue;
-}
-
-/*
-==================
-BotIsLastInRankings
-==================
-*/
-int BotIsLastInRankings(bot_state_t *bs) {
- int i, score;
- char buf[MAX_INFO_STRING];
- static int maxclients;
- playerState_t ps;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- score = bs->cur_ps.persistant[PERS_SCORE];
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- BotAI_GetClientState(i, &ps);
- if (score > ps.persistant[PERS_SCORE]) return qfalse;
- }
- return qtrue;
-}
-
-/*
-==================
-BotFirstClientInRankings
-==================
-*/
-char *BotFirstClientInRankings(void) {
- int i, bestscore, bestclient;
- char buf[MAX_INFO_STRING];
- static char name[32];
- static int maxclients;
- playerState_t ps;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- bestscore = -999999;
- bestclient = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- BotAI_GetClientState(i, &ps);
- if (ps.persistant[PERS_SCORE] > bestscore) {
- bestscore = ps.persistant[PERS_SCORE];
- bestclient = i;
- }
- }
- EasyClientName(bestclient, name, 32);
- return name;
-}
-
-/*
-==================
-BotLastClientInRankings
-==================
-*/
-char *BotLastClientInRankings(void) {
- int i, worstscore, bestclient;
- char buf[MAX_INFO_STRING];
- static char name[32];
- static int maxclients;
- playerState_t ps;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- worstscore = 999999;
- bestclient = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- BotAI_GetClientState(i, &ps);
- if (ps.persistant[PERS_SCORE] < worstscore) {
- worstscore = ps.persistant[PERS_SCORE];
- bestclient = i;
- }
- }
- EasyClientName(bestclient, name, 32);
- return name;
-}
-
-/*
-==================
-BotRandomOpponentName
-==================
-*/
-char *BotRandomOpponentName(bot_state_t *bs) {
- int i, count;
- char buf[MAX_INFO_STRING];
- int opponents[MAX_CLIENTS], numopponents;
- static int maxclients;
- static char name[32];
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- numopponents = 0;
- opponents[0] = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client) continue;
- //
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //skip team mates
- if (BotSameTeam(bs, i)) continue;
- //
- opponents[numopponents] = i;
- numopponents++;
- }
- count = random() * numopponents;
- for (i = 0; i < numopponents; i++) {
- count--;
- if (count <= 0) {
- EasyClientName(opponents[i], name, sizeof(name));
- return name;
- }
- }
- EasyClientName(opponents[0], name, sizeof(name));
- return name;
-}
-
-/*
-==================
-BotMapTitle
-==================
-*/
-
-char *BotMapTitle(void) {
- char info[1024];
- static char mapname[128];
-
- trap_GetServerinfo(info, sizeof(info));
-
- strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1);
- mapname[sizeof(mapname)-1] = '\0';
-
- return mapname;
-}
-
-
-/*
-==================
-BotWeaponNameForMeansOfDeath
-==================
-*/
-
-char *BotWeaponNameForMeansOfDeath(int mod) {
- switch(mod) {
- case MOD_SHOTGUN: return "Shotgun";
- case MOD_GAUNTLET: return "Gauntlet";
- case MOD_MACHINEGUN: return "Machinegun";
- case MOD_GRENADE:
- case MOD_GRENADE_SPLASH: return "Grenade Launcher";
- case MOD_ROCKET:
- case MOD_ROCKET_SPLASH: return "Rocket Launcher";
- case MOD_PLASMA:
- case MOD_PLASMA_SPLASH: return "Plasmagun";
- case MOD_RAILGUN: return "Railgun";
- case MOD_LIGHTNING: return "Lightning Gun";
- case MOD_BFG:
- case MOD_BFG_SPLASH: return "BFG10K";
-#ifdef MISSIONPACK
- case MOD_NAIL: return "Nailgun";
- case MOD_CHAINGUN: return "Chaingun";
- case MOD_PROXIMITY_MINE: return "Proximity Launcher";
- case MOD_KAMIKAZE: return "Kamikaze";
- case MOD_JUICED: return "Prox mine";
-#endif
- case MOD_GRAPPLE: return "Grapple";
- default: return "[unknown weapon]";
- }
-}
-
-/*
-==================
-BotRandomWeaponName
-==================
-*/
-char *BotRandomWeaponName(void) {
- int rnd;
-
-#ifdef MISSIONPACK
- rnd = random() * 11.9;
-#else
- rnd = random() * 8.9;
-#endif
- switch(rnd) {
- case 0: return "Gauntlet";
- case 1: return "Shotgun";
- case 2: return "Machinegun";
- case 3: return "Grenade Launcher";
- case 4: return "Rocket Launcher";
- case 5: return "Plasmagun";
- case 6: return "Railgun";
- case 7: return "Lightning Gun";
-#ifdef MISSIONPACK
- case 8: return "Nailgun";
- case 9: return "Chaingun";
- case 10: return "Proximity Launcher";
-#endif
- default: return "BFG10K";
- }
-}
-
-/*
-==================
-BotVisibleEnemies
-==================
-*/
-int BotVisibleEnemies(bot_state_t *bs) {
- float vis;
- int i;
- aas_entityinfo_t entinfo;
-
- for (i = 0; i < MAX_CLIENTS; i++) {
-
- if (i == bs->client) continue;
- //
- BotEntityInfo(i, &entinfo);
- //
- if (!entinfo.valid) continue;
- //if the enemy isn't dead and the enemy isn't the bot self
- if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;
- //if the enemy is invisible and not shooting
- if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
- continue;
- }
- //if on the same team
- if (BotSameTeam(bs, i)) continue;
- //check if the enemy is visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
- if (vis > 0) return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-BotValidChatPosition
-==================
-*/
-int BotValidChatPosition(bot_state_t *bs) {
- vec3_t point, start, end, mins, maxs;
- bsp_trace_t trace;
-
- //if the bot is dead all positions are valid
- if (BotIsDead(bs)) return qtrue;
- //never start chatting with a powerup
- if (bs->inventory[INVENTORY_QUAD] ||
- bs->inventory[INVENTORY_HASTE] ||
- bs->inventory[INVENTORY_INVISIBILITY] ||
- bs->inventory[INVENTORY_REGEN] ||
- bs->inventory[INVENTORY_FLIGHT]) return qfalse;
- //must be on the ground
- //if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) return qfalse;
- //do not chat if in lava or slime
- VectorCopy(bs->origin, point);
- point[2] -= 24;
- if (trap_PointContents(point,bs->entitynum) & (CONTENTS_LAVA|CONTENTS_SLIME)) return qfalse;
- //do not chat if under water
- VectorCopy(bs->origin, point);
- point[2] += 32;
- if (trap_PointContents(point,bs->entitynum) & MASK_WATER) return qfalse;
- //must be standing on the world entity
- VectorCopy(bs->origin, start);
- VectorCopy(bs->origin, end);
- start[2] += 1;
- end[2] -= 10;
- trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs);
- BotAI_Trace(&trace, start, mins, maxs, end, bs->client, MASK_SOLID);
- if (trace.ent != ENTITYNUM_WORLD) return qfalse;
- //the bot is in a position where it can chat
- return qtrue;
-}
-
-/*
-==================
-BotChat_EnterGame
-==================
-*/
-int BotChat_EnterGame(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- //don't chat in teamplay
- if (TeamPlayIsOn()) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (BotNumActivePlayers() <= 1) return qfalse;
- if (!BotValidChatPosition(bs)) return qfalse;
- BotAI_BotInitialChat(bs, "game_enter",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_ExitGame
-==================
-*/
-int BotChat_ExitGame(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- //don't chat in teamplay
- if (TeamPlayIsOn()) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (BotNumActivePlayers() <= 1) return qfalse;
- //
- BotAI_BotInitialChat(bs, "game_exit",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_StartLevel
-==================
-*/
-int BotChat_StartLevel(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (BotIsObserver(bs)) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- //don't chat in teamplay
- if (TeamPlayIsOn()) {
- trap_EA_Command(bs->client, "vtaunt");
- return qfalse;
- }
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (BotNumActivePlayers() <= 1) return qfalse;
- BotAI_BotInitialChat(bs, "level_start",
- EasyClientName(bs->client, name, 32), // 0
- NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_EndLevel
-==================
-*/
-int BotChat_EndLevel(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (BotIsObserver(bs)) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- // teamplay
- if (TeamPlayIsOn())
- {
- if (BotIsFirstInRankings(bs)) {
- trap_EA_Command(bs->client, "vtaunt");
- }
- return qtrue;
- }
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (BotNumActivePlayers() <= 1) return qfalse;
- //
- if (BotIsFirstInRankings(bs)) {
- BotAI_BotInitialChat(bs, "level_end_victory",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- "[invalid var]", // 2
- BotLastClientInRankings(), // 3
- BotMapTitle(), // 4
- NULL);
- }
- else if (BotIsLastInRankings(bs)) {
- BotAI_BotInitialChat(bs, "level_end_lose",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- BotFirstClientInRankings(), // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- NULL);
- }
- else {
- BotAI_BotInitialChat(bs, "level_end",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- BotFirstClientInRankings(), // 2
- BotLastClientInRankings(), // 3
- BotMapTitle(), // 4
- NULL);
- }
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_Death
-==================
-*/
-int BotChat_Death(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_DEATH, 0, 1);
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //if fast chatting is off
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (BotNumActivePlayers() <= 1) return qfalse;
- //
- if (bs->lastkilledby >= 0 && bs->lastkilledby < MAX_CLIENTS)
- EasyClientName(bs->lastkilledby, name, 32);
- else
- strcpy(name, "[world]");
- //
- if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledby)) {
- if (bs->lastkilledby == bs->client) return qfalse;
- BotAI_BotInitialChat(bs, "death_teammate", name, NULL);
- bs->chatto = CHAT_TEAM;
- }
- else
- {
- //teamplay
- if (TeamPlayIsOn()) {
- trap_EA_Command(bs->client, "vtaunt");
- return qtrue;
- }
- //
- if (bs->botdeathtype == MOD_WATER)
- BotAI_BotInitialChat(bs, "death_drown", BotRandomOpponentName(bs), NULL);
- else if (bs->botdeathtype == MOD_SLIME)
- BotAI_BotInitialChat(bs, "death_slime", BotRandomOpponentName(bs), NULL);
- else if (bs->botdeathtype == MOD_LAVA)
- BotAI_BotInitialChat(bs, "death_lava", BotRandomOpponentName(bs), NULL);
- else if (bs->botdeathtype == MOD_FALLING)
- BotAI_BotInitialChat(bs, "death_cratered", BotRandomOpponentName(bs), NULL);
- else if (bs->botsuicide || //all other suicides by own weapon
- bs->botdeathtype == MOD_CRUSH ||
- bs->botdeathtype == MOD_SUICIDE ||
- bs->botdeathtype == MOD_TARGET_LASER ||
- bs->botdeathtype == MOD_TRIGGER_HURT ||
- bs->botdeathtype == MOD_UNKNOWN)
- BotAI_BotInitialChat(bs, "death_suicide", BotRandomOpponentName(bs), NULL);
- else if (bs->botdeathtype == MOD_TELEFRAG)
- BotAI_BotInitialChat(bs, "death_telefrag", name, NULL);
-#ifdef MISSIONPACK
- else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "death_kamikaze"))
- BotAI_BotInitialChat(bs, "death_kamikaze", name, NULL);
-#endif
- else {
- if ((bs->botdeathtype == MOD_GAUNTLET ||
- bs->botdeathtype == MOD_RAILGUN ||
- bs->botdeathtype == MOD_BFG ||
- bs->botdeathtype == MOD_BFG_SPLASH) && random() < 0.5) {
-
- if (bs->botdeathtype == MOD_GAUNTLET)
- BotAI_BotInitialChat(bs, "death_gauntlet",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- else if (bs->botdeathtype == MOD_RAILGUN)
- BotAI_BotInitialChat(bs, "death_rail",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- else
- BotAI_BotInitialChat(bs, "death_bfg",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- }
- //choose between insult and praise
- else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {
- BotAI_BotInitialChat(bs, "death_insult",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- }
- else {
- BotAI_BotInitialChat(bs, "death_praise",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- }
- }
- bs->chatto = CHAT_ALL;
- }
- bs->lastchat_time = FloatTime();
- return qtrue;
-}
-
-/*
-==================
-BotChat_Kill
-==================
-*/
-int BotChat_Kill(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1);
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //if fast chat is off
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (bs->lastkilledplayer == bs->client) return qfalse;
- if (BotNumActivePlayers() <= 1) return qfalse;
- if (!BotValidChatPosition(bs)) return qfalse;
- //
- if (BotVisibleEnemies(bs)) return qfalse;
- //
- EasyClientName(bs->lastkilledplayer, name, 32);
- //
- bs->chatto = CHAT_ALL;
- if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledplayer)) {
- BotAI_BotInitialChat(bs, "kill_teammate", name, NULL);
- bs->chatto = CHAT_TEAM;
- }
- else
- {
- //don't chat in teamplay
- if (TeamPlayIsOn()) {
- trap_EA_Command(bs->client, "vtaunt");
- return qfalse; // don't wait
- }
- //
- if (bs->enemydeathtype == MOD_GAUNTLET) {
- BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL);
- }
- else if (bs->enemydeathtype == MOD_RAILGUN) {
- BotAI_BotInitialChat(bs, "kill_rail", name, NULL);
- }
- else if (bs->enemydeathtype == MOD_TELEFRAG) {
- BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL);
- }
-#ifdef MISSIONPACK
- else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "kill_kamikaze"))
- BotAI_BotInitialChat(bs, "kill_kamikaze", name, NULL);
-#endif
- //choose between insult and praise
- else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {
- BotAI_BotInitialChat(bs, "kill_insult", name, NULL);
- }
- else {
- BotAI_BotInitialChat(bs, "kill_praise", name, NULL);
- }
- }
- bs->lastchat_time = FloatTime();
- return qtrue;
-}
-
-/*
-==================
-BotChat_EnemySuicide
-==================
-*/
-int BotChat_EnemySuicide(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- if (BotNumActivePlayers() <= 1) return qfalse;
- //
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1);
- //don't chat in teamplay
- if (TeamPlayIsOn()) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //if fast chat is off
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (!BotValidChatPosition(bs)) return qfalse;
- //
- if (BotVisibleEnemies(bs)) return qfalse;
- //
- if (bs->enemy >= 0) EasyClientName(bs->enemy, name, 32);
- else strcpy(name, "");
- BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_HitTalking
-==================
-*/
-int BotChat_HitTalking(bot_state_t *bs) {
- char name[32], *weap;
- int lasthurt_client;
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- if (BotNumActivePlayers() <= 1) return qfalse;
- lasthurt_client = g_entities[bs->client].client->lasthurt_client;
- if (!lasthurt_client) return qfalse;
- if (lasthurt_client == bs->client) return qfalse;
- //
- if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;
- //
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITTALKING, 0, 1);
- //don't chat in teamplay
- if (TeamPlayIsOn()) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //if fast chat is off
- if (!bot_fastchat.integer) {
- if (random() > rnd * 0.5) return qfalse;
- }
- if (!BotValidChatPosition(bs)) return qfalse;
- //
- ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name));
- weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client);
- //
- BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_HitNoDeath
-==================
-*/
-int BotChat_HitNoDeath(bot_state_t *bs) {
- char name[32], *weap;
- float rnd;
- int lasthurt_client;
- aas_entityinfo_t entinfo;
-
- lasthurt_client = g_entities[bs->client].client->lasthurt_client;
- if (!lasthurt_client) return qfalse;
- if (lasthurt_client == bs->client) return qfalse;
- //
- if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;
- //
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- if (BotNumActivePlayers() <= 1) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNODEATH, 0, 1);
- //don't chat in teamplay
- if (TeamPlayIsOn()) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //if fast chat is off
- if (!bot_fastchat.integer) {
- if (random() > rnd * 0.5) return qfalse;
- }
- if (!BotValidChatPosition(bs)) return qfalse;
- //
- if (BotVisibleEnemies(bs)) return qfalse;
- //
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityIsShooting(&entinfo)) return qfalse;
- //
- ClientName(lasthurt_client, name, sizeof(name));
- weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_mod);
- //
- BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_HitNoKill
-==================
-*/
-int BotChat_HitNoKill(bot_state_t *bs) {
- char name[32], *weap;
- float rnd;
- aas_entityinfo_t entinfo;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- if (BotNumActivePlayers() <= 1) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNOKILL, 0, 1);
- //don't chat in teamplay
- if (TeamPlayIsOn()) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //if fast chat is off
- if (!bot_fastchat.integer) {
- if (random() > rnd * 0.5) return qfalse;
- }
- if (!BotValidChatPosition(bs)) return qfalse;
- //
- if (BotVisibleEnemies(bs)) return qfalse;
- //
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityIsShooting(&entinfo)) return qfalse;
- //
- ClientName(bs->enemy, name, sizeof(name));
- weap = BotWeaponNameForMeansOfDeath(g_entities[bs->enemy].client->lasthurt_mod);
- //
- BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_Random
-==================
-*/
-int BotChat_Random(bot_state_t *bs) {
- float rnd;
- char name[32];
-
- if (bot_nochat.integer) return qfalse;
- if (BotIsObserver(bs)) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //don't chat when doing something important :)
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_RUSHBASE) return qfalse;
- //
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_RANDOM, 0, 1);
- if (random() > bs->thinktime * 0.1) return qfalse;
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- if (random() > 0.25) return qfalse;
- }
- if (BotNumActivePlayers() <= 1) return qfalse;
- //
- if (!BotValidChatPosition(bs)) return qfalse;
- //
- if (BotVisibleEnemies(bs)) return qfalse;
- //
- if (bs->lastkilledplayer == bs->client) {
- strcpy(name, BotRandomOpponentName(bs));
- }
- else {
- EasyClientName(bs->lastkilledplayer, name, sizeof(name));
- }
- if (TeamPlayIsOn()) {
- trap_EA_Command(bs->client, "vtaunt");
- return qfalse; // don't wait
- }
- //
- if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_MISC, 0, 1)) {
- BotAI_BotInitialChat(bs, "random_misc",
- BotRandomOpponentName(bs), // 0
- name, // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- BotRandomWeaponName(), // 5
- NULL);
- }
- else {
- BotAI_BotInitialChat(bs, "random_insult",
- BotRandomOpponentName(bs), // 0
- name, // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- BotRandomWeaponName(), // 5
- NULL);
- }
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChatTime
-==================
-*/
-float BotChatTime(bot_state_t *bs) {
- int cpm;
-
- cpm = trap_Characteristic_BInteger(bs->character, CHARACTERISTIC_CHAT_CPM, 1, 4000);
-
- return 2.0; //(float) trap_BotChatLength(bs->cs) * 30 / cpm;
-}
-
-/*
-==================
-BotChatTest
-==================
-*/
-void BotChatTest(bot_state_t *bs) {
-
- char name[32];
- char *weap;
- int num, i;
-
- num = trap_BotNumInitialChats(bs->cs, "game_enter");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "game_enter",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "game_exit");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "game_exit",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "level_start");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "level_start",
- EasyClientName(bs->client, name, 32), // 0
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "level_end_victory");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "level_end_victory",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- BotFirstClientInRankings(), // 2
- BotLastClientInRankings(), // 3
- BotMapTitle(), // 4
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "level_end_lose");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "level_end_lose",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- BotFirstClientInRankings(), // 2
- BotLastClientInRankings(), // 3
- BotMapTitle(), // 4
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "level_end");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "level_end",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- BotFirstClientInRankings(), // 2
- BotLastClientInRankings(), // 3
- BotMapTitle(), // 4
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- EasyClientName(bs->lastkilledby, name, sizeof(name));
- num = trap_BotNumInitialChats(bs->cs, "death_drown");
- for (i = 0; i < num; i++)
- {
- //
- BotAI_BotInitialChat(bs, "death_drown", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_slime");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_slime", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_lava");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_lava", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_cratered");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_cratered", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_suicide");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_suicide", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_telefrag");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_telefrag", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_gauntlet");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_gauntlet",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_rail");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_rail",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_bfg");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_bfg",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_insult");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_insult",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_praise");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_praise",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- //
- EasyClientName(bs->lastkilledplayer, name, 32);
- //
- num = trap_BotNumInitialChats(bs->cs, "kill_gauntlet");
- for (i = 0; i < num; i++)
- {
- //
- BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "kill_rail");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "kill_rail", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "kill_telefrag");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "kill_insult");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "kill_insult", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "kill_praise");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "kill_praise", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "enemy_suicide");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name));
- weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client);
- num = trap_BotNumInitialChats(bs->cs, "hit_talking");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "hit_nodeath");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "hit_nokill");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- //
- if (bs->lastkilledplayer == bs->client) {
- strcpy(name, BotRandomOpponentName(bs));
- }
- else {
- EasyClientName(bs->lastkilledplayer, name, sizeof(name));
- }
- //
- num = trap_BotNumInitialChats(bs->cs, "random_misc");
- for (i = 0; i < num; i++)
- {
- //
- BotAI_BotInitialChat(bs, "random_misc",
- BotRandomOpponentName(bs), // 0
- name, // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- BotRandomWeaponName(), // 5
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "random_insult");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "random_insult",
- BotRandomOpponentName(bs), // 0
- name, // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- BotRandomWeaponName(), // 5
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
-}
diff --git a/engine/code/game/ai_cmd.c b/engine/code/game/ai_cmd.c
deleted file mode 100644
index db95485..0000000
--- a/engine/code/game/ai_cmd.c
+++ /dev/null
@@ -1,1992 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_cmd.c
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /MissionPack/code/game/ai_cmd.c $
- *
- *****************************************************************************/
-
-#include "g_local.h"
-#include "../botlib/botlib.h"
-#include "../botlib/be_aas.h"
-#include "../botlib/be_ea.h"
-#include "../botlib/be_ai_char.h"
-#include "../botlib/be_ai_chat.h"
-#include "../botlib/be_ai_gen.h"
-#include "../botlib/be_ai_goal.h"
-#include "../botlib/be_ai_move.h"
-#include "../botlib/be_ai_weap.h"
-//
-#include "ai_main.h"
-#include "ai_dmq3.h"
-#include "ai_chat.h"
-#include "ai_cmd.h"
-#include "ai_dmnet.h"
-#include "ai_team.h"
-//
-#include "chars.h" //characteristics
-#include "inv.h" //indexes into the inventory
-#include "syn.h" //synonyms
-#include "match.h" //string matching types and vars
-
-// for the voice chats
-#include "../../ui/menudef.h"
-
-int notleader[MAX_CLIENTS];
-
-#ifdef DEBUG
-/*
-==================
-BotPrintTeamGoal
-==================
-*/
-void BotPrintTeamGoal(bot_state_t *bs) {
- char netname[MAX_NETNAME];
- float t;
-
- ClientName(bs->client, netname, sizeof(netname));
- t = bs->teamgoal_time - FloatTime();
- switch(bs->ltgtype) {
- case LTG_TEAMHELP:
- {
- BotAI_Print(PRT_MESSAGE, "%s: I'm gonna help a team mate for %1.0f secs\n", netname, t);
- break;
- }
- case LTG_TEAMACCOMPANY:
- {
- BotAI_Print(PRT_MESSAGE, "%s: I'm gonna accompany a team mate for %1.0f secs\n", netname, t);
- break;
- }
- case LTG_GETFLAG:
- {
- BotAI_Print(PRT_MESSAGE, "%s: I'm gonna get the flag for %1.0f secs\n", netname, t);
- break;
- }
- case LTG_RUSHBASE:
- {
- BotAI_Print(PRT_MESSAGE, "%s: I'm gonna rush to the base for %1.0f secs\n", netname, t);
- break;
- }
- case LTG_RETURNFLAG:
- {
- BotAI_Print(PRT_MESSAGE, "%s: I'm gonna try to return the flag for %1.0f secs\n", netname, t);
- break;
- }
-#ifdef MISSIONPACK
- case LTG_ATTACKENEMYBASE:
- {
- BotAI_Print(PRT_MESSAGE, "%s: I'm gonna attack the enemy base for %1.0f secs\n", netname, t);
- break;
- }
- case LTG_HARVEST:
- {
- BotAI_Print(PRT_MESSAGE, "%s: I'm gonna harvest for %1.0f secs\n", netname, t);
- break;
- }
-#endif
- case LTG_DEFENDKEYAREA:
- {
- BotAI_Print(PRT_MESSAGE, "%s: I'm gonna defend a key area for %1.0f secs\n", netname, t);
- break;
- }
- case LTG_GETITEM:
- {
- BotAI_Print(PRT_MESSAGE, "%s: I'm gonna get an item for %1.0f secs\n", netname, t);
- break;
- }
- case LTG_KILL:
- {
- BotAI_Print(PRT_MESSAGE, "%s: I'm gonna kill someone for %1.0f secs\n", netname, t);
- break;
- }
- case LTG_CAMP:
- case LTG_CAMPORDER:
- {
- BotAI_Print(PRT_MESSAGE, "%s: I'm gonna camp for %1.0f secs\n", netname, t);
- break;
- }
- case LTG_PATROL:
- {
- BotAI_Print(PRT_MESSAGE, "%s: I'm gonna patrol for %1.0f secs\n", netname, t);
- break;
- }
- default:
- {
- if (bs->ctfroam_time > FloatTime()) {
- t = bs->ctfroam_time - FloatTime();
- BotAI_Print(PRT_MESSAGE, "%s: I'm gonna roam for %1.0f secs\n", netname, t);
- }
- else {
- BotAI_Print(PRT_MESSAGE, "%s: I've got a regular goal\n", netname);
- }
- }
- }
-}
-#endif //DEBUG
-
-/*
-==================
-BotGetItemTeamGoal
-
-FIXME: add stuff like "upper rocket launcher"
-"the rl near the railgun", "lower grenade launcher" etc.
-==================
-*/
-int BotGetItemTeamGoal(char *goalname, bot_goal_t *goal) {
- int i;
-
- if (!strlen(goalname)) return qfalse;
- i = -1;
- do {
- i = trap_BotGetLevelItemGoal(i, goalname, goal);
- if (i > 0) {
- //do NOT defend dropped items
- if (goal->flags & GFL_DROPPED)
- continue;
- return qtrue;
- }
- } while(i > 0);
- return qfalse;
-}
-
-/*
-==================
-BotGetMessageTeamGoal
-==================
-*/
-int BotGetMessageTeamGoal(bot_state_t *bs, char *goalname, bot_goal_t *goal) {
- bot_waypoint_t *cp;
-
- if (BotGetItemTeamGoal(goalname, goal)) return qtrue;
-
- cp = BotFindWayPoint(bs->checkpoints, goalname);
- if (cp) {
- memcpy(goal, &cp->goal, sizeof(bot_goal_t));
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-BotGetTime
-==================
-*/
-float BotGetTime(bot_match_t *match) {
- bot_match_t timematch;
- char timestring[MAX_MESSAGE_SIZE];
- float t;
-
- //if the matched string has a time
- if (match->subtype & ST_TIME) {
- //get the time string
- trap_BotMatchVariable(match, TIME, timestring, MAX_MESSAGE_SIZE);
- //match it to find out if the time is in seconds or minutes
- if (trap_BotFindMatch(timestring, &timematch, MTCONTEXT_TIME)) {
- if (timematch.type == MSG_FOREVER) {
- t = 99999999.0f;
- }
- else if (timematch.type == MSG_FORAWHILE) {
- t = 10 * 60; // 10 minutes
- }
- else if (timematch.type == MSG_FORALONGTIME) {
- t = 30 * 60; // 30 minutes
- }
- else {
- trap_BotMatchVariable(&timematch, TIME, timestring, MAX_MESSAGE_SIZE);
- if (timematch.type == MSG_MINUTES) t = atof(timestring) * 60;
- else if (timematch.type == MSG_SECONDS) t = atof(timestring);
- else t = 0;
- }
- //if there's a valid time
- if (t > 0) return FloatTime() + t;
- }
- }
- return 0;
-}
-
-/*
-==================
-FindClientByName
-==================
-*/
-int FindClientByName(char *name) {
- int i;
- char buf[MAX_INFO_STRING];
- static int maxclients;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- ClientName(i, buf, sizeof(buf));
- if (!Q_stricmp(buf, name)) return i;
- }
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- ClientName(i, buf, sizeof(buf));
- if (stristr(buf, name)) return i;
- }
- return -1;
-}
-
-/*
-==================
-FindEnemyByName
-==================
-*/
-int FindEnemyByName(bot_state_t *bs, char *name) {
- int i;
- char buf[MAX_INFO_STRING];
- static int maxclients;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (BotSameTeam(bs, i)) continue;
- ClientName(i, buf, sizeof(buf));
- if (!Q_stricmp(buf, name)) return i;
- }
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (BotSameTeam(bs, i)) continue;
- ClientName(i, buf, sizeof(buf));
- if (stristr(buf, name)) return i;
- }
- return -1;
-}
-
-/*
-==================
-NumPlayersOnSameTeam
-==================
-*/
-int NumPlayersOnSameTeam(bot_state_t *bs) {
- int i, num;
- char buf[MAX_INFO_STRING];
- static int maxclients;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- num = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, MAX_INFO_STRING);
- if (strlen(buf)) {
- if (BotSameTeam(bs, i+1)) num++;
- }
- }
- return num;
-}
-
-/*
-==================
-TeamPlayIsOn
-==================
-*/
-int BotGetPatrolWaypoints(bot_state_t *bs, bot_match_t *match) {
- char keyarea[MAX_MESSAGE_SIZE];
- int patrolflags;
- bot_waypoint_t *wp, *newwp, *newpatrolpoints;
- bot_match_t keyareamatch;
- bot_goal_t goal;
-
- newpatrolpoints = NULL;
- patrolflags = 0;
- //
- trap_BotMatchVariable(match, KEYAREA, keyarea, MAX_MESSAGE_SIZE);
- //
- while(1) {
- if (!trap_BotFindMatch(keyarea, &keyareamatch, MTCONTEXT_PATROLKEYAREA)) {
- trap_EA_SayTeam(bs->client, "what do you say?");
- BotFreeWaypoints(newpatrolpoints);
- bs->patrolpoints = NULL;
- return qfalse;
- }
- trap_BotMatchVariable(&keyareamatch, KEYAREA, keyarea, MAX_MESSAGE_SIZE);
- if (!BotGetMessageTeamGoal(bs, keyarea, &goal)) {
- //BotAI_BotInitialChat(bs, "cannotfind", keyarea, NULL);
- //trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotFreeWaypoints(newpatrolpoints);
- bs->patrolpoints = NULL;
- return qfalse;
- }
- //create a new waypoint
- newwp = BotCreateWayPoint(keyarea, goal.origin, goal.areanum);
- if (!newwp)
- break;
- //add the waypoint to the patrol points
- newwp->next = NULL;
- for (wp = newpatrolpoints; wp && wp->next; wp = wp->next);
- if (!wp) {
- newpatrolpoints = newwp;
- newwp->prev = NULL;
- }
- else {
- wp->next = newwp;
- newwp->prev = wp;
- }
- //
- if (keyareamatch.subtype & ST_BACK) {
- patrolflags = PATROL_LOOP;
- break;
- }
- else if (keyareamatch.subtype & ST_REVERSE) {
- patrolflags = PATROL_REVERSE;
- break;
- }
- else if (keyareamatch.subtype & ST_MORE) {
- trap_BotMatchVariable(&keyareamatch, MORE, keyarea, MAX_MESSAGE_SIZE);
- }
- else {
- break;
- }
- }
- //
- if (!newpatrolpoints || !newpatrolpoints->next) {
- trap_EA_SayTeam(bs->client, "I need more key points to patrol\n");
- BotFreeWaypoints(newpatrolpoints);
- newpatrolpoints = NULL;
- return qfalse;
- }
- //
- BotFreeWaypoints(bs->patrolpoints);
- bs->patrolpoints = newpatrolpoints;
- //
- bs->curpatrolpoint = bs->patrolpoints;
- bs->patrolflags = patrolflags;
- //
- return qtrue;
-}
-
-/*
-==================
-BotAddressedToBot
-==================
-*/
-int BotAddressedToBot(bot_state_t *bs, bot_match_t *match) {
- char addressedto[MAX_MESSAGE_SIZE];
- char netname[MAX_MESSAGE_SIZE];
- char name[MAX_MESSAGE_SIZE];
- char botname[128];
- int client;
- bot_match_t addresseematch;
-
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = ClientOnSameTeamFromName(bs, netname);
- if (client < 0) return qfalse;
- //if the message is addressed to someone
- if (match->subtype & ST_ADDRESSED) {
- trap_BotMatchVariable(match, ADDRESSEE, addressedto, sizeof(addressedto));
- //the name of this bot
- ClientName(bs->client, botname, 128);
- //
- while(trap_BotFindMatch(addressedto, &addresseematch, MTCONTEXT_ADDRESSEE)) {
- if (addresseematch.type == MSG_EVERYONE) {
- return qtrue;
- }
- else if (addresseematch.type == MSG_MULTIPLENAMES) {
- trap_BotMatchVariable(&addresseematch, TEAMMATE, name, sizeof(name));
- if (strlen(name)) {
- if (stristr(botname, name)) return qtrue;
- if (stristr(bs->subteam, name)) return qtrue;
- }
- trap_BotMatchVariable(&addresseematch, MORE, addressedto, MAX_MESSAGE_SIZE);
- }
- else {
- trap_BotMatchVariable(&addresseematch, TEAMMATE, name, MAX_MESSAGE_SIZE);
- if (strlen(name)) {
- if (stristr(botname, name)) return qtrue;
- if (stristr(bs->subteam, name)) return qtrue;
- }
- break;
- }
- }
- //Com_sprintf(buf, sizeof(buf), "not addressed to me but %s", addressedto);
- //trap_EA_Say(bs->client, buf);
- return qfalse;
- }
- else {
- bot_match_t tellmatch;
-
- tellmatch.type = 0;
- //if this message wasn't directed solely to this bot
- if (!trap_BotFindMatch(match->string, &tellmatch, MTCONTEXT_REPLYCHAT) ||
- tellmatch.type != MSG_CHATTELL) {
- //make sure not everyone reacts to this message
- if (random() > (float ) 1.0 / (NumPlayersOnSameTeam(bs)-1)) return qfalse;
- }
- }
- return qtrue;
-}
-
-/*
-==================
-BotGPSToPosition
-==================
-*/
-int BotGPSToPosition(char *buf, vec3_t position) {
- int i, j = 0;
- int num, sign;
-
- for (i = 0; i < 3; i++) {
- num = 0;
- while(buf[j] == ' ') j++;
- if (buf[j] == '-') {
- j++;
- sign = -1;
- }
- else {
- sign = 1;
- }
- while (buf[j]) {
- if (buf[j] >= '0' && buf[j] <= '9') {
- num = num * 10 + buf[j] - '0';
- j++;
- }
- else {
- j++;
- break;
- }
- }
- BotAI_Print(PRT_MESSAGE, "%d\n", sign * num);
- position[i] = (float) sign * num;
- }
- return qtrue;
-}
-
-/*
-==================
-BotMatch_HelpAccompany
-==================
-*/
-void BotMatch_HelpAccompany(bot_state_t *bs, bot_match_t *match) {
- int client, other, areanum;
- char teammate[MAX_MESSAGE_SIZE];
- char netname[MAX_MESSAGE_SIZE];
- char itemname[MAX_MESSAGE_SIZE];
- bot_match_t teammatematch;
- aas_entityinfo_t entinfo;
-
- if (!TeamPlayIsOn()) return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //get the team mate name
- trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));
- //get the client to help
- if (trap_BotFindMatch(teammate, &teammatematch, MTCONTEXT_TEAMMATE) &&
- //if someone asks for him or herself
- teammatematch.type == MSG_ME) {
- //get the netname
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = ClientFromName(netname);
- other = qfalse;
- }
- else {
- //asked for someone else
- client = FindClientByName(teammate);
- //if this is the bot self
- if (client == bs->client) {
- other = qfalse;
- }
- else if (!BotSameTeam(bs, client)) {
- //FIXME: say "I don't help the enemy"
- return;
- }
- else {
- other = qtrue;
- }
- }
- //if the bot doesn't know who to help (FindClientByName returned -1)
- if (client < 0) {
- if (other) BotAI_BotInitialChat(bs, "whois", teammate, NULL);
- else BotAI_BotInitialChat(bs, "whois", netname, NULL);
- client = ClientFromName(netname);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
- return;
- }
- //don't help or accompany yourself
- if (client == bs->client) {
- return;
- }
- //
- bs->teamgoal.entitynum = -1;
- BotEntityInfo(client, &entinfo);
- //if info is valid (in PVS)
- if (entinfo.valid) {
- areanum = BotPointAreaNum(entinfo.origin);
- if (areanum) {// && trap_AAS_AreaReachability(areanum)) {
- bs->teamgoal.entitynum = client;
- bs->teamgoal.areanum = areanum;
- VectorCopy(entinfo.origin, bs->teamgoal.origin);
- VectorSet(bs->teamgoal.mins, -8, -8, -8);
- VectorSet(bs->teamgoal.maxs, 8, 8, 8);
- }
- }
- //if no teamgoal yet
- if (bs->teamgoal.entitynum < 0) {
- //if near an item
- if (match->subtype & ST_NEARITEM) {
- //get the match variable
- trap_BotMatchVariable(match, ITEM, itemname, sizeof(itemname));
- //
- if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {
- //BotAI_BotInitialChat(bs, "cannotfind", itemname, NULL);
- //trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
- return;
- }
- }
- }
- //
- if (bs->teamgoal.entitynum < 0) {
- if (other) BotAI_BotInitialChat(bs, "whereis", teammate, NULL);
- else BotAI_BotInitialChat(bs, "whereareyou", netname, NULL);
- client = ClientFromName(netname);
- trap_BotEnterChat(bs->cs, client, CHAT_TEAM);
- return;
- }
- //the team mate
- bs->teammate = client;
- //
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- //
- client = ClientFromName(netname);
- //the team mate who ordered
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //last time the team mate was assumed visible
- bs->teammatevisible_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //get the team goal time
- bs->teamgoal_time = BotGetTime(match);
- //set the ltg type
- if (match->type == MSG_HELP) {
- bs->ltgtype = LTG_TEAMHELP;
- if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_HELP_TIME;
- }
- else {
- bs->ltgtype = LTG_TEAMACCOMPANY;
- if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
- bs->formation_dist = 3.5 * 32; //3.5 meter
- bs->arrive_time = 0;
- //
- BotSetTeamStatus(bs);
- // remember last ordered task
- BotRememberLastOrderedTask(bs);
- }
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotMatch_DefendKeyArea
-==================
-*/
-void BotMatch_DefendKeyArea(bot_state_t *bs, bot_match_t *match) {
- char itemname[MAX_MESSAGE_SIZE];
- char netname[MAX_MESSAGE_SIZE];
- int client;
-
- if (!TeamPlayIsOn()) return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //get the match variable
- trap_BotMatchVariable(match, KEYAREA, itemname, sizeof(itemname));
- //
- if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {
- //BotAI_BotInitialChat(bs, "cannotfind", itemname, NULL);
- //trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
- return;
- }
- //
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- //
- client = ClientFromName(netname);
- //the team mate who ordered
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_DEFENDKEYAREA;
- //get the team goal time
- bs->teamgoal_time = BotGetTime(match);
- //set the team goal time
- if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
- //away from defending
- bs->defendaway_time = 0;
- //
- BotSetTeamStatus(bs);
- // remember last ordered task
- BotRememberLastOrderedTask(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotMatch_GetItem
-==================
-*/
-void BotMatch_GetItem(bot_state_t *bs, bot_match_t *match) {
- char itemname[MAX_MESSAGE_SIZE];
- char netname[MAX_MESSAGE_SIZE];
- int client;
-
- if (!TeamPlayIsOn()) return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //get the match variable
- trap_BotMatchVariable(match, ITEM, itemname, sizeof(itemname));
- //
- if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {
- //BotAI_BotInitialChat(bs, "cannotfind", itemname, NULL);
- //trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
- return;
- }
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = ClientOnSameTeamFromName(bs, netname);
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_GETITEM;
- //set the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_GETITEM_TIME;
- //
- BotSetTeamStatus(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotMatch_Camp
-==================
-*/
-void BotMatch_Camp(bot_state_t *bs, bot_match_t *match) {
- int client, areanum;
- char netname[MAX_MESSAGE_SIZE];
- char itemname[MAX_MESSAGE_SIZE];
- aas_entityinfo_t entinfo;
-
- if (!TeamPlayIsOn()) return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- //asked for someone else
- client = FindClientByName(netname);
- //if there's no valid client with this name
- if (client < 0) {
- BotAI_BotInitialChat(bs, "whois", netname, NULL);
- trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
- return;
- }
- //get the match variable
- trap_BotMatchVariable(match, KEYAREA, itemname, sizeof(itemname));
- //in CTF it could be the base
- if (match->subtype & ST_THERE) {
- //camp at the spot the bot is currently standing
- bs->teamgoal.entitynum = bs->entitynum;
- bs->teamgoal.areanum = bs->areanum;
- VectorCopy(bs->origin, bs->teamgoal.origin);
- VectorSet(bs->teamgoal.mins, -8, -8, -8);
- VectorSet(bs->teamgoal.maxs, 8, 8, 8);
- }
- else if (match->subtype & ST_HERE) {
- //if this is the bot self
- if (client == bs->client) return;
- //
- bs->teamgoal.entitynum = -1;
- BotEntityInfo(client, &entinfo);
- //if info is valid (in PVS)
- if (entinfo.valid) {
- areanum = BotPointAreaNum(entinfo.origin);
- if (areanum) {// && trap_AAS_AreaReachability(areanum)) {
- //NOTE: just assume the bot knows where the person is
- //if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, client)) {
- bs->teamgoal.entitynum = client;
- bs->teamgoal.areanum = areanum;
- VectorCopy(entinfo.origin, bs->teamgoal.origin);
- VectorSet(bs->teamgoal.mins, -8, -8, -8);
- VectorSet(bs->teamgoal.maxs, 8, 8, 8);
- //}
- }
- }
- //if the other is not visible
- if (bs->teamgoal.entitynum < 0) {
- BotAI_BotInitialChat(bs, "whereareyou", netname, NULL);
- client = ClientFromName(netname);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
- return;
- }
- }
- else if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {
- //BotAI_BotInitialChat(bs, "cannotfind", itemname, NULL);
- //client = ClientFromName(netname);
- //trap_BotEnterChat(bs->cs, client, CHAT_TELL);
- return;
- }
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_CAMPORDER;
- //get the team goal time
- bs->teamgoal_time = BotGetTime(match);
- //set the team goal time
- if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_CAMP_TIME;
- //not arrived yet
- bs->arrive_time = 0;
- //
- BotSetTeamStatus(bs);
- // remember last ordered task
- BotRememberLastOrderedTask(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotMatch_Patrol
-==================
-*/
-void BotMatch_Patrol(bot_state_t *bs, bot_match_t *match) {
- char netname[MAX_MESSAGE_SIZE];
- int client;
-
- if (!TeamPlayIsOn()) return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //get the patrol waypoints
- if (!BotGetPatrolWaypoints(bs, match)) return;
- //
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- //
- client = FindClientByName(netname);
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_PATROL;
- //get the team goal time
- bs->teamgoal_time = BotGetTime(match);
- //set the team goal time if not set already
- if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_PATROL_TIME;
- //
- BotSetTeamStatus(bs);
- // remember last ordered task
- BotRememberLastOrderedTask(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotMatch_GetFlag
-==================
-*/
-void BotMatch_GetFlag(bot_state_t *bs, bot_match_t *match) {
- char netname[MAX_MESSAGE_SIZE];
- int client;
-
- if (gametype == GT_CTF) {
- if (!ctf_redflag.areanum || !ctf_blueflag.areanum)
- return;
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- if (!ctf_neutralflag.areanum || !ctf_redflag.areanum || !ctf_blueflag.areanum)
- return;
- }
-#endif
- else {
- return;
- }
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- //
- client = FindClientByName(netname);
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_GETFLAG;
- //set the team goal time
- bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
- // get an alternate route in ctf
- if (gametype == GT_CTF) {
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- }
- //
- BotSetTeamStatus(bs);
- // remember last ordered task
- BotRememberLastOrderedTask(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotMatch_AttackEnemyBase
-==================
-*/
-void BotMatch_AttackEnemyBase(bot_state_t *bs, bot_match_t *match) {
- char netname[MAX_MESSAGE_SIZE];
- int client;
-
- if (gametype == GT_CTF) {
- BotMatch_GetFlag(bs, match);
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF || gametype == GT_OBELISK || gametype == GT_HARVESTER) {
- if (!redobelisk.areanum || !blueobelisk.areanum)
- return;
- }
-#endif
- else {
- return;
- }
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- //
- client = FindClientByName(netname);
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_ATTACKENEMYBASE;
- //set the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
- bs->attackaway_time = 0;
- //
- BotSetTeamStatus(bs);
- // remember last ordered task
- BotRememberLastOrderedTask(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-#ifdef MISSIONPACK
-/*
-==================
-BotMatch_Harvest
-==================
-*/
-void BotMatch_Harvest(bot_state_t *bs, bot_match_t *match) {
- char netname[MAX_MESSAGE_SIZE];
- int client;
-
- if (gametype == GT_HARVESTER) {
- if (!neutralobelisk.areanum || !redobelisk.areanum || !blueobelisk.areanum)
- return;
- }
- else {
- return;
- }
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- //
- client = FindClientByName(netname);
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_HARVEST;
- //set the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME;
- bs->harvestaway_time = 0;
- //
- BotSetTeamStatus(bs);
- // remember last ordered task
- BotRememberLastOrderedTask(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-#endif
-
-/*
-==================
-BotMatch_RushBase
-==================
-*/
-void BotMatch_RushBase(bot_state_t *bs, bot_match_t *match) {
- char netname[MAX_MESSAGE_SIZE];
- int client;
-
- if (gametype == GT_CTF) {
- if (!ctf_redflag.areanum || !ctf_blueflag.areanum)
- return;
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF || gametype == GT_HARVESTER) {
- if (!redobelisk.areanum || !blueobelisk.areanum)
- return;
- }
-#endif
- else {
- return;
- }
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- //
- client = FindClientByName(netname);
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_RUSHBASE;
- //set the team goal time
- bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
- bs->rushbaseaway_time = 0;
- //
- BotSetTeamStatus(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotMatch_TaskPreference
-==================
-*/
-void BotMatch_TaskPreference(bot_state_t *bs, bot_match_t *match) {
- char netname[MAX_NETNAME];
- char teammatename[MAX_MESSAGE_SIZE];
- int teammate, preference;
-
- ClientName(bs->client, netname, sizeof(netname));
- if (Q_stricmp(netname, bs->teamleader) != 0) return;
-
- trap_BotMatchVariable(match, NETNAME, teammatename, sizeof(teammatename));
- teammate = ClientFromName(teammatename);
- if (teammate < 0) return;
-
- preference = BotGetTeamMateTaskPreference(bs, teammate);
- switch(match->subtype)
- {
- case ST_DEFENDER:
- {
- preference &= ~TEAMTP_ATTACKER;
- preference |= TEAMTP_DEFENDER;
- break;
- }
- case ST_ATTACKER:
- {
- preference &= ~TEAMTP_DEFENDER;
- preference |= TEAMTP_ATTACKER;
- break;
- }
- case ST_ROAMER:
- {
- preference &= ~(TEAMTP_ATTACKER|TEAMTP_DEFENDER);
- break;
- }
- }
- BotSetTeamMateTaskPreference(bs, teammate, preference);
- //
- EasyClientName(teammate, teammatename, sizeof(teammatename));
- BotAI_BotInitialChat(bs, "keepinmind", teammatename, NULL);
- trap_BotEnterChat(bs->cs, teammate, CHAT_TELL);
- BotVoiceChatOnly(bs, teammate, VOICECHAT_YES);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
-}
-
-/*
-==================
-BotMatch_ReturnFlag
-==================
-*/
-void BotMatch_ReturnFlag(bot_state_t *bs, bot_match_t *match) {
- char netname[MAX_MESSAGE_SIZE];
- int client;
-
- //if not in CTF mode
- if (
- gametype != GT_CTF
-#ifdef MISSIONPACK
- && gametype != GT_1FCTF
-#endif
- )
- return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match))
- return;
- //
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- //
- client = FindClientByName(netname);
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_RETURNFLAG;
- //set the team goal time
- bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME;
- bs->rushbaseaway_time = 0;
- //
- BotSetTeamStatus(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotMatch_JoinSubteam
-==================
-*/
-void BotMatch_JoinSubteam(bot_state_t *bs, bot_match_t *match) {
- char teammate[MAX_MESSAGE_SIZE];
- char netname[MAX_MESSAGE_SIZE];
- int client;
-
- if (!TeamPlayIsOn()) return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //get the sub team name
- trap_BotMatchVariable(match, TEAMNAME, teammate, sizeof(teammate));
- //set the sub team name
- strncpy(bs->subteam, teammate, 32);
- bs->subteam[31] = '\0';
- //
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- BotAI_BotInitialChat(bs, "joinedteam", teammate, NULL);
- client = ClientFromName(netname);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
-}
-
-/*
-==================
-BotMatch_LeaveSubteam
-==================
-*/
-void BotMatch_LeaveSubteam(bot_state_t *bs, bot_match_t *match) {
- char netname[MAX_MESSAGE_SIZE];
- int client;
-
- if (!TeamPlayIsOn()) return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //
- if (strlen(bs->subteam))
- {
- BotAI_BotInitialChat(bs, "leftteam", bs->subteam, NULL);
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = ClientFromName(netname);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
- } //end if
- strcpy(bs->subteam, "");
-}
-
-/*
-==================
-BotMatch_LeaveSubteam
-==================
-*/
-void BotMatch_WhichTeam(bot_state_t *bs, bot_match_t *match) {
- if (!TeamPlayIsOn()) return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //
- if (strlen(bs->subteam)) {
- BotAI_BotInitialChat(bs, "inteam", bs->subteam, NULL);
- }
- else {
- BotAI_BotInitialChat(bs, "noteam", NULL);
- }
- trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
-}
-
-/*
-==================
-BotMatch_CheckPoint
-==================
-*/
-void BotMatch_CheckPoint(bot_state_t *bs, bot_match_t *match) {
- int areanum, client;
- char buf[MAX_MESSAGE_SIZE];
- char netname[MAX_MESSAGE_SIZE];
- vec3_t position;
- bot_waypoint_t *cp;
-
- if (!TeamPlayIsOn()) return;
- //
- trap_BotMatchVariable(match, POSITION, buf, MAX_MESSAGE_SIZE);
- VectorClear(position);
- //
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = ClientFromName(netname);
- //BotGPSToPosition(buf, position);
- sscanf(buf, "%f %f %f", &position[0], &position[1], &position[2]);
- position[2] += 0.5;
- areanum = BotPointAreaNum(position);
- if (!areanum) {
- if (BotAddressedToBot(bs, match)) {
- BotAI_BotInitialChat(bs, "checkpoint_invalid", NULL);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
- }
- return;
- }
- //
- trap_BotMatchVariable(match, NAME, buf, MAX_MESSAGE_SIZE);
- //check if there already exists a checkpoint with this name
- cp = BotFindWayPoint(bs->checkpoints, buf);
- if (cp) {
- if (cp->next) cp->next->prev = cp->prev;
- if (cp->prev) cp->prev->next = cp->next;
- else bs->checkpoints = cp->next;
- cp->inuse = qfalse;
- }
- //create a new check point
- cp = BotCreateWayPoint(buf, position, areanum);
- //add the check point to the bot's known chech points
- cp->next = bs->checkpoints;
- if (bs->checkpoints) bs->checkpoints->prev = cp;
- bs->checkpoints = cp;
- //
- if (BotAddressedToBot(bs, match)) {
- Com_sprintf(buf, sizeof(buf), "%1.0f %1.0f %1.0f", cp->goal.origin[0],
- cp->goal.origin[1],
- cp->goal.origin[2]);
-
- BotAI_BotInitialChat(bs, "checkpoint_confirm", cp->name, buf, NULL);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
- }
-}
-
-/*
-==================
-BotMatch_FormationSpace
-==================
-*/
-void BotMatch_FormationSpace(bot_state_t *bs, bot_match_t *match) {
- char buf[MAX_MESSAGE_SIZE];
- float space;
-
- if (!TeamPlayIsOn()) return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //
- trap_BotMatchVariable(match, NUMBER, buf, MAX_MESSAGE_SIZE);
- //if it's the distance in feet
- if (match->subtype & ST_FEET) space = 0.3048 * 32 * atof(buf);
- //else it's in meters
- else space = 32 * atof(buf);
- //check if the formation intervening space is valid
- if (space < 48 || space > 500) space = 100;
- bs->formation_dist = space;
-}
-
-/*
-==================
-BotMatch_Dismiss
-==================
-*/
-void BotMatch_Dismiss(bot_state_t *bs, bot_match_t *match) {
- char netname[MAX_MESSAGE_SIZE];
- int client;
-
- if (!TeamPlayIsOn()) return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = ClientFromName(netname);
- //
- bs->decisionmaker = client;
- //
- bs->ltgtype = 0;
- bs->lead_time = 0;
- bs->lastgoal_ltgtype = 0;
- //
- BotAI_BotInitialChat(bs, "dismissed", NULL);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
-}
-
-/*
-==================
-BotMatch_Suicide
-==================
-*/
-void BotMatch_Suicide(bot_state_t *bs, bot_match_t *match) {
- char netname[MAX_MESSAGE_SIZE];
- int client;
-
- if (!TeamPlayIsOn()) return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //
- trap_EA_Command(bs->client, "kill");
- //
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = ClientFromName(netname);
- //
- BotVoiceChat(bs, client, VOICECHAT_TAUNT);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
-}
-
-/*
-==================
-BotMatch_StartTeamLeaderShip
-==================
-*/
-void BotMatch_StartTeamLeaderShip(bot_state_t *bs, bot_match_t *match) {
- int client;
- char teammate[MAX_MESSAGE_SIZE];
-
- if (!TeamPlayIsOn()) return;
- //if chats for him or herself
- if (match->subtype & ST_I) {
- //get the team mate that will be the team leader
- trap_BotMatchVariable(match, NETNAME, teammate, sizeof(teammate));
- strncpy(bs->teamleader, teammate, sizeof(bs->teamleader));
- bs->teamleader[sizeof(bs->teamleader)-1] = '\0';
- }
- //chats for someone else
- else {
- //get the team mate that will be the team leader
- trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));
- client = FindClientByName(teammate);
- if (client >= 0) ClientName(client, bs->teamleader, sizeof(bs->teamleader));
- }
-}
-
-/*
-==================
-BotMatch_StopTeamLeaderShip
-==================
-*/
-void BotMatch_StopTeamLeaderShip(bot_state_t *bs, bot_match_t *match) {
- int client;
- char teammate[MAX_MESSAGE_SIZE];
- char netname[MAX_MESSAGE_SIZE];
-
- if (!TeamPlayIsOn()) return;
- //get the team mate that stops being the team leader
- trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));
- //if chats for him or herself
- if (match->subtype & ST_I) {
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = FindClientByName(netname);
- }
- //chats for someone else
- else {
- client = FindClientByName(teammate);
- } //end else
- if (client >= 0) {
- if (!Q_stricmp(bs->teamleader, ClientName(client, netname, sizeof(netname)))) {
- bs->teamleader[0] = '\0';
- notleader[client] = qtrue;
- }
- }
-}
-
-/*
-==================
-BotMatch_WhoIsTeamLeader
-==================
-*/
-void BotMatch_WhoIsTeamLeader(bot_state_t *bs, bot_match_t *match) {
- char netname[MAX_MESSAGE_SIZE];
-
- if (!TeamPlayIsOn()) return;
-
- ClientName(bs->client, netname, sizeof(netname));
- //if this bot IS the team leader
- if (!Q_stricmp(netname, bs->teamleader)) {
- trap_EA_SayTeam(bs->client, "I'm the team leader\n");
- }
-}
-
-/*
-==================
-BotMatch_WhatAreYouDoing
-==================
-*/
-void BotMatch_WhatAreYouDoing(bot_state_t *bs, bot_match_t *match) {
- char netname[MAX_MESSAGE_SIZE];
- char goalname[MAX_MESSAGE_SIZE];
- int client;
-
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //
- switch(bs->ltgtype) {
- case LTG_TEAMHELP:
- {
- EasyClientName(bs->teammate, netname, sizeof(netname));
- BotAI_BotInitialChat(bs, "helping", netname, NULL);
- break;
- }
- case LTG_TEAMACCOMPANY:
- {
- EasyClientName(bs->teammate, netname, sizeof(netname));
- BotAI_BotInitialChat(bs, "accompanying", netname, NULL);
- break;
- }
- case LTG_DEFENDKEYAREA:
- {
- trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
- BotAI_BotInitialChat(bs, "defending", goalname, NULL);
- break;
- }
- case LTG_GETITEM:
- {
- trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
- BotAI_BotInitialChat(bs, "gettingitem", goalname, NULL);
- break;
- }
- case LTG_KILL:
- {
- ClientName(bs->teamgoal.entitynum, netname, sizeof(netname));
- BotAI_BotInitialChat(bs, "killing", netname, NULL);
- break;
- }
- case LTG_CAMP:
- case LTG_CAMPORDER:
- {
- BotAI_BotInitialChat(bs, "camping", NULL);
- break;
- }
- case LTG_PATROL:
- {
- BotAI_BotInitialChat(bs, "patrolling", NULL);
- break;
- }
- case LTG_GETFLAG:
- {
- BotAI_BotInitialChat(bs, "capturingflag", NULL);
- break;
- }
- case LTG_RUSHBASE:
- {
- BotAI_BotInitialChat(bs, "rushingbase", NULL);
- break;
- }
- case LTG_RETURNFLAG:
- {
- BotAI_BotInitialChat(bs, "returningflag", NULL);
- break;
- }
-#ifdef MISSIONPACK
- case LTG_ATTACKENEMYBASE:
- {
- BotAI_BotInitialChat(bs, "attackingenemybase", NULL);
- break;
- }
- case LTG_HARVEST:
- {
- BotAI_BotInitialChat(bs, "harvesting", NULL);
- break;
- }
-#endif
- default:
- {
- BotAI_BotInitialChat(bs, "roaming", NULL);
- break;
- }
- }
- //chat what the bot is doing
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = ClientFromName(netname);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
-}
-
-/*
-==================
-BotMatch_WhatIsMyCommand
-==================
-*/
-void BotMatch_WhatIsMyCommand(bot_state_t *bs, bot_match_t *match) {
- char netname[MAX_NETNAME];
-
- ClientName(bs->client, netname, sizeof(netname));
- if (Q_stricmp(netname, bs->teamleader) != 0) return;
- bs->forceorders = qtrue;
-}
-
-/*
-==================
-BotNearestVisibleItem
-==================
-*/
-float BotNearestVisibleItem(bot_state_t *bs, char *itemname, bot_goal_t *goal) {
- int i;
- char name[64];
- bot_goal_t tmpgoal;
- float dist, bestdist;
- vec3_t dir;
- bsp_trace_t trace;
-
- bestdist = 999999;
- i = -1;
- do {
- i = trap_BotGetLevelItemGoal(i, itemname, &tmpgoal);
- trap_BotGoalName(tmpgoal.number, name, sizeof(name));
- if (Q_stricmp(itemname, name) != 0)
- continue;
- VectorSubtract(tmpgoal.origin, bs->origin, dir);
- dist = VectorLength(dir);
- if (dist < bestdist) {
- //trace from start to end
- BotAI_Trace(&trace, bs->eye, NULL, NULL, tmpgoal.origin, bs->client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- if (trace.fraction >= 1.0) {
- bestdist = dist;
- memcpy(goal, &tmpgoal, sizeof(bot_goal_t));
- }
- }
- } while(i > 0);
- return bestdist;
-}
-
-/*
-==================
-BotMatch_WhereAreYou
-==================
-*/
-void BotMatch_WhereAreYou(bot_state_t *bs, bot_match_t *match) {
- float dist, bestdist;
- int i, bestitem, redtt, bluett, client;
- bot_goal_t goal;
- char netname[MAX_MESSAGE_SIZE];
- char *nearbyitems[] = {
- "Shotgun",
- "Grenade Launcher",
- "Rocket Launcher",
- "Plasmagun",
- "Railgun",
- "Lightning Gun",
- "BFG10K",
- "Quad Damage",
- "Regeneration",
- "Battle Suit",
- "Speed",
- "Invisibility",
- "Flight",
- "Armor",
- "Heavy Armor",
- "Red Flag",
- "Blue Flag",
-#ifdef MISSIONPACK
- "Nailgun",
- "Prox Launcher",
- "Chaingun",
- "Scout",
- "Guard",
- "Doubler",
- "Ammo Regen",
- "Neutral Flag",
- "Red Obelisk",
- "Blue Obelisk",
- "Neutral Obelisk",
-#endif
- NULL
- };
- //
- if (!TeamPlayIsOn())
- return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match))
- return;
-
- bestitem = -1;
- bestdist = 999999;
- for (i = 0; nearbyitems[i]; i++) {
- dist = BotNearestVisibleItem(bs, nearbyitems[i], &goal);
- if (dist < bestdist) {
- bestdist = dist;
- bestitem = i;
- }
- }
- if (bestitem != -1) {
- if (gametype == GT_CTF
-#ifdef MISSIONPACK
- || gametype == GT_1FCTF
-#endif
- ) {
- redtt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_redflag.areanum, TFL_DEFAULT);
- bluett = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_blueflag.areanum, TFL_DEFAULT);
- if (redtt < (redtt + bluett) * 0.4) {
- BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "red", NULL);
- }
- else if (bluett < (redtt + bluett) * 0.4) {
- BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "blue", NULL);
- }
- else {
- BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL);
- }
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_OBELISK || gametype == GT_HARVESTER) {
- redtt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, redobelisk.areanum, TFL_DEFAULT);
- bluett = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, blueobelisk.areanum, TFL_DEFAULT);
- if (redtt < (redtt + bluett) * 0.4) {
- BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "red", NULL);
- }
- else if (bluett < (redtt + bluett) * 0.4) {
- BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "blue", NULL);
- }
- else {
- BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL);
- }
- }
-#endif
- else {
- BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL);
- }
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = ClientFromName(netname);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
- }
-}
-
-/*
-==================
-BotMatch_LeadTheWay
-==================
-*/
-void BotMatch_LeadTheWay(bot_state_t *bs, bot_match_t *match) {
- aas_entityinfo_t entinfo;
- char netname[MAX_MESSAGE_SIZE], teammate[MAX_MESSAGE_SIZE];
- int client, areanum, other;
-
- if (!TeamPlayIsOn()) return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
- //if someone asks for someone else
- if (match->subtype & ST_SOMEONE) {
- //get the team mate name
- trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));
- client = FindClientByName(teammate);
- //if this is the bot self
- if (client == bs->client) {
- other = qfalse;
- }
- else if (!BotSameTeam(bs, client)) {
- //FIXME: say "I don't help the enemy"
- return;
- }
- else {
- other = qtrue;
- }
- }
- else {
- //get the netname
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = ClientFromName(netname);
- other = qfalse;
- }
- //if the bot doesn't know who to help (FindClientByName returned -1)
- if (client < 0) {
- BotAI_BotInitialChat(bs, "whois", netname, NULL);
- trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
- return;
- }
- //
- bs->lead_teamgoal.entitynum = -1;
- BotEntityInfo(client, &entinfo);
- //if info is valid (in PVS)
- if (entinfo.valid) {
- areanum = BotPointAreaNum(entinfo.origin);
- if (areanum) { // && trap_AAS_AreaReachability(areanum)) {
- bs->lead_teamgoal.entitynum = client;
- bs->lead_teamgoal.areanum = areanum;
- VectorCopy(entinfo.origin, bs->lead_teamgoal.origin);
- VectorSet(bs->lead_teamgoal.mins, -8, -8, -8);
- VectorSet(bs->lead_teamgoal.maxs, 8, 8, 8);
- }
- }
-
- if (bs->teamgoal.entitynum < 0) {
- if (other) BotAI_BotInitialChat(bs, "whereis", teammate, NULL);
- else BotAI_BotInitialChat(bs, "whereareyou", netname, NULL);
- trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
- return;
- }
- bs->lead_teammate = client;
- bs->lead_time = FloatTime() + TEAM_LEAD_TIME;
- bs->leadvisible_time = 0;
- bs->leadmessage_time = -(FloatTime() + 2 * random());
-}
-
-/*
-==================
-BotMatch_Kill
-==================
-*/
-void BotMatch_Kill(bot_state_t *bs, bot_match_t *match) {
- char enemy[MAX_MESSAGE_SIZE];
- char netname[MAX_MESSAGE_SIZE];
- int client;
-
- if (!TeamPlayIsOn()) return;
- //if not addressed to this bot
- if (!BotAddressedToBot(bs, match)) return;
-
- trap_BotMatchVariable(match, ENEMY, enemy, sizeof(enemy));
- //
- client = FindEnemyByName(bs, enemy);
- if (client < 0) {
- BotAI_BotInitialChat(bs, "whois", enemy, NULL);
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = ClientFromName(netname);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
- return;
- }
- bs->teamgoal.entitynum = client;
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_KILL;
- //set the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_KILL_SOMEONE;
- //
- BotSetTeamStatus(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotMatch_CTF
-==================
-*/
-void BotMatch_CTF(bot_state_t *bs, bot_match_t *match) {
-
- char flag[128], netname[MAX_NETNAME];
-
- if (gametype == GT_CTF) {
- trap_BotMatchVariable(match, FLAG, flag, sizeof(flag));
- if (match->subtype & ST_GOTFLAG) {
- if (!Q_stricmp(flag, "red")) {
- bs->redflagstatus = 1;
- if (BotTeam(bs) == TEAM_BLUE) {
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- bs->flagcarrier = ClientFromName(netname);
- }
- }
- else {
- bs->blueflagstatus = 1;
- if (BotTeam(bs) == TEAM_RED) {
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- bs->flagcarrier = ClientFromName(netname);
- }
- }
- bs->flagstatuschanged = 1;
- bs->lastflagcapture_time = FloatTime();
- }
- else if (match->subtype & ST_CAPTUREDFLAG) {
- bs->redflagstatus = 0;
- bs->blueflagstatus = 0;
- bs->flagcarrier = 0;
- bs->flagstatuschanged = 1;
- }
- else if (match->subtype & ST_RETURNEDFLAG) {
- if (!Q_stricmp(flag, "red")) bs->redflagstatus = 0;
- else bs->blueflagstatus = 0;
- bs->flagstatuschanged = 1;
- }
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- if (match->subtype & ST_1FCTFGOTFLAG) {
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- bs->flagcarrier = ClientFromName(netname);
- }
- }
-#endif
-}
-
-void BotMatch_EnterGame(bot_state_t *bs, bot_match_t *match) {
- int client;
- char netname[MAX_NETNAME];
-
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = FindClientByName(netname);
- if (client >= 0) {
- notleader[client] = qfalse;
- }
- //NOTE: eliza chats will catch this
- //Com_sprintf(buf, sizeof(buf), "heya %s", netname);
- //EA_Say(bs->client, buf);
-}
-
-void BotMatch_NewLeader(bot_state_t *bs, bot_match_t *match) {
- int client;
- char netname[MAX_NETNAME];
-
- trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
- client = FindClientByName(netname);
- if (!BotSameTeam(bs, client))
- return;
- Q_strncpyz(bs->teamleader, netname, sizeof(bs->teamleader));
-}
-
-/*
-==================
-BotMatchMessage
-==================
-*/
-int BotMatchMessage(bot_state_t *bs, char *message) {
- bot_match_t match;
-
- match.type = 0;
- //if it is an unknown message
- if (!trap_BotFindMatch(message, &match, MTCONTEXT_MISC
- |MTCONTEXT_INITIALTEAMCHAT
- |MTCONTEXT_CTF)) {
- return qfalse;
- }
- //react to the found message
- switch(match.type)
- {
- case MSG_HELP: //someone calling for help
- case MSG_ACCOMPANY: //someone calling for company
- {
- BotMatch_HelpAccompany(bs, &match);
- break;
- }
- case MSG_DEFENDKEYAREA: //teamplay defend a key area
- {
- BotMatch_DefendKeyArea(bs, &match);
- break;
- }
- case MSG_CAMP: //camp somewhere
- {
- BotMatch_Camp(bs, &match);
- break;
- }
- case MSG_PATROL: //patrol between several key areas
- {
- BotMatch_Patrol(bs, &match);
- break;
- }
- //CTF & 1FCTF
- case MSG_GETFLAG: //ctf get the enemy flag
- {
- BotMatch_GetFlag(bs, &match);
- break;
- }
-#ifdef MISSIONPACK
- //CTF & 1FCTF & Obelisk & Harvester
- case MSG_ATTACKENEMYBASE:
- {
- BotMatch_AttackEnemyBase(bs, &match);
- break;
- }
- //Harvester
- case MSG_HARVEST:
- {
- BotMatch_Harvest(bs, &match);
- break;
- }
-#endif
- //CTF & 1FCTF & Harvester
- case MSG_RUSHBASE: //ctf rush to the base
- {
- BotMatch_RushBase(bs, &match);
- break;
- }
- //CTF & 1FCTF
- case MSG_RETURNFLAG:
- {
- BotMatch_ReturnFlag(bs, &match);
- break;
- }
- //CTF & 1FCTF & Obelisk & Harvester
- case MSG_TASKPREFERENCE:
- {
- BotMatch_TaskPreference(bs, &match);
- break;
- }
- //CTF & 1FCTF
- case MSG_CTF:
- {
- BotMatch_CTF(bs, &match);
- break;
- }
- case MSG_GETITEM:
- {
- BotMatch_GetItem(bs, &match);
- break;
- }
- case MSG_JOINSUBTEAM: //join a sub team
- {
- BotMatch_JoinSubteam(bs, &match);
- break;
- }
- case MSG_LEAVESUBTEAM: //leave a sub team
- {
- BotMatch_LeaveSubteam(bs, &match);
- break;
- }
- case MSG_WHICHTEAM:
- {
- BotMatch_WhichTeam(bs, &match);
- break;
- }
- case MSG_CHECKPOINT: //remember a check point
- {
- BotMatch_CheckPoint(bs, &match);
- break;
- }
- case MSG_CREATENEWFORMATION: //start the creation of a new formation
- {
- trap_EA_SayTeam(bs->client, "the part of my brain to create formations has been damaged");
- break;
- }
- case MSG_FORMATIONPOSITION: //tell someone his/her position in the formation
- {
- trap_EA_SayTeam(bs->client, "the part of my brain to create formations has been damaged");
- break;
- }
- case MSG_FORMATIONSPACE: //set the formation space
- {
- BotMatch_FormationSpace(bs, &match);
- break;
- }
- case MSG_DOFORMATION: //form a certain formation
- {
- break;
- }
- case MSG_DISMISS: //dismiss someone
- {
- BotMatch_Dismiss(bs, &match);
- break;
- }
- case MSG_STARTTEAMLEADERSHIP: //someone will become the team leader
- {
- BotMatch_StartTeamLeaderShip(bs, &match);
- break;
- }
- case MSG_STOPTEAMLEADERSHIP: //someone will stop being the team leader
- {
- BotMatch_StopTeamLeaderShip(bs, &match);
- break;
- }
- case MSG_WHOISTEAMLAEDER:
- {
- BotMatch_WhoIsTeamLeader(bs, &match);
- break;
- }
- case MSG_WHATAREYOUDOING: //ask a bot what he/she is doing
- {
- BotMatch_WhatAreYouDoing(bs, &match);
- break;
- }
- case MSG_WHATISMYCOMMAND:
- {
- BotMatch_WhatIsMyCommand(bs, &match);
- break;
- }
- case MSG_WHEREAREYOU:
- {
- BotMatch_WhereAreYou(bs, &match);
- break;
- }
- case MSG_LEADTHEWAY:
- {
- BotMatch_LeadTheWay(bs, &match);
- break;
- }
- case MSG_KILL:
- {
- BotMatch_Kill(bs, &match);
- break;
- }
- case MSG_ENTERGAME: //someone entered the game
- {
- BotMatch_EnterGame(bs, &match);
- break;
- }
- case MSG_NEWLEADER:
- {
- BotMatch_NewLeader(bs, &match);
- break;
- }
- case MSG_WAIT:
- {
- break;
- }
- case MSG_SUICIDE:
- {
- BotMatch_Suicide(bs, &match);
- break;
- }
- default:
- {
- BotAI_Print(PRT_MESSAGE, "unknown match type\n");
- break;
- }
- }
- return qtrue;
-}
diff --git a/engine/code/game/ai_dmnet.c b/engine/code/game/ai_dmnet.c
deleted file mode 100644
index 5050bd1..0000000
--- a/engine/code/game/ai_dmnet.c
+++ /dev/null
@@ -1,2610 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_dmnet.c
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /MissionPack/code/game/ai_dmnet.c $
- *
- *****************************************************************************/
-
-#include "g_local.h"
-#include "../botlib/botlib.h"
-#include "../botlib/be_aas.h"
-#include "../botlib/be_ea.h"
-#include "../botlib/be_ai_char.h"
-#include "../botlib/be_ai_chat.h"
-#include "../botlib/be_ai_gen.h"
-#include "../botlib/be_ai_goal.h"
-#include "../botlib/be_ai_move.h"
-#include "../botlib/be_ai_weap.h"
-//
-#include "ai_main.h"
-#include "ai_dmq3.h"
-#include "ai_chat.h"
-#include "ai_cmd.h"
-#include "ai_dmnet.h"
-#include "ai_team.h"
-//data file headers
-#include "chars.h" //characteristics
-#include "inv.h" //indexes into the inventory
-#include "syn.h" //synonyms
-#include "match.h" //string matching types and vars
-
-// for the voice chats
-#include "../../ui/menudef.h"
-
-//goal flag, see ../botlib/be_ai_goal.h for the other GFL_*
-#define GFL_AIR 128
-
-int numnodeswitches;
-char nodeswitch[MAX_NODESWITCHES+1][144];
-
-#define LOOKAHEAD_DISTANCE 300
-
-/*
-==================
-BotResetNodeSwitches
-==================
-*/
-void BotResetNodeSwitches(void) {
- numnodeswitches = 0;
-}
-
-/*
-==================
-BotDumpNodeSwitches
-==================
-*/
-void BotDumpNodeSwitches(bot_state_t *bs) {
- int i;
- char netname[MAX_NETNAME];
-
- ClientName(bs->client, netname, sizeof(netname));
- BotAI_Print(PRT_MESSAGE, "%s at %1.1f switched more than %d AI nodes\n", netname, FloatTime(), MAX_NODESWITCHES);
- for (i = 0; i < numnodeswitches; i++) {
- BotAI_Print(PRT_MESSAGE, "%s", nodeswitch[i]);
- }
- BotAI_Print(PRT_FATAL, "");
-}
-
-/*
-==================
-BotRecordNodeSwitch
-==================
-*/
-void BotRecordNodeSwitch(bot_state_t *bs, char *node, char *str, char *s) {
- char netname[MAX_NETNAME];
-
- ClientName(bs->client, netname, sizeof(netname));
- Com_sprintf(nodeswitch[numnodeswitches], 144, "%s at %2.1f entered %s: %s from %s\n", netname, FloatTime(), node, str, s);
-#ifdef DEBUG
- if (0) {
- BotAI_Print(PRT_MESSAGE, "%s", nodeswitch[numnodeswitches]);
- }
-#endif //DEBUG
- numnodeswitches++;
-}
-
-/*
-==================
-BotGetAirGoal
-==================
-*/
-int BotGetAirGoal(bot_state_t *bs, bot_goal_t *goal) {
- bsp_trace_t bsptrace;
- vec3_t end, mins = {-15, -15, -2}, maxs = {15, 15, 2};
- int areanum;
-
- //trace up until we hit solid
- VectorCopy(bs->origin, end);
- end[2] += 1000;
- BotAI_Trace(&bsptrace, bs->origin, mins, maxs, end, bs->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- //trace down until we hit water
- VectorCopy(bsptrace.endpos, end);
- BotAI_Trace(&bsptrace, end, mins, maxs, bs->origin, bs->entitynum, CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA);
- //if we found the water surface
- if (bsptrace.fraction > 0) {
- areanum = BotPointAreaNum(bsptrace.endpos);
- if (areanum) {
- VectorCopy(bsptrace.endpos, goal->origin);
- goal->origin[2] -= 2;
- goal->areanum = areanum;
- goal->mins[0] = -15;
- goal->mins[1] = -15;
- goal->mins[2] = -1;
- goal->maxs[0] = 15;
- goal->maxs[1] = 15;
- goal->maxs[2] = 1;
- goal->flags = GFL_AIR;
- goal->number = 0;
- goal->iteminfo = 0;
- goal->entitynum = 0;
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-==================
-BotGoForAir
-==================
-*/
-int BotGoForAir(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) {
- bot_goal_t goal;
-
- //if the bot needs air
- if (bs->lastair_time < FloatTime() - 6) {
- //
-#ifdef DEBUG
- //BotAI_Print(PRT_MESSAGE, "going for air\n");
-#endif //DEBUG
- //if we can find an air goal
- if (BotGetAirGoal(bs, &goal)) {
- trap_BotPushGoal(bs->gs, &goal);
- return qtrue;
- }
- else {
- //get a nearby goal outside the water
- while(trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range)) {
- trap_BotGetTopGoal(bs->gs, &goal);
- //if the goal is not in water
- if (!(trap_AAS_PointContents(goal.origin) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))) {
- return qtrue;
- }
- trap_BotPopGoal(bs->gs);
- }
- trap_BotResetAvoidGoals(bs->gs);
- }
- }
- return qfalse;
-}
-
-/*
-==================
-BotNearbyGoal
-==================
-*/
-int BotNearbyGoal(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) {
- int ret;
-
- //check if the bot should go for air
- if (BotGoForAir(bs, tfl, ltg, range)) return qtrue;
- //if the bot is carrying the enemy flag
- if (BotCTFCarryingFlag(bs)) {
- //if the bot is just a few secs away from the base
- if (trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin,
- bs->teamgoal.areanum, TFL_DEFAULT) < 300) {
- //make the range really small
- range = 50;
- }
- }
- //
- ret = trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range);
- /*
- if (ret)
- {
- char buf[128];
- //get the goal at the top of the stack
- trap_BotGetTopGoal(bs->gs, &goal);
- trap_BotGoalName(goal.number, buf, sizeof(buf));
- BotAI_Print(PRT_MESSAGE, "%1.1f: new nearby goal %s\n", FloatTime(), buf);
- }
- */
- return ret;
-}
-
-/*
-==================
-BotReachedGoal
-==================
-*/
-int BotReachedGoal(bot_state_t *bs, bot_goal_t *goal) {
- if (goal->flags & GFL_ITEM) {
- //if touching the goal
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- if (!(goal->flags & GFL_DROPPED)) {
- trap_BotSetAvoidGoalTime(bs->gs, goal->number, -1);
- }
- return qtrue;
- }
- //if the goal isn't there
- if (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) {
- /*
- float avoidtime;
- int t;
-
- avoidtime = trap_BotAvoidGoalTime(bs->gs, goal->number);
- if (avoidtime > 0) {
- t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, goal->areanum, bs->tfl);
- if ((float) t * 0.009 < avoidtime)
- return qtrue;
- }
- */
- return qtrue;
- }
- //if in the goal area and below or above the goal and not swimming
- if (bs->areanum == goal->areanum) {
- if (bs->origin[0] > goal->origin[0] + goal->mins[0] && bs->origin[0] < goal->origin[0] + goal->maxs[0]) {
- if (bs->origin[1] > goal->origin[1] + goal->mins[1] && bs->origin[1] < goal->origin[1] + goal->maxs[1]) {
- if (!trap_AAS_Swimming(bs->origin)) {
- return qtrue;
- }
- }
- }
- }
- }
- else if (goal->flags & GFL_AIR) {
- //if touching the goal
- if (trap_BotTouchingGoal(bs->origin, goal)) return qtrue;
- //if the bot got air
- if (bs->lastair_time > FloatTime() - 1) return qtrue;
- }
- else {
- //if touching the goal
- if (trap_BotTouchingGoal(bs->origin, goal)) return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-BotGetItemLongTermGoal
-==================
-*/
-int BotGetItemLongTermGoal(bot_state_t *bs, int tfl, bot_goal_t *goal) {
- //if the bot has no goal
- if (!trap_BotGetTopGoal(bs->gs, goal)) {
- //BotAI_Print(PRT_MESSAGE, "no ltg on stack\n");
- bs->ltg_time = 0;
- }
- //if the bot touches the current goal
- else if (BotReachedGoal(bs, goal)) {
- BotChooseWeapon(bs);
- bs->ltg_time = 0;
- }
- //if it is time to find a new long term goal
- if (bs->ltg_time < FloatTime()) {
- //pop the current goal from the stack
- trap_BotPopGoal(bs->gs);
- //BotAI_Print(PRT_MESSAGE, "%s: choosing new ltg\n", ClientName(bs->client, netname, sizeof(netname)));
- //choose a new goal
- //BotAI_Print(PRT_MESSAGE, "%6.1f client %d: BotChooseLTGItem\n", FloatTime(), bs->client);
- if (trap_BotChooseLTGItem(bs->gs, bs->origin, bs->inventory, tfl)) {
- /*
- char buf[128];
- //get the goal at the top of the stack
- trap_BotGetTopGoal(bs->gs, goal);
- trap_BotGoalName(goal->number, buf, sizeof(buf));
- BotAI_Print(PRT_MESSAGE, "%1.1f: new long term goal %s\n", FloatTime(), buf);
- */
- bs->ltg_time = FloatTime() + 20;
- }
- else {//the bot gets sorta stuck with all the avoid timings, shouldn't happen though
- //
-#ifdef DEBUG
- char netname[128];
-
- BotAI_Print(PRT_MESSAGE, "%s: no valid ltg (probably stuck)\n", ClientName(bs->client, netname, sizeof(netname)));
-#endif
- //trap_BotDumpAvoidGoals(bs->gs);
- //reset the avoid goals and the avoid reach
- trap_BotResetAvoidGoals(bs->gs);
- trap_BotResetAvoidReach(bs->ms);
- }
- //get the goal at the top of the stack
- return trap_BotGetTopGoal(bs->gs, goal);
- }
- return qtrue;
-}
-
-/*
-==================
-BotGetLongTermGoal
-
-we could also create a seperate AI node for every long term goal type
-however this saves us a lot of code
-==================
-*/
-int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) {
- vec3_t target, dir, dir2;
- char netname[MAX_NETNAME];
- char buf[MAX_MESSAGE_SIZE];
- int areanum;
- float croucher;
- aas_entityinfo_t entinfo, botinfo;
- bot_waypoint_t *wp;
-
- if (bs->ltgtype == LTG_TEAMHELP && !retreat) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "help_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
- bs->teammessage_time = 0;
- }
- //if trying to help the team mate for more than a minute
- if (bs->teamgoal_time < FloatTime())
- bs->ltgtype = 0;
- //if the team mate IS visible for quite some time
- if (bs->teammatevisible_time < FloatTime() - 10) bs->ltgtype = 0;
- //get entity information of the companion
- BotEntityInfo(bs->teammate, &entinfo);
- //if the team mate is visible
- if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) {
- //if close just stand still there
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(100)) {
- trap_BotResetAvoidReach(bs->ms);
- return qfalse;
- }
- }
- else {
- //last time the bot was NOT visible
- bs->teammatevisible_time = FloatTime();
- }
- //if the entity information is valid (entity in PVS)
- if (entinfo.valid) {
- areanum = BotPointAreaNum(entinfo.origin);
- if (areanum && trap_AAS_AreaReachability(areanum)) {
- //update team goal
- bs->teamgoal.entitynum = bs->teammate;
- bs->teamgoal.areanum = areanum;
- VectorCopy(entinfo.origin, bs->teamgoal.origin);
- VectorSet(bs->teamgoal.mins, -8, -8, -8);
- VectorSet(bs->teamgoal.maxs, 8, 8, 8);
- }
- }
- memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
- return qtrue;
- }
- //if the bot accompanies someone
- if (bs->ltgtype == LTG_TEAMACCOMPANY && !retreat) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "accompany_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
- bs->teammessage_time = 0;
- }
- //if accompanying the companion for 3 minutes
- if (bs->teamgoal_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "accompany_stop", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->ltgtype = 0;
- }
- //get entity information of the companion
- BotEntityInfo(bs->teammate, &entinfo);
- //if the companion is visible
- if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) {
- //update visible time
- bs->teammatevisible_time = FloatTime();
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(bs->formation_dist)) {
- //
- // if the client being followed bumps into this bot then
- // the bot should back up
- BotEntityInfo(bs->entitynum, &botinfo);
- // if the followed client is not standing ontop of the bot
- if (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2]) {
- // if the bounding boxes touch each other
- if (botinfo.origin[0] + botinfo.maxs[0] > entinfo.origin[0] + entinfo.mins[0] - 4&&
- botinfo.origin[0] + botinfo.mins[0] < entinfo.origin[0] + entinfo.maxs[0] + 4) {
- if (botinfo.origin[1] + botinfo.maxs[1] > entinfo.origin[1] + entinfo.mins[1] - 4 &&
- botinfo.origin[1] + botinfo.mins[1] < entinfo.origin[1] + entinfo.maxs[1] + 4) {
- if (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2] - 4 &&
- botinfo.origin[2] + botinfo.mins[2] < entinfo.origin[2] + entinfo.maxs[2] + 4) {
- // if the followed client looks in the direction of this bot
- AngleVectors(entinfo.angles, dir, NULL, NULL);
- dir[2] = 0;
- VectorNormalize(dir);
- //VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir);
- VectorSubtract(bs->origin, entinfo.origin, dir2);
- VectorNormalize(dir2);
- if (DotProduct(dir, dir2) > 0.7) {
- // back up
- BotSetupForMovement(bs);
- trap_BotMoveInDirection(bs->ms, dir2, 400, MOVE_WALK);
- }
- }
- }
- }
- }
- //check if the bot wants to crouch
- //don't crouch if crouched less than 5 seconds ago
- if (bs->attackcrouch_time < FloatTime() - 5) {
- croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);
- if (random() < bs->thinktime * croucher) {
- bs->attackcrouch_time = FloatTime() + 5 + croucher * 15;
- }
- }
- //don't crouch when swimming
- if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1;
- //if not arrived yet or arived some time ago
- if (bs->arrive_time < FloatTime() - 2) {
- //if not arrived yet
- if (!bs->arrive_time) {
- trap_EA_Gesture(bs->client);
- BotAI_BotInitialChat(bs, "accompany_arrive", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->arrive_time = FloatTime();
- }
- //if the bot wants to crouch
- else if (bs->attackcrouch_time > FloatTime()) {
- trap_EA_Crouch(bs->client);
- }
- //else do some model taunts
- else if (random() < bs->thinktime * 0.05) {
- //do a gesture :)
- trap_EA_Gesture(bs->client);
- }
- }
- //if just arrived look at the companion
- if (bs->arrive_time > FloatTime() - 2) {
- VectorSubtract(entinfo.origin, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- //else look strategically around for enemies
- else if (random() < bs->thinktime * 0.8) {
- BotRoamGoal(bs, target);
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- //check if the bot wants to go for air
- if (BotGoForAir(bs, bs->tfl, &bs->teamgoal, 400)) {
- trap_BotResetLastAvoidReach(bs->ms);
- //get the goal at the top of the stack
- //trap_BotGetTopGoal(bs->gs, &tmpgoal);
- //trap_BotGoalName(tmpgoal.number, buf, 144);
- //BotAI_Print(PRT_MESSAGE, "new nearby goal %s\n", buf);
- //time the bot gets to pick up the nearby goal item
- bs->nbg_time = FloatTime() + 8;
- AIEnter_Seek_NBG(bs, "BotLongTermGoal: go for air");
- return qfalse;
- }
- //
- trap_BotResetAvoidReach(bs->ms);
- return qfalse;
- }
- }
- //if the entity information is valid (entity in PVS)
- if (entinfo.valid) {
- areanum = BotPointAreaNum(entinfo.origin);
- if (areanum && trap_AAS_AreaReachability(areanum)) {
- //update team goal
- bs->teamgoal.entitynum = bs->teammate;
- bs->teamgoal.areanum = areanum;
- VectorCopy(entinfo.origin, bs->teamgoal.origin);
- VectorSet(bs->teamgoal.mins, -8, -8, -8);
- VectorSet(bs->teamgoal.maxs, 8, 8, 8);
- }
- }
- //the goal the bot should go for
- memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
- //if the companion is NOT visible for too long
- if (bs->teammatevisible_time < FloatTime() - 60) {
- BotAI_BotInitialChat(bs, "accompany_cannotfind", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->ltgtype = 0;
- // just to make sure the bot won't spam this message
- bs->teammatevisible_time = FloatTime();
- }
- return qtrue;
- }
- //
- if (bs->ltgtype == LTG_DEFENDKEYAREA) {
- if (trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin,
- bs->teamgoal.areanum, TFL_DEFAULT) > bs->defendaway_range) {
- bs->defendaway_time = 0;
- }
- }
- //if defending a key area
- if (bs->ltgtype == LTG_DEFENDKEYAREA && !retreat &&
- bs->defendaway_time < FloatTime()) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "defend_start", buf, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE);
- bs->teammessage_time = 0;
- }
- //set the bot goal
- memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
- //stop after 2 minutes
- if (bs->teamgoal_time < FloatTime()) {
- trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "defend_stop", buf, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- bs->ltgtype = 0;
- }
- //if very close... go away for some time
- VectorSubtract(goal->origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(70)) {
- trap_BotResetAvoidReach(bs->ms);
- bs->defendaway_time = FloatTime() + 3 + 3 * random();
- if (BotHasPersistantPowerupAndWeapon(bs)) {
- bs->defendaway_range = 100;
- }
- else {
- bs->defendaway_range = 350;
- }
- }
- return qtrue;
- }
- //going to kill someone
- if (bs->ltgtype == LTG_KILL && !retreat) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "kill_start", buf, NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- bs->teammessage_time = 0;
- }
- //
- if (bs->lastkilledplayer == bs->teamgoal.entitynum) {
- EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "kill_done", buf, NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- bs->lastkilledplayer = -1;
- bs->ltgtype = 0;
- }
- //
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //just roam around
- return BotGetItemLongTermGoal(bs, tfl, goal);
- }
- //get an item
- if (bs->ltgtype == LTG_GETITEM && !retreat) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "getitem_start", buf, NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
- bs->teammessage_time = 0;
- }
- //set the bot goal
- memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
- //stop after some time
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //
- if (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) {
- trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "getitem_notthere", buf, NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- bs->ltgtype = 0;
- }
- else if (BotReachedGoal(bs, goal)) {
- trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "getitem_gotit", buf, NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- bs->ltgtype = 0;
- }
- return qtrue;
- }
- //if camping somewhere
- if ((bs->ltgtype == LTG_CAMP || bs->ltgtype == LTG_CAMPORDER) && !retreat) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- if (bs->ltgtype == LTG_CAMPORDER) {
- BotAI_BotInitialChat(bs, "camp_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
- }
- bs->teammessage_time = 0;
- }
- //set the bot goal
- memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
- //
- if (bs->teamgoal_time < FloatTime()) {
- if (bs->ltgtype == LTG_CAMPORDER) {
- BotAI_BotInitialChat(bs, "camp_stop", NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- }
- bs->ltgtype = 0;
- }
- //if really near the camp spot
- VectorSubtract(goal->origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(60))
- {
- //if not arrived yet
- if (!bs->arrive_time) {
- if (bs->ltgtype == LTG_CAMPORDER) {
- BotAI_BotInitialChat(bs, "camp_arrive", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_INPOSITION);
- }
- bs->arrive_time = FloatTime();
- }
- //look strategically around for enemies
- if (random() < bs->thinktime * 0.8) {
- BotRoamGoal(bs, target);
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- //check if the bot wants to crouch
- //don't crouch if crouched less than 5 seconds ago
- if (bs->attackcrouch_time < FloatTime() - 5) {
- croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);
- if (random() < bs->thinktime * croucher) {
- bs->attackcrouch_time = FloatTime() + 5 + croucher * 15;
- }
- }
- //if the bot wants to crouch
- if (bs->attackcrouch_time > FloatTime()) {
- trap_EA_Crouch(bs->client);
- }
- //don't crouch when swimming
- if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1;
- //make sure the bot is not gonna drown
- if (trap_PointContents(bs->eye,bs->entitynum) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) {
- if (bs->ltgtype == LTG_CAMPORDER) {
- BotAI_BotInitialChat(bs, "camp_stop", NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- //
- if (bs->lastgoal_ltgtype == LTG_CAMPORDER) {
- bs->lastgoal_ltgtype = 0;
- }
- }
- bs->ltgtype = 0;
- }
- //
- if (bs->camp_range > 0) {
- //FIXME: move around a bit
- }
- //
- trap_BotResetAvoidReach(bs->ms);
- return qfalse;
- }
- return qtrue;
- }
- //patrolling along several waypoints
- if (bs->ltgtype == LTG_PATROL && !retreat) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- strcpy(buf, "");
- for (wp = bs->patrolpoints; wp; wp = wp->next) {
- strcat(buf, wp->name);
- if (wp->next) strcat(buf, " to ");
- }
- BotAI_BotInitialChat(bs, "patrol_start", buf, NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
- bs->teammessage_time = 0;
- }
- //
- if (!bs->curpatrolpoint) {
- bs->ltgtype = 0;
- return qfalse;
- }
- //if the bot touches the current goal
- if (trap_BotTouchingGoal(bs->origin, &bs->curpatrolpoint->goal)) {
- if (bs->patrolflags & PATROL_BACK) {
- if (bs->curpatrolpoint->prev) {
- bs->curpatrolpoint = bs->curpatrolpoint->prev;
- }
- else {
- bs->curpatrolpoint = bs->curpatrolpoint->next;
- bs->patrolflags &= ~PATROL_BACK;
- }
- }
- else {
- if (bs->curpatrolpoint->next) {
- bs->curpatrolpoint = bs->curpatrolpoint->next;
- }
- else {
- bs->curpatrolpoint = bs->curpatrolpoint->prev;
- bs->patrolflags |= PATROL_BACK;
- }
- }
- }
- //stop after 5 minutes
- if (bs->teamgoal_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "patrol_stop", NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- bs->ltgtype = 0;
- }
- if (!bs->curpatrolpoint) {
- bs->ltgtype = 0;
- return qfalse;
- }
- memcpy(goal, &bs->curpatrolpoint->goal, sizeof(bot_goal_t));
- return qtrue;
- }
-#ifdef CTF
- if (gametype == GT_CTF) {
- //if going for enemy flag
- if (bs->ltgtype == LTG_GETFLAG) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "captureflag_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONGETFLAG);
- bs->teammessage_time = 0;
- }
- //
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //if touching the flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- // make sure the bot knows the flag isn't there anymore
- switch(BotTeam(bs)) {
- case TEAM_RED: bs->blueflagstatus = 1; break;
- case TEAM_BLUE: bs->redflagstatus = 1; break;
- }
- bs->ltgtype = 0;
- }
- //stop after 3 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- BotAlternateRoute(bs, goal);
- return qtrue;
- }
- //if rushing to the base
- if (bs->ltgtype == LTG_RUSHBASE && bs->rushbaseaway_time < FloatTime()) {
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //if not carrying the flag anymore
- if (!BotCTFCarryingFlag(bs)) bs->ltgtype = 0;
- //quit rushing after 2 minutes
- if (bs->teamgoal_time < FloatTime()) bs->ltgtype = 0;
- //if touching the base flag the bot should loose the enemy flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- //if the bot is still carrying the enemy flag then the
- //base flag is gone, now just walk near the base a bit
- if (BotCTFCarryingFlag(bs)) {
- trap_BotResetAvoidReach(bs->ms);
- bs->rushbaseaway_time = FloatTime() + 5 + 10 * random();
- //FIXME: add chat to tell the others to get back the flag
- }
- else {
- bs->ltgtype = 0;
- }
- }
- BotAlternateRoute(bs, goal);
- return qtrue;
- }
- //returning flag
- if (bs->ltgtype == LTG_RETURNFLAG) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "returnflag_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONRETURNFLAG);
- bs->teammessage_time = 0;
- }
- //
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //if touching the flag
- if (trap_BotTouchingGoal(bs->origin, goal)) bs->ltgtype = 0;
- //stop after 3 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- BotAlternateRoute(bs, goal);
- return qtrue;
- }
- }
-#endif //CTF
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- if (bs->ltgtype == LTG_GETFLAG) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "captureflag_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONGETFLAG);
- bs->teammessage_time = 0;
- }
- memcpy(goal, &ctf_neutralflag, sizeof(bot_goal_t));
- //if touching the flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- bs->ltgtype = 0;
- }
- //stop after 3 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- return qtrue;
- }
- //if rushing to the base
- if (bs->ltgtype == LTG_RUSHBASE) {
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //if not carrying the flag anymore
- if (!Bot1FCTFCarryingFlag(bs)) {
- bs->ltgtype = 0;
- }
- //quit rushing after 2 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //if touching the base flag the bot should loose the enemy flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- bs->ltgtype = 0;
- }
- BotAlternateRoute(bs, goal);
- return qtrue;
- }
- //attack the enemy base
- if (bs->ltgtype == LTG_ATTACKENEMYBASE &&
- bs->attackaway_time < FloatTime()) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "attackenemybase_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
- bs->teammessage_time = 0;
- }
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //quit rushing after 2 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //if touching the base flag the bot should loose the enemy flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- bs->attackaway_time = FloatTime() + 2 + 5 * random();
- }
- return qtrue;
- }
- //returning flag
- if (bs->ltgtype == LTG_RETURNFLAG) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "returnflag_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONRETURNFLAG);
- bs->teammessage_time = 0;
- }
- //
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //just roam around
- return BotGetItemLongTermGoal(bs, tfl, goal);
- }
- }
- else if (gametype == GT_OBELISK) {
- if (bs->ltgtype == LTG_ATTACKENEMYBASE &&
- bs->attackaway_time < FloatTime()) {
-
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "attackenemybase_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
- bs->teammessage_time = 0;
- }
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //if the bot no longer wants to attack the obelisk
- if (BotFeelingBad(bs) > 50) {
- return BotGetItemLongTermGoal(bs, tfl, goal);
- }
- //if touching the obelisk
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- bs->attackaway_time = FloatTime() + 3 + 5 * random();
- }
- // or very close to the obelisk
- VectorSubtract(bs->origin, goal->origin, dir);
- if (VectorLengthSquared(dir) < Square(60)) {
- bs->attackaway_time = FloatTime() + 3 + 5 * random();
- }
- //quit rushing after 2 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- BotAlternateRoute(bs, goal);
- //just move towards the obelisk
- return qtrue;
- }
- }
- else if (gametype == GT_HARVESTER) {
- //if rushing to the base
- if (bs->ltgtype == LTG_RUSHBASE) {
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break;
- default: BotGoHarvest(bs); return qfalse;
- }
- //if not carrying any cubes
- if (!BotHarvesterCarryingCubes(bs)) {
- BotGoHarvest(bs);
- return qfalse;
- }
- //quit rushing after 2 minutes
- if (bs->teamgoal_time < FloatTime()) {
- BotGoHarvest(bs);
- return qfalse;
- }
- //if touching the base flag the bot should loose the enemy flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- BotGoHarvest(bs);
- return qfalse;
- }
- BotAlternateRoute(bs, goal);
- return qtrue;
- }
- //attack the enemy base
- if (bs->ltgtype == LTG_ATTACKENEMYBASE &&
- bs->attackaway_time < FloatTime()) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "attackenemybase_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
- bs->teammessage_time = 0;
- }
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //quit rushing after 2 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //if touching the base flag the bot should loose the enemy flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- bs->attackaway_time = FloatTime() + 2 + 5 * random();
- }
- return qtrue;
- }
- //harvest cubes
- if (bs->ltgtype == LTG_HARVEST &&
- bs->harvestaway_time < FloatTime()) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "harvest_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
- bs->teammessage_time = 0;
- }
- memcpy(goal, &neutralobelisk, sizeof(bot_goal_t));
- //
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- bs->harvestaway_time = FloatTime() + 4 + 3 * random();
- }
- return qtrue;
- }
- }
-#endif
- //normal goal stuff
- return BotGetItemLongTermGoal(bs, tfl, goal);
-}
-
-/*
-==================
-BotLongTermGoal
-==================
-*/
-int BotLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) {
- aas_entityinfo_t entinfo;
- char teammate[MAX_MESSAGE_SIZE];
- float squaredist;
- int areanum;
- vec3_t dir;
-
- //FIXME: also have air long term goals?
- //
- //if the bot is leading someone and not retreating
- if (bs->lead_time > 0 && !retreat) {
- if (bs->lead_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "lead_stop", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->lead_time = 0;
- return BotGetLongTermGoal(bs, tfl, retreat, goal);
- }
- //
- if (bs->leadmessage_time < 0 && -bs->leadmessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->leadmessage_time = FloatTime();
- }
- //get entity information of the companion
- BotEntityInfo(bs->lead_teammate, &entinfo);
- //
- if (entinfo.valid) {
- areanum = BotPointAreaNum(entinfo.origin);
- if (areanum && trap_AAS_AreaReachability(areanum)) {
- //update team goal
- bs->lead_teamgoal.entitynum = bs->lead_teammate;
- bs->lead_teamgoal.areanum = areanum;
- VectorCopy(entinfo.origin, bs->lead_teamgoal.origin);
- VectorSet(bs->lead_teamgoal.mins, -8, -8, -8);
- VectorSet(bs->lead_teamgoal.maxs, 8, 8, 8);
- }
- }
- //if the team mate is visible
- if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->lead_teammate)) {
- bs->leadvisible_time = FloatTime();
- }
- //if the team mate is not visible for 1 seconds
- if (bs->leadvisible_time < FloatTime() - 1) {
- bs->leadbackup_time = FloatTime() + 2;
- }
- //distance towards the team mate
- VectorSubtract(bs->origin, bs->lead_teamgoal.origin, dir);
- squaredist = VectorLengthSquared(dir);
- //if backing up towards the team mate
- if (bs->leadbackup_time > FloatTime()) {
- if (bs->leadmessage_time < FloatTime() - 20) {
- BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->leadmessage_time = FloatTime();
- }
- //if very close to the team mate
- if (squaredist < Square(100)) {
- bs->leadbackup_time = 0;
- }
- //the bot should go back to the team mate
- memcpy(goal, &bs->lead_teamgoal, sizeof(bot_goal_t));
- return qtrue;
- }
- else {
- //if quite distant from the team mate
- if (squaredist > Square(500)) {
- if (bs->leadmessage_time < FloatTime() - 20) {
- BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->leadmessage_time = FloatTime();
- }
- //look at the team mate
- VectorSubtract(entinfo.origin, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- //just wait for the team mate
- return qfalse;
- }
- }
- }
- return BotGetLongTermGoal(bs, tfl, retreat, goal);
-}
-
-/*
-==================
-AIEnter_Intermission
-==================
-*/
-void AIEnter_Intermission(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "intermission", "", s);
- //reset the bot state
- BotResetState(bs);
- //check for end level chat
- if (BotChat_EndLevel(bs)) {
- trap_BotEnterChat(bs->cs, 0, bs->chatto);
- }
- bs->ainode = AINode_Intermission;
-}
-
-/*
-==================
-AINode_Intermission
-==================
-*/
-int AINode_Intermission(bot_state_t *bs) {
- //if the intermission ended
- if (!BotIntermission(bs)) {
- if (BotChat_StartLevel(bs)) {
- bs->stand_time = FloatTime() + BotChatTime(bs);
- }
- else {
- bs->stand_time = FloatTime() + 2;
- }
- AIEnter_Stand(bs, "intermission: chat");
- }
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Observer
-==================
-*/
-void AIEnter_Observer(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "observer", "", s);
- //reset the bot state
- BotResetState(bs);
- bs->ainode = AINode_Observer;
-}
-
-/*
-==================
-AINode_Observer
-==================
-*/
-int AINode_Observer(bot_state_t *bs) {
- //if the bot left observer mode
- if (!BotIsObserver(bs)) {
- AIEnter_Stand(bs, "observer: left observer");
- }
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Stand
-==================
-*/
-void AIEnter_Stand(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "stand", "", s);
- bs->standfindenemy_time = FloatTime() + 1;
- bs->ainode = AINode_Stand;
-}
-
-/*
-==================
-AINode_Stand
-==================
-*/
-int AINode_Stand(bot_state_t *bs) {
-
- //if the bot's health decreased
- if (bs->lastframe_health > bs->inventory[INVENTORY_HEALTH]) {
- if (BotChat_HitTalking(bs)) {
- bs->standfindenemy_time = FloatTime() + BotChatTime(bs) + 0.1;
- bs->stand_time = FloatTime() + BotChatTime(bs) + 0.1;
- }
- }
- if (bs->standfindenemy_time < FloatTime()) {
- if (BotFindEnemy(bs, -1)) {
- AIEnter_Battle_Fight(bs, "stand: found enemy");
- return qfalse;
- }
- bs->standfindenemy_time = FloatTime() + 1;
- }
- // put up chat icon
- trap_EA_Talk(bs->client);
- // when done standing
- if (bs->stand_time < FloatTime()) {
- trap_BotEnterChat(bs->cs, 0, bs->chatto);
- AIEnter_Seek_LTG(bs, "stand: time out");
- return qfalse;
- }
- //
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Respawn
-==================
-*/
-void AIEnter_Respawn(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "respawn", "", s);
- //reset some states
- trap_BotResetMoveState(bs->ms);
- trap_BotResetGoalState(bs->gs);
- trap_BotResetAvoidGoals(bs->gs);
- trap_BotResetAvoidReach(bs->ms);
- //if the bot wants to chat
- if (BotChat_Death(bs)) {
- bs->respawn_time = FloatTime() + BotChatTime(bs);
- bs->respawnchat_time = FloatTime();
- }
- else {
- bs->respawn_time = FloatTime() + 1 + random();
- bs->respawnchat_time = 0;
- }
- //set respawn state
- bs->respawn_wait = qfalse;
- bs->ainode = AINode_Respawn;
-}
-
-/*
-==================
-AINode_Respawn
-==================
-*/
-int AINode_Respawn(bot_state_t *bs) {
- // if waiting for the actual respawn
- if (bs->respawn_wait) {
- if (!BotIsDead(bs)) {
- AIEnter_Seek_LTG(bs, "respawn: respawned");
- }
- else {
- trap_EA_Respawn(bs->client);
- }
- }
- else if (bs->respawn_time < FloatTime()) {
- // wait until respawned
- bs->respawn_wait = qtrue;
- // elementary action respawn
- trap_EA_Respawn(bs->client);
- //
- if (bs->respawnchat_time) {
- trap_BotEnterChat(bs->cs, 0, bs->chatto);
- bs->enemy = -1;
- }
- }
- if (bs->respawnchat_time && bs->respawnchat_time < FloatTime() - 0.5) {
- trap_EA_Talk(bs->client);
- }
- //
- return qtrue;
-}
-
-/*
-==================
-BotSelectActivateWeapon
-==================
-*/
-int BotSelectActivateWeapon(bot_state_t *bs) {
- //
- if (bs->inventory[INVENTORY_MACHINEGUN] > 0 && bs->inventory[INVENTORY_BULLETS] > 0)
- return WEAPONINDEX_MACHINEGUN;
- else if (bs->inventory[INVENTORY_SHOTGUN] > 0 && bs->inventory[INVENTORY_SHELLS] > 0)
- return WEAPONINDEX_SHOTGUN;
- else if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0)
- return WEAPONINDEX_PLASMAGUN;
- else if (bs->inventory[INVENTORY_LIGHTNING] > 0 && bs->inventory[INVENTORY_LIGHTNINGAMMO] > 0)
- return WEAPONINDEX_LIGHTNING;
-#ifdef MISSIONPACK
- else if (bs->inventory[INVENTORY_CHAINGUN] > 0 && bs->inventory[INVENTORY_BELT] > 0)
- return WEAPONINDEX_CHAINGUN;
- else if (bs->inventory[INVENTORY_NAILGUN] > 0 && bs->inventory[INVENTORY_NAILS] > 0)
- return WEAPONINDEX_NAILGUN;
-#endif
- else if (bs->inventory[INVENTORY_RAILGUN] > 0 && bs->inventory[INVENTORY_SLUGS] > 0)
- return WEAPONINDEX_RAILGUN;
- else if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0)
- return WEAPONINDEX_ROCKET_LAUNCHER;
- else if (bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0)
- return WEAPONINDEX_BFG;
- else {
- return -1;
- }
-}
-
-/*
-==================
-BotClearPath
-
- try to deactivate obstacles like proximity mines on the bot's path
-==================
-*/
-void BotClearPath(bot_state_t *bs, bot_moveresult_t *moveresult) {
- int i, bestmine;
- float dist, bestdist;
- vec3_t target, dir;
- bsp_trace_t bsptrace;
- entityState_t state;
-
- // if there is a dead body wearing kamikze nearby
- if (bs->kamikazebody) {
- // if the bot's view angles and weapon are not used for movement
- if ( !(moveresult->flags & (MOVERESULT_MOVEMENTVIEW | MOVERESULT_MOVEMENTWEAPON)) ) {
- //
- BotAI_GetEntityState(bs->kamikazebody, &state);
- VectorCopy(state.pos.trBase, target);
- target[2] += 8;
- VectorSubtract(target, bs->eye, dir);
- vectoangles(dir, moveresult->ideal_viewangles);
- //
- moveresult->weapon = BotSelectActivateWeapon(bs);
- if (moveresult->weapon == -1) {
- // FIXME: run away!
- moveresult->weapon = 0;
- }
- if (moveresult->weapon) {
- //
- moveresult->flags |= MOVERESULT_MOVEMENTWEAPON | MOVERESULT_MOVEMENTVIEW;
- // if holding the right weapon
- if (bs->cur_ps.weapon == moveresult->weapon) {
- // if the bot is pretty close with it's aim
- if (InFieldOfVision(bs->viewangles, 20, moveresult->ideal_viewangles)) {
- //
- BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, target, bs->entitynum, MASK_SHOT);
- // if the mine is visible from the current position
- if (bsptrace.fraction >= 1.0 || bsptrace.ent == state.number) {
- // shoot at the mine
- trap_EA_Attack(bs->client);
- }
- }
- }
- }
- }
- }
- if (moveresult->flags & MOVERESULT_BLOCKEDBYAVOIDSPOT) {
- bs->blockedbyavoidspot_time = FloatTime() + 5;
- }
- // if blocked by an avoid spot and the view angles and weapon are used for movement
- if (bs->blockedbyavoidspot_time > FloatTime() &&
- !(moveresult->flags & (MOVERESULT_MOVEMENTVIEW | MOVERESULT_MOVEMENTWEAPON)) ) {
- bestdist = 300;
- bestmine = -1;
- for (i = 0; i < bs->numproxmines; i++) {
- BotAI_GetEntityState(bs->proxmines[i], &state);
- VectorSubtract(state.pos.trBase, bs->origin, dir);
- dist = VectorLength(dir);
- if (dist < bestdist) {
- bestdist = dist;
- bestmine = i;
- }
- }
- if (bestmine != -1) {
- //
- // state->generic1 == TEAM_RED || state->generic1 == TEAM_BLUE
- //
- // deactivate prox mines in the bot's path by shooting
- // rockets or plasma cells etc. at them
- BotAI_GetEntityState(bs->proxmines[bestmine], &state);
- VectorCopy(state.pos.trBase, target);
- target[2] += 2;
- VectorSubtract(target, bs->eye, dir);
- vectoangles(dir, moveresult->ideal_viewangles);
- // if the bot has a weapon that does splash damage
- if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0)
- moveresult->weapon = WEAPONINDEX_PLASMAGUN;
- else if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0)
- moveresult->weapon = WEAPONINDEX_ROCKET_LAUNCHER;
- else if (bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0)
- moveresult->weapon = WEAPONINDEX_BFG;
- else {
- moveresult->weapon = 0;
- }
- if (moveresult->weapon) {
- //
- moveresult->flags |= MOVERESULT_MOVEMENTWEAPON | MOVERESULT_MOVEMENTVIEW;
- // if holding the right weapon
- if (bs->cur_ps.weapon == moveresult->weapon) {
- // if the bot is pretty close with it's aim
- if (InFieldOfVision(bs->viewangles, 20, moveresult->ideal_viewangles)) {
- //
- BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, target, bs->entitynum, MASK_SHOT);
- // if the mine is visible from the current position
- if (bsptrace.fraction >= 1.0 || bsptrace.ent == state.number) {
- // shoot at the mine
- trap_EA_Attack(bs->client);
- }
- }
- }
- }
- }
- }
-}
-
-/*
-==================
-AIEnter_Seek_ActivateEntity
-==================
-*/
-void AIEnter_Seek_ActivateEntity(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "activate entity", "", s);
- bs->ainode = AINode_Seek_ActivateEntity;
-}
-
-/*
-==================
-AINode_Seek_Activate_Entity
-==================
-*/
-int AINode_Seek_ActivateEntity(bot_state_t *bs) {
- bot_goal_t *goal;
- vec3_t target, dir, ideal_viewangles;
- bot_moveresult_t moveresult;
- int targetvisible;
- bsp_trace_t bsptrace;
- aas_entityinfo_t entinfo;
-
- if (BotIsObserver(bs)) {
- BotClearActivateGoalStack(bs);
- AIEnter_Observer(bs, "active entity: observer");
- return qfalse;
- }
- //if in the intermission
- if (BotIntermission(bs)) {
- BotClearActivateGoalStack(bs);
- AIEnter_Intermission(bs, "activate entity: intermission");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- BotClearActivateGoalStack(bs);
- AIEnter_Respawn(bs, "activate entity: bot dead");
- return qfalse;
- }
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- // if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- // map specific code
- BotMapScripts(bs);
- // no enemy
- bs->enemy = -1;
- // if the bot has no activate goal
- if (!bs->activatestack) {
- BotClearActivateGoalStack(bs);
- AIEnter_Seek_NBG(bs, "activate entity: no goal");
- return qfalse;
- }
- //
- goal = &bs->activatestack->goal;
- // initialize target being visible to false
- targetvisible = qfalse;
- // if the bot has to shoot at a target to activate something
- if (bs->activatestack->shoot) {
- //
- BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, bs->activatestack->target, bs->entitynum, MASK_SHOT);
- // if the shootable entity is visible from the current position
- if (bsptrace.fraction >= 1.0 || bsptrace.ent == goal->entitynum) {
- targetvisible = qtrue;
- // if holding the right weapon
- if (bs->cur_ps.weapon == bs->activatestack->weapon) {
- VectorSubtract(bs->activatestack->target, bs->eye, dir);
- vectoangles(dir, ideal_viewangles);
- // if the bot is pretty close with it's aim
- if (InFieldOfVision(bs->viewangles, 20, ideal_viewangles)) {
- trap_EA_Attack(bs->client);
- }
- }
- }
- }
- // if the shoot target is visible
- if (targetvisible) {
- // get the entity info of the entity the bot is shooting at
- BotEntityInfo(goal->entitynum, &entinfo);
- // if the entity the bot shoots at moved
- if (!VectorCompare(bs->activatestack->origin, entinfo.origin)) {
-#ifdef DEBUG
- BotAI_Print(PRT_MESSAGE, "hit shootable button or trigger\n");
-#endif //DEBUG
- bs->activatestack->time = 0;
- }
- // if the activate goal has been activated or the bot takes too long
- if (bs->activatestack->time < FloatTime()) {
- BotPopFromActivateGoalStack(bs);
- // if there are more activate goals on the stack
- if (bs->activatestack) {
- bs->activatestack->time = FloatTime() + 10;
- return qfalse;
- }
- AIEnter_Seek_NBG(bs, "activate entity: time out");
- return qfalse;
- }
- memset(&moveresult, 0, sizeof(bot_moveresult_t));
- }
- else {
- // if the bot has no goal
- if (!goal) {
- bs->activatestack->time = 0;
- }
- // if the bot does not have a shoot goal
- else if (!bs->activatestack->shoot) {
- //if the bot touches the current goal
- if (trap_BotTouchingGoal(bs->origin, goal)) {
-#ifdef DEBUG
- BotAI_Print(PRT_MESSAGE, "touched button or trigger\n");
-#endif //DEBUG
- bs->activatestack->time = 0;
- }
- }
- // if the activate goal has been activated or the bot takes too long
- if (bs->activatestack->time < FloatTime()) {
- BotPopFromActivateGoalStack(bs);
- // if there are more activate goals on the stack
- if (bs->activatestack) {
- bs->activatestack->time = FloatTime() + 10;
- return qfalse;
- }
- AIEnter_Seek_NBG(bs, "activate entity: activated");
- return qfalse;
- }
- //predict obstacles
- if (BotAIPredictObstacles(bs, goal))
- return qfalse;
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, goal, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- //
- bs->activatestack->time = 0;
- }
- //check if the bot is blocked
- BotAIBlocked(bs, &moveresult, qtrue);
- }
- //
- BotClearPath(bs, &moveresult);
- // if the bot has to shoot to activate
- if (bs->activatestack->shoot) {
- // if the view angles aren't yet used for the movement
- if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEW)) {
- VectorSubtract(bs->activatestack->target, bs->eye, dir);
- vectoangles(dir, moveresult.ideal_viewangles);
- moveresult.flags |= MOVERESULT_MOVEMENTVIEW;
- }
- // if there's no weapon yet used for the movement
- if (!(moveresult.flags & MOVERESULT_MOVEMENTWEAPON)) {
- moveresult.flags |= MOVERESULT_MOVEMENTWEAPON;
- //
- bs->activatestack->weapon = BotSelectActivateWeapon(bs);
- if (bs->activatestack->weapon == -1) {
- //FIXME: find a decent weapon first
- bs->activatestack->weapon = 0;
- }
- moveresult.weapon = bs->activatestack->weapon;
- }
- }
- // if the ideal view angles are set for movement
- if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
- VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
- }
- // if waiting for something
- else if (moveresult.flags & MOVERESULT_WAITING) {
- if (random() < bs->thinktime * 0.8) {
- BotRoamGoal(bs, target);
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- }
- else if (!(bs->flags & BFL_IDEALVIEWSET)) {
- if (trap_BotMovementViewTarget(bs->ms, goal, bs->tfl, 300, target)) {
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- }
- else {
- vectoangles(moveresult.movedir, bs->ideal_viewangles);
- }
- bs->ideal_viewangles[2] *= 0.5;
- }
- // if the weapon is used for the bot movement
- if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON)
- bs->weaponnum = moveresult.weapon;
- // if there is an enemy
- if (BotFindEnemy(bs, -1)) {
- if (BotWantsToRetreat(bs)) {
- //keep the current long term goal and retreat
- AIEnter_Battle_NBG(bs, "activate entity: found enemy");
- }
- else {
- trap_BotResetLastAvoidReach(bs->ms);
- //empty the goal stack
- trap_BotEmptyGoalStack(bs->gs);
- //go fight
- AIEnter_Battle_Fight(bs, "activate entity: found enemy");
- }
- BotClearActivateGoalStack(bs);
- }
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Seek_NBG
-==================
-*/
-void AIEnter_Seek_NBG(bot_state_t *bs, char *s) {
- bot_goal_t goal;
- char buf[144];
-
- if (trap_BotGetTopGoal(bs->gs, &goal)) {
- trap_BotGoalName(goal.number, buf, 144);
- BotRecordNodeSwitch(bs, "seek NBG", buf, s);
- }
- else {
- BotRecordNodeSwitch(bs, "seek NBG", "no goal", s);
- }
- bs->ainode = AINode_Seek_NBG;
-}
-
-/*
-==================
-AINode_Seek_NBG
-==================
-*/
-int AINode_Seek_NBG(bot_state_t *bs) {
- bot_goal_t goal;
- vec3_t target, dir;
- bot_moveresult_t moveresult;
-
- if (BotIsObserver(bs)) {
- AIEnter_Observer(bs, "seek nbg: observer");
- return qfalse;
- }
- //if in the intermission
- if (BotIntermission(bs)) {
- AIEnter_Intermission(bs, "seek nbg: intermision");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- AIEnter_Respawn(bs, "seek nbg: bot dead");
- return qfalse;
- }
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- //if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- //
- if (BotCanAndWantsToRocketJump(bs)) {
- bs->tfl |= TFL_ROCKETJUMP;
- }
- //map specific code
- BotMapScripts(bs);
- //no enemy
- bs->enemy = -1;
- //if the bot has no goal
- if (!trap_BotGetTopGoal(bs->gs, &goal)) bs->nbg_time = 0;
- //if the bot touches the current goal
- else if (BotReachedGoal(bs, &goal)) {
- BotChooseWeapon(bs);
- bs->nbg_time = 0;
- }
- //
- if (bs->nbg_time < FloatTime()) {
- //pop the current goal from the stack
- trap_BotPopGoal(bs->gs);
- //check for new nearby items right away
- //NOTE: we canNOT reset the check_time to zero because it would create an endless loop of node switches
- bs->check_time = FloatTime() + 0.05;
- //go back to seek ltg
- AIEnter_Seek_LTG(bs, "seek nbg: time out");
- return qfalse;
- }
- //predict obstacles
- if (BotAIPredictObstacles(bs, &goal))
- return qfalse;
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- bs->nbg_time = 0;
- }
- //check if the bot is blocked
- BotAIBlocked(bs, &moveresult, qtrue);
- //
- BotClearPath(bs, &moveresult);
- //if the viewangles are used for the movement
- if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
- VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
- }
- //if waiting for something
- else if (moveresult.flags & MOVERESULT_WAITING) {
- if (random() < bs->thinktime * 0.8) {
- BotRoamGoal(bs, target);
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- }
- else if (!(bs->flags & BFL_IDEALVIEWSET)) {
- if (!trap_BotGetSecondGoal(bs->gs, &goal)) trap_BotGetTopGoal(bs->gs, &goal);
- if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- }
- //FIXME: look at cluster portals?
- else vectoangles(moveresult.movedir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- //if the weapon is used for the bot movement
- if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
- //if there is an enemy
- if (BotFindEnemy(bs, -1)) {
- if (BotWantsToRetreat(bs)) {
- //keep the current long term goal and retreat
- AIEnter_Battle_NBG(bs, "seek nbg: found enemy");
- }
- else {
- trap_BotResetLastAvoidReach(bs->ms);
- //empty the goal stack
- trap_BotEmptyGoalStack(bs->gs);
- //go fight
- AIEnter_Battle_Fight(bs, "seek nbg: found enemy");
- }
- }
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Seek_LTG
-==================
-*/
-void AIEnter_Seek_LTG(bot_state_t *bs, char *s) {
- bot_goal_t goal;
- char buf[144];
-
- if (trap_BotGetTopGoal(bs->gs, &goal)) {
- trap_BotGoalName(goal.number, buf, 144);
- BotRecordNodeSwitch(bs, "seek LTG", buf, s);
- }
- else {
- BotRecordNodeSwitch(bs, "seek LTG", "no goal", s);
- }
- bs->ainode = AINode_Seek_LTG;
-}
-
-/*
-==================
-AINode_Seek_LTG
-==================
-*/
-int AINode_Seek_LTG(bot_state_t *bs)
-{
- bot_goal_t goal;
- vec3_t target, dir;
- bot_moveresult_t moveresult;
- int range;
- //char buf[128];
- //bot_goal_t tmpgoal;
-
- if (BotIsObserver(bs)) {
- AIEnter_Observer(bs, "seek ltg: observer");
- return qfalse;
- }
- //if in the intermission
- if (BotIntermission(bs)) {
- AIEnter_Intermission(bs, "seek ltg: intermission");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- AIEnter_Respawn(bs, "seek ltg: bot dead");
- return qfalse;
- }
- //
- if (BotChat_Random(bs)) {
- bs->stand_time = FloatTime() + BotChatTime(bs);
- AIEnter_Stand(bs, "seek ltg: random chat");
- return qfalse;
- }
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- //if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- //
- if (BotCanAndWantsToRocketJump(bs)) {
- bs->tfl |= TFL_ROCKETJUMP;
- }
- //map specific code
- BotMapScripts(bs);
- //no enemy
- bs->enemy = -1;
- //
- if (bs->killedenemy_time > FloatTime() - 2) {
- if (random() < bs->thinktime * 1) {
- trap_EA_Gesture(bs->client);
- }
- }
- //if there is an enemy
- if (BotFindEnemy(bs, -1)) {
- if (BotWantsToRetreat(bs)) {
- //keep the current long term goal and retreat
- AIEnter_Battle_Retreat(bs, "seek ltg: found enemy");
- return qfalse;
- }
- else {
- trap_BotResetLastAvoidReach(bs->ms);
- //empty the goal stack
- trap_BotEmptyGoalStack(bs->gs);
- //go fight
- AIEnter_Battle_Fight(bs, "seek ltg: found enemy");
- return qfalse;
- }
- }
- //
- BotTeamGoals(bs, qfalse);
- //get the current long term goal
- if (!BotLongTermGoal(bs, bs->tfl, qfalse, &goal)) {
- return qtrue;
- }
- //check for nearby goals periodicly
- if (bs->check_time < FloatTime()) {
- bs->check_time = FloatTime() + 0.5;
- //check if the bot wants to camp
- BotWantsToCamp(bs);
- //
- if (bs->ltgtype == LTG_DEFENDKEYAREA) range = 400;
- else range = 150;
- //
-#ifdef CTF
- if (gametype == GT_CTF) {
- //if carrying a flag the bot shouldn't be distracted too much
- if (BotCTFCarryingFlag(bs))
- range = 50;
- }
-#endif //CTF
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- if (Bot1FCTFCarryingFlag(bs))
- range = 50;
- }
- else if (gametype == GT_HARVESTER) {
- if (BotHarvesterCarryingCubes(bs))
- range = 80;
- }
-#endif
- //
- if (BotNearbyGoal(bs, bs->tfl, &goal, range)) {
- trap_BotResetLastAvoidReach(bs->ms);
- //get the goal at the top of the stack
- //trap_BotGetTopGoal(bs->gs, &tmpgoal);
- //trap_BotGoalName(tmpgoal.number, buf, 144);
- //BotAI_Print(PRT_MESSAGE, "new nearby goal %s\n", buf);
- //time the bot gets to pick up the nearby goal item
- bs->nbg_time = FloatTime() + 4 + range * 0.01;
- AIEnter_Seek_NBG(bs, "ltg seek: nbg");
- return qfalse;
- }
- }
- //predict obstacles
- if (BotAIPredictObstacles(bs, &goal))
- return qfalse;
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
- bs->ltg_time = 0;
- }
- //
- BotAIBlocked(bs, &moveresult, qtrue);
- //
- BotClearPath(bs, &moveresult);
- //if the viewangles are used for the movement
- if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
- VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
- }
- //if waiting for something
- else if (moveresult.flags & MOVERESULT_WAITING) {
- if (random() < bs->thinktime * 0.8) {
- BotRoamGoal(bs, target);
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- }
- else if (!(bs->flags & BFL_IDEALVIEWSET)) {
- if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- }
- //FIXME: look at cluster portals?
- else if (VectorLengthSquared(moveresult.movedir)) {
- vectoangles(moveresult.movedir, bs->ideal_viewangles);
- }
- else if (random() < bs->thinktime * 0.8) {
- BotRoamGoal(bs, target);
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- bs->ideal_viewangles[2] *= 0.5;
- }
- //if the weapon is used for the bot movement
- if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
- //
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Battle_Fight
-==================
-*/
-void AIEnter_Battle_Fight(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "battle fight", "", s);
- trap_BotResetLastAvoidReach(bs->ms);
- bs->ainode = AINode_Battle_Fight;
-}
-
-/*
-==================
-AIEnter_Battle_Fight
-==================
-*/
-void AIEnter_Battle_SuicidalFight(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "battle fight", "", s);
- trap_BotResetLastAvoidReach(bs->ms);
- bs->ainode = AINode_Battle_Fight;
- bs->flags |= BFL_FIGHTSUICIDAL;
-}
-
-/*
-==================
-AINode_Battle_Fight
-==================
-*/
-int AINode_Battle_Fight(bot_state_t *bs) {
- int areanum;
- vec3_t target;
- aas_entityinfo_t entinfo;
- bot_moveresult_t moveresult;
-
- if (BotIsObserver(bs)) {
- AIEnter_Observer(bs, "battle fight: observer");
- return qfalse;
- }
-
- //if in the intermission
- if (BotIntermission(bs)) {
- AIEnter_Intermission(bs, "battle fight: intermission");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- AIEnter_Respawn(bs, "battle fight: bot dead");
- return qfalse;
- }
- //if there is another better enemy
- if (BotFindEnemy(bs, bs->enemy)) {
-#ifdef DEBUG
- BotAI_Print(PRT_MESSAGE, "found new better enemy\n");
-#endif
- }
- //if no enemy
- if (bs->enemy < 0) {
- AIEnter_Seek_LTG(bs, "battle fight: no enemy");
- return qfalse;
- }
- //
- BotEntityInfo(bs->enemy, &entinfo);
- //if the enemy is dead
- if (bs->enemydeath_time) {
- if (bs->enemydeath_time < FloatTime() - 1.0) {
- bs->enemydeath_time = 0;
- if (bs->enemysuicide) {
- BotChat_EnemySuicide(bs);
- }
- if (bs->lastkilledplayer == bs->enemy && BotChat_Kill(bs)) {
- bs->stand_time = FloatTime() + BotChatTime(bs);
- AIEnter_Stand(bs, "battle fight: enemy dead");
- }
- else {
- bs->ltg_time = 0;
- AIEnter_Seek_LTG(bs, "battle fight: enemy dead");
- }
- return qfalse;
- }
- }
- else {
- if (EntityIsDead(&entinfo)) {
- bs->enemydeath_time = FloatTime();
- }
- }
- //if the enemy is invisible and not shooting the bot looses track easily
- if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
- if (random() < 0.2) {
- AIEnter_Seek_LTG(bs, "battle fight: invisible");
- return qfalse;
- }
- }
- //
- VectorCopy(entinfo.origin, target);
- // if not a player enemy
- if (bs->enemy >= MAX_CLIENTS) {
-#ifdef MISSIONPACK
- // if attacking an obelisk
- if ( bs->enemy == redobelisk.entitynum ||
- bs->enemy == blueobelisk.entitynum ) {
- target[2] += 16;
- }
-#endif
- }
- //update the reachability area and origin if possible
- areanum = BotPointAreaNum(target);
- if (areanum && trap_AAS_AreaReachability(areanum)) {
- VectorCopy(target, bs->lastenemyorigin);
- bs->lastenemyareanum = areanum;
- }
- //update the attack inventory values
- BotUpdateBattleInventory(bs, bs->enemy);
- //if the bot's health decreased
- if (bs->lastframe_health > bs->inventory[INVENTORY_HEALTH]) {
- if (BotChat_HitNoDeath(bs)) {
- bs->stand_time = FloatTime() + BotChatTime(bs);
- AIEnter_Stand(bs, "battle fight: chat health decreased");
- return qfalse;
- }
- }
- //if the bot hit someone
- if (bs->cur_ps.persistant[PERS_HITS] > bs->lasthitcount) {
- if (BotChat_HitNoKill(bs)) {
- bs->stand_time = FloatTime() + BotChatTime(bs);
- AIEnter_Stand(bs, "battle fight: chat hit someone");
- return qfalse;
- }
- }
- //if the enemy is not visible
- if (!BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
- if (BotWantsToChase(bs)) {
- AIEnter_Battle_Chase(bs, "battle fight: enemy out of sight");
- return qfalse;
- }
- else {
- AIEnter_Seek_LTG(bs, "battle fight: enemy out of sight");
- return qfalse;
- }
- }
- //use holdable items
- BotBattleUseItems(bs);
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- //if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- //
- if (BotCanAndWantsToRocketJump(bs)) {
- bs->tfl |= TFL_ROCKETJUMP;
- }
- //choose the best weapon to fight with
- BotChooseWeapon(bs);
- //do attack movements
- moveresult = BotAttackMove(bs, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
- bs->ltg_time = 0;
- }
- //
- BotAIBlocked(bs, &moveresult, qfalse);
- //aim at the enemy
- BotAimAtEnemy(bs);
- //attack the enemy if possible
- BotCheckAttack(bs);
- //if the bot wants to retreat
- if (!(bs->flags & BFL_FIGHTSUICIDAL)) {
- if (BotWantsToRetreat(bs)) {
- AIEnter_Battle_Retreat(bs, "battle fight: wants to retreat");
- return qtrue;
- }
- }
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Battle_Chase
-==================
-*/
-void AIEnter_Battle_Chase(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "battle chase", "", s);
- bs->chase_time = FloatTime();
- bs->ainode = AINode_Battle_Chase;
-}
-
-/*
-==================
-AINode_Battle_Chase
-==================
-*/
-int AINode_Battle_Chase(bot_state_t *bs)
-{
- bot_goal_t goal;
- vec3_t target, dir;
- bot_moveresult_t moveresult;
- float range;
-
- if (BotIsObserver(bs)) {
- AIEnter_Observer(bs, "battle chase: observer");
- return qfalse;
- }
- //if in the intermission
- if (BotIntermission(bs)) {
- AIEnter_Intermission(bs, "battle chase: intermission");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- AIEnter_Respawn(bs, "battle chase: bot dead");
- return qfalse;
- }
- //if no enemy
- if (bs->enemy < 0) {
- AIEnter_Seek_LTG(bs, "battle chase: no enemy");
- return qfalse;
- }
- //if the enemy is visible
- if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
- AIEnter_Battle_Fight(bs, "battle chase");
- return qfalse;
- }
- //if there is another enemy
- if (BotFindEnemy(bs, -1)) {
- AIEnter_Battle_Fight(bs, "battle chase: better enemy");
- return qfalse;
- }
- //there is no last enemy area
- if (!bs->lastenemyareanum) {
- AIEnter_Seek_LTG(bs, "battle chase: no enemy area");
- return qfalse;
- }
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- //if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- //
- if (BotCanAndWantsToRocketJump(bs)) {
- bs->tfl |= TFL_ROCKETJUMP;
- }
- //map specific code
- BotMapScripts(bs);
- //create the chase goal
- goal.entitynum = bs->enemy;
- goal.areanum = bs->lastenemyareanum;
- VectorCopy(bs->lastenemyorigin, goal.origin);
- VectorSet(goal.mins, -8, -8, -8);
- VectorSet(goal.maxs, 8, 8, 8);
- //if the last seen enemy spot is reached the enemy could not be found
- if (trap_BotTouchingGoal(bs->origin, &goal)) bs->chase_time = 0;
- //if there's no chase time left
- if (!bs->chase_time || bs->chase_time < FloatTime() - 10) {
- AIEnter_Seek_LTG(bs, "battle chase: time out");
- return qfalse;
- }
- //check for nearby goals periodicly
- if (bs->check_time < FloatTime()) {
- bs->check_time = FloatTime() + 1;
- range = 150;
- //
- if (BotNearbyGoal(bs, bs->tfl, &goal, range)) {
- //the bot gets 5 seconds to pick up the nearby goal item
- bs->nbg_time = FloatTime() + 0.1 * range + 1;
- trap_BotResetLastAvoidReach(bs->ms);
- AIEnter_Battle_NBG(bs, "battle chase: nbg");
- return qfalse;
- }
- }
- //
- BotUpdateBattleInventory(bs, bs->enemy);
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
- bs->ltg_time = 0;
- }
- //
- BotAIBlocked(bs, &moveresult, qfalse);
- //
- if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
- VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
- }
- else if (!(bs->flags & BFL_IDEALVIEWSET)) {
- if (bs->chase_time > FloatTime() - 2) {
- BotAimAtEnemy(bs);
- }
- else {
- if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- }
- else {
- vectoangles(moveresult.movedir, bs->ideal_viewangles);
- }
- }
- bs->ideal_viewangles[2] *= 0.5;
- }
- //if the weapon is used for the bot movement
- if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
- //if the bot is in the area the enemy was last seen in
- if (bs->areanum == bs->lastenemyareanum) bs->chase_time = 0;
- //if the bot wants to retreat (the bot could have been damage during the chase)
- if (BotWantsToRetreat(bs)) {
- AIEnter_Battle_Retreat(bs, "battle chase: wants to retreat");
- return qtrue;
- }
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Battle_Retreat
-==================
-*/
-void AIEnter_Battle_Retreat(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "battle retreat", "", s);
- bs->ainode = AINode_Battle_Retreat;
-}
-
-/*
-==================
-AINode_Battle_Retreat
-==================
-*/
-int AINode_Battle_Retreat(bot_state_t *bs) {
- bot_goal_t goal;
- aas_entityinfo_t entinfo;
- bot_moveresult_t moveresult;
- vec3_t target, dir;
- float attack_skill, range;
- int areanum;
-
- if (BotIsObserver(bs)) {
- AIEnter_Observer(bs, "battle retreat: observer");
- return qfalse;
- }
- //if in the intermission
- if (BotIntermission(bs)) {
- AIEnter_Intermission(bs, "battle retreat: intermission");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- AIEnter_Respawn(bs, "battle retreat: bot dead");
- return qfalse;
- }
- //if no enemy
- if (bs->enemy < 0) {
- AIEnter_Seek_LTG(bs, "battle retreat: no enemy");
- return qfalse;
- }
- //
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityIsDead(&entinfo)) {
- AIEnter_Seek_LTG(bs, "battle retreat: enemy dead");
- return qfalse;
- }
- //if there is another better enemy
- if (BotFindEnemy(bs, bs->enemy)) {
-#ifdef DEBUG
- BotAI_Print(PRT_MESSAGE, "found new better enemy\n");
-#endif
- }
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- //if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- //map specific code
- BotMapScripts(bs);
- //update the attack inventory values
- BotUpdateBattleInventory(bs, bs->enemy);
- //if the bot doesn't want to retreat anymore... probably picked up some nice items
- if (BotWantsToChase(bs)) {
- //empty the goal stack, when chasing, only the enemy is the goal
- trap_BotEmptyGoalStack(bs->gs);
- //go chase the enemy
- AIEnter_Battle_Chase(bs, "battle retreat: wants to chase");
- return qfalse;
- }
- //update the last time the enemy was visible
- if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
- bs->enemyvisible_time = FloatTime();
- VectorCopy(entinfo.origin, target);
- // if not a player enemy
- if (bs->enemy >= MAX_CLIENTS) {
-#ifdef MISSIONPACK
- // if attacking an obelisk
- if ( bs->enemy == redobelisk.entitynum ||
- bs->enemy == blueobelisk.entitynum ) {
- target[2] += 16;
- }
-#endif
- }
- //update the reachability area and origin if possible
- areanum = BotPointAreaNum(target);
- if (areanum && trap_AAS_AreaReachability(areanum)) {
- VectorCopy(target, bs->lastenemyorigin);
- bs->lastenemyareanum = areanum;
- }
- }
- //if the enemy is NOT visible for 4 seconds
- if (bs->enemyvisible_time < FloatTime() - 4) {
- AIEnter_Seek_LTG(bs, "battle retreat: lost enemy");
- return qfalse;
- }
- //else if the enemy is NOT visible
- else if (bs->enemyvisible_time < FloatTime()) {
- //if there is another enemy
- if (BotFindEnemy(bs, -1)) {
- AIEnter_Battle_Fight(bs, "battle retreat: another enemy");
- return qfalse;
- }
- }
- //
- BotTeamGoals(bs, qtrue);
- //use holdable items
- BotBattleUseItems(bs);
- //get the current long term goal while retreating
- if (!BotLongTermGoal(bs, bs->tfl, qtrue, &goal)) {
- AIEnter_Battle_SuicidalFight(bs, "battle retreat: no way out");
- return qfalse;
- }
- //check for nearby goals periodicly
- if (bs->check_time < FloatTime()) {
- bs->check_time = FloatTime() + 1;
- range = 150;
-#ifdef CTF
- if (gametype == GT_CTF) {
- //if carrying a flag the bot shouldn't be distracted too much
- if (BotCTFCarryingFlag(bs))
- range = 50;
- }
-#endif //CTF
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- if (Bot1FCTFCarryingFlag(bs))
- range = 50;
- }
- else if (gametype == GT_HARVESTER) {
- if (BotHarvesterCarryingCubes(bs))
- range = 80;
- }
-#endif
- //
- if (BotNearbyGoal(bs, bs->tfl, &goal, range)) {
- trap_BotResetLastAvoidReach(bs->ms);
- //time the bot gets to pick up the nearby goal item
- bs->nbg_time = FloatTime() + range / 100 + 1;
- AIEnter_Battle_NBG(bs, "battle retreat: nbg");
- return qfalse;
- }
- }
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
- bs->ltg_time = 0;
- }
- //
- BotAIBlocked(bs, &moveresult, qfalse);
- //choose the best weapon to fight with
- BotChooseWeapon(bs);
- //if the view is fixed for the movement
- if (moveresult.flags & (MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
- VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
- }
- else if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET)
- && !(bs->flags & BFL_IDEALVIEWSET) ) {
- attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1);
- //if the bot is skilled anough
- if (attack_skill > 0.3) {
- BotAimAtEnemy(bs);
- }
- else {
- if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- }
- else {
- vectoangles(moveresult.movedir, bs->ideal_viewangles);
- }
- bs->ideal_viewangles[2] *= 0.5;
- }
- }
- //if the weapon is used for the bot movement
- if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
- //attack the enemy if possible
- BotCheckAttack(bs);
- //
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Battle_NBG
-==================
-*/
-void AIEnter_Battle_NBG(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "battle NBG", "", s);
- bs->ainode = AINode_Battle_NBG;
-}
-
-/*
-==================
-AINode_Battle_NBG
-==================
-*/
-int AINode_Battle_NBG(bot_state_t *bs) {
- int areanum;
- bot_goal_t goal;
- aas_entityinfo_t entinfo;
- bot_moveresult_t moveresult;
- float attack_skill;
- vec3_t target, dir;
-
- if (BotIsObserver(bs)) {
- AIEnter_Observer(bs, "battle nbg: observer");
- return qfalse;
- }
- //if in the intermission
- if (BotIntermission(bs)) {
- AIEnter_Intermission(bs, "battle nbg: intermission");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- AIEnter_Respawn(bs, "battle nbg: bot dead");
- return qfalse;
- }
- //if no enemy
- if (bs->enemy < 0) {
- AIEnter_Seek_NBG(bs, "battle nbg: no enemy");
- return qfalse;
- }
- //
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityIsDead(&entinfo)) {
- AIEnter_Seek_NBG(bs, "battle nbg: enemy dead");
- return qfalse;
- }
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- //if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- //
- if (BotCanAndWantsToRocketJump(bs)) {
- bs->tfl |= TFL_ROCKETJUMP;
- }
- //map specific code
- BotMapScripts(bs);
- //update the last time the enemy was visible
- if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
- bs->enemyvisible_time = FloatTime();
- VectorCopy(entinfo.origin, target);
- // if not a player enemy
- if (bs->enemy >= MAX_CLIENTS) {
-#ifdef MISSIONPACK
- // if attacking an obelisk
- if ( bs->enemy == redobelisk.entitynum ||
- bs->enemy == blueobelisk.entitynum ) {
- target[2] += 16;
- }
-#endif
- }
- //update the reachability area and origin if possible
- areanum = BotPointAreaNum(target);
- if (areanum && trap_AAS_AreaReachability(areanum)) {
- VectorCopy(target, bs->lastenemyorigin);
- bs->lastenemyareanum = areanum;
- }
- }
- //if the bot has no goal or touches the current goal
- if (!trap_BotGetTopGoal(bs->gs, &goal)) {
- bs->nbg_time = 0;
- }
- else if (BotReachedGoal(bs, &goal)) {
- bs->nbg_time = 0;
- }
- //
- if (bs->nbg_time < FloatTime()) {
- //pop the current goal from the stack
- trap_BotPopGoal(bs->gs);
- //if the bot still has a goal
- if (trap_BotGetTopGoal(bs->gs, &goal))
- AIEnter_Battle_Retreat(bs, "battle nbg: time out");
- else
- AIEnter_Battle_Fight(bs, "battle nbg: time out");
- //
- return qfalse;
- }
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
- bs->nbg_time = 0;
- }
- //
- BotAIBlocked(bs, &moveresult, qfalse);
- //update the attack inventory values
- BotUpdateBattleInventory(bs, bs->enemy);
- //choose the best weapon to fight with
- BotChooseWeapon(bs);
- //if the view is fixed for the movement
- if (moveresult.flags & (MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
- VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
- }
- else if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET)
- && !(bs->flags & BFL_IDEALVIEWSET)) {
- attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1);
- //if the bot is skilled anough and the enemy is visible
- if (attack_skill > 0.3) {
- //&& BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)
- BotAimAtEnemy(bs);
- }
- else {
- if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- }
- else {
- vectoangles(moveresult.movedir, bs->ideal_viewangles);
- }
- bs->ideal_viewangles[2] *= 0.5;
- }
- }
- //if the weapon is used for the bot movement
- if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
- //attack the enemy if possible
- BotCheckAttack(bs);
- //
- return qtrue;
-}
-
diff --git a/engine/code/game/ai_dmq3.c b/engine/code/game/ai_dmq3.c
deleted file mode 100644
index 894e295..0000000
--- a/engine/code/game/ai_dmq3.c
+++ /dev/null
@@ -1,5460 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_dmq3.c
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /MissionPack/code/game/ai_dmq3.c $
- *
- *****************************************************************************/
-
-
-#include "g_local.h"
-#include "../botlib/botlib.h"
-#include "../botlib/be_aas.h"
-#include "../botlib/be_ea.h"
-#include "../botlib/be_ai_char.h"
-#include "../botlib/be_ai_chat.h"
-#include "../botlib/be_ai_gen.h"
-#include "../botlib/be_ai_goal.h"
-#include "../botlib/be_ai_move.h"
-#include "../botlib/be_ai_weap.h"
-//
-#include "ai_main.h"
-#include "ai_dmq3.h"
-#include "ai_chat.h"
-#include "ai_cmd.h"
-#include "ai_dmnet.h"
-#include "ai_team.h"
-//
-#include "chars.h" //characteristics
-#include "inv.h" //indexes into the inventory
-#include "syn.h" //synonyms
-#include "match.h" //string matching types and vars
-
-// for the voice chats
-#include "../../ui/menudef.h" // sos001205 - for q3_ui also
-
-// from aasfile.h
-#define AREACONTENTS_MOVER 1024
-#define AREACONTENTS_MODELNUMSHIFT 24
-#define AREACONTENTS_MAXMODELNUM 0xFF
-#define AREACONTENTS_MODELNUM (AREACONTENTS_MAXMODELNUM << AREACONTENTS_MODELNUMSHIFT)
-
-#define IDEAL_ATTACKDIST 140
-
-#define MAX_WAYPOINTS 128
-//
-bot_waypoint_t botai_waypoints[MAX_WAYPOINTS];
-bot_waypoint_t *botai_freewaypoints;
-
-//NOTE: not using a cvars which can be updated because the game should be reloaded anyway
-int gametype; //game type
-int maxclients; //maximum number of clients
-
-vmCvar_t bot_grapple;
-vmCvar_t bot_rocketjump;
-vmCvar_t bot_fastchat;
-vmCvar_t bot_nochat;
-vmCvar_t bot_testrchat;
-vmCvar_t bot_challenge;
-vmCvar_t bot_predictobstacles;
-vmCvar_t g_spSkill;
-
-extern vmCvar_t bot_developer;
-
-vec3_t lastteleport_origin; //last teleport event origin
-float lastteleport_time; //last teleport event time
-int max_bspmodelindex; //maximum BSP model index
-
-//CTF flag goals
-bot_goal_t ctf_redflag;
-bot_goal_t ctf_blueflag;
-#ifdef MISSIONPACK
-bot_goal_t ctf_neutralflag;
-bot_goal_t redobelisk;
-bot_goal_t blueobelisk;
-bot_goal_t neutralobelisk;
-#endif
-
-#define MAX_ALTROUTEGOALS 32
-
-int altroutegoals_setup;
-aas_altroutegoal_t red_altroutegoals[MAX_ALTROUTEGOALS];
-int red_numaltroutegoals;
-aas_altroutegoal_t blue_altroutegoals[MAX_ALTROUTEGOALS];
-int blue_numaltroutegoals;
-
-
-/*
-==================
-BotSetUserInfo
-==================
-*/
-void BotSetUserInfo(bot_state_t *bs, char *key, char *value) {
- char userinfo[MAX_INFO_STRING];
-
- trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo));
- Info_SetValueForKey(userinfo, key, value);
- trap_SetUserinfo(bs->client, userinfo);
- ClientUserinfoChanged( bs->client );
-}
-
-/*
-==================
-BotCTFCarryingFlag
-==================
-*/
-int BotCTFCarryingFlag(bot_state_t *bs) {
- if (gametype != GT_CTF) return CTF_FLAG_NONE;
-
- if (bs->inventory[INVENTORY_REDFLAG] > 0) return CTF_FLAG_RED;
- else if (bs->inventory[INVENTORY_BLUEFLAG] > 0) return CTF_FLAG_BLUE;
- return CTF_FLAG_NONE;
-}
-
-/*
-==================
-BotTeam
-==================
-*/
-int BotTeam(bot_state_t *bs) {
- char info[1024];
-
- if (bs->client < 0 || bs->client >= MAX_CLIENTS) {
- //BotAI_Print(PRT_ERROR, "BotCTFTeam: client out of range\n");
- return qfalse;
- }
- trap_GetConfigstring(CS_PLAYERS+bs->client, info, sizeof(info));
- //
- if (atoi(Info_ValueForKey(info, "t")) == TEAM_RED) return TEAM_RED;
- else if (atoi(Info_ValueForKey(info, "t")) == TEAM_BLUE) return TEAM_BLUE;
- return TEAM_FREE;
-}
-
-/*
-==================
-BotOppositeTeam
-==================
-*/
-int BotOppositeTeam(bot_state_t *bs) {
- switch(BotTeam(bs)) {
- case TEAM_RED: return TEAM_BLUE;
- case TEAM_BLUE: return TEAM_RED;
- default: return TEAM_FREE;
- }
-}
-
-/*
-==================
-BotEnemyFlag
-==================
-*/
-bot_goal_t *BotEnemyFlag(bot_state_t *bs) {
- if (BotTeam(bs) == TEAM_RED) {
- return &ctf_blueflag;
- }
- else {
- return &ctf_redflag;
- }
-}
-
-/*
-==================
-BotTeamFlag
-==================
-*/
-bot_goal_t *BotTeamFlag(bot_state_t *bs) {
- if (BotTeam(bs) == TEAM_RED) {
- return &ctf_redflag;
- }
- else {
- return &ctf_blueflag;
- }
-}
-
-
-/*
-==================
-EntityIsDead
-==================
-*/
-qboolean EntityIsDead(aas_entityinfo_t *entinfo) {
- playerState_t ps;
-
- if (entinfo->number >= 0 && entinfo->number < MAX_CLIENTS) {
- //retrieve the current client state
- BotAI_GetClientState( entinfo->number, &ps );
- if (ps.pm_type != PM_NORMAL) return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-EntityCarriesFlag
-==================
-*/
-qboolean EntityCarriesFlag(aas_entityinfo_t *entinfo) {
- if ( entinfo->powerups & ( 1 << PW_REDFLAG ) )
- return qtrue;
- if ( entinfo->powerups & ( 1 << PW_BLUEFLAG ) )
- return qtrue;
-#ifdef MISSIONPACK
- if ( entinfo->powerups & ( 1 << PW_NEUTRALFLAG ) )
- return qtrue;
-#endif
- return qfalse;
-}
-
-/*
-==================
-EntityIsInvisible
-==================
-*/
-qboolean EntityIsInvisible(aas_entityinfo_t *entinfo) {
- // the flag is always visible
- if (EntityCarriesFlag(entinfo)) {
- return qfalse;
- }
- if (entinfo->powerups & (1 << PW_INVIS)) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-EntityIsShooting
-==================
-*/
-qboolean EntityIsShooting(aas_entityinfo_t *entinfo) {
- if (entinfo->flags & EF_FIRING) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-EntityIsChatting
-==================
-*/
-qboolean EntityIsChatting(aas_entityinfo_t *entinfo) {
- if (entinfo->flags & EF_TALK) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-EntityHasQuad
-==================
-*/
-qboolean EntityHasQuad(aas_entityinfo_t *entinfo) {
- if (entinfo->powerups & (1 << PW_QUAD)) {
- return qtrue;
- }
- return qfalse;
-}
-
-#ifdef MISSIONPACK
-/*
-==================
-EntityHasKamikze
-==================
-*/
-qboolean EntityHasKamikaze(aas_entityinfo_t *entinfo) {
- if (entinfo->flags & EF_KAMIKAZE) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-EntityCarriesCubes
-==================
-*/
-qboolean EntityCarriesCubes(aas_entityinfo_t *entinfo) {
- entityState_t state;
-
- if (gametype != GT_HARVESTER)
- return qfalse;
- //FIXME: get this info from the aas_entityinfo_t ?
- BotAI_GetEntityState(entinfo->number, &state);
- if (state.generic1 > 0)
- return qtrue;
- return qfalse;
-}
-
-/*
-==================
-Bot1FCTFCarryingFlag
-==================
-*/
-int Bot1FCTFCarryingFlag(bot_state_t *bs) {
- if (gametype != GT_1FCTF) return qfalse;
-
- if (bs->inventory[INVENTORY_NEUTRALFLAG] > 0) return qtrue;
- return qfalse;
-}
-
-/*
-==================
-BotHarvesterCarryingCubes
-==================
-*/
-int BotHarvesterCarryingCubes(bot_state_t *bs) {
- if (gametype != GT_HARVESTER) return qfalse;
-
- if (bs->inventory[INVENTORY_REDCUBE] > 0) return qtrue;
- if (bs->inventory[INVENTORY_BLUECUBE] > 0) return qtrue;
- return qfalse;
-}
-#endif
-
-/*
-==================
-BotRememberLastOrderedTask
-==================
-*/
-void BotRememberLastOrderedTask(bot_state_t *bs) {
- if (!bs->ordered) {
- return;
- }
- bs->lastgoal_decisionmaker = bs->decisionmaker;
- bs->lastgoal_ltgtype = bs->ltgtype;
- memcpy(&bs->lastgoal_teamgoal, &bs->teamgoal, sizeof(bot_goal_t));
- bs->lastgoal_teammate = bs->teammate;
-}
-
-/*
-==================
-BotSetTeamStatus
-==================
-*/
-void BotSetTeamStatus(bot_state_t *bs) {
-#ifdef MISSIONPACK
- int teamtask;
- aas_entityinfo_t entinfo;
-
- teamtask = TEAMTASK_PATROL;
-
- switch(bs->ltgtype) {
- case LTG_TEAMHELP:
- break;
- case LTG_TEAMACCOMPANY:
- BotEntityInfo(bs->teammate, &entinfo);
- if ( ( (gametype == GT_CTF || gametype == GT_1FCTF) && EntityCarriesFlag(&entinfo))
- || ( gametype == GT_HARVESTER && EntityCarriesCubes(&entinfo)) ) {
- teamtask = TEAMTASK_ESCORT;
- }
- else {
- teamtask = TEAMTASK_FOLLOW;
- }
- break;
- case LTG_DEFENDKEYAREA:
- teamtask = TEAMTASK_DEFENSE;
- break;
- case LTG_GETFLAG:
- teamtask = TEAMTASK_OFFENSE;
- break;
- case LTG_RUSHBASE:
- teamtask = TEAMTASK_DEFENSE;
- break;
- case LTG_RETURNFLAG:
- teamtask = TEAMTASK_RETRIEVE;
- break;
- case LTG_CAMP:
- case LTG_CAMPORDER:
- teamtask = TEAMTASK_CAMP;
- break;
- case LTG_PATROL:
- teamtask = TEAMTASK_PATROL;
- break;
- case LTG_GETITEM:
- teamtask = TEAMTASK_PATROL;
- break;
- case LTG_KILL:
- teamtask = TEAMTASK_PATROL;
- break;
- case LTG_HARVEST:
- teamtask = TEAMTASK_OFFENSE;
- break;
- case LTG_ATTACKENEMYBASE:
- teamtask = TEAMTASK_OFFENSE;
- break;
- default:
- teamtask = TEAMTASK_PATROL;
- break;
- }
- BotSetUserInfo(bs, "teamtask", va("%d", teamtask));
-#endif
-}
-
-/*
-==================
-BotSetLastOrderedTask
-==================
-*/
-int BotSetLastOrderedTask(bot_state_t *bs) {
-
- if (gametype == GT_CTF) {
- // don't go back to returning the flag if it's at the base
- if ( bs->lastgoal_ltgtype == LTG_RETURNFLAG ) {
- if ( BotTeam(bs) == TEAM_RED ) {
- if ( bs->redflagstatus == 0 ) {
- bs->lastgoal_ltgtype = 0;
- }
- }
- else {
- if ( bs->blueflagstatus == 0 ) {
- bs->lastgoal_ltgtype = 0;
- }
- }
- }
- }
-
- if ( bs->lastgoal_ltgtype ) {
- bs->decisionmaker = bs->lastgoal_decisionmaker;
- bs->ordered = qtrue;
- bs->ltgtype = bs->lastgoal_ltgtype;
- memcpy(&bs->teamgoal, &bs->lastgoal_teamgoal, sizeof(bot_goal_t));
- bs->teammate = bs->lastgoal_teammate;
- bs->teamgoal_time = FloatTime() + 300;
- BotSetTeamStatus(bs);
- //
- if ( gametype == GT_CTF ) {
- if ( bs->ltgtype == LTG_GETFLAG ) {
- bot_goal_t *tb, *eb;
- int tt, et;
-
- tb = BotTeamFlag(bs);
- eb = BotEnemyFlag(bs);
- tt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, tb->areanum, TFL_DEFAULT);
- et = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, eb->areanum, TFL_DEFAULT);
- // if the travel time towards the enemy base is larger than towards our base
- if (et > tt) {
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- }
- }
- }
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-BotRefuseOrder
-==================
-*/
-void BotRefuseOrder(bot_state_t *bs) {
- if (!bs->ordered)
- return;
- // if the bot was ordered to do something
- if ( bs->order_time && bs->order_time > FloatTime() - 10 ) {
- trap_EA_Action(bs->client, ACTION_NEGATIVE);
- BotVoiceChat(bs, bs->decisionmaker, VOICECHAT_NO);
- bs->order_time = 0;
- }
-}
-
-/*
-==================
-BotCTFSeekGoals
-==================
-*/
-void BotCTFSeekGoals(bot_state_t *bs) {
- float rnd, l1, l2;
- int flagstatus, c;
- vec3_t dir;
- aas_entityinfo_t entinfo;
-
- //when carrying a flag in ctf the bot should rush to the base
- if (BotCTFCarryingFlag(bs)) {
- //if not already rushing to the base
- if (bs->ltgtype != LTG_RUSHBASE) {
- BotRefuseOrder(bs);
- bs->ltgtype = LTG_RUSHBASE;
- bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
- bs->rushbaseaway_time = 0;
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- switch(BotTeam(bs)) {
- case TEAM_RED: VectorSubtract(bs->origin, ctf_blueflag.origin, dir); break;
- case TEAM_BLUE: VectorSubtract(bs->origin, ctf_redflag.origin, dir); break;
- default: VectorSet(dir, 999, 999, 999); break;
- }
- // if the bot picked up the flag very close to the enemy base
- if ( VectorLength(dir) < 128 ) {
- // get an alternative route goal through the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- } else {
- // don't use any alt route goal, just get the hell out of the base
- bs->altroutegoal.areanum = 0;
- }
- BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_OFFENSE));
- BotVoiceChat(bs, -1, VOICECHAT_IHAVEFLAG);
- }
- else if (bs->rushbaseaway_time > FloatTime()) {
- if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus;
- else flagstatus = bs->blueflagstatus;
- //if the flag is back
- if (flagstatus == 0) {
- bs->rushbaseaway_time = 0;
- }
- }
- return;
- }
- // if the bot decided to follow someone
- if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) {
- // if the team mate being accompanied no longer carries the flag
- BotEntityInfo(bs->teammate, &entinfo);
- if (!EntityCarriesFlag(&entinfo)) {
- bs->ltgtype = 0;
- }
- }
- //
- if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus;
- else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus;
- //if our team has the enemy flag and our flag is at the base
- if (flagstatus == 1) {
- //
- if (bs->owndecision_time < FloatTime()) {
- //if Not defending the base already
- if (!(bs->ltgtype == LTG_DEFENDKEYAREA &&
- (bs->teamgoal.number == ctf_redflag.number ||
- bs->teamgoal.number == ctf_blueflag.number))) {
- //if there is a visible team mate flag carrier
- c = BotTeamFlagCarrierVisible(bs);
- if (c >= 0 &&
- // and not already following the team mate flag carrier
- (bs->ltgtype != LTG_TEAMACCOMPANY || bs->teammate != c)) {
- //
- BotRefuseOrder(bs);
- //follow the flag carrier
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //the team mate
- bs->teammate = c;
- //last time the team mate was visible
- bs->teammatevisible_time = FloatTime();
- //no message
- bs->teammessage_time = 0;
- //no arrive message
- bs->arrive_time = 1;
- //
- BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
- //get the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
- bs->ltgtype = LTG_TEAMACCOMPANY;
- bs->formation_dist = 3.5 * 32; //3.5 meter
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- }
- }
- }
- return;
- }
- //if the enemy has our flag
- else if (flagstatus == 2) {
- //
- if (bs->owndecision_time < FloatTime()) {
- //if enemy flag carrier is visible
- c = BotEnemyFlagCarrierVisible(bs);
- if (c >= 0) {
- //FIXME: fight enemy flag carrier
- }
- //if not already doing something important
- if (bs->ltgtype != LTG_GETFLAG &&
- bs->ltgtype != LTG_RETURNFLAG &&
- bs->ltgtype != LTG_TEAMHELP &&
- bs->ltgtype != LTG_TEAMACCOMPANY &&
- bs->ltgtype != LTG_CAMPORDER &&
- bs->ltgtype != LTG_PATROL &&
- bs->ltgtype != LTG_GETITEM) {
-
- BotRefuseOrder(bs);
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (random() < 0.5) {
- //go for the enemy flag
- bs->ltgtype = LTG_GETFLAG;
- }
- else {
- bs->ltgtype = LTG_RETURNFLAG;
- }
- //no team message
- bs->teammessage_time = 0;
- //set the time the bot will stop getting the flag
- bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- //
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- }
- }
- return;
- }
- //if both flags Not at their bases
- else if (flagstatus == 3) {
- //
- if (bs->owndecision_time < FloatTime()) {
- // if not trying to return the flag and not following the team flag carrier
- if ( bs->ltgtype != LTG_RETURNFLAG && bs->ltgtype != LTG_TEAMACCOMPANY ) {
- //
- c = BotTeamFlagCarrierVisible(bs);
- // if there is a visible team mate flag carrier
- if (c >= 0) {
- BotRefuseOrder(bs);
- //follow the flag carrier
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //the team mate
- bs->teammate = c;
- //last time the team mate was visible
- bs->teammatevisible_time = FloatTime();
- //no message
- bs->teammessage_time = 0;
- //no arrive message
- bs->arrive_time = 1;
- //
- BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
- //get the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
- bs->ltgtype = LTG_TEAMACCOMPANY;
- bs->formation_dist = 3.5 * 32; //3.5 meter
- //
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- }
- else {
- BotRefuseOrder(bs);
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //get the enemy flag
- bs->teammessage_time = FloatTime() + 2 * random();
- //get the flag
- bs->ltgtype = LTG_RETURNFLAG;
- //set the time the bot will stop getting the flag
- bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME;
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- //
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- }
- }
- }
- return;
- }
- // don't just do something wait for the bot team leader to give orders
- if (BotTeamLeader(bs)) {
- return;
- }
- // if the bot is ordered to do something
- if ( bs->lastgoal_ltgtype ) {
- bs->teamgoal_time += 60;
- }
- // if the bot decided to do something on it's own and has a last ordered goal
- if ( !bs->ordered && bs->lastgoal_ltgtype ) {
- bs->ltgtype = 0;
- }
- //if already a CTF or team goal
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_DEFENDKEYAREA ||
- bs->ltgtype == LTG_GETFLAG ||
- bs->ltgtype == LTG_RUSHBASE ||
- bs->ltgtype == LTG_RETURNFLAG ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL ||
- bs->ltgtype == LTG_GETITEM ||
- bs->ltgtype == LTG_MAKELOVE_UNDER ||
- bs->ltgtype == LTG_MAKELOVE_ONTOP) {
- return;
- }
- //
- if (BotSetLastOrderedTask(bs))
- return;
- //
- if (bs->owndecision_time > FloatTime())
- return;;
- //if the bot is roaming
- if (bs->ctfroam_time > FloatTime())
- return;
- //if the bot has anough aggression to decide what to do
- if (BotAggression(bs) < 50)
- return;
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //
- if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
- if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
- l1 = 0.7f;
- }
- else {
- l1 = 0.2f;
- }
- l2 = 0.9f;
- }
- else {
- l1 = 0.4f;
- l2 = 0.7f;
- }
- //get the flag or defend the base
- rnd = random();
- if (rnd < l1 && ctf_redflag.areanum && ctf_blueflag.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- bs->ltgtype = LTG_GETFLAG;
- //set the time the bot will stop getting the flag
- bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- BotSetTeamStatus(bs);
- }
- else if (rnd < l2 && ctf_redflag.areanum && ctf_blueflag.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_DEFENDKEYAREA;
- //set the time the bot stops defending the base
- bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
- bs->defendaway_time = 0;
- BotSetTeamStatus(bs);
- }
- else {
- bs->ltgtype = 0;
- //set the time the bot will stop roaming
- bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
- BotSetTeamStatus(bs);
- }
- bs->owndecision_time = FloatTime() + 5;
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotCTFRetreatGoals
-==================
-*/
-void BotCTFRetreatGoals(bot_state_t *bs) {
- //when carrying a flag in ctf the bot should rush to the base
- if (BotCTFCarryingFlag(bs)) {
- //if not already rushing to the base
- if (bs->ltgtype != LTG_RUSHBASE) {
- BotRefuseOrder(bs);
- bs->ltgtype = LTG_RUSHBASE;
- bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
- bs->rushbaseaway_time = 0;
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- BotSetTeamStatus(bs);
- }
- }
-}
-
-#ifdef MISSIONPACK
-/*
-==================
-Bot1FCTFSeekGoals
-==================
-*/
-void Bot1FCTFSeekGoals(bot_state_t *bs) {
- aas_entityinfo_t entinfo;
- float rnd, l1, l2;
- int c;
-
- //when carrying a flag in ctf the bot should rush to the base
- if (Bot1FCTFCarryingFlag(bs)) {
- //if not already rushing to the base
- if (bs->ltgtype != LTG_RUSHBASE) {
- BotRefuseOrder(bs);
- bs->ltgtype = LTG_RUSHBASE;
- bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
- bs->rushbaseaway_time = 0;
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- //
- BotSetTeamStatus(bs);
- BotVoiceChat(bs, -1, VOICECHAT_IHAVEFLAG);
- }
- return;
- }
- // if the bot decided to follow someone
- if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) {
- // if the team mate being accompanied no longer carries the flag
- BotEntityInfo(bs->teammate, &entinfo);
- if (!EntityCarriesFlag(&entinfo)) {
- bs->ltgtype = 0;
- }
- }
- //our team has the flag
- if (bs->neutralflagstatus == 1) {
- if (bs->owndecision_time < FloatTime()) {
- // if not already following someone
- if (bs->ltgtype != LTG_TEAMACCOMPANY) {
- //if there is a visible team mate flag carrier
- c = BotTeamFlagCarrierVisible(bs);
- if (c >= 0) {
- BotRefuseOrder(bs);
- //follow the flag carrier
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //the team mate
- bs->teammate = c;
- //last time the team mate was visible
- bs->teammatevisible_time = FloatTime();
- //no message
- bs->teammessage_time = 0;
- //no arrive message
- bs->arrive_time = 1;
- //
- BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
- //get the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
- bs->ltgtype = LTG_TEAMACCOMPANY;
- bs->formation_dist = 3.5 * 32; //3.5 meter
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- return;
- }
- }
- //if already a CTF or team goal
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_DEFENDKEYAREA ||
- bs->ltgtype == LTG_GETFLAG ||
- bs->ltgtype == LTG_RUSHBASE ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL ||
- bs->ltgtype == LTG_ATTACKENEMYBASE ||
- bs->ltgtype == LTG_GETITEM ||
- bs->ltgtype == LTG_MAKELOVE_UNDER ||
- bs->ltgtype == LTG_MAKELOVE_ONTOP) {
- return;
- }
- //if not already attacking the enemy base
- if (bs->ltgtype != LTG_ATTACKENEMYBASE) {
- BotRefuseOrder(bs);
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_ATTACKENEMYBASE;
- //set the time the bot will stop getting the flag
- bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- }
- }
- return;
- }
- //enemy team has the flag
- else if (bs->neutralflagstatus == 2) {
- if (bs->owndecision_time < FloatTime()) {
- c = BotEnemyFlagCarrierVisible(bs);
- if (c >= 0) {
- //FIXME: attack enemy flag carrier
- }
- //if already a CTF or team goal
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL ||
- bs->ltgtype == LTG_GETITEM) {
- return;
- }
- // if not already defending the base
- if (bs->ltgtype != LTG_DEFENDKEYAREA) {
- BotRefuseOrder(bs);
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_DEFENDKEYAREA;
- //set the time the bot stops defending the base
- bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
- bs->defendaway_time = 0;
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- }
- }
- return;
- }
- // don't just do something wait for the bot team leader to give orders
- if (BotTeamLeader(bs)) {
- return;
- }
- // if the bot is ordered to do something
- if ( bs->lastgoal_ltgtype ) {
- bs->teamgoal_time += 60;
- }
- // if the bot decided to do something on it's own and has a last ordered goal
- if ( !bs->ordered && bs->lastgoal_ltgtype ) {
- bs->ltgtype = 0;
- }
- //if already a CTF or team goal
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_DEFENDKEYAREA ||
- bs->ltgtype == LTG_GETFLAG ||
- bs->ltgtype == LTG_RUSHBASE ||
- bs->ltgtype == LTG_RETURNFLAG ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL ||
- bs->ltgtype == LTG_ATTACKENEMYBASE ||
- bs->ltgtype == LTG_GETITEM ||
- bs->ltgtype == LTG_MAKELOVE_UNDER ||
- bs->ltgtype == LTG_MAKELOVE_ONTOP) {
- return;
- }
- //
- if (BotSetLastOrderedTask(bs))
- return;
- //
- if (bs->owndecision_time > FloatTime())
- return;;
- //if the bot is roaming
- if (bs->ctfroam_time > FloatTime())
- return;
- //if the bot has anough aggression to decide what to do
- if (BotAggression(bs) < 50)
- return;
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //
- if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
- if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
- l1 = 0.7f;
- }
- else {
- l1 = 0.2f;
- }
- l2 = 0.9f;
- }
- else {
- l1 = 0.4f;
- l2 = 0.7f;
- }
- //get the flag or defend the base
- rnd = random();
- if (rnd < l1 && ctf_neutralflag.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- bs->ltgtype = LTG_GETFLAG;
- //set the time the bot will stop getting the flag
- bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
- BotSetTeamStatus(bs);
- }
- else if (rnd < l2 && ctf_redflag.areanum && ctf_blueflag.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_DEFENDKEYAREA;
- //set the time the bot stops defending the base
- bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
- bs->defendaway_time = 0;
- BotSetTeamStatus(bs);
- }
- else {
- bs->ltgtype = 0;
- //set the time the bot will stop roaming
- bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
- BotSetTeamStatus(bs);
- }
- bs->owndecision_time = FloatTime() + 5;
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-Bot1FCTFRetreatGoals
-==================
-*/
-void Bot1FCTFRetreatGoals(bot_state_t *bs) {
- //when carrying a flag in ctf the bot should rush to the enemy base
- if (Bot1FCTFCarryingFlag(bs)) {
- //if not already rushing to the base
- if (bs->ltgtype != LTG_RUSHBASE) {
- BotRefuseOrder(bs);
- bs->ltgtype = LTG_RUSHBASE;
- bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
- bs->rushbaseaway_time = 0;
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- BotSetTeamStatus(bs);
- }
- }
-}
-
-/*
-==================
-BotObeliskSeekGoals
-==================
-*/
-void BotObeliskSeekGoals(bot_state_t *bs) {
- float rnd, l1, l2;
-
- // don't just do something wait for the bot team leader to give orders
- if (BotTeamLeader(bs)) {
- return;
- }
- // if the bot is ordered to do something
- if ( bs->lastgoal_ltgtype ) {
- bs->teamgoal_time += 60;
- }
- //if already a team goal
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_DEFENDKEYAREA ||
- bs->ltgtype == LTG_GETFLAG ||
- bs->ltgtype == LTG_RUSHBASE ||
- bs->ltgtype == LTG_RETURNFLAG ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL ||
- bs->ltgtype == LTG_ATTACKENEMYBASE ||
- bs->ltgtype == LTG_GETITEM ||
- bs->ltgtype == LTG_MAKELOVE_UNDER ||
- bs->ltgtype == LTG_MAKELOVE_ONTOP) {
- return;
- }
- //
- if (BotSetLastOrderedTask(bs))
- return;
- //if the bot is roaming
- if (bs->ctfroam_time > FloatTime())
- return;
- //if the bot has anough aggression to decide what to do
- if (BotAggression(bs) < 50)
- return;
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //
- if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
- if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
- l1 = 0.7f;
- }
- else {
- l1 = 0.2f;
- }
- l2 = 0.9f;
- }
- else {
- l1 = 0.4f;
- l2 = 0.7f;
- }
- //get the flag or defend the base
- rnd = random();
- if (rnd < l1 && redobelisk.areanum && blueobelisk.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_ATTACKENEMYBASE;
- //set the time the bot will stop attacking the enemy base
- bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
- //get an alternate route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- BotSetTeamStatus(bs);
- }
- else if (rnd < l2 && redobelisk.areanum && blueobelisk.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_DEFENDKEYAREA;
- //set the time the bot stops defending the base
- bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
- bs->defendaway_time = 0;
- BotSetTeamStatus(bs);
- }
- else {
- bs->ltgtype = 0;
- //set the time the bot will stop roaming
- bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
- BotSetTeamStatus(bs);
- }
-}
-
-/*
-==================
-BotGoHarvest
-==================
-*/
-void BotGoHarvest(bot_state_t *bs) {
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_HARVEST;
- //set the time the bot will stop harvesting
- bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME;
- bs->harvestaway_time = 0;
- BotSetTeamStatus(bs);
-}
-
-/*
-==================
-BotObeliskRetreatGoals
-==================
-*/
-void BotObeliskRetreatGoals(bot_state_t *bs) {
- //nothing special
-}
-
-/*
-==================
-BotHarvesterSeekGoals
-==================
-*/
-void BotHarvesterSeekGoals(bot_state_t *bs) {
- aas_entityinfo_t entinfo;
- float rnd, l1, l2;
- int c;
-
- //when carrying cubes in harvester the bot should rush to the base
- if (BotHarvesterCarryingCubes(bs)) {
- //if not already rushing to the base
- if (bs->ltgtype != LTG_RUSHBASE) {
- BotRefuseOrder(bs);
- bs->ltgtype = LTG_RUSHBASE;
- bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
- bs->rushbaseaway_time = 0;
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- //
- BotSetTeamStatus(bs);
- }
- return;
- }
- // don't just do something wait for the bot team leader to give orders
- if (BotTeamLeader(bs)) {
- return;
- }
- // if the bot decided to follow someone
- if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) {
- // if the team mate being accompanied no longer carries the flag
- BotEntityInfo(bs->teammate, &entinfo);
- if (!EntityCarriesCubes(&entinfo)) {
- bs->ltgtype = 0;
- }
- }
- // if the bot is ordered to do something
- if ( bs->lastgoal_ltgtype ) {
- bs->teamgoal_time += 60;
- }
- //if not yet doing something
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_DEFENDKEYAREA ||
- bs->ltgtype == LTG_GETFLAG ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL ||
- bs->ltgtype == LTG_ATTACKENEMYBASE ||
- bs->ltgtype == LTG_HARVEST ||
- bs->ltgtype == LTG_GETITEM ||
- bs->ltgtype == LTG_MAKELOVE_UNDER ||
- bs->ltgtype == LTG_MAKELOVE_ONTOP) {
- return;
- }
- //
- if (BotSetLastOrderedTask(bs))
- return;
- //if the bot is roaming
- if (bs->ctfroam_time > FloatTime())
- return;
- //if the bot has anough aggression to decide what to do
- if (BotAggression(bs) < 50)
- return;
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //
- c = BotEnemyCubeCarrierVisible(bs);
- if (c >= 0) {
- //FIXME: attack enemy cube carrier
- }
- if (bs->ltgtype != LTG_TEAMACCOMPANY) {
- //if there is a visible team mate carrying cubes
- c = BotTeamCubeCarrierVisible(bs);
- if (c >= 0) {
- //follow the team mate carrying cubes
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //the team mate
- bs->teammate = c;
- //last time the team mate was visible
- bs->teammatevisible_time = FloatTime();
- //no message
- bs->teammessage_time = 0;
- //no arrive message
- bs->arrive_time = 1;
- //
- BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
- //get the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
- bs->ltgtype = LTG_TEAMACCOMPANY;
- bs->formation_dist = 3.5 * 32; //3.5 meter
- BotSetTeamStatus(bs);
- return;
- }
- }
- //
- if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
- if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
- l1 = 0.7f;
- }
- else {
- l1 = 0.2f;
- }
- l2 = 0.9f;
- }
- else {
- l1 = 0.4f;
- l2 = 0.7f;
- }
- //
- rnd = random();
- if (rnd < l1 && redobelisk.areanum && blueobelisk.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- BotGoHarvest(bs);
- }
- else if (rnd < l2 && redobelisk.areanum && blueobelisk.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_DEFENDKEYAREA;
- //set the time the bot stops defending the base
- bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
- bs->defendaway_time = 0;
- BotSetTeamStatus(bs);
- }
- else {
- bs->ltgtype = 0;
- //set the time the bot will stop roaming
- bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
- BotSetTeamStatus(bs);
- }
-}
-
-/*
-==================
-BotHarvesterRetreatGoals
-==================
-*/
-void BotHarvesterRetreatGoals(bot_state_t *bs) {
- //when carrying cubes in harvester the bot should rush to the base
- if (BotHarvesterCarryingCubes(bs)) {
- //if not already rushing to the base
- if (bs->ltgtype != LTG_RUSHBASE) {
- BotRefuseOrder(bs);
- bs->ltgtype = LTG_RUSHBASE;
- bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
- bs->rushbaseaway_time = 0;
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- BotSetTeamStatus(bs);
- }
- return;
- }
-}
-#endif
-
-/*
-==================
-BotTeamGoals
-==================
-*/
-void BotTeamGoals(bot_state_t *bs, int retreat) {
-
- if ( retreat ) {
- if (gametype == GT_CTF) {
- BotCTFRetreatGoals(bs);
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- Bot1FCTFRetreatGoals(bs);
- }
- else if (gametype == GT_OBELISK) {
- BotObeliskRetreatGoals(bs);
- }
- else if (gametype == GT_HARVESTER) {
- BotHarvesterRetreatGoals(bs);
- }
-#endif
- }
- else {
- if (gametype == GT_CTF) {
- //decide what to do in CTF mode
- BotCTFSeekGoals(bs);
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- Bot1FCTFSeekGoals(bs);
- }
- else if (gametype == GT_OBELISK) {
- BotObeliskSeekGoals(bs);
- }
- else if (gametype == GT_HARVESTER) {
- BotHarvesterSeekGoals(bs);
- }
-#endif
- }
- // reset the order time which is used to see if
- // we decided to refuse an order
- bs->order_time = 0;
-}
-
-/*
-==================
-BotPointAreaNum
-==================
-*/
-int BotPointAreaNum(vec3_t origin) {
- int areanum, numareas, areas[10];
- vec3_t end;
-
- areanum = trap_AAS_PointAreaNum(origin);
- if (areanum) return areanum;
- VectorCopy(origin, end);
- end[2] += 10;
- numareas = trap_AAS_TraceAreas(origin, end, areas, NULL, 10);
- if (numareas > 0) return areas[0];
- return 0;
-}
-
-/*
-==================
-ClientName
-==================
-*/
-char *ClientName(int client, char *name, int size) {
- char buf[MAX_INFO_STRING];
-
- if (client < 0 || client >= MAX_CLIENTS) {
- BotAI_Print(PRT_ERROR, "ClientName: client out of range\n");
- return "[client out of range]";
- }
- trap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf));
- strncpy(name, Info_ValueForKey(buf, "n"), size-1);
- name[size-1] = '\0';
- Q_CleanStr( name );
- return name;
-}
-
-/*
-==================
-ClientSkin
-==================
-*/
-char *ClientSkin(int client, char *skin, int size) {
- char buf[MAX_INFO_STRING];
-
- if (client < 0 || client >= MAX_CLIENTS) {
- BotAI_Print(PRT_ERROR, "ClientSkin: client out of range\n");
- return "[client out of range]";
- }
- trap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf));
- strncpy(skin, Info_ValueForKey(buf, "model"), size-1);
- skin[size-1] = '\0';
- return skin;
-}
-
-/*
-==================
-ClientFromName
-==================
-*/
-int ClientFromName(char *name) {
- int i;
- char buf[MAX_INFO_STRING];
- static int maxclients;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- Q_CleanStr( buf );
- if (!Q_stricmp(Info_ValueForKey(buf, "n"), name)) return i;
- }
- return -1;
-}
-
-/*
-==================
-ClientOnSameTeamFromName
-==================
-*/
-int ClientOnSameTeamFromName(bot_state_t *bs, char *name) {
- int i;
- char buf[MAX_INFO_STRING];
- static int maxclients;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (!BotSameTeam(bs, i))
- continue;
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- Q_CleanStr( buf );
- if (!Q_stricmp(Info_ValueForKey(buf, "n"), name)) return i;
- }
- return -1;
-}
-
-/*
-==================
-stristr
-==================
-*/
-char *stristr(char *str, char *charset) {
- int i;
-
- while(*str) {
- for (i = 0; charset[i] && str[i]; i++) {
- if (toupper(charset[i]) != toupper(str[i])) break;
- }
- if (!charset[i]) return str;
- str++;
- }
- return NULL;
-}
-
-/*
-==================
-EasyClientName
-==================
-*/
-char *EasyClientName(int client, char *buf, int size) {
- int i;
- char *str1, *str2, *ptr, c;
- char name[128];
-
- strcpy(name, ClientName(client, name, sizeof(name)));
- for (i = 0; name[i]; i++) name[i] &= 127;
- //remove all spaces
- for (ptr = strstr(name, " "); ptr; ptr = strstr(name, " ")) {
- memmove(ptr, ptr+1, strlen(ptr+1)+1);
- }
- //check for [x] and ]x[ clan names
- str1 = strstr(name, "[");
- str2 = strstr(name, "]");
- if (str1 && str2) {
- if (str2 > str1) memmove(str1, str2+1, strlen(str2+1)+1);
- else memmove(str2, str1+1, strlen(str1+1)+1);
- }
- //remove Mr prefix
- if ((name[0] == 'm' || name[0] == 'M') &&
- (name[1] == 'r' || name[1] == 'R')) {
- memmove(name, name+2, strlen(name+2)+1);
- }
- //only allow lower case alphabet characters
- ptr = name;
- while(*ptr) {
- c = *ptr;
- if ((c >= 'a' && c <= 'z') ||
- (c >= '0' && c <= '9') || c == '_') {
- ptr++;
- }
- else if (c >= 'A' && c <= 'Z') {
- *ptr += 'a' - 'A';
- ptr++;
- }
- else {
- memmove(ptr, ptr+1, strlen(ptr + 1)+1);
- }
- }
- strncpy(buf, name, size-1);
- buf[size-1] = '\0';
- return buf;
-}
-
-/*
-==================
-BotSynonymContext
-==================
-*/
-int BotSynonymContext(bot_state_t *bs) {
- int context;
-
- context = CONTEXT_NORMAL|CONTEXT_NEARBYITEM|CONTEXT_NAMES;
- //
- if (gametype == GT_CTF
-#ifdef MISSIONPACK
- || gametype == GT_1FCTF
-#endif
- ) {
- if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_CTFREDTEAM;
- else context |= CONTEXT_CTFBLUETEAM;
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_OBELISK) {
- if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_OBELISKREDTEAM;
- else context |= CONTEXT_OBELISKBLUETEAM;
- }
- else if (gametype == GT_HARVESTER) {
- if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_HARVESTERREDTEAM;
- else context |= CONTEXT_HARVESTERBLUETEAM;
- }
-#endif
- return context;
-}
-
-/*
-==================
-BotChooseWeapon
-==================
-*/
-void BotChooseWeapon(bot_state_t *bs) {
- int newweaponnum;
-
- if (bs->cur_ps.weaponstate == WEAPON_RAISING ||
- bs->cur_ps.weaponstate == WEAPON_DROPPING) {
- trap_EA_SelectWeapon(bs->client, bs->weaponnum);
- }
- else {
- newweaponnum = trap_BotChooseBestFightWeapon(bs->ws, bs->inventory);
- if (bs->weaponnum != newweaponnum) bs->weaponchange_time = FloatTime();
- bs->weaponnum = newweaponnum;
- //BotAI_Print(PRT_MESSAGE, "bs->weaponnum = %d\n", bs->weaponnum);
- trap_EA_SelectWeapon(bs->client, bs->weaponnum);
- }
-}
-
-/*
-==================
-BotSetupForMovement
-==================
-*/
-void BotSetupForMovement(bot_state_t *bs) {
- bot_initmove_t initmove;
-
- memset(&initmove, 0, sizeof(bot_initmove_t));
- VectorCopy(bs->cur_ps.origin, initmove.origin);
- VectorCopy(bs->cur_ps.velocity, initmove.velocity);
- VectorClear(initmove.viewoffset);
- initmove.viewoffset[2] += bs->cur_ps.viewheight;
- initmove.entitynum = bs->entitynum;
- initmove.client = bs->client;
- initmove.thinktime = bs->thinktime;
- //set the onground flag
- if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) initmove.or_moveflags |= MFL_ONGROUND;
- //set the teleported flag
- if ((bs->cur_ps.pm_flags & PMF_TIME_KNOCKBACK) && (bs->cur_ps.pm_time > 0)) {
- initmove.or_moveflags |= MFL_TELEPORTED;
- }
- //set the waterjump flag
- if ((bs->cur_ps.pm_flags & PMF_TIME_WATERJUMP) && (bs->cur_ps.pm_time > 0)) {
- initmove.or_moveflags |= MFL_WATERJUMP;
- }
- //set presence type
- if (bs->cur_ps.pm_flags & PMF_DUCKED) initmove.presencetype = PRESENCE_CROUCH;
- else initmove.presencetype = PRESENCE_NORMAL;
- //
- if (bs->walker > 0.5) initmove.or_moveflags |= MFL_WALK;
- //
- VectorCopy(bs->viewangles, initmove.viewangles);
- //
- trap_BotInitMoveState(bs->ms, &initmove);
-}
-
-/*
-==================
-BotCheckItemPickup
-==================
-*/
-void BotCheckItemPickup(bot_state_t *bs, int *oldinventory) {
-#ifdef MISSIONPACK
- int offence, leader;
-
- if (gametype <= GT_TEAM)
- return;
-
- offence = -1;
- // go into offence if picked up the kamikaze or invulnerability
- if (!oldinventory[INVENTORY_KAMIKAZE] && bs->inventory[INVENTORY_KAMIKAZE] >= 1) {
- offence = qtrue;
- }
- if (!oldinventory[INVENTORY_INVULNERABILITY] && bs->inventory[INVENTORY_INVULNERABILITY] >= 1) {
- offence = qtrue;
- }
- // if not already wearing the kamikaze or invulnerability
- if (!bs->inventory[INVENTORY_KAMIKAZE] && !bs->inventory[INVENTORY_INVULNERABILITY]) {
- if (!oldinventory[INVENTORY_SCOUT] && bs->inventory[INVENTORY_SCOUT] >= 1) {
- offence = qtrue;
- }
- if (!oldinventory[INVENTORY_GUARD] && bs->inventory[INVENTORY_GUARD] >= 1) {
- offence = qtrue;
- }
- if (!oldinventory[INVENTORY_DOUBLER] && bs->inventory[INVENTORY_DOUBLER] >= 1) {
- offence = qfalse;
- }
- if (!oldinventory[INVENTORY_AMMOREGEN] && bs->inventory[INVENTORY_AMMOREGEN] >= 1) {
- offence = qfalse;
- }
- }
-
- if (offence >= 0) {
- leader = ClientFromName(bs->teamleader);
- if (offence) {
- if (!(bs->teamtaskpreference & TEAMTP_ATTACKER)) {
- // if we have a bot team leader
- if (BotTeamLeader(bs)) {
- // tell the leader we want to be on offence
- BotVoiceChat(bs, leader, VOICECHAT_WANTONOFFENSE);
- //BotAI_BotInitialChat(bs, "wantoffence", NULL);
- //trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
- }
- else if (g_spSkill.integer <= 3) {
- if ( bs->ltgtype != LTG_GETFLAG &&
- bs->ltgtype != LTG_ATTACKENEMYBASE &&
- bs->ltgtype != LTG_HARVEST ) {
- //
- if ((gametype != GT_CTF || (bs->redflagstatus == 0 && bs->blueflagstatus == 0)) &&
- (gametype != GT_1FCTF || bs->neutralflagstatus == 0) ) {
- // tell the leader we want to be on offence
- BotVoiceChat(bs, leader, VOICECHAT_WANTONOFFENSE);
- //BotAI_BotInitialChat(bs, "wantoffence", NULL);
- //trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
- }
- }
- bs->teamtaskpreference |= TEAMTP_ATTACKER;
- }
- }
- bs->teamtaskpreference &= ~TEAMTP_DEFENDER;
- }
- else {
- if (!(bs->teamtaskpreference & TEAMTP_DEFENDER)) {
- // if we have a bot team leader
- if (BotTeamLeader(bs)) {
- // tell the leader we want to be on defense
- BotVoiceChat(bs, -1, VOICECHAT_WANTONDEFENSE);
- //BotAI_BotInitialChat(bs, "wantdefence", NULL);
- //trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
- }
- else if (g_spSkill.integer <= 3) {
- if ( bs->ltgtype != LTG_DEFENDKEYAREA ) {
- //
- if ((gametype != GT_CTF || (bs->redflagstatus == 0 && bs->blueflagstatus == 0)) &&
- (gametype != GT_1FCTF || bs->neutralflagstatus == 0) ) {
- // tell the leader we want to be on defense
- BotVoiceChat(bs, -1, VOICECHAT_WANTONDEFENSE);
- //BotAI_BotInitialChat(bs, "wantdefence", NULL);
- //trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
- }
- }
- }
- bs->teamtaskpreference |= TEAMTP_DEFENDER;
- }
- bs->teamtaskpreference &= ~TEAMTP_ATTACKER;
- }
- }
-#endif
-}
-
-/*
-==================
-BotUpdateInventory
-==================
-*/
-void BotUpdateInventory(bot_state_t *bs) {
- int oldinventory[MAX_ITEMS];
-
- memcpy(oldinventory, bs->inventory, sizeof(oldinventory));
- //armor
- bs->inventory[INVENTORY_ARMOR] = bs->cur_ps.stats[STAT_ARMOR];
- //weapons
- bs->inventory[INVENTORY_GAUNTLET] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GAUNTLET)) != 0;
- bs->inventory[INVENTORY_SHOTGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_SHOTGUN)) != 0;
- bs->inventory[INVENTORY_MACHINEGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_MACHINEGUN)) != 0;
- bs->inventory[INVENTORY_GRENADELAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRENADE_LAUNCHER)) != 0;
- bs->inventory[INVENTORY_ROCKETLAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_ROCKET_LAUNCHER)) != 0;
- bs->inventory[INVENTORY_LIGHTNING] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_LIGHTNING)) != 0;
- bs->inventory[INVENTORY_RAILGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_RAILGUN)) != 0;
- bs->inventory[INVENTORY_PLASMAGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_PLASMAGUN)) != 0;
- bs->inventory[INVENTORY_BFG10K] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_BFG)) != 0;
- bs->inventory[INVENTORY_GRAPPLINGHOOK] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRAPPLING_HOOK)) != 0;
-#ifdef MISSIONPACK
- bs->inventory[INVENTORY_NAILGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_NAILGUN)) != 0;;
- bs->inventory[INVENTORY_PROXLAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_PROX_LAUNCHER)) != 0;;
- bs->inventory[INVENTORY_CHAINGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_CHAINGUN)) != 0;;
-#endif
- //ammo
- bs->inventory[INVENTORY_SHELLS] = bs->cur_ps.ammo[WP_SHOTGUN];
- bs->inventory[INVENTORY_BULLETS] = bs->cur_ps.ammo[WP_MACHINEGUN];
- bs->inventory[INVENTORY_GRENADES] = bs->cur_ps.ammo[WP_GRENADE_LAUNCHER];
- bs->inventory[INVENTORY_CELLS] = bs->cur_ps.ammo[WP_PLASMAGUN];
- bs->inventory[INVENTORY_LIGHTNINGAMMO] = bs->cur_ps.ammo[WP_LIGHTNING];
- bs->inventory[INVENTORY_ROCKETS] = bs->cur_ps.ammo[WP_ROCKET_LAUNCHER];
- bs->inventory[INVENTORY_SLUGS] = bs->cur_ps.ammo[WP_RAILGUN];
- bs->inventory[INVENTORY_BFGAMMO] = bs->cur_ps.ammo[WP_BFG];
-#ifdef MISSIONPACK
- bs->inventory[INVENTORY_NAILS] = bs->cur_ps.ammo[WP_NAILGUN];
- bs->inventory[INVENTORY_MINES] = bs->cur_ps.ammo[WP_PROX_LAUNCHER];
- bs->inventory[INVENTORY_BELT] = bs->cur_ps.ammo[WP_CHAINGUN];
-#endif
- //powerups
- bs->inventory[INVENTORY_HEALTH] = bs->cur_ps.stats[STAT_HEALTH];
- bs->inventory[INVENTORY_TELEPORTER] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_TELEPORTER;
- bs->inventory[INVENTORY_MEDKIT] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_MEDKIT;
-#ifdef MISSIONPACK
- bs->inventory[INVENTORY_KAMIKAZE] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_KAMIKAZE;
- bs->inventory[INVENTORY_PORTAL] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_PORTAL;
- bs->inventory[INVENTORY_INVULNERABILITY] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_INVULNERABILITY;
-#endif
- bs->inventory[INVENTORY_QUAD] = bs->cur_ps.powerups[PW_QUAD] != 0;
- bs->inventory[INVENTORY_ENVIRONMENTSUIT] = bs->cur_ps.powerups[PW_BATTLESUIT] != 0;
- bs->inventory[INVENTORY_HASTE] = bs->cur_ps.powerups[PW_HASTE] != 0;
- bs->inventory[INVENTORY_INVISIBILITY] = bs->cur_ps.powerups[PW_INVIS] != 0;
- bs->inventory[INVENTORY_REGEN] = bs->cur_ps.powerups[PW_REGEN] != 0;
- bs->inventory[INVENTORY_FLIGHT] = bs->cur_ps.powerups[PW_FLIGHT] != 0;
-#ifdef MISSIONPACK
- bs->inventory[INVENTORY_SCOUT] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_SCOUT;
- bs->inventory[INVENTORY_GUARD] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_GUARD;
- bs->inventory[INVENTORY_DOUBLER] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_DOUBLER;
- bs->inventory[INVENTORY_AMMOREGEN] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_AMMOREGEN;
-#endif
- bs->inventory[INVENTORY_REDFLAG] = bs->cur_ps.powerups[PW_REDFLAG] != 0;
- bs->inventory[INVENTORY_BLUEFLAG] = bs->cur_ps.powerups[PW_BLUEFLAG] != 0;
-#ifdef MISSIONPACK
- bs->inventory[INVENTORY_NEUTRALFLAG] = bs->cur_ps.powerups[PW_NEUTRALFLAG] != 0;
- if (BotTeam(bs) == TEAM_RED) {
- bs->inventory[INVENTORY_REDCUBE] = bs->cur_ps.generic1;
- bs->inventory[INVENTORY_BLUECUBE] = 0;
- }
- else {
- bs->inventory[INVENTORY_REDCUBE] = 0;
- bs->inventory[INVENTORY_BLUECUBE] = bs->cur_ps.generic1;
- }
-#endif
- BotCheckItemPickup(bs, oldinventory);
-}
-
-/*
-==================
-BotUpdateBattleInventory
-==================
-*/
-void BotUpdateBattleInventory(bot_state_t *bs, int enemy) {
- vec3_t dir;
- aas_entityinfo_t entinfo;
-
- BotEntityInfo(enemy, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- bs->inventory[ENEMY_HEIGHT] = (int) dir[2];
- dir[2] = 0;
- bs->inventory[ENEMY_HORIZONTAL_DIST] = (int) VectorLength(dir);
- //FIXME: add num visible enemies and num visible team mates to the inventory
-}
-
-#ifdef MISSIONPACK
-/*
-==================
-BotUseKamikaze
-==================
-*/
-#define KAMIKAZE_DIST 1024
-
-void BotUseKamikaze(bot_state_t *bs) {
- int c, teammates, enemies;
- aas_entityinfo_t entinfo;
- vec3_t dir, target;
- bot_goal_t *goal;
- bsp_trace_t trace;
-
- //if the bot has no kamikaze
- if (bs->inventory[INVENTORY_KAMIKAZE] <= 0)
- return;
- if (bs->kamikaze_time > FloatTime())
- return;
- bs->kamikaze_time = FloatTime() + 0.2;
- if (gametype == GT_CTF) {
- //never use kamikaze if the team flag carrier is visible
- if (BotCTFCarryingFlag(bs))
- return;
- c = BotTeamFlagCarrierVisible(bs);
- if (c >= 0) {
- BotEntityInfo(c, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST))
- return;
- }
- c = BotEnemyFlagCarrierVisible(bs);
- if (c >= 0) {
- BotEntityInfo(c, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- else if (gametype == GT_1FCTF) {
- //never use kamikaze if the team flag carrier is visible
- if (Bot1FCTFCarryingFlag(bs))
- return;
- c = BotTeamFlagCarrierVisible(bs);
- if (c >= 0) {
- BotEntityInfo(c, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST))
- return;
- }
- c = BotEnemyFlagCarrierVisible(bs);
- if (c >= 0) {
- BotEntityInfo(c, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- else if (gametype == GT_OBELISK) {
- switch(BotTeam(bs)) {
- case TEAM_RED: goal = &blueobelisk; break;
- default: goal = &redobelisk; break;
- }
- //if the obelisk is visible
- VectorCopy(goal->origin, target);
- target[2] += 1;
- VectorSubtract(bs->origin, target, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST * 0.9)) {
- BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
- if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- else if (gametype == GT_HARVESTER) {
- //
- if (BotHarvesterCarryingCubes(bs))
- return;
- //never use kamikaze if a team mate carrying cubes is visible
- c = BotTeamCubeCarrierVisible(bs);
- if (c >= 0) {
- BotEntityInfo(c, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST))
- return;
- }
- c = BotEnemyCubeCarrierVisible(bs);
- if (c >= 0) {
- BotEntityInfo(c, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- //
- BotVisibleTeamMatesAndEnemies(bs, &teammates, &enemies, KAMIKAZE_DIST);
- //
- if (enemies > 2 && enemies > teammates+1) {
- trap_EA_Use(bs->client);
- return;
- }
-}
-
-/*
-==================
-BotUseInvulnerability
-==================
-*/
-void BotUseInvulnerability(bot_state_t *bs) {
- int c;
- vec3_t dir, target;
- bot_goal_t *goal;
- bsp_trace_t trace;
-
- //if the bot has no invulnerability
- if (bs->inventory[INVENTORY_INVULNERABILITY] <= 0)
- return;
- if (bs->invulnerability_time > FloatTime())
- return;
- bs->invulnerability_time = FloatTime() + 0.2;
- if (gametype == GT_CTF) {
- //never use kamikaze if the team flag carrier is visible
- if (BotCTFCarryingFlag(bs))
- return;
- c = BotEnemyFlagCarrierVisible(bs);
- if (c >= 0)
- return;
- //if near enemy flag and the flag is visible
- switch(BotTeam(bs)) {
- case TEAM_RED: goal = &ctf_blueflag; break;
- default: goal = &ctf_redflag; break;
- }
- //if the obelisk is visible
- VectorCopy(goal->origin, target);
- target[2] += 1;
- VectorSubtract(bs->origin, target, dir);
- if (VectorLengthSquared(dir) < Square(200)) {
- BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
- if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- else if (gametype == GT_1FCTF) {
- //never use kamikaze if the team flag carrier is visible
- if (Bot1FCTFCarryingFlag(bs))
- return;
- c = BotEnemyFlagCarrierVisible(bs);
- if (c >= 0)
- return;
- //if near enemy flag and the flag is visible
- switch(BotTeam(bs)) {
- case TEAM_RED: goal = &ctf_blueflag; break;
- default: goal = &ctf_redflag; break;
- }
- //if the obelisk is visible
- VectorCopy(goal->origin, target);
- target[2] += 1;
- VectorSubtract(bs->origin, target, dir);
- if (VectorLengthSquared(dir) < Square(200)) {
- BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
- if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- else if (gametype == GT_OBELISK) {
- switch(BotTeam(bs)) {
- case TEAM_RED: goal = &blueobelisk; break;
- default: goal = &redobelisk; break;
- }
- //if the obelisk is visible
- VectorCopy(goal->origin, target);
- target[2] += 1;
- VectorSubtract(bs->origin, target, dir);
- if (VectorLengthSquared(dir) < Square(300)) {
- BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
- if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- else if (gametype == GT_HARVESTER) {
- //
- if (BotHarvesterCarryingCubes(bs))
- return;
- c = BotEnemyCubeCarrierVisible(bs);
- if (c >= 0)
- return;
- //if near enemy base and enemy base is visible
- switch(BotTeam(bs)) {
- case TEAM_RED: goal = &blueobelisk; break;
- default: goal = &redobelisk; break;
- }
- //if the obelisk is visible
- VectorCopy(goal->origin, target);
- target[2] += 1;
- VectorSubtract(bs->origin, target, dir);
- if (VectorLengthSquared(dir) < Square(200)) {
- BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
- if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
-}
-#endif
-
-/*
-==================
-BotBattleUseItems
-==================
-*/
-void BotBattleUseItems(bot_state_t *bs) {
- if (bs->inventory[INVENTORY_HEALTH] < 40) {
- if (bs->inventory[INVENTORY_TELEPORTER] > 0) {
- if (!BotCTFCarryingFlag(bs)
-#ifdef MISSIONPACK
- && !Bot1FCTFCarryingFlag(bs)
- && !BotHarvesterCarryingCubes(bs)
-#endif
- ) {
- trap_EA_Use(bs->client);
- }
- }
- }
- if (bs->inventory[INVENTORY_HEALTH] < 60) {
- if (bs->inventory[INVENTORY_MEDKIT] > 0) {
- trap_EA_Use(bs->client);
- }
- }
-#ifdef MISSIONPACK
- BotUseKamikaze(bs);
- BotUseInvulnerability(bs);
-#endif
-}
-
-/*
-==================
-BotSetTeleportTime
-==================
-*/
-void BotSetTeleportTime(bot_state_t *bs) {
- if ((bs->cur_ps.eFlags ^ bs->last_eFlags) & EF_TELEPORT_BIT) {
- bs->teleport_time = FloatTime();
- }
- bs->last_eFlags = bs->cur_ps.eFlags;
-}
-
-/*
-==================
-BotIsDead
-==================
-*/
-qboolean BotIsDead(bot_state_t *bs) {
- return (bs->cur_ps.pm_type == PM_DEAD);
-}
-
-/*
-==================
-BotIsObserver
-==================
-*/
-qboolean BotIsObserver(bot_state_t *bs) {
- char buf[MAX_INFO_STRING];
- if (bs->cur_ps.pm_type == PM_SPECTATOR) return qtrue;
- trap_GetConfigstring(CS_PLAYERS+bs->client, buf, sizeof(buf));
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) return qtrue;
- return qfalse;
-}
-
-/*
-==================
-BotIntermission
-==================
-*/
-qboolean BotIntermission(bot_state_t *bs) {
- //NOTE: we shouldn't be looking at the game code...
- if (level.intermissiontime) return qtrue;
- return (bs->cur_ps.pm_type == PM_FREEZE || bs->cur_ps.pm_type == PM_INTERMISSION);
-}
-
-/*
-==================
-BotInLavaOrSlime
-==================
-*/
-qboolean BotInLavaOrSlime(bot_state_t *bs) {
- vec3_t feet;
-
- VectorCopy(bs->origin, feet);
- feet[2] -= 23;
- return (trap_AAS_PointContents(feet) & (CONTENTS_LAVA|CONTENTS_SLIME));
-}
-
-/*
-==================
-BotCreateWayPoint
-==================
-*/
-bot_waypoint_t *BotCreateWayPoint(char *name, vec3_t origin, int areanum) {
- bot_waypoint_t *wp;
- vec3_t waypointmins = {-8, -8, -8}, waypointmaxs = {8, 8, 8};
-
- wp = botai_freewaypoints;
- if ( !wp ) {
- BotAI_Print( PRT_WARNING, "BotCreateWayPoint: Out of waypoints\n" );
- return NULL;
- }
- botai_freewaypoints = botai_freewaypoints->next;
-
- Q_strncpyz( wp->name, name, sizeof(wp->name) );
- VectorCopy(origin, wp->goal.origin);
- VectorCopy(waypointmins, wp->goal.mins);
- VectorCopy(waypointmaxs, wp->goal.maxs);
- wp->goal.areanum = areanum;
- wp->next = NULL;
- wp->prev = NULL;
- return wp;
-}
-
-/*
-==================
-BotFindWayPoint
-==================
-*/
-bot_waypoint_t *BotFindWayPoint(bot_waypoint_t *waypoints, char *name) {
- bot_waypoint_t *wp;
-
- for (wp = waypoints; wp; wp = wp->next) {
- if (!Q_stricmp(wp->name, name)) return wp;
- }
- return NULL;
-}
-
-/*
-==================
-BotFreeWaypoints
-==================
-*/
-void BotFreeWaypoints(bot_waypoint_t *wp) {
- bot_waypoint_t *nextwp;
-
- for (; wp; wp = nextwp) {
- nextwp = wp->next;
- wp->next = botai_freewaypoints;
- botai_freewaypoints = wp;
- }
-}
-
-/*
-==================
-BotInitWaypoints
-==================
-*/
-void BotInitWaypoints(void) {
- int i;
-
- botai_freewaypoints = NULL;
- for (i = 0; i < MAX_WAYPOINTS; i++) {
- botai_waypoints[i].next = botai_freewaypoints;
- botai_freewaypoints = &botai_waypoints[i];
- }
-}
-
-/*
-==================
-TeamPlayIsOn
-==================
-*/
-int TeamPlayIsOn(void) {
- return ( gametype >= GT_TEAM );
-}
-
-/*
-==================
-BotAggression
-==================
-*/
-float BotAggression(bot_state_t *bs) {
- //if the bot has quad
- if (bs->inventory[INVENTORY_QUAD]) {
- //if the bot is not holding the gauntlet or the enemy is really nearby
- if (bs->weaponnum != WP_GAUNTLET ||
- bs->inventory[ENEMY_HORIZONTAL_DIST] < 80) {
- return 70;
- }
- }
- //if the enemy is located way higher than the bot
- if (bs->inventory[ENEMY_HEIGHT] > 200) return 0;
- //if the bot is very low on health
- if (bs->inventory[INVENTORY_HEALTH] < 60) return 0;
- //if the bot is low on health
- if (bs->inventory[INVENTORY_HEALTH] < 80) {
- //if the bot has insufficient armor
- if (bs->inventory[INVENTORY_ARMOR] < 40) return 0;
- }
- //if the bot can use the bfg
- if (bs->inventory[INVENTORY_BFG10K] > 0 &&
- bs->inventory[INVENTORY_BFGAMMO] > 7) return 100;
- //if the bot can use the railgun
- if (bs->inventory[INVENTORY_RAILGUN] > 0 &&
- bs->inventory[INVENTORY_SLUGS] > 5) return 95;
- //if the bot can use the lightning gun
- if (bs->inventory[INVENTORY_LIGHTNING] > 0 &&
- bs->inventory[INVENTORY_LIGHTNINGAMMO] > 50) return 90;
- //if the bot can use the rocketlauncher
- if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 &&
- bs->inventory[INVENTORY_ROCKETS] > 5) return 90;
- //if the bot can use the plasmagun
- if (bs->inventory[INVENTORY_PLASMAGUN] > 0 &&
- bs->inventory[INVENTORY_CELLS] > 40) return 85;
- //if the bot can use the grenade launcher
- if (bs->inventory[INVENTORY_GRENADELAUNCHER] > 0 &&
- bs->inventory[INVENTORY_GRENADES] > 10) return 80;
- //if the bot can use the shotgun
- if (bs->inventory[INVENTORY_SHOTGUN] > 0 &&
- bs->inventory[INVENTORY_SHELLS] > 10) return 50;
- //otherwise the bot is not feeling too good
- return 0;
-}
-
-/*
-==================
-BotFeelingBad
-==================
-*/
-float BotFeelingBad(bot_state_t *bs) {
- if (bs->weaponnum == WP_GAUNTLET) {
- return 100;
- }
- if (bs->inventory[INVENTORY_HEALTH] < 40) {
- return 100;
- }
- if (bs->weaponnum == WP_MACHINEGUN) {
- return 90;
- }
- if (bs->inventory[INVENTORY_HEALTH] < 60) {
- return 80;
- }
- return 0;
-}
-
-/*
-==================
-BotWantsToRetreat
-==================
-*/
-int BotWantsToRetreat(bot_state_t *bs) {
- aas_entityinfo_t entinfo;
-
- if (gametype == GT_CTF) {
- //always retreat when carrying a CTF flag
- if (BotCTFCarryingFlag(bs))
- return qtrue;
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- //if carrying the flag then always retreat
- if (Bot1FCTFCarryingFlag(bs))
- return qtrue;
- }
- else if (gametype == GT_OBELISK) {
- //the bots should be dedicated to attacking the enemy obelisk
- if (bs->ltgtype == LTG_ATTACKENEMYBASE) {
- if (bs->enemy != redobelisk.entitynum ||
- bs->enemy != blueobelisk.entitynum) {
- return qtrue;
- }
- }
- if (BotFeelingBad(bs) > 50) {
- return qtrue;
- }
- return qfalse;
- }
- else if (gametype == GT_HARVESTER) {
- //if carrying cubes then always retreat
- if (BotHarvesterCarryingCubes(bs)) return qtrue;
- }
-#endif
- //
- if (bs->enemy >= 0) {
- //if the enemy is carrying a flag
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityCarriesFlag(&entinfo))
- return qfalse;
- }
- //if the bot is getting the flag
- if (bs->ltgtype == LTG_GETFLAG)
- return qtrue;
- //
- if (BotAggression(bs) < 50)
- return qtrue;
- return qfalse;
-}
-
-/*
-==================
-BotWantsToChase
-==================
-*/
-int BotWantsToChase(bot_state_t *bs) {
- aas_entityinfo_t entinfo;
-
- if (gametype == GT_CTF) {
- //never chase when carrying a CTF flag
- if (BotCTFCarryingFlag(bs))
- return qfalse;
- //always chase if the enemy is carrying a flag
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityCarriesFlag(&entinfo))
- return qtrue;
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- //never chase if carrying the flag
- if (Bot1FCTFCarryingFlag(bs))
- return qfalse;
- //always chase if the enemy is carrying a flag
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityCarriesFlag(&entinfo))
- return qtrue;
- }
- else if (gametype == GT_OBELISK) {
- //the bots should be dedicated to attacking the enemy obelisk
- if (bs->ltgtype == LTG_ATTACKENEMYBASE) {
- if (bs->enemy != redobelisk.entitynum ||
- bs->enemy != blueobelisk.entitynum) {
- return qfalse;
- }
- }
- }
- else if (gametype == GT_HARVESTER) {
- //never chase if carrying cubes
- if (BotHarvesterCarryingCubes(bs))
- return qfalse;
- }
-#endif
- //if the bot is getting the flag
- if (bs->ltgtype == LTG_GETFLAG)
- return qfalse;
- //
- if (BotAggression(bs) > 50)
- return qtrue;
- return qfalse;
-}
-
-/*
-==================
-BotWantsToHelp
-==================
-*/
-int BotWantsToHelp(bot_state_t *bs) {
- return qtrue;
-}
-
-/*
-==================
-BotCanAndWantsToRocketJump
-==================
-*/
-int BotCanAndWantsToRocketJump(bot_state_t *bs) {
- float rocketjumper;
-
- //if rocket jumping is disabled
- if (!bot_rocketjump.integer) return qfalse;
- //if no rocket launcher
- if (bs->inventory[INVENTORY_ROCKETLAUNCHER] <= 0) return qfalse;
- //if low on rockets
- if (bs->inventory[INVENTORY_ROCKETS] < 3) return qfalse;
- //never rocket jump with the Quad
- if (bs->inventory[INVENTORY_QUAD]) return qfalse;
- //if low on health
- if (bs->inventory[INVENTORY_HEALTH] < 60) return qfalse;
- //if not full health
- if (bs->inventory[INVENTORY_HEALTH] < 90) {
- //if the bot has insufficient armor
- if (bs->inventory[INVENTORY_ARMOR] < 40) return qfalse;
- }
- rocketjumper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WEAPONJUMPING, 0, 1);
- if (rocketjumper < 0.5) return qfalse;
- return qtrue;
-}
-
-/*
-==================
-BotHasPersistantPowerupAndWeapon
-==================
-*/
-int BotHasPersistantPowerupAndWeapon(bot_state_t *bs) {
-#ifdef MISSIONPACK
- // if the bot does not have a persistant powerup
- if (!bs->inventory[INVENTORY_SCOUT] &&
- !bs->inventory[INVENTORY_GUARD] &&
- !bs->inventory[INVENTORY_DOUBLER] &&
- !bs->inventory[INVENTORY_AMMOREGEN] ) {
- return qfalse;
- }
-#endif
- //if the bot is very low on health
- if (bs->inventory[INVENTORY_HEALTH] < 60) return qfalse;
- //if the bot is low on health
- if (bs->inventory[INVENTORY_HEALTH] < 80) {
- //if the bot has insufficient armor
- if (bs->inventory[INVENTORY_ARMOR] < 40) return qfalse;
- }
- //if the bot can use the bfg
- if (bs->inventory[INVENTORY_BFG10K] > 0 &&
- bs->inventory[INVENTORY_BFGAMMO] > 7) return qtrue;
- //if the bot can use the railgun
- if (bs->inventory[INVENTORY_RAILGUN] > 0 &&
- bs->inventory[INVENTORY_SLUGS] > 5) return qtrue;
- //if the bot can use the lightning gun
- if (bs->inventory[INVENTORY_LIGHTNING] > 0 &&
- bs->inventory[INVENTORY_LIGHTNINGAMMO] > 50) return qtrue;
- //if the bot can use the rocketlauncher
- if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 &&
- bs->inventory[INVENTORY_ROCKETS] > 5) return qtrue;
- //
- if (bs->inventory[INVENTORY_NAILGUN] > 0 &&
- bs->inventory[INVENTORY_NAILS] > 5) return qtrue;
- //
- if (bs->inventory[INVENTORY_PROXLAUNCHER] > 0 &&
- bs->inventory[INVENTORY_MINES] > 5) return qtrue;
- //
- if (bs->inventory[INVENTORY_CHAINGUN] > 0 &&
- bs->inventory[INVENTORY_BELT] > 40) return qtrue;
- //if the bot can use the plasmagun
- if (bs->inventory[INVENTORY_PLASMAGUN] > 0 &&
- bs->inventory[INVENTORY_CELLS] > 20) return qtrue;
- return qfalse;
-}
-
-/*
-==================
-BotGoCamp
-==================
-*/
-void BotGoCamp(bot_state_t *bs, bot_goal_t *goal) {
- float camper;
-
- bs->decisionmaker = bs->client;
- //set message time to zero so bot will NOT show any message
- bs->teammessage_time = 0;
- //set the ltg type
- bs->ltgtype = LTG_CAMP;
- //set the team goal
- memcpy(&bs->teamgoal, goal, sizeof(bot_goal_t));
- //get the team goal time
- camper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CAMPER, 0, 1);
- if (camper > 0.99) bs->teamgoal_time = FloatTime() + 99999;
- else bs->teamgoal_time = FloatTime() + 120 + 180 * camper + random() * 15;
- //set the last time the bot started camping
- bs->camp_time = FloatTime();
- //the teammate that requested the camping
- bs->teammate = 0;
- //do NOT type arrive message
- bs->arrive_time = 1;
-}
-
-/*
-==================
-BotWantsToCamp
-==================
-*/
-int BotWantsToCamp(bot_state_t *bs) {
- float camper;
- int cs, traveltime, besttraveltime;
- bot_goal_t goal, bestgoal;
-
- camper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CAMPER, 0, 1);
- if (camper < 0.1) return qfalse;
- //if the bot has a team goal
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_DEFENDKEYAREA ||
- bs->ltgtype == LTG_GETFLAG ||
- bs->ltgtype == LTG_RUSHBASE ||
- bs->ltgtype == LTG_CAMP ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL) {
- return qfalse;
- }
- //if camped recently
- if (bs->camp_time > FloatTime() - 60 + 300 * (1-camper)) return qfalse;
- //
- if (random() > camper) {
- bs->camp_time = FloatTime();
- return qfalse;
- }
- //if the bot isn't healthy anough
- if (BotAggression(bs) < 50) return qfalse;
- //the bot should have at least have the rocket launcher, the railgun or the bfg10k with some ammo
- if ((bs->inventory[INVENTORY_ROCKETLAUNCHER] <= 0 || bs->inventory[INVENTORY_ROCKETS < 10]) &&
- (bs->inventory[INVENTORY_RAILGUN] <= 0 || bs->inventory[INVENTORY_SLUGS] < 10) &&
- (bs->inventory[INVENTORY_BFG10K] <= 0 || bs->inventory[INVENTORY_BFGAMMO] < 10)) {
- return qfalse;
- }
- //find the closest camp spot
- besttraveltime = 99999;
- for (cs = trap_BotGetNextCampSpotGoal(0, &goal); cs; cs = trap_BotGetNextCampSpotGoal(cs, &goal)) {
- traveltime = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, goal.areanum, TFL_DEFAULT);
- if (traveltime && traveltime < besttraveltime) {
- besttraveltime = traveltime;
- memcpy(&bestgoal, &goal, sizeof(bot_goal_t));
- }
- }
- if (besttraveltime > 150) return qfalse;
- //ok found a camp spot, go camp there
- BotGoCamp(bs, &bestgoal);
- bs->ordered = qfalse;
- //
- return qtrue;
-}
-
-/*
-==================
-BotDontAvoid
-==================
-*/
-void BotDontAvoid(bot_state_t *bs, char *itemname) {
- bot_goal_t goal;
- int num;
-
- num = trap_BotGetLevelItemGoal(-1, itemname, &goal);
- while(num >= 0) {
- trap_BotRemoveFromAvoidGoals(bs->gs, goal.number);
- num = trap_BotGetLevelItemGoal(num, itemname, &goal);
- }
-}
-
-/*
-==================
-BotGoForPowerups
-==================
-*/
-void BotGoForPowerups(bot_state_t *bs) {
-
- //don't avoid any of the powerups anymore
- BotDontAvoid(bs, "Quad Damage");
- BotDontAvoid(bs, "Regeneration");
- BotDontAvoid(bs, "Battle Suit");
- BotDontAvoid(bs, "Speed");
- BotDontAvoid(bs, "Invisibility");
- //BotDontAvoid(bs, "Flight");
- //reset the long term goal time so the bot will go for the powerup
- //NOTE: the long term goal type doesn't change
- bs->ltg_time = 0;
-}
-
-/*
-==================
-BotRoamGoal
-==================
-*/
-void BotRoamGoal(bot_state_t *bs, vec3_t goal) {
- int pc, i;
- float len, rnd;
- vec3_t dir, bestorg, belowbestorg;
- bsp_trace_t trace;
-
- for (i = 0; i < 10; i++) {
- //start at the bot origin
- VectorCopy(bs->origin, bestorg);
- rnd = random();
- if (rnd > 0.25) {
- //add a random value to the x-coordinate
- if (random() < 0.5) bestorg[0] -= 800 * random() + 100;
- else bestorg[0] += 800 * random() + 100;
- }
- if (rnd < 0.75) {
- //add a random value to the y-coordinate
- if (random() < 0.5) bestorg[1] -= 800 * random() + 100;
- else bestorg[1] += 800 * random() + 100;
- }
- //add a random value to the z-coordinate (NOTE: 48 = maxjump?)
- bestorg[2] += 2 * 48 * crandom();
- //trace a line from the origin to the roam target
- BotAI_Trace(&trace, bs->origin, NULL, NULL, bestorg, bs->entitynum, MASK_SOLID);
- //direction and length towards the roam target
- VectorSubtract(trace.endpos, bs->origin, dir);
- len = VectorNormalize(dir);
- //if the roam target is far away anough
- if (len > 200) {
- //the roam target is in the given direction before walls
- VectorScale(dir, len * trace.fraction - 40, dir);
- VectorAdd(bs->origin, dir, bestorg);
- //get the coordinates of the floor below the roam target
- belowbestorg[0] = bestorg[0];
- belowbestorg[1] = bestorg[1];
- belowbestorg[2] = bestorg[2] - 800;
- BotAI_Trace(&trace, bestorg, NULL, NULL, belowbestorg, bs->entitynum, MASK_SOLID);
- //
- if (!trace.startsolid) {
- trace.endpos[2]++;
- pc = trap_PointContents(trace.endpos, bs->entitynum);
- if (!(pc & (CONTENTS_LAVA | CONTENTS_SLIME))) {
- VectorCopy(bestorg, goal);
- return;
- }
- }
- }
- }
- VectorCopy(bestorg, goal);
-}
-
-/*
-==================
-BotAttackMove
-==================
-*/
-bot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl) {
- int movetype, i, attackentity;
- float attack_skill, jumper, croucher, dist, strafechange_time;
- float attack_dist, attack_range;
- vec3_t forward, backward, sideward, hordir, up = {0, 0, 1};
- aas_entityinfo_t entinfo;
- bot_moveresult_t moveresult;
- bot_goal_t goal;
-
- attackentity = bs->enemy;
- //
- if (bs->attackchase_time > FloatTime()) {
- //create the chase goal
- goal.entitynum = attackentity;
- goal.areanum = bs->lastenemyareanum;
- VectorCopy(bs->lastenemyorigin, goal.origin);
- VectorSet(goal.mins, -8, -8, -8);
- VectorSet(goal.maxs, 8, 8, 8);
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, &goal, tfl);
- return moveresult;
- }
- //
- memset(&moveresult, 0, sizeof(bot_moveresult_t));
- //
- attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1);
- jumper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_JUMPER, 0, 1);
- croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);
- //if the bot is really stupid
- if (attack_skill < 0.2) return moveresult;
- //initialize the movement state
- BotSetupForMovement(bs);
- //get the enemy entity info
- BotEntityInfo(attackentity, &entinfo);
- //direction towards the enemy
- VectorSubtract(entinfo.origin, bs->origin, forward);
- //the distance towards the enemy
- dist = VectorNormalize(forward);
- VectorNegate(forward, backward);
- //walk, crouch or jump
- movetype = MOVE_WALK;
- //
- if (bs->attackcrouch_time < FloatTime() - 1) {
- if (random() < jumper) {
- movetype = MOVE_JUMP;
- }
- //wait at least one second before crouching again
- else if (bs->attackcrouch_time < FloatTime() - 1 && random() < croucher) {
- bs->attackcrouch_time = FloatTime() + croucher * 5;
- }
- }
- if (bs->attackcrouch_time > FloatTime()) movetype = MOVE_CROUCH;
- //if the bot should jump
- if (movetype == MOVE_JUMP) {
- //if jumped last frame
- if (bs->attackjump_time > FloatTime()) {
- movetype = MOVE_WALK;
- }
- else {
- bs->attackjump_time = FloatTime() + 1;
- }
- }
- if (bs->cur_ps.weapon == WP_GAUNTLET) {
- attack_dist = 0;
- attack_range = 0;
- }
- else {
- attack_dist = IDEAL_ATTACKDIST;
- attack_range = 40;
- }
- //if the bot is stupid
- if (attack_skill <= 0.4) {
- //just walk to or away from the enemy
- if (dist > attack_dist + attack_range) {
- if (trap_BotMoveInDirection(bs->ms, forward, 400, movetype)) return moveresult;
- }
- if (dist < attack_dist - attack_range) {
- if (trap_BotMoveInDirection(bs->ms, backward, 400, movetype)) return moveresult;
- }
- return moveresult;
- }
- //increase the strafe time
- bs->attackstrafe_time += bs->thinktime;
- //get the strafe change time
- strafechange_time = 0.4 + (1 - attack_skill) * 0.2;
- if (attack_skill > 0.7) strafechange_time += crandom() * 0.2;
- //if the strafe direction should be changed
- if (bs->attackstrafe_time > strafechange_time) {
- //some magic number :)
- if (random() > 0.935) {
- //flip the strafe direction
- bs->flags ^= BFL_STRAFERIGHT;
- bs->attackstrafe_time = 0;
- }
- }
- //
- for (i = 0; i < 2; i++) {
- hordir[0] = forward[0];
- hordir[1] = forward[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //get the sideward vector
- CrossProduct(hordir, up, sideward);
- //reverse the vector depending on the strafe direction
- if (bs->flags & BFL_STRAFERIGHT) VectorNegate(sideward, sideward);
- //randomly go back a little
- if (random() > 0.9) {
- VectorAdd(sideward, backward, sideward);
- }
- else {
- //walk forward or backward to get at the ideal attack distance
- if (dist > attack_dist + attack_range) {
- VectorAdd(sideward, forward, sideward);
- }
- else if (dist < attack_dist - attack_range) {
- VectorAdd(sideward, backward, sideward);
- }
- }
- //perform the movement
- if (trap_BotMoveInDirection(bs->ms, sideward, 400, movetype))
- return moveresult;
- //movement failed, flip the strafe direction
- bs->flags ^= BFL_STRAFERIGHT;
- bs->attackstrafe_time = 0;
- }
- //bot couldn't do any usefull movement
-// bs->attackchase_time = AAS_Time() + 6;
- return moveresult;
-}
-
-/*
-==================
-BotSameTeam
-==================
-*/
-int BotSameTeam(bot_state_t *bs, int entnum) {
- char info1[1024], info2[1024];
-
- if (bs->client < 0 || bs->client >= MAX_CLIENTS) {
- //BotAI_Print(PRT_ERROR, "BotSameTeam: client out of range\n");
- return qfalse;
- }
- if (entnum < 0 || entnum >= MAX_CLIENTS) {
- //BotAI_Print(PRT_ERROR, "BotSameTeam: client out of range\n");
- return qfalse;
- }
- if ( gametype >= GT_TEAM ) {
- trap_GetConfigstring(CS_PLAYERS+bs->client, info1, sizeof(info1));
- trap_GetConfigstring(CS_PLAYERS+entnum, info2, sizeof(info2));
- //
- if (atoi(Info_ValueForKey(info1, "t")) == atoi(Info_ValueForKey(info2, "t"))) return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-InFieldOfVision
-==================
-*/
-qboolean InFieldOfVision(vec3_t viewangles, float fov, vec3_t angles)
-{
- int i;
- float diff, angle;
-
- for (i = 0; i < 2; i++) {
- angle = AngleMod(viewangles[i]);
- angles[i] = AngleMod(angles[i]);
- diff = angles[i] - angle;
- if (angles[i] > angle) {
- if (diff > 180.0) diff -= 360.0;
- }
- else {
- if (diff < -180.0) diff += 360.0;
- }
- if (diff > 0) {
- if (diff > fov * 0.5) return qfalse;
- }
- else {
- if (diff < -fov * 0.5) return qfalse;
- }
- }
- return qtrue;
-}
-
-/*
-==================
-BotEntityVisible
-
-returns visibility in the range [0, 1] taking fog and water surfaces into account
-==================
-*/
-float BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int ent) {
- int i, contents_mask, passent, hitent, infog, inwater, otherinfog, pc;
- float squaredfogdist, waterfactor, vis, bestvis;
- bsp_trace_t trace;
- aas_entityinfo_t entinfo;
- vec3_t dir, entangles, start, end, middle;
-
- //calculate middle of bounding box
- BotEntityInfo(ent, &entinfo);
- VectorAdd(entinfo.mins, entinfo.maxs, middle);
- VectorScale(middle, 0.5, middle);
- VectorAdd(entinfo.origin, middle, middle);
- //check if entity is within field of vision
- VectorSubtract(middle, eye, dir);
- vectoangles(dir, entangles);
- if (!InFieldOfVision(viewangles, fov, entangles)) return 0;
- //
- pc = trap_AAS_PointContents(eye);
- infog = (pc & CONTENTS_FOG);
- inwater = (pc & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER));
- //
- bestvis = 0;
- for (i = 0; i < 3; i++) {
- //if the point is not in potential visible sight
- //if (!AAS_inPVS(eye, middle)) continue;
- //
- contents_mask = CONTENTS_SOLID|CONTENTS_PLAYERCLIP;
- passent = viewer;
- hitent = ent;
- VectorCopy(eye, start);
- VectorCopy(middle, end);
- //if the entity is in water, lava or slime
- if (trap_AAS_PointContents(middle) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) {
- contents_mask |= (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER);
- }
- //if eye is in water, lava or slime
- if (inwater) {
- if (!(contents_mask & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) {
- passent = ent;
- hitent = viewer;
- VectorCopy(middle, start);
- VectorCopy(eye, end);
- }
- contents_mask ^= (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER);
- }
- //trace from start to end
- BotAI_Trace(&trace, start, NULL, NULL, end, passent, contents_mask);
- //if water was hit
- waterfactor = 1.0;
- if (trace.contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) {
- //if the water surface is translucent
- if (1) {
- //trace through the water
- contents_mask &= ~(CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER);
- BotAI_Trace(&trace, trace.endpos, NULL, NULL, end, passent, contents_mask);
- waterfactor = 0.5;
- }
- }
- //if a full trace or the hitent was hit
- if (trace.fraction >= 1 || trace.ent == hitent) {
- //check for fog, assuming there's only one fog brush where
- //either the viewer or the entity is in or both are in
- otherinfog = (trap_AAS_PointContents(middle) & CONTENTS_FOG);
- if (infog && otherinfog) {
- VectorSubtract(trace.endpos, eye, dir);
- squaredfogdist = VectorLengthSquared(dir);
- }
- else if (infog) {
- VectorCopy(trace.endpos, start);
- BotAI_Trace(&trace, start, NULL, NULL, eye, viewer, CONTENTS_FOG);
- VectorSubtract(eye, trace.endpos, dir);
- squaredfogdist = VectorLengthSquared(dir);
- }
- else if (otherinfog) {
- VectorCopy(trace.endpos, end);
- BotAI_Trace(&trace, eye, NULL, NULL, end, viewer, CONTENTS_FOG);
- VectorSubtract(end, trace.endpos, dir);
- squaredfogdist = VectorLengthSquared(dir);
- }
- else {
- //if the entity and the viewer are not in fog assume there's no fog in between
- squaredfogdist = 0;
- }
- //decrease visibility with the view distance through fog
- vis = 1 / ((squaredfogdist * 0.001) < 1 ? 1 : (squaredfogdist * 0.001));
- //if entering water visibility is reduced
- vis *= waterfactor;
- //
- if (vis > bestvis) bestvis = vis;
- //if pretty much no fog
- if (bestvis >= 0.95) return bestvis;
- }
- //check bottom and top of bounding box as well
- if (i == 0) middle[2] += entinfo.mins[2];
- else if (i == 1) middle[2] += entinfo.maxs[2] - entinfo.mins[2];
- }
- return bestvis;
-}
-
-/*
-==================
-BotFindEnemy
-==================
-*/
-int BotFindEnemy(bot_state_t *bs, int curenemy) {
- int i, healthdecrease;
- float f, alertness, easyfragger, vis;
- float squaredist, cursquaredist;
- aas_entityinfo_t entinfo, curenemyinfo;
- vec3_t dir, angles;
-
- alertness = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ALERTNESS, 0, 1);
- easyfragger = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_EASY_FRAGGER, 0, 1);
- //check if the health decreased
- healthdecrease = bs->lasthealth > bs->inventory[INVENTORY_HEALTH];
- //remember the current health value
- bs->lasthealth = bs->inventory[INVENTORY_HEALTH];
- //
- if (curenemy >= 0) {
- BotEntityInfo(curenemy, &curenemyinfo);
- if (EntityCarriesFlag(&curenemyinfo)) return qfalse;
- VectorSubtract(curenemyinfo.origin, bs->origin, dir);
- cursquaredist = VectorLengthSquared(dir);
- }
- else {
- cursquaredist = 0;
- }
-#ifdef MISSIONPACK
- if (gametype == GT_OBELISK) {
- vec3_t target;
- bot_goal_t *goal;
- bsp_trace_t trace;
-
- if (BotTeam(bs) == TEAM_RED)
- goal = &blueobelisk;
- else
- goal = &redobelisk;
- //if the obelisk is visible
- VectorCopy(goal->origin, target);
- target[2] += 1;
- BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
- if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
- if (goal->entitynum == bs->enemy) {
- return qfalse;
- }
- bs->enemy = goal->entitynum;
- bs->enemysight_time = FloatTime();
- bs->enemysuicide = qfalse;
- bs->enemydeath_time = 0;
- bs->enemyvisible_time = FloatTime();
- return qtrue;
- }
- }
-#endif
- //
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
-
- if (i == bs->client) continue;
- //if it's the current enemy
- if (i == curenemy) continue;
- //
- BotEntityInfo(i, &entinfo);
- //
- if (!entinfo.valid) continue;
- //if the enemy isn't dead and the enemy isn't the bot self
- if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;
- //if the enemy is invisible and not shooting
- if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
- continue;
- }
- //if not an easy fragger don't shoot at chatting players
- if (easyfragger < 0.5 && EntityIsChatting(&entinfo)) continue;
- //
- if (lastteleport_time > FloatTime() - 3) {
- VectorSubtract(entinfo.origin, lastteleport_origin, dir);
- if (VectorLengthSquared(dir) < Square(70)) continue;
- }
- //calculate the distance towards the enemy
- VectorSubtract(entinfo.origin, bs->origin, dir);
- squaredist = VectorLengthSquared(dir);
- //if this entity is not carrying a flag
- if (!EntityCarriesFlag(&entinfo))
- {
- //if this enemy is further away than the current one
- if (curenemy >= 0 && squaredist > cursquaredist) continue;
- } //end if
- //if the bot has no
- if (squaredist > Square(900.0 + alertness * 4000.0)) continue;
- //if on the same team
- if (BotSameTeam(bs, i)) continue;
- //if the bot's health decreased or the enemy is shooting
- if (curenemy < 0 && (healthdecrease || EntityIsShooting(&entinfo)))
- f = 360;
- else
- f = 90 + 90 - (90 - (squaredist > Square(810) ? Square(810) : squaredist) / (810 * 9));
- //check if the enemy is visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, f, i);
- if (vis <= 0) continue;
- //if the enemy is quite far away, not shooting and the bot is not damaged
- if (curenemy < 0 && squaredist > Square(100) && !healthdecrease && !EntityIsShooting(&entinfo))
- {
- //check if we can avoid this enemy
- VectorSubtract(bs->origin, entinfo.origin, dir);
- vectoangles(dir, angles);
- //if the bot isn't in the fov of the enemy
- if (!InFieldOfVision(entinfo.angles, 90, angles)) {
- //update some stuff for this enemy
- BotUpdateBattleInventory(bs, i);
- //if the bot doesn't really want to fight
- if (BotWantsToRetreat(bs)) continue;
- }
- }
- //found an enemy
- bs->enemy = entinfo.number;
- if (curenemy >= 0) bs->enemysight_time = FloatTime() - 2;
- else bs->enemysight_time = FloatTime();
- bs->enemysuicide = qfalse;
- bs->enemydeath_time = 0;
- bs->enemyvisible_time = FloatTime();
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-BotTeamFlagCarrierVisible
-==================
-*/
-int BotTeamFlagCarrierVisible(bot_state_t *bs) {
- int i;
- float vis;
- aas_entityinfo_t entinfo;
-
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client)
- continue;
- //
- BotEntityInfo(i, &entinfo);
- //if this player is active
- if (!entinfo.valid)
- continue;
- //if this player is carrying a flag
- if (!EntityCarriesFlag(&entinfo))
- continue;
- //if the flag carrier is not on the same team
- if (!BotSameTeam(bs, i))
- continue;
- //if the flag carrier is not visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
- if (vis <= 0)
- continue;
- //
- return i;
- }
- return -1;
-}
-
-/*
-==================
-BotTeamFlagCarrier
-==================
-*/
-int BotTeamFlagCarrier(bot_state_t *bs) {
- int i;
- aas_entityinfo_t entinfo;
-
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client)
- continue;
- //
- BotEntityInfo(i, &entinfo);
- //if this player is active
- if (!entinfo.valid)
- continue;
- //if this player is carrying a flag
- if (!EntityCarriesFlag(&entinfo))
- continue;
- //if the flag carrier is not on the same team
- if (!BotSameTeam(bs, i))
- continue;
- //
- return i;
- }
- return -1;
-}
-
-/*
-==================
-BotEnemyFlagCarrierVisible
-==================
-*/
-int BotEnemyFlagCarrierVisible(bot_state_t *bs) {
- int i;
- float vis;
- aas_entityinfo_t entinfo;
-
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client)
- continue;
- //
- BotEntityInfo(i, &entinfo);
- //if this player is active
- if (!entinfo.valid)
- continue;
- //if this player is carrying a flag
- if (!EntityCarriesFlag(&entinfo))
- continue;
- //if the flag carrier is on the same team
- if (BotSameTeam(bs, i))
- continue;
- //if the flag carrier is not visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
- if (vis <= 0)
- continue;
- //
- return i;
- }
- return -1;
-}
-
-/*
-==================
-BotVisibleTeamMatesAndEnemies
-==================
-*/
-void BotVisibleTeamMatesAndEnemies(bot_state_t *bs, int *teammates, int *enemies, float range) {
- int i;
- float vis;
- aas_entityinfo_t entinfo;
- vec3_t dir;
-
- if (teammates)
- *teammates = 0;
- if (enemies)
- *enemies = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client)
- continue;
- //
- BotEntityInfo(i, &entinfo);
- //if this player is active
- if (!entinfo.valid)
- continue;
- //if this player is carrying a flag
- if (!EntityCarriesFlag(&entinfo))
- continue;
- //if not within range
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) > Square(range))
- continue;
- //if the flag carrier is not visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
- if (vis <= 0)
- continue;
- //if the flag carrier is on the same team
- if (BotSameTeam(bs, i)) {
- if (teammates)
- (*teammates)++;
- }
- else {
- if (enemies)
- (*enemies)++;
- }
- }
-}
-
-#ifdef MISSIONPACK
-/*
-==================
-BotTeamCubeCarrierVisible
-==================
-*/
-int BotTeamCubeCarrierVisible(bot_state_t *bs) {
- int i;
- float vis;
- aas_entityinfo_t entinfo;
-
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client) continue;
- //
- BotEntityInfo(i, &entinfo);
- //if this player is active
- if (!entinfo.valid) continue;
- //if this player is carrying a flag
- if (!EntityCarriesCubes(&entinfo)) continue;
- //if the flag carrier is not on the same team
- if (!BotSameTeam(bs, i)) continue;
- //if the flag carrier is not visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
- if (vis <= 0) continue;
- //
- return i;
- }
- return -1;
-}
-
-/*
-==================
-BotEnemyCubeCarrierVisible
-==================
-*/
-int BotEnemyCubeCarrierVisible(bot_state_t *bs) {
- int i;
- float vis;
- aas_entityinfo_t entinfo;
-
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client)
- continue;
- //
- BotEntityInfo(i, &entinfo);
- //if this player is active
- if (!entinfo.valid)
- continue;
- //if this player is carrying a flag
- if (!EntityCarriesCubes(&entinfo)) continue;
- //if the flag carrier is on the same team
- if (BotSameTeam(bs, i))
- continue;
- //if the flag carrier is not visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
- if (vis <= 0)
- continue;
- //
- return i;
- }
- return -1;
-}
-#endif
-
-/*
-==================
-BotAimAtEnemy
-==================
-*/
-void BotAimAtEnemy(bot_state_t *bs) {
- int i, enemyvisible;
- float dist, f, aim_skill, aim_accuracy, speed, reactiontime;
- vec3_t dir, bestorigin, end, start, groundtarget, cmdmove, enemyvelocity;
- vec3_t mins = {-4,-4,-4}, maxs = {4, 4, 4};
- weaponinfo_t wi;
- aas_entityinfo_t entinfo;
- bot_goal_t goal;
- bsp_trace_t trace;
- vec3_t target;
-
- //if the bot has no enemy
- if (bs->enemy < 0) {
- return;
- }
- //get the enemy entity information
- BotEntityInfo(bs->enemy, &entinfo);
- //if this is not a player (should be an obelisk)
- if (bs->enemy >= MAX_CLIENTS) {
- //if the obelisk is visible
- VectorCopy(entinfo.origin, target);
-#ifdef MISSIONPACK
- // if attacking an obelisk
- if ( bs->enemy == redobelisk.entitynum ||
- bs->enemy == blueobelisk.entitynum ) {
- target[2] += 32;
- }
-#endif
- //aim at the obelisk
- VectorSubtract(target, bs->eye, dir);
- vectoangles(dir, bs->ideal_viewangles);
- //set the aim target before trying to attack
- VectorCopy(target, bs->aimtarget);
- return;
- }
- //
- //BotAI_Print(PRT_MESSAGE, "client %d: aiming at client %d\n", bs->entitynum, bs->enemy);
- //
- aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL, 0, 1);
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY, 0, 1);
- //
- if (aim_skill > 0.95) {
- //don't aim too early
- reactiontime = 0.5 * trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_REACTIONTIME, 0, 1);
- if (bs->enemysight_time > FloatTime() - reactiontime) return;
- if (bs->teleport_time > FloatTime() - reactiontime) return;
- }
-
- //get the weapon information
- trap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi);
- //get the weapon specific aim accuracy and or aim skill
- if (wi.number == WP_MACHINEGUN) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1);
- }
- else if (wi.number == WP_SHOTGUN) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_SHOTGUN, 0, 1);
- }
- else if (wi.number == WP_GRENADE_LAUNCHER) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_GRENADELAUNCHER, 0, 1);
- aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_GRENADELAUNCHER, 0, 1);
- }
- else if (wi.number == WP_ROCKET_LAUNCHER) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_ROCKETLAUNCHER, 0, 1);
- aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_ROCKETLAUNCHER, 0, 1);
- }
- else if (wi.number == WP_LIGHTNING) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_LIGHTNING, 0, 1);
- }
- else if (wi.number == WP_RAILGUN) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_RAILGUN, 0, 1);
- }
- else if (wi.number == WP_PLASMAGUN) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_PLASMAGUN, 0, 1);
- aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_PLASMAGUN, 0, 1);
- }
- else if (wi.number == WP_BFG) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_BFG10K, 0, 1);
- aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_BFG10K, 0, 1);
- }
- //
- if (aim_accuracy <= 0) aim_accuracy = 0.0001f;
- //get the enemy entity information
- BotEntityInfo(bs->enemy, &entinfo);
- //if the enemy is invisible then shoot crappy most of the time
- if (EntityIsInvisible(&entinfo)) {
- if (random() > 0.1) aim_accuracy *= 0.4f;
- }
- //
- VectorSubtract(entinfo.origin, entinfo.lastvisorigin, enemyvelocity);
- VectorScale(enemyvelocity, 1 / entinfo.update_time, enemyvelocity);
- //enemy origin and velocity is remembered every 0.5 seconds
- if (bs->enemyposition_time < FloatTime()) {
- //
- bs->enemyposition_time = FloatTime() + 0.5;
- VectorCopy(enemyvelocity, bs->enemyvelocity);
- VectorCopy(entinfo.origin, bs->enemyorigin);
- }
- //if not extremely skilled
- if (aim_skill < 0.9) {
- VectorSubtract(entinfo.origin, bs->enemyorigin, dir);
- //if the enemy moved a bit
- if (VectorLengthSquared(dir) > Square(48)) {
- //if the enemy changed direction
- if (DotProduct(bs->enemyvelocity, enemyvelocity) < 0) {
- //aim accuracy should be worse now
- aim_accuracy *= 0.7f;
- }
- }
- }
- //check visibility of enemy
- enemyvisible = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy);
- //if the enemy is visible
- if (enemyvisible) {
- //
- VectorCopy(entinfo.origin, bestorigin);
- bestorigin[2] += 8;
- //get the start point shooting from
- //NOTE: the x and y projectile start offsets are ignored
- VectorCopy(bs->origin, start);
- start[2] += bs->cur_ps.viewheight;
- start[2] += wi.offset[2];
- //
- BotAI_Trace(&trace, start, mins, maxs, bestorigin, bs->entitynum, MASK_SHOT);
- //if the enemy is NOT hit
- if (trace.fraction <= 1 && trace.ent != entinfo.number) {
- bestorigin[2] += 16;
- }
- //if it is not an instant hit weapon the bot might want to predict the enemy
- if (wi.speed) {
- //
- VectorSubtract(bestorigin, bs->origin, dir);
- dist = VectorLength(dir);
- VectorSubtract(entinfo.origin, bs->enemyorigin, dir);
- //if the enemy is NOT pretty far away and strafing just small steps left and right
- if (!(dist > 100 && VectorLengthSquared(dir) < Square(32))) {
- //if skilled anough do exact prediction
- if (aim_skill > 0.8 &&
- //if the weapon is ready to fire
- bs->cur_ps.weaponstate == WEAPON_READY) {
- aas_clientmove_t move;
- vec3_t origin;
-
- VectorSubtract(entinfo.origin, bs->origin, dir);
- //distance towards the enemy
- dist = VectorLength(dir);
- //direction the enemy is moving in
- VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir);
- //
- VectorScale(dir, 1 / entinfo.update_time, dir);
- //
- VectorCopy(entinfo.origin, origin);
- origin[2] += 1;
- //
- VectorClear(cmdmove);
- //AAS_ClearShownDebugLines();
- trap_AAS_PredictClientMovement(&move, bs->enemy, origin,
- PRESENCE_CROUCH, qfalse,
- dir, cmdmove, 0,
- dist * 10 / wi.speed, 0.1f, 0, 0, qfalse);
- VectorCopy(move.endpos, bestorigin);
- //BotAI_Print(PRT_MESSAGE, "%1.1f predicted speed = %f, frames = %f\n", FloatTime(), VectorLength(dir), dist * 10 / wi.speed);
- }
- //if not that skilled do linear prediction
- else if (aim_skill > 0.4) {
- VectorSubtract(entinfo.origin, bs->origin, dir);
- //distance towards the enemy
- dist = VectorLength(dir);
- //direction the enemy is moving in
- VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir);
- dir[2] = 0;
- //
- speed = VectorNormalize(dir) / entinfo.update_time;
- //botimport.Print(PRT_MESSAGE, "speed = %f, wi->speed = %f\n", speed, wi->speed);
- //best spot to aim at
- VectorMA(entinfo.origin, (dist / wi.speed) * speed, dir, bestorigin);
- }
- }
- }
- //if the projectile does radial damage
- if (aim_skill > 0.6 && wi.proj.damagetype & DAMAGETYPE_RADIAL) {
- //if the enemy isn't standing significantly higher than the bot
- if (entinfo.origin[2] < bs->origin[2] + 16) {
- //try to aim at the ground in front of the enemy
- VectorCopy(entinfo.origin, end);
- end[2] -= 64;
- BotAI_Trace(&trace, entinfo.origin, NULL, NULL, end, entinfo.number, MASK_SHOT);
- //
- VectorCopy(bestorigin, groundtarget);
- if (trace.startsolid) groundtarget[2] = entinfo.origin[2] - 16;
- else groundtarget[2] = trace.endpos[2] - 8;
- //trace a line from projectile start to ground target
- BotAI_Trace(&trace, start, NULL, NULL, groundtarget, bs->entitynum, MASK_SHOT);
- //if hitpoint is not vertically too far from the ground target
- if (fabs(trace.endpos[2] - groundtarget[2]) < 50) {
- VectorSubtract(trace.endpos, groundtarget, dir);
- //if the hitpoint is near anough the ground target
- if (VectorLengthSquared(dir) < Square(60)) {
- VectorSubtract(trace.endpos, start, dir);
- //if the hitpoint is far anough from the bot
- if (VectorLengthSquared(dir) > Square(100)) {
- //check if the bot is visible from the ground target
- trace.endpos[2] += 1;
- BotAI_Trace(&trace, trace.endpos, NULL, NULL, entinfo.origin, entinfo.number, MASK_SHOT);
- if (trace.fraction >= 1) {
- //botimport.Print(PRT_MESSAGE, "%1.1f aiming at ground\n", AAS_Time());
- VectorCopy(groundtarget, bestorigin);
- }
- }
- }
- }
- }
- }
- bestorigin[0] += 20 * crandom() * (1 - aim_accuracy);
- bestorigin[1] += 20 * crandom() * (1 - aim_accuracy);
- bestorigin[2] += 10 * crandom() * (1 - aim_accuracy);
- }
- else {
- //
- VectorCopy(bs->lastenemyorigin, bestorigin);
- bestorigin[2] += 8;
- //if the bot is skilled anough
- if (aim_skill > 0.5) {
- //do prediction shots around corners
- if (wi.number == WP_BFG ||
- wi.number == WP_ROCKET_LAUNCHER ||
- wi.number == WP_GRENADE_LAUNCHER) {
- //create the chase goal
- goal.entitynum = bs->client;
- goal.areanum = bs->areanum;
- VectorCopy(bs->eye, goal.origin);
- VectorSet(goal.mins, -8, -8, -8);
- VectorSet(goal.maxs, 8, 8, 8);
- //
- if (trap_BotPredictVisiblePosition(bs->lastenemyorigin, bs->lastenemyareanum, &goal, TFL_DEFAULT, target)) {
- VectorSubtract(target, bs->eye, dir);
- if (VectorLengthSquared(dir) > Square(80)) {
- VectorCopy(target, bestorigin);
- bestorigin[2] -= 20;
- }
- }
- aim_accuracy = 1;
- }
- }
- }
- //
- if (enemyvisible) {
- BotAI_Trace(&trace, bs->eye, NULL, NULL, bestorigin, bs->entitynum, MASK_SHOT);
- VectorCopy(trace.endpos, bs->aimtarget);
- }
- else {
- VectorCopy(bestorigin, bs->aimtarget);
- }
- //get aim direction
- VectorSubtract(bestorigin, bs->eye, dir);
- //
- if (wi.number == WP_MACHINEGUN ||
- wi.number == WP_SHOTGUN ||
- wi.number == WP_LIGHTNING ||
- wi.number == WP_RAILGUN) {
- //distance towards the enemy
- dist = VectorLength(dir);
- if (dist > 150) dist = 150;
- f = 0.6 + dist / 150 * 0.4;
- aim_accuracy *= f;
- }
- //add some random stuff to the aim direction depending on the aim accuracy
- if (aim_accuracy < 0.8) {
- VectorNormalize(dir);
- for (i = 0; i < 3; i++) dir[i] += 0.3 * crandom() * (1 - aim_accuracy);
- }
- //set the ideal view angles
- vectoangles(dir, bs->ideal_viewangles);
- //take the weapon spread into account for lower skilled bots
- bs->ideal_viewangles[PITCH] += 6 * wi.vspread * crandom() * (1 - aim_accuracy);
- bs->ideal_viewangles[PITCH] = AngleMod(bs->ideal_viewangles[PITCH]);
- bs->ideal_viewangles[YAW] += 6 * wi.hspread * crandom() * (1 - aim_accuracy);
- bs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]);
- //if the bots should be really challenging
- if (bot_challenge.integer) {
- //if the bot is really accurate and has the enemy in view for some time
- if (aim_accuracy > 0.9 && bs->enemysight_time < FloatTime() - 1) {
- //set the view angles directly
- if (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360;
- VectorCopy(bs->ideal_viewangles, bs->viewangles);
- trap_EA_View(bs->client, bs->viewangles);
- }
- }
-}
-
-/*
-==================
-BotCheckAttack
-==================
-*/
-void BotCheckAttack(bot_state_t *bs) {
- float points, reactiontime, fov, firethrottle;
- int attackentity;
- bsp_trace_t bsptrace;
- //float selfpreservation;
- vec3_t forward, right, start, end, dir, angles;
- weaponinfo_t wi;
- bsp_trace_t trace;
- aas_entityinfo_t entinfo;
- vec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8};
-
- attackentity = bs->enemy;
- //
- BotEntityInfo(attackentity, &entinfo);
- // if not attacking a player
- if (attackentity >= MAX_CLIENTS) {
-#ifdef MISSIONPACK
- // if attacking an obelisk
- if ( entinfo.number == redobelisk.entitynum ||
- entinfo.number == blueobelisk.entitynum ) {
- // if obelisk is respawning return
- if ( g_entities[entinfo.number].activator &&
- g_entities[entinfo.number].activator->s.frame == 2 ) {
- return;
- }
- }
-#endif
- }
- //
- reactiontime = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_REACTIONTIME, 0, 1);
- if (bs->enemysight_time > FloatTime() - reactiontime) return;
- if (bs->teleport_time > FloatTime() - reactiontime) return;
- //if changing weapons
- if (bs->weaponchange_time > FloatTime() - 0.1) return;
- //check fire throttle characteristic
- if (bs->firethrottlewait_time > FloatTime()) return;
- firethrottle = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_FIRETHROTTLE, 0, 1);
- if (bs->firethrottleshoot_time < FloatTime()) {
- if (random() > firethrottle) {
- bs->firethrottlewait_time = FloatTime() + firethrottle;
- bs->firethrottleshoot_time = 0;
- }
- else {
- bs->firethrottleshoot_time = FloatTime() + 1 - firethrottle;
- bs->firethrottlewait_time = 0;
- }
- }
- //
- //
- VectorSubtract(bs->aimtarget, bs->eye, dir);
- //
- if (bs->weaponnum == WP_GAUNTLET) {
- if (VectorLengthSquared(dir) > Square(60)) {
- return;
- }
- }
- if (VectorLengthSquared(dir) < Square(100))
- fov = 120;
- else
- fov = 50;
- //
- vectoangles(dir, angles);
- if (!InFieldOfVision(bs->viewangles, fov, angles))
- return;
- BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, bs->aimtarget, bs->client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- if (bsptrace.fraction < 1 && bsptrace.ent != attackentity)
- return;
-
- //get the weapon info
- trap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi);
- //get the start point shooting from
- VectorCopy(bs->origin, start);
- start[2] += bs->cur_ps.viewheight;
- AngleVectors(bs->viewangles, forward, right, NULL);
- start[0] += forward[0] * wi.offset[0] + right[0] * wi.offset[1];
- start[1] += forward[1] * wi.offset[0] + right[1] * wi.offset[1];
- start[2] += forward[2] * wi.offset[0] + right[2] * wi.offset[1] + wi.offset[2];
- //end point aiming at
- VectorMA(start, 1000, forward, end);
- //a little back to make sure not inside a very close enemy
- VectorMA(start, -12, forward, start);
- BotAI_Trace(&trace, start, mins, maxs, end, bs->entitynum, MASK_SHOT);
- //if the entity is a client
- if (trace.ent > 0 && trace.ent <= MAX_CLIENTS) {
- if (trace.ent != attackentity) {
- //if a teammate is hit
- if (BotSameTeam(bs, trace.ent))
- return;
- }
- }
- //if won't hit the enemy or not attacking a player (obelisk)
- if (trace.ent != attackentity || attackentity >= MAX_CLIENTS) {
- //if the projectile does radial damage
- if (wi.proj.damagetype & DAMAGETYPE_RADIAL) {
- if (trace.fraction * 1000 < wi.proj.radius) {
- points = (wi.proj.damage - 0.5 * trace.fraction * 1000) * 0.5;
- if (points > 0) {
- return;
- }
- }
- //FIXME: check if a teammate gets radial damage
- }
- }
- //if fire has to be release to activate weapon
- if (wi.flags & WFL_FIRERELEASED) {
- if (bs->flags & BFL_ATTACKED) {
- trap_EA_Attack(bs->client);
- }
- }
- else {
- trap_EA_Attack(bs->client);
- }
- bs->flags ^= BFL_ATTACKED;
-}
-
-/*
-==================
-BotMapScripts
-==================
-*/
-void BotMapScripts(bot_state_t *bs) {
- char info[1024];
- char mapname[128];
- int i, shootbutton;
- float aim_accuracy;
- aas_entityinfo_t entinfo;
- vec3_t dir;
-
- trap_GetServerinfo(info, sizeof(info));
-
- strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1);
- mapname[sizeof(mapname)-1] = '\0';
-
- if (!Q_stricmp(mapname, "q3tourney6")) {
- vec3_t mins = {700, 204, 672}, maxs = {964, 468, 680};
- vec3_t buttonorg = {304, 352, 920};
- //NOTE: NEVER use the func_bobbing in q3tourney6
- bs->tfl &= ~TFL_FUNCBOB;
- //if the bot is below the bounding box
- if (bs->origin[0] > mins[0] && bs->origin[0] < maxs[0]) {
- if (bs->origin[1] > mins[1] && bs->origin[1] < maxs[1]) {
- if (bs->origin[2] < mins[2]) {
- return;
- }
- }
- }
- shootbutton = qfalse;
- //if an enemy is below this bounding box then shoot the button
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
-
- if (i == bs->client) continue;
- //
- BotEntityInfo(i, &entinfo);
- //
- if (!entinfo.valid) continue;
- //if the enemy isn't dead and the enemy isn't the bot self
- if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;
- //
- if (entinfo.origin[0] > mins[0] && entinfo.origin[0] < maxs[0]) {
- if (entinfo.origin[1] > mins[1] && entinfo.origin[1] < maxs[1]) {
- if (entinfo.origin[2] < mins[2]) {
- //if there's a team mate below the crusher
- if (BotSameTeam(bs, i)) {
- shootbutton = qfalse;
- break;
- }
- else {
- shootbutton = qtrue;
- }
- }
- }
- }
- }
- if (shootbutton) {
- bs->flags |= BFL_IDEALVIEWSET;
- VectorSubtract(buttonorg, bs->eye, dir);
- vectoangles(dir, bs->ideal_viewangles);
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY, 0, 1);
- bs->ideal_viewangles[PITCH] += 8 * crandom() * (1 - aim_accuracy);
- bs->ideal_viewangles[PITCH] = AngleMod(bs->ideal_viewangles[PITCH]);
- bs->ideal_viewangles[YAW] += 8 * crandom() * (1 - aim_accuracy);
- bs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]);
- //
- if (InFieldOfVision(bs->viewangles, 20, bs->ideal_viewangles)) {
- trap_EA_Attack(bs->client);
- }
- }
- }
- else if (!Q_stricmp(mapname, "mpq3tourney6")) {
- //NOTE: NEVER use the func_bobbing in mpq3tourney6
- bs->tfl &= ~TFL_FUNCBOB;
- }
-}
-
-/*
-==================
-BotSetMovedir
-==================
-*/
-static vec3_t VEC_UP = {0, -1, 0};
-static vec3_t MOVEDIR_UP = {0, 0, 1};
-static vec3_t VEC_DOWN = {0, -2, 0};
-static vec3_t MOVEDIR_DOWN = {0, 0, -1};
-
-void BotSetMovedir(vec3_t angles, vec3_t movedir) {
- if (VectorCompare(angles, VEC_UP)) {
- VectorCopy(MOVEDIR_UP, movedir);
- }
- else if (VectorCompare(angles, VEC_DOWN)) {
- VectorCopy(MOVEDIR_DOWN, movedir);
- }
- else {
- AngleVectors(angles, movedir, NULL, NULL);
- }
-}
-
-/*
-==================
-BotModelMinsMaxs
-
-this is ugly
-==================
-*/
-int BotModelMinsMaxs(int modelindex, int eType, int contents, vec3_t mins, vec3_t maxs) {
- gentity_t *ent;
- int i;
-
- ent = &g_entities[0];
- for (i = 0; i < level.num_entities; i++, ent++) {
- if ( !ent->inuse ) {
- continue;
- }
- if ( eType && ent->s.eType != eType) {
- continue;
- }
- if ( contents && ent->r.contents != contents) {
- continue;
- }
- if (ent->s.modelindex == modelindex) {
- if (mins)
- VectorAdd(ent->r.currentOrigin, ent->r.mins, mins);
- if (maxs)
- VectorAdd(ent->r.currentOrigin, ent->r.maxs, maxs);
- return i;
- }
- }
- if (mins)
- VectorClear(mins);
- if (maxs)
- VectorClear(maxs);
- return 0;
-}
-
-/*
-==================
-BotFuncButtonGoal
-==================
-*/
-int BotFuncButtonActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) {
- int i, areas[10], numareas, modelindex, entitynum;
- char model[128];
- float lip, dist, health, angle;
- vec3_t size, start, end, mins, maxs, angles, points[10];
- vec3_t movedir, origin, goalorigin, bboxmins, bboxmaxs;
- vec3_t extramins = {1, 1, 1}, extramaxs = {-1, -1, -1};
- bsp_trace_t bsptrace;
-
- activategoal->shoot = qfalse;
- VectorClear(activategoal->target);
- //create a bot goal towards the button
- trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model));
- if (!*model)
- return qfalse;
- modelindex = atoi(model+1);
- if (!modelindex)
- return qfalse;
- VectorClear(angles);
- entitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs);
- //get the lip of the button
- trap_AAS_FloatForBSPEpairKey(bspent, "lip", &lip);
- if (!lip) lip = 4;
- //get the move direction from the angle
- trap_AAS_FloatForBSPEpairKey(bspent, "angle", &angle);
- VectorSet(angles, 0, angle, 0);
- BotSetMovedir(angles, movedir);
- //button size
- VectorSubtract(maxs, mins, size);
- //button origin
- VectorAdd(mins, maxs, origin);
- VectorScale(origin, 0.5, origin);
- //touch distance of the button
- dist = fabs(movedir[0]) * size[0] + fabs(movedir[1]) * size[1] + fabs(movedir[2]) * size[2];
- dist *= 0.5;
- //
- trap_AAS_FloatForBSPEpairKey(bspent, "health", &health);
- //if the button is shootable
- if (health) {
- //calculate the shoot target
- VectorMA(origin, -dist, movedir, goalorigin);
- //
- VectorCopy(goalorigin, activategoal->target);
- activategoal->shoot = qtrue;
- //
- BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, goalorigin, bs->entitynum, MASK_SHOT);
- // if the button is visible from the current position
- if (bsptrace.fraction >= 1.0 || bsptrace.ent == entitynum) {
- //
- activategoal->goal.entitynum = entitynum; //NOTE: this is the entity number of the shootable button
- activategoal->goal.number = 0;
- activategoal->goal.flags = 0;
- VectorCopy(bs->origin, activategoal->goal.origin);
- activategoal->goal.areanum = bs->areanum;
- VectorSet(activategoal->goal.mins, -8, -8, -8);
- VectorSet(activategoal->goal.maxs, 8, 8, 8);
- //
- return qtrue;
- }
- else {
- //create a goal from where the button is visible and shoot at the button from there
- //add bounding box size to the dist
- trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs);
- for (i = 0; i < 3; i++) {
- if (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]);
- else dist += fabs(movedir[i]) * fabs(bboxmins[i]);
- }
- //calculate the goal origin
- VectorMA(origin, -dist, movedir, goalorigin);
- //
- VectorCopy(goalorigin, start);
- start[2] += 24;
- VectorCopy(start, end);
- end[2] -= 512;
- numareas = trap_AAS_TraceAreas(start, end, areas, points, 10);
- //
- for (i = numareas-1; i >= 0; i--) {
- if (trap_AAS_AreaReachability(areas[i])) {
- break;
- }
- }
- if (i < 0) {
- // FIXME: trace forward and maybe in other directions to find a valid area
- }
- if (i >= 0) {
- //
- VectorCopy(points[i], activategoal->goal.origin);
- activategoal->goal.areanum = areas[i];
- VectorSet(activategoal->goal.mins, 8, 8, 8);
- VectorSet(activategoal->goal.maxs, -8, -8, -8);
- //
- for (i = 0; i < 3; i++)
- {
- if (movedir[i] < 0) activategoal->goal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]);
- else activategoal->goal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]);
- } //end for
- //
- activategoal->goal.entitynum = entitynum;
- activategoal->goal.number = 0;
- activategoal->goal.flags = 0;
- return qtrue;
- }
- }
- return qfalse;
- }
- else {
- //add bounding box size to the dist
- trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs);
- for (i = 0; i < 3; i++) {
- if (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]);
- else dist += fabs(movedir[i]) * fabs(bboxmins[i]);
- }
- //calculate the goal origin
- VectorMA(origin, -dist, movedir, goalorigin);
- //
- VectorCopy(goalorigin, start);
- start[2] += 24;
- VectorCopy(start, end);
- end[2] -= 100;
- numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10);
- //
- for (i = 0; i < numareas; i++) {
- if (trap_AAS_AreaReachability(areas[i])) {
- break;
- }
- }
- if (i < numareas) {
- //
- VectorCopy(origin, activategoal->goal.origin);
- activategoal->goal.areanum = areas[i];
- VectorSubtract(mins, origin, activategoal->goal.mins);
- VectorSubtract(maxs, origin, activategoal->goal.maxs);
- //
- for (i = 0; i < 3; i++)
- {
- if (movedir[i] < 0) activategoal->goal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]);
- else activategoal->goal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]);
- } //end for
- //
- activategoal->goal.entitynum = entitynum;
- activategoal->goal.number = 0;
- activategoal->goal.flags = 0;
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-==================
-BotFuncDoorGoal
-==================
-*/
-int BotFuncDoorActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) {
- int modelindex, entitynum;
- char model[MAX_INFO_STRING];
- vec3_t mins, maxs, origin, angles;
-
- //shoot at the shootable door
- trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model));
- if (!*model)
- return qfalse;
- modelindex = atoi(model+1);
- if (!modelindex)
- return qfalse;
- VectorClear(angles);
- entitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs);
- //door origin
- VectorAdd(mins, maxs, origin);
- VectorScale(origin, 0.5, origin);
- VectorCopy(origin, activategoal->target);
- activategoal->shoot = qtrue;
- //
- activategoal->goal.entitynum = entitynum; //NOTE: this is the entity number of the shootable door
- activategoal->goal.number = 0;
- activategoal->goal.flags = 0;
- VectorCopy(bs->origin, activategoal->goal.origin);
- activategoal->goal.areanum = bs->areanum;
- VectorSet(activategoal->goal.mins, -8, -8, -8);
- VectorSet(activategoal->goal.maxs, 8, 8, 8);
- return qtrue;
-}
-
-/*
-==================
-BotTriggerMultipleGoal
-==================
-*/
-int BotTriggerMultipleActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) {
- int i, areas[10], numareas, modelindex, entitynum;
- char model[128];
- vec3_t start, end, mins, maxs, angles;
- vec3_t origin, goalorigin;
-
- activategoal->shoot = qfalse;
- VectorClear(activategoal->target);
- //create a bot goal towards the trigger
- trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model));
- if (!*model)
- return qfalse;
- modelindex = atoi(model+1);
- if (!modelindex)
- return qfalse;
- VectorClear(angles);
- entitynum = BotModelMinsMaxs(modelindex, 0, CONTENTS_TRIGGER, mins, maxs);
- //trigger origin
- VectorAdd(mins, maxs, origin);
- VectorScale(origin, 0.5, origin);
- VectorCopy(origin, goalorigin);
- //
- VectorCopy(goalorigin, start);
- start[2] += 24;
- VectorCopy(start, end);
- end[2] -= 100;
- numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10);
- //
- for (i = 0; i < numareas; i++) {
- if (trap_AAS_AreaReachability(areas[i])) {
- break;
- }
- }
- if (i < numareas) {
- VectorCopy(origin, activategoal->goal.origin);
- activategoal->goal.areanum = areas[i];
- VectorSubtract(mins, origin, activategoal->goal.mins);
- VectorSubtract(maxs, origin, activategoal->goal.maxs);
- //
- activategoal->goal.entitynum = entitynum;
- activategoal->goal.number = 0;
- activategoal->goal.flags = 0;
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-BotPopFromActivateGoalStack
-==================
-*/
-int BotPopFromActivateGoalStack(bot_state_t *bs) {
- if (!bs->activatestack)
- return qfalse;
- BotEnableActivateGoalAreas(bs->activatestack, qtrue);
- bs->activatestack->inuse = qfalse;
- bs->activatestack->justused_time = FloatTime();
- bs->activatestack = bs->activatestack->next;
- return qtrue;
-}
-
-/*
-==================
-BotPushOntoActivateGoalStack
-==================
-*/
-int BotPushOntoActivateGoalStack(bot_state_t *bs, bot_activategoal_t *activategoal) {
- int i, best;
- float besttime;
-
- best = -1;
- besttime = FloatTime() + 9999;
- //
- for (i = 0; i < MAX_ACTIVATESTACK; i++) {
- if (!bs->activategoalheap[i].inuse) {
- if (bs->activategoalheap[i].justused_time < besttime) {
- besttime = bs->activategoalheap[i].justused_time;
- best = i;
- }
- }
- }
- if (best != -1) {
- memcpy(&bs->activategoalheap[best], activategoal, sizeof(bot_activategoal_t));
- bs->activategoalheap[best].inuse = qtrue;
- bs->activategoalheap[best].next = bs->activatestack;
- bs->activatestack = &bs->activategoalheap[best];
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-BotClearActivateGoalStack
-==================
-*/
-void BotClearActivateGoalStack(bot_state_t *bs) {
- while(bs->activatestack)
- BotPopFromActivateGoalStack(bs);
-}
-
-/*
-==================
-BotEnableActivateGoalAreas
-==================
-*/
-void BotEnableActivateGoalAreas(bot_activategoal_t *activategoal, int enable) {
- int i;
-
- if (activategoal->areasdisabled == !enable)
- return;
- for (i = 0; i < activategoal->numareas; i++)
- trap_AAS_EnableRoutingArea( activategoal->areas[i], enable );
- activategoal->areasdisabled = !enable;
-}
-
-/*
-==================
-BotIsGoingToActivateEntity
-==================
-*/
-int BotIsGoingToActivateEntity(bot_state_t *bs, int entitynum) {
- bot_activategoal_t *a;
- int i;
-
- for (a = bs->activatestack; a; a = a->next) {
- if (a->time < FloatTime())
- continue;
- if (a->goal.entitynum == entitynum)
- return qtrue;
- }
- for (i = 0; i < MAX_ACTIVATESTACK; i++) {
- if (bs->activategoalheap[i].inuse)
- continue;
- //
- if (bs->activategoalheap[i].goal.entitynum == entitynum) {
- // if the bot went for this goal less than 2 seconds ago
- if (bs->activategoalheap[i].justused_time > FloatTime() - 2)
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-==================
-BotGetActivateGoal
-
- returns the number of the bsp entity to activate
- goal->entitynum will be set to the game entity to activate
-==================
-*/
-//#define OBSTACLEDEBUG
-
-int BotGetActivateGoal(bot_state_t *bs, int entitynum, bot_activategoal_t *activategoal) {
- int i, ent, cur_entities[10], spawnflags, modelindex, areas[MAX_ACTIVATEAREAS*2], numareas, t;
- char model[MAX_INFO_STRING], tmpmodel[128];
- char target[128], classname[128];
- float health;
- char targetname[10][128];
- aas_entityinfo_t entinfo;
- aas_areainfo_t areainfo;
- vec3_t origin, angles, absmins, absmaxs;
-
- memset(activategoal, 0, sizeof(bot_activategoal_t));
- BotEntityInfo(entitynum, &entinfo);
- Com_sprintf(model, sizeof( model ), "*%d", entinfo.modelindex);
- for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) {
- if (!trap_AAS_ValueForBSPEpairKey(ent, "model", tmpmodel, sizeof(tmpmodel))) continue;
- if (!strcmp(model, tmpmodel)) break;
- }
- if (!ent) {
- BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no entity found with model %s\n", model);
- return 0;
- }
- trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname));
- if (!*classname) {
- BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with model %s has no classname\n", model);
- return 0;
- }
- //if it is a door
- if (!strcmp(classname, "func_door")) {
- if (trap_AAS_FloatForBSPEpairKey(ent, "health", &health)) {
- //if the door has health then the door must be shot to open
- if (health) {
- BotFuncDoorActivateGoal(bs, ent, activategoal);
- return ent;
- }
- }
- //
- trap_AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags);
- // if the door starts open then just wait for the door to return
- if ( spawnflags & 1 )
- return 0;
- //get the door origin
- if (!trap_AAS_VectorForBSPEpairKey(ent, "origin", origin)) {
- VectorClear(origin);
- }
- //if the door is open or opening already
- if (!VectorCompare(origin, entinfo.origin))
- return 0;
- // store all the areas the door is in
- trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model));
- if (*model) {
- modelindex = atoi(model+1);
- if (modelindex) {
- VectorClear(angles);
- BotModelMinsMaxs(modelindex, ET_MOVER, 0, absmins, absmaxs);
- //
- numareas = trap_AAS_BBoxAreas(absmins, absmaxs, areas, MAX_ACTIVATEAREAS*2);
- // store the areas with reachabilities first
- for (i = 0; i < numareas; i++) {
- if (activategoal->numareas >= MAX_ACTIVATEAREAS)
- break;
- if ( !trap_AAS_AreaReachability(areas[i]) ) {
- continue;
- }
- trap_AAS_AreaInfo(areas[i], &areainfo);
- if (areainfo.contents & AREACONTENTS_MOVER) {
- activategoal->areas[activategoal->numareas++] = areas[i];
- }
- }
- // store any remaining areas
- for (i = 0; i < numareas; i++) {
- if (activategoal->numareas >= MAX_ACTIVATEAREAS)
- break;
- if ( trap_AAS_AreaReachability(areas[i]) ) {
- continue;
- }
- trap_AAS_AreaInfo(areas[i], &areainfo);
- if (areainfo.contents & AREACONTENTS_MOVER) {
- activategoal->areas[activategoal->numareas++] = areas[i];
- }
- }
- }
- }
- }
- // if the bot is blocked by or standing on top of a button
- if (!strcmp(classname, "func_button")) {
- return 0;
- }
- // get the targetname so we can find an entity with a matching target
- if (!trap_AAS_ValueForBSPEpairKey(ent, "targetname", targetname[0], sizeof(targetname[0]))) {
- if (bot_developer.integer) {
- BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with model \"%s\" has no targetname\n", model);
- }
- return 0;
- }
- // allow tree-like activation
- cur_entities[0] = trap_AAS_NextBSPEntity(0);
- for (i = 0; i >= 0 && i < 10;) {
- for (ent = cur_entities[i]; ent; ent = trap_AAS_NextBSPEntity(ent)) {
- if (!trap_AAS_ValueForBSPEpairKey(ent, "target", target, sizeof(target))) continue;
- if (!strcmp(targetname[i], target)) {
- cur_entities[i] = trap_AAS_NextBSPEntity(ent);
- break;
- }
- }
- if (!ent) {
- if (bot_developer.integer) {
- BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no entity with target \"%s\"\n", targetname[i]);
- }
- i--;
- continue;
- }
- if (!trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname))) {
- if (bot_developer.integer) {
- BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with target \"%s\" has no classname\n", targetname[i]);
- }
- continue;
- }
- // BSP button model
- if (!strcmp(classname, "func_button")) {
- //
- if (!BotFuncButtonActivateGoal(bs, ent, activategoal))
- continue;
- // if the bot tries to activate this button already
- if ( bs->activatestack && bs->activatestack->inuse &&
- bs->activatestack->goal.entitynum == activategoal->goal.entitynum &&
- bs->activatestack->time > FloatTime() &&
- bs->activatestack->start_time < FloatTime() - 2)
- continue;
- // if the bot is in a reachability area
- if ( trap_AAS_AreaReachability(bs->areanum) ) {
- // disable all areas the blocking entity is in
- BotEnableActivateGoalAreas( activategoal, qfalse );
- //
- t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, activategoal->goal.areanum, bs->tfl);
- // if the button is not reachable
- if (!t) {
- continue;
- }
- activategoal->time = FloatTime() + t * 0.01 + 5;
- }
- return ent;
- }
- // invisible trigger multiple box
- else if (!strcmp(classname, "trigger_multiple")) {
- //
- if (!BotTriggerMultipleActivateGoal(bs, ent, activategoal))
- continue;
- // if the bot tries to activate this trigger already
- if ( bs->activatestack && bs->activatestack->inuse &&
- bs->activatestack->goal.entitynum == activategoal->goal.entitynum &&
- bs->activatestack->time > FloatTime() &&
- bs->activatestack->start_time < FloatTime() - 2)
- continue;
- // if the bot is in a reachability area
- if ( trap_AAS_AreaReachability(bs->areanum) ) {
- // disable all areas the blocking entity is in
- BotEnableActivateGoalAreas( activategoal, qfalse );
- //
- t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, activategoal->goal.areanum, bs->tfl);
- // if the trigger is not reachable
- if (!t) {
- continue;
- }
- activategoal->time = FloatTime() + t * 0.01 + 5;
- }
- return ent;
- }
- else if (!strcmp(classname, "func_timer")) {
- // just skip the func_timer
- continue;
- }
- // the actual button or trigger might be linked through a target_relay or target_delay
- else if (!strcmp(classname, "target_relay") || !strcmp(classname, "target_delay")) {
- if (trap_AAS_ValueForBSPEpairKey(ent, "targetname", targetname[i+1], sizeof(targetname[0]))) {
- i++;
- cur_entities[i] = trap_AAS_NextBSPEntity(0);
- }
- }
- }
-#ifdef OBSTACLEDEBUG
- BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no valid activator for entity with target \"%s\"\n", targetname[0]);
-#endif
- return 0;
-}
-
-/*
-==================
-BotGoForActivateGoal
-==================
-*/
-int BotGoForActivateGoal(bot_state_t *bs, bot_activategoal_t *activategoal) {
- aas_entityinfo_t activateinfo;
-
- activategoal->inuse = qtrue;
- if (!activategoal->time)
- activategoal->time = FloatTime() + 10;
- activategoal->start_time = FloatTime();
- BotEntityInfo(activategoal->goal.entitynum, &activateinfo);
- VectorCopy(activateinfo.origin, activategoal->origin);
- //
- if (BotPushOntoActivateGoalStack(bs, activategoal)) {
- // enter the activate entity AI node
- AIEnter_Seek_ActivateEntity(bs, "BotGoForActivateGoal");
- return qtrue;
- }
- else {
- // enable any routing areas that were disabled
- BotEnableActivateGoalAreas(activategoal, qtrue);
- return qfalse;
- }
-}
-
-/*
-==================
-BotPrintActivateGoalInfo
-==================
-*/
-void BotPrintActivateGoalInfo(bot_state_t *bs, bot_activategoal_t *activategoal, int bspent) {
- char netname[MAX_NETNAME];
- char classname[128];
- char buf[128];
-
- ClientName(bs->client, netname, sizeof(netname));
- trap_AAS_ValueForBSPEpairKey(bspent, "classname", classname, sizeof(classname));
- if (activategoal->shoot) {
- Com_sprintf(buf, sizeof(buf), "%s: I have to shoot at a %s from %1.1f %1.1f %1.1f in area %d\n",
- netname, classname,
- activategoal->goal.origin[0],
- activategoal->goal.origin[1],
- activategoal->goal.origin[2],
- activategoal->goal.areanum);
- }
- else {
- Com_sprintf(buf, sizeof(buf), "%s: I have to activate a %s at %1.1f %1.1f %1.1f in area %d\n",
- netname, classname,
- activategoal->goal.origin[0],
- activategoal->goal.origin[1],
- activategoal->goal.origin[2],
- activategoal->goal.areanum);
- }
- trap_EA_Say(bs->client, buf);
-}
-
-/*
-==================
-BotRandomMove
-==================
-*/
-void BotRandomMove(bot_state_t *bs, bot_moveresult_t *moveresult) {
- vec3_t dir, angles;
-
- angles[0] = 0;
- angles[1] = random() * 360;
- angles[2] = 0;
- AngleVectors(angles, dir, NULL, NULL);
-
- trap_BotMoveInDirection(bs->ms, dir, 400, MOVE_WALK);
-
- moveresult->failure = qfalse;
- VectorCopy(dir, moveresult->movedir);
-}
-
-/*
-==================
-BotAIBlocked
-
-Very basic handling of bots being blocked by other entities.
-Check what kind of entity is blocking the bot and try to activate
-it. If that's not an option then try to walk around or over the entity.
-Before the bot ends in this part of the AI it should predict which doors to
-open, which buttons to activate etc.
-==================
-*/
-void BotAIBlocked(bot_state_t *bs, bot_moveresult_t *moveresult, int activate) {
- int movetype, bspent;
- vec3_t hordir, start, end, mins, maxs, sideward, angles, up = {0, 0, 1};
- aas_entityinfo_t entinfo;
- bot_activategoal_t activategoal;
-
- // if the bot is not blocked by anything
- if (!moveresult->blocked) {
- bs->notblocked_time = FloatTime();
- return;
- }
- // if stuck in a solid area
- if ( moveresult->type == RESULTTYPE_INSOLIDAREA ) {
- // move in a random direction in the hope to get out
- BotRandomMove(bs, moveresult);
- //
- return;
- }
- // get info for the entity that is blocking the bot
- BotEntityInfo(moveresult->blockentity, &entinfo);
-#ifdef OBSTACLEDEBUG
- ClientName(bs->client, netname, sizeof(netname));
- BotAI_Print(PRT_MESSAGE, "%s: I'm blocked by model %d\n", netname, entinfo.modelindex);
-#endif // OBSTACLEDEBUG
- // if blocked by a bsp model and the bot wants to activate it
- if (activate && entinfo.modelindex > 0 && entinfo.modelindex <= max_bspmodelindex) {
- // find the bsp entity which should be activated in order to get the blocking entity out of the way
- bspent = BotGetActivateGoal(bs, entinfo.number, &activategoal);
- if (bspent) {
- //
- if (bs->activatestack && !bs->activatestack->inuse)
- bs->activatestack = NULL;
- // if not already trying to activate this entity
- if (!BotIsGoingToActivateEntity(bs, activategoal.goal.entitynum)) {
- //
- BotGoForActivateGoal(bs, &activategoal);
- }
- // if ontop of an obstacle or
- // if the bot is not in a reachability area it'll still
- // need some dynamic obstacle avoidance, otherwise return
- if (!(moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE) &&
- trap_AAS_AreaReachability(bs->areanum))
- return;
- }
- else {
- // enable any routing areas that were disabled
- BotEnableActivateGoalAreas(&activategoal, qtrue);
- }
- }
- // just some basic dynamic obstacle avoidance code
- hordir[0] = moveresult->movedir[0];
- hordir[1] = moveresult->movedir[1];
- hordir[2] = 0;
- // if no direction just take a random direction
- if (VectorNormalize(hordir) < 0.1) {
- VectorSet(angles, 0, 360 * random(), 0);
- AngleVectors(angles, hordir, NULL, NULL);
- }
- //
- //if (moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE) movetype = MOVE_JUMP;
- //else
- movetype = MOVE_WALK;
- // if there's an obstacle at the bot's feet and head then
- // the bot might be able to crouch through
- VectorCopy(bs->origin, start);
- start[2] += 18;
- VectorMA(start, 5, hordir, end);
- VectorSet(mins, -16, -16, -24);
- VectorSet(maxs, 16, 16, 4);
- //
- //bsptrace = AAS_Trace(start, mins, maxs, end, bs->entitynum, MASK_PLAYERSOLID);
- //if (bsptrace.fraction >= 1) movetype = MOVE_CROUCH;
- // get the sideward vector
- CrossProduct(hordir, up, sideward);
- //
- if (bs->flags & BFL_AVOIDRIGHT) VectorNegate(sideward, sideward);
- // try to crouch straight forward?
- if (movetype != MOVE_CROUCH || !trap_BotMoveInDirection(bs->ms, hordir, 400, movetype)) {
- // perform the movement
- if (!trap_BotMoveInDirection(bs->ms, sideward, 400, movetype)) {
- // flip the avoid direction flag
- bs->flags ^= BFL_AVOIDRIGHT;
- // flip the direction
- // VectorNegate(sideward, sideward);
- VectorMA(sideward, -1, hordir, sideward);
- // move in the other direction
- trap_BotMoveInDirection(bs->ms, sideward, 400, movetype);
- }
- }
- //
- if (bs->notblocked_time < FloatTime() - 0.4) {
- // just reset goals and hope the bot will go into another direction?
- // is this still needed??
- if (bs->ainode == AINode_Seek_NBG) bs->nbg_time = 0;
- else if (bs->ainode == AINode_Seek_LTG) bs->ltg_time = 0;
- }
-}
-
-/*
-==================
-BotAIPredictObstacles
-
-Predict the route towards the goal and check if the bot
-will be blocked by certain obstacles. When the bot has obstacles
-on it's path the bot should figure out if they can be removed
-by activating certain entities.
-==================
-*/
-int BotAIPredictObstacles(bot_state_t *bs, bot_goal_t *goal) {
- int modelnum, entitynum, bspent;
- bot_activategoal_t activategoal;
- aas_predictroute_t route;
-
- if (!bot_predictobstacles.integer)
- return qfalse;
-
- // always predict when the goal change or at regular intervals
- if (bs->predictobstacles_goalareanum == goal->areanum &&
- bs->predictobstacles_time > FloatTime() - 6) {
- return qfalse;
- }
- bs->predictobstacles_goalareanum = goal->areanum;
- bs->predictobstacles_time = FloatTime();
-
- // predict at most 100 areas or 10 seconds ahead
- trap_AAS_PredictRoute(&route, bs->areanum, bs->origin,
- goal->areanum, bs->tfl, 100, 1000,
- RSE_USETRAVELTYPE|RSE_ENTERCONTENTS,
- AREACONTENTS_MOVER, TFL_BRIDGE, 0);
- // if bot has to travel through an area with a mover
- if (route.stopevent & RSE_ENTERCONTENTS) {
- // if the bot will run into a mover
- if (route.endcontents & AREACONTENTS_MOVER) {
- //NOTE: this only works with bspc 2.1 or higher
- modelnum = (route.endcontents & AREACONTENTS_MODELNUM) >> AREACONTENTS_MODELNUMSHIFT;
- if (modelnum) {
- //
- entitynum = BotModelMinsMaxs(modelnum, ET_MOVER, 0, NULL, NULL);
- if (entitynum) {
- //NOTE: BotGetActivateGoal already checks if the door is open or not
- bspent = BotGetActivateGoal(bs, entitynum, &activategoal);
- if (bspent) {
- //
- if (bs->activatestack && !bs->activatestack->inuse)
- bs->activatestack = NULL;
- // if not already trying to activate this entity
- if (!BotIsGoingToActivateEntity(bs, activategoal.goal.entitynum)) {
- //
- //BotAI_Print(PRT_MESSAGE, "blocked by mover model %d, entity %d ?\n", modelnum, entitynum);
- //
- BotGoForActivateGoal(bs, &activategoal);
- return qtrue;
- }
- else {
- // enable any routing areas that were disabled
- BotEnableActivateGoalAreas(&activategoal, qtrue);
- }
- }
- }
- }
- }
- }
- else if (route.stopevent & RSE_USETRAVELTYPE) {
- if (route.endtravelflags & TFL_BRIDGE) {
- //FIXME: check if the bridge is available to travel over
- }
- }
- return qfalse;
-}
-
-/*
-==================
-BotCheckConsoleMessages
-==================
-*/
-void BotCheckConsoleMessages(bot_state_t *bs) {
- char botname[MAX_NETNAME], message[MAX_MESSAGE_SIZE], netname[MAX_NETNAME], *ptr;
- float chat_reply;
- int context, handle;
- bot_consolemessage_t m;
- bot_match_t match;
-
- //the name of this bot
- ClientName(bs->client, botname, sizeof(botname));
- //
- while((handle = trap_BotNextConsoleMessage(bs->cs, &m)) != 0) {
- //if the chat state is flooded with messages the bot will read them quickly
- if (trap_BotNumConsoleMessages(bs->cs) < 10) {
- //if it is a chat message the bot needs some time to read it
- if (m.type == CMS_CHAT && m.time > FloatTime() - (1 + random())) break;
- }
- //
- ptr = m.message;
- //if it is a chat message then don't unify white spaces and don't
- //replace synonyms in the netname
- if (m.type == CMS_CHAT) {
- //
- if (trap_BotFindMatch(m.message, &match, MTCONTEXT_REPLYCHAT)) {
- ptr = m.message + match.variables[MESSAGE].offset;
- }
- }
- //unify the white spaces in the message
- trap_UnifyWhiteSpaces(ptr);
- //replace synonyms in the right context
- context = BotSynonymContext(bs);
- trap_BotReplaceSynonyms(ptr, context);
- //if there's no match
- if (!BotMatchMessage(bs, m.message)) {
- //if it is a chat message
- if (m.type == CMS_CHAT && !bot_nochat.integer) {
- //
- if (!trap_BotFindMatch(m.message, &match, MTCONTEXT_REPLYCHAT)) {
- trap_BotRemoveConsoleMessage(bs->cs, handle);
- continue;
- }
- //don't use eliza chats with team messages
- if (match.subtype & ST_TEAM) {
- trap_BotRemoveConsoleMessage(bs->cs, handle);
- continue;
- }
- //
- trap_BotMatchVariable(&match, NETNAME, netname, sizeof(netname));
- trap_BotMatchVariable(&match, MESSAGE, message, sizeof(message));
- //if this is a message from the bot self
- if (bs->client == ClientFromName(netname)) {
- trap_BotRemoveConsoleMessage(bs->cs, handle);
- continue;
- }
- //unify the message
- trap_UnifyWhiteSpaces(message);
- //
- trap_Cvar_Update(&bot_testrchat);
- if (bot_testrchat.integer) {
- //
- trap_BotLibVarSet("bot_testrchat", "1");
- //if bot replies with a chat message
- if (trap_BotReplyChat(bs->cs, message, context, CONTEXT_REPLY,
- NULL, NULL,
- NULL, NULL,
- NULL, NULL,
- botname, netname)) {
- BotAI_Print(PRT_MESSAGE, "------------------------\n");
- }
- else {
- BotAI_Print(PRT_MESSAGE, "**** no valid reply ****\n");
- }
- }
- //if at a valid chat position and not chatting already and not in teamplay
- else if (bs->ainode != AINode_Stand && BotValidChatPosition(bs) && !TeamPlayIsOn()) {
- chat_reply = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_REPLY, 0, 1);
- if (random() < 1.5 / (NumBots()+1) && random() < chat_reply) {
- //if bot replies with a chat message
- if (trap_BotReplyChat(bs->cs, message, context, CONTEXT_REPLY,
- NULL, NULL,
- NULL, NULL,
- NULL, NULL,
- botname, netname)) {
- //remove the console message
- trap_BotRemoveConsoleMessage(bs->cs, handle);
- bs->stand_time = FloatTime() + BotChatTime(bs);
- AIEnter_Stand(bs, "BotCheckConsoleMessages: reply chat");
- //EA_Say(bs->client, bs->cs.chatmessage);
- break;
- }
- }
- }
- }
- }
- //remove the console message
- trap_BotRemoveConsoleMessage(bs->cs, handle);
- }
-}
-
-/*
-==================
-BotCheckEvents
-==================
-*/
-void BotCheckForGrenades(bot_state_t *bs, entityState_t *state) {
- // if this is not a grenade
- if (state->eType != ET_MISSILE || state->weapon != WP_GRENADE_LAUNCHER)
- return;
- // try to avoid the grenade
- trap_BotAddAvoidSpot(bs->ms, state->pos.trBase, 160, AVOID_ALWAYS);
-}
-
-#ifdef MISSIONPACK
-/*
-==================
-BotCheckForProxMines
-==================
-*/
-void BotCheckForProxMines(bot_state_t *bs, entityState_t *state) {
- // if this is not a prox mine
- if (state->eType != ET_MISSILE || state->weapon != WP_PROX_LAUNCHER)
- return;
- // if this prox mine is from someone on our own team
- if (state->generic1 == BotTeam(bs))
- return;
- // if the bot doesn't have a weapon to deactivate the mine
- if (!(bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0) &&
- !(bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0) &&
- !(bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0) ) {
- return;
- }
- // try to avoid the prox mine
- trap_BotAddAvoidSpot(bs->ms, state->pos.trBase, 160, AVOID_ALWAYS);
- //
- if (bs->numproxmines >= MAX_PROXMINES)
- return;
- bs->proxmines[bs->numproxmines] = state->number;
- bs->numproxmines++;
-}
-
-/*
-==================
-BotCheckForKamikazeBody
-==================
-*/
-void BotCheckForKamikazeBody(bot_state_t *bs, entityState_t *state) {
- // if this entity is not wearing the kamikaze
- if (!(state->eFlags & EF_KAMIKAZE))
- return;
- // if this entity isn't dead
- if (!(state->eFlags & EF_DEAD))
- return;
- //remember this kamikaze body
- bs->kamikazebody = state->number;
-}
-#endif
-
-/*
-==================
-BotCheckEvents
-==================
-*/
-void BotCheckEvents(bot_state_t *bs, entityState_t *state) {
- int event;
- char buf[128];
-#ifdef MISSIONPACK
- aas_entityinfo_t entinfo;
-#endif
-
- //NOTE: this sucks, we're accessing the gentity_t directly
- //but there's no other fast way to do it right now
- if (bs->entityeventTime[state->number] == g_entities[state->number].eventTime) {
- return;
- }
- bs->entityeventTime[state->number] = g_entities[state->number].eventTime;
- //if it's an event only entity
- if (state->eType > ET_EVENTS) {
- event = (state->eType - ET_EVENTS) & ~EV_EVENT_BITS;
- }
- else {
- event = state->event & ~EV_EVENT_BITS;
- }
- //
- switch(event) {
- //client obituary event
- case EV_OBITUARY:
- {
- int target, attacker, mod;
-
- target = state->otherEntityNum;
- attacker = state->otherEntityNum2;
- mod = state->eventParm;
- //
- if (target == bs->client) {
- bs->botdeathtype = mod;
- bs->lastkilledby = attacker;
- //
- if (target == attacker ||
- target == ENTITYNUM_NONE ||
- target == ENTITYNUM_WORLD) bs->botsuicide = qtrue;
- else bs->botsuicide = qfalse;
- //
- bs->num_deaths++;
- }
- //else if this client was killed by the bot
- else if (attacker == bs->client) {
- bs->enemydeathtype = mod;
- bs->lastkilledplayer = target;
- bs->killedenemy_time = FloatTime();
- //
- bs->num_kills++;
- }
- else if (attacker == bs->enemy && target == attacker) {
- bs->enemysuicide = qtrue;
- }
- //
-#ifdef MISSIONPACK
- if (gametype == GT_1FCTF) {
- //
- BotEntityInfo(target, &entinfo);
- if ( entinfo.powerups & ( 1 << PW_NEUTRALFLAG ) ) {
- if (!BotSameTeam(bs, target)) {
- bs->neutralflagstatus = 3; //enemy dropped the flag
- bs->flagstatuschanged = qtrue;
- }
- }
- }
-#endif
- break;
- }
- case EV_GLOBAL_SOUND:
- {
- if (state->eventParm < 0 || state->eventParm > MAX_SOUNDS) {
- BotAI_Print(PRT_ERROR, "EV_GLOBAL_SOUND: eventParm (%d) out of range\n", state->eventParm);
- break;
- }
- trap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf));
- /*
- if (!strcmp(buf, "sound/teamplay/flagret_red.wav")) {
- //red flag is returned
- bs->redflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- }
- else if (!strcmp(buf, "sound/teamplay/flagret_blu.wav")) {
- //blue flag is returned
- bs->blueflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- }
- else*/
-#ifdef MISSIONPACK
- if (!strcmp(buf, "sound/items/kamikazerespawn.wav" )) {
- //the kamikaze respawned so dont avoid it
- BotDontAvoid(bs, "Kamikaze");
- }
- else
-#endif
- if (!strcmp(buf, "sound/items/poweruprespawn.wav")) {
- //powerup respawned... go get it
- BotGoForPowerups(bs);
- }
- break;
- }
- case EV_GLOBAL_TEAM_SOUND:
- {
- if (gametype == GT_CTF) {
- switch(state->eventParm) {
- case GTS_RED_CAPTURE:
- bs->blueflagstatus = 0;
- bs->redflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break; //see BotMatch_CTF
- case GTS_BLUE_CAPTURE:
- bs->blueflagstatus = 0;
- bs->redflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break; //see BotMatch_CTF
- case GTS_RED_RETURN:
- //blue flag is returned
- bs->blueflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_BLUE_RETURN:
- //red flag is returned
- bs->redflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_RED_TAKEN:
- //blue flag is taken
- bs->blueflagstatus = 1;
- bs->flagstatuschanged = qtrue;
- break; //see BotMatch_CTF
- case GTS_BLUE_TAKEN:
- //red flag is taken
- bs->redflagstatus = 1;
- bs->flagstatuschanged = qtrue;
- break; //see BotMatch_CTF
- }
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- switch(state->eventParm) {
- case GTS_RED_CAPTURE:
- bs->neutralflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_BLUE_CAPTURE:
- bs->neutralflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_RED_RETURN:
- //flag has returned
- bs->neutralflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_BLUE_RETURN:
- //flag has returned
- bs->neutralflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_RED_TAKEN:
- bs->neutralflagstatus = BotTeam(bs) == TEAM_RED ? 2 : 1; //FIXME: check Team_TakeFlagSound in g_team.c
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_BLUE_TAKEN:
- bs->neutralflagstatus = BotTeam(bs) == TEAM_BLUE ? 2 : 1; //FIXME: check Team_TakeFlagSound in g_team.c
- bs->flagstatuschanged = qtrue;
- break;
- }
- }
-#endif
- break;
- }
- case EV_PLAYER_TELEPORT_IN:
- {
- VectorCopy(state->origin, lastteleport_origin);
- lastteleport_time = FloatTime();
- break;
- }
- case EV_GENERAL_SOUND:
- {
- //if this sound is played on the bot
- if (state->number == bs->client) {
- if (state->eventParm < 0 || state->eventParm > MAX_SOUNDS) {
- BotAI_Print(PRT_ERROR, "EV_GENERAL_SOUND: eventParm (%d) out of range\n", state->eventParm);
- break;
- }
- //check out the sound
- trap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf));
- //if falling into a death pit
- if (!strcmp(buf, "*falling1.wav")) {
- //if the bot has a personal teleporter
- if (bs->inventory[INVENTORY_TELEPORTER] > 0) {
- //use the holdable item
- trap_EA_Use(bs->client);
- }
- }
- }
- break;
- }
- case EV_FOOTSTEP:
- case EV_FOOTSTEP_METAL:
- case EV_FOOTSPLASH:
- case EV_FOOTWADE:
- case EV_SWIM:
- case EV_FALL_SHORT:
- case EV_FALL_MEDIUM:
- case EV_FALL_FAR:
- case EV_STEP_4:
- case EV_STEP_8:
- case EV_STEP_12:
- case EV_STEP_16:
- case EV_JUMP_PAD:
- case EV_JUMP:
- case EV_TAUNT:
- case EV_WATER_TOUCH:
- case EV_WATER_LEAVE:
- case EV_WATER_UNDER:
- case EV_WATER_CLEAR:
- case EV_ITEM_PICKUP:
- case EV_GLOBAL_ITEM_PICKUP:
- case EV_NOAMMO:
- case EV_CHANGE_WEAPON:
- case EV_FIRE_WEAPON:
- //FIXME: either add to sound queue or mark player as someone making noise
- break;
- case EV_USE_ITEM0:
- case EV_USE_ITEM1:
- case EV_USE_ITEM2:
- case EV_USE_ITEM3:
- case EV_USE_ITEM4:
- case EV_USE_ITEM5:
- case EV_USE_ITEM6:
- case EV_USE_ITEM7:
- case EV_USE_ITEM8:
- case EV_USE_ITEM9:
- case EV_USE_ITEM10:
- case EV_USE_ITEM11:
- case EV_USE_ITEM12:
- case EV_USE_ITEM13:
- case EV_USE_ITEM14:
- break;
- }
-}
-
-/*
-==================
-BotCheckSnapshot
-==================
-*/
-void BotCheckSnapshot(bot_state_t *bs) {
- int ent;
- entityState_t state;
-
- //remove all avoid spots
- trap_BotAddAvoidSpot(bs->ms, vec3_origin, 0, AVOID_CLEAR);
- //reset kamikaze body
- bs->kamikazebody = 0;
- //reset number of proxmines
- bs->numproxmines = 0;
- //
- ent = 0;
- while( ( ent = BotAI_GetSnapshotEntity( bs->client, ent, &state ) ) != -1 ) {
- //check the entity state for events
- BotCheckEvents(bs, &state);
- //check for grenades the bot should avoid
- BotCheckForGrenades(bs, &state);
- //
-#ifdef MISSIONPACK
- //check for proximity mines which the bot should deactivate
- BotCheckForProxMines(bs, &state);
- //check for dead bodies with the kamikaze effect which should be gibbed
- BotCheckForKamikazeBody(bs, &state);
-#endif
- }
- //check the player state for events
- BotAI_GetEntityState(bs->client, &state);
- //copy the player state events to the entity state
- state.event = bs->cur_ps.externalEvent;
- state.eventParm = bs->cur_ps.externalEventParm;
- //
- BotCheckEvents(bs, &state);
-}
-
-/*
-==================
-BotCheckAir
-==================
-*/
-void BotCheckAir(bot_state_t *bs) {
- if (bs->inventory[INVENTORY_ENVIRONMENTSUIT] <= 0) {
- if (trap_AAS_PointContents(bs->eye) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) {
- return;
- }
- }
- bs->lastair_time = FloatTime();
-}
-
-/*
-==================
-BotAlternateRoute
-==================
-*/
-bot_goal_t *BotAlternateRoute(bot_state_t *bs, bot_goal_t *goal) {
- int t;
-
- // if the bot has an alternative route goal
- if (bs->altroutegoal.areanum) {
- //
- if (bs->reachedaltroutegoal_time)
- return goal;
- // travel time towards alternative route goal
- t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, bs->altroutegoal.areanum, bs->tfl);
- if (t && t < 20) {
- //BotAI_Print(PRT_MESSAGE, "reached alternate route goal\n");
- bs->reachedaltroutegoal_time = FloatTime();
- }
- memcpy(goal, &bs->altroutegoal, sizeof(bot_goal_t));
- return &bs->altroutegoal;
- }
- return goal;
-}
-
-/*
-==================
-BotGetAlternateRouteGoal
-==================
-*/
-int BotGetAlternateRouteGoal(bot_state_t *bs, int base) {
- aas_altroutegoal_t *altroutegoals;
- bot_goal_t *goal;
- int numaltroutegoals, rnd;
-
- if (base == TEAM_RED) {
- altroutegoals = red_altroutegoals;
- numaltroutegoals = red_numaltroutegoals;
- }
- else {
- altroutegoals = blue_altroutegoals;
- numaltroutegoals = blue_numaltroutegoals;
- }
- if (!numaltroutegoals)
- return qfalse;
- rnd = (float) random() * numaltroutegoals;
- if (rnd >= numaltroutegoals)
- rnd = numaltroutegoals-1;
- goal = &bs->altroutegoal;
- goal->areanum = altroutegoals[rnd].areanum;
- VectorCopy(altroutegoals[rnd].origin, goal->origin);
- VectorSet(goal->mins, -8, -8, -8);
- VectorSet(goal->maxs, 8, 8, 8);
- goal->entitynum = 0;
- goal->iteminfo = 0;
- goal->number = 0;
- goal->flags = 0;
- //
- bs->reachedaltroutegoal_time = 0;
- return qtrue;
-}
-
-/*
-==================
-BotSetupAlternateRouteGoals
-==================
-*/
-void BotSetupAlternativeRouteGoals(void) {
-
- if (altroutegoals_setup)
- return;
-#ifdef MISSIONPACK
- if (gametype == GT_CTF) {
- if (trap_BotGetLevelItemGoal(-1, "Neutral Flag", &ctf_neutralflag) < 0)
- BotAI_Print(PRT_WARNING, "no alt routes without Neutral Flag\n");
- if (ctf_neutralflag.areanum) {
- //
- red_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- ctf_neutralflag.origin, ctf_neutralflag.areanum,
- ctf_redflag.origin, ctf_redflag.areanum, TFL_DEFAULT,
- red_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- ctf_neutralflag.origin, ctf_neutralflag.areanum,
- ctf_blueflag.origin, ctf_blueflag.areanum, TFL_DEFAULT,
- blue_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- }
- }
- else if (gametype == GT_1FCTF) {
- //
- red_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- ctf_neutralflag.origin, ctf_neutralflag.areanum,
- ctf_redflag.origin, ctf_redflag.areanum, TFL_DEFAULT,
- red_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- ctf_neutralflag.origin, ctf_neutralflag.areanum,
- ctf_blueflag.origin, ctf_blueflag.areanum, TFL_DEFAULT,
- blue_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- }
- else if (gametype == GT_OBELISK) {
- if (trap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0)
- BotAI_Print(PRT_WARNING, "Harvester without neutral obelisk\n");
- //
- red_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- neutralobelisk.origin, neutralobelisk.areanum,
- redobelisk.origin, redobelisk.areanum, TFL_DEFAULT,
- red_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- neutralobelisk.origin, neutralobelisk.areanum,
- blueobelisk.origin, blueobelisk.areanum, TFL_DEFAULT,
- blue_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- }
- else if (gametype == GT_HARVESTER) {
- //
- red_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- neutralobelisk.origin, neutralobelisk.areanum,
- redobelisk.origin, redobelisk.areanum, TFL_DEFAULT,
- red_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- neutralobelisk.origin, neutralobelisk.areanum,
- blueobelisk.origin, blueobelisk.areanum, TFL_DEFAULT,
- blue_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- }
-#endif
- altroutegoals_setup = qtrue;
-}
-
-/*
-==================
-BotDeathmatchAI
-==================
-*/
-void BotDeathmatchAI(bot_state_t *bs, float thinktime) {
- char gender[144], name[144], buf[144];
- char userinfo[MAX_INFO_STRING];
- int i;
-
- //if the bot has just been setup
- if (bs->setupcount > 0) {
- bs->setupcount--;
- if (bs->setupcount > 0) return;
- //get the gender characteristic
- trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, sizeof(gender));
- //set the bot gender
- trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo));
- Info_SetValueForKey(userinfo, "sex", gender);
- trap_SetUserinfo(bs->client, userinfo);
- //set the team
- if ( !bs->map_restart && g_gametype.integer != GT_TOURNAMENT ) {
- Com_sprintf(buf, sizeof(buf), "team %s", bs->settings.team);
- trap_EA_Command(bs->client, buf);
- }
- //set the chat gender
- if (gender[0] == 'm') trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE);
- else if (gender[0] == 'f') trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE);
- else trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS);
- //set the chat name
- ClientName(bs->client, name, sizeof(name));
- trap_BotSetChatName(bs->cs, name, bs->client);
- //
- bs->lastframe_health = bs->inventory[INVENTORY_HEALTH];
- bs->lasthitcount = bs->cur_ps.persistant[PERS_HITS];
- //
- bs->setupcount = 0;
- //
- BotSetupAlternativeRouteGoals();
- }
- //no ideal view set
- bs->flags &= ~BFL_IDEALVIEWSET;
- //
- if (!BotIntermission(bs)) {
- //set the teleport time
- BotSetTeleportTime(bs);
- //update some inventory values
- BotUpdateInventory(bs);
- //check out the snapshot
- BotCheckSnapshot(bs);
- //check for air
- BotCheckAir(bs);
- }
- //check the console messages
- BotCheckConsoleMessages(bs);
- //if not in the intermission and not in observer mode
- if (!BotIntermission(bs) && !BotIsObserver(bs)) {
- //do team AI
- BotTeamAI(bs);
- }
- //if the bot has no ai node
- if (!bs->ainode) {
- AIEnter_Seek_LTG(bs, "BotDeathmatchAI: no ai node");
- }
- //if the bot entered the game less than 8 seconds ago
- if (!bs->entergamechat && bs->entergame_time > FloatTime() - 8) {
- if (BotChat_EnterGame(bs)) {
- bs->stand_time = FloatTime() + BotChatTime(bs);
- AIEnter_Stand(bs, "BotDeathmatchAI: chat enter game");
- }
- bs->entergamechat = qtrue;
- }
- //reset the node switches from the previous frame
- BotResetNodeSwitches();
- //execute AI nodes
- for (i = 0; i < MAX_NODESWITCHES; i++) {
- if (bs->ainode(bs)) break;
- }
- //if the bot removed itself :)
- if (!bs->inuse) return;
- //if the bot executed too many AI nodes
- if (i >= MAX_NODESWITCHES) {
- trap_BotDumpGoalStack(bs->gs);
- trap_BotDumpAvoidGoals(bs->gs);
- BotDumpNodeSwitches(bs);
- ClientName(bs->client, name, sizeof(name));
- BotAI_Print(PRT_ERROR, "%s at %1.1f switched more than %d AI nodes\n", name, FloatTime(), MAX_NODESWITCHES);
- }
- //
- bs->lastframe_health = bs->inventory[INVENTORY_HEALTH];
- bs->lasthitcount = bs->cur_ps.persistant[PERS_HITS];
-}
-
-/*
-==================
-BotSetEntityNumForGoalWithModel
-==================
-*/
-void BotSetEntityNumForGoalWithModel(bot_goal_t *goal, int eType, char *modelname) {
- gentity_t *ent;
- int i, modelindex;
- vec3_t dir;
-
- modelindex = G_ModelIndex( modelname );
- ent = &g_entities[0];
- for (i = 0; i < level.num_entities; i++, ent++) {
- if ( !ent->inuse ) {
- continue;
- }
- if ( eType && ent->s.eType != eType) {
- continue;
- }
- if (ent->s.modelindex != modelindex) {
- continue;
- }
- VectorSubtract(goal->origin, ent->s.origin, dir);
- if (VectorLengthSquared(dir) < Square(10)) {
- goal->entitynum = i;
- return;
- }
- }
-}
-
-/*
-==================
-BotSetEntityNumForGoal
-==================
-*/
-void BotSetEntityNumForGoal(bot_goal_t *goal, char *classname) {
- gentity_t *ent;
- int i;
- vec3_t dir;
-
- ent = &g_entities[0];
- for (i = 0; i < level.num_entities; i++, ent++) {
- if ( !ent->inuse ) {
- continue;
- }
- if ( !Q_stricmp(ent->classname, classname) ) {
- continue;
- }
- VectorSubtract(goal->origin, ent->s.origin, dir);
- if (VectorLengthSquared(dir) < Square(10)) {
- goal->entitynum = i;
- return;
- }
- }
-}
-
-/*
-==================
-BotGoalForBSPEntity
-==================
-*/
-int BotGoalForBSPEntity( char *classname, bot_goal_t *goal ) {
- char value[MAX_INFO_STRING];
- vec3_t origin, start, end;
- int ent, numareas, areas[10];
-
- memset(goal, 0, sizeof(bot_goal_t));
- for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) {
- if (!trap_AAS_ValueForBSPEpairKey(ent, "classname", value, sizeof(value)))
- continue;
- if (!strcmp(value, classname)) {
- if (!trap_AAS_VectorForBSPEpairKey(ent, "origin", origin))
- return qfalse;
- VectorCopy(origin, goal->origin);
- VectorCopy(origin, start);
- start[2] -= 32;
- VectorCopy(origin, end);
- end[2] += 32;
- numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10);
- if (!numareas)
- return qfalse;
- goal->areanum = areas[0];
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-==================
-BotSetupDeathmatchAI
-==================
-*/
-void BotSetupDeathmatchAI(void) {
- int ent, modelnum;
- char model[128];
-
- gametype = trap_Cvar_VariableIntegerValue("g_gametype");
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- trap_Cvar_Register(&bot_rocketjump, "bot_rocketjump", "1", 0);
- trap_Cvar_Register(&bot_grapple, "bot_grapple", "0", 0);
- trap_Cvar_Register(&bot_fastchat, "bot_fastchat", "0", 0);
- trap_Cvar_Register(&bot_nochat, "bot_nochat", "0", 0);
- trap_Cvar_Register(&bot_testrchat, "bot_testrchat", "0", 0);
- trap_Cvar_Register(&bot_challenge, "bot_challenge", "0", 0);
- trap_Cvar_Register(&bot_predictobstacles, "bot_predictobstacles", "1", 0);
- trap_Cvar_Register(&g_spSkill, "g_spSkill", "2", 0);
- //
- if (gametype == GT_CTF) {
- if (trap_BotGetLevelItemGoal(-1, "Red Flag", &ctf_redflag) < 0)
- BotAI_Print(PRT_WARNING, "CTF without Red Flag\n");
- if (trap_BotGetLevelItemGoal(-1, "Blue Flag", &ctf_blueflag) < 0)
- BotAI_Print(PRT_WARNING, "CTF without Blue Flag\n");
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- if (trap_BotGetLevelItemGoal(-1, "Neutral Flag", &ctf_neutralflag) < 0)
- BotAI_Print(PRT_WARNING, "One Flag CTF without Neutral Flag\n");
- if (trap_BotGetLevelItemGoal(-1, "Red Flag", &ctf_redflag) < 0)
- BotAI_Print(PRT_WARNING, "CTF without Red Flag\n");
- if (trap_BotGetLevelItemGoal(-1, "Blue Flag", &ctf_blueflag) < 0)
- BotAI_Print(PRT_WARNING, "CTF without Blue Flag\n");
- }
- else if (gametype == GT_OBELISK) {
- if (trap_BotGetLevelItemGoal(-1, "Red Obelisk", &redobelisk) < 0)
- BotAI_Print(PRT_WARNING, "Obelisk without red obelisk\n");
- BotSetEntityNumForGoal(&redobelisk, "team_redobelisk");
- if (trap_BotGetLevelItemGoal(-1, "Blue Obelisk", &blueobelisk) < 0)
- BotAI_Print(PRT_WARNING, "Obelisk without blue obelisk\n");
- BotSetEntityNumForGoal(&blueobelisk, "team_blueobelisk");
- }
- else if (gametype == GT_HARVESTER) {
- if (trap_BotGetLevelItemGoal(-1, "Red Obelisk", &redobelisk) < 0)
- BotAI_Print(PRT_WARNING, "Harvester without red obelisk\n");
- BotSetEntityNumForGoal(&redobelisk, "team_redobelisk");
- if (trap_BotGetLevelItemGoal(-1, "Blue Obelisk", &blueobelisk) < 0)
- BotAI_Print(PRT_WARNING, "Harvester without blue obelisk\n");
- BotSetEntityNumForGoal(&blueobelisk, "team_blueobelisk");
- if (trap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0)
- BotAI_Print(PRT_WARNING, "Harvester without neutral obelisk\n");
- BotSetEntityNumForGoal(&neutralobelisk, "team_neutralobelisk");
- }
-#endif
-
- max_bspmodelindex = 0;
- for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) {
- if (!trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model))) continue;
- if (model[0] == '*') {
- modelnum = atoi(model+1);
- if (modelnum > max_bspmodelindex)
- max_bspmodelindex = modelnum;
- }
- }
- //initialize the waypoint heap
- BotInitWaypoints();
-}
-
-/*
-==================
-BotShutdownDeathmatchAI
-==================
-*/
-void BotShutdownDeathmatchAI(void) {
- altroutegoals_setup = qfalse;
-}
diff --git a/engine/code/game/ai_dmq3.h b/engine/code/game/ai_dmq3.h
deleted file mode 100644
index f6829be..0000000
--- a/engine/code/game/ai_dmq3.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_dmq3.h
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /source/code/botai/ai_chat.c $
- *
- *****************************************************************************/
-
-//setup the deathmatch AI
-void BotSetupDeathmatchAI(void);
-//shutdown the deathmatch AI
-void BotShutdownDeathmatchAI(void);
-//let the bot live within it's deathmatch AI net
-void BotDeathmatchAI(bot_state_t *bs, float thinktime);
-//free waypoints
-void BotFreeWaypoints(bot_waypoint_t *wp);
-//choose a weapon
-void BotChooseWeapon(bot_state_t *bs);
-//setup movement stuff
-void BotSetupForMovement(bot_state_t *bs);
-//update the inventory
-void BotUpdateInventory(bot_state_t *bs);
-//update the inventory during battle
-void BotUpdateBattleInventory(bot_state_t *bs, int enemy);
-//use holdable items during battle
-void BotBattleUseItems(bot_state_t *bs);
-//return true if the bot is dead
-qboolean BotIsDead(bot_state_t *bs);
-//returns true if the bot is in observer mode
-qboolean BotIsObserver(bot_state_t *bs);
-//returns true if the bot is in the intermission
-qboolean BotIntermission(bot_state_t *bs);
-//returns true if the bot is in lava or slime
-qboolean BotInLavaOrSlime(bot_state_t *bs);
-//returns true if the entity is dead
-qboolean EntityIsDead(aas_entityinfo_t *entinfo);
-//returns true if the entity is invisible
-qboolean EntityIsInvisible(aas_entityinfo_t *entinfo);
-//returns true if the entity is shooting
-qboolean EntityIsShooting(aas_entityinfo_t *entinfo);
-#ifdef MISSIONPACK
-//returns true if this entity has the kamikaze
-qboolean EntityHasKamikaze(aas_entityinfo_t *entinfo);
-#endif
-// set a user info key/value pair
-void BotSetUserInfo(bot_state_t *bs, char *key, char *value);
-// set the team status (offense, defense etc.)
-void BotSetTeamStatus(bot_state_t *bs);
-//returns the name of the client
-char *ClientName(int client, char *name, int size);
-//returns an simplyfied client name
-char *EasyClientName(int client, char *name, int size);
-//returns the skin used by the client
-char *ClientSkin(int client, char *skin, int size);
-// returns the appropriate synonym context for the current game type and situation
-int BotSynonymContext(bot_state_t *bs);
-// set last ordered task
-int BotSetLastOrderedTask(bot_state_t *bs);
-// selection of goals for teamplay
-void BotTeamGoals(bot_state_t *bs, int retreat);
-//returns the aggression of the bot in the range [0, 100]
-float BotAggression(bot_state_t *bs);
-//returns how bad the bot feels
-float BotFeelingBad(bot_state_t *bs);
-//returns true if the bot wants to retreat
-int BotWantsToRetreat(bot_state_t *bs);
-//returns true if the bot wants to chase
-int BotWantsToChase(bot_state_t *bs);
-//returns true if the bot wants to help
-int BotWantsToHelp(bot_state_t *bs);
-//returns true if the bot can and wants to rocketjump
-int BotCanAndWantsToRocketJump(bot_state_t *bs);
-// returns true if the bot has a persistant powerup and a weapon
-int BotHasPersistantPowerupAndWeapon(bot_state_t *bs);
-//returns true if the bot wants to and goes camping
-int BotWantsToCamp(bot_state_t *bs);
-//the bot will perform attack movements
-bot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl);
-//returns true if the bot and the entity are in the same team
-int BotSameTeam(bot_state_t *bs, int entnum);
-//returns true if teamplay is on
-int TeamPlayIsOn(void);
-// returns the client number of the team mate flag carrier (-1 if none)
-int BotTeamFlagCarrier(bot_state_t *bs);
-//returns visible team mate flag carrier if available
-int BotTeamFlagCarrierVisible(bot_state_t *bs);
-//returns visible enemy flag carrier if available
-int BotEnemyFlagCarrierVisible(bot_state_t *bs);
-//get the number of visible teammates and enemies
-void BotVisibleTeamMatesAndEnemies(bot_state_t *bs, int *teammates, int *enemies, float range);
-//returns true if within the field of vision for the given angles
-qboolean InFieldOfVision(vec3_t viewangles, float fov, vec3_t angles);
-//returns true and sets the .enemy field when an enemy is found
-int BotFindEnemy(bot_state_t *bs, int curenemy);
-//returns a roam goal
-void BotRoamGoal(bot_state_t *bs, vec3_t goal);
-//returns entity visibility in the range [0, 1]
-float BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int ent);
-//the bot will aim at the current enemy
-void BotAimAtEnemy(bot_state_t *bs);
-//check if the bot should attack
-void BotCheckAttack(bot_state_t *bs);
-//AI when the bot is blocked
-void BotAIBlocked(bot_state_t *bs, bot_moveresult_t *moveresult, int activate);
-//AI to predict obstacles
-int BotAIPredictObstacles(bot_state_t *bs, bot_goal_t *goal);
-//enable or disable the areas the blocking entity is in
-void BotEnableActivateGoalAreas(bot_activategoal_t *activategoal, int enable);
-//pop an activate goal from the stack
-int BotPopFromActivateGoalStack(bot_state_t *bs);
-//clear the activate goal stack
-void BotClearActivateGoalStack(bot_state_t *bs);
-//returns the team the bot is in
-int BotTeam(bot_state_t *bs);
-//retuns the opposite team of the bot
-int BotOppositeTeam(bot_state_t *bs);
-//returns the flag the bot is carrying (CTFFLAG_?)
-int BotCTFCarryingFlag(bot_state_t *bs);
-//remember the last ordered task
-void BotRememberLastOrderedTask(bot_state_t *bs);
-//set ctf goals (defend base, get enemy flag) during seek
-void BotCTFSeekGoals(bot_state_t *bs);
-//set ctf goals (defend base, get enemy flag) during retreat
-void BotCTFRetreatGoals(bot_state_t *bs);
-//
-#ifdef MISSIONPACK
-int Bot1FCTFCarryingFlag(bot_state_t *bs);
-int BotHarvesterCarryingCubes(bot_state_t *bs);
-void Bot1FCTFSeekGoals(bot_state_t *bs);
-void Bot1FCTFRetreatGoals(bot_state_t *bs);
-void BotObeliskSeekGoals(bot_state_t *bs);
-void BotObeliskRetreatGoals(bot_state_t *bs);
-void BotGoHarvest(bot_state_t *bs);
-void BotHarvesterSeekGoals(bot_state_t *bs);
-void BotHarvesterRetreatGoals(bot_state_t *bs);
-int BotTeamCubeCarrierVisible(bot_state_t *bs);
-int BotEnemyCubeCarrierVisible(bot_state_t *bs);
-#endif
-//get a random alternate route goal towards the given base
-int BotGetAlternateRouteGoal(bot_state_t *bs, int base);
-//returns either the alternate route goal or the given goal
-bot_goal_t *BotAlternateRoute(bot_state_t *bs, bot_goal_t *goal);
-//create a new waypoint
-bot_waypoint_t *BotCreateWayPoint(char *name, vec3_t origin, int areanum);
-//find a waypoint with the given name
-bot_waypoint_t *BotFindWayPoint(bot_waypoint_t *waypoints, char *name);
-//strstr but case insensitive
-char *stristr(char *str, char *charset);
-//returns the number of the client with the given name
-int ClientFromName(char *name);
-int ClientOnSameTeamFromName(bot_state_t *bs, char *name);
-//
-int BotPointAreaNum(vec3_t origin);
-//
-void BotMapScripts(bot_state_t *bs);
-
-//ctf flags
-#define CTF_FLAG_NONE 0
-#define CTF_FLAG_RED 1
-#define CTF_FLAG_BLUE 2
-//CTF skins
-#define CTF_SKIN_REDTEAM "red"
-#define CTF_SKIN_BLUETEAM "blue"
-
-extern int gametype; //game type
-extern int maxclients; //maximum number of clients
-
-extern vmCvar_t bot_grapple;
-extern vmCvar_t bot_rocketjump;
-extern vmCvar_t bot_fastchat;
-extern vmCvar_t bot_nochat;
-extern vmCvar_t bot_testrchat;
-extern vmCvar_t bot_challenge;
-
-extern bot_goal_t ctf_redflag;
-extern bot_goal_t ctf_blueflag;
-#ifdef MISSIONPACK
-extern bot_goal_t ctf_neutralflag;
-extern bot_goal_t redobelisk;
-extern bot_goal_t blueobelisk;
-extern bot_goal_t neutralobelisk;
-#endif
diff --git a/engine/code/game/ai_main.c b/engine/code/game/ai_main.c
deleted file mode 100644
index fb37c28..0000000
--- a/engine/code/game/ai_main.c
+++ /dev/null
@@ -1,1698 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_main.c
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /MissionPack/code/game/ai_main.c $
- *
- *****************************************************************************/
-
-
-#include "g_local.h"
-#include "../qcommon/q_shared.h"
-#include "../botlib/botlib.h" //bot lib interface
-#include "../botlib/be_aas.h"
-#include "../botlib/be_ea.h"
-#include "../botlib/be_ai_char.h"
-#include "../botlib/be_ai_chat.h"
-#include "../botlib/be_ai_gen.h"
-#include "../botlib/be_ai_goal.h"
-#include "../botlib/be_ai_move.h"
-#include "../botlib/be_ai_weap.h"
-//
-#include "ai_main.h"
-#include "ai_dmq3.h"
-#include "ai_chat.h"
-#include "ai_cmd.h"
-#include "ai_dmnet.h"
-#include "ai_vcmd.h"
-
-//
-#include "chars.h"
-#include "inv.h"
-#include "syn.h"
-
-#ifndef MAX_PATH
-#define MAX_PATH 144
-#endif
-
-
-//bot states
-bot_state_t *botstates[MAX_CLIENTS];
-//number of bots
-int numbots;
-//floating point time
-float floattime;
-//time to do a regular update
-float regularupdate_time;
-//
-int bot_interbreed;
-int bot_interbreedmatchcount;
-//
-vmCvar_t bot_thinktime;
-vmCvar_t bot_memorydump;
-vmCvar_t bot_saveroutingcache;
-vmCvar_t bot_pause;
-vmCvar_t bot_report;
-vmCvar_t bot_testsolid;
-vmCvar_t bot_testclusters;
-vmCvar_t bot_developer;
-vmCvar_t bot_interbreedchar;
-vmCvar_t bot_interbreedbots;
-vmCvar_t bot_interbreedcycle;
-vmCvar_t bot_interbreedwrite;
-
-
-void ExitLevel( void );
-
-
-/*
-==================
-BotAI_Print
-==================
-*/
-void QDECL BotAI_Print(int type, char *fmt, ...) {
- char str[2048];
- va_list ap;
-
- va_start(ap, fmt);
- Q_vsnprintf(str, sizeof(str), fmt, ap);
- va_end(ap);
-
- switch(type) {
- case PRT_MESSAGE: {
- G_Printf("%s", str);
- break;
- }
- case PRT_WARNING: {
- G_Printf( S_COLOR_YELLOW "Warning: %s", str );
- break;
- }
- case PRT_ERROR: {
- G_Printf( S_COLOR_RED "Error: %s", str );
- break;
- }
- case PRT_FATAL: {
- G_Printf( S_COLOR_RED "Fatal: %s", str );
- break;
- }
- case PRT_EXIT: {
- G_Error( S_COLOR_RED "Exit: %s", str );
- break;
- }
- default: {
- G_Printf( "unknown print type\n" );
- break;
- }
- }
-}
-
-
-/*
-==================
-BotAI_Trace
-==================
-*/
-void BotAI_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) {
- trace_t trace;
-
- trap_Trace(&trace, start, mins, maxs, end, passent, contentmask);
- //copy the trace information
- bsptrace->allsolid = trace.allsolid;
- bsptrace->startsolid = trace.startsolid;
- bsptrace->fraction = trace.fraction;
- VectorCopy(trace.endpos, bsptrace->endpos);
- bsptrace->plane.dist = trace.plane.dist;
- VectorCopy(trace.plane.normal, bsptrace->plane.normal);
- bsptrace->plane.signbits = trace.plane.signbits;
- bsptrace->plane.type = trace.plane.type;
- bsptrace->surface.value = trace.surfaceFlags;
- bsptrace->ent = trace.entityNum;
- bsptrace->exp_dist = 0;
- bsptrace->sidenum = 0;
- bsptrace->contents = 0;
-}
-
-/*
-==================
-BotAI_GetClientState
-==================
-*/
-int BotAI_GetClientState( int clientNum, playerState_t *state ) {
- gentity_t *ent;
-
- ent = &g_entities[clientNum];
- if ( !ent->inuse ) {
- return qfalse;
- }
- if ( !ent->client ) {
- return qfalse;
- }
-
- memcpy( state, &ent->client->ps, sizeof(playerState_t) );
- return qtrue;
-}
-
-/*
-==================
-BotAI_GetEntityState
-==================
-*/
-int BotAI_GetEntityState( int entityNum, entityState_t *state ) {
- gentity_t *ent;
-
- ent = &g_entities[entityNum];
- memset( state, 0, sizeof(entityState_t) );
- if (!ent->inuse) return qfalse;
- if (!ent->r.linked) return qfalse;
- if (ent->r.svFlags & SVF_NOCLIENT) return qfalse;
- memcpy( state, &ent->s, sizeof(entityState_t) );
- return qtrue;
-}
-
-/*
-==================
-BotAI_GetSnapshotEntity
-==================
-*/
-int BotAI_GetSnapshotEntity( int clientNum, int sequence, entityState_t *state ) {
- int entNum;
-
- entNum = trap_BotGetSnapshotEntity( clientNum, sequence );
- if ( entNum == -1 ) {
- memset(state, 0, sizeof(entityState_t));
- return -1;
- }
-
- BotAI_GetEntityState( entNum, state );
-
- return sequence + 1;
-}
-
-/*
-==================
-BotAI_BotInitialChat
-==================
-*/
-void QDECL BotAI_BotInitialChat( bot_state_t *bs, char *type, ... ) {
- int i, mcontext;
- va_list ap;
- char *p;
- char *vars[MAX_MATCHVARIABLES];
-
- memset(vars, 0, sizeof(vars));
- va_start(ap, type);
- p = va_arg(ap, char *);
- for (i = 0; i < MAX_MATCHVARIABLES; i++) {
- if( !p ) {
- break;
- }
- vars[i] = p;
- p = va_arg(ap, char *);
- }
- va_end(ap);
-
- mcontext = BotSynonymContext(bs);
-
- trap_BotInitialChat( bs->cs, type, mcontext, vars[0], vars[1], vars[2], vars[3], vars[4], vars[5], vars[6], vars[7] );
-}
-
-
-/*
-==================
-BotTestAAS
-==================
-*/
-void BotTestAAS(vec3_t origin) {
- int areanum;
- aas_areainfo_t info;
-
- trap_Cvar_Update(&bot_testsolid);
- trap_Cvar_Update(&bot_testclusters);
- if (bot_testsolid.integer) {
- if (!trap_AAS_Initialized()) return;
- areanum = BotPointAreaNum(origin);
- if (areanum) BotAI_Print(PRT_MESSAGE, "\remtpy area");
- else BotAI_Print(PRT_MESSAGE, "\r^1SOLID area");
- }
- else if (bot_testclusters.integer) {
- if (!trap_AAS_Initialized()) return;
- areanum = BotPointAreaNum(origin);
- if (!areanum)
- BotAI_Print(PRT_MESSAGE, "\r^1Solid! ");
- else {
- trap_AAS_AreaInfo(areanum, &info);
- BotAI_Print(PRT_MESSAGE, "\rarea %d, cluster %d ", areanum, info.cluster);
- }
- }
-}
-
-/*
-==================
-BotReportStatus
-==================
-*/
-void BotReportStatus(bot_state_t *bs) {
- char goalname[MAX_MESSAGE_SIZE];
- char netname[MAX_MESSAGE_SIZE];
- char *leader, flagstatus[32];
- //
- ClientName(bs->client, netname, sizeof(netname));
- if (Q_stricmp(netname, bs->teamleader) == 0) leader = "L";
- else leader = " ";
-
- strcpy(flagstatus, " ");
- if (gametype == GT_CTF) {
- if (BotCTFCarryingFlag(bs)) {
- if (BotTeam(bs) == TEAM_RED) strcpy(flagstatus, S_COLOR_RED"F ");
- else strcpy(flagstatus, S_COLOR_BLUE"F ");
- }
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- if (Bot1FCTFCarryingFlag(bs)) {
- if (BotTeam(bs) == TEAM_RED) strcpy(flagstatus, S_COLOR_RED"F ");
- else strcpy(flagstatus, S_COLOR_BLUE"F ");
- }
- }
- else if (gametype == GT_HARVESTER) {
- if (BotHarvesterCarryingCubes(bs)) {
- if (BotTeam(bs) == TEAM_RED) Com_sprintf(flagstatus, sizeof(flagstatus), S_COLOR_RED"%2d", bs->inventory[INVENTORY_REDCUBE]);
- else Com_sprintf(flagstatus, sizeof(flagstatus), S_COLOR_BLUE"%2d", bs->inventory[INVENTORY_BLUECUBE]);
- }
- }
-#endif
-
- switch(bs->ltgtype) {
- case LTG_TEAMHELP:
- {
- EasyClientName(bs->teammate, goalname, sizeof(goalname));
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: helping %s\n", netname, leader, flagstatus, goalname);
- break;
- }
- case LTG_TEAMACCOMPANY:
- {
- EasyClientName(bs->teammate, goalname, sizeof(goalname));
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: accompanying %s\n", netname, leader, flagstatus, goalname);
- break;
- }
- case LTG_DEFENDKEYAREA:
- {
- trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: defending %s\n", netname, leader, flagstatus, goalname);
- break;
- }
- case LTG_GETITEM:
- {
- trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: getting item %s\n", netname, leader, flagstatus, goalname);
- break;
- }
- case LTG_KILL:
- {
- ClientName(bs->teamgoal.entitynum, goalname, sizeof(goalname));
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: killing %s\n", netname, leader, flagstatus, goalname);
- break;
- }
- case LTG_CAMP:
- case LTG_CAMPORDER:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: camping\n", netname, leader, flagstatus);
- break;
- }
- case LTG_PATROL:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: patrolling\n", netname, leader, flagstatus);
- break;
- }
- case LTG_GETFLAG:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: capturing flag\n", netname, leader, flagstatus);
- break;
- }
- case LTG_RUSHBASE:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: rushing base\n", netname, leader, flagstatus);
- break;
- }
- case LTG_RETURNFLAG:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: returning flag\n", netname, leader, flagstatus);
- break;
- }
- case LTG_ATTACKENEMYBASE:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: attacking the enemy base\n", netname, leader, flagstatus);
- break;
- }
- case LTG_HARVEST:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: harvesting\n", netname, leader, flagstatus);
- break;
- }
- default:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: roaming\n", netname, leader, flagstatus);
- break;
- }
- }
-}
-
-/*
-==================
-BotTeamplayReport
-==================
-*/
-void BotTeamplayReport(void) {
- int i;
- char buf[MAX_INFO_STRING];
-
- BotAI_Print(PRT_MESSAGE, S_COLOR_RED"RED\n");
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- //
- if ( !botstates[i] || !botstates[i]->inuse ) continue;
- //
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_RED) {
- BotReportStatus(botstates[i]);
- }
- }
- BotAI_Print(PRT_MESSAGE, S_COLOR_BLUE"BLUE\n");
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- //
- if ( !botstates[i] || !botstates[i]->inuse ) continue;
- //
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_BLUE) {
- BotReportStatus(botstates[i]);
- }
- }
-}
-
-/*
-==================
-BotSetInfoConfigString
-==================
-*/
-void BotSetInfoConfigString(bot_state_t *bs) {
- char goalname[MAX_MESSAGE_SIZE];
- char netname[MAX_MESSAGE_SIZE];
- char action[MAX_MESSAGE_SIZE];
- char *leader, carrying[32], *cs;
- bot_goal_t goal;
- //
- ClientName(bs->client, netname, sizeof(netname));
- if (Q_stricmp(netname, bs->teamleader) == 0) leader = "L";
- else leader = " ";
-
- strcpy(carrying, " ");
- if (gametype == GT_CTF) {
- if (BotCTFCarryingFlag(bs)) {
- strcpy(carrying, "F ");
- }
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- if (Bot1FCTFCarryingFlag(bs)) {
- strcpy(carrying, "F ");
- }
- }
- else if (gametype == GT_HARVESTER) {
- if (BotHarvesterCarryingCubes(bs)) {
- if (BotTeam(bs) == TEAM_RED) Com_sprintf(carrying, sizeof(carrying), "%2d", bs->inventory[INVENTORY_REDCUBE]);
- else Com_sprintf(carrying, sizeof(carrying), "%2d", bs->inventory[INVENTORY_BLUECUBE]);
- }
- }
-#endif
-
- switch(bs->ltgtype) {
- case LTG_TEAMHELP:
- {
- EasyClientName(bs->teammate, goalname, sizeof(goalname));
- Com_sprintf(action, sizeof(action), "helping %s", goalname);
- break;
- }
- case LTG_TEAMACCOMPANY:
- {
- EasyClientName(bs->teammate, goalname, sizeof(goalname));
- Com_sprintf(action, sizeof(action), "accompanying %s", goalname);
- break;
- }
- case LTG_DEFENDKEYAREA:
- {
- trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
- Com_sprintf(action, sizeof(action), "defending %s", goalname);
- break;
- }
- case LTG_GETITEM:
- {
- trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
- Com_sprintf(action, sizeof(action), "getting item %s", goalname);
- break;
- }
- case LTG_KILL:
- {
- ClientName(bs->teamgoal.entitynum, goalname, sizeof(goalname));
- Com_sprintf(action, sizeof(action), "killing %s", goalname);
- break;
- }
- case LTG_CAMP:
- case LTG_CAMPORDER:
- {
- Com_sprintf(action, sizeof(action), "camping");
- break;
- }
- case LTG_PATROL:
- {
- Com_sprintf(action, sizeof(action), "patrolling");
- break;
- }
- case LTG_GETFLAG:
- {
- Com_sprintf(action, sizeof(action), "capturing flag");
- break;
- }
- case LTG_RUSHBASE:
- {
- Com_sprintf(action, sizeof(action), "rushing base");
- break;
- }
- case LTG_RETURNFLAG:
- {
- Com_sprintf(action, sizeof(action), "returning flag");
- break;
- }
- case LTG_ATTACKENEMYBASE:
- {
- Com_sprintf(action, sizeof(action), "attacking the enemy base");
- break;
- }
- case LTG_HARVEST:
- {
- Com_sprintf(action, sizeof(action), "harvesting");
- break;
- }
- default:
- {
- trap_BotGetTopGoal(bs->gs, &goal);
- trap_BotGoalName(goal.number, goalname, sizeof(goalname));
- Com_sprintf(action, sizeof(action), "roaming %s", goalname);
- break;
- }
- }
- cs = va("l\\%s\\c\\%s\\a\\%s",
- leader,
- carrying,
- action);
- trap_SetConfigstring (CS_BOTINFO + bs->client, cs);
-}
-
-/*
-==============
-BotUpdateInfoConfigStrings
-==============
-*/
-void BotUpdateInfoConfigStrings(void) {
- int i;
- char buf[MAX_INFO_STRING];
-
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- //
- if ( !botstates[i] || !botstates[i]->inuse )
- continue;
- //
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n")))
- continue;
- BotSetInfoConfigString(botstates[i]);
- }
-}
-
-/*
-==============
-BotInterbreedBots
-==============
-*/
-void BotInterbreedBots(void) {
- float ranks[MAX_CLIENTS];
- int parent1, parent2, child;
- int i;
-
- // get rankings for all the bots
- for (i = 0; i < MAX_CLIENTS; i++) {
- if ( botstates[i] && botstates[i]->inuse ) {
- ranks[i] = botstates[i]->num_kills * 2 - botstates[i]->num_deaths;
- }
- else {
- ranks[i] = -1;
- }
- }
-
- if (trap_GeneticParentsAndChildSelection(MAX_CLIENTS, ranks, &parent1, &parent2, &child)) {
- trap_BotInterbreedGoalFuzzyLogic(botstates[parent1]->gs, botstates[parent2]->gs, botstates[child]->gs);
- trap_BotMutateGoalFuzzyLogic(botstates[child]->gs, 1);
- }
- // reset the kills and deaths
- for (i = 0; i < MAX_CLIENTS; i++) {
- if (botstates[i] && botstates[i]->inuse) {
- botstates[i]->num_kills = 0;
- botstates[i]->num_deaths = 0;
- }
- }
-}
-
-/*
-==============
-BotWriteInterbreeded
-==============
-*/
-void BotWriteInterbreeded(char *filename) {
- float rank, bestrank;
- int i, bestbot;
-
- bestrank = 0;
- bestbot = -1;
- // get the best bot
- for (i = 0; i < MAX_CLIENTS; i++) {
- if ( botstates[i] && botstates[i]->inuse ) {
- rank = botstates[i]->num_kills * 2 - botstates[i]->num_deaths;
- }
- else {
- rank = -1;
- }
- if (rank > bestrank) {
- bestrank = rank;
- bestbot = i;
- }
- }
- if (bestbot >= 0) {
- //write out the new goal fuzzy logic
- trap_BotSaveGoalFuzzyLogic(botstates[bestbot]->gs, filename);
- }
-}
-
-/*
-==============
-BotInterbreedEndMatch
-
-add link back into ExitLevel?
-==============
-*/
-void BotInterbreedEndMatch(void) {
-
- if (!bot_interbreed) return;
- bot_interbreedmatchcount++;
- if (bot_interbreedmatchcount >= bot_interbreedcycle.integer) {
- bot_interbreedmatchcount = 0;
- //
- trap_Cvar_Update(&bot_interbreedwrite);
- if (strlen(bot_interbreedwrite.string)) {
- BotWriteInterbreeded(bot_interbreedwrite.string);
- trap_Cvar_Set("bot_interbreedwrite", "");
- }
- BotInterbreedBots();
- }
-}
-
-/*
-==============
-BotInterbreeding
-==============
-*/
-void BotInterbreeding(void) {
- int i;
-
- trap_Cvar_Update(&bot_interbreedchar);
- if (!strlen(bot_interbreedchar.string)) return;
- //make sure we are in tournament mode
- if (gametype != GT_TOURNAMENT) {
- trap_Cvar_Set("g_gametype", va("%d", GT_TOURNAMENT));
- ExitLevel();
- return;
- }
- //shutdown all the bots
- for (i = 0; i < MAX_CLIENTS; i++) {
- if (botstates[i] && botstates[i]->inuse) {
- BotAIShutdownClient(botstates[i]->client, qfalse);
- }
- }
- //make sure all item weight configs are reloaded and Not shared
- trap_BotLibVarSet("bot_reloadcharacters", "1");
- //add a number of bots using the desired bot character
- for (i = 0; i < bot_interbreedbots.integer; i++) {
- trap_SendConsoleCommand( EXEC_INSERT, va("addbot %s 4 free %i %s%d\n",
- bot_interbreedchar.string, i * 50, bot_interbreedchar.string, i) );
- }
- //
- trap_Cvar_Set("bot_interbreedchar", "");
- bot_interbreed = qtrue;
-}
-
-/*
-==============
-BotEntityInfo
-==============
-*/
-void BotEntityInfo(int entnum, aas_entityinfo_t *info) {
- trap_AAS_EntityInfo(entnum, info);
-}
-
-/*
-==============
-NumBots
-==============
-*/
-int NumBots(void) {
- return numbots;
-}
-
-/*
-==============
-BotTeamLeader
-==============
-*/
-int BotTeamLeader(bot_state_t *bs) {
- int leader;
-
- leader = ClientFromName(bs->teamleader);
- if (leader < 0) return qfalse;
- if (!botstates[leader] || !botstates[leader]->inuse) return qfalse;
- return qtrue;
-}
-
-/*
-==============
-AngleDifference
-==============
-*/
-float AngleDifference(float ang1, float ang2) {
- float diff;
-
- diff = ang1 - ang2;
- if (ang1 > ang2) {
- if (diff > 180.0) diff -= 360.0;
- }
- else {
- if (diff < -180.0) diff += 360.0;
- }
- return diff;
-}
-
-/*
-==============
-BotChangeViewAngle
-==============
-*/
-float BotChangeViewAngle(float angle, float ideal_angle, float speed) {
- float move;
-
- angle = AngleMod(angle);
- ideal_angle = AngleMod(ideal_angle);
- if (angle == ideal_angle) return angle;
- move = ideal_angle - angle;
- if (ideal_angle > angle) {
- if (move > 180.0) move -= 360.0;
- }
- else {
- if (move < -180.0) move += 360.0;
- }
- if (move > 0) {
- if (move > speed) move = speed;
- }
- else {
- if (move < -speed) move = -speed;
- }
- return AngleMod(angle + move);
-}
-
-/*
-==============
-BotChangeViewAngles
-==============
-*/
-void BotChangeViewAngles(bot_state_t *bs, float thinktime) {
- float diff, factor, maxchange, anglespeed, disired_speed;
- int i;
-
- if (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360;
- //
- if (bs->enemy >= 0) {
- factor = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_FACTOR, 0.01f, 1);
- maxchange = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_MAXCHANGE, 1, 1800);
- }
- else {
- factor = 0.05f;
- maxchange = 360;
- }
- if (maxchange < 240) maxchange = 240;
- maxchange *= thinktime;
- for (i = 0; i < 2; i++) {
- //
- if (bot_challenge.integer) {
- //smooth slowdown view model
- diff = abs(AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]));
- anglespeed = diff * factor;
- if (anglespeed > maxchange) anglespeed = maxchange;
- bs->viewangles[i] = BotChangeViewAngle(bs->viewangles[i],
- bs->ideal_viewangles[i], anglespeed);
- }
- else {
- //over reaction view model
- bs->viewangles[i] = AngleMod(bs->viewangles[i]);
- bs->ideal_viewangles[i] = AngleMod(bs->ideal_viewangles[i]);
- diff = AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]);
- disired_speed = diff * factor;
- bs->viewanglespeed[i] += (bs->viewanglespeed[i] - disired_speed);
- if (bs->viewanglespeed[i] > 180) bs->viewanglespeed[i] = maxchange;
- if (bs->viewanglespeed[i] < -180) bs->viewanglespeed[i] = -maxchange;
- anglespeed = bs->viewanglespeed[i];
- if (anglespeed > maxchange) anglespeed = maxchange;
- if (anglespeed < -maxchange) anglespeed = -maxchange;
- bs->viewangles[i] += anglespeed;
- bs->viewangles[i] = AngleMod(bs->viewangles[i]);
- //demping
- bs->viewanglespeed[i] *= 0.45 * (1 - factor);
- }
- //BotAI_Print(PRT_MESSAGE, "ideal_angles %f %f\n", bs->ideal_viewangles[0], bs->ideal_viewangles[1], bs->ideal_viewangles[2]);`
- //bs->viewangles[i] = bs->ideal_viewangles[i];
- }
- //bs->viewangles[PITCH] = 0;
- if (bs->viewangles[PITCH] > 180) bs->viewangles[PITCH] -= 360;
- //elementary action: view
- trap_EA_View(bs->client, bs->viewangles);
-}
-
-/*
-==============
-BotInputToUserCommand
-==============
-*/
-void BotInputToUserCommand(bot_input_t *bi, usercmd_t *ucmd, int delta_angles[3], int time) {
- vec3_t angles, forward, right;
- short temp;
- int j;
-
- //clear the whole structure
- memset(ucmd, 0, sizeof(usercmd_t));
- //
- //Com_Printf("dir = %f %f %f speed = %f\n", bi->dir[0], bi->dir[1], bi->dir[2], bi->speed);
- //the duration for the user command in milli seconds
- ucmd->serverTime = time;
- //
- if (bi->actionflags & ACTION_DELAYEDJUMP) {
- bi->actionflags |= ACTION_JUMP;
- bi->actionflags &= ~ACTION_DELAYEDJUMP;
- }
- //set the buttons
- if (bi->actionflags & ACTION_RESPAWN) ucmd->buttons = BUTTON_ATTACK;
- if (bi->actionflags & ACTION_ATTACK) ucmd->buttons |= BUTTON_ATTACK;
- if (bi->actionflags & ACTION_TALK) ucmd->buttons |= BUTTON_TALK;
- if (bi->actionflags & ACTION_GESTURE) ucmd->buttons |= BUTTON_GESTURE;
- if (bi->actionflags & ACTION_USE) ucmd->buttons |= BUTTON_USE_HOLDABLE;
- if (bi->actionflags & ACTION_WALK) ucmd->buttons |= BUTTON_WALKING;
- if (bi->actionflags & ACTION_AFFIRMATIVE) ucmd->buttons |= BUTTON_AFFIRMATIVE;
- if (bi->actionflags & ACTION_NEGATIVE) ucmd->buttons |= BUTTON_NEGATIVE;
- if (bi->actionflags & ACTION_GETFLAG) ucmd->buttons |= BUTTON_GETFLAG;
- if (bi->actionflags & ACTION_GUARDBASE) ucmd->buttons |= BUTTON_GUARDBASE;
- if (bi->actionflags & ACTION_PATROL) ucmd->buttons |= BUTTON_PATROL;
- if (bi->actionflags & ACTION_FOLLOWME) ucmd->buttons |= BUTTON_FOLLOWME;
- //
- ucmd->weapon = bi->weapon;
- //set the view angles
- //NOTE: the ucmd->angles are the angles WITHOUT the delta angles
- ucmd->angles[PITCH] = ANGLE2SHORT(bi->viewangles[PITCH]);
- ucmd->angles[YAW] = ANGLE2SHORT(bi->viewangles[YAW]);
- ucmd->angles[ROLL] = ANGLE2SHORT(bi->viewangles[ROLL]);
- //subtract the delta angles
- for (j = 0; j < 3; j++) {
- temp = ucmd->angles[j] - delta_angles[j];
- /*NOTE: disabled because temp should be mod first
- if ( j == PITCH ) {
- // don't let the player look up or down more than 90 degrees
- if ( temp > 16000 ) temp = 16000;
- else if ( temp < -16000 ) temp = -16000;
- }
- */
- ucmd->angles[j] = temp;
- }
- //NOTE: movement is relative to the REAL view angles
- //get the horizontal forward and right vector
- //get the pitch in the range [-180, 180]
- if (bi->dir[2]) angles[PITCH] = bi->viewangles[PITCH];
- else angles[PITCH] = 0;
- angles[YAW] = bi->viewangles[YAW];
- angles[ROLL] = 0;
- AngleVectors(angles, forward, right, NULL);
- //bot input speed is in the range [0, 400]
- bi->speed = bi->speed * 127 / 400;
- //set the view independent movement
- ucmd->forwardmove = DotProduct(forward, bi->dir) * bi->speed;
- ucmd->rightmove = DotProduct(right, bi->dir) * bi->speed;
- ucmd->upmove = abs(forward[2]) * bi->dir[2] * bi->speed;
- //normal keyboard movement
- if (bi->actionflags & ACTION_MOVEFORWARD) ucmd->forwardmove += 127;
- if (bi->actionflags & ACTION_MOVEBACK) ucmd->forwardmove -= 127;
- if (bi->actionflags & ACTION_MOVELEFT) ucmd->rightmove -= 127;
- if (bi->actionflags & ACTION_MOVERIGHT) ucmd->rightmove += 127;
- //jump/moveup
- if (bi->actionflags & ACTION_JUMP) ucmd->upmove += 127;
- //crouch/movedown
- if (bi->actionflags & ACTION_CROUCH) ucmd->upmove -= 127;
- //
- //Com_Printf("forward = %d right = %d up = %d\n", ucmd.forwardmove, ucmd.rightmove, ucmd.upmove);
- //Com_Printf("ucmd->serverTime = %d\n", ucmd->serverTime);
-}
-
-/*
-==============
-BotUpdateInput
-==============
-*/
-void BotUpdateInput(bot_state_t *bs, int time, int elapsed_time) {
- bot_input_t bi;
- int j;
-
- //add the delta angles to the bot's current view angles
- for (j = 0; j < 3; j++) {
- bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
- }
- //change the bot view angles
- BotChangeViewAngles(bs, (float) elapsed_time / 1000);
- //retrieve the bot input
- trap_EA_GetInput(bs->client, (float) time / 1000, &bi);
- //respawn hack
- if (bi.actionflags & ACTION_RESPAWN) {
- if (bs->lastucmd.buttons & BUTTON_ATTACK) bi.actionflags &= ~(ACTION_RESPAWN|ACTION_ATTACK);
- }
- //convert the bot input to a usercmd
- BotInputToUserCommand(&bi, &bs->lastucmd, bs->cur_ps.delta_angles, time);
- //subtract the delta angles
- for (j = 0; j < 3; j++) {
- bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
- }
-}
-
-/*
-==============
-BotAIRegularUpdate
-==============
-*/
-void BotAIRegularUpdate(void) {
- if (regularupdate_time < FloatTime()) {
- trap_BotUpdateEntityItems();
- regularupdate_time = FloatTime() + 0.3;
- }
-}
-
-/*
-==============
-RemoveColorEscapeSequences
-==============
-*/
-void RemoveColorEscapeSequences( char *text ) {
- int i, l;
-
- l = 0;
- for ( i = 0; text[i]; i++ ) {
- if (Q_IsColorString(&text[i])) {
- i++;
- continue;
- }
- if (text[i] > 0x7E)
- continue;
- text[l++] = text[i];
- }
- text[l] = '\0';
-}
-
-/*
-==============
-BotAI
-==============
-*/
-int BotAI(int client, float thinktime) {
- bot_state_t *bs;
- char buf[1024], *args;
- int j;
-
- trap_EA_ResetInput(client);
- //
- bs = botstates[client];
- if (!bs || !bs->inuse) {
- BotAI_Print(PRT_FATAL, "BotAI: client %d is not setup\n", client);
- return qfalse;
- }
-
- //retrieve the current client state
- BotAI_GetClientState( client, &bs->cur_ps );
-
- //retrieve any waiting server commands
- while( trap_BotGetServerCommand(client, buf, sizeof(buf)) ) {
- //have buf point to the command and args to the command arguments
- args = strchr( buf, ' ');
- if (!args) continue;
- *args++ = '\0';
-
- //remove color espace sequences from the arguments
- RemoveColorEscapeSequences( args );
-
- if (!Q_stricmp(buf, "cp "))
- { /*CenterPrintf*/ }
- else if (!Q_stricmp(buf, "cs"))
- { /*ConfigStringModified*/ }
- else if (!Q_stricmp(buf, "print")) {
- //remove first and last quote from the chat message
- memmove(args, args+1, strlen(args));
- args[strlen(args)-1] = '\0';
- trap_BotQueueConsoleMessage(bs->cs, CMS_NORMAL, args);
- }
- else if (!Q_stricmp(buf, "chat")) {
- //remove first and last quote from the chat message
- memmove(args, args+1, strlen(args));
- args[strlen(args)-1] = '\0';
- trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, args);
- }
- else if (!Q_stricmp(buf, "tchat")) {
- //remove first and last quote from the chat message
- memmove(args, args+1, strlen(args));
- args[strlen(args)-1] = '\0';
- trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, args);
- }
-#ifdef MISSIONPACK
- else if (!Q_stricmp(buf, "vchat")) {
- BotVoiceChatCommand(bs, SAY_ALL, args);
- }
- else if (!Q_stricmp(buf, "vtchat")) {
- BotVoiceChatCommand(bs, SAY_TEAM, args);
- }
- else if (!Q_stricmp(buf, "vtell")) {
- BotVoiceChatCommand(bs, SAY_TELL, args);
- }
-#endif
- else if (!Q_stricmp(buf, "scores"))
- { /*FIXME: parse scores?*/ }
- else if (!Q_stricmp(buf, "clientLevelShot"))
- { /*ignore*/ }
- }
- //add the delta angles to the bot's current view angles
- for (j = 0; j < 3; j++) {
- bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
- }
- //increase the local time of the bot
- bs->ltime += thinktime;
- //
- bs->thinktime = thinktime;
- //origin of the bot
- VectorCopy(bs->cur_ps.origin, bs->origin);
- //eye coordinates of the bot
- VectorCopy(bs->cur_ps.origin, bs->eye);
- bs->eye[2] += bs->cur_ps.viewheight;
- //get the area the bot is in
- bs->areanum = BotPointAreaNum(bs->origin);
- //the real AI
- BotDeathmatchAI(bs, thinktime);
- //set the weapon selection every AI frame
- trap_EA_SelectWeapon(bs->client, bs->weaponnum);
- //subtract the delta angles
- for (j = 0; j < 3; j++) {
- bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
- }
- //everything was ok
- return qtrue;
-}
-
-/*
-==================
-BotScheduleBotThink
-==================
-*/
-void BotScheduleBotThink(void) {
- int i, botnum;
-
- botnum = 0;
-
- for( i = 0; i < MAX_CLIENTS; i++ ) {
- if( !botstates[i] || !botstates[i]->inuse ) {
- continue;
- }
- //initialize the bot think residual time
- botstates[i]->botthink_residual = bot_thinktime.integer * botnum / numbots;
- botnum++;
- }
-}
-
-/*
-==============
-BotWriteSessionData
-==============
-*/
-void BotWriteSessionData(bot_state_t *bs) {
- const char *s;
- const char *var;
-
- s = va(
- "%i %i %i %i %i %i %i %i"
- " %f %f %f"
- " %f %f %f"
- " %f %f %f",
- bs->lastgoal_decisionmaker,
- bs->lastgoal_ltgtype,
- bs->lastgoal_teammate,
- bs->lastgoal_teamgoal.areanum,
- bs->lastgoal_teamgoal.entitynum,
- bs->lastgoal_teamgoal.flags,
- bs->lastgoal_teamgoal.iteminfo,
- bs->lastgoal_teamgoal.number,
- bs->lastgoal_teamgoal.origin[0],
- bs->lastgoal_teamgoal.origin[1],
- bs->lastgoal_teamgoal.origin[2],
- bs->lastgoal_teamgoal.mins[0],
- bs->lastgoal_teamgoal.mins[1],
- bs->lastgoal_teamgoal.mins[2],
- bs->lastgoal_teamgoal.maxs[0],
- bs->lastgoal_teamgoal.maxs[1],
- bs->lastgoal_teamgoal.maxs[2]
- );
-
- var = va( "botsession%i", bs->client );
-
- trap_Cvar_Set( var, s );
-}
-
-/*
-==============
-BotReadSessionData
-==============
-*/
-void BotReadSessionData(bot_state_t *bs) {
- char s[MAX_STRING_CHARS];
- const char *var;
-
- var = va( "botsession%i", bs->client );
- trap_Cvar_VariableStringBuffer( var, s, sizeof(s) );
-
- sscanf(s,
- "%i %i %i %i %i %i %i %i"
- " %f %f %f"
- " %f %f %f"
- " %f %f %f",
- &bs->lastgoal_decisionmaker,
- &bs->lastgoal_ltgtype,
- &bs->lastgoal_teammate,
- &bs->lastgoal_teamgoal.areanum,
- &bs->lastgoal_teamgoal.entitynum,
- &bs->lastgoal_teamgoal.flags,
- &bs->lastgoal_teamgoal.iteminfo,
- &bs->lastgoal_teamgoal.number,
- &bs->lastgoal_teamgoal.origin[0],
- &bs->lastgoal_teamgoal.origin[1],
- &bs->lastgoal_teamgoal.origin[2],
- &bs->lastgoal_teamgoal.mins[0],
- &bs->lastgoal_teamgoal.mins[1],
- &bs->lastgoal_teamgoal.mins[2],
- &bs->lastgoal_teamgoal.maxs[0],
- &bs->lastgoal_teamgoal.maxs[1],
- &bs->lastgoal_teamgoal.maxs[2]
- );
-}
-
-/*
-==============
-BotAISetupClient
-==============
-*/
-int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean restart) {
- char filename[MAX_PATH], name[MAX_PATH], gender[MAX_PATH];
- bot_state_t *bs;
- int errnum;
-
- if (!botstates[client]) botstates[client] = G_Alloc(sizeof(bot_state_t));
- bs = botstates[client];
-
- if (bs && bs->inuse) {
- BotAI_Print(PRT_FATAL, "BotAISetupClient: client %d already setup\n", client);
- return qfalse;
- }
-
- if (!trap_AAS_Initialized()) {
- BotAI_Print(PRT_FATAL, "AAS not initialized\n");
- return qfalse;
- }
-
- //load the bot character
- bs->character = trap_BotLoadCharacter(settings->characterfile, settings->skill);
- if (!bs->character) {
- BotAI_Print(PRT_FATAL, "couldn't load skill %f from %s\n", settings->skill, settings->characterfile);
- return qfalse;
- }
- //copy the settings
- memcpy(&bs->settings, settings, sizeof(bot_settings_t));
- //allocate a goal state
- bs->gs = trap_BotAllocGoalState(client);
- //load the item weights
- trap_Characteristic_String(bs->character, CHARACTERISTIC_ITEMWEIGHTS, filename, MAX_PATH);
- errnum = trap_BotLoadItemWeights(bs->gs, filename);
- if (errnum != BLERR_NOERROR) {
- trap_BotFreeGoalState(bs->gs);
- return qfalse;
- }
- //allocate a weapon state
- bs->ws = trap_BotAllocWeaponState();
- //load the weapon weights
- trap_Characteristic_String(bs->character, CHARACTERISTIC_WEAPONWEIGHTS, filename, MAX_PATH);
- errnum = trap_BotLoadWeaponWeights(bs->ws, filename);
- if (errnum != BLERR_NOERROR) {
- trap_BotFreeGoalState(bs->gs);
- trap_BotFreeWeaponState(bs->ws);
- return qfalse;
- }
- //allocate a chat state
- bs->cs = trap_BotAllocChatState();
- //load the chat file
- trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_FILE, filename, MAX_PATH);
- trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_NAME, name, MAX_PATH);
- errnum = trap_BotLoadChatFile(bs->cs, filename, name);
- if (errnum != BLERR_NOERROR) {
- trap_BotFreeChatState(bs->cs);
- trap_BotFreeGoalState(bs->gs);
- trap_BotFreeWeaponState(bs->ws);
- return qfalse;
- }
- //get the gender characteristic
- trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, MAX_PATH);
- //set the chat gender
- if (*gender == 'f' || *gender == 'F') trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE);
- else if (*gender == 'm' || *gender == 'M') trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE);
- else trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS);
-
- bs->inuse = qtrue;
- bs->client = client;
- bs->entitynum = client;
- bs->setupcount = 4;
- bs->entergame_time = FloatTime();
- bs->ms = trap_BotAllocMoveState();
- bs->walker = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WALKER, 0, 1);
- numbots++;
-
- if (trap_Cvar_VariableIntegerValue("bot_testichat")) {
- trap_BotLibVarSet("bot_testichat", "1");
- BotChatTest(bs);
- }
- //NOTE: reschedule the bot thinking
- BotScheduleBotThink();
- //if interbreeding start with a mutation
- if (bot_interbreed) {
- trap_BotMutateGoalFuzzyLogic(bs->gs, 1);
- }
- // if we kept the bot client
- if (restart) {
- BotReadSessionData(bs);
- }
- //bot has been setup succesfully
- return qtrue;
-}
-
-/*
-==============
-BotAIShutdownClient
-==============
-*/
-int BotAIShutdownClient(int client, qboolean restart) {
- bot_state_t *bs;
-
- bs = botstates[client];
- if (!bs || !bs->inuse) {
- //BotAI_Print(PRT_ERROR, "BotAIShutdownClient: client %d already shutdown\n", client);
- return qfalse;
- }
-
- if (restart) {
- BotWriteSessionData(bs);
- }
-
- if (BotChat_ExitGame(bs)) {
- trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
- }
-
- trap_BotFreeMoveState(bs->ms);
- //free the goal state`
- trap_BotFreeGoalState(bs->gs);
- //free the chat file
- trap_BotFreeChatState(bs->cs);
- //free the weapon weights
- trap_BotFreeWeaponState(bs->ws);
- //free the bot character
- trap_BotFreeCharacter(bs->character);
- //
- BotFreeWaypoints(bs->checkpoints);
- BotFreeWaypoints(bs->patrolpoints);
- //clear activate goal stack
- BotClearActivateGoalStack(bs);
- //clear the bot state
- memset(bs, 0, sizeof(bot_state_t));
- //set the inuse flag to qfalse
- bs->inuse = qfalse;
- //there's one bot less
- numbots--;
- //everything went ok
- return qtrue;
-}
-
-/*
-==============
-BotResetState
-
-called when a bot enters the intermission or observer mode and
-when the level is changed
-==============
-*/
-void BotResetState(bot_state_t *bs) {
- int client, entitynum, inuse;
- int movestate, goalstate, chatstate, weaponstate;
- bot_settings_t settings;
- int character;
- playerState_t ps; //current player state
- float entergame_time;
-
- //save some things that should not be reset here
- memcpy(&settings, &bs->settings, sizeof(bot_settings_t));
- memcpy(&ps, &bs->cur_ps, sizeof(playerState_t));
- inuse = bs->inuse;
- client = bs->client;
- entitynum = bs->entitynum;
- character = bs->character;
- movestate = bs->ms;
- goalstate = bs->gs;
- chatstate = bs->cs;
- weaponstate = bs->ws;
- entergame_time = bs->entergame_time;
- //free checkpoints and patrol points
- BotFreeWaypoints(bs->checkpoints);
- BotFreeWaypoints(bs->patrolpoints);
- //reset the whole state
- memset(bs, 0, sizeof(bot_state_t));
- //copy back some state stuff that should not be reset
- bs->ms = movestate;
- bs->gs = goalstate;
- bs->cs = chatstate;
- bs->ws = weaponstate;
- memcpy(&bs->cur_ps, &ps, sizeof(playerState_t));
- memcpy(&bs->settings, &settings, sizeof(bot_settings_t));
- bs->inuse = inuse;
- bs->client = client;
- bs->entitynum = entitynum;
- bs->character = character;
- bs->entergame_time = entergame_time;
- //reset several states
- if (bs->ms) trap_BotResetMoveState(bs->ms);
- if (bs->gs) trap_BotResetGoalState(bs->gs);
- if (bs->ws) trap_BotResetWeaponState(bs->ws);
- if (bs->gs) trap_BotResetAvoidGoals(bs->gs);
- if (bs->ms) trap_BotResetAvoidReach(bs->ms);
-}
-
-/*
-==============
-BotAILoadMap
-==============
-*/
-int BotAILoadMap( int restart ) {
- int i;
- vmCvar_t mapname;
-
- if (!restart) {
- trap_Cvar_Register( &mapname, "mapname", "", CVAR_SERVERINFO | CVAR_ROM );
- trap_BotLibLoadMap( mapname.string );
- }
-
- for (i = 0; i < MAX_CLIENTS; i++) {
- if (botstates[i] && botstates[i]->inuse) {
- BotResetState( botstates[i] );
- botstates[i]->setupcount = 4;
- }
- }
-
- BotSetupDeathmatchAI();
-
- return qtrue;
-}
-
-#ifdef MISSIONPACK
-void ProximityMine_Trigger( gentity_t *trigger, gentity_t *other, trace_t *trace );
-#endif
-
-/*
-==================
-BotAIStartFrame
-==================
-*/
-int BotAIStartFrame(int time) {
- int i;
- gentity_t *ent;
- bot_entitystate_t state;
- int elapsed_time, thinktime;
- static int local_time;
- static int botlib_residual;
- static int lastbotthink_time;
-
- G_CheckBotSpawn();
-
- trap_Cvar_Update(&bot_rocketjump);
- trap_Cvar_Update(&bot_grapple);
- trap_Cvar_Update(&bot_fastchat);
- trap_Cvar_Update(&bot_nochat);
- trap_Cvar_Update(&bot_testrchat);
- trap_Cvar_Update(&bot_thinktime);
- trap_Cvar_Update(&bot_memorydump);
- trap_Cvar_Update(&bot_saveroutingcache);
- trap_Cvar_Update(&bot_pause);
- trap_Cvar_Update(&bot_report);
-
- if (bot_report.integer) {
-// BotTeamplayReport();
-// trap_Cvar_Set("bot_report", "0");
- BotUpdateInfoConfigStrings();
- }
-
- if (bot_pause.integer) {
- // execute bot user commands every frame
- for( i = 0; i < MAX_CLIENTS; i++ ) {
- if( !botstates[i] || !botstates[i]->inuse ) {
- continue;
- }
- if( g_entities[i].client->pers.connected != CON_CONNECTED ) {
- continue;
- }
- botstates[i]->lastucmd.forwardmove = 0;
- botstates[i]->lastucmd.rightmove = 0;
- botstates[i]->lastucmd.upmove = 0;
- botstates[i]->lastucmd.buttons = 0;
- botstates[i]->lastucmd.serverTime = time;
- trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd);
- }
- return qtrue;
- }
-
- if (bot_memorydump.integer) {
- trap_BotLibVarSet("memorydump", "1");
- trap_Cvar_Set("bot_memorydump", "0");
- }
- if (bot_saveroutingcache.integer) {
- trap_BotLibVarSet("saveroutingcache", "1");
- trap_Cvar_Set("bot_saveroutingcache", "0");
- }
- //check if bot interbreeding is activated
- BotInterbreeding();
- //cap the bot think time
- if (bot_thinktime.integer > 200) {
- trap_Cvar_Set("bot_thinktime", "200");
- }
- //if the bot think time changed we should reschedule the bots
- if (bot_thinktime.integer != lastbotthink_time) {
- lastbotthink_time = bot_thinktime.integer;
- BotScheduleBotThink();
- }
-
- elapsed_time = time - local_time;
- local_time = time;
-
- botlib_residual += elapsed_time;
-
- if (elapsed_time > bot_thinktime.integer) thinktime = elapsed_time;
- else thinktime = bot_thinktime.integer;
-
- // update the bot library
- if ( botlib_residual >= thinktime ) {
- botlib_residual -= thinktime;
-
- trap_BotLibStartFrame((float) time / 1000);
-
- if (!trap_AAS_Initialized()) return qfalse;
-
- //update entities in the botlib
- for (i = 0; i < MAX_GENTITIES; i++) {
- ent = &g_entities[i];
- if (!ent->inuse) {
- trap_BotLibUpdateEntity(i, NULL);
- continue;
- }
- if (!ent->r.linked) {
- trap_BotLibUpdateEntity(i, NULL);
- continue;
- }
- if (ent->r.svFlags & SVF_NOCLIENT) {
- trap_BotLibUpdateEntity(i, NULL);
- continue;
- }
- // do not update missiles
- if (ent->s.eType == ET_MISSILE && ent->s.weapon != WP_GRAPPLING_HOOK) {
- trap_BotLibUpdateEntity(i, NULL);
- continue;
- }
- // do not update event only entities
- if (ent->s.eType > ET_EVENTS) {
- trap_BotLibUpdateEntity(i, NULL);
- continue;
- }
-#ifdef MISSIONPACK
- // never link prox mine triggers
- if (ent->r.contents == CONTENTS_TRIGGER) {
- if (ent->touch == ProximityMine_Trigger) {
- trap_BotLibUpdateEntity(i, NULL);
- continue;
- }
- }
-#endif
- //
- memset(&state, 0, sizeof(bot_entitystate_t));
- //
- VectorCopy(ent->r.currentOrigin, state.origin);
- if (i < MAX_CLIENTS) {
- VectorCopy(ent->s.apos.trBase, state.angles);
- } else {
- VectorCopy(ent->r.currentAngles, state.angles);
- }
- VectorCopy(ent->s.origin2, state.old_origin);
- VectorCopy(ent->r.mins, state.mins);
- VectorCopy(ent->r.maxs, state.maxs);
- state.type = ent->s.eType;
- state.flags = ent->s.eFlags;
- if (ent->r.bmodel) state.solid = SOLID_BSP;
- else state.solid = SOLID_BBOX;
- state.groundent = ent->s.groundEntityNum;
- state.modelindex = ent->s.modelindex;
- state.modelindex2 = ent->s.modelindex2;
- state.frame = ent->s.frame;
- state.event = ent->s.event;
- state.eventParm = ent->s.eventParm;
- state.powerups = ent->s.powerups;
- state.legsAnim = ent->s.legsAnim;
- state.torsoAnim = ent->s.torsoAnim;
- state.weapon = ent->s.weapon;
- //
- trap_BotLibUpdateEntity(i, &state);
- }
-
- BotAIRegularUpdate();
- }
-
- floattime = trap_AAS_Time();
-
- // execute scheduled bot AI
- for( i = 0; i < MAX_CLIENTS; i++ ) {
- if( !botstates[i] || !botstates[i]->inuse ) {
- continue;
- }
- //
- botstates[i]->botthink_residual += elapsed_time;
- //
- if ( botstates[i]->botthink_residual >= thinktime ) {
- botstates[i]->botthink_residual -= thinktime;
-
- if (!trap_AAS_Initialized()) return qfalse;
-
- if (g_entities[i].client->pers.connected == CON_CONNECTED) {
- BotAI(i, (float) thinktime / 1000);
- }
- }
- }
-
-
- // execute bot user commands every frame
- for( i = 0; i < MAX_CLIENTS; i++ ) {
- if( !botstates[i] || !botstates[i]->inuse ) {
- continue;
- }
- if( g_entities[i].client->pers.connected != CON_CONNECTED ) {
- continue;
- }
-
- BotUpdateInput(botstates[i], time, elapsed_time);
- trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd);
- }
-
- return qtrue;
-}
-
-/*
-==============
-BotInitLibrary
-==============
-*/
-int BotInitLibrary(void) {
- char buf[144];
-
- //set the maxclients and maxentities library variables before calling BotSetupLibrary
- trap_Cvar_VariableStringBuffer("sv_maxclients", buf, sizeof(buf));
- if (!strlen(buf)) strcpy(buf, "8");
- trap_BotLibVarSet("maxclients", buf);
- Com_sprintf(buf, sizeof(buf), "%d", MAX_GENTITIES);
- trap_BotLibVarSet("maxentities", buf);
- //bsp checksum
- trap_Cvar_VariableStringBuffer("sv_mapChecksum", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("sv_mapChecksum", buf);
- //maximum number of aas links
- trap_Cvar_VariableStringBuffer("max_aaslinks", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("max_aaslinks", buf);
- //maximum number of items in a level
- trap_Cvar_VariableStringBuffer("max_levelitems", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("max_levelitems", buf);
- //game type
- trap_Cvar_VariableStringBuffer("g_gametype", buf, sizeof(buf));
- if (!strlen(buf)) strcpy(buf, "0");
- trap_BotLibVarSet("g_gametype", buf);
- //bot developer mode and log file
- trap_BotLibVarSet("bot_developer", bot_developer.string);
- trap_Cvar_VariableStringBuffer("logfile", buf, sizeof(buf));
- trap_BotLibVarSet("log", buf);
- //no chatting
- trap_Cvar_VariableStringBuffer("bot_nochat", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("nochat", buf);
- //visualize jump pads
- trap_Cvar_VariableStringBuffer("bot_visualizejumppads", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("bot_visualizejumppads", buf);
- //forced clustering calculations
- trap_Cvar_VariableStringBuffer("bot_forceclustering", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("forceclustering", buf);
- //forced reachability calculations
- trap_Cvar_VariableStringBuffer("bot_forcereachability", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("forcereachability", buf);
- //force writing of AAS to file
- trap_Cvar_VariableStringBuffer("bot_forcewrite", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("forcewrite", buf);
- //no AAS optimization
- trap_Cvar_VariableStringBuffer("bot_aasoptimize", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("aasoptimize", buf);
- //
- trap_Cvar_VariableStringBuffer("bot_saveroutingcache", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("saveroutingcache", buf);
- //reload instead of cache bot character files
- trap_Cvar_VariableStringBuffer("bot_reloadcharacters", buf, sizeof(buf));
- if (!strlen(buf)) strcpy(buf, "0");
- trap_BotLibVarSet("bot_reloadcharacters", buf);
- //base directory
- trap_Cvar_VariableStringBuffer("fs_basepath", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("basedir", buf);
- //game directory
- trap_Cvar_VariableStringBuffer("fs_game", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("gamedir", buf);
- //home directory
- trap_Cvar_VariableStringBuffer("fs_homepath", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("homedir", buf);
- //
-#ifdef MISSIONPACK
- trap_BotLibDefine("MISSIONPACK");
-#endif
- //setup the bot library
- return trap_BotLibSetup();
-}
-
-/*
-==============
-BotAISetup
-==============
-*/
-int BotAISetup( int restart ) {
- int errnum;
-
- trap_Cvar_Register(&bot_thinktime, "bot_thinktime", "100", CVAR_CHEAT);
- trap_Cvar_Register(&bot_memorydump, "bot_memorydump", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_saveroutingcache, "bot_saveroutingcache", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_pause, "bot_pause", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_report, "bot_report", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_testsolid, "bot_testsolid", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_testclusters, "bot_testclusters", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_developer, "bot_developer", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_interbreedchar, "bot_interbreedchar", "", 0);
- trap_Cvar_Register(&bot_interbreedbots, "bot_interbreedbots", "10", 0);
- trap_Cvar_Register(&bot_interbreedcycle, "bot_interbreedcycle", "20", 0);
- trap_Cvar_Register(&bot_interbreedwrite, "bot_interbreedwrite", "", 0);
-
- //if the game is restarted for a tournament
- if (restart) {
- return qtrue;
- }
-
- //initialize the bot states
- memset( botstates, 0, sizeof(botstates) );
-
- errnum = BotInitLibrary();
- if (errnum != BLERR_NOERROR) return qfalse;
- return qtrue;
-}
-
-/*
-==============
-BotAIShutdown
-==============
-*/
-int BotAIShutdown( int restart ) {
-
- int i;
-
- //if the game is restarted for a tournament
- if ( restart ) {
- //shutdown all the bots in the botlib
- for (i = 0; i < MAX_CLIENTS; i++) {
- if (botstates[i] && botstates[i]->inuse) {
- BotAIShutdownClient(botstates[i]->client, restart);
- }
- }
- //don't shutdown the bot library
- }
- else {
- trap_BotLibShutdown();
- }
- return qtrue;
-}
-
diff --git a/engine/code/game/ai_main.h b/engine/code/game/ai_main.h
deleted file mode 100644
index effa306..0000000
--- a/engine/code/game/ai_main.h
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_main.h
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /source/code/botai/ai_chat.c $
- *
- *****************************************************************************/
-
-//#define DEBUG
-#define CTF
-
-#define MAX_ITEMS 256
-//bot flags
-#define BFL_STRAFERIGHT 1 //strafe to the right
-#define BFL_ATTACKED 2 //bot has attacked last ai frame
-#define BFL_ATTACKJUMPED 4 //bot jumped during attack last frame
-#define BFL_AIMATENEMY 8 //bot aimed at the enemy this frame
-#define BFL_AVOIDRIGHT 16 //avoid obstacles by going to the right
-#define BFL_IDEALVIEWSET 32 //bot has ideal view angles set
-#define BFL_FIGHTSUICIDAL 64 //bot is in a suicidal fight
-//long term goal types
-#define LTG_TEAMHELP 1 //help a team mate
-#define LTG_TEAMACCOMPANY 2 //accompany a team mate
-#define LTG_DEFENDKEYAREA 3 //defend a key area
-#define LTG_GETFLAG 4 //get the enemy flag
-#define LTG_RUSHBASE 5 //rush to the base
-#define LTG_RETURNFLAG 6 //return the flag
-#define LTG_CAMP 7 //camp somewhere
-#define LTG_CAMPORDER 8 //ordered to camp somewhere
-#define LTG_PATROL 9 //patrol
-#define LTG_GETITEM 10 //get an item
-#define LTG_KILL 11 //kill someone
-#define LTG_HARVEST 12 //harvest skulls
-#define LTG_ATTACKENEMYBASE 13 //attack the enemy base
-#define LTG_MAKELOVE_UNDER 14
-#define LTG_MAKELOVE_ONTOP 15
-//some goal dedication times
-#define TEAM_HELP_TIME 60 //1 minute teamplay help time
-#define TEAM_ACCOMPANY_TIME 600 //10 minutes teamplay accompany time
-#define TEAM_DEFENDKEYAREA_TIME 600 //10 minutes ctf defend base time
-#define TEAM_CAMP_TIME 600 //10 minutes camping time
-#define TEAM_PATROL_TIME 600 //10 minutes patrolling time
-#define TEAM_LEAD_TIME 600 //10 minutes taking the lead
-#define TEAM_GETITEM_TIME 60 //1 minute
-#define TEAM_KILL_SOMEONE 180 //3 minute to kill someone
-#define TEAM_ATTACKENEMYBASE_TIME 600 //10 minutes
-#define TEAM_HARVEST_TIME 120 //2 minutes
-#define CTF_GETFLAG_TIME 600 //10 minutes ctf get flag time
-#define CTF_RUSHBASE_TIME 120 //2 minutes ctf rush base time
-#define CTF_RETURNFLAG_TIME 180 //3 minutes to return the flag
-#define CTF_ROAM_TIME 60 //1 minute ctf roam time
-//patrol flags
-#define PATROL_LOOP 1
-#define PATROL_REVERSE 2
-#define PATROL_BACK 4
-//teamplay task preference
-#define TEAMTP_DEFENDER 1
-#define TEAMTP_ATTACKER 2
-//CTF strategy
-#define CTFS_AGRESSIVE 1
-//copied from the aas file header
-#define PRESENCE_NONE 1
-#define PRESENCE_NORMAL 2
-#define PRESENCE_CROUCH 4
-//
-#define MAX_PROXMINES 64
-
-//check points
-typedef struct bot_waypoint_s
-{
- int inuse;
- char name[32];
- bot_goal_t goal;
- struct bot_waypoint_s *next, *prev;
-} bot_waypoint_t;
-
-#define MAX_ACTIVATESTACK 8
-#define MAX_ACTIVATEAREAS 32
-
-typedef struct bot_activategoal_s
-{
- int inuse;
- bot_goal_t goal; //goal to activate (buttons etc.)
- float time; //time to activate something
- float start_time; //time starting to activate something
- float justused_time; //time the goal was used
- int shoot; //true if bot has to shoot to activate
- int weapon; //weapon to be used for activation
- vec3_t target; //target to shoot at to activate something
- vec3_t origin; //origin of the blocking entity to activate
- int areas[MAX_ACTIVATEAREAS]; //routing areas disabled by blocking entity
- int numareas; //number of disabled routing areas
- int areasdisabled; //true if the areas are disabled for the routing
- struct bot_activategoal_s *next; //next activate goal on stack
-} bot_activategoal_t;
-
-//bot state
-typedef struct bot_state_s
-{
- int inuse; //true if this state is used by a bot client
- int botthink_residual; //residual for the bot thinks
- int client; //client number of the bot
- int entitynum; //entity number of the bot
- playerState_t cur_ps; //current player state
- int last_eFlags; //last ps flags
- usercmd_t lastucmd; //usercmd from last frame
- int entityeventTime[1024]; //last entity event time
- //
- bot_settings_t settings; //several bot settings
- int (*ainode)(struct bot_state_s *bs); //current AI node
- float thinktime; //time the bot thinks this frame
- vec3_t origin; //origin of the bot
- vec3_t velocity; //velocity of the bot
- int presencetype; //presence type of the bot
- vec3_t eye; //eye coordinates of the bot
- int areanum; //the number of the area the bot is in
- int inventory[MAX_ITEMS]; //string with items amounts the bot has
- int tfl; //the travel flags the bot uses
- int flags; //several flags
- int respawn_wait; //wait until respawned
- int lasthealth; //health value previous frame
- int lastkilledplayer; //last killed player
- int lastkilledby; //player that last killed this bot
- int botdeathtype; //the death type of the bot
- int enemydeathtype; //the death type of the enemy
- int botsuicide; //true when the bot suicides
- int enemysuicide; //true when the enemy of the bot suicides
- int setupcount; //true when the bot has just been setup
- int map_restart; //true when the map is being restarted
- int entergamechat; //true when the bot used an enter game chat
- int num_deaths; //number of time this bot died
- int num_kills; //number of kills of this bot
- int revenge_enemy; //the revenge enemy
- int revenge_kills; //number of kills the enemy made
- int lastframe_health; //health value the last frame
- int lasthitcount; //number of hits last frame
- int chatto; //chat to all or team
- float walker; //walker charactertic
- float ltime; //local bot time
- float entergame_time; //time the bot entered the game
- float ltg_time; //long term goal time
- float nbg_time; //nearby goal time
- float respawn_time; //time the bot takes to respawn
- float respawnchat_time; //time the bot started a chat during respawn
- float chase_time; //time the bot will chase the enemy
- float enemyvisible_time; //time the enemy was last visible
- float check_time; //time to check for nearby items
- float stand_time; //time the bot is standing still
- float lastchat_time; //time the bot last selected a chat
- float kamikaze_time; //time to check for kamikaze usage
- float invulnerability_time; //time to check for invulnerability usage
- float standfindenemy_time; //time to find enemy while standing
- float attackstrafe_time; //time the bot is strafing in one dir
- float attackcrouch_time; //time the bot will stop crouching
- float attackchase_time; //time the bot chases during actual attack
- float attackjump_time; //time the bot jumped during attack
- float enemysight_time; //time before reacting to enemy
- float enemydeath_time; //time the enemy died
- float enemyposition_time; //time the position and velocity of the enemy were stored
- float defendaway_time; //time away while defending
- float defendaway_range; //max travel time away from defend area
- float rushbaseaway_time; //time away from rushing to the base
- float attackaway_time; //time away from attacking the enemy base
- float harvestaway_time; //time away from harvesting
- float ctfroam_time; //time the bot is roaming in ctf
- float killedenemy_time; //time the bot killed the enemy
- float arrive_time; //time arrived (at companion)
- float lastair_time; //last time the bot had air
- float teleport_time; //last time the bot teleported
- float camp_time; //last time camped
- float camp_range; //camp range
- float weaponchange_time; //time the bot started changing weapons
- float firethrottlewait_time; //amount of time to wait
- float firethrottleshoot_time; //amount of time to shoot
- float notblocked_time; //last time the bot was not blocked
- float blockedbyavoidspot_time; //time blocked by an avoid spot
- float predictobstacles_time; //last time the bot predicted obstacles
- int predictobstacles_goalareanum; //last goal areanum the bot predicted obstacles for
- vec3_t aimtarget;
- vec3_t enemyvelocity; //enemy velocity 0.5 secs ago during battle
- vec3_t enemyorigin; //enemy origin 0.5 secs ago during battle
- //
- int kamikazebody; //kamikaze body
- int proxmines[MAX_PROXMINES];
- int numproxmines;
- //
- int character; //the bot character
- int ms; //move state of the bot
- int gs; //goal state of the bot
- int cs; //chat state of the bot
- int ws; //weapon state of the bot
- //
- int enemy; //enemy entity number
- int lastenemyareanum; //last reachability area the enemy was in
- vec3_t lastenemyorigin; //last origin of the enemy in the reachability area
- int weaponnum; //current weapon number
- vec3_t viewangles; //current view angles
- vec3_t ideal_viewangles; //ideal view angles
- vec3_t viewanglespeed;
- //
- int ltgtype; //long term goal type
- // team goals
- int teammate; //team mate involved in this team goal
- int decisionmaker; //player who decided to go for this goal
- int ordered; //true if ordered to do something
- float order_time; //time ordered to do something
- int owndecision_time; //time the bot made it's own decision
- bot_goal_t teamgoal; //the team goal
- bot_goal_t altroutegoal; //alternative route goal
- float reachedaltroutegoal_time; //time the bot reached the alt route goal
- float teammessage_time; //time to message team mates what the bot is doing
- float teamgoal_time; //time to stop helping team mate
- float teammatevisible_time; //last time the team mate was NOT visible
- int teamtaskpreference; //team task preference
- // last ordered team goal
- int lastgoal_decisionmaker;
- int lastgoal_ltgtype;
- int lastgoal_teammate;
- bot_goal_t lastgoal_teamgoal;
- // for leading team mates
- int lead_teammate; //team mate the bot is leading
- bot_goal_t lead_teamgoal; //team goal while leading
- float lead_time; //time leading someone
- float leadvisible_time; //last time the team mate was visible
- float leadmessage_time; //last time a messaged was sent to the team mate
- float leadbackup_time; //time backing up towards team mate
- //
- char teamleader[32]; //netname of the team leader
- float askteamleader_time; //time asked for team leader
- float becometeamleader_time; //time the bot will become the team leader
- float teamgiveorders_time; //time to give team orders
- float lastflagcapture_time; //last time a flag was captured
- int numteammates; //number of team mates
- int redflagstatus; //0 = at base, 1 = not at base
- int blueflagstatus; //0 = at base, 1 = not at base
- int neutralflagstatus; //0 = at base, 1 = our team has flag, 2 = enemy team has flag, 3 = enemy team dropped the flag
- int flagstatuschanged; //flag status changed
- int forceorders; //true if forced to give orders
- int flagcarrier; //team mate carrying the enemy flag
- int ctfstrategy; //ctf strategy
- char subteam[32]; //sub team name
- float formation_dist; //formation team mate intervening space
- char formation_teammate[16]; //netname of the team mate the bot uses for relative positioning
- float formation_angle; //angle relative to the formation team mate
- vec3_t formation_dir; //the direction the formation is moving in
- vec3_t formation_origin; //origin the bot uses for relative positioning
- bot_goal_t formation_goal; //formation goal
-
- bot_activategoal_t *activatestack; //first activate goal on the stack
- bot_activategoal_t activategoalheap[MAX_ACTIVATESTACK]; //activate goal heap
-
- bot_waypoint_t *checkpoints; //check points
- bot_waypoint_t *patrolpoints; //patrol points
- bot_waypoint_t *curpatrolpoint; //current patrol point the bot is going for
- int patrolflags; //patrol flags
-} bot_state_t;
-
-//resets the whole bot state
-void BotResetState(bot_state_t *bs);
-//returns the number of bots in the game
-int NumBots(void);
-//returns info about the entity
-void BotEntityInfo(int entnum, aas_entityinfo_t *info);
-
-extern float floattime;
-#define FloatTime() floattime
-
-// from the game source
-void QDECL BotAI_Print(int type, char *fmt, ...);
-void QDECL QDECL BotAI_BotInitialChat( bot_state_t *bs, char *type, ... );
-void BotAI_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask);
-int BotAI_GetClientState( int clientNum, playerState_t *state );
-int BotAI_GetEntityState( int entityNum, entityState_t *state );
-int BotAI_GetSnapshotEntity( int clientNum, int sequence, entityState_t *state );
-int BotTeamLeader(bot_state_t *bs);
diff --git a/engine/code/game/ai_team.c b/engine/code/game/ai_team.c
deleted file mode 100644
index 858c16c..0000000
--- a/engine/code/game/ai_team.c
+++ /dev/null
@@ -1,2080 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_team.c
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /MissionPack/code/game/ai_team.c $
- *
- *****************************************************************************/
-
-#include "g_local.h"
-#include "../botlib/botlib.h"
-#include "../botlib/be_aas.h"
-#include "../botlib/be_ea.h"
-#include "../botlib/be_ai_char.h"
-#include "../botlib/be_ai_chat.h"
-#include "../botlib/be_ai_gen.h"
-#include "../botlib/be_ai_goal.h"
-#include "../botlib/be_ai_move.h"
-#include "../botlib/be_ai_weap.h"
-//
-#include "ai_main.h"
-#include "ai_dmq3.h"
-#include "ai_chat.h"
-#include "ai_cmd.h"
-#include "ai_dmnet.h"
-#include "ai_team.h"
-#include "ai_vcmd.h"
-
-#include "match.h"
-
-// for the voice chats
-#include "../../ui/menudef.h"
-
-//ctf task preferences for a client
-typedef struct bot_ctftaskpreference_s
-{
- char name[36];
- int preference;
-} bot_ctftaskpreference_t;
-
-bot_ctftaskpreference_t ctftaskpreferences[MAX_CLIENTS];
-
-
-/*
-==================
-BotValidTeamLeader
-==================
-*/
-int BotValidTeamLeader(bot_state_t *bs) {
- if (!strlen(bs->teamleader)) return qfalse;
- if (ClientFromName(bs->teamleader) == -1) return qfalse;
- return qtrue;
-}
-
-/*
-==================
-BotNumTeamMates
-==================
-*/
-int BotNumTeamMates(bot_state_t *bs) {
- int i, numplayers;
- char buf[MAX_INFO_STRING];
- static int maxclients;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- numplayers = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- if (BotSameTeam(bs, i)) {
- numplayers++;
- }
- }
- return numplayers;
-}
-
-/*
-==================
-BotClientTravelTimeToGoal
-==================
-*/
-int BotClientTravelTimeToGoal(int client, bot_goal_t *goal) {
- playerState_t ps;
- int areanum;
-
- BotAI_GetClientState(client, &ps);
- areanum = BotPointAreaNum(ps.origin);
- if (!areanum) return 1;
- return trap_AAS_AreaTravelTimeToGoalArea(areanum, ps.origin, goal->areanum, TFL_DEFAULT);
-}
-
-/*
-==================
-BotSortTeamMatesByBaseTravelTime
-==================
-*/
-int BotSortTeamMatesByBaseTravelTime(bot_state_t *bs, int *teammates, int maxteammates) {
-
- int i, j, k, numteammates, traveltime;
- char buf[MAX_INFO_STRING];
- static int maxclients;
- int traveltimes[MAX_CLIENTS];
- bot_goal_t *goal = NULL;
-
- if (gametype == GT_CTF || gametype == GT_1FCTF) {
- if (BotTeam(bs) == TEAM_RED)
- goal = &ctf_redflag;
- else
- goal = &ctf_blueflag;
- }
-#ifdef MISSIONPACK
- else {
- if (BotTeam(bs) == TEAM_RED)
- goal = &redobelisk;
- else
- goal = &blueobelisk;
- }
-#endif
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- numteammates = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- if (BotSameTeam(bs, i)) {
- //
- traveltime = BotClientTravelTimeToGoal(i, goal);
- //
- for (j = 0; j < numteammates; j++) {
- if (traveltime < traveltimes[j]) {
- for (k = numteammates; k > j; k--) {
- traveltimes[k] = traveltimes[k-1];
- teammates[k] = teammates[k-1];
- }
- break;
- }
- }
- traveltimes[j] = traveltime;
- teammates[j] = i;
- numteammates++;
- if (numteammates >= maxteammates) break;
- }
- }
- return numteammates;
-}
-
-/*
-==================
-BotSetTeamMateTaskPreference
-==================
-*/
-void BotSetTeamMateTaskPreference(bot_state_t *bs, int teammate, int preference) {
- char teammatename[MAX_NETNAME];
-
- ctftaskpreferences[teammate].preference = preference;
- ClientName(teammate, teammatename, sizeof(teammatename));
- strcpy(ctftaskpreferences[teammate].name, teammatename);
-}
-
-/*
-==================
-BotGetTeamMateTaskPreference
-==================
-*/
-int BotGetTeamMateTaskPreference(bot_state_t *bs, int teammate) {
- char teammatename[MAX_NETNAME];
-
- if (!ctftaskpreferences[teammate].preference) return 0;
- ClientName(teammate, teammatename, sizeof(teammatename));
- if (Q_stricmp(teammatename, ctftaskpreferences[teammate].name)) return 0;
- return ctftaskpreferences[teammate].preference;
-}
-
-/*
-==================
-BotSortTeamMatesByTaskPreference
-==================
-*/
-int BotSortTeamMatesByTaskPreference(bot_state_t *bs, int *teammates, int numteammates) {
- int defenders[MAX_CLIENTS], numdefenders;
- int attackers[MAX_CLIENTS], numattackers;
- int roamers[MAX_CLIENTS], numroamers;
- int i, preference;
-
- numdefenders = numattackers = numroamers = 0;
- for (i = 0; i < numteammates; i++) {
- preference = BotGetTeamMateTaskPreference(bs, teammates[i]);
- if (preference & TEAMTP_DEFENDER) {
- defenders[numdefenders++] = teammates[i];
- }
- else if (preference & TEAMTP_ATTACKER) {
- attackers[numattackers++] = teammates[i];
- }
- else {
- roamers[numroamers++] = teammates[i];
- }
- }
- numteammates = 0;
- //defenders at the front of the list
- memcpy(&teammates[numteammates], defenders, numdefenders * sizeof(int));
- numteammates += numdefenders;
- //roamers in the middle
- memcpy(&teammates[numteammates], roamers, numroamers * sizeof(int));
- numteammates += numroamers;
- //attacker in the back of the list
- memcpy(&teammates[numteammates], attackers, numattackers * sizeof(int));
- numteammates += numattackers;
-
- return numteammates;
-}
-
-/*
-==================
-BotSayTeamOrders
-==================
-*/
-void BotSayTeamOrderAlways(bot_state_t *bs, int toclient) {
- char teamchat[MAX_MESSAGE_SIZE];
- char buf[MAX_MESSAGE_SIZE];
- char name[MAX_NETNAME];
-
- //if the bot is talking to itself
- if (bs->client == toclient) {
- //don't show the message just put it in the console message queue
- trap_BotGetChatMessage(bs->cs, buf, sizeof(buf));
- ClientName(bs->client, name, sizeof(name));
- Com_sprintf(teamchat, sizeof(teamchat), EC"(%s"EC")"EC": %s", name, buf);
- trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, teamchat);
- }
- else {
- trap_BotEnterChat(bs->cs, toclient, CHAT_TELL);
- }
-}
-
-/*
-==================
-BotSayTeamOrders
-==================
-*/
-void BotSayTeamOrder(bot_state_t *bs, int toclient) {
-#ifdef MISSIONPACK
- // voice chats only
- char buf[MAX_MESSAGE_SIZE];
-
- trap_BotGetChatMessage(bs->cs, buf, sizeof(buf));
-#else
- BotSayTeamOrderAlways(bs, toclient);
-#endif
-}
-
-/*
-==================
-BotVoiceChat
-==================
-*/
-void BotVoiceChat(bot_state_t *bs, int toclient, char *voicechat) {
-#ifdef MISSIONPACK
- if (toclient == -1)
- // voice only say team
- trap_EA_Command(bs->client, va("vsay_team %s", voicechat));
- else
- // voice only tell single player
- trap_EA_Command(bs->client, va("vtell %d %s", toclient, voicechat));
-#endif
-}
-
-/*
-==================
-BotVoiceChatOnly
-==================
-*/
-void BotVoiceChatOnly(bot_state_t *bs, int toclient, char *voicechat) {
-#ifdef MISSIONPACK
- if (toclient == -1)
- // voice only say team
- trap_EA_Command(bs->client, va("vosay_team %s", voicechat));
- else
- // voice only tell single player
- trap_EA_Command(bs->client, va("votell %d %s", toclient, voicechat));
-#endif
-}
-
-/*
-==================
-BotSayVoiceTeamOrder
-==================
-*/
-void BotSayVoiceTeamOrder(bot_state_t *bs, int toclient, char *voicechat) {
-#ifdef MISSIONPACK
- BotVoiceChat(bs, toclient, voicechat);
-#endif
-}
-
-/*
-==================
-BotCTFOrders
-==================
-*/
-void BotCTFOrders_BothFlagsNotAtBase(bot_state_t *bs) {
- int numteammates, defenders, attackers, i, other;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME], carriername[MAX_NETNAME];
-
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //different orders based on the number of team mates
- switch(bs->numteammates) {
- case 1: break;
- case 2:
- {
- //tell the one not carrying the flag to attack the enemy base
- if (teammates[0] != bs->flagcarrier) other = teammates[0];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //tell the one closest to the base not carrying the flag to accompany the flag carrier
- if (teammates[0] != bs->flagcarrier) other = teammates[0];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- if ( bs->flagcarrier != -1 ) {
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- if (bs->flagcarrier == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
- }
- }
- else {
- //
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
- }
- BotSayTeamOrder(bs, other);
- //tell the one furthest from the the base not carrying the flag to get the enemy flag
- if (teammates[2] != bs->flagcarrier) other = teammates[2];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_RETURNFLAG);
- break;
- }
- default:
- {
- defenders = (int) (float) numteammates * 0.4 + 0.5;
- if (defenders > 4) defenders = 4;
- attackers = (int) (float) numteammates * 0.5 + 0.5;
- if (attackers > 5) attackers = 5;
- if (bs->flagcarrier != -1) {
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- for (i = 0; i < defenders; i++) {
- //
- if (teammates[i] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[i], name, sizeof(name));
- if (bs->flagcarrier == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWME);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWFLAGCARRIER);
- }
- BotSayTeamOrder(bs, teammates[i]);
- }
- }
- else {
- for (i = 0; i < defenders; i++) {
- //
- if (teammates[i] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_GETFLAG);
- BotSayTeamOrder(bs, teammates[i]);
- }
- }
- for (i = 0; i < attackers; i++) {
- //
- if (teammates[numteammates - i - 1] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_RETURNFLAG);
- }
- //
- break;
- }
- }
-}
-
-/*
-==================
-BotCTFOrders
-==================
-*/
-void BotCTFOrders_FlagNotAtBase(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
-
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(bs->numteammates) {
- case 1: break;
- case 2:
- {
- //both will go for the enemy flag
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //keep one near the base for when the flag is returned
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other two get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //keep some people near the base for when the flag is returned
- defenders = (int) (float) numteammates * 0.3 + 0.5;
- if (defenders > 3) defenders = 3;
- attackers = (int) (float) numteammates * 0.7 + 0.5;
- if (attackers > 6) attackers = 6;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
- else {
- //different orders based on the number of team mates
- switch(bs->numteammates) {
- case 1: break;
- case 2:
- {
- //both will go for the enemy flag
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //everyone go for the flag
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //keep some people near the base for when the flag is returned
- defenders = (int) (float) numteammates * 0.2 + 0.5;
- if (defenders > 2) defenders = 2;
- attackers = (int) (float) numteammates * 0.7 + 0.5;
- if (attackers > 7) attackers = 7;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-BotCTFOrders
-==================
-*/
-void BotCTFOrders_EnemyFlagNotAtBase(bot_state_t *bs) {
- int numteammates, defenders, attackers, i, other;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME], carriername[MAX_NETNAME];
-
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //tell the one not carrying the flag to defend the base
- if (teammates[0] == bs->flagcarrier) other = teammates[1];
- else other = teammates[0];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
- break;
- }
- case 3:
- {
- //tell the one closest to the base not carrying the flag to defend the base
- if (teammates[0] != bs->flagcarrier) other = teammates[0];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
- //tell the other also to defend the base
- if (teammates[2] != bs->flagcarrier) other = teammates[2];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
- break;
- }
- default:
- {
- //60% will defend the base
- defenders = (int) (float) numteammates * 0.6 + 0.5;
- if (defenders > 6) defenders = 6;
- //30% accompanies the flag carrier
- attackers = (int) (float) numteammates * 0.3 + 0.5;
- if (attackers > 3) attackers = 3;
- for (i = 0; i < defenders; i++) {
- //
- if (teammates[i] == bs->flagcarrier) {
- continue;
- }
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- // if we have a flag carrier
- if ( bs->flagcarrier != -1 ) {
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- for (i = 0; i < attackers; i++) {
- //
- if (teammates[numteammates - i - 1] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- if (bs->flagcarrier == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
- }
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- }
- }
- else {
- for (i = 0; i < attackers; i++) {
- //
- if (teammates[numteammates - i - 1] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- }
- }
- //
- break;
- }
- }
-}
-
-
-/*
-==================
-BotCTFOrders
-==================
-*/
-void BotCTFOrders_BothFlagsAtBase(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the second one closest to the base will defend the base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- defenders = (int) (float) numteammates * 0.5 + 0.5;
- if (defenders > 5) defenders = 5;
- attackers = (int) (float) numteammates * 0.4 + 0.5;
- if (attackers > 4) attackers = 4;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
- else {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the others should go for the enemy flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- defenders = (int) (float) numteammates * 0.4 + 0.5;
- if (defenders > 4) defenders = 4;
- attackers = (int) (float) numteammates * 0.5 + 0.5;
- if (attackers > 5) attackers = 5;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-BotCTFOrders
-==================
-*/
-void BotCTFOrders(bot_state_t *bs) {
- int flagstatus;
-
- //
- if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus;
- else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus;
- //
- switch(flagstatus) {
- case 0: BotCTFOrders_BothFlagsAtBase(bs); break;
- case 1: BotCTFOrders_EnemyFlagNotAtBase(bs); break;
- case 2: BotCTFOrders_FlagNotAtBase(bs); break;
- case 3: BotCTFOrders_BothFlagsNotAtBase(bs); break;
- }
-}
-
-
-/*
-==================
-BotCreateGroup
-==================
-*/
-void BotCreateGroup(bot_state_t *bs, int *teammates, int groupsize) {
- char name[MAX_NETNAME], leadername[MAX_NETNAME];
- int i;
-
- // the others in the group will follow the teammates[0]
- ClientName(teammates[0], leadername, sizeof(leadername));
- for (i = 1; i < groupsize; i++)
- {
- ClientName(teammates[i], name, sizeof(name));
- if (teammates[0] == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, leadername, NULL);
- }
- BotSayTeamOrderAlways(bs, teammates[i]);
- }
-}
-
-/*
-==================
-BotTeamOrders
-
- FIXME: defend key areas?
-==================
-*/
-void BotTeamOrders(bot_state_t *bs) {
- int teammates[MAX_CLIENTS];
- int numteammates, i;
- char buf[MAX_INFO_STRING];
- static int maxclients;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- numteammates = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- if (BotSameTeam(bs, i)) {
- teammates[numteammates] = i;
- numteammates++;
- }
- }
- //
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //nothing special
- break;
- }
- case 3:
- {
- //have one follow another and one free roaming
- BotCreateGroup(bs, teammates, 2);
- break;
- }
- case 4:
- {
- BotCreateGroup(bs, teammates, 2); //a group of 2
- BotCreateGroup(bs, &teammates[2], 2); //a group of 2
- break;
- }
- case 5:
- {
- BotCreateGroup(bs, teammates, 2); //a group of 2
- BotCreateGroup(bs, &teammates[2], 3); //a group of 3
- break;
- }
- default:
- {
- if (numteammates <= 10) {
- for (i = 0; i < numteammates / 2; i++) {
- BotCreateGroup(bs, &teammates[i*2], 2); //groups of 2
- }
- }
- break;
- }
- }
-}
-
-#ifdef MISSIONPACK
-
-/*
-==================
-Bot1FCTFOrders_FlagAtCenter
-
- X% defend the base, Y% get the flag
-==================
-*/
-void Bot1FCTFOrders_FlagAtCenter(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the second one closest to the base will defend the base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //50% defend the base
- defenders = (int) (float) numteammates * 0.5 + 0.5;
- if (defenders > 5) defenders = 5;
- //40% get the flag
- attackers = (int) (float) numteammates * 0.4 + 0.5;
- if (attackers > 4) attackers = 4;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
- else { //agressive
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the others should go for the enemy flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //30% defend the base
- defenders = (int) (float) numteammates * 0.3 + 0.5;
- if (defenders > 3) defenders = 3;
- //60% get the flag
- attackers = (int) (float) numteammates * 0.6 + 0.5;
- if (attackers > 6) attackers = 6;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-Bot1FCTFOrders_TeamHasFlag
-
- X% towards neutral flag, Y% go towards enemy base and accompany flag carrier if visible
-==================
-*/
-void Bot1FCTFOrders_TeamHasFlag(bot_state_t *bs) {
- int numteammates, defenders, attackers, i, other;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME], carriername[MAX_NETNAME];
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //tell the one not carrying the flag to attack the enemy base
- if (teammates[0] == bs->flagcarrier) other = teammates[1];
- else other = teammates[0];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_OFFENSE);
- break;
- }
- case 3:
- {
- //tell the one closest to the base not carrying the flag to defend the base
- if (teammates[0] != bs->flagcarrier) other = teammates[0];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
- //tell the one furthest from the base not carrying the flag to accompany the flag carrier
- if (teammates[2] != bs->flagcarrier) other = teammates[2];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- if ( bs->flagcarrier != -1 ) {
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- if (bs->flagcarrier == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
- }
- }
- else {
- //
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
- }
- BotSayTeamOrder(bs, other);
- break;
- }
- default:
- {
- //30% will defend the base
- defenders = (int) (float) numteammates * 0.3 + 0.5;
- if (defenders > 3) defenders = 3;
- //70% accompanies the flag carrier
- attackers = (int) (float) numteammates * 0.7 + 0.5;
- if (attackers > 7) attackers = 7;
- for (i = 0; i < defenders; i++) {
- //
- if (teammates[i] == bs->flagcarrier) {
- continue;
- }
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- if (bs->flagcarrier != -1) {
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- for (i = 0; i < attackers; i++) {
- //
- if (teammates[numteammates - i - 1] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- if (bs->flagcarrier == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
- }
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- }
- }
- else {
- for (i = 0; i < attackers; i++) {
- //
- if (teammates[numteammates - i - 1] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- }
- //
- break;
- }
- }
- }
- else { //agressive
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //tell the one not carrying the flag to defend the base
- if (teammates[0] == bs->flagcarrier) other = teammates[1];
- else other = teammates[0];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
- break;
- }
- case 3:
- {
- //tell the one closest to the base not carrying the flag to defend the base
- if (teammates[0] != bs->flagcarrier) other = teammates[0];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
- //tell the one furthest from the base not carrying the flag to accompany the flag carrier
- if (teammates[2] != bs->flagcarrier) other = teammates[2];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- if (bs->flagcarrier == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
- }
- BotSayTeamOrder(bs, other);
- break;
- }
- default:
- {
- //20% will defend the base
- defenders = (int) (float) numteammates * 0.2 + 0.5;
- if (defenders > 2) defenders = 2;
- //80% accompanies the flag carrier
- attackers = (int) (float) numteammates * 0.8 + 0.5;
- if (attackers > 8) attackers = 8;
- for (i = 0; i < defenders; i++) {
- //
- if (teammates[i] == bs->flagcarrier) {
- continue;
- }
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- for (i = 0; i < attackers; i++) {
- //
- if (teammates[numteammates - i - 1] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- if (bs->flagcarrier == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
- }
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-Bot1FCTFOrders_EnemyHasFlag
-
- X% defend the base, Y% towards neutral flag
-==================
-*/
-void Bot1FCTFOrders_EnemyHasFlag(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //both defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the second one closest to the base will defend the base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- //the other will also defend the base
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_DEFEND);
- break;
- }
- default:
- {
- //80% will defend the base
- defenders = (int) (float) numteammates * 0.8 + 0.5;
- if (defenders > 8) defenders = 8;
- //10% will try to return the flag
- attackers = (int) (float) numteammates * 0.1 + 0.5;
- if (attackers > 2) attackers = 2;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
- else { //agressive
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the others should go for the enemy flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //70% defend the base
- defenders = (int) (float) numteammates * 0.7 + 0.5;
- if (defenders > 8) defenders = 8;
- //20% try to return the flag
- attackers = (int) (float) numteammates * 0.2 + 0.5;
- if (attackers > 2) attackers = 2;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-Bot1FCTFOrders_EnemyDroppedFlag
-
- X% defend the base, Y% get the flag
-==================
-*/
-void Bot1FCTFOrders_EnemyDroppedFlag(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the second one closest to the base will defend the base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //50% defend the base
- defenders = (int) (float) numteammates * 0.5 + 0.5;
- if (defenders > 5) defenders = 5;
- //40% get the flag
- attackers = (int) (float) numteammates * 0.4 + 0.5;
- if (attackers > 4) attackers = 4;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
- else { //agressive
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the others should go for the enemy flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //30% defend the base
- defenders = (int) (float) numteammates * 0.3 + 0.5;
- if (defenders > 3) defenders = 3;
- //60% get the flag
- attackers = (int) (float) numteammates * 0.6 + 0.5;
- if (attackers > 6) attackers = 6;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_DEFEND);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-Bot1FCTFOrders
-==================
-*/
-void Bot1FCTFOrders(bot_state_t *bs) {
- switch(bs->neutralflagstatus) {
- case 0: Bot1FCTFOrders_FlagAtCenter(bs); break;
- case 1: Bot1FCTFOrders_TeamHasFlag(bs); break;
- case 2: Bot1FCTFOrders_EnemyHasFlag(bs); break;
- case 3: Bot1FCTFOrders_EnemyDroppedFlag(bs); break;
- }
-}
-
-/*
-==================
-BotObeliskOrders
-
- X% in defence Y% in offence
-==================
-*/
-void BotObeliskOrders(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will attack the enemy base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the one second closest to the base also defends the base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- //the other one attacks the enemy base
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
- break;
- }
- default:
- {
- //50% defend the base
- defenders = (int) (float) numteammates * 0.5 + 0.5;
- if (defenders > 5) defenders = 5;
- //40% attack the enemy base
- attackers = (int) (float) numteammates * 0.4 + 0.5;
- if (attackers > 4) attackers = 4;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
- }
- //
- break;
- }
- }
- }
- else {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will attack the enemy base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the others attack the enemy base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
- break;
- }
- default:
- {
- //30% defend the base
- defenders = (int) (float) numteammates * 0.3 + 0.5;
- if (defenders > 3) defenders = 3;
- //70% attack the enemy base
- attackers = (int) (float) numteammates * 0.7 + 0.5;
- if (attackers > 7) attackers = 7;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-BotHarvesterOrders
-
- X% defend the base, Y% harvest
-==================
-*/
-void BotHarvesterOrders(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will harvest
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the one second closest to the base also defends the base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- //the other one goes harvesting
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
- break;
- }
- default:
- {
- //50% defend the base
- defenders = (int) (float) numteammates * 0.5 + 0.5;
- if (defenders > 5) defenders = 5;
- //40% goes harvesting
- attackers = (int) (float) numteammates * 0.4 + 0.5;
- if (attackers > 4) attackers = 4;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
- }
- //
- break;
- }
- }
- }
- else {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will harvest
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the others go harvesting
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
- break;
- }
- default:
- {
- //30% defend the base
- defenders = (int) (float) numteammates * 0.3 + 0.5;
- if (defenders > 3) defenders = 3;
- //70% go harvesting
- attackers = (int) (float) numteammates * 0.7 + 0.5;
- if (attackers > 7) attackers = 7;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
- }
- //
- break;
- }
- }
- }
-}
-#endif
-
-/*
-==================
-FindHumanTeamLeader
-==================
-*/
-int FindHumanTeamLeader(bot_state_t *bs) {
- int i;
-
- for (i = 0; i < MAX_CLIENTS; i++) {
- if ( g_entities[i].inuse ) {
- // if this player is not a bot
- if ( !(g_entities[i].r.svFlags & SVF_BOT) ) {
- // if this player is ok with being the leader
- if (!notleader[i]) {
- // if this player is on the same team
- if ( BotSameTeam(bs, i) ) {
- ClientName(i, bs->teamleader, sizeof(bs->teamleader));
- // if not yet ordered to do anything
- if ( !BotSetLastOrderedTask(bs) ) {
- // go on defense by default
- BotVoiceChat_Defend(bs, i, SAY_TELL);
- }
- return qtrue;
- }
- }
- }
- }
- }
- return qfalse;
-}
-
-/*
-==================
-BotTeamAI
-==================
-*/
-void BotTeamAI(bot_state_t *bs) {
- int numteammates;
- char netname[MAX_NETNAME];
-
- //
- if ( gametype < GT_TEAM )
- return;
- // make sure we've got a valid team leader
- if (!BotValidTeamLeader(bs)) {
- //
- if (!FindHumanTeamLeader(bs)) {
- //
- if (!bs->askteamleader_time && !bs->becometeamleader_time) {
- if (bs->entergame_time + 10 > FloatTime()) {
- bs->askteamleader_time = FloatTime() + 5 + random() * 10;
- }
- else {
- bs->becometeamleader_time = FloatTime() + 5 + random() * 10;
- }
- }
- if (bs->askteamleader_time && bs->askteamleader_time < FloatTime()) {
- // if asked for a team leader and no response
- BotAI_BotInitialChat(bs, "whoisteamleader", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- bs->askteamleader_time = 0;
- bs->becometeamleader_time = FloatTime() + 8 + random() * 10;
- }
- if (bs->becometeamleader_time && bs->becometeamleader_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "iamteamleader", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotSayVoiceTeamOrder(bs, -1, VOICECHAT_STARTLEADER);
- ClientName(bs->client, netname, sizeof(netname));
- strncpy(bs->teamleader, netname, sizeof(bs->teamleader));
- bs->teamleader[sizeof(bs->teamleader)-1] = '\0';
- bs->becometeamleader_time = 0;
- }
- return;
- }
- }
- bs->askteamleader_time = 0;
- bs->becometeamleader_time = 0;
-
- //return if this bot is NOT the team leader
- ClientName(bs->client, netname, sizeof(netname));
- if (Q_stricmp(netname, bs->teamleader) != 0) return;
- //
- numteammates = BotNumTeamMates(bs);
- //give orders
- switch(gametype) {
- case GT_TEAM:
- {
- if (bs->numteammates != numteammates || bs->forceorders) {
- bs->teamgiveorders_time = FloatTime();
- bs->numteammates = numteammates;
- bs->forceorders = qfalse;
- }
- //if it's time to give orders
- if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
- BotTeamOrders(bs);
- //give orders again after 120 seconds
- bs->teamgiveorders_time = FloatTime() + 120;
- }
- break;
- }
- case GT_CTF:
- {
- //if the number of team mates changed or the flag status changed
- //or someone wants to know what to do
- if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) {
- bs->teamgiveorders_time = FloatTime();
- bs->numteammates = numteammates;
- bs->flagstatuschanged = qfalse;
- bs->forceorders = qfalse;
- }
- //if there were no flag captures the last 3 minutes
- if (bs->lastflagcapture_time < FloatTime() - 240) {
- bs->lastflagcapture_time = FloatTime();
- //randomly change the CTF strategy
- if (random() < 0.4) {
- bs->ctfstrategy ^= CTFS_AGRESSIVE;
- bs->teamgiveorders_time = FloatTime();
- }
- }
- //if it's time to give orders
- if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 3) {
- BotCTFOrders(bs);
- //
- bs->teamgiveorders_time = 0;
- }
- break;
- }
-#ifdef MISSIONPACK
- case GT_1FCTF:
- {
- if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) {
- bs->teamgiveorders_time = FloatTime();
- bs->numteammates = numteammates;
- bs->flagstatuschanged = qfalse;
- bs->forceorders = qfalse;
- }
- //if there were no flag captures the last 4 minutes
- if (bs->lastflagcapture_time < FloatTime() - 240) {
- bs->lastflagcapture_time = FloatTime();
- //randomly change the CTF strategy
- if (random() < 0.4) {
- bs->ctfstrategy ^= CTFS_AGRESSIVE;
- bs->teamgiveorders_time = FloatTime();
- }
- }
- //if it's time to give orders
- if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 2) {
- Bot1FCTFOrders(bs);
- //
- bs->teamgiveorders_time = 0;
- }
- break;
- }
- case GT_OBELISK:
- {
- if (bs->numteammates != numteammates || bs->forceorders) {
- bs->teamgiveorders_time = FloatTime();
- bs->numteammates = numteammates;
- bs->forceorders = qfalse;
- }
- //if it's time to give orders
- if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
- BotObeliskOrders(bs);
- //give orders again after 30 seconds
- bs->teamgiveorders_time = FloatTime() + 30;
- }
- break;
- }
- case GT_HARVESTER:
- {
- if (bs->numteammates != numteammates || bs->forceorders) {
- bs->teamgiveorders_time = FloatTime();
- bs->numteammates = numteammates;
- bs->forceorders = qfalse;
- }
- //if it's time to give orders
- if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
- BotHarvesterOrders(bs);
- //give orders again after 30 seconds
- bs->teamgiveorders_time = FloatTime() + 30;
- }
- break;
- }
-#endif
- }
-}
-
diff --git a/engine/code/game/ai_vcmd.c b/engine/code/game/ai_vcmd.c
deleted file mode 100644
index 205c4b8..0000000
--- a/engine/code/game/ai_vcmd.c
+++ /dev/null
@@ -1,550 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_vcmd.c
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /MissionPack/code/game/ai_vcmd.c $
- *
- *****************************************************************************/
-
-#include "g_local.h"
-#include "../botlib/botlib.h"
-#include "../botlib/be_aas.h"
-#include "../botlib/be_ea.h"
-#include "../botlib/be_ai_char.h"
-#include "../botlib/be_ai_chat.h"
-#include "../botlib/be_ai_gen.h"
-#include "../botlib/be_ai_goal.h"
-#include "../botlib/be_ai_move.h"
-#include "../botlib/be_ai_weap.h"
-//
-#include "ai_main.h"
-#include "ai_dmq3.h"
-#include "ai_chat.h"
-#include "ai_cmd.h"
-#include "ai_dmnet.h"
-#include "ai_team.h"
-#include "ai_vcmd.h"
-//
-#include "chars.h" //characteristics
-#include "inv.h" //indexes into the inventory
-#include "syn.h" //synonyms
-#include "match.h" //string matching types and vars
-
-// for the voice chats
-#include "../../ui/menudef.h"
-
-
-typedef struct voiceCommand_s
-{
- char *cmd;
- void (*func)(bot_state_t *bs, int client, int mode);
-} voiceCommand_t;
-
-/*
-==================
-BotVoiceChat_GetFlag
-==================
-*/
-void BotVoiceChat_GetFlag(bot_state_t *bs, int client, int mode) {
- //
- if (gametype == GT_CTF) {
- if (!ctf_redflag.areanum || !ctf_blueflag.areanum)
- return;
- }
-#ifdef MISSIONPACK
- else if (gametype == GT_1FCTF) {
- if (!ctf_neutralflag.areanum || !ctf_redflag.areanum || !ctf_blueflag.areanum)
- return;
- }
-#endif
- else {
- return;
- }
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_GETFLAG;
- //set the team goal time
- bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
- // get an alternate route in ctf
- if (gametype == GT_CTF) {
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- }
- //
- BotSetTeamStatus(bs);
- // remember last ordered task
- BotRememberLastOrderedTask(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotVoiceChat_Offense
-==================
-*/
-void BotVoiceChat_Offense(bot_state_t *bs, int client, int mode) {
- if ( gametype == GT_CTF
-#ifdef MISSIONPACK
- || gametype == GT_1FCTF
-#endif
- ) {
- BotVoiceChat_GetFlag(bs, client, mode);
- return;
- }
-#ifdef MISSIONPACK
- if (gametype == GT_HARVESTER) {
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_HARVEST;
- //set the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME;
- bs->harvestaway_time = 0;
- //
- BotSetTeamStatus(bs);
- // remember last ordered task
- BotRememberLastOrderedTask(bs);
- }
- else
-#endif
- {
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_ATTACKENEMYBASE;
- //set the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
- bs->attackaway_time = 0;
- //
- BotSetTeamStatus(bs);
- // remember last ordered task
- BotRememberLastOrderedTask(bs);
- }
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotVoiceChat_Defend
-==================
-*/
-void BotVoiceChat_Defend(bot_state_t *bs, int client, int mode) {
-#ifdef MISSIONPACK
- if ( gametype == GT_OBELISK || gametype == GT_HARVESTER) {
- //
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); break;
- default: return;
- }
- }
- else
-#endif
- if (gametype == GT_CTF
-#ifdef MISSIONPACK
- || gametype == GT_1FCTF
-#endif
- ) {
- //
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); break;
- default: return;
- }
- }
- else {
- return;
- }
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_DEFENDKEYAREA;
- //get the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
- //away from defending
- bs->defendaway_time = 0;
- //
- BotSetTeamStatus(bs);
- // remember last ordered task
- BotRememberLastOrderedTask(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotVoiceChat_DefendFlag
-==================
-*/
-void BotVoiceChat_DefendFlag(bot_state_t *bs, int client, int mode) {
- BotVoiceChat_Defend(bs, client, mode);
-}
-
-/*
-==================
-BotVoiceChat_Patrol
-==================
-*/
-void BotVoiceChat_Patrol(bot_state_t *bs, int client, int mode) {
- //
- bs->decisionmaker = client;
- //
- bs->ltgtype = 0;
- bs->lead_time = 0;
- bs->lastgoal_ltgtype = 0;
- //
- BotAI_BotInitialChat(bs, "dismissed", NULL);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONPATROL);
- //
- BotSetTeamStatus(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotVoiceChat_Camp
-==================
-*/
-void BotVoiceChat_Camp(bot_state_t *bs, int client, int mode) {
- int areanum;
- aas_entityinfo_t entinfo;
- char netname[MAX_NETNAME];
-
- //
- bs->teamgoal.entitynum = -1;
- BotEntityInfo(client, &entinfo);
- //if info is valid (in PVS)
- if (entinfo.valid) {
- areanum = BotPointAreaNum(entinfo.origin);
- if (areanum) { // && trap_AAS_AreaReachability(areanum)) {
- //NOTE: just assume the bot knows where the person is
- //if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, client)) {
- bs->teamgoal.entitynum = client;
- bs->teamgoal.areanum = areanum;
- VectorCopy(entinfo.origin, bs->teamgoal.origin);
- VectorSet(bs->teamgoal.mins, -8, -8, -8);
- VectorSet(bs->teamgoal.maxs, 8, 8, 8);
- //}
- }
- }
- //if the other is not visible
- if (bs->teamgoal.entitynum < 0) {
- BotAI_BotInitialChat(bs, "whereareyou", EasyClientName(client, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
- return;
- }
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_CAMPORDER;
- //get the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_CAMP_TIME;
- //the teammate that requested the camping
- bs->teammate = client;
- //not arrived yet
- bs->arrive_time = 0;
- //
- BotSetTeamStatus(bs);
- // remember last ordered task
- BotRememberLastOrderedTask(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotVoiceChat_FollowMe
-==================
-*/
-void BotVoiceChat_FollowMe(bot_state_t *bs, int client, int mode) {
- int areanum;
- aas_entityinfo_t entinfo;
- char netname[MAX_NETNAME];
-
- bs->teamgoal.entitynum = -1;
- BotEntityInfo(client, &entinfo);
- //if info is valid (in PVS)
- if (entinfo.valid) {
- areanum = BotPointAreaNum(entinfo.origin);
- if (areanum) { // && trap_AAS_AreaReachability(areanum)) {
- bs->teamgoal.entitynum = client;
- bs->teamgoal.areanum = areanum;
- VectorCopy(entinfo.origin, bs->teamgoal.origin);
- VectorSet(bs->teamgoal.mins, -8, -8, -8);
- VectorSet(bs->teamgoal.maxs, 8, 8, 8);
- }
- }
- //if the other is not visible
- if (bs->teamgoal.entitynum < 0) {
- BotAI_BotInitialChat(bs, "whereareyou", EasyClientName(client, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
- return;
- }
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //the team mate
- bs->teammate = client;
- //last time the team mate was assumed visible
- bs->teammatevisible_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //get the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
- //set the ltg type
- bs->ltgtype = LTG_TEAMACCOMPANY;
- bs->formation_dist = 3.5 * 32; //3.5 meter
- bs->arrive_time = 0;
- //
- BotSetTeamStatus(bs);
- // remember last ordered task
- BotRememberLastOrderedTask(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotVoiceChat_FollowFlagCarrier
-==================
-*/
-void BotVoiceChat_FollowFlagCarrier(bot_state_t *bs, int client, int mode) {
- int carrier;
-
- carrier = BotTeamFlagCarrier(bs);
- if (carrier >= 0)
- BotVoiceChat_FollowMe(bs, carrier, mode);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotVoiceChat_ReturnFlag
-==================
-*/
-void BotVoiceChat_ReturnFlag(bot_state_t *bs, int client, int mode) {
- //if not in CTF mode
- if (
- gametype != GT_CTF
-#ifdef MISSIONPACK
- && gametype != GT_1FCTF
-#endif
- ) {
- return;
- }
- //
- bs->decisionmaker = client;
- bs->ordered = qtrue;
- bs->order_time = FloatTime();
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //set the ltg type
- bs->ltgtype = LTG_RETURNFLAG;
- //set the team goal time
- bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME;
- bs->rushbaseaway_time = 0;
- BotSetTeamStatus(bs);
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotVoiceChat_StartLeader
-==================
-*/
-void BotVoiceChat_StartLeader(bot_state_t *bs, int client, int mode) {
- ClientName(client, bs->teamleader, sizeof(bs->teamleader));
-}
-
-/*
-==================
-BotVoiceChat_StopLeader
-==================
-*/
-void BotVoiceChat_StopLeader(bot_state_t *bs, int client, int mode) {
- char netname[MAX_MESSAGE_SIZE];
-
- if (!Q_stricmp(bs->teamleader, ClientName(client, netname, sizeof(netname)))) {
- bs->teamleader[0] = '\0';
- notleader[client] = qtrue;
- }
-}
-
-/*
-==================
-BotVoiceChat_WhoIsLeader
-==================
-*/
-void BotVoiceChat_WhoIsLeader(bot_state_t *bs, int client, int mode) {
- char netname[MAX_MESSAGE_SIZE];
-
- if (!TeamPlayIsOn()) return;
-
- ClientName(bs->client, netname, sizeof(netname));
- //if this bot IS the team leader
- if (!Q_stricmp(netname, bs->teamleader)) {
- BotAI_BotInitialChat(bs, "iamteamleader", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_STARTLEADER);
- }
-}
-
-/*
-==================
-BotVoiceChat_WantOnDefense
-==================
-*/
-void BotVoiceChat_WantOnDefense(bot_state_t *bs, int client, int mode) {
- char netname[MAX_NETNAME];
- int preference;
-
- preference = BotGetTeamMateTaskPreference(bs, client);
- preference &= ~TEAMTP_ATTACKER;
- preference |= TEAMTP_DEFENDER;
- BotSetTeamMateTaskPreference(bs, client, preference);
- //
- EasyClientName(client, netname, sizeof(netname));
- BotAI_BotInitialChat(bs, "keepinmind", netname, NULL);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
- BotVoiceChatOnly(bs, client, VOICECHAT_YES);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
-}
-
-/*
-==================
-BotVoiceChat_WantOnOffense
-==================
-*/
-void BotVoiceChat_WantOnOffense(bot_state_t *bs, int client, int mode) {
- char netname[MAX_NETNAME];
- int preference;
-
- preference = BotGetTeamMateTaskPreference(bs, client);
- preference &= ~TEAMTP_DEFENDER;
- preference |= TEAMTP_ATTACKER;
- BotSetTeamMateTaskPreference(bs, client, preference);
- //
- EasyClientName(client, netname, sizeof(netname));
- BotAI_BotInitialChat(bs, "keepinmind", netname, NULL);
- trap_BotEnterChat(bs->cs, client, CHAT_TELL);
- BotVoiceChatOnly(bs, client, VOICECHAT_YES);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
-}
-
-void BotVoiceChat_Dummy(bot_state_t *bs, int client, int mode) {
-}
-
-voiceCommand_t voiceCommands[] = {
- {VOICECHAT_GETFLAG, BotVoiceChat_GetFlag},
- {VOICECHAT_OFFENSE, BotVoiceChat_Offense },
- {VOICECHAT_DEFEND, BotVoiceChat_Defend },
- {VOICECHAT_DEFENDFLAG, BotVoiceChat_DefendFlag },
- {VOICECHAT_PATROL, BotVoiceChat_Patrol },
- {VOICECHAT_CAMP, BotVoiceChat_Camp },
- {VOICECHAT_FOLLOWME, BotVoiceChat_FollowMe },
- {VOICECHAT_FOLLOWFLAGCARRIER, BotVoiceChat_FollowFlagCarrier },
- {VOICECHAT_RETURNFLAG, BotVoiceChat_ReturnFlag },
- {VOICECHAT_STARTLEADER, BotVoiceChat_StartLeader },
- {VOICECHAT_STOPLEADER, BotVoiceChat_StopLeader },
- {VOICECHAT_WHOISLEADER, BotVoiceChat_WhoIsLeader },
- {VOICECHAT_WANTONDEFENSE, BotVoiceChat_WantOnDefense },
- {VOICECHAT_WANTONOFFENSE, BotVoiceChat_WantOnOffense },
- {NULL, BotVoiceChat_Dummy}
-};
-
-int BotVoiceChatCommand(bot_state_t *bs, int mode, char *voiceChat) {
- int i, voiceOnly, clientNum, color;
- char *ptr, buf[MAX_MESSAGE_SIZE], *cmd;
-
- if (!TeamPlayIsOn()) {
- return qfalse;
- }
-
- if ( mode == SAY_ALL ) {
- return qfalse; // don't do anything with voice chats to everyone
- }
-
- Q_strncpyz(buf, voiceChat, sizeof(buf));
- cmd = buf;
- for (ptr = cmd; *cmd && *cmd > ' '; cmd++);
- while (*cmd && *cmd <= ' ') *cmd++ = '\0';
- voiceOnly = atoi(ptr);
- for (ptr = cmd; *cmd && *cmd > ' '; cmd++);
- while (*cmd && *cmd <= ' ') *cmd++ = '\0';
- clientNum = atoi(ptr);
- for (ptr = cmd; *cmd && *cmd > ' '; cmd++);
- while (*cmd && *cmd <= ' ') *cmd++ = '\0';
- color = atoi(ptr);
-
- if (!BotSameTeam(bs, clientNum)) {
- return qfalse;
- }
-
- for (i = 0; voiceCommands[i].cmd; i++) {
- if (!Q_stricmp(cmd, voiceCommands[i].cmd)) {
- voiceCommands[i].func(bs, clientNum, mode);
- return qtrue;
- }
- }
- return qfalse;
-}
diff --git a/engine/code/game/bg_lib.c b/engine/code/game/bg_lib.c
deleted file mode 100644
index e1e9e9e..0000000
--- a/engine/code/game/bg_lib.c
+++ /dev/null
@@ -1,2133 +0,0 @@
-//
-//
-// bg_lib,c -- standard C library replacement routines used by code
-// compiled for the virtual machine
-
-#ifdef Q3_VM
-
-#include "../qcommon/q_shared.h"
-
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "bg_lib.h"
-
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
-#endif
-static const char rcsid[] =
-#endif /* LIBC_SCCS and not lint */
-
-static char* med3(char *, char *, char *, cmp_t *);
-static void swapfunc(char *, char *, int, int);
-
-#ifndef min
-#define min(a, b) ((a) < (b) ? (a) : (b))
-#endif
-
-/*
- * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
- */
-#define swapcode(TYPE, parmi, parmj, n) { \
- long i = (n) / sizeof (TYPE); \
- register TYPE *pi = (TYPE *) (parmi); \
- register TYPE *pj = (TYPE *) (parmj); \
- do { \
- register TYPE t = *pi; \
- *pi++ = *pj; \
- *pj++ = t; \
- } while (--i > 0); \
-}
-
-#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
- es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
-
-static void
-swapfunc(a, b, n, swaptype)
- char *a, *b;
- int n, swaptype;
-{
- if(swaptype <= 1)
- swapcode(long, a, b, n)
- else
- swapcode(char, a, b, n)
-}
-
-#define swap(a, b) \
- if (swaptype == 0) { \
- long t = *(long *)(a); \
- *(long *)(a) = *(long *)(b); \
- *(long *)(b) = t; \
- } else \
- swapfunc(a, b, es, swaptype)
-
-#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
-
-static char *
-med3(a, b, c, cmp)
- char *a, *b, *c;
- cmp_t *cmp;
-{
- return cmp(a, b) < 0 ?
- (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
- :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
-}
-
-void
-qsort(a, n, es, cmp)
- void *a;
- size_t n, es;
- cmp_t *cmp;
-{
- char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
- int d, r, swaptype, swap_cnt;
-
-loop: SWAPINIT(a, es);
- swap_cnt = 0;
- if (n < 7) {
- for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
- for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0;
- pl -= es)
- swap(pl, pl - es);
- return;
- }
- pm = (char *)a + (n / 2) * es;
- if (n > 7) {
- pl = a;
- pn = (char *)a + (n - 1) * es;
- if (n > 40) {
- d = (n / 8) * es;
- pl = med3(pl, pl + d, pl + 2 * d, cmp);
- pm = med3(pm - d, pm, pm + d, cmp);
- pn = med3(pn - 2 * d, pn - d, pn, cmp);
- }
- pm = med3(pl, pm, pn, cmp);
- }
- swap(a, pm);
- pa = pb = (char *)a + es;
-
- pc = pd = (char *)a + (n - 1) * es;
- for (;;) {
- while (pb <= pc && (r = cmp(pb, a)) <= 0) {
- if (r == 0) {
- swap_cnt = 1;
- swap(pa, pb);
- pa += es;
- }
- pb += es;
- }
- while (pb <= pc && (r = cmp(pc, a)) >= 0) {
- if (r == 0) {
- swap_cnt = 1;
- swap(pc, pd);
- pd -= es;
- }
- pc -= es;
- }
- if (pb > pc)
- break;
- swap(pb, pc);
- swap_cnt = 1;
- pb += es;
- pc -= es;
- }
- if (swap_cnt == 0) { /* Switch to insertion sort */
- for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
- for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0;
- pl -= es)
- swap(pl, pl - es);
- return;
- }
-
- pn = (char *)a + n * es;
- r = min(pa - (char *)a, pb - pa);
- vecswap(a, pb - r, r);
- r = min(pd - pc, pn - pd - es);
- vecswap(pb, pn - r, r);
- if ((r = pb - pa) > es)
- qsort(a, r / es, es, cmp);
- if ((r = pd - pc) > es) {
- /* Iterate rather than recurse to save stack space */
- a = pn - r;
- n = r / es;
- goto loop;
- }
-/* qsort(pn - r, r / es, es, cmp);*/
-}
-
-//==================================================================================
-
-size_t strlen( const char *string ) {
- const char *s;
-
- s = string;
- while ( *s ) {
- s++;
- }
- return s - string;
-}
-
-
-char *strcat( char *strDestination, const char *strSource ) {
- char *s;
-
- s = strDestination;
- while ( *s ) {
- s++;
- }
- while ( *strSource ) {
- *s++ = *strSource++;
- }
- *s = 0;
- return strDestination;
-}
-
-char *strcpy( char *strDestination, const char *strSource ) {
- char *s;
-
- s = strDestination;
- while ( *strSource ) {
- *s++ = *strSource++;
- }
- *s = 0;
- return strDestination;
-}
-
-
-int strcmp( const char *string1, const char *string2 ) {
- while ( *string1 == *string2 && *string1 && *string2 ) {
- string1++;
- string2++;
- }
- return *string1 - *string2;
-}
-
-
-char *strchr( const char *string, int c ) {
- while ( *string ) {
- if ( *string == c ) {
- return ( char * )string;
- }
- string++;
- }
- return (char *)0;
-}
-
-char *strstr( const char *string, const char *strCharSet ) {
- while ( *string ) {
- int i;
-
- for ( i = 0 ; strCharSet[i] ; i++ ) {
- if ( string[i] != strCharSet[i] ) {
- break;
- }
- }
- if ( !strCharSet[i] ) {
- return (char *)string;
- }
- string++;
- }
- return (char *)0;
-}
-
-int tolower( int c ) {
- if ( c >= 'A' && c <= 'Z' ) {
- c += 'a' - 'A';
- }
- return c;
-}
-
-
-int toupper( int c ) {
- if ( c >= 'a' && c <= 'z' ) {
- c += 'A' - 'a';
- }
- return c;
-}
-
-void *memmove( void *dest, const void *src, size_t count ) {
- int i;
-
- if ( dest > src ) {
- for ( i = count-1 ; i >= 0 ; i-- ) {
- ((char *)dest)[i] = ((char *)src)[i];
- }
- } else {
- for ( i = 0 ; i < count ; i++ ) {
- ((char *)dest)[i] = ((char *)src)[i];
- }
- }
- return dest;
-}
-
-
-#if 0
-
-double floor( double x ) {
- return (int)(x + 0x40000000) - 0x40000000;
-}
-
-void *memset( void *dest, int c, size_t count ) {
- while ( count-- ) {
- ((char *)dest)[count] = c;
- }
- return dest;
-}
-
-void *memcpy( void *dest, const void *src, size_t count ) {
- while ( count-- ) {
- ((char *)dest)[count] = ((char *)src)[count];
- }
- return dest;
-}
-
-char *strncpy( char *strDest, const char *strSource, size_t count ) {
- char *s;
-
- s = strDest;
- while ( *strSource && count ) {
- *s++ = *strSource++;
- count--;
- }
- while ( count-- ) {
- *s++ = 0;
- }
- return strDest;
-}
-
-double sqrt( double x ) {
- float y;
- float delta;
- float maxError;
-
- if ( x <= 0 ) {
- return 0;
- }
-
- // initial guess
- y = x / 2;
-
- // refine
- maxError = x * 0.001;
-
- do {
- delta = ( y * y ) - x;
- y -= delta / ( 2 * y );
- } while ( delta > maxError || delta < -maxError );
-
- return y;
-}
-
-
-float sintable[1024] = {
-0.000000,0.001534,0.003068,0.004602,0.006136,0.007670,0.009204,0.010738,
-0.012272,0.013805,0.015339,0.016873,0.018407,0.019940,0.021474,0.023008,
-0.024541,0.026075,0.027608,0.029142,0.030675,0.032208,0.033741,0.035274,
-0.036807,0.038340,0.039873,0.041406,0.042938,0.044471,0.046003,0.047535,
-0.049068,0.050600,0.052132,0.053664,0.055195,0.056727,0.058258,0.059790,
-0.061321,0.062852,0.064383,0.065913,0.067444,0.068974,0.070505,0.072035,
-0.073565,0.075094,0.076624,0.078153,0.079682,0.081211,0.082740,0.084269,
-0.085797,0.087326,0.088854,0.090381,0.091909,0.093436,0.094963,0.096490,
-0.098017,0.099544,0.101070,0.102596,0.104122,0.105647,0.107172,0.108697,
-0.110222,0.111747,0.113271,0.114795,0.116319,0.117842,0.119365,0.120888,
-0.122411,0.123933,0.125455,0.126977,0.128498,0.130019,0.131540,0.133061,
-0.134581,0.136101,0.137620,0.139139,0.140658,0.142177,0.143695,0.145213,
-0.146730,0.148248,0.149765,0.151281,0.152797,0.154313,0.155828,0.157343,
-0.158858,0.160372,0.161886,0.163400,0.164913,0.166426,0.167938,0.169450,
-0.170962,0.172473,0.173984,0.175494,0.177004,0.178514,0.180023,0.181532,
-0.183040,0.184548,0.186055,0.187562,0.189069,0.190575,0.192080,0.193586,
-0.195090,0.196595,0.198098,0.199602,0.201105,0.202607,0.204109,0.205610,
-0.207111,0.208612,0.210112,0.211611,0.213110,0.214609,0.216107,0.217604,
-0.219101,0.220598,0.222094,0.223589,0.225084,0.226578,0.228072,0.229565,
-0.231058,0.232550,0.234042,0.235533,0.237024,0.238514,0.240003,0.241492,
-0.242980,0.244468,0.245955,0.247442,0.248928,0.250413,0.251898,0.253382,
-0.254866,0.256349,0.257831,0.259313,0.260794,0.262275,0.263755,0.265234,
-0.266713,0.268191,0.269668,0.271145,0.272621,0.274097,0.275572,0.277046,
-0.278520,0.279993,0.281465,0.282937,0.284408,0.285878,0.287347,0.288816,
-0.290285,0.291752,0.293219,0.294685,0.296151,0.297616,0.299080,0.300543,
-0.302006,0.303468,0.304929,0.306390,0.307850,0.309309,0.310767,0.312225,
-0.313682,0.315138,0.316593,0.318048,0.319502,0.320955,0.322408,0.323859,
-0.325310,0.326760,0.328210,0.329658,0.331106,0.332553,0.334000,0.335445,
-0.336890,0.338334,0.339777,0.341219,0.342661,0.344101,0.345541,0.346980,
-0.348419,0.349856,0.351293,0.352729,0.354164,0.355598,0.357031,0.358463,
-0.359895,0.361326,0.362756,0.364185,0.365613,0.367040,0.368467,0.369892,
-0.371317,0.372741,0.374164,0.375586,0.377007,0.378428,0.379847,0.381266,
-0.382683,0.384100,0.385516,0.386931,0.388345,0.389758,0.391170,0.392582,
-0.393992,0.395401,0.396810,0.398218,0.399624,0.401030,0.402435,0.403838,
-0.405241,0.406643,0.408044,0.409444,0.410843,0.412241,0.413638,0.415034,
-0.416430,0.417824,0.419217,0.420609,0.422000,0.423390,0.424780,0.426168,
-0.427555,0.428941,0.430326,0.431711,0.433094,0.434476,0.435857,0.437237,
-0.438616,0.439994,0.441371,0.442747,0.444122,0.445496,0.446869,0.448241,
-0.449611,0.450981,0.452350,0.453717,0.455084,0.456449,0.457813,0.459177,
-0.460539,0.461900,0.463260,0.464619,0.465976,0.467333,0.468689,0.470043,
-0.471397,0.472749,0.474100,0.475450,0.476799,0.478147,0.479494,0.480839,
-0.482184,0.483527,0.484869,0.486210,0.487550,0.488889,0.490226,0.491563,
-0.492898,0.494232,0.495565,0.496897,0.498228,0.499557,0.500885,0.502212,
-0.503538,0.504863,0.506187,0.507509,0.508830,0.510150,0.511469,0.512786,
-0.514103,0.515418,0.516732,0.518045,0.519356,0.520666,0.521975,0.523283,
-0.524590,0.525895,0.527199,0.528502,0.529804,0.531104,0.532403,0.533701,
-0.534998,0.536293,0.537587,0.538880,0.540171,0.541462,0.542751,0.544039,
-0.545325,0.546610,0.547894,0.549177,0.550458,0.551738,0.553017,0.554294,
-0.555570,0.556845,0.558119,0.559391,0.560662,0.561931,0.563199,0.564466,
-0.565732,0.566996,0.568259,0.569521,0.570781,0.572040,0.573297,0.574553,
-0.575808,0.577062,0.578314,0.579565,0.580814,0.582062,0.583309,0.584554,
-0.585798,0.587040,0.588282,0.589521,0.590760,0.591997,0.593232,0.594466,
-0.595699,0.596931,0.598161,0.599389,0.600616,0.601842,0.603067,0.604290,
-0.605511,0.606731,0.607950,0.609167,0.610383,0.611597,0.612810,0.614022,
-0.615232,0.616440,0.617647,0.618853,0.620057,0.621260,0.622461,0.623661,
-0.624859,0.626056,0.627252,0.628446,0.629638,0.630829,0.632019,0.633207,
-0.634393,0.635578,0.636762,0.637944,0.639124,0.640303,0.641481,0.642657,
-0.643832,0.645005,0.646176,0.647346,0.648514,0.649681,0.650847,0.652011,
-0.653173,0.654334,0.655493,0.656651,0.657807,0.658961,0.660114,0.661266,
-0.662416,0.663564,0.664711,0.665856,0.667000,0.668142,0.669283,0.670422,
-0.671559,0.672695,0.673829,0.674962,0.676093,0.677222,0.678350,0.679476,
-0.680601,0.681724,0.682846,0.683965,0.685084,0.686200,0.687315,0.688429,
-0.689541,0.690651,0.691759,0.692866,0.693971,0.695075,0.696177,0.697278,
-0.698376,0.699473,0.700569,0.701663,0.702755,0.703845,0.704934,0.706021,
-0.707107,0.708191,0.709273,0.710353,0.711432,0.712509,0.713585,0.714659,
-0.715731,0.716801,0.717870,0.718937,0.720003,0.721066,0.722128,0.723188,
-0.724247,0.725304,0.726359,0.727413,0.728464,0.729514,0.730563,0.731609,
-0.732654,0.733697,0.734739,0.735779,0.736817,0.737853,0.738887,0.739920,
-0.740951,0.741980,0.743008,0.744034,0.745058,0.746080,0.747101,0.748119,
-0.749136,0.750152,0.751165,0.752177,0.753187,0.754195,0.755201,0.756206,
-0.757209,0.758210,0.759209,0.760207,0.761202,0.762196,0.763188,0.764179,
-0.765167,0.766154,0.767139,0.768122,0.769103,0.770083,0.771061,0.772036,
-0.773010,0.773983,0.774953,0.775922,0.776888,0.777853,0.778817,0.779778,
-0.780737,0.781695,0.782651,0.783605,0.784557,0.785507,0.786455,0.787402,
-0.788346,0.789289,0.790230,0.791169,0.792107,0.793042,0.793975,0.794907,
-0.795837,0.796765,0.797691,0.798615,0.799537,0.800458,0.801376,0.802293,
-0.803208,0.804120,0.805031,0.805940,0.806848,0.807753,0.808656,0.809558,
-0.810457,0.811355,0.812251,0.813144,0.814036,0.814926,0.815814,0.816701,
-0.817585,0.818467,0.819348,0.820226,0.821103,0.821977,0.822850,0.823721,
-0.824589,0.825456,0.826321,0.827184,0.828045,0.828904,0.829761,0.830616,
-0.831470,0.832321,0.833170,0.834018,0.834863,0.835706,0.836548,0.837387,
-0.838225,0.839060,0.839894,0.840725,0.841555,0.842383,0.843208,0.844032,
-0.844854,0.845673,0.846491,0.847307,0.848120,0.848932,0.849742,0.850549,
-0.851355,0.852159,0.852961,0.853760,0.854558,0.855354,0.856147,0.856939,
-0.857729,0.858516,0.859302,0.860085,0.860867,0.861646,0.862424,0.863199,
-0.863973,0.864744,0.865514,0.866281,0.867046,0.867809,0.868571,0.869330,
-0.870087,0.870842,0.871595,0.872346,0.873095,0.873842,0.874587,0.875329,
-0.876070,0.876809,0.877545,0.878280,0.879012,0.879743,0.880471,0.881197,
-0.881921,0.882643,0.883363,0.884081,0.884797,0.885511,0.886223,0.886932,
-0.887640,0.888345,0.889048,0.889750,0.890449,0.891146,0.891841,0.892534,
-0.893224,0.893913,0.894599,0.895284,0.895966,0.896646,0.897325,0.898001,
-0.898674,0.899346,0.900016,0.900683,0.901349,0.902012,0.902673,0.903332,
-0.903989,0.904644,0.905297,0.905947,0.906596,0.907242,0.907886,0.908528,
-0.909168,0.909806,0.910441,0.911075,0.911706,0.912335,0.912962,0.913587,
-0.914210,0.914830,0.915449,0.916065,0.916679,0.917291,0.917901,0.918508,
-0.919114,0.919717,0.920318,0.920917,0.921514,0.922109,0.922701,0.923291,
-0.923880,0.924465,0.925049,0.925631,0.926210,0.926787,0.927363,0.927935,
-0.928506,0.929075,0.929641,0.930205,0.930767,0.931327,0.931884,0.932440,
-0.932993,0.933544,0.934093,0.934639,0.935184,0.935726,0.936266,0.936803,
-0.937339,0.937872,0.938404,0.938932,0.939459,0.939984,0.940506,0.941026,
-0.941544,0.942060,0.942573,0.943084,0.943593,0.944100,0.944605,0.945107,
-0.945607,0.946105,0.946601,0.947094,0.947586,0.948075,0.948561,0.949046,
-0.949528,0.950008,0.950486,0.950962,0.951435,0.951906,0.952375,0.952842,
-0.953306,0.953768,0.954228,0.954686,0.955141,0.955594,0.956045,0.956494,
-0.956940,0.957385,0.957826,0.958266,0.958703,0.959139,0.959572,0.960002,
-0.960431,0.960857,0.961280,0.961702,0.962121,0.962538,0.962953,0.963366,
-0.963776,0.964184,0.964590,0.964993,0.965394,0.965793,0.966190,0.966584,
-0.966976,0.967366,0.967754,0.968139,0.968522,0.968903,0.969281,0.969657,
-0.970031,0.970403,0.970772,0.971139,0.971504,0.971866,0.972226,0.972584,
-0.972940,0.973293,0.973644,0.973993,0.974339,0.974684,0.975025,0.975365,
-0.975702,0.976037,0.976370,0.976700,0.977028,0.977354,0.977677,0.977999,
-0.978317,0.978634,0.978948,0.979260,0.979570,0.979877,0.980182,0.980485,
-0.980785,0.981083,0.981379,0.981673,0.981964,0.982253,0.982539,0.982824,
-0.983105,0.983385,0.983662,0.983937,0.984210,0.984480,0.984749,0.985014,
-0.985278,0.985539,0.985798,0.986054,0.986308,0.986560,0.986809,0.987057,
-0.987301,0.987544,0.987784,0.988022,0.988258,0.988491,0.988722,0.988950,
-0.989177,0.989400,0.989622,0.989841,0.990058,0.990273,0.990485,0.990695,
-0.990903,0.991108,0.991311,0.991511,0.991710,0.991906,0.992099,0.992291,
-0.992480,0.992666,0.992850,0.993032,0.993212,0.993389,0.993564,0.993737,
-0.993907,0.994075,0.994240,0.994404,0.994565,0.994723,0.994879,0.995033,
-0.995185,0.995334,0.995481,0.995625,0.995767,0.995907,0.996045,0.996180,
-0.996313,0.996443,0.996571,0.996697,0.996820,0.996941,0.997060,0.997176,
-0.997290,0.997402,0.997511,0.997618,0.997723,0.997825,0.997925,0.998023,
-0.998118,0.998211,0.998302,0.998390,0.998476,0.998559,0.998640,0.998719,
-0.998795,0.998870,0.998941,0.999011,0.999078,0.999142,0.999205,0.999265,
-0.999322,0.999378,0.999431,0.999481,0.999529,0.999575,0.999619,0.999660,
-0.999699,0.999735,0.999769,0.999801,0.999831,0.999858,0.999882,0.999905,
-0.999925,0.999942,0.999958,0.999971,0.999981,0.999989,0.999995,0.999999
-};
-
-double sin( double x ) {
- int index;
- int quad;
-
- index = 1024 * x / (M_PI * 0.5);
- quad = ( index >> 10 ) & 3;
- index &= 1023;
- switch ( quad ) {
- case 0:
- return sintable[index];
- case 1:
- return sintable[1023-index];
- case 2:
- return -sintable[index];
- case 3:
- return -sintable[1023-index];
- }
- return 0;
-}
-
-
-double cos( double x ) {
- int index;
- int quad;
-
- index = 1024 * x / (M_PI * 0.5);
- quad = ( index >> 10 ) & 3;
- index &= 1023;
- switch ( quad ) {
- case 3:
- return sintable[index];
- case 0:
- return sintable[1023-index];
- case 1:
- return -sintable[index];
- case 2:
- return -sintable[1023-index];
- }
- return 0;
-}
-
-
-/*
-void create_acostable( void ) {
- int i;
- FILE *fp;
- float a;
-
- fp = fopen("c:\\acostable.txt", "w");
- fprintf(fp, "float acostable[] = {");
- for (i = 0; i < 1024; i++) {
- if (!(i & 7))
- fprintf(fp, "\n");
- a = acos( (float) -1 + i / 512 );
- fprintf(fp, "%1.8f,", a);
- }
- fprintf(fp, "\n}\n");
- fclose(fp);
-}
-*/
-
-float acostable[] = {
-3.14159265,3.07908248,3.05317551,3.03328655,3.01651113,3.00172442,2.98834964,2.97604422,
-2.96458497,2.95381690,2.94362719,2.93393068,2.92466119,2.91576615,2.90720289,2.89893629,
-2.89093699,2.88318015,2.87564455,2.86831188,2.86116621,2.85419358,2.84738169,2.84071962,
-2.83419760,2.82780691,2.82153967,2.81538876,2.80934770,2.80341062,2.79757211,2.79182724,
-2.78617145,2.78060056,2.77511069,2.76969824,2.76435988,2.75909250,2.75389319,2.74875926,
-2.74368816,2.73867752,2.73372510,2.72882880,2.72398665,2.71919677,2.71445741,2.70976688,
-2.70512362,2.70052613,2.69597298,2.69146283,2.68699438,2.68256642,2.67817778,2.67382735,
-2.66951407,2.66523692,2.66099493,2.65678719,2.65261279,2.64847088,2.64436066,2.64028133,
-2.63623214,2.63221238,2.62822133,2.62425835,2.62032277,2.61641398,2.61253138,2.60867440,
-2.60484248,2.60103507,2.59725167,2.59349176,2.58975488,2.58604053,2.58234828,2.57867769,
-2.57502832,2.57139977,2.56779164,2.56420354,2.56063509,2.55708594,2.55355572,2.55004409,
-2.54655073,2.54307530,2.53961750,2.53617701,2.53275354,2.52934680,2.52595650,2.52258238,
-2.51922417,2.51588159,2.51255441,2.50924238,2.50594525,2.50266278,2.49939476,2.49614096,
-2.49290115,2.48967513,2.48646269,2.48326362,2.48007773,2.47690482,2.47374472,2.47059722,
-2.46746215,2.46433933,2.46122860,2.45812977,2.45504269,2.45196720,2.44890314,2.44585034,
-2.44280867,2.43977797,2.43675809,2.43374890,2.43075025,2.42776201,2.42478404,2.42181622,
-2.41885841,2.41591048,2.41297232,2.41004380,2.40712480,2.40421521,2.40131491,2.39842379,
-2.39554173,2.39266863,2.38980439,2.38694889,2.38410204,2.38126374,2.37843388,2.37561237,
-2.37279910,2.36999400,2.36719697,2.36440790,2.36162673,2.35885335,2.35608768,2.35332964,
-2.35057914,2.34783610,2.34510044,2.34237208,2.33965094,2.33693695,2.33423003,2.33153010,
-2.32883709,2.32615093,2.32347155,2.32079888,2.31813284,2.31547337,2.31282041,2.31017388,
-2.30753373,2.30489988,2.30227228,2.29965086,2.29703556,2.29442632,2.29182309,2.28922580,
-2.28663439,2.28404881,2.28146900,2.27889490,2.27632647,2.27376364,2.27120637,2.26865460,
-2.26610827,2.26356735,2.26103177,2.25850149,2.25597646,2.25345663,2.25094195,2.24843238,
-2.24592786,2.24342836,2.24093382,2.23844420,2.23595946,2.23347956,2.23100444,2.22853408,
-2.22606842,2.22360742,2.22115104,2.21869925,2.21625199,2.21380924,2.21137096,2.20893709,
-2.20650761,2.20408248,2.20166166,2.19924511,2.19683280,2.19442469,2.19202074,2.18962092,
-2.18722520,2.18483354,2.18244590,2.18006225,2.17768257,2.17530680,2.17293493,2.17056692,
-2.16820274,2.16584236,2.16348574,2.16113285,2.15878367,2.15643816,2.15409630,2.15175805,
-2.14942338,2.14709226,2.14476468,2.14244059,2.14011997,2.13780279,2.13548903,2.13317865,
-2.13087163,2.12856795,2.12626757,2.12397047,2.12167662,2.11938600,2.11709859,2.11481435,
-2.11253326,2.11025530,2.10798044,2.10570867,2.10343994,2.10117424,2.09891156,2.09665185,
-2.09439510,2.09214129,2.08989040,2.08764239,2.08539725,2.08315496,2.08091550,2.07867884,
-2.07644495,2.07421383,2.07198545,2.06975978,2.06753681,2.06531651,2.06309887,2.06088387,
-2.05867147,2.05646168,2.05425445,2.05204979,2.04984765,2.04764804,2.04545092,2.04325628,
-2.04106409,2.03887435,2.03668703,2.03450211,2.03231957,2.03013941,2.02796159,2.02578610,
-2.02361292,2.02144204,2.01927344,2.01710710,2.01494300,2.01278113,2.01062146,2.00846399,
-2.00630870,2.00415556,2.00200457,1.99985570,1.99770895,1.99556429,1.99342171,1.99128119,
-1.98914271,1.98700627,1.98487185,1.98273942,1.98060898,1.97848051,1.97635399,1.97422942,
-1.97210676,1.96998602,1.96786718,1.96575021,1.96363511,1.96152187,1.95941046,1.95730088,
-1.95519310,1.95308712,1.95098292,1.94888050,1.94677982,1.94468089,1.94258368,1.94048818,
-1.93839439,1.93630228,1.93421185,1.93212308,1.93003595,1.92795046,1.92586659,1.92378433,
-1.92170367,1.91962459,1.91754708,1.91547113,1.91339673,1.91132385,1.90925250,1.90718266,
-1.90511432,1.90304746,1.90098208,1.89891815,1.89685568,1.89479464,1.89273503,1.89067683,
-1.88862003,1.88656463,1.88451060,1.88245794,1.88040664,1.87835668,1.87630806,1.87426076,
-1.87221477,1.87017008,1.86812668,1.86608457,1.86404371,1.86200412,1.85996577,1.85792866,
-1.85589277,1.85385809,1.85182462,1.84979234,1.84776125,1.84573132,1.84370256,1.84167495,
-1.83964848,1.83762314,1.83559892,1.83357582,1.83155381,1.82953289,1.82751305,1.82549429,
-1.82347658,1.82145993,1.81944431,1.81742973,1.81541617,1.81340362,1.81139207,1.80938151,
-1.80737194,1.80536334,1.80335570,1.80134902,1.79934328,1.79733848,1.79533460,1.79333164,
-1.79132959,1.78932843,1.78732817,1.78532878,1.78333027,1.78133261,1.77933581,1.77733985,
-1.77534473,1.77335043,1.77135695,1.76936428,1.76737240,1.76538132,1.76339101,1.76140148,
-1.75941271,1.75742470,1.75543743,1.75345090,1.75146510,1.74948002,1.74749565,1.74551198,
-1.74352900,1.74154672,1.73956511,1.73758417,1.73560389,1.73362426,1.73164527,1.72966692,
-1.72768920,1.72571209,1.72373560,1.72175971,1.71978441,1.71780969,1.71583556,1.71386199,
-1.71188899,1.70991653,1.70794462,1.70597325,1.70400241,1.70203209,1.70006228,1.69809297,
-1.69612416,1.69415584,1.69218799,1.69022062,1.68825372,1.68628727,1.68432127,1.68235571,
-1.68039058,1.67842588,1.67646160,1.67449772,1.67253424,1.67057116,1.66860847,1.66664615,
-1.66468420,1.66272262,1.66076139,1.65880050,1.65683996,1.65487975,1.65291986,1.65096028,
-1.64900102,1.64704205,1.64508338,1.64312500,1.64116689,1.63920905,1.63725148,1.63529416,
-1.63333709,1.63138026,1.62942366,1.62746728,1.62551112,1.62355517,1.62159943,1.61964388,
-1.61768851,1.61573332,1.61377831,1.61182346,1.60986877,1.60791422,1.60595982,1.60400556,
-1.60205142,1.60009739,1.59814349,1.59618968,1.59423597,1.59228235,1.59032882,1.58837536,
-1.58642196,1.58446863,1.58251535,1.58056211,1.57860891,1.57665574,1.57470259,1.57274945,
-1.57079633,1.56884320,1.56689007,1.56493692,1.56298375,1.56103055,1.55907731,1.55712403,
-1.55517069,1.55321730,1.55126383,1.54931030,1.54735668,1.54540297,1.54344917,1.54149526,
-1.53954124,1.53758710,1.53563283,1.53367843,1.53172389,1.52976919,1.52781434,1.52585933,
-1.52390414,1.52194878,1.51999323,1.51803748,1.51608153,1.51412537,1.51216900,1.51021240,
-1.50825556,1.50629849,1.50434117,1.50238360,1.50042576,1.49846765,1.49650927,1.49455060,
-1.49259163,1.49063237,1.48867280,1.48671291,1.48475270,1.48279215,1.48083127,1.47887004,
-1.47690845,1.47494650,1.47298419,1.47102149,1.46905841,1.46709493,1.46513106,1.46316677,
-1.46120207,1.45923694,1.45727138,1.45530538,1.45333893,1.45137203,1.44940466,1.44743682,
-1.44546850,1.44349969,1.44153038,1.43956057,1.43759024,1.43561940,1.43364803,1.43167612,
-1.42970367,1.42773066,1.42575709,1.42378296,1.42180825,1.41983295,1.41785705,1.41588056,
-1.41390346,1.41192573,1.40994738,1.40796840,1.40598877,1.40400849,1.40202755,1.40004594,
-1.39806365,1.39608068,1.39409701,1.39211264,1.39012756,1.38814175,1.38615522,1.38416795,
-1.38217994,1.38019117,1.37820164,1.37621134,1.37422025,1.37222837,1.37023570,1.36824222,
-1.36624792,1.36425280,1.36225684,1.36026004,1.35826239,1.35626387,1.35426449,1.35226422,
-1.35026307,1.34826101,1.34625805,1.34425418,1.34224937,1.34024364,1.33823695,1.33622932,
-1.33422072,1.33221114,1.33020059,1.32818904,1.32617649,1.32416292,1.32214834,1.32013273,
-1.31811607,1.31609837,1.31407960,1.31205976,1.31003885,1.30801684,1.30599373,1.30396951,
-1.30194417,1.29991770,1.29789009,1.29586133,1.29383141,1.29180031,1.28976803,1.28773456,
-1.28569989,1.28366400,1.28162688,1.27958854,1.27754894,1.27550809,1.27346597,1.27142257,
-1.26937788,1.26733189,1.26528459,1.26323597,1.26118602,1.25913471,1.25708205,1.25502803,
-1.25297262,1.25091583,1.24885763,1.24679802,1.24473698,1.24267450,1.24061058,1.23854519,
-1.23647833,1.23440999,1.23234015,1.23026880,1.22819593,1.22612152,1.22404557,1.22196806,
-1.21988898,1.21780832,1.21572606,1.21364219,1.21155670,1.20946958,1.20738080,1.20529037,
-1.20319826,1.20110447,1.19900898,1.19691177,1.19481283,1.19271216,1.19060973,1.18850553,
-1.18639955,1.18429178,1.18218219,1.18007079,1.17795754,1.17584244,1.17372548,1.17160663,
-1.16948589,1.16736324,1.16523866,1.16311215,1.16098368,1.15885323,1.15672081,1.15458638,
-1.15244994,1.15031147,1.14817095,1.14602836,1.14388370,1.14173695,1.13958808,1.13743709,
-1.13528396,1.13312866,1.13097119,1.12881153,1.12664966,1.12448556,1.12231921,1.12015061,
-1.11797973,1.11580656,1.11363107,1.11145325,1.10927308,1.10709055,1.10490563,1.10271831,
-1.10052856,1.09833638,1.09614174,1.09394462,1.09174500,1.08954287,1.08733820,1.08513098,
-1.08292118,1.08070879,1.07849378,1.07627614,1.07405585,1.07183287,1.06960721,1.06737882,
-1.06514770,1.06291382,1.06067715,1.05843769,1.05619540,1.05395026,1.05170226,1.04945136,
-1.04719755,1.04494080,1.04268110,1.04041841,1.03815271,1.03588399,1.03361221,1.03133735,
-1.02905939,1.02677830,1.02449407,1.02220665,1.01991603,1.01762219,1.01532509,1.01302471,
-1.01072102,1.00841400,1.00610363,1.00378986,1.00147268,0.99915206,0.99682798,0.99450039,
-0.99216928,0.98983461,0.98749636,0.98515449,0.98280898,0.98045980,0.97810691,0.97575030,
-0.97338991,0.97102573,0.96865772,0.96628585,0.96391009,0.96153040,0.95914675,0.95675912,
-0.95436745,0.95197173,0.94957191,0.94716796,0.94475985,0.94234754,0.93993099,0.93751017,
-0.93508504,0.93265556,0.93022170,0.92778341,0.92534066,0.92289341,0.92044161,0.91798524,
-0.91552424,0.91305858,0.91058821,0.90811309,0.90563319,0.90314845,0.90065884,0.89816430,
-0.89566479,0.89316028,0.89065070,0.88813602,0.88561619,0.88309116,0.88056088,0.87802531,
-0.87548438,0.87293806,0.87038629,0.86782901,0.86526619,0.86269775,0.86012366,0.85754385,
-0.85495827,0.85236686,0.84976956,0.84716633,0.84455709,0.84194179,0.83932037,0.83669277,
-0.83405893,0.83141877,0.82877225,0.82611928,0.82345981,0.82079378,0.81812110,0.81544172,
-0.81275556,0.81006255,0.80736262,0.80465570,0.80194171,0.79922057,0.79649221,0.79375655,
-0.79101352,0.78826302,0.78550497,0.78273931,0.77996593,0.77718475,0.77439569,0.77159865,
-0.76879355,0.76598029,0.76315878,0.76032891,0.75749061,0.75464376,0.75178826,0.74892402,
-0.74605092,0.74316887,0.74027775,0.73737744,0.73446785,0.73154885,0.72862033,0.72568217,
-0.72273425,0.71977644,0.71680861,0.71383064,0.71084240,0.70784376,0.70483456,0.70181469,
-0.69878398,0.69574231,0.69268952,0.68962545,0.68654996,0.68346288,0.68036406,0.67725332,
-0.67413051,0.67099544,0.66784794,0.66468783,0.66151492,0.65832903,0.65512997,0.65191753,
-0.64869151,0.64545170,0.64219789,0.63892987,0.63564741,0.63235028,0.62903824,0.62571106,
-0.62236849,0.61901027,0.61563615,0.61224585,0.60883911,0.60541564,0.60197515,0.59851735,
-0.59504192,0.59154856,0.58803694,0.58450672,0.58095756,0.57738911,0.57380101,0.57019288,
-0.56656433,0.56291496,0.55924437,0.55555212,0.55183778,0.54810089,0.54434099,0.54055758,
-0.53675018,0.53291825,0.52906127,0.52517867,0.52126988,0.51733431,0.51337132,0.50938028,
-0.50536051,0.50131132,0.49723200,0.49312177,0.48897987,0.48480547,0.48059772,0.47635573,
-0.47207859,0.46776530,0.46341487,0.45902623,0.45459827,0.45012983,0.44561967,0.44106652,
-0.43646903,0.43182577,0.42713525,0.42239588,0.41760600,0.41276385,0.40786755,0.40291513,
-0.39790449,0.39283339,0.38769946,0.38250016,0.37723277,0.37189441,0.36648196,0.36099209,
-0.35542120,0.34976542,0.34402054,0.33818204,0.33224495,0.32620390,0.32005298,0.31378574,
-0.30739505,0.30087304,0.29421096,0.28739907,0.28042645,0.27328078,0.26594810,0.25841250,
-0.25065566,0.24265636,0.23438976,0.22582651,0.21693146,0.20766198,0.19796546,0.18777575,
-0.17700769,0.16554844,0.15324301,0.13986823,0.12508152,0.10830610,0.08841715,0.06251018,
-}
-
-double acos( double x ) {
- int index;
-
- if (x < -1)
- x = -1;
- if (x > 1)
- x = 1;
- index = (float) (1.0 + x) * 511.9;
- return acostable[index];
-}
-
-double atan2( double y, double x ) {
- float base;
- float temp;
- float dir;
- float test;
- int i;
-
- if ( x < 0 ) {
- if ( y >= 0 ) {
- // quad 1
- base = M_PI / 2;
- temp = x;
- x = y;
- y = -temp;
- } else {
- // quad 2
- base = M_PI;
- x = -x;
- y = -y;
- }
- } else {
- if ( y < 0 ) {
- // quad 3
- base = 3 * M_PI / 2;
- temp = x;
- x = -y;
- y = temp;
- }
- }
-
- if ( y > x ) {
- base += M_PI/2;
- temp = x;
- x = y;
- y = temp;
- dir = -1;
- } else {
- dir = 1;
- }
-
- // calcualte angle in octant 0
- if ( x == 0 ) {
- return base;
- }
- y /= x;
-
- for ( i = 0 ; i < 512 ; i++ ) {
- test = sintable[i] / sintable[1023-i];
- if ( test > y ) {
- break;
- }
- }
-
- return base + dir * i * ( M_PI/2048);
-}
-
-
-#endif
-
-double tan( double x ) {
- return sin(x) / cos(x);
-}
-
-
-static int randSeed = 0;
-
-void srand( unsigned seed ) {
- randSeed = seed;
-}
-
-int rand( void ) {
- randSeed = (69069 * randSeed + 1);
- return randSeed & 0x7fff;
-}
-
-double atof( const char *string ) {
- float sign;
- float value;
- int c;
-
-
- // skip whitespace
- while ( *string <= ' ' ) {
- if ( !*string ) {
- return 0;
- }
- string++;
- }
-
- // check sign
- switch ( *string ) {
- case '+':
- string++;
- sign = 1;
- break;
- case '-':
- string++;
- sign = -1;
- break;
- default:
- sign = 1;
- break;
- }
-
- // read digits
- value = 0;
- c = string[0];
- if ( c != '.' ) {
- do {
- c = *string++;
- if ( c < '0' || c > '9' ) {
- break;
- }
- c -= '0';
- value = value * 10 + c;
- } while ( 1 );
- } else {
- string++;
- }
-
- // check for decimal point
- if ( c == '.' ) {
- double fraction;
-
- fraction = 0.1;
- do {
- c = *string++;
- if ( c < '0' || c > '9' ) {
- break;
- }
- c -= '0';
- value += c * fraction;
- fraction *= 0.1;
- } while ( 1 );
-
- }
-
- // not handling 10e10 notation...
-
- return value * sign;
-}
-
-double _atof( const char **stringPtr ) {
- const char *string;
- float sign;
- float value;
- int c = '0';
-
- string = *stringPtr;
-
- // skip whitespace
- while ( *string <= ' ' ) {
- if ( !*string ) {
- *stringPtr = string;
- return 0;
- }
- string++;
- }
-
- // check sign
- switch ( *string ) {
- case '+':
- string++;
- sign = 1;
- break;
- case '-':
- string++;
- sign = -1;
- break;
- default:
- sign = 1;
- break;
- }
-
- // read digits
- value = 0;
- if ( string[0] != '.' ) {
- do {
- c = *string++;
- if ( c < '0' || c > '9' ) {
- break;
- }
- c -= '0';
- value = value * 10 + c;
- } while ( 1 );
- }
-
- // check for decimal point
- if ( c == '.' ) {
- double fraction;
-
- fraction = 0.1;
- do {
- c = *string++;
- if ( c < '0' || c > '9' ) {
- break;
- }
- c -= '0';
- value += c * fraction;
- fraction *= 0.1;
- } while ( 1 );
-
- }
-
- // not handling 10e10 notation...
- *stringPtr = string;
-
- return value * sign;
-}
-
-/*
-==============
-strtod
-
-Without an errno variable, this is a fair bit less useful than it is in libc
-but it's still a fair bit more capable than atof or _atof
-Handles inf[inity], nan (ignoring case), hexadecimals, and decimals
-Handles decimal exponents like 10e10 and hex exponents like 0x7f8p20
-10e10 == 10000000000 (power of ten)
-0x7f8p20 == 0x7f800000 (decimal power of two)
-The variable pointed to by endptr will hold the location of the first character
-in the nptr string that was not used in the conversion
-==============
-*/
-double strtod( const char *nptr, const char **endptr )
-{
- double res;
- qboolean neg = qfalse;
-
- // skip whitespace
- while( isspace( *nptr ) )
- nptr++;
-
- // special string parsing
- if( Q_stricmpn( nptr, "nan", 3 ) == 0 )
- {
- floatint_t nan;
- if( endptr == NULL )
- {
- nan.ui = 0x7fffffff;
- return nan.f;
- }
- *endptr = &nptr[3];
- // nan can be followed by a bracketed number (in hex, octal,
- // or decimal) which is then put in the mantissa
- // this can be used to generate signalling or quiet NaNs, for
- // example (though I doubt it'll ever be used)
- // note that nan(0) is infinity!
- if( nptr[3] == '(' )
- {
- const char *end;
- int mantissa = strtol( &nptr[4], &end, 0 );
- if( *end == ')' )
- {
- nan.ui = 0x7f800000 | ( mantissa & 0x7fffff );
- if( endptr )
- *endptr = &end[1];
- return nan.f;
- }
- }
- nan.ui = 0x7fffffff;
- return nan.f;
- }
- if( Q_stricmpn( nptr, "inf", 3 ) == 0 )
- {
- floatint_t inf;
- inf.ui = 0x7f800000;
- if( endptr == NULL )
- return inf.f;
- if( Q_stricmpn( &nptr[3], "inity", 5 ) == 0 )
- *endptr = &nptr[8];
- else
- *endptr = &nptr[3];
- return inf.f;
- }
-
- // normal numeric parsing
- // sign
- if( *nptr == '-' )
- {
- nptr++;
- neg = qtrue;
- }
- else if( *nptr == '+' )
- nptr++;
- // hex
- if( Q_stricmpn( nptr, "0x", 2 ) == 0 )
- {
- // track if we use any digits
- const char *s = &nptr[1], *end = s;
- nptr += 2;
- res = 0;
- while( qtrue )
- {
- if( isdigit( *nptr ) )
- res = 16 * res + ( *nptr++ - '0' );
- else if( *nptr >= 'A' && *nptr <= 'F' )
- res = 16 * res + 10 + *nptr++ - 'A';
- else if( *nptr >= 'a' && *nptr <= 'f' )
- res = 16 * res + 10 + *nptr++ - 'a';
- else
- break;
- }
- // if nptr moved, save it
- if( end + 1 < nptr )
- end = nptr;
- if( *nptr == '.' )
- {
- float place;
- nptr++;
- // 1.0 / 16.0 == 0.0625
- // I don't expect the float accuracy to hold out for
- // very long but since we need to know the length of
- // the string anyway we keep on going regardless
- for( place = 0.0625;; place /= 16.0 )
- {
- if( isdigit( *nptr ) )
- res += place * ( *nptr++ - '0' );
- else if( *nptr >= 'A' && *nptr <= 'F' )
- res += place * ( 10 + *nptr++ - 'A' );
- else if( *nptr >= 'a' && *nptr <= 'f' )
- res += place * ( 10 + *nptr++ - 'a' );
- else
- break;
- }
- if( end < nptr )
- end = nptr;
- }
- // parse an optional exponent, representing multiplication
- // by a power of two
- // exponents are only valid if we encountered at least one
- // digit already (and have therefore set end to something)
- if( end != s && tolower( *nptr ) == 'p' )
- {
- int exp;
- float res2;
- // apparently (confusingly) the exponent should be
- // decimal
- exp = strtol( &nptr[1], &end, 10 );
- if( &nptr[1] == end )
- {
- // no exponent
- if( endptr )
- *endptr = nptr;
- return res;
- }
- if( exp > 0 )
- {
- while( exp-- > 0 )
- {
- res2 = res * 2;
- // check for infinity
- if( res2 <= res )
- break;
- res = res2;
- }
- }
- else
- {
- while( exp++ < 0 )
- {
- res2 = res / 2;
- // check for underflow
- if( res2 >= res )
- break;
- res = res2;
- }
- }
- }
- if( endptr )
- *endptr = end;
- return res;
- }
- // decimal
- else
- {
- // track if we find any digits
- const char *end = nptr, *p = nptr;
- // this is most of the work
- for( res = 0; isdigit( *nptr );
- res = 10 * res + *nptr++ - '0' );
- // if nptr moved, we read something
- if( end < nptr )
- end = nptr;
- if( *nptr == '.' )
- {
- // fractional part
- float place;
- nptr++;
- for( place = 0.1; isdigit( *nptr ); place /= 10.0 )
- res += ( *nptr++ - '0' ) * place;
- // if nptr moved, we read something
- if( end + 1 < nptr )
- end = nptr;
- }
- // exponent
- // meaningless without having already read digits, so check
- // we've set end to something
- if( p != end && tolower( *nptr ) == 'e' )
- {
- int exp;
- float res10;
- exp = strtol( &nptr[1], &end, 10 );
- if( &nptr[1] == end )
- {
- // no exponent
- if( endptr )
- *endptr = nptr;
- return res;
- }
- if( exp > 0 )
- {
- while( exp-- > 0 )
- {
- res10 = res * 10;
- // check for infinity to save us time
- if( res10 <= res )
- break;
- res = res10;
- }
- }
- else if( exp < 0 )
- {
- while( exp++ < 0 )
- {
- res10 = res / 10;
- // check for underflow
- // (test for 0 would probably be just
- // as good)
- if( res10 >= res )
- break;
- res = res10;
- }
- }
- }
- if( endptr )
- *endptr = end;
- return res;
- }
-}
-
-int atoi( const char *string ) {
- int sign;
- int value;
- int c;
-
-
- // skip whitespace
- while ( *string <= ' ' ) {
- if ( !*string ) {
- return 0;
- }
- string++;
- }
-
- // check sign
- switch ( *string ) {
- case '+':
- string++;
- sign = 1;
- break;
- case '-':
- string++;
- sign = -1;
- break;
- default:
- sign = 1;
- break;
- }
-
- // read digits
- value = 0;
- do {
- c = *string++;
- if ( c < '0' || c > '9' ) {
- break;
- }
- c -= '0';
- value = value * 10 + c;
- } while ( 1 );
-
- // not handling 10e10 notation...
-
- return value * sign;
-}
-
-
-int _atoi( const char **stringPtr ) {
- int sign;
- int value;
- int c;
- const char *string;
-
- string = *stringPtr;
-
- // skip whitespace
- while ( *string <= ' ' ) {
- if ( !*string ) {
- return 0;
- }
- string++;
- }
-
- // check sign
- switch ( *string ) {
- case '+':
- string++;
- sign = 1;
- break;
- case '-':
- string++;
- sign = -1;
- break;
- default:
- sign = 1;
- break;
- }
-
- // read digits
- value = 0;
- do {
- c = *string++;
- if ( c < '0' || c > '9' ) {
- break;
- }
- c -= '0';
- value = value * 10 + c;
- } while ( 1 );
-
- // not handling 10e10 notation...
-
- *stringPtr = string;
-
- return value * sign;
-}
-
-/*
-==============
-strtol
-
-Handles any base from 2 to 36. If base is 0 then it guesses
-decimal, hex, or octal based on the format of the number (leading 0 or 0x)
-Will not overflow - returns LONG_MIN or LONG_MAX as appropriate
-*endptr is set to the location of the first character not used
-==============
-*/
-long strtol( const char *nptr, const char **endptr, int base )
-{
- long res;
- qboolean pos = qtrue;
-
- if( endptr )
- *endptr = nptr;
- // bases other than 0, 2, 8, 16 are very rarely used, but they're
- // not much extra effort to support
- if( base < 0 || base == 1 || base > 36 )
- return 0;
- // skip leading whitespace
- while( isspace( *nptr ) )
- nptr++;
- // sign
- if( *nptr == '-' )
- {
- nptr++;
- pos = qfalse;
- }
- else if( *nptr == '+' )
- nptr++;
- // look for base-identifying sequences e.g. 0x for hex, 0 for octal
- if( nptr[0] == '0' )
- {
- nptr++;
- // 0 is always a valid digit
- if( endptr )
- *endptr = nptr;
- if( *nptr == 'x' || *nptr == 'X' )
- {
- if( base != 0 && base != 16 )
- {
- // can't be hex, reject x (accept 0)
- if( endptr )
- *endptr = nptr;
- return 0;
- }
- nptr++;
- base = 16;
- }
- else if( base == 0 )
- base = 8;
- }
- else if( base == 0 )
- base = 10;
- res = 0;
- while( qtrue )
- {
- int val;
- if( isdigit( *nptr ) )
- val = *nptr - '0';
- else if( islower( *nptr ) )
- val = 10 + *nptr - 'a';
- else if( isupper( *nptr ) )
- val = 10 + *nptr - 'A';
- else
- break;
- if( val >= base )
- break;
- // we go negative because LONG_MIN is further from 0 than
- // LONG_MAX
- if( res < ( LONG_MIN + val ) / base )
- res = LONG_MIN; // overflow
- else
- res = res * base - val;
- nptr++;
- if( endptr )
- *endptr = nptr;
- }
- if( pos )
- {
- // can't represent LONG_MIN positive
- if( res == LONG_MIN )
- res = LONG_MAX;
- else
- res = -res;
- }
- return res;
-}
-
-int abs( int n ) {
- return n < 0 ? -n : n;
-}
-
-double fabs( double x ) {
- return x < 0 ? -x : x;
-}
-
-
-
-//=========================================================
-
-/*
- * New implementation by Patrick Powell and others for vsnprintf.
- * Supports length checking in strings.
-*/
-
-/*
- * Copyright Patrick Powell 1995
- * This code is based on code written by Patrick Powell (papowell at astart.com)
- * It may be used for any purpose as long as this notice remains intact
- * on all source code distributions
- */
-
-/**************************************************************
- * Original:
- * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
- * A bombproof version of doprnt (dopr) included.
- * Sigh. This sort of thing is always nasty do deal with. Note that
- * the version here does not include floating point...
- *
- * snprintf() is used instead of sprintf() as it does limit checks
- * for string length. This covers a nasty loophole.
- *
- * The other functions are there to prevent NULL pointers from
- * causing nast effects.
- *
- * More Recently:
- * Brandon Long <blong at fiction.net> 9/15/96 for mutt 0.43
- * This was ugly. It is still ugly. I opted out of floating point
- * numbers, but the formatter understands just about everything
- * from the normal C string format, at least as far as I can tell from
- * the Solaris 2.5 printf(3S) man page.
- *
- * Brandon Long <blong at fiction.net> 10/22/97 for mutt 0.87.1
- * Ok, added some minimal floating point support, which means this
- * probably requires libm on most operating systems. Don't yet
- * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
- * was pretty badly broken, it just wasn't being exercised in ways
- * which showed it, so that's been fixed. Also, formated the code
- * to mutt conventions, and removed dead code left over from the
- * original. Also, there is now a builtin-test, just compile with:
- * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
- * and run snprintf for results.
- *
- * Thomas Roessler <roessler at guug.de> 01/27/98 for mutt 0.89i
- * The PGP code was using unsigned hexadecimal formats.
- * Unfortunately, unsigned formats simply didn't work.
- *
- * Michael Elkins <me at cs.hmc.edu> 03/05/98 for mutt 0.90.8
- * The original code assumed that both snprintf() and vsnprintf() were
- * missing. Some systems only have snprintf() but not vsnprintf(), so
- * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
- *
- * Andrew Tridgell (tridge at samba.org) Oct 1998
- * fixed handling of %.0f
- * added test for HAVE_LONG_DOUBLE
- *
- * Russ Allbery <rra at stanford.edu> 2000-08-26
- * fixed return value to comply with C99
- * fixed handling of snprintf(NULL, ...)
- *
- * Hrvoje Niksic <hniksic at arsdigita.com> 2000-11-04
- * include <config.h> instead of "config.h".
- * moved TEST_SNPRINTF stuff out of HAVE_SNPRINTF ifdef.
- * include <stdio.h> for NULL.
- * added support and test cases for long long.
- * don't declare argument types to (v)snprintf if stdarg is not used.
- * use int instead of short int as 2nd arg to va_arg.
- *
- **************************************************************/
-
-/* BDR 2002-01-13 %e and %g were being ignored. Now do something,
- if not necessarily correctly */
-
-#if (SIZEOF_LONG_DOUBLE > 0)
-/* #ifdef HAVE_LONG_DOUBLE */
-#define LDOUBLE long double
-#else
-#define LDOUBLE double
-#endif
-
-#if (SIZEOF_LONG_LONG > 0)
-/* #ifdef HAVE_LONG_LONG */
-# define LLONG long long
-#else
-# define LLONG long
-#endif
-
-static int dopr (char *buffer, size_t maxlen, const char *format,
- va_list args);
-static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
- char *value, int flags, int min, int max);
-static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
- LLONG value, int base, int min, int max, int flags);
-static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
- LDOUBLE fvalue, int min, int max, int flags);
-static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
-
-/*
- * dopr(): poor man's version of doprintf
- */
-
-/* format read states */
-#define DP_S_DEFAULT 0
-#define DP_S_FLAGS 1
-#define DP_S_MIN 2
-#define DP_S_DOT 3
-#define DP_S_MAX 4
-#define DP_S_MOD 5
-#define DP_S_MOD_L 6
-#define DP_S_CONV 7
-#define DP_S_DONE 8
-
-/* format flags - Bits */
-#define DP_F_MINUS (1 << 0)
-#define DP_F_PLUS (1 << 1)
-#define DP_F_SPACE (1 << 2)
-#define DP_F_NUM (1 << 3)
-#define DP_F_ZERO (1 << 4)
-#define DP_F_UP (1 << 5)
-#define DP_F_UNSIGNED (1 << 6)
-
-/* Conversion Flags */
-#define DP_C_SHORT 1
-#define DP_C_LONG 2
-#define DP_C_LLONG 3
-#define DP_C_LDOUBLE 4
-
-#define char_to_int(p) (p - '0')
-#define MAX(p,q) ((p >= q) ? p : q)
-#define MIN(p,q) ((p <= q) ? p : q)
-
-static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
-{
- char ch;
- LLONG value;
- LDOUBLE fvalue;
- char *strvalue;
- int min;
- int max;
- int state;
- int flags;
- int cflags;
- int total;
- size_t currlen;
-
- state = DP_S_DEFAULT;
- currlen = flags = cflags = min = 0;
- max = -1;
- ch = *format++;
- total = 0;
-
- while (state != DP_S_DONE)
- {
- if (ch == '\0')
- state = DP_S_DONE;
-
- switch(state)
- {
- case DP_S_DEFAULT:
- if (ch == '%')
- state = DP_S_FLAGS;
- else
- total += dopr_outch (buffer, &currlen, maxlen, ch);
- ch = *format++;
- break;
- case DP_S_FLAGS:
- switch (ch)
- {
- case '-':
- flags |= DP_F_MINUS;
- ch = *format++;
- break;
- case '+':
- flags |= DP_F_PLUS;
- ch = *format++;
- break;
- case ' ':
- flags |= DP_F_SPACE;
- ch = *format++;
- break;
- case '#':
- flags |= DP_F_NUM;
- ch = *format++;
- break;
- case '0':
- flags |= DP_F_ZERO;
- ch = *format++;
- break;
- default:
- state = DP_S_MIN;
- break;
- }
- break;
- case DP_S_MIN:
- if ('0' <= ch && ch <= '9')
- {
- min = 10*min + char_to_int (ch);
- ch = *format++;
- }
- else if (ch == '*')
- {
- min = va_arg (args, int);
- ch = *format++;
- state = DP_S_DOT;
- }
- else
- state = DP_S_DOT;
- break;
- case DP_S_DOT:
- if (ch == '.')
- {
- state = DP_S_MAX;
- ch = *format++;
- }
- else
- state = DP_S_MOD;
- break;
- case DP_S_MAX:
- if ('0' <= ch && ch <= '9')
- {
- if (max < 0)
- max = 0;
- max = 10*max + char_to_int (ch);
- ch = *format++;
- }
- else if (ch == '*')
- {
- max = va_arg (args, int);
- ch = *format++;
- state = DP_S_MOD;
- }
- else
- state = DP_S_MOD;
- break;
- case DP_S_MOD:
- switch (ch)
- {
- case 'h':
- cflags = DP_C_SHORT;
- ch = *format++;
- break;
- case 'l':
- cflags = DP_C_LONG;
- ch = *format++;
- break;
- case 'L':
- cflags = DP_C_LDOUBLE;
- ch = *format++;
- break;
- default:
- break;
- }
- if (cflags != DP_C_LONG)
- state = DP_S_CONV;
- else
- state = DP_S_MOD_L;
- break;
- case DP_S_MOD_L:
- switch (ch)
- {
- case 'l':
- cflags = DP_C_LLONG;
- ch = *format++;
- break;
- default:
- break;
- }
- state = DP_S_CONV;
- break;
- case DP_S_CONV:
- switch (ch)
- {
- case 'd':
- case 'i':
- if (cflags == DP_C_SHORT)
- value = (short int)va_arg (args, int);
- else if (cflags == DP_C_LONG)
- value = va_arg (args, long int);
- else if (cflags == DP_C_LLONG)
- value = va_arg (args, LLONG);
- else
- value = va_arg (args, int);
- total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
- break;
- case 'o':
- flags |= DP_F_UNSIGNED;
- if (cflags == DP_C_SHORT)
-// value = (unsigned short int) va_arg (args, unsigned short int); // Thilo: This does not work because the rcc compiler cannot do that cast correctly.
- value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1); // Using this workaround instead.
- else if (cflags == DP_C_LONG)
- value = va_arg (args, unsigned long int);
- else if (cflags == DP_C_LLONG)
- value = va_arg (args, unsigned LLONG);
- else
- value = va_arg (args, unsigned int);
- total += fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
- break;
- case 'u':
- flags |= DP_F_UNSIGNED;
- if (cflags == DP_C_SHORT)
- value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1);
- else if (cflags == DP_C_LONG)
- value = va_arg (args, unsigned long int);
- else if (cflags == DP_C_LLONG)
- value = va_arg (args, unsigned LLONG);
- else
- value = va_arg (args, unsigned int);
- total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
- break;
- case 'X':
- flags |= DP_F_UP;
- case 'x':
- flags |= DP_F_UNSIGNED;
- if (cflags == DP_C_SHORT)
- value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1);
- else if (cflags == DP_C_LONG)
- value = va_arg (args, unsigned long int);
- else if (cflags == DP_C_LLONG)
- value = va_arg (args, unsigned LLONG);
- else
- value = va_arg (args, unsigned int);
- total += fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
- break;
- case 'f':
- if (cflags == DP_C_LDOUBLE)
- fvalue = va_arg (args, LDOUBLE);
- else
- fvalue = va_arg (args, double);
- /* um, floating point? */
- total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
- break;
- case 'E':
- flags |= DP_F_UP;
- case 'e':
- if (cflags == DP_C_LDOUBLE)
- fvalue = va_arg (args, LDOUBLE);
- else
- fvalue = va_arg (args, double);
- /* um, floating point? */
- total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
- break;
- case 'G':
- flags |= DP_F_UP;
- case 'g':
- if (cflags == DP_C_LDOUBLE)
- fvalue = va_arg (args, LDOUBLE);
- else
- fvalue = va_arg (args, double);
- /* um, floating point? */
- total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
- break;
- case 'c':
- total += dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
- break;
- case 's':
- strvalue = va_arg (args, char *);
- total += fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
- break;
- case 'p':
- strvalue = va_arg (args, void *);
- total += fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min,
- max, flags);
- break;
- case 'n':
- if (cflags == DP_C_SHORT)
- {
- short int *num;
- num = va_arg (args, short int *);
- *num = currlen;
- }
- else if (cflags == DP_C_LONG)
- {
- long int *num;
- num = va_arg (args, long int *);
- *num = currlen;
- }
- else if (cflags == DP_C_LLONG)
- {
- LLONG *num;
- num = va_arg (args, LLONG *);
- *num = currlen;
- }
- else
- {
- int *num;
- num = va_arg (args, int *);
- *num = currlen;
- }
- break;
- case '%':
- total += dopr_outch (buffer, &currlen, maxlen, ch);
- break;
- case 'w':
- /* not supported yet, treat as next char */
- ch = *format++;
- break;
- default:
- /* Unknown, skip */
- break;
- }
- ch = *format++;
- state = DP_S_DEFAULT;
- flags = cflags = min = 0;
- max = -1;
- break;
- case DP_S_DONE:
- break;
- default:
- /* hmm? */
- break; /* some picky compilers need this */
- }
- }
- if (buffer != NULL)
- {
- if (currlen < maxlen - 1)
- buffer[currlen] = '\0';
- else
- buffer[maxlen - 1] = '\0';
- }
- return total;
-}
-
-static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
- char *value, int flags, int min, int max)
-{
- int padlen, strln; /* amount to pad */
- int cnt = 0;
- int total = 0;
-
- if (value == 0)
- {
- value = "<NULL>";
- }
-
- for (strln = 0; value[strln]; ++strln); /* strlen */
- if (max >= 0 && max < strln)
- strln = max;
- padlen = min - strln;
- if (padlen < 0)
- padlen = 0;
- if (flags & DP_F_MINUS)
- padlen = -padlen; /* Left Justify */
-
- while (padlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- --padlen;
- }
- while (*value && ((max < 0) || (cnt < max)))
- {
- total += dopr_outch (buffer, currlen, maxlen, *value++);
- ++cnt;
- }
- while (padlen < 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- ++padlen;
- }
- return total;
-}
-
-/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
-
-static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
- LLONG value, int base, int min, int max, int flags)
-{
- int signvalue = 0;
- unsigned LLONG uvalue;
- char convert[24];
- int place = 0;
- int spadlen = 0; /* amount to space pad */
- int zpadlen = 0; /* amount to zero pad */
- const char *digits;
- int total = 0;
-
- if (max < 0)
- max = 0;
-
- uvalue = value;
-
- if(!(flags & DP_F_UNSIGNED))
- {
- if( value < 0 ) {
- signvalue = '-';
- uvalue = -value;
- }
- else
- if (flags & DP_F_PLUS) /* Do a sign (+/i) */
- signvalue = '+';
- else
- if (flags & DP_F_SPACE)
- signvalue = ' ';
- }
-
- if (flags & DP_F_UP)
- /* Should characters be upper case? */
- digits = "0123456789ABCDEF";
- else
- digits = "0123456789abcdef";
-
- do {
- convert[place++] = digits[uvalue % (unsigned)base];
- uvalue = (uvalue / (unsigned)base );
- } while(uvalue && (place < sizeof (convert)));
- if (place == sizeof (convert)) place--;
- convert[place] = 0;
-
- zpadlen = max - place;
- spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
- if (zpadlen < 0) zpadlen = 0;
- if (spadlen < 0) spadlen = 0;
- if (flags & DP_F_ZERO)
- {
- zpadlen = MAX(zpadlen, spadlen);
- spadlen = 0;
- }
- if (flags & DP_F_MINUS)
- spadlen = -spadlen; /* Left Justifty */
-
-#ifdef DEBUG_SNPRINTF
- dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
- zpadlen, spadlen, min, max, place));
-#endif
-
- /* Spaces */
- while (spadlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- --spadlen;
- }
-
- /* Sign */
- if (signvalue)
- total += dopr_outch (buffer, currlen, maxlen, signvalue);
-
- /* Zeros */
- if (zpadlen > 0)
- {
- while (zpadlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, '0');
- --zpadlen;
- }
- }
-
- /* Digits */
- while (place > 0)
- total += dopr_outch (buffer, currlen, maxlen, convert[--place]);
-
- /* Left Justified spaces */
- while (spadlen < 0) {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- ++spadlen;
- }
-
- return total;
-}
-
-static LDOUBLE abs_val (LDOUBLE value)
-{
- LDOUBLE result = value;
-
- if (value < 0)
- result = -value;
-
- return result;
-}
-
-static LDOUBLE pow10 (int exp)
-{
- LDOUBLE result = 1;
-
- while (exp)
- {
- result *= 10;
- exp--;
- }
-
- return result;
-}
-
-static long round (LDOUBLE value)
-{
- long intpart;
-
- intpart = value;
- value = value - intpart;
- if (value >= 0.5)
- intpart++;
-
- return intpart;
-}
-
-static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
- LDOUBLE fvalue, int min, int max, int flags)
-{
- int signvalue = 0;
- LDOUBLE ufvalue;
- char iconvert[20];
- char fconvert[20];
- int iplace = 0;
- int fplace = 0;
- int padlen = 0; /* amount to pad */
- int zpadlen = 0;
- int caps = 0;
- int total = 0;
- long intpart;
- long fracpart;
-
- /*
- * AIX manpage says the default is 0, but Solaris says the default
- * is 6, and sprintf on AIX defaults to 6
- */
- if (max < 0)
- max = 6;
-
- ufvalue = abs_val (fvalue);
-
- if (fvalue < 0)
- signvalue = '-';
- else
- if (flags & DP_F_PLUS) /* Do a sign (+/i) */
- signvalue = '+';
- else
- if (flags & DP_F_SPACE)
- signvalue = ' ';
-
-#if 0
- if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
-#endif
-
- intpart = ufvalue;
-
- /*
- * Sorry, we only support 9 digits past the decimal because of our
- * conversion method
- */
- if (max > 9)
- max = 9;
-
- /* We "cheat" by converting the fractional part to integer by
- * multiplying by a factor of 10
- */
- fracpart = round ((pow10 (max)) * (ufvalue - intpart));
-
- if (fracpart >= pow10 (max))
- {
- intpart++;
- fracpart -= pow10 (max);
- }
-
-#ifdef DEBUG_SNPRINTF
- dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
-#endif
-
- /* Convert integer part */
- do {
- iconvert[iplace++] =
- (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
- intpart = (intpart / 10);
- } while(intpart && (iplace < 20));
- if (iplace == 20) iplace--;
- iconvert[iplace] = 0;
-
- /* Convert fractional part */
- do {
- fconvert[fplace++] =
- (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
- fracpart = (fracpart / 10);
- } while(fracpart && (fplace < 20));
- if (fplace == 20) fplace--;
- fconvert[fplace] = 0;
-
- /* -1 for decimal point, another -1 if we are printing a sign */
- padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
- zpadlen = max - fplace;
- if (zpadlen < 0)
- zpadlen = 0;
- if (padlen < 0)
- padlen = 0;
- if (flags & DP_F_MINUS)
- padlen = -padlen; /* Left Justifty */
-
- if ((flags & DP_F_ZERO) && (padlen > 0))
- {
- if (signvalue)
- {
- total += dopr_outch (buffer, currlen, maxlen, signvalue);
- --padlen;
- signvalue = 0;
- }
- while (padlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, '0');
- --padlen;
- }
- }
- while (padlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- --padlen;
- }
- if (signvalue)
- total += dopr_outch (buffer, currlen, maxlen, signvalue);
-
- while (iplace > 0)
- total += dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
-
- /*
- * Decimal point. This should probably use locale to find the correct
- * char to print out.
- */
- if (max > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, '.');
-
- while (zpadlen-- > 0)
- total += dopr_outch (buffer, currlen, maxlen, '0');
-
- while (fplace > 0)
- total += dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
- }
-
- while (padlen < 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- ++padlen;
- }
-
- return total;
-}
-
-static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
-{
- if (*currlen + 1 < maxlen)
- buffer[(*currlen)++] = c;
- return 1;
-}
-
-int Q_vsnprintf(char *str, size_t length, const char *fmt, va_list args)
-{
- if (str != NULL)
- str[0] = 0;
- return dopr(str, length, fmt, args);
-}
-
-int Q_snprintf(char *str, size_t length, const char *fmt, ...)
-{
- va_list ap;
- int retval;
-
- va_start(ap, fmt);
- retval = Q_vsnprintf(str, length, fmt, ap);
- va_end(ap);
-
- return retval;
-}
-
-/* this is really crappy */
-int sscanf( const char *buffer, const char *fmt, ... ) {
- int cmd;
- va_list ap;
- int count;
- size_t len;
-
- va_start (ap, fmt);
- count = 0;
-
- while ( *fmt ) {
- if ( fmt[0] != '%' ) {
- fmt++;
- continue;
- }
-
- fmt++;
- cmd = *fmt;
-
- if (isdigit (cmd)) {
- len = (size_t)_atoi (&fmt);
- cmd = *(fmt - 1);
- } else {
- len = MAX_STRING_CHARS - 1;
- fmt++;
- }
-
- switch ( cmd ) {
- case 'i':
- case 'd':
- case 'u':
- *(va_arg (ap, int *)) = _atoi( &buffer );
- break;
- case 'f':
- *(va_arg (ap, float *)) = _atof( &buffer );
- break;
- case 's':
- {
- char *s = va_arg (ap, char *);
- while (isspace (*buffer))
- buffer++;
- while (*buffer && !isspace (*buffer) && len-- > 0 )
- *s++ = *buffer++;
- *s++ = '\0';
- break;
- }
- }
- }
-
- va_end (ap);
- return count;
-}
-
-#endif
diff --git a/engine/code/game/bg_lib.h b/engine/code/game/bg_lib.h
deleted file mode 100644
index 0090ddd..0000000
--- a/engine/code/game/bg_lib.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// bg_lib.h -- standard C library replacement routines used by code
-// compiled for the virtual machine
-
-// This file is NOT included on native builds
-#if !defined( BG_LIB_H ) && defined( Q3_VM )
-#define BG_LIB_H
-
-//Ignore __attribute__ on non-gcc platforms
-#ifndef __GNUC__
-#ifndef __attribute__
-#define __attribute__(x)
-#endif
-#endif
-
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
-typedef int size_t;
-
-typedef char * va_list;
-#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
-#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
-#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
-#define va_end(ap) ( ap = (va_list)0 )
-
-#define CHAR_BIT 8 /* number of bits in a char */
-#define SCHAR_MAX 0x7f /* maximum signed char value */
-#define SCHAR_MIN (-SCHAR_MAX - 1) /* minimum signed char value */
-#define UCHAR_MAX 0xff /* maximum unsigned char value */
-
-#define SHRT_MAX 0x7fff /* maximum (signed) short value */
-#define SHRT_MIN (-SHRT_MAX - 1) /* minimum (signed) short value */
-#define USHRT_MAX 0xffff /* maximum unsigned short value */
-#define INT_MAX 0x7fffffff /* maximum (signed) int value */
-#define INT_MIN (-INT_MAX - 1) /* minimum (signed) int value */
-#define UINT_MAX 0xffffffff /* maximum unsigned int value */
-#define LONG_MAX 0x7fffffffL /* maximum (signed) long value */
-#define LONG_MIN (-LONG_MAX - 1) /* minimum (signed) long value */
-#define ULONG_MAX 0xffffffffUL /* maximum unsigned long value */
-
-#define isalnum(c) (isalpha(c) || isdigit(c))
-#define isalpha(c) (isupper(c) || islower(c))
-#define isascii(c) ((c) > 0 && (c) <= 0x7f)
-#define iscntrl(c) (((c) >= 0) && (((c) <= 0x1f) || ((c) == 0x7f)))
-#define isdigit(c) ((c) >= '0' && (c) <= '9')
-#define isgraph(c) ((c) != ' ' && isprint(c))
-#define islower(c) ((c) >= 'a' && (c) <= 'z')
-#define isprint(c) ((c) >= ' ' && (c) <= '~')
-#define ispunct(c) (((c) > ' ' && (c) <= '~') && !isalnum(c))
-#define isspace(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || (c) == '\r' || \
- (c) == '\t' || (c) == '\v')
-#define isupper(c) ((c) >= 'A' && (c) <= 'Z')
-#define isxdigit(c) (isxupper(c) || isxlower(c))
-#define isxlower(c) (isdigit(c) || (c >= 'a' && c <= 'f'))
-#define isxupper(c) (isdigit(c) || (c >= 'A' && c <= 'F'))
-
-// Misc functions
-typedef int cmp_t(const void *, const void *);
-void qsort(void *a, size_t n, size_t es, cmp_t *cmp);
-void srand( unsigned seed );
-int rand( void );
-
-// String functions
-size_t strlen( const char *string );
-char *strcat( char *strDestination, const char *strSource );
-char *strcpy( char *strDestination, const char *strSource );
-int strcmp( const char *string1, const char *string2 );
-char *strchr( const char *string, int c );
-char *strstr( const char *string, const char *strCharSet );
-char *strncpy( char *strDest, const char *strSource, size_t count );
-int tolower( int c );
-int toupper( int c );
-
-double atof( const char *string );
-double _atof( const char **stringPtr );
-double strtod( const char *nptr, const char **endptr );
-int atoi( const char *string );
-int _atoi( const char **stringPtr );
-long strtol( const char *nptr, const char **endptr, int base );
-
-int Q_vsnprintf( char *buffer, size_t length, const char *fmt, va_list argptr );
-int Q_snprintf( char *buffer, size_t length, const char *fmt, ... ) __attribute__ ((format (printf, 3, 4)));
-
-int sscanf( const char *buffer, const char *fmt, ... ) __attribute__ ((format (scanf, 2, 3)));
-
-// Memory functions
-void *memmove( void *dest, const void *src, size_t count );
-void *memset( void *dest, int c, size_t count );
-void *memcpy( void *dest, const void *src, size_t count );
-
-// Math functions
-double ceil( double x );
-double floor( double x );
-double sqrt( double x );
-double sin( double x );
-double cos( double x );
-double atan2( double y, double x );
-double tan( double x );
-int abs( int n );
-double fabs( double x );
-double acos( double x );
-
-#endif // BG_LIB_H
diff --git a/engine/code/game/bg_misc.c b/engine/code/game/bg_misc.c
deleted file mode 100644
index a6ec86e..0000000
--- a/engine/code/game/bg_misc.c
+++ /dev/null
@@ -1,1604 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// bg_misc.c -- both games misc functions, all completely stateless
-
-#include "../qcommon/q_shared.h"
-#include "bg_public.h"
-
-/*QUAKED item_***** ( 0 0 0 ) (-16 -16 -16) (16 16 16) suspended
-DO NOT USE THIS CLASS, IT JUST HOLDS GENERAL INFORMATION.
-The suspended flag will allow items to hang in the air, otherwise they are dropped to the next surface.
-
-If an item is the target of another entity, it will not spawn in until fired.
-
-An item fires all of its targets when it is picked up. If the toucher can't carry it, the targets won't be fired.
-
-"notfree" if set to 1, don't spawn in free for all games
-"notteam" if set to 1, don't spawn in team games
-"notsingle" if set to 1, don't spawn in single player games
-"wait" override the default wait before respawning. -1 = never respawn automatically, which can be used with targeted spawning.
-"random" random number of plus or minus seconds varied from the respawn time
-"count" override quantity or duration on most items.
-*/
-
-gitem_t bg_itemlist[] =
-{
- {
- NULL,
- NULL,
- { NULL,
- NULL,
- NULL, NULL} ,
-/* icon */ NULL,
-/* pickup */ NULL,
- 0,
- 0,
- 0,
-/* precache */ "",
-/* sounds */ ""
- }, // leave index 0 alone
-
- //
- // ARMOR
- //
-
-/*QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "item_armor_shard",
- "sound/misc/ar1_pkup.wav",
- { "models/powerups/armor/shard.md3",
- "models/powerups/armor/shard_sphere.md3",
- NULL, NULL} ,
-/* icon */ "icons/iconr_shard",
-/* pickup */ "Armor Shard",
- 5,
- IT_ARMOR,
- 0,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "item_armor_combat",
- "sound/misc/ar2_pkup.wav",
- { "models/powerups/armor/armor_yel.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconr_yellow",
-/* pickup */ "Armor",
- 50,
- IT_ARMOR,
- 0,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "item_armor_body",
- "sound/misc/ar2_pkup.wav",
- { "models/powerups/armor/armor_red.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconr_red",
-/* pickup */ "Heavy Armor",
- 100,
- IT_ARMOR,
- 0,
-/* precache */ "",
-/* sounds */ ""
- },
-
- //
- // health
- //
-/*QUAKED item_health_small (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "item_health_small",
- "sound/items/s_health.wav",
- { "models/powerups/health/small_cross.md3",
- "models/powerups/health/small_sphere.md3",
- NULL, NULL },
-/* icon */ "icons/iconh_green",
-/* pickup */ "5 Health",
- 5,
- IT_HEALTH,
- 0,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED item_health (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "item_health",
- "sound/items/n_health.wav",
- { "models/powerups/health/medium_cross.md3",
- "models/powerups/health/medium_sphere.md3",
- NULL, NULL },
-/* icon */ "icons/iconh_yellow",
-/* pickup */ "25 Health",
- 25,
- IT_HEALTH,
- 0,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED item_health_large (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "item_health_large",
- "sound/items/l_health.wav",
- { "models/powerups/health/large_cross.md3",
- "models/powerups/health/large_sphere.md3",
- NULL, NULL },
-/* icon */ "icons/iconh_red",
-/* pickup */ "50 Health",
- 50,
- IT_HEALTH,
- 0,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED item_health_mega (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "item_health_mega",
- "sound/items/m_health.wav",
- { "models/powerups/health/mega_cross.md3",
- "models/powerups/health/mega_sphere.md3",
- NULL, NULL },
-/* icon */ "icons/iconh_mega",
-/* pickup */ "Mega Health",
- 100,
- IT_HEALTH,
- 0,
-/* precache */ "",
-/* sounds */ ""
- },
-
-
- //
- // WEAPONS
- //
-
-/*QUAKED weapon_gauntlet (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "weapon_gauntlet",
- "sound/misc/w_pkup.wav",
- { "models/weapons2/gauntlet/gauntlet.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconw_gauntlet",
-/* pickup */ "Gauntlet",
- 0,
- IT_WEAPON,
- WP_GAUNTLET,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "weapon_shotgun",
- "sound/misc/w_pkup.wav",
- { "models/weapons2/shotgun/shotgun.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconw_shotgun",
-/* pickup */ "Shotgun",
- 10,
- IT_WEAPON,
- WP_SHOTGUN,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "weapon_machinegun",
- "sound/misc/w_pkup.wav",
- { "models/weapons2/machinegun/machinegun.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconw_machinegun",
-/* pickup */ "Machinegun",
- 40,
- IT_WEAPON,
- WP_MACHINEGUN,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "weapon_grenadelauncher",
- "sound/misc/w_pkup.wav",
- { "models/weapons2/grenadel/grenadel.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconw_grenade",
-/* pickup */ "Grenade Launcher",
- 10,
- IT_WEAPON,
- WP_GRENADE_LAUNCHER,
-/* precache */ "",
-/* sounds */ "sound/weapons/grenade/hgrenb1a.wav sound/weapons/grenade/hgrenb2a.wav"
- },
-
-/*QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "weapon_rocketlauncher",
- "sound/misc/w_pkup.wav",
- { "models/weapons2/rocketl/rocketl.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconw_rocket",
-/* pickup */ "Rocket Launcher",
- 10,
- IT_WEAPON,
- WP_ROCKET_LAUNCHER,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED weapon_lightning (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "weapon_lightning",
- "sound/misc/w_pkup.wav",
- { "models/weapons2/lightning/lightning.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconw_lightning",
-/* pickup */ "Lightning Gun",
- 100,
- IT_WEAPON,
- WP_LIGHTNING,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "weapon_railgun",
- "sound/misc/w_pkup.wav",
- { "models/weapons2/railgun/railgun.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconw_railgun",
-/* pickup */ "Railgun",
- 10,
- IT_WEAPON,
- WP_RAILGUN,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED weapon_plasmagun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "weapon_plasmagun",
- "sound/misc/w_pkup.wav",
- { "models/weapons2/plasma/plasma.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconw_plasma",
-/* pickup */ "Plasma Gun",
- 50,
- IT_WEAPON,
- WP_PLASMAGUN,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "weapon_bfg",
- "sound/misc/w_pkup.wav",
- { "models/weapons2/bfg/bfg.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconw_bfg",
-/* pickup */ "BFG10K",
- 20,
- IT_WEAPON,
- WP_BFG,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED weapon_grapplinghook (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "weapon_grapplinghook",
- "sound/misc/w_pkup.wav",
- { "models/weapons2/grapple/grapple.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconw_grapple",
-/* pickup */ "Grappling Hook",
- 0,
- IT_WEAPON,
- WP_GRAPPLING_HOOK,
-/* precache */ "",
-/* sounds */ ""
- },
-
- //
- // AMMO ITEMS
- //
-
-/*QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "ammo_shells",
- "sound/misc/am_pkup.wav",
- { "models/powerups/ammo/shotgunam.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/icona_shotgun",
-/* pickup */ "Shells",
- 10,
- IT_AMMO,
- WP_SHOTGUN,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "ammo_bullets",
- "sound/misc/am_pkup.wav",
- { "models/powerups/ammo/machinegunam.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/icona_machinegun",
-/* pickup */ "Bullets",
- 50,
- IT_AMMO,
- WP_MACHINEGUN,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "ammo_grenades",
- "sound/misc/am_pkup.wav",
- { "models/powerups/ammo/grenadeam.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/icona_grenade",
-/* pickup */ "Grenades",
- 5,
- IT_AMMO,
- WP_GRENADE_LAUNCHER,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "ammo_cells",
- "sound/misc/am_pkup.wav",
- { "models/powerups/ammo/plasmaam.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/icona_plasma",
-/* pickup */ "Cells",
- 30,
- IT_AMMO,
- WP_PLASMAGUN,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED ammo_lightning (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "ammo_lightning",
- "sound/misc/am_pkup.wav",
- { "models/powerups/ammo/lightningam.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/icona_lightning",
-/* pickup */ "Lightning",
- 60,
- IT_AMMO,
- WP_LIGHTNING,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "ammo_rockets",
- "sound/misc/am_pkup.wav",
- { "models/powerups/ammo/rocketam.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/icona_rocket",
-/* pickup */ "Rockets",
- 5,
- IT_AMMO,
- WP_ROCKET_LAUNCHER,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "ammo_slugs",
- "sound/misc/am_pkup.wav",
- { "models/powerups/ammo/railgunam.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/icona_railgun",
-/* pickup */ "Slugs",
- 10,
- IT_AMMO,
- WP_RAILGUN,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED ammo_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "ammo_bfg",
- "sound/misc/am_pkup.wav",
- { "models/powerups/ammo/bfgam.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/icona_bfg",
-/* pickup */ "Bfg Ammo",
- 15,
- IT_AMMO,
- WP_BFG,
-/* precache */ "",
-/* sounds */ ""
- },
-
- //
- // HOLDABLE ITEMS
- //
-/*QUAKED holdable_teleporter (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "holdable_teleporter",
- "sound/items/holdable.wav",
- { "models/powerups/holdable/teleporter.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/teleporter",
-/* pickup */ "Personal Teleporter",
- 60,
- IT_HOLDABLE,
- HI_TELEPORTER,
-/* precache */ "",
-/* sounds */ ""
- },
-/*QUAKED holdable_medkit (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "holdable_medkit",
- "sound/items/holdable.wav",
- {
- "models/powerups/holdable/medkit.md3",
- "models/powerups/holdable/medkit_sphere.md3",
- NULL, NULL},
-/* icon */ "icons/medkit",
-/* pickup */ "Medkit",
- 60,
- IT_HOLDABLE,
- HI_MEDKIT,
-/* precache */ "",
-/* sounds */ "sound/items/use_medkit.wav"
- },
-
- //
- // POWERUP ITEMS
- //
-/*QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "item_quad",
- "sound/items/quaddamage.wav",
- { "models/powerups/instant/quad.md3",
- "models/powerups/instant/quad_ring.md3",
- NULL, NULL },
-/* icon */ "icons/quad",
-/* pickup */ "Quad Damage",
- 30,
- IT_POWERUP,
- PW_QUAD,
-/* precache */ "",
-/* sounds */ "sound/items/damage2.wav sound/items/damage3.wav"
- },
-
-/*QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "item_enviro",
- "sound/items/protect.wav",
- { "models/powerups/instant/enviro.md3",
- "models/powerups/instant/enviro_ring.md3",
- NULL, NULL },
-/* icon */ "icons/envirosuit",
-/* pickup */ "Battle Suit",
- 30,
- IT_POWERUP,
- PW_BATTLESUIT,
-/* precache */ "",
-/* sounds */ "sound/items/airout.wav sound/items/protect3.wav"
- },
-
-/*QUAKED item_haste (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "item_haste",
- "sound/items/haste.wav",
- { "models/powerups/instant/haste.md3",
- "models/powerups/instant/haste_ring.md3",
- NULL, NULL },
-/* icon */ "icons/haste",
-/* pickup */ "Speed",
- 30,
- IT_POWERUP,
- PW_HASTE,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED item_invis (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "item_invis",
- "sound/items/invisibility.wav",
- { "models/powerups/instant/invis.md3",
- "models/powerups/instant/invis_ring.md3",
- NULL, NULL },
-/* icon */ "icons/invis",
-/* pickup */ "Invisibility",
- 30,
- IT_POWERUP,
- PW_INVIS,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED item_regen (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "item_regen",
- "sound/items/regeneration.wav",
- { "models/powerups/instant/regen.md3",
- "models/powerups/instant/regen_ring.md3",
- NULL, NULL },
-/* icon */ "icons/regen",
-/* pickup */ "Regeneration",
- 30,
- IT_POWERUP,
- PW_REGEN,
-/* precache */ "",
-/* sounds */ "sound/items/regen.wav"
- },
-
-/*QUAKED item_flight (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "item_flight",
- "sound/items/flight.wav",
- { "models/powerups/instant/flight.md3",
- "models/powerups/instant/flight_ring.md3",
- NULL, NULL },
-/* icon */ "icons/flight",
-/* pickup */ "Flight",
- 60,
- IT_POWERUP,
- PW_FLIGHT,
-/* precache */ "",
-/* sounds */ "sound/items/flight.wav"
- },
-
-/*QUAKED team_CTF_redflag (1 0 0) (-16 -16 -16) (16 16 16)
-Only in CTF games
-*/
- {
- "team_CTF_redflag",
- NULL,
- { "models/flags/r_flag.md3",
- NULL, NULL, NULL },
-/* icon */ "icons/iconf_red1",
-/* pickup */ "Red Flag",
- 0,
- IT_TEAM,
- PW_REDFLAG,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED team_CTF_blueflag (0 0 1) (-16 -16 -16) (16 16 16)
-Only in CTF games
-*/
- {
- "team_CTF_blueflag",
- NULL,
- { "models/flags/b_flag.md3",
- NULL, NULL, NULL },
-/* icon */ "icons/iconf_blu1",
-/* pickup */ "Blue Flag",
- 0,
- IT_TEAM,
- PW_BLUEFLAG,
-/* precache */ "",
-/* sounds */ ""
- },
-
-#ifdef MISSIONPACK
-/*QUAKED holdable_kamikaze (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "holdable_kamikaze",
- "sound/items/holdable.wav",
- { "models/powerups/kamikazi.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/kamikaze",
-/* pickup */ "Kamikaze",
- 60,
- IT_HOLDABLE,
- HI_KAMIKAZE,
-/* precache */ "",
-/* sounds */ "sound/items/kamikazerespawn.wav"
- },
-
-/*QUAKED holdable_portal (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "holdable_portal",
- "sound/items/holdable.wav",
- { "models/powerups/holdable/porter.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/portal",
-/* pickup */ "Portal",
- 60,
- IT_HOLDABLE,
- HI_PORTAL,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED holdable_invulnerability (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "holdable_invulnerability",
- "sound/items/holdable.wav",
- { "models/powerups/holdable/invulnerability.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/invulnerability",
-/* pickup */ "Invulnerability",
- 60,
- IT_HOLDABLE,
- HI_INVULNERABILITY,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED ammo_nails (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "ammo_nails",
- "sound/misc/am_pkup.wav",
- { "models/powerups/ammo/nailgunam.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/icona_nailgun",
-/* pickup */ "Nails",
- 20,
- IT_AMMO,
- WP_NAILGUN,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED ammo_mines (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "ammo_mines",
- "sound/misc/am_pkup.wav",
- { "models/powerups/ammo/proxmineam.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/icona_proxlauncher",
-/* pickup */ "Proximity Mines",
- 10,
- IT_AMMO,
- WP_PROX_LAUNCHER,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED ammo_belt (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "ammo_belt",
- "sound/misc/am_pkup.wav",
- { "models/powerups/ammo/chaingunam.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/icona_chaingun",
-/* pickup */ "Chaingun Belt",
- 100,
- IT_AMMO,
- WP_CHAINGUN,
-/* precache */ "",
-/* sounds */ ""
- },
-
- //
- // PERSISTANT POWERUP ITEMS
- //
-/*QUAKED item_scout (.3 .3 1) (-16 -16 -16) (16 16 16) suspended redTeam blueTeam
-*/
- {
- "item_scout",
- "sound/items/scout.wav",
- { "models/powerups/scout.md3",
- NULL, NULL, NULL },
-/* icon */ "icons/scout",
-/* pickup */ "Scout",
- 30,
- IT_PERSISTANT_POWERUP,
- PW_SCOUT,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED item_guard (.3 .3 1) (-16 -16 -16) (16 16 16) suspended redTeam blueTeam
-*/
- {
- "item_guard",
- "sound/items/guard.wav",
- { "models/powerups/guard.md3",
- NULL, NULL, NULL },
-/* icon */ "icons/guard",
-/* pickup */ "Guard",
- 30,
- IT_PERSISTANT_POWERUP,
- PW_GUARD,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED item_doubler (.3 .3 1) (-16 -16 -16) (16 16 16) suspended redTeam blueTeam
-*/
- {
- "item_doubler",
- "sound/items/doubler.wav",
- { "models/powerups/doubler.md3",
- NULL, NULL, NULL },
-/* icon */ "icons/doubler",
-/* pickup */ "Doubler",
- 30,
- IT_PERSISTANT_POWERUP,
- PW_DOUBLER,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED item_doubler (.3 .3 1) (-16 -16 -16) (16 16 16) suspended redTeam blueTeam
-*/
- {
- "item_ammoregen",
- "sound/items/ammoregen.wav",
- { "models/powerups/ammo.md3",
- NULL, NULL, NULL },
-/* icon */ "icons/ammo_regen",
-/* pickup */ "Ammo Regen",
- 30,
- IT_PERSISTANT_POWERUP,
- PW_AMMOREGEN,
-/* precache */ "",
-/* sounds */ ""
- },
-
- /*QUAKED team_CTF_neutralflag (0 0 1) (-16 -16 -16) (16 16 16)
-Only in One Flag CTF games
-*/
- {
- "team_CTF_neutralflag",
- NULL,
- { "models/flags/n_flag.md3",
- NULL, NULL, NULL },
-/* icon */ "icons/iconf_neutral1",
-/* pickup */ "Neutral Flag",
- 0,
- IT_TEAM,
- PW_NEUTRALFLAG,
-/* precache */ "",
-/* sounds */ ""
- },
-
- {
- "item_redcube",
- "sound/misc/am_pkup.wav",
- { "models/powerups/orb/r_orb.md3",
- NULL, NULL, NULL },
-/* icon */ "icons/iconh_rorb",
-/* pickup */ "Red Cube",
- 0,
- IT_TEAM,
- 0,
-/* precache */ "",
-/* sounds */ ""
- },
-
- {
- "item_bluecube",
- "sound/misc/am_pkup.wav",
- { "models/powerups/orb/b_orb.md3",
- NULL, NULL, NULL },
-/* icon */ "icons/iconh_borb",
-/* pickup */ "Blue Cube",
- 0,
- IT_TEAM,
- 0,
-/* precache */ "",
-/* sounds */ ""
- },
-/*QUAKED weapon_nailgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "weapon_nailgun",
- "sound/misc/w_pkup.wav",
- { "models/weapons/nailgun/nailgun.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconw_nailgun",
-/* pickup */ "Nailgun",
- 10,
- IT_WEAPON,
- WP_NAILGUN,
-/* precache */ "",
-/* sounds */ ""
- },
-
-/*QUAKED weapon_prox_launcher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "weapon_prox_launcher",
- "sound/misc/w_pkup.wav",
- { "models/weapons/proxmine/proxmine.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconw_proxlauncher",
-/* pickup */ "Prox Launcher",
- 5,
- IT_WEAPON,
- WP_PROX_LAUNCHER,
-/* precache */ "",
-/* sounds */ "sound/weapons/proxmine/wstbtick.wav "
- "sound/weapons/proxmine/wstbactv.wav "
- "sound/weapons/proxmine/wstbimpl.wav "
- "sound/weapons/proxmine/wstbimpm.wav "
- "sound/weapons/proxmine/wstbimpd.wav "
- "sound/weapons/proxmine/wstbactv.wav"
- },
-
-/*QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
-*/
- {
- "weapon_chaingun",
- "sound/misc/w_pkup.wav",
- { "models/weapons/vulcan/vulcan.md3",
- NULL, NULL, NULL},
-/* icon */ "icons/iconw_chaingun",
-/* pickup */ "Chaingun",
- 80,
- IT_WEAPON,
- WP_CHAINGUN,
-/* precache */ "",
-/* sounds */ "sound/weapons/vulcan/wvulwind.wav"
- },
-#endif
-
- // end of list marker
- {NULL}
-};
-
-int bg_numItems = sizeof(bg_itemlist) / sizeof(bg_itemlist[0]) - 1;
-
-
-/*
-==============
-BG_FindItemForPowerup
-==============
-*/
-gitem_t *BG_FindItemForPowerup( powerup_t pw ) {
- int i;
-
- for ( i = 0 ; i < bg_numItems ; i++ ) {
- if ( (bg_itemlist[i].giType == IT_POWERUP ||
- bg_itemlist[i].giType == IT_TEAM ||
- bg_itemlist[i].giType == IT_PERSISTANT_POWERUP) &&
- bg_itemlist[i].giTag == pw ) {
- return &bg_itemlist[i];
- }
- }
-
- return NULL;
-}
-
-
-/*
-==============
-BG_FindItemForHoldable
-==============
-*/
-gitem_t *BG_FindItemForHoldable( holdable_t pw ) {
- int i;
-
- for ( i = 0 ; i < bg_numItems ; i++ ) {
- if ( bg_itemlist[i].giType == IT_HOLDABLE && bg_itemlist[i].giTag == pw ) {
- return &bg_itemlist[i];
- }
- }
-
- Com_Error( ERR_DROP, "HoldableItem not found" );
-
- return NULL;
-}
-
-
-/*
-===============
-BG_FindItemForWeapon
-
-===============
-*/
-gitem_t *BG_FindItemForWeapon( weapon_t weapon ) {
- gitem_t *it;
-
- for ( it = bg_itemlist + 1 ; it->classname ; it++) {
- if ( it->giType == IT_WEAPON && it->giTag == weapon ) {
- return it;
- }
- }
-
- Com_Error( ERR_DROP, "Couldn't find item for weapon %i", weapon);
- return NULL;
-}
-
-/*
-===============
-BG_FindItem
-
-===============
-*/
-gitem_t *BG_FindItem( const char *pickupName ) {
- gitem_t *it;
-
- for ( it = bg_itemlist + 1 ; it->classname ; it++ ) {
- if ( !Q_stricmp( it->pickup_name, pickupName ) )
- return it;
- }
-
- return NULL;
-}
-
-/*
-============
-BG_PlayerTouchesItem
-
-Items can be picked up without actually touching their physical bounds to make
-grabbing them easier
-============
-*/
-qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ) {
- vec3_t origin;
-
- BG_EvaluateTrajectory( &item->pos, atTime, origin );
-
- // we are ignoring ducked differences here
- if ( ps->origin[0] - origin[0] > 44
- || ps->origin[0] - origin[0] < -50
- || ps->origin[1] - origin[1] > 36
- || ps->origin[1] - origin[1] < -36
- || ps->origin[2] - origin[2] > 36
- || ps->origin[2] - origin[2] < -36 ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-
-/*
-================
-BG_CanItemBeGrabbed
-
-Returns false if the item should not be picked up.
-This needs to be the same for client side prediction and server use.
-================
-*/
-qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps ) {
- gitem_t *item;
-#ifdef MISSIONPACK
- int upperBound;
-#endif
-
- if ( ent->modelindex < 1 || ent->modelindex >= bg_numItems ) {
- Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: index out of range" );
- }
-
- item = &bg_itemlist[ent->modelindex];
-
- switch( item->giType ) {
- case IT_WEAPON:
- return qtrue; // weapons are always picked up
-
- case IT_AMMO:
- if ( ps->ammo[ item->giTag ] >= 200 ) {
- return qfalse; // can't hold any more
- }
- return qtrue;
-
- case IT_ARMOR:
-#ifdef MISSIONPACK
- if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
- return qfalse;
- }
-
- // we also clamp armor to the maxhealth for handicapping
- if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
- upperBound = ps->stats[STAT_MAX_HEALTH];
- }
- else {
- upperBound = ps->stats[STAT_MAX_HEALTH] * 2;
- }
-
- if ( ps->stats[STAT_ARMOR] >= upperBound ) {
- return qfalse;
- }
-#else
- if ( ps->stats[STAT_ARMOR] >= ps->stats[STAT_MAX_HEALTH] * 2 ) {
- return qfalse;
- }
-#endif
- return qtrue;
-
- case IT_HEALTH:
- // small and mega healths will go over the max, otherwise
- // don't pick up if already at max
-#ifdef MISSIONPACK
- if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
- upperBound = ps->stats[STAT_MAX_HEALTH];
- }
- else
-#endif
- if ( item->quantity == 5 || item->quantity == 100 ) {
- if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] * 2 ) {
- return qfalse;
- }
- return qtrue;
- }
-
- if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] ) {
- return qfalse;
- }
- return qtrue;
-
- case IT_POWERUP:
- return qtrue; // powerups are always picked up
-
-#ifdef MISSIONPACK
- case IT_PERSISTANT_POWERUP:
- // can only hold one item at a time
- if ( ps->stats[STAT_PERSISTANT_POWERUP] ) {
- return qfalse;
- }
-
- // check team only
- if( ( ent->generic1 & 2 ) && ( ps->persistant[PERS_TEAM] != TEAM_RED ) ) {
- return qfalse;
- }
- if( ( ent->generic1 & 4 ) && ( ps->persistant[PERS_TEAM] != TEAM_BLUE ) ) {
- return qfalse;
- }
-
- return qtrue;
-#endif
-
- case IT_TEAM: // team items, such as flags
-#ifdef MISSIONPACK
- if( gametype == GT_1FCTF ) {
- // neutral flag can always be picked up
- if( item->giTag == PW_NEUTRALFLAG ) {
- return qtrue;
- }
- if (ps->persistant[PERS_TEAM] == TEAM_RED) {
- if (item->giTag == PW_BLUEFLAG && ps->powerups[PW_NEUTRALFLAG] ) {
- return qtrue;
- }
- } else if (ps->persistant[PERS_TEAM] == TEAM_BLUE) {
- if (item->giTag == PW_REDFLAG && ps->powerups[PW_NEUTRALFLAG] ) {
- return qtrue;
- }
- }
- }
-#endif
- if( gametype == GT_CTF ) {
- // ent->modelindex2 is non-zero on items if they are dropped
- // we need to know this because we can pick up our dropped flag (and return it)
- // but we can't pick up our flag at base
- if (ps->persistant[PERS_TEAM] == TEAM_RED) {
- if (item->giTag == PW_BLUEFLAG ||
- (item->giTag == PW_REDFLAG && ent->modelindex2) ||
- (item->giTag == PW_REDFLAG && ps->powerups[PW_BLUEFLAG]) )
- return qtrue;
- } else if (ps->persistant[PERS_TEAM] == TEAM_BLUE) {
- if (item->giTag == PW_REDFLAG ||
- (item->giTag == PW_BLUEFLAG && ent->modelindex2) ||
- (item->giTag == PW_BLUEFLAG && ps->powerups[PW_REDFLAG]) )
- return qtrue;
- }
- }
-
-#ifdef MISSIONPACK
- if( gametype == GT_HARVESTER ) {
- return qtrue;
- }
-#endif
- return qfalse;
-
- case IT_HOLDABLE:
- // can only hold one item at a time
- if ( ps->stats[STAT_HOLDABLE_ITEM] ) {
- return qfalse;
- }
- return qtrue;
-
- case IT_BAD:
- Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: IT_BAD" );
- default:
-#ifndef Q3_VM
-#ifndef NDEBUG
- Com_Printf("BG_CanItemBeGrabbed: unknown enum %d\n", item->giType );
-#endif
-#endif
- break;
- }
-
- return qfalse;
-}
-
-//======================================================================
-
-/*
-================
-BG_EvaluateTrajectory
-
-================
-*/
-void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) {
- float deltaTime;
- float phase;
-
- switch( tr->trType ) {
- case TR_STATIONARY:
- case TR_INTERPOLATE:
- VectorCopy( tr->trBase, result );
- break;
- case TR_LINEAR:
- deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds
- VectorMA( tr->trBase, deltaTime, tr->trDelta, result );
- break;
- case TR_SINE:
- deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration;
- phase = sin( deltaTime * M_PI * 2 );
- VectorMA( tr->trBase, phase, tr->trDelta, result );
- break;
- case TR_LINEAR_STOP:
- if ( atTime > tr->trTime + tr->trDuration ) {
- atTime = tr->trTime + tr->trDuration;
- }
- deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds
- if ( deltaTime < 0 ) {
- deltaTime = 0;
- }
- VectorMA( tr->trBase, deltaTime, tr->trDelta, result );
- break;
- case TR_GRAVITY:
- deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds
- VectorMA( tr->trBase, deltaTime, tr->trDelta, result );
- result[2] -= 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime; // FIXME: local gravity...
- break;
- default:
- Com_Error( ERR_DROP, "BG_EvaluateTrajectory: unknown trType: %i", tr->trTime );
- break;
- }
-}
-
-/*
-================
-BG_EvaluateTrajectoryDelta
-
-For determining velocity at a given time
-================
-*/
-void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ) {
- float deltaTime;
- float phase;
-
- switch( tr->trType ) {
- case TR_STATIONARY:
- case TR_INTERPOLATE:
- VectorClear( result );
- break;
- case TR_LINEAR:
- VectorCopy( tr->trDelta, result );
- break;
- case TR_SINE:
- deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration;
- phase = cos( deltaTime * M_PI * 2 ); // derivative of sin = cos
- phase *= 0.5;
- VectorScale( tr->trDelta, phase, result );
- break;
- case TR_LINEAR_STOP:
- if ( atTime > tr->trTime + tr->trDuration ) {
- VectorClear( result );
- return;
- }
- VectorCopy( tr->trDelta, result );
- break;
- case TR_GRAVITY:
- deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds
- VectorCopy( tr->trDelta, result );
- result[2] -= DEFAULT_GRAVITY * deltaTime; // FIXME: local gravity...
- break;
- default:
- Com_Error( ERR_DROP, "BG_EvaluateTrajectoryDelta: unknown trType: %i", tr->trTime );
- break;
- }
-}
-
-char *eventnames[] = {
- "EV_NONE",
-
- "EV_FOOTSTEP",
- "EV_FOOTSTEP_METAL",
- "EV_FOOTSPLASH",
- "EV_FOOTWADE",
- "EV_SWIM",
-
- "EV_STEP_4",
- "EV_STEP_8",
- "EV_STEP_12",
- "EV_STEP_16",
-
- "EV_FALL_SHORT",
- "EV_FALL_MEDIUM",
- "EV_FALL_FAR",
-
- "EV_JUMP_PAD", // boing sound at origin", jump sound on player
-
- "EV_JUMP",
- "EV_WATER_TOUCH", // foot touches
- "EV_WATER_LEAVE", // foot leaves
- "EV_WATER_UNDER", // head touches
- "EV_WATER_CLEAR", // head leaves
-
- "EV_ITEM_PICKUP", // normal item pickups are predictable
- "EV_GLOBAL_ITEM_PICKUP", // powerup / team sounds are broadcast to everyone
-
- "EV_NOAMMO",
- "EV_CHANGE_WEAPON",
- "EV_FIRE_WEAPON",
-
- "EV_USE_ITEM0",
- "EV_USE_ITEM1",
- "EV_USE_ITEM2",
- "EV_USE_ITEM3",
- "EV_USE_ITEM4",
- "EV_USE_ITEM5",
- "EV_USE_ITEM6",
- "EV_USE_ITEM7",
- "EV_USE_ITEM8",
- "EV_USE_ITEM9",
- "EV_USE_ITEM10",
- "EV_USE_ITEM11",
- "EV_USE_ITEM12",
- "EV_USE_ITEM13",
- "EV_USE_ITEM14",
- "EV_USE_ITEM15",
-
- "EV_ITEM_RESPAWN",
- "EV_ITEM_POP",
- "EV_PLAYER_TELEPORT_IN",
- "EV_PLAYER_TELEPORT_OUT",
-
- "EV_GRENADE_BOUNCE", // eventParm will be the soundindex
-
- "EV_GENERAL_SOUND",
- "EV_GLOBAL_SOUND", // no attenuation
- "EV_GLOBAL_TEAM_SOUND",
-
- "EV_BULLET_HIT_FLESH",
- "EV_BULLET_HIT_WALL",
-
- "EV_MISSILE_HIT",
- "EV_MISSILE_MISS",
- "EV_MISSILE_MISS_METAL",
- "EV_RAILTRAIL",
- "EV_SHOTGUN",
- "EV_BULLET", // otherEntity is the shooter
-
- "EV_PAIN",
- "EV_DEATH1",
- "EV_DEATH2",
- "EV_DEATH3",
- "EV_OBITUARY",
-
- "EV_POWERUP_QUAD",
- "EV_POWERUP_BATTLESUIT",
- "EV_POWERUP_REGEN",
-
- "EV_GIB_PLAYER", // gib a previously living player
- "EV_SCOREPLUM", // score plum
-
-//#ifdef MISSIONPACK
- "EV_PROXIMITY_MINE_STICK",
- "EV_PROXIMITY_MINE_TRIGGER",
- "EV_KAMIKAZE", // kamikaze explodes
- "EV_OBELISKEXPLODE", // obelisk explodes
- "EV_INVUL_IMPACT", // invulnerability sphere impact
- "EV_JUICED", // invulnerability juiced effect
- "EV_LIGHTNINGBOLT", // lightning bolt bounced of invulnerability sphere
-//#endif
-
- "EV_DEBUG_LINE",
- "EV_STOPLOOPINGSOUND",
- "EV_TAUNT"
-
-};
-
-/*
-===============
-BG_AddPredictableEventToPlayerstate
-
-Handles the sequence numbers
-===============
-*/
-
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-
-void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ) {
-
-#ifdef _DEBUG
- {
- char buf[256];
- trap_Cvar_VariableStringBuffer("showevents", buf, sizeof(buf));
- if ( atof(buf) != 0 ) {
-#ifdef QAGAME
- Com_Printf(" game event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm);
-#else
- Com_Printf("Cgame event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm);
-#endif
- }
- }
-#endif
- ps->events[ps->eventSequence & (MAX_PS_EVENTS-1)] = newEvent;
- ps->eventParms[ps->eventSequence & (MAX_PS_EVENTS-1)] = eventParm;
- ps->eventSequence++;
-}
-
-/*
-========================
-BG_TouchJumpPad
-========================
-*/
-void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad ) {
- vec3_t angles;
- float p;
- int effectNum;
-
- // spectators don't use jump pads
- if ( ps->pm_type != PM_NORMAL ) {
- return;
- }
-
- // flying characters don't hit bounce pads
- if ( ps->powerups[PW_FLIGHT] ) {
- return;
- }
-
- // if we didn't hit this same jumppad the previous frame
- // then don't play the event sound again if we are in a fat trigger
- if ( ps->jumppad_ent != jumppad->number ) {
-
- vectoangles( jumppad->origin2, angles);
- p = fabs( AngleNormalize180( angles[PITCH] ) );
- if( p < 45 ) {
- effectNum = 0;
- } else {
- effectNum = 1;
- }
- BG_AddPredictableEventToPlayerstate( EV_JUMP_PAD, effectNum, ps );
- }
- // remember hitting this jumppad this frame
- ps->jumppad_ent = jumppad->number;
- ps->jumppad_frame = ps->pmove_framecount;
- // give the player the velocity from the jumppad
- VectorCopy( jumppad->origin2, ps->velocity );
-}
-
-/*
-========================
-BG_PlayerStateToEntityState
-
-This is done after each set of usercmd_t on the server,
-and after local prediction on the client
-========================
-*/
-void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ) {
- int i;
-
- if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) {
- s->eType = ET_INVISIBLE;
- } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) {
- s->eType = ET_INVISIBLE;
- } else {
- s->eType = ET_PLAYER;
- }
-
- s->number = ps->clientNum;
-
- s->pos.trType = TR_INTERPOLATE;
- VectorCopy( ps->origin, s->pos.trBase );
- if ( snap ) {
- SnapVector( s->pos.trBase );
- }
- // set the trDelta for flag direction
- VectorCopy( ps->velocity, s->pos.trDelta );
-
- s->apos.trType = TR_INTERPOLATE;
- VectorCopy( ps->viewangles, s->apos.trBase );
- if ( snap ) {
- SnapVector( s->apos.trBase );
- }
-
- s->angles2[YAW] = ps->movementDir;
- s->legsAnim = ps->legsAnim;
- s->torsoAnim = ps->torsoAnim;
- s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number
- // so corpses can also reference the proper config
- s->eFlags = ps->eFlags;
- if ( ps->stats[STAT_HEALTH] <= 0 ) {
- s->eFlags |= EF_DEAD;
- } else {
- s->eFlags &= ~EF_DEAD;
- }
-
- if ( ps->externalEvent ) {
- s->event = ps->externalEvent;
- s->eventParm = ps->externalEventParm;
- } else if ( ps->entityEventSequence < ps->eventSequence ) {
- int seq;
-
- if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) {
- ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS;
- }
- seq = ps->entityEventSequence & (MAX_PS_EVENTS-1);
- s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );
- s->eventParm = ps->eventParms[ seq ];
- ps->entityEventSequence++;
- }
-
- s->weapon = ps->weapon;
- s->groundEntityNum = ps->groundEntityNum;
-
- s->powerups = 0;
- for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
- if ( ps->powerups[ i ] ) {
- s->powerups |= 1 << i;
- }
- }
-
- s->loopSound = ps->loopSound;
- s->generic1 = ps->generic1;
-}
-
-/*
-========================
-BG_PlayerStateToEntityStateExtraPolate
-
-This is done after each set of usercmd_t on the server,
-and after local prediction on the client
-========================
-*/
-void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ) {
- int i;
-
- if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) {
- s->eType = ET_INVISIBLE;
- } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) {
- s->eType = ET_INVISIBLE;
- } else {
- s->eType = ET_PLAYER;
- }
-
- s->number = ps->clientNum;
-
- s->pos.trType = TR_LINEAR_STOP;
- VectorCopy( ps->origin, s->pos.trBase );
- if ( snap ) {
- SnapVector( s->pos.trBase );
- }
- // set the trDelta for flag direction and linear prediction
- VectorCopy( ps->velocity, s->pos.trDelta );
- // set the time for linear prediction
- s->pos.trTime = time;
- // set maximum extra polation time
- s->pos.trDuration = 50; // 1000 / sv_fps (default = 20)
-
- s->apos.trType = TR_INTERPOLATE;
- VectorCopy( ps->viewangles, s->apos.trBase );
- if ( snap ) {
- SnapVector( s->apos.trBase );
- }
-
- s->angles2[YAW] = ps->movementDir;
- s->legsAnim = ps->legsAnim;
- s->torsoAnim = ps->torsoAnim;
- s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number
- // so corpses can also reference the proper config
- s->eFlags = ps->eFlags;
- if ( ps->stats[STAT_HEALTH] <= 0 ) {
- s->eFlags |= EF_DEAD;
- } else {
- s->eFlags &= ~EF_DEAD;
- }
-
- if ( ps->externalEvent ) {
- s->event = ps->externalEvent;
- s->eventParm = ps->externalEventParm;
- } else if ( ps->entityEventSequence < ps->eventSequence ) {
- int seq;
-
- if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) {
- ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS;
- }
- seq = ps->entityEventSequence & (MAX_PS_EVENTS-1);
- s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );
- s->eventParm = ps->eventParms[ seq ];
- ps->entityEventSequence++;
- }
-
- s->weapon = ps->weapon;
- s->groundEntityNum = ps->groundEntityNum;
-
- s->powerups = 0;
- for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
- if ( ps->powerups[ i ] ) {
- s->powerups |= 1 << i;
- }
- }
-
- s->loopSound = ps->loopSound;
- s->generic1 = ps->generic1;
-}
diff --git a/engine/code/game/bg_pmove.c b/engine/code/game/bg_pmove.c
deleted file mode 100644
index f31222a..0000000
--- a/engine/code/game/bg_pmove.c
+++ /dev/null
@@ -1,2069 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// bg_pmove.c -- both games player movement code
-// takes a playerstate and a usercmd as input and returns a modifed playerstate
-
-#include "../qcommon/q_shared.h"
-#include "bg_public.h"
-#include "bg_local.h"
-
-pmove_t *pm;
-pml_t pml;
-
-// movement parameters
-float pm_stopspeed = 100.0f;
-float pm_duckScale = 0.25f;
-float pm_swimScale = 0.50f;
-float pm_wadeScale = 0.70f;
-
-float pm_accelerate = 10.0f;
-float pm_airaccelerate = 1.0f;
-float pm_wateraccelerate = 4.0f;
-float pm_flyaccelerate = 8.0f;
-
-float pm_friction = 6.0f;
-float pm_waterfriction = 1.0f;
-float pm_flightfriction = 3.0f;
-float pm_spectatorfriction = 5.0f;
-
-int c_pmove = 0;
-
-
-/*
-===============
-PM_AddEvent
-
-===============
-*/
-void PM_AddEvent( int newEvent ) {
- BG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps );
-}
-
-/*
-===============
-PM_AddTouchEnt
-===============
-*/
-void PM_AddTouchEnt( int entityNum ) {
- int i;
-
- if ( entityNum == ENTITYNUM_WORLD ) {
- return;
- }
- if ( pm->numtouch == MAXTOUCH ) {
- return;
- }
-
- // see if it is already added
- for ( i = 0 ; i < pm->numtouch ; i++ ) {
- if ( pm->touchents[ i ] == entityNum ) {
- return;
- }
- }
-
- // add it
- pm->touchents[pm->numtouch] = entityNum;
- pm->numtouch++;
-}
-
-/*
-===================
-PM_StartTorsoAnim
-===================
-*/
-static void PM_StartTorsoAnim( int anim ) {
- if ( pm->ps->pm_type >= PM_DEAD ) {
- return;
- }
- pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
- | anim;
-}
-static void PM_StartLegsAnim( int anim ) {
- if ( pm->ps->pm_type >= PM_DEAD ) {
- return;
- }
- if ( pm->ps->legsTimer > 0 ) {
- return; // a high priority animation is running
- }
- pm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
- | anim;
-}
-
-static void PM_ContinueLegsAnim( int anim ) {
- if ( ( pm->ps->legsAnim & ~ANIM_TOGGLEBIT ) == anim ) {
- return;
- }
- if ( pm->ps->legsTimer > 0 ) {
- return; // a high priority animation is running
- }
- PM_StartLegsAnim( anim );
-}
-
-static void PM_ContinueTorsoAnim( int anim ) {
- if ( ( pm->ps->torsoAnim & ~ANIM_TOGGLEBIT ) == anim ) {
- return;
- }
- if ( pm->ps->torsoTimer > 0 ) {
- return; // a high priority animation is running
- }
- PM_StartTorsoAnim( anim );
-}
-
-static void PM_ForceLegsAnim( int anim ) {
- pm->ps->legsTimer = 0;
- PM_StartLegsAnim( anim );
-}
-
-
-/*
-==================
-PM_ClipVelocity
-
-Slide off of the impacting surface
-==================
-*/
-void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) {
- float backoff;
- float change;
- int i;
-
- backoff = DotProduct (in, normal);
-
- if ( backoff < 0 ) {
- backoff *= overbounce;
- } else {
- backoff /= overbounce;
- }
-
- for ( i=0 ; i<3 ; i++ ) {
- change = normal[i]*backoff;
- out[i] = in[i] - change;
- }
-}
-
-
-/*
-==================
-PM_Friction
-
-Handles both ground friction and water friction
-==================
-*/
-static void PM_Friction( void ) {
- vec3_t vec;
- float *vel;
- float speed, newspeed, control;
- float drop;
-
- vel = pm->ps->velocity;
-
- VectorCopy( vel, vec );
- if ( pml.walking ) {
- vec[2] = 0; // ignore slope movement
- }
-
- speed = VectorLength(vec);
- if (speed < 1) {
- vel[0] = 0;
- vel[1] = 0; // allow sinking underwater
- // FIXME: still have z friction underwater?
- return;
- }
-
- drop = 0;
-
- // apply ground friction
- if ( pm->waterlevel <= 1 ) {
- if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) {
- // if getting knocked back, no friction
- if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) {
- control = speed < pm_stopspeed ? pm_stopspeed : speed;
- drop += control*pm_friction*pml.frametime;
- }
- }
- }
-
- // apply water friction even if just wading
- if ( pm->waterlevel ) {
- drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
- }
-
- // apply flying friction
- if ( pm->ps->powerups[PW_FLIGHT]) {
- drop += speed*pm_flightfriction*pml.frametime;
- }
-
- if ( pm->ps->pm_type == PM_SPECTATOR) {
- drop += speed*pm_spectatorfriction*pml.frametime;
- }
-
- // scale the velocity
- newspeed = speed - drop;
- if (newspeed < 0) {
- newspeed = 0;
- }
- newspeed /= speed;
-
- vel[0] = vel[0] * newspeed;
- vel[1] = vel[1] * newspeed;
- vel[2] = vel[2] * newspeed;
-}
-
-
-/*
-==============
-PM_Accelerate
-
-Handles user intended acceleration
-==============
-*/
-static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) {
-#if 1
- // q2 style
- int i;
- float addspeed, accelspeed, currentspeed;
-
- currentspeed = DotProduct (pm->ps->velocity, wishdir);
- addspeed = wishspeed - currentspeed;
- if (addspeed <= 0) {
- return;
- }
- accelspeed = accel*pml.frametime*wishspeed;
- if (accelspeed > addspeed) {
- accelspeed = addspeed;
- }
-
- for (i=0 ; i<3 ; i++) {
- pm->ps->velocity[i] += accelspeed*wishdir[i];
- }
-#else
- // proper way (avoids strafe jump maxspeed bug), but feels bad
- vec3_t wishVelocity;
- vec3_t pushDir;
- float pushLen;
- float canPush;
-
- VectorScale( wishdir, wishspeed, wishVelocity );
- VectorSubtract( wishVelocity, pm->ps->velocity, pushDir );
- pushLen = VectorNormalize( pushDir );
-
- canPush = accel*pml.frametime*wishspeed;
- if (canPush > pushLen) {
- canPush = pushLen;
- }
-
- VectorMA( pm->ps->velocity, canPush, pushDir, pm->ps->velocity );
-#endif
-}
-
-
-
-/*
-============
-PM_CmdScale
-
-Returns the scale factor to apply to cmd movements
-This allows the clients to use axial -127 to 127 values for all directions
-without getting a sqrt(2) distortion in speed.
-============
-*/
-static float PM_CmdScale( usercmd_t *cmd ) {
- int max;
- float total;
- float scale;
-
- max = abs( cmd->forwardmove );
- if ( abs( cmd->rightmove ) > max ) {
- max = abs( cmd->rightmove );
- }
- if ( abs( cmd->upmove ) > max ) {
- max = abs( cmd->upmove );
- }
- if ( !max ) {
- return 0;
- }
-
- total = sqrt( cmd->forwardmove * cmd->forwardmove
- + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove );
- scale = (float)pm->ps->speed * max / ( 127.0 * total );
-
- return scale;
-}
-
-
-/*
-================
-PM_SetMovementDir
-
-Determine the rotation of the legs reletive
-to the facing dir
-================
-*/
-static void PM_SetMovementDir( void ) {
- if ( pm->cmd.forwardmove || pm->cmd.rightmove ) {
- if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove > 0 ) {
- pm->ps->movementDir = 0;
- } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove > 0 ) {
- pm->ps->movementDir = 1;
- } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove == 0 ) {
- pm->ps->movementDir = 2;
- } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove < 0 ) {
- pm->ps->movementDir = 3;
- } else if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove < 0 ) {
- pm->ps->movementDir = 4;
- } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove < 0 ) {
- pm->ps->movementDir = 5;
- } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove == 0 ) {
- pm->ps->movementDir = 6;
- } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove > 0 ) {
- pm->ps->movementDir = 7;
- }
- } else {
- // if they aren't actively going directly sideways,
- // change the animation to the diagonal so they
- // don't stop too crooked
- if ( pm->ps->movementDir == 2 ) {
- pm->ps->movementDir = 1;
- } else if ( pm->ps->movementDir == 6 ) {
- pm->ps->movementDir = 7;
- }
- }
-}
-
-
-/*
-=============
-PM_CheckJump
-=============
-*/
-static qboolean PM_CheckJump( void ) {
- if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
- return qfalse; // don't allow jump until all buttons are up
- }
-
- if ( pm->cmd.upmove < 10 ) {
- // not holding jump
- return qfalse;
- }
-
- // must wait for jump to be released
- if ( pm->ps->pm_flags & PMF_JUMP_HELD ) {
- // clear upmove so cmdscale doesn't lower running speed
- pm->cmd.upmove = 0;
- return qfalse;
- }
-
- pml.groundPlane = qfalse; // jumping away
- pml.walking = qfalse;
- pm->ps->pm_flags |= PMF_JUMP_HELD;
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pm->ps->velocity[2] = JUMP_VELOCITY;
- PM_AddEvent( EV_JUMP );
-
- if ( pm->cmd.forwardmove >= 0 ) {
- PM_ForceLegsAnim( LEGS_JUMP );
- pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
- } else {
- PM_ForceLegsAnim( LEGS_JUMPB );
- pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
- }
-
- return qtrue;
-}
-
-/*
-=============
-PM_CheckWaterJump
-=============
-*/
-static qboolean PM_CheckWaterJump( void ) {
- vec3_t spot;
- int cont;
- vec3_t flatforward;
-
- if (pm->ps->pm_time) {
- return qfalse;
- }
-
- // check for water jump
- if ( pm->waterlevel != 2 ) {
- return qfalse;
- }
-
- flatforward[0] = pml.forward[0];
- flatforward[1] = pml.forward[1];
- flatforward[2] = 0;
- VectorNormalize (flatforward);
-
- VectorMA (pm->ps->origin, 30, flatforward, spot);
- spot[2] += 4;
- cont = pm->pointcontents (spot, pm->ps->clientNum );
- if ( !(cont & CONTENTS_SOLID) ) {
- return qfalse;
- }
-
- spot[2] += 16;
- cont = pm->pointcontents (spot, pm->ps->clientNum );
- if ( cont ) {
- return qfalse;
- }
-
- // jump out of water
- VectorScale (pml.forward, 200, pm->ps->velocity);
- pm->ps->velocity[2] = 350;
-
- pm->ps->pm_flags |= PMF_TIME_WATERJUMP;
- pm->ps->pm_time = 2000;
-
- return qtrue;
-}
-
-//============================================================================
-
-
-/*
-===================
-PM_WaterJumpMove
-
-Flying out of the water
-===================
-*/
-static void PM_WaterJumpMove( void ) {
- // waterjump has no control, but falls
-
- PM_StepSlideMove( qtrue );
-
- pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
- if (pm->ps->velocity[2] < 0) {
- // cancel as soon as we are falling down again
- pm->ps->pm_flags &= ~PMF_ALL_TIMES;
- pm->ps->pm_time = 0;
- }
-}
-
-/*
-===================
-PM_WaterMove
-
-===================
-*/
-static void PM_WaterMove( void ) {
- int i;
- vec3_t wishvel;
- float wishspeed;
- vec3_t wishdir;
- float scale;
- float vel;
-
- if ( PM_CheckWaterJump() ) {
- PM_WaterJumpMove();
- return;
- }
-#if 0
- // jump = head for surface
- if ( pm->cmd.upmove >= 10 ) {
- if (pm->ps->velocity[2] > -300) {
- if ( pm->watertype == CONTENTS_WATER ) {
- pm->ps->velocity[2] = 100;
- } else if (pm->watertype == CONTENTS_SLIME) {
- pm->ps->velocity[2] = 80;
- } else {
- pm->ps->velocity[2] = 50;
- }
- }
- }
-#endif
- PM_Friction ();
-
- scale = PM_CmdScale( &pm->cmd );
- //
- // user intentions
- //
- if ( !scale ) {
- wishvel[0] = 0;
- wishvel[1] = 0;
- wishvel[2] = -60; // sink towards bottom
- } else {
- for (i=0 ; i<3 ; i++)
- wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;
-
- wishvel[2] += scale * pm->cmd.upmove;
- }
-
- VectorCopy (wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
-
- if ( wishspeed > pm->ps->speed * pm_swimScale ) {
- wishspeed = pm->ps->speed * pm_swimScale;
- }
-
- PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);
-
- // make sure we can go up slopes easily under water
- if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) {
- vel = VectorLength(pm->ps->velocity);
- // slide along the ground plane
- PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
-
- VectorNormalize(pm->ps->velocity);
- VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
- }
-
- PM_SlideMove( qfalse );
-}
-
-#ifdef MISSIONPACK
-/*
-===================
-PM_InvulnerabilityMove
-
-Only with the invulnerability powerup
-===================
-*/
-static void PM_InvulnerabilityMove( void ) {
- pm->cmd.forwardmove = 0;
- pm->cmd.rightmove = 0;
- pm->cmd.upmove = 0;
- VectorClear(pm->ps->velocity);
-}
-#endif
-
-/*
-===================
-PM_FlyMove
-
-Only with the flight powerup
-===================
-*/
-static void PM_FlyMove( void ) {
- int i;
- vec3_t wishvel;
- float wishspeed;
- vec3_t wishdir;
- float scale;
-
- // normal slowdown
- PM_Friction ();
-
- scale = PM_CmdScale( &pm->cmd );
- //
- // user intentions
- //
- if ( !scale ) {
- wishvel[0] = 0;
- wishvel[1] = 0;
- wishvel[2] = 0;
- } else {
- for (i=0 ; i<3 ; i++) {
- wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;
- }
-
- wishvel[2] += scale * pm->cmd.upmove;
- }
-
- VectorCopy (wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
-
- PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate);
-
- PM_StepSlideMove( qfalse );
-}
-
-
-/*
-===================
-PM_AirMove
-
-===================
-*/
-static void PM_AirMove( void ) {
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- float scale;
- usercmd_t cmd;
-
- PM_Friction();
-
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.rightmove;
-
- cmd = pm->cmd;
- scale = PM_CmdScale( &cmd );
-
- // set the movementDir so clients can rotate the legs for strafing
- PM_SetMovementDir();
-
- // project moves down to flat plane
- pml.forward[2] = 0;
- pml.right[2] = 0;
- VectorNormalize (pml.forward);
- VectorNormalize (pml.right);
-
- for ( i = 0 ; i < 2 ; i++ ) {
- wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
- }
- wishvel[2] = 0;
-
- VectorCopy (wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
- wishspeed *= scale;
-
- // not on ground, so little effect on velocity
- PM_Accelerate (wishdir, wishspeed, pm_airaccelerate);
-
- // we may have a ground plane that is very steep, even
- // though we don't have a groundentity
- // slide along the steep plane
- if ( pml.groundPlane ) {
- PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
- }
-
-#if 0
- //ZOID: If we are on the grapple, try stair-stepping
- //this allows a player to use the grapple to pull himself
- //over a ledge
- if (pm->ps->pm_flags & PMF_GRAPPLE_PULL)
- PM_StepSlideMove ( qtrue );
- else
- PM_SlideMove ( qtrue );
-#endif
-
- PM_StepSlideMove ( qtrue );
-}
-
-/*
-===================
-PM_GrappleMove
-
-===================
-*/
-static void PM_GrappleMove( void ) {
- vec3_t vel, v;
- float vlen;
-
- VectorScale(pml.forward, -16, v);
- VectorAdd(pm->ps->grapplePoint, v, v);
- VectorSubtract(v, pm->ps->origin, vel);
- vlen = VectorLength(vel);
- VectorNormalize( vel );
-
- if (vlen <= 100)
- VectorScale(vel, 10 * vlen, vel);
- else
- VectorScale(vel, 800, vel);
-
- VectorCopy(vel, pm->ps->velocity);
-
- pml.groundPlane = qfalse;
-}
-
-/*
-===================
-PM_WalkMove
-
-===================
-*/
-static void PM_WalkMove( void ) {
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- float scale;
- usercmd_t cmd;
- float accelerate;
- float vel;
-
- if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) {
- // begin swimming
- PM_WaterMove();
- return;
- }
-
-
- if ( PM_CheckJump () ) {
- // jumped away
- if ( pm->waterlevel > 1 ) {
- PM_WaterMove();
- } else {
- PM_AirMove();
- }
- return;
- }
-
- PM_Friction ();
-
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.rightmove;
-
- cmd = pm->cmd;
- scale = PM_CmdScale( &cmd );
-
- // set the movementDir so clients can rotate the legs for strafing
- PM_SetMovementDir();
-
- // project moves down to flat plane
- pml.forward[2] = 0;
- pml.right[2] = 0;
-
- // project the forward and right directions onto the ground plane
- PM_ClipVelocity (pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP );
- PM_ClipVelocity (pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP );
- //
- VectorNormalize (pml.forward);
- VectorNormalize (pml.right);
-
- for ( i = 0 ; i < 3 ; i++ ) {
- wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
- }
- // when going up or down slopes the wish velocity should Not be zero
-// wishvel[2] = 0;
-
- VectorCopy (wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
- wishspeed *= scale;
-
- // clamp the speed lower if ducking
- if ( pm->ps->pm_flags & PMF_DUCKED ) {
- if ( wishspeed > pm->ps->speed * pm_duckScale ) {
- wishspeed = pm->ps->speed * pm_duckScale;
- }
- }
-
- // clamp the speed lower if wading or walking on the bottom
- if ( pm->waterlevel ) {
- float waterScale;
-
- waterScale = pm->waterlevel / 3.0;
- waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale;
- if ( wishspeed > pm->ps->speed * waterScale ) {
- wishspeed = pm->ps->speed * waterScale;
- }
- }
-
- // when a player gets hit, they temporarily lose
- // full control, which allows them to be moved a bit
- if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
- accelerate = pm_airaccelerate;
- } else {
- accelerate = pm_accelerate;
- }
-
- PM_Accelerate (wishdir, wishspeed, accelerate);
-
- //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]);
- //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity));
-
- if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
- pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
- } else {
- // don't reset the z velocity for slopes
-// pm->ps->velocity[2] = 0;
- }
-
- vel = VectorLength(pm->ps->velocity);
-
- // slide along the ground plane
- PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
-
- // don't decrease velocity when going up or down a slope
- VectorNormalize(pm->ps->velocity);
- VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
-
- // don't do anything if standing still
- if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) {
- return;
- }
-
- PM_StepSlideMove( qfalse );
-
- //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity));
-
-}
-
-
-/*
-==============
-PM_DeadMove
-==============
-*/
-static void PM_DeadMove( void ) {
- float forward;
-
- if ( !pml.walking ) {
- return;
- }
-
- // extra friction
-
- forward = VectorLength (pm->ps->velocity);
- forward -= 20;
- if ( forward <= 0 ) {
- VectorClear (pm->ps->velocity);
- } else {
- VectorNormalize (pm->ps->velocity);
- VectorScale (pm->ps->velocity, forward, pm->ps->velocity);
- }
-}
-
-
-/*
-===============
-PM_NoclipMove
-===============
-*/
-static void PM_NoclipMove( void ) {
- float speed, drop, friction, control, newspeed;
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- float scale;
-
- pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
-
- // friction
-
- speed = VectorLength (pm->ps->velocity);
- if (speed < 1)
- {
- VectorCopy (vec3_origin, pm->ps->velocity);
- }
- else
- {
- drop = 0;
-
- friction = pm_friction*1.5; // extra friction
- control = speed < pm_stopspeed ? pm_stopspeed : speed;
- drop += control*friction*pml.frametime;
-
- // scale the velocity
- newspeed = speed - drop;
- if (newspeed < 0)
- newspeed = 0;
- newspeed /= speed;
-
- VectorScale (pm->ps->velocity, newspeed, pm->ps->velocity);
- }
-
- // accelerate
- scale = PM_CmdScale( &pm->cmd );
-
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.rightmove;
-
- for (i=0 ; i<3 ; i++)
- wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
- wishvel[2] += pm->cmd.upmove;
-
- VectorCopy (wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
- wishspeed *= scale;
-
- PM_Accelerate( wishdir, wishspeed, pm_accelerate );
-
- // move
- VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin);
-}
-
-//============================================================================
-
-/*
-================
-PM_FootstepForSurface
-
-Returns an event number apropriate for the groundsurface
-================
-*/
-static int PM_FootstepForSurface( void ) {
- if ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) {
- return 0;
- }
- if ( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) {
- return EV_FOOTSTEP_METAL;
- }
- return EV_FOOTSTEP;
-}
-
-
-/*
-=================
-PM_CrashLand
-
-Check for hard landings that generate sound events
-=================
-*/
-static void PM_CrashLand( void ) {
- float delta;
- float dist;
- float vel, acc;
- float t;
- float a, b, c, den;
-
- // decide which landing animation to use
- if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) {
- PM_ForceLegsAnim( LEGS_LANDB );
- } else {
- PM_ForceLegsAnim( LEGS_LAND );
- }
-
- pm->ps->legsTimer = TIMER_LAND;
-
- // calculate the exact velocity on landing
- dist = pm->ps->origin[2] - pml.previous_origin[2];
- vel = pml.previous_velocity[2];
- acc = -pm->ps->gravity;
-
- a = acc / 2;
- b = vel;
- c = -dist;
-
- den = b * b - 4 * a * c;
- if ( den < 0 ) {
- return;
- }
- t = (-b - sqrt( den ) ) / ( 2 * a );
-
- delta = vel + t * acc;
- delta = delta*delta * 0.0001;
-
- // ducking while falling doubles damage
- if ( pm->ps->pm_flags & PMF_DUCKED ) {
- delta *= 2;
- }
-
- // never take falling damage if completely underwater
- if ( pm->waterlevel == 3 ) {
- return;
- }
-
- // reduce falling damage if there is standing water
- if ( pm->waterlevel == 2 ) {
- delta *= 0.25;
- }
- if ( pm->waterlevel == 1 ) {
- delta *= 0.5;
- }
-
- if ( delta < 1 ) {
- return;
- }
-
- // create a local entity event to play the sound
-
- // SURF_NODAMAGE is used for bounce pads where you don't ever
- // want to take damage or play a crunch sound
- if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) {
- if ( delta > 60 ) {
- PM_AddEvent( EV_FALL_FAR );
- } else if ( delta > 40 ) {
- // this is a pain grunt, so don't play it if dead
- if ( pm->ps->stats[STAT_HEALTH] > 0 ) {
- PM_AddEvent( EV_FALL_MEDIUM );
- }
- } else if ( delta > 7 ) {
- PM_AddEvent( EV_FALL_SHORT );
- } else {
- PM_AddEvent( PM_FootstepForSurface() );
- }
- }
-
- // start footstep cycle over
- pm->ps->bobCycle = 0;
-}
-
-/*
-=============
-PM_CheckStuck
-=============
-*/
-/*
-void PM_CheckStuck(void) {
- trace_t trace;
-
- pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask);
- if (trace.allsolid) {
- //int shit = qtrue;
- }
-}
-*/
-
-/*
-=============
-PM_CorrectAllSolid
-=============
-*/
-static int PM_CorrectAllSolid( trace_t *trace ) {
- int i, j, k;
- vec3_t point;
-
- if ( pm->debugLevel ) {
- Com_Printf("%i:allsolid\n", c_pmove);
- }
-
- // jitter around
- for (i = -1; i <= 1; i++) {
- for (j = -1; j <= 1; j++) {
- for (k = -1; k <= 1; k++) {
- VectorCopy(pm->ps->origin, point);
- point[0] += (float) i;
- point[1] += (float) j;
- point[2] += (float) k;
- pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
- if ( !trace->allsolid ) {
- point[0] = pm->ps->origin[0];
- point[1] = pm->ps->origin[1];
- point[2] = pm->ps->origin[2] - 0.25;
-
- pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
- pml.groundTrace = *trace;
- return qtrue;
- }
- }
- }
- }
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
-
- return qfalse;
-}
-
-
-/*
-=============
-PM_GroundTraceMissed
-
-The ground trace didn't hit a surface, so we are in freefall
-=============
-*/
-static void PM_GroundTraceMissed( void ) {
- trace_t trace;
- vec3_t point;
-
- if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) {
- // we just transitioned into freefall
- if ( pm->debugLevel ) {
- Com_Printf("%i:lift\n", c_pmove);
- }
-
- // if they aren't in a jumping animation and the ground is a ways away, force into it
- // if we didn't do the trace, the player would be backflipping down staircases
- VectorCopy( pm->ps->origin, point );
- point[2] -= 64;
-
- pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
- if ( trace.fraction == 1.0 ) {
- if ( pm->cmd.forwardmove >= 0 ) {
- PM_ForceLegsAnim( LEGS_JUMP );
- pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
- } else {
- PM_ForceLegsAnim( LEGS_JUMPB );
- pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
- }
- }
- }
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
-}
-
-
-/*
-=============
-PM_GroundTrace
-=============
-*/
-static void PM_GroundTrace( void ) {
- vec3_t point;
- trace_t trace;
-
- point[0] = pm->ps->origin[0];
- point[1] = pm->ps->origin[1];
- point[2] = pm->ps->origin[2] - 0.25;
-
- pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
- pml.groundTrace = trace;
-
- // do something corrective if the trace starts in a solid...
- if ( trace.allsolid ) {
- if ( !PM_CorrectAllSolid(&trace) )
- return;
- }
-
- // if the trace didn't hit anything, we are in free fall
- if ( trace.fraction == 1.0 ) {
- PM_GroundTraceMissed();
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
- return;
- }
-
- // check if getting thrown off the ground
- if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) {
- if ( pm->debugLevel ) {
- Com_Printf("%i:kickoff\n", c_pmove);
- }
- // go into jump animation
- if ( pm->cmd.forwardmove >= 0 ) {
- PM_ForceLegsAnim( LEGS_JUMP );
- pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
- } else {
- PM_ForceLegsAnim( LEGS_JUMPB );
- pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
- }
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
- return;
- }
-
- // slopes that are too steep will not be considered onground
- if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) {
- if ( pm->debugLevel ) {
- Com_Printf("%i:steep\n", c_pmove);
- }
- // FIXME: if they can't slide down the slope, let them
- // walk (sharp crevices)
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pml.groundPlane = qtrue;
- pml.walking = qfalse;
- return;
- }
-
- pml.groundPlane = qtrue;
- pml.walking = qtrue;
-
- // hitting solid ground will end a waterjump
- if (pm->ps->pm_flags & PMF_TIME_WATERJUMP)
- {
- pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND);
- pm->ps->pm_time = 0;
- }
-
- if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
- // just hit the ground
- if ( pm->debugLevel ) {
- Com_Printf("%i:Land\n", c_pmove);
- }
-
- PM_CrashLand();
-
- // don't do landing time if we were just going down a slope
- if ( pml.previous_velocity[2] < -200 ) {
- // don't allow another jump for a little while
- pm->ps->pm_flags |= PMF_TIME_LAND;
- pm->ps->pm_time = 250;
- }
- }
-
- pm->ps->groundEntityNum = trace.entityNum;
-
- // don't reset the z velocity for slopes
-// pm->ps->velocity[2] = 0;
-
- PM_AddTouchEnt( trace.entityNum );
-}
-
-
-/*
-=============
-PM_SetWaterLevel FIXME: avoid this twice? certainly if not moving
-=============
-*/
-static void PM_SetWaterLevel( void ) {
- vec3_t point;
- int cont;
- int sample1;
- int sample2;
-
- //
- // get waterlevel, accounting for ducking
- //
- pm->waterlevel = 0;
- pm->watertype = 0;
-
- point[0] = pm->ps->origin[0];
- point[1] = pm->ps->origin[1];
- point[2] = pm->ps->origin[2] + MINS_Z + 1;
- cont = pm->pointcontents( point, pm->ps->clientNum );
-
- if ( cont & MASK_WATER ) {
- sample2 = pm->ps->viewheight - MINS_Z;
- sample1 = sample2 / 2;
-
- pm->watertype = cont;
- pm->waterlevel = 1;
- point[2] = pm->ps->origin[2] + MINS_Z + sample1;
- cont = pm->pointcontents (point, pm->ps->clientNum );
- if ( cont & MASK_WATER ) {
- pm->waterlevel = 2;
- point[2] = pm->ps->origin[2] + MINS_Z + sample2;
- cont = pm->pointcontents (point, pm->ps->clientNum );
- if ( cont & MASK_WATER ){
- pm->waterlevel = 3;
- }
- }
- }
-
-}
-
-/*
-==============
-PM_CheckDuck
-
-Sets mins, maxs, and pm->ps->viewheight
-==============
-*/
-static void PM_CheckDuck (void)
-{
- trace_t trace;
-
- if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
- if ( pm->ps->pm_flags & PMF_INVULEXPAND ) {
- // invulnerability sphere has a 42 units radius
- VectorSet( pm->mins, -42, -42, -42 );
- VectorSet( pm->maxs, 42, 42, 42 );
- }
- else {
- VectorSet( pm->mins, -15, -15, MINS_Z );
- VectorSet( pm->maxs, 15, 15, 16 );
- }
- pm->ps->pm_flags |= PMF_DUCKED;
- pm->ps->viewheight = CROUCH_VIEWHEIGHT;
- return;
- }
- pm->ps->pm_flags &= ~PMF_INVULEXPAND;
-
- pm->mins[0] = -15;
- pm->mins[1] = -15;
-
- pm->maxs[0] = 15;
- pm->maxs[1] = 15;
-
- pm->mins[2] = MINS_Z;
-
- if (pm->ps->pm_type == PM_DEAD)
- {
- pm->maxs[2] = -8;
- pm->ps->viewheight = DEAD_VIEWHEIGHT;
- return;
- }
-
- if (pm->cmd.upmove < 0)
- { // duck
- pm->ps->pm_flags |= PMF_DUCKED;
- }
- else
- { // stand up if possible
- if (pm->ps->pm_flags & PMF_DUCKED)
- {
- // try to stand up
- pm->maxs[2] = 32;
- pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask );
- if (!trace.allsolid)
- pm->ps->pm_flags &= ~PMF_DUCKED;
- }
- }
-
- if (pm->ps->pm_flags & PMF_DUCKED)
- {
- pm->maxs[2] = 16;
- pm->ps->viewheight = CROUCH_VIEWHEIGHT;
- }
- else
- {
- pm->maxs[2] = 32;
- pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
- }
-}
-
-
-
-//===================================================================
-
-
-/*
-===============
-PM_Footsteps
-===============
-*/
-static void PM_Footsteps( void ) {
- float bobmove;
- int old;
- qboolean footstep;
-
- //
- // calculate speed and cycle to be used for
- // all cyclic walking effects
- //
- pm->xyspeed = sqrt( pm->ps->velocity[0] * pm->ps->velocity[0]
- + pm->ps->velocity[1] * pm->ps->velocity[1] );
-
- if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
-
- if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
- PM_ContinueLegsAnim( LEGS_IDLECR );
- }
- // airborne leaves position in cycle intact, but doesn't advance
- if ( pm->waterlevel > 1 ) {
- PM_ContinueLegsAnim( LEGS_SWIM );
- }
- return;
- }
-
- // if not trying to move
- if ( !pm->cmd.forwardmove && !pm->cmd.rightmove ) {
- if ( pm->xyspeed < 5 ) {
- pm->ps->bobCycle = 0; // start at beginning of cycle again
- if ( pm->ps->pm_flags & PMF_DUCKED ) {
- PM_ContinueLegsAnim( LEGS_IDLECR );
- } else {
- PM_ContinueLegsAnim( LEGS_IDLE );
- }
- }
- return;
- }
-
-
- footstep = qfalse;
-
- if ( pm->ps->pm_flags & PMF_DUCKED ) {
- bobmove = 0.5; // ducked characters bob much faster
- if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
- PM_ContinueLegsAnim( LEGS_BACKCR );
- }
- else {
- PM_ContinueLegsAnim( LEGS_WALKCR );
- }
- // ducked characters never play footsteps
- /*
- } else if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
- if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
- bobmove = 0.4; // faster speeds bob faster
- footstep = qtrue;
- } else {
- bobmove = 0.3;
- }
- PM_ContinueLegsAnim( LEGS_BACK );
- */
- } else {
- if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
- bobmove = 0.4f; // faster speeds bob faster
- if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
- PM_ContinueLegsAnim( LEGS_BACK );
- }
- else {
- PM_ContinueLegsAnim( LEGS_RUN );
- }
- footstep = qtrue;
- } else {
- bobmove = 0.3f; // walking bobs slow
- if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
- PM_ContinueLegsAnim( LEGS_BACKWALK );
- }
- else {
- PM_ContinueLegsAnim( LEGS_WALK );
- }
- }
- }
-
- // check for footstep / splash sounds
- old = pm->ps->bobCycle;
- pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255;
-
- // if we just crossed a cycle boundary, play an apropriate footstep event
- if ( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) {
- if ( pm->waterlevel == 0 ) {
- // on ground will only play sounds if running
- if ( footstep && !pm->noFootsteps ) {
- PM_AddEvent( PM_FootstepForSurface() );
- }
- } else if ( pm->waterlevel == 1 ) {
- // splashing
- PM_AddEvent( EV_FOOTSPLASH );
- } else if ( pm->waterlevel == 2 ) {
- // wading / swimming at surface
- PM_AddEvent( EV_SWIM );
- } else if ( pm->waterlevel == 3 ) {
- // no sound when completely underwater
-
- }
- }
-}
-
-/*
-==============
-PM_WaterEvents
-
-Generate sound events for entering and leaving water
-==============
-*/
-static void PM_WaterEvents( void ) { // FIXME?
- //
- // if just entered a water volume, play a sound
- //
- if (!pml.previous_waterlevel && pm->waterlevel) {
- PM_AddEvent( EV_WATER_TOUCH );
- }
-
- //
- // if just completely exited a water volume, play a sound
- //
- if (pml.previous_waterlevel && !pm->waterlevel) {
- PM_AddEvent( EV_WATER_LEAVE );
- }
-
- //
- // check for head just going under water
- //
- if (pml.previous_waterlevel != 3 && pm->waterlevel == 3) {
- PM_AddEvent( EV_WATER_UNDER );
- }
-
- //
- // check for head just coming out of water
- //
- if (pml.previous_waterlevel == 3 && pm->waterlevel != 3) {
- PM_AddEvent( EV_WATER_CLEAR );
- }
-}
-
-
-/*
-===============
-PM_BeginWeaponChange
-===============
-*/
-static void PM_BeginWeaponChange( int weapon ) {
- if ( weapon <= WP_NONE || weapon >= WP_NUM_WEAPONS ) {
- return;
- }
-
- if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
- return;
- }
-
- if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
- return;
- }
-
- PM_AddEvent( EV_CHANGE_WEAPON );
- pm->ps->weaponstate = WEAPON_DROPPING;
- pm->ps->weaponTime += 200;
- PM_StartTorsoAnim( TORSO_DROP );
-}
-
-
-/*
-===============
-PM_FinishWeaponChange
-===============
-*/
-static void PM_FinishWeaponChange( void ) {
- int weapon;
-
- weapon = pm->cmd.weapon;
- if ( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) {
- weapon = WP_NONE;
- }
-
- if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
- weapon = WP_NONE;
- }
-
- pm->ps->weapon = weapon;
- pm->ps->weaponstate = WEAPON_RAISING;
- pm->ps->weaponTime += 250;
- PM_StartTorsoAnim( TORSO_RAISE );
-}
-
-
-/*
-==============
-PM_TorsoAnimation
-
-==============
-*/
-static void PM_TorsoAnimation( void ) {
- if ( pm->ps->weaponstate == WEAPON_READY ) {
- if ( pm->ps->weapon == WP_GAUNTLET ) {
- PM_ContinueTorsoAnim( TORSO_STAND2 );
- } else {
- PM_ContinueTorsoAnim( TORSO_STAND );
- }
- return;
- }
-}
-
-
-/*
-==============
-PM_Weapon
-
-Generates weapon events and modifes the weapon counter
-==============
-*/
-static void PM_Weapon( void ) {
- int addTime;
-
- // don't allow attack until all buttons are up
- if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
- return;
- }
-
- // ignore if spectator
- if ( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
- return;
- }
-
- // check for dead player
- if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
- pm->ps->weapon = WP_NONE;
- return;
- }
-
- // check for item using
- if ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) {
- if ( ! ( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) {
- if ( bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_MEDKIT
- && pm->ps->stats[STAT_HEALTH] >= (pm->ps->stats[STAT_MAX_HEALTH] + 25) ) {
- // don't use medkit if at max health
- } else {
- pm->ps->pm_flags |= PMF_USE_ITEM_HELD;
- PM_AddEvent( EV_USE_ITEM0 + bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag );
- pm->ps->stats[STAT_HOLDABLE_ITEM] = 0;
- }
- return;
- }
- } else {
- pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD;
- }
-
-
- // make weapon function
- if ( pm->ps->weaponTime > 0 ) {
- pm->ps->weaponTime -= pml.msec;
- }
-
- // check for weapon change
- // can't change if weapon is firing, but can change
- // again if lowering or raising
- if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) {
- if ( pm->ps->weapon != pm->cmd.weapon ) {
- PM_BeginWeaponChange( pm->cmd.weapon );
- }
- }
-
- if ( pm->ps->weaponTime > 0 ) {
- return;
- }
-
- // change weapon if time
- if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
- PM_FinishWeaponChange();
- return;
- }
-
- if ( pm->ps->weaponstate == WEAPON_RAISING ) {
- pm->ps->weaponstate = WEAPON_READY;
- if ( pm->ps->weapon == WP_GAUNTLET ) {
- PM_StartTorsoAnim( TORSO_STAND2 );
- } else {
- PM_StartTorsoAnim( TORSO_STAND );
- }
- return;
- }
-
- // check for fire
- if ( ! (pm->cmd.buttons & BUTTON_ATTACK) ) {
- pm->ps->weaponTime = 0;
- pm->ps->weaponstate = WEAPON_READY;
- return;
- }
-
- // start the animation even if out of ammo
- if ( pm->ps->weapon == WP_GAUNTLET ) {
- // the guantlet only "fires" when it actually hits something
- if ( !pm->gauntletHit ) {
- pm->ps->weaponTime = 0;
- pm->ps->weaponstate = WEAPON_READY;
- return;
- }
- PM_StartTorsoAnim( TORSO_ATTACK2 );
- } else {
- PM_StartTorsoAnim( TORSO_ATTACK );
- }
-
- pm->ps->weaponstate = WEAPON_FIRING;
-
- // check for out of ammo
- if ( ! pm->ps->ammo[ pm->ps->weapon ] ) {
- PM_AddEvent( EV_NOAMMO );
- pm->ps->weaponTime += 500;
- return;
- }
-
- // take an ammo away if not infinite
- if ( pm->ps->ammo[ pm->ps->weapon ] != -1 ) {
- pm->ps->ammo[ pm->ps->weapon ]--;
- }
-
- // fire weapon
- PM_AddEvent( EV_FIRE_WEAPON );
-
- switch( pm->ps->weapon ) {
- default:
- case WP_GAUNTLET:
- addTime = 400;
- break;
- case WP_LIGHTNING:
- addTime = 50;
- break;
- case WP_SHOTGUN:
- addTime = 1000;
- break;
- case WP_MACHINEGUN:
- addTime = 100;
- break;
- case WP_GRENADE_LAUNCHER:
- addTime = 800;
- break;
- case WP_ROCKET_LAUNCHER:
- addTime = 800;
- break;
- case WP_PLASMAGUN:
- addTime = 100;
- break;
- case WP_RAILGUN:
- addTime = 1500;
- break;
- case WP_BFG:
- addTime = 200;
- break;
- case WP_GRAPPLING_HOOK:
- addTime = 400;
- break;
-#ifdef MISSIONPACK
- case WP_NAILGUN:
- addTime = 1000;
- break;
- case WP_PROX_LAUNCHER:
- addTime = 800;
- break;
- case WP_CHAINGUN:
- addTime = 30;
- break;
-#endif
- }
-
-#ifdef MISSIONPACK
- if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
- addTime /= 1.5;
- }
- else
- if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
- addTime /= 1.3;
- }
- else
-#endif
- if ( pm->ps->powerups[PW_HASTE] ) {
- addTime /= 1.3;
- }
-
- pm->ps->weaponTime += addTime;
-}
-
-/*
-================
-PM_Animate
-================
-*/
-
-static void PM_Animate( void ) {
- if ( pm->cmd.buttons & BUTTON_GESTURE ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_GESTURE );
- pm->ps->torsoTimer = TIMER_GESTURE;
- PM_AddEvent( EV_TAUNT );
- }
-#ifdef MISSIONPACK
- } else if ( pm->cmd.buttons & BUTTON_GETFLAG ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_GETFLAG );
- pm->ps->torsoTimer = 600; //TIMER_GESTURE;
- }
- } else if ( pm->cmd.buttons & BUTTON_GUARDBASE ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_GUARDBASE );
- pm->ps->torsoTimer = 600; //TIMER_GESTURE;
- }
- } else if ( pm->cmd.buttons & BUTTON_PATROL ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_PATROL );
- pm->ps->torsoTimer = 600; //TIMER_GESTURE;
- }
- } else if ( pm->cmd.buttons & BUTTON_FOLLOWME ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_FOLLOWME );
- pm->ps->torsoTimer = 600; //TIMER_GESTURE;
- }
- } else if ( pm->cmd.buttons & BUTTON_AFFIRMATIVE ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_AFFIRMATIVE);
- pm->ps->torsoTimer = 600; //TIMER_GESTURE;
- }
- } else if ( pm->cmd.buttons & BUTTON_NEGATIVE ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_NEGATIVE );
- pm->ps->torsoTimer = 600; //TIMER_GESTURE;
- }
-#endif
- }
-}
-
-
-/*
-================
-PM_DropTimers
-================
-*/
-static void PM_DropTimers( void ) {
- // drop misc timing counter
- if ( pm->ps->pm_time ) {
- if ( pml.msec >= pm->ps->pm_time ) {
- pm->ps->pm_flags &= ~PMF_ALL_TIMES;
- pm->ps->pm_time = 0;
- } else {
- pm->ps->pm_time -= pml.msec;
- }
- }
-
- // drop animation counter
- if ( pm->ps->legsTimer > 0 ) {
- pm->ps->legsTimer -= pml.msec;
- if ( pm->ps->legsTimer < 0 ) {
- pm->ps->legsTimer = 0;
- }
- }
-
- if ( pm->ps->torsoTimer > 0 ) {
- pm->ps->torsoTimer -= pml.msec;
- if ( pm->ps->torsoTimer < 0 ) {
- pm->ps->torsoTimer = 0;
- }
- }
-}
-
-/*
-================
-PM_UpdateViewAngles
-
-This can be used as another entry point when only the viewangles
-are being updated isntead of a full move
-================
-*/
-void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) {
- short temp;
- int i;
-
- if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) {
- return; // no view changes at all
- }
-
- if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) {
- return; // no view changes at all
- }
-
- // circularly clamp the angles with deltas
- for (i=0 ; i<3 ; i++) {
- temp = cmd->angles[i] + ps->delta_angles[i];
- if ( i == PITCH ) {
- // don't let the player look up or down more than 90 degrees
- if ( temp > 16000 ) {
- ps->delta_angles[i] = 16000 - cmd->angles[i];
- temp = 16000;
- } else if ( temp < -16000 ) {
- ps->delta_angles[i] = -16000 - cmd->angles[i];
- temp = -16000;
- }
- }
- ps->viewangles[i] = SHORT2ANGLE(temp);
- }
-
-}
-
-
-/*
-================
-PmoveSingle
-
-================
-*/
-void trap_SnapVector( float *v );
-
-void PmoveSingle (pmove_t *pmove) {
- pm = pmove;
-
- // this counter lets us debug movement problems with a journal
- // by setting a conditional breakpoint fot the previous frame
- c_pmove++;
-
- // clear results
- pm->numtouch = 0;
- pm->watertype = 0;
- pm->waterlevel = 0;
-
- if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
- pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies
- }
-
- // make sure walking button is clear if they are running, to avoid
- // proxy no-footsteps cheats
- if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) {
- pm->cmd.buttons &= ~BUTTON_WALKING;
- }
-
- // set the talk balloon flag
- if ( pm->cmd.buttons & BUTTON_TALK ) {
- pm->ps->eFlags |= EF_TALK;
- } else {
- pm->ps->eFlags &= ~EF_TALK;
- }
-
- // set the firing flag for continuous beam weapons
- if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION
- && ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) {
- pm->ps->eFlags |= EF_FIRING;
- } else {
- pm->ps->eFlags &= ~EF_FIRING;
- }
-
- // clear the respawned flag if attack and use are cleared
- if ( pm->ps->stats[STAT_HEALTH] > 0 &&
- !( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) {
- pm->ps->pm_flags &= ~PMF_RESPAWNED;
- }
-
- // if talk button is down, dissallow all other input
- // this is to prevent any possible intercept proxy from
- // adding fake talk balloons
- if ( pmove->cmd.buttons & BUTTON_TALK ) {
- // keep the talk button set tho for when the cmd.serverTime > 66 msec
- // and the same cmd is used multiple times in Pmove
- pmove->cmd.buttons = BUTTON_TALK;
- pmove->cmd.forwardmove = 0;
- pmove->cmd.rightmove = 0;
- pmove->cmd.upmove = 0;
- }
-
- // clear all pmove local vars
- memset (&pml, 0, sizeof(pml));
-
- // determine the time
- pml.msec = pmove->cmd.serverTime - pm->ps->commandTime;
- if ( pml.msec < 1 ) {
- pml.msec = 1;
- } else if ( pml.msec > 200 ) {
- pml.msec = 200;
- }
- pm->ps->commandTime = pmove->cmd.serverTime;
-
- // save old org in case we get stuck
- VectorCopy (pm->ps->origin, pml.previous_origin);
-
- // save old velocity for crashlanding
- VectorCopy (pm->ps->velocity, pml.previous_velocity);
-
- pml.frametime = pml.msec * 0.001;
-
- // update the viewangles
- PM_UpdateViewAngles( pm->ps, &pm->cmd );
-
- AngleVectors (pm->ps->viewangles, pml.forward, pml.right, pml.up);
-
- if ( pm->cmd.upmove < 10 ) {
- // not holding jump
- pm->ps->pm_flags &= ~PMF_JUMP_HELD;
- }
-
- // decide if backpedaling animations should be used
- if ( pm->cmd.forwardmove < 0 ) {
- pm->ps->pm_flags |= PMF_BACKWARDS_RUN;
- } else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) {
- pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;
- }
-
- if ( pm->ps->pm_type >= PM_DEAD ) {
- pm->cmd.forwardmove = 0;
- pm->cmd.rightmove = 0;
- pm->cmd.upmove = 0;
- }
-
- if ( pm->ps->pm_type == PM_SPECTATOR ) {
- PM_CheckDuck ();
- PM_FlyMove ();
- PM_DropTimers ();
- return;
- }
-
- if ( pm->ps->pm_type == PM_NOCLIP ) {
- PM_NoclipMove ();
- PM_DropTimers ();
- return;
- }
-
- if (pm->ps->pm_type == PM_FREEZE) {
- return; // no movement at all
- }
-
- if ( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION) {
- return; // no movement at all
- }
-
- // set watertype, and waterlevel
- PM_SetWaterLevel();
- pml.previous_waterlevel = pmove->waterlevel;
-
- // set mins, maxs, and viewheight
- PM_CheckDuck ();
-
- // set groundentity
- PM_GroundTrace();
-
- if ( pm->ps->pm_type == PM_DEAD ) {
- PM_DeadMove ();
- }
-
- PM_DropTimers();
-
-#ifdef MISSIONPACK
- if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
- PM_InvulnerabilityMove();
- } else
-#endif
- if ( pm->ps->powerups[PW_FLIGHT] ) {
- // flight powerup doesn't allow jump and has different friction
- PM_FlyMove();
- } else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) {
- PM_GrappleMove();
- // We can wiggle a bit
- PM_AirMove();
- } else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) {
- PM_WaterJumpMove();
- } else if ( pm->waterlevel > 1 ) {
- // swimming
- PM_WaterMove();
- } else if ( pml.walking ) {
- // walking on ground
- PM_WalkMove();
- } else {
- // airborne
- PM_AirMove();
- }
-
- PM_Animate();
-
- // set groundentity, watertype, and waterlevel
- PM_GroundTrace();
- PM_SetWaterLevel();
-
- // weapons
- PM_Weapon();
-
- // torso animation
- PM_TorsoAnimation();
-
- // footstep events / legs animations
- PM_Footsteps();
-
- // entering / leaving water splashes
- PM_WaterEvents();
-
- // snap some parts of playerstate to save network bandwidth
- trap_SnapVector( pm->ps->velocity );
-}
-
-
-/*
-================
-Pmove
-
-Can be called by either the server or the client
-================
-*/
-void Pmove (pmove_t *pmove) {
- int finalTime;
-
- finalTime = pmove->cmd.serverTime;
-
- if ( finalTime < pmove->ps->commandTime ) {
- return; // should not happen
- }
-
- if ( finalTime > pmove->ps->commandTime + 1000 ) {
- pmove->ps->commandTime = finalTime - 1000;
- }
-
- pmove->ps->pmove_framecount = (pmove->ps->pmove_framecount+1) & ((1<<PS_PMOVEFRAMECOUNTBITS)-1);
-
- // chop the move up if it is too long, to prevent framerate
- // dependent behavior
- while ( pmove->ps->commandTime != finalTime ) {
- int msec;
-
- msec = finalTime - pmove->ps->commandTime;
-
- if ( pmove->pmove_fixed ) {
- if ( msec > pmove->pmove_msec ) {
- msec = pmove->pmove_msec;
- }
- }
- else {
- if ( msec > 66 ) {
- msec = 66;
- }
- }
- pmove->cmd.serverTime = pmove->ps->commandTime + msec;
- PmoveSingle( pmove );
-
- if ( pmove->ps->pm_flags & PMF_JUMP_HELD ) {
- pmove->cmd.upmove = 20;
- }
- }
-
- //PM_CheckStuck();
-
-}
-
diff --git a/engine/code/game/bg_public.h b/engine/code/game/bg_public.h
deleted file mode 100644
index ad5ab39..0000000
--- a/engine/code/game/bg_public.h
+++ /dev/null
@@ -1,738 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// bg_public.h -- definitions shared by both the server game and client game modules
-
-// because games can change separately from the main system version, we need a
-// second version that must match between game and cgame
-
-#define GAME_VERSION BASEGAME "-1"
-
-#define DEFAULT_GRAVITY 800
-#define GIB_HEALTH -40
-#define ARMOR_PROTECTION 0.66
-
-#define MAX_ITEMS 256
-
-#define RANK_TIED_FLAG 0x4000
-
-#define DEFAULT_SHOTGUN_SPREAD 700
-#define DEFAULT_SHOTGUN_COUNT 11
-
-#define ITEM_RADIUS 15 // item sizes are needed for client side pickup detection
-
-#define LIGHTNING_RANGE 768
-
-#define SCORE_NOT_PRESENT -9999 // for the CS_SCORES[12] when only one player is present
-
-#define VOTE_TIME 30000 // 30 seconds before vote times out
-
-#define MINS_Z -24
-#define DEFAULT_VIEWHEIGHT 26
-#define CROUCH_VIEWHEIGHT 12
-#define DEAD_VIEWHEIGHT -16
-
-//
-// config strings are a general means of communicating variable length strings
-// from the server to all connected clients.
-//
-
-// CS_SERVERINFO and CS_SYSTEMINFO are defined in q_shared.h
-#define CS_MUSIC 2
-#define CS_MESSAGE 3 // from the map worldspawn's message field
-#define CS_MOTD 4 // g_motd string for server message of the day
-#define CS_WARMUP 5 // server time when the match will be restarted
-#define CS_SCORES1 6
-#define CS_SCORES2 7
-#define CS_VOTE_TIME 8
-#define CS_VOTE_STRING 9
-#define CS_VOTE_YES 10
-#define CS_VOTE_NO 11
-
-#define CS_TEAMVOTE_TIME 12
-#define CS_TEAMVOTE_STRING 14
-#define CS_TEAMVOTE_YES 16
-#define CS_TEAMVOTE_NO 18
-
-#define CS_GAME_VERSION 20
-#define CS_LEVEL_START_TIME 21 // so the timer only shows the current level
-#define CS_INTERMISSION 22 // when 1, fraglimit/timelimit has been hit and intermission will start in a second or two
-#define CS_FLAGSTATUS 23 // string indicating flag status in CTF
-#define CS_SHADERSTATE 24
-#define CS_BOTINFO 25
-
-#define CS_ITEMS 27 // string of 0's and 1's that tell which items are present
-
-#define CS_MODELS 32
-#define CS_SOUNDS (CS_MODELS+MAX_MODELS)
-#define CS_PLAYERS (CS_SOUNDS+MAX_SOUNDS)
-#define CS_LOCATIONS (CS_PLAYERS+MAX_CLIENTS)
-#define CS_PARTICLES (CS_LOCATIONS+MAX_LOCATIONS)
-
-#define CS_MAX (CS_PARTICLES+MAX_LOCATIONS)
-
-#if (CS_MAX) > MAX_CONFIGSTRINGS
-#error overflow: (CS_MAX) > MAX_CONFIGSTRINGS
-#endif
-
-typedef enum {
- GT_FFA, // free for all
- GT_TOURNAMENT, // one on one tournament
- GT_SINGLE_PLAYER, // single player ffa
-
- //-- team games go after this --
-
- GT_TEAM, // team deathmatch
- GT_CTF, // capture the flag
- GT_1FCTF,
- GT_OBELISK,
- GT_HARVESTER,
- GT_MAX_GAME_TYPE
-} gametype_t;
-
-typedef enum { GENDER_MALE, GENDER_FEMALE, GENDER_NEUTER } gender_t;
-
-/*
-===================================================================================
-
-PMOVE MODULE
-
-The pmove code takes a player_state_t and a usercmd_t and generates a new player_state_t
-and some other output data. Used for local prediction on the client game and true
-movement on the server game.
-===================================================================================
-*/
-
-typedef enum {
- PM_NORMAL, // can accelerate and turn
- PM_NOCLIP, // noclip movement
- PM_SPECTATOR, // still run into walls
- PM_DEAD, // no acceleration or turning, but free falling
- PM_FREEZE, // stuck in place with no control
- PM_INTERMISSION, // no movement or status bar
- PM_SPINTERMISSION // no movement or status bar
-} pmtype_t;
-
-typedef enum {
- WEAPON_READY,
- WEAPON_RAISING,
- WEAPON_DROPPING,
- WEAPON_FIRING
-} weaponstate_t;
-
-// pmove->pm_flags
-#define PMF_DUCKED 1
-#define PMF_JUMP_HELD 2
-#define PMF_BACKWARDS_JUMP 8 // go into backwards land
-#define PMF_BACKWARDS_RUN 16 // coast down to backwards run
-#define PMF_TIME_LAND 32 // pm_time is time before rejump
-#define PMF_TIME_KNOCKBACK 64 // pm_time is an air-accelerate only time
-#define PMF_TIME_WATERJUMP 256 // pm_time is waterjump
-#define PMF_RESPAWNED 512 // clear after attack and jump buttons come up
-#define PMF_USE_ITEM_HELD 1024
-#define PMF_GRAPPLE_PULL 2048 // pull towards grapple location
-#define PMF_FOLLOW 4096 // spectate following another player
-#define PMF_SCOREBOARD 8192 // spectate as a scoreboard
-#define PMF_INVULEXPAND 16384 // invulnerability sphere set to full size
-
-#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK)
-
-#define MAXTOUCH 32
-typedef struct {
- // state (in / out)
- playerState_t *ps;
-
- // command (in)
- usercmd_t cmd;
- int tracemask; // collide against these types of surfaces
- int debugLevel; // if set, diagnostic output will be printed
- qboolean noFootsteps; // if the game is setup for no footsteps by the server
- qboolean gauntletHit; // true if a gauntlet attack would actually hit something
-
- int framecount;
-
- // results (out)
- int numtouch;
- int touchents[MAXTOUCH];
-
- vec3_t mins, maxs; // bounding box size
-
- int watertype;
- int waterlevel;
-
- float xyspeed;
-
- // for fixed msec Pmove
- int pmove_fixed;
- int pmove_msec;
-
- // callbacks to test the world
- // these will be different functions during game and cgame
- void (*trace)( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask );
- int (*pointcontents)( const vec3_t point, int passEntityNum );
-} pmove_t;
-
-// if a full pmove isn't done on the client, you can just update the angles
-void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd );
-void Pmove (pmove_t *pmove);
-
-//===================================================================================
-
-
-// player_state->stats[] indexes
-// NOTE: may not have more than 16
-typedef enum {
- STAT_HEALTH,
- STAT_HOLDABLE_ITEM,
-#ifdef MISSIONPACK
- STAT_PERSISTANT_POWERUP,
-#endif
- STAT_WEAPONS, // 16 bit fields
- STAT_ARMOR,
- STAT_DEAD_YAW, // look this direction when dead (FIXME: get rid of?)
- STAT_CLIENTS_READY, // bit mask of clients wishing to exit the intermission (FIXME: configstring?)
- STAT_MAX_HEALTH // health / armor limit, changable by handicap
-} statIndex_t;
-
-
-// player_state->persistant[] indexes
-// these fields are the only part of player_state that isn't
-// cleared on respawn
-// NOTE: may not have more than 16
-typedef enum {
- PERS_SCORE, // !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!!
- PERS_HITS, // total points damage inflicted so damage beeps can sound on change
- PERS_RANK, // player rank or team rank
- PERS_TEAM, // player team
- PERS_SPAWN_COUNT, // incremented every respawn
- PERS_PLAYEREVENTS, // 16 bits that can be flipped for events
- PERS_ATTACKER, // clientnum of last damage inflicter
- PERS_ATTACKEE_ARMOR, // health/armor of last person we attacked
- PERS_KILLED, // count of the number of times you died
- // player awards tracking
- PERS_IMPRESSIVE_COUNT, // two railgun hits in a row
- PERS_EXCELLENT_COUNT, // two successive kills in a short amount of time
- PERS_DEFEND_COUNT, // defend awards
- PERS_ASSIST_COUNT, // assist awards
- PERS_GAUNTLET_FRAG_COUNT, // kills with the guantlet
- PERS_CAPTURES // captures
-} persEnum_t;
-
-
-// entityState_t->eFlags
-#define EF_DEAD 0x00000001 // don't draw a foe marker over players with EF_DEAD
-#ifdef MISSIONPACK
-#define EF_TICKING 0x00000002 // used to make players play the prox mine ticking sound
-#endif
-#define EF_TELEPORT_BIT 0x00000004 // toggled every time the origin abruptly changes
-#define EF_AWARD_EXCELLENT 0x00000008 // draw an excellent sprite
-#define EF_PLAYER_EVENT 0x00000010
-#define EF_BOUNCE 0x00000010 // for missiles
-#define EF_BOUNCE_HALF 0x00000020 // for missiles
-#define EF_AWARD_GAUNTLET 0x00000040 // draw a gauntlet sprite
-#define EF_NODRAW 0x00000080 // may have an event, but no model (unspawned items)
-#define EF_FIRING 0x00000100 // for lightning gun
-#define EF_KAMIKAZE 0x00000200
-#define EF_MOVER_STOP 0x00000400 // will push otherwise
-#define EF_AWARD_CAP 0x00000800 // draw the capture sprite
-#define EF_TALK 0x00001000 // draw a talk balloon
-#define EF_CONNECTION 0x00002000 // draw a connection trouble sprite
-#define EF_VOTED 0x00004000 // already cast a vote
-#define EF_AWARD_IMPRESSIVE 0x00008000 // draw an impressive sprite
-#define EF_AWARD_DEFEND 0x00010000 // draw a defend sprite
-#define EF_AWARD_ASSIST 0x00020000 // draw a assist sprite
-#define EF_AWARD_DENIED 0x00040000 // denied
-#define EF_TEAMVOTED 0x00080000 // already cast a team vote
-
-// NOTE: may not have more than 16
-typedef enum {
- PW_NONE,
-
- PW_QUAD,
- PW_BATTLESUIT,
- PW_HASTE,
- PW_INVIS,
- PW_REGEN,
- PW_FLIGHT,
-
- PW_REDFLAG,
- PW_BLUEFLAG,
- PW_NEUTRALFLAG,
-
- PW_SCOUT,
- PW_GUARD,
- PW_DOUBLER,
- PW_AMMOREGEN,
- PW_INVULNERABILITY,
-
- PW_NUM_POWERUPS
-
-} powerup_t;
-
-typedef enum {
- HI_NONE,
-
- HI_TELEPORTER,
- HI_MEDKIT,
- HI_KAMIKAZE,
- HI_PORTAL,
- HI_INVULNERABILITY,
-
- HI_NUM_HOLDABLE
-} holdable_t;
-
-
-typedef enum {
- WP_NONE,
-
- WP_GAUNTLET,
- WP_MACHINEGUN,
- WP_SHOTGUN,
- WP_GRENADE_LAUNCHER,
- WP_ROCKET_LAUNCHER,
- WP_LIGHTNING,
- WP_RAILGUN,
- WP_PLASMAGUN,
- WP_BFG,
- WP_GRAPPLING_HOOK,
-#ifdef MISSIONPACK
- WP_NAILGUN,
- WP_PROX_LAUNCHER,
- WP_CHAINGUN,
-#endif
-
- WP_NUM_WEAPONS
-} weapon_t;
-
-
-// reward sounds (stored in ps->persistant[PERS_PLAYEREVENTS])
-#define PLAYEREVENT_DENIEDREWARD 0x0001
-#define PLAYEREVENT_GAUNTLETREWARD 0x0002
-#define PLAYEREVENT_HOLYSHIT 0x0004
-
-// entityState_t->event values
-// entity events are for effects that take place reletive
-// to an existing entities origin. Very network efficient.
-
-// two bits at the top of the entityState->event field
-// will be incremented with each change in the event so
-// that an identical event started twice in a row can
-// be distinguished. And off the value with ~EV_EVENT_BITS
-// to retrieve the actual event number
-#define EV_EVENT_BIT1 0x00000100
-#define EV_EVENT_BIT2 0x00000200
-#define EV_EVENT_BITS (EV_EVENT_BIT1|EV_EVENT_BIT2)
-
-#define EVENT_VALID_MSEC 300
-
-typedef enum {
- EV_NONE,
-
- EV_FOOTSTEP,
- EV_FOOTSTEP_METAL,
- EV_FOOTSPLASH,
- EV_FOOTWADE,
- EV_SWIM,
-
- EV_STEP_4,
- EV_STEP_8,
- EV_STEP_12,
- EV_STEP_16,
-
- EV_FALL_SHORT,
- EV_FALL_MEDIUM,
- EV_FALL_FAR,
-
- EV_JUMP_PAD, // boing sound at origin, jump sound on player
-
- EV_JUMP,
- EV_WATER_TOUCH, // foot touches
- EV_WATER_LEAVE, // foot leaves
- EV_WATER_UNDER, // head touches
- EV_WATER_CLEAR, // head leaves
-
- EV_ITEM_PICKUP, // normal item pickups are predictable
- EV_GLOBAL_ITEM_PICKUP, // powerup / team sounds are broadcast to everyone
-
- EV_NOAMMO,
- EV_CHANGE_WEAPON,
- EV_FIRE_WEAPON,
-
- EV_USE_ITEM0,
- EV_USE_ITEM1,
- EV_USE_ITEM2,
- EV_USE_ITEM3,
- EV_USE_ITEM4,
- EV_USE_ITEM5,
- EV_USE_ITEM6,
- EV_USE_ITEM7,
- EV_USE_ITEM8,
- EV_USE_ITEM9,
- EV_USE_ITEM10,
- EV_USE_ITEM11,
- EV_USE_ITEM12,
- EV_USE_ITEM13,
- EV_USE_ITEM14,
- EV_USE_ITEM15,
-
- EV_ITEM_RESPAWN,
- EV_ITEM_POP,
- EV_PLAYER_TELEPORT_IN,
- EV_PLAYER_TELEPORT_OUT,
-
- EV_GRENADE_BOUNCE, // eventParm will be the soundindex
-
- EV_GENERAL_SOUND,
- EV_GLOBAL_SOUND, // no attenuation
- EV_GLOBAL_TEAM_SOUND,
-
- EV_BULLET_HIT_FLESH,
- EV_BULLET_HIT_WALL,
-
- EV_MISSILE_HIT,
- EV_MISSILE_MISS,
- EV_MISSILE_MISS_METAL,
- EV_RAILTRAIL,
- EV_SHOTGUN,
- EV_BULLET, // otherEntity is the shooter
-
- EV_PAIN,
- EV_DEATH1,
- EV_DEATH2,
- EV_DEATH3,
- EV_OBITUARY,
-
- EV_POWERUP_QUAD,
- EV_POWERUP_BATTLESUIT,
- EV_POWERUP_REGEN,
-
- EV_GIB_PLAYER, // gib a previously living player
- EV_SCOREPLUM, // score plum
-
-//#ifdef MISSIONPACK
- EV_PROXIMITY_MINE_STICK,
- EV_PROXIMITY_MINE_TRIGGER,
- EV_KAMIKAZE, // kamikaze explodes
- EV_OBELISKEXPLODE, // obelisk explodes
- EV_OBELISKPAIN, // obelisk is in pain
- EV_INVUL_IMPACT, // invulnerability sphere impact
- EV_JUICED, // invulnerability juiced effect
- EV_LIGHTNINGBOLT, // lightning bolt bounced of invulnerability sphere
-//#endif
-
- EV_DEBUG_LINE,
- EV_STOPLOOPINGSOUND,
- EV_TAUNT,
- EV_TAUNT_YES,
- EV_TAUNT_NO,
- EV_TAUNT_FOLLOWME,
- EV_TAUNT_GETFLAG,
- EV_TAUNT_GUARDBASE,
- EV_TAUNT_PATROL
-
-} entity_event_t;
-
-
-typedef enum {
- GTS_RED_CAPTURE,
- GTS_BLUE_CAPTURE,
- GTS_RED_RETURN,
- GTS_BLUE_RETURN,
- GTS_RED_TAKEN,
- GTS_BLUE_TAKEN,
- GTS_REDOBELISK_ATTACKED,
- GTS_BLUEOBELISK_ATTACKED,
- GTS_REDTEAM_SCORED,
- GTS_BLUETEAM_SCORED,
- GTS_REDTEAM_TOOK_LEAD,
- GTS_BLUETEAM_TOOK_LEAD,
- GTS_TEAMS_ARE_TIED,
- GTS_KAMIKAZE
-} global_team_sound_t;
-
-// animations
-typedef enum {
- BOTH_DEATH1,
- BOTH_DEAD1,
- BOTH_DEATH2,
- BOTH_DEAD2,
- BOTH_DEATH3,
- BOTH_DEAD3,
-
- TORSO_GESTURE,
-
- TORSO_ATTACK,
- TORSO_ATTACK2,
-
- TORSO_DROP,
- TORSO_RAISE,
-
- TORSO_STAND,
- TORSO_STAND2,
-
- LEGS_WALKCR,
- LEGS_WALK,
- LEGS_RUN,
- LEGS_BACK,
- LEGS_SWIM,
-
- LEGS_JUMP,
- LEGS_LAND,
-
- LEGS_JUMPB,
- LEGS_LANDB,
-
- LEGS_IDLE,
- LEGS_IDLECR,
-
- LEGS_TURN,
-
- TORSO_GETFLAG,
- TORSO_GUARDBASE,
- TORSO_PATROL,
- TORSO_FOLLOWME,
- TORSO_AFFIRMATIVE,
- TORSO_NEGATIVE,
-
- MAX_ANIMATIONS,
-
- LEGS_BACKCR,
- LEGS_BACKWALK,
- FLAG_RUN,
- FLAG_STAND,
- FLAG_STAND2RUN,
-
- MAX_TOTALANIMATIONS
-} animNumber_t;
-
-
-typedef struct animation_s {
- int firstFrame;
- int numFrames;
- int loopFrames; // 0 to numFrames
- int frameLerp; // msec between frames
- int initialLerp; // msec to get to first frame
- int reversed; // true if animation is reversed
- int flipflop; // true if animation should flipflop back to base
-} animation_t;
-
-
-// flip the togglebit every time an animation
-// changes so a restart of the same anim can be detected
-#define ANIM_TOGGLEBIT 128
-
-
-typedef enum {
- TEAM_FREE,
- TEAM_RED,
- TEAM_BLUE,
- TEAM_SPECTATOR,
-
- TEAM_NUM_TEAMS
-} team_t;
-
-// Time between location updates
-#define TEAM_LOCATION_UPDATE_TIME 1000
-
-// How many players on the overlay
-#define TEAM_MAXOVERLAY 32
-
-//team task
-typedef enum {
- TEAMTASK_NONE,
- TEAMTASK_OFFENSE,
- TEAMTASK_DEFENSE,
- TEAMTASK_PATROL,
- TEAMTASK_FOLLOW,
- TEAMTASK_RETRIEVE,
- TEAMTASK_ESCORT,
- TEAMTASK_CAMP
-} teamtask_t;
-
-// means of death
-typedef enum {
- MOD_UNKNOWN,
- MOD_SHOTGUN,
- MOD_GAUNTLET,
- MOD_MACHINEGUN,
- MOD_GRENADE,
- MOD_GRENADE_SPLASH,
- MOD_ROCKET,
- MOD_ROCKET_SPLASH,
- MOD_PLASMA,
- MOD_PLASMA_SPLASH,
- MOD_RAILGUN,
- MOD_LIGHTNING,
- MOD_BFG,
- MOD_BFG_SPLASH,
- MOD_WATER,
- MOD_SLIME,
- MOD_LAVA,
- MOD_CRUSH,
- MOD_TELEFRAG,
- MOD_FALLING,
- MOD_SUICIDE,
- MOD_TARGET_LASER,
- MOD_TRIGGER_HURT,
-#ifdef MISSIONPACK
- MOD_NAIL,
- MOD_CHAINGUN,
- MOD_PROXIMITY_MINE,
- MOD_KAMIKAZE,
- MOD_JUICED,
-#endif
- MOD_GRAPPLE
-} meansOfDeath_t;
-
-
-//---------------------------------------------------------
-
-// gitem_t->type
-typedef enum {
- IT_BAD,
- IT_WEAPON, // EFX: rotate + upscale + minlight
- IT_AMMO, // EFX: rotate
- IT_ARMOR, // EFX: rotate + minlight
- IT_HEALTH, // EFX: static external sphere + rotating internal
- IT_POWERUP, // instant on, timer based
- // EFX: rotate + external ring that rotates
- IT_HOLDABLE, // single use, holdable item
- // EFX: rotate + bob
- IT_PERSISTANT_POWERUP,
- IT_TEAM
-} itemType_t;
-
-#define MAX_ITEM_MODELS 4
-
-typedef struct gitem_s {
- char *classname; // spawning name
- char *pickup_sound;
- char *world_model[MAX_ITEM_MODELS];
-
- char *icon;
- char *pickup_name; // for printing on pickup
-
- int quantity; // for ammo how much, or duration of powerup
- itemType_t giType; // IT_* flags
-
- int giTag;
-
- char *precaches; // string of all models and images this item will use
- char *sounds; // string of all sounds this item will use
-} gitem_t;
-
-// included in both the game dll and the client
-extern gitem_t bg_itemlist[];
-extern int bg_numItems;
-
-gitem_t *BG_FindItem( const char *pickupName );
-gitem_t *BG_FindItemForWeapon( weapon_t weapon );
-gitem_t *BG_FindItemForPowerup( powerup_t pw );
-gitem_t *BG_FindItemForHoldable( holdable_t pw );
-#define ITEM_INDEX(x) ((x)-bg_itemlist)
-
-qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps );
-
-
-// g_dmflags->integer flags
-#define DF_NO_FALLING 8
-#define DF_FIXED_FOV 16
-#define DF_NO_FOOTSTEPS 32
-
-// content masks
-#define MASK_ALL (-1)
-#define MASK_SOLID (CONTENTS_SOLID)
-#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY)
-#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP)
-#define MASK_WATER (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME)
-#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA)
-#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE)
-
-
-//
-// entityState_t->eType
-//
-typedef enum {
- ET_GENERAL,
- ET_PLAYER,
- ET_ITEM,
- ET_MISSILE,
- ET_MOVER,
- ET_BEAM,
- ET_PORTAL,
- ET_SPEAKER,
- ET_PUSH_TRIGGER,
- ET_TELEPORT_TRIGGER,
- ET_INVISIBLE,
- ET_GRAPPLE, // grapple hooked on wall
- ET_TEAM,
-
- ET_EVENTS // any of the EV_* events can be added freestanding
- // by setting eType to ET_EVENTS + eventNum
- // this avoids having to set eFlags and eventNum
-} entityType_t;
-
-
-
-void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result );
-void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result );
-
-void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps );
-
-void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad );
-
-void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap );
-void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap );
-
-qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime );
-
-
-#define ARENAS_PER_TIER 4
-#define MAX_ARENAS 1024
-#define MAX_ARENAS_TEXT 8192
-
-#define MAX_BOTS 1024
-#define MAX_BOTS_TEXT 8192
-
-
-// Kamikaze
-
-// 1st shockwave times
-#define KAMI_SHOCKWAVE_STARTTIME 0
-#define KAMI_SHOCKWAVEFADE_STARTTIME 1500
-#define KAMI_SHOCKWAVE_ENDTIME 2000
-// explosion/implosion times
-#define KAMI_EXPLODE_STARTTIME 250
-#define KAMI_IMPLODE_STARTTIME 2000
-#define KAMI_IMPLODE_ENDTIME 2250
-// 2nd shockwave times
-#define KAMI_SHOCKWAVE2_STARTTIME 2000
-#define KAMI_SHOCKWAVE2FADE_STARTTIME 2500
-#define KAMI_SHOCKWAVE2_ENDTIME 3000
-// radius of the models without scaling
-#define KAMI_SHOCKWAVEMODEL_RADIUS 88
-#define KAMI_BOOMSPHEREMODEL_RADIUS 72
-// maximum radius of the models during the effect
-#define KAMI_SHOCKWAVE_MAXRADIUS 1320
-#define KAMI_BOOMSPHERE_MAXRADIUS 720
-#define KAMI_SHOCKWAVE2_MAXRADIUS 704
-
diff --git a/engine/code/game/g_active.c b/engine/code/game/g_active.c
deleted file mode 100644
index aa48c80..0000000
--- a/engine/code/game/g_active.c
+++ /dev/null
@@ -1,1191 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-#include "g_local.h"
-
-
-/*
-===============
-G_DamageFeedback
-
-Called just before a snapshot is sent to the given player.
-Totals up all damage and generates both the player_state_t
-damage values to that client for pain blends and kicks, and
-global pain sound events for all clients.
-===============
-*/
-void P_DamageFeedback( gentity_t *player ) {
- gclient_t *client;
- float count;
- vec3_t angles;
-
- client = player->client;
- if ( client->ps.pm_type == PM_DEAD ) {
- return;
- }
-
- // total points of damage shot at the player this frame
- count = client->damage_blood + client->damage_armor;
- if ( count == 0 ) {
- return; // didn't take any damage
- }
-
- if ( count > 255 ) {
- count = 255;
- }
-
- // send the information to the client
-
- // world damage (falling, slime, etc) uses a special code
- // to make the blend blob centered instead of positional
- if ( client->damage_fromWorld ) {
- client->ps.damagePitch = 255;
- client->ps.damageYaw = 255;
-
- client->damage_fromWorld = qfalse;
- } else {
- vectoangles( client->damage_from, angles );
- client->ps.damagePitch = angles[PITCH]/360.0 * 256;
- client->ps.damageYaw = angles[YAW]/360.0 * 256;
- }
-
- // play an apropriate pain sound
- if ( (level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) ) {
- player->pain_debounce_time = level.time + 700;
- G_AddEvent( player, EV_PAIN, player->health );
- client->ps.damageEvent++;
- }
-
-
- client->ps.damageCount = count;
-
- //
- // clear totals
- //
- client->damage_blood = 0;
- client->damage_armor = 0;
- client->damage_knockback = 0;
-}
-
-
-
-/*
-=============
-P_WorldEffects
-
-Check for lava / slime contents and drowning
-=============
-*/
-void P_WorldEffects( gentity_t *ent ) {
- qboolean envirosuit;
- int waterlevel;
-
- if ( ent->client->noclip ) {
- ent->client->airOutTime = level.time + 12000; // don't need air
- return;
- }
-
- waterlevel = ent->waterlevel;
-
- envirosuit = ent->client->ps.powerups[PW_BATTLESUIT] > level.time;
-
- //
- // check for drowning
- //
- if ( waterlevel == 3 ) {
- // envirosuit give air
- if ( envirosuit ) {
- ent->client->airOutTime = level.time + 10000;
- }
-
- // if out of air, start drowning
- if ( ent->client->airOutTime < level.time) {
- // drown!
- ent->client->airOutTime += 1000;
- if ( ent->health > 0 ) {
- // take more damage the longer underwater
- ent->damage += 2;
- if (ent->damage > 15)
- ent->damage = 15;
-
- // play a gurp sound instead of a normal pain sound
- if (ent->health <= ent->damage) {
- G_Sound(ent, CHAN_VOICE, G_SoundIndex("*drown.wav"));
- } else if (rand()&1) {
- G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp1.wav"));
- } else {
- G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp2.wav"));
- }
-
- // don't play a normal pain sound
- ent->pain_debounce_time = level.time + 200;
-
- G_Damage (ent, NULL, NULL, NULL, NULL,
- ent->damage, DAMAGE_NO_ARMOR, MOD_WATER);
- }
- }
- } else {
- ent->client->airOutTime = level.time + 12000;
- ent->damage = 2;
- }
-
- //
- // check for sizzle damage (move to pmove?)
- //
- if (waterlevel &&
- (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) {
- if (ent->health > 0
- && ent->pain_debounce_time <= level.time ) {
-
- if ( envirosuit ) {
- G_AddEvent( ent, EV_POWERUP_BATTLESUIT, 0 );
- } else {
- if (ent->watertype & CONTENTS_LAVA) {
- G_Damage (ent, NULL, NULL, NULL, NULL,
- 30*waterlevel, 0, MOD_LAVA);
- }
-
- if (ent->watertype & CONTENTS_SLIME) {
- G_Damage (ent, NULL, NULL, NULL, NULL,
- 10*waterlevel, 0, MOD_SLIME);
- }
- }
- }
- }
-}
-
-
-
-/*
-===============
-G_SetClientSound
-===============
-*/
-void G_SetClientSound( gentity_t *ent ) {
-#ifdef MISSIONPACK
- if( ent->s.eFlags & EF_TICKING ) {
- ent->client->ps.loopSound = G_SoundIndex( "sound/weapons/proxmine/wstbtick.wav");
- }
- else
-#endif
- if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) {
- ent->client->ps.loopSound = level.snd_fry;
- } else {
- ent->client->ps.loopSound = 0;
- }
-}
-
-
-
-//==============================================================
-
-/*
-==============
-ClientImpacts
-==============
-*/
-void ClientImpacts( gentity_t *ent, pmove_t *pm ) {
- int i, j;
- trace_t trace;
- gentity_t *other;
-
- memset( &trace, 0, sizeof( trace ) );
- for (i=0 ; i<pm->numtouch ; i++) {
- for (j=0 ; j<i ; j++) {
- if (pm->touchents[j] == pm->touchents[i] ) {
- break;
- }
- }
- if (j != i) {
- continue; // duplicated
- }
- other = &g_entities[ pm->touchents[i] ];
-
- if ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) {
- ent->touch( ent, other, &trace );
- }
-
- if ( !other->touch ) {
- continue;
- }
-
- other->touch( other, ent, &trace );
- }
-
-}
-
-/*
-============
-G_TouchTriggers
-
-Find all trigger entities that ent's current position touches.
-Spectators will only interact with teleporters.
-============
-*/
-void G_TouchTriggers( gentity_t *ent ) {
- int i, num;
- int touch[MAX_GENTITIES];
- gentity_t *hit;
- trace_t trace;
- vec3_t mins, maxs;
- static vec3_t range = { 40, 40, 52 };
-
- if ( !ent->client ) {
- return;
- }
-
- // dead clients don't activate triggers!
- if ( ent->client->ps.stats[STAT_HEALTH] <= 0 ) {
- return;
- }
-
- VectorSubtract( ent->client->ps.origin, range, mins );
- VectorAdd( ent->client->ps.origin, range, maxs );
-
- num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
-
- // can't use ent->absmin, because that has a one unit pad
- VectorAdd( ent->client->ps.origin, ent->r.mins, mins );
- VectorAdd( ent->client->ps.origin, ent->r.maxs, maxs );
-
- for ( i=0 ; i<num ; i++ ) {
- hit = &g_entities[touch[i]];
-
- if ( !hit->touch && !ent->touch ) {
- continue;
- }
- if ( !( hit->r.contents & CONTENTS_TRIGGER ) ) {
- continue;
- }
-
- // ignore most entities if a spectator
- if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
- if ( hit->s.eType != ET_TELEPORT_TRIGGER &&
- // this is ugly but adding a new ET_? type will
- // most likely cause network incompatibilities
- hit->touch != Touch_DoorTrigger) {
- continue;
- }
- }
-
- // use seperate code for determining if an item is picked up
- // so you don't have to actually contact its bounding box
- if ( hit->s.eType == ET_ITEM ) {
- if ( !BG_PlayerTouchesItem( &ent->client->ps, &hit->s, level.time ) ) {
- continue;
- }
- } else {
- if ( !trap_EntityContact( mins, maxs, hit ) ) {
- continue;
- }
- }
-
- memset( &trace, 0, sizeof(trace) );
-
- if ( hit->touch ) {
- hit->touch (hit, ent, &trace);
- }
-
- if ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) {
- ent->touch( ent, hit, &trace );
- }
- }
-
- // if we didn't touch a jump pad this pmove frame
- if ( ent->client->ps.jumppad_frame != ent->client->ps.pmove_framecount ) {
- ent->client->ps.jumppad_frame = 0;
- ent->client->ps.jumppad_ent = 0;
- }
-}
-
-/*
-=================
-SpectatorThink
-=================
-*/
-void SpectatorThink( gentity_t *ent, usercmd_t *ucmd ) {
- pmove_t pm;
- gclient_t *client;
-
- client = ent->client;
-
- if ( client->sess.spectatorState != SPECTATOR_FOLLOW ) {
- client->ps.pm_type = PM_SPECTATOR;
- client->ps.speed = 400; // faster than normal
-
- // set up for pmove
- memset (&pm, 0, sizeof(pm));
- pm.ps = &client->ps;
- pm.cmd = *ucmd;
- pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; // spectators can fly through bodies
- pm.trace = trap_Trace;
- pm.pointcontents = trap_PointContents;
-
- // perform a pmove
- Pmove (&pm);
- // save results of pmove
- VectorCopy( client->ps.origin, ent->s.origin );
-
- G_TouchTriggers( ent );
- trap_UnlinkEntity( ent );
- }
-
- client->oldbuttons = client->buttons;
- client->buttons = ucmd->buttons;
-
- // attack button cycles through spectators
- if ( ( client->buttons & BUTTON_ATTACK ) && ! ( client->oldbuttons & BUTTON_ATTACK ) ) {
- Cmd_FollowCycle_f( ent, 1 );
- }
-}
-
-
-
-/*
-=================
-ClientInactivityTimer
-
-Returns qfalse if the client is dropped
-=================
-*/
-qboolean ClientInactivityTimer( gclient_t *client ) {
- if ( ! g_inactivity.integer ) {
- // give everyone some time, so if the operator sets g_inactivity during
- // gameplay, everyone isn't kicked
- client->inactivityTime = level.time + 60 * 1000;
- client->inactivityWarning = qfalse;
- } else if ( client->pers.cmd.forwardmove ||
- client->pers.cmd.rightmove ||
- client->pers.cmd.upmove ||
- (client->pers.cmd.buttons & BUTTON_ATTACK) ) {
- client->inactivityTime = level.time + g_inactivity.integer * 1000;
- client->inactivityWarning = qfalse;
- } else if ( !client->pers.localClient ) {
- if ( level.time > client->inactivityTime ) {
- trap_DropClient( client - level.clients, "Dropped due to inactivity" );
- return qfalse;
- }
- if ( level.time > client->inactivityTime - 10000 && !client->inactivityWarning ) {
- client->inactivityWarning = qtrue;
- trap_SendServerCommand( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" );
- }
- }
- return qtrue;
-}
-
-/*
-==================
-ClientTimerActions
-
-Actions that happen once a second
-==================
-*/
-void ClientTimerActions( gentity_t *ent, int msec ) {
- gclient_t *client;
-#ifdef MISSIONPACK
- int maxHealth;
-#endif
-
- client = ent->client;
- client->timeResidual += msec;
-
- while ( client->timeResidual >= 1000 ) {
- client->timeResidual -= 1000;
-
- // regenerate
-#ifdef MISSIONPACK
- if( bg_itemlist[client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
- maxHealth = client->ps.stats[STAT_MAX_HEALTH] / 2;
- }
- else if ( client->ps.powerups[PW_REGEN] ) {
- maxHealth = client->ps.stats[STAT_MAX_HEALTH];
- }
- else {
- maxHealth = 0;
- }
- if( maxHealth ) {
- if ( ent->health < maxHealth ) {
- ent->health += 15;
- if ( ent->health > maxHealth * 1.1 ) {
- ent->health = maxHealth * 1.1;
- }
- G_AddEvent( ent, EV_POWERUP_REGEN, 0 );
- } else if ( ent->health < maxHealth * 2) {
- ent->health += 5;
- if ( ent->health > maxHealth * 2 ) {
- ent->health = maxHealth * 2;
- }
- G_AddEvent( ent, EV_POWERUP_REGEN, 0 );
- }
-#else
- if ( client->ps.powerups[PW_REGEN] ) {
- if ( ent->health < client->ps.stats[STAT_MAX_HEALTH]) {
- ent->health += 15;
- if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] * 1.1 ) {
- ent->health = client->ps.stats[STAT_MAX_HEALTH] * 1.1;
- }
- G_AddEvent( ent, EV_POWERUP_REGEN, 0 );
- } else if ( ent->health < client->ps.stats[STAT_MAX_HEALTH] * 2) {
- ent->health += 5;
- if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] * 2 ) {
- ent->health = client->ps.stats[STAT_MAX_HEALTH] * 2;
- }
- G_AddEvent( ent, EV_POWERUP_REGEN, 0 );
- }
-#endif
- } else {
- // count down health when over max
- if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] ) {
- ent->health--;
- }
- }
-
- // count down armor when over max
- if ( client->ps.stats[STAT_ARMOR] > client->ps.stats[STAT_MAX_HEALTH] ) {
- client->ps.stats[STAT_ARMOR]--;
- }
- }
-#ifdef MISSIONPACK
- if( bg_itemlist[client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
- int w, max, inc, t, i;
- int weapList[]={WP_MACHINEGUN,WP_SHOTGUN,WP_GRENADE_LAUNCHER,WP_ROCKET_LAUNCHER,WP_LIGHTNING,WP_RAILGUN,WP_PLASMAGUN,WP_BFG,WP_NAILGUN,WP_PROX_LAUNCHER,WP_CHAINGUN};
- int weapCount = sizeof(weapList) / sizeof(int);
- //
- for (i = 0; i < weapCount; i++) {
- w = weapList[i];
-
- switch(w) {
- case WP_MACHINEGUN: max = 50; inc = 4; t = 1000; break;
- case WP_SHOTGUN: max = 10; inc = 1; t = 1500; break;
- case WP_GRENADE_LAUNCHER: max = 10; inc = 1; t = 2000; break;
- case WP_ROCKET_LAUNCHER: max = 10; inc = 1; t = 1750; break;
- case WP_LIGHTNING: max = 50; inc = 5; t = 1500; break;
- case WP_RAILGUN: max = 10; inc = 1; t = 1750; break;
- case WP_PLASMAGUN: max = 50; inc = 5; t = 1500; break;
- case WP_BFG: max = 10; inc = 1; t = 4000; break;
- case WP_NAILGUN: max = 10; inc = 1; t = 1250; break;
- case WP_PROX_LAUNCHER: max = 5; inc = 1; t = 2000; break;
- case WP_CHAINGUN: max = 100; inc = 5; t = 1000; break;
- default: max = 0; inc = 0; t = 1000; break;
- }
- client->ammoTimes[w] += msec;
- if ( client->ps.ammo[w] >= max ) {
- client->ammoTimes[w] = 0;
- }
- if ( client->ammoTimes[w] >= t ) {
- while ( client->ammoTimes[w] >= t )
- client->ammoTimes[w] -= t;
- client->ps.ammo[w] += inc;
- if ( client->ps.ammo[w] > max ) {
- client->ps.ammo[w] = max;
- }
- }
- }
- }
-#endif
-}
-
-/*
-====================
-ClientIntermissionThink
-====================
-*/
-void ClientIntermissionThink( gclient_t *client ) {
- client->ps.eFlags &= ~EF_TALK;
- client->ps.eFlags &= ~EF_FIRING;
-
- // the level will exit when everyone wants to or after timeouts
-
- // swap and latch button actions
- client->oldbuttons = client->buttons;
- client->buttons = client->pers.cmd.buttons;
- if ( client->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) & ( client->oldbuttons ^ client->buttons ) ) {
- // this used to be an ^1 but once a player says ready, it should stick
- client->readyToExit = 1;
- }
-}
-
-
-/*
-================
-ClientEvents
-
-Events will be passed on to the clients for presentation,
-but any server game effects are handled here
-================
-*/
-void ClientEvents( gentity_t *ent, int oldEventSequence ) {
- int i, j;
- int event;
- gclient_t *client;
- int damage;
- vec3_t dir;
- vec3_t origin, angles;
-// qboolean fired;
- gitem_t *item;
- gentity_t *drop;
-
- client = ent->client;
-
- if ( oldEventSequence < client->ps.eventSequence - MAX_PS_EVENTS ) {
- oldEventSequence = client->ps.eventSequence - MAX_PS_EVENTS;
- }
- for ( i = oldEventSequence ; i < client->ps.eventSequence ; i++ ) {
- event = client->ps.events[ i & (MAX_PS_EVENTS-1) ];
-
- switch ( event ) {
- case EV_FALL_MEDIUM:
- case EV_FALL_FAR:
- if ( ent->s.eType != ET_PLAYER ) {
- break; // not in the player model
- }
- if ( g_dmflags.integer & DF_NO_FALLING ) {
- break;
- }
- if ( event == EV_FALL_FAR ) {
- damage = 10;
- } else {
- damage = 5;
- }
- VectorSet (dir, 0, 0, 1);
- ent->pain_debounce_time = level.time + 200; // no normal pain sound
- G_Damage (ent, NULL, NULL, NULL, NULL, damage, 0, MOD_FALLING);
- break;
-
- case EV_FIRE_WEAPON:
- FireWeapon( ent );
- break;
-
- case EV_USE_ITEM1: // teleporter
- // drop flags in CTF
- item = NULL;
- j = 0;
-
- if ( ent->client->ps.powerups[ PW_REDFLAG ] ) {
- item = BG_FindItemForPowerup( PW_REDFLAG );
- j = PW_REDFLAG;
- } else if ( ent->client->ps.powerups[ PW_BLUEFLAG ] ) {
- item = BG_FindItemForPowerup( PW_BLUEFLAG );
- j = PW_BLUEFLAG;
- } else if ( ent->client->ps.powerups[ PW_NEUTRALFLAG ] ) {
- item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
- j = PW_NEUTRALFLAG;
- }
-
- if ( item ) {
- drop = Drop_Item( ent, item, 0 );
- // decide how many seconds it has left
- drop->count = ( ent->client->ps.powerups[ j ] - level.time ) / 1000;
- if ( drop->count < 1 ) {
- drop->count = 1;
- }
-
- ent->client->ps.powerups[ j ] = 0;
- }
-
-#ifdef MISSIONPACK
- if ( g_gametype.integer == GT_HARVESTER ) {
- if ( ent->client->ps.generic1 > 0 ) {
- if ( ent->client->sess.sessionTeam == TEAM_RED ) {
- item = BG_FindItem( "Blue Cube" );
- } else {
- item = BG_FindItem( "Red Cube" );
- }
- if ( item ) {
- for ( j = 0; j < ent->client->ps.generic1; j++ ) {
- drop = Drop_Item( ent, item, 0 );
- if ( ent->client->sess.sessionTeam == TEAM_RED ) {
- drop->spawnflags = TEAM_BLUE;
- } else {
- drop->spawnflags = TEAM_RED;
- }
- }
- }
- ent->client->ps.generic1 = 0;
- }
- }
-#endif
- SelectSpawnPoint( ent->client->ps.origin, origin, angles, qfalse );
- TeleportPlayer( ent, origin, angles );
- break;
-
- case EV_USE_ITEM2: // medkit
- ent->health = ent->client->ps.stats[STAT_MAX_HEALTH] + 25;
-
- break;
-
-#ifdef MISSIONPACK
- case EV_USE_ITEM3: // kamikaze
- // make sure the invulnerability is off
- ent->client->invulnerabilityTime = 0;
- // start the kamikze
- G_StartKamikaze( ent );
- break;
-
- case EV_USE_ITEM4: // portal
- if( ent->client->portalID ) {
- DropPortalSource( ent );
- }
- else {
- DropPortalDestination( ent );
- }
- break;
- case EV_USE_ITEM5: // invulnerability
- ent->client->invulnerabilityTime = level.time + 10000;
- break;
-#endif
-
- default:
- break;
- }
- }
-
-}
-
-#ifdef MISSIONPACK
-/*
-==============
-StuckInOtherClient
-==============
-*/
-static int StuckInOtherClient(gentity_t *ent) {
- int i;
- gentity_t *ent2;
-
- ent2 = &g_entities[0];
- for ( i = 0; i < MAX_CLIENTS; i++, ent2++ ) {
- if ( ent2 == ent ) {
- continue;
- }
- if ( !ent2->inuse ) {
- continue;
- }
- if ( !ent2->client ) {
- continue;
- }
- if ( ent2->health <= 0 ) {
- continue;
- }
- //
- if (ent2->r.absmin[0] > ent->r.absmax[0])
- continue;
- if (ent2->r.absmin[1] > ent->r.absmax[1])
- continue;
- if (ent2->r.absmin[2] > ent->r.absmax[2])
- continue;
- if (ent2->r.absmax[0] < ent->r.absmin[0])
- continue;
- if (ent2->r.absmax[1] < ent->r.absmin[1])
- continue;
- if (ent2->r.absmax[2] < ent->r.absmin[2])
- continue;
- return qtrue;
- }
- return qfalse;
-}
-#endif
-
-void BotTestSolid(vec3_t origin);
-
-/*
-==============
-SendPendingPredictableEvents
-==============
-*/
-void SendPendingPredictableEvents( playerState_t *ps ) {
- gentity_t *t;
- int event, seq;
- int extEvent, number;
-
- // if there are still events pending
- if ( ps->entityEventSequence < ps->eventSequence ) {
- // create a temporary entity for this event which is sent to everyone
- // except the client who generated the event
- seq = ps->entityEventSequence & (MAX_PS_EVENTS-1);
- event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );
- // set external event to zero before calling BG_PlayerStateToEntityState
- extEvent = ps->externalEvent;
- ps->externalEvent = 0;
- // create temporary entity for event
- t = G_TempEntity( ps->origin, event );
- number = t->s.number;
- BG_PlayerStateToEntityState( ps, &t->s, qtrue );
- t->s.number = number;
- t->s.eType = ET_EVENTS + event;
- t->s.eFlags |= EF_PLAYER_EVENT;
- t->s.otherEntityNum = ps->clientNum;
- // send to everyone except the client who generated the event
- t->r.svFlags |= SVF_NOTSINGLECLIENT;
- t->r.singleClient = ps->clientNum;
- // set back external event
- ps->externalEvent = extEvent;
- }
-}
-
-/*
-==============
-ClientThink
-
-This will be called once for each client frame, which will
-usually be a couple times for each server frame on fast clients.
-
-If "g_synchronousClients 1" is set, this will be called exactly
-once for each server frame, which makes for smooth demo recording.
-==============
-*/
-void ClientThink_real( gentity_t *ent ) {
- gclient_t *client;
- pmove_t pm;
- int oldEventSequence;
- int msec;
- usercmd_t *ucmd;
-
- client = ent->client;
-
- // don't think if the client is not yet connected (and thus not yet spawned in)
- if (client->pers.connected != CON_CONNECTED) {
- return;
- }
- // mark the time, so the connection sprite can be removed
- ucmd = &ent->client->pers.cmd;
-
- // sanity check the command time to prevent speedup cheating
- if ( ucmd->serverTime > level.time + 200 ) {
- ucmd->serverTime = level.time + 200;
-// G_Printf("serverTime <<<<<\n" );
- }
- if ( ucmd->serverTime < level.time - 1000 ) {
- ucmd->serverTime = level.time - 1000;
-// G_Printf("serverTime >>>>>\n" );
- }
-
- msec = ucmd->serverTime - client->ps.commandTime;
- // following others may result in bad times, but we still want
- // to check for follow toggles
- if ( msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW ) {
- return;
- }
- if ( msec > 200 ) {
- msec = 200;
- }
-
- if ( pmove_msec.integer < 8 ) {
- trap_Cvar_Set("pmove_msec", "8");
- }
- else if (pmove_msec.integer > 33) {
- trap_Cvar_Set("pmove_msec", "33");
- }
-
- if ( pmove_fixed.integer || client->pers.pmoveFixed ) {
- ucmd->serverTime = ((ucmd->serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;
- //if (ucmd->serverTime - client->ps.commandTime <= 0)
- // return;
- }
-
- //
- // check for exiting intermission
- //
- if ( level.intermissiontime ) {
- ClientIntermissionThink( client );
- return;
- }
-
- // spectators don't do much
- if ( client->sess.sessionTeam == TEAM_SPECTATOR ) {
- if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
- return;
- }
- SpectatorThink( ent, ucmd );
- return;
- }
-
- // check for inactivity timer, but never drop the local client of a non-dedicated server
- if ( !ClientInactivityTimer( client ) ) {
- return;
- }
-
- // clear the rewards if time
- if ( level.time > client->rewardTime ) {
- client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- }
-
- if ( client->noclip ) {
- client->ps.pm_type = PM_NOCLIP;
- } else if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
- client->ps.pm_type = PM_DEAD;
- } else {
- client->ps.pm_type = PM_NORMAL;
- }
-
- client->ps.gravity = g_gravity.value;
-
- // set speed
- client->ps.speed = g_speed.value;
-
-#ifdef MISSIONPACK
- if( bg_itemlist[client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
- client->ps.speed *= 1.5;
- }
- else
-#endif
- if ( client->ps.powerups[PW_HASTE] ) {
- client->ps.speed *= 1.3;
- }
-
- // Let go of the hook if we aren't firing
- if ( client->ps.weapon == WP_GRAPPLING_HOOK &&
- client->hook && !( ucmd->buttons & BUTTON_ATTACK ) ) {
- Weapon_HookFree(client->hook);
- }
-
- // set up for pmove
- oldEventSequence = client->ps.eventSequence;
-
- memset (&pm, 0, sizeof(pm));
-
- // check for the hit-scan gauntlet, don't let the action
- // go through as an attack unless it actually hits something
- if ( client->ps.weapon == WP_GAUNTLET && !( ucmd->buttons & BUTTON_TALK ) &&
- ( ucmd->buttons & BUTTON_ATTACK ) && client->ps.weaponTime <= 0 ) {
- pm.gauntletHit = CheckGauntletAttack( ent );
- }
-
- if ( ent->flags & FL_FORCE_GESTURE ) {
- ent->flags &= ~FL_FORCE_GESTURE;
- ent->client->pers.cmd.buttons |= BUTTON_GESTURE;
- }
-
-#ifdef MISSIONPACK
- // check for invulnerability expansion before doing the Pmove
- if (client->ps.powerups[PW_INVULNERABILITY] ) {
- if ( !(client->ps.pm_flags & PMF_INVULEXPAND) ) {
- vec3_t mins = { -42, -42, -42 };
- vec3_t maxs = { 42, 42, 42 };
- vec3_t oldmins, oldmaxs;
-
- VectorCopy (ent->r.mins, oldmins);
- VectorCopy (ent->r.maxs, oldmaxs);
- // expand
- VectorCopy (mins, ent->r.mins);
- VectorCopy (maxs, ent->r.maxs);
- trap_LinkEntity(ent);
- // check if this would get anyone stuck in this player
- if ( !StuckInOtherClient(ent) ) {
- // set flag so the expanded size will be set in PM_CheckDuck
- client->ps.pm_flags |= PMF_INVULEXPAND;
- }
- // set back
- VectorCopy (oldmins, ent->r.mins);
- VectorCopy (oldmaxs, ent->r.maxs);
- trap_LinkEntity(ent);
- }
- }
-#endif
-
- pm.ps = &client->ps;
- pm.cmd = *ucmd;
- if ( pm.ps->pm_type == PM_DEAD ) {
- pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
- }
- else if ( ent->r.svFlags & SVF_BOT ) {
- pm.tracemask = MASK_PLAYERSOLID | CONTENTS_BOTCLIP;
- }
- else {
- pm.tracemask = MASK_PLAYERSOLID;
- }
- pm.trace = trap_Trace;
- pm.pointcontents = trap_PointContents;
- pm.debugLevel = g_debugMove.integer;
- pm.noFootsteps = ( g_dmflags.integer & DF_NO_FOOTSTEPS ) > 0;
-
- pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed;
- pm.pmove_msec = pmove_msec.integer;
-
- VectorCopy( client->ps.origin, client->oldOrigin );
-
-#ifdef MISSIONPACK
- if (level.intermissionQueued != 0 && g_singlePlayer.integer) {
- if ( level.time - level.intermissionQueued >= 1000 ) {
- pm.cmd.buttons = 0;
- pm.cmd.forwardmove = 0;
- pm.cmd.rightmove = 0;
- pm.cmd.upmove = 0;
- if ( level.time - level.intermissionQueued >= 2000 && level.time - level.intermissionQueued <= 2500 ) {
- trap_SendConsoleCommand( EXEC_APPEND, "centerview\n");
- }
- ent->client->ps.pm_type = PM_SPINTERMISSION;
- }
- }
- Pmove (&pm);
-#else
- Pmove (&pm);
-#endif
-
- // save results of pmove
- if ( ent->client->ps.eventSequence != oldEventSequence ) {
- ent->eventTime = level.time;
- }
- if (g_smoothClients.integer) {
- BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
- }
- else {
- BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
- }
- SendPendingPredictableEvents( &ent->client->ps );
-
- if ( !( ent->client->ps.eFlags & EF_FIRING ) ) {
- client->fireHeld = qfalse; // for grapple
- }
-
- // use the snapped origin for linking so it matches client predicted versions
- VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );
-
- VectorCopy (pm.mins, ent->r.mins);
- VectorCopy (pm.maxs, ent->r.maxs);
-
- ent->waterlevel = pm.waterlevel;
- ent->watertype = pm.watertype;
-
- // execute client events
- ClientEvents( ent, oldEventSequence );
-
- // link entity now, after any personal teleporters have been used
- trap_LinkEntity (ent);
- if ( !ent->client->noclip ) {
- G_TouchTriggers( ent );
- }
-
- // NOTE: now copy the exact origin over otherwise clients can be snapped into solid
- VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
-
- //test for solid areas in the AAS file
- BotTestAAS(ent->r.currentOrigin);
-
- // touch other objects
- ClientImpacts( ent, &pm );
-
- // save results of triggers and client events
- if (ent->client->ps.eventSequence != oldEventSequence) {
- ent->eventTime = level.time;
- }
-
- // swap and latch button actions
- client->oldbuttons = client->buttons;
- client->buttons = ucmd->buttons;
- client->latched_buttons |= client->buttons & ~client->oldbuttons;
-
- // check for respawning
- if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
- // wait for the attack button to be pressed
- if ( level.time > client->respawnTime ) {
- // forcerespawn is to prevent users from waiting out powerups
- if ( g_forcerespawn.integer > 0 &&
- ( level.time - client->respawnTime ) > g_forcerespawn.integer * 1000 ) {
- respawn( ent );
- return;
- }
-
- // pressing attack or use is the normal respawn method
- if ( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) {
- respawn( ent );
- }
- }
- return;
- }
-
- // perform once-a-second actions
- ClientTimerActions( ent, msec );
-}
-
-/*
-==================
-ClientThink
-
-A new command has arrived from the client
-==================
-*/
-void ClientThink( int clientNum ) {
- gentity_t *ent;
-
- ent = g_entities + clientNum;
- trap_GetUsercmd( clientNum, &ent->client->pers.cmd );
-
- // mark the time we got info, so we can display the
- // phone jack if they don't get any for a while
- ent->client->lastCmdTime = level.time;
-
- if ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) {
- ClientThink_real( ent );
- }
-}
-
-
-void G_RunClient( gentity_t *ent ) {
- if ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) {
- return;
- }
- ent->client->pers.cmd.serverTime = level.time;
- ClientThink_real( ent );
-}
-
-
-/*
-==================
-SpectatorClientEndFrame
-
-==================
-*/
-void SpectatorClientEndFrame( gentity_t *ent ) {
- gclient_t *cl;
-
- // if we are doing a chase cam or a remote view, grab the latest info
- if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {
- int clientNum, flags;
-
- clientNum = ent->client->sess.spectatorClient;
-
- // team follow1 and team follow2 go to whatever clients are playing
- if ( clientNum == -1 ) {
- clientNum = level.follow1;
- } else if ( clientNum == -2 ) {
- clientNum = level.follow2;
- }
- if ( clientNum >= 0 ) {
- cl = &level.clients[ clientNum ];
- if ( cl->pers.connected == CON_CONNECTED && cl->sess.sessionTeam != TEAM_SPECTATOR ) {
- flags = (cl->ps.eFlags & ~(EF_VOTED | EF_TEAMVOTED)) | (ent->client->ps.eFlags & (EF_VOTED | EF_TEAMVOTED));
- ent->client->ps = cl->ps;
- ent->client->ps.pm_flags |= PMF_FOLLOW;
- ent->client->ps.eFlags = flags;
- return;
- } else {
- // drop them to free spectators unless they are dedicated camera followers
- if ( ent->client->sess.spectatorClient >= 0 ) {
- ent->client->sess.spectatorState = SPECTATOR_FREE;
- ClientBegin( ent->client - level.clients );
- }
- }
- }
- }
-
- if ( ent->client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
- ent->client->ps.pm_flags |= PMF_SCOREBOARD;
- } else {
- ent->client->ps.pm_flags &= ~PMF_SCOREBOARD;
- }
-}
-
-/*
-==============
-ClientEndFrame
-
-Called at the end of each server frame for each connected client
-A fast client will have multiple ClientThink for each ClientEdFrame,
-while a slow client may have multiple ClientEndFrame between ClientThink.
-==============
-*/
-void ClientEndFrame( gentity_t *ent ) {
- int i;
- clientPersistant_t *pers;
-
- if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
- SpectatorClientEndFrame( ent );
- return;
- }
-
- pers = &ent->client->pers;
-
- // turn off any expired powerups
- for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
- if ( ent->client->ps.powerups[ i ] < level.time ) {
- ent->client->ps.powerups[ i ] = 0;
- }
- }
-
-#ifdef MISSIONPACK
- // set powerup for player animation
- if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
- ent->client->ps.powerups[PW_GUARD] = level.time;
- }
- if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
- ent->client->ps.powerups[PW_SCOUT] = level.time;
- }
- if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_DOUBLER ) {
- ent->client->ps.powerups[PW_DOUBLER] = level.time;
- }
- if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
- ent->client->ps.powerups[PW_AMMOREGEN] = level.time;
- }
- if ( ent->client->invulnerabilityTime > level.time ) {
- ent->client->ps.powerups[PW_INVULNERABILITY] = level.time;
- }
-#endif
-
- // save network bandwidth
-#if 0
- if ( !g_synchronousClients->integer && ent->client->ps.pm_type == PM_NORMAL ) {
- // FIXME: this must change eventually for non-sync demo recording
- VectorClear( ent->client->ps.viewangles );
- }
-#endif
-
- //
- // If the end of unit layout is displayed, don't give
- // the player any normal movement attributes
- //
- if ( level.intermissiontime ) {
- return;
- }
-
- // burn from lava, etc
- P_WorldEffects (ent);
-
- // apply all the damage taken this frame
- P_DamageFeedback (ent);
-
- // add the EF_CONNECTION flag if we haven't gotten commands recently
- if ( level.time - ent->client->lastCmdTime > 1000 ) {
- ent->s.eFlags |= EF_CONNECTION;
- } else {
- ent->s.eFlags &= ~EF_CONNECTION;
- }
-
- ent->client->ps.stats[STAT_HEALTH] = ent->health; // FIXME: get rid of ent->health...
-
- G_SetClientSound (ent);
-
- // set the latest infor
- if (g_smoothClients.integer) {
- BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
- }
- else {
- BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
- }
- SendPendingPredictableEvents( &ent->client->ps );
-
- // set the bit for the reachability area the client is currently in
-// i = trap_AAS_PointReachabilityAreaIndex( ent->client->ps.origin );
-// ent->client->areabits[i >> 3] |= 1 << (i & 7);
-}
-
-
diff --git a/engine/code/game/g_arenas.c b/engine/code/game/g_arenas.c
deleted file mode 100644
index da96c47..0000000
--- a/engine/code/game/g_arenas.c
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-//
-// g_arenas.c
-//
-
-#include "g_local.h"
-
-
-gentity_t *podium1;
-gentity_t *podium2;
-gentity_t *podium3;
-
-
-/*
-==================
-UpdateTournamentInfo
-==================
-*/
-void UpdateTournamentInfo( void ) {
- int i;
- gentity_t *player;
- int playerClientNum;
- int n, accuracy, perfect, msglen;
- int buflen;
-#ifdef MISSIONPACK
- int score1, score2;
- qboolean won;
-#endif
- char buf[32];
- char msg[MAX_STRING_CHARS];
-
- // find the real player
- player = NULL;
- for (i = 0; i < level.maxclients; i++ ) {
- player = &g_entities[i];
- if ( !player->inuse ) {
- continue;
- }
- if ( !( player->r.svFlags & SVF_BOT ) ) {
- break;
- }
- }
- // this should never happen!
- if ( !player || i == level.maxclients ) {
- return;
- }
- playerClientNum = i;
-
- CalculateRanks();
-
- if ( level.clients[playerClientNum].sess.sessionTeam == TEAM_SPECTATOR ) {
-#ifdef MISSIONPACK
- Com_sprintf( msg, sizeof(msg), "postgame %i %i 0 0 0 0 0 0 0 0 0 0 0", level.numNonSpectatorClients, playerClientNum );
-#else
- Com_sprintf( msg, sizeof(msg), "postgame %i %i 0 0 0 0 0 0", level.numNonSpectatorClients, playerClientNum );
-#endif
- }
- else {
- if( player->client->accuracy_shots ) {
- accuracy = player->client->accuracy_hits * 100 / player->client->accuracy_shots;
- }
- else {
- accuracy = 0;
- }
-#ifdef MISSIONPACK
- won = qfalse;
- if (g_gametype.integer >= GT_CTF) {
- score1 = level.teamScores[TEAM_RED];
- score2 = level.teamScores[TEAM_BLUE];
- if (level.clients[playerClientNum].sess.sessionTeam == TEAM_RED) {
- won = (level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE]);
- } else {
- won = (level.teamScores[TEAM_BLUE] > level.teamScores[TEAM_RED]);
- }
- } else {
- if (&level.clients[playerClientNum] == &level.clients[ level.sortedClients[0] ]) {
- won = qtrue;
- score1 = level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE];
- score2 = level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE];
- } else {
- score2 = level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE];
- score1 = level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE];
- }
- }
- if (won && player->client->ps.persistant[PERS_KILLED] == 0) {
- perfect = 1;
- } else {
- perfect = 0;
- }
- Com_sprintf( msg, sizeof(msg), "postgame %i %i %i %i %i %i %i %i %i %i %i %i %i %i", level.numNonSpectatorClients, playerClientNum, accuracy,
- player->client->ps.persistant[PERS_IMPRESSIVE_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT],player->client->ps.persistant[PERS_DEFEND_COUNT],
- player->client->ps.persistant[PERS_ASSIST_COUNT], player->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE],
- perfect, score1, score2, level.time, player->client->ps.persistant[PERS_CAPTURES] );
-
-#else
- perfect = ( level.clients[playerClientNum].ps.persistant[PERS_RANK] == 0 && player->client->ps.persistant[PERS_KILLED] == 0 ) ? 1 : 0;
- Com_sprintf( msg, sizeof(msg), "postgame %i %i %i %i %i %i %i %i", level.numNonSpectatorClients, playerClientNum, accuracy,
- player->client->ps.persistant[PERS_IMPRESSIVE_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT],
- player->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE],
- perfect );
-#endif
- }
-
- msglen = strlen( msg );
- for( i = 0; i < level.numNonSpectatorClients; i++ ) {
- n = level.sortedClients[i];
- Com_sprintf( buf, sizeof(buf), " %i %i %i", n, level.clients[n].ps.persistant[PERS_RANK], level.clients[n].ps.persistant[PERS_SCORE] );
- buflen = strlen( buf );
- if( msglen + buflen + 1 >= sizeof(msg) ) {
- break;
- }
- strcat( msg, buf );
- }
- trap_SendConsoleCommand( EXEC_APPEND, msg );
-}
-
-
-static gentity_t *SpawnModelOnVictoryPad( gentity_t *pad, vec3_t offset, gentity_t *ent, int place ) {
- gentity_t *body;
- vec3_t vec;
- vec3_t f, r, u;
-
- body = G_Spawn();
- if ( !body ) {
- G_Printf( S_COLOR_RED "ERROR: out of gentities\n" );
- return NULL;
- }
-
- body->classname = ent->client->pers.netname;
- body->client = ent->client;
- body->s = ent->s;
- body->s.eType = ET_PLAYER; // could be ET_INVISIBLE
- body->s.eFlags = 0; // clear EF_TALK, etc
- body->s.powerups = 0; // clear powerups
- body->s.loopSound = 0; // clear lava burning
- body->s.number = body - g_entities;
- body->timestamp = level.time;
- body->physicsObject = qtrue;
- body->physicsBounce = 0; // don't bounce
- body->s.event = 0;
- body->s.pos.trType = TR_STATIONARY;
- body->s.groundEntityNum = ENTITYNUM_WORLD;
- body->s.legsAnim = LEGS_IDLE;
- body->s.torsoAnim = TORSO_STAND;
- if( body->s.weapon == WP_NONE ) {
- body->s.weapon = WP_MACHINEGUN;
- }
- if( body->s.weapon == WP_GAUNTLET) {
- body->s.torsoAnim = TORSO_STAND2;
- }
- body->s.event = 0;
- body->r.svFlags = ent->r.svFlags;
- VectorCopy (ent->r.mins, body->r.mins);
- VectorCopy (ent->r.maxs, body->r.maxs);
- VectorCopy (ent->r.absmin, body->r.absmin);
- VectorCopy (ent->r.absmax, body->r.absmax);
- body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
- body->r.contents = CONTENTS_BODY;
- body->r.ownerNum = ent->r.ownerNum;
- body->takedamage = qfalse;
-
- VectorSubtract( level.intermission_origin, pad->r.currentOrigin, vec );
- vectoangles( vec, body->s.apos.trBase );
- body->s.apos.trBase[PITCH] = 0;
- body->s.apos.trBase[ROLL] = 0;
-
- AngleVectors( body->s.apos.trBase, f, r, u );
- VectorMA( pad->r.currentOrigin, offset[0], f, vec );
- VectorMA( vec, offset[1], r, vec );
- VectorMA( vec, offset[2], u, vec );
-
- G_SetOrigin( body, vec );
-
- trap_LinkEntity (body);
-
- body->count = place;
-
- return body;
-}
-
-
-static void CelebrateStop( gentity_t *player ) {
- int anim;
-
- if( player->s.weapon == WP_GAUNTLET) {
- anim = TORSO_STAND2;
- }
- else {
- anim = TORSO_STAND;
- }
- player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-}
-
-
-#define TIMER_GESTURE (34*66+50)
-static void CelebrateStart( gentity_t *player ) {
- player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | TORSO_GESTURE;
- player->nextthink = level.time + TIMER_GESTURE;
- player->think = CelebrateStop;
-
- /*
- player->client->ps.events[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = EV_TAUNT;
- player->client->ps.eventParms[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = 0;
- player->client->ps.eventSequence++;
- */
- G_AddEvent(player, EV_TAUNT, 0);
-}
-
-
-static vec3_t offsetFirst = {0, 0, 74};
-static vec3_t offsetSecond = {-10, 60, 54};
-static vec3_t offsetThird = {-19, -60, 45};
-
-static void PodiumPlacementThink( gentity_t *podium ) {
- vec3_t vec;
- vec3_t origin;
- vec3_t f, r, u;
-
- podium->nextthink = level.time + 100;
-
- AngleVectors( level.intermission_angle, vec, NULL, NULL );
- VectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( "g_podiumDist" ), vec, origin );
- origin[2] -= trap_Cvar_VariableIntegerValue( "g_podiumDrop" );
- G_SetOrigin( podium, origin );
-
- if( podium1 ) {
- VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
- vectoangles( vec, podium1->s.apos.trBase );
- podium1->s.apos.trBase[PITCH] = 0;
- podium1->s.apos.trBase[ROLL] = 0;
-
- AngleVectors( podium1->s.apos.trBase, f, r, u );
- VectorMA( podium->r.currentOrigin, offsetFirst[0], f, vec );
- VectorMA( vec, offsetFirst[1], r, vec );
- VectorMA( vec, offsetFirst[2], u, vec );
-
- G_SetOrigin( podium1, vec );
- }
-
- if( podium2 ) {
- VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
- vectoangles( vec, podium2->s.apos.trBase );
- podium2->s.apos.trBase[PITCH] = 0;
- podium2->s.apos.trBase[ROLL] = 0;
-
- AngleVectors( podium2->s.apos.trBase, f, r, u );
- VectorMA( podium->r.currentOrigin, offsetSecond[0], f, vec );
- VectorMA( vec, offsetSecond[1], r, vec );
- VectorMA( vec, offsetSecond[2], u, vec );
-
- G_SetOrigin( podium2, vec );
- }
-
- if( podium3 ) {
- VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
- vectoangles( vec, podium3->s.apos.trBase );
- podium3->s.apos.trBase[PITCH] = 0;
- podium3->s.apos.trBase[ROLL] = 0;
-
- AngleVectors( podium3->s.apos.trBase, f, r, u );
- VectorMA( podium->r.currentOrigin, offsetThird[0], f, vec );
- VectorMA( vec, offsetThird[1], r, vec );
- VectorMA( vec, offsetThird[2], u, vec );
-
- G_SetOrigin( podium3, vec );
- }
-}
-
-
-static gentity_t *SpawnPodium( void ) {
- gentity_t *podium;
- vec3_t vec;
- vec3_t origin;
-
- podium = G_Spawn();
- if ( !podium ) {
- return NULL;
- }
-
- podium->classname = "podium";
- podium->s.eType = ET_GENERAL;
- podium->s.number = podium - g_entities;
- podium->clipmask = CONTENTS_SOLID;
- podium->r.contents = CONTENTS_SOLID;
- podium->s.modelindex = G_ModelIndex( SP_PODIUM_MODEL );
-
- AngleVectors( level.intermission_angle, vec, NULL, NULL );
- VectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( "g_podiumDist" ), vec, origin );
- origin[2] -= trap_Cvar_VariableIntegerValue( "g_podiumDrop" );
- G_SetOrigin( podium, origin );
-
- VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
- podium->s.apos.trBase[YAW] = vectoyaw( vec );
- trap_LinkEntity (podium);
-
- podium->think = PodiumPlacementThink;
- podium->nextthink = level.time + 100;
- return podium;
-}
-
-
-/*
-==================
-SpawnModelsOnVictoryPads
-==================
-*/
-void SpawnModelsOnVictoryPads( void ) {
- gentity_t *player;
- gentity_t *podium;
-
- podium1 = NULL;
- podium2 = NULL;
- podium3 = NULL;
-
- podium = SpawnPodium();
-
- player = SpawnModelOnVictoryPad( podium, offsetFirst, &g_entities[level.sortedClients[0]],
- level.clients[ level.sortedClients[0] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
- if ( player ) {
- player->nextthink = level.time + 2000;
- player->think = CelebrateStart;
- podium1 = player;
- }
-
- player = SpawnModelOnVictoryPad( podium, offsetSecond, &g_entities[level.sortedClients[1]],
- level.clients[ level.sortedClients[1] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
- if ( player ) {
- podium2 = player;
- }
-
- if ( level.numNonSpectatorClients > 2 ) {
- player = SpawnModelOnVictoryPad( podium, offsetThird, &g_entities[level.sortedClients[2]],
- level.clients[ level.sortedClients[2] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
- if ( player ) {
- podium3 = player;
- }
- }
-}
-
-
-/*
-===============
-Svcmd_AbortPodium_f
-===============
-*/
-void Svcmd_AbortPodium_f( void ) {
- if( g_gametype.integer != GT_SINGLE_PLAYER ) {
- return;
- }
-
- if( podium1 ) {
- podium1->nextthink = level.time;
- podium1->think = CelebrateStop;
- }
-}
diff --git a/engine/code/game/g_bot.c b/engine/code/game/g_bot.c
deleted file mode 100644
index 4c9cf8c..0000000
--- a/engine/code/game/g_bot.c
+++ /dev/null
@@ -1,1013 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// g_bot.c
-
-#include "g_local.h"
-
-
-static int g_numBots;
-static char *g_botInfos[MAX_BOTS];
-
-
-int g_numArenas;
-static char *g_arenaInfos[MAX_ARENAS];
-
-
-#define BOT_BEGIN_DELAY_BASE 2000
-#define BOT_BEGIN_DELAY_INCREMENT 1500
-
-#define BOT_SPAWN_QUEUE_DEPTH 16
-
-typedef struct {
- int clientNum;
- int spawnTime;
-} botSpawnQueue_t;
-
-static botSpawnQueue_t botSpawnQueue[BOT_SPAWN_QUEUE_DEPTH];
-
-vmCvar_t bot_minplayers;
-
-extern gentity_t *podium1;
-extern gentity_t *podium2;
-extern gentity_t *podium3;
-
-float trap_Cvar_VariableValue( const char *var_name ) {
- char buf[128];
-
- trap_Cvar_VariableStringBuffer(var_name, buf, sizeof(buf));
- return atof(buf);
-}
-
-
-
-/*
-===============
-G_ParseInfos
-===============
-*/
-int G_ParseInfos( char *buf, int max, char *infos[] ) {
- char *token;
- int count;
- char key[MAX_TOKEN_CHARS];
- char info[MAX_INFO_STRING];
-
- count = 0;
-
- while ( 1 ) {
- token = COM_Parse( &buf );
- if ( !token[0] ) {
- break;
- }
- if ( strcmp( token, "{" ) ) {
- Com_Printf( "Missing { in info file\n" );
- break;
- }
-
- if ( count == max ) {
- Com_Printf( "Max infos exceeded\n" );
- break;
- }
-
- info[0] = '\0';
- while ( 1 ) {
- token = COM_ParseExt( &buf, qtrue );
- if ( !token[0] ) {
- Com_Printf( "Unexpected end of info file\n" );
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- Q_strncpyz( key, token, sizeof( key ) );
-
- token = COM_ParseExt( &buf, qfalse );
- if ( !token[0] ) {
- strcpy( token, "<NULL>" );
- }
- Info_SetValueForKey( info, key, token );
- }
- //NOTE: extra space for arena number
- infos[count] = G_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
- if (infos[count]) {
- strcpy(infos[count], info);
- count++;
- }
- }
- return count;
-}
-
-/*
-===============
-G_LoadArenasFromFile
-===============
-*/
-static void G_LoadArenasFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_ARENAS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Printf( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_ARENAS_TEXT ) {
- trap_Printf( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_ARENAS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- g_numArenas += G_ParseInfos( buf, MAX_ARENAS - g_numArenas, &g_arenaInfos[g_numArenas] );
-}
-
-/*
-===============
-G_LoadArenas
-===============
-*/
-static void G_LoadArenas( void ) {
- int numdirs;
- vmCvar_t arenasFile;
- char filename[128];
- char dirlist[1024];
- char* dirptr;
- int i, n;
- int dirlen;
-
- g_numArenas = 0;
-
- trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
- if( *arenasFile.string ) {
- G_LoadArenasFromFile(arenasFile.string);
- }
- else {
- G_LoadArenasFromFile("scripts/arenas.txt");
- }
-
- // get all arenas from .arena files
- numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- G_LoadArenasFromFile(filename);
- }
- trap_Printf( va( "%i arenas parsed\n", g_numArenas ) );
-
- for( n = 0; n < g_numArenas; n++ ) {
- Info_SetValueForKey( g_arenaInfos[n], "num", va( "%i", n ) );
- }
-}
-
-
-/*
-===============
-G_GetArenaInfoByNumber
-===============
-*/
-const char *G_GetArenaInfoByMap( const char *map ) {
- int n;
-
- for( n = 0; n < g_numArenas; n++ ) {
- if( Q_stricmp( Info_ValueForKey( g_arenaInfos[n], "map" ), map ) == 0 ) {
- return g_arenaInfos[n];
- }
- }
-
- return NULL;
-}
-
-
-/*
-=================
-PlayerIntroSound
-=================
-*/
-static void PlayerIntroSound( const char *modelAndSkin ) {
- char model[MAX_QPATH];
- char *skin;
-
- Q_strncpyz( model, modelAndSkin, sizeof(model) );
- skin = Q_strrchr( model, '/' );
- if ( skin ) {
- *skin++ = '\0';
- }
- else {
- skin = model;
- }
-
- if( Q_stricmp( skin, "default" ) == 0 ) {
- skin = model;
- }
-
- trap_SendConsoleCommand( EXEC_APPEND, va( "play sound/player/announce/%s.wav\n", skin ) );
-}
-
-/*
-===============
-G_AddRandomBot
-===============
-*/
-void G_AddRandomBot( int team ) {
- int i, n, num;
- float skill;
- char *value, netname[36], *teamstr;
- gclient_t *cl;
-
- num = 0;
- for ( n = 0; n < g_numBots ; n++ ) {
- value = Info_ValueForKey( g_botInfos[n], "name" );
- //
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
- continue;
- }
- if ( team >= 0 && cl->sess.sessionTeam != team ) {
- continue;
- }
- if ( !Q_stricmp( value, cl->pers.netname ) ) {
- break;
- }
- }
- if (i >= g_maxclients.integer) {
- num++;
- }
- }
- num = random() * num;
- for ( n = 0; n < g_numBots ; n++ ) {
- value = Info_ValueForKey( g_botInfos[n], "name" );
- //
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
- continue;
- }
- if ( team >= 0 && cl->sess.sessionTeam != team ) {
- continue;
- }
- if ( !Q_stricmp( value, cl->pers.netname ) ) {
- break;
- }
- }
- if (i >= g_maxclients.integer) {
- num--;
- if (num <= 0) {
- skill = trap_Cvar_VariableValue( "g_spSkill" );
- if (team == TEAM_RED) teamstr = "red";
- else if (team == TEAM_BLUE) teamstr = "blue";
- else teamstr = "";
- strncpy(netname, value, sizeof(netname)-1);
- netname[sizeof(netname)-1] = '\0';
- Q_CleanStr(netname);
- trap_SendConsoleCommand( EXEC_INSERT, va("addbot %s %f %s %i\n", netname, skill, teamstr, 0) );
- return;
- }
- }
- }
-}
-
-/*
-===============
-G_RemoveRandomBot
-===============
-*/
-int G_RemoveRandomBot( int team ) {
- int i;
- gclient_t *cl;
-
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
- continue;
- }
- if ( team >= 0 && cl->sess.sessionTeam != team ) {
- continue;
- }
- trap_SendConsoleCommand( EXEC_INSERT, va("clientkick %d\n", cl->ps.clientNum) );
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-===============
-G_CountHumanPlayers
-===============
-*/
-int G_CountHumanPlayers( int team ) {
- int i, num;
- gclient_t *cl;
-
- num = 0;
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT ) {
- continue;
- }
- if ( team >= 0 && cl->sess.sessionTeam != team ) {
- continue;
- }
- num++;
- }
- return num;
-}
-
-/*
-===============
-G_CountBotPlayers
-===============
-*/
-int G_CountBotPlayers( int team ) {
- int i, n, num;
- gclient_t *cl;
-
- num = 0;
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
- continue;
- }
- if ( team >= 0 && cl->sess.sessionTeam != team ) {
- continue;
- }
- num++;
- }
- for( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {
- if( !botSpawnQueue[n].spawnTime ) {
- continue;
- }
- if ( botSpawnQueue[n].spawnTime > level.time ) {
- continue;
- }
- num++;
- }
- return num;
-}
-
-/*
-===============
-G_CheckMinimumPlayers
-===============
-*/
-void G_CheckMinimumPlayers( void ) {
- int minplayers;
- int humanplayers, botplayers;
- static int checkminimumplayers_time;
-
- if (level.intermissiontime) return;
- //only check once each 10 seconds
- if (checkminimumplayers_time > level.time - 10000) {
- return;
- }
- checkminimumplayers_time = level.time;
- trap_Cvar_Update(&bot_minplayers);
- minplayers = bot_minplayers.integer;
- if (minplayers <= 0) return;
-
- if (g_gametype.integer >= GT_TEAM) {
- if (minplayers >= g_maxclients.integer / 2) {
- minplayers = (g_maxclients.integer / 2) -1;
- }
-
- humanplayers = G_CountHumanPlayers( TEAM_RED );
- botplayers = G_CountBotPlayers( TEAM_RED );
- //
- if (humanplayers + botplayers < minplayers) {
- G_AddRandomBot( TEAM_RED );
- } else if (humanplayers + botplayers > minplayers && botplayers) {
- G_RemoveRandomBot( TEAM_RED );
- }
- //
- humanplayers = G_CountHumanPlayers( TEAM_BLUE );
- botplayers = G_CountBotPlayers( TEAM_BLUE );
- //
- if (humanplayers + botplayers < minplayers) {
- G_AddRandomBot( TEAM_BLUE );
- } else if (humanplayers + botplayers > minplayers && botplayers) {
- G_RemoveRandomBot( TEAM_BLUE );
- }
- }
- else if (g_gametype.integer == GT_TOURNAMENT ) {
- if (minplayers >= g_maxclients.integer) {
- minplayers = g_maxclients.integer-1;
- }
- humanplayers = G_CountHumanPlayers( -1 );
- botplayers = G_CountBotPlayers( -1 );
- //
- if (humanplayers + botplayers < minplayers) {
- G_AddRandomBot( TEAM_FREE );
- } else if (humanplayers + botplayers > minplayers && botplayers) {
- // try to remove spectators first
- if (!G_RemoveRandomBot( TEAM_SPECTATOR )) {
- // just remove the bot that is playing
- G_RemoveRandomBot( -1 );
- }
- }
- }
- else if (g_gametype.integer == GT_FFA) {
- if (minplayers >= g_maxclients.integer) {
- minplayers = g_maxclients.integer-1;
- }
- humanplayers = G_CountHumanPlayers( TEAM_FREE );
- botplayers = G_CountBotPlayers( TEAM_FREE );
- //
- if (humanplayers + botplayers < minplayers) {
- G_AddRandomBot( TEAM_FREE );
- } else if (humanplayers + botplayers > minplayers && botplayers) {
- G_RemoveRandomBot( TEAM_FREE );
- }
- }
-}
-
-/*
-===============
-G_CheckBotSpawn
-===============
-*/
-void G_CheckBotSpawn( void ) {
- int n;
- char userinfo[MAX_INFO_VALUE];
-
- G_CheckMinimumPlayers();
-
- for( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {
- if( !botSpawnQueue[n].spawnTime ) {
- continue;
- }
- if ( botSpawnQueue[n].spawnTime > level.time ) {
- continue;
- }
- ClientBegin( botSpawnQueue[n].clientNum );
- botSpawnQueue[n].spawnTime = 0;
-
- if( g_gametype.integer == GT_SINGLE_PLAYER ) {
- trap_GetUserinfo( botSpawnQueue[n].clientNum, userinfo, sizeof(userinfo) );
- PlayerIntroSound( Info_ValueForKey (userinfo, "model") );
- }
- }
-}
-
-
-/*
-===============
-AddBotToSpawnQueue
-===============
-*/
-static void AddBotToSpawnQueue( int clientNum, int delay ) {
- int n;
-
- for( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {
- if( !botSpawnQueue[n].spawnTime ) {
- botSpawnQueue[n].spawnTime = level.time + delay;
- botSpawnQueue[n].clientNum = clientNum;
- return;
- }
- }
-
- G_Printf( S_COLOR_YELLOW "Unable to delay spawn\n" );
- ClientBegin( clientNum );
-}
-
-
-/*
-===============
-G_RemoveQueuedBotBegin
-
-Called on client disconnect to make sure the delayed spawn
-doesn't happen on a freed index
-===============
-*/
-void G_RemoveQueuedBotBegin( int clientNum ) {
- int n;
-
- for( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {
- if( botSpawnQueue[n].clientNum == clientNum ) {
- botSpawnQueue[n].spawnTime = 0;
- return;
- }
- }
-}
-
-
-/*
-===============
-G_BotConnect
-===============
-*/
-qboolean G_BotConnect( int clientNum, qboolean restart ) {
- bot_settings_t settings;
- char userinfo[MAX_INFO_STRING];
-
- trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
-
- Q_strncpyz( settings.characterfile, Info_ValueForKey( userinfo, "characterfile" ), sizeof(settings.characterfile) );
- settings.skill = atof( Info_ValueForKey( userinfo, "skill" ) );
- Q_strncpyz( settings.team, Info_ValueForKey( userinfo, "team" ), sizeof(settings.team) );
-
- if (!BotAISetupClient( clientNum, &settings, restart )) {
- trap_DropClient( clientNum, "BotAISetupClient failed" );
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-===============
-G_AddBot
-===============
-*/
-static void G_AddBot( const char *name, float skill, const char *team, int delay, char *altname) {
- int clientNum;
- char *botinfo;
- gentity_t *bot;
- char *key;
- char *s;
- char *botname;
- char *model;
- char *headmodel;
- char userinfo[MAX_INFO_STRING];
-
- // get the botinfo from bots.txt
- botinfo = G_GetBotInfoByName( name );
- if ( !botinfo ) {
- G_Printf( S_COLOR_RED "Error: Bot '%s' not defined\n", name );
- return;
- }
-
- // create the bot's userinfo
- userinfo[0] = '\0';
-
- botname = Info_ValueForKey( botinfo, "funname" );
- if( !botname[0] ) {
- botname = Info_ValueForKey( botinfo, "name" );
- }
- // check for an alternative name
- if (altname && altname[0]) {
- botname = altname;
- }
- Info_SetValueForKey( userinfo, "name", botname );
- Info_SetValueForKey( userinfo, "rate", "25000" );
- Info_SetValueForKey( userinfo, "snaps", "20" );
- Info_SetValueForKey( userinfo, "skill", va("%1.2f", skill) );
-
- if ( skill >= 1 && skill < 2 ) {
- Info_SetValueForKey( userinfo, "handicap", "50" );
- }
- else if ( skill >= 2 && skill < 3 ) {
- Info_SetValueForKey( userinfo, "handicap", "70" );
- }
- else if ( skill >= 3 && skill < 4 ) {
- Info_SetValueForKey( userinfo, "handicap", "90" );
- }
-
- key = "model";
- model = Info_ValueForKey( botinfo, key );
- if ( !*model ) {
- model = "visor/default";
- }
- Info_SetValueForKey( userinfo, key, model );
- key = "team_model";
- Info_SetValueForKey( userinfo, key, model );
-
- key = "headmodel";
- headmodel = Info_ValueForKey( botinfo, key );
- if ( !*headmodel ) {
- headmodel = model;
- }
- Info_SetValueForKey( userinfo, key, headmodel );
- key = "team_headmodel";
- Info_SetValueForKey( userinfo, key, headmodel );
-
- key = "gender";
- s = Info_ValueForKey( botinfo, key );
- if ( !*s ) {
- s = "male";
- }
- Info_SetValueForKey( userinfo, "sex", s );
-
- key = "color1";
- s = Info_ValueForKey( botinfo, key );
- if ( !*s ) {
- s = "4";
- }
- Info_SetValueForKey( userinfo, key, s );
-
- key = "color2";
- s = Info_ValueForKey( botinfo, key );
- if ( !*s ) {
- s = "5";
- }
- Info_SetValueForKey( userinfo, key, s );
-
- s = Info_ValueForKey(botinfo, "aifile");
- if (!*s ) {
- trap_Printf( S_COLOR_RED "Error: bot has no aifile specified\n" );
- return;
- }
-
- // have the server allocate a client slot
- clientNum = trap_BotAllocateClient();
- if ( clientNum == -1 ) {
- G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" );
- G_Printf( S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n" );
- return;
- }
-
- // initialize the bot settings
- if( !team || !*team ) {
- if( g_gametype.integer >= GT_TEAM ) {
- if( PickTeam(clientNum) == TEAM_RED) {
- team = "red";
- }
- else {
- team = "blue";
- }
- }
- else {
- team = "red";
- }
- }
- Info_SetValueForKey( userinfo, "characterfile", Info_ValueForKey( botinfo, "aifile" ) );
- Info_SetValueForKey( userinfo, "skill", va( "%5.2f", skill ) );
- Info_SetValueForKey( userinfo, "team", team );
-
- bot = &g_entities[ clientNum ];
- bot->r.svFlags |= SVF_BOT;
- bot->inuse = qtrue;
-
- // register the userinfo
- trap_SetUserinfo( clientNum, userinfo );
-
- // have it connect to the game as a normal client
- if ( ClientConnect( clientNum, qtrue, qtrue ) ) {
- return;
- }
-
- if( delay == 0 ) {
- ClientBegin( clientNum );
- return;
- }
-
- AddBotToSpawnQueue( clientNum, delay );
-}
-
-
-/*
-===============
-Svcmd_AddBot_f
-===============
-*/
-void Svcmd_AddBot_f( void ) {
- float skill;
- int delay;
- char name[MAX_TOKEN_CHARS];
- char altname[MAX_TOKEN_CHARS];
- char string[MAX_TOKEN_CHARS];
- char team[MAX_TOKEN_CHARS];
-
- // are bots enabled?
- if ( !trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
- return;
- }
-
- // name
- trap_Argv( 1, name, sizeof( name ) );
- if ( !name[0] ) {
- trap_Printf( "Usage: Addbot <botname> [skill 1-5] [team] [msec delay] [altname]\n" );
- return;
- }
-
- // skill
- trap_Argv( 2, string, sizeof( string ) );
- if ( !string[0] ) {
- skill = 4;
- }
- else {
- skill = atof( string );
- }
-
- // team
- trap_Argv( 3, team, sizeof( team ) );
-
- // delay
- trap_Argv( 4, string, sizeof( string ) );
- if ( !string[0] ) {
- delay = 0;
- }
- else {
- delay = atoi( string );
- }
-
- // alternative name
- trap_Argv( 5, altname, sizeof( altname ) );
-
- G_AddBot( name, skill, team, delay, altname );
-
- // if this was issued during gameplay and we are playing locally,
- // go ahead and load the bot's media immediately
- if ( level.time - level.startTime > 1000 &&
- trap_Cvar_VariableIntegerValue( "cl_running" ) ) {
- trap_SendServerCommand( -1, "loaddefered\n" ); // FIXME: spelled wrong, but not changing for demo
- }
-}
-
-/*
-===============
-Svcmd_BotList_f
-===============
-*/
-void Svcmd_BotList_f( void ) {
- int i;
- char name[MAX_TOKEN_CHARS];
- char funname[MAX_TOKEN_CHARS];
- char model[MAX_TOKEN_CHARS];
- char aifile[MAX_TOKEN_CHARS];
-
- trap_Printf("^1name model aifile funname\n");
- for (i = 0; i < g_numBots; i++) {
- strcpy(name, Info_ValueForKey( g_botInfos[i], "name" ));
- if ( !*name ) {
- strcpy(name, "UnnamedPlayer");
- }
- strcpy(funname, Info_ValueForKey( g_botInfos[i], "funname" ));
- if ( !*funname ) {
- strcpy(funname, "");
- }
- strcpy(model, Info_ValueForKey( g_botInfos[i], "model" ));
- if ( !*model ) {
- strcpy(model, "visor/default");
- }
- strcpy(aifile, Info_ValueForKey( g_botInfos[i], "aifile"));
- if (!*aifile ) {
- strcpy(aifile, "bots/default_c.c");
- }
- trap_Printf(va("%-16s %-16s %-20s %-20s\n", name, model, aifile, funname));
- }
-}
-
-
-/*
-===============
-G_SpawnBots
-===============
-*/
-static void G_SpawnBots( char *botList, int baseDelay ) {
- char *bot;
- char *p;
- float skill;
- int delay;
- char bots[MAX_INFO_VALUE];
-
- podium1 = NULL;
- podium2 = NULL;
- podium3 = NULL;
-
- skill = trap_Cvar_VariableValue( "g_spSkill" );
- if( skill < 1 ) {
- trap_Cvar_Set( "g_spSkill", "1" );
- skill = 1;
- }
- else if ( skill > 5 ) {
- trap_Cvar_Set( "g_spSkill", "5" );
- skill = 5;
- }
-
- Q_strncpyz( bots, botList, sizeof(bots) );
- p = &bots[0];
- delay = baseDelay;
- while( *p ) {
- //skip spaces
- while( *p && *p == ' ' ) {
- p++;
- }
- if( !p ) {
- break;
- }
-
- // mark start of bot name
- bot = p;
-
- // skip until space of null
- while( *p && *p != ' ' ) {
- p++;
- }
- if( *p ) {
- *p++ = 0;
- }
-
- // we must add the bot this way, calling G_AddBot directly at this stage
- // does "Bad Things"
- trap_SendConsoleCommand( EXEC_INSERT, va("addbot %s %f free %i\n", bot, skill, delay) );
-
- delay += BOT_BEGIN_DELAY_INCREMENT;
- }
-}
-
-
-/*
-===============
-G_LoadBotsFromFile
-===============
-*/
-static void G_LoadBotsFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_BOTS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Printf( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_BOTS_TEXT ) {
- trap_Printf( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- g_numBots += G_ParseInfos( buf, MAX_BOTS - g_numBots, &g_botInfos[g_numBots] );
-}
-
-/*
-===============
-G_LoadBots
-===============
-*/
-static void G_LoadBots( void ) {
- vmCvar_t botsFile;
- int numdirs;
- char filename[128];
- char dirlist[1024];
- char* dirptr;
- int i;
- int dirlen;
-
- if ( !trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
- return;
- }
-
- g_numBots = 0;
-
- trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
- if( *botsFile.string ) {
- G_LoadBotsFromFile(botsFile.string);
- }
- else {
- G_LoadBotsFromFile("scripts/bots.txt");
- }
-
- // get all bots from .bot files
- numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- G_LoadBotsFromFile(filename);
- }
- trap_Printf( va( "%i bots parsed\n", g_numBots ) );
-}
-
-
-
-/*
-===============
-G_GetBotInfoByNumber
-===============
-*/
-char *G_GetBotInfoByNumber( int num ) {
- if( num < 0 || num >= g_numBots ) {
- trap_Printf( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
- return NULL;
- }
- return g_botInfos[num];
-}
-
-
-/*
-===============
-G_GetBotInfoByName
-===============
-*/
-char *G_GetBotInfoByName( const char *name ) {
- int n;
- char *value;
-
- for ( n = 0; n < g_numBots ; n++ ) {
- value = Info_ValueForKey( g_botInfos[n], "name" );
- if ( !Q_stricmp( value, name ) ) {
- return g_botInfos[n];
- }
- }
-
- return NULL;
-}
-
-/*
-===============
-G_InitBots
-===============
-*/
-void G_InitBots( qboolean restart ) {
- int fragLimit;
- int timeLimit;
- const char *arenainfo;
- char *strValue;
- int basedelay;
- char map[MAX_QPATH];
- char serverinfo[MAX_INFO_STRING];
-
- G_LoadBots();
- G_LoadArenas();
-
- trap_Cvar_Register( &bot_minplayers, "bot_minplayers", "0", CVAR_SERVERINFO );
-
- if( g_gametype.integer == GT_SINGLE_PLAYER ) {
- trap_GetServerinfo( serverinfo, sizeof(serverinfo) );
- Q_strncpyz( map, Info_ValueForKey( serverinfo, "mapname" ), sizeof(map) );
- arenainfo = G_GetArenaInfoByMap( map );
- if ( !arenainfo ) {
- return;
- }
-
- strValue = Info_ValueForKey( arenainfo, "fraglimit" );
- fragLimit = atoi( strValue );
- if ( fragLimit ) {
- trap_Cvar_Set( "fraglimit", strValue );
- }
- else {
- trap_Cvar_Set( "fraglimit", "0" );
- }
-
- strValue = Info_ValueForKey( arenainfo, "timelimit" );
- timeLimit = atoi( strValue );
- if ( timeLimit ) {
- trap_Cvar_Set( "timelimit", strValue );
- }
- else {
- trap_Cvar_Set( "timelimit", "0" );
- }
-
- if ( !fragLimit && !timeLimit ) {
- trap_Cvar_Set( "fraglimit", "10" );
- trap_Cvar_Set( "timelimit", "0" );
- }
-
- basedelay = BOT_BEGIN_DELAY_BASE;
- strValue = Info_ValueForKey( arenainfo, "special" );
- if( Q_stricmp( strValue, "training" ) == 0 ) {
- basedelay += 10000;
- }
-
- if( !restart ) {
- G_SpawnBots( Info_ValueForKey( arenainfo, "bots" ), basedelay );
- }
- }
-}
diff --git a/engine/code/game/g_client.c b/engine/code/game/g_client.c
deleted file mode 100644
index 1c9dbd7..0000000
--- a/engine/code/game/g_client.c
+++ /dev/null
@@ -1,1364 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-// g_client.c -- client functions that don't happen every frame
-
-static vec3_t playerMins = {-15, -15, -24};
-static vec3_t playerMaxs = {15, 15, 32};
-
-/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32) initial
-potential spawning position for deathmatch games.
-The first time a player enters the game, they will be at an 'initial' spot.
-Targets will be fired when someone spawns in on them.
-"nobots" will prevent bots from using this spot.
-"nohumans" will prevent non-bots from using this spot.
-*/
-void SP_info_player_deathmatch( gentity_t *ent ) {
- int i;
-
- G_SpawnInt( "nobots", "0", &i);
- if ( i ) {
- ent->flags |= FL_NO_BOTS;
- }
- G_SpawnInt( "nohumans", "0", &i );
- if ( i ) {
- ent->flags |= FL_NO_HUMANS;
- }
-}
-
-/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
-equivelant to info_player_deathmatch
-*/
-void SP_info_player_start(gentity_t *ent) {
- ent->classname = "info_player_deathmatch";
- SP_info_player_deathmatch( ent );
-}
-
-/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)
-The intermission will be viewed from this point. Target an info_notnull for the view direction.
-*/
-void SP_info_player_intermission( gentity_t *ent ) {
-
-}
-
-
-
-/*
-=======================================================================
-
- SelectSpawnPoint
-
-=======================================================================
-*/
-
-/*
-================
-SpotWouldTelefrag
-
-================
-*/
-qboolean SpotWouldTelefrag( gentity_t *spot ) {
- int i, num;
- int touch[MAX_GENTITIES];
- gentity_t *hit;
- vec3_t mins, maxs;
-
- VectorAdd( spot->s.origin, playerMins, mins );
- VectorAdd( spot->s.origin, playerMaxs, maxs );
- num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
-
- for (i=0 ; i<num ; i++) {
- hit = &g_entities[touch[i]];
- //if ( hit->client && hit->client->ps.stats[STAT_HEALTH] > 0 ) {
- if ( hit->client) {
- return qtrue;
- }
-
- }
-
- return qfalse;
-}
-
-/*
-================
-SelectNearestDeathmatchSpawnPoint
-
-Find the spot that we DON'T want to use
-================
-*/
-#define MAX_SPAWN_POINTS 128
-gentity_t *SelectNearestDeathmatchSpawnPoint( vec3_t from ) {
- gentity_t *spot;
- vec3_t delta;
- float dist, nearestDist;
- gentity_t *nearestSpot;
-
- nearestDist = 999999;
- nearestSpot = NULL;
- spot = NULL;
-
- while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
-
- VectorSubtract( spot->s.origin, from, delta );
- dist = VectorLength( delta );
- if ( dist < nearestDist ) {
- nearestDist = dist;
- nearestSpot = spot;
- }
- }
-
- return nearestSpot;
-}
-
-
-/*
-================
-SelectRandomDeathmatchSpawnPoint
-
-go to a random point that doesn't telefrag
-================
-*/
-#define MAX_SPAWN_POINTS 128
-gentity_t *SelectRandomDeathmatchSpawnPoint(qboolean isbot) {
- gentity_t *spot;
- int count;
- int selection;
- gentity_t *spots[MAX_SPAWN_POINTS];
-
- count = 0;
- spot = NULL;
-
- while((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL && count < MAX_SPAWN_POINTS)
- {
- if(SpotWouldTelefrag(spot))
- continue;
-
- if(((spot->flags & FL_NO_BOTS) && isbot) ||
- ((spot->flags & FL_NO_HUMANS) && !isbot))
- {
- // spot is not for this human/bot player
- continue;
- }
-
- spots[count] = spot;
- count++;
- }
-
- if ( !count ) { // no spots that won't telefrag
- return G_Find( NULL, FOFS(classname), "info_player_deathmatch");
- }
-
- selection = rand() % count;
- return spots[ selection ];
-}
-
-/*
-===========
-SelectRandomFurthestSpawnPoint
-
-Chooses a player start, deathmatch start, etc
-============
-*/
-gentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles, qboolean isbot ) {
- gentity_t *spot;
- vec3_t delta;
- float dist;
- float list_dist[MAX_SPAWN_POINTS];
- gentity_t *list_spot[MAX_SPAWN_POINTS];
- int numSpots, rnd, i, j;
-
- numSpots = 0;
- spot = NULL;
-
- while((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
- {
- if(SpotWouldTelefrag(spot))
- continue;
-
- if(((spot->flags & FL_NO_BOTS) && isbot) ||
- ((spot->flags & FL_NO_HUMANS) && !isbot))
- {
- // spot is not for this human/bot player
- continue;
- }
-
- VectorSubtract( spot->s.origin, avoidPoint, delta );
- dist = VectorLength( delta );
-
- for (i = 0; i < numSpots; i++)
- {
- if(dist > list_dist[i])
- {
- if (numSpots >= MAX_SPAWN_POINTS)
- numSpots = MAX_SPAWN_POINTS - 1;
-
- for(j = numSpots; j > i; j--)
- {
- list_dist[j] = list_dist[j-1];
- list_spot[j] = list_spot[j-1];
- }
-
- list_dist[i] = dist;
- list_spot[i] = spot;
-
- numSpots++;
- break;
- }
- }
-
- if(i >= numSpots && numSpots < MAX_SPAWN_POINTS)
- {
- list_dist[numSpots] = dist;
- list_spot[numSpots] = spot;
- numSpots++;
- }
- }
-
- if(!numSpots)
- {
- spot = G_Find(NULL, FOFS(classname), "info_player_deathmatch");
-
- if (!spot)
- G_Error( "Couldn't find a spawn point" );
-
- VectorCopy (spot->s.origin, origin);
- origin[2] += 9;
- VectorCopy (spot->s.angles, angles);
- return spot;
- }
-
- // select a random spot from the spawn points furthest away
- rnd = random() * (numSpots / 2);
-
- VectorCopy (list_spot[rnd]->s.origin, origin);
- origin[2] += 9;
- VectorCopy (list_spot[rnd]->s.angles, angles);
-
- return list_spot[rnd];
-}
-
-/*
-===========
-SelectSpawnPoint
-
-Chooses a player start, deathmatch start, etc
-============
-*/
-gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles, qboolean isbot ) {
- return SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles, isbot );
-
- /*
- gentity_t *spot;
- gentity_t *nearestSpot;
-
- nearestSpot = SelectNearestDeathmatchSpawnPoint( avoidPoint );
-
- spot = SelectRandomDeathmatchSpawnPoint ( );
- if ( spot == nearestSpot ) {
- // roll again if it would be real close to point of death
- spot = SelectRandomDeathmatchSpawnPoint ( );
- if ( spot == nearestSpot ) {
- // last try
- spot = SelectRandomDeathmatchSpawnPoint ( );
- }
- }
-
- // find a single player start spot
- if (!spot) {
- G_Error( "Couldn't find a spawn point" );
- }
-
- VectorCopy (spot->s.origin, origin);
- origin[2] += 9;
- VectorCopy (spot->s.angles, angles);
-
- return spot;
- */
-}
-
-/*
-===========
-SelectInitialSpawnPoint
-
-Try to find a spawn point marked 'initial', otherwise
-use normal spawn selection.
-============
-*/
-gentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles, qboolean isbot ) {
- gentity_t *spot;
-
- spot = NULL;
-
- while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
- {
- if(((spot->flags & FL_NO_BOTS) && isbot) ||
- ((spot->flags & FL_NO_HUMANS) && !isbot))
- {
- continue;
- }
-
- if((spot->spawnflags & 0x01))
- break;
- }
-
- if (!spot || SpotWouldTelefrag(spot))
- return SelectSpawnPoint(vec3_origin, origin, angles, isbot);
-
- VectorCopy (spot->s.origin, origin);
- origin[2] += 9;
- VectorCopy (spot->s.angles, angles);
-
- return spot;
-}
-
-/*
-===========
-SelectSpectatorSpawnPoint
-
-============
-*/
-gentity_t *SelectSpectatorSpawnPoint( vec3_t origin, vec3_t angles ) {
- FindIntermissionPoint();
-
- VectorCopy( level.intermission_origin, origin );
- VectorCopy( level.intermission_angle, angles );
-
- return NULL;
-}
-
-/*
-=======================================================================
-
-BODYQUE
-
-=======================================================================
-*/
-
-/*
-===============
-InitBodyQue
-===============
-*/
-void InitBodyQue (void) {
- int i;
- gentity_t *ent;
-
- level.bodyQueIndex = 0;
- for (i=0; i<BODY_QUEUE_SIZE ; i++) {
- ent = G_Spawn();
- ent->classname = "bodyque";
- ent->neverFree = qtrue;
- level.bodyQue[i] = ent;
- }
-}
-
-/*
-=============
-BodySink
-
-After sitting around for five seconds, fall into the ground and dissapear
-=============
-*/
-void BodySink( gentity_t *ent ) {
- if ( level.time - ent->timestamp > 6500 ) {
- // the body ques are never actually freed, they are just unlinked
- trap_UnlinkEntity( ent );
- ent->physicsObject = qfalse;
- return;
- }
- ent->nextthink = level.time + 100;
- ent->s.pos.trBase[2] -= 1;
-}
-
-/*
-=============
-CopyToBodyQue
-
-A player is respawning, so make an entity that looks
-just like the existing corpse to leave behind.
-=============
-*/
-void CopyToBodyQue( gentity_t *ent ) {
-#ifdef MISSIONPACK
- gentity_t *e;
- int i;
-#endif
- gentity_t *body;
- int contents;
-
- trap_UnlinkEntity (ent);
-
- // if client is in a nodrop area, don't leave the body
- contents = trap_PointContents( ent->s.origin, -1 );
- if ( contents & CONTENTS_NODROP ) {
- return;
- }
-
- // grab a body que and cycle to the next one
- body = level.bodyQue[ level.bodyQueIndex ];
- level.bodyQueIndex = (level.bodyQueIndex + 1) % BODY_QUEUE_SIZE;
-
- trap_UnlinkEntity (body);
-
- body->s = ent->s;
- body->s.eFlags = EF_DEAD; // clear EF_TALK, etc
-#ifdef MISSIONPACK
- if ( ent->s.eFlags & EF_KAMIKAZE ) {
- body->s.eFlags |= EF_KAMIKAZE;
-
- // check if there is a kamikaze timer around for this owner
- for (i = 0; i < MAX_GENTITIES; i++) {
- e = &g_entities[i];
- if (!e->inuse)
- continue;
- if (e->activator != ent)
- continue;
- if (strcmp(e->classname, "kamikaze timer"))
- continue;
- e->activator = body;
- break;
- }
- }
-#endif
- body->s.powerups = 0; // clear powerups
- body->s.loopSound = 0; // clear lava burning
- body->s.number = body - g_entities;
- body->timestamp = level.time;
- body->physicsObject = qtrue;
- body->physicsBounce = 0; // don't bounce
- if ( body->s.groundEntityNum == ENTITYNUM_NONE ) {
- body->s.pos.trType = TR_GRAVITY;
- body->s.pos.trTime = level.time;
- VectorCopy( ent->client->ps.velocity, body->s.pos.trDelta );
- } else {
- body->s.pos.trType = TR_STATIONARY;
- }
- body->s.event = 0;
-
- // change the animation to the last-frame only, so the sequence
- // doesn't repeat anew for the body
- switch ( body->s.legsAnim & ~ANIM_TOGGLEBIT ) {
- case BOTH_DEATH1:
- case BOTH_DEAD1:
- body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD1;
- break;
- case BOTH_DEATH2:
- case BOTH_DEAD2:
- body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD2;
- break;
- case BOTH_DEATH3:
- case BOTH_DEAD3:
- default:
- body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD3;
- break;
- }
-
- body->r.svFlags = ent->r.svFlags;
- VectorCopy (ent->r.mins, body->r.mins);
- VectorCopy (ent->r.maxs, body->r.maxs);
- VectorCopy (ent->r.absmin, body->r.absmin);
- VectorCopy (ent->r.absmax, body->r.absmax);
-
- body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
- body->r.contents = CONTENTS_CORPSE;
- body->r.ownerNum = ent->s.number;
-
- body->nextthink = level.time + 5000;
- body->think = BodySink;
-
- body->die = body_die;
-
- // don't take more damage if already gibbed
- if ( ent->health <= GIB_HEALTH ) {
- body->takedamage = qfalse;
- } else {
- body->takedamage = qtrue;
- }
-
-
- VectorCopy ( body->s.pos.trBase, body->r.currentOrigin );
- trap_LinkEntity (body);
-}
-
-//======================================================================
-
-
-/*
-==================
-SetClientViewAngle
-
-==================
-*/
-void SetClientViewAngle( gentity_t *ent, vec3_t angle ) {
- int i;
-
- // set the delta angle
- for (i=0 ; i<3 ; i++) {
- int cmdAngle;
-
- cmdAngle = ANGLE2SHORT(angle[i]);
- ent->client->ps.delta_angles[i] = cmdAngle - ent->client->pers.cmd.angles[i];
- }
- VectorCopy( angle, ent->s.angles );
- VectorCopy (ent->s.angles, ent->client->ps.viewangles);
-}
-
-/*
-================
-respawn
-================
-*/
-void respawn( gentity_t *ent ) {
- gentity_t *tent;
-
- CopyToBodyQue (ent);
- ClientSpawn(ent);
-
- // add a teleportation effect
- tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );
- tent->s.clientNum = ent->s.clientNum;
-}
-
-/*
-================
-TeamCount
-
-Returns number of players on a team
-================
-*/
-team_t TeamCount( int ignoreClientNum, int team ) {
- int i;
- int count = 0;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( i == ignoreClientNum ) {
- continue;
- }
- if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
- continue;
- }
- if ( level.clients[i].sess.sessionTeam == team ) {
- count++;
- }
- }
-
- return count;
-}
-
-/*
-================
-TeamLeader
-
-Returns the client number of the team leader
-================
-*/
-int TeamLeader( int team ) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
- continue;
- }
- if ( level.clients[i].sess.sessionTeam == team ) {
- if ( level.clients[i].sess.teamLeader )
- return i;
- }
- }
-
- return -1;
-}
-
-
-/*
-================
-PickTeam
-
-================
-*/
-team_t PickTeam( int ignoreClientNum ) {
- int counts[TEAM_NUM_TEAMS];
-
- counts[TEAM_BLUE] = TeamCount( ignoreClientNum, TEAM_BLUE );
- counts[TEAM_RED] = TeamCount( ignoreClientNum, TEAM_RED );
-
- if ( counts[TEAM_BLUE] > counts[TEAM_RED] ) {
- return TEAM_RED;
- }
- if ( counts[TEAM_RED] > counts[TEAM_BLUE] ) {
- return TEAM_BLUE;
- }
- // equal team count, so join the team with the lowest score
- if ( level.teamScores[TEAM_BLUE] > level.teamScores[TEAM_RED] ) {
- return TEAM_RED;
- }
- return TEAM_BLUE;
-}
-
-/*
-===========
-ForceClientSkin
-
-Forces a client's skin (for teamplay)
-===========
-*/
-/*
-static void ForceClientSkin( gclient_t *client, char *model, const char *skin ) {
- char *p;
-
- if ((p = Q_strrchr(model, '/')) != 0) {
- *p = 0;
- }
-
- Q_strcat(model, MAX_QPATH, "/");
- Q_strcat(model, MAX_QPATH, skin);
-}
-*/
-
-/*
-===========
-ClientCheckName
-============
-*/
-static void ClientCleanName(const char *in, char *out, int outSize)
-{
- int outpos = 0, colorlessLen = 0, spaces = 0;
-
- // discard leading spaces
- for(; *in == ' '; in++);
-
- for(; *in && outpos < outSize - 1; in++)
- {
- out[outpos] = *in;
-
- if(*in == ' ')
- {
- // don't allow too many consecutive spaces
- if(spaces > 2)
- continue;
-
- spaces++;
- }
- else if(outpos > 0 && out[outpos - 1] == Q_COLOR_ESCAPE)
- {
- if(Q_IsColorString(&out[outpos - 1]))
- {
- colorlessLen--;
-
- if(ColorIndex(*in) == 0)
- {
- // Disallow color black in names to prevent players
- // from getting advantage playing in front of black backgrounds
- outpos--;
- continue;
- }
- }
- else
- {
- spaces = 0;
- colorlessLen++;
- }
- }
- else
- {
- spaces = 0;
- colorlessLen++;
- }
-
- outpos++;
- }
-
- out[outpos] = '\0';
-
- // don't allow empty names
- if( *out == '\0' || colorlessLen == 0)
- Q_strncpyz(out, "UnnamedPlayer", outSize );
-}
-
-
-/*
-===========
-ClientUserInfoChanged
-
-Called from ClientConnect when the player first connects and
-directly by the server system when the player updates a userinfo variable.
-
-The game can override any of the settings and call trap_SetUserinfo
-if desired.
-============
-*/
-void ClientUserinfoChanged( int clientNum ) {
- gentity_t *ent;
- int teamTask, teamLeader, team, health;
- char *s;
- char model[MAX_QPATH];
- char headModel[MAX_QPATH];
- char oldname[MAX_STRING_CHARS];
- gclient_t *client;
- char c1[MAX_INFO_STRING];
- char c2[MAX_INFO_STRING];
- char redTeam[MAX_INFO_STRING];
- char blueTeam[MAX_INFO_STRING];
- char userinfo[MAX_INFO_STRING];
- char guid[MAX_INFO_STRING];
-
- ent = g_entities + clientNum;
- client = ent->client;
-
- trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
-
- // check for malformed or illegal info strings
- if ( !Info_Validate(userinfo) ) {
- strcpy (userinfo, "\\name\\badinfo");
- }
-
- // check for local client
- s = Info_ValueForKey( userinfo, "ip" );
- if ( !strcmp( s, "localhost" ) ) {
- client->pers.localClient = qtrue;
- }
-
- // check the item prediction
- s = Info_ValueForKey( userinfo, "cg_predictItems" );
- if ( !atoi( s ) ) {
- client->pers.predictItemPickup = qfalse;
- } else {
- client->pers.predictItemPickup = qtrue;
- }
-
- // set name
- Q_strncpyz ( oldname, client->pers.netname, sizeof( oldname ) );
- s = Info_ValueForKey (userinfo, "name");
- ClientCleanName( s, client->pers.netname, sizeof(client->pers.netname) );
-
- if ( client->sess.sessionTeam == TEAM_SPECTATOR ) {
- if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
- Q_strncpyz( client->pers.netname, "scoreboard", sizeof(client->pers.netname) );
- }
- }
-
- if ( client->pers.connected == CON_CONNECTED ) {
- if ( strcmp( oldname, client->pers.netname ) ) {
- trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname,
- client->pers.netname) );
- }
- }
-
- // set max health
-#ifdef MISSIONPACK
- if (client->ps.powerups[PW_GUARD]) {
- client->pers.maxHealth = 200;
- } else {
- health = atoi( Info_ValueForKey( userinfo, "handicap" ) );
- client->pers.maxHealth = health;
- if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) {
- client->pers.maxHealth = 100;
- }
- }
-#else
- health = atoi( Info_ValueForKey( userinfo, "handicap" ) );
- client->pers.maxHealth = health;
- if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) {
- client->pers.maxHealth = 100;
- }
-#endif
- client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;
-
- // set model
- if( g_gametype.integer >= GT_TEAM ) {
- Q_strncpyz( model, Info_ValueForKey (userinfo, "team_model"), sizeof( model ) );
- Q_strncpyz( headModel, Info_ValueForKey (userinfo, "team_headmodel"), sizeof( headModel ) );
- } else {
- Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) );
- Q_strncpyz( headModel, Info_ValueForKey (userinfo, "headmodel"), sizeof( headModel ) );
- }
-
- // bots set their team a few frames later
- if (g_gametype.integer >= GT_TEAM && g_entities[clientNum].r.svFlags & SVF_BOT) {
- s = Info_ValueForKey( userinfo, "team" );
- if ( !Q_stricmp( s, "red" ) || !Q_stricmp( s, "r" ) ) {
- team = TEAM_RED;
- } else if ( !Q_stricmp( s, "blue" ) || !Q_stricmp( s, "b" ) ) {
- team = TEAM_BLUE;
- } else {
- // pick the team with the least number of players
- team = PickTeam( clientNum );
- }
- }
- else {
- team = client->sess.sessionTeam;
- }
-
-/* NOTE: all client side now
-
- // team
- switch( team ) {
- case TEAM_RED:
- ForceClientSkin(client, model, "red");
-// ForceClientSkin(client, headModel, "red");
- break;
- case TEAM_BLUE:
- ForceClientSkin(client, model, "blue");
-// ForceClientSkin(client, headModel, "blue");
- break;
- }
- // don't ever use a default skin in teamplay, it would just waste memory
- // however bots will always join a team but they spawn in as spectator
- if ( g_gametype.integer >= GT_TEAM && team == TEAM_SPECTATOR) {
- ForceClientSkin(client, model, "red");
-// ForceClientSkin(client, headModel, "red");
- }
-*/
-
-#ifdef MISSIONPACK
- if (g_gametype.integer >= GT_TEAM) {
- client->pers.teamInfo = qtrue;
- } else {
- s = Info_ValueForKey( userinfo, "teamoverlay" );
- if ( ! *s || atoi( s ) != 0 ) {
- client->pers.teamInfo = qtrue;
- } else {
- client->pers.teamInfo = qfalse;
- }
- }
-#else
- // teamInfo
- s = Info_ValueForKey( userinfo, "teamoverlay" );
- if ( ! *s || atoi( s ) != 0 ) {
- client->pers.teamInfo = qtrue;
- } else {
- client->pers.teamInfo = qfalse;
- }
-#endif
- /*
- s = Info_ValueForKey( userinfo, "cg_pmove_fixed" );
- if ( !*s || atoi( s ) == 0 ) {
- client->pers.pmoveFixed = qfalse;
- }
- else {
- client->pers.pmoveFixed = qtrue;
- }
- */
-
- // team task (0 = none, 1 = offence, 2 = defence)
- teamTask = atoi(Info_ValueForKey(userinfo, "teamtask"));
- // team Leader (1 = leader, 0 is normal player)
- teamLeader = client->sess.teamLeader;
-
- // colors
- strcpy(c1, Info_ValueForKey( userinfo, "color1" ));
- strcpy(c2, Info_ValueForKey( userinfo, "color2" ));
-
- strcpy(redTeam, Info_ValueForKey( userinfo, "g_redteam" ));
- strcpy(blueTeam, Info_ValueForKey( userinfo, "g_blueteam" ));
- strcpy(guid, Info_ValueForKey(userinfo, "cl_guid"));
-
- // send over a subset of the userinfo keys so other clients can
- // print scoreboards, display models, and play custom sounds
- if (ent->r.svFlags & SVF_BOT)
- {
- s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d",
- client->pers.netname, team, model, headModel, c1, c2,
- client->pers.maxHealth, client->sess.wins, client->sess.losses,
- Info_ValueForKey( userinfo, "skill" ), teamTask, teamLeader );
- }
- else
- {
- s = va("n\\%s\\guid\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\g_redteam\\%s\\g_blueteam\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d",
- client->pers.netname, guid, client->sess.sessionTeam, model, headModel, redTeam, blueTeam, c1, c2,
- client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader);
- }
-
- trap_SetConfigstring( CS_PLAYERS+clientNum, s );
-
- // this is not the userinfo, more like the configstring actually
- G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s );
-}
-
-
-/*
-===========
-ClientConnect
-
-Called when a player begins connecting to the server.
-Called again for every map change or tournement restart.
-
-The session information will be valid after exit.
-
-Return NULL if the client should be allowed, otherwise return
-a string with the reason for denial.
-
-Otherwise, the client will be sent the current gamestate
-and will eventually get to ClientBegin.
-
-firstTime will be qtrue the very first time a client connects
-to the server machine, but qfalse on map changes and tournement
-restarts.
-============
-*/
-char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) {
- char *value;
-// char *areabits;
- gclient_t *client;
- char userinfo[MAX_INFO_STRING];
- gentity_t *ent;
-
- ent = &g_entities[ clientNum ];
-
- trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
-
- // IP filtering
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=500
- // recommanding PB based IP / GUID banning, the builtin system is pretty limited
- // check to see if they are on the banned IP list
- value = Info_ValueForKey (userinfo, "ip");
- if ( G_FilterPacket( value ) ) {
- return "You are banned from this server.";
- }
-
- // we don't check password for bots and local client
- // NOTE: local client <-> "ip" "localhost"
- // this means this client is not running in our current process
- if ( !isBot && (strcmp(value, "localhost") != 0)) {
- // check for a password
- value = Info_ValueForKey (userinfo, "password");
- if ( g_password.string[0] && Q_stricmp( g_password.string, "none" ) &&
- strcmp( g_password.string, value) != 0) {
- return "Invalid password";
- }
- }
-
- // they can connect
- ent->client = level.clients + clientNum;
- client = ent->client;
-
-// areabits = client->areabits;
-
- memset( client, 0, sizeof(*client) );
-
- client->pers.connected = CON_CONNECTING;
-
- // read or initialize the session data
- if ( firstTime || level.newSession ) {
- G_InitSessionData( client, userinfo );
- }
- G_ReadSessionData( client );
-
- if( isBot ) {
- ent->r.svFlags |= SVF_BOT;
- ent->inuse = qtrue;
- if( !G_BotConnect( clientNum, !firstTime ) ) {
- return "BotConnectfailed";
- }
- }
-
- // get and distribute relevent paramters
- G_LogPrintf( "ClientConnect: %i\n", clientNum );
- ClientUserinfoChanged( clientNum );
-
- // don't do the "xxx connected" messages if they were caried over from previous level
- if ( firstTime ) {
- trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname) );
- }
-
- if ( g_gametype.integer >= GT_TEAM &&
- client->sess.sessionTeam != TEAM_SPECTATOR ) {
- BroadcastTeamChange( client, -1 );
- }
-
- // count current clients and rank for scoreboard
- CalculateRanks();
-
- // for statistics
-// client->areabits = areabits;
-// if ( !client->areabits )
-// client->areabits = G_Alloc( (trap_AAS_PointReachabilityAreaIndex( NULL ) + 7) / 8 );
-
- return NULL;
-}
-
-/*
-===========
-ClientBegin
-
-called when a client has finished connecting, and is ready
-to be placed into the level. This will happen every level load,
-and on transition between teams, but doesn't happen on respawns
-============
-*/
-void ClientBegin( int clientNum ) {
- gentity_t *ent;
- gclient_t *client;
- gentity_t *tent;
- int flags;
-
- ent = g_entities + clientNum;
-
- client = level.clients + clientNum;
-
- if ( ent->r.linked ) {
- trap_UnlinkEntity( ent );
- }
- G_InitGentity( ent );
- ent->touch = 0;
- ent->pain = 0;
- ent->client = client;
-
- client->pers.connected = CON_CONNECTED;
- client->pers.enterTime = level.time;
- client->pers.teamState.state = TEAM_BEGIN;
-
- // save eflags around this, because changing teams will
- // cause this to happen with a valid entity, and we
- // want to make sure the teleport bit is set right
- // so the viewpoint doesn't interpolate through the
- // world to the new position
- flags = client->ps.eFlags;
- memset( &client->ps, 0, sizeof( client->ps ) );
- client->ps.eFlags = flags;
-
- // locate ent at a spawn point
- ClientSpawn( ent );
-
- if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
- // send event
- tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );
- tent->s.clientNum = ent->s.clientNum;
-
- if ( g_gametype.integer != GT_TOURNAMENT ) {
- trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname) );
- }
- }
- G_LogPrintf( "ClientBegin: %i\n", clientNum );
-
- // count current clients and rank for scoreboard
- CalculateRanks();
-}
-
-/*
-===========
-ClientSpawn
-
-Called every time a client is placed fresh in the world:
-after the first ClientBegin, and after each respawn
-Initializes all non-persistant parts of playerState
-============
-*/
-void ClientSpawn(gentity_t *ent) {
- int index;
- vec3_t spawn_origin, spawn_angles;
- gclient_t *client;
- int i;
- clientPersistant_t saved;
- clientSession_t savedSess;
- int persistant[MAX_PERSISTANT];
- gentity_t *spawnPoint;
- int flags;
- int savedPing;
-// char *savedAreaBits;
- int accuracy_hits, accuracy_shots;
- int eventSequence;
- char userinfo[MAX_INFO_STRING];
-
- index = ent - g_entities;
- client = ent->client;
-
- VectorClear(spawn_origin);
-
- // find a spawn point
- // do it before setting health back up, so farthest
- // ranging doesn't count this client
- if ( client->sess.sessionTeam == TEAM_SPECTATOR ) {
- spawnPoint = SelectSpectatorSpawnPoint (
- spawn_origin, spawn_angles);
- } else if (g_gametype.integer >= GT_CTF ) {
- // all base oriented team games use the CTF spawn points
- spawnPoint = SelectCTFSpawnPoint (
- client->sess.sessionTeam,
- client->pers.teamState.state,
- spawn_origin, spawn_angles,
- !!(ent->r.svFlags & SVF_BOT));
- }
- else
- {
- // the first spawn should be at a good looking spot
- if ( !client->pers.initialSpawn && client->pers.localClient )
- {
- client->pers.initialSpawn = qtrue;
- spawnPoint = SelectInitialSpawnPoint(spawn_origin, spawn_angles,
- !!(ent->r.svFlags & SVF_BOT));
- }
- else
- {
- // don't spawn near existing origin if possible
- spawnPoint = SelectSpawnPoint (
- client->ps.origin,
- spawn_origin, spawn_angles, !!(ent->r.svFlags & SVF_BOT));
- }
- }
- client->pers.teamState.state = TEAM_ACTIVE;
-
- // always clear the kamikaze flag
- ent->s.eFlags &= ~EF_KAMIKAZE;
-
- // toggle the teleport bit so the client knows to not lerp
- // and never clear the voted flag
- flags = ent->client->ps.eFlags & (EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED);
- flags ^= EF_TELEPORT_BIT;
-
- // clear everything but the persistant data
-
- saved = client->pers;
- savedSess = client->sess;
- savedPing = client->ps.ping;
-// savedAreaBits = client->areabits;
- accuracy_hits = client->accuracy_hits;
- accuracy_shots = client->accuracy_shots;
- for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) {
- persistant[i] = client->ps.persistant[i];
- }
- eventSequence = client->ps.eventSequence;
-
- Com_Memset (client, 0, sizeof(*client));
-
- client->pers = saved;
- client->sess = savedSess;
- client->ps.ping = savedPing;
-// client->areabits = savedAreaBits;
- client->accuracy_hits = accuracy_hits;
- client->accuracy_shots = accuracy_shots;
- client->lastkilled_client = -1;
-
- for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) {
- client->ps.persistant[i] = persistant[i];
- }
- client->ps.eventSequence = eventSequence;
- // increment the spawncount so the client will detect the respawn
- client->ps.persistant[PERS_SPAWN_COUNT]++;
- client->ps.persistant[PERS_TEAM] = client->sess.sessionTeam;
-
- client->airOutTime = level.time + 12000;
-
- trap_GetUserinfo( index, userinfo, sizeof(userinfo) );
- // set max health
- client->pers.maxHealth = atoi( Info_ValueForKey( userinfo, "handicap" ) );
- if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) {
- client->pers.maxHealth = 100;
- }
- // clear entity values
- client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;
- client->ps.eFlags = flags;
-
- ent->s.groundEntityNum = ENTITYNUM_NONE;
- ent->client = &level.clients[index];
- ent->takedamage = qtrue;
- ent->inuse = qtrue;
- ent->classname = "player";
- ent->r.contents = CONTENTS_BODY;
- ent->clipmask = MASK_PLAYERSOLID;
- ent->die = player_die;
- ent->waterlevel = 0;
- ent->watertype = 0;
- ent->flags = 0;
-
- VectorCopy (playerMins, ent->r.mins);
- VectorCopy (playerMaxs, ent->r.maxs);
-
- client->ps.clientNum = index;
-
- client->ps.stats[STAT_WEAPONS] = ( 1 << WP_MACHINEGUN );
- if ( g_gametype.integer == GT_TEAM ) {
- client->ps.ammo[WP_MACHINEGUN] = 50;
- } else {
- client->ps.ammo[WP_MACHINEGUN] = 100;
- }
-
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GAUNTLET );
- client->ps.ammo[WP_GAUNTLET] = -1;
- client->ps.ammo[WP_GRAPPLING_HOOK] = -1;
-
- // health will count down towards max_health
- ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] + 25;
-
- G_SetOrigin( ent, spawn_origin );
- VectorCopy( spawn_origin, client->ps.origin );
-
- // the respawned flag will be cleared after the attack and jump keys come up
- client->ps.pm_flags |= PMF_RESPAWNED;
-
- trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd );
- SetClientViewAngle( ent, spawn_angles );
-
- if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
-
- } else {
- G_KillBox( ent );
- trap_LinkEntity (ent);
-
- // force the base weapon up
- client->ps.weapon = WP_MACHINEGUN;
- client->ps.weaponstate = WEAPON_READY;
-
- }
-
- // don't allow full run speed for a bit
- client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
- client->ps.pm_time = 100;
-
- client->respawnTime = level.time;
- client->inactivityTime = level.time + g_inactivity.integer * 1000;
- client->latched_buttons = 0;
-
- // set default animations
- client->ps.torsoAnim = TORSO_STAND;
- client->ps.legsAnim = LEGS_IDLE;
-
- if ( level.intermissiontime ) {
- MoveClientToIntermission( ent );
- } else {
- // fire the targets of the spawn point
- G_UseTargets( spawnPoint, ent );
-
- // select the highest weapon number available, after any
- // spawn given items have fired
- client->ps.weapon = 1;
- for ( i = WP_NUM_WEAPONS - 1 ; i > 0 ; i-- ) {
- if ( client->ps.stats[STAT_WEAPONS] & ( 1 << i ) ) {
- client->ps.weapon = i;
- break;
- }
- }
- }
-
- // run a client frame to drop exactly to the floor,
- // initialize animations and other things
- client->ps.commandTime = level.time - 100;
- ent->client->pers.cmd.serverTime = level.time;
- ClientThink( ent-g_entities );
-
- // positively link the client, even if the command times are weird
- if ( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
- VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
- trap_LinkEntity( ent );
- }
-
- // run the presend to set anything else
- ClientEndFrame( ent );
-
- // clear entity state values
- BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
-}
-
-
-/*
-===========
-ClientDisconnect
-
-Called when a player drops from the server.
-Will not be called between levels.
-
-This should NOT be called directly by any game logic,
-call trap_DropClient(), which will call this and do
-server system housekeeping.
-============
-*/
-void ClientDisconnect( int clientNum ) {
- gentity_t *ent;
- gentity_t *tent;
- int i;
-
- // cleanup if we are kicking a bot that
- // hasn't spawned yet
- G_RemoveQueuedBotBegin( clientNum );
-
- ent = g_entities + clientNum;
- if ( !ent->client ) {
- return;
- }
-
- // stop any following clients
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR
- && level.clients[i].sess.spectatorState == SPECTATOR_FOLLOW
- && level.clients[i].sess.spectatorClient == clientNum ) {
- StopFollowing( &g_entities[i] );
- }
- }
-
- // send effect if they were completely connected
- if ( ent->client->pers.connected == CON_CONNECTED
- && ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
- tent->s.clientNum = ent->s.clientNum;
-
- // They don't get to take powerups with them!
- // Especially important for stuff like CTF flags
- TossClientItems( ent );
-#ifdef MISSIONPACK
- TossClientPersistantPowerups( ent );
- if( g_gametype.integer == GT_HARVESTER ) {
- TossClientCubes( ent );
- }
-#endif
-
- }
-
- G_LogPrintf( "ClientDisconnect: %i\n", clientNum );
-
- // if we are playing in tourney mode and losing, give a win to the other player
- if ( (g_gametype.integer == GT_TOURNAMENT )
- && !level.intermissiontime
- && !level.warmupTime && level.sortedClients[1] == clientNum ) {
- level.clients[ level.sortedClients[0] ].sess.wins++;
- ClientUserinfoChanged( level.sortedClients[0] );
- }
-
- if( g_gametype.integer == GT_TOURNAMENT &&
- ent->client->sess.sessionTeam == TEAM_FREE &&
- level.intermissiontime ) {
-
- trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
- level.restarted = qtrue;
- level.changemap = NULL;
- level.intermissiontime = 0;
- }
-
- trap_UnlinkEntity (ent);
- ent->s.modelindex = 0;
- ent->inuse = qfalse;
- ent->classname = "disconnected";
- ent->client->pers.connected = CON_DISCONNECTED;
- ent->client->ps.persistant[PERS_TEAM] = TEAM_FREE;
- ent->client->sess.sessionTeam = TEAM_FREE;
-
- trap_SetConfigstring( CS_PLAYERS + clientNum, "");
-
- CalculateRanks();
-
- if ( ent->r.svFlags & SVF_BOT ) {
- BotAIShutdownClient( clientNum, qfalse );
- }
-}
-
-
diff --git a/engine/code/game/g_cmds.c b/engine/code/game/g_cmds.c
deleted file mode 100644
index 06df2db..0000000
--- a/engine/code/game/g_cmds.c
+++ /dev/null
@@ -1,1685 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-#include "../../ui/menudef.h" // for the voice chats
-
-/*
-==================
-DeathmatchScoreboardMessage
-
-==================
-*/
-void DeathmatchScoreboardMessage( gentity_t *ent ) {
- char entry[1024];
- char string[1400];
- int stringlength;
- int i, j;
- gclient_t *cl;
- int numSorted, scoreFlags, accuracy, perfect;
-
- // send the latest information on all clients
- string[0] = 0;
- stringlength = 0;
- scoreFlags = 0;
-
- numSorted = level.numConnectedClients;
-
- for (i=0 ; i < numSorted ; i++) {
- int ping;
-
- cl = &level.clients[level.sortedClients[i]];
-
- if ( cl->pers.connected == CON_CONNECTING ) {
- ping = -1;
- } else {
- ping = cl->ps.ping < 999 ? cl->ps.ping : 999;
- }
-
- if( cl->accuracy_shots ) {
- accuracy = cl->accuracy_hits * 100 / cl->accuracy_shots;
- }
- else {
- accuracy = 0;
- }
- perfect = ( cl->ps.persistant[PERS_RANK] == 0 && cl->ps.persistant[PERS_KILLED] == 0 ) ? 1 : 0;
-
- Com_sprintf (entry, sizeof(entry),
- " %i %i %i %i %i %i %i %i %i %i %i %i %i %i", level.sortedClients[i],
- cl->ps.persistant[PERS_SCORE], ping, (level.time - cl->pers.enterTime)/60000,
- scoreFlags, g_entities[level.sortedClients[i]].s.powerups, accuracy,
- cl->ps.persistant[PERS_IMPRESSIVE_COUNT],
- cl->ps.persistant[PERS_EXCELLENT_COUNT],
- cl->ps.persistant[PERS_GAUNTLET_FRAG_COUNT],
- cl->ps.persistant[PERS_DEFEND_COUNT],
- cl->ps.persistant[PERS_ASSIST_COUNT],
- perfect,
- cl->ps.persistant[PERS_CAPTURES]);
- j = strlen(entry);
- if (stringlength + j > 1024)
- break;
- strcpy (string + stringlength, entry);
- stringlength += j;
- }
-
- trap_SendServerCommand( ent-g_entities, va("scores %i %i %i%s", i,
- level.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE],
- string ) );
-}
-
-
-/*
-==================
-Cmd_Score_f
-
-Request current scoreboard information
-==================
-*/
-void Cmd_Score_f( gentity_t *ent ) {
- DeathmatchScoreboardMessage( ent );
-}
-
-
-
-/*
-==================
-CheatsOk
-==================
-*/
-qboolean CheatsOk( gentity_t *ent ) {
- if ( !g_cheats.integer ) {
- trap_SendServerCommand( ent-g_entities, va("print \"Cheats are not enabled on this server.\n\""));
- return qfalse;
- }
- if ( ent->health <= 0 ) {
- trap_SendServerCommand( ent-g_entities, va("print \"You must be alive to use this command.\n\""));
- return qfalse;
- }
- return qtrue;
-}
-
-
-/*
-==================
-ConcatArgs
-==================
-*/
-char *ConcatArgs( int start ) {
- int i, c, tlen;
- static char line[MAX_STRING_CHARS];
- int len;
- char arg[MAX_STRING_CHARS];
-
- len = 0;
- c = trap_Argc();
- for ( i = start ; i < c ; i++ ) {
- trap_Argv( i, arg, sizeof( arg ) );
- tlen = strlen( arg );
- if ( len + tlen >= MAX_STRING_CHARS - 1 ) {
- break;
- }
- memcpy( line + len, arg, tlen );
- len += tlen;
- if ( i != c - 1 ) {
- line[len] = ' ';
- len++;
- }
- }
-
- line[len] = 0;
-
- return line;
-}
-
-/*
-==================
-ClientNumberFromString
-
-Returns a player number for either a number or name string
-Returns -1 if invalid
-==================
-*/
-int ClientNumberFromString( gentity_t *to, char *s ) {
- gclient_t *cl;
- int idnum;
- char cleanName[MAX_STRING_CHARS];
-
- // numeric values are just slot numbers
- if (s[0] >= '0' && s[0] <= '9') {
- idnum = atoi( s );
- if ( idnum < 0 || idnum >= level.maxclients ) {
- trap_SendServerCommand( to-g_entities, va("print \"Bad client slot: %i\n\"", idnum));
- return -1;
- }
-
- cl = &level.clients[idnum];
- if ( cl->pers.connected != CON_CONNECTED ) {
- trap_SendServerCommand( to-g_entities, va("print \"Client %i is not active\n\"", idnum));
- return -1;
- }
- return idnum;
- }
-
- // check for a name match
- for ( idnum=0,cl=level.clients ; idnum < level.maxclients ; idnum++,cl++ ) {
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- Q_strncpyz(cleanName, cl->pers.netname, sizeof(cleanName));
- Q_CleanStr(cleanName);
- if ( !Q_stricmp( cleanName, s ) ) {
- return idnum;
- }
- }
-
- trap_SendServerCommand( to-g_entities, va("print \"User %s is not on the server\n\"", s));
- return -1;
-}
-
-/*
-==================
-Cmd_Give_f
-
-Give items to a client
-==================
-*/
-void Cmd_Give_f (gentity_t *ent)
-{
- char *name;
- gitem_t *it;
- int i;
- qboolean give_all;
- gentity_t *it_ent;
- trace_t trace;
-
- if ( !CheatsOk( ent ) ) {
- return;
- }
-
- name = ConcatArgs( 1 );
-
- if (Q_stricmp(name, "all") == 0)
- give_all = qtrue;
- else
- give_all = qfalse;
-
- if (give_all || Q_stricmp( name, "health") == 0)
- {
- ent->health = ent->client->ps.stats[STAT_MAX_HEALTH];
- if (!give_all)
- return;
- }
-
- if (give_all || Q_stricmp(name, "weapons") == 0)
- {
- ent->client->ps.stats[STAT_WEAPONS] = (1 << WP_NUM_WEAPONS) - 1 -
- ( 1 << WP_GRAPPLING_HOOK ) - ( 1 << WP_NONE );
- if (!give_all)
- return;
- }
-
- if (give_all || Q_stricmp(name, "ammo") == 0)
- {
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- ent->client->ps.ammo[i] = 999;
- }
- if (!give_all)
- return;
- }
-
- if (give_all || Q_stricmp(name, "armor") == 0)
- {
- ent->client->ps.stats[STAT_ARMOR] = 200;
-
- if (!give_all)
- return;
- }
-
- if (Q_stricmp(name, "excellent") == 0) {
- ent->client->ps.persistant[PERS_EXCELLENT_COUNT]++;
- return;
- }
- if (Q_stricmp(name, "impressive") == 0) {
- ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
- return;
- }
- if (Q_stricmp(name, "gauntletaward") == 0) {
- ent->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;
- return;
- }
- if (Q_stricmp(name, "defend") == 0) {
- ent->client->ps.persistant[PERS_DEFEND_COUNT]++;
- return;
- }
- if (Q_stricmp(name, "assist") == 0) {
- ent->client->ps.persistant[PERS_ASSIST_COUNT]++;
- return;
- }
-
- // spawn a specific item right on the player
- if ( !give_all ) {
- it = BG_FindItem (name);
- if (!it) {
- return;
- }
-
- it_ent = G_Spawn();
- VectorCopy( ent->r.currentOrigin, it_ent->s.origin );
- it_ent->classname = it->classname;
- G_SpawnItem (it_ent, it);
- FinishSpawningItem(it_ent );
- memset( &trace, 0, sizeof( trace ) );
- Touch_Item (it_ent, ent, &trace);
- if (it_ent->inuse) {
- G_FreeEntity( it_ent );
- }
- }
-}
-
-
-/*
-==================
-Cmd_God_f
-
-Sets client to godmode
-
-argv(0) god
-==================
-*/
-void Cmd_God_f (gentity_t *ent)
-{
- char *msg;
-
- if ( !CheatsOk( ent ) ) {
- return;
- }
-
- ent->flags ^= FL_GODMODE;
- if (!(ent->flags & FL_GODMODE) )
- msg = "godmode OFF\n";
- else
- msg = "godmode ON\n";
-
- trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg));
-}
-
-
-/*
-==================
-Cmd_Notarget_f
-
-Sets client to notarget
-
-argv(0) notarget
-==================
-*/
-void Cmd_Notarget_f( gentity_t *ent ) {
- char *msg;
-
- if ( !CheatsOk( ent ) ) {
- return;
- }
-
- ent->flags ^= FL_NOTARGET;
- if (!(ent->flags & FL_NOTARGET) )
- msg = "notarget OFF\n";
- else
- msg = "notarget ON\n";
-
- trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg));
-}
-
-
-/*
-==================
-Cmd_Noclip_f
-
-argv(0) noclip
-==================
-*/
-void Cmd_Noclip_f( gentity_t *ent ) {
- char *msg;
-
- if ( !CheatsOk( ent ) ) {
- return;
- }
-
- if ( ent->client->noclip ) {
- msg = "noclip OFF\n";
- } else {
- msg = "noclip ON\n";
- }
- ent->client->noclip = !ent->client->noclip;
-
- trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg));
-}
-
-
-/*
-==================
-Cmd_LevelShot_f
-
-This is just to help generate the level pictures
-for the menus. It goes to the intermission immediately
-and sends over a command to the client to resize the view,
-hide the scoreboard, and take a special screenshot
-==================
-*/
-void Cmd_LevelShot_f( gentity_t *ent ) {
- if ( !CheatsOk( ent ) ) {
- return;
- }
-
- // doesn't work in single player
- if ( g_gametype.integer != 0 ) {
- trap_SendServerCommand( ent-g_entities,
- "print \"Must be in g_gametype 0 for levelshot\n\"" );
- return;
- }
-
- BeginIntermission();
- trap_SendServerCommand( ent-g_entities, "clientLevelShot" );
-}
-
-
-/*
-==================
-Cmd_LevelShot_f
-
-This is just to help generate the level pictures
-for the menus. It goes to the intermission immediately
-and sends over a command to the client to resize the view,
-hide the scoreboard, and take a special screenshot
-==================
-*/
-void Cmd_TeamTask_f( gentity_t *ent ) {
- char userinfo[MAX_INFO_STRING];
- char arg[MAX_TOKEN_CHARS];
- int task;
- int client = ent->client - level.clients;
-
- if ( trap_Argc() != 2 ) {
- return;
- }
- trap_Argv( 1, arg, sizeof( arg ) );
- task = atoi( arg );
-
- trap_GetUserinfo(client, userinfo, sizeof(userinfo));
- Info_SetValueForKey(userinfo, "teamtask", va("%d", task));
- trap_SetUserinfo(client, userinfo);
- ClientUserinfoChanged(client);
-}
-
-
-
-/*
-=================
-Cmd_Kill_f
-=================
-*/
-void Cmd_Kill_f( gentity_t *ent ) {
- if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
- return;
- }
- if (ent->health <= 0) {
- return;
- }
- ent->flags &= ~FL_GODMODE;
- ent->client->ps.stats[STAT_HEALTH] = ent->health = -999;
- player_die (ent, ent, ent, 100000, MOD_SUICIDE);
-}
-
-/*
-=================
-BroadCastTeamChange
-
-Let everyone know about a team change
-=================
-*/
-void BroadcastTeamChange( gclient_t *client, int oldTeam )
-{
- if ( client->sess.sessionTeam == TEAM_RED ) {
- trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the red team.\n\"",
- client->pers.netname) );
- } else if ( client->sess.sessionTeam == TEAM_BLUE ) {
- trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the blue team.\n\"",
- client->pers.netname));
- } else if ( client->sess.sessionTeam == TEAM_SPECTATOR && oldTeam != TEAM_SPECTATOR ) {
- trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the spectators.\n\"",
- client->pers.netname));
- } else if ( client->sess.sessionTeam == TEAM_FREE ) {
- trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the battle.\n\"",
- client->pers.netname));
- }
-}
-
-/*
-=================
-SetTeam
-=================
-*/
-void SetTeam( gentity_t *ent, char *s ) {
- int team, oldTeam;
- gclient_t *client;
- int clientNum;
- spectatorState_t specState;
- int specClient;
- int teamLeader;
-
- //
- // see what change is requested
- //
- client = ent->client;
-
- clientNum = client - level.clients;
- specClient = 0;
- specState = SPECTATOR_NOT;
- if ( !Q_stricmp( s, "scoreboard" ) || !Q_stricmp( s, "score" ) ) {
- team = TEAM_SPECTATOR;
- specState = SPECTATOR_SCOREBOARD;
- } else if ( !Q_stricmp( s, "follow1" ) ) {
- team = TEAM_SPECTATOR;
- specState = SPECTATOR_FOLLOW;
- specClient = -1;
- } else if ( !Q_stricmp( s, "follow2" ) ) {
- team = TEAM_SPECTATOR;
- specState = SPECTATOR_FOLLOW;
- specClient = -2;
- } else if ( !Q_stricmp( s, "spectator" ) || !Q_stricmp( s, "s" ) ) {
- team = TEAM_SPECTATOR;
- specState = SPECTATOR_FREE;
- } else if ( g_gametype.integer >= GT_TEAM ) {
- // if running a team game, assign player to one of the teams
- specState = SPECTATOR_NOT;
- if ( !Q_stricmp( s, "red" ) || !Q_stricmp( s, "r" ) ) {
- team = TEAM_RED;
- } else if ( !Q_stricmp( s, "blue" ) || !Q_stricmp( s, "b" ) ) {
- team = TEAM_BLUE;
- } else {
- // pick the team with the least number of players
- team = PickTeam( clientNum );
- }
-
- if ( g_teamForceBalance.integer ) {
- int counts[TEAM_NUM_TEAMS];
-
- counts[TEAM_BLUE] = TeamCount( clientNum, TEAM_BLUE );
- counts[TEAM_RED] = TeamCount( clientNum, TEAM_RED );
-
- // We allow a spread of two
- if ( team == TEAM_RED && counts[TEAM_RED] - counts[TEAM_BLUE] > 1 ) {
- trap_SendServerCommand( clientNum,
- "cp \"Red team has too many players.\n\"" );
- return; // ignore the request
- }
- if ( team == TEAM_BLUE && counts[TEAM_BLUE] - counts[TEAM_RED] > 1 ) {
- trap_SendServerCommand( clientNum,
- "cp \"Blue team has too many players.\n\"" );
- return; // ignore the request
- }
-
- // It's ok, the team we are switching to has less or same number of players
- }
-
- } else {
- // force them to spectators if there aren't any spots free
- team = TEAM_FREE;
- }
-
- // override decision if limiting the players
- if ( (g_gametype.integer == GT_TOURNAMENT)
- && level.numNonSpectatorClients >= 2 ) {
- team = TEAM_SPECTATOR;
- } else if ( g_maxGameClients.integer > 0 &&
- level.numNonSpectatorClients >= g_maxGameClients.integer ) {
- team = TEAM_SPECTATOR;
- }
-
- //
- // decide if we will allow the change
- //
- oldTeam = client->sess.sessionTeam;
- if ( team == oldTeam && team != TEAM_SPECTATOR ) {
- return;
- }
-
- //
- // execute the team change
- //
-
- // if the player was dead leave the body
- if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
- CopyToBodyQue(ent);
- }
-
- // he starts at 'base'
- client->pers.teamState.state = TEAM_BEGIN;
- if ( oldTeam != TEAM_SPECTATOR ) {
- // Kill him (makes sure he loses flags, etc)
- ent->flags &= ~FL_GODMODE;
- ent->client->ps.stats[STAT_HEALTH] = ent->health = 0;
- player_die (ent, ent, ent, 100000, MOD_SUICIDE);
-
- }
- // they go to the end of the line for tournements
- if ( team == TEAM_SPECTATOR ) {
- client->sess.spectatorTime = level.time;
- }
-
- client->sess.sessionTeam = team;
- client->sess.spectatorState = specState;
- client->sess.spectatorClient = specClient;
-
- client->sess.teamLeader = qfalse;
- if ( team == TEAM_RED || team == TEAM_BLUE ) {
- teamLeader = TeamLeader( team );
- // if there is no team leader or the team leader is a bot and this client is not a bot
- if ( teamLeader == -1 || ( !(g_entities[clientNum].r.svFlags & SVF_BOT) && (g_entities[teamLeader].r.svFlags & SVF_BOT) ) ) {
- SetLeader( team, clientNum );
- }
- }
- // make sure there is a team leader on the team the player came from
- if ( oldTeam == TEAM_RED || oldTeam == TEAM_BLUE ) {
- CheckTeamLeader( oldTeam );
- }
-
- BroadcastTeamChange( client, oldTeam );
-
- // get and distribute relevent paramters
- ClientUserinfoChanged( clientNum );
-
- ClientBegin( clientNum );
-}
-
-/*
-=================
-StopFollowing
-
-If the client being followed leaves the game, or you just want to drop
-to free floating spectator mode
-=================
-*/
-void StopFollowing( gentity_t *ent ) {
- ent->client->ps.persistant[ PERS_TEAM ] = TEAM_SPECTATOR;
- ent->client->sess.sessionTeam = TEAM_SPECTATOR;
- ent->client->sess.spectatorState = SPECTATOR_FREE;
- ent->client->ps.pm_flags &= ~PMF_FOLLOW;
- ent->r.svFlags &= ~SVF_BOT;
- ent->client->ps.clientNum = ent - g_entities;
-}
-
-/*
-=================
-Cmd_Team_f
-=================
-*/
-void Cmd_Team_f( gentity_t *ent ) {
- int oldTeam;
- char s[MAX_TOKEN_CHARS];
-
- if ( trap_Argc() != 2 ) {
- oldTeam = ent->client->sess.sessionTeam;
- switch ( oldTeam ) {
- case TEAM_BLUE:
- trap_SendServerCommand( ent-g_entities, "print \"Blue team\n\"" );
- break;
- case TEAM_RED:
- trap_SendServerCommand( ent-g_entities, "print \"Red team\n\"" );
- break;
- case TEAM_FREE:
- trap_SendServerCommand( ent-g_entities, "print \"Free team\n\"" );
- break;
- case TEAM_SPECTATOR:
- trap_SendServerCommand( ent-g_entities, "print \"Spectator team\n\"" );
- break;
- }
- return;
- }
-
- if ( ent->client->switchTeamTime > level.time ) {
- trap_SendServerCommand( ent-g_entities, "print \"May not switch teams more than once per 5 seconds.\n\"" );
- return;
- }
-
- // if they are playing a tournement game, count as a loss
- if ( (g_gametype.integer == GT_TOURNAMENT )
- && ent->client->sess.sessionTeam == TEAM_FREE ) {
- ent->client->sess.losses++;
- }
-
- trap_Argv( 1, s, sizeof( s ) );
-
- SetTeam( ent, s );
-
- ent->client->switchTeamTime = level.time + 5000;
-}
-
-
-/*
-=================
-Cmd_Follow_f
-=================
-*/
-void Cmd_Follow_f( gentity_t *ent ) {
- int i;
- char arg[MAX_TOKEN_CHARS];
-
- if ( trap_Argc() != 2 ) {
- if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {
- StopFollowing( ent );
- }
- return;
- }
-
- trap_Argv( 1, arg, sizeof( arg ) );
- i = ClientNumberFromString( ent, arg );
- if ( i == -1 ) {
- return;
- }
-
- // can't follow self
- if ( &level.clients[ i ] == ent->client ) {
- return;
- }
-
- // can't follow another spectator
- if ( level.clients[ i ].sess.sessionTeam == TEAM_SPECTATOR ) {
- return;
- }
-
- // if they are playing a tournement game, count as a loss
- if ( (g_gametype.integer == GT_TOURNAMENT )
- && ent->client->sess.sessionTeam == TEAM_FREE ) {
- ent->client->sess.losses++;
- }
-
- // first set them to spectator
- if ( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- SetTeam( ent, "spectator" );
- }
-
- ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
- ent->client->sess.spectatorClient = i;
-}
-
-/*
-=================
-Cmd_FollowCycle_f
-=================
-*/
-void Cmd_FollowCycle_f( gentity_t *ent, int dir ) {
- int clientnum;
- int original;
-
- // if they are playing a tournement game, count as a loss
- if ( (g_gametype.integer == GT_TOURNAMENT )
- && ent->client->sess.sessionTeam == TEAM_FREE ) {
- ent->client->sess.losses++;
- }
- // first set them to spectator
- if ( ent->client->sess.spectatorState == SPECTATOR_NOT ) {
- SetTeam( ent, "spectator" );
- }
-
- if ( dir != 1 && dir != -1 ) {
- G_Error( "Cmd_FollowCycle_f: bad dir %i", dir );
- }
-
- clientnum = ent->client->sess.spectatorClient;
- original = clientnum;
- do {
- clientnum += dir;
- if ( clientnum >= level.maxclients ) {
- clientnum = 0;
- }
- if ( clientnum < 0 ) {
- clientnum = level.maxclients - 1;
- }
-
- // can only follow connected clients
- if ( level.clients[ clientnum ].pers.connected != CON_CONNECTED ) {
- continue;
- }
-
- // can't follow another spectator
- if ( level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR ) {
- continue;
- }
-
- // this is good, we can use it
- ent->client->sess.spectatorClient = clientnum;
- ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
- return;
- } while ( clientnum != original );
-
- // leave it where it was
-}
-
-
-/*
-==================
-G_Say
-==================
-*/
-
-static void G_SayTo( gentity_t *ent, gentity_t *other, int mode, int color, const char *name, const char *message ) {
- if (!other) {
- return;
- }
- if (!other->inuse) {
- return;
- }
- if (!other->client) {
- return;
- }
- if ( other->client->pers.connected != CON_CONNECTED ) {
- return;
- }
- if ( mode == SAY_TEAM && !OnSameTeam(ent, other) ) {
- return;
- }
- // no chatting to players in tournements
- if ( (g_gametype.integer == GT_TOURNAMENT )
- && other->client->sess.sessionTeam == TEAM_FREE
- && ent->client->sess.sessionTeam != TEAM_FREE ) {
- return;
- }
-
- trap_SendServerCommand( other-g_entities, va("%s \"%s%c%c%s\"",
- mode == SAY_TEAM ? "tchat" : "chat",
- name, Q_COLOR_ESCAPE, color, message));
-}
-
-#define EC "\x19"
-
-void G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText ) {
- int j;
- gentity_t *other;
- int color;
- char name[64];
- // don't let text be too long for malicious reasons
- char text[MAX_SAY_TEXT];
- char location[64];
-
- if ( g_gametype.integer < GT_TEAM && mode == SAY_TEAM ) {
- mode = SAY_ALL;
- }
-
- switch ( mode ) {
- default:
- case SAY_ALL:
- G_LogPrintf( "say: %s: %s\n", ent->client->pers.netname, chatText );
- Com_sprintf (name, sizeof(name), "%s%c%c"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_GREEN;
- break;
- case SAY_TEAM:
- G_LogPrintf( "sayteam: %s: %s\n", ent->client->pers.netname, chatText );
- if (Team_GetLocationMsg(ent, location, sizeof(location)))
- Com_sprintf (name, sizeof(name), EC"(%s%c%c"EC") (%s)"EC": ",
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location);
- else
- Com_sprintf (name, sizeof(name), EC"(%s%c%c"EC")"EC": ",
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_CYAN;
- break;
- case SAY_TELL:
- if (target && g_gametype.integer >= GT_TEAM &&
- target->client->sess.sessionTeam == ent->client->sess.sessionTeam &&
- Team_GetLocationMsg(ent, location, sizeof(location)))
- Com_sprintf (name, sizeof(name), EC"[%s%c%c"EC"] (%s)"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location );
- else
- Com_sprintf (name, sizeof(name), EC"[%s%c%c"EC"]"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_MAGENTA;
- break;
- }
-
- Q_strncpyz( text, chatText, sizeof(text) );
-
- if ( target ) {
- G_SayTo( ent, target, mode, color, name, text );
- return;
- }
-
- // echo the text to the console
- if ( g_dedicated.integer ) {
- G_Printf( "%s%s\n", name, text);
- }
-
- // send it to all the apropriate clients
- for (j = 0; j < level.maxclients; j++) {
- other = &g_entities[j];
- G_SayTo( ent, other, mode, color, name, text );
- }
-}
-
-
-/*
-==================
-Cmd_Say_f
-==================
-*/
-static void Cmd_Say_f( gentity_t *ent, int mode, qboolean arg0 ) {
- char *p;
-
- if ( trap_Argc () < 2 && !arg0 ) {
- return;
- }
-
- if (arg0)
- {
- p = ConcatArgs( 0 );
- }
- else
- {
- p = ConcatArgs( 1 );
- }
-
- G_Say( ent, NULL, mode, p );
-}
-
-/*
-==================
-Cmd_Tell_f
-==================
-*/
-static void Cmd_Tell_f( gentity_t *ent ) {
- int targetNum;
- gentity_t *target;
- char *p;
- char arg[MAX_TOKEN_CHARS];
-
- if ( trap_Argc () < 2 ) {
- return;
- }
-
- trap_Argv( 1, arg, sizeof( arg ) );
- targetNum = atoi( arg );
- if ( targetNum < 0 || targetNum >= level.maxclients ) {
- return;
- }
-
- target = &g_entities[targetNum];
- if ( !target || !target->inuse || !target->client ) {
- return;
- }
-
- p = ConcatArgs( 2 );
-
- G_LogPrintf( "tell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, p );
- G_Say( ent, target, SAY_TELL, p );
- // don't tell to the player self if it was already directed to this player
- // also don't send the chat back to a bot
- if ( ent != target && !(ent->r.svFlags & SVF_BOT)) {
- G_Say( ent, ent, SAY_TELL, p );
- }
-}
-
-
-static void G_VoiceTo( gentity_t *ent, gentity_t *other, int mode, const char *id, qboolean voiceonly ) {
- int color;
- char *cmd;
-
- if (!other) {
- return;
- }
- if (!other->inuse) {
- return;
- }
- if (!other->client) {
- return;
- }
- if ( mode == SAY_TEAM && !OnSameTeam(ent, other) ) {
- return;
- }
- // no chatting to players in tournements
- if ( (g_gametype.integer == GT_TOURNAMENT )) {
- return;
- }
-
- if (mode == SAY_TEAM) {
- color = COLOR_CYAN;
- cmd = "vtchat";
- }
- else if (mode == SAY_TELL) {
- color = COLOR_MAGENTA;
- cmd = "vtell";
- }
- else {
- color = COLOR_GREEN;
- cmd = "vchat";
- }
-
- trap_SendServerCommand( other-g_entities, va("%s %d %d %d %s", cmd, voiceonly, ent->s.number, color, id));
-}
-
-void G_Voice( gentity_t *ent, gentity_t *target, int mode, const char *id, qboolean voiceonly ) {
- int j;
- gentity_t *other;
-
- if ( g_gametype.integer < GT_TEAM && mode == SAY_TEAM ) {
- mode = SAY_ALL;
- }
-
- if ( target ) {
- G_VoiceTo( ent, target, mode, id, voiceonly );
- return;
- }
-
- // echo the text to the console
- if ( g_dedicated.integer ) {
- G_Printf( "voice: %s %s\n", ent->client->pers.netname, id);
- }
-
- // send it to all the apropriate clients
- for (j = 0; j < level.maxclients; j++) {
- other = &g_entities[j];
- G_VoiceTo( ent, other, mode, id, voiceonly );
- }
-}
-
-/*
-==================
-Cmd_Voice_f
-==================
-*/
-static void Cmd_Voice_f( gentity_t *ent, int mode, qboolean arg0, qboolean voiceonly ) {
- char *p;
-
- if ( trap_Argc () < 2 && !arg0 ) {
- return;
- }
-
- if (arg0)
- {
- p = ConcatArgs( 0 );
- }
- else
- {
- p = ConcatArgs( 1 );
- }
-
- G_Voice( ent, NULL, mode, p, voiceonly );
-}
-
-/*
-==================
-Cmd_VoiceTell_f
-==================
-*/
-static void Cmd_VoiceTell_f( gentity_t *ent, qboolean voiceonly ) {
- int targetNum;
- gentity_t *target;
- char *id;
- char arg[MAX_TOKEN_CHARS];
-
- if ( trap_Argc () < 2 ) {
- return;
- }
-
- trap_Argv( 1, arg, sizeof( arg ) );
- targetNum = atoi( arg );
- if ( targetNum < 0 || targetNum >= level.maxclients ) {
- return;
- }
-
- target = &g_entities[targetNum];
- if ( !target || !target->inuse || !target->client ) {
- return;
- }
-
- id = ConcatArgs( 2 );
-
- G_LogPrintf( "vtell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, id );
- G_Voice( ent, target, SAY_TELL, id, voiceonly );
- // don't tell to the player self if it was already directed to this player
- // also don't send the chat back to a bot
- if ( ent != target && !(ent->r.svFlags & SVF_BOT)) {
- G_Voice( ent, ent, SAY_TELL, id, voiceonly );
- }
-}
-
-
-/*
-==================
-Cmd_VoiceTaunt_f
-==================
-*/
-static void Cmd_VoiceTaunt_f( gentity_t *ent ) {
- gentity_t *who;
- int i;
-
- if (!ent->client) {
- return;
- }
-
- // insult someone who just killed you
- if (ent->enemy && ent->enemy->client && ent->enemy->client->lastkilled_client == ent->s.number) {
- // i am a dead corpse
- if (!(ent->enemy->r.svFlags & SVF_BOT)) {
- G_Voice( ent, ent->enemy, SAY_TELL, VOICECHAT_DEATHINSULT, qfalse );
- }
- if (!(ent->r.svFlags & SVF_BOT)) {
- G_Voice( ent, ent, SAY_TELL, VOICECHAT_DEATHINSULT, qfalse );
- }
- ent->enemy = NULL;
- return;
- }
- // insult someone you just killed
- if (ent->client->lastkilled_client >= 0 && ent->client->lastkilled_client != ent->s.number) {
- who = g_entities + ent->client->lastkilled_client;
- if (who->client) {
- // who is the person I just killed
- if (who->client->lasthurt_mod == MOD_GAUNTLET) {
- if (!(who->r.svFlags & SVF_BOT)) {
- G_Voice( ent, who, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse ); // and I killed them with a gauntlet
- }
- if (!(ent->r.svFlags & SVF_BOT)) {
- G_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse );
- }
- } else {
- if (!(who->r.svFlags & SVF_BOT)) {
- G_Voice( ent, who, SAY_TELL, VOICECHAT_KILLINSULT, qfalse ); // and I killed them with something else
- }
- if (!(ent->r.svFlags & SVF_BOT)) {
- G_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLINSULT, qfalse );
- }
- }
- ent->client->lastkilled_client = -1;
- return;
- }
- }
-
- if (g_gametype.integer >= GT_TEAM) {
- // praise a team mate who just got a reward
- for(i = 0; i < MAX_CLIENTS; i++) {
- who = g_entities + i;
- if (who->client && who != ent && who->client->sess.sessionTeam == ent->client->sess.sessionTeam) {
- if (who->client->rewardTime > level.time) {
- if (!(who->r.svFlags & SVF_BOT)) {
- G_Voice( ent, who, SAY_TELL, VOICECHAT_PRAISE, qfalse );
- }
- if (!(ent->r.svFlags & SVF_BOT)) {
- G_Voice( ent, ent, SAY_TELL, VOICECHAT_PRAISE, qfalse );
- }
- return;
- }
- }
- }
- }
-
- // just say something
- G_Voice( ent, NULL, SAY_ALL, VOICECHAT_TAUNT, qfalse );
-}
-
-
-
-static char *gc_orders[] = {
- "hold your position",
- "hold this position",
- "come here",
- "cover me",
- "guard location",
- "search and destroy",
- "report"
-};
-
-void Cmd_GameCommand_f( gentity_t *ent ) {
- int player;
- int order;
- char str[MAX_TOKEN_CHARS];
-
- trap_Argv( 1, str, sizeof( str ) );
- player = atoi( str );
- trap_Argv( 2, str, sizeof( str ) );
- order = atoi( str );
-
- if ( player < 0 || player >= MAX_CLIENTS ) {
- return;
- }
- if ( order < 0 || order > sizeof(gc_orders)/sizeof(char *) ) {
- return;
- }
- G_Say( ent, &g_entities[player], SAY_TELL, gc_orders[order] );
- G_Say( ent, ent, SAY_TELL, gc_orders[order] );
-}
-
-/*
-==================
-Cmd_Where_f
-==================
-*/
-void Cmd_Where_f( gentity_t *ent ) {
- trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", vtos( ent->s.origin ) ) );
-}
-
-static const char *gameNames[] = {
- "Free For All",
- "Tournament",
- "Single Player",
- "Team Deathmatch",
- "Capture the Flag",
- "One Flag CTF",
- "Overload",
- "Harvester"
-};
-
-/*
-==================
-Cmd_CallVote_f
-==================
-*/
-void Cmd_CallVote_f( gentity_t *ent ) {
- char* c;
- int i;
- char arg1[MAX_STRING_TOKENS];
- char arg2[MAX_STRING_TOKENS];
-
- if ( !g_allowVote.integer ) {
- trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here.\n\"" );
- return;
- }
-
- if ( level.voteTime ) {
- trap_SendServerCommand( ent-g_entities, "print \"A vote is already in progress.\n\"" );
- return;
- }
- if ( ent->client->pers.voteCount >= MAX_VOTE_COUNT ) {
- trap_SendServerCommand( ent-g_entities, "print \"You have called the maximum number of votes.\n\"" );
- return;
- }
- if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
- trap_SendServerCommand( ent-g_entities, "print \"Not allowed to call a vote as spectator.\n\"" );
- return;
- }
-
- // make sure it is a valid command to vote on
- trap_Argv( 1, arg1, sizeof( arg1 ) );
- trap_Argv( 2, arg2, sizeof( arg2 ) );
-
- // check for command separators in arg2
- for( c = arg2; *c; ++c) {
- switch(*c) {
- case '\n':
- case '\r':
- case ';':
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
- return;
- break;
- }
- }
-
- if ( !Q_stricmp( arg1, "map_restart" ) ) {
- } else if ( !Q_stricmp( arg1, "nextmap" ) ) {
- } else if ( !Q_stricmp( arg1, "map" ) ) {
- } else if ( !Q_stricmp( arg1, "g_gametype" ) ) {
- } else if ( !Q_stricmp( arg1, "kick" ) ) {
- } else if ( !Q_stricmp( arg1, "clientkick" ) ) {
- } else if ( !Q_stricmp( arg1, "g_doWarmup" ) ) {
- } else if ( !Q_stricmp( arg1, "timelimit" ) ) {
- } else if ( !Q_stricmp( arg1, "fraglimit" ) ) {
- } else {
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
- trap_SendServerCommand( ent-g_entities, "print \"Vote commands are: map_restart, nextmap, map <mapname>, g_gametype <n>, kick <player>, clientkick <clientnum>, g_doWarmup, timelimit <time>, fraglimit <frags>.\n\"" );
- return;
- }
-
- // if there is still a vote to be executed
- if ( level.voteExecuteTime ) {
- level.voteExecuteTime = 0;
- trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.voteString ) );
- }
-
- // special case for g_gametype, check for bad values
- if ( !Q_stricmp( arg1, "g_gametype" ) ) {
- i = atoi( arg2 );
- if( i == GT_SINGLE_PLAYER || i < GT_FFA || i >= GT_MAX_GAME_TYPE) {
- trap_SendServerCommand( ent-g_entities, "print \"Invalid gametype.\n\"" );
- return;
- }
-
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %d", arg1, i );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s %s", arg1, gameNames[i] );
- } else if ( !Q_stricmp( arg1, "map" ) ) {
- // special case for map changes, we want to reset the nextmap setting
- // this allows a player to change maps, but not upset the map rotation
- char s[MAX_STRING_CHARS];
-
- trap_Cvar_VariableStringBuffer( "nextmap", s, sizeof(s) );
- if (*s) {
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %s; set nextmap \"%s\"", arg1, arg2, s );
- } else {
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %s", arg1, arg2 );
- }
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString );
- } else if ( !Q_stricmp( arg1, "nextmap" ) ) {
- char s[MAX_STRING_CHARS];
-
- trap_Cvar_VariableStringBuffer( "nextmap", s, sizeof(s) );
- if (!*s) {
- trap_SendServerCommand( ent-g_entities, "print \"nextmap not set.\n\"" );
- return;
- }
- Com_sprintf( level.voteString, sizeof( level.voteString ), "vstr nextmap");
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString );
- } else {
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s \"%s\"", arg1, arg2 );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString );
- }
-
- trap_SendServerCommand( -1, va("print \"%s called a vote.\n\"", ent->client->pers.netname ) );
-
- // start the voting, the caller autoamtically votes yes
- level.voteTime = level.time;
- level.voteYes = 1;
- level.voteNo = 0;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- level.clients[i].ps.eFlags &= ~EF_VOTED;
- }
- ent->client->ps.eFlags |= EF_VOTED;
-
- trap_SetConfigstring( CS_VOTE_TIME, va("%i", level.voteTime ) );
- trap_SetConfigstring( CS_VOTE_STRING, level.voteDisplayString );
- trap_SetConfigstring( CS_VOTE_YES, va("%i", level.voteYes ) );
- trap_SetConfigstring( CS_VOTE_NO, va("%i", level.voteNo ) );
-}
-
-/*
-==================
-Cmd_Vote_f
-==================
-*/
-void Cmd_Vote_f( gentity_t *ent ) {
- char msg[64];
-
- if ( !level.voteTime ) {
- trap_SendServerCommand( ent-g_entities, "print \"No vote in progress.\n\"" );
- return;
- }
- if ( ent->client->ps.eFlags & EF_VOTED ) {
- trap_SendServerCommand( ent-g_entities, "print \"Vote already cast.\n\"" );
- return;
- }
- if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
- trap_SendServerCommand( ent-g_entities, "print \"Not allowed to vote as spectator.\n\"" );
- return;
- }
-
- trap_SendServerCommand( ent-g_entities, "print \"Vote cast.\n\"" );
-
- ent->client->ps.eFlags |= EF_VOTED;
-
- trap_Argv( 1, msg, sizeof( msg ) );
-
- if ( msg[0] == 'y' || msg[1] == 'Y' || msg[1] == '1' ) {
- level.voteYes++;
- trap_SetConfigstring( CS_VOTE_YES, va("%i", level.voteYes ) );
- } else {
- level.voteNo++;
- trap_SetConfigstring( CS_VOTE_NO, va("%i", level.voteNo ) );
- }
-
- // a majority will be determined in CheckVote, which will also account
- // for players entering or leaving
-}
-
-/*
-==================
-Cmd_CallTeamVote_f
-==================
-*/
-void Cmd_CallTeamVote_f( gentity_t *ent ) {
- int i, team, cs_offset;
- char arg1[MAX_STRING_TOKENS];
- char arg2[MAX_STRING_TOKENS];
-
- team = ent->client->sess.sessionTeam;
- if ( team == TEAM_RED )
- cs_offset = 0;
- else if ( team == TEAM_BLUE )
- cs_offset = 1;
- else
- return;
-
- if ( !g_allowVote.integer ) {
- trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here.\n\"" );
- return;
- }
-
- if ( level.teamVoteTime[cs_offset] ) {
- trap_SendServerCommand( ent-g_entities, "print \"A team vote is already in progress.\n\"" );
- return;
- }
- if ( ent->client->pers.teamVoteCount >= MAX_VOTE_COUNT ) {
- trap_SendServerCommand( ent-g_entities, "print \"You have called the maximum number of team votes.\n\"" );
- return;
- }
- if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
- trap_SendServerCommand( ent-g_entities, "print \"Not allowed to call a vote as spectator.\n\"" );
- return;
- }
-
- // make sure it is a valid command to vote on
- trap_Argv( 1, arg1, sizeof( arg1 ) );
- arg2[0] = '\0';
- for ( i = 2; i < trap_Argc(); i++ ) {
- if (i > 2)
- strcat(arg2, " ");
- trap_Argv( i, &arg2[strlen(arg2)], sizeof( arg2 ) - strlen(arg2) );
- }
-
- if( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) {
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
- return;
- }
-
- if ( !Q_stricmp( arg1, "leader" ) ) {
- char netname[MAX_NETNAME], leader[MAX_NETNAME];
-
- if ( !arg2[0] ) {
- i = ent->client->ps.clientNum;
- }
- else {
- // numeric values are just slot numbers
- for (i = 0; i < 3; i++) {
- if ( !arg2[i] || arg2[i] < '0' || arg2[i] > '9' )
- break;
- }
- if ( i >= 3 || !arg2[i]) {
- i = atoi( arg2 );
- if ( i < 0 || i >= level.maxclients ) {
- trap_SendServerCommand( ent-g_entities, va("print \"Bad client slot: %i\n\"", i) );
- return;
- }
-
- if ( !g_entities[i].inuse ) {
- trap_SendServerCommand( ent-g_entities, va("print \"Client %i is not active\n\"", i) );
- return;
- }
- }
- else {
- Q_strncpyz(leader, arg2, sizeof(leader));
- Q_CleanStr(leader);
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].pers.connected == CON_DISCONNECTED )
- continue;
- if (level.clients[i].sess.sessionTeam != team)
- continue;
- Q_strncpyz(netname, level.clients[i].pers.netname, sizeof(netname));
- Q_CleanStr(netname);
- if ( !Q_stricmp(netname, leader) ) {
- break;
- }
- }
- if ( i >= level.maxclients ) {
- trap_SendServerCommand( ent-g_entities, va("print \"%s is not a valid player on your team.\n\"", arg2) );
- return;
- }
- }
- }
- Com_sprintf(arg2, sizeof(arg2), "%d", i);
- } else {
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
- trap_SendServerCommand( ent-g_entities, "print \"Team vote commands are: leader <player>.\n\"" );
- return;
- }
-
- Com_sprintf( level.teamVoteString[cs_offset], sizeof( level.teamVoteString[cs_offset] ), "%s %s", arg1, arg2 );
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].pers.connected == CON_DISCONNECTED )
- continue;
- if (level.clients[i].sess.sessionTeam == team)
- trap_SendServerCommand( i, va("print \"%s called a team vote.\n\"", ent->client->pers.netname ) );
- }
-
- // start the voting, the caller autoamtically votes yes
- level.teamVoteTime[cs_offset] = level.time;
- level.teamVoteYes[cs_offset] = 1;
- level.teamVoteNo[cs_offset] = 0;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if (level.clients[i].sess.sessionTeam == team)
- level.clients[i].ps.eFlags &= ~EF_TEAMVOTED;
- }
- ent->client->ps.eFlags |= EF_TEAMVOTED;
-
- trap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, va("%i", level.teamVoteTime[cs_offset] ) );
- trap_SetConfigstring( CS_TEAMVOTE_STRING + cs_offset, level.teamVoteString[cs_offset] );
- trap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, va("%i", level.teamVoteYes[cs_offset] ) );
- trap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, va("%i", level.teamVoteNo[cs_offset] ) );
-}
-
-/*
-==================
-Cmd_TeamVote_f
-==================
-*/
-void Cmd_TeamVote_f( gentity_t *ent ) {
- int team, cs_offset;
- char msg[64];
-
- team = ent->client->sess.sessionTeam;
- if ( team == TEAM_RED )
- cs_offset = 0;
- else if ( team == TEAM_BLUE )
- cs_offset = 1;
- else
- return;
-
- if ( !level.teamVoteTime[cs_offset] ) {
- trap_SendServerCommand( ent-g_entities, "print \"No team vote in progress.\n\"" );
- return;
- }
- if ( ent->client->ps.eFlags & EF_TEAMVOTED ) {
- trap_SendServerCommand( ent-g_entities, "print \"Team vote already cast.\n\"" );
- return;
- }
- if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
- trap_SendServerCommand( ent-g_entities, "print \"Not allowed to vote as spectator.\n\"" );
- return;
- }
-
- trap_SendServerCommand( ent-g_entities, "print \"Team vote cast.\n\"" );
-
- ent->client->ps.eFlags |= EF_TEAMVOTED;
-
- trap_Argv( 1, msg, sizeof( msg ) );
-
- if ( msg[0] == 'y' || msg[1] == 'Y' || msg[1] == '1' ) {
- level.teamVoteYes[cs_offset]++;
- trap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, va("%i", level.teamVoteYes[cs_offset] ) );
- } else {
- level.teamVoteNo[cs_offset]++;
- trap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, va("%i", level.teamVoteNo[cs_offset] ) );
- }
-
- // a majority will be determined in TeamCheckVote, which will also account
- // for players entering or leaving
-}
-
-
-/*
-=================
-Cmd_SetViewpos_f
-=================
-*/
-void Cmd_SetViewpos_f( gentity_t *ent ) {
- vec3_t origin, angles;
- char buffer[MAX_TOKEN_CHARS];
- int i;
-
- if ( !g_cheats.integer ) {
- trap_SendServerCommand( ent-g_entities, va("print \"Cheats are not enabled on this server.\n\""));
- return;
- }
- if ( trap_Argc() != 5 ) {
- trap_SendServerCommand( ent-g_entities, va("print \"usage: setviewpos x y z yaw\n\""));
- return;
- }
-
- VectorClear( angles );
- for ( i = 0 ; i < 3 ; i++ ) {
- trap_Argv( i + 1, buffer, sizeof( buffer ) );
- origin[i] = atof( buffer );
- }
-
- trap_Argv( 4, buffer, sizeof( buffer ) );
- angles[YAW] = atof( buffer );
-
- TeleportPlayer( ent, origin, angles );
-}
-
-
-
-/*
-=================
-Cmd_Stats_f
-=================
-*/
-void Cmd_Stats_f( gentity_t *ent ) {
-/*
- int max, n, i;
-
- max = trap_AAS_PointReachabilityAreaIndex( NULL );
-
- n = 0;
- for ( i = 0; i < max; i++ ) {
- if ( ent->client->areabits[i >> 3] & (1 << (i & 7)) )
- n++;
- }
-
- //trap_SendServerCommand( ent-g_entities, va("print \"visited %d of %d areas\n\"", n, max));
- trap_SendServerCommand( ent-g_entities, va("print \"%d%% level coverage\n\"", n * 100 / max));
-*/
-}
-
-/*
-=================
-ClientCommand
-=================
-*/
-void ClientCommand( int clientNum ) {
- gentity_t *ent;
- char cmd[MAX_TOKEN_CHARS];
-
- ent = g_entities + clientNum;
- if ( !ent->client ) {
- return; // not fully in game yet
- }
-
-
- trap_Argv( 0, cmd, sizeof( cmd ) );
-
- if (Q_stricmp (cmd, "say") == 0) {
- Cmd_Say_f (ent, SAY_ALL, qfalse);
- return;
- }
- if (Q_stricmp (cmd, "say_team") == 0) {
- Cmd_Say_f (ent, SAY_TEAM, qfalse);
- return;
- }
- if (Q_stricmp (cmd, "tell") == 0) {
- Cmd_Tell_f ( ent );
- return;
- }
- if (Q_stricmp (cmd, "vsay") == 0) {
- Cmd_Voice_f (ent, SAY_ALL, qfalse, qfalse);
- return;
- }
- if (Q_stricmp (cmd, "vsay_team") == 0) {
- Cmd_Voice_f (ent, SAY_TEAM, qfalse, qfalse);
- return;
- }
- if (Q_stricmp (cmd, "vtell") == 0) {
- Cmd_VoiceTell_f ( ent, qfalse );
- return;
- }
- if (Q_stricmp (cmd, "vosay") == 0) {
- Cmd_Voice_f (ent, SAY_ALL, qfalse, qtrue);
- return;
- }
- if (Q_stricmp (cmd, "vosay_team") == 0) {
- Cmd_Voice_f (ent, SAY_TEAM, qfalse, qtrue);
- return;
- }
- if (Q_stricmp (cmd, "votell") == 0) {
- Cmd_VoiceTell_f ( ent, qtrue );
- return;
- }
- if (Q_stricmp (cmd, "vtaunt") == 0) {
- Cmd_VoiceTaunt_f ( ent );
- return;
- }
- if (Q_stricmp (cmd, "score") == 0) {
- Cmd_Score_f (ent);
- return;
- }
-
- // ignore all other commands when at intermission
- if (level.intermissiontime) {
- Cmd_Say_f (ent, qfalse, qtrue);
- return;
- }
-
- if (Q_stricmp (cmd, "give") == 0)
- Cmd_Give_f (ent);
- else if (Q_stricmp (cmd, "god") == 0)
- Cmd_God_f (ent);
- else if (Q_stricmp (cmd, "notarget") == 0)
- Cmd_Notarget_f (ent);
- else if (Q_stricmp (cmd, "noclip") == 0)
- Cmd_Noclip_f (ent);
- else if (Q_stricmp (cmd, "kill") == 0)
- Cmd_Kill_f (ent);
- else if (Q_stricmp (cmd, "teamtask") == 0)
- Cmd_TeamTask_f (ent);
- else if (Q_stricmp (cmd, "levelshot") == 0)
- Cmd_LevelShot_f (ent);
- else if (Q_stricmp (cmd, "follow") == 0)
- Cmd_Follow_f (ent);
- else if (Q_stricmp (cmd, "follownext") == 0)
- Cmd_FollowCycle_f (ent, 1);
- else if (Q_stricmp (cmd, "followprev") == 0)
- Cmd_FollowCycle_f (ent, -1);
- else if (Q_stricmp (cmd, "team") == 0)
- Cmd_Team_f (ent);
- else if (Q_stricmp (cmd, "where") == 0)
- Cmd_Where_f (ent);
- else if (Q_stricmp (cmd, "callvote") == 0)
- Cmd_CallVote_f (ent);
- else if (Q_stricmp (cmd, "vote") == 0)
- Cmd_Vote_f (ent);
- else if (Q_stricmp (cmd, "callteamvote") == 0)
- Cmd_CallTeamVote_f (ent);
- else if (Q_stricmp (cmd, "teamvote") == 0)
- Cmd_TeamVote_f (ent);
- else if (Q_stricmp (cmd, "gc") == 0)
- Cmd_GameCommand_f( ent );
- else if (Q_stricmp (cmd, "setviewpos") == 0)
- Cmd_SetViewpos_f( ent );
- else if (Q_stricmp (cmd, "stats") == 0)
- Cmd_Stats_f( ent );
- else
- trap_SendServerCommand( clientNum, va("print \"unknown cmd %s\n\"", cmd ) );
-}
diff --git a/engine/code/game/g_combat.c b/engine/code/game/g_combat.c
deleted file mode 100644
index 6538656..0000000
--- a/engine/code/game/g_combat.c
+++ /dev/null
@@ -1,1196 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// g_combat.c
-
-#include "g_local.h"
-
-
-/*
-============
-ScorePlum
-============
-*/
-void ScorePlum( gentity_t *ent, vec3_t origin, int score ) {
- gentity_t *plum;
-
- plum = G_TempEntity( origin, EV_SCOREPLUM );
- // only send this temp entity to a single client
- plum->r.svFlags |= SVF_SINGLECLIENT;
- plum->r.singleClient = ent->s.number;
- //
- plum->s.otherEntityNum = ent->s.number;
- plum->s.time = score;
-}
-
-/*
-============
-AddScore
-
-Adds score to both the client and his team
-============
-*/
-void AddScore( gentity_t *ent, vec3_t origin, int score ) {
- if ( !ent->client ) {
- return;
- }
- // no scoring during pre-match warmup
- if ( level.warmupTime ) {
- return;
- }
- // show score plum
- ScorePlum(ent, origin, score);
- //
- ent->client->ps.persistant[PERS_SCORE] += score;
- if ( g_gametype.integer == GT_TEAM )
- level.teamScores[ ent->client->ps.persistant[PERS_TEAM] ] += score;
- CalculateRanks();
-}
-
-/*
-=================
-TossClientItems
-
-Toss the weapon and powerups for the killed player
-=================
-*/
-void TossClientItems( gentity_t *self ) {
- gitem_t *item;
- int weapon;
- float angle;
- int i;
- gentity_t *drop;
-
- // drop the weapon if not a gauntlet or machinegun
- weapon = self->s.weapon;
-
- // make a special check to see if they are changing to a new
- // weapon that isn't the mg or gauntlet. Without this, a client
- // can pick up a weapon, be killed, and not drop the weapon because
- // their weapon change hasn't completed yet and they are still holding the MG.
- if ( weapon == WP_MACHINEGUN || weapon == WP_GRAPPLING_HOOK ) {
- if ( self->client->ps.weaponstate == WEAPON_DROPPING ) {
- weapon = self->client->pers.cmd.weapon;
- }
- if ( !( self->client->ps.stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
- weapon = WP_NONE;
- }
- }
-
- if ( weapon > WP_MACHINEGUN && weapon != WP_GRAPPLING_HOOK &&
- self->client->ps.ammo[ weapon ] ) {
- // find the item type for this weapon
- item = BG_FindItemForWeapon( weapon );
-
- // spawn the item
- Drop_Item( self, item, 0 );
- }
-
- // drop all the powerups if not in teamplay
- if ( g_gametype.integer != GT_TEAM ) {
- angle = 45;
- for ( i = 1 ; i < PW_NUM_POWERUPS ; i++ ) {
- if ( self->client->ps.powerups[ i ] > level.time ) {
- item = BG_FindItemForPowerup( i );
- if ( !item ) {
- continue;
- }
- drop = Drop_Item( self, item, angle );
- // decide how many seconds it has left
- drop->count = ( self->client->ps.powerups[ i ] - level.time ) / 1000;
- if ( drop->count < 1 ) {
- drop->count = 1;
- }
- angle += 45;
- }
- }
- }
-}
-
-#ifdef MISSIONPACK
-
-/*
-=================
-TossClientCubes
-=================
-*/
-extern gentity_t *neutralObelisk;
-
-void TossClientCubes( gentity_t *self ) {
- gitem_t *item;
- gentity_t *drop;
- vec3_t velocity;
- vec3_t angles;
- vec3_t origin;
-
- self->client->ps.generic1 = 0;
-
- // this should never happen but we should never
- // get the server to crash due to skull being spawned in
- if (!G_EntitiesFree()) {
- return;
- }
-
- if( self->client->sess.sessionTeam == TEAM_RED ) {
- item = BG_FindItem( "Red Cube" );
- }
- else {
- item = BG_FindItem( "Blue Cube" );
- }
-
- angles[YAW] = (float)(level.time % 360);
- angles[PITCH] = 0; // always forward
- angles[ROLL] = 0;
-
- AngleVectors( angles, velocity, NULL, NULL );
- VectorScale( velocity, 150, velocity );
- velocity[2] += 200 + crandom() * 50;
-
- if( neutralObelisk ) {
- VectorCopy( neutralObelisk->s.pos.trBase, origin );
- origin[2] += 44;
- } else {
- VectorClear( origin ) ;
- }
-
- drop = LaunchItem( item, origin, velocity );
-
- drop->nextthink = level.time + g_cubeTimeout.integer * 1000;
- drop->think = G_FreeEntity;
- drop->spawnflags = self->client->sess.sessionTeam;
-}
-
-
-/*
-=================
-TossClientPersistantPowerups
-=================
-*/
-void TossClientPersistantPowerups( gentity_t *ent ) {
- gentity_t *powerup;
-
- if( !ent->client ) {
- return;
- }
-
- if( !ent->client->persistantPowerup ) {
- return;
- }
-
- powerup = ent->client->persistantPowerup;
-
- powerup->r.svFlags &= ~SVF_NOCLIENT;
- powerup->s.eFlags &= ~EF_NODRAW;
- powerup->r.contents = CONTENTS_TRIGGER;
- trap_LinkEntity( powerup );
-
- ent->client->ps.stats[STAT_PERSISTANT_POWERUP] = 0;
- ent->client->persistantPowerup = NULL;
-}
-#endif
-
-
-/*
-==================
-LookAtKiller
-==================
-*/
-void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker ) {
- vec3_t dir;
- vec3_t angles;
-
- if ( attacker && attacker != self ) {
- VectorSubtract (attacker->s.pos.trBase, self->s.pos.trBase, dir);
- } else if ( inflictor && inflictor != self ) {
- VectorSubtract (inflictor->s.pos.trBase, self->s.pos.trBase, dir);
- } else {
- self->client->ps.stats[STAT_DEAD_YAW] = self->s.angles[YAW];
- return;
- }
-
- self->client->ps.stats[STAT_DEAD_YAW] = vectoyaw ( dir );
-
- angles[YAW] = vectoyaw ( dir );
- angles[PITCH] = 0;
- angles[ROLL] = 0;
-}
-
-/*
-==================
-GibEntity
-==================
-*/
-void GibEntity( gentity_t *self, int killer ) {
- gentity_t *ent;
- int i;
-
- //if this entity still has kamikaze
- if (self->s.eFlags & EF_KAMIKAZE) {
- // check if there is a kamikaze timer around for this owner
- for (i = 0; i < MAX_GENTITIES; i++) {
- ent = &g_entities[i];
- if (!ent->inuse)
- continue;
- if (ent->activator != self)
- continue;
- if (strcmp(ent->classname, "kamikaze timer"))
- continue;
- G_FreeEntity(ent);
- break;
- }
- }
- G_AddEvent( self, EV_GIB_PLAYER, killer );
- self->takedamage = qfalse;
- self->s.eType = ET_INVISIBLE;
- self->r.contents = 0;
-}
-
-/*
-==================
-body_die
-==================
-*/
-void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
- if ( self->health > GIB_HEALTH ) {
- return;
- }
- if ( !g_blood.integer ) {
- self->health = GIB_HEALTH+1;
- return;
- }
-
- GibEntity( self, 0 );
-}
-
-
-// these are just for logging, the client prints its own messages
-char *modNames[] = {
- "MOD_UNKNOWN",
- "MOD_SHOTGUN",
- "MOD_GAUNTLET",
- "MOD_MACHINEGUN",
- "MOD_GRENADE",
- "MOD_GRENADE_SPLASH",
- "MOD_ROCKET",
- "MOD_ROCKET_SPLASH",
- "MOD_PLASMA",
- "MOD_PLASMA_SPLASH",
- "MOD_RAILGUN",
- "MOD_LIGHTNING",
- "MOD_BFG",
- "MOD_BFG_SPLASH",
- "MOD_WATER",
- "MOD_SLIME",
- "MOD_LAVA",
- "MOD_CRUSH",
- "MOD_TELEFRAG",
- "MOD_FALLING",
- "MOD_SUICIDE",
- "MOD_TARGET_LASER",
- "MOD_TRIGGER_HURT",
-#ifdef MISSIONPACK
- "MOD_NAIL",
- "MOD_CHAINGUN",
- "MOD_PROXIMITY_MINE",
- "MOD_KAMIKAZE",
- "MOD_JUICED",
-#endif
- "MOD_GRAPPLE"
-};
-
-#ifdef MISSIONPACK
-/*
-==================
-Kamikaze_DeathActivate
-==================
-*/
-void Kamikaze_DeathActivate( gentity_t *ent ) {
- G_StartKamikaze(ent);
- G_FreeEntity(ent);
-}
-
-/*
-==================
-Kamikaze_DeathTimer
-==================
-*/
-void Kamikaze_DeathTimer( gentity_t *self ) {
- gentity_t *ent;
-
- ent = G_Spawn();
- ent->classname = "kamikaze timer";
- VectorCopy(self->s.pos.trBase, ent->s.pos.trBase);
- ent->r.svFlags |= SVF_NOCLIENT;
- ent->think = Kamikaze_DeathActivate;
- ent->nextthink = level.time + 5 * 1000;
-
- ent->activator = self;
-}
-
-#endif
-
-/*
-==================
-CheckAlmostCapture
-==================
-*/
-void CheckAlmostCapture( gentity_t *self, gentity_t *attacker ) {
- gentity_t *ent;
- vec3_t dir;
- char *classname;
-
- // if this player was carrying a flag
- if ( self->client->ps.powerups[PW_REDFLAG] ||
- self->client->ps.powerups[PW_BLUEFLAG] ||
- self->client->ps.powerups[PW_NEUTRALFLAG] ) {
- // get the goal flag this player should have been going for
- if ( g_gametype.integer == GT_CTF ) {
- if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
- classname = "team_CTF_blueflag";
- }
- else {
- classname = "team_CTF_redflag";
- }
- }
- else {
- if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
- classname = "team_CTF_redflag";
- }
- else {
- classname = "team_CTF_blueflag";
- }
- }
- ent = NULL;
- do
- {
- ent = G_Find(ent, FOFS(classname), classname);
- } while (ent && (ent->flags & FL_DROPPED_ITEM));
- // if we found the destination flag and it's not picked up
- if (ent && !(ent->r.svFlags & SVF_NOCLIENT) ) {
- // if the player was *very* close
- VectorSubtract( self->client->ps.origin, ent->s.origin, dir );
- if ( VectorLength(dir) < 200 ) {
- self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
- if ( attacker->client ) {
- attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
- }
- }
- }
- }
-}
-
-/*
-==================
-CheckAlmostScored
-==================
-*/
-void CheckAlmostScored( gentity_t *self, gentity_t *attacker ) {
- gentity_t *ent;
- vec3_t dir;
- char *classname;
-
- // if the player was carrying cubes
- if ( self->client->ps.generic1 ) {
- if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
- classname = "team_redobelisk";
- }
- else {
- classname = "team_blueobelisk";
- }
- ent = G_Find(NULL, FOFS(classname), classname);
- // if we found the destination obelisk
- if ( ent ) {
- // if the player was *very* close
- VectorSubtract( self->client->ps.origin, ent->s.origin, dir );
- if ( VectorLength(dir) < 200 ) {
- self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
- if ( attacker->client ) {
- attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
- }
- }
- }
- }
-}
-
-/*
-==================
-player_die
-==================
-*/
-void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
- gentity_t *ent;
- int anim;
- int contents;
- int killer;
- int i;
- char *killerName, *obit;
-
- if ( self->client->ps.pm_type == PM_DEAD ) {
- return;
- }
-
- if ( level.intermissiontime ) {
- return;
- }
-
- // check for an almost capture
- CheckAlmostCapture( self, attacker );
- // check for a player that almost brought in cubes
- CheckAlmostScored( self, attacker );
-
- if (self->client && self->client->hook) {
- Weapon_HookFree(self->client->hook);
- }
-#ifdef MISSIONPACK
- if ((self->client->ps.eFlags & EF_TICKING) && self->activator) {
- self->client->ps.eFlags &= ~EF_TICKING;
- self->activator->think = G_FreeEntity;
- self->activator->nextthink = level.time;
- }
-#endif
- self->client->ps.pm_type = PM_DEAD;
-
- if ( attacker ) {
- killer = attacker->s.number;
- if ( attacker->client ) {
- killerName = attacker->client->pers.netname;
- } else {
- killerName = "<non-client>";
- }
- } else {
- killer = ENTITYNUM_WORLD;
- killerName = "<world>";
- }
-
- if ( killer < 0 || killer >= MAX_CLIENTS ) {
- killer = ENTITYNUM_WORLD;
- killerName = "<world>";
- }
-
- if ( meansOfDeath < 0 || meansOfDeath >= sizeof( modNames ) / sizeof( modNames[0] ) ) {
- obit = "<bad obituary>";
- } else {
- obit = modNames[meansOfDeath];
- }
-
- G_LogPrintf("Kill: %i %i %i: %s killed %s by %s\n",
- killer, self->s.number, meansOfDeath, killerName,
- self->client->pers.netname, obit );
-
- // broadcast the death event to everyone
- ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
- ent->s.eventParm = meansOfDeath;
- ent->s.otherEntityNum = self->s.number;
- ent->s.otherEntityNum2 = killer;
- ent->r.svFlags = SVF_BROADCAST; // send to everyone
-
- self->enemy = attacker;
-
- self->client->ps.persistant[PERS_KILLED]++;
-
- if (attacker && attacker->client) {
- attacker->client->lastkilled_client = self->s.number;
-
- if ( attacker == self || OnSameTeam (self, attacker ) ) {
- AddScore( attacker, self->r.currentOrigin, -1 );
- } else {
- AddScore( attacker, self->r.currentOrigin, 1 );
-
- if( meansOfDeath == MOD_GAUNTLET ) {
-
- // play humiliation on player
- attacker->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;
-
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_GAUNTLET;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- // also play humiliation on target
- self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_GAUNTLETREWARD;
- }
-
- // check for two kills in a short amount of time
- // if this is close enough to the last kill, give a reward sound
- if ( level.time - attacker->client->lastKillTime < CARNAGE_REWARD_TIME ) {
- // play excellent on player
- attacker->client->ps.persistant[PERS_EXCELLENT_COUNT]++;
-
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_EXCELLENT;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
- }
- attacker->client->lastKillTime = level.time;
-
- }
- } else {
- AddScore( self, self->r.currentOrigin, -1 );
- }
-
- // Add team bonuses
- Team_FragBonuses(self, inflictor, attacker);
-
- // if I committed suicide, the flag does not fall, it returns.
- if (meansOfDeath == MOD_SUICIDE) {
- if ( self->client->ps.powerups[PW_NEUTRALFLAG] ) { // only happens in One Flag CTF
- Team_ReturnFlag( TEAM_FREE );
- self->client->ps.powerups[PW_NEUTRALFLAG] = 0;
- }
- else if ( self->client->ps.powerups[PW_REDFLAG] ) { // only happens in standard CTF
- Team_ReturnFlag( TEAM_RED );
- self->client->ps.powerups[PW_REDFLAG] = 0;
- }
- else if ( self->client->ps.powerups[PW_BLUEFLAG] ) { // only happens in standard CTF
- Team_ReturnFlag( TEAM_BLUE );
- self->client->ps.powerups[PW_BLUEFLAG] = 0;
- }
- }
-
- // if client is in a nodrop area, don't drop anything (but return CTF flags!)
- contents = trap_PointContents( self->r.currentOrigin, -1 );
- if ( !( contents & CONTENTS_NODROP )) {
- TossClientItems( self );
- }
- else {
- if ( self->client->ps.powerups[PW_NEUTRALFLAG] ) { // only happens in One Flag CTF
- Team_ReturnFlag( TEAM_FREE );
- }
- else if ( self->client->ps.powerups[PW_REDFLAG] ) { // only happens in standard CTF
- Team_ReturnFlag( TEAM_RED );
- }
- else if ( self->client->ps.powerups[PW_BLUEFLAG] ) { // only happens in standard CTF
- Team_ReturnFlag( TEAM_BLUE );
- }
- }
-#ifdef MISSIONPACK
- TossClientPersistantPowerups( self );
- if( g_gametype.integer == GT_HARVESTER ) {
- TossClientCubes( self );
- }
-#endif
-
- Cmd_Score_f( self ); // show scores
- // send updated scores to any clients that are following this one,
- // or they would get stale scoreboards
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- gclient_t *client;
-
- client = &level.clients[i];
- if ( client->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
- continue;
- }
- if ( client->sess.spectatorClient == self->s.number ) {
- Cmd_Score_f( g_entities + i );
- }
- }
-
- self->takedamage = qtrue; // can still be gibbed
-
- self->s.weapon = WP_NONE;
- self->s.powerups = 0;
- self->r.contents = CONTENTS_CORPSE;
-
- self->s.angles[0] = 0;
- self->s.angles[2] = 0;
- LookAtKiller (self, inflictor, attacker);
-
- VectorCopy( self->s.angles, self->client->ps.viewangles );
-
- self->s.loopSound = 0;
-
- self->r.maxs[2] = -8;
-
- // don't allow respawn until the death anim is done
- // g_forcerespawn may force spawning at some later time
- self->client->respawnTime = level.time + 1700;
-
- // remove powerups
- memset( self->client->ps.powerups, 0, sizeof(self->client->ps.powerups) );
-
- // never gib in a nodrop
- if ( (self->health <= GIB_HEALTH && !(contents & CONTENTS_NODROP) && g_blood.integer) || meansOfDeath == MOD_SUICIDE) {
- // gib death
- GibEntity( self, killer );
- } else {
- // normal death
- static int i;
-
- switch ( i ) {
- case 0:
- anim = BOTH_DEATH1;
- break;
- case 1:
- anim = BOTH_DEATH2;
- break;
- case 2:
- default:
- anim = BOTH_DEATH3;
- break;
- }
-
- // for the no-blood option, we need to prevent the health
- // from going to gib level
- if ( self->health <= GIB_HEALTH ) {
- self->health = GIB_HEALTH+1;
- }
-
- self->client->ps.legsAnim =
- ( ( self->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
- self->client->ps.torsoAnim =
- ( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-
- G_AddEvent( self, EV_DEATH1 + i, killer );
-
- // the body can still be gibbed
- self->die = body_die;
-
- // globally cycle through the different death animations
- i = ( i + 1 ) % 3;
-
-#ifdef MISSIONPACK
- if (self->s.eFlags & EF_KAMIKAZE) {
- Kamikaze_DeathTimer( self );
- }
-#endif
- }
-
- trap_LinkEntity (self);
-
-}
-
-
-/*
-================
-CheckArmor
-================
-*/
-int CheckArmor (gentity_t *ent, int damage, int dflags)
-{
- gclient_t *client;
- int save;
- int count;
-
- if (!damage)
- return 0;
-
- client = ent->client;
-
- if (!client)
- return 0;
-
- if (dflags & DAMAGE_NO_ARMOR)
- return 0;
-
- // armor
- count = client->ps.stats[STAT_ARMOR];
- save = ceil( damage * ARMOR_PROTECTION );
- if (save >= count)
- save = count;
-
- if (!save)
- return 0;
-
- client->ps.stats[STAT_ARMOR] -= save;
-
- return save;
-}
-
-/*
-================
-RaySphereIntersections
-================
-*/
-int RaySphereIntersections( vec3_t origin, float radius, vec3_t point, vec3_t dir, vec3_t intersections[2] ) {
- float b, c, d, t;
-
- // | origin - (point + t * dir) | = radius
- // a = dir[0]^2 + dir[1]^2 + dir[2]^2;
- // b = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2]));
- // c = (point[0] - origin[0])^2 + (point[1] - origin[1])^2 + (point[2] - origin[2])^2 - radius^2;
-
- // normalize dir so a = 1
- VectorNormalize(dir);
- b = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2]));
- c = (point[0] - origin[0]) * (point[0] - origin[0]) +
- (point[1] - origin[1]) * (point[1] - origin[1]) +
- (point[2] - origin[2]) * (point[2] - origin[2]) -
- radius * radius;
-
- d = b * b - 4 * c;
- if (d > 0) {
- t = (- b + sqrt(d)) / 2;
- VectorMA(point, t, dir, intersections[0]);
- t = (- b - sqrt(d)) / 2;
- VectorMA(point, t, dir, intersections[1]);
- return 2;
- }
- else if (d == 0) {
- t = (- b ) / 2;
- VectorMA(point, t, dir, intersections[0]);
- return 1;
- }
- return 0;
-}
-
-#ifdef MISSIONPACK
-/*
-================
-G_InvulnerabilityEffect
-================
-*/
-int G_InvulnerabilityEffect( gentity_t *targ, vec3_t dir, vec3_t point, vec3_t impactpoint, vec3_t bouncedir ) {
- gentity_t *impact;
- vec3_t intersections[2], vec;
- int n;
-
- if ( !targ->client ) {
- return qfalse;
- }
- VectorCopy(dir, vec);
- VectorInverse(vec);
- // sphere model radius = 42 units
- n = RaySphereIntersections( targ->client->ps.origin, 42, point, vec, intersections);
- if (n > 0) {
- impact = G_TempEntity( targ->client->ps.origin, EV_INVUL_IMPACT );
- VectorSubtract(intersections[0], targ->client->ps.origin, vec);
- vectoangles(vec, impact->s.angles);
- impact->s.angles[0] += 90;
- if (impact->s.angles[0] > 360)
- impact->s.angles[0] -= 360;
- if ( impactpoint ) {
- VectorCopy( intersections[0], impactpoint );
- }
- if ( bouncedir ) {
- VectorCopy( vec, bouncedir );
- VectorNormalize( bouncedir );
- }
- return qtrue;
- }
- else {
- return qfalse;
- }
-}
-#endif
-/*
-============
-T_Damage
-
-targ entity that is being damaged
-inflictor entity that is causing the damage
-attacker entity that caused the inflictor to damage targ
- example: targ=monster, inflictor=rocket, attacker=player
-
-dir direction of the attack for knockback
-point point at which the damage is being inflicted, used for headshots
-damage amount of damage being inflicted
-knockback force to be applied against targ as a result of the damage
-
-inflictor, attacker, dir, and point can be NULL for environmental effects
-
-dflags these flags are used to control how T_Damage works
- DAMAGE_RADIUS damage was indirect (from a nearby explosion)
- DAMAGE_NO_ARMOR armor does not protect from this damage
- DAMAGE_NO_KNOCKBACK do not affect velocity, just view angles
- DAMAGE_NO_PROTECTION kills godmode, armor, everything
-============
-*/
-
-void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
- vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {
- gclient_t *client;
- int take;
- int save;
- int asave;
- int knockback;
- int max;
-#ifdef MISSIONPACK
- vec3_t bouncedir, impactpoint;
-#endif
-
- if (!targ->takedamage) {
- return;
- }
-
- // the intermission has allready been qualified for, so don't
- // allow any extra scoring
- if ( level.intermissionQueued ) {
- return;
- }
-#ifdef MISSIONPACK
- if ( targ->client && mod != MOD_JUICED) {
- if ( targ->client->invulnerabilityTime > level.time) {
- if ( dir && point ) {
- G_InvulnerabilityEffect( targ, dir, point, impactpoint, bouncedir );
- }
- return;
- }
- }
-#endif
- if ( !inflictor ) {
- inflictor = &g_entities[ENTITYNUM_WORLD];
- }
- if ( !attacker ) {
- attacker = &g_entities[ENTITYNUM_WORLD];
- }
-
- // shootable doors / buttons don't actually have any health
- if ( targ->s.eType == ET_MOVER ) {
- if ( targ->use && targ->moverState == MOVER_POS1 ) {
- targ->use( targ, inflictor, attacker );
- }
- return;
- }
-#ifdef MISSIONPACK
- if( g_gametype.integer == GT_OBELISK && CheckObeliskAttack( targ, attacker ) ) {
- return;
- }
-#endif
- // reduce damage by the attacker's handicap value
- // unless they are rocket jumping
- if ( attacker->client && attacker != targ ) {
- max = attacker->client->ps.stats[STAT_MAX_HEALTH];
-#ifdef MISSIONPACK
- if( bg_itemlist[attacker->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
- max /= 2;
- }
-#endif
- damage = damage * max / 100;
- }
-
- client = targ->client;
-
- if ( client ) {
- if ( client->noclip ) {
- return;
- }
- }
-
- if ( !dir ) {
- dflags |= DAMAGE_NO_KNOCKBACK;
- } else {
- VectorNormalize(dir);
- }
-
- knockback = damage;
- if ( knockback > 200 ) {
- knockback = 200;
- }
- if ( targ->flags & FL_NO_KNOCKBACK ) {
- knockback = 0;
- }
- if ( dflags & DAMAGE_NO_KNOCKBACK ) {
- knockback = 0;
- }
-
- // figure momentum add, even if the damage won't be taken
- if ( knockback && targ->client ) {
- vec3_t kvel;
- float mass;
-
- mass = 200;
-
- VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
- VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);
-
- // set the timer so that the other client can't cancel
- // out the movement immediately
- if ( !targ->client->ps.pm_time ) {
- int t;
-
- t = knockback * 2;
- if ( t < 50 ) {
- t = 50;
- }
- if ( t > 200 ) {
- t = 200;
- }
- targ->client->ps.pm_time = t;
- targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
- }
- }
-
- // check for completely getting out of the damage
- if ( !(dflags & DAMAGE_NO_PROTECTION) ) {
-
- // if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
- // if the attacker was on the same team
-#ifdef MISSIONPACK
- if ( mod != MOD_JUICED && targ != attacker && !(dflags & DAMAGE_NO_TEAM_PROTECTION) && OnSameTeam (targ, attacker) ) {
-#else
- if ( targ != attacker && OnSameTeam (targ, attacker) ) {
-#endif
- if ( !g_friendlyFire.integer ) {
- return;
- }
- }
-#ifdef MISSIONPACK
- if (mod == MOD_PROXIMITY_MINE) {
- if (inflictor && inflictor->parent && OnSameTeam(targ, inflictor->parent)) {
- return;
- }
- if (targ == attacker) {
- return;
- }
- }
-#endif
-
- // check for godmode
- if ( targ->flags & FL_GODMODE ) {
- return;
- }
- }
-
- // battlesuit protects from all radius damage (but takes knockback)
- // and protects 50% against all damage
- if ( client && client->ps.powerups[PW_BATTLESUIT] ) {
- G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );
- if ( ( dflags & DAMAGE_RADIUS ) || ( mod == MOD_FALLING ) ) {
- return;
- }
- damage *= 0.5;
- }
-
- // add to the attacker's hit counter (if the target isn't a general entity like a prox mine)
- if ( attacker->client && client
- && targ != attacker && targ->health > 0
- && targ->s.eType != ET_MISSILE
- && targ->s.eType != ET_GENERAL) {
- if ( OnSameTeam( targ, attacker ) ) {
- attacker->client->ps.persistant[PERS_HITS]--;
- } else {
- attacker->client->ps.persistant[PERS_HITS]++;
- }
- attacker->client->ps.persistant[PERS_ATTACKEE_ARMOR] = (targ->health<<8)|(client->ps.stats[STAT_ARMOR]);
- }
-
- // always give half damage if hurting self
- // calculated after knockback, so rocket jumping works
- if ( targ == attacker) {
- damage *= 0.5;
- }
-
- if ( damage < 1 ) {
- damage = 1;
- }
- take = damage;
- save = 0;
-
- // save some from armor
- asave = CheckArmor (targ, take, dflags);
- take -= asave;
-
- if ( g_debugDamage.integer ) {
- G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number,
- targ->health, take, asave );
- }
-
- // add to the damage inflicted on a player this frame
- // the total will be turned into screen blends and view angle kicks
- // at the end of the frame
- if ( client ) {
- if ( attacker ) {
- client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
- } else {
- client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
- }
- client->damage_armor += asave;
- client->damage_blood += take;
- client->damage_knockback += knockback;
- if ( dir ) {
- VectorCopy ( dir, client->damage_from );
- client->damage_fromWorld = qfalse;
- } else {
- VectorCopy ( targ->r.currentOrigin, client->damage_from );
- client->damage_fromWorld = qtrue;
- }
- }
-
- // See if it's the player hurting the emeny flag carrier
-#ifdef MISSIONPACK
- if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF ) {
-#else
- if( g_gametype.integer == GT_CTF) {
-#endif
- Team_CheckHurtCarrier(targ, attacker);
- }
-
- if (targ->client) {
- // set the last client who damaged the target
- targ->client->lasthurt_client = attacker->s.number;
- targ->client->lasthurt_mod = mod;
- }
-
- // do the damage
- if (take) {
- targ->health = targ->health - take;
- if ( targ->client ) {
- targ->client->ps.stats[STAT_HEALTH] = targ->health;
- }
-
- if ( targ->health <= 0 ) {
- if ( client )
- targ->flags |= FL_NO_KNOCKBACK;
-
- if (targ->health < -999)
- targ->health = -999;
-
- targ->enemy = attacker;
- targ->die (targ, inflictor, attacker, take, mod);
- return;
- } else if ( targ->pain ) {
- targ->pain (targ, attacker, take);
- }
- }
-
-}
-
-
-/*
-============
-CanDamage
-
-Returns qtrue if the inflictor can directly damage the target. Used for
-explosions and melee attacks.
-============
-*/
-qboolean CanDamage (gentity_t *targ, vec3_t origin) {
- vec3_t dest;
- trace_t tr;
- vec3_t midpoint;
-
- // use the midpoint of the bounds instead of the origin, because
- // bmodels may have their origin is 0,0,0
- VectorAdd (targ->r.absmin, targ->r.absmax, midpoint);
- VectorScale (midpoint, 0.5, midpoint);
-
- VectorCopy (midpoint, dest);
- trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
- if (tr.fraction == 1.0 || tr.entityNum == targ->s.number)
- return qtrue;
-
- // this should probably check in the plane of projection,
- // rather than in world coordinate, and also include Z
- VectorCopy (midpoint, dest);
- dest[0] += 15.0;
- dest[1] += 15.0;
- trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
- if (tr.fraction == 1.0)
- return qtrue;
-
- VectorCopy (midpoint, dest);
- dest[0] += 15.0;
- dest[1] -= 15.0;
- trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
- if (tr.fraction == 1.0)
- return qtrue;
-
- VectorCopy (midpoint, dest);
- dest[0] -= 15.0;
- dest[1] += 15.0;
- trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
- if (tr.fraction == 1.0)
- return qtrue;
-
- VectorCopy (midpoint, dest);
- dest[0] -= 15.0;
- dest[1] -= 15.0;
- trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
- if (tr.fraction == 1.0)
- return qtrue;
-
-
- return qfalse;
-}
-
-
-/*
-============
-G_RadiusDamage
-============
-*/
-qboolean G_RadiusDamage ( vec3_t origin, gentity_t *attacker, float damage, float radius,
- gentity_t *ignore, int mod) {
- float points, dist;
- gentity_t *ent;
- int entityList[MAX_GENTITIES];
- int numListedEntities;
- vec3_t mins, maxs;
- vec3_t v;
- vec3_t dir;
- int i, e;
- qboolean hitClient = qfalse;
-
- if ( radius < 1 ) {
- radius = 1;
- }
-
- for ( i = 0 ; i < 3 ; i++ ) {
- mins[i] = origin[i] - radius;
- maxs[i] = origin[i] + radius;
- }
-
- numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
-
- for ( e = 0 ; e < numListedEntities ; e++ ) {
- ent = &g_entities[entityList[ e ]];
-
- if (ent == ignore)
- continue;
- if (!ent->takedamage)
- continue;
-
- // find the distance from the edge of the bounding box
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( origin[i] < ent->r.absmin[i] ) {
- v[i] = ent->r.absmin[i] - origin[i];
- } else if ( origin[i] > ent->r.absmax[i] ) {
- v[i] = origin[i] - ent->r.absmax[i];
- } else {
- v[i] = 0;
- }
- }
-
- dist = VectorLength( v );
- if ( dist >= radius ) {
- continue;
- }
-
- points = damage * ( 1.0 - dist / radius );
-
- if( CanDamage (ent, origin) ) {
- if( LogAccuracyHit( ent, attacker ) ) {
- hitClient = qtrue;
- }
- VectorSubtract (ent->r.currentOrigin, origin, dir);
- // push the center of mass higher than the origin so players
- // get knocked into the air more
- dir[2] += 24;
- G_Damage (ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod);
- }
- }
-
- return hitClient;
-}
diff --git a/engine/code/game/g_items.c b/engine/code/game/g_items.c
deleted file mode 100644
index 73b2552..0000000
--- a/engine/code/game/g_items.c
+++ /dev/null
@@ -1,1010 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-/*
-
- Items are any object that a player can touch to gain some effect.
-
- Pickup will return the number of seconds until they should respawn.
-
- all items should pop when dropped in lava or slime
-
- Respawnable items don't actually go away when picked up, they are
- just made invisible and untouchable. This allows them to ride
- movers and respawn apropriately.
-*/
-
-
-#define RESPAWN_ARMOR 25
-#define RESPAWN_HEALTH 35
-#define RESPAWN_AMMO 40
-#define RESPAWN_HOLDABLE 60
-#define RESPAWN_MEGAHEALTH 35//120
-#define RESPAWN_POWERUP 120
-
-
-//======================================================================
-
-int Pickup_Powerup( gentity_t *ent, gentity_t *other ) {
- int quantity;
- int i;
- gclient_t *client;
-
- if ( !other->client->ps.powerups[ent->item->giTag] ) {
- // round timing to seconds to make multiple powerup timers
- // count in sync
- other->client->ps.powerups[ent->item->giTag] =
- level.time - ( level.time % 1000 );
- }
-
- if ( ent->count ) {
- quantity = ent->count;
- } else {
- quantity = ent->item->quantity;
- }
-
- other->client->ps.powerups[ent->item->giTag] += quantity * 1000;
-
- // give any nearby players a "denied" anti-reward
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- vec3_t delta;
- float len;
- vec3_t forward;
- trace_t tr;
-
- client = &level.clients[i];
- if ( client == other->client ) {
- continue;
- }
- if ( client->pers.connected == CON_DISCONNECTED ) {
- continue;
- }
- if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
- continue;
- }
-
- // if same team in team game, no sound
- // cannot use OnSameTeam as it expects to g_entities, not clients
- if ( g_gametype.integer >= GT_TEAM && other->client->sess.sessionTeam == client->sess.sessionTeam ) {
- continue;
- }
-
- // if too far away, no sound
- VectorSubtract( ent->s.pos.trBase, client->ps.origin, delta );
- len = VectorNormalize( delta );
- if ( len > 192 ) {
- continue;
- }
-
- // if not facing, no sound
- AngleVectors( client->ps.viewangles, forward, NULL, NULL );
- if ( DotProduct( delta, forward ) < 0.4 ) {
- continue;
- }
-
- // if not line of sight, no sound
- trap_Trace( &tr, client->ps.origin, NULL, NULL, ent->s.pos.trBase, ENTITYNUM_NONE, CONTENTS_SOLID );
- if ( tr.fraction != 1.0 ) {
- continue;
- }
-
- // anti-reward
- client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_DENIEDREWARD;
- }
- return RESPAWN_POWERUP;
-}
-
-//======================================================================
-
-#ifdef MISSIONPACK
-int Pickup_PersistantPowerup( gentity_t *ent, gentity_t *other ) {
- int clientNum;
- char userinfo[MAX_INFO_STRING];
- float handicap;
- int max;
-
- other->client->ps.stats[STAT_PERSISTANT_POWERUP] = ent->item - bg_itemlist;
- other->client->persistantPowerup = ent;
-
- switch( ent->item->giTag ) {
- case PW_GUARD:
- clientNum = other->client->ps.clientNum;
- trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
- handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
- if( handicap<=0.0f || handicap>100.0f) {
- handicap = 100.0f;
- }
- max = (int)(2 * handicap);
-
- other->health = max;
- other->client->ps.stats[STAT_HEALTH] = max;
- other->client->ps.stats[STAT_MAX_HEALTH] = max;
- other->client->ps.stats[STAT_ARMOR] = max;
- other->client->pers.maxHealth = max;
-
- break;
-
- case PW_SCOUT:
- clientNum = other->client->ps.clientNum;
- trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
- handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
- if( handicap<=0.0f || handicap>100.0f) {
- handicap = 100.0f;
- }
- other->client->pers.maxHealth = handicap;
- other->client->ps.stats[STAT_ARMOR] = 0;
- break;
-
- case PW_DOUBLER:
- clientNum = other->client->ps.clientNum;
- trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
- handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
- if( handicap<=0.0f || handicap>100.0f) {
- handicap = 100.0f;
- }
- other->client->pers.maxHealth = handicap;
- break;
- case PW_AMMOREGEN:
- clientNum = other->client->ps.clientNum;
- trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
- handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
- if( handicap<=0.0f || handicap>100.0f) {
- handicap = 100.0f;
- }
- other->client->pers.maxHealth = handicap;
- memset(other->client->ammoTimes, 0, sizeof(other->client->ammoTimes));
- break;
- default:
- clientNum = other->client->ps.clientNum;
- trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
- handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
- if( handicap<=0.0f || handicap>100.0f) {
- handicap = 100.0f;
- }
- other->client->pers.maxHealth = handicap;
- break;
- }
-
- return -1;
-}
-
-//======================================================================
-#endif
-
-int Pickup_Holdable( gentity_t *ent, gentity_t *other ) {
-
- other->client->ps.stats[STAT_HOLDABLE_ITEM] = ent->item - bg_itemlist;
-
- if( ent->item->giTag == HI_KAMIKAZE ) {
- other->client->ps.eFlags |= EF_KAMIKAZE;
- }
-
- return RESPAWN_HOLDABLE;
-}
-
-
-//======================================================================
-
-void Add_Ammo (gentity_t *ent, int weapon, int count)
-{
- ent->client->ps.ammo[weapon] += count;
- if ( ent->client->ps.ammo[weapon] > 200 ) {
- ent->client->ps.ammo[weapon] = 200;
- }
-}
-
-int Pickup_Ammo (gentity_t *ent, gentity_t *other)
-{
- int quantity;
-
- if ( ent->count ) {
- quantity = ent->count;
- } else {
- quantity = ent->item->quantity;
- }
-
- Add_Ammo (other, ent->item->giTag, quantity);
-
- return RESPAWN_AMMO;
-}
-
-//======================================================================
-
-
-int Pickup_Weapon (gentity_t *ent, gentity_t *other) {
- int quantity;
-
- if ( ent->count < 0 ) {
- quantity = 0; // None for you, sir!
- } else {
- if ( ent->count ) {
- quantity = ent->count;
- } else {
- quantity = ent->item->quantity;
- }
-
- // dropped items and teamplay weapons always have full ammo
- if ( ! (ent->flags & FL_DROPPED_ITEM) && g_gametype.integer != GT_TEAM ) {
- // respawning rules
- // drop the quantity if the already have over the minimum
- if ( other->client->ps.ammo[ ent->item->giTag ] < quantity ) {
- quantity = quantity - other->client->ps.ammo[ ent->item->giTag ];
- } else {
- quantity = 1; // only add a single shot
- }
- }
- }
-
- // add the weapon
- other->client->ps.stats[STAT_WEAPONS] |= ( 1 << ent->item->giTag );
-
- Add_Ammo( other, ent->item->giTag, quantity );
-
- if (ent->item->giTag == WP_GRAPPLING_HOOK)
- other->client->ps.ammo[ent->item->giTag] = -1; // unlimited ammo
-
- // team deathmatch has slow weapon respawns
- if ( g_gametype.integer == GT_TEAM ) {
- return g_weaponTeamRespawn.integer;
- }
-
- return g_weaponRespawn.integer;
-}
-
-
-//======================================================================
-
-int Pickup_Health (gentity_t *ent, gentity_t *other) {
- int max;
- int quantity;
-
- // small and mega healths will go over the max
-#ifdef MISSIONPACK
- if( other->client && bg_itemlist[other->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
- max = other->client->ps.stats[STAT_MAX_HEALTH];
- }
- else
-#endif
- if ( ent->item->quantity != 5 && ent->item->quantity != 100 ) {
- max = other->client->ps.stats[STAT_MAX_HEALTH];
- } else {
- max = other->client->ps.stats[STAT_MAX_HEALTH] * 2;
- }
-
- if ( ent->count ) {
- quantity = ent->count;
- } else {
- quantity = ent->item->quantity;
- }
-
- other->health += quantity;
-
- if (other->health > max ) {
- other->health = max;
- }
- other->client->ps.stats[STAT_HEALTH] = other->health;
-
- if ( ent->item->quantity == 100 ) { // mega health respawns slow
- return RESPAWN_MEGAHEALTH;
- }
-
- return RESPAWN_HEALTH;
-}
-
-//======================================================================
-
-int Pickup_Armor( gentity_t *ent, gentity_t *other ) {
-#ifdef MISSIONPACK
- int upperBound;
-
- other->client->ps.stats[STAT_ARMOR] += ent->item->quantity;
-
- if( other->client && bg_itemlist[other->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
- upperBound = other->client->ps.stats[STAT_MAX_HEALTH];
- }
- else {
- upperBound = other->client->ps.stats[STAT_MAX_HEALTH] * 2;
- }
-
- if ( other->client->ps.stats[STAT_ARMOR] > upperBound ) {
- other->client->ps.stats[STAT_ARMOR] = upperBound;
- }
-#else
- other->client->ps.stats[STAT_ARMOR] += ent->item->quantity;
- if ( other->client->ps.stats[STAT_ARMOR] > other->client->ps.stats[STAT_MAX_HEALTH] * 2 ) {
- other->client->ps.stats[STAT_ARMOR] = other->client->ps.stats[STAT_MAX_HEALTH] * 2;
- }
-#endif
-
- return RESPAWN_ARMOR;
-}
-
-//======================================================================
-
-/*
-===============
-RespawnItem
-===============
-*/
-void RespawnItem( gentity_t *ent ) {
- // randomly select from teamed entities
- if (ent->team) {
- gentity_t *master;
- int count;
- int choice;
-
- if ( !ent->teammaster ) {
- G_Error( "RespawnItem: bad teammaster");
- }
- master = ent->teammaster;
-
- for (count = 0, ent = master; ent; ent = ent->teamchain, count++)
- ;
-
- choice = rand() % count;
-
- for (count = 0, ent = master; count < choice; ent = ent->teamchain, count++)
- ;
- }
-
- ent->r.contents = CONTENTS_TRIGGER;
- ent->s.eFlags &= ~EF_NODRAW;
- ent->r.svFlags &= ~SVF_NOCLIENT;
- trap_LinkEntity (ent);
-
- if ( ent->item->giType == IT_POWERUP ) {
- // play powerup spawn sound to all clients
- gentity_t *te;
-
- // if the powerup respawn sound should Not be global
- if (ent->speed) {
- te = G_TempEntity( ent->s.pos.trBase, EV_GENERAL_SOUND );
- }
- else {
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_SOUND );
- }
- te->s.eventParm = G_SoundIndex( "sound/items/poweruprespawn.wav" );
- te->r.svFlags |= SVF_BROADCAST;
- }
-
- if ( ent->item->giType == IT_HOLDABLE && ent->item->giTag == HI_KAMIKAZE ) {
- // play powerup spawn sound to all clients
- gentity_t *te;
-
- // if the powerup respawn sound should Not be global
- if (ent->speed) {
- te = G_TempEntity( ent->s.pos.trBase, EV_GENERAL_SOUND );
- }
- else {
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_SOUND );
- }
- te->s.eventParm = G_SoundIndex( "sound/items/kamikazerespawn.wav" );
- te->r.svFlags |= SVF_BROADCAST;
- }
-
- // play the normal respawn sound only to nearby clients
- G_AddEvent( ent, EV_ITEM_RESPAWN, 0 );
-
- ent->nextthink = 0;
-}
-
-
-/*
-===============
-Touch_Item
-===============
-*/
-void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) {
- int respawn;
- qboolean predict;
-
- if (!other->client)
- return;
- if (other->health < 1)
- return; // dead people can't pickup
-
- // the same pickup rules are used for client side and server side
- if ( !BG_CanItemBeGrabbed( g_gametype.integer, &ent->s, &other->client->ps ) ) {
- return;
- }
-
- G_LogPrintf( "Item: %i %s\n", other->s.number, ent->item->classname );
-
- predict = other->client->pers.predictItemPickup;
-
- // call the item-specific pickup function
- switch( ent->item->giType ) {
- case IT_WEAPON:
- respawn = Pickup_Weapon(ent, other);
-// predict = qfalse;
- break;
- case IT_AMMO:
- respawn = Pickup_Ammo(ent, other);
-// predict = qfalse;
- break;
- case IT_ARMOR:
- respawn = Pickup_Armor(ent, other);
- break;
- case IT_HEALTH:
- respawn = Pickup_Health(ent, other);
- break;
- case IT_POWERUP:
- respawn = Pickup_Powerup(ent, other);
- predict = qfalse;
- break;
-#ifdef MISSIONPACK
- case IT_PERSISTANT_POWERUP:
- respawn = Pickup_PersistantPowerup(ent, other);
- break;
-#endif
- case IT_TEAM:
- respawn = Pickup_Team(ent, other);
- break;
- case IT_HOLDABLE:
- respawn = Pickup_Holdable(ent, other);
- break;
- default:
- return;
- }
-
- if ( !respawn ) {
- return;
- }
-
- // play the normal pickup sound
- if (predict) {
- G_AddPredictableEvent( other, EV_ITEM_PICKUP, ent->s.modelindex );
- } else {
- G_AddEvent( other, EV_ITEM_PICKUP, ent->s.modelindex );
- }
-
- // powerup pickups are global broadcasts
- if ( ent->item->giType == IT_POWERUP || ent->item->giType == IT_TEAM) {
- // if we want the global sound to play
- if (!ent->speed) {
- gentity_t *te;
-
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP );
- te->s.eventParm = ent->s.modelindex;
- te->r.svFlags |= SVF_BROADCAST;
- } else {
- gentity_t *te;
-
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP );
- te->s.eventParm = ent->s.modelindex;
- // only send this temp entity to a single client
- te->r.svFlags |= SVF_SINGLECLIENT;
- te->r.singleClient = other->s.number;
- }
- }
-
- // fire item targets
- G_UseTargets (ent, other);
-
- // wait of -1 will not respawn
- if ( ent->wait == -1 ) {
- ent->r.svFlags |= SVF_NOCLIENT;
- ent->s.eFlags |= EF_NODRAW;
- ent->r.contents = 0;
- ent->unlinkAfterEvent = qtrue;
- return;
- }
-
- // non zero wait overrides respawn time
- if ( ent->wait ) {
- respawn = ent->wait;
- }
-
- // random can be used to vary the respawn time
- if ( ent->random ) {
- respawn += crandom() * ent->random;
- if ( respawn < 1 ) {
- respawn = 1;
- }
- }
-
- // dropped items will not respawn
- if ( ent->flags & FL_DROPPED_ITEM ) {
- ent->freeAfterEvent = qtrue;
- }
-
- // picked up items still stay around, they just don't
- // draw anything. This allows respawnable items
- // to be placed on movers.
- ent->r.svFlags |= SVF_NOCLIENT;
- ent->s.eFlags |= EF_NODRAW;
- ent->r.contents = 0;
-
- // ZOID
- // A negative respawn times means to never respawn this item (but don't
- // delete it). This is used by items that are respawned by third party
- // events such as ctf flags
- if ( respawn <= 0 ) {
- ent->nextthink = 0;
- ent->think = 0;
- } else {
- ent->nextthink = level.time + respawn * 1000;
- ent->think = RespawnItem;
- }
- trap_LinkEntity( ent );
-}
-
-
-//======================================================================
-
-/*
-================
-LaunchItem
-
-Spawns an item and tosses it forward
-================
-*/
-gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity ) {
- gentity_t *dropped;
-
- dropped = G_Spawn();
-
- dropped->s.eType = ET_ITEM;
- dropped->s.modelindex = item - bg_itemlist; // store item number in modelindex
- dropped->s.modelindex2 = 1; // This is non-zero is it's a dropped item
-
- dropped->classname = item->classname;
- dropped->item = item;
- VectorSet (dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS);
- VectorSet (dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
- dropped->r.contents = CONTENTS_TRIGGER;
-
- dropped->touch = Touch_Item;
-
- G_SetOrigin( dropped, origin );
- dropped->s.pos.trType = TR_GRAVITY;
- dropped->s.pos.trTime = level.time;
- VectorCopy( velocity, dropped->s.pos.trDelta );
-
- dropped->s.eFlags |= EF_BOUNCE_HALF;
-#ifdef MISSIONPACK
- if ((g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF) && item->giType == IT_TEAM) { // Special case for CTF flags
-#else
- if (g_gametype.integer == GT_CTF && item->giType == IT_TEAM) { // Special case for CTF flags
-#endif
- dropped->think = Team_DroppedFlagThink;
- dropped->nextthink = level.time + 30000;
- Team_CheckDroppedItem( dropped );
- } else { // auto-remove after 30 seconds
- dropped->think = G_FreeEntity;
- dropped->nextthink = level.time + 30000;
- }
-
- dropped->flags = FL_DROPPED_ITEM;
-
- trap_LinkEntity (dropped);
-
- return dropped;
-}
-
-/*
-================
-Drop_Item
-
-Spawns an item and tosses it forward
-================
-*/
-gentity_t *Drop_Item( gentity_t *ent, gitem_t *item, float angle ) {
- vec3_t velocity;
- vec3_t angles;
-
- VectorCopy( ent->s.apos.trBase, angles );
- angles[YAW] += angle;
- angles[PITCH] = 0; // always forward
-
- AngleVectors( angles, velocity, NULL, NULL );
- VectorScale( velocity, 150, velocity );
- velocity[2] += 200 + crandom() * 50;
-
- return LaunchItem( item, ent->s.pos.trBase, velocity );
-}
-
-
-/*
-================
-Use_Item
-
-Respawn the item
-================
-*/
-void Use_Item( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
- RespawnItem( ent );
-}
-
-//======================================================================
-
-/*
-================
-FinishSpawningItem
-
-Traces down to find where an item should rest, instead of letting them
-free fall from their spawn points
-================
-*/
-void FinishSpawningItem( gentity_t *ent ) {
- trace_t tr;
- vec3_t dest;
-
- VectorSet( ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS );
- VectorSet( ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS );
-
- ent->s.eType = ET_ITEM;
- ent->s.modelindex = ent->item - bg_itemlist; // store item number in modelindex
- ent->s.modelindex2 = 0; // zero indicates this isn't a dropped item
-
- ent->r.contents = CONTENTS_TRIGGER;
- ent->touch = Touch_Item;
- // useing an item causes it to respawn
- ent->use = Use_Item;
-
- if ( ent->spawnflags & 1 ) {
- // suspended
- G_SetOrigin( ent, ent->s.origin );
- } else {
- // drop to floor
- VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
- trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
- if ( tr.startsolid ) {
- G_Printf ("FinishSpawningItem: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
- G_FreeEntity( ent );
- return;
- }
-
- // allow to ride movers
- ent->s.groundEntityNum = tr.entityNum;
-
- G_SetOrigin( ent, tr.endpos );
- }
-
- // team slaves and targeted items aren't present at start
- if ( ( ent->flags & FL_TEAMSLAVE ) || ent->targetname ) {
- ent->s.eFlags |= EF_NODRAW;
- ent->r.contents = 0;
- return;
- }
-
- // powerups don't spawn in for a while
- if ( ent->item->giType == IT_POWERUP ) {
- float respawn;
-
- respawn = 45 + crandom() * 15;
- ent->s.eFlags |= EF_NODRAW;
- ent->r.contents = 0;
- ent->nextthink = level.time + respawn * 1000;
- ent->think = RespawnItem;
- return;
- }
-
-
- trap_LinkEntity (ent);
-}
-
-
-qboolean itemRegistered[MAX_ITEMS];
-
-/*
-==================
-G_CheckTeamItems
-==================
-*/
-void G_CheckTeamItems( void ) {
-
- // Set up team stuff
- Team_InitGame();
-
- if( g_gametype.integer == GT_CTF ) {
- gitem_t *item;
-
- // check for the two flags
- item = BG_FindItem( "Red Flag" );
- if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_redflag in map" );
- }
- item = BG_FindItem( "Blue Flag" );
- if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_blueflag in map" );
- }
- }
-#ifdef MISSIONPACK
- if( g_gametype.integer == GT_1FCTF ) {
- gitem_t *item;
-
- // check for all three flags
- item = BG_FindItem( "Red Flag" );
- if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_redflag in map" );
- }
- item = BG_FindItem( "Blue Flag" );
- if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_blueflag in map" );
- }
- item = BG_FindItem( "Neutral Flag" );
- if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_neutralflag in map" );
- }
- }
-
- if( g_gametype.integer == GT_OBELISK ) {
- gentity_t *ent;
-
- // check for the two obelisks
- ent = NULL;
- ent = G_Find( ent, FOFS(classname), "team_redobelisk" );
- if( !ent ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_redobelisk in map" );
- }
-
- ent = NULL;
- ent = G_Find( ent, FOFS(classname), "team_blueobelisk" );
- if( !ent ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_blueobelisk in map" );
- }
- }
-
- if( g_gametype.integer == GT_HARVESTER ) {
- gentity_t *ent;
-
- // check for all three obelisks
- ent = NULL;
- ent = G_Find( ent, FOFS(classname), "team_redobelisk" );
- if( !ent ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_redobelisk in map" );
- }
-
- ent = NULL;
- ent = G_Find( ent, FOFS(classname), "team_blueobelisk" );
- if( !ent ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_blueobelisk in map" );
- }
-
- ent = NULL;
- ent = G_Find( ent, FOFS(classname), "team_neutralobelisk" );
- if( !ent ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_neutralobelisk in map" );
- }
- }
-#endif
-}
-
-/*
-==============
-ClearRegisteredItems
-==============
-*/
-void ClearRegisteredItems( void ) {
- memset( itemRegistered, 0, sizeof( itemRegistered ) );
-
- // players always start with the base weapon
- RegisterItem( BG_FindItemForWeapon( WP_MACHINEGUN ) );
- RegisterItem( BG_FindItemForWeapon( WP_GAUNTLET ) );
-#ifdef MISSIONPACK
- if( g_gametype.integer == GT_HARVESTER ) {
- RegisterItem( BG_FindItem( "Red Cube" ) );
- RegisterItem( BG_FindItem( "Blue Cube" ) );
- }
-#endif
-}
-
-/*
-===============
-RegisterItem
-
-The item will be added to the precache list
-===============
-*/
-void RegisterItem( gitem_t *item ) {
- if ( !item ) {
- G_Error( "RegisterItem: NULL" );
- }
- itemRegistered[ item - bg_itemlist ] = qtrue;
-}
-
-
-/*
-===============
-SaveRegisteredItems
-
-Write the needed items to a config string
-so the client will know which ones to precache
-===============
-*/
-void SaveRegisteredItems( void ) {
- char string[MAX_ITEMS+1];
- int i;
- int count;
-
- count = 0;
- for ( i = 0 ; i < bg_numItems ; i++ ) {
- if ( itemRegistered[i] ) {
- count++;
- string[i] = '1';
- } else {
- string[i] = '0';
- }
- }
- string[ bg_numItems ] = 0;
-
- G_Printf( "%i items registered\n", count );
- trap_SetConfigstring(CS_ITEMS, string);
-}
-
-/*
-============
-G_ItemDisabled
-============
-*/
-int G_ItemDisabled( gitem_t *item ) {
-
- char name[128];
-
- Com_sprintf(name, sizeof(name), "disable_%s", item->classname);
- return trap_Cvar_VariableIntegerValue( name );
-}
-
-/*
-============
-G_SpawnItem
-
-Sets the clipping size and plants the object on the floor.
-
-Items can't be immediately dropped to floor, because they might
-be on an entity that hasn't spawned yet.
-============
-*/
-void G_SpawnItem (gentity_t *ent, gitem_t *item) {
- G_SpawnFloat( "random", "0", &ent->random );
- G_SpawnFloat( "wait", "0", &ent->wait );
-
- RegisterItem( item );
- if ( G_ItemDisabled(item) )
- return;
-
- ent->item = item;
- // some movers spawn on the second frame, so delay item
- // spawns until the third frame so they can ride trains
- ent->nextthink = level.time + FRAMETIME * 2;
- ent->think = FinishSpawningItem;
-
- ent->physicsBounce = 0.50; // items are bouncy
-
- if ( item->giType == IT_POWERUP ) {
- G_SoundIndex( "sound/items/poweruprespawn.wav" );
- G_SpawnFloat( "noglobalsound", "0", &ent->speed);
- }
-
-#ifdef MISSIONPACK
- if ( item->giType == IT_PERSISTANT_POWERUP ) {
- ent->s.generic1 = ent->spawnflags;
- }
-#endif
-}
-
-
-/*
-================
-G_BounceItem
-
-================
-*/
-void G_BounceItem( gentity_t *ent, trace_t *trace ) {
- vec3_t velocity;
- float dot;
- int hitTime;
-
- // reflect the velocity on the trace plane
- hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
- BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
- dot = DotProduct( velocity, trace->plane.normal );
- VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );
-
- // cut the velocity to keep from bouncing forever
- VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta );
-
- // check for stop
- if ( trace->plane.normal[2] > 0 && ent->s.pos.trDelta[2] < 40 ) {
- trace->endpos[2] += 1.0; // make sure it is off ground
- SnapVector( trace->endpos );
- G_SetOrigin( ent, trace->endpos );
- ent->s.groundEntityNum = trace->entityNum;
- return;
- }
-
- VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
- VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
- ent->s.pos.trTime = level.time;
-}
-
-
-/*
-================
-G_RunItem
-
-================
-*/
-void G_RunItem( gentity_t *ent ) {
- vec3_t origin;
- trace_t tr;
- int contents;
- int mask;
-
- // if groundentity has been set to -1, it may have been pushed off an edge
- if ( ent->s.groundEntityNum == -1 ) {
- if ( ent->s.pos.trType != TR_GRAVITY ) {
- ent->s.pos.trType = TR_GRAVITY;
- ent->s.pos.trTime = level.time;
- }
- }
-
- if ( ent->s.pos.trType == TR_STATIONARY ) {
- // check think function
- G_RunThink( ent );
- return;
- }
-
- // get current position
- BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
-
- // trace a line from the previous position to the current position
- if ( ent->clipmask ) {
- mask = ent->clipmask;
- } else {
- mask = MASK_PLAYERSOLID & ~CONTENTS_BODY;//MASK_SOLID;
- }
- trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin,
- ent->r.ownerNum, mask );
-
- VectorCopy( tr.endpos, ent->r.currentOrigin );
-
- if ( tr.startsolid ) {
- tr.fraction = 0;
- }
-
- trap_LinkEntity( ent ); // FIXME: avoid this for stationary?
-
- // check think function
- G_RunThink( ent );
-
- if ( tr.fraction == 1 ) {
- return;
- }
-
- // if it is in a nodrop volume, remove it
- contents = trap_PointContents( ent->r.currentOrigin, -1 );
- if ( contents & CONTENTS_NODROP ) {
- if (ent->item && ent->item->giType == IT_TEAM) {
- Team_FreeEntity(ent);
- } else {
- G_FreeEntity( ent );
- }
- return;
- }
-
- G_BounceItem( ent, &tr );
-}
-
diff --git a/engine/code/game/g_local.h b/engine/code/game/g_local.h
deleted file mode 100644
index 3698a2c..0000000
--- a/engine/code/game/g_local.h
+++ /dev/null
@@ -1,972 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// g_local.h -- local definitions for game module
-
-#include "../qcommon/q_shared.h"
-#include "bg_public.h"
-#include "g_public.h"
-
-//==================================================================
-
-// the "gameversion" client command will print this plus compile date
-#define GAMEVERSION BASEGAME
-
-#define BODY_QUEUE_SIZE 8
-
-#define INFINITE 1000000
-
-#define FRAMETIME 100 // msec
-#define CARNAGE_REWARD_TIME 3000
-#define REWARD_SPRITE_TIME 2000
-
-#define INTERMISSION_DELAY_TIME 1000
-#define SP_INTERMISSION_DELAY_TIME 5000
-
-// gentity->flags
-#define FL_GODMODE 0x00000010
-#define FL_NOTARGET 0x00000020
-#define FL_TEAMSLAVE 0x00000400 // not the first on the team
-#define FL_NO_KNOCKBACK 0x00000800
-#define FL_DROPPED_ITEM 0x00001000
-#define FL_NO_BOTS 0x00002000 // spawn point not for bot use
-#define FL_NO_HUMANS 0x00004000 // spawn point just for bots
-#define FL_FORCE_GESTURE 0x00008000 // force gesture on client
-
-// movers are things like doors, plats, buttons, etc
-typedef enum {
- MOVER_POS1,
- MOVER_POS2,
- MOVER_1TO2,
- MOVER_2TO1
-} moverState_t;
-
-#define SP_PODIUM_MODEL "models/mapobjects/podium/podium4.md3"
-
-//============================================================================
-
-typedef struct gentity_s gentity_t;
-typedef struct gclient_s gclient_t;
-
-struct gentity_s {
- entityState_t s; // communicated by server to clients
- entityShared_t r; // shared by both the server system and game
-
- // DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
- // EXPECTS THE FIELDS IN THAT ORDER!
- //================================
-
- struct gclient_s *client; // NULL if not a client
-
- qboolean inuse;
-
- char *classname; // set in QuakeEd
- int spawnflags; // set in QuakeEd
-
- qboolean neverFree; // if true, FreeEntity will only unlink
- // bodyque uses this
-
- int flags; // FL_* variables
-
- char *model;
- char *model2;
- int freetime; // level.time when the object was freed
-
- int eventTime; // events will be cleared EVENT_VALID_MSEC after set
- qboolean freeAfterEvent;
- qboolean unlinkAfterEvent;
-
- qboolean physicsObject; // if true, it can be pushed by movers and fall off edges
- // all game items are physicsObjects,
- float physicsBounce; // 1.0 = continuous bounce, 0.0 = no bounce
- int clipmask; // brushes with this content value will be collided against
- // when moving. items and corpses do not collide against
- // players, for instance
-
- // movers
- moverState_t moverState;
- int soundPos1;
- int sound1to2;
- int sound2to1;
- int soundPos2;
- int soundLoop;
- gentity_t *parent;
- gentity_t *nextTrain;
- gentity_t *prevTrain;
- vec3_t pos1, pos2;
-
- char *message;
-
- int timestamp; // body queue sinking, etc
-
- float angle; // set in editor, -1 = up, -2 = down
- char *target;
- char *targetname;
- char *team;
- char *targetShaderName;
- char *targetShaderNewName;
- gentity_t *target_ent;
-
- float speed;
- vec3_t movedir;
-
- int nextthink;
- void (*think)(gentity_t *self);
- void (*reached)(gentity_t *self); // movers call this when hitting endpoint
- void (*blocked)(gentity_t *self, gentity_t *other);
- void (*touch)(gentity_t *self, gentity_t *other, trace_t *trace);
- void (*use)(gentity_t *self, gentity_t *other, gentity_t *activator);
- void (*pain)(gentity_t *self, gentity_t *attacker, int damage);
- void (*die)(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod);
-
- int pain_debounce_time;
- int fly_sound_debounce_time; // wind tunnel
- int last_move_time;
-
- int health;
-
- qboolean takedamage;
-
- int damage;
- int splashDamage; // quad will increase this without increasing radius
- int splashRadius;
- int methodOfDeath;
- int splashMethodOfDeath;
-
- int count;
-
- gentity_t *chain;
- gentity_t *enemy;
- gentity_t *activator;
- gentity_t *teamchain; // next entity in team
- gentity_t *teammaster; // master of the team
-
-#ifdef MISSIONPACK
- int kamikazeTime;
- int kamikazeShockTime;
-#endif
-
- int watertype;
- int waterlevel;
-
- int noise_index;
-
- // timing variables
- float wait;
- float random;
-
- gitem_t *item; // for bonus items
-};
-
-
-typedef enum {
- CON_DISCONNECTED,
- CON_CONNECTING,
- CON_CONNECTED
-} clientConnected_t;
-
-typedef enum {
- SPECTATOR_NOT,
- SPECTATOR_FREE,
- SPECTATOR_FOLLOW,
- SPECTATOR_SCOREBOARD
-} spectatorState_t;
-
-typedef enum {
- TEAM_BEGIN, // Beginning a team game, spawn at base
- TEAM_ACTIVE // Now actively playing
-} playerTeamStateState_t;
-
-typedef struct {
- playerTeamStateState_t state;
-
- int location;
-
- int captures;
- int basedefense;
- int carrierdefense;
- int flagrecovery;
- int fragcarrier;
- int assists;
-
- float lasthurtcarrier;
- float lastreturnedflag;
- float flagsince;
- float lastfraggedcarrier;
-} playerTeamState_t;
-
-// the auto following clients don't follow a specific client
-// number, but instead follow the first two active players
-#define FOLLOW_ACTIVE1 -1
-#define FOLLOW_ACTIVE2 -2
-
-// client data that stays across multiple levels or tournament restarts
-// this is achieved by writing all the data to cvar strings at game shutdown
-// time and reading them back at connection time. Anything added here
-// MUST be dealt with in G_InitSessionData() / G_ReadSessionData() / G_WriteSessionData()
-typedef struct {
- team_t sessionTeam;
- int spectatorTime; // for determining next-in-line to play
- spectatorState_t spectatorState;
- int spectatorClient; // for chasecam and follow mode
- int wins, losses; // tournament stats
- qboolean teamLeader; // true when this client is a team leader
-} clientSession_t;
-
-//
-#define MAX_NETNAME 36
-#define MAX_VOTE_COUNT 3
-
-// client data that stays across multiple respawns, but is cleared
-// on each level change or team change at ClientBegin()
-typedef struct {
- clientConnected_t connected;
- usercmd_t cmd; // we would lose angles if not persistant
- qboolean localClient; // true if "ip" info key is "localhost"
- qboolean initialSpawn; // the first spawn should be at a cool location
- qboolean predictItemPickup; // based on cg_predictItems userinfo
- qboolean pmoveFixed; //
- char netname[MAX_NETNAME];
- int maxHealth; // for handicapping
- int enterTime; // level.time the client entered the game
- playerTeamState_t teamState; // status in teamplay games
- int voteCount; // to prevent people from constantly calling votes
- int teamVoteCount; // to prevent people from constantly calling votes
- qboolean teamInfo; // send team overlay updates?
-} clientPersistant_t;
-
-
-// this structure is cleared on each ClientSpawn(),
-// except for 'client->pers' and 'client->sess'
-struct gclient_s {
- // ps MUST be the first element, because the server expects it
- playerState_t ps; // communicated by server to clients
-
- // the rest of the structure is private to game
- clientPersistant_t pers;
- clientSession_t sess;
-
- qboolean readyToExit; // wishes to leave the intermission
-
- qboolean noclip;
-
- int lastCmdTime; // level.time of last usercmd_t, for EF_CONNECTION
- // we can't just use pers.lastCommand.time, because
- // of the g_sycronousclients case
- int buttons;
- int oldbuttons;
- int latched_buttons;
-
- vec3_t oldOrigin;
-
- // sum up damage over an entire frame, so
- // shotgun blasts give a single big kick
- int damage_armor; // damage absorbed by armor
- int damage_blood; // damage taken out of health
- int damage_knockback; // impact damage
- vec3_t damage_from; // origin for vector calculation
- qboolean damage_fromWorld; // if true, don't use the damage_from vector
-
- int accurateCount; // for "impressive" reward sound
-
- int accuracy_shots; // total number of shots
- int accuracy_hits; // total number of hits
-
- //
- int lastkilled_client; // last client that this client killed
- int lasthurt_client; // last client that damaged this client
- int lasthurt_mod; // type of damage the client did
-
- // timers
- int respawnTime; // can respawn when time > this, force after g_forcerespwan
- int inactivityTime; // kick players when time > this
- qboolean inactivityWarning; // qtrue if the five seoond warning has been given
- int rewardTime; // clear the EF_AWARD_IMPRESSIVE, etc when time > this
-
- int airOutTime;
-
- int lastKillTime; // for multiple kill rewards
-
- qboolean fireHeld; // used for hook
- gentity_t *hook; // grapple hook if out
-
- int switchTeamTime; // time the player switched teams
-
- // timeResidual is used to handle events that happen every second
- // like health / armor countdowns and regeneration
- int timeResidual;
-
-#ifdef MISSIONPACK
- gentity_t *persistantPowerup;
- int portalID;
- int ammoTimes[WP_NUM_WEAPONS];
- int invulnerabilityTime;
-#endif
-
- char *areabits;
-};
-
-
-//
-// this structure is cleared as each map is entered
-//
-#define MAX_SPAWN_VARS 64
-#define MAX_SPAWN_VARS_CHARS 4096
-
-typedef struct {
- struct gclient_s *clients; // [maxclients]
-
- struct gentity_s *gentities;
- int gentitySize;
- int num_entities; // current number, <= MAX_GENTITIES
-
- int warmupTime; // restart match at this time
-
- fileHandle_t logFile;
-
- // store latched cvars here that we want to get at often
- int maxclients;
-
- int framenum;
- int time; // in msec
- int previousTime; // so movers can back up when blocked
-
- int startTime; // level.time the map was started
-
- int teamScores[TEAM_NUM_TEAMS];
- int lastTeamLocationTime; // last time of client team location update
-
- qboolean newSession; // don't use any old session data, because
- // we changed gametype
-
- qboolean restarted; // waiting for a map_restart to fire
-
- int numConnectedClients;
- int numNonSpectatorClients; // includes connecting clients
- int numPlayingClients; // connected, non-spectators
- int sortedClients[MAX_CLIENTS]; // sorted by score
- int follow1, follow2; // clientNums for auto-follow spectators
-
- int snd_fry; // sound index for standing in lava
-
- int warmupModificationCount; // for detecting if g_warmup is changed
-
- // voting state
- char voteString[MAX_STRING_CHARS];
- char voteDisplayString[MAX_STRING_CHARS];
- int voteTime; // level.time vote was called
- int voteExecuteTime; // time the vote is executed
- int voteYes;
- int voteNo;
- int numVotingClients; // set by CalculateRanks
-
- // team voting state
- char teamVoteString[2][MAX_STRING_CHARS];
- int teamVoteTime[2]; // level.time vote was called
- int teamVoteYes[2];
- int teamVoteNo[2];
- int numteamVotingClients[2];// set by CalculateRanks
-
- // spawn variables
- qboolean spawning; // the G_Spawn*() functions are valid
- int numSpawnVars;
- char *spawnVars[MAX_SPAWN_VARS][2]; // key / value pairs
- int numSpawnVarChars;
- char spawnVarChars[MAX_SPAWN_VARS_CHARS];
-
- // intermission state
- int intermissionQueued; // intermission was qualified, but
- // wait INTERMISSION_DELAY_TIME before
- // actually going there so the last
- // frag can be watched. Disable future
- // kills during this delay
- int intermissiontime; // time the intermission was started
- char *changemap;
- qboolean readyToExit; // at least one client wants to exit
- int exitTime;
- vec3_t intermission_origin; // also used for spectator spawns
- vec3_t intermission_angle;
-
- qboolean locationLinked; // target_locations get linked
- gentity_t *locationHead; // head of the location list
- int bodyQueIndex; // dead bodies
- gentity_t *bodyQue[BODY_QUEUE_SIZE];
-#ifdef MISSIONPACK
- int portalSequence;
-#endif
-} level_locals_t;
-
-
-//
-// g_spawn.c
-//
-qboolean G_SpawnString( const char *key, const char *defaultString, char **out );
-// spawn string returns a temporary reference, you must CopyString() if you want to keep it
-qboolean G_SpawnFloat( const char *key, const char *defaultString, float *out );
-qboolean G_SpawnInt( const char *key, const char *defaultString, int *out );
-qboolean G_SpawnVector( const char *key, const char *defaultString, float *out );
-void G_SpawnEntitiesFromString( void );
-char *G_NewString( const char *string );
-
-//
-// g_cmds.c
-//
-void Cmd_Score_f (gentity_t *ent);
-void StopFollowing( gentity_t *ent );
-void BroadcastTeamChange( gclient_t *client, int oldTeam );
-void SetTeam( gentity_t *ent, char *s );
-void Cmd_FollowCycle_f( gentity_t *ent, int dir );
-
-//
-// g_items.c
-//
-void G_CheckTeamItems( void );
-void G_RunItem( gentity_t *ent );
-void RespawnItem( gentity_t *ent );
-
-void UseHoldableItem( gentity_t *ent );
-void PrecacheItem (gitem_t *it);
-gentity_t *Drop_Item( gentity_t *ent, gitem_t *item, float angle );
-gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity );
-void SetRespawn (gentity_t *ent, float delay);
-void G_SpawnItem (gentity_t *ent, gitem_t *item);
-void FinishSpawningItem( gentity_t *ent );
-void Think_Weapon (gentity_t *ent);
-int ArmorIndex (gentity_t *ent);
-void Add_Ammo (gentity_t *ent, int weapon, int count);
-void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace);
-
-void ClearRegisteredItems( void );
-void RegisterItem( gitem_t *item );
-void SaveRegisteredItems( void );
-
-//
-// g_utils.c
-//
-int G_ModelIndex( char *name );
-int G_SoundIndex( char *name );
-void G_TeamCommand( team_t team, char *cmd );
-void G_KillBox (gentity_t *ent);
-gentity_t *G_Find (gentity_t *from, int fieldofs, const char *match);
-gentity_t *G_PickTarget (char *targetname);
-void G_UseTargets (gentity_t *ent, gentity_t *activator);
-void G_SetMovedir ( vec3_t angles, vec3_t movedir);
-
-void G_InitGentity( gentity_t *e );
-gentity_t *G_Spawn (void);
-gentity_t *G_TempEntity( vec3_t origin, int event );
-void G_Sound( gentity_t *ent, int channel, int soundIndex );
-void G_FreeEntity( gentity_t *e );
-qboolean G_EntitiesFree( void );
-
-void G_TouchTriggers (gentity_t *ent);
-void G_TouchSolids (gentity_t *ent);
-
-float *tv (float x, float y, float z);
-char *vtos( const vec3_t v );
-
-float vectoyaw( const vec3_t vec );
-
-void G_AddPredictableEvent( gentity_t *ent, int event, int eventParm );
-void G_AddEvent( gentity_t *ent, int event, int eventParm );
-void G_SetOrigin( gentity_t *ent, vec3_t origin );
-void AddRemap(const char *oldShader, const char *newShader, float timeOffset);
-const char *BuildShaderStateConfig( void );
-
-//
-// g_combat.c
-//
-qboolean CanDamage (gentity_t *targ, vec3_t origin);
-void G_Damage (gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_t dir, vec3_t point, int damage, int dflags, int mod);
-qboolean G_RadiusDamage (vec3_t origin, gentity_t *attacker, float damage, float radius, gentity_t *ignore, int mod);
-int G_InvulnerabilityEffect( gentity_t *targ, vec3_t dir, vec3_t point, vec3_t impactpoint, vec3_t bouncedir );
-void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath );
-void TossClientItems( gentity_t *self );
-#ifdef MISSIONPACK
-void TossClientPersistantPowerups( gentity_t *self );
-#endif
-void TossClientCubes( gentity_t *self );
-
-// damage flags
-#define DAMAGE_RADIUS 0x00000001 // damage was indirect
-#define DAMAGE_NO_ARMOR 0x00000002 // armour does not protect from this damage
-#define DAMAGE_NO_KNOCKBACK 0x00000004 // do not affect velocity, just view angles
-#define DAMAGE_NO_PROTECTION 0x00000008 // armor, shields, invulnerability, and godmode have no effect
-#ifdef MISSIONPACK
-#define DAMAGE_NO_TEAM_PROTECTION 0x00000010 // armor, shields, invulnerability, and godmode have no effect
-#endif
-
-//
-// g_missile.c
-//
-void G_RunMissile( gentity_t *ent );
-
-gentity_t *fire_blaster (gentity_t *self, vec3_t start, vec3_t aimdir);
-gentity_t *fire_plasma (gentity_t *self, vec3_t start, vec3_t aimdir);
-gentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t aimdir);
-gentity_t *fire_rocket (gentity_t *self, vec3_t start, vec3_t dir);
-gentity_t *fire_bfg (gentity_t *self, vec3_t start, vec3_t dir);
-gentity_t *fire_grapple (gentity_t *self, vec3_t start, vec3_t dir);
-#ifdef MISSIONPACK
-gentity_t *fire_nail( gentity_t *self, vec3_t start, vec3_t forward, vec3_t right, vec3_t up );
-gentity_t *fire_prox( gentity_t *self, vec3_t start, vec3_t aimdir );
-#endif
-
-
-//
-// g_mover.c
-//
-void G_RunMover( gentity_t *ent );
-void Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace );
-
-//
-// g_trigger.c
-//
-void trigger_teleporter_touch (gentity_t *self, gentity_t *other, trace_t *trace );
-
-
-//
-// g_misc.c
-//
-void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles );
-#ifdef MISSIONPACK
-void DropPortalSource( gentity_t *ent );
-void DropPortalDestination( gentity_t *ent );
-#endif
-
-
-//
-// g_weapon.c
-//
-qboolean LogAccuracyHit( gentity_t *target, gentity_t *attacker );
-void CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint );
-void SnapVectorTowards( vec3_t v, vec3_t to );
-qboolean CheckGauntletAttack( gentity_t *ent );
-void Weapon_HookFree (gentity_t *ent);
-void Weapon_HookThink (gentity_t *ent);
-
-
-//
-// g_client.c
-//
-team_t TeamCount( int ignoreClientNum, int team );
-int TeamLeader( int team );
-team_t PickTeam( int ignoreClientNum );
-void SetClientViewAngle( gentity_t *ent, vec3_t angle );
-gentity_t *SelectSpawnPoint (vec3_t avoidPoint, vec3_t origin, vec3_t angles, qboolean isbot);
-void CopyToBodyQue( gentity_t *ent );
-void respawn (gentity_t *ent);
-void BeginIntermission (void);
-void InitClientPersistant (gclient_t *client);
-void InitClientResp (gclient_t *client);
-void InitBodyQue (void);
-void ClientSpawn( gentity_t *ent );
-void player_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod);
-void AddScore( gentity_t *ent, vec3_t origin, int score );
-void CalculateRanks( void );
-qboolean SpotWouldTelefrag( gentity_t *spot );
-
-//
-// g_svcmds.c
-//
-qboolean ConsoleCommand( void );
-void G_ProcessIPBans(void);
-qboolean G_FilterPacket (char *from);
-
-//
-// g_weapon.c
-//
-void FireWeapon( gentity_t *ent );
-#ifdef MISSIONPACK
-void G_StartKamikaze( gentity_t *ent );
-#endif
-
-//
-// p_hud.c
-//
-void MoveClientToIntermission (gentity_t *client);
-void G_SetStats (gentity_t *ent);
-void DeathmatchScoreboardMessage (gentity_t *client);
-
-//
-// g_cmds.c
-//
-
-//
-// g_pweapon.c
-//
-
-
-//
-// g_main.c
-//
-void FindIntermissionPoint( void );
-void SetLeader(int team, int client);
-void CheckTeamLeader( int team );
-void G_RunThink (gentity_t *ent);
-void QDECL G_LogPrintf( const char *fmt, ... );
-void SendScoreboardMessageToAllClients( void );
-void QDECL G_Printf( const char *fmt, ... );
-void QDECL G_Error( const char *fmt, ... );
-
-//
-// g_client.c
-//
-char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot );
-void ClientUserinfoChanged( int clientNum );
-void ClientDisconnect( int clientNum );
-void ClientBegin( int clientNum );
-void ClientCommand( int clientNum );
-
-//
-// g_active.c
-//
-void ClientThink( int clientNum );
-void ClientEndFrame( gentity_t *ent );
-void G_RunClient( gentity_t *ent );
-
-//
-// g_team.c
-//
-qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 );
-void Team_CheckDroppedItem( gentity_t *dropped );
-qboolean CheckObeliskAttack( gentity_t *obelisk, gentity_t *attacker );
-
-//
-// g_mem.c
-//
-void *G_Alloc( int size );
-void G_InitMemory( void );
-void Svcmd_GameMem_f( void );
-
-//
-// g_session.c
-//
-void G_ReadSessionData( gclient_t *client );
-void G_InitSessionData( gclient_t *client, char *userinfo );
-
-void G_InitWorldSession( void );
-void G_WriteSessionData( void );
-
-//
-// g_arenas.c
-//
-void UpdateTournamentInfo( void );
-void SpawnModelsOnVictoryPads( void );
-void Svcmd_AbortPodium_f( void );
-
-//
-// g_bot.c
-//
-void G_InitBots( qboolean restart );
-char *G_GetBotInfoByNumber( int num );
-char *G_GetBotInfoByName( const char *name );
-void G_CheckBotSpawn( void );
-void G_RemoveQueuedBotBegin( int clientNum );
-qboolean G_BotConnect( int clientNum, qboolean restart );
-void Svcmd_AddBot_f( void );
-void Svcmd_BotList_f( void );
-void BotInterbreedEndMatch( void );
-
-// ai_main.c
-#define MAX_FILEPATH 144
-
-//bot settings
-typedef struct bot_settings_s
-{
- char characterfile[MAX_FILEPATH];
- float skill;
- char team[MAX_FILEPATH];
-} bot_settings_t;
-
-int BotAISetup( int restart );
-int BotAIShutdown( int restart );
-int BotAILoadMap( int restart );
-int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean restart);
-int BotAIShutdownClient( int client, qboolean restart );
-int BotAIStartFrame( int time );
-void BotTestAAS(vec3_t origin);
-
-#include "g_team.h" // teamplay specific stuff
-
-
-extern level_locals_t level;
-extern gentity_t g_entities[MAX_GENTITIES];
-
-#define FOFS(x) ((size_t)&(((gentity_t *)0)->x))
-
-extern vmCvar_t g_gametype;
-extern vmCvar_t g_dedicated;
-extern vmCvar_t g_cheats;
-extern vmCvar_t g_maxclients; // allow this many total, including spectators
-extern vmCvar_t g_maxGameClients; // allow this many active
-extern vmCvar_t g_restarted;
-
-extern vmCvar_t g_dmflags;
-extern vmCvar_t g_fraglimit;
-extern vmCvar_t g_timelimit;
-extern vmCvar_t g_capturelimit;
-extern vmCvar_t g_friendlyFire;
-extern vmCvar_t g_password;
-extern vmCvar_t g_needpass;
-extern vmCvar_t g_gravity;
-extern vmCvar_t g_speed;
-extern vmCvar_t g_knockback;
-extern vmCvar_t g_quadfactor;
-extern vmCvar_t g_forcerespawn;
-extern vmCvar_t g_inactivity;
-extern vmCvar_t g_debugMove;
-extern vmCvar_t g_debugAlloc;
-extern vmCvar_t g_debugDamage;
-extern vmCvar_t g_weaponRespawn;
-extern vmCvar_t g_weaponTeamRespawn;
-extern vmCvar_t g_synchronousClients;
-extern vmCvar_t g_motd;
-extern vmCvar_t g_warmup;
-extern vmCvar_t g_doWarmup;
-extern vmCvar_t g_blood;
-extern vmCvar_t g_allowVote;
-extern vmCvar_t g_teamAutoJoin;
-extern vmCvar_t g_teamForceBalance;
-extern vmCvar_t g_banIPs;
-extern vmCvar_t g_filterBan;
-extern vmCvar_t g_obeliskHealth;
-extern vmCvar_t g_obeliskRegenPeriod;
-extern vmCvar_t g_obeliskRegenAmount;
-extern vmCvar_t g_obeliskRespawnDelay;
-extern vmCvar_t g_cubeTimeout;
-extern vmCvar_t g_redteam;
-extern vmCvar_t g_blueteam;
-extern vmCvar_t g_smoothClients;
-extern vmCvar_t pmove_fixed;
-extern vmCvar_t pmove_msec;
-extern vmCvar_t g_rankings;
-extern vmCvar_t g_enableDust;
-extern vmCvar_t g_enableBreath;
-extern vmCvar_t g_singlePlayer;
-extern vmCvar_t g_proxMineTimeout;
-
-void trap_Printf( const char *fmt );
-void trap_Error( const char *fmt );
-int trap_Milliseconds( void );
-int trap_RealTime( qtime_t *qtime );
-int trap_Argc( void );
-void trap_Argv( int n, char *buffer, int bufferLength );
-void trap_Args( char *buffer, int bufferLength );
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
-void trap_FS_Read( void *buffer, int len, fileHandle_t f );
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
-void trap_FS_FCloseFile( fileHandle_t f );
-int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
-void trap_SendConsoleCommand( int exec_when, const char *text );
-void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags );
-void trap_Cvar_Update( vmCvar_t *cvar );
-void trap_Cvar_Set( const char *var_name, const char *value );
-int trap_Cvar_VariableIntegerValue( const char *var_name );
-float trap_Cvar_VariableValue( const char *var_name );
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-void trap_LocateGameData( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t, playerState_t *gameClients, int sizeofGameClient );
-void trap_DropClient( int clientNum, const char *reason );
-void trap_SendServerCommand( int clientNum, const char *text );
-void trap_SetConfigstring( int num, const char *string );
-void trap_GetConfigstring( int num, char *buffer, int bufferSize );
-void trap_GetUserinfo( int num, char *buffer, int bufferSize );
-void trap_SetUserinfo( int num, const char *buffer );
-void trap_GetServerinfo( char *buffer, int bufferSize );
-void trap_SetBrushModel( gentity_t *ent, const char *name );
-void trap_Trace( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
-int trap_PointContents( const vec3_t point, int passEntityNum );
-qboolean trap_InPVS( const vec3_t p1, const vec3_t p2 );
-qboolean trap_InPVSIgnorePortals( const vec3_t p1, const vec3_t p2 );
-void trap_AdjustAreaPortalState( gentity_t *ent, qboolean open );
-qboolean trap_AreasConnected( int area1, int area2 );
-void trap_LinkEntity( gentity_t *ent );
-void trap_UnlinkEntity( gentity_t *ent );
-int trap_EntitiesInBox( const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount );
-qboolean trap_EntityContact( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
-int trap_BotAllocateClient( void );
-void trap_BotFreeClient( int clientNum );
-void trap_GetUsercmd( int clientNum, usercmd_t *cmd );
-qboolean trap_GetEntityToken( char *buffer, int bufferSize );
-
-int trap_DebugPolygonCreate(int color, int numPoints, vec3_t *points);
-void trap_DebugPolygonDelete(int id);
-
-int trap_BotLibSetup( void );
-int trap_BotLibShutdown( void );
-int trap_BotLibVarSet(char *var_name, char *value);
-int trap_BotLibVarGet(char *var_name, char *value, int size);
-int trap_BotLibDefine(char *string);
-int trap_BotLibStartFrame(float time);
-int trap_BotLibLoadMap(const char *mapname);
-int trap_BotLibUpdateEntity(int ent, void /* struct bot_updateentity_s */ *bue);
-int trap_BotLibTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3);
-
-int trap_BotGetSnapshotEntity( int clientNum, int sequence );
-int trap_BotGetServerCommand(int clientNum, char *message, int size);
-void trap_BotUserCommand(int client, usercmd_t *ucmd);
-
-int trap_AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas);
-int trap_AAS_AreaInfo( int areanum, void /* struct aas_areainfo_s */ *info );
-void trap_AAS_EntityInfo(int entnum, void /* struct aas_entityinfo_s */ *info);
-
-int trap_AAS_Initialized(void);
-void trap_AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs);
-float trap_AAS_Time(void);
-
-int trap_AAS_PointAreaNum(vec3_t point);
-int trap_AAS_PointReachabilityAreaIndex(vec3_t point);
-int trap_AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas);
-
-int trap_AAS_PointContents(vec3_t point);
-int trap_AAS_NextBSPEntity(int ent);
-int trap_AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size);
-int trap_AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v);
-int trap_AAS_FloatForBSPEpairKey(int ent, char *key, float *value);
-int trap_AAS_IntForBSPEpairKey(int ent, char *key, int *value);
-
-int trap_AAS_AreaReachability(int areanum);
-
-int trap_AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags);
-int trap_AAS_EnableRoutingArea( int areanum, int enable );
-int trap_AAS_PredictRoute(void /*struct aas_predictroute_s*/ *route, int areanum, vec3_t origin,
- int goalareanum, int travelflags, int maxareas, int maxtime,
- int stopevent, int stopcontents, int stoptfl, int stopareanum);
-
-int trap_AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,
- void /*struct aas_altroutegoal_s*/ *altroutegoals, int maxaltroutegoals,
- int type);
-int trap_AAS_Swimming(vec3_t origin);
-int trap_AAS_PredictClientMovement(void /* aas_clientmove_s */ *move, int entnum, vec3_t origin, int presencetype, int onground, vec3_t velocity, vec3_t cmdmove, int cmdframes, int maxframes, float frametime, int stopevent, int stopareanum, int visualize);
-
-
-void trap_EA_Say(int client, char *str);
-void trap_EA_SayTeam(int client, char *str);
-void trap_EA_Command(int client, char *command);
-
-void trap_EA_Action(int client, int action);
-void trap_EA_Gesture(int client);
-void trap_EA_Talk(int client);
-void trap_EA_Attack(int client);
-void trap_EA_Use(int client);
-void trap_EA_Respawn(int client);
-void trap_EA_Crouch(int client);
-void trap_EA_MoveUp(int client);
-void trap_EA_MoveDown(int client);
-void trap_EA_MoveForward(int client);
-void trap_EA_MoveBack(int client);
-void trap_EA_MoveLeft(int client);
-void trap_EA_MoveRight(int client);
-void trap_EA_SelectWeapon(int client, int weapon);
-void trap_EA_Jump(int client);
-void trap_EA_DelayedJump(int client);
-void trap_EA_Move(int client, vec3_t dir, float speed);
-void trap_EA_View(int client, vec3_t viewangles);
-
-void trap_EA_EndRegular(int client, float thinktime);
-void trap_EA_GetInput(int client, float thinktime, void /* struct bot_input_s */ *input);
-void trap_EA_ResetInput(int client);
-
-
-int trap_BotLoadCharacter(char *charfile, float skill);
-void trap_BotFreeCharacter(int character);
-float trap_Characteristic_Float(int character, int index);
-float trap_Characteristic_BFloat(int character, int index, float min, float max);
-int trap_Characteristic_Integer(int character, int index);
-int trap_Characteristic_BInteger(int character, int index, int min, int max);
-void trap_Characteristic_String(int character, int index, char *buf, int size);
-
-int trap_BotAllocChatState(void);
-void trap_BotFreeChatState(int handle);
-void trap_BotQueueConsoleMessage(int chatstate, int type, char *message);
-void trap_BotRemoveConsoleMessage(int chatstate, int handle);
-int trap_BotNextConsoleMessage(int chatstate, void /* struct bot_consolemessage_s */ *cm);
-int trap_BotNumConsoleMessages(int chatstate);
-void trap_BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 );
-int trap_BotNumInitialChats(int chatstate, char *type);
-int trap_BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 );
-int trap_BotChatLength(int chatstate);
-void trap_BotEnterChat(int chatstate, int client, int sendto);
-void trap_BotGetChatMessage(int chatstate, char *buf, int size);
-int trap_StringContains(char *str1, char *str2, int casesensitive);
-int trap_BotFindMatch(char *str, void /* struct bot_match_s */ *match, unsigned long int context);
-void trap_BotMatchVariable(void /* struct bot_match_s */ *match, int variable, char *buf, int size);
-void trap_UnifyWhiteSpaces(char *string);
-void trap_BotReplaceSynonyms(char *string, unsigned long int context);
-int trap_BotLoadChatFile(int chatstate, char *chatfile, char *chatname);
-void trap_BotSetChatGender(int chatstate, int gender);
-void trap_BotSetChatName(int chatstate, char *name, int client);
-void trap_BotResetGoalState(int goalstate);
-void trap_BotRemoveFromAvoidGoals(int goalstate, int number);
-void trap_BotResetAvoidGoals(int goalstate);
-void trap_BotPushGoal(int goalstate, void /* struct bot_goal_s */ *goal);
-void trap_BotPopGoal(int goalstate);
-void trap_BotEmptyGoalStack(int goalstate);
-void trap_BotDumpAvoidGoals(int goalstate);
-void trap_BotDumpGoalStack(int goalstate);
-void trap_BotGoalName(int number, char *name, int size);
-int trap_BotGetTopGoal(int goalstate, void /* struct bot_goal_s */ *goal);
-int trap_BotGetSecondGoal(int goalstate, void /* struct bot_goal_s */ *goal);
-int trap_BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags);
-int trap_BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, void /* struct bot_goal_s */ *ltg, float maxtime);
-int trap_BotTouchingGoal(vec3_t origin, void /* struct bot_goal_s */ *goal);
-int trap_BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, void /* struct bot_goal_s */ *goal);
-int trap_BotGetNextCampSpotGoal(int num, void /* struct bot_goal_s */ *goal);
-int trap_BotGetMapLocationGoal(char *name, void /* struct bot_goal_s */ *goal);
-int trap_BotGetLevelItemGoal(int index, char *classname, void /* struct bot_goal_s */ *goal);
-float trap_BotAvoidGoalTime(int goalstate, int number);
-void trap_BotSetAvoidGoalTime(int goalstate, int number, float avoidtime);
-void trap_BotInitLevelItems(void);
-void trap_BotUpdateEntityItems(void);
-int trap_BotLoadItemWeights(int goalstate, char *filename);
-void trap_BotFreeItemWeights(int goalstate);
-void trap_BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child);
-void trap_BotSaveGoalFuzzyLogic(int goalstate, char *filename);
-void trap_BotMutateGoalFuzzyLogic(int goalstate, float range);
-int trap_BotAllocGoalState(int state);
-void trap_BotFreeGoalState(int handle);
-
-void trap_BotResetMoveState(int movestate);
-void trap_BotMoveToGoal(void /* struct bot_moveresult_s */ *result, int movestate, void /* struct bot_goal_s */ *goal, int travelflags);
-int trap_BotMoveInDirection(int movestate, vec3_t dir, float speed, int type);
-void trap_BotResetAvoidReach(int movestate);
-void trap_BotResetLastAvoidReach(int movestate);
-int trap_BotReachabilityArea(vec3_t origin, int testground);
-int trap_BotMovementViewTarget(int movestate, void /* struct bot_goal_s */ *goal, int travelflags, float lookahead, vec3_t target);
-int trap_BotPredictVisiblePosition(vec3_t origin, int areanum, void /* struct bot_goal_s */ *goal, int travelflags, vec3_t target);
-int trap_BotAllocMoveState(void);
-void trap_BotFreeMoveState(int handle);
-void trap_BotInitMoveState(int handle, void /* struct bot_initmove_s */ *initmove);
-void trap_BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type);
-
-int trap_BotChooseBestFightWeapon(int weaponstate, int *inventory);
-void trap_BotGetWeaponInfo(int weaponstate, int weapon, void /* struct weaponinfo_s */ *weaponinfo);
-int trap_BotLoadWeaponWeights(int weaponstate, char *filename);
-int trap_BotAllocWeaponState(void);
-void trap_BotFreeWeaponState(int weaponstate);
-void trap_BotResetWeaponState(int weaponstate);
-
-int trap_GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child);
-
-void trap_SnapVector( float *v );
-
diff --git a/engine/code/game/g_main.c b/engine/code/game/g_main.c
deleted file mode 100644
index 583479b..0000000
--- a/engine/code/game/g_main.c
+++ /dev/null
@@ -1,1845 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-#include "g_local.h"
-
-level_locals_t level;
-
-typedef struct {
- vmCvar_t *vmCvar;
- char *cvarName;
- char *defaultString;
- int cvarFlags;
- int modificationCount; // for tracking changes
- qboolean trackChange; // track this variable, and announce if changed
- qboolean teamShader; // track and if changed, update shader state
-} cvarTable_t;
-
-gentity_t g_entities[MAX_GENTITIES];
-gclient_t g_clients[MAX_CLIENTS];
-
-vmCvar_t g_gametype;
-vmCvar_t g_dmflags;
-vmCvar_t g_fraglimit;
-vmCvar_t g_timelimit;
-vmCvar_t g_capturelimit;
-vmCvar_t g_friendlyFire;
-vmCvar_t g_password;
-vmCvar_t g_needpass;
-vmCvar_t g_maxclients;
-vmCvar_t g_maxGameClients;
-vmCvar_t g_dedicated;
-vmCvar_t g_speed;
-vmCvar_t g_gravity;
-vmCvar_t g_cheats;
-vmCvar_t g_knockback;
-vmCvar_t g_quadfactor;
-vmCvar_t g_forcerespawn;
-vmCvar_t g_inactivity;
-vmCvar_t g_debugMove;
-vmCvar_t g_debugDamage;
-vmCvar_t g_debugAlloc;
-vmCvar_t g_weaponRespawn;
-vmCvar_t g_weaponTeamRespawn;
-vmCvar_t g_motd;
-vmCvar_t g_synchronousClients;
-vmCvar_t g_warmup;
-vmCvar_t g_doWarmup;
-vmCvar_t g_restarted;
-vmCvar_t g_logfile;
-vmCvar_t g_logfileSync;
-vmCvar_t g_blood;
-vmCvar_t g_podiumDist;
-vmCvar_t g_podiumDrop;
-vmCvar_t g_allowVote;
-vmCvar_t g_teamAutoJoin;
-vmCvar_t g_teamForceBalance;
-vmCvar_t g_banIPs;
-vmCvar_t g_filterBan;
-vmCvar_t g_smoothClients;
-vmCvar_t pmove_fixed;
-vmCvar_t pmove_msec;
-vmCvar_t g_rankings;
-vmCvar_t g_listEntity;
-#ifdef MISSIONPACK
-vmCvar_t g_obeliskHealth;
-vmCvar_t g_obeliskRegenPeriod;
-vmCvar_t g_obeliskRegenAmount;
-vmCvar_t g_obeliskRespawnDelay;
-vmCvar_t g_cubeTimeout;
-vmCvar_t g_redteam;
-vmCvar_t g_blueteam;
-vmCvar_t g_singlePlayer;
-vmCvar_t g_enableDust;
-vmCvar_t g_enableBreath;
-vmCvar_t g_proxMineTimeout;
-#endif
-
-static cvarTable_t gameCvarTable[] = {
- // don't override the cheat state set by the system
- { &g_cheats, "sv_cheats", "", 0, 0, qfalse },
-
- // noset vars
- { NULL, "gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
- { NULL, "gamedate", __DATE__ , CVAR_ROM, 0, qfalse },
- { &g_restarted, "g_restarted", "0", CVAR_ROM, 0, qfalse },
- { NULL, "sv_mapname", "", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
-
- // latched vars
- { &g_gametype, "g_gametype", "0", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH, 0, qfalse },
-
- { &g_maxclients, "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse },
- { &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse },
-
- // change anytime vars
- { &g_dmflags, "dmflags", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
- { &g_fraglimit, "fraglimit", "20", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
- { &g_timelimit, "timelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
- { &g_capturelimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
-
- { &g_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO, 0, qfalse },
-
- { &g_friendlyFire, "g_friendlyFire", "0", CVAR_ARCHIVE, 0, qtrue },
-
- { &g_teamAutoJoin, "g_teamAutoJoin", "0", CVAR_ARCHIVE },
- { &g_teamForceBalance, "g_teamForceBalance", "0", CVAR_ARCHIVE },
-
- { &g_warmup, "g_warmup", "20", CVAR_ARCHIVE, 0, qtrue },
- { &g_doWarmup, "g_doWarmup", "0", 0, 0, qtrue },
- { &g_logfile, "g_log", "games.log", CVAR_ARCHIVE, 0, qfalse },
- { &g_logfileSync, "g_logsync", "0", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_password, "g_password", "", CVAR_USERINFO, 0, qfalse },
-
- { &g_banIPs, "g_banIPs", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_filterBan, "g_filterBan", "1", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_needpass, "g_needpass", "0", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
-
- { &g_dedicated, "dedicated", "0", 0, 0, qfalse },
-
- { &g_speed, "g_speed", "320", 0, 0, qtrue },
- { &g_gravity, "g_gravity", "800", 0, 0, qtrue },
- { &g_knockback, "g_knockback", "1000", 0, 0, qtrue },
- { &g_quadfactor, "g_quadfactor", "3", 0, 0, qtrue },
- { &g_weaponRespawn, "g_weaponrespawn", "5", 0, 0, qtrue },
- { &g_weaponTeamRespawn, "g_weaponTeamRespawn", "30", 0, 0, qtrue },
- { &g_forcerespawn, "g_forcerespawn", "20", 0, 0, qtrue },
- { &g_inactivity, "g_inactivity", "0", 0, 0, qtrue },
- { &g_debugMove, "g_debugMove", "0", 0, 0, qfalse },
- { &g_debugDamage, "g_debugDamage", "0", 0, 0, qfalse },
- { &g_debugAlloc, "g_debugAlloc", "0", 0, 0, qfalse },
- { &g_motd, "g_motd", "", 0, 0, qfalse },
- { &g_blood, "com_blood", "1", 0, 0, qfalse },
-
- { &g_podiumDist, "g_podiumDist", "80", 0, 0, qfalse },
- { &g_podiumDrop, "g_podiumDrop", "70", 0, 0, qfalse },
-
- { &g_allowVote, "g_allowVote", "1", CVAR_ARCHIVE, 0, qfalse },
- { &g_listEntity, "g_listEntity", "0", 0, 0, qfalse },
-
-#ifdef MISSIONPACK
- { &g_obeliskHealth, "g_obeliskHealth", "2500", 0, 0, qfalse },
- { &g_obeliskRegenPeriod, "g_obeliskRegenPeriod", "1", 0, 0, qfalse },
- { &g_obeliskRegenAmount, "g_obeliskRegenAmount", "15", 0, 0, qfalse },
- { &g_obeliskRespawnDelay, "g_obeliskRespawnDelay", "10", CVAR_SERVERINFO, 0, qfalse },
-
- { &g_cubeTimeout, "g_cubeTimeout", "30", 0, 0, qfalse },
- { &g_redteam, "g_redteam", "Stroggs", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO , 0, qtrue, qtrue },
- { &g_blueteam, "g_blueteam", "Pagans", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO , 0, qtrue, qtrue },
- { &g_singlePlayer, "ui_singlePlayerActive", "", 0, 0, qfalse, qfalse },
-
- { &g_enableDust, "g_enableDust", "0", CVAR_SERVERINFO, 0, qtrue, qfalse },
- { &g_enableBreath, "g_enableBreath", "0", CVAR_SERVERINFO, 0, qtrue, qfalse },
- { &g_proxMineTimeout, "g_proxMineTimeout", "20000", 0, 0, qfalse },
-#endif
- { &g_smoothClients, "g_smoothClients", "1", 0, 0, qfalse},
- { &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO, 0, qfalse},
- { &pmove_msec, "pmove_msec", "8", CVAR_SYSTEMINFO, 0, qfalse},
-
- { &g_rankings, "g_rankings", "0", 0, 0, qfalse}
-
-};
-
-static int gameCvarTableSize = sizeof( gameCvarTable ) / sizeof( gameCvarTable[0] );
-
-
-void G_InitGame( int levelTime, int randomSeed, int restart );
-void G_RunFrame( int levelTime );
-void G_ShutdownGame( int restart );
-void CheckExitRules( void );
-
-
-/*
-================
-vmMain
-
-This is the only way control passes into the module.
-This must be the very first function compiled into the .q3vm file
-================
-*/
-Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
- switch ( command ) {
- case GAME_INIT:
- G_InitGame( arg0, arg1, arg2 );
- return 0;
- case GAME_SHUTDOWN:
- G_ShutdownGame( arg0 );
- return 0;
- case GAME_CLIENT_CONNECT:
- return (intptr_t)ClientConnect( arg0, arg1, arg2 );
- case GAME_CLIENT_THINK:
- ClientThink( arg0 );
- return 0;
- case GAME_CLIENT_USERINFO_CHANGED:
- ClientUserinfoChanged( arg0 );
- return 0;
- case GAME_CLIENT_DISCONNECT:
- ClientDisconnect( arg0 );
- return 0;
- case GAME_CLIENT_BEGIN:
- ClientBegin( arg0 );
- return 0;
- case GAME_CLIENT_COMMAND:
- ClientCommand( arg0 );
- return 0;
- case GAME_RUN_FRAME:
- G_RunFrame( arg0 );
- return 0;
- case GAME_CONSOLE_COMMAND:
- return ConsoleCommand();
- case BOTAI_START_FRAME:
- return BotAIStartFrame( arg0 );
- }
-
- return -1;
-}
-
-
-void QDECL G_Printf( const char *fmt, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, fmt);
- Q_vsnprintf (text, sizeof(text), fmt, argptr);
- va_end (argptr);
-
- trap_Printf( text );
-}
-
-void QDECL G_Error( const char *fmt, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, fmt);
- Q_vsnprintf (text, sizeof(text), fmt, argptr);
- va_end (argptr);
-
- trap_Error( text );
-}
-
-/*
-================
-G_FindTeams
-
-Chain together all entities with a matching team field.
-Entity teams are used for item groups and multi-entity mover groups.
-
-All but the first will have the FL_TEAMSLAVE flag set and teammaster field set
-All but the last will have the teamchain field set to the next one
-================
-*/
-void G_FindTeams( void ) {
- gentity_t *e, *e2;
- int i, j;
- int c, c2;
-
- c = 0;
- c2 = 0;
- for ( i=1, e=g_entities+i ; i < level.num_entities ; i++,e++ ){
- if (!e->inuse)
- continue;
- if (!e->team)
- continue;
- if (e->flags & FL_TEAMSLAVE)
- continue;
- e->teammaster = e;
- c++;
- c2++;
- for (j=i+1, e2=e+1 ; j < level.num_entities ; j++,e2++)
- {
- if (!e2->inuse)
- continue;
- if (!e2->team)
- continue;
- if (e2->flags & FL_TEAMSLAVE)
- continue;
- if (!strcmp(e->team, e2->team))
- {
- c2++;
- e2->teamchain = e->teamchain;
- e->teamchain = e2;
- e2->teammaster = e;
- e2->flags |= FL_TEAMSLAVE;
-
- // make sure that targets only point at the master
- if ( e2->targetname ) {
- e->targetname = e2->targetname;
- e2->targetname = NULL;
- }
- }
- }
- }
-
- G_Printf ("%i teams with %i entities\n", c, c2);
-}
-
-void G_RemapTeamShaders( void ) {
-#ifdef MISSIONPACK
- char string[1024];
- float f = level.time * 0.001;
- Com_sprintf( string, sizeof(string), "team_icon/%s_red", g_redteam.string );
- AddRemap("textures/ctf2/redteam01", string, f);
- AddRemap("textures/ctf2/redteam02", string, f);
- Com_sprintf( string, sizeof(string), "team_icon/%s_blue", g_blueteam.string );
- AddRemap("textures/ctf2/blueteam01", string, f);
- AddRemap("textures/ctf2/blueteam02", string, f);
- trap_SetConfigstring(CS_SHADERSTATE, BuildShaderStateConfig());
-#endif
-}
-
-
-/*
-=================
-G_RegisterCvars
-=================
-*/
-void G_RegisterCvars( void ) {
- int i;
- cvarTable_t *cv;
- qboolean remapped = qfalse;
-
- for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) {
- trap_Cvar_Register( cv->vmCvar, cv->cvarName,
- cv->defaultString, cv->cvarFlags );
- if ( cv->vmCvar )
- cv->modificationCount = cv->vmCvar->modificationCount;
-
- if (cv->teamShader) {
- remapped = qtrue;
- }
- }
-
- if (remapped) {
- G_RemapTeamShaders();
- }
-
- // check some things
- if ( g_gametype.integer < 0 || g_gametype.integer >= GT_MAX_GAME_TYPE ) {
- G_Printf( "g_gametype %i is out of range, defaulting to 0\n", g_gametype.integer );
- trap_Cvar_Set( "g_gametype", "0" );
- }
-
- level.warmupModificationCount = g_warmup.modificationCount;
-}
-
-/*
-=================
-G_UpdateCvars
-=================
-*/
-void G_UpdateCvars( void ) {
- int i;
- cvarTable_t *cv;
- qboolean remapped = qfalse;
-
- for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) {
- if ( cv->vmCvar ) {
- trap_Cvar_Update( cv->vmCvar );
-
- if ( cv->modificationCount != cv->vmCvar->modificationCount ) {
- cv->modificationCount = cv->vmCvar->modificationCount;
-
- if ( cv->trackChange ) {
- trap_SendServerCommand( -1, va("print \"Server: %s changed to %s\n\"",
- cv->cvarName, cv->vmCvar->string ) );
- }
-
- if (cv->teamShader) {
- remapped = qtrue;
- }
- }
- }
- }
-
- if (remapped) {
- G_RemapTeamShaders();
- }
-}
-
-/*
-============
-G_InitGame
-
-============
-*/
-void G_InitGame( int levelTime, int randomSeed, int restart ) {
- int i;
-
- G_Printf ("------- Game Initialization -------\n");
- G_Printf ("gamename: %s\n", GAMEVERSION);
- G_Printf ("gamedate: %s\n", __DATE__);
-
- srand( randomSeed );
-
- G_RegisterCvars();
-
- G_ProcessIPBans();
-
- G_InitMemory();
-
- // set some level globals
- memset( &level, 0, sizeof( level ) );
- level.time = levelTime;
- level.startTime = levelTime;
-
- level.snd_fry = G_SoundIndex("sound/player/fry.wav"); // FIXME standing in lava / slime
-
- if ( g_gametype.integer != GT_SINGLE_PLAYER && g_logfile.string[0] ) {
- if ( g_logfileSync.integer ) {
- trap_FS_FOpenFile( g_logfile.string, &level.logFile, FS_APPEND_SYNC );
- } else {
- trap_FS_FOpenFile( g_logfile.string, &level.logFile, FS_APPEND );
- }
- if ( !level.logFile ) {
- G_Printf( "WARNING: Couldn't open logfile: %s\n", g_logfile.string );
- } else {
- char serverinfo[MAX_INFO_STRING];
-
- trap_GetServerinfo( serverinfo, sizeof( serverinfo ) );
-
- G_LogPrintf("------------------------------------------------------------\n" );
- G_LogPrintf("InitGame: %s\n", serverinfo );
- }
- } else {
- G_Printf( "Not logging to disk.\n" );
- }
-
- G_InitWorldSession();
-
- // initialize all entities for this game
- memset( g_entities, 0, MAX_GENTITIES * sizeof(g_entities[0]) );
- level.gentities = g_entities;
-
- // initialize all clients for this game
- level.maxclients = g_maxclients.integer;
- memset( g_clients, 0, MAX_CLIENTS * sizeof(g_clients[0]) );
- level.clients = g_clients;
-
- // set client fields on player ents
- for ( i=0 ; i<level.maxclients ; i++ ) {
- g_entities[i].client = level.clients + i;
- }
-
- // always leave room for the max number of clients,
- // even if they aren't all used, so numbers inside that
- // range are NEVER anything but clients
- level.num_entities = MAX_CLIENTS;
-
- // let the server system know where the entites are
- trap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ),
- &level.clients[0].ps, sizeof( level.clients[0] ) );
-
- // reserve some spots for dead player bodies
- InitBodyQue();
-
- ClearRegisteredItems();
-
- // parse the key/value pairs and spawn gentities
- G_SpawnEntitiesFromString();
-
- // general initialization
- G_FindTeams();
-
- // make sure we have flags for CTF, etc
- if( g_gametype.integer >= GT_TEAM ) {
- G_CheckTeamItems();
- }
-
- SaveRegisteredItems();
-
- G_Printf ("-----------------------------------\n");
-
- if( g_gametype.integer == GT_SINGLE_PLAYER || trap_Cvar_VariableIntegerValue( "com_buildScript" ) ) {
- G_ModelIndex( SP_PODIUM_MODEL );
- G_SoundIndex( "sound/player/gurp1.wav" );
- G_SoundIndex( "sound/player/gurp2.wav" );
- }
-
- if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
- BotAISetup( restart );
- BotAILoadMap( restart );
- G_InitBots( restart );
- }
-
- G_RemapTeamShaders();
-
-}
-
-
-
-/*
-=================
-G_ShutdownGame
-=================
-*/
-void G_ShutdownGame( int restart ) {
- G_Printf ("==== ShutdownGame ====\n");
-
- if ( level.logFile ) {
- G_LogPrintf("ShutdownGame:\n" );
- G_LogPrintf("------------------------------------------------------------\n" );
- trap_FS_FCloseFile( level.logFile );
- }
-
- // write all the client session data so we can get it back
- G_WriteSessionData();
-
- if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
- BotAIShutdown( restart );
- }
-}
-
-
-
-//===================================================================
-
-void QDECL Com_Error ( int level, const char *error, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, error);
- Q_vsnprintf (text, sizeof(text), error, argptr);
- va_end (argptr);
-
- G_Error( "%s", text);
-}
-
-void QDECL Com_Printf( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- Q_vsnprintf (text, sizeof(text), msg, argptr);
- va_end (argptr);
-
- G_Printf ("%s", text);
-}
-
-/*
-========================================================================
-
-PLAYER COUNTING / SCORE SORTING
-
-========================================================================
-*/
-
-/*
-=============
-AddTournamentPlayer
-
-If there are less than two tournament players, put a
-spectator in the game and restart
-=============
-*/
-void AddTournamentPlayer( void ) {
- int i;
- gclient_t *client;
- gclient_t *nextInLine;
-
- if ( level.numPlayingClients >= 2 ) {
- return;
- }
-
- // never change during intermission
- if ( level.intermissiontime ) {
- return;
- }
-
- nextInLine = NULL;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- client = &level.clients[i];
- if ( client->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
- continue;
- }
- // never select the dedicated follow or scoreboard clients
- if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ||
- client->sess.spectatorClient < 0 ) {
- continue;
- }
-
- if ( !nextInLine || client->sess.spectatorTime < nextInLine->sess.spectatorTime ) {
- nextInLine = client;
- }
- }
-
- if ( !nextInLine ) {
- return;
- }
-
- level.warmupTime = -1;
-
- // set them to free-for-all team
- SetTeam( &g_entities[ nextInLine - level.clients ], "f" );
-}
-
-/*
-=======================
-RemoveTournamentLoser
-
-Make the loser a spectator at the back of the line
-=======================
-*/
-void RemoveTournamentLoser( void ) {
- int clientNum;
-
- if ( level.numPlayingClients != 2 ) {
- return;
- }
-
- clientNum = level.sortedClients[1];
-
- if ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) {
- return;
- }
-
- // make them a spectator
- SetTeam( &g_entities[ clientNum ], "s" );
-}
-
-/*
-=======================
-RemoveTournamentWinner
-=======================
-*/
-void RemoveTournamentWinner( void ) {
- int clientNum;
-
- if ( level.numPlayingClients != 2 ) {
- return;
- }
-
- clientNum = level.sortedClients[0];
-
- if ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) {
- return;
- }
-
- // make them a spectator
- SetTeam( &g_entities[ clientNum ], "s" );
-}
-
-/*
-=======================
-AdjustTournamentScores
-=======================
-*/
-void AdjustTournamentScores( void ) {
- int clientNum;
-
- clientNum = level.sortedClients[0];
- if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {
- level.clients[ clientNum ].sess.wins++;
- ClientUserinfoChanged( clientNum );
- }
-
- clientNum = level.sortedClients[1];
- if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {
- level.clients[ clientNum ].sess.losses++;
- ClientUserinfoChanged( clientNum );
- }
-
-}
-
-/*
-=============
-SortRanks
-
-=============
-*/
-int QDECL SortRanks( const void *a, const void *b ) {
- gclient_t *ca, *cb;
-
- ca = &level.clients[*(int *)a];
- cb = &level.clients[*(int *)b];
-
- // sort special clients last
- if ( ca->sess.spectatorState == SPECTATOR_SCOREBOARD || ca->sess.spectatorClient < 0 ) {
- return 1;
- }
- if ( cb->sess.spectatorState == SPECTATOR_SCOREBOARD || cb->sess.spectatorClient < 0 ) {
- return -1;
- }
-
- // then connecting clients
- if ( ca->pers.connected == CON_CONNECTING ) {
- return 1;
- }
- if ( cb->pers.connected == CON_CONNECTING ) {
- return -1;
- }
-
-
- // then spectators
- if ( ca->sess.sessionTeam == TEAM_SPECTATOR && cb->sess.sessionTeam == TEAM_SPECTATOR ) {
- if ( ca->sess.spectatorTime < cb->sess.spectatorTime ) {
- return -1;
- }
- if ( ca->sess.spectatorTime > cb->sess.spectatorTime ) {
- return 1;
- }
- return 0;
- }
- if ( ca->sess.sessionTeam == TEAM_SPECTATOR ) {
- return 1;
- }
- if ( cb->sess.sessionTeam == TEAM_SPECTATOR ) {
- return -1;
- }
-
- // then sort by score
- if ( ca->ps.persistant[PERS_SCORE]
- > cb->ps.persistant[PERS_SCORE] ) {
- return -1;
- }
- if ( ca->ps.persistant[PERS_SCORE]
- < cb->ps.persistant[PERS_SCORE] ) {
- return 1;
- }
- return 0;
-}
-
-/*
-============
-CalculateRanks
-
-Recalculates the score ranks of all players
-This will be called on every client connect, begin, disconnect, death,
-and team change.
-============
-*/
-void CalculateRanks( void ) {
- int i;
- int rank;
- int score;
- int newScore;
- gclient_t *cl;
-
- level.follow1 = -1;
- level.follow2 = -1;
- level.numConnectedClients = 0;
- level.numNonSpectatorClients = 0;
- level.numPlayingClients = 0;
- level.numVotingClients = 0; // don't count bots
- for ( i = 0; i < TEAM_NUM_TEAMS; i++ ) {
- level.numteamVotingClients[i] = 0;
- }
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].pers.connected != CON_DISCONNECTED ) {
- level.sortedClients[level.numConnectedClients] = i;
- level.numConnectedClients++;
-
- if ( level.clients[i].sess.sessionTeam != TEAM_SPECTATOR ) {
- level.numNonSpectatorClients++;
-
- // decide if this should be auto-followed
- if ( level.clients[i].pers.connected == CON_CONNECTED ) {
- level.numPlayingClients++;
- if ( !(g_entities[i].r.svFlags & SVF_BOT) ) {
- level.numVotingClients++;
- if ( level.clients[i].sess.sessionTeam == TEAM_RED )
- level.numteamVotingClients[0]++;
- else if ( level.clients[i].sess.sessionTeam == TEAM_BLUE )
- level.numteamVotingClients[1]++;
- }
- if ( level.follow1 == -1 ) {
- level.follow1 = i;
- } else if ( level.follow2 == -1 ) {
- level.follow2 = i;
- }
- }
- }
- }
- }
-
- qsort( level.sortedClients, level.numConnectedClients,
- sizeof(level.sortedClients[0]), SortRanks );
-
- // set the rank value for all clients that are connected and not spectators
- if ( g_gametype.integer >= GT_TEAM ) {
- // in team games, rank is just the order of the teams, 0=red, 1=blue, 2=tied
- for ( i = 0; i < level.numConnectedClients; i++ ) {
- cl = &level.clients[ level.sortedClients[i] ];
- if ( level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE] ) {
- cl->ps.persistant[PERS_RANK] = 2;
- } else if ( level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE] ) {
- cl->ps.persistant[PERS_RANK] = 0;
- } else {
- cl->ps.persistant[PERS_RANK] = 1;
- }
- }
- } else {
- rank = -1;
- score = 0;
- for ( i = 0; i < level.numPlayingClients; i++ ) {
- cl = &level.clients[ level.sortedClients[i] ];
- newScore = cl->ps.persistant[PERS_SCORE];
- if ( i == 0 || newScore != score ) {
- rank = i;
- // assume we aren't tied until the next client is checked
- level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank;
- } else {
- // we are tied with the previous client
- level.clients[ level.sortedClients[i-1] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
- level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
- }
- score = newScore;
- if ( g_gametype.integer == GT_SINGLE_PLAYER && level.numPlayingClients == 1 ) {
- level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
- }
- }
- }
-
- // set the CS_SCORES1/2 configstrings, which will be visible to everyone
- if ( g_gametype.integer >= GT_TEAM ) {
- trap_SetConfigstring( CS_SCORES1, va("%i", level.teamScores[TEAM_RED] ) );
- trap_SetConfigstring( CS_SCORES2, va("%i", level.teamScores[TEAM_BLUE] ) );
- } else {
- if ( level.numConnectedClients == 0 ) {
- trap_SetConfigstring( CS_SCORES1, va("%i", SCORE_NOT_PRESENT) );
- trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) );
- } else if ( level.numConnectedClients == 1 ) {
- trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );
- trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) );
- } else {
- trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );
- trap_SetConfigstring( CS_SCORES2, va("%i", level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE] ) );
- }
- }
-
- // see if it is time to end the level
- CheckExitRules();
-
- // if we are at the intermission, send the new info to everyone
- if ( level.intermissiontime ) {
- SendScoreboardMessageToAllClients();
- }
-}
-
-
-/*
-========================================================================
-
-MAP CHANGING
-
-========================================================================
-*/
-
-/*
-========================
-SendScoreboardMessageToAllClients
-
-Do this at BeginIntermission time and whenever ranks are recalculated
-due to enters/exits/forced team changes
-========================
-*/
-void SendScoreboardMessageToAllClients( void ) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
- DeathmatchScoreboardMessage( g_entities + i );
- }
- }
-}
-
-/*
-========================
-MoveClientToIntermission
-
-When the intermission starts, this will be called for all players.
-If a new client connects, this will be called after the spawn function.
-========================
-*/
-void MoveClientToIntermission( gentity_t *ent ) {
- // take out of follow mode if needed
- if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {
- StopFollowing( ent );
- }
-
-
- // move to the spot
- VectorCopy( level.intermission_origin, ent->s.origin );
- VectorCopy( level.intermission_origin, ent->client->ps.origin );
- VectorCopy (level.intermission_angle, ent->client->ps.viewangles);
- ent->client->ps.pm_type = PM_INTERMISSION;
-
- // clean up powerup info
- memset( ent->client->ps.powerups, 0, sizeof(ent->client->ps.powerups) );
-
- ent->client->ps.eFlags = 0;
- ent->s.eFlags = 0;
- ent->s.eType = ET_GENERAL;
- ent->s.modelindex = 0;
- ent->s.loopSound = 0;
- ent->s.event = 0;
- ent->r.contents = 0;
-}
-
-/*
-==================
-FindIntermissionPoint
-
-This is also used for spectator spawns
-==================
-*/
-void FindIntermissionPoint( void ) {
- gentity_t *ent, *target;
- vec3_t dir;
-
- // find the intermission spot
- ent = G_Find (NULL, FOFS(classname), "info_player_intermission");
- if ( !ent ) { // the map creator forgot to put in an intermission point...
- SelectSpawnPoint ( vec3_origin, level.intermission_origin, level.intermission_angle, qfalse );
- } else {
- VectorCopy (ent->s.origin, level.intermission_origin);
- VectorCopy (ent->s.angles, level.intermission_angle);
- // if it has a target, look towards it
- if ( ent->target ) {
- target = G_PickTarget( ent->target );
- if ( target ) {
- VectorSubtract( target->s.origin, level.intermission_origin, dir );
- vectoangles( dir, level.intermission_angle );
- }
- }
- }
-
-}
-
-/*
-==================
-BeginIntermission
-==================
-*/
-void BeginIntermission( void ) {
- int i;
- gentity_t *client;
-
- if ( level.intermissiontime ) {
- return; // already active
- }
-
- // if in tournement mode, change the wins / losses
- if ( g_gametype.integer == GT_TOURNAMENT ) {
- AdjustTournamentScores();
- }
-
- level.intermissiontime = level.time;
- FindIntermissionPoint();
-
-#ifdef MISSIONPACK
- if (g_singlePlayer.integer) {
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- UpdateTournamentInfo();
- }
-#else
- // if single player game
- if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
- UpdateTournamentInfo();
- SpawnModelsOnVictoryPads();
- }
-#endif
-
- // move all clients to the intermission point
- for (i=0 ; i< level.maxclients ; i++) {
- client = g_entities + i;
- if (!client->inuse)
- continue;
- // respawn if dead
- if (client->health <= 0) {
- respawn(client);
- }
- MoveClientToIntermission( client );
- }
-
- // send the current scoring to all clients
- SendScoreboardMessageToAllClients();
-
-}
-
-
-/*
-=============
-ExitLevel
-
-When the intermission has been exited, the server is either killed
-or moved to a new level based on the "nextmap" cvar
-
-=============
-*/
-void ExitLevel (void) {
- int i;
- gclient_t *cl;
- char nextmap[MAX_STRING_CHARS];
- char d1[MAX_STRING_CHARS];
-
- //bot interbreeding
- BotInterbreedEndMatch();
-
- // if we are running a tournement map, kick the loser to spectator status,
- // which will automatically grab the next spectator and restart
- if ( g_gametype.integer == GT_TOURNAMENT ) {
- if ( !level.restarted ) {
- RemoveTournamentLoser();
- trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
- level.restarted = qtrue;
- level.changemap = NULL;
- level.intermissiontime = 0;
- }
- return;
- }
-
- trap_Cvar_VariableStringBuffer( "nextmap", nextmap, sizeof(nextmap) );
- trap_Cvar_VariableStringBuffer( "d1", d1, sizeof(d1) );
-
- if( !Q_stricmp( nextmap, "map_restart 0" ) && Q_stricmp( d1, "" ) ) {
- trap_Cvar_Set( "nextmap", "vstr d2" );
- trap_SendConsoleCommand( EXEC_APPEND, "vstr d1\n" );
- } else {
- trap_SendConsoleCommand( EXEC_APPEND, "vstr nextmap\n" );
- }
-
- level.changemap = NULL;
- level.intermissiontime = 0;
-
- // reset all the scores so we don't enter the intermission again
- level.teamScores[TEAM_RED] = 0;
- level.teamScores[TEAM_BLUE] = 0;
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- cl->ps.persistant[PERS_SCORE] = 0;
- }
-
- // we need to do this here before chaning to CON_CONNECTING
- G_WriteSessionData();
-
- // change all client states to connecting, so the early players into the
- // next level will know the others aren't done reconnecting
- for (i=0 ; i< g_maxclients.integer ; i++) {
- if ( level.clients[i].pers.connected == CON_CONNECTED ) {
- level.clients[i].pers.connected = CON_CONNECTING;
- }
- }
-
-}
-
-/*
-=================
-G_LogPrintf
-
-Print to the logfile with a time stamp if it is open
-=================
-*/
-void QDECL G_LogPrintf( const char *fmt, ... ) {
- va_list argptr;
- char string[1024];
- int min, tens, sec;
-
- sec = level.time / 1000;
-
- min = sec / 60;
- sec -= min * 60;
- tens = sec / 10;
- sec -= tens * 10;
-
- Com_sprintf( string, sizeof(string), "%3i:%i%i ", min, tens, sec );
-
- va_start( argptr, fmt );
- Q_vsnprintf(string + 7, sizeof(string) - 7, fmt, argptr);
- va_end( argptr );
-
- if ( g_dedicated.integer ) {
- G_Printf( "%s", string + 7 );
- }
-
- if ( !level.logFile ) {
- return;
- }
-
- trap_FS_Write( string, strlen( string ), level.logFile );
-}
-
-/*
-================
-LogExit
-
-Append information about this game to the log file
-================
-*/
-void LogExit( const char *string ) {
- int i, numSorted;
- gclient_t *cl;
-#ifdef MISSIONPACK
- qboolean won = qtrue;
-#endif
- G_LogPrintf( "Exit: %s\n", string );
-
- level.intermissionQueued = level.time;
-
- // this will keep the clients from playing any voice sounds
- // that will get cut off when the queued intermission starts
- trap_SetConfigstring( CS_INTERMISSION, "1" );
-
- // don't send more than 32 scores (FIXME?)
- numSorted = level.numConnectedClients;
- if ( numSorted > 32 ) {
- numSorted = 32;
- }
-
- if ( g_gametype.integer >= GT_TEAM ) {
- G_LogPrintf( "red:%i blue:%i\n",
- level.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE] );
- }
-
- for (i=0 ; i < numSorted ; i++) {
- int ping;
-
- cl = &level.clients[level.sortedClients[i]];
-
- if ( cl->sess.sessionTeam == TEAM_SPECTATOR ) {
- continue;
- }
- if ( cl->pers.connected == CON_CONNECTING ) {
- continue;
- }
-
- ping = cl->ps.ping < 999 ? cl->ps.ping : 999;
-
- G_LogPrintf( "score: %i ping: %i client: %i %s\n", cl->ps.persistant[PERS_SCORE], ping, level.sortedClients[i], cl->pers.netname );
-#ifdef MISSIONPACK
- if (g_singlePlayer.integer && g_gametype.integer == GT_TOURNAMENT) {
- if (g_entities[cl - level.clients].r.svFlags & SVF_BOT && cl->ps.persistant[PERS_RANK] == 0) {
- won = qfalse;
- }
- }
-#endif
-
- }
-
-#ifdef MISSIONPACK
- if (g_singlePlayer.integer) {
- if (g_gametype.integer >= GT_CTF) {
- won = level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE];
- }
- trap_SendConsoleCommand( EXEC_APPEND, (won) ? "spWin\n" : "spLose\n" );
- }
-#endif
-
-
-}
-
-
-/*
-=================
-CheckIntermissionExit
-
-The level will stay at the intermission for a minimum of 5 seconds
-If all players wish to continue, the level will then exit.
-If one or more players have not acknowledged the continue, the game will
-wait 10 seconds before going on.
-=================
-*/
-void CheckIntermissionExit( void ) {
- int ready, notReady, playerCount;
- int i;
- gclient_t *cl;
- int readyMask;
-
- if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
- return;
- }
-
- // see which players are ready
- ready = 0;
- notReady = 0;
- readyMask = 0;
- playerCount = 0;
- for (i=0 ; i< g_maxclients.integer ; i++) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT ) {
- continue;
- }
-
- playerCount++;
- if ( cl->readyToExit ) {
- ready++;
- if ( i < 16 ) {
- readyMask |= 1 << i;
- }
- } else {
- notReady++;
- }
- }
-
- // copy the readyMask to each player's stats so
- // it can be displayed on the scoreboard
- for (i=0 ; i< g_maxclients.integer ; i++) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- cl->ps.stats[STAT_CLIENTS_READY] = readyMask;
- }
-
- // never exit in less than five seconds
- if ( level.time < level.intermissiontime + 5000 ) {
- return;
- }
-
- // only test ready status when there are real players present
- if ( playerCount > 0 ) {
- // if nobody wants to go, clear timer
- if ( !ready ) {
- level.readyToExit = qfalse;
- return;
- }
-
- // if everyone wants to go, go now
- if ( !notReady ) {
- ExitLevel();
- return;
- }
- }
-
- // the first person to ready starts the ten second timeout
- if ( !level.readyToExit ) {
- level.readyToExit = qtrue;
- level.exitTime = level.time;
- }
-
- // if we have waited ten seconds since at least one player
- // wanted to exit, go ahead
- if ( level.time < level.exitTime + 10000 ) {
- return;
- }
-
- ExitLevel();
-}
-
-/*
-=============
-ScoreIsTied
-=============
-*/
-qboolean ScoreIsTied( void ) {
- int a, b;
-
- if ( level.numPlayingClients < 2 ) {
- return qfalse;
- }
-
- if ( g_gametype.integer >= GT_TEAM ) {
- return level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE];
- }
-
- a = level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE];
- b = level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE];
-
- return a == b;
-}
-
-/*
-=================
-CheckExitRules
-
-There will be a delay between the time the exit is qualified for
-and the time everyone is moved to the intermission spot, so you
-can see the last frag.
-=================
-*/
-void CheckExitRules( void ) {
- int i;
- gclient_t *cl;
- // if at the intermission, wait for all non-bots to
- // signal ready, then go to next level
- if ( level.intermissiontime ) {
- CheckIntermissionExit ();
- return;
- }
-
- if ( level.intermissionQueued ) {
-#ifdef MISSIONPACK
- int time = (g_singlePlayer.integer) ? SP_INTERMISSION_DELAY_TIME : INTERMISSION_DELAY_TIME;
- if ( level.time - level.intermissionQueued >= time ) {
- level.intermissionQueued = 0;
- BeginIntermission();
- }
-#else
- if ( level.time - level.intermissionQueued >= INTERMISSION_DELAY_TIME ) {
- level.intermissionQueued = 0;
- BeginIntermission();
- }
-#endif
- return;
- }
-
- // check for sudden death
- if ( ScoreIsTied() ) {
- // always wait for sudden death
- return;
- }
-
- if ( g_timelimit.integer && !level.warmupTime ) {
- if ( level.time - level.startTime >= g_timelimit.integer*60000 ) {
- trap_SendServerCommand( -1, "print \"Timelimit hit.\n\"");
- LogExit( "Timelimit hit." );
- return;
- }
- }
-
- if ( level.numPlayingClients < 2 ) {
- return;
- }
-
- if ( g_gametype.integer < GT_CTF && g_fraglimit.integer ) {
- if ( level.teamScores[TEAM_RED] >= g_fraglimit.integer ) {
- trap_SendServerCommand( -1, "print \"Red hit the fraglimit.\n\"" );
- LogExit( "Fraglimit hit." );
- return;
- }
-
- if ( level.teamScores[TEAM_BLUE] >= g_fraglimit.integer ) {
- trap_SendServerCommand( -1, "print \"Blue hit the fraglimit.\n\"" );
- LogExit( "Fraglimit hit." );
- return;
- }
-
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( cl->sess.sessionTeam != TEAM_FREE ) {
- continue;
- }
-
- if ( cl->ps.persistant[PERS_SCORE] >= g_fraglimit.integer ) {
- LogExit( "Fraglimit hit." );
- trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " hit the fraglimit.\n\"",
- cl->pers.netname ) );
- return;
- }
- }
- }
-
- if ( g_gametype.integer >= GT_CTF && g_capturelimit.integer ) {
-
- if ( level.teamScores[TEAM_RED] >= g_capturelimit.integer ) {
- trap_SendServerCommand( -1, "print \"Red hit the capturelimit.\n\"" );
- LogExit( "Capturelimit hit." );
- return;
- }
-
- if ( level.teamScores[TEAM_BLUE] >= g_capturelimit.integer ) {
- trap_SendServerCommand( -1, "print \"Blue hit the capturelimit.\n\"" );
- LogExit( "Capturelimit hit." );
- return;
- }
- }
-}
-
-
-
-/*
-========================================================================
-
-FUNCTIONS CALLED EVERY FRAME
-
-========================================================================
-*/
-
-
-/*
-=============
-CheckTournament
-
-Once a frame, check for changes in tournement player state
-=============
-*/
-void CheckTournament( void ) {
- // check because we run 3 game frames before calling Connect and/or ClientBegin
- // for clients on a map_restart
- if ( level.numPlayingClients == 0 ) {
- return;
- }
-
- if ( g_gametype.integer == GT_TOURNAMENT ) {
-
- // pull in a spectator if needed
- if ( level.numPlayingClients < 2 ) {
- AddTournamentPlayer();
- }
-
- // if we don't have two players, go back to "waiting for players"
- if ( level.numPlayingClients != 2 ) {
- if ( level.warmupTime != -1 ) {
- level.warmupTime = -1;
- trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
- G_LogPrintf( "Warmup:\n" );
- }
- return;
- }
-
- if ( level.warmupTime == 0 ) {
- return;
- }
-
- // if the warmup is changed at the console, restart it
- if ( g_warmup.modificationCount != level.warmupModificationCount ) {
- level.warmupModificationCount = g_warmup.modificationCount;
- level.warmupTime = -1;
- }
-
- // if all players have arrived, start the countdown
- if ( level.warmupTime < 0 ) {
- if ( level.numPlayingClients == 2 ) {
- // fudge by -1 to account for extra delays
- if ( g_warmup.integer > 1 ) {
- level.warmupTime = level.time + ( g_warmup.integer - 1 ) * 1000;
- } else {
- level.warmupTime = 0;
- }
-
- trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
- }
- return;
- }
-
- // if the warmup time has counted down, restart
- if ( level.time > level.warmupTime ) {
- level.warmupTime += 10000;
- trap_Cvar_Set( "g_restarted", "1" );
- trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
- level.restarted = qtrue;
- return;
- }
- } else if ( g_gametype.integer != GT_SINGLE_PLAYER && level.warmupTime != 0 ) {
- int counts[TEAM_NUM_TEAMS];
- qboolean notEnough = qfalse;
-
- if ( g_gametype.integer > GT_TEAM ) {
- counts[TEAM_BLUE] = TeamCount( -1, TEAM_BLUE );
- counts[TEAM_RED] = TeamCount( -1, TEAM_RED );
-
- if (counts[TEAM_RED] < 1 || counts[TEAM_BLUE] < 1) {
- notEnough = qtrue;
- }
- } else if ( level.numPlayingClients < 2 ) {
- notEnough = qtrue;
- }
-
- if ( notEnough ) {
- if ( level.warmupTime != -1 ) {
- level.warmupTime = -1;
- trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
- G_LogPrintf( "Warmup:\n" );
- }
- return; // still waiting for team members
- }
-
- if ( level.warmupTime == 0 ) {
- return;
- }
-
- // if the warmup is changed at the console, restart it
- if ( g_warmup.modificationCount != level.warmupModificationCount ) {
- level.warmupModificationCount = g_warmup.modificationCount;
- level.warmupTime = -1;
- }
-
- // if all players have arrived, start the countdown
- if ( level.warmupTime < 0 ) {
- // fudge by -1 to account for extra delays
- level.warmupTime = level.time + ( g_warmup.integer - 1 ) * 1000;
- trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
- return;
- }
-
- // if the warmup time has counted down, restart
- if ( level.time > level.warmupTime ) {
- level.warmupTime += 10000;
- trap_Cvar_Set( "g_restarted", "1" );
- trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
- level.restarted = qtrue;
- return;
- }
- }
-}
-
-
-/*
-==================
-CheckVote
-==================
-*/
-void CheckVote( void ) {
- if ( level.voteExecuteTime && level.voteExecuteTime < level.time ) {
- level.voteExecuteTime = 0;
- trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.voteString ) );
- }
- if ( !level.voteTime ) {
- return;
- }
- if ( level.time - level.voteTime >= VOTE_TIME ) {
- trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
- } else {
- // ATVI Q3 1.32 Patch #9, WNF
- if ( level.voteYes > level.numVotingClients/2 ) {
- // execute the command, then remove the vote
- trap_SendServerCommand( -1, "print \"Vote passed.\n\"" );
- level.voteExecuteTime = level.time + 3000;
- } else if ( level.voteNo >= level.numVotingClients/2 ) {
- // same behavior as a timeout
- trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
- } else {
- // still waiting for a majority
- return;
- }
- }
- level.voteTime = 0;
- trap_SetConfigstring( CS_VOTE_TIME, "" );
-
-}
-
-/*
-==================
-PrintTeam
-==================
-*/
-void PrintTeam(int team, char *message) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if (level.clients[i].sess.sessionTeam != team)
- continue;
- trap_SendServerCommand( i, message );
- }
-}
-
-/*
-==================
-SetLeader
-==================
-*/
-void SetLeader(int team, int client) {
- int i;
-
- if ( level.clients[client].pers.connected == CON_DISCONNECTED ) {
- PrintTeam(team, va("print \"%s is not connected\n\"", level.clients[client].pers.netname) );
- return;
- }
- if (level.clients[client].sess.sessionTeam != team) {
- PrintTeam(team, va("print \"%s is not on the team anymore\n\"", level.clients[client].pers.netname) );
- return;
- }
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if (level.clients[i].sess.sessionTeam != team)
- continue;
- if (level.clients[i].sess.teamLeader) {
- level.clients[i].sess.teamLeader = qfalse;
- ClientUserinfoChanged(i);
- }
- }
- level.clients[client].sess.teamLeader = qtrue;
- ClientUserinfoChanged( client );
- PrintTeam(team, va("print \"%s is the new team leader\n\"", level.clients[client].pers.netname) );
-}
-
-/*
-==================
-CheckTeamLeader
-==================
-*/
-void CheckTeamLeader( int team ) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if (level.clients[i].sess.sessionTeam != team)
- continue;
- if (level.clients[i].sess.teamLeader)
- break;
- }
- if (i >= level.maxclients) {
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if (level.clients[i].sess.sessionTeam != team)
- continue;
- if (!(g_entities[i].r.svFlags & SVF_BOT)) {
- level.clients[i].sess.teamLeader = qtrue;
- break;
- }
- }
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if (level.clients[i].sess.sessionTeam != team)
- continue;
- level.clients[i].sess.teamLeader = qtrue;
- break;
- }
- }
-}
-
-/*
-==================
-CheckTeamVote
-==================
-*/
-void CheckTeamVote( int team ) {
- int cs_offset;
-
- if ( team == TEAM_RED )
- cs_offset = 0;
- else if ( team == TEAM_BLUE )
- cs_offset = 1;
- else
- return;
-
- if ( !level.teamVoteTime[cs_offset] ) {
- return;
- }
- if ( level.time - level.teamVoteTime[cs_offset] >= VOTE_TIME ) {
- trap_SendServerCommand( -1, "print \"Team vote failed.\n\"" );
- } else {
- if ( level.teamVoteYes[cs_offset] > level.numteamVotingClients[cs_offset]/2 ) {
- // execute the command, then remove the vote
- trap_SendServerCommand( -1, "print \"Team vote passed.\n\"" );
- //
- if ( !Q_strncmp( "leader", level.teamVoteString[cs_offset], 6) ) {
- //set the team leader
- SetLeader(team, atoi(level.teamVoteString[cs_offset] + 7));
- }
- else {
- trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.teamVoteString[cs_offset] ) );
- }
- } else if ( level.teamVoteNo[cs_offset] >= level.numteamVotingClients[cs_offset]/2 ) {
- // same behavior as a timeout
- trap_SendServerCommand( -1, "print \"Team vote failed.\n\"" );
- } else {
- // still waiting for a majority
- return;
- }
- }
- level.teamVoteTime[cs_offset] = 0;
- trap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, "" );
-
-}
-
-
-/*
-==================
-CheckCvars
-==================
-*/
-void CheckCvars( void ) {
- static int lastMod = -1;
-
- if ( g_password.modificationCount != lastMod ) {
- lastMod = g_password.modificationCount;
- if ( *g_password.string && Q_stricmp( g_password.string, "none" ) ) {
- trap_Cvar_Set( "g_needpass", "1" );
- } else {
- trap_Cvar_Set( "g_needpass", "0" );
- }
- }
-}
-
-/*
-=============
-G_RunThink
-
-Runs thinking code for this frame if necessary
-=============
-*/
-void G_RunThink (gentity_t *ent) {
- float thinktime;
-
- thinktime = ent->nextthink;
- if (thinktime <= 0) {
- return;
- }
- if (thinktime > level.time) {
- return;
- }
-
- ent->nextthink = 0;
- if (!ent->think) {
- G_Error ( "NULL ent->think");
- }
- ent->think (ent);
-}
-
-/*
-================
-G_RunFrame
-
-Advances the non-player objects in the world
-================
-*/
-void G_RunFrame( int levelTime ) {
- int i;
- gentity_t *ent;
- int msec;
-int start, end;
-
- // if we are waiting for the level to restart, do nothing
- if ( level.restarted ) {
- return;
- }
-
- level.framenum++;
- level.previousTime = level.time;
- level.time = levelTime;
- msec = level.time - level.previousTime;
-
- // get any cvar changes
- G_UpdateCvars();
-
- //
- // go through all allocated objects
- //
- start = trap_Milliseconds();
- ent = &g_entities[0];
- for (i=0 ; i<level.num_entities ; i++, ent++) {
- if ( !ent->inuse ) {
- continue;
- }
-
- // clear events that are too old
- if ( level.time - ent->eventTime > EVENT_VALID_MSEC ) {
- if ( ent->s.event ) {
- ent->s.event = 0; // &= EV_EVENT_BITS;
- if ( ent->client ) {
- ent->client->ps.externalEvent = 0;
- // predicted events should never be set to zero
- //ent->client->ps.events[0] = 0;
- //ent->client->ps.events[1] = 0;
- }
- }
- if ( ent->freeAfterEvent ) {
- // tempEntities or dropped items completely go away after their event
- G_FreeEntity( ent );
- continue;
- } else if ( ent->unlinkAfterEvent ) {
- // items that will respawn will hide themselves after their pickup event
- ent->unlinkAfterEvent = qfalse;
- trap_UnlinkEntity( ent );
- }
- }
-
- // temporary entities don't think
- if ( ent->freeAfterEvent ) {
- continue;
- }
-
- if ( !ent->r.linked && ent->neverFree ) {
- continue;
- }
-
- if ( ent->s.eType == ET_MISSILE ) {
- G_RunMissile( ent );
- continue;
- }
-
- if ( ent->s.eType == ET_ITEM || ent->physicsObject ) {
- G_RunItem( ent );
- continue;
- }
-
- if ( ent->s.eType == ET_MOVER ) {
- G_RunMover( ent );
- continue;
- }
-
- if ( i < MAX_CLIENTS ) {
- G_RunClient( ent );
- continue;
- }
-
- G_RunThink( ent );
- }
-end = trap_Milliseconds();
-
-start = trap_Milliseconds();
- // perform final fixups on the players
- ent = &g_entities[0];
- for (i=0 ; i < level.maxclients ; i++, ent++ ) {
- if ( ent->inuse ) {
- ClientEndFrame( ent );
- }
- }
-end = trap_Milliseconds();
-
- // see if it is time to do a tournement restart
- CheckTournament();
-
- // see if it is time to end the level
- CheckExitRules();
-
- // update to team status?
- CheckTeamStatus();
-
- // cancel vote if timed out
- CheckVote();
-
- // check team votes
- CheckTeamVote( TEAM_RED );
- CheckTeamVote( TEAM_BLUE );
-
- // for tracking changes
- CheckCvars();
-
- if (g_listEntity.integer) {
- for (i = 0; i < MAX_GENTITIES; i++) {
- G_Printf("%4i: %s\n", i, g_entities[i].classname);
- }
- trap_Cvar_Set("g_listEntity", "0");
- }
-}
diff --git a/engine/code/game/g_mem.c b/engine/code/game/g_mem.c
deleted file mode 100644
index dbeb301..0000000
--- a/engine/code/game/g_mem.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-//
-// g_mem.c
-//
-
-
-#include "g_local.h"
-
-
-#define POOLSIZE (256 * 1024)
-
-static char memoryPool[POOLSIZE];
-static int allocPoint;
-
-void *G_Alloc( int size ) {
- char *p;
-
- if ( g_debugAlloc.integer ) {
- G_Printf( "G_Alloc of %i bytes (%i left)\n", size, POOLSIZE - allocPoint - ( ( size + 31 ) & ~31 ) );
- }
-
- if ( allocPoint + size > POOLSIZE ) {
- G_Error( "G_Alloc: failed on allocation of %i bytes\n", size );
- return NULL;
- }
-
- p = &memoryPool[allocPoint];
-
- allocPoint += ( size + 31 ) & ~31;
-
- return p;
-}
-
-void G_InitMemory( void ) {
- allocPoint = 0;
-}
-
-void Svcmd_GameMem_f( void ) {
- G_Printf( "Game memory status: %i out of %i bytes allocated\n", allocPoint, POOLSIZE );
-}
diff --git a/engine/code/game/g_misc.c b/engine/code/game/g_misc.c
deleted file mode 100644
index b736cfd..0000000
--- a/engine/code/game/g_misc.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// g_misc.c
-
-#include "g_local.h"
-
-
-/*QUAKED func_group (0 0 0) ?
-Used to group brushes together just for editor convenience. They are turned into normal brushes by the utilities.
-*/
-
-
-/*QUAKED info_camp (0 0.5 0) (-4 -4 -4) (4 4 4)
-Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
-*/
-void SP_info_camp( gentity_t *self ) {
- G_SetOrigin( self, self->s.origin );
-}
-
-
-/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
-Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
-*/
-void SP_info_null( gentity_t *self ) {
- G_FreeEntity( self );
-}
-
-
-/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
-Used as a positional target for in-game calculation, like jumppad targets.
-target_position does the same thing
-*/
-void SP_info_notnull( gentity_t *self ){
- G_SetOrigin( self, self->s.origin );
-}
-
-
-/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) linear
-Non-displayed light.
-"light" overrides the default 300 intensity.
-Linear checbox gives linear falloff instead of inverse square
-Lights pointed at a target will be spotlights.
-"radius" overrides the default 64 unit radius of a spotlight at the target point.
-*/
-void SP_light( gentity_t *self ) {
- G_FreeEntity( self );
-}
-
-
-
-/*
-=================================================================================
-
-TELEPORTERS
-
-=================================================================================
-*/
-
-void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles ) {
- gentity_t *tent;
-
- // use temp events at source and destination to prevent the effect
- // from getting dropped by a second player event
- if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
- tent->s.clientNum = player->s.clientNum;
-
- tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN );
- tent->s.clientNum = player->s.clientNum;
- }
-
- // unlink to make sure it can't possibly interfere with G_KillBox
- trap_UnlinkEntity (player);
-
- VectorCopy ( origin, player->client->ps.origin );
- player->client->ps.origin[2] += 1;
-
- // spit the player out
- AngleVectors( angles, player->client->ps.velocity, NULL, NULL );
- VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );
- player->client->ps.pm_time = 160; // hold time
- player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
-
- // toggle the teleport bit so the client knows to not lerp
- player->client->ps.eFlags ^= EF_TELEPORT_BIT;
-
- // set angles
- SetClientViewAngle( player, angles );
-
- // kill anything at the destination
- if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- G_KillBox (player);
- }
-
- // save results of pmove
- BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );
-
- // use the precise origin for linking
- VectorCopy( player->client->ps.origin, player->r.currentOrigin );
-
- if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- trap_LinkEntity (player);
- }
-}
-
-
-/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
-Point teleporters at these.
-Now that we don't have teleport destination pads, this is just
-an info_notnull
-*/
-void SP_misc_teleporter_dest( gentity_t *ent ) {
-}
-
-
-//===========================================================
-
-/*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16)
-"model" arbitrary .md3 file to display
-*/
-void SP_misc_model( gentity_t *ent ) {
-
-#if 0
- ent->s.modelindex = G_ModelIndex( ent->model );
- VectorSet (ent->mins, -16, -16, -16);
- VectorSet (ent->maxs, 16, 16, 16);
- trap_LinkEntity (ent);
-
- G_SetOrigin( ent, ent->s.origin );
- VectorCopy( ent->s.angles, ent->s.apos.trBase );
-#else
- G_FreeEntity( ent );
-#endif
-}
-
-//===========================================================
-
-void locateCamera( gentity_t *ent ) {
- vec3_t dir;
- gentity_t *target;
- gentity_t *owner;
-
- owner = G_PickTarget( ent->target );
- if ( !owner ) {
- G_Printf( "Couldn't find target for misc_partal_surface\n" );
- G_FreeEntity( ent );
- return;
- }
- ent->r.ownerNum = owner->s.number;
-
- // frame holds the rotate speed
- if ( owner->spawnflags & 1 ) {
- ent->s.frame = 25;
- } else if ( owner->spawnflags & 2 ) {
- ent->s.frame = 75;
- }
-
- // swing camera ?
- if ( owner->spawnflags & 4 ) {
- // set to 0 for no rotation at all
- ent->s.powerups = 0;
- }
- else {
- ent->s.powerups = 1;
- }
-
- // clientNum holds the rotate offset
- ent->s.clientNum = owner->s.clientNum;
-
- VectorCopy( owner->s.origin, ent->s.origin2 );
-
- // see if the portal_camera has a target
- target = G_PickTarget( owner->target );
- if ( target ) {
- VectorSubtract( target->s.origin, owner->s.origin, dir );
- VectorNormalize( dir );
- } else {
- G_SetMovedir( owner->s.angles, dir );
- }
-
- ent->s.eventParm = DirToByte( dir );
-}
-
-/*QUAKED misc_portal_surface (0 0 1) (-8 -8 -8) (8 8 8)
-The portal surface nearest this entity will show a view from the targeted misc_portal_camera, or a mirror view if untargeted.
-This must be within 64 world units of the surface!
-*/
-void SP_misc_portal_surface(gentity_t *ent) {
- VectorClear( ent->r.mins );
- VectorClear( ent->r.maxs );
- trap_LinkEntity (ent);
-
- ent->r.svFlags = SVF_PORTAL;
- ent->s.eType = ET_PORTAL;
-
- if ( !ent->target ) {
- VectorCopy( ent->s.origin, ent->s.origin2 );
- } else {
- ent->think = locateCamera;
- ent->nextthink = level.time + 100;
- }
-}
-
-/*QUAKED misc_portal_camera (0 0 1) (-8 -8 -8) (8 8 8) slowrotate fastrotate noswing
-The target for a misc_portal_director. You can set either angles or target another entity to determine the direction of view.
-"roll" an angle modifier to orient the camera around the target vector;
-*/
-void SP_misc_portal_camera(gentity_t *ent) {
- float roll;
-
- VectorClear( ent->r.mins );
- VectorClear( ent->r.maxs );
- trap_LinkEntity (ent);
-
- G_SpawnFloat( "roll", "0", &roll );
-
- ent->s.clientNum = roll/360.0 * 256;
-}
-
-/*
-======================================================================
-
- SHOOTERS
-
-======================================================================
-*/
-
-void Use_Shooter( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
- vec3_t dir;
- float deg;
- vec3_t up, right;
-
- // see if we have a target
- if ( ent->enemy ) {
- VectorSubtract( ent->enemy->r.currentOrigin, ent->s.origin, dir );
- VectorNormalize( dir );
- } else {
- VectorCopy( ent->movedir, dir );
- }
-
- // randomize a bit
- PerpendicularVector( up, dir );
- CrossProduct( up, dir, right );
-
- deg = crandom() * ent->random;
- VectorMA( dir, deg, up, dir );
-
- deg = crandom() * ent->random;
- VectorMA( dir, deg, right, dir );
-
- VectorNormalize( dir );
-
- switch ( ent->s.weapon ) {
- case WP_GRENADE_LAUNCHER:
- fire_grenade( ent, ent->s.origin, dir );
- break;
- case WP_ROCKET_LAUNCHER:
- fire_rocket( ent, ent->s.origin, dir );
- break;
- case WP_PLASMAGUN:
- fire_plasma( ent, ent->s.origin, dir );
- break;
- }
-
- G_AddEvent( ent, EV_FIRE_WEAPON, 0 );
-}
-
-
-static void InitShooter_Finish( gentity_t *ent ) {
- ent->enemy = G_PickTarget( ent->target );
- ent->think = 0;
- ent->nextthink = 0;
-}
-
-void InitShooter( gentity_t *ent, int weapon ) {
- ent->use = Use_Shooter;
- ent->s.weapon = weapon;
-
- RegisterItem( BG_FindItemForWeapon( weapon ) );
-
- G_SetMovedir( ent->s.angles, ent->movedir );
-
- if ( !ent->random ) {
- ent->random = 1.0;
- }
- ent->random = sin( M_PI * ent->random / 180 );
- // target might be a moving object, so we can't set movedir for it
- if ( ent->target ) {
- ent->think = InitShooter_Finish;
- ent->nextthink = level.time + 500;
- }
- trap_LinkEntity( ent );
-}
-
-/*QUAKED shooter_rocket (1 0 0) (-16 -16 -16) (16 16 16)
-Fires at either the target or the current direction.
-"random" the number of degrees of deviance from the taget. (1.0 default)
-*/
-void SP_shooter_rocket( gentity_t *ent ) {
- InitShooter( ent, WP_ROCKET_LAUNCHER );
-}
-
-/*QUAKED shooter_plasma (1 0 0) (-16 -16 -16) (16 16 16)
-Fires at either the target or the current direction.
-"random" is the number of degrees of deviance from the taget. (1.0 default)
-*/
-void SP_shooter_plasma( gentity_t *ent ) {
- InitShooter( ent, WP_PLASMAGUN);
-}
-
-/*QUAKED shooter_grenade (1 0 0) (-16 -16 -16) (16 16 16)
-Fires at either the target or the current direction.
-"random" is the number of degrees of deviance from the taget. (1.0 default)
-*/
-void SP_shooter_grenade( gentity_t *ent ) {
- InitShooter( ent, WP_GRENADE_LAUNCHER);
-}
-
-
-#ifdef MISSIONPACK
-static void PortalDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod) {
- G_FreeEntity( self );
- //FIXME do something more interesting
-}
-
-
-void DropPortalDestination( gentity_t *player ) {
- gentity_t *ent;
- vec3_t snapped;
-
- // create the portal destination
- ent = G_Spawn();
- ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_exit.md3" );
-
- VectorCopy( player->s.pos.trBase, snapped );
- SnapVector( snapped );
- G_SetOrigin( ent, snapped );
- VectorCopy( player->r.mins, ent->r.mins );
- VectorCopy( player->r.maxs, ent->r.maxs );
-
- ent->classname = "hi_portal destination";
- ent->s.pos.trType = TR_STATIONARY;
-
- ent->r.contents = CONTENTS_CORPSE;
- ent->takedamage = qtrue;
- ent->health = 200;
- ent->die = PortalDie;
-
- VectorCopy( player->s.apos.trBase, ent->s.angles );
-
- ent->think = G_FreeEntity;
- ent->nextthink = level.time + 2 * 60 * 1000;
-
- trap_LinkEntity( ent );
-
- player->client->portalID = ++level.portalSequence;
- ent->count = player->client->portalID;
-
- // give the item back so they can drop the source now
- player->client->ps.stats[STAT_HOLDABLE_ITEM] = BG_FindItem( "Portal" ) - bg_itemlist;
-}
-
-
-static void PortalTouch( gentity_t *self, gentity_t *other, trace_t *trace) {
- gentity_t *destination;
-
- // see if we will even let other try to use it
- if( other->health <= 0 ) {
- return;
- }
- if( !other->client ) {
- return;
- }
-// if( other->client->ps.persistant[PERS_TEAM] != self->spawnflags ) {
-// return;
-// }
-
- if ( other->client->ps.powerups[PW_NEUTRALFLAG] ) { // only happens in One Flag CTF
- Drop_Item( other, BG_FindItemForPowerup( PW_NEUTRALFLAG ), 0 );
- other->client->ps.powerups[PW_NEUTRALFLAG] = 0;
- }
- else if ( other->client->ps.powerups[PW_REDFLAG] ) { // only happens in standard CTF
- Drop_Item( other, BG_FindItemForPowerup( PW_REDFLAG ), 0 );
- other->client->ps.powerups[PW_REDFLAG] = 0;
- }
- else if ( other->client->ps.powerups[PW_BLUEFLAG] ) { // only happens in standard CTF
- Drop_Item( other, BG_FindItemForPowerup( PW_BLUEFLAG ), 0 );
- other->client->ps.powerups[PW_BLUEFLAG] = 0;
- }
-
- // find the destination
- destination = NULL;
- while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
- if( destination->count == self->count ) {
- break;
- }
- }
-
- // if there is not one, die!
- if( !destination ) {
- if( self->pos1[0] || self->pos1[1] || self->pos1[2] ) {
- TeleportPlayer( other, self->pos1, self->s.angles );
- }
- G_Damage( other, other, other, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG );
- return;
- }
-
- TeleportPlayer( other, destination->s.pos.trBase, destination->s.angles );
-}
-
-
-static void PortalEnable( gentity_t *self ) {
- self->touch = PortalTouch;
- self->think = G_FreeEntity;
- self->nextthink = level.time + 2 * 60 * 1000;
-}
-
-
-void DropPortalSource( gentity_t *player ) {
- gentity_t *ent;
- gentity_t *destination;
- vec3_t snapped;
-
- // create the portal source
- ent = G_Spawn();
- ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_enter.md3" );
-
- VectorCopy( player->s.pos.trBase, snapped );
- SnapVector( snapped );
- G_SetOrigin( ent, snapped );
- VectorCopy( player->r.mins, ent->r.mins );
- VectorCopy( player->r.maxs, ent->r.maxs );
-
- ent->classname = "hi_portal source";
- ent->s.pos.trType = TR_STATIONARY;
-
- ent->r.contents = CONTENTS_CORPSE | CONTENTS_TRIGGER;
- ent->takedamage = qtrue;
- ent->health = 200;
- ent->die = PortalDie;
-
- trap_LinkEntity( ent );
-
- ent->count = player->client->portalID;
- player->client->portalID = 0;
-
-// ent->spawnflags = player->client->ps.persistant[PERS_TEAM];
-
- ent->nextthink = level.time + 1000;
- ent->think = PortalEnable;
-
- // find the destination
- destination = NULL;
- while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
- if( destination->count == ent->count ) {
- VectorCopy( destination->s.pos.trBase, ent->pos1 );
- break;
- }
- }
-
-}
-#endif
diff --git a/engine/code/game/g_missile.c b/engine/code/game/g_missile.c
deleted file mode 100644
index fbf21e4..0000000
--- a/engine/code/game/g_missile.c
+++ /dev/null
@@ -1,808 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-#define MISSILE_PRESTEP_TIME 50
-
-/*
-================
-G_BounceMissile
-
-================
-*/
-void G_BounceMissile( gentity_t *ent, trace_t *trace ) {
- vec3_t velocity;
- float dot;
- int hitTime;
-
- // reflect the velocity on the trace plane
- hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
- BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
- dot = DotProduct( velocity, trace->plane.normal );
- VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );
-
- if ( ent->s.eFlags & EF_BOUNCE_HALF ) {
- VectorScale( ent->s.pos.trDelta, 0.65, ent->s.pos.trDelta );
- // check for stop
- if ( trace->plane.normal[2] > 0.2 && VectorLength( ent->s.pos.trDelta ) < 40 ) {
- G_SetOrigin( ent, trace->endpos );
- return;
- }
- }
-
- VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
- VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
- ent->s.pos.trTime = level.time;
-}
-
-
-/*
-================
-G_ExplodeMissile
-
-Explode a missile without an impact
-================
-*/
-void G_ExplodeMissile( gentity_t *ent ) {
- vec3_t dir;
- vec3_t origin;
-
- BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
- SnapVector( origin );
- G_SetOrigin( ent, origin );
-
- // we don't have a valid direction, so just point straight up
- dir[0] = dir[1] = 0;
- dir[2] = 1;
-
- ent->s.eType = ET_GENERAL;
- G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );
-
- ent->freeAfterEvent = qtrue;
-
- // splash damage
- if ( ent->splashDamage ) {
- if( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent
- , ent->splashMethodOfDeath ) ) {
- g_entities[ent->r.ownerNum].client->accuracy_hits++;
- }
- }
-
- trap_LinkEntity( ent );
-}
-
-
-#ifdef MISSIONPACK
-/*
-================
-ProximityMine_Explode
-================
-*/
-static void ProximityMine_Explode( gentity_t *mine ) {
- G_ExplodeMissile( mine );
- // if the prox mine has a trigger free it
- if (mine->activator) {
- G_FreeEntity(mine->activator);
- mine->activator = NULL;
- }
-}
-
-/*
-================
-ProximityMine_Die
-================
-*/
-static void ProximityMine_Die( gentity_t *ent, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) {
- ent->think = ProximityMine_Explode;
- ent->nextthink = level.time + 1;
-}
-
-/*
-================
-ProximityMine_Trigger
-================
-*/
-void ProximityMine_Trigger( gentity_t *trigger, gentity_t *other, trace_t *trace ) {
- vec3_t v;
- gentity_t *mine;
-
- if( !other->client ) {
- return;
- }
-
- // trigger is a cube, do a distance test now to act as if it's a sphere
- VectorSubtract( trigger->s.pos.trBase, other->s.pos.trBase, v );
- if( VectorLength( v ) > trigger->parent->splashRadius ) {
- return;
- }
-
-
- if ( g_gametype.integer >= GT_TEAM ) {
- // don't trigger same team mines
- if (trigger->parent->s.generic1 == other->client->sess.sessionTeam) {
- return;
- }
- }
-
- // ok, now check for ability to damage so we don't get triggered thru walls, closed doors, etc...
- if( !CanDamage( other, trigger->s.pos.trBase ) ) {
- return;
- }
-
- // trigger the mine!
- mine = trigger->parent;
- mine->s.loopSound = 0;
- G_AddEvent( mine, EV_PROXIMITY_MINE_TRIGGER, 0 );
- mine->nextthink = level.time + 500;
-
- G_FreeEntity( trigger );
-}
-
-/*
-================
-ProximityMine_Activate
-================
-*/
-static void ProximityMine_Activate( gentity_t *ent ) {
- gentity_t *trigger;
- float r;
-
- ent->think = ProximityMine_Explode;
- ent->nextthink = level.time + g_proxMineTimeout.integer;
-
- ent->takedamage = qtrue;
- ent->health = 1;
- ent->die = ProximityMine_Die;
-
- ent->s.loopSound = G_SoundIndex( "sound/weapons/proxmine/wstbtick.wav" );
-
- // build the proximity trigger
- trigger = G_Spawn ();
-
- trigger->classname = "proxmine_trigger";
-
- r = ent->splashRadius;
- VectorSet( trigger->r.mins, -r, -r, -r );
- VectorSet( trigger->r.maxs, r, r, r );
-
- G_SetOrigin( trigger, ent->s.pos.trBase );
-
- trigger->parent = ent;
- trigger->r.contents = CONTENTS_TRIGGER;
- trigger->touch = ProximityMine_Trigger;
-
- trap_LinkEntity (trigger);
-
- // set pointer to trigger so the entity can be freed when the mine explodes
- ent->activator = trigger;
-}
-
-/*
-================
-ProximityMine_ExplodeOnPlayer
-================
-*/
-static void ProximityMine_ExplodeOnPlayer( gentity_t *mine ) {
- gentity_t *player;
-
- player = mine->enemy;
- player->client->ps.eFlags &= ~EF_TICKING;
-
- if ( player->client->invulnerabilityTime > level.time ) {
- G_Damage( player, mine->parent, mine->parent, vec3_origin, mine->s.origin, 1000, DAMAGE_NO_KNOCKBACK, MOD_JUICED );
- player->client->invulnerabilityTime = 0;
- G_TempEntity( player->client->ps.origin, EV_JUICED );
- }
- else {
- G_SetOrigin( mine, player->s.pos.trBase );
- // make sure the explosion gets to the client
- mine->r.svFlags &= ~SVF_NOCLIENT;
- mine->splashMethodOfDeath = MOD_PROXIMITY_MINE;
- G_ExplodeMissile( mine );
- }
-}
-
-/*
-================
-ProximityMine_Player
-================
-*/
-static void ProximityMine_Player( gentity_t *mine, gentity_t *player ) {
- if( mine->s.eFlags & EF_NODRAW ) {
- return;
- }
-
- G_AddEvent( mine, EV_PROXIMITY_MINE_STICK, 0 );
-
- if( player->s.eFlags & EF_TICKING ) {
- player->activator->splashDamage += mine->splashDamage;
- player->activator->splashRadius *= 1.50;
- mine->think = G_FreeEntity;
- mine->nextthink = level.time;
- return;
- }
-
- player->client->ps.eFlags |= EF_TICKING;
- player->activator = mine;
-
- mine->s.eFlags |= EF_NODRAW;
- mine->r.svFlags |= SVF_NOCLIENT;
- mine->s.pos.trType = TR_LINEAR;
- VectorClear( mine->s.pos.trDelta );
-
- mine->enemy = player;
- mine->think = ProximityMine_ExplodeOnPlayer;
- if ( player->client->invulnerabilityTime > level.time ) {
- mine->nextthink = level.time + 2 * 1000;
- }
- else {
- mine->nextthink = level.time + 10 * 1000;
- }
-}
-#endif
-
-/*
-================
-G_MissileImpact
-================
-*/
-void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
- gentity_t *other;
- qboolean hitClient = qfalse;
-#ifdef MISSIONPACK
- vec3_t forward, impactpoint, bouncedir;
- int eFlags;
-#endif
- other = &g_entities[trace->entityNum];
-
- // check for bounce
- if ( !other->takedamage &&
- ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) ) {
- G_BounceMissile( ent, trace );
- G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
- return;
- }
-
-#ifdef MISSIONPACK
- if ( other->takedamage ) {
- if ( ent->s.weapon != WP_PROX_LAUNCHER ) {
- if ( other->client && other->client->invulnerabilityTime > level.time ) {
- //
- VectorCopy( ent->s.pos.trDelta, forward );
- VectorNormalize( forward );
- if (G_InvulnerabilityEffect( other, forward, ent->s.pos.trBase, impactpoint, bouncedir )) {
- VectorCopy( bouncedir, trace->plane.normal );
- eFlags = ent->s.eFlags & EF_BOUNCE_HALF;
- ent->s.eFlags &= ~EF_BOUNCE_HALF;
- G_BounceMissile( ent, trace );
- ent->s.eFlags |= eFlags;
- }
- ent->target_ent = other;
- return;
- }
- }
- }
-#endif
- // impact damage
- if (other->takedamage) {
- // FIXME: wrong damage direction?
- if ( ent->damage ) {
- vec3_t velocity;
-
- if( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) {
- g_entities[ent->r.ownerNum].client->accuracy_hits++;
- hitClient = qtrue;
- }
- BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
- if ( VectorLength( velocity ) == 0 ) {
- velocity[2] = 1; // stepped on a grenade
- }
- G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
- ent->s.origin, ent->damage,
- 0, ent->methodOfDeath);
- }
- }
-
-#ifdef MISSIONPACK
- if( ent->s.weapon == WP_PROX_LAUNCHER ) {
- if( ent->s.pos.trType != TR_GRAVITY ) {
- return;
- }
-
- // if it's a player, stick it on to them (flag them and remove this entity)
- if( other->s.eType == ET_PLAYER && other->health > 0 ) {
- ProximityMine_Player( ent, other );
- return;
- }
-
- SnapVectorTowards( trace->endpos, ent->s.pos.trBase );
- G_SetOrigin( ent, trace->endpos );
- ent->s.pos.trType = TR_STATIONARY;
- VectorClear( ent->s.pos.trDelta );
-
- G_AddEvent( ent, EV_PROXIMITY_MINE_STICK, trace->surfaceFlags );
-
- ent->think = ProximityMine_Activate;
- ent->nextthink = level.time + 2000;
-
- vectoangles( trace->plane.normal, ent->s.angles );
- ent->s.angles[0] += 90;
-
- // link the prox mine to the other entity
- ent->enemy = other;
- ent->die = ProximityMine_Die;
- VectorCopy(trace->plane.normal, ent->movedir);
- VectorSet(ent->r.mins, -4, -4, -4);
- VectorSet(ent->r.maxs, 4, 4, 4);
- trap_LinkEntity(ent);
-
- return;
- }
-#endif
-
- if (!strcmp(ent->classname, "hook")) {
- gentity_t *nent;
- vec3_t v;
-
- nent = G_Spawn();
- if ( other->takedamage && other->client ) {
-
- G_AddEvent( nent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
- nent->s.otherEntityNum = other->s.number;
-
- ent->enemy = other;
-
- v[0] = other->r.currentOrigin[0] + (other->r.mins[0] + other->r.maxs[0]) * 0.5;
- v[1] = other->r.currentOrigin[1] + (other->r.mins[1] + other->r.maxs[1]) * 0.5;
- v[2] = other->r.currentOrigin[2] + (other->r.mins[2] + other->r.maxs[2]) * 0.5;
-
- SnapVectorTowards( v, ent->s.pos.trBase ); // save net bandwidth
- } else {
- VectorCopy(trace->endpos, v);
- G_AddEvent( nent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
- ent->enemy = NULL;
- }
-
- SnapVectorTowards( v, ent->s.pos.trBase ); // save net bandwidth
-
- nent->freeAfterEvent = qtrue;
- // change over to a normal entity right at the point of impact
- nent->s.eType = ET_GENERAL;
- ent->s.eType = ET_GRAPPLE;
-
- G_SetOrigin( ent, v );
- G_SetOrigin( nent, v );
-
- ent->think = Weapon_HookThink;
- ent->nextthink = level.time + FRAMETIME;
-
- ent->parent->client->ps.pm_flags |= PMF_GRAPPLE_PULL;
- VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);
-
- trap_LinkEntity( ent );
- trap_LinkEntity( nent );
-
- return;
- }
-
- // is it cheaper in bandwidth to just remove this ent and create a new
- // one, rather than changing the missile into the explosion?
-
- if ( other->takedamage && other->client ) {
- G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
- ent->s.otherEntityNum = other->s.number;
- } else if( trace->surfaceFlags & SURF_METALSTEPS ) {
- G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
- } else {
- G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
- }
-
- ent->freeAfterEvent = qtrue;
-
- // change over to a normal entity right at the point of impact
- ent->s.eType = ET_GENERAL;
-
- SnapVectorTowards( trace->endpos, ent->s.pos.trBase ); // save net bandwidth
-
- G_SetOrigin( ent, trace->endpos );
-
- // splash damage (doesn't apply to person directly hit)
- if ( ent->splashDamage ) {
- if( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
- other, ent->splashMethodOfDeath ) ) {
- if( !hitClient ) {
- g_entities[ent->r.ownerNum].client->accuracy_hits++;
- }
- }
- }
-
- trap_LinkEntity( ent );
-}
-
-/*
-================
-G_RunMissile
-================
-*/
-void G_RunMissile( gentity_t *ent ) {
- vec3_t origin;
- trace_t tr;
- int passent;
-
- // get current position
- BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
-
- // if this missile bounced off an invulnerability sphere
- if ( ent->target_ent ) {
- passent = ent->target_ent->s.number;
- }
-#ifdef MISSIONPACK
- // prox mines that left the owner bbox will attach to anything, even the owner
- else if (ent->s.weapon == WP_PROX_LAUNCHER && ent->count) {
- passent = ENTITYNUM_NONE;
- }
-#endif
- else {
- // ignore interactions with the missile owner
- passent = ent->r.ownerNum;
- }
- // trace a line from the previous position to the current position
- trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );
-
- if ( tr.startsolid || tr.allsolid ) {
- // make sure the tr.entityNum is set to the entity we're stuck in
- trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask );
- tr.fraction = 0;
- }
- else {
- VectorCopy( tr.endpos, ent->r.currentOrigin );
- }
-
- trap_LinkEntity( ent );
-
- if ( tr.fraction != 1 ) {
- // never explode or bounce on sky
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- // If grapple, reset owner
- if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {
- ent->parent->client->hook = NULL;
- }
- G_FreeEntity( ent );
- return;
- }
- G_MissileImpact( ent, &tr );
- if ( ent->s.eType != ET_MISSILE ) {
- return; // exploded
- }
- }
-#ifdef MISSIONPACK
- // if the prox mine wasn't yet outside the player body
- if (ent->s.weapon == WP_PROX_LAUNCHER && !ent->count) {
- // check if the prox mine is outside the owner bbox
- trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, ENTITYNUM_NONE, ent->clipmask );
- if (!tr.startsolid || tr.entityNum != ent->r.ownerNum) {
- ent->count = 1;
- }
- }
-#endif
- // check think function after bouncing
- G_RunThink( ent );
-}
-
-
-//=============================================================================
-
-/*
-=================
-fire_plasma
-
-=================
-*/
-gentity_t *fire_plasma (gentity_t *self, vec3_t start, vec3_t dir) {
- gentity_t *bolt;
-
- VectorNormalize (dir);
-
- bolt = G_Spawn();
- bolt->classname = "plasma";
- bolt->nextthink = level.time + 10000;
- bolt->think = G_ExplodeMissile;
- bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- bolt->s.weapon = WP_PLASMAGUN;
- bolt->r.ownerNum = self->s.number;
- bolt->parent = self;
- bolt->damage = 20;
- bolt->splashDamage = 15;
- bolt->splashRadius = 20;
- bolt->methodOfDeath = MOD_PLASMA;
- bolt->splashMethodOfDeath = MOD_PLASMA_SPLASH;
- bolt->clipmask = MASK_SHOT;
- bolt->target_ent = NULL;
-
- bolt->s.pos.trType = TR_LINEAR;
- bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
- VectorCopy( start, bolt->s.pos.trBase );
- VectorScale( dir, 2000, bolt->s.pos.trDelta );
- SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
-
- VectorCopy (start, bolt->r.currentOrigin);
-
- return bolt;
-}
-
-//=============================================================================
-
-
-/*
-=================
-fire_grenade
-=================
-*/
-gentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t dir) {
- gentity_t *bolt;
-
- VectorNormalize (dir);
-
- bolt = G_Spawn();
- bolt->classname = "grenade";
- bolt->nextthink = level.time + 2500;
- bolt->think = G_ExplodeMissile;
- bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- bolt->s.weapon = WP_GRENADE_LAUNCHER;
- bolt->s.eFlags = EF_BOUNCE_HALF;
- bolt->r.ownerNum = self->s.number;
- bolt->parent = self;
- bolt->damage = 100;
- bolt->splashDamage = 100;
- bolt->splashRadius = 150;
- bolt->methodOfDeath = MOD_GRENADE;
- bolt->splashMethodOfDeath = MOD_GRENADE_SPLASH;
- bolt->clipmask = MASK_SHOT;
- bolt->target_ent = NULL;
-
- bolt->s.pos.trType = TR_GRAVITY;
- bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
- VectorCopy( start, bolt->s.pos.trBase );
- VectorScale( dir, 700, bolt->s.pos.trDelta );
- SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
-
- VectorCopy (start, bolt->r.currentOrigin);
-
- return bolt;
-}
-
-//=============================================================================
-
-
-/*
-=================
-fire_bfg
-=================
-*/
-gentity_t *fire_bfg (gentity_t *self, vec3_t start, vec3_t dir) {
- gentity_t *bolt;
-
- VectorNormalize (dir);
-
- bolt = G_Spawn();
- bolt->classname = "bfg";
- bolt->nextthink = level.time + 10000;
- bolt->think = G_ExplodeMissile;
- bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- bolt->s.weapon = WP_BFG;
- bolt->r.ownerNum = self->s.number;
- bolt->parent = self;
- bolt->damage = 100;
- bolt->splashDamage = 100;
- bolt->splashRadius = 120;
- bolt->methodOfDeath = MOD_BFG;
- bolt->splashMethodOfDeath = MOD_BFG_SPLASH;
- bolt->clipmask = MASK_SHOT;
- bolt->target_ent = NULL;
-
- bolt->s.pos.trType = TR_LINEAR;
- bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
- VectorCopy( start, bolt->s.pos.trBase );
- VectorScale( dir, 2000, bolt->s.pos.trDelta );
- SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
- VectorCopy (start, bolt->r.currentOrigin);
-
- return bolt;
-}
-
-//=============================================================================
-
-
-/*
-=================
-fire_rocket
-=================
-*/
-gentity_t *fire_rocket (gentity_t *self, vec3_t start, vec3_t dir) {
- gentity_t *bolt;
-
- VectorNormalize (dir);
-
- bolt = G_Spawn();
- bolt->classname = "rocket";
- bolt->nextthink = level.time + 15000;
- bolt->think = G_ExplodeMissile;
- bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- bolt->s.weapon = WP_ROCKET_LAUNCHER;
- bolt->r.ownerNum = self->s.number;
- bolt->parent = self;
- bolt->damage = 100;
- bolt->splashDamage = 100;
- bolt->splashRadius = 120;
- bolt->methodOfDeath = MOD_ROCKET;
- bolt->splashMethodOfDeath = MOD_ROCKET_SPLASH;
- bolt->clipmask = MASK_SHOT;
- bolt->target_ent = NULL;
-
- bolt->s.pos.trType = TR_LINEAR;
- bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
- VectorCopy( start, bolt->s.pos.trBase );
- VectorScale( dir, 900, bolt->s.pos.trDelta );
- SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
- VectorCopy (start, bolt->r.currentOrigin);
-
- return bolt;
-}
-
-/*
-=================
-fire_grapple
-=================
-*/
-gentity_t *fire_grapple (gentity_t *self, vec3_t start, vec3_t dir) {
- gentity_t *hook;
-
- VectorNormalize (dir);
-
- hook = G_Spawn();
- hook->classname = "hook";
- hook->nextthink = level.time + 10000;
- hook->think = Weapon_HookFree;
- hook->s.eType = ET_MISSILE;
- hook->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- hook->s.weapon = WP_GRAPPLING_HOOK;
- hook->r.ownerNum = self->s.number;
- hook->methodOfDeath = MOD_GRAPPLE;
- hook->clipmask = MASK_SHOT;
- hook->parent = self;
- hook->target_ent = NULL;
-
- hook->s.pos.trType = TR_LINEAR;
- hook->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
- hook->s.otherEntityNum = self->s.number; // use to match beam in client
- VectorCopy( start, hook->s.pos.trBase );
- VectorScale( dir, 800, hook->s.pos.trDelta );
- SnapVector( hook->s.pos.trDelta ); // save net bandwidth
- VectorCopy (start, hook->r.currentOrigin);
-
- self->client->hook = hook;
-
- return hook;
-}
-
-
-#ifdef MISSIONPACK
-/*
-=================
-fire_nail
-=================
-*/
-#define NAILGUN_SPREAD 500
-
-gentity_t *fire_nail( gentity_t *self, vec3_t start, vec3_t forward, vec3_t right, vec3_t up ) {
- gentity_t *bolt;
- vec3_t dir;
- vec3_t end;
- float r, u, scale;
-
- bolt = G_Spawn();
- bolt->classname = "nail";
- bolt->nextthink = level.time + 10000;
- bolt->think = G_ExplodeMissile;
- bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- bolt->s.weapon = WP_NAILGUN;
- bolt->r.ownerNum = self->s.number;
- bolt->parent = self;
- bolt->damage = 20;
- bolt->methodOfDeath = MOD_NAIL;
- bolt->clipmask = MASK_SHOT;
- bolt->target_ent = NULL;
-
- bolt->s.pos.trType = TR_LINEAR;
- bolt->s.pos.trTime = level.time;
- VectorCopy( start, bolt->s.pos.trBase );
-
- r = random() * M_PI * 2.0f;
- u = sin(r) * crandom() * NAILGUN_SPREAD * 16;
- r = cos(r) * crandom() * NAILGUN_SPREAD * 16;
- VectorMA( start, 8192 * 16, forward, end);
- VectorMA (end, r, right, end);
- VectorMA (end, u, up, end);
- VectorSubtract( end, start, dir );
- VectorNormalize( dir );
-
- scale = 555 + random() * 1800;
- VectorScale( dir, scale, bolt->s.pos.trDelta );
- SnapVector( bolt->s.pos.trDelta );
-
- VectorCopy( start, bolt->r.currentOrigin );
-
- return bolt;
-}
-
-
-/*
-=================
-fire_prox
-=================
-*/
-gentity_t *fire_prox( gentity_t *self, vec3_t start, vec3_t dir ) {
- gentity_t *bolt;
-
- VectorNormalize (dir);
-
- bolt = G_Spawn();
- bolt->classname = "prox mine";
- bolt->nextthink = level.time + 3000;
- bolt->think = G_ExplodeMissile;
- bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- bolt->s.weapon = WP_PROX_LAUNCHER;
- bolt->s.eFlags = 0;
- bolt->r.ownerNum = self->s.number;
- bolt->parent = self;
- bolt->damage = 0;
- bolt->splashDamage = 100;
- bolt->splashRadius = 150;
- bolt->methodOfDeath = MOD_PROXIMITY_MINE;
- bolt->splashMethodOfDeath = MOD_PROXIMITY_MINE;
- bolt->clipmask = MASK_SHOT;
- bolt->target_ent = NULL;
- // count is used to check if the prox mine left the player bbox
- // if count == 1 then the prox mine left the player bbox and can attack to it
- bolt->count = 0;
-
- //FIXME: we prolly wanna abuse another field
- bolt->s.generic1 = self->client->sess.sessionTeam;
-
- bolt->s.pos.trType = TR_GRAVITY;
- bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
- VectorCopy( start, bolt->s.pos.trBase );
- VectorScale( dir, 700, bolt->s.pos.trDelta );
- SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
-
- VectorCopy (start, bolt->r.currentOrigin);
-
- return bolt;
-}
-#endif
diff --git a/engine/code/game/g_mover.c b/engine/code/game/g_mover.c
deleted file mode 100644
index 63bd54b..0000000
--- a/engine/code/game/g_mover.c
+++ /dev/null
@@ -1,1631 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-#include "g_local.h"
-
-
-
-/*
-===============================================================================
-
-PUSHMOVE
-
-===============================================================================
-*/
-
-void MatchTeam( gentity_t *teamLeader, int moverState, int time );
-
-typedef struct {
- gentity_t *ent;
- vec3_t origin;
- vec3_t angles;
- float deltayaw;
-} pushed_t;
-pushed_t pushed[MAX_GENTITIES], *pushed_p;
-
-
-/*
-============
-G_TestEntityPosition
-
-============
-*/
-gentity_t *G_TestEntityPosition( gentity_t *ent ) {
- trace_t tr;
- int mask;
-
- if ( ent->clipmask ) {
- mask = ent->clipmask;
- } else {
- mask = MASK_SOLID;
- }
- if ( ent->client ) {
- trap_Trace( &tr, ent->client->ps.origin, ent->r.mins, ent->r.maxs, ent->client->ps.origin, ent->s.number, mask );
- } else {
- trap_Trace( &tr, ent->s.pos.trBase, ent->r.mins, ent->r.maxs, ent->s.pos.trBase, ent->s.number, mask );
- }
-
- if (tr.startsolid)
- return &g_entities[ tr.entityNum ];
-
- return NULL;
-}
-
-/*
-================
-G_CreateRotationMatrix
-================
-*/
-void G_CreateRotationMatrix(vec3_t angles, vec3_t matrix[3]) {
- AngleVectors(angles, matrix[0], matrix[1], matrix[2]);
- VectorInverse(matrix[1]);
-}
-
-/*
-================
-G_TransposeMatrix
-================
-*/
-void G_TransposeMatrix(vec3_t matrix[3], vec3_t transpose[3]) {
- int i, j;
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 3; j++) {
- transpose[i][j] = matrix[j][i];
- }
- }
-}
-
-/*
-================
-G_RotatePoint
-================
-*/
-void G_RotatePoint(vec3_t point, vec3_t matrix[3]) {
- vec3_t tvec;
-
- VectorCopy(point, tvec);
- point[0] = DotProduct(matrix[0], tvec);
- point[1] = DotProduct(matrix[1], tvec);
- point[2] = DotProduct(matrix[2], tvec);
-}
-
-/*
-==================
-G_TryPushingEntity
-
-Returns qfalse if the move is blocked
-==================
-*/
-qboolean G_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, vec3_t amove ) {
- vec3_t matrix[3], transpose[3];
- vec3_t org, org2, move2;
- gentity_t *block;
-
- // EF_MOVER_STOP will just stop when contacting another entity
- // instead of pushing it, but entities can still ride on top of it
- if ( ( pusher->s.eFlags & EF_MOVER_STOP ) &&
- check->s.groundEntityNum != pusher->s.number ) {
- return qfalse;
- }
-
- // save off the old position
- if (pushed_p > &pushed[MAX_GENTITIES]) {
- G_Error( "pushed_p > &pushed[MAX_GENTITIES]" );
- }
- pushed_p->ent = check;
- VectorCopy (check->s.pos.trBase, pushed_p->origin);
- VectorCopy (check->s.apos.trBase, pushed_p->angles);
- if ( check->client ) {
- pushed_p->deltayaw = check->client->ps.delta_angles[YAW];
- VectorCopy (check->client->ps.origin, pushed_p->origin);
- }
- pushed_p++;
-
- // try moving the contacted entity
- // figure movement due to the pusher's amove
- G_CreateRotationMatrix( amove, transpose );
- G_TransposeMatrix( transpose, matrix );
- if ( check->client ) {
- VectorSubtract (check->client->ps.origin, pusher->r.currentOrigin, org);
- }
- else {
- VectorSubtract (check->s.pos.trBase, pusher->r.currentOrigin, org);
- }
- VectorCopy( org, org2 );
- G_RotatePoint( org2, matrix );
- VectorSubtract (org2, org, move2);
- // add movement
- VectorAdd (check->s.pos.trBase, move, check->s.pos.trBase);
- VectorAdd (check->s.pos.trBase, move2, check->s.pos.trBase);
- if ( check->client ) {
- VectorAdd (check->client->ps.origin, move, check->client->ps.origin);
- VectorAdd (check->client->ps.origin, move2, check->client->ps.origin);
- // make sure the client's view rotates when on a rotating mover
- check->client->ps.delta_angles[YAW] += ANGLE2SHORT(amove[YAW]);
- }
-
- // may have pushed them off an edge
- if ( check->s.groundEntityNum != pusher->s.number ) {
- check->s.groundEntityNum = -1;
- }
-
- block = G_TestEntityPosition( check );
- if (!block) {
- // pushed ok
- if ( check->client ) {
- VectorCopy( check->client->ps.origin, check->r.currentOrigin );
- } else {
- VectorCopy( check->s.pos.trBase, check->r.currentOrigin );
- }
- trap_LinkEntity (check);
- return qtrue;
- }
-
- // if it is ok to leave in the old position, do it
- // this is only relevent for riding entities, not pushed
- // Sliding trapdoors can cause this.
- VectorCopy( (pushed_p-1)->origin, check->s.pos.trBase);
- if ( check->client ) {
- VectorCopy( (pushed_p-1)->origin, check->client->ps.origin);
- }
- VectorCopy( (pushed_p-1)->angles, check->s.apos.trBase );
- block = G_TestEntityPosition (check);
- if ( !block ) {
- check->s.groundEntityNum = -1;
- pushed_p--;
- return qtrue;
- }
-
- // blocked
- return qfalse;
-}
-
-/*
-==================
-G_CheckProxMinePosition
-==================
-*/
-qboolean G_CheckProxMinePosition( gentity_t *check ) {
- vec3_t start, end;
- trace_t tr;
-
- VectorMA(check->s.pos.trBase, 0.125, check->movedir, start);
- VectorMA(check->s.pos.trBase, 2, check->movedir, end);
- trap_Trace( &tr, start, NULL, NULL, end, check->s.number, MASK_SOLID );
-
- if (tr.startsolid || tr.fraction < 1)
- return qfalse;
-
- return qtrue;
-}
-
-/*
-==================
-G_TryPushingProxMine
-==================
-*/
-qboolean G_TryPushingProxMine( gentity_t *check, gentity_t *pusher, vec3_t move, vec3_t amove ) {
- vec3_t forward, right, up;
- vec3_t org, org2, move2;
- int ret;
-
- // we need this for pushing things later
- VectorSubtract (vec3_origin, amove, org);
- AngleVectors (org, forward, right, up);
-
- // try moving the contacted entity
- VectorAdd (check->s.pos.trBase, move, check->s.pos.trBase);
-
- // figure movement due to the pusher's amove
- VectorSubtract (check->s.pos.trBase, pusher->r.currentOrigin, org);
- org2[0] = DotProduct (org, forward);
- org2[1] = -DotProduct (org, right);
- org2[2] = DotProduct (org, up);
- VectorSubtract (org2, org, move2);
- VectorAdd (check->s.pos.trBase, move2, check->s.pos.trBase);
-
- ret = G_CheckProxMinePosition( check );
- if (ret) {
- VectorCopy( check->s.pos.trBase, check->r.currentOrigin );
- trap_LinkEntity (check);
- }
- return ret;
-}
-
-void G_ExplodeMissile( gentity_t *ent );
-
-/*
-============
-G_MoverPush
-
-Objects need to be moved back on a failed push,
-otherwise riders would continue to slide.
-If qfalse is returned, *obstacle will be the blocking entity
-============
-*/
-qboolean G_MoverPush( gentity_t *pusher, vec3_t move, vec3_t amove, gentity_t **obstacle ) {
- int i, e;
- gentity_t *check;
- vec3_t mins, maxs;
- pushed_t *p;
- int entityList[MAX_GENTITIES];
- int listedEntities;
- vec3_t totalMins, totalMaxs;
-
- *obstacle = NULL;
-
-
- // mins/maxs are the bounds at the destination
- // totalMins / totalMaxs are the bounds for the entire move
- if ( pusher->r.currentAngles[0] || pusher->r.currentAngles[1] || pusher->r.currentAngles[2]
- || amove[0] || amove[1] || amove[2] ) {
- float radius;
-
- radius = RadiusFromBounds( pusher->r.mins, pusher->r.maxs );
- for ( i = 0 ; i < 3 ; i++ ) {
- mins[i] = pusher->r.currentOrigin[i] + move[i] - radius;
- maxs[i] = pusher->r.currentOrigin[i] + move[i] + radius;
- totalMins[i] = mins[i] - move[i];
- totalMaxs[i] = maxs[i] - move[i];
- }
- } else {
- for (i=0 ; i<3 ; i++) {
- mins[i] = pusher->r.absmin[i] + move[i];
- maxs[i] = pusher->r.absmax[i] + move[i];
- }
-
- VectorCopy( pusher->r.absmin, totalMins );
- VectorCopy( pusher->r.absmax, totalMaxs );
- for (i=0 ; i<3 ; i++) {
- if ( move[i] > 0 ) {
- totalMaxs[i] += move[i];
- } else {
- totalMins[i] += move[i];
- }
- }
- }
-
- // unlink the pusher so we don't get it in the entityList
- trap_UnlinkEntity( pusher );
-
- listedEntities = trap_EntitiesInBox( totalMins, totalMaxs, entityList, MAX_GENTITIES );
-
- // move the pusher to it's final position
- VectorAdd( pusher->r.currentOrigin, move, pusher->r.currentOrigin );
- VectorAdd( pusher->r.currentAngles, amove, pusher->r.currentAngles );
- trap_LinkEntity( pusher );
-
- // see if any solid entities are inside the final position
- for ( e = 0 ; e < listedEntities ; e++ ) {
- check = &g_entities[ entityList[ e ] ];
-
-#ifdef MISSIONPACK
- if ( check->s.eType == ET_MISSILE ) {
- // if it is a prox mine
- if ( !strcmp(check->classname, "prox mine") ) {
- // if this prox mine is attached to this mover try to move it with the pusher
- if ( check->enemy == pusher ) {
- if (!G_TryPushingProxMine( check, pusher, move, amove )) {
- //explode
- check->s.loopSound = 0;
- G_AddEvent( check, EV_PROXIMITY_MINE_TRIGGER, 0 );
- G_ExplodeMissile(check);
- if (check->activator) {
- G_FreeEntity(check->activator);
- check->activator = NULL;
- }
- //G_Printf("prox mine explodes\n");
- }
- }
- else {
- //check if the prox mine is crushed by the mover
- if (!G_CheckProxMinePosition( check )) {
- //explode
- check->s.loopSound = 0;
- G_AddEvent( check, EV_PROXIMITY_MINE_TRIGGER, 0 );
- G_ExplodeMissile(check);
- if (check->activator) {
- G_FreeEntity(check->activator);
- check->activator = NULL;
- }
- //G_Printf("prox mine explodes\n");
- }
- }
- continue;
- }
- }
-#endif
- // only push items and players
- if ( check->s.eType != ET_ITEM && check->s.eType != ET_PLAYER && !check->physicsObject ) {
- continue;
- }
-
- // if the entity is standing on the pusher, it will definitely be moved
- if ( check->s.groundEntityNum != pusher->s.number ) {
- // see if the ent needs to be tested
- if ( check->r.absmin[0] >= maxs[0]
- || check->r.absmin[1] >= maxs[1]
- || check->r.absmin[2] >= maxs[2]
- || check->r.absmax[0] <= mins[0]
- || check->r.absmax[1] <= mins[1]
- || check->r.absmax[2] <= mins[2] ) {
- continue;
- }
- // see if the ent's bbox is inside the pusher's final position
- // this does allow a fast moving object to pass through a thin entity...
- if (!G_TestEntityPosition (check)) {
- continue;
- }
- }
-
- // the entity needs to be pushed
- if ( G_TryPushingEntity( check, pusher, move, amove ) ) {
- continue;
- }
-
- // the move was blocked an entity
-
- // bobbing entities are instant-kill and never get blocked
- if ( pusher->s.pos.trType == TR_SINE || pusher->s.apos.trType == TR_SINE ) {
- G_Damage( check, pusher, pusher, NULL, NULL, 99999, 0, MOD_CRUSH );
- continue;
- }
-
-
- // save off the obstacle so we can call the block function (crush, etc)
- *obstacle = check;
-
- // move back any entities we already moved
- // go backwards, so if the same entity was pushed
- // twice, it goes back to the original position
- for ( p=pushed_p-1 ; p>=pushed ; p-- ) {
- VectorCopy (p->origin, p->ent->s.pos.trBase);
- VectorCopy (p->angles, p->ent->s.apos.trBase);
- if ( p->ent->client ) {
- p->ent->client->ps.delta_angles[YAW] = p->deltayaw;
- VectorCopy (p->origin, p->ent->client->ps.origin);
- }
- trap_LinkEntity (p->ent);
- }
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-=================
-G_MoverTeam
-=================
-*/
-void G_MoverTeam( gentity_t *ent ) {
- vec3_t move, amove;
- gentity_t *part, *obstacle;
- vec3_t origin, angles;
-
- obstacle = NULL;
-
- // make sure all team slaves can move before commiting
- // any moves or calling any think functions
- // if the move is blocked, all moved objects will be backed out
- pushed_p = pushed;
- for (part = ent ; part ; part=part->teamchain) {
- // get current position
- BG_EvaluateTrajectory( &part->s.pos, level.time, origin );
- BG_EvaluateTrajectory( &part->s.apos, level.time, angles );
- VectorSubtract( origin, part->r.currentOrigin, move );
- VectorSubtract( angles, part->r.currentAngles, amove );
- if ( !G_MoverPush( part, move, amove, &obstacle ) ) {
- break; // move was blocked
- }
- }
-
- if (part) {
- // go back to the previous position
- for ( part = ent ; part ; part = part->teamchain ) {
- part->s.pos.trTime += level.time - level.previousTime;
- part->s.apos.trTime += level.time - level.previousTime;
- BG_EvaluateTrajectory( &part->s.pos, level.time, part->r.currentOrigin );
- BG_EvaluateTrajectory( &part->s.apos, level.time, part->r.currentAngles );
- trap_LinkEntity( part );
- }
-
- // if the pusher has a "blocked" function, call it
- if (ent->blocked) {
- ent->blocked( ent, obstacle );
- }
- return;
- }
-
- // the move succeeded
- for ( part = ent ; part ; part = part->teamchain ) {
- // call the reached function if time is at or past end point
- if ( part->s.pos.trType == TR_LINEAR_STOP ) {
- if ( level.time >= part->s.pos.trTime + part->s.pos.trDuration ) {
- if ( part->reached ) {
- part->reached( part );
- }
- }
- }
- }
-}
-
-/*
-================
-G_RunMover
-
-================
-*/
-void G_RunMover( gentity_t *ent ) {
- // if not a team captain, don't do anything, because
- // the captain will handle everything
- if ( ent->flags & FL_TEAMSLAVE ) {
- return;
- }
-
- // if stationary at one of the positions, don't move anything
- if ( ent->s.pos.trType != TR_STATIONARY || ent->s.apos.trType != TR_STATIONARY ) {
- G_MoverTeam( ent );
- }
-
- // check think function
- G_RunThink( ent );
-}
-
-/*
-============================================================================
-
-GENERAL MOVERS
-
-Doors, plats, and buttons are all binary (two position) movers
-Pos1 is "at rest", pos2 is "activated"
-============================================================================
-*/
-
-/*
-===============
-SetMoverState
-===============
-*/
-void SetMoverState( gentity_t *ent, moverState_t moverState, int time ) {
- vec3_t delta;
- float f;
-
- ent->moverState = moverState;
-
- ent->s.pos.trTime = time;
- switch( moverState ) {
- case MOVER_POS1:
- VectorCopy( ent->pos1, ent->s.pos.trBase );
- ent->s.pos.trType = TR_STATIONARY;
- break;
- case MOVER_POS2:
- VectorCopy( ent->pos2, ent->s.pos.trBase );
- ent->s.pos.trType = TR_STATIONARY;
- break;
- case MOVER_1TO2:
- VectorCopy( ent->pos1, ent->s.pos.trBase );
- VectorSubtract( ent->pos2, ent->pos1, delta );
- f = 1000.0 / ent->s.pos.trDuration;
- VectorScale( delta, f, ent->s.pos.trDelta );
- ent->s.pos.trType = TR_LINEAR_STOP;
- break;
- case MOVER_2TO1:
- VectorCopy( ent->pos2, ent->s.pos.trBase );
- VectorSubtract( ent->pos1, ent->pos2, delta );
- f = 1000.0 / ent->s.pos.trDuration;
- VectorScale( delta, f, ent->s.pos.trDelta );
- ent->s.pos.trType = TR_LINEAR_STOP;
- break;
- }
- BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin );
- trap_LinkEntity( ent );
-}
-
-/*
-================
-MatchTeam
-
-All entities in a mover team will move from pos1 to pos2
-in the same amount of time
-================
-*/
-void MatchTeam( gentity_t *teamLeader, int moverState, int time ) {
- gentity_t *slave;
-
- for ( slave = teamLeader ; slave ; slave = slave->teamchain ) {
- SetMoverState( slave, moverState, time );
- }
-}
-
-
-
-/*
-================
-ReturnToPos1
-================
-*/
-void ReturnToPos1( gentity_t *ent ) {
- MatchTeam( ent, MOVER_2TO1, level.time );
-
- // looping sound
- ent->s.loopSound = ent->soundLoop;
-
- // starting sound
- if ( ent->sound2to1 ) {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
- }
-}
-
-
-/*
-================
-Reached_BinaryMover
-================
-*/
-void Reached_BinaryMover( gentity_t *ent ) {
-
- // stop the looping sound
- ent->s.loopSound = ent->soundLoop;
-
- if ( ent->moverState == MOVER_1TO2 ) {
- // reached pos2
- SetMoverState( ent, MOVER_POS2, level.time );
-
- // play sound
- if ( ent->soundPos2 ) {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos2 );
- }
-
- // return to pos1 after a delay
- ent->think = ReturnToPos1;
- ent->nextthink = level.time + ent->wait;
-
- // fire targets
- if ( !ent->activator ) {
- ent->activator = ent;
- }
- G_UseTargets( ent, ent->activator );
- } else if ( ent->moverState == MOVER_2TO1 ) {
- // reached pos1
- SetMoverState( ent, MOVER_POS1, level.time );
-
- // play sound
- if ( ent->soundPos1 ) {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos1 );
- }
-
- // close areaportals
- if ( ent->teammaster == ent || !ent->teammaster ) {
- trap_AdjustAreaPortalState( ent, qfalse );
- }
- } else {
- G_Error( "Reached_BinaryMover: bad moverState" );
- }
-}
-
-
-/*
-================
-Use_BinaryMover
-================
-*/
-void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
- int total;
- int partial;
-
- // only the master should be used
- if ( ent->flags & FL_TEAMSLAVE ) {
- Use_BinaryMover( ent->teammaster, other, activator );
- return;
- }
-
- ent->activator = activator;
-
- if ( ent->moverState == MOVER_POS1 ) {
- // start moving 50 msec later, becase if this was player
- // triggered, level.time hasn't been advanced yet
- MatchTeam( ent, MOVER_1TO2, level.time + 50 );
-
- // starting sound
- if ( ent->sound1to2 ) {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );
- }
-
- // looping sound
- ent->s.loopSound = ent->soundLoop;
-
- // open areaportal
- if ( ent->teammaster == ent || !ent->teammaster ) {
- trap_AdjustAreaPortalState( ent, qtrue );
- }
- return;
- }
-
- // if all the way up, just delay before coming down
- if ( ent->moverState == MOVER_POS2 ) {
- ent->nextthink = level.time + ent->wait;
- return;
- }
-
- // only partway down before reversing
- if ( ent->moverState == MOVER_2TO1 ) {
- total = ent->s.pos.trDuration;
- partial = level.time - ent->s.pos.trTime;
- if ( partial > total ) {
- partial = total;
- }
-
- MatchTeam( ent, MOVER_1TO2, level.time - ( total - partial ) );
-
- if ( ent->sound1to2 ) {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );
- }
- return;
- }
-
- // only partway up before reversing
- if ( ent->moverState == MOVER_1TO2 ) {
- total = ent->s.pos.trDuration;
- partial = level.time - ent->s.pos.trTime;
- if ( partial > total ) {
- partial = total;
- }
-
- MatchTeam( ent, MOVER_2TO1, level.time - ( total - partial ) );
-
- if ( ent->sound2to1 ) {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
- }
- return;
- }
-}
-
-
-
-/*
-================
-InitMover
-
-"pos1", "pos2", and "speed" should be set before calling,
-so the movement delta can be calculated
-================
-*/
-void InitMover( gentity_t *ent ) {
- vec3_t move;
- float distance;
- float light;
- vec3_t color;
- qboolean lightSet, colorSet;
- char *sound;
-
- // if the "model2" key is set, use a seperate model
- // for drawing, but clip against the brushes
- if ( ent->model2 ) {
- ent->s.modelindex2 = G_ModelIndex( ent->model2 );
- }
-
- // if the "loopsound" key is set, use a constant looping sound when moving
- if ( G_SpawnString( "noise", "100", &sound ) ) {
- ent->s.loopSound = G_SoundIndex( sound );
- }
-
- // if the "color" or "light" keys are set, setup constantLight
- lightSet = G_SpawnFloat( "light", "100", &light );
- colorSet = G_SpawnVector( "color", "1 1 1", color );
- if ( lightSet || colorSet ) {
- int r, g, b, i;
-
- r = color[0] * 255;
- if ( r > 255 ) {
- r = 255;
- }
- g = color[1] * 255;
- if ( g > 255 ) {
- g = 255;
- }
- b = color[2] * 255;
- if ( b > 255 ) {
- b = 255;
- }
- i = light / 4;
- if ( i > 255 ) {
- i = 255;
- }
- ent->s.constantLight = r | ( g << 8 ) | ( b << 16 ) | ( i << 24 );
- }
-
-
- ent->use = Use_BinaryMover;
- ent->reached = Reached_BinaryMover;
-
- ent->moverState = MOVER_POS1;
- ent->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- ent->s.eType = ET_MOVER;
- VectorCopy (ent->pos1, ent->r.currentOrigin);
- trap_LinkEntity (ent);
-
- ent->s.pos.trType = TR_STATIONARY;
- VectorCopy( ent->pos1, ent->s.pos.trBase );
-
- // calculate time to reach second position from speed
- VectorSubtract( ent->pos2, ent->pos1, move );
- distance = VectorLength( move );
- if ( ! ent->speed ) {
- ent->speed = 100;
- }
- VectorScale( move, ent->speed, ent->s.pos.trDelta );
- ent->s.pos.trDuration = distance * 1000 / ent->speed;
- if ( ent->s.pos.trDuration <= 0 ) {
- ent->s.pos.trDuration = 1;
- }
-}
-
-
-/*
-===============================================================================
-
-DOOR
-
-A use can be triggered either by a touch function, by being shot, or by being
-targeted by another entity.
-
-===============================================================================
-*/
-
-/*
-================
-Blocked_Door
-================
-*/
-void Blocked_Door( gentity_t *ent, gentity_t *other ) {
- // remove anything other than a client
- if ( !other->client ) {
- // except CTF flags!!!!
- if( other->s.eType == ET_ITEM && other->item->giType == IT_TEAM ) {
- Team_DroppedFlagThink( other );
- return;
- }
- G_TempEntity( other->s.origin, EV_ITEM_POP );
- G_FreeEntity( other );
- return;
- }
-
- if ( ent->damage ) {
- G_Damage( other, ent, ent, NULL, NULL, ent->damage, 0, MOD_CRUSH );
- }
- if ( ent->spawnflags & 4 ) {
- return; // crushers don't reverse
- }
-
- // reverse direction
- Use_BinaryMover( ent, ent, other );
-}
-
-/*
-================
-Touch_DoorTriggerSpectator
-================
-*/
-static void Touch_DoorTriggerSpectator( gentity_t *ent, gentity_t *other, trace_t *trace ) {
- int i, axis;
- vec3_t origin, dir, angles;
-
- axis = ent->count;
- VectorClear(dir);
- if (fabs(other->s.origin[axis] - ent->r.absmax[axis]) <
- fabs(other->s.origin[axis] - ent->r.absmin[axis])) {
- origin[axis] = ent->r.absmin[axis] - 10;
- dir[axis] = -1;
- }
- else {
- origin[axis] = ent->r.absmax[axis] + 10;
- dir[axis] = 1;
- }
- for (i = 0; i < 3; i++) {
- if (i == axis) continue;
- origin[i] = (ent->r.absmin[i] + ent->r.absmax[i]) * 0.5;
- }
- vectoangles(dir, angles);
- TeleportPlayer(other, origin, angles );
-}
-
-/*
-================
-Touch_DoorTrigger
-================
-*/
-void Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace ) {
- if ( other->client && other->client->sess.sessionTeam == TEAM_SPECTATOR ) {
- // if the door is not open and not opening
- if ( ent->parent->moverState != MOVER_1TO2 &&
- ent->parent->moverState != MOVER_POS2) {
- Touch_DoorTriggerSpectator( ent, other, trace );
- }
- }
- else if ( ent->parent->moverState != MOVER_1TO2 ) {
- Use_BinaryMover( ent->parent, ent, other );
- }
-}
-
-
-/*
-======================
-Think_SpawnNewDoorTrigger
-
-All of the parts of a door have been spawned, so create
-a trigger that encloses all of them
-======================
-*/
-void Think_SpawnNewDoorTrigger( gentity_t *ent ) {
- gentity_t *other;
- vec3_t mins, maxs;
- int i, best;
-
- // set all of the slaves as shootable
- for ( other = ent ; other ; other = other->teamchain ) {
- other->takedamage = qtrue;
- }
-
- // find the bounds of everything on the team
- VectorCopy (ent->r.absmin, mins);
- VectorCopy (ent->r.absmax, maxs);
-
- for (other = ent->teamchain ; other ; other=other->teamchain) {
- AddPointToBounds (other->r.absmin, mins, maxs);
- AddPointToBounds (other->r.absmax, mins, maxs);
- }
-
- // find the thinnest axis, which will be the one we expand
- best = 0;
- for ( i = 1 ; i < 3 ; i++ ) {
- if ( maxs[i] - mins[i] < maxs[best] - mins[best] ) {
- best = i;
- }
- }
- maxs[best] += 120;
- mins[best] -= 120;
-
- // create a trigger with this size
- other = G_Spawn ();
- other->classname = "door_trigger";
- VectorCopy (mins, other->r.mins);
- VectorCopy (maxs, other->r.maxs);
- other->parent = ent;
- other->r.contents = CONTENTS_TRIGGER;
- other->touch = Touch_DoorTrigger;
- // remember the thinnest axis
- other->count = best;
- trap_LinkEntity (other);
-
- MatchTeam( ent, ent->moverState, level.time );
-}
-
-void Think_MatchTeam( gentity_t *ent ) {
- MatchTeam( ent, ent->moverState, level.time );
-}
-
-
-/*QUAKED func_door (0 .5 .8) ? START_OPEN x CRUSHER
-TOGGLE wait in both the start and end states for a trigger event.
-START_OPEN the door to moves to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
-NOMONSTER monsters will not trigger this door
-
-"model2" .md3 model to also draw
-"angle" determines the opening direction
-"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
-"speed" movement speed (100 default)
-"wait" wait before returning (3 default, -1 = never return)
-"lip" lip remaining at end of move (8 default)
-"dmg" damage to inflict when blocked (2 default)
-"color" constantLight color
-"light" constantLight radius
-"health" if set, the door must be shot open
-*/
-void SP_func_door (gentity_t *ent) {
- vec3_t abs_movedir;
- float distance;
- vec3_t size;
- float lip;
-
- ent->sound1to2 = ent->sound2to1 = G_SoundIndex("sound/movers/doors/dr1_strt.wav");
- ent->soundPos1 = ent->soundPos2 = G_SoundIndex("sound/movers/doors/dr1_end.wav");
-
- ent->blocked = Blocked_Door;
-
- // default speed of 400
- if (!ent->speed)
- ent->speed = 400;
-
- // default wait of 2 seconds
- if (!ent->wait)
- ent->wait = 2;
- ent->wait *= 1000;
-
- // default lip of 8 units
- G_SpawnFloat( "lip", "8", &lip );
-
- // default damage of 2 points
- G_SpawnInt( "dmg", "2", &ent->damage );
-
- // first position at start
- VectorCopy( ent->s.origin, ent->pos1 );
-
- // calculate second position
- trap_SetBrushModel( ent, ent->model );
- G_SetMovedir (ent->s.angles, ent->movedir);
- abs_movedir[0] = fabs(ent->movedir[0]);
- abs_movedir[1] = fabs(ent->movedir[1]);
- abs_movedir[2] = fabs(ent->movedir[2]);
- VectorSubtract( ent->r.maxs, ent->r.mins, size );
- distance = DotProduct( abs_movedir, size ) - lip;
- VectorMA( ent->pos1, distance, ent->movedir, ent->pos2 );
-
- // if "start_open", reverse position 1 and 2
- if ( ent->spawnflags & 1 ) {
- vec3_t temp;
-
- VectorCopy( ent->pos2, temp );
- VectorCopy( ent->s.origin, ent->pos2 );
- VectorCopy( temp, ent->pos1 );
- }
-
- InitMover( ent );
-
- ent->nextthink = level.time + FRAMETIME;
-
- if ( ! (ent->flags & FL_TEAMSLAVE ) ) {
- int health;
-
- G_SpawnInt( "health", "0", &health );
- if ( health ) {
- ent->takedamage = qtrue;
- }
- if ( ent->targetname || health ) {
- // non touch/shoot doors
- ent->think = Think_MatchTeam;
- } else {
- ent->think = Think_SpawnNewDoorTrigger;
- }
- }
-
-
-}
-
-/*
-===============================================================================
-
-PLAT
-
-===============================================================================
-*/
-
-/*
-==============
-Touch_Plat
-
-Don't allow decent if a living player is on it
-===============
-*/
-void Touch_Plat( gentity_t *ent, gentity_t *other, trace_t *trace ) {
- if ( !other->client || other->client->ps.stats[STAT_HEALTH] <= 0 ) {
- return;
- }
-
- // delay return-to-pos1 by one second
- if ( ent->moverState == MOVER_POS2 ) {
- ent->nextthink = level.time + 1000;
- }
-}
-
-/*
-==============
-Touch_PlatCenterTrigger
-
-If the plat is at the bottom position, start it going up
-===============
-*/
-void Touch_PlatCenterTrigger(gentity_t *ent, gentity_t *other, trace_t *trace ) {
- if ( !other->client ) {
- return;
- }
-
- if ( ent->parent->moverState == MOVER_POS1 ) {
- Use_BinaryMover( ent->parent, ent, other );
- }
-}
-
-
-/*
-================
-SpawnPlatTrigger
-
-Spawn a trigger in the middle of the plat's low position
-Elevator cars require that the trigger extend through the entire low position,
-not just sit on top of it.
-================
-*/
-void SpawnPlatTrigger( gentity_t *ent ) {
- gentity_t *trigger;
- vec3_t tmin, tmax;
-
- // the middle trigger will be a thin trigger just
- // above the starting position
- trigger = G_Spawn();
- trigger->classname = "plat_trigger";
- trigger->touch = Touch_PlatCenterTrigger;
- trigger->r.contents = CONTENTS_TRIGGER;
- trigger->parent = ent;
-
- tmin[0] = ent->pos1[0] + ent->r.mins[0] + 33;
- tmin[1] = ent->pos1[1] + ent->r.mins[1] + 33;
- tmin[2] = ent->pos1[2] + ent->r.mins[2];
-
- tmax[0] = ent->pos1[0] + ent->r.maxs[0] - 33;
- tmax[1] = ent->pos1[1] + ent->r.maxs[1] - 33;
- tmax[2] = ent->pos1[2] + ent->r.maxs[2] + 8;
-
- if ( tmax[0] <= tmin[0] ) {
- tmin[0] = ent->pos1[0] + (ent->r.mins[0] + ent->r.maxs[0]) *0.5;
- tmax[0] = tmin[0] + 1;
- }
- if ( tmax[1] <= tmin[1] ) {
- tmin[1] = ent->pos1[1] + (ent->r.mins[1] + ent->r.maxs[1]) *0.5;
- tmax[1] = tmin[1] + 1;
- }
-
- VectorCopy (tmin, trigger->r.mins);
- VectorCopy (tmax, trigger->r.maxs);
-
- trap_LinkEntity (trigger);
-}
-
-
-/*QUAKED func_plat (0 .5 .8) ?
-Plats are always drawn in the extended position so they will light correctly.
-
-"lip" default 8, protrusion above rest position
-"height" total height of movement, defaults to model height
-"speed" overrides default 200.
-"dmg" overrides default 2
-"model2" .md3 model to also draw
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_plat (gentity_t *ent) {
- float lip, height;
-
- ent->sound1to2 = ent->sound2to1 = G_SoundIndex("sound/movers/plats/pt1_strt.wav");
- ent->soundPos1 = ent->soundPos2 = G_SoundIndex("sound/movers/plats/pt1_end.wav");
-
- VectorClear (ent->s.angles);
-
- G_SpawnFloat( "speed", "200", &ent->speed );
- G_SpawnInt( "dmg", "2", &ent->damage );
- G_SpawnFloat( "wait", "1", &ent->wait );
- G_SpawnFloat( "lip", "8", &lip );
-
- ent->wait = 1000;
-
- // create second position
- trap_SetBrushModel( ent, ent->model );
-
- if ( !G_SpawnFloat( "height", "0", &height ) ) {
- height = (ent->r.maxs[2] - ent->r.mins[2]) - lip;
- }
-
- // pos1 is the rest (bottom) position, pos2 is the top
- VectorCopy( ent->s.origin, ent->pos2 );
- VectorCopy( ent->pos2, ent->pos1 );
- ent->pos1[2] -= height;
-
- InitMover( ent );
-
- // touch function keeps the plat from returning while
- // a live player is standing on it
- ent->touch = Touch_Plat;
-
- ent->blocked = Blocked_Door;
-
- ent->parent = ent; // so it can be treated as a door
-
- // spawn the trigger if one hasn't been custom made
- if ( !ent->targetname ) {
- SpawnPlatTrigger(ent);
- }
-}
-
-
-/*
-===============================================================================
-
-BUTTON
-
-===============================================================================
-*/
-
-/*
-==============
-Touch_Button
-
-===============
-*/
-void Touch_Button(gentity_t *ent, gentity_t *other, trace_t *trace ) {
- if ( !other->client ) {
- return;
- }
-
- if ( ent->moverState == MOVER_POS1 ) {
- Use_BinaryMover( ent, other, other );
- }
-}
-
-
-/*QUAKED func_button (0 .5 .8) ?
-When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
-
-"model2" .md3 model to also draw
-"angle" determines the opening direction
-"target" all entities with a matching targetname will be used
-"speed" override the default 40 speed
-"wait" override the default 1 second wait (-1 = never return)
-"lip" override the default 4 pixel lip remaining at end of move
-"health" if set, the button must be killed instead of touched
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_button( gentity_t *ent ) {
- vec3_t abs_movedir;
- float distance;
- vec3_t size;
- float lip;
-
- ent->sound1to2 = G_SoundIndex("sound/movers/switches/butn2.wav");
-
- if ( !ent->speed ) {
- ent->speed = 40;
- }
-
- if ( !ent->wait ) {
- ent->wait = 1;
- }
- ent->wait *= 1000;
-
- // first position
- VectorCopy( ent->s.origin, ent->pos1 );
-
- // calculate second position
- trap_SetBrushModel( ent, ent->model );
-
- G_SpawnFloat( "lip", "4", &lip );
-
- G_SetMovedir( ent->s.angles, ent->movedir );
- abs_movedir[0] = fabs(ent->movedir[0]);
- abs_movedir[1] = fabs(ent->movedir[1]);
- abs_movedir[2] = fabs(ent->movedir[2]);
- VectorSubtract( ent->r.maxs, ent->r.mins, size );
- distance = abs_movedir[0] * size[0] + abs_movedir[1] * size[1] + abs_movedir[2] * size[2] - lip;
- VectorMA (ent->pos1, distance, ent->movedir, ent->pos2);
-
- if (ent->health) {
- // shootable button
- ent->takedamage = qtrue;
- } else {
- // touchable button
- ent->touch = Touch_Button;
- }
-
- InitMover( ent );
-}
-
-
-
-/*
-===============================================================================
-
-TRAIN
-
-===============================================================================
-*/
-
-
-#define TRAIN_START_ON 1
-#define TRAIN_TOGGLE 2
-#define TRAIN_BLOCK_STOPS 4
-
-/*
-===============
-Think_BeginMoving
-
-The wait time at a corner has completed, so start moving again
-===============
-*/
-void Think_BeginMoving( gentity_t *ent ) {
- ent->s.pos.trTime = level.time;
- ent->s.pos.trType = TR_LINEAR_STOP;
-}
-
-/*
-===============
-Reached_Train
-===============
-*/
-void Reached_Train( gentity_t *ent ) {
- gentity_t *next;
- float speed;
- vec3_t move;
- float length;
-
- // copy the apropriate values
- next = ent->nextTrain;
- if ( !next || !next->nextTrain ) {
- return; // just stop
- }
-
- // fire all other targets
- G_UseTargets( next, NULL );
-
- // set the new trajectory
- ent->nextTrain = next->nextTrain;
- VectorCopy( next->s.origin, ent->pos1 );
- VectorCopy( next->nextTrain->s.origin, ent->pos2 );
-
- // if the path_corner has a speed, use that
- if ( next->speed ) {
- speed = next->speed;
- } else {
- // otherwise use the train's speed
- speed = ent->speed;
- }
- if ( speed < 1 ) {
- speed = 1;
- }
-
- // calculate duration
- VectorSubtract( ent->pos2, ent->pos1, move );
- length = VectorLength( move );
-
- ent->s.pos.trDuration = length * 1000 / speed;
-
- // Tequila comment: Be sure to send to clients after any fast move case
- ent->r.svFlags &= ~SVF_NOCLIENT;
-
- // Tequila comment: Fast move case
- if(ent->s.pos.trDuration<1) {
- // Tequila comment: As trDuration is used later in a division, we need to avoid that case now
- // With null trDuration,
- // the calculated rocks bounding box becomes infinite and the engine think for a short time
- // any entity is riding that mover but not the world entity... In rare case, I found it
- // can also stuck every map entities after func_door are used.
- // The desired effect with very very big speed is to have instant move, so any not null duration
- // lower than a frame duration should be sufficient.
- // Afaik, the negative case don't have to be supported.
- ent->s.pos.trDuration=1;
-
- // Tequila comment: Don't send entity to clients so it becomes really invisible
- ent->r.svFlags |= SVF_NOCLIENT;
- }
-
- // looping sound
- ent->s.loopSound = next->soundLoop;
-
- // start it going
- SetMoverState( ent, MOVER_1TO2, level.time );
-
- // if there is a "wait" value on the target, don't start moving yet
- if ( next->wait ) {
- ent->nextthink = level.time + next->wait * 1000;
- ent->think = Think_BeginMoving;
- ent->s.pos.trType = TR_STATIONARY;
- }
-}
-
-
-/*
-===============
-Think_SetupTrainTargets
-
-Link all the corners together
-===============
-*/
-void Think_SetupTrainTargets( gentity_t *ent ) {
- gentity_t *path, *next, *start;
-
- ent->nextTrain = G_Find( NULL, FOFS(targetname), ent->target );
- if ( !ent->nextTrain ) {
- G_Printf( "func_train at %s with an unfound target\n",
- vtos(ent->r.absmin) );
- return;
- }
-
- start = NULL;
- for ( path = ent->nextTrain ; path != start ; path = next ) {
- if ( !start ) {
- start = path;
- }
-
- if ( !path->target ) {
- G_Printf( "Train corner at %s without a target\n",
- vtos(path->s.origin) );
- return;
- }
-
- // find a path_corner among the targets
- // there may also be other targets that get fired when the corner
- // is reached
- next = NULL;
- do {
- next = G_Find( next, FOFS(targetname), path->target );
- if ( !next ) {
- G_Printf( "Train corner at %s without a target path_corner\n",
- vtos(path->s.origin) );
- return;
- }
- } while ( strcmp( next->classname, "path_corner" ) );
-
- path->nextTrain = next;
- }
-
- // start the train moving from the first corner
- Reached_Train( ent );
-}
-
-
-
-/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8)
-Train path corners.
-Target: next path corner and other targets to fire
-"speed" speed to move to the next corner
-"wait" seconds to wait before behining move to next corner
-*/
-void SP_path_corner( gentity_t *self ) {
- if ( !self->targetname ) {
- G_Printf ("path_corner with no targetname at %s\n", vtos(self->s.origin));
- G_FreeEntity( self );
- return;
- }
- // path corners don't need to be linked in
-}
-
-
-
-/*QUAKED func_train (0 .5 .8) ? START_ON TOGGLE BLOCK_STOPS
-A train is a mover that moves between path_corner target points.
-Trains MUST HAVE AN ORIGIN BRUSH.
-The train spawns at the first target it is pointing at.
-"model2" .md3 model to also draw
-"speed" default 100
-"dmg" default 2
-"noise" looping sound to play when the train is in motion
-"target" next path corner
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_train (gentity_t *self) {
- VectorClear (self->s.angles);
-
- if (self->spawnflags & TRAIN_BLOCK_STOPS) {
- self->damage = 0;
- } else {
- if (!self->damage) {
- self->damage = 2;
- }
- }
-
- if ( !self->speed ) {
- self->speed = 100;
- }
-
- if ( !self->target ) {
- G_Printf ("func_train without a target at %s\n", vtos(self->r.absmin));
- G_FreeEntity( self );
- return;
- }
-
- trap_SetBrushModel( self, self->model );
- InitMover( self );
-
- self->reached = Reached_Train;
-
- // start trains on the second frame, to make sure their targets have had
- // a chance to spawn
- self->nextthink = level.time + FRAMETIME;
- self->think = Think_SetupTrainTargets;
-}
-
-/*
-===============================================================================
-
-STATIC
-
-===============================================================================
-*/
-
-
-/*QUAKED func_static (0 .5 .8) ?
-A bmodel that just sits there, doing nothing. Can be used for conditional walls and models.
-"model2" .md3 model to also draw
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_static( gentity_t *ent ) {
- trap_SetBrushModel( ent, ent->model );
- InitMover( ent );
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.origin, ent->r.currentOrigin );
-}
-
-
-/*
-===============================================================================
-
-ROTATING
-
-===============================================================================
-*/
-
-
-/*QUAKED func_rotating (0 .5 .8) ? START_ON - X_AXIS Y_AXIS
-You need to have an origin brush as part of this entity. The center of that brush will be
-the point around which it is rotated. It will rotate around the Z axis by default. You can
-check either the X_AXIS or Y_AXIS box to change that.
-
-"model2" .md3 model to also draw
-"speed" determines how fast it moves; default value is 100.
-"dmg" damage to inflict when blocked (2 default)
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_rotating (gentity_t *ent) {
- if ( !ent->speed ) {
- ent->speed = 100;
- }
-
- // set the axis of rotation
- ent->s.apos.trType = TR_LINEAR;
- if ( ent->spawnflags & 4 ) {
- ent->s.apos.trDelta[2] = ent->speed;
- } else if ( ent->spawnflags & 8 ) {
- ent->s.apos.trDelta[0] = ent->speed;
- } else {
- ent->s.apos.trDelta[1] = ent->speed;
- }
-
- if (!ent->damage) {
- ent->damage = 2;
- }
-
- trap_SetBrushModel( ent, ent->model );
- InitMover( ent );
-
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );
- VectorCopy( ent->s.apos.trBase, ent->r.currentAngles );
-
- trap_LinkEntity( ent );
-}
-
-
-/*
-===============================================================================
-
-BOBBING
-
-===============================================================================
-*/
-
-
-/*QUAKED func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS
-Normally bobs on the Z axis
-"model2" .md3 model to also draw
-"height" amplitude of bob (32 default)
-"speed" seconds to complete a bob cycle (4 default)
-"phase" the 0.0 to 1.0 offset in the cycle to start at
-"dmg" damage to inflict when blocked (2 default)
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_bobbing (gentity_t *ent) {
- float height;
- float phase;
-
- G_SpawnFloat( "speed", "4", &ent->speed );
- G_SpawnFloat( "height", "32", &height );
- G_SpawnInt( "dmg", "2", &ent->damage );
- G_SpawnFloat( "phase", "0", &phase );
-
- trap_SetBrushModel( ent, ent->model );
- InitMover( ent );
-
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.origin, ent->r.currentOrigin );
-
- ent->s.pos.trDuration = ent->speed * 1000;
- ent->s.pos.trTime = ent->s.pos.trDuration * phase;
- ent->s.pos.trType = TR_SINE;
-
- // set the axis of bobbing
- if ( ent->spawnflags & 1 ) {
- ent->s.pos.trDelta[0] = height;
- } else if ( ent->spawnflags & 2 ) {
- ent->s.pos.trDelta[1] = height;
- } else {
- ent->s.pos.trDelta[2] = height;
- }
-}
-
-/*
-===============================================================================
-
-PENDULUM
-
-===============================================================================
-*/
-
-
-/*QUAKED func_pendulum (0 .5 .8) ?
-You need to have an origin brush as part of this entity.
-Pendulums always swing north / south on unrotated models. Add an angles field to the model to allow rotation in other directions.
-Pendulum frequency is a physical constant based on the length of the beam and gravity.
-"model2" .md3 model to also draw
-"speed" the number of degrees each way the pendulum swings, (30 default)
-"phase" the 0.0 to 1.0 offset in the cycle to start at
-"dmg" damage to inflict when blocked (2 default)
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_pendulum(gentity_t *ent) {
- float freq;
- float length;
- float phase;
- float speed;
-
- G_SpawnFloat( "speed", "30", &speed );
- G_SpawnInt( "dmg", "2", &ent->damage );
- G_SpawnFloat( "phase", "0", &phase );
-
- trap_SetBrushModel( ent, ent->model );
-
- // find pendulum length
- length = fabs( ent->r.mins[2] );
- if ( length < 8 ) {
- length = 8;
- }
-
- freq = 1 / ( M_PI * 2 ) * sqrt( g_gravity.value / ( 3 * length ) );
-
- ent->s.pos.trDuration = ( 1000 / freq );
-
- InitMover( ent );
-
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.origin, ent->r.currentOrigin );
-
- VectorCopy( ent->s.angles, ent->s.apos.trBase );
-
- ent->s.apos.trDuration = 1000 / freq;
- ent->s.apos.trTime = ent->s.apos.trDuration * phase;
- ent->s.apos.trType = TR_SINE;
- ent->s.apos.trDelta[2] = speed;
-}
diff --git a/engine/code/game/g_rankings.c b/engine/code/game/g_rankings.c
deleted file mode 100644
index 862f307..0000000
--- a/engine/code/game/g_rankings.c
+++ /dev/null
@@ -1,1135 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// g_rankings.c -- reports for global rankings system
-
-#include "g_local.h"
-#include "g_rankings.h"
-
-/*
-================
-G_RankRunFrame
-================
-*/
-void G_RankRunFrame()
-{
- gentity_t* ent;
- gentity_t* ent2;
- grank_status_t old_status;
- grank_status_t status;
- int time;
- int i;
- int j;
-
- if( !trap_RankCheckInit() )
- {
- trap_RankBegin( GR_GAMEKEY );
- }
-
- trap_RankPoll();
-
- if( trap_RankActive() )
- {
- for( i = 0; i < level.maxclients; i++ )
- {
- ent = &(g_entities[i]);
- if ( !ent->inuse )
- continue;
- if ( ent->client == NULL )
- continue;
- if ( ent->r.svFlags & SVF_BOT)
- {
- // no bots in ranked games
- trap_SendConsoleCommand( EXEC_INSERT, va("kick %s\n",
- ent->client->pers.netname) );
- continue;
- }
-
- old_status = ent->client->client_status;
- status = trap_RankUserStatus( i );
-
- if( ent->client->client_status != status )
- {
- // inform client of current status
- // not needed for client side log in
- trap_SendServerCommand( i, va("rank_status %i\n",status) );
- if ( i == 0 )
- {
- int j = 0;
- }
- ent->client->client_status = status;
- }
-
- switch( status )
- {
- case QGR_STATUS_NEW:
- case QGR_STATUS_SPECTATOR:
- if( ent->client->sess.sessionTeam != TEAM_SPECTATOR )
- {
- ent->client->sess.sessionTeam = TEAM_SPECTATOR;
- ent->client->sess.spectatorState = SPECTATOR_FREE;
- ClientSpawn( ent );
- // make sure by now CS_GRAND rankingsGameID is ready
- trap_SendServerCommand( i, va("rank_status %i\n",status) );
- trap_SendServerCommand( i, "rank_menu\n" );
- }
- break;
- case QGR_STATUS_NO_USER:
- case QGR_STATUS_BAD_PASSWORD:
- case QGR_STATUS_TIMEOUT:
- case QGR_STATUS_NO_MEMBERSHIP:
- case QGR_STATUS_INVALIDUSER:
- case QGR_STATUS_ERROR:
- if( (ent->r.svFlags & SVF_BOT) == 0 )
- {
- trap_RankUserReset( ent->s.clientNum );
- }
- break;
- case QGR_STATUS_ACTIVE:
- if( (ent->client->sess.sessionTeam == TEAM_SPECTATOR) &&
- (g_gametype.integer < GT_TEAM) )
- {
- SetTeam( ent, "free" );
- }
-
- if( old_status != QGR_STATUS_ACTIVE )
- {
- // player has just become active
- for( j = 0; j < level.maxclients; j++ )
- {
- ent2 = &(g_entities[j]);
- if ( !ent2->inuse )
- continue;
- if ( ent2->client == NULL )
- continue;
- if ( ent2->r.svFlags & SVF_BOT)
- continue;
-
- if( (i != j) && (trap_RankUserStatus( j ) == QGR_STATUS_ACTIVE) )
- {
- trap_RankReportInt( i, j, QGR_KEY_PLAYED_WITH, 1, 0 );
- }
-
- // send current scores so the player's rank will show
- // up under the crosshair immediately
- DeathmatchScoreboardMessage( ent2 );
- }
- }
- break;
- default:
- break;
- }
- }
-
- // don't let ranked games last forever
- if( ((g_fraglimit.integer == 0) || (g_fraglimit.integer > 100)) &&
- ((g_timelimit.integer == 0) || (g_timelimit.integer > 1000)) )
- {
- trap_Cvar_Set( "timelimit", "1000" );
- }
- }
-
- // tell time to clients so they can show current match rating
- if( level.intermissiontime == 0 )
- {
- for( i = 0; i < level.maxclients; i++ )
- {
- ent = &(g_entities[i]);
- if( ent->client == NULL )
- {
- continue;
- }
-
- time = (level.time - ent->client->pers.enterTime) / 1000;
- ent->client->ps.persistant[PERS_MATCH_TIME] = time;
- }
- }
-}
-
-/*
-================
-G_RankFireWeapon
-================
-*/
-void G_RankFireWeapon( int self, int weapon )
-{
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- if( weapon == WP_GAUNTLET )
- {
- // the gauntlet only "fires" when it actually hits something
- return;
- }
-
- trap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED, 1, 1 );
-
- switch( weapon )
- {
- case WP_MACHINEGUN:
- trap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_MACHINEGUN, 1, 1 );
- break;
- case WP_SHOTGUN:
- trap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_SHOTGUN, 1, 1 );
- break;
- case WP_GRENADE_LAUNCHER:
- trap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_GRENADE, 1, 1 );
- break;
- case WP_ROCKET_LAUNCHER:
- trap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_ROCKET, 1, 1 );
- break;
- case WP_LIGHTNING:
- trap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_LIGHTNING, 1, 1 );
- break;
- case WP_RAILGUN:
- trap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_RAILGUN, 1, 1 );
- break;
- case WP_PLASMAGUN:
- trap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_PLASMA, 1, 1 );
- break;
- case WP_BFG:
- trap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_BFG, 1, 1 );
- break;
- case WP_GRAPPLING_HOOK:
- trap_RankReportInt( self, -1, QGR_KEY_SHOT_FIRED_GRAPPLE, 1, 1 );
- break;
- default:
- break;
- }
-}
-
-/*
-================
-G_RankDamage
-================
-*/
-void G_RankDamage( int self, int attacker, int damage, int means_of_death )
-{
- // state information to avoid counting each shotgun pellet as a hit
- static int last_framenum = -1;
- static int last_self = -1;
- static int last_attacker = -1;
- static int last_means_of_death = MOD_UNKNOWN;
-
- qboolean new_hit;
- int splash;
- int key_hit;
- int key_damage;
- int key_splash;
-
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- new_hit = (level.framenum != last_framenum) ||
- (self != last_self) ||
- (attacker != last_attacker) ||
- (means_of_death != last_means_of_death);
-
- // update state information
- last_framenum = level.framenum;
- last_self = self;
- last_attacker = attacker;
- last_means_of_death = means_of_death;
-
- // the gauntlet only "fires" when it actually hits something
- if( (attacker != ENTITYNUM_WORLD) && (attacker != self) &&
- (means_of_death == MOD_GAUNTLET) &&
- (g_entities[attacker].client) )
- {
- trap_RankReportInt( attacker, -1, QGR_KEY_SHOT_FIRED_GAUNTLET, 1, 1 );
- }
-
- // don't track hazard damage, just deaths
- switch( means_of_death )
- {
- case MOD_WATER:
- case MOD_SLIME:
- case MOD_LAVA:
- case MOD_CRUSH:
- case MOD_TELEFRAG:
- case MOD_FALLING:
- case MOD_SUICIDE:
- case MOD_TRIGGER_HURT:
- return;
- default:
- break;
- }
-
- // get splash damage
- switch( means_of_death )
- {
- case MOD_GRENADE_SPLASH:
- case MOD_ROCKET_SPLASH:
- case MOD_PLASMA_SPLASH:
- case MOD_BFG_SPLASH:
- splash = damage;
- break;
- default:
- splash = 0;
- key_splash = -1;
- break;
- }
-
- // hit, damage, and splash taken
- switch( means_of_death )
- {
- case MOD_GAUNTLET:
- key_hit = QGR_KEY_HIT_TAKEN_GAUNTLET;
- key_damage = QGR_KEY_DAMAGE_TAKEN_GAUNTLET;
- break;
- case MOD_MACHINEGUN:
- key_hit = QGR_KEY_HIT_TAKEN_MACHINEGUN;
- key_damage = QGR_KEY_DAMAGE_TAKEN_MACHINEGUN;
- break;
- case MOD_SHOTGUN:
- key_hit = QGR_KEY_HIT_TAKEN_SHOTGUN;
- key_damage = QGR_KEY_DAMAGE_TAKEN_SHOTGUN;
- break;
- case MOD_GRENADE:
- case MOD_GRENADE_SPLASH:
- key_hit = QGR_KEY_HIT_TAKEN_GRENADE;
- key_damage = QGR_KEY_DAMAGE_TAKEN_GRENADE;
- key_splash = QGR_KEY_SPLASH_TAKEN_GRENADE;
- break;
- case MOD_ROCKET:
- case MOD_ROCKET_SPLASH:
- key_hit = QGR_KEY_HIT_TAKEN_ROCKET;
- key_damage = QGR_KEY_DAMAGE_TAKEN_ROCKET;
- key_splash = QGR_KEY_SPLASH_TAKEN_ROCKET;
- break;
- case MOD_PLASMA:
- case MOD_PLASMA_SPLASH:
- key_hit = QGR_KEY_HIT_TAKEN_PLASMA;
- key_damage = QGR_KEY_DAMAGE_TAKEN_PLASMA;
- key_splash = QGR_KEY_SPLASH_TAKEN_PLASMA;
- break;
- case MOD_RAILGUN:
- key_hit = QGR_KEY_HIT_TAKEN_RAILGUN;
- key_damage = QGR_KEY_DAMAGE_TAKEN_RAILGUN;
- break;
- case MOD_LIGHTNING:
- key_hit = QGR_KEY_HIT_TAKEN_LIGHTNING;
- key_damage = QGR_KEY_DAMAGE_TAKEN_LIGHTNING;
- break;
- case MOD_BFG:
- case MOD_BFG_SPLASH:
- key_hit = QGR_KEY_HIT_TAKEN_BFG;
- key_damage = QGR_KEY_DAMAGE_TAKEN_BFG;
- key_splash = QGR_KEY_SPLASH_TAKEN_BFG;
- break;
- case MOD_GRAPPLE:
- key_hit = QGR_KEY_HIT_TAKEN_GRAPPLE;
- key_damage = QGR_KEY_DAMAGE_TAKEN_GRAPPLE;
- break;
- default:
- key_hit = QGR_KEY_HIT_TAKEN_UNKNOWN;
- key_damage = QGR_KEY_DAMAGE_TAKEN_UNKNOWN;
- break;
- }
-
- // report general and specific hit taken
- if( new_hit )
- {
- trap_RankReportInt( self, -1, QGR_KEY_HIT_TAKEN, 1, 1 );
- trap_RankReportInt( self, -1, key_hit, 1, 1 );
- }
-
- // report general and specific damage taken
- trap_RankReportInt( self, -1, QGR_KEY_DAMAGE_TAKEN, damage, 1 );
- trap_RankReportInt( self, -1, key_damage, damage, 1 );
-
- // report general and specific splash taken
- if( splash != 0 )
- {
- trap_RankReportInt( self, -1, QGR_KEY_SPLASH_TAKEN, splash, 1 );
- trap_RankReportInt( self, -1, key_splash, splash, 1 );
- }
-
- // hit, damage, and splash given
- if( (attacker != ENTITYNUM_WORLD) && (attacker != self) )
- {
- switch( means_of_death )
- {
- case MOD_GAUNTLET:
- key_hit = QGR_KEY_HIT_GIVEN_GAUNTLET;
- key_damage = QGR_KEY_DAMAGE_GIVEN_GAUNTLET;
- break;
- case MOD_MACHINEGUN:
- key_hit = QGR_KEY_HIT_GIVEN_MACHINEGUN;
- key_damage = QGR_KEY_DAMAGE_GIVEN_MACHINEGUN;
- break;
- case MOD_SHOTGUN:
- key_hit = QGR_KEY_HIT_GIVEN_SHOTGUN;
- key_damage = QGR_KEY_DAMAGE_GIVEN_SHOTGUN;
- break;
- case MOD_GRENADE:
- case MOD_GRENADE_SPLASH:
- key_hit = QGR_KEY_HIT_GIVEN_GRENADE;
- key_damage = QGR_KEY_DAMAGE_GIVEN_GRENADE;
- key_splash = QGR_KEY_SPLASH_GIVEN_GRENADE;
- break;
- case MOD_ROCKET:
- case MOD_ROCKET_SPLASH:
- key_hit = QGR_KEY_HIT_GIVEN_ROCKET;
- key_damage = QGR_KEY_DAMAGE_GIVEN_ROCKET;
- key_splash = QGR_KEY_SPLASH_GIVEN_ROCKET;
- break;
- case MOD_PLASMA:
- case MOD_PLASMA_SPLASH:
- key_hit = QGR_KEY_HIT_GIVEN_PLASMA;
- key_damage = QGR_KEY_DAMAGE_GIVEN_PLASMA;
- key_splash = QGR_KEY_SPLASH_GIVEN_PLASMA;
- break;
- case MOD_RAILGUN:
- key_hit = QGR_KEY_HIT_GIVEN_RAILGUN;
- key_damage = QGR_KEY_DAMAGE_GIVEN_RAILGUN;
- break;
- case MOD_LIGHTNING:
- key_hit = QGR_KEY_HIT_GIVEN_LIGHTNING;
- key_damage = QGR_KEY_DAMAGE_GIVEN_LIGHTNING;
- break;
- case MOD_BFG:
- case MOD_BFG_SPLASH:
- key_hit = QGR_KEY_HIT_GIVEN_BFG;
- key_damage = QGR_KEY_DAMAGE_GIVEN_BFG;
- key_splash = QGR_KEY_SPLASH_GIVEN_BFG;
- break;
- case MOD_GRAPPLE:
- key_hit = QGR_KEY_HIT_GIVEN_GRAPPLE;
- key_damage = QGR_KEY_DAMAGE_GIVEN_GRAPPLE;
- break;
- default:
- key_hit = QGR_KEY_HIT_GIVEN_UNKNOWN;
- key_damage = QGR_KEY_DAMAGE_GIVEN_UNKNOWN;
- break;
- }
-
- // report general and specific hit given
- // jwu 8/26/00
- // had a case where attacker is 245 which is grnadeshooter attacker is
- // g_entities index not necessarilly clientnum
- if (g_entities[attacker].client) {
- if( new_hit )
- {
- trap_RankReportInt( attacker, -1, QGR_KEY_HIT_GIVEN, 1, 1 );
- trap_RankReportInt( attacker, -1, key_hit, 1, 1 );
- }
-
- // report general and specific damage given
- trap_RankReportInt( attacker, -1, QGR_KEY_DAMAGE_GIVEN, damage, 1 );
- trap_RankReportInt( attacker, -1, key_damage, damage, 1 );
-
- // report general and specific splash given
- if( splash != 0 )
- {
- trap_RankReportInt( attacker, -1, QGR_KEY_SPLASH_GIVEN, splash, 1 );
- trap_RankReportInt( attacker, -1, key_splash, splash, 1 );
- }
- }
- }
-
- // friendly fire
- if( (attacker != self) &&
- OnSameTeam( &(g_entities[self]), &(g_entities[attacker])) &&
- (g_entities[attacker].client) )
- {
- // report teammate hit
- if( new_hit )
- {
- trap_RankReportInt( self, -1, QGR_KEY_TEAMMATE_HIT_TAKEN, 1, 1 );
- trap_RankReportInt( attacker, -1, QGR_KEY_TEAMMATE_HIT_GIVEN, 1,
- 1 );
- }
-
- // report teammate damage
- trap_RankReportInt( self, -1, QGR_KEY_TEAMMATE_DAMAGE_TAKEN, damage,
- 1 );
- trap_RankReportInt( attacker, -1, QGR_KEY_TEAMMATE_DAMAGE_GIVEN,
- damage, 1 );
-
- // report teammate splash
- if( splash != 0 )
- {
- trap_RankReportInt( self, -1, QGR_KEY_TEAMMATE_SPLASH_TAKEN,
- splash, 1 );
- trap_RankReportInt( attacker, -1, QGR_KEY_TEAMMATE_SPLASH_GIVEN,
- splash, 1 );
- }
- }
-}
-
-/*
-================
-G_RankPlayerDie
-================
-*/
-void G_RankPlayerDie( int self, int attacker, int means_of_death )
-{
- int p1;
- int p2;
-
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- if( attacker == ENTITYNUM_WORLD )
- {
- p1 = self;
- p2 = -1;
-
- trap_RankReportInt( p1, p2, QGR_KEY_HAZARD_DEATH, 1, 1 );
-
- switch( means_of_death )
- {
- case MOD_WATER:
- trap_RankReportInt( p1, p2, QGR_KEY_WATER, 1, 1 );
- break;
- case MOD_SLIME:
- trap_RankReportInt( p1, p2, QGR_KEY_SLIME, 1, 1 );
- break;
- case MOD_LAVA:
- trap_RankReportInt( p1, p2, QGR_KEY_LAVA, 1, 1 );
- break;
- case MOD_CRUSH:
- trap_RankReportInt( p1, p2, QGR_KEY_CRUSH, 1, 1 );
- break;
- case MOD_TELEFRAG:
- trap_RankReportInt( p1, p2, QGR_KEY_TELEFRAG, 1, 1 );
- break;
- case MOD_FALLING:
- trap_RankReportInt( p1, p2, QGR_KEY_FALLING, 1, 1 );
- break;
- case MOD_SUICIDE:
- trap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_CMD, 1, 1 );
- break;
- case MOD_TRIGGER_HURT:
- trap_RankReportInt( p1, p2, QGR_KEY_TRIGGER_HURT, 1, 1 );
- break;
- default:
- trap_RankReportInt( p1, p2, QGR_KEY_HAZARD_MISC, 1, 1 );
- break;
- }
- }
- else if( attacker == self )
- {
- p1 = self;
- p2 = -1;
-
- trap_RankReportInt( p1, p2, QGR_KEY_SUICIDE, 1, 1 );
-
- switch( means_of_death )
- {
- case MOD_GAUNTLET:
- trap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_GAUNTLET, 1, 1 );
- break;
- case MOD_MACHINEGUN:
- trap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_MACHINEGUN, 1, 1 );
- break;
- case MOD_SHOTGUN:
- trap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_SHOTGUN, 1, 1 );
- break;
- case MOD_GRENADE:
- case MOD_GRENADE_SPLASH:
- trap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_GRENADE, 1, 1 );
- break;
- case MOD_ROCKET:
- case MOD_ROCKET_SPLASH:
- trap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_ROCKET, 1, 1 );
- break;
- case MOD_PLASMA:
- case MOD_PLASMA_SPLASH:
- trap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_PLASMA, 1, 1 );
- break;
- case MOD_RAILGUN:
- trap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_RAILGUN, 1, 1 );
- break;
- case MOD_LIGHTNING:
- trap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_LIGHTNING, 1, 1 );
- break;
- case MOD_BFG:
- case MOD_BFG_SPLASH:
- trap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_BFG, 1, 1 );
- break;
- case MOD_GRAPPLE:
- trap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_GRAPPLE, 1, 1 );
- break;
- default:
- trap_RankReportInt( p1, p2, QGR_KEY_SUICIDE_UNKNOWN, 1, 1 );
- break;
- }
- }
- else
- {
- p1 = attacker;
- p2 = self;
-
- trap_RankReportInt( p1, p2, QGR_KEY_FRAG, 1, 1 );
-
- switch( means_of_death )
- {
- case MOD_GAUNTLET:
- trap_RankReportInt( p1, p2, QGR_KEY_FRAG_GAUNTLET, 1, 1 );
- break;
- case MOD_MACHINEGUN:
- trap_RankReportInt( p1, p2, QGR_KEY_FRAG_MACHINEGUN, 1, 1 );
- break;
- case MOD_SHOTGUN:
- trap_RankReportInt( p1, p2, QGR_KEY_FRAG_SHOTGUN, 1, 1 );
- break;
- case MOD_GRENADE:
- case MOD_GRENADE_SPLASH:
- trap_RankReportInt( p1, p2, QGR_KEY_FRAG_GRENADE, 1, 1 );
- break;
- case MOD_ROCKET:
- case MOD_ROCKET_SPLASH:
- trap_RankReportInt( p1, p2, QGR_KEY_FRAG_ROCKET, 1, 1 );
- break;
- case MOD_PLASMA:
- case MOD_PLASMA_SPLASH:
- trap_RankReportInt( p1, p2, QGR_KEY_FRAG_PLASMA, 1, 1 );
- break;
- case MOD_RAILGUN:
- trap_RankReportInt( p1, p2, QGR_KEY_FRAG_RAILGUN, 1, 1 );
- break;
- case MOD_LIGHTNING:
- trap_RankReportInt( p1, p2, QGR_KEY_FRAG_LIGHTNING, 1, 1 );
- break;
- case MOD_BFG:
- case MOD_BFG_SPLASH:
- trap_RankReportInt( p1, p2, QGR_KEY_FRAG_BFG, 1, 1 );
- break;
- case MOD_GRAPPLE:
- trap_RankReportInt( p1, p2, QGR_KEY_FRAG_GRAPPLE, 1, 1 );
- break;
- default:
- trap_RankReportInt( p1, p2, QGR_KEY_FRAG_UNKNOWN, 1, 1 );
- break;
- }
- }
-}
-
-/*
-================
-G_RankWeaponTime
-================
-*/
-void G_RankWeaponTime( int self, int weapon )
-{
- gclient_t* client;
- int time;
-
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- client = g_entities[self].client;
- time = (level.time - client->weapon_change_time) / 1000;
- client->weapon_change_time = level.time;
-
- if( time <= 0 )
- {
- return;
- }
-
- trap_RankReportInt( self, -1, QGR_KEY_TIME, time, 1 );
-
- switch( weapon )
- {
- case WP_GAUNTLET:
- trap_RankReportInt( self, -1, QGR_KEY_TIME_GAUNTLET, time, 1 );
- break;
- case WP_MACHINEGUN:
- trap_RankReportInt( self, -1, QGR_KEY_TIME_MACHINEGUN, time, 1 );
- break;
- case WP_SHOTGUN:
- trap_RankReportInt( self, -1, QGR_KEY_TIME_SHOTGUN, time, 1 );
- break;
- case WP_GRENADE_LAUNCHER:
- trap_RankReportInt( self, -1, QGR_KEY_TIME_GRENADE, time, 1 );
- break;
- case WP_ROCKET_LAUNCHER:
- trap_RankReportInt( self, -1, QGR_KEY_TIME_ROCKET, time, 1 );
- break;
- case WP_LIGHTNING:
- trap_RankReportInt( self, -1, QGR_KEY_TIME_LIGHTNING, time, 1 );
- break;
- case WP_RAILGUN:
- trap_RankReportInt( self, -1, QGR_KEY_TIME_RAILGUN, time, 1 );
- break;
- case WP_PLASMAGUN:
- trap_RankReportInt( self, -1, QGR_KEY_TIME_PLASMA, time, 1 );
- break;
- case WP_BFG:
- trap_RankReportInt( self, -1, QGR_KEY_TIME_BFG, time, 1 );
- break;
- case WP_GRAPPLING_HOOK:
- trap_RankReportInt( self, -1, QGR_KEY_TIME_GRAPPLE, time, 1 );
- break;
- default:
- break;
- }
-}
-
-/*
-================
-G_RankPickupWeapon
-================
-*/
-void G_RankPickupWeapon( int self, int weapon )
-{
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- trap_RankReportInt( self, -1, QGR_KEY_PICKUP_WEAPON, 1, 1 );
- switch( weapon )
- {
- case WP_GAUNTLET:
- trap_RankReportInt( self, -1, QGR_KEY_PICKUP_GAUNTLET, 1, 1 );
- break;
- case WP_MACHINEGUN:
- trap_RankReportInt( self, -1, QGR_KEY_PICKUP_MACHINEGUN, 1, 1 );
- break;
- case WP_SHOTGUN:
- trap_RankReportInt( self, -1, QGR_KEY_PICKUP_SHOTGUN, 1, 1 );
- break;
- case WP_GRENADE_LAUNCHER:
- trap_RankReportInt( self, -1, QGR_KEY_PICKUP_GRENADE, 1, 1 );
- break;
- case WP_ROCKET_LAUNCHER:
- trap_RankReportInt( self, -1, QGR_KEY_PICKUP_ROCKET, 1, 1 );
- break;
- case WP_LIGHTNING:
- trap_RankReportInt( self, -1, QGR_KEY_PICKUP_LIGHTNING, 1, 1 );
- break;
- case WP_RAILGUN:
- trap_RankReportInt( self, -1, QGR_KEY_PICKUP_RAILGUN, 1, 1 );
- break;
- case WP_PLASMAGUN:
- trap_RankReportInt( self, -1, QGR_KEY_PICKUP_PLASMA, 1, 1 );
- break;
- case WP_BFG:
- trap_RankReportInt( self, -1, QGR_KEY_PICKUP_BFG, 1, 1 );
- break;
- case WP_GRAPPLING_HOOK:
- trap_RankReportInt( self, -1, QGR_KEY_PICKUP_GRAPPLE, 1, 1 );
- break;
- default:
- break;
- }
-}
-
-/*
-================
-G_RankPickupAmmo
-================
-*/
-void G_RankPickupAmmo( int self, int weapon, int quantity )
-{
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- trap_RankReportInt( self, -1, QGR_KEY_BOXES, 1, 1 );
- trap_RankReportInt( self, -1, QGR_KEY_ROUNDS, quantity, 1 );
-
- switch( weapon )
- {
- case WP_MACHINEGUN:
- trap_RankReportInt( self, -1, QGR_KEY_BOXES_BULLETS, 1, 1 );
- trap_RankReportInt( self, -1, QGR_KEY_ROUNDS_BULLETS, quantity, 1 );
- break;
- case WP_SHOTGUN:
- trap_RankReportInt( self, -1, QGR_KEY_BOXES_SHELLS, 1, 1 );
- trap_RankReportInt( self, -1, QGR_KEY_ROUNDS_SHELLS, quantity, 1 );
- break;
- case WP_GRENADE_LAUNCHER:
- trap_RankReportInt( self, -1, QGR_KEY_BOXES_GRENADES, 1, 1 );
- trap_RankReportInt( self, -1, QGR_KEY_ROUNDS_GRENADES, quantity, 1 );
- break;
- case WP_ROCKET_LAUNCHER:
- trap_RankReportInt( self, -1, QGR_KEY_BOXES_ROCKETS, 1, 1 );
- trap_RankReportInt( self, -1, QGR_KEY_ROUNDS_ROCKETS, quantity, 1 );
- break;
- case WP_LIGHTNING:
- trap_RankReportInt( self, -1, QGR_KEY_BOXES_LG_AMMO, 1, 1 );
- trap_RankReportInt( self, -1, QGR_KEY_ROUNDS_LG_AMMO, quantity, 1 );
- break;
- case WP_RAILGUN:
- trap_RankReportInt( self, -1, QGR_KEY_BOXES_SLUGS, 1, 1 );
- trap_RankReportInt( self, -1, QGR_KEY_ROUNDS_SLUGS, quantity, 1 );
- break;
- case WP_PLASMAGUN:
- trap_RankReportInt( self, -1, QGR_KEY_BOXES_CELLS, 1, 1 );
- trap_RankReportInt( self, -1, QGR_KEY_ROUNDS_CELLS, quantity, 1 );
- break;
- case WP_BFG:
- trap_RankReportInt( self, -1, QGR_KEY_BOXES_BFG_AMMO, 1, 1 );
- trap_RankReportInt( self, -1, QGR_KEY_ROUNDS_BFG_AMMO, quantity, 1 );
- break;
- default:
- break;
- }
-}
-
-/*
-================
-G_RankPickupHealth
-================
-*/
-void G_RankPickupHealth( int self, int quantity )
-{
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- trap_RankReportInt( self, -1, QGR_KEY_HEALTH, 1, 1 );
- trap_RankReportInt( self, -1, QGR_KEY_HEALTH_TOTAL, quantity, 1 );
-
- switch( quantity )
- {
- case 5:
- trap_RankReportInt( self, -1, QGR_KEY_HEALTH_5, 1, 1 );
- break;
- case 25:
- trap_RankReportInt( self, -1, QGR_KEY_HEALTH_25, 1, 1 );
- break;
- case 50:
- trap_RankReportInt( self, -1, QGR_KEY_HEALTH_50, 1, 1 );
- break;
- case 100:
- trap_RankReportInt( self, -1, QGR_KEY_HEALTH_MEGA, 1, 1 );
- break;
- default:
- break;
- }
-}
-
-/*
-================
-G_RankPickupArmor
-================
-*/
-void G_RankPickupArmor( int self, int quantity )
-{
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- trap_RankReportInt( self, -1, QGR_KEY_ARMOR, 1, 1 );
- trap_RankReportInt( self, -1, QGR_KEY_ARMOR_TOTAL, quantity, 1 );
-
- switch( quantity )
- {
- case 5:
- trap_RankReportInt( self, -1, QGR_KEY_ARMOR_SHARD, 1, 1 );
- break;
- case 50:
- trap_RankReportInt( self, -1, QGR_KEY_ARMOR_YELLOW, 1, 1 );
- break;
- case 100:
- trap_RankReportInt( self, -1, QGR_KEY_ARMOR_RED, 1, 1 );
- break;
- default:
- break;
- }
-}
-
-/*
-================
-G_RankPickupPowerup
-================
-*/
-void G_RankPickupPowerup( int self, int powerup )
-{
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- // ctf flags are treated as powerups
- if( (powerup == PW_REDFLAG) || (powerup == PW_BLUEFLAG) )
- {
- trap_RankReportInt( self, -1, QGR_KEY_FLAG_PICKUP, 1, 1 );
- return;
- }
-
- trap_RankReportInt( self, -1, QGR_KEY_POWERUP, 1, 1 );
-
- switch( powerup )
- {
- case PW_QUAD:
- trap_RankReportInt( self, -1, QGR_KEY_QUAD, 1, 1 );
- break;
- case PW_BATTLESUIT:
- trap_RankReportInt( self, -1, QGR_KEY_SUIT, 1, 1 );
- break;
- case PW_HASTE:
- trap_RankReportInt( self, -1, QGR_KEY_HASTE, 1, 1 );
- break;
- case PW_INVIS:
- trap_RankReportInt( self, -1, QGR_KEY_INVIS, 1, 1 );
- break;
- case PW_REGEN:
- trap_RankReportInt( self, -1, QGR_KEY_REGEN, 1, 1 );
- break;
- case PW_FLIGHT:
- trap_RankReportInt( self, -1, QGR_KEY_FLIGHT, 1, 1 );
- break;
- default:
- break;
- }
-}
-
-/*
-================
-G_RankPickupHoldable
-================
-*/
-void G_RankPickupHoldable( int self, int holdable )
-{
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- switch( holdable )
- {
- case HI_MEDKIT:
- trap_RankReportInt( self, -1, QGR_KEY_MEDKIT, 1, 1 );
- break;
- case HI_TELEPORTER:
- trap_RankReportInt( self, -1, QGR_KEY_TELEPORTER, 1, 1 );
- break;
- default:
- break;
- }
-}
-
-/*
-================
-G_RankUseHoldable
-================
-*/
-void G_RankUseHoldable( int self, int holdable )
-{
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- switch( holdable )
- {
- case HI_MEDKIT:
- trap_RankReportInt( self, -1, QGR_KEY_MEDKIT_USE, 1, 1 );
- break;
- case HI_TELEPORTER:
- trap_RankReportInt( self, -1, QGR_KEY_TELEPORTER_USE, 1, 1 );
- break;
- default:
- break;
- }
-}
-
-/*
-================
-G_RankReward
-================
-*/
-void G_RankReward( int self, int award )
-{
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- switch( award )
- {
- case EF_AWARD_IMPRESSIVE:
- trap_RankReportInt( self, -1, QGR_KEY_IMPRESSIVE, 1, 1 );
- break;
- case EF_AWARD_EXCELLENT:
- trap_RankReportInt( self, -1, QGR_KEY_EXCELLENT, 1, 1 );
- break;
- default:
- break;
- }
-}
-
-/*
-================
-G_RankCapture
-================
-*/
-void G_RankCapture( int self )
-{
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- trap_RankReportInt( self, -1, QGR_KEY_FLAG_CAPTURE, 1, 1 );
-}
-
-/*
-================
-G_RankUserTeamName
-================
-*/
-void G_RankUserTeamName( int self, char* team_name )
-{
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- trap_RankReportStr( self, -1, QGR_KEY_TEAM_NAME, team_name );
-}
-
-/*
-================
-G_RankClientDisconnect
-================
-*/
-void G_RankClientDisconnect( int self )
-{
- gclient_t* client;
- int time;
- int match_rating;
-
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- // match rating
- client = g_entities[self].client;
- time = (level.time - client->pers.enterTime) / 1000;
- if( time < 60 )
- {
- match_rating = 0;
- }
- else
- {
- match_rating = client->ps.persistant[PERS_MATCH_RATING] / time;
- }
- trap_RankReportInt( self, -1, QGR_KEY_MATCH_RATING, match_rating, 0 );
-}
-
-/*
-================
-G_RankGameOver
-================
-*/
-void G_RankGameOver( void )
-{
- int i;
- char str[MAX_INFO_VALUE];
- int num;
-
- if( level.warmupTime != 0 )
- {
- // no reports during warmup period
- return;
- }
-
- for( i = 0; i < level.maxclients; i++ )
- {
- if( trap_RankUserStatus( i ) == QGR_STATUS_ACTIVE )
- {
- G_RankClientDisconnect( i );
- }
- }
-
- // hostname
- trap_Cvar_VariableStringBuffer( "sv_hostname", str, sizeof(str) );
- trap_RankReportStr( -1, -1, QGR_KEY_HOSTNAME, str );
-
- // map
- trap_Cvar_VariableStringBuffer( "mapname", str, sizeof(str) );
- trap_RankReportStr( -1, -1, QGR_KEY_MAP, str );
-
- // mod
- trap_Cvar_VariableStringBuffer( "fs_game", str, sizeof(str) );
- trap_RankReportStr( -1, -1, QGR_KEY_MOD, str );
-
- // gametype
- num = trap_Cvar_VariableIntegerValue("g_gametype");
- trap_RankReportInt( -1, -1, QGR_KEY_GAMETYPE, num, 0 );
-
- // fraglimit
- num = trap_Cvar_VariableIntegerValue("fraglimit");
- trap_RankReportInt( -1, -1, QGR_KEY_FRAGLIMIT, num, 0 );
-
- // timelimit
- num = trap_Cvar_VariableIntegerValue("timelimit");
- trap_RankReportInt( -1, -1, QGR_KEY_TIMELIMIT, num, 0 );
-
- // maxclients
- num = trap_Cvar_VariableIntegerValue("sv_maxclients");
- trap_RankReportInt( -1, -1, QGR_KEY_MAXCLIENTS, num, 0 );
-
- // maxrate
- num = trap_Cvar_VariableIntegerValue("sv_maxRate");
- trap_RankReportInt( -1, -1, QGR_KEY_MAXRATE, num, 0 );
-
- // minping
- num = trap_Cvar_VariableIntegerValue("sv_minPing");
- trap_RankReportInt( -1, -1, QGR_KEY_MINPING, num, 0 );
-
- // maxping
- num = trap_Cvar_VariableIntegerValue("sv_maxPing");
- trap_RankReportInt( -1, -1, QGR_KEY_MAXPING, num, 0 );
-
- // dedicated
- num = trap_Cvar_VariableIntegerValue("dedicated");
- trap_RankReportInt( -1, -1, QGR_KEY_DEDICATED, num, 0 );
-
- // version
- trap_Cvar_VariableStringBuffer( "version", str, sizeof(str) );
- trap_RankReportStr( -1, -1, QGR_KEY_VERSION, str );
-}
-
diff --git a/engine/code/game/g_rankings.h b/engine/code/game/g_rankings.h
deleted file mode 100644
index 05348e1..0000000
--- a/engine/code/game/g_rankings.h
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// g_rankings.h -- score keys for global rankings
-
-#ifndef _G_RANKINGS_H_
-#define _G_RANKINGS_H_
-
-/*
-==============================================================================
-
-Key digits:
- 10^9: report type
- 1 = normal
- 2 = developer-only
- 10^8: stat type
- 0 = match stat
- 1 = single player stat
- 2 = duel stat
- 10^7: data type
- 0 = string
- 1 = uint32
- 10^6: calculation
- 0 = use raw value
- 1 = add to total
- 2 = average
- 3 = max
- 4 = min
- 10^5
- 10^4: category
- 00 = general
- 01 = session
- 02 = weapon
- 03 = ammo
- 04 = health
- 05 = armor
- 06 = powerup
- 07 = holdable
- 08 = hazard
- 09 = reward
- 10 = teammate
- 11 = ctf
- 10^3:
- 10^2: sub-category
- 10^1:
- 10^0: ordinal
-
-==============================================================================
-*/
-
-// general keys
-#define QGR_KEY_MATCH_RATING 1112000001
-#define QGR_KEY_PLAYED_WITH 1210000002
-
-// session keys
-#define QGR_KEY_HOSTNAME 1000010000
-#define QGR_KEY_MAP 1000010001
-#define QGR_KEY_MOD 1000010002
-#define QGR_KEY_GAMETYPE 1010010003
-#define QGR_KEY_FRAGLIMIT 1010010004
-#define QGR_KEY_TIMELIMIT 1010010005
-#define QGR_KEY_MAXCLIENTS 1010010006
-#define QGR_KEY_MAXRATE 1010010007
-#define QGR_KEY_MINPING 1010010008
-#define QGR_KEY_MAXPING 1010010009
-#define QGR_KEY_DEDICATED 1010010010
-#define QGR_KEY_VERSION 1000010011
-
-// weapon keys
-#define QGR_KEY_FRAG 1211020000
-#define QGR_KEY_SUICIDE 1111020001
-#define QGR_KEY_SHOT_FIRED 1111020002
-#define QGR_KEY_HIT_GIVEN 1111020003
-#define QGR_KEY_HIT_TAKEN 1111020004
-#define QGR_KEY_DAMAGE_GIVEN 1111020005
-#define QGR_KEY_DAMAGE_TAKEN 1111020006
-#define QGR_KEY_SPLASH_GIVEN 1111020007
-#define QGR_KEY_SPLASH_TAKEN 1111020008
-#define QGR_KEY_PICKUP_WEAPON 1111020009
-#define QGR_KEY_TIME 1111020010
-
-#define QGR_KEY_FRAG_GAUNTLET 1211020100
-#define QGR_KEY_SUICIDE_GAUNTLET 1111020101
-#define QGR_KEY_SHOT_FIRED_GAUNTLET 1111020102
-#define QGR_KEY_HIT_GIVEN_GAUNTLET 1111020103
-#define QGR_KEY_HIT_TAKEN_GAUNTLET 1111020104
-#define QGR_KEY_DAMAGE_GIVEN_GAUNTLET 1111020105
-#define QGR_KEY_DAMAGE_TAKEN_GAUNTLET 1111020106
-#define QGR_KEY_SPLASH_GIVEN_GAUNTLET 1111020107
-#define QGR_KEY_SPLASH_TAKEN_GAUNTLET 1111020108
-#define QGR_KEY_PICKUP_GAUNTLET 1111020109
-#define QGR_KEY_TIME_GAUNTLET 1111020110
-
-#define QGR_KEY_FRAG_MACHINEGUN 1211020200
-#define QGR_KEY_SUICIDE_MACHINEGUN 1111020201
-#define QGR_KEY_SHOT_FIRED_MACHINEGUN 1111020202
-#define QGR_KEY_HIT_GIVEN_MACHINEGUN 1111020203
-#define QGR_KEY_HIT_TAKEN_MACHINEGUN 1111020204
-#define QGR_KEY_DAMAGE_GIVEN_MACHINEGUN 1111020205
-#define QGR_KEY_DAMAGE_TAKEN_MACHINEGUN 1111020206
-#define QGR_KEY_SPLASH_GIVEN_MACHINEGUN 1111020207
-#define QGR_KEY_SPLASH_TAKEN_MACHINEGUN 1111020208
-#define QGR_KEY_PICKUP_MACHINEGUN 1111020209
-#define QGR_KEY_TIME_MACHINEGUN 1111020210
-
-#define QGR_KEY_FRAG_SHOTGUN 1211020300
-#define QGR_KEY_SUICIDE_SHOTGUN 1111020301
-#define QGR_KEY_SHOT_FIRED_SHOTGUN 1111020302
-#define QGR_KEY_HIT_GIVEN_SHOTGUN 1111020303
-#define QGR_KEY_HIT_TAKEN_SHOTGUN 1111020304
-#define QGR_KEY_DAMAGE_GIVEN_SHOTGUN 1111020305
-#define QGR_KEY_DAMAGE_TAKEN_SHOTGUN 1111020306
-#define QGR_KEY_SPLASH_GIVEN_SHOTGUN 1111020307
-#define QGR_KEY_SPLASH_TAKEN_SHOTGUN 1111020308
-#define QGR_KEY_PICKUP_SHOTGUN 1111020309
-#define QGR_KEY_TIME_SHOTGUN 1111020310
-
-#define QGR_KEY_FRAG_GRENADE 1211020400
-#define QGR_KEY_SUICIDE_GRENADE 1111020401
-#define QGR_KEY_SHOT_FIRED_GRENADE 1111020402
-#define QGR_KEY_HIT_GIVEN_GRENADE 1111020403
-#define QGR_KEY_HIT_TAKEN_GRENADE 1111020404
-#define QGR_KEY_DAMAGE_GIVEN_GRENADE 1111020405
-#define QGR_KEY_DAMAGE_TAKEN_GRENADE 1111020406
-#define QGR_KEY_SPLASH_GIVEN_GRENADE 1111020407
-#define QGR_KEY_SPLASH_TAKEN_GRENADE 1111020408
-#define QGR_KEY_PICKUP_GRENADE 1111020409
-#define QGR_KEY_TIME_GRENADE 1111020410
-
-#define QGR_KEY_FRAG_ROCKET 1211020500
-#define QGR_KEY_SUICIDE_ROCKET 1111020501
-#define QGR_KEY_SHOT_FIRED_ROCKET 1111020502
-#define QGR_KEY_HIT_GIVEN_ROCKET 1111020503
-#define QGR_KEY_HIT_TAKEN_ROCKET 1111020504
-#define QGR_KEY_DAMAGE_GIVEN_ROCKET 1111020505
-#define QGR_KEY_DAMAGE_TAKEN_ROCKET 1111020506
-#define QGR_KEY_SPLASH_GIVEN_ROCKET 1111020507
-#define QGR_KEY_SPLASH_TAKEN_ROCKET 1111020508
-#define QGR_KEY_PICKUP_ROCKET 1111020509
-#define QGR_KEY_TIME_ROCKET 1111020510
-
-#define QGR_KEY_FRAG_PLASMA 1211020600
-#define QGR_KEY_SUICIDE_PLASMA 1111020601
-#define QGR_KEY_SHOT_FIRED_PLASMA 1111020602
-#define QGR_KEY_HIT_GIVEN_PLASMA 1111020603
-#define QGR_KEY_HIT_TAKEN_PLASMA 1111020604
-#define QGR_KEY_DAMAGE_GIVEN_PLASMA 1111020605
-#define QGR_KEY_DAMAGE_TAKEN_PLASMA 1111020606
-#define QGR_KEY_SPLASH_GIVEN_PLASMA 1111020607
-#define QGR_KEY_SPLASH_TAKEN_PLASMA 1111020608
-#define QGR_KEY_PICKUP_PLASMA 1111020609
-#define QGR_KEY_TIME_PLASMA 1111020610
-
-#define QGR_KEY_FRAG_RAILGUN 1211020700
-#define QGR_KEY_SUICIDE_RAILGUN 1111020701
-#define QGR_KEY_SHOT_FIRED_RAILGUN 1111020702
-#define QGR_KEY_HIT_GIVEN_RAILGUN 1111020703
-#define QGR_KEY_HIT_TAKEN_RAILGUN 1111020704
-#define QGR_KEY_DAMAGE_GIVEN_RAILGUN 1111020705
-#define QGR_KEY_DAMAGE_TAKEN_RAILGUN 1111020706
-#define QGR_KEY_SPLASH_GIVEN_RAILGUN 1111020707
-#define QGR_KEY_SPLASH_TAKEN_RAILGUN 1111020708
-#define QGR_KEY_PICKUP_RAILGUN 1111020709
-#define QGR_KEY_TIME_RAILGUN 1111020710
-
-#define QGR_KEY_FRAG_LIGHTNING 1211020800
-#define QGR_KEY_SUICIDE_LIGHTNING 1111020801
-#define QGR_KEY_SHOT_FIRED_LIGHTNING 1111020802
-#define QGR_KEY_HIT_GIVEN_LIGHTNING 1111020803
-#define QGR_KEY_HIT_TAKEN_LIGHTNING 1111020804
-#define QGR_KEY_DAMAGE_GIVEN_LIGHTNING 1111020805
-#define QGR_KEY_DAMAGE_TAKEN_LIGHTNING 1111020806
-#define QGR_KEY_SPLASH_GIVEN_LIGHTNING 1111020807
-#define QGR_KEY_SPLASH_TAKEN_LIGHTNING 1111020808
-#define QGR_KEY_PICKUP_LIGHTNING 1111020809
-#define QGR_KEY_TIME_LIGHTNING 1111020810
-
-#define QGR_KEY_FRAG_BFG 1211020900
-#define QGR_KEY_SUICIDE_BFG 1111020901
-#define QGR_KEY_SHOT_FIRED_BFG 1111020902
-#define QGR_KEY_HIT_GIVEN_BFG 1111020903
-#define QGR_KEY_HIT_TAKEN_BFG 1111020904
-#define QGR_KEY_DAMAGE_GIVEN_BFG 1111020905
-#define QGR_KEY_DAMAGE_TAKEN_BFG 1111020906
-#define QGR_KEY_SPLASH_GIVEN_BFG 1111020907
-#define QGR_KEY_SPLASH_TAKEN_BFG 1111020908
-#define QGR_KEY_PICKUP_BFG 1111020909
-#define QGR_KEY_TIME_BFG 1111020910
-
-#define QGR_KEY_FRAG_GRAPPLE 1211021000
-#define QGR_KEY_SUICIDE_GRAPPLE 1111021001
-#define QGR_KEY_SHOT_FIRED_GRAPPLE 1111021002
-#define QGR_KEY_HIT_GIVEN_GRAPPLE 1111021003
-#define QGR_KEY_HIT_TAKEN_GRAPPLE 1111021004
-#define QGR_KEY_DAMAGE_GIVEN_GRAPPLE 1111021005
-#define QGR_KEY_DAMAGE_TAKEN_GRAPPLE 1111021006
-#define QGR_KEY_SPLASH_GIVEN_GRAPPLE 1111021007
-#define QGR_KEY_SPLASH_TAKEN_GRAPPLE 1111021008
-#define QGR_KEY_PICKUP_GRAPPLE 1111021009
-#define QGR_KEY_TIME_GRAPPLE 1111021010
-
-#define QGR_KEY_FRAG_UNKNOWN 1211021100
-#define QGR_KEY_SUICIDE_UNKNOWN 1111021101
-#define QGR_KEY_SHOT_FIRED_UNKNOWN 1111021102
-#define QGR_KEY_HIT_GIVEN_UNKNOWN 1111021103
-#define QGR_KEY_HIT_TAKEN_UNKNOWN 1111021104
-#define QGR_KEY_DAMAGE_GIVEN_UNKNOWN 1111021105
-#define QGR_KEY_DAMAGE_TAKEN_UNKNOWN 1111021106
-#define QGR_KEY_SPLASH_GIVEN_UNKNOWN 1111021107
-#define QGR_KEY_SPLASH_TAKEN_UNKNOWN 1111021108
-#define QGR_KEY_PICKUP_UNKNOWN 1111021109
-#define QGR_KEY_TIME_UNKNOWN 1111021110
-
-#ifdef MISSIONPACK
-// new to team arena
-#define QGR_KEY_FRAG_NAILGIN 1211021200
-#define QGR_KEY_SUICIDE_NAILGIN 1111021201
-#define QGR_KEY_SHOT_FIRED_NAILGIN 1111021202
-#define QGR_KEY_HIT_GIVEN_NAILGIN 1111021203
-#define QGR_KEY_HIT_TAKEN_NAILGIN 1111021204
-#define QGR_KEY_DAMAGE_GIVEN_NAILGIN 1111021205
-#define QGR_KEY_DAMAGE_TAKEN_NAILGIN 1111021206
-#define QGR_KEY_SPLASH_GIVEN_NAILGIN 1111021207
-#define QGR_KEY_SPLASH_TAKEN_NAILGIN 1111021208
-#define QGR_KEY_PICKUP_NAILGIN 1111021209
-#define QGR_KEY_TIME_NAILGIN 1111021210
-// new to team arena
-#define QGR_KEY_FRAG_PROX_LAUNCHER 1211021300
-#define QGR_KEY_SUICIDE_PROX_LAUNCHER 1111021301
-#define QGR_KEY_SHOT_FIRED_PROX_LAUNCHER 1111021302
-#define QGR_KEY_HIT_GIVEN_PROX_LAUNCHER 1111021303
-#define QGR_KEY_HIT_TAKEN_PROX_LAUNCHER 1111021304
-#define QGR_KEY_DAMAGE_GIVEN_PROX_LAUNCHER 1111021305
-#define QGR_KEY_DAMAGE_TAKEN_PROX_LAUNCHER 1111021306
-#define QGR_KEY_SPLASH_GIVEN_PROX_LAUNCHER 1111021307
-#define QGR_KEY_SPLASH_TAKEN_PROX_LAUNCHER 1111021308
-#define QGR_KEY_PICKUP_PROX_LAUNCHER 1111021309
-#define QGR_KEY_TIME_PROX_LAUNCHER 1111021310
-// new to team arena
-#define QGR_KEY_FRAG_CHAINGUN 1211021400
-#define QGR_KEY_SUICIDE_CHAINGUN 1111021401
-#define QGR_KEY_SHOT_FIRED_CHAINGUN 1111021402
-#define QGR_KEY_HIT_GIVEN_CHAINGUN 1111021403
-#define QGR_KEY_HIT_TAKEN_CHAINGUN 1111021404
-#define QGR_KEY_DAMAGE_GIVEN_CHAINGUN 1111021405
-#define QGR_KEY_DAMAGE_TAKEN_CHAINGUN 1111021406
-#define QGR_KEY_SPLASH_GIVEN_CHAINGUN 1111021407
-#define QGR_KEY_SPLASH_TAKEN_CHAINGUN 1111021408
-#define QGR_KEY_PICKUP_CHAINGUN 1111021409
-#define QGR_KEY_TIME_CHAINGUN 1111021410
-#endif /* MISSIONPACK */
-
-// ammo keys
-#define QGR_KEY_BOXES 1111030000
-#define QGR_KEY_ROUNDS 1111030001
-
-#define QGR_KEY_BOXES_BULLETS 1111030100
-#define QGR_KEY_ROUNDS_BULLETS 1111030101
-
-#define QGR_KEY_BOXES_SHELLS 1111030200
-#define QGR_KEY_ROUNDS_SHELLS 1111030201
-
-#define QGR_KEY_BOXES_GRENADES 1111030300
-#define QGR_KEY_ROUNDS_GRENADES 1111030301
-
-#define QGR_KEY_BOXES_ROCKETS 1111030400
-#define QGR_KEY_ROUNDS_ROCKETS 1111030401
-
-#define QGR_KEY_BOXES_CELLS 1111030500
-#define QGR_KEY_ROUNDS_CELLS 1111030501
-
-#define QGR_KEY_BOXES_SLUGS 1111030600
-#define QGR_KEY_ROUNDS_SLUGS 1111030601
-
-#define QGR_KEY_BOXES_LG_AMMO 1111030700
-#define QGR_KEY_ROUNDS_LG_AMMO 1111030701
-
-#define QGR_KEY_BOXES_BFG_AMMO 1111030800
-#define QGR_KEY_ROUNDS_BFG_AMMO 1111030801
-
-#ifdef MISSIONPACK
-// new to team arena
-#define QGR_KEY_BOXES_NAILGUN_AMMO 1111030900
-#define QGR_KEY_ROUNDS_NAILGUN_AMMO 1111030901
-// new to team arena
-#define QGR_KEY_BOXES_PROX_LAUNCHER_AMMO 1111031000
-#define QGR_KEY_ROUNDS_PROX_LAUNCHER_AMMO 1111031001
-// new to team arena
-#define QGR_KEY_BOXES_CHAINGUN_AMMO 1111031100
-#define QGR_KEY_ROUNDS_CHAINGUN_AMMO 1111031101
-#endif /* MISSIONPACK */
-
-// health keys
-#define QGR_KEY_HEALTH 1111040000
-#define QGR_KEY_HEALTH_TOTAL 1111040001
-
-#define QGR_KEY_HEALTH_5 1111040100
-#define QGR_KEY_HEALTH_25 1111040200
-#define QGR_KEY_HEALTH_50 1111040300
-#define QGR_KEY_HEALTH_MEGA 1111040400
-
-// armor keys
-#define QGR_KEY_ARMOR 1111050000
-#define QGR_KEY_ARMOR_TOTAL 1111050001
-
-#define QGR_KEY_ARMOR_SHARD 1111050100
-#define QGR_KEY_ARMOR_YELLOW 1111050200
-#define QGR_KEY_ARMOR_RED 1111050300
-
-// powerup keys
-#define QGR_KEY_POWERUP 1111060000
-#define QGR_KEY_QUAD 1111060100
-#define QGR_KEY_SUIT 1111060200
-#define QGR_KEY_HASTE 1111060300
-#define QGR_KEY_INVIS 1111060400
-#define QGR_KEY_REGEN 1111060500
-#define QGR_KEY_FLIGHT 1111060600
-
-#ifdef MISSIONPACK
-// persistant powerup keys
-// new to team arena
-#define QGR_KEY_SCOUT 1111160800
-#define QGR_KEY_GUARD 1111160801
-#define QGR_KEY_DOUBLER 1111160802
-#define QGR_KEY_AMMOREGEN 1111160803
-
-#endif //MISSIONPACK
-
-// holdable item keys
-#define QGR_KEY_MEDKIT 1111070000
-#define QGR_KEY_MEDKIT_USE 1111070001
-
-#define QGR_KEY_TELEPORTER 1111070100
-#define QGR_KEY_TELEPORTER_USE 1111070101
-
-#ifdef MISSIONPACK
-// new to team arena
-#define QGR_KEY_KAMIKAZE 1111070200
-#define QGR_KEY_KAMIKAZE_USE 1111070201
-// new to team arena
-#define QGR_KEY_PORTAL 1111070300
-#define QGR_KEY_PORTAL_USE 1111070301
-// new to team arena
-#define QGR_KEY_INVULNERABILITY 1111070400
-#define QGR_KEY_INVULNERABILITY_USE 1111070401
-#endif /* MISSIONPACK */
-
-// hazard keys
-#define QGR_KEY_HAZARD_DEATH 1111080000
-#define QGR_KEY_WATER 1111080100
-#define QGR_KEY_SLIME 1111080200
-#define QGR_KEY_LAVA 1111080300
-#define QGR_KEY_CRUSH 1111080400
-#define QGR_KEY_TELEFRAG 1111080500
-#define QGR_KEY_FALLING 1111080600
-#define QGR_KEY_SUICIDE_CMD 1111080700
-#define QGR_KEY_TRIGGER_HURT 1111080800
-#define QGR_KEY_HAZARD_MISC 1111080900
-
-// reward keys
-#define QGR_KEY_IMPRESSIVE 1111090000
-#define QGR_KEY_EXCELLENT 1111090100
-
-// teammate keys
-#define QGR_KEY_TEAMMATE_FRAG 1211100000
-#define QGR_KEY_TEAMMATE_HIT_GIVEN 1111100001
-#define QGR_KEY_TEAMMATE_HIT_TAKEN 1111100002
-#define QGR_KEY_TEAMMATE_DAMAGE_GIVEN 1111100003
-#define QGR_KEY_TEAMMATE_DAMAGE_TAKEN 1111100004
-#define QGR_KEY_TEAMMATE_SPLASH_GIVEN 1111100005
-#define QGR_KEY_TEAMMATE_SPLASH_TAKEN 1111100006
-#define QGR_KEY_TEAM_NAME 1100100007
-
-// ctf keys
-#define QGR_KEY_FLAG_PICKUP 1111110000
-#define QGR_KEY_FLAG_CAPTURE 1111110001
-
-#endif // _G_RANKINGS_H_
diff --git a/engine/code/game/g_session.c b/engine/code/game/g_session.c
deleted file mode 100644
index 26a9e16..0000000
--- a/engine/code/game/g_session.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-
-/*
-=======================================================================
-
- SESSION DATA
-
-Session data is the only data that stays persistant across level loads
-and tournament restarts.
-=======================================================================
-*/
-
-/*
-================
-G_WriteClientSessionData
-
-Called on game shutdown
-================
-*/
-void G_WriteClientSessionData( gclient_t *client ) {
- const char *s;
- const char *var;
-
- s = va("%i %i %i %i %i %i %i",
- client->sess.sessionTeam,
- client->sess.spectatorTime,
- client->sess.spectatorState,
- client->sess.spectatorClient,
- client->sess.wins,
- client->sess.losses,
- client->sess.teamLeader
- );
-
- var = va( "session%i", (int)(client - level.clients) );
-
- trap_Cvar_Set( var, s );
-}
-
-/*
-================
-G_ReadSessionData
-
-Called on a reconnect
-================
-*/
-void G_ReadSessionData( gclient_t *client ) {
- char s[MAX_STRING_CHARS];
- const char *var;
- int teamLeader;
- int spectatorState;
- int sessionTeam;
-
- var = va( "session%i", (int)(client - level.clients) );
- trap_Cvar_VariableStringBuffer( var, s, sizeof(s) );
-
- sscanf( s, "%i %i %i %i %i %i %i",
- &sessionTeam,
- &client->sess.spectatorTime,
- &spectatorState,
- &client->sess.spectatorClient,
- &client->sess.wins,
- &client->sess.losses,
- &teamLeader
- );
-
- client->sess.sessionTeam = (team_t)sessionTeam;
- client->sess.spectatorState = (spectatorState_t)spectatorState;
- client->sess.teamLeader = (qboolean)teamLeader;
-}
-
-
-/*
-================
-G_InitSessionData
-
-Called on a first-time connect
-================
-*/
-void G_InitSessionData( gclient_t *client, char *userinfo ) {
- clientSession_t *sess;
- const char *value;
-
- sess = &client->sess;
-
- // initial team determination
- if ( g_gametype.integer >= GT_TEAM ) {
- if ( g_teamAutoJoin.integer ) {
- sess->sessionTeam = PickTeam( -1 );
- BroadcastTeamChange( client, -1 );
- } else {
- // always spawn as spectator in team games
- sess->sessionTeam = TEAM_SPECTATOR;
- }
- } else {
- value = Info_ValueForKey( userinfo, "team" );
- if ( value[0] == 's' ) {
- // a willing spectator, not a waiting-in-line
- sess->sessionTeam = TEAM_SPECTATOR;
- } else {
- switch ( g_gametype.integer ) {
- default:
- case GT_FFA:
- case GT_SINGLE_PLAYER:
- if ( g_maxGameClients.integer > 0 &&
- level.numNonSpectatorClients >= g_maxGameClients.integer ) {
- sess->sessionTeam = TEAM_SPECTATOR;
- } else {
- sess->sessionTeam = TEAM_FREE;
- }
- break;
- case GT_TOURNAMENT:
- // if the game is full, go into a waiting mode
- if ( level.numNonSpectatorClients >= 2 ) {
- sess->sessionTeam = TEAM_SPECTATOR;
- } else {
- sess->sessionTeam = TEAM_FREE;
- }
- break;
- }
- }
- }
-
- sess->spectatorState = SPECTATOR_FREE;
- sess->spectatorTime = level.time;
-
- G_WriteClientSessionData( client );
-}
-
-
-/*
-==================
-G_InitWorldSession
-
-==================
-*/
-void G_InitWorldSession( void ) {
- char s[MAX_STRING_CHARS];
- int gt;
-
- trap_Cvar_VariableStringBuffer( "session", s, sizeof(s) );
- gt = atoi( s );
-
- // if the gametype changed since the last session, don't use any
- // client sessions
- if ( g_gametype.integer != gt ) {
- level.newSession = qtrue;
- G_Printf( "Gametype changed, clearing session data.\n" );
- }
-}
-
-/*
-==================
-G_WriteSessionData
-
-==================
-*/
-void G_WriteSessionData( void ) {
- int i;
-
- trap_Cvar_Set( "session", va("%i", g_gametype.integer) );
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].pers.connected == CON_CONNECTED ) {
- G_WriteClientSessionData( &level.clients[i] );
- }
- }
-}
diff --git a/engine/code/game/g_spawn.c b/engine/code/game/g_spawn.c
deleted file mode 100644
index 67d5262..0000000
--- a/engine/code/game/g_spawn.c
+++ /dev/null
@@ -1,643 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-#include "g_local.h"
-
-qboolean G_SpawnString( const char *key, const char *defaultString, char **out ) {
- int i;
-
- if ( !level.spawning ) {
- *out = (char *)defaultString;
-// G_Error( "G_SpawnString() called while not spawning" );
- }
-
- for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
- if ( !Q_stricmp( key, level.spawnVars[i][0] ) ) {
- *out = level.spawnVars[i][1];
- return qtrue;
- }
- }
-
- *out = (char *)defaultString;
- return qfalse;
-}
-
-qboolean G_SpawnFloat( const char *key, const char *defaultString, float *out ) {
- char *s;
- qboolean present;
-
- present = G_SpawnString( key, defaultString, &s );
- *out = atof( s );
- return present;
-}
-
-qboolean G_SpawnInt( const char *key, const char *defaultString, int *out ) {
- char *s;
- qboolean present;
-
- present = G_SpawnString( key, defaultString, &s );
- *out = atoi( s );
- return present;
-}
-
-qboolean G_SpawnVector( const char *key, const char *defaultString, float *out ) {
- char *s;
- qboolean present;
-
- present = G_SpawnString( key, defaultString, &s );
- sscanf( s, "%f %f %f", &out[0], &out[1], &out[2] );
- return present;
-}
-
-
-
-//
-// fields are needed for spawning from the entity string
-//
-typedef enum {
- F_INT,
- F_FLOAT,
- F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL
- F_GSTRING, // string on disk, pointer in memory, TAG_GAME
- F_VECTOR,
- F_ANGLEHACK,
- F_ENTITY, // index on disk, pointer in memory
- F_ITEM, // index on disk, pointer in memory
- F_CLIENT, // index on disk, pointer in memory
- F_IGNORE
-} fieldtype_t;
-
-typedef struct
-{
- char *name;
- int ofs;
- fieldtype_t type;
- int flags;
-} field_t;
-
-field_t fields[] = {
- {"classname", FOFS(classname), F_LSTRING},
- {"origin", FOFS(s.origin), F_VECTOR},
- {"model", FOFS(model), F_LSTRING},
- {"model2", FOFS(model2), F_LSTRING},
- {"spawnflags", FOFS(spawnflags), F_INT},
- {"speed", FOFS(speed), F_FLOAT},
- {"target", FOFS(target), F_LSTRING},
- {"targetname", FOFS(targetname), F_LSTRING},
- {"message", FOFS(message), F_LSTRING},
- {"team", FOFS(team), F_LSTRING},
- {"wait", FOFS(wait), F_FLOAT},
- {"random", FOFS(random), F_FLOAT},
- {"count", FOFS(count), F_INT},
- {"health", FOFS(health), F_INT},
- {"light", 0, F_IGNORE},
- {"dmg", FOFS(damage), F_INT},
- {"angles", FOFS(s.angles), F_VECTOR},
- {"angle", FOFS(s.angles), F_ANGLEHACK},
- {"targetShaderName", FOFS(targetShaderName), F_LSTRING},
- {"targetShaderNewName", FOFS(targetShaderNewName), F_LSTRING},
-
- {NULL}
-};
-
-
-typedef struct {
- char *name;
- void (*spawn)(gentity_t *ent);
-} spawn_t;
-
-void SP_info_player_start (gentity_t *ent);
-void SP_info_player_deathmatch (gentity_t *ent);
-void SP_info_player_intermission (gentity_t *ent);
-void SP_info_firstplace(gentity_t *ent);
-void SP_info_secondplace(gentity_t *ent);
-void SP_info_thirdplace(gentity_t *ent);
-void SP_info_podium(gentity_t *ent);
-
-void SP_func_plat (gentity_t *ent);
-void SP_func_static (gentity_t *ent);
-void SP_func_rotating (gentity_t *ent);
-void SP_func_bobbing (gentity_t *ent);
-void SP_func_pendulum( gentity_t *ent );
-void SP_func_button (gentity_t *ent);
-void SP_func_door (gentity_t *ent);
-void SP_func_train (gentity_t *ent);
-void SP_func_timer (gentity_t *self);
-
-void SP_trigger_always (gentity_t *ent);
-void SP_trigger_multiple (gentity_t *ent);
-void SP_trigger_push (gentity_t *ent);
-void SP_trigger_teleport (gentity_t *ent);
-void SP_trigger_hurt (gentity_t *ent);
-
-void SP_target_remove_powerups( gentity_t *ent );
-void SP_target_give (gentity_t *ent);
-void SP_target_delay (gentity_t *ent);
-void SP_target_speaker (gentity_t *ent);
-void SP_target_print (gentity_t *ent);
-void SP_target_laser (gentity_t *self);
-void SP_target_character (gentity_t *ent);
-void SP_target_score( gentity_t *ent );
-void SP_target_teleporter( gentity_t *ent );
-void SP_target_relay (gentity_t *ent);
-void SP_target_kill (gentity_t *ent);
-void SP_target_position (gentity_t *ent);
-void SP_target_location (gentity_t *ent);
-void SP_target_push (gentity_t *ent);
-
-void SP_light (gentity_t *self);
-void SP_info_null (gentity_t *self);
-void SP_info_notnull (gentity_t *self);
-void SP_info_camp (gentity_t *self);
-void SP_path_corner (gentity_t *self);
-
-void SP_misc_teleporter_dest (gentity_t *self);
-void SP_misc_model(gentity_t *ent);
-void SP_misc_portal_camera(gentity_t *ent);
-void SP_misc_portal_surface(gentity_t *ent);
-
-void SP_shooter_rocket( gentity_t *ent );
-void SP_shooter_plasma( gentity_t *ent );
-void SP_shooter_grenade( gentity_t *ent );
-
-void SP_team_CTF_redplayer( gentity_t *ent );
-void SP_team_CTF_blueplayer( gentity_t *ent );
-
-void SP_team_CTF_redspawn( gentity_t *ent );
-void SP_team_CTF_bluespawn( gentity_t *ent );
-
-#ifdef MISSIONPACK
-void SP_team_blueobelisk( gentity_t *ent );
-void SP_team_redobelisk( gentity_t *ent );
-void SP_team_neutralobelisk( gentity_t *ent );
-#endif
-void SP_item_botroam( gentity_t *ent ) { }
-
-spawn_t spawns[] = {
- // info entities don't do anything at all, but provide positional
- // information for things controlled by other processes
- {"info_player_start", SP_info_player_start},
- {"info_player_deathmatch", SP_info_player_deathmatch},
- {"info_player_intermission", SP_info_player_intermission},
- {"info_null", SP_info_null},
- {"info_notnull", SP_info_notnull}, // use target_position instead
- {"info_camp", SP_info_camp},
-
- {"func_plat", SP_func_plat},
- {"func_button", SP_func_button},
- {"func_door", SP_func_door},
- {"func_static", SP_func_static},
- {"func_rotating", SP_func_rotating},
- {"func_bobbing", SP_func_bobbing},
- {"func_pendulum", SP_func_pendulum},
- {"func_train", SP_func_train},
- {"func_group", SP_info_null},
- {"func_timer", SP_func_timer}, // rename trigger_timer?
-
- // Triggers are brush objects that cause an effect when contacted
- // by a living player, usually involving firing targets.
- // While almost everything could be done with
- // a single trigger class and different targets, triggered effects
- // could not be client side predicted (push and teleport).
- {"trigger_always", SP_trigger_always},
- {"trigger_multiple", SP_trigger_multiple},
- {"trigger_push", SP_trigger_push},
- {"trigger_teleport", SP_trigger_teleport},
- {"trigger_hurt", SP_trigger_hurt},
-
- // targets perform no action by themselves, but must be triggered
- // by another entity
- {"target_give", SP_target_give},
- {"target_remove_powerups", SP_target_remove_powerups},
- {"target_delay", SP_target_delay},
- {"target_speaker", SP_target_speaker},
- {"target_print", SP_target_print},
- {"target_laser", SP_target_laser},
- {"target_score", SP_target_score},
- {"target_teleporter", SP_target_teleporter},
- {"target_relay", SP_target_relay},
- {"target_kill", SP_target_kill},
- {"target_position", SP_target_position},
- {"target_location", SP_target_location},
- {"target_push", SP_target_push},
-
- {"light", SP_light},
- {"path_corner", SP_path_corner},
-
- {"misc_teleporter_dest", SP_misc_teleporter_dest},
- {"misc_model", SP_misc_model},
- {"misc_portal_surface", SP_misc_portal_surface},
- {"misc_portal_camera", SP_misc_portal_camera},
-
- {"shooter_rocket", SP_shooter_rocket},
- {"shooter_grenade", SP_shooter_grenade},
- {"shooter_plasma", SP_shooter_plasma},
-
- {"team_CTF_redplayer", SP_team_CTF_redplayer},
- {"team_CTF_blueplayer", SP_team_CTF_blueplayer},
-
- {"team_CTF_redspawn", SP_team_CTF_redspawn},
- {"team_CTF_bluespawn", SP_team_CTF_bluespawn},
-
-#ifdef MISSIONPACK
- {"team_redobelisk", SP_team_redobelisk},
- {"team_blueobelisk", SP_team_blueobelisk},
- {"team_neutralobelisk", SP_team_neutralobelisk},
-#endif
- {"item_botroam", SP_item_botroam},
-
- {NULL, 0}
-};
-
-/*
-===============
-G_CallSpawn
-
-Finds the spawn function for the entity and calls it,
-returning qfalse if not found
-===============
-*/
-qboolean G_CallSpawn( gentity_t *ent ) {
- spawn_t *s;
- gitem_t *item;
-
- if ( !ent->classname ) {
- G_Printf ("G_CallSpawn: NULL classname\n");
- return qfalse;
- }
-
- // check item spawn functions
- for ( item=bg_itemlist+1 ; item->classname ; item++ ) {
- if ( !strcmp(item->classname, ent->classname) ) {
- G_SpawnItem( ent, item );
- return qtrue;
- }
- }
-
- // check normal spawn functions
- for ( s=spawns ; s->name ; s++ ) {
- if ( !strcmp(s->name, ent->classname) ) {
- // found it
- s->spawn(ent);
- return qtrue;
- }
- }
- G_Printf ("%s doesn't have a spawn function\n", ent->classname);
- return qfalse;
-}
-
-/*
-=============
-G_NewString
-
-Builds a copy of the string, translating \n to real linefeeds
-so message texts can be multi-line
-=============
-*/
-char *G_NewString( const char *string ) {
- char *newb, *new_p;
- int i,l;
-
- l = strlen(string) + 1;
-
- newb = G_Alloc( l );
-
- new_p = newb;
-
- // turn \n into a real linefeed
- for ( i=0 ; i< l ; i++ ) {
- if (string[i] == '\\' && i < l-1) {
- i++;
- if (string[i] == 'n') {
- *new_p++ = '\n';
- } else {
- *new_p++ = '\\';
- }
- } else {
- *new_p++ = string[i];
- }
- }
-
- return newb;
-}
-
-
-
-
-/*
-===============
-G_ParseField
-
-Takes a key/value pair and sets the binary values
-in a gentity
-===============
-*/
-void G_ParseField( const char *key, const char *value, gentity_t *ent ) {
- field_t *f;
- byte *b;
- float v;
- vec3_t vec;
-
- for ( f=fields ; f->name ; f++ ) {
- if ( !Q_stricmp(f->name, key) ) {
- // found it
- b = (byte *)ent;
-
- switch( f->type ) {
- case F_LSTRING:
- *(char **)(b+f->ofs) = G_NewString (value);
- break;
- case F_VECTOR:
- sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
- ((float *)(b+f->ofs))[0] = vec[0];
- ((float *)(b+f->ofs))[1] = vec[1];
- ((float *)(b+f->ofs))[2] = vec[2];
- break;
- case F_INT:
- *(int *)(b+f->ofs) = atoi(value);
- break;
- case F_FLOAT:
- *(float *)(b+f->ofs) = atof(value);
- break;
- case F_ANGLEHACK:
- v = atof(value);
- ((float *)(b+f->ofs))[0] = 0;
- ((float *)(b+f->ofs))[1] = v;
- ((float *)(b+f->ofs))[2] = 0;
- break;
- default:
- case F_IGNORE:
- break;
- }
- return;
- }
- }
-}
-
-
-
-
-/*
-===================
-G_SpawnGEntityFromSpawnVars
-
-Spawn an entity and fill in all of the level fields from
-level.spawnVars[], then call the class specfic spawn function
-===================
-*/
-void G_SpawnGEntityFromSpawnVars( void ) {
- int i;
- gentity_t *ent;
- char *s, *value, *gametypeName;
- static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester", "teamtournament"};
-
- // get the next free entity
- ent = G_Spawn();
-
- for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
- G_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], ent );
- }
-
- // check for "notsingle" flag
- if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
- G_SpawnInt( "notsingle", "0", &i );
- if ( i ) {
- G_FreeEntity( ent );
- return;
- }
- }
- // check for "notteam" flag (GT_FFA, GT_TOURNAMENT, GT_SINGLE_PLAYER)
- if ( g_gametype.integer >= GT_TEAM ) {
- G_SpawnInt( "notteam", "0", &i );
- if ( i ) {
- G_FreeEntity( ent );
- return;
- }
- } else {
- G_SpawnInt( "notfree", "0", &i );
- if ( i ) {
- G_FreeEntity( ent );
- return;
- }
- }
-
-#ifdef MISSIONPACK
- G_SpawnInt( "notta", "0", &i );
- if ( i ) {
- G_FreeEntity( ent );
- return;
- }
-#else
- G_SpawnInt( "notq3a", "0", &i );
- if ( i ) {
- G_FreeEntity( ent );
- return;
- }
-#endif
-
- if( G_SpawnString( "gametype", NULL, &value ) ) {
- if( g_gametype.integer >= GT_FFA && g_gametype.integer < GT_MAX_GAME_TYPE ) {
- gametypeName = gametypeNames[g_gametype.integer];
-
- s = strstr( value, gametypeName );
- if( !s ) {
- G_FreeEntity( ent );
- return;
- }
- }
- }
-
- // move editor origin to pos
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.origin, ent->r.currentOrigin );
-
- // if we didn't get a classname, don't bother spawning anything
- if ( !G_CallSpawn( ent ) ) {
- G_FreeEntity( ent );
- }
-}
-
-
-
-/*
-====================
-G_AddSpawnVarToken
-====================
-*/
-char *G_AddSpawnVarToken( const char *string ) {
- int l;
- char *dest;
-
- l = strlen( string );
- if ( level.numSpawnVarChars + l + 1 > MAX_SPAWN_VARS_CHARS ) {
- G_Error( "G_AddSpawnVarToken: MAX_SPAWN_CHARS" );
- }
-
- dest = level.spawnVarChars + level.numSpawnVarChars;
- memcpy( dest, string, l+1 );
-
- level.numSpawnVarChars += l + 1;
-
- return dest;
-}
-
-/*
-====================
-G_ParseSpawnVars
-
-Parses a brace bounded set of key / value pairs out of the
-level's entity strings into level.spawnVars[]
-
-This does not actually spawn an entity.
-====================
-*/
-qboolean G_ParseSpawnVars( void ) {
- char keyname[MAX_TOKEN_CHARS];
- char com_token[MAX_TOKEN_CHARS];
-
- level.numSpawnVars = 0;
- level.numSpawnVarChars = 0;
-
- // parse the opening brace
- if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
- // end of spawn string
- return qfalse;
- }
- if ( com_token[0] != '{' ) {
- G_Error( "G_ParseSpawnVars: found %s when expecting {",com_token );
- }
-
- // go through all the key / value pairs
- while ( 1 ) {
- // parse key
- if ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) {
- G_Error( "G_ParseSpawnVars: EOF without closing brace" );
- }
-
- if ( keyname[0] == '}' ) {
- break;
- }
-
- // parse value
- if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
- G_Error( "G_ParseSpawnVars: EOF without closing brace" );
- }
-
- if ( com_token[0] == '}' ) {
- G_Error( "G_ParseSpawnVars: closing brace without data" );
- }
- if ( level.numSpawnVars == MAX_SPAWN_VARS ) {
- G_Error( "G_ParseSpawnVars: MAX_SPAWN_VARS" );
- }
- level.spawnVars[ level.numSpawnVars ][0] = G_AddSpawnVarToken( keyname );
- level.spawnVars[ level.numSpawnVars ][1] = G_AddSpawnVarToken( com_token );
- level.numSpawnVars++;
- }
-
- return qtrue;
-}
-
-
-
-/*QUAKED worldspawn (0 0 0) ?
-
-Every map should have exactly one worldspawn.
-"music" music wav file
-"gravity" 800 is default gravity
-"message" Text to print during connection process
-*/
-void SP_worldspawn( void ) {
- char *s;
-
- G_SpawnString( "classname", "", &s );
- if ( Q_stricmp( s, "worldspawn" ) ) {
- G_Error( "SP_worldspawn: The first entity isn't 'worldspawn'" );
- }
-
- // make some data visible to connecting client
- trap_SetConfigstring( CS_GAME_VERSION, GAME_VERSION );
-
- trap_SetConfigstring( CS_LEVEL_START_TIME, va("%i", level.startTime ) );
-
- G_SpawnString( "music", "", &s );
- trap_SetConfigstring( CS_MUSIC, s );
-
- G_SpawnString( "message", "", &s );
- trap_SetConfigstring( CS_MESSAGE, s ); // map specific message
-
- trap_SetConfigstring( CS_MOTD, g_motd.string ); // message of the day
-
- G_SpawnString( "gravity", "800", &s );
- trap_Cvar_Set( "g_gravity", s );
-
- G_SpawnString( "enableDust", "0", &s );
- trap_Cvar_Set( "g_enableDust", s );
-
- G_SpawnString( "enableBreath", "0", &s );
- trap_Cvar_Set( "g_enableBreath", s );
-
- g_entities[ENTITYNUM_WORLD].s.number = ENTITYNUM_WORLD;
- g_entities[ENTITYNUM_WORLD].classname = "worldspawn";
-
- // see if we want a warmup time
- trap_SetConfigstring( CS_WARMUP, "" );
- if ( g_restarted.integer ) {
- trap_Cvar_Set( "g_restarted", "0" );
- level.warmupTime = 0;
- } else if ( g_doWarmup.integer ) { // Turn it on
- level.warmupTime = -1;
- trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
- G_LogPrintf( "Warmup:\n" );
- }
-
-}
-
-
-/*
-==============
-G_SpawnEntitiesFromString
-
-Parses textual entity definitions out of an entstring and spawns gentities.
-==============
-*/
-void G_SpawnEntitiesFromString( void ) {
- // allow calls to G_Spawn*()
- level.spawning = qtrue;
- level.numSpawnVars = 0;
-
- // the worldspawn is not an actual entity, but it still
- // has a "spawn" function to perform any global setup
- // needed by a level (setting configstrings or cvars, etc)
- if ( !G_ParseSpawnVars() ) {
- G_Error( "SpawnEntities: no entities" );
- }
- SP_worldspawn();
-
- // parse ents
- while( G_ParseSpawnVars() ) {
- G_SpawnGEntityFromSpawnVars();
- }
-
- level.spawning = qfalse; // any future calls to G_Spawn*() will be errors
-}
-
diff --git a/engine/code/game/g_svcmds.c b/engine/code/game/g_svcmds.c
deleted file mode 100644
index 705afd7..0000000
--- a/engine/code/game/g_svcmds.c
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-// this file holds commands that can be executed by the server console, but not remote clients
-
-#include "g_local.h"
-
-
-/*
-==============================================================================
-
-PACKET FILTERING
-
-
-You can add or remove addresses from the filter list with:
-
-addip <ip>
-removeip <ip>
-
-The ip address is specified in dot format, and you can use '*' to match any value
-so you can specify an entire class C network with "addip 192.246.40.*"
-
-Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host.
-
-listip
-Prints the current list of filters.
-
-g_filterban <0 or 1>
-
-If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game. This is the default setting.
-
-If 0, then only addresses matching the list will be allowed. This lets you easily set up a private game, or a game that only allows players from your local network.
-
-TTimo NOTE: for persistence, bans are stored in g_banIPs cvar MAX_CVAR_VALUE_STRING
-The size of the cvar string buffer is limiting the banning to around 20 masks
-this could be improved by putting some g_banIPs2 g_banIps3 etc. maybe
-still, you should rely on PB for banning instead
-
-==============================================================================
-*/
-
-typedef struct ipFilter_s
-{
- unsigned mask;
- unsigned compare;
-} ipFilter_t;
-
-#define MAX_IPFILTERS 1024
-
-static ipFilter_t ipFilters[MAX_IPFILTERS];
-static int numIPFilters;
-
-/*
-=================
-StringToFilter
-=================
-*/
-static qboolean StringToFilter (char *s, ipFilter_t *f)
-{
- char num[128];
- int i, j;
- byte b[4];
- byte m[4];
-
- for (i=0 ; i<4 ; i++)
- {
- b[i] = 0;
- m[i] = 0;
- }
-
- for (i=0 ; i<4 ; i++)
- {
- if (*s < '0' || *s > '9')
- {
- if (*s == '*') // 'match any'
- {
- // b[i] and m[i] to 0
- s++;
- if (!*s)
- break;
- s++;
- continue;
- }
- G_Printf( "Bad filter address: %s\n", s );
- return qfalse;
- }
-
- j = 0;
- while (*s >= '0' && *s <= '9')
- {
- num[j++] = *s++;
- }
- num[j] = 0;
- b[i] = atoi(num);
- m[i] = 255;
-
- if (!*s)
- break;
- s++;
- }
-
- f->mask = *(unsigned *)m;
- f->compare = *(unsigned *)b;
-
- return qtrue;
-}
-
-/*
-=================
-UpdateIPBans
-=================
-*/
-static void UpdateIPBans (void)
-{
- byte b[4];
- byte m[4];
- int i,j;
- char iplist_final[MAX_CVAR_VALUE_STRING];
- char ip[64];
-
- *iplist_final = 0;
- for (i = 0 ; i < numIPFilters ; i++)
- {
- if (ipFilters[i].compare == 0xffffffff)
- continue;
-
- *(unsigned *)b = ipFilters[i].compare;
- *(unsigned *)m = ipFilters[i].mask;
- *ip = 0;
- for (j = 0 ; j < 4 ; j++)
- {
- if (m[j]!=255)
- Q_strcat(ip, sizeof(ip), "*");
- else
- Q_strcat(ip, sizeof(ip), va("%i", b[j]));
- Q_strcat(ip, sizeof(ip), (j<3) ? "." : " ");
- }
- if (strlen(iplist_final)+strlen(ip) < MAX_CVAR_VALUE_STRING)
- {
- Q_strcat( iplist_final, sizeof(iplist_final), ip);
- }
- else
- {
- Com_Printf("g_banIPs overflowed at MAX_CVAR_VALUE_STRING\n");
- break;
- }
- }
-
- trap_Cvar_Set( "g_banIPs", iplist_final );
-}
-
-/*
-=================
-G_FilterPacket
-=================
-*/
-qboolean G_FilterPacket (char *from)
-{
- int i;
- unsigned in;
- byte m[4];
- char *p;
-
- i = 0;
- p = from;
- while (*p && i < 4) {
- m[i] = 0;
- while (*p >= '0' && *p <= '9') {
- m[i] = m[i]*10 + (*p - '0');
- p++;
- }
- if (!*p || *p == ':')
- break;
- i++, p++;
- }
-
- in = *(unsigned *)m;
-
- for (i=0 ; i<numIPFilters ; i++)
- if ( (in & ipFilters[i].mask) == ipFilters[i].compare)
- return g_filterBan.integer != 0;
-
- return g_filterBan.integer == 0;
-}
-
-/*
-=================
-AddIP
-=================
-*/
-static void AddIP( char *str )
-{
- int i;
-
- for (i = 0 ; i < numIPFilters ; i++)
- if (ipFilters[i].compare == 0xffffffff)
- break; // free spot
- if (i == numIPFilters)
- {
- if (numIPFilters == MAX_IPFILTERS)
- {
- G_Printf ("IP filter list is full\n");
- return;
- }
- numIPFilters++;
- }
-
- if (!StringToFilter (str, &ipFilters[i]))
- ipFilters[i].compare = 0xffffffffu;
-
- UpdateIPBans();
-}
-
-/*
-=================
-G_ProcessIPBans
-=================
-*/
-void G_ProcessIPBans(void)
-{
- char *s, *t;
- char str[MAX_CVAR_VALUE_STRING];
-
- Q_strncpyz( str, g_banIPs.string, sizeof(str) );
-
- for (t = s = g_banIPs.string; *t; /* */ ) {
- s = strchr(s, ' ');
- if (!s)
- break;
- while (*s == ' ')
- *s++ = 0;
- if (*t)
- AddIP( t );
- t = s;
- }
-}
-
-
-/*
-=================
-Svcmd_AddIP_f
-=================
-*/
-void Svcmd_AddIP_f (void)
-{
- char str[MAX_TOKEN_CHARS];
-
- if ( trap_Argc() < 2 ) {
- G_Printf("Usage: addip <ip-mask>\n");
- return;
- }
-
- trap_Argv( 1, str, sizeof( str ) );
-
- AddIP( str );
-
-}
-
-/*
-=================
-Svcmd_RemoveIP_f
-=================
-*/
-void Svcmd_RemoveIP_f (void)
-{
- ipFilter_t f;
- int i;
- char str[MAX_TOKEN_CHARS];
-
- if ( trap_Argc() < 2 ) {
- G_Printf("Usage: sv removeip <ip-mask>\n");
- return;
- }
-
- trap_Argv( 1, str, sizeof( str ) );
-
- if (!StringToFilter (str, &f))
- return;
-
- for (i=0 ; i<numIPFilters ; i++) {
- if (ipFilters[i].mask == f.mask &&
- ipFilters[i].compare == f.compare) {
- ipFilters[i].compare = 0xffffffffu;
- G_Printf ("Removed.\n");
-
- UpdateIPBans();
- return;
- }
- }
-
- G_Printf ( "Didn't find %s.\n", str );
-}
-
-/*
-===================
-Svcmd_EntityList_f
-===================
-*/
-void Svcmd_EntityList_f (void) {
- int e;
- gentity_t *check;
-
- check = g_entities+1;
- for (e = 1; e < level.num_entities ; e++, check++) {
- if ( !check->inuse ) {
- continue;
- }
- G_Printf("%3i:", e);
- switch ( check->s.eType ) {
- case ET_GENERAL:
- G_Printf("ET_GENERAL ");
- break;
- case ET_PLAYER:
- G_Printf("ET_PLAYER ");
- break;
- case ET_ITEM:
- G_Printf("ET_ITEM ");
- break;
- case ET_MISSILE:
- G_Printf("ET_MISSILE ");
- break;
- case ET_MOVER:
- G_Printf("ET_MOVER ");
- break;
- case ET_BEAM:
- G_Printf("ET_BEAM ");
- break;
- case ET_PORTAL:
- G_Printf("ET_PORTAL ");
- break;
- case ET_SPEAKER:
- G_Printf("ET_SPEAKER ");
- break;
- case ET_PUSH_TRIGGER:
- G_Printf("ET_PUSH_TRIGGER ");
- break;
- case ET_TELEPORT_TRIGGER:
- G_Printf("ET_TELEPORT_TRIGGER ");
- break;
- case ET_INVISIBLE:
- G_Printf("ET_INVISIBLE ");
- break;
- case ET_GRAPPLE:
- G_Printf("ET_GRAPPLE ");
- break;
- default:
- G_Printf("%3i ", check->s.eType);
- break;
- }
-
- if ( check->classname ) {
- G_Printf("%s", check->classname);
- }
- G_Printf("\n");
- }
-}
-
-gclient_t *ClientForString( const char *s ) {
- gclient_t *cl;
- int i;
- int idnum;
-
- // numeric values are just slot numbers
- if ( s[0] >= '0' && s[0] <= '9' ) {
- idnum = atoi( s );
- if ( idnum < 0 || idnum >= level.maxclients ) {
- Com_Printf( "Bad client slot: %i\n", idnum );
- return NULL;
- }
-
- cl = &level.clients[idnum];
- if ( cl->pers.connected == CON_DISCONNECTED ) {
- G_Printf( "Client %i is not connected\n", idnum );
- return NULL;
- }
- return cl;
- }
-
- // check for a name match
- for ( i=0 ; i < level.maxclients ; i++ ) {
- cl = &level.clients[i];
- if ( cl->pers.connected == CON_DISCONNECTED ) {
- continue;
- }
- if ( !Q_stricmp( cl->pers.netname, s ) ) {
- return cl;
- }
- }
-
- G_Printf( "User %s is not on the server\n", s );
-
- return NULL;
-}
-
-/*
-===================
-Svcmd_ForceTeam_f
-
-forceteam <player> <team>
-===================
-*/
-void Svcmd_ForceTeam_f( void ) {
- gclient_t *cl;
- char str[MAX_TOKEN_CHARS];
-
- // find the player
- trap_Argv( 1, str, sizeof( str ) );
- cl = ClientForString( str );
- if ( !cl ) {
- return;
- }
-
- // set the team
- trap_Argv( 2, str, sizeof( str ) );
- SetTeam( &g_entities[cl - level.clients], str );
-}
-
-char *ConcatArgs( int start );
-
-/*
-=================
-ConsoleCommand
-
-=================
-*/
-qboolean ConsoleCommand( void ) {
- char cmd[MAX_TOKEN_CHARS];
-
- trap_Argv( 0, cmd, sizeof( cmd ) );
-
- if ( Q_stricmp (cmd, "entitylist") == 0 ) {
- Svcmd_EntityList_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "forceteam") == 0 ) {
- Svcmd_ForceTeam_f();
- return qtrue;
- }
-
- if (Q_stricmp (cmd, "game_memory") == 0) {
- Svcmd_GameMem_f();
- return qtrue;
- }
-
- if (Q_stricmp (cmd, "addbot") == 0) {
- Svcmd_AddBot_f();
- return qtrue;
- }
-
- if (Q_stricmp (cmd, "botlist") == 0) {
- Svcmd_BotList_f();
- return qtrue;
- }
-
- if (Q_stricmp (cmd, "abort_podium") == 0) {
- Svcmd_AbortPodium_f();
- return qtrue;
- }
-
- if (Q_stricmp (cmd, "addip") == 0) {
- Svcmd_AddIP_f();
- return qtrue;
- }
-
- if (Q_stricmp (cmd, "removeip") == 0) {
- Svcmd_RemoveIP_f();
- return qtrue;
- }
-
- if (Q_stricmp (cmd, "listip") == 0) {
- trap_SendConsoleCommand( EXEC_NOW, "g_banIPs\n" );
- return qtrue;
- }
-
- if (g_dedicated.integer) {
- if (Q_stricmp (cmd, "say") == 0) {
- trap_SendServerCommand( -1, va("print \"server: %s\"", ConcatArgs(1) ) );
- return qtrue;
- }
- // everything else will also be printed as a say command
- trap_SendServerCommand( -1, va("print \"server: %s\"", ConcatArgs(0) ) );
- return qtrue;
- }
-
- return qfalse;
-}
-
diff --git a/engine/code/game/g_syscalls.c b/engine/code/game/g_syscalls.c
deleted file mode 100644
index 1868d0a..0000000
--- a/engine/code/game/g_syscalls.c
+++ /dev/null
@@ -1,790 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-// this file is only included when building a dll
-// g_syscalls.asm is included instead when building a qvm
-#ifdef Q3_VM
-#error "Do not use in VM build"
-#endif
-
-static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;
-
-
-Q_EXPORT void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) {
- syscall = syscallptr;
-}
-
-int PASSFLOAT( float x ) {
- floatint_t fi;
- fi.f = x;
- return fi.i;
-}
-
-void trap_Printf( const char *fmt ) {
- syscall( G_PRINT, fmt );
-}
-
-void trap_Error( const char *fmt ) {
- syscall( G_ERROR, fmt );
-}
-
-int trap_Milliseconds( void ) {
- return syscall( G_MILLISECONDS );
-}
-int trap_Argc( void ) {
- return syscall( G_ARGC );
-}
-
-void trap_Argv( int n, char *buffer, int bufferLength ) {
- syscall( G_ARGV, n, buffer, bufferLength );
-}
-
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
- return syscall( G_FS_FOPEN_FILE, qpath, f, mode );
-}
-
-void trap_FS_Read( void *buffer, int len, fileHandle_t f ) {
- syscall( G_FS_READ, buffer, len, f );
-}
-
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f ) {
- syscall( G_FS_WRITE, buffer, len, f );
-}
-
-void trap_FS_FCloseFile( fileHandle_t f ) {
- syscall( G_FS_FCLOSE_FILE, f );
-}
-
-int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ) {
- return syscall( G_FS_GETFILELIST, path, extension, listbuf, bufsize );
-}
-
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ) {
- return syscall( G_FS_SEEK, f, offset, origin );
-}
-
-void trap_SendConsoleCommand( int exec_when, const char *text ) {
- syscall( G_SEND_CONSOLE_COMMAND, exec_when, text );
-}
-
-void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags ) {
- syscall( G_CVAR_REGISTER, cvar, var_name, value, flags );
-}
-
-void trap_Cvar_Update( vmCvar_t *cvar ) {
- syscall( G_CVAR_UPDATE, cvar );
-}
-
-void trap_Cvar_Set( const char *var_name, const char *value ) {
- syscall( G_CVAR_SET, var_name, value );
-}
-
-int trap_Cvar_VariableIntegerValue( const char *var_name ) {
- return syscall( G_CVAR_VARIABLE_INTEGER_VALUE, var_name );
-}
-
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
- syscall( G_CVAR_VARIABLE_STRING_BUFFER, var_name, buffer, bufsize );
-}
-
-
-void trap_LocateGameData( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
- playerState_t *clients, int sizeofGClient ) {
- syscall( G_LOCATE_GAME_DATA, gEnts, numGEntities, sizeofGEntity_t, clients, sizeofGClient );
-}
-
-void trap_DropClient( int clientNum, const char *reason ) {
- syscall( G_DROP_CLIENT, clientNum, reason );
-}
-
-void trap_SendServerCommand( int clientNum, const char *text ) {
- syscall( G_SEND_SERVER_COMMAND, clientNum, text );
-}
-
-void trap_SetConfigstring( int num, const char *string ) {
- syscall( G_SET_CONFIGSTRING, num, string );
-}
-
-void trap_GetConfigstring( int num, char *buffer, int bufferSize ) {
- syscall( G_GET_CONFIGSTRING, num, buffer, bufferSize );
-}
-
-void trap_GetUserinfo( int num, char *buffer, int bufferSize ) {
- syscall( G_GET_USERINFO, num, buffer, bufferSize );
-}
-
-void trap_SetUserinfo( int num, const char *buffer ) {
- syscall( G_SET_USERINFO, num, buffer );
-}
-
-void trap_GetServerinfo( char *buffer, int bufferSize ) {
- syscall( G_GET_SERVERINFO, buffer, bufferSize );
-}
-
-void trap_SetBrushModel( gentity_t *ent, const char *name ) {
- syscall( G_SET_BRUSH_MODEL, ent, name );
-}
-
-void trap_Trace( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask ) {
- syscall( G_TRACE, results, start, mins, maxs, end, passEntityNum, contentmask );
-}
-
-void trap_TraceCapsule( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask ) {
- syscall( G_TRACECAPSULE, results, start, mins, maxs, end, passEntityNum, contentmask );
-}
-
-int trap_PointContents( const vec3_t point, int passEntityNum ) {
- return syscall( G_POINT_CONTENTS, point, passEntityNum );
-}
-
-
-qboolean trap_InPVS( const vec3_t p1, const vec3_t p2 ) {
- return syscall( G_IN_PVS, p1, p2 );
-}
-
-qboolean trap_InPVSIgnorePortals( const vec3_t p1, const vec3_t p2 ) {
- return syscall( G_IN_PVS_IGNORE_PORTALS, p1, p2 );
-}
-
-void trap_AdjustAreaPortalState( gentity_t *ent, qboolean open ) {
- syscall( G_ADJUST_AREA_PORTAL_STATE, ent, open );
-}
-
-qboolean trap_AreasConnected( int area1, int area2 ) {
- return syscall( G_AREAS_CONNECTED, area1, area2 );
-}
-
-void trap_LinkEntity( gentity_t *ent ) {
- syscall( G_LINKENTITY, ent );
-}
-
-void trap_UnlinkEntity( gentity_t *ent ) {
- syscall( G_UNLINKENTITY, ent );
-}
-
-int trap_EntitiesInBox( const vec3_t mins, const vec3_t maxs, int *list, int maxcount ) {
- return syscall( G_ENTITIES_IN_BOX, mins, maxs, list, maxcount );
-}
-
-qboolean trap_EntityContact( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ) {
- return syscall( G_ENTITY_CONTACT, mins, maxs, ent );
-}
-
-qboolean trap_EntityContactCapsule( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ) {
- return syscall( G_ENTITY_CONTACTCAPSULE, mins, maxs, ent );
-}
-
-int trap_BotAllocateClient( void ) {
- return syscall( G_BOT_ALLOCATE_CLIENT );
-}
-
-void trap_BotFreeClient( int clientNum ) {
- syscall( G_BOT_FREE_CLIENT, clientNum );
-}
-
-void trap_GetUsercmd( int clientNum, usercmd_t *cmd ) {
- syscall( G_GET_USERCMD, clientNum, cmd );
-}
-
-qboolean trap_GetEntityToken( char *buffer, int bufferSize ) {
- return syscall( G_GET_ENTITY_TOKEN, buffer, bufferSize );
-}
-
-int trap_DebugPolygonCreate(int color, int numPoints, vec3_t *points) {
- return syscall( G_DEBUG_POLYGON_CREATE, color, numPoints, points );
-}
-
-void trap_DebugPolygonDelete(int id) {
- syscall( G_DEBUG_POLYGON_DELETE, id );
-}
-
-int trap_RealTime( qtime_t *qtime ) {
- return syscall( G_REAL_TIME, qtime );
-}
-
-void trap_SnapVector( float *v ) {
- syscall( G_SNAPVECTOR, v );
- return;
-}
-
-// BotLib traps start here
-int trap_BotLibSetup( void ) {
- return syscall( BOTLIB_SETUP );
-}
-
-int trap_BotLibShutdown( void ) {
- return syscall( BOTLIB_SHUTDOWN );
-}
-
-int trap_BotLibVarSet(char *var_name, char *value) {
- return syscall( BOTLIB_LIBVAR_SET, var_name, value );
-}
-
-int trap_BotLibVarGet(char *var_name, char *value, int size) {
- return syscall( BOTLIB_LIBVAR_GET, var_name, value, size );
-}
-
-int trap_BotLibDefine(char *string) {
- return syscall( BOTLIB_PC_ADD_GLOBAL_DEFINE, string );
-}
-
-int trap_BotLibStartFrame(float time) {
- return syscall( BOTLIB_START_FRAME, PASSFLOAT( time ) );
-}
-
-int trap_BotLibLoadMap(const char *mapname) {
- return syscall( BOTLIB_LOAD_MAP, mapname );
-}
-
-int trap_BotLibUpdateEntity(int ent, void /* struct bot_updateentity_s */ *bue) {
- return syscall( BOTLIB_UPDATENTITY, ent, bue );
-}
-
-int trap_BotLibTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3) {
- return syscall( BOTLIB_TEST, parm0, parm1, parm2, parm3 );
-}
-
-int trap_BotGetSnapshotEntity( int clientNum, int sequence ) {
- return syscall( BOTLIB_GET_SNAPSHOT_ENTITY, clientNum, sequence );
-}
-
-int trap_BotGetServerCommand(int clientNum, char *message, int size) {
- return syscall( BOTLIB_GET_CONSOLE_MESSAGE, clientNum, message, size );
-}
-
-void trap_BotUserCommand(int clientNum, usercmd_t *ucmd) {
- syscall( BOTLIB_USER_COMMAND, clientNum, ucmd );
-}
-
-void trap_AAS_EntityInfo(int entnum, void /* struct aas_entityinfo_s */ *info) {
- syscall( BOTLIB_AAS_ENTITY_INFO, entnum, info );
-}
-
-int trap_AAS_Initialized(void) {
- return syscall( BOTLIB_AAS_INITIALIZED );
-}
-
-void trap_AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs) {
- syscall( BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX, presencetype, mins, maxs );
-}
-
-float trap_AAS_Time(void) {
- floatint_t fi;
- fi.i = syscall( BOTLIB_AAS_TIME );
- return fi.f;
-}
-
-int trap_AAS_PointAreaNum(vec3_t point) {
- return syscall( BOTLIB_AAS_POINT_AREA_NUM, point );
-}
-
-int trap_AAS_PointReachabilityAreaIndex(vec3_t point) {
- return syscall( BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX, point );
-}
-
-int trap_AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas) {
- return syscall( BOTLIB_AAS_TRACE_AREAS, start, end, areas, points, maxareas );
-}
-
-int trap_AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas) {
- return syscall( BOTLIB_AAS_BBOX_AREAS, absmins, absmaxs, areas, maxareas );
-}
-
-int trap_AAS_AreaInfo( int areanum, void /* struct aas_areainfo_s */ *info ) {
- return syscall( BOTLIB_AAS_AREA_INFO, areanum, info );
-}
-
-int trap_AAS_PointContents(vec3_t point) {
- return syscall( BOTLIB_AAS_POINT_CONTENTS, point );
-}
-
-int trap_AAS_NextBSPEntity(int ent) {
- return syscall( BOTLIB_AAS_NEXT_BSP_ENTITY, ent );
-}
-
-int trap_AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size) {
- return syscall( BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY, ent, key, value, size );
-}
-
-int trap_AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v) {
- return syscall( BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY, ent, key, v );
-}
-
-int trap_AAS_FloatForBSPEpairKey(int ent, char *key, float *value) {
- return syscall( BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY, ent, key, value );
-}
-
-int trap_AAS_IntForBSPEpairKey(int ent, char *key, int *value) {
- return syscall( BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY, ent, key, value );
-}
-
-int trap_AAS_AreaReachability(int areanum) {
- return syscall( BOTLIB_AAS_AREA_REACHABILITY, areanum );
-}
-
-int trap_AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags) {
- return syscall( BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA, areanum, origin, goalareanum, travelflags );
-}
-
-int trap_AAS_EnableRoutingArea( int areanum, int enable ) {
- return syscall( BOTLIB_AAS_ENABLE_ROUTING_AREA, areanum, enable );
-}
-
-int trap_AAS_PredictRoute(void /*struct aas_predictroute_s*/ *route, int areanum, vec3_t origin,
- int goalareanum, int travelflags, int maxareas, int maxtime,
- int stopevent, int stopcontents, int stoptfl, int stopareanum) {
- return syscall( BOTLIB_AAS_PREDICT_ROUTE, route, areanum, origin, goalareanum, travelflags, maxareas, maxtime, stopevent, stopcontents, stoptfl, stopareanum );
-}
-
-int trap_AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,
- void /*struct aas_altroutegoal_s*/ *altroutegoals, int maxaltroutegoals,
- int type) {
- return syscall( BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL, start, startareanum, goal, goalareanum, travelflags, altroutegoals, maxaltroutegoals, type );
-}
-
-int trap_AAS_Swimming(vec3_t origin) {
- return syscall( BOTLIB_AAS_SWIMMING, origin );
-}
-
-int trap_AAS_PredictClientMovement(void /* struct aas_clientmove_s */ *move, int entnum, vec3_t origin, int presencetype, int onground, vec3_t velocity, vec3_t cmdmove, int cmdframes, int maxframes, float frametime, int stopevent, int stopareanum, int visualize) {
- return syscall( BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT, move, entnum, origin, presencetype, onground, velocity, cmdmove, cmdframes, maxframes, PASSFLOAT(frametime), stopevent, stopareanum, visualize );
-}
-
-void trap_EA_Say(int client, char *str) {
- syscall( BOTLIB_EA_SAY, client, str );
-}
-
-void trap_EA_SayTeam(int client, char *str) {
- syscall( BOTLIB_EA_SAY_TEAM, client, str );
-}
-
-void trap_EA_Command(int client, char *command) {
- syscall( BOTLIB_EA_COMMAND, client, command );
-}
-
-void trap_EA_Action(int client, int action) {
- syscall( BOTLIB_EA_ACTION, client, action );
-}
-
-void trap_EA_Gesture(int client) {
- syscall( BOTLIB_EA_GESTURE, client );
-}
-
-void trap_EA_Talk(int client) {
- syscall( BOTLIB_EA_TALK, client );
-}
-
-void trap_EA_Attack(int client) {
- syscall( BOTLIB_EA_ATTACK, client );
-}
-
-void trap_EA_Use(int client) {
- syscall( BOTLIB_EA_USE, client );
-}
-
-void trap_EA_Respawn(int client) {
- syscall( BOTLIB_EA_RESPAWN, client );
-}
-
-void trap_EA_Crouch(int client) {
- syscall( BOTLIB_EA_CROUCH, client );
-}
-
-void trap_EA_MoveUp(int client) {
- syscall( BOTLIB_EA_MOVE_UP, client );
-}
-
-void trap_EA_MoveDown(int client) {
- syscall( BOTLIB_EA_MOVE_DOWN, client );
-}
-
-void trap_EA_MoveForward(int client) {
- syscall( BOTLIB_EA_MOVE_FORWARD, client );
-}
-
-void trap_EA_MoveBack(int client) {
- syscall( BOTLIB_EA_MOVE_BACK, client );
-}
-
-void trap_EA_MoveLeft(int client) {
- syscall( BOTLIB_EA_MOVE_LEFT, client );
-}
-
-void trap_EA_MoveRight(int client) {
- syscall( BOTLIB_EA_MOVE_RIGHT, client );
-}
-
-void trap_EA_SelectWeapon(int client, int weapon) {
- syscall( BOTLIB_EA_SELECT_WEAPON, client, weapon );
-}
-
-void trap_EA_Jump(int client) {
- syscall( BOTLIB_EA_JUMP, client );
-}
-
-void trap_EA_DelayedJump(int client) {
- syscall( BOTLIB_EA_DELAYED_JUMP, client );
-}
-
-void trap_EA_Move(int client, vec3_t dir, float speed) {
- syscall( BOTLIB_EA_MOVE, client, dir, PASSFLOAT(speed) );
-}
-
-void trap_EA_View(int client, vec3_t viewangles) {
- syscall( BOTLIB_EA_VIEW, client, viewangles );
-}
-
-void trap_EA_EndRegular(int client, float thinktime) {
- syscall( BOTLIB_EA_END_REGULAR, client, PASSFLOAT(thinktime) );
-}
-
-void trap_EA_GetInput(int client, float thinktime, void /* struct bot_input_s */ *input) {
- syscall( BOTLIB_EA_GET_INPUT, client, PASSFLOAT(thinktime), input );
-}
-
-void trap_EA_ResetInput(int client) {
- syscall( BOTLIB_EA_RESET_INPUT, client );
-}
-
-int trap_BotLoadCharacter(char *charfile, float skill) {
- return syscall( BOTLIB_AI_LOAD_CHARACTER, charfile, PASSFLOAT(skill));
-}
-
-void trap_BotFreeCharacter(int character) {
- syscall( BOTLIB_AI_FREE_CHARACTER, character );
-}
-
-float trap_Characteristic_Float(int character, int index) {
- floatint_t fi;
- fi.i = syscall( BOTLIB_AI_CHARACTERISTIC_FLOAT, character, index );
- return fi.f;
-}
-
-float trap_Characteristic_BFloat(int character, int index, float min, float max) {
- floatint_t fi;
- fi.i = syscall( BOTLIB_AI_CHARACTERISTIC_BFLOAT, character, index, PASSFLOAT(min), PASSFLOAT(max) );
- return fi.f;
-}
-
-int trap_Characteristic_Integer(int character, int index) {
- return syscall( BOTLIB_AI_CHARACTERISTIC_INTEGER, character, index );
-}
-
-int trap_Characteristic_BInteger(int character, int index, int min, int max) {
- return syscall( BOTLIB_AI_CHARACTERISTIC_BINTEGER, character, index, min, max );
-}
-
-void trap_Characteristic_String(int character, int index, char *buf, int size) {
- syscall( BOTLIB_AI_CHARACTERISTIC_STRING, character, index, buf, size );
-}
-
-int trap_BotAllocChatState(void) {
- return syscall( BOTLIB_AI_ALLOC_CHAT_STATE );
-}
-
-void trap_BotFreeChatState(int handle) {
- syscall( BOTLIB_AI_FREE_CHAT_STATE, handle );
-}
-
-void trap_BotQueueConsoleMessage(int chatstate, int type, char *message) {
- syscall( BOTLIB_AI_QUEUE_CONSOLE_MESSAGE, chatstate, type, message );
-}
-
-void trap_BotRemoveConsoleMessage(int chatstate, int handle) {
- syscall( BOTLIB_AI_REMOVE_CONSOLE_MESSAGE, chatstate, handle );
-}
-
-int trap_BotNextConsoleMessage(int chatstate, void /* struct bot_consolemessage_s */ *cm) {
- return syscall( BOTLIB_AI_NEXT_CONSOLE_MESSAGE, chatstate, cm );
-}
-
-int trap_BotNumConsoleMessages(int chatstate) {
- return syscall( BOTLIB_AI_NUM_CONSOLE_MESSAGE, chatstate );
-}
-
-void trap_BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 ) {
- syscall( BOTLIB_AI_INITIAL_CHAT, chatstate, type, mcontext, var0, var1, var2, var3, var4, var5, var6, var7 );
-}
-
-int trap_BotNumInitialChats(int chatstate, char *type) {
- return syscall( BOTLIB_AI_NUM_INITIAL_CHATS, chatstate, type );
-}
-
-int trap_BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 ) {
- return syscall( BOTLIB_AI_REPLY_CHAT, chatstate, message, mcontext, vcontext, var0, var1, var2, var3, var4, var5, var6, var7 );
-}
-
-int trap_BotChatLength(int chatstate) {
- return syscall( BOTLIB_AI_CHAT_LENGTH, chatstate );
-}
-
-void trap_BotEnterChat(int chatstate, int client, int sendto) {
- syscall( BOTLIB_AI_ENTER_CHAT, chatstate, client, sendto );
-}
-
-void trap_BotGetChatMessage(int chatstate, char *buf, int size) {
- syscall( BOTLIB_AI_GET_CHAT_MESSAGE, chatstate, buf, size);
-}
-
-int trap_StringContains(char *str1, char *str2, int casesensitive) {
- return syscall( BOTLIB_AI_STRING_CONTAINS, str1, str2, casesensitive );
-}
-
-int trap_BotFindMatch(char *str, void /* struct bot_match_s */ *match, unsigned long int context) {
- return syscall( BOTLIB_AI_FIND_MATCH, str, match, context );
-}
-
-void trap_BotMatchVariable(void /* struct bot_match_s */ *match, int variable, char *buf, int size) {
- syscall( BOTLIB_AI_MATCH_VARIABLE, match, variable, buf, size );
-}
-
-void trap_UnifyWhiteSpaces(char *string) {
- syscall( BOTLIB_AI_UNIFY_WHITE_SPACES, string );
-}
-
-void trap_BotReplaceSynonyms(char *string, unsigned long int context) {
- syscall( BOTLIB_AI_REPLACE_SYNONYMS, string, context );
-}
-
-int trap_BotLoadChatFile(int chatstate, char *chatfile, char *chatname) {
- return syscall( BOTLIB_AI_LOAD_CHAT_FILE, chatstate, chatfile, chatname );
-}
-
-void trap_BotSetChatGender(int chatstate, int gender) {
- syscall( BOTLIB_AI_SET_CHAT_GENDER, chatstate, gender );
-}
-
-void trap_BotSetChatName(int chatstate, char *name, int client) {
- syscall( BOTLIB_AI_SET_CHAT_NAME, chatstate, name, client );
-}
-
-void trap_BotResetGoalState(int goalstate) {
- syscall( BOTLIB_AI_RESET_GOAL_STATE, goalstate );
-}
-
-void trap_BotResetAvoidGoals(int goalstate) {
- syscall( BOTLIB_AI_RESET_AVOID_GOALS, goalstate );
-}
-
-void trap_BotRemoveFromAvoidGoals(int goalstate, int number) {
- syscall( BOTLIB_AI_REMOVE_FROM_AVOID_GOALS, goalstate, number);
-}
-
-void trap_BotPushGoal(int goalstate, void /* struct bot_goal_s */ *goal) {
- syscall( BOTLIB_AI_PUSH_GOAL, goalstate, goal );
-}
-
-void trap_BotPopGoal(int goalstate) {
- syscall( BOTLIB_AI_POP_GOAL, goalstate );
-}
-
-void trap_BotEmptyGoalStack(int goalstate) {
- syscall( BOTLIB_AI_EMPTY_GOAL_STACK, goalstate );
-}
-
-void trap_BotDumpAvoidGoals(int goalstate) {
- syscall( BOTLIB_AI_DUMP_AVOID_GOALS, goalstate );
-}
-
-void trap_BotDumpGoalStack(int goalstate) {
- syscall( BOTLIB_AI_DUMP_GOAL_STACK, goalstate );
-}
-
-void trap_BotGoalName(int number, char *name, int size) {
- syscall( BOTLIB_AI_GOAL_NAME, number, name, size );
-}
-
-int trap_BotGetTopGoal(int goalstate, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_GET_TOP_GOAL, goalstate, goal );
-}
-
-int trap_BotGetSecondGoal(int goalstate, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_GET_SECOND_GOAL, goalstate, goal );
-}
-
-int trap_BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags) {
- return syscall( BOTLIB_AI_CHOOSE_LTG_ITEM, goalstate, origin, inventory, travelflags );
-}
-
-int trap_BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, void /* struct bot_goal_s */ *ltg, float maxtime) {
- return syscall( BOTLIB_AI_CHOOSE_NBG_ITEM, goalstate, origin, inventory, travelflags, ltg, PASSFLOAT(maxtime) );
-}
-
-int trap_BotTouchingGoal(vec3_t origin, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_TOUCHING_GOAL, origin, goal );
-}
-
-int trap_BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE, viewer, eye, viewangles, goal );
-}
-
-int trap_BotGetLevelItemGoal(int index, char *classname, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_GET_LEVEL_ITEM_GOAL, index, classname, goal );
-}
-
-int trap_BotGetNextCampSpotGoal(int num, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL, num, goal );
-}
-
-int trap_BotGetMapLocationGoal(char *name, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_GET_MAP_LOCATION_GOAL, name, goal );
-}
-
-float trap_BotAvoidGoalTime(int goalstate, int number) {
- floatint_t fi;
- fi.i = syscall( BOTLIB_AI_AVOID_GOAL_TIME, goalstate, number );
- return fi.f;
-}
-
-void trap_BotSetAvoidGoalTime(int goalstate, int number, float avoidtime) {
- syscall( BOTLIB_AI_SET_AVOID_GOAL_TIME, goalstate, number, PASSFLOAT(avoidtime));
-}
-
-void trap_BotInitLevelItems(void) {
- syscall( BOTLIB_AI_INIT_LEVEL_ITEMS );
-}
-
-void trap_BotUpdateEntityItems(void) {
- syscall( BOTLIB_AI_UPDATE_ENTITY_ITEMS );
-}
-
-int trap_BotLoadItemWeights(int goalstate, char *filename) {
- return syscall( BOTLIB_AI_LOAD_ITEM_WEIGHTS, goalstate, filename );
-}
-
-void trap_BotFreeItemWeights(int goalstate) {
- syscall( BOTLIB_AI_FREE_ITEM_WEIGHTS, goalstate );
-}
-
-void trap_BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child) {
- syscall( BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC, parent1, parent2, child );
-}
-
-void trap_BotSaveGoalFuzzyLogic(int goalstate, char *filename) {
- syscall( BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC, goalstate, filename );
-}
-
-void trap_BotMutateGoalFuzzyLogic(int goalstate, float range) {
- syscall( BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC, goalstate, range );
-}
-
-int trap_BotAllocGoalState(int state) {
- return syscall( BOTLIB_AI_ALLOC_GOAL_STATE, state );
-}
-
-void trap_BotFreeGoalState(int handle) {
- syscall( BOTLIB_AI_FREE_GOAL_STATE, handle );
-}
-
-void trap_BotResetMoveState(int movestate) {
- syscall( BOTLIB_AI_RESET_MOVE_STATE, movestate );
-}
-
-void trap_BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type) {
- syscall( BOTLIB_AI_ADD_AVOID_SPOT, movestate, origin, PASSFLOAT(radius), type);
-}
-
-void trap_BotMoveToGoal(void /* struct bot_moveresult_s */ *result, int movestate, void /* struct bot_goal_s */ *goal, int travelflags) {
- syscall( BOTLIB_AI_MOVE_TO_GOAL, result, movestate, goal, travelflags );
-}
-
-int trap_BotMoveInDirection(int movestate, vec3_t dir, float speed, int type) {
- return syscall( BOTLIB_AI_MOVE_IN_DIRECTION, movestate, dir, PASSFLOAT(speed), type );
-}
-
-void trap_BotResetAvoidReach(int movestate) {
- syscall( BOTLIB_AI_RESET_AVOID_REACH, movestate );
-}
-
-void trap_BotResetLastAvoidReach(int movestate) {
- syscall( BOTLIB_AI_RESET_LAST_AVOID_REACH,movestate );
-}
-
-int trap_BotReachabilityArea(vec3_t origin, int testground) {
- return syscall( BOTLIB_AI_REACHABILITY_AREA, origin, testground );
-}
-
-int trap_BotMovementViewTarget(int movestate, void /* struct bot_goal_s */ *goal, int travelflags, float lookahead, vec3_t target) {
- return syscall( BOTLIB_AI_MOVEMENT_VIEW_TARGET, movestate, goal, travelflags, PASSFLOAT(lookahead), target );
-}
-
-int trap_BotPredictVisiblePosition(vec3_t origin, int areanum, void /* struct bot_goal_s */ *goal, int travelflags, vec3_t target) {
- return syscall( BOTLIB_AI_PREDICT_VISIBLE_POSITION, origin, areanum, goal, travelflags, target );
-}
-
-int trap_BotAllocMoveState(void) {
- return syscall( BOTLIB_AI_ALLOC_MOVE_STATE );
-}
-
-void trap_BotFreeMoveState(int handle) {
- syscall( BOTLIB_AI_FREE_MOVE_STATE, handle );
-}
-
-void trap_BotInitMoveState(int handle, void /* struct bot_initmove_s */ *initmove) {
- syscall( BOTLIB_AI_INIT_MOVE_STATE, handle, initmove );
-}
-
-int trap_BotChooseBestFightWeapon(int weaponstate, int *inventory) {
- return syscall( BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON, weaponstate, inventory );
-}
-
-void trap_BotGetWeaponInfo(int weaponstate, int weapon, void /* struct weaponinfo_s */ *weaponinfo) {
- syscall( BOTLIB_AI_GET_WEAPON_INFO, weaponstate, weapon, weaponinfo );
-}
-
-int trap_BotLoadWeaponWeights(int weaponstate, char *filename) {
- return syscall( BOTLIB_AI_LOAD_WEAPON_WEIGHTS, weaponstate, filename );
-}
-
-int trap_BotAllocWeaponState(void) {
- return syscall( BOTLIB_AI_ALLOC_WEAPON_STATE );
-}
-
-void trap_BotFreeWeaponState(int weaponstate) {
- syscall( BOTLIB_AI_FREE_WEAPON_STATE, weaponstate );
-}
-
-void trap_BotResetWeaponState(int weaponstate) {
- syscall( BOTLIB_AI_RESET_WEAPON_STATE, weaponstate );
-}
-
-int trap_GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child) {
- return syscall( BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION, numranks, ranks, parent1, parent2, child );
-}
-
-int trap_PC_LoadSource( const char *filename ) {
- return syscall( BOTLIB_PC_LOAD_SOURCE, filename );
-}
-
-int trap_PC_FreeSource( int handle ) {
- return syscall( BOTLIB_PC_FREE_SOURCE, handle );
-}
-
-int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) {
- return syscall( BOTLIB_PC_READ_TOKEN, handle, pc_token );
-}
-
-int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) {
- return syscall( BOTLIB_PC_SOURCE_FILE_AND_LINE, handle, filename, line );
-}
diff --git a/engine/code/game/g_target.c b/engine/code/game/g_target.c
deleted file mode 100644
index 495a8d5..0000000
--- a/engine/code/game/g_target.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-//==========================================================
-
-/*QUAKED target_give (1 0 0) (-8 -8 -8) (8 8 8)
-Gives the activator all the items pointed to.
-*/
-void Use_Target_Give( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
- gentity_t *t;
- trace_t trace;
-
- if ( !activator->client ) {
- return;
- }
-
- if ( !ent->target ) {
- return;
- }
-
- memset( &trace, 0, sizeof( trace ) );
- t = NULL;
- while ( (t = G_Find (t, FOFS(targetname), ent->target)) != NULL ) {
- if ( !t->item ) {
- continue;
- }
- Touch_Item( t, activator, &trace );
-
- // make sure it isn't going to respawn or show any events
- t->nextthink = 0;
- trap_UnlinkEntity( t );
- }
-}
-
-void SP_target_give( gentity_t *ent ) {
- ent->use = Use_Target_Give;
-}
-
-
-//==========================================================
-
-/*QUAKED target_remove_powerups (1 0 0) (-8 -8 -8) (8 8 8)
-takes away all the activators powerups.
-Used to drop flight powerups into death puts.
-*/
-void Use_target_remove_powerups( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
- if( !activator->client ) {
- return;
- }
-
- if( activator->client->ps.powerups[PW_REDFLAG] ) {
- Team_ReturnFlag( TEAM_RED );
- } else if( activator->client->ps.powerups[PW_BLUEFLAG] ) {
- Team_ReturnFlag( TEAM_BLUE );
- } else if( activator->client->ps.powerups[PW_NEUTRALFLAG] ) {
- Team_ReturnFlag( TEAM_FREE );
- }
-
- memset( activator->client->ps.powerups, 0, sizeof( activator->client->ps.powerups ) );
-}
-
-void SP_target_remove_powerups( gentity_t *ent ) {
- ent->use = Use_target_remove_powerups;
-}
-
-
-//==========================================================
-
-/*QUAKED target_delay (1 0 0) (-8 -8 -8) (8 8 8)
-"wait" seconds to pause before firing targets.
-"random" delay variance, total delay = delay +/- random seconds
-*/
-void Think_Target_Delay( gentity_t *ent ) {
- G_UseTargets( ent, ent->activator );
-}
-
-void Use_Target_Delay( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
- ent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;
- ent->think = Think_Target_Delay;
- ent->activator = activator;
-}
-
-void SP_target_delay( gentity_t *ent ) {
- // check delay for backwards compatability
- if ( !G_SpawnFloat( "delay", "0", &ent->wait ) ) {
- G_SpawnFloat( "wait", "1", &ent->wait );
- }
-
- if ( !ent->wait ) {
- ent->wait = 1;
- }
- ent->use = Use_Target_Delay;
-}
-
-
-//==========================================================
-
-/*QUAKED target_score (1 0 0) (-8 -8 -8) (8 8 8)
-"count" number of points to add, default 1
-
-The activator is given this many points.
-*/
-void Use_Target_Score (gentity_t *ent, gentity_t *other, gentity_t *activator) {
- AddScore( activator, ent->r.currentOrigin, ent->count );
-}
-
-void SP_target_score( gentity_t *ent ) {
- if ( !ent->count ) {
- ent->count = 1;
- }
- ent->use = Use_Target_Score;
-}
-
-
-//==========================================================
-
-/*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8) redteam blueteam private
-"message" text to print
-If "private", only the activator gets the message. If no checks, all clients get the message.
-*/
-void Use_Target_Print (gentity_t *ent, gentity_t *other, gentity_t *activator) {
- if ( activator->client && ( ent->spawnflags & 4 ) ) {
- trap_SendServerCommand( activator-g_entities, va("cp \"%s\"", ent->message ));
- return;
- }
-
- if ( ent->spawnflags & 3 ) {
- if ( ent->spawnflags & 1 ) {
- G_TeamCommand( TEAM_RED, va("cp \"%s\"", ent->message) );
- }
- if ( ent->spawnflags & 2 ) {
- G_TeamCommand( TEAM_BLUE, va("cp \"%s\"", ent->message) );
- }
- return;
- }
-
- trap_SendServerCommand( -1, va("cp \"%s\"", ent->message ));
-}
-
-void SP_target_print( gentity_t *ent ) {
- ent->use = Use_Target_Print;
-}
-
-
-//==========================================================
-
-
-/*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off global activator
-"noise" wav file to play
-
-A global sound will play full volume throughout the level.
-Activator sounds will play on the player that activated the target.
-Global and activator sounds can't be combined with looping.
-Normal sounds play each time the target is used.
-Looped sounds will be toggled by use functions.
-Multiple identical looping sounds will just increase volume without any speed cost.
-"wait" : Seconds between auto triggerings, 0 = don't auto trigger
-"random" wait variance, default is 0
-*/
-void Use_Target_Speaker (gentity_t *ent, gentity_t *other, gentity_t *activator) {
- if (ent->spawnflags & 3) { // looping sound toggles
- if (ent->s.loopSound)
- ent->s.loopSound = 0; // turn it off
- else
- ent->s.loopSound = ent->noise_index; // start it
- }else { // normal sound
- if ( ent->spawnflags & 8 ) {
- G_AddEvent( activator, EV_GENERAL_SOUND, ent->noise_index );
- } else if (ent->spawnflags & 4) {
- G_AddEvent( ent, EV_GLOBAL_SOUND, ent->noise_index );
- } else {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->noise_index );
- }
- }
-}
-
-void SP_target_speaker( gentity_t *ent ) {
- char buffer[MAX_QPATH];
- char *s;
-
- G_SpawnFloat( "wait", "0", &ent->wait );
- G_SpawnFloat( "random", "0", &ent->random );
-
- if ( !G_SpawnString( "noise", "NOSOUND", &s ) ) {
- G_Error( "target_speaker without a noise key at %s", vtos( ent->s.origin ) );
- }
-
- // force all client reletive sounds to be "activator" speakers that
- // play on the entity that activates it
- if ( s[0] == '*' ) {
- ent->spawnflags |= 8;
- }
-
- if (!strstr( s, ".wav" )) {
- Com_sprintf (buffer, sizeof(buffer), "%s.wav", s );
- } else {
- Q_strncpyz( buffer, s, sizeof(buffer) );
- }
- ent->noise_index = G_SoundIndex(buffer);
-
- // a repeating speaker can be done completely client side
- ent->s.eType = ET_SPEAKER;
- ent->s.eventParm = ent->noise_index;
- ent->s.frame = ent->wait * 10;
- ent->s.clientNum = ent->random * 10;
-
-
- // check for prestarted looping sound
- if ( ent->spawnflags & 1 ) {
- ent->s.loopSound = ent->noise_index;
- }
-
- ent->use = Use_Target_Speaker;
-
- if (ent->spawnflags & 4) {
- ent->r.svFlags |= SVF_BROADCAST;
- }
-
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
-
- // must link the entity so we get areas and clusters so
- // the server can determine who to send updates to
- trap_LinkEntity( ent );
-}
-
-
-
-//==========================================================
-
-/*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON
-When triggered, fires a laser. You can either set a target or a direction.
-*/
-void target_laser_think (gentity_t *self) {
- vec3_t end;
- trace_t tr;
- vec3_t point;
-
- // if pointed at another entity, set movedir to point at it
- if ( self->enemy ) {
- VectorMA (self->enemy->s.origin, 0.5, self->enemy->r.mins, point);
- VectorMA (point, 0.5, self->enemy->r.maxs, point);
- VectorSubtract (point, self->s.origin, self->movedir);
- VectorNormalize (self->movedir);
- }
-
- // fire forward and see what we hit
- VectorMA (self->s.origin, 2048, self->movedir, end);
-
- trap_Trace( &tr, self->s.origin, NULL, NULL, end, self->s.number, CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE);
-
- if ( tr.entityNum ) {
- // hurt it if we can
- G_Damage ( &g_entities[tr.entityNum], self, self->activator, self->movedir,
- tr.endpos, self->damage, DAMAGE_NO_KNOCKBACK, MOD_TARGET_LASER);
- }
-
- VectorCopy (tr.endpos, self->s.origin2);
-
- trap_LinkEntity( self );
- self->nextthink = level.time + FRAMETIME;
-}
-
-void target_laser_on (gentity_t *self)
-{
- if (!self->activator)
- self->activator = self;
- target_laser_think (self);
-}
-
-void target_laser_off (gentity_t *self)
-{
- trap_UnlinkEntity( self );
- self->nextthink = 0;
-}
-
-void target_laser_use (gentity_t *self, gentity_t *other, gentity_t *activator)
-{
- self->activator = activator;
- if ( self->nextthink > 0 )
- target_laser_off (self);
- else
- target_laser_on (self);
-}
-
-void target_laser_start (gentity_t *self)
-{
- gentity_t *ent;
-
- self->s.eType = ET_BEAM;
-
- if (self->target) {
- ent = G_Find (NULL, FOFS(targetname), self->target);
- if (!ent) {
- G_Printf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
- }
- self->enemy = ent;
- } else {
- G_SetMovedir (self->s.angles, self->movedir);
- }
-
- self->use = target_laser_use;
- self->think = target_laser_think;
-
- if ( !self->damage ) {
- self->damage = 1;
- }
-
- if (self->spawnflags & 1)
- target_laser_on (self);
- else
- target_laser_off (self);
-}
-
-void SP_target_laser (gentity_t *self)
-{
- // let everything else get spawned before we start firing
- self->think = target_laser_start;
- self->nextthink = level.time + FRAMETIME;
-}
-
-
-//==========================================================
-
-void target_teleporter_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
- gentity_t *dest;
-
- if (!activator->client)
- return;
- dest = G_PickTarget( self->target );
- if (!dest) {
- G_Printf ("Couldn't find teleporter destination\n");
- return;
- }
-
- TeleportPlayer( activator, dest->s.origin, dest->s.angles );
-}
-
-/*QUAKED target_teleporter (1 0 0) (-8 -8 -8) (8 8 8)
-The activator will be teleported away.
-*/
-void SP_target_teleporter( gentity_t *self ) {
- if (!self->targetname)
- G_Printf("untargeted %s at %s\n", self->classname, vtos(self->s.origin));
-
- self->use = target_teleporter_use;
-}
-
-//==========================================================
-
-
-/*QUAKED target_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) RED_ONLY BLUE_ONLY RANDOM
-This doesn't perform any actions except fire its targets.
-The activator can be forced to be from a certain team.
-if RANDOM is checked, only one of the targets will be fired, not all of them
-*/
-void target_relay_use (gentity_t *self, gentity_t *other, gentity_t *activator) {
- if ( ( self->spawnflags & 1 ) && activator->client
- && activator->client->sess.sessionTeam != TEAM_RED ) {
- return;
- }
- if ( ( self->spawnflags & 2 ) && activator->client
- && activator->client->sess.sessionTeam != TEAM_BLUE ) {
- return;
- }
- if ( self->spawnflags & 4 ) {
- gentity_t *ent;
-
- ent = G_PickTarget( self->target );
- if ( ent && ent->use ) {
- ent->use( ent, self, activator );
- }
- return;
- }
- G_UseTargets (self, activator);
-}
-
-void SP_target_relay (gentity_t *self) {
- self->use = target_relay_use;
-}
-
-
-//==========================================================
-
-/*QUAKED target_kill (.5 .5 .5) (-8 -8 -8) (8 8 8)
-Kills the activator.
-*/
-void target_kill_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
- G_Damage ( activator, NULL, NULL, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
-}
-
-void SP_target_kill( gentity_t *self ) {
- self->use = target_kill_use;
-}
-
-/*QUAKED target_position (0 0.5 0) (-4 -4 -4) (4 4 4)
-Used as a positional target for in-game calculation, like jumppad targets.
-*/
-void SP_target_position( gentity_t *self ){
- G_SetOrigin( self, self->s.origin );
-}
-
-static void target_location_linkup(gentity_t *ent)
-{
- int i;
- int n;
-
- if (level.locationLinked)
- return;
-
- level.locationLinked = qtrue;
-
- level.locationHead = NULL;
-
- trap_SetConfigstring( CS_LOCATIONS, "unknown" );
-
- for (i = 0, ent = g_entities, n = 1;
- i < level.num_entities;
- i++, ent++) {
- if (ent->classname && !Q_stricmp(ent->classname, "target_location")) {
- // lets overload some variables!
- ent->health = n; // use for location marking
- trap_SetConfigstring( CS_LOCATIONS + n, ent->message );
- n++;
- ent->nextTrain = level.locationHead;
- level.locationHead = ent;
- }
- }
-
- // All linked together now
-}
-
-/*QUAKED target_location (0 0.5 0) (-8 -8 -8) (8 8 8)
-Set "message" to the name of this location.
-Set "count" to 0-7 for color.
-0:white 1:red 2:green 3:yellow 4:blue 5:cyan 6:magenta 7:white
-
-Closest target_location in sight used for the location, if none
-in site, closest in distance
-*/
-void SP_target_location( gentity_t *self ){
- self->think = target_location_linkup;
- self->nextthink = level.time + 200; // Let them all spawn first
-
- G_SetOrigin( self, self->s.origin );
-}
-
diff --git a/engine/code/game/g_team.c b/engine/code/game/g_team.c
deleted file mode 100644
index 0191f55..0000000
--- a/engine/code/game/g_team.c
+++ /dev/null
@@ -1,1486 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-#include "g_local.h"
-
-
-typedef struct teamgame_s {
- float last_flag_capture;
- int last_capture_team;
- flagStatus_t redStatus; // CTF
- flagStatus_t blueStatus; // CTF
- flagStatus_t flagStatus; // One Flag CTF
- int redTakenTime;
- int blueTakenTime;
- int redObeliskAttackedTime;
- int blueObeliskAttackedTime;
-} teamgame_t;
-
-teamgame_t teamgame;
-
-gentity_t *neutralObelisk;
-
-void Team_SetFlagStatus( int team, flagStatus_t status );
-
-void Team_InitGame( void ) {
- memset(&teamgame, 0, sizeof teamgame);
-
- switch( g_gametype.integer ) {
- case GT_CTF:
- teamgame.redStatus = -1; // Invalid to force update
- Team_SetFlagStatus( TEAM_RED, FLAG_ATBASE );
- teamgame.blueStatus = -1; // Invalid to force update
- Team_SetFlagStatus( TEAM_BLUE, FLAG_ATBASE );
- break;
-#ifdef MISSIONPACK
- case GT_1FCTF:
- teamgame.flagStatus = -1; // Invalid to force update
- Team_SetFlagStatus( TEAM_FREE, FLAG_ATBASE );
- break;
-#endif
- default:
- break;
- }
-}
-
-int OtherTeam(int team) {
- if (team==TEAM_RED)
- return TEAM_BLUE;
- else if (team==TEAM_BLUE)
- return TEAM_RED;
- return team;
-}
-
-const char *TeamName(int team) {
- if (team==TEAM_RED)
- return "RED";
- else if (team==TEAM_BLUE)
- return "BLUE";
- else if (team==TEAM_SPECTATOR)
- return "SPECTATOR";
- return "FREE";
-}
-
-const char *OtherTeamName(int team) {
- if (team==TEAM_RED)
- return "BLUE";
- else if (team==TEAM_BLUE)
- return "RED";
- else if (team==TEAM_SPECTATOR)
- return "SPECTATOR";
- return "FREE";
-}
-
-const char *TeamColorString(int team) {
- if (team==TEAM_RED)
- return S_COLOR_RED;
- else if (team==TEAM_BLUE)
- return S_COLOR_BLUE;
- else if (team==TEAM_SPECTATOR)
- return S_COLOR_YELLOW;
- return S_COLOR_WHITE;
-}
-
-// NULL for everyone
-void QDECL PrintMsg( gentity_t *ent, const char *fmt, ... ) {
- char msg[1024];
- va_list argptr;
- char *p;
-
- va_start (argptr,fmt);
- if (Q_vsnprintf (msg, sizeof(msg), fmt, argptr) > sizeof(msg)) {
- G_Error ( "PrintMsg overrun" );
- }
- va_end (argptr);
-
- // double quotes are bad
- while ((p = strchr(msg, '"')) != NULL)
- *p = '\'';
-
- trap_SendServerCommand ( ( (ent == NULL) ? -1 : ent-g_entities ), va("print \"%s\"", msg ));
-}
-
-/*
-==============
-AddTeamScore
-
- used for gametype > GT_TEAM
- for gametype GT_TEAM the level.teamScores is updated in AddScore in g_combat.c
-==============
-*/
-void AddTeamScore(vec3_t origin, int team, int score) {
- gentity_t *te;
-
- te = G_TempEntity(origin, EV_GLOBAL_TEAM_SOUND );
- te->r.svFlags |= SVF_BROADCAST;
-
- if ( team == TEAM_RED ) {
- if ( level.teamScores[ TEAM_RED ] + score == level.teamScores[ TEAM_BLUE ] ) {
- //teams are tied sound
- te->s.eventParm = GTS_TEAMS_ARE_TIED;
- }
- else if ( level.teamScores[ TEAM_RED ] <= level.teamScores[ TEAM_BLUE ] &&
- level.teamScores[ TEAM_RED ] + score > level.teamScores[ TEAM_BLUE ]) {
- // red took the lead sound
- te->s.eventParm = GTS_REDTEAM_TOOK_LEAD;
- }
- else {
- // red scored sound
- te->s.eventParm = GTS_REDTEAM_SCORED;
- }
- }
- else {
- if ( level.teamScores[ TEAM_BLUE ] + score == level.teamScores[ TEAM_RED ] ) {
- //teams are tied sound
- te->s.eventParm = GTS_TEAMS_ARE_TIED;
- }
- else if ( level.teamScores[ TEAM_BLUE ] <= level.teamScores[ TEAM_RED ] &&
- level.teamScores[ TEAM_BLUE ] + score > level.teamScores[ TEAM_RED ]) {
- // blue took the lead sound
- te->s.eventParm = GTS_BLUETEAM_TOOK_LEAD;
- }
- else {
- // blue scored sound
- te->s.eventParm = GTS_BLUETEAM_SCORED;
- }
- }
- level.teamScores[ team ] += score;
-}
-
-/*
-==============
-OnSameTeam
-==============
-*/
-qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 ) {
- if ( !ent1->client || !ent2->client ) {
- return qfalse;
- }
-
- if ( g_gametype.integer < GT_TEAM ) {
- return qfalse;
- }
-
- if ( ent1->client->sess.sessionTeam == ent2->client->sess.sessionTeam ) {
- return qtrue;
- }
-
- return qfalse;
-}
-
-
-static char ctfFlagStatusRemap[] = { '0', '1', '*', '*', '2' };
-static char oneFlagStatusRemap[] = { '0', '1', '2', '3', '4' };
-
-void Team_SetFlagStatus( int team, flagStatus_t status ) {
- qboolean modified = qfalse;
-
- switch( team ) {
- case TEAM_RED: // CTF
- if( teamgame.redStatus != status ) {
- teamgame.redStatus = status;
- modified = qtrue;
- }
- break;
-
- case TEAM_BLUE: // CTF
- if( teamgame.blueStatus != status ) {
- teamgame.blueStatus = status;
- modified = qtrue;
- }
- break;
-
- case TEAM_FREE: // One Flag CTF
- if( teamgame.flagStatus != status ) {
- teamgame.flagStatus = status;
- modified = qtrue;
- }
- break;
- }
-
- if( modified ) {
- char st[4];
-
- if( g_gametype.integer == GT_CTF ) {
- st[0] = ctfFlagStatusRemap[teamgame.redStatus];
- st[1] = ctfFlagStatusRemap[teamgame.blueStatus];
- st[2] = 0;
- }
- else { // GT_1FCTF
- st[0] = oneFlagStatusRemap[teamgame.flagStatus];
- st[1] = 0;
- }
-
- trap_SetConfigstring( CS_FLAGSTATUS, st );
- }
-}
-
-void Team_CheckDroppedItem( gentity_t *dropped ) {
- if( dropped->item->giTag == PW_REDFLAG ) {
- Team_SetFlagStatus( TEAM_RED, FLAG_DROPPED );
- }
- else if( dropped->item->giTag == PW_BLUEFLAG ) {
- Team_SetFlagStatus( TEAM_BLUE, FLAG_DROPPED );
- }
- else if( dropped->item->giTag == PW_NEUTRALFLAG ) {
- Team_SetFlagStatus( TEAM_FREE, FLAG_DROPPED );
- }
-}
-
-/*
-================
-Team_ForceGesture
-================
-*/
-void Team_ForceGesture(int team) {
- int i;
- gentity_t *ent;
-
- for (i = 0; i < MAX_CLIENTS; i++) {
- ent = &g_entities[i];
- if (!ent->inuse)
- continue;
- if (!ent->client)
- continue;
- if (ent->client->sess.sessionTeam != team)
- continue;
- //
- ent->flags |= FL_FORCE_GESTURE;
- }
-}
-
-/*
-================
-Team_FragBonuses
-
-Calculate the bonuses for flag defense, flag carrier defense, etc.
-Note that bonuses are not cumulative. You get one, they are in importance
-order.
-================
-*/
-void Team_FragBonuses(gentity_t *targ, gentity_t *inflictor, gentity_t *attacker)
-{
- int i;
- gentity_t *ent;
- int flag_pw, enemy_flag_pw;
- int otherteam;
- int tokens;
- gentity_t *flag, *carrier = NULL;
- char *c;
- vec3_t v1, v2;
- int team;
-
- // no bonus for fragging yourself or team mates
- if (!targ->client || !attacker->client || targ == attacker || OnSameTeam(targ, attacker))
- return;
-
- team = targ->client->sess.sessionTeam;
- otherteam = OtherTeam(targ->client->sess.sessionTeam);
- if (otherteam < 0)
- return; // whoever died isn't on a team
-
- // same team, if the flag at base, check to he has the enemy flag
- if (team == TEAM_RED) {
- flag_pw = PW_REDFLAG;
- enemy_flag_pw = PW_BLUEFLAG;
- } else {
- flag_pw = PW_BLUEFLAG;
- enemy_flag_pw = PW_REDFLAG;
- }
-
- if (g_gametype.integer == GT_1FCTF) {
- enemy_flag_pw = PW_NEUTRALFLAG;
- }
-
- // did the attacker frag the flag carrier?
- tokens = 0;
-#ifdef MISSIONPACK
- if( g_gametype.integer == GT_HARVESTER ) {
- tokens = targ->client->ps.generic1;
- }
-#endif
- if (targ->client->ps.powerups[enemy_flag_pw]) {
- attacker->client->pers.teamState.lastfraggedcarrier = level.time;
- AddScore(attacker, targ->r.currentOrigin, CTF_FRAG_CARRIER_BONUS);
- attacker->client->pers.teamState.fragcarrier++;
- PrintMsg(NULL, "%s" S_COLOR_WHITE " fragged %s's flag carrier!\n",
- attacker->client->pers.netname, TeamName(team));
-
- // the target had the flag, clear the hurt carrier
- // field on the other team
- for (i = 0; i < g_maxclients.integer; i++) {
- ent = g_entities + i;
- if (ent->inuse && ent->client->sess.sessionTeam == otherteam)
- ent->client->pers.teamState.lasthurtcarrier = 0;
- }
- return;
- }
-
- // did the attacker frag a head carrier? other->client->ps.generic1
- if (tokens) {
- attacker->client->pers.teamState.lastfraggedcarrier = level.time;
- AddScore(attacker, targ->r.currentOrigin, CTF_FRAG_CARRIER_BONUS * tokens * tokens);
- attacker->client->pers.teamState.fragcarrier++;
- PrintMsg(NULL, "%s" S_COLOR_WHITE " fragged %s's skull carrier!\n",
- attacker->client->pers.netname, TeamName(team));
-
- // the target had the flag, clear the hurt carrier
- // field on the other team
- for (i = 0; i < g_maxclients.integer; i++) {
- ent = g_entities + i;
- if (ent->inuse && ent->client->sess.sessionTeam == otherteam)
- ent->client->pers.teamState.lasthurtcarrier = 0;
- }
- return;
- }
-
- if (targ->client->pers.teamState.lasthurtcarrier &&
- level.time - targ->client->pers.teamState.lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT &&
- !attacker->client->ps.powerups[flag_pw]) {
- // attacker is on the same team as the flag carrier and
- // fragged a guy who hurt our flag carrier
- AddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_DANGER_PROTECT_BONUS);
-
- attacker->client->pers.teamState.carrierdefense++;
- targ->client->pers.teamState.lasthurtcarrier = 0;
-
- attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
- team = attacker->client->sess.sessionTeam;
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- return;
- }
-
- if (targ->client->pers.teamState.lasthurtcarrier &&
- level.time - targ->client->pers.teamState.lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT) {
- // attacker is on the same team as the skull carrier and
- AddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_DANGER_PROTECT_BONUS);
-
- attacker->client->pers.teamState.carrierdefense++;
- targ->client->pers.teamState.lasthurtcarrier = 0;
-
- attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
- team = attacker->client->sess.sessionTeam;
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- return;
- }
-
- // flag and flag carrier area defense bonuses
-
- // we have to find the flag and carrier entities
-
-#ifdef MISSIONPACK
- if( g_gametype.integer == GT_OBELISK ) {
- // find the team obelisk
- switch (attacker->client->sess.sessionTeam) {
- case TEAM_RED:
- c = "team_redobelisk";
- break;
- case TEAM_BLUE:
- c = "team_blueobelisk";
- break;
- default:
- return;
- }
-
- } else if (g_gametype.integer == GT_HARVESTER ) {
- // find the center obelisk
- c = "team_neutralobelisk";
- } else {
-#endif
- // find the flag
- switch (attacker->client->sess.sessionTeam) {
- case TEAM_RED:
- c = "team_CTF_redflag";
- break;
- case TEAM_BLUE:
- c = "team_CTF_blueflag";
- break;
- default:
- return;
- }
- // find attacker's team's flag carrier
- for (i = 0; i < g_maxclients.integer; i++) {
- carrier = g_entities + i;
- if (carrier->inuse && carrier->client->ps.powerups[flag_pw])
- break;
- carrier = NULL;
- }
-#ifdef MISSIONPACK
- }
-#endif
- flag = NULL;
- while ((flag = G_Find (flag, FOFS(classname), c)) != NULL) {
- if (!(flag->flags & FL_DROPPED_ITEM))
- break;
- }
-
- if (!flag)
- return; // can't find attacker's flag
-
- // ok we have the attackers flag and a pointer to the carrier
-
- // check to see if we are defending the base's flag
- VectorSubtract(targ->r.currentOrigin, flag->r.currentOrigin, v1);
- VectorSubtract(attacker->r.currentOrigin, flag->r.currentOrigin, v2);
-
- if ( ( ( VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS &&
- trap_InPVS(flag->r.currentOrigin, targ->r.currentOrigin ) ) ||
- ( VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS &&
- trap_InPVS(flag->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&
- attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam) {
-
- // we defended the base flag
- AddScore(attacker, targ->r.currentOrigin, CTF_FLAG_DEFENSE_BONUS);
- attacker->client->pers.teamState.basedefense++;
-
- attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- return;
- }
-
- if (carrier && carrier != attacker) {
- VectorSubtract(targ->r.currentOrigin, carrier->r.currentOrigin, v1);
- VectorSubtract(attacker->r.currentOrigin, carrier->r.currentOrigin, v1);
-
- if ( ( ( VectorLength(v1) < CTF_ATTACKER_PROTECT_RADIUS &&
- trap_InPVS(carrier->r.currentOrigin, targ->r.currentOrigin ) ) ||
- ( VectorLength(v2) < CTF_ATTACKER_PROTECT_RADIUS &&
- trap_InPVS(carrier->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&
- attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam) {
- AddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_PROTECT_BONUS);
- attacker->client->pers.teamState.carrierdefense++;
-
- attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- return;
- }
- }
-}
-
-/*
-================
-Team_CheckHurtCarrier
-
-Check to see if attacker hurt the flag carrier. Needed when handing out bonuses for assistance to flag
-carrier defense.
-================
-*/
-void Team_CheckHurtCarrier(gentity_t *targ, gentity_t *attacker)
-{
- int flag_pw;
-
- if (!targ->client || !attacker->client)
- return;
-
- if (targ->client->sess.sessionTeam == TEAM_RED)
- flag_pw = PW_BLUEFLAG;
- else
- flag_pw = PW_REDFLAG;
-
- // flags
- if (targ->client->ps.powerups[flag_pw] &&
- targ->client->sess.sessionTeam != attacker->client->sess.sessionTeam)
- attacker->client->pers.teamState.lasthurtcarrier = level.time;
-
- // skulls
- if (targ->client->ps.generic1 &&
- targ->client->sess.sessionTeam != attacker->client->sess.sessionTeam)
- attacker->client->pers.teamState.lasthurtcarrier = level.time;
-}
-
-
-gentity_t *Team_ResetFlag( int team ) {
- char *c;
- gentity_t *ent, *rent = NULL;
-
- switch (team) {
- case TEAM_RED:
- c = "team_CTF_redflag";
- break;
- case TEAM_BLUE:
- c = "team_CTF_blueflag";
- break;
- case TEAM_FREE:
- c = "team_CTF_neutralflag";
- break;
- default:
- return NULL;
- }
-
- ent = NULL;
- while ((ent = G_Find (ent, FOFS(classname), c)) != NULL) {
- if (ent->flags & FL_DROPPED_ITEM)
- G_FreeEntity(ent);
- else {
- rent = ent;
- RespawnItem(ent);
- }
- }
-
- Team_SetFlagStatus( team, FLAG_ATBASE );
-
- return rent;
-}
-
-void Team_ResetFlags( void ) {
- if( g_gametype.integer == GT_CTF ) {
- Team_ResetFlag( TEAM_RED );
- Team_ResetFlag( TEAM_BLUE );
- }
-#ifdef MISSIONPACK
- else if( g_gametype.integer == GT_1FCTF ) {
- Team_ResetFlag( TEAM_FREE );
- }
-#endif
-}
-
-void Team_ReturnFlagSound( gentity_t *ent, int team ) {
- gentity_t *te;
-
- if (ent == NULL) {
- G_Printf ("Warning: NULL passed to Team_ReturnFlagSound\n");
- return;
- }
-
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
- if( team == TEAM_BLUE ) {
- te->s.eventParm = GTS_RED_RETURN;
- }
- else {
- te->s.eventParm = GTS_BLUE_RETURN;
- }
- te->r.svFlags |= SVF_BROADCAST;
-}
-
-void Team_TakeFlagSound( gentity_t *ent, int team ) {
- gentity_t *te;
-
- if (ent == NULL) {
- G_Printf ("Warning: NULL passed to Team_TakeFlagSound\n");
- return;
- }
-
- // only play sound when the flag was at the base
- // or not picked up the last 10 seconds
- switch(team) {
- case TEAM_RED:
- if( teamgame.blueStatus != FLAG_ATBASE ) {
- if (teamgame.blueTakenTime > level.time - 10000)
- return;
- }
- teamgame.blueTakenTime = level.time;
- break;
-
- case TEAM_BLUE: // CTF
- if( teamgame.redStatus != FLAG_ATBASE ) {
- if (teamgame.redTakenTime > level.time - 10000)
- return;
- }
- teamgame.redTakenTime = level.time;
- break;
- }
-
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
- if( team == TEAM_BLUE ) {
- te->s.eventParm = GTS_RED_TAKEN;
- }
- else {
- te->s.eventParm = GTS_BLUE_TAKEN;
- }
- te->r.svFlags |= SVF_BROADCAST;
-}
-
-void Team_CaptureFlagSound( gentity_t *ent, int team ) {
- gentity_t *te;
-
- if (ent == NULL) {
- G_Printf ("Warning: NULL passed to Team_CaptureFlagSound\n");
- return;
- }
-
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
- if( team == TEAM_BLUE ) {
- te->s.eventParm = GTS_BLUE_CAPTURE;
- }
- else {
- te->s.eventParm = GTS_RED_CAPTURE;
- }
- te->r.svFlags |= SVF_BROADCAST;
-}
-
-void Team_ReturnFlag( int team ) {
- Team_ReturnFlagSound(Team_ResetFlag(team), team);
- if( team == TEAM_FREE ) {
- PrintMsg(NULL, "The flag has returned!\n" );
- }
- else {
- PrintMsg(NULL, "The %s flag has returned!\n", TeamName(team));
- }
-}
-
-void Team_FreeEntity( gentity_t *ent ) {
- if( ent->item->giTag == PW_REDFLAG ) {
- Team_ReturnFlag( TEAM_RED );
- }
- else if( ent->item->giTag == PW_BLUEFLAG ) {
- Team_ReturnFlag( TEAM_BLUE );
- }
- else if( ent->item->giTag == PW_NEUTRALFLAG ) {
- Team_ReturnFlag( TEAM_FREE );
- }
-}
-
-/*
-==============
-Team_DroppedFlagThink
-
-Automatically set in Launch_Item if the item is one of the flags
-
-Flags are unique in that if they are dropped, the base flag must be respawned when they time out
-==============
-*/
-void Team_DroppedFlagThink(gentity_t *ent) {
- int team = TEAM_FREE;
-
- if( ent->item->giTag == PW_REDFLAG ) {
- team = TEAM_RED;
- }
- else if( ent->item->giTag == PW_BLUEFLAG ) {
- team = TEAM_BLUE;
- }
- else if( ent->item->giTag == PW_NEUTRALFLAG ) {
- team = TEAM_FREE;
- }
-
- Team_ReturnFlagSound( Team_ResetFlag( team ), team );
- // Reset Flag will delete this entity
-}
-
-
-/*
-==============
-Team_DroppedFlagThink
-==============
-*/
-int Team_TouchOurFlag( gentity_t *ent, gentity_t *other, int team ) {
- int i;
- gentity_t *player;
- gclient_t *cl = other->client;
- int enemy_flag;
-
-#ifdef MISSIONPACK
- if( g_gametype.integer == GT_1FCTF ) {
- enemy_flag = PW_NEUTRALFLAG;
- }
- else {
-#endif
- if (cl->sess.sessionTeam == TEAM_RED) {
- enemy_flag = PW_BLUEFLAG;
- } else {
- enemy_flag = PW_REDFLAG;
- }
-
- if ( ent->flags & FL_DROPPED_ITEM ) {
- // hey, its not home. return it by teleporting it back
- PrintMsg( NULL, "%s" S_COLOR_WHITE " returned the %s flag!\n",
- cl->pers.netname, TeamName(team));
- AddScore(other, ent->r.currentOrigin, CTF_RECOVERY_BONUS);
- other->client->pers.teamState.flagrecovery++;
- other->client->pers.teamState.lastreturnedflag = level.time;
- //ResetFlag will remove this entity! We must return zero
- Team_ReturnFlagSound(Team_ResetFlag(team), team);
- return 0;
- }
-#ifdef MISSIONPACK
- }
-#endif
-
- // the flag is at home base. if the player has the enemy
- // flag, he's just won!
- if (!cl->ps.powerups[enemy_flag])
- return 0; // We don't have the flag
-#ifdef MISSIONPACK
- if( g_gametype.integer == GT_1FCTF ) {
- PrintMsg( NULL, "%s" S_COLOR_WHITE " captured the flag!\n", cl->pers.netname );
- }
- else {
-#endif
- PrintMsg( NULL, "%s" S_COLOR_WHITE " captured the %s flag!\n", cl->pers.netname, TeamName(OtherTeam(team)));
-#ifdef MISSIONPACK
- }
-#endif
-
- cl->ps.powerups[enemy_flag] = 0;
-
- teamgame.last_flag_capture = level.time;
- teamgame.last_capture_team = team;
-
- // Increase the team's score
- AddTeamScore(ent->s.pos.trBase, other->client->sess.sessionTeam, 1);
- Team_ForceGesture(other->client->sess.sessionTeam);
-
- other->client->pers.teamState.captures++;
- // add the sprite over the player's head
- other->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- other->client->ps.eFlags |= EF_AWARD_CAP;
- other->client->rewardTime = level.time + REWARD_SPRITE_TIME;
- other->client->ps.persistant[PERS_CAPTURES]++;
-
- // other gets another 10 frag bonus
- AddScore(other, ent->r.currentOrigin, CTF_CAPTURE_BONUS);
-
- Team_CaptureFlagSound( ent, team );
-
- // Ok, let's do the player loop, hand out the bonuses
- for (i = 0; i < g_maxclients.integer; i++) {
- player = &g_entities[i];
-
- // also make sure we don't award assist bonuses to the flag carrier himself.
- if (!player->inuse || player == other)
- continue;
-
- if (player->client->sess.sessionTeam !=
- cl->sess.sessionTeam) {
- player->client->pers.teamState.lasthurtcarrier = -5;
- } else if (player->client->sess.sessionTeam ==
- cl->sess.sessionTeam) {
- if (player != other)
- AddScore(player, ent->r.currentOrigin, CTF_TEAM_BONUS);
- // award extra points for capture assists
- if (player->client->pers.teamState.lastreturnedflag +
- CTF_RETURN_FLAG_ASSIST_TIMEOUT > level.time) {
- AddScore (player, ent->r.currentOrigin, CTF_RETURN_FLAG_ASSIST_BONUS);
- other->client->pers.teamState.assists++;
-
- player->client->ps.persistant[PERS_ASSIST_COUNT]++;
- // add the sprite over the player's head
- player->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- player->client->ps.eFlags |= EF_AWARD_ASSIST;
- player->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- } else if (player->client->pers.teamState.lastfraggedcarrier +
- CTF_FRAG_CARRIER_ASSIST_TIMEOUT > level.time) {
- AddScore(player, ent->r.currentOrigin, CTF_FRAG_CARRIER_ASSIST_BONUS);
- other->client->pers.teamState.assists++;
- player->client->ps.persistant[PERS_ASSIST_COUNT]++;
- // add the sprite over the player's head
- player->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- player->client->ps.eFlags |= EF_AWARD_ASSIST;
- player->client->rewardTime = level.time + REWARD_SPRITE_TIME;
- }
- }
- }
- Team_ResetFlags();
-
- CalculateRanks();
-
- return 0; // Do not respawn this automatically
-}
-
-int Team_TouchEnemyFlag( gentity_t *ent, gentity_t *other, int team ) {
- gclient_t *cl = other->client;
-
-#ifdef MISSIONPACK
- if( g_gametype.integer == GT_1FCTF ) {
- PrintMsg (NULL, "%s" S_COLOR_WHITE " got the flag!\n", other->client->pers.netname );
-
- cl->ps.powerups[PW_NEUTRALFLAG] = INT_MAX; // flags never expire
-
- if( team == TEAM_RED ) {
- Team_SetFlagStatus( TEAM_FREE, FLAG_TAKEN_RED );
- }
- else {
- Team_SetFlagStatus( TEAM_FREE, FLAG_TAKEN_BLUE );
- }
- }
- else{
-#endif
- PrintMsg (NULL, "%s" S_COLOR_WHITE " got the %s flag!\n",
- other->client->pers.netname, TeamName(team));
-
- if (team == TEAM_RED)
- cl->ps.powerups[PW_REDFLAG] = INT_MAX; // flags never expire
- else
- cl->ps.powerups[PW_BLUEFLAG] = INT_MAX; // flags never expire
-
- Team_SetFlagStatus( team, FLAG_TAKEN );
-#ifdef MISSIONPACK
- }
-#endif
-
- AddScore(other, ent->r.currentOrigin, CTF_FLAG_BONUS);
- cl->pers.teamState.flagsince = level.time;
- Team_TakeFlagSound( ent, team );
-
- return -1; // Do not respawn this automatically, but do delete it if it was FL_DROPPED
-}
-
-int Pickup_Team( gentity_t *ent, gentity_t *other ) {
- int team;
- gclient_t *cl = other->client;
-
-#ifdef MISSIONPACK
- if( g_gametype.integer == GT_OBELISK ) {
- // there are no team items that can be picked up in obelisk
- G_FreeEntity( ent );
- return 0;
- }
-
- if( g_gametype.integer == GT_HARVESTER ) {
- // the only team items that can be picked up in harvester are the cubes
- if( ent->spawnflags != cl->sess.sessionTeam ) {
- cl->ps.generic1 += 1;
- }
- G_FreeEntity( ent );
- return 0;
- }
-#endif
- // figure out what team this flag is
- if( strcmp(ent->classname, "team_CTF_redflag") == 0 ) {
- team = TEAM_RED;
- }
- else if( strcmp(ent->classname, "team_CTF_blueflag") == 0 ) {
- team = TEAM_BLUE;
- }
-#ifdef MISSIONPACK
- else if( strcmp(ent->classname, "team_CTF_neutralflag") == 0 ) {
- team = TEAM_FREE;
- }
-#endif
- else {
- PrintMsg ( other, "Don't know what team the flag is on.\n");
- return 0;
- }
-#ifdef MISSIONPACK
- if( g_gametype.integer == GT_1FCTF ) {
- if( team == TEAM_FREE ) {
- return Team_TouchEnemyFlag( ent, other, cl->sess.sessionTeam );
- }
- if( team != cl->sess.sessionTeam) {
- return Team_TouchOurFlag( ent, other, cl->sess.sessionTeam );
- }
- return 0;
- }
-#endif
- // GT_CTF
- if( team == cl->sess.sessionTeam) {
- return Team_TouchOurFlag( ent, other, team );
- }
- return Team_TouchEnemyFlag( ent, other, team );
-}
-
-/*
-===========
-Team_GetLocation
-
-Report a location for the player. Uses placed nearby target_location entities
-============
-*/
-gentity_t *Team_GetLocation(gentity_t *ent)
-{
- gentity_t *eloc, *best;
- float bestlen, len;
- vec3_t origin;
-
- best = NULL;
- bestlen = 3*8192.0*8192.0;
-
- VectorCopy( ent->r.currentOrigin, origin );
-
- for (eloc = level.locationHead; eloc; eloc = eloc->nextTrain) {
- len = ( origin[0] - eloc->r.currentOrigin[0] ) * ( origin[0] - eloc->r.currentOrigin[0] )
- + ( origin[1] - eloc->r.currentOrigin[1] ) * ( origin[1] - eloc->r.currentOrigin[1] )
- + ( origin[2] - eloc->r.currentOrigin[2] ) * ( origin[2] - eloc->r.currentOrigin[2] );
-
- if ( len > bestlen ) {
- continue;
- }
-
- if ( !trap_InPVS( origin, eloc->r.currentOrigin ) ) {
- continue;
- }
-
- bestlen = len;
- best = eloc;
- }
-
- return best;
-}
-
-
-/*
-===========
-Team_GetLocation
-
-Report a location for the player. Uses placed nearby target_location entities
-============
-*/
-qboolean Team_GetLocationMsg(gentity_t *ent, char *loc, int loclen)
-{
- gentity_t *best;
-
- best = Team_GetLocation( ent );
-
- if (!best)
- return qfalse;
-
- if (best->count) {
- if (best->count < 0)
- best->count = 0;
- if (best->count > 7)
- best->count = 7;
- Com_sprintf(loc, loclen, "%c%c%s" S_COLOR_WHITE, Q_COLOR_ESCAPE, best->count + '0', best->message );
- } else
- Com_sprintf(loc, loclen, "%s", best->message);
-
- return qtrue;
-}
-
-
-/*---------------------------------------------------------------------------*/
-
-/*
-================
-SelectRandomTeamSpawnPoint
-
-go to a random point that doesn't telefrag
-================
-*/
-#define MAX_TEAM_SPAWN_POINTS 32
-gentity_t *SelectRandomTeamSpawnPoint( int teamstate, team_t team ) {
- gentity_t *spot;
- int count;
- int selection;
- gentity_t *spots[MAX_TEAM_SPAWN_POINTS];
- char *classname;
-
- if (teamstate == TEAM_BEGIN) {
- if (team == TEAM_RED)
- classname = "team_CTF_redplayer";
- else if (team == TEAM_BLUE)
- classname = "team_CTF_blueplayer";
- else
- return NULL;
- } else {
- if (team == TEAM_RED)
- classname = "team_CTF_redspawn";
- else if (team == TEAM_BLUE)
- classname = "team_CTF_bluespawn";
- else
- return NULL;
- }
- count = 0;
-
- spot = NULL;
-
- while ((spot = G_Find (spot, FOFS(classname), classname)) != NULL) {
- if ( SpotWouldTelefrag( spot ) ) {
- continue;
- }
- spots[ count ] = spot;
- if (++count == MAX_TEAM_SPAWN_POINTS)
- break;
- }
-
- if ( !count ) { // no spots that won't telefrag
- return G_Find( NULL, FOFS(classname), classname);
- }
-
- selection = rand() % count;
- return spots[ selection ];
-}
-
-
-/*
-===========
-SelectCTFSpawnPoint
-
-============
-*/
-gentity_t *SelectCTFSpawnPoint ( team_t team, int teamstate, vec3_t origin, vec3_t angles, qboolean isbot ) {
- gentity_t *spot;
-
- spot = SelectRandomTeamSpawnPoint ( teamstate, team );
-
- if (!spot) {
- return SelectSpawnPoint( vec3_origin, origin, angles, isbot );
- }
-
- VectorCopy (spot->s.origin, origin);
- origin[2] += 9;
- VectorCopy (spot->s.angles, angles);
-
- return spot;
-}
-
-/*---------------------------------------------------------------------------*/
-
-static int QDECL SortClients( const void *a, const void *b ) {
- return *(int *)a - *(int *)b;
-}
-
-
-/*
-==================
-TeamplayLocationsMessage
-
-Format:
- clientNum location health armor weapon powerups
-
-==================
-*/
-void TeamplayInfoMessage( gentity_t *ent ) {
- char entry[1024];
- char string[8192];
- int stringlength;
- int i, j;
- gentity_t *player;
- int cnt;
- int h, a;
- int clients[TEAM_MAXOVERLAY];
-
- if ( ! ent->client->pers.teamInfo )
- return;
-
- // figure out what client should be on the display
- // we are limited to 8, but we want to use the top eight players
- // but in client order (so they don't keep changing position on the overlay)
- for (i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {
- player = g_entities + level.sortedClients[i];
- if (player->inuse && player->client->sess.sessionTeam ==
- ent->client->sess.sessionTeam ) {
- clients[cnt++] = level.sortedClients[i];
- }
- }
-
- // We have the top eight players, sort them by clientNum
- qsort( clients, cnt, sizeof( clients[0] ), SortClients );
-
- // send the latest information on all clients
- string[0] = 0;
- stringlength = 0;
-
- for (i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {
- player = g_entities + i;
- if (player->inuse && player->client->sess.sessionTeam ==
- ent->client->sess.sessionTeam ) {
-
- h = player->client->ps.stats[STAT_HEALTH];
- a = player->client->ps.stats[STAT_ARMOR];
- if (h < 0) h = 0;
- if (a < 0) a = 0;
-
- Com_sprintf (entry, sizeof(entry),
- " %i %i %i %i %i %i",
-// level.sortedClients[i], player->client->pers.teamState.location, h, a,
- i, player->client->pers.teamState.location, h, a,
- player->client->ps.weapon, player->s.powerups);
- j = strlen(entry);
- if (stringlength + j > sizeof(string))
- break;
- strcpy (string + stringlength, entry);
- stringlength += j;
- cnt++;
- }
- }
-
- trap_SendServerCommand( ent-g_entities, va("tinfo %i %s", cnt, string) );
-}
-
-void CheckTeamStatus(void) {
- int i;
- gentity_t *loc, *ent;
-
- if (level.time - level.lastTeamLocationTime > TEAM_LOCATION_UPDATE_TIME) {
-
- level.lastTeamLocationTime = level.time;
-
- for (i = 0; i < g_maxclients.integer; i++) {
- ent = g_entities + i;
-
- if ( ent->client->pers.connected != CON_CONNECTED ) {
- continue;
- }
-
- if (ent->inuse && (ent->client->sess.sessionTeam == TEAM_RED || ent->client->sess.sessionTeam == TEAM_BLUE)) {
- loc = Team_GetLocation( ent );
- if (loc)
- ent->client->pers.teamState.location = loc->health;
- else
- ent->client->pers.teamState.location = 0;
- }
- }
-
- for (i = 0; i < g_maxclients.integer; i++) {
- ent = g_entities + i;
-
- if ( ent->client->pers.connected != CON_CONNECTED ) {
- continue;
- }
-
- if (ent->inuse && (ent->client->sess.sessionTeam == TEAM_RED || ent->client->sess.sessionTeam == TEAM_BLUE)) {
- TeamplayInfoMessage( ent );
- }
- }
- }
-}
-
-/*-----------------------------------------------------------------*/
-
-/*QUAKED team_CTF_redplayer (1 0 0) (-16 -16 -16) (16 16 32)
-Only in CTF games. Red players spawn here at game start.
-*/
-void SP_team_CTF_redplayer( gentity_t *ent ) {
-}
-
-
-/*QUAKED team_CTF_blueplayer (0 0 1) (-16 -16 -16) (16 16 32)
-Only in CTF games. Blue players spawn here at game start.
-*/
-void SP_team_CTF_blueplayer( gentity_t *ent ) {
-}
-
-
-/*QUAKED team_CTF_redspawn (1 0 0) (-16 -16 -24) (16 16 32)
-potential spawning position for red team in CTF games.
-Targets will be fired when someone spawns in on them.
-*/
-void SP_team_CTF_redspawn(gentity_t *ent) {
-}
-
-/*QUAKED team_CTF_bluespawn (0 0 1) (-16 -16 -24) (16 16 32)
-potential spawning position for blue team in CTF games.
-Targets will be fired when someone spawns in on them.
-*/
-void SP_team_CTF_bluespawn(gentity_t *ent) {
-}
-
-
-#ifdef MISSIONPACK
-/*
-================
-Obelisks
-================
-*/
-
-static void ObeliskRegen( gentity_t *self ) {
- self->nextthink = level.time + g_obeliskRegenPeriod.integer * 1000;
- if( self->health >= g_obeliskHealth.integer ) {
- return;
- }
-
- G_AddEvent( self, EV_POWERUP_REGEN, 0 );
- self->health += g_obeliskRegenAmount.integer;
- if ( self->health > g_obeliskHealth.integer ) {
- self->health = g_obeliskHealth.integer;
- }
-
- self->activator->s.modelindex2 = self->health * 0xff / g_obeliskHealth.integer;
- self->activator->s.frame = 0;
-}
-
-
-static void ObeliskRespawn( gentity_t *self ) {
- self->takedamage = qtrue;
- self->health = g_obeliskHealth.integer;
-
- self->think = ObeliskRegen;
- self->nextthink = level.time + g_obeliskRegenPeriod.integer * 1000;
-
- self->activator->s.frame = 0;
-}
-
-
-static void ObeliskDie( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) {
- int otherTeam;
-
- otherTeam = OtherTeam( self->spawnflags );
- AddTeamScore(self->s.pos.trBase, otherTeam, 1);
- Team_ForceGesture(otherTeam);
-
- CalculateRanks();
-
- self->takedamage = qfalse;
- self->think = ObeliskRespawn;
- self->nextthink = level.time + g_obeliskRespawnDelay.integer * 1000;
-
- self->activator->s.modelindex2 = 0xff;
- self->activator->s.frame = 2;
-
- G_AddEvent( self->activator, EV_OBELISKEXPLODE, 0 );
-
- AddScore(attacker, self->r.currentOrigin, CTF_CAPTURE_BONUS);
-
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_CAP;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
- attacker->client->ps.persistant[PERS_CAPTURES]++;
-
- teamgame.redObeliskAttackedTime = 0;
- teamgame.blueObeliskAttackedTime = 0;
-}
-
-
-static void ObeliskTouch( gentity_t *self, gentity_t *other, trace_t *trace ) {
- int tokens;
-
- if ( !other->client ) {
- return;
- }
-
- if ( OtherTeam(other->client->sess.sessionTeam) != self->spawnflags ) {
- return;
- }
-
- tokens = other->client->ps.generic1;
- if( tokens <= 0 ) {
- return;
- }
-
- PrintMsg(NULL, "%s" S_COLOR_WHITE " brought in %i skull%s.\n",
- other->client->pers.netname, tokens, tokens ? "s" : "" );
-
- AddTeamScore(self->s.pos.trBase, other->client->sess.sessionTeam, tokens);
- Team_ForceGesture(other->client->sess.sessionTeam);
-
- AddScore(other, self->r.currentOrigin, CTF_CAPTURE_BONUS*tokens);
-
- // add the sprite over the player's head
- other->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- other->client->ps.eFlags |= EF_AWARD_CAP;
- other->client->rewardTime = level.time + REWARD_SPRITE_TIME;
- other->client->ps.persistant[PERS_CAPTURES] += tokens;
-
- other->client->ps.generic1 = 0;
- CalculateRanks();
-
- Team_CaptureFlagSound( self, self->spawnflags );
-}
-
-static void ObeliskPain( gentity_t *self, gentity_t *attacker, int damage ) {
- int actualDamage = damage / 10;
- if (actualDamage <= 0) {
- actualDamage = 1;
- }
- self->activator->s.modelindex2 = self->health * 0xff / g_obeliskHealth.integer;
- if (!self->activator->s.frame) {
- G_AddEvent(self, EV_OBELISKPAIN, 0);
- }
- self->activator->s.frame = 1;
- AddScore(attacker, self->r.currentOrigin, actualDamage);
-}
-
-gentity_t *SpawnObelisk( vec3_t origin, int team, int spawnflags) {
- trace_t tr;
- vec3_t dest;
- gentity_t *ent;
-
- ent = G_Spawn();
-
- VectorCopy( origin, ent->s.origin );
- VectorCopy( origin, ent->s.pos.trBase );
- VectorCopy( origin, ent->r.currentOrigin );
-
- VectorSet( ent->r.mins, -15, -15, 0 );
- VectorSet( ent->r.maxs, 15, 15, 87 );
-
- ent->s.eType = ET_GENERAL;
- ent->flags = FL_NO_KNOCKBACK;
-
- if( g_gametype.integer == GT_OBELISK ) {
- ent->r.contents = CONTENTS_SOLID;
- ent->takedamage = qtrue;
- ent->health = g_obeliskHealth.integer;
- ent->die = ObeliskDie;
- ent->pain = ObeliskPain;
- ent->think = ObeliskRegen;
- ent->nextthink = level.time + g_obeliskRegenPeriod.integer * 1000;
- }
- if( g_gametype.integer == GT_HARVESTER ) {
- ent->r.contents = CONTENTS_TRIGGER;
- ent->touch = ObeliskTouch;
- }
-
- if ( spawnflags & 1 ) {
- // suspended
- G_SetOrigin( ent, ent->s.origin );
- } else {
- // mappers like to put them exactly on the floor, but being coplanar
- // will sometimes show up as starting in solid, so lif it up one pixel
- ent->s.origin[2] += 1;
-
- // drop to floor
- VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
- trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
- if ( tr.startsolid ) {
- ent->s.origin[2] -= 1;
- G_Printf( "SpawnObelisk: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin) );
-
- ent->s.groundEntityNum = ENTITYNUM_NONE;
- G_SetOrigin( ent, ent->s.origin );
- }
- else {
- // allow to ride movers
- ent->s.groundEntityNum = tr.entityNum;
- G_SetOrigin( ent, tr.endpos );
- }
- }
-
- ent->spawnflags = team;
-
- trap_LinkEntity( ent );
-
- return ent;
-}
-
-/*QUAKED team_redobelisk (1 0 0) (-16 -16 0) (16 16 8)
-*/
-void SP_team_redobelisk( gentity_t *ent ) {
- gentity_t *obelisk;
-
- if ( g_gametype.integer <= GT_TEAM ) {
- G_FreeEntity(ent);
- return;
- }
- ent->s.eType = ET_TEAM;
- if ( g_gametype.integer == GT_OBELISK ) {
- obelisk = SpawnObelisk( ent->s.origin, TEAM_RED, ent->spawnflags );
- obelisk->activator = ent;
- // initial obelisk health value
- ent->s.modelindex2 = 0xff;
- ent->s.frame = 0;
- }
- if ( g_gametype.integer == GT_HARVESTER ) {
- obelisk = SpawnObelisk( ent->s.origin, TEAM_RED, ent->spawnflags );
- obelisk->activator = ent;
- }
- ent->s.modelindex = TEAM_RED;
- trap_LinkEntity(ent);
-}
-
-/*QUAKED team_blueobelisk (0 0 1) (-16 -16 0) (16 16 88)
-*/
-void SP_team_blueobelisk( gentity_t *ent ) {
- gentity_t *obelisk;
-
- if ( g_gametype.integer <= GT_TEAM ) {
- G_FreeEntity(ent);
- return;
- }
- ent->s.eType = ET_TEAM;
- if ( g_gametype.integer == GT_OBELISK ) {
- obelisk = SpawnObelisk( ent->s.origin, TEAM_BLUE, ent->spawnflags );
- obelisk->activator = ent;
- // initial obelisk health value
- ent->s.modelindex2 = 0xff;
- ent->s.frame = 0;
- }
- if ( g_gametype.integer == GT_HARVESTER ) {
- obelisk = SpawnObelisk( ent->s.origin, TEAM_BLUE, ent->spawnflags );
- obelisk->activator = ent;
- }
- ent->s.modelindex = TEAM_BLUE;
- trap_LinkEntity(ent);
-}
-
-/*QUAKED team_neutralobelisk (0 0 1) (-16 -16 0) (16 16 88)
-*/
-void SP_team_neutralobelisk( gentity_t *ent ) {
- if ( g_gametype.integer != GT_1FCTF && g_gametype.integer != GT_HARVESTER ) {
- G_FreeEntity(ent);
- return;
- }
- ent->s.eType = ET_TEAM;
- if ( g_gametype.integer == GT_HARVESTER) {
- neutralObelisk = SpawnObelisk( ent->s.origin, TEAM_FREE, ent->spawnflags);
- neutralObelisk->spawnflags = TEAM_FREE;
- }
- ent->s.modelindex = TEAM_FREE;
- trap_LinkEntity(ent);
-}
-
-
-/*
-================
-CheckObeliskAttack
-================
-*/
-qboolean CheckObeliskAttack( gentity_t *obelisk, gentity_t *attacker ) {
- gentity_t *te;
-
- // if this really is an obelisk
- if( obelisk->die != ObeliskDie ) {
- return qfalse;
- }
-
- // if the attacker is a client
- if( !attacker->client ) {
- return qfalse;
- }
-
- // if the obelisk is on the same team as the attacker then don't hurt it
- if( obelisk->spawnflags == attacker->client->sess.sessionTeam ) {
- return qtrue;
- }
-
- // obelisk may be hurt
-
- // if not played any sounds recently
- if ((obelisk->spawnflags == TEAM_RED &&
- teamgame.redObeliskAttackedTime < level.time - OVERLOAD_ATTACK_BASE_SOUND_TIME) ||
- (obelisk->spawnflags == TEAM_BLUE &&
- teamgame.blueObeliskAttackedTime < level.time - OVERLOAD_ATTACK_BASE_SOUND_TIME) ) {
-
- // tell which obelisk is under attack
- te = G_TempEntity( obelisk->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
- if( obelisk->spawnflags == TEAM_RED ) {
- te->s.eventParm = GTS_REDOBELISK_ATTACKED;
- teamgame.redObeliskAttackedTime = level.time;
- }
- else {
- te->s.eventParm = GTS_BLUEOBELISK_ATTACKED;
- teamgame.blueObeliskAttackedTime = level.time;
- }
- te->r.svFlags |= SVF_BROADCAST;
- }
-
- return qfalse;
-}
-#endif
diff --git a/engine/code/game/g_team.h b/engine/code/game/g_team.h
deleted file mode 100644
index ca54caf..0000000
--- a/engine/code/game/g_team.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-#ifdef MISSIONPACK
-
-#define CTF_CAPTURE_BONUS 100 // what you get for capture
-#define CTF_TEAM_BONUS 25 // what your team gets for capture
-#define CTF_RECOVERY_BONUS 10 // what you get for recovery
-#define CTF_FLAG_BONUS 10 // what you get for picking up enemy flag
-#define CTF_FRAG_CARRIER_BONUS 20 // what you get for fragging enemy flag carrier
-#define CTF_FLAG_RETURN_TIME 40000 // seconds until auto return
-
-#define CTF_CARRIER_DANGER_PROTECT_BONUS 5 // bonus for fraggin someone who has recently hurt your flag carrier
-#define CTF_CARRIER_PROTECT_BONUS 2 // bonus for fraggin someone while either you or your target are near your flag carrier
-#define CTF_FLAG_DEFENSE_BONUS 10 // bonus for fraggin someone while either you or your target are near your flag
-#define CTF_RETURN_FLAG_ASSIST_BONUS 10 // awarded for returning a flag that causes a capture to happen almost immediately
-#define CTF_FRAG_CARRIER_ASSIST_BONUS 10 // award for fragging a flag carrier if a capture happens almost immediately
-
-#else
-
-#define CTF_CAPTURE_BONUS 5 // what you get for capture
-#define CTF_TEAM_BONUS 0 // what your team gets for capture
-#define CTF_RECOVERY_BONUS 1 // what you get for recovery
-#define CTF_FLAG_BONUS 0 // what you get for picking up enemy flag
-#define CTF_FRAG_CARRIER_BONUS 2 // what you get for fragging enemy flag carrier
-#define CTF_FLAG_RETURN_TIME 40000 // seconds until auto return
-
-#define CTF_CARRIER_DANGER_PROTECT_BONUS 2 // bonus for fraggin someone who has recently hurt your flag carrier
-#define CTF_CARRIER_PROTECT_BONUS 1 // bonus for fraggin someone while either you or your target are near your flag carrier
-#define CTF_FLAG_DEFENSE_BONUS 1 // bonus for fraggin someone while either you or your target are near your flag
-#define CTF_RETURN_FLAG_ASSIST_BONUS 1 // awarded for returning a flag that causes a capture to happen almost immediately
-#define CTF_FRAG_CARRIER_ASSIST_BONUS 2 // award for fragging a flag carrier if a capture happens almost immediately
-
-#endif
-
-#define CTF_TARGET_PROTECT_RADIUS 1000 // the radius around an object being defended where a target will be worth extra frags
-#define CTF_ATTACKER_PROTECT_RADIUS 1000 // the radius around an object being defended where an attacker will get extra frags when making kills
-
-#define CTF_CARRIER_DANGER_PROTECT_TIMEOUT 8000
-#define CTF_FRAG_CARRIER_ASSIST_TIMEOUT 10000
-#define CTF_RETURN_FLAG_ASSIST_TIMEOUT 10000
-
-#define CTF_GRAPPLE_SPEED 750 // speed of grapple in flight
-#define CTF_GRAPPLE_PULL_SPEED 750 // speed player is pulled at
-
-#define OVERLOAD_ATTACK_BASE_SOUND_TIME 20000
-
-// Prototypes
-
-int OtherTeam(int team);
-const char *TeamName(int team);
-const char *OtherTeamName(int team);
-const char *TeamColorString(int team);
-void AddTeamScore(vec3_t origin, int team, int score);
-
-void Team_DroppedFlagThink(gentity_t *ent);
-void Team_FragBonuses(gentity_t *targ, gentity_t *inflictor, gentity_t *attacker);
-void Team_CheckHurtCarrier(gentity_t *targ, gentity_t *attacker);
-void Team_InitGame(void);
-void Team_ReturnFlag(int team);
-void Team_FreeEntity(gentity_t *ent);
-gentity_t *SelectCTFSpawnPoint ( team_t team, int teamstate, vec3_t origin, vec3_t angles, qboolean isbot );
-gentity_t *Team_GetLocation(gentity_t *ent);
-qboolean Team_GetLocationMsg(gentity_t *ent, char *loc, int loclen);
-void TeamplayInfoMessage( gentity_t *ent );
-void CheckTeamStatus(void);
-
-int Pickup_Team( gentity_t *ent, gentity_t *other );
diff --git a/engine/code/game/g_trigger.c b/engine/code/game/g_trigger.c
deleted file mode 100644
index 5a9538c..0000000
--- a/engine/code/game/g_trigger.c
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-
-void InitTrigger( gentity_t *self ) {
- if (!VectorCompare (self->s.angles, vec3_origin))
- G_SetMovedir (self->s.angles, self->movedir);
-
- trap_SetBrushModel( self, self->model );
- self->r.contents = CONTENTS_TRIGGER; // replaces the -1 from trap_SetBrushModel
- self->r.svFlags = SVF_NOCLIENT;
-}
-
-
-// the wait time has passed, so set back up for another activation
-void multi_wait( gentity_t *ent ) {
- ent->nextthink = 0;
-}
-
-
-// the trigger was just activated
-// ent->activator should be set to the activator so it can be held through a delay
-// so wait for the delay time before firing
-void multi_trigger( gentity_t *ent, gentity_t *activator ) {
- ent->activator = activator;
- if ( ent->nextthink ) {
- return; // can't retrigger until the wait is over
- }
-
- if ( activator->client ) {
- if ( ( ent->spawnflags & 1 ) &&
- activator->client->sess.sessionTeam != TEAM_RED ) {
- return;
- }
- if ( ( ent->spawnflags & 2 ) &&
- activator->client->sess.sessionTeam != TEAM_BLUE ) {
- return;
- }
- }
-
- G_UseTargets (ent, ent->activator);
-
- if ( ent->wait > 0 ) {
- ent->think = multi_wait;
- ent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;
- } else {
- // we can't just remove (self) here, because this is a touch function
- // called while looping through area links...
- ent->touch = 0;
- ent->nextthink = level.time + FRAMETIME;
- ent->think = G_FreeEntity;
- }
-}
-
-void Use_Multi( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
- multi_trigger( ent, activator );
-}
-
-void Touch_Multi( gentity_t *self, gentity_t *other, trace_t *trace ) {
- if( !other->client ) {
- return;
- }
- multi_trigger( self, other );
-}
-
-/*QUAKED trigger_multiple (.5 .5 .5) ?
-"wait" : Seconds between triggerings, 0.5 default, -1 = one time only.
-"random" wait variance, default is 0
-Variable sized repeatable trigger. Must be targeted at one or more entities.
-so, the basic time between firing is a random time between
-(wait - random) and (wait + random)
-*/
-void SP_trigger_multiple( gentity_t *ent ) {
- G_SpawnFloat( "wait", "0.5", &ent->wait );
- G_SpawnFloat( "random", "0", &ent->random );
-
- if ( ent->random >= ent->wait && ent->wait >= 0 ) {
- ent->random = ent->wait - FRAMETIME;
- G_Printf( "trigger_multiple has random >= wait\n" );
- }
-
- ent->touch = Touch_Multi;
- ent->use = Use_Multi;
-
- InitTrigger( ent );
- trap_LinkEntity (ent);
-}
-
-
-
-/*
-==============================================================================
-
-trigger_always
-
-==============================================================================
-*/
-
-void trigger_always_think( gentity_t *ent ) {
- G_UseTargets(ent, ent);
- G_FreeEntity( ent );
-}
-
-/*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
-This trigger will always fire. It is activated by the world.
-*/
-void SP_trigger_always (gentity_t *ent) {
- // we must have some delay to make sure our use targets are present
- ent->nextthink = level.time + 300;
- ent->think = trigger_always_think;
-}
-
-
-/*
-==============================================================================
-
-trigger_push
-
-==============================================================================
-*/
-
-void trigger_push_touch (gentity_t *self, gentity_t *other, trace_t *trace ) {
-
- if ( !other->client ) {
- return;
- }
-
- BG_TouchJumpPad( &other->client->ps, &self->s );
-}
-
-
-/*
-=================
-AimAtTarget
-
-Calculate origin2 so the target apogee will be hit
-=================
-*/
-void AimAtTarget( gentity_t *self ) {
- gentity_t *ent;
- vec3_t origin;
- float height, gravity, time, forward;
- float dist;
-
- VectorAdd( self->r.absmin, self->r.absmax, origin );
- VectorScale ( origin, 0.5, origin );
-
- ent = G_PickTarget( self->target );
- if ( !ent ) {
- G_FreeEntity( self );
- return;
- }
-
- height = ent->s.origin[2] - origin[2];
- gravity = g_gravity.value;
- time = sqrt( height / ( .5 * gravity ) );
- if ( !time ) {
- G_FreeEntity( self );
- return;
- }
-
- // set s.origin2 to the push velocity
- VectorSubtract ( ent->s.origin, origin, self->s.origin2 );
- self->s.origin2[2] = 0;
- dist = VectorNormalize( self->s.origin2);
-
- forward = dist / time;
- VectorScale( self->s.origin2, forward, self->s.origin2 );
-
- self->s.origin2[2] = time * gravity;
-}
-
-
-/*QUAKED trigger_push (.5 .5 .5) ?
-Must point at a target_position, which will be the apex of the leap.
-This will be client side predicted, unlike target_push
-*/
-void SP_trigger_push( gentity_t *self ) {
- InitTrigger (self);
-
- // unlike other triggers, we need to send this one to the client
- self->r.svFlags &= ~SVF_NOCLIENT;
-
- // make sure the client precaches this sound
- G_SoundIndex("sound/world/jumppad.wav");
-
- self->s.eType = ET_PUSH_TRIGGER;
- self->touch = trigger_push_touch;
- self->think = AimAtTarget;
- self->nextthink = level.time + FRAMETIME;
- trap_LinkEntity (self);
-}
-
-
-void Use_target_push( gentity_t *self, gentity_t *other, gentity_t *activator ) {
- if ( !activator->client ) {
- return;
- }
-
- if ( activator->client->ps.pm_type != PM_NORMAL ) {
- return;
- }
- if ( activator->client->ps.powerups[PW_FLIGHT] ) {
- return;
- }
-
- VectorCopy (self->s.origin2, activator->client->ps.velocity);
-
- // play fly sound every 1.5 seconds
- if ( activator->fly_sound_debounce_time < level.time ) {
- activator->fly_sound_debounce_time = level.time + 1500;
- G_Sound( activator, CHAN_AUTO, self->noise_index );
- }
-}
-
-/*QUAKED target_push (.5 .5 .5) (-8 -8 -8) (8 8 8) bouncepad
-Pushes the activator in the direction.of angle, or towards a target apex.
-"speed" defaults to 1000
-if "bouncepad", play bounce noise instead of windfly
-*/
-void SP_target_push( gentity_t *self ) {
- if (!self->speed) {
- self->speed = 1000;
- }
- G_SetMovedir (self->s.angles, self->s.origin2);
- VectorScale (self->s.origin2, self->speed, self->s.origin2);
-
- if ( self->spawnflags & 1 ) {
- self->noise_index = G_SoundIndex("sound/world/jumppad.wav");
- } else {
- self->noise_index = G_SoundIndex("sound/misc/windfly.wav");
- }
- if ( self->target ) {
- VectorCopy( self->s.origin, self->r.absmin );
- VectorCopy( self->s.origin, self->r.absmax );
- self->think = AimAtTarget;
- self->nextthink = level.time + FRAMETIME;
- }
- self->use = Use_target_push;
-}
-
-/*
-==============================================================================
-
-trigger_teleport
-
-==============================================================================
-*/
-
-void trigger_teleporter_touch (gentity_t *self, gentity_t *other, trace_t *trace ) {
- gentity_t *dest;
-
- if ( !other->client ) {
- return;
- }
- if ( other->client->ps.pm_type == PM_DEAD ) {
- return;
- }
- // Spectators only?
- if ( ( self->spawnflags & 1 ) &&
- other->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- return;
- }
-
-
- dest = G_PickTarget( self->target );
- if (!dest) {
- G_Printf ("Couldn't find teleporter destination\n");
- return;
- }
-
- TeleportPlayer( other, dest->s.origin, dest->s.angles );
-}
-
-
-/*QUAKED trigger_teleport (.5 .5 .5) ? SPECTATOR
-Allows client side prediction of teleportation events.
-Must point at a target_position, which will be the teleport destination.
-
-If spectator is set, only spectators can use this teleport
-Spectator teleporters are not normally placed in the editor, but are created
-automatically near doors to allow spectators to move through them
-*/
-void SP_trigger_teleport( gentity_t *self ) {
- InitTrigger (self);
-
- // unlike other triggers, we need to send this one to the client
- // unless is a spectator trigger
- if ( self->spawnflags & 1 ) {
- self->r.svFlags |= SVF_NOCLIENT;
- } else {
- self->r.svFlags &= ~SVF_NOCLIENT;
- }
-
- // make sure the client precaches this sound
- G_SoundIndex("sound/world/jumppad.wav");
-
- self->s.eType = ET_TELEPORT_TRIGGER;
- self->touch = trigger_teleporter_touch;
-
- trap_LinkEntity (self);
-}
-
-
-/*
-==============================================================================
-
-trigger_hurt
-
-==============================================================================
-*/
-
-/*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF - SILENT NO_PROTECTION SLOW
-Any entity that touches this will be hurt.
-It does dmg points of damage each server frame
-Targeting the trigger will toggle its on / off state.
-
-SILENT supresses playing the sound
-SLOW changes the damage rate to once per second
-NO_PROTECTION *nothing* stops the damage
-
-"dmg" default 5 (whole numbers only)
-
-*/
-void hurt_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
- if ( self->r.linked ) {
- trap_UnlinkEntity( self );
- } else {
- trap_LinkEntity( self );
- }
-}
-
-void hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) {
- int dflags;
-
- if ( !other->takedamage ) {
- return;
- }
-
- if ( self->timestamp > level.time ) {
- return;
- }
-
- if ( self->spawnflags & 16 ) {
- self->timestamp = level.time + 1000;
- } else {
- self->timestamp = level.time + FRAMETIME;
- }
-
- // play sound
- if ( !(self->spawnflags & 4) ) {
- G_Sound( other, CHAN_AUTO, self->noise_index );
- }
-
- if (self->spawnflags & 8)
- dflags = DAMAGE_NO_PROTECTION;
- else
- dflags = 0;
- G_Damage (other, self, self, NULL, NULL, self->damage, dflags, MOD_TRIGGER_HURT);
-}
-
-void SP_trigger_hurt( gentity_t *self ) {
- InitTrigger (self);
-
- self->noise_index = G_SoundIndex( "sound/world/electro.wav" );
- self->touch = hurt_touch;
-
- if ( !self->damage ) {
- self->damage = 5;
- }
-
- self->r.contents = CONTENTS_TRIGGER;
-
- if ( self->spawnflags & 2 ) {
- self->use = hurt_use;
- }
-
- // link in to the world if starting active
- if ( ! (self->spawnflags & 1) ) {
- trap_LinkEntity (self);
- }
-}
-
-
-/*
-==============================================================================
-
-timer
-
-==============================================================================
-*/
-
-
-/*QUAKED func_timer (0.3 0.1 0.6) (-8 -8 -8) (8 8 8) START_ON
-This should be renamed trigger_timer...
-Repeatedly fires its targets.
-Can be turned on or off by using.
-
-"wait" base time between triggering all targets, default is 1
-"random" wait variance, default is 0
-so, the basic time between firing is a random time between
-(wait - random) and (wait + random)
-
-*/
-void func_timer_think( gentity_t *self ) {
- G_UseTargets (self, self->activator);
- // set time before next firing
- self->nextthink = level.time + 1000 * ( self->wait + crandom() * self->random );
-}
-
-void func_timer_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
- self->activator = activator;
-
- // if on, turn it off
- if ( self->nextthink ) {
- self->nextthink = 0;
- return;
- }
-
- // turn it on
- func_timer_think (self);
-}
-
-void SP_func_timer( gentity_t *self ) {
- G_SpawnFloat( "random", "1", &self->random);
- G_SpawnFloat( "wait", "1", &self->wait );
-
- self->use = func_timer_use;
- self->think = func_timer_think;
-
- if ( self->random >= self->wait ) {
- self->random = self->wait - FRAMETIME;
- G_Printf( "func_timer at %s has random >= wait\n", vtos( self->s.origin ) );
- }
-
- if ( self->spawnflags & 1 ) {
- self->nextthink = level.time + FRAMETIME;
- self->activator = self;
- }
-
- self->r.svFlags = SVF_NOCLIENT;
-}
-
-
diff --git a/engine/code/game/g_utils.c b/engine/code/game/g_utils.c
deleted file mode 100644
index 4178155..0000000
--- a/engine/code/game/g_utils.c
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// g_utils.c -- misc utility functions for game module
-
-#include "g_local.h"
-
-typedef struct {
- char oldShader[MAX_QPATH];
- char newShader[MAX_QPATH];
- float timeOffset;
-} shaderRemap_t;
-
-#define MAX_SHADER_REMAPS 128
-
-int remapCount = 0;
-shaderRemap_t remappedShaders[MAX_SHADER_REMAPS];
-
-void AddRemap(const char *oldShader, const char *newShader, float timeOffset) {
- int i;
-
- for (i = 0; i < remapCount; i++) {
- if (Q_stricmp(oldShader, remappedShaders[i].oldShader) == 0) {
- // found it, just update this one
- strcpy(remappedShaders[i].newShader,newShader);
- remappedShaders[i].timeOffset = timeOffset;
- return;
- }
- }
- if (remapCount < MAX_SHADER_REMAPS) {
- strcpy(remappedShaders[remapCount].newShader,newShader);
- strcpy(remappedShaders[remapCount].oldShader,oldShader);
- remappedShaders[remapCount].timeOffset = timeOffset;
- remapCount++;
- }
-}
-
-const char *BuildShaderStateConfig(void) {
- static char buff[MAX_STRING_CHARS*4];
- char out[(MAX_QPATH * 2) + 5];
- int i;
-
- memset(buff, 0, MAX_STRING_CHARS);
- for (i = 0; i < remapCount; i++) {
- Com_sprintf(out, (MAX_QPATH * 2) + 5, "%s=%s:%5.2f@", remappedShaders[i].oldShader, remappedShaders[i].newShader, remappedShaders[i].timeOffset);
- Q_strcat( buff, sizeof( buff ), out);
- }
- return buff;
-}
-
-/*
-=========================================================================
-
-model / sound configstring indexes
-
-=========================================================================
-*/
-
-/*
-================
-G_FindConfigstringIndex
-
-================
-*/
-int G_FindConfigstringIndex( char *name, int start, int max, qboolean create ) {
- int i;
- char s[MAX_STRING_CHARS];
-
- if ( !name || !name[0] ) {
- return 0;
- }
-
- for ( i=1 ; i<max ; i++ ) {
- trap_GetConfigstring( start + i, s, sizeof( s ) );
- if ( !s[0] ) {
- break;
- }
- if ( !strcmp( s, name ) ) {
- return i;
- }
- }
-
- if ( !create ) {
- return 0;
- }
-
- if ( i == max ) {
- G_Error( "G_FindConfigstringIndex: overflow" );
- }
-
- trap_SetConfigstring( start + i, name );
-
- return i;
-}
-
-
-int G_ModelIndex( char *name ) {
- return G_FindConfigstringIndex (name, CS_MODELS, MAX_MODELS, qtrue);
-}
-
-int G_SoundIndex( char *name ) {
- return G_FindConfigstringIndex (name, CS_SOUNDS, MAX_SOUNDS, qtrue);
-}
-
-//=====================================================================
-
-
-/*
-================
-G_TeamCommand
-
-Broadcasts a command to only a specific team
-================
-*/
-void G_TeamCommand( team_t team, char *cmd ) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].pers.connected == CON_CONNECTED ) {
- if ( level.clients[i].sess.sessionTeam == team ) {
- trap_SendServerCommand( i, va("%s", cmd ));
- }
- }
- }
-}
-
-
-/*
-=============
-G_Find
-
-Searches all active entities for the next one that holds
-the matching string at fieldofs (use the FOFS() macro) in the structure.
-
-Searches beginning at the entity after from, or the beginning if NULL
-NULL will be returned if the end of the list is reached.
-
-=============
-*/
-gentity_t *G_Find (gentity_t *from, int fieldofs, const char *match)
-{
- char *s;
-
- if (!from)
- from = g_entities;
- else
- from++;
-
- for ( ; from < &g_entities[level.num_entities] ; from++)
- {
- if (!from->inuse)
- continue;
- s = *(char **) ((byte *)from + fieldofs);
- if (!s)
- continue;
- if (!Q_stricmp (s, match))
- return from;
- }
-
- return NULL;
-}
-
-
-/*
-=============
-G_PickTarget
-
-Selects a random entity from among the targets
-=============
-*/
-#define MAXCHOICES 32
-
-gentity_t *G_PickTarget (char *targetname)
-{
- gentity_t *ent = NULL;
- int num_choices = 0;
- gentity_t *choice[MAXCHOICES];
-
- if (!targetname)
- {
- G_Printf("G_PickTarget called with NULL targetname\n");
- return NULL;
- }
-
- while(1)
- {
- ent = G_Find (ent, FOFS(targetname), targetname);
- if (!ent)
- break;
- choice[num_choices++] = ent;
- if (num_choices == MAXCHOICES)
- break;
- }
-
- if (!num_choices)
- {
- G_Printf("G_PickTarget: target %s not found\n", targetname);
- return NULL;
- }
-
- return choice[rand() % num_choices];
-}
-
-
-/*
-==============================
-G_UseTargets
-
-"activator" should be set to the entity that initiated the firing.
-
-Search for (string)targetname in all entities that
-match (string)self.target and call their .use function
-
-==============================
-*/
-void G_UseTargets( gentity_t *ent, gentity_t *activator ) {
- gentity_t *t;
-
- if ( !ent ) {
- return;
- }
-
- if (ent->targetShaderName && ent->targetShaderNewName) {
- float f = level.time * 0.001;
- AddRemap(ent->targetShaderName, ent->targetShaderNewName, f);
- trap_SetConfigstring(CS_SHADERSTATE, BuildShaderStateConfig());
- }
-
- if ( !ent->target ) {
- return;
- }
-
- t = NULL;
- while ( (t = G_Find (t, FOFS(targetname), ent->target)) != NULL ) {
- if ( t == ent ) {
- G_Printf ("WARNING: Entity used itself.\n");
- } else {
- if ( t->use ) {
- t->use (t, ent, activator);
- }
- }
- if ( !ent->inuse ) {
- G_Printf("entity was removed while using targets\n");
- return;
- }
- }
-}
-
-
-/*
-=============
-TempVector
-
-This is just a convenience function
-for making temporary vectors for function calls
-=============
-*/
-float *tv( float x, float y, float z ) {
- static int index;
- static vec3_t vecs[8];
- float *v;
-
- // use an array so that multiple tempvectors won't collide
- // for a while
- v = vecs[index];
- index = (index + 1)&7;
-
- v[0] = x;
- v[1] = y;
- v[2] = z;
-
- return v;
-}
-
-
-/*
-=============
-VectorToString
-
-This is just a convenience function
-for printing vectors
-=============
-*/
-char *vtos( const vec3_t v ) {
- static int index;
- static char str[8][32];
- char *s;
-
- // use an array so that multiple vtos won't collide
- s = str[index];
- index = (index + 1)&7;
-
- Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]);
-
- return s;
-}
-
-
-/*
-===============
-G_SetMovedir
-
-The editor only specifies a single value for angles (yaw),
-but we have special constants to generate an up or down direction.
-Angles will be cleared, because it is being used to represent a direction
-instead of an orientation.
-===============
-*/
-void G_SetMovedir( vec3_t angles, vec3_t movedir ) {
- static vec3_t VEC_UP = {0, -1, 0};
- static vec3_t MOVEDIR_UP = {0, 0, 1};
- static vec3_t VEC_DOWN = {0, -2, 0};
- static vec3_t MOVEDIR_DOWN = {0, 0, -1};
-
- if ( VectorCompare (angles, VEC_UP) ) {
- VectorCopy (MOVEDIR_UP, movedir);
- } else if ( VectorCompare (angles, VEC_DOWN) ) {
- VectorCopy (MOVEDIR_DOWN, movedir);
- } else {
- AngleVectors (angles, movedir, NULL, NULL);
- }
- VectorClear( angles );
-}
-
-
-float vectoyaw( const vec3_t vec ) {
- float yaw;
-
- if (vec[YAW] == 0 && vec[PITCH] == 0) {
- yaw = 0;
- } else {
- if (vec[PITCH]) {
- yaw = ( atan2( vec[YAW], vec[PITCH]) * 180 / M_PI );
- } else if (vec[YAW] > 0) {
- yaw = 90;
- } else {
- yaw = 270;
- }
- if (yaw < 0) {
- yaw += 360;
- }
- }
-
- return yaw;
-}
-
-
-void G_InitGentity( gentity_t *e ) {
- e->inuse = qtrue;
- e->classname = "noclass";
- e->s.number = e - g_entities;
- e->r.ownerNum = ENTITYNUM_NONE;
-}
-
-/*
-=================
-G_Spawn
-
-Either finds a free entity, or allocates a new one.
-
- The slots from 0 to MAX_CLIENTS-1 are always reserved for clients, and will
-never be used by anything else.
-
-Try to avoid reusing an entity that was recently freed, because it
-can cause the client to think the entity morphed into something else
-instead of being removed and recreated, which can cause interpolated
-angles and bad trails.
-=================
-*/
-gentity_t *G_Spawn( void ) {
- int i, force;
- gentity_t *e;
-
- e = NULL; // shut up warning
- i = 0; // shut up warning
- for ( force = 0 ; force < 2 ; force++ ) {
- // if we go through all entities and can't find one to free,
- // override the normal minimum times before use
- e = &g_entities[MAX_CLIENTS];
- for ( i = MAX_CLIENTS ; i<level.num_entities ; i++, e++) {
- if ( e->inuse ) {
- continue;
- }
-
- // the first couple seconds of server time can involve a lot of
- // freeing and allocating, so relax the replacement policy
- if ( !force && e->freetime > level.startTime + 2000 && level.time - e->freetime < 1000 ) {
- continue;
- }
-
- // reuse this slot
- G_InitGentity( e );
- return e;
- }
- if ( i != MAX_GENTITIES ) {
- break;
- }
- }
- if ( i == ENTITYNUM_MAX_NORMAL ) {
- for (i = 0; i < MAX_GENTITIES; i++) {
- G_Printf("%4i: %s\n", i, g_entities[i].classname);
- }
- G_Error( "G_Spawn: no free entities" );
- }
-
- // open up a new slot
- level.num_entities++;
-
- // let the server system know that there are more entities
- trap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ),
- &level.clients[0].ps, sizeof( level.clients[0] ) );
-
- G_InitGentity( e );
- return e;
-}
-
-/*
-=================
-G_EntitiesFree
-=================
-*/
-qboolean G_EntitiesFree( void ) {
- int i;
- gentity_t *e;
-
- e = &g_entities[MAX_CLIENTS];
- for ( i = MAX_CLIENTS; i < level.num_entities; i++, e++) {
- if ( e->inuse ) {
- continue;
- }
- // slot available
- return qtrue;
- }
- return qfalse;
-}
-
-
-/*
-=================
-G_FreeEntity
-
-Marks the entity as free
-=================
-*/
-void G_FreeEntity( gentity_t *ed ) {
- trap_UnlinkEntity (ed); // unlink from world
-
- if ( ed->neverFree ) {
- return;
- }
-
- memset (ed, 0, sizeof(*ed));
- ed->classname = "freed";
- ed->freetime = level.time;
- ed->inuse = qfalse;
-}
-
-/*
-=================
-G_TempEntity
-
-Spawns an event entity that will be auto-removed
-The origin will be snapped to save net bandwidth, so care
-must be taken if the origin is right on a surface (snap towards start vector first)
-=================
-*/
-gentity_t *G_TempEntity( vec3_t origin, int event ) {
- gentity_t *e;
- vec3_t snapped;
-
- e = G_Spawn();
- e->s.eType = ET_EVENTS + event;
-
- e->classname = "tempEntity";
- e->eventTime = level.time;
- e->freeAfterEvent = qtrue;
-
- VectorCopy( origin, snapped );
- SnapVector( snapped ); // save network bandwidth
- G_SetOrigin( e, snapped );
-
- // find cluster for PVS
- trap_LinkEntity( e );
-
- return e;
-}
-
-
-
-/*
-==============================================================================
-
-Kill box
-
-==============================================================================
-*/
-
-/*
-=================
-G_KillBox
-
-Kills all entities that would touch the proposed new positioning
-of ent. Ent should be unlinked before calling this!
-=================
-*/
-void G_KillBox (gentity_t *ent) {
- int i, num;
- int touch[MAX_GENTITIES];
- gentity_t *hit;
- vec3_t mins, maxs;
-
- VectorAdd( ent->client->ps.origin, ent->r.mins, mins );
- VectorAdd( ent->client->ps.origin, ent->r.maxs, maxs );
- num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
-
- for (i=0 ; i<num ; i++) {
- hit = &g_entities[touch[i]];
- if ( !hit->client ) {
- continue;
- }
-
- // nail it
- G_Damage ( hit, ent, ent, NULL, NULL,
- 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
- }
-
-}
-
-//==============================================================================
-
-/*
-===============
-G_AddPredictableEvent
-
-Use for non-pmove events that would also be predicted on the
-client side: jumppads and item pickups
-Adds an event+parm and twiddles the event counter
-===============
-*/
-void G_AddPredictableEvent( gentity_t *ent, int event, int eventParm ) {
- if ( !ent->client ) {
- return;
- }
- BG_AddPredictableEventToPlayerstate( event, eventParm, &ent->client->ps );
-}
-
-
-/*
-===============
-G_AddEvent
-
-Adds an event+parm and twiddles the event counter
-===============
-*/
-void G_AddEvent( gentity_t *ent, int event, int eventParm ) {
- int bits;
-
- if ( !event ) {
- G_Printf( "G_AddEvent: zero event added for entity %i\n", ent->s.number );
- return;
- }
-
- // clients need to add the event in playerState_t instead of entityState_t
- if ( ent->client ) {
- bits = ent->client->ps.externalEvent & EV_EVENT_BITS;
- bits = ( bits + EV_EVENT_BIT1 ) & EV_EVENT_BITS;
- ent->client->ps.externalEvent = event | bits;
- ent->client->ps.externalEventParm = eventParm;
- ent->client->ps.externalEventTime = level.time;
- } else {
- bits = ent->s.event & EV_EVENT_BITS;
- bits = ( bits + EV_EVENT_BIT1 ) & EV_EVENT_BITS;
- ent->s.event = event | bits;
- ent->s.eventParm = eventParm;
- }
- ent->eventTime = level.time;
-}
-
-
-/*
-=============
-G_Sound
-=============
-*/
-void G_Sound( gentity_t *ent, int channel, int soundIndex ) {
- gentity_t *te;
-
- te = G_TempEntity( ent->r.currentOrigin, EV_GENERAL_SOUND );
- te->s.eventParm = soundIndex;
-}
-
-
-//==============================================================================
-
-
-/*
-================
-G_SetOrigin
-
-Sets the pos trajectory for a fixed position
-================
-*/
-void G_SetOrigin( gentity_t *ent, vec3_t origin ) {
- VectorCopy( origin, ent->s.pos.trBase );
- ent->s.pos.trType = TR_STATIONARY;
- ent->s.pos.trTime = 0;
- ent->s.pos.trDuration = 0;
- VectorClear( ent->s.pos.trDelta );
-
- VectorCopy( origin, ent->r.currentOrigin );
-}
-
-/*
-================
-DebugLine
-
- debug polygons only work when running a local game
- with r_debugSurface set to 2
-================
-*/
-int DebugLine(vec3_t start, vec3_t end, int color) {
- vec3_t points[4], dir, cross, up = {0, 0, 1};
- float dot;
-
- VectorCopy(start, points[0]);
- VectorCopy(start, points[1]);
- //points[1][2] -= 2;
- VectorCopy(end, points[2]);
- //points[2][2] -= 2;
- VectorCopy(end, points[3]);
-
-
- VectorSubtract(end, start, dir);
- VectorNormalize(dir);
- dot = DotProduct(dir, up);
- if (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0);
- else CrossProduct(dir, up, cross);
-
- VectorNormalize(cross);
-
- VectorMA(points[0], 2, cross, points[0]);
- VectorMA(points[1], -2, cross, points[1]);
- VectorMA(points[2], -2, cross, points[2]);
- VectorMA(points[3], 2, cross, points[3]);
-
- return trap_DebugPolygonCreate(color, 4, points);
-}
diff --git a/engine/code/game/g_weapon.c b/engine/code/game/g_weapon.c
deleted file mode 100644
index 8cd7198..0000000
--- a/engine/code/game/g_weapon.c
+++ /dev/null
@@ -1,1145 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// g_weapon.c
-// perform the server side effects of a weapon firing
-
-#include "g_local.h"
-
-static float s_quadFactor;
-static vec3_t forward, right, up;
-static vec3_t muzzle;
-
-#define NUM_NAILSHOTS 15
-
-/*
-================
-G_BounceProjectile
-================
-*/
-void G_BounceProjectile( vec3_t start, vec3_t impact, vec3_t dir, vec3_t endout ) {
- vec3_t v, newv;
- float dot;
-
- VectorSubtract( impact, start, v );
- dot = DotProduct( v, dir );
- VectorMA( v, -2*dot, dir, newv );
-
- VectorNormalize(newv);
- VectorMA(impact, 8192, newv, endout);
-}
-
-
-/*
-======================================================================
-
-GAUNTLET
-
-======================================================================
-*/
-
-void Weapon_Gauntlet( gentity_t *ent ) {
-
-}
-
-/*
-===============
-CheckGauntletAttack
-===============
-*/
-qboolean CheckGauntletAttack( gentity_t *ent ) {
- trace_t tr;
- vec3_t end;
- gentity_t *tent;
- gentity_t *traceEnt;
- int damage;
-
- // set aiming directions
- AngleVectors (ent->client->ps.viewangles, forward, right, up);
-
- CalcMuzzlePoint ( ent, forward, right, up, muzzle );
-
- VectorMA (muzzle, 32, forward, end);
-
- trap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT);
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- return qfalse;
- }
-
- traceEnt = &g_entities[ tr.entityNum ];
-
- // send blood impact
- if ( traceEnt->takedamage && traceEnt->client ) {
- tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
- tent->s.otherEntityNum = traceEnt->s.number;
- tent->s.eventParm = DirToByte( tr.plane.normal );
- tent->s.weapon = ent->s.weapon;
- }
-
- if ( !traceEnt->takedamage) {
- return qfalse;
- }
-
- if (ent->client->ps.powerups[PW_QUAD] ) {
- G_AddEvent( ent, EV_POWERUP_QUAD, 0 );
- s_quadFactor = g_quadfactor.value;
- } else {
- s_quadFactor = 1;
- }
-#ifdef MISSIONPACK
- if( ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->giTag == PW_DOUBLER ) {
- s_quadFactor *= 2;
- }
-#endif
-
- damage = 50 * s_quadFactor;
- G_Damage( traceEnt, ent, ent, forward, tr.endpos,
- damage, 0, MOD_GAUNTLET );
-
- return qtrue;
-}
-
-
-/*
-======================================================================
-
-MACHINEGUN
-
-======================================================================
-*/
-
-/*
-======================
-SnapVectorTowards
-
-Round a vector to integers for more efficient network
-transmission, but make sure that it rounds towards a given point
-rather than blindly truncating. This prevents it from truncating
-into a wall.
-======================
-*/
-void SnapVectorTowards( vec3_t v, vec3_t to ) {
- int i;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( to[i] <= v[i] ) {
- v[i] = (int)v[i];
- } else {
- v[i] = (int)v[i] + 1;
- }
- }
-}
-
-#ifdef MISSIONPACK
-#define CHAINGUN_SPREAD 600
-#endif
-#define MACHINEGUN_SPREAD 200
-#define MACHINEGUN_DAMAGE 7
-#define MACHINEGUN_TEAM_DAMAGE 5 // wimpier MG in teamplay
-
-void Bullet_Fire (gentity_t *ent, float spread, int damage ) {
- trace_t tr;
- vec3_t end;
-#ifdef MISSIONPACK
- vec3_t impactpoint, bouncedir;
-#endif
- float r;
- float u;
- gentity_t *tent;
- gentity_t *traceEnt;
- int i, passent;
-
- damage *= s_quadFactor;
-
- r = random() * M_PI * 2.0f;
- u = sin(r) * crandom() * spread * 16;
- r = cos(r) * crandom() * spread * 16;
- VectorMA (muzzle, 8192*16, forward, end);
- VectorMA (end, r, right, end);
- VectorMA (end, u, up, end);
-
- passent = ent->s.number;
- for (i = 0; i < 10; i++) {
-
- trap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT);
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- return;
- }
-
- traceEnt = &g_entities[ tr.entityNum ];
-
- // snap the endpos to integers, but nudged towards the line
- SnapVectorTowards( tr.endpos, muzzle );
-
- // send bullet impact
- if ( traceEnt->takedamage && traceEnt->client ) {
- tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
- tent->s.eventParm = traceEnt->s.number;
- if( LogAccuracyHit( traceEnt, ent ) ) {
- ent->client->accuracy_hits++;
- }
- } else {
- tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL );
- tent->s.eventParm = DirToByte( tr.plane.normal );
- }
- tent->s.otherEntityNum = ent->s.number;
-
- if ( traceEnt->takedamage) {
-#ifdef MISSIONPACK
- if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
- if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
- G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
- VectorCopy( impactpoint, muzzle );
- // the player can hit him/herself with the bounced rail
- passent = ENTITYNUM_NONE;
- }
- else {
- VectorCopy( tr.endpos, muzzle );
- passent = traceEnt->s.number;
- }
- continue;
- }
- else {
-#endif
- G_Damage( traceEnt, ent, ent, forward, tr.endpos,
- damage, 0, MOD_MACHINEGUN);
-#ifdef MISSIONPACK
- }
-#endif
- }
- break;
- }
-}
-
-
-/*
-======================================================================
-
-BFG
-
-======================================================================
-*/
-
-void BFG_Fire ( gentity_t *ent ) {
- gentity_t *m;
-
- m = fire_bfg (ent, muzzle, forward);
- m->damage *= s_quadFactor;
- m->splashDamage *= s_quadFactor;
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
-}
-
-
-/*
-======================================================================
-
-SHOTGUN
-
-======================================================================
-*/
-
-// DEFAULT_SHOTGUN_SPREAD and DEFAULT_SHOTGUN_COUNT are in bg_public.h, because
-// client predicts same spreads
-#define DEFAULT_SHOTGUN_DAMAGE 10
-
-qboolean ShotgunPellet( vec3_t start, vec3_t end, gentity_t *ent ) {
- trace_t tr;
- int damage, i, passent;
- gentity_t *traceEnt;
-#ifdef MISSIONPACK
- vec3_t impactpoint, bouncedir;
-#endif
- vec3_t tr_start, tr_end;
-
- passent = ent->s.number;
- VectorCopy( start, tr_start );
- VectorCopy( end, tr_end );
- for (i = 0; i < 10; i++) {
- trap_Trace (&tr, tr_start, NULL, NULL, tr_end, passent, MASK_SHOT);
- traceEnt = &g_entities[ tr.entityNum ];
-
- // send bullet impact
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- return qfalse;
- }
-
- if ( traceEnt->takedamage) {
- damage = DEFAULT_SHOTGUN_DAMAGE * s_quadFactor;
-#ifdef MISSIONPACK
- if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
- if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
- G_BounceProjectile( tr_start, impactpoint, bouncedir, tr_end );
- VectorCopy( impactpoint, tr_start );
- // the player can hit him/herself with the bounced rail
- passent = ENTITYNUM_NONE;
- }
- else {
- VectorCopy( tr.endpos, tr_start );
- passent = traceEnt->s.number;
- }
- continue;
- }
- else {
- G_Damage( traceEnt, ent, ent, forward, tr.endpos,
- damage, 0, MOD_SHOTGUN);
- if( LogAccuracyHit( traceEnt, ent ) ) {
- return qtrue;
- }
- }
-#else
- G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_SHOTGUN);
- if( LogAccuracyHit( traceEnt, ent ) ) {
- return qtrue;
- }
-#endif
- }
- return qfalse;
- }
- return qfalse;
-}
-
-// this should match CG_ShotgunPattern
-void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {
- int i;
- float r, u;
- vec3_t end;
- vec3_t forward, right, up;
- int oldScore;
- qboolean hitClient = qfalse;
-
- // derive the right and up vectors from the forward vector, because
- // the client won't have any other information
- VectorNormalize2( origin2, forward );
- PerpendicularVector( right, forward );
- CrossProduct( forward, right, up );
-
- oldScore = ent->client->ps.persistant[PERS_SCORE];
-
- // generate the "random" spread pattern
- for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {
- r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
- u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
- VectorMA( origin, 8192 * 16, forward, end);
- VectorMA (end, r, right, end);
- VectorMA (end, u, up, end);
- if( ShotgunPellet( origin, end, ent ) && !hitClient ) {
- hitClient = qtrue;
- ent->client->accuracy_hits++;
- }
- }
-}
-
-
-void weapon_supershotgun_fire (gentity_t *ent) {
- gentity_t *tent;
-
- // send shotgun blast
- tent = G_TempEntity( muzzle, EV_SHOTGUN );
- VectorScale( forward, 4096, tent->s.origin2 );
- SnapVector( tent->s.origin2 );
- tent->s.eventParm = rand() & 255; // seed for spread pattern
- tent->s.otherEntityNum = ent->s.number;
-
- ShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent );
-}
-
-
-/*
-======================================================================
-
-GRENADE LAUNCHER
-
-======================================================================
-*/
-
-void weapon_grenadelauncher_fire (gentity_t *ent) {
- gentity_t *m;
-
- // extra vertical velocity
- forward[2] += 0.2f;
- VectorNormalize( forward );
-
- m = fire_grenade (ent, muzzle, forward);
- m->damage *= s_quadFactor;
- m->splashDamage *= s_quadFactor;
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
-}
-
-/*
-======================================================================
-
-ROCKET
-
-======================================================================
-*/
-
-void Weapon_RocketLauncher_Fire (gentity_t *ent) {
- gentity_t *m;
-
- m = fire_rocket (ent, muzzle, forward);
- m->damage *= s_quadFactor;
- m->splashDamage *= s_quadFactor;
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
-}
-
-
-/*
-======================================================================
-
-PLASMA GUN
-
-======================================================================
-*/
-
-void Weapon_Plasmagun_Fire (gentity_t *ent) {
- gentity_t *m;
-
- m = fire_plasma (ent, muzzle, forward);
- m->damage *= s_quadFactor;
- m->splashDamage *= s_quadFactor;
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
-}
-
-/*
-======================================================================
-
-RAILGUN
-
-======================================================================
-*/
-
-
-/*
-=================
-weapon_railgun_fire
-=================
-*/
-#define MAX_RAIL_HITS 4
-void weapon_railgun_fire (gentity_t *ent) {
- vec3_t end;
-#ifdef MISSIONPACK
- vec3_t impactpoint, bouncedir;
-#endif
- trace_t trace;
- gentity_t *tent;
- gentity_t *traceEnt;
- int damage;
- int i;
- int hits;
- int unlinked;
- int passent;
- gentity_t *unlinkedEntities[MAX_RAIL_HITS];
-
- damage = 100 * s_quadFactor;
-
- VectorMA (muzzle, 8192, forward, end);
-
- // trace only against the solids, so the railgun will go through people
- unlinked = 0;
- hits = 0;
- passent = ent->s.number;
- do {
- trap_Trace (&trace, muzzle, NULL, NULL, end, passent, MASK_SHOT );
- if ( trace.entityNum >= ENTITYNUM_MAX_NORMAL ) {
- break;
- }
- traceEnt = &g_entities[ trace.entityNum ];
- if ( traceEnt->takedamage ) {
-#ifdef MISSIONPACK
- if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
- if ( G_InvulnerabilityEffect( traceEnt, forward, trace.endpos, impactpoint, bouncedir ) ) {
- G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
- // snap the endpos to integers to save net bandwidth, but nudged towards the line
- SnapVectorTowards( trace.endpos, muzzle );
- // send railgun beam effect
- tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );
- // set player number for custom colors on the railtrail
- tent->s.clientNum = ent->s.clientNum;
- VectorCopy( muzzle, tent->s.origin2 );
- // move origin a bit to come closer to the drawn gun muzzle
- VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
- VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
- tent->s.eventParm = 255; // don't make the explosion at the end
- //
- VectorCopy( impactpoint, muzzle );
- // the player can hit him/herself with the bounced rail
- passent = ENTITYNUM_NONE;
- }
- }
- else {
- if( LogAccuracyHit( traceEnt, ent ) ) {
- hits++;
- }
- G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
- }
-#else
- if( LogAccuracyHit( traceEnt, ent ) ) {
- hits++;
- }
- G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
-#endif
- }
- if ( trace.contents & CONTENTS_SOLID ) {
- break; // we hit something solid enough to stop the beam
- }
- // unlink this entity, so the next trace will go past it
- trap_UnlinkEntity( traceEnt );
- unlinkedEntities[unlinked] = traceEnt;
- unlinked++;
- } while ( unlinked < MAX_RAIL_HITS );
-
- // link back in any entities we unlinked
- for ( i = 0 ; i < unlinked ; i++ ) {
- trap_LinkEntity( unlinkedEntities[i] );
- }
-
- // the final trace endpos will be the terminal point of the rail trail
-
- // snap the endpos to integers to save net bandwidth, but nudged towards the line
- SnapVectorTowards( trace.endpos, muzzle );
-
- // send railgun beam effect
- tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );
-
- // set player number for custom colors on the railtrail
- tent->s.clientNum = ent->s.clientNum;
-
- VectorCopy( muzzle, tent->s.origin2 );
- // move origin a bit to come closer to the drawn gun muzzle
- VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
- VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
-
- // no explosion at end if SURF_NOIMPACT, but still make the trail
- if ( trace.surfaceFlags & SURF_NOIMPACT ) {
- tent->s.eventParm = 255; // don't make the explosion at the end
- } else {
- tent->s.eventParm = DirToByte( trace.plane.normal );
- }
- tent->s.clientNum = ent->s.clientNum;
-
- // give the shooter a reward sound if they have made two railgun hits in a row
- if ( hits == 0 ) {
- // complete miss
- ent->client->accurateCount = 0;
- } else {
- // check for "impressive" reward sound
- ent->client->accurateCount += hits;
- if ( ent->client->accurateCount >= 2 ) {
- ent->client->accurateCount -= 2;
- ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
- // add the sprite over the player's head
- ent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- ent->client->ps.eFlags |= EF_AWARD_IMPRESSIVE;
- ent->client->rewardTime = level.time + REWARD_SPRITE_TIME;
- }
- ent->client->accuracy_hits++;
- }
-
-}
-
-
-/*
-======================================================================
-
-GRAPPLING HOOK
-
-======================================================================
-*/
-
-void Weapon_GrapplingHook_Fire (gentity_t *ent)
-{
- if (!ent->client->fireHeld && !ent->client->hook)
- fire_grapple (ent, muzzle, forward);
-
- ent->client->fireHeld = qtrue;
-}
-
-void Weapon_HookFree (gentity_t *ent)
-{
- ent->parent->client->hook = NULL;
- ent->parent->client->ps.pm_flags &= ~PMF_GRAPPLE_PULL;
- G_FreeEntity( ent );
-}
-
-void Weapon_HookThink (gentity_t *ent)
-{
- if (ent->enemy) {
- vec3_t v, oldorigin;
-
- VectorCopy(ent->r.currentOrigin, oldorigin);
- v[0] = ent->enemy->r.currentOrigin[0] + (ent->enemy->r.mins[0] + ent->enemy->r.maxs[0]) * 0.5;
- v[1] = ent->enemy->r.currentOrigin[1] + (ent->enemy->r.mins[1] + ent->enemy->r.maxs[1]) * 0.5;
- v[2] = ent->enemy->r.currentOrigin[2] + (ent->enemy->r.mins[2] + ent->enemy->r.maxs[2]) * 0.5;
- SnapVectorTowards( v, oldorigin ); // save net bandwidth
-
- G_SetOrigin( ent, v );
- }
-
- VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);
-}
-
-/*
-======================================================================
-
-LIGHTNING GUN
-
-======================================================================
-*/
-
-void Weapon_LightningFire( gentity_t *ent ) {
- trace_t tr;
- vec3_t end;
-#ifdef MISSIONPACK
- vec3_t impactpoint, bouncedir;
-#endif
- gentity_t *traceEnt, *tent;
- int damage, i, passent;
-
- damage = 8 * s_quadFactor;
-
- passent = ent->s.number;
- for (i = 0; i < 10; i++) {
- VectorMA( muzzle, LIGHTNING_RANGE, forward, end );
-
- trap_Trace( &tr, muzzle, NULL, NULL, end, passent, MASK_SHOT );
-
-#ifdef MISSIONPACK
- // if not the first trace (the lightning bounced of an invulnerability sphere)
- if (i) {
- // add bounced off lightning bolt temp entity
- // the first lightning bolt is a cgame only visual
- //
- tent = G_TempEntity( muzzle, EV_LIGHTNINGBOLT );
- VectorCopy( tr.endpos, end );
- SnapVector( end );
- VectorCopy( end, tent->s.origin2 );
- }
-#endif
- if ( tr.entityNum == ENTITYNUM_NONE ) {
- return;
- }
-
- traceEnt = &g_entities[ tr.entityNum ];
-
- if ( traceEnt->takedamage) {
-#ifdef MISSIONPACK
- if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
- if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
- G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
- VectorCopy( impactpoint, muzzle );
- VectorSubtract( end, impactpoint, forward );
- VectorNormalize(forward);
- // the player can hit him/herself with the bounced lightning
- passent = ENTITYNUM_NONE;
- }
- else {
- VectorCopy( tr.endpos, muzzle );
- passent = traceEnt->s.number;
- }
- continue;
- }
- else {
- G_Damage( traceEnt, ent, ent, forward, tr.endpos,
- damage, 0, MOD_LIGHTNING);
- }
-#else
- G_Damage( traceEnt, ent, ent, forward, tr.endpos,
- damage, 0, MOD_LIGHTNING);
-#endif
- }
-
- if ( traceEnt->takedamage && traceEnt->client ) {
- tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
- tent->s.otherEntityNum = traceEnt->s.number;
- tent->s.eventParm = DirToByte( tr.plane.normal );
- tent->s.weapon = ent->s.weapon;
- if( LogAccuracyHit( traceEnt, ent ) ) {
- ent->client->accuracy_hits++;
- }
- } else if ( !( tr.surfaceFlags & SURF_NOIMPACT ) ) {
- tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS );
- tent->s.eventParm = DirToByte( tr.plane.normal );
- }
-
- break;
- }
-}
-
-#ifdef MISSIONPACK
-/*
-======================================================================
-
-NAILGUN
-
-======================================================================
-*/
-
-void Weapon_Nailgun_Fire (gentity_t *ent) {
- gentity_t *m;
- int count;
-
- for( count = 0; count < NUM_NAILSHOTS; count++ ) {
- m = fire_nail (ent, muzzle, forward, right, up );
- m->damage *= s_quadFactor;
- m->splashDamage *= s_quadFactor;
- }
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
-}
-
-
-/*
-======================================================================
-
-PROXIMITY MINE LAUNCHER
-
-======================================================================
-*/
-
-void weapon_proxlauncher_fire (gentity_t *ent) {
- gentity_t *m;
-
- // extra vertical velocity
- forward[2] += 0.2f;
- VectorNormalize( forward );
-
- m = fire_prox (ent, muzzle, forward);
- m->damage *= s_quadFactor;
- m->splashDamage *= s_quadFactor;
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
-}
-
-#endif
-
-//======================================================================
-
-
-/*
-===============
-LogAccuracyHit
-===============
-*/
-qboolean LogAccuracyHit( gentity_t *target, gentity_t *attacker ) {
- if( !target->takedamage ) {
- return qfalse;
- }
-
- if ( target == attacker ) {
- return qfalse;
- }
-
- if( !target->client ) {
- return qfalse;
- }
-
- if( !attacker->client ) {
- return qfalse;
- }
-
- if( target->client->ps.stats[STAT_HEALTH] <= 0 ) {
- return qfalse;
- }
-
- if ( OnSameTeam( target, attacker ) ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-===============
-CalcMuzzlePoint
-
-set muzzle location relative to pivoting eye
-===============
-*/
-void CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {
- VectorCopy( ent->s.pos.trBase, muzzlePoint );
- muzzlePoint[2] += ent->client->ps.viewheight;
- VectorMA( muzzlePoint, 14, forward, muzzlePoint );
- // snap to integer coordinates for more efficient network bandwidth usage
- SnapVector( muzzlePoint );
-}
-
-/*
-===============
-CalcMuzzlePointOrigin
-
-set muzzle location relative to pivoting eye
-===============
-*/
-void CalcMuzzlePointOrigin ( gentity_t *ent, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {
- VectorCopy( ent->s.pos.trBase, muzzlePoint );
- muzzlePoint[2] += ent->client->ps.viewheight;
- VectorMA( muzzlePoint, 14, forward, muzzlePoint );
- // snap to integer coordinates for more efficient network bandwidth usage
- SnapVector( muzzlePoint );
-}
-
-
-
-/*
-===============
-FireWeapon
-===============
-*/
-void FireWeapon( gentity_t *ent ) {
- if (ent->client->ps.powerups[PW_QUAD] ) {
- s_quadFactor = g_quadfactor.value;
- } else {
- s_quadFactor = 1;
- }
-#ifdef MISSIONPACK
- if( ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->giTag == PW_DOUBLER ) {
- s_quadFactor *= 2;
- }
-#endif
-
- // track shots taken for accuracy tracking. Grapple is not a weapon and gauntet is just not tracked
- if( ent->s.weapon != WP_GRAPPLING_HOOK && ent->s.weapon != WP_GAUNTLET ) {
-#ifdef MISSIONPACK
- if( ent->s.weapon == WP_NAILGUN ) {
- ent->client->accuracy_shots += NUM_NAILSHOTS;
- } else {
- ent->client->accuracy_shots++;
- }
-#else
- ent->client->accuracy_shots++;
-#endif
- }
-
- // set aiming directions
- AngleVectors (ent->client->ps.viewangles, forward, right, up);
-
- CalcMuzzlePointOrigin ( ent, ent->client->oldOrigin, forward, right, up, muzzle );
-
- // fire the specific weapon
- switch( ent->s.weapon ) {
- case WP_GAUNTLET:
- Weapon_Gauntlet( ent );
- break;
- case WP_LIGHTNING:
- Weapon_LightningFire( ent );
- break;
- case WP_SHOTGUN:
- weapon_supershotgun_fire( ent );
- break;
- case WP_MACHINEGUN:
- if ( g_gametype.integer != GT_TEAM ) {
- Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_DAMAGE );
- } else {
- Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_TEAM_DAMAGE );
- }
- break;
- case WP_GRENADE_LAUNCHER:
- weapon_grenadelauncher_fire( ent );
- break;
- case WP_ROCKET_LAUNCHER:
- Weapon_RocketLauncher_Fire( ent );
- break;
- case WP_PLASMAGUN:
- Weapon_Plasmagun_Fire( ent );
- break;
- case WP_RAILGUN:
- weapon_railgun_fire( ent );
- break;
- case WP_BFG:
- BFG_Fire( ent );
- break;
- case WP_GRAPPLING_HOOK:
- Weapon_GrapplingHook_Fire( ent );
- break;
-#ifdef MISSIONPACK
- case WP_NAILGUN:
- Weapon_Nailgun_Fire( ent );
- break;
- case WP_PROX_LAUNCHER:
- weapon_proxlauncher_fire( ent );
- break;
- case WP_CHAINGUN:
- Bullet_Fire( ent, CHAINGUN_SPREAD, MACHINEGUN_DAMAGE );
- break;
-#endif
- default:
-// FIXME G_Error( "Bad ent->s.weapon" );
- break;
- }
-}
-
-
-#ifdef MISSIONPACK
-
-/*
-===============
-KamikazeRadiusDamage
-===============
-*/
-static void KamikazeRadiusDamage( vec3_t origin, gentity_t *attacker, float damage, float radius ) {
- float dist;
- gentity_t *ent;
- int entityList[MAX_GENTITIES];
- int numListedEntities;
- vec3_t mins, maxs;
- vec3_t v;
- vec3_t dir;
- int i, e;
-
- if ( radius < 1 ) {
- radius = 1;
- }
-
- for ( i = 0 ; i < 3 ; i++ ) {
- mins[i] = origin[i] - radius;
- maxs[i] = origin[i] + radius;
- }
-
- numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
-
- for ( e = 0 ; e < numListedEntities ; e++ ) {
- ent = &g_entities[entityList[ e ]];
-
- if (!ent->takedamage) {
- continue;
- }
-
- // dont hit things we have already hit
- if( ent->kamikazeTime > level.time ) {
- continue;
- }
-
- // find the distance from the edge of the bounding box
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( origin[i] < ent->r.absmin[i] ) {
- v[i] = ent->r.absmin[i] - origin[i];
- } else if ( origin[i] > ent->r.absmax[i] ) {
- v[i] = origin[i] - ent->r.absmax[i];
- } else {
- v[i] = 0;
- }
- }
-
- dist = VectorLength( v );
- if ( dist >= radius ) {
- continue;
- }
-
-// if( CanDamage (ent, origin) ) {
- VectorSubtract (ent->r.currentOrigin, origin, dir);
- // push the center of mass higher than the origin so players
- // get knocked into the air more
- dir[2] += 24;
- G_Damage( ent, NULL, attacker, dir, origin, damage, DAMAGE_RADIUS|DAMAGE_NO_TEAM_PROTECTION, MOD_KAMIKAZE );
- ent->kamikazeTime = level.time + 3000;
-// }
- }
-}
-
-/*
-===============
-KamikazeShockWave
-===============
-*/
-static void KamikazeShockWave( vec3_t origin, gentity_t *attacker, float damage, float push, float radius ) {
- float dist;
- gentity_t *ent;
- int entityList[MAX_GENTITIES];
- int numListedEntities;
- vec3_t mins, maxs;
- vec3_t v;
- vec3_t dir;
- int i, e;
-
- if ( radius < 1 )
- radius = 1;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- mins[i] = origin[i] - radius;
- maxs[i] = origin[i] + radius;
- }
-
- numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
-
- for ( e = 0 ; e < numListedEntities ; e++ ) {
- ent = &g_entities[entityList[ e ]];
-
- // dont hit things we have already hit
- if( ent->kamikazeShockTime > level.time ) {
- continue;
- }
-
- // find the distance from the edge of the bounding box
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( origin[i] < ent->r.absmin[i] ) {
- v[i] = ent->r.absmin[i] - origin[i];
- } else if ( origin[i] > ent->r.absmax[i] ) {
- v[i] = origin[i] - ent->r.absmax[i];
- } else {
- v[i] = 0;
- }
- }
-
- dist = VectorLength( v );
- if ( dist >= radius ) {
- continue;
- }
-
-// if( CanDamage (ent, origin) ) {
- VectorSubtract (ent->r.currentOrigin, origin, dir);
- dir[2] += 24;
- G_Damage( ent, NULL, attacker, dir, origin, damage, DAMAGE_RADIUS|DAMAGE_NO_TEAM_PROTECTION, MOD_KAMIKAZE );
- //
- dir[2] = 0;
- VectorNormalize(dir);
- if ( ent->client ) {
- ent->client->ps.velocity[0] = dir[0] * push;
- ent->client->ps.velocity[1] = dir[1] * push;
- ent->client->ps.velocity[2] = 100;
- }
- ent->kamikazeShockTime = level.time + 3000;
-// }
- }
-}
-
-/*
-===============
-KamikazeDamage
-===============
-*/
-static void KamikazeDamage( gentity_t *self ) {
- int i;
- float t;
- gentity_t *ent;
- vec3_t newangles;
-
- self->count += 100;
-
- if (self->count >= KAMI_SHOCKWAVE_STARTTIME) {
- // shockwave push back
- t = self->count - KAMI_SHOCKWAVE_STARTTIME;
- KamikazeShockWave(self->s.pos.trBase, self->activator, 25, 400, (int) (float) t * KAMI_SHOCKWAVE_MAXRADIUS / (KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVE_STARTTIME) );
- }
- //
- if (self->count >= KAMI_EXPLODE_STARTTIME) {
- // do our damage
- t = self->count - KAMI_EXPLODE_STARTTIME;
- KamikazeRadiusDamage( self->s.pos.trBase, self->activator, 400, (int) (float) t * KAMI_BOOMSPHERE_MAXRADIUS / (KAMI_IMPLODE_STARTTIME - KAMI_EXPLODE_STARTTIME) );
- }
-
- // either cycle or kill self
- if( self->count >= KAMI_SHOCKWAVE_ENDTIME ) {
- G_FreeEntity( self );
- return;
- }
- self->nextthink = level.time + 100;
-
- // add earth quake effect
- newangles[0] = crandom() * 2;
- newangles[1] = crandom() * 2;
- newangles[2] = 0;
- for (i = 0; i < MAX_CLIENTS; i++)
- {
- ent = &g_entities[i];
- if (!ent->inuse)
- continue;
- if (!ent->client)
- continue;
-
- if (ent->client->ps.groundEntityNum != ENTITYNUM_NONE) {
- ent->client->ps.velocity[0] += crandom() * 120;
- ent->client->ps.velocity[1] += crandom() * 120;
- ent->client->ps.velocity[2] = 30 + random() * 25;
- }
-
- ent->client->ps.delta_angles[0] += ANGLE2SHORT(newangles[0] - self->movedir[0]);
- ent->client->ps.delta_angles[1] += ANGLE2SHORT(newangles[1] - self->movedir[1]);
- ent->client->ps.delta_angles[2] += ANGLE2SHORT(newangles[2] - self->movedir[2]);
- }
- VectorCopy(newangles, self->movedir);
-}
-
-/*
-===============
-G_StartKamikaze
-===============
-*/
-void G_StartKamikaze( gentity_t *ent ) {
- gentity_t *explosion;
- gentity_t *te;
- vec3_t snapped;
-
- // start up the explosion logic
- explosion = G_Spawn();
-
- explosion->s.eType = ET_EVENTS + EV_KAMIKAZE;
- explosion->eventTime = level.time;
-
- if ( ent->client ) {
- VectorCopy( ent->s.pos.trBase, snapped );
- }
- else {
- VectorCopy( ent->activator->s.pos.trBase, snapped );
- }
- SnapVector( snapped ); // save network bandwidth
- G_SetOrigin( explosion, snapped );
-
- explosion->classname = "kamikaze";
- explosion->s.pos.trType = TR_STATIONARY;
-
- explosion->kamikazeTime = level.time;
-
- explosion->think = KamikazeDamage;
- explosion->nextthink = level.time + 100;
- explosion->count = 0;
- VectorClear(explosion->movedir);
-
- trap_LinkEntity( explosion );
-
- if (ent->client) {
- //
- explosion->activator = ent;
- //
- ent->s.eFlags &= ~EF_KAMIKAZE;
- // nuke the guy that used it
- G_Damage( ent, ent, ent, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_KAMIKAZE );
- }
- else {
- if ( !strcmp(ent->activator->classname, "bodyque") ) {
- explosion->activator = &g_entities[ent->activator->r.ownerNum];
- }
- else {
- explosion->activator = ent->activator;
- }
- }
-
- // play global sound at all clients
- te = G_TempEntity(snapped, EV_GLOBAL_TEAM_SOUND );
- te->r.svFlags |= SVF_BROADCAST;
- te->s.eventParm = GTS_KAMIKAZE;
-}
-#endif
diff --git a/engine/code/game/inv.h b/engine/code/game/inv.h
deleted file mode 100644
index dbbebcd..0000000
--- a/engine/code/game/inv.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#define INVENTORY_NONE 0
-//armor
-#define INVENTORY_ARMOR 1
-//weapons
-#define INVENTORY_GAUNTLET 4
-#define INVENTORY_SHOTGUN 5
-#define INVENTORY_MACHINEGUN 6
-#define INVENTORY_GRENADELAUNCHER 7
-#define INVENTORY_ROCKETLAUNCHER 8
-#define INVENTORY_LIGHTNING 9
-#define INVENTORY_RAILGUN 10
-#define INVENTORY_PLASMAGUN 11
-#define INVENTORY_BFG10K 13
-#define INVENTORY_GRAPPLINGHOOK 14
-#define INVENTORY_NAILGUN 15
-#define INVENTORY_PROXLAUNCHER 16
-#define INVENTORY_CHAINGUN 17
-//ammo
-#define INVENTORY_SHELLS 18
-#define INVENTORY_BULLETS 19
-#define INVENTORY_GRENADES 20
-#define INVENTORY_CELLS 21
-#define INVENTORY_LIGHTNINGAMMO 22
-#define INVENTORY_ROCKETS 23
-#define INVENTORY_SLUGS 24
-#define INVENTORY_BFGAMMO 25
-#define INVENTORY_NAILS 26
-#define INVENTORY_MINES 27
-#define INVENTORY_BELT 28
-//powerups
-#define INVENTORY_HEALTH 29
-#define INVENTORY_TELEPORTER 30
-#define INVENTORY_MEDKIT 31
-#define INVENTORY_KAMIKAZE 32
-#define INVENTORY_PORTAL 33
-#define INVENTORY_INVULNERABILITY 34
-#define INVENTORY_QUAD 35
-#define INVENTORY_ENVIRONMENTSUIT 36
-#define INVENTORY_HASTE 37
-#define INVENTORY_INVISIBILITY 38
-#define INVENTORY_REGEN 39
-#define INVENTORY_FLIGHT 40
-#define INVENTORY_SCOUT 41
-#define INVENTORY_GUARD 42
-#define INVENTORY_DOUBLER 43
-#define INVENTORY_AMMOREGEN 44
-
-#define INVENTORY_REDFLAG 45
-#define INVENTORY_BLUEFLAG 46
-#define INVENTORY_NEUTRALFLAG 47
-#define INVENTORY_REDCUBE 48
-#define INVENTORY_BLUECUBE 49
-//enemy stuff
-#define ENEMY_HORIZONTAL_DIST 200
-#define ENEMY_HEIGHT 201
-#define NUM_VISIBLE_ENEMIES 202
-#define NUM_VISIBLE_TEAMMATES 203
-
-// if running the mission pack
-#ifdef MISSIONPACK
-
-//#error "running mission pack"
-
-#endif
-
-//item numbers (make sure they are in sync with bg_itemlist in bg_misc.c)
-#define MODELINDEX_ARMORSHARD 1
-#define MODELINDEX_ARMORCOMBAT 2
-#define MODELINDEX_ARMORBODY 3
-#define MODELINDEX_HEALTHSMALL 4
-#define MODELINDEX_HEALTH 5
-#define MODELINDEX_HEALTHLARGE 6
-#define MODELINDEX_HEALTHMEGA 7
-
-#define MODELINDEX_GAUNTLET 8
-#define MODELINDEX_SHOTGUN 9
-#define MODELINDEX_MACHINEGUN 10
-#define MODELINDEX_GRENADELAUNCHER 11
-#define MODELINDEX_ROCKETLAUNCHER 12
-#define MODELINDEX_LIGHTNING 13
-#define MODELINDEX_RAILGUN 14
-#define MODELINDEX_PLASMAGUN 15
-#define MODELINDEX_BFG10K 16
-#define MODELINDEX_GRAPPLINGHOOK 17
-
-#define MODELINDEX_SHELLS 18
-#define MODELINDEX_BULLETS 19
-#define MODELINDEX_GRENADES 20
-#define MODELINDEX_CELLS 21
-#define MODELINDEX_LIGHTNINGAMMO 22
-#define MODELINDEX_ROCKETS 23
-#define MODELINDEX_SLUGS 24
-#define MODELINDEX_BFGAMMO 25
-
-#define MODELINDEX_TELEPORTER 26
-#define MODELINDEX_MEDKIT 27
-#define MODELINDEX_QUAD 28
-#define MODELINDEX_ENVIRONMENTSUIT 29
-#define MODELINDEX_HASTE 30
-#define MODELINDEX_INVISIBILITY 31
-#define MODELINDEX_REGEN 32
-#define MODELINDEX_FLIGHT 33
-
-#define MODELINDEX_REDFLAG 34
-#define MODELINDEX_BLUEFLAG 35
-
-// mission pack only defines
-
-#define MODELINDEX_KAMIKAZE 36
-#define MODELINDEX_PORTAL 37
-#define MODELINDEX_INVULNERABILITY 38
-
-#define MODELINDEX_NAILS 39
-#define MODELINDEX_MINES 40
-#define MODELINDEX_BELT 41
-
-#define MODELINDEX_SCOUT 42
-#define MODELINDEX_GUARD 43
-#define MODELINDEX_DOUBLER 44
-#define MODELINDEX_AMMOREGEN 45
-
-#define MODELINDEX_NEUTRALFLAG 46
-#define MODELINDEX_REDCUBE 47
-#define MODELINDEX_BLUECUBE 48
-
-#define MODELINDEX_NAILGUN 49
-#define MODELINDEX_PROXLAUNCHER 50
-#define MODELINDEX_CHAINGUN 51
-
-
-//
-#define WEAPONINDEX_GAUNTLET 1
-#define WEAPONINDEX_MACHINEGUN 2
-#define WEAPONINDEX_SHOTGUN 3
-#define WEAPONINDEX_GRENADE_LAUNCHER 4
-#define WEAPONINDEX_ROCKET_LAUNCHER 5
-#define WEAPONINDEX_LIGHTNING 6
-#define WEAPONINDEX_RAILGUN 7
-#define WEAPONINDEX_PLASMAGUN 8
-#define WEAPONINDEX_BFG 9
-#define WEAPONINDEX_GRAPPLING_HOOK 10
-#define WEAPONINDEX_NAILGUN 11
-#define WEAPONINDEX_PROXLAUNCHER 12
-#define WEAPONINDEX_CHAINGUN 13
diff --git a/engine/code/game/match.h b/engine/code/game/match.h
deleted file mode 100644
index a29d8fa..0000000
--- a/engine/code/game/match.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-// make sure this is the same character as we use in chats in g_cmd.c
-#define EC "\x19"
-
-//match template contexts
-#define MTCONTEXT_MISC 2
-#define MTCONTEXT_INITIALTEAMCHAT 4
-#define MTCONTEXT_TIME 8
-#define MTCONTEXT_TEAMMATE 16
-#define MTCONTEXT_ADDRESSEE 32
-#define MTCONTEXT_PATROLKEYAREA 64
-#define MTCONTEXT_REPLYCHAT 128
-#define MTCONTEXT_CTF 256
-
-//message types
-#define MSG_NEWLEADER 1 //new leader
-#define MSG_ENTERGAME 2 //enter game message
-#define MSG_HELP 3 //help someone
-#define MSG_ACCOMPANY 4 //accompany someone
-#define MSG_DEFENDKEYAREA 5 //defend a key area
-#define MSG_RUSHBASE 6 //everyone rush to base
-#define MSG_GETFLAG 7 //get the enemy flag
-#define MSG_STARTTEAMLEADERSHIP 8 //someone wants to become the team leader
-#define MSG_STOPTEAMLEADERSHIP 9 //someone wants to stop being the team leader
-#define MSG_WHOISTEAMLAEDER 10 //who is the team leader
-#define MSG_WAIT 11 //wait for someone
-#define MSG_WHATAREYOUDOING 12 //what are you doing?
-#define MSG_JOINSUBTEAM 13 //join a sub-team
-#define MSG_LEAVESUBTEAM 14 //leave a sub-team
-#define MSG_CREATENEWFORMATION 15 //create a new formation
-#define MSG_FORMATIONPOSITION 16 //tell someone his/her position in a formation
-#define MSG_FORMATIONSPACE 17 //set the formation intervening space
-#define MSG_DOFORMATION 18 //form a known formation
-#define MSG_DISMISS 19 //dismiss commanded team mates
-#define MSG_CAMP 20 //camp somewhere
-#define MSG_CHECKPOINT 21 //remember a check point
-#define MSG_PATROL 22 //patrol between certain keypoints
-#define MSG_LEADTHEWAY 23 //lead the way
-#define MSG_GETITEM 24 //get an item
-#define MSG_KILL 25 //kill someone
-#define MSG_WHEREAREYOU 26 //where is someone
-#define MSG_RETURNFLAG 27 //return the flag
-#define MSG_WHATISMYCOMMAND 28 //ask the team leader what to do
-#define MSG_WHICHTEAM 29 //ask which team a bot is in
-#define MSG_TASKPREFERENCE 30 //tell your teamplay task preference
-#define MSG_ATTACKENEMYBASE 31 //attack the enemy base
-#define MSG_HARVEST 32 //go harvest
-#define MSG_SUICIDE 33 //order to suicide
-//
-#define MSG_ME 100
-#define MSG_EVERYONE 101
-#define MSG_MULTIPLENAMES 102
-#define MSG_NAME 103
-#define MSG_PATROLKEYAREA 104
-#define MSG_MINUTES 105
-#define MSG_SECONDS 106
-#define MSG_FOREVER 107
-#define MSG_FORALONGTIME 108
-#define MSG_FORAWHILE 109
-//
-#define MSG_CHATALL 200
-#define MSG_CHATTEAM 201
-#define MSG_CHATTELL 202
-//
-#define MSG_CTF 300 //ctf message
-
-//command sub types
-#define ST_SOMEWHERE 0
-#define ST_NEARITEM 1
-#define ST_ADDRESSED 2
-#define ST_METER 4
-#define ST_FEET 8
-#define ST_TIME 16
-#define ST_HERE 32
-#define ST_THERE 64
-#define ST_I 128
-#define ST_MORE 256
-#define ST_BACK 512
-#define ST_REVERSE 1024
-#define ST_SOMEONE 2048
-#define ST_GOTFLAG 4096
-#define ST_CAPTUREDFLAG 8192
-#define ST_RETURNEDFLAG 16384
-#define ST_TEAM 32768
-#define ST_1FCTFGOTFLAG 65535
-//ctf task preferences
-#define ST_DEFENDER 1
-#define ST_ATTACKER 2
-#define ST_ROAMER 4
-
-
-//word replacement variables
-#define THE_ENEMY 7
-#define THE_TEAM 7
-//team message variables
-#define NETNAME 0
-#define PLACE 1
-#define FLAG 1
-#define MESSAGE 2
-#define ADDRESSEE 2
-#define ITEM 3
-#define TEAMMATE 4
-#define TEAMNAME 4
-#define ENEMY 4
-#define KEYAREA 5
-#define FORMATION 5
-#define POSITION 5
-#define NUMBER 5
-#define TIME 6
-#define NAME 6
-#define MORE 6
-
-
diff --git a/engine/code/jpeg-6b/README b/engine/code/jpeg-6b/README
deleted file mode 100644
index 86cc206..0000000
--- a/engine/code/jpeg-6b/README
+++ /dev/null
@@ -1,385 +0,0 @@
-The Independent JPEG Group's JPEG software
-==========================================
-
-README for release 6b of 27-Mar-1998
-====================================
-
-This distribution contains the sixth public release of the Independent JPEG
-Group's free JPEG software. You are welcome to redistribute this software and
-to use it for any purpose, subject to the conditions under LEGAL ISSUES, below.
-
-Serious users of this software (particularly those incorporating it into
-larger programs) should contact IJG at jpeg-info at uunet.uu.net to be added to
-our electronic mailing list. Mailing list members are notified of updates
-and have a chance to participate in technical discussions, etc.
-
-This software is the work of Tom Lane, Philip Gladstone, Jim Boucher,
-Lee Crocker, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi,
-Guido Vollbeding, Ge' Weijers, and other members of the Independent JPEG
-Group.
-
-IJG is not affiliated with the official ISO JPEG standards committee.
-
-
-DOCUMENTATION ROADMAP
-=====================
-
-This file contains the following sections:
-
-OVERVIEW General description of JPEG and the IJG software.
-LEGAL ISSUES Copyright, lack of warranty, terms of distribution.
-REFERENCES Where to learn more about JPEG.
-ARCHIVE LOCATIONS Where to find newer versions of this software.
-RELATED SOFTWARE Other stuff you should get.
-FILE FORMAT WARS Software *not* to get.
-TO DO Plans for future IJG releases.
-
-Other documentation files in the distribution are:
-
-User documentation:
- install.doc How to configure and install the IJG software.
- usage.doc Usage instructions for cjpeg, djpeg, jpegtran,
- rdjpgcom, and wrjpgcom.
- *.1 Unix-style man pages for programs (same info as usage.doc).
- wizard.doc Advanced usage instructions for JPEG wizards only.
- change.log Version-to-version change highlights.
-Programmer and internal documentation:
- libjpeg.doc How to use the JPEG library in your own programs.
- example.c Sample code for calling the JPEG library.
- structure.doc Overview of the JPEG library's internal structure.
- filelist.doc Road map of IJG files.
- coderules.doc Coding style rules --- please read if you contribute code.
-
-Please read at least the files install.doc and usage.doc. Useful information
-can also be found in the JPEG FAQ (Frequently Asked Questions) article. See
-ARCHIVE LOCATIONS below to find out where to obtain the FAQ article.
-
-If you want to understand how the JPEG code works, we suggest reading one or
-more of the REFERENCES, then looking at the documentation files (in roughly
-the order listed) before diving into the code.
-
-
-OVERVIEW
-========
-
-This package contains C software to implement JPEG image compression and
-decompression. JPEG (pronounced "jay-peg") is a standardized compression
-method for full-color and gray-scale images. JPEG is intended for compressing
-"real-world" scenes; line drawings, cartoons and other non-realistic images
-are not its strong suit. JPEG is lossy, meaning that the output image is not
-exactly identical to the input image. Hence you must not use JPEG if you
-have to have identical output bits. However, on typical photographic images,
-very good compression levels can be obtained with no visible change, and
-remarkably high compression levels are possible if you can tolerate a
-low-quality image. For more details, see the references, or just experiment
-with various compression settings.
-
-This software implements JPEG baseline, extended-sequential, and progressive
-compression processes. Provision is made for supporting all variants of these
-processes, although some uncommon parameter settings aren't implemented yet.
-For legal reasons, we are not distributing code for the arithmetic-coding
-variants of JPEG; see LEGAL ISSUES. We have made no provision for supporting
-the hierarchical or lossless processes defined in the standard.
-
-We provide a set of library routines for reading and writing JPEG image files,
-plus two sample applications "cjpeg" and "djpeg", which use the library to
-perform conversion between JPEG and some other popular image file formats.
-The library is intended to be reused in other applications.
-
-In order to support file conversion and viewing software, we have included
-considerable functionality beyond the bare JPEG coding/decoding capability;
-for example, the color quantization modules are not strictly part of JPEG
-decoding, but they are essential for output to colormapped file formats or
-colormapped displays. These extra functions can be compiled out of the
-library if not required for a particular application. We have also included
-"jpegtran", a utility for lossless transcoding between different JPEG
-processes, and "rdjpgcom" and "wrjpgcom", two simple applications for
-inserting and extracting textual comments in JFIF files.
-
-The emphasis in designing this software has been on achieving portability and
-flexibility, while also making it fast enough to be useful. In particular,
-the software is not intended to be read as a tutorial on JPEG. (See the
-REFERENCES section for introductory material.) Rather, it is intended to
-be reliable, portable, industrial-strength code. We do not claim to have
-achieved that goal in every aspect of the software, but we strive for it.
-
-We welcome the use of this software as a component of commercial products.
-No royalty is required, but we do ask for an acknowledgement in product
-documentation, as described under LEGAL ISSUES.
-
-
-LEGAL ISSUES
-============
-
-In plain English:
-
-1. We don't promise that this software works. (But if you find any bugs,
- please let us know!)
-2. You can use this software for whatever you want. You don't have to pay us.
-3. You may not pretend that you wrote this software. If you use it in a
- program, you must acknowledge somewhere in your documentation that
- you've used the IJG code.
-
-In legalese:
-
-The authors make NO WARRANTY or representation, either express or implied,
-with respect to this software, its quality, accuracy, merchantability, or
-fitness for a particular purpose. This software is provided "AS IS", and you,
-its user, assume the entire risk as to its quality and accuracy.
-
-This software is copyright (C) 1991-1998, Thomas G. Lane.
-All Rights Reserved except as specified below.
-
-Permission is hereby granted to use, copy, modify, and distribute this
-software (or portions thereof) for any purpose, without fee, subject to these
-conditions:
-(1) If any part of the source code for this software is distributed, then this
-README file must be included, with this copyright and no-warranty notice
-unaltered; and any additions, deletions, or changes to the original files
-must be clearly indicated in accompanying documentation.
-(2) If only executable code is distributed, then the accompanying
-documentation must state that "this software is based in part on the work of
-the Independent JPEG Group".
-(3) Permission for use of this software is granted only if the user accepts
-full responsibility for any undesirable consequences; the authors accept
-NO LIABILITY for damages of any kind.
-
-These conditions apply to any software derived from or based on the IJG code,
-not just to the unmodified library. If you use our work, you ought to
-acknowledge us.
-
-Permission is NOT granted for the use of any IJG author's name or company name
-in advertising or publicity relating to this software or products derived from
-it. This software may be referred to only as "the Independent JPEG Group's
-software".
-
-We specifically permit and encourage the use of this software as the basis of
-commercial products, provided that all warranty or liability claims are
-assumed by the product vendor.
-
-
-ansi2knr.c is included in this distribution by permission of L. Peter Deutsch,
-sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA.
-ansi2knr.c is NOT covered by the above copyright and conditions, but instead
-by the usual distribution terms of the Free Software Foundation; principally,
-that you must include source code if you redistribute it. (See the file
-ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part
-of any program generated from the IJG code, this does not limit you more than
-the foregoing paragraphs do.
-
-The Unix configuration script "configure" was produced with GNU Autoconf.
-It is copyright by the Free Software Foundation but is freely distributable.
-The same holds for its supporting scripts (config.guess, config.sub,
-ltconfig, ltmain.sh). Another support script, install-sh, is copyright
-by M.I.T. but is also freely distributable.
-
-It appears that the arithmetic coding option of the JPEG spec is covered by
-patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot
-legally be used without obtaining one or more licenses. For this reason,
-support for arithmetic coding has been removed from the free JPEG software.
-(Since arithmetic coding provides only a marginal gain over the unpatented
-Huffman mode, it is unlikely that very many implementations will support it.)
-So far as we are aware, there are no patent restrictions on the remaining
-code.
-
-The IJG distribution formerly included code to read and write GIF files.
-To avoid entanglement with the Unisys LZW patent, GIF reading support has
-been removed altogether, and the GIF writer has been simplified to produce
-"uncompressed GIFs". This technique does not use the LZW algorithm; the
-resulting GIF files are larger than usual, but are readable by all standard
-GIF decoders.
-
-We are required to state that
- "The Graphics Interchange Format(c) is the Copyright property of
- CompuServe Incorporated. GIF(sm) is a Service Mark property of
- CompuServe Incorporated."
-
-
-REFERENCES
-==========
-
-We highly recommend reading one or more of these references before trying to
-understand the innards of the JPEG software.
-
-The best short technical introduction to the JPEG compression algorithm is
- Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
- Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
-(Adjacent articles in that issue discuss MPEG motion picture compression,
-applications of JPEG, and related topics.) If you don't have the CACM issue
-handy, a PostScript file containing a revised version of Wallace's article is
-available at ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz. The file (actually
-a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
-omits the sample images that appeared in CACM, but it includes corrections
-and some added material. Note: the Wallace article is copyright ACM and IEEE,
-and it may not be used for commercial purposes.
-
-A somewhat less technical, more leisurely introduction to JPEG can be found in
-"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by
-M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides
-good explanations and example C code for a multitude of compression methods
-including JPEG. It is an excellent source if you are comfortable reading C
-code but don't know much about data compression in general. The book's JPEG
-sample code is far from industrial-strength, but when you are ready to look
-at a full implementation, you've got one here...
-
-The best full description of JPEG is the textbook "JPEG Still Image Data
-Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published
-by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp.
-The book includes the complete text of the ISO JPEG standards (DIS 10918-1
-and draft DIS 10918-2). This is by far the most complete exposition of JPEG
-in existence, and we highly recommend it.
-
-The JPEG standard itself is not available electronically; you must order a
-paper copy through ISO or ITU. (Unless you feel a need to own a certified
-official copy, we recommend buying the Pennebaker and Mitchell book instead;
-it's much cheaper and includes a great deal of useful explanatory material.)
-In the USA, copies of the standard may be ordered from ANSI Sales at (212)
-642-4900, or from Global Engineering Documents at (800) 854-7179. (ANSI
-doesn't take credit card orders, but Global does.) It's not cheap: as of
-1992, ANSI was charging $95 for Part 1 and $47 for Part 2, plus 7%
-shipping/handling. The standard is divided into two parts, Part 1 being the
-actual specification, while Part 2 covers compliance testing methods. Part 1
-is titled "Digital Compression and Coding of Continuous-tone Still Images,
-Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS
-10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of
-Continuous-tone Still Images, Part 2: Compliance testing" and has document
-numbers ISO/IEC IS 10918-2, ITU-T T.83.
-
-Some extensions to the original JPEG standard are defined in JPEG Part 3,
-a newer ISO standard numbered ISO/IEC IS 10918-3 and ITU-T T.84. IJG
-currently does not support any Part 3 extensions.
-
-The JPEG standard does not specify all details of an interchangeable file
-format. For the omitted details we follow the "JFIF" conventions, revision
-1.02. A copy of the JFIF spec is available from:
- Literature Department
- C-Cube Microsystems, Inc.
- 1778 McCarthy Blvd.
- Milpitas, CA 95035
- phone (408) 944-6300, fax (408) 944-6314
-A PostScript version of this document is available by FTP at
-ftp://ftp.uu.net/graphics/jpeg/jfif.ps.gz. There is also a plain text
-version at ftp://ftp.uu.net/graphics/jpeg/jfif.txt.gz, but it is missing
-the figures.
-
-The TIFF 6.0 file format specification can be obtained by FTP from
-ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme
-found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems.
-IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6).
-Instead, we recommend the JPEG design proposed by TIFF Technical Note #2
-(Compression tag 7). Copies of this Note can be obtained from ftp.sgi.com or
-from ftp://ftp.uu.net/graphics/jpeg/. It is expected that the next revision
-of the TIFF spec will replace the 6.0 JPEG design with the Note's design.
-Although IJG's own code does not support TIFF/JPEG, the free libtiff library
-uses our library to implement TIFF/JPEG per the Note. libtiff is available
-from ftp://ftp.sgi.com/graphics/tiff/.
-
-
-ARCHIVE LOCATIONS
-=================
-
-The "official" archive site for this software is ftp.uu.net (Internet
-address 192.48.96.9). The most recent released version can always be found
-there in directory graphics/jpeg. This particular version will be archived
-as ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz. If you don't have
-direct Internet access, UUNET's archives are also available via UUCP; contact
-help at uunet.uu.net for information on retrieving files that way.
-
-Numerous Internet sites maintain copies of the UUNET files. However, only
-ftp.uu.net is guaranteed to have the latest official version.
-
-You can also obtain this software in DOS-compatible "zip" archive format from
-the SimTel archives (ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/), or
-on CompuServe in the Graphics Support forum (GO CIS:GRAPHSUP), library 12
-"JPEG Tools". Again, these versions may sometimes lag behind the ftp.uu.net
-release.
-
-The JPEG FAQ (Frequently Asked Questions) article is a useful source of
-general information about JPEG. It is updated constantly and therefore is
-not included in this distribution. The FAQ is posted every two weeks to
-Usenet newsgroups comp.graphics.misc, news.answers, and other groups.
-It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/
-and other news.answers archive sites, including the official news.answers
-archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/.
-If you don't have Web or FTP access, send e-mail to mail-server at rtfm.mit.edu
-with body
- send usenet/news.answers/jpeg-faq/part1
- send usenet/news.answers/jpeg-faq/part2
-
-
-RELATED SOFTWARE
-================
-
-Numerous viewing and image manipulation programs now support JPEG. (Quite a
-few of them use this library to do so.) The JPEG FAQ described above lists
-some of the more popular free and shareware viewers, and tells where to
-obtain them on Internet.
-
-If you are on a Unix machine, we highly recommend Jef Poskanzer's free
-PBMPLUS software, which provides many useful operations on PPM-format image
-files. In particular, it can convert PPM images to and from a wide range of
-other formats, thus making cjpeg/djpeg considerably more useful. The latest
-version is distributed by the NetPBM group, and is available from numerous
-sites, notably ftp://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/.
-Unfortunately PBMPLUS/NETPBM is not nearly as portable as the IJG software is;
-you are likely to have difficulty making it work on any non-Unix machine.
-
-A different free JPEG implementation, written by the PVRG group at Stanford,
-is available from ftp://havefun.stanford.edu/pub/jpeg/. This program
-is designed for research and experimentation rather than production use;
-it is slower, harder to use, and less portable than the IJG code, but it
-is easier to read and modify. Also, the PVRG code supports lossless JPEG,
-which we do not. (On the other hand, it doesn't do progressive JPEG.)
-
-
-FILE FORMAT WARS
-================
-
-Some JPEG programs produce files that are not compatible with our library.
-The root of the problem is that the ISO JPEG committee failed to specify a
-concrete file format. Some vendors "filled in the blanks" on their own,
-creating proprietary formats that no one else could read. (For example, none
-of the early commercial JPEG implementations for the Macintosh were able to
-exchange compressed files.)
-
-The file format we have adopted is called JFIF (see REFERENCES). This format
-has been agreed to by a number of major commercial JPEG vendors, and it has
-become the de facto standard. JFIF is a minimal or "low end" representation.
-We recommend the use of TIFF/JPEG (TIFF revision 6.0 as modified by TIFF
-Technical Note #2) for "high end" applications that need to record a lot of
-additional data about an image. TIFF/JPEG is fairly new and not yet widely
-supported, unfortunately.
-
-The upcoming JPEG Part 3 standard defines a file format called SPIFF.
-SPIFF is interoperable with JFIF, in the sense that most JFIF decoders should
-be able to read the most common variant of SPIFF. SPIFF has some technical
-advantages over JFIF, but its major claim to fame is simply that it is an
-official standard rather than an informal one. At this point it is unclear
-whether SPIFF will supersede JFIF or whether JFIF will remain the de-facto
-standard. IJG intends to support SPIFF once the standard is frozen, but we
-have not decided whether it should become our default output format or not.
-(In any case, our decoder will remain capable of reading JFIF indefinitely.)
-
-Various proprietary file formats incorporating JPEG compression also exist.
-We have little or no sympathy for the existence of these formats. Indeed,
-one of the original reasons for developing this free software was to help
-force convergence on common, open format standards for JPEG files. Don't
-use a proprietary file format!
-
-
-TO DO
-=====
-
-The major thrust for v7 will probably be improvement of visual quality.
-The current method for scaling the quantization tables is known not to be
-very good at low Q values. We also intend to investigate block boundary
-smoothing, "poor man's variable quantization", and other means of improving
-quality-vs-file-size performance without sacrificing compatibility.
-
-In future versions, we are considering supporting some of the upcoming JPEG
-Part 3 extensions --- principally, variable quantization and the SPIFF file
-format.
-
-As always, speeding things up is of great interest.
-
-Please send bug reports, offers of help, etc. to jpeg-info at uunet.uu.net.
diff --git a/engine/code/jpeg-6b/ioq3-changes.diff b/engine/code/jpeg-6b/ioq3-changes.diff
deleted file mode 100644
index 1ce424b..0000000
--- a/engine/code/jpeg-6b/ioq3-changes.diff
+++ /dev/null
@@ -1,916 +0,0 @@
-diff -u -w /home/tma/sources/jpeg-6b/jcdctmgr.c ./jcdctmgr.c
---- /home/tma/sources/jpeg-6b/jcdctmgr.c 1996-01-13 19:15:12.000000000 +0000
-+++ ./jcdctmgr.c 2008-08-22 00:07:09.000000000 +0100
-@@ -57,7 +57,6 @@
- int ci, qtblno, i;
- jpeg_component_info *compptr;
- JQUANT_TBL * qtbl;
-- DCTELEM * dtbl;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
-@@ -168,6 +167,8 @@
- }
-
-
-+/* code/jpeg-6b/jcdctmgr.c:184: warning: âforward_DCTâ defined but not used */
-+#if 0
- /*
- * Perform forward DCT on one or more blocks of a component.
- *
-@@ -262,6 +263,7 @@
- }
- }
- }
-+#endif
-
-
- #ifdef DCT_FLOAT_SUPPORTED
-diff -u -w /home/tma/sources/jpeg-6b/jcmainct.c ./jcmainct.c
---- /home/tma/sources/jpeg-6b/jcmainct.c 1996-01-06 23:24:59.000000000 +0000
-+++ ./jcmainct.c 2008-08-22 00:10:21.000000000 +0100
-@@ -68,32 +68,32 @@
- METHODDEF(void)
- start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
- {
-- my_main_ptr main = (my_main_ptr) cinfo->main;
-+ my_main_ptr jmain = (my_main_ptr) cinfo->main;
-
- /* Do nothing in raw-data mode. */
- if (cinfo->raw_data_in)
- return;
-
-- main->cur_iMCU_row = 0; /* initialize counters */
-- main->rowgroup_ctr = 0;
-- main->suspended = FALSE;
-- main->pass_mode = pass_mode; /* save mode for use by process_data */
-+ jmain->cur_iMCU_row = 0; /* initialize counters */
-+ jmain->rowgroup_ctr = 0;
-+ jmain->suspended = FALSE;
-+ jmain->pass_mode = pass_mode; /* save mode for use by process_data */
-
- switch (pass_mode) {
- case JBUF_PASS_THRU:
- #ifdef FULL_MAIN_BUFFER_SUPPORTED
-- if (main->whole_image[0] != NULL)
-+ if (jmain->whole_image[0] != NULL)
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- #endif
-- main->pub.process_data = process_data_simple_main;
-+ jmain->pub.process_data = process_data_simple_main;
- break;
- #ifdef FULL_MAIN_BUFFER_SUPPORTED
- case JBUF_SAVE_SOURCE:
- case JBUF_CRANK_DEST:
- case JBUF_SAVE_AND_PASS:
-- if (main->whole_image[0] == NULL)
-+ if (jmain->whole_image[0] == NULL)
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
-- main->pub.process_data = process_data_buffer_main;
-+ jmain->pub.process_data = process_data_buffer_main;
- break;
- #endif
- default:
-@@ -114,46 +114,46 @@
- JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
- JDIMENSION in_rows_avail)
- {
-- my_main_ptr main = (my_main_ptr) cinfo->main;
-+ my_main_ptr jmain = (my_main_ptr) cinfo->main;
-
-- while (main->cur_iMCU_row < cinfo->total_iMCU_rows) {
-- /* Read input data if we haven't filled the main buffer yet */
-- if (main->rowgroup_ctr < DCTSIZE)
-+ while (jmain->cur_iMCU_row < cinfo->total_iMCU_rows) {
-+ /* Read input data if we haven't filled the jmain buffer yet */
-+ if (jmain->rowgroup_ctr < DCTSIZE)
- (*cinfo->prep->pre_process_data) (cinfo,
- input_buf, in_row_ctr, in_rows_avail,
-- main->buffer, &main->rowgroup_ctr,
-+ jmain->buffer, &jmain->rowgroup_ctr,
- (JDIMENSION) DCTSIZE);
-
- /* If we don't have a full iMCU row buffered, return to application for
- * more data. Note that preprocessor will always pad to fill the iMCU row
- * at the bottom of the image.
- */
-- if (main->rowgroup_ctr != DCTSIZE)
-+ if (jmain->rowgroup_ctr != DCTSIZE)
- return;
-
- /* Send the completed row to the compressor */
-- if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) {
-+ if (! (*cinfo->coef->compress_data) (cinfo, jmain->buffer)) {
- /* If compressor did not consume the whole row, then we must need to
- * suspend processing and return to the application. In this situation
- * we pretend we didn't yet consume the last input row; otherwise, if
- * it happened to be the last row of the image, the application would
- * think we were done.
- */
-- if (! main->suspended) {
-+ if (! jmain->suspended) {
- (*in_row_ctr)--;
-- main->suspended = TRUE;
-+ jmain->suspended = TRUE;
- }
- return;
- }
- /* We did finish the row. Undo our little suspension hack if a previous
-- * call suspended; then mark the main buffer empty.
-+ * call suspended; then mark the jmain buffer empty.
- */
-- if (main->suspended) {
-+ if (jmain->suspended) {
- (*in_row_ctr)++;
-- main->suspended = FALSE;
-+ jmain->suspended = FALSE;
- }
-- main->rowgroup_ctr = 0;
-- main->cur_iMCU_row++;
-+ jmain->rowgroup_ctr = 0;
-+ jmain->cur_iMCU_row++;
- }
- }
-
-@@ -170,25 +170,25 @@
- JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
- JDIMENSION in_rows_avail)
- {
-- my_main_ptr main = (my_main_ptr) cinfo->main;
-+ my_main_ptr jmain = (my_main_ptr) cinfo->main;
- int ci;
- jpeg_component_info *compptr;
-- boolean writing = (main->pass_mode != JBUF_CRANK_DEST);
-+ boolean writing = (jmain->pass_mode != JBUF_CRANK_DEST);
-
-- while (main->cur_iMCU_row < cinfo->total_iMCU_rows) {
-+ while (jmain->cur_iMCU_row < cinfo->total_iMCU_rows) {
- /* Realign the virtual buffers if at the start of an iMCU row. */
-- if (main->rowgroup_ctr == 0) {
-+ if (jmain->rowgroup_ctr == 0) {
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
-- main->buffer[ci] = (*cinfo->mem->access_virt_sarray)
-- ((j_common_ptr) cinfo, main->whole_image[ci],
-- main->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE),
-+ jmain->buffer[ci] = (*cinfo->mem->access_virt_sarray)
-+ ((j_common_ptr) cinfo, jmain->whole_image[ci],
-+ jmain->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE),
- (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing);
- }
- /* In a read pass, pretend we just read some source data. */
- if (! writing) {
- *in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE;
-- main->rowgroup_ctr = DCTSIZE;
-+ jmain->rowgroup_ctr = DCTSIZE;
- }
- }
-
-@@ -197,40 +197,40 @@
- if (writing) {
- (*cinfo->prep->pre_process_data) (cinfo,
- input_buf, in_row_ctr, in_rows_avail,
-- main->buffer, &main->rowgroup_ctr,
-+ jmain->buffer, &jmain->rowgroup_ctr,
- (JDIMENSION) DCTSIZE);
- /* Return to application if we need more data to fill the iMCU row. */
-- if (main->rowgroup_ctr < DCTSIZE)
-+ if (jmain->rowgroup_ctr < DCTSIZE)
- return;
- }
-
- /* Emit data, unless this is a sink-only pass. */
-- if (main->pass_mode != JBUF_SAVE_SOURCE) {
-- if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) {
-+ if (jmain->pass_mode != JBUF_SAVE_SOURCE) {
-+ if (! (*cinfo->coef->compress_data) (cinfo, jmain->buffer)) {
- /* If compressor did not consume the whole row, then we must need to
- * suspend processing and return to the application. In this situation
- * we pretend we didn't yet consume the last input row; otherwise, if
- * it happened to be the last row of the image, the application would
- * think we were done.
- */
-- if (! main->suspended) {
-+ if (! jmain->suspended) {
- (*in_row_ctr)--;
-- main->suspended = TRUE;
-+ jmain->suspended = TRUE;
- }
- return;
- }
- /* We did finish the row. Undo our little suspension hack if a previous
-- * call suspended; then mark the main buffer empty.
-+ * call suspended; then mark the jmain buffer empty.
- */
-- if (main->suspended) {
-+ if (jmain->suspended) {
- (*in_row_ctr)++;
-- main->suspended = FALSE;
-+ jmain->suspended = FALSE;
- }
- }
-
- /* If get here, we are done with this iMCU row. Mark buffer empty. */
-- main->rowgroup_ctr = 0;
-- main->cur_iMCU_row++;
-+ jmain->rowgroup_ctr = 0;
-+ jmain->cur_iMCU_row++;
- }
- }
-
-@@ -238,21 +238,21 @@
-
-
- /*
-- * Initialize main buffer controller.
-+ * Initialize jmain buffer controller.
- */
-
- GLOBAL(void)
- jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
- {
-- my_main_ptr main;
-+ my_main_ptr jmain;
- int ci;
- jpeg_component_info *compptr;
-
-- main = (my_main_ptr)
-+ jmain = (my_main_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_main_controller));
-- cinfo->main = (struct jpeg_c_main_controller *) main;
-- main->pub.start_pass = start_pass_main;
-+ cinfo->main = (struct jpeg_c_main_controller *) jmain;
-+ jmain->pub.start_pass = start_pass_main;
-
- /* We don't need to create a buffer in raw-data mode. */
- if (cinfo->raw_data_in)
-@@ -267,7 +267,7 @@
- /* Note we pad the bottom to a multiple of the iMCU height */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
-- main->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
-+ jmain->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
- compptr->width_in_blocks * DCTSIZE,
- (JDIMENSION) jround_up((long) compptr->height_in_blocks,
-@@ -279,12 +279,12 @@
- #endif
- } else {
- #ifdef FULL_MAIN_BUFFER_SUPPORTED
-- main->whole_image[0] = NULL; /* flag for no virtual arrays */
-+ jmain->whole_image[0] = NULL; /* flag for no virtual arrays */
- #endif
- /* Allocate a strip buffer for each component */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
-- main->buffer[ci] = (*cinfo->mem->alloc_sarray)
-+ jmain->buffer[ci] = (*cinfo->mem->alloc_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- compptr->width_in_blocks * DCTSIZE,
- (JDIMENSION) (compptr->v_samp_factor * DCTSIZE));
-diff -u -w /home/tma/sources/jpeg-6b/jdatasrc.c ./jdatasrc.c
---- /home/tma/sources/jpeg-6b/jdatasrc.c 1996-01-06 23:26:42.000000000 +0000
-+++ ./jdatasrc.c 2008-08-22 00:00:59.000000000 +0100
-@@ -19,13 +19,17 @@
- #include "jpeglib.h"
- #include "jerror.h"
-
-+#ifndef MIN
-+#define MIN(a, b) ((a)<(b)?(a):(b))
-+#endif
-
- /* Expanded data source object for stdio input */
-
- typedef struct {
- struct jpeg_source_mgr pub; /* public fields */
-
-- FILE * infile; /* source stream */
-+ unsigned char *inbuf; /* source stream */
-+ size_t inbufbytes;
- JOCTET * buffer; /* start of buffer */
- boolean start_of_file; /* have we gotten any data yet? */
- } my_source_mgr;
-@@ -90,18 +94,19 @@
- fill_input_buffer (j_decompress_ptr cinfo)
- {
- my_src_ptr src = (my_src_ptr) cinfo->src;
-- size_t nbytes;
--
-- nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE);
-+ size_t nbytes = MIN(src->inbufbytes, INPUT_BUF_SIZE);
-
- if (nbytes <= 0) {
-- if (src->start_of_file) /* Treat empty input file as fatal error */
-- ERREXIT(cinfo, JERR_INPUT_EMPTY);
- WARNMS(cinfo, JWRN_JPEG_EOF);
- /* Insert a fake EOI marker */
- src->buffer[0] = (JOCTET) 0xFF;
- src->buffer[1] = (JOCTET) JPEG_EOI;
- nbytes = 2;
-+ } else {
-+ memcpy( src->buffer, src->inbuf, nbytes);
-+
-+ src->inbuf += nbytes;
-+ src->inbufbytes -= nbytes;
- }
-
- src->pub.next_input_byte = src->buffer;
-@@ -179,7 +184,7 @@
- */
-
- GLOBAL(void)
--jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
-+jpeg_mem_src (j_decompress_ptr cinfo, unsigned char *inbuf, size_t size)
- {
- my_src_ptr src;
-
-@@ -206,7 +211,8 @@
- src->pub.skip_input_data = skip_input_data;
- src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
- src->pub.term_source = term_source;
-- src->infile = infile;
-+ src->inbuf = inbuf;
-+ src->inbufbytes = size;
- src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
- src->pub.next_input_byte = NULL; /* until buffer loaded */
- }
-diff -u -w /home/tma/sources/jpeg-6b/jdmainct.c ./jdmainct.c
---- /home/tma/sources/jpeg-6b/jdmainct.c 1996-01-06 23:27:17.000000000 +0000
-+++ ./jdmainct.c 2008-08-22 00:13:48.000000000 +0100
-@@ -159,7 +159,7 @@
- * This is done only once, not once per pass.
- */
- {
-- my_main_ptr main = (my_main_ptr) cinfo->main;
-+ my_main_ptr jmain = (my_main_ptr) cinfo->main;
- int ci, rgroup;
- int M = cinfo->min_DCT_scaled_size;
- jpeg_component_info *compptr;
-@@ -168,10 +168,10 @@
- /* Get top-level space for component array pointers.
- * We alloc both arrays with one call to save a few cycles.
- */
-- main->xbuffer[0] = (JSAMPIMAGE)
-+ jmain->xbuffer[0] = (JSAMPIMAGE)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- cinfo->num_components * 2 * SIZEOF(JSAMPARRAY));
-- main->xbuffer[1] = main->xbuffer[0] + cinfo->num_components;
-+ jmain->xbuffer[1] = jmain->xbuffer[0] + cinfo->num_components;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
-@@ -184,9 +184,9 @@
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW));
- xbuf += rgroup; /* want one row group at negative offsets */
-- main->xbuffer[0][ci] = xbuf;
-+ jmain->xbuffer[0][ci] = xbuf;
- xbuf += rgroup * (M + 4);
-- main->xbuffer[1][ci] = xbuf;
-+ jmain->xbuffer[1][ci] = xbuf;
- }
- }
-
-@@ -194,13 +194,13 @@
- LOCAL(void)
- make_funny_pointers (j_decompress_ptr cinfo)
- /* Create the funny pointer lists discussed in the comments above.
-- * The actual workspace is already allocated (in main->buffer),
-+ * The actual workspace is already allocated (in jmain->buffer),
- * and the space for the pointer lists is allocated too.
- * This routine just fills in the curiously ordered lists.
- * This will be repeated at the beginning of each pass.
- */
- {
-- my_main_ptr main = (my_main_ptr) cinfo->main;
-+ my_main_ptr jmain = (my_main_ptr) cinfo->main;
- int ci, i, rgroup;
- int M = cinfo->min_DCT_scaled_size;
- jpeg_component_info *compptr;
-@@ -210,10 +210,10 @@
- ci++, compptr++) {
- rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
- cinfo->min_DCT_scaled_size; /* height of a row group of component */
-- xbuf0 = main->xbuffer[0][ci];
-- xbuf1 = main->xbuffer[1][ci];
-+ xbuf0 = jmain->xbuffer[0][ci];
-+ xbuf1 = jmain->xbuffer[1][ci];
- /* First copy the workspace pointers as-is */
-- buf = main->buffer[ci];
-+ buf = jmain->buffer[ci];
- for (i = 0; i < rgroup * (M + 2); i++) {
- xbuf0[i] = xbuf1[i] = buf[i];
- }
-@@ -240,7 +240,7 @@
- * This changes the pointer list state from top-of-image to the normal state.
- */
- {
-- my_main_ptr main = (my_main_ptr) cinfo->main;
-+ my_main_ptr jmain = (my_main_ptr) cinfo->main;
- int ci, i, rgroup;
- int M = cinfo->min_DCT_scaled_size;
- jpeg_component_info *compptr;
-@@ -250,8 +250,8 @@
- ci++, compptr++) {
- rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
- cinfo->min_DCT_scaled_size; /* height of a row group of component */
-- xbuf0 = main->xbuffer[0][ci];
-- xbuf1 = main->xbuffer[1][ci];
-+ xbuf0 = jmain->xbuffer[0][ci];
-+ xbuf1 = jmain->xbuffer[1][ci];
- for (i = 0; i < rgroup; i++) {
- xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
- xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
-@@ -269,7 +269,7 @@
- * Also sets rowgroups_avail to indicate number of nondummy row groups in row.
- */
- {
-- my_main_ptr main = (my_main_ptr) cinfo->main;
-+ my_main_ptr jmain = (my_main_ptr) cinfo->main;
- int ci, i, rgroup, iMCUheight, rows_left;
- jpeg_component_info *compptr;
- JSAMPARRAY xbuf;
-@@ -286,12 +286,12 @@
- * so we need only do it once.
- */
- if (ci == 0) {
-- main->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1);
-+ jmain->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1);
- }
- /* Duplicate the last real sample row rgroup*2 times; this pads out the
- * last partial rowgroup and ensures at least one full rowgroup of context.
- */
-- xbuf = main->xbuffer[main->whichptr][ci];
-+ xbuf = jmain->xbuffer[jmain->whichptr][ci];
- for (i = 0; i < rgroup * 2; i++) {
- xbuf[rows_left + i] = xbuf[rows_left-1];
- }
-@@ -306,27 +306,27 @@
- METHODDEF(void)
- start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
- {
-- my_main_ptr main = (my_main_ptr) cinfo->main;
-+ my_main_ptr jmain = (my_main_ptr) cinfo->main;
-
- switch (pass_mode) {
- case JBUF_PASS_THRU:
- if (cinfo->upsample->need_context_rows) {
-- main->pub.process_data = process_data_context_main;
-+ jmain->pub.process_data = process_data_context_main;
- make_funny_pointers(cinfo); /* Create the xbuffer[] lists */
-- main->whichptr = 0; /* Read first iMCU row into xbuffer[0] */
-- main->context_state = CTX_PREPARE_FOR_IMCU;
-- main->iMCU_row_ctr = 0;
-+ jmain->whichptr = 0; /* Read first iMCU row into xbuffer[0] */
-+ jmain->context_state = CTX_PREPARE_FOR_IMCU;
-+ jmain->iMCU_row_ctr = 0;
- } else {
- /* Simple case with no context needed */
-- main->pub.process_data = process_data_simple_main;
-+ jmain->pub.process_data = process_data_simple_main;
- }
-- main->buffer_full = FALSE; /* Mark buffer empty */
-- main->rowgroup_ctr = 0;
-+ jmain->buffer_full = FALSE; /* Mark buffer empty */
-+ jmain->rowgroup_ctr = 0;
- break;
- #ifdef QUANT_2PASS_SUPPORTED
- case JBUF_CRANK_DEST:
- /* For last pass of 2-pass quantization, just crank the postprocessor */
-- main->pub.process_data = process_data_crank_post;
-+ jmain->pub.process_data = process_data_crank_post;
- break;
- #endif
- default:
-@@ -346,14 +346,14 @@
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail)
- {
-- my_main_ptr main = (my_main_ptr) cinfo->main;
-+ my_main_ptr jmain = (my_main_ptr) cinfo->main;
- JDIMENSION rowgroups_avail;
-
-- /* Read input data if we haven't filled the main buffer yet */
-- if (! main->buffer_full) {
-- if (! (*cinfo->coef->decompress_data) (cinfo, main->buffer))
-+ /* Read input data if we haven't filled the jmain buffer yet */
-+ if (! jmain->buffer_full) {
-+ if (! (*cinfo->coef->decompress_data) (cinfo, jmain->buffer))
- return; /* suspension forced, can do nothing more */
-- main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
-+ jmain->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
- }
-
- /* There are always min_DCT_scaled_size row groups in an iMCU row. */
-@@ -364,14 +364,14 @@
- */
-
- /* Feed the postprocessor */
-- (*cinfo->post->post_process_data) (cinfo, main->buffer,
-- &main->rowgroup_ctr, rowgroups_avail,
-+ (*cinfo->post->post_process_data) (cinfo, jmain->buffer,
-+ &jmain->rowgroup_ctr, rowgroups_avail,
- output_buf, out_row_ctr, out_rows_avail);
-
- /* Has postprocessor consumed all the data yet? If so, mark buffer empty */
-- if (main->rowgroup_ctr >= rowgroups_avail) {
-- main->buffer_full = FALSE;
-- main->rowgroup_ctr = 0;
-+ if (jmain->rowgroup_ctr >= rowgroups_avail) {
-+ jmain->buffer_full = FALSE;
-+ jmain->rowgroup_ctr = 0;
- }
- }
-
-@@ -386,15 +386,15 @@
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail)
- {
-- my_main_ptr main = (my_main_ptr) cinfo->main;
-+ my_main_ptr jmain = (my_main_ptr) cinfo->main;
-
-- /* Read input data if we haven't filled the main buffer yet */
-- if (! main->buffer_full) {
-+ /* Read input data if we haven't filled the jmain buffer yet */
-+ if (! jmain->buffer_full) {
- if (! (*cinfo->coef->decompress_data) (cinfo,
-- main->xbuffer[main->whichptr]))
-+ jmain->xbuffer[jmain->whichptr]))
- return; /* suspension forced, can do nothing more */
-- main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
-- main->iMCU_row_ctr++; /* count rows received */
-+ jmain->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
-+ jmain->iMCU_row_ctr++; /* count rows received */
- }
-
- /* Postprocessor typically will not swallow all the input data it is handed
-@@ -402,47 +402,47 @@
- * to exit and restart. This switch lets us keep track of how far we got.
- * Note that each case falls through to the next on successful completion.
- */
-- switch (main->context_state) {
-+ switch (jmain->context_state) {
- case CTX_POSTPONED_ROW:
- /* Call postprocessor using previously set pointers for postponed row */
-- (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr],
-- &main->rowgroup_ctr, main->rowgroups_avail,
-+ (*cinfo->post->post_process_data) (cinfo, jmain->xbuffer[jmain->whichptr],
-+ &jmain->rowgroup_ctr, jmain->rowgroups_avail,
- output_buf, out_row_ctr, out_rows_avail);
-- if (main->rowgroup_ctr < main->rowgroups_avail)
-+ if (jmain->rowgroup_ctr < jmain->rowgroups_avail)
- return; /* Need to suspend */
-- main->context_state = CTX_PREPARE_FOR_IMCU;
-+ jmain->context_state = CTX_PREPARE_FOR_IMCU;
- if (*out_row_ctr >= out_rows_avail)
- return; /* Postprocessor exactly filled output buf */
- /*FALLTHROUGH*/
- case CTX_PREPARE_FOR_IMCU:
- /* Prepare to process first M-1 row groups of this iMCU row */
-- main->rowgroup_ctr = 0;
-- main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size - 1);
-+ jmain->rowgroup_ctr = 0;
-+ jmain->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size - 1);
- /* Check for bottom of image: if so, tweak pointers to "duplicate"
- * the last sample row, and adjust rowgroups_avail to ignore padding rows.
- */
-- if (main->iMCU_row_ctr == cinfo->total_iMCU_rows)
-+ if (jmain->iMCU_row_ctr == cinfo->total_iMCU_rows)
- set_bottom_pointers(cinfo);
-- main->context_state = CTX_PROCESS_IMCU;
-+ jmain->context_state = CTX_PROCESS_IMCU;
- /*FALLTHROUGH*/
- case CTX_PROCESS_IMCU:
- /* Call postprocessor using previously set pointers */
-- (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr],
-- &main->rowgroup_ctr, main->rowgroups_avail,
-+ (*cinfo->post->post_process_data) (cinfo, jmain->xbuffer[jmain->whichptr],
-+ &jmain->rowgroup_ctr, jmain->rowgroups_avail,
- output_buf, out_row_ctr, out_rows_avail);
-- if (main->rowgroup_ctr < main->rowgroups_avail)
-+ if (jmain->rowgroup_ctr < jmain->rowgroups_avail)
- return; /* Need to suspend */
- /* After the first iMCU, change wraparound pointers to normal state */
-- if (main->iMCU_row_ctr == 1)
-+ if (jmain->iMCU_row_ctr == 1)
- set_wraparound_pointers(cinfo);
- /* Prepare to load new iMCU row using other xbuffer list */
-- main->whichptr ^= 1; /* 0=>1 or 1=>0 */
-- main->buffer_full = FALSE;
-+ jmain->whichptr ^= 1; /* 0=>1 or 1=>0 */
-+ jmain->buffer_full = FALSE;
- /* Still need to process last row group of this iMCU row, */
- /* which is saved at index M+1 of the other xbuffer */
-- main->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_scaled_size + 1);
-- main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size + 2);
-- main->context_state = CTX_POSTPONED_ROW;
-+ jmain->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_scaled_size + 1);
-+ jmain->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size + 2);
-+ jmain->context_state = CTX_POSTPONED_ROW;
- }
- }
-
-@@ -469,21 +469,21 @@
-
-
- /*
-- * Initialize main buffer controller.
-+ * Initialize jmain buffer controller.
- */
-
- GLOBAL(void)
- jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
- {
-- my_main_ptr main;
-+ my_main_ptr jmain;
- int ci, rgroup, ngroups;
- jpeg_component_info *compptr;
-
-- main = (my_main_ptr)
-+ jmain = (my_main_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_main_controller));
-- cinfo->main = (struct jpeg_d_main_controller *) main;
-- main->pub.start_pass = start_pass_main;
-+ cinfo->main = (struct jpeg_d_main_controller *) jmain;
-+ jmain->pub.start_pass = start_pass_main;
-
- if (need_full_buffer) /* shouldn't happen */
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
-@@ -504,7 +504,7 @@
- ci++, compptr++) {
- rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
- cinfo->min_DCT_scaled_size; /* height of a row group of component */
-- main->buffer[ci] = (*cinfo->mem->alloc_sarray)
-+ jmain->buffer[ci] = (*cinfo->mem->alloc_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- compptr->width_in_blocks * compptr->DCT_scaled_size,
- (JDIMENSION) (rgroup * ngroups));
-diff -u -w /home/tma/sources/jpeg-6b/jerror.c ./jerror.c
---- /home/tma/sources/jpeg-6b/jerror.c 1998-02-22 01:03:15.000000000 +0000
-+++ ./jerror.c 2008-08-21 23:58:36.000000000 +0100
-@@ -18,6 +18,8 @@
- * These routines are used by both the compression and decompression code.
- */
-
-+#include "../renderer/tr_local.h"
-+
- /* this is not a core library module, so it doesn't define JPEG_INTERNALS */
- #include "jinclude.h"
- #include "jpeglib.h"
-@@ -69,13 +71,15 @@
- METHODDEF(void)
- error_exit (j_common_ptr cinfo)
- {
-- /* Always display the message */
-- (*cinfo->err->output_message) (cinfo);
-+ char buffer[JMSG_LENGTH_MAX];
-+
-+ /* Create the message */
-+ (*cinfo->err->format_message) (cinfo, buffer);
-
- /* Let the memory manager delete any temp files before we die */
- jpeg_destroy(cinfo);
-
-- exit(EXIT_FAILURE);
-+ ri.Error( ERR_FATAL, "%s\n", buffer );
- }
-
-
-@@ -108,7 +112,7 @@
- MB_OK | MB_ICONERROR);
- #else
- /* Send it to stderr, adding a newline */
-- fprintf(stderr, "%s\n", buffer);
-+ ri.Printf(PRINT_ALL, "%s\n", buffer);
- #endif
- }
-
-diff -u -w /home/tma/sources/jpeg-6b/jinclude.h ./jinclude.h
---- /home/tma/sources/jpeg-6b/jinclude.h 1994-04-01 21:29:31.000000000 +0100
-+++ ./jinclude.h 2008-08-21 23:58:36.000000000 +0100
-@@ -15,9 +15,34 @@
- */
-
-
-+#ifdef _MSC_VER
-+
-+#pragma warning(disable : 4018) // signed/unsigned mismatch
-+#pragma warning(disable : 4032)
-+#pragma warning(disable : 4051)
-+#pragma warning(disable : 4057) // slightly different base types
-+#pragma warning(disable : 4100) // unreferenced formal parameter
-+#pragma warning(disable : 4115)
-+#pragma warning(disable : 4125) // decimal digit terminates octal escape sequence
-+#pragma warning(disable : 4127) // conditional expression is constant
-+#pragma warning(disable : 4136)
-+#pragma warning(disable : 4152) // nonstandard extension, function/data pointer conversion in expression
-+#pragma warning(disable : 4201)
-+#pragma warning(disable : 4214)
-+#pragma warning(disable : 4244)
-+#pragma warning(disable : 4305) // truncation from const double to float
-+#pragma warning(disable : 4310) // cast truncates constant value
-+#pragma warning(disable: 4505) // unreferenced local function has been removed
-+#pragma warning(disable : 4514)
-+#pragma warning(disable : 4702) // unreachable code
-+#pragma warning(disable : 4711) // selected for automatic inline expansion
-+#pragma warning(disable : 4220) // varargs matches remaining parameters
-+#pragma warning(disable : 4761) // integral size mismatch
-+#endif
-+
- /* Include auto-config file to find out which system include files we need. */
-
--#include "jconfig.h" /* auto configuration options */
-+#include "../jpeg-6b/jconfig.h" /* auto configuration options */
- #define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */
-
- /*
-diff -u -w /home/tma/sources/jpeg-6b/jmemnobs.c ./jmemnobs.c
---- /home/tma/sources/jpeg-6b/jmemnobs.c 1996-01-06 23:31:18.000000000 +0000
-+++ ./jmemnobs.c 2008-08-21 23:58:36.000000000 +0100
-@@ -8,39 +8,35 @@
- * This file provides a really simple implementation of the system-
- * dependent portion of the JPEG memory manager. This implementation
- * assumes that no backing-store files are needed: all required space
-- * can be obtained from malloc().
-+ * can be obtained from ri.Malloc().
- * This is very portable in the sense that it'll compile on almost anything,
- * but you'd better have lots of main memory (or virtual memory) if you want
- * to process big images.
- * Note that the max_memory_to_use option is ignored by this implementation.
- */
-
-+#include "../renderer/tr_local.h"
-+
- #define JPEG_INTERNALS
- #include "jinclude.h"
- #include "jpeglib.h"
- #include "jmemsys.h" /* import the system-dependent declarations */
-
--#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
--extern void * malloc JPP((size_t size));
--extern void free JPP((void *ptr));
--#endif
--
--
- /*
- * Memory allocation and freeing are controlled by the regular library
-- * routines malloc() and free().
-+ * routines ri.Malloc() and ri.Free().
- */
-
- GLOBAL(void *)
- jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
- {
-- return (void *) malloc(sizeofobject);
-+ return (void *) ri.Malloc(sizeofobject);
- }
-
- GLOBAL(void)
- jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
- {
-- free(object);
-+ ri.Free(object);
- }
-
-
-@@ -54,13 +50,13 @@
- GLOBAL(void FAR *)
- jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
- {
-- return (void FAR *) malloc(sizeofobject);
-+ return (void FAR *) ri.Malloc(sizeofobject);
- }
-
- GLOBAL(void)
- jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
- {
-- free(object);
-+ ri.Free(object);
- }
-
-
-diff -u -w /home/tma/sources/jpeg-6b/jmorecfg.h ./jmorecfg.h
---- /home/tma/sources/jpeg-6b/jmorecfg.h 1997-08-10 00:58:56.000000000 +0100
-+++ ./jmorecfg.h 2008-08-21 23:58:36.000000000 +0100
-@@ -157,7 +157,8 @@
-
- /* INT32 must hold at least signed 32-bit values. */
-
--#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */
-+/* MinGW basetsd.h defines INT32 - don't redefine it */
-+#if !(defined __MINGW32__ && defined _BASETSD_H)
- typedef long INT32;
- #endif
-
-@@ -210,8 +211,10 @@
- */
-
- #ifdef NEED_FAR_POINTERS
-+#undef FAR
- #define FAR far
- #else
-+#undef FAR
- #define FAR
- #endif
-
-@@ -223,9 +226,7 @@
- * Defining HAVE_BOOLEAN before including jpeglib.h should make it work.
- */
-
--#ifndef HAVE_BOOLEAN
--typedef int boolean;
--#endif
-+typedef unsigned char boolean;
- #ifndef FALSE /* in case these macros already exist */
- #define FALSE 0 /* values of boolean */
- #endif
-@@ -260,8 +261,8 @@
-
- /* Capability options common to encoder and decoder: */
-
--#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */
--#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */
-+#undef DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */
-+#undef DCT_IFAST_SUPPORTED /* faster, less accurate integer method */
- #define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */
-
- /* Encoder capability options: */
-@@ -283,15 +284,15 @@
- /* Decoder capability options: */
-
- #undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */
--#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
--#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
--#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */
--#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */
--#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */
-+#undef D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
-+#undef D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
-+#undef SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */
-+#undef BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */
-+#undef IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */
- #undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */
--#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */
--#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */
--#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */
-+#undef UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */
-+#undef QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */
-+#undef QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */
-
- /* more capability options later, no doubt */
-
-@@ -314,7 +315,7 @@
- #define RGB_RED 0 /* Offset of Red in an RGB scanline element */
- #define RGB_GREEN 1 /* Offset of Green */
- #define RGB_BLUE 2 /* Offset of Blue */
--#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */
-+#define RGB_PIXELSIZE 4 /* JSAMPLEs per RGB scanline element */
-
-
- /* Definitions for speed-related optimizations. */
-diff -u -w /home/tma/sources/jpeg-6b/jpeglib.h ./jpeglib.h
---- /home/tma/sources/jpeg-6b/jpeglib.h 1998-02-21 19:48:14.000000000 +0000
-+++ ./jpeglib.h 2008-08-22 00:01:58.000000000 +0100
-@@ -21,9 +21,9 @@
- */
-
- #ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */
--#include "jconfig.h" /* widely used configuration options */
-+#include "../jpeg-6b/jconfig.h" /* widely used configuration options */
- #endif
--#include "jmorecfg.h" /* seldom changed options */
-+#include "../jpeg-6b/jmorecfg.h" /* seldom changed options */
-
-
- /* Version ID for the JPEG library.
-@@ -835,7 +835,7 @@
- #define jpeg_destroy_compress jDestCompress
- #define jpeg_destroy_decompress jDestDecompress
- #define jpeg_stdio_dest jStdDest
--#define jpeg_stdio_src jStdSrc
-+#define jpeg_mem_src jMemSrc
- #define jpeg_set_defaults jSetDefaults
- #define jpeg_set_colorspace jSetColorspace
- #define jpeg_default_colorspace jDefColorspace
-@@ -908,7 +908,7 @@
- /* Standard data source and destination managers: stdio streams. */
- /* Caller is responsible for opening the file before and closing after. */
- EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile));
--EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile));
-+EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo, unsigned char *inbuf, size_t size));
-
- /* Default parameter setup for compression */
- EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo));
-@@ -1089,8 +1089,8 @@
- */
-
- #ifdef JPEG_INTERNALS
--#include "jpegint.h" /* fetch private declarations */
--#include "jerror.h" /* fetch error codes too */
-+#include "../jpeg-6b/jpegint.h" /* fetch private declarations */
-+#include "../jpeg-6b/jerror.h" /* fetch error codes too */
- #endif
-
- #endif /* JPEGLIB_H */
diff --git a/engine/code/jpeg-6b/jcapimin.c b/engine/code/jpeg-6b/jcapimin.c
deleted file mode 100644
index 54fb8c5..0000000
--- a/engine/code/jpeg-6b/jcapimin.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * jcapimin.c
- *
- * Copyright (C) 1994-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains application interface code for the compression half
- * of the JPEG library. These are the "minimum" API routines that may be
- * needed in either the normal full-compression case or the transcoding-only
- * case.
- *
- * Most of the routines intended to be called directly by an application
- * are in this file or in jcapistd.c. But also see jcparam.c for
- * parameter-setup helper routines, jcomapi.c for routines shared by
- * compression and decompression, and jctrans.c for the transcoding case.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/*
- * Initialization of a JPEG compression object.
- * The error manager must already be set up (in case memory manager fails).
- */
-
-GLOBAL(void)
-jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize)
-{
- int i;
-
- /* Guard against version mismatches between library and caller. */
- cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */
- if (version != JPEG_LIB_VERSION)
- ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
- if (structsize != SIZEOF(struct jpeg_compress_struct))
- ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE,
- (int) SIZEOF(struct jpeg_compress_struct), (int) structsize);
-
- /* For debugging purposes, we zero the whole master structure.
- * But the application has already set the err pointer, and may have set
- * client_data, so we have to save and restore those fields.
- * Note: if application hasn't set client_data, tools like Purify may
- * complain here.
- */
- {
- struct jpeg_error_mgr * err = cinfo->err;
- void * client_data = cinfo->client_data; /* ignore Purify complaint here */
- MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct));
- cinfo->err = err;
- cinfo->client_data = client_data;
- }
- cinfo->is_decompressor = FALSE;
-
- /* Initialize a memory manager instance for this object */
- jinit_memory_mgr((j_common_ptr) cinfo);
-
- /* Zero out pointers to permanent structures. */
- cinfo->progress = NULL;
- cinfo->dest = NULL;
-
- cinfo->comp_info = NULL;
-
- for (i = 0; i < NUM_QUANT_TBLS; i++)
- cinfo->quant_tbl_ptrs[i] = NULL;
-
- for (i = 0; i < NUM_HUFF_TBLS; i++) {
- cinfo->dc_huff_tbl_ptrs[i] = NULL;
- cinfo->ac_huff_tbl_ptrs[i] = NULL;
- }
-
- cinfo->script_space = NULL;
-
- cinfo->input_gamma = 1.0; /* in case application forgets */
-
- /* OK, I'm ready */
- cinfo->global_state = CSTATE_START;
-}
-
-
-/*
- * Destruction of a JPEG compression object
- */
-
-GLOBAL(void)
-jpeg_destroy_compress (j_compress_ptr cinfo)
-{
- jpeg_destroy((j_common_ptr) cinfo); /* use common routine */
-}
-
-
-/*
- * Abort processing of a JPEG compression operation,
- * but don't destroy the object itself.
- */
-
-GLOBAL(void)
-jpeg_abort_compress (j_compress_ptr cinfo)
-{
- jpeg_abort((j_common_ptr) cinfo); /* use common routine */
-}
-
-
-/*
- * Forcibly suppress or un-suppress all quantization and Huffman tables.
- * Marks all currently defined tables as already written (if suppress)
- * or not written (if !suppress). This will control whether they get emitted
- * by a subsequent jpeg_start_compress call.
- *
- * This routine is exported for use by applications that want to produce
- * abbreviated JPEG datastreams. It logically belongs in jcparam.c, but
- * since it is called by jpeg_start_compress, we put it here --- otherwise
- * jcparam.o would be linked whether the application used it or not.
- */
-
-GLOBAL(void)
-jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress)
-{
- int i;
- JQUANT_TBL * qtbl;
- JHUFF_TBL * htbl;
-
- for (i = 0; i < NUM_QUANT_TBLS; i++) {
- if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL)
- qtbl->sent_table = suppress;
- }
-
- for (i = 0; i < NUM_HUFF_TBLS; i++) {
- if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL)
- htbl->sent_table = suppress;
- if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL)
- htbl->sent_table = suppress;
- }
-}
-
-
-/*
- * Finish JPEG compression.
- *
- * If a multipass operating mode was selected, this may do a great deal of
- * work including most of the actual output.
- */
-
-GLOBAL(void)
-jpeg_finish_compress (j_compress_ptr cinfo)
-{
- JDIMENSION iMCU_row;
-
- if (cinfo->global_state == CSTATE_SCANNING ||
- cinfo->global_state == CSTATE_RAW_OK) {
- /* Terminate first pass */
- if (cinfo->next_scanline < cinfo->image_height)
- ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
- (*cinfo->master->finish_pass) (cinfo);
- } else if (cinfo->global_state != CSTATE_WRCOEFS)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- /* Perform any remaining passes */
- while (! cinfo->master->is_last_pass) {
- (*cinfo->master->prepare_for_pass) (cinfo);
- for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) {
- if (cinfo->progress != NULL) {
- cinfo->progress->pass_counter = (long) iMCU_row;
- cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows;
- (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
- }
- /* We bypass the main controller and invoke coef controller directly;
- * all work is being done from the coefficient buffer.
- */
- if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL))
- ERREXIT(cinfo, JERR_CANT_SUSPEND);
- }
- (*cinfo->master->finish_pass) (cinfo);
- }
- /* Write EOI, do final cleanup */
- (*cinfo->marker->write_file_trailer) (cinfo);
- (*cinfo->dest->term_destination) (cinfo);
- /* We can use jpeg_abort to release memory and reset global_state */
- jpeg_abort((j_common_ptr) cinfo);
-}
-
-
-/*
- * Write a special marker.
- * This is only recommended for writing COM or APPn markers.
- * Must be called after jpeg_start_compress() and before
- * first call to jpeg_write_scanlines() or jpeg_write_raw_data().
- */
-
-GLOBAL(void)
-jpeg_write_marker (j_compress_ptr cinfo, int marker,
- const JOCTET *dataptr, unsigned int datalen)
-{
- JMETHOD(void, write_marker_byte, (j_compress_ptr info, int val));
-
- if (cinfo->next_scanline != 0 ||
- (cinfo->global_state != CSTATE_SCANNING &&
- cinfo->global_state != CSTATE_RAW_OK &&
- cinfo->global_state != CSTATE_WRCOEFS))
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
- (*cinfo->marker->write_marker_header) (cinfo, marker, datalen);
- write_marker_byte = cinfo->marker->write_marker_byte; /* copy for speed */
- while (datalen--) {
- (*write_marker_byte) (cinfo, *dataptr);
- dataptr++;
- }
-}
-
-/* Same, but piecemeal. */
-
-GLOBAL(void)
-jpeg_write_m_header (j_compress_ptr cinfo, int marker, unsigned int datalen)
-{
- if (cinfo->next_scanline != 0 ||
- (cinfo->global_state != CSTATE_SCANNING &&
- cinfo->global_state != CSTATE_RAW_OK &&
- cinfo->global_state != CSTATE_WRCOEFS))
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
- (*cinfo->marker->write_marker_header) (cinfo, marker, datalen);
-}
-
-GLOBAL(void)
-jpeg_write_m_byte (j_compress_ptr cinfo, int val)
-{
- (*cinfo->marker->write_marker_byte) (cinfo, val);
-}
-
-
-/*
- * Alternate compression function: just write an abbreviated table file.
- * Before calling this, all parameters and a data destination must be set up.
- *
- * To produce a pair of files containing abbreviated tables and abbreviated
- * image data, one would proceed as follows:
- *
- * initialize JPEG object
- * set JPEG parameters
- * set destination to table file
- * jpeg_write_tables(cinfo);
- * set destination to image file
- * jpeg_start_compress(cinfo, FALSE);
- * write data...
- * jpeg_finish_compress(cinfo);
- *
- * jpeg_write_tables has the side effect of marking all tables written
- * (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress
- * will not re-emit the tables unless it is passed write_all_tables=TRUE.
- */
-
-GLOBAL(void)
-jpeg_write_tables (j_compress_ptr cinfo)
-{
- if (cinfo->global_state != CSTATE_START)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
- /* (Re)initialize error mgr and destination modules */
- (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
- (*cinfo->dest->init_destination) (cinfo);
- /* Initialize the marker writer ... bit of a crock to do it here. */
- jinit_marker_writer(cinfo);
- /* Write them tables! */
- (*cinfo->marker->write_tables_only) (cinfo);
- /* And clean up. */
- (*cinfo->dest->term_destination) (cinfo);
- /*
- * In library releases up through v6a, we called jpeg_abort() here to free
- * any working memory allocated by the destination manager and marker
- * writer. Some applications had a problem with that: they allocated space
- * of their own from the library memory manager, and didn't want it to go
- * away during write_tables. So now we do nothing. This will cause a
- * memory leak if an app calls write_tables repeatedly without doing a full
- * compression cycle or otherwise resetting the JPEG object. However, that
- * seems less bad than unexpectedly freeing memory in the normal case.
- * An app that prefers the old behavior can call jpeg_abort for itself after
- * each call to jpeg_write_tables().
- */
-}
diff --git a/engine/code/jpeg-6b/jcapistd.c b/engine/code/jpeg-6b/jcapistd.c
deleted file mode 100644
index c0320b1..0000000
--- a/engine/code/jpeg-6b/jcapistd.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * jcapistd.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains application interface code for the compression half
- * of the JPEG library. These are the "standard" API routines that are
- * used in the normal full-compression case. They are not used by a
- * transcoding-only application. Note that if an application links in
- * jpeg_start_compress, it will end up linking in the entire compressor.
- * We thus must separate this file from jcapimin.c to avoid linking the
- * whole compression library into a transcoder.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/*
- * Compression initialization.
- * Before calling this, all parameters and a data destination must be set up.
- *
- * We require a write_all_tables parameter as a failsafe check when writing
- * multiple datastreams from the same compression object. Since prior runs
- * will have left all the tables marked sent_table=TRUE, a subsequent run
- * would emit an abbreviated stream (no tables) by default. This may be what
- * is wanted, but for safety's sake it should not be the default behavior:
- * programmers should have to make a deliberate choice to emit abbreviated
- * images. Therefore the documentation and examples should encourage people
- * to pass write_all_tables=TRUE; then it will take active thought to do the
- * wrong thing.
- */
-
-GLOBAL(void)
-jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables)
-{
- if (cinfo->global_state != CSTATE_START)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
- if (write_all_tables)
- jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */
-
- /* (Re)initialize error mgr and destination modules */
- (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
- (*cinfo->dest->init_destination) (cinfo);
- /* Perform master selection of active modules */
- jinit_compress_master(cinfo);
- /* Set up for the first pass */
- (*cinfo->master->prepare_for_pass) (cinfo);
- /* Ready for application to drive first pass through jpeg_write_scanlines
- * or jpeg_write_raw_data.
- */
- cinfo->next_scanline = 0;
- cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING);
-}
-
-
-/*
- * Write some scanlines of data to the JPEG compressor.
- *
- * The return value will be the number of lines actually written.
- * This should be less than the supplied num_lines only in case that
- * the data destination module has requested suspension of the compressor,
- * or if more than image_height scanlines are passed in.
- *
- * Note: we warn about excess calls to jpeg_write_scanlines() since
- * this likely signals an application programmer error. However,
- * excess scanlines passed in the last valid call are *silently* ignored,
- * so that the application need not adjust num_lines for end-of-image
- * when using a multiple-scanline buffer.
- */
-
-GLOBAL(JDIMENSION)
-jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines,
- JDIMENSION num_lines)
-{
- JDIMENSION row_ctr, rows_left;
-
- if (cinfo->global_state != CSTATE_SCANNING)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- if (cinfo->next_scanline >= cinfo->image_height)
- WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
-
- /* Call progress monitor hook if present */
- if (cinfo->progress != NULL) {
- cinfo->progress->pass_counter = (long) cinfo->next_scanline;
- cinfo->progress->pass_limit = (long) cinfo->image_height;
- (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
- }
-
- /* Give master control module another chance if this is first call to
- * jpeg_write_scanlines. This lets output of the frame/scan headers be
- * delayed so that application can write COM, etc, markers between
- * jpeg_start_compress and jpeg_write_scanlines.
- */
- if (cinfo->master->call_pass_startup)
- (*cinfo->master->pass_startup) (cinfo);
-
- /* Ignore any extra scanlines at bottom of image. */
- rows_left = cinfo->image_height - cinfo->next_scanline;
- if (num_lines > rows_left)
- num_lines = rows_left;
-
- row_ctr = 0;
- (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);
- cinfo->next_scanline += row_ctr;
- return row_ctr;
-}
-
-
-/*
- * Alternate entry point to write raw data.
- * Processes exactly one iMCU row per call, unless suspended.
- */
-
-GLOBAL(JDIMENSION)
-jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data,
- JDIMENSION num_lines)
-{
- JDIMENSION lines_per_iMCU_row;
-
- if (cinfo->global_state != CSTATE_RAW_OK)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- if (cinfo->next_scanline >= cinfo->image_height) {
- WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
- return 0;
- }
-
- /* Call progress monitor hook if present */
- if (cinfo->progress != NULL) {
- cinfo->progress->pass_counter = (long) cinfo->next_scanline;
- cinfo->progress->pass_limit = (long) cinfo->image_height;
- (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
- }
-
- /* Give master control module another chance if this is first call to
- * jpeg_write_raw_data. This lets output of the frame/scan headers be
- * delayed so that application can write COM, etc, markers between
- * jpeg_start_compress and jpeg_write_raw_data.
- */
- if (cinfo->master->call_pass_startup)
- (*cinfo->master->pass_startup) (cinfo);
-
- /* Verify that at least one iMCU row has been passed. */
- lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE;
- if (num_lines < lines_per_iMCU_row)
- ERREXIT(cinfo, JERR_BUFFER_SIZE);
-
- /* Directly compress the row. */
- if (! (*cinfo->coef->compress_data) (cinfo, data)) {
- /* If compressor did not consume the whole row, suspend processing. */
- return 0;
- }
-
- /* OK, we processed one iMCU row. */
- cinfo->next_scanline += lines_per_iMCU_row;
- return lines_per_iMCU_row;
-}
diff --git a/engine/code/jpeg-6b/jccoefct.c b/engine/code/jpeg-6b/jccoefct.c
deleted file mode 100644
index 1963ddb..0000000
--- a/engine/code/jpeg-6b/jccoefct.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * jccoefct.c
- *
- * Copyright (C) 1994-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains the coefficient buffer controller for compression.
- * This controller is the top level of the JPEG compressor proper.
- * The coefficient buffer lies between forward-DCT and entropy encoding steps.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* We use a full-image coefficient buffer when doing Huffman optimization,
- * and also for writing multiple-scan JPEG files. In all cases, the DCT
- * step is run during the first pass, and subsequent passes need only read
- * the buffered coefficients.
- */
-#ifdef ENTROPY_OPT_SUPPORTED
-#define FULL_COEF_BUFFER_SUPPORTED
-#else
-#ifdef C_MULTISCAN_FILES_SUPPORTED
-#define FULL_COEF_BUFFER_SUPPORTED
-#endif
-#endif
-
-
-/* Private buffer controller object */
-
-typedef struct {
- struct jpeg_c_coef_controller pub; /* public fields */
-
- JDIMENSION iMCU_row_num; /* iMCU row # within image */
- JDIMENSION mcu_ctr; /* counts MCUs processed in current row */
- int MCU_vert_offset; /* counts MCU rows within iMCU row */
- int MCU_rows_per_iMCU_row; /* number of such rows needed */
-
- /* For single-pass compression, it's sufficient to buffer just one MCU
- * (although this may prove a bit slow in practice). We allocate a
- * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each
- * MCU constructed and sent. (On 80x86, the workspace is FAR even though
- * it's not really very big; this is to keep the module interfaces unchanged
- * when a large coefficient buffer is necessary.)
- * In multi-pass modes, this array points to the current MCU's blocks
- * within the virtual arrays.
- */
- JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];
-
- /* In multi-pass modes, we need a virtual block array for each component. */
- jvirt_barray_ptr whole_image[MAX_COMPONENTS];
-} my_coef_controller;
-
-typedef my_coef_controller * my_coef_ptr;
-
-
-/* Forward declarations */
-METHODDEF(boolean) compress_data
- JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
-#ifdef FULL_COEF_BUFFER_SUPPORTED
-METHODDEF(boolean) compress_first_pass
- JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
-METHODDEF(boolean) compress_output
- JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
-#endif
-
-
-LOCAL(void)
-start_iMCU_row (j_compress_ptr cinfo)
-/* Reset within-iMCU-row counters for a new row */
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
-
- /* In an interleaved scan, an MCU row is the same as an iMCU row.
- * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
- * But at the bottom of the image, process only what's left.
- */
- if (cinfo->comps_in_scan > 1) {
- coef->MCU_rows_per_iMCU_row = 1;
- } else {
- if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1))
- coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
- else
- coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
- }
-
- coef->mcu_ctr = 0;
- coef->MCU_vert_offset = 0;
-}
-
-
-/*
- * Initialize for a processing pass.
- */
-
-METHODDEF(void)
-start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
-
- coef->iMCU_row_num = 0;
- start_iMCU_row(cinfo);
-
- switch (pass_mode) {
- case JBUF_PASS_THRU:
- if (coef->whole_image[0] != NULL)
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- coef->pub.compress_data = compress_data;
- break;
-#ifdef FULL_COEF_BUFFER_SUPPORTED
- case JBUF_SAVE_AND_PASS:
- if (coef->whole_image[0] == NULL)
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- coef->pub.compress_data = compress_first_pass;
- break;
- case JBUF_CRANK_DEST:
- if (coef->whole_image[0] == NULL)
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- coef->pub.compress_data = compress_output;
- break;
-#endif
- default:
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- break;
- }
-}
-
-
-/*
- * Process some data in the single-pass case.
- * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
- * per call, ie, v_samp_factor block rows for each component in the image.
- * Returns TRUE if the iMCU row is completed, FALSE if suspended.
- *
- * NB: input_buf contains a plane for each component in image,
- * which we index according to the component's SOF position.
- */
-
-METHODDEF(boolean)
-compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
- JDIMENSION MCU_col_num; /* index of current MCU within row */
- JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
- JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
- int blkn, bi, ci, yindex, yoffset, blockcnt;
- JDIMENSION ypos, xpos;
- jpeg_component_info *compptr;
-
- /* Loop to write as much as one whole iMCU row */
- for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
- yoffset++) {
- for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col;
- MCU_col_num++) {
- /* Determine where data comes from in input_buf and do the DCT thing.
- * Each call on forward_DCT processes a horizontal row of DCT blocks
- * as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks
- * sequentially. Dummy blocks at the right or bottom edge are filled in
- * specially. The data in them does not matter for image reconstruction,
- * so we fill them with values that will encode to the smallest amount of
- * data, viz: all zeroes in the AC entries, DC entries equal to previous
- * block's DC value. (Thanks to Thomas Kinsman for this idea.)
- */
- blkn = 0;
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
- : compptr->last_col_width;
- xpos = MCU_col_num * compptr->MCU_sample_width;
- ypos = yoffset * DCTSIZE; /* ypos == (yoffset+yindex) * DCTSIZE */
- for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
- if (coef->iMCU_row_num < last_iMCU_row ||
- yoffset+yindex < compptr->last_row_height) {
- (*cinfo->fdct->forward_DCT) (cinfo, compptr,
- input_buf[compptr->component_index],
- coef->MCU_buffer[blkn],
- ypos, xpos, (JDIMENSION) blockcnt);
- if (blockcnt < compptr->MCU_width) {
- /* Create some dummy blocks at the right edge of the image. */
- jzero_far((void FAR *) coef->MCU_buffer[blkn + blockcnt],
- (compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK));
- for (bi = blockcnt; bi < compptr->MCU_width; bi++) {
- coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0];
- }
- }
- } else {
- /* Create a row of dummy blocks at the bottom of the image. */
- jzero_far((void FAR *) coef->MCU_buffer[blkn],
- compptr->MCU_width * SIZEOF(JBLOCK));
- for (bi = 0; bi < compptr->MCU_width; bi++) {
- coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0];
- }
- }
- blkn += compptr->MCU_width;
- ypos += DCTSIZE;
- }
- }
- /* Try to write the MCU. In event of a suspension failure, we will
- * re-DCT the MCU on restart (a bit inefficient, could be fixed...)
- */
- if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
- /* Suspension forced; update state counters and exit */
- coef->MCU_vert_offset = yoffset;
- coef->mcu_ctr = MCU_col_num;
- return FALSE;
- }
- }
- /* Completed an MCU row, but perhaps not an iMCU row */
- coef->mcu_ctr = 0;
- }
- /* Completed the iMCU row, advance counters for next one */
- coef->iMCU_row_num++;
- start_iMCU_row(cinfo);
- return TRUE;
-}
-
-
-#ifdef FULL_COEF_BUFFER_SUPPORTED
-
-/*
- * Process some data in the first pass of a multi-pass case.
- * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
- * per call, ie, v_samp_factor block rows for each component in the image.
- * This amount of data is read from the source buffer, DCT'd and quantized,
- * and saved into the virtual arrays. We also generate suitable dummy blocks
- * as needed at the right and lower edges. (The dummy blocks are constructed
- * in the virtual arrays, which have been padded appropriately.) This makes
- * it possible for subsequent passes not to worry about real vs. dummy blocks.
- *
- * We must also emit the data to the entropy encoder. This is conveniently
- * done by calling compress_output() after we've loaded the current strip
- * of the virtual arrays.
- *
- * NB: input_buf contains a plane for each component in image. All
- * components are DCT'd and loaded into the virtual arrays in this pass.
- * However, it may be that only a subset of the components are emitted to
- * the entropy encoder during this first pass; be careful about looking
- * at the scan-dependent variables (MCU dimensions, etc).
- */
-
-METHODDEF(boolean)
-compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
- JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
- JDIMENSION blocks_across, MCUs_across, MCUindex;
- int bi, ci, h_samp_factor, block_row, block_rows, ndummy;
- JCOEF lastDC;
- jpeg_component_info *compptr;
- JBLOCKARRAY buffer;
- JBLOCKROW thisblockrow, lastblockrow;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* Align the virtual buffer for this component. */
- buffer = (*cinfo->mem->access_virt_barray)
- ((j_common_ptr) cinfo, coef->whole_image[ci],
- coef->iMCU_row_num * compptr->v_samp_factor,
- (JDIMENSION) compptr->v_samp_factor, TRUE);
- /* Count non-dummy DCT block rows in this iMCU row. */
- if (coef->iMCU_row_num < last_iMCU_row)
- block_rows = compptr->v_samp_factor;
- else {
- /* NB: can't use last_row_height here, since may not be set! */
- block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
- if (block_rows == 0) block_rows = compptr->v_samp_factor;
- }
- blocks_across = compptr->width_in_blocks;
- h_samp_factor = compptr->h_samp_factor;
- /* Count number of dummy blocks to be added at the right margin. */
- ndummy = (int) (blocks_across % h_samp_factor);
- if (ndummy > 0)
- ndummy = h_samp_factor - ndummy;
- /* Perform DCT for all non-dummy blocks in this iMCU row. Each call
- * on forward_DCT processes a complete horizontal row of DCT blocks.
- */
- for (block_row = 0; block_row < block_rows; block_row++) {
- thisblockrow = buffer[block_row];
- (*cinfo->fdct->forward_DCT) (cinfo, compptr,
- input_buf[ci], thisblockrow,
- (JDIMENSION) (block_row * DCTSIZE),
- (JDIMENSION) 0, blocks_across);
- if (ndummy > 0) {
- /* Create dummy blocks at the right edge of the image. */
- thisblockrow += blocks_across; /* => first dummy block */
- jzero_far((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK));
- lastDC = thisblockrow[-1][0];
- for (bi = 0; bi < ndummy; bi++) {
- thisblockrow[bi][0] = lastDC;
- }
- }
- }
- /* If at end of image, create dummy block rows as needed.
- * The tricky part here is that within each MCU, we want the DC values
- * of the dummy blocks to match the last real block's DC value.
- * This squeezes a few more bytes out of the resulting file...
- */
- if (coef->iMCU_row_num == last_iMCU_row) {
- blocks_across += ndummy; /* include lower right corner */
- MCUs_across = blocks_across / h_samp_factor;
- for (block_row = block_rows; block_row < compptr->v_samp_factor;
- block_row++) {
- thisblockrow = buffer[block_row];
- lastblockrow = buffer[block_row-1];
- jzero_far((void FAR *) thisblockrow,
- (size_t) (blocks_across * SIZEOF(JBLOCK)));
- for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) {
- lastDC = lastblockrow[h_samp_factor-1][0];
- for (bi = 0; bi < h_samp_factor; bi++) {
- thisblockrow[bi][0] = lastDC;
- }
- thisblockrow += h_samp_factor; /* advance to next MCU in row */
- lastblockrow += h_samp_factor;
- }
- }
- }
- }
- /* NB: compress_output will increment iMCU_row_num if successful.
- * A suspension return will result in redoing all the work above next time.
- */
-
- /* Emit data to the entropy encoder, sharing code with subsequent passes */
- return compress_output(cinfo, input_buf);
-}
-
-
-/*
- * Process some data in subsequent passes of a multi-pass case.
- * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
- * per call, ie, v_samp_factor block rows for each component in the scan.
- * The data is obtained from the virtual arrays and fed to the entropy coder.
- * Returns TRUE if the iMCU row is completed, FALSE if suspended.
- *
- * NB: input_buf is ignored; it is likely to be a NULL pointer.
- */
-
-METHODDEF(boolean)
-compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
- JDIMENSION MCU_col_num; /* index of current MCU within row */
- int blkn, ci, xindex, yindex, yoffset;
- JDIMENSION start_col;
- JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
- JBLOCKROW buffer_ptr;
- jpeg_component_info *compptr;
-
- /* Align the virtual buffers for the components used in this scan.
- * NB: during first pass, this is safe only because the buffers will
- * already be aligned properly, so jmemmgr.c won't need to do any I/O.
- */
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- buffer[ci] = (*cinfo->mem->access_virt_barray)
- ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
- coef->iMCU_row_num * compptr->v_samp_factor,
- (JDIMENSION) compptr->v_samp_factor, FALSE);
- }
-
- /* Loop to process one whole iMCU row */
- for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
- yoffset++) {
- for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row;
- MCU_col_num++) {
- /* Construct list of pointers to DCT blocks belonging to this MCU */
- blkn = 0; /* index of current DCT block within MCU */
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- start_col = MCU_col_num * compptr->MCU_width;
- for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
- buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
- for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
- coef->MCU_buffer[blkn++] = buffer_ptr++;
- }
- }
- }
- /* Try to write the MCU. */
- if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
- /* Suspension forced; update state counters and exit */
- coef->MCU_vert_offset = yoffset;
- coef->mcu_ctr = MCU_col_num;
- return FALSE;
- }
- }
- /* Completed an MCU row, but perhaps not an iMCU row */
- coef->mcu_ctr = 0;
- }
- /* Completed the iMCU row, advance counters for next one */
- coef->iMCU_row_num++;
- start_iMCU_row(cinfo);
- return TRUE;
-}
-
-#endif /* FULL_COEF_BUFFER_SUPPORTED */
-
-
-/*
- * Initialize coefficient buffer controller.
- */
-
-GLOBAL(void)
-jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)
-{
- my_coef_ptr coef;
-
- coef = (my_coef_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_coef_controller));
- cinfo->coef = (struct jpeg_c_coef_controller *) coef;
- coef->pub.start_pass = start_pass_coef;
-
- /* Create the coefficient buffer. */
- if (need_full_buffer) {
-#ifdef FULL_COEF_BUFFER_SUPPORTED
- /* Allocate a full-image virtual array for each component, */
- /* padded to a multiple of samp_factor DCT blocks in each direction. */
- int ci;
- jpeg_component_info *compptr;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
- (JDIMENSION) jround_up((long) compptr->width_in_blocks,
- (long) compptr->h_samp_factor),
- (JDIMENSION) jround_up((long) compptr->height_in_blocks,
- (long) compptr->v_samp_factor),
- (JDIMENSION) compptr->v_samp_factor);
- }
-#else
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
-#endif
- } else {
- /* We only need a single-MCU buffer. */
- JBLOCKROW buffer;
- int i;
-
- buffer = (JBLOCKROW)
- (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
- for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
- coef->MCU_buffer[i] = buffer + i;
- }
- coef->whole_image[0] = NULL; /* flag for no virtual arrays */
- }
-}
diff --git a/engine/code/jpeg-6b/jccolor.c b/engine/code/jpeg-6b/jccolor.c
deleted file mode 100644
index 0a8a4b5..0000000
--- a/engine/code/jpeg-6b/jccolor.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * jccolor.c
- *
- * Copyright (C) 1991-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains input colorspace conversion routines.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* Private subobject */
-
-typedef struct {
- struct jpeg_color_converter pub; /* public fields */
-
- /* Private state for RGB->YCC conversion */
- INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */
-} my_color_converter;
-
-typedef my_color_converter * my_cconvert_ptr;
-
-
-/**************** RGB -> YCbCr conversion: most common case **************/
-
-/*
- * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
- * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
- * The conversion equations to be implemented are therefore
- * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
- * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE
- * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE
- * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
- * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2,
- * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and
- * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0)
- * were not represented exactly. Now we sacrifice exact representation of
- * maximum red and maximum blue in order to get exact grayscales.
- *
- * To avoid floating-point arithmetic, we represent the fractional constants
- * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
- * the products by 2^16, with appropriate rounding, to get the correct answer.
- *
- * For even more speed, we avoid doing any multiplications in the inner loop
- * by precalculating the constants times R,G,B for all possible values.
- * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
- * for 12-bit samples it is still acceptable. It's not very reasonable for
- * 16-bit samples, but if you want lossless storage you shouldn't be changing
- * colorspace anyway.
- * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included
- * in the tables to save adding them separately in the inner loop.
- */
-
-#define SCALEBITS 16 /* speediest right-shift on some machines */
-#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS)
-#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
-#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
-
-/* We allocate one big table and divide it up into eight parts, instead of
- * doing eight alloc_small requests. This lets us use a single table base
- * address, which can be held in a register in the inner loops on many
- * machines (more than can hold all eight addresses, anyway).
- */
-
-#define R_Y_OFF 0 /* offset to R => Y section */
-#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */
-#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */
-#define R_CB_OFF (3*(MAXJSAMPLE+1))
-#define G_CB_OFF (4*(MAXJSAMPLE+1))
-#define B_CB_OFF (5*(MAXJSAMPLE+1))
-#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */
-#define G_CR_OFF (6*(MAXJSAMPLE+1))
-#define B_CR_OFF (7*(MAXJSAMPLE+1))
-#define TABLE_SIZE (8*(MAXJSAMPLE+1))
-
-
-/*
- * Initialize for RGB->YCC colorspace conversion.
- */
-
-METHODDEF(void)
-rgb_ycc_start (j_compress_ptr cinfo)
-{
- my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
- INT32 * rgb_ycc_tab;
- INT32 i;
-
- /* Allocate and fill in the conversion tables. */
- cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (TABLE_SIZE * SIZEOF(INT32)));
-
- for (i = 0; i <= MAXJSAMPLE; i++) {
- rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i;
- rgb_ycc_tab[i+G_Y_OFF] = FIX(0.58700) * i;
- rgb_ycc_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF;
- rgb_ycc_tab[i+R_CB_OFF] = (-FIX(0.16874)) * i;
- rgb_ycc_tab[i+G_CB_OFF] = (-FIX(0.33126)) * i;
- /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr.
- * This ensures that the maximum output will round to MAXJSAMPLE
- * not MAXJSAMPLE+1, and thus that we don't have to range-limit.
- */
- rgb_ycc_tab[i+B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1;
-/* B=>Cb and R=>Cr tables are the same
- rgb_ycc_tab[i+R_CR_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1;
-*/
- rgb_ycc_tab[i+G_CR_OFF] = (-FIX(0.41869)) * i;
- rgb_ycc_tab[i+B_CR_OFF] = (-FIX(0.08131)) * i;
- }
-}
-
-
-/*
- * Convert some rows of samples to the JPEG colorspace.
- *
- * Note that we change from the application's interleaved-pixel format
- * to our internal noninterleaved, one-plane-per-component format.
- * The input buffer is therefore three times as wide as the output buffer.
- *
- * A starting row offset is provided only for the output buffer. The caller
- * can easily adjust the passed input_buf value to accommodate any row
- * offset required on that side.
- */
-
-METHODDEF(void)
-rgb_ycc_convert (j_compress_ptr cinfo,
- JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
- JDIMENSION output_row, int num_rows)
-{
- my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
- register int r, g, b;
- register INT32 * ctab = cconvert->rgb_ycc_tab;
- register JSAMPROW inptr;
- register JSAMPROW outptr0, outptr1, outptr2;
- register JDIMENSION col;
- JDIMENSION num_cols = cinfo->image_width;
-
- while (--num_rows >= 0) {
- inptr = *input_buf++;
- outptr0 = output_buf[0][output_row];
- outptr1 = output_buf[1][output_row];
- outptr2 = output_buf[2][output_row];
- output_row++;
- for (col = 0; col < num_cols; col++) {
- r = GETJSAMPLE(inptr[RGB_RED]);
- g = GETJSAMPLE(inptr[RGB_GREEN]);
- b = GETJSAMPLE(inptr[RGB_BLUE]);
- inptr += RGB_PIXELSIZE;
- /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
- * must be too; we do not need an explicit range-limiting operation.
- * Hence the value being shifted is never negative, and we don't
- * need the general RIGHT_SHIFT macro.
- */
- /* Y */
- outptr0[col] = (JSAMPLE)
- ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
- >> SCALEBITS);
- /* Cb */
- outptr1[col] = (JSAMPLE)
- ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
- >> SCALEBITS);
- /* Cr */
- outptr2[col] = (JSAMPLE)
- ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
- >> SCALEBITS);
- }
- }
-}
-
-
-/**************** Cases other than RGB -> YCbCr **************/
-
-
-/*
- * Convert some rows of samples to the JPEG colorspace.
- * This version handles RGB->grayscale conversion, which is the same
- * as the RGB->Y portion of RGB->YCbCr.
- * We assume rgb_ycc_start has been called (we only use the Y tables).
- */
-
-METHODDEF(void)
-rgb_gray_convert (j_compress_ptr cinfo,
- JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
- JDIMENSION output_row, int num_rows)
-{
- my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
- register int r, g, b;
- register INT32 * ctab = cconvert->rgb_ycc_tab;
- register JSAMPROW inptr;
- register JSAMPROW outptr;
- register JDIMENSION col;
- JDIMENSION num_cols = cinfo->image_width;
-
- while (--num_rows >= 0) {
- inptr = *input_buf++;
- outptr = output_buf[0][output_row];
- output_row++;
- for (col = 0; col < num_cols; col++) {
- r = GETJSAMPLE(inptr[RGB_RED]);
- g = GETJSAMPLE(inptr[RGB_GREEN]);
- b = GETJSAMPLE(inptr[RGB_BLUE]);
- inptr += RGB_PIXELSIZE;
- /* Y */
- outptr[col] = (JSAMPLE)
- ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
- >> SCALEBITS);
- }
- }
-}
-
-
-/*
- * Convert some rows of samples to the JPEG colorspace.
- * This version handles Adobe-style CMYK->YCCK conversion,
- * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same
- * conversion as above, while passing K (black) unchanged.
- * We assume rgb_ycc_start has been called.
- */
-
-METHODDEF(void)
-cmyk_ycck_convert (j_compress_ptr cinfo,
- JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
- JDIMENSION output_row, int num_rows)
-{
- my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
- register int r, g, b;
- register INT32 * ctab = cconvert->rgb_ycc_tab;
- register JSAMPROW inptr;
- register JSAMPROW outptr0, outptr1, outptr2, outptr3;
- register JDIMENSION col;
- JDIMENSION num_cols = cinfo->image_width;
-
- while (--num_rows >= 0) {
- inptr = *input_buf++;
- outptr0 = output_buf[0][output_row];
- outptr1 = output_buf[1][output_row];
- outptr2 = output_buf[2][output_row];
- outptr3 = output_buf[3][output_row];
- output_row++;
- for (col = 0; col < num_cols; col++) {
- r = MAXJSAMPLE - GETJSAMPLE(inptr[0]);
- g = MAXJSAMPLE - GETJSAMPLE(inptr[1]);
- b = MAXJSAMPLE - GETJSAMPLE(inptr[2]);
- /* K passes through as-is */
- outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */
- inptr += 4;
- /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
- * must be too; we do not need an explicit range-limiting operation.
- * Hence the value being shifted is never negative, and we don't
- * need the general RIGHT_SHIFT macro.
- */
- /* Y */
- outptr0[col] = (JSAMPLE)
- ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
- >> SCALEBITS);
- /* Cb */
- outptr1[col] = (JSAMPLE)
- ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
- >> SCALEBITS);
- /* Cr */
- outptr2[col] = (JSAMPLE)
- ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
- >> SCALEBITS);
- }
- }
-}
-
-
-/*
- * Convert some rows of samples to the JPEG colorspace.
- * This version handles grayscale output with no conversion.
- * The source can be either plain grayscale or YCbCr (since Y == gray).
- */
-
-METHODDEF(void)
-grayscale_convert (j_compress_ptr cinfo,
- JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
- JDIMENSION output_row, int num_rows)
-{
- register JSAMPROW inptr;
- register JSAMPROW outptr;
- register JDIMENSION col;
- JDIMENSION num_cols = cinfo->image_width;
- int instride = cinfo->input_components;
-
- while (--num_rows >= 0) {
- inptr = *input_buf++;
- outptr = output_buf[0][output_row];
- output_row++;
- for (col = 0; col < num_cols; col++) {
- outptr[col] = inptr[0]; /* don't need GETJSAMPLE() here */
- inptr += instride;
- }
- }
-}
-
-
-/*
- * Convert some rows of samples to the JPEG colorspace.
- * This version handles multi-component colorspaces without conversion.
- * We assume input_components == num_components.
- */
-
-METHODDEF(void)
-null_convert (j_compress_ptr cinfo,
- JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
- JDIMENSION output_row, int num_rows)
-{
- register JSAMPROW inptr;
- register JSAMPROW outptr;
- register JDIMENSION col;
- register int ci;
- int nc = cinfo->num_components;
- JDIMENSION num_cols = cinfo->image_width;
-
- while (--num_rows >= 0) {
- /* It seems fastest to make a separate pass for each component. */
- for (ci = 0; ci < nc; ci++) {
- inptr = *input_buf;
- outptr = output_buf[ci][output_row];
- for (col = 0; col < num_cols; col++) {
- outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */
- inptr += nc;
- }
- }
- input_buf++;
- output_row++;
- }
-}
-
-
-/*
- * Empty method for start_pass.
- */
-
-METHODDEF(void)
-null_method (j_compress_ptr cinfo)
-{
- /* no work needed */
-}
-
-
-/*
- * Module initialization routine for input colorspace conversion.
- */
-
-GLOBAL(void)
-jinit_color_converter (j_compress_ptr cinfo)
-{
- my_cconvert_ptr cconvert;
-
- cconvert = (my_cconvert_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_color_converter));
- cinfo->cconvert = (struct jpeg_color_converter *) cconvert;
- /* set start_pass to null method until we find out differently */
- cconvert->pub.start_pass = null_method;
-
- /* Make sure input_components agrees with in_color_space */
- switch (cinfo->in_color_space) {
- case JCS_GRAYSCALE:
- if (cinfo->input_components != 1)
- ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
- break;
-
- case JCS_RGB:
-#if RGB_PIXELSIZE != 3
- if (cinfo->input_components != RGB_PIXELSIZE)
- ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
- break;
-#endif /* else share code with YCbCr */
-
- case JCS_YCbCr:
- if (cinfo->input_components != 3)
- ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
- break;
-
- case JCS_CMYK:
- case JCS_YCCK:
- if (cinfo->input_components != 4)
- ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
- break;
-
- default: /* JCS_UNKNOWN can be anything */
- if (cinfo->input_components < 1)
- ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
- break;
- }
-
- /* Check num_components, set conversion method based on requested space */
- switch (cinfo->jpeg_color_space) {
- case JCS_GRAYSCALE:
- if (cinfo->num_components != 1)
- ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
- if (cinfo->in_color_space == JCS_GRAYSCALE)
- cconvert->pub.color_convert = grayscale_convert;
- else if (cinfo->in_color_space == JCS_RGB) {
- cconvert->pub.start_pass = rgb_ycc_start;
- cconvert->pub.color_convert = rgb_gray_convert;
- } else if (cinfo->in_color_space == JCS_YCbCr)
- cconvert->pub.color_convert = grayscale_convert;
- else
- ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
- break;
-
- case JCS_RGB:
- if (cinfo->num_components != 3)
- ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
- if (cinfo->in_color_space == JCS_RGB && RGB_PIXELSIZE == 3)
- cconvert->pub.color_convert = null_convert;
- else
- ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
- break;
-
- case JCS_YCbCr:
- if (cinfo->num_components != 3)
- ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
- if (cinfo->in_color_space == JCS_RGB) {
- cconvert->pub.start_pass = rgb_ycc_start;
- cconvert->pub.color_convert = rgb_ycc_convert;
- } else if (cinfo->in_color_space == JCS_YCbCr)
- cconvert->pub.color_convert = null_convert;
- else
- ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
- break;
-
- case JCS_CMYK:
- if (cinfo->num_components != 4)
- ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
- if (cinfo->in_color_space == JCS_CMYK)
- cconvert->pub.color_convert = null_convert;
- else
- ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
- break;
-
- case JCS_YCCK:
- if (cinfo->num_components != 4)
- ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
- if (cinfo->in_color_space == JCS_CMYK) {
- cconvert->pub.start_pass = rgb_ycc_start;
- cconvert->pub.color_convert = cmyk_ycck_convert;
- } else if (cinfo->in_color_space == JCS_YCCK)
- cconvert->pub.color_convert = null_convert;
- else
- ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
- break;
-
- default: /* allow null conversion of JCS_UNKNOWN */
- if (cinfo->jpeg_color_space != cinfo->in_color_space ||
- cinfo->num_components != cinfo->input_components)
- ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
- cconvert->pub.color_convert = null_convert;
- break;
- }
-}
diff --git a/engine/code/jpeg-6b/jcdctmgr.c b/engine/code/jpeg-6b/jcdctmgr.c
deleted file mode 100644
index 94d5cda..0000000
--- a/engine/code/jpeg-6b/jcdctmgr.c
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * jcdctmgr.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains the forward-DCT management logic.
- * This code selects a particular DCT implementation to be used,
- * and it performs related housekeeping chores including coefficient
- * quantization.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jdct.h" /* Private declarations for DCT subsystem */
-
-
-/* Private subobject for this module */
-
-typedef struct {
- struct jpeg_forward_dct pub; /* public fields */
-
- /* Pointer to the DCT routine actually in use */
- forward_DCT_method_ptr do_dct;
-
- /* The actual post-DCT divisors --- not identical to the quant table
- * entries, because of scaling (especially for an unnormalized DCT).
- * Each table is given in normal array order.
- */
- DCTELEM * divisors[NUM_QUANT_TBLS];
-
-#ifdef DCT_FLOAT_SUPPORTED
- /* Same as above for the floating-point case. */
- float_DCT_method_ptr do_float_dct;
- FAST_FLOAT * float_divisors[NUM_QUANT_TBLS];
-#endif
-} my_fdct_controller;
-
-typedef my_fdct_controller * my_fdct_ptr;
-
-
-/*
- * Initialize for a processing pass.
- * Verify that all referenced Q-tables are present, and set up
- * the divisor table for each one.
- * In the current implementation, DCT of all components is done during
- * the first pass, even if only some components will be output in the
- * first scan. Hence all components should be examined here.
- */
-
-METHODDEF(void)
-start_pass_fdctmgr (j_compress_ptr cinfo)
-{
- my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
- int ci, qtblno, i;
- jpeg_component_info *compptr;
- JQUANT_TBL * qtbl;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- qtblno = compptr->quant_tbl_no;
- /* Make sure specified quantization table is present */
- if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
- cinfo->quant_tbl_ptrs[qtblno] == NULL)
- ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
- qtbl = cinfo->quant_tbl_ptrs[qtblno];
- /* Compute divisors for this quant table */
- /* We may do this more than once for same table, but it's not a big deal */
- switch (cinfo->dct_method) {
-#ifdef DCT_ISLOW_SUPPORTED
- case JDCT_ISLOW:
- /* For LL&M IDCT method, divisors are equal to raw quantization
- * coefficients multiplied by 8 (to counteract scaling).
- */
- if (fdct->divisors[qtblno] == NULL) {
- fdct->divisors[qtblno] = (DCTELEM *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- DCTSIZE2 * SIZEOF(DCTELEM));
- }
- dtbl = fdct->divisors[qtblno];
- for (i = 0; i < DCTSIZE2; i++) {
- dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3;
- }
- break;
-#endif
-#ifdef DCT_IFAST_SUPPORTED
- case JDCT_IFAST:
- {
- /* For AA&N IDCT method, divisors are equal to quantization
- * coefficients scaled by scalefactor[row]*scalefactor[col], where
- * scalefactor[0] = 1
- * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
- * We apply a further scale factor of 8.
- */
-#define CONST_BITS 14
- static const INT16 aanscales[DCTSIZE2] = {
- /* precomputed values scaled up by 14 bits */
- 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
- 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
- 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
- 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
- 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
- 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
- 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
- 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
- };
- SHIFT_TEMPS
-
- if (fdct->divisors[qtblno] == NULL) {
- fdct->divisors[qtblno] = (DCTELEM *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- DCTSIZE2 * SIZEOF(DCTELEM));
- }
- dtbl = fdct->divisors[qtblno];
- for (i = 0; i < DCTSIZE2; i++) {
- dtbl[i] = (DCTELEM)
- DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
- (INT32) aanscales[i]),
- CONST_BITS-3);
- }
- }
- break;
-#endif
-#ifdef DCT_FLOAT_SUPPORTED
- case JDCT_FLOAT:
- {
- /* For float AA&N IDCT method, divisors are equal to quantization
- * coefficients scaled by scalefactor[row]*scalefactor[col], where
- * scalefactor[0] = 1
- * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
- * We apply a further scale factor of 8.
- * What's actually stored is 1/divisor so that the inner loop can
- * use a multiplication rather than a division.
- */
- FAST_FLOAT * fdtbl;
- int row, col;
- static const double aanscalefactor[DCTSIZE] = {
- 1.0, 1.387039845, 1.306562965, 1.175875602,
- 1.0, 0.785694958, 0.541196100, 0.275899379
- };
-
- if (fdct->float_divisors[qtblno] == NULL) {
- fdct->float_divisors[qtblno] = (FAST_FLOAT *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- DCTSIZE2 * SIZEOF(FAST_FLOAT));
- }
- fdtbl = fdct->float_divisors[qtblno];
- i = 0;
- for (row = 0; row < DCTSIZE; row++) {
- for (col = 0; col < DCTSIZE; col++) {
- fdtbl[i] = (FAST_FLOAT)
- (1.0 / (((double) qtbl->quantval[i] *
- aanscalefactor[row] * aanscalefactor[col] * 8.0)));
- i++;
- }
- }
- }
- break;
-#endif
- default:
- ERREXIT(cinfo, JERR_NOT_COMPILED);
- break;
- }
- }
-}
-
-
-/* code/jpeg-6b/jcdctmgr.c:184: warning: âforward_DCTâ defined but not used */
-#if 0
-/*
- * Perform forward DCT on one or more blocks of a component.
- *
- * The input samples are taken from the sample_data[] array starting at
- * position start_row/start_col, and moving to the right for any additional
- * blocks. The quantized coefficients are returned in coef_blocks[].
- */
-
-METHODDEF(void)
-forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
- JDIMENSION start_row, JDIMENSION start_col,
- JDIMENSION num_blocks)
-/* This version is used for integer DCT implementations. */
-{
- /* This routine is heavily used, so it's worth coding it tightly. */
- my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
- forward_DCT_method_ptr do_dct = fdct->do_dct;
- DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no];
- DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */
- JDIMENSION bi;
-
- sample_data += start_row; /* fold in the vertical offset once */
-
- for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) {
- /* Load data into workspace, applying unsigned->signed conversion */
- { register DCTELEM *workspaceptr;
- register JSAMPROW elemptr;
- register int elemr;
-
- workspaceptr = workspace;
- for (elemr = 0; elemr < DCTSIZE; elemr++) {
- elemptr = sample_data[elemr] + start_col;
-#if DCTSIZE == 8 /* unroll the inner loop */
- *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
-#else
- { register int elemc;
- for (elemc = DCTSIZE; elemc > 0; elemc--) {
- *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
- }
- }
-#endif
- }
- }
-
- /* Perform the DCT */
- (*do_dct) (workspace);
-
- /* Quantize/descale the coefficients, and store into coef_blocks[] */
- { register DCTELEM temp, qval;
- register int i;
- register JCOEFPTR output_ptr = coef_blocks[bi];
-
- for (i = 0; i < DCTSIZE2; i++) {
- qval = divisors[i];
- temp = workspace[i];
- /* Divide the coefficient value by qval, ensuring proper rounding.
- * Since C does not specify the direction of rounding for negative
- * quotients, we have to force the dividend positive for portability.
- *
- * In most files, at least half of the output values will be zero
- * (at default quantization settings, more like three-quarters...)
- * so we should ensure that this case is fast. On many machines,
- * a comparison is enough cheaper than a divide to make a special test
- * a win. Since both inputs will be nonnegative, we need only test
- * for a < b to discover whether a/b is 0.
- * If your machine's division is fast enough, define FAST_DIVIDE.
- */
-#ifdef FAST_DIVIDE
-#define DIVIDE_BY(a,b) a /= b
-#else
-#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0
-#endif
- if (temp < 0) {
- temp = -temp;
- temp += qval>>1; /* for rounding */
- DIVIDE_BY(temp, qval);
- temp = -temp;
- } else {
- temp += qval>>1; /* for rounding */
- DIVIDE_BY(temp, qval);
- }
- output_ptr[i] = (JCOEF) temp;
- }
- }
- }
-}
-#endif
-
-
-#ifdef DCT_FLOAT_SUPPORTED
-
-METHODDEF(void)
-forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
- JDIMENSION start_row, JDIMENSION start_col,
- JDIMENSION num_blocks)
-/* This version is used for floating-point DCT implementations. */
-{
- /* This routine is heavily used, so it's worth coding it tightly. */
- my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
- float_DCT_method_ptr do_dct = fdct->do_float_dct;
- FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no];
- FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */
- JDIMENSION bi;
-
- sample_data += start_row; /* fold in the vertical offset once */
-
- for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) {
- /* Load data into workspace, applying unsigned->signed conversion */
- { register FAST_FLOAT *workspaceptr;
- register JSAMPROW elemptr;
- register int elemr;
-
- workspaceptr = workspace;
- for (elemr = 0; elemr < DCTSIZE; elemr++) {
- elemptr = sample_data[elemr] + start_col;
-#if DCTSIZE == 8 /* unroll the inner loop */
- *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
-#else
- { register int elemc;
- for (elemc = DCTSIZE; elemc > 0; elemc--) {
- *workspaceptr++ = (FAST_FLOAT)
- (GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
- }
- }
-#endif
- }
- }
-
- /* Perform the DCT */
- (*do_dct) (workspace);
-
- /* Quantize/descale the coefficients, and store into coef_blocks[] */
- { register FAST_FLOAT temp;
- register int i;
- register JCOEFPTR output_ptr = coef_blocks[bi];
-
- for (i = 0; i < DCTSIZE2; i++) {
- /* Apply the quantization and scaling factor */
- temp = workspace[i] * divisors[i];
- /* Round to nearest integer.
- * Since C does not specify the direction of rounding for negative
- * quotients, we have to force the dividend positive for portability.
- * The maximum coefficient size is +-16K (for 12-bit data), so this
- * code should work for either 16-bit or 32-bit ints.
- */
- output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384);
- }
- }
- }
-}
-
-#endif /* DCT_FLOAT_SUPPORTED */
-
-
-/*
- * Initialize FDCT manager.
- */
-
-GLOBAL(void)
-jinit_forward_dct (j_compress_ptr cinfo)
-{
- my_fdct_ptr fdct;
- int i;
-
- fdct = (my_fdct_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_fdct_controller));
- cinfo->fdct = (struct jpeg_forward_dct *) fdct;
- fdct->pub.start_pass = start_pass_fdctmgr;
-
- switch (cinfo->dct_method) {
-#ifdef DCT_ISLOW_SUPPORTED
- case JDCT_ISLOW:
- fdct->pub.forward_DCT = forward_DCT;
- fdct->do_dct = jpeg_fdct_islow;
- break;
-#endif
-#ifdef DCT_IFAST_SUPPORTED
- case JDCT_IFAST:
- fdct->pub.forward_DCT = forward_DCT;
- fdct->do_dct = jpeg_fdct_ifast;
- break;
-#endif
-#ifdef DCT_FLOAT_SUPPORTED
- case JDCT_FLOAT:
- fdct->pub.forward_DCT = forward_DCT_float;
- fdct->do_float_dct = jpeg_fdct_float;
- break;
-#endif
- default:
- ERREXIT(cinfo, JERR_NOT_COMPILED);
- break;
- }
-
- /* Mark divisor tables unallocated */
- for (i = 0; i < NUM_QUANT_TBLS; i++) {
- fdct->divisors[i] = NULL;
-#ifdef DCT_FLOAT_SUPPORTED
- fdct->float_divisors[i] = NULL;
-#endif
- }
-}
diff --git a/engine/code/jpeg-6b/jchuff.c b/engine/code/jpeg-6b/jchuff.c
deleted file mode 100644
index f235250..0000000
--- a/engine/code/jpeg-6b/jchuff.c
+++ /dev/null
@@ -1,909 +0,0 @@
-/*
- * jchuff.c
- *
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains Huffman entropy encoding routines.
- *
- * Much of the complexity here has to do with supporting output suspension.
- * If the data destination module demands suspension, we want to be able to
- * back up to the start of the current MCU. To do this, we copy state
- * variables into local working storage, and update them back to the
- * permanent JPEG objects only upon successful completion of an MCU.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jchuff.h" /* Declarations shared with jcphuff.c */
-
-
-/* Expanded entropy encoder object for Huffman encoding.
- *
- * The savable_state subrecord contains fields that change within an MCU,
- * but must not be updated permanently until we complete the MCU.
- */
-
-typedef struct {
- INT32 put_buffer; /* current bit-accumulation buffer */
- int put_bits; /* # of bits now in it */
- int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
-} savable_state;
-
-/* This macro is to work around compilers with missing or broken
- * structure assignment. You'll need to fix this code if you have
- * such a compiler and you change MAX_COMPS_IN_SCAN.
- */
-
-#ifndef NO_STRUCT_ASSIGN
-#define ASSIGN_STATE(dest,src) ((dest) = (src))
-#else
-#if MAX_COMPS_IN_SCAN == 4
-#define ASSIGN_STATE(dest,src) \
- ((dest).put_buffer = (src).put_buffer, \
- (dest).put_bits = (src).put_bits, \
- (dest).last_dc_val[0] = (src).last_dc_val[0], \
- (dest).last_dc_val[1] = (src).last_dc_val[1], \
- (dest).last_dc_val[2] = (src).last_dc_val[2], \
- (dest).last_dc_val[3] = (src).last_dc_val[3])
-#endif
-#endif
-
-
-typedef struct {
- struct jpeg_entropy_encoder pub; /* public fields */
-
- savable_state saved; /* Bit buffer & DC state at start of MCU */
-
- /* These fields are NOT loaded into local working state. */
- unsigned int restarts_to_go; /* MCUs left in this restart interval */
- int next_restart_num; /* next restart number to write (0-7) */
-
- /* Pointers to derived tables (these workspaces have image lifespan) */
- c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
- c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
-
-#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */
- long * dc_count_ptrs[NUM_HUFF_TBLS];
- long * ac_count_ptrs[NUM_HUFF_TBLS];
-#endif
-} huff_entropy_encoder;
-
-typedef huff_entropy_encoder * huff_entropy_ptr;
-
-/* Working state while writing an MCU.
- * This struct contains all the fields that are needed by subroutines.
- */
-
-typedef struct {
- JOCTET * next_output_byte; /* => next byte to write in buffer */
- size_t free_in_buffer; /* # of byte spaces remaining in buffer */
- savable_state cur; /* Current bit buffer & DC state */
- j_compress_ptr cinfo; /* dump_buffer needs access to this */
-} working_state;
-
-
-/* Forward declarations */
-METHODDEF(boolean) encode_mcu_huff JPP((j_compress_ptr cinfo,
- JBLOCKROW *MCU_data));
-METHODDEF(void) finish_pass_huff JPP((j_compress_ptr cinfo));
-#ifdef ENTROPY_OPT_SUPPORTED
-METHODDEF(boolean) encode_mcu_gather JPP((j_compress_ptr cinfo,
- JBLOCKROW *MCU_data));
-METHODDEF(void) finish_pass_gather JPP((j_compress_ptr cinfo));
-#endif
-
-
-/*
- * Initialize for a Huffman-compressed scan.
- * If gather_statistics is TRUE, we do not output anything during the scan,
- * just count the Huffman symbols used and generate Huffman code tables.
- */
-
-METHODDEF(void)
-start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
-{
- huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
- int ci, dctbl, actbl;
- jpeg_component_info * compptr;
-
- if (gather_statistics) {
-#ifdef ENTROPY_OPT_SUPPORTED
- entropy->pub.encode_mcu = encode_mcu_gather;
- entropy->pub.finish_pass = finish_pass_gather;
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- } else {
- entropy->pub.encode_mcu = encode_mcu_huff;
- entropy->pub.finish_pass = finish_pass_huff;
- }
-
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- dctbl = compptr->dc_tbl_no;
- actbl = compptr->ac_tbl_no;
- if (gather_statistics) {
-#ifdef ENTROPY_OPT_SUPPORTED
- /* Check for invalid table indexes */
- /* (make_c_derived_tbl does this in the other path) */
- if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS)
- ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl);
- if (actbl < 0 || actbl >= NUM_HUFF_TBLS)
- ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl);
- /* Allocate and zero the statistics tables */
- /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */
- if (entropy->dc_count_ptrs[dctbl] == NULL)
- entropy->dc_count_ptrs[dctbl] = (long *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- 257 * SIZEOF(long));
- MEMZERO(entropy->dc_count_ptrs[dctbl], 257 * SIZEOF(long));
- if (entropy->ac_count_ptrs[actbl] == NULL)
- entropy->ac_count_ptrs[actbl] = (long *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- 257 * SIZEOF(long));
- MEMZERO(entropy->ac_count_ptrs[actbl], 257 * SIZEOF(long));
-#endif
- } else {
- /* Compute derived values for Huffman tables */
- /* We may do this more than once for a table, but it's not expensive */
- jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl,
- & entropy->dc_derived_tbls[dctbl]);
- jpeg_make_c_derived_tbl(cinfo, FALSE, actbl,
- & entropy->ac_derived_tbls[actbl]);
- }
- /* Initialize DC predictions to 0 */
- entropy->saved.last_dc_val[ci] = 0;
- }
-
- /* Initialize bit buffer to empty */
- entropy->saved.put_buffer = 0;
- entropy->saved.put_bits = 0;
-
- /* Initialize restart stuff */
- entropy->restarts_to_go = cinfo->restart_interval;
- entropy->next_restart_num = 0;
-}
-
-
-/*
- * Compute the derived values for a Huffman table.
- * This routine also performs some validation checks on the table.
- *
- * Note this is also used by jcphuff.c.
- */
-
-GLOBAL(void)
-jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,
- c_derived_tbl ** pdtbl)
-{
- JHUFF_TBL *htbl;
- c_derived_tbl *dtbl;
- int p, i, l, lastp, si, maxsymbol;
- char huffsize[257];
- unsigned int huffcode[257];
- unsigned int code;
-
- /* Note that huffsize[] and huffcode[] are filled in code-length order,
- * paralleling the order of the symbols themselves in htbl->huffval[].
- */
-
- /* Find the input Huffman table */
- if (tblno < 0 || tblno >= NUM_HUFF_TBLS)
- ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
- htbl =
- isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno];
- if (htbl == NULL)
- ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
-
- /* Allocate a workspace if we haven't already done so. */
- if (*pdtbl == NULL)
- *pdtbl = (c_derived_tbl *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(c_derived_tbl));
- dtbl = *pdtbl;
-
- /* Figure C.1: make table of Huffman code length for each symbol */
-
- p = 0;
- for (l = 1; l <= 16; l++) {
- i = (int) htbl->bits[l];
- if (i < 0 || p + i > 256) /* protect against table overrun */
- ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
- while (i--)
- huffsize[p++] = (char) l;
- }
- huffsize[p] = 0;
- lastp = p;
-
- /* Figure C.2: generate the codes themselves */
- /* We also validate that the counts represent a legal Huffman code tree. */
-
- code = 0;
- si = huffsize[0];
- p = 0;
- while (huffsize[p]) {
- while (((int) huffsize[p]) == si) {
- huffcode[p++] = code;
- code++;
- }
- /* code is now 1 more than the last code used for codelength si; but
- * it must still fit in si bits, since no code is allowed to be all ones.
- */
- if (((INT32) code) >= (((INT32) 1) << si))
- ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
- code <<= 1;
- si++;
- }
-
- /* Figure C.3: generate encoding tables */
- /* These are code and size indexed by symbol value */
-
- /* Set all codeless symbols to have code length 0;
- * this lets us detect duplicate VAL entries here, and later
- * allows emit_bits to detect any attempt to emit such symbols.
- */
- MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi));
-
- /* This is also a convenient place to check for out-of-range
- * and duplicated VAL entries. We allow 0..255 for AC symbols
- * but only 0..15 for DC. (We could constrain them further
- * based on data depth and mode, but this seems enough.)
- */
- maxsymbol = isDC ? 15 : 255;
-
- for (p = 0; p < lastp; p++) {
- i = htbl->huffval[p];
- if (i < 0 || i > maxsymbol || dtbl->ehufsi[i])
- ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
- dtbl->ehufco[i] = huffcode[p];
- dtbl->ehufsi[i] = huffsize[p];
- }
-}
-
-
-/* Outputting bytes to the file */
-
-/* Emit a byte, taking 'action' if must suspend. */
-#define emit_byte(state,val,action) \
- { *(state)->next_output_byte++ = (JOCTET) (val); \
- if (--(state)->free_in_buffer == 0) \
- if (! dump_buffer(state)) \
- { action; } }
-
-
-LOCAL(boolean)
-dump_buffer (working_state * state)
-/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */
-{
- struct jpeg_destination_mgr * dest = state->cinfo->dest;
-
- if (! (*dest->empty_output_buffer) (state->cinfo))
- return FALSE;
- /* After a successful buffer dump, must reset buffer pointers */
- state->next_output_byte = dest->next_output_byte;
- state->free_in_buffer = dest->free_in_buffer;
- return TRUE;
-}
-
-
-/* Outputting bits to the file */
-
-/* Only the right 24 bits of put_buffer are used; the valid bits are
- * left-justified in this part. At most 16 bits can be passed to emit_bits
- * in one call, and we never retain more than 7 bits in put_buffer
- * between calls, so 24 bits are sufficient.
- */
-
-INLINE
-LOCAL(boolean)
-emit_bits (working_state * state, unsigned int code, int size)
-/* Emit some bits; return TRUE if successful, FALSE if must suspend */
-{
- /* This routine is heavily used, so it's worth coding tightly. */
- register INT32 put_buffer = (INT32) code;
- register int put_bits = state->cur.put_bits;
-
- /* if size is 0, caller used an invalid Huffman table entry */
- if (size == 0)
- ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE);
-
- put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */
-
- put_bits += size; /* new number of bits in buffer */
-
- put_buffer <<= 24 - put_bits; /* align incoming bits */
-
- put_buffer |= state->cur.put_buffer; /* and merge with old buffer contents */
-
- while (put_bits >= 8) {
- int c = (int) ((put_buffer >> 16) & 0xFF);
-
- emit_byte(state, c, return FALSE);
- if (c == 0xFF) { /* need to stuff a zero byte? */
- emit_byte(state, 0, return FALSE);
- }
- put_buffer <<= 8;
- put_bits -= 8;
- }
-
- state->cur.put_buffer = put_buffer; /* update state variables */
- state->cur.put_bits = put_bits;
-
- return TRUE;
-}
-
-
-LOCAL(boolean)
-flush_bits (working_state * state)
-{
- if (! emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */
- return FALSE;
- state->cur.put_buffer = 0; /* and reset bit-buffer to empty */
- state->cur.put_bits = 0;
- return TRUE;
-}
-
-
-/* Encode a single block's worth of coefficients */
-
-LOCAL(boolean)
-encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,
- c_derived_tbl *dctbl, c_derived_tbl *actbl)
-{
- register int temp, temp2;
- register int nbits;
- register int k, r, i;
-
- /* Encode the DC coefficient difference per section F.1.2.1 */
-
- temp = temp2 = block[0] - last_dc_val;
-
- if (temp < 0) {
- temp = -temp; /* temp is abs value of input */
- /* For a negative input, want temp2 = bitwise complement of abs(input) */
- /* This code assumes we are on a two's complement machine */
- temp2--;
- }
-
- /* Find the number of bits needed for the magnitude of the coefficient */
- nbits = 0;
- while (temp) {
- nbits++;
- temp >>= 1;
- }
- /* Check for out-of-range coefficient values.
- * Since we're encoding a difference, the range limit is twice as much.
- */
- if (nbits > MAX_COEF_BITS+1)
- ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
-
- /* Emit the Huffman-coded symbol for the number of bits */
- if (! emit_bits(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits]))
- return FALSE;
-
- /* Emit that number of bits of the value, if positive, */
- /* or the complement of its magnitude, if negative. */
- if (nbits) /* emit_bits rejects calls with size 0 */
- if (! emit_bits(state, (unsigned int) temp2, nbits))
- return FALSE;
-
- /* Encode the AC coefficients per section F.1.2.2 */
-
- r = 0; /* r = run length of zeros */
-
- for (k = 1; k < DCTSIZE2; k++) {
- if ((temp = block[jpeg_natural_order[k]]) == 0) {
- r++;
- } else {
- /* if run length > 15, must emit special run-length-16 codes (0xF0) */
- while (r > 15) {
- if (! emit_bits(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0]))
- return FALSE;
- r -= 16;
- }
-
- temp2 = temp;
- if (temp < 0) {
- temp = -temp; /* temp is abs value of input */
- /* This code assumes we are on a two's complement machine */
- temp2--;
- }
-
- /* Find the number of bits needed for the magnitude of the coefficient */
- nbits = 1; /* there must be at least one 1 bit */
- while ((temp >>= 1))
- nbits++;
- /* Check for out-of-range coefficient values */
- if (nbits > MAX_COEF_BITS)
- ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
-
- /* Emit Huffman symbol for run length / number of bits */
- i = (r << 4) + nbits;
- if (! emit_bits(state, actbl->ehufco[i], actbl->ehufsi[i]))
- return FALSE;
-
- /* Emit that number of bits of the value, if positive, */
- /* or the complement of its magnitude, if negative. */
- if (! emit_bits(state, (unsigned int) temp2, nbits))
- return FALSE;
-
- r = 0;
- }
- }
-
- /* If the last coef(s) were zero, emit an end-of-block code */
- if (r > 0)
- if (! emit_bits(state, actbl->ehufco[0], actbl->ehufsi[0]))
- return FALSE;
-
- return TRUE;
-}
-
-
-/*
- * Emit a restart marker & resynchronize predictions.
- */
-
-LOCAL(boolean)
-emit_restart (working_state * state, int restart_num)
-{
- int ci;
-
- if (! flush_bits(state))
- return FALSE;
-
- emit_byte(state, 0xFF, return FALSE);
- emit_byte(state, JPEG_RST0 + restart_num, return FALSE);
-
- /* Re-initialize DC predictions to 0 */
- for (ci = 0; ci < state->cinfo->comps_in_scan; ci++)
- state->cur.last_dc_val[ci] = 0;
-
- /* The restart counter is not updated until we successfully write the MCU. */
-
- return TRUE;
-}
-
-
-/*
- * Encode and output one MCU's worth of Huffman-compressed coefficients.
- */
-
-METHODDEF(boolean)
-encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
-{
- huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
- working_state state;
- int blkn, ci;
- jpeg_component_info * compptr;
-
- /* Load up working state */
- state.next_output_byte = cinfo->dest->next_output_byte;
- state.free_in_buffer = cinfo->dest->free_in_buffer;
- ASSIGN_STATE(state.cur, entropy->saved);
- state.cinfo = cinfo;
-
- /* Emit restart marker if needed */
- if (cinfo->restart_interval) {
- if (entropy->restarts_to_go == 0)
- if (! emit_restart(&state, entropy->next_restart_num))
- return FALSE;
- }
-
- /* Encode the MCU data blocks */
- for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
- ci = cinfo->MCU_membership[blkn];
- compptr = cinfo->cur_comp_info[ci];
- if (! encode_one_block(&state,
- MCU_data[blkn][0], state.cur.last_dc_val[ci],
- entropy->dc_derived_tbls[compptr->dc_tbl_no],
- entropy->ac_derived_tbls[compptr->ac_tbl_no]))
- return FALSE;
- /* Update last_dc_val */
- state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
- }
-
- /* Completed MCU, so update state */
- cinfo->dest->next_output_byte = state.next_output_byte;
- cinfo->dest->free_in_buffer = state.free_in_buffer;
- ASSIGN_STATE(entropy->saved, state.cur);
-
- /* Update restart-interval state too */
- if (cinfo->restart_interval) {
- if (entropy->restarts_to_go == 0) {
- entropy->restarts_to_go = cinfo->restart_interval;
- entropy->next_restart_num++;
- entropy->next_restart_num &= 7;
- }
- entropy->restarts_to_go--;
- }
-
- return TRUE;
-}
-
-
-/*
- * Finish up at the end of a Huffman-compressed scan.
- */
-
-METHODDEF(void)
-finish_pass_huff (j_compress_ptr cinfo)
-{
- huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
- working_state state;
-
- /* Load up working state ... flush_bits needs it */
- state.next_output_byte = cinfo->dest->next_output_byte;
- state.free_in_buffer = cinfo->dest->free_in_buffer;
- ASSIGN_STATE(state.cur, entropy->saved);
- state.cinfo = cinfo;
-
- /* Flush out the last data */
- if (! flush_bits(&state))
- ERREXIT(cinfo, JERR_CANT_SUSPEND);
-
- /* Update state */
- cinfo->dest->next_output_byte = state.next_output_byte;
- cinfo->dest->free_in_buffer = state.free_in_buffer;
- ASSIGN_STATE(entropy->saved, state.cur);
-}
-
-
-/*
- * Huffman coding optimization.
- *
- * We first scan the supplied data and count the number of uses of each symbol
- * that is to be Huffman-coded. (This process MUST agree with the code above.)
- * Then we build a Huffman coding tree for the observed counts.
- * Symbols which are not needed at all for the particular image are not
- * assigned any code, which saves space in the DHT marker as well as in
- * the compressed data.
- */
-
-#ifdef ENTROPY_OPT_SUPPORTED
-
-
-/* Process a single block's worth of coefficients */
-
-LOCAL(void)
-htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val,
- long dc_counts[], long ac_counts[])
-{
- register int temp;
- register int nbits;
- register int k, r;
-
- /* Encode the DC coefficient difference per section F.1.2.1 */
-
- temp = block[0] - last_dc_val;
- if (temp < 0)
- temp = -temp;
-
- /* Find the number of bits needed for the magnitude of the coefficient */
- nbits = 0;
- while (temp) {
- nbits++;
- temp >>= 1;
- }
- /* Check for out-of-range coefficient values.
- * Since we're encoding a difference, the range limit is twice as much.
- */
- if (nbits > MAX_COEF_BITS+1)
- ERREXIT(cinfo, JERR_BAD_DCT_COEF);
-
- /* Count the Huffman symbol for the number of bits */
- dc_counts[nbits]++;
-
- /* Encode the AC coefficients per section F.1.2.2 */
-
- r = 0; /* r = run length of zeros */
-
- for (k = 1; k < DCTSIZE2; k++) {
- if ((temp = block[jpeg_natural_order[k]]) == 0) {
- r++;
- } else {
- /* if run length > 15, must emit special run-length-16 codes (0xF0) */
- while (r > 15) {
- ac_counts[0xF0]++;
- r -= 16;
- }
-
- /* Find the number of bits needed for the magnitude of the coefficient */
- if (temp < 0)
- temp = -temp;
-
- /* Find the number of bits needed for the magnitude of the coefficient */
- nbits = 1; /* there must be at least one 1 bit */
- while ((temp >>= 1))
- nbits++;
- /* Check for out-of-range coefficient values */
- if (nbits > MAX_COEF_BITS)
- ERREXIT(cinfo, JERR_BAD_DCT_COEF);
-
- /* Count Huffman symbol for run length / number of bits */
- ac_counts[(r << 4) + nbits]++;
-
- r = 0;
- }
- }
-
- /* If the last coef(s) were zero, emit an end-of-block code */
- if (r > 0)
- ac_counts[0]++;
-}
-
-
-/*
- * Trial-encode one MCU's worth of Huffman-compressed coefficients.
- * No data is actually output, so no suspension return is possible.
- */
-
-METHODDEF(boolean)
-encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
-{
- huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
- int blkn, ci;
- jpeg_component_info * compptr;
-
- /* Take care of restart intervals if needed */
- if (cinfo->restart_interval) {
- if (entropy->restarts_to_go == 0) {
- /* Re-initialize DC predictions to 0 */
- for (ci = 0; ci < cinfo->comps_in_scan; ci++)
- entropy->saved.last_dc_val[ci] = 0;
- /* Update restart state */
- entropy->restarts_to_go = cinfo->restart_interval;
- }
- entropy->restarts_to_go--;
- }
-
- for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
- ci = cinfo->MCU_membership[blkn];
- compptr = cinfo->cur_comp_info[ci];
- htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci],
- entropy->dc_count_ptrs[compptr->dc_tbl_no],
- entropy->ac_count_ptrs[compptr->ac_tbl_no]);
- entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0];
- }
-
- return TRUE;
-}
-
-
-/*
- * Generate the best Huffman code table for the given counts, fill htbl.
- * Note this is also used by jcphuff.c.
- *
- * The JPEG standard requires that no symbol be assigned a codeword of all
- * one bits (so that padding bits added at the end of a compressed segment
- * can't look like a valid code). Because of the canonical ordering of
- * codewords, this just means that there must be an unused slot in the
- * longest codeword length category. Section K.2 of the JPEG spec suggests
- * reserving such a slot by pretending that symbol 256 is a valid symbol
- * with count 1. In theory that's not optimal; giving it count zero but
- * including it in the symbol set anyway should give a better Huffman code.
- * But the theoretically better code actually seems to come out worse in
- * practice, because it produces more all-ones bytes (which incur stuffed
- * zero bytes in the final file). In any case the difference is tiny.
- *
- * The JPEG standard requires Huffman codes to be no more than 16 bits long.
- * If some symbols have a very small but nonzero probability, the Huffman tree
- * must be adjusted to meet the code length restriction. We currently use
- * the adjustment method suggested in JPEG section K.2. This method is *not*
- * optimal; it may not choose the best possible limited-length code. But
- * typically only very-low-frequency symbols will be given less-than-optimal
- * lengths, so the code is almost optimal. Experimental comparisons against
- * an optimal limited-length-code algorithm indicate that the difference is
- * microscopic --- usually less than a hundredth of a percent of total size.
- * So the extra complexity of an optimal algorithm doesn't seem worthwhile.
- */
-
-GLOBAL(void)
-jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])
-{
-#define MAX_CLEN 32 /* assumed maximum initial code length */
- UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */
- int codesize[257]; /* codesize[k] = code length of symbol k */
- int others[257]; /* next symbol in current branch of tree */
- int c1, c2;
- int p, i, j;
- long v;
-
- /* This algorithm is explained in section K.2 of the JPEG standard */
-
- MEMZERO(bits, SIZEOF(bits));
- MEMZERO(codesize, SIZEOF(codesize));
- for (i = 0; i < 257; i++)
- others[i] = -1; /* init links to empty */
-
- freq[256] = 1; /* make sure 256 has a nonzero count */
- /* Including the pseudo-symbol 256 in the Huffman procedure guarantees
- * that no real symbol is given code-value of all ones, because 256
- * will be placed last in the largest codeword category.
- */
-
- /* Huffman's basic algorithm to assign optimal code lengths to symbols */
-
- for (;;) {
- /* Find the smallest nonzero frequency, set c1 = its symbol */
- /* In case of ties, take the larger symbol number */
- c1 = -1;
- v = 1000000000L;
- for (i = 0; i <= 256; i++) {
- if (freq[i] && freq[i] <= v) {
- v = freq[i];
- c1 = i;
- }
- }
-
- /* Find the next smallest nonzero frequency, set c2 = its symbol */
- /* In case of ties, take the larger symbol number */
- c2 = -1;
- v = 1000000000L;
- for (i = 0; i <= 256; i++) {
- if (freq[i] && freq[i] <= v && i != c1) {
- v = freq[i];
- c2 = i;
- }
- }
-
- /* Done if we've merged everything into one frequency */
- if (c2 < 0)
- break;
-
- /* Else merge the two counts/trees */
- freq[c1] += freq[c2];
- freq[c2] = 0;
-
- /* Increment the codesize of everything in c1's tree branch */
- codesize[c1]++;
- while (others[c1] >= 0) {
- c1 = others[c1];
- codesize[c1]++;
- }
-
- others[c1] = c2; /* chain c2 onto c1's tree branch */
-
- /* Increment the codesize of everything in c2's tree branch */
- codesize[c2]++;
- while (others[c2] >= 0) {
- c2 = others[c2];
- codesize[c2]++;
- }
- }
-
- /* Now count the number of symbols of each code length */
- for (i = 0; i <= 256; i++) {
- if (codesize[i]) {
- /* The JPEG standard seems to think that this can't happen, */
- /* but I'm paranoid... */
- if (codesize[i] > MAX_CLEN)
- ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW);
-
- bits[codesize[i]]++;
- }
- }
-
- /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure
- * Huffman procedure assigned any such lengths, we must adjust the coding.
- * Here is what the JPEG spec says about how this next bit works:
- * Since symbols are paired for the longest Huffman code, the symbols are
- * removed from this length category two at a time. The prefix for the pair
- * (which is one bit shorter) is allocated to one of the pair; then,
- * skipping the BITS entry for that prefix length, a code word from the next
- * shortest nonzero BITS entry is converted into a prefix for two code words
- * one bit longer.
- */
-
- for (i = MAX_CLEN; i > 16; i--) {
- while (bits[i] > 0) {
- j = i - 2; /* find length of new prefix to be used */
- while (bits[j] == 0)
- j--;
-
- bits[i] -= 2; /* remove two symbols */
- bits[i-1]++; /* one goes in this length */
- bits[j+1] += 2; /* two new symbols in this length */
- bits[j]--; /* symbol of this length is now a prefix */
- }
- }
-
- /* Remove the count for the pseudo-symbol 256 from the largest codelength */
- while (bits[i] == 0) /* find largest codelength still in use */
- i--;
- bits[i]--;
-
- /* Return final symbol counts (only for lengths 0..16) */
- MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits));
-
- /* Return a list of the symbols sorted by code length */
- /* It's not real clear to me why we don't need to consider the codelength
- * changes made above, but the JPEG spec seems to think this works.
- */
- p = 0;
- for (i = 1; i <= MAX_CLEN; i++) {
- for (j = 0; j <= 255; j++) {
- if (codesize[j] == i) {
- htbl->huffval[p] = (UINT8) j;
- p++;
- }
- }
- }
-
- /* Set sent_table FALSE so updated table will be written to JPEG file. */
- htbl->sent_table = FALSE;
-}
-
-
-/*
- * Finish up a statistics-gathering pass and create the new Huffman tables.
- */
-
-METHODDEF(void)
-finish_pass_gather (j_compress_ptr cinfo)
-{
- huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
- int ci, dctbl, actbl;
- jpeg_component_info * compptr;
- JHUFF_TBL **htblptr;
- boolean did_dc[NUM_HUFF_TBLS];
- boolean did_ac[NUM_HUFF_TBLS];
-
- /* It's important not to apply jpeg_gen_optimal_table more than once
- * per table, because it clobbers the input frequency counts!
- */
- MEMZERO(did_dc, SIZEOF(did_dc));
- MEMZERO(did_ac, SIZEOF(did_ac));
-
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- dctbl = compptr->dc_tbl_no;
- actbl = compptr->ac_tbl_no;
- if (! did_dc[dctbl]) {
- htblptr = & cinfo->dc_huff_tbl_ptrs[dctbl];
- if (*htblptr == NULL)
- *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
- jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[dctbl]);
- did_dc[dctbl] = TRUE;
- }
- if (! did_ac[actbl]) {
- htblptr = & cinfo->ac_huff_tbl_ptrs[actbl];
- if (*htblptr == NULL)
- *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
- jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[actbl]);
- did_ac[actbl] = TRUE;
- }
- }
-}
-
-
-#endif /* ENTROPY_OPT_SUPPORTED */
-
-
-/*
- * Module initialization routine for Huffman entropy encoding.
- */
-
-GLOBAL(void)
-jinit_huff_encoder (j_compress_ptr cinfo)
-{
- huff_entropy_ptr entropy;
- int i;
-
- entropy = (huff_entropy_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(huff_entropy_encoder));
- cinfo->entropy = (struct jpeg_entropy_encoder *) entropy;
- entropy->pub.start_pass = start_pass_huff;
-
- /* Mark tables unallocated */
- for (i = 0; i < NUM_HUFF_TBLS; i++) {
- entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
-#ifdef ENTROPY_OPT_SUPPORTED
- entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL;
-#endif
- }
-}
diff --git a/engine/code/jpeg-6b/jchuff.h b/engine/code/jpeg-6b/jchuff.h
deleted file mode 100644
index a9599fc..0000000
--- a/engine/code/jpeg-6b/jchuff.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * jchuff.h
- *
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains declarations for Huffman entropy encoding routines
- * that are shared between the sequential encoder (jchuff.c) and the
- * progressive encoder (jcphuff.c). No other modules need to see these.
- */
-
-/* The legal range of a DCT coefficient is
- * -1024 .. +1023 for 8-bit data;
- * -16384 .. +16383 for 12-bit data.
- * Hence the magnitude should always fit in 10 or 14 bits respectively.
- */
-
-#if BITS_IN_JSAMPLE == 8
-#define MAX_COEF_BITS 10
-#else
-#define MAX_COEF_BITS 14
-#endif
-
-/* Derived data constructed for each Huffman table */
-
-typedef struct {
- unsigned int ehufco[256]; /* code for each symbol */
- char ehufsi[256]; /* length of code for each symbol */
- /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */
-} c_derived_tbl;
-
-/* Short forms of external names for systems with brain-damaged linkers. */
-
-#ifdef NEED_SHORT_EXTERNAL_NAMES
-#define jpeg_make_c_derived_tbl jMkCDerived
-#define jpeg_gen_optimal_table jGenOptTbl
-#endif /* NEED_SHORT_EXTERNAL_NAMES */
-
-/* Expand a Huffman table definition into the derived format */
-EXTERN(void) jpeg_make_c_derived_tbl
- JPP((j_compress_ptr cinfo, boolean isDC, int tblno,
- c_derived_tbl ** pdtbl));
-
-/* Generate an optimal table definition given the specified counts */
-EXTERN(void) jpeg_gen_optimal_table
- JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]));
diff --git a/engine/code/jpeg-6b/jcinit.c b/engine/code/jpeg-6b/jcinit.c
deleted file mode 100644
index 5efffe3..0000000
--- a/engine/code/jpeg-6b/jcinit.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * jcinit.c
- *
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains initialization logic for the JPEG compressor.
- * This routine is in charge of selecting the modules to be executed and
- * making an initialization call to each one.
- *
- * Logically, this code belongs in jcmaster.c. It's split out because
- * linking this routine implies linking the entire compression library.
- * For a transcoding-only application, we want to be able to use jcmaster.c
- * without linking in the whole library.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/*
- * Master selection of compression modules.
- * This is done once at the start of processing an image. We determine
- * which modules will be used and give them appropriate initialization calls.
- */
-
-GLOBAL(void)
-jinit_compress_master (j_compress_ptr cinfo)
-{
- /* Initialize master control (includes parameter checking/processing) */
- jinit_c_master_control(cinfo, FALSE /* full compression */);
-
- /* Preprocessing */
- if (! cinfo->raw_data_in) {
- jinit_color_converter(cinfo);
- jinit_downsampler(cinfo);
- jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */);
- }
- /* Forward DCT */
- jinit_forward_dct(cinfo);
- /* Entropy encoding: either Huffman or arithmetic coding. */
- if (cinfo->arith_code) {
- ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
- } else {
- if (cinfo->progressive_mode) {
-#ifdef C_PROGRESSIVE_SUPPORTED
- jinit_phuff_encoder(cinfo);
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- } else
- jinit_huff_encoder(cinfo);
- }
-
- /* Need a full-image coefficient buffer in any multi-pass mode. */
- jinit_c_coef_controller(cinfo,
- (boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding));
- jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);
-
- jinit_marker_writer(cinfo);
-
- /* We can now tell the memory manager to allocate virtual arrays. */
- (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
-
- /* Write the datastream header (SOI) immediately.
- * Frame and scan headers are postponed till later.
- * This lets application insert special markers after the SOI.
- */
- (*cinfo->marker->write_file_header) (cinfo);
-}
diff --git a/engine/code/jpeg-6b/jcmainct.c b/engine/code/jpeg-6b/jcmainct.c
deleted file mode 100644
index 03a61a7..0000000
--- a/engine/code/jpeg-6b/jcmainct.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * jcmainct.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains the main buffer controller for compression.
- * The main buffer lies between the pre-processor and the JPEG
- * compressor proper; it holds downsampled data in the JPEG colorspace.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* Note: currently, there is no operating mode in which a full-image buffer
- * is needed at this step. If there were, that mode could not be used with
- * "raw data" input, since this module is bypassed in that case. However,
- * we've left the code here for possible use in special applications.
- */
-#undef FULL_MAIN_BUFFER_SUPPORTED
-
-
-/* Private buffer controller object */
-
-typedef struct {
- struct jpeg_c_main_controller pub; /* public fields */
-
- JDIMENSION cur_iMCU_row; /* number of current iMCU row */
- JDIMENSION rowgroup_ctr; /* counts row groups received in iMCU row */
- boolean suspended; /* remember if we suspended output */
- J_BUF_MODE pass_mode; /* current operating mode */
-
- /* If using just a strip buffer, this points to the entire set of buffers
- * (we allocate one for each component). In the full-image case, this
- * points to the currently accessible strips of the virtual arrays.
- */
- JSAMPARRAY buffer[MAX_COMPONENTS];
-
-#ifdef FULL_MAIN_BUFFER_SUPPORTED
- /* If using full-image storage, this array holds pointers to virtual-array
- * control blocks for each component. Unused if not full-image storage.
- */
- jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
-#endif
-} my_main_controller;
-
-typedef my_main_controller * my_main_ptr;
-
-
-/* Forward declarations */
-METHODDEF(void) process_data_simple_main
- JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
-#ifdef FULL_MAIN_BUFFER_SUPPORTED
-METHODDEF(void) process_data_buffer_main
- JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
-#endif
-
-
-/*
- * Initialize for a processing pass.
- */
-
-METHODDEF(void)
-start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
-{
- my_main_ptr jmain = (my_main_ptr) cinfo->main;
-
- /* Do nothing in raw-data mode. */
- if (cinfo->raw_data_in)
- return;
-
- jmain->cur_iMCU_row = 0; /* initialize counters */
- jmain->rowgroup_ctr = 0;
- jmain->suspended = FALSE;
- jmain->pass_mode = pass_mode; /* save mode for use by process_data */
-
- switch (pass_mode) {
- case JBUF_PASS_THRU:
-#ifdef FULL_MAIN_BUFFER_SUPPORTED
- if (jmain->whole_image[0] != NULL)
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
-#endif
- jmain->pub.process_data = process_data_simple_main;
- break;
-#ifdef FULL_MAIN_BUFFER_SUPPORTED
- case JBUF_SAVE_SOURCE:
- case JBUF_CRANK_DEST:
- case JBUF_SAVE_AND_PASS:
- if (jmain->whole_image[0] == NULL)
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- jmain->pub.process_data = process_data_buffer_main;
- break;
-#endif
- default:
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- break;
- }
-}
-
-
-/*
- * Process some data.
- * This routine handles the simple pass-through mode,
- * where we have only a strip buffer.
- */
-
-METHODDEF(void)
-process_data_simple_main (j_compress_ptr cinfo,
- JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
- JDIMENSION in_rows_avail)
-{
- my_main_ptr jmain = (my_main_ptr) cinfo->main;
-
- while (jmain->cur_iMCU_row < cinfo->total_iMCU_rows) {
- /* Read input data if we haven't filled the jmain buffer yet */
- if (jmain->rowgroup_ctr < DCTSIZE)
- (*cinfo->prep->pre_process_data) (cinfo,
- input_buf, in_row_ctr, in_rows_avail,
- jmain->buffer, &jmain->rowgroup_ctr,
- (JDIMENSION) DCTSIZE);
-
- /* If we don't have a full iMCU row buffered, return to application for
- * more data. Note that preprocessor will always pad to fill the iMCU row
- * at the bottom of the image.
- */
- if (jmain->rowgroup_ctr != DCTSIZE)
- return;
-
- /* Send the completed row to the compressor */
- if (! (*cinfo->coef->compress_data) (cinfo, jmain->buffer)) {
- /* If compressor did not consume the whole row, then we must need to
- * suspend processing and return to the application. In this situation
- * we pretend we didn't yet consume the last input row; otherwise, if
- * it happened to be the last row of the image, the application would
- * think we were done.
- */
- if (! jmain->suspended) {
- (*in_row_ctr)--;
- jmain->suspended = TRUE;
- }
- return;
- }
- /* We did finish the row. Undo our little suspension hack if a previous
- * call suspended; then mark the jmain buffer empty.
- */
- if (jmain->suspended) {
- (*in_row_ctr)++;
- jmain->suspended = FALSE;
- }
- jmain->rowgroup_ctr = 0;
- jmain->cur_iMCU_row++;
- }
-}
-
-
-#ifdef FULL_MAIN_BUFFER_SUPPORTED
-
-/*
- * Process some data.
- * This routine handles all of the modes that use a full-size buffer.
- */
-
-METHODDEF(void)
-process_data_buffer_main (j_compress_ptr cinfo,
- JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
- JDIMENSION in_rows_avail)
-{
- my_main_ptr jmain = (my_main_ptr) cinfo->main;
- int ci;
- jpeg_component_info *compptr;
- boolean writing = (jmain->pass_mode != JBUF_CRANK_DEST);
-
- while (jmain->cur_iMCU_row < cinfo->total_iMCU_rows) {
- /* Realign the virtual buffers if at the start of an iMCU row. */
- if (jmain->rowgroup_ctr == 0) {
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- jmain->buffer[ci] = (*cinfo->mem->access_virt_sarray)
- ((j_common_ptr) cinfo, jmain->whole_image[ci],
- jmain->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE),
- (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing);
- }
- /* In a read pass, pretend we just read some source data. */
- if (! writing) {
- *in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE;
- jmain->rowgroup_ctr = DCTSIZE;
- }
- }
-
- /* If a write pass, read input data until the current iMCU row is full. */
- /* Note: preprocessor will pad if necessary to fill the last iMCU row. */
- if (writing) {
- (*cinfo->prep->pre_process_data) (cinfo,
- input_buf, in_row_ctr, in_rows_avail,
- jmain->buffer, &jmain->rowgroup_ctr,
- (JDIMENSION) DCTSIZE);
- /* Return to application if we need more data to fill the iMCU row. */
- if (jmain->rowgroup_ctr < DCTSIZE)
- return;
- }
-
- /* Emit data, unless this is a sink-only pass. */
- if (jmain->pass_mode != JBUF_SAVE_SOURCE) {
- if (! (*cinfo->coef->compress_data) (cinfo, jmain->buffer)) {
- /* If compressor did not consume the whole row, then we must need to
- * suspend processing and return to the application. In this situation
- * we pretend we didn't yet consume the last input row; otherwise, if
- * it happened to be the last row of the image, the application would
- * think we were done.
- */
- if (! jmain->suspended) {
- (*in_row_ctr)--;
- jmain->suspended = TRUE;
- }
- return;
- }
- /* We did finish the row. Undo our little suspension hack if a previous
- * call suspended; then mark the jmain buffer empty.
- */
- if (jmain->suspended) {
- (*in_row_ctr)++;
- jmain->suspended = FALSE;
- }
- }
-
- /* If get here, we are done with this iMCU row. Mark buffer empty. */
- jmain->rowgroup_ctr = 0;
- jmain->cur_iMCU_row++;
- }
-}
-
-#endif /* FULL_MAIN_BUFFER_SUPPORTED */
-
-
-/*
- * Initialize jmain buffer controller.
- */
-
-GLOBAL(void)
-jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
-{
- my_main_ptr jmain;
- int ci;
- jpeg_component_info *compptr;
-
- jmain = (my_main_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_main_controller));
- cinfo->main = (struct jpeg_c_main_controller *) jmain;
- jmain->pub.start_pass = start_pass_main;
-
- /* We don't need to create a buffer in raw-data mode. */
- if (cinfo->raw_data_in)
- return;
-
- /* Create the buffer. It holds downsampled data, so each component
- * may be of a different size.
- */
- if (need_full_buffer) {
-#ifdef FULL_MAIN_BUFFER_SUPPORTED
- /* Allocate a full-image virtual array for each component */
- /* Note we pad the bottom to a multiple of the iMCU height */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- jmain->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
- compptr->width_in_blocks * DCTSIZE,
- (JDIMENSION) jround_up((long) compptr->height_in_blocks,
- (long) compptr->v_samp_factor) * DCTSIZE,
- (JDIMENSION) (compptr->v_samp_factor * DCTSIZE));
- }
-#else
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
-#endif
- } else {
-#ifdef FULL_MAIN_BUFFER_SUPPORTED
- jmain->whole_image[0] = NULL; /* flag for no virtual arrays */
-#endif
- /* Allocate a strip buffer for each component */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- jmain->buffer[ci] = (*cinfo->mem->alloc_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- compptr->width_in_blocks * DCTSIZE,
- (JDIMENSION) (compptr->v_samp_factor * DCTSIZE));
- }
- }
-}
diff --git a/engine/code/jpeg-6b/jcmarker.c b/engine/code/jpeg-6b/jcmarker.c
deleted file mode 100644
index 3d1e6c6..0000000
--- a/engine/code/jpeg-6b/jcmarker.c
+++ /dev/null
@@ -1,664 +0,0 @@
-/*
- * jcmarker.c
- *
- * Copyright (C) 1991-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains routines to write JPEG datastream markers.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-typedef enum { /* JPEG marker codes */
- M_SOF0 = 0xc0,
- M_SOF1 = 0xc1,
- M_SOF2 = 0xc2,
- M_SOF3 = 0xc3,
-
- M_SOF5 = 0xc5,
- M_SOF6 = 0xc6,
- M_SOF7 = 0xc7,
-
- M_JPG = 0xc8,
- M_SOF9 = 0xc9,
- M_SOF10 = 0xca,
- M_SOF11 = 0xcb,
-
- M_SOF13 = 0xcd,
- M_SOF14 = 0xce,
- M_SOF15 = 0xcf,
-
- M_DHT = 0xc4,
-
- M_DAC = 0xcc,
-
- M_RST0 = 0xd0,
- M_RST1 = 0xd1,
- M_RST2 = 0xd2,
- M_RST3 = 0xd3,
- M_RST4 = 0xd4,
- M_RST5 = 0xd5,
- M_RST6 = 0xd6,
- M_RST7 = 0xd7,
-
- M_SOI = 0xd8,
- M_EOI = 0xd9,
- M_SOS = 0xda,
- M_DQT = 0xdb,
- M_DNL = 0xdc,
- M_DRI = 0xdd,
- M_DHP = 0xde,
- M_EXP = 0xdf,
-
- M_APP0 = 0xe0,
- M_APP1 = 0xe1,
- M_APP2 = 0xe2,
- M_APP3 = 0xe3,
- M_APP4 = 0xe4,
- M_APP5 = 0xe5,
- M_APP6 = 0xe6,
- M_APP7 = 0xe7,
- M_APP8 = 0xe8,
- M_APP9 = 0xe9,
- M_APP10 = 0xea,
- M_APP11 = 0xeb,
- M_APP12 = 0xec,
- M_APP13 = 0xed,
- M_APP14 = 0xee,
- M_APP15 = 0xef,
-
- M_JPG0 = 0xf0,
- M_JPG13 = 0xfd,
- M_COM = 0xfe,
-
- M_TEM = 0x01,
-
- M_ERROR = 0x100
-} JPEG_MARKER;
-
-
-/* Private state */
-
-typedef struct {
- struct jpeg_marker_writer pub; /* public fields */
-
- unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */
-} my_marker_writer;
-
-typedef my_marker_writer * my_marker_ptr;
-
-
-/*
- * Basic output routines.
- *
- * Note that we do not support suspension while writing a marker.
- * Therefore, an application using suspension must ensure that there is
- * enough buffer space for the initial markers (typ. 600-700 bytes) before
- * calling jpeg_start_compress, and enough space to write the trailing EOI
- * (a few bytes) before calling jpeg_finish_compress. Multipass compression
- * modes are not supported at all with suspension, so those two are the only
- * points where markers will be written.
- */
-
-LOCAL(void)
-emit_byte (j_compress_ptr cinfo, int val)
-/* Emit a byte */
-{
- struct jpeg_destination_mgr * dest = cinfo->dest;
-
- *(dest->next_output_byte)++ = (JOCTET) val;
- if (--dest->free_in_buffer == 0) {
- if (! (*dest->empty_output_buffer) (cinfo))
- ERREXIT(cinfo, JERR_CANT_SUSPEND);
- }
-}
-
-
-LOCAL(void)
-emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark)
-/* Emit a marker code */
-{
- emit_byte(cinfo, 0xFF);
- emit_byte(cinfo, (int) mark);
-}
-
-
-LOCAL(void)
-emit_2bytes (j_compress_ptr cinfo, int value)
-/* Emit a 2-byte integer; these are always MSB first in JPEG files */
-{
- emit_byte(cinfo, (value >> 8) & 0xFF);
- emit_byte(cinfo, value & 0xFF);
-}
-
-
-/*
- * Routines to write specific marker types.
- */
-
-LOCAL(int)
-emit_dqt (j_compress_ptr cinfo, int index)
-/* Emit a DQT marker */
-/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */
-{
- JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index];
- int prec;
- int i;
-
- if (qtbl == NULL)
- ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index);
-
- prec = 0;
- for (i = 0; i < DCTSIZE2; i++) {
- if (qtbl->quantval[i] > 255)
- prec = 1;
- }
-
- if (! qtbl->sent_table) {
- emit_marker(cinfo, M_DQT);
-
- emit_2bytes(cinfo, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2);
-
- emit_byte(cinfo, index + (prec<<4));
-
- for (i = 0; i < DCTSIZE2; i++) {
- /* The table entries must be emitted in zigzag order. */
- unsigned int qval = qtbl->quantval[jpeg_natural_order[i]];
- if (prec)
- emit_byte(cinfo, (int) (qval >> 8));
- emit_byte(cinfo, (int) (qval & 0xFF));
- }
-
- qtbl->sent_table = TRUE;
- }
-
- return prec;
-}
-
-
-LOCAL(void)
-emit_dht (j_compress_ptr cinfo, int index, boolean is_ac)
-/* Emit a DHT marker */
-{
- JHUFF_TBL * htbl;
- int length, i;
-
- if (is_ac) {
- htbl = cinfo->ac_huff_tbl_ptrs[index];
- index += 0x10; /* output index has AC bit set */
- } else {
- htbl = cinfo->dc_huff_tbl_ptrs[index];
- }
-
- if (htbl == NULL)
- ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index);
-
- if (! htbl->sent_table) {
- emit_marker(cinfo, M_DHT);
-
- length = 0;
- for (i = 1; i <= 16; i++)
- length += htbl->bits[i];
-
- emit_2bytes(cinfo, length + 2 + 1 + 16);
- emit_byte(cinfo, index);
-
- for (i = 1; i <= 16; i++)
- emit_byte(cinfo, htbl->bits[i]);
-
- for (i = 0; i < length; i++)
- emit_byte(cinfo, htbl->huffval[i]);
-
- htbl->sent_table = TRUE;
- }
-}
-
-
-LOCAL(void)
-emit_dac (j_compress_ptr cinfo)
-/* Emit a DAC marker */
-/* Since the useful info is so small, we want to emit all the tables in */
-/* one DAC marker. Therefore this routine does its own scan of the table. */
-{
-#ifdef C_ARITH_CODING_SUPPORTED
- char dc_in_use[NUM_ARITH_TBLS];
- char ac_in_use[NUM_ARITH_TBLS];
- int length, i;
- jpeg_component_info *compptr;
-
- for (i = 0; i < NUM_ARITH_TBLS; i++)
- dc_in_use[i] = ac_in_use[i] = 0;
-
- for (i = 0; i < cinfo->comps_in_scan; i++) {
- compptr = cinfo->cur_comp_info[i];
- dc_in_use[compptr->dc_tbl_no] = 1;
- ac_in_use[compptr->ac_tbl_no] = 1;
- }
-
- length = 0;
- for (i = 0; i < NUM_ARITH_TBLS; i++)
- length += dc_in_use[i] + ac_in_use[i];
-
- emit_marker(cinfo, M_DAC);
-
- emit_2bytes(cinfo, length*2 + 2);
-
- for (i = 0; i < NUM_ARITH_TBLS; i++) {
- if (dc_in_use[i]) {
- emit_byte(cinfo, i);
- emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4));
- }
- if (ac_in_use[i]) {
- emit_byte(cinfo, i + 0x10);
- emit_byte(cinfo, cinfo->arith_ac_K[i]);
- }
- }
-#endif /* C_ARITH_CODING_SUPPORTED */
-}
-
-
-LOCAL(void)
-emit_dri (j_compress_ptr cinfo)
-/* Emit a DRI marker */
-{
- emit_marker(cinfo, M_DRI);
-
- emit_2bytes(cinfo, 4); /* fixed length */
-
- emit_2bytes(cinfo, (int) cinfo->restart_interval);
-}
-
-
-LOCAL(void)
-emit_sof (j_compress_ptr cinfo, JPEG_MARKER code)
-/* Emit a SOF marker */
-{
- int ci;
- jpeg_component_info *compptr;
-
- emit_marker(cinfo, code);
-
- emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */
-
- /* Make sure image isn't bigger than SOF field can handle */
- if ((long) cinfo->image_height > 65535L ||
- (long) cinfo->image_width > 65535L)
- ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535);
-
- emit_byte(cinfo, cinfo->data_precision);
- emit_2bytes(cinfo, (int) cinfo->image_height);
- emit_2bytes(cinfo, (int) cinfo->image_width);
-
- emit_byte(cinfo, cinfo->num_components);
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- emit_byte(cinfo, compptr->component_id);
- emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor);
- emit_byte(cinfo, compptr->quant_tbl_no);
- }
-}
-
-
-LOCAL(void)
-emit_sos (j_compress_ptr cinfo)
-/* Emit a SOS marker */
-{
- int i, td, ta;
- jpeg_component_info *compptr;
-
- emit_marker(cinfo, M_SOS);
-
- emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */
-
- emit_byte(cinfo, cinfo->comps_in_scan);
-
- for (i = 0; i < cinfo->comps_in_scan; i++) {
- compptr = cinfo->cur_comp_info[i];
- emit_byte(cinfo, compptr->component_id);
- td = compptr->dc_tbl_no;
- ta = compptr->ac_tbl_no;
- if (cinfo->progressive_mode) {
- /* Progressive mode: only DC or only AC tables are used in one scan;
- * furthermore, Huffman coding of DC refinement uses no table at all.
- * We emit 0 for unused field(s); this is recommended by the P&M text
- * but does not seem to be specified in the standard.
- */
- if (cinfo->Ss == 0) {
- ta = 0; /* DC scan */
- if (cinfo->Ah != 0 && !cinfo->arith_code)
- td = 0; /* no DC table either */
- } else {
- td = 0; /* AC scan */
- }
- }
- emit_byte(cinfo, (td << 4) + ta);
- }
-
- emit_byte(cinfo, cinfo->Ss);
- emit_byte(cinfo, cinfo->Se);
- emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al);
-}
-
-
-LOCAL(void)
-emit_jfif_app0 (j_compress_ptr cinfo)
-/* Emit a JFIF-compliant APP0 marker */
-{
- /*
- * Length of APP0 block (2 bytes)
- * Block ID (4 bytes - ASCII "JFIF")
- * Zero byte (1 byte to terminate the ID string)
- * Version Major, Minor (2 bytes - major first)
- * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm)
- * Xdpu (2 bytes - dots per unit horizontal)
- * Ydpu (2 bytes - dots per unit vertical)
- * Thumbnail X size (1 byte)
- * Thumbnail Y size (1 byte)
- */
-
- emit_marker(cinfo, M_APP0);
-
- emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */
-
- emit_byte(cinfo, 0x4A); /* Identifier: ASCII "JFIF" */
- emit_byte(cinfo, 0x46);
- emit_byte(cinfo, 0x49);
- emit_byte(cinfo, 0x46);
- emit_byte(cinfo, 0);
- emit_byte(cinfo, cinfo->JFIF_major_version); /* Version fields */
- emit_byte(cinfo, cinfo->JFIF_minor_version);
- emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */
- emit_2bytes(cinfo, (int) cinfo->X_density);
- emit_2bytes(cinfo, (int) cinfo->Y_density);
- emit_byte(cinfo, 0); /* No thumbnail image */
- emit_byte(cinfo, 0);
-}
-
-
-LOCAL(void)
-emit_adobe_app14 (j_compress_ptr cinfo)
-/* Emit an Adobe APP14 marker */
-{
- /*
- * Length of APP14 block (2 bytes)
- * Block ID (5 bytes - ASCII "Adobe")
- * Version Number (2 bytes - currently 100)
- * Flags0 (2 bytes - currently 0)
- * Flags1 (2 bytes - currently 0)
- * Color transform (1 byte)
- *
- * Although Adobe TN 5116 mentions Version = 101, all the Adobe files
- * now in circulation seem to use Version = 100, so that's what we write.
- *
- * We write the color transform byte as 1 if the JPEG color space is
- * YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with
- * whether the encoder performed a transformation, which is pretty useless.
- */
-
- emit_marker(cinfo, M_APP14);
-
- emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */
-
- emit_byte(cinfo, 0x41); /* Identifier: ASCII "Adobe" */
- emit_byte(cinfo, 0x64);
- emit_byte(cinfo, 0x6F);
- emit_byte(cinfo, 0x62);
- emit_byte(cinfo, 0x65);
- emit_2bytes(cinfo, 100); /* Version */
- emit_2bytes(cinfo, 0); /* Flags0 */
- emit_2bytes(cinfo, 0); /* Flags1 */
- switch (cinfo->jpeg_color_space) {
- case JCS_YCbCr:
- emit_byte(cinfo, 1); /* Color transform = 1 */
- break;
- case JCS_YCCK:
- emit_byte(cinfo, 2); /* Color transform = 2 */
- break;
- default:
- emit_byte(cinfo, 0); /* Color transform = 0 */
- break;
- }
-}
-
-
-/*
- * These routines allow writing an arbitrary marker with parameters.
- * The only intended use is to emit COM or APPn markers after calling
- * write_file_header and before calling write_frame_header.
- * Other uses are not guaranteed to produce desirable results.
- * Counting the parameter bytes properly is the caller's responsibility.
- */
-
-METHODDEF(void)
-write_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen)
-/* Emit an arbitrary marker header */
-{
- if (datalen > (unsigned int) 65533) /* safety check */
- ERREXIT(cinfo, JERR_BAD_LENGTH);
-
- emit_marker(cinfo, (JPEG_MARKER) marker);
-
- emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */
-}
-
-METHODDEF(void)
-write_marker_byte (j_compress_ptr cinfo, int val)
-/* Emit one byte of marker parameters following write_marker_header */
-{
- emit_byte(cinfo, val);
-}
-
-
-/*
- * Write datastream header.
- * This consists of an SOI and optional APPn markers.
- * We recommend use of the JFIF marker, but not the Adobe marker,
- * when using YCbCr or grayscale data. The JFIF marker should NOT
- * be used for any other JPEG colorspace. The Adobe marker is helpful
- * to distinguish RGB, CMYK, and YCCK colorspaces.
- * Note that an application can write additional header markers after
- * jpeg_start_compress returns.
- */
-
-METHODDEF(void)
-write_file_header (j_compress_ptr cinfo)
-{
- my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
-
- emit_marker(cinfo, M_SOI); /* first the SOI */
-
- /* SOI is defined to reset restart interval to 0 */
- marker->last_restart_interval = 0;
-
- if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */
- emit_jfif_app0(cinfo);
- if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */
- emit_adobe_app14(cinfo);
-}
-
-
-/*
- * Write frame header.
- * This consists of DQT and SOFn markers.
- * Note that we do not emit the SOF until we have emitted the DQT(s).
- * This avoids compatibility problems with incorrect implementations that
- * try to error-check the quant table numbers as soon as they see the SOF.
- */
-
-METHODDEF(void)
-write_frame_header (j_compress_ptr cinfo)
-{
- int ci, prec;
- boolean is_baseline;
- jpeg_component_info *compptr;
-
- /* Emit DQT for each quantization table.
- * Note that emit_dqt() suppresses any duplicate tables.
- */
- prec = 0;
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- prec += emit_dqt(cinfo, compptr->quant_tbl_no);
- }
- /* now prec is nonzero iff there are any 16-bit quant tables. */
-
- /* Check for a non-baseline specification.
- * Note we assume that Huffman table numbers won't be changed later.
- */
- if (cinfo->arith_code || cinfo->progressive_mode ||
- cinfo->data_precision != 8) {
- is_baseline = FALSE;
- } else {
- is_baseline = TRUE;
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1)
- is_baseline = FALSE;
- }
- if (prec && is_baseline) {
- is_baseline = FALSE;
- /* If it's baseline except for quantizer size, warn the user */
- TRACEMS(cinfo, 0, JTRC_16BIT_TABLES);
- }
- }
-
- /* Emit the proper SOF marker */
- if (cinfo->arith_code) {
- emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */
- } else {
- if (cinfo->progressive_mode)
- emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */
- else if (is_baseline)
- emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */
- else
- emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */
- }
-}
-
-
-/*
- * Write scan header.
- * This consists of DHT or DAC markers, optional DRI, and SOS.
- * Compressed data will be written following the SOS.
- */
-
-METHODDEF(void)
-write_scan_header (j_compress_ptr cinfo)
-{
- my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
- int i;
- jpeg_component_info *compptr;
-
- if (cinfo->arith_code) {
- /* Emit arith conditioning info. We may have some duplication
- * if the file has multiple scans, but it's so small it's hardly
- * worth worrying about.
- */
- emit_dac(cinfo);
- } else {
- /* Emit Huffman tables.
- * Note that emit_dht() suppresses any duplicate tables.
- */
- for (i = 0; i < cinfo->comps_in_scan; i++) {
- compptr = cinfo->cur_comp_info[i];
- if (cinfo->progressive_mode) {
- /* Progressive mode: only DC or only AC tables are used in one scan */
- if (cinfo->Ss == 0) {
- if (cinfo->Ah == 0) /* DC needs no table for refinement scan */
- emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
- } else {
- emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
- }
- } else {
- /* Sequential mode: need both DC and AC tables */
- emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
- emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
- }
- }
- }
-
- /* Emit DRI if required --- note that DRI value could change for each scan.
- * We avoid wasting space with unnecessary DRIs, however.
- */
- if (cinfo->restart_interval != marker->last_restart_interval) {
- emit_dri(cinfo);
- marker->last_restart_interval = cinfo->restart_interval;
- }
-
- emit_sos(cinfo);
-}
-
-
-/*
- * Write datastream trailer.
- */
-
-METHODDEF(void)
-write_file_trailer (j_compress_ptr cinfo)
-{
- emit_marker(cinfo, M_EOI);
-}
-
-
-/*
- * Write an abbreviated table-specification datastream.
- * This consists of SOI, DQT and DHT tables, and EOI.
- * Any table that is defined and not marked sent_table = TRUE will be
- * emitted. Note that all tables will be marked sent_table = TRUE at exit.
- */
-
-METHODDEF(void)
-write_tables_only (j_compress_ptr cinfo)
-{
- int i;
-
- emit_marker(cinfo, M_SOI);
-
- for (i = 0; i < NUM_QUANT_TBLS; i++) {
- if (cinfo->quant_tbl_ptrs[i] != NULL)
- (void) emit_dqt(cinfo, i);
- }
-
- if (! cinfo->arith_code) {
- for (i = 0; i < NUM_HUFF_TBLS; i++) {
- if (cinfo->dc_huff_tbl_ptrs[i] != NULL)
- emit_dht(cinfo, i, FALSE);
- if (cinfo->ac_huff_tbl_ptrs[i] != NULL)
- emit_dht(cinfo, i, TRUE);
- }
- }
-
- emit_marker(cinfo, M_EOI);
-}
-
-
-/*
- * Initialize the marker writer module.
- */
-
-GLOBAL(void)
-jinit_marker_writer (j_compress_ptr cinfo)
-{
- my_marker_ptr marker;
-
- /* Create the subobject */
- marker = (my_marker_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_marker_writer));
- cinfo->marker = (struct jpeg_marker_writer *) marker;
- /* Initialize method pointers */
- marker->pub.write_file_header = write_file_header;
- marker->pub.write_frame_header = write_frame_header;
- marker->pub.write_scan_header = write_scan_header;
- marker->pub.write_file_trailer = write_file_trailer;
- marker->pub.write_tables_only = write_tables_only;
- marker->pub.write_marker_header = write_marker_header;
- marker->pub.write_marker_byte = write_marker_byte;
- /* Initialize private state */
- marker->last_restart_interval = 0;
-}
diff --git a/engine/code/jpeg-6b/jcmaster.c b/engine/code/jpeg-6b/jcmaster.c
deleted file mode 100644
index aab4020..0000000
--- a/engine/code/jpeg-6b/jcmaster.c
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * jcmaster.c
- *
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains master control logic for the JPEG compressor.
- * These routines are concerned with parameter validation, initial setup,
- * and inter-pass control (determining the number of passes and the work
- * to be done in each pass).
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* Private state */
-
-typedef enum {
- main_pass, /* input data, also do first output step */
- huff_opt_pass, /* Huffman code optimization pass */
- output_pass /* data output pass */
-} c_pass_type;
-
-typedef struct {
- struct jpeg_comp_master pub; /* public fields */
-
- c_pass_type pass_type; /* the type of the current pass */
-
- int pass_number; /* # of passes completed */
- int total_passes; /* total # of passes needed */
-
- int scan_number; /* current index in scan_info[] */
-} my_comp_master;
-
-typedef my_comp_master * my_master_ptr;
-
-
-/*
- * Support routines that do various essential calculations.
- */
-
-LOCAL(void)
-initial_setup (j_compress_ptr cinfo)
-/* Do computations that are needed before master selection phase */
-{
- int ci;
- jpeg_component_info *compptr;
- long samplesperrow;
- JDIMENSION jd_samplesperrow;
-
- /* Sanity check on image dimensions */
- if (cinfo->image_height <= 0 || cinfo->image_width <= 0
- || cinfo->num_components <= 0 || cinfo->input_components <= 0)
- ERREXIT(cinfo, JERR_EMPTY_IMAGE);
-
- /* Make sure image isn't bigger than I can handle */
- if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||
- (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)
- ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
-
- /* Width of an input scanline must be representable as JDIMENSION. */
- samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components;
- jd_samplesperrow = (JDIMENSION) samplesperrow;
- if ((long) jd_samplesperrow != samplesperrow)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
-
- /* For now, precision must match compiled-in value... */
- if (cinfo->data_precision != BITS_IN_JSAMPLE)
- ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
-
- /* Check that number of components won't exceed internal array sizes */
- if (cinfo->num_components > MAX_COMPONENTS)
- ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
- MAX_COMPONENTS);
-
- /* Compute maximum sampling factors; check factor validity */
- cinfo->max_h_samp_factor = 1;
- cinfo->max_v_samp_factor = 1;
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||
- compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
- ERREXIT(cinfo, JERR_BAD_SAMPLING);
- cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,
- compptr->h_samp_factor);
- cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,
- compptr->v_samp_factor);
- }
-
- /* Compute dimensions of components */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* Fill in the correct component_index value; don't rely on application */
- compptr->component_index = ci;
- /* For compression, we never do DCT scaling. */
- compptr->DCT_scaled_size = DCTSIZE;
- /* Size in DCT blocks */
- compptr->width_in_blocks = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
- (long) (cinfo->max_h_samp_factor * DCTSIZE));
- compptr->height_in_blocks = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
- (long) (cinfo->max_v_samp_factor * DCTSIZE));
- /* Size in samples */
- compptr->downsampled_width = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
- (long) cinfo->max_h_samp_factor);
- compptr->downsampled_height = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
- (long) cinfo->max_v_samp_factor);
- /* Mark component needed (this flag isn't actually used for compression) */
- compptr->component_needed = TRUE;
- }
-
- /* Compute number of fully interleaved MCU rows (number of times that
- * main controller will call coefficient controller).
- */
- cinfo->total_iMCU_rows = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_height,
- (long) (cinfo->max_v_samp_factor*DCTSIZE));
-}
-
-
-#ifdef C_MULTISCAN_FILES_SUPPORTED
-
-LOCAL(void)
-validate_script (j_compress_ptr cinfo)
-/* Verify that the scan script in cinfo->scan_info[] is valid; also
- * determine whether it uses progressive JPEG, and set cinfo->progressive_mode.
- */
-{
- const jpeg_scan_info * scanptr;
- int scanno, ncomps, ci, coefi, thisi;
- int Ss, Se, Ah, Al;
- boolean component_sent[MAX_COMPONENTS];
-#ifdef C_PROGRESSIVE_SUPPORTED
- int * last_bitpos_ptr;
- int last_bitpos[MAX_COMPONENTS][DCTSIZE2];
- /* -1 until that coefficient has been seen; then last Al for it */
-#endif
-
- if (cinfo->num_scans <= 0)
- ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0);
-
- /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1;
- * for progressive JPEG, no scan can have this.
- */
- scanptr = cinfo->scan_info;
- if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) {
-#ifdef C_PROGRESSIVE_SUPPORTED
- cinfo->progressive_mode = TRUE;
- last_bitpos_ptr = & last_bitpos[0][0];
- for (ci = 0; ci < cinfo->num_components; ci++)
- for (coefi = 0; coefi < DCTSIZE2; coefi++)
- *last_bitpos_ptr++ = -1;
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- } else {
- cinfo->progressive_mode = FALSE;
- for (ci = 0; ci < cinfo->num_components; ci++)
- component_sent[ci] = FALSE;
- }
-
- for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) {
- /* Validate component indexes */
- ncomps = scanptr->comps_in_scan;
- if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN)
- ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN);
- for (ci = 0; ci < ncomps; ci++) {
- thisi = scanptr->component_index[ci];
- if (thisi < 0 || thisi >= cinfo->num_components)
- ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
- /* Components must appear in SOF order within each scan */
- if (ci > 0 && thisi <= scanptr->component_index[ci-1])
- ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
- }
- /* Validate progression parameters */
- Ss = scanptr->Ss;
- Se = scanptr->Se;
- Ah = scanptr->Ah;
- Al = scanptr->Al;
- if (cinfo->progressive_mode) {
-#ifdef C_PROGRESSIVE_SUPPORTED
- /* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that
- * seems wrong: the upper bound ought to depend on data precision.
- * Perhaps they really meant 0..N+1 for N-bit precision.
- * Here we allow 0..10 for 8-bit data; Al larger than 10 results in
- * out-of-range reconstructed DC values during the first DC scan,
- * which might cause problems for some decoders.
- */
-#if BITS_IN_JSAMPLE == 8
-#define MAX_AH_AL 10
-#else
-#define MAX_AH_AL 13
-#endif
- if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 ||
- Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL)
- ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
- if (Ss == 0) {
- if (Se != 0) /* DC and AC together not OK */
- ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
- } else {
- if (ncomps != 1) /* AC scans must be for only one component */
- ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
- }
- for (ci = 0; ci < ncomps; ci++) {
- last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0];
- if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */
- ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
- for (coefi = Ss; coefi <= Se; coefi++) {
- if (last_bitpos_ptr[coefi] < 0) {
- /* first scan of this coefficient */
- if (Ah != 0)
- ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
- } else {
- /* not first scan */
- if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1)
- ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
- }
- last_bitpos_ptr[coefi] = Al;
- }
- }
-#endif
- } else {
- /* For sequential JPEG, all progression parameters must be these: */
- if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0)
- ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
- /* Make sure components are not sent twice */
- for (ci = 0; ci < ncomps; ci++) {
- thisi = scanptr->component_index[ci];
- if (component_sent[thisi])
- ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
- component_sent[thisi] = TRUE;
- }
- }
- }
-
- /* Now verify that everything got sent. */
- if (cinfo->progressive_mode) {
-#ifdef C_PROGRESSIVE_SUPPORTED
- /* For progressive mode, we only check that at least some DC data
- * got sent for each component; the spec does not require that all bits
- * of all coefficients be transmitted. Would it be wiser to enforce
- * transmission of all coefficient bits??
- */
- for (ci = 0; ci < cinfo->num_components; ci++) {
- if (last_bitpos[ci][0] < 0)
- ERREXIT(cinfo, JERR_MISSING_DATA);
- }
-#endif
- } else {
- for (ci = 0; ci < cinfo->num_components; ci++) {
- if (! component_sent[ci])
- ERREXIT(cinfo, JERR_MISSING_DATA);
- }
- }
-}
-
-#endif /* C_MULTISCAN_FILES_SUPPORTED */
-
-
-LOCAL(void)
-select_scan_parameters (j_compress_ptr cinfo)
-/* Set up the scan parameters for the current scan */
-{
- int ci;
-
-#ifdef C_MULTISCAN_FILES_SUPPORTED
- if (cinfo->scan_info != NULL) {
- /* Prepare for current scan --- the script is already validated */
- my_master_ptr master = (my_master_ptr) cinfo->master;
- const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number;
-
- cinfo->comps_in_scan = scanptr->comps_in_scan;
- for (ci = 0; ci < scanptr->comps_in_scan; ci++) {
- cinfo->cur_comp_info[ci] =
- &cinfo->comp_info[scanptr->component_index[ci]];
- }
- cinfo->Ss = scanptr->Ss;
- cinfo->Se = scanptr->Se;
- cinfo->Ah = scanptr->Ah;
- cinfo->Al = scanptr->Al;
- }
- else
-#endif
- {
- /* Prepare for single sequential-JPEG scan containing all components */
- if (cinfo->num_components > MAX_COMPS_IN_SCAN)
- ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
- MAX_COMPS_IN_SCAN);
- cinfo->comps_in_scan = cinfo->num_components;
- for (ci = 0; ci < cinfo->num_components; ci++) {
- cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci];
- }
- cinfo->Ss = 0;
- cinfo->Se = DCTSIZE2-1;
- cinfo->Ah = 0;
- cinfo->Al = 0;
- }
-}
-
-
-LOCAL(void)
-per_scan_setup (j_compress_ptr cinfo)
-/* Do computations that are needed before processing a JPEG scan */
-/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */
-{
- int ci, mcublks, tmp;
- jpeg_component_info *compptr;
-
- if (cinfo->comps_in_scan == 1) {
-
- /* Noninterleaved (single-component) scan */
- compptr = cinfo->cur_comp_info[0];
-
- /* Overall image size in MCUs */
- cinfo->MCUs_per_row = compptr->width_in_blocks;
- cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
-
- /* For noninterleaved scan, always one block per MCU */
- compptr->MCU_width = 1;
- compptr->MCU_height = 1;
- compptr->MCU_blocks = 1;
- compptr->MCU_sample_width = DCTSIZE;
- compptr->last_col_width = 1;
- /* For noninterleaved scans, it is convenient to define last_row_height
- * as the number of block rows present in the last iMCU row.
- */
- tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
- if (tmp == 0) tmp = compptr->v_samp_factor;
- compptr->last_row_height = tmp;
-
- /* Prepare array describing MCU composition */
- cinfo->blocks_in_MCU = 1;
- cinfo->MCU_membership[0] = 0;
-
- } else {
-
- /* Interleaved (multi-component) scan */
- if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)
- ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,
- MAX_COMPS_IN_SCAN);
-
- /* Overall image size in MCUs */
- cinfo->MCUs_per_row = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_width,
- (long) (cinfo->max_h_samp_factor*DCTSIZE));
- cinfo->MCU_rows_in_scan = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_height,
- (long) (cinfo->max_v_samp_factor*DCTSIZE));
-
- cinfo->blocks_in_MCU = 0;
-
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- /* Sampling factors give # of blocks of component in each MCU */
- compptr->MCU_width = compptr->h_samp_factor;
- compptr->MCU_height = compptr->v_samp_factor;
- compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
- compptr->MCU_sample_width = compptr->MCU_width * DCTSIZE;
- /* Figure number of non-dummy blocks in last MCU column & row */
- tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
- if (tmp == 0) tmp = compptr->MCU_width;
- compptr->last_col_width = tmp;
- tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
- if (tmp == 0) tmp = compptr->MCU_height;
- compptr->last_row_height = tmp;
- /* Prepare array describing MCU composition */
- mcublks = compptr->MCU_blocks;
- if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU)
- ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
- while (mcublks-- > 0) {
- cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
- }
- }
-
- }
-
- /* Convert restart specified in rows to actual MCU count. */
- /* Note that count must fit in 16 bits, so we provide limiting. */
- if (cinfo->restart_in_rows > 0) {
- long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row;
- cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L);
- }
-}
-
-
-/*
- * Per-pass setup.
- * This is called at the beginning of each pass. We determine which modules
- * will be active during this pass and give them appropriate start_pass calls.
- * We also set is_last_pass to indicate whether any more passes will be
- * required.
- */
-
-METHODDEF(void)
-prepare_for_pass (j_compress_ptr cinfo)
-{
- my_master_ptr master = (my_master_ptr) cinfo->master;
-
- switch (master->pass_type) {
- case main_pass:
- /* Initial pass: will collect input data, and do either Huffman
- * optimization or data output for the first scan.
- */
- select_scan_parameters(cinfo);
- per_scan_setup(cinfo);
- if (! cinfo->raw_data_in) {
- (*cinfo->cconvert->start_pass) (cinfo);
- (*cinfo->downsample->start_pass) (cinfo);
- (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU);
- }
- (*cinfo->fdct->start_pass) (cinfo);
- (*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding);
- (*cinfo->coef->start_pass) (cinfo,
- (master->total_passes > 1 ?
- JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
- (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
- if (cinfo->optimize_coding) {
- /* No immediate data output; postpone writing frame/scan headers */
- master->pub.call_pass_startup = FALSE;
- } else {
- /* Will write frame/scan headers at first jpeg_write_scanlines call */
- master->pub.call_pass_startup = TRUE;
- }
- break;
-#ifdef ENTROPY_OPT_SUPPORTED
- case huff_opt_pass:
- /* Do Huffman optimization for a scan after the first one. */
- select_scan_parameters(cinfo);
- per_scan_setup(cinfo);
- if (cinfo->Ss != 0 || cinfo->Ah == 0 || cinfo->arith_code) {
- (*cinfo->entropy->start_pass) (cinfo, TRUE);
- (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
- master->pub.call_pass_startup = FALSE;
- break;
- }
- /* Special case: Huffman DC refinement scans need no Huffman table
- * and therefore we can skip the optimization pass for them.
- */
- master->pass_type = output_pass;
- master->pass_number++;
- /*FALLTHROUGH*/
-#endif
- case output_pass:
- /* Do a data-output pass. */
- /* We need not repeat per-scan setup if prior optimization pass did it. */
- if (! cinfo->optimize_coding) {
- select_scan_parameters(cinfo);
- per_scan_setup(cinfo);
- }
- (*cinfo->entropy->start_pass) (cinfo, FALSE);
- (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
- /* We emit frame/scan headers now */
- if (master->scan_number == 0)
- (*cinfo->marker->write_frame_header) (cinfo);
- (*cinfo->marker->write_scan_header) (cinfo);
- master->pub.call_pass_startup = FALSE;
- break;
- default:
- ERREXIT(cinfo, JERR_NOT_COMPILED);
- }
-
- master->pub.is_last_pass = (master->pass_number == master->total_passes-1);
-
- /* Set up progress monitor's pass info if present */
- if (cinfo->progress != NULL) {
- cinfo->progress->completed_passes = master->pass_number;
- cinfo->progress->total_passes = master->total_passes;
- }
-}
-
-
-/*
- * Special start-of-pass hook.
- * This is called by jpeg_write_scanlines if call_pass_startup is TRUE.
- * In single-pass processing, we need this hook because we don't want to
- * write frame/scan headers during jpeg_start_compress; we want to let the
- * application write COM markers etc. between jpeg_start_compress and the
- * jpeg_write_scanlines loop.
- * In multi-pass processing, this routine is not used.
- */
-
-METHODDEF(void)
-pass_startup (j_compress_ptr cinfo)
-{
- cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */
-
- (*cinfo->marker->write_frame_header) (cinfo);
- (*cinfo->marker->write_scan_header) (cinfo);
-}
-
-
-/*
- * Finish up at end of pass.
- */
-
-METHODDEF(void)
-finish_pass_master (j_compress_ptr cinfo)
-{
- my_master_ptr master = (my_master_ptr) cinfo->master;
-
- /* The entropy coder always needs an end-of-pass call,
- * either to analyze statistics or to flush its output buffer.
- */
- (*cinfo->entropy->finish_pass) (cinfo);
-
- /* Update state for next pass */
- switch (master->pass_type) {
- case main_pass:
- /* next pass is either output of scan 0 (after optimization)
- * or output of scan 1 (if no optimization).
- */
- master->pass_type = output_pass;
- if (! cinfo->optimize_coding)
- master->scan_number++;
- break;
- case huff_opt_pass:
- /* next pass is always output of current scan */
- master->pass_type = output_pass;
- break;
- case output_pass:
- /* next pass is either optimization or output of next scan */
- if (cinfo->optimize_coding)
- master->pass_type = huff_opt_pass;
- master->scan_number++;
- break;
- }
-
- master->pass_number++;
-}
-
-
-/*
- * Initialize master compression control.
- */
-
-GLOBAL(void)
-jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
-{
- my_master_ptr master;
-
- master = (my_master_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_comp_master));
- cinfo->master = (struct jpeg_comp_master *) master;
- master->pub.prepare_for_pass = prepare_for_pass;
- master->pub.pass_startup = pass_startup;
- master->pub.finish_pass = finish_pass_master;
- master->pub.is_last_pass = FALSE;
-
- /* Validate parameters, determine derived values */
- initial_setup(cinfo);
-
- if (cinfo->scan_info != NULL) {
-#ifdef C_MULTISCAN_FILES_SUPPORTED
- validate_script(cinfo);
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- } else {
- cinfo->progressive_mode = FALSE;
- cinfo->num_scans = 1;
- }
-
- if (cinfo->progressive_mode) /* TEMPORARY HACK ??? */
- cinfo->optimize_coding = TRUE; /* assume default tables no good for progressive mode */
-
- /* Initialize my private state */
- if (transcode_only) {
- /* no main pass in transcoding */
- if (cinfo->optimize_coding)
- master->pass_type = huff_opt_pass;
- else
- master->pass_type = output_pass;
- } else {
- /* for normal compression, first pass is always this type: */
- master->pass_type = main_pass;
- }
- master->scan_number = 0;
- master->pass_number = 0;
- if (cinfo->optimize_coding)
- master->total_passes = cinfo->num_scans * 2;
- else
- master->total_passes = cinfo->num_scans;
-}
diff --git a/engine/code/jpeg-6b/jcomapi.c b/engine/code/jpeg-6b/jcomapi.c
deleted file mode 100644
index 9b1fa75..0000000
--- a/engine/code/jpeg-6b/jcomapi.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * jcomapi.c
- *
- * Copyright (C) 1994-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains application interface routines that are used for both
- * compression and decompression.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/*
- * Abort processing of a JPEG compression or decompression operation,
- * but don't destroy the object itself.
- *
- * For this, we merely clean up all the nonpermanent memory pools.
- * Note that temp files (virtual arrays) are not allowed to belong to
- * the permanent pool, so we will be able to close all temp files here.
- * Closing a data source or destination, if necessary, is the application's
- * responsibility.
- */
-
-GLOBAL(void)
-jpeg_abort (j_common_ptr cinfo)
-{
- int pool;
-
- /* Do nothing if called on a not-initialized or destroyed JPEG object. */
- if (cinfo->mem == NULL)
- return;
-
- /* Releasing pools in reverse order might help avoid fragmentation
- * with some (brain-damaged) malloc libraries.
- */
- for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) {
- (*cinfo->mem->free_pool) (cinfo, pool);
- }
-
- /* Reset overall state for possible reuse of object */
- if (cinfo->is_decompressor) {
- cinfo->global_state = DSTATE_START;
- /* Try to keep application from accessing now-deleted marker list.
- * A bit kludgy to do it here, but this is the most central place.
- */
- ((j_decompress_ptr) cinfo)->marker_list = NULL;
- } else {
- cinfo->global_state = CSTATE_START;
- }
-}
-
-
-/*
- * Destruction of a JPEG object.
- *
- * Everything gets deallocated except the master jpeg_compress_struct itself
- * and the error manager struct. Both of these are supplied by the application
- * and must be freed, if necessary, by the application. (Often they are on
- * the stack and so don't need to be freed anyway.)
- * Closing a data source or destination, if necessary, is the application's
- * responsibility.
- */
-
-GLOBAL(void)
-jpeg_destroy (j_common_ptr cinfo)
-{
- /* We need only tell the memory manager to release everything. */
- /* NB: mem pointer is NULL if memory mgr failed to initialize. */
- if (cinfo->mem != NULL)
- (*cinfo->mem->self_destruct) (cinfo);
- cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */
- cinfo->global_state = 0; /* mark it destroyed */
-}
-
-
-/*
- * Convenience routines for allocating quantization and Huffman tables.
- * (Would jutils.c be a more reasonable place to put these?)
- */
-
-GLOBAL(JQUANT_TBL *)
-jpeg_alloc_quant_table (j_common_ptr cinfo)
-{
- JQUANT_TBL *tbl;
-
- tbl = (JQUANT_TBL *)
- (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL));
- tbl->sent_table = FALSE; /* make sure this is false in any new table */
- return tbl;
-}
-
-
-GLOBAL(JHUFF_TBL *)
-jpeg_alloc_huff_table (j_common_ptr cinfo)
-{
- JHUFF_TBL *tbl;
-
- tbl = (JHUFF_TBL *)
- (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL));
- tbl->sent_table = FALSE; /* make sure this is false in any new table */
- return tbl;
-}
diff --git a/engine/code/jpeg-6b/jconfig.h b/engine/code/jpeg-6b/jconfig.h
deleted file mode 100644
index 361586e..0000000
--- a/engine/code/jpeg-6b/jconfig.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* jconfig.wat --- jconfig.h for Watcom C/C++ on MS-DOS or OS/2. */
-/* see jconfig.doc for explanations */
-
-#define HAVE_PROTOTYPES
-#define HAVE_UNSIGNED_CHAR
-#define HAVE_UNSIGNED_SHORT
-/* #define void char */
-/* #define const */
-#define CHAR_IS_UNSIGNED
-#define HAVE_STDDEF_H
-#undef NEED_BSD_STRINGS
-#undef NEED_SYS_TYPES_H
-#undef NEED_FAR_POINTERS /* Watcom uses flat 32-bit addressing */
-#undef NEED_SHORT_EXTERNAL_NAMES
-#undef INCOMPLETE_TYPES_BROKEN
-
-#define JDCT_DEFAULT JDCT_FLOAT
-#define JDCT_FASTEST JDCT_FLOAT
-
-#ifdef JPEG_INTERNALS
-
-#undef RIGHT_SHIFT_IS_UNSIGNED
-
-#endif /* JPEG_INTERNALS */
-
-#ifdef JPEG_CJPEG_DJPEG
-
-#define BMP_SUPPORTED /* BMP image file format */
-#define GIF_SUPPORTED /* GIF image file format */
-#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
-#undef RLE_SUPPORTED /* Utah RLE image file format */
-#define TARGA_SUPPORTED /* Targa image file format */
-
-#undef TWO_FILE_COMMANDLINE /* optional */
-#define USE_SETMODE /* Needed to make one-file style work in Watcom */
-#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */
-#undef DONT_USE_B_MODE
-#undef PROGRESS_REPORT /* optional */
-
-#endif /* JPEG_CJPEG_DJPEG */
diff --git a/engine/code/jpeg-6b/jcparam.c b/engine/code/jpeg-6b/jcparam.c
deleted file mode 100644
index 6fc48f5..0000000
--- a/engine/code/jpeg-6b/jcparam.c
+++ /dev/null
@@ -1,610 +0,0 @@
-/*
- * jcparam.c
- *
- * Copyright (C) 1991-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains optional default-setting code for the JPEG compressor.
- * Applications do not have to use this file, but those that don't use it
- * must know a lot more about the innards of the JPEG code.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/*
- * Quantization table setup routines
- */
-
-GLOBAL(void)
-jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
- const unsigned int *basic_table,
- int scale_factor, boolean force_baseline)
-/* Define a quantization table equal to the basic_table times
- * a scale factor (given as a percentage).
- * If force_baseline is TRUE, the computed quantization table entries
- * are limited to 1..255 for JPEG baseline compatibility.
- */
-{
- JQUANT_TBL ** qtblptr;
- int i;
- long temp;
-
- /* Safety check to ensure start_compress not called yet. */
- if (cinfo->global_state != CSTATE_START)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
- if (which_tbl < 0 || which_tbl >= NUM_QUANT_TBLS)
- ERREXIT1(cinfo, JERR_DQT_INDEX, which_tbl);
-
- qtblptr = & cinfo->quant_tbl_ptrs[which_tbl];
-
- if (*qtblptr == NULL)
- *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo);
-
- for (i = 0; i < DCTSIZE2; i++) {
- temp = ((long) basic_table[i] * scale_factor + 50L) / 100L;
- /* limit the values to the valid range */
- if (temp <= 0L) temp = 1L;
- if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */
- if (force_baseline && temp > 255L)
- temp = 255L; /* limit to baseline range if requested */
- (*qtblptr)->quantval[i] = (UINT16) temp;
- }
-
- /* Initialize sent_table FALSE so table will be written to JPEG file. */
- (*qtblptr)->sent_table = FALSE;
-}
-
-
-GLOBAL(void)
-jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor,
- boolean force_baseline)
-/* Set or change the 'quality' (quantization) setting, using default tables
- * and a straight percentage-scaling quality scale. In most cases it's better
- * to use jpeg_set_quality (below); this entry point is provided for
- * applications that insist on a linear percentage scaling.
- */
-{
- /* These are the sample quantization tables given in JPEG spec section K.1.
- * The spec says that the values given produce "good" quality, and
- * when divided by 2, "very good" quality.
- */
- static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
- 16, 11, 10, 16, 24, 40, 51, 61,
- 12, 12, 14, 19, 26, 58, 60, 55,
- 14, 13, 16, 24, 40, 57, 69, 56,
- 14, 17, 22, 29, 51, 87, 80, 62,
- 18, 22, 37, 56, 68, 109, 103, 77,
- 24, 35, 55, 64, 81, 104, 113, 92,
- 49, 64, 78, 87, 103, 121, 120, 101,
- 72, 92, 95, 98, 112, 100, 103, 99
- };
- static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
- 17, 18, 24, 47, 99, 99, 99, 99,
- 18, 21, 26, 66, 99, 99, 99, 99,
- 24, 26, 56, 99, 99, 99, 99, 99,
- 47, 66, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99
- };
-
- /* Set up two quantization tables using the specified scaling */
- jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
- scale_factor, force_baseline);
- jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
- scale_factor, force_baseline);
-}
-
-
-GLOBAL(int)
-jpeg_quality_scaling (int quality)
-/* Convert a user-specified quality rating to a percentage scaling factor
- * for an underlying quantization table, using our recommended scaling curve.
- * The input 'quality' factor should be 0 (terrible) to 100 (very good).
- */
-{
- /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */
- if (quality <= 0) quality = 1;
- if (quality > 100) quality = 100;
-
- /* The basic table is used as-is (scaling 100) for a quality of 50.
- * Qualities 50..100 are converted to scaling percentage 200 - 2*Q;
- * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table
- * to make all the table entries 1 (hence, minimum quantization loss).
- * Qualities 1..50 are converted to scaling percentage 5000/Q.
- */
- if (quality < 50)
- quality = 5000 / quality;
- else
- quality = 200 - quality*2;
-
- return quality;
-}
-
-
-GLOBAL(void)
-jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline)
-/* Set or change the 'quality' (quantization) setting, using default tables.
- * This is the standard quality-adjusting entry point for typical user
- * interfaces; only those who want detailed control over quantization tables
- * would use the preceding three routines directly.
- */
-{
- /* Convert user 0-100 rating to percentage scaling */
- quality = jpeg_quality_scaling(quality);
-
- /* Set up standard quality tables */
- jpeg_set_linear_quality(cinfo, quality, force_baseline);
-}
-
-
-/*
- * Huffman table setup routines
- */
-
-LOCAL(void)
-add_huff_table (j_compress_ptr cinfo,
- JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val)
-/* Define a Huffman table */
-{
- int nsymbols, len;
-
- if (*htblptr == NULL)
- *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
-
- /* Copy the number-of-symbols-of-each-code-length counts */
- MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits));
-
- /* Validate the counts. We do this here mainly so we can copy the right
- * number of symbols from the val[] array, without risking marching off
- * the end of memory. jchuff.c will do a more thorough test later.
- */
- nsymbols = 0;
- for (len = 1; len <= 16; len++)
- nsymbols += bits[len];
- if (nsymbols < 1 || nsymbols > 256)
- ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
-
- MEMCOPY((*htblptr)->huffval, val, nsymbols * SIZEOF(UINT8));
-
- /* Initialize sent_table FALSE so table will be written to JPEG file. */
- (*htblptr)->sent_table = FALSE;
-}
-
-
-LOCAL(void)
-std_huff_tables (j_compress_ptr cinfo)
-/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
-/* IMPORTANT: these are only valid for 8-bit data precision! */
-{
- static const UINT8 bits_dc_luminance[17] =
- { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
- static const UINT8 val_dc_luminance[] =
- { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
-
- static const UINT8 bits_dc_chrominance[17] =
- { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
- static const UINT8 val_dc_chrominance[] =
- { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
-
- static const UINT8 bits_ac_luminance[17] =
- { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
- static const UINT8 val_ac_luminance[] =
- { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
- 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
- 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
- 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
- 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
- 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
- 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
- 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
- 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
- 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
- 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
- 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
- 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
- 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
- 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
- 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
- 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
- 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
- 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
- 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
- 0xf9, 0xfa };
-
- static const UINT8 bits_ac_chrominance[17] =
- { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
- static const UINT8 val_ac_chrominance[] =
- { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
- 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
- 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
- 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
- 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
- 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
- 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
- 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
- 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
- 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
- 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
- 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
- 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
- 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
- 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
- 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
- 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
- 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
- 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
- 0xf9, 0xfa };
-
- add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0],
- bits_dc_luminance, val_dc_luminance);
- add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0],
- bits_ac_luminance, val_ac_luminance);
- add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1],
- bits_dc_chrominance, val_dc_chrominance);
- add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1],
- bits_ac_chrominance, val_ac_chrominance);
-}
-
-
-/*
- * Default parameter setup for compression.
- *
- * Applications that don't choose to use this routine must do their
- * own setup of all these parameters. Alternately, you can call this
- * to establish defaults and then alter parameters selectively. This
- * is the recommended approach since, if we add any new parameters,
- * your code will still work (they'll be set to reasonable defaults).
- */
-
-GLOBAL(void)
-jpeg_set_defaults (j_compress_ptr cinfo)
-{
- int i;
-
- /* Safety check to ensure start_compress not called yet. */
- if (cinfo->global_state != CSTATE_START)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
- /* Allocate comp_info array large enough for maximum component count.
- * Array is made permanent in case application wants to compress
- * multiple images at same param settings.
- */
- if (cinfo->comp_info == NULL)
- cinfo->comp_info = (jpeg_component_info *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- MAX_COMPONENTS * SIZEOF(jpeg_component_info));
-
- /* Initialize everything not dependent on the color space */
-
- cinfo->data_precision = BITS_IN_JSAMPLE;
- /* Set up two quantization tables using default quality of 75 */
- jpeg_set_quality(cinfo, 75, TRUE);
- /* Set up two Huffman tables */
- std_huff_tables(cinfo);
-
- /* Initialize default arithmetic coding conditioning */
- for (i = 0; i < NUM_ARITH_TBLS; i++) {
- cinfo->arith_dc_L[i] = 0;
- cinfo->arith_dc_U[i] = 1;
- cinfo->arith_ac_K[i] = 5;
- }
-
- /* Default is no multiple-scan output */
- cinfo->scan_info = NULL;
- cinfo->num_scans = 0;
-
- /* Expect normal source image, not raw downsampled data */
- cinfo->raw_data_in = FALSE;
-
- /* Use Huffman coding, not arithmetic coding, by default */
- cinfo->arith_code = FALSE;
-
- /* By default, don't do extra passes to optimize entropy coding */
- cinfo->optimize_coding = FALSE;
- /* The standard Huffman tables are only valid for 8-bit data precision.
- * If the precision is higher, force optimization on so that usable
- * tables will be computed. This test can be removed if default tables
- * are supplied that are valid for the desired precision.
- */
- if (cinfo->data_precision > 8)
- cinfo->optimize_coding = TRUE;
-
- /* By default, use the simpler non-cosited sampling alignment */
- cinfo->CCIR601_sampling = FALSE;
-
- /* No input smoothing */
- cinfo->smoothing_factor = 0;
-
- /* DCT algorithm preference */
- cinfo->dct_method = JDCT_DEFAULT;
-
- /* No restart markers */
- cinfo->restart_interval = 0;
- cinfo->restart_in_rows = 0;
-
- /* Fill in default JFIF marker parameters. Note that whether the marker
- * will actually be written is determined by jpeg_set_colorspace.
- *
- * By default, the library emits JFIF version code 1.01.
- * An application that wants to emit JFIF 1.02 extension markers should set
- * JFIF_minor_version to 2. We could probably get away with just defaulting
- * to 1.02, but there may still be some decoders in use that will complain
- * about that; saying 1.01 should minimize compatibility problems.
- */
- cinfo->JFIF_major_version = 1; /* Default JFIF version = 1.01 */
- cinfo->JFIF_minor_version = 1;
- cinfo->density_unit = 0; /* Pixel size is unknown by default */
- cinfo->X_density = 1; /* Pixel aspect ratio is square by default */
- cinfo->Y_density = 1;
-
- /* Choose JPEG colorspace based on input space, set defaults accordingly */
-
- jpeg_default_colorspace(cinfo);
-}
-
-
-/*
- * Select an appropriate JPEG colorspace for in_color_space.
- */
-
-GLOBAL(void)
-jpeg_default_colorspace (j_compress_ptr cinfo)
-{
- switch (cinfo->in_color_space) {
- case JCS_GRAYSCALE:
- jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
- break;
- case JCS_RGB:
- jpeg_set_colorspace(cinfo, JCS_YCbCr);
- break;
- case JCS_YCbCr:
- jpeg_set_colorspace(cinfo, JCS_YCbCr);
- break;
- case JCS_CMYK:
- jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */
- break;
- case JCS_YCCK:
- jpeg_set_colorspace(cinfo, JCS_YCCK);
- break;
- case JCS_UNKNOWN:
- jpeg_set_colorspace(cinfo, JCS_UNKNOWN);
- break;
- default:
- ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
- }
-}
-
-
-/*
- * Set the JPEG colorspace, and choose colorspace-dependent default values.
- */
-
-GLOBAL(void)
-jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
-{
- jpeg_component_info * compptr;
- int ci;
-
-#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \
- (compptr = &cinfo->comp_info[index], \
- compptr->component_id = (id), \
- compptr->h_samp_factor = (hsamp), \
- compptr->v_samp_factor = (vsamp), \
- compptr->quant_tbl_no = (quant), \
- compptr->dc_tbl_no = (dctbl), \
- compptr->ac_tbl_no = (actbl) )
-
- /* Safety check to ensure start_compress not called yet. */
- if (cinfo->global_state != CSTATE_START)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
- /* For all colorspaces, we use Q and Huff tables 0 for luminance components,
- * tables 1 for chrominance components.
- */
-
- cinfo->jpeg_color_space = colorspace;
-
- cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */
- cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */
-
- switch (colorspace) {
- case JCS_GRAYSCALE:
- cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */
- cinfo->num_components = 1;
- /* JFIF specifies component ID 1 */
- SET_COMP(0, 1, 1,1, 0, 0,0);
- break;
- case JCS_RGB:
- cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */
- cinfo->num_components = 3;
- SET_COMP(0, 0x52 /* 'R' */, 1,1, 0, 0,0);
- SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0);
- SET_COMP(2, 0x42 /* 'B' */, 1,1, 0, 0,0);
- break;
- case JCS_YCbCr:
- cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */
- cinfo->num_components = 3;
- /* JFIF specifies component IDs 1,2,3 */
- /* We default to 2x2 subsamples of chrominance */
- SET_COMP(0, 1, 2,2, 0, 0,0);
- SET_COMP(1, 2, 1,1, 1, 1,1);
- SET_COMP(2, 3, 1,1, 1, 1,1);
- break;
- case JCS_CMYK:
- cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */
- cinfo->num_components = 4;
- SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0);
- SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0);
- SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0);
- SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0);
- break;
- case JCS_YCCK:
- cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */
- cinfo->num_components = 4;
- SET_COMP(0, 1, 2,2, 0, 0,0);
- SET_COMP(1, 2, 1,1, 1, 1,1);
- SET_COMP(2, 3, 1,1, 1, 1,1);
- SET_COMP(3, 4, 2,2, 0, 0,0);
- break;
- case JCS_UNKNOWN:
- cinfo->num_components = cinfo->input_components;
- if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS)
- ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
- MAX_COMPONENTS);
- for (ci = 0; ci < cinfo->num_components; ci++) {
- SET_COMP(ci, ci, 1,1, 0, 0,0);
- }
- break;
- default:
- ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
- }
-}
-
-
-#ifdef C_PROGRESSIVE_SUPPORTED
-
-LOCAL(jpeg_scan_info *)
-fill_a_scan (jpeg_scan_info * scanptr, int ci,
- int Ss, int Se, int Ah, int Al)
-/* Support routine: generate one scan for specified component */
-{
- scanptr->comps_in_scan = 1;
- scanptr->component_index[0] = ci;
- scanptr->Ss = Ss;
- scanptr->Se = Se;
- scanptr->Ah = Ah;
- scanptr->Al = Al;
- scanptr++;
- return scanptr;
-}
-
-LOCAL(jpeg_scan_info *)
-fill_scans (jpeg_scan_info * scanptr, int ncomps,
- int Ss, int Se, int Ah, int Al)
-/* Support routine: generate one scan for each component */
-{
- int ci;
-
- for (ci = 0; ci < ncomps; ci++) {
- scanptr->comps_in_scan = 1;
- scanptr->component_index[0] = ci;
- scanptr->Ss = Ss;
- scanptr->Se = Se;
- scanptr->Ah = Ah;
- scanptr->Al = Al;
- scanptr++;
- }
- return scanptr;
-}
-
-LOCAL(jpeg_scan_info *)
-fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al)
-/* Support routine: generate interleaved DC scan if possible, else N scans */
-{
- int ci;
-
- if (ncomps <= MAX_COMPS_IN_SCAN) {
- /* Single interleaved DC scan */
- scanptr->comps_in_scan = ncomps;
- for (ci = 0; ci < ncomps; ci++)
- scanptr->component_index[ci] = ci;
- scanptr->Ss = scanptr->Se = 0;
- scanptr->Ah = Ah;
- scanptr->Al = Al;
- scanptr++;
- } else {
- /* Noninterleaved DC scan for each component */
- scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al);
- }
- return scanptr;
-}
-
-
-/*
- * Create a recommended progressive-JPEG script.
- * cinfo->num_components and cinfo->jpeg_color_space must be correct.
- */
-
-GLOBAL(void)
-jpeg_simple_progression (j_compress_ptr cinfo)
-{
- int ncomps = cinfo->num_components;
- int nscans;
- jpeg_scan_info * scanptr;
-
- /* Safety check to ensure start_compress not called yet. */
- if (cinfo->global_state != CSTATE_START)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
- /* Figure space needed for script. Calculation must match code below! */
- if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
- /* Custom script for YCbCr color images. */
- nscans = 10;
- } else {
- /* All-purpose script for other color spaces. */
- if (ncomps > MAX_COMPS_IN_SCAN)
- nscans = 6 * ncomps; /* 2 DC + 4 AC scans per component */
- else
- nscans = 2 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */
- }
-
- /* Allocate space for script.
- * We need to put it in the permanent pool in case the application performs
- * multiple compressions without changing the settings. To avoid a memory
- * leak if jpeg_simple_progression is called repeatedly for the same JPEG
- * object, we try to re-use previously allocated space, and we allocate
- * enough space to handle YCbCr even if initially asked for grayscale.
- */
- if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) {
- cinfo->script_space_size = MAX(nscans, 10);
- cinfo->script_space = (jpeg_scan_info *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- cinfo->script_space_size * SIZEOF(jpeg_scan_info));
- }
- scanptr = cinfo->script_space;
- cinfo->scan_info = scanptr;
- cinfo->num_scans = nscans;
-
- if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
- /* Custom script for YCbCr color images. */
- /* Initial DC scan */
- scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
- /* Initial AC scan: get some luma data out in a hurry */
- scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2);
- /* Chroma data is too small to be worth expending many scans on */
- scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1);
- scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1);
- /* Complete spectral selection for luma AC */
- scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2);
- /* Refine next bit of luma AC */
- scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1);
- /* Finish DC successive approximation */
- scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
- /* Finish AC successive approximation */
- scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0);
- scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0);
- /* Luma bottom bit comes last since it's usually largest scan */
- scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0);
- } else {
- /* All-purpose script for other color spaces. */
- /* Successive approximation first pass */
- scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
- scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2);
- scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2);
- /* Successive approximation second pass */
- scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1);
- /* Successive approximation final pass */
- scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
- scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0);
- }
-}
-
-#endif /* C_PROGRESSIVE_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jcphuff.c b/engine/code/jpeg-6b/jcphuff.c
deleted file mode 100644
index 07f9178..0000000
--- a/engine/code/jpeg-6b/jcphuff.c
+++ /dev/null
@@ -1,833 +0,0 @@
-/*
- * jcphuff.c
- *
- * Copyright (C) 1995-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains Huffman entropy encoding routines for progressive JPEG.
- *
- * We do not support output suspension in this module, since the library
- * currently does not allow multiple-scan files to be written with output
- * suspension.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jchuff.h" /* Declarations shared with jchuff.c */
-
-#ifdef C_PROGRESSIVE_SUPPORTED
-
-/* Expanded entropy encoder object for progressive Huffman encoding. */
-
-typedef struct {
- struct jpeg_entropy_encoder pub; /* public fields */
-
- /* Mode flag: TRUE for optimization, FALSE for actual data output */
- boolean gather_statistics;
-
- /* Bit-level coding status.
- * next_output_byte/free_in_buffer are local copies of cinfo->dest fields.
- */
- JOCTET * next_output_byte; /* => next byte to write in buffer */
- size_t free_in_buffer; /* # of byte spaces remaining in buffer */
- INT32 put_buffer; /* current bit-accumulation buffer */
- int put_bits; /* # of bits now in it */
- j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */
-
- /* Coding status for DC components */
- int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
-
- /* Coding status for AC components */
- int ac_tbl_no; /* the table number of the single component */
- unsigned int EOBRUN; /* run length of EOBs */
- unsigned int BE; /* # of buffered correction bits before MCU */
- char * bit_buffer; /* buffer for correction bits (1 per char) */
- /* packing correction bits tightly would save some space but cost time... */
-
- unsigned int restarts_to_go; /* MCUs left in this restart interval */
- int next_restart_num; /* next restart number to write (0-7) */
-
- /* Pointers to derived tables (these workspaces have image lifespan).
- * Since any one scan codes only DC or only AC, we only need one set
- * of tables, not one for DC and one for AC.
- */
- c_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
-
- /* Statistics tables for optimization; again, one set is enough */
- long * count_ptrs[NUM_HUFF_TBLS];
-} phuff_entropy_encoder;
-
-typedef phuff_entropy_encoder * phuff_entropy_ptr;
-
-/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit
- * buffer can hold. Larger sizes may slightly improve compression, but
- * 1000 is already well into the realm of overkill.
- * The minimum safe size is 64 bits.
- */
-
-#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */
-
-/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
- * We assume that int right shift is unsigned if INT32 right shift is,
- * which should be safe.
- */
-
-#ifdef RIGHT_SHIFT_IS_UNSIGNED
-#define ISHIFT_TEMPS int ishift_temp;
-#define IRIGHT_SHIFT(x,shft) \
- ((ishift_temp = (x)) < 0 ? \
- (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \
- (ishift_temp >> (shft)))
-#else
-#define ISHIFT_TEMPS
-#define IRIGHT_SHIFT(x,shft) ((x) >> (shft))
-#endif
-
-/* Forward declarations */
-METHODDEF(boolean) encode_mcu_DC_first JPP((j_compress_ptr cinfo,
- JBLOCKROW *MCU_data));
-METHODDEF(boolean) encode_mcu_AC_first JPP((j_compress_ptr cinfo,
- JBLOCKROW *MCU_data));
-METHODDEF(boolean) encode_mcu_DC_refine JPP((j_compress_ptr cinfo,
- JBLOCKROW *MCU_data));
-METHODDEF(boolean) encode_mcu_AC_refine JPP((j_compress_ptr cinfo,
- JBLOCKROW *MCU_data));
-METHODDEF(void) finish_pass_phuff JPP((j_compress_ptr cinfo));
-METHODDEF(void) finish_pass_gather_phuff JPP((j_compress_ptr cinfo));
-
-
-/*
- * Initialize for a Huffman-compressed scan using progressive JPEG.
- */
-
-METHODDEF(void)
-start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics)
-{
- phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
- boolean is_DC_band;
- int ci, tbl;
- jpeg_component_info * compptr;
-
- entropy->cinfo = cinfo;
- entropy->gather_statistics = gather_statistics;
-
- is_DC_band = (cinfo->Ss == 0);
-
- /* We assume jcmaster.c already validated the scan parameters. */
-
- /* Select execution routines */
- if (cinfo->Ah == 0) {
- if (is_DC_band)
- entropy->pub.encode_mcu = encode_mcu_DC_first;
- else
- entropy->pub.encode_mcu = encode_mcu_AC_first;
- } else {
- if (is_DC_band)
- entropy->pub.encode_mcu = encode_mcu_DC_refine;
- else {
- entropy->pub.encode_mcu = encode_mcu_AC_refine;
- /* AC refinement needs a correction bit buffer */
- if (entropy->bit_buffer == NULL)
- entropy->bit_buffer = (char *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- MAX_CORR_BITS * SIZEOF(char));
- }
- }
- if (gather_statistics)
- entropy->pub.finish_pass = finish_pass_gather_phuff;
- else
- entropy->pub.finish_pass = finish_pass_phuff;
-
- /* Only DC coefficients may be interleaved, so cinfo->comps_in_scan = 1
- * for AC coefficients.
- */
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- /* Initialize DC predictions to 0 */
- entropy->last_dc_val[ci] = 0;
- /* Get table index */
- if (is_DC_band) {
- if (cinfo->Ah != 0) /* DC refinement needs no table */
- continue;
- tbl = compptr->dc_tbl_no;
- } else {
- entropy->ac_tbl_no = tbl = compptr->ac_tbl_no;
- }
- if (gather_statistics) {
- /* Check for invalid table index */
- /* (make_c_derived_tbl does this in the other path) */
- if (tbl < 0 || tbl >= NUM_HUFF_TBLS)
- ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl);
- /* Allocate and zero the statistics tables */
- /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */
- if (entropy->count_ptrs[tbl] == NULL)
- entropy->count_ptrs[tbl] = (long *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- 257 * SIZEOF(long));
- MEMZERO(entropy->count_ptrs[tbl], 257 * SIZEOF(long));
- } else {
- /* Compute derived values for Huffman table */
- /* We may do this more than once for a table, but it's not expensive */
- jpeg_make_c_derived_tbl(cinfo, is_DC_band, tbl,
- & entropy->derived_tbls[tbl]);
- }
- }
-
- /* Initialize AC stuff */
- entropy->EOBRUN = 0;
- entropy->BE = 0;
-
- /* Initialize bit buffer to empty */
- entropy->put_buffer = 0;
- entropy->put_bits = 0;
-
- /* Initialize restart stuff */
- entropy->restarts_to_go = cinfo->restart_interval;
- entropy->next_restart_num = 0;
-}
-
-
-/* Outputting bytes to the file.
- * NB: these must be called only when actually outputting,
- * that is, entropy->gather_statistics == FALSE.
- */
-
-/* Emit a byte */
-#define emit_byte(entropy,val) \
- { *(entropy)->next_output_byte++ = (JOCTET) (val); \
- if (--(entropy)->free_in_buffer == 0) \
- dump_buffer(entropy); }
-
-
-LOCAL(void)
-dump_buffer (phuff_entropy_ptr entropy)
-/* Empty the output buffer; we do not support suspension in this module. */
-{
- struct jpeg_destination_mgr * dest = entropy->cinfo->dest;
-
- if (! (*dest->empty_output_buffer) (entropy->cinfo))
- ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND);
- /* After a successful buffer dump, must reset buffer pointers */
- entropy->next_output_byte = dest->next_output_byte;
- entropy->free_in_buffer = dest->free_in_buffer;
-}
-
-
-/* Outputting bits to the file */
-
-/* Only the right 24 bits of put_buffer are used; the valid bits are
- * left-justified in this part. At most 16 bits can be passed to emit_bits
- * in one call, and we never retain more than 7 bits in put_buffer
- * between calls, so 24 bits are sufficient.
- */
-
-INLINE
-LOCAL(void)
-emit_bits (phuff_entropy_ptr entropy, unsigned int code, int size)
-/* Emit some bits, unless we are in gather mode */
-{
- /* This routine is heavily used, so it's worth coding tightly. */
- register INT32 put_buffer = (INT32) code;
- register int put_bits = entropy->put_bits;
-
- /* if size is 0, caller used an invalid Huffman table entry */
- if (size == 0)
- ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE);
-
- if (entropy->gather_statistics)
- return; /* do nothing if we're only getting stats */
-
- put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */
-
- put_bits += size; /* new number of bits in buffer */
-
- put_buffer <<= 24 - put_bits; /* align incoming bits */
-
- put_buffer |= entropy->put_buffer; /* and merge with old buffer contents */
-
- while (put_bits >= 8) {
- int c = (int) ((put_buffer >> 16) & 0xFF);
-
- emit_byte(entropy, c);
- if (c == 0xFF) { /* need to stuff a zero byte? */
- emit_byte(entropy, 0);
- }
- put_buffer <<= 8;
- put_bits -= 8;
- }
-
- entropy->put_buffer = put_buffer; /* update variables */
- entropy->put_bits = put_bits;
-}
-
-
-LOCAL(void)
-flush_bits (phuff_entropy_ptr entropy)
-{
- emit_bits(entropy, 0x7F, 7); /* fill any partial byte with ones */
- entropy->put_buffer = 0; /* and reset bit-buffer to empty */
- entropy->put_bits = 0;
-}
-
-
-/*
- * Emit (or just count) a Huffman symbol.
- */
-
-INLINE
-LOCAL(void)
-emit_symbol (phuff_entropy_ptr entropy, int tbl_no, int symbol)
-{
- if (entropy->gather_statistics)
- entropy->count_ptrs[tbl_no][symbol]++;
- else {
- c_derived_tbl * tbl = entropy->derived_tbls[tbl_no];
- emit_bits(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);
- }
-}
-
-
-/*
- * Emit bits from a correction bit buffer.
- */
-
-LOCAL(void)
-emit_buffered_bits (phuff_entropy_ptr entropy, char * bufstart,
- unsigned int nbits)
-{
- if (entropy->gather_statistics)
- return; /* no real work */
-
- while (nbits > 0) {
- emit_bits(entropy, (unsigned int) (*bufstart), 1);
- bufstart++;
- nbits--;
- }
-}
-
-
-/*
- * Emit any pending EOBRUN symbol.
- */
-
-LOCAL(void)
-emit_eobrun (phuff_entropy_ptr entropy)
-{
- register int temp, nbits;
-
- if (entropy->EOBRUN > 0) { /* if there is any pending EOBRUN */
- temp = entropy->EOBRUN;
- nbits = 0;
- while ((temp >>= 1))
- nbits++;
- /* safety check: shouldn't happen given limited correction-bit buffer */
- if (nbits > 14)
- ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE);
-
- emit_symbol(entropy, entropy->ac_tbl_no, nbits << 4);
- if (nbits)
- emit_bits(entropy, entropy->EOBRUN, nbits);
-
- entropy->EOBRUN = 0;
-
- /* Emit any buffered correction bits */
- emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE);
- entropy->BE = 0;
- }
-}
-
-
-/*
- * Emit a restart marker & resynchronize predictions.
- */
-
-LOCAL(void)
-emit_restart (phuff_entropy_ptr entropy, int restart_num)
-{
- int ci;
-
- emit_eobrun(entropy);
-
- if (! entropy->gather_statistics) {
- flush_bits(entropy);
- emit_byte(entropy, 0xFF);
- emit_byte(entropy, JPEG_RST0 + restart_num);
- }
-
- if (entropy->cinfo->Ss == 0) {
- /* Re-initialize DC predictions to 0 */
- for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++)
- entropy->last_dc_val[ci] = 0;
- } else {
- /* Re-initialize all AC-related fields to 0 */
- entropy->EOBRUN = 0;
- entropy->BE = 0;
- }
-}
-
-
-/*
- * MCU encoding for DC initial scan (either spectral selection,
- * or first pass of successive approximation).
- */
-
-METHODDEF(boolean)
-encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
-{
- phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
- register int temp, temp2;
- register int nbits;
- int blkn, ci;
- int Al = cinfo->Al;
- JBLOCKROW block;
- jpeg_component_info * compptr;
- ISHIFT_TEMPS
-
- entropy->next_output_byte = cinfo->dest->next_output_byte;
- entropy->free_in_buffer = cinfo->dest->free_in_buffer;
-
- /* Emit restart marker if needed */
- if (cinfo->restart_interval)
- if (entropy->restarts_to_go == 0)
- emit_restart(entropy, entropy->next_restart_num);
-
- /* Encode the MCU data blocks */
- for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
- block = MCU_data[blkn];
- ci = cinfo->MCU_membership[blkn];
- compptr = cinfo->cur_comp_info[ci];
-
- /* Compute the DC value after the required point transform by Al.
- * This is simply an arithmetic right shift.
- */
- temp2 = IRIGHT_SHIFT((int) ((*block)[0]), Al);
-
- /* DC differences are figured on the point-transformed values. */
- temp = temp2 - entropy->last_dc_val[ci];
- entropy->last_dc_val[ci] = temp2;
-
- /* Encode the DC coefficient difference per section G.1.2.1 */
- temp2 = temp;
- if (temp < 0) {
- temp = -temp; /* temp is abs value of input */
- /* For a negative input, want temp2 = bitwise complement of abs(input) */
- /* This code assumes we are on a two's complement machine */
- temp2--;
- }
-
- /* Find the number of bits needed for the magnitude of the coefficient */
- nbits = 0;
- while (temp) {
- nbits++;
- temp >>= 1;
- }
- /* Check for out-of-range coefficient values.
- * Since we're encoding a difference, the range limit is twice as much.
- */
- if (nbits > MAX_COEF_BITS+1)
- ERREXIT(cinfo, JERR_BAD_DCT_COEF);
-
- /* Count/emit the Huffman-coded symbol for the number of bits */
- emit_symbol(entropy, compptr->dc_tbl_no, nbits);
-
- /* Emit that number of bits of the value, if positive, */
- /* or the complement of its magnitude, if negative. */
- if (nbits) /* emit_bits rejects calls with size 0 */
- emit_bits(entropy, (unsigned int) temp2, nbits);
- }
-
- cinfo->dest->next_output_byte = entropy->next_output_byte;
- cinfo->dest->free_in_buffer = entropy->free_in_buffer;
-
- /* Update restart-interval state too */
- if (cinfo->restart_interval) {
- if (entropy->restarts_to_go == 0) {
- entropy->restarts_to_go = cinfo->restart_interval;
- entropy->next_restart_num++;
- entropy->next_restart_num &= 7;
- }
- entropy->restarts_to_go--;
- }
-
- return TRUE;
-}
-
-
-/*
- * MCU encoding for AC initial scan (either spectral selection,
- * or first pass of successive approximation).
- */
-
-METHODDEF(boolean)
-encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
-{
- phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
- register int temp, temp2;
- register int nbits;
- register int r, k;
- int Se = cinfo->Se;
- int Al = cinfo->Al;
- JBLOCKROW block;
-
- entropy->next_output_byte = cinfo->dest->next_output_byte;
- entropy->free_in_buffer = cinfo->dest->free_in_buffer;
-
- /* Emit restart marker if needed */
- if (cinfo->restart_interval)
- if (entropy->restarts_to_go == 0)
- emit_restart(entropy, entropy->next_restart_num);
-
- /* Encode the MCU data block */
- block = MCU_data[0];
-
- /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */
-
- r = 0; /* r = run length of zeros */
-
- for (k = cinfo->Ss; k <= Se; k++) {
- if ((temp = (*block)[jpeg_natural_order[k]]) == 0) {
- r++;
- continue;
- }
- /* We must apply the point transform by Al. For AC coefficients this
- * is an integer division with rounding towards 0. To do this portably
- * in C, we shift after obtaining the absolute value; so the code is
- * interwoven with finding the abs value (temp) and output bits (temp2).
- */
- if (temp < 0) {
- temp = -temp; /* temp is abs value of input */
- temp >>= Al; /* apply the point transform */
- /* For a negative coef, want temp2 = bitwise complement of abs(coef) */
- temp2 = ~temp;
- } else {
- temp >>= Al; /* apply the point transform */
- temp2 = temp;
- }
- /* Watch out for case that nonzero coef is zero after point transform */
- if (temp == 0) {
- r++;
- continue;
- }
-
- /* Emit any pending EOBRUN */
- if (entropy->EOBRUN > 0)
- emit_eobrun(entropy);
- /* if run length > 15, must emit special run-length-16 codes (0xF0) */
- while (r > 15) {
- emit_symbol(entropy, entropy->ac_tbl_no, 0xF0);
- r -= 16;
- }
-
- /* Find the number of bits needed for the magnitude of the coefficient */
- nbits = 1; /* there must be at least one 1 bit */
- while ((temp >>= 1))
- nbits++;
- /* Check for out-of-range coefficient values */
- if (nbits > MAX_COEF_BITS)
- ERREXIT(cinfo, JERR_BAD_DCT_COEF);
-
- /* Count/emit Huffman symbol for run length / number of bits */
- emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits);
-
- /* Emit that number of bits of the value, if positive, */
- /* or the complement of its magnitude, if negative. */
- emit_bits(entropy, (unsigned int) temp2, nbits);
-
- r = 0; /* reset zero run length */
- }
-
- if (r > 0) { /* If there are trailing zeroes, */
- entropy->EOBRUN++; /* count an EOB */
- if (entropy->EOBRUN == 0x7FFF)
- emit_eobrun(entropy); /* force it out to avoid overflow */
- }
-
- cinfo->dest->next_output_byte = entropy->next_output_byte;
- cinfo->dest->free_in_buffer = entropy->free_in_buffer;
-
- /* Update restart-interval state too */
- if (cinfo->restart_interval) {
- if (entropy->restarts_to_go == 0) {
- entropy->restarts_to_go = cinfo->restart_interval;
- entropy->next_restart_num++;
- entropy->next_restart_num &= 7;
- }
- entropy->restarts_to_go--;
- }
-
- return TRUE;
-}
-
-
-/*
- * MCU encoding for DC successive approximation refinement scan.
- * Note: we assume such scans can be multi-component, although the spec
- * is not very clear on the point.
- */
-
-METHODDEF(boolean)
-encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
-{
- phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
- register int temp;
- int blkn;
- int Al = cinfo->Al;
- JBLOCKROW block;
-
- entropy->next_output_byte = cinfo->dest->next_output_byte;
- entropy->free_in_buffer = cinfo->dest->free_in_buffer;
-
- /* Emit restart marker if needed */
- if (cinfo->restart_interval)
- if (entropy->restarts_to_go == 0)
- emit_restart(entropy, entropy->next_restart_num);
-
- /* Encode the MCU data blocks */
- for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
- block = MCU_data[blkn];
-
- /* We simply emit the Al'th bit of the DC coefficient value. */
- temp = (*block)[0];
- emit_bits(entropy, (unsigned int) (temp >> Al), 1);
- }
-
- cinfo->dest->next_output_byte = entropy->next_output_byte;
- cinfo->dest->free_in_buffer = entropy->free_in_buffer;
-
- /* Update restart-interval state too */
- if (cinfo->restart_interval) {
- if (entropy->restarts_to_go == 0) {
- entropy->restarts_to_go = cinfo->restart_interval;
- entropy->next_restart_num++;
- entropy->next_restart_num &= 7;
- }
- entropy->restarts_to_go--;
- }
-
- return TRUE;
-}
-
-
-/*
- * MCU encoding for AC successive approximation refinement scan.
- */
-
-METHODDEF(boolean)
-encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
-{
- phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
- register int temp;
- register int r, k;
- int EOB;
- char *BR_buffer;
- unsigned int BR;
- int Se = cinfo->Se;
- int Al = cinfo->Al;
- JBLOCKROW block;
- int absvalues[DCTSIZE2];
-
- entropy->next_output_byte = cinfo->dest->next_output_byte;
- entropy->free_in_buffer = cinfo->dest->free_in_buffer;
-
- /* Emit restart marker if needed */
- if (cinfo->restart_interval)
- if (entropy->restarts_to_go == 0)
- emit_restart(entropy, entropy->next_restart_num);
-
- /* Encode the MCU data block */
- block = MCU_data[0];
-
- /* It is convenient to make a pre-pass to determine the transformed
- * coefficients' absolute values and the EOB position.
- */
- EOB = 0;
- for (k = cinfo->Ss; k <= Se; k++) {
- temp = (*block)[jpeg_natural_order[k]];
- /* We must apply the point transform by Al. For AC coefficients this
- * is an integer division with rounding towards 0. To do this portably
- * in C, we shift after obtaining the absolute value.
- */
- if (temp < 0)
- temp = -temp; /* temp is abs value of input */
- temp >>= Al; /* apply the point transform */
- absvalues[k] = temp; /* save abs value for main pass */
- if (temp == 1)
- EOB = k; /* EOB = index of last newly-nonzero coef */
- }
-
- /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */
-
- r = 0; /* r = run length of zeros */
- BR = 0; /* BR = count of buffered bits added now */
- BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */
-
- for (k = cinfo->Ss; k <= Se; k++) {
- if ((temp = absvalues[k]) == 0) {
- r++;
- continue;
- }
-
- /* Emit any required ZRLs, but not if they can be folded into EOB */
- while (r > 15 && k <= EOB) {
- /* emit any pending EOBRUN and the BE correction bits */
- emit_eobrun(entropy);
- /* Emit ZRL */
- emit_symbol(entropy, entropy->ac_tbl_no, 0xF0);
- r -= 16;
- /* Emit buffered correction bits that must be associated with ZRL */
- emit_buffered_bits(entropy, BR_buffer, BR);
- BR_buffer = entropy->bit_buffer; /* BE bits are gone now */
- BR = 0;
- }
-
- /* If the coef was previously nonzero, it only needs a correction bit.
- * NOTE: a straight translation of the spec's figure G.7 would suggest
- * that we also need to test r > 15. But if r > 15, we can only get here
- * if k > EOB, which implies that this coefficient is not 1.
- */
- if (temp > 1) {
- /* The correction bit is the next bit of the absolute value. */
- BR_buffer[BR++] = (char) (temp & 1);
- continue;
- }
-
- /* Emit any pending EOBRUN and the BE correction bits */
- emit_eobrun(entropy);
-
- /* Count/emit Huffman symbol for run length / number of bits */
- emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1);
-
- /* Emit output bit for newly-nonzero coef */
- temp = ((*block)[jpeg_natural_order[k]] < 0) ? 0 : 1;
- emit_bits(entropy, (unsigned int) temp, 1);
-
- /* Emit buffered correction bits that must be associated with this code */
- emit_buffered_bits(entropy, BR_buffer, BR);
- BR_buffer = entropy->bit_buffer; /* BE bits are gone now */
- BR = 0;
- r = 0; /* reset zero run length */
- }
-
- if (r > 0 || BR > 0) { /* If there are trailing zeroes, */
- entropy->EOBRUN++; /* count an EOB */
- entropy->BE += BR; /* concat my correction bits to older ones */
- /* We force out the EOB if we risk either:
- * 1. overflow of the EOB counter;
- * 2. overflow of the correction bit buffer during the next MCU.
- */
- if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1))
- emit_eobrun(entropy);
- }
-
- cinfo->dest->next_output_byte = entropy->next_output_byte;
- cinfo->dest->free_in_buffer = entropy->free_in_buffer;
-
- /* Update restart-interval state too */
- if (cinfo->restart_interval) {
- if (entropy->restarts_to_go == 0) {
- entropy->restarts_to_go = cinfo->restart_interval;
- entropy->next_restart_num++;
- entropy->next_restart_num &= 7;
- }
- entropy->restarts_to_go--;
- }
-
- return TRUE;
-}
-
-
-/*
- * Finish up at the end of a Huffman-compressed progressive scan.
- */
-
-METHODDEF(void)
-finish_pass_phuff (j_compress_ptr cinfo)
-{
- phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
-
- entropy->next_output_byte = cinfo->dest->next_output_byte;
- entropy->free_in_buffer = cinfo->dest->free_in_buffer;
-
- /* Flush out any buffered data */
- emit_eobrun(entropy);
- flush_bits(entropy);
-
- cinfo->dest->next_output_byte = entropy->next_output_byte;
- cinfo->dest->free_in_buffer = entropy->free_in_buffer;
-}
-
-
-/*
- * Finish up a statistics-gathering pass and create the new Huffman tables.
- */
-
-METHODDEF(void)
-finish_pass_gather_phuff (j_compress_ptr cinfo)
-{
- phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
- boolean is_DC_band;
- int ci, tbl;
- jpeg_component_info * compptr;
- JHUFF_TBL **htblptr;
- boolean did[NUM_HUFF_TBLS];
-
- /* Flush out buffered data (all we care about is counting the EOB symbol) */
- emit_eobrun(entropy);
-
- is_DC_band = (cinfo->Ss == 0);
-
- /* It's important not to apply jpeg_gen_optimal_table more than once
- * per table, because it clobbers the input frequency counts!
- */
- MEMZERO(did, SIZEOF(did));
-
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- if (is_DC_band) {
- if (cinfo->Ah != 0) /* DC refinement needs no table */
- continue;
- tbl = compptr->dc_tbl_no;
- } else {
- tbl = compptr->ac_tbl_no;
- }
- if (! did[tbl]) {
- if (is_DC_band)
- htblptr = & cinfo->dc_huff_tbl_ptrs[tbl];
- else
- htblptr = & cinfo->ac_huff_tbl_ptrs[tbl];
- if (*htblptr == NULL)
- *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
- jpeg_gen_optimal_table(cinfo, *htblptr, entropy->count_ptrs[tbl]);
- did[tbl] = TRUE;
- }
- }
-}
-
-
-/*
- * Module initialization routine for progressive Huffman entropy encoding.
- */
-
-GLOBAL(void)
-jinit_phuff_encoder (j_compress_ptr cinfo)
-{
- phuff_entropy_ptr entropy;
- int i;
-
- entropy = (phuff_entropy_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(phuff_entropy_encoder));
- cinfo->entropy = (struct jpeg_entropy_encoder *) entropy;
- entropy->pub.start_pass = start_pass_phuff;
-
- /* Mark tables unallocated */
- for (i = 0; i < NUM_HUFF_TBLS; i++) {
- entropy->derived_tbls[i] = NULL;
- entropy->count_ptrs[i] = NULL;
- }
- entropy->bit_buffer = NULL; /* needed only in AC refinement scan */
-}
-
-#endif /* C_PROGRESSIVE_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jcprepct.c b/engine/code/jpeg-6b/jcprepct.c
deleted file mode 100644
index fa93333..0000000
--- a/engine/code/jpeg-6b/jcprepct.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * jcprepct.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains the compression preprocessing controller.
- * This controller manages the color conversion, downsampling,
- * and edge expansion steps.
- *
- * Most of the complexity here is associated with buffering input rows
- * as required by the downsampler. See the comments at the head of
- * jcsample.c for the downsampler's needs.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* At present, jcsample.c can request context rows only for smoothing.
- * In the future, we might also need context rows for CCIR601 sampling
- * or other more-complex downsampling procedures. The code to support
- * context rows should be compiled only if needed.
- */
-#ifdef INPUT_SMOOTHING_SUPPORTED
-#define CONTEXT_ROWS_SUPPORTED
-#endif
-
-
-/*
- * For the simple (no-context-row) case, we just need to buffer one
- * row group's worth of pixels for the downsampling step. At the bottom of
- * the image, we pad to a full row group by replicating the last pixel row.
- * The downsampler's last output row is then replicated if needed to pad
- * out to a full iMCU row.
- *
- * When providing context rows, we must buffer three row groups' worth of
- * pixels. Three row groups are physically allocated, but the row pointer
- * arrays are made five row groups high, with the extra pointers above and
- * below "wrapping around" to point to the last and first real row groups.
- * This allows the downsampler to access the proper context rows.
- * At the top and bottom of the image, we create dummy context rows by
- * copying the first or last real pixel row. This copying could be avoided
- * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the
- * trouble on the compression side.
- */
-
-
-/* Private buffer controller object */
-
-typedef struct {
- struct jpeg_c_prep_controller pub; /* public fields */
-
- /* Downsampling input buffer. This buffer holds color-converted data
- * until we have enough to do a downsample step.
- */
- JSAMPARRAY color_buf[MAX_COMPONENTS];
-
- JDIMENSION rows_to_go; /* counts rows remaining in source image */
- int next_buf_row; /* index of next row to store in color_buf */
-
-#ifdef CONTEXT_ROWS_SUPPORTED /* only needed for context case */
- int this_row_group; /* starting row index of group to process */
- int next_buf_stop; /* downsample when we reach this index */
-#endif
-} my_prep_controller;
-
-typedef my_prep_controller * my_prep_ptr;
-
-
-/*
- * Initialize for a processing pass.
- */
-
-METHODDEF(void)
-start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
-{
- my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
-
- if (pass_mode != JBUF_PASS_THRU)
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
-
- /* Initialize total-height counter for detecting bottom of image */
- prep->rows_to_go = cinfo->image_height;
- /* Mark the conversion buffer empty */
- prep->next_buf_row = 0;
-#ifdef CONTEXT_ROWS_SUPPORTED
- /* Preset additional state variables for context mode.
- * These aren't used in non-context mode, so we needn't test which mode.
- */
- prep->this_row_group = 0;
- /* Set next_buf_stop to stop after two row groups have been read in. */
- prep->next_buf_stop = 2 * cinfo->max_v_samp_factor;
-#endif
-}
-
-
-/*
- * Expand an image vertically from height input_rows to height output_rows,
- * by duplicating the bottom row.
- */
-
-LOCAL(void)
-expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols,
- int input_rows, int output_rows)
-{
- register int row;
-
- for (row = input_rows; row < output_rows; row++) {
- jcopy_sample_rows(image_data, input_rows-1, image_data, row,
- 1, num_cols);
- }
-}
-
-
-/*
- * Process some data in the simple no-context case.
- *
- * Preprocessor output data is counted in "row groups". A row group
- * is defined to be v_samp_factor sample rows of each component.
- * Downsampling will produce this much data from each max_v_samp_factor
- * input rows.
- */
-
-METHODDEF(void)
-pre_process_data (j_compress_ptr cinfo,
- JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
- JDIMENSION in_rows_avail,
- JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
- JDIMENSION out_row_groups_avail)
-{
- my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
- int numrows, ci;
- JDIMENSION inrows;
- jpeg_component_info * compptr;
-
- while (*in_row_ctr < in_rows_avail &&
- *out_row_group_ctr < out_row_groups_avail) {
- /* Do color conversion to fill the conversion buffer. */
- inrows = in_rows_avail - *in_row_ctr;
- numrows = cinfo->max_v_samp_factor - prep->next_buf_row;
- numrows = (int) MIN((JDIMENSION) numrows, inrows);
- (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
- prep->color_buf,
- (JDIMENSION) prep->next_buf_row,
- numrows);
- *in_row_ctr += numrows;
- prep->next_buf_row += numrows;
- prep->rows_to_go -= numrows;
- /* If at bottom of image, pad to fill the conversion buffer. */
- if (prep->rows_to_go == 0 &&
- prep->next_buf_row < cinfo->max_v_samp_factor) {
- for (ci = 0; ci < cinfo->num_components; ci++) {
- expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
- prep->next_buf_row, cinfo->max_v_samp_factor);
- }
- prep->next_buf_row = cinfo->max_v_samp_factor;
- }
- /* If we've filled the conversion buffer, empty it. */
- if (prep->next_buf_row == cinfo->max_v_samp_factor) {
- (*cinfo->downsample->downsample) (cinfo,
- prep->color_buf, (JDIMENSION) 0,
- output_buf, *out_row_group_ctr);
- prep->next_buf_row = 0;
- (*out_row_group_ctr)++;
- }
- /* If at bottom of image, pad the output to a full iMCU height.
- * Note we assume the caller is providing a one-iMCU-height output buffer!
- */
- if (prep->rows_to_go == 0 &&
- *out_row_group_ctr < out_row_groups_avail) {
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- expand_bottom_edge(output_buf[ci],
- compptr->width_in_blocks * DCTSIZE,
- (int) (*out_row_group_ctr * compptr->v_samp_factor),
- (int) (out_row_groups_avail * compptr->v_samp_factor));
- }
- *out_row_group_ctr = out_row_groups_avail;
- break; /* can exit outer loop without test */
- }
- }
-}
-
-
-#ifdef CONTEXT_ROWS_SUPPORTED
-
-/*
- * Process some data in the context case.
- */
-
-METHODDEF(void)
-pre_process_context (j_compress_ptr cinfo,
- JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
- JDIMENSION in_rows_avail,
- JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
- JDIMENSION out_row_groups_avail)
-{
- my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
- int numrows, ci;
- int buf_height = cinfo->max_v_samp_factor * 3;
- JDIMENSION inrows;
-
- while (*out_row_group_ctr < out_row_groups_avail) {
- if (*in_row_ctr < in_rows_avail) {
- /* Do color conversion to fill the conversion buffer. */
- inrows = in_rows_avail - *in_row_ctr;
- numrows = prep->next_buf_stop - prep->next_buf_row;
- numrows = (int) MIN((JDIMENSION) numrows, inrows);
- (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
- prep->color_buf,
- (JDIMENSION) prep->next_buf_row,
- numrows);
- /* Pad at top of image, if first time through */
- if (prep->rows_to_go == cinfo->image_height) {
- for (ci = 0; ci < cinfo->num_components; ci++) {
- int row;
- for (row = 1; row <= cinfo->max_v_samp_factor; row++) {
- jcopy_sample_rows(prep->color_buf[ci], 0,
- prep->color_buf[ci], -row,
- 1, cinfo->image_width);
- }
- }
- }
- *in_row_ctr += numrows;
- prep->next_buf_row += numrows;
- prep->rows_to_go -= numrows;
- } else {
- /* Return for more data, unless we are at the bottom of the image. */
- if (prep->rows_to_go != 0)
- break;
- /* When at bottom of image, pad to fill the conversion buffer. */
- if (prep->next_buf_row < prep->next_buf_stop) {
- for (ci = 0; ci < cinfo->num_components; ci++) {
- expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
- prep->next_buf_row, prep->next_buf_stop);
- }
- prep->next_buf_row = prep->next_buf_stop;
- }
- }
- /* If we've gotten enough data, downsample a row group. */
- if (prep->next_buf_row == prep->next_buf_stop) {
- (*cinfo->downsample->downsample) (cinfo,
- prep->color_buf,
- (JDIMENSION) prep->this_row_group,
- output_buf, *out_row_group_ctr);
- (*out_row_group_ctr)++;
- /* Advance pointers with wraparound as necessary. */
- prep->this_row_group += cinfo->max_v_samp_factor;
- if (prep->this_row_group >= buf_height)
- prep->this_row_group = 0;
- if (prep->next_buf_row >= buf_height)
- prep->next_buf_row = 0;
- prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor;
- }
- }
-}
-
-
-/*
- * Create the wrapped-around downsampling input buffer needed for context mode.
- */
-
-LOCAL(void)
-create_context_buffer (j_compress_ptr cinfo)
-{
- my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
- int rgroup_height = cinfo->max_v_samp_factor;
- int ci, i;
- jpeg_component_info * compptr;
- JSAMPARRAY true_buffer, fake_buffer;
-
- /* Grab enough space for fake row pointers for all the components;
- * we need five row groups' worth of pointers for each component.
- */
- fake_buffer = (JSAMPARRAY)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (cinfo->num_components * 5 * rgroup_height) *
- SIZEOF(JSAMPROW));
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* Allocate the actual buffer space (3 row groups) for this component.
- * We make the buffer wide enough to allow the downsampler to edge-expand
- * horizontally within the buffer, if it so chooses.
- */
- true_buffer = (*cinfo->mem->alloc_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE *
- cinfo->max_h_samp_factor) / compptr->h_samp_factor),
- (JDIMENSION) (3 * rgroup_height));
- /* Copy true buffer row pointers into the middle of the fake row array */
- MEMCOPY(fake_buffer + rgroup_height, true_buffer,
- 3 * rgroup_height * SIZEOF(JSAMPROW));
- /* Fill in the above and below wraparound pointers */
- for (i = 0; i < rgroup_height; i++) {
- fake_buffer[i] = true_buffer[2 * rgroup_height + i];
- fake_buffer[4 * rgroup_height + i] = true_buffer[i];
- }
- prep->color_buf[ci] = fake_buffer + rgroup_height;
- fake_buffer += 5 * rgroup_height; /* point to space for next component */
- }
-}
-
-#endif /* CONTEXT_ROWS_SUPPORTED */
-
-
-/*
- * Initialize preprocessing controller.
- */
-
-GLOBAL(void)
-jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer)
-{
- my_prep_ptr prep;
- int ci;
- jpeg_component_info * compptr;
-
- if (need_full_buffer) /* safety check */
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
-
- prep = (my_prep_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_prep_controller));
- cinfo->prep = (struct jpeg_c_prep_controller *) prep;
- prep->pub.start_pass = start_pass_prep;
-
- /* Allocate the color conversion buffer.
- * We make the buffer wide enough to allow the downsampler to edge-expand
- * horizontally within the buffer, if it so chooses.
- */
- if (cinfo->downsample->need_context_rows) {
- /* Set up to provide context rows */
-#ifdef CONTEXT_ROWS_SUPPORTED
- prep->pub.pre_process_data = pre_process_context;
- create_context_buffer(cinfo);
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- } else {
- /* No context, just make it tall enough for one row group */
- prep->pub.pre_process_data = pre_process_data;
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- prep->color_buf[ci] = (*cinfo->mem->alloc_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE *
- cinfo->max_h_samp_factor) / compptr->h_samp_factor),
- (JDIMENSION) cinfo->max_v_samp_factor);
- }
- }
-}
diff --git a/engine/code/jpeg-6b/jcsample.c b/engine/code/jpeg-6b/jcsample.c
deleted file mode 100644
index 212ec87..0000000
--- a/engine/code/jpeg-6b/jcsample.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * jcsample.c
- *
- * Copyright (C) 1991-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains downsampling routines.
- *
- * Downsampling input data is counted in "row groups". A row group
- * is defined to be max_v_samp_factor pixel rows of each component,
- * from which the downsampler produces v_samp_factor sample rows.
- * A single row group is processed in each call to the downsampler module.
- *
- * The downsampler is responsible for edge-expansion of its output data
- * to fill an integral number of DCT blocks horizontally. The source buffer
- * may be modified if it is helpful for this purpose (the source buffer is
- * allocated wide enough to correspond to the desired output width).
- * The caller (the prep controller) is responsible for vertical padding.
- *
- * The downsampler may request "context rows" by setting need_context_rows
- * during startup. In this case, the input arrays will contain at least
- * one row group's worth of pixels above and below the passed-in data;
- * the caller will create dummy rows at image top and bottom by replicating
- * the first or last real pixel row.
- *
- * An excellent reference for image resampling is
- * Digital Image Warping, George Wolberg, 1990.
- * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
- *
- * The downsampling algorithm used here is a simple average of the source
- * pixels covered by the output pixel. The hi-falutin sampling literature
- * refers to this as a "box filter". In general the characteristics of a box
- * filter are not very good, but for the specific cases we normally use (1:1
- * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not
- * nearly so bad. If you intend to use other sampling ratios, you'd be well
- * advised to improve this code.
- *
- * A simple input-smoothing capability is provided. This is mainly intended
- * for cleaning up color-dithered GIF input files (if you find it inadequate,
- * we suggest using an external filtering program such as pnmconvol). When
- * enabled, each input pixel P is replaced by a weighted sum of itself and its
- * eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF,
- * where SF = (smoothing_factor / 1024).
- * Currently, smoothing is only supported for 2h2v sampling factors.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* Pointer to routine to downsample a single component */
-typedef JMETHOD(void, downsample1_ptr,
- (j_compress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data));
-
-/* Private subobject */
-
-typedef struct {
- struct jpeg_downsampler pub; /* public fields */
-
- /* Downsampling method pointers, one per component */
- downsample1_ptr methods[MAX_COMPONENTS];
-} my_downsampler;
-
-typedef my_downsampler * my_downsample_ptr;
-
-
-/*
- * Initialize for a downsampling pass.
- */
-
-METHODDEF(void)
-start_pass_downsample (j_compress_ptr cinfo)
-{
- /* no work for now */
-}
-
-
-/*
- * Expand a component horizontally from width input_cols to width output_cols,
- * by duplicating the rightmost samples.
- */
-
-LOCAL(void)
-expand_right_edge (JSAMPARRAY image_data, int num_rows,
- JDIMENSION input_cols, JDIMENSION output_cols)
-{
- register JSAMPROW ptr;
- register JSAMPLE pixval;
- register int count;
- int row;
- int numcols = (int) (output_cols - input_cols);
-
- if (numcols > 0) {
- for (row = 0; row < num_rows; row++) {
- ptr = image_data[row] + input_cols;
- pixval = ptr[-1]; /* don't need GETJSAMPLE() here */
- for (count = numcols; count > 0; count--)
- *ptr++ = pixval;
- }
- }
-}
-
-
-/*
- * Do downsampling for a whole row group (all components).
- *
- * In this version we simply downsample each component independently.
- */
-
-METHODDEF(void)
-sep_downsample (j_compress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION in_row_index,
- JSAMPIMAGE output_buf, JDIMENSION out_row_group_index)
-{
- my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;
- int ci;
- jpeg_component_info * compptr;
- JSAMPARRAY in_ptr, out_ptr;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- in_ptr = input_buf[ci] + in_row_index;
- out_ptr = output_buf[ci] + (out_row_group_index * compptr->v_samp_factor);
- (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr);
- }
-}
-
-
-/*
- * Downsample pixel values of a single component.
- * One row group is processed per call.
- * This version handles arbitrary integral sampling ratios, without smoothing.
- * Note that this version is not actually used for customary sampling ratios.
- */
-
-METHODDEF(void)
-int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
-{
- int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v;
- JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- JSAMPROW inptr, outptr;
- INT32 outvalue;
-
- h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor;
- v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor;
- numpix = h_expand * v_expand;
- numpix2 = numpix/2;
-
- /* Expand input data enough to let all the output samples be generated
- * by the standard loop. Special-casing padded output would be more
- * efficient.
- */
- expand_right_edge(input_data, cinfo->max_v_samp_factor,
- cinfo->image_width, output_cols * h_expand);
-
- inrow = 0;
- for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
- outptr = output_data[outrow];
- for (outcol = 0, outcol_h = 0; outcol < output_cols;
- outcol++, outcol_h += h_expand) {
- outvalue = 0;
- for (v = 0; v < v_expand; v++) {
- inptr = input_data[inrow+v] + outcol_h;
- for (h = 0; h < h_expand; h++) {
- outvalue += (INT32) GETJSAMPLE(*inptr++);
- }
- }
- *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix);
- }
- inrow += v_expand;
- }
-}
-
-
-/*
- * Downsample pixel values of a single component.
- * This version handles the special case of a full-size component,
- * without smoothing.
- */
-
-METHODDEF(void)
-fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
-{
- /* Copy the data */
- jcopy_sample_rows(input_data, 0, output_data, 0,
- cinfo->max_v_samp_factor, cinfo->image_width);
- /* Edge-expand */
- expand_right_edge(output_data, cinfo->max_v_samp_factor,
- cinfo->image_width, compptr->width_in_blocks * DCTSIZE);
-}
-
-
-/*
- * Downsample pixel values of a single component.
- * This version handles the common case of 2:1 horizontal and 1:1 vertical,
- * without smoothing.
- *
- * A note about the "bias" calculations: when rounding fractional values to
- * integer, we do not want to always round 0.5 up to the next integer.
- * If we did that, we'd introduce a noticeable bias towards larger values.
- * Instead, this code is arranged so that 0.5 will be rounded up or down at
- * alternate pixel locations (a simple ordered dither pattern).
- */
-
-METHODDEF(void)
-h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
-{
- int outrow;
- JDIMENSION outcol;
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- register JSAMPROW inptr, outptr;
- register int bias;
-
- /* Expand input data enough to let all the output samples be generated
- * by the standard loop. Special-casing padded output would be more
- * efficient.
- */
- expand_right_edge(input_data, cinfo->max_v_samp_factor,
- cinfo->image_width, output_cols * 2);
-
- for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
- outptr = output_data[outrow];
- inptr = input_data[outrow];
- bias = 0; /* bias = 0,1,0,1,... for successive samples */
- for (outcol = 0; outcol < output_cols; outcol++) {
- *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1])
- + bias) >> 1);
- bias ^= 1; /* 0=>1, 1=>0 */
- inptr += 2;
- }
- }
-}
-
-
-/*
- * Downsample pixel values of a single component.
- * This version handles the standard case of 2:1 horizontal and 2:1 vertical,
- * without smoothing.
- */
-
-METHODDEF(void)
-h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
-{
- int inrow, outrow;
- JDIMENSION outcol;
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- register JSAMPROW inptr0, inptr1, outptr;
- register int bias;
-
- /* Expand input data enough to let all the output samples be generated
- * by the standard loop. Special-casing padded output would be more
- * efficient.
- */
- expand_right_edge(input_data, cinfo->max_v_samp_factor,
- cinfo->image_width, output_cols * 2);
-
- inrow = 0;
- for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
- outptr = output_data[outrow];
- inptr0 = input_data[inrow];
- inptr1 = input_data[inrow+1];
- bias = 1; /* bias = 1,2,1,2,... for successive samples */
- for (outcol = 0; outcol < output_cols; outcol++) {
- *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
- GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1])
- + bias) >> 2);
- bias ^= 3; /* 1=>2, 2=>1 */
- inptr0 += 2; inptr1 += 2;
- }
- inrow += 2;
- }
-}
-
-
-#ifdef INPUT_SMOOTHING_SUPPORTED
-
-/*
- * Downsample pixel values of a single component.
- * This version handles the standard case of 2:1 horizontal and 2:1 vertical,
- * with smoothing. One row of context is required.
- */
-
-METHODDEF(void)
-h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
-{
- int inrow, outrow;
- JDIMENSION colctr;
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
- INT32 membersum, neighsum, memberscale, neighscale;
-
- /* Expand input data enough to let all the output samples be generated
- * by the standard loop. Special-casing padded output would be more
- * efficient.
- */
- expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,
- cinfo->image_width, output_cols * 2);
-
- /* We don't bother to form the individual "smoothed" input pixel values;
- * we can directly compute the output which is the average of the four
- * smoothed values. Each of the four member pixels contributes a fraction
- * (1-8*SF) to its own smoothed image and a fraction SF to each of the three
- * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final
- * output. The four corner-adjacent neighbor pixels contribute a fraction
- * SF to just one smoothed pixel, or SF/4 to the final output; while the
- * eight edge-adjacent neighbors contribute SF to each of two smoothed
- * pixels, or SF/2 overall. In order to use integer arithmetic, these
- * factors are scaled by 2^16 = 65536.
- * Also recall that SF = smoothing_factor / 1024.
- */
-
- memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */
- neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */
-
- inrow = 0;
- for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
- outptr = output_data[outrow];
- inptr0 = input_data[inrow];
- inptr1 = input_data[inrow+1];
- above_ptr = input_data[inrow-1];
- below_ptr = input_data[inrow+2];
-
- /* Special case for first column: pretend column -1 is same as column 0 */
- membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
- GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
- neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
- GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
- GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) +
- GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]);
- neighsum += neighsum;
- neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) +
- GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]);
- membersum = membersum * memberscale + neighsum * neighscale;
- *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
- inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
-
- for (colctr = output_cols - 2; colctr > 0; colctr--) {
- /* sum of pixels directly mapped to this output element */
- membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
- GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
- /* sum of edge-neighbor pixels */
- neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
- GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
- GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) +
- GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]);
- /* The edge-neighbors count twice as much as corner-neighbors */
- neighsum += neighsum;
- /* Add in the corner-neighbors */
- neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) +
- GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]);
- /* form final output scaled up by 2^16 */
- membersum = membersum * memberscale + neighsum * neighscale;
- /* round, descale and output it */
- *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
- inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
- }
-
- /* Special case for last column */
- membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
- GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
- neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
- GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
- GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) +
- GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]);
- neighsum += neighsum;
- neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) +
- GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]);
- membersum = membersum * memberscale + neighsum * neighscale;
- *outptr = (JSAMPLE) ((membersum + 32768) >> 16);
-
- inrow += 2;
- }
-}
-
-
-/*
- * Downsample pixel values of a single component.
- * This version handles the special case of a full-size component,
- * with smoothing. One row of context is required.
- */
-
-METHODDEF(void)
-fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
-{
- int outrow;
- JDIMENSION colctr;
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- register JSAMPROW inptr, above_ptr, below_ptr, outptr;
- INT32 membersum, neighsum, memberscale, neighscale;
- int colsum, lastcolsum, nextcolsum;
-
- /* Expand input data enough to let all the output samples be generated
- * by the standard loop. Special-casing padded output would be more
- * efficient.
- */
- expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,
- cinfo->image_width, output_cols);
-
- /* Each of the eight neighbor pixels contributes a fraction SF to the
- * smoothed pixel, while the main pixel contributes (1-8*SF). In order
- * to use integer arithmetic, these factors are multiplied by 2^16 = 65536.
- * Also recall that SF = smoothing_factor / 1024.
- */
-
- memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */
- neighscale = cinfo->smoothing_factor * 64; /* scaled SF */
-
- for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
- outptr = output_data[outrow];
- inptr = input_data[outrow];
- above_ptr = input_data[outrow-1];
- below_ptr = input_data[outrow+1];
-
- /* Special case for first column */
- colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) +
- GETJSAMPLE(*inptr);
- membersum = GETJSAMPLE(*inptr++);
- nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
- GETJSAMPLE(*inptr);
- neighsum = colsum + (colsum - membersum) + nextcolsum;
- membersum = membersum * memberscale + neighsum * neighscale;
- *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
- lastcolsum = colsum; colsum = nextcolsum;
-
- for (colctr = output_cols - 2; colctr > 0; colctr--) {
- membersum = GETJSAMPLE(*inptr++);
- above_ptr++; below_ptr++;
- nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
- GETJSAMPLE(*inptr);
- neighsum = lastcolsum + (colsum - membersum) + nextcolsum;
- membersum = membersum * memberscale + neighsum * neighscale;
- *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
- lastcolsum = colsum; colsum = nextcolsum;
- }
-
- /* Special case for last column */
- membersum = GETJSAMPLE(*inptr);
- neighsum = lastcolsum + (colsum - membersum) + colsum;
- membersum = membersum * memberscale + neighsum * neighscale;
- *outptr = (JSAMPLE) ((membersum + 32768) >> 16);
-
- }
-}
-
-#endif /* INPUT_SMOOTHING_SUPPORTED */
-
-
-/*
- * Module initialization routine for downsampling.
- * Note that we must select a routine for each component.
- */
-
-GLOBAL(void)
-jinit_downsampler (j_compress_ptr cinfo)
-{
- my_downsample_ptr downsample;
- int ci;
- jpeg_component_info * compptr;
- boolean smoothok = TRUE;
-
- downsample = (my_downsample_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_downsampler));
- cinfo->downsample = (struct jpeg_downsampler *) downsample;
- downsample->pub.start_pass = start_pass_downsample;
- downsample->pub.downsample = sep_downsample;
- downsample->pub.need_context_rows = FALSE;
-
- if (cinfo->CCIR601_sampling)
- ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
-
- /* Verify we can handle the sampling factors, and set up method pointers */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- if (compptr->h_samp_factor == cinfo->max_h_samp_factor &&
- compptr->v_samp_factor == cinfo->max_v_samp_factor) {
-#ifdef INPUT_SMOOTHING_SUPPORTED
- if (cinfo->smoothing_factor) {
- downsample->methods[ci] = fullsize_smooth_downsample;
- downsample->pub.need_context_rows = TRUE;
- } else
-#endif
- downsample->methods[ci] = fullsize_downsample;
- } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor &&
- compptr->v_samp_factor == cinfo->max_v_samp_factor) {
- smoothok = FALSE;
- downsample->methods[ci] = h2v1_downsample;
- } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor &&
- compptr->v_samp_factor * 2 == cinfo->max_v_samp_factor) {
-#ifdef INPUT_SMOOTHING_SUPPORTED
- if (cinfo->smoothing_factor) {
- downsample->methods[ci] = h2v2_smooth_downsample;
- downsample->pub.need_context_rows = TRUE;
- } else
-#endif
- downsample->methods[ci] = h2v2_downsample;
- } else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 &&
- (cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) {
- smoothok = FALSE;
- downsample->methods[ci] = int_downsample;
- } else
- ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
- }
-
-#ifdef INPUT_SMOOTHING_SUPPORTED
- if (cinfo->smoothing_factor && !smoothok)
- TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL);
-#endif
-}
diff --git a/engine/code/jpeg-6b/jctrans.c b/engine/code/jpeg-6b/jctrans.c
deleted file mode 100644
index 0e6d707..0000000
--- a/engine/code/jpeg-6b/jctrans.c
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * jctrans.c
- *
- * Copyright (C) 1995-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains library routines for transcoding compression,
- * that is, writing raw DCT coefficient arrays to an output JPEG file.
- * The routines in jcapimin.c will also be needed by a transcoder.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* Forward declarations */
-LOCAL(void) transencode_master_selection
- JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
-LOCAL(void) transencode_coef_controller
- JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
-
-
-/*
- * Compression initialization for writing raw-coefficient data.
- * Before calling this, all parameters and a data destination must be set up.
- * Call jpeg_finish_compress() to actually write the data.
- *
- * The number of passed virtual arrays must match cinfo->num_components.
- * Note that the virtual arrays need not be filled or even realized at
- * the time write_coefficients is called; indeed, if the virtual arrays
- * were requested from this compression object's memory manager, they
- * typically will be realized during this routine and filled afterwards.
- */
-
-GLOBAL(void)
-jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)
-{
- if (cinfo->global_state != CSTATE_START)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- /* Mark all tables to be written */
- jpeg_suppress_tables(cinfo, FALSE);
- /* (Re)initialize error mgr and destination modules */
- (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
- (*cinfo->dest->init_destination) (cinfo);
- /* Perform master selection of active modules */
- transencode_master_selection(cinfo, coef_arrays);
- /* Wait for jpeg_finish_compress() call */
- cinfo->next_scanline = 0; /* so jpeg_write_marker works */
- cinfo->global_state = CSTATE_WRCOEFS;
-}
-
-
-/*
- * Initialize the compression object with default parameters,
- * then copy from the source object all parameters needed for lossless
- * transcoding. Parameters that can be varied without loss (such as
- * scan script and Huffman optimization) are left in their default states.
- */
-
-GLOBAL(void)
-jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
- j_compress_ptr dstinfo)
-{
- JQUANT_TBL ** qtblptr;
- jpeg_component_info *incomp, *outcomp;
- JQUANT_TBL *c_quant, *slot_quant;
- int tblno, ci, coefi;
-
- /* Safety check to ensure start_compress not called yet. */
- if (dstinfo->global_state != CSTATE_START)
- ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state);
- /* Copy fundamental image dimensions */
- dstinfo->image_width = srcinfo->image_width;
- dstinfo->image_height = srcinfo->image_height;
- dstinfo->input_components = srcinfo->num_components;
- dstinfo->in_color_space = srcinfo->jpeg_color_space;
- /* Initialize all parameters to default values */
- jpeg_set_defaults(dstinfo);
- /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB.
- * Fix it to get the right header markers for the image colorspace.
- */
- jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space);
- dstinfo->data_precision = srcinfo->data_precision;
- dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling;
- /* Copy the source's quantization tables. */
- for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
- if (srcinfo->quant_tbl_ptrs[tblno] != NULL) {
- qtblptr = & dstinfo->quant_tbl_ptrs[tblno];
- if (*qtblptr == NULL)
- *qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo);
- MEMCOPY((*qtblptr)->quantval,
- srcinfo->quant_tbl_ptrs[tblno]->quantval,
- SIZEOF((*qtblptr)->quantval));
- (*qtblptr)->sent_table = FALSE;
- }
- }
- /* Copy the source's per-component info.
- * Note we assume jpeg_set_defaults has allocated the dest comp_info array.
- */
- dstinfo->num_components = srcinfo->num_components;
- if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS)
- ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components,
- MAX_COMPONENTS);
- for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info;
- ci < dstinfo->num_components; ci++, incomp++, outcomp++) {
- outcomp->component_id = incomp->component_id;
- outcomp->h_samp_factor = incomp->h_samp_factor;
- outcomp->v_samp_factor = incomp->v_samp_factor;
- outcomp->quant_tbl_no = incomp->quant_tbl_no;
- /* Make sure saved quantization table for component matches the qtable
- * slot. If not, the input file re-used this qtable slot.
- * IJG encoder currently cannot duplicate this.
- */
- tblno = outcomp->quant_tbl_no;
- if (tblno < 0 || tblno >= NUM_QUANT_TBLS ||
- srcinfo->quant_tbl_ptrs[tblno] == NULL)
- ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno);
- slot_quant = srcinfo->quant_tbl_ptrs[tblno];
- c_quant = incomp->quant_table;
- if (c_quant != NULL) {
- for (coefi = 0; coefi < DCTSIZE2; coefi++) {
- if (c_quant->quantval[coefi] != slot_quant->quantval[coefi])
- ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno);
- }
- }
- /* Note: we do not copy the source's Huffman table assignments;
- * instead we rely on jpeg_set_colorspace to have made a suitable choice.
- */
- }
- /* Also copy JFIF version and resolution information, if available.
- * Strictly speaking this isn't "critical" info, but it's nearly
- * always appropriate to copy it if available. In particular,
- * if the application chooses to copy JFIF 1.02 extension markers from
- * the source file, we need to copy the version to make sure we don't
- * emit a file that has 1.02 extensions but a claimed version of 1.01.
- * We will *not*, however, copy version info from mislabeled "2.01" files.
- */
- if (srcinfo->saw_JFIF_marker) {
- if (srcinfo->JFIF_major_version == 1) {
- dstinfo->JFIF_major_version = srcinfo->JFIF_major_version;
- dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version;
- }
- dstinfo->density_unit = srcinfo->density_unit;
- dstinfo->X_density = srcinfo->X_density;
- dstinfo->Y_density = srcinfo->Y_density;
- }
-}
-
-
-/*
- * Master selection of compression modules for transcoding.
- * This substitutes for jcinit.c's initialization of the full compressor.
- */
-
-LOCAL(void)
-transencode_master_selection (j_compress_ptr cinfo,
- jvirt_barray_ptr * coef_arrays)
-{
- /* Although we don't actually use input_components for transcoding,
- * jcmaster.c's initial_setup will complain if input_components is 0.
- */
- cinfo->input_components = 1;
- /* Initialize master control (includes parameter checking/processing) */
- jinit_c_master_control(cinfo, TRUE /* transcode only */);
-
- /* Entropy encoding: either Huffman or arithmetic coding. */
- if (cinfo->arith_code) {
- ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
- } else {
- if (cinfo->progressive_mode) {
-#ifdef C_PROGRESSIVE_SUPPORTED
- jinit_phuff_encoder(cinfo);
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- } else
- jinit_huff_encoder(cinfo);
- }
-
- /* We need a special coefficient buffer controller. */
- transencode_coef_controller(cinfo, coef_arrays);
-
- jinit_marker_writer(cinfo);
-
- /* We can now tell the memory manager to allocate virtual arrays. */
- (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
-
- /* Write the datastream header (SOI, JFIF) immediately.
- * Frame and scan headers are postponed till later.
- * This lets application insert special markers after the SOI.
- */
- (*cinfo->marker->write_file_header) (cinfo);
-}
-
-
-/*
- * The rest of this file is a special implementation of the coefficient
- * buffer controller. This is similar to jccoefct.c, but it handles only
- * output from presupplied virtual arrays. Furthermore, we generate any
- * dummy padding blocks on-the-fly rather than expecting them to be present
- * in the arrays.
- */
-
-/* Private buffer controller object */
-
-typedef struct {
- struct jpeg_c_coef_controller pub; /* public fields */
-
- JDIMENSION iMCU_row_num; /* iMCU row # within image */
- JDIMENSION mcu_ctr; /* counts MCUs processed in current row */
- int MCU_vert_offset; /* counts MCU rows within iMCU row */
- int MCU_rows_per_iMCU_row; /* number of such rows needed */
-
- /* Virtual block array for each component. */
- jvirt_barray_ptr * whole_image;
-
- /* Workspace for constructing dummy blocks at right/bottom edges. */
- JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU];
-} my_coef_controller;
-
-typedef my_coef_controller * my_coef_ptr;
-
-
-LOCAL(void)
-start_iMCU_row (j_compress_ptr cinfo)
-/* Reset within-iMCU-row counters for a new row */
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
-
- /* In an interleaved scan, an MCU row is the same as an iMCU row.
- * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
- * But at the bottom of the image, process only what's left.
- */
- if (cinfo->comps_in_scan > 1) {
- coef->MCU_rows_per_iMCU_row = 1;
- } else {
- if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1))
- coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
- else
- coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
- }
-
- coef->mcu_ctr = 0;
- coef->MCU_vert_offset = 0;
-}
-
-
-/*
- * Initialize for a processing pass.
- */
-
-METHODDEF(void)
-start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
-
- if (pass_mode != JBUF_CRANK_DEST)
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
-
- coef->iMCU_row_num = 0;
- start_iMCU_row(cinfo);
-}
-
-
-/*
- * Process some data.
- * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
- * per call, ie, v_samp_factor block rows for each component in the scan.
- * The data is obtained from the virtual arrays and fed to the entropy coder.
- * Returns TRUE if the iMCU row is completed, FALSE if suspended.
- *
- * NB: input_buf is ignored; it is likely to be a NULL pointer.
- */
-
-METHODDEF(boolean)
-compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
- JDIMENSION MCU_col_num; /* index of current MCU within row */
- JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
- JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
- int blkn, ci, xindex, yindex, yoffset, blockcnt;
- JDIMENSION start_col;
- JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
- JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];
- JBLOCKROW buffer_ptr;
- jpeg_component_info *compptr;
-
- /* Align the virtual buffers for the components used in this scan. */
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- buffer[ci] = (*cinfo->mem->access_virt_barray)
- ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
- coef->iMCU_row_num * compptr->v_samp_factor,
- (JDIMENSION) compptr->v_samp_factor, FALSE);
- }
-
- /* Loop to process one whole iMCU row */
- for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
- yoffset++) {
- for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row;
- MCU_col_num++) {
- /* Construct list of pointers to DCT blocks belonging to this MCU */
- blkn = 0; /* index of current DCT block within MCU */
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- start_col = MCU_col_num * compptr->MCU_width;
- blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
- : compptr->last_col_width;
- for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
- if (coef->iMCU_row_num < last_iMCU_row ||
- yindex+yoffset < compptr->last_row_height) {
- /* Fill in pointers to real blocks in this row */
- buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
- for (xindex = 0; xindex < blockcnt; xindex++)
- MCU_buffer[blkn++] = buffer_ptr++;
- } else {
- /* At bottom of image, need a whole row of dummy blocks */
- xindex = 0;
- }
- /* Fill in any dummy blocks needed in this row.
- * Dummy blocks are filled in the same way as in jccoefct.c:
- * all zeroes in the AC entries, DC entries equal to previous
- * block's DC value. The init routine has already zeroed the
- * AC entries, so we need only set the DC entries correctly.
- */
- for (; xindex < compptr->MCU_width; xindex++) {
- MCU_buffer[blkn] = coef->dummy_buffer[blkn];
- MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0];
- blkn++;
- }
- }
- }
- /* Try to write the MCU. */
- if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) {
- /* Suspension forced; update state counters and exit */
- coef->MCU_vert_offset = yoffset;
- coef->mcu_ctr = MCU_col_num;
- return FALSE;
- }
- }
- /* Completed an MCU row, but perhaps not an iMCU row */
- coef->mcu_ctr = 0;
- }
- /* Completed the iMCU row, advance counters for next one */
- coef->iMCU_row_num++;
- start_iMCU_row(cinfo);
- return TRUE;
-}
-
-
-/*
- * Initialize coefficient buffer controller.
- *
- * Each passed coefficient array must be the right size for that
- * coefficient: width_in_blocks wide and height_in_blocks high,
- * with unitheight at least v_samp_factor.
- */
-
-LOCAL(void)
-transencode_coef_controller (j_compress_ptr cinfo,
- jvirt_barray_ptr * coef_arrays)
-{
- my_coef_ptr coef;
- JBLOCKROW buffer;
- int i;
-
- coef = (my_coef_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_coef_controller));
- cinfo->coef = (struct jpeg_c_coef_controller *) coef;
- coef->pub.start_pass = start_pass_coef;
- coef->pub.compress_data = compress_output;
-
- /* Save pointer to virtual arrays */
- coef->whole_image = coef_arrays;
-
- /* Allocate and pre-zero space for dummy DCT blocks. */
- buffer = (JBLOCKROW)
- (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
- jzero_far((void FAR *) buffer, C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
- for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
- coef->dummy_buffer[i] = buffer + i;
- }
-}
diff --git a/engine/code/jpeg-6b/jdapimin.c b/engine/code/jpeg-6b/jdapimin.c
deleted file mode 100644
index cadb59f..0000000
--- a/engine/code/jpeg-6b/jdapimin.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * jdapimin.c
- *
- * Copyright (C) 1994-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains application interface code for the decompression half
- * of the JPEG library. These are the "minimum" API routines that may be
- * needed in either the normal full-decompression case or the
- * transcoding-only case.
- *
- * Most of the routines intended to be called directly by an application
- * are in this file or in jdapistd.c. But also see jcomapi.c for routines
- * shared by compression and decompression, and jdtrans.c for the transcoding
- * case.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/*
- * Initialization of a JPEG decompression object.
- * The error manager must already be set up (in case memory manager fails).
- */
-
-GLOBAL(void)
-jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize)
-{
- int i;
-
- /* Guard against version mismatches between library and caller. */
- cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */
- if (version != JPEG_LIB_VERSION)
- ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
- if (structsize != SIZEOF(struct jpeg_decompress_struct))
- ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE,
- (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize);
-
- /* For debugging purposes, we zero the whole master structure.
- * But the application has already set the err pointer, and may have set
- * client_data, so we have to save and restore those fields.
- * Note: if application hasn't set client_data, tools like Purify may
- * complain here.
- */
- {
- struct jpeg_error_mgr * err = cinfo->err;
- void * client_data = cinfo->client_data; /* ignore Purify complaint here */
- MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct));
- cinfo->err = err;
- cinfo->client_data = client_data;
- }
- cinfo->is_decompressor = TRUE;
-
- /* Initialize a memory manager instance for this object */
- jinit_memory_mgr((j_common_ptr) cinfo);
-
- /* Zero out pointers to permanent structures. */
- cinfo->progress = NULL;
- cinfo->src = NULL;
-
- for (i = 0; i < NUM_QUANT_TBLS; i++)
- cinfo->quant_tbl_ptrs[i] = NULL;
-
- for (i = 0; i < NUM_HUFF_TBLS; i++) {
- cinfo->dc_huff_tbl_ptrs[i] = NULL;
- cinfo->ac_huff_tbl_ptrs[i] = NULL;
- }
-
- /* Initialize marker processor so application can override methods
- * for COM, APPn markers before calling jpeg_read_header.
- */
- cinfo->marker_list = NULL;
- jinit_marker_reader(cinfo);
-
- /* And initialize the overall input controller. */
- jinit_input_controller(cinfo);
-
- /* OK, I'm ready */
- cinfo->global_state = DSTATE_START;
-}
-
-
-/*
- * Destruction of a JPEG decompression object
- */
-
-GLOBAL(void)
-jpeg_destroy_decompress (j_decompress_ptr cinfo)
-{
- jpeg_destroy((j_common_ptr) cinfo); /* use common routine */
-}
-
-
-/*
- * Abort processing of a JPEG decompression operation,
- * but don't destroy the object itself.
- */
-
-GLOBAL(void)
-jpeg_abort_decompress (j_decompress_ptr cinfo)
-{
- jpeg_abort((j_common_ptr) cinfo); /* use common routine */
-}
-
-
-/*
- * Set default decompression parameters.
- */
-
-LOCAL(void)
-default_decompress_parms (j_decompress_ptr cinfo)
-{
- /* Guess the input colorspace, and set output colorspace accordingly. */
- /* (Wish JPEG committee had provided a real way to specify this...) */
- /* Note application may override our guesses. */
- switch (cinfo->num_components) {
- case 1:
- cinfo->jpeg_color_space = JCS_GRAYSCALE;
- cinfo->out_color_space = JCS_GRAYSCALE;
- break;
-
- case 3:
- if (cinfo->saw_JFIF_marker) {
- cinfo->jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */
- } else if (cinfo->saw_Adobe_marker) {
- switch (cinfo->Adobe_transform) {
- case 0:
- cinfo->jpeg_color_space = JCS_RGB;
- break;
- case 1:
- cinfo->jpeg_color_space = JCS_YCbCr;
- break;
- default:
- WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
- cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
- break;
- }
- } else {
- /* Saw no special markers, try to guess from the component IDs */
- int cid0 = cinfo->comp_info[0].component_id;
- int cid1 = cinfo->comp_info[1].component_id;
- int cid2 = cinfo->comp_info[2].component_id;
-
- if (cid0 == 1 && cid1 == 2 && cid2 == 3)
- cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */
- else if (cid0 == 82 && cid1 == 71 && cid2 == 66)
- cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */
- else {
- TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);
- cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
- }
- }
- /* Always guess RGB is proper output colorspace. */
- cinfo->out_color_space = JCS_RGB;
- break;
-
- case 4:
- if (cinfo->saw_Adobe_marker) {
- switch (cinfo->Adobe_transform) {
- case 0:
- cinfo->jpeg_color_space = JCS_CMYK;
- break;
- case 2:
- cinfo->jpeg_color_space = JCS_YCCK;
- break;
- default:
- WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
- cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */
- break;
- }
- } else {
- /* No special markers, assume straight CMYK. */
- cinfo->jpeg_color_space = JCS_CMYK;
- }
- cinfo->out_color_space = JCS_CMYK;
- break;
-
- default:
- cinfo->jpeg_color_space = JCS_UNKNOWN;
- cinfo->out_color_space = JCS_UNKNOWN;
- break;
- }
-
- /* Set defaults for other decompression parameters. */
- cinfo->scale_num = 1; /* 1:1 scaling */
- cinfo->scale_denom = 1;
- cinfo->output_gamma = 1.0;
- cinfo->buffered_image = FALSE;
- cinfo->raw_data_out = FALSE;
- cinfo->dct_method = JDCT_DEFAULT;
- cinfo->do_fancy_upsampling = TRUE;
- cinfo->do_block_smoothing = TRUE;
- cinfo->quantize_colors = FALSE;
- /* We set these in case application only sets quantize_colors. */
- cinfo->dither_mode = JDITHER_FS;
-#ifdef QUANT_2PASS_SUPPORTED
- cinfo->two_pass_quantize = TRUE;
-#else
- cinfo->two_pass_quantize = FALSE;
-#endif
- cinfo->desired_number_of_colors = 256;
- cinfo->colormap = NULL;
- /* Initialize for no mode change in buffered-image mode. */
- cinfo->enable_1pass_quant = FALSE;
- cinfo->enable_external_quant = FALSE;
- cinfo->enable_2pass_quant = FALSE;
-}
-
-
-/*
- * Decompression startup: read start of JPEG datastream to see what's there.
- * Need only initialize JPEG object and supply a data source before calling.
- *
- * This routine will read as far as the first SOS marker (ie, actual start of
- * compressed data), and will save all tables and parameters in the JPEG
- * object. It will also initialize the decompression parameters to default
- * values, and finally return JPEG_HEADER_OK. On return, the application may
- * adjust the decompression parameters and then call jpeg_start_decompress.
- * (Or, if the application only wanted to determine the image parameters,
- * the data need not be decompressed. In that case, call jpeg_abort or
- * jpeg_destroy to release any temporary space.)
- * If an abbreviated (tables only) datastream is presented, the routine will
- * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then
- * re-use the JPEG object to read the abbreviated image datastream(s).
- * It is unnecessary (but OK) to call jpeg_abort in this case.
- * The JPEG_SUSPENDED return code only occurs if the data source module
- * requests suspension of the decompressor. In this case the application
- * should load more source data and then re-call jpeg_read_header to resume
- * processing.
- * If a non-suspending data source is used and require_image is TRUE, then the
- * return code need not be inspected since only JPEG_HEADER_OK is possible.
- *
- * This routine is now just a front end to jpeg_consume_input, with some
- * extra error checking.
- */
-
-GLOBAL(int)
-jpeg_read_header (j_decompress_ptr cinfo, boolean require_image)
-{
- int retcode;
-
- if (cinfo->global_state != DSTATE_START &&
- cinfo->global_state != DSTATE_INHEADER)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
- retcode = jpeg_consume_input(cinfo);
-
- switch (retcode) {
- case JPEG_REACHED_SOS:
- retcode = JPEG_HEADER_OK;
- break;
- case JPEG_REACHED_EOI:
- if (require_image) /* Complain if application wanted an image */
- ERREXIT(cinfo, JERR_NO_IMAGE);
- /* Reset to start state; it would be safer to require the application to
- * call jpeg_abort, but we can't change it now for compatibility reasons.
- * A side effect is to free any temporary memory (there shouldn't be any).
- */
- jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */
- retcode = JPEG_HEADER_TABLES_ONLY;
- break;
- case JPEG_SUSPENDED:
- /* no work */
- break;
- }
-
- return retcode;
-}
-
-
-/*
- * Consume data in advance of what the decompressor requires.
- * This can be called at any time once the decompressor object has
- * been created and a data source has been set up.
- *
- * This routine is essentially a state machine that handles a couple
- * of critical state-transition actions, namely initial setup and
- * transition from header scanning to ready-for-start_decompress.
- * All the actual input is done via the input controller's consume_input
- * method.
- */
-
-GLOBAL(int)
-jpeg_consume_input (j_decompress_ptr cinfo)
-{
- int retcode = JPEG_SUSPENDED;
-
- /* NB: every possible DSTATE value should be listed in this switch */
- switch (cinfo->global_state) {
- case DSTATE_START:
- /* Start-of-datastream actions: reset appropriate modules */
- (*cinfo->inputctl->reset_input_controller) (cinfo);
- /* Initialize application's data source module */
- (*cinfo->src->init_source) (cinfo);
- cinfo->global_state = DSTATE_INHEADER;
- /*FALLTHROUGH*/
- case DSTATE_INHEADER:
- retcode = (*cinfo->inputctl->consume_input) (cinfo);
- if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */
- /* Set up default parameters based on header data */
- default_decompress_parms(cinfo);
- /* Set global state: ready for start_decompress */
- cinfo->global_state = DSTATE_READY;
- }
- break;
- case DSTATE_READY:
- /* Can't advance past first SOS until start_decompress is called */
- retcode = JPEG_REACHED_SOS;
- break;
- case DSTATE_PRELOAD:
- case DSTATE_PRESCAN:
- case DSTATE_SCANNING:
- case DSTATE_RAW_OK:
- case DSTATE_BUFIMAGE:
- case DSTATE_BUFPOST:
- case DSTATE_STOPPING:
- retcode = (*cinfo->inputctl->consume_input) (cinfo);
- break;
- default:
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- }
- return retcode;
-}
-
-
-/*
- * Have we finished reading the input file?
- */
-
-GLOBAL(boolean)
-jpeg_input_complete (j_decompress_ptr cinfo)
-{
- /* Check for valid jpeg object */
- if (cinfo->global_state < DSTATE_START ||
- cinfo->global_state > DSTATE_STOPPING)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- return cinfo->inputctl->eoi_reached;
-}
-
-
-/*
- * Is there more than one scan?
- */
-
-GLOBAL(boolean)
-jpeg_has_multiple_scans (j_decompress_ptr cinfo)
-{
- /* Only valid after jpeg_read_header completes */
- if (cinfo->global_state < DSTATE_READY ||
- cinfo->global_state > DSTATE_STOPPING)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- return cinfo->inputctl->has_multiple_scans;
-}
-
-
-/*
- * Finish JPEG decompression.
- *
- * This will normally just verify the file trailer and release temp storage.
- *
- * Returns FALSE if suspended. The return value need be inspected only if
- * a suspending data source is used.
- */
-
-GLOBAL(boolean)
-jpeg_finish_decompress (j_decompress_ptr cinfo)
-{
- if ((cinfo->global_state == DSTATE_SCANNING ||
- cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) {
- /* Terminate final pass of non-buffered mode */
- if (cinfo->output_scanline < cinfo->output_height)
- ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
- (*cinfo->master->finish_output_pass) (cinfo);
- cinfo->global_state = DSTATE_STOPPING;
- } else if (cinfo->global_state == DSTATE_BUFIMAGE) {
- /* Finishing after a buffered-image operation */
- cinfo->global_state = DSTATE_STOPPING;
- } else if (cinfo->global_state != DSTATE_STOPPING) {
- /* STOPPING = repeat call after a suspension, anything else is error */
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- }
- /* Read until EOI */
- while (! cinfo->inputctl->eoi_reached) {
- if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
- return FALSE; /* Suspend, come back later */
- }
- /* Do final cleanup */
- (*cinfo->src->term_source) (cinfo);
- /* We can use jpeg_abort to release memory and reset global_state */
- jpeg_abort((j_common_ptr) cinfo);
- return TRUE;
-}
diff --git a/engine/code/jpeg-6b/jdapistd.c b/engine/code/jpeg-6b/jdapistd.c
deleted file mode 100644
index c8e3fa0..0000000
--- a/engine/code/jpeg-6b/jdapistd.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * jdapistd.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains application interface code for the decompression half
- * of the JPEG library. These are the "standard" API routines that are
- * used in the normal full-decompression case. They are not used by a
- * transcoding-only application. Note that if an application links in
- * jpeg_start_decompress, it will end up linking in the entire decompressor.
- * We thus must separate this file from jdapimin.c to avoid linking the
- * whole decompression library into a transcoder.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* Forward declarations */
-LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo));
-
-
-/*
- * Decompression initialization.
- * jpeg_read_header must be completed before calling this.
- *
- * If a multipass operating mode was selected, this will do all but the
- * last pass, and thus may take a great deal of time.
- *
- * Returns FALSE if suspended. The return value need be inspected only if
- * a suspending data source is used.
- */
-
-GLOBAL(boolean)
-jpeg_start_decompress (j_decompress_ptr cinfo)
-{
- if (cinfo->global_state == DSTATE_READY) {
- /* First call: initialize master control, select active modules */
- jinit_master_decompress(cinfo);
- if (cinfo->buffered_image) {
- /* No more work here; expecting jpeg_start_output next */
- cinfo->global_state = DSTATE_BUFIMAGE;
- return TRUE;
- }
- cinfo->global_state = DSTATE_PRELOAD;
- }
- if (cinfo->global_state == DSTATE_PRELOAD) {
- /* If file has multiple scans, absorb them all into the coef buffer */
- if (cinfo->inputctl->has_multiple_scans) {
-#ifdef D_MULTISCAN_FILES_SUPPORTED
- for (;;) {
- int retcode;
- /* Call progress monitor hook if present */
- if (cinfo->progress != NULL)
- (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
- /* Absorb some more input */
- retcode = (*cinfo->inputctl->consume_input) (cinfo);
- if (retcode == JPEG_SUSPENDED)
- return FALSE;
- if (retcode == JPEG_REACHED_EOI)
- break;
- /* Advance progress counter if appropriate */
- if (cinfo->progress != NULL &&
- (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
- if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
- /* jdmaster underestimated number of scans; ratchet up one scan */
- cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
- }
- }
- }
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif /* D_MULTISCAN_FILES_SUPPORTED */
- }
- cinfo->output_scan_number = cinfo->input_scan_number;
- } else if (cinfo->global_state != DSTATE_PRESCAN)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- /* Perform any dummy output passes, and set up for the final pass */
- return output_pass_setup(cinfo);
-}
-
-
-/*
- * Set up for an output pass, and perform any dummy pass(es) needed.
- * Common subroutine for jpeg_start_decompress and jpeg_start_output.
- * Entry: global_state = DSTATE_PRESCAN only if previously suspended.
- * Exit: If done, returns TRUE and sets global_state for proper output mode.
- * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN.
- */
-
-LOCAL(boolean)
-output_pass_setup (j_decompress_ptr cinfo)
-{
- if (cinfo->global_state != DSTATE_PRESCAN) {
- /* First call: do pass setup */
- (*cinfo->master->prepare_for_output_pass) (cinfo);
- cinfo->output_scanline = 0;
- cinfo->global_state = DSTATE_PRESCAN;
- }
- /* Loop over any required dummy passes */
- while (cinfo->master->is_dummy_pass) {
-#ifdef QUANT_2PASS_SUPPORTED
- /* Crank through the dummy pass */
- while (cinfo->output_scanline < cinfo->output_height) {
- JDIMENSION last_scanline;
- /* Call progress monitor hook if present */
- if (cinfo->progress != NULL) {
- cinfo->progress->pass_counter = (long) cinfo->output_scanline;
- cinfo->progress->pass_limit = (long) cinfo->output_height;
- (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
- }
- /* Process some data */
- last_scanline = cinfo->output_scanline;
- (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL,
- &cinfo->output_scanline, (JDIMENSION) 0);
- if (cinfo->output_scanline == last_scanline)
- return FALSE; /* No progress made, must suspend */
- }
- /* Finish up dummy pass, and set up for another one */
- (*cinfo->master->finish_output_pass) (cinfo);
- (*cinfo->master->prepare_for_output_pass) (cinfo);
- cinfo->output_scanline = 0;
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif /* QUANT_2PASS_SUPPORTED */
- }
- /* Ready for application to drive output pass through
- * jpeg_read_scanlines or jpeg_read_raw_data.
- */
- cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING;
- return TRUE;
-}
-
-
-/*
- * Read some scanlines of data from the JPEG decompressor.
- *
- * The return value will be the number of lines actually read.
- * This may be less than the number requested in several cases,
- * including bottom of image, data source suspension, and operating
- * modes that emit multiple scanlines at a time.
- *
- * Note: we warn about excess calls to jpeg_read_scanlines() since
- * this likely signals an application programmer error. However,
- * an oversize buffer (max_lines > scanlines remaining) is not an error.
- */
-
-GLOBAL(JDIMENSION)
-jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines,
- JDIMENSION max_lines)
-{
- JDIMENSION row_ctr;
-
- if (cinfo->global_state != DSTATE_SCANNING)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- if (cinfo->output_scanline >= cinfo->output_height) {
- WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
- return 0;
- }
-
- /* Call progress monitor hook if present */
- if (cinfo->progress != NULL) {
- cinfo->progress->pass_counter = (long) cinfo->output_scanline;
- cinfo->progress->pass_limit = (long) cinfo->output_height;
- (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
- }
-
- /* Process some data */
- row_ctr = 0;
- (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines);
- cinfo->output_scanline += row_ctr;
- return row_ctr;
-}
-
-
-/*
- * Alternate entry point to read raw data.
- * Processes exactly one iMCU row per call, unless suspended.
- */
-
-GLOBAL(JDIMENSION)
-jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data,
- JDIMENSION max_lines)
-{
- JDIMENSION lines_per_iMCU_row;
-
- if (cinfo->global_state != DSTATE_RAW_OK)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- if (cinfo->output_scanline >= cinfo->output_height) {
- WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
- return 0;
- }
-
- /* Call progress monitor hook if present */
- if (cinfo->progress != NULL) {
- cinfo->progress->pass_counter = (long) cinfo->output_scanline;
- cinfo->progress->pass_limit = (long) cinfo->output_height;
- (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
- }
-
- /* Verify that at least one iMCU row can be returned. */
- lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size;
- if (max_lines < lines_per_iMCU_row)
- ERREXIT(cinfo, JERR_BUFFER_SIZE);
-
- /* Decompress directly into user's buffer. */
- if (! (*cinfo->coef->decompress_data) (cinfo, data))
- return 0; /* suspension forced, can do nothing more */
-
- /* OK, we processed one iMCU row. */
- cinfo->output_scanline += lines_per_iMCU_row;
- return lines_per_iMCU_row;
-}
-
-
-/* Additional entry points for buffered-image mode. */
-
-#ifdef D_MULTISCAN_FILES_SUPPORTED
-
-/*
- * Initialize for an output pass in buffered-image mode.
- */
-
-GLOBAL(boolean)
-jpeg_start_output (j_decompress_ptr cinfo, int scan_number)
-{
- if (cinfo->global_state != DSTATE_BUFIMAGE &&
- cinfo->global_state != DSTATE_PRESCAN)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- /* Limit scan number to valid range */
- if (scan_number <= 0)
- scan_number = 1;
- if (cinfo->inputctl->eoi_reached &&
- scan_number > cinfo->input_scan_number)
- scan_number = cinfo->input_scan_number;
- cinfo->output_scan_number = scan_number;
- /* Perform any dummy output passes, and set up for the real pass */
- return output_pass_setup(cinfo);
-}
-
-
-/*
- * Finish up after an output pass in buffered-image mode.
- *
- * Returns FALSE if suspended. The return value need be inspected only if
- * a suspending data source is used.
- */
-
-GLOBAL(boolean)
-jpeg_finish_output (j_decompress_ptr cinfo)
-{
- if ((cinfo->global_state == DSTATE_SCANNING ||
- cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) {
- /* Terminate this pass. */
- /* We do not require the whole pass to have been completed. */
- (*cinfo->master->finish_output_pass) (cinfo);
- cinfo->global_state = DSTATE_BUFPOST;
- } else if (cinfo->global_state != DSTATE_BUFPOST) {
- /* BUFPOST = repeat call after a suspension, anything else is error */
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- }
- /* Read markers looking for SOS or EOI */
- while (cinfo->input_scan_number <= cinfo->output_scan_number &&
- ! cinfo->inputctl->eoi_reached) {
- if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
- return FALSE; /* Suspend, come back later */
- }
- cinfo->global_state = DSTATE_BUFIMAGE;
- return TRUE;
-}
-
-#endif /* D_MULTISCAN_FILES_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jdatadst.c b/engine/code/jpeg-6b/jdatadst.c
deleted file mode 100644
index a8f6fb0..0000000
--- a/engine/code/jpeg-6b/jdatadst.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * jdatadst.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains compression data destination routines for the case of
- * emitting JPEG data to a file (or any stdio stream). While these routines
- * are sufficient for most applications, some will want to use a different
- * destination manager.
- * IMPORTANT: we assume that fwrite() will correctly transcribe an array of
- * JOCTETs into 8-bit-wide elements on external storage. If char is wider
- * than 8 bits on your machine, you may need to do some tweaking.
- */
-
-/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jerror.h"
-
-
-/* Expanded data destination object for stdio output */
-
-typedef struct {
- struct jpeg_destination_mgr pub; /* public fields */
-
- FILE * outfile; /* target stream */
- JOCTET * buffer; /* start of buffer */
-} my_destination_mgr;
-
-typedef my_destination_mgr * my_dest_ptr;
-
-#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
-
-
-/*
- * Initialize destination --- called by jpeg_start_compress
- * before any data is actually written.
- */
-
-METHODDEF(void)
-init_destination (j_compress_ptr cinfo)
-{
- my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
-
- /* Allocate the output buffer --- it will be released when done with image */
- dest->buffer = (JOCTET *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- OUTPUT_BUF_SIZE * SIZEOF(JOCTET));
-
- dest->pub.next_output_byte = dest->buffer;
- dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
-}
-
-
-/*
- * Empty the output buffer --- called whenever buffer fills up.
- *
- * In typical applications, this should write the entire output buffer
- * (ignoring the current state of next_output_byte & free_in_buffer),
- * reset the pointer & count to the start of the buffer, and return TRUE
- * indicating that the buffer has been dumped.
- *
- * In applications that need to be able to suspend compression due to output
- * overrun, a FALSE return indicates that the buffer cannot be emptied now.
- * In this situation, the compressor will return to its caller (possibly with
- * an indication that it has not accepted all the supplied scanlines). The
- * application should resume compression after it has made more room in the
- * output buffer. Note that there are substantial restrictions on the use of
- * suspension --- see the documentation.
- *
- * When suspending, the compressor will back up to a convenient restart point
- * (typically the start of the current MCU). next_output_byte & free_in_buffer
- * indicate where the restart point will be if the current call returns FALSE.
- * Data beyond this point will be regenerated after resumption, so do not
- * write it out when emptying the buffer externally.
- */
-
-METHODDEF(boolean)
-empty_output_buffer (j_compress_ptr cinfo)
-{
- my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
-
- if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) !=
- (size_t) OUTPUT_BUF_SIZE)
- ERREXIT(cinfo, JERR_FILE_WRITE);
-
- dest->pub.next_output_byte = dest->buffer;
- dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
-
- return TRUE;
-}
-
-
-/*
- * Terminate destination --- called by jpeg_finish_compress
- * after all data has been written. Usually needs to flush buffer.
- *
- * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
- * application must deal with any cleanup that should happen even
- * for error exit.
- */
-
-METHODDEF(void)
-term_destination (j_compress_ptr cinfo)
-{
- my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
- size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
-
- /* Write any data remaining in the buffer */
- if (datacount > 0) {
- if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount)
- ERREXIT(cinfo, JERR_FILE_WRITE);
- }
- fflush(dest->outfile);
- /* Make sure we wrote the output file OK */
- if (ferror(dest->outfile))
- ERREXIT(cinfo, JERR_FILE_WRITE);
-}
-
-
-/*
- * Prepare for output to a stdio stream.
- * The caller must have already opened the stream, and is responsible
- * for closing it after finishing compression.
- */
-
-GLOBAL(void)
-jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile)
-{
- my_dest_ptr dest;
-
- /* The destination object is made permanent so that multiple JPEG images
- * can be written to the same file without re-executing jpeg_stdio_dest.
- * This makes it dangerous to use this manager and a different destination
- * manager serially with the same JPEG object, because their private object
- * sizes may be different. Caveat programmer.
- */
- if (cinfo->dest == NULL) { /* first time for this JPEG object? */
- cinfo->dest = (struct jpeg_destination_mgr *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- SIZEOF(my_destination_mgr));
- }
-
- dest = (my_dest_ptr) cinfo->dest;
- dest->pub.init_destination = init_destination;
- dest->pub.empty_output_buffer = empty_output_buffer;
- dest->pub.term_destination = term_destination;
- dest->outfile = outfile;
-}
diff --git a/engine/code/jpeg-6b/jdatasrc.c b/engine/code/jpeg-6b/jdatasrc.c
deleted file mode 100644
index 795f65e..0000000
--- a/engine/code/jpeg-6b/jdatasrc.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * jdatasrc.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains decompression data source routines for the case of
- * reading JPEG data from a file (or any stdio stream). While these routines
- * are sufficient for most applications, some will want to use a different
- * source manager.
- * IMPORTANT: we assume that fread() will correctly transcribe an array of
- * JOCTETs from 8-bit-wide elements on external storage. If char is wider
- * than 8 bits on your machine, you may need to do some tweaking.
- */
-
-/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jerror.h"
-
-#ifndef MIN
-#define MIN(a, b) ((a)<(b)?(a):(b))
-#endif
-
-/* Expanded data source object for stdio input */
-
-typedef struct {
- struct jpeg_source_mgr pub; /* public fields */
-
- unsigned char *inbuf; /* source stream */
- size_t inbufbytes;
- JOCTET * buffer; /* start of buffer */
- boolean start_of_file; /* have we gotten any data yet? */
-} my_source_mgr;
-
-typedef my_source_mgr * my_src_ptr;
-
-#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
-
-
-/*
- * Initialize source --- called by jpeg_read_header
- * before any data is actually read.
- */
-
-METHODDEF(void)
-init_source (j_decompress_ptr cinfo)
-{
- my_src_ptr src = (my_src_ptr) cinfo->src;
-
- /* We reset the empty-input-file flag for each image,
- * but we don't clear the input buffer.
- * This is correct behavior for reading a series of images from one source.
- */
- src->start_of_file = TRUE;
-}
-
-
-/*
- * Fill the input buffer --- called whenever buffer is emptied.
- *
- * In typical applications, this should read fresh data into the buffer
- * (ignoring the current state of next_input_byte & bytes_in_buffer),
- * reset the pointer & count to the start of the buffer, and return TRUE
- * indicating that the buffer has been reloaded. It is not necessary to
- * fill the buffer entirely, only to obtain at least one more byte.
- *
- * There is no such thing as an EOF return. If the end of the file has been
- * reached, the routine has a choice of ERREXIT() or inserting fake data into
- * the buffer. In most cases, generating a warning message and inserting a
- * fake EOI marker is the best course of action --- this will allow the
- * decompressor to output however much of the image is there. However,
- * the resulting error message is misleading if the real problem is an empty
- * input file, so we handle that case specially.
- *
- * In applications that need to be able to suspend compression due to input
- * not being available yet, a FALSE return indicates that no more data can be
- * obtained right now, but more may be forthcoming later. In this situation,
- * the decompressor will return to its caller (with an indication of the
- * number of scanlines it has read, if any). The application should resume
- * decompression after it has loaded more data into the input buffer. Note
- * that there are substantial restrictions on the use of suspension --- see
- * the documentation.
- *
- * When suspending, the decompressor will back up to a convenient restart point
- * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
- * indicate where the restart point will be if the current call returns FALSE.
- * Data beyond this point must be rescanned after resumption, so move it to
- * the front of the buffer rather than discarding it.
- */
-
-METHODDEF(boolean)
-fill_input_buffer (j_decompress_ptr cinfo)
-{
- my_src_ptr src = (my_src_ptr) cinfo->src;
- size_t nbytes = MIN(src->inbufbytes, INPUT_BUF_SIZE);
-
- if (nbytes <= 0) {
- WARNMS(cinfo, JWRN_JPEG_EOF);
- /* Insert a fake EOI marker */
- src->buffer[0] = (JOCTET) 0xFF;
- src->buffer[1] = (JOCTET) JPEG_EOI;
- nbytes = 2;
- } else {
- memcpy( src->buffer, src->inbuf, nbytes);
-
- src->inbuf += nbytes;
- src->inbufbytes -= nbytes;
- }
-
- src->pub.next_input_byte = src->buffer;
- src->pub.bytes_in_buffer = nbytes;
- src->start_of_file = FALSE;
-
- return TRUE;
-}
-
-
-/*
- * Skip data --- used to skip over a potentially large amount of
- * uninteresting data (such as an APPn marker).
- *
- * Writers of suspendable-input applications must note that skip_input_data
- * is not granted the right to give a suspension return. If the skip extends
- * beyond the data currently in the buffer, the buffer can be marked empty so
- * that the next read will cause a fill_input_buffer call that can suspend.
- * Arranging for additional bytes to be discarded before reloading the input
- * buffer is the application writer's problem.
- */
-
-METHODDEF(void)
-skip_input_data (j_decompress_ptr cinfo, long num_bytes)
-{
- my_src_ptr src = (my_src_ptr) cinfo->src;
-
- /* Just a dumb implementation for now. Could use fseek() except
- * it doesn't work on pipes. Not clear that being smart is worth
- * any trouble anyway --- large skips are infrequent.
- */
- if (num_bytes > 0) {
- while (num_bytes > (long) src->pub.bytes_in_buffer) {
- num_bytes -= (long) src->pub.bytes_in_buffer;
- (void) fill_input_buffer(cinfo);
- /* note we assume that fill_input_buffer will never return FALSE,
- * so suspension need not be handled.
- */
- }
- src->pub.next_input_byte += (size_t) num_bytes;
- src->pub.bytes_in_buffer -= (size_t) num_bytes;
- }
-}
-
-
-/*
- * An additional method that can be provided by data source modules is the
- * resync_to_restart method for error recovery in the presence of RST markers.
- * For the moment, this source module just uses the default resync method
- * provided by the JPEG library. That method assumes that no backtracking
- * is possible.
- */
-
-
-/*
- * Terminate source --- called by jpeg_finish_decompress
- * after all data has been read. Often a no-op.
- *
- * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
- * application must deal with any cleanup that should happen even
- * for error exit.
- */
-
-METHODDEF(void)
-term_source (j_decompress_ptr cinfo)
-{
- /* no work necessary here */
-}
-
-
-/*
- * Prepare for input from a stdio stream.
- * The caller must have already opened the stream, and is responsible
- * for closing it after finishing decompression.
- */
-
-GLOBAL(void)
-jpeg_mem_src (j_decompress_ptr cinfo, unsigned char *inbuf, size_t size)
-{
- my_src_ptr src;
-
- /* The source object and input buffer are made permanent so that a series
- * of JPEG images can be read from the same file by calling jpeg_stdio_src
- * only before the first one. (If we discarded the buffer at the end of
- * one image, we'd likely lose the start of the next one.)
- * This makes it unsafe to use this manager and a different source
- * manager serially with the same JPEG object. Caveat programmer.
- */
- if (cinfo->src == NULL) { /* first time for this JPEG object? */
- cinfo->src = (struct jpeg_source_mgr *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- SIZEOF(my_source_mgr));
- src = (my_src_ptr) cinfo->src;
- src->buffer = (JOCTET *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- INPUT_BUF_SIZE * SIZEOF(JOCTET));
- }
-
- src = (my_src_ptr) cinfo->src;
- src->pub.init_source = init_source;
- src->pub.fill_input_buffer = fill_input_buffer;
- src->pub.skip_input_data = skip_input_data;
- src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
- src->pub.term_source = term_source;
- src->inbuf = inbuf;
- src->inbufbytes = size;
- src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
- src->pub.next_input_byte = NULL; /* until buffer loaded */
-}
diff --git a/engine/code/jpeg-6b/jdcoefct.c b/engine/code/jpeg-6b/jdcoefct.c
deleted file mode 100644
index 4938d20..0000000
--- a/engine/code/jpeg-6b/jdcoefct.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * jdcoefct.c
- *
- * Copyright (C) 1994-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains the coefficient buffer controller for decompression.
- * This controller is the top level of the JPEG decompressor proper.
- * The coefficient buffer lies between entropy decoding and inverse-DCT steps.
- *
- * In buffered-image mode, this controller is the interface between
- * input-oriented processing and output-oriented processing.
- * Also, the input side (only) is used when reading a file for transcoding.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-/* Block smoothing is only applicable for progressive JPEG, so: */
-#ifndef D_PROGRESSIVE_SUPPORTED
-#undef BLOCK_SMOOTHING_SUPPORTED
-#endif
-
-/* Private buffer controller object */
-
-typedef struct {
- struct jpeg_d_coef_controller pub; /* public fields */
-
- /* These variables keep track of the current location of the input side. */
- /* cinfo->input_iMCU_row is also used for this. */
- JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
- int MCU_vert_offset; /* counts MCU rows within iMCU row */
- int MCU_rows_per_iMCU_row; /* number of such rows needed */
-
- /* The output side's location is represented by cinfo->output_iMCU_row. */
-
- /* In single-pass modes, it's sufficient to buffer just one MCU.
- * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
- * and let the entropy decoder write into that workspace each time.
- * (On 80x86, the workspace is FAR even though it's not really very big;
- * this is to keep the module interfaces unchanged when a large coefficient
- * buffer is necessary.)
- * In multi-pass modes, this array points to the current MCU's blocks
- * within the virtual arrays; it is used only by the input side.
- */
- JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];
-
-#ifdef D_MULTISCAN_FILES_SUPPORTED
- /* In multi-pass modes, we need a virtual block array for each component. */
- jvirt_barray_ptr whole_image[MAX_COMPONENTS];
-#endif
-
-#ifdef BLOCK_SMOOTHING_SUPPORTED
- /* When doing block smoothing, we latch coefficient Al values here */
- int * coef_bits_latch;
-#define SAVED_COEFS 6 /* we save coef_bits[0..5] */
-#endif
-} my_coef_controller;
-
-typedef my_coef_controller * my_coef_ptr;
-
-/* Forward declarations */
-METHODDEF(int) decompress_onepass
- JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
-#ifdef D_MULTISCAN_FILES_SUPPORTED
-METHODDEF(int) decompress_data
- JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
-#endif
-#ifdef BLOCK_SMOOTHING_SUPPORTED
-LOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo));
-METHODDEF(int) decompress_smooth_data
- JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
-#endif
-
-
-LOCAL(void)
-start_iMCU_row (j_decompress_ptr cinfo)
-/* Reset within-iMCU-row counters for a new row (input side) */
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
-
- /* In an interleaved scan, an MCU row is the same as an iMCU row.
- * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
- * But at the bottom of the image, process only what's left.
- */
- if (cinfo->comps_in_scan > 1) {
- coef->MCU_rows_per_iMCU_row = 1;
- } else {
- if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
- coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
- else
- coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
- }
-
- coef->MCU_ctr = 0;
- coef->MCU_vert_offset = 0;
-}
-
-
-/*
- * Initialize for an input processing pass.
- */
-
-METHODDEF(void)
-start_input_pass (j_decompress_ptr cinfo)
-{
- cinfo->input_iMCU_row = 0;
- start_iMCU_row(cinfo);
-}
-
-
-/*
- * Initialize for an output processing pass.
- */
-
-METHODDEF(void)
-start_output_pass (j_decompress_ptr cinfo)
-{
-#ifdef BLOCK_SMOOTHING_SUPPORTED
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
-
- /* If multipass, check to see whether to use block smoothing on this pass */
- if (coef->pub.coef_arrays != NULL) {
- if (cinfo->do_block_smoothing && smoothing_ok(cinfo))
- coef->pub.decompress_data = decompress_smooth_data;
- else
- coef->pub.decompress_data = decompress_data;
- }
-#endif
- cinfo->output_iMCU_row = 0;
-}
-
-
-/*
- * Decompress and return some data in the single-pass case.
- * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
- * Input and output must run in lockstep since we have only a one-MCU buffer.
- * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
- *
- * NB: output_buf contains a plane for each component in image,
- * which we index according to the component's SOF position.
- */
-
-METHODDEF(int)
-decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
- JDIMENSION MCU_col_num; /* index of current MCU within row */
- JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
- JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
- int blkn, ci, xindex, yindex, yoffset, useful_width;
- JSAMPARRAY output_ptr;
- JDIMENSION start_col, output_col;
- jpeg_component_info *compptr;
- inverse_DCT_method_ptr inverse_DCT;
-
- /* Loop to process as much as one whole iMCU row */
- for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
- yoffset++) {
- for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col;
- MCU_col_num++) {
- /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */
- jzero_far((void FAR *) coef->MCU_buffer[0],
- (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK)));
- if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
- /* Suspension forced; update state counters and exit */
- coef->MCU_vert_offset = yoffset;
- coef->MCU_ctr = MCU_col_num;
- return JPEG_SUSPENDED;
- }
- /* Determine where data should go in output_buf and do the IDCT thing.
- * We skip dummy blocks at the right and bottom edges (but blkn gets
- * incremented past them!). Note the inner loop relies on having
- * allocated the MCU_buffer[] blocks sequentially.
- */
- blkn = 0; /* index of current DCT block within MCU */
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- /* Don't bother to IDCT an uninteresting component. */
- if (! compptr->component_needed) {
- blkn += compptr->MCU_blocks;
- continue;
- }
- inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];
- useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
- : compptr->last_col_width;
- output_ptr = output_buf[compptr->component_index] +
- yoffset * compptr->DCT_scaled_size;
- start_col = MCU_col_num * compptr->MCU_sample_width;
- for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
- if (cinfo->input_iMCU_row < last_iMCU_row ||
- yoffset+yindex < compptr->last_row_height) {
- output_col = start_col;
- for (xindex = 0; xindex < useful_width; xindex++) {
- (*inverse_DCT) (cinfo, compptr,
- (JCOEFPTR) coef->MCU_buffer[blkn+xindex],
- output_ptr, output_col);
- output_col += compptr->DCT_scaled_size;
- }
- }
- blkn += compptr->MCU_width;
- output_ptr += compptr->DCT_scaled_size;
- }
- }
- }
- /* Completed an MCU row, but perhaps not an iMCU row */
- coef->MCU_ctr = 0;
- }
- /* Completed the iMCU row, advance counters for next one */
- cinfo->output_iMCU_row++;
- if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
- start_iMCU_row(cinfo);
- return JPEG_ROW_COMPLETED;
- }
- /* Completed the scan */
- (*cinfo->inputctl->finish_input_pass) (cinfo);
- return JPEG_SCAN_COMPLETED;
-}
-
-
-/*
- * Dummy consume-input routine for single-pass operation.
- */
-
-METHODDEF(int)
-dummy_consume_data (j_decompress_ptr cinfo)
-{
- return JPEG_SUSPENDED; /* Always indicate nothing was done */
-}
-
-
-#ifdef D_MULTISCAN_FILES_SUPPORTED
-
-/*
- * Consume input data and store it in the full-image coefficient buffer.
- * We read as much as one fully interleaved MCU row ("iMCU" row) per call,
- * ie, v_samp_factor block rows for each component in the scan.
- * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
- */
-
-METHODDEF(int)
-consume_data (j_decompress_ptr cinfo)
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
- JDIMENSION MCU_col_num; /* index of current MCU within row */
- int blkn, ci, xindex, yindex, yoffset;
- JDIMENSION start_col;
- JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
- JBLOCKROW buffer_ptr;
- jpeg_component_info *compptr;
-
- /* Align the virtual buffers for the components used in this scan. */
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- buffer[ci] = (*cinfo->mem->access_virt_barray)
- ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
- cinfo->input_iMCU_row * compptr->v_samp_factor,
- (JDIMENSION) compptr->v_samp_factor, TRUE);
- /* Note: entropy decoder expects buffer to be zeroed,
- * but this is handled automatically by the memory manager
- * because we requested a pre-zeroed array.
- */
- }
-
- /* Loop to process one whole iMCU row */
- for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
- yoffset++) {
- for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row;
- MCU_col_num++) {
- /* Construct list of pointers to DCT blocks belonging to this MCU */
- blkn = 0; /* index of current DCT block within MCU */
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- start_col = MCU_col_num * compptr->MCU_width;
- for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
- buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
- for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
- coef->MCU_buffer[blkn++] = buffer_ptr++;
- }
- }
- }
- /* Try to fetch the MCU. */
- if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
- /* Suspension forced; update state counters and exit */
- coef->MCU_vert_offset = yoffset;
- coef->MCU_ctr = MCU_col_num;
- return JPEG_SUSPENDED;
- }
- }
- /* Completed an MCU row, but perhaps not an iMCU row */
- coef->MCU_ctr = 0;
- }
- /* Completed the iMCU row, advance counters for next one */
- if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
- start_iMCU_row(cinfo);
- return JPEG_ROW_COMPLETED;
- }
- /* Completed the scan */
- (*cinfo->inputctl->finish_input_pass) (cinfo);
- return JPEG_SCAN_COMPLETED;
-}
-
-
-/*
- * Decompress and return some data in the multi-pass case.
- * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
- * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
- *
- * NB: output_buf contains a plane for each component in image.
- */
-
-METHODDEF(int)
-decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
- JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
- JDIMENSION block_num;
- int ci, block_row, block_rows;
- JBLOCKARRAY buffer;
- JBLOCKROW buffer_ptr;
- JSAMPARRAY output_ptr;
- JDIMENSION output_col;
- jpeg_component_info *compptr;
- inverse_DCT_method_ptr inverse_DCT;
-
- /* Force some input to be done if we are getting ahead of the input. */
- while (cinfo->input_scan_number < cinfo->output_scan_number ||
- (cinfo->input_scan_number == cinfo->output_scan_number &&
- cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) {
- if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)
- return JPEG_SUSPENDED;
- }
-
- /* OK, output from the virtual arrays. */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* Don't bother to IDCT an uninteresting component. */
- if (! compptr->component_needed)
- continue;
- /* Align the virtual buffer for this component. */
- buffer = (*cinfo->mem->access_virt_barray)
- ((j_common_ptr) cinfo, coef->whole_image[ci],
- cinfo->output_iMCU_row * compptr->v_samp_factor,
- (JDIMENSION) compptr->v_samp_factor, FALSE);
- /* Count non-dummy DCT block rows in this iMCU row. */
- if (cinfo->output_iMCU_row < last_iMCU_row)
- block_rows = compptr->v_samp_factor;
- else {
- /* NB: can't use last_row_height here; it is input-side-dependent! */
- block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
- if (block_rows == 0) block_rows = compptr->v_samp_factor;
- }
- inverse_DCT = cinfo->idct->inverse_DCT[ci];
- output_ptr = output_buf[ci];
- /* Loop over all DCT blocks to be processed. */
- for (block_row = 0; block_row < block_rows; block_row++) {
- buffer_ptr = buffer[block_row];
- output_col = 0;
- for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) {
- (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr,
- output_ptr, output_col);
- buffer_ptr++;
- output_col += compptr->DCT_scaled_size;
- }
- output_ptr += compptr->DCT_scaled_size;
- }
- }
-
- if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
- return JPEG_ROW_COMPLETED;
- return JPEG_SCAN_COMPLETED;
-}
-
-#endif /* D_MULTISCAN_FILES_SUPPORTED */
-
-
-#ifdef BLOCK_SMOOTHING_SUPPORTED
-
-/*
- * This code applies interblock smoothing as described by section K.8
- * of the JPEG standard: the first 5 AC coefficients are estimated from
- * the DC values of a DCT block and its 8 neighboring blocks.
- * We apply smoothing only for progressive JPEG decoding, and only if
- * the coefficients it can estimate are not yet known to full precision.
- */
-
-/* Natural-order array positions of the first 5 zigzag-order coefficients */
-#define Q01_POS 1
-#define Q10_POS 8
-#define Q20_POS 16
-#define Q11_POS 9
-#define Q02_POS 2
-
-/*
- * Determine whether block smoothing is applicable and safe.
- * We also latch the current states of the coef_bits[] entries for the
- * AC coefficients; otherwise, if the input side of the decompressor
- * advances into a new scan, we might think the coefficients are known
- * more accurately than they really are.
- */
-
-LOCAL(boolean)
-smoothing_ok (j_decompress_ptr cinfo)
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
- boolean smoothing_useful = FALSE;
- int ci, coefi;
- jpeg_component_info *compptr;
- JQUANT_TBL * qtable;
- int * coef_bits;
- int * coef_bits_latch;
-
- if (! cinfo->progressive_mode || cinfo->coef_bits == NULL)
- return FALSE;
-
- /* Allocate latch area if not already done */
- if (coef->coef_bits_latch == NULL)
- coef->coef_bits_latch = (int *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- cinfo->num_components *
- (SAVED_COEFS * SIZEOF(int)));
- coef_bits_latch = coef->coef_bits_latch;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* All components' quantization values must already be latched. */
- if ((qtable = compptr->quant_table) == NULL)
- return FALSE;
- /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */
- if (qtable->quantval[0] == 0 ||
- qtable->quantval[Q01_POS] == 0 ||
- qtable->quantval[Q10_POS] == 0 ||
- qtable->quantval[Q20_POS] == 0 ||
- qtable->quantval[Q11_POS] == 0 ||
- qtable->quantval[Q02_POS] == 0)
- return FALSE;
- /* DC values must be at least partly known for all components. */
- coef_bits = cinfo->coef_bits[ci];
- if (coef_bits[0] < 0)
- return FALSE;
- /* Block smoothing is helpful if some AC coefficients remain inaccurate. */
- for (coefi = 1; coefi <= 5; coefi++) {
- coef_bits_latch[coefi] = coef_bits[coefi];
- if (coef_bits[coefi] != 0)
- smoothing_useful = TRUE;
- }
- coef_bits_latch += SAVED_COEFS;
- }
-
- return smoothing_useful;
-}
-
-
-/*
- * Variant of decompress_data for use when doing block smoothing.
- */
-
-METHODDEF(int)
-decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
-{
- my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
- JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
- JDIMENSION block_num, last_block_column;
- int ci, block_row, block_rows, access_rows;
- JBLOCKARRAY buffer;
- JBLOCKROW buffer_ptr, prev_block_row, next_block_row;
- JSAMPARRAY output_ptr;
- JDIMENSION output_col;
- jpeg_component_info *compptr;
- inverse_DCT_method_ptr inverse_DCT;
- boolean first_row, last_row;
- JBLOCK workspace;
- int *coef_bits;
- JQUANT_TBL *quanttbl;
- INT32 Q00,Q01,Q02,Q10,Q11,Q20, num;
- int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9;
- int Al, pred;
-
- /* Force some input to be done if we are getting ahead of the input. */
- while (cinfo->input_scan_number <= cinfo->output_scan_number &&
- ! cinfo->inputctl->eoi_reached) {
- if (cinfo->input_scan_number == cinfo->output_scan_number) {
- /* If input is working on current scan, we ordinarily want it to
- * have completed the current row. But if input scan is DC,
- * we want it to keep one row ahead so that next block row's DC
- * values are up to date.
- */
- JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0;
- if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta)
- break;
- }
- if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)
- return JPEG_SUSPENDED;
- }
-
- /* OK, output from the virtual arrays. */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* Don't bother to IDCT an uninteresting component. */
- if (! compptr->component_needed)
- continue;
- /* Count non-dummy DCT block rows in this iMCU row. */
- if (cinfo->output_iMCU_row < last_iMCU_row) {
- block_rows = compptr->v_samp_factor;
- access_rows = block_rows * 2; /* this and next iMCU row */
- last_row = FALSE;
- } else {
- /* NB: can't use last_row_height here; it is input-side-dependent! */
- block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
- if (block_rows == 0) block_rows = compptr->v_samp_factor;
- access_rows = block_rows; /* this iMCU row only */
- last_row = TRUE;
- }
- /* Align the virtual buffer for this component. */
- if (cinfo->output_iMCU_row > 0) {
- access_rows += compptr->v_samp_factor; /* prior iMCU row too */
- buffer = (*cinfo->mem->access_virt_barray)
- ((j_common_ptr) cinfo, coef->whole_image[ci],
- (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor,
- (JDIMENSION) access_rows, FALSE);
- buffer += compptr->v_samp_factor; /* point to current iMCU row */
- first_row = FALSE;
- } else {
- buffer = (*cinfo->mem->access_virt_barray)
- ((j_common_ptr) cinfo, coef->whole_image[ci],
- (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE);
- first_row = TRUE;
- }
- /* Fetch component-dependent info */
- coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS);
- quanttbl = compptr->quant_table;
- Q00 = quanttbl->quantval[0];
- Q01 = quanttbl->quantval[Q01_POS];
- Q10 = quanttbl->quantval[Q10_POS];
- Q20 = quanttbl->quantval[Q20_POS];
- Q11 = quanttbl->quantval[Q11_POS];
- Q02 = quanttbl->quantval[Q02_POS];
- inverse_DCT = cinfo->idct->inverse_DCT[ci];
- output_ptr = output_buf[ci];
- /* Loop over all DCT blocks to be processed. */
- for (block_row = 0; block_row < block_rows; block_row++) {
- buffer_ptr = buffer[block_row];
- if (first_row && block_row == 0)
- prev_block_row = buffer_ptr;
- else
- prev_block_row = buffer[block_row-1];
- if (last_row && block_row == block_rows-1)
- next_block_row = buffer_ptr;
- else
- next_block_row = buffer[block_row+1];
- /* We fetch the surrounding DC values using a sliding-register approach.
- * Initialize all nine here so as to do the right thing on narrow pics.
- */
- DC1 = DC2 = DC3 = (int) prev_block_row[0][0];
- DC4 = DC5 = DC6 = (int) buffer_ptr[0][0];
- DC7 = DC8 = DC9 = (int) next_block_row[0][0];
- output_col = 0;
- last_block_column = compptr->width_in_blocks - 1;
- for (block_num = 0; block_num <= last_block_column; block_num++) {
- /* Fetch current DCT block into workspace so we can modify it. */
- jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1);
- /* Update DC values */
- if (block_num < last_block_column) {
- DC3 = (int) prev_block_row[1][0];
- DC6 = (int) buffer_ptr[1][0];
- DC9 = (int) next_block_row[1][0];
- }
- /* Compute coefficient estimates per K.8.
- * An estimate is applied only if coefficient is still zero,
- * and is not known to be fully accurate.
- */
- /* AC01 */
- if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) {
- num = 36 * Q00 * (DC4 - DC6);
- if (num >= 0) {
- pred = (int) (((Q01<<7) + num) / (Q01<<8));
- if (Al > 0 && pred >= (1<<Al))
- pred = (1<<Al)-1;
- } else {
- pred = (int) (((Q01<<7) - num) / (Q01<<8));
- if (Al > 0 && pred >= (1<<Al))
- pred = (1<<Al)-1;
- pred = -pred;
- }
- workspace[1] = (JCOEF) pred;
- }
- /* AC10 */
- if ((Al=coef_bits[2]) != 0 && workspace[8] == 0) {
- num = 36 * Q00 * (DC2 - DC8);
- if (num >= 0) {
- pred = (int) (((Q10<<7) + num) / (Q10<<8));
- if (Al > 0 && pred >= (1<<Al))
- pred = (1<<Al)-1;
- } else {
- pred = (int) (((Q10<<7) - num) / (Q10<<8));
- if (Al > 0 && pred >= (1<<Al))
- pred = (1<<Al)-1;
- pred = -pred;
- }
- workspace[8] = (JCOEF) pred;
- }
- /* AC20 */
- if ((Al=coef_bits[3]) != 0 && workspace[16] == 0) {
- num = 9 * Q00 * (DC2 + DC8 - 2*DC5);
- if (num >= 0) {
- pred = (int) (((Q20<<7) + num) / (Q20<<8));
- if (Al > 0 && pred >= (1<<Al))
- pred = (1<<Al)-1;
- } else {
- pred = (int) (((Q20<<7) - num) / (Q20<<8));
- if (Al > 0 && pred >= (1<<Al))
- pred = (1<<Al)-1;
- pred = -pred;
- }
- workspace[16] = (JCOEF) pred;
- }
- /* AC11 */
- if ((Al=coef_bits[4]) != 0 && workspace[9] == 0) {
- num = 5 * Q00 * (DC1 - DC3 - DC7 + DC9);
- if (num >= 0) {
- pred = (int) (((Q11<<7) + num) / (Q11<<8));
- if (Al > 0 && pred >= (1<<Al))
- pred = (1<<Al)-1;
- } else {
- pred = (int) (((Q11<<7) - num) / (Q11<<8));
- if (Al > 0 && pred >= (1<<Al))
- pred = (1<<Al)-1;
- pred = -pred;
- }
- workspace[9] = (JCOEF) pred;
- }
- /* AC02 */
- if ((Al=coef_bits[5]) != 0 && workspace[2] == 0) {
- num = 9 * Q00 * (DC4 + DC6 - 2*DC5);
- if (num >= 0) {
- pred = (int) (((Q02<<7) + num) / (Q02<<8));
- if (Al > 0 && pred >= (1<<Al))
- pred = (1<<Al)-1;
- } else {
- pred = (int) (((Q02<<7) - num) / (Q02<<8));
- if (Al > 0 && pred >= (1<<Al))
- pred = (1<<Al)-1;
- pred = -pred;
- }
- workspace[2] = (JCOEF) pred;
- }
- /* OK, do the IDCT */
- (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) workspace,
- output_ptr, output_col);
- /* Advance for next column */
- DC1 = DC2; DC2 = DC3;
- DC4 = DC5; DC5 = DC6;
- DC7 = DC8; DC8 = DC9;
- buffer_ptr++, prev_block_row++, next_block_row++;
- output_col += compptr->DCT_scaled_size;
- }
- output_ptr += compptr->DCT_scaled_size;
- }
- }
-
- if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
- return JPEG_ROW_COMPLETED;
- return JPEG_SCAN_COMPLETED;
-}
-
-#endif /* BLOCK_SMOOTHING_SUPPORTED */
-
-
-/*
- * Initialize coefficient buffer controller.
- */
-
-GLOBAL(void)
-jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
-{
- my_coef_ptr coef;
-
- coef = (my_coef_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_coef_controller));
- cinfo->coef = (struct jpeg_d_coef_controller *) coef;
- coef->pub.start_input_pass = start_input_pass;
- coef->pub.start_output_pass = start_output_pass;
-#ifdef BLOCK_SMOOTHING_SUPPORTED
- coef->coef_bits_latch = NULL;
-#endif
-
- /* Create the coefficient buffer. */
- if (need_full_buffer) {
-#ifdef D_MULTISCAN_FILES_SUPPORTED
- /* Allocate a full-image virtual array for each component, */
- /* padded to a multiple of samp_factor DCT blocks in each direction. */
- /* Note we ask for a pre-zeroed array. */
- int ci, access_rows;
- jpeg_component_info *compptr;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- access_rows = compptr->v_samp_factor;
-#ifdef BLOCK_SMOOTHING_SUPPORTED
- /* If block smoothing could be used, need a bigger window */
- if (cinfo->progressive_mode)
- access_rows *= 3;
-#endif
- coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE,
- (JDIMENSION) jround_up((long) compptr->width_in_blocks,
- (long) compptr->h_samp_factor),
- (JDIMENSION) jround_up((long) compptr->height_in_blocks,
- (long) compptr->v_samp_factor),
- (JDIMENSION) access_rows);
- }
- coef->pub.consume_data = consume_data;
- coef->pub.decompress_data = decompress_data;
- coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- } else {
- /* We only need a single-MCU buffer. */
- JBLOCKROW buffer;
- int i;
-
- buffer = (JBLOCKROW)
- (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
- for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) {
- coef->MCU_buffer[i] = buffer + i;
- }
- coef->pub.consume_data = dummy_consume_data;
- coef->pub.decompress_data = decompress_onepass;
- coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */
- }
-}
diff --git a/engine/code/jpeg-6b/jdcolor.c b/engine/code/jpeg-6b/jdcolor.c
deleted file mode 100644
index 6c04dfe..0000000
--- a/engine/code/jpeg-6b/jdcolor.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * jdcolor.c
- *
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains output colorspace conversion routines.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* Private subobject */
-
-typedef struct {
- struct jpeg_color_deconverter pub; /* public fields */
-
- /* Private state for YCC->RGB conversion */
- int * Cr_r_tab; /* => table for Cr to R conversion */
- int * Cb_b_tab; /* => table for Cb to B conversion */
- INT32 * Cr_g_tab; /* => table for Cr to G conversion */
- INT32 * Cb_g_tab; /* => table for Cb to G conversion */
-} my_color_deconverter;
-
-typedef my_color_deconverter * my_cconvert_ptr;
-
-
-/**************** YCbCr -> RGB conversion: most common case **************/
-
-/*
- * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
- * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
- * The conversion equations to be implemented are therefore
- * R = Y + 1.40200 * Cr
- * G = Y - 0.34414 * Cb - 0.71414 * Cr
- * B = Y + 1.77200 * Cb
- * where Cb and Cr represent the incoming values less CENTERJSAMPLE.
- * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
- *
- * To avoid floating-point arithmetic, we represent the fractional constants
- * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
- * the products by 2^16, with appropriate rounding, to get the correct answer.
- * Notice that Y, being an integral input, does not contribute any fraction
- * so it need not participate in the rounding.
- *
- * For even more speed, we avoid doing any multiplications in the inner loop
- * by precalculating the constants times Cb and Cr for all possible values.
- * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
- * for 12-bit samples it is still acceptable. It's not very reasonable for
- * 16-bit samples, but if you want lossless storage you shouldn't be changing
- * colorspace anyway.
- * The Cr=>R and Cb=>B values can be rounded to integers in advance; the
- * values for the G calculation are left scaled up, since we must add them
- * together before rounding.
- */
-
-#define SCALEBITS 16 /* speediest right-shift on some machines */
-#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
-#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
-
-
-/*
- * Initialize tables for YCC->RGB colorspace conversion.
- */
-
-LOCAL(void)
-build_ycc_rgb_table (j_decompress_ptr cinfo)
-{
- my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
- int i;
- INT32 x;
- SHIFT_TEMPS
-
- cconvert->Cr_r_tab = (int *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE+1) * SIZEOF(int));
- cconvert->Cb_b_tab = (int *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE+1) * SIZEOF(int));
- cconvert->Cr_g_tab = (INT32 *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE+1) * SIZEOF(INT32));
- cconvert->Cb_g_tab = (INT32 *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE+1) * SIZEOF(INT32));
-
- for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
- /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
- /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
- /* Cr=>R value is nearest int to 1.40200 * x */
- cconvert->Cr_r_tab[i] = (int)
- RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
- /* Cb=>B value is nearest int to 1.77200 * x */
- cconvert->Cb_b_tab[i] = (int)
- RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS);
- /* Cr=>G value is scaled-up -0.71414 * x */
- cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x;
- /* Cb=>G value is scaled-up -0.34414 * x */
- /* We also add in ONE_HALF so that need not do it in inner loop */
- cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF;
- }
-}
-
-
-/*
- * Convert some rows of samples to the output colorspace.
- *
- * Note that we change from noninterleaved, one-plane-per-component format
- * to interleaved-pixel format. The output buffer is therefore three times
- * as wide as the input buffer.
- * A starting row offset is provided only for the input buffer. The caller
- * can easily adjust the passed output_buf value to accommodate any row
- * offset required on that side.
- */
-
-METHODDEF(void)
-ycc_rgb_convert (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION input_row,
- JSAMPARRAY output_buf, int num_rows)
-{
- my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
- register int y, cb, cr;
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2;
- register JDIMENSION col;
- JDIMENSION num_cols = cinfo->output_width;
- /* copy these pointers into registers if possible */
- register JSAMPLE * range_limit = cinfo->sample_range_limit;
- register int * Crrtab = cconvert->Cr_r_tab;
- register int * Cbbtab = cconvert->Cb_b_tab;
- register INT32 * Crgtab = cconvert->Cr_g_tab;
- register INT32 * Cbgtab = cconvert->Cb_g_tab;
- SHIFT_TEMPS
-
- while (--num_rows >= 0) {
- inptr0 = input_buf[0][input_row];
- inptr1 = input_buf[1][input_row];
- inptr2 = input_buf[2][input_row];
- input_row++;
- outptr = *output_buf++;
- for (col = 0; col < num_cols; col++) {
- y = GETJSAMPLE(inptr0[col]);
- cb = GETJSAMPLE(inptr1[col]);
- cr = GETJSAMPLE(inptr2[col]);
- /* Range-limiting is essential due to noise introduced by DCT losses. */
- outptr[RGB_RED] = range_limit[y + Crrtab[cr]];
- outptr[RGB_GREEN] = range_limit[y +
- ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
- SCALEBITS))];
- outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]];
- outptr += RGB_PIXELSIZE;
- }
- }
-}
-
-
-/**************** Cases other than YCbCr -> RGB **************/
-
-
-/*
- * Color conversion for no colorspace change: just copy the data,
- * converting from separate-planes to interleaved representation.
- */
-
-METHODDEF(void)
-null_convert (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION input_row,
- JSAMPARRAY output_buf, int num_rows)
-{
- register JSAMPROW inptr, outptr;
- register JDIMENSION count;
- register int num_components = cinfo->num_components;
- JDIMENSION num_cols = cinfo->output_width;
- int ci;
-
- while (--num_rows >= 0) {
- for (ci = 0; ci < num_components; ci++) {
- inptr = input_buf[ci][input_row];
- outptr = output_buf[0] + ci;
- for (count = num_cols; count > 0; count--) {
- *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */
- outptr += num_components;
- }
- }
- input_row++;
- output_buf++;
- }
-}
-
-
-/*
- * Color conversion for grayscale: just copy the data.
- * This also works for YCbCr -> grayscale conversion, in which
- * we just copy the Y (luminance) component and ignore chrominance.
- */
-
-METHODDEF(void)
-grayscale_convert (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION input_row,
- JSAMPARRAY output_buf, int num_rows)
-{
- jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0,
- num_rows, cinfo->output_width);
-}
-
-
-/*
- * Convert grayscale to RGB: just duplicate the graylevel three times.
- * This is provided to support applications that don't want to cope
- * with grayscale as a separate case.
- */
-
-METHODDEF(void)
-gray_rgb_convert (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION input_row,
- JSAMPARRAY output_buf, int num_rows)
-{
- register JSAMPROW inptr, outptr;
- register JDIMENSION col;
- JDIMENSION num_cols = cinfo->output_width;
-
- while (--num_rows >= 0) {
- inptr = input_buf[0][input_row++];
- outptr = *output_buf++;
- for (col = 0; col < num_cols; col++) {
- /* We can dispense with GETJSAMPLE() here */
- outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col];
- outptr += RGB_PIXELSIZE;
- }
- }
-}
-
-
-/*
- * Adobe-style YCCK->CMYK conversion.
- * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same
- * conversion as above, while passing K (black) unchanged.
- * We assume build_ycc_rgb_table has been called.
- */
-
-METHODDEF(void)
-ycck_cmyk_convert (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION input_row,
- JSAMPARRAY output_buf, int num_rows)
-{
- my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
- register int y, cb, cr;
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2, inptr3;
- register JDIMENSION col;
- JDIMENSION num_cols = cinfo->output_width;
- /* copy these pointers into registers if possible */
- register JSAMPLE * range_limit = cinfo->sample_range_limit;
- register int * Crrtab = cconvert->Cr_r_tab;
- register int * Cbbtab = cconvert->Cb_b_tab;
- register INT32 * Crgtab = cconvert->Cr_g_tab;
- register INT32 * Cbgtab = cconvert->Cb_g_tab;
- SHIFT_TEMPS
-
- while (--num_rows >= 0) {
- inptr0 = input_buf[0][input_row];
- inptr1 = input_buf[1][input_row];
- inptr2 = input_buf[2][input_row];
- inptr3 = input_buf[3][input_row];
- input_row++;
- outptr = *output_buf++;
- for (col = 0; col < num_cols; col++) {
- y = GETJSAMPLE(inptr0[col]);
- cb = GETJSAMPLE(inptr1[col]);
- cr = GETJSAMPLE(inptr2[col]);
- /* Range-limiting is essential due to noise introduced by DCT losses. */
- outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */
- outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */
- ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
- SCALEBITS)))];
- outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */
- /* K passes through unchanged */
- outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */
- outptr += 4;
- }
- }
-}
-
-
-/*
- * Empty method for start_pass.
- */
-
-METHODDEF(void)
-start_pass_dcolor (j_decompress_ptr cinfo)
-{
- /* no work needed */
-}
-
-
-/*
- * Module initialization routine for output colorspace conversion.
- */
-
-GLOBAL(void)
-jinit_color_deconverter (j_decompress_ptr cinfo)
-{
- my_cconvert_ptr cconvert;
- int ci;
-
- cconvert = (my_cconvert_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_color_deconverter));
- cinfo->cconvert = (struct jpeg_color_deconverter *) cconvert;
- cconvert->pub.start_pass = start_pass_dcolor;
-
- /* Make sure num_components agrees with jpeg_color_space */
- switch (cinfo->jpeg_color_space) {
- case JCS_GRAYSCALE:
- if (cinfo->num_components != 1)
- ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
- break;
-
- case JCS_RGB:
- case JCS_YCbCr:
- if (cinfo->num_components != 3)
- ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
- break;
-
- case JCS_CMYK:
- case JCS_YCCK:
- if (cinfo->num_components != 4)
- ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
- break;
-
- default: /* JCS_UNKNOWN can be anything */
- if (cinfo->num_components < 1)
- ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
- break;
- }
-
- /* Set out_color_components and conversion method based on requested space.
- * Also clear the component_needed flags for any unused components,
- * so that earlier pipeline stages can avoid useless computation.
- */
-
- switch (cinfo->out_color_space) {
- case JCS_GRAYSCALE:
- cinfo->out_color_components = 1;
- if (cinfo->jpeg_color_space == JCS_GRAYSCALE ||
- cinfo->jpeg_color_space == JCS_YCbCr) {
- cconvert->pub.color_convert = grayscale_convert;
- /* For color->grayscale conversion, only the Y (0) component is needed */
- for (ci = 1; ci < cinfo->num_components; ci++)
- cinfo->comp_info[ci].component_needed = FALSE;
- } else
- ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
- break;
-
- case JCS_RGB:
- cinfo->out_color_components = RGB_PIXELSIZE;
- if (cinfo->jpeg_color_space == JCS_YCbCr) {
- cconvert->pub.color_convert = ycc_rgb_convert;
- build_ycc_rgb_table(cinfo);
- } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
- cconvert->pub.color_convert = gray_rgb_convert;
- } else if (cinfo->jpeg_color_space == JCS_RGB && RGB_PIXELSIZE == 3) {
- cconvert->pub.color_convert = null_convert;
- } else
- ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
- break;
-
- case JCS_CMYK:
- cinfo->out_color_components = 4;
- if (cinfo->jpeg_color_space == JCS_YCCK) {
- cconvert->pub.color_convert = ycck_cmyk_convert;
- build_ycc_rgb_table(cinfo);
- } else if (cinfo->jpeg_color_space == JCS_CMYK) {
- cconvert->pub.color_convert = null_convert;
- } else
- ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
- break;
-
- default:
- /* Permit null conversion to same output space */
- if (cinfo->out_color_space == cinfo->jpeg_color_space) {
- cinfo->out_color_components = cinfo->num_components;
- cconvert->pub.color_convert = null_convert;
- } else /* unsupported non-null conversion */
- ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
- break;
- }
-
- if (cinfo->quantize_colors)
- cinfo->output_components = 1; /* single colormapped output component */
- else
- cinfo->output_components = cinfo->out_color_components;
-}
diff --git a/engine/code/jpeg-6b/jdct.h b/engine/code/jpeg-6b/jdct.h
deleted file mode 100644
index 04192a2..0000000
--- a/engine/code/jpeg-6b/jdct.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * jdct.h
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This include file contains common declarations for the forward and
- * inverse DCT modules. These declarations are private to the DCT managers
- * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms.
- * The individual DCT algorithms are kept in separate files to ease
- * machine-dependent tuning (e.g., assembly coding).
- */
-
-
-/*
- * A forward DCT routine is given a pointer to a work area of type DCTELEM[];
- * the DCT is to be performed in-place in that buffer. Type DCTELEM is int
- * for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT
- * implementations use an array of type FAST_FLOAT, instead.)
- * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE).
- * The DCT outputs are returned scaled up by a factor of 8; they therefore
- * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This
- * convention improves accuracy in integer implementations and saves some
- * work in floating-point ones.
- * Quantization of the output coefficients is done by jcdctmgr.c.
- */
-
-#if BITS_IN_JSAMPLE == 8
-typedef int DCTELEM; /* 16 or 32 bits is fine */
-#else
-typedef INT32 DCTELEM; /* must have 32 bits */
-#endif
-
-typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data));
-typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data));
-
-
-/*
- * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer
- * to an output sample array. The routine must dequantize the input data as
- * well as perform the IDCT; for dequantization, it uses the multiplier table
- * pointed to by compptr->dct_table. The output data is to be placed into the
- * sample array starting at a specified column. (Any row offset needed will
- * be applied to the array pointer before it is passed to the IDCT code.)
- * Note that the number of samples emitted by the IDCT routine is
- * DCT_scaled_size * DCT_scaled_size.
- */
-
-/* typedef inverse_DCT_method_ptr is declared in jpegint.h */
-
-/*
- * Each IDCT routine has its own ideas about the best dct_table element type.
- */
-
-typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */
-#if BITS_IN_JSAMPLE == 8
-typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */
-#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */
-#else
-typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */
-#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */
-#endif
-typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
-
-
-/*
- * Each IDCT routine is responsible for range-limiting its results and
- * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could
- * be quite far out of range if the input data is corrupt, so a bulletproof
- * range-limiting step is required. We use a mask-and-table-lookup method
- * to do the combined operations quickly. See the comments with
- * prepare_range_limit_table (in jdmaster.c) for more info.
- */
-
-#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE)
-
-#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */
-
-
-/* Short forms of external names for systems with brain-damaged linkers. */
-
-#ifdef NEED_SHORT_EXTERNAL_NAMES
-#define jpeg_fdct_islow jFDislow
-#define jpeg_fdct_ifast jFDifast
-#define jpeg_fdct_float jFDfloat
-#define jpeg_idct_islow jRDislow
-#define jpeg_idct_ifast jRDifast
-#define jpeg_idct_float jRDfloat
-#define jpeg_idct_4x4 jRD4x4
-#define jpeg_idct_2x2 jRD2x2
-#define jpeg_idct_1x1 jRD1x1
-#endif /* NEED_SHORT_EXTERNAL_NAMES */
-
-/* Extern declarations for the forward and inverse DCT routines. */
-
-EXTERN(void) jpeg_fdct_islow JPP((DCTELEM * data));
-EXTERN(void) jpeg_fdct_ifast JPP((DCTELEM * data));
-EXTERN(void) jpeg_fdct_float JPP((FAST_FLOAT * data));
-
-EXTERN(void) jpeg_idct_islow
- JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
-EXTERN(void) jpeg_idct_ifast
- JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
-EXTERN(void) jpeg_idct_float
- JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
-EXTERN(void) jpeg_idct_4x4
- JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
-EXTERN(void) jpeg_idct_2x2
- JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
-EXTERN(void) jpeg_idct_1x1
- JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
-
-
-/*
- * Macros for handling fixed-point arithmetic; these are used by many
- * but not all of the DCT/IDCT modules.
- *
- * All values are expected to be of type INT32.
- * Fractional constants are scaled left by CONST_BITS bits.
- * CONST_BITS is defined within each module using these macros,
- * and may differ from one module to the next.
- */
-
-#define ONE ((INT32) 1)
-#define CONST_SCALE (ONE << CONST_BITS)
-
-/* Convert a positive real constant to an integer scaled by CONST_SCALE.
- * Caution: some C compilers fail to reduce "FIX(constant)" at compile time,
- * thus causing a lot of useless floating-point operations at run time.
- */
-
-#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5))
-
-/* Descale and correctly round an INT32 value that's scaled by N bits.
- * We assume RIGHT_SHIFT rounds towards minus infinity, so adding
- * the fudge factor is correct for either sign of X.
- */
-
-#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
-
-/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
- * This macro is used only when the two inputs will actually be no more than
- * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a
- * full 32x32 multiply. This provides a useful speedup on many machines.
- * Unfortunately there is no way to specify a 16x16->32 multiply portably
- * in C, but some C compilers will do the right thing if you provide the
- * correct combination of casts.
- */
-
-#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
-#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const)))
-#endif
-#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */
-#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const)))
-#endif
-
-#ifndef MULTIPLY16C16 /* default definition */
-#define MULTIPLY16C16(var,const) ((var) * (const))
-#endif
-
-/* Same except both inputs are variables. */
-
-#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
-#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2)))
-#endif
-
-#ifndef MULTIPLY16V16 /* default definition */
-#define MULTIPLY16V16(var1,var2) ((var1) * (var2))
-#endif
diff --git a/engine/code/jpeg-6b/jddctmgr.c b/engine/code/jpeg-6b/jddctmgr.c
deleted file mode 100644
index bbf8d0e..0000000
--- a/engine/code/jpeg-6b/jddctmgr.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * jddctmgr.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains the inverse-DCT management logic.
- * This code selects a particular IDCT implementation to be used,
- * and it performs related housekeeping chores. No code in this file
- * is executed per IDCT step, only during output pass setup.
- *
- * Note that the IDCT routines are responsible for performing coefficient
- * dequantization as well as the IDCT proper. This module sets up the
- * dequantization multiplier table needed by the IDCT routine.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jdct.h" /* Private declarations for DCT subsystem */
-
-
-/*
- * The decompressor input side (jdinput.c) saves away the appropriate
- * quantization table for each component at the start of the first scan
- * involving that component. (This is necessary in order to correctly
- * decode files that reuse Q-table slots.)
- * When we are ready to make an output pass, the saved Q-table is converted
- * to a multiplier table that will actually be used by the IDCT routine.
- * The multiplier table contents are IDCT-method-dependent. To support
- * application changes in IDCT method between scans, we can remake the
- * multiplier tables if necessary.
- * In buffered-image mode, the first output pass may occur before any data
- * has been seen for some components, and thus before their Q-tables have
- * been saved away. To handle this case, multiplier tables are preset
- * to zeroes; the result of the IDCT will be a neutral gray level.
- */
-
-
-/* Private subobject for this module */
-
-typedef struct {
- struct jpeg_inverse_dct pub; /* public fields */
-
- /* This array contains the IDCT method code that each multiplier table
- * is currently set up for, or -1 if it's not yet set up.
- * The actual multiplier tables are pointed to by dct_table in the
- * per-component comp_info structures.
- */
- int cur_method[MAX_COMPONENTS];
-} my_idct_controller;
-
-typedef my_idct_controller * my_idct_ptr;
-
-
-/* Allocated multiplier tables: big enough for any supported variant */
-
-typedef union {
- ISLOW_MULT_TYPE islow_array[DCTSIZE2];
-#ifdef DCT_IFAST_SUPPORTED
- IFAST_MULT_TYPE ifast_array[DCTSIZE2];
-#endif
-#ifdef DCT_FLOAT_SUPPORTED
- FLOAT_MULT_TYPE float_array[DCTSIZE2];
-#endif
-} multiplier_table;
-
-
-/* The current scaled-IDCT routines require ISLOW-style multiplier tables,
- * so be sure to compile that code if either ISLOW or SCALING is requested.
- */
-#ifdef DCT_ISLOW_SUPPORTED
-#define PROVIDE_ISLOW_TABLES
-#else
-#ifdef IDCT_SCALING_SUPPORTED
-#define PROVIDE_ISLOW_TABLES
-#endif
-#endif
-
-
-/*
- * Prepare for an output pass.
- * Here we select the proper IDCT routine for each component and build
- * a matching multiplier table.
- */
-
-METHODDEF(void)
-start_pass (j_decompress_ptr cinfo)
-{
- my_idct_ptr idct = (my_idct_ptr) cinfo->idct;
- int ci, i;
- jpeg_component_info *compptr;
- int method = 0;
- inverse_DCT_method_ptr method_ptr = NULL;
- JQUANT_TBL * qtbl;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* Select the proper IDCT routine for this component's scaling */
- switch (compptr->DCT_scaled_size) {
-#ifdef IDCT_SCALING_SUPPORTED
- case 1:
- method_ptr = jpeg_idct_1x1;
- method = JDCT_ISLOW; /* jidctred uses islow-style table */
- break;
- case 2:
- method_ptr = jpeg_idct_2x2;
- method = JDCT_ISLOW; /* jidctred uses islow-style table */
- break;
- case 4:
- method_ptr = jpeg_idct_4x4;
- method = JDCT_ISLOW; /* jidctred uses islow-style table */
- break;
-#endif
- case DCTSIZE:
- switch (cinfo->dct_method) {
-#ifdef DCT_ISLOW_SUPPORTED
- case JDCT_ISLOW:
- method_ptr = jpeg_idct_islow;
- method = JDCT_ISLOW;
- break;
-#endif
-#ifdef DCT_IFAST_SUPPORTED
- case JDCT_IFAST:
- method_ptr = jpeg_idct_ifast;
- method = JDCT_IFAST;
- break;
-#endif
-#ifdef DCT_FLOAT_SUPPORTED
- case JDCT_FLOAT:
- method_ptr = jpeg_idct_float;
- method = JDCT_FLOAT;
- break;
-#endif
- default:
- ERREXIT(cinfo, JERR_NOT_COMPILED);
- break;
- }
- break;
- default:
- ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->DCT_scaled_size);
- break;
- }
- idct->pub.inverse_DCT[ci] = method_ptr;
- /* Create multiplier table from quant table.
- * However, we can skip this if the component is uninteresting
- * or if we already built the table. Also, if no quant table
- * has yet been saved for the component, we leave the
- * multiplier table all-zero; we'll be reading zeroes from the
- * coefficient controller's buffer anyway.
- */
- if (! compptr->component_needed || idct->cur_method[ci] == method)
- continue;
- qtbl = compptr->quant_table;
- if (qtbl == NULL) /* happens if no data yet for component */
- continue;
- idct->cur_method[ci] = method;
- switch (method) {
-#ifdef PROVIDE_ISLOW_TABLES
- case JDCT_ISLOW:
- {
- /* For LL&M IDCT method, multipliers are equal to raw quantization
- * coefficients, but are stored as ints to ensure access efficiency.
- */
- ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table;
- for (i = 0; i < DCTSIZE2; i++) {
- ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i];
- }
- }
- break;
-#endif
-#ifdef DCT_IFAST_SUPPORTED
- case JDCT_IFAST:
- {
- /* For AA&N IDCT method, multipliers are equal to quantization
- * coefficients scaled by scalefactor[row]*scalefactor[col], where
- * scalefactor[0] = 1
- * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
- * For integer operation, the multiplier table is to be scaled by
- * IFAST_SCALE_BITS.
- */
- IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table;
-#define CONST_BITS 14
- static const INT16 aanscales[DCTSIZE2] = {
- /* precomputed values scaled up by 14 bits */
- 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
- 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
- 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
- 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
- 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
- 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
- 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
- 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
- };
- SHIFT_TEMPS
-
- for (i = 0; i < DCTSIZE2; i++) {
- ifmtbl[i] = (IFAST_MULT_TYPE)
- DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
- (INT32) aanscales[i]),
- CONST_BITS-IFAST_SCALE_BITS);
- }
- }
- break;
-#endif
-#ifdef DCT_FLOAT_SUPPORTED
- case JDCT_FLOAT:
- {
- /* For float AA&N IDCT method, multipliers are equal to quantization
- * coefficients scaled by scalefactor[row]*scalefactor[col], where
- * scalefactor[0] = 1
- * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
- */
- FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table;
- int row, col;
- static const double aanscalefactor[DCTSIZE] = {
- 1.0, 1.387039845, 1.306562965, 1.175875602,
- 1.0, 0.785694958, 0.541196100, 0.275899379
- };
-
- i = 0;
- for (row = 0; row < DCTSIZE; row++) {
- for (col = 0; col < DCTSIZE; col++) {
- fmtbl[i] = (FLOAT_MULT_TYPE)
- ((double) qtbl->quantval[i] *
- aanscalefactor[row] * aanscalefactor[col]);
- i++;
- }
- }
- }
- break;
-#endif
- default:
- ERREXIT(cinfo, JERR_NOT_COMPILED);
- break;
- }
- }
-}
-
-
-/*
- * Initialize IDCT manager.
- */
-
-GLOBAL(void)
-jinit_inverse_dct (j_decompress_ptr cinfo)
-{
- my_idct_ptr idct;
- int ci;
- jpeg_component_info *compptr;
-
- idct = (my_idct_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_idct_controller));
- cinfo->idct = (struct jpeg_inverse_dct *) idct;
- idct->pub.start_pass = start_pass;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* Allocate and pre-zero a multiplier table for each component */
- compptr->dct_table =
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(multiplier_table));
- MEMZERO(compptr->dct_table, SIZEOF(multiplier_table));
- /* Mark multiplier table not yet set up for any method */
- idct->cur_method[ci] = -1;
- }
-}
diff --git a/engine/code/jpeg-6b/jdhuff.c b/engine/code/jpeg-6b/jdhuff.c
deleted file mode 100644
index b5ba39f..0000000
--- a/engine/code/jpeg-6b/jdhuff.c
+++ /dev/null
@@ -1,651 +0,0 @@
-/*
- * jdhuff.c
- *
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains Huffman entropy decoding routines.
- *
- * Much of the complexity here has to do with supporting input suspension.
- * If the data source module demands suspension, we want to be able to back
- * up to the start of the current MCU. To do this, we copy state variables
- * into local working storage, and update them back to the permanent
- * storage only upon successful completion of an MCU.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jdhuff.h" /* Declarations shared with jdphuff.c */
-
-
-/*
- * Expanded entropy decoder object for Huffman decoding.
- *
- * The savable_state subrecord contains fields that change within an MCU,
- * but must not be updated permanently until we complete the MCU.
- */
-
-typedef struct {
- int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
-} savable_state;
-
-/* This macro is to work around compilers with missing or broken
- * structure assignment. You'll need to fix this code if you have
- * such a compiler and you change MAX_COMPS_IN_SCAN.
- */
-
-#ifndef NO_STRUCT_ASSIGN
-#define ASSIGN_STATE(dest,src) ((dest) = (src))
-#else
-#if MAX_COMPS_IN_SCAN == 4
-#define ASSIGN_STATE(dest,src) \
- ((dest).last_dc_val[0] = (src).last_dc_val[0], \
- (dest).last_dc_val[1] = (src).last_dc_val[1], \
- (dest).last_dc_val[2] = (src).last_dc_val[2], \
- (dest).last_dc_val[3] = (src).last_dc_val[3])
-#endif
-#endif
-
-
-typedef struct {
- struct jpeg_entropy_decoder pub; /* public fields */
-
- /* These fields are loaded into local variables at start of each MCU.
- * In case of suspension, we exit WITHOUT updating them.
- */
- bitread_perm_state bitstate; /* Bit buffer at start of MCU */
- savable_state saved; /* Other state at start of MCU */
-
- /* These fields are NOT loaded into local working state. */
- unsigned int restarts_to_go; /* MCUs left in this restart interval */
-
- /* Pointers to derived tables (these workspaces have image lifespan) */
- d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
- d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
-
- /* Precalculated info set up by start_pass for use in decode_mcu: */
-
- /* Pointers to derived tables to be used for each block within an MCU */
- d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU];
- d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU];
- /* Whether we care about the DC and AC coefficient values for each block */
- boolean dc_needed[D_MAX_BLOCKS_IN_MCU];
- boolean ac_needed[D_MAX_BLOCKS_IN_MCU];
-} huff_entropy_decoder;
-
-typedef huff_entropy_decoder * huff_entropy_ptr;
-
-
-/*
- * Initialize for a Huffman-compressed scan.
- */
-
-METHODDEF(void)
-start_pass_huff_decoder (j_decompress_ptr cinfo)
-{
- huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
- int ci, blkn, dctbl, actbl;
- jpeg_component_info * compptr;
-
- /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
- * This ought to be an error condition, but we make it a warning because
- * there are some baseline files out there with all zeroes in these bytes.
- */
- if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2-1 ||
- cinfo->Ah != 0 || cinfo->Al != 0)
- WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
-
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- dctbl = compptr->dc_tbl_no;
- actbl = compptr->ac_tbl_no;
- /* Compute derived values for Huffman tables */
- /* We may do this more than once for a table, but it's not expensive */
- jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl,
- & entropy->dc_derived_tbls[dctbl]);
- jpeg_make_d_derived_tbl(cinfo, FALSE, actbl,
- & entropy->ac_derived_tbls[actbl]);
- /* Initialize DC predictions to 0 */
- entropy->saved.last_dc_val[ci] = 0;
- }
-
- /* Precalculate decoding info for each block in an MCU of this scan */
- for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
- ci = cinfo->MCU_membership[blkn];
- compptr = cinfo->cur_comp_info[ci];
- /* Precalculate which table to use for each block */
- entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no];
- entropy->ac_cur_tbls[blkn] = entropy->ac_derived_tbls[compptr->ac_tbl_no];
- /* Decide whether we really care about the coefficient values */
- if (compptr->component_needed) {
- entropy->dc_needed[blkn] = TRUE;
- /* we don't need the ACs if producing a 1/8th-size image */
- entropy->ac_needed[blkn] = (compptr->DCT_scaled_size > 1);
- } else {
- entropy->dc_needed[blkn] = entropy->ac_needed[blkn] = FALSE;
- }
- }
-
- /* Initialize bitread state variables */
- entropy->bitstate.bits_left = 0;
- entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
- entropy->pub.insufficient_data = FALSE;
-
- /* Initialize restart counter */
- entropy->restarts_to_go = cinfo->restart_interval;
-}
-
-
-/*
- * Compute the derived values for a Huffman table.
- * This routine also performs some validation checks on the table.
- *
- * Note this is also used by jdphuff.c.
- */
-
-GLOBAL(void)
-jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
- d_derived_tbl ** pdtbl)
-{
- JHUFF_TBL *htbl;
- d_derived_tbl *dtbl;
- int p, i, l, si, numsymbols;
- int lookbits, ctr;
- char huffsize[257];
- unsigned int huffcode[257];
- unsigned int code;
-
- /* Note that huffsize[] and huffcode[] are filled in code-length order,
- * paralleling the order of the symbols themselves in htbl->huffval[].
- */
-
- /* Find the input Huffman table */
- if (tblno < 0 || tblno >= NUM_HUFF_TBLS)
- ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
- htbl =
- isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno];
- if (htbl == NULL)
- ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
-
- /* Allocate a workspace if we haven't already done so. */
- if (*pdtbl == NULL)
- *pdtbl = (d_derived_tbl *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(d_derived_tbl));
- dtbl = *pdtbl;
- dtbl->pub = htbl; /* fill in back link */
-
- /* Figure C.1: make table of Huffman code length for each symbol */
-
- p = 0;
- for (l = 1; l <= 16; l++) {
- i = (int) htbl->bits[l];
- if (i < 0 || p + i > 256) /* protect against table overrun */
- ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
- while (i--)
- huffsize[p++] = (char) l;
- }
- huffsize[p] = 0;
- numsymbols = p;
-
- /* Figure C.2: generate the codes themselves */
- /* We also validate that the counts represent a legal Huffman code tree. */
-
- code = 0;
- si = huffsize[0];
- p = 0;
- while (huffsize[p]) {
- while (((int) huffsize[p]) == si) {
- huffcode[p++] = code;
- code++;
- }
- /* code is now 1 more than the last code used for codelength si; but
- * it must still fit in si bits, since no code is allowed to be all ones.
- */
- if (((INT32) code) >= (((INT32) 1) << si))
- ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
- code <<= 1;
- si++;
- }
-
- /* Figure F.15: generate decoding tables for bit-sequential decoding */
-
- p = 0;
- for (l = 1; l <= 16; l++) {
- if (htbl->bits[l]) {
- /* valoffset[l] = huffval[] index of 1st symbol of code length l,
- * minus the minimum code of length l
- */
- dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p];
- p += htbl->bits[l];
- dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */
- } else {
- dtbl->maxcode[l] = -1; /* -1 if no codes of this length */
- }
- }
- dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */
-
- /* Compute lookahead tables to speed up decoding.
- * First we set all the table entries to 0, indicating "too long";
- * then we iterate through the Huffman codes that are short enough and
- * fill in all the entries that correspond to bit sequences starting
- * with that code.
- */
-
- MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits));
-
- p = 0;
- for (l = 1; l <= HUFF_LOOKAHEAD; l++) {
- for (i = 1; i <= (int) htbl->bits[l]; i++, p++) {
- /* l = current code's length, p = its index in huffcode[] & huffval[]. */
- /* Generate left-justified code followed by all possible bit sequences */
- lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l);
- for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) {
- dtbl->look_nbits[lookbits] = l;
- dtbl->look_sym[lookbits] = htbl->huffval[p];
- lookbits++;
- }
- }
- }
-
- /* Validate symbols as being reasonable.
- * For AC tables, we make no check, but accept all byte values 0..255.
- * For DC tables, we require the symbols to be in range 0..15.
- * (Tighter bounds could be applied depending on the data depth and mode,
- * but this is sufficient to ensure safe decoding.)
- */
- if (isDC) {
- for (i = 0; i < numsymbols; i++) {
- int sym = htbl->huffval[i];
- if (sym < 0 || sym > 15)
- ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
- }
- }
-}
-
-
-/*
- * Out-of-line code for bit fetching (shared with jdphuff.c).
- * See jdhuff.h for info about usage.
- * Note: current values of get_buffer and bits_left are passed as parameters,
- * but are returned in the corresponding fields of the state struct.
- *
- * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width
- * of get_buffer to be used. (On machines with wider words, an even larger
- * buffer could be used.) However, on some machines 32-bit shifts are
- * quite slow and take time proportional to the number of places shifted.
- * (This is true with most PC compilers, for instance.) In this case it may
- * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the
- * average shift distance at the cost of more calls to jpeg_fill_bit_buffer.
- */
-
-#ifdef SLOW_SHIFT_32
-#define MIN_GET_BITS 15 /* minimum allowable value */
-#else
-#define MIN_GET_BITS (BIT_BUF_SIZE-7)
-#endif
-
-
-GLOBAL(boolean)
-jpeg_fill_bit_buffer (bitread_working_state * state,
- register bit_buf_type get_buffer, register int bits_left,
- int nbits)
-/* Load up the bit buffer to a depth of at least nbits */
-{
- /* Copy heavily used state fields into locals (hopefully registers) */
- register const JOCTET * next_input_byte = state->next_input_byte;
- register size_t bytes_in_buffer = state->bytes_in_buffer;
- j_decompress_ptr cinfo = state->cinfo;
-
- /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */
- /* (It is assumed that no request will be for more than that many bits.) */
- /* We fail to do so only if we hit a marker or are forced to suspend. */
-
- if (cinfo->unread_marker == 0) { /* cannot advance past a marker */
- while (bits_left < MIN_GET_BITS) {
- register int c;
-
- /* Attempt to read a byte */
- if (bytes_in_buffer == 0) {
- if (! (*cinfo->src->fill_input_buffer) (cinfo))
- return FALSE;
- next_input_byte = cinfo->src->next_input_byte;
- bytes_in_buffer = cinfo->src->bytes_in_buffer;
- }
- bytes_in_buffer--;
- c = GETJOCTET(*next_input_byte++);
-
- /* If it's 0xFF, check and discard stuffed zero byte */
- if (c == 0xFF) {
- /* Loop here to discard any padding FF's on terminating marker,
- * so that we can save a valid unread_marker value. NOTE: we will
- * accept multiple FF's followed by a 0 as meaning a single FF data
- * byte. This data pattern is not valid according to the standard.
- */
- do {
- if (bytes_in_buffer == 0) {
- if (! (*cinfo->src->fill_input_buffer) (cinfo))
- return FALSE;
- next_input_byte = cinfo->src->next_input_byte;
- bytes_in_buffer = cinfo->src->bytes_in_buffer;
- }
- bytes_in_buffer--;
- c = GETJOCTET(*next_input_byte++);
- } while (c == 0xFF);
-
- if (c == 0) {
- /* Found FF/00, which represents an FF data byte */
- c = 0xFF;
- } else {
- /* Oops, it's actually a marker indicating end of compressed data.
- * Save the marker code for later use.
- * Fine point: it might appear that we should save the marker into
- * bitread working state, not straight into permanent state. But
- * once we have hit a marker, we cannot need to suspend within the
- * current MCU, because we will read no more bytes from the data
- * source. So it is OK to update permanent state right away.
- */
- cinfo->unread_marker = c;
- /* See if we need to insert some fake zero bits. */
- goto no_more_bytes;
- }
- }
-
- /* OK, load c into get_buffer */
- get_buffer = (get_buffer << 8) | c;
- bits_left += 8;
- } /* end while */
- } else {
- no_more_bytes:
- /* We get here if we've read the marker that terminates the compressed
- * data segment. There should be enough bits in the buffer register
- * to satisfy the request; if so, no problem.
- */
- if (nbits > bits_left) {
- /* Uh-oh. Report corrupted data to user and stuff zeroes into
- * the data stream, so that we can produce some kind of image.
- * We use a nonvolatile flag to ensure that only one warning message
- * appears per data segment.
- */
- if (! cinfo->entropy->insufficient_data) {
- WARNMS(cinfo, JWRN_HIT_MARKER);
- cinfo->entropy->insufficient_data = TRUE;
- }
- /* Fill the buffer with zero bits */
- get_buffer <<= MIN_GET_BITS - bits_left;
- bits_left = MIN_GET_BITS;
- }
- }
-
- /* Unload the local registers */
- state->next_input_byte = next_input_byte;
- state->bytes_in_buffer = bytes_in_buffer;
- state->get_buffer = get_buffer;
- state->bits_left = bits_left;
-
- return TRUE;
-}
-
-
-/*
- * Out-of-line code for Huffman code decoding.
- * See jdhuff.h for info about usage.
- */
-
-GLOBAL(int)
-jpeg_huff_decode (bitread_working_state * state,
- register bit_buf_type get_buffer, register int bits_left,
- d_derived_tbl * htbl, int min_bits)
-{
- register int l = min_bits;
- register INT32 code;
-
- /* HUFF_DECODE has determined that the code is at least min_bits */
- /* bits long, so fetch that many bits in one swoop. */
-
- CHECK_BIT_BUFFER(*state, l, return -1);
- code = GET_BITS(l);
-
- /* Collect the rest of the Huffman code one bit at a time. */
- /* This is per Figure F.16 in the JPEG spec. */
-
- while (code > htbl->maxcode[l]) {
- code <<= 1;
- CHECK_BIT_BUFFER(*state, 1, return -1);
- code |= GET_BITS(1);
- l++;
- }
-
- /* Unload the local registers */
- state->get_buffer = get_buffer;
- state->bits_left = bits_left;
-
- /* With garbage input we may reach the sentinel value l = 17. */
-
- if (l > 16) {
- WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE);
- return 0; /* fake a zero as the safest result */
- }
-
- return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ];
-}
-
-
-/*
- * Figure F.12: extend sign bit.
- * On some machines, a shift and add will be faster than a table lookup.
- */
-
-#ifdef AVOID_TABLES
-
-#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x))
-
-#else
-
-#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
-
-static const int extend_test[16] = /* entry n is 2**(n-1) */
- { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
- 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 };
-
-static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */
- { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1,
- ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1,
- ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1,
- ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 };
-
-#endif /* AVOID_TABLES */
-
-
-/*
- * Check for a restart marker & resynchronize decoder.
- * Returns FALSE if must suspend.
- */
-
-LOCAL(boolean)
-process_restart (j_decompress_ptr cinfo)
-{
- huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
- int ci;
-
- /* Throw away any unused bits remaining in bit buffer; */
- /* include any full bytes in next_marker's count of discarded bytes */
- cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;
- entropy->bitstate.bits_left = 0;
-
- /* Advance past the RSTn marker */
- if (! (*cinfo->marker->read_restart_marker) (cinfo))
- return FALSE;
-
- /* Re-initialize DC predictions to 0 */
- for (ci = 0; ci < cinfo->comps_in_scan; ci++)
- entropy->saved.last_dc_val[ci] = 0;
-
- /* Reset restart counter */
- entropy->restarts_to_go = cinfo->restart_interval;
-
- /* Reset out-of-data flag, unless read_restart_marker left us smack up
- * against a marker. In that case we will end up treating the next data
- * segment as empty, and we can avoid producing bogus output pixels by
- * leaving the flag set.
- */
- if (cinfo->unread_marker == 0)
- entropy->pub.insufficient_data = FALSE;
-
- return TRUE;
-}
-
-
-/*
- * Decode and return one MCU's worth of Huffman-compressed coefficients.
- * The coefficients are reordered from zigzag order into natural array order,
- * but are not dequantized.
- *
- * The i'th block of the MCU is stored into the block pointed to by
- * MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER.
- * (Wholesale zeroing is usually a little faster than retail...)
- *
- * Returns FALSE if data source requested suspension. In that case no
- * changes have been made to permanent state. (Exception: some output
- * coefficients may already have been assigned. This is harmless for
- * this module, since we'll just re-assign them on the next call.)
- */
-
-METHODDEF(boolean)
-decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
-{
- huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
- int blkn;
- BITREAD_STATE_VARS;
- savable_state state;
-
- /* Process restart marker if needed; may have to suspend */
- if (cinfo->restart_interval) {
- if (entropy->restarts_to_go == 0)
- if (! process_restart(cinfo))
- return FALSE;
- }
-
- /* If we've run out of data, just leave the MCU set to zeroes.
- * This way, we return uniform gray for the remainder of the segment.
- */
- if (! entropy->pub.insufficient_data) {
-
- /* Load up working state */
- BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
- ASSIGN_STATE(state, entropy->saved);
-
- /* Outer loop handles each block in the MCU */
-
- for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
- JBLOCKROW block = MCU_data[blkn];
- d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
- d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
- register int s, k, r;
-
- /* Decode a single block's worth of coefficients */
-
- /* Section F.2.2.1: decode the DC coefficient difference */
- HUFF_DECODE(s, br_state, dctbl, return FALSE, label1);
- if (s) {
- CHECK_BIT_BUFFER(br_state, s, return FALSE);
- r = GET_BITS(s);
- s = HUFF_EXTEND(r, s);
- }
-
- if (entropy->dc_needed[blkn]) {
- /* Convert DC difference to actual value, update last_dc_val */
- int ci = cinfo->MCU_membership[blkn];
- s += state.last_dc_val[ci];
- state.last_dc_val[ci] = s;
- /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */
- (*block)[0] = (JCOEF) s;
- }
-
- if (entropy->ac_needed[blkn]) {
-
- /* Section F.2.2.2: decode the AC coefficients */
- /* Since zeroes are skipped, output area must be cleared beforehand */
- for (k = 1; k < DCTSIZE2; k++) {
- HUFF_DECODE(s, br_state, actbl, return FALSE, label2);
-
- r = s >> 4;
- s &= 15;
-
- if (s) {
- k += r;
- CHECK_BIT_BUFFER(br_state, s, return FALSE);
- r = GET_BITS(s);
- s = HUFF_EXTEND(r, s);
- /* Output coefficient in natural (dezigzagged) order.
- * Note: the extra entries in jpeg_natural_order[] will save us
- * if k >= DCTSIZE2, which could happen if the data is corrupted.
- */
- (*block)[jpeg_natural_order[k]] = (JCOEF) s;
- } else {
- if (r != 15)
- break;
- k += 15;
- }
- }
-
- } else {
-
- /* Section F.2.2.2: decode the AC coefficients */
- /* In this path we just discard the values */
- for (k = 1; k < DCTSIZE2; k++) {
- HUFF_DECODE(s, br_state, actbl, return FALSE, label3);
-
- r = s >> 4;
- s &= 15;
-
- if (s) {
- k += r;
- CHECK_BIT_BUFFER(br_state, s, return FALSE);
- DROP_BITS(s);
- } else {
- if (r != 15)
- break;
- k += 15;
- }
- }
-
- }
- }
-
- /* Completed MCU, so update state */
- BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
- ASSIGN_STATE(entropy->saved, state);
- }
-
- /* Account for restart interval (no-op if not using restarts) */
- entropy->restarts_to_go--;
-
- return TRUE;
-}
-
-
-/*
- * Module initialization routine for Huffman entropy decoding.
- */
-
-GLOBAL(void)
-jinit_huff_decoder (j_decompress_ptr cinfo)
-{
- huff_entropy_ptr entropy;
- int i;
-
- entropy = (huff_entropy_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(huff_entropy_decoder));
- cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
- entropy->pub.start_pass = start_pass_huff_decoder;
- entropy->pub.decode_mcu = decode_mcu;
-
- /* Mark tables unallocated */
- for (i = 0; i < NUM_HUFF_TBLS; i++) {
- entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
- }
-}
diff --git a/engine/code/jpeg-6b/jdhuff.h b/engine/code/jpeg-6b/jdhuff.h
deleted file mode 100644
index ae19b6c..0000000
--- a/engine/code/jpeg-6b/jdhuff.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * jdhuff.h
- *
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains declarations for Huffman entropy decoding routines
- * that are shared between the sequential decoder (jdhuff.c) and the
- * progressive decoder (jdphuff.c). No other modules need to see these.
- */
-
-/* Short forms of external names for systems with brain-damaged linkers. */
-
-#ifdef NEED_SHORT_EXTERNAL_NAMES
-#define jpeg_make_d_derived_tbl jMkDDerived
-#define jpeg_fill_bit_buffer jFilBitBuf
-#define jpeg_huff_decode jHufDecode
-#endif /* NEED_SHORT_EXTERNAL_NAMES */
-
-
-/* Derived data constructed for each Huffman table */
-
-#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */
-
-typedef struct {
- /* Basic tables: (element [0] of each array is unused) */
- INT32 maxcode[18]; /* largest code of length k (-1 if none) */
- /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */
- INT32 valoffset[17]; /* huffval[] offset for codes of length k */
- /* valoffset[k] = huffval[] index of 1st symbol of code length k, less
- * the smallest code of length k; so given a code of length k, the
- * corresponding symbol is huffval[code + valoffset[k]]
- */
-
- /* Link to public Huffman table (needed only in jpeg_huff_decode) */
- JHUFF_TBL *pub;
-
- /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of
- * the input data stream. If the next Huffman code is no more
- * than HUFF_LOOKAHEAD bits long, we can obtain its length and
- * the corresponding symbol directly from these tables.
- */
- int look_nbits[1<<HUFF_LOOKAHEAD]; /* # bits, or 0 if too long */
- UINT8 look_sym[1<<HUFF_LOOKAHEAD]; /* symbol, or unused */
-} d_derived_tbl;
-
-/* Expand a Huffman table definition into the derived format */
-EXTERN(void) jpeg_make_d_derived_tbl
- JPP((j_decompress_ptr cinfo, boolean isDC, int tblno,
- d_derived_tbl ** pdtbl));
-
-
-/*
- * Fetching the next N bits from the input stream is a time-critical operation
- * for the Huffman decoders. We implement it with a combination of inline
- * macros and out-of-line subroutines. Note that N (the number of bits
- * demanded at one time) never exceeds 15 for JPEG use.
- *
- * We read source bytes into get_buffer and dole out bits as needed.
- * If get_buffer already contains enough bits, they are fetched in-line
- * by the macros CHECK_BIT_BUFFER and GET_BITS. When there aren't enough
- * bits, jpeg_fill_bit_buffer is called; it will attempt to fill get_buffer
- * as full as possible (not just to the number of bits needed; this
- * prefetching reduces the overhead cost of calling jpeg_fill_bit_buffer).
- * Note that jpeg_fill_bit_buffer may return FALSE to indicate suspension.
- * On TRUE return, jpeg_fill_bit_buffer guarantees that get_buffer contains
- * at least the requested number of bits --- dummy zeroes are inserted if
- * necessary.
- */
-
-typedef INT32 bit_buf_type; /* type of bit-extraction buffer */
-#define BIT_BUF_SIZE 32 /* size of buffer in bits */
-
-/* If long is > 32 bits on your machine, and shifting/masking longs is
- * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE
- * appropriately should be a win. Unfortunately we can't define the size
- * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8)
- * because not all machines measure sizeof in 8-bit bytes.
- */
-
-typedef struct { /* Bitreading state saved across MCUs */
- bit_buf_type get_buffer; /* current bit-extraction buffer */
- int bits_left; /* # of unused bits in it */
-} bitread_perm_state;
-
-typedef struct { /* Bitreading working state within an MCU */
- /* Current data source location */
- /* We need a copy, rather than munging the original, in case of suspension */
- const JOCTET * next_input_byte; /* => next byte to read from source */
- size_t bytes_in_buffer; /* # of bytes remaining in source buffer */
- /* Bit input buffer --- note these values are kept in register variables,
- * not in this struct, inside the inner loops.
- */
- bit_buf_type get_buffer; /* current bit-extraction buffer */
- int bits_left; /* # of unused bits in it */
- /* Pointer needed by jpeg_fill_bit_buffer. */
- j_decompress_ptr cinfo; /* back link to decompress master record */
-} bitread_working_state;
-
-/* Macros to declare and load/save bitread local variables. */
-#define BITREAD_STATE_VARS \
- register bit_buf_type get_buffer; \
- register int bits_left; \
- bitread_working_state br_state
-
-#define BITREAD_LOAD_STATE(cinfop,permstate) \
- br_state.cinfo = cinfop; \
- br_state.next_input_byte = cinfop->src->next_input_byte; \
- br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \
- get_buffer = permstate.get_buffer; \
- bits_left = permstate.bits_left;
-
-#define BITREAD_SAVE_STATE(cinfop,permstate) \
- cinfop->src->next_input_byte = br_state.next_input_byte; \
- cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \
- permstate.get_buffer = get_buffer; \
- permstate.bits_left = bits_left
-
-/*
- * These macros provide the in-line portion of bit fetching.
- * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer
- * before using GET_BITS, PEEK_BITS, or DROP_BITS.
- * The variables get_buffer and bits_left are assumed to be locals,
- * but the state struct might not be (jpeg_huff_decode needs this).
- * CHECK_BIT_BUFFER(state,n,action);
- * Ensure there are N bits in get_buffer; if suspend, take action.
- * val = GET_BITS(n);
- * Fetch next N bits.
- * val = PEEK_BITS(n);
- * Fetch next N bits without removing them from the buffer.
- * DROP_BITS(n);
- * Discard next N bits.
- * The value N should be a simple variable, not an expression, because it
- * is evaluated multiple times.
- */
-
-#define CHECK_BIT_BUFFER(state,nbits,action) \
- { if (bits_left < (nbits)) { \
- if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \
- { action; } \
- get_buffer = (state).get_buffer; bits_left = (state).bits_left; } }
-
-#define GET_BITS(nbits) \
- (((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1))
-
-#define PEEK_BITS(nbits) \
- (((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1))
-
-#define DROP_BITS(nbits) \
- (bits_left -= (nbits))
-
-/* Load up the bit buffer to a depth of at least nbits */
-EXTERN(boolean) jpeg_fill_bit_buffer
- JPP((bitread_working_state * state, register bit_buf_type get_buffer,
- register int bits_left, int nbits));
-
-
-/*
- * Code for extracting next Huffman-coded symbol from input bit stream.
- * Again, this is time-critical and we make the main paths be macros.
- *
- * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits
- * without looping. Usually, more than 95% of the Huffman codes will be 8
- * or fewer bits long. The few overlength codes are handled with a loop,
- * which need not be inline code.
- *
- * Notes about the HUFF_DECODE macro:
- * 1. Near the end of the data segment, we may fail to get enough bits
- * for a lookahead. In that case, we do it the hard way.
- * 2. If the lookahead table contains no entry, the next code must be
- * more than HUFF_LOOKAHEAD bits long.
- * 3. jpeg_huff_decode returns -1 if forced to suspend.
- */
-
-#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \
-{ register int nb, look; \
- if (bits_left < HUFF_LOOKAHEAD) { \
- if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \
- get_buffer = state.get_buffer; bits_left = state.bits_left; \
- if (bits_left < HUFF_LOOKAHEAD) { \
- nb = 1; goto slowlabel; \
- } \
- } \
- look = PEEK_BITS(HUFF_LOOKAHEAD); \
- if ((nb = htbl->look_nbits[look]) != 0) { \
- DROP_BITS(nb); \
- result = htbl->look_sym[look]; \
- } else { \
- nb = HUFF_LOOKAHEAD+1; \
-slowlabel: \
- if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \
- { failaction; } \
- get_buffer = state.get_buffer; bits_left = state.bits_left; \
- } \
-}
-
-/* Out-of-line case for Huffman code fetching */
-EXTERN(int) jpeg_huff_decode
- JPP((bitread_working_state * state, register bit_buf_type get_buffer,
- register int bits_left, d_derived_tbl * htbl, int min_bits));
diff --git a/engine/code/jpeg-6b/jdinput.c b/engine/code/jpeg-6b/jdinput.c
deleted file mode 100644
index 0c2ac8f..0000000
--- a/engine/code/jpeg-6b/jdinput.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * jdinput.c
- *
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains input control logic for the JPEG decompressor.
- * These routines are concerned with controlling the decompressor's input
- * processing (marker reading and coefficient decoding). The actual input
- * reading is done in jdmarker.c, jdhuff.c, and jdphuff.c.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* Private state */
-
-typedef struct {
- struct jpeg_input_controller pub; /* public fields */
-
- boolean inheaders; /* TRUE until first SOS is reached */
-} my_input_controller;
-
-typedef my_input_controller * my_inputctl_ptr;
-
-
-/* Forward declarations */
-METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo));
-
-
-/*
- * Routines to calculate various quantities related to the size of the image.
- */
-
-LOCAL(void)
-initial_setup (j_decompress_ptr cinfo)
-/* Called once, when first SOS marker is reached */
-{
- int ci;
- jpeg_component_info *compptr;
-
- /* Make sure image isn't bigger than I can handle */
- if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||
- (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)
- ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
-
- /* For now, precision must match compiled-in value... */
- if (cinfo->data_precision != BITS_IN_JSAMPLE)
- ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
-
- /* Check that number of components won't exceed internal array sizes */
- if (cinfo->num_components > MAX_COMPONENTS)
- ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
- MAX_COMPONENTS);
-
- /* Compute maximum sampling factors; check factor validity */
- cinfo->max_h_samp_factor = 1;
- cinfo->max_v_samp_factor = 1;
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||
- compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
- ERREXIT(cinfo, JERR_BAD_SAMPLING);
- cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,
- compptr->h_samp_factor);
- cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,
- compptr->v_samp_factor);
- }
-
- /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE.
- * In the full decompressor, this will be overridden by jdmaster.c;
- * but in the transcoder, jdmaster.c is not used, so we must do it here.
- */
- cinfo->min_DCT_scaled_size = DCTSIZE;
-
- /* Compute dimensions of components */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- compptr->DCT_scaled_size = DCTSIZE;
- /* Size in DCT blocks */
- compptr->width_in_blocks = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
- (long) (cinfo->max_h_samp_factor * DCTSIZE));
- compptr->height_in_blocks = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
- (long) (cinfo->max_v_samp_factor * DCTSIZE));
- /* downsampled_width and downsampled_height will also be overridden by
- * jdmaster.c if we are doing full decompression. The transcoder library
- * doesn't use these values, but the calling application might.
- */
- /* Size in samples */
- compptr->downsampled_width = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
- (long) cinfo->max_h_samp_factor);
- compptr->downsampled_height = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
- (long) cinfo->max_v_samp_factor);
- /* Mark component needed, until color conversion says otherwise */
- compptr->component_needed = TRUE;
- /* Mark no quantization table yet saved for component */
- compptr->quant_table = NULL;
- }
-
- /* Compute number of fully interleaved MCU rows. */
- cinfo->total_iMCU_rows = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_height,
- (long) (cinfo->max_v_samp_factor*DCTSIZE));
-
- /* Decide whether file contains multiple scans */
- if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode)
- cinfo->inputctl->has_multiple_scans = TRUE;
- else
- cinfo->inputctl->has_multiple_scans = FALSE;
-}
-
-
-LOCAL(void)
-per_scan_setup (j_decompress_ptr cinfo)
-/* Do computations that are needed before processing a JPEG scan */
-/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */
-{
- int ci, mcublks, tmp;
- jpeg_component_info *compptr;
-
- if (cinfo->comps_in_scan == 1) {
-
- /* Noninterleaved (single-component) scan */
- compptr = cinfo->cur_comp_info[0];
-
- /* Overall image size in MCUs */
- cinfo->MCUs_per_row = compptr->width_in_blocks;
- cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
-
- /* For noninterleaved scan, always one block per MCU */
- compptr->MCU_width = 1;
- compptr->MCU_height = 1;
- compptr->MCU_blocks = 1;
- compptr->MCU_sample_width = compptr->DCT_scaled_size;
- compptr->last_col_width = 1;
- /* For noninterleaved scans, it is convenient to define last_row_height
- * as the number of block rows present in the last iMCU row.
- */
- tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
- if (tmp == 0) tmp = compptr->v_samp_factor;
- compptr->last_row_height = tmp;
-
- /* Prepare array describing MCU composition */
- cinfo->blocks_in_MCU = 1;
- cinfo->MCU_membership[0] = 0;
-
- } else {
-
- /* Interleaved (multi-component) scan */
- if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)
- ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,
- MAX_COMPS_IN_SCAN);
-
- /* Overall image size in MCUs */
- cinfo->MCUs_per_row = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_width,
- (long) (cinfo->max_h_samp_factor*DCTSIZE));
- cinfo->MCU_rows_in_scan = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_height,
- (long) (cinfo->max_v_samp_factor*DCTSIZE));
-
- cinfo->blocks_in_MCU = 0;
-
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- /* Sampling factors give # of blocks of component in each MCU */
- compptr->MCU_width = compptr->h_samp_factor;
- compptr->MCU_height = compptr->v_samp_factor;
- compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
- compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_scaled_size;
- /* Figure number of non-dummy blocks in last MCU column & row */
- tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
- if (tmp == 0) tmp = compptr->MCU_width;
- compptr->last_col_width = tmp;
- tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
- if (tmp == 0) tmp = compptr->MCU_height;
- compptr->last_row_height = tmp;
- /* Prepare array describing MCU composition */
- mcublks = compptr->MCU_blocks;
- if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU)
- ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
- while (mcublks-- > 0) {
- cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
- }
- }
-
- }
-}
-
-
-/*
- * Save away a copy of the Q-table referenced by each component present
- * in the current scan, unless already saved during a prior scan.
- *
- * In a multiple-scan JPEG file, the encoder could assign different components
- * the same Q-table slot number, but change table definitions between scans
- * so that each component uses a different Q-table. (The IJG encoder is not
- * currently capable of doing this, but other encoders might.) Since we want
- * to be able to dequantize all the components at the end of the file, this
- * means that we have to save away the table actually used for each component.
- * We do this by copying the table at the start of the first scan containing
- * the component.
- * The JPEG spec prohibits the encoder from changing the contents of a Q-table
- * slot between scans of a component using that slot. If the encoder does so
- * anyway, this decoder will simply use the Q-table values that were current
- * at the start of the first scan for the component.
- *
- * The decompressor output side looks only at the saved quant tables,
- * not at the current Q-table slots.
- */
-
-LOCAL(void)
-latch_quant_tables (j_decompress_ptr cinfo)
-{
- int ci, qtblno;
- jpeg_component_info *compptr;
- JQUANT_TBL * qtbl;
-
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- /* No work if we already saved Q-table for this component */
- if (compptr->quant_table != NULL)
- continue;
- /* Make sure specified quantization table is present */
- qtblno = compptr->quant_tbl_no;
- if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
- cinfo->quant_tbl_ptrs[qtblno] == NULL)
- ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
- /* OK, save away the quantization table */
- qtbl = (JQUANT_TBL *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(JQUANT_TBL));
- MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL));
- compptr->quant_table = qtbl;
- }
-}
-
-
-/*
- * Initialize the input modules to read a scan of compressed data.
- * The first call to this is done by jdmaster.c after initializing
- * the entire decompressor (during jpeg_start_decompress).
- * Subsequent calls come from consume_markers, below.
- */
-
-METHODDEF(void)
-start_input_pass (j_decompress_ptr cinfo)
-{
- per_scan_setup(cinfo);
- latch_quant_tables(cinfo);
- (*cinfo->entropy->start_pass) (cinfo);
- (*cinfo->coef->start_input_pass) (cinfo);
- cinfo->inputctl->consume_input = cinfo->coef->consume_data;
-}
-
-
-/*
- * Finish up after inputting a compressed-data scan.
- * This is called by the coefficient controller after it's read all
- * the expected data of the scan.
- */
-
-METHODDEF(void)
-finish_input_pass (j_decompress_ptr cinfo)
-{
- cinfo->inputctl->consume_input = consume_markers;
-}
-
-
-/*
- * Read JPEG markers before, between, or after compressed-data scans.
- * Change state as necessary when a new scan is reached.
- * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
- *
- * The consume_input method pointer points either here or to the
- * coefficient controller's consume_data routine, depending on whether
- * we are reading a compressed data segment or inter-segment markers.
- */
-
-METHODDEF(int)
-consume_markers (j_decompress_ptr cinfo)
-{
- my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;
- int val;
-
- if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */
- return JPEG_REACHED_EOI;
-
- val = (*cinfo->marker->read_markers) (cinfo);
-
- switch (val) {
- case JPEG_REACHED_SOS: /* Found SOS */
- if (inputctl->inheaders) { /* 1st SOS */
- initial_setup(cinfo);
- inputctl->inheaders = FALSE;
- /* Note: start_input_pass must be called by jdmaster.c
- * before any more input can be consumed. jdapimin.c is
- * responsible for enforcing this sequencing.
- */
- } else { /* 2nd or later SOS marker */
- if (! inputctl->pub.has_multiple_scans)
- ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */
- start_input_pass(cinfo);
- }
- break;
- case JPEG_REACHED_EOI: /* Found EOI */
- inputctl->pub.eoi_reached = TRUE;
- if (inputctl->inheaders) { /* Tables-only datastream, apparently */
- if (cinfo->marker->saw_SOF)
- ERREXIT(cinfo, JERR_SOF_NO_SOS);
- } else {
- /* Prevent infinite loop in coef ctlr's decompress_data routine
- * if user set output_scan_number larger than number of scans.
- */
- if (cinfo->output_scan_number > cinfo->input_scan_number)
- cinfo->output_scan_number = cinfo->input_scan_number;
- }
- break;
- case JPEG_SUSPENDED:
- break;
- }
-
- return val;
-}
-
-
-/*
- * Reset state to begin a fresh datastream.
- */
-
-METHODDEF(void)
-reset_input_controller (j_decompress_ptr cinfo)
-{
- my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;
-
- inputctl->pub.consume_input = consume_markers;
- inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
- inputctl->pub.eoi_reached = FALSE;
- inputctl->inheaders = TRUE;
- /* Reset other modules */
- (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
- (*cinfo->marker->reset_marker_reader) (cinfo);
- /* Reset progression state -- would be cleaner if entropy decoder did this */
- cinfo->coef_bits = NULL;
-}
-
-
-/*
- * Initialize the input controller module.
- * This is called only once, when the decompression object is created.
- */
-
-GLOBAL(void)
-jinit_input_controller (j_decompress_ptr cinfo)
-{
- my_inputctl_ptr inputctl;
-
- /* Create subobject in permanent pool */
- inputctl = (my_inputctl_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- SIZEOF(my_input_controller));
- cinfo->inputctl = (struct jpeg_input_controller *) inputctl;
- /* Initialize method pointers */
- inputctl->pub.consume_input = consume_markers;
- inputctl->pub.reset_input_controller = reset_input_controller;
- inputctl->pub.start_input_pass = start_input_pass;
- inputctl->pub.finish_input_pass = finish_input_pass;
- /* Initialize state: can't use reset_input_controller since we don't
- * want to try to reset other modules yet.
- */
- inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
- inputctl->pub.eoi_reached = FALSE;
- inputctl->inheaders = TRUE;
-}
diff --git a/engine/code/jpeg-6b/jdmainct.c b/engine/code/jpeg-6b/jdmainct.c
deleted file mode 100644
index 2f26533..0000000
--- a/engine/code/jpeg-6b/jdmainct.c
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * jdmainct.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains the main buffer controller for decompression.
- * The main buffer lies between the JPEG decompressor proper and the
- * post-processor; it holds downsampled data in the JPEG colorspace.
- *
- * Note that this code is bypassed in raw-data mode, since the application
- * supplies the equivalent of the main buffer in that case.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/*
- * In the current system design, the main buffer need never be a full-image
- * buffer; any full-height buffers will be found inside the coefficient or
- * postprocessing controllers. Nonetheless, the main controller is not
- * trivial. Its responsibility is to provide context rows for upsampling/
- * rescaling, and doing this in an efficient fashion is a bit tricky.
- *
- * Postprocessor input data is counted in "row groups". A row group
- * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
- * sample rows of each component. (We require DCT_scaled_size values to be
- * chosen such that these numbers are integers. In practice DCT_scaled_size
- * values will likely be powers of two, so we actually have the stronger
- * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.)
- * Upsampling will typically produce max_v_samp_factor pixel rows from each
- * row group (times any additional scale factor that the upsampler is
- * applying).
- *
- * The coefficient controller will deliver data to us one iMCU row at a time;
- * each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or
- * exactly min_DCT_scaled_size row groups. (This amount of data corresponds
- * to one row of MCUs when the image is fully interleaved.) Note that the
- * number of sample rows varies across components, but the number of row
- * groups does not. Some garbage sample rows may be included in the last iMCU
- * row at the bottom of the image.
- *
- * Depending on the vertical scaling algorithm used, the upsampler may need
- * access to the sample row(s) above and below its current input row group.
- * The upsampler is required to set need_context_rows TRUE at global selection
- * time if so. When need_context_rows is FALSE, this controller can simply
- * obtain one iMCU row at a time from the coefficient controller and dole it
- * out as row groups to the postprocessor.
- *
- * When need_context_rows is TRUE, this controller guarantees that the buffer
- * passed to postprocessing contains at least one row group's worth of samples
- * above and below the row group(s) being processed. Note that the context
- * rows "above" the first passed row group appear at negative row offsets in
- * the passed buffer. At the top and bottom of the image, the required
- * context rows are manufactured by duplicating the first or last real sample
- * row; this avoids having special cases in the upsampling inner loops.
- *
- * The amount of context is fixed at one row group just because that's a
- * convenient number for this controller to work with. The existing
- * upsamplers really only need one sample row of context. An upsampler
- * supporting arbitrary output rescaling might wish for more than one row
- * group of context when shrinking the image; tough, we don't handle that.
- * (This is justified by the assumption that downsizing will be handled mostly
- * by adjusting the DCT_scaled_size values, so that the actual scale factor at
- * the upsample step needn't be much less than one.)
- *
- * To provide the desired context, we have to retain the last two row groups
- * of one iMCU row while reading in the next iMCU row. (The last row group
- * can't be processed until we have another row group for its below-context,
- * and so we have to save the next-to-last group too for its above-context.)
- * We could do this most simply by copying data around in our buffer, but
- * that'd be very slow. We can avoid copying any data by creating a rather
- * strange pointer structure. Here's how it works. We allocate a workspace
- * consisting of M+2 row groups (where M = min_DCT_scaled_size is the number
- * of row groups per iMCU row). We create two sets of redundant pointers to
- * the workspace. Labeling the physical row groups 0 to M+1, the synthesized
- * pointer lists look like this:
- * M+1 M-1
- * master pointer --> 0 master pointer --> 0
- * 1 1
- * ... ...
- * M-3 M-3
- * M-2 M
- * M-1 M+1
- * M M-2
- * M+1 M-1
- * 0 0
- * We read alternate iMCU rows using each master pointer; thus the last two
- * row groups of the previous iMCU row remain un-overwritten in the workspace.
- * The pointer lists are set up so that the required context rows appear to
- * be adjacent to the proper places when we pass the pointer lists to the
- * upsampler.
- *
- * The above pictures describe the normal state of the pointer lists.
- * At top and bottom of the image, we diddle the pointer lists to duplicate
- * the first or last sample row as necessary (this is cheaper than copying
- * sample rows around).
- *
- * This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that
- * situation each iMCU row provides only one row group so the buffering logic
- * must be different (eg, we must read two iMCU rows before we can emit the
- * first row group). For now, we simply do not support providing context
- * rows when min_DCT_scaled_size is 1. That combination seems unlikely to
- * be worth providing --- if someone wants a 1/8th-size preview, they probably
- * want it quick and dirty, so a context-free upsampler is sufficient.
- */
-
-
-/* Private buffer controller object */
-
-typedef struct {
- struct jpeg_d_main_controller pub; /* public fields */
-
- /* Pointer to allocated workspace (M or M+2 row groups). */
- JSAMPARRAY buffer[MAX_COMPONENTS];
-
- boolean buffer_full; /* Have we gotten an iMCU row from decoder? */
- JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */
-
- /* Remaining fields are only used in the context case. */
-
- /* These are the master pointers to the funny-order pointer lists. */
- JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */
-
- int whichptr; /* indicates which pointer set is now in use */
- int context_state; /* process_data state machine status */
- JDIMENSION rowgroups_avail; /* row groups available to postprocessor */
- JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */
-} my_main_controller;
-
-typedef my_main_controller * my_main_ptr;
-
-/* context_state values: */
-#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */
-#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */
-#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */
-
-
-/* Forward declarations */
-METHODDEF(void) process_data_simple_main
- JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
- JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
-METHODDEF(void) process_data_context_main
- JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
- JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
-#ifdef QUANT_2PASS_SUPPORTED
-METHODDEF(void) process_data_crank_post
- JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
- JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
-#endif
-
-
-LOCAL(void)
-alloc_funny_pointers (j_decompress_ptr cinfo)
-/* Allocate space for the funny pointer lists.
- * This is done only once, not once per pass.
- */
-{
- my_main_ptr jmain = (my_main_ptr) cinfo->main;
- int ci, rgroup;
- int M = cinfo->min_DCT_scaled_size;
- jpeg_component_info *compptr;
- JSAMPARRAY xbuf;
-
- /* Get top-level space for component array pointers.
- * We alloc both arrays with one call to save a few cycles.
- */
- jmain->xbuffer[0] = (JSAMPIMAGE)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- cinfo->num_components * 2 * SIZEOF(JSAMPARRAY));
- jmain->xbuffer[1] = jmain->xbuffer[0] + cinfo->num_components;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
- cinfo->min_DCT_scaled_size; /* height of a row group of component */
- /* Get space for pointer lists --- M+4 row groups in each list.
- * We alloc both pointer lists with one call to save a few cycles.
- */
- xbuf = (JSAMPARRAY)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW));
- xbuf += rgroup; /* want one row group at negative offsets */
- jmain->xbuffer[0][ci] = xbuf;
- xbuf += rgroup * (M + 4);
- jmain->xbuffer[1][ci] = xbuf;
- }
-}
-
-
-LOCAL(void)
-make_funny_pointers (j_decompress_ptr cinfo)
-/* Create the funny pointer lists discussed in the comments above.
- * The actual workspace is already allocated (in jmain->buffer),
- * and the space for the pointer lists is allocated too.
- * This routine just fills in the curiously ordered lists.
- * This will be repeated at the beginning of each pass.
- */
-{
- my_main_ptr jmain = (my_main_ptr) cinfo->main;
- int ci, i, rgroup;
- int M = cinfo->min_DCT_scaled_size;
- jpeg_component_info *compptr;
- JSAMPARRAY buf, xbuf0, xbuf1;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
- cinfo->min_DCT_scaled_size; /* height of a row group of component */
- xbuf0 = jmain->xbuffer[0][ci];
- xbuf1 = jmain->xbuffer[1][ci];
- /* First copy the workspace pointers as-is */
- buf = jmain->buffer[ci];
- for (i = 0; i < rgroup * (M + 2); i++) {
- xbuf0[i] = xbuf1[i] = buf[i];
- }
- /* In the second list, put the last four row groups in swapped order */
- for (i = 0; i < rgroup * 2; i++) {
- xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i];
- xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i];
- }
- /* The wraparound pointers at top and bottom will be filled later
- * (see set_wraparound_pointers, below). Initially we want the "above"
- * pointers to duplicate the first actual data line. This only needs
- * to happen in xbuffer[0].
- */
- for (i = 0; i < rgroup; i++) {
- xbuf0[i - rgroup] = xbuf0[0];
- }
- }
-}
-
-
-LOCAL(void)
-set_wraparound_pointers (j_decompress_ptr cinfo)
-/* Set up the "wraparound" pointers at top and bottom of the pointer lists.
- * This changes the pointer list state from top-of-image to the normal state.
- */
-{
- my_main_ptr jmain = (my_main_ptr) cinfo->main;
- int ci, i, rgroup;
- int M = cinfo->min_DCT_scaled_size;
- jpeg_component_info *compptr;
- JSAMPARRAY xbuf0, xbuf1;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
- cinfo->min_DCT_scaled_size; /* height of a row group of component */
- xbuf0 = jmain->xbuffer[0][ci];
- xbuf1 = jmain->xbuffer[1][ci];
- for (i = 0; i < rgroup; i++) {
- xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
- xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
- xbuf0[rgroup*(M+2) + i] = xbuf0[i];
- xbuf1[rgroup*(M+2) + i] = xbuf1[i];
- }
- }
-}
-
-
-LOCAL(void)
-set_bottom_pointers (j_decompress_ptr cinfo)
-/* Change the pointer lists to duplicate the last sample row at the bottom
- * of the image. whichptr indicates which xbuffer holds the final iMCU row.
- * Also sets rowgroups_avail to indicate number of nondummy row groups in row.
- */
-{
- my_main_ptr jmain = (my_main_ptr) cinfo->main;
- int ci, i, rgroup, iMCUheight, rows_left;
- jpeg_component_info *compptr;
- JSAMPARRAY xbuf;
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* Count sample rows in one iMCU row and in one row group */
- iMCUheight = compptr->v_samp_factor * compptr->DCT_scaled_size;
- rgroup = iMCUheight / cinfo->min_DCT_scaled_size;
- /* Count nondummy sample rows remaining for this component */
- rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight);
- if (rows_left == 0) rows_left = iMCUheight;
- /* Count nondummy row groups. Should get same answer for each component,
- * so we need only do it once.
- */
- if (ci == 0) {
- jmain->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1);
- }
- /* Duplicate the last real sample row rgroup*2 times; this pads out the
- * last partial rowgroup and ensures at least one full rowgroup of context.
- */
- xbuf = jmain->xbuffer[jmain->whichptr][ci];
- for (i = 0; i < rgroup * 2; i++) {
- xbuf[rows_left + i] = xbuf[rows_left-1];
- }
- }
-}
-
-
-/*
- * Initialize for a processing pass.
- */
-
-METHODDEF(void)
-start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
-{
- my_main_ptr jmain = (my_main_ptr) cinfo->main;
-
- switch (pass_mode) {
- case JBUF_PASS_THRU:
- if (cinfo->upsample->need_context_rows) {
- jmain->pub.process_data = process_data_context_main;
- make_funny_pointers(cinfo); /* Create the xbuffer[] lists */
- jmain->whichptr = 0; /* Read first iMCU row into xbuffer[0] */
- jmain->context_state = CTX_PREPARE_FOR_IMCU;
- jmain->iMCU_row_ctr = 0;
- } else {
- /* Simple case with no context needed */
- jmain->pub.process_data = process_data_simple_main;
- }
- jmain->buffer_full = FALSE; /* Mark buffer empty */
- jmain->rowgroup_ctr = 0;
- break;
-#ifdef QUANT_2PASS_SUPPORTED
- case JBUF_CRANK_DEST:
- /* For last pass of 2-pass quantization, just crank the postprocessor */
- jmain->pub.process_data = process_data_crank_post;
- break;
-#endif
- default:
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- break;
- }
-}
-
-
-/*
- * Process some data.
- * This handles the simple case where no context is required.
- */
-
-METHODDEF(void)
-process_data_simple_main (j_decompress_ptr cinfo,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail)
-{
- my_main_ptr jmain = (my_main_ptr) cinfo->main;
- JDIMENSION rowgroups_avail;
-
- /* Read input data if we haven't filled the jmain buffer yet */
- if (! jmain->buffer_full) {
- if (! (*cinfo->coef->decompress_data) (cinfo, jmain->buffer))
- return; /* suspension forced, can do nothing more */
- jmain->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
- }
-
- /* There are always min_DCT_scaled_size row groups in an iMCU row. */
- rowgroups_avail = (JDIMENSION) cinfo->min_DCT_scaled_size;
- /* Note: at the bottom of the image, we may pass extra garbage row groups
- * to the postprocessor. The postprocessor has to check for bottom
- * of image anyway (at row resolution), so no point in us doing it too.
- */
-
- /* Feed the postprocessor */
- (*cinfo->post->post_process_data) (cinfo, jmain->buffer,
- &jmain->rowgroup_ctr, rowgroups_avail,
- output_buf, out_row_ctr, out_rows_avail);
-
- /* Has postprocessor consumed all the data yet? If so, mark buffer empty */
- if (jmain->rowgroup_ctr >= rowgroups_avail) {
- jmain->buffer_full = FALSE;
- jmain->rowgroup_ctr = 0;
- }
-}
-
-
-/*
- * Process some data.
- * This handles the case where context rows must be provided.
- */
-
-METHODDEF(void)
-process_data_context_main (j_decompress_ptr cinfo,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail)
-{
- my_main_ptr jmain = (my_main_ptr) cinfo->main;
-
- /* Read input data if we haven't filled the jmain buffer yet */
- if (! jmain->buffer_full) {
- if (! (*cinfo->coef->decompress_data) (cinfo,
- jmain->xbuffer[jmain->whichptr]))
- return; /* suspension forced, can do nothing more */
- jmain->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
- jmain->iMCU_row_ctr++; /* count rows received */
- }
-
- /* Postprocessor typically will not swallow all the input data it is handed
- * in one call (due to filling the output buffer first). Must be prepared
- * to exit and restart. This switch lets us keep track of how far we got.
- * Note that each case falls through to the next on successful completion.
- */
- switch (jmain->context_state) {
- case CTX_POSTPONED_ROW:
- /* Call postprocessor using previously set pointers for postponed row */
- (*cinfo->post->post_process_data) (cinfo, jmain->xbuffer[jmain->whichptr],
- &jmain->rowgroup_ctr, jmain->rowgroups_avail,
- output_buf, out_row_ctr, out_rows_avail);
- if (jmain->rowgroup_ctr < jmain->rowgroups_avail)
- return; /* Need to suspend */
- jmain->context_state = CTX_PREPARE_FOR_IMCU;
- if (*out_row_ctr >= out_rows_avail)
- return; /* Postprocessor exactly filled output buf */
- /*FALLTHROUGH*/
- case CTX_PREPARE_FOR_IMCU:
- /* Prepare to process first M-1 row groups of this iMCU row */
- jmain->rowgroup_ctr = 0;
- jmain->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size - 1);
- /* Check for bottom of image: if so, tweak pointers to "duplicate"
- * the last sample row, and adjust rowgroups_avail to ignore padding rows.
- */
- if (jmain->iMCU_row_ctr == cinfo->total_iMCU_rows)
- set_bottom_pointers(cinfo);
- jmain->context_state = CTX_PROCESS_IMCU;
- /*FALLTHROUGH*/
- case CTX_PROCESS_IMCU:
- /* Call postprocessor using previously set pointers */
- (*cinfo->post->post_process_data) (cinfo, jmain->xbuffer[jmain->whichptr],
- &jmain->rowgroup_ctr, jmain->rowgroups_avail,
- output_buf, out_row_ctr, out_rows_avail);
- if (jmain->rowgroup_ctr < jmain->rowgroups_avail)
- return; /* Need to suspend */
- /* After the first iMCU, change wraparound pointers to normal state */
- if (jmain->iMCU_row_ctr == 1)
- set_wraparound_pointers(cinfo);
- /* Prepare to load new iMCU row using other xbuffer list */
- jmain->whichptr ^= 1; /* 0=>1 or 1=>0 */
- jmain->buffer_full = FALSE;
- /* Still need to process last row group of this iMCU row, */
- /* which is saved at index M+1 of the other xbuffer */
- jmain->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_scaled_size + 1);
- jmain->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size + 2);
- jmain->context_state = CTX_POSTPONED_ROW;
- }
-}
-
-
-/*
- * Process some data.
- * Final pass of two-pass quantization: just call the postprocessor.
- * Source data will be the postprocessor controller's internal buffer.
- */
-
-#ifdef QUANT_2PASS_SUPPORTED
-
-METHODDEF(void)
-process_data_crank_post (j_decompress_ptr cinfo,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail)
-{
- (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL,
- (JDIMENSION *) NULL, (JDIMENSION) 0,
- output_buf, out_row_ctr, out_rows_avail);
-}
-
-#endif /* QUANT_2PASS_SUPPORTED */
-
-
-/*
- * Initialize jmain buffer controller.
- */
-
-GLOBAL(void)
-jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
-{
- my_main_ptr jmain;
- int ci, rgroup, ngroups;
- jpeg_component_info *compptr;
-
- jmain = (my_main_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_main_controller));
- cinfo->main = (struct jpeg_d_main_controller *) jmain;
- jmain->pub.start_pass = start_pass_main;
-
- if (need_full_buffer) /* shouldn't happen */
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
-
- /* Allocate the workspace.
- * ngroups is the number of row groups we need.
- */
- if (cinfo->upsample->need_context_rows) {
- if (cinfo->min_DCT_scaled_size < 2) /* unsupported, see comments above */
- ERREXIT(cinfo, JERR_NOTIMPL);
- alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */
- ngroups = cinfo->min_DCT_scaled_size + 2;
- } else {
- ngroups = cinfo->min_DCT_scaled_size;
- }
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
- cinfo->min_DCT_scaled_size; /* height of a row group of component */
- jmain->buffer[ci] = (*cinfo->mem->alloc_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- compptr->width_in_blocks * compptr->DCT_scaled_size,
- (JDIMENSION) (rgroup * ngroups));
- }
-}
diff --git a/engine/code/jpeg-6b/jdmarker.c b/engine/code/jpeg-6b/jdmarker.c
deleted file mode 100644
index f4cca8c..0000000
--- a/engine/code/jpeg-6b/jdmarker.c
+++ /dev/null
@@ -1,1360 +0,0 @@
-/*
- * jdmarker.c
- *
- * Copyright (C) 1991-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains routines to decode JPEG datastream markers.
- * Most of the complexity arises from our desire to support input
- * suspension: if not all of the data for a marker is available,
- * we must exit back to the application. On resumption, we reprocess
- * the marker.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-typedef enum { /* JPEG marker codes */
- M_SOF0 = 0xc0,
- M_SOF1 = 0xc1,
- M_SOF2 = 0xc2,
- M_SOF3 = 0xc3,
-
- M_SOF5 = 0xc5,
- M_SOF6 = 0xc6,
- M_SOF7 = 0xc7,
-
- M_JPG = 0xc8,
- M_SOF9 = 0xc9,
- M_SOF10 = 0xca,
- M_SOF11 = 0xcb,
-
- M_SOF13 = 0xcd,
- M_SOF14 = 0xce,
- M_SOF15 = 0xcf,
-
- M_DHT = 0xc4,
-
- M_DAC = 0xcc,
-
- M_RST0 = 0xd0,
- M_RST1 = 0xd1,
- M_RST2 = 0xd2,
- M_RST3 = 0xd3,
- M_RST4 = 0xd4,
- M_RST5 = 0xd5,
- M_RST6 = 0xd6,
- M_RST7 = 0xd7,
-
- M_SOI = 0xd8,
- M_EOI = 0xd9,
- M_SOS = 0xda,
- M_DQT = 0xdb,
- M_DNL = 0xdc,
- M_DRI = 0xdd,
- M_DHP = 0xde,
- M_EXP = 0xdf,
-
- M_APP0 = 0xe0,
- M_APP1 = 0xe1,
- M_APP2 = 0xe2,
- M_APP3 = 0xe3,
- M_APP4 = 0xe4,
- M_APP5 = 0xe5,
- M_APP6 = 0xe6,
- M_APP7 = 0xe7,
- M_APP8 = 0xe8,
- M_APP9 = 0xe9,
- M_APP10 = 0xea,
- M_APP11 = 0xeb,
- M_APP12 = 0xec,
- M_APP13 = 0xed,
- M_APP14 = 0xee,
- M_APP15 = 0xef,
-
- M_JPG0 = 0xf0,
- M_JPG13 = 0xfd,
- M_COM = 0xfe,
-
- M_TEM = 0x01,
-
- M_ERROR = 0x100
-} JPEG_MARKER;
-
-
-/* Private state */
-
-typedef struct {
- struct jpeg_marker_reader pub; /* public fields */
-
- /* Application-overridable marker processing methods */
- jpeg_marker_parser_method process_COM;
- jpeg_marker_parser_method process_APPn[16];
-
- /* Limit on marker data length to save for each marker type */
- unsigned int length_limit_COM;
- unsigned int length_limit_APPn[16];
-
- /* Status of COM/APPn marker saving */
- jpeg_saved_marker_ptr cur_marker; /* NULL if not processing a marker */
- unsigned int bytes_read; /* data bytes read so far in marker */
- /* Note: cur_marker is not linked into marker_list until it's all read. */
-} my_marker_reader;
-
-typedef my_marker_reader * my_marker_ptr;
-
-
-/*
- * Macros for fetching data from the data source module.
- *
- * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect
- * the current restart point; we update them only when we have reached a
- * suitable place to restart if a suspension occurs.
- */
-
-/* Declare and initialize local copies of input pointer/count */
-#define INPUT_VARS(cinfo) \
- struct jpeg_source_mgr * datasrc = (cinfo)->src; \
- const JOCTET * next_input_byte = datasrc->next_input_byte; \
- size_t bytes_in_buffer = datasrc->bytes_in_buffer
-
-/* Unload the local copies --- do this only at a restart boundary */
-#define INPUT_SYNC(cinfo) \
- ( datasrc->next_input_byte = next_input_byte, \
- datasrc->bytes_in_buffer = bytes_in_buffer )
-
-/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */
-#define INPUT_RELOAD(cinfo) \
- ( next_input_byte = datasrc->next_input_byte, \
- bytes_in_buffer = datasrc->bytes_in_buffer )
-
-/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available.
- * Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
- * but we must reload the local copies after a successful fill.
- */
-#define MAKE_BYTE_AVAIL(cinfo,action) \
- if (bytes_in_buffer == 0) { \
- if (! (*datasrc->fill_input_buffer) (cinfo)) \
- { action; } \
- INPUT_RELOAD(cinfo); \
- }
-
-/* Read a byte into variable V.
- * If must suspend, take the specified action (typically "return FALSE").
- */
-#define INPUT_BYTE(cinfo,V,action) \
- MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
- bytes_in_buffer--; \
- V = GETJOCTET(*next_input_byte++); )
-
-/* As above, but read two bytes interpreted as an unsigned 16-bit integer.
- * V should be declared unsigned int or perhaps INT32.
- */
-#define INPUT_2BYTES(cinfo,V,action) \
- MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
- bytes_in_buffer--; \
- V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \
- MAKE_BYTE_AVAIL(cinfo,action); \
- bytes_in_buffer--; \
- V += GETJOCTET(*next_input_byte++); )
-
-
-/*
- * Routines to process JPEG markers.
- *
- * Entry condition: JPEG marker itself has been read and its code saved
- * in cinfo->unread_marker; input restart point is just after the marker.
- *
- * Exit: if return TRUE, have read and processed any parameters, and have
- * updated the restart point to point after the parameters.
- * If return FALSE, was forced to suspend before reaching end of
- * marker parameters; restart point has not been moved. Same routine
- * will be called again after application supplies more input data.
- *
- * This approach to suspension assumes that all of a marker's parameters
- * can fit into a single input bufferload. This should hold for "normal"
- * markers. Some COM/APPn markers might have large parameter segments
- * that might not fit. If we are simply dropping such a marker, we use
- * skip_input_data to get past it, and thereby put the problem on the
- * source manager's shoulders. If we are saving the marker's contents
- * into memory, we use a slightly different convention: when forced to
- * suspend, the marker processor updates the restart point to the end of
- * what it's consumed (ie, the end of the buffer) before returning FALSE.
- * On resumption, cinfo->unread_marker still contains the marker code,
- * but the data source will point to the next chunk of marker data.
- * The marker processor must retain internal state to deal with this.
- *
- * Note that we don't bother to avoid duplicate trace messages if a
- * suspension occurs within marker parameters. Other side effects
- * require more care.
- */
-
-
-LOCAL(boolean)
-get_soi (j_decompress_ptr cinfo)
-/* Process an SOI marker */
-{
- int i;
-
- TRACEMS(cinfo, 1, JTRC_SOI);
-
- if (cinfo->marker->saw_SOI)
- ERREXIT(cinfo, JERR_SOI_DUPLICATE);
-
- /* Reset all parameters that are defined to be reset by SOI */
-
- for (i = 0; i < NUM_ARITH_TBLS; i++) {
- cinfo->arith_dc_L[i] = 0;
- cinfo->arith_dc_U[i] = 1;
- cinfo->arith_ac_K[i] = 5;
- }
- cinfo->restart_interval = 0;
-
- /* Set initial assumptions for colorspace etc */
-
- cinfo->jpeg_color_space = JCS_UNKNOWN;
- cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */
-
- cinfo->saw_JFIF_marker = FALSE;
- cinfo->JFIF_major_version = 1; /* set default JFIF APP0 values */
- cinfo->JFIF_minor_version = 1;
- cinfo->density_unit = 0;
- cinfo->X_density = 1;
- cinfo->Y_density = 1;
- cinfo->saw_Adobe_marker = FALSE;
- cinfo->Adobe_transform = 0;
-
- cinfo->marker->saw_SOI = TRUE;
-
- return TRUE;
-}
-
-
-LOCAL(boolean)
-get_sof (j_decompress_ptr cinfo, boolean is_prog, boolean is_arith)
-/* Process a SOFn marker */
-{
- INT32 length;
- int c, ci;
- jpeg_component_info * compptr;
- INPUT_VARS(cinfo);
-
- cinfo->progressive_mode = is_prog;
- cinfo->arith_code = is_arith;
-
- INPUT_2BYTES(cinfo, length, return FALSE);
-
- INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE);
- INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE);
- INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE);
- INPUT_BYTE(cinfo, cinfo->num_components, return FALSE);
-
- length -= 8;
-
- TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker,
- (int) cinfo->image_width, (int) cinfo->image_height,
- cinfo->num_components);
-
- if (cinfo->marker->saw_SOF)
- ERREXIT(cinfo, JERR_SOF_DUPLICATE);
-
- /* We don't support files in which the image height is initially specified */
- /* as 0 and is later redefined by DNL. As long as we have to check that, */
- /* might as well have a general sanity check. */
- if (cinfo->image_height <= 0 || cinfo->image_width <= 0
- || cinfo->num_components <= 0)
- ERREXIT(cinfo, JERR_EMPTY_IMAGE);
-
- if (length != (cinfo->num_components * 3))
- ERREXIT(cinfo, JERR_BAD_LENGTH);
-
- if (cinfo->comp_info == NULL) /* do only once, even if suspend */
- cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- cinfo->num_components * SIZEOF(jpeg_component_info));
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- compptr->component_index = ci;
- INPUT_BYTE(cinfo, compptr->component_id, return FALSE);
- INPUT_BYTE(cinfo, c, return FALSE);
- compptr->h_samp_factor = (c >> 4) & 15;
- compptr->v_samp_factor = (c ) & 15;
- INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE);
-
- TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT,
- compptr->component_id, compptr->h_samp_factor,
- compptr->v_samp_factor, compptr->quant_tbl_no);
- }
-
- cinfo->marker->saw_SOF = TRUE;
-
- INPUT_SYNC(cinfo);
- return TRUE;
-}
-
-
-LOCAL(boolean)
-get_sos (j_decompress_ptr cinfo)
-/* Process a SOS marker */
-{
- INT32 length;
- int i, ci, n, c, cc;
- jpeg_component_info * compptr;
- INPUT_VARS(cinfo);
-
- if (! cinfo->marker->saw_SOF)
- ERREXIT(cinfo, JERR_SOS_NO_SOF);
-
- INPUT_2BYTES(cinfo, length, return FALSE);
-
- INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */
-
- TRACEMS1(cinfo, 1, JTRC_SOS, n);
-
- if (length != (n * 2 + 6) || n < 1 || n > MAX_COMPS_IN_SCAN)
- ERREXIT(cinfo, JERR_BAD_LENGTH);
-
- cinfo->comps_in_scan = n;
-
- /* Collect the component-spec parameters */
-
- for (i = 0; i < n; i++) {
- INPUT_BYTE(cinfo, cc, return FALSE);
- INPUT_BYTE(cinfo, c, return FALSE);
-
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- if (cc == compptr->component_id)
- goto id_found;
- }
-
- ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc);
-
- id_found:
-
- cinfo->cur_comp_info[i] = compptr;
- compptr->dc_tbl_no = (c >> 4) & 15;
- compptr->ac_tbl_no = (c ) & 15;
-
- TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc,
- compptr->dc_tbl_no, compptr->ac_tbl_no);
- }
-
- /* Collect the additional scan parameters Ss, Se, Ah/Al. */
- INPUT_BYTE(cinfo, c, return FALSE);
- cinfo->Ss = c;
- INPUT_BYTE(cinfo, c, return FALSE);
- cinfo->Se = c;
- INPUT_BYTE(cinfo, c, return FALSE);
- cinfo->Ah = (c >> 4) & 15;
- cinfo->Al = (c ) & 15;
-
- TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se,
- cinfo->Ah, cinfo->Al);
-
- /* Prepare to scan data & restart markers */
- cinfo->marker->next_restart_num = 0;
-
- /* Count another SOS marker */
- cinfo->input_scan_number++;
-
- INPUT_SYNC(cinfo);
- return TRUE;
-}
-
-
-#ifdef D_ARITH_CODING_SUPPORTED
-
-LOCAL(boolean)
-get_dac (j_decompress_ptr cinfo)
-/* Process a DAC marker */
-{
- INT32 length;
- int index, val;
- INPUT_VARS(cinfo);
-
- INPUT_2BYTES(cinfo, length, return FALSE);
- length -= 2;
-
- while (length > 0) {
- INPUT_BYTE(cinfo, index, return FALSE);
- INPUT_BYTE(cinfo, val, return FALSE);
-
- length -= 2;
-
- TRACEMS2(cinfo, 1, JTRC_DAC, index, val);
-
- if (index < 0 || index >= (2*NUM_ARITH_TBLS))
- ERREXIT1(cinfo, JERR_DAC_INDEX, index);
-
- if (index >= NUM_ARITH_TBLS) { /* define AC table */
- cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val;
- } else { /* define DC table */
- cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F);
- cinfo->arith_dc_U[index] = (UINT8) (val >> 4);
- if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index])
- ERREXIT1(cinfo, JERR_DAC_VALUE, val);
- }
- }
-
- if (length != 0)
- ERREXIT(cinfo, JERR_BAD_LENGTH);
-
- INPUT_SYNC(cinfo);
- return TRUE;
-}
-
-#else /* ! D_ARITH_CODING_SUPPORTED */
-
-#define get_dac(cinfo) skip_variable(cinfo)
-
-#endif /* D_ARITH_CODING_SUPPORTED */
-
-
-LOCAL(boolean)
-get_dht (j_decompress_ptr cinfo)
-/* Process a DHT marker */
-{
- INT32 length;
- UINT8 bits[17];
- UINT8 huffval[256];
- int i, index, count;
- JHUFF_TBL **htblptr;
- INPUT_VARS(cinfo);
-
- INPUT_2BYTES(cinfo, length, return FALSE);
- length -= 2;
-
- while (length > 16) {
- INPUT_BYTE(cinfo, index, return FALSE);
-
- TRACEMS1(cinfo, 1, JTRC_DHT, index);
-
- bits[0] = 0;
- count = 0;
- for (i = 1; i <= 16; i++) {
- INPUT_BYTE(cinfo, bits[i], return FALSE);
- count += bits[i];
- }
-
- length -= 1 + 16;
-
- TRACEMS8(cinfo, 2, JTRC_HUFFBITS,
- bits[1], bits[2], bits[3], bits[4],
- bits[5], bits[6], bits[7], bits[8]);
- TRACEMS8(cinfo, 2, JTRC_HUFFBITS,
- bits[9], bits[10], bits[11], bits[12],
- bits[13], bits[14], bits[15], bits[16]);
-
- /* Here we just do minimal validation of the counts to avoid walking
- * off the end of our table space. jdhuff.c will check more carefully.
- */
- if (count > 256 || ((INT32) count) > length)
- ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
-
- for (i = 0; i < count; i++)
- INPUT_BYTE(cinfo, huffval[i], return FALSE);
-
- length -= count;
-
- if (index & 0x10) { /* AC table definition */
- index -= 0x10;
- htblptr = &cinfo->ac_huff_tbl_ptrs[index];
- } else { /* DC table definition */
- htblptr = &cinfo->dc_huff_tbl_ptrs[index];
- }
-
- if (index < 0 || index >= NUM_HUFF_TBLS)
- ERREXIT1(cinfo, JERR_DHT_INDEX, index);
-
- if (*htblptr == NULL)
- *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
-
- MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits));
- MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval));
- }
-
- if (length != 0)
- ERREXIT(cinfo, JERR_BAD_LENGTH);
-
- INPUT_SYNC(cinfo);
- return TRUE;
-}
-
-
-LOCAL(boolean)
-get_dqt (j_decompress_ptr cinfo)
-/* Process a DQT marker */
-{
- INT32 length;
- int n, i, prec;
- unsigned int tmp;
- JQUANT_TBL *quant_ptr;
- INPUT_VARS(cinfo);
-
- INPUT_2BYTES(cinfo, length, return FALSE);
- length -= 2;
-
- while (length > 0) {
- INPUT_BYTE(cinfo, n, return FALSE);
- prec = n >> 4;
- n &= 0x0F;
-
- TRACEMS2(cinfo, 1, JTRC_DQT, n, prec);
-
- if (n >= NUM_QUANT_TBLS)
- ERREXIT1(cinfo, JERR_DQT_INDEX, n);
-
- if (cinfo->quant_tbl_ptrs[n] == NULL)
- cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo);
- quant_ptr = cinfo->quant_tbl_ptrs[n];
-
- for (i = 0; i < DCTSIZE2; i++) {
- if (prec)
- INPUT_2BYTES(cinfo, tmp, return FALSE);
- else
- INPUT_BYTE(cinfo, tmp, return FALSE);
- /* We convert the zigzag-order table to natural array order. */
- quant_ptr->quantval[jpeg_natural_order[i]] = (UINT16) tmp;
- }
-
- if (cinfo->err->trace_level >= 2) {
- for (i = 0; i < DCTSIZE2; i += 8) {
- TRACEMS8(cinfo, 2, JTRC_QUANTVALS,
- quant_ptr->quantval[i], quant_ptr->quantval[i+1],
- quant_ptr->quantval[i+2], quant_ptr->quantval[i+3],
- quant_ptr->quantval[i+4], quant_ptr->quantval[i+5],
- quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]);
- }
- }
-
- length -= DCTSIZE2+1;
- if (prec) length -= DCTSIZE2;
- }
-
- if (length != 0)
- ERREXIT(cinfo, JERR_BAD_LENGTH);
-
- INPUT_SYNC(cinfo);
- return TRUE;
-}
-
-
-LOCAL(boolean)
-get_dri (j_decompress_ptr cinfo)
-/* Process a DRI marker */
-{
- INT32 length;
- unsigned int tmp;
- INPUT_VARS(cinfo);
-
- INPUT_2BYTES(cinfo, length, return FALSE);
-
- if (length != 4)
- ERREXIT(cinfo, JERR_BAD_LENGTH);
-
- INPUT_2BYTES(cinfo, tmp, return FALSE);
-
- TRACEMS1(cinfo, 1, JTRC_DRI, tmp);
-
- cinfo->restart_interval = tmp;
-
- INPUT_SYNC(cinfo);
- return TRUE;
-}
-
-
-/*
- * Routines for processing APPn and COM markers.
- * These are either saved in memory or discarded, per application request.
- * APP0 and APP14 are specially checked to see if they are
- * JFIF and Adobe markers, respectively.
- */
-
-#define APP0_DATA_LEN 14 /* Length of interesting data in APP0 */
-#define APP14_DATA_LEN 12 /* Length of interesting data in APP14 */
-#define APPN_DATA_LEN 14 /* Must be the largest of the above!! */
-
-
-LOCAL(void)
-examine_app0 (j_decompress_ptr cinfo, JOCTET FAR * data,
- unsigned int datalen, INT32 remaining)
-/* Examine first few bytes from an APP0.
- * Take appropriate action if it is a JFIF marker.
- * datalen is # of bytes at data[], remaining is length of rest of marker data.
- */
-{
- INT32 totallen = (INT32) datalen + remaining;
-
- if (datalen >= APP0_DATA_LEN &&
- GETJOCTET(data[0]) == 0x4A &&
- GETJOCTET(data[1]) == 0x46 &&
- GETJOCTET(data[2]) == 0x49 &&
- GETJOCTET(data[3]) == 0x46 &&
- GETJOCTET(data[4]) == 0) {
- /* Found JFIF APP0 marker: save info */
- cinfo->saw_JFIF_marker = TRUE;
- cinfo->JFIF_major_version = GETJOCTET(data[5]);
- cinfo->JFIF_minor_version = GETJOCTET(data[6]);
- cinfo->density_unit = GETJOCTET(data[7]);
- cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]);
- cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]);
- /* Check version.
- * Major version must be 1, anything else signals an incompatible change.
- * (We used to treat this as an error, but now it's a nonfatal warning,
- * because some bozo at Hijaak couldn't read the spec.)
- * Minor version should be 0..2, but process anyway if newer.
- */
- if (cinfo->JFIF_major_version != 1)
- WARNMS2(cinfo, JWRN_JFIF_MAJOR,
- cinfo->JFIF_major_version, cinfo->JFIF_minor_version);
- /* Generate trace messages */
- TRACEMS5(cinfo, 1, JTRC_JFIF,
- cinfo->JFIF_major_version, cinfo->JFIF_minor_version,
- cinfo->X_density, cinfo->Y_density, cinfo->density_unit);
- /* Validate thumbnail dimensions and issue appropriate messages */
- if (GETJOCTET(data[12]) | GETJOCTET(data[13]))
- TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL,
- GETJOCTET(data[12]), GETJOCTET(data[13]));
- totallen -= APP0_DATA_LEN;
- if (totallen !=
- ((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3))
- TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen);
- } else if (datalen >= 6 &&
- GETJOCTET(data[0]) == 0x4A &&
- GETJOCTET(data[1]) == 0x46 &&
- GETJOCTET(data[2]) == 0x58 &&
- GETJOCTET(data[3]) == 0x58 &&
- GETJOCTET(data[4]) == 0) {
- /* Found JFIF "JFXX" extension APP0 marker */
- /* The library doesn't actually do anything with these,
- * but we try to produce a helpful trace message.
- */
- switch (GETJOCTET(data[5])) {
- case 0x10:
- TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen);
- break;
- case 0x11:
- TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen);
- break;
- case 0x13:
- TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen);
- break;
- default:
- TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION,
- GETJOCTET(data[5]), (int) totallen);
- break;
- }
- } else {
- /* Start of APP0 does not match "JFIF" or "JFXX", or too short */
- TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen);
- }
-}
-
-
-LOCAL(void)
-examine_app14 (j_decompress_ptr cinfo, JOCTET FAR * data,
- unsigned int datalen, INT32 remaining)
-/* Examine first few bytes from an APP14.
- * Take appropriate action if it is an Adobe marker.
- * datalen is # of bytes at data[], remaining is length of rest of marker data.
- */
-{
- unsigned int version, flags0, flags1, transform;
-
- if (datalen >= APP14_DATA_LEN &&
- GETJOCTET(data[0]) == 0x41 &&
- GETJOCTET(data[1]) == 0x64 &&
- GETJOCTET(data[2]) == 0x6F &&
- GETJOCTET(data[3]) == 0x62 &&
- GETJOCTET(data[4]) == 0x65) {
- /* Found Adobe APP14 marker */
- version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]);
- flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]);
- flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]);
- transform = GETJOCTET(data[11]);
- TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform);
- cinfo->saw_Adobe_marker = TRUE;
- cinfo->Adobe_transform = (UINT8) transform;
- } else {
- /* Start of APP14 does not match "Adobe", or too short */
- TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining));
- }
-}
-
-
-METHODDEF(boolean)
-get_interesting_appn (j_decompress_ptr cinfo)
-/* Process an APP0 or APP14 marker without saving it */
-{
- INT32 length;
- JOCTET b[APPN_DATA_LEN];
- unsigned int i, numtoread;
- INPUT_VARS(cinfo);
-
- INPUT_2BYTES(cinfo, length, return FALSE);
- length -= 2;
-
- /* get the interesting part of the marker data */
- if (length >= APPN_DATA_LEN)
- numtoread = APPN_DATA_LEN;
- else if (length > 0)
- numtoread = (unsigned int) length;
- else
- numtoread = 0;
- for (i = 0; i < numtoread; i++)
- INPUT_BYTE(cinfo, b[i], return FALSE);
- length -= numtoread;
-
- /* process it */
- switch (cinfo->unread_marker) {
- case M_APP0:
- examine_app0(cinfo, (JOCTET FAR *) b, numtoread, length);
- break;
- case M_APP14:
- examine_app14(cinfo, (JOCTET FAR *) b, numtoread, length);
- break;
- default:
- /* can't get here unless jpeg_save_markers chooses wrong processor */
- ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker);
- break;
- }
-
- /* skip any remaining data -- could be lots */
- INPUT_SYNC(cinfo);
- if (length > 0)
- (*cinfo->src->skip_input_data) (cinfo, (long) length);
-
- return TRUE;
-}
-
-
-#ifdef SAVE_MARKERS_SUPPORTED
-
-METHODDEF(boolean)
-save_marker (j_decompress_ptr cinfo)
-/* Save an APPn or COM marker into the marker list */
-{
- my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
- jpeg_saved_marker_ptr cur_marker = marker->cur_marker;
- unsigned int bytes_read, data_length;
- JOCTET FAR * data;
- INT32 length = 0;
- INPUT_VARS(cinfo);
-
- if (cur_marker == NULL) {
- /* begin reading a marker */
- INPUT_2BYTES(cinfo, length, return FALSE);
- length -= 2;
- if (length >= 0) { /* watch out for bogus length word */
- /* figure out how much we want to save */
- unsigned int limit;
- if (cinfo->unread_marker == (int) M_COM)
- limit = marker->length_limit_COM;
- else
- limit = marker->length_limit_APPn[cinfo->unread_marker - (int) M_APP0];
- if ((unsigned int) length < limit)
- limit = (unsigned int) length;
- /* allocate and initialize the marker item */
- cur_marker = (jpeg_saved_marker_ptr)
- (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(struct jpeg_marker_struct) + limit);
- cur_marker->next = NULL;
- cur_marker->marker = (UINT8) cinfo->unread_marker;
- cur_marker->original_length = (unsigned int) length;
- cur_marker->data_length = limit;
- /* data area is just beyond the jpeg_marker_struct */
- data = cur_marker->data = (JOCTET FAR *) (cur_marker + 1);
- marker->cur_marker = cur_marker;
- marker->bytes_read = 0;
- bytes_read = 0;
- data_length = limit;
- } else {
- /* deal with bogus length word */
- bytes_read = data_length = 0;
- data = NULL;
- }
- } else {
- /* resume reading a marker */
- bytes_read = marker->bytes_read;
- data_length = cur_marker->data_length;
- data = cur_marker->data + bytes_read;
- }
-
- while (bytes_read < data_length) {
- INPUT_SYNC(cinfo); /* move the restart point to here */
- marker->bytes_read = bytes_read;
- /* If there's not at least one byte in buffer, suspend */
- MAKE_BYTE_AVAIL(cinfo, return FALSE);
- /* Copy bytes with reasonable rapidity */
- while (bytes_read < data_length && bytes_in_buffer > 0) {
- *data++ = *next_input_byte++;
- bytes_in_buffer--;
- bytes_read++;
- }
- }
-
- /* Done reading what we want to read */
- if (cur_marker != NULL) { /* will be NULL if bogus length word */
- /* Add new marker to end of list */
- if (cinfo->marker_list == NULL) {
- cinfo->marker_list = cur_marker;
- } else {
- jpeg_saved_marker_ptr prev = cinfo->marker_list;
- while (prev->next != NULL)
- prev = prev->next;
- prev->next = cur_marker;
- }
- /* Reset pointer & calc remaining data length */
- data = cur_marker->data;
- length = cur_marker->original_length - data_length;
- }
- /* Reset to initial state for next marker */
- marker->cur_marker = NULL;
-
- /* Process the marker if interesting; else just make a generic trace msg */
- switch (cinfo->unread_marker) {
- case M_APP0:
- examine_app0(cinfo, data, data_length, length);
- break;
- case M_APP14:
- examine_app14(cinfo, data, data_length, length);
- break;
- default:
- TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker,
- (int) (data_length + length));
- break;
- }
-
- /* skip any remaining data -- could be lots */
- INPUT_SYNC(cinfo); /* do before skip_input_data */
- if (length > 0)
- (*cinfo->src->skip_input_data) (cinfo, (long) length);
-
- return TRUE;
-}
-
-#endif /* SAVE_MARKERS_SUPPORTED */
-
-
-METHODDEF(boolean)
-skip_variable (j_decompress_ptr cinfo)
-/* Skip over an unknown or uninteresting variable-length marker */
-{
- INT32 length;
- INPUT_VARS(cinfo);
-
- INPUT_2BYTES(cinfo, length, return FALSE);
- length -= 2;
-
- TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length);
-
- INPUT_SYNC(cinfo); /* do before skip_input_data */
- if (length > 0)
- (*cinfo->src->skip_input_data) (cinfo, (long) length);
-
- return TRUE;
-}
-
-
-/*
- * Find the next JPEG marker, save it in cinfo->unread_marker.
- * Returns FALSE if had to suspend before reaching a marker;
- * in that case cinfo->unread_marker is unchanged.
- *
- * Note that the result might not be a valid marker code,
- * but it will never be 0 or FF.
- */
-
-LOCAL(boolean)
-next_marker (j_decompress_ptr cinfo)
-{
- int c;
- INPUT_VARS(cinfo);
-
- for (;;) {
- INPUT_BYTE(cinfo, c, return FALSE);
- /* Skip any non-FF bytes.
- * This may look a bit inefficient, but it will not occur in a valid file.
- * We sync after each discarded byte so that a suspending data source
- * can discard the byte from its buffer.
- */
- while (c != 0xFF) {
- cinfo->marker->discarded_bytes++;
- INPUT_SYNC(cinfo);
- INPUT_BYTE(cinfo, c, return FALSE);
- }
- /* This loop swallows any duplicate FF bytes. Extra FFs are legal as
- * pad bytes, so don't count them in discarded_bytes. We assume there
- * will not be so many consecutive FF bytes as to overflow a suspending
- * data source's input buffer.
- */
- do {
- INPUT_BYTE(cinfo, c, return FALSE);
- } while (c == 0xFF);
- if (c != 0)
- break; /* found a valid marker, exit loop */
- /* Reach here if we found a stuffed-zero data sequence (FF/00).
- * Discard it and loop back to try again.
- */
- cinfo->marker->discarded_bytes += 2;
- INPUT_SYNC(cinfo);
- }
-
- if (cinfo->marker->discarded_bytes != 0) {
- WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c);
- cinfo->marker->discarded_bytes = 0;
- }
-
- cinfo->unread_marker = c;
-
- INPUT_SYNC(cinfo);
- return TRUE;
-}
-
-
-LOCAL(boolean)
-first_marker (j_decompress_ptr cinfo)
-/* Like next_marker, but used to obtain the initial SOI marker. */
-/* For this marker, we do not allow preceding garbage or fill; otherwise,
- * we might well scan an entire input file before realizing it ain't JPEG.
- * If an application wants to process non-JFIF files, it must seek to the
- * SOI before calling the JPEG library.
- */
-{
- int c, c2;
- INPUT_VARS(cinfo);
-
- INPUT_BYTE(cinfo, c, return FALSE);
- INPUT_BYTE(cinfo, c2, return FALSE);
- if (c != 0xFF || c2 != (int) M_SOI)
- ERREXIT2(cinfo, JERR_NO_SOI, c, c2);
-
- cinfo->unread_marker = c2;
-
- INPUT_SYNC(cinfo);
- return TRUE;
-}
-
-
-/*
- * Read markers until SOS or EOI.
- *
- * Returns same codes as are defined for jpeg_consume_input:
- * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
- */
-
-METHODDEF(int)
-read_markers (j_decompress_ptr cinfo)
-{
- /* Outer loop repeats once for each marker. */
- for (;;) {
- /* Collect the marker proper, unless we already did. */
- /* NB: first_marker() enforces the requirement that SOI appear first. */
- if (cinfo->unread_marker == 0) {
- if (! cinfo->marker->saw_SOI) {
- if (! first_marker(cinfo))
- return JPEG_SUSPENDED;
- } else {
- if (! next_marker(cinfo))
- return JPEG_SUSPENDED;
- }
- }
- /* At this point cinfo->unread_marker contains the marker code and the
- * input point is just past the marker proper, but before any parameters.
- * A suspension will cause us to return with this state still true.
- */
- switch (cinfo->unread_marker) {
- case M_SOI:
- if (! get_soi(cinfo))
- return JPEG_SUSPENDED;
- break;
-
- case M_SOF0: /* Baseline */
- case M_SOF1: /* Extended sequential, Huffman */
- if (! get_sof(cinfo, FALSE, FALSE))
- return JPEG_SUSPENDED;
- break;
-
- case M_SOF2: /* Progressive, Huffman */
- if (! get_sof(cinfo, TRUE, FALSE))
- return JPEG_SUSPENDED;
- break;
-
- case M_SOF9: /* Extended sequential, arithmetic */
- if (! get_sof(cinfo, FALSE, TRUE))
- return JPEG_SUSPENDED;
- break;
-
- case M_SOF10: /* Progressive, arithmetic */
- if (! get_sof(cinfo, TRUE, TRUE))
- return JPEG_SUSPENDED;
- break;
-
- /* Currently unsupported SOFn types */
- case M_SOF3: /* Lossless, Huffman */
- case M_SOF5: /* Differential sequential, Huffman */
- case M_SOF6: /* Differential progressive, Huffman */
- case M_SOF7: /* Differential lossless, Huffman */
- case M_JPG: /* Reserved for JPEG extensions */
- case M_SOF11: /* Lossless, arithmetic */
- case M_SOF13: /* Differential sequential, arithmetic */
- case M_SOF14: /* Differential progressive, arithmetic */
- case M_SOF15: /* Differential lossless, arithmetic */
- ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker);
- break;
-
- case M_SOS:
- if (! get_sos(cinfo))
- return JPEG_SUSPENDED;
- cinfo->unread_marker = 0; /* processed the marker */
- return JPEG_REACHED_SOS;
-
- case M_EOI:
- TRACEMS(cinfo, 1, JTRC_EOI);
- cinfo->unread_marker = 0; /* processed the marker */
- return JPEG_REACHED_EOI;
-
- case M_DAC:
- if (! get_dac(cinfo))
- return JPEG_SUSPENDED;
- break;
-
- case M_DHT:
- if (! get_dht(cinfo))
- return JPEG_SUSPENDED;
- break;
-
- case M_DQT:
- if (! get_dqt(cinfo))
- return JPEG_SUSPENDED;
- break;
-
- case M_DRI:
- if (! get_dri(cinfo))
- return JPEG_SUSPENDED;
- break;
-
- case M_APP0:
- case M_APP1:
- case M_APP2:
- case M_APP3:
- case M_APP4:
- case M_APP5:
- case M_APP6:
- case M_APP7:
- case M_APP8:
- case M_APP9:
- case M_APP10:
- case M_APP11:
- case M_APP12:
- case M_APP13:
- case M_APP14:
- case M_APP15:
- if (! (*((my_marker_ptr) cinfo->marker)->process_APPn[
- cinfo->unread_marker - (int) M_APP0]) (cinfo))
- return JPEG_SUSPENDED;
- break;
-
- case M_COM:
- if (! (*((my_marker_ptr) cinfo->marker)->process_COM) (cinfo))
- return JPEG_SUSPENDED;
- break;
-
- case M_RST0: /* these are all parameterless */
- case M_RST1:
- case M_RST2:
- case M_RST3:
- case M_RST4:
- case M_RST5:
- case M_RST6:
- case M_RST7:
- case M_TEM:
- TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker);
- break;
-
- case M_DNL: /* Ignore DNL ... perhaps the wrong thing */
- if (! skip_variable(cinfo))
- return JPEG_SUSPENDED;
- break;
-
- default: /* must be DHP, EXP, JPGn, or RESn */
- /* For now, we treat the reserved markers as fatal errors since they are
- * likely to be used to signal incompatible JPEG Part 3 extensions.
- * Once the JPEG 3 version-number marker is well defined, this code
- * ought to change!
- */
- ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker);
- break;
- }
- /* Successfully processed marker, so reset state variable */
- cinfo->unread_marker = 0;
- } /* end loop */
-}
-
-
-/*
- * Read a restart marker, which is expected to appear next in the datastream;
- * if the marker is not there, take appropriate recovery action.
- * Returns FALSE if suspension is required.
- *
- * This is called by the entropy decoder after it has read an appropriate
- * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder
- * has already read a marker from the data source. Under normal conditions
- * cinfo->unread_marker will be reset to 0 before returning; if not reset,
- * it holds a marker which the decoder will be unable to read past.
- */
-
-METHODDEF(boolean)
-read_restart_marker (j_decompress_ptr cinfo)
-{
- /* Obtain a marker unless we already did. */
- /* Note that next_marker will complain if it skips any data. */
- if (cinfo->unread_marker == 0) {
- if (! next_marker(cinfo))
- return FALSE;
- }
-
- if (cinfo->unread_marker ==
- ((int) M_RST0 + cinfo->marker->next_restart_num)) {
- /* Normal case --- swallow the marker and let entropy decoder continue */
- TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num);
- cinfo->unread_marker = 0;
- } else {
- /* Uh-oh, the restart markers have been messed up. */
- /* Let the data source manager determine how to resync. */
- if (! (*cinfo->src->resync_to_restart) (cinfo,
- cinfo->marker->next_restart_num))
- return FALSE;
- }
-
- /* Update next-restart state */
- cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7;
-
- return TRUE;
-}
-
-
-/*
- * This is the default resync_to_restart method for data source managers
- * to use if they don't have any better approach. Some data source managers
- * may be able to back up, or may have additional knowledge about the data
- * which permits a more intelligent recovery strategy; such managers would
- * presumably supply their own resync method.
- *
- * read_restart_marker calls resync_to_restart if it finds a marker other than
- * the restart marker it was expecting. (This code is *not* used unless
- * a nonzero restart interval has been declared.) cinfo->unread_marker is
- * the marker code actually found (might be anything, except 0 or FF).
- * The desired restart marker number (0..7) is passed as a parameter.
- * This routine is supposed to apply whatever error recovery strategy seems
- * appropriate in order to position the input stream to the next data segment.
- * Note that cinfo->unread_marker is treated as a marker appearing before
- * the current data-source input point; usually it should be reset to zero
- * before returning.
- * Returns FALSE if suspension is required.
- *
- * This implementation is substantially constrained by wanting to treat the
- * input as a data stream; this means we can't back up. Therefore, we have
- * only the following actions to work with:
- * 1. Simply discard the marker and let the entropy decoder resume at next
- * byte of file.
- * 2. Read forward until we find another marker, discarding intervening
- * data. (In theory we could look ahead within the current bufferload,
- * without having to discard data if we don't find the desired marker.
- * This idea is not implemented here, in part because it makes behavior
- * dependent on buffer size and chance buffer-boundary positions.)
- * 3. Leave the marker unread (by failing to zero cinfo->unread_marker).
- * This will cause the entropy decoder to process an empty data segment,
- * inserting dummy zeroes, and then we will reprocess the marker.
- *
- * #2 is appropriate if we think the desired marker lies ahead, while #3 is
- * appropriate if the found marker is a future restart marker (indicating
- * that we have missed the desired restart marker, probably because it got
- * corrupted).
- * We apply #2 or #3 if the found marker is a restart marker no more than
- * two counts behind or ahead of the expected one. We also apply #2 if the
- * found marker is not a legal JPEG marker code (it's certainly bogus data).
- * If the found marker is a restart marker more than 2 counts away, we do #1
- * (too much risk that the marker is erroneous; with luck we will be able to
- * resync at some future point).
- * For any valid non-restart JPEG marker, we apply #3. This keeps us from
- * overrunning the end of a scan. An implementation limited to single-scan
- * files might find it better to apply #2 for markers other than EOI, since
- * any other marker would have to be bogus data in that case.
- */
-
-GLOBAL(boolean)
-jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired)
-{
- int marker = cinfo->unread_marker;
- int action = 1;
-
- /* Always put up a warning. */
- WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired);
-
- /* Outer loop handles repeated decision after scanning forward. */
- for (;;) {
- if (marker < (int) M_SOF0)
- action = 2; /* invalid marker */
- else if (marker < (int) M_RST0 || marker > (int) M_RST7)
- action = 3; /* valid non-restart marker */
- else {
- if (marker == ((int) M_RST0 + ((desired+1) & 7)) ||
- marker == ((int) M_RST0 + ((desired+2) & 7)))
- action = 3; /* one of the next two expected restarts */
- else if (marker == ((int) M_RST0 + ((desired-1) & 7)) ||
- marker == ((int) M_RST0 + ((desired-2) & 7)))
- action = 2; /* a prior restart, so advance */
- else
- action = 1; /* desired restart or too far away */
- }
- TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action);
- switch (action) {
- case 1:
- /* Discard marker and let entropy decoder resume processing. */
- cinfo->unread_marker = 0;
- return TRUE;
- case 2:
- /* Scan to the next marker, and repeat the decision loop. */
- if (! next_marker(cinfo))
- return FALSE;
- marker = cinfo->unread_marker;
- break;
- case 3:
- /* Return without advancing past this marker. */
- /* Entropy decoder will be forced to process an empty segment. */
- return TRUE;
- }
- } /* end loop */
-}
-
-
-/*
- * Reset marker processing state to begin a fresh datastream.
- */
-
-METHODDEF(void)
-reset_marker_reader (j_decompress_ptr cinfo)
-{
- my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
-
- cinfo->comp_info = NULL; /* until allocated by get_sof */
- cinfo->input_scan_number = 0; /* no SOS seen yet */
- cinfo->unread_marker = 0; /* no pending marker */
- marker->pub.saw_SOI = FALSE; /* set internal state too */
- marker->pub.saw_SOF = FALSE;
- marker->pub.discarded_bytes = 0;
- marker->cur_marker = NULL;
-}
-
-
-/*
- * Initialize the marker reader module.
- * This is called only once, when the decompression object is created.
- */
-
-GLOBAL(void)
-jinit_marker_reader (j_decompress_ptr cinfo)
-{
- my_marker_ptr marker;
- int i;
-
- /* Create subobject in permanent pool */
- marker = (my_marker_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- SIZEOF(my_marker_reader));
- cinfo->marker = (struct jpeg_marker_reader *) marker;
- /* Initialize public method pointers */
- marker->pub.reset_marker_reader = reset_marker_reader;
- marker->pub.read_markers = read_markers;
- marker->pub.read_restart_marker = read_restart_marker;
- /* Initialize COM/APPn processing.
- * By default, we examine and then discard APP0 and APP14,
- * but simply discard COM and all other APPn.
- */
- marker->process_COM = skip_variable;
- marker->length_limit_COM = 0;
- for (i = 0; i < 16; i++) {
- marker->process_APPn[i] = skip_variable;
- marker->length_limit_APPn[i] = 0;
- }
- marker->process_APPn[0] = get_interesting_appn;
- marker->process_APPn[14] = get_interesting_appn;
- /* Reset marker processing state */
- reset_marker_reader(cinfo);
-}
-
-
-/*
- * Control saving of COM and APPn markers into marker_list.
- */
-
-#ifdef SAVE_MARKERS_SUPPORTED
-
-GLOBAL(void)
-jpeg_save_markers (j_decompress_ptr cinfo, int marker_code,
- unsigned int length_limit)
-{
- my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
- long maxlength;
- jpeg_marker_parser_method processor;
-
- /* Length limit mustn't be larger than what we can allocate
- * (should only be a concern in a 16-bit environment).
- */
- maxlength = cinfo->mem->max_alloc_chunk - SIZEOF(struct jpeg_marker_struct);
- if (((long) length_limit) > maxlength)
- length_limit = (unsigned int) maxlength;
-
- /* Choose processor routine to use.
- * APP0/APP14 have special requirements.
- */
- if (length_limit) {
- processor = save_marker;
- /* If saving APP0/APP14, save at least enough for our internal use. */
- if (marker_code == (int) M_APP0 && length_limit < APP0_DATA_LEN)
- length_limit = APP0_DATA_LEN;
- else if (marker_code == (int) M_APP14 && length_limit < APP14_DATA_LEN)
- length_limit = APP14_DATA_LEN;
- } else {
- processor = skip_variable;
- /* If discarding APP0/APP14, use our regular on-the-fly processor. */
- if (marker_code == (int) M_APP0 || marker_code == (int) M_APP14)
- processor = get_interesting_appn;
- }
-
- if (marker_code == (int) M_COM) {
- marker->process_COM = processor;
- marker->length_limit_COM = length_limit;
- } else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) {
- marker->process_APPn[marker_code - (int) M_APP0] = processor;
- marker->length_limit_APPn[marker_code - (int) M_APP0] = length_limit;
- } else
- ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code);
-}
-
-#endif /* SAVE_MARKERS_SUPPORTED */
-
-
-/*
- * Install a special processing method for COM or APPn markers.
- */
-
-GLOBAL(void)
-jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code,
- jpeg_marker_parser_method routine)
-{
- my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
-
- if (marker_code == (int) M_COM)
- marker->process_COM = routine;
- else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15)
- marker->process_APPn[marker_code - (int) M_APP0] = routine;
- else
- ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code);
-}
diff --git a/engine/code/jpeg-6b/jdmaster.c b/engine/code/jpeg-6b/jdmaster.c
deleted file mode 100644
index 2802c5b..0000000
--- a/engine/code/jpeg-6b/jdmaster.c
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- * jdmaster.c
- *
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains master control logic for the JPEG decompressor.
- * These routines are concerned with selecting the modules to be executed
- * and with determining the number of passes and the work to be done in each
- * pass.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* Private state */
-
-typedef struct {
- struct jpeg_decomp_master pub; /* public fields */
-
- int pass_number; /* # of passes completed */
-
- boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */
-
- /* Saved references to initialized quantizer modules,
- * in case we need to switch modes.
- */
- struct jpeg_color_quantizer * quantizer_1pass;
- struct jpeg_color_quantizer * quantizer_2pass;
-} my_decomp_master;
-
-typedef my_decomp_master * my_master_ptr;
-
-
-/*
- * Determine whether merged upsample/color conversion should be used.
- * CRUCIAL: this must match the actual capabilities of jdmerge.c!
- */
-
-LOCAL(boolean)
-use_merged_upsample (j_decompress_ptr cinfo)
-{
-#ifdef UPSAMPLE_MERGING_SUPPORTED
- /* Merging is the equivalent of plain box-filter upsampling */
- if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling)
- return FALSE;
- /* jdmerge.c only supports YCC=>RGB color conversion */
- if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 ||
- cinfo->out_color_space != JCS_RGB ||
- cinfo->out_color_components != RGB_PIXELSIZE)
- return FALSE;
- /* and it only handles 2h1v or 2h2v sampling ratios */
- if (cinfo->comp_info[0].h_samp_factor != 2 ||
- cinfo->comp_info[1].h_samp_factor != 1 ||
- cinfo->comp_info[2].h_samp_factor != 1 ||
- cinfo->comp_info[0].v_samp_factor > 2 ||
- cinfo->comp_info[1].v_samp_factor != 1 ||
- cinfo->comp_info[2].v_samp_factor != 1)
- return FALSE;
- /* furthermore, it doesn't work if we've scaled the IDCTs differently */
- if (cinfo->comp_info[0].DCT_scaled_size != cinfo->min_DCT_scaled_size ||
- cinfo->comp_info[1].DCT_scaled_size != cinfo->min_DCT_scaled_size ||
- cinfo->comp_info[2].DCT_scaled_size != cinfo->min_DCT_scaled_size)
- return FALSE;
- /* ??? also need to test for upsample-time rescaling, when & if supported */
- return TRUE; /* by golly, it'll work... */
-#else
- return FALSE;
-#endif
-}
-
-
-/*
- * Compute output image dimensions and related values.
- * NOTE: this is exported for possible use by application.
- * Hence it mustn't do anything that can't be done twice.
- * Also note that it may be called before the master module is initialized!
- */
-
-GLOBAL(void)
-jpeg_calc_output_dimensions (j_decompress_ptr cinfo)
-/* Do computations that are needed before master selection phase */
-{
-#ifdef IDCT_SCALING_SUPPORTED
- int ci;
- jpeg_component_info *compptr;
-#endif
-
- /* Prevent application from calling me at wrong times */
- if (cinfo->global_state != DSTATE_READY)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
-#ifdef IDCT_SCALING_SUPPORTED
-
- /* Compute actual output image dimensions and DCT scaling choices. */
- if (cinfo->scale_num * 8 <= cinfo->scale_denom) {
- /* Provide 1/8 scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_width, 8L);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_height, 8L);
- cinfo->min_DCT_scaled_size = 1;
- } else if (cinfo->scale_num * 4 <= cinfo->scale_denom) {
- /* Provide 1/4 scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_width, 4L);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_height, 4L);
- cinfo->min_DCT_scaled_size = 2;
- } else if (cinfo->scale_num * 2 <= cinfo->scale_denom) {
- /* Provide 1/2 scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_width, 2L);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_height, 2L);
- cinfo->min_DCT_scaled_size = 4;
- } else {
- /* Provide 1/1 scaling */
- cinfo->output_width = cinfo->image_width;
- cinfo->output_height = cinfo->image_height;
- cinfo->min_DCT_scaled_size = DCTSIZE;
- }
- /* In selecting the actual DCT scaling for each component, we try to
- * scale up the chroma components via IDCT scaling rather than upsampling.
- * This saves time if the upsampler gets to use 1:1 scaling.
- * Note this code assumes that the supported DCT scalings are powers of 2.
- */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- int ssize = cinfo->min_DCT_scaled_size;
- while (ssize < DCTSIZE &&
- (compptr->h_samp_factor * ssize * 2 <=
- cinfo->max_h_samp_factor * cinfo->min_DCT_scaled_size) &&
- (compptr->v_samp_factor * ssize * 2 <=
- cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size)) {
- ssize = ssize * 2;
- }
- compptr->DCT_scaled_size = ssize;
- }
-
- /* Recompute downsampled dimensions of components;
- * application needs to know these if using raw downsampled data.
- */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* Size in samples, after IDCT scaling */
- compptr->downsampled_width = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_width *
- (long) (compptr->h_samp_factor * compptr->DCT_scaled_size),
- (long) (cinfo->max_h_samp_factor * DCTSIZE));
- compptr->downsampled_height = (JDIMENSION)
- jdiv_round_up((long) cinfo->image_height *
- (long) (compptr->v_samp_factor * compptr->DCT_scaled_size),
- (long) (cinfo->max_v_samp_factor * DCTSIZE));
- }
-
-#else /* !IDCT_SCALING_SUPPORTED */
-
- /* Hardwire it to "no scaling" */
- cinfo->output_width = cinfo->image_width;
- cinfo->output_height = cinfo->image_height;
- /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE,
- * and has computed unscaled downsampled_width and downsampled_height.
- */
-
-#endif /* IDCT_SCALING_SUPPORTED */
-
- /* Report number of components in selected colorspace. */
- /* Probably this should be in the color conversion module... */
- switch (cinfo->out_color_space) {
- case JCS_GRAYSCALE:
- cinfo->out_color_components = 1;
- break;
- case JCS_RGB:
-#if RGB_PIXELSIZE != 3
- cinfo->out_color_components = RGB_PIXELSIZE;
- break;
-#endif /* else share code with YCbCr */
- case JCS_YCbCr:
- cinfo->out_color_components = 3;
- break;
- case JCS_CMYK:
- case JCS_YCCK:
- cinfo->out_color_components = 4;
- break;
- default: /* else must be same colorspace as in file */
- cinfo->out_color_components = cinfo->num_components;
- break;
- }
- cinfo->output_components = (cinfo->quantize_colors ? 1 :
- cinfo->out_color_components);
-
- /* See if upsampler will want to emit more than one row at a time */
- if (use_merged_upsample(cinfo))
- cinfo->rec_outbuf_height = cinfo->max_v_samp_factor;
- else
- cinfo->rec_outbuf_height = 1;
-}
-
-
-/*
- * Several decompression processes need to range-limit values to the range
- * 0..MAXJSAMPLE; the input value may fall somewhat outside this range
- * due to noise introduced by quantization, roundoff error, etc. These
- * processes are inner loops and need to be as fast as possible. On most
- * machines, particularly CPUs with pipelines or instruction prefetch,
- * a (subscript-check-less) C table lookup
- * x = sample_range_limit[x];
- * is faster than explicit tests
- * if (x < 0) x = 0;
- * else if (x > MAXJSAMPLE) x = MAXJSAMPLE;
- * These processes all use a common table prepared by the routine below.
- *
- * For most steps we can mathematically guarantee that the initial value
- * of x is within MAXJSAMPLE+1 of the legal range, so a table running from
- * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial
- * limiting step (just after the IDCT), a wildly out-of-range value is
- * possible if the input data is corrupt. To avoid any chance of indexing
- * off the end of memory and getting a bad-pointer trap, we perform the
- * post-IDCT limiting thus:
- * x = range_limit[x & MASK];
- * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit
- * samples. Under normal circumstances this is more than enough range and
- * a correct output will be generated; with bogus input data the mask will
- * cause wraparound, and we will safely generate a bogus-but-in-range output.
- * For the post-IDCT step, we want to convert the data from signed to unsigned
- * representation by adding CENTERJSAMPLE at the same time that we limit it.
- * So the post-IDCT limiting table ends up looking like this:
- * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE,
- * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
- * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
- * 0,1,...,CENTERJSAMPLE-1
- * Negative inputs select values from the upper half of the table after
- * masking.
- *
- * We can save some space by overlapping the start of the post-IDCT table
- * with the simpler range limiting table. The post-IDCT table begins at
- * sample_range_limit + CENTERJSAMPLE.
- *
- * Note that the table is allocated in near data space on PCs; it's small
- * enough and used often enough to justify this.
- */
-
-LOCAL(void)
-prepare_range_limit_table (j_decompress_ptr cinfo)
-/* Allocate and fill in the sample_range_limit table */
-{
- JSAMPLE * table;
- int i;
-
- table = (JSAMPLE *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE));
- table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */
- cinfo->sample_range_limit = table;
- /* First segment of "simple" table: limit[x] = 0 for x < 0 */
- MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE));
- /* Main part of "simple" table: limit[x] = x */
- for (i = 0; i <= MAXJSAMPLE; i++)
- table[i] = (JSAMPLE) i;
- table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */
- /* End of simple table, rest of first half of post-IDCT table */
- for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++)
- table[i] = MAXJSAMPLE;
- /* Second half of post-IDCT table */
- MEMZERO(table + (2 * (MAXJSAMPLE+1)),
- (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE));
- MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE),
- cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE));
-}
-
-
-/*
- * Master selection of decompression modules.
- * This is done once at jpeg_start_decompress time. We determine
- * which modules will be used and give them appropriate initialization calls.
- * We also initialize the decompressor input side to begin consuming data.
- *
- * Since jpeg_read_header has finished, we know what is in the SOF
- * and (first) SOS markers. We also have all the application parameter
- * settings.
- */
-
-LOCAL(void)
-master_selection (j_decompress_ptr cinfo)
-{
- my_master_ptr master = (my_master_ptr) cinfo->master;
- boolean use_c_buffer;
- long samplesperrow;
- JDIMENSION jd_samplesperrow;
-
- /* Initialize dimensions and other stuff */
- jpeg_calc_output_dimensions(cinfo);
- prepare_range_limit_table(cinfo);
-
- /* Width of an output scanline must be representable as JDIMENSION. */
- samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components;
- jd_samplesperrow = (JDIMENSION) samplesperrow;
- if ((long) jd_samplesperrow != samplesperrow)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
-
- /* Initialize my private state */
- master->pass_number = 0;
- master->using_merged_upsample = use_merged_upsample(cinfo);
-
- /* Color quantizer selection */
- master->quantizer_1pass = NULL;
- master->quantizer_2pass = NULL;
- /* No mode changes if not using buffered-image mode. */
- if (! cinfo->quantize_colors || ! cinfo->buffered_image) {
- cinfo->enable_1pass_quant = FALSE;
- cinfo->enable_external_quant = FALSE;
- cinfo->enable_2pass_quant = FALSE;
- }
- if (cinfo->quantize_colors) {
- if (cinfo->raw_data_out)
- ERREXIT(cinfo, JERR_NOTIMPL);
- /* 2-pass quantizer only works in 3-component color space. */
- if (cinfo->out_color_components != 3) {
- cinfo->enable_1pass_quant = TRUE;
- cinfo->enable_external_quant = FALSE;
- cinfo->enable_2pass_quant = FALSE;
- cinfo->colormap = NULL;
- } else if (cinfo->colormap != NULL) {
- cinfo->enable_external_quant = TRUE;
- } else if (cinfo->two_pass_quantize) {
- cinfo->enable_2pass_quant = TRUE;
- } else {
- cinfo->enable_1pass_quant = TRUE;
- }
-
- if (cinfo->enable_1pass_quant) {
-#ifdef QUANT_1PASS_SUPPORTED
- jinit_1pass_quantizer(cinfo);
- master->quantizer_1pass = cinfo->cquantize;
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- }
-
- /* We use the 2-pass code to map to external colormaps. */
- if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) {
-#ifdef QUANT_2PASS_SUPPORTED
- jinit_2pass_quantizer(cinfo);
- master->quantizer_2pass = cinfo->cquantize;
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- }
- /* If both quantizers are initialized, the 2-pass one is left active;
- * this is necessary for starting with quantization to an external map.
- */
- }
-
- /* Post-processing: in particular, color conversion first */
- if (! cinfo->raw_data_out) {
- if (master->using_merged_upsample) {
-#ifdef UPSAMPLE_MERGING_SUPPORTED
- jinit_merged_upsampler(cinfo); /* does color conversion too */
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- } else {
- jinit_color_deconverter(cinfo);
- jinit_upsampler(cinfo);
- }
- jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);
- }
- /* Inverse DCT */
- jinit_inverse_dct(cinfo);
- /* Entropy decoding: either Huffman or arithmetic coding. */
- if (cinfo->arith_code) {
- ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
- } else {
- if (cinfo->progressive_mode) {
-#ifdef D_PROGRESSIVE_SUPPORTED
- jinit_phuff_decoder(cinfo);
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- } else
- jinit_huff_decoder(cinfo);
- }
-
- /* Initialize principal buffer controllers. */
- use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image;
- jinit_d_coef_controller(cinfo, use_c_buffer);
-
- if (! cinfo->raw_data_out)
- jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);
-
- /* We can now tell the memory manager to allocate virtual arrays. */
- (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
-
- /* Initialize input side of decompressor to consume first scan. */
- (*cinfo->inputctl->start_input_pass) (cinfo);
-
-#ifdef D_MULTISCAN_FILES_SUPPORTED
- /* If jpeg_start_decompress will read the whole file, initialize
- * progress monitoring appropriately. The input step is counted
- * as one pass.
- */
- if (cinfo->progress != NULL && ! cinfo->buffered_image &&
- cinfo->inputctl->has_multiple_scans) {
- int nscans;
- /* Estimate number of scans to set pass_limit. */
- if (cinfo->progressive_mode) {
- /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
- nscans = 2 + 3 * cinfo->num_components;
- } else {
- /* For a nonprogressive multiscan file, estimate 1 scan per component. */
- nscans = cinfo->num_components;
- }
- cinfo->progress->pass_counter = 0L;
- cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;
- cinfo->progress->completed_passes = 0;
- cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2);
- /* Count the input pass as done */
- master->pass_number++;
- }
-#endif /* D_MULTISCAN_FILES_SUPPORTED */
-}
-
-
-/*
- * Per-pass setup.
- * This is called at the beginning of each output pass. We determine which
- * modules will be active during this pass and give them appropriate
- * start_pass calls. We also set is_dummy_pass to indicate whether this
- * is a "real" output pass or a dummy pass for color quantization.
- * (In the latter case, jdapistd.c will crank the pass to completion.)
- */
-
-METHODDEF(void)
-prepare_for_output_pass (j_decompress_ptr cinfo)
-{
- my_master_ptr master = (my_master_ptr) cinfo->master;
-
- if (master->pub.is_dummy_pass) {
-#ifdef QUANT_2PASS_SUPPORTED
- /* Final pass of 2-pass quantization */
- master->pub.is_dummy_pass = FALSE;
- (*cinfo->cquantize->start_pass) (cinfo, FALSE);
- (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST);
- (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST);
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif /* QUANT_2PASS_SUPPORTED */
- } else {
- if (cinfo->quantize_colors && cinfo->colormap == NULL) {
- /* Select new quantization method */
- if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) {
- cinfo->cquantize = master->quantizer_2pass;
- master->pub.is_dummy_pass = TRUE;
- } else if (cinfo->enable_1pass_quant) {
- cinfo->cquantize = master->quantizer_1pass;
- } else {
- ERREXIT(cinfo, JERR_MODE_CHANGE);
- }
- }
- (*cinfo->idct->start_pass) (cinfo);
- (*cinfo->coef->start_output_pass) (cinfo);
- if (! cinfo->raw_data_out) {
- if (! master->using_merged_upsample)
- (*cinfo->cconvert->start_pass) (cinfo);
- (*cinfo->upsample->start_pass) (cinfo);
- if (cinfo->quantize_colors)
- (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass);
- (*cinfo->post->start_pass) (cinfo,
- (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
- (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
- }
- }
-
- /* Set up progress monitor's pass info if present */
- if (cinfo->progress != NULL) {
- cinfo->progress->completed_passes = master->pass_number;
- cinfo->progress->total_passes = master->pass_number +
- (master->pub.is_dummy_pass ? 2 : 1);
- /* In buffered-image mode, we assume one more output pass if EOI not
- * yet reached, but no more passes if EOI has been reached.
- */
- if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) {
- cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1);
- }
- }
-}
-
-
-/*
- * Finish up at end of an output pass.
- */
-
-METHODDEF(void)
-finish_output_pass (j_decompress_ptr cinfo)
-{
- my_master_ptr master = (my_master_ptr) cinfo->master;
-
- if (cinfo->quantize_colors)
- (*cinfo->cquantize->finish_pass) (cinfo);
- master->pass_number++;
-}
-
-
-#ifdef D_MULTISCAN_FILES_SUPPORTED
-
-/*
- * Switch to a new external colormap between output passes.
- */
-
-GLOBAL(void)
-jpeg_new_colormap (j_decompress_ptr cinfo)
-{
- my_master_ptr master = (my_master_ptr) cinfo->master;
-
- /* Prevent application from calling me at wrong times */
- if (cinfo->global_state != DSTATE_BUFIMAGE)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
- if (cinfo->quantize_colors && cinfo->enable_external_quant &&
- cinfo->colormap != NULL) {
- /* Select 2-pass quantizer for external colormap use */
- cinfo->cquantize = master->quantizer_2pass;
- /* Notify quantizer of colormap change */
- (*cinfo->cquantize->new_color_map) (cinfo);
- master->pub.is_dummy_pass = FALSE; /* just in case */
- } else
- ERREXIT(cinfo, JERR_MODE_CHANGE);
-}
-
-#endif /* D_MULTISCAN_FILES_SUPPORTED */
-
-
-/*
- * Initialize master decompression control and select active modules.
- * This is performed at the start of jpeg_start_decompress.
- */
-
-GLOBAL(void)
-jinit_master_decompress (j_decompress_ptr cinfo)
-{
- my_master_ptr master;
-
- master = (my_master_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_decomp_master));
- cinfo->master = (struct jpeg_decomp_master *) master;
- master->pub.prepare_for_output_pass = prepare_for_output_pass;
- master->pub.finish_output_pass = finish_output_pass;
-
- master->pub.is_dummy_pass = FALSE;
-
- master_selection(cinfo);
-}
diff --git a/engine/code/jpeg-6b/jdmerge.c b/engine/code/jpeg-6b/jdmerge.c
deleted file mode 100644
index 3744446..0000000
--- a/engine/code/jpeg-6b/jdmerge.c
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * jdmerge.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains code for merged upsampling/color conversion.
- *
- * This file combines functions from jdsample.c and jdcolor.c;
- * read those files first to understand what's going on.
- *
- * When the chroma components are to be upsampled by simple replication
- * (ie, box filtering), we can save some work in color conversion by
- * calculating all the output pixels corresponding to a pair of chroma
- * samples at one time. In the conversion equations
- * R = Y + K1 * Cr
- * G = Y + K2 * Cb + K3 * Cr
- * B = Y + K4 * Cb
- * only the Y term varies among the group of pixels corresponding to a pair
- * of chroma samples, so the rest of the terms can be calculated just once.
- * At typical sampling ratios, this eliminates half or three-quarters of the
- * multiplications needed for color conversion.
- *
- * This file currently provides implementations for the following cases:
- * YCbCr => RGB color conversion only.
- * Sampling ratios of 2h1v or 2h2v.
- * No scaling needed at upsample time.
- * Corner-aligned (non-CCIR601) sampling alignment.
- * Other special cases could be added, but in most applications these are
- * the only common cases. (For uncommon cases we fall back on the more
- * general code in jdsample.c and jdcolor.c.)
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-#ifdef UPSAMPLE_MERGING_SUPPORTED
-
-
-/* Private subobject */
-
-typedef struct {
- struct jpeg_upsampler pub; /* public fields */
-
- /* Pointer to routine to do actual upsampling/conversion of one row group */
- JMETHOD(void, upmethod, (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf));
-
- /* Private state for YCC->RGB conversion */
- int * Cr_r_tab; /* => table for Cr to R conversion */
- int * Cb_b_tab; /* => table for Cb to B conversion */
- INT32 * Cr_g_tab; /* => table for Cr to G conversion */
- INT32 * Cb_g_tab; /* => table for Cb to G conversion */
-
- /* For 2:1 vertical sampling, we produce two output rows at a time.
- * We need a "spare" row buffer to hold the second output row if the
- * application provides just a one-row buffer; we also use the spare
- * to discard the dummy last row if the image height is odd.
- */
- JSAMPROW spare_row;
- boolean spare_full; /* T if spare buffer is occupied */
-
- JDIMENSION out_row_width; /* samples per output row */
- JDIMENSION rows_to_go; /* counts rows remaining in image */
-} my_upsampler;
-
-typedef my_upsampler * my_upsample_ptr;
-
-#define SCALEBITS 16 /* speediest right-shift on some machines */
-#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
-#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
-
-
-/*
- * Initialize tables for YCC->RGB colorspace conversion.
- * This is taken directly from jdcolor.c; see that file for more info.
- */
-
-LOCAL(void)
-build_ycc_rgb_table (j_decompress_ptr cinfo)
-{
- my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
- int i;
- INT32 x;
- SHIFT_TEMPS
-
- upsample->Cr_r_tab = (int *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE+1) * SIZEOF(int));
- upsample->Cb_b_tab = (int *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE+1) * SIZEOF(int));
- upsample->Cr_g_tab = (INT32 *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE+1) * SIZEOF(INT32));
- upsample->Cb_g_tab = (INT32 *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE+1) * SIZEOF(INT32));
-
- for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
- /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
- /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
- /* Cr=>R value is nearest int to 1.40200 * x */
- upsample->Cr_r_tab[i] = (int)
- RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
- /* Cb=>B value is nearest int to 1.77200 * x */
- upsample->Cb_b_tab[i] = (int)
- RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS);
- /* Cr=>G value is scaled-up -0.71414 * x */
- upsample->Cr_g_tab[i] = (- FIX(0.71414)) * x;
- /* Cb=>G value is scaled-up -0.34414 * x */
- /* We also add in ONE_HALF so that need not do it in inner loop */
- upsample->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF;
- }
-}
-
-
-/*
- * Initialize for an upsampling pass.
- */
-
-METHODDEF(void)
-start_pass_merged_upsample (j_decompress_ptr cinfo)
-{
- my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
-
- /* Mark the spare buffer empty */
- upsample->spare_full = FALSE;
- /* Initialize total-height counter for detecting bottom of image */
- upsample->rows_to_go = cinfo->output_height;
-}
-
-
-/*
- * Control routine to do upsampling (and color conversion).
- *
- * The control routine just handles the row buffering considerations.
- */
-
-METHODDEF(void)
-merged_2v_upsample (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail)
-/* 2:1 vertical sampling case: may need a spare row. */
-{
- my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
- JSAMPROW work_ptrs[2];
- JDIMENSION num_rows; /* number of rows returned to caller */
-
- if (upsample->spare_full) {
- /* If we have a spare row saved from a previous cycle, just return it. */
- jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0,
- 1, upsample->out_row_width);
- num_rows = 1;
- upsample->spare_full = FALSE;
- } else {
- /* Figure number of rows to return to caller. */
- num_rows = 2;
- /* Not more than the distance to the end of the image. */
- if (num_rows > upsample->rows_to_go)
- num_rows = upsample->rows_to_go;
- /* And not more than what the client can accept: */
- out_rows_avail -= *out_row_ctr;
- if (num_rows > out_rows_avail)
- num_rows = out_rows_avail;
- /* Create output pointer array for upsampler. */
- work_ptrs[0] = output_buf[*out_row_ctr];
- if (num_rows > 1) {
- work_ptrs[1] = output_buf[*out_row_ctr + 1];
- } else {
- work_ptrs[1] = upsample->spare_row;
- upsample->spare_full = TRUE;
- }
- /* Now do the upsampling. */
- (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs);
- }
-
- /* Adjust counts */
- *out_row_ctr += num_rows;
- upsample->rows_to_go -= num_rows;
- /* When the buffer is emptied, declare this input row group consumed */
- if (! upsample->spare_full)
- (*in_row_group_ctr)++;
-}
-
-
-METHODDEF(void)
-merged_1v_upsample (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail)
-/* 1:1 vertical sampling case: much easier, never need a spare row. */
-{
- my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
-
- /* Just do the upsampling. */
- (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr,
- output_buf + *out_row_ctr);
- /* Adjust counts */
- (*out_row_ctr)++;
- (*in_row_group_ctr)++;
-}
-
-
-/*
- * These are the routines invoked by the control routines to do
- * the actual upsampling/conversion. One row group is processed per call.
- *
- * Note: since we may be writing directly into application-supplied buffers,
- * we have to be honest about the output width; we can't assume the buffer
- * has been rounded up to an even width.
- */
-
-
-/*
- * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical.
- */
-
-METHODDEF(void)
-h2v1_merged_upsample (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
-{
- my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
- register int y, cred, cgreen, cblue;
- int cb, cr;
- register JSAMPROW outptr;
- JSAMPROW inptr0, inptr1, inptr2;
- JDIMENSION col;
- /* copy these pointers into registers if possible */
- register JSAMPLE * range_limit = cinfo->sample_range_limit;
- int * Crrtab = upsample->Cr_r_tab;
- int * Cbbtab = upsample->Cb_b_tab;
- INT32 * Crgtab = upsample->Cr_g_tab;
- INT32 * Cbgtab = upsample->Cb_g_tab;
- SHIFT_TEMPS
-
- inptr0 = input_buf[0][in_row_group_ctr];
- inptr1 = input_buf[1][in_row_group_ctr];
- inptr2 = input_buf[2][in_row_group_ctr];
- outptr = output_buf[0];
- /* Loop for each pair of output pixels */
- for (col = cinfo->output_width >> 1; col > 0; col--) {
- /* Do the chroma part of the calculation */
- cb = GETJSAMPLE(*inptr1++);
- cr = GETJSAMPLE(*inptr2++);
- cred = Crrtab[cr];
- cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
- cblue = Cbbtab[cb];
- /* Fetch 2 Y values and emit 2 pixels */
- y = GETJSAMPLE(*inptr0++);
- outptr[RGB_RED] = range_limit[y + cred];
- outptr[RGB_GREEN] = range_limit[y + cgreen];
- outptr[RGB_BLUE] = range_limit[y + cblue];
- outptr += RGB_PIXELSIZE;
- y = GETJSAMPLE(*inptr0++);
- outptr[RGB_RED] = range_limit[y + cred];
- outptr[RGB_GREEN] = range_limit[y + cgreen];
- outptr[RGB_BLUE] = range_limit[y + cblue];
- outptr += RGB_PIXELSIZE;
- }
- /* If image width is odd, do the last output column separately */
- if (cinfo->output_width & 1) {
- cb = GETJSAMPLE(*inptr1);
- cr = GETJSAMPLE(*inptr2);
- cred = Crrtab[cr];
- cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
- cblue = Cbbtab[cb];
- y = GETJSAMPLE(*inptr0);
- outptr[RGB_RED] = range_limit[y + cred];
- outptr[RGB_GREEN] = range_limit[y + cgreen];
- outptr[RGB_BLUE] = range_limit[y + cblue];
- }
-}
-
-
-/*
- * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical.
- */
-
-METHODDEF(void)
-h2v2_merged_upsample (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
-{
- my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
- register int y, cred, cgreen, cblue;
- int cb, cr;
- register JSAMPROW outptr0, outptr1;
- JSAMPROW inptr00, inptr01, inptr1, inptr2;
- JDIMENSION col;
- /* copy these pointers into registers if possible */
- register JSAMPLE * range_limit = cinfo->sample_range_limit;
- int * Crrtab = upsample->Cr_r_tab;
- int * Cbbtab = upsample->Cb_b_tab;
- INT32 * Crgtab = upsample->Cr_g_tab;
- INT32 * Cbgtab = upsample->Cb_g_tab;
- SHIFT_TEMPS
-
- inptr00 = input_buf[0][in_row_group_ctr*2];
- inptr01 = input_buf[0][in_row_group_ctr*2 + 1];
- inptr1 = input_buf[1][in_row_group_ctr];
- inptr2 = input_buf[2][in_row_group_ctr];
- outptr0 = output_buf[0];
- outptr1 = output_buf[1];
- /* Loop for each group of output pixels */
- for (col = cinfo->output_width >> 1; col > 0; col--) {
- /* Do the chroma part of the calculation */
- cb = GETJSAMPLE(*inptr1++);
- cr = GETJSAMPLE(*inptr2++);
- cred = Crrtab[cr];
- cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
- cblue = Cbbtab[cb];
- /* Fetch 4 Y values and emit 4 pixels */
- y = GETJSAMPLE(*inptr00++);
- outptr0[RGB_RED] = range_limit[y + cred];
- outptr0[RGB_GREEN] = range_limit[y + cgreen];
- outptr0[RGB_BLUE] = range_limit[y + cblue];
- outptr0 += RGB_PIXELSIZE;
- y = GETJSAMPLE(*inptr00++);
- outptr0[RGB_RED] = range_limit[y + cred];
- outptr0[RGB_GREEN] = range_limit[y + cgreen];
- outptr0[RGB_BLUE] = range_limit[y + cblue];
- outptr0 += RGB_PIXELSIZE;
- y = GETJSAMPLE(*inptr01++);
- outptr1[RGB_RED] = range_limit[y + cred];
- outptr1[RGB_GREEN] = range_limit[y + cgreen];
- outptr1[RGB_BLUE] = range_limit[y + cblue];
- outptr1 += RGB_PIXELSIZE;
- y = GETJSAMPLE(*inptr01++);
- outptr1[RGB_RED] = range_limit[y + cred];
- outptr1[RGB_GREEN] = range_limit[y + cgreen];
- outptr1[RGB_BLUE] = range_limit[y + cblue];
- outptr1 += RGB_PIXELSIZE;
- }
- /* If image width is odd, do the last output column separately */
- if (cinfo->output_width & 1) {
- cb = GETJSAMPLE(*inptr1);
- cr = GETJSAMPLE(*inptr2);
- cred = Crrtab[cr];
- cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
- cblue = Cbbtab[cb];
- y = GETJSAMPLE(*inptr00);
- outptr0[RGB_RED] = range_limit[y + cred];
- outptr0[RGB_GREEN] = range_limit[y + cgreen];
- outptr0[RGB_BLUE] = range_limit[y + cblue];
- y = GETJSAMPLE(*inptr01);
- outptr1[RGB_RED] = range_limit[y + cred];
- outptr1[RGB_GREEN] = range_limit[y + cgreen];
- outptr1[RGB_BLUE] = range_limit[y + cblue];
- }
-}
-
-
-/*
- * Module initialization routine for merged upsampling/color conversion.
- *
- * NB: this is called under the conditions determined by use_merged_upsample()
- * in jdmaster.c. That routine MUST correspond to the actual capabilities
- * of this module; no safety checks are made here.
- */
-
-GLOBAL(void)
-jinit_merged_upsampler (j_decompress_ptr cinfo)
-{
- my_upsample_ptr upsample;
-
- upsample = (my_upsample_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_upsampler));
- cinfo->upsample = (struct jpeg_upsampler *) upsample;
- upsample->pub.start_pass = start_pass_merged_upsample;
- upsample->pub.need_context_rows = FALSE;
-
- upsample->out_row_width = cinfo->output_width * cinfo->out_color_components;
-
- if (cinfo->max_v_samp_factor == 2) {
- upsample->pub.upsample = merged_2v_upsample;
- upsample->upmethod = h2v2_merged_upsample;
- /* Allocate a spare row buffer */
- upsample->spare_row = (JSAMPROW)
- (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (size_t) (upsample->out_row_width * SIZEOF(JSAMPLE)));
- } else {
- upsample->pub.upsample = merged_1v_upsample;
- upsample->upmethod = h2v1_merged_upsample;
- /* No spare row needed */
- upsample->spare_row = NULL;
- }
-
- build_ycc_rgb_table(cinfo);
-}
-
-#endif /* UPSAMPLE_MERGING_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jdphuff.c b/engine/code/jpeg-6b/jdphuff.c
deleted file mode 100644
index 2267809..0000000
--- a/engine/code/jpeg-6b/jdphuff.c
+++ /dev/null
@@ -1,668 +0,0 @@
-/*
- * jdphuff.c
- *
- * Copyright (C) 1995-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains Huffman entropy decoding routines for progressive JPEG.
- *
- * Much of the complexity here has to do with supporting input suspension.
- * If the data source module demands suspension, we want to be able to back
- * up to the start of the current MCU. To do this, we copy state variables
- * into local working storage, and update them back to the permanent
- * storage only upon successful completion of an MCU.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jdhuff.h" /* Declarations shared with jdhuff.c */
-
-
-#ifdef D_PROGRESSIVE_SUPPORTED
-
-/*
- * Expanded entropy decoder object for progressive Huffman decoding.
- *
- * The savable_state subrecord contains fields that change within an MCU,
- * but must not be updated permanently until we complete the MCU.
- */
-
-typedef struct {
- unsigned int EOBRUN; /* remaining EOBs in EOBRUN */
- int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
-} savable_state;
-
-/* This macro is to work around compilers with missing or broken
- * structure assignment. You'll need to fix this code if you have
- * such a compiler and you change MAX_COMPS_IN_SCAN.
- */
-
-#ifndef NO_STRUCT_ASSIGN
-#define ASSIGN_STATE(dest,src) ((dest) = (src))
-#else
-#if MAX_COMPS_IN_SCAN == 4
-#define ASSIGN_STATE(dest,src) \
- ((dest).EOBRUN = (src).EOBRUN, \
- (dest).last_dc_val[0] = (src).last_dc_val[0], \
- (dest).last_dc_val[1] = (src).last_dc_val[1], \
- (dest).last_dc_val[2] = (src).last_dc_val[2], \
- (dest).last_dc_val[3] = (src).last_dc_val[3])
-#endif
-#endif
-
-
-typedef struct {
- struct jpeg_entropy_decoder pub; /* public fields */
-
- /* These fields are loaded into local variables at start of each MCU.
- * In case of suspension, we exit WITHOUT updating them.
- */
- bitread_perm_state bitstate; /* Bit buffer at start of MCU */
- savable_state saved; /* Other state at start of MCU */
-
- /* These fields are NOT loaded into local working state. */
- unsigned int restarts_to_go; /* MCUs left in this restart interval */
-
- /* Pointers to derived tables (these workspaces have image lifespan) */
- d_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
-
- d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */
-} phuff_entropy_decoder;
-
-typedef phuff_entropy_decoder * phuff_entropy_ptr;
-
-/* Forward declarations */
-METHODDEF(boolean) decode_mcu_DC_first JPP((j_decompress_ptr cinfo,
- JBLOCKROW *MCU_data));
-METHODDEF(boolean) decode_mcu_AC_first JPP((j_decompress_ptr cinfo,
- JBLOCKROW *MCU_data));
-METHODDEF(boolean) decode_mcu_DC_refine JPP((j_decompress_ptr cinfo,
- JBLOCKROW *MCU_data));
-METHODDEF(boolean) decode_mcu_AC_refine JPP((j_decompress_ptr cinfo,
- JBLOCKROW *MCU_data));
-
-
-/*
- * Initialize for a Huffman-compressed scan.
- */
-
-METHODDEF(void)
-start_pass_phuff_decoder (j_decompress_ptr cinfo)
-{
- phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
- boolean is_DC_band, bad;
- int ci, coefi, tbl;
- int *coef_bit_ptr;
- jpeg_component_info * compptr;
-
- is_DC_band = (cinfo->Ss == 0);
-
- /* Validate scan parameters */
- bad = FALSE;
- if (is_DC_band) {
- if (cinfo->Se != 0)
- bad = TRUE;
- } else {
- /* need not check Ss/Se < 0 since they came from unsigned bytes */
- if (cinfo->Ss > cinfo->Se || cinfo->Se >= DCTSIZE2)
- bad = TRUE;
- /* AC scans may have only one component */
- if (cinfo->comps_in_scan != 1)
- bad = TRUE;
- }
- if (cinfo->Ah != 0) {
- /* Successive approximation refinement scan: must have Al = Ah-1. */
- if (cinfo->Al != cinfo->Ah-1)
- bad = TRUE;
- }
- if (cinfo->Al > 13) /* need not check for < 0 */
- bad = TRUE;
- /* Arguably the maximum Al value should be less than 13 for 8-bit precision,
- * but the spec doesn't say so, and we try to be liberal about what we
- * accept. Note: large Al values could result in out-of-range DC
- * coefficients during early scans, leading to bizarre displays due to
- * overflows in the IDCT math. But we won't crash.
- */
- if (bad)
- ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
- cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
- /* Update progression status, and verify that scan order is legal.
- * Note that inter-scan inconsistencies are treated as warnings
- * not fatal errors ... not clear if this is right way to behave.
- */
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- int cindex = cinfo->cur_comp_info[ci]->component_index;
- coef_bit_ptr = & cinfo->coef_bits[cindex][0];
- if (!is_DC_band && coef_bit_ptr[0] < 0) /* AC without prior DC scan */
- WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
- for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {
- int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
- if (cinfo->Ah != expected)
- WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);
- coef_bit_ptr[coefi] = cinfo->Al;
- }
- }
-
- /* Select MCU decoding routine */
- if (cinfo->Ah == 0) {
- if (is_DC_band)
- entropy->pub.decode_mcu = decode_mcu_DC_first;
- else
- entropy->pub.decode_mcu = decode_mcu_AC_first;
- } else {
- if (is_DC_band)
- entropy->pub.decode_mcu = decode_mcu_DC_refine;
- else
- entropy->pub.decode_mcu = decode_mcu_AC_refine;
- }
-
- for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
- compptr = cinfo->cur_comp_info[ci];
- /* Make sure requested tables are present, and compute derived tables.
- * We may build same derived table more than once, but it's not expensive.
- */
- if (is_DC_band) {
- if (cinfo->Ah == 0) { /* DC refinement needs no table */
- tbl = compptr->dc_tbl_no;
- jpeg_make_d_derived_tbl(cinfo, TRUE, tbl,
- & entropy->derived_tbls[tbl]);
- }
- } else {
- tbl = compptr->ac_tbl_no;
- jpeg_make_d_derived_tbl(cinfo, FALSE, tbl,
- & entropy->derived_tbls[tbl]);
- /* remember the single active table */
- entropy->ac_derived_tbl = entropy->derived_tbls[tbl];
- }
- /* Initialize DC predictions to 0 */
- entropy->saved.last_dc_val[ci] = 0;
- }
-
- /* Initialize bitread state variables */
- entropy->bitstate.bits_left = 0;
- entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
- entropy->pub.insufficient_data = FALSE;
-
- /* Initialize private state variables */
- entropy->saved.EOBRUN = 0;
-
- /* Initialize restart counter */
- entropy->restarts_to_go = cinfo->restart_interval;
-}
-
-
-/*
- * Figure F.12: extend sign bit.
- * On some machines, a shift and add will be faster than a table lookup.
- */
-
-#ifdef AVOID_TABLES
-
-#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x))
-
-#else
-
-#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
-
-static const int extend_test[16] = /* entry n is 2**(n-1) */
- { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
- 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 };
-
-static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */
- { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1,
- ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1,
- ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1,
- ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 };
-
-#endif /* AVOID_TABLES */
-
-
-/*
- * Check for a restart marker & resynchronize decoder.
- * Returns FALSE if must suspend.
- */
-
-LOCAL(boolean)
-process_restart (j_decompress_ptr cinfo)
-{
- phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
- int ci;
-
- /* Throw away any unused bits remaining in bit buffer; */
- /* include any full bytes in next_marker's count of discarded bytes */
- cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;
- entropy->bitstate.bits_left = 0;
-
- /* Advance past the RSTn marker */
- if (! (*cinfo->marker->read_restart_marker) (cinfo))
- return FALSE;
-
- /* Re-initialize DC predictions to 0 */
- for (ci = 0; ci < cinfo->comps_in_scan; ci++)
- entropy->saved.last_dc_val[ci] = 0;
- /* Re-init EOB run count, too */
- entropy->saved.EOBRUN = 0;
-
- /* Reset restart counter */
- entropy->restarts_to_go = cinfo->restart_interval;
-
- /* Reset out-of-data flag, unless read_restart_marker left us smack up
- * against a marker. In that case we will end up treating the next data
- * segment as empty, and we can avoid producing bogus output pixels by
- * leaving the flag set.
- */
- if (cinfo->unread_marker == 0)
- entropy->pub.insufficient_data = FALSE;
-
- return TRUE;
-}
-
-
-/*
- * Huffman MCU decoding.
- * Each of these routines decodes and returns one MCU's worth of
- * Huffman-compressed coefficients.
- * The coefficients are reordered from zigzag order into natural array order,
- * but are not dequantized.
- *
- * The i'th block of the MCU is stored into the block pointed to by
- * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.
- *
- * We return FALSE if data source requested suspension. In that case no
- * changes have been made to permanent state. (Exception: some output
- * coefficients may already have been assigned. This is harmless for
- * spectral selection, since we'll just re-assign them on the next call.
- * Successive approximation AC refinement has to be more careful, however.)
- */
-
-/*
- * MCU decoding for DC initial scan (either spectral selection,
- * or first pass of successive approximation).
- */
-
-METHODDEF(boolean)
-decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
-{
- phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
- int Al = cinfo->Al;
- register int s, r;
- int blkn, ci;
- JBLOCKROW block;
- BITREAD_STATE_VARS;
- savable_state state;
- d_derived_tbl * tbl;
- jpeg_component_info * compptr;
-
- /* Process restart marker if needed; may have to suspend */
- if (cinfo->restart_interval) {
- if (entropy->restarts_to_go == 0)
- if (! process_restart(cinfo))
- return FALSE;
- }
-
- /* If we've run out of data, just leave the MCU set to zeroes.
- * This way, we return uniform gray for the remainder of the segment.
- */
- if (! entropy->pub.insufficient_data) {
-
- /* Load up working state */
- BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
- ASSIGN_STATE(state, entropy->saved);
-
- /* Outer loop handles each block in the MCU */
-
- for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
- block = MCU_data[blkn];
- ci = cinfo->MCU_membership[blkn];
- compptr = cinfo->cur_comp_info[ci];
- tbl = entropy->derived_tbls[compptr->dc_tbl_no];
-
- /* Decode a single block's worth of coefficients */
-
- /* Section F.2.2.1: decode the DC coefficient difference */
- HUFF_DECODE(s, br_state, tbl, return FALSE, label1);
- if (s) {
- CHECK_BIT_BUFFER(br_state, s, return FALSE);
- r = GET_BITS(s);
- s = HUFF_EXTEND(r, s);
- }
-
- /* Convert DC difference to actual value, update last_dc_val */
- s += state.last_dc_val[ci];
- state.last_dc_val[ci] = s;
- /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */
- (*block)[0] = (JCOEF) (s << Al);
- }
-
- /* Completed MCU, so update state */
- BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
- ASSIGN_STATE(entropy->saved, state);
- }
-
- /* Account for restart interval (no-op if not using restarts) */
- entropy->restarts_to_go--;
-
- return TRUE;
-}
-
-
-/*
- * MCU decoding for AC initial scan (either spectral selection,
- * or first pass of successive approximation).
- */
-
-METHODDEF(boolean)
-decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
-{
- phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
- int Se = cinfo->Se;
- int Al = cinfo->Al;
- register int s, k, r;
- unsigned int EOBRUN;
- JBLOCKROW block;
- BITREAD_STATE_VARS;
- d_derived_tbl * tbl;
-
- /* Process restart marker if needed; may have to suspend */
- if (cinfo->restart_interval) {
- if (entropy->restarts_to_go == 0)
- if (! process_restart(cinfo))
- return FALSE;
- }
-
- /* If we've run out of data, just leave the MCU set to zeroes.
- * This way, we return uniform gray for the remainder of the segment.
- */
- if (! entropy->pub.insufficient_data) {
-
- /* Load up working state.
- * We can avoid loading/saving bitread state if in an EOB run.
- */
- EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */
-
- /* There is always only one block per MCU */
-
- if (EOBRUN > 0) /* if it's a band of zeroes... */
- EOBRUN--; /* ...process it now (we do nothing) */
- else {
- BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
- block = MCU_data[0];
- tbl = entropy->ac_derived_tbl;
-
- for (k = cinfo->Ss; k <= Se; k++) {
- HUFF_DECODE(s, br_state, tbl, return FALSE, label2);
- r = s >> 4;
- s &= 15;
- if (s) {
- k += r;
- CHECK_BIT_BUFFER(br_state, s, return FALSE);
- r = GET_BITS(s);
- s = HUFF_EXTEND(r, s);
- /* Scale and output coefficient in natural (dezigzagged) order */
- (*block)[jpeg_natural_order[k]] = (JCOEF) (s << Al);
- } else {
- if (r == 15) { /* ZRL */
- k += 15; /* skip 15 zeroes in band */
- } else { /* EOBr, run length is 2^r + appended bits */
- EOBRUN = 1 << r;
- if (r) { /* EOBr, r > 0 */
- CHECK_BIT_BUFFER(br_state, r, return FALSE);
- r = GET_BITS(r);
- EOBRUN += r;
- }
- EOBRUN--; /* this band is processed at this moment */
- break; /* force end-of-band */
- }
- }
- }
-
- BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
- }
-
- /* Completed MCU, so update state */
- entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */
- }
-
- /* Account for restart interval (no-op if not using restarts) */
- entropy->restarts_to_go--;
-
- return TRUE;
-}
-
-
-/*
- * MCU decoding for DC successive approximation refinement scan.
- * Note: we assume such scans can be multi-component, although the spec
- * is not very clear on the point.
- */
-
-METHODDEF(boolean)
-decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
-{
- phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
- int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
- int blkn;
- JBLOCKROW block;
- BITREAD_STATE_VARS;
-
- /* Process restart marker if needed; may have to suspend */
- if (cinfo->restart_interval) {
- if (entropy->restarts_to_go == 0)
- if (! process_restart(cinfo))
- return FALSE;
- }
-
- /* Not worth the cycles to check insufficient_data here,
- * since we will not change the data anyway if we read zeroes.
- */
-
- /* Load up working state */
- BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
-
- /* Outer loop handles each block in the MCU */
-
- for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
- block = MCU_data[blkn];
-
- /* Encoded data is simply the next bit of the two's-complement DC value */
- CHECK_BIT_BUFFER(br_state, 1, return FALSE);
- if (GET_BITS(1))
- (*block)[0] |= p1;
- /* Note: since we use |=, repeating the assignment later is safe */
- }
-
- /* Completed MCU, so update state */
- BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
-
- /* Account for restart interval (no-op if not using restarts) */
- entropy->restarts_to_go--;
-
- return TRUE;
-}
-
-
-/*
- * MCU decoding for AC successive approximation refinement scan.
- */
-
-METHODDEF(boolean)
-decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
-{
- phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
- int Se = cinfo->Se;
- int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
- int m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */
- register int s, k, r;
- unsigned int EOBRUN;
- JBLOCKROW block;
- JCOEFPTR thiscoef;
- BITREAD_STATE_VARS;
- d_derived_tbl * tbl;
- int num_newnz;
- int newnz_pos[DCTSIZE2];
-
- /* Process restart marker if needed; may have to suspend */
- if (cinfo->restart_interval) {
- if (entropy->restarts_to_go == 0)
- if (! process_restart(cinfo))
- return FALSE;
- }
-
- /* If we've run out of data, don't modify the MCU.
- */
- if (! entropy->pub.insufficient_data) {
-
- /* Load up working state */
- BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
- EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */
-
- /* There is always only one block per MCU */
- block = MCU_data[0];
- tbl = entropy->ac_derived_tbl;
-
- /* If we are forced to suspend, we must undo the assignments to any newly
- * nonzero coefficients in the block, because otherwise we'd get confused
- * next time about which coefficients were already nonzero.
- * But we need not undo addition of bits to already-nonzero coefficients;
- * instead, we can test the current bit to see if we already did it.
- */
- num_newnz = 0;
-
- /* initialize coefficient loop counter to start of band */
- k = cinfo->Ss;
-
- if (EOBRUN == 0) {
- for (; k <= Se; k++) {
- HUFF_DECODE(s, br_state, tbl, goto undoit, label3);
- r = s >> 4;
- s &= 15;
- if (s) {
- if (s != 1) /* size of new coef should always be 1 */
- WARNMS(cinfo, JWRN_HUFF_BAD_CODE);
- CHECK_BIT_BUFFER(br_state, 1, goto undoit);
- if (GET_BITS(1))
- s = p1; /* newly nonzero coef is positive */
- else
- s = m1; /* newly nonzero coef is negative */
- } else {
- if (r != 15) {
- EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */
- if (r) {
- CHECK_BIT_BUFFER(br_state, r, goto undoit);
- r = GET_BITS(r);
- EOBRUN += r;
- }
- break; /* rest of block is handled by EOB logic */
- }
- /* note s = 0 for processing ZRL */
- }
- /* Advance over already-nonzero coefs and r still-zero coefs,
- * appending correction bits to the nonzeroes. A correction bit is 1
- * if the absolute value of the coefficient must be increased.
- */
- do {
- thiscoef = *block + jpeg_natural_order[k];
- if (*thiscoef != 0) {
- CHECK_BIT_BUFFER(br_state, 1, goto undoit);
- if (GET_BITS(1)) {
- if ((*thiscoef & p1) == 0) { /* do nothing if already set it */
- if (*thiscoef >= 0)
- *thiscoef += p1;
- else
- *thiscoef += m1;
- }
- }
- } else {
- if (--r < 0)
- break; /* reached target zero coefficient */
- }
- k++;
- } while (k <= Se);
- if (s) {
- int pos = jpeg_natural_order[k];
- /* Output newly nonzero coefficient */
- (*block)[pos] = (JCOEF) s;
- /* Remember its position in case we have to suspend */
- newnz_pos[num_newnz++] = pos;
- }
- }
- }
-
- if (EOBRUN > 0) {
- /* Scan any remaining coefficient positions after the end-of-band
- * (the last newly nonzero coefficient, if any). Append a correction
- * bit to each already-nonzero coefficient. A correction bit is 1
- * if the absolute value of the coefficient must be increased.
- */
- for (; k <= Se; k++) {
- thiscoef = *block + jpeg_natural_order[k];
- if (*thiscoef != 0) {
- CHECK_BIT_BUFFER(br_state, 1, goto undoit);
- if (GET_BITS(1)) {
- if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */
- if (*thiscoef >= 0)
- *thiscoef += p1;
- else
- *thiscoef += m1;
- }
- }
- }
- }
- /* Count one block completed in EOB run */
- EOBRUN--;
- }
-
- /* Completed MCU, so update state */
- BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
- entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */
- }
-
- /* Account for restart interval (no-op if not using restarts) */
- entropy->restarts_to_go--;
-
- return TRUE;
-
-undoit:
- /* Re-zero any output coefficients that we made newly nonzero */
- while (num_newnz > 0)
- (*block)[newnz_pos[--num_newnz]] = 0;
-
- return FALSE;
-}
-
-
-/*
- * Module initialization routine for progressive Huffman entropy decoding.
- */
-
-GLOBAL(void)
-jinit_phuff_decoder (j_decompress_ptr cinfo)
-{
- phuff_entropy_ptr entropy;
- int *coef_bit_ptr;
- int ci, i;
-
- entropy = (phuff_entropy_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(phuff_entropy_decoder));
- cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
- entropy->pub.start_pass = start_pass_phuff_decoder;
-
- /* Mark derived tables unallocated */
- for (i = 0; i < NUM_HUFF_TBLS; i++) {
- entropy->derived_tbls[i] = NULL;
- }
-
- /* Create progression status table */
- cinfo->coef_bits = (int (*)[DCTSIZE2])
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- cinfo->num_components*DCTSIZE2*SIZEOF(int));
- coef_bit_ptr = & cinfo->coef_bits[0][0];
- for (ci = 0; ci < cinfo->num_components; ci++)
- for (i = 0; i < DCTSIZE2; i++)
- *coef_bit_ptr++ = -1;
-}
-
-#endif /* D_PROGRESSIVE_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jdpostct.c b/engine/code/jpeg-6b/jdpostct.c
deleted file mode 100644
index 571563d..0000000
--- a/engine/code/jpeg-6b/jdpostct.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * jdpostct.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains the decompression postprocessing controller.
- * This controller manages the upsampling, color conversion, and color
- * quantization/reduction steps; specifically, it controls the buffering
- * between upsample/color conversion and color quantization/reduction.
- *
- * If no color quantization/reduction is required, then this module has no
- * work to do, and it just hands off to the upsample/color conversion code.
- * An integrated upsample/convert/quantize process would replace this module
- * entirely.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* Private buffer controller object */
-
-typedef struct {
- struct jpeg_d_post_controller pub; /* public fields */
-
- /* Color quantization source buffer: this holds output data from
- * the upsample/color conversion step to be passed to the quantizer.
- * For two-pass color quantization, we need a full-image buffer;
- * for one-pass operation, a strip buffer is sufficient.
- */
- jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */
- JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */
- JDIMENSION strip_height; /* buffer size in rows */
- /* for two-pass mode only: */
- JDIMENSION starting_row; /* row # of first row in current strip */
- JDIMENSION next_row; /* index of next row to fill/empty in strip */
-} my_post_controller;
-
-typedef my_post_controller * my_post_ptr;
-
-
-/* Forward declarations */
-METHODDEF(void) post_process_1pass
- JPP((j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail));
-#ifdef QUANT_2PASS_SUPPORTED
-METHODDEF(void) post_process_prepass
- JPP((j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail));
-METHODDEF(void) post_process_2pass
- JPP((j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail));
-#endif
-
-
-/*
- * Initialize for a processing pass.
- */
-
-METHODDEF(void)
-start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
-{
- my_post_ptr post = (my_post_ptr) cinfo->post;
-
- switch (pass_mode) {
- case JBUF_PASS_THRU:
- if (cinfo->quantize_colors) {
- /* Single-pass processing with color quantization. */
- post->pub.post_process_data = post_process_1pass;
- /* We could be doing buffered-image output before starting a 2-pass
- * color quantization; in that case, jinit_d_post_controller did not
- * allocate a strip buffer. Use the virtual-array buffer as workspace.
- */
- if (post->buffer == NULL) {
- post->buffer = (*cinfo->mem->access_virt_sarray)
- ((j_common_ptr) cinfo, post->whole_image,
- (JDIMENSION) 0, post->strip_height, TRUE);
- }
- } else {
- /* For single-pass processing without color quantization,
- * I have no work to do; just call the upsampler directly.
- */
- post->pub.post_process_data = cinfo->upsample->upsample;
- }
- break;
-#ifdef QUANT_2PASS_SUPPORTED
- case JBUF_SAVE_AND_PASS:
- /* First pass of 2-pass quantization */
- if (post->whole_image == NULL)
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- post->pub.post_process_data = post_process_prepass;
- break;
- case JBUF_CRANK_DEST:
- /* Second pass of 2-pass quantization */
- if (post->whole_image == NULL)
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- post->pub.post_process_data = post_process_2pass;
- break;
-#endif /* QUANT_2PASS_SUPPORTED */
- default:
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- break;
- }
- post->starting_row = post->next_row = 0;
-}
-
-
-/*
- * Process some data in the one-pass (strip buffer) case.
- * This is used for color precision reduction as well as one-pass quantization.
- */
-
-METHODDEF(void)
-post_process_1pass (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail)
-{
- my_post_ptr post = (my_post_ptr) cinfo->post;
- JDIMENSION num_rows, max_rows;
-
- /* Fill the buffer, but not more than what we can dump out in one go. */
- /* Note we rely on the upsampler to detect bottom of image. */
- max_rows = out_rows_avail - *out_row_ctr;
- if (max_rows > post->strip_height)
- max_rows = post->strip_height;
- num_rows = 0;
- (*cinfo->upsample->upsample) (cinfo,
- input_buf, in_row_group_ctr, in_row_groups_avail,
- post->buffer, &num_rows, max_rows);
- /* Quantize and emit data. */
- (*cinfo->cquantize->color_quantize) (cinfo,
- post->buffer, output_buf + *out_row_ctr, (int) num_rows);
- *out_row_ctr += num_rows;
-}
-
-
-#ifdef QUANT_2PASS_SUPPORTED
-
-/*
- * Process some data in the first pass of 2-pass quantization.
- */
-
-METHODDEF(void)
-post_process_prepass (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail)
-{
- my_post_ptr post = (my_post_ptr) cinfo->post;
- JDIMENSION old_next_row, num_rows;
-
- /* Reposition virtual buffer if at start of strip. */
- if (post->next_row == 0) {
- post->buffer = (*cinfo->mem->access_virt_sarray)
- ((j_common_ptr) cinfo, post->whole_image,
- post->starting_row, post->strip_height, TRUE);
- }
-
- /* Upsample some data (up to a strip height's worth). */
- old_next_row = post->next_row;
- (*cinfo->upsample->upsample) (cinfo,
- input_buf, in_row_group_ctr, in_row_groups_avail,
- post->buffer, &post->next_row, post->strip_height);
-
- /* Allow quantizer to scan new data. No data is emitted, */
- /* but we advance out_row_ctr so outer loop can tell when we're done. */
- if (post->next_row > old_next_row) {
- num_rows = post->next_row - old_next_row;
- (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row,
- (JSAMPARRAY) NULL, (int) num_rows);
- *out_row_ctr += num_rows;
- }
-
- /* Advance if we filled the strip. */
- if (post->next_row >= post->strip_height) {
- post->starting_row += post->strip_height;
- post->next_row = 0;
- }
-}
-
-
-/*
- * Process some data in the second pass of 2-pass quantization.
- */
-
-METHODDEF(void)
-post_process_2pass (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail)
-{
- my_post_ptr post = (my_post_ptr) cinfo->post;
- JDIMENSION num_rows, max_rows;
-
- /* Reposition virtual buffer if at start of strip. */
- if (post->next_row == 0) {
- post->buffer = (*cinfo->mem->access_virt_sarray)
- ((j_common_ptr) cinfo, post->whole_image,
- post->starting_row, post->strip_height, FALSE);
- }
-
- /* Determine number of rows to emit. */
- num_rows = post->strip_height - post->next_row; /* available in strip */
- max_rows = out_rows_avail - *out_row_ctr; /* available in output area */
- if (num_rows > max_rows)
- num_rows = max_rows;
- /* We have to check bottom of image here, can't depend on upsampler. */
- max_rows = cinfo->output_height - post->starting_row;
- if (num_rows > max_rows)
- num_rows = max_rows;
-
- /* Quantize and emit data. */
- (*cinfo->cquantize->color_quantize) (cinfo,
- post->buffer + post->next_row, output_buf + *out_row_ctr,
- (int) num_rows);
- *out_row_ctr += num_rows;
-
- /* Advance if we filled the strip. */
- post->next_row += num_rows;
- if (post->next_row >= post->strip_height) {
- post->starting_row += post->strip_height;
- post->next_row = 0;
- }
-}
-
-#endif /* QUANT_2PASS_SUPPORTED */
-
-
-/*
- * Initialize postprocessing controller.
- */
-
-GLOBAL(void)
-jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
-{
- my_post_ptr post;
-
- post = (my_post_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_post_controller));
- cinfo->post = (struct jpeg_d_post_controller *) post;
- post->pub.start_pass = start_pass_dpost;
- post->whole_image = NULL; /* flag for no virtual arrays */
- post->buffer = NULL; /* flag for no strip buffer */
-
- /* Create the quantization buffer, if needed */
- if (cinfo->quantize_colors) {
- /* The buffer strip height is max_v_samp_factor, which is typically
- * an efficient number of rows for upsampling to return.
- * (In the presence of output rescaling, we might want to be smarter?)
- */
- post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor;
- if (need_full_buffer) {
- /* Two-pass color quantization: need full-image storage. */
- /* We round up the number of rows to a multiple of the strip height. */
-#ifdef QUANT_2PASS_SUPPORTED
- post->whole_image = (*cinfo->mem->request_virt_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
- cinfo->output_width * cinfo->out_color_components,
- (JDIMENSION) jround_up((long) cinfo->output_height,
- (long) post->strip_height),
- post->strip_height);
-#else
- ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
-#endif /* QUANT_2PASS_SUPPORTED */
- } else {
- /* One-pass color quantization: just make a strip buffer. */
- post->buffer = (*cinfo->mem->alloc_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- cinfo->output_width * cinfo->out_color_components,
- post->strip_height);
- }
- }
-}
diff --git a/engine/code/jpeg-6b/jdsample.c b/engine/code/jpeg-6b/jdsample.c
deleted file mode 100644
index 80ffefb..0000000
--- a/engine/code/jpeg-6b/jdsample.c
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * jdsample.c
- *
- * Copyright (C) 1991-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains upsampling routines.
- *
- * Upsampling input data is counted in "row groups". A row group
- * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
- * sample rows of each component. Upsampling will normally produce
- * max_v_samp_factor pixel rows from each row group (but this could vary
- * if the upsampler is applying a scale factor of its own).
- *
- * An excellent reference for image resampling is
- * Digital Image Warping, George Wolberg, 1990.
- * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* Pointer to routine to upsample a single component */
-typedef JMETHOD(void, upsample1_ptr,
- (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr));
-
-/* Private subobject */
-
-typedef struct {
- struct jpeg_upsampler pub; /* public fields */
-
- /* Color conversion buffer. When using separate upsampling and color
- * conversion steps, this buffer holds one upsampled row group until it
- * has been color converted and output.
- * Note: we do not allocate any storage for component(s) which are full-size,
- * ie do not need rescaling. The corresponding entry of color_buf[] is
- * simply set to point to the input data array, thereby avoiding copying.
- */
- JSAMPARRAY color_buf[MAX_COMPONENTS];
-
- /* Per-component upsampling method pointers */
- upsample1_ptr methods[MAX_COMPONENTS];
-
- int next_row_out; /* counts rows emitted from color_buf */
- JDIMENSION rows_to_go; /* counts rows remaining in image */
-
- /* Height of an input row group for each component. */
- int rowgroup_height[MAX_COMPONENTS];
-
- /* These arrays save pixel expansion factors so that int_expand need not
- * recompute them each time. They are unused for other upsampling methods.
- */
- UINT8 h_expand[MAX_COMPONENTS];
- UINT8 v_expand[MAX_COMPONENTS];
-} my_upsampler;
-
-typedef my_upsampler * my_upsample_ptr;
-
-
-/*
- * Initialize for an upsampling pass.
- */
-
-METHODDEF(void)
-start_pass_upsample (j_decompress_ptr cinfo)
-{
- my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
-
- /* Mark the conversion buffer empty */
- upsample->next_row_out = cinfo->max_v_samp_factor;
- /* Initialize total-height counter for detecting bottom of image */
- upsample->rows_to_go = cinfo->output_height;
-}
-
-
-/*
- * Control routine to do upsampling (and color conversion).
- *
- * In this version we upsample each component independently.
- * We upsample one row group into the conversion buffer, then apply
- * color conversion a row at a time.
- */
-
-METHODDEF(void)
-sep_upsample (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail)
-{
- my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
- int ci;
- jpeg_component_info * compptr;
- JDIMENSION num_rows;
-
- /* Fill the conversion buffer, if it's empty */
- if (upsample->next_row_out >= cinfo->max_v_samp_factor) {
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* Invoke per-component upsample method. Notice we pass a POINTER
- * to color_buf[ci], so that fullsize_upsample can change it.
- */
- (*upsample->methods[ci]) (cinfo, compptr,
- input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]),
- upsample->color_buf + ci);
- }
- upsample->next_row_out = 0;
- }
-
- /* Color-convert and emit rows */
-
- /* How many we have in the buffer: */
- num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out);
- /* Not more than the distance to the end of the image. Need this test
- * in case the image height is not a multiple of max_v_samp_factor:
- */
- if (num_rows > upsample->rows_to_go)
- num_rows = upsample->rows_to_go;
- /* And not more than what the client can accept: */
- out_rows_avail -= *out_row_ctr;
- if (num_rows > out_rows_avail)
- num_rows = out_rows_avail;
-
- (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf,
- (JDIMENSION) upsample->next_row_out,
- output_buf + *out_row_ctr,
- (int) num_rows);
-
- /* Adjust counts */
- *out_row_ctr += num_rows;
- upsample->rows_to_go -= num_rows;
- upsample->next_row_out += num_rows;
- /* When the buffer is emptied, declare this input row group consumed */
- if (upsample->next_row_out >= cinfo->max_v_samp_factor)
- (*in_row_group_ctr)++;
-}
-
-
-/*
- * These are the routines invoked by sep_upsample to upsample pixel values
- * of a single component. One row group is processed per call.
- */
-
-
-/*
- * For full-size components, we just make color_buf[ci] point at the
- * input buffer, and thus avoid copying any data. Note that this is
- * safe only because sep_upsample doesn't declare the input row group
- * "consumed" until we are done color converting and emitting it.
- */
-
-METHODDEF(void)
-fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
-{
- *output_data_ptr = input_data;
-}
-
-
-/*
- * This is a no-op version used for "uninteresting" components.
- * These components will not be referenced by color conversion.
- */
-
-METHODDEF(void)
-noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
-{
- *output_data_ptr = NULL; /* safety check */
-}
-
-
-/*
- * This version handles any integral sampling ratios.
- * This is not used for typical JPEG files, so it need not be fast.
- * Nor, for that matter, is it particularly accurate: the algorithm is
- * simple replication of the input pixel onto the corresponding output
- * pixels. The hi-falutin sampling literature refers to this as a
- * "box filter". A box filter tends to introduce visible artifacts,
- * so if you are actually going to use 3:1 or 4:1 sampling ratios
- * you would be well advised to improve this code.
- */
-
-METHODDEF(void)
-int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
-{
- my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr, outptr;
- register JSAMPLE invalue;
- register int h;
- JSAMPROW outend;
- int h_expand, v_expand;
- int inrow, outrow;
-
- h_expand = upsample->h_expand[compptr->component_index];
- v_expand = upsample->v_expand[compptr->component_index];
-
- inrow = outrow = 0;
- while (outrow < cinfo->max_v_samp_factor) {
- /* Generate one output row with proper horizontal expansion */
- inptr = input_data[inrow];
- outptr = output_data[outrow];
- outend = outptr + cinfo->output_width;
- while (outptr < outend) {
- invalue = *inptr++; /* don't need GETJSAMPLE() here */
- for (h = h_expand; h > 0; h--) {
- *outptr++ = invalue;
- }
- }
- /* Generate any additional output rows by duplicating the first one */
- if (v_expand > 1) {
- jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
- v_expand-1, cinfo->output_width);
- }
- inrow++;
- outrow += v_expand;
- }
-}
-
-
-/*
- * Fast processing for the common case of 2:1 horizontal and 1:1 vertical.
- * It's still a box filter.
- */
-
-METHODDEF(void)
-h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
-{
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr, outptr;
- register JSAMPLE invalue;
- JSAMPROW outend;
- int inrow;
-
- for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
- inptr = input_data[inrow];
- outptr = output_data[inrow];
- outend = outptr + cinfo->output_width;
- while (outptr < outend) {
- invalue = *inptr++; /* don't need GETJSAMPLE() here */
- *outptr++ = invalue;
- *outptr++ = invalue;
- }
- }
-}
-
-
-/*
- * Fast processing for the common case of 2:1 horizontal and 2:1 vertical.
- * It's still a box filter.
- */
-
-METHODDEF(void)
-h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
-{
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr, outptr;
- register JSAMPLE invalue;
- JSAMPROW outend;
- int inrow, outrow;
-
- inrow = outrow = 0;
- while (outrow < cinfo->max_v_samp_factor) {
- inptr = input_data[inrow];
- outptr = output_data[outrow];
- outend = outptr + cinfo->output_width;
- while (outptr < outend) {
- invalue = *inptr++; /* don't need GETJSAMPLE() here */
- *outptr++ = invalue;
- *outptr++ = invalue;
- }
- jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
- 1, cinfo->output_width);
- inrow++;
- outrow += 2;
- }
-}
-
-
-/*
- * Fancy processing for the common case of 2:1 horizontal and 1:1 vertical.
- *
- * The upsampling algorithm is linear interpolation between pixel centers,
- * also known as a "triangle filter". This is a good compromise between
- * speed and visual quality. The centers of the output pixels are 1/4 and 3/4
- * of the way between input pixel centers.
- *
- * A note about the "bias" calculations: when rounding fractional values to
- * integer, we do not want to always round 0.5 up to the next integer.
- * If we did that, we'd introduce a noticeable bias towards larger values.
- * Instead, this code is arranged so that 0.5 will be rounded up or down at
- * alternate pixel locations (a simple ordered dither pattern).
- */
-
-METHODDEF(void)
-h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
-{
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr, outptr;
- register int invalue;
- register JDIMENSION colctr;
- int inrow;
-
- for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
- inptr = input_data[inrow];
- outptr = output_data[inrow];
- /* Special case for first column */
- invalue = GETJSAMPLE(*inptr++);
- *outptr++ = (JSAMPLE) invalue;
- *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(*inptr) + 2) >> 2);
-
- for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) {
- /* General case: 3/4 * nearer pixel + 1/4 * further pixel */
- invalue = GETJSAMPLE(*inptr++) * 3;
- *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(inptr[-2]) + 1) >> 2);
- *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(*inptr) + 2) >> 2);
- }
-
- /* Special case for last column */
- invalue = GETJSAMPLE(*inptr);
- *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(inptr[-1]) + 1) >> 2);
- *outptr++ = (JSAMPLE) invalue;
- }
-}
-
-
-/*
- * Fancy processing for the common case of 2:1 horizontal and 2:1 vertical.
- * Again a triangle filter; see comments for h2v1 case, above.
- *
- * It is OK for us to reference the adjacent input rows because we demanded
- * context from the main buffer controller (see initialization code).
- */
-
-METHODDEF(void)
-h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
-{
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr0, inptr1, outptr;
-#if BITS_IN_JSAMPLE == 8
- register int thiscolsum, lastcolsum, nextcolsum;
-#else
- register INT32 thiscolsum, lastcolsum, nextcolsum;
-#endif
- register JDIMENSION colctr;
- int inrow, outrow, v;
-
- inrow = outrow = 0;
- while (outrow < cinfo->max_v_samp_factor) {
- for (v = 0; v < 2; v++) {
- /* inptr0 points to nearest input row, inptr1 points to next nearest */
- inptr0 = input_data[inrow];
- if (v == 0) /* next nearest is row above */
- inptr1 = input_data[inrow-1];
- else /* next nearest is row below */
- inptr1 = input_data[inrow+1];
- outptr = output_data[outrow++];
-
- /* Special case for first column */
- thiscolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++);
- nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++);
- *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 8) >> 4);
- *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4);
- lastcolsum = thiscolsum; thiscolsum = nextcolsum;
-
- for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) {
- /* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */
- /* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */
- nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++);
- *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4);
- *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4);
- lastcolsum = thiscolsum; thiscolsum = nextcolsum;
- }
-
- /* Special case for last column */
- *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4);
- *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 7) >> 4);
- }
- inrow++;
- }
-}
-
-
-/*
- * Module initialization routine for upsampling.
- */
-
-GLOBAL(void)
-jinit_upsampler (j_decompress_ptr cinfo)
-{
- my_upsample_ptr upsample;
- int ci;
- jpeg_component_info * compptr;
- boolean need_buffer, do_fancy;
- int h_in_group, v_in_group, h_out_group, v_out_group;
-
- upsample = (my_upsample_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_upsampler));
- cinfo->upsample = (struct jpeg_upsampler *) upsample;
- upsample->pub.start_pass = start_pass_upsample;
- upsample->pub.upsample = sep_upsample;
- upsample->pub.need_context_rows = FALSE; /* until we find out differently */
-
- if (cinfo->CCIR601_sampling) /* this isn't supported */
- ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
-
- /* jdmainct.c doesn't support context rows when min_DCT_scaled_size = 1,
- * so don't ask for it.
- */
- do_fancy = cinfo->do_fancy_upsampling && cinfo->min_DCT_scaled_size > 1;
-
- /* Verify we can handle the sampling factors, select per-component methods,
- * and create storage as needed.
- */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* Compute size of an "input group" after IDCT scaling. This many samples
- * are to be converted to max_h_samp_factor * max_v_samp_factor pixels.
- */
- h_in_group = (compptr->h_samp_factor * compptr->DCT_scaled_size) /
- cinfo->min_DCT_scaled_size;
- v_in_group = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
- cinfo->min_DCT_scaled_size;
- h_out_group = cinfo->max_h_samp_factor;
- v_out_group = cinfo->max_v_samp_factor;
- upsample->rowgroup_height[ci] = v_in_group; /* save for use later */
- need_buffer = TRUE;
- if (! compptr->component_needed) {
- /* Don't bother to upsample an uninteresting component. */
- upsample->methods[ci] = noop_upsample;
- need_buffer = FALSE;
- } else if (h_in_group == h_out_group && v_in_group == v_out_group) {
- /* Fullsize components can be processed without any work. */
- upsample->methods[ci] = fullsize_upsample;
- need_buffer = FALSE;
- } else if (h_in_group * 2 == h_out_group &&
- v_in_group == v_out_group) {
- /* Special cases for 2h1v upsampling */
- if (do_fancy && compptr->downsampled_width > 2)
- upsample->methods[ci] = h2v1_fancy_upsample;
- else
- upsample->methods[ci] = h2v1_upsample;
- } else if (h_in_group * 2 == h_out_group &&
- v_in_group * 2 == v_out_group) {
- /* Special cases for 2h2v upsampling */
- if (do_fancy && compptr->downsampled_width > 2) {
- upsample->methods[ci] = h2v2_fancy_upsample;
- upsample->pub.need_context_rows = TRUE;
- } else
- upsample->methods[ci] = h2v2_upsample;
- } else if ((h_out_group % h_in_group) == 0 &&
- (v_out_group % v_in_group) == 0) {
- /* Generic integral-factors upsampling method */
- upsample->methods[ci] = int_upsample;
- upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group);
- upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group);
- } else
- ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
- if (need_buffer) {
- upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (JDIMENSION) jround_up((long) cinfo->output_width,
- (long) cinfo->max_h_samp_factor),
- (JDIMENSION) cinfo->max_v_samp_factor);
- }
- }
-}
diff --git a/engine/code/jpeg-6b/jdtrans.c b/engine/code/jpeg-6b/jdtrans.c
deleted file mode 100644
index 6c0ab71..0000000
--- a/engine/code/jpeg-6b/jdtrans.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * jdtrans.c
- *
- * Copyright (C) 1995-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains library routines for transcoding decompression,
- * that is, reading raw DCT coefficient arrays from an input JPEG file.
- * The routines in jdapimin.c will also be needed by a transcoder.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/* Forward declarations */
-LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo));
-
-
-/*
- * Read the coefficient arrays from a JPEG file.
- * jpeg_read_header must be completed before calling this.
- *
- * The entire image is read into a set of virtual coefficient-block arrays,
- * one per component. The return value is a pointer to the array of
- * virtual-array descriptors. These can be manipulated directly via the
- * JPEG memory manager, or handed off to jpeg_write_coefficients().
- * To release the memory occupied by the virtual arrays, call
- * jpeg_finish_decompress() when done with the data.
- *
- * An alternative usage is to simply obtain access to the coefficient arrays
- * during a buffered-image-mode decompression operation. This is allowed
- * after any jpeg_finish_output() call. The arrays can be accessed until
- * jpeg_finish_decompress() is called. (Note that any call to the library
- * may reposition the arrays, so don't rely on access_virt_barray() results
- * to stay valid across library calls.)
- *
- * Returns NULL if suspended. This case need be checked only if
- * a suspending data source is used.
- */
-
-GLOBAL(jvirt_barray_ptr *)
-jpeg_read_coefficients (j_decompress_ptr cinfo)
-{
- if (cinfo->global_state == DSTATE_READY) {
- /* First call: initialize active modules */
- transdecode_master_selection(cinfo);
- cinfo->global_state = DSTATE_RDCOEFS;
- }
- if (cinfo->global_state == DSTATE_RDCOEFS) {
- /* Absorb whole file into the coef buffer */
- for (;;) {
- int retcode;
- /* Call progress monitor hook if present */
- if (cinfo->progress != NULL)
- (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
- /* Absorb some more input */
- retcode = (*cinfo->inputctl->consume_input) (cinfo);
- if (retcode == JPEG_SUSPENDED)
- return NULL;
- if (retcode == JPEG_REACHED_EOI)
- break;
- /* Advance progress counter if appropriate */
- if (cinfo->progress != NULL &&
- (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
- if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
- /* startup underestimated number of scans; ratchet up one scan */
- cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
- }
- }
- }
- /* Set state so that jpeg_finish_decompress does the right thing */
- cinfo->global_state = DSTATE_STOPPING;
- }
- /* At this point we should be in state DSTATE_STOPPING if being used
- * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access
- * to the coefficients during a full buffered-image-mode decompression.
- */
- if ((cinfo->global_state == DSTATE_STOPPING ||
- cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) {
- return cinfo->coef->coef_arrays;
- }
- /* Oops, improper usage */
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- return NULL; /* keep compiler happy */
-}
-
-
-/*
- * Master selection of decompression modules for transcoding.
- * This substitutes for jdmaster.c's initialization of the full decompressor.
- */
-
-LOCAL(void)
-transdecode_master_selection (j_decompress_ptr cinfo)
-{
- /* This is effectively a buffered-image operation. */
- cinfo->buffered_image = TRUE;
-
- /* Entropy decoding: either Huffman or arithmetic coding. */
- if (cinfo->arith_code) {
- ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
- } else {
- if (cinfo->progressive_mode) {
-#ifdef D_PROGRESSIVE_SUPPORTED
- jinit_phuff_decoder(cinfo);
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- } else
- jinit_huff_decoder(cinfo);
- }
-
- /* Always get a full-image coefficient buffer. */
- jinit_d_coef_controller(cinfo, TRUE);
-
- /* We can now tell the memory manager to allocate virtual arrays. */
- (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
-
- /* Initialize input side of decompressor to consume first scan. */
- (*cinfo->inputctl->start_input_pass) (cinfo);
-
- /* Initialize progress monitoring. */
- if (cinfo->progress != NULL) {
- int nscans;
- /* Estimate number of scans to set pass_limit. */
- if (cinfo->progressive_mode) {
- /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
- nscans = 2 + 3 * cinfo->num_components;
- } else if (cinfo->inputctl->has_multiple_scans) {
- /* For a nonprogressive multiscan file, estimate 1 scan per component. */
- nscans = cinfo->num_components;
- } else {
- nscans = 1;
- }
- cinfo->progress->pass_counter = 0L;
- cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;
- cinfo->progress->completed_passes = 0;
- cinfo->progress->total_passes = 1;
- }
-}
diff --git a/engine/code/jpeg-6b/jerror.c b/engine/code/jpeg-6b/jerror.c
deleted file mode 100644
index 9df35d6..0000000
--- a/engine/code/jpeg-6b/jerror.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * jerror.c
- *
- * Copyright (C) 1991-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains simple error-reporting and trace-message routines.
- * These are suitable for Unix-like systems and others where writing to
- * stderr is the right thing to do. Many applications will want to replace
- * some or all of these routines.
- *
- * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile,
- * you get a Windows-specific hack to display error messages in a dialog box.
- * It ain't much, but it beats dropping error messages into the bit bucket,
- * which is what happens to output to stderr under most Windows C compilers.
- *
- * These routines are used by both the compression and decompression code.
- */
-
-#include "../renderer/tr_local.h"
-
-/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jversion.h"
-#include "jerror.h"
-
-#ifdef USE_WINDOWS_MESSAGEBOX
-#include <windows.h>
-#endif
-
-#ifndef EXIT_FAILURE /* define exit() codes if not provided */
-#define EXIT_FAILURE 1
-#endif
-
-
-/*
- * Create the message string table.
- * We do this from the master message list in jerror.h by re-reading
- * jerror.h with a suitable definition for macro JMESSAGE.
- * The message table is made an external symbol just in case any applications
- * want to refer to it directly.
- */
-
-#ifdef NEED_SHORT_EXTERNAL_NAMES
-#define jpeg_std_message_table jMsgTable
-#endif
-
-#define JMESSAGE(code,string) string ,
-
-const char * const jpeg_std_message_table[] = {
-#include "jerror.h"
- NULL
-};
-
-
-/*
- * Error exit handler: must not return to caller.
- *
- * Applications may override this if they want to get control back after
- * an error. Typically one would longjmp somewhere instead of exiting.
- * The setjmp buffer can be made a private field within an expanded error
- * handler object. Note that the info needed to generate an error message
- * is stored in the error object, so you can generate the message now or
- * later, at your convenience.
- * You should make sure that the JPEG object is cleaned up (with jpeg_abort
- * or jpeg_destroy) at some point.
- */
-
-METHODDEF(void)
-error_exit (j_common_ptr cinfo)
-{
- char buffer[JMSG_LENGTH_MAX];
-
- /* Create the message */
- (*cinfo->err->format_message) (cinfo, buffer);
-
- /* Let the memory manager delete any temp files before we die */
- jpeg_destroy(cinfo);
-
- ri.Error( ERR_FATAL, "%s\n", buffer );
-}
-
-
-/*
- * Actual output of an error or trace message.
- * Applications may override this method to send JPEG messages somewhere
- * other than stderr.
- *
- * On Windows, printing to stderr is generally completely useless,
- * so we provide optional code to produce an error-dialog popup.
- * Most Windows applications will still prefer to override this routine,
- * but if they don't, it'll do something at least marginally useful.
- *
- * NOTE: to use the library in an environment that doesn't support the
- * C stdio library, you may have to delete the call to fprintf() entirely,
- * not just not use this routine.
- */
-
-METHODDEF(void)
-output_message (j_common_ptr cinfo)
-{
- char buffer[JMSG_LENGTH_MAX];
-
- /* Create the message */
- (*cinfo->err->format_message) (cinfo, buffer);
-
-#ifdef USE_WINDOWS_MESSAGEBOX
- /* Display it in a message dialog box */
- MessageBox(GetActiveWindow(), buffer, "JPEG Library Error",
- MB_OK | MB_ICONERROR);
-#else
- /* Send it to stderr, adding a newline */
- ri.Printf(PRINT_ALL, "%s\n", buffer);
-#endif
-}
-
-
-/*
- * Decide whether to emit a trace or warning message.
- * msg_level is one of:
- * -1: recoverable corrupt-data warning, may want to abort.
- * 0: important advisory messages (always display to user).
- * 1: first level of tracing detail.
- * 2,3,...: successively more detailed tracing messages.
- * An application might override this method if it wanted to abort on warnings
- * or change the policy about which messages to display.
- */
-
-METHODDEF(void)
-emit_message (j_common_ptr cinfo, int msg_level)
-{
- struct jpeg_error_mgr * err = cinfo->err;
-
- if (msg_level < 0) {
- /* It's a warning message. Since corrupt files may generate many warnings,
- * the policy implemented here is to show only the first warning,
- * unless trace_level >= 3.
- */
- if (err->num_warnings == 0 || err->trace_level >= 3)
- (*err->output_message) (cinfo);
- /* Always count warnings in num_warnings. */
- err->num_warnings++;
- } else {
- /* It's a trace message. Show it if trace_level >= msg_level. */
- if (err->trace_level >= msg_level)
- (*err->output_message) (cinfo);
- }
-}
-
-
-/*
- * Format a message string for the most recent JPEG error or message.
- * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX
- * characters. Note that no '\n' character is added to the string.
- * Few applications should need to override this method.
- */
-
-METHODDEF(void)
-format_message (j_common_ptr cinfo, char * buffer)
-{
- struct jpeg_error_mgr * err = cinfo->err;
- int msg_code = err->msg_code;
- const char * msgtext = NULL;
- const char * msgptr;
- char ch;
- boolean isstring;
-
- /* Look up message string in proper table */
- if (msg_code > 0 && msg_code <= err->last_jpeg_message) {
- msgtext = err->jpeg_message_table[msg_code];
- } else if (err->addon_message_table != NULL &&
- msg_code >= err->first_addon_message &&
- msg_code <= err->last_addon_message) {
- msgtext = err->addon_message_table[msg_code - err->first_addon_message];
- }
-
- /* Defend against bogus message number */
- if (msgtext == NULL) {
- err->msg_parm.i[0] = msg_code;
- msgtext = err->jpeg_message_table[0];
- }
-
- /* Check for string parameter, as indicated by %s in the message text */
- isstring = FALSE;
- msgptr = msgtext;
- while ((ch = *msgptr++) != '\0') {
- if (ch == '%') {
- if (*msgptr == 's') isstring = TRUE;
- break;
- }
- }
-
- /* Format the message into the passed buffer */
- if (isstring)
- sprintf(buffer, msgtext, err->msg_parm.s);
- else
- sprintf(buffer, msgtext,
- err->msg_parm.i[0], err->msg_parm.i[1],
- err->msg_parm.i[2], err->msg_parm.i[3],
- err->msg_parm.i[4], err->msg_parm.i[5],
- err->msg_parm.i[6], err->msg_parm.i[7]);
-}
-
-
-/*
- * Reset error state variables at start of a new image.
- * This is called during compression startup to reset trace/error
- * processing to default state, without losing any application-specific
- * method pointers. An application might possibly want to override
- * this method if it has additional error processing state.
- */
-
-METHODDEF(void)
-reset_error_mgr (j_common_ptr cinfo)
-{
- cinfo->err->num_warnings = 0;
- /* trace_level is not reset since it is an application-supplied parameter */
- cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */
-}
-
-
-/*
- * Fill in the standard error-handling methods in a jpeg_error_mgr object.
- * Typical call is:
- * struct jpeg_compress_struct cinfo;
- * struct jpeg_error_mgr err;
- *
- * cinfo.err = jpeg_std_error(&err);
- * after which the application may override some of the methods.
- */
-
-GLOBAL(struct jpeg_error_mgr *)
-jpeg_std_error (struct jpeg_error_mgr * err)
-{
- err->error_exit = error_exit;
- err->emit_message = emit_message;
- err->output_message = output_message;
- err->format_message = format_message;
- err->reset_error_mgr = reset_error_mgr;
-
- err->trace_level = 0; /* default = no tracing */
- err->num_warnings = 0; /* no warnings emitted yet */
- err->msg_code = 0; /* may be useful as a flag for "no error" */
-
- /* Initialize message table pointers */
- err->jpeg_message_table = jpeg_std_message_table;
- err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1;
-
- err->addon_message_table = NULL;
- err->first_addon_message = 0; /* for safety */
- err->last_addon_message = 0;
-
- return err;
-}
diff --git a/engine/code/jpeg-6b/jerror.h b/engine/code/jpeg-6b/jerror.h
deleted file mode 100644
index fc2fffe..0000000
--- a/engine/code/jpeg-6b/jerror.h
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * jerror.h
- *
- * Copyright (C) 1994-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file defines the error and message codes for the JPEG library.
- * Edit this file to add new codes, or to translate the message strings to
- * some other language.
- * A set of error-reporting macros are defined too. Some applications using
- * the JPEG library may wish to include this file to get the error codes
- * and/or the macros.
- */
-
-/*
- * To define the enum list of message codes, include this file without
- * defining macro JMESSAGE. To create a message string table, include it
- * again with a suitable JMESSAGE definition (see jerror.c for an example).
- */
-#ifndef JMESSAGE
-#ifndef JERROR_H
-/* First time through, define the enum list */
-#define JMAKE_ENUM_LIST
-#else
-/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */
-#define JMESSAGE(code,string)
-#endif /* JERROR_H */
-#endif /* JMESSAGE */
-
-#ifdef JMAKE_ENUM_LIST
-
-typedef enum {
-
-#define JMESSAGE(code,string) code ,
-
-#endif /* JMAKE_ENUM_LIST */
-
-JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */
-
-/* For maintenance convenience, list is alphabetical by message code name */
-JMESSAGE(JERR_ARITH_NOTIMPL,
- "Sorry, there are legal restrictions on arithmetic coding")
-JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix")
-JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix")
-JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode")
-JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
-JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range")
-JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported")
-JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition")
-JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace")
-JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace")
-JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length")
-JMESSAGE(JERR_BAD_LIB_VERSION,
- "Wrong JPEG library version: library is %d, caller expects %d")
-JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan")
-JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d")
-JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d")
-JMESSAGE(JERR_BAD_PROGRESSION,
- "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d")
-JMESSAGE(JERR_BAD_PROG_SCRIPT,
- "Invalid progressive parameters at scan script entry %d")
-JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors")
-JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d")
-JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d")
-JMESSAGE(JERR_BAD_STRUCT_SIZE,
- "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u")
-JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access")
-JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small")
-JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here")
-JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet")
-JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d")
-JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request")
-JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d")
-JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x")
-JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d")
-JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d")
-JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)")
-JMESSAGE(JERR_EMS_READ, "Read from EMS failed")
-JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed")
-JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan")
-JMESSAGE(JERR_FILE_READ, "Input file read error")
-JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?")
-JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet")
-JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow")
-JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry")
-JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels")
-JMESSAGE(JERR_INPUT_EMPTY, "Empty input file")
-JMESSAGE(JERR_INPUT_EOF, "Premature end of input file")
-JMESSAGE(JERR_MISMATCHED_QUANT_TABLE,
- "Cannot transcode due to multiple use of quantization table %d")
-JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data")
-JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change")
-JMESSAGE(JERR_NOTIMPL, "Not implemented yet")
-JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time")
-JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported")
-JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined")
-JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image")
-JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined")
-JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x")
-JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)")
-JMESSAGE(JERR_QUANT_COMPONENTS,
- "Cannot quantize more than %d color components")
-JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors")
-JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors")
-JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers")
-JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker")
-JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x")
-JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers")
-JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF")
-JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s")
-JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file")
-JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file")
-JMESSAGE(JERR_TFILE_WRITE,
- "Write failed on temporary file --- out of disk space?")
-JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines")
-JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x")
-JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up")
-JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation")
-JMESSAGE(JERR_XMS_READ, "Read from XMS failed")
-JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed")
-JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT)
-JMESSAGE(JMSG_VERSION, JVERSION)
-JMESSAGE(JTRC_16BIT_TABLES,
- "Caution: quantization tables are too coarse for baseline JPEG")
-JMESSAGE(JTRC_ADOBE,
- "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d")
-JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u")
-JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u")
-JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x")
-JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x")
-JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d")
-JMESSAGE(JTRC_DRI, "Define Restart Interval %u")
-JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u")
-JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u")
-JMESSAGE(JTRC_EOI, "End Of Image")
-JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d")
-JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d")
-JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE,
- "Warning: thumbnail image size does not match data length %u")
-JMESSAGE(JTRC_JFIF_EXTENSION,
- "JFIF extension marker: type 0x%02x, length %u")
-JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image")
-JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u")
-JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x")
-JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u")
-JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors")
-JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors")
-JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization")
-JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d")
-JMESSAGE(JTRC_RST, "RST%d")
-JMESSAGE(JTRC_SMOOTH_NOTIMPL,
- "Smoothing not supported with nonstandard sampling ratios")
-JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d")
-JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d")
-JMESSAGE(JTRC_SOI, "Start of Image")
-JMESSAGE(JTRC_SOS, "Start Of Scan: %d components")
-JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d")
-JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d")
-JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s")
-JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s")
-JMESSAGE(JTRC_THUMB_JPEG,
- "JFIF extension marker: JPEG-compressed thumbnail image, length %u")
-JMESSAGE(JTRC_THUMB_PALETTE,
- "JFIF extension marker: palette thumbnail image, length %u")
-JMESSAGE(JTRC_THUMB_RGB,
- "JFIF extension marker: RGB thumbnail image, length %u")
-JMESSAGE(JTRC_UNKNOWN_IDS,
- "Unrecognized component IDs %d %d %d, assuming YCbCr")
-JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u")
-JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u")
-JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d")
-JMESSAGE(JWRN_BOGUS_PROGRESSION,
- "Inconsistent progression sequence for component %d coefficient %d")
-JMESSAGE(JWRN_EXTRANEOUS_DATA,
- "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x")
-JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment")
-JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code")
-JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d")
-JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file")
-JMESSAGE(JWRN_MUST_RESYNC,
- "Corrupt JPEG data: found marker 0x%02x instead of RST%d")
-JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG")
-JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines")
-
-#ifdef JMAKE_ENUM_LIST
-
- JMSG_LASTMSGCODE
-} J_MESSAGE_CODE;
-
-#undef JMAKE_ENUM_LIST
-#endif /* JMAKE_ENUM_LIST */
-
-/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */
-#undef JMESSAGE
-
-
-#ifndef JERROR_H
-#define JERROR_H
-
-/* Macros to simplify using the error and trace message stuff */
-/* The first parameter is either type of cinfo pointer */
-
-/* Fatal errors (print message and exit) */
-#define ERREXIT(cinfo,code) \
- ((cinfo)->err->msg_code = (code), \
- (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
-#define ERREXIT1(cinfo,code,p1) \
- ((cinfo)->err->msg_code = (code), \
- (cinfo)->err->msg_parm.i[0] = (p1), \
- (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
-#define ERREXIT2(cinfo,code,p1,p2) \
- ((cinfo)->err->msg_code = (code), \
- (cinfo)->err->msg_parm.i[0] = (p1), \
- (cinfo)->err->msg_parm.i[1] = (p2), \
- (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
-#define ERREXIT3(cinfo,code,p1,p2,p3) \
- ((cinfo)->err->msg_code = (code), \
- (cinfo)->err->msg_parm.i[0] = (p1), \
- (cinfo)->err->msg_parm.i[1] = (p2), \
- (cinfo)->err->msg_parm.i[2] = (p3), \
- (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
-#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \
- ((cinfo)->err->msg_code = (code), \
- (cinfo)->err->msg_parm.i[0] = (p1), \
- (cinfo)->err->msg_parm.i[1] = (p2), \
- (cinfo)->err->msg_parm.i[2] = (p3), \
- (cinfo)->err->msg_parm.i[3] = (p4), \
- (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
-#define ERREXITS(cinfo,code,str) \
- ((cinfo)->err->msg_code = (code), \
- strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
- (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
-
-#define MAKESTMT(stuff) do { stuff } while (0)
-
-/* Nonfatal errors (we can keep going, but the data is probably corrupt) */
-#define WARNMS(cinfo,code) \
- ((cinfo)->err->msg_code = (code), \
- (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
-#define WARNMS1(cinfo,code,p1) \
- ((cinfo)->err->msg_code = (code), \
- (cinfo)->err->msg_parm.i[0] = (p1), \
- (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
-#define WARNMS2(cinfo,code,p1,p2) \
- ((cinfo)->err->msg_code = (code), \
- (cinfo)->err->msg_parm.i[0] = (p1), \
- (cinfo)->err->msg_parm.i[1] = (p2), \
- (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
-
-/* Informational/debugging messages */
-#define TRACEMS(cinfo,lvl,code) \
- ((cinfo)->err->msg_code = (code), \
- (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
-#define TRACEMS1(cinfo,lvl,code,p1) \
- ((cinfo)->err->msg_code = (code), \
- (cinfo)->err->msg_parm.i[0] = (p1), \
- (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
-#define TRACEMS2(cinfo,lvl,code,p1,p2) \
- ((cinfo)->err->msg_code = (code), \
- (cinfo)->err->msg_parm.i[0] = (p1), \
- (cinfo)->err->msg_parm.i[1] = (p2), \
- (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
-#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \
- MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
- _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \
- (cinfo)->err->msg_code = (code); \
- (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
-#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \
- MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
- _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
- (cinfo)->err->msg_code = (code); \
- (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
-#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \
- MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
- _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
- _mp[4] = (p5); \
- (cinfo)->err->msg_code = (code); \
- (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
-#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \
- MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
- _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
- _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \
- (cinfo)->err->msg_code = (code); \
- (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
-#define TRACEMSS(cinfo,lvl,code,str) \
- ((cinfo)->err->msg_code = (code), \
- strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
- (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
-
-#endif /* JERROR_H */
diff --git a/engine/code/jpeg-6b/jfdctflt.c b/engine/code/jpeg-6b/jfdctflt.c
deleted file mode 100644
index 79d7a00..0000000
--- a/engine/code/jpeg-6b/jfdctflt.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * jfdctflt.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains a floating-point implementation of the
- * forward DCT (Discrete Cosine Transform).
- *
- * This implementation should be more accurate than either of the integer
- * DCT implementations. However, it may not give the same results on all
- * machines because of differences in roundoff behavior. Speed will depend
- * on the hardware's floating point capacity.
- *
- * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
- * on each column. Direct algorithms are also available, but they are
- * much more complex and seem not to be any faster when reduced to code.
- *
- * This implementation is based on Arai, Agui, and Nakajima's algorithm for
- * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
- * Japanese, but the algorithm is described in the Pennebaker & Mitchell
- * JPEG textbook (see REFERENCES section in file README). The following code
- * is based directly on figure 4-8 in P&M.
- * While an 8-point DCT cannot be done in less than 11 multiplies, it is
- * possible to arrange the computation so that many of the multiplies are
- * simple scalings of the final outputs. These multiplies can then be
- * folded into the multiplications or divisions by the JPEG quantization
- * table entries. The AA&N method leaves only 5 multiplies and 29 adds
- * to be done in the DCT itself.
- * The primary disadvantage of this method is that with a fixed-point
- * implementation, accuracy is lost due to imprecise representation of the
- * scaled quantization values. However, that problem does not arise if
- * we use floating point arithmetic.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jdct.h" /* Private declarations for DCT subsystem */
-
-#ifdef DCT_FLOAT_SUPPORTED
-
-
-/*
- * This module is specialized to the case DCTSIZE = 8.
- */
-
-#if DCTSIZE != 8
- Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
-#endif
-
-
-/*
- * Perform the forward DCT on one block of samples.
- */
-
-GLOBAL(void)
-jpeg_fdct_float (FAST_FLOAT * data)
-{
- FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
- FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
- FAST_FLOAT z1, z2, z3, z4, z5, z11, z13;
- FAST_FLOAT *dataptr;
- int ctr;
-
- /* Pass 1: process rows. */
-
- dataptr = data;
- for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
- tmp0 = dataptr[0] + dataptr[7];
- tmp7 = dataptr[0] - dataptr[7];
- tmp1 = dataptr[1] + dataptr[6];
- tmp6 = dataptr[1] - dataptr[6];
- tmp2 = dataptr[2] + dataptr[5];
- tmp5 = dataptr[2] - dataptr[5];
- tmp3 = dataptr[3] + dataptr[4];
- tmp4 = dataptr[3] - dataptr[4];
-
- /* Even part */
-
- tmp10 = tmp0 + tmp3; /* phase 2 */
- tmp13 = tmp0 - tmp3;
- tmp11 = tmp1 + tmp2;
- tmp12 = tmp1 - tmp2;
-
- dataptr[0] = tmp10 + tmp11; /* phase 3 */
- dataptr[4] = tmp10 - tmp11;
-
- z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */
- dataptr[2] = tmp13 + z1; /* phase 5 */
- dataptr[6] = tmp13 - z1;
-
- /* Odd part */
-
- tmp10 = tmp4 + tmp5; /* phase 2 */
- tmp11 = tmp5 + tmp6;
- tmp12 = tmp6 + tmp7;
-
- /* The rotator is modified from fig 4-8 to avoid extra negations. */
- z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */
- z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */
- z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */
- z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */
-
- z11 = tmp7 + z3; /* phase 5 */
- z13 = tmp7 - z3;
-
- dataptr[5] = z13 + z2; /* phase 6 */
- dataptr[3] = z13 - z2;
- dataptr[1] = z11 + z4;
- dataptr[7] = z11 - z4;
-
- dataptr += DCTSIZE; /* advance pointer to next row */
- }
-
- /* Pass 2: process columns. */
-
- dataptr = data;
- for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
- tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
- tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
- tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
- tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
- tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
- tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
- tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
- tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
-
- /* Even part */
-
- tmp10 = tmp0 + tmp3; /* phase 2 */
- tmp13 = tmp0 - tmp3;
- tmp11 = tmp1 + tmp2;
- tmp12 = tmp1 - tmp2;
-
- dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */
- dataptr[DCTSIZE*4] = tmp10 - tmp11;
-
- z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */
- dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */
- dataptr[DCTSIZE*6] = tmp13 - z1;
-
- /* Odd part */
-
- tmp10 = tmp4 + tmp5; /* phase 2 */
- tmp11 = tmp5 + tmp6;
- tmp12 = tmp6 + tmp7;
-
- /* The rotator is modified from fig 4-8 to avoid extra negations. */
- z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */
- z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */
- z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */
- z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */
-
- z11 = tmp7 + z3; /* phase 5 */
- z13 = tmp7 - z3;
-
- dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */
- dataptr[DCTSIZE*3] = z13 - z2;
- dataptr[DCTSIZE*1] = z11 + z4;
- dataptr[DCTSIZE*7] = z11 - z4;
-
- dataptr++; /* advance pointer to next column */
- }
-}
-
-#endif /* DCT_FLOAT_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jfdctfst.c b/engine/code/jpeg-6b/jfdctfst.c
deleted file mode 100644
index ccb378a..0000000
--- a/engine/code/jpeg-6b/jfdctfst.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * jfdctfst.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains a fast, not so accurate integer implementation of the
- * forward DCT (Discrete Cosine Transform).
- *
- * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
- * on each column. Direct algorithms are also available, but they are
- * much more complex and seem not to be any faster when reduced to code.
- *
- * This implementation is based on Arai, Agui, and Nakajima's algorithm for
- * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
- * Japanese, but the algorithm is described in the Pennebaker & Mitchell
- * JPEG textbook (see REFERENCES section in file README). The following code
- * is based directly on figure 4-8 in P&M.
- * While an 8-point DCT cannot be done in less than 11 multiplies, it is
- * possible to arrange the computation so that many of the multiplies are
- * simple scalings of the final outputs. These multiplies can then be
- * folded into the multiplications or divisions by the JPEG quantization
- * table entries. The AA&N method leaves only 5 multiplies and 29 adds
- * to be done in the DCT itself.
- * The primary disadvantage of this method is that with fixed-point math,
- * accuracy is lost due to imprecise representation of the scaled
- * quantization values. The smaller the quantization table entry, the less
- * precise the scaled value, so this implementation does worse with high-
- * quality-setting files than with low-quality ones.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jdct.h" /* Private declarations for DCT subsystem */
-
-#ifdef DCT_IFAST_SUPPORTED
-
-
-/*
- * This module is specialized to the case DCTSIZE = 8.
- */
-
-#if DCTSIZE != 8
- Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
-#endif
-
-
-/* Scaling decisions are generally the same as in the LL&M algorithm;
- * see jfdctint.c for more details. However, we choose to descale
- * (right shift) multiplication products as soon as they are formed,
- * rather than carrying additional fractional bits into subsequent additions.
- * This compromises accuracy slightly, but it lets us save a few shifts.
- * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)
- * everywhere except in the multiplications proper; this saves a good deal
- * of work on 16-bit-int machines.
- *
- * Again to save a few shifts, the intermediate results between pass 1 and
- * pass 2 are not upscaled, but are represented only to integral precision.
- *
- * A final compromise is to represent the multiplicative constants to only
- * 8 fractional bits, rather than 13. This saves some shifting work on some
- * machines, and may also reduce the cost of multiplication (since there
- * are fewer one-bits in the constants).
- */
-
-#define CONST_BITS 8
-
-
-/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
- * causing a lot of useless floating-point operations at run time.
- * To get around this we use the following pre-calculated constants.
- * If you change CONST_BITS you may want to add appropriate values.
- * (With a reasonable C compiler, you can just rely on the FIX() macro...)
- */
-
-#if CONST_BITS == 8
-#define FIX_0_382683433 ((INT32) 98) /* FIX(0.382683433) */
-#define FIX_0_541196100 ((INT32) 139) /* FIX(0.541196100) */
-#define FIX_0_707106781 ((INT32) 181) /* FIX(0.707106781) */
-#define FIX_1_306562965 ((INT32) 334) /* FIX(1.306562965) */
-#else
-#define FIX_0_382683433 FIX(0.382683433)
-#define FIX_0_541196100 FIX(0.541196100)
-#define FIX_0_707106781 FIX(0.707106781)
-#define FIX_1_306562965 FIX(1.306562965)
-#endif
-
-
-/* We can gain a little more speed, with a further compromise in accuracy,
- * by omitting the addition in a descaling shift. This yields an incorrectly
- * rounded result half the time...
- */
-
-#ifndef USE_ACCURATE_ROUNDING
-#undef DESCALE
-#define DESCALE(x,n) RIGHT_SHIFT(x, n)
-#endif
-
-
-/* Multiply a DCTELEM variable by an INT32 constant, and immediately
- * descale to yield a DCTELEM result.
- */
-
-#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS))
-
-
-/*
- * Perform the forward DCT on one block of samples.
- */
-
-GLOBAL(void)
-jpeg_fdct_ifast (DCTELEM * data)
-{
- DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
- DCTELEM tmp10, tmp11, tmp12, tmp13;
- DCTELEM z1, z2, z3, z4, z5, z11, z13;
- DCTELEM *dataptr;
- int ctr;
- SHIFT_TEMPS
-
- /* Pass 1: process rows. */
-
- dataptr = data;
- for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
- tmp0 = dataptr[0] + dataptr[7];
- tmp7 = dataptr[0] - dataptr[7];
- tmp1 = dataptr[1] + dataptr[6];
- tmp6 = dataptr[1] - dataptr[6];
- tmp2 = dataptr[2] + dataptr[5];
- tmp5 = dataptr[2] - dataptr[5];
- tmp3 = dataptr[3] + dataptr[4];
- tmp4 = dataptr[3] - dataptr[4];
-
- /* Even part */
-
- tmp10 = tmp0 + tmp3; /* phase 2 */
- tmp13 = tmp0 - tmp3;
- tmp11 = tmp1 + tmp2;
- tmp12 = tmp1 - tmp2;
-
- dataptr[0] = tmp10 + tmp11; /* phase 3 */
- dataptr[4] = tmp10 - tmp11;
-
- z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
- dataptr[2] = tmp13 + z1; /* phase 5 */
- dataptr[6] = tmp13 - z1;
-
- /* Odd part */
-
- tmp10 = tmp4 + tmp5; /* phase 2 */
- tmp11 = tmp5 + tmp6;
- tmp12 = tmp6 + tmp7;
-
- /* The rotator is modified from fig 4-8 to avoid extra negations. */
- z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
- z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
- z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
- z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
-
- z11 = tmp7 + z3; /* phase 5 */
- z13 = tmp7 - z3;
-
- dataptr[5] = z13 + z2; /* phase 6 */
- dataptr[3] = z13 - z2;
- dataptr[1] = z11 + z4;
- dataptr[7] = z11 - z4;
-
- dataptr += DCTSIZE; /* advance pointer to next row */
- }
-
- /* Pass 2: process columns. */
-
- dataptr = data;
- for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
- tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
- tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
- tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
- tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
- tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
- tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
- tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
- tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
-
- /* Even part */
-
- tmp10 = tmp0 + tmp3; /* phase 2 */
- tmp13 = tmp0 - tmp3;
- tmp11 = tmp1 + tmp2;
- tmp12 = tmp1 - tmp2;
-
- dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */
- dataptr[DCTSIZE*4] = tmp10 - tmp11;
-
- z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
- dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */
- dataptr[DCTSIZE*6] = tmp13 - z1;
-
- /* Odd part */
-
- tmp10 = tmp4 + tmp5; /* phase 2 */
- tmp11 = tmp5 + tmp6;
- tmp12 = tmp6 + tmp7;
-
- /* The rotator is modified from fig 4-8 to avoid extra negations. */
- z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
- z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
- z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
- z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
-
- z11 = tmp7 + z3; /* phase 5 */
- z13 = tmp7 - z3;
-
- dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */
- dataptr[DCTSIZE*3] = z13 - z2;
- dataptr[DCTSIZE*1] = z11 + z4;
- dataptr[DCTSIZE*7] = z11 - z4;
-
- dataptr++; /* advance pointer to next column */
- }
-}
-
-#endif /* DCT_IFAST_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jfdctint.c b/engine/code/jpeg-6b/jfdctint.c
deleted file mode 100644
index 0a78b64..0000000
--- a/engine/code/jpeg-6b/jfdctint.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * jfdctint.c
- *
- * Copyright (C) 1991-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains a slow-but-accurate integer implementation of the
- * forward DCT (Discrete Cosine Transform).
- *
- * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
- * on each column. Direct algorithms are also available, but they are
- * much more complex and seem not to be any faster when reduced to code.
- *
- * This implementation is based on an algorithm described in
- * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
- * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
- * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
- * The primary algorithm described there uses 11 multiplies and 29 adds.
- * We use their alternate method with 12 multiplies and 32 adds.
- * The advantage of this method is that no data path contains more than one
- * multiplication; this allows a very simple and accurate implementation in
- * scaled fixed-point arithmetic, with a minimal number of shifts.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jdct.h" /* Private declarations for DCT subsystem */
-
-#ifdef DCT_ISLOW_SUPPORTED
-
-
-/*
- * This module is specialized to the case DCTSIZE = 8.
- */
-
-#if DCTSIZE != 8
- Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
-#endif
-
-
-/*
- * The poop on this scaling stuff is as follows:
- *
- * Each 1-D DCT step produces outputs which are a factor of sqrt(N)
- * larger than the true DCT outputs. The final outputs are therefore
- * a factor of N larger than desired; since N=8 this can be cured by
- * a simple right shift at the end of the algorithm. The advantage of
- * this arrangement is that we save two multiplications per 1-D DCT,
- * because the y0 and y4 outputs need not be divided by sqrt(N).
- * In the IJG code, this factor of 8 is removed by the quantization step
- * (in jcdctmgr.c), NOT in this module.
- *
- * We have to do addition and subtraction of the integer inputs, which
- * is no problem, and multiplication by fractional constants, which is
- * a problem to do in integer arithmetic. We multiply all the constants
- * by CONST_SCALE and convert them to integer constants (thus retaining
- * CONST_BITS bits of precision in the constants). After doing a
- * multiplication we have to divide the product by CONST_SCALE, with proper
- * rounding, to produce the correct output. This division can be done
- * cheaply as a right shift of CONST_BITS bits. We postpone shifting
- * as long as possible so that partial sums can be added together with
- * full fractional precision.
- *
- * The outputs of the first pass are scaled up by PASS1_BITS bits so that
- * they are represented to better-than-integral precision. These outputs
- * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
- * with the recommended scaling. (For 12-bit sample data, the intermediate
- * array is INT32 anyway.)
- *
- * To avoid overflow of the 32-bit intermediate results in pass 2, we must
- * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis
- * shows that the values given below are the most effective.
- */
-
-#if BITS_IN_JSAMPLE == 8
-#define CONST_BITS 13
-#define PASS1_BITS 2
-#else
-#define CONST_BITS 13
-#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
-#endif
-
-/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
- * causing a lot of useless floating-point operations at run time.
- * To get around this we use the following pre-calculated constants.
- * If you change CONST_BITS you may want to add appropriate values.
- * (With a reasonable C compiler, you can just rely on the FIX() macro...)
- */
-
-#if CONST_BITS == 13
-#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */
-#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */
-#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */
-#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */
-#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */
-#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */
-#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */
-#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */
-#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */
-#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */
-#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */
-#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */
-#else
-#define FIX_0_298631336 FIX(0.298631336)
-#define FIX_0_390180644 FIX(0.390180644)
-#define FIX_0_541196100 FIX(0.541196100)
-#define FIX_0_765366865 FIX(0.765366865)
-#define FIX_0_899976223 FIX(0.899976223)
-#define FIX_1_175875602 FIX(1.175875602)
-#define FIX_1_501321110 FIX(1.501321110)
-#define FIX_1_847759065 FIX(1.847759065)
-#define FIX_1_961570560 FIX(1.961570560)
-#define FIX_2_053119869 FIX(2.053119869)
-#define FIX_2_562915447 FIX(2.562915447)
-#define FIX_3_072711026 FIX(3.072711026)
-#endif
-
-
-/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
- * For 8-bit samples with the recommended scaling, all the variable
- * and constant values involved are no more than 16 bits wide, so a
- * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
- * For 12-bit samples, a full 32-bit multiplication will be needed.
- */
-
-#if BITS_IN_JSAMPLE == 8
-#define MULTIPLY(var,const) MULTIPLY16C16(var,const)
-#else
-#define MULTIPLY(var,const) ((var) * (const))
-#endif
-
-
-/*
- * Perform the forward DCT on one block of samples.
- */
-
-GLOBAL(void)
-jpeg_fdct_islow (DCTELEM * data)
-{
- INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
- INT32 tmp10, tmp11, tmp12, tmp13;
- INT32 z1, z2, z3, z4, z5;
- DCTELEM *dataptr;
- int ctr;
- SHIFT_TEMPS
-
- /* Pass 1: process rows. */
- /* Note results are scaled up by sqrt(8) compared to a true DCT; */
- /* furthermore, we scale the results by 2**PASS1_BITS. */
-
- dataptr = data;
- for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
- tmp0 = dataptr[0] + dataptr[7];
- tmp7 = dataptr[0] - dataptr[7];
- tmp1 = dataptr[1] + dataptr[6];
- tmp6 = dataptr[1] - dataptr[6];
- tmp2 = dataptr[2] + dataptr[5];
- tmp5 = dataptr[2] - dataptr[5];
- tmp3 = dataptr[3] + dataptr[4];
- tmp4 = dataptr[3] - dataptr[4];
-
- /* Even part per LL&M figure 1 --- note that published figure is faulty;
- * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
- */
-
- tmp10 = tmp0 + tmp3;
- tmp13 = tmp0 - tmp3;
- tmp11 = tmp1 + tmp2;
- tmp12 = tmp1 - tmp2;
-
- dataptr[0] = (DCTELEM) ((tmp10 + tmp11) << PASS1_BITS);
- dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS);
-
- z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
- dataptr[2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865),
- CONST_BITS-PASS1_BITS);
- dataptr[6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065),
- CONST_BITS-PASS1_BITS);
-
- /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
- * cK represents cos(K*pi/16).
- * i0..i3 in the paper are tmp4..tmp7 here.
- */
-
- z1 = tmp4 + tmp7;
- z2 = tmp5 + tmp6;
- z3 = tmp4 + tmp6;
- z4 = tmp5 + tmp7;
- z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */
-
- tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
- tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
- tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
- tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
- z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
- z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
- z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
- z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
-
- z3 += z5;
- z4 += z5;
-
- dataptr[7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, CONST_BITS-PASS1_BITS);
- dataptr[5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, CONST_BITS-PASS1_BITS);
- dataptr[3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, CONST_BITS-PASS1_BITS);
- dataptr[1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, CONST_BITS-PASS1_BITS);
-
- dataptr += DCTSIZE; /* advance pointer to next row */
- }
-
- /* Pass 2: process columns.
- * We remove the PASS1_BITS scaling, but leave the results scaled up
- * by an overall factor of 8.
- */
-
- dataptr = data;
- for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
- tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
- tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
- tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
- tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
- tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
- tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
- tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
- tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
-
- /* Even part per LL&M figure 1 --- note that published figure is faulty;
- * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
- */
-
- tmp10 = tmp0 + tmp3;
- tmp13 = tmp0 - tmp3;
- tmp11 = tmp1 + tmp2;
- tmp12 = tmp1 - tmp2;
-
- dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS);
- dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS);
-
- z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
- dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865),
- CONST_BITS+PASS1_BITS);
- dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065),
- CONST_BITS+PASS1_BITS);
-
- /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
- * cK represents cos(K*pi/16).
- * i0..i3 in the paper are tmp4..tmp7 here.
- */
-
- z1 = tmp4 + tmp7;
- z2 = tmp5 + tmp6;
- z3 = tmp4 + tmp6;
- z4 = tmp5 + tmp7;
- z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */
-
- tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
- tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
- tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
- tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
- z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
- z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
- z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
- z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
-
- z3 += z5;
- z4 += z5;
-
- dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp4 + z1 + z3,
- CONST_BITS+PASS1_BITS);
- dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp5 + z2 + z4,
- CONST_BITS+PASS1_BITS);
- dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp6 + z2 + z3,
- CONST_BITS+PASS1_BITS);
- dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp7 + z1 + z4,
- CONST_BITS+PASS1_BITS);
-
- dataptr++; /* advance pointer to next column */
- }
-}
-
-#endif /* DCT_ISLOW_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jidctflt.c b/engine/code/jpeg-6b/jidctflt.c
deleted file mode 100644
index 0188ce3..0000000
--- a/engine/code/jpeg-6b/jidctflt.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * jidctflt.c
- *
- * Copyright (C) 1994-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains a floating-point implementation of the
- * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
- * must also perform dequantization of the input coefficients.
- *
- * This implementation should be more accurate than either of the integer
- * IDCT implementations. However, it may not give the same results on all
- * machines because of differences in roundoff behavior. Speed will depend
- * on the hardware's floating point capacity.
- *
- * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
- * on each row (or vice versa, but it's more convenient to emit a row at
- * a time). Direct algorithms are also available, but they are much more
- * complex and seem not to be any faster when reduced to code.
- *
- * This implementation is based on Arai, Agui, and Nakajima's algorithm for
- * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
- * Japanese, but the algorithm is described in the Pennebaker & Mitchell
- * JPEG textbook (see REFERENCES section in file README). The following code
- * is based directly on figure 4-8 in P&M.
- * While an 8-point DCT cannot be done in less than 11 multiplies, it is
- * possible to arrange the computation so that many of the multiplies are
- * simple scalings of the final outputs. These multiplies can then be
- * folded into the multiplications or divisions by the JPEG quantization
- * table entries. The AA&N method leaves only 5 multiplies and 29 adds
- * to be done in the DCT itself.
- * The primary disadvantage of this method is that with a fixed-point
- * implementation, accuracy is lost due to imprecise representation of the
- * scaled quantization values. However, that problem does not arise if
- * we use floating point arithmetic.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jdct.h" /* Private declarations for DCT subsystem */
-
-#ifdef DCT_FLOAT_SUPPORTED
-
-
-/*
- * This module is specialized to the case DCTSIZE = 8.
- */
-
-#if DCTSIZE != 8
- Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
-#endif
-
-
-/* Dequantize a coefficient by multiplying it by the multiplier-table
- * entry; produce a float result.
- */
-
-#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval))
-
-
-/*
- * Perform dequantization and inverse DCT on one block of coefficients.
- */
-
-GLOBAL(void)
-jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col)
-{
- FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
- FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
- FAST_FLOAT z5, z10, z11, z12, z13;
- JCOEFPTR inptr;
- FLOAT_MULT_TYPE * quantptr;
- FAST_FLOAT * wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
- int ctr;
- FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */
- SHIFT_TEMPS
-
- /* Pass 1: process columns from input, store into work array. */
-
- inptr = coef_block;
- quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table;
- wsptr = workspace;
- for (ctr = DCTSIZE; ctr > 0; ctr--) {
- /* Due to quantization, we will usually find that many of the input
- * coefficients are zero, especially the AC terms. We can exploit this
- * by short-circuiting the IDCT calculation for any column in which all
- * the AC terms are zero. In that case each output is equal to the
- * DC coefficient (with scale factor as needed).
- * With typical images and quantization tables, half or more of the
- * column DCT calculations can be simplified this way.
- */
-
- if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
- inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
- inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
- inptr[DCTSIZE*7] == 0) {
- /* AC terms all zero */
- FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
-
- wsptr[DCTSIZE*0] = dcval;
- wsptr[DCTSIZE*1] = dcval;
- wsptr[DCTSIZE*2] = dcval;
- wsptr[DCTSIZE*3] = dcval;
- wsptr[DCTSIZE*4] = dcval;
- wsptr[DCTSIZE*5] = dcval;
- wsptr[DCTSIZE*6] = dcval;
- wsptr[DCTSIZE*7] = dcval;
-
- inptr++; /* advance pointers to next column */
- quantptr++;
- wsptr++;
- continue;
- }
-
- /* Even part */
-
- tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
- tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
- tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
- tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
-
- tmp10 = tmp0 + tmp2; /* phase 3 */
- tmp11 = tmp0 - tmp2;
-
- tmp13 = tmp1 + tmp3; /* phases 5-3 */
- tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */
-
- tmp0 = tmp10 + tmp13; /* phase 2 */
- tmp3 = tmp10 - tmp13;
- tmp1 = tmp11 + tmp12;
- tmp2 = tmp11 - tmp12;
-
- /* Odd part */
-
- tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
- tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
- tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
- tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
-
- z13 = tmp6 + tmp5; /* phase 6 */
- z10 = tmp6 - tmp5;
- z11 = tmp4 + tmp7;
- z12 = tmp4 - tmp7;
-
- tmp7 = z11 + z13; /* phase 5 */
- tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */
-
- z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
- tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
- tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
-
- tmp6 = tmp12 - tmp7; /* phase 2 */
- tmp5 = tmp11 - tmp6;
- tmp4 = tmp10 + tmp5;
-
- wsptr[DCTSIZE*0] = tmp0 + tmp7;
- wsptr[DCTSIZE*7] = tmp0 - tmp7;
- wsptr[DCTSIZE*1] = tmp1 + tmp6;
- wsptr[DCTSIZE*6] = tmp1 - tmp6;
- wsptr[DCTSIZE*2] = tmp2 + tmp5;
- wsptr[DCTSIZE*5] = tmp2 - tmp5;
- wsptr[DCTSIZE*4] = tmp3 + tmp4;
- wsptr[DCTSIZE*3] = tmp3 - tmp4;
-
- inptr++; /* advance pointers to next column */
- quantptr++;
- wsptr++;
- }
-
- /* Pass 2: process rows from work array, store into output array. */
- /* Note that we must descale the results by a factor of 8 == 2**3. */
-
- wsptr = workspace;
- for (ctr = 0; ctr < DCTSIZE; ctr++) {
- outptr = output_buf[ctr] + output_col;
- /* Rows of zeroes can be exploited in the same way as we did with columns.
- * However, the column calculation has created many nonzero AC terms, so
- * the simplification applies less often (typically 5% to 10% of the time).
- * And testing floats for zero is relatively expensive, so we don't bother.
- */
-
- /* Even part */
-
- tmp10 = wsptr[0] + wsptr[4];
- tmp11 = wsptr[0] - wsptr[4];
-
- tmp13 = wsptr[2] + wsptr[6];
- tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13;
-
- tmp0 = tmp10 + tmp13;
- tmp3 = tmp10 - tmp13;
- tmp1 = tmp11 + tmp12;
- tmp2 = tmp11 - tmp12;
-
- /* Odd part */
-
- z13 = wsptr[5] + wsptr[3];
- z10 = wsptr[5] - wsptr[3];
- z11 = wsptr[1] + wsptr[7];
- z12 = wsptr[1] - wsptr[7];
-
- tmp7 = z11 + z13;
- tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562);
-
- z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
- tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
- tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
-
- tmp6 = tmp12 - tmp7;
- tmp5 = tmp11 - tmp6;
- tmp4 = tmp10 + tmp5;
-
- /* Final output stage: scale down by a factor of 8 and range-limit */
-
- outptr[0] = range_limit[(int) DESCALE((INT32) (tmp0 + tmp7), 3)
- & RANGE_MASK];
- outptr[7] = range_limit[(int) DESCALE((INT32) (tmp0 - tmp7), 3)
- & RANGE_MASK];
- outptr[1] = range_limit[(int) DESCALE((INT32) (tmp1 + tmp6), 3)
- & RANGE_MASK];
- outptr[6] = range_limit[(int) DESCALE((INT32) (tmp1 - tmp6), 3)
- & RANGE_MASK];
- outptr[2] = range_limit[(int) DESCALE((INT32) (tmp2 + tmp5), 3)
- & RANGE_MASK];
- outptr[5] = range_limit[(int) DESCALE((INT32) (tmp2 - tmp5), 3)
- & RANGE_MASK];
- outptr[4] = range_limit[(int) DESCALE((INT32) (tmp3 + tmp4), 3)
- & RANGE_MASK];
- outptr[3] = range_limit[(int) DESCALE((INT32) (tmp3 - tmp4), 3)
- & RANGE_MASK];
-
- wsptr += DCTSIZE; /* advance pointer to next row */
- }
-}
-
-#endif /* DCT_FLOAT_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jidctfst.c b/engine/code/jpeg-6b/jidctfst.c
deleted file mode 100644
index dba4216..0000000
--- a/engine/code/jpeg-6b/jidctfst.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * jidctfst.c
- *
- * Copyright (C) 1994-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains a fast, not so accurate integer implementation of the
- * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
- * must also perform dequantization of the input coefficients.
- *
- * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
- * on each row (or vice versa, but it's more convenient to emit a row at
- * a time). Direct algorithms are also available, but they are much more
- * complex and seem not to be any faster when reduced to code.
- *
- * This implementation is based on Arai, Agui, and Nakajima's algorithm for
- * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
- * Japanese, but the algorithm is described in the Pennebaker & Mitchell
- * JPEG textbook (see REFERENCES section in file README). The following code
- * is based directly on figure 4-8 in P&M.
- * While an 8-point DCT cannot be done in less than 11 multiplies, it is
- * possible to arrange the computation so that many of the multiplies are
- * simple scalings of the final outputs. These multiplies can then be
- * folded into the multiplications or divisions by the JPEG quantization
- * table entries. The AA&N method leaves only 5 multiplies and 29 adds
- * to be done in the DCT itself.
- * The primary disadvantage of this method is that with fixed-point math,
- * accuracy is lost due to imprecise representation of the scaled
- * quantization values. The smaller the quantization table entry, the less
- * precise the scaled value, so this implementation does worse with high-
- * quality-setting files than with low-quality ones.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jdct.h" /* Private declarations for DCT subsystem */
-
-#ifdef DCT_IFAST_SUPPORTED
-
-
-/*
- * This module is specialized to the case DCTSIZE = 8.
- */
-
-#if DCTSIZE != 8
- Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
-#endif
-
-
-/* Scaling decisions are generally the same as in the LL&M algorithm;
- * see jidctint.c for more details. However, we choose to descale
- * (right shift) multiplication products as soon as they are formed,
- * rather than carrying additional fractional bits into subsequent additions.
- * This compromises accuracy slightly, but it lets us save a few shifts.
- * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)
- * everywhere except in the multiplications proper; this saves a good deal
- * of work on 16-bit-int machines.
- *
- * The dequantized coefficients are not integers because the AA&N scaling
- * factors have been incorporated. We represent them scaled up by PASS1_BITS,
- * so that the first and second IDCT rounds have the same input scaling.
- * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to
- * avoid a descaling shift; this compromises accuracy rather drastically
- * for small quantization table entries, but it saves a lot of shifts.
- * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway,
- * so we use a much larger scaling factor to preserve accuracy.
- *
- * A final compromise is to represent the multiplicative constants to only
- * 8 fractional bits, rather than 13. This saves some shifting work on some
- * machines, and may also reduce the cost of multiplication (since there
- * are fewer one-bits in the constants).
- */
-
-#if BITS_IN_JSAMPLE == 8
-#define CONST_BITS 8
-#define PASS1_BITS 2
-#else
-#define CONST_BITS 8
-#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
-#endif
-
-/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
- * causing a lot of useless floating-point operations at run time.
- * To get around this we use the following pre-calculated constants.
- * If you change CONST_BITS you may want to add appropriate values.
- * (With a reasonable C compiler, you can just rely on the FIX() macro...)
- */
-
-#if CONST_BITS == 8
-#define FIX_1_082392200 ((INT32) 277) /* FIX(1.082392200) */
-#define FIX_1_414213562 ((INT32) 362) /* FIX(1.414213562) */
-#define FIX_1_847759065 ((INT32) 473) /* FIX(1.847759065) */
-#define FIX_2_613125930 ((INT32) 669) /* FIX(2.613125930) */
-#else
-#define FIX_1_082392200 FIX(1.082392200)
-#define FIX_1_414213562 FIX(1.414213562)
-#define FIX_1_847759065 FIX(1.847759065)
-#define FIX_2_613125930 FIX(2.613125930)
-#endif
-
-
-/* We can gain a little more speed, with a further compromise in accuracy,
- * by omitting the addition in a descaling shift. This yields an incorrectly
- * rounded result half the time...
- */
-
-#ifndef USE_ACCURATE_ROUNDING
-#undef DESCALE
-#define DESCALE(x,n) RIGHT_SHIFT(x, n)
-#endif
-
-
-/* Multiply a DCTELEM variable by an INT32 constant, and immediately
- * descale to yield a DCTELEM result.
- */
-
-#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS))
-
-
-/* Dequantize a coefficient by multiplying it by the multiplier-table
- * entry; produce a DCTELEM result. For 8-bit data a 16x16->16
- * multiplication will do. For 12-bit data, the multiplier table is
- * declared INT32, so a 32-bit multiply will be used.
- */
-
-#if BITS_IN_JSAMPLE == 8
-#define DEQUANTIZE(coef,quantval) (((IFAST_MULT_TYPE) (coef)) * (quantval))
-#else
-#define DEQUANTIZE(coef,quantval) \
- DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS)
-#endif
-
-
-/* Like DESCALE, but applies to a DCTELEM and produces an int.
- * We assume that int right shift is unsigned if INT32 right shift is.
- */
-
-#ifdef RIGHT_SHIFT_IS_UNSIGNED
-#define ISHIFT_TEMPS DCTELEM ishift_temp;
-#if BITS_IN_JSAMPLE == 8
-#define DCTELEMBITS 16 /* DCTELEM may be 16 or 32 bits */
-#else
-#define DCTELEMBITS 32 /* DCTELEM must be 32 bits */
-#endif
-#define IRIGHT_SHIFT(x,shft) \
- ((ishift_temp = (x)) < 0 ? \
- (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \
- (ishift_temp >> (shft)))
-#else
-#define ISHIFT_TEMPS
-#define IRIGHT_SHIFT(x,shft) ((x) >> (shft))
-#endif
-
-#ifdef USE_ACCURATE_ROUNDING
-#define IDESCALE(x,n) ((int) IRIGHT_SHIFT((x) + (1 << ((n)-1)), n))
-#else
-#define IDESCALE(x,n) ((int) IRIGHT_SHIFT(x, n))
-#endif
-
-
-/*
- * Perform dequantization and inverse DCT on one block of coefficients.
- */
-
-GLOBAL(void)
-jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col)
-{
- DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
- DCTELEM tmp10, tmp11, tmp12, tmp13;
- DCTELEM z5, z10, z11, z12, z13;
- JCOEFPTR inptr;
- IFAST_MULT_TYPE * quantptr;
- int * wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
- int ctr;
- int workspace[DCTSIZE2]; /* buffers data between passes */
- SHIFT_TEMPS /* for DESCALE */
- ISHIFT_TEMPS /* for IDESCALE */
-
- /* Pass 1: process columns from input, store into work array. */
-
- inptr = coef_block;
- quantptr = (IFAST_MULT_TYPE *) compptr->dct_table;
- wsptr = workspace;
- for (ctr = DCTSIZE; ctr > 0; ctr--) {
- /* Due to quantization, we will usually find that many of the input
- * coefficients are zero, especially the AC terms. We can exploit this
- * by short-circuiting the IDCT calculation for any column in which all
- * the AC terms are zero. In that case each output is equal to the
- * DC coefficient (with scale factor as needed).
- * With typical images and quantization tables, half or more of the
- * column DCT calculations can be simplified this way.
- */
-
- if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
- inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
- inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
- inptr[DCTSIZE*7] == 0) {
- /* AC terms all zero */
- int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
-
- wsptr[DCTSIZE*0] = dcval;
- wsptr[DCTSIZE*1] = dcval;
- wsptr[DCTSIZE*2] = dcval;
- wsptr[DCTSIZE*3] = dcval;
- wsptr[DCTSIZE*4] = dcval;
- wsptr[DCTSIZE*5] = dcval;
- wsptr[DCTSIZE*6] = dcval;
- wsptr[DCTSIZE*7] = dcval;
-
- inptr++; /* advance pointers to next column */
- quantptr++;
- wsptr++;
- continue;
- }
-
- /* Even part */
-
- tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
- tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
- tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
- tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
-
- tmp10 = tmp0 + tmp2; /* phase 3 */
- tmp11 = tmp0 - tmp2;
-
- tmp13 = tmp1 + tmp3; /* phases 5-3 */
- tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */
-
- tmp0 = tmp10 + tmp13; /* phase 2 */
- tmp3 = tmp10 - tmp13;
- tmp1 = tmp11 + tmp12;
- tmp2 = tmp11 - tmp12;
-
- /* Odd part */
-
- tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
- tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
- tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
- tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
-
- z13 = tmp6 + tmp5; /* phase 6 */
- z10 = tmp6 - tmp5;
- z11 = tmp4 + tmp7;
- z12 = tmp4 - tmp7;
-
- tmp7 = z11 + z13; /* phase 5 */
- tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
-
- z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
- tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
- tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */
-
- tmp6 = tmp12 - tmp7; /* phase 2 */
- tmp5 = tmp11 - tmp6;
- tmp4 = tmp10 + tmp5;
-
- wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7);
- wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7);
- wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6);
- wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6);
- wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5);
- wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5);
- wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4);
- wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4);
-
- inptr++; /* advance pointers to next column */
- quantptr++;
- wsptr++;
- }
-
- /* Pass 2: process rows from work array, store into output array. */
- /* Note that we must descale the results by a factor of 8 == 2**3, */
- /* and also undo the PASS1_BITS scaling. */
-
- wsptr = workspace;
- for (ctr = 0; ctr < DCTSIZE; ctr++) {
- outptr = output_buf[ctr] + output_col;
- /* Rows of zeroes can be exploited in the same way as we did with columns.
- * However, the column calculation has created many nonzero AC terms, so
- * the simplification applies less often (typically 5% to 10% of the time).
- * On machines with very fast multiplication, it's possible that the
- * test takes more time than it's worth. In that case this section
- * may be commented out.
- */
-
-#ifndef NO_ZERO_ROW_TEST
- if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&
- wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
- /* AC terms all zero */
- JSAMPLE dcval = range_limit[IDESCALE(wsptr[0], PASS1_BITS+3)
- & RANGE_MASK];
-
- outptr[0] = dcval;
- outptr[1] = dcval;
- outptr[2] = dcval;
- outptr[3] = dcval;
- outptr[4] = dcval;
- outptr[5] = dcval;
- outptr[6] = dcval;
- outptr[7] = dcval;
-
- wsptr += DCTSIZE; /* advance pointer to next row */
- continue;
- }
-#endif
-
- /* Even part */
-
- tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]);
- tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]);
-
- tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]);
- tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562)
- - tmp13;
-
- tmp0 = tmp10 + tmp13;
- tmp3 = tmp10 - tmp13;
- tmp1 = tmp11 + tmp12;
- tmp2 = tmp11 - tmp12;
-
- /* Odd part */
-
- z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3];
- z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3];
- z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7];
- z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7];
-
- tmp7 = z11 + z13; /* phase 5 */
- tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
-
- z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
- tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
- tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */
-
- tmp6 = tmp12 - tmp7; /* phase 2 */
- tmp5 = tmp11 - tmp6;
- tmp4 = tmp10 + tmp5;
-
- /* Final output stage: scale down by a factor of 8 and range-limit */
-
- outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3)
- & RANGE_MASK];
- outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3)
- & RANGE_MASK];
- outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3)
- & RANGE_MASK];
- outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3)
- & RANGE_MASK];
- outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3)
- & RANGE_MASK];
- outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3)
- & RANGE_MASK];
- outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3)
- & RANGE_MASK];
- outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3)
- & RANGE_MASK];
-
- wsptr += DCTSIZE; /* advance pointer to next row */
- }
-}
-
-#endif /* DCT_IFAST_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jidctint.c b/engine/code/jpeg-6b/jidctint.c
deleted file mode 100644
index a72b320..0000000
--- a/engine/code/jpeg-6b/jidctint.c
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * jidctint.c
- *
- * Copyright (C) 1991-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains a slow-but-accurate integer implementation of the
- * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
- * must also perform dequantization of the input coefficients.
- *
- * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
- * on each row (or vice versa, but it's more convenient to emit a row at
- * a time). Direct algorithms are also available, but they are much more
- * complex and seem not to be any faster when reduced to code.
- *
- * This implementation is based on an algorithm described in
- * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
- * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
- * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
- * The primary algorithm described there uses 11 multiplies and 29 adds.
- * We use their alternate method with 12 multiplies and 32 adds.
- * The advantage of this method is that no data path contains more than one
- * multiplication; this allows a very simple and accurate implementation in
- * scaled fixed-point arithmetic, with a minimal number of shifts.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jdct.h" /* Private declarations for DCT subsystem */
-
-#ifdef DCT_ISLOW_SUPPORTED
-
-
-/*
- * This module is specialized to the case DCTSIZE = 8.
- */
-
-#if DCTSIZE != 8
- Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
-#endif
-
-
-/*
- * The poop on this scaling stuff is as follows:
- *
- * Each 1-D IDCT step produces outputs which are a factor of sqrt(N)
- * larger than the true IDCT outputs. The final outputs are therefore
- * a factor of N larger than desired; since N=8 this can be cured by
- * a simple right shift at the end of the algorithm. The advantage of
- * this arrangement is that we save two multiplications per 1-D IDCT,
- * because the y0 and y4 inputs need not be divided by sqrt(N).
- *
- * We have to do addition and subtraction of the integer inputs, which
- * is no problem, and multiplication by fractional constants, which is
- * a problem to do in integer arithmetic. We multiply all the constants
- * by CONST_SCALE and convert them to integer constants (thus retaining
- * CONST_BITS bits of precision in the constants). After doing a
- * multiplication we have to divide the product by CONST_SCALE, with proper
- * rounding, to produce the correct output. This division can be done
- * cheaply as a right shift of CONST_BITS bits. We postpone shifting
- * as long as possible so that partial sums can be added together with
- * full fractional precision.
- *
- * The outputs of the first pass are scaled up by PASS1_BITS bits so that
- * they are represented to better-than-integral precision. These outputs
- * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
- * with the recommended scaling. (To scale up 12-bit sample data further, an
- * intermediate INT32 array would be needed.)
- *
- * To avoid overflow of the 32-bit intermediate results in pass 2, we must
- * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis
- * shows that the values given below are the most effective.
- */
-
-#if BITS_IN_JSAMPLE == 8
-#define CONST_BITS 13
-#define PASS1_BITS 2
-#else
-#define CONST_BITS 13
-#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
-#endif
-
-/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
- * causing a lot of useless floating-point operations at run time.
- * To get around this we use the following pre-calculated constants.
- * If you change CONST_BITS you may want to add appropriate values.
- * (With a reasonable C compiler, you can just rely on the FIX() macro...)
- */
-
-#if CONST_BITS == 13
-#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */
-#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */
-#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */
-#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */
-#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */
-#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */
-#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */
-#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */
-#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */
-#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */
-#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */
-#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */
-#else
-#define FIX_0_298631336 FIX(0.298631336)
-#define FIX_0_390180644 FIX(0.390180644)
-#define FIX_0_541196100 FIX(0.541196100)
-#define FIX_0_765366865 FIX(0.765366865)
-#define FIX_0_899976223 FIX(0.899976223)
-#define FIX_1_175875602 FIX(1.175875602)
-#define FIX_1_501321110 FIX(1.501321110)
-#define FIX_1_847759065 FIX(1.847759065)
-#define FIX_1_961570560 FIX(1.961570560)
-#define FIX_2_053119869 FIX(2.053119869)
-#define FIX_2_562915447 FIX(2.562915447)
-#define FIX_3_072711026 FIX(3.072711026)
-#endif
-
-
-/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
- * For 8-bit samples with the recommended scaling, all the variable
- * and constant values involved are no more than 16 bits wide, so a
- * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
- * For 12-bit samples, a full 32-bit multiplication will be needed.
- */
-
-#if BITS_IN_JSAMPLE == 8
-#define MULTIPLY(var,const) MULTIPLY16C16(var,const)
-#else
-#define MULTIPLY(var,const) ((var) * (const))
-#endif
-
-
-/* Dequantize a coefficient by multiplying it by the multiplier-table
- * entry; produce an int result. In this module, both inputs and result
- * are 16 bits or less, so either int or short multiply will work.
- */
-
-#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval))
-
-
-/*
- * Perform dequantization and inverse DCT on one block of coefficients.
- */
-
-GLOBAL(void)
-jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col)
-{
- INT32 tmp0, tmp1, tmp2, tmp3;
- INT32 tmp10, tmp11, tmp12, tmp13;
- INT32 z1, z2, z3, z4, z5;
- JCOEFPTR inptr;
- ISLOW_MULT_TYPE * quantptr;
- int * wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
- int ctr;
- int workspace[DCTSIZE2]; /* buffers data between passes */
- SHIFT_TEMPS
-
- /* Pass 1: process columns from input, store into work array. */
- /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
- /* furthermore, we scale the results by 2**PASS1_BITS. */
-
- inptr = coef_block;
- quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
- wsptr = workspace;
- for (ctr = DCTSIZE; ctr > 0; ctr--) {
- /* Due to quantization, we will usually find that many of the input
- * coefficients are zero, especially the AC terms. We can exploit this
- * by short-circuiting the IDCT calculation for any column in which all
- * the AC terms are zero. In that case each output is equal to the
- * DC coefficient (with scale factor as needed).
- * With typical images and quantization tables, half or more of the
- * column DCT calculations can be simplified this way.
- */
-
- if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
- inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
- inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
- inptr[DCTSIZE*7] == 0) {
- /* AC terms all zero */
- int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
-
- wsptr[DCTSIZE*0] = dcval;
- wsptr[DCTSIZE*1] = dcval;
- wsptr[DCTSIZE*2] = dcval;
- wsptr[DCTSIZE*3] = dcval;
- wsptr[DCTSIZE*4] = dcval;
- wsptr[DCTSIZE*5] = dcval;
- wsptr[DCTSIZE*6] = dcval;
- wsptr[DCTSIZE*7] = dcval;
-
- inptr++; /* advance pointers to next column */
- quantptr++;
- wsptr++;
- continue;
- }
-
- /* Even part: reverse the even part of the forward DCT. */
- /* The rotator is sqrt(2)*c(-6). */
-
- z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
- z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
-
- z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
- tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
- tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
-
- z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
- z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
-
- tmp0 = (z2 + z3) << CONST_BITS;
- tmp1 = (z2 - z3) << CONST_BITS;
-
- tmp10 = tmp0 + tmp3;
- tmp13 = tmp0 - tmp3;
- tmp11 = tmp1 + tmp2;
- tmp12 = tmp1 - tmp2;
-
- /* Odd part per figure 8; the matrix is unitary and hence its
- * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
- */
-
- tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
- tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
- tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
- tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
-
- z1 = tmp0 + tmp3;
- z2 = tmp1 + tmp2;
- z3 = tmp0 + tmp2;
- z4 = tmp1 + tmp3;
- z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */
-
- tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
- tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
- tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
- tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
- z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
- z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
- z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
- z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
-
- z3 += z5;
- z4 += z5;
-
- tmp0 += z1 + z3;
- tmp1 += z2 + z4;
- tmp2 += z2 + z3;
- tmp3 += z1 + z4;
-
- /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
-
- wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
- wsptr[DCTSIZE*7] = (int) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
- wsptr[DCTSIZE*1] = (int) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
- wsptr[DCTSIZE*6] = (int) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
- wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
- wsptr[DCTSIZE*5] = (int) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
- wsptr[DCTSIZE*3] = (int) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
- wsptr[DCTSIZE*4] = (int) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS);
-
- inptr++; /* advance pointers to next column */
- quantptr++;
- wsptr++;
- }
-
- /* Pass 2: process rows from work array, store into output array. */
- /* Note that we must descale the results by a factor of 8 == 2**3, */
- /* and also undo the PASS1_BITS scaling. */
-
- wsptr = workspace;
- for (ctr = 0; ctr < DCTSIZE; ctr++) {
- outptr = output_buf[ctr] + output_col;
- /* Rows of zeroes can be exploited in the same way as we did with columns.
- * However, the column calculation has created many nonzero AC terms, so
- * the simplification applies less often (typically 5% to 10% of the time).
- * On machines with very fast multiplication, it's possible that the
- * test takes more time than it's worth. In that case this section
- * may be commented out.
- */
-
-#ifndef NO_ZERO_ROW_TEST
- if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&
- wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
- /* AC terms all zero */
- JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3)
- & RANGE_MASK];
-
- outptr[0] = dcval;
- outptr[1] = dcval;
- outptr[2] = dcval;
- outptr[3] = dcval;
- outptr[4] = dcval;
- outptr[5] = dcval;
- outptr[6] = dcval;
- outptr[7] = dcval;
-
- wsptr += DCTSIZE; /* advance pointer to next row */
- continue;
- }
-#endif
-
- /* Even part: reverse the even part of the forward DCT. */
- /* The rotator is sqrt(2)*c(-6). */
-
- z2 = (INT32) wsptr[2];
- z3 = (INT32) wsptr[6];
-
- z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
- tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
- tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
-
- tmp0 = ((INT32) wsptr[0] + (INT32) wsptr[4]) << CONST_BITS;
- tmp1 = ((INT32) wsptr[0] - (INT32) wsptr[4]) << CONST_BITS;
-
- tmp10 = tmp0 + tmp3;
- tmp13 = tmp0 - tmp3;
- tmp11 = tmp1 + tmp2;
- tmp12 = tmp1 - tmp2;
-
- /* Odd part per figure 8; the matrix is unitary and hence its
- * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
- */
-
- tmp0 = (INT32) wsptr[7];
- tmp1 = (INT32) wsptr[5];
- tmp2 = (INT32) wsptr[3];
- tmp3 = (INT32) wsptr[1];
-
- z1 = tmp0 + tmp3;
- z2 = tmp1 + tmp2;
- z3 = tmp0 + tmp2;
- z4 = tmp1 + tmp3;
- z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */
-
- tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
- tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
- tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
- tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
- z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
- z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
- z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
- z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
-
- z3 += z5;
- z4 += z5;
-
- tmp0 += z1 + z3;
- tmp1 += z2 + z4;
- tmp2 += z2 + z3;
- tmp3 += z1 + z4;
-
- /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
-
- outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp3,
- CONST_BITS+PASS1_BITS+3)
- & RANGE_MASK];
- outptr[7] = range_limit[(int) DESCALE(tmp10 - tmp3,
- CONST_BITS+PASS1_BITS+3)
- & RANGE_MASK];
- outptr[1] = range_limit[(int) DESCALE(tmp11 + tmp2,
- CONST_BITS+PASS1_BITS+3)
- & RANGE_MASK];
- outptr[6] = range_limit[(int) DESCALE(tmp11 - tmp2,
- CONST_BITS+PASS1_BITS+3)
- & RANGE_MASK];
- outptr[2] = range_limit[(int) DESCALE(tmp12 + tmp1,
- CONST_BITS+PASS1_BITS+3)
- & RANGE_MASK];
- outptr[5] = range_limit[(int) DESCALE(tmp12 - tmp1,
- CONST_BITS+PASS1_BITS+3)
- & RANGE_MASK];
- outptr[3] = range_limit[(int) DESCALE(tmp13 + tmp0,
- CONST_BITS+PASS1_BITS+3)
- & RANGE_MASK];
- outptr[4] = range_limit[(int) DESCALE(tmp13 - tmp0,
- CONST_BITS+PASS1_BITS+3)
- & RANGE_MASK];
-
- wsptr += DCTSIZE; /* advance pointer to next row */
- }
-}
-
-#endif /* DCT_ISLOW_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jidctred.c b/engine/code/jpeg-6b/jidctred.c
deleted file mode 100644
index 421f3c7..0000000
--- a/engine/code/jpeg-6b/jidctred.c
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * jidctred.c
- *
- * Copyright (C) 1994-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains inverse-DCT routines that produce reduced-size output:
- * either 4x4, 2x2, or 1x1 pixels from an 8x8 DCT block.
- *
- * The implementation is based on the Loeffler, Ligtenberg and Moschytz (LL&M)
- * algorithm used in jidctint.c. We simply replace each 8-to-8 1-D IDCT step
- * with an 8-to-4 step that produces the four averages of two adjacent outputs
- * (or an 8-to-2 step producing two averages of four outputs, for 2x2 output).
- * These steps were derived by computing the corresponding values at the end
- * of the normal LL&M code, then simplifying as much as possible.
- *
- * 1x1 is trivial: just take the DC coefficient divided by 8.
- *
- * See jidctint.c for additional comments.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jdct.h" /* Private declarations for DCT subsystem */
-
-#ifdef IDCT_SCALING_SUPPORTED
-
-
-/*
- * This module is specialized to the case DCTSIZE = 8.
- */
-
-#if DCTSIZE != 8
- Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
-#endif
-
-
-/* Scaling is the same as in jidctint.c. */
-
-#if BITS_IN_JSAMPLE == 8
-#define CONST_BITS 13
-#define PASS1_BITS 2
-#else
-#define CONST_BITS 13
-#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
-#endif
-
-/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
- * causing a lot of useless floating-point operations at run time.
- * To get around this we use the following pre-calculated constants.
- * If you change CONST_BITS you may want to add appropriate values.
- * (With a reasonable C compiler, you can just rely on the FIX() macro...)
- */
-
-#if CONST_BITS == 13
-#define FIX_0_211164243 ((INT32) 1730) /* FIX(0.211164243) */
-#define FIX_0_509795579 ((INT32) 4176) /* FIX(0.509795579) */
-#define FIX_0_601344887 ((INT32) 4926) /* FIX(0.601344887) */
-#define FIX_0_720959822 ((INT32) 5906) /* FIX(0.720959822) */
-#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */
-#define FIX_0_850430095 ((INT32) 6967) /* FIX(0.850430095) */
-#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */
-#define FIX_1_061594337 ((INT32) 8697) /* FIX(1.061594337) */
-#define FIX_1_272758580 ((INT32) 10426) /* FIX(1.272758580) */
-#define FIX_1_451774981 ((INT32) 11893) /* FIX(1.451774981) */
-#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */
-#define FIX_2_172734803 ((INT32) 17799) /* FIX(2.172734803) */
-#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */
-#define FIX_3_624509785 ((INT32) 29692) /* FIX(3.624509785) */
-#else
-#define FIX_0_211164243 FIX(0.211164243)
-#define FIX_0_509795579 FIX(0.509795579)
-#define FIX_0_601344887 FIX(0.601344887)
-#define FIX_0_720959822 FIX(0.720959822)
-#define FIX_0_765366865 FIX(0.765366865)
-#define FIX_0_850430095 FIX(0.850430095)
-#define FIX_0_899976223 FIX(0.899976223)
-#define FIX_1_061594337 FIX(1.061594337)
-#define FIX_1_272758580 FIX(1.272758580)
-#define FIX_1_451774981 FIX(1.451774981)
-#define FIX_1_847759065 FIX(1.847759065)
-#define FIX_2_172734803 FIX(2.172734803)
-#define FIX_2_562915447 FIX(2.562915447)
-#define FIX_3_624509785 FIX(3.624509785)
-#endif
-
-
-/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
- * For 8-bit samples with the recommended scaling, all the variable
- * and constant values involved are no more than 16 bits wide, so a
- * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
- * For 12-bit samples, a full 32-bit multiplication will be needed.
- */
-
-#if BITS_IN_JSAMPLE == 8
-#define MULTIPLY(var,const) MULTIPLY16C16(var,const)
-#else
-#define MULTIPLY(var,const) ((var) * (const))
-#endif
-
-
-/* Dequantize a coefficient by multiplying it by the multiplier-table
- * entry; produce an int result. In this module, both inputs and result
- * are 16 bits or less, so either int or short multiply will work.
- */
-
-#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval))
-
-
-/*
- * Perform dequantization and inverse DCT on one block of coefficients,
- * producing a reduced-size 4x4 output block.
- */
-
-GLOBAL(void)
-jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col)
-{
- INT32 tmp0, tmp2, tmp10, tmp12;
- INT32 z1, z2, z3, z4;
- JCOEFPTR inptr;
- ISLOW_MULT_TYPE * quantptr;
- int * wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
- int ctr;
- int workspace[DCTSIZE*4]; /* buffers data between passes */
- SHIFT_TEMPS
-
- /* Pass 1: process columns from input, store into work array. */
-
- inptr = coef_block;
- quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
- wsptr = workspace;
- for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) {
- /* Don't bother to process column 4, because second pass won't use it */
- if (ctr == DCTSIZE-4)
- continue;
- if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
- inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*5] == 0 &&
- inptr[DCTSIZE*6] == 0 && inptr[DCTSIZE*7] == 0) {
- /* AC terms all zero; we need not examine term 4 for 4x4 output */
- int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
-
- wsptr[DCTSIZE*0] = dcval;
- wsptr[DCTSIZE*1] = dcval;
- wsptr[DCTSIZE*2] = dcval;
- wsptr[DCTSIZE*3] = dcval;
-
- continue;
- }
-
- /* Even part */
-
- tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
- tmp0 <<= (CONST_BITS+1);
-
- z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
- z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
-
- tmp2 = MULTIPLY(z2, FIX_1_847759065) + MULTIPLY(z3, - FIX_0_765366865);
-
- tmp10 = tmp0 + tmp2;
- tmp12 = tmp0 - tmp2;
-
- /* Odd part */
-
- z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
- z2 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
- z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
- z4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
-
- tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */
- + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */
- + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */
- + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */
-
- tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */
- + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */
- + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */
- + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */
-
- /* Final output stage */
-
- wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp2, CONST_BITS-PASS1_BITS+1);
- wsptr[DCTSIZE*3] = (int) DESCALE(tmp10 - tmp2, CONST_BITS-PASS1_BITS+1);
- wsptr[DCTSIZE*1] = (int) DESCALE(tmp12 + tmp0, CONST_BITS-PASS1_BITS+1);
- wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 - tmp0, CONST_BITS-PASS1_BITS+1);
- }
-
- /* Pass 2: process 4 rows from work array, store into output array. */
-
- wsptr = workspace;
- for (ctr = 0; ctr < 4; ctr++) {
- outptr = output_buf[ctr] + output_col;
- /* It's not clear whether a zero row test is worthwhile here ... */
-
-#ifndef NO_ZERO_ROW_TEST
- if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 &&
- wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
- /* AC terms all zero */
- JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3)
- & RANGE_MASK];
-
- outptr[0] = dcval;
- outptr[1] = dcval;
- outptr[2] = dcval;
- outptr[3] = dcval;
-
- wsptr += DCTSIZE; /* advance pointer to next row */
- continue;
- }
-#endif
-
- /* Even part */
-
- tmp0 = ((INT32) wsptr[0]) << (CONST_BITS+1);
-
- tmp2 = MULTIPLY((INT32) wsptr[2], FIX_1_847759065)
- + MULTIPLY((INT32) wsptr[6], - FIX_0_765366865);
-
- tmp10 = tmp0 + tmp2;
- tmp12 = tmp0 - tmp2;
-
- /* Odd part */
-
- z1 = (INT32) wsptr[7];
- z2 = (INT32) wsptr[5];
- z3 = (INT32) wsptr[3];
- z4 = (INT32) wsptr[1];
-
- tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */
- + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */
- + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */
- + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */
-
- tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */
- + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */
- + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */
- + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */
-
- /* Final output stage */
-
- outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp2,
- CONST_BITS+PASS1_BITS+3+1)
- & RANGE_MASK];
- outptr[3] = range_limit[(int) DESCALE(tmp10 - tmp2,
- CONST_BITS+PASS1_BITS+3+1)
- & RANGE_MASK];
- outptr[1] = range_limit[(int) DESCALE(tmp12 + tmp0,
- CONST_BITS+PASS1_BITS+3+1)
- & RANGE_MASK];
- outptr[2] = range_limit[(int) DESCALE(tmp12 - tmp0,
- CONST_BITS+PASS1_BITS+3+1)
- & RANGE_MASK];
-
- wsptr += DCTSIZE; /* advance pointer to next row */
- }
-}
-
-
-/*
- * Perform dequantization and inverse DCT on one block of coefficients,
- * producing a reduced-size 2x2 output block.
- */
-
-GLOBAL(void)
-jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col)
-{
- INT32 tmp0, tmp10, z1;
- JCOEFPTR inptr;
- ISLOW_MULT_TYPE * quantptr;
- int * wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
- int ctr;
- int workspace[DCTSIZE*2]; /* buffers data between passes */
- SHIFT_TEMPS
-
- /* Pass 1: process columns from input, store into work array. */
-
- inptr = coef_block;
- quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
- wsptr = workspace;
- for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) {
- /* Don't bother to process columns 2,4,6 */
- if (ctr == DCTSIZE-2 || ctr == DCTSIZE-4 || ctr == DCTSIZE-6)
- continue;
- if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*3] == 0 &&
- inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*7] == 0) {
- /* AC terms all zero; we need not examine terms 2,4,6 for 2x2 output */
- int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
-
- wsptr[DCTSIZE*0] = dcval;
- wsptr[DCTSIZE*1] = dcval;
-
- continue;
- }
-
- /* Even part */
-
- z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
- tmp10 = z1 << (CONST_BITS+2);
-
- /* Odd part */
-
- z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
- tmp0 = MULTIPLY(z1, - FIX_0_720959822); /* sqrt(2) * (c7-c5+c3-c1) */
- z1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
- tmp0 += MULTIPLY(z1, FIX_0_850430095); /* sqrt(2) * (-c1+c3+c5+c7) */
- z1 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
- tmp0 += MULTIPLY(z1, - FIX_1_272758580); /* sqrt(2) * (-c1+c3-c5-c7) */
- z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
- tmp0 += MULTIPLY(z1, FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */
-
- /* Final output stage */
-
- wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp0, CONST_BITS-PASS1_BITS+2);
- wsptr[DCTSIZE*1] = (int) DESCALE(tmp10 - tmp0, CONST_BITS-PASS1_BITS+2);
- }
-
- /* Pass 2: process 2 rows from work array, store into output array. */
-
- wsptr = workspace;
- for (ctr = 0; ctr < 2; ctr++) {
- outptr = output_buf[ctr] + output_col;
- /* It's not clear whether a zero row test is worthwhile here ... */
-
-#ifndef NO_ZERO_ROW_TEST
- if (wsptr[1] == 0 && wsptr[3] == 0 && wsptr[5] == 0 && wsptr[7] == 0) {
- /* AC terms all zero */
- JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3)
- & RANGE_MASK];
-
- outptr[0] = dcval;
- outptr[1] = dcval;
-
- wsptr += DCTSIZE; /* advance pointer to next row */
- continue;
- }
-#endif
-
- /* Even part */
-
- tmp10 = ((INT32) wsptr[0]) << (CONST_BITS+2);
-
- /* Odd part */
-
- tmp0 = MULTIPLY((INT32) wsptr[7], - FIX_0_720959822) /* sqrt(2) * (c7-c5+c3-c1) */
- + MULTIPLY((INT32) wsptr[5], FIX_0_850430095) /* sqrt(2) * (-c1+c3+c5+c7) */
- + MULTIPLY((INT32) wsptr[3], - FIX_1_272758580) /* sqrt(2) * (-c1+c3-c5-c7) */
- + MULTIPLY((INT32) wsptr[1], FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */
-
- /* Final output stage */
-
- outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp0,
- CONST_BITS+PASS1_BITS+3+2)
- & RANGE_MASK];
- outptr[1] = range_limit[(int) DESCALE(tmp10 - tmp0,
- CONST_BITS+PASS1_BITS+3+2)
- & RANGE_MASK];
-
- wsptr += DCTSIZE; /* advance pointer to next row */
- }
-}
-
-
-/*
- * Perform dequantization and inverse DCT on one block of coefficients,
- * producing a reduced-size 1x1 output block.
- */
-
-GLOBAL(void)
-jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col)
-{
- int dcval;
- ISLOW_MULT_TYPE * quantptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
- SHIFT_TEMPS
-
- /* We hardly need an inverse DCT routine for this: just take the
- * average pixel value, which is one-eighth of the DC coefficient.
- */
- quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
- dcval = DEQUANTIZE(coef_block[0], quantptr[0]);
- dcval = (int) DESCALE((INT32) dcval, 3);
-
- output_buf[0][output_col] = range_limit[dcval & RANGE_MASK];
-}
-
-#endif /* IDCT_SCALING_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jinclude.h b/engine/code/jpeg-6b/jinclude.h
deleted file mode 100644
index 1c5515c..0000000
--- a/engine/code/jpeg-6b/jinclude.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * jinclude.h
- *
- * Copyright (C) 1991-1994, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file exists to provide a single place to fix any problems with
- * including the wrong system include files. (Common problems are taken
- * care of by the standard jconfig symbols, but on really weird systems
- * you may have to edit this file.)
- *
- * NOTE: this file is NOT intended to be included by applications using the
- * JPEG library. Most applications need only include jpeglib.h.
- */
-
-
-#ifdef _MSC_VER
-
-#pragma warning(disable : 4018) // signed/unsigned mismatch
-#pragma warning(disable : 4032)
-#pragma warning(disable : 4051)
-#pragma warning(disable : 4057) // slightly different base types
-#pragma warning(disable : 4100) // unreferenced formal parameter
-#pragma warning(disable : 4115)
-#pragma warning(disable : 4125) // decimal digit terminates octal escape sequence
-#pragma warning(disable : 4127) // conditional expression is constant
-#pragma warning(disable : 4136)
-#pragma warning(disable : 4152) // nonstandard extension, function/data pointer conversion in expression
-#pragma warning(disable : 4201)
-#pragma warning(disable : 4214)
-#pragma warning(disable : 4244)
-#pragma warning(disable : 4305) // truncation from const double to float
-#pragma warning(disable : 4310) // cast truncates constant value
-#pragma warning(disable: 4505) // unreferenced local function has been removed
-#pragma warning(disable : 4514)
-#pragma warning(disable : 4702) // unreachable code
-#pragma warning(disable : 4711) // selected for automatic inline expansion
-#pragma warning(disable : 4220) // varargs matches remaining parameters
-#pragma warning(disable : 4761) // integral size mismatch
-#endif
-
-/* Include auto-config file to find out which system include files we need. */
-
-#include "../jpeg-6b/jconfig.h" /* auto configuration options */
-#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */
-
-/*
- * We need the NULL macro and size_t typedef.
- * On an ANSI-conforming system it is sufficient to include <stddef.h>.
- * Otherwise, we get them from <stdlib.h> or <stdio.h>; we may have to
- * pull in <sys/types.h> as well.
- * Note that the core JPEG library does not require <stdio.h>;
- * only the default error handler and data source/destination modules do.
- * But we must pull it in because of the references to FILE in jpeglib.h.
- * You can remove those references if you want to compile without <stdio.h>.
- */
-
-#ifdef HAVE_STDDEF_H
-#include <stddef.h>
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifdef NEED_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#include <stdio.h>
-
-/*
- * We need memory copying and zeroing functions, plus strncpy().
- * ANSI and System V implementations declare these in <string.h>.
- * BSD doesn't have the mem() functions, but it does have bcopy()/bzero().
- * Some systems may declare memset and memcpy in <memory.h>.
- *
- * NOTE: we assume the size parameters to these functions are of type size_t.
- * Change the casts in these macros if not!
- */
-
-#ifdef NEED_BSD_STRINGS
-
-#include <strings.h>
-#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size))
-#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size))
-
-#else /* not BSD, assume ANSI/SysV string lib */
-
-#include <string.h>
-#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size))
-#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size))
-
-#endif
-
-/*
- * In ANSI C, and indeed any rational implementation, size_t is also the
- * type returned by sizeof(). However, it seems there are some irrational
- * implementations out there, in which sizeof() returns an int even though
- * size_t is defined as long or unsigned long. To ensure consistent results
- * we always use this SIZEOF() macro in place of using sizeof() directly.
- */
-
-#define SIZEOF(object) ((size_t) sizeof(object))
-
-/*
- * The modules that use fread() and fwrite() always invoke them through
- * these macros. On some systems you may need to twiddle the argument casts.
- * CAUTION: argument order is different from underlying functions!
- */
-
-#define JFREAD(file,buf,sizeofbuf) \
- ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
-#define JFWRITE(file,buf,sizeofbuf) \
- ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
diff --git a/engine/code/jpeg-6b/jload.c b/engine/code/jpeg-6b/jload.c
deleted file mode 100644
index 29e750b..0000000
--- a/engine/code/jpeg-6b/jload.c
+++ /dev/null
@@ -1,145 +0,0 @@
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-
-/*
- * Include file for users of JPEG library.
- * You will need to have included system headers that define at least
- * the typedefs FILE and size_t before you can include jpeglib.h.
- * (stdio.h is sufficient on ANSI-conforming systems.)
- * You may also wish to include "jerror.h".
- */
-
-#include "jpeglib.h"
-
-
-int LoadJPG( const char *filename, unsigned char **pic, int *width, int *height ) {
- /* This struct contains the JPEG decompression parameters and pointers to
- * working space (which is allocated as needed by the JPEG library).
- */
- struct jpeg_decompress_struct cinfo;
- /* We use our private extension JPEG error handler.
- * Note that this struct must live as long as the main JPEG parameter
- * struct, to avoid dangling-pointer problems.
- */
- /* This struct represents a JPEG error handler. It is declared separately
- * because applications often want to supply a specialized error handler
- * (see the second half of this file for an example). But here we just
- * take the easy way out and use the standard error handler, which will
- * print a message on stderr and call exit() if compression fails.
- * Note that this struct must live as long as the main JPEG parameter
- * struct, to avoid dangling-pointer problems.
- */
- struct jpeg_error_mgr jerr;
- /* More stuff */
- fileHandle_t infile; /* source file */
- JSAMPARRAY buffer; /* Output row buffer */
- int row_stride; /* physical row width in output buffer */
- unsigned char *out;
-
- /* In this example we want to open the input file before doing anything else,
- * so that the setjmp() error recovery below can assume the file is open.
- * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
- * requires it in order to read binary files.
- */
-
- FS_FOpenFileRead( filename, &infile, qfalse );
- if (infile == 0) {
- return 0;
- }
-
- /* Step 1: allocate and initialize JPEG decompression object */
-
- /* We have to set up the error handler first, in case the initialization
- * step fails. (Unlikely, but it could happen if you are out of memory.)
- * This routine fills in the contents of struct jerr, and returns jerr's
- * address which we place into the link field in cinfo.
- */
- cinfo.err = jpeg_std_error(&jerr);
-
- /* Now we can initialize the JPEG decompression object. */
- jpeg_create_decompress(&cinfo);
-
- /* Step 2: specify data source (eg, a file) */
-
- jpeg_stdio_src(&cinfo, infile);
-
- /* Step 3: read file parameters with jpeg_read_header() */
-
- (void) jpeg_read_header(&cinfo, TRUE);
- /* We can ignore the return value from jpeg_read_header since
- * (a) suspension is not possible with the stdio data source, and
- * (b) we passed TRUE to reject a tables-only JPEG file as an error.
- * See libjpeg.doc for more info.
- */
-
- /* Step 4: set parameters for decompression */
-
- /* In this example, we don't need to change any of the defaults set by
- * jpeg_read_header(), so we do nothing here.
- */
-
- /* Step 5: Start decompressor */
-
- (void) jpeg_start_decompress(&cinfo);
- /* We can ignore the return value since suspension is not possible
- * with the stdio data source.
- */
-
- /* We may need to do some setup of our own at this point before reading
- * the data. After jpeg_start_decompress() we have the correct scaled
- * output image dimensions available, as well as the output colormap
- * if we asked for color quantization.
- * In this example, we need to make an output work buffer of the right size.
- */
- /* JSAMPLEs per row in output buffer */
- row_stride = cinfo.output_width * cinfo.output_components;
-
- out = Z_Malloc(cinfo.output_width*cinfo.output_height*cinfo.output_components);
-
- *pic = out;
- *width = cinfo.output_width;
- *height = cinfo.output_height;
-
- /* Step 6: while (scan lines remain to be read) */
- /* jpeg_read_scanlines(...); */
-
- /* Here we use the library's state variable cinfo.output_scanline as the
- * loop counter, so that we don't have to keep track ourselves.
- */
- while (cinfo.output_scanline < cinfo.output_height) {
- /* jpeg_read_scanlines expects an array of pointers to scanlines.
- * Here the array is only one element long, but you could ask for
- * more than one scanline at a time if that's more convenient.
- */
- buffer = (JSAMPARRAY)out+(row_stride*cinfo.output_scanline);
- (void) jpeg_read_scanlines(&cinfo, buffer, 1);
- }
-
- /* Step 7: Finish decompression */
-
- (void) jpeg_finish_decompress(&cinfo);
- /* We can ignore the return value since suspension is not possible
- * with the stdio data source.
- */
-
- /* Step 8: Release JPEG decompression object */
-
- /* This is an important step since it will release a good deal of memory. */
- jpeg_destroy_decompress(&cinfo);
-
- /* After finish_decompress, we can close the input file.
- * Here we postpone it until after no more JPEG errors are possible,
- * so as to simplify the setjmp error logic above. (Actually, I don't
- * think that jpeg_destroy can do an error exit, but why assume anything...)
- */
- FS_FCloseFile(infile);
-
- /* At this point you may want to check to see whether any corrupt-data
- * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
- */
-
- /* And we're done! */
- return 1;
-}
-
diff --git a/engine/code/jpeg-6b/jmemansi.c b/engine/code/jpeg-6b/jmemansi.c
deleted file mode 100644
index 2d93e49..0000000
--- a/engine/code/jpeg-6b/jmemansi.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * jmemansi.c
- *
- * Copyright (C) 1992-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file provides a simple generic implementation of the system-
- * dependent portion of the JPEG memory manager. This implementation
- * assumes that you have the ANSI-standard library routine tmpfile().
- * Also, the problem of determining the amount of memory available
- * is shoved onto the user.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jmemsys.h" /* import the system-dependent declarations */
-
-#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
-extern void * malloc JPP((size_t size));
-extern void free JPP((void *ptr));
-#endif
-
-#ifndef SEEK_SET /* pre-ANSI systems may not define this; */
-#define SEEK_SET 0 /* if not, assume 0 is correct */
-#endif
-
-
-/*
- * Memory allocation and freeing are controlled by the regular library
- * routines malloc() and free().
- */
-
-GLOBAL(void *)
-jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
-{
- return (void *) malloc(sizeofobject);
-}
-
-GLOBAL(void)
-jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
-{
- free(object);
-}
-
-
-/*
- * "Large" objects are treated the same as "small" ones.
- * NB: although we include FAR keywords in the routine declarations,
- * this file won't actually work in 80x86 small/medium model; at least,
- * you probably won't be able to process useful-size images in only 64KB.
- */
-
-GLOBAL(void FAR *)
-jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
-{
- return (void FAR *) malloc(sizeofobject);
-}
-
-GLOBAL(void)
-jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
-{
- free(object);
-}
-
-
-/*
- * This routine computes the total memory space available for allocation.
- * It's impossible to do this in a portable way; our current solution is
- * to make the user tell us (with a default value set at compile time).
- * If you can actually get the available space, it's a good idea to subtract
- * a slop factor of 5% or so.
- */
-
-#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
-#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */
-#endif
-
-GLOBAL(long)
-jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
- long max_bytes_needed, long already_allocated)
-{
- return cinfo->mem->max_memory_to_use - already_allocated;
-}
-
-
-/*
- * Backing store (temporary file) management.
- * Backing store objects are only used when the value returned by
- * jpeg_mem_available is less than the total space needed. You can dispense
- * with these routines if you have plenty of virtual memory; see jmemnobs.c.
- */
-
-
-METHODDEF(void)
-read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
- void FAR * buffer_address,
- long file_offset, long byte_count)
-{
- if (fseek(info->temp_file, file_offset, SEEK_SET))
- ERREXIT(cinfo, JERR_TFILE_SEEK);
- if (JFREAD(info->temp_file, buffer_address, byte_count)
- != (size_t) byte_count)
- ERREXIT(cinfo, JERR_TFILE_READ);
-}
-
-
-METHODDEF(void)
-write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
- void FAR * buffer_address,
- long file_offset, long byte_count)
-{
- if (fseek(info->temp_file, file_offset, SEEK_SET))
- ERREXIT(cinfo, JERR_TFILE_SEEK);
- if (JFWRITE(info->temp_file, buffer_address, byte_count)
- != (size_t) byte_count)
- ERREXIT(cinfo, JERR_TFILE_WRITE);
-}
-
-
-METHODDEF(void)
-close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
-{
- fclose(info->temp_file);
- /* Since this implementation uses tmpfile() to create the file,
- * no explicit file deletion is needed.
- */
-}
-
-
-/*
- * Initial opening of a backing-store object.
- *
- * This version uses tmpfile(), which constructs a suitable file name
- * behind the scenes. We don't have to use info->temp_name[] at all;
- * indeed, we can't even find out the actual name of the temp file.
- */
-
-GLOBAL(void)
-jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
- long total_bytes_needed)
-{
- if ((info->temp_file = tmpfile()) == NULL)
- ERREXITS(cinfo, JERR_TFILE_CREATE, "");
- info->read_backing_store = read_backing_store;
- info->write_backing_store = write_backing_store;
- info->close_backing_store = close_backing_store;
-}
-
-
-/*
- * These routines take care of any system-dependent initialization and
- * cleanup required.
- */
-
-GLOBAL(long)
-jpeg_mem_init (j_common_ptr cinfo)
-{
- return DEFAULT_MAX_MEM; /* default for max_memory_to_use */
-}
-
-GLOBAL(void)
-jpeg_mem_term (j_common_ptr cinfo)
-{
- /* no work */
-}
diff --git a/engine/code/jpeg-6b/jmemdos.c b/engine/code/jpeg-6b/jmemdos.c
deleted file mode 100644
index 60b45c6..0000000
--- a/engine/code/jpeg-6b/jmemdos.c
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
- * jmemdos.c
- *
- * Copyright (C) 1992-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file provides an MS-DOS-compatible implementation of the system-
- * dependent portion of the JPEG memory manager. Temporary data can be
- * stored in extended or expanded memory as well as in regular DOS files.
- *
- * If you use this file, you must be sure that NEED_FAR_POINTERS is defined
- * if you compile in a small-data memory model; it should NOT be defined if
- * you use a large-data memory model. This file is not recommended if you
- * are using a flat-memory-space 386 environment such as DJGCC or Watcom C.
- * Also, this code will NOT work if struct fields are aligned on greater than
- * 2-byte boundaries.
- *
- * Based on code contributed by Ge' Weijers.
- */
-
-/*
- * If you have both extended and expanded memory, you may want to change the
- * order in which they are tried in jopen_backing_store. On a 286 machine
- * expanded memory is usually faster, since extended memory access involves
- * an expensive protected-mode-and-back switch. On 386 and better, extended
- * memory is usually faster. As distributed, the code tries extended memory
- * first (what? not everyone has a 386? :-).
- *
- * You can disable use of extended/expanded memory entirely by altering these
- * definitions or overriding them from the Makefile (eg, -DEMS_SUPPORTED=0).
- */
-
-#ifndef XMS_SUPPORTED
-#define XMS_SUPPORTED 1
-#endif
-#ifndef EMS_SUPPORTED
-#define EMS_SUPPORTED 1
-#endif
-
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jmemsys.h" /* import the system-dependent declarations */
-
-#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare these */
-extern void * malloc JPP((size_t size));
-extern void free JPP((void *ptr));
-extern char * getenv JPP((const char * name));
-#endif
-
-#ifdef NEED_FAR_POINTERS
-
-#ifdef __TURBOC__
-/* These definitions work for Borland C (Turbo C) */
-#include <alloc.h> /* need farmalloc(), farfree() */
-#define far_malloc(x) farmalloc(x)
-#define far_free(x) farfree(x)
-#else
-/* These definitions work for Microsoft C and compatible compilers */
-#include <malloc.h> /* need _fmalloc(), _ffree() */
-#define far_malloc(x) _fmalloc(x)
-#define far_free(x) _ffree(x)
-#endif
-
-#else /* not NEED_FAR_POINTERS */
-
-#define far_malloc(x) malloc(x)
-#define far_free(x) free(x)
-
-#endif /* NEED_FAR_POINTERS */
-
-#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
-#define READ_BINARY "r"
-#else
-#define READ_BINARY "rb"
-#endif
-
-#ifndef USE_MSDOS_MEMMGR /* make sure user got configuration right */
- You forgot to define USE_MSDOS_MEMMGR in jconfig.h. /* deliberate syntax error */
-#endif
-
-#if MAX_ALLOC_CHUNK >= 65535L /* make sure jconfig.h got this right */
- MAX_ALLOC_CHUNK should be less than 64K. /* deliberate syntax error */
-#endif
-
-
-/*
- * Declarations for assembly-language support routines (see jmemdosa.asm).
- *
- * The functions are declared "far" as are all their pointer arguments;
- * this ensures the assembly source code will work regardless of the
- * compiler memory model. We assume "short" is 16 bits, "long" is 32.
- */
-
-typedef void far * XMSDRIVER; /* actually a pointer to code */
-typedef struct { /* registers for calling XMS driver */
- unsigned short ax, dx, bx;
- void far * ds_si;
- } XMScontext;
-typedef struct { /* registers for calling EMS driver */
- unsigned short ax, dx, bx;
- void far * ds_si;
- } EMScontext;
-
-extern short far jdos_open JPP((short far * handle, char far * filename));
-extern short far jdos_close JPP((short handle));
-extern short far jdos_seek JPP((short handle, long offset));
-extern short far jdos_read JPP((short handle, void far * buffer,
- unsigned short count));
-extern short far jdos_write JPP((short handle, void far * buffer,
- unsigned short count));
-extern void far jxms_getdriver JPP((XMSDRIVER far *));
-extern void far jxms_calldriver JPP((XMSDRIVER, XMScontext far *));
-extern short far jems_available JPP((void));
-extern void far jems_calldriver JPP((EMScontext far *));
-
-
-/*
- * Selection of a file name for a temporary file.
- * This is highly system-dependent, and you may want to customize it.
- */
-
-static int next_file_num; /* to distinguish among several temp files */
-
-LOCAL(void)
-select_file_name (char * fname)
-{
- const char * env;
- char * ptr;
- FILE * tfile;
-
- /* Keep generating file names till we find one that's not in use */
- for (;;) {
- /* Get temp directory name from environment TMP or TEMP variable;
- * if none, use "."
- */
- if ((env = (const char *) getenv("TMP")) == NULL)
- if ((env = (const char *) getenv("TEMP")) == NULL)
- env = ".";
- if (*env == '\0') /* null string means "." */
- env = ".";
- ptr = fname; /* copy name to fname */
- while (*env != '\0')
- *ptr++ = *env++;
- if (ptr[-1] != '\\' && ptr[-1] != '/')
- *ptr++ = '\\'; /* append backslash if not in env variable */
- /* Append a suitable file name */
- next_file_num++; /* advance counter */
- sprintf(ptr, "JPG%03d.TMP", next_file_num);
- /* Probe to see if file name is already in use */
- if ((tfile = fopen(fname, READ_BINARY)) == NULL)
- break;
- fclose(tfile); /* oops, it's there; close tfile & try again */
- }
-}
-
-
-/*
- * Near-memory allocation and freeing are controlled by the regular library
- * routines malloc() and free().
- */
-
-GLOBAL(void *)
-jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
-{
- return (void *) malloc(sizeofobject);
-}
-
-GLOBAL(void)
-jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
-{
- free(object);
-}
-
-
-/*
- * "Large" objects are allocated in far memory, if possible
- */
-
-GLOBAL(void FAR *)
-jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
-{
- return (void FAR *) far_malloc(sizeofobject);
-}
-
-GLOBAL(void)
-jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
-{
- far_free(object);
-}
-
-
-/*
- * This routine computes the total memory space available for allocation.
- * It's impossible to do this in a portable way; our current solution is
- * to make the user tell us (with a default value set at compile time).
- * If you can actually get the available space, it's a good idea to subtract
- * a slop factor of 5% or so.
- */
-
-#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
-#define DEFAULT_MAX_MEM 300000L /* for total usage about 450K */
-#endif
-
-GLOBAL(long)
-jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
- long max_bytes_needed, long already_allocated)
-{
- return cinfo->mem->max_memory_to_use - already_allocated;
-}
-
-
-/*
- * Backing store (temporary file) management.
- * Backing store objects are only used when the value returned by
- * jpeg_mem_available is less than the total space needed. You can dispense
- * with these routines if you have plenty of virtual memory; see jmemnobs.c.
- */
-
-/*
- * For MS-DOS we support three types of backing storage:
- * 1. Conventional DOS files. We access these by direct DOS calls rather
- * than via the stdio package. This provides a bit better performance,
- * but the real reason is that the buffers to be read or written are FAR.
- * The stdio library for small-data memory models can't cope with that.
- * 2. Extended memory, accessed per the XMS V2.0 specification.
- * 3. Expanded memory, accessed per the LIM/EMS 4.0 specification.
- * You'll need copies of those specs to make sense of the related code.
- * The specs are available by Internet FTP from the SIMTEL archives
- * (oak.oakland.edu and its various mirror sites). See files
- * pub/msdos/microsoft/xms20.arc and pub/msdos/info/limems41.zip.
- */
-
-
-/*
- * Access methods for a DOS file.
- */
-
-
-METHODDEF(void)
-read_file_store (j_common_ptr cinfo, backing_store_ptr info,
- void FAR * buffer_address,
- long file_offset, long byte_count)
-{
- if (jdos_seek(info->handle.file_handle, file_offset))
- ERREXIT(cinfo, JERR_TFILE_SEEK);
- /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
- if (byte_count > 65535L) /* safety check */
- ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
- if (jdos_read(info->handle.file_handle, buffer_address,
- (unsigned short) byte_count))
- ERREXIT(cinfo, JERR_TFILE_READ);
-}
-
-
-METHODDEF(void)
-write_file_store (j_common_ptr cinfo, backing_store_ptr info,
- void FAR * buffer_address,
- long file_offset, long byte_count)
-{
- if (jdos_seek(info->handle.file_handle, file_offset))
- ERREXIT(cinfo, JERR_TFILE_SEEK);
- /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
- if (byte_count > 65535L) /* safety check */
- ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
- if (jdos_write(info->handle.file_handle, buffer_address,
- (unsigned short) byte_count))
- ERREXIT(cinfo, JERR_TFILE_WRITE);
-}
-
-
-METHODDEF(void)
-close_file_store (j_common_ptr cinfo, backing_store_ptr info)
-{
- jdos_close(info->handle.file_handle); /* close the file */
- remove(info->temp_name); /* delete the file */
-/* If your system doesn't have remove(), try unlink() instead.
- * remove() is the ANSI-standard name for this function, but
- * unlink() was more common in pre-ANSI systems.
- */
- TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name);
-}
-
-
-LOCAL(boolean)
-open_file_store (j_common_ptr cinfo, backing_store_ptr info,
- long total_bytes_needed)
-{
- short handle;
-
- select_file_name(info->temp_name);
- if (jdos_open((short far *) & handle, (char far *) info->temp_name)) {
- /* might as well exit since jpeg_open_backing_store will fail anyway */
- ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
- return FALSE;
- }
- info->handle.file_handle = handle;
- info->read_backing_store = read_file_store;
- info->write_backing_store = write_file_store;
- info->close_backing_store = close_file_store;
- TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
- return TRUE; /* succeeded */
-}
-
-
-/*
- * Access methods for extended memory.
- */
-
-#if XMS_SUPPORTED
-
-static XMSDRIVER xms_driver; /* saved address of XMS driver */
-
-typedef union { /* either long offset or real-mode pointer */
- long offset;
- void far * ptr;
- } XMSPTR;
-
-typedef struct { /* XMS move specification structure */
- long length;
- XMSH src_handle;
- XMSPTR src;
- XMSH dst_handle;
- XMSPTR dst;
- } XMSspec;
-
-#define ODD(X) (((X) & 1L) != 0)
-
-
-METHODDEF(void)
-read_xms_store (j_common_ptr cinfo, backing_store_ptr info,
- void FAR * buffer_address,
- long file_offset, long byte_count)
-{
- XMScontext ctx;
- XMSspec spec;
- char endbuffer[2];
-
- /* The XMS driver can't cope with an odd length, so handle the last byte
- * specially if byte_count is odd. We don't expect this to be common.
- */
-
- spec.length = byte_count & (~ 1L);
- spec.src_handle = info->handle.xms_handle;
- spec.src.offset = file_offset;
- spec.dst_handle = 0;
- spec.dst.ptr = buffer_address;
-
- ctx.ds_si = (void far *) & spec;
- ctx.ax = 0x0b00; /* EMB move */
- jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
- if (ctx.ax != 1)
- ERREXIT(cinfo, JERR_XMS_READ);
-
- if (ODD(byte_count)) {
- read_xms_store(cinfo, info, (void FAR *) endbuffer,
- file_offset + byte_count - 1L, 2L);
- ((char FAR *) buffer_address)[byte_count - 1L] = endbuffer[0];
- }
-}
-
-
-METHODDEF(void)
-write_xms_store (j_common_ptr cinfo, backing_store_ptr info,
- void FAR * buffer_address,
- long file_offset, long byte_count)
-{
- XMScontext ctx;
- XMSspec spec;
- char endbuffer[2];
-
- /* The XMS driver can't cope with an odd length, so handle the last byte
- * specially if byte_count is odd. We don't expect this to be common.
- */
-
- spec.length = byte_count & (~ 1L);
- spec.src_handle = 0;
- spec.src.ptr = buffer_address;
- spec.dst_handle = info->handle.xms_handle;
- spec.dst.offset = file_offset;
-
- ctx.ds_si = (void far *) & spec;
- ctx.ax = 0x0b00; /* EMB move */
- jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
- if (ctx.ax != 1)
- ERREXIT(cinfo, JERR_XMS_WRITE);
-
- if (ODD(byte_count)) {
- read_xms_store(cinfo, info, (void FAR *) endbuffer,
- file_offset + byte_count - 1L, 2L);
- endbuffer[0] = ((char FAR *) buffer_address)[byte_count - 1L];
- write_xms_store(cinfo, info, (void FAR *) endbuffer,
- file_offset + byte_count - 1L, 2L);
- }
-}
-
-
-METHODDEF(void)
-close_xms_store (j_common_ptr cinfo, backing_store_ptr info)
-{
- XMScontext ctx;
-
- ctx.dx = info->handle.xms_handle;
- ctx.ax = 0x0a00;
- jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
- TRACEMS1(cinfo, 1, JTRC_XMS_CLOSE, info->handle.xms_handle);
- /* we ignore any error return from the driver */
-}
-
-
-LOCAL(boolean)
-open_xms_store (j_common_ptr cinfo, backing_store_ptr info,
- long total_bytes_needed)
-{
- XMScontext ctx;
-
- /* Get address of XMS driver */
- jxms_getdriver((XMSDRIVER far *) & xms_driver);
- if (xms_driver == NULL)
- return FALSE; /* no driver to be had */
-
- /* Get version number, must be >= 2.00 */
- ctx.ax = 0x0000;
- jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
- if (ctx.ax < (unsigned short) 0x0200)
- return FALSE;
-
- /* Try to get space (expressed in kilobytes) */
- ctx.dx = (unsigned short) ((total_bytes_needed + 1023L) >> 10);
- ctx.ax = 0x0900;
- jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
- if (ctx.ax != 1)
- return FALSE;
-
- /* Succeeded, save the handle and away we go */
- info->handle.xms_handle = ctx.dx;
- info->read_backing_store = read_xms_store;
- info->write_backing_store = write_xms_store;
- info->close_backing_store = close_xms_store;
- TRACEMS1(cinfo, 1, JTRC_XMS_OPEN, ctx.dx);
- return TRUE; /* succeeded */
-}
-
-#endif /* XMS_SUPPORTED */
-
-
-/*
- * Access methods for expanded memory.
- */
-
-#if EMS_SUPPORTED
-
-/* The EMS move specification structure requires word and long fields aligned
- * at odd byte boundaries. Some compilers will align struct fields at even
- * byte boundaries. While it's usually possible to force byte alignment,
- * that causes an overall performance penalty and may pose problems in merging
- * JPEG into a larger application. Instead we accept some rather dirty code
- * here. Note this code would fail if the hardware did not allow odd-byte
- * word & long accesses, but all 80x86 CPUs do.
- */
-
-typedef void far * EMSPTR;
-
-typedef union { /* EMS move specification structure */
- long length; /* It's easy to access first 4 bytes */
- char bytes[18]; /* Misaligned fields in here! */
- } EMSspec;
-
-/* Macros for accessing misaligned fields */
-#define FIELD_AT(spec,offset,type) (*((type *) &(spec.bytes[offset])))
-#define SRC_TYPE(spec) FIELD_AT(spec,4,char)
-#define SRC_HANDLE(spec) FIELD_AT(spec,5,EMSH)
-#define SRC_OFFSET(spec) FIELD_AT(spec,7,unsigned short)
-#define SRC_PAGE(spec) FIELD_AT(spec,9,unsigned short)
-#define SRC_PTR(spec) FIELD_AT(spec,7,EMSPTR)
-#define DST_TYPE(spec) FIELD_AT(spec,11,char)
-#define DST_HANDLE(spec) FIELD_AT(spec,12,EMSH)
-#define DST_OFFSET(spec) FIELD_AT(spec,14,unsigned short)
-#define DST_PAGE(spec) FIELD_AT(spec,16,unsigned short)
-#define DST_PTR(spec) FIELD_AT(spec,14,EMSPTR)
-
-#define EMSPAGESIZE 16384L /* gospel, see the EMS specs */
-
-#define HIBYTE(W) (((W) >> 8) & 0xFF)
-#define LOBYTE(W) ((W) & 0xFF)
-
-
-METHODDEF(void)
-read_ems_store (j_common_ptr cinfo, backing_store_ptr info,
- void FAR * buffer_address,
- long file_offset, long byte_count)
-{
- EMScontext ctx;
- EMSspec spec;
-
- spec.length = byte_count;
- SRC_TYPE(spec) = 1;
- SRC_HANDLE(spec) = info->handle.ems_handle;
- SRC_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE);
- SRC_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
- DST_TYPE(spec) = 0;
- DST_HANDLE(spec) = 0;
- DST_PTR(spec) = buffer_address;
-
- ctx.ds_si = (void far *) & spec;
- ctx.ax = 0x5700; /* move memory region */
- jems_calldriver((EMScontext far *) & ctx);
- if (HIBYTE(ctx.ax) != 0)
- ERREXIT(cinfo, JERR_EMS_READ);
-}
-
-
-METHODDEF(void)
-write_ems_store (j_common_ptr cinfo, backing_store_ptr info,
- void FAR * buffer_address,
- long file_offset, long byte_count)
-{
- EMScontext ctx;
- EMSspec spec;
-
- spec.length = byte_count;
- SRC_TYPE(spec) = 0;
- SRC_HANDLE(spec) = 0;
- SRC_PTR(spec) = buffer_address;
- DST_TYPE(spec) = 1;
- DST_HANDLE(spec) = info->handle.ems_handle;
- DST_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE);
- DST_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
-
- ctx.ds_si = (void far *) & spec;
- ctx.ax = 0x5700; /* move memory region */
- jems_calldriver((EMScontext far *) & ctx);
- if (HIBYTE(ctx.ax) != 0)
- ERREXIT(cinfo, JERR_EMS_WRITE);
-}
-
-
-METHODDEF(void)
-close_ems_store (j_common_ptr cinfo, backing_store_ptr info)
-{
- EMScontext ctx;
-
- ctx.ax = 0x4500;
- ctx.dx = info->handle.ems_handle;
- jems_calldriver((EMScontext far *) & ctx);
- TRACEMS1(cinfo, 1, JTRC_EMS_CLOSE, info->handle.ems_handle);
- /* we ignore any error return from the driver */
-}
-
-
-LOCAL(boolean)
-open_ems_store (j_common_ptr cinfo, backing_store_ptr info,
- long total_bytes_needed)
-{
- EMScontext ctx;
-
- /* Is EMS driver there? */
- if (! jems_available())
- return FALSE;
-
- /* Get status, make sure EMS is OK */
- ctx.ax = 0x4000;
- jems_calldriver((EMScontext far *) & ctx);
- if (HIBYTE(ctx.ax) != 0)
- return FALSE;
-
- /* Get version, must be >= 4.0 */
- ctx.ax = 0x4600;
- jems_calldriver((EMScontext far *) & ctx);
- if (HIBYTE(ctx.ax) != 0 || LOBYTE(ctx.ax) < 0x40)
- return FALSE;
-
- /* Try to allocate requested space */
- ctx.ax = 0x4300;
- ctx.bx = (unsigned short) ((total_bytes_needed + EMSPAGESIZE-1L) / EMSPAGESIZE);
- jems_calldriver((EMScontext far *) & ctx);
- if (HIBYTE(ctx.ax) != 0)
- return FALSE;
-
- /* Succeeded, save the handle and away we go */
- info->handle.ems_handle = ctx.dx;
- info->read_backing_store = read_ems_store;
- info->write_backing_store = write_ems_store;
- info->close_backing_store = close_ems_store;
- TRACEMS1(cinfo, 1, JTRC_EMS_OPEN, ctx.dx);
- return TRUE; /* succeeded */
-}
-
-#endif /* EMS_SUPPORTED */
-
-
-/*
- * Initial opening of a backing-store object.
- */
-
-GLOBAL(void)
-jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
- long total_bytes_needed)
-{
- /* Try extended memory, then expanded memory, then regular file. */
-#if XMS_SUPPORTED
- if (open_xms_store(cinfo, info, total_bytes_needed))
- return;
-#endif
-#if EMS_SUPPORTED
- if (open_ems_store(cinfo, info, total_bytes_needed))
- return;
-#endif
- if (open_file_store(cinfo, info, total_bytes_needed))
- return;
- ERREXITS(cinfo, JERR_TFILE_CREATE, "");
-}
-
-
-/*
- * These routines take care of any system-dependent initialization and
- * cleanup required.
- */
-
-GLOBAL(long)
-jpeg_mem_init (j_common_ptr cinfo)
-{
- next_file_num = 0; /* initialize temp file name generator */
- return DEFAULT_MAX_MEM; /* default for max_memory_to_use */
-}
-
-GLOBAL(void)
-jpeg_mem_term (j_common_ptr cinfo)
-{
- /* Microsoft C, at least in v6.00A, will not successfully reclaim freed
- * blocks of size > 32Kbytes unless we give it a kick in the rear, like so:
- */
-#ifdef NEED_FHEAPMIN
- _fheapmin();
-#endif
-}
diff --git a/engine/code/jpeg-6b/jmemmgr.c b/engine/code/jpeg-6b/jmemmgr.c
deleted file mode 100644
index d801b32..0000000
--- a/engine/code/jpeg-6b/jmemmgr.c
+++ /dev/null
@@ -1,1118 +0,0 @@
-/*
- * jmemmgr.c
- *
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains the JPEG system-independent memory management
- * routines. This code is usable across a wide variety of machines; most
- * of the system dependencies have been isolated in a separate file.
- * The major functions provided here are:
- * * pool-based allocation and freeing of memory;
- * * policy decisions about how to divide available memory among the
- * virtual arrays;
- * * control logic for swapping virtual arrays between main memory and
- * backing storage.
- * The separate system-dependent file provides the actual backing-storage
- * access code, and it contains the policy decision about how much total
- * main memory to use.
- * This file is system-dependent in the sense that some of its functions
- * are unnecessary in some systems. For example, if there is enough virtual
- * memory so that backing storage will never be used, much of the virtual
- * array control logic could be removed. (Of course, if you have that much
- * memory then you shouldn't care about a little bit of unused code...)
- */
-
-#define JPEG_INTERNALS
-#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jmemsys.h" /* import the system-dependent declarations */
-
-#ifndef NO_GETENV
-#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare getenv() */
-extern char * getenv JPP((const char * name));
-#endif
-#endif
-
-
-/*
- * Some important notes:
- * The allocation routines provided here must never return NULL.
- * They should exit to error_exit if unsuccessful.
- *
- * It's not a good idea to try to merge the sarray and barray routines,
- * even though they are textually almost the same, because samples are
- * usually stored as bytes while coefficients are shorts or ints. Thus,
- * in machines where byte pointers have a different representation from
- * word pointers, the resulting machine code could not be the same.
- */
-
-
-/*
- * Many machines require storage alignment: longs must start on 4-byte
- * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc()
- * always returns pointers that are multiples of the worst-case alignment
- * requirement, and we had better do so too.
- * There isn't any really portable way to determine the worst-case alignment
- * requirement. This module assumes that the alignment requirement is
- * multiples of sizeof(ALIGN_TYPE).
- * By default, we define ALIGN_TYPE as double. This is necessary on some
- * workstations (where doubles really do need 8-byte alignment) and will work
- * fine on nearly everything. If your machine has lesser alignment needs,
- * you can save a few bytes by making ALIGN_TYPE smaller.
- * The only place I know of where this will NOT work is certain Macintosh
- * 680x0 compilers that define double as a 10-byte IEEE extended float.
- * Doing 10-byte alignment is counterproductive because longwords won't be
- * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have
- * such a compiler.
- */
-
-#ifndef ALIGN_TYPE /* so can override from jconfig.h */
-#define ALIGN_TYPE double
-#endif
-
-
-/*
- * We allocate objects from "pools", where each pool is gotten with a single
- * request to jpeg_get_small() or jpeg_get_large(). There is no per-object
- * overhead within a pool, except for alignment padding. Each pool has a
- * header with a link to the next pool of the same class.
- * Small and large pool headers are identical except that the latter's
- * link pointer must be FAR on 80x86 machines.
- * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE
- * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple
- * of the alignment requirement of ALIGN_TYPE.
- */
-
-typedef union small_pool_struct * small_pool_ptr;
-
-typedef union small_pool_struct {
- struct {
- small_pool_ptr next; /* next in list of pools */
- size_t bytes_used; /* how many bytes already used within pool */
- size_t bytes_left; /* bytes still available in this pool */
- } hdr;
- ALIGN_TYPE dummy; /* included in union to ensure alignment */
-} small_pool_hdr;
-
-typedef union large_pool_struct FAR * large_pool_ptr;
-
-typedef union large_pool_struct {
- struct {
- large_pool_ptr next; /* next in list of pools */
- size_t bytes_used; /* how many bytes already used within pool */
- size_t bytes_left; /* bytes still available in this pool */
- } hdr;
- ALIGN_TYPE dummy; /* included in union to ensure alignment */
-} large_pool_hdr;
-
-
-/*
- * Here is the full definition of a memory manager object.
- */
-
-typedef struct {
- struct jpeg_memory_mgr pub; /* public fields */
-
- /* Each pool identifier (lifetime class) names a linked list of pools. */
- small_pool_ptr small_list[JPOOL_NUMPOOLS];
- large_pool_ptr large_list[JPOOL_NUMPOOLS];
-
- /* Since we only have one lifetime class of virtual arrays, only one
- * linked list is necessary (for each datatype). Note that the virtual
- * array control blocks being linked together are actually stored somewhere
- * in the small-pool list.
- */
- jvirt_sarray_ptr virt_sarray_list;
- jvirt_barray_ptr virt_barray_list;
-
- /* This counts total space obtained from jpeg_get_small/large */
- long total_space_allocated;
-
- /* alloc_sarray and alloc_barray set this value for use by virtual
- * array routines.
- */
- JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */
-} my_memory_mgr;
-
-typedef my_memory_mgr * my_mem_ptr;
-
-
-/*
- * The control blocks for virtual arrays.
- * Note that these blocks are allocated in the "small" pool area.
- * System-dependent info for the associated backing store (if any) is hidden
- * inside the backing_store_info struct.
- */
-
-struct jvirt_sarray_control {
- JSAMPARRAY mem_buffer; /* => the in-memory buffer */
- JDIMENSION rows_in_array; /* total virtual array height */
- JDIMENSION samplesperrow; /* width of array (and of memory buffer) */
- JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */
- JDIMENSION rows_in_mem; /* height of memory buffer */
- JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */
- JDIMENSION cur_start_row; /* first logical row # in the buffer */
- JDIMENSION first_undef_row; /* row # of first uninitialized row */
- boolean pre_zero; /* pre-zero mode requested? */
- boolean dirty; /* do current buffer contents need written? */
- boolean b_s_open; /* is backing-store data valid? */
- jvirt_sarray_ptr next; /* link to next virtual sarray control block */
- backing_store_info b_s_info; /* System-dependent control info */
-};
-
-struct jvirt_barray_control {
- JBLOCKARRAY mem_buffer; /* => the in-memory buffer */
- JDIMENSION rows_in_array; /* total virtual array height */
- JDIMENSION blocksperrow; /* width of array (and of memory buffer) */
- JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */
- JDIMENSION rows_in_mem; /* height of memory buffer */
- JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */
- JDIMENSION cur_start_row; /* first logical row # in the buffer */
- JDIMENSION first_undef_row; /* row # of first uninitialized row */
- boolean pre_zero; /* pre-zero mode requested? */
- boolean dirty; /* do current buffer contents need written? */
- boolean b_s_open; /* is backing-store data valid? */
- jvirt_barray_ptr next; /* link to next virtual barray control block */
- backing_store_info b_s_info; /* System-dependent control info */
-};
-
-
-#ifdef MEM_STATS /* optional extra stuff for statistics */
-
-LOCAL(void)
-print_mem_stats (j_common_ptr cinfo, int pool_id)
-{
- my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
- small_pool_ptr shdr_ptr;
- large_pool_ptr lhdr_ptr;
-
- /* Since this is only a debugging stub, we can cheat a little by using
- * fprintf directly rather than going through the trace message code.
- * This is helpful because message parm array can't handle longs.
- */
- fprintf(stderr, "Freeing pool %d, total space = %ld\n",
- pool_id, mem->total_space_allocated);
-
- for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL;
- lhdr_ptr = lhdr_ptr->hdr.next) {
- fprintf(stderr, " Large chunk used %ld\n",
- (long) lhdr_ptr->hdr.bytes_used);
- }
-
- for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL;
- shdr_ptr = shdr_ptr->hdr.next) {
- fprintf(stderr, " Small chunk used %ld free %ld\n",
- (long) shdr_ptr->hdr.bytes_used,
- (long) shdr_ptr->hdr.bytes_left);
- }
-}
-
-#endif /* MEM_STATS */
-
-
-LOCAL(void)
-out_of_memory (j_common_ptr cinfo, int which)
-/* Report an out-of-memory error and stop execution */
-/* If we compiled MEM_STATS support, report alloc requests before dying */
-{
-#ifdef MEM_STATS
- cinfo->err->trace_level = 2; /* force self_destruct to report stats */
-#endif
- ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which);
-}
-
-
-/*
- * Allocation of "small" objects.
- *
- * For these, we use pooled storage. When a new pool must be created,
- * we try to get enough space for the current request plus a "slop" factor,
- * where the slop will be the amount of leftover space in the new pool.
- * The speed vs. space tradeoff is largely determined by the slop values.
- * A different slop value is provided for each pool class (lifetime),
- * and we also distinguish the first pool of a class from later ones.
- * NOTE: the values given work fairly well on both 16- and 32-bit-int
- * machines, but may be too small if longs are 64 bits or more.
- */
-
-static const size_t first_pool_slop[JPOOL_NUMPOOLS] =
-{
- 1600, /* first PERMANENT pool */
- 16000 /* first IMAGE pool */
-};
-
-static const size_t extra_pool_slop[JPOOL_NUMPOOLS] =
-{
- 0, /* additional PERMANENT pools */
- 5000 /* additional IMAGE pools */
-};
-
-#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */
-
-
-METHODDEF(void *)
-alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject)
-/* Allocate a "small" object */
-{
- my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
- small_pool_ptr hdr_ptr, prev_hdr_ptr;
- char * data_ptr;
- size_t odd_bytes, min_request, slop;
-
- /* Check for unsatisfiable request (do now to ensure no overflow below) */
- if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr)))
- out_of_memory(cinfo, 1); /* request exceeds malloc's ability */
-
- /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */
- odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);
- if (odd_bytes > 0)
- sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;
-
- /* See if space is available in any existing pool */
- if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
- ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
- prev_hdr_ptr = NULL;
- hdr_ptr = mem->small_list[pool_id];
- while (hdr_ptr != NULL) {
- if (hdr_ptr->hdr.bytes_left >= sizeofobject)
- break; /* found pool with enough space */
- prev_hdr_ptr = hdr_ptr;
- hdr_ptr = hdr_ptr->hdr.next;
- }
-
- /* Time to make a new pool? */
- if (hdr_ptr == NULL) {
- /* min_request is what we need now, slop is what will be leftover */
- min_request = sizeofobject + SIZEOF(small_pool_hdr);
- if (prev_hdr_ptr == NULL) /* first pool in class? */
- slop = first_pool_slop[pool_id];
- else
- slop = extra_pool_slop[pool_id];
- /* Don't ask for more than MAX_ALLOC_CHUNK */
- if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request))
- slop = (size_t) (MAX_ALLOC_CHUNK-min_request);
- /* Try to get space, if fail reduce slop and try again */
- for (;;) {
- hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop);
- if (hdr_ptr != NULL)
- break;
- slop /= 2;
- if (slop < MIN_SLOP) /* give up when it gets real small */
- out_of_memory(cinfo, 2); /* jpeg_get_small failed */
- }
- mem->total_space_allocated += min_request + slop;
- /* Success, initialize the new pool header and add to end of list */
- hdr_ptr->hdr.next = NULL;
- hdr_ptr->hdr.bytes_used = 0;
- hdr_ptr->hdr.bytes_left = sizeofobject + slop;
- if (prev_hdr_ptr == NULL) /* first pool in class? */
- mem->small_list[pool_id] = hdr_ptr;
- else
- prev_hdr_ptr->hdr.next = hdr_ptr;
- }
-
- /* OK, allocate the object from the current pool */
- data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */
- data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */
- hdr_ptr->hdr.bytes_used += sizeofobject;
- hdr_ptr->hdr.bytes_left -= sizeofobject;
-
- return (void *) data_ptr;
-}
-
-
-/*
- * Allocation of "large" objects.
- *
- * The external semantics of these are the same as "small" objects,
- * except that FAR pointers are used on 80x86. However the pool
- * management heuristics are quite different. We assume that each
- * request is large enough that it may as well be passed directly to
- * jpeg_get_large; the pool management just links everything together
- * so that we can free it all on demand.
- * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY
- * structures. The routines that create these structures (see below)
- * deliberately bunch rows together to ensure a large request size.
- */
-
-METHODDEF(void FAR *)
-alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject)
-/* Allocate a "large" object */
-{
- my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
- large_pool_ptr hdr_ptr;
- size_t odd_bytes;
-
- /* Check for unsatisfiable request (do now to ensure no overflow below) */
- if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)))
- out_of_memory(cinfo, 3); /* request exceeds malloc's ability */
-
- /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */
- odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);
- if (odd_bytes > 0)
- sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;
-
- /* Always make a new pool */
- if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
- ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
-
- hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject +
- SIZEOF(large_pool_hdr));
- if (hdr_ptr == NULL)
- out_of_memory(cinfo, 4); /* jpeg_get_large failed */
- mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr);
-
- /* Success, initialize the new pool header and add to list */
- hdr_ptr->hdr.next = mem->large_list[pool_id];
- /* We maintain space counts in each pool header for statistical purposes,
- * even though they are not needed for allocation.
- */
- hdr_ptr->hdr.bytes_used = sizeofobject;
- hdr_ptr->hdr.bytes_left = 0;
- mem->large_list[pool_id] = hdr_ptr;
-
- return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */
-}
-
-
-/*
- * Creation of 2-D sample arrays.
- * The pointers are in near heap, the samples themselves in FAR heap.
- *
- * To minimize allocation overhead and to allow I/O of large contiguous
- * blocks, we allocate the sample rows in groups of as many rows as possible
- * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.
- * NB: the virtual array control routines, later in this file, know about
- * this chunking of rows. The rowsperchunk value is left in the mem manager
- * object so that it can be saved away if this sarray is the workspace for
- * a virtual array.
- */
-
-METHODDEF(JSAMPARRAY)
-alloc_sarray (j_common_ptr cinfo, int pool_id,
- JDIMENSION samplesperrow, JDIMENSION numrows)
-/* Allocate a 2-D sample array */
-{
- my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
- JSAMPARRAY result;
- JSAMPROW workspace;
- JDIMENSION rowsperchunk, currow, i;
- long ltemp;
-
- /* Calculate max # of rows allowed in one allocation chunk */
- ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
- ((long) samplesperrow * SIZEOF(JSAMPLE));
- if (ltemp <= 0)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
- if (ltemp < (long) numrows)
- rowsperchunk = (JDIMENSION) ltemp;
- else
- rowsperchunk = numrows;
- mem->last_rowsperchunk = rowsperchunk;
-
- /* Get space for row pointers (small object) */
- result = (JSAMPARRAY) alloc_small(cinfo, pool_id,
- (size_t) (numrows * SIZEOF(JSAMPROW)));
-
- /* Get the rows themselves (large objects) */
- currow = 0;
- while (currow < numrows) {
- rowsperchunk = MIN(rowsperchunk, numrows - currow);
- workspace = (JSAMPROW) alloc_large(cinfo, pool_id,
- (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow
- * SIZEOF(JSAMPLE)));
- for (i = rowsperchunk; i > 0; i--) {
- result[currow++] = workspace;
- workspace += samplesperrow;
- }
- }
-
- return result;
-}
-
-
-/*
- * Creation of 2-D coefficient-block arrays.
- * This is essentially the same as the code for sample arrays, above.
- */
-
-METHODDEF(JBLOCKARRAY)
-alloc_barray (j_common_ptr cinfo, int pool_id,
- JDIMENSION blocksperrow, JDIMENSION numrows)
-/* Allocate a 2-D coefficient-block array */
-{
- my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
- JBLOCKARRAY result;
- JBLOCKROW workspace;
- JDIMENSION rowsperchunk, currow, i;
- long ltemp;
-
- /* Calculate max # of rows allowed in one allocation chunk */
- ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
- ((long) blocksperrow * SIZEOF(JBLOCK));
- if (ltemp <= 0)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
- if (ltemp < (long) numrows)
- rowsperchunk = (JDIMENSION) ltemp;
- else
- rowsperchunk = numrows;
- mem->last_rowsperchunk = rowsperchunk;
-
- /* Get space for row pointers (small object) */
- result = (JBLOCKARRAY) alloc_small(cinfo, pool_id,
- (size_t) (numrows * SIZEOF(JBLOCKROW)));
-
- /* Get the rows themselves (large objects) */
- currow = 0;
- while (currow < numrows) {
- rowsperchunk = MIN(rowsperchunk, numrows - currow);
- workspace = (JBLOCKROW) alloc_large(cinfo, pool_id,
- (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow
- * SIZEOF(JBLOCK)));
- for (i = rowsperchunk; i > 0; i--) {
- result[currow++] = workspace;
- workspace += blocksperrow;
- }
- }
-
- return result;
-}
-
-
-/*
- * About virtual array management:
- *
- * The above "normal" array routines are only used to allocate strip buffers
- * (as wide as the image, but just a few rows high). Full-image-sized buffers
- * are handled as "virtual" arrays. The array is still accessed a strip at a
- * time, but the memory manager must save the whole array for repeated
- * accesses. The intended implementation is that there is a strip buffer in
- * memory (as high as is possible given the desired memory limit), plus a
- * backing file that holds the rest of the array.
- *
- * The request_virt_array routines are told the total size of the image and
- * the maximum number of rows that will be accessed at once. The in-memory
- * buffer must be at least as large as the maxaccess value.
- *
- * The request routines create control blocks but not the in-memory buffers.
- * That is postponed until realize_virt_arrays is called. At that time the
- * total amount of space needed is known (approximately, anyway), so free
- * memory can be divided up fairly.
- *
- * The access_virt_array routines are responsible for making a specific strip
- * area accessible (after reading or writing the backing file, if necessary).
- * Note that the access routines are told whether the caller intends to modify
- * the accessed strip; during a read-only pass this saves having to rewrite
- * data to disk. The access routines are also responsible for pre-zeroing
- * any newly accessed rows, if pre-zeroing was requested.
- *
- * In current usage, the access requests are usually for nonoverlapping
- * strips; that is, successive access start_row numbers differ by exactly
- * num_rows = maxaccess. This means we can get good performance with simple
- * buffer dump/reload logic, by making the in-memory buffer be a multiple
- * of the access height; then there will never be accesses across bufferload
- * boundaries. The code will still work with overlapping access requests,
- * but it doesn't handle bufferload overlaps very efficiently.
- */
-
-
-METHODDEF(jvirt_sarray_ptr)
-request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero,
- JDIMENSION samplesperrow, JDIMENSION numrows,
- JDIMENSION maxaccess)
-/* Request a virtual 2-D sample array */
-{
- my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
- jvirt_sarray_ptr result;
-
- /* Only IMAGE-lifetime virtual arrays are currently supported */
- if (pool_id != JPOOL_IMAGE)
- ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
-
- /* get control block */
- result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id,
- SIZEOF(struct jvirt_sarray_control));
-
- result->mem_buffer = NULL; /* marks array not yet realized */
- result->rows_in_array = numrows;
- result->samplesperrow = samplesperrow;
- result->maxaccess = maxaccess;
- result->pre_zero = pre_zero;
- result->b_s_open = FALSE; /* no associated backing-store object */
- result->next = mem->virt_sarray_list; /* add to list of virtual arrays */
- mem->virt_sarray_list = result;
-
- return result;
-}
-
-
-METHODDEF(jvirt_barray_ptr)
-request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero,
- JDIMENSION blocksperrow, JDIMENSION numrows,
- JDIMENSION maxaccess)
-/* Request a virtual 2-D coefficient-block array */
-{
- my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
- jvirt_barray_ptr result;
-
- /* Only IMAGE-lifetime virtual arrays are currently supported */
- if (pool_id != JPOOL_IMAGE)
- ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
-
- /* get control block */
- result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id,
- SIZEOF(struct jvirt_barray_control));
-
- result->mem_buffer = NULL; /* marks array not yet realized */
- result->rows_in_array = numrows;
- result->blocksperrow = blocksperrow;
- result->maxaccess = maxaccess;
- result->pre_zero = pre_zero;
- result->b_s_open = FALSE; /* no associated backing-store object */
- result->next = mem->virt_barray_list; /* add to list of virtual arrays */
- mem->virt_barray_list = result;
-
- return result;
-}
-
-
-METHODDEF(void)
-realize_virt_arrays (j_common_ptr cinfo)
-/* Allocate the in-memory buffers for any unrealized virtual arrays */
-{
- my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
- long space_per_minheight, maximum_space, avail_mem;
- long minheights, max_minheights;
- jvirt_sarray_ptr sptr;
- jvirt_barray_ptr bptr;
-
- /* Compute the minimum space needed (maxaccess rows in each buffer)
- * and the maximum space needed (full image height in each buffer).
- * These may be of use to the system-dependent jpeg_mem_available routine.
- */
- space_per_minheight = 0;
- maximum_space = 0;
- for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
- if (sptr->mem_buffer == NULL) { /* if not realized yet */
- space_per_minheight += (long) sptr->maxaccess *
- (long) sptr->samplesperrow * SIZEOF(JSAMPLE);
- maximum_space += (long) sptr->rows_in_array *
- (long) sptr->samplesperrow * SIZEOF(JSAMPLE);
- }
- }
- for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
- if (bptr->mem_buffer == NULL) { /* if not realized yet */
- space_per_minheight += (long) bptr->maxaccess *
- (long) bptr->blocksperrow * SIZEOF(JBLOCK);
- maximum_space += (long) bptr->rows_in_array *
- (long) bptr->blocksperrow * SIZEOF(JBLOCK);
- }
- }
-
- if (space_per_minheight <= 0)
- return; /* no unrealized arrays, no work */
-
- /* Determine amount of memory to actually use; this is system-dependent. */
- avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space,
- mem->total_space_allocated);
-
- /* If the maximum space needed is available, make all the buffers full
- * height; otherwise parcel it out with the same number of minheights
- * in each buffer.
- */
- if (avail_mem >= maximum_space)
- max_minheights = 1000000000L;
- else {
- max_minheights = avail_mem / space_per_minheight;
- /* If there doesn't seem to be enough space, try to get the minimum
- * anyway. This allows a "stub" implementation of jpeg_mem_available().
- */
- if (max_minheights <= 0)
- max_minheights = 1;
- }
-
- /* Allocate the in-memory buffers and initialize backing store as needed. */
-
- for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
- if (sptr->mem_buffer == NULL) { /* if not realized yet */
- minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L;
- if (minheights <= max_minheights) {
- /* This buffer fits in memory */
- sptr->rows_in_mem = sptr->rows_in_array;
- } else {
- /* It doesn't fit in memory, create backing store. */
- sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess);
- jpeg_open_backing_store(cinfo, & sptr->b_s_info,
- (long) sptr->rows_in_array *
- (long) sptr->samplesperrow *
- (long) SIZEOF(JSAMPLE));
- sptr->b_s_open = TRUE;
- }
- sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE,
- sptr->samplesperrow, sptr->rows_in_mem);
- sptr->rowsperchunk = mem->last_rowsperchunk;
- sptr->cur_start_row = 0;
- sptr->first_undef_row = 0;
- sptr->dirty = FALSE;
- }
- }
-
- for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
- if (bptr->mem_buffer == NULL) { /* if not realized yet */
- minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L;
- if (minheights <= max_minheights) {
- /* This buffer fits in memory */
- bptr->rows_in_mem = bptr->rows_in_array;
- } else {
- /* It doesn't fit in memory, create backing store. */
- bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess);
- jpeg_open_backing_store(cinfo, & bptr->b_s_info,
- (long) bptr->rows_in_array *
- (long) bptr->blocksperrow *
- (long) SIZEOF(JBLOCK));
- bptr->b_s_open = TRUE;
- }
- bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE,
- bptr->blocksperrow, bptr->rows_in_mem);
- bptr->rowsperchunk = mem->last_rowsperchunk;
- bptr->cur_start_row = 0;
- bptr->first_undef_row = 0;
- bptr->dirty = FALSE;
- }
- }
-}
-
-
-LOCAL(void)
-do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)
-/* Do backing store read or write of a virtual sample array */
-{
- long bytesperrow, file_offset, byte_count, rows, thisrow, i;
-
- bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE);
- file_offset = ptr->cur_start_row * bytesperrow;
- /* Loop to read or write each allocation chunk in mem_buffer */
- for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {
- /* One chunk, but check for short chunk at end of buffer */
- rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);
- /* Transfer no more than is currently defined */
- thisrow = (long) ptr->cur_start_row + i;
- rows = MIN(rows, (long) ptr->first_undef_row - thisrow);
- /* Transfer no more than fits in file */
- rows = MIN(rows, (long) ptr->rows_in_array - thisrow);
- if (rows <= 0) /* this chunk might be past end of file! */
- break;
- byte_count = rows * bytesperrow;
- if (writing)
- (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,
- (void FAR *) ptr->mem_buffer[i],
- file_offset, byte_count);
- else
- (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,
- (void FAR *) ptr->mem_buffer[i],
- file_offset, byte_count);
- file_offset += byte_count;
- }
-}
-
-
-LOCAL(void)
-do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing)
-/* Do backing store read or write of a virtual coefficient-block array */
-{
- long bytesperrow, file_offset, byte_count, rows, thisrow, i;
-
- bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK);
- file_offset = ptr->cur_start_row * bytesperrow;
- /* Loop to read or write each allocation chunk in mem_buffer */
- for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {
- /* One chunk, but check for short chunk at end of buffer */
- rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);
- /* Transfer no more than is currently defined */
- thisrow = (long) ptr->cur_start_row + i;
- rows = MIN(rows, (long) ptr->first_undef_row - thisrow);
- /* Transfer no more than fits in file */
- rows = MIN(rows, (long) ptr->rows_in_array - thisrow);
- if (rows <= 0) /* this chunk might be past end of file! */
- break;
- byte_count = rows * bytesperrow;
- if (writing)
- (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,
- (void FAR *) ptr->mem_buffer[i],
- file_offset, byte_count);
- else
- (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,
- (void FAR *) ptr->mem_buffer[i],
- file_offset, byte_count);
- file_offset += byte_count;
- }
-}
-
-
-METHODDEF(JSAMPARRAY)
-access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr,
- JDIMENSION start_row, JDIMENSION num_rows,
- boolean writable)
-/* Access the part of a virtual sample array starting at start_row */
-/* and extending for num_rows rows. writable is true if */
-/* caller intends to modify the accessed area. */
-{
- JDIMENSION end_row = start_row + num_rows;
- JDIMENSION undef_row;
-
- /* debugging check */
- if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
- ptr->mem_buffer == NULL)
- ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
-
- /* Make the desired part of the virtual array accessible */
- if (start_row < ptr->cur_start_row ||
- end_row > ptr->cur_start_row+ptr->rows_in_mem) {
- if (! ptr->b_s_open)
- ERREXIT(cinfo, JERR_VIRTUAL_BUG);
- /* Flush old buffer contents if necessary */
- if (ptr->dirty) {
- do_sarray_io(cinfo, ptr, TRUE);
- ptr->dirty = FALSE;
- }
- /* Decide what part of virtual array to access.
- * Algorithm: if target address > current window, assume forward scan,
- * load starting at target address. If target address < current window,
- * assume backward scan, load so that target area is top of window.
- * Note that when switching from forward write to forward read, will have
- * start_row = 0, so the limiting case applies and we load from 0 anyway.
- */
- if (start_row > ptr->cur_start_row) {
- ptr->cur_start_row = start_row;
- } else {
- /* use long arithmetic here to avoid overflow & unsigned problems */
- long ltemp;
-
- ltemp = (long) end_row - (long) ptr->rows_in_mem;
- if (ltemp < 0)
- ltemp = 0; /* don't fall off front end of file */
- ptr->cur_start_row = (JDIMENSION) ltemp;
- }
- /* Read in the selected part of the array.
- * During the initial write pass, we will do no actual read
- * because the selected part is all undefined.
- */
- do_sarray_io(cinfo, ptr, FALSE);
- }
- /* Ensure the accessed part of the array is defined; prezero if needed.
- * To improve locality of access, we only prezero the part of the array
- * that the caller is about to access, not the entire in-memory array.
- */
- if (ptr->first_undef_row < end_row) {
- if (ptr->first_undef_row < start_row) {
- if (writable) /* writer skipped over a section of array */
- ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
- undef_row = start_row; /* but reader is allowed to read ahead */
- } else {
- undef_row = ptr->first_undef_row;
- }
- if (writable)
- ptr->first_undef_row = end_row;
- if (ptr->pre_zero) {
- size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE);
- undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
- end_row -= ptr->cur_start_row;
- while (undef_row < end_row) {
- jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);
- undef_row++;
- }
- } else {
- if (! writable) /* reader looking at undefined data */
- ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
- }
- }
- /* Flag the buffer dirty if caller will write in it */
- if (writable)
- ptr->dirty = TRUE;
- /* Return address of proper part of the buffer */
- return ptr->mem_buffer + (start_row - ptr->cur_start_row);
-}
-
-
-METHODDEF(JBLOCKARRAY)
-access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr,
- JDIMENSION start_row, JDIMENSION num_rows,
- boolean writable)
-/* Access the part of a virtual block array starting at start_row */
-/* and extending for num_rows rows. writable is true if */
-/* caller intends to modify the accessed area. */
-{
- JDIMENSION end_row = start_row + num_rows;
- JDIMENSION undef_row;
-
- /* debugging check */
- if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
- ptr->mem_buffer == NULL)
- ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
-
- /* Make the desired part of the virtual array accessible */
- if (start_row < ptr->cur_start_row ||
- end_row > ptr->cur_start_row+ptr->rows_in_mem) {
- if (! ptr->b_s_open)
- ERREXIT(cinfo, JERR_VIRTUAL_BUG);
- /* Flush old buffer contents if necessary */
- if (ptr->dirty) {
- do_barray_io(cinfo, ptr, TRUE);
- ptr->dirty = FALSE;
- }
- /* Decide what part of virtual array to access.
- * Algorithm: if target address > current window, assume forward scan,
- * load starting at target address. If target address < current window,
- * assume backward scan, load so that target area is top of window.
- * Note that when switching from forward write to forward read, will have
- * start_row = 0, so the limiting case applies and we load from 0 anyway.
- */
- if (start_row > ptr->cur_start_row) {
- ptr->cur_start_row = start_row;
- } else {
- /* use long arithmetic here to avoid overflow & unsigned problems */
- long ltemp;
-
- ltemp = (long) end_row - (long) ptr->rows_in_mem;
- if (ltemp < 0)
- ltemp = 0; /* don't fall off front end of file */
- ptr->cur_start_row = (JDIMENSION) ltemp;
- }
- /* Read in the selected part of the array.
- * During the initial write pass, we will do no actual read
- * because the selected part is all undefined.
- */
- do_barray_io(cinfo, ptr, FALSE);
- }
- /* Ensure the accessed part of the array is defined; prezero if needed.
- * To improve locality of access, we only prezero the part of the array
- * that the caller is about to access, not the entire in-memory array.
- */
- if (ptr->first_undef_row < end_row) {
- if (ptr->first_undef_row < start_row) {
- if (writable) /* writer skipped over a section of array */
- ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
- undef_row = start_row; /* but reader is allowed to read ahead */
- } else {
- undef_row = ptr->first_undef_row;
- }
- if (writable)
- ptr->first_undef_row = end_row;
- if (ptr->pre_zero) {
- size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK);
- undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
- end_row -= ptr->cur_start_row;
- while (undef_row < end_row) {
- jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);
- undef_row++;
- }
- } else {
- if (! writable) /* reader looking at undefined data */
- ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
- }
- }
- /* Flag the buffer dirty if caller will write in it */
- if (writable)
- ptr->dirty = TRUE;
- /* Return address of proper part of the buffer */
- return ptr->mem_buffer + (start_row - ptr->cur_start_row);
-}
-
-
-/*
- * Release all objects belonging to a specified pool.
- */
-
-METHODDEF(void)
-free_pool (j_common_ptr cinfo, int pool_id)
-{
- my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
- small_pool_ptr shdr_ptr;
- large_pool_ptr lhdr_ptr;
- size_t space_freed;
-
- if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
- ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
-
-#ifdef MEM_STATS
- if (cinfo->err->trace_level > 1)
- print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */
-#endif
-
- /* If freeing IMAGE pool, close any virtual arrays first */
- if (pool_id == JPOOL_IMAGE) {
- jvirt_sarray_ptr sptr;
- jvirt_barray_ptr bptr;
-
- for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
- if (sptr->b_s_open) { /* there may be no backing store */
- sptr->b_s_open = FALSE; /* prevent recursive close if error */
- (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info);
- }
- }
- mem->virt_sarray_list = NULL;
- for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
- if (bptr->b_s_open) { /* there may be no backing store */
- bptr->b_s_open = FALSE; /* prevent recursive close if error */
- (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info);
- }
- }
- mem->virt_barray_list = NULL;
- }
-
- /* Release large objects */
- lhdr_ptr = mem->large_list[pool_id];
- mem->large_list[pool_id] = NULL;
-
- while (lhdr_ptr != NULL) {
- large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next;
- space_freed = lhdr_ptr->hdr.bytes_used +
- lhdr_ptr->hdr.bytes_left +
- SIZEOF(large_pool_hdr);
- jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed);
- mem->total_space_allocated -= space_freed;
- lhdr_ptr = next_lhdr_ptr;
- }
-
- /* Release small objects */
- shdr_ptr = mem->small_list[pool_id];
- mem->small_list[pool_id] = NULL;
-
- while (shdr_ptr != NULL) {
- small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next;
- space_freed = shdr_ptr->hdr.bytes_used +
- shdr_ptr->hdr.bytes_left +
- SIZEOF(small_pool_hdr);
- jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed);
- mem->total_space_allocated -= space_freed;
- shdr_ptr = next_shdr_ptr;
- }
-}
-
-
-/*
- * Close up shop entirely.
- * Note that this cannot be called unless cinfo->mem is non-NULL.
- */
-
-METHODDEF(void)
-self_destruct (j_common_ptr cinfo)
-{
- int pool;
-
- /* Close all backing store, release all memory.
- * Releasing pools in reverse order might help avoid fragmentation
- * with some (brain-damaged) malloc libraries.
- */
- for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {
- free_pool(cinfo, pool);
- }
-
- /* Release the memory manager control block too. */
- jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr));
- cinfo->mem = NULL; /* ensures I will be called only once */
-
- jpeg_mem_term(cinfo); /* system-dependent cleanup */
-}
-
-
-/*
- * Memory manager initialization.
- * When this is called, only the error manager pointer is valid in cinfo!
- */
-
-GLOBAL(void)
-jinit_memory_mgr (j_common_ptr cinfo)
-{
- my_mem_ptr mem;
- long max_to_use;
- int pool;
- size_t test_mac;
-
- cinfo->mem = NULL; /* for safety if init fails */
-
- /* Check for configuration errors.
- * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably
- * doesn't reflect any real hardware alignment requirement.
- * The test is a little tricky: for X>0, X and X-1 have no one-bits
- * in common if and only if X is a power of 2, ie has only one one-bit.
- * Some compilers may give an "unreachable code" warning here; ignore it.
- */
- if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0)
- ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE);
- /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be
- * a multiple of SIZEOF(ALIGN_TYPE).
- * Again, an "unreachable code" warning may be ignored here.
- * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK.
- */
- test_mac = (size_t) MAX_ALLOC_CHUNK;
- if ((long) test_mac != MAX_ALLOC_CHUNK ||
- (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0)
- ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
-
- max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */
-
- /* Attempt to allocate memory manager's control block */
- mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr));
-
- if (mem == NULL) {
- jpeg_mem_term(cinfo); /* system-dependent cleanup */
- ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0);
- }
-
- /* OK, fill in the method pointers */
- mem->pub.alloc_small = alloc_small;
- mem->pub.alloc_large = alloc_large;
- mem->pub.alloc_sarray = alloc_sarray;
- mem->pub.alloc_barray = alloc_barray;
- mem->pub.request_virt_sarray = request_virt_sarray;
- mem->pub.request_virt_barray = request_virt_barray;
- mem->pub.realize_virt_arrays = realize_virt_arrays;
- mem->pub.access_virt_sarray = access_virt_sarray;
- mem->pub.access_virt_barray = access_virt_barray;
- mem->pub.free_pool = free_pool;
- mem->pub.self_destruct = self_destruct;
-
- /* Make MAX_ALLOC_CHUNK accessible to other modules */
- mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK;
-
- /* Initialize working state */
- mem->pub.max_memory_to_use = max_to_use;
-
- for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {
- mem->small_list[pool] = NULL;
- mem->large_list[pool] = NULL;
- }
- mem->virt_sarray_list = NULL;
- mem->virt_barray_list = NULL;
-
- mem->total_space_allocated = SIZEOF(my_memory_mgr);
-
- /* Declare ourselves open for business */
- cinfo->mem = & mem->pub;
-
- /* Check for an environment variable JPEGMEM; if found, override the
- * default max_memory setting from jpeg_mem_init. Note that the
- * surrounding application may again override this value.
- * If your system doesn't support getenv(), define NO_GETENV to disable
- * this feature.
- */
-#ifndef NO_GETENV
- { char * memenv;
-
- if ((memenv = getenv("JPEGMEM")) != NULL) {
- char ch = 'x';
-
- if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) {
- if (ch == 'm' || ch == 'M')
- max_to_use *= 1000L;
- mem->pub.max_memory_to_use = max_to_use * 1000L;
- }
- }
- }
-#endif
-
-}
diff --git a/engine/code/jpeg-6b/jmemname.c b/engine/code/jpeg-6b/jmemname.c
deleted file mode 100644
index ed96dee..0000000
--- a/engine/code/jpeg-6b/jmemname.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * jmemname.c
- *
- * Copyright (C) 1992-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file provides a generic implementation of the system-dependent
- * portion of the JPEG memory manager. This implementation assumes that
- * you must explicitly construct a name for each temp file.
- * Also, the problem of determining the amount of memory available
- * is shoved onto the user.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jmemsys.h" /* import the system-dependent declarations */
-
-#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
-extern void * malloc JPP((size_t size));
-extern void free JPP((void *ptr));
-#endif
-
-#ifndef SEEK_SET /* pre-ANSI systems may not define this; */
-#define SEEK_SET 0 /* if not, assume 0 is correct */
-#endif
-
-#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
-#define READ_BINARY "r"
-#define RW_BINARY "w+"
-#else
-#ifdef VMS /* VMS is very nonstandard */
-#define READ_BINARY "rb", "ctx=stm"
-#define RW_BINARY "w+b", "ctx=stm"
-#else /* standard ANSI-compliant case */
-#define READ_BINARY "rb"
-#define RW_BINARY "w+b"
-#endif
-#endif
-
-
-/*
- * Selection of a file name for a temporary file.
- * This is system-dependent!
- *
- * The code as given is suitable for most Unix systems, and it is easily
- * modified for most non-Unix systems. Some notes:
- * 1. The temp file is created in the directory named by TEMP_DIRECTORY.
- * The default value is /usr/tmp, which is the conventional place for
- * creating large temp files on Unix. On other systems you'll probably
- * want to change the file location. You can do this by editing the
- * #define, or (preferred) by defining TEMP_DIRECTORY in jconfig.h.
- *
- * 2. If you need to change the file name as well as its location,
- * you can override the TEMP_FILE_NAME macro. (Note that this is
- * actually a printf format string; it must contain %s and %d.)
- * Few people should need to do this.
- *
- * 3. mktemp() is used to ensure that multiple processes running
- * simultaneously won't select the same file names. If your system
- * doesn't have mktemp(), define NO_MKTEMP to do it the hard way.
- * (If you don't have <errno.h>, also define NO_ERRNO_H.)
- *
- * 4. You probably want to define NEED_SIGNAL_CATCHER so that cjpeg.c/djpeg.c
- * will cause the temp files to be removed if you stop the program early.
- */
-
-#ifndef TEMP_DIRECTORY /* can override from jconfig.h or Makefile */
-#define TEMP_DIRECTORY "/usr/tmp/" /* recommended setting for Unix */
-#endif
-
-static int next_file_num; /* to distinguish among several temp files */
-
-#ifdef NO_MKTEMP
-
-#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */
-#define TEMP_FILE_NAME "%sJPG%03d.TMP"
-#endif
-
-#ifndef NO_ERRNO_H
-#include <errno.h> /* to define ENOENT */
-#endif
-
-/* ANSI C specifies that errno is a macro, but on older systems it's more
- * likely to be a plain int variable. And not all versions of errno.h
- * bother to declare it, so we have to in order to be most portable. Thus:
- */
-#ifndef errno
-extern int errno;
-#endif
-
-
-LOCAL(void)
-select_file_name (char * fname)
-{
- FILE * tfile;
-
- /* Keep generating file names till we find one that's not in use */
- for (;;) {
- next_file_num++; /* advance counter */
- sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num);
- if ((tfile = fopen(fname, READ_BINARY)) == NULL) {
- /* fopen could have failed for a reason other than the file not
- * being there; for example, file there but unreadable.
- * If <errno.h> isn't available, then we cannot test the cause.
- */
-#ifdef ENOENT
- if (errno != ENOENT)
- continue;
-#endif
- break;
- }
- fclose(tfile); /* oops, it's there; close tfile & try again */
- }
-}
-
-#else /* ! NO_MKTEMP */
-
-/* Note that mktemp() requires the initial filename to end in six X's */
-#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */
-#define TEMP_FILE_NAME "%sJPG%dXXXXXX"
-#endif
-
-LOCAL(void)
-select_file_name (char * fname)
-{
- next_file_num++; /* advance counter */
- sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num);
- mktemp(fname); /* make sure file name is unique */
- /* mktemp replaces the trailing XXXXXX with a unique string of characters */
-}
-
-#endif /* NO_MKTEMP */
-
-
-/*
- * Memory allocation and freeing are controlled by the regular library
- * routines malloc() and free().
- */
-
-GLOBAL(void *)
-jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
-{
- return (void *) malloc(sizeofobject);
-}
-
-GLOBAL(void)
-jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
-{
- free(object);
-}
-
-
-/*
- * "Large" objects are treated the same as "small" ones.
- * NB: although we include FAR keywords in the routine declarations,
- * this file won't actually work in 80x86 small/medium model; at least,
- * you probably won't be able to process useful-size images in only 64KB.
- */
-
-GLOBAL(void FAR *)
-jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
-{
- return (void FAR *) malloc(sizeofobject);
-}
-
-GLOBAL(void)
-jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
-{
- free(object);
-}
-
-
-/*
- * This routine computes the total memory space available for allocation.
- * It's impossible to do this in a portable way; our current solution is
- * to make the user tell us (with a default value set at compile time).
- * If you can actually get the available space, it's a good idea to subtract
- * a slop factor of 5% or so.
- */
-
-#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
-#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */
-#endif
-
-GLOBAL(long)
-jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
- long max_bytes_needed, long already_allocated)
-{
- return cinfo->mem->max_memory_to_use - already_allocated;
-}
-
-
-/*
- * Backing store (temporary file) management.
- * Backing store objects are only used when the value returned by
- * jpeg_mem_available is less than the total space needed. You can dispense
- * with these routines if you have plenty of virtual memory; see jmemnobs.c.
- */
-
-
-METHODDEF(void)
-read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
- void FAR * buffer_address,
- long file_offset, long byte_count)
-{
- if (fseek(info->temp_file, file_offset, SEEK_SET))
- ERREXIT(cinfo, JERR_TFILE_SEEK);
- if (JFREAD(info->temp_file, buffer_address, byte_count)
- != (size_t) byte_count)
- ERREXIT(cinfo, JERR_TFILE_READ);
-}
-
-
-METHODDEF(void)
-write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
- void FAR * buffer_address,
- long file_offset, long byte_count)
-{
- if (fseek(info->temp_file, file_offset, SEEK_SET))
- ERREXIT(cinfo, JERR_TFILE_SEEK);
- if (JFWRITE(info->temp_file, buffer_address, byte_count)
- != (size_t) byte_count)
- ERREXIT(cinfo, JERR_TFILE_WRITE);
-}
-
-
-METHODDEF(void)
-close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
-{
- fclose(info->temp_file); /* close the file */
- unlink(info->temp_name); /* delete the file */
-/* If your system doesn't have unlink(), use remove() instead.
- * remove() is the ANSI-standard name for this function, but if
- * your system was ANSI you'd be using jmemansi.c, right?
- */
- TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name);
-}
-
-
-/*
- * Initial opening of a backing-store object.
- */
-
-GLOBAL(void)
-jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
- long total_bytes_needed)
-{
- select_file_name(info->temp_name);
- if ((info->temp_file = fopen(info->temp_name, RW_BINARY)) == NULL)
- ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
- info->read_backing_store = read_backing_store;
- info->write_backing_store = write_backing_store;
- info->close_backing_store = close_backing_store;
- TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
-}
-
-
-/*
- * These routines take care of any system-dependent initialization and
- * cleanup required.
- */
-
-GLOBAL(long)
-jpeg_mem_init (j_common_ptr cinfo)
-{
- next_file_num = 0; /* initialize temp file name generator */
- return DEFAULT_MAX_MEM; /* default for max_memory_to_use */
-}
-
-GLOBAL(void)
-jpeg_mem_term (j_common_ptr cinfo)
-{
- /* no work */
-}
diff --git a/engine/code/jpeg-6b/jmemnobs.c b/engine/code/jpeg-6b/jmemnobs.c
deleted file mode 100644
index cbd6081..0000000
--- a/engine/code/jpeg-6b/jmemnobs.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * jmemnobs.c
- *
- * Copyright (C) 1992-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file provides a really simple implementation of the system-
- * dependent portion of the JPEG memory manager. This implementation
- * assumes that no backing-store files are needed: all required space
- * can be obtained from ri.Malloc().
- * This is very portable in the sense that it'll compile on almost anything,
- * but you'd better have lots of main memory (or virtual memory) if you want
- * to process big images.
- * Note that the max_memory_to_use option is ignored by this implementation.
- */
-
-#include "../renderer/tr_local.h"
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jmemsys.h" /* import the system-dependent declarations */
-
-/*
- * Memory allocation and freeing are controlled by the regular library
- * routines ri.Malloc() and ri.Free().
- */
-
-GLOBAL(void *)
-jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
-{
- return (void *) ri.Malloc(sizeofobject);
-}
-
-GLOBAL(void)
-jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
-{
- ri.Free(object);
-}
-
-
-/*
- * "Large" objects are treated the same as "small" ones.
- * NB: although we include FAR keywords in the routine declarations,
- * this file won't actually work in 80x86 small/medium model; at least,
- * you probably won't be able to process useful-size images in only 64KB.
- */
-
-GLOBAL(void FAR *)
-jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
-{
- return (void FAR *) ri.Malloc(sizeofobject);
-}
-
-GLOBAL(void)
-jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
-{
- ri.Free(object);
-}
-
-
-/*
- * This routine computes the total memory space available for allocation.
- * Here we always say, "we got all you want bud!"
- */
-
-GLOBAL(long)
-jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
- long max_bytes_needed, long already_allocated)
-{
- return max_bytes_needed;
-}
-
-
-/*
- * Backing store (temporary file) management.
- * Since jpeg_mem_available always promised the moon,
- * this should never be called and we can just error out.
- */
-
-GLOBAL(void)
-jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
- long total_bytes_needed)
-{
- ERREXIT(cinfo, JERR_NO_BACKING_STORE);
-}
-
-
-/*
- * These routines take care of any system-dependent initialization and
- * cleanup required. Here, there isn't any.
- */
-
-GLOBAL(long)
-jpeg_mem_init (j_common_ptr cinfo)
-{
- return 0; /* just set max_memory_to_use to 0 */
-}
-
-GLOBAL(void)
-jpeg_mem_term (j_common_ptr cinfo)
-{
- /* no work */
-}
diff --git a/engine/code/jpeg-6b/jmemsys.h b/engine/code/jpeg-6b/jmemsys.h
deleted file mode 100644
index 6c3c6d3..0000000
--- a/engine/code/jpeg-6b/jmemsys.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * jmemsys.h
- *
- * Copyright (C) 1992-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This include file defines the interface between the system-independent
- * and system-dependent portions of the JPEG memory manager. No other
- * modules need include it. (The system-independent portion is jmemmgr.c;
- * there are several different versions of the system-dependent portion.)
- *
- * This file works as-is for the system-dependent memory managers supplied
- * in the IJG distribution. You may need to modify it if you write a
- * custom memory manager. If system-dependent changes are needed in
- * this file, the best method is to #ifdef them based on a configuration
- * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR
- * and USE_MAC_MEMMGR.
- */
-
-
-/* Short forms of external names for systems with brain-damaged linkers. */
-
-#ifdef NEED_SHORT_EXTERNAL_NAMES
-#define jpeg_get_small jGetSmall
-#define jpeg_free_small jFreeSmall
-#define jpeg_get_large jGetLarge
-#define jpeg_free_large jFreeLarge
-#define jpeg_mem_available jMemAvail
-#define jpeg_open_backing_store jOpenBackStore
-#define jpeg_mem_init jMemInit
-#define jpeg_mem_term jMemTerm
-#endif /* NEED_SHORT_EXTERNAL_NAMES */
-
-
-/*
- * These two functions are used to allocate and release small chunks of
- * memory. (Typically the total amount requested through jpeg_get_small is
- * no more than 20K or so; this will be requested in chunks of a few K each.)
- * Behavior should be the same as for the standard library functions malloc
- * and free; in particular, jpeg_get_small must return NULL on failure.
- * On most systems, these ARE malloc and free. jpeg_free_small is passed the
- * size of the object being freed, just in case it's needed.
- * On an 80x86 machine using small-data memory model, these manage near heap.
- */
-
-EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject));
-EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object,
- size_t sizeofobject));
-
-/*
- * These two functions are used to allocate and release large chunks of
- * memory (up to the total free space designated by jpeg_mem_available).
- * The interface is the same as above, except that on an 80x86 machine,
- * far pointers are used. On most other machines these are identical to
- * the jpeg_get/free_small routines; but we keep them separate anyway,
- * in case a different allocation strategy is desirable for large chunks.
- */
-
-EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo,
- size_t sizeofobject));
-EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object,
- size_t sizeofobject));
-
-/*
- * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may
- * be requested in a single call to jpeg_get_large (and jpeg_get_small for that
- * matter, but that case should never come into play). This macro is needed
- * to model the 64Kb-segment-size limit of far addressing on 80x86 machines.
- * On those machines, we expect that jconfig.h will provide a proper value.
- * On machines with 32-bit flat address spaces, any large constant may be used.
- *
- * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type
- * size_t and will be a multiple of sizeof(align_type).
- */
-
-#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */
-#define MAX_ALLOC_CHUNK 1000000000L
-#endif
-
-/*
- * This routine computes the total space still available for allocation by
- * jpeg_get_large. If more space than this is needed, backing store will be
- * used. NOTE: any memory already allocated must not be counted.
- *
- * There is a minimum space requirement, corresponding to the minimum
- * feasible buffer sizes; jmemmgr.c will request that much space even if
- * jpeg_mem_available returns zero. The maximum space needed, enough to hold
- * all working storage in memory, is also passed in case it is useful.
- * Finally, the total space already allocated is passed. If no better
- * method is available, cinfo->mem->max_memory_to_use - already_allocated
- * is often a suitable calculation.
- *
- * It is OK for jpeg_mem_available to underestimate the space available
- * (that'll just lead to more backing-store access than is really necessary).
- * However, an overestimate will lead to failure. Hence it's wise to subtract
- * a slop factor from the true available space. 5% should be enough.
- *
- * On machines with lots of virtual memory, any large constant may be returned.
- * Conversely, zero may be returned to always use the minimum amount of memory.
- */
-
-EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo,
- long min_bytes_needed,
- long max_bytes_needed,
- long already_allocated));
-
-
-/*
- * This structure holds whatever state is needed to access a single
- * backing-store object. The read/write/close method pointers are called
- * by jmemmgr.c to manipulate the backing-store object; all other fields
- * are private to the system-dependent backing store routines.
- */
-
-#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */
-
-
-#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */
-
-typedef unsigned short XMSH; /* type of extended-memory handles */
-typedef unsigned short EMSH; /* type of expanded-memory handles */
-
-typedef union {
- short file_handle; /* DOS file handle if it's a temp file */
- XMSH xms_handle; /* handle if it's a chunk of XMS */
- EMSH ems_handle; /* handle if it's a chunk of EMS */
-} handle_union;
-
-#endif /* USE_MSDOS_MEMMGR */
-
-#ifdef USE_MAC_MEMMGR /* Mac-specific junk */
-#include <Files.h>
-#endif /* USE_MAC_MEMMGR */
-
-
-typedef struct backing_store_struct * backing_store_ptr;
-
-typedef struct backing_store_struct {
- /* Methods for reading/writing/closing this backing-store object */
- JMETHOD(void, read_backing_store, (j_common_ptr cinfo,
- backing_store_ptr info,
- void FAR * buffer_address,
- long file_offset, long byte_count));
- JMETHOD(void, write_backing_store, (j_common_ptr cinfo,
- backing_store_ptr info,
- void FAR * buffer_address,
- long file_offset, long byte_count));
- JMETHOD(void, close_backing_store, (j_common_ptr cinfo,
- backing_store_ptr info));
-
- /* Private fields for system-dependent backing-store management */
-#ifdef USE_MSDOS_MEMMGR
- /* For the MS-DOS manager (jmemdos.c), we need: */
- handle_union handle; /* reference to backing-store storage object */
- char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
-#else
-#ifdef USE_MAC_MEMMGR
- /* For the Mac manager (jmemmac.c), we need: */
- short temp_file; /* file reference number to temp file */
- FSSpec tempSpec; /* the FSSpec for the temp file */
- char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
-#else
- /* For a typical implementation with temp files, we need: */
- FILE * temp_file; /* stdio reference to temp file */
- char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */
-#endif
-#endif
-} backing_store_info;
-
-
-/*
- * Initial opening of a backing-store object. This must fill in the
- * read/write/close pointers in the object. The read/write routines
- * may take an error exit if the specified maximum file size is exceeded.
- * (If jpeg_mem_available always returns a large value, this routine can
- * just take an error exit.)
- */
-
-EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo,
- backing_store_ptr info,
- long total_bytes_needed));
-
-
-/*
- * These routines take care of any system-dependent initialization and
- * cleanup required. jpeg_mem_init will be called before anything is
- * allocated (and, therefore, nothing in cinfo is of use except the error
- * manager pointer). It should return a suitable default value for
- * max_memory_to_use; this may subsequently be overridden by the surrounding
- * application. (Note that max_memory_to_use is only important if
- * jpeg_mem_available chooses to consult it ... no one else will.)
- * jpeg_mem_term may assume that all requested memory has been freed and that
- * all opened backing-store objects have been closed.
- */
-
-EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo));
-EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo));
diff --git a/engine/code/jpeg-6b/jmorecfg.h b/engine/code/jpeg-6b/jmorecfg.h
deleted file mode 100644
index f802007..0000000
--- a/engine/code/jpeg-6b/jmorecfg.h
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * jmorecfg.h
- *
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains additional configuration options that customize the
- * JPEG software for special applications or support machine-dependent
- * optimizations. Most users will not need to touch this file.
- */
-
-
-/*
- * Define BITS_IN_JSAMPLE as either
- * 8 for 8-bit sample values (the usual setting)
- * 12 for 12-bit sample values
- * Only 8 and 12 are legal data precisions for lossy JPEG according to the
- * JPEG standard, and the IJG code does not support anything else!
- * We do not support run-time selection of data precision, sorry.
- */
-
-#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */
-
-
-/*
- * Maximum number of components (color channels) allowed in JPEG image.
- * To meet the letter of the JPEG spec, set this to 255. However, darn
- * few applications need more than 4 channels (maybe 5 for CMYK + alpha
- * mask). We recommend 10 as a reasonable compromise; use 4 if you are
- * really short on memory. (Each allowed component costs a hundred or so
- * bytes of storage, whether actually used in an image or not.)
- */
-
-#define MAX_COMPONENTS 10 /* maximum number of image components */
-
-
-/*
- * Basic data types.
- * You may need to change these if you have a machine with unusual data
- * type sizes; for example, "char" not 8 bits, "short" not 16 bits,
- * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits,
- * but it had better be at least 16.
- */
-
-/* Representation of a single sample (pixel element value).
- * We frequently allocate large arrays of these, so it's important to keep
- * them small. But if you have memory to burn and access to char or short
- * arrays is very slow on your hardware, you might want to change these.
- */
-
-#if BITS_IN_JSAMPLE == 8
-/* JSAMPLE should be the smallest type that will hold the values 0..255.
- * You can use a signed char by having GETJSAMPLE mask it with 0xFF.
- */
-
-#ifdef HAVE_UNSIGNED_CHAR
-
-typedef unsigned char JSAMPLE;
-#define GETJSAMPLE(value) ((int) (value))
-
-#else /* not HAVE_UNSIGNED_CHAR */
-
-typedef char JSAMPLE;
-#ifdef CHAR_IS_UNSIGNED
-#define GETJSAMPLE(value) ((int) (value))
-#else
-#define GETJSAMPLE(value) ((int) (value) & 0xFF)
-#endif /* CHAR_IS_UNSIGNED */
-
-#endif /* HAVE_UNSIGNED_CHAR */
-
-#define MAXJSAMPLE 255
-#define CENTERJSAMPLE 128
-
-#endif /* BITS_IN_JSAMPLE == 8 */
-
-
-#if BITS_IN_JSAMPLE == 12
-/* JSAMPLE should be the smallest type that will hold the values 0..4095.
- * On nearly all machines "short" will do nicely.
- */
-
-typedef short JSAMPLE;
-#define GETJSAMPLE(value) ((int) (value))
-
-#define MAXJSAMPLE 4095
-#define CENTERJSAMPLE 2048
-
-#endif /* BITS_IN_JSAMPLE == 12 */
-
-
-/* Representation of a DCT frequency coefficient.
- * This should be a signed value of at least 16 bits; "short" is usually OK.
- * Again, we allocate large arrays of these, but you can change to int
- * if you have memory to burn and "short" is really slow.
- */
-
-typedef short JCOEF;
-
-
-/* Compressed datastreams are represented as arrays of JOCTET.
- * These must be EXACTLY 8 bits wide, at least once they are written to
- * external storage. Note that when using the stdio data source/destination
- * managers, this is also the data type passed to fread/fwrite.
- */
-
-#ifdef HAVE_UNSIGNED_CHAR
-
-typedef unsigned char JOCTET;
-#define GETJOCTET(value) (value)
-
-#else /* not HAVE_UNSIGNED_CHAR */
-
-typedef char JOCTET;
-#ifdef CHAR_IS_UNSIGNED
-#define GETJOCTET(value) (value)
-#else
-#define GETJOCTET(value) ((value) & 0xFF)
-#endif /* CHAR_IS_UNSIGNED */
-
-#endif /* HAVE_UNSIGNED_CHAR */
-
-
-/* These typedefs are used for various table entries and so forth.
- * They must be at least as wide as specified; but making them too big
- * won't cost a huge amount of memory, so we don't provide special
- * extraction code like we did for JSAMPLE. (In other words, these
- * typedefs live at a different point on the speed/space tradeoff curve.)
- */
-
-/* UINT8 must hold at least the values 0..255. */
-
-#ifdef HAVE_UNSIGNED_CHAR
-typedef unsigned char UINT8;
-#else /* not HAVE_UNSIGNED_CHAR */
-#ifdef CHAR_IS_UNSIGNED
-typedef char UINT8;
-#else /* not CHAR_IS_UNSIGNED */
-typedef short UINT8;
-#endif /* CHAR_IS_UNSIGNED */
-#endif /* HAVE_UNSIGNED_CHAR */
-
-/* UINT16 must hold at least the values 0..65535. */
-
-#ifdef HAVE_UNSIGNED_SHORT
-typedef unsigned short UINT16;
-#else /* not HAVE_UNSIGNED_SHORT */
-typedef unsigned int UINT16;
-#endif /* HAVE_UNSIGNED_SHORT */
-
-/* INT16 must hold at least the values -32768..32767. */
-
-#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */
-typedef short INT16;
-#endif
-
-/* INT32 must hold at least signed 32-bit values. */
-
-/* MinGW basetsd.h defines INT32 - don't redefine it */
-#if !(defined __MINGW32__ && defined _BASETSD_H)
-typedef long INT32;
-#endif
-
-/* Datatype used for image dimensions. The JPEG standard only supports
- * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore
- * "unsigned int" is sufficient on all machines. However, if you need to
- * handle larger images and you don't mind deviating from the spec, you
- * can change this datatype.
- */
-
-typedef unsigned int JDIMENSION;
-
-#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */
-
-
-/* These macros are used in all function definitions and extern declarations.
- * You could modify them if you need to change function linkage conventions;
- * in particular, you'll need to do that to make the library a Windows DLL.
- * Another application is to make all functions global for use with debuggers
- * or code profilers that require it.
- */
-
-/* a function called through method pointers: */
-#define METHODDEF(type) static type
-/* a function used only in its module: */
-#define LOCAL(type) static type
-/* a function referenced thru EXTERNs: */
-#define GLOBAL(type) type
-/* a reference to a GLOBAL function: */
-#define EXTERN(type) extern type
-
-
-/* This macro is used to declare a "method", that is, a function pointer.
- * We want to supply prototype parameters if the compiler can cope.
- * Note that the arglist parameter must be parenthesized!
- * Again, you can customize this if you need special linkage keywords.
- */
-
-#ifdef HAVE_PROTOTYPES
-#define JMETHOD(type,methodname,arglist) type (*methodname) arglist
-#else
-#define JMETHOD(type,methodname,arglist) type (*methodname) ()
-#endif
-
-
-/* Here is the pseudo-keyword for declaring pointers that must be "far"
- * on 80x86 machines. Most of the specialized coding for 80x86 is handled
- * by just saying "FAR *" where such a pointer is needed. In a few places
- * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol.
- */
-
-#ifdef NEED_FAR_POINTERS
-#undef FAR
-#define FAR far
-#else
-#undef FAR
-#define FAR
-#endif
-
-
-/*
- * On a few systems, type boolean and/or its values FALSE, TRUE may appear
- * in standard header files. Or you may have conflicts with application-
- * specific header files that you want to include together with these files.
- * Defining HAVE_BOOLEAN before including jpeglib.h should make it work.
- */
-
-typedef unsigned char boolean;
-#ifndef FALSE /* in case these macros already exist */
-#define FALSE 0 /* values of boolean */
-#endif
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-
-/*
- * The remaining options affect code selection within the JPEG library,
- * but they don't need to be visible to most applications using the library.
- * To minimize application namespace pollution, the symbols won't be
- * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined.
- */
-
-#ifdef JPEG_INTERNALS
-#define JPEG_INTERNAL_OPTIONS
-#endif
-
-#ifdef JPEG_INTERNAL_OPTIONS
-
-
-/*
- * These defines indicate whether to include various optional functions.
- * Undefining some of these symbols will produce a smaller but less capable
- * library. Note that you can leave certain source files out of the
- * compilation/linking process if you've #undef'd the corresponding symbols.
- * (You may HAVE to do that if your compiler doesn't like null source files.)
- */
-
-/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */
-
-/* Capability options common to encoder and decoder: */
-
-#undef DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */
-#undef DCT_IFAST_SUPPORTED /* faster, less accurate integer method */
-#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */
-
-/* Encoder capability options: */
-
-#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */
-#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
-#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
-#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */
-/* Note: if you selected 12-bit data precision, it is dangerous to turn off
- * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit
- * precision, so jchuff.c normally uses entropy optimization to compute
- * usable tables for higher precision. If you don't want to do optimization,
- * you'll have to supply different default Huffman tables.
- * The exact same statements apply for progressive JPEG: the default tables
- * don't work for progressive mode. (This may get fixed, however.)
- */
-#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */
-
-/* Decoder capability options: */
-
-#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */
-#undef D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
-#undef D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
-#undef SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */
-#undef BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */
-#undef IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */
-#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */
-#undef UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */
-#undef QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */
-#undef QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */
-
-/* more capability options later, no doubt */
-
-
-/*
- * Ordering of RGB data in scanlines passed to or from the application.
- * If your application wants to deal with data in the order B,G,R, just
- * change these macros. You can also deal with formats such as R,G,B,X
- * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing
- * the offsets will also change the order in which colormap data is organized.
- * RESTRICTIONS:
- * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats.
- * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not
- * useful if you are using JPEG color spaces other than YCbCr or grayscale.
- * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE
- * is not 3 (they don't understand about dummy color components!). So you
- * can't use color quantization if you change that value.
- */
-
-#define RGB_RED 0 /* Offset of Red in an RGB scanline element */
-#define RGB_GREEN 1 /* Offset of Green */
-#define RGB_BLUE 2 /* Offset of Blue */
-#define RGB_PIXELSIZE 4 /* JSAMPLEs per RGB scanline element */
-
-
-/* Definitions for speed-related optimizations. */
-
-
-/* If your compiler supports inline functions, define INLINE
- * as the inline keyword; otherwise define it as empty.
- */
-
-#ifndef INLINE
-#ifdef __GNUC__ /* for instance, GNU C knows about inline */
-#define INLINE __inline__
-#endif
-#ifndef INLINE
-#define INLINE /* default is to define it as empty */
-#endif
-#endif
-
-
-/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying
- * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER
- * as short on such a machine. MULTIPLIER must be at least 16 bits wide.
- */
-
-#ifndef MULTIPLIER
-#define MULTIPLIER int /* type for fastest integer multiply */
-#endif
-
-
-/* FAST_FLOAT should be either float or double, whichever is done faster
- * by your compiler. (Note that this type is only used in the floating point
- * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.)
- * Typically, float is faster in ANSI C compilers, while double is faster in
- * pre-ANSI compilers (because they insist on converting to double anyway).
- * The code below therefore chooses float if we have ANSI-style prototypes.
- */
-
-#ifndef FAST_FLOAT
-#ifdef HAVE_PROTOTYPES
-#define FAST_FLOAT float
-#else
-#define FAST_FLOAT double
-#endif
-#endif
-
-#endif /* JPEG_INTERNAL_OPTIONS */
diff --git a/engine/code/jpeg-6b/jpegint.h b/engine/code/jpeg-6b/jpegint.h
deleted file mode 100644
index 95b00d4..0000000
--- a/engine/code/jpeg-6b/jpegint.h
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * jpegint.h
- *
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file provides common declarations for the various JPEG modules.
- * These declarations are considered internal to the JPEG library; most
- * applications using the library shouldn't need to include this file.
- */
-
-
-/* Declarations for both compression & decompression */
-
-typedef enum { /* Operating modes for buffer controllers */
- JBUF_PASS_THRU, /* Plain stripwise operation */
- /* Remaining modes require a full-image buffer to have been created */
- JBUF_SAVE_SOURCE, /* Run source subobject only, save output */
- JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */
- JBUF_SAVE_AND_PASS /* Run both subobjects, save output */
-} J_BUF_MODE;
-
-/* Values of global_state field (jdapi.c has some dependencies on ordering!) */
-#define CSTATE_START 100 /* after create_compress */
-#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */
-#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */
-#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */
-#define DSTATE_START 200 /* after create_decompress */
-#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */
-#define DSTATE_READY 202 /* found SOS, ready for start_decompress */
-#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/
-#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */
-#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */
-#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */
-#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */
-#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */
-#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */
-#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */
-
-
-/* Declarations for compression modules */
-
-/* Master control module */
-struct jpeg_comp_master {
- JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo));
- JMETHOD(void, pass_startup, (j_compress_ptr cinfo));
- JMETHOD(void, finish_pass, (j_compress_ptr cinfo));
-
- /* State variables made visible to other modules */
- boolean call_pass_startup; /* True if pass_startup must be called */
- boolean is_last_pass; /* True during last pass */
-};
-
-/* Main buffer control (downsampled-data buffer) */
-struct jpeg_c_main_controller {
- JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
- JMETHOD(void, process_data, (j_compress_ptr cinfo,
- JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
- JDIMENSION in_rows_avail));
-};
-
-/* Compression preprocessing (downsampling input buffer control) */
-struct jpeg_c_prep_controller {
- JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
- JMETHOD(void, pre_process_data, (j_compress_ptr cinfo,
- JSAMPARRAY input_buf,
- JDIMENSION *in_row_ctr,
- JDIMENSION in_rows_avail,
- JSAMPIMAGE output_buf,
- JDIMENSION *out_row_group_ctr,
- JDIMENSION out_row_groups_avail));
-};
-
-/* Coefficient buffer control */
-struct jpeg_c_coef_controller {
- JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
- JMETHOD(boolean, compress_data, (j_compress_ptr cinfo,
- JSAMPIMAGE input_buf));
-};
-
-/* Colorspace conversion */
-struct jpeg_color_converter {
- JMETHOD(void, start_pass, (j_compress_ptr cinfo));
- JMETHOD(void, color_convert, (j_compress_ptr cinfo,
- JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
- JDIMENSION output_row, int num_rows));
-};
-
-/* Downsampling */
-struct jpeg_downsampler {
- JMETHOD(void, start_pass, (j_compress_ptr cinfo));
- JMETHOD(void, downsample, (j_compress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION in_row_index,
- JSAMPIMAGE output_buf,
- JDIMENSION out_row_group_index));
-
- boolean need_context_rows; /* TRUE if need rows above & below */
-};
-
-/* Forward DCT (also controls coefficient quantization) */
-struct jpeg_forward_dct {
- JMETHOD(void, start_pass, (j_compress_ptr cinfo));
- /* perhaps this should be an array??? */
- JMETHOD(void, forward_DCT, (j_compress_ptr cinfo,
- jpeg_component_info * compptr,
- JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
- JDIMENSION start_row, JDIMENSION start_col,
- JDIMENSION num_blocks));
-};
-
-/* Entropy encoding */
-struct jpeg_entropy_encoder {
- JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics));
- JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data));
- JMETHOD(void, finish_pass, (j_compress_ptr cinfo));
-};
-
-/* Marker writing */
-struct jpeg_marker_writer {
- JMETHOD(void, write_file_header, (j_compress_ptr cinfo));
- JMETHOD(void, write_frame_header, (j_compress_ptr cinfo));
- JMETHOD(void, write_scan_header, (j_compress_ptr cinfo));
- JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo));
- JMETHOD(void, write_tables_only, (j_compress_ptr cinfo));
- /* These routines are exported to allow insertion of extra markers */
- /* Probably only COM and APPn markers should be written this way */
- JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker,
- unsigned int datalen));
- JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val));
-};
-
-
-/* Declarations for decompression modules */
-
-/* Master control module */
-struct jpeg_decomp_master {
- JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo));
- JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo));
-
- /* State variables made visible to other modules */
- boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */
-};
-
-/* Input control module */
-struct jpeg_input_controller {
- JMETHOD(int, consume_input, (j_decompress_ptr cinfo));
- JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo));
- JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));
- JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo));
-
- /* State variables made visible to other modules */
- boolean has_multiple_scans; /* True if file has multiple scans */
- boolean eoi_reached; /* True when EOI has been consumed */
-};
-
-/* Main buffer control (downsampled-data buffer) */
-struct jpeg_d_main_controller {
- JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
- JMETHOD(void, process_data, (j_decompress_ptr cinfo,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail));
-};
-
-/* Coefficient buffer control */
-struct jpeg_d_coef_controller {
- JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));
- JMETHOD(int, consume_data, (j_decompress_ptr cinfo));
- JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo));
- JMETHOD(int, decompress_data, (j_decompress_ptr cinfo,
- JSAMPIMAGE output_buf));
- /* Pointer to array of coefficient virtual arrays, or NULL if none */
- jvirt_barray_ptr *coef_arrays;
-};
-
-/* Decompression postprocessing (color quantization buffer control) */
-struct jpeg_d_post_controller {
- JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
- JMETHOD(void, post_process_data, (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf,
- JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf,
- JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail));
-};
-
-/* Marker reading & parsing */
-struct jpeg_marker_reader {
- JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo));
- /* Read markers until SOS or EOI.
- * Returns same codes as are defined for jpeg_consume_input:
- * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
- */
- JMETHOD(int, read_markers, (j_decompress_ptr cinfo));
- /* Read a restart marker --- exported for use by entropy decoder only */
- jpeg_marker_parser_method read_restart_marker;
-
- /* State of marker reader --- nominally internal, but applications
- * supplying COM or APPn handlers might like to know the state.
- */
- boolean saw_SOI; /* found SOI? */
- boolean saw_SOF; /* found SOF? */
- int next_restart_num; /* next restart number expected (0-7) */
- unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */
-};
-
-/* Entropy decoding */
-struct jpeg_entropy_decoder {
- JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
- JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo,
- JBLOCKROW *MCU_data));
-
- /* This is here to share code between baseline and progressive decoders; */
- /* other modules probably should not use it */
- boolean insufficient_data; /* set TRUE after emitting warning */
-};
-
-/* Inverse DCT (also performs dequantization) */
-typedef JMETHOD(void, inverse_DCT_method_ptr,
- (j_decompress_ptr cinfo, jpeg_component_info * compptr,
- JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col));
-
-struct jpeg_inverse_dct {
- JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
- /* It is useful to allow each component to have a separate IDCT method. */
- inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS];
-};
-
-/* Upsampling (note that upsampler must also call color converter) */
-struct jpeg_upsampler {
- JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
- JMETHOD(void, upsample, (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf,
- JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf,
- JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail));
-
- boolean need_context_rows; /* TRUE if need rows above & below */
-};
-
-/* Colorspace conversion */
-struct jpeg_color_deconverter {
- JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
- JMETHOD(void, color_convert, (j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf, JDIMENSION input_row,
- JSAMPARRAY output_buf, int num_rows));
-};
-
-/* Color quantization or color precision reduction */
-struct jpeg_color_quantizer {
- JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan));
- JMETHOD(void, color_quantize, (j_decompress_ptr cinfo,
- JSAMPARRAY input_buf, JSAMPARRAY output_buf,
- int num_rows));
- JMETHOD(void, finish_pass, (j_decompress_ptr cinfo));
- JMETHOD(void, new_color_map, (j_decompress_ptr cinfo));
-};
-
-
-/* Miscellaneous useful macros */
-
-#undef MAX
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-#undef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-
-
-/* We assume that right shift corresponds to signed division by 2 with
- * rounding towards minus infinity. This is correct for typical "arithmetic
- * shift" instructions that shift in copies of the sign bit. But some
- * C compilers implement >> with an unsigned shift. For these machines you
- * must define RIGHT_SHIFT_IS_UNSIGNED.
- * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity.
- * It is only applied with constant shift counts. SHIFT_TEMPS must be
- * included in the variables of any routine using RIGHT_SHIFT.
- */
-
-#ifdef RIGHT_SHIFT_IS_UNSIGNED
-#define SHIFT_TEMPS INT32 shift_temp;
-#define RIGHT_SHIFT(x,shft) \
- ((shift_temp = (x)) < 0 ? \
- (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \
- (shift_temp >> (shft)))
-#else
-#define SHIFT_TEMPS
-#define RIGHT_SHIFT(x,shft) ((x) >> (shft))
-#endif
-
-
-/* Short forms of external names for systems with brain-damaged linkers. */
-
-#ifdef NEED_SHORT_EXTERNAL_NAMES
-#define jinit_compress_master jICompress
-#define jinit_c_master_control jICMaster
-#define jinit_c_main_controller jICMainC
-#define jinit_c_prep_controller jICPrepC
-#define jinit_c_coef_controller jICCoefC
-#define jinit_color_converter jICColor
-#define jinit_downsampler jIDownsampler
-#define jinit_forward_dct jIFDCT
-#define jinit_huff_encoder jIHEncoder
-#define jinit_phuff_encoder jIPHEncoder
-#define jinit_marker_writer jIMWriter
-#define jinit_master_decompress jIDMaster
-#define jinit_d_main_controller jIDMainC
-#define jinit_d_coef_controller jIDCoefC
-#define jinit_d_post_controller jIDPostC
-#define jinit_input_controller jIInCtlr
-#define jinit_marker_reader jIMReader
-#define jinit_huff_decoder jIHDecoder
-#define jinit_phuff_decoder jIPHDecoder
-#define jinit_inverse_dct jIIDCT
-#define jinit_upsampler jIUpsampler
-#define jinit_color_deconverter jIDColor
-#define jinit_1pass_quantizer jI1Quant
-#define jinit_2pass_quantizer jI2Quant
-#define jinit_merged_upsampler jIMUpsampler
-#define jinit_memory_mgr jIMemMgr
-#define jdiv_round_up jDivRound
-#define jround_up jRound
-#define jcopy_sample_rows jCopySamples
-#define jcopy_block_row jCopyBlocks
-#define jzero_far jZeroFar
-#define jpeg_zigzag_order jZIGTable
-#define jpeg_natural_order jZAGTable
-#endif /* NEED_SHORT_EXTERNAL_NAMES */
-
-
-/* Compression module initialization routines */
-EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo));
-EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo,
- boolean transcode_only));
-EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo,
- boolean need_full_buffer));
-EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo,
- boolean need_full_buffer));
-EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo,
- boolean need_full_buffer));
-EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo));
-EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo));
-EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo));
-EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo));
-EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo));
-EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo));
-/* Decompression module initialization routines */
-EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo));
-EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo,
- boolean need_full_buffer));
-EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo,
- boolean need_full_buffer));
-EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo,
- boolean need_full_buffer));
-EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo));
-EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo));
-EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo));
-EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo));
-EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo));
-EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo));
-EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo));
-EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo));
-EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo));
-EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo));
-/* Memory manager initialization */
-EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo));
-
-/* Utility routines in jutils.c */
-EXTERN(long) jdiv_round_up JPP((long a, long b));
-EXTERN(long) jround_up JPP((long a, long b));
-EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row,
- JSAMPARRAY output_array, int dest_row,
- int num_rows, JDIMENSION num_cols));
-EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row,
- JDIMENSION num_blocks));
-EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero));
-/* Constant tables in jutils.c */
-#if 0 /* This table is not actually needed in v6a */
-extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */
-#endif
-extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */
-
-/* Suppress undefined-structure complaints if necessary. */
-
-#ifdef INCOMPLETE_TYPES_BROKEN
-#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */
-struct jvirt_sarray_control { long dummy; };
-struct jvirt_barray_control { long dummy; };
-#endif
-#endif /* INCOMPLETE_TYPES_BROKEN */
diff --git a/engine/code/jpeg-6b/jpeglib.h b/engine/code/jpeg-6b/jpeglib.h
deleted file mode 100644
index 8ff305d..0000000
--- a/engine/code/jpeg-6b/jpeglib.h
+++ /dev/null
@@ -1,1096 +0,0 @@
-/*
- * jpeglib.h
- *
- * Copyright (C) 1991-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file defines the application interface for the JPEG library.
- * Most applications using the library need only include this file,
- * and perhaps jerror.h if they want to know the exact error codes.
- */
-
-#ifndef JPEGLIB_H
-#define JPEGLIB_H
-
-/*
- * First we include the configuration files that record how this
- * installation of the JPEG library is set up. jconfig.h can be
- * generated automatically for many systems. jmorecfg.h contains
- * manual configuration options that most people need not worry about.
- */
-
-#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */
-#include "../jpeg-6b/jconfig.h" /* widely used configuration options */
-#endif
-#include "../jpeg-6b/jmorecfg.h" /* seldom changed options */
-
-
-/* Version ID for the JPEG library.
- * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60".
- */
-
-#define JPEG_LIB_VERSION 62 /* Version 6b */
-
-
-/* Various constants determining the sizes of things.
- * All of these are specified by the JPEG standard, so don't change them
- * if you want to be compatible.
- */
-
-#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */
-#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */
-#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */
-#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */
-#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */
-#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */
-#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */
-/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard;
- * the PostScript DCT filter can emit files with many more than 10 blocks/MCU.
- * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU
- * to handle it. We even let you do this from the jconfig.h file. However,
- * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe
- * sometimes emits noncompliant files doesn't mean you should too.
- */
-#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */
-#ifndef D_MAX_BLOCKS_IN_MCU
-#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */
-#endif
-
-
-/* Data structures for images (arrays of samples and of DCT coefficients).
- * On 80x86 machines, the image arrays are too big for near pointers,
- * but the pointer arrays can fit in near memory.
- */
-
-typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */
-typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */
-typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */
-
-typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */
-typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */
-typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */
-typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */
-
-typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */
-
-
-/* Types for JPEG compression parameters and working tables. */
-
-
-/* DCT coefficient quantization tables. */
-
-typedef struct {
- /* This array gives the coefficient quantizers in natural array order
- * (not the zigzag order in which they are stored in a JPEG DQT marker).
- * CAUTION: IJG versions prior to v6a kept this array in zigzag order.
- */
- UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */
- /* This field is used only during compression. It's initialized FALSE when
- * the table is created, and set TRUE when it's been output to the file.
- * You could suppress output of a table by setting this to TRUE.
- * (See jpeg_suppress_tables for an example.)
- */
- boolean sent_table; /* TRUE when table has been output */
-} JQUANT_TBL;
-
-
-/* Huffman coding tables. */
-
-typedef struct {
- /* These two fields directly represent the contents of a JPEG DHT marker */
- UINT8 bits[17]; /* bits[k] = # of symbols with codes of */
- /* length k bits; bits[0] is unused */
- UINT8 huffval[256]; /* The symbols, in order of incr code length */
- /* This field is used only during compression. It's initialized FALSE when
- * the table is created, and set TRUE when it's been output to the file.
- * You could suppress output of a table by setting this to TRUE.
- * (See jpeg_suppress_tables for an example.)
- */
- boolean sent_table; /* TRUE when table has been output */
-} JHUFF_TBL;
-
-
-/* Basic info about one component (color channel). */
-
-typedef struct {
- /* These values are fixed over the whole image. */
- /* For compression, they must be supplied by parameter setup; */
- /* for decompression, they are read from the SOF marker. */
- int component_id; /* identifier for this component (0..255) */
- int component_index; /* its index in SOF or cinfo->comp_info[] */
- int h_samp_factor; /* horizontal sampling factor (1..4) */
- int v_samp_factor; /* vertical sampling factor (1..4) */
- int quant_tbl_no; /* quantization table selector (0..3) */
- /* These values may vary between scans. */
- /* For compression, they must be supplied by parameter setup; */
- /* for decompression, they are read from the SOS marker. */
- /* The decompressor output side may not use these variables. */
- int dc_tbl_no; /* DC entropy table selector (0..3) */
- int ac_tbl_no; /* AC entropy table selector (0..3) */
-
- /* Remaining fields should be treated as private by applications. */
-
- /* These values are computed during compression or decompression startup: */
- /* Component's size in DCT blocks.
- * Any dummy blocks added to complete an MCU are not counted; therefore
- * these values do not depend on whether a scan is interleaved or not.
- */
- JDIMENSION width_in_blocks;
- JDIMENSION height_in_blocks;
- /* Size of a DCT block in samples. Always DCTSIZE for compression.
- * For decompression this is the size of the output from one DCT block,
- * reflecting any scaling we choose to apply during the IDCT step.
- * Values of 1,2,4,8 are likely to be supported. Note that different
- * components may receive different IDCT scalings.
- */
- int DCT_scaled_size;
- /* The downsampled dimensions are the component's actual, unpadded number
- * of samples at the main buffer (preprocessing/compression interface), thus
- * downsampled_width = ceil(image_width * Hi/Hmax)
- * and similarly for height. For decompression, IDCT scaling is included, so
- * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE)
- */
- JDIMENSION downsampled_width; /* actual width in samples */
- JDIMENSION downsampled_height; /* actual height in samples */
- /* This flag is used only for decompression. In cases where some of the
- * components will be ignored (eg grayscale output from YCbCr image),
- * we can skip most computations for the unused components.
- */
- boolean component_needed; /* do we need the value of this component? */
-
- /* These values are computed before starting a scan of the component. */
- /* The decompressor output side may not use these variables. */
- int MCU_width; /* number of blocks per MCU, horizontally */
- int MCU_height; /* number of blocks per MCU, vertically */
- int MCU_blocks; /* MCU_width * MCU_height */
- int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */
- int last_col_width; /* # of non-dummy blocks across in last MCU */
- int last_row_height; /* # of non-dummy blocks down in last MCU */
-
- /* Saved quantization table for component; NULL if none yet saved.
- * See jdinput.c comments about the need for this information.
- * This field is currently used only for decompression.
- */
- JQUANT_TBL * quant_table;
-
- /* Private per-component storage for DCT or IDCT subsystem. */
- void * dct_table;
-} jpeg_component_info;
-
-
-/* The script for encoding a multiple-scan file is an array of these: */
-
-typedef struct {
- int comps_in_scan; /* number of components encoded in this scan */
- int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */
- int Ss, Se; /* progressive JPEG spectral selection parms */
- int Ah, Al; /* progressive JPEG successive approx. parms */
-} jpeg_scan_info;
-
-/* The decompressor can save APPn and COM markers in a list of these: */
-
-typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr;
-
-struct jpeg_marker_struct {
- jpeg_saved_marker_ptr next; /* next in list, or NULL */
- UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */
- unsigned int original_length; /* # bytes of data in the file */
- unsigned int data_length; /* # bytes of data saved at data[] */
- JOCTET FAR * data; /* the data contained in the marker */
- /* the marker length word is not counted in data_length or original_length */
-};
-
-/* Known color spaces. */
-
-typedef enum {
- JCS_UNKNOWN, /* error/unspecified */
- JCS_GRAYSCALE, /* monochrome */
- JCS_RGB, /* red/green/blue */
- JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */
- JCS_CMYK, /* C/M/Y/K */
- JCS_YCCK /* Y/Cb/Cr/K */
-} J_COLOR_SPACE;
-
-/* DCT/IDCT algorithm options. */
-
-typedef enum {
- JDCT_ISLOW, /* slow but accurate integer algorithm */
- JDCT_IFAST, /* faster, less accurate integer method */
- JDCT_FLOAT /* floating-point: accurate, fast on fast HW */
-} J_DCT_METHOD;
-
-#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */
-#define JDCT_DEFAULT JDCT_ISLOW
-#endif
-#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */
-#define JDCT_FASTEST JDCT_IFAST
-#endif
-
-/* Dithering options for decompression. */
-
-typedef enum {
- JDITHER_NONE, /* no dithering */
- JDITHER_ORDERED, /* simple ordered dither */
- JDITHER_FS /* Floyd-Steinberg error diffusion dither */
-} J_DITHER_MODE;
-
-
-/* Common fields between JPEG compression and decompression master structs. */
-
-#define jpeg_common_fields \
- struct jpeg_error_mgr * err; /* Error handler module */\
- struct jpeg_memory_mgr * mem; /* Memory manager module */\
- struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\
- void * client_data; /* Available for use by application */\
- boolean is_decompressor; /* So common code can tell which is which */\
- int global_state /* For checking call sequence validity */
-
-/* Routines that are to be used by both halves of the library are declared
- * to receive a pointer to this structure. There are no actual instances of
- * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct.
- */
-struct jpeg_common_struct {
- jpeg_common_fields; /* Fields common to both master struct types */
- /* Additional fields follow in an actual jpeg_compress_struct or
- * jpeg_decompress_struct. All three structs must agree on these
- * initial fields! (This would be a lot cleaner in C++.)
- */
-};
-
-typedef struct jpeg_common_struct * j_common_ptr;
-typedef struct jpeg_compress_struct * j_compress_ptr;
-typedef struct jpeg_decompress_struct * j_decompress_ptr;
-
-
-/* Master record for a compression instance */
-
-struct jpeg_compress_struct {
- jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */
-
- /* Destination for compressed data */
- struct jpeg_destination_mgr * dest;
-
- /* Description of source image --- these fields must be filled in by
- * outer application before starting compression. in_color_space must
- * be correct before you can even call jpeg_set_defaults().
- */
-
- JDIMENSION image_width; /* input image width */
- JDIMENSION image_height; /* input image height */
- int input_components; /* # of color components in input image */
- J_COLOR_SPACE in_color_space; /* colorspace of input image */
-
- double input_gamma; /* image gamma of input image */
-
- /* Compression parameters --- these fields must be set before calling
- * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to
- * initialize everything to reasonable defaults, then changing anything
- * the application specifically wants to change. That way you won't get
- * burnt when new parameters are added. Also note that there are several
- * helper routines to simplify changing parameters.
- */
-
- int data_precision; /* bits of precision in image data */
-
- int num_components; /* # of color components in JPEG image */
- J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */
-
- jpeg_component_info * comp_info;
- /* comp_info[i] describes component that appears i'th in SOF */
-
- JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS];
- /* ptrs to coefficient quantization tables, or NULL if not defined */
-
- JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS];
- JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS];
- /* ptrs to Huffman coding tables, or NULL if not defined */
-
- UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */
- UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */
- UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */
-
- int num_scans; /* # of entries in scan_info array */
- const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */
- /* The default value of scan_info is NULL, which causes a single-scan
- * sequential JPEG file to be emitted. To create a multi-scan file,
- * set num_scans and scan_info to point to an array of scan definitions.
- */
-
- boolean raw_data_in; /* TRUE=caller supplies downsampled data */
- boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */
- boolean optimize_coding; /* TRUE=optimize entropy encoding parms */
- boolean CCIR601_sampling; /* TRUE=first samples are cosited */
- int smoothing_factor; /* 1..100, or 0 for no input smoothing */
- J_DCT_METHOD dct_method; /* DCT algorithm selector */
-
- /* The restart interval can be specified in absolute MCUs by setting
- * restart_interval, or in MCU rows by setting restart_in_rows
- * (in which case the correct restart_interval will be figured
- * for each scan).
- */
- unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */
- int restart_in_rows; /* if > 0, MCU rows per restart interval */
-
- /* Parameters controlling emission of special markers. */
-
- boolean write_JFIF_header; /* should a JFIF marker be written? */
- UINT8 JFIF_major_version; /* What to write for the JFIF version number */
- UINT8 JFIF_minor_version;
- /* These three values are not used by the JPEG code, merely copied */
- /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */
- /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */
- /* ratio is defined by X_density/Y_density even when density_unit=0. */
- UINT8 density_unit; /* JFIF code for pixel size units */
- UINT16 X_density; /* Horizontal pixel density */
- UINT16 Y_density; /* Vertical pixel density */
- boolean write_Adobe_marker; /* should an Adobe marker be written? */
-
- /* State variable: index of next scanline to be written to
- * jpeg_write_scanlines(). Application may use this to control its
- * processing loop, e.g., "while (next_scanline < image_height)".
- */
-
- JDIMENSION next_scanline; /* 0 .. image_height-1 */
-
- /* Remaining fields are known throughout compressor, but generally
- * should not be touched by a surrounding application.
- */
-
- /*
- * These fields are computed during compression startup
- */
- boolean progressive_mode; /* TRUE if scan script uses progressive mode */
- int max_h_samp_factor; /* largest h_samp_factor */
- int max_v_samp_factor; /* largest v_samp_factor */
-
- JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */
- /* The coefficient controller receives data in units of MCU rows as defined
- * for fully interleaved scans (whether the JPEG file is interleaved or not).
- * There are v_samp_factor * DCTSIZE sample rows of each component in an
- * "iMCU" (interleaved MCU) row.
- */
-
- /*
- * These fields are valid during any one scan.
- * They describe the components and MCUs actually appearing in the scan.
- */
- int comps_in_scan; /* # of JPEG components in this scan */
- jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN];
- /* *cur_comp_info[i] describes component that appears i'th in SOS */
-
- JDIMENSION MCUs_per_row; /* # of MCUs across the image */
- JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
-
- int blocks_in_MCU; /* # of DCT blocks per MCU */
- int MCU_membership[C_MAX_BLOCKS_IN_MCU];
- /* MCU_membership[i] is index in cur_comp_info of component owning */
- /* i'th block in an MCU */
-
- int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */
-
- /*
- * Links to compression subobjects (methods and private variables of modules)
- */
- struct jpeg_comp_master * master;
- struct jpeg_c_main_controller * main;
- struct jpeg_c_prep_controller * prep;
- struct jpeg_c_coef_controller * coef;
- struct jpeg_marker_writer * marker;
- struct jpeg_color_converter * cconvert;
- struct jpeg_downsampler * downsample;
- struct jpeg_forward_dct * fdct;
- struct jpeg_entropy_encoder * entropy;
- jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */
- int script_space_size;
-};
-
-
-/* Master record for a decompression instance */
-
-struct jpeg_decompress_struct {
- jpeg_common_fields; /* Fields shared with jpeg_compress_struct */
-
- /* Source of compressed data */
- struct jpeg_source_mgr * src;
-
- /* Basic description of image --- filled in by jpeg_read_header(). */
- /* Application may inspect these values to decide how to process image. */
-
- JDIMENSION image_width; /* nominal image width (from SOF marker) */
- JDIMENSION image_height; /* nominal image height */
- int num_components; /* # of color components in JPEG image */
- J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */
-
- /* Decompression processing parameters --- these fields must be set before
- * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes
- * them to default values.
- */
-
- J_COLOR_SPACE out_color_space; /* colorspace for output */
-
- unsigned int scale_num, scale_denom; /* fraction by which to scale image */
-
- double output_gamma; /* image gamma wanted in output */
-
- boolean buffered_image; /* TRUE=multiple output passes */
- boolean raw_data_out; /* TRUE=downsampled data wanted */
-
- J_DCT_METHOD dct_method; /* IDCT algorithm selector */
- boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */
- boolean do_block_smoothing; /* TRUE=apply interblock smoothing */
-
- boolean quantize_colors; /* TRUE=colormapped output wanted */
- /* the following are ignored if not quantize_colors: */
- J_DITHER_MODE dither_mode; /* type of color dithering to use */
- boolean two_pass_quantize; /* TRUE=use two-pass color quantization */
- int desired_number_of_colors; /* max # colors to use in created colormap */
- /* these are significant only in buffered-image mode: */
- boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */
- boolean enable_external_quant;/* enable future use of external colormap */
- boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */
-
- /* Description of actual output image that will be returned to application.
- * These fields are computed by jpeg_start_decompress().
- * You can also use jpeg_calc_output_dimensions() to determine these values
- * in advance of calling jpeg_start_decompress().
- */
-
- JDIMENSION output_width; /* scaled image width */
- JDIMENSION output_height; /* scaled image height */
- int out_color_components; /* # of color components in out_color_space */
- int output_components; /* # of color components returned */
- /* output_components is 1 (a colormap index) when quantizing colors;
- * otherwise it equals out_color_components.
- */
- int rec_outbuf_height; /* min recommended height of scanline buffer */
- /* If the buffer passed to jpeg_read_scanlines() is less than this many rows
- * high, space and time will be wasted due to unnecessary data copying.
- * Usually rec_outbuf_height will be 1 or 2, at most 4.
- */
-
- /* When quantizing colors, the output colormap is described by these fields.
- * The application can supply a colormap by setting colormap non-NULL before
- * calling jpeg_start_decompress; otherwise a colormap is created during
- * jpeg_start_decompress or jpeg_start_output.
- * The map has out_color_components rows and actual_number_of_colors columns.
- */
- int actual_number_of_colors; /* number of entries in use */
- JSAMPARRAY colormap; /* The color map as a 2-D pixel array */
-
- /* State variables: these variables indicate the progress of decompression.
- * The application may examine these but must not modify them.
- */
-
- /* Row index of next scanline to be read from jpeg_read_scanlines().
- * Application may use this to control its processing loop, e.g.,
- * "while (output_scanline < output_height)".
- */
- JDIMENSION output_scanline; /* 0 .. output_height-1 */
-
- /* Current input scan number and number of iMCU rows completed in scan.
- * These indicate the progress of the decompressor input side.
- */
- int input_scan_number; /* Number of SOS markers seen so far */
- JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */
-
- /* The "output scan number" is the notional scan being displayed by the
- * output side. The decompressor will not allow output scan/row number
- * to get ahead of input scan/row, but it can fall arbitrarily far behind.
- */
- int output_scan_number; /* Nominal scan number being displayed */
- JDIMENSION output_iMCU_row; /* Number of iMCU rows read */
-
- /* Current progression status. coef_bits[c][i] indicates the precision
- * with which component c's DCT coefficient i (in zigzag order) is known.
- * It is -1 when no data has yet been received, otherwise it is the point
- * transform (shift) value for the most recent scan of the coefficient
- * (thus, 0 at completion of the progression).
- * This pointer is NULL when reading a non-progressive file.
- */
- int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */
-
- /* Internal JPEG parameters --- the application usually need not look at
- * these fields. Note that the decompressor output side may not use
- * any parameters that can change between scans.
- */
-
- /* Quantization and Huffman tables are carried forward across input
- * datastreams when processing abbreviated JPEG datastreams.
- */
-
- JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS];
- /* ptrs to coefficient quantization tables, or NULL if not defined */
-
- JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS];
- JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS];
- /* ptrs to Huffman coding tables, or NULL if not defined */
-
- /* These parameters are never carried across datastreams, since they
- * are given in SOF/SOS markers or defined to be reset by SOI.
- */
-
- int data_precision; /* bits of precision in image data */
-
- jpeg_component_info * comp_info;
- /* comp_info[i] describes component that appears i'th in SOF */
-
- boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */
- boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */
-
- UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */
- UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */
- UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */
-
- unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */
-
- /* These fields record data obtained from optional markers recognized by
- * the JPEG library.
- */
- boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */
- /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */
- UINT8 JFIF_major_version; /* JFIF version number */
- UINT8 JFIF_minor_version;
- UINT8 density_unit; /* JFIF code for pixel size units */
- UINT16 X_density; /* Horizontal pixel density */
- UINT16 Y_density; /* Vertical pixel density */
- boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */
- UINT8 Adobe_transform; /* Color transform code from Adobe marker */
-
- boolean CCIR601_sampling; /* TRUE=first samples are cosited */
-
- /* Aside from the specific data retained from APPn markers known to the
- * library, the uninterpreted contents of any or all APPn and COM markers
- * can be saved in a list for examination by the application.
- */
- jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */
-
- /* Remaining fields are known throughout decompressor, but generally
- * should not be touched by a surrounding application.
- */
-
- /*
- * These fields are computed during decompression startup
- */
- int max_h_samp_factor; /* largest h_samp_factor */
- int max_v_samp_factor; /* largest v_samp_factor */
-
- int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */
-
- JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */
- /* The coefficient controller's input and output progress is measured in
- * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows
- * in fully interleaved JPEG scans, but are used whether the scan is
- * interleaved or not. We define an iMCU row as v_samp_factor DCT block
- * rows of each component. Therefore, the IDCT output contains
- * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row.
- */
-
- JSAMPLE * sample_range_limit; /* table for fast range-limiting */
-
- /*
- * These fields are valid during any one scan.
- * They describe the components and MCUs actually appearing in the scan.
- * Note that the decompressor output side must not use these fields.
- */
- int comps_in_scan; /* # of JPEG components in this scan */
- jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN];
- /* *cur_comp_info[i] describes component that appears i'th in SOS */
-
- JDIMENSION MCUs_per_row; /* # of MCUs across the image */
- JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
-
- int blocks_in_MCU; /* # of DCT blocks per MCU */
- int MCU_membership[D_MAX_BLOCKS_IN_MCU];
- /* MCU_membership[i] is index in cur_comp_info of component owning */
- /* i'th block in an MCU */
-
- int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */
-
- /* This field is shared between entropy decoder and marker parser.
- * It is either zero or the code of a JPEG marker that has been
- * read from the data source, but has not yet been processed.
- */
- int unread_marker;
-
- /*
- * Links to decompression subobjects (methods, private variables of modules)
- */
- struct jpeg_decomp_master * master;
- struct jpeg_d_main_controller * main;
- struct jpeg_d_coef_controller * coef;
- struct jpeg_d_post_controller * post;
- struct jpeg_input_controller * inputctl;
- struct jpeg_marker_reader * marker;
- struct jpeg_entropy_decoder * entropy;
- struct jpeg_inverse_dct * idct;
- struct jpeg_upsampler * upsample;
- struct jpeg_color_deconverter * cconvert;
- struct jpeg_color_quantizer * cquantize;
-};
-
-
-/* "Object" declarations for JPEG modules that may be supplied or called
- * directly by the surrounding application.
- * As with all objects in the JPEG library, these structs only define the
- * publicly visible methods and state variables of a module. Additional
- * private fields may exist after the public ones.
- */
-
-
-/* Error handler object */
-
-struct jpeg_error_mgr {
- /* Error exit handler: does not return to caller */
- JMETHOD(void, error_exit, (j_common_ptr cinfo));
- /* Conditionally emit a trace or warning message */
- JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level));
- /* Routine that actually outputs a trace or error message */
- JMETHOD(void, output_message, (j_common_ptr cinfo));
- /* Format a message string for the most recent JPEG error or message */
- JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer));
-#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */
- /* Reset error state variables at start of a new image */
- JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo));
-
- /* The message ID code and any parameters are saved here.
- * A message can have one string parameter or up to 8 int parameters.
- */
- int msg_code;
-#define JMSG_STR_PARM_MAX 80
- union {
- int i[8];
- char s[JMSG_STR_PARM_MAX];
- } msg_parm;
-
- /* Standard state variables for error facility */
-
- int trace_level; /* max msg_level that will be displayed */
-
- /* For recoverable corrupt-data errors, we emit a warning message,
- * but keep going unless emit_message chooses to abort. emit_message
- * should count warnings in num_warnings. The surrounding application
- * can check for bad data by seeing if num_warnings is nonzero at the
- * end of processing.
- */
- long num_warnings; /* number of corrupt-data warnings */
-
- /* These fields point to the table(s) of error message strings.
- * An application can change the table pointer to switch to a different
- * message list (typically, to change the language in which errors are
- * reported). Some applications may wish to add additional error codes
- * that will be handled by the JPEG library error mechanism; the second
- * table pointer is used for this purpose.
- *
- * First table includes all errors generated by JPEG library itself.
- * Error code 0 is reserved for a "no such error string" message.
- */
- const char * const * jpeg_message_table; /* Library errors */
- int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */
- /* Second table can be added by application (see cjpeg/djpeg for example).
- * It contains strings numbered first_addon_message..last_addon_message.
- */
- const char * const * addon_message_table; /* Non-library errors */
- int first_addon_message; /* code for first string in addon table */
- int last_addon_message; /* code for last string in addon table */
-};
-
-
-/* Progress monitor object */
-
-struct jpeg_progress_mgr {
- JMETHOD(void, progress_monitor, (j_common_ptr cinfo));
-
- long pass_counter; /* work units completed in this pass */
- long pass_limit; /* total number of work units in this pass */
- int completed_passes; /* passes completed so far */
- int total_passes; /* total number of passes expected */
-};
-
-
-/* Data destination object for compression */
-
-struct jpeg_destination_mgr {
- JOCTET * next_output_byte; /* => next byte to write in buffer */
- size_t free_in_buffer; /* # of byte spaces remaining in buffer */
-
- JMETHOD(void, init_destination, (j_compress_ptr cinfo));
- JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo));
- JMETHOD(void, term_destination, (j_compress_ptr cinfo));
-};
-
-
-/* Data source object for decompression */
-
-struct jpeg_source_mgr {
- const JOCTET * next_input_byte; /* => next byte to read from buffer */
- size_t bytes_in_buffer; /* # of bytes remaining in buffer */
-
- JMETHOD(void, init_source, (j_decompress_ptr cinfo));
- JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo));
- JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes));
- JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired));
- JMETHOD(void, term_source, (j_decompress_ptr cinfo));
-};
-
-
-/* Memory manager object.
- * Allocates "small" objects (a few K total), "large" objects (tens of K),
- * and "really big" objects (virtual arrays with backing store if needed).
- * The memory manager does not allow individual objects to be freed; rather,
- * each created object is assigned to a pool, and whole pools can be freed
- * at once. This is faster and more convenient than remembering exactly what
- * to free, especially where malloc()/free() are not too speedy.
- * NB: alloc routines never return NULL. They exit to error_exit if not
- * successful.
- */
-
-#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */
-#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */
-#define JPOOL_NUMPOOLS 2
-
-typedef struct jvirt_sarray_control * jvirt_sarray_ptr;
-typedef struct jvirt_barray_control * jvirt_barray_ptr;
-
-
-struct jpeg_memory_mgr {
- /* Method pointers */
- JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id,
- size_t sizeofobject));
- JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id,
- size_t sizeofobject));
- JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id,
- JDIMENSION samplesperrow,
- JDIMENSION numrows));
- JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id,
- JDIMENSION blocksperrow,
- JDIMENSION numrows));
- JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo,
- int pool_id,
- boolean pre_zero,
- JDIMENSION samplesperrow,
- JDIMENSION numrows,
- JDIMENSION maxaccess));
- JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo,
- int pool_id,
- boolean pre_zero,
- JDIMENSION blocksperrow,
- JDIMENSION numrows,
- JDIMENSION maxaccess));
- JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo));
- JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo,
- jvirt_sarray_ptr ptr,
- JDIMENSION start_row,
- JDIMENSION num_rows,
- boolean writable));
- JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo,
- jvirt_barray_ptr ptr,
- JDIMENSION start_row,
- JDIMENSION num_rows,
- boolean writable));
- JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id));
- JMETHOD(void, self_destruct, (j_common_ptr cinfo));
-
- /* Limit on memory allocation for this JPEG object. (Note that this is
- * merely advisory, not a guaranteed maximum; it only affects the space
- * used for virtual-array buffers.) May be changed by outer application
- * after creating the JPEG object.
- */
- long max_memory_to_use;
-
- /* Maximum allocation request accepted by alloc_large. */
- long max_alloc_chunk;
-};
-
-
-/* Routine signature for application-supplied marker processing methods.
- * Need not pass marker code since it is stored in cinfo->unread_marker.
- */
-typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo));
-
-
-/* Declarations for routines called by application.
- * The JPP macro hides prototype parameters from compilers that can't cope.
- * Note JPP requires double parentheses.
- */
-
-#ifdef HAVE_PROTOTYPES
-#define JPP(arglist) arglist
-#else
-#define JPP(arglist) ()
-#endif
-
-
-/* Short forms of external names for systems with brain-damaged linkers.
- * We shorten external names to be unique in the first six letters, which
- * is good enough for all known systems.
- * (If your compiler itself needs names to be unique in less than 15
- * characters, you are out of luck. Get a better compiler.)
- */
-
-#ifdef NEED_SHORT_EXTERNAL_NAMES
-#define jpeg_std_error jStdError
-#define jpeg_CreateCompress jCreaCompress
-#define jpeg_CreateDecompress jCreaDecompress
-#define jpeg_destroy_compress jDestCompress
-#define jpeg_destroy_decompress jDestDecompress
-#define jpeg_stdio_dest jStdDest
-#define jpeg_mem_src jMemSrc
-#define jpeg_set_defaults jSetDefaults
-#define jpeg_set_colorspace jSetColorspace
-#define jpeg_default_colorspace jDefColorspace
-#define jpeg_set_quality jSetQuality
-#define jpeg_set_linear_quality jSetLQuality
-#define jpeg_add_quant_table jAddQuantTable
-#define jpeg_quality_scaling jQualityScaling
-#define jpeg_simple_progression jSimProgress
-#define jpeg_suppress_tables jSuppressTables
-#define jpeg_alloc_quant_table jAlcQTable
-#define jpeg_alloc_huff_table jAlcHTable
-#define jpeg_start_compress jStrtCompress
-#define jpeg_write_scanlines jWrtScanlines
-#define jpeg_finish_compress jFinCompress
-#define jpeg_write_raw_data jWrtRawData
-#define jpeg_write_marker jWrtMarker
-#define jpeg_write_m_header jWrtMHeader
-#define jpeg_write_m_byte jWrtMByte
-#define jpeg_write_tables jWrtTables
-#define jpeg_read_header jReadHeader
-#define jpeg_start_decompress jStrtDecompress
-#define jpeg_read_scanlines jReadScanlines
-#define jpeg_finish_decompress jFinDecompress
-#define jpeg_read_raw_data jReadRawData
-#define jpeg_has_multiple_scans jHasMultScn
-#define jpeg_start_output jStrtOutput
-#define jpeg_finish_output jFinOutput
-#define jpeg_input_complete jInComplete
-#define jpeg_new_colormap jNewCMap
-#define jpeg_consume_input jConsumeInput
-#define jpeg_calc_output_dimensions jCalcDimensions
-#define jpeg_save_markers jSaveMarkers
-#define jpeg_set_marker_processor jSetMarker
-#define jpeg_read_coefficients jReadCoefs
-#define jpeg_write_coefficients jWrtCoefs
-#define jpeg_copy_critical_parameters jCopyCrit
-#define jpeg_abort_compress jAbrtCompress
-#define jpeg_abort_decompress jAbrtDecompress
-#define jpeg_abort jAbort
-#define jpeg_destroy jDestroy
-#define jpeg_resync_to_restart jResyncRestart
-#endif /* NEED_SHORT_EXTERNAL_NAMES */
-
-
-/* Default error-management setup */
-EXTERN(struct jpeg_error_mgr *) jpeg_std_error
- JPP((struct jpeg_error_mgr * err));
-
-/* Initialization of JPEG compression objects.
- * jpeg_create_compress() and jpeg_create_decompress() are the exported
- * names that applications should call. These expand to calls on
- * jpeg_CreateCompress and jpeg_CreateDecompress with additional information
- * passed for version mismatch checking.
- * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx.
- */
-#define jpeg_create_compress(cinfo) \
- jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \
- (size_t) sizeof(struct jpeg_compress_struct))
-#define jpeg_create_decompress(cinfo) \
- jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \
- (size_t) sizeof(struct jpeg_decompress_struct))
-EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo,
- int version, size_t structsize));
-EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo,
- int version, size_t structsize));
-/* Destruction of JPEG compression objects */
-EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo));
-EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo));
-
-/* Standard data source and destination managers: stdio streams. */
-/* Caller is responsible for opening the file before and closing after. */
-EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile));
-EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo, unsigned char *inbuf, size_t size));
-
-/* Default parameter setup for compression */
-EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo));
-/* Compression parameter setup aids */
-EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo,
- J_COLOR_SPACE colorspace));
-EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo));
-EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality,
- boolean force_baseline));
-EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo,
- int scale_factor,
- boolean force_baseline));
-EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl,
- const unsigned int *basic_table,
- int scale_factor,
- boolean force_baseline));
-EXTERN(int) jpeg_quality_scaling JPP((int quality));
-EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo));
-EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo,
- boolean suppress));
-EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo));
-EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo));
-
-/* Main entry points for compression */
-EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo,
- boolean write_all_tables));
-EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo,
- JSAMPARRAY scanlines,
- JDIMENSION num_lines));
-EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo));
-
-/* Replaces jpeg_write_scanlines when writing raw downsampled data. */
-EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo,
- JSAMPIMAGE data,
- JDIMENSION num_lines));
-
-/* Write a special marker. See libjpeg.doc concerning safe usage. */
-EXTERN(void) jpeg_write_marker
- JPP((j_compress_ptr cinfo, int marker,
- const JOCTET * dataptr, unsigned int datalen));
-/* Same, but piecemeal. */
-EXTERN(void) jpeg_write_m_header
- JPP((j_compress_ptr cinfo, int marker, unsigned int datalen));
-EXTERN(void) jpeg_write_m_byte
- JPP((j_compress_ptr cinfo, int val));
-
-/* Alternate compression function: just write an abbreviated table file */
-EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo));
-
-/* Decompression startup: read start of JPEG datastream to see what's there */
-EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo,
- boolean require_image));
-/* Return value is one of: */
-#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */
-#define JPEG_HEADER_OK 1 /* Found valid image datastream */
-#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */
-/* If you pass require_image = TRUE (normal case), you need not check for
- * a TABLES_ONLY return code; an abbreviated file will cause an error exit.
- * JPEG_SUSPENDED is only possible if you use a data source module that can
- * give a suspension return (the stdio source module doesn't).
- */
-
-/* Main entry points for decompression */
-EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo));
-EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo,
- JSAMPARRAY scanlines,
- JDIMENSION max_lines));
-EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo));
-
-/* Replaces jpeg_read_scanlines when reading raw downsampled data. */
-EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo,
- JSAMPIMAGE data,
- JDIMENSION max_lines));
-
-/* Additional entry points for buffered-image mode. */
-EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo));
-EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo,
- int scan_number));
-EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo));
-EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo));
-EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo));
-EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo));
-/* Return value is one of: */
-/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */
-#define JPEG_REACHED_SOS 1 /* Reached start of new scan */
-#define JPEG_REACHED_EOI 2 /* Reached end of image */
-#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */
-#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */
-
-/* Precalculate output dimensions for current decompression parameters. */
-EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo));
-
-/* Control saving of COM and APPn markers into marker_list. */
-EXTERN(void) jpeg_save_markers
- JPP((j_decompress_ptr cinfo, int marker_code,
- unsigned int length_limit));
-
-/* Install a special processing method for COM or APPn markers. */
-EXTERN(void) jpeg_set_marker_processor
- JPP((j_decompress_ptr cinfo, int marker_code,
- jpeg_marker_parser_method routine));
-
-/* Read or write raw DCT coefficients --- useful for lossless transcoding. */
-EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo));
-EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo,
- jvirt_barray_ptr * coef_arrays));
-EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo,
- j_compress_ptr dstinfo));
-
-/* If you choose to abort compression or decompression before completing
- * jpeg_finish_(de)compress, then you need to clean up to release memory,
- * temporary files, etc. You can just call jpeg_destroy_(de)compress
- * if you're done with the JPEG object, but if you want to clean it up and
- * reuse it, call this:
- */
-EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo));
-EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo));
-
-/* Generic versions of jpeg_abort and jpeg_destroy that work on either
- * flavor of JPEG object. These may be more convenient in some places.
- */
-EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo));
-EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo));
-
-/* Default restart-marker-resync procedure for use by data source modules */
-EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo,
- int desired));
-
-
-/* These marker codes are exported since applications and data source modules
- * are likely to want to use them.
- */
-
-#define JPEG_RST0 0xD0 /* RST0 marker code */
-#define JPEG_EOI 0xD9 /* EOI marker code */
-#define JPEG_APP0 0xE0 /* APP0 marker code */
-#define JPEG_COM 0xFE /* COM marker code */
-
-
-/* If we have a brain-damaged compiler that emits warnings (or worse, errors)
- * for structure definitions that are never filled in, keep it quiet by
- * supplying dummy definitions for the various substructures.
- */
-
-#ifdef INCOMPLETE_TYPES_BROKEN
-#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */
-struct jvirt_sarray_control { long dummy; };
-struct jvirt_barray_control { long dummy; };
-struct jpeg_comp_master { long dummy; };
-struct jpeg_c_main_controller { long dummy; };
-struct jpeg_c_prep_controller { long dummy; };
-struct jpeg_c_coef_controller { long dummy; };
-struct jpeg_marker_writer { long dummy; };
-struct jpeg_color_converter { long dummy; };
-struct jpeg_downsampler { long dummy; };
-struct jpeg_forward_dct { long dummy; };
-struct jpeg_entropy_encoder { long dummy; };
-struct jpeg_decomp_master { long dummy; };
-struct jpeg_d_main_controller { long dummy; };
-struct jpeg_d_coef_controller { long dummy; };
-struct jpeg_d_post_controller { long dummy; };
-struct jpeg_input_controller { long dummy; };
-struct jpeg_marker_reader { long dummy; };
-struct jpeg_entropy_decoder { long dummy; };
-struct jpeg_inverse_dct { long dummy; };
-struct jpeg_upsampler { long dummy; };
-struct jpeg_color_deconverter { long dummy; };
-struct jpeg_color_quantizer { long dummy; };
-#endif /* JPEG_INTERNALS */
-#endif /* INCOMPLETE_TYPES_BROKEN */
-
-
-/*
- * The JPEG library modules define JPEG_INTERNALS before including this file.
- * The internal structure declarations are read only when that is true.
- * Applications using the library should not include jpegint.h, but may wish
- * to include jerror.h.
- */
-
-#ifdef JPEG_INTERNALS
-#include "../jpeg-6b/jpegint.h" /* fetch private declarations */
-#include "../jpeg-6b/jerror.h" /* fetch error codes too */
-#endif
-
-#endif /* JPEGLIB_H */
diff --git a/engine/code/jpeg-6b/jpegtran.c b/engine/code/jpeg-6b/jpegtran.c
deleted file mode 100644
index 20ef111..0000000
--- a/engine/code/jpeg-6b/jpegtran.c
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * jpegtran.c
- *
- * Copyright (C) 1995-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains a command-line user interface for JPEG transcoding.
- * It is very similar to cjpeg.c, but provides lossless transcoding between
- * different JPEG file formats. It also provides some lossless and sort-of-
- * lossless transformations of JPEG data.
- */
-
-#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
-#include "transupp.h" /* Support routines for jpegtran */
-#include "jversion.h" /* for version message */
-
-#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
-#ifdef __MWERKS__
-#include <SIOUX.h> /* Metrowerks needs this */
-#include <console.h> /* ... and this */
-#endif
-#ifdef THINK_C
-#include <console.h> /* Think declares it here */
-#endif
-#endif
-
-
-/*
- * Argument-parsing code.
- * The switch parser is designed to be useful with DOS-style command line
- * syntax, ie, intermixed switches and file names, where only the switches
- * to the left of a given file name affect processing of that file.
- * The main program in this file doesn't actually use this capability...
- */
-
-
-static const char * progname; /* program name for error messages */
-static char * outfilename; /* for -outfile switch */
-static JCOPY_OPTION copyoption; /* -copy switch */
-static jpeg_transform_info transformoption; /* image transformation options */
-
-
-LOCAL(void)
-usage (void)
-/* complain about bad command line */
-{
- fprintf(stderr, "usage: %s [switches] ", progname);
-#ifdef TWO_FILE_COMMANDLINE
- fprintf(stderr, "inputfile outputfile\n");
-#else
- fprintf(stderr, "[inputfile]\n");
-#endif
-
- fprintf(stderr, "Switches (names may be abbreviated):\n");
- fprintf(stderr, " -copy none Copy no extra markers from source file\n");
- fprintf(stderr, " -copy comments Copy only comment markers (default)\n");
- fprintf(stderr, " -copy all Copy all extra markers\n");
-#ifdef ENTROPY_OPT_SUPPORTED
- fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n");
-#endif
-#ifdef C_PROGRESSIVE_SUPPORTED
- fprintf(stderr, " -progressive Create progressive JPEG file\n");
-#endif
-#if TRANSFORMS_SUPPORTED
- fprintf(stderr, "Switches for modifying the image:\n");
- fprintf(stderr, " -grayscale Reduce to grayscale (omit color data)\n");
- fprintf(stderr, " -flip [horizontal|vertical] Mirror image (left-right or top-bottom)\n");
- fprintf(stderr, " -rotate [90|180|270] Rotate image (degrees clockwise)\n");
- fprintf(stderr, " -transpose Transpose image\n");
- fprintf(stderr, " -transverse Transverse transpose image\n");
- fprintf(stderr, " -trim Drop non-transformable edge blocks\n");
-#endif /* TRANSFORMS_SUPPORTED */
- fprintf(stderr, "Switches for advanced users:\n");
- fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n");
- fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
- fprintf(stderr, " -outfile name Specify name for output file\n");
- fprintf(stderr, " -verbose or -debug Emit debug output\n");
- fprintf(stderr, "Switches for wizards:\n");
-#ifdef C_ARITH_CODING_SUPPORTED
- fprintf(stderr, " -arithmetic Use arithmetic coding\n");
-#endif
-#ifdef C_MULTISCAN_FILES_SUPPORTED
- fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n");
-#endif
- exit(EXIT_FAILURE);
-}
-
-
-LOCAL(void)
-select_transform (JXFORM_CODE transform)
-/* Silly little routine to detect multiple transform options,
- * which we can't handle.
- */
-{
-#if TRANSFORMS_SUPPORTED
- if (transformoption.transform == JXFORM_NONE ||
- transformoption.transform == transform) {
- transformoption.transform = transform;
- } else {
- fprintf(stderr, "%s: can only do one image transformation at a time\n",
- progname);
- usage();
- }
-#else
- fprintf(stderr, "%s: sorry, image transformation was not compiled\n",
- progname);
- exit(EXIT_FAILURE);
-#endif
-}
-
-
-LOCAL(int)
-parse_switches (j_compress_ptr cinfo, int argc, char **argv,
- int last_file_arg_seen, boolean for_real)
-/* Parse optional switches.
- * Returns argv[] index of first file-name argument (== argc if none).
- * Any file names with indexes <= last_file_arg_seen are ignored;
- * they have presumably been processed in a previous iteration.
- * (Pass 0 for last_file_arg_seen on the first or only iteration.)
- * for_real is FALSE on the first (dummy) pass; we may skip any expensive
- * processing.
- */
-{
- int argn;
- char * arg;
- boolean simple_progressive;
- char * scansarg = NULL; /* saves -scans parm if any */
-
- /* Set up default JPEG parameters. */
- simple_progressive = FALSE;
- outfilename = NULL;
- copyoption = JCOPYOPT_DEFAULT;
- transformoption.transform = JXFORM_NONE;
- transformoption.trim = FALSE;
- transformoption.force_grayscale = FALSE;
- cinfo->err->trace_level = 0;
-
- /* Scan command line options, adjust parameters */
-
- for (argn = 1; argn < argc; argn++) {
- arg = argv[argn];
- if (*arg != '-') {
- /* Not a switch, must be a file name argument */
- if (argn <= last_file_arg_seen) {
- outfilename = NULL; /* -outfile applies to just one input file */
- continue; /* ignore this name if previously processed */
- }
- break; /* else done parsing switches */
- }
- arg++; /* advance past switch marker character */
-
- if (keymatch(arg, "arithmetic", 1)) {
- /* Use arithmetic coding. */
-#ifdef C_ARITH_CODING_SUPPORTED
- cinfo->arith_code = TRUE;
-#else
- fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
- progname);
- exit(EXIT_FAILURE);
-#endif
-
- } else if (keymatch(arg, "copy", 1)) {
- /* Select which extra markers to copy. */
- if (++argn >= argc) /* advance to next argument */
- usage();
- if (keymatch(argv[argn], "none", 1)) {
- copyoption = JCOPYOPT_NONE;
- } else if (keymatch(argv[argn], "comments", 1)) {
- copyoption = JCOPYOPT_COMMENTS;
- } else if (keymatch(argv[argn], "all", 1)) {
- copyoption = JCOPYOPT_ALL;
- } else
- usage();
-
- } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
- /* Enable debug printouts. */
- /* On first -d, print version identification */
- static boolean printed_version = FALSE;
-
- if (! printed_version) {
- fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n",
- JVERSION, JCOPYRIGHT);
- printed_version = TRUE;
- }
- cinfo->err->trace_level++;
-
- } else if (keymatch(arg, "flip", 1)) {
- /* Mirror left-right or top-bottom. */
- if (++argn >= argc) /* advance to next argument */
- usage();
- if (keymatch(argv[argn], "horizontal", 1))
- select_transform(JXFORM_FLIP_H);
- else if (keymatch(argv[argn], "vertical", 1))
- select_transform(JXFORM_FLIP_V);
- else
- usage();
-
- } else if (keymatch(arg, "grayscale", 1) || keymatch(arg, "greyscale",1)) {
- /* Force to grayscale. */
-#if TRANSFORMS_SUPPORTED
- transformoption.force_grayscale = TRUE;
-#else
- select_transform(JXFORM_NONE); /* force an error */
-#endif
-
- } else if (keymatch(arg, "maxmemory", 3)) {
- /* Maximum memory in Kb (or Mb with 'm'). */
- long lval;
- char ch = 'x';
-
- if (++argn >= argc) /* advance to next argument */
- usage();
- if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
- usage();
- if (ch == 'm' || ch == 'M')
- lval *= 1000L;
- cinfo->mem->max_memory_to_use = lval * 1000L;
-
- } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
- /* Enable entropy parm optimization. */
-#ifdef ENTROPY_OPT_SUPPORTED
- cinfo->optimize_coding = TRUE;
-#else
- fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
- progname);
- exit(EXIT_FAILURE);
-#endif
-
- } else if (keymatch(arg, "outfile", 4)) {
- /* Set output file name. */
- if (++argn >= argc) /* advance to next argument */
- usage();
- outfilename = argv[argn]; /* save it away for later use */
-
- } else if (keymatch(arg, "progressive", 1)) {
- /* Select simple progressive mode. */
-#ifdef C_PROGRESSIVE_SUPPORTED
- simple_progressive = TRUE;
- /* We must postpone execution until num_components is known. */
-#else
- fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
- progname);
- exit(EXIT_FAILURE);
-#endif
-
- } else if (keymatch(arg, "restart", 1)) {
- /* Restart interval in MCU rows (or in MCUs with 'b'). */
- long lval;
- char ch = 'x';
-
- if (++argn >= argc) /* advance to next argument */
- usage();
- if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
- usage();
- if (lval < 0 || lval > 65535L)
- usage();
- if (ch == 'b' || ch == 'B') {
- cinfo->restart_interval = (unsigned int) lval;
- cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
- } else {
- cinfo->restart_in_rows = (int) lval;
- /* restart_interval will be computed during startup */
- }
-
- } else if (keymatch(arg, "rotate", 2)) {
- /* Rotate 90, 180, or 270 degrees (measured clockwise). */
- if (++argn >= argc) /* advance to next argument */
- usage();
- if (keymatch(argv[argn], "90", 2))
- select_transform(JXFORM_ROT_90);
- else if (keymatch(argv[argn], "180", 3))
- select_transform(JXFORM_ROT_180);
- else if (keymatch(argv[argn], "270", 3))
- select_transform(JXFORM_ROT_270);
- else
- usage();
-
- } else if (keymatch(arg, "scans", 1)) {
- /* Set scan script. */
-#ifdef C_MULTISCAN_FILES_SUPPORTED
- if (++argn >= argc) /* advance to next argument */
- usage();
- scansarg = argv[argn];
- /* We must postpone reading the file in case -progressive appears. */
-#else
- fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
- progname);
- exit(EXIT_FAILURE);
-#endif
-
- } else if (keymatch(arg, "transpose", 1)) {
- /* Transpose (across UL-to-LR axis). */
- select_transform(JXFORM_TRANSPOSE);
-
- } else if (keymatch(arg, "transverse", 6)) {
- /* Transverse transpose (across UR-to-LL axis). */
- select_transform(JXFORM_TRANSVERSE);
-
- } else if (keymatch(arg, "trim", 3)) {
- /* Trim off any partial edge MCUs that the transform can't handle. */
- transformoption.trim = TRUE;
-
- } else {
- usage(); /* bogus switch */
- }
- }
-
- /* Post-switch-scanning cleanup */
-
- if (for_real) {
-
-#ifdef C_PROGRESSIVE_SUPPORTED
- if (simple_progressive) /* process -progressive; -scans can override */
- jpeg_simple_progression(cinfo);
-#endif
-
-#ifdef C_MULTISCAN_FILES_SUPPORTED
- if (scansarg != NULL) /* process -scans if it was present */
- if (! read_scan_script(cinfo, scansarg))
- usage();
-#endif
- }
-
- return argn; /* return index of next arg (file name) */
-}
-
-
-/*
- * The main program.
- */
-
-int
-main (int argc, char **argv)
-{
- struct jpeg_decompress_struct srcinfo;
- struct jpeg_compress_struct dstinfo;
- struct jpeg_error_mgr jsrcerr, jdsterr;
-#ifdef PROGRESS_REPORT
- struct cdjpeg_progress_mgr progress;
-#endif
- jvirt_barray_ptr * src_coef_arrays;
- jvirt_barray_ptr * dst_coef_arrays;
- int file_index;
- FILE * input_file;
- FILE * output_file;
-
- /* On Mac, fetch a command line. */
-#ifdef USE_CCOMMAND
- argc = ccommand(&argv);
-#endif
-
- progname = argv[0];
- if (progname == NULL || progname[0] == 0)
- progname = "jpegtran"; /* in case C library doesn't provide it */
-
- /* Initialize the JPEG decompression object with default error handling. */
- srcinfo.err = jpeg_std_error(&jsrcerr);
- jpeg_create_decompress(&srcinfo);
- /* Initialize the JPEG compression object with default error handling. */
- dstinfo.err = jpeg_std_error(&jdsterr);
- jpeg_create_compress(&dstinfo);
-
- /* Now safe to enable signal catcher.
- * Note: we assume only the decompression object will have virtual arrays.
- */
-#ifdef NEED_SIGNAL_CATCHER
- enable_signal_catcher((j_common_ptr) &srcinfo);
-#endif
-
- /* Scan command line to find file names.
- * It is convenient to use just one switch-parsing routine, but the switch
- * values read here are mostly ignored; we will rescan the switches after
- * opening the input file. Also note that most of the switches affect the
- * destination JPEG object, so we parse into that and then copy over what
- * needs to affects the source too.
- */
-
- file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE);
- jsrcerr.trace_level = jdsterr.trace_level;
- srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;
-
-#ifdef TWO_FILE_COMMANDLINE
- /* Must have either -outfile switch or explicit output file name */
- if (outfilename == NULL) {
- if (file_index != argc-2) {
- fprintf(stderr, "%s: must name one input and one output file\n",
- progname);
- usage();
- }
- outfilename = argv[file_index+1];
- } else {
- if (file_index != argc-1) {
- fprintf(stderr, "%s: must name one input and one output file\n",
- progname);
- usage();
- }
- }
-#else
- /* Unix style: expect zero or one file name */
- if (file_index < argc-1) {
- fprintf(stderr, "%s: only one input file\n", progname);
- usage();
- }
-#endif /* TWO_FILE_COMMANDLINE */
-
- /* Open the input file. */
- if (file_index < argc) {
- if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
- fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
- exit(EXIT_FAILURE);
- }
- } else {
- /* default input file is stdin */
- input_file = read_stdin();
- }
-
- /* Open the output file. */
- if (outfilename != NULL) {
- if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
- fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
- exit(EXIT_FAILURE);
- }
- } else {
- /* default output file is stdout */
- output_file = write_stdout();
- }
-
-#ifdef PROGRESS_REPORT
- start_progress_monitor((j_common_ptr) &dstinfo, &progress);
-#endif
-
- /* Specify data source for decompression */
- jpeg_stdio_src(&srcinfo, input_file);
-
- /* Enable saving of extra markers that we want to copy */
- jcopy_markers_setup(&srcinfo, copyoption);
-
- /* Read file header */
- (void) jpeg_read_header(&srcinfo, TRUE);
-
- /* Any space needed by a transform option must be requested before
- * jpeg_read_coefficients so that memory allocation will be done right.
- */
-#if TRANSFORMS_SUPPORTED
- jtransform_request_workspace(&srcinfo, &transformoption);
-#endif
-
- /* Read source file as DCT coefficients */
- src_coef_arrays = jpeg_read_coefficients(&srcinfo);
-
- /* Initialize destination compression parameters from source values */
- jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
-
- /* Adjust destination parameters if required by transform options;
- * also find out which set of coefficient arrays will hold the output.
- */
-#if TRANSFORMS_SUPPORTED
- dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo,
- src_coef_arrays,
- &transformoption);
-#else
- dst_coef_arrays = src_coef_arrays;
-#endif
-
- /* Adjust default compression parameters by re-parsing the options */
- file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
-
- /* Specify data destination for compression */
- jpeg_stdio_dest(&dstinfo, output_file);
-
- /* Start compressor (note no image data is actually written here) */
- jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
-
- /* Copy to the output file any extra markers that we want to preserve */
- jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);
-
- /* Execute image transformation, if any */
-#if TRANSFORMS_SUPPORTED
- jtransform_execute_transformation(&srcinfo, &dstinfo,
- src_coef_arrays,
- &transformoption);
-#endif
-
- /* Finish compression and release memory */
- jpeg_finish_compress(&dstinfo);
- jpeg_destroy_compress(&dstinfo);
- (void) jpeg_finish_decompress(&srcinfo);
- jpeg_destroy_decompress(&srcinfo);
-
- /* Close files, if we opened them */
- if (input_file != stdin)
- fclose(input_file);
- if (output_file != stdout)
- fclose(output_file);
-
-#ifdef PROGRESS_REPORT
- end_progress_monitor((j_common_ptr) &dstinfo);
-#endif
-
- /* All done. */
- exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS);
- return 0; /* suppress no-return-value warnings */
-}
diff --git a/engine/code/jpeg-6b/jquant1.c b/engine/code/jpeg-6b/jquant1.c
deleted file mode 100644
index b2f96aa..0000000
--- a/engine/code/jpeg-6b/jquant1.c
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- * jquant1.c
- *
- * Copyright (C) 1991-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains 1-pass color quantization (color mapping) routines.
- * These routines provide mapping to a fixed color map using equally spaced
- * color values. Optional Floyd-Steinberg or ordered dithering is available.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-#ifdef QUANT_1PASS_SUPPORTED
-
-
-/*
- * The main purpose of 1-pass quantization is to provide a fast, if not very
- * high quality, colormapped output capability. A 2-pass quantizer usually
- * gives better visual quality; however, for quantized grayscale output this
- * quantizer is perfectly adequate. Dithering is highly recommended with this
- * quantizer, though you can turn it off if you really want to.
- *
- * In 1-pass quantization the colormap must be chosen in advance of seeing the
- * image. We use a map consisting of all combinations of Ncolors[i] color
- * values for the i'th component. The Ncolors[] values are chosen so that
- * their product, the total number of colors, is no more than that requested.
- * (In most cases, the product will be somewhat less.)
- *
- * Since the colormap is orthogonal, the representative value for each color
- * component can be determined without considering the other components;
- * then these indexes can be combined into a colormap index by a standard
- * N-dimensional-array-subscript calculation. Most of the arithmetic involved
- * can be precalculated and stored in the lookup table colorindex[].
- * colorindex[i][j] maps pixel value j in component i to the nearest
- * representative value (grid plane) for that component; this index is
- * multiplied by the array stride for component i, so that the
- * index of the colormap entry closest to a given pixel value is just
- * sum( colorindex[component-number][pixel-component-value] )
- * Aside from being fast, this scheme allows for variable spacing between
- * representative values with no additional lookup cost.
- *
- * If gamma correction has been applied in color conversion, it might be wise
- * to adjust the color grid spacing so that the representative colors are
- * equidistant in linear space. At this writing, gamma correction is not
- * implemented by jdcolor, so nothing is done here.
- */
-
-
-/* Declarations for ordered dithering.
- *
- * We use a standard 16x16 ordered dither array. The basic concept of ordered
- * dithering is described in many references, for instance Dale Schumacher's
- * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991).
- * In place of Schumacher's comparisons against a "threshold" value, we add a
- * "dither" value to the input pixel and then round the result to the nearest
- * output value. The dither value is equivalent to (0.5 - threshold) times
- * the distance between output values. For ordered dithering, we assume that
- * the output colors are equally spaced; if not, results will probably be
- * worse, since the dither may be too much or too little at a given point.
- *
- * The normal calculation would be to form pixel value + dither, range-limit
- * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual.
- * We can skip the separate range-limiting step by extending the colorindex
- * table in both directions.
- */
-
-#define ODITHER_SIZE 16 /* dimension of dither matrix */
-/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */
-#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE) /* # cells in matrix */
-#define ODITHER_MASK (ODITHER_SIZE-1) /* mask for wrapping around counters */
-
-typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE];
-typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE];
-
-static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = {
- /* Bayer's order-4 dither array. Generated by the code given in
- * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I.
- * The values in this array must range from 0 to ODITHER_CELLS-1.
- */
- { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
- { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
- { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
- { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
- { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
- { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
- { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
- { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
- { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
- { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
- { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
- { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
- { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
- { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
- { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
- { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
-};
-
-
-/* Declarations for Floyd-Steinberg dithering.
- *
- * Errors are accumulated into the array fserrors[], at a resolution of
- * 1/16th of a pixel count. The error at a given pixel is propagated
- * to its not-yet-processed neighbors using the standard F-S fractions,
- * ... (here) 7/16
- * 3/16 5/16 1/16
- * We work left-to-right on even rows, right-to-left on odd rows.
- *
- * We can get away with a single array (holding one row's worth of errors)
- * by using it to store the current row's errors at pixel columns not yet
- * processed, but the next row's errors at columns already processed. We
- * need only a few extra variables to hold the errors immediately around the
- * current column. (If we are lucky, those variables are in registers, but
- * even if not, they're probably cheaper to access than array elements are.)
- *
- * The fserrors[] array is indexed [component#][position].
- * We provide (#columns + 2) entries per component; the extra entry at each
- * end saves us from special-casing the first and last pixels.
- *
- * Note: on a wide image, we might not have enough room in a PC's near data
- * segment to hold the error array; so it is allocated with alloc_large.
- */
-
-#if BITS_IN_JSAMPLE == 8
-typedef INT16 FSERROR; /* 16 bits should be enough */
-typedef int LOCFSERROR; /* use 'int' for calculation temps */
-#else
-typedef INT32 FSERROR; /* may need more than 16 bits */
-typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */
-#endif
-
-typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */
-
-
-/* Private subobject */
-
-#define MAX_Q_COMPS 4 /* max components I can handle */
-
-typedef struct {
- struct jpeg_color_quantizer pub; /* public fields */
-
- /* Initially allocated colormap is saved here */
- JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */
- int sv_actual; /* number of entries in use */
-
- JSAMPARRAY colorindex; /* Precomputed mapping for speed */
- /* colorindex[i][j] = index of color closest to pixel value j in component i,
- * premultiplied as described above. Since colormap indexes must fit into
- * JSAMPLEs, the entries of this array will too.
- */
- boolean is_padded; /* is the colorindex padded for odither? */
-
- int Ncolors[MAX_Q_COMPS]; /* # of values alloced to each component */
-
- /* Variables for ordered dithering */
- int row_index; /* cur row's vertical index in dither matrix */
- ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */
-
- /* Variables for Floyd-Steinberg dithering */
- FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */
- boolean on_odd_row; /* flag to remember which row we are on */
-} my_cquantizer;
-
-typedef my_cquantizer * my_cquantize_ptr;
-
-
-/*
- * Policy-making subroutines for create_colormap and create_colorindex.
- * These routines determine the colormap to be used. The rest of the module
- * only assumes that the colormap is orthogonal.
- *
- * * select_ncolors decides how to divvy up the available colors
- * among the components.
- * * output_value defines the set of representative values for a component.
- * * largest_input_value defines the mapping from input values to
- * representative values for a component.
- * Note that the latter two routines may impose different policies for
- * different components, though this is not currently done.
- */
-
-
-LOCAL(int)
-select_ncolors (j_decompress_ptr cinfo, int Ncolors[])
-/* Determine allocation of desired colors to components, */
-/* and fill in Ncolors[] array to indicate choice. */
-/* Return value is total number of colors (product of Ncolors[] values). */
-{
- int nc = cinfo->out_color_components; /* number of color components */
- int max_colors = cinfo->desired_number_of_colors;
- int total_colors, iroot, i, j;
- boolean changed;
- long temp;
- static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE };
-
- /* We can allocate at least the nc'th root of max_colors per component. */
- /* Compute floor(nc'th root of max_colors). */
- iroot = 1;
- do {
- iroot++;
- temp = iroot; /* set temp = iroot ** nc */
- for (i = 1; i < nc; i++)
- temp *= iroot;
- } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */
- iroot--; /* now iroot = floor(root) */
-
- /* Must have at least 2 color values per component */
- if (iroot < 2)
- ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp);
-
- /* Initialize to iroot color values for each component */
- total_colors = 1;
- for (i = 0; i < nc; i++) {
- Ncolors[i] = iroot;
- total_colors *= iroot;
- }
- /* We may be able to increment the count for one or more components without
- * exceeding max_colors, though we know not all can be incremented.
- * Sometimes, the first component can be incremented more than once!
- * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.)
- * In RGB colorspace, try to increment G first, then R, then B.
- */
- do {
- changed = FALSE;
- for (i = 0; i < nc; i++) {
- j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i);
- /* calculate new total_colors if Ncolors[j] is incremented */
- temp = total_colors / Ncolors[j];
- temp *= Ncolors[j]+1; /* done in long arith to avoid oflo */
- if (temp > (long) max_colors)
- break; /* won't fit, done with this pass */
- Ncolors[j]++; /* OK, apply the increment */
- total_colors = (int) temp;
- changed = TRUE;
- }
- } while (changed);
-
- return total_colors;
-}
-
-
-LOCAL(int)
-output_value (j_decompress_ptr cinfo, int ci, int j, int maxj)
-/* Return j'th output value, where j will range from 0 to maxj */
-/* The output values must fall in 0..MAXJSAMPLE in increasing order */
-{
- /* We always provide values 0 and MAXJSAMPLE for each component;
- * any additional values are equally spaced between these limits.
- * (Forcing the upper and lower values to the limits ensures that
- * dithering can't produce a color outside the selected gamut.)
- */
- return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj);
-}
-
-
-LOCAL(int)
-largest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj)
-/* Return largest input value that should map to j'th output value */
-/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */
-{
- /* Breakpoints are halfway between values returned by output_value */
- return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj));
-}
-
-
-/*
- * Create the colormap.
- */
-
-LOCAL(void)
-create_colormap (j_decompress_ptr cinfo)
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- JSAMPARRAY colormap; /* Created colormap */
- int total_colors; /* Number of distinct output colors */
- int i,j,k, nci, blksize, blkdist, ptr, val;
-
- /* Select number of colors for each component */
- total_colors = select_ncolors(cinfo, cquantize->Ncolors);
-
- /* Report selected color counts */
- if (cinfo->out_color_components == 3)
- TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS,
- total_colors, cquantize->Ncolors[0],
- cquantize->Ncolors[1], cquantize->Ncolors[2]);
- else
- TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors);
-
- /* Allocate and fill in the colormap. */
- /* The colors are ordered in the map in standard row-major order, */
- /* i.e. rightmost (highest-indexed) color changes most rapidly. */
-
- colormap = (*cinfo->mem->alloc_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components);
-
- /* blksize is number of adjacent repeated entries for a component */
- /* blkdist is distance between groups of identical entries for a component */
- blkdist = total_colors;
-
- for (i = 0; i < cinfo->out_color_components; i++) {
- /* fill in colormap entries for i'th color component */
- nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
- blksize = blkdist / nci;
- for (j = 0; j < nci; j++) {
- /* Compute j'th output value (out of nci) for component */
- val = output_value(cinfo, i, j, nci-1);
- /* Fill in all colormap entries that have this value of this component */
- for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) {
- /* fill in blksize entries beginning at ptr */
- for (k = 0; k < blksize; k++)
- colormap[i][ptr+k] = (JSAMPLE) val;
- }
- }
- blkdist = blksize; /* blksize of this color is blkdist of next */
- }
-
- /* Save the colormap in private storage,
- * where it will survive color quantization mode changes.
- */
- cquantize->sv_colormap = colormap;
- cquantize->sv_actual = total_colors;
-}
-
-
-/*
- * Create the color index table.
- */
-
-LOCAL(void)
-create_colorindex (j_decompress_ptr cinfo)
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- JSAMPROW indexptr;
- int i,j,k, nci, blksize, val, pad;
-
- /* For ordered dither, we pad the color index tables by MAXJSAMPLE in
- * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE).
- * This is not necessary in the other dithering modes. However, we
- * flag whether it was done in case user changes dithering mode.
- */
- if (cinfo->dither_mode == JDITHER_ORDERED) {
- pad = MAXJSAMPLE*2;
- cquantize->is_padded = TRUE;
- } else {
- pad = 0;
- cquantize->is_padded = FALSE;
- }
-
- cquantize->colorindex = (*cinfo->mem->alloc_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (JDIMENSION) (MAXJSAMPLE+1 + pad),
- (JDIMENSION) cinfo->out_color_components);
-
- /* blksize is number of adjacent repeated entries for a component */
- blksize = cquantize->sv_actual;
-
- for (i = 0; i < cinfo->out_color_components; i++) {
- /* fill in colorindex entries for i'th color component */
- nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
- blksize = blksize / nci;
-
- /* adjust colorindex pointers to provide padding at negative indexes. */
- if (pad)
- cquantize->colorindex[i] += MAXJSAMPLE;
-
- /* in loop, val = index of current output value, */
- /* and k = largest j that maps to current val */
- indexptr = cquantize->colorindex[i];
- val = 0;
- k = largest_input_value(cinfo, i, 0, nci-1);
- for (j = 0; j <= MAXJSAMPLE; j++) {
- while (j > k) /* advance val if past boundary */
- k = largest_input_value(cinfo, i, ++val, nci-1);
- /* premultiply so that no multiplication needed in main processing */
- indexptr[j] = (JSAMPLE) (val * blksize);
- }
- /* Pad at both ends if necessary */
- if (pad)
- for (j = 1; j <= MAXJSAMPLE; j++) {
- indexptr[-j] = indexptr[0];
- indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE];
- }
- }
-}
-
-
-/*
- * Create an ordered-dither array for a component having ncolors
- * distinct output values.
- */
-
-LOCAL(ODITHER_MATRIX_PTR)
-make_odither_array (j_decompress_ptr cinfo, int ncolors)
-{
- ODITHER_MATRIX_PTR odither;
- int j,k;
- INT32 num,den;
-
- odither = (ODITHER_MATRIX_PTR)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(ODITHER_MATRIX));
- /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1).
- * Hence the dither value for the matrix cell with fill order f
- * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1).
- * On 16-bit-int machine, be careful to avoid overflow.
- */
- den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1));
- for (j = 0; j < ODITHER_SIZE; j++) {
- for (k = 0; k < ODITHER_SIZE; k++) {
- num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k])))
- * MAXJSAMPLE;
- /* Ensure round towards zero despite C's lack of consistency
- * about rounding negative values in integer division...
- */
- odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den);
- }
- }
- return odither;
-}
-
-
-/*
- * Create the ordered-dither tables.
- * Components having the same number of representative colors may
- * share a dither table.
- */
-
-LOCAL(void)
-create_odither_tables (j_decompress_ptr cinfo)
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- ODITHER_MATRIX_PTR odither;
- int i, j, nci;
-
- for (i = 0; i < cinfo->out_color_components; i++) {
- nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
- odither = NULL; /* search for matching prior component */
- for (j = 0; j < i; j++) {
- if (nci == cquantize->Ncolors[j]) {
- odither = cquantize->odither[j];
- break;
- }
- }
- if (odither == NULL) /* need a new table? */
- odither = make_odither_array(cinfo, nci);
- cquantize->odither[i] = odither;
- }
-}
-
-
-/*
- * Map some rows of pixels to the output colormapped representation.
- */
-
-METHODDEF(void)
-color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
-/* General case, no dithering */
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- JSAMPARRAY colorindex = cquantize->colorindex;
- register int pixcode, ci;
- register JSAMPROW ptrin, ptrout;
- int row;
- JDIMENSION col;
- JDIMENSION width = cinfo->output_width;
- register int nc = cinfo->out_color_components;
-
- for (row = 0; row < num_rows; row++) {
- ptrin = input_buf[row];
- ptrout = output_buf[row];
- for (col = width; col > 0; col--) {
- pixcode = 0;
- for (ci = 0; ci < nc; ci++) {
- pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]);
- }
- *ptrout++ = (JSAMPLE) pixcode;
- }
- }
-}
-
-
-METHODDEF(void)
-color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
-/* Fast path for out_color_components==3, no dithering */
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- register int pixcode;
- register JSAMPROW ptrin, ptrout;
- JSAMPROW colorindex0 = cquantize->colorindex[0];
- JSAMPROW colorindex1 = cquantize->colorindex[1];
- JSAMPROW colorindex2 = cquantize->colorindex[2];
- int row;
- JDIMENSION col;
- JDIMENSION width = cinfo->output_width;
-
- for (row = 0; row < num_rows; row++) {
- ptrin = input_buf[row];
- ptrout = output_buf[row];
- for (col = width; col > 0; col--) {
- pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]);
- pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]);
- pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]);
- *ptrout++ = (JSAMPLE) pixcode;
- }
- }
-}
-
-
-METHODDEF(void)
-quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
-/* General case, with ordered dithering */
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- register JSAMPROW input_ptr;
- register JSAMPROW output_ptr;
- JSAMPROW colorindex_ci;
- int * dither; /* points to active row of dither matrix */
- int row_index, col_index; /* current indexes into dither matrix */
- int nc = cinfo->out_color_components;
- int ci;
- int row;
- JDIMENSION col;
- JDIMENSION width = cinfo->output_width;
-
- for (row = 0; row < num_rows; row++) {
- /* Initialize output values to 0 so can process components separately */
- jzero_far((void FAR *) output_buf[row],
- (size_t) (width * SIZEOF(JSAMPLE)));
- row_index = cquantize->row_index;
- for (ci = 0; ci < nc; ci++) {
- input_ptr = input_buf[row] + ci;
- output_ptr = output_buf[row];
- colorindex_ci = cquantize->colorindex[ci];
- dither = cquantize->odither[ci][row_index];
- col_index = 0;
-
- for (col = width; col > 0; col--) {
- /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE,
- * select output value, accumulate into output code for this pixel.
- * Range-limiting need not be done explicitly, as we have extended
- * the colorindex table to produce the right answers for out-of-range
- * inputs. The maximum dither is +- MAXJSAMPLE; this sets the
- * required amount of padding.
- */
- *output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]];
- input_ptr += nc;
- output_ptr++;
- col_index = (col_index + 1) & ODITHER_MASK;
- }
- }
- /* Advance row index for next row */
- row_index = (row_index + 1) & ODITHER_MASK;
- cquantize->row_index = row_index;
- }
-}
-
-
-METHODDEF(void)
-quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
-/* Fast path for out_color_components==3, with ordered dithering */
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- register int pixcode;
- register JSAMPROW input_ptr;
- register JSAMPROW output_ptr;
- JSAMPROW colorindex0 = cquantize->colorindex[0];
- JSAMPROW colorindex1 = cquantize->colorindex[1];
- JSAMPROW colorindex2 = cquantize->colorindex[2];
- int * dither0; /* points to active row of dither matrix */
- int * dither1;
- int * dither2;
- int row_index, col_index; /* current indexes into dither matrix */
- int row;
- JDIMENSION col;
- JDIMENSION width = cinfo->output_width;
-
- for (row = 0; row < num_rows; row++) {
- row_index = cquantize->row_index;
- input_ptr = input_buf[row];
- output_ptr = output_buf[row];
- dither0 = cquantize->odither[0][row_index];
- dither1 = cquantize->odither[1][row_index];
- dither2 = cquantize->odither[2][row_index];
- col_index = 0;
-
- for (col = width; col > 0; col--) {
- pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) +
- dither0[col_index]]);
- pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) +
- dither1[col_index]]);
- pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) +
- dither2[col_index]]);
- *output_ptr++ = (JSAMPLE) pixcode;
- col_index = (col_index + 1) & ODITHER_MASK;
- }
- row_index = (row_index + 1) & ODITHER_MASK;
- cquantize->row_index = row_index;
- }
-}
-
-
-METHODDEF(void)
-quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
-/* General case, with Floyd-Steinberg dithering */
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- register LOCFSERROR cur; /* current error or pixel value */
- LOCFSERROR belowerr; /* error for pixel below cur */
- LOCFSERROR bpreverr; /* error for below/prev col */
- LOCFSERROR bnexterr; /* error for below/next col */
- LOCFSERROR delta;
- register FSERRPTR errorptr; /* => fserrors[] at column before current */
- register JSAMPROW input_ptr;
- register JSAMPROW output_ptr;
- JSAMPROW colorindex_ci;
- JSAMPROW colormap_ci;
- int pixcode;
- int nc = cinfo->out_color_components;
- int dir; /* 1 for left-to-right, -1 for right-to-left */
- int dirnc; /* dir * nc */
- int ci;
- int row;
- JDIMENSION col;
- JDIMENSION width = cinfo->output_width;
- JSAMPLE *range_limit = cinfo->sample_range_limit;
- SHIFT_TEMPS
-
- for (row = 0; row < num_rows; row++) {
- /* Initialize output values to 0 so can process components separately */
- jzero_far((void FAR *) output_buf[row],
- (size_t) (width * SIZEOF(JSAMPLE)));
- for (ci = 0; ci < nc; ci++) {
- input_ptr = input_buf[row] + ci;
- output_ptr = output_buf[row];
- if (cquantize->on_odd_row) {
- /* work right to left in this row */
- input_ptr += (width-1) * nc; /* so point to rightmost pixel */
- output_ptr += width-1;
- dir = -1;
- dirnc = -nc;
- errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */
- } else {
- /* work left to right in this row */
- dir = 1;
- dirnc = nc;
- errorptr = cquantize->fserrors[ci]; /* => entry before first column */
- }
- colorindex_ci = cquantize->colorindex[ci];
- colormap_ci = cquantize->sv_colormap[ci];
- /* Preset error values: no error propagated to first pixel from left */
- cur = 0;
- /* and no error propagated to row below yet */
- belowerr = bpreverr = 0;
-
- for (col = width; col > 0; col--) {
- /* cur holds the error propagated from the previous pixel on the
- * current line. Add the error propagated from the previous line
- * to form the complete error correction term for this pixel, and
- * round the error term (which is expressed * 16) to an integer.
- * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
- * for either sign of the error value.
- * Note: errorptr points to *previous* column's array entry.
- */
- cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4);
- /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
- * The maximum error is +- MAXJSAMPLE; this sets the required size
- * of the range_limit array.
- */
- cur += GETJSAMPLE(*input_ptr);
- cur = GETJSAMPLE(range_limit[cur]);
- /* Select output value, accumulate into output code for this pixel */
- pixcode = GETJSAMPLE(colorindex_ci[cur]);
- *output_ptr += (JSAMPLE) pixcode;
- /* Compute actual representation error at this pixel */
- /* Note: we can do this even though we don't have the final */
- /* pixel code, because the colormap is orthogonal. */
- cur -= GETJSAMPLE(colormap_ci[pixcode]);
- /* Compute error fractions to be propagated to adjacent pixels.
- * Add these into the running sums, and simultaneously shift the
- * next-line error sums left by 1 column.
- */
- bnexterr = cur;
- delta = cur * 2;
- cur += delta; /* form error * 3 */
- errorptr[0] = (FSERROR) (bpreverr + cur);
- cur += delta; /* form error * 5 */
- bpreverr = belowerr + cur;
- belowerr = bnexterr;
- cur += delta; /* form error * 7 */
- /* At this point cur contains the 7/16 error value to be propagated
- * to the next pixel on the current line, and all the errors for the
- * next line have been shifted over. We are therefore ready to move on.
- */
- input_ptr += dirnc; /* advance input ptr to next column */
- output_ptr += dir; /* advance output ptr to next column */
- errorptr += dir; /* advance errorptr to current column */
- }
- /* Post-loop cleanup: we must unload the final error value into the
- * final fserrors[] entry. Note we need not unload belowerr because
- * it is for the dummy column before or after the actual array.
- */
- errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */
- }
- cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE);
- }
-}
-
-
-/*
- * Allocate workspace for Floyd-Steinberg errors.
- */
-
-LOCAL(void)
-alloc_fs_workspace (j_decompress_ptr cinfo)
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- size_t arraysize;
- int i;
-
- arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR));
- for (i = 0; i < cinfo->out_color_components; i++) {
- cquantize->fserrors[i] = (FSERRPTR)
- (*cinfo->mem->alloc_large)((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize);
- }
-}
-
-
-/*
- * Initialize for one-pass color quantization.
- */
-
-METHODDEF(void)
-start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan)
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- size_t arraysize;
- int i;
-
- /* Install my colormap. */
- cinfo->colormap = cquantize->sv_colormap;
- cinfo->actual_number_of_colors = cquantize->sv_actual;
-
- /* Initialize for desired dithering mode. */
- switch (cinfo->dither_mode) {
- case JDITHER_NONE:
- if (cinfo->out_color_components == 3)
- cquantize->pub.color_quantize = color_quantize3;
- else
- cquantize->pub.color_quantize = color_quantize;
- break;
- case JDITHER_ORDERED:
- if (cinfo->out_color_components == 3)
- cquantize->pub.color_quantize = quantize3_ord_dither;
- else
- cquantize->pub.color_quantize = quantize_ord_dither;
- cquantize->row_index = 0; /* initialize state for ordered dither */
- /* If user changed to ordered dither from another mode,
- * we must recreate the color index table with padding.
- * This will cost extra space, but probably isn't very likely.
- */
- if (! cquantize->is_padded)
- create_colorindex(cinfo);
- /* Create ordered-dither tables if we didn't already. */
- if (cquantize->odither[0] == NULL)
- create_odither_tables(cinfo);
- break;
- case JDITHER_FS:
- cquantize->pub.color_quantize = quantize_fs_dither;
- cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */
- /* Allocate Floyd-Steinberg workspace if didn't already. */
- if (cquantize->fserrors[0] == NULL)
- alloc_fs_workspace(cinfo);
- /* Initialize the propagated errors to zero. */
- arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR));
- for (i = 0; i < cinfo->out_color_components; i++)
- jzero_far((void FAR *) cquantize->fserrors[i], arraysize);
- break;
- default:
- ERREXIT(cinfo, JERR_NOT_COMPILED);
- break;
- }
-}
-
-
-/*
- * Finish up at the end of the pass.
- */
-
-METHODDEF(void)
-finish_pass_1_quant (j_decompress_ptr cinfo)
-{
- /* no work in 1-pass case */
-}
-
-
-/*
- * Switch to a new external colormap between output passes.
- * Shouldn't get to this module!
- */
-
-METHODDEF(void)
-new_color_map_1_quant (j_decompress_ptr cinfo)
-{
- ERREXIT(cinfo, JERR_MODE_CHANGE);
-}
-
-
-/*
- * Module initialization routine for 1-pass color quantization.
- */
-
-GLOBAL(void)
-jinit_1pass_quantizer (j_decompress_ptr cinfo)
-{
- my_cquantize_ptr cquantize;
-
- cquantize = (my_cquantize_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_cquantizer));
- cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize;
- cquantize->pub.start_pass = start_pass_1_quant;
- cquantize->pub.finish_pass = finish_pass_1_quant;
- cquantize->pub.new_color_map = new_color_map_1_quant;
- cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */
- cquantize->odither[0] = NULL; /* Also flag odither arrays not allocated */
-
- /* Make sure my internal arrays won't overflow */
- if (cinfo->out_color_components > MAX_Q_COMPS)
- ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS);
- /* Make sure colormap indexes can be represented by JSAMPLEs */
- if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1))
- ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1);
-
- /* Create the colormap and color index table. */
- create_colormap(cinfo);
- create_colorindex(cinfo);
-
- /* Allocate Floyd-Steinberg workspace now if requested.
- * We do this now since it is FAR storage and may affect the memory
- * manager's space calculations. If the user changes to FS dither
- * mode in a later pass, we will allocate the space then, and will
- * possibly overrun the max_memory_to_use setting.
- */
- if (cinfo->dither_mode == JDITHER_FS)
- alloc_fs_workspace(cinfo);
-}
-
-#endif /* QUANT_1PASS_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jquant2.c b/engine/code/jpeg-6b/jquant2.c
deleted file mode 100644
index af601e3..0000000
--- a/engine/code/jpeg-6b/jquant2.c
+++ /dev/null
@@ -1,1310 +0,0 @@
-/*
- * jquant2.c
- *
- * Copyright (C) 1991-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains 2-pass color quantization (color mapping) routines.
- * These routines provide selection of a custom color map for an image,
- * followed by mapping of the image to that color map, with optional
- * Floyd-Steinberg dithering.
- * It is also possible to use just the second pass to map to an arbitrary
- * externally-given color map.
- *
- * Note: ordered dithering is not supported, since there isn't any fast
- * way to compute intercolor distances; it's unclear that ordered dither's
- * fundamental assumptions even hold with an irregularly spaced color map.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-#ifdef QUANT_2PASS_SUPPORTED
-
-
-/*
- * This module implements the well-known Heckbert paradigm for color
- * quantization. Most of the ideas used here can be traced back to
- * Heckbert's seminal paper
- * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display",
- * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304.
- *
- * In the first pass over the image, we accumulate a histogram showing the
- * usage count of each possible color. To keep the histogram to a reasonable
- * size, we reduce the precision of the input; typical practice is to retain
- * 5 or 6 bits per color, so that 8 or 4 different input values are counted
- * in the same histogram cell.
- *
- * Next, the color-selection step begins with a box representing the whole
- * color space, and repeatedly splits the "largest" remaining box until we
- * have as many boxes as desired colors. Then the mean color in each
- * remaining box becomes one of the possible output colors.
- *
- * The second pass over the image maps each input pixel to the closest output
- * color (optionally after applying a Floyd-Steinberg dithering correction).
- * This mapping is logically trivial, but making it go fast enough requires
- * considerable care.
- *
- * Heckbert-style quantizers vary a good deal in their policies for choosing
- * the "largest" box and deciding where to cut it. The particular policies
- * used here have proved out well in experimental comparisons, but better ones
- * may yet be found.
- *
- * In earlier versions of the IJG code, this module quantized in YCbCr color
- * space, processing the raw upsampled data without a color conversion step.
- * This allowed the color conversion math to be done only once per colormap
- * entry, not once per pixel. However, that optimization precluded other
- * useful optimizations (such as merging color conversion with upsampling)
- * and it also interfered with desired capabilities such as quantizing to an
- * externally-supplied colormap. We have therefore abandoned that approach.
- * The present code works in the post-conversion color space, typically RGB.
- *
- * To improve the visual quality of the results, we actually work in scaled
- * RGB space, giving G distances more weight than R, and R in turn more than
- * B. To do everything in integer math, we must use integer scale factors.
- * The 2/3/1 scale factors used here correspond loosely to the relative
- * weights of the colors in the NTSC grayscale equation.
- * If you want to use this code to quantize a non-RGB color space, you'll
- * probably need to change these scale factors.
- */
-
-#define R_SCALE 2 /* scale R distances by this much */
-#define G_SCALE 3 /* scale G distances by this much */
-#define B_SCALE 1 /* and B by this much */
-
-/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined
- * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B
- * and B,G,R orders. If you define some other weird order in jmorecfg.h,
- * you'll get compile errors until you extend this logic. In that case
- * you'll probably want to tweak the histogram sizes too.
- */
-
-#if RGB_RED == 0
-#define C0_SCALE R_SCALE
-#endif
-#if RGB_BLUE == 0
-#define C0_SCALE B_SCALE
-#endif
-#if RGB_GREEN == 1
-#define C1_SCALE G_SCALE
-#endif
-#if RGB_RED == 2
-#define C2_SCALE R_SCALE
-#endif
-#if RGB_BLUE == 2
-#define C2_SCALE B_SCALE
-#endif
-
-
-/*
- * First we have the histogram data structure and routines for creating it.
- *
- * The number of bits of precision can be adjusted by changing these symbols.
- * We recommend keeping 6 bits for G and 5 each for R and B.
- * If you have plenty of memory and cycles, 6 bits all around gives marginally
- * better results; if you are short of memory, 5 bits all around will save
- * some space but degrade the results.
- * To maintain a fully accurate histogram, we'd need to allocate a "long"
- * (preferably unsigned long) for each cell. In practice this is overkill;
- * we can get by with 16 bits per cell. Few of the cell counts will overflow,
- * and clamping those that do overflow to the maximum value will give close-
- * enough results. This reduces the recommended histogram size from 256Kb
- * to 128Kb, which is a useful savings on PC-class machines.
- * (In the second pass the histogram space is re-used for pixel mapping data;
- * in that capacity, each cell must be able to store zero to the number of
- * desired colors. 16 bits/cell is plenty for that too.)
- * Since the JPEG code is intended to run in small memory model on 80x86
- * machines, we can't just allocate the histogram in one chunk. Instead
- * of a true 3-D array, we use a row of pointers to 2-D arrays. Each
- * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and
- * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that
- * on 80x86 machines, the pointer row is in near memory but the actual
- * arrays are in far memory (same arrangement as we use for image arrays).
- */
-
-#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */
-
-/* These will do the right thing for either R,G,B or B,G,R color order,
- * but you may not like the results for other color orders.
- */
-#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */
-#define HIST_C1_BITS 6 /* bits of precision in G histogram */
-#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */
-
-/* Number of elements along histogram axes. */
-#define HIST_C0_ELEMS (1<<HIST_C0_BITS)
-#define HIST_C1_ELEMS (1<<HIST_C1_BITS)
-#define HIST_C2_ELEMS (1<<HIST_C2_BITS)
-
-/* These are the amounts to shift an input value to get a histogram index. */
-#define C0_SHIFT (BITS_IN_JSAMPLE-HIST_C0_BITS)
-#define C1_SHIFT (BITS_IN_JSAMPLE-HIST_C1_BITS)
-#define C2_SHIFT (BITS_IN_JSAMPLE-HIST_C2_BITS)
-
-
-typedef UINT16 histcell; /* histogram cell; prefer an unsigned type */
-
-typedef histcell FAR * histptr; /* for pointers to histogram cells */
-
-typedef histcell hist1d[HIST_C2_ELEMS]; /* typedefs for the array */
-typedef hist1d FAR * hist2d; /* type for the 2nd-level pointers */
-typedef hist2d * hist3d; /* type for top-level pointer */
-
-
-/* Declarations for Floyd-Steinberg dithering.
- *
- * Errors are accumulated into the array fserrors[], at a resolution of
- * 1/16th of a pixel count. The error at a given pixel is propagated
- * to its not-yet-processed neighbors using the standard F-S fractions,
- * ... (here) 7/16
- * 3/16 5/16 1/16
- * We work left-to-right on even rows, right-to-left on odd rows.
- *
- * We can get away with a single array (holding one row's worth of errors)
- * by using it to store the current row's errors at pixel columns not yet
- * processed, but the next row's errors at columns already processed. We
- * need only a few extra variables to hold the errors immediately around the
- * current column. (If we are lucky, those variables are in registers, but
- * even if not, they're probably cheaper to access than array elements are.)
- *
- * The fserrors[] array has (#columns + 2) entries; the extra entry at
- * each end saves us from special-casing the first and last pixels.
- * Each entry is three values long, one value for each color component.
- *
- * Note: on a wide image, we might not have enough room in a PC's near data
- * segment to hold the error array; so it is allocated with alloc_large.
- */
-
-#if BITS_IN_JSAMPLE == 8
-typedef INT16 FSERROR; /* 16 bits should be enough */
-typedef int LOCFSERROR; /* use 'int' for calculation temps */
-#else
-typedef INT32 FSERROR; /* may need more than 16 bits */
-typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */
-#endif
-
-typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */
-
-
-/* Private subobject */
-
-typedef struct {
- struct jpeg_color_quantizer pub; /* public fields */
-
- /* Space for the eventually created colormap is stashed here */
- JSAMPARRAY sv_colormap; /* colormap allocated at init time */
- int desired; /* desired # of colors = size of colormap */
-
- /* Variables for accumulating image statistics */
- hist3d histogram; /* pointer to the histogram */
-
- boolean needs_zeroed; /* TRUE if next pass must zero histogram */
-
- /* Variables for Floyd-Steinberg dithering */
- FSERRPTR fserrors; /* accumulated errors */
- boolean on_odd_row; /* flag to remember which row we are on */
- int * error_limiter; /* table for clamping the applied error */
-} my_cquantizer;
-
-typedef my_cquantizer * my_cquantize_ptr;
-
-
-/*
- * Prescan some rows of pixels.
- * In this module the prescan simply updates the histogram, which has been
- * initialized to zeroes by start_pass.
- * An output_buf parameter is required by the method signature, but no data
- * is actually output (in fact the buffer controller is probably passing a
- * NULL pointer).
- */
-
-METHODDEF(void)
-prescan_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- register JSAMPROW ptr;
- register histptr histp;
- register hist3d histogram = cquantize->histogram;
- int row;
- JDIMENSION col;
- JDIMENSION width = cinfo->output_width;
-
- for (row = 0; row < num_rows; row++) {
- ptr = input_buf[row];
- for (col = width; col > 0; col--) {
- /* get pixel value and index into the histogram */
- histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT]
- [GETJSAMPLE(ptr[1]) >> C1_SHIFT]
- [GETJSAMPLE(ptr[2]) >> C2_SHIFT];
- /* increment, check for overflow and undo increment if so. */
- if (++(*histp) <= 0)
- (*histp)--;
- ptr += 3;
- }
- }
-}
-
-
-/*
- * Next we have the really interesting routines: selection of a colormap
- * given the completed histogram.
- * These routines work with a list of "boxes", each representing a rectangular
- * subset of the input color space (to histogram precision).
- */
-
-typedef struct {
- /* The bounds of the box (inclusive); expressed as histogram indexes */
- int c0min, c0max;
- int c1min, c1max;
- int c2min, c2max;
- /* The volume (actually 2-norm) of the box */
- INT32 volume;
- /* The number of nonzero histogram cells within this box */
- long colorcount;
-} box;
-
-typedef box * boxptr;
-
-
-LOCAL(boxptr)
-find_biggest_color_pop (boxptr boxlist, int numboxes)
-/* Find the splittable box with the largest color population */
-/* Returns NULL if no splittable boxes remain */
-{
- register boxptr boxp;
- register int i;
- register long maxc = 0;
- boxptr which = NULL;
-
- for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
- if (boxp->colorcount > maxc && boxp->volume > 0) {
- which = boxp;
- maxc = boxp->colorcount;
- }
- }
- return which;
-}
-
-
-LOCAL(boxptr)
-find_biggest_volume (boxptr boxlist, int numboxes)
-/* Find the splittable box with the largest (scaled) volume */
-/* Returns NULL if no splittable boxes remain */
-{
- register boxptr boxp;
- register int i;
- register INT32 maxv = 0;
- boxptr which = NULL;
-
- for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
- if (boxp->volume > maxv) {
- which = boxp;
- maxv = boxp->volume;
- }
- }
- return which;
-}
-
-
-LOCAL(void)
-update_box (j_decompress_ptr cinfo, boxptr boxp)
-/* Shrink the min/max bounds of a box to enclose only nonzero elements, */
-/* and recompute its volume and population */
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- hist3d histogram = cquantize->histogram;
- histptr histp;
- int c0,c1,c2;
- int c0min,c0max,c1min,c1max,c2min,c2max;
- INT32 dist0,dist1,dist2;
- long ccount;
-
- c0min = boxp->c0min; c0max = boxp->c0max;
- c1min = boxp->c1min; c1max = boxp->c1max;
- c2min = boxp->c2min; c2max = boxp->c2max;
-
- if (c0max > c0min)
- for (c0 = c0min; c0 <= c0max; c0++)
- for (c1 = c1min; c1 <= c1max; c1++) {
- histp = & histogram[c0][c1][c2min];
- for (c2 = c2min; c2 <= c2max; c2++)
- if (*histp++ != 0) {
- boxp->c0min = c0min = c0;
- goto have_c0min;
- }
- }
- have_c0min:
- if (c0max > c0min)
- for (c0 = c0max; c0 >= c0min; c0--)
- for (c1 = c1min; c1 <= c1max; c1++) {
- histp = & histogram[c0][c1][c2min];
- for (c2 = c2min; c2 <= c2max; c2++)
- if (*histp++ != 0) {
- boxp->c0max = c0max = c0;
- goto have_c0max;
- }
- }
- have_c0max:
- if (c1max > c1min)
- for (c1 = c1min; c1 <= c1max; c1++)
- for (c0 = c0min; c0 <= c0max; c0++) {
- histp = & histogram[c0][c1][c2min];
- for (c2 = c2min; c2 <= c2max; c2++)
- if (*histp++ != 0) {
- boxp->c1min = c1min = c1;
- goto have_c1min;
- }
- }
- have_c1min:
- if (c1max > c1min)
- for (c1 = c1max; c1 >= c1min; c1--)
- for (c0 = c0min; c0 <= c0max; c0++) {
- histp = & histogram[c0][c1][c2min];
- for (c2 = c2min; c2 <= c2max; c2++)
- if (*histp++ != 0) {
- boxp->c1max = c1max = c1;
- goto have_c1max;
- }
- }
- have_c1max:
- if (c2max > c2min)
- for (c2 = c2min; c2 <= c2max; c2++)
- for (c0 = c0min; c0 <= c0max; c0++) {
- histp = & histogram[c0][c1min][c2];
- for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS)
- if (*histp != 0) {
- boxp->c2min = c2min = c2;
- goto have_c2min;
- }
- }
- have_c2min:
- if (c2max > c2min)
- for (c2 = c2max; c2 >= c2min; c2--)
- for (c0 = c0min; c0 <= c0max; c0++) {
- histp = & histogram[c0][c1min][c2];
- for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS)
- if (*histp != 0) {
- boxp->c2max = c2max = c2;
- goto have_c2max;
- }
- }
- have_c2max:
-
- /* Update box volume.
- * We use 2-norm rather than real volume here; this biases the method
- * against making long narrow boxes, and it has the side benefit that
- * a box is splittable iff norm > 0.
- * Since the differences are expressed in histogram-cell units,
- * we have to shift back to JSAMPLE units to get consistent distances;
- * after which, we scale according to the selected distance scale factors.
- */
- dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE;
- dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE;
- dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE;
- boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2;
-
- /* Now scan remaining volume of box and compute population */
- ccount = 0;
- for (c0 = c0min; c0 <= c0max; c0++)
- for (c1 = c1min; c1 <= c1max; c1++) {
- histp = & histogram[c0][c1][c2min];
- for (c2 = c2min; c2 <= c2max; c2++, histp++)
- if (*histp != 0) {
- ccount++;
- }
- }
- boxp->colorcount = ccount;
-}
-
-
-LOCAL(int)
-median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes,
- int desired_colors)
-/* Repeatedly select and split the largest box until we have enough boxes */
-{
- int n,lb;
- int c0,c1,c2,cmax;
- register boxptr b1,b2;
-
- while (numboxes < desired_colors) {
- /* Select box to split.
- * Current algorithm: by population for first half, then by volume.
- */
- if (numboxes*2 <= desired_colors) {
- b1 = find_biggest_color_pop(boxlist, numboxes);
- } else {
- b1 = find_biggest_volume(boxlist, numboxes);
- }
- if (b1 == NULL) /* no splittable boxes left! */
- break;
- b2 = &boxlist[numboxes]; /* where new box will go */
- /* Copy the color bounds to the new box. */
- b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max;
- b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min;
- /* Choose which axis to split the box on.
- * Current algorithm: longest scaled axis.
- * See notes in update_box about scaling distances.
- */
- c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE;
- c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE;
- c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE;
- /* We want to break any ties in favor of green, then red, blue last.
- * This code does the right thing for R,G,B or B,G,R color orders only.
- */
-#if RGB_RED == 0
- cmax = c1; n = 1;
- if (c0 > cmax) { cmax = c0; n = 0; }
- if (c2 > cmax) { n = 2; }
-#else
- cmax = c1; n = 1;
- if (c2 > cmax) { cmax = c2; n = 2; }
- if (c0 > cmax) { n = 0; }
-#endif
- /* Choose split point along selected axis, and update box bounds.
- * Current algorithm: split at halfway point.
- * (Since the box has been shrunk to minimum volume,
- * any split will produce two nonempty subboxes.)
- * Note that lb value is max for lower box, so must be < old max.
- */
- switch (n) {
- case 0:
- lb = (b1->c0max + b1->c0min) / 2;
- b1->c0max = lb;
- b2->c0min = lb+1;
- break;
- case 1:
- lb = (b1->c1max + b1->c1min) / 2;
- b1->c1max = lb;
- b2->c1min = lb+1;
- break;
- case 2:
- lb = (b1->c2max + b1->c2min) / 2;
- b1->c2max = lb;
- b2->c2min = lb+1;
- break;
- }
- /* Update stats for boxes */
- update_box(cinfo, b1);
- update_box(cinfo, b2);
- numboxes++;
- }
- return numboxes;
-}
-
-
-LOCAL(void)
-compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor)
-/* Compute representative color for a box, put it in colormap[icolor] */
-{
- /* Current algorithm: mean weighted by pixels (not colors) */
- /* Note it is important to get the rounding correct! */
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- hist3d histogram = cquantize->histogram;
- histptr histp;
- int c0,c1,c2;
- int c0min,c0max,c1min,c1max,c2min,c2max;
- long count;
- long total = 0;
- long c0total = 0;
- long c1total = 0;
- long c2total = 0;
-
- c0min = boxp->c0min; c0max = boxp->c0max;
- c1min = boxp->c1min; c1max = boxp->c1max;
- c2min = boxp->c2min; c2max = boxp->c2max;
-
- for (c0 = c0min; c0 <= c0max; c0++)
- for (c1 = c1min; c1 <= c1max; c1++) {
- histp = & histogram[c0][c1][c2min];
- for (c2 = c2min; c2 <= c2max; c2++) {
- if ((count = *histp++) != 0) {
- total += count;
- c0total += ((c0 << C0_SHIFT) + ((1<<C0_SHIFT)>>1)) * count;
- c1total += ((c1 << C1_SHIFT) + ((1<<C1_SHIFT)>>1)) * count;
- c2total += ((c2 << C2_SHIFT) + ((1<<C2_SHIFT)>>1)) * count;
- }
- }
- }
-
- cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total);
- cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total);
- cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total);
-}
-
-
-LOCAL(void)
-select_colors (j_decompress_ptr cinfo, int desired_colors)
-/* Master routine for color selection */
-{
- boxptr boxlist;
- int numboxes;
- int i;
-
- /* Allocate workspace for box list */
- boxlist = (boxptr) (*cinfo->mem->alloc_small)
- ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box));
- /* Initialize one box containing whole space */
- numboxes = 1;
- boxlist[0].c0min = 0;
- boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT;
- boxlist[0].c1min = 0;
- boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT;
- boxlist[0].c2min = 0;
- boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT;
- /* Shrink it to actually-used volume and set its statistics */
- update_box(cinfo, & boxlist[0]);
- /* Perform median-cut to produce final box list */
- numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors);
- /* Compute the representative color for each box, fill colormap */
- for (i = 0; i < numboxes; i++)
- compute_color(cinfo, & boxlist[i], i);
- cinfo->actual_number_of_colors = numboxes;
- TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes);
-}
-
-
-/*
- * These routines are concerned with the time-critical task of mapping input
- * colors to the nearest color in the selected colormap.
- *
- * We re-use the histogram space as an "inverse color map", essentially a
- * cache for the results of nearest-color searches. All colors within a
- * histogram cell will be mapped to the same colormap entry, namely the one
- * closest to the cell's center. This may not be quite the closest entry to
- * the actual input color, but it's almost as good. A zero in the cache
- * indicates we haven't found the nearest color for that cell yet; the array
- * is cleared to zeroes before starting the mapping pass. When we find the
- * nearest color for a cell, its colormap index plus one is recorded in the
- * cache for future use. The pass2 scanning routines call fill_inverse_cmap
- * when they need to use an unfilled entry in the cache.
- *
- * Our method of efficiently finding nearest colors is based on the "locally
- * sorted search" idea described by Heckbert and on the incremental distance
- * calculation described by Spencer W. Thomas in chapter III.1 of Graphics
- * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that
- * the distances from a given colormap entry to each cell of the histogram can
- * be computed quickly using an incremental method: the differences between
- * distances to adjacent cells themselves differ by a constant. This allows a
- * fairly fast implementation of the "brute force" approach of computing the
- * distance from every colormap entry to every histogram cell. Unfortunately,
- * it needs a work array to hold the best-distance-so-far for each histogram
- * cell (because the inner loop has to be over cells, not colormap entries).
- * The work array elements have to be INT32s, so the work array would need
- * 256Kb at our recommended precision. This is not feasible in DOS machines.
- *
- * To get around these problems, we apply Thomas' method to compute the
- * nearest colors for only the cells within a small subbox of the histogram.
- * The work array need be only as big as the subbox, so the memory usage
- * problem is solved. Furthermore, we need not fill subboxes that are never
- * referenced in pass2; many images use only part of the color gamut, so a
- * fair amount of work is saved. An additional advantage of this
- * approach is that we can apply Heckbert's locality criterion to quickly
- * eliminate colormap entries that are far away from the subbox; typically
- * three-fourths of the colormap entries are rejected by Heckbert's criterion,
- * and we need not compute their distances to individual cells in the subbox.
- * The speed of this approach is heavily influenced by the subbox size: too
- * small means too much overhead, too big loses because Heckbert's criterion
- * can't eliminate as many colormap entries. Empirically the best subbox
- * size seems to be about 1/512th of the histogram (1/8th in each direction).
- *
- * Thomas' article also describes a refined method which is asymptotically
- * faster than the brute-force method, but it is also far more complex and
- * cannot efficiently be applied to small subboxes. It is therefore not
- * useful for programs intended to be portable to DOS machines. On machines
- * with plenty of memory, filling the whole histogram in one shot with Thomas'
- * refined method might be faster than the present code --- but then again,
- * it might not be any faster, and it's certainly more complicated.
- */
-
-
-/* log2(histogram cells in update box) for each axis; this can be adjusted */
-#define BOX_C0_LOG (HIST_C0_BITS-3)
-#define BOX_C1_LOG (HIST_C1_BITS-3)
-#define BOX_C2_LOG (HIST_C2_BITS-3)
-
-#define BOX_C0_ELEMS (1<<BOX_C0_LOG) /* # of hist cells in update box */
-#define BOX_C1_ELEMS (1<<BOX_C1_LOG)
-#define BOX_C2_ELEMS (1<<BOX_C2_LOG)
-
-#define BOX_C0_SHIFT (C0_SHIFT + BOX_C0_LOG)
-#define BOX_C1_SHIFT (C1_SHIFT + BOX_C1_LOG)
-#define BOX_C2_SHIFT (C2_SHIFT + BOX_C2_LOG)
-
-
-/*
- * The next three routines implement inverse colormap filling. They could
- * all be folded into one big routine, but splitting them up this way saves
- * some stack space (the mindist[] and bestdist[] arrays need not coexist)
- * and may allow some compilers to produce better code by registerizing more
- * inner-loop variables.
- */
-
-LOCAL(int)
-find_nearby_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
- JSAMPLE colorlist[])
-/* Locate the colormap entries close enough to an update box to be candidates
- * for the nearest entry to some cell(s) in the update box. The update box
- * is specified by the center coordinates of its first cell. The number of
- * candidate colormap entries is returned, and their colormap indexes are
- * placed in colorlist[].
- * This routine uses Heckbert's "locally sorted search" criterion to select
- * the colors that need further consideration.
- */
-{
- int numcolors = cinfo->actual_number_of_colors;
- int maxc0, maxc1, maxc2;
- int centerc0, centerc1, centerc2;
- int i, x, ncolors;
- INT32 minmaxdist, min_dist, max_dist, tdist;
- INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */
-
- /* Compute true coordinates of update box's upper corner and center.
- * Actually we compute the coordinates of the center of the upper-corner
- * histogram cell, which are the upper bounds of the volume we care about.
- * Note that since ">>" rounds down, the "center" values may be closer to
- * min than to max; hence comparisons to them must be "<=", not "<".
- */
- maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT));
- centerc0 = (minc0 + maxc0) >> 1;
- maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT));
- centerc1 = (minc1 + maxc1) >> 1;
- maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT));
- centerc2 = (minc2 + maxc2) >> 1;
-
- /* For each color in colormap, find:
- * 1. its minimum squared-distance to any point in the update box
- * (zero if color is within update box);
- * 2. its maximum squared-distance to any point in the update box.
- * Both of these can be found by considering only the corners of the box.
- * We save the minimum distance for each color in mindist[];
- * only the smallest maximum distance is of interest.
- */
- minmaxdist = 0x7FFFFFFFL;
-
- for (i = 0; i < numcolors; i++) {
- /* We compute the squared-c0-distance term, then add in the other two. */
- x = GETJSAMPLE(cinfo->colormap[0][i]);
- if (x < minc0) {
- tdist = (x - minc0) * C0_SCALE;
- min_dist = tdist*tdist;
- tdist = (x - maxc0) * C0_SCALE;
- max_dist = tdist*tdist;
- } else if (x > maxc0) {
- tdist = (x - maxc0) * C0_SCALE;
- min_dist = tdist*tdist;
- tdist = (x - minc0) * C0_SCALE;
- max_dist = tdist*tdist;
- } else {
- /* within cell range so no contribution to min_dist */
- min_dist = 0;
- if (x <= centerc0) {
- tdist = (x - maxc0) * C0_SCALE;
- max_dist = tdist*tdist;
- } else {
- tdist = (x - minc0) * C0_SCALE;
- max_dist = tdist*tdist;
- }
- }
-
- x = GETJSAMPLE(cinfo->colormap[1][i]);
- if (x < minc1) {
- tdist = (x - minc1) * C1_SCALE;
- min_dist += tdist*tdist;
- tdist = (x - maxc1) * C1_SCALE;
- max_dist += tdist*tdist;
- } else if (x > maxc1) {
- tdist = (x - maxc1) * C1_SCALE;
- min_dist += tdist*tdist;
- tdist = (x - minc1) * C1_SCALE;
- max_dist += tdist*tdist;
- } else {
- /* within cell range so no contribution to min_dist */
- if (x <= centerc1) {
- tdist = (x - maxc1) * C1_SCALE;
- max_dist += tdist*tdist;
- } else {
- tdist = (x - minc1) * C1_SCALE;
- max_dist += tdist*tdist;
- }
- }
-
- x = GETJSAMPLE(cinfo->colormap[2][i]);
- if (x < minc2) {
- tdist = (x - minc2) * C2_SCALE;
- min_dist += tdist*tdist;
- tdist = (x - maxc2) * C2_SCALE;
- max_dist += tdist*tdist;
- } else if (x > maxc2) {
- tdist = (x - maxc2) * C2_SCALE;
- min_dist += tdist*tdist;
- tdist = (x - minc2) * C2_SCALE;
- max_dist += tdist*tdist;
- } else {
- /* within cell range so no contribution to min_dist */
- if (x <= centerc2) {
- tdist = (x - maxc2) * C2_SCALE;
- max_dist += tdist*tdist;
- } else {
- tdist = (x - minc2) * C2_SCALE;
- max_dist += tdist*tdist;
- }
- }
-
- mindist[i] = min_dist; /* save away the results */
- if (max_dist < minmaxdist)
- minmaxdist = max_dist;
- }
-
- /* Now we know that no cell in the update box is more than minmaxdist
- * away from some colormap entry. Therefore, only colors that are
- * within minmaxdist of some part of the box need be considered.
- */
- ncolors = 0;
- for (i = 0; i < numcolors; i++) {
- if (mindist[i] <= minmaxdist)
- colorlist[ncolors++] = (JSAMPLE) i;
- }
- return ncolors;
-}
-
-
-LOCAL(void)
-find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
- int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[])
-/* Find the closest colormap entry for each cell in the update box,
- * given the list of candidate colors prepared by find_nearby_colors.
- * Return the indexes of the closest entries in the bestcolor[] array.
- * This routine uses Thomas' incremental distance calculation method to
- * find the distance from a colormap entry to successive cells in the box.
- */
-{
- int ic0, ic1, ic2;
- int i, icolor;
- register INT32 * bptr; /* pointer into bestdist[] array */
- JSAMPLE * cptr; /* pointer into bestcolor[] array */
- INT32 dist0, dist1; /* initial distance values */
- register INT32 dist2; /* current distance in inner loop */
- INT32 xx0, xx1; /* distance increments */
- register INT32 xx2;
- INT32 inc0, inc1, inc2; /* initial values for increments */
- /* This array holds the distance to the nearest-so-far color for each cell */
- INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
-
- /* Initialize best-distance for each cell of the update box */
- bptr = bestdist;
- for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--)
- *bptr++ = 0x7FFFFFFFL;
-
- /* For each color selected by find_nearby_colors,
- * compute its distance to the center of each cell in the box.
- * If that's less than best-so-far, update best distance and color number.
- */
-
- /* Nominal steps between cell centers ("x" in Thomas article) */
-#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE)
-#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE)
-#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE)
-
- for (i = 0; i < numcolors; i++) {
- icolor = GETJSAMPLE(colorlist[i]);
- /* Compute (square of) distance from minc0/c1/c2 to this color */
- inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE;
- dist0 = inc0*inc0;
- inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE;
- dist0 += inc1*inc1;
- inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE;
- dist0 += inc2*inc2;
- /* Form the initial difference increments */
- inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0;
- inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1;
- inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2;
- /* Now loop over all cells in box, updating distance per Thomas method */
- bptr = bestdist;
- cptr = bestcolor;
- xx0 = inc0;
- for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) {
- dist1 = dist0;
- xx1 = inc1;
- for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) {
- dist2 = dist1;
- xx2 = inc2;
- for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) {
- if (dist2 < *bptr) {
- *bptr = dist2;
- *cptr = (JSAMPLE) icolor;
- }
- dist2 += xx2;
- xx2 += 2 * STEP_C2 * STEP_C2;
- bptr++;
- cptr++;
- }
- dist1 += xx1;
- xx1 += 2 * STEP_C1 * STEP_C1;
- }
- dist0 += xx0;
- xx0 += 2 * STEP_C0 * STEP_C0;
- }
- }
-}
-
-
-LOCAL(void)
-fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2)
-/* Fill the inverse-colormap entries in the update box that contains */
-/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */
-/* we can fill as many others as we wish.) */
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- hist3d histogram = cquantize->histogram;
- int minc0, minc1, minc2; /* lower left corner of update box */
- int ic0, ic1, ic2;
- register JSAMPLE * cptr; /* pointer into bestcolor[] array */
- register histptr cachep; /* pointer into main cache array */
- /* This array lists the candidate colormap indexes. */
- JSAMPLE colorlist[MAXNUMCOLORS];
- int numcolors; /* number of candidate colors */
- /* This array holds the actually closest colormap index for each cell. */
- JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
-
- /* Convert cell coordinates to update box ID */
- c0 >>= BOX_C0_LOG;
- c1 >>= BOX_C1_LOG;
- c2 >>= BOX_C2_LOG;
-
- /* Compute true coordinates of update box's origin corner.
- * Actually we compute the coordinates of the center of the corner
- * histogram cell, which are the lower bounds of the volume we care about.
- */
- minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1);
- minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1);
- minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1);
-
- /* Determine which colormap entries are close enough to be candidates
- * for the nearest entry to some cell in the update box.
- */
- numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist);
-
- /* Determine the actually nearest colors. */
- find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist,
- bestcolor);
-
- /* Save the best color numbers (plus 1) in the main cache array */
- c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */
- c1 <<= BOX_C1_LOG;
- c2 <<= BOX_C2_LOG;
- cptr = bestcolor;
- for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) {
- for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) {
- cachep = & histogram[c0+ic0][c1+ic1][c2];
- for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) {
- *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1);
- }
- }
- }
-}
-
-
-/*
- * Map some rows of pixels to the output colormapped representation.
- */
-
-METHODDEF(void)
-pass2_no_dither (j_decompress_ptr cinfo,
- JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)
-/* This version performs no dithering */
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- hist3d histogram = cquantize->histogram;
- register JSAMPROW inptr, outptr;
- register histptr cachep;
- register int c0, c1, c2;
- int row;
- JDIMENSION col;
- JDIMENSION width = cinfo->output_width;
-
- for (row = 0; row < num_rows; row++) {
- inptr = input_buf[row];
- outptr = output_buf[row];
- for (col = width; col > 0; col--) {
- /* get pixel value and index into the cache */
- c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT;
- c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT;
- c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT;
- cachep = & histogram[c0][c1][c2];
- /* If we have not seen this color before, find nearest colormap entry */
- /* and update the cache */
- if (*cachep == 0)
- fill_inverse_cmap(cinfo, c0,c1,c2);
- /* Now emit the colormap index for this cell */
- *outptr++ = (JSAMPLE) (*cachep - 1);
- }
- }
-}
-
-
-METHODDEF(void)
-pass2_fs_dither (j_decompress_ptr cinfo,
- JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)
-/* This version performs Floyd-Steinberg dithering */
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- hist3d histogram = cquantize->histogram;
- register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */
- LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */
- LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */
- register FSERRPTR errorptr; /* => fserrors[] at column before current */
- JSAMPROW inptr; /* => current input pixel */
- JSAMPROW outptr; /* => current output pixel */
- histptr cachep;
- int dir; /* +1 or -1 depending on direction */
- int dir3; /* 3*dir, for advancing inptr & errorptr */
- int row;
- JDIMENSION col;
- JDIMENSION width = cinfo->output_width;
- JSAMPLE *range_limit = cinfo->sample_range_limit;
- int *error_limit = cquantize->error_limiter;
- JSAMPROW colormap0 = cinfo->colormap[0];
- JSAMPROW colormap1 = cinfo->colormap[1];
- JSAMPROW colormap2 = cinfo->colormap[2];
- SHIFT_TEMPS
-
- for (row = 0; row < num_rows; row++) {
- inptr = input_buf[row];
- outptr = output_buf[row];
- if (cquantize->on_odd_row) {
- /* work right to left in this row */
- inptr += (width-1) * 3; /* so point to rightmost pixel */
- outptr += width-1;
- dir = -1;
- dir3 = -3;
- errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */
- cquantize->on_odd_row = FALSE; /* flip for next time */
- } else {
- /* work left to right in this row */
- dir = 1;
- dir3 = 3;
- errorptr = cquantize->fserrors; /* => entry before first real column */
- cquantize->on_odd_row = TRUE; /* flip for next time */
- }
- /* Preset error values: no error propagated to first pixel from left */
- cur0 = cur1 = cur2 = 0;
- /* and no error propagated to row below yet */
- belowerr0 = belowerr1 = belowerr2 = 0;
- bpreverr0 = bpreverr1 = bpreverr2 = 0;
-
- for (col = width; col > 0; col--) {
- /* curN holds the error propagated from the previous pixel on the
- * current line. Add the error propagated from the previous line
- * to form the complete error correction term for this pixel, and
- * round the error term (which is expressed * 16) to an integer.
- * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
- * for either sign of the error value.
- * Note: errorptr points to *previous* column's array entry.
- */
- cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4);
- cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4);
- cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4);
- /* Limit the error using transfer function set by init_error_limit.
- * See comments with init_error_limit for rationale.
- */
- cur0 = error_limit[cur0];
- cur1 = error_limit[cur1];
- cur2 = error_limit[cur2];
- /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
- * The maximum error is +- MAXJSAMPLE (or less with error limiting);
- * this sets the required size of the range_limit array.
- */
- cur0 += GETJSAMPLE(inptr[0]);
- cur1 += GETJSAMPLE(inptr[1]);
- cur2 += GETJSAMPLE(inptr[2]);
- cur0 = GETJSAMPLE(range_limit[cur0]);
- cur1 = GETJSAMPLE(range_limit[cur1]);
- cur2 = GETJSAMPLE(range_limit[cur2]);
- /* Index into the cache with adjusted pixel value */
- cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT];
- /* If we have not seen this color before, find nearest colormap */
- /* entry and update the cache */
- if (*cachep == 0)
- fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT);
- /* Now emit the colormap index for this cell */
- { register int pixcode = *cachep - 1;
- *outptr = (JSAMPLE) pixcode;
- /* Compute representation error for this pixel */
- cur0 -= GETJSAMPLE(colormap0[pixcode]);
- cur1 -= GETJSAMPLE(colormap1[pixcode]);
- cur2 -= GETJSAMPLE(colormap2[pixcode]);
- }
- /* Compute error fractions to be propagated to adjacent pixels.
- * Add these into the running sums, and simultaneously shift the
- * next-line error sums left by 1 column.
- */
- { register LOCFSERROR bnexterr, delta;
-
- bnexterr = cur0; /* Process component 0 */
- delta = cur0 * 2;
- cur0 += delta; /* form error * 3 */
- errorptr[0] = (FSERROR) (bpreverr0 + cur0);
- cur0 += delta; /* form error * 5 */
- bpreverr0 = belowerr0 + cur0;
- belowerr0 = bnexterr;
- cur0 += delta; /* form error * 7 */
- bnexterr = cur1; /* Process component 1 */
- delta = cur1 * 2;
- cur1 += delta; /* form error * 3 */
- errorptr[1] = (FSERROR) (bpreverr1 + cur1);
- cur1 += delta; /* form error * 5 */
- bpreverr1 = belowerr1 + cur1;
- belowerr1 = bnexterr;
- cur1 += delta; /* form error * 7 */
- bnexterr = cur2; /* Process component 2 */
- delta = cur2 * 2;
- cur2 += delta; /* form error * 3 */
- errorptr[2] = (FSERROR) (bpreverr2 + cur2);
- cur2 += delta; /* form error * 5 */
- bpreverr2 = belowerr2 + cur2;
- belowerr2 = bnexterr;
- cur2 += delta; /* form error * 7 */
- }
- /* At this point curN contains the 7/16 error value to be propagated
- * to the next pixel on the current line, and all the errors for the
- * next line have been shifted over. We are therefore ready to move on.
- */
- inptr += dir3; /* Advance pixel pointers to next column */
- outptr += dir;
- errorptr += dir3; /* advance errorptr to current column */
- }
- /* Post-loop cleanup: we must unload the final error values into the
- * final fserrors[] entry. Note we need not unload belowerrN because
- * it is for the dummy column before or after the actual array.
- */
- errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */
- errorptr[1] = (FSERROR) bpreverr1;
- errorptr[2] = (FSERROR) bpreverr2;
- }
-}
-
-
-/*
- * Initialize the error-limiting transfer function (lookup table).
- * The raw F-S error computation can potentially compute error values of up to
- * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be
- * much less, otherwise obviously wrong pixels will be created. (Typical
- * effects include weird fringes at color-area boundaries, isolated bright
- * pixels in a dark area, etc.) The standard advice for avoiding this problem
- * is to ensure that the "corners" of the color cube are allocated as output
- * colors; then repeated errors in the same direction cannot cause cascading
- * error buildup. However, that only prevents the error from getting
- * completely out of hand; Aaron Giles reports that error limiting improves
- * the results even with corner colors allocated.
- * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty
- * well, but the smoother transfer function used below is even better. Thanks
- * to Aaron Giles for this idea.
- */
-
-LOCAL(void)
-init_error_limit (j_decompress_ptr cinfo)
-/* Allocate and fill in the error_limiter table */
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- int * table;
- int in, out;
-
- table = (int *) (*cinfo->mem->alloc_small)
- ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int));
- table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */
- cquantize->error_limiter = table;
-
-#define STEPSIZE ((MAXJSAMPLE+1)/16)
- /* Map errors 1:1 up to +- MAXJSAMPLE/16 */
- out = 0;
- for (in = 0; in < STEPSIZE; in++, out++) {
- table[in] = out; table[-in] = -out;
- }
- /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */
- for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) {
- table[in] = out; table[-in] = -out;
- }
- /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */
- for (; in <= MAXJSAMPLE; in++) {
- table[in] = out; table[-in] = -out;
- }
-#undef STEPSIZE
-}
-
-
-/*
- * Finish up at the end of each pass.
- */
-
-METHODDEF(void)
-finish_pass1 (j_decompress_ptr cinfo)
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
-
- /* Select the representative colors and fill in cinfo->colormap */
- cinfo->colormap = cquantize->sv_colormap;
- select_colors(cinfo, cquantize->desired);
- /* Force next pass to zero the color index table */
- cquantize->needs_zeroed = TRUE;
-}
-
-
-METHODDEF(void)
-finish_pass2 (j_decompress_ptr cinfo)
-{
- /* no work */
-}
-
-
-/*
- * Initialize for each processing pass.
- */
-
-METHODDEF(void)
-start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan)
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
- hist3d histogram = cquantize->histogram;
- int i;
-
- /* Only F-S dithering or no dithering is supported. */
- /* If user asks for ordered dither, give him F-S. */
- if (cinfo->dither_mode != JDITHER_NONE)
- cinfo->dither_mode = JDITHER_FS;
-
- if (is_pre_scan) {
- /* Set up method pointers */
- cquantize->pub.color_quantize = prescan_quantize;
- cquantize->pub.finish_pass = finish_pass1;
- cquantize->needs_zeroed = TRUE; /* Always zero histogram */
- } else {
- /* Set up method pointers */
- if (cinfo->dither_mode == JDITHER_FS)
- cquantize->pub.color_quantize = pass2_fs_dither;
- else
- cquantize->pub.color_quantize = pass2_no_dither;
- cquantize->pub.finish_pass = finish_pass2;
-
- /* Make sure color count is acceptable */
- i = cinfo->actual_number_of_colors;
- if (i < 1)
- ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1);
- if (i > MAXNUMCOLORS)
- ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
-
- if (cinfo->dither_mode == JDITHER_FS) {
- size_t arraysize = (size_t) ((cinfo->output_width + 2) *
- (3 * SIZEOF(FSERROR)));
- /* Allocate Floyd-Steinberg workspace if we didn't already. */
- if (cquantize->fserrors == NULL)
- cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large)
- ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize);
- /* Initialize the propagated errors to zero. */
- jzero_far((void FAR *) cquantize->fserrors, arraysize);
- /* Make the error-limit table if we didn't already. */
- if (cquantize->error_limiter == NULL)
- init_error_limit(cinfo);
- cquantize->on_odd_row = FALSE;
- }
-
- }
- /* Zero the histogram or inverse color map, if necessary */
- if (cquantize->needs_zeroed) {
- for (i = 0; i < HIST_C0_ELEMS; i++) {
- jzero_far((void FAR *) histogram[i],
- HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell));
- }
- cquantize->needs_zeroed = FALSE;
- }
-}
-
-
-/*
- * Switch to a new external colormap between output passes.
- */
-
-METHODDEF(void)
-new_color_map_2_quant (j_decompress_ptr cinfo)
-{
- my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
-
- /* Reset the inverse color map */
- cquantize->needs_zeroed = TRUE;
-}
-
-
-/*
- * Module initialization routine for 2-pass color quantization.
- */
-
-GLOBAL(void)
-jinit_2pass_quantizer (j_decompress_ptr cinfo)
-{
- my_cquantize_ptr cquantize;
- int i;
-
- cquantize = (my_cquantize_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(my_cquantizer));
- cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize;
- cquantize->pub.start_pass = start_pass_2_quant;
- cquantize->pub.new_color_map = new_color_map_2_quant;
- cquantize->fserrors = NULL; /* flag optional arrays not allocated */
- cquantize->error_limiter = NULL;
-
- /* Make sure jdmaster didn't give me a case I can't handle */
- if (cinfo->out_color_components != 3)
- ERREXIT(cinfo, JERR_NOTIMPL);
-
- /* Allocate the histogram/inverse colormap storage */
- cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small)
- ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d));
- for (i = 0; i < HIST_C0_ELEMS; i++) {
- cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell));
- }
- cquantize->needs_zeroed = TRUE; /* histogram is garbage now */
-
- /* Allocate storage for the completed colormap, if required.
- * We do this now since it is FAR storage and may affect
- * the memory manager's space calculations.
- */
- if (cinfo->enable_2pass_quant) {
- /* Make sure color count is acceptable */
- int desired = cinfo->desired_number_of_colors;
- /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */
- if (desired < 8)
- ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8);
- /* Make sure colormap indexes can be represented by JSAMPLEs */
- if (desired > MAXNUMCOLORS)
- ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
- cquantize->sv_colormap = (*cinfo->mem->alloc_sarray)
- ((j_common_ptr) cinfo,JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3);
- cquantize->desired = desired;
- } else
- cquantize->sv_colormap = NULL;
-
- /* Only F-S dithering or no dithering is supported. */
- /* If user asks for ordered dither, give him F-S. */
- if (cinfo->dither_mode != JDITHER_NONE)
- cinfo->dither_mode = JDITHER_FS;
-
- /* Allocate Floyd-Steinberg workspace if necessary.
- * This isn't really needed until pass 2, but again it is FAR storage.
- * Although we will cope with a later change in dither_mode,
- * we do not promise to honor max_memory_to_use if dither_mode changes.
- */
- if (cinfo->dither_mode == JDITHER_FS) {
- cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF(FSERROR))));
- /* Might as well create the error-limiting table too. */
- init_error_limit(cinfo);
- }
-}
-
-#endif /* QUANT_2PASS_SUPPORTED */
diff --git a/engine/code/jpeg-6b/jutils.c b/engine/code/jpeg-6b/jutils.c
deleted file mode 100644
index d18a955..0000000
--- a/engine/code/jpeg-6b/jutils.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * jutils.c
- *
- * Copyright (C) 1991-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains tables and miscellaneous utility routines needed
- * for both compression and decompression.
- * Note we prefix all global names with "j" to minimize conflicts with
- * a surrounding application.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-
-
-/*
- * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element
- * of a DCT block read in natural order (left to right, top to bottom).
- */
-
-#if 0 /* This table is not actually needed in v6a */
-
-const int jpeg_zigzag_order[DCTSIZE2] = {
- 0, 1, 5, 6, 14, 15, 27, 28,
- 2, 4, 7, 13, 16, 26, 29, 42,
- 3, 8, 12, 17, 25, 30, 41, 43,
- 9, 11, 18, 24, 31, 40, 44, 53,
- 10, 19, 23, 32, 39, 45, 52, 54,
- 20, 22, 33, 38, 46, 51, 55, 60,
- 21, 34, 37, 47, 50, 56, 59, 61,
- 35, 36, 48, 49, 57, 58, 62, 63
-};
-
-#endif
-
-/*
- * jpeg_natural_order[i] is the natural-order position of the i'th element
- * of zigzag order.
- *
- * When reading corrupted data, the Huffman decoders could attempt
- * to reference an entry beyond the end of this array (if the decoded
- * zero run length reaches past the end of the block). To prevent
- * wild stores without adding an inner-loop test, we put some extra
- * "63"s after the real entries. This will cause the extra coefficient
- * to be stored in location 63 of the block, not somewhere random.
- * The worst case would be a run-length of 15, which means we need 16
- * fake entries.
- */
-
-const int jpeg_natural_order[DCTSIZE2+16] = {
- 0, 1, 8, 16, 9, 2, 3, 10,
- 17, 24, 32, 25, 18, 11, 4, 5,
- 12, 19, 26, 33, 40, 48, 41, 34,
- 27, 20, 13, 6, 7, 14, 21, 28,
- 35, 42, 49, 56, 57, 50, 43, 36,
- 29, 22, 15, 23, 30, 37, 44, 51,
- 58, 59, 52, 45, 38, 31, 39, 46,
- 53, 60, 61, 54, 47, 55, 62, 63,
- 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
- 63, 63, 63, 63, 63, 63, 63, 63
-};
-
-
-/*
- * Arithmetic utilities
- */
-
-GLOBAL(long)
-jdiv_round_up (long a, long b)
-/* Compute a/b rounded up to next integer, ie, ceil(a/b) */
-/* Assumes a >= 0, b > 0 */
-{
- return (a + b - 1L) / b;
-}
-
-
-GLOBAL(long)
-jround_up (long a, long b)
-/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */
-/* Assumes a >= 0, b > 0 */
-{
- a += b - 1L;
- return a - (a % b);
-}
-
-
-/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays
- * and coefficient-block arrays. This won't work on 80x86 because the arrays
- * are FAR and we're assuming a small-pointer memory model. However, some
- * DOS compilers provide far-pointer versions of memcpy() and memset() even
- * in the small-model libraries. These will be used if USE_FMEM is defined.
- * Otherwise, the routines below do it the hard way. (The performance cost
- * is not all that great, because these routines aren't very heavily used.)
- */
-
-#ifndef NEED_FAR_POINTERS /* normal case, same as regular macros */
-#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size)
-#define FMEMZERO(target,size) MEMZERO(target,size)
-#else /* 80x86 case, define if we can */
-#ifdef USE_FMEM
-#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size))
-#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size))
-#endif
-#endif
-
-
-GLOBAL(void)
-jcopy_sample_rows (JSAMPARRAY input_array, int source_row,
- JSAMPARRAY output_array, int dest_row,
- int num_rows, JDIMENSION num_cols)
-/* Copy some rows of samples from one place to another.
- * num_rows rows are copied from input_array[source_row++]
- * to output_array[dest_row++]; these areas may overlap for duplication.
- * The source and destination arrays must be at least as wide as num_cols.
- */
-{
- register JSAMPROW inptr, outptr;
-#ifdef FMEMCOPY
- register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE));
-#else
- register JDIMENSION count;
-#endif
- register int row;
-
- input_array += source_row;
- output_array += dest_row;
-
- for (row = num_rows; row > 0; row--) {
- inptr = *input_array++;
- outptr = *output_array++;
-#ifdef FMEMCOPY
- FMEMCOPY(outptr, inptr, count);
-#else
- for (count = num_cols; count > 0; count--)
- *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */
-#endif
- }
-}
-
-
-GLOBAL(void)
-jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row,
- JDIMENSION num_blocks)
-/* Copy a row of coefficient blocks from one place to another. */
-{
-#ifdef FMEMCOPY
- FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF)));
-#else
- register JCOEFPTR inptr, outptr;
- register long count;
-
- inptr = (JCOEFPTR) input_row;
- outptr = (JCOEFPTR) output_row;
- for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) {
- *outptr++ = *inptr++;
- }
-#endif
-}
-
-
-GLOBAL(void)
-jzero_far (void FAR * target, size_t bytestozero)
-/* Zero out a chunk of FAR memory. */
-/* This might be sample-array data, block-array data, or alloc_large data. */
-{
-#ifdef FMEMZERO
- FMEMZERO(target, bytestozero);
-#else
- register char FAR * ptr = (char FAR *) target;
- register size_t count;
-
- for (count = bytestozero; count > 0; count--) {
- *ptr++ = 0;
- }
-#endif
-}
diff --git a/engine/code/jpeg-6b/jversion.h b/engine/code/jpeg-6b/jversion.h
deleted file mode 100644
index 6472c58..0000000
--- a/engine/code/jpeg-6b/jversion.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * jversion.h
- *
- * Copyright (C) 1991-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains software version identification.
- */
-
-
-#define JVERSION "6b 27-Mar-1998"
-
-#define JCOPYRIGHT "Copyright (C) 1998, Thomas G. Lane"
diff --git a/engine/code/null/mac_net.c b/engine/code/null/mac_net.c
deleted file mode 100644
index 8f9c22f..0000000
--- a/engine/code/null/mac_net.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-
-/*
-=============
-NET_StringToAdr
-
-localhost
-idnewt
-idnewt:28000
-192.246.40.70
-192.246.40.70:28000
-=============
-*/
-qboolean NET_StringToAdr (char *s, netadr_t *a)
-{
- if (!strcmp (s, "localhost")) {
- memset (a, 0, sizeof(*a));
- a->type = NA_LOOPBACK;
- return true;
- }
-
- return false;
-}
-
-/*
-==================
-Sys_SendPacket
-==================
-*/
-void Sys_SendPacket( int length, void *data, netadr_t to ) {
-}
-
-/*
-==================
-Sys_GetPacket
-
-Never called by the game logic, just the system event queing
-==================
-*/
-qboolean Sys_GetPacket ( netadr_t *net_from, msg_t *net_message ) {
- return false;
-}
diff --git a/engine/code/null/null_client.c b/engine/code/null/null_client.c
deleted file mode 100644
index e67b95b..0000000
--- a/engine/code/null/null_client.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-
-cvar_t *cl_shownet;
-
-void CL_Shutdown( void ) {
-}
-
-void CL_Init( void ) {
- cl_shownet = Cvar_Get ("cl_shownet", "0", CVAR_TEMP );
-}
-
-void CL_MouseEvent( int dx, int dy, int time ) {
-}
-
-void Key_WriteBindings( fileHandle_t f ) {
-}
-
-void CL_Frame ( int msec ) {
-}
-
-void CL_PacketEvent( netadr_t from, msg_t *msg ) {
-}
-
-void CL_CharEvent( int key ) {
-}
-
-void CL_Disconnect( qboolean showMainMenu ) {
-}
-
-void CL_MapLoading( void ) {
-}
-
-qboolean CL_GameCommand( void ) {
- return qfalse;
-}
-
-void CL_KeyEvent (int key, qboolean down, unsigned time) {
-}
-
-qboolean UI_GameCommand( void ) {
- return qfalse;
-}
-
-void CL_ForwardCommandToServer( const char *string ) {
-}
-
-void CL_ConsolePrint( char *txt ) {
-}
-
-void CL_JoystickEvent( int axis, int value, int time ) {
-}
-
-void CL_InitKeyCommands( void ) {
-}
-
-void CL_CDDialog( void ) {
-}
-
-void CL_FlushMemory( void ) {
-}
-
-void CL_StartHunkUsers( qboolean rendererOnly ) {
-}
-
-void CL_Snd_Restart(void)
-{
-}
-
-void CL_ShutdownAll(void) {}
-
-qboolean CL_CDKeyValidate( const char *key, const char *checksum ) { return qtrue; }
diff --git a/engine/code/null/null_glimp.c b/engine/code/null/null_glimp.c
deleted file mode 100644
index c9a9d73..0000000
--- a/engine/code/null/null_glimp.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "../renderer/tr_local.h"
-
-
-qboolean ( * qwglSwapIntervalEXT)( int interval );
-void ( * qglMultiTexCoord2fARB )( GLenum texture, float s, float t );
-void ( * qglActiveTextureARB )( GLenum texture );
-void ( * qglClientActiveTextureARB )( GLenum texture );
-
-
-void ( * qglLockArraysEXT)( int, int);
-void ( * qglUnlockArraysEXT) ( void );
-
-
-void GLimp_EndFrame( void ) {
-}
-
-int GLimp_Init( void )
-{
-}
-
-void GLimp_Shutdown( void ) {
-}
-
-void GLimp_EnableLogging( qboolean enable ) {
-}
-
-void GLimp_LogComment( char *comment ) {
-}
-
-qboolean QGL_Init( const char *dllname ) {
- return qtrue;
-}
-
-void QGL_Shutdown( void ) {
-}
diff --git a/engine/code/null/null_input.c b/engine/code/null/null_input.c
deleted file mode 100644
index 8a76555..0000000
--- a/engine/code/null/null_input.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-void IN_Init( void ) {
-}
-
-void IN_Frame (void) {
-}
-
-void IN_Shutdown( void ) {
-}
-
-void IN_Restart( void ) {
-}
-
-void Sys_SendKeyEvents (void) {
-}
-
diff --git a/engine/code/null/null_main.c b/engine/code/null/null_main.c
deleted file mode 100644
index f2d9a2d..0000000
--- a/engine/code/null/null_main.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// sys_null.h -- null system driver to aid porting efforts
-
-#include <errno.h>
-#include <stdio.h>
-#include "../qcommon/qcommon.h"
-
-int sys_curtime;
-
-
-//===================================================================
-
-void Sys_BeginStreamedFile( FILE *f, int readAhead ) {
-}
-
-void Sys_EndStreamedFile( FILE *f ) {
-}
-
-int Sys_StreamedRead( void *buffer, int size, int count, FILE *f ) {
- return fread( buffer, size, count, f );
-}
-
-void Sys_StreamSeek( FILE *f, int offset, int origin ) {
- fseek( f, offset, origin );
-}
-
-
-//===================================================================
-
-
-void Sys_mkdir ( const char *path ) {
-}
-
-void Sys_Error (char *error, ...) {
- va_list argptr;
-
- printf ("Sys_Error: ");
- va_start (argptr,error);
- vprintf (error,argptr);
- va_end (argptr);
- printf ("\n");
-
- exit (1);
-}
-
-void Sys_Quit (void) {
- exit (0);
-}
-
-void Sys_UnloadGame (void) {
-}
-
-void *Sys_GetGameAPI (void *parms) {
- return NULL;
-}
-
-char *Sys_GetClipboardData( void ) {
- return NULL;
-}
-
-int Sys_Milliseconds (void) {
- return 0;
-}
-
-void Sys_Mkdir (char *path) {
-}
-
-char *Sys_FindFirst (char *path, unsigned musthave, unsigned canthave) {
- return NULL;
-}
-
-char *Sys_FindNext (unsigned musthave, unsigned canthave) {
- return NULL;
-}
-
-void Sys_FindClose (void) {
-}
-
-void Sys_Init (void) {
-}
-
-
-void Sys_EarlyOutput( char *string ) {
- printf( "%s", string );
-}
-
-
-void main (int argc, char **argv) {
- Com_Init (argc, argv);
-
- while (1) {
- Com_Frame( );
- }
-}
-
-
diff --git a/engine/code/null/null_net.c b/engine/code/null/null_net.c
deleted file mode 100644
index 04d5e7a..0000000
--- a/engine/code/null/null_net.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../qcommon/qcommon.h"
-
-/*
-=============
-NET_StringToAdr
-
-localhost
-idnewt
-idnewt:28000
-192.246.40.70
-192.246.40.70:28000
-=============
-*/
-qboolean NET_StringToAdr (char *s, netadr_t *a)
-{
- if (!strcmp (s, "localhost")) {
- memset (a, 0, sizeof(*a));
- a->type = NA_LOOPBACK;
- return true;
- }
-
- return false;
-}
-
-/*
-==================
-Sys_SendPacket
-==================
-*/
-void Sys_SendPacket( int length, void *data, netadr_t to ) {
-}
-
-/*
-==================
-Sys_GetPacket
-
-Never called by the game logic, just the system event queing
-==================
-*/
-qboolean Sys_GetPacket ( netadr_t *net_from, msg_t *net_message ) {
- return false;
-}
diff --git a/engine/code/null/null_snddma.c b/engine/code/null/null_snddma.c
deleted file mode 100644
index 448a4dc..0000000
--- a/engine/code/null/null_snddma.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-// snddma_null.c
-// all other sound mixing is portable
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-
-qboolean SNDDMA_Init(void)
-{
- return qfalse;
-}
-
-int SNDDMA_GetDMAPos(void)
-{
- return 0;
-}
-
-void SNDDMA_Shutdown(void)
-{
-}
-
-void SNDDMA_BeginPainting (void)
-{
-}
-
-void SNDDMA_Submit(void)
-{
-}
-
-sfxHandle_t S_RegisterSound( const char *name, qboolean compressed )
-{
- return 0;
-}
-
-void S_StartLocalSound( sfxHandle_t sfxHandle, int channelNum ) {
-}
-
-void S_ClearSoundBuffer( void ) {
-}
diff --git a/engine/code/q3_ui/ui_addbots.c b/engine/code/q3_ui/ui_addbots.c
deleted file mode 100644
index 8b9f448..0000000
--- a/engine/code/q3_ui/ui_addbots.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-ADD BOTS MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-#define ART_FIGHT0 "menu/art/accept_0"
-#define ART_FIGHT1 "menu/art/accept_1"
-#define ART_BACKGROUND "menu/art/addbotframe"
-#define ART_ARROWS "menu/art/arrows_vert_0"
-#define ART_ARROWUP "menu/art/arrows_vert_top"
-#define ART_ARROWDOWN "menu/art/arrows_vert_bot"
-
-#define ID_BACK 10
-#define ID_GO 11
-#define ID_LIST 12
-#define ID_UP 13
-#define ID_DOWN 14
-#define ID_SKILL 15
-#define ID_TEAM 16
-#define ID_BOTNAME0 20
-#define ID_BOTNAME1 21
-#define ID_BOTNAME2 22
-#define ID_BOTNAME3 23
-#define ID_BOTNAME4 24
-#define ID_BOTNAME5 25
-#define ID_BOTNAME6 26
-
-
-typedef struct {
- menuframework_s menu;
- menubitmap_s arrows;
- menubitmap_s up;
- menubitmap_s down;
- menutext_s bots[7];
- menulist_s skill;
- menulist_s team;
- menubitmap_s go;
- menubitmap_s back;
-
- int numBots;
- int delay;
- int baseBotNum;
- int selectedBotNum;
- int sortedBotNums[MAX_BOTS];
- char botnames[7][32];
-} addBotsMenuInfo_t;
-
-static addBotsMenuInfo_t addBotsMenuInfo;
-
-
-/*
-=================
-UI_AddBotsMenu_FightEvent
-=================
-*/
-static void UI_AddBotsMenu_FightEvent( void* ptr, int event ) {
- const char *team;
- int skill;
-
- if (event != QM_ACTIVATED) {
- return;
- }
-
- team = addBotsMenuInfo.team.itemnames[addBotsMenuInfo.team.curvalue];
- skill = addBotsMenuInfo.skill.curvalue + 1;
-
- trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s %i\n",
- addBotsMenuInfo.botnames[addBotsMenuInfo.selectedBotNum], skill, team, addBotsMenuInfo.delay) );
-
- addBotsMenuInfo.delay += 1500;
-}
-
-
-/*
-=================
-UI_AddBotsMenu_BotEvent
-=================
-*/
-static void UI_AddBotsMenu_BotEvent( void* ptr, int event ) {
- if (event != QM_ACTIVATED) {
- return;
- }
-
- addBotsMenuInfo.bots[addBotsMenuInfo.selectedBotNum].color = color_orange;
- addBotsMenuInfo.selectedBotNum = ((menucommon_s*)ptr)->id - ID_BOTNAME0;
- addBotsMenuInfo.bots[addBotsMenuInfo.selectedBotNum].color = color_white;
-}
-
-
-/*
-=================
-UI_AddBotsMenu_BackEvent
-=================
-*/
-static void UI_AddBotsMenu_BackEvent( void* ptr, int event ) {
- if (event != QM_ACTIVATED) {
- return;
- }
- UI_PopMenu();
-}
-
-
-/*
-=================
-UI_AddBotsMenu_SetBotNames
-=================
-*/
-static void UI_AddBotsMenu_SetBotNames( void ) {
- int n;
- const char *info;
-
- for ( n = 0; n < 7; n++ ) {
- info = UI_GetBotInfoByNumber( addBotsMenuInfo.sortedBotNums[addBotsMenuInfo.baseBotNum + n] );
- Q_strncpyz( addBotsMenuInfo.botnames[n], Info_ValueForKey( info, "name" ), sizeof(addBotsMenuInfo.botnames[n]) );
- }
-
-}
-
-
-/*
-=================
-UI_AddBotsMenu_UpEvent
-=================
-*/
-static void UI_AddBotsMenu_UpEvent( void* ptr, int event ) {
- if (event != QM_ACTIVATED) {
- return;
- }
-
- if( addBotsMenuInfo.baseBotNum > 0 ) {
- addBotsMenuInfo.baseBotNum--;
- UI_AddBotsMenu_SetBotNames();
- }
-}
-
-
-/*
-=================
-UI_AddBotsMenu_DownEvent
-=================
-*/
-static void UI_AddBotsMenu_DownEvent( void* ptr, int event ) {
- if (event != QM_ACTIVATED) {
- return;
- }
-
- if( addBotsMenuInfo.baseBotNum + 7 < addBotsMenuInfo.numBots ) {
- addBotsMenuInfo.baseBotNum++;
- UI_AddBotsMenu_SetBotNames();
- }
-}
-
-
-/*
-=================
-UI_AddBotsMenu_GetSortedBotNums
-=================
-*/
-static int QDECL UI_AddBotsMenu_SortCompare( const void *arg1, const void *arg2 ) {
- int num1, num2;
- const char *info1, *info2;
- const char *name1, *name2;
-
- num1 = *(int *)arg1;
- num2 = *(int *)arg2;
-
- info1 = UI_GetBotInfoByNumber( num1 );
- info2 = UI_GetBotInfoByNumber( num2 );
-
- name1 = Info_ValueForKey( info1, "name" );
- name2 = Info_ValueForKey( info2, "name" );
-
- return Q_stricmp( name1, name2 );
-}
-
-static void UI_AddBotsMenu_GetSortedBotNums( void ) {
- int n;
-
- // initialize the array
- for( n = 0; n < addBotsMenuInfo.numBots; n++ ) {
- addBotsMenuInfo.sortedBotNums[n] = n;
- }
-
- qsort( addBotsMenuInfo.sortedBotNums, addBotsMenuInfo.numBots, sizeof(addBotsMenuInfo.sortedBotNums[0]), UI_AddBotsMenu_SortCompare );
-}
-
-
-/*
-=================
-UI_AddBotsMenu_Draw
-=================
-*/
-static void UI_AddBotsMenu_Draw( void ) {
- UI_DrawBannerString( 320, 16, "ADD BOTS", UI_CENTER, color_white );
- UI_DrawNamedPic( 320-233, 240-166, 466, 332, ART_BACKGROUND );
-
- // standard menu drawing
- Menu_Draw( &addBotsMenuInfo.menu );
-}
-
-
-/*
-=================
-UI_AddBotsMenu_Init
-=================
-*/
-static const char *skillNames[] = {
- "I Can Win",
- "Bring It On",
- "Hurt Me Plenty",
- "Hardcore",
- "Nightmare!",
- NULL
-};
-
-static const char *teamNames1[] = {
- "Free",
- NULL
-};
-
-static const char *teamNames2[] = {
- "Red",
- "Blue",
- NULL
-};
-
-static void UI_AddBotsMenu_Init( void ) {
- int n;
- int y;
- int gametype;
- int count;
- char info[MAX_INFO_STRING];
-
- trap_GetConfigString(CS_SERVERINFO, info, MAX_INFO_STRING);
- gametype = atoi( Info_ValueForKey( info,"g_gametype" ) );
-
- memset( &addBotsMenuInfo, 0 ,sizeof(addBotsMenuInfo) );
- addBotsMenuInfo.menu.draw = UI_AddBotsMenu_Draw;
- addBotsMenuInfo.menu.fullscreen = qfalse;
- addBotsMenuInfo.menu.wrapAround = qtrue;
- addBotsMenuInfo.delay = 1000;
-
- UI_AddBots_Cache();
-
- addBotsMenuInfo.numBots = UI_GetNumBots();
- count = addBotsMenuInfo.numBots < 7 ? addBotsMenuInfo.numBots : 7;
-
- addBotsMenuInfo.arrows.generic.type = MTYPE_BITMAP;
- addBotsMenuInfo.arrows.generic.name = ART_ARROWS;
- addBotsMenuInfo.arrows.generic.flags = QMF_INACTIVE;
- addBotsMenuInfo.arrows.generic.x = 200;
- addBotsMenuInfo.arrows.generic.y = 128;
- addBotsMenuInfo.arrows.width = 64;
- addBotsMenuInfo.arrows.height = 128;
-
- addBotsMenuInfo.up.generic.type = MTYPE_BITMAP;
- addBotsMenuInfo.up.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- addBotsMenuInfo.up.generic.x = 200;
- addBotsMenuInfo.up.generic.y = 128;
- addBotsMenuInfo.up.generic.id = ID_UP;
- addBotsMenuInfo.up.generic.callback = UI_AddBotsMenu_UpEvent;
- addBotsMenuInfo.up.width = 64;
- addBotsMenuInfo.up.height = 64;
- addBotsMenuInfo.up.focuspic = ART_ARROWUP;
-
- addBotsMenuInfo.down.generic.type = MTYPE_BITMAP;
- addBotsMenuInfo.down.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- addBotsMenuInfo.down.generic.x = 200;
- addBotsMenuInfo.down.generic.y = 128+64;
- addBotsMenuInfo.down.generic.id = ID_DOWN;
- addBotsMenuInfo.down.generic.callback = UI_AddBotsMenu_DownEvent;
- addBotsMenuInfo.down.width = 64;
- addBotsMenuInfo.down.height = 64;
- addBotsMenuInfo.down.focuspic = ART_ARROWDOWN;
-
- for( n = 0, y = 120; n < count; n++, y += 20 ) {
- addBotsMenuInfo.bots[n].generic.type = MTYPE_PTEXT;
- addBotsMenuInfo.bots[n].generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- addBotsMenuInfo.bots[n].generic.id = ID_BOTNAME0 + n;
- addBotsMenuInfo.bots[n].generic.x = 320 - 56;
- addBotsMenuInfo.bots[n].generic.y = y;
- addBotsMenuInfo.bots[n].generic.callback = UI_AddBotsMenu_BotEvent;
- addBotsMenuInfo.bots[n].string = addBotsMenuInfo.botnames[n];
- addBotsMenuInfo.bots[n].color = color_orange;
- addBotsMenuInfo.bots[n].style = UI_LEFT|UI_SMALLFONT;
- }
-
- y += 12;
- addBotsMenuInfo.skill.generic.type = MTYPE_SPINCONTROL;
- addBotsMenuInfo.skill.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- addBotsMenuInfo.skill.generic.x = 320;
- addBotsMenuInfo.skill.generic.y = y;
- addBotsMenuInfo.skill.generic.name = "Skill:";
- addBotsMenuInfo.skill.generic.id = ID_SKILL;
- addBotsMenuInfo.skill.itemnames = skillNames;
- addBotsMenuInfo.skill.curvalue = Com_Clamp( 0, 4, (int)trap_Cvar_VariableValue( "g_spSkill" ) - 1 );
-
- y += SMALLCHAR_HEIGHT;
- addBotsMenuInfo.team.generic.type = MTYPE_SPINCONTROL;
- addBotsMenuInfo.team.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- addBotsMenuInfo.team.generic.x = 320;
- addBotsMenuInfo.team.generic.y = y;
- addBotsMenuInfo.team.generic.name = "Team: ";
- addBotsMenuInfo.team.generic.id = ID_TEAM;
- if( gametype >= GT_TEAM ) {
- addBotsMenuInfo.team.itemnames = teamNames2;
- }
- else {
- addBotsMenuInfo.team.itemnames = teamNames1;
- addBotsMenuInfo.team.generic.flags = QMF_GRAYED;
- }
-
- addBotsMenuInfo.go.generic.type = MTYPE_BITMAP;
- addBotsMenuInfo.go.generic.name = ART_FIGHT0;
- addBotsMenuInfo.go.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- addBotsMenuInfo.go.generic.id = ID_GO;
- addBotsMenuInfo.go.generic.callback = UI_AddBotsMenu_FightEvent;
- addBotsMenuInfo.go.generic.x = 320+128-128;
- addBotsMenuInfo.go.generic.y = 256+128-64;
- addBotsMenuInfo.go.width = 128;
- addBotsMenuInfo.go.height = 64;
- addBotsMenuInfo.go.focuspic = ART_FIGHT1;
-
- addBotsMenuInfo.back.generic.type = MTYPE_BITMAP;
- addBotsMenuInfo.back.generic.name = ART_BACK0;
- addBotsMenuInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- addBotsMenuInfo.back.generic.id = ID_BACK;
- addBotsMenuInfo.back.generic.callback = UI_AddBotsMenu_BackEvent;
- addBotsMenuInfo.back.generic.x = 320-128;
- addBotsMenuInfo.back.generic.y = 256+128-64;
- addBotsMenuInfo.back.width = 128;
- addBotsMenuInfo.back.height = 64;
- addBotsMenuInfo.back.focuspic = ART_BACK1;
-
- addBotsMenuInfo.baseBotNum = 0;
- addBotsMenuInfo.selectedBotNum = 0;
- addBotsMenuInfo.bots[0].color = color_white;
-
- UI_AddBotsMenu_GetSortedBotNums();
- UI_AddBotsMenu_SetBotNames();
-
- Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.arrows );
-
- Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.up );
- Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.down );
- for( n = 0; n < count; n++ ) {
- Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.bots[n] );
- }
- Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.skill );
- Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.team );
- Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.go );
- Menu_AddItem( &addBotsMenuInfo.menu, &addBotsMenuInfo.back );
-}
-
-
-/*
-=================
-UI_AddBots_Cache
-=================
-*/
-void UI_AddBots_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_FIGHT0 );
- trap_R_RegisterShaderNoMip( ART_FIGHT1 );
- trap_R_RegisterShaderNoMip( ART_BACKGROUND );
- trap_R_RegisterShaderNoMip( ART_ARROWS );
- trap_R_RegisterShaderNoMip( ART_ARROWUP );
- trap_R_RegisterShaderNoMip( ART_ARROWDOWN );
-}
-
-
-/*
-=================
-UI_AddBotsMenu
-=================
-*/
-void UI_AddBotsMenu( void ) {
- UI_AddBotsMenu_Init();
- UI_PushMenu( &addBotsMenuInfo.menu );
-}
diff --git a/engine/code/q3_ui/ui_atoms.c b/engine/code/q3_ui/ui_atoms.c
deleted file mode 100644
index c798bdd..0000000
--- a/engine/code/q3_ui/ui_atoms.c
+++ /dev/null
@@ -1,1261 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/**********************************************************************
- UI_ATOMS.C
-
- User interface building blocks and support functions.
-**********************************************************************/
-#include "ui_local.h"
-
-uiStatic_t uis;
-qboolean m_entersound; // after a frame, so caching won't disrupt the sound
-
-void QDECL Com_Error( int level, const char *error, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, error);
- Q_vsnprintf (text, sizeof(text), error, argptr);
- va_end (argptr);
-
- trap_Error( va("%s", text) );
-}
-
-void QDECL Com_Printf( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- Q_vsnprintf (text, sizeof(text), msg, argptr);
- va_end (argptr);
-
- trap_Print( va("%s", text) );
-}
-
-/*
-=================
-UI_ClampCvar
-=================
-*/
-float UI_ClampCvar( float min, float max, float value )
-{
- if ( value < min ) return min;
- if ( value > max ) return max;
- return value;
-}
-
-/*
-=================
-UI_StartDemoLoop
-=================
-*/
-void UI_StartDemoLoop( void ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "d1\n" );
-}
-
-/*
-=================
-UI_PushMenu
-=================
-*/
-void UI_PushMenu( menuframework_s *menu )
-{
- int i;
- menucommon_s* item;
-
- // avoid stacking menus invoked by hotkeys
- for (i=0 ; i<uis.menusp ; i++)
- {
- if (uis.stack[i] == menu)
- {
- uis.menusp = i;
- break;
- }
- }
-
- if (i == uis.menusp)
- {
- if (uis.menusp >= MAX_MENUDEPTH)
- trap_Error("UI_PushMenu: menu stack overflow");
-
- uis.stack[uis.menusp++] = menu;
- }
-
- uis.activemenu = menu;
-
- // default cursor position
- menu->cursor = 0;
- menu->cursor_prev = 0;
-
- m_entersound = qtrue;
-
- trap_Key_SetCatcher( KEYCATCH_UI );
-
- // force first available item to have focus
- for (i=0; i<menu->nitems; i++)
- {
- item = (menucommon_s *)menu->items[i];
- if (!(item->flags & (QMF_GRAYED|QMF_MOUSEONLY|QMF_INACTIVE)))
- {
- menu->cursor_prev = -1;
- Menu_SetCursor( menu, i );
- break;
- }
- }
-
- uis.firstdraw = qtrue;
-}
-
-/*
-=================
-UI_PopMenu
-=================
-*/
-void UI_PopMenu (void)
-{
- trap_S_StartLocalSound( menu_out_sound, CHAN_LOCAL_SOUND );
-
- uis.menusp--;
-
- if (uis.menusp < 0)
- trap_Error ("UI_PopMenu: menu stack underflow");
-
- if (uis.menusp) {
- uis.activemenu = uis.stack[uis.menusp-1];
- uis.firstdraw = qtrue;
- }
- else {
- UI_ForceMenuOff ();
- }
-}
-
-void UI_ForceMenuOff (void)
-{
- uis.menusp = 0;
- uis.activemenu = NULL;
-
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
-}
-
-/*
-=================
-UI_LerpColor
-=================
-*/
-void UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)
-{
- int i;
-
- // lerp and clamp each component
- for (i=0; i<4; i++)
- {
- c[i] = a[i] + t*(b[i]-a[i]);
- if (c[i] < 0)
- c[i] = 0;
- else if (c[i] > 1.0)
- c[i] = 1.0;
- }
-}
-
-/*
-=================
-UI_DrawProportionalString2
-=================
-*/
-static int propMap[128][3] = {
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-
-{0, 0, PROP_SPACE_WIDTH}, // SPACE
-{11, 122, 7}, // !
-{154, 181, 14}, // "
-{55, 122, 17}, // #
-{79, 122, 18}, // $
-{101, 122, 23}, // %
-{153, 122, 18}, // &
-{9, 93, 7}, // '
-{207, 122, 8}, // (
-{230, 122, 9}, // )
-{177, 122, 18}, // *
-{30, 152, 18}, // +
-{85, 181, 7}, // ,
-{34, 93, 11}, // -
-{110, 181, 6}, // .
-{130, 152, 14}, // /
-
-{22, 64, 17}, // 0
-{41, 64, 12}, // 1
-{58, 64, 17}, // 2
-{78, 64, 18}, // 3
-{98, 64, 19}, // 4
-{120, 64, 18}, // 5
-{141, 64, 18}, // 6
-{204, 64, 16}, // 7
-{162, 64, 17}, // 8
-{182, 64, 18}, // 9
-{59, 181, 7}, // :
-{35,181, 7}, // ;
-{203, 152, 14}, // <
-{56, 93, 14}, // =
-{228, 152, 14}, // >
-{177, 181, 18}, // ?
-
-{28, 122, 22}, // @
-{5, 4, 18}, // A
-{27, 4, 18}, // B
-{48, 4, 18}, // C
-{69, 4, 17}, // D
-{90, 4, 13}, // E
-{106, 4, 13}, // F
-{121, 4, 18}, // G
-{143, 4, 17}, // H
-{164, 4, 8}, // I
-{175, 4, 16}, // J
-{195, 4, 18}, // K
-{216, 4, 12}, // L
-{230, 4, 23}, // M
-{6, 34, 18}, // N
-{27, 34, 18}, // O
-
-{48, 34, 18}, // P
-{68, 34, 18}, // Q
-{90, 34, 17}, // R
-{110, 34, 18}, // S
-{130, 34, 14}, // T
-{146, 34, 18}, // U
-{166, 34, 19}, // V
-{185, 34, 29}, // W
-{215, 34, 18}, // X
-{234, 34, 18}, // Y
-{5, 64, 14}, // Z
-{60, 152, 7}, // [
-{106, 151, 13}, // '\'
-{83, 152, 7}, // ]
-{128, 122, 17}, // ^
-{4, 152, 21}, // _
-
-{134, 181, 5}, // '
-{5, 4, 18}, // A
-{27, 4, 18}, // B
-{48, 4, 18}, // C
-{69, 4, 17}, // D
-{90, 4, 13}, // E
-{106, 4, 13}, // F
-{121, 4, 18}, // G
-{143, 4, 17}, // H
-{164, 4, 8}, // I
-{175, 4, 16}, // J
-{195, 4, 18}, // K
-{216, 4, 12}, // L
-{230, 4, 23}, // M
-{6, 34, 18}, // N
-{27, 34, 18}, // O
-
-{48, 34, 18}, // P
-{68, 34, 18}, // Q
-{90, 34, 17}, // R
-{110, 34, 18}, // S
-{130, 34, 14}, // T
-{146, 34, 18}, // U
-{166, 34, 19}, // V
-{185, 34, 29}, // W
-{215, 34, 18}, // X
-{234, 34, 18}, // Y
-{5, 64, 14}, // Z
-{153, 152, 13}, // {
-{11, 181, 5}, // |
-{180, 152, 13}, // }
-{79, 93, 17}, // ~
-{0, 0, -1} // DEL
-};
-
-static int propMapB[26][3] = {
-{11, 12, 33},
-{49, 12, 31},
-{85, 12, 31},
-{120, 12, 30},
-{156, 12, 21},
-{183, 12, 21},
-{207, 12, 32},
-
-{13, 55, 30},
-{49, 55, 13},
-{66, 55, 29},
-{101, 55, 31},
-{135, 55, 21},
-{158, 55, 40},
-{204, 55, 32},
-
-{12, 97, 31},
-{48, 97, 31},
-{82, 97, 30},
-{118, 97, 30},
-{153, 97, 30},
-{185, 97, 25},
-{213, 97, 30},
-
-{11, 139, 32},
-{42, 139, 51},
-{93, 139, 32},
-{126, 139, 31},
-{158, 139, 25},
-};
-
-#define PROPB_GAP_WIDTH 4
-#define PROPB_SPACE_WIDTH 12
-#define PROPB_HEIGHT 36
-
-/*
-=================
-UI_DrawBannerString
-=================
-*/
-static void UI_DrawBannerString2( int x, int y, const char* str, vec4_t color )
-{
- const char* s;
- unsigned char ch;
- float ax;
- float ay;
- float aw;
- float ah;
- float frow;
- float fcol;
- float fwidth;
- float fheight;
-
- // draw the colored text
- trap_R_SetColor( color );
-
- ax = x * uis.xscale + uis.bias;
- ay = y * uis.yscale;
-
- s = str;
- while ( *s )
- {
- ch = *s & 127;
- if ( ch == ' ' ) {
- ax += ((float)PROPB_SPACE_WIDTH + (float)PROPB_GAP_WIDTH)* uis.xscale;
- }
- else if ( ch >= 'A' && ch <= 'Z' ) {
- ch -= 'A';
- fcol = (float)propMapB[ch][0] / 256.0f;
- frow = (float)propMapB[ch][1] / 256.0f;
- fwidth = (float)propMapB[ch][2] / 256.0f;
- fheight = (float)PROPB_HEIGHT / 256.0f;
- aw = (float)propMapB[ch][2] * uis.xscale;
- ah = (float)PROPB_HEIGHT * uis.yscale;
- trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, uis.charsetPropB );
- ax += (aw + (float)PROPB_GAP_WIDTH * uis.xscale);
- }
- s++;
- }
-
- trap_R_SetColor( NULL );
-}
-
-void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color ) {
- const char * s;
- int ch;
- int width;
- vec4_t drawcolor;
-
- // find the width of the drawn text
- s = str;
- width = 0;
- while ( *s ) {
- ch = *s;
- if ( ch == ' ' ) {
- width += PROPB_SPACE_WIDTH;
- }
- else if ( ch >= 'A' && ch <= 'Z' ) {
- width += propMapB[ch - 'A'][2] + PROPB_GAP_WIDTH;
- }
- s++;
- }
- width -= PROPB_GAP_WIDTH;
-
- switch( style & UI_FORMATMASK ) {
- case UI_CENTER:
- x -= width / 2;
- break;
-
- case UI_RIGHT:
- x -= width;
- break;
-
- case UI_LEFT:
- default:
- break;
- }
-
- if ( style & UI_DROPSHADOW ) {
- drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
- drawcolor[3] = color[3];
- UI_DrawBannerString2( x+2, y+2, str, drawcolor );
- }
-
- UI_DrawBannerString2( x, y, str, color );
-}
-
-
-int UI_ProportionalStringWidth( const char* str ) {
- const char * s;
- int ch;
- int charWidth;
- int width;
-
- s = str;
- width = 0;
- while ( *s ) {
- ch = *s & 127;
- charWidth = propMap[ch][2];
- if ( charWidth != -1 ) {
- width += charWidth;
- width += PROP_GAP_WIDTH;
- }
- s++;
- }
-
- width -= PROP_GAP_WIDTH;
- return width;
-}
-
-static void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t color, float sizeScale, qhandle_t charset )
-{
- const char* s;
- unsigned char ch;
- float ax;
- float ay;
- float aw = 0;
- float ah;
- float frow;
- float fcol;
- float fwidth;
- float fheight;
-
- // draw the colored text
- trap_R_SetColor( color );
-
- ax = x * uis.xscale + uis.bias;
- ay = y * uis.yscale;
-
- s = str;
- while ( *s )
- {
- ch = *s & 127;
- if ( ch == ' ' ) {
- aw = (float)PROP_SPACE_WIDTH * uis.xscale * sizeScale;
- }
- else if ( propMap[ch][2] != -1 ) {
- fcol = (float)propMap[ch][0] / 256.0f;
- frow = (float)propMap[ch][1] / 256.0f;
- fwidth = (float)propMap[ch][2] / 256.0f;
- fheight = (float)PROP_HEIGHT / 256.0f;
- aw = (float)propMap[ch][2] * uis.xscale * sizeScale;
- ah = (float)PROP_HEIGHT * uis.yscale * sizeScale;
- trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, charset );
- }
-
- ax += (aw + (float)PROP_GAP_WIDTH * uis.xscale * sizeScale);
- s++;
- }
-
- trap_R_SetColor( NULL );
-}
-
-/*
-=================
-UI_ProportionalSizeScale
-=================
-*/
-float UI_ProportionalSizeScale( int style ) {
- if( style & UI_SMALLFONT ) {
- return PROP_SMALL_SIZE_SCALE;
- }
-
- return 1.00;
-}
-
-
-/*
-=================
-UI_DrawProportionalString
-=================
-*/
-void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ) {
- vec4_t drawcolor;
- int width;
- float sizeScale;
-
- sizeScale = UI_ProportionalSizeScale( style );
-
- switch( style & UI_FORMATMASK ) {
- case UI_CENTER:
- width = UI_ProportionalStringWidth( str ) * sizeScale;
- x -= width / 2;
- break;
-
- case UI_RIGHT:
- width = UI_ProportionalStringWidth( str ) * sizeScale;
- x -= width;
- break;
-
- case UI_LEFT:
- default:
- break;
- }
-
- if ( style & UI_DROPSHADOW ) {
- drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
- drawcolor[3] = color[3];
- UI_DrawProportionalString2( x+2, y+2, str, drawcolor, sizeScale, uis.charsetProp );
- }
-
- if ( style & UI_INVERSE ) {
- drawcolor[0] = color[0] * 0.7;
- drawcolor[1] = color[1] * 0.7;
- drawcolor[2] = color[2] * 0.7;
- drawcolor[3] = color[3];
- UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, uis.charsetProp );
- return;
- }
-
- if ( style & UI_PULSE ) {
- drawcolor[0] = color[0] * 0.7;
- drawcolor[1] = color[1] * 0.7;
- drawcolor[2] = color[2] * 0.7;
- drawcolor[3] = color[3];
- UI_DrawProportionalString2( x, y, str, color, sizeScale, uis.charsetProp );
-
- drawcolor[0] = color[0];
- drawcolor[1] = color[1];
- drawcolor[2] = color[2];
- drawcolor[3] = 0.5 + 0.5 * sin( uis.realtime / PULSE_DIVISOR );
- UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, uis.charsetPropGlow );
- return;
- }
-
- UI_DrawProportionalString2( x, y, str, color, sizeScale, uis.charsetProp );
-}
-
-/*
-=================
-UI_DrawProportionalString_Wrapped
-=================
-*/
-void UI_DrawProportionalString_AutoWrapped( int x, int y, int xmax, int ystep, const char* str, int style, vec4_t color ) {
- int width;
- char *s1,*s2,*s3;
- char c_bcp;
- char buf[1024];
- float sizeScale;
-
- if (!str || str[0]=='\0')
- return;
-
- sizeScale = UI_ProportionalSizeScale( style );
-
- Q_strncpyz(buf, str, sizeof(buf));
- s1 = s2 = s3 = buf;
-
- while (1) {
- do {
- s3++;
- } while (*s3!=' ' && *s3!='\0');
- c_bcp = *s3;
- *s3 = '\0';
- width = UI_ProportionalStringWidth(s1) * sizeScale;
- *s3 = c_bcp;
- if (width > xmax) {
- if (s1==s2)
- {
- // fuck, don't have a clean cut, we'll overflow
- s2 = s3;
- }
- *s2 = '\0';
- UI_DrawProportionalString(x, y, s1, style, color);
- y += ystep;
- if (c_bcp == '\0')
- {
- // that was the last word
- // we could start a new loop, but that wouldn't be much use
- // even if the word is too long, we would overflow it (see above)
- // so just print it now if needed
- s2++;
- if (*s2 != '\0') // if we are printing an overflowing line we have s2 == s3
- UI_DrawProportionalString(x, y, s2, style, color);
- break;
- }
- s2++;
- s1 = s2;
- s3 = s2;
- }
- else
- {
- s2 = s3;
- if (c_bcp == '\0') // we reached the end
- {
- UI_DrawProportionalString(x, y, s1, style, color);
- break;
- }
- }
- }
-}
-
-/*
-=================
-UI_DrawString2
-=================
-*/
-static void UI_DrawString2( int x, int y, const char* str, vec4_t color, int charw, int charh )
-{
- const char* s;
- char ch;
- int forceColor = qfalse; //APSFIXME;
- vec4_t tempcolor;
- float ax;
- float ay;
- float aw;
- float ah;
- float frow;
- float fcol;
-
- if (y < -charh)
- // offscreen
- return;
-
- // draw the colored text
- trap_R_SetColor( color );
-
- ax = x * uis.xscale + uis.bias;
- ay = y * uis.yscale;
- aw = charw * uis.xscale;
- ah = charh * uis.yscale;
-
- s = str;
- while ( *s )
- {
- if ( Q_IsColorString( s ) )
- {
- if ( !forceColor )
- {
- memcpy( tempcolor, g_color_table[ColorIndex(s[1])], sizeof( tempcolor ) );
- tempcolor[3] = color[3];
- trap_R_SetColor( tempcolor );
- }
- s += 2;
- continue;
- }
-
- ch = *s & 255;
- if (ch != ' ')
- {
- frow = (ch>>4)*0.0625;
- fcol = (ch&15)*0.0625;
- trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol + 0.0625, frow + 0.0625, uis.charset );
- }
-
- ax += aw;
- s++;
- }
-
- trap_R_SetColor( NULL );
-}
-
-/*
-=================
-UI_DrawString
-=================
-*/
-void UI_DrawString( int x, int y, const char* str, int style, vec4_t color )
-{
- int len;
- int charw;
- int charh;
- vec4_t newcolor;
- vec4_t lowlight;
- float *drawcolor;
- vec4_t dropcolor;
-
- if( !str ) {
- return;
- }
-
- if ((style & UI_BLINK) && ((uis.realtime/BLINK_DIVISOR) & 1))
- return;
-
- if (style & UI_SMALLFONT)
- {
- charw = SMALLCHAR_WIDTH;
- charh = SMALLCHAR_HEIGHT;
- }
- else if (style & UI_GIANTFONT)
- {
- charw = GIANTCHAR_WIDTH;
- charh = GIANTCHAR_HEIGHT;
- }
- else
- {
- charw = BIGCHAR_WIDTH;
- charh = BIGCHAR_HEIGHT;
- }
-
- if (style & UI_PULSE)
- {
- lowlight[0] = 0.8*color[0];
- lowlight[1] = 0.8*color[1];
- lowlight[2] = 0.8*color[2];
- lowlight[3] = 0.8*color[3];
- UI_LerpColor(color,lowlight,newcolor,0.5+0.5*sin(uis.realtime/PULSE_DIVISOR));
- drawcolor = newcolor;
- }
- else
- drawcolor = color;
-
- switch (style & UI_FORMATMASK)
- {
- case UI_CENTER:
- // center justify at x
- len = strlen(str);
- x = x - len*charw/2;
- break;
-
- case UI_RIGHT:
- // right justify at x
- len = strlen(str);
- x = x - len*charw;
- break;
-
- default:
- // left justify at x
- break;
- }
-
- if ( style & UI_DROPSHADOW )
- {
- dropcolor[0] = dropcolor[1] = dropcolor[2] = 0;
- dropcolor[3] = drawcolor[3];
- UI_DrawString2(x+2,y+2,str,dropcolor,charw,charh);
- }
-
- UI_DrawString2(x,y,str,drawcolor,charw,charh);
-}
-
-/*
-=================
-UI_DrawChar
-=================
-*/
-void UI_DrawChar( int x, int y, int ch, int style, vec4_t color )
-{
- char buff[2];
-
- buff[0] = ch;
- buff[1] = '\0';
-
- UI_DrawString( x, y, buff, style, color );
-}
-
-qboolean UI_IsFullscreen( void ) {
- if ( uis.activemenu && ( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
- return uis.activemenu->fullscreen;
- }
-
- return qfalse;
-}
-
-static void NeedCDAction( qboolean result ) {
- if ( !result ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
- }
-}
-
-static void NeedCDKeyAction( qboolean result ) {
- if ( !result ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
- }
-}
-
-void UI_SetActiveMenu( uiMenuCommand_t menu ) {
- // this should be the ONLY way the menu system is brought up
- // enusure minumum menu data is cached
- Menu_Cache();
-
- switch ( menu ) {
- case UIMENU_NONE:
- UI_ForceMenuOff();
- return;
- case UIMENU_MAIN:
- UI_MainMenu();
- return;
- case UIMENU_NEED_CD:
- UI_ConfirmMenu( "Insert the CD", 0, NeedCDAction );
- return;
- case UIMENU_BAD_CD_KEY:
- UI_ConfirmMenu( "Bad CD Key", 0, NeedCDKeyAction );
- return;
- case UIMENU_INGAME:
- /*
- //GRank
- UI_RankingsMenu();
- return;
- */
- trap_Cvar_Set( "cl_paused", "1" );
- UI_InGameMenu();
- return;
-
- case UIMENU_TEAM:
- case UIMENU_POSTGAME:
- default:
-#ifndef NDEBUG
- Com_Printf("UI_SetActiveMenu: bad enum %d\n", menu );
-#endif
- break;
- }
-}
-
-/*
-=================
-UI_KeyEvent
-=================
-*/
-void UI_KeyEvent( int key, int down ) {
- sfxHandle_t s;
-
- if (!uis.activemenu) {
- return;
- }
-
- if (!down) {
- return;
- }
-
- if (uis.activemenu->key)
- s = uis.activemenu->key( key );
- else
- s = Menu_DefaultKey( uis.activemenu, key );
-
- if ((s > 0) && (s != menu_null_sound))
- trap_S_StartLocalSound( s, CHAN_LOCAL_SOUND );
-}
-
-/*
-=================
-UI_MouseEvent
-=================
-*/
-void UI_MouseEvent( int dx, int dy )
-{
- int i;
- menucommon_s* m;
-
- if (!uis.activemenu)
- return;
-
- // update mouse screen position
- uis.cursorx += dx;
- if (uis.cursorx < 0)
- uis.cursorx = 0;
- else if (uis.cursorx > SCREEN_WIDTH)
- uis.cursorx = SCREEN_WIDTH;
-
- uis.cursory += dy;
- if (uis.cursory < 0)
- uis.cursory = 0;
- else if (uis.cursory > SCREEN_HEIGHT)
- uis.cursory = SCREEN_HEIGHT;
-
- // region test the active menu items
- for (i=0; i<uis.activemenu->nitems; i++)
- {
- m = (menucommon_s*)uis.activemenu->items[i];
-
- if (m->flags & (QMF_GRAYED|QMF_INACTIVE))
- continue;
-
- if ((uis.cursorx < m->left) ||
- (uis.cursorx > m->right) ||
- (uis.cursory < m->top) ||
- (uis.cursory > m->bottom))
- {
- // cursor out of item bounds
- continue;
- }
-
- // set focus to item at cursor
- if (uis.activemenu->cursor != i)
- {
- Menu_SetCursor( uis.activemenu, i );
- ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor_prev]))->flags &= ~QMF_HASMOUSEFOCUS;
-
- if ( !(((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags & QMF_SILENT ) ) {
- trap_S_StartLocalSound( menu_move_sound, CHAN_LOCAL_SOUND );
- }
- }
-
- ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags |= QMF_HASMOUSEFOCUS;
- return;
- }
-
- if (uis.activemenu->nitems > 0) {
- // out of any region
- ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags &= ~QMF_HASMOUSEFOCUS;
- }
-}
-
-char *UI_Argv( int arg ) {
- static char buffer[MAX_STRING_CHARS];
-
- trap_Argv( arg, buffer, sizeof( buffer ) );
-
- return buffer;
-}
-
-
-char *UI_Cvar_VariableString( const char *var_name ) {
- static char buffer[MAX_STRING_CHARS];
-
- trap_Cvar_VariableStringBuffer( var_name, buffer, sizeof( buffer ) );
-
- return buffer;
-}
-
-
-/*
-=================
-UI_Cache
-=================
-*/
-void UI_Cache_f( void ) {
- MainMenu_Cache();
- InGame_Cache();
- ConfirmMenu_Cache();
- PlayerModel_Cache();
- PlayerSettings_Cache();
- Controls_Cache();
- Demos_Cache();
- UI_CinematicsMenu_Cache();
- Preferences_Cache();
- ServerInfo_Cache();
- SpecifyServer_Cache();
- ArenaServers_Cache();
- StartServer_Cache();
- ServerOptions_Cache();
- DriverInfo_Cache();
- GraphicsOptions_Cache();
- UI_DisplayOptionsMenu_Cache();
- UI_SoundOptionsMenu_Cache();
- UI_NetworkOptionsMenu_Cache();
- UI_SPLevelMenu_Cache();
- UI_SPSkillMenu_Cache();
- UI_SPPostgameMenu_Cache();
- TeamMain_Cache();
- UI_AddBots_Cache();
- UI_RemoveBots_Cache();
- UI_SetupMenu_Cache();
-// UI_LoadConfig_Cache();
-// UI_SaveConfigMenu_Cache();
- UI_BotSelectMenu_Cache();
- UI_CDKeyMenu_Cache();
- UI_ModsMenu_Cache();
-
-}
-
-
-/*
-=================
-UI_ConsoleCommand
-=================
-*/
-qboolean UI_ConsoleCommand( int realTime ) {
- char *cmd;
-
- cmd = UI_Argv( 0 );
-
- // ensure minimum menu data is available
- Menu_Cache();
-
- if ( Q_stricmp (cmd, "levelselect") == 0 ) {
- UI_SPLevelMenu_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "postgame") == 0 ) {
- UI_SPPostgameMenu_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "ui_cache") == 0 ) {
- UI_Cache_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "ui_cinematics") == 0 ) {
- UI_CinematicsMenu_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "ui_teamOrders") == 0 ) {
- UI_TeamOrdersMenu_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "iamacheater") == 0 ) {
- UI_SPUnlock_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "iamamonkey") == 0 ) {
- UI_SPUnlockMedals_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "ui_cdkey") == 0 ) {
- UI_CDKeyMenu_f();
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-=================
-UI_Shutdown
-=================
-*/
-void UI_Shutdown( void ) {
-}
-
-/*
-=================
-UI_Init
-=================
-*/
-void UI_Init( void ) {
- UI_RegisterCvars();
-
- UI_InitGameinfo();
-
- // cache redundant calulations
- trap_GetGlconfig( &uis.glconfig );
-
- // for 640x480 virtualized screen
- uis.xscale = uis.glconfig.vidWidth * (1.0/640.0);
- uis.yscale = uis.glconfig.vidHeight * (1.0/480.0);
- if ( uis.glconfig.vidWidth * 480 > uis.glconfig.vidHeight * 640 ) {
- // wide screen
- uis.bias = 0.5 * ( uis.glconfig.vidWidth - ( uis.glconfig.vidHeight * (640.0/480.0) ) );
- uis.xscale = uis.yscale;
- }
- else {
- // no wide screen
- uis.bias = 0;
- }
-
- // initialize the menu system
- Menu_Cache();
-
- uis.activemenu = NULL;
- uis.menusp = 0;
-}
-
-/*
-================
-UI_AdjustFrom640
-
-Adjusted for resolution and screen aspect ratio
-================
-*/
-void UI_AdjustFrom640( float *x, float *y, float *w, float *h ) {
- // expect valid pointers
- *x = *x * uis.xscale + uis.bias;
- *y *= uis.yscale;
- *w *= uis.xscale;
- *h *= uis.yscale;
-}
-
-void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {
- qhandle_t hShader;
-
- hShader = trap_R_RegisterShaderNoMip( picname );
- UI_AdjustFrom640( &x, &y, &width, &height );
- trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
-}
-
-void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader ) {
- float s0;
- float s1;
- float t0;
- float t1;
-
- if( w < 0 ) { // flip about vertical
- w = -w;
- s0 = 1;
- s1 = 0;
- }
- else {
- s0 = 0;
- s1 = 1;
- }
-
- if( h < 0 ) { // flip about horizontal
- h = -h;
- t0 = 1;
- t1 = 0;
- }
- else {
- t0 = 0;
- t1 = 1;
- }
-
- UI_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, w, h, s0, t0, s1, t1, hShader );
-}
-
-/*
-================
-UI_FillRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void UI_FillRect( float x, float y, float width, float height, const float *color ) {
- trap_R_SetColor( color );
-
- UI_AdjustFrom640( &x, &y, &width, &height );
- trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, uis.whiteShader );
-
- trap_R_SetColor( NULL );
-}
-
-/*
-================
-UI_DrawRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void UI_DrawRect( float x, float y, float width, float height, const float *color ) {
- trap_R_SetColor( color );
-
- UI_AdjustFrom640( &x, &y, &width, &height );
-
- trap_R_DrawStretchPic( x, y, width, 1, 0, 0, 0, 0, uis.whiteShader );
- trap_R_DrawStretchPic( x, y, 1, height, 0, 0, 0, 0, uis.whiteShader );
- trap_R_DrawStretchPic( x, y + height - 1, width, 1, 0, 0, 0, 0, uis.whiteShader );
- trap_R_DrawStretchPic( x + width - 1, y, 1, height, 0, 0, 0, 0, uis.whiteShader );
-
- trap_R_SetColor( NULL );
-}
-
-void UI_SetColor( const float *rgba ) {
- trap_R_SetColor( rgba );
-}
-
-void UI_UpdateScreen( void ) {
- trap_UpdateScreen();
-}
-
-/*
-=================
-UI_Refresh
-=================
-*/
-void UI_Refresh( int realtime )
-{
- uis.frametime = realtime - uis.realtime;
- uis.realtime = realtime;
-
- if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
- return;
- }
-
- UI_UpdateCvars();
-
- if ( uis.activemenu )
- {
- if (uis.activemenu->fullscreen)
- {
- // draw the background
- if( uis.activemenu->showlogo ) {
- UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackShader );
- }
- else {
- UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackNoLogoShader );
- }
- }
-
- if (uis.activemenu->draw)
- uis.activemenu->draw();
- else
- Menu_Draw( uis.activemenu );
-
- if( uis.firstdraw ) {
- UI_MouseEvent( 0, 0 );
- uis.firstdraw = qfalse;
- }
- }
-
- // draw cursor
- UI_SetColor( NULL );
- UI_DrawHandlePic( uis.cursorx-16, uis.cursory-16, 32, 32, uis.cursor);
-
-#ifndef NDEBUG
- if (uis.debug)
- {
- // cursor coordinates
- UI_DrawString( 0, 0, va("(%d,%d)",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed );
- }
-#endif
-
- // delay playing the enter sound until after the
- // menu has been drawn, to avoid delay while
- // caching images
- if (m_entersound)
- {
- trap_S_StartLocalSound( menu_in_sound, CHAN_LOCAL_SOUND );
- m_entersound = qfalse;
- }
-}
-
-void UI_DrawTextBox (int x, int y, int width, int lines)
-{
- UI_FillRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorBlack );
- UI_DrawRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorWhite );
-}
-
-qboolean UI_CursorInRect (int x, int y, int width, int height)
-{
- if (uis.cursorx < x ||
- uis.cursory < y ||
- uis.cursorx > x+width ||
- uis.cursory > y+height)
- return qfalse;
-
- return qtrue;
-}
diff --git a/engine/code/q3_ui/ui_cinematics.c b/engine/code/q3_ui/ui_cinematics.c
deleted file mode 100644
index e2fd778..0000000
--- a/engine/code/q3_ui/ui_cinematics.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-#define ART_FRAMEL "menu/art/frame2_l"
-#define ART_FRAMER "menu/art/frame1_r"
-
-#define VERTICAL_SPACING 30
-
-#define ID_BACK 10
-#define ID_CIN_IDLOGO 11
-#define ID_CIN_INTRO 12
-#define ID_CIN_TIER1 13
-#define ID_CIN_TIER2 14
-#define ID_CIN_TIER3 15
-#define ID_CIN_TIER4 16
-#define ID_CIN_TIER5 17
-#define ID_CIN_TIER6 18
-#define ID_CIN_TIER7 19
-#define ID_CIN_END 20
-
-
-typedef struct {
- menuframework_s menu;
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
- menutext_s cin_idlogo;
- menutext_s cin_intro;
- menutext_s cin_tier1;
- menutext_s cin_tier2;
- menutext_s cin_tier3;
- menutext_s cin_tier4;
- menutext_s cin_tier5;
- menutext_s cin_tier6;
- menutext_s cin_tier7;
- menutext_s cin_end;
- menubitmap_s back;
-} cinematicsMenuInfo_t;
-
-static cinematicsMenuInfo_t cinematicsMenuInfo;
-
-static char *cinematics[] = {
- "idlogo",
- "intro",
- "tier1",
- "tier2",
- "tier3",
- "tier4",
- "tier5",
- "tier6",
- "tier7",
- "end"
-};
-
-/*
-===============
-UI_CinematicsMenu_BackEvent
-===============
-*/
-static void UI_CinematicsMenu_BackEvent( void *ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- UI_PopMenu();
-}
-
-
-/*
-===============
-UI_CinematicsMenu_Event
-===============
-*/
-static void UI_CinematicsMenu_Event( void *ptr, int event ) {
- int n;
-
- if (event != QM_ACTIVATED)
- return;
-
- n = ((menucommon_s*)ptr)->id - ID_CIN_IDLOGO;
- trap_Cvar_Set( "nextmap", va( "ui_cinematics %i", n ) );
- if( uis.demoversion && ((menucommon_s*)ptr)->id == ID_CIN_END ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect; cinematic demoEnd.RoQ 1\n" );
- }
- else {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "disconnect; cinematic %s.RoQ\n", cinematics[n] ) );
- }
-}
-
-
-/*
-===============
-UI_CinematicsMenu_Init
-===============
-*/
-static void UI_CinematicsMenu_Init( void ) {
- int y;
-
- UI_CinematicsMenu_Cache();
-
- memset( &cinematicsMenuInfo, 0, sizeof(cinematicsMenuInfo) );
- cinematicsMenuInfo.menu.fullscreen = qtrue;
-
- cinematicsMenuInfo.banner.generic.type = MTYPE_BTEXT;
- cinematicsMenuInfo.banner.generic.x = 320;
- cinematicsMenuInfo.banner.generic.y = 16;
- cinematicsMenuInfo.banner.string = "CINEMATICS";
- cinematicsMenuInfo.banner.color = color_white;
- cinematicsMenuInfo.banner.style = UI_CENTER;
-
- cinematicsMenuInfo.framel.generic.type = MTYPE_BITMAP;
- cinematicsMenuInfo.framel.generic.name = ART_FRAMEL;
- cinematicsMenuInfo.framel.generic.flags = QMF_INACTIVE;
- cinematicsMenuInfo.framel.generic.x = 0;
- cinematicsMenuInfo.framel.generic.y = 78;
- cinematicsMenuInfo.framel.width = 256;
- cinematicsMenuInfo.framel.height = 329;
-
- cinematicsMenuInfo.framer.generic.type = MTYPE_BITMAP;
- cinematicsMenuInfo.framer.generic.name = ART_FRAMER;
- cinematicsMenuInfo.framer.generic.flags = QMF_INACTIVE;
- cinematicsMenuInfo.framer.generic.x = 376;
- cinematicsMenuInfo.framer.generic.y = 76;
- cinematicsMenuInfo.framer.width = 256;
- cinematicsMenuInfo.framer.height = 334;
-
- y = 100;
- cinematicsMenuInfo.cin_idlogo.generic.type = MTYPE_PTEXT;
- cinematicsMenuInfo.cin_idlogo.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- cinematicsMenuInfo.cin_idlogo.generic.x = 320;
- cinematicsMenuInfo.cin_idlogo.generic.y = y;
- cinematicsMenuInfo.cin_idlogo.generic.id = ID_CIN_IDLOGO;
- cinematicsMenuInfo.cin_idlogo.generic.callback = UI_CinematicsMenu_Event;
- cinematicsMenuInfo.cin_idlogo.string = "ID LOGO";
- cinematicsMenuInfo.cin_idlogo.color = color_red;
- cinematicsMenuInfo.cin_idlogo.style = UI_CENTER;
-
- y += VERTICAL_SPACING;
- cinematicsMenuInfo.cin_intro.generic.type = MTYPE_PTEXT;
- cinematicsMenuInfo.cin_intro.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- cinematicsMenuInfo.cin_intro.generic.x = 320;
- cinematicsMenuInfo.cin_intro.generic.y = y;
- cinematicsMenuInfo.cin_intro.generic.id = ID_CIN_INTRO;
- cinematicsMenuInfo.cin_intro.generic.callback = UI_CinematicsMenu_Event;
- cinematicsMenuInfo.cin_intro.string = "INTRO";
- cinematicsMenuInfo.cin_intro.color = color_red;
- cinematicsMenuInfo.cin_intro.style = UI_CENTER;
- if( uis.demoversion ) {
- cinematicsMenuInfo.cin_intro.generic.flags |= QMF_GRAYED;
- }
-
- y += VERTICAL_SPACING;
- cinematicsMenuInfo.cin_tier1.generic.type = MTYPE_PTEXT;
- cinematicsMenuInfo.cin_tier1.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- cinematicsMenuInfo.cin_tier1.generic.x = 320;
- cinematicsMenuInfo.cin_tier1.generic.y = y;
- cinematicsMenuInfo.cin_tier1.generic.id = ID_CIN_TIER1;
- cinematicsMenuInfo.cin_tier1.generic.callback = UI_CinematicsMenu_Event;
- cinematicsMenuInfo.cin_tier1.string = "Tier 1";
- cinematicsMenuInfo.cin_tier1.color = color_red;
- cinematicsMenuInfo.cin_tier1.style = UI_CENTER;
- if( !UI_CanShowTierVideo( 1 ) ) {
- cinematicsMenuInfo.cin_tier1.generic.flags |= QMF_GRAYED;
- }
-
- y += VERTICAL_SPACING;
- cinematicsMenuInfo.cin_tier2.generic.type = MTYPE_PTEXT;
- cinematicsMenuInfo.cin_tier2.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- cinematicsMenuInfo.cin_tier2.generic.x = 320;
- cinematicsMenuInfo.cin_tier2.generic.y = y;
- cinematicsMenuInfo.cin_tier2.generic.id = ID_CIN_TIER2;
- cinematicsMenuInfo.cin_tier2.generic.callback = UI_CinematicsMenu_Event;
- cinematicsMenuInfo.cin_tier2.string = "Tier 2";
- cinematicsMenuInfo.cin_tier2.color = color_red;
- cinematicsMenuInfo.cin_tier2.style = UI_CENTER;
- if( !UI_CanShowTierVideo( 2 ) ) {
- cinematicsMenuInfo.cin_tier2.generic.flags |= QMF_GRAYED;
- }
-
- y += VERTICAL_SPACING;
- cinematicsMenuInfo.cin_tier3.generic.type = MTYPE_PTEXT;
- cinematicsMenuInfo.cin_tier3.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- cinematicsMenuInfo.cin_tier3.generic.x = 320;
- cinematicsMenuInfo.cin_tier3.generic.y = y;
- cinematicsMenuInfo.cin_tier3.generic.id = ID_CIN_TIER3;
- cinematicsMenuInfo.cin_tier3.generic.callback = UI_CinematicsMenu_Event;
- cinematicsMenuInfo.cin_tier3.string = "Tier 3";
- cinematicsMenuInfo.cin_tier3.color = color_red;
- cinematicsMenuInfo.cin_tier3.style = UI_CENTER;
- if( !UI_CanShowTierVideo( 3 ) ) {
- cinematicsMenuInfo.cin_tier3.generic.flags |= QMF_GRAYED;
- }
-
- y += VERTICAL_SPACING;
- cinematicsMenuInfo.cin_tier4.generic.type = MTYPE_PTEXT;
- cinematicsMenuInfo.cin_tier4.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- cinematicsMenuInfo.cin_tier4.generic.x = 320;
- cinematicsMenuInfo.cin_tier4.generic.y = y;
- cinematicsMenuInfo.cin_tier4.generic.id = ID_CIN_TIER4;
- cinematicsMenuInfo.cin_tier4.generic.callback = UI_CinematicsMenu_Event;
- cinematicsMenuInfo.cin_tier4.string = "Tier 4";
- cinematicsMenuInfo.cin_tier4.color = color_red;
- cinematicsMenuInfo.cin_tier4.style = UI_CENTER;
- if( !UI_CanShowTierVideo( 4 ) ) {
- cinematicsMenuInfo.cin_tier4.generic.flags |= QMF_GRAYED;
- }
-
- y += VERTICAL_SPACING;
- cinematicsMenuInfo.cin_tier5.generic.type = MTYPE_PTEXT;
- cinematicsMenuInfo.cin_tier5.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- cinematicsMenuInfo.cin_tier5.generic.x = 320;
- cinematicsMenuInfo.cin_tier5.generic.y = y;
- cinematicsMenuInfo.cin_tier5.generic.id = ID_CIN_TIER5;
- cinematicsMenuInfo.cin_tier5.generic.callback = UI_CinematicsMenu_Event;
- cinematicsMenuInfo.cin_tier5.string = "Tier 5";
- cinematicsMenuInfo.cin_tier5.color = color_red;
- cinematicsMenuInfo.cin_tier5.style = UI_CENTER;
- if( !UI_CanShowTierVideo( 5 ) ) {
- cinematicsMenuInfo.cin_tier5.generic.flags |= QMF_GRAYED;
- }
-
- y += VERTICAL_SPACING;
- cinematicsMenuInfo.cin_tier6.generic.type = MTYPE_PTEXT;
- cinematicsMenuInfo.cin_tier6.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- cinematicsMenuInfo.cin_tier6.generic.x = 320;
- cinematicsMenuInfo.cin_tier6.generic.y = y;
- cinematicsMenuInfo.cin_tier6.generic.id = ID_CIN_TIER6;
- cinematicsMenuInfo.cin_tier6.generic.callback = UI_CinematicsMenu_Event;
- cinematicsMenuInfo.cin_tier6.string = "Tier 6";
- cinematicsMenuInfo.cin_tier6.color = color_red;
- cinematicsMenuInfo.cin_tier6.style = UI_CENTER;
- if( !UI_CanShowTierVideo( 6 ) ) {
- cinematicsMenuInfo.cin_tier6.generic.flags |= QMF_GRAYED;
- }
-
- y += VERTICAL_SPACING;
- cinematicsMenuInfo.cin_tier7.generic.type = MTYPE_PTEXT;
- cinematicsMenuInfo.cin_tier7.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- cinematicsMenuInfo.cin_tier7.generic.x = 320;
- cinematicsMenuInfo.cin_tier7.generic.y = y;
- cinematicsMenuInfo.cin_tier7.generic.id = ID_CIN_TIER7;
- cinematicsMenuInfo.cin_tier7.generic.callback = UI_CinematicsMenu_Event;
- cinematicsMenuInfo.cin_tier7.string = "Tier 7";
- cinematicsMenuInfo.cin_tier7.color = color_red;
- cinematicsMenuInfo.cin_tier7.style = UI_CENTER;
- if( !UI_CanShowTierVideo( 7 ) ) {
- cinematicsMenuInfo.cin_tier7.generic.flags |= QMF_GRAYED;
- }
-
- y += VERTICAL_SPACING;
- cinematicsMenuInfo.cin_end.generic.type = MTYPE_PTEXT;
- cinematicsMenuInfo.cin_end.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- cinematicsMenuInfo.cin_end.generic.x = 320;
- cinematicsMenuInfo.cin_end.generic.y = y;
- cinematicsMenuInfo.cin_end.generic.id = ID_CIN_END;
- cinematicsMenuInfo.cin_end.generic.callback = UI_CinematicsMenu_Event;
- cinematicsMenuInfo.cin_end.string = "END";
- cinematicsMenuInfo.cin_end.color = color_red;
- cinematicsMenuInfo.cin_end.style = UI_CENTER;
- if( !UI_CanShowTierVideo( 8 ) ) {
- cinematicsMenuInfo.cin_end.generic.flags |= QMF_GRAYED;
- }
-
- cinematicsMenuInfo.back.generic.type = MTYPE_BITMAP;
- cinematicsMenuInfo.back.generic.name = ART_BACK0;
- cinematicsMenuInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- cinematicsMenuInfo.back.generic.id = ID_BACK;
- cinematicsMenuInfo.back.generic.callback = UI_CinematicsMenu_BackEvent;
- cinematicsMenuInfo.back.generic.x = 0;
- cinematicsMenuInfo.back.generic.y = 480-64;
- cinematicsMenuInfo.back.width = 128;
- cinematicsMenuInfo.back.height = 64;
- cinematicsMenuInfo.back.focuspic = ART_BACK1;
-
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.banner );
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.framel );
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.framer );
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_idlogo );
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_intro );
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier1 );
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier2 );
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier3 );
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier4 );
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier5 );
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier6 );
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_tier7 );
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.cin_end );
- Menu_AddItem( &cinematicsMenuInfo.menu, &cinematicsMenuInfo.back );
-}
-
-
-/*
-=================
-UI_CinematicsMenu_Cache
-=================
-*/
-void UI_CinematicsMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
-}
-
-
-/*
-===============
-UI_CinematicsMenu
-===============
-*/
-void UI_CinematicsMenu( void ) {
- UI_CinematicsMenu_Init();
- UI_PushMenu( &cinematicsMenuInfo.menu );
-}
-
-
-/*
-===============
-UI_CinematicsMenu_f
-===============
-*/
-void UI_CinematicsMenu_f( void ) {
- int n;
-
- n = atoi( UI_Argv( 1 ) );
- UI_CinematicsMenu();
- Menu_SetCursorToItem( &cinematicsMenuInfo.menu, cinematicsMenuInfo.menu.items[n + 3] );
-}
diff --git a/engine/code/q3_ui/ui_confirm.c b/engine/code/q3_ui/ui_confirm.c
deleted file mode 100644
index a5f6f16..0000000
--- a/engine/code/q3_ui/ui_confirm.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-CONFIRMATION MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define ART_CONFIRM_FRAME "menu/art/cut_frame"
-
-#define ID_CONFIRM_NO 10
-#define ID_CONFIRM_YES 11
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s no;
- menutext_s yes;
-
- int slashX;
- const char * question;
- void (*draw)( void );
- void (*action)( qboolean result );
-
- int style;
- const char **lines;
-} confirmMenu_t;
-
-
-static confirmMenu_t s_confirm;
-
-
-/*
-=================
-ConfirmMenu_Event
-=================
-*/
-static void ConfirmMenu_Event( void* ptr, int event ) {
- qboolean result;
-
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- UI_PopMenu();
-
- if( ((menucommon_s*)ptr)->id == ID_CONFIRM_NO ) {
- result = qfalse;
- }
- else {
- result = qtrue;
- }
-
- if( s_confirm.action ) {
- s_confirm.action( result );
- }
-}
-
-
-/*
-=================
-ConfirmMenu_Key
-=================
-*/
-static sfxHandle_t ConfirmMenu_Key( int key ) {
- switch ( key ) {
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- key = K_TAB;
- break;
-
- case 'n':
- case 'N':
- ConfirmMenu_Event( &s_confirm.no, QM_ACTIVATED );
- break;
-
- case 'y':
- case 'Y':
- ConfirmMenu_Event( &s_confirm.yes, QM_ACTIVATED );
- break;
- }
-
- return Menu_DefaultKey( &s_confirm.menu, key );
-}
-
-
-/*
-=================
-MessaheMenu_Draw
-=================
-*/
-static void MessageMenu_Draw( void ) {
- int i,y;
-
- UI_DrawNamedPic( 142, 118, 359, 256, ART_CONFIRM_FRAME );
-
- y = 188;
- for(i=0; s_confirm.lines[i]; i++)
- {
- UI_DrawProportionalString( 320, y, s_confirm.lines[i], s_confirm.style, color_red );
- y += 18;
- }
-
- Menu_Draw( &s_confirm.menu );
-
- if( s_confirm.draw ) {
- s_confirm.draw();
- }
-}
-
-/*
-=================
-ConfirmMenu_Draw
-=================
-*/
-static void ConfirmMenu_Draw( void ) {
- UI_DrawNamedPic( 142, 118, 359, 256, ART_CONFIRM_FRAME );
- UI_DrawProportionalString( 320, 204, s_confirm.question, s_confirm.style, color_red );
- UI_DrawProportionalString( s_confirm.slashX, 265, "/", UI_LEFT|UI_INVERSE, color_red );
-
- Menu_Draw( &s_confirm.menu );
-
- if( s_confirm.draw ) {
- s_confirm.draw();
- }
-}
-
-
-/*
-=================
-ConfirmMenu_Cache
-=================
-*/
-void ConfirmMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_CONFIRM_FRAME );
-}
-
-
-/*
-=================
-UI_ConfirmMenu_Stlye
-=================
-*/
-void UI_ConfirmMenu_Style( const char *question, int style, void (*draw)( void ), void (*action)( qboolean result ) ) {
- uiClientState_t cstate;
- int n1, n2, n3;
- int l1, l2, l3;
-
- // zero set all our globals
- memset( &s_confirm, 0, sizeof(s_confirm) );
-
- ConfirmMenu_Cache();
-
- n1 = UI_ProportionalStringWidth( "YES/NO" );
- n2 = UI_ProportionalStringWidth( "YES" ) + PROP_GAP_WIDTH;
- n3 = UI_ProportionalStringWidth( "/" ) + PROP_GAP_WIDTH;
- l1 = 320 - ( n1 / 2 );
- l2 = l1 + n2;
- l3 = l2 + n3;
- s_confirm.slashX = l2;
-
- s_confirm.question = question;
- s_confirm.draw = draw;
- s_confirm.action = action;
- s_confirm.style = style;
-
- s_confirm.menu.draw = ConfirmMenu_Draw;
- s_confirm.menu.key = ConfirmMenu_Key;
- s_confirm.menu.wrapAround = qtrue;
-
- trap_GetClientState( &cstate );
- if ( cstate.connState >= CA_CONNECTED ) {
- s_confirm.menu.fullscreen = qfalse;
- }
- else {
- s_confirm.menu.fullscreen = qtrue;
- }
-
- s_confirm.yes.generic.type = MTYPE_PTEXT;
- s_confirm.yes.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_confirm.yes.generic.callback = ConfirmMenu_Event;
- s_confirm.yes.generic.id = ID_CONFIRM_YES;
- s_confirm.yes.generic.x = l1;
- s_confirm.yes.generic.y = 264;
- s_confirm.yes.string = "YES";
- s_confirm.yes.color = color_red;
- s_confirm.yes.style = UI_LEFT;
-
- s_confirm.no.generic.type = MTYPE_PTEXT;
- s_confirm.no.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_confirm.no.generic.callback = ConfirmMenu_Event;
- s_confirm.no.generic.id = ID_CONFIRM_NO;
- s_confirm.no.generic.x = l3;
- s_confirm.no.generic.y = 264;
- s_confirm.no.string = "NO";
- s_confirm.no.color = color_red;
- s_confirm.no.style = UI_LEFT;
-
- Menu_AddItem( &s_confirm.menu, &s_confirm.yes );
- Menu_AddItem( &s_confirm.menu, &s_confirm.no );
-
- UI_PushMenu( &s_confirm.menu );
-
- Menu_SetCursorToItem( &s_confirm.menu, &s_confirm.no );
-}
-
-/*
-=================
-UI_ConfirmMenu
-=================
-*/
-void UI_ConfirmMenu( const char *question, void (*draw)( void ), void (*action)( qboolean result ) ) {
- UI_ConfirmMenu_Style(question, UI_CENTER|UI_INVERSE, draw, action);
-}
-
-/*
-=================
-UI_Message
-hacked over from Confirm stuff
-=================
-*/
-void UI_Message( const char **lines ) {
- uiClientState_t cstate;
- int n1, l1;
-
- // zero set all our globals
- memset( &s_confirm, 0, sizeof(s_confirm) );
-
- ConfirmMenu_Cache();
-
- n1 = UI_ProportionalStringWidth( "OK" );
- l1 = 320 - ( n1 / 2 );
-
- s_confirm.lines = lines;
- s_confirm.style = UI_CENTER|UI_INVERSE|UI_SMALLFONT;
-
- s_confirm.menu.draw = MessageMenu_Draw;
- s_confirm.menu.key = ConfirmMenu_Key;
- s_confirm.menu.wrapAround = qtrue;
-
- trap_GetClientState( &cstate );
- if ( cstate.connState >= CA_CONNECTED ) {
- s_confirm.menu.fullscreen = qfalse;
- }
- else {
- s_confirm.menu.fullscreen = qtrue;
- }
-
- s_confirm.yes.generic.type = MTYPE_PTEXT;
- s_confirm.yes.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_confirm.yes.generic.callback = ConfirmMenu_Event;
- s_confirm.yes.generic.id = ID_CONFIRM_YES;
- s_confirm.yes.generic.x = l1;
- s_confirm.yes.generic.y = 280;
- s_confirm.yes.string = "OK";
- s_confirm.yes.color = color_red;
- s_confirm.yes.style = UI_LEFT;
-
- Menu_AddItem( &s_confirm.menu, &s_confirm.yes );
-
- UI_PushMenu( &s_confirm.menu );
-
- Menu_SetCursorToItem( &s_confirm.menu, &s_confirm.yes );
-}
diff --git a/engine/code/q3_ui/ui_connect.c b/engine/code/q3_ui/ui_connect.c
deleted file mode 100644
index 27db956..0000000
--- a/engine/code/q3_ui/ui_connect.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-/*
-===============================================================================
-
-CONNECTION SCREEN
-
-===============================================================================
-*/
-
-qboolean passwordNeeded = qtrue;
-menufield_s passwordField;
-
-static connstate_t lastConnState;
-static char lastLoadingText[MAX_INFO_VALUE];
-
-static void UI_ReadableSize ( char *buf, int bufsize, int value )
-{
- if (value > 1024*1024*1024 ) { // gigs
- Com_sprintf( buf, bufsize, "%d", value / (1024*1024*1024) );
- Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d GB",
- (value % (1024*1024*1024))*100 / (1024*1024*1024) );
- } else if (value > 1024*1024 ) { // megs
- Com_sprintf( buf, bufsize, "%d", value / (1024*1024) );
- Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d MB",
- (value % (1024*1024))*100 / (1024*1024) );
- } else if (value > 1024 ) { // kilos
- Com_sprintf( buf, bufsize, "%d KB", value / 1024 );
- } else { // bytes
- Com_sprintf( buf, bufsize, "%d bytes", value );
- }
-}
-
-// Assumes time is in msec
-static void UI_PrintTime ( char *buf, int bufsize, int time ) {
- time /= 1000; // change to seconds
-
- if (time > 3600) { // in the hours range
- Com_sprintf( buf, bufsize, "%d hr %d min", time / 3600, (time % 3600) / 60 );
- } else if (time > 60) { // mins
- Com_sprintf( buf, bufsize, "%d min %d sec", time / 60, time % 60 );
- } else { // secs
- Com_sprintf( buf, bufsize, "%d sec", time );
- }
-}
-
-static void UI_DisplayDownloadInfo( const char *downloadName ) {
- static char dlText[] = "Downloading:";
- static char etaText[] = "Estimated time left:";
- static char xferText[] = "Transfer rate:";
-
- int downloadSize, downloadCount, downloadTime;
- char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64];
- int xferRate;
- int width, leftWidth;
- int style = UI_LEFT|UI_SMALLFONT|UI_DROPSHADOW;
- const char *s;
-
- downloadSize = trap_Cvar_VariableValue( "cl_downloadSize" );
- downloadCount = trap_Cvar_VariableValue( "cl_downloadCount" );
- downloadTime = trap_Cvar_VariableValue( "cl_downloadTime" );
-
- leftWidth = width = UI_ProportionalStringWidth( dlText ) * UI_ProportionalSizeScale( style );
- width = UI_ProportionalStringWidth( etaText ) * UI_ProportionalSizeScale( style );
- if (width > leftWidth) leftWidth = width;
- width = UI_ProportionalStringWidth( xferText ) * UI_ProportionalSizeScale( style );
- if (width > leftWidth) leftWidth = width;
- leftWidth += 16;
-
- UI_DrawProportionalString( 8, 128, dlText, style, color_white );
- UI_DrawProportionalString( 8, 160, etaText, style, color_white );
- UI_DrawProportionalString( 8, 224, xferText, style, color_white );
-
- if (downloadSize > 0) {
- s = va( "%s (%d%%)", downloadName, (int)( (float)downloadCount * 100.0f / downloadSize ) );
- } else {
- s = downloadName;
- }
-
- UI_DrawProportionalString( leftWidth, 128, s, style, color_white );
-
- UI_ReadableSize( dlSizeBuf, sizeof dlSizeBuf, downloadCount );
- UI_ReadableSize( totalSizeBuf, sizeof totalSizeBuf, downloadSize );
-
- if (downloadCount < 4096 || !downloadTime) {
- UI_DrawProportionalString( leftWidth, 160, "estimating", style, color_white );
- UI_DrawProportionalString( leftWidth, 192,
- va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), style, color_white );
- } else {
- if ( (uis.realtime - downloadTime) / 1000) {
- xferRate = downloadCount / ((uis.realtime - downloadTime) / 1000);
- //xferRate = (int)( ((float)downloadCount) / elapsedTime);
- } else {
- xferRate = 0;
- }
-
- UI_ReadableSize( xferRateBuf, sizeof xferRateBuf, xferRate );
-
- // Extrapolate estimated completion time
- if (downloadSize && xferRate) {
- int n = downloadSize / xferRate; // estimated time for entire d/l in secs
-
- // We do it in K (/1024) because we'd overflow around 4MB
- n = (n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000;
-
- UI_PrintTime ( dlTimeBuf, sizeof dlTimeBuf, n );
- //(n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000);
-
- UI_DrawProportionalString( leftWidth, 160,
- dlTimeBuf, style, color_white );
- UI_DrawProportionalString( leftWidth, 192,
- va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), style, color_white );
- } else {
- UI_DrawProportionalString( leftWidth, 160,
- "estimating", style, color_white );
- if (downloadSize) {
- UI_DrawProportionalString( leftWidth, 192,
- va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), style, color_white );
- } else {
- UI_DrawProportionalString( leftWidth, 192,
- va("(%s copied)", dlSizeBuf), style, color_white );
- }
- }
-
- if (xferRate) {
- UI_DrawProportionalString( leftWidth, 224,
- va("%s/Sec", xferRateBuf), style, color_white );
- }
- }
-}
-
-/*
-========================
-UI_DrawConnectScreen
-
-This will also be overlaid on the cgame info screen during loading
-to prevent it from blinking away too rapidly on local or lan games.
-========================
-*/
-void UI_DrawConnectScreen( qboolean overlay ) {
- char *s;
- uiClientState_t cstate;
- char info[MAX_INFO_VALUE];
-
- Menu_Cache();
-
- if ( !overlay ) {
- // draw the dialog background
- UI_SetColor( color_white );
- UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackShader );
- }
-
- // see what information we should display
- trap_GetClientState( &cstate );
-
- info[0] = '\0';
- if( trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ) ) {
- UI_DrawProportionalString( 320, 16, va( "Loading %s", Info_ValueForKey( info, "mapname" ) ), UI_BIGFONT|UI_CENTER|UI_DROPSHADOW, color_white );
- }
-
- UI_DrawProportionalString( 320, 64, va("Connecting to %s", cstate.servername), UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
- //UI_DrawProportionalString( 320, 96, "Press Esc to abort", UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
-
- // display global MOTD at bottom
- UI_DrawProportionalString( SCREEN_WIDTH/2, SCREEN_HEIGHT-32,
- Info_ValueForKey( cstate.updateInfoString, "motd" ), UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
-
- // print any server info (server full, bad version, etc)
- if ( cstate.connState < CA_CONNECTED ) {
- UI_DrawProportionalString_AutoWrapped( 320, 192, 630, 20, cstate.messageString, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
- }
-
-#if 0
- // display password field
- if ( passwordNeeded ) {
- s_ingame_menu.x = SCREEN_WIDTH * 0.50 - 128;
- s_ingame_menu.nitems = 0;
- s_ingame_menu.wrapAround = qtrue;
-
- passwordField.generic.type = MTYPE_FIELD;
- passwordField.generic.name = "Password:";
- passwordField.generic.callback = 0;
- passwordField.generic.x = 10;
- passwordField.generic.y = 180;
- Field_Clear( &passwordField.field );
- passwordField.width = 256;
- passwordField.field.widthInChars = 16;
- Q_strncpyz( passwordField.field.buffer, Cvar_VariableString("password"),
- sizeof(passwordField.field.buffer) );
-
- Menu_AddItem( &s_ingame_menu, ( void * ) &s_customize_player_action );
-
- MField_Draw( &passwordField );
- }
-#endif
-
- if ( lastConnState > cstate.connState ) {
- lastLoadingText[0] = '\0';
- }
- lastConnState = cstate.connState;
-
- switch ( cstate.connState ) {
- case CA_CONNECTING:
- s = va("Awaiting challenge...%i", cstate.connectPacketCount);
- break;
- case CA_CHALLENGING:
- s = va("Awaiting connection...%i", cstate.connectPacketCount);
- break;
- case CA_CONNECTED: {
- char downloadName[MAX_INFO_VALUE];
-
- trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof(downloadName) );
- if (*downloadName) {
- UI_DisplayDownloadInfo( downloadName );
- return;
- }
- }
- s = "Awaiting gamestate...";
- break;
- case CA_LOADING:
- return;
- case CA_PRIMED:
- return;
- default:
- return;
- }
-
- UI_DrawProportionalString( 320, 128, s, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, color_white );
-
- // password required / connection rejected information goes here
-}
-
-
-/*
-===================
-UI_KeyConnect
-===================
-*/
-void UI_KeyConnect( int key ) {
- if ( key == K_ESCAPE ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" );
- return;
- }
-}
diff --git a/engine/code/q3_ui/ui_controls2.c b/engine/code/q3_ui/ui_controls2.c
deleted file mode 100644
index 907ad00..0000000
--- a/engine/code/q3_ui/ui_controls2.c
+++ /dev/null
@@ -1,1664 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-CONTROLS MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-#define ART_FRAMEL "menu/art/frame2_l"
-#define ART_FRAMER "menu/art/frame1_r"
-
-
-typedef struct {
- char *command;
- char *label;
- int id;
- int anim;
- int defaultbind1;
- int defaultbind2;
- int bind1;
- int bind2;
-} bind_t;
-
-typedef struct
-{
- char* name;
- float defaultvalue;
- float value;
-} configcvar_t;
-
-#define SAVE_NOOP 0
-#define SAVE_YES 1
-#define SAVE_NO 2
-#define SAVE_CANCEL 3
-
-// control sections
-#define C_MOVEMENT 0
-#define C_LOOKING 1
-#define C_WEAPONS 2
-#define C_MISC 3
-#define C_MAX 4
-
-#define ID_MOVEMENT 100
-#define ID_LOOKING 101
-#define ID_WEAPONS 102
-#define ID_MISC 103
-#define ID_DEFAULTS 104
-#define ID_BACK 105
-#define ID_SAVEANDEXIT 106
-#define ID_EXIT 107
-
-// bindable actions
-#define ID_SHOWSCORES 0
-#define ID_USEITEM 1
-#define ID_SPEED 2
-#define ID_FORWARD 3
-#define ID_BACKPEDAL 4
-#define ID_MOVELEFT 5
-#define ID_MOVERIGHT 6
-#define ID_MOVEUP 7
-#define ID_MOVEDOWN 8
-#define ID_LEFT 9
-#define ID_RIGHT 10
-#define ID_STRAFE 11
-#define ID_LOOKUP 12
-#define ID_LOOKDOWN 13
-#define ID_MOUSELOOK 14
-#define ID_CENTERVIEW 15
-#define ID_ZOOMVIEW 16
-#define ID_WEAPON1 17
-#define ID_WEAPON2 18
-#define ID_WEAPON3 19
-#define ID_WEAPON4 20
-#define ID_WEAPON5 21
-#define ID_WEAPON6 22
-#define ID_WEAPON7 23
-#define ID_WEAPON8 24
-#define ID_WEAPON9 25
-#define ID_ATTACK 26
-#define ID_WEAPPREV 27
-#define ID_WEAPNEXT 28
-#define ID_GESTURE 29
-#define ID_CHAT 30
-#define ID_CHAT2 31
-#define ID_CHAT3 32
-#define ID_CHAT4 33
-
-// all others
-#define ID_FREELOOK 34
-#define ID_INVERTMOUSE 35
-#define ID_ALWAYSRUN 36
-#define ID_AUTOSWITCH 37
-#define ID_MOUSESPEED 38
-#define ID_JOYENABLE 39
-#define ID_JOYTHRESHOLD 40
-#define ID_SMOOTHMOUSE 41
-
-#define ANIM_IDLE 0
-#define ANIM_RUN 1
-#define ANIM_WALK 2
-#define ANIM_BACK 3
-#define ANIM_JUMP 4
-#define ANIM_CROUCH 5
-#define ANIM_STEPLEFT 6
-#define ANIM_STEPRIGHT 7
-#define ANIM_TURNLEFT 8
-#define ANIM_TURNRIGHT 9
-#define ANIM_LOOKUP 10
-#define ANIM_LOOKDOWN 11
-#define ANIM_WEAPON1 12
-#define ANIM_WEAPON2 13
-#define ANIM_WEAPON3 14
-#define ANIM_WEAPON4 15
-#define ANIM_WEAPON5 16
-#define ANIM_WEAPON6 17
-#define ANIM_WEAPON7 18
-#define ANIM_WEAPON8 19
-#define ANIM_WEAPON9 20
-#define ANIM_WEAPON10 21
-#define ANIM_ATTACK 22
-#define ANIM_GESTURE 23
-#define ANIM_DIE 24
-#define ANIM_CHAT 25
-
-typedef struct
-{
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
- menubitmap_s player;
-
- menutext_s movement;
- menutext_s looking;
- menutext_s weapons;
- menutext_s misc;
-
- menuaction_s walkforward;
- menuaction_s backpedal;
- menuaction_s stepleft;
- menuaction_s stepright;
- menuaction_s moveup;
- menuaction_s movedown;
- menuaction_s turnleft;
- menuaction_s turnright;
- menuaction_s sidestep;
- menuaction_s run;
- menuaction_s machinegun;
- menuaction_s chainsaw;
- menuaction_s shotgun;
- menuaction_s grenadelauncher;
- menuaction_s rocketlauncher;
- menuaction_s lightning;
- menuaction_s railgun;
- menuaction_s plasma;
- menuaction_s bfg;
- menuaction_s attack;
- menuaction_s prevweapon;
- menuaction_s nextweapon;
- menuaction_s lookup;
- menuaction_s lookdown;
- menuaction_s mouselook;
- menuradiobutton_s freelook;
- menuaction_s centerview;
- menuaction_s zoomview;
- menuaction_s gesture;
- menuradiobutton_s invertmouse;
- menuslider_s sensitivity;
- menuradiobutton_s smoothmouse;
- menuradiobutton_s alwaysrun;
- menuaction_s showscores;
- menuradiobutton_s autoswitch;
- menuaction_s useitem;
- playerInfo_t playerinfo;
- qboolean changesmade;
- menuaction_s chat;
- menuaction_s chat2;
- menuaction_s chat3;
- menuaction_s chat4;
- menuradiobutton_s joyenable;
- menuslider_s joythreshold;
- int section;
- qboolean waitingforkey;
- char playerModel[64];
- vec3_t playerViewangles;
- vec3_t playerMoveangles;
- int playerLegs;
- int playerTorso;
- int playerWeapon;
- qboolean playerChat;
-
- menubitmap_s back;
- menutext_s name;
-} controls_t;
-
-static controls_t s_controls;
-
-static vec4_t controls_binding_color = {1.00f, 0.43f, 0.00f, 1.00f};
-
-static bind_t g_bindings[] =
-{
- {"+scores", "show scores", ID_SHOWSCORES, ANIM_IDLE, K_TAB, -1, -1, -1},
- {"+button2", "use item", ID_USEITEM, ANIM_IDLE, K_ENTER, -1, -1, -1},
- {"+speed", "run / walk", ID_SPEED, ANIM_RUN, K_SHIFT, -1, -1, -1},
- {"+forward", "walk forward", ID_FORWARD, ANIM_WALK, K_UPARROW, -1, -1, -1},
- {"+back", "backpedal", ID_BACKPEDAL, ANIM_BACK, K_DOWNARROW, -1, -1, -1},
- {"+moveleft", "step left", ID_MOVELEFT, ANIM_STEPLEFT, ',', -1, -1, -1},
- {"+moveright", "step right", ID_MOVERIGHT, ANIM_STEPRIGHT, '.', -1, -1, -1},
- {"+moveup", "up / jump", ID_MOVEUP, ANIM_JUMP, K_SPACE, -1, -1, -1},
- {"+movedown", "down / crouch", ID_MOVEDOWN, ANIM_CROUCH, 'c', -1, -1, -1},
- {"+left", "turn left", ID_LEFT, ANIM_TURNLEFT, K_LEFTARROW, -1, -1, -1},
- {"+right", "turn right", ID_RIGHT, ANIM_TURNRIGHT, K_RIGHTARROW, -1, -1, -1},
- {"+strafe", "sidestep / turn", ID_STRAFE, ANIM_IDLE, K_ALT, -1, -1, -1},
- {"+lookup", "look up", ID_LOOKUP, ANIM_LOOKUP, K_PGDN, -1, -1, -1},
- {"+lookdown", "look down", ID_LOOKDOWN, ANIM_LOOKDOWN, K_DEL, -1, -1, -1},
- {"+mlook", "mouse look", ID_MOUSELOOK, ANIM_IDLE, '/', -1, -1, -1},
- {"centerview", "center view", ID_CENTERVIEW, ANIM_IDLE, K_END, -1, -1, -1},
- {"+zoom", "zoom view", ID_ZOOMVIEW, ANIM_IDLE, -1, -1, -1, -1},
- {"weapon 1", "gauntlet", ID_WEAPON1, ANIM_WEAPON1, '1', -1, -1, -1},
- {"weapon 2", "machinegun", ID_WEAPON2, ANIM_WEAPON2, '2', -1, -1, -1},
- {"weapon 3", "shotgun", ID_WEAPON3, ANIM_WEAPON3, '3', -1, -1, -1},
- {"weapon 4", "grenade launcher", ID_WEAPON4, ANIM_WEAPON4, '4', -1, -1, -1},
- {"weapon 5", "rocket launcher", ID_WEAPON5, ANIM_WEAPON5, '5', -1, -1, -1},
- {"weapon 6", "lightning", ID_WEAPON6, ANIM_WEAPON6, '6', -1, -1, -1},
- {"weapon 7", "railgun", ID_WEAPON7, ANIM_WEAPON7, '7', -1, -1, -1},
- {"weapon 8", "plasma gun", ID_WEAPON8, ANIM_WEAPON8, '8', -1, -1, -1},
- {"weapon 9", "BFG", ID_WEAPON9, ANIM_WEAPON9, '9', -1, -1, -1},
- {"+attack", "attack", ID_ATTACK, ANIM_ATTACK, K_CTRL, -1, -1, -1},
- {"weapprev", "prev weapon", ID_WEAPPREV, ANIM_IDLE, '[', -1, -1, -1},
- {"weapnext", "next weapon", ID_WEAPNEXT, ANIM_IDLE, ']', -1, -1, -1},
- {"+button3", "gesture", ID_GESTURE, ANIM_GESTURE, K_MOUSE3, -1, -1, -1},
- {"messagemode", "chat", ID_CHAT, ANIM_CHAT, 't', -1, -1, -1},
- {"messagemode2", "chat - team", ID_CHAT2, ANIM_CHAT, -1, -1, -1, -1},
- {"messagemode3", "chat - target", ID_CHAT3, ANIM_CHAT, -1, -1, -1, -1},
- {"messagemode4", "chat - attacker", ID_CHAT4, ANIM_CHAT, -1, -1, -1, -1},
- {(char*)NULL, (char*)NULL, 0, 0, -1, -1, -1, -1},
-};
-
-static configcvar_t g_configcvars[] =
-{
- {"cl_run", 0, 0},
- {"m_pitch", 0, 0},
- {"cg_autoswitch", 0, 0},
- {"sensitivity", 0, 0},
- {"in_joystick", 0, 0},
- {"joy_threshold", 0, 0},
- {"m_filter", 0, 0},
- {"cl_freelook", 0, 0},
- {NULL, 0, 0}
-};
-
-static menucommon_s *g_movement_controls[] =
-{
- (menucommon_s *)&s_controls.alwaysrun,
- (menucommon_s *)&s_controls.run,
- (menucommon_s *)&s_controls.walkforward,
- (menucommon_s *)&s_controls.backpedal,
- (menucommon_s *)&s_controls.stepleft,
- (menucommon_s *)&s_controls.stepright,
- (menucommon_s *)&s_controls.moveup,
- (menucommon_s *)&s_controls.movedown,
- (menucommon_s *)&s_controls.turnleft,
- (menucommon_s *)&s_controls.turnright,
- (menucommon_s *)&s_controls.sidestep,
- NULL
-};
-
-static menucommon_s *g_weapons_controls[] = {
- (menucommon_s *)&s_controls.attack,
- (menucommon_s *)&s_controls.nextweapon,
- (menucommon_s *)&s_controls.prevweapon,
- (menucommon_s *)&s_controls.autoswitch,
- (menucommon_s *)&s_controls.chainsaw,
- (menucommon_s *)&s_controls.machinegun,
- (menucommon_s *)&s_controls.shotgun,
- (menucommon_s *)&s_controls.grenadelauncher,
- (menucommon_s *)&s_controls.rocketlauncher,
- (menucommon_s *)&s_controls.lightning,
- (menucommon_s *)&s_controls.railgun,
- (menucommon_s *)&s_controls.plasma,
- (menucommon_s *)&s_controls.bfg,
- NULL,
-};
-
-static menucommon_s *g_looking_controls[] = {
- (menucommon_s *)&s_controls.sensitivity,
- (menucommon_s *)&s_controls.smoothmouse,
- (menucommon_s *)&s_controls.invertmouse,
- (menucommon_s *)&s_controls.lookup,
- (menucommon_s *)&s_controls.lookdown,
- (menucommon_s *)&s_controls.mouselook,
- (menucommon_s *)&s_controls.freelook,
- (menucommon_s *)&s_controls.centerview,
- (menucommon_s *)&s_controls.zoomview,
- (menucommon_s *)&s_controls.joyenable,
- (menucommon_s *)&s_controls.joythreshold,
- NULL,
-};
-
-static menucommon_s *g_misc_controls[] = {
- (menucommon_s *)&s_controls.showscores,
- (menucommon_s *)&s_controls.useitem,
- (menucommon_s *)&s_controls.gesture,
- (menucommon_s *)&s_controls.chat,
- (menucommon_s *)&s_controls.chat2,
- (menucommon_s *)&s_controls.chat3,
- (menucommon_s *)&s_controls.chat4,
- NULL,
-};
-
-static menucommon_s **g_controls[] = {
- g_movement_controls,
- g_looking_controls,
- g_weapons_controls,
- g_misc_controls,
-};
-
-/*
-=================
-Controls_InitCvars
-=================
-*/
-static void Controls_InitCvars( void )
-{
- int i;
- configcvar_t* cvarptr;
-
- cvarptr = g_configcvars;
- for (i=0; ;i++,cvarptr++)
- {
- if (!cvarptr->name)
- break;
-
- // get current value
- cvarptr->value = trap_Cvar_VariableValue( cvarptr->name );
-
- // get default value
- trap_Cvar_Reset( cvarptr->name );
- cvarptr->defaultvalue = trap_Cvar_VariableValue( cvarptr->name );
-
- // restore current value
- trap_Cvar_SetValue( cvarptr->name, cvarptr->value );
- }
-}
-
-/*
-=================
-Controls_GetCvarDefault
-=================
-*/
-static float Controls_GetCvarDefault( char* name )
-{
- configcvar_t* cvarptr;
- int i;
-
- cvarptr = g_configcvars;
- for (i=0; ;i++,cvarptr++)
- {
- if (!cvarptr->name)
- return (0);
-
- if (!strcmp(cvarptr->name,name))
- break;
- }
-
- return (cvarptr->defaultvalue);
-}
-
-/*
-=================
-Controls_GetCvarValue
-=================
-*/
-static float Controls_GetCvarValue( char* name )
-{
- configcvar_t* cvarptr;
- int i;
-
- cvarptr = g_configcvars;
- for (i=0; ;i++,cvarptr++)
- {
- if (!cvarptr->name)
- return (0);
-
- if (!strcmp(cvarptr->name,name))
- break;
- }
-
- return (cvarptr->value);
-}
-
-
-/*
-=================
-Controls_UpdateModel
-=================
-*/
-static void Controls_UpdateModel( int anim ) {
- VectorClear( s_controls.playerViewangles );
- VectorClear( s_controls.playerMoveangles );
- s_controls.playerViewangles[YAW] = 180 - 30;
- s_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW];
- s_controls.playerLegs = LEGS_IDLE;
- s_controls.playerTorso = TORSO_STAND;
- s_controls.playerWeapon = -1;
- s_controls.playerChat = qfalse;
-
- switch( anim ) {
- case ANIM_RUN:
- s_controls.playerLegs = LEGS_RUN;
- break;
-
- case ANIM_WALK:
- s_controls.playerLegs = LEGS_WALK;
- break;
-
- case ANIM_BACK:
- s_controls.playerLegs = LEGS_BACK;
- break;
-
- case ANIM_JUMP:
- s_controls.playerLegs = LEGS_JUMP;
- break;
-
- case ANIM_CROUCH:
- s_controls.playerLegs = LEGS_IDLECR;
- break;
-
- case ANIM_TURNLEFT:
- s_controls.playerViewangles[YAW] += 90;
- break;
-
- case ANIM_TURNRIGHT:
- s_controls.playerViewangles[YAW] -= 90;
- break;
-
- case ANIM_STEPLEFT:
- s_controls.playerLegs = LEGS_WALK;
- s_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW] + 90;
- break;
-
- case ANIM_STEPRIGHT:
- s_controls.playerLegs = LEGS_WALK;
- s_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW] - 90;
- break;
-
- case ANIM_LOOKUP:
- s_controls.playerViewangles[PITCH] = -45;
- break;
-
- case ANIM_LOOKDOWN:
- s_controls.playerViewangles[PITCH] = 45;
- break;
-
- case ANIM_WEAPON1:
- s_controls.playerWeapon = WP_GAUNTLET;
- break;
-
- case ANIM_WEAPON2:
- s_controls.playerWeapon = WP_MACHINEGUN;
- break;
-
- case ANIM_WEAPON3:
- s_controls.playerWeapon = WP_SHOTGUN;
- break;
-
- case ANIM_WEAPON4:
- s_controls.playerWeapon = WP_GRENADE_LAUNCHER;
- break;
-
- case ANIM_WEAPON5:
- s_controls.playerWeapon = WP_ROCKET_LAUNCHER;
- break;
-
- case ANIM_WEAPON6:
- s_controls.playerWeapon = WP_LIGHTNING;
- break;
-
- case ANIM_WEAPON7:
- s_controls.playerWeapon = WP_RAILGUN;
- break;
-
- case ANIM_WEAPON8:
- s_controls.playerWeapon = WP_PLASMAGUN;
- break;
-
- case ANIM_WEAPON9:
- s_controls.playerWeapon = WP_BFG;
- break;
-
- case ANIM_WEAPON10:
- s_controls.playerWeapon = WP_GRAPPLING_HOOK;
- break;
-
- case ANIM_ATTACK:
- s_controls.playerTorso = TORSO_ATTACK;
- break;
-
- case ANIM_GESTURE:
- s_controls.playerTorso = TORSO_GESTURE;
- break;
-
- case ANIM_DIE:
- s_controls.playerLegs = BOTH_DEATH1;
- s_controls.playerTorso = BOTH_DEATH1;
- s_controls.playerWeapon = WP_NONE;
- break;
-
- case ANIM_CHAT:
- s_controls.playerChat = qtrue;
- break;
-
- default:
- break;
- }
-
- UI_PlayerInfo_SetInfo( &s_controls.playerinfo, s_controls.playerLegs, s_controls.playerTorso, s_controls.playerViewangles, s_controls.playerMoveangles, s_controls.playerWeapon, s_controls.playerChat );
-}
-
-
-/*
-=================
-Controls_Update
-=================
-*/
-static void Controls_Update( void ) {
- int i;
- int j;
- int y;
- menucommon_s **controls;
- menucommon_s *control;
-
- // disable all controls in all groups
- for( i = 0; i < C_MAX; i++ ) {
- controls = g_controls[i];
- for( j = 0; (control = controls[j]) ; j++ ) {
- control->flags |= (QMF_HIDDEN|QMF_INACTIVE);
- }
- }
-
- controls = g_controls[s_controls.section];
-
- // enable controls in active group (and count number of items for vertical centering)
- for( j = 0; (control = controls[j]) ; j++ ) {
- control->flags &= ~(QMF_GRAYED|QMF_HIDDEN|QMF_INACTIVE);
- }
-
- // position controls
- y = ( SCREEN_HEIGHT - j * SMALLCHAR_HEIGHT ) / 2;
- for( j = 0; (control = controls[j]) ; j++, y += SMALLCHAR_HEIGHT ) {
- control->x = 320;
- control->y = y;
- control->left = 320 - 19*SMALLCHAR_WIDTH;
- control->right = 320 + 21*SMALLCHAR_WIDTH;
- control->top = y;
- control->bottom = y + SMALLCHAR_HEIGHT;
- }
-
- if( s_controls.waitingforkey ) {
- // disable everybody
- for( i = 0; i < s_controls.menu.nitems; i++ ) {
- ((menucommon_s*)(s_controls.menu.items[i]))->flags |= QMF_GRAYED;
- }
-
- // enable action item
- ((menucommon_s*)(s_controls.menu.items[s_controls.menu.cursor]))->flags &= ~QMF_GRAYED;
-
- // don't gray out player's name
- s_controls.name.generic.flags &= ~QMF_GRAYED;
-
- return;
- }
-
- // enable everybody
- for( i = 0; i < s_controls.menu.nitems; i++ ) {
- ((menucommon_s*)(s_controls.menu.items[i]))->flags &= ~QMF_GRAYED;
- }
-
- // makes sure flags are right on the group selection controls
- s_controls.looking.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- s_controls.movement.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- s_controls.weapons.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- s_controls.misc.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
-
- s_controls.looking.generic.flags |= QMF_PULSEIFFOCUS;
- s_controls.movement.generic.flags |= QMF_PULSEIFFOCUS;
- s_controls.weapons.generic.flags |= QMF_PULSEIFFOCUS;
- s_controls.misc.generic.flags |= QMF_PULSEIFFOCUS;
-
- // set buttons
- switch( s_controls.section ) {
- case C_MOVEMENT:
- s_controls.movement.generic.flags &= ~QMF_PULSEIFFOCUS;
- s_controls.movement.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- break;
-
- case C_LOOKING:
- s_controls.looking.generic.flags &= ~QMF_PULSEIFFOCUS;
- s_controls.looking.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- break;
-
- case C_WEAPONS:
- s_controls.weapons.generic.flags &= ~QMF_PULSEIFFOCUS;
- s_controls.weapons.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- break;
-
- case C_MISC:
- s_controls.misc.generic.flags &= ~QMF_PULSEIFFOCUS;
- s_controls.misc.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- break;
- }
-}
-
-
-/*
-=================
-Controls_DrawKeyBinding
-=================
-*/
-static void Controls_DrawKeyBinding( void *self )
-{
- menuaction_s* a;
- int x;
- int y;
- int b1;
- int b2;
- qboolean c;
- char name[32];
- char name2[32];
-
- a = (menuaction_s*) self;
-
- x = a->generic.x;
- y = a->generic.y;
-
- c = (Menu_ItemAtCursor( a->generic.parent ) == a);
-
- b1 = g_bindings[a->generic.id].bind1;
- if (b1 == -1)
- strcpy(name,"???");
- else
- {
- trap_Key_KeynumToStringBuf( b1, name, 32 );
- Q_strupr(name);
-
- b2 = g_bindings[a->generic.id].bind2;
- if (b2 != -1)
- {
- trap_Key_KeynumToStringBuf( b2, name2, 32 );
- Q_strupr(name2);
-
- strcat( name, " or " );
- strcat( name, name2 );
- }
- }
-
- if (c)
- {
- UI_FillRect( a->generic.left, a->generic.top, a->generic.right-a->generic.left+1, a->generic.bottom-a->generic.top+1, listbar_color );
-
- UI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, text_color_highlight );
- UI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT|UI_PULSE, text_color_highlight );
-
- if (s_controls.waitingforkey)
- {
- UI_DrawChar( x, y, '=', UI_CENTER|UI_BLINK|UI_SMALLFONT, text_color_highlight);
- UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.80, "Waiting for new key ... ESCAPE to cancel", UI_SMALLFONT|UI_CENTER|UI_PULSE, colorWhite );
- }
- else
- {
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, text_color_highlight);
- UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.78, "Press ENTER or CLICK to change", UI_SMALLFONT|UI_CENTER, colorWhite );
- UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.82, "Press BACKSPACE to clear", UI_SMALLFONT|UI_CENTER, colorWhite );
- }
- }
- else
- {
- if (a->generic.flags & QMF_GRAYED)
- {
- UI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, text_color_disabled );
- UI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT, text_color_disabled );
- }
- else
- {
- UI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, controls_binding_color );
- UI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT, controls_binding_color );
- }
- }
-}
-
-/*
-=================
-Controls_StatusBar
-=================
-*/
-static void Controls_StatusBar( void *self )
-{
- UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.80, "Use Arrow Keys or CLICK to change", UI_SMALLFONT|UI_CENTER, colorWhite );
-}
-
-
-/*
-=================
-Controls_DrawPlayer
-=================
-*/
-static void Controls_DrawPlayer( void *self ) {
- menubitmap_s *b;
- char buf[MAX_QPATH];
-
- trap_Cvar_VariableStringBuffer( "model", buf, sizeof( buf ) );
- if ( strcmp( buf, s_controls.playerModel ) != 0 ) {
- UI_PlayerInfo_SetModel( &s_controls.playerinfo, buf );
- strcpy( s_controls.playerModel, buf );
- Controls_UpdateModel( ANIM_IDLE );
- }
-
- b = (menubitmap_s*) self;
- UI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_controls.playerinfo, uis.realtime/2 );
-}
-
-
-/*
-=================
-Controls_GetKeyAssignment
-=================
-*/
-static void Controls_GetKeyAssignment (char *command, int *twokeys)
-{
- int count;
- int j;
- char b[256];
-
- twokeys[0] = twokeys[1] = -1;
- count = 0;
-
- for ( j = 0; j < 256; j++ )
- {
- trap_Key_GetBindingBuf( j, b, 256 );
- if ( *b == 0 ) {
- continue;
- }
- if ( !Q_stricmp( b, command ) ) {
- twokeys[count] = j;
- count++;
- if (count == 2)
- break;
- }
- }
-}
-
-/*
-=================
-Controls_GetConfig
-=================
-*/
-static void Controls_GetConfig( void )
-{
- int i;
- int twokeys[2];
- bind_t* bindptr;
-
- // put the bindings into a local store
- bindptr = g_bindings;
-
- // iterate each command, get its numeric binding
- for (i=0; ;i++,bindptr++)
- {
- if (!bindptr->label)
- break;
-
- Controls_GetKeyAssignment(bindptr->command, twokeys);
-
- bindptr->bind1 = twokeys[0];
- bindptr->bind2 = twokeys[1];
- }
-
- s_controls.invertmouse.curvalue = Controls_GetCvarValue( "m_pitch" ) < 0;
- s_controls.smoothmouse.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "m_filter" ) );
- s_controls.alwaysrun.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_run" ) );
- s_controls.autoswitch.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_autoswitch" ) );
- s_controls.sensitivity.curvalue = UI_ClampCvar( 2, 30, Controls_GetCvarValue( "sensitivity" ) );
- s_controls.joyenable.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "in_joystick" ) );
- s_controls.joythreshold.curvalue = UI_ClampCvar( 0.05f, 0.75f, Controls_GetCvarValue( "joy_threshold" ) );
- s_controls.freelook.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_freelook" ) );
-}
-
-/*
-=================
-Controls_SetConfig
-=================
-*/
-static void Controls_SetConfig( void )
-{
- int i;
- bind_t* bindptr;
-
- // set the bindings from the local store
- bindptr = g_bindings;
-
- // iterate each command, get its numeric binding
- for (i=0; ;i++,bindptr++)
- {
- if (!bindptr->label)
- break;
-
- if (bindptr->bind1 != -1)
- {
- trap_Key_SetBinding( bindptr->bind1, bindptr->command );
-
- if (bindptr->bind2 != -1)
- trap_Key_SetBinding( bindptr->bind2, bindptr->command );
- }
- }
-
- if ( s_controls.invertmouse.curvalue )
- trap_Cvar_SetValue( "m_pitch", -fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
- else
- trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
-
- trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue );
- trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue );
- trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue );
- trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue );
- trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue );
- trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue );
- trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue );
- trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" );
-}
-
-/*
-=================
-Controls_SetDefaults
-=================
-*/
-static void Controls_SetDefaults( void )
-{
- int i;
- bind_t* bindptr;
-
- // set the bindings from the local store
- bindptr = g_bindings;
-
- // iterate each command, set its default binding
- for (i=0; ;i++,bindptr++)
- {
- if (!bindptr->label)
- break;
-
- bindptr->bind1 = bindptr->defaultbind1;
- bindptr->bind2 = bindptr->defaultbind2;
- }
-
- s_controls.invertmouse.curvalue = Controls_GetCvarDefault( "m_pitch" ) < 0;
- s_controls.smoothmouse.curvalue = Controls_GetCvarDefault( "m_filter" );
- s_controls.alwaysrun.curvalue = Controls_GetCvarDefault( "cl_run" );
- s_controls.autoswitch.curvalue = Controls_GetCvarDefault( "cg_autoswitch" );
- s_controls.sensitivity.curvalue = Controls_GetCvarDefault( "sensitivity" );
- s_controls.joyenable.curvalue = Controls_GetCvarDefault( "in_joystick" );
- s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" );
- s_controls.freelook.curvalue = Controls_GetCvarDefault( "cl_freelook" );
-}
-
-/*
-=================
-Controls_MenuKey
-=================
-*/
-static sfxHandle_t Controls_MenuKey( int key )
-{
- int id;
- int i;
- qboolean found;
- bind_t* bindptr;
- found = qfalse;
-
- if (!s_controls.waitingforkey)
- {
- switch (key)
- {
- case K_BACKSPACE:
- case K_DEL:
- case K_KP_DEL:
- key = -1;
- break;
-
- case K_MOUSE2:
- case K_ESCAPE:
- if (s_controls.changesmade)
- Controls_SetConfig();
- goto ignorekey;
-
- default:
- goto ignorekey;
- }
- }
- else
- {
- if (key & K_CHAR_FLAG)
- goto ignorekey;
-
- switch (key)
- {
- case K_ESCAPE:
- s_controls.waitingforkey = qfalse;
- Controls_Update();
- return (menu_out_sound);
-
- case '`':
- goto ignorekey;
- }
- }
-
- s_controls.changesmade = qtrue;
-
- if (key != -1)
- {
- // remove from any other bind
- bindptr = g_bindings;
- for (i=0; ;i++,bindptr++)
- {
- if (!bindptr->label)
- break;
-
- if (bindptr->bind2 == key)
- bindptr->bind2 = -1;
-
- if (bindptr->bind1 == key)
- {
- bindptr->bind1 = bindptr->bind2;
- bindptr->bind2 = -1;
- }
- }
- }
-
- // assign key to local store
- id = ((menucommon_s*)(s_controls.menu.items[s_controls.menu.cursor]))->id;
- bindptr = g_bindings;
- for (i=0; ;i++,bindptr++)
- {
- if (!bindptr->label)
- break;
-
- if (bindptr->id == id)
- {
- found = qtrue;
- if (key == -1)
- {
- if( bindptr->bind1 != -1 ) {
- trap_Key_SetBinding( bindptr->bind1, "" );
- bindptr->bind1 = -1;
- }
- if( bindptr->bind2 != -1 ) {
- trap_Key_SetBinding( bindptr->bind2, "" );
- bindptr->bind2 = -1;
- }
- }
- else if (bindptr->bind1 == -1) {
- bindptr->bind1 = key;
- }
- else if (bindptr->bind1 != key && bindptr->bind2 == -1) {
- bindptr->bind2 = key;
- }
- else
- {
- trap_Key_SetBinding( bindptr->bind1, "" );
- trap_Key_SetBinding( bindptr->bind2, "" );
- bindptr->bind1 = key;
- bindptr->bind2 = -1;
- }
- break;
- }
- }
-
- s_controls.waitingforkey = qfalse;
-
- if (found)
- {
- Controls_Update();
- return (menu_out_sound);
- }
-
-ignorekey:
- return Menu_DefaultKey( &s_controls.menu, key );
-}
-
-/*
-=================
-Controls_ResetDefaults_Action
-=================
-*/
-static void Controls_ResetDefaults_Action( qboolean result ) {
- if( !result ) {
- return;
- }
-
- s_controls.changesmade = qtrue;
- Controls_SetDefaults();
- Controls_Update();
-}
-
-/*
-=================
-Controls_ResetDefaults_Draw
-=================
-*/
-static void Controls_ResetDefaults_Draw( void ) {
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, "WARNING: This will reset all", UI_CENTER|UI_SMALLFONT, color_yellow );
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, "controls to their default values.", UI_CENTER|UI_SMALLFONT, color_yellow );
-}
-
-/*
-=================
-Controls_MenuEvent
-=================
-*/
-static void Controls_MenuEvent( void* ptr, int event )
-{
- switch (((menucommon_s*)ptr)->id)
- {
- case ID_MOVEMENT:
- if (event == QM_ACTIVATED)
- {
- s_controls.section = C_MOVEMENT;
- Controls_Update();
- }
- break;
-
- case ID_LOOKING:
- if (event == QM_ACTIVATED)
- {
- s_controls.section = C_LOOKING;
- Controls_Update();
- }
- break;
-
- case ID_WEAPONS:
- if (event == QM_ACTIVATED)
- {
- s_controls.section = C_WEAPONS;
- Controls_Update();
- }
- break;
-
- case ID_MISC:
- if (event == QM_ACTIVATED)
- {
- s_controls.section = C_MISC;
- Controls_Update();
- }
- break;
-
- case ID_DEFAULTS:
- if (event == QM_ACTIVATED)
- {
- UI_ConfirmMenu( "SET TO DEFAULTS?", Controls_ResetDefaults_Draw, Controls_ResetDefaults_Action );
- }
- break;
-
- case ID_BACK:
- if (event == QM_ACTIVATED)
- {
- if (s_controls.changesmade)
- Controls_SetConfig();
- UI_PopMenu();
- }
- break;
-
- case ID_SAVEANDEXIT:
- if (event == QM_ACTIVATED)
- {
- Controls_SetConfig();
- UI_PopMenu();
- }
- break;
-
- case ID_EXIT:
- if (event == QM_ACTIVATED)
- {
- UI_PopMenu();
- }
- break;
-
- case ID_FREELOOK:
- case ID_MOUSESPEED:
- case ID_INVERTMOUSE:
- case ID_SMOOTHMOUSE:
- case ID_ALWAYSRUN:
- case ID_AUTOSWITCH:
- case ID_JOYENABLE:
- case ID_JOYTHRESHOLD:
- if (event == QM_ACTIVATED)
- {
- s_controls.changesmade = qtrue;
- }
- break;
- }
-}
-
-/*
-=================
-Controls_ActionEvent
-=================
-*/
-static void Controls_ActionEvent( void* ptr, int event )
-{
- if (event == QM_LOSTFOCUS)
- {
- Controls_UpdateModel( ANIM_IDLE );
- }
- else if (event == QM_GOTFOCUS)
- {
- Controls_UpdateModel( g_bindings[((menucommon_s*)ptr)->id].anim );
- }
- else if ((event == QM_ACTIVATED) && !s_controls.waitingforkey)
- {
- s_controls.waitingforkey = 1;
- Controls_Update();
- }
-}
-
-/*
-=================
-Controls_InitModel
-=================
-*/
-static void Controls_InitModel( void )
-{
- memset( &s_controls.playerinfo, 0, sizeof(playerInfo_t) );
-
- UI_PlayerInfo_SetModel( &s_controls.playerinfo, UI_Cvar_VariableString( "model" ) );
-
- Controls_UpdateModel( ANIM_IDLE );
-}
-
-/*
-=================
-Controls_InitWeapons
-=================
-*/
-static void Controls_InitWeapons( void ) {
- gitem_t * item;
-
- for ( item = bg_itemlist + 1 ; item->classname ; item++ ) {
- if ( item->giType != IT_WEAPON ) {
- continue;
- }
- trap_R_RegisterModel( item->world_model[0] );
- }
-}
-
-/*
-=================
-Controls_MenuInit
-=================
-*/
-static void Controls_MenuInit( void )
-{
- static char playername[32];
-
- // zero set all our globals
- memset( &s_controls, 0 ,sizeof(controls_t) );
-
- Controls_Cache();
-
- s_controls.menu.key = Controls_MenuKey;
- s_controls.menu.wrapAround = qtrue;
- s_controls.menu.fullscreen = qtrue;
-
- s_controls.banner.generic.type = MTYPE_BTEXT;
- s_controls.banner.generic.flags = QMF_CENTER_JUSTIFY;
- s_controls.banner.generic.x = 320;
- s_controls.banner.generic.y = 16;
- s_controls.banner.string = "CONTROLS";
- s_controls.banner.color = color_white;
- s_controls.banner.style = UI_CENTER;
-
- s_controls.framel.generic.type = MTYPE_BITMAP;
- s_controls.framel.generic.name = ART_FRAMEL;
- s_controls.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_controls.framel.generic.x = 0;
- s_controls.framel.generic.y = 78;
- s_controls.framel.width = 256;
- s_controls.framel.height = 329;
-
- s_controls.framer.generic.type = MTYPE_BITMAP;
- s_controls.framer.generic.name = ART_FRAMER;
- s_controls.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_controls.framer.generic.x = 376;
- s_controls.framer.generic.y = 76;
- s_controls.framer.width = 256;
- s_controls.framer.height = 334;
-
- s_controls.looking.generic.type = MTYPE_PTEXT;
- s_controls.looking.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_controls.looking.generic.id = ID_LOOKING;
- s_controls.looking.generic.callback = Controls_MenuEvent;
- s_controls.looking.generic.x = 152;
- s_controls.looking.generic.y = 240 - 2 * PROP_HEIGHT;
- s_controls.looking.string = "LOOK";
- s_controls.looking.style = UI_RIGHT;
- s_controls.looking.color = color_red;
-
- s_controls.movement.generic.type = MTYPE_PTEXT;
- s_controls.movement.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_controls.movement.generic.id = ID_MOVEMENT;
- s_controls.movement.generic.callback = Controls_MenuEvent;
- s_controls.movement.generic.x = 152;
- s_controls.movement.generic.y = 240 - PROP_HEIGHT;
- s_controls.movement.string = "MOVE";
- s_controls.movement.style = UI_RIGHT;
- s_controls.movement.color = color_red;
-
- s_controls.weapons.generic.type = MTYPE_PTEXT;
- s_controls.weapons.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_controls.weapons.generic.id = ID_WEAPONS;
- s_controls.weapons.generic.callback = Controls_MenuEvent;
- s_controls.weapons.generic.x = 152;
- s_controls.weapons.generic.y = 240;
- s_controls.weapons.string = "SHOOT";
- s_controls.weapons.style = UI_RIGHT;
- s_controls.weapons.color = color_red;
-
- s_controls.misc.generic.type = MTYPE_PTEXT;
- s_controls.misc.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_controls.misc.generic.id = ID_MISC;
- s_controls.misc.generic.callback = Controls_MenuEvent;
- s_controls.misc.generic.x = 152;
- s_controls.misc.generic.y = 240 + PROP_HEIGHT;
- s_controls.misc.string = "MISC";
- s_controls.misc.style = UI_RIGHT;
- s_controls.misc.color = color_red;
-
- s_controls.back.generic.type = MTYPE_BITMAP;
- s_controls.back.generic.name = ART_BACK0;
- s_controls.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_controls.back.generic.x = 0;
- s_controls.back.generic.y = 480-64;
- s_controls.back.generic.id = ID_BACK;
- s_controls.back.generic.callback = Controls_MenuEvent;
- s_controls.back.width = 128;
- s_controls.back.height = 64;
- s_controls.back.focuspic = ART_BACK1;
-
- s_controls.player.generic.type = MTYPE_BITMAP;
- s_controls.player.generic.flags = QMF_INACTIVE;
- s_controls.player.generic.ownerdraw = Controls_DrawPlayer;
- s_controls.player.generic.x = 400;
- s_controls.player.generic.y = -40;
- s_controls.player.width = 32*10;
- s_controls.player.height = 56*10;
-
- s_controls.walkforward.generic.type = MTYPE_ACTION;
- s_controls.walkforward.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.walkforward.generic.callback = Controls_ActionEvent;
- s_controls.walkforward.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.walkforward.generic.id = ID_FORWARD;
-
- s_controls.backpedal.generic.type = MTYPE_ACTION;
- s_controls.backpedal.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.backpedal.generic.callback = Controls_ActionEvent;
- s_controls.backpedal.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.backpedal.generic.id = ID_BACKPEDAL;
-
- s_controls.stepleft.generic.type = MTYPE_ACTION;
- s_controls.stepleft.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.stepleft.generic.callback = Controls_ActionEvent;
- s_controls.stepleft.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.stepleft.generic.id = ID_MOVELEFT;
-
- s_controls.stepright.generic.type = MTYPE_ACTION;
- s_controls.stepright.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.stepright.generic.callback = Controls_ActionEvent;
- s_controls.stepright.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.stepright.generic.id = ID_MOVERIGHT;
-
- s_controls.moveup.generic.type = MTYPE_ACTION;
- s_controls.moveup.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.moveup.generic.callback = Controls_ActionEvent;
- s_controls.moveup.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.moveup.generic.id = ID_MOVEUP;
-
- s_controls.movedown.generic.type = MTYPE_ACTION;
- s_controls.movedown.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.movedown.generic.callback = Controls_ActionEvent;
- s_controls.movedown.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.movedown.generic.id = ID_MOVEDOWN;
-
- s_controls.turnleft.generic.type = MTYPE_ACTION;
- s_controls.turnleft.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.turnleft.generic.callback = Controls_ActionEvent;
- s_controls.turnleft.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.turnleft.generic.id = ID_LEFT;
-
- s_controls.turnright.generic.type = MTYPE_ACTION;
- s_controls.turnright.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.turnright.generic.callback = Controls_ActionEvent;
- s_controls.turnright.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.turnright.generic.id = ID_RIGHT;
-
- s_controls.sidestep.generic.type = MTYPE_ACTION;
- s_controls.sidestep.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.sidestep.generic.callback = Controls_ActionEvent;
- s_controls.sidestep.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.sidestep.generic.id = ID_STRAFE;
-
- s_controls.run.generic.type = MTYPE_ACTION;
- s_controls.run.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.run.generic.callback = Controls_ActionEvent;
- s_controls.run.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.run.generic.id = ID_SPEED;
-
- s_controls.chainsaw.generic.type = MTYPE_ACTION;
- s_controls.chainsaw.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.chainsaw.generic.callback = Controls_ActionEvent;
- s_controls.chainsaw.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.chainsaw.generic.id = ID_WEAPON1;
-
- s_controls.machinegun.generic.type = MTYPE_ACTION;
- s_controls.machinegun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.machinegun.generic.callback = Controls_ActionEvent;
- s_controls.machinegun.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.machinegun.generic.id = ID_WEAPON2;
-
- s_controls.shotgun.generic.type = MTYPE_ACTION;
- s_controls.shotgun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.shotgun.generic.callback = Controls_ActionEvent;
- s_controls.shotgun.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.shotgun.generic.id = ID_WEAPON3;
-
- s_controls.grenadelauncher.generic.type = MTYPE_ACTION;
- s_controls.grenadelauncher.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.grenadelauncher.generic.callback = Controls_ActionEvent;
- s_controls.grenadelauncher.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.grenadelauncher.generic.id = ID_WEAPON4;
-
- s_controls.rocketlauncher.generic.type = MTYPE_ACTION;
- s_controls.rocketlauncher.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.rocketlauncher.generic.callback = Controls_ActionEvent;
- s_controls.rocketlauncher.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.rocketlauncher.generic.id = ID_WEAPON5;
-
- s_controls.lightning.generic.type = MTYPE_ACTION;
- s_controls.lightning.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.lightning.generic.callback = Controls_ActionEvent;
- s_controls.lightning.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.lightning.generic.id = ID_WEAPON6;
-
- s_controls.railgun.generic.type = MTYPE_ACTION;
- s_controls.railgun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.railgun.generic.callback = Controls_ActionEvent;
- s_controls.railgun.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.railgun.generic.id = ID_WEAPON7;
-
- s_controls.plasma.generic.type = MTYPE_ACTION;
- s_controls.plasma.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.plasma.generic.callback = Controls_ActionEvent;
- s_controls.plasma.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.plasma.generic.id = ID_WEAPON8;
-
- s_controls.bfg.generic.type = MTYPE_ACTION;
- s_controls.bfg.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.bfg.generic.callback = Controls_ActionEvent;
- s_controls.bfg.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.bfg.generic.id = ID_WEAPON9;
-
- s_controls.attack.generic.type = MTYPE_ACTION;
- s_controls.attack.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.attack.generic.callback = Controls_ActionEvent;
- s_controls.attack.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.attack.generic.id = ID_ATTACK;
-
- s_controls.prevweapon.generic.type = MTYPE_ACTION;
- s_controls.prevweapon.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.prevweapon.generic.callback = Controls_ActionEvent;
- s_controls.prevweapon.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.prevweapon.generic.id = ID_WEAPPREV;
-
- s_controls.nextweapon.generic.type = MTYPE_ACTION;
- s_controls.nextweapon.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.nextweapon.generic.callback = Controls_ActionEvent;
- s_controls.nextweapon.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.nextweapon.generic.id = ID_WEAPNEXT;
-
- s_controls.lookup.generic.type = MTYPE_ACTION;
- s_controls.lookup.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.lookup.generic.callback = Controls_ActionEvent;
- s_controls.lookup.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.lookup.generic.id = ID_LOOKUP;
-
- s_controls.lookdown.generic.type = MTYPE_ACTION;
- s_controls.lookdown.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.lookdown.generic.callback = Controls_ActionEvent;
- s_controls.lookdown.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.lookdown.generic.id = ID_LOOKDOWN;
-
- s_controls.mouselook.generic.type = MTYPE_ACTION;
- s_controls.mouselook.generic.flags = QMF_LEFT_JUSTIFY|QMF_HIGHLIGHT_IF_FOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.mouselook.generic.callback = Controls_ActionEvent;
- s_controls.mouselook.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.mouselook.generic.id = ID_MOUSELOOK;
-
- s_controls.freelook.generic.type = MTYPE_RADIOBUTTON;
- s_controls.freelook.generic.flags = QMF_SMALLFONT;
- s_controls.freelook.generic.x = SCREEN_WIDTH/2;
- s_controls.freelook.generic.name = "free look";
- s_controls.freelook.generic.id = ID_FREELOOK;
- s_controls.freelook.generic.callback = Controls_MenuEvent;
- s_controls.freelook.generic.statusbar = Controls_StatusBar;
-
- s_controls.centerview.generic.type = MTYPE_ACTION;
- s_controls.centerview.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.centerview.generic.callback = Controls_ActionEvent;
- s_controls.centerview.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.centerview.generic.id = ID_CENTERVIEW;
-
- s_controls.zoomview.generic.type = MTYPE_ACTION;
- s_controls.zoomview.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.zoomview.generic.callback = Controls_ActionEvent;
- s_controls.zoomview.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.zoomview.generic.id = ID_ZOOMVIEW;
-
- s_controls.useitem.generic.type = MTYPE_ACTION;
- s_controls.useitem.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.useitem.generic.callback = Controls_ActionEvent;
- s_controls.useitem.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.useitem.generic.id = ID_USEITEM;
-
- s_controls.showscores.generic.type = MTYPE_ACTION;
- s_controls.showscores.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.showscores.generic.callback = Controls_ActionEvent;
- s_controls.showscores.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.showscores.generic.id = ID_SHOWSCORES;
-
- s_controls.invertmouse.generic.type = MTYPE_RADIOBUTTON;
- s_controls.invertmouse.generic.flags = QMF_SMALLFONT;
- s_controls.invertmouse.generic.x = SCREEN_WIDTH/2;
- s_controls.invertmouse.generic.name = "invert mouse";
- s_controls.invertmouse.generic.id = ID_INVERTMOUSE;
- s_controls.invertmouse.generic.callback = Controls_MenuEvent;
- s_controls.invertmouse.generic.statusbar = Controls_StatusBar;
-
- s_controls.smoothmouse.generic.type = MTYPE_RADIOBUTTON;
- s_controls.smoothmouse.generic.flags = QMF_SMALLFONT;
- s_controls.smoothmouse.generic.x = SCREEN_WIDTH/2;
- s_controls.smoothmouse.generic.name = "smooth mouse";
- s_controls.smoothmouse.generic.id = ID_SMOOTHMOUSE;
- s_controls.smoothmouse.generic.callback = Controls_MenuEvent;
- s_controls.smoothmouse.generic.statusbar = Controls_StatusBar;
-
- s_controls.alwaysrun.generic.type = MTYPE_RADIOBUTTON;
- s_controls.alwaysrun.generic.flags = QMF_SMALLFONT;
- s_controls.alwaysrun.generic.x = SCREEN_WIDTH/2;
- s_controls.alwaysrun.generic.name = "always run";
- s_controls.alwaysrun.generic.id = ID_ALWAYSRUN;
- s_controls.alwaysrun.generic.callback = Controls_MenuEvent;
- s_controls.alwaysrun.generic.statusbar = Controls_StatusBar;
-
- s_controls.autoswitch.generic.type = MTYPE_RADIOBUTTON;
- s_controls.autoswitch.generic.flags = QMF_SMALLFONT;
- s_controls.autoswitch.generic.x = SCREEN_WIDTH/2;
- s_controls.autoswitch.generic.name = "autoswitch weapons";
- s_controls.autoswitch.generic.id = ID_AUTOSWITCH;
- s_controls.autoswitch.generic.callback = Controls_MenuEvent;
- s_controls.autoswitch.generic.statusbar = Controls_StatusBar;
-
- s_controls.sensitivity.generic.type = MTYPE_SLIDER;
- s_controls.sensitivity.generic.x = SCREEN_WIDTH/2;
- s_controls.sensitivity.generic.flags = QMF_SMALLFONT;
- s_controls.sensitivity.generic.name = "mouse speed";
- s_controls.sensitivity.generic.id = ID_MOUSESPEED;
- s_controls.sensitivity.generic.callback = Controls_MenuEvent;
- s_controls.sensitivity.minvalue = 2;
- s_controls.sensitivity.maxvalue = 30;
- s_controls.sensitivity.generic.statusbar = Controls_StatusBar;
-
- s_controls.gesture.generic.type = MTYPE_ACTION;
- s_controls.gesture.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.gesture.generic.callback = Controls_ActionEvent;
- s_controls.gesture.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.gesture.generic.id = ID_GESTURE;
-
- s_controls.chat.generic.type = MTYPE_ACTION;
- s_controls.chat.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.chat.generic.callback = Controls_ActionEvent;
- s_controls.chat.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.chat.generic.id = ID_CHAT;
-
- s_controls.chat2.generic.type = MTYPE_ACTION;
- s_controls.chat2.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.chat2.generic.callback = Controls_ActionEvent;
- s_controls.chat2.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.chat2.generic.id = ID_CHAT2;
-
- s_controls.chat3.generic.type = MTYPE_ACTION;
- s_controls.chat3.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.chat3.generic.callback = Controls_ActionEvent;
- s_controls.chat3.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.chat3.generic.id = ID_CHAT3;
-
- s_controls.chat4.generic.type = MTYPE_ACTION;
- s_controls.chat4.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.chat4.generic.callback = Controls_ActionEvent;
- s_controls.chat4.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.chat4.generic.id = ID_CHAT4;
-
- s_controls.joyenable.generic.type = MTYPE_RADIOBUTTON;
- s_controls.joyenable.generic.flags = QMF_SMALLFONT;
- s_controls.joyenable.generic.x = SCREEN_WIDTH/2;
- s_controls.joyenable.generic.name = "joystick";
- s_controls.joyenable.generic.id = ID_JOYENABLE;
- s_controls.joyenable.generic.callback = Controls_MenuEvent;
- s_controls.joyenable.generic.statusbar = Controls_StatusBar;
-
- s_controls.joythreshold.generic.type = MTYPE_SLIDER;
- s_controls.joythreshold.generic.x = SCREEN_WIDTH/2;
- s_controls.joythreshold.generic.flags = QMF_SMALLFONT;
- s_controls.joythreshold.generic.name = "joystick threshold";
- s_controls.joythreshold.generic.id = ID_JOYTHRESHOLD;
- s_controls.joythreshold.generic.callback = Controls_MenuEvent;
- s_controls.joythreshold.minvalue = 0.05f;
- s_controls.joythreshold.maxvalue = 0.75f;
- s_controls.joythreshold.generic.statusbar = Controls_StatusBar;
-
- s_controls.name.generic.type = MTYPE_PTEXT;
- s_controls.name.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
- s_controls.name.generic.x = 320;
- s_controls.name.generic.y = 440;
- s_controls.name.string = playername;
- s_controls.name.style = UI_CENTER;
- s_controls.name.color = text_color_normal;
-
- Menu_AddItem( &s_controls.menu, &s_controls.banner );
- Menu_AddItem( &s_controls.menu, &s_controls.framel );
- Menu_AddItem( &s_controls.menu, &s_controls.framer );
- Menu_AddItem( &s_controls.menu, &s_controls.player );
- Menu_AddItem( &s_controls.menu, &s_controls.name );
-
- Menu_AddItem( &s_controls.menu, &s_controls.looking );
- Menu_AddItem( &s_controls.menu, &s_controls.movement );
- Menu_AddItem( &s_controls.menu, &s_controls.weapons );
- Menu_AddItem( &s_controls.menu, &s_controls.misc );
-
- Menu_AddItem( &s_controls.menu, &s_controls.sensitivity );
- Menu_AddItem( &s_controls.menu, &s_controls.smoothmouse );
- Menu_AddItem( &s_controls.menu, &s_controls.invertmouse );
- Menu_AddItem( &s_controls.menu, &s_controls.lookup );
- Menu_AddItem( &s_controls.menu, &s_controls.lookdown );
- Menu_AddItem( &s_controls.menu, &s_controls.mouselook );
- Menu_AddItem( &s_controls.menu, &s_controls.freelook );
- Menu_AddItem( &s_controls.menu, &s_controls.centerview );
- Menu_AddItem( &s_controls.menu, &s_controls.zoomview );
- Menu_AddItem( &s_controls.menu, &s_controls.joyenable );
- Menu_AddItem( &s_controls.menu, &s_controls.joythreshold );
-
- Menu_AddItem( &s_controls.menu, &s_controls.alwaysrun );
- Menu_AddItem( &s_controls.menu, &s_controls.run );
- Menu_AddItem( &s_controls.menu, &s_controls.walkforward );
- Menu_AddItem( &s_controls.menu, &s_controls.backpedal );
- Menu_AddItem( &s_controls.menu, &s_controls.stepleft );
- Menu_AddItem( &s_controls.menu, &s_controls.stepright );
- Menu_AddItem( &s_controls.menu, &s_controls.moveup );
- Menu_AddItem( &s_controls.menu, &s_controls.movedown );
- Menu_AddItem( &s_controls.menu, &s_controls.turnleft );
- Menu_AddItem( &s_controls.menu, &s_controls.turnright );
- Menu_AddItem( &s_controls.menu, &s_controls.sidestep );
-
- Menu_AddItem( &s_controls.menu, &s_controls.attack );
- Menu_AddItem( &s_controls.menu, &s_controls.nextweapon );
- Menu_AddItem( &s_controls.menu, &s_controls.prevweapon );
- Menu_AddItem( &s_controls.menu, &s_controls.autoswitch );
- Menu_AddItem( &s_controls.menu, &s_controls.chainsaw );
- Menu_AddItem( &s_controls.menu, &s_controls.machinegun );
- Menu_AddItem( &s_controls.menu, &s_controls.shotgun );
- Menu_AddItem( &s_controls.menu, &s_controls.grenadelauncher );
- Menu_AddItem( &s_controls.menu, &s_controls.rocketlauncher );
- Menu_AddItem( &s_controls.menu, &s_controls.lightning );
- Menu_AddItem( &s_controls.menu, &s_controls.railgun );
- Menu_AddItem( &s_controls.menu, &s_controls.plasma );
- Menu_AddItem( &s_controls.menu, &s_controls.bfg );
-
- Menu_AddItem( &s_controls.menu, &s_controls.showscores );
- Menu_AddItem( &s_controls.menu, &s_controls.useitem );
- Menu_AddItem( &s_controls.menu, &s_controls.gesture );
- Menu_AddItem( &s_controls.menu, &s_controls.chat );
- Menu_AddItem( &s_controls.menu, &s_controls.chat2 );
- Menu_AddItem( &s_controls.menu, &s_controls.chat3 );
- Menu_AddItem( &s_controls.menu, &s_controls.chat4 );
-
- Menu_AddItem( &s_controls.menu, &s_controls.back );
-
- trap_Cvar_VariableStringBuffer( "name", s_controls.name.string, 16 );
- Q_CleanStr( s_controls.name.string );
-
- // initialize the configurable cvars
- Controls_InitCvars();
-
- // initialize the current config
- Controls_GetConfig();
-
- // intialize the model
- Controls_InitModel();
-
- // intialize the weapons
- Controls_InitWeapons ();
-
- // initial default section
- s_controls.section = C_LOOKING;
-
- // update the ui
- Controls_Update();
-}
-
-
-/*
-=================
-Controls_Cache
-=================
-*/
-void Controls_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
-}
-
-
-/*
-=================
-UI_ControlsMenu
-=================
-*/
-void UI_ControlsMenu( void ) {
- Controls_MenuInit();
- UI_PushMenu( &s_controls.menu );
-}
diff --git a/engine/code/q3_ui/ui_credits.c b/engine/code/q3_ui/ui_credits.c
deleted file mode 100644
index 7baee61..0000000
--- a/engine/code/q3_ui/ui_credits.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-CREDITS
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-typedef struct {
- menuframework_s menu;
- int frame;
-} creditsmenu_t;
-
-static creditsmenu_t s_credits;
-
-
-/*
-===============
-UI_CreditMenu_Draw_ioq3
-===============
-*/
-static void UI_CreditMenu_Draw_ioq3( void ) {
- int y;
- int i;
-
- // These are all people that have made commits to Subversion, and thus
- // probably incomplete.
- // (These are in alphabetical order, for the defense of everyone's egos.)
- static const char *names[] = {
- "Tim Angus",
- "Vincent Cojot",
- "Ryan C. Gordon",
- "Aaron Gyes",
- "Ludwig Nussel",
- "Julian Priestley",
- "Scirocco Six",
- "Thilo Schulz",
- "Zachary J. Slater",
- "Tony J. White",
- "...and many, many others!", // keep this one last.
- NULL
- };
-
- y = 12;
- UI_DrawProportionalString( 320, y, "ioquake3 contributors:", UI_CENTER|UI_SMALLFONT, color_white );
- y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
-
- for (i = 0; names[i]; i++) {
- UI_DrawProportionalString( 320, y, names[i], UI_CENTER|UI_SMALLFONT, color_white );
- y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- }
-
- UI_DrawString( 320, 459, "http://www.ioquake3.org/", UI_CENTER|UI_SMALLFONT, color_red );
-}
-
-
-/*
-=================
-UI_CreditMenu_Key
-=================
-*/
-static sfxHandle_t UI_CreditMenu_Key( int key ) {
- if( key & K_CHAR_FLAG ) {
- return 0;
- }
-
- s_credits.frame++;
- if (s_credits.frame == 1) {
- s_credits.menu.draw = UI_CreditMenu_Draw_ioq3;
- } else {
- trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
- }
- return 0;
-}
-
-
-/*
-===============
-UI_CreditMenu_Draw
-===============
-*/
-static void UI_CreditMenu_Draw( void ) {
- int y;
-
- y = 12;
- UI_DrawProportionalString( 320, y, "id Software is:", UI_CENTER|UI_SMALLFONT, color_white );
-
- y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Programming", UI_CENTER|UI_SMALLFONT, color_white );
- y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "John Carmack, Robert A. Duffy, Jim Dose'", UI_CENTER|UI_SMALLFONT, color_white );
-
- y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Art", UI_CENTER|UI_SMALLFONT, color_white );
- y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Adrian Carmack, Kevin Cloud,", UI_CENTER|UI_SMALLFONT, color_white );
- y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Kenneth Scott, Seneca Menard, Fred Nilsson", UI_CENTER|UI_SMALLFONT, color_white );
-
- y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Game Designer", UI_CENTER|UI_SMALLFONT, color_white );
- y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Graeme Devine", UI_CENTER|UI_SMALLFONT, color_white );
-
- y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Level Design", UI_CENTER|UI_SMALLFONT, color_white );
- y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Tim Willits, Christian Antkow, Paul Jaquays", UI_CENTER|UI_SMALLFONT, color_white );
-
- y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "CEO", UI_CENTER|UI_SMALLFONT, color_white );
- y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Todd Hollenshead", UI_CENTER|UI_SMALLFONT, color_white );
-
- y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Director of Business Development", UI_CENTER|UI_SMALLFONT, color_white );
- y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Marty Stratton", UI_CENTER|UI_SMALLFONT, color_white );
-
- y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Biz Assist and id Mom", UI_CENTER|UI_SMALLFONT, color_white );
- y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Donna Jackson", UI_CENTER|UI_SMALLFONT, color_white );
-
- y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Development Assistance", UI_CENTER|UI_SMALLFONT, color_white );
- y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Eric Webb", UI_CENTER|UI_SMALLFONT, color_white );
-
- y += 1.35 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawString( 320, y, "To order: 1-800-idgames www.quake3arena.com www.idsoftware.com", UI_CENTER|UI_SMALLFONT, color_red );
- y += SMALLCHAR_HEIGHT;
- UI_DrawString( 320, y, "Quake III Arena(c) 1999-2000, Id Software, Inc. All Rights Reserved", UI_CENTER|UI_SMALLFONT, color_red );
-}
-
-
-/*
-===============
-UI_CreditMenu
-===============
-*/
-void UI_CreditMenu( void ) {
- /* This UI_FillRect() hack will blank the borders if you're in widescreen,
- so you get a completely black background instead of stripes from the
- previous frame on each side of the credits.. */
- const float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
- UI_FillRect(0 - uis.bias, 0, (640.0f / uis.xscale) * 2.0f, 480.0f / uis.yscale, black);
-
- memset( &s_credits, 0 ,sizeof(s_credits) );
-
- s_credits.menu.draw = UI_CreditMenu_Draw;
- s_credits.menu.key = UI_CreditMenu_Key;
- s_credits.menu.fullscreen = qtrue;
- UI_PushMenu ( &s_credits.menu );
-}
diff --git a/engine/code/q3_ui/ui_demo2.c b/engine/code/q3_ui/ui_demo2.c
deleted file mode 100644
index a3810bb..0000000
--- a/engine/code/q3_ui/ui_demo2.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-DEMOS MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-#define ART_GO0 "menu/art/play_0"
-#define ART_GO1 "menu/art/play_1"
-#define ART_FRAMEL "menu/art/frame2_l"
-#define ART_FRAMER "menu/art/frame1_r"
-#define ART_ARROWS "menu/art/arrows_horz_0"
-#define ART_ARROWLEFT "menu/art/arrows_horz_left"
-#define ART_ARROWRIGHT "menu/art/arrows_horz_right"
-
-#define MAX_DEMOS 128
-#define NAMEBUFSIZE ( MAX_DEMOS * 16 )
-
-#define ID_BACK 10
-#define ID_GO 11
-#define ID_LIST 12
-#define ID_RIGHT 13
-#define ID_LEFT 14
-
-#define ARROWS_WIDTH 128
-#define ARROWS_HEIGHT 48
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menulist_s list;
-
- menubitmap_s arrows;
- menubitmap_s left;
- menubitmap_s right;
- menubitmap_s back;
- menubitmap_s go;
-
- int numDemos;
- char names[NAMEBUFSIZE];
- char *demolist[MAX_DEMOS];
-} demos_t;
-
-static demos_t s_demos;
-
-
-/*
-===============
-Demos_MenuEvent
-===============
-*/
-static void Demos_MenuEvent( void *ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_GO:
- UI_ForceMenuOff ();
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "demo %s\n",
- s_demos.list.itemnames[s_demos.list.curvalue]) );
- break;
-
- case ID_BACK:
- UI_PopMenu();
- break;
-
- case ID_LEFT:
- ScrollList_Key( &s_demos.list, K_LEFTARROW );
- break;
-
- case ID_RIGHT:
- ScrollList_Key( &s_demos.list, K_RIGHTARROW );
- break;
- }
-}
-
-
-/*
-=================
-UI_DemosMenu_Key
-=================
-*/
-static sfxHandle_t UI_DemosMenu_Key( int key ) {
- menucommon_s *item;
-
- item = Menu_ItemAtCursor( &s_demos.menu );
-
- return Menu_DefaultKey( &s_demos.menu, key );
-}
-
-
-/*
-===============
-Demos_MenuInit
-===============
-*/
-static void Demos_MenuInit( void ) {
- int i;
- int len;
- char *demoname, extension[32];
-
- memset( &s_demos, 0 ,sizeof(demos_t) );
- s_demos.menu.key = UI_DemosMenu_Key;
-
- Demos_Cache();
-
- s_demos.menu.fullscreen = qtrue;
- s_demos.menu.wrapAround = qtrue;
-
- s_demos.banner.generic.type = MTYPE_BTEXT;
- s_demos.banner.generic.x = 320;
- s_demos.banner.generic.y = 16;
- s_demos.banner.string = "DEMOS";
- s_demos.banner.color = color_white;
- s_demos.banner.style = UI_CENTER;
-
- s_demos.framel.generic.type = MTYPE_BITMAP;
- s_demos.framel.generic.name = ART_FRAMEL;
- s_demos.framel.generic.flags = QMF_INACTIVE;
- s_demos.framel.generic.x = 0;
- s_demos.framel.generic.y = 78;
- s_demos.framel.width = 256;
- s_demos.framel.height = 329;
-
- s_demos.framer.generic.type = MTYPE_BITMAP;
- s_demos.framer.generic.name = ART_FRAMER;
- s_demos.framer.generic.flags = QMF_INACTIVE;
- s_demos.framer.generic.x = 376;
- s_demos.framer.generic.y = 76;
- s_demos.framer.width = 256;
- s_demos.framer.height = 334;
-
- s_demos.arrows.generic.type = MTYPE_BITMAP;
- s_demos.arrows.generic.name = ART_ARROWS;
- s_demos.arrows.generic.flags = QMF_INACTIVE;
- s_demos.arrows.generic.x = 320-ARROWS_WIDTH/2;
- s_demos.arrows.generic.y = 400;
- s_demos.arrows.width = ARROWS_WIDTH;
- s_demos.arrows.height = ARROWS_HEIGHT;
-
- s_demos.left.generic.type = MTYPE_BITMAP;
- s_demos.left.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
- s_demos.left.generic.x = 320-ARROWS_WIDTH/2;
- s_demos.left.generic.y = 400;
- s_demos.left.generic.id = ID_LEFT;
- s_demos.left.generic.callback = Demos_MenuEvent;
- s_demos.left.width = ARROWS_WIDTH/2;
- s_demos.left.height = ARROWS_HEIGHT;
- s_demos.left.focuspic = ART_ARROWLEFT;
-
- s_demos.right.generic.type = MTYPE_BITMAP;
- s_demos.right.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
- s_demos.right.generic.x = 320;
- s_demos.right.generic.y = 400;
- s_demos.right.generic.id = ID_RIGHT;
- s_demos.right.generic.callback = Demos_MenuEvent;
- s_demos.right.width = ARROWS_WIDTH/2;
- s_demos.right.height = ARROWS_HEIGHT;
- s_demos.right.focuspic = ART_ARROWRIGHT;
-
- s_demos.back.generic.type = MTYPE_BITMAP;
- s_demos.back.generic.name = ART_BACK0;
- s_demos.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_demos.back.generic.id = ID_BACK;
- s_demos.back.generic.callback = Demos_MenuEvent;
- s_demos.back.generic.x = 0;
- s_demos.back.generic.y = 480-64;
- s_demos.back.width = 128;
- s_demos.back.height = 64;
- s_demos.back.focuspic = ART_BACK1;
-
- s_demos.go.generic.type = MTYPE_BITMAP;
- s_demos.go.generic.name = ART_GO0;
- s_demos.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_demos.go.generic.id = ID_GO;
- s_demos.go.generic.callback = Demos_MenuEvent;
- s_demos.go.generic.x = 640;
- s_demos.go.generic.y = 480-64;
- s_demos.go.width = 128;
- s_demos.go.height = 64;
- s_demos.go.focuspic = ART_GO1;
-
- s_demos.list.generic.type = MTYPE_SCROLLLIST;
- s_demos.list.generic.flags = QMF_PULSEIFFOCUS;
- s_demos.list.generic.callback = Demos_MenuEvent;
- s_demos.list.generic.id = ID_LIST;
- s_demos.list.generic.x = 118;
- s_demos.list.generic.y = 130;
- s_demos.list.width = 16;
- s_demos.list.height = 14;
- Com_sprintf(extension, sizeof(extension), "dm_%d", (int)trap_Cvar_VariableValue( "protocol" ) );
- s_demos.list.numitems = trap_FS_GetFileList( "demos", extension, s_demos.names, NAMEBUFSIZE );
- s_demos.list.itemnames = (const char **)s_demos.demolist;
- s_demos.list.columns = 3;
-
- if (!s_demos.list.numitems) {
- strcpy( s_demos.names, "No Demos Found." );
- s_demos.list.numitems = 1;
-
- //degenerate case, not selectable
- s_demos.go.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- }
- else if (s_demos.list.numitems > MAX_DEMOS)
- s_demos.list.numitems = MAX_DEMOS;
-
- demoname = s_demos.names;
- for ( i = 0; i < s_demos.list.numitems; i++ ) {
- s_demos.list.itemnames[i] = demoname;
-
- // strip extension
- len = strlen( demoname );
- if (!Q_stricmp(demoname + len - 4,".dm3"))
- demoname[len-4] = '\0';
-
-// Q_strupr(demoname);
-
- demoname += len + 1;
- }
-
- Menu_AddItem( &s_demos.menu, &s_demos.banner );
- Menu_AddItem( &s_demos.menu, &s_demos.framel );
- Menu_AddItem( &s_demos.menu, &s_demos.framer );
- Menu_AddItem( &s_demos.menu, &s_demos.list );
- Menu_AddItem( &s_demos.menu, &s_demos.arrows );
- Menu_AddItem( &s_demos.menu, &s_demos.left );
- Menu_AddItem( &s_demos.menu, &s_demos.right );
- Menu_AddItem( &s_demos.menu, &s_demos.back );
- Menu_AddItem( &s_demos.menu, &s_demos.go );
-}
-
-/*
-=================
-Demos_Cache
-=================
-*/
-void Demos_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_GO0 );
- trap_R_RegisterShaderNoMip( ART_GO1 );
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
- trap_R_RegisterShaderNoMip( ART_ARROWS );
- trap_R_RegisterShaderNoMip( ART_ARROWLEFT );
- trap_R_RegisterShaderNoMip( ART_ARROWRIGHT );
-}
-
-/*
-===============
-UI_DemosMenu
-===============
-*/
-void UI_DemosMenu( void ) {
- Demos_MenuInit();
- UI_PushMenu( &s_demos.menu );
-}
diff --git a/engine/code/q3_ui/ui_display.c b/engine/code/q3_ui/ui_display.c
deleted file mode 100644
index 5980c1a..0000000
--- a/engine/code/q3_ui/ui_display.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-DISPLAY OPTIONS MENU
-
-=======================================================================
-*/
-
-#include "ui_local.h"
-
-
-#define ART_FRAMEL "menu/art/frame2_l"
-#define ART_FRAMER "menu/art/frame1_r"
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-
-#define ID_GRAPHICS 10
-#define ID_DISPLAY 11
-#define ID_SOUND 12
-#define ID_NETWORK 13
-#define ID_BRIGHTNESS 14
-#define ID_SCREENSIZE 15
-#define ID_BACK 16
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menutext_s graphics;
- menutext_s display;
- menutext_s sound;
- menutext_s network;
-
- menuslider_s brightness;
- menuslider_s screensize;
-
- menubitmap_s back;
-} displayOptionsInfo_t;
-
-static displayOptionsInfo_t displayOptionsInfo;
-
-
-/*
-=================
-UI_DisplayOptionsMenu_Event
-=================
-*/
-static void UI_DisplayOptionsMenu_Event( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_GRAPHICS:
- UI_PopMenu();
- UI_GraphicsOptionsMenu();
- break;
-
- case ID_DISPLAY:
- break;
-
- case ID_SOUND:
- UI_PopMenu();
- UI_SoundOptionsMenu();
- break;
-
- case ID_NETWORK:
- UI_PopMenu();
- UI_NetworkOptionsMenu();
- break;
-
- case ID_BRIGHTNESS:
- trap_Cvar_SetValue( "r_gamma", displayOptionsInfo.brightness.curvalue / 10.0f );
- break;
-
- case ID_SCREENSIZE:
- trap_Cvar_SetValue( "cg_viewsize", displayOptionsInfo.screensize.curvalue * 10 );
- break;
-
- case ID_BACK:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-===============
-UI_DisplayOptionsMenu_Init
-===============
-*/
-static void UI_DisplayOptionsMenu_Init( void ) {
- int y;
-
- memset( &displayOptionsInfo, 0, sizeof(displayOptionsInfo) );
-
- UI_DisplayOptionsMenu_Cache();
- displayOptionsInfo.menu.wrapAround = qtrue;
- displayOptionsInfo.menu.fullscreen = qtrue;
-
- displayOptionsInfo.banner.generic.type = MTYPE_BTEXT;
- displayOptionsInfo.banner.generic.flags = QMF_CENTER_JUSTIFY;
- displayOptionsInfo.banner.generic.x = 320;
- displayOptionsInfo.banner.generic.y = 16;
- displayOptionsInfo.banner.string = "SYSTEM SETUP";
- displayOptionsInfo.banner.color = color_white;
- displayOptionsInfo.banner.style = UI_CENTER;
-
- displayOptionsInfo.framel.generic.type = MTYPE_BITMAP;
- displayOptionsInfo.framel.generic.name = ART_FRAMEL;
- displayOptionsInfo.framel.generic.flags = QMF_INACTIVE;
- displayOptionsInfo.framel.generic.x = 0;
- displayOptionsInfo.framel.generic.y = 78;
- displayOptionsInfo.framel.width = 256;
- displayOptionsInfo.framel.height = 329;
-
- displayOptionsInfo.framer.generic.type = MTYPE_BITMAP;
- displayOptionsInfo.framer.generic.name = ART_FRAMER;
- displayOptionsInfo.framer.generic.flags = QMF_INACTIVE;
- displayOptionsInfo.framer.generic.x = 376;
- displayOptionsInfo.framer.generic.y = 76;
- displayOptionsInfo.framer.width = 256;
- displayOptionsInfo.framer.height = 334;
-
- displayOptionsInfo.graphics.generic.type = MTYPE_PTEXT;
- displayOptionsInfo.graphics.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- displayOptionsInfo.graphics.generic.id = ID_GRAPHICS;
- displayOptionsInfo.graphics.generic.callback = UI_DisplayOptionsMenu_Event;
- displayOptionsInfo.graphics.generic.x = 216;
- displayOptionsInfo.graphics.generic.y = 240 - 2 * PROP_HEIGHT;
- displayOptionsInfo.graphics.string = "GRAPHICS";
- displayOptionsInfo.graphics.style = UI_RIGHT;
- displayOptionsInfo.graphics.color = color_red;
-
- displayOptionsInfo.display.generic.type = MTYPE_PTEXT;
- displayOptionsInfo.display.generic.flags = QMF_RIGHT_JUSTIFY;
- displayOptionsInfo.display.generic.id = ID_DISPLAY;
- displayOptionsInfo.display.generic.callback = UI_DisplayOptionsMenu_Event;
- displayOptionsInfo.display.generic.x = 216;
- displayOptionsInfo.display.generic.y = 240 - PROP_HEIGHT;
- displayOptionsInfo.display.string = "DISPLAY";
- displayOptionsInfo.display.style = UI_RIGHT;
- displayOptionsInfo.display.color = color_red;
-
- displayOptionsInfo.sound.generic.type = MTYPE_PTEXT;
- displayOptionsInfo.sound.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- displayOptionsInfo.sound.generic.id = ID_SOUND;
- displayOptionsInfo.sound.generic.callback = UI_DisplayOptionsMenu_Event;
- displayOptionsInfo.sound.generic.x = 216;
- displayOptionsInfo.sound.generic.y = 240;
- displayOptionsInfo.sound.string = "SOUND";
- displayOptionsInfo.sound.style = UI_RIGHT;
- displayOptionsInfo.sound.color = color_red;
-
- displayOptionsInfo.network.generic.type = MTYPE_PTEXT;
- displayOptionsInfo.network.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- displayOptionsInfo.network.generic.id = ID_NETWORK;
- displayOptionsInfo.network.generic.callback = UI_DisplayOptionsMenu_Event;
- displayOptionsInfo.network.generic.x = 216;
- displayOptionsInfo.network.generic.y = 240 + PROP_HEIGHT;
- displayOptionsInfo.network.string = "NETWORK";
- displayOptionsInfo.network.style = UI_RIGHT;
- displayOptionsInfo.network.color = color_red;
-
- y = 240 - 1 * (BIGCHAR_HEIGHT+2);
- displayOptionsInfo.brightness.generic.type = MTYPE_SLIDER;
- displayOptionsInfo.brightness.generic.name = "Brightness:";
- displayOptionsInfo.brightness.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- displayOptionsInfo.brightness.generic.callback = UI_DisplayOptionsMenu_Event;
- displayOptionsInfo.brightness.generic.id = ID_BRIGHTNESS;
- displayOptionsInfo.brightness.generic.x = 400;
- displayOptionsInfo.brightness.generic.y = y;
- displayOptionsInfo.brightness.minvalue = 5;
- displayOptionsInfo.brightness.maxvalue = 20;
- if( !uis.glconfig.deviceSupportsGamma ) {
- displayOptionsInfo.brightness.generic.flags |= QMF_GRAYED;
- }
-
- y += BIGCHAR_HEIGHT+2;
- displayOptionsInfo.screensize.generic.type = MTYPE_SLIDER;
- displayOptionsInfo.screensize.generic.name = "Screen Size:";
- displayOptionsInfo.screensize.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- displayOptionsInfo.screensize.generic.callback = UI_DisplayOptionsMenu_Event;
- displayOptionsInfo.screensize.generic.id = ID_SCREENSIZE;
- displayOptionsInfo.screensize.generic.x = 400;
- displayOptionsInfo.screensize.generic.y = y;
- displayOptionsInfo.screensize.minvalue = 3;
- displayOptionsInfo.screensize.maxvalue = 10;
-
- displayOptionsInfo.back.generic.type = MTYPE_BITMAP;
- displayOptionsInfo.back.generic.name = ART_BACK0;
- displayOptionsInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- displayOptionsInfo.back.generic.callback = UI_DisplayOptionsMenu_Event;
- displayOptionsInfo.back.generic.id = ID_BACK;
- displayOptionsInfo.back.generic.x = 0;
- displayOptionsInfo.back.generic.y = 480-64;
- displayOptionsInfo.back.width = 128;
- displayOptionsInfo.back.height = 64;
- displayOptionsInfo.back.focuspic = ART_BACK1;
-
- Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.banner );
- Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.framel );
- Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.framer );
- Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.graphics );
- Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.display );
- Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.sound );
- Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.network );
- Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.brightness );
- Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.screensize );
- Menu_AddItem( &displayOptionsInfo.menu, ( void * ) &displayOptionsInfo.back );
-
- displayOptionsInfo.brightness.curvalue = trap_Cvar_VariableValue("r_gamma") * 10;
- displayOptionsInfo.screensize.curvalue = trap_Cvar_VariableValue( "cg_viewsize")/10;
-}
-
-
-/*
-===============
-UI_DisplayOptionsMenu_Cache
-===============
-*/
-void UI_DisplayOptionsMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
-}
-
-
-/*
-===============
-UI_DisplayOptionsMenu
-===============
-*/
-void UI_DisplayOptionsMenu( void ) {
- UI_DisplayOptionsMenu_Init();
- UI_PushMenu( &displayOptionsInfo.menu );
- Menu_SetCursorToItem( &displayOptionsInfo.menu, &displayOptionsInfo.display );
-}
diff --git a/engine/code/q3_ui/ui_gameinfo.c b/engine/code/q3_ui/ui_gameinfo.c
deleted file mode 100644
index d9deacd..0000000
--- a/engine/code/q3_ui/ui_gameinfo.c
+++ /dev/null
@@ -1,815 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-//
-// gameinfo.c
-//
-
-#include "ui_local.h"
-
-
-//
-// arena and bot info
-//
-
-#define POOLSIZE 128 * 1024
-
-int ui_numBots;
-static char *ui_botInfos[MAX_BOTS];
-
-static int ui_numArenas;
-static char *ui_arenaInfos[MAX_ARENAS];
-
-static int ui_numSinglePlayerArenas;
-static int ui_numSpecialSinglePlayerArenas;
-
-static char memoryPool[POOLSIZE];
-static int allocPoint, outOfMemory;
-
-
-/*
-===============
-UI_Alloc
-===============
-*/
-void *UI_Alloc( int size ) {
- char *p;
-
- if ( allocPoint + size > POOLSIZE ) {
- outOfMemory = qtrue;
- return NULL;
- }
-
- p = &memoryPool[allocPoint];
-
- allocPoint += ( size + 31 ) & ~31;
-
- return p;
-}
-
-/*
-===============
-UI_InitMemory
-===============
-*/
-void UI_InitMemory( void ) {
- allocPoint = 0;
- outOfMemory = qfalse;
-}
-
-/*
-===============
-UI_ParseInfos
-===============
-*/
-int UI_ParseInfos( char *buf, int max, char *infos[] ) {
- char *token;
- int count;
- char key[MAX_TOKEN_CHARS];
- char info[MAX_INFO_STRING];
-
- count = 0;
-
- while ( 1 ) {
- token = COM_Parse( &buf );
- if ( !token[0] ) {
- break;
- }
- if ( strcmp( token, "{" ) ) {
- Com_Printf( "Missing { in info file\n" );
- break;
- }
-
- if ( count == max ) {
- Com_Printf( "Max infos exceeded\n" );
- break;
- }
-
- info[0] = '\0';
- while ( 1 ) {
- token = COM_ParseExt( &buf, qtrue );
- if ( !token[0] ) {
- Com_Printf( "Unexpected end of info file\n" );
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- Q_strncpyz( key, token, sizeof( key ) );
-
- token = COM_ParseExt( &buf, qfalse );
- if ( !token[0] ) {
- strcpy( token, "<NULL>" );
- }
- Info_SetValueForKey( info, key, token );
- }
- //NOTE: extra space for arena number
- infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
- if (infos[count]) {
- strcpy(infos[count], info);
- count++;
- }
- }
- return count;
-}
-
-/*
-===============
-UI_LoadArenasFromFile
-===============
-*/
-static void UI_LoadArenasFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_ARENAS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_ARENAS_TEXT ) {
- trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_ARENAS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] );
-}
-
-/*
-===============
-UI_LoadArenas
-===============
-*/
-static void UI_LoadArenas( void ) {
- int numdirs;
- vmCvar_t arenasFile;
- char filename[128];
- char dirlist[2048];
- char* dirptr;
- int i, n;
- int dirlen;
- char *type;
- char *tag;
- int singlePlayerNum, specialNum, otherNum;
-
- ui_numArenas = 0;
-
- trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
- if( *arenasFile.string ) {
- UI_LoadArenasFromFile(arenasFile.string);
- }
- else {
- UI_LoadArenasFromFile("scripts/arenas.txt");
- }
-
- // get all arenas from .arena files
- numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 2048 );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- UI_LoadArenasFromFile(filename);
- }
- trap_Print( va( "%i arenas parsed\n", ui_numArenas ) );
- if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all arenas\n");
-
- // set initial numbers
- for( n = 0; n < ui_numArenas; n++ ) {
- Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", n ) );
- }
-
- // go through and count single players levels
- ui_numSinglePlayerArenas = 0;
- ui_numSpecialSinglePlayerArenas = 0;
- for( n = 0; n < ui_numArenas; n++ ) {
- // determine type
- type = Info_ValueForKey( ui_arenaInfos[n], "type" );
-
- // if no type specified, it will be treated as "ffa"
- if( !*type ) {
- continue;
- }
-
- if( strstr( type, "single" ) ) {
- // check for special single player arenas (training, final)
- tag = Info_ValueForKey( ui_arenaInfos[n], "special" );
- if( *tag ) {
- ui_numSpecialSinglePlayerArenas++;
- continue;
- }
-
- ui_numSinglePlayerArenas++;
- }
- }
-
- n = ui_numSinglePlayerArenas % ARENAS_PER_TIER;
- if( n != 0 ) {
- ui_numSinglePlayerArenas -= n;
- trap_Print( va( "%i arenas ignored to make count divisible by %i\n", n, ARENAS_PER_TIER ) );
- }
-
- // go through once more and assign number to the levels
- singlePlayerNum = 0;
- specialNum = singlePlayerNum + ui_numSinglePlayerArenas;
- otherNum = specialNum + ui_numSpecialSinglePlayerArenas;
- for( n = 0; n < ui_numArenas; n++ ) {
- // determine type
- type = Info_ValueForKey( ui_arenaInfos[n], "type" );
-
- // if no type specified, it will be treated as "ffa"
- if( *type ) {
- if( strstr( type, "single" ) ) {
- // check for special single player arenas (training, final)
- tag = Info_ValueForKey( ui_arenaInfos[n], "special" );
- if( *tag ) {
- Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", specialNum++ ) );
- continue;
- }
-
- Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", singlePlayerNum++ ) );
- continue;
- }
- }
-
- Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", otherNum++ ) );
- }
-}
-
-/*
-===============
-UI_GetArenaInfoByNumber
-===============
-*/
-const char *UI_GetArenaInfoByNumber( int num ) {
- int n;
- char *value;
-
- if( num < 0 || num >= ui_numArenas ) {
- trap_Print( va( S_COLOR_RED "Invalid arena number: %i\n", num ) );
- return NULL;
- }
-
- for( n = 0; n < ui_numArenas; n++ ) {
- value = Info_ValueForKey( ui_arenaInfos[n], "num" );
- if( *value && atoi(value) == num ) {
- return ui_arenaInfos[n];
- }
- }
-
- return NULL;
-}
-
-
-/*
-===============
-UI_GetArenaInfoByNumber
-===============
-*/
-const char *UI_GetArenaInfoByMap( const char *map ) {
- int n;
-
- for( n = 0; n < ui_numArenas; n++ ) {
- if( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], "map" ), map ) == 0 ) {
- return ui_arenaInfos[n];
- }
- }
-
- return NULL;
-}
-
-
-/*
-===============
-UI_GetSpecialArenaInfo
-===============
-*/
-const char *UI_GetSpecialArenaInfo( const char *tag ) {
- int n;
-
- for( n = 0; n < ui_numArenas; n++ ) {
- if( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], "special" ), tag ) == 0 ) {
- return ui_arenaInfos[n];
- }
- }
-
- return NULL;
-}
-
-/*
-===============
-UI_LoadBotsFromFile
-===============
-*/
-static void UI_LoadBotsFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_BOTS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_BOTS_TEXT ) {
- trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- ui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] );
- if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all bots\n");
-}
-
-/*
-===============
-UI_LoadBots
-===============
-*/
-static void UI_LoadBots( void ) {
- vmCvar_t botsFile;
- int numdirs;
- char filename[128];
- char dirlist[1024];
- char* dirptr;
- int i;
- int dirlen;
-
- ui_numBots = 0;
-
- trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
- if( *botsFile.string ) {
- UI_LoadBotsFromFile(botsFile.string);
- }
- else {
- UI_LoadBotsFromFile("scripts/bots.txt");
- }
-
- // get all bots from .bot files
- numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- UI_LoadBotsFromFile(filename);
- }
- trap_Print( va( "%i bots parsed\n", ui_numBots ) );
-}
-
-
-/*
-===============
-UI_GetBotInfoByNumber
-===============
-*/
-char *UI_GetBotInfoByNumber( int num ) {
- if( num < 0 || num >= ui_numBots ) {
- trap_Print( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
- return NULL;
- }
- return ui_botInfos[num];
-}
-
-
-/*
-===============
-UI_GetBotInfoByName
-===============
-*/
-char *UI_GetBotInfoByName( const char *name ) {
- int n;
- char *value;
-
- for ( n = 0; n < ui_numBots ; n++ ) {
- value = Info_ValueForKey( ui_botInfos[n], "name" );
- if ( !Q_stricmp( value, name ) ) {
- return ui_botInfos[n];
- }
- }
-
- return NULL;
-}
-
-
-//
-// single player game info
-//
-
-/*
-===============
-UI_GetBestScore
-
-Returns the player's best finish on a given level, 0 if the have not played the level
-===============
-*/
-void UI_GetBestScore( int level, int *score, int *skill ) {
- int n;
- int skillScore;
- int bestScore;
- int bestScoreSkill;
- char arenaKey[16];
- char scores[MAX_INFO_VALUE];
-
- if( !score || !skill ) {
- return;
- }
-
- if( level < 0 || level > ui_numArenas ) {
- return;
- }
-
- bestScore = 0;
- bestScoreSkill = 0;
-
- for( n = 1; n <= 5; n++ ) {
- trap_Cvar_VariableStringBuffer( va( "g_spScores%i", n ), scores, MAX_INFO_VALUE );
-
- Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
- skillScore = atoi( Info_ValueForKey( scores, arenaKey ) );
-
- if( skillScore < 1 || skillScore > 8 ) {
- continue;
- }
-
- if( !bestScore || skillScore <= bestScore ) {
- bestScore = skillScore;
- bestScoreSkill = n;
- }
- }
-
- *score = bestScore;
- *skill = bestScoreSkill;
-}
-
-
-/*
-===============
-UI_SetBestScore
-
-Set the player's best finish for a level
-===============
-*/
-void UI_SetBestScore( int level, int score ) {
- int skill;
- int oldScore;
- char arenaKey[16];
- char scores[MAX_INFO_VALUE];
-
- // validate score
- if( score < 1 || score > 8 ) {
- return;
- }
-
- // validate skill
- skill = (int)trap_Cvar_VariableValue( "g_spSkill" );
- if( skill < 1 || skill > 5 ) {
- return;
- }
-
- // get scores
- trap_Cvar_VariableStringBuffer( va( "g_spScores%i", skill ), scores, MAX_INFO_VALUE );
-
- // see if this is better
- Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
- oldScore = atoi( Info_ValueForKey( scores, arenaKey ) );
- if( oldScore && oldScore <= score ) {
- return;
- }
-
- // update scores
- Info_SetValueForKey( scores, arenaKey, va( "%i", score ) );
- trap_Cvar_Set( va( "g_spScores%i", skill ), scores );
-}
-
-
-/*
-===============
-UI_LogAwardData
-===============
-*/
-void UI_LogAwardData( int award, int data ) {
- char key[16];
- char awardData[MAX_INFO_VALUE];
- int oldValue;
-
- if( data == 0 ) {
- return;
- }
-
- if( award > AWARD_PERFECT ) {
- trap_Print( va( S_COLOR_RED "Bad award %i in UI_LogAwardData\n", award ) );
- return;
- }
-
- trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, sizeof(awardData) );
-
- Com_sprintf( key, sizeof(key), "a%i", award );
- oldValue = atoi( Info_ValueForKey( awardData, key ) );
-
- Info_SetValueForKey( awardData, key, va( "%i", oldValue + data ) );
- trap_Cvar_Set( "g_spAwards", awardData );
-}
-
-
-/*
-===============
-UI_GetAwardLevel
-===============
-*/
-int UI_GetAwardLevel( int award ) {
- char key[16];
- char awardData[MAX_INFO_VALUE];
-
- trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, sizeof(awardData) );
-
- Com_sprintf( key, sizeof(key), "a%i", award );
- return atoi( Info_ValueForKey( awardData, key ) );
-}
-
-
-/*
-===============
-UI_TierCompleted
-===============
-*/
-int UI_TierCompleted( int levelWon ) {
- int level;
- int n;
- int tier;
- int score;
- int skill;
- const char *info;
-
- tier = levelWon / ARENAS_PER_TIER;
- level = tier * ARENAS_PER_TIER;
-
- if( tier == UI_GetNumSPTiers() ) {
- info = UI_GetSpecialArenaInfo( "training" );
- if( levelWon == atoi( Info_ValueForKey( info, "num" ) ) ) {
- return 0;
- }
- info = UI_GetSpecialArenaInfo( "final" );
- if( !info || levelWon == atoi( Info_ValueForKey( info, "num" ) ) ) {
- return tier + 1;
- }
- return -1;
- }
-
- for( n = 0; n < ARENAS_PER_TIER; n++, level++ ) {
- UI_GetBestScore( level, &score, &skill );
- if ( score != 1 ) {
- return -1;
- }
- }
- return tier + 1;
-}
-
-
-/*
-===============
-UI_ShowTierVideo
-===============
-*/
-qboolean UI_ShowTierVideo( int tier ) {
- char key[16];
- char videos[MAX_INFO_VALUE];
-
- if( tier <= 0 ) {
- return qfalse;
- }
-
- trap_Cvar_VariableStringBuffer( "g_spVideos", videos, sizeof(videos) );
-
- Com_sprintf( key, sizeof(key), "tier%i", tier );
- if( atoi( Info_ValueForKey( videos, key ) ) ) {
- return qfalse;
- }
-
- Info_SetValueForKey( videos, key, va( "%i", 1 ) );
- trap_Cvar_Set( "g_spVideos", videos );
-
- return qtrue;
-}
-
-
-/*
-===============
-UI_CanShowTierVideo
-===============
-*/
-qboolean UI_CanShowTierVideo( int tier ) {
- char key[16];
- char videos[MAX_INFO_VALUE];
-
- if( !tier ) {
- return qfalse;
- }
-
- if( uis.demoversion && tier != 8 ) {
- return qfalse;
- }
-
- trap_Cvar_VariableStringBuffer( "g_spVideos", videos, sizeof(videos) );
-
- Com_sprintf( key, sizeof(key), "tier%i", tier );
- if( atoi( Info_ValueForKey( videos, key ) ) ) {
- return qtrue;
- }
-
- return qfalse;
-}
-
-
-/*
-===============
-UI_GetCurrentGame
-
-Returns the next level the player has not won
-===============
-*/
-int UI_GetCurrentGame( void ) {
- int level;
- int rank;
- int skill;
- const char *info;
-
- info = UI_GetSpecialArenaInfo( "training" );
- if( info ) {
- level = atoi( Info_ValueForKey( info, "num" ) );
- UI_GetBestScore( level, &rank, &skill );
- if ( !rank || rank > 1 ) {
- return level;
- }
- }
-
- for( level = 0; level < ui_numSinglePlayerArenas; level++ ) {
- UI_GetBestScore( level, &rank, &skill );
- if ( !rank || rank > 1 ) {
- return level;
- }
- }
-
- info = UI_GetSpecialArenaInfo( "final" );
- if( !info ) {
- return -1;
- }
- return atoi( Info_ValueForKey( info, "num" ) );
-}
-
-
-/*
-===============
-UI_NewGame
-
-Clears the scores and sets the difficutly level
-===============
-*/
-void UI_NewGame( void ) {
- trap_Cvar_Set( "g_spScores1", "" );
- trap_Cvar_Set( "g_spScores2", "" );
- trap_Cvar_Set( "g_spScores3", "" );
- trap_Cvar_Set( "g_spScores4", "" );
- trap_Cvar_Set( "g_spScores5", "" );
- trap_Cvar_Set( "g_spAwards", "" );
- trap_Cvar_Set( "g_spVideos", "" );
-}
-
-
-/*
-===============
-UI_GetNumArenas
-===============
-*/
-int UI_GetNumArenas( void ) {
- return ui_numArenas;
-}
-
-
-/*
-===============
-UI_GetNumSPArenas
-===============
-*/
-int UI_GetNumSPArenas( void ) {
- return ui_numSinglePlayerArenas;
-}
-
-
-/*
-===============
-UI_GetNumSPTiers
-===============
-*/
-int UI_GetNumSPTiers( void ) {
- return ui_numSinglePlayerArenas / ARENAS_PER_TIER;
-}
-
-
-/*
-===============
-UI_GetNumBots
-===============
-*/
-int UI_GetNumBots( void ) {
- return ui_numBots;
-}
-
-
-/*
-===============
-UI_SPUnlock_f
-===============
-*/
-void UI_SPUnlock_f( void ) {
- char arenaKey[16];
- char scores[MAX_INFO_VALUE];
- int level;
- int tier;
-
- // get scores for skill 1
- trap_Cvar_VariableStringBuffer( "g_spScores1", scores, MAX_INFO_VALUE );
-
- // update scores
- for( level = 0; level < ui_numSinglePlayerArenas + ui_numSpecialSinglePlayerArenas; level++ ) {
- Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
- Info_SetValueForKey( scores, arenaKey, "1" );
- }
- trap_Cvar_Set( "g_spScores1", scores );
-
- // unlock cinematics
- for( tier = 1; tier <= 8; tier++ ) {
- UI_ShowTierVideo( tier );
- }
-
- trap_Print( "All levels unlocked at skill level 1\n" );
-
- UI_SPLevelMenu_ReInit();
-}
-
-
-/*
-===============
-UI_SPUnlockMedals_f
-===============
-*/
-void UI_SPUnlockMedals_f( void ) {
- int n;
- char key[16];
- char awardData[MAX_INFO_VALUE];
-
- trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, MAX_INFO_VALUE );
-
- for( n = 0; n < 6; n++ ) {
- Com_sprintf( key, sizeof(key), "a%i", n );
- Info_SetValueForKey( awardData, key, "100" );
- }
-
- trap_Cvar_Set( "g_spAwards", awardData );
-
- trap_Print( "All levels unlocked at 100\n" );
-}
-
-
-/*
-===============
-UI_InitGameinfo
-===============
-*/
-void UI_InitGameinfo( void ) {
-
- UI_InitMemory();
- UI_LoadArenas();
- UI_LoadBots();
-
- uis.demoversion = qfalse;
-}
diff --git a/engine/code/q3_ui/ui_ingame.c b/engine/code/q3_ui/ui_ingame.c
deleted file mode 100644
index b687162..0000000
--- a/engine/code/q3_ui/ui_ingame.c
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-INGAME MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define INGAME_FRAME "menu/art/addbotframe"
-//#define INGAME_FRAME "menu/art/cut_frame"
-#define INGAME_MENU_VERTICAL_SPACING 28
-
-#define ID_TEAM 10
-#define ID_ADDBOTS 11
-#define ID_REMOVEBOTS 12
-#define ID_SETUP 13
-#define ID_SERVERINFO 14
-#define ID_LEAVEARENA 15
-#define ID_RESTART 16
-#define ID_QUIT 17
-#define ID_RESUME 18
-#define ID_TEAMORDERS 19
-
-
-typedef struct {
- menuframework_s menu;
-
- menubitmap_s frame;
- menutext_s team;
- menutext_s setup;
- menutext_s server;
- menutext_s leave;
- menutext_s restart;
- menutext_s addbots;
- menutext_s removebots;
- menutext_s teamorders;
- menutext_s quit;
- menutext_s resume;
-} ingamemenu_t;
-
-static ingamemenu_t s_ingame;
-
-
-/*
-=================
-InGame_RestartAction
-=================
-*/
-static void InGame_RestartAction( qboolean result ) {
- if( !result ) {
- return;
- }
-
- UI_PopMenu();
- trap_Cmd_ExecuteText( EXEC_APPEND, "map_restart 0\n" );
-}
-
-
-/*
-=================
-InGame_QuitAction
-=================
-*/
-static void InGame_QuitAction( qboolean result ) {
- if( !result ) {
- return;
- }
- UI_PopMenu();
- UI_CreditMenu();
-}
-
-
-/*
-=================
-InGame_Event
-=================
-*/
-void InGame_Event( void *ptr, int notification ) {
- if( notification != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_TEAM:
- UI_TeamMainMenu();
- break;
-
- case ID_SETUP:
- UI_SetupMenu();
- break;
-
- case ID_LEAVEARENA:
- trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" );
- break;
-
- case ID_RESTART:
- UI_ConfirmMenu( "RESTART ARENA?", 0, InGame_RestartAction );
- break;
-
- case ID_QUIT:
- UI_ConfirmMenu( "EXIT GAME?", 0, InGame_QuitAction );
- break;
-
- case ID_SERVERINFO:
- UI_ServerInfoMenu();
- break;
-
- case ID_ADDBOTS:
- UI_AddBotsMenu();
- break;
-
- case ID_REMOVEBOTS:
- UI_RemoveBotsMenu();
- break;
-
- case ID_TEAMORDERS:
- UI_TeamOrdersMenu();
- break;
-
- case ID_RESUME:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-=================
-InGame_MenuInit
-=================
-*/
-void InGame_MenuInit( void ) {
- int y;
- uiClientState_t cs;
- char info[MAX_INFO_STRING];
- int team;
-
- memset( &s_ingame, 0 ,sizeof(ingamemenu_t) );
-
- InGame_Cache();
-
- s_ingame.menu.wrapAround = qtrue;
- s_ingame.menu.fullscreen = qfalse;
-
- s_ingame.frame.generic.type = MTYPE_BITMAP;
- s_ingame.frame.generic.flags = QMF_INACTIVE;
- s_ingame.frame.generic.name = INGAME_FRAME;
- s_ingame.frame.generic.x = 320-233;//142;
- s_ingame.frame.generic.y = 240-166;//118;
- s_ingame.frame.width = 466;//359;
- s_ingame.frame.height = 332;//256;
-
- //y = 96;
- y = 88;
- s_ingame.team.generic.type = MTYPE_PTEXT;
- s_ingame.team.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_ingame.team.generic.x = 320;
- s_ingame.team.generic.y = y;
- s_ingame.team.generic.id = ID_TEAM;
- s_ingame.team.generic.callback = InGame_Event;
- s_ingame.team.string = "START";
- s_ingame.team.color = color_red;
- s_ingame.team.style = UI_CENTER|UI_SMALLFONT;
-
- y += INGAME_MENU_VERTICAL_SPACING;
- s_ingame.addbots.generic.type = MTYPE_PTEXT;
- s_ingame.addbots.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_ingame.addbots.generic.x = 320;
- s_ingame.addbots.generic.y = y;
- s_ingame.addbots.generic.id = ID_ADDBOTS;
- s_ingame.addbots.generic.callback = InGame_Event;
- s_ingame.addbots.string = "ADD BOTS";
- s_ingame.addbots.color = color_red;
- s_ingame.addbots.style = UI_CENTER|UI_SMALLFONT;
- if( !trap_Cvar_VariableValue( "sv_running" ) || !trap_Cvar_VariableValue( "bot_enable" ) || (trap_Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER)) {
- s_ingame.addbots.generic.flags |= QMF_GRAYED;
- }
-
- y += INGAME_MENU_VERTICAL_SPACING;
- s_ingame.removebots.generic.type = MTYPE_PTEXT;
- s_ingame.removebots.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_ingame.removebots.generic.x = 320;
- s_ingame.removebots.generic.y = y;
- s_ingame.removebots.generic.id = ID_REMOVEBOTS;
- s_ingame.removebots.generic.callback = InGame_Event;
- s_ingame.removebots.string = "REMOVE BOTS";
- s_ingame.removebots.color = color_red;
- s_ingame.removebots.style = UI_CENTER|UI_SMALLFONT;
- if( !trap_Cvar_VariableValue( "sv_running" ) || !trap_Cvar_VariableValue( "bot_enable" ) || (trap_Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER)) {
- s_ingame.removebots.generic.flags |= QMF_GRAYED;
- }
-
- y += INGAME_MENU_VERTICAL_SPACING;
- s_ingame.teamorders.generic.type = MTYPE_PTEXT;
- s_ingame.teamorders.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_ingame.teamorders.generic.x = 320;
- s_ingame.teamorders.generic.y = y;
- s_ingame.teamorders.generic.id = ID_TEAMORDERS;
- s_ingame.teamorders.generic.callback = InGame_Event;
- s_ingame.teamorders.string = "TEAM ORDERS";
- s_ingame.teamorders.color = color_red;
- s_ingame.teamorders.style = UI_CENTER|UI_SMALLFONT;
- if( !(trap_Cvar_VariableValue( "g_gametype" ) >= GT_TEAM) ) {
- s_ingame.teamorders.generic.flags |= QMF_GRAYED;
- }
- else {
- trap_GetClientState( &cs );
- trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );
- team = atoi( Info_ValueForKey( info, "t" ) );
- if( team == TEAM_SPECTATOR ) {
- s_ingame.teamorders.generic.flags |= QMF_GRAYED;
- }
- }
-
- y += INGAME_MENU_VERTICAL_SPACING;
- s_ingame.setup.generic.type = MTYPE_PTEXT;
- s_ingame.setup.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_ingame.setup.generic.x = 320;
- s_ingame.setup.generic.y = y;
- s_ingame.setup.generic.id = ID_SETUP;
- s_ingame.setup.generic.callback = InGame_Event;
- s_ingame.setup.string = "SETUP";
- s_ingame.setup.color = color_red;
- s_ingame.setup.style = UI_CENTER|UI_SMALLFONT;
-
- y += INGAME_MENU_VERTICAL_SPACING;
- s_ingame.server.generic.type = MTYPE_PTEXT;
- s_ingame.server.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_ingame.server.generic.x = 320;
- s_ingame.server.generic.y = y;
- s_ingame.server.generic.id = ID_SERVERINFO;
- s_ingame.server.generic.callback = InGame_Event;
- s_ingame.server.string = "SERVER INFO";
- s_ingame.server.color = color_red;
- s_ingame.server.style = UI_CENTER|UI_SMALLFONT;
-
- y += INGAME_MENU_VERTICAL_SPACING;
- s_ingame.restart.generic.type = MTYPE_PTEXT;
- s_ingame.restart.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_ingame.restart.generic.x = 320;
- s_ingame.restart.generic.y = y;
- s_ingame.restart.generic.id = ID_RESTART;
- s_ingame.restart.generic.callback = InGame_Event;
- s_ingame.restart.string = "RESTART ARENA";
- s_ingame.restart.color = color_red;
- s_ingame.restart.style = UI_CENTER|UI_SMALLFONT;
- if( !trap_Cvar_VariableValue( "sv_running" ) ) {
- s_ingame.restart.generic.flags |= QMF_GRAYED;
- }
-
- y += INGAME_MENU_VERTICAL_SPACING;
- s_ingame.resume.generic.type = MTYPE_PTEXT;
- s_ingame.resume.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_ingame.resume.generic.x = 320;
- s_ingame.resume.generic.y = y;
- s_ingame.resume.generic.id = ID_RESUME;
- s_ingame.resume.generic.callback = InGame_Event;
- s_ingame.resume.string = "RESUME GAME";
- s_ingame.resume.color = color_red;
- s_ingame.resume.style = UI_CENTER|UI_SMALLFONT;
-
- y += INGAME_MENU_VERTICAL_SPACING;
- s_ingame.leave.generic.type = MTYPE_PTEXT;
- s_ingame.leave.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_ingame.leave.generic.x = 320;
- s_ingame.leave.generic.y = y;
- s_ingame.leave.generic.id = ID_LEAVEARENA;
- s_ingame.leave.generic.callback = InGame_Event;
- s_ingame.leave.string = "LEAVE ARENA";
- s_ingame.leave.color = color_red;
- s_ingame.leave.style = UI_CENTER|UI_SMALLFONT;
-
- y += INGAME_MENU_VERTICAL_SPACING;
- s_ingame.quit.generic.type = MTYPE_PTEXT;
- s_ingame.quit.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_ingame.quit.generic.x = 320;
- s_ingame.quit.generic.y = y;
- s_ingame.quit.generic.id = ID_QUIT;
- s_ingame.quit.generic.callback = InGame_Event;
- s_ingame.quit.string = "EXIT GAME";
- s_ingame.quit.color = color_red;
- s_ingame.quit.style = UI_CENTER|UI_SMALLFONT;
-
- Menu_AddItem( &s_ingame.menu, &s_ingame.frame );
- Menu_AddItem( &s_ingame.menu, &s_ingame.team );
- Menu_AddItem( &s_ingame.menu, &s_ingame.addbots );
- Menu_AddItem( &s_ingame.menu, &s_ingame.removebots );
- Menu_AddItem( &s_ingame.menu, &s_ingame.teamorders );
- Menu_AddItem( &s_ingame.menu, &s_ingame.setup );
- Menu_AddItem( &s_ingame.menu, &s_ingame.server );
- Menu_AddItem( &s_ingame.menu, &s_ingame.restart );
- Menu_AddItem( &s_ingame.menu, &s_ingame.resume );
- Menu_AddItem( &s_ingame.menu, &s_ingame.leave );
- Menu_AddItem( &s_ingame.menu, &s_ingame.quit );
-}
-
-
-/*
-=================
-InGame_Cache
-=================
-*/
-void InGame_Cache( void ) {
- trap_R_RegisterShaderNoMip( INGAME_FRAME );
-}
-
-
-/*
-=================
-UI_InGameMenu
-=================
-*/
-void UI_InGameMenu( void ) {
- // force as top level menu
- uis.menusp = 0;
-
- // set menu cursor to a nice location
- uis.cursorx = 319;
- uis.cursory = 80;
-
- InGame_MenuInit();
- UI_PushMenu( &s_ingame.menu );
-}
diff --git a/engine/code/q3_ui/ui_loadconfig.c b/engine/code/q3_ui/ui_loadconfig.c
deleted file mode 100644
index ef7ae41..0000000
--- a/engine/code/q3_ui/ui_loadconfig.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=============================================================================
-
-LOAD CONFIG MENU
-
-=============================================================================
-*/
-
-#include "ui_local.h"
-
-
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-#define ART_FIGHT0 "menu/art/load_0"
-#define ART_FIGHT1 "menu/art/load_1"
-#define ART_FRAMEL "menu/art/frame2_l"
-#define ART_FRAMER "menu/art/frame1_r"
-#define ART_ARROWS "menu/art/arrows_horz_0"
-#define ART_ARROWLEFT "menu/art/arrows_horz_left"
-#define ART_ARROWRIGHT "menu/art/arrows_horz_right"
-
-#define MAX_CONFIGS 128
-#define NAMEBUFSIZE ( MAX_CONFIGS * 16 )
-
-#define ID_BACK 10
-#define ID_GO 11
-#define ID_LIST 12
-#define ID_LEFT 13
-#define ID_RIGHT 14
-
-#define ARROWS_WIDTH 128
-#define ARROWS_HEIGHT 48
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menulist_s list;
-
- menubitmap_s arrows;
- menubitmap_s left;
- menubitmap_s right;
- menubitmap_s back;
- menubitmap_s go;
-
- char names[NAMEBUFSIZE];
- char* configlist[MAX_CONFIGS];
-} configs_t;
-
-static configs_t s_configs;
-
-
-/*
-===============
-LoadConfig_MenuEvent
-===============
-*/
-static void LoadConfig_MenuEvent( void *ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch ( ((menucommon_s*)ptr)->id ) {
- case ID_GO:
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "exec %s\n", s_configs.list.itemnames[s_configs.list.curvalue] ) );
- UI_PopMenu();
- break;
-
- case ID_BACK:
- UI_PopMenu();
- break;
-
- case ID_LEFT:
- ScrollList_Key( &s_configs.list, K_LEFTARROW );
- break;
-
- case ID_RIGHT:
- ScrollList_Key( &s_configs.list, K_RIGHTARROW );
- break;
- }
-}
-
-
-/*
-===============
-LoadConfig_MenuInit
-===============
-*/
-static void LoadConfig_MenuInit( void ) {
- int i;
- int len;
- char *configname;
-
- UI_LoadConfig_Cache();
-
- memset( &s_configs, 0 ,sizeof(configs_t) );
- s_configs.menu.wrapAround = qtrue;
- s_configs.menu.fullscreen = qtrue;
-
- s_configs.banner.generic.type = MTYPE_BTEXT;
- s_configs.banner.generic.x = 320;
- s_configs.banner.generic.y = 16;
- s_configs.banner.string = "LOAD CONFIG";
- s_configs.banner.color = color_white;
- s_configs.banner.style = UI_CENTER;
-
- s_configs.framel.generic.type = MTYPE_BITMAP;
- s_configs.framel.generic.name = ART_FRAMEL;
- s_configs.framel.generic.flags = QMF_INACTIVE;
- s_configs.framel.generic.x = 0;
- s_configs.framel.generic.y = 78;
- s_configs.framel.width = 256;
- s_configs.framel.height = 329;
-
- s_configs.framer.generic.type = MTYPE_BITMAP;
- s_configs.framer.generic.name = ART_FRAMER;
- s_configs.framer.generic.flags = QMF_INACTIVE;
- s_configs.framer.generic.x = 376;
- s_configs.framer.generic.y = 76;
- s_configs.framer.width = 256;
- s_configs.framer.height = 334;
-
- s_configs.arrows.generic.type = MTYPE_BITMAP;
- s_configs.arrows.generic.name = ART_ARROWS;
- s_configs.arrows.generic.flags = QMF_INACTIVE;
- s_configs.arrows.generic.x = 320-ARROWS_WIDTH/2;
- s_configs.arrows.generic.y = 400;
- s_configs.arrows.width = ARROWS_WIDTH;
- s_configs.arrows.height = ARROWS_HEIGHT;
-
- s_configs.left.generic.type = MTYPE_BITMAP;
- s_configs.left.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
- s_configs.left.generic.x = 320-ARROWS_WIDTH/2;
- s_configs.left.generic.y = 400;
- s_configs.left.generic.id = ID_LEFT;
- s_configs.left.generic.callback = LoadConfig_MenuEvent;
- s_configs.left.width = ARROWS_WIDTH/2;
- s_configs.left.height = ARROWS_HEIGHT;
- s_configs.left.focuspic = ART_ARROWLEFT;
-
- s_configs.right.generic.type = MTYPE_BITMAP;
- s_configs.right.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
- s_configs.right.generic.x = 320;
- s_configs.right.generic.y = 400;
- s_configs.right.generic.id = ID_RIGHT;
- s_configs.right.generic.callback = LoadConfig_MenuEvent;
- s_configs.right.width = ARROWS_WIDTH/2;
- s_configs.right.height = ARROWS_HEIGHT;
- s_configs.right.focuspic = ART_ARROWRIGHT;
-
- s_configs.back.generic.type = MTYPE_BITMAP;
- s_configs.back.generic.name = ART_BACK0;
- s_configs.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_configs.back.generic.id = ID_BACK;
- s_configs.back.generic.callback = LoadConfig_MenuEvent;
- s_configs.back.generic.x = 0;
- s_configs.back.generic.y = 480-64;
- s_configs.back.width = 128;
- s_configs.back.height = 64;
- s_configs.back.focuspic = ART_BACK1;
-
- s_configs.go.generic.type = MTYPE_BITMAP;
- s_configs.go.generic.name = ART_FIGHT0;
- s_configs.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_configs.go.generic.id = ID_GO;
- s_configs.go.generic.callback = LoadConfig_MenuEvent;
- s_configs.go.generic.x = 640;
- s_configs.go.generic.y = 480-64;
- s_configs.go.width = 128;
- s_configs.go.height = 64;
- s_configs.go.focuspic = ART_FIGHT1;
-
- // scan for configs
- s_configs.list.generic.type = MTYPE_SCROLLLIST;
- s_configs.list.generic.flags = QMF_PULSEIFFOCUS;
- s_configs.list.generic.callback = LoadConfig_MenuEvent;
- s_configs.list.generic.id = ID_LIST;
- s_configs.list.generic.x = 118;
- s_configs.list.generic.y = 130;
- s_configs.list.width = 16;
- s_configs.list.height = 14;
- s_configs.list.numitems = trap_FS_GetFileList( "", "cfg", s_configs.names, NAMEBUFSIZE );
- s_configs.list.itemnames = (const char **)s_configs.configlist;
- s_configs.list.columns = 3;
-
- if (!s_configs.list.numitems) {
- strcpy(s_configs.names,"No Files Found.");
- s_configs.list.numitems = 1;
-
- //degenerate case, not selectable
- s_configs.go.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- }
- else if (s_configs.list.numitems > MAX_CONFIGS)
- s_configs.list.numitems = MAX_CONFIGS;
-
- configname = s_configs.names;
- for ( i = 0; i < s_configs.list.numitems; i++ ) {
- s_configs.list.itemnames[i] = configname;
-
- // strip extension
- len = strlen( configname );
- if (!Q_stricmp(configname + len - 4,".cfg"))
- configname[len-4] = '\0';
-
- Q_strupr(configname);
-
- configname += len + 1;
- }
-
- Menu_AddItem( &s_configs.menu, &s_configs.banner );
- Menu_AddItem( &s_configs.menu, &s_configs.framel );
- Menu_AddItem( &s_configs.menu, &s_configs.framer );
- Menu_AddItem( &s_configs.menu, &s_configs.list );
- Menu_AddItem( &s_configs.menu, &s_configs.arrows );
- Menu_AddItem( &s_configs.menu, &s_configs.left );
- Menu_AddItem( &s_configs.menu, &s_configs.right );
- Menu_AddItem( &s_configs.menu, &s_configs.back );
- Menu_AddItem( &s_configs.menu, &s_configs.go );
-}
-
-/*
-=================
-UI_LoadConfig_Cache
-=================
-*/
-void UI_LoadConfig_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_FIGHT0 );
- trap_R_RegisterShaderNoMip( ART_FIGHT1 );
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
- trap_R_RegisterShaderNoMip( ART_ARROWS );
- trap_R_RegisterShaderNoMip( ART_ARROWLEFT );
- trap_R_RegisterShaderNoMip( ART_ARROWRIGHT );
-}
-
-
-/*
-===============
-UI_LoadConfigMenu
-===============
-*/
-void UI_LoadConfigMenu( void ) {
- LoadConfig_MenuInit();
- UI_PushMenu( &s_configs.menu );
-}
-
diff --git a/engine/code/q3_ui/ui_local.h b/engine/code/q3_ui/ui_local.h
deleted file mode 100644
index 464298e..0000000
--- a/engine/code/q3_ui/ui_local.h
+++ /dev/null
@@ -1,802 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#ifndef __UI_LOCAL_H__
-#define __UI_LOCAL_H__
-
-#include "../qcommon/q_shared.h"
-#include "../renderer/tr_types.h"
-//NOTE: include the ui_public.h from the new UI
-#include "../ui/ui_public.h"
-//redefine to old API version
-#undef UI_API_VERSION
-#define UI_API_VERSION 4
-#include "../client/keycodes.h"
-#include "../game/bg_public.h"
-
-typedef void (*voidfunc_f)(void);
-
-extern vmCvar_t ui_ffa_fraglimit;
-extern vmCvar_t ui_ffa_timelimit;
-
-extern vmCvar_t ui_tourney_fraglimit;
-extern vmCvar_t ui_tourney_timelimit;
-
-extern vmCvar_t ui_team_fraglimit;
-extern vmCvar_t ui_team_timelimit;
-extern vmCvar_t ui_team_friendly;
-
-extern vmCvar_t ui_ctf_capturelimit;
-extern vmCvar_t ui_ctf_timelimit;
-extern vmCvar_t ui_ctf_friendly;
-
-extern vmCvar_t ui_arenasFile;
-extern vmCvar_t ui_botsFile;
-extern vmCvar_t ui_spScores1;
-extern vmCvar_t ui_spScores2;
-extern vmCvar_t ui_spScores3;
-extern vmCvar_t ui_spScores4;
-extern vmCvar_t ui_spScores5;
-extern vmCvar_t ui_spAwards;
-extern vmCvar_t ui_spVideos;
-extern vmCvar_t ui_spSkill;
-
-extern vmCvar_t ui_spSelection;
-
-extern vmCvar_t ui_browserMaster;
-extern vmCvar_t ui_browserGameType;
-extern vmCvar_t ui_browserSortKey;
-extern vmCvar_t ui_browserShowFull;
-extern vmCvar_t ui_browserShowEmpty;
-
-extern vmCvar_t ui_brassTime;
-extern vmCvar_t ui_drawCrosshair;
-extern vmCvar_t ui_drawCrosshairNames;
-extern vmCvar_t ui_marks;
-
-extern vmCvar_t ui_server1;
-extern vmCvar_t ui_server2;
-extern vmCvar_t ui_server3;
-extern vmCvar_t ui_server4;
-extern vmCvar_t ui_server5;
-extern vmCvar_t ui_server6;
-extern vmCvar_t ui_server7;
-extern vmCvar_t ui_server8;
-extern vmCvar_t ui_server9;
-extern vmCvar_t ui_server10;
-extern vmCvar_t ui_server11;
-extern vmCvar_t ui_server12;
-extern vmCvar_t ui_server13;
-extern vmCvar_t ui_server14;
-extern vmCvar_t ui_server15;
-extern vmCvar_t ui_server16;
-
-extern vmCvar_t ui_cdkey;
-extern vmCvar_t ui_cdkeychecked;
-extern vmCvar_t ui_ioq3;
-
-
-//
-// ui_qmenu.c
-//
-
-#define RCOLUMN_OFFSET ( BIGCHAR_WIDTH )
-#define LCOLUMN_OFFSET (-BIGCHAR_WIDTH )
-
-#define SLIDER_RANGE 10
-#define MAX_EDIT_LINE 256
-
-#define MAX_MENUDEPTH 8
-#define MAX_MENUITEMS 64
-
-#define MTYPE_NULL 0
-#define MTYPE_SLIDER 1
-#define MTYPE_ACTION 2
-#define MTYPE_SPINCONTROL 3
-#define MTYPE_FIELD 4
-#define MTYPE_RADIOBUTTON 5
-#define MTYPE_BITMAP 6
-#define MTYPE_TEXT 7
-#define MTYPE_SCROLLLIST 8
-#define MTYPE_PTEXT 9
-#define MTYPE_BTEXT 10
-
-#define QMF_BLINK ((unsigned int) 0x00000001)
-#define QMF_SMALLFONT ((unsigned int) 0x00000002)
-#define QMF_LEFT_JUSTIFY ((unsigned int) 0x00000004)
-#define QMF_CENTER_JUSTIFY ((unsigned int) 0x00000008)
-#define QMF_RIGHT_JUSTIFY ((unsigned int) 0x00000010)
-#define QMF_NUMBERSONLY ((unsigned int) 0x00000020) // edit field is only numbers
-#define QMF_HIGHLIGHT ((unsigned int) 0x00000040)
-#define QMF_HIGHLIGHT_IF_FOCUS ((unsigned int) 0x00000080) // steady focus
-#define QMF_PULSEIFFOCUS ((unsigned int) 0x00000100) // pulse if focus
-#define QMF_HASMOUSEFOCUS ((unsigned int) 0x00000200)
-#define QMF_NOONOFFTEXT ((unsigned int) 0x00000400)
-#define QMF_MOUSEONLY ((unsigned int) 0x00000800) // only mouse input allowed
-#define QMF_HIDDEN ((unsigned int) 0x00001000) // skips drawing
-#define QMF_GRAYED ((unsigned int) 0x00002000) // grays and disables
-#define QMF_INACTIVE ((unsigned int) 0x00004000) // disables any input
-#define QMF_NODEFAULTINIT ((unsigned int) 0x00008000) // skip default initialization
-#define QMF_OWNERDRAW ((unsigned int) 0x00010000)
-#define QMF_PULSE ((unsigned int) 0x00020000)
-#define QMF_LOWERCASE ((unsigned int) 0x00040000) // edit field is all lower case
-#define QMF_UPPERCASE ((unsigned int) 0x00080000) // edit field is all upper case
-#define QMF_SILENT ((unsigned int) 0x00100000)
-
-// callback notifications
-#define QM_GOTFOCUS 1
-#define QM_LOSTFOCUS 2
-#define QM_ACTIVATED 3
-
-typedef struct _tag_menuframework
-{
- int cursor;
- int cursor_prev;
-
- int nitems;
- void *items[MAX_MENUITEMS];
-
- void (*draw) (void);
- sfxHandle_t (*key) (int key);
-
- qboolean wrapAround;
- qboolean fullscreen;
- qboolean showlogo;
-} menuframework_s;
-
-typedef struct
-{
- int type;
- const char *name;
- int id;
- int x, y;
- int left;
- int top;
- int right;
- int bottom;
- menuframework_s *parent;
- int menuPosition;
- unsigned int flags;
-
- void (*callback)( void *self, int event );
- void (*statusbar)( void *self );
- void (*ownerdraw)( void *self );
-} menucommon_s;
-
-typedef struct {
- int cursor;
- int scroll;
- int widthInChars;
- char buffer[MAX_EDIT_LINE];
- int maxchars;
-} mfield_t;
-
-typedef struct
-{
- menucommon_s generic;
- mfield_t field;
-} menufield_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- float minvalue;
- float maxvalue;
- float curvalue;
-
- float range;
-} menuslider_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- int oldvalue;
- int curvalue;
- int numitems;
- int top;
-
- const char **itemnames;
-
- int width;
- int height;
- int columns;
- int seperation;
-} menulist_s;
-
-typedef struct
-{
- menucommon_s generic;
-} menuaction_s;
-
-typedef struct
-{
- menucommon_s generic;
- int curvalue;
-} menuradiobutton_s;
-
-typedef struct
-{
- menucommon_s generic;
- char* focuspic;
- char* errorpic;
- qhandle_t shader;
- qhandle_t focusshader;
- int width;
- int height;
- float* focuscolor;
-} menubitmap_s;
-
-typedef struct
-{
- menucommon_s generic;
- char* string;
- int style;
- float* color;
-} menutext_s;
-
-extern void Menu_Cache( void );
-extern void Menu_Focus( menucommon_s *m );
-extern void Menu_AddItem( menuframework_s *menu, void *item );
-extern void Menu_AdjustCursor( menuframework_s *menu, int dir );
-extern void Menu_Draw( menuframework_s *menu );
-extern void *Menu_ItemAtCursor( menuframework_s *m );
-extern sfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item );
-extern void Menu_SetCursor( menuframework_s *s, int cursor );
-extern void Menu_SetCursorToItem( menuframework_s *m, void* ptr );
-extern sfxHandle_t Menu_DefaultKey( menuframework_s *s, int key );
-extern void Bitmap_Init( menubitmap_s *b );
-extern void Bitmap_Draw( menubitmap_s *b );
-extern void ScrollList_Draw( menulist_s *l );
-extern sfxHandle_t ScrollList_Key( menulist_s *l, int key );
-extern sfxHandle_t menu_in_sound;
-extern sfxHandle_t menu_move_sound;
-extern sfxHandle_t menu_out_sound;
-extern sfxHandle_t menu_buzz_sound;
-extern sfxHandle_t menu_null_sound;
-extern sfxHandle_t weaponChangeSound;
-extern vec4_t menu_text_color;
-extern vec4_t menu_grayed_color;
-extern vec4_t menu_dark_color;
-extern vec4_t menu_highlight_color;
-extern vec4_t menu_red_color;
-extern vec4_t menu_black_color;
-extern vec4_t menu_dim_color;
-extern vec4_t color_black;
-extern vec4_t color_white;
-extern vec4_t color_yellow;
-extern vec4_t color_blue;
-extern vec4_t color_orange;
-extern vec4_t color_red;
-extern vec4_t color_dim;
-extern vec4_t name_color;
-extern vec4_t list_color;
-extern vec4_t listbar_color;
-extern vec4_t text_color_disabled;
-extern vec4_t text_color_normal;
-extern vec4_t text_color_highlight;
-
-extern char *ui_medalNames[];
-extern char *ui_medalPicNames[];
-extern char *ui_medalSounds[];
-
-//
-// ui_mfield.c
-//
-extern void MField_Clear( mfield_t *edit );
-extern void MField_KeyDownEvent( mfield_t *edit, int key );
-extern void MField_CharEvent( mfield_t *edit, int ch );
-extern void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color );
-extern void MenuField_Init( menufield_s* m );
-extern void MenuField_Draw( menufield_s *f );
-extern sfxHandle_t MenuField_Key( menufield_s* m, int* key );
-
-//
-// ui_menu.c
-//
-extern void MainMenu_Cache( void );
-extern void UI_MainMenu(void);
-extern void UI_RegisterCvars( void );
-extern void UI_UpdateCvars( void );
-
-//
-// ui_credits.c
-//
-extern void UI_CreditMenu( void );
-
-//
-// ui_ingame.c
-//
-extern void InGame_Cache( void );
-extern void UI_InGameMenu(void);
-
-//
-// ui_confirm.c
-//
-extern void ConfirmMenu_Cache( void );
-extern void UI_ConfirmMenu( const char *question, void (*draw)( void ), void (*action)( qboolean result ) );
-extern void UI_ConfirmMenu_Style( const char *question, int style, void (*draw)( void ), void (*action)( qboolean result ) );
-extern void UI_Message( const char **lines );
-
-//
-// ui_setup.c
-//
-extern void UI_SetupMenu_Cache( void );
-extern void UI_SetupMenu(void);
-
-//
-// ui_team.c
-//
-extern void UI_TeamMainMenu( void );
-extern void TeamMain_Cache( void );
-
-//
-// ui_connect.c
-//
-extern void UI_DrawConnectScreen( qboolean overlay );
-
-//
-// ui_controls2.c
-//
-extern void UI_ControlsMenu( void );
-extern void Controls_Cache( void );
-
-//
-// ui_demo2.c
-//
-extern void UI_DemosMenu( void );
-extern void Demos_Cache( void );
-
-//
-// ui_cinematics.c
-//
-extern void UI_CinematicsMenu( void );
-extern void UI_CinematicsMenu_f( void );
-extern void UI_CinematicsMenu_Cache( void );
-
-//
-// ui_mods.c
-//
-extern void UI_ModsMenu( void );
-extern void UI_ModsMenu_Cache( void );
-
-//
-// ui_cdkey.c
-//
-extern void UI_CDKeyMenu( void );
-extern void UI_CDKeyMenu_Cache( void );
-extern void UI_CDKeyMenu_f( void );
-
-//
-// ui_playermodel.c
-//
-extern void UI_PlayerModelMenu( void );
-extern void PlayerModel_Cache( void );
-
-//
-// ui_playersettings.c
-//
-extern void UI_PlayerSettingsMenu( void );
-extern void PlayerSettings_Cache( void );
-
-//
-// ui_preferences.c
-//
-extern void UI_PreferencesMenu( void );
-extern void Preferences_Cache( void );
-
-//
-// ui_specifyleague.c
-//
-extern void UI_SpecifyLeagueMenu( void );
-extern void SpecifyLeague_Cache( void );
-
-//
-// ui_specifyserver.c
-//
-extern void UI_SpecifyServerMenu( void );
-extern void SpecifyServer_Cache( void );
-
-//
-// ui_servers2.c
-//
-#define MAX_FAVORITESERVERS 16
-
-extern void UI_ArenaServersMenu( void );
-extern void ArenaServers_Cache( void );
-
-//
-// ui_startserver.c
-//
-extern void UI_StartServerMenu( qboolean multiplayer );
-extern void StartServer_Cache( void );
-extern void ServerOptions_Cache( void );
-extern void UI_BotSelectMenu( char *bot );
-extern void UI_BotSelectMenu_Cache( void );
-
-//
-// ui_serverinfo.c
-//
-extern void UI_ServerInfoMenu( void );
-extern void ServerInfo_Cache( void );
-
-//
-// ui_video.c
-//
-extern void UI_GraphicsOptionsMenu( void );
-extern void GraphicsOptions_Cache( void );
-extern void DriverInfo_Cache( void );
-
-//
-// ui_players.c
-//
-
-//FIXME ripped from cg_local.h
-typedef struct {
- int oldFrame;
- int oldFrameTime; // time when ->oldFrame was exactly on
-
- int frame;
- int frameTime; // time when ->frame will be exactly on
-
- float backlerp;
-
- float yawAngle;
- qboolean yawing;
- float pitchAngle;
- qboolean pitching;
-
- int animationNumber; // may include ANIM_TOGGLEBIT
- animation_t *animation;
- int animationTime; // time when the first frame of the animation will be exact
-} lerpFrame_t;
-
-typedef struct {
- // model info
- qhandle_t legsModel;
- qhandle_t legsSkin;
- lerpFrame_t legs;
-
- qhandle_t torsoModel;
- qhandle_t torsoSkin;
- lerpFrame_t torso;
-
- qhandle_t headModel;
- qhandle_t headSkin;
-
- animation_t animations[MAX_ANIMATIONS];
-
- qhandle_t weaponModel;
- qhandle_t barrelModel;
- qhandle_t flashModel;
- vec3_t flashDlightColor;
- int muzzleFlashTime;
-
- // currently in use drawing parms
- vec3_t viewAngles;
- vec3_t moveAngles;
- weapon_t currentWeapon;
- int legsAnim;
- int torsoAnim;
-
- // animation vars
- weapon_t weapon;
- weapon_t lastWeapon;
- weapon_t pendingWeapon;
- int weaponTimer;
- int pendingLegsAnim;
- int torsoAnimationTimer;
-
- int pendingTorsoAnim;
- int legsAnimationTimer;
-
- qboolean chat;
- qboolean newModel;
-
- qboolean barrelSpinning;
- float barrelAngle;
- int barrelTime;
-
- int realWeapon;
-} playerInfo_t;
-
-void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time );
-void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model );
-void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNum, qboolean chat );
-qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName );
-
-//
-// ui_atoms.c
-//
-typedef struct {
- int frametime;
- int realtime;
- int cursorx;
- int cursory;
- int menusp;
- menuframework_s* activemenu;
- menuframework_s* stack[MAX_MENUDEPTH];
- glconfig_t glconfig;
- qboolean debug;
- qhandle_t whiteShader;
- qhandle_t menuBackShader;
- qhandle_t menuBackNoLogoShader;
- qhandle_t charset;
- qhandle_t charsetProp;
- qhandle_t charsetPropGlow;
- qhandle_t charsetPropB;
- qhandle_t cursor;
- qhandle_t rb_on;
- qhandle_t rb_off;
- float xscale;
- float yscale;
- float bias;
- qboolean demoversion;
- qboolean firstdraw;
-} uiStatic_t;
-
-extern void UI_Init( void );
-extern void UI_Shutdown( void );
-extern void UI_KeyEvent( int key, int down );
-extern void UI_MouseEvent( int dx, int dy );
-extern void UI_Refresh( int realtime );
-extern qboolean UI_ConsoleCommand( int realTime );
-extern float UI_ClampCvar( float min, float max, float value );
-extern void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname );
-extern void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader );
-extern void UI_FillRect( float x, float y, float width, float height, const float *color );
-extern void UI_DrawRect( float x, float y, float width, float height, const float *color );
-extern void UI_UpdateScreen( void );
-extern void UI_SetColor( const float *rgba );
-extern void UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t);
-extern void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color );
-extern float UI_ProportionalSizeScale( int style );
-extern void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );
-extern void UI_DrawProportionalString_AutoWrapped( int x, int ystart, int xmax, int ystep, const char* str, int style, vec4_t color );
-extern int UI_ProportionalStringWidth( const char* str );
-extern void UI_DrawString( int x, int y, const char* str, int style, vec4_t color );
-extern void UI_DrawChar( int x, int y, int ch, int style, vec4_t color );
-extern qboolean UI_CursorInRect (int x, int y, int width, int height);
-extern void UI_AdjustFrom640( float *x, float *y, float *w, float *h );
-extern void UI_DrawTextBox (int x, int y, int width, int lines);
-extern qboolean UI_IsFullscreen( void );
-extern void UI_SetActiveMenu( uiMenuCommand_t menu );
-extern void UI_PushMenu ( menuframework_s *menu );
-extern void UI_PopMenu (void);
-extern void UI_ForceMenuOff (void);
-extern char *UI_Argv( int arg );
-extern char *UI_Cvar_VariableString( const char *var_name );
-extern void UI_Refresh( int time );
-extern void UI_StartDemoLoop( void );
-extern qboolean m_entersound;
-extern uiStatic_t uis;
-
-//
-// ui_spLevel.c
-//
-void UI_SPLevelMenu_Cache( void );
-void UI_SPLevelMenu( void );
-void UI_SPLevelMenu_f( void );
-void UI_SPLevelMenu_ReInit( void );
-
-//
-// ui_spArena.c
-//
-void UI_SPArena_Start( const char *arenaInfo );
-
-//
-// ui_spPostgame.c
-//
-void UI_SPPostgameMenu_Cache( void );
-void UI_SPPostgameMenu_f( void );
-
-//
-// ui_spSkill.c
-//
-void UI_SPSkillMenu( const char *arenaInfo );
-void UI_SPSkillMenu_Cache( void );
-
-//
-// ui_syscalls.c
-//
-void trap_Print( const char *string );
-void trap_Error( const char *string );
-int trap_Milliseconds( void );
-void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
-void trap_Cvar_Update( vmCvar_t *vmCvar );
-void trap_Cvar_Set( const char *var_name, const char *value );
-float trap_Cvar_VariableValue( const char *var_name );
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-void trap_Cvar_SetValue( const char *var_name, float value );
-void trap_Cvar_Reset( const char *name );
-void trap_Cvar_Create( const char *var_name, const char *var_value, int flags );
-void trap_Cvar_InfoStringBuffer( int bit, char *buffer, int bufsize );
-int trap_Argc( void );
-void trap_Argv( int n, char *buffer, int bufferLength );
-void trap_Cmd_ExecuteText( int exec_when, const char *text ); // don't use EXEC_NOW!
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
-void trap_FS_Read( void *buffer, int len, fileHandle_t f );
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
-void trap_FS_FCloseFile( fileHandle_t f );
-int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
-qhandle_t trap_R_RegisterModel( const char *name );
-qhandle_t trap_R_RegisterSkin( const char *name );
-qhandle_t trap_R_RegisterShaderNoMip( const char *name );
-void trap_R_ClearScene( void );
-void trap_R_AddRefEntityToScene( const refEntity_t *re );
-void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );
-void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
-void trap_R_RenderScene( const refdef_t *fd );
-void trap_R_SetColor( const float *rgba );
-void trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
-void trap_UpdateScreen( void );
-int trap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName );
-void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );
-sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed );
-void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen );
-void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen );
-void trap_Key_SetBinding( int keynum, const char *binding );
-qboolean trap_Key_IsDown( int keynum );
-qboolean trap_Key_GetOverstrikeMode( void );
-void trap_Key_SetOverstrikeMode( qboolean state );
-void trap_Key_ClearStates( void );
-int trap_Key_GetCatcher( void );
-void trap_Key_SetCatcher( int catcher );
-void trap_GetClipboardData( char *buf, int bufsize );
-void trap_GetClientState( uiClientState_t *state );
-void trap_GetGlconfig( glconfig_t *glconfig );
-int trap_GetConfigString( int index, char* buff, int buffsize );
-int trap_LAN_GetServerCount( int source );
-void trap_LAN_GetServerAddressString( int source, int n, char *buf, int buflen );
-void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen );
-int trap_LAN_GetPingQueueCount( void );
-int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen );
-void trap_LAN_ClearPing( int n );
-void trap_LAN_GetPing( int n, char *buf, int buflen, int *pingtime );
-void trap_LAN_GetPingInfo( int n, char *buf, int buflen );
-int trap_MemoryRemaining( void );
-void trap_GetCDKey( char *buf, int buflen );
-void trap_SetCDKey( char *buf );
-
-qboolean trap_VerifyCDKey( const char *key, const char *chksum);
-
-void trap_SetPbClStatus( int status );
-
-//
-// ui_addbots.c
-//
-void UI_AddBots_Cache( void );
-void UI_AddBotsMenu( void );
-
-//
-// ui_removebots.c
-//
-void UI_RemoveBots_Cache( void );
-void UI_RemoveBotsMenu( void );
-
-//
-// ui_teamorders.c
-//
-extern void UI_TeamOrdersMenu( void );
-extern void UI_TeamOrdersMenu_f( void );
-extern void UI_TeamOrdersMenu_Cache( void );
-
-//
-// ui_loadconfig.c
-//
-void UI_LoadConfig_Cache( void );
-void UI_LoadConfigMenu( void );
-
-//
-// ui_saveconfig.c
-//
-void UI_SaveConfigMenu_Cache( void );
-void UI_SaveConfigMenu( void );
-
-//
-// ui_display.c
-//
-void UI_DisplayOptionsMenu_Cache( void );
-void UI_DisplayOptionsMenu( void );
-
-//
-// ui_sound.c
-//
-void UI_SoundOptionsMenu_Cache( void );
-void UI_SoundOptionsMenu( void );
-
-//
-// ui_network.c
-//
-void UI_NetworkOptionsMenu_Cache( void );
-void UI_NetworkOptionsMenu( void );
-
-//
-// ui_gameinfo.c
-//
-typedef enum {
- AWARD_ACCURACY,
- AWARD_IMPRESSIVE,
- AWARD_EXCELLENT,
- AWARD_GAUNTLET,
- AWARD_FRAGS,
- AWARD_PERFECT
-} awardType_t;
-
-const char *UI_GetArenaInfoByNumber( int num );
-const char *UI_GetArenaInfoByMap( const char *map );
-const char *UI_GetSpecialArenaInfo( const char *tag );
-int UI_GetNumArenas( void );
-int UI_GetNumSPArenas( void );
-int UI_GetNumSPTiers( void );
-
-char *UI_GetBotInfoByNumber( int num );
-char *UI_GetBotInfoByName( const char *name );
-int UI_GetNumBots( void );
-
-void UI_GetBestScore( int level, int *score, int *skill );
-void UI_SetBestScore( int level, int score );
-int UI_TierCompleted( int levelWon );
-qboolean UI_ShowTierVideo( int tier );
-qboolean UI_CanShowTierVideo( int tier );
-int UI_GetCurrentGame( void );
-void UI_NewGame( void );
-void UI_LogAwardData( int award, int data );
-int UI_GetAwardLevel( int award );
-
-void UI_SPUnlock_f( void );
-void UI_SPUnlockMedals_f( void );
-
-void UI_InitGameinfo( void );
-
-//GRank
-
-//
-// ui_rankings.c
-//
-void Rankings_DrawText( void* self );
-void Rankings_DrawName( void* self );
-void Rankings_DrawPassword( void* self );
-void Rankings_Cache( void );
-void UI_RankingsMenu( void );
-
-//
-// ui_login.c
-//
-void Login_Cache( void );
-void UI_LoginMenu( void );
-
-//
-// ui_signup.c
-//
-void Signup_Cache( void );
-void UI_SignupMenu( void );
-
-//
-// ui_rankstatus.c
-//
-void RankStatus_Cache( void );
-void UI_RankStatusMenu( void );
-
-#endif
diff --git a/engine/code/q3_ui/ui_login.c b/engine/code/q3_ui/ui_login.c
deleted file mode 100644
index a0df46b..0000000
--- a/engine/code/q3_ui/ui_login.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-//
-// ui_login.c
-//
-
-#include "ui_local.h"
-
-
-#define LOGIN_FRAME "menu/art/cut_frame"
-
-#define ID_NAME 100
-#define ID_NAME_BOX 101
-#define ID_PASSWORD 102
-#define ID_PASSWORD_BOX 103
-#define ID_LOGIN 104
-#define ID_CANCEL 105
-
-
-typedef struct
-{
- menuframework_s menu;
- menubitmap_s frame;
- menutext_s name;
- menufield_s name_box;
- menutext_s password;
- menufield_s password_box;
- menutext_s login;
- menutext_s cancel;
-} login_t;
-
-static login_t s_login;
-
-static menuframework_s s_login_menu;
-static menuaction_s s_login_login;
-static menuaction_s s_login_cancel;
-
-static vec4_t s_login_color_prompt = {1.00, 0.43, 0.00, 1.00};
-
-/*
-===============
-Login_MenuEvent
-===============
-*/
-static void Login_MenuEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_LOGIN:
- // set name ``
- //trap_Cvar_Set( "name", s_login.name_box.field.buffer );
- /*
- trap_Cvar_Set( "rank_name", s_login.name_box.field.buffer );
- trap_Cvar_Set( "rank_pwd", s_login.password_box.field.buffer );
- */
-
- // login
- trap_CL_UI_RankUserLogin(
- s_login.name_box.field.buffer,
- s_login.password_box.field.buffer );
-
- UI_ForceMenuOff();
- break;
-
- case ID_CANCEL:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-===============
-Login_MenuInit
-===============
-*/
-void Login_MenuInit( void ) {
- int y;
-
- memset( &s_login, 0, sizeof(s_login) );
-
- Login_Cache();
-
- s_login.menu.wrapAround = qtrue;
- s_login.menu.fullscreen = qfalse;
-
- s_login.frame.generic.type = MTYPE_BITMAP;
- s_login.frame.generic.flags = QMF_INACTIVE;
- s_login.frame.generic.name = LOGIN_FRAME;
- s_login.frame.generic.x = 142; //320-233;
- s_login.frame.generic.y = 118; //240-166;
- s_login.frame.width = 359; //466;
- s_login.frame.height = 256; //332;
-
- y = 214;
-
- s_login.name.generic.type = MTYPE_PTEXT;
- s_login.name.generic.flags = QMF_RIGHT_JUSTIFY|QMF_INACTIVE;
- s_login.name.generic.id = ID_NAME;
- s_login.name.generic.x = 310;
- s_login.name.generic.y = y;
- s_login.name.string = "NAME";
- s_login.name.style = UI_RIGHT|UI_SMALLFONT;
- s_login.name.color = s_login_color_prompt;
-
- s_login.name_box.generic.type = MTYPE_FIELD;
- s_login.name_box.generic.ownerdraw = Rankings_DrawName;
- s_login.name_box.generic.name = "";
- s_login.name_box.generic.flags = 0;
- s_login.name_box.generic.x = 330;
- s_login.name_box.generic.y = y;
- s_login.name_box.field.widthInChars = 16;
- s_login.name_box.field.maxchars = 16;
- y += 20;
-
- s_login.password.generic.type = MTYPE_PTEXT;
- s_login.password.generic.flags = QMF_RIGHT_JUSTIFY|QMF_INACTIVE;
- s_login.password.generic.id = ID_PASSWORD;
- s_login.password.generic.x = 310;
- s_login.password.generic.y = y;
- s_login.password.string = "PASSWORD";
- s_login.password.style = UI_RIGHT|UI_SMALLFONT;
- s_login.password.color = s_login_color_prompt;
-
- s_login.password_box.generic.type = MTYPE_FIELD;
- s_login.password_box.generic.ownerdraw = Rankings_DrawPassword;
- s_login.password_box.generic.name = "";
- s_login.password_box.generic.flags = 0;
- s_login.password_box.generic.x = 330;
- s_login.password_box.generic.y = y;
- s_login.password_box.field.widthInChars = 16;
- s_login.password_box.field.maxchars = 16;
- y += 40;
-
- s_login.login.generic.type = MTYPE_PTEXT;
- s_login.login.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_login.login.generic.id = ID_LOGIN;
- s_login.login.generic.callback = Login_MenuEvent;
- s_login.login.generic.x = 310;
- s_login.login.generic.y = y;
- s_login.login.string = "LOGIN";
- s_login.login.style = UI_RIGHT|UI_SMALLFONT;
- s_login.login.color = colorRed;
-
- s_login.cancel.generic.type = MTYPE_PTEXT;
- s_login.cancel.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_login.cancel.generic.id = ID_CANCEL;
- s_login.cancel.generic.callback = Login_MenuEvent;
- s_login.cancel.generic.x = 330;
- s_login.cancel.generic.y = y;
- s_login.cancel.string = "CANCEL";
- s_login.cancel.style = UI_LEFT|UI_SMALLFONT;
- s_login.cancel.color = colorRed;
- y += 20;
-
- Menu_AddItem( &s_login.menu, (void*) &s_login.frame );
- Menu_AddItem( &s_login.menu, (void*) &s_login.name );
- Menu_AddItem( &s_login.menu, (void*) &s_login.name_box );
- Menu_AddItem( &s_login.menu, (void*) &s_login.password );
- Menu_AddItem( &s_login.menu, (void*) &s_login.password_box );
- Menu_AddItem( &s_login.menu, (void*) &s_login.login );
- Menu_AddItem( &s_login.menu, (void*) &s_login.cancel );
-}
-
-
-/*
-===============
-Login_Cache
-===============
-*/
-void Login_Cache( void ) {
- trap_R_RegisterShaderNoMip( LOGIN_FRAME );
-}
-
-
-/*
-===============
-UI_LoginMenu
-===============
-*/
-void UI_LoginMenu( void ) {
- Login_MenuInit();
- UI_PushMenu ( &s_login.menu );
-}
-
-
diff --git a/engine/code/q3_ui/ui_main.c b/engine/code/q3_ui/ui_main.c
deleted file mode 100644
index 8ec498d..0000000
--- a/engine/code/q3_ui/ui_main.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-USER INTERFACE MAIN
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-/*
-================
-vmMain
-
-This is the only way control passes into the module.
-This must be the very first function compiled into the .qvm file
-================
-*/
-Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
- switch ( command ) {
- case UI_GETAPIVERSION:
- return UI_API_VERSION;
-
- case UI_INIT:
- UI_Init();
- return 0;
-
- case UI_SHUTDOWN:
- UI_Shutdown();
- return 0;
-
- case UI_KEY_EVENT:
- UI_KeyEvent( arg0, arg1 );
- return 0;
-
- case UI_MOUSE_EVENT:
- UI_MouseEvent( arg0, arg1 );
- return 0;
-
- case UI_REFRESH:
- UI_Refresh( arg0 );
- return 0;
-
- case UI_IS_FULLSCREEN:
- return UI_IsFullscreen();
-
- case UI_SET_ACTIVE_MENU:
- UI_SetActiveMenu( arg0 );
- return 0;
-
- case UI_CONSOLE_COMMAND:
- return UI_ConsoleCommand(arg0);
-
- case UI_DRAW_CONNECT_SCREEN:
- UI_DrawConnectScreen( arg0 );
- return 0;
- case UI_HASUNIQUECDKEY: // mod authors need to observe this
- return qtrue; // change this to qfalse for mods!
- }
-
- return -1;
-}
-
-
-/*
-================
-cvars
-================
-*/
-
-typedef struct {
- vmCvar_t *vmCvar;
- char *cvarName;
- char *defaultString;
- int cvarFlags;
-} cvarTable_t;
-
-vmCvar_t ui_ffa_fraglimit;
-vmCvar_t ui_ffa_timelimit;
-
-vmCvar_t ui_tourney_fraglimit;
-vmCvar_t ui_tourney_timelimit;
-
-vmCvar_t ui_team_fraglimit;
-vmCvar_t ui_team_timelimit;
-vmCvar_t ui_team_friendly;
-
-vmCvar_t ui_ctf_capturelimit;
-vmCvar_t ui_ctf_timelimit;
-vmCvar_t ui_ctf_friendly;
-
-vmCvar_t ui_arenasFile;
-vmCvar_t ui_botsFile;
-vmCvar_t ui_spScores1;
-vmCvar_t ui_spScores2;
-vmCvar_t ui_spScores3;
-vmCvar_t ui_spScores4;
-vmCvar_t ui_spScores5;
-vmCvar_t ui_spAwards;
-vmCvar_t ui_spVideos;
-vmCvar_t ui_spSkill;
-
-vmCvar_t ui_spSelection;
-
-vmCvar_t ui_browserMaster;
-vmCvar_t ui_browserGameType;
-vmCvar_t ui_browserSortKey;
-vmCvar_t ui_browserShowFull;
-vmCvar_t ui_browserShowEmpty;
-
-vmCvar_t ui_brassTime;
-vmCvar_t ui_drawCrosshair;
-vmCvar_t ui_drawCrosshairNames;
-vmCvar_t ui_marks;
-
-vmCvar_t ui_server1;
-vmCvar_t ui_server2;
-vmCvar_t ui_server3;
-vmCvar_t ui_server4;
-vmCvar_t ui_server5;
-vmCvar_t ui_server6;
-vmCvar_t ui_server7;
-vmCvar_t ui_server8;
-vmCvar_t ui_server9;
-vmCvar_t ui_server10;
-vmCvar_t ui_server11;
-vmCvar_t ui_server12;
-vmCvar_t ui_server13;
-vmCvar_t ui_server14;
-vmCvar_t ui_server15;
-vmCvar_t ui_server16;
-
-vmCvar_t ui_cdkeychecked;
-vmCvar_t ui_ioq3;
-
-static cvarTable_t cvarTable[] = {
- { &ui_ffa_fraglimit, "ui_ffa_fraglimit", "20", CVAR_ARCHIVE },
- { &ui_ffa_timelimit, "ui_ffa_timelimit", "0", CVAR_ARCHIVE },
-
- { &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE },
- { &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE },
-
- { &ui_team_fraglimit, "ui_team_fraglimit", "0", CVAR_ARCHIVE },
- { &ui_team_timelimit, "ui_team_timelimit", "20", CVAR_ARCHIVE },
- { &ui_team_friendly, "ui_team_friendly", "1", CVAR_ARCHIVE },
-
- { &ui_ctf_capturelimit, "ui_ctf_capturelimit", "8", CVAR_ARCHIVE },
- { &ui_ctf_timelimit, "ui_ctf_timelimit", "30", CVAR_ARCHIVE },
- { &ui_ctf_friendly, "ui_ctf_friendly", "0", CVAR_ARCHIVE },
-
- { &ui_arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM },
- { &ui_botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM },
- { &ui_spScores1, "g_spScores1", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores2, "g_spScores2", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores3, "g_spScores3", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores4, "g_spScores4", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores5, "g_spScores5", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spAwards, "g_spAwards", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spVideos, "g_spVideos", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spSkill, "g_spSkill", "2", CVAR_ARCHIVE | CVAR_LATCH },
-
- { &ui_spSelection, "ui_spSelection", "", CVAR_ROM },
-
- { &ui_browserMaster, "ui_browserMaster", "0", CVAR_ARCHIVE },
- { &ui_browserGameType, "ui_browserGameType", "0", CVAR_ARCHIVE },
- { &ui_browserSortKey, "ui_browserSortKey", "4", CVAR_ARCHIVE },
- { &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE },
- { &ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE },
-
- { &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
- { &ui_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
- { &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
- { &ui_marks, "cg_marks", "1", CVAR_ARCHIVE },
-
- { &ui_server1, "server1", "", CVAR_ARCHIVE },
- { &ui_server2, "server2", "", CVAR_ARCHIVE },
- { &ui_server3, "server3", "", CVAR_ARCHIVE },
- { &ui_server4, "server4", "", CVAR_ARCHIVE },
- { &ui_server5, "server5", "", CVAR_ARCHIVE },
- { &ui_server6, "server6", "", CVAR_ARCHIVE },
- { &ui_server7, "server7", "", CVAR_ARCHIVE },
- { &ui_server8, "server8", "", CVAR_ARCHIVE },
- { &ui_server9, "server9", "", CVAR_ARCHIVE },
- { &ui_server10, "server10", "", CVAR_ARCHIVE },
- { &ui_server11, "server11", "", CVAR_ARCHIVE },
- { &ui_server12, "server12", "", CVAR_ARCHIVE },
- { &ui_server13, "server13", "", CVAR_ARCHIVE },
- { &ui_server14, "server14", "", CVAR_ARCHIVE },
- { &ui_server15, "server15", "", CVAR_ARCHIVE },
- { &ui_server16, "server16", "", CVAR_ARCHIVE },
-
- { &ui_cdkeychecked, "ui_cdkeychecked", "0", CVAR_ROM },
- { &ui_ioq3, "ui_ioq3", "1", CVAR_ROM }
-};
-
-static int cvarTableSize = sizeof(cvarTable) / sizeof(cvarTable[0]);
-
-
-/*
-=================
-UI_RegisterCvars
-=================
-*/
-void UI_RegisterCvars( void ) {
- int i;
- cvarTable_t *cv;
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );
- }
-}
-
-/*
-=================
-UI_UpdateCvars
-=================
-*/
-void UI_UpdateCvars( void ) {
- int i;
- cvarTable_t *cv;
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Update( cv->vmCvar );
- }
-}
diff --git a/engine/code/q3_ui/ui_menu.c b/engine/code/q3_ui/ui_menu.c
deleted file mode 100644
index 73cddd0..0000000
--- a/engine/code/q3_ui/ui_menu.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-MAIN MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define ID_SINGLEPLAYER 10
-#define ID_MULTIPLAYER 11
-#define ID_SETUP 12
-#define ID_DEMOS 13
-#define ID_CINEMATICS 14
-#define ID_TEAMARENA 15
-#define ID_MODS 16
-#define ID_EXIT 17
-
-#define MAIN_BANNER_MODEL "models/mapobjects/banner/banner5.md3"
-#define MAIN_MENU_VERTICAL_SPACING 34
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s singleplayer;
- menutext_s multiplayer;
- menutext_s setup;
- menutext_s demos;
- menutext_s cinematics;
- menutext_s teamArena;
- menutext_s mods;
- menutext_s exit;
-
- qhandle_t bannerModel;
-} mainmenu_t;
-
-
-static mainmenu_t s_main;
-
-typedef struct {
- menuframework_s menu;
- char errorMessage[4096];
-} errorMessage_t;
-
-static errorMessage_t s_errorMessage;
-
-/*
-=================
-MainMenu_ExitAction
-=================
-*/
-static void MainMenu_ExitAction( qboolean result ) {
- if( !result ) {
- return;
- }
- UI_PopMenu();
- UI_CreditMenu();
-}
-
-
-
-/*
-=================
-Main_MenuEvent
-=================
-*/
-void Main_MenuEvent (void* ptr, int event) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_SINGLEPLAYER:
- UI_SPLevelMenu();
- break;
-
- case ID_MULTIPLAYER:
- UI_ArenaServersMenu();
- break;
-
- case ID_SETUP:
- UI_SetupMenu();
- break;
-
- case ID_DEMOS:
- UI_DemosMenu();
- break;
-
- case ID_CINEMATICS:
- UI_CinematicsMenu();
- break;
-
- case ID_MODS:
- UI_ModsMenu();
- break;
-
- case ID_TEAMARENA:
- trap_Cvar_Set( "fs_game", "missionpack");
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
- break;
-
- case ID_EXIT:
- UI_ConfirmMenu( "EXIT GAME?", 0, MainMenu_ExitAction );
- break;
- }
-}
-
-
-/*
-===============
-MainMenu_Cache
-===============
-*/
-void MainMenu_Cache( void ) {
- s_main.bannerModel = trap_R_RegisterModel( MAIN_BANNER_MODEL );
-}
-
-sfxHandle_t ErrorMessage_Key(int key)
-{
- trap_Cvar_Set( "com_errorMessage", "" );
- UI_MainMenu();
- return (menu_null_sound);
-}
-
-/*
-===============
-Main_MenuDraw
-TTimo: this function is common to the main menu and errorMessage menu
-===============
-*/
-
-static void Main_MenuDraw( void ) {
- refdef_t refdef;
- refEntity_t ent;
- vec3_t origin;
- vec3_t angles;
- float adjust;
- float x, y, w, h;
- vec4_t color = {0.5, 0, 0, 1};
-
- // setup the refdef
-
- memset( &refdef, 0, sizeof( refdef ) );
-
- refdef.rdflags = RDF_NOWORLDMODEL;
-
- AxisClear( refdef.viewaxis );
-
- x = 0;
- y = 0;
- w = 640;
- h = 120;
- UI_AdjustFrom640( &x, &y, &w, &h );
- refdef.x = x;
- refdef.y = y;
- refdef.width = w;
- refdef.height = h;
-
- adjust = 0; // JDC: Kenneth asked me to stop this 1.0 * sin( (float)uis.realtime / 1000 );
- refdef.fov_x = 60 + adjust;
- refdef.fov_y = 19.6875 + adjust;
-
- refdef.time = uis.realtime;
-
- origin[0] = 300;
- origin[1] = 0;
- origin[2] = -32;
-
- trap_R_ClearScene();
-
- // add the model
-
- memset( &ent, 0, sizeof(ent) );
-
- adjust = 5.0 * sin( (float)uis.realtime / 5000 );
- VectorSet( angles, 0, 180 + adjust, 0 );
- AnglesToAxis( angles, ent.axis );
- ent.hModel = s_main.bannerModel;
- VectorCopy( origin, ent.origin );
- VectorCopy( origin, ent.lightingOrigin );
- ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
- VectorCopy( ent.origin, ent.oldorigin );
-
- trap_R_AddRefEntityToScene( &ent );
-
- trap_R_RenderScene( &refdef );
-
- if (strlen(s_errorMessage.errorMessage))
- {
- UI_DrawProportionalString_AutoWrapped( 320, 192, 600, 20, s_errorMessage.errorMessage, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
- }
- else
- {
- // standard menu drawing
- Menu_Draw( &s_main.menu );
- }
-
- if (uis.demoversion) {
- UI_DrawProportionalString( 320, 372, "DEMO FOR MATURE AUDIENCES DEMO", UI_CENTER|UI_SMALLFONT, color );
- UI_DrawString( 320, 400, "Quake III Arena(c) 1999-2000, Id Software, Inc. All Rights Reserved", UI_CENTER|UI_SMALLFONT, color );
- } else {
- UI_DrawString( 320, 450, "Quake III Arena(c) 1999-2000, Id Software, Inc. All Rights Reserved", UI_CENTER|UI_SMALLFONT, color );
- }
-}
-
-
-/*
-===============
-UI_TeamArenaExists
-===============
-*/
-static qboolean UI_TeamArenaExists( void ) {
- int numdirs;
- char dirlist[2048];
- char *dirptr;
- char *descptr;
- int i;
- int dirlen;
-
- numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) );
- dirptr = dirlist;
- for( i = 0; i < numdirs; i++ ) {
- dirlen = strlen( dirptr ) + 1;
- descptr = dirptr + dirlen;
- if (Q_stricmp(dirptr, "missionpack") == 0) {
- return qtrue;
- }
- dirptr += dirlen + strlen(descptr) + 1;
- }
- return qfalse;
-}
-
-
-/*
-===============
-UI_MainMenu
-
-The main menu only comes up when not in a game,
-so make sure that the attract loop server is down
-and that local cinematics are killed
-===============
-*/
-void UI_MainMenu( void ) {
- int y;
- qboolean teamArena = qfalse;
- int style = UI_CENTER | UI_DROPSHADOW;
-
- trap_Cvar_Set( "sv_killserver", "1" );
-
- if( !uis.demoversion && !ui_cdkeychecked.integer ) {
- char key[17];
-
- trap_GetCDKey( key, sizeof(key) );
- if( trap_VerifyCDKey( key, NULL ) == qfalse ) {
- UI_CDKeyMenu();
- return;
- }
- }
-
- memset( &s_main, 0 ,sizeof(mainmenu_t) );
- memset( &s_errorMessage, 0 ,sizeof(errorMessage_t) );
-
- // com_errorMessage would need that too
- MainMenu_Cache();
-
- trap_Cvar_VariableStringBuffer( "com_errorMessage", s_errorMessage.errorMessage, sizeof(s_errorMessage.errorMessage) );
- if (strlen(s_errorMessage.errorMessage))
- {
- s_errorMessage.menu.draw = Main_MenuDraw;
- s_errorMessage.menu.key = ErrorMessage_Key;
- s_errorMessage.menu.fullscreen = qtrue;
- s_errorMessage.menu.wrapAround = qtrue;
- s_errorMessage.menu.showlogo = qtrue;
-
- trap_Key_SetCatcher( KEYCATCH_UI );
- uis.menusp = 0;
- UI_PushMenu ( &s_errorMessage.menu );
-
- return;
- }
-
- s_main.menu.draw = Main_MenuDraw;
- s_main.menu.fullscreen = qtrue;
- s_main.menu.wrapAround = qtrue;
- s_main.menu.showlogo = qtrue;
-
- y = 134;
- s_main.singleplayer.generic.type = MTYPE_PTEXT;
- s_main.singleplayer.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.singleplayer.generic.x = 320;
- s_main.singleplayer.generic.y = y;
- s_main.singleplayer.generic.id = ID_SINGLEPLAYER;
- s_main.singleplayer.generic.callback = Main_MenuEvent;
- s_main.singleplayer.string = "SINGLE PLAYER";
- s_main.singleplayer.color = color_red;
- s_main.singleplayer.style = style;
-
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.multiplayer.generic.type = MTYPE_PTEXT;
- s_main.multiplayer.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.multiplayer.generic.x = 320;
- s_main.multiplayer.generic.y = y;
- s_main.multiplayer.generic.id = ID_MULTIPLAYER;
- s_main.multiplayer.generic.callback = Main_MenuEvent;
- s_main.multiplayer.string = "MULTIPLAYER";
- s_main.multiplayer.color = color_red;
- s_main.multiplayer.style = style;
-
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.setup.generic.type = MTYPE_PTEXT;
- s_main.setup.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.setup.generic.x = 320;
- s_main.setup.generic.y = y;
- s_main.setup.generic.id = ID_SETUP;
- s_main.setup.generic.callback = Main_MenuEvent;
- s_main.setup.string = "SETUP";
- s_main.setup.color = color_red;
- s_main.setup.style = style;
-
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.demos.generic.type = MTYPE_PTEXT;
- s_main.demos.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.demos.generic.x = 320;
- s_main.demos.generic.y = y;
- s_main.demos.generic.id = ID_DEMOS;
- s_main.demos.generic.callback = Main_MenuEvent;
- s_main.demos.string = "DEMOS";
- s_main.demos.color = color_red;
- s_main.demos.style = style;
-
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.cinematics.generic.type = MTYPE_PTEXT;
- s_main.cinematics.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.cinematics.generic.x = 320;
- s_main.cinematics.generic.y = y;
- s_main.cinematics.generic.id = ID_CINEMATICS;
- s_main.cinematics.generic.callback = Main_MenuEvent;
- s_main.cinematics.string = "CINEMATICS";
- s_main.cinematics.color = color_red;
- s_main.cinematics.style = style;
-
- if (UI_TeamArenaExists()) {
- teamArena = qtrue;
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.teamArena.generic.type = MTYPE_PTEXT;
- s_main.teamArena.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.teamArena.generic.x = 320;
- s_main.teamArena.generic.y = y;
- s_main.teamArena.generic.id = ID_TEAMARENA;
- s_main.teamArena.generic.callback = Main_MenuEvent;
- s_main.teamArena.string = "TEAM ARENA";
- s_main.teamArena.color = color_red;
- s_main.teamArena.style = style;
- }
-
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.mods.generic.type = MTYPE_PTEXT;
- s_main.mods.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.mods.generic.x = 320;
- s_main.mods.generic.y = y;
- s_main.mods.generic.id = ID_MODS;
- s_main.mods.generic.callback = Main_MenuEvent;
- s_main.mods.string = "MODS";
- s_main.mods.color = color_red;
- s_main.mods.style = style;
-
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.exit.generic.type = MTYPE_PTEXT;
- s_main.exit.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.exit.generic.x = 320;
- s_main.exit.generic.y = y;
- s_main.exit.generic.id = ID_EXIT;
- s_main.exit.generic.callback = Main_MenuEvent;
- s_main.exit.string = "EXIT";
- s_main.exit.color = color_red;
- s_main.exit.style = style;
-
- Menu_AddItem( &s_main.menu, &s_main.singleplayer );
- Menu_AddItem( &s_main.menu, &s_main.multiplayer );
- Menu_AddItem( &s_main.menu, &s_main.setup );
- Menu_AddItem( &s_main.menu, &s_main.demos );
- Menu_AddItem( &s_main.menu, &s_main.cinematics );
- if (teamArena) {
- Menu_AddItem( &s_main.menu, &s_main.teamArena );
- }
- Menu_AddItem( &s_main.menu, &s_main.mods );
- Menu_AddItem( &s_main.menu, &s_main.exit );
-
- trap_Key_SetCatcher( KEYCATCH_UI );
- uis.menusp = 0;
- UI_PushMenu ( &s_main.menu );
-
-}
diff --git a/engine/code/q3_ui/ui_mfield.c b/engine/code/q3_ui/ui_mfield.c
deleted file mode 100644
index d7b13fe..0000000
--- a/engine/code/q3_ui/ui_mfield.c
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-/*
-===================
-MField_Draw
-
-Handles horizontal scrolling and cursor blinking
-x, y, are in pixels
-===================
-*/
-void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color ) {
- int len;
- int charw;
- int drawLen;
- int prestep;
- int cursorChar;
- char str[MAX_STRING_CHARS];
-
- drawLen = edit->widthInChars;
- len = strlen( edit->buffer ) + 1;
-
- // guarantee that cursor will be visible
- if ( len <= drawLen ) {
- prestep = 0;
- } else {
- if ( edit->scroll + drawLen > len ) {
- edit->scroll = len - drawLen;
- if ( edit->scroll < 0 ) {
- edit->scroll = 0;
- }
- }
- prestep = edit->scroll;
- }
-
- if ( prestep + drawLen > len ) {
- drawLen = len - prestep;
- }
-
- // extract <drawLen> characters from the field at <prestep>
- if ( drawLen >= MAX_STRING_CHARS ) {
- trap_Error( "drawLen >= MAX_STRING_CHARS" );
- }
- memcpy( str, edit->buffer + prestep, drawLen );
- str[ drawLen ] = 0;
-
- UI_DrawString( x, y, str, style, color );
-
- // draw the cursor
- if (!(style & UI_PULSE)) {
- return;
- }
-
- if ( trap_Key_GetOverstrikeMode() ) {
- cursorChar = 11;
- } else {
- cursorChar = 10;
- }
-
- style &= ~UI_PULSE;
- style |= UI_BLINK;
-
- if (style & UI_SMALLFONT)
- {
- charw = SMALLCHAR_WIDTH;
- }
- else if (style & UI_GIANTFONT)
- {
- charw = GIANTCHAR_WIDTH;
- }
- else
- {
- charw = BIGCHAR_WIDTH;
- }
-
- if (style & UI_CENTER)
- {
- len = strlen(str);
- x = x - len*charw/2;
- }
- else if (style & UI_RIGHT)
- {
- len = strlen(str);
- x = x - len*charw;
- }
-
- UI_DrawChar( x + ( edit->cursor - prestep ) * charw, y, cursorChar, style & ~(UI_CENTER|UI_RIGHT), color );
-}
-
-/*
-================
-MField_Paste
-================
-*/
-void MField_Paste( mfield_t *edit ) {
- char pasteBuffer[64];
- int pasteLen, i;
-
- trap_GetClipboardData( pasteBuffer, 64 );
-
- // send as if typed, so insert / overstrike works properly
- pasteLen = strlen( pasteBuffer );
- for ( i = 0 ; i < pasteLen ; i++ ) {
- MField_CharEvent( edit, pasteBuffer[i] );
- }
-}
-
-/*
-=================
-MField_KeyDownEvent
-
-Performs the basic line editing functions for the console,
-in-game talk, and menu fields
-
-Key events are used for non-printable characters, others are gotten from char events.
-=================
-*/
-void MField_KeyDownEvent( mfield_t *edit, int key ) {
- int len;
-
- // shift-insert is paste
- if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && trap_Key_IsDown( K_SHIFT ) ) {
- MField_Paste( edit );
- return;
- }
-
- len = strlen( edit->buffer );
-
- if ( key == K_DEL || key == K_KP_DEL ) {
- if ( edit->cursor < len ) {
- memmove( edit->buffer + edit->cursor,
- edit->buffer + edit->cursor + 1, len - edit->cursor );
- }
- return;
- }
-
- if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW )
- {
- if ( edit->cursor < len ) {
- edit->cursor++;
- }
- if ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )
- {
- edit->scroll++;
- }
- return;
- }
-
- if ( key == K_LEFTARROW || key == K_KP_LEFTARROW )
- {
- if ( edit->cursor > 0 ) {
- edit->cursor--;
- }
- if ( edit->cursor < edit->scroll )
- {
- edit->scroll--;
- }
- return;
- }
-
- if ( key == K_HOME || key == K_KP_HOME || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {
- edit->cursor = 0;
- edit->scroll = 0;
- return;
- }
-
- if ( key == K_END || key == K_KP_END || ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {
- edit->cursor = len;
- edit->scroll = len - edit->widthInChars + 1;
- if (edit->scroll < 0)
- edit->scroll = 0;
- return;
- }
-
- if ( key == K_INS || key == K_KP_INS ) {
- trap_Key_SetOverstrikeMode( !trap_Key_GetOverstrikeMode() );
- return;
- }
-}
-
-/*
-==================
-MField_CharEvent
-==================
-*/
-void MField_CharEvent( mfield_t *edit, int ch ) {
- int len;
-
- if ( ch == 'v' - 'a' + 1 ) { // ctrl-v is paste
- MField_Paste( edit );
- return;
- }
-
- if ( ch == 'c' - 'a' + 1 ) { // ctrl-c clears the field
- MField_Clear( edit );
- return;
- }
-
- len = strlen( edit->buffer );
-
- if ( ch == 'h' - 'a' + 1 ) { // ctrl-h is backspace
- if ( edit->cursor > 0 ) {
- memmove( edit->buffer + edit->cursor - 1,
- edit->buffer + edit->cursor, len + 1 - edit->cursor );
- edit->cursor--;
- if ( edit->cursor < edit->scroll )
- {
- edit->scroll--;
- }
- }
- return;
- }
-
- if ( ch == 'a' - 'a' + 1 ) { // ctrl-a is home
- edit->cursor = 0;
- edit->scroll = 0;
- return;
- }
-
- if ( ch == 'e' - 'a' + 1 ) { // ctrl-e is end
- edit->cursor = len;
- edit->scroll = edit->cursor - edit->widthInChars + 1;
- if (edit->scroll < 0)
- edit->scroll = 0;
- return;
- }
-
- //
- // ignore any other non printable chars
- //
- if ( ch < 32 ) {
- return;
- }
-
- if ( !trap_Key_GetOverstrikeMode() ) {
- if ((edit->cursor == MAX_EDIT_LINE - 1) || (edit->maxchars && edit->cursor >= edit->maxchars))
- return;
- } else {
- // insert mode
- if (( len == MAX_EDIT_LINE - 1 ) || (edit->maxchars && len >= edit->maxchars))
- return;
- memmove( edit->buffer + edit->cursor + 1, edit->buffer + edit->cursor, len + 1 - edit->cursor );
- }
-
- edit->buffer[edit->cursor] = ch;
- if (!edit->maxchars || edit->cursor < edit->maxchars-1)
- edit->cursor++;
-
- if ( edit->cursor >= edit->widthInChars )
- {
- edit->scroll++;
- }
-
- if ( edit->cursor == len + 1) {
- edit->buffer[edit->cursor] = 0;
- }
-}
-
-/*
-==================
-MField_Clear
-==================
-*/
-void MField_Clear( mfield_t *edit ) {
- edit->buffer[0] = 0;
- edit->cursor = 0;
- edit->scroll = 0;
-}
-
-/*
-==================
-MenuField_Init
-==================
-*/
-void MenuField_Init( menufield_s* m ) {
- int l;
- int w;
- int h;
-
- MField_Clear( &m->field );
-
- if (m->generic.flags & QMF_SMALLFONT)
- {
- w = SMALLCHAR_WIDTH;
- h = SMALLCHAR_HEIGHT;
- }
- else
- {
- w = BIGCHAR_WIDTH;
- h = BIGCHAR_HEIGHT;
- }
-
- if (m->generic.name) {
- l = (strlen( m->generic.name )+1) * w;
- }
- else {
- l = 0;
- }
-
- m->generic.left = m->generic.x - l;
- m->generic.top = m->generic.y;
- m->generic.right = m->generic.x + w + m->field.widthInChars*w;
- m->generic.bottom = m->generic.y + h;
-}
-
-/*
-==================
-MenuField_Draw
-==================
-*/
-void MenuField_Draw( menufield_s *f )
-{
- int x;
- int y;
- int w;
- int h;
- int style;
- qboolean focus;
- float *color;
-
- x = f->generic.x;
- y = f->generic.y;
-
- if (f->generic.flags & QMF_SMALLFONT)
- {
- w = SMALLCHAR_WIDTH;
- h = SMALLCHAR_HEIGHT;
- style = UI_SMALLFONT;
- }
- else
- {
- w = BIGCHAR_WIDTH;
- h = BIGCHAR_HEIGHT;
- style = UI_BIGFONT;
- }
-
- if (Menu_ItemAtCursor( f->generic.parent ) == f) {
- focus = qtrue;
- style |= UI_PULSE;
- }
- else {
- focus = qfalse;
- }
-
- if (f->generic.flags & QMF_GRAYED)
- color = text_color_disabled;
- else if (focus)
- color = text_color_highlight;
- else
- color = text_color_normal;
-
- if ( focus )
- {
- // draw cursor
- UI_FillRect( f->generic.left, f->generic.top, f->generic.right-f->generic.left+1, f->generic.bottom-f->generic.top+1, listbar_color );
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|style, color);
- }
-
- if ( f->generic.name ) {
- UI_DrawString( x - w, y, f->generic.name, style|UI_RIGHT, color );
- }
-
- MField_Draw( &f->field, x + w, y, style, color );
-}
-
-/*
-==================
-MenuField_Key
-==================
-*/
-sfxHandle_t MenuField_Key( menufield_s* m, int* key )
-{
- int keycode;
-
- keycode = *key;
-
- switch ( keycode )
- {
- case K_KP_ENTER:
- case K_ENTER:
- case K_JOY1:
- case K_JOY2:
- case K_JOY3:
- case K_JOY4:
- // have enter go to next cursor point
- *key = K_TAB;
- break;
-
- case K_TAB:
- case K_KP_DOWNARROW:
- case K_DOWNARROW:
- case K_KP_UPARROW:
- case K_UPARROW:
- break;
-
- default:
- if ( keycode & K_CHAR_FLAG )
- {
- keycode &= ~K_CHAR_FLAG;
-
- if ((m->generic.flags & QMF_UPPERCASE) && Q_islower( keycode ))
- keycode -= 'a' - 'A';
- else if ((m->generic.flags & QMF_LOWERCASE) && Q_isupper( keycode ))
- keycode -= 'A' - 'a';
- else if ((m->generic.flags & QMF_NUMBERSONLY) && Q_isalpha( keycode ))
- return (menu_buzz_sound);
-
- MField_CharEvent( &m->field, keycode);
- }
- else
- MField_KeyDownEvent( &m->field, keycode );
- break;
- }
-
- return (0);
-}
-
-
diff --git a/engine/code/q3_ui/ui_mods.c b/engine/code/q3_ui/ui_mods.c
deleted file mode 100644
index e144375..0000000
--- a/engine/code/q3_ui/ui_mods.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-#define ART_FIGHT0 "menu/art/load_0"
-#define ART_FIGHT1 "menu/art/load_1"
-#define ART_FRAMEL "menu/art/frame2_l"
-#define ART_FRAMER "menu/art/frame1_r"
-
-#define MAX_MODS 64
-#define NAMEBUFSIZE ( MAX_MODS * 48 )
-#define GAMEBUFSIZE ( MAX_MODS * 16 )
-
-#define ID_BACK 10
-#define ID_GO 11
-#define ID_LIST 12
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menulist_s list;
-
- menubitmap_s back;
- menubitmap_s go;
-
- char description[NAMEBUFSIZE];
- char fs_game[GAMEBUFSIZE];
-
- char *descriptionPtr;
- char *fs_gamePtr;
-
- char *descriptionList[MAX_MODS];
- char *fs_gameList[MAX_MODS];
-} mods_t;
-
-static mods_t s_mods;
-
-
-/*
-===============
-UI_Mods_MenuEvent
-===============
-*/
-static void UI_Mods_MenuEvent( void *ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch ( ((menucommon_s*)ptr)->id ) {
- case ID_GO:
- trap_Cvar_Set( "fs_game", s_mods.fs_gameList[s_mods.list.curvalue] );
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
- UI_PopMenu();
- break;
-
- case ID_BACK:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-===============
-UI_Mods_ParseInfos
-===============
-*/
-static void UI_Mods_ParseInfos( char *modDir, char *modDesc ) {
- s_mods.fs_gameList[s_mods.list.numitems] = s_mods.fs_gamePtr;
- Q_strncpyz( s_mods.fs_gamePtr, modDir, 16 );
-
- s_mods.descriptionList[s_mods.list.numitems] = s_mods.descriptionPtr;
- Q_strncpyz( s_mods.descriptionPtr, modDesc, 48 );
-
- s_mods.list.itemnames[s_mods.list.numitems] = s_mods.descriptionPtr;
- s_mods.descriptionPtr += strlen( s_mods.descriptionPtr ) + 1;
- s_mods.fs_gamePtr += strlen( s_mods.fs_gamePtr ) + 1;
- s_mods.list.numitems++;
-}
-
-
-/*
-===============
-UI_Mods_LoadMods
-===============
-*/
-static void UI_Mods_LoadMods( void ) {
- int numdirs;
- char dirlist[2048];
- char *dirptr;
- char *descptr;
- int i;
- int dirlen;
-
- s_mods.list.itemnames = (const char **)s_mods.descriptionList;
- s_mods.descriptionPtr = s_mods.description;
- s_mods.fs_gamePtr = s_mods.fs_game;
-
- // always start off with baseq3
- s_mods.list.numitems = 1;
- s_mods.list.itemnames[0] = s_mods.descriptionList[0] = "Quake III Arena";
- s_mods.fs_gameList[0] = "";
-
- numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) );
- dirptr = dirlist;
- for( i = 0; i < numdirs; i++ ) {
- dirlen = strlen( dirptr ) + 1;
- descptr = dirptr + dirlen;
- UI_Mods_ParseInfos( dirptr, descptr);
- dirptr += dirlen + strlen(descptr) + 1;
- }
-
- trap_Print( va( "%i mods parsed\n", s_mods.list.numitems ) );
- if (s_mods.list.numitems > MAX_MODS) {
- s_mods.list.numitems = MAX_MODS;
- }
-}
-
-
-/*
-===============
-UI_Mods_MenuInit
-===============
-*/
-static void UI_Mods_MenuInit( void ) {
- UI_ModsMenu_Cache();
-
- memset( &s_mods, 0 ,sizeof(mods_t) );
- s_mods.menu.wrapAround = qtrue;
- s_mods.menu.fullscreen = qtrue;
-
- s_mods.banner.generic.type = MTYPE_BTEXT;
- s_mods.banner.generic.x = 320;
- s_mods.banner.generic.y = 16;
- s_mods.banner.string = "MODS";
- s_mods.banner.color = color_white;
- s_mods.banner.style = UI_CENTER;
-
- s_mods.framel.generic.type = MTYPE_BITMAP;
- s_mods.framel.generic.name = ART_FRAMEL;
- s_mods.framel.generic.flags = QMF_INACTIVE;
- s_mods.framel.generic.x = 0;
- s_mods.framel.generic.y = 78;
- s_mods.framel.width = 256;
- s_mods.framel.height = 329;
-
- s_mods.framer.generic.type = MTYPE_BITMAP;
- s_mods.framer.generic.name = ART_FRAMER;
- s_mods.framer.generic.flags = QMF_INACTIVE;
- s_mods.framer.generic.x = 376;
- s_mods.framer.generic.y = 76;
- s_mods.framer.width = 256;
- s_mods.framer.height = 334;
-
- s_mods.back.generic.type = MTYPE_BITMAP;
- s_mods.back.generic.name = ART_BACK0;
- s_mods.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_mods.back.generic.id = ID_BACK;
- s_mods.back.generic.callback = UI_Mods_MenuEvent;
- s_mods.back.generic.x = 0;
- s_mods.back.generic.y = 480-64;
- s_mods.back.width = 128;
- s_mods.back.height = 64;
- s_mods.back.focuspic = ART_BACK1;
-
- s_mods.go.generic.type = MTYPE_BITMAP;
- s_mods.go.generic.name = ART_FIGHT0;
- s_mods.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_mods.go.generic.id = ID_GO;
- s_mods.go.generic.callback = UI_Mods_MenuEvent;
- s_mods.go.generic.x = 640;
- s_mods.go.generic.y = 480-64;
- s_mods.go.width = 128;
- s_mods.go.height = 64;
- s_mods.go.focuspic = ART_FIGHT1;
-
- // scan for mods
- s_mods.list.generic.type = MTYPE_SCROLLLIST;
- s_mods.list.generic.flags = QMF_PULSEIFFOCUS|QMF_CENTER_JUSTIFY;
- s_mods.list.generic.callback = UI_Mods_MenuEvent;
- s_mods.list.generic.id = ID_LIST;
- s_mods.list.generic.x = 320;
- s_mods.list.generic.y = 130;
- s_mods.list.width = 48;
- s_mods.list.height = 14;
-
- UI_Mods_LoadMods();
-
- Menu_AddItem( &s_mods.menu, &s_mods.banner );
- Menu_AddItem( &s_mods.menu, &s_mods.framel );
- Menu_AddItem( &s_mods.menu, &s_mods.framer );
- Menu_AddItem( &s_mods.menu, &s_mods.list );
- Menu_AddItem( &s_mods.menu, &s_mods.back );
- Menu_AddItem( &s_mods.menu, &s_mods.go );
-}
-
-/*
-=================
-UI_Mods_Cache
-=================
-*/
-void UI_ModsMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_FIGHT0 );
- trap_R_RegisterShaderNoMip( ART_FIGHT1 );
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
-}
-
-
-/*
-===============
-UI_ModsMenu
-===============
-*/
-void UI_ModsMenu( void ) {
- UI_Mods_MenuInit();
- UI_PushMenu( &s_mods.menu );
-}
diff --git a/engine/code/q3_ui/ui_network.c b/engine/code/q3_ui/ui_network.c
deleted file mode 100644
index 0b4bf83..0000000
--- a/engine/code/q3_ui/ui_network.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-NETWORK OPTIONS MENU
-
-=======================================================================
-*/
-
-#include "ui_local.h"
-
-
-#define ART_FRAMEL "menu/art/frame2_l"
-#define ART_FRAMER "menu/art/frame1_r"
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-
-#define ID_GRAPHICS 10
-#define ID_DISPLAY 11
-#define ID_SOUND 12
-#define ID_NETWORK 13
-#define ID_RATE 14
-#define ID_BACK 15
-
-
-static const char *rate_items[] = {
- "<= 28.8K",
- "33.6K",
- "56K",
- "ISDN",
- "LAN/Cable/xDSL",
- NULL
-};
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menutext_s graphics;
- menutext_s display;
- menutext_s sound;
- menutext_s network;
-
- menulist_s rate;
-
- menubitmap_s back;
-} networkOptionsInfo_t;
-
-static networkOptionsInfo_t networkOptionsInfo;
-
-
-/*
-=================
-UI_NetworkOptionsMenu_Event
-=================
-*/
-static void UI_NetworkOptionsMenu_Event( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_GRAPHICS:
- UI_PopMenu();
- UI_GraphicsOptionsMenu();
- break;
-
- case ID_DISPLAY:
- UI_PopMenu();
- UI_DisplayOptionsMenu();
- break;
-
- case ID_SOUND:
- UI_PopMenu();
- UI_SoundOptionsMenu();
- break;
-
- case ID_NETWORK:
- break;
-
- case ID_RATE:
- if( networkOptionsInfo.rate.curvalue == 0 ) {
- trap_Cvar_SetValue( "rate", 2500 );
- }
- else if( networkOptionsInfo.rate.curvalue == 1 ) {
- trap_Cvar_SetValue( "rate", 3000 );
- }
- else if( networkOptionsInfo.rate.curvalue == 2 ) {
- trap_Cvar_SetValue( "rate", 4000 );
- }
- else if( networkOptionsInfo.rate.curvalue == 3 ) {
- trap_Cvar_SetValue( "rate", 5000 );
- }
- else if( networkOptionsInfo.rate.curvalue == 4 ) {
- trap_Cvar_SetValue( "rate", 25000 );
- }
- break;
-
- case ID_BACK:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-===============
-UI_NetworkOptionsMenu_Init
-===============
-*/
-static void UI_NetworkOptionsMenu_Init( void ) {
- int y;
- int rate;
-
- memset( &networkOptionsInfo, 0, sizeof(networkOptionsInfo) );
-
- UI_NetworkOptionsMenu_Cache();
- networkOptionsInfo.menu.wrapAround = qtrue;
- networkOptionsInfo.menu.fullscreen = qtrue;
-
- networkOptionsInfo.banner.generic.type = MTYPE_BTEXT;
- networkOptionsInfo.banner.generic.flags = QMF_CENTER_JUSTIFY;
- networkOptionsInfo.banner.generic.x = 320;
- networkOptionsInfo.banner.generic.y = 16;
- networkOptionsInfo.banner.string = "SYSTEM SETUP";
- networkOptionsInfo.banner.color = color_white;
- networkOptionsInfo.banner.style = UI_CENTER;
-
- networkOptionsInfo.framel.generic.type = MTYPE_BITMAP;
- networkOptionsInfo.framel.generic.name = ART_FRAMEL;
- networkOptionsInfo.framel.generic.flags = QMF_INACTIVE;
- networkOptionsInfo.framel.generic.x = 0;
- networkOptionsInfo.framel.generic.y = 78;
- networkOptionsInfo.framel.width = 256;
- networkOptionsInfo.framel.height = 329;
-
- networkOptionsInfo.framer.generic.type = MTYPE_BITMAP;
- networkOptionsInfo.framer.generic.name = ART_FRAMER;
- networkOptionsInfo.framer.generic.flags = QMF_INACTIVE;
- networkOptionsInfo.framer.generic.x = 376;
- networkOptionsInfo.framer.generic.y = 76;
- networkOptionsInfo.framer.width = 256;
- networkOptionsInfo.framer.height = 334;
-
- networkOptionsInfo.graphics.generic.type = MTYPE_PTEXT;
- networkOptionsInfo.graphics.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- networkOptionsInfo.graphics.generic.id = ID_GRAPHICS;
- networkOptionsInfo.graphics.generic.callback = UI_NetworkOptionsMenu_Event;
- networkOptionsInfo.graphics.generic.x = 216;
- networkOptionsInfo.graphics.generic.y = 240 - 2 * PROP_HEIGHT;
- networkOptionsInfo.graphics.string = "GRAPHICS";
- networkOptionsInfo.graphics.style = UI_RIGHT;
- networkOptionsInfo.graphics.color = color_red;
-
- networkOptionsInfo.display.generic.type = MTYPE_PTEXT;
- networkOptionsInfo.display.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- networkOptionsInfo.display.generic.id = ID_DISPLAY;
- networkOptionsInfo.display.generic.callback = UI_NetworkOptionsMenu_Event;
- networkOptionsInfo.display.generic.x = 216;
- networkOptionsInfo.display.generic.y = 240 - PROP_HEIGHT;
- networkOptionsInfo.display.string = "DISPLAY";
- networkOptionsInfo.display.style = UI_RIGHT;
- networkOptionsInfo.display.color = color_red;
-
- networkOptionsInfo.sound.generic.type = MTYPE_PTEXT;
- networkOptionsInfo.sound.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- networkOptionsInfo.sound.generic.id = ID_SOUND;
- networkOptionsInfo.sound.generic.callback = UI_NetworkOptionsMenu_Event;
- networkOptionsInfo.sound.generic.x = 216;
- networkOptionsInfo.sound.generic.y = 240;
- networkOptionsInfo.sound.string = "SOUND";
- networkOptionsInfo.sound.style = UI_RIGHT;
- networkOptionsInfo.sound.color = color_red;
-
- networkOptionsInfo.network.generic.type = MTYPE_PTEXT;
- networkOptionsInfo.network.generic.flags = QMF_RIGHT_JUSTIFY;
- networkOptionsInfo.network.generic.id = ID_NETWORK;
- networkOptionsInfo.network.generic.callback = UI_NetworkOptionsMenu_Event;
- networkOptionsInfo.network.generic.x = 216;
- networkOptionsInfo.network.generic.y = 240 + PROP_HEIGHT;
- networkOptionsInfo.network.string = "NETWORK";
- networkOptionsInfo.network.style = UI_RIGHT;
- networkOptionsInfo.network.color = color_red;
-
- y = 240 - 1 * (BIGCHAR_HEIGHT+2);
- networkOptionsInfo.rate.generic.type = MTYPE_SPINCONTROL;
- networkOptionsInfo.rate.generic.name = "Data Rate:";
- networkOptionsInfo.rate.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- networkOptionsInfo.rate.generic.callback = UI_NetworkOptionsMenu_Event;
- networkOptionsInfo.rate.generic.id = ID_RATE;
- networkOptionsInfo.rate.generic.x = 400;
- networkOptionsInfo.rate.generic.y = y;
- networkOptionsInfo.rate.itemnames = rate_items;
-
- networkOptionsInfo.back.generic.type = MTYPE_BITMAP;
- networkOptionsInfo.back.generic.name = ART_BACK0;
- networkOptionsInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- networkOptionsInfo.back.generic.callback = UI_NetworkOptionsMenu_Event;
- networkOptionsInfo.back.generic.id = ID_BACK;
- networkOptionsInfo.back.generic.x = 0;
- networkOptionsInfo.back.generic.y = 480-64;
- networkOptionsInfo.back.width = 128;
- networkOptionsInfo.back.height = 64;
- networkOptionsInfo.back.focuspic = ART_BACK1;
-
- Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.banner );
- Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.framel );
- Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.framer );
- Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.graphics );
- Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.display );
- Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.sound );
- Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.network );
- Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.rate );
- Menu_AddItem( &networkOptionsInfo.menu, ( void * ) &networkOptionsInfo.back );
-
- rate = trap_Cvar_VariableValue( "rate" );
- if( rate <= 2500 ) {
- networkOptionsInfo.rate.curvalue = 0;
- }
- else if( rate <= 3000 ) {
- networkOptionsInfo.rate.curvalue = 1;
- }
- else if( rate <= 4000 ) {
- networkOptionsInfo.rate.curvalue = 2;
- }
- else if( rate <= 5000 ) {
- networkOptionsInfo.rate.curvalue = 3;
- }
- else {
- networkOptionsInfo.rate.curvalue = 4;
- }
-}
-
-
-/*
-===============
-UI_NetworkOptionsMenu_Cache
-===============
-*/
-void UI_NetworkOptionsMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
-}
-
-
-/*
-===============
-UI_NetworkOptionsMenu
-===============
-*/
-void UI_NetworkOptionsMenu( void ) {
- UI_NetworkOptionsMenu_Init();
- UI_PushMenu( &networkOptionsInfo.menu );
- Menu_SetCursorToItem( &networkOptionsInfo.menu, &networkOptionsInfo.network );
-}
diff --git a/engine/code/q3_ui/ui_options.c b/engine/code/q3_ui/ui_options.c
deleted file mode 100644
index 288bd4e..0000000
--- a/engine/code/q3_ui/ui_options.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-/*
-=======================================================================
-
-SYSTEM CONFIGURATION MENU
-
-=======================================================================
-*/
-
-#include "ui_local.h"
-
-
-#define ART_FRAMEL "menu/art/frame2_l"
-#define ART_FRAMER "menu/art/frame1_r"
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-
-#define ID_GRAPHICS 10
-#define ID_DISPLAY 11
-#define ID_SOUND 12
-#define ID_NETWORK 13
-#define ID_BACK 14
-
-#define VERTICAL_SPACING 34
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menutext_s graphics;
- menutext_s display;
- menutext_s sound;
- menutext_s network;
- menubitmap_s back;
-} optionsmenu_t;
-
-static optionsmenu_t s_options;
-
-
-/*
-=================
-Options_Event
-=================
-*/
-static void Options_Event( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_GRAPHICS:
- UI_GraphicsOptionsMenu();
- break;
-
- case ID_DISPLAY:
- UI_DisplayOptionsMenu();
- break;
-
- case ID_SOUND:
- UI_SoundOptionsMenu();
- break;
-
- case ID_NETWORK:
- UI_NetworkOptionsMenu();
- break;
-
- case ID_BACK:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-===============
-SystemConfig_Cache
-===============
-*/
-void SystemConfig_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
-}
-
-/*
-===============
-Options_MenuInit
-===============
-*/
-void Options_MenuInit( void ) {
- int y;
- uiClientState_t cstate;
-
- memset( &s_options, 0, sizeof(optionsmenu_t) );
-
- SystemConfig_Cache();
- s_options.menu.wrapAround = qtrue;
-
- trap_GetClientState( &cstate );
- if ( cstate.connState >= CA_CONNECTED ) {
- s_options.menu.fullscreen = qfalse;
- }
- else {
- s_options.menu.fullscreen = qtrue;
- }
-
- s_options.banner.generic.type = MTYPE_BTEXT;
- s_options.banner.generic.flags = QMF_CENTER_JUSTIFY;
- s_options.banner.generic.x = 320;
- s_options.banner.generic.y = 16;
- s_options.banner.string = "SYSTEM SETUP";
- s_options.banner.color = color_white;
- s_options.banner.style = UI_CENTER;
-
- s_options.framel.generic.type = MTYPE_BITMAP;
- s_options.framel.generic.name = ART_FRAMEL;
- s_options.framel.generic.flags = QMF_INACTIVE;
- s_options.framel.generic.x = 8;
- s_options.framel.generic.y = 76;
- s_options.framel.width = 256;
- s_options.framel.height = 334;
-
- s_options.framer.generic.type = MTYPE_BITMAP;
- s_options.framer.generic.name = ART_FRAMER;
- s_options.framer.generic.flags = QMF_INACTIVE;
- s_options.framer.generic.x = 376;
- s_options.framer.generic.y = 76;
- s_options.framer.width = 256;
- s_options.framer.height = 334;
-
- y = 168;
- s_options.graphics.generic.type = MTYPE_PTEXT;
- s_options.graphics.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_options.graphics.generic.callback = Options_Event;
- s_options.graphics.generic.id = ID_GRAPHICS;
- s_options.graphics.generic.x = 320;
- s_options.graphics.generic.y = y;
- s_options.graphics.string = "GRAPHICS";
- s_options.graphics.color = color_red;
- s_options.graphics.style = UI_CENTER;
-
- y += VERTICAL_SPACING;
- s_options.display.generic.type = MTYPE_PTEXT;
- s_options.display.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_options.display.generic.callback = Options_Event;
- s_options.display.generic.id = ID_DISPLAY;
- s_options.display.generic.x = 320;
- s_options.display.generic.y = y;
- s_options.display.string = "DISPLAY";
- s_options.display.color = color_red;
- s_options.display.style = UI_CENTER;
-
- y += VERTICAL_SPACING;
- s_options.sound.generic.type = MTYPE_PTEXT;
- s_options.sound.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_options.sound.generic.callback = Options_Event;
- s_options.sound.generic.id = ID_SOUND;
- s_options.sound.generic.x = 320;
- s_options.sound.generic.y = y;
- s_options.sound.string = "SOUND";
- s_options.sound.color = color_red;
- s_options.sound.style = UI_CENTER;
-
- y += VERTICAL_SPACING;
- s_options.network.generic.type = MTYPE_PTEXT;
- s_options.network.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_options.network.generic.callback = Options_Event;
- s_options.network.generic.id = ID_NETWORK;
- s_options.network.generic.x = 320;
- s_options.network.generic.y = y;
- s_options.network.string = "NETWORK";
- s_options.network.color = color_red;
- s_options.network.style = UI_CENTER;
-
- s_options.back.generic.type = MTYPE_BITMAP;
- s_options.back.generic.name = ART_BACK0;
- s_options.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_options.back.generic.callback = Options_Event;
- s_options.back.generic.id = ID_BACK;
- s_options.back.generic.x = 0;
- s_options.back.generic.y = 480-64;
- s_options.back.width = 128;
- s_options.back.height = 64;
- s_options.back.focuspic = ART_BACK1;
-
- Menu_AddItem( &s_options.menu, ( void * ) &s_options.banner );
- Menu_AddItem( &s_options.menu, ( void * ) &s_options.framel );
- Menu_AddItem( &s_options.menu, ( void * ) &s_options.framer );
- Menu_AddItem( &s_options.menu, ( void * ) &s_options.graphics );
- Menu_AddItem( &s_options.menu, ( void * ) &s_options.display );
- Menu_AddItem( &s_options.menu, ( void * ) &s_options.sound );
- Menu_AddItem( &s_options.menu, ( void * ) &s_options.network );
- Menu_AddItem( &s_options.menu, ( void * ) &s_options.back );
-}
-
-
-/*
-===============
-UI_SystemConfigMenu
-===============
-*/
-void UI_SystemConfigMenu( void ) {
- Options_MenuInit();
- UI_PushMenu ( &s_options.menu );
-}
diff --git a/engine/code/q3_ui/ui_playermodel.c b/engine/code/q3_ui/ui_playermodel.c
deleted file mode 100644
index e247149..0000000
--- a/engine/code/q3_ui/ui_playermodel.c
+++ /dev/null
@@ -1,731 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-#define MODEL_BACK0 "menu/art/back_0"
-#define MODEL_BACK1 "menu/art/back_1"
-#define MODEL_SELECT "menu/art/opponents_select"
-#define MODEL_SELECTED "menu/art/opponents_selected"
-#define MODEL_FRAMEL "menu/art/frame1_l"
-#define MODEL_FRAMER "menu/art/frame1_r"
-#define MODEL_PORTS "menu/art/player_models_ports"
-#define MODEL_ARROWS "menu/art/gs_arrows_0"
-#define MODEL_ARROWSL "menu/art/gs_arrows_l"
-#define MODEL_ARROWSR "menu/art/gs_arrows_r"
-
-#define LOW_MEMORY (5 * 1024 * 1024)
-
-static char* playermodel_artlist[] =
-{
- MODEL_BACK0,
- MODEL_BACK1,
- MODEL_SELECT,
- MODEL_SELECTED,
- MODEL_FRAMEL,
- MODEL_FRAMER,
- MODEL_PORTS,
- MODEL_ARROWS,
- MODEL_ARROWSL,
- MODEL_ARROWSR,
- NULL
-};
-
-#define PLAYERGRID_COLS 4
-#define PLAYERGRID_ROWS 4
-#define MAX_MODELSPERPAGE (PLAYERGRID_ROWS*PLAYERGRID_COLS)
-
-#define MAX_PLAYERMODELS 256
-
-#define ID_PLAYERPIC0 0
-#define ID_PLAYERPIC1 1
-#define ID_PLAYERPIC2 2
-#define ID_PLAYERPIC3 3
-#define ID_PLAYERPIC4 4
-#define ID_PLAYERPIC5 5
-#define ID_PLAYERPIC6 6
-#define ID_PLAYERPIC7 7
-#define ID_PLAYERPIC8 8
-#define ID_PLAYERPIC9 9
-#define ID_PLAYERPIC10 10
-#define ID_PLAYERPIC11 11
-#define ID_PLAYERPIC12 12
-#define ID_PLAYERPIC13 13
-#define ID_PLAYERPIC14 14
-#define ID_PLAYERPIC15 15
-#define ID_PREVPAGE 100
-#define ID_NEXTPAGE 101
-#define ID_BACK 102
-
-typedef struct
-{
- menuframework_s menu;
- menubitmap_s pics[MAX_MODELSPERPAGE];
- menubitmap_s picbuttons[MAX_MODELSPERPAGE];
- menubitmap_s framel;
- menubitmap_s framer;
- menubitmap_s ports;
- menutext_s banner;
- menubitmap_s back;
- menubitmap_s player;
- menubitmap_s arrows;
- menubitmap_s left;
- menubitmap_s right;
- menutext_s modelname;
- menutext_s skinname;
- menutext_s playername;
- playerInfo_t playerinfo;
- int nummodels;
- char modelnames[MAX_PLAYERMODELS][128];
- int modelpage;
- int numpages;
- char modelskin[64];
- int selectedmodel;
-} playermodel_t;
-
-static playermodel_t s_playermodel;
-
-/*
-=================
-PlayerModel_UpdateGrid
-=================
-*/
-static void PlayerModel_UpdateGrid( void )
-{
- int i;
- int j;
-
- j = s_playermodel.modelpage * MAX_MODELSPERPAGE;
- for (i=0; i<PLAYERGRID_ROWS*PLAYERGRID_COLS; i++,j++)
- {
- if (j < s_playermodel.nummodels)
- {
- // model/skin portrait
- s_playermodel.pics[i].generic.name = s_playermodel.modelnames[j];
- s_playermodel.picbuttons[i].generic.flags &= ~QMF_INACTIVE;
- }
- else
- {
- // dead slot
- s_playermodel.pics[i].generic.name = NULL;
- s_playermodel.picbuttons[i].generic.flags |= QMF_INACTIVE;
- }
-
- s_playermodel.pics[i].generic.flags &= ~QMF_HIGHLIGHT;
- s_playermodel.pics[i].shader = 0;
- s_playermodel.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
- }
-
- if (s_playermodel.selectedmodel/MAX_MODELSPERPAGE == s_playermodel.modelpage)
- {
- // set selected model
- i = s_playermodel.selectedmodel % MAX_MODELSPERPAGE;
-
- s_playermodel.pics[i].generic.flags |= QMF_HIGHLIGHT;
- s_playermodel.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
- }
-
- if (s_playermodel.numpages > 1)
- {
- if (s_playermodel.modelpage > 0)
- s_playermodel.left.generic.flags &= ~QMF_INACTIVE;
- else
- s_playermodel.left.generic.flags |= QMF_INACTIVE;
-
- if (s_playermodel.modelpage < s_playermodel.numpages-1)
- s_playermodel.right.generic.flags &= ~QMF_INACTIVE;
- else
- s_playermodel.right.generic.flags |= QMF_INACTIVE;
- }
- else
- {
- // hide left/right markers
- s_playermodel.left.generic.flags |= QMF_INACTIVE;
- s_playermodel.right.generic.flags |= QMF_INACTIVE;
- }
-}
-
-/*
-=================
-PlayerModel_UpdateModel
-=================
-*/
-static void PlayerModel_UpdateModel( void )
-{
- vec3_t viewangles;
- vec3_t moveangles;
-
- memset( &s_playermodel.playerinfo, 0, sizeof(playerInfo_t) );
-
- viewangles[YAW] = 180 - 30;
- viewangles[PITCH] = 0;
- viewangles[ROLL] = 0;
- VectorClear( moveangles );
-
- UI_PlayerInfo_SetModel( &s_playermodel.playerinfo, s_playermodel.modelskin );
- UI_PlayerInfo_SetInfo( &s_playermodel.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, moveangles, WP_MACHINEGUN, qfalse );
-}
-
-/*
-=================
-PlayerModel_SaveChanges
-=================
-*/
-static void PlayerModel_SaveChanges( void )
-{
- trap_Cvar_Set( "model", s_playermodel.modelskin );
- trap_Cvar_Set( "headmodel", s_playermodel.modelskin );
- trap_Cvar_Set( "team_model", s_playermodel.modelskin );
- trap_Cvar_Set( "team_headmodel", s_playermodel.modelskin );
-}
-
-/*
-=================
-PlayerModel_MenuEvent
-=================
-*/
-static void PlayerModel_MenuEvent( void* ptr, int event )
-{
- if (event != QM_ACTIVATED)
- return;
-
- switch (((menucommon_s*)ptr)->id)
- {
- case ID_PREVPAGE:
- if (s_playermodel.modelpage > 0)
- {
- s_playermodel.modelpage--;
- PlayerModel_UpdateGrid();
- }
- break;
-
- case ID_NEXTPAGE:
- if (s_playermodel.modelpage < s_playermodel.numpages-1)
- {
- s_playermodel.modelpage++;
- PlayerModel_UpdateGrid();
- }
- break;
-
- case ID_BACK:
- PlayerModel_SaveChanges();
- UI_PopMenu();
- break;
- }
-}
-
-/*
-=================
-PlayerModel_MenuKey
-=================
-*/
-static sfxHandle_t PlayerModel_MenuKey( int key )
-{
- menucommon_s* m;
- int picnum;
-
- switch (key)
- {
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- m = Menu_ItemAtCursor(&s_playermodel.menu);
- picnum = m->id - ID_PLAYERPIC0;
- if (picnum >= 0 && picnum <= 15)
- {
- if (picnum > 0)
- {
- Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor-1);
- return (menu_move_sound);
-
- }
- else if (s_playermodel.modelpage > 0)
- {
- s_playermodel.modelpage--;
- Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor+15);
- PlayerModel_UpdateGrid();
- return (menu_move_sound);
- }
- else
- return (menu_buzz_sound);
- }
- break;
-
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- m = Menu_ItemAtCursor(&s_playermodel.menu);
- picnum = m->id - ID_PLAYERPIC0;
- if (picnum >= 0 && picnum <= 15)
- {
- if ((picnum < 15) && (s_playermodel.modelpage*MAX_MODELSPERPAGE + picnum+1 < s_playermodel.nummodels))
- {
- Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor+1);
- return (menu_move_sound);
- }
- else if ((picnum == 15) && (s_playermodel.modelpage < s_playermodel.numpages-1))
- {
- s_playermodel.modelpage++;
- Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor-15);
- PlayerModel_UpdateGrid();
- return (menu_move_sound);
- }
- else
- return (menu_buzz_sound);
- }
- break;
-
- case K_MOUSE2:
- case K_ESCAPE:
- PlayerModel_SaveChanges();
- break;
- }
-
- return ( Menu_DefaultKey( &s_playermodel.menu, key ) );
-}
-
-/*
-=================
-PlayerModel_PicEvent
-=================
-*/
-static void PlayerModel_PicEvent( void* ptr, int event )
-{
- int modelnum;
- int maxlen;
- char* buffptr;
- char* pdest;
- int i;
-
- if (event != QM_ACTIVATED)
- return;
-
- for (i=0; i<PLAYERGRID_ROWS*PLAYERGRID_COLS; i++)
- {
- // reset
- s_playermodel.pics[i].generic.flags &= ~QMF_HIGHLIGHT;
- s_playermodel.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
- }
-
- // set selected
- i = ((menucommon_s*)ptr)->id - ID_PLAYERPIC0;
- s_playermodel.pics[i].generic.flags |= QMF_HIGHLIGHT;
- s_playermodel.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
-
- // get model and strip icon_
- modelnum = s_playermodel.modelpage*MAX_MODELSPERPAGE + i;
- buffptr = s_playermodel.modelnames[modelnum] + strlen("models/players/");
- pdest = strstr(buffptr,"icon_");
- if (pdest)
- {
- // track the whole model/skin name
- Q_strncpyz(s_playermodel.modelskin,buffptr,pdest-buffptr+1);
- strcat(s_playermodel.modelskin,pdest + 5);
-
- // seperate the model name
- maxlen = pdest-buffptr;
- if (maxlen > 16)
- maxlen = 16;
- Q_strncpyz( s_playermodel.modelname.string, buffptr, maxlen );
- Q_strupr( s_playermodel.modelname.string );
-
- // seperate the skin name
- maxlen = strlen(pdest+5)+1;
- if (maxlen > 16)
- maxlen = 16;
- Q_strncpyz( s_playermodel.skinname.string, pdest+5, maxlen );
- Q_strupr( s_playermodel.skinname.string );
-
- s_playermodel.selectedmodel = modelnum;
-
- if( trap_MemoryRemaining() > LOW_MEMORY ) {
- PlayerModel_UpdateModel();
- }
- }
-}
-
-/*
-=================
-PlayerModel_DrawPlayer
-=================
-*/
-static void PlayerModel_DrawPlayer( void *self )
-{
- menubitmap_s* b;
-
- b = (menubitmap_s*) self;
-
- if( trap_MemoryRemaining() <= LOW_MEMORY ) {
- UI_DrawProportionalString( b->generic.x, b->generic.y + b->height / 2, "LOW MEMORY", UI_LEFT, color_red );
- return;
- }
-
- UI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_playermodel.playerinfo, uis.realtime/2 );
-}
-
-/*
-=================
-PlayerModel_BuildList
-=================
-*/
-static void PlayerModel_BuildList( void )
-{
- int numdirs;
- int numfiles;
- char dirlist[2048];
- char filelist[2048];
- char skinname[MAX_QPATH];
- char* dirptr;
- char* fileptr;
- int i;
- int j;
- int dirlen;
- int filelen;
- qboolean precache;
-
- precache = trap_Cvar_VariableValue("com_buildscript");
-
- s_playermodel.modelpage = 0;
- s_playermodel.nummodels = 0;
-
- // iterate directory of all player models
- numdirs = trap_FS_GetFileList("models/players", "/", dirlist, 2048 );
- dirptr = dirlist;
- for (i=0; i<numdirs && s_playermodel.nummodels < MAX_PLAYERMODELS; i++,dirptr+=dirlen+1)
- {
- dirlen = strlen(dirptr);
-
- if (dirlen && dirptr[dirlen-1]=='/') dirptr[dirlen-1]='\0';
-
- if (!strcmp(dirptr,".") || !strcmp(dirptr,".."))
- continue;
-
- // iterate all skin files in directory
- numfiles = trap_FS_GetFileList( va("models/players/%s",dirptr), "tga", filelist, 2048 );
- fileptr = filelist;
- for (j=0; j<numfiles && s_playermodel.nummodels < MAX_PLAYERMODELS;j++,fileptr+=filelen+1)
- {
- filelen = strlen(fileptr);
-
- COM_StripExtension(fileptr,skinname, sizeof(skinname));
-
- // look for icon_????
- if (!Q_stricmpn(skinname,"icon_",5))
- {
- Com_sprintf( s_playermodel.modelnames[s_playermodel.nummodels++],
- sizeof( s_playermodel.modelnames[s_playermodel.nummodels] ),
- "models/players/%s/%s", dirptr, skinname );
- //if (s_playermodel.nummodels >= MAX_PLAYERMODELS)
- // return;
- }
-
- if( precache ) {
- trap_S_RegisterSound( va( "sound/player/announce/%s_wins.wav", skinname), qfalse );
- }
- }
- }
-
- //APSFIXME - Degenerate no models case
-
- s_playermodel.numpages = s_playermodel.nummodels/MAX_MODELSPERPAGE;
- if (s_playermodel.nummodels % MAX_MODELSPERPAGE)
- s_playermodel.numpages++;
-}
-
-/*
-=================
-PlayerModel_SetMenuItems
-=================
-*/
-static void PlayerModel_SetMenuItems( void )
-{
- int i;
- int maxlen;
- char modelskin[64];
- char* buffptr;
- char* pdest;
-
- // name
- trap_Cvar_VariableStringBuffer( "name", s_playermodel.playername.string, 16 );
- Q_CleanStr( s_playermodel.playername.string );
-
- // model
- trap_Cvar_VariableStringBuffer( "model", s_playermodel.modelskin, 64 );
-
- // find model in our list
- for (i=0; i<s_playermodel.nummodels; i++)
- {
- // strip icon_
- buffptr = s_playermodel.modelnames[i] + strlen("models/players/");
- pdest = strstr(buffptr,"icon_");
- if (pdest)
- {
- Q_strncpyz(modelskin,buffptr,pdest-buffptr+1);
- strcat(modelskin,pdest + 5);
- }
- else
- continue;
-
- if (!Q_stricmp( s_playermodel.modelskin, modelskin ))
- {
- // found pic, set selection here
- s_playermodel.selectedmodel = i;
- s_playermodel.modelpage = i/MAX_MODELSPERPAGE;
-
- // seperate the model name
- maxlen = pdest-buffptr;
- if (maxlen > 16)
- maxlen = 16;
- Q_strncpyz( s_playermodel.modelname.string, buffptr, maxlen );
- Q_strupr( s_playermodel.modelname.string );
-
- // seperate the skin name
- maxlen = strlen(pdest+5)+1;
- if (maxlen > 16)
- maxlen = 16;
- Q_strncpyz( s_playermodel.skinname.string, pdest+5, maxlen );
- Q_strupr( s_playermodel.skinname.string );
- break;
- }
- }
-}
-
-/*
-=================
-PlayerModel_MenuInit
-=================
-*/
-static void PlayerModel_MenuInit( void )
-{
- int i;
- int j;
- int k;
- int x;
- int y;
- static char playername[32];
- static char modelname[32];
- static char skinname[32];
-
- // zero set all our globals
- memset( &s_playermodel, 0 ,sizeof(playermodel_t) );
-
- PlayerModel_Cache();
-
- s_playermodel.menu.key = PlayerModel_MenuKey;
- s_playermodel.menu.wrapAround = qtrue;
- s_playermodel.menu.fullscreen = qtrue;
-
- s_playermodel.banner.generic.type = MTYPE_BTEXT;
- s_playermodel.banner.generic.x = 320;
- s_playermodel.banner.generic.y = 16;
- s_playermodel.banner.string = "PLAYER MODEL";
- s_playermodel.banner.color = color_white;
- s_playermodel.banner.style = UI_CENTER;
-
- s_playermodel.framel.generic.type = MTYPE_BITMAP;
- s_playermodel.framel.generic.name = MODEL_FRAMEL;
- s_playermodel.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_playermodel.framel.generic.x = 0;
- s_playermodel.framel.generic.y = 78;
- s_playermodel.framel.width = 256;
- s_playermodel.framel.height = 329;
-
- s_playermodel.framer.generic.type = MTYPE_BITMAP;
- s_playermodel.framer.generic.name = MODEL_FRAMER;
- s_playermodel.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_playermodel.framer.generic.x = 376;
- s_playermodel.framer.generic.y = 76;
- s_playermodel.framer.width = 256;
- s_playermodel.framer.height = 334;
-
- s_playermodel.ports.generic.type = MTYPE_BITMAP;
- s_playermodel.ports.generic.name = MODEL_PORTS;
- s_playermodel.ports.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_playermodel.ports.generic.x = 50;
- s_playermodel.ports.generic.y = 59;
- s_playermodel.ports.width = 274;
- s_playermodel.ports.height = 274;
-
- y = 59;
- for (i=0,k=0; i<PLAYERGRID_ROWS; i++)
- {
- x = 50;
- for (j=0; j<PLAYERGRID_COLS; j++,k++)
- {
- s_playermodel.pics[k].generic.type = MTYPE_BITMAP;
- s_playermodel.pics[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_playermodel.pics[k].generic.x = x;
- s_playermodel.pics[k].generic.y = y;
- s_playermodel.pics[k].width = 64;
- s_playermodel.pics[k].height = 64;
- s_playermodel.pics[k].focuspic = MODEL_SELECTED;
- s_playermodel.pics[k].focuscolor = colorRed;
-
- s_playermodel.picbuttons[k].generic.type = MTYPE_BITMAP;
- s_playermodel.picbuttons[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS;
- s_playermodel.picbuttons[k].generic.id = ID_PLAYERPIC0+k;
- s_playermodel.picbuttons[k].generic.callback = PlayerModel_PicEvent;
- s_playermodel.picbuttons[k].generic.x = x - 16;
- s_playermodel.picbuttons[k].generic.y = y - 16;
- s_playermodel.picbuttons[k].generic.left = x;
- s_playermodel.picbuttons[k].generic.top = y;
- s_playermodel.picbuttons[k].generic.right = x + 64;
- s_playermodel.picbuttons[k].generic.bottom = y + 64;
- s_playermodel.picbuttons[k].width = 128;
- s_playermodel.picbuttons[k].height = 128;
- s_playermodel.picbuttons[k].focuspic = MODEL_SELECT;
- s_playermodel.picbuttons[k].focuscolor = colorRed;
-
- x += 64+6;
- }
- y += 64+6;
- }
-
- s_playermodel.playername.generic.type = MTYPE_PTEXT;
- s_playermodel.playername.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
- s_playermodel.playername.generic.x = 320;
- s_playermodel.playername.generic.y = 440;
- s_playermodel.playername.string = playername;
- s_playermodel.playername.style = UI_CENTER;
- s_playermodel.playername.color = text_color_normal;
-
- s_playermodel.modelname.generic.type = MTYPE_PTEXT;
- s_playermodel.modelname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
- s_playermodel.modelname.generic.x = 497;
- s_playermodel.modelname.generic.y = 54;
- s_playermodel.modelname.string = modelname;
- s_playermodel.modelname.style = UI_CENTER;
- s_playermodel.modelname.color = text_color_normal;
-
- s_playermodel.skinname.generic.type = MTYPE_PTEXT;
- s_playermodel.skinname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
- s_playermodel.skinname.generic.x = 497;
- s_playermodel.skinname.generic.y = 394;
- s_playermodel.skinname.string = skinname;
- s_playermodel.skinname.style = UI_CENTER;
- s_playermodel.skinname.color = text_color_normal;
-
- s_playermodel.player.generic.type = MTYPE_BITMAP;
- s_playermodel.player.generic.flags = QMF_INACTIVE;
- s_playermodel.player.generic.ownerdraw = PlayerModel_DrawPlayer;
- s_playermodel.player.generic.x = 400;
- s_playermodel.player.generic.y = -40;
- s_playermodel.player.width = 32*10;
- s_playermodel.player.height = 56*10;
-
- s_playermodel.arrows.generic.type = MTYPE_BITMAP;
- s_playermodel.arrows.generic.name = MODEL_ARROWS;
- s_playermodel.arrows.generic.flags = QMF_INACTIVE;
- s_playermodel.arrows.generic.x = 125;
- s_playermodel.arrows.generic.y = 340;
- s_playermodel.arrows.width = 128;
- s_playermodel.arrows.height = 32;
-
- s_playermodel.left.generic.type = MTYPE_BITMAP;
- s_playermodel.left.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_playermodel.left.generic.callback = PlayerModel_MenuEvent;
- s_playermodel.left.generic.id = ID_PREVPAGE;
- s_playermodel.left.generic.x = 125;
- s_playermodel.left.generic.y = 340;
- s_playermodel.left.width = 64;
- s_playermodel.left.height = 32;
- s_playermodel.left.focuspic = MODEL_ARROWSL;
-
- s_playermodel.right.generic.type = MTYPE_BITMAP;
- s_playermodel.right.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_playermodel.right.generic.callback = PlayerModel_MenuEvent;
- s_playermodel.right.generic.id = ID_NEXTPAGE;
- s_playermodel.right.generic.x = 125+61;
- s_playermodel.right.generic.y = 340;
- s_playermodel.right.width = 64;
- s_playermodel.right.height = 32;
- s_playermodel.right.focuspic = MODEL_ARROWSR;
-
- s_playermodel.back.generic.type = MTYPE_BITMAP;
- s_playermodel.back.generic.name = MODEL_BACK0;
- s_playermodel.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_playermodel.back.generic.callback = PlayerModel_MenuEvent;
- s_playermodel.back.generic.id = ID_BACK;
- s_playermodel.back.generic.x = 0;
- s_playermodel.back.generic.y = 480-64;
- s_playermodel.back.width = 128;
- s_playermodel.back.height = 64;
- s_playermodel.back.focuspic = MODEL_BACK1;
-
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.banner );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.framel );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.framer );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.ports );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.playername );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.modelname );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.skinname );
-
- for (i=0; i<MAX_MODELSPERPAGE; i++)
- {
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.pics[i] );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.picbuttons[i] );
- }
-
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.player );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.arrows );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.left );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.right );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.back );
-
- // find all available models
-// PlayerModel_BuildList();
-
- // set initial states
- PlayerModel_SetMenuItems();
-
- // update user interface
- PlayerModel_UpdateGrid();
- PlayerModel_UpdateModel();
-}
-
-/*
-=================
-PlayerModel_Cache
-=================
-*/
-void PlayerModel_Cache( void )
-{
- int i;
-
- for( i = 0; playermodel_artlist[i]; i++ ) {
- trap_R_RegisterShaderNoMip( playermodel_artlist[i] );
- }
-
- PlayerModel_BuildList();
- for( i = 0; i < s_playermodel.nummodels; i++ ) {
- trap_R_RegisterShaderNoMip( s_playermodel.modelnames[i] );
- }
-}
-
-void UI_PlayerModelMenu(void)
-{
- PlayerModel_MenuInit();
-
- UI_PushMenu( &s_playermodel.menu );
-
- Menu_SetCursorToItem( &s_playermodel.menu, &s_playermodel.pics[s_playermodel.selectedmodel % MAX_MODELSPERPAGE] );
-}
-
-
diff --git a/engine/code/q3_ui/ui_players.c b/engine/code/q3_ui/ui_players.c
deleted file mode 100644
index 182b5f0..0000000
--- a/engine/code/q3_ui/ui_players.c
+++ /dev/null
@@ -1,1249 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// ui_players.c
-
-#include "ui_local.h"
-
-
-#define UI_TIMER_GESTURE 2300
-#define UI_TIMER_JUMP 1000
-#define UI_TIMER_LAND 130
-#define UI_TIMER_WEAPON_SWITCH 300
-#define UI_TIMER_ATTACK 500
-#define UI_TIMER_MUZZLE_FLASH 20
-#define UI_TIMER_WEAPON_DELAY 250
-
-#define JUMP_HEIGHT 56
-
-#define SWINGSPEED 0.3f
-
-#define SPIN_SPEED 0.9f
-#define COAST_TIME 1000
-
-
-static int dp_realtime;
-static float jumpHeight;
-
-
-/*
-===============
-UI_PlayerInfo_SetWeapon
-===============
-*/
-static void UI_PlayerInfo_SetWeapon( playerInfo_t *pi, weapon_t weaponNum ) {
- gitem_t * item;
- char path[MAX_QPATH];
-
- pi->currentWeapon = weaponNum;
-tryagain:
- pi->realWeapon = weaponNum;
- pi->weaponModel = 0;
- pi->barrelModel = 0;
- pi->flashModel = 0;
-
- if ( weaponNum == WP_NONE ) {
- return;
- }
-
- for ( item = bg_itemlist + 1; item->classname ; item++ ) {
- if ( item->giType != IT_WEAPON ) {
- continue;
- }
- if ( item->giTag == weaponNum ) {
- break;
- }
- }
-
- if ( item->classname ) {
- pi->weaponModel = trap_R_RegisterModel( item->world_model[0] );
- }
-
- if( pi->weaponModel == 0 ) {
- if( weaponNum == WP_MACHINEGUN ) {
- weaponNum = WP_NONE;
- goto tryagain;
- }
- weaponNum = WP_MACHINEGUN;
- goto tryagain;
- }
-
- if ( weaponNum == WP_MACHINEGUN || weaponNum == WP_GAUNTLET || weaponNum == WP_BFG ) {
- strcpy( path, item->world_model[0] );
- COM_StripExtension( path, path, sizeof(path) );
- strcat( path, "_barrel.md3" );
- pi->barrelModel = trap_R_RegisterModel( path );
- }
-
- strcpy( path, item->world_model[0] );
- COM_StripExtension( path, path, sizeof(path) );
- strcat( path, "_flash.md3" );
- pi->flashModel = trap_R_RegisterModel( path );
-
- switch( weaponNum ) {
- case WP_GAUNTLET:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_MACHINEGUN:
- MAKERGB( pi->flashDlightColor, 1, 1, 0 );
- break;
-
- case WP_SHOTGUN:
- MAKERGB( pi->flashDlightColor, 1, 1, 0 );
- break;
-
- case WP_GRENADE_LAUNCHER:
- MAKERGB( pi->flashDlightColor, 1, 0.7f, 0.5f );
- break;
-
- case WP_ROCKET_LAUNCHER:
- MAKERGB( pi->flashDlightColor, 1, 0.75f, 0 );
- break;
-
- case WP_LIGHTNING:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_RAILGUN:
- MAKERGB( pi->flashDlightColor, 1, 0.5f, 0 );
- break;
-
- case WP_PLASMAGUN:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_BFG:
- MAKERGB( pi->flashDlightColor, 1, 0.7f, 1 );
- break;
-
- case WP_GRAPPLING_HOOK:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- default:
- MAKERGB( pi->flashDlightColor, 1, 1, 1 );
- break;
- }
-}
-
-
-/*
-===============
-UI_ForceLegsAnim
-===============
-*/
-static void UI_ForceLegsAnim( playerInfo_t *pi, int anim ) {
- pi->legsAnim = ( ( pi->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-
- if ( anim == LEGS_JUMP ) {
- pi->legsAnimationTimer = UI_TIMER_JUMP;
- }
-}
-
-
-/*
-===============
-UI_SetLegsAnim
-===============
-*/
-static void UI_SetLegsAnim( playerInfo_t *pi, int anim ) {
- if ( pi->pendingLegsAnim ) {
- anim = pi->pendingLegsAnim;
- pi->pendingLegsAnim = 0;
- }
- UI_ForceLegsAnim( pi, anim );
-}
-
-
-/*
-===============
-UI_ForceTorsoAnim
-===============
-*/
-static void UI_ForceTorsoAnim( playerInfo_t *pi, int anim ) {
- pi->torsoAnim = ( ( pi->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-
- if ( anim == TORSO_GESTURE ) {
- pi->torsoAnimationTimer = UI_TIMER_GESTURE;
- }
-
- if ( anim == TORSO_ATTACK || anim == TORSO_ATTACK2 ) {
- pi->torsoAnimationTimer = UI_TIMER_ATTACK;
- }
-}
-
-
-/*
-===============
-UI_SetTorsoAnim
-===============
-*/
-static void UI_SetTorsoAnim( playerInfo_t *pi, int anim ) {
- if ( pi->pendingTorsoAnim ) {
- anim = pi->pendingTorsoAnim;
- pi->pendingTorsoAnim = 0;
- }
-
- UI_ForceTorsoAnim( pi, anim );
-}
-
-
-/*
-===============
-UI_TorsoSequencing
-===============
-*/
-static void UI_TorsoSequencing( playerInfo_t *pi ) {
- int currentAnim;
-
- currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
-
- if ( pi->weapon != pi->currentWeapon ) {
- if ( currentAnim != TORSO_DROP ) {
- pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
- UI_ForceTorsoAnim( pi, TORSO_DROP );
- }
- }
-
- if ( pi->torsoAnimationTimer > 0 ) {
- return;
- }
-
- if( currentAnim == TORSO_GESTURE ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-
- if( currentAnim == TORSO_ATTACK || currentAnim == TORSO_ATTACK2 ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-
- if ( currentAnim == TORSO_DROP ) {
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
- pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
- UI_ForceTorsoAnim( pi, TORSO_RAISE );
- return;
- }
-
- if ( currentAnim == TORSO_RAISE ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-}
-
-
-/*
-===============
-UI_LegsSequencing
-===============
-*/
-static void UI_LegsSequencing( playerInfo_t *pi ) {
- int currentAnim;
-
- currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
-
- if ( pi->legsAnimationTimer > 0 ) {
- if ( currentAnim == LEGS_JUMP ) {
- jumpHeight = JUMP_HEIGHT * sin( M_PI * ( UI_TIMER_JUMP - pi->legsAnimationTimer ) / UI_TIMER_JUMP );
- }
- return;
- }
-
- if ( currentAnim == LEGS_JUMP ) {
- UI_ForceLegsAnim( pi, LEGS_LAND );
- pi->legsAnimationTimer = UI_TIMER_LAND;
- jumpHeight = 0;
- return;
- }
-
- if ( currentAnim == LEGS_LAND ) {
- UI_SetLegsAnim( pi, LEGS_IDLE );
- return;
- }
-}
-
-
-/*
-======================
-UI_PositionEntityOnTag
-======================
-*/
-static void UI_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- clipHandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
-
- // lerp the tag
- trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // cast away const because of compiler problems
- MatrixMultiply( lerped.axis, ((refEntity_t*)parent)->axis, entity->axis );
- entity->backlerp = parent->backlerp;
-}
-
-
-/*
-======================
-UI_PositionRotatedEntityOnTag
-======================
-*/
-static void UI_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- clipHandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
- vec3_t tempAxis[3];
-
- // lerp the tag
- trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // cast away const because of compiler problems
- MatrixMultiply( entity->axis, ((refEntity_t *)parent)->axis, tempAxis );
- MatrixMultiply( lerped.axis, tempAxis, entity->axis );
-}
-
-
-/*
-===============
-UI_SetLerpFrameAnimation
-===============
-*/
-static void UI_SetLerpFrameAnimation( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
- animation_t *anim;
-
- lf->animationNumber = newAnimation;
- newAnimation &= ~ANIM_TOGGLEBIT;
-
- if ( newAnimation < 0 || newAnimation >= MAX_ANIMATIONS ) {
- trap_Error( va("Bad animation number: %i", newAnimation) );
- }
-
- anim = &ci->animations[ newAnimation ];
-
- lf->animation = anim;
- lf->animationTime = lf->frameTime + anim->initialLerp;
-}
-
-
-/*
-===============
-UI_RunLerpFrame
-===============
-*/
-static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
- int f;
- animation_t *anim;
-
- // see if the animation sequence is switching
- if ( newAnimation != lf->animationNumber || !lf->animation ) {
- UI_SetLerpFrameAnimation( ci, lf, newAnimation );
- }
-
- // if we have passed the current frame, move it to
- // oldFrame and calculate a new frame
- if ( dp_realtime >= lf->frameTime ) {
- lf->oldFrame = lf->frame;
- lf->oldFrameTime = lf->frameTime;
-
- // get the next frame based on the animation
- anim = lf->animation;
- if ( dp_realtime < lf->animationTime ) {
- lf->frameTime = lf->animationTime; // initial lerp
- } else {
- lf->frameTime = lf->oldFrameTime + anim->frameLerp;
- }
- f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
- if ( f >= anim->numFrames ) {
- f -= anim->numFrames;
- if ( anim->loopFrames ) {
- f %= anim->loopFrames;
- f += anim->numFrames - anim->loopFrames;
- } else {
- f = anim->numFrames - 1;
- // the animation is stuck at the end, so it
- // can immediately transition to another sequence
- lf->frameTime = dp_realtime;
- }
- }
- lf->frame = anim->firstFrame + f;
- if ( dp_realtime > lf->frameTime ) {
- lf->frameTime = dp_realtime;
- }
- }
-
- if ( lf->frameTime > dp_realtime + 200 ) {
- lf->frameTime = dp_realtime;
- }
-
- if ( lf->oldFrameTime > dp_realtime ) {
- lf->oldFrameTime = dp_realtime;
- }
- // calculate current lerp value
- if ( lf->frameTime == lf->oldFrameTime ) {
- lf->backlerp = 0;
- } else {
- lf->backlerp = 1.0 - (float)( dp_realtime - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
- }
-}
-
-
-/*
-===============
-UI_PlayerAnimation
-===============
-*/
-static void UI_PlayerAnimation( playerInfo_t *pi, int *legsOld, int *legs, float *legsBackLerp,
- int *torsoOld, int *torso, float *torsoBackLerp ) {
-
- // legs animation
- pi->legsAnimationTimer -= uis.frametime;
- if ( pi->legsAnimationTimer < 0 ) {
- pi->legsAnimationTimer = 0;
- }
-
- UI_LegsSequencing( pi );
-
- if ( pi->legs.yawing && ( pi->legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {
- UI_RunLerpFrame( pi, &pi->legs, LEGS_TURN );
- } else {
- UI_RunLerpFrame( pi, &pi->legs, pi->legsAnim );
- }
- *legsOld = pi->legs.oldFrame;
- *legs = pi->legs.frame;
- *legsBackLerp = pi->legs.backlerp;
-
- // torso animation
- pi->torsoAnimationTimer -= uis.frametime;
- if ( pi->torsoAnimationTimer < 0 ) {
- pi->torsoAnimationTimer = 0;
- }
-
- UI_TorsoSequencing( pi );
-
- UI_RunLerpFrame( pi, &pi->torso, pi->torsoAnim );
- *torsoOld = pi->torso.oldFrame;
- *torso = pi->torso.frame;
- *torsoBackLerp = pi->torso.backlerp;
-}
-
-
-/*
-==================
-UI_SwingAngles
-==================
-*/
-static void UI_SwingAngles( float destination, float swingTolerance, float clampTolerance,
- float speed, float *angle, qboolean *swinging ) {
- float swing;
- float move;
- float scale;
-
- if ( !*swinging ) {
- // see if a swing should be started
- swing = AngleSubtract( *angle, destination );
- if ( swing > swingTolerance || swing < -swingTolerance ) {
- *swinging = qtrue;
- }
- }
-
- if ( !*swinging ) {
- return;
- }
-
- // modify the speed depending on the delta
- // so it doesn't seem so linear
- swing = AngleSubtract( destination, *angle );
- scale = fabs( swing );
- if ( scale < swingTolerance * 0.5 ) {
- scale = 0.5;
- } else if ( scale < swingTolerance ) {
- scale = 1.0;
- } else {
- scale = 2.0;
- }
-
- // swing towards the destination angle
- if ( swing >= 0 ) {
- move = uis.frametime * scale * speed;
- if ( move >= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- } else if ( swing < 0 ) {
- move = uis.frametime * scale * -speed;
- if ( move <= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- }
-
- // clamp to no more than tolerance
- swing = AngleSubtract( destination, *angle );
- if ( swing > clampTolerance ) {
- *angle = AngleMod( destination - (clampTolerance - 1) );
- } else if ( swing < -clampTolerance ) {
- *angle = AngleMod( destination + (clampTolerance - 1) );
- }
-}
-
-
-/*
-======================
-UI_MovedirAdjustment
-======================
-*/
-static float UI_MovedirAdjustment( playerInfo_t *pi ) {
- vec3_t relativeAngles;
- vec3_t moveVector;
-
- VectorSubtract( pi->viewAngles, pi->moveAngles, relativeAngles );
- AngleVectors( relativeAngles, moveVector, NULL, NULL );
- if ( Q_fabs( moveVector[0] ) < 0.01 ) {
- moveVector[0] = 0.0;
- }
- if ( Q_fabs( moveVector[1] ) < 0.01 ) {
- moveVector[1] = 0.0;
- }
-
- if ( moveVector[1] == 0 && moveVector[0] > 0 ) {
- return 0;
- }
- if ( moveVector[1] < 0 && moveVector[0] > 0 ) {
- return 22;
- }
- if ( moveVector[1] < 0 && moveVector[0] == 0 ) {
- return 45;
- }
- if ( moveVector[1] < 0 && moveVector[0] < 0 ) {
- return -22;
- }
- if ( moveVector[1] == 0 && moveVector[0] < 0 ) {
- return 0;
- }
- if ( moveVector[1] > 0 && moveVector[0] < 0 ) {
- return 22;
- }
- if ( moveVector[1] > 0 && moveVector[0] == 0 ) {
- return -45;
- }
-
- return -22;
-}
-
-
-/*
-===============
-UI_PlayerAngles
-===============
-*/
-static void UI_PlayerAngles( playerInfo_t *pi, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {
- vec3_t legsAngles, torsoAngles, headAngles;
- float dest;
- float adjust;
-
- VectorCopy( pi->viewAngles, headAngles );
- headAngles[YAW] = AngleMod( headAngles[YAW] );
- VectorClear( legsAngles );
- VectorClear( torsoAngles );
-
- // --------- yaw -------------
-
- // allow yaw to drift a bit
- if ( ( pi->legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE
- || ( pi->torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) {
- // if not standing still, always point all in the same direction
- pi->torso.yawing = qtrue; // always center
- pi->torso.pitching = qtrue; // always center
- pi->legs.yawing = qtrue; // always center
- }
-
- // adjust legs for movement dir
- adjust = UI_MovedirAdjustment( pi );
- legsAngles[YAW] = headAngles[YAW] + adjust;
- torsoAngles[YAW] = headAngles[YAW] + 0.25 * adjust;
-
-
- // torso
- UI_SwingAngles( torsoAngles[YAW], 25, 90, SWINGSPEED, &pi->torso.yawAngle, &pi->torso.yawing );
- UI_SwingAngles( legsAngles[YAW], 40, 90, SWINGSPEED, &pi->legs.yawAngle, &pi->legs.yawing );
-
- torsoAngles[YAW] = pi->torso.yawAngle;
- legsAngles[YAW] = pi->legs.yawAngle;
-
- // --------- pitch -------------
-
- // only show a fraction of the pitch angle in the torso
- if ( headAngles[PITCH] > 180 ) {
- dest = (-360 + headAngles[PITCH]) * 0.75;
- } else {
- dest = headAngles[PITCH] * 0.75;
- }
- UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching );
- torsoAngles[PITCH] = pi->torso.pitchAngle;
-
- // pull the angles back out of the hierarchial chain
- AnglesSubtract( headAngles, torsoAngles, headAngles );
- AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
- AnglesToAxis( legsAngles, legs );
- AnglesToAxis( torsoAngles, torso );
- AnglesToAxis( headAngles, head );
-}
-
-
-/*
-===============
-UI_PlayerFloatSprite
-===============
-*/
-static void UI_PlayerFloatSprite( playerInfo_t *pi, vec3_t origin, qhandle_t shader ) {
- refEntity_t ent;
-
- memset( &ent, 0, sizeof( ent ) );
- VectorCopy( origin, ent.origin );
- ent.origin[2] += 48;
- ent.reType = RT_SPRITE;
- ent.customShader = shader;
- ent.radius = 10;
- ent.renderfx = 0;
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-/*
-======================
-UI_MachinegunSpinAngle
-======================
-*/
-float UI_MachinegunSpinAngle( playerInfo_t *pi ) {
- int delta;
- float angle;
- float speed;
- int torsoAnim;
-
- delta = dp_realtime - pi->barrelTime;
- if ( pi->barrelSpinning ) {
- angle = pi->barrelAngle + delta * SPIN_SPEED;
- } else {
- if ( delta > COAST_TIME ) {
- delta = COAST_TIME;
- }
-
- speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
- angle = pi->barrelAngle + delta * speed;
- }
-
- torsoAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
- if( torsoAnim == TORSO_ATTACK2 ) {
- torsoAnim = TORSO_ATTACK;
- }
- if ( pi->barrelSpinning == !(torsoAnim == TORSO_ATTACK) ) {
- pi->barrelTime = dp_realtime;
- pi->barrelAngle = AngleMod( angle );
- pi->barrelSpinning = !!(torsoAnim == TORSO_ATTACK);
- }
-
- return angle;
-}
-
-
-/*
-===============
-UI_DrawPlayer
-===============
-*/
-void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ) {
- refdef_t refdef;
- refEntity_t legs;
- refEntity_t torso;
- refEntity_t head;
- refEntity_t gun;
- refEntity_t barrel;
- refEntity_t flash;
- vec3_t origin;
- int renderfx;
- vec3_t mins = {-16, -16, -24};
- vec3_t maxs = {16, 16, 32};
- float len;
- float xx;
-
- if ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) {
- return;
- }
-
- dp_realtime = time;
-
- if ( pi->pendingWeapon != -1 && dp_realtime > pi->weaponTimer ) {
- pi->weapon = pi->pendingWeapon;
- pi->lastWeapon = pi->pendingWeapon;
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- if( pi->currentWeapon != pi->weapon ) {
- trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL );
- }
- }
-
- UI_AdjustFrom640( &x, &y, &w, &h );
-
- y -= jumpHeight;
-
- memset( &refdef, 0, sizeof( refdef ) );
- memset( &legs, 0, sizeof(legs) );
- memset( &torso, 0, sizeof(torso) );
- memset( &head, 0, sizeof(head) );
-
- refdef.rdflags = RDF_NOWORLDMODEL;
-
- AxisClear( refdef.viewaxis );
-
- refdef.x = x;
- refdef.y = y;
- refdef.width = w;
- refdef.height = h;
-
- refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
- xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
- refdef.fov_y = atan2( refdef.height, xx );
- refdef.fov_y *= ( 360 / M_PI );
-
- // calculate distance so the player nearly fills the box
- len = 0.7 * ( maxs[2] - mins[2] );
- origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
-
- refdef.time = dp_realtime;
-
- trap_R_ClearScene();
-
- // get the rotation information
- UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis );
-
- // get the animation state (after rotation, to allow feet shuffle)
- UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp,
- &torso.oldframe, &torso.frame, &torso.backlerp );
-
- renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
-
- //
- // add the legs
- //
- legs.hModel = pi->legsModel;
- legs.customSkin = pi->legsSkin;
-
- VectorCopy( origin, legs.origin );
-
- VectorCopy( origin, legs.lightingOrigin );
- legs.renderfx = renderfx;
- VectorCopy (legs.origin, legs.oldorigin);
-
- trap_R_AddRefEntityToScene( &legs );
-
- if (!legs.hModel) {
- return;
- }
-
- //
- // add the torso
- //
- torso.hModel = pi->torsoModel;
- if (!torso.hModel) {
- return;
- }
-
- torso.customSkin = pi->torsoSkin;
-
- VectorCopy( origin, torso.lightingOrigin );
-
- UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, "tag_torso");
-
- torso.renderfx = renderfx;
-
- trap_R_AddRefEntityToScene( &torso );
-
- //
- // add the head
- //
- head.hModel = pi->headModel;
- if (!head.hModel) {
- return;
- }
- head.customSkin = pi->headSkin;
-
- VectorCopy( origin, head.lightingOrigin );
-
- UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, "tag_head");
-
- head.renderfx = renderfx;
-
- trap_R_AddRefEntityToScene( &head );
-
- //
- // add the gun
- //
- if ( pi->currentWeapon != WP_NONE ) {
- memset( &gun, 0, sizeof(gun) );
- gun.hModel = pi->weaponModel;
- VectorCopy( origin, gun.lightingOrigin );
- UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, "tag_weapon");
- gun.renderfx = renderfx;
- trap_R_AddRefEntityToScene( &gun );
- }
-
- //
- // add the spinning barrel
- //
- if ( pi->realWeapon == WP_MACHINEGUN || pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
- vec3_t angles;
-
- memset( &barrel, 0, sizeof(barrel) );
- VectorCopy( origin, barrel.lightingOrigin );
- barrel.renderfx = renderfx;
-
- barrel.hModel = pi->barrelModel;
- angles[YAW] = 0;
- angles[PITCH] = 0;
- angles[ROLL] = UI_MachinegunSpinAngle( pi );
- if( pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
- angles[PITCH] = angles[ROLL];
- angles[ROLL] = 0;
- }
- AnglesToAxis( angles, barrel.axis );
-
- UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel");
-
- trap_R_AddRefEntityToScene( &barrel );
- }
-
- //
- // add muzzle flash
- //
- if ( dp_realtime <= pi->muzzleFlashTime ) {
- if ( pi->flashModel ) {
- memset( &flash, 0, sizeof(flash) );
- flash.hModel = pi->flashModel;
- VectorCopy( origin, flash.lightingOrigin );
- UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash");
- flash.renderfx = renderfx;
- trap_R_AddRefEntityToScene( &flash );
- }
-
- // make a dlight for the flash
- if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) {
- trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), pi->flashDlightColor[0],
- pi->flashDlightColor[1], pi->flashDlightColor[2] );
- }
- }
-
- //
- // add the chat icon
- //
- if ( pi->chat ) {
- UI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) );
- }
-
- //
- // add an accent light
- //
- origin[0] -= 100; // + = behind, - = in front
- origin[1] += 100; // + = left, - = right
- origin[2] += 100; // + = above, - = below
- trap_R_AddLightToScene( origin, 500, 1.0, 1.0, 1.0 );
-
- origin[0] -= 100;
- origin[1] -= 100;
- origin[2] -= 100;
- trap_R_AddLightToScene( origin, 500, 1.0, 0.0, 0.0 );
-
- trap_R_RenderScene( &refdef );
-}
-
-
-/*
-==========================
-UI_RegisterClientSkin
-==========================
-*/
-static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, const char *skinName ) {
- char filename[MAX_QPATH];
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName );
- pi->legsSkin = trap_R_RegisterSkin( filename );
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName );
- pi->torsoSkin = trap_R_RegisterSkin( filename );
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/head_%s.skin", modelName, skinName );
- pi->headSkin = trap_R_RegisterSkin( filename );
-
- if ( !pi->legsSkin || !pi->torsoSkin || !pi->headSkin ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-======================
-UI_ParseAnimationFile
-======================
-*/
-static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) {
- char *text_p, *prev;
- int len;
- int i;
- char *token;
- float fps;
- int skip;
- char text[20000];
- fileHandle_t f;
-
- memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS );
-
- // load the file
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( len <= 0 ) {
- return qfalse;
- }
- if ( len >= ( sizeof( text ) - 1 ) ) {
- Com_Printf( "File %s too long\n", filename );
- trap_FS_FCloseFile( f );
- return qfalse;
- }
- trap_FS_Read( text, len, f );
- text[len] = 0;
- trap_FS_FCloseFile( f );
-
- // parse the text
- text_p = text;
- skip = 0; // quite the compiler warning
-
- // read optional parameters
- while ( 1 ) {
- prev = text_p; // so we can unget
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( !Q_stricmp( token, "footsteps" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- continue;
- } else if ( !Q_stricmp( token, "headoffset" ) ) {
- for ( i = 0 ; i < 3 ; i++ ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- }
- continue;
- } else if ( !Q_stricmp( token, "sex" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- continue;
- }
-
- // if it is a number, start parsing animations
- if ( token[0] >= '0' && token[0] <= '9' ) {
- text_p = prev; // unget the token
- break;
- }
-
- Com_Printf( "unknown token '%s' is %s\n", token, filename );
- }
-
- // read information for each frame
- for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].firstFrame = atoi( token );
- // leg only frames are adjusted to not count the upper body only frames
- if ( i == LEGS_WALKCR ) {
- skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
- }
- if ( i >= LEGS_WALKCR ) {
- animations[i].firstFrame -= skip;
- }
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].numFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].loopFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- fps = atof( token );
- if ( fps == 0 ) {
- fps = 1;
- }
- animations[i].frameLerp = 1000 / fps;
- animations[i].initialLerp = 1000 / fps;
- }
-
- if ( i != MAX_ANIMATIONS ) {
- Com_Printf( "Error parsing animation file: %s", filename );
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-==========================
-UI_RegisterClientModelname
-==========================
-*/
-qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName ) {
- char modelName[MAX_QPATH];
- char skinName[MAX_QPATH];
- char filename[MAX_QPATH];
- char *slash;
-
- pi->torsoModel = 0;
- pi->headModel = 0;
-
- if ( !modelSkinName[0] ) {
- return qfalse;
- }
-
- Q_strncpyz( modelName, modelSkinName, sizeof( modelName ) );
-
- slash = strchr( modelName, '/' );
- if ( !slash ) {
- // modelName did not include a skin name
- Q_strncpyz( skinName, "default", sizeof( skinName ) );
- } else {
- Q_strncpyz( skinName, slash + 1, sizeof( skinName ) );
- // truncate modelName
- *slash = 0;
- }
-
- // load cmodels before models so filecache works
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
- pi->legsModel = trap_R_RegisterModel( filename );
- if ( !pi->legsModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
- pi->torsoModel = trap_R_RegisterModel( filename );
- if ( !pi->torsoModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", modelName );
- pi->headModel = trap_R_RegisterModel( filename );
- if ( !pi->headModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
-
- // if any skins failed to load, fall back to default
- if ( !UI_RegisterClientSkin( pi, modelName, skinName ) ) {
- if ( !UI_RegisterClientSkin( pi, modelName, "default" ) ) {
- Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName );
- return qfalse;
- }
- }
-
- // load the animations
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
- if ( !UI_ParseAnimationFile( filename, pi->animations ) ) {
- Com_Printf( "Failed to load animation file %s\n", filename );
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-===============
-UI_PlayerInfo_SetModel
-===============
-*/
-void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model ) {
- memset( pi, 0, sizeof(*pi) );
- UI_RegisterClientModelname( pi, model );
- pi->weapon = WP_MACHINEGUN;
- pi->currentWeapon = pi->weapon;
- pi->lastWeapon = pi->weapon;
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- pi->chat = qfalse;
- pi->newModel = qtrue;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
-}
-
-
-/*
-===============
-UI_PlayerInfo_SetInfo
-===============
-*/
-void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) {
- int currentAnim;
- weapon_t weaponNum;
-
- pi->chat = chat;
-
- // view angles
- VectorCopy( viewAngles, pi->viewAngles );
-
- // move angles
- VectorCopy( moveAngles, pi->moveAngles );
-
- if ( pi->newModel ) {
- pi->newModel = qfalse;
-
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
- pi->legs.yawAngle = viewAngles[YAW];
- pi->legs.yawing = qfalse;
-
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
- pi->torso.yawAngle = viewAngles[YAW];
- pi->torso.yawing = qfalse;
-
- if ( weaponNumber != -1 ) {
- pi->weapon = weaponNumber;
- pi->currentWeapon = weaponNumber;
- pi->lastWeapon = weaponNumber;
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
- }
-
- return;
- }
-
- // weapon
- if ( weaponNumber == -1 ) {
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- }
- else if ( weaponNumber != WP_NONE ) {
- pi->pendingWeapon = weaponNumber;
- pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY;
- }
- weaponNum = pi->lastWeapon;
- pi->weapon = weaponNum;
-
- if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) {
- torsoAnim = legsAnim = BOTH_DEATH1;
- pi->weapon = pi->currentWeapon = WP_NONE;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
-
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
-
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
-
- return;
- }
-
- // leg animation
- currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
- if ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) {
- pi->pendingLegsAnim = legsAnim;
- }
- else if ( legsAnim != currentAnim ) {
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
- }
-
- // torso animation
- if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) {
- if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
- torsoAnim = TORSO_STAND2;
- }
- else {
- torsoAnim = TORSO_STAND;
- }
- }
-
- if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) {
- if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
- torsoAnim = TORSO_ATTACK2;
- }
- else {
- torsoAnim = TORSO_ATTACK;
- }
- pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH;
- //FIXME play firing sound here
- }
-
- currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
-
- if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) {
- pi->pendingTorsoAnim = torsoAnim;
- }
- else if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) {
- pi->pendingTorsoAnim = torsoAnim;
- }
- else if ( torsoAnim != currentAnim ) {
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
- }
-}
diff --git a/engine/code/q3_ui/ui_playersettings.c b/engine/code/q3_ui/ui_playersettings.c
deleted file mode 100644
index df4b2d1..0000000
--- a/engine/code/q3_ui/ui_playersettings.c
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-#define ART_FRAMEL "menu/art/frame2_l"
-#define ART_FRAMER "menu/art/frame1_r"
-#define ART_MODEL0 "menu/art/model_0"
-#define ART_MODEL1 "menu/art/model_1"
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-#define ART_FX_BASE "menu/art/fx_base"
-#define ART_FX_BLUE "menu/art/fx_blue"
-#define ART_FX_CYAN "menu/art/fx_cyan"
-#define ART_FX_GREEN "menu/art/fx_grn"
-#define ART_FX_RED "menu/art/fx_red"
-#define ART_FX_TEAL "menu/art/fx_teal"
-#define ART_FX_WHITE "menu/art/fx_white"
-#define ART_FX_YELLOW "menu/art/fx_yel"
-
-#define ID_NAME 10
-#define ID_HANDICAP 11
-#define ID_EFFECTS 12
-#define ID_BACK 13
-#define ID_MODEL 14
-
-#define MAX_NAMELENGTH 20
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
- menubitmap_s player;
-
- menufield_s name;
- menulist_s handicap;
- menulist_s effects;
-
- menubitmap_s back;
- menubitmap_s model;
- menubitmap_s item_null;
-
- qhandle_t fxBasePic;
- qhandle_t fxPic[7];
- playerInfo_t playerinfo;
- int current_fx;
- char playerModel[MAX_QPATH];
-} playersettings_t;
-
-static playersettings_t s_playersettings;
-
-static int gamecodetoui[] = {4,2,3,0,5,1,6};
-static int uitogamecode[] = {4,6,2,3,1,5,7};
-
-static const char *handicap_items[] = {
- "None",
- "95",
- "90",
- "85",
- "80",
- "75",
- "70",
- "65",
- "60",
- "55",
- "50",
- "45",
- "40",
- "35",
- "30",
- "25",
- "20",
- "15",
- "10",
- "5",
- NULL
-};
-
-
-/*
-=================
-PlayerSettings_DrawName
-=================
-*/
-static void PlayerSettings_DrawName( void *self ) {
- menufield_s *f;
- qboolean focus;
- int style;
- char *txt;
- char c;
- float *color;
- int n;
- int basex, x, y;
- char name[32];
-
- f = (menufield_s*)self;
- basex = f->generic.x;
- y = f->generic.y;
- focus = (f->generic.parent->cursor == f->generic.menuPosition);
-
- style = UI_LEFT|UI_SMALLFONT;
- color = text_color_normal;
- if( focus ) {
- style |= UI_PULSE;
- color = text_color_highlight;
- }
-
- UI_DrawProportionalString( basex, y, "Name", style, color );
-
- // draw the actual name
- basex += 64;
- y += PROP_HEIGHT;
- txt = f->field.buffer;
- color = g_color_table[ColorIndex(COLOR_WHITE)];
- x = basex;
- while ( (c = *txt) != 0 ) {
- if ( !focus && Q_IsColorString( txt ) ) {
- n = ColorIndex( *(txt+1) );
- if( n == 0 ) {
- n = 7;
- }
- color = g_color_table[n];
- txt += 2;
- continue;
- }
- UI_DrawChar( x, y, c, style, color );
- txt++;
- x += SMALLCHAR_WIDTH;
- }
-
- // draw cursor if we have focus
- if( focus ) {
- if ( trap_Key_GetOverstrikeMode() ) {
- c = 11;
- } else {
- c = 10;
- }
-
- style &= ~UI_PULSE;
- style |= UI_BLINK;
-
- UI_DrawChar( basex + f->field.cursor * SMALLCHAR_WIDTH, y, c, style, color_white );
- }
-
- // draw at bottom also using proportional font
- Q_strncpyz( name, f->field.buffer, sizeof(name) );
- Q_CleanStr( name );
- UI_DrawProportionalString( 320, 440, name, UI_CENTER|UI_BIGFONT, text_color_normal );
-}
-
-
-/*
-=================
-PlayerSettings_DrawHandicap
-=================
-*/
-static void PlayerSettings_DrawHandicap( void *self ) {
- menulist_s *item;
- qboolean focus;
- int style;
- float *color;
-
- item = (menulist_s *)self;
- focus = (item->generic.parent->cursor == item->generic.menuPosition);
-
- style = UI_LEFT|UI_SMALLFONT;
- color = text_color_normal;
- if( focus ) {
- style |= UI_PULSE;
- color = text_color_highlight;
- }
-
- UI_DrawProportionalString( item->generic.x, item->generic.y, "Handicap", style, color );
- UI_DrawProportionalString( item->generic.x + 64, item->generic.y + PROP_HEIGHT, handicap_items[item->curvalue], style, color );
-}
-
-
-/*
-=================
-PlayerSettings_DrawEffects
-=================
-*/
-static void PlayerSettings_DrawEffects( void *self ) {
- menulist_s *item;
- qboolean focus;
- int style;
- float *color;
-
- item = (menulist_s *)self;
- focus = (item->generic.parent->cursor == item->generic.menuPosition);
-
- style = UI_LEFT|UI_SMALLFONT;
- color = text_color_normal;
- if( focus ) {
- style |= UI_PULSE;
- color = text_color_highlight;
- }
-
- UI_DrawProportionalString( item->generic.x, item->generic.y, "Effects", style, color );
-
- UI_DrawHandlePic( item->generic.x + 64, item->generic.y + PROP_HEIGHT + 8, 128, 8, s_playersettings.fxBasePic );
- UI_DrawHandlePic( item->generic.x + 64 + item->curvalue * 16 + 8, item->generic.y + PROP_HEIGHT + 6, 16, 12, s_playersettings.fxPic[item->curvalue] );
-}
-
-
-/*
-=================
-PlayerSettings_DrawPlayer
-=================
-*/
-static void PlayerSettings_DrawPlayer( void *self ) {
- menubitmap_s *b;
- vec3_t viewangles;
- char buf[MAX_QPATH];
-
- trap_Cvar_VariableStringBuffer( "model", buf, sizeof( buf ) );
- if ( strcmp( buf, s_playersettings.playerModel ) != 0 ) {
- UI_PlayerInfo_SetModel( &s_playersettings.playerinfo, buf );
- strcpy( s_playersettings.playerModel, buf );
-
- viewangles[YAW] = 180 - 30;
- viewangles[PITCH] = 0;
- viewangles[ROLL] = 0;
- UI_PlayerInfo_SetInfo( &s_playersettings.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
- }
-
- b = (menubitmap_s*) self;
- UI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_playersettings.playerinfo, uis.realtime/2 );
-}
-
-
-/*
-=================
-PlayerSettings_SaveChanges
-=================
-*/
-static void PlayerSettings_SaveChanges( void ) {
- // name
- trap_Cvar_Set( "name", s_playersettings.name.field.buffer );
-
- // handicap
- trap_Cvar_SetValue( "handicap", 100 - s_playersettings.handicap.curvalue * 5 );
-
- // effects color
- trap_Cvar_SetValue( "color1", uitogamecode[s_playersettings.effects.curvalue] );
-}
-
-
-/*
-=================
-PlayerSettings_MenuKey
-=================
-*/
-static sfxHandle_t PlayerSettings_MenuKey( int key ) {
- if( key == K_MOUSE2 || key == K_ESCAPE ) {
- PlayerSettings_SaveChanges();
- }
- return Menu_DefaultKey( &s_playersettings.menu, key );
-}
-
-
-/*
-=================
-PlayerSettings_SetMenuItems
-=================
-*/
-static void PlayerSettings_SetMenuItems( void ) {
- vec3_t viewangles;
- int c;
- int h;
-
- // name
- Q_strncpyz( s_playersettings.name.field.buffer, UI_Cvar_VariableString("name"), sizeof(s_playersettings.name.field.buffer) );
-
- // effects color
- c = trap_Cvar_VariableValue( "color1" ) - 1;
- if( c < 0 || c > 6 ) {
- c = 6;
- }
- s_playersettings.effects.curvalue = gamecodetoui[c];
-
- // model/skin
- memset( &s_playersettings.playerinfo, 0, sizeof(playerInfo_t) );
-
- viewangles[YAW] = 180 - 30;
- viewangles[PITCH] = 0;
- viewangles[ROLL] = 0;
-
- UI_PlayerInfo_SetModel( &s_playersettings.playerinfo, UI_Cvar_VariableString( "model" ) );
- UI_PlayerInfo_SetInfo( &s_playersettings.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
-
- // handicap
- h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
- s_playersettings.handicap.curvalue = 20 - h / 5;
-}
-
-
-/*
-=================
-PlayerSettings_MenuEvent
-=================
-*/
-static void PlayerSettings_MenuEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_HANDICAP:
- trap_Cvar_Set( "handicap", va( "%i", 100 - 25 * s_playersettings.handicap.curvalue ) );
- break;
-
- case ID_MODEL:
- PlayerSettings_SaveChanges();
- UI_PlayerModelMenu();
- break;
-
- case ID_BACK:
- PlayerSettings_SaveChanges();
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-=================
-PlayerSettings_MenuInit
-=================
-*/
-static void PlayerSettings_MenuInit( void ) {
- int y;
-
- memset(&s_playersettings,0,sizeof(playersettings_t));
-
- PlayerSettings_Cache();
-
- s_playersettings.menu.key = PlayerSettings_MenuKey;
- s_playersettings.menu.wrapAround = qtrue;
- s_playersettings.menu.fullscreen = qtrue;
-
- s_playersettings.banner.generic.type = MTYPE_BTEXT;
- s_playersettings.banner.generic.x = 320;
- s_playersettings.banner.generic.y = 16;
- s_playersettings.banner.string = "PLAYER SETTINGS";
- s_playersettings.banner.color = color_white;
- s_playersettings.banner.style = UI_CENTER;
-
- s_playersettings.framel.generic.type = MTYPE_BITMAP;
- s_playersettings.framel.generic.name = ART_FRAMEL;
- s_playersettings.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_playersettings.framel.generic.x = 0;
- s_playersettings.framel.generic.y = 78;
- s_playersettings.framel.width = 256;
- s_playersettings.framel.height = 329;
-
- s_playersettings.framer.generic.type = MTYPE_BITMAP;
- s_playersettings.framer.generic.name = ART_FRAMER;
- s_playersettings.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_playersettings.framer.generic.x = 376;
- s_playersettings.framer.generic.y = 76;
- s_playersettings.framer.width = 256;
- s_playersettings.framer.height = 334;
-
- y = 144;
- s_playersettings.name.generic.type = MTYPE_FIELD;
- s_playersettings.name.generic.flags = QMF_NODEFAULTINIT;
- s_playersettings.name.generic.ownerdraw = PlayerSettings_DrawName;
- s_playersettings.name.field.widthInChars = MAX_NAMELENGTH;
- s_playersettings.name.field.maxchars = MAX_NAMELENGTH;
- s_playersettings.name.generic.x = 192;
- s_playersettings.name.generic.y = y;
- s_playersettings.name.generic.left = 192 - 8;
- s_playersettings.name.generic.top = y - 8;
- s_playersettings.name.generic.right = 192 + 200;
- s_playersettings.name.generic.bottom = y + 2 * PROP_HEIGHT;
-
- y += 3 * PROP_HEIGHT;
- s_playersettings.handicap.generic.type = MTYPE_SPINCONTROL;
- s_playersettings.handicap.generic.flags = QMF_NODEFAULTINIT;
- s_playersettings.handicap.generic.id = ID_HANDICAP;
- s_playersettings.handicap.generic.ownerdraw = PlayerSettings_DrawHandicap;
- s_playersettings.handicap.generic.x = 192;
- s_playersettings.handicap.generic.y = y;
- s_playersettings.handicap.generic.left = 192 - 8;
- s_playersettings.handicap.generic.top = y - 8;
- s_playersettings.handicap.generic.right = 192 + 200;
- s_playersettings.handicap.generic.bottom = y + 2 * PROP_HEIGHT;
- s_playersettings.handicap.numitems = 20;
-
- y += 3 * PROP_HEIGHT;
- s_playersettings.effects.generic.type = MTYPE_SPINCONTROL;
- s_playersettings.effects.generic.flags = QMF_NODEFAULTINIT;
- s_playersettings.effects.generic.id = ID_EFFECTS;
- s_playersettings.effects.generic.ownerdraw = PlayerSettings_DrawEffects;
- s_playersettings.effects.generic.x = 192;
- s_playersettings.effects.generic.y = y;
- s_playersettings.effects.generic.left = 192 - 8;
- s_playersettings.effects.generic.top = y - 8;
- s_playersettings.effects.generic.right = 192 + 200;
- s_playersettings.effects.generic.bottom = y + 2* PROP_HEIGHT;
- s_playersettings.effects.numitems = 7;
-
- s_playersettings.model.generic.type = MTYPE_BITMAP;
- s_playersettings.model.generic.name = ART_MODEL0;
- s_playersettings.model.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_playersettings.model.generic.id = ID_MODEL;
- s_playersettings.model.generic.callback = PlayerSettings_MenuEvent;
- s_playersettings.model.generic.x = 640;
- s_playersettings.model.generic.y = 480-64;
- s_playersettings.model.width = 128;
- s_playersettings.model.height = 64;
- s_playersettings.model.focuspic = ART_MODEL1;
-
- s_playersettings.player.generic.type = MTYPE_BITMAP;
- s_playersettings.player.generic.flags = QMF_INACTIVE;
- s_playersettings.player.generic.ownerdraw = PlayerSettings_DrawPlayer;
- s_playersettings.player.generic.x = 400;
- s_playersettings.player.generic.y = -40;
- s_playersettings.player.width = 32*10;
- s_playersettings.player.height = 56*10;
-
- s_playersettings.back.generic.type = MTYPE_BITMAP;
- s_playersettings.back.generic.name = ART_BACK0;
- s_playersettings.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_playersettings.back.generic.id = ID_BACK;
- s_playersettings.back.generic.callback = PlayerSettings_MenuEvent;
- s_playersettings.back.generic.x = 0;
- s_playersettings.back.generic.y = 480-64;
- s_playersettings.back.width = 128;
- s_playersettings.back.height = 64;
- s_playersettings.back.focuspic = ART_BACK1;
-
- s_playersettings.item_null.generic.type = MTYPE_BITMAP;
- s_playersettings.item_null.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;
- s_playersettings.item_null.generic.x = 0;
- s_playersettings.item_null.generic.y = 0;
- s_playersettings.item_null.width = 640;
- s_playersettings.item_null.height = 480;
-
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.banner );
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.framel );
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.framer );
-
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.name );
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.handicap );
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.effects );
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.model );
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.back );
-
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.player );
-
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.item_null );
-
- PlayerSettings_SetMenuItems();
-}
-
-
-/*
-=================
-PlayerSettings_Cache
-=================
-*/
-void PlayerSettings_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
- trap_R_RegisterShaderNoMip( ART_MODEL0 );
- trap_R_RegisterShaderNoMip( ART_MODEL1 );
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
-
- s_playersettings.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
- s_playersettings.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
- s_playersettings.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
- s_playersettings.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
- s_playersettings.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
- s_playersettings.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
- s_playersettings.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
- s_playersettings.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
-}
-
-
-/*
-=================
-UI_PlayerSettingsMenu
-=================
-*/
-void UI_PlayerSettingsMenu( void ) {
- PlayerSettings_MenuInit();
- UI_PushMenu( &s_playersettings.menu );
-}
diff --git a/engine/code/q3_ui/ui_preferences.c b/engine/code/q3_ui/ui_preferences.c
deleted file mode 100644
index 693e3f4..0000000
--- a/engine/code/q3_ui/ui_preferences.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-GAME OPTIONS MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define ART_FRAMEL "menu/art/frame2_l"
-#define ART_FRAMER "menu/art/frame1_r"
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-
-#define PREFERENCES_X_POS 360
-
-#define ID_CROSSHAIR 127
-#define ID_SIMPLEITEMS 128
-#define ID_HIGHQUALITYSKY 129
-#define ID_EJECTINGBRASS 130
-#define ID_WALLMARKS 131
-#define ID_DYNAMICLIGHTS 132
-#define ID_IDENTIFYTARGET 133
-#define ID_SYNCEVERYFRAME 134
-#define ID_FORCEMODEL 135
-#define ID_DRAWTEAMOVERLAY 136
-#define ID_ALLOWDOWNLOAD 137
-#define ID_BACK 138
-
-#define NUM_CROSSHAIRS 10
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menulist_s crosshair;
- menuradiobutton_s simpleitems;
- menuradiobutton_s brass;
- menuradiobutton_s wallmarks;
- menuradiobutton_s dynamiclights;
- menuradiobutton_s identifytarget;
- menuradiobutton_s highqualitysky;
- menuradiobutton_s synceveryframe;
- menuradiobutton_s forcemodel;
- menulist_s drawteamoverlay;
- menuradiobutton_s allowdownload;
- menubitmap_s back;
-
- qhandle_t crosshairShader[NUM_CROSSHAIRS];
-} preferences_t;
-
-static preferences_t s_preferences;
-
-static const char *teamoverlay_names[] =
-{
- "off",
- "upper right",
- "lower right",
- "lower left",
- NULL
-};
-
-static void Preferences_SetMenuItems( void ) {
- s_preferences.crosshair.curvalue = (int)trap_Cvar_VariableValue( "cg_drawCrosshair" ) % NUM_CROSSHAIRS;
- s_preferences.simpleitems.curvalue = trap_Cvar_VariableValue( "cg_simpleItems" ) != 0;
- s_preferences.brass.curvalue = trap_Cvar_VariableValue( "cg_brassTime" ) != 0;
- s_preferences.wallmarks.curvalue = trap_Cvar_VariableValue( "cg_marks" ) != 0;
- s_preferences.identifytarget.curvalue = trap_Cvar_VariableValue( "cg_drawCrosshairNames" ) != 0;
- s_preferences.dynamiclights.curvalue = trap_Cvar_VariableValue( "r_dynamiclight" ) != 0;
- s_preferences.highqualitysky.curvalue = trap_Cvar_VariableValue ( "r_fastsky" ) == 0;
- s_preferences.synceveryframe.curvalue = trap_Cvar_VariableValue( "r_finish" ) != 0;
- s_preferences.forcemodel.curvalue = trap_Cvar_VariableValue( "cg_forcemodel" ) != 0;
- s_preferences.drawteamoverlay.curvalue = Com_Clamp( 0, 3, trap_Cvar_VariableValue( "cg_drawTeamOverlay" ) );
- s_preferences.allowdownload.curvalue = trap_Cvar_VariableValue( "cl_allowDownload" ) != 0;
-}
-
-
-static void Preferences_Event( void* ptr, int notification ) {
- if( notification != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_CROSSHAIR:
- s_preferences.crosshair.curvalue++;
- if( s_preferences.crosshair.curvalue == NUM_CROSSHAIRS ) {
- s_preferences.crosshair.curvalue = 0;
- }
- trap_Cvar_SetValue( "cg_drawCrosshair", s_preferences.crosshair.curvalue );
- break;
-
- case ID_SIMPLEITEMS:
- trap_Cvar_SetValue( "cg_simpleItems", s_preferences.simpleitems.curvalue );
- break;
-
- case ID_HIGHQUALITYSKY:
- trap_Cvar_SetValue( "r_fastsky", !s_preferences.highqualitysky.curvalue );
- break;
-
- case ID_EJECTINGBRASS:
- if ( s_preferences.brass.curvalue )
- trap_Cvar_Reset( "cg_brassTime" );
- else
- trap_Cvar_SetValue( "cg_brassTime", 0 );
- break;
-
- case ID_WALLMARKS:
- trap_Cvar_SetValue( "cg_marks", s_preferences.wallmarks.curvalue );
- break;
-
- case ID_DYNAMICLIGHTS:
- trap_Cvar_SetValue( "r_dynamiclight", s_preferences.dynamiclights.curvalue );
- break;
-
- case ID_IDENTIFYTARGET:
- trap_Cvar_SetValue( "cg_drawCrosshairNames", s_preferences.identifytarget.curvalue );
- break;
-
- case ID_SYNCEVERYFRAME:
- trap_Cvar_SetValue( "r_finish", s_preferences.synceveryframe.curvalue );
- break;
-
- case ID_FORCEMODEL:
- trap_Cvar_SetValue( "cg_forcemodel", s_preferences.forcemodel.curvalue );
- break;
-
- case ID_DRAWTEAMOVERLAY:
- trap_Cvar_SetValue( "cg_drawTeamOverlay", s_preferences.drawteamoverlay.curvalue );
- break;
-
- case ID_ALLOWDOWNLOAD:
- trap_Cvar_SetValue( "cl_allowDownload", s_preferences.allowdownload.curvalue );
- trap_Cvar_SetValue( "sv_allowDownload", s_preferences.allowdownload.curvalue );
- break;
-
- case ID_BACK:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-=================
-Crosshair_Draw
-=================
-*/
-static void Crosshair_Draw( void *self ) {
- menulist_s *s;
- float *color;
- int x, y;
- int style;
- qboolean focus;
-
- s = (menulist_s *)self;
- x = s->generic.x;
- y = s->generic.y;
-
- style = UI_SMALLFONT;
- focus = (s->generic.parent->cursor == s->generic.menuPosition);
-
- if ( s->generic.flags & QMF_GRAYED )
- color = text_color_disabled;
- else if ( focus )
- {
- color = text_color_highlight;
- style |= UI_PULSE;
- }
- else if ( s->generic.flags & QMF_BLINK )
- {
- color = text_color_highlight;
- style |= UI_BLINK;
- }
- else
- color = text_color_normal;
-
- if ( focus )
- {
- // draw cursor
- UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
- }
-
- UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );
- if( !s->curvalue ) {
- return;
- }
- UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y - 4, 24, 24, s_preferences.crosshairShader[s->curvalue] );
-}
-
-
-static void Preferences_MenuInit( void ) {
- int y;
-
- memset( &s_preferences, 0 ,sizeof(preferences_t) );
-
- Preferences_Cache();
-
- s_preferences.menu.wrapAround = qtrue;
- s_preferences.menu.fullscreen = qtrue;
-
- s_preferences.banner.generic.type = MTYPE_BTEXT;
- s_preferences.banner.generic.x = 320;
- s_preferences.banner.generic.y = 16;
- s_preferences.banner.string = "GAME OPTIONS";
- s_preferences.banner.color = color_white;
- s_preferences.banner.style = UI_CENTER;
-
- s_preferences.framel.generic.type = MTYPE_BITMAP;
- s_preferences.framel.generic.name = ART_FRAMEL;
- s_preferences.framel.generic.flags = QMF_INACTIVE;
- s_preferences.framel.generic.x = 0;
- s_preferences.framel.generic.y = 78;
- s_preferences.framel.width = 256;
- s_preferences.framel.height = 329;
-
- s_preferences.framer.generic.type = MTYPE_BITMAP;
- s_preferences.framer.generic.name = ART_FRAMER;
- s_preferences.framer.generic.flags = QMF_INACTIVE;
- s_preferences.framer.generic.x = 376;
- s_preferences.framer.generic.y = 76;
- s_preferences.framer.width = 256;
- s_preferences.framer.height = 334;
-
- y = 144;
- s_preferences.crosshair.generic.type = MTYPE_TEXT;
- s_preferences.crosshair.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT|QMF_NODEFAULTINIT|QMF_OWNERDRAW;
- s_preferences.crosshair.generic.x = PREFERENCES_X_POS;
- s_preferences.crosshair.generic.y = y;
- s_preferences.crosshair.generic.name = "Crosshair:";
- s_preferences.crosshair.generic.callback = Preferences_Event;
- s_preferences.crosshair.generic.ownerdraw = Crosshair_Draw;
- s_preferences.crosshair.generic.id = ID_CROSSHAIR;
- s_preferences.crosshair.generic.top = y - 4;
- s_preferences.crosshair.generic.bottom = y + 20;
- s_preferences.crosshair.generic.left = PREFERENCES_X_POS - ( ( strlen(s_preferences.crosshair.generic.name) + 1 ) * SMALLCHAR_WIDTH );
- s_preferences.crosshair.generic.right = PREFERENCES_X_POS + 48;
-
- y += BIGCHAR_HEIGHT+2+4;
- s_preferences.simpleitems.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.simpleitems.generic.name = "Simple Items:";
- s_preferences.simpleitems.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.simpleitems.generic.callback = Preferences_Event;
- s_preferences.simpleitems.generic.id = ID_SIMPLEITEMS;
- s_preferences.simpleitems.generic.x = PREFERENCES_X_POS;
- s_preferences.simpleitems.generic.y = y;
-
- y += BIGCHAR_HEIGHT;
- s_preferences.wallmarks.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.wallmarks.generic.name = "Marks on Walls:";
- s_preferences.wallmarks.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.wallmarks.generic.callback = Preferences_Event;
- s_preferences.wallmarks.generic.id = ID_WALLMARKS;
- s_preferences.wallmarks.generic.x = PREFERENCES_X_POS;
- s_preferences.wallmarks.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.brass.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.brass.generic.name = "Ejecting Brass:";
- s_preferences.brass.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.brass.generic.callback = Preferences_Event;
- s_preferences.brass.generic.id = ID_EJECTINGBRASS;
- s_preferences.brass.generic.x = PREFERENCES_X_POS;
- s_preferences.brass.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.dynamiclights.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.dynamiclights.generic.name = "Dynamic Lights:";
- s_preferences.dynamiclights.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.dynamiclights.generic.callback = Preferences_Event;
- s_preferences.dynamiclights.generic.id = ID_DYNAMICLIGHTS;
- s_preferences.dynamiclights.generic.x = PREFERENCES_X_POS;
- s_preferences.dynamiclights.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.identifytarget.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.identifytarget.generic.name = "Identify Target:";
- s_preferences.identifytarget.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.identifytarget.generic.callback = Preferences_Event;
- s_preferences.identifytarget.generic.id = ID_IDENTIFYTARGET;
- s_preferences.identifytarget.generic.x = PREFERENCES_X_POS;
- s_preferences.identifytarget.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.highqualitysky.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.highqualitysky.generic.name = "High Quality Sky:";
- s_preferences.highqualitysky.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.highqualitysky.generic.callback = Preferences_Event;
- s_preferences.highqualitysky.generic.id = ID_HIGHQUALITYSKY;
- s_preferences.highqualitysky.generic.x = PREFERENCES_X_POS;
- s_preferences.highqualitysky.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.synceveryframe.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.synceveryframe.generic.name = "Sync Every Frame:";
- s_preferences.synceveryframe.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.synceveryframe.generic.callback = Preferences_Event;
- s_preferences.synceveryframe.generic.id = ID_SYNCEVERYFRAME;
- s_preferences.synceveryframe.generic.x = PREFERENCES_X_POS;
- s_preferences.synceveryframe.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.forcemodel.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.forcemodel.generic.name = "Force Player Models:";
- s_preferences.forcemodel.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.forcemodel.generic.callback = Preferences_Event;
- s_preferences.forcemodel.generic.id = ID_FORCEMODEL;
- s_preferences.forcemodel.generic.x = PREFERENCES_X_POS;
- s_preferences.forcemodel.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.drawteamoverlay.generic.type = MTYPE_SPINCONTROL;
- s_preferences.drawteamoverlay.generic.name = "Draw Team Overlay:";
- s_preferences.drawteamoverlay.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.drawteamoverlay.generic.callback = Preferences_Event;
- s_preferences.drawteamoverlay.generic.id = ID_DRAWTEAMOVERLAY;
- s_preferences.drawteamoverlay.generic.x = PREFERENCES_X_POS;
- s_preferences.drawteamoverlay.generic.y = y;
- s_preferences.drawteamoverlay.itemnames = teamoverlay_names;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.allowdownload.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.allowdownload.generic.name = "Automatic Downloading:";
- s_preferences.allowdownload.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.allowdownload.generic.callback = Preferences_Event;
- s_preferences.allowdownload.generic.id = ID_ALLOWDOWNLOAD;
- s_preferences.allowdownload.generic.x = PREFERENCES_X_POS;
- s_preferences.allowdownload.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.back.generic.type = MTYPE_BITMAP;
- s_preferences.back.generic.name = ART_BACK0;
- s_preferences.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_preferences.back.generic.callback = Preferences_Event;
- s_preferences.back.generic.id = ID_BACK;
- s_preferences.back.generic.x = 0;
- s_preferences.back.generic.y = 480-64;
- s_preferences.back.width = 128;
- s_preferences.back.height = 64;
- s_preferences.back.focuspic = ART_BACK1;
-
- Menu_AddItem( &s_preferences.menu, &s_preferences.banner );
- Menu_AddItem( &s_preferences.menu, &s_preferences.framel );
- Menu_AddItem( &s_preferences.menu, &s_preferences.framer );
-
- Menu_AddItem( &s_preferences.menu, &s_preferences.crosshair );
- Menu_AddItem( &s_preferences.menu, &s_preferences.simpleitems );
- Menu_AddItem( &s_preferences.menu, &s_preferences.wallmarks );
- Menu_AddItem( &s_preferences.menu, &s_preferences.brass );
- Menu_AddItem( &s_preferences.menu, &s_preferences.dynamiclights );
- Menu_AddItem( &s_preferences.menu, &s_preferences.identifytarget );
- Menu_AddItem( &s_preferences.menu, &s_preferences.highqualitysky );
- Menu_AddItem( &s_preferences.menu, &s_preferences.synceveryframe );
- Menu_AddItem( &s_preferences.menu, &s_preferences.forcemodel );
- Menu_AddItem( &s_preferences.menu, &s_preferences.drawteamoverlay );
- Menu_AddItem( &s_preferences.menu, &s_preferences.allowdownload );
-
- Menu_AddItem( &s_preferences.menu, &s_preferences.back );
-
- Preferences_SetMenuItems();
-}
-
-
-/*
-===============
-Preferences_Cache
-===============
-*/
-void Preferences_Cache( void ) {
- int n;
-
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- for( n = 0; n < NUM_CROSSHAIRS; n++ ) {
- s_preferences.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a' + n ) );
- }
-}
-
-
-/*
-===============
-UI_PreferencesMenu
-===============
-*/
-void UI_PreferencesMenu( void ) {
- Preferences_MenuInit();
- UI_PushMenu( &s_preferences.menu );
-}
diff --git a/engine/code/q3_ui/ui_qmenu.c b/engine/code/q3_ui/ui_qmenu.c
deleted file mode 100644
index e955c51..0000000
--- a/engine/code/q3_ui/ui_qmenu.c
+++ /dev/null
@@ -1,1745 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/**********************************************************************
- UI_QMENU.C
-
- Quake's menu framework system.
-**********************************************************************/
-#include "ui_local.h"
-
-sfxHandle_t menu_in_sound;
-sfxHandle_t menu_move_sound;
-sfxHandle_t menu_out_sound;
-sfxHandle_t menu_buzz_sound;
-sfxHandle_t menu_null_sound;
-sfxHandle_t weaponChangeSound;
-
-static qhandle_t sliderBar;
-static qhandle_t sliderButton_0;
-static qhandle_t sliderButton_1;
-
-vec4_t menu_text_color = {1.0f, 1.0f, 1.0f, 1.0f};
-vec4_t menu_dim_color = {0.0f, 0.0f, 0.0f, 0.75f};
-vec4_t color_black = {0.00f, 0.00f, 0.00f, 1.00f};
-vec4_t color_white = {1.00f, 1.00f, 1.00f, 1.00f};
-vec4_t color_yellow = {1.00f, 1.00f, 0.00f, 1.00f};
-vec4_t color_blue = {0.00f, 0.00f, 1.00f, 1.00f};
-vec4_t color_lightOrange = {1.00f, 0.68f, 0.00f, 1.00f };
-vec4_t color_orange = {1.00f, 0.43f, 0.00f, 1.00f};
-vec4_t color_red = {1.00f, 0.00f, 0.00f, 1.00f};
-vec4_t color_dim = {0.00f, 0.00f, 0.00f, 0.25f};
-
-// current color scheme
-vec4_t pulse_color = {1.00f, 1.00f, 1.00f, 1.00f};
-vec4_t text_color_disabled = {0.50f, 0.50f, 0.50f, 1.00f}; // light gray
-vec4_t text_color_normal = {1.00f, 0.43f, 0.00f, 1.00f}; // light orange
-vec4_t text_color_highlight = {1.00f, 1.00f, 0.00f, 1.00f}; // bright yellow
-vec4_t listbar_color = {1.00f, 0.43f, 0.00f, 0.30f}; // transluscent orange
-vec4_t text_color_status = {1.00f, 1.00f, 1.00f, 1.00f}; // bright white
-
-// action widget
-static void Action_Init( menuaction_s *a );
-static void Action_Draw( menuaction_s *a );
-
-// radio button widget
-static void RadioButton_Init( menuradiobutton_s *rb );
-static void RadioButton_Draw( menuradiobutton_s *rb );
-static sfxHandle_t RadioButton_Key( menuradiobutton_s *rb, int key );
-
-// slider widget
-static void Slider_Init( menuslider_s *s );
-static sfxHandle_t Slider_Key( menuslider_s *s, int key );
-static void Slider_Draw( menuslider_s *s );
-
-// spin control widget
-static void SpinControl_Init( menulist_s *s );
-static void SpinControl_Draw( menulist_s *s );
-static sfxHandle_t SpinControl_Key( menulist_s *l, int key );
-
-// text widget
-static void Text_Init( menutext_s *b );
-static void Text_Draw( menutext_s *b );
-
-// scrolllist widget
-static void ScrollList_Init( menulist_s *l );
-sfxHandle_t ScrollList_Key( menulist_s *l, int key );
-
-// proportional text widget
-static void PText_Init( menutext_s *b );
-static void PText_Draw( menutext_s *b );
-
-// proportional banner text widget
-static void BText_Init( menutext_s *b );
-static void BText_Draw( menutext_s *b );
-
-/*
-=================
-Text_Init
-=================
-*/
-static void Text_Init( menutext_s *t )
-{
- t->generic.flags |= QMF_INACTIVE;
-}
-
-/*
-=================
-Text_Draw
-=================
-*/
-static void Text_Draw( menutext_s *t )
-{
- int x;
- int y;
- char buff[512];
- float* color;
-
- x = t->generic.x;
- y = t->generic.y;
-
- buff[0] = '\0';
-
- // possible label
- if (t->generic.name)
- strcpy(buff,t->generic.name);
-
- // possible value
- if (t->string)
- strcat(buff,t->string);
-
- if (t->generic.flags & QMF_GRAYED)
- color = text_color_disabled;
- else
- color = t->color;
-
- UI_DrawString( x, y, buff, t->style, color );
-}
-
-/*
-=================
-BText_Init
-=================
-*/
-static void BText_Init( menutext_s *t )
-{
- t->generic.flags |= QMF_INACTIVE;
-}
-
-/*
-=================
-BText_Draw
-=================
-*/
-static void BText_Draw( menutext_s *t )
-{
- int x;
- int y;
- float* color;
-
- x = t->generic.x;
- y = t->generic.y;
-
- if (t->generic.flags & QMF_GRAYED)
- color = text_color_disabled;
- else
- color = t->color;
-
- UI_DrawBannerString( x, y, t->string, t->style, color );
-}
-
-/*
-=================
-PText_Init
-=================
-*/
-static void PText_Init( menutext_s *t )
-{
- int x;
- int y;
- int w;
- int h;
- float sizeScale;
-
- sizeScale = UI_ProportionalSizeScale( t->style );
-
- x = t->generic.x;
- y = t->generic.y;
- w = UI_ProportionalStringWidth( t->string ) * sizeScale;
- h = PROP_HEIGHT * sizeScale;
-
- if( t->generic.flags & QMF_RIGHT_JUSTIFY ) {
- x -= w;
- }
- else if( t->generic.flags & QMF_CENTER_JUSTIFY ) {
- x -= w / 2;
- }
-
- t->generic.left = x - PROP_GAP_WIDTH * sizeScale;
- t->generic.right = x + w + PROP_GAP_WIDTH * sizeScale;
- t->generic.top = y;
- t->generic.bottom = y + h;
-}
-
-/*
-=================
-PText_Draw
-=================
-*/
-static void PText_Draw( menutext_s *t )
-{
- int x;
- int y;
- float * color;
- int style;
-
- x = t->generic.x;
- y = t->generic.y;
-
- if (t->generic.flags & QMF_GRAYED)
- color = text_color_disabled;
- else
- color = t->color;
-
- style = t->style;
- if( t->generic.flags & QMF_PULSEIFFOCUS ) {
- if( Menu_ItemAtCursor( t->generic.parent ) == t ) {
- style |= UI_PULSE;
- }
- else {
- style |= UI_INVERSE;
- }
- }
-
- UI_DrawProportionalString( x, y, t->string, style, color );
-}
-
-/*
-=================
-Bitmap_Init
-=================
-*/
-void Bitmap_Init( menubitmap_s *b )
-{
- int x;
- int y;
- int w;
- int h;
-
- x = b->generic.x;
- y = b->generic.y;
- w = b->width;
- h = b->height;
- if( w < 0 ) {
- w = -w;
- }
- if( h < 0 ) {
- h = -h;
- }
-
- if (b->generic.flags & QMF_RIGHT_JUSTIFY)
- {
- x = x - w;
- }
- else if (b->generic.flags & QMF_CENTER_JUSTIFY)
- {
- x = x - w/2;
- }
-
- b->generic.left = x;
- b->generic.right = x + w;
- b->generic.top = y;
- b->generic.bottom = y + h;
-
- b->shader = 0;
- b->focusshader = 0;
-}
-
-/*
-=================
-Bitmap_Draw
-=================
-*/
-void Bitmap_Draw( menubitmap_s *b )
-{
- float x;
- float y;
- float w;
- float h;
- vec4_t tempcolor;
- float* color;
-
- x = b->generic.x;
- y = b->generic.y;
- w = b->width;
- h = b->height;
-
- if (b->generic.flags & QMF_RIGHT_JUSTIFY)
- {
- x = x - w;
- }
- else if (b->generic.flags & QMF_CENTER_JUSTIFY)
- {
- x = x - w/2;
- }
-
- // used to refresh shader
- if (b->generic.name && !b->shader)
- {
- b->shader = trap_R_RegisterShaderNoMip( b->generic.name );
- if (!b->shader && b->errorpic)
- b->shader = trap_R_RegisterShaderNoMip( b->errorpic );
- }
-
- if (b->focuspic && !b->focusshader)
- b->focusshader = trap_R_RegisterShaderNoMip( b->focuspic );
-
- if (b->generic.flags & QMF_GRAYED)
- {
- if (b->shader)
- {
- trap_R_SetColor( colorMdGrey );
- UI_DrawHandlePic( x, y, w, h, b->shader );
- trap_R_SetColor( NULL );
- }
- }
- else
- {
- if (b->shader)
- UI_DrawHandlePic( x, y, w, h, b->shader );
-
- if ( ( (b->generic.flags & QMF_PULSE)
- || (b->generic.flags & QMF_PULSEIFFOCUS) )
- && (Menu_ItemAtCursor( b->generic.parent ) == b))
- {
- if (b->focuscolor)
- {
- tempcolor[0] = b->focuscolor[0];
- tempcolor[1] = b->focuscolor[1];
- tempcolor[2] = b->focuscolor[2];
- color = tempcolor;
- }
- else
- color = pulse_color;
- color[3] = 0.5+0.5*sin(uis.realtime/PULSE_DIVISOR);
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( x, y, w, h, b->focusshader );
- trap_R_SetColor( NULL );
- }
- else if ((b->generic.flags & QMF_HIGHLIGHT) || ((b->generic.flags & QMF_HIGHLIGHT_IF_FOCUS) && (Menu_ItemAtCursor( b->generic.parent ) == b)))
- {
- if (b->focuscolor)
- {
- trap_R_SetColor( b->focuscolor );
- UI_DrawHandlePic( x, y, w, h, b->focusshader );
- trap_R_SetColor( NULL );
- }
- else
- UI_DrawHandlePic( x, y, w, h, b->focusshader );
- }
- }
-}
-
-/*
-=================
-Action_Init
-=================
-*/
-static void Action_Init( menuaction_s *a )
-{
- int len;
-
- // calculate bounds
- if (a->generic.name)
- len = strlen(a->generic.name);
- else
- len = 0;
-
- // left justify text
- a->generic.left = a->generic.x;
- a->generic.right = a->generic.x + len*BIGCHAR_WIDTH;
- a->generic.top = a->generic.y;
- a->generic.bottom = a->generic.y + BIGCHAR_HEIGHT;
-}
-
-/*
-=================
-Action_Draw
-=================
-*/
-static void Action_Draw( menuaction_s *a )
-{
- int x, y;
- int style;
- float* color;
-
- style = 0;
- color = menu_text_color;
- if ( a->generic.flags & QMF_GRAYED )
- {
- color = text_color_disabled;
- }
- else if (( a->generic.flags & QMF_PULSEIFFOCUS ) && ( a->generic.parent->cursor == a->generic.menuPosition ))
- {
- color = text_color_highlight;
- style = UI_PULSE;
- }
- else if (( a->generic.flags & QMF_HIGHLIGHT_IF_FOCUS ) && ( a->generic.parent->cursor == a->generic.menuPosition ))
- {
- color = text_color_highlight;
- }
- else if ( a->generic.flags & QMF_BLINK )
- {
- style = UI_BLINK;
- color = text_color_highlight;
- }
-
- x = a->generic.x;
- y = a->generic.y;
-
- UI_DrawString( x, y, a->generic.name, UI_LEFT|style, color );
-
- if ( a->generic.parent->cursor == a->generic.menuPosition )
- {
- // draw cursor
- UI_DrawChar( x - BIGCHAR_WIDTH, y, 13, UI_LEFT|UI_BLINK, color);
- }
-}
-
-/*
-=================
-RadioButton_Init
-=================
-*/
-static void RadioButton_Init( menuradiobutton_s *rb )
-{
- int len;
-
- // calculate bounds
- if (rb->generic.name)
- len = strlen(rb->generic.name);
- else
- len = 0;
-
- rb->generic.left = rb->generic.x - (len+1)*SMALLCHAR_WIDTH;
- rb->generic.right = rb->generic.x + 6*SMALLCHAR_WIDTH;
- rb->generic.top = rb->generic.y;
- rb->generic.bottom = rb->generic.y + SMALLCHAR_HEIGHT;
-}
-
-/*
-=================
-RadioButton_Key
-=================
-*/
-static sfxHandle_t RadioButton_Key( menuradiobutton_s *rb, int key )
-{
- switch (key)
- {
- case K_MOUSE1:
- if (!(rb->generic.flags & QMF_HASMOUSEFOCUS))
- break;
-
- case K_JOY1:
- case K_JOY2:
- case K_JOY3:
- case K_JOY4:
- case K_ENTER:
- case K_KP_ENTER:
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- rb->curvalue = !rb->curvalue;
- if ( rb->generic.callback )
- rb->generic.callback( rb, QM_ACTIVATED );
-
- return (menu_move_sound);
- }
-
- // key not handled
- return 0;
-}
-
-/*
-=================
-RadioButton_Draw
-=================
-*/
-static void RadioButton_Draw( menuradiobutton_s *rb )
-{
- int x;
- int y;
- float *color;
- int style;
- qboolean focus;
-
- x = rb->generic.x;
- y = rb->generic.y;
-
- focus = (rb->generic.parent->cursor == rb->generic.menuPosition);
-
- if ( rb->generic.flags & QMF_GRAYED )
- {
- color = text_color_disabled;
- style = UI_LEFT|UI_SMALLFONT;
- }
- else if ( focus )
- {
- color = text_color_highlight;
- style = UI_LEFT|UI_PULSE|UI_SMALLFONT;
- }
- else
- {
- color = text_color_normal;
- style = UI_LEFT|UI_SMALLFONT;
- }
-
- if ( focus )
- {
- // draw cursor
- UI_FillRect( rb->generic.left, rb->generic.top, rb->generic.right-rb->generic.left+1, rb->generic.bottom-rb->generic.top+1, listbar_color );
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
- }
-
- if ( rb->generic.name )
- UI_DrawString( x - SMALLCHAR_WIDTH, y, rb->generic.name, UI_RIGHT|UI_SMALLFONT, color );
-
- if ( !rb->curvalue )
- {
- UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y + 2, 16, 16, uis.rb_off);
- UI_DrawString( x + SMALLCHAR_WIDTH + 16, y, "off", style, color );
- }
- else
- {
- UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y + 2, 16, 16, uis.rb_on );
- UI_DrawString( x + SMALLCHAR_WIDTH + 16, y, "on", style, color );
- }
-}
-
-/*
-=================
-Slider_Init
-=================
-*/
-static void Slider_Init( menuslider_s *s )
-{
- int len;
-
- // calculate bounds
- if (s->generic.name)
- len = strlen(s->generic.name);
- else
- len = 0;
-
- s->generic.left = s->generic.x - (len+1)*SMALLCHAR_WIDTH;
- s->generic.right = s->generic.x + (SLIDER_RANGE+2+1)*SMALLCHAR_WIDTH;
- s->generic.top = s->generic.y;
- s->generic.bottom = s->generic.y + SMALLCHAR_HEIGHT;
-}
-
-/*
-=================
-Slider_Key
-=================
-*/
-static sfxHandle_t Slider_Key( menuslider_s *s, int key )
-{
- sfxHandle_t sound;
- int x;
- int oldvalue;
-
- switch (key)
- {
- case K_MOUSE1:
- x = uis.cursorx - s->generic.x - 2*SMALLCHAR_WIDTH;
- oldvalue = s->curvalue;
- s->curvalue = (x/(float)(SLIDER_RANGE*SMALLCHAR_WIDTH)) * (s->maxvalue-s->minvalue) + s->minvalue;
-
- if (s->curvalue < s->minvalue)
- s->curvalue = s->minvalue;
- else if (s->curvalue > s->maxvalue)
- s->curvalue = s->maxvalue;
- if (s->curvalue != oldvalue)
- sound = menu_move_sound;
- else
- sound = 0;
- break;
-
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- if (s->curvalue > s->minvalue)
- {
- s->curvalue--;
- sound = menu_move_sound;
- }
- else
- sound = menu_buzz_sound;
- break;
-
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- if (s->curvalue < s->maxvalue)
- {
- s->curvalue++;
- sound = menu_move_sound;
- }
- else
- sound = menu_buzz_sound;
- break;
-
- default:
- // key not handled
- sound = 0;
- break;
- }
-
- if ( sound && s->generic.callback )
- s->generic.callback( s, QM_ACTIVATED );
-
- return (sound);
-}
-
-#if 1
-/*
-=================
-Slider_Draw
-=================
-*/
-static void Slider_Draw( menuslider_s *s ) {
- int x;
- int y;
- int style;
- float *color;
- int button;
- qboolean focus;
-
- x = s->generic.x;
- y = s->generic.y;
- focus = (s->generic.parent->cursor == s->generic.menuPosition);
-
- if( s->generic.flags & QMF_GRAYED ) {
- color = text_color_disabled;
- style = UI_SMALLFONT;
- }
- else if( focus ) {
- color = text_color_highlight;
- style = UI_SMALLFONT | UI_PULSE;
- }
- else {
- color = text_color_normal;
- style = UI_SMALLFONT;
- }
-
- // draw label
- UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, UI_RIGHT|style, color );
-
- // draw slider
- UI_SetColor( color );
- UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y, 96, 16, sliderBar );
- UI_SetColor( NULL );
-
- // clamp thumb
- if( s->maxvalue > s->minvalue ) {
- s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
- if( s->range < 0 ) {
- s->range = 0;
- }
- else if( s->range > 1) {
- s->range = 1;
- }
- }
- else {
- s->range = 0;
- }
-
- // draw thumb
- if( style & UI_PULSE) {
- button = sliderButton_1;
- }
- else {
- button = sliderButton_0;
- }
-
- UI_DrawHandlePic( (int)( x + 2*SMALLCHAR_WIDTH + (SLIDER_RANGE-1)*SMALLCHAR_WIDTH* s->range ) - 2, y - 2, 12, 20, button );
-}
-#else
-/*
-=================
-Slider_Draw
-=================
-*/
-static void Slider_Draw( menuslider_s *s )
-{
- float *color;
- int style;
- int i;
- int x;
- int y;
- qboolean focus;
-
- x = s->generic.x;
- y = s->generic.y;
- focus = (s->generic.parent->cursor == s->generic.menuPosition);
-
- style = UI_SMALLFONT;
- if ( s->generic.flags & QMF_GRAYED )
- {
- color = text_color_disabled;
- }
- else if (focus)
- {
- color = text_color_highlight;
- style |= UI_PULSE;
- }
- else
- {
- color = text_color_normal;
- }
-
- if ( focus )
- {
- // draw cursor
- UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
- }
-
- // draw label
- UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, UI_RIGHT|style, color );
-
- // draw slider
- UI_DrawChar( x + SMALLCHAR_WIDTH, y, 128, UI_LEFT|style, color);
- for ( i = 0; i < SLIDER_RANGE; i++ )
- UI_DrawChar( x + (i+2)*SMALLCHAR_WIDTH, y, 129, UI_LEFT|style, color);
- UI_DrawChar( x + (i+2)*SMALLCHAR_WIDTH, y, 130, UI_LEFT|style, color);
-
- // clamp thumb
- if (s->maxvalue > s->minvalue)
- {
- s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
- if ( s->range < 0)
- s->range = 0;
- else if ( s->range > 1)
- s->range = 1;
- }
- else
- s->range = 0;
-
- // draw thumb
- if (style & UI_PULSE) {
- style &= ~UI_PULSE;
- style |= UI_BLINK;
- }
- UI_DrawChar( (int)( x + 2*SMALLCHAR_WIDTH + (SLIDER_RANGE-1)*SMALLCHAR_WIDTH* s->range ), y, 131, UI_LEFT|style, color);
-}
-#endif
-
-/*
-=================
-SpinControl_Init
-=================
-*/
-static void SpinControl_Init( menulist_s *s ) {
- int len;
- int l;
- const char* str;
-
- if (s->generic.name)
- len = strlen(s->generic.name) * SMALLCHAR_WIDTH;
- else
- len = 0;
-
- s->generic.left = s->generic.x - SMALLCHAR_WIDTH - len;
-
- len = s->numitems = 0;
- while ( (str = s->itemnames[s->numitems]) != 0 )
- {
- l = strlen(str);
- if (l > len)
- len = l;
-
- s->numitems++;
- }
-
- s->generic.top = s->generic.y;
- s->generic.right = s->generic.x + (len+1)*SMALLCHAR_WIDTH;
- s->generic.bottom = s->generic.y + SMALLCHAR_HEIGHT;
-}
-
-/*
-=================
-SpinControl_Key
-=================
-*/
-static sfxHandle_t SpinControl_Key( menulist_s *s, int key )
-{
- sfxHandle_t sound;
-
- sound = 0;
- switch (key)
- {
- case K_MOUSE1:
- s->curvalue++;
- if (s->curvalue >= s->numitems)
- s->curvalue = 0;
- sound = menu_move_sound;
- break;
-
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- if (s->curvalue > 0)
- {
- s->curvalue--;
- sound = menu_move_sound;
- }
- else
- sound = menu_buzz_sound;
- break;
-
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- if (s->curvalue < s->numitems-1)
- {
- s->curvalue++;
- sound = menu_move_sound;
- }
- else
- sound = menu_buzz_sound;
- break;
- }
-
- if ( sound && s->generic.callback )
- s->generic.callback( s, QM_ACTIVATED );
-
- return (sound);
-}
-
-/*
-=================
-SpinControl_Draw
-=================
-*/
-static void SpinControl_Draw( menulist_s *s )
-{
- float *color;
- int x,y;
- int style;
- qboolean focus;
-
- x = s->generic.x;
- y = s->generic.y;
-
- style = UI_SMALLFONT;
- focus = (s->generic.parent->cursor == s->generic.menuPosition);
-
- if ( s->generic.flags & QMF_GRAYED )
- color = text_color_disabled;
- else if ( focus )
- {
- color = text_color_highlight;
- style |= UI_PULSE;
- }
- else if ( s->generic.flags & QMF_BLINK )
- {
- color = text_color_highlight;
- style |= UI_BLINK;
- }
- else
- color = text_color_normal;
-
- if ( focus )
- {
- // draw cursor
- UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
- }
-
- UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );
- UI_DrawString( x + SMALLCHAR_WIDTH, y, s->itemnames[s->curvalue], style|UI_LEFT, color );
-}
-
-/*
-=================
-ScrollList_Init
-=================
-*/
-static void ScrollList_Init( menulist_s *l )
-{
- int w;
-
- l->oldvalue = 0;
- l->curvalue = 0;
- l->top = 0;
-
- if( !l->columns ) {
- l->columns = 1;
- l->seperation = 0;
- }
- else if( !l->seperation ) {
- l->seperation = 3;
- }
-
- w = ( (l->width + l->seperation) * l->columns - l->seperation) * SMALLCHAR_WIDTH;
-
- l->generic.left = l->generic.x;
- l->generic.top = l->generic.y;
- l->generic.right = l->generic.x + w;
- l->generic.bottom = l->generic.y + l->height * SMALLCHAR_HEIGHT;
-
- if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
- l->generic.left -= w / 2;
- l->generic.right -= w / 2;
- }
-}
-
-/*
-=================
-ScrollList_Key
-=================
-*/
-sfxHandle_t ScrollList_Key( menulist_s *l, int key )
-{
- int x;
- int y;
- int w;
- int i;
- int j;
- int c;
- int cursorx;
- int cursory;
- int column;
- int index;
-
- switch (key)
- {
- case K_MOUSE1:
- if (l->generic.flags & QMF_HASMOUSEFOCUS)
- {
- // check scroll region
- x = l->generic.x;
- y = l->generic.y;
- w = ( (l->width + l->seperation) * l->columns - l->seperation) * SMALLCHAR_WIDTH;
- if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
- x -= w / 2;
- }
- if (UI_CursorInRect( x, y, w, l->height*SMALLCHAR_HEIGHT ))
- {
- cursorx = (uis.cursorx - x)/SMALLCHAR_WIDTH;
- column = cursorx / (l->width + l->seperation);
- cursory = (uis.cursory - y)/SMALLCHAR_HEIGHT;
- index = column * l->height + cursory;
- if (l->top + index < l->numitems)
- {
- l->oldvalue = l->curvalue;
- l->curvalue = l->top + index;
-
- if (l->oldvalue != l->curvalue && l->generic.callback)
- {
- l->generic.callback( l, QM_GOTFOCUS );
- return (menu_move_sound);
- }
- }
- }
-
- // absorbed, silent sound effect
- return (menu_null_sound);
- }
- break;
-
- case K_KP_HOME:
- case K_HOME:
- l->oldvalue = l->curvalue;
- l->curvalue = 0;
- l->top = 0;
-
- if (l->oldvalue != l->curvalue && l->generic.callback)
- {
- l->generic.callback( l, QM_GOTFOCUS );
- return (menu_move_sound);
- }
- return (menu_buzz_sound);
-
- case K_KP_END:
- case K_END:
- l->oldvalue = l->curvalue;
- l->curvalue = l->numitems-1;
- if( l->columns > 1 ) {
- c = (l->curvalue / l->height + 1) * l->height;
- l->top = c - (l->columns * l->height);
- }
- else {
- l->top = l->curvalue - (l->height - 1);
- }
- if (l->top < 0)
- l->top = 0;
-
- if (l->oldvalue != l->curvalue && l->generic.callback)
- {
- l->generic.callback( l, QM_GOTFOCUS );
- return (menu_move_sound);
- }
- return (menu_buzz_sound);
-
- case K_PGUP:
- case K_KP_PGUP:
- if( l->columns > 1 ) {
- return menu_null_sound;
- }
-
- if (l->curvalue > 0)
- {
- l->oldvalue = l->curvalue;
- l->curvalue -= l->height-1;
- if (l->curvalue < 0)
- l->curvalue = 0;
- l->top = l->curvalue;
- if (l->top < 0)
- l->top = 0;
-
- if (l->generic.callback)
- l->generic.callback( l, QM_GOTFOCUS );
-
- return (menu_move_sound);
- }
- return (menu_buzz_sound);
-
- case K_PGDN:
- case K_KP_PGDN:
- if( l->columns > 1 ) {
- return menu_null_sound;
- }
-
- if (l->curvalue < l->numitems-1)
- {
- l->oldvalue = l->curvalue;
- l->curvalue += l->height-1;
- if (l->curvalue > l->numitems-1)
- l->curvalue = l->numitems-1;
- l->top = l->curvalue - (l->height-1);
- if (l->top < 0)
- l->top = 0;
-
- if (l->generic.callback)
- l->generic.callback( l, QM_GOTFOCUS );
-
- return (menu_move_sound);
- }
- return (menu_buzz_sound);
-
- case K_KP_UPARROW:
- case K_UPARROW:
- if( l->curvalue == 0 ) {
- return menu_buzz_sound;
- }
-
- l->oldvalue = l->curvalue;
- l->curvalue--;
-
- if( l->curvalue < l->top ) {
- if( l->columns == 1 ) {
- l->top--;
- }
- else {
- l->top -= l->height;
- }
- }
-
- if( l->generic.callback ) {
- l->generic.callback( l, QM_GOTFOCUS );
- }
-
- return (menu_move_sound);
-
- case K_KP_DOWNARROW:
- case K_DOWNARROW:
- if( l->curvalue == l->numitems - 1 ) {
- return menu_buzz_sound;
- }
-
- l->oldvalue = l->curvalue;
- l->curvalue++;
-
- if( l->curvalue >= l->top + l->columns * l->height ) {
- if( l->columns == 1 ) {
- l->top++;
- }
- else {
- l->top += l->height;
- }
- }
-
- if( l->generic.callback ) {
- l->generic.callback( l, QM_GOTFOCUS );
- }
-
- return menu_move_sound;
-
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- if( l->columns == 1 ) {
- return menu_null_sound;
- }
-
- if( l->curvalue < l->height ) {
- return menu_buzz_sound;
- }
-
- l->oldvalue = l->curvalue;
- l->curvalue -= l->height;
-
- if( l->curvalue < l->top ) {
- l->top -= l->height;
- }
-
- if( l->generic.callback ) {
- l->generic.callback( l, QM_GOTFOCUS );
- }
-
- return menu_move_sound;
-
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- if( l->columns == 1 ) {
- return menu_null_sound;
- }
-
- c = l->curvalue + l->height;
-
- if( c >= l->numitems ) {
- return menu_buzz_sound;
- }
-
- l->oldvalue = l->curvalue;
- l->curvalue = c;
-
- if( l->curvalue > l->top + l->columns * l->height - 1 ) {
- l->top += l->height;
- }
-
- if( l->generic.callback ) {
- l->generic.callback( l, QM_GOTFOCUS );
- }
-
- return menu_move_sound;
- }
-
- // cycle look for ascii key inside list items
- if ( !Q_isprint( key ) )
- return (0);
-
- // force to lower for case insensitive compare
- if ( Q_isupper( key ) )
- {
- key -= 'A' - 'a';
- }
-
- // iterate list items
- for (i=1; i<=l->numitems; i++)
- {
- j = (l->curvalue + i) % l->numitems;
- c = l->itemnames[j][0];
- if ( Q_isupper( c ) )
- {
- c -= 'A' - 'a';
- }
-
- if (c == key)
- {
- // set current item, mimic windows listbox scroll behavior
- if (j < l->top)
- {
- // behind top most item, set this as new top
- l->top = j;
- }
- else if (j > l->top+l->height-1)
- {
- // past end of list box, do page down
- l->top = (j+1) - l->height;
- }
-
- if (l->curvalue != j)
- {
- l->oldvalue = l->curvalue;
- l->curvalue = j;
- if (l->generic.callback)
- l->generic.callback( l, QM_GOTFOCUS );
- return ( menu_move_sound );
- }
-
- return (menu_buzz_sound);
- }
- }
-
- return (menu_buzz_sound);
-}
-
-/*
-=================
-ScrollList_Draw
-=================
-*/
-void ScrollList_Draw( menulist_s *l )
-{
- int x;
- int u;
- int y;
- int i;
- int base;
- int column;
- float* color;
- qboolean hasfocus;
- int style;
-
- hasfocus = (l->generic.parent->cursor == l->generic.menuPosition);
-
- x = l->generic.x;
- for( column = 0; column < l->columns; column++ ) {
- y = l->generic.y;
- base = l->top + column * l->height;
- for( i = base; i < base + l->height; i++) {
- if (i >= l->numitems)
- break;
-
- if (i == l->curvalue)
- {
- u = x - 2;
- if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
- u -= (l->width * SMALLCHAR_WIDTH) / 2 + 1;
- }
-
- UI_FillRect(u,y,l->width*SMALLCHAR_WIDTH,SMALLCHAR_HEIGHT+2,listbar_color);
- color = text_color_highlight;
-
- if (hasfocus)
- style = UI_PULSE|UI_LEFT|UI_SMALLFONT;
- else
- style = UI_LEFT|UI_SMALLFONT;
- }
- else
- {
- color = text_color_normal;
- style = UI_LEFT|UI_SMALLFONT;
- }
- if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
- style |= UI_CENTER;
- }
-
- UI_DrawString(
- x,
- y,
- l->itemnames[i],
- style,
- color);
-
- y += SMALLCHAR_HEIGHT;
- }
- x += (l->width + l->seperation) * SMALLCHAR_WIDTH;
- }
-}
-
-/*
-=================
-Menu_AddItem
-=================
-*/
-void Menu_AddItem( menuframework_s *menu, void *item )
-{
- menucommon_s *itemptr;
-
- if (menu->nitems >= MAX_MENUITEMS)
- trap_Error ("Menu_AddItem: excessive items");
-
- menu->items[menu->nitems] = item;
- ((menucommon_s*)menu->items[menu->nitems])->parent = menu;
- ((menucommon_s*)menu->items[menu->nitems])->menuPosition = menu->nitems;
- ((menucommon_s*)menu->items[menu->nitems])->flags &= ~QMF_HASMOUSEFOCUS;
-
- // perform any item specific initializations
- itemptr = (menucommon_s*)item;
- if (!(itemptr->flags & QMF_NODEFAULTINIT))
- {
- switch (itemptr->type)
- {
- case MTYPE_ACTION:
- Action_Init((menuaction_s*)item);
- break;
-
- case MTYPE_FIELD:
- MenuField_Init((menufield_s*)item);
- break;
-
- case MTYPE_SPINCONTROL:
- SpinControl_Init((menulist_s*)item);
- break;
-
- case MTYPE_RADIOBUTTON:
- RadioButton_Init((menuradiobutton_s*)item);
- break;
-
- case MTYPE_SLIDER:
- Slider_Init((menuslider_s*)item);
- break;
-
- case MTYPE_BITMAP:
- Bitmap_Init((menubitmap_s*)item);
- break;
-
- case MTYPE_TEXT:
- Text_Init((menutext_s*)item);
- break;
-
- case MTYPE_SCROLLLIST:
- ScrollList_Init((menulist_s*)item);
- break;
-
- case MTYPE_PTEXT:
- PText_Init((menutext_s*)item);
- break;
-
- case MTYPE_BTEXT:
- BText_Init((menutext_s*)item);
- break;
-
- default:
- trap_Error( va("Menu_Init: unknown type %d", itemptr->type) );
- }
- }
-
- menu->nitems++;
-}
-
-/*
-=================
-Menu_CursorMoved
-=================
-*/
-void Menu_CursorMoved( menuframework_s *m )
-{
- void (*callback)( void *self, int notification );
-
- if (m->cursor_prev == m->cursor)
- return;
-
- if (m->cursor_prev >= 0 && m->cursor_prev < m->nitems)
- {
- callback = ((menucommon_s*)(m->items[m->cursor_prev]))->callback;
- if (callback)
- callback(m->items[m->cursor_prev],QM_LOSTFOCUS);
- }
-
- if (m->cursor >= 0 && m->cursor < m->nitems)
- {
- callback = ((menucommon_s*)(m->items[m->cursor]))->callback;
- if (callback)
- callback(m->items[m->cursor],QM_GOTFOCUS);
- }
-}
-
-/*
-=================
-Menu_SetCursor
-=================
-*/
-void Menu_SetCursor( menuframework_s *m, int cursor )
-{
- if (((menucommon_s*)(m->items[cursor]))->flags & (QMF_GRAYED|QMF_INACTIVE))
- {
- // cursor can't go there
- return;
- }
-
- m->cursor_prev = m->cursor;
- m->cursor = cursor;
-
- Menu_CursorMoved( m );
-}
-
-/*
-=================
-Menu_SetCursorToItem
-=================
-*/
-void Menu_SetCursorToItem( menuframework_s *m, void* ptr )
-{
- int i;
-
- for (i=0; i<m->nitems; i++)
- {
- if (m->items[i] == ptr)
- {
- Menu_SetCursor( m, i );
- return;
- }
- }
-}
-
-/*
-** Menu_AdjustCursor
-**
-** This function takes the given menu, the direction, and attempts
-** to adjust the menu's cursor so that it's at the next available
-** slot.
-*/
-void Menu_AdjustCursor( menuframework_s *m, int dir ) {
- menucommon_s *item = NULL;
- qboolean wrapped = qfalse;
-
-wrap:
- while ( m->cursor >= 0 && m->cursor < m->nitems ) {
- item = ( menucommon_s * ) m->items[m->cursor];
- if (( item->flags & (QMF_GRAYED|QMF_MOUSEONLY|QMF_INACTIVE) ) ) {
- m->cursor += dir;
- }
- else {
- break;
- }
- }
-
- if ( dir == 1 ) {
- if ( m->cursor >= m->nitems ) {
- if ( m->wrapAround ) {
- if ( wrapped ) {
- m->cursor = m->cursor_prev;
- return;
- }
- m->cursor = 0;
- wrapped = qtrue;
- goto wrap;
- }
- m->cursor = m->cursor_prev;
- }
- }
- else {
- if ( m->cursor < 0 ) {
- if ( m->wrapAround ) {
- if ( wrapped ) {
- m->cursor = m->cursor_prev;
- return;
- }
- m->cursor = m->nitems - 1;
- wrapped = qtrue;
- goto wrap;
- }
- m->cursor = m->cursor_prev;
- }
- }
-}
-
-/*
-=================
-Menu_Draw
-=================
-*/
-void Menu_Draw( menuframework_s *menu )
-{
- int i;
- menucommon_s *itemptr;
-
- // draw menu
- for (i=0; i<menu->nitems; i++)
- {
- itemptr = (menucommon_s*)menu->items[i];
-
- if (itemptr->flags & QMF_HIDDEN)
- continue;
-
- if (itemptr->ownerdraw)
- {
- // total subclassing, owner draws everything
- itemptr->ownerdraw( itemptr );
- }
- else
- {
- switch (itemptr->type)
- {
- case MTYPE_RADIOBUTTON:
- RadioButton_Draw( (menuradiobutton_s*)itemptr );
- break;
-
- case MTYPE_FIELD:
- MenuField_Draw( (menufield_s*)itemptr );
- break;
-
- case MTYPE_SLIDER:
- Slider_Draw( (menuslider_s*)itemptr );
- break;
-
- case MTYPE_SPINCONTROL:
- SpinControl_Draw( (menulist_s*)itemptr );
- break;
-
- case MTYPE_ACTION:
- Action_Draw( (menuaction_s*)itemptr );
- break;
-
- case MTYPE_BITMAP:
- Bitmap_Draw( (menubitmap_s*)itemptr );
- break;
-
- case MTYPE_TEXT:
- Text_Draw( (menutext_s*)itemptr );
- break;
-
- case MTYPE_SCROLLLIST:
- ScrollList_Draw( (menulist_s*)itemptr );
- break;
-
- case MTYPE_PTEXT:
- PText_Draw( (menutext_s*)itemptr );
- break;
-
- case MTYPE_BTEXT:
- BText_Draw( (menutext_s*)itemptr );
- break;
-
- default:
- trap_Error( va("Menu_Draw: unknown type %d", itemptr->type) );
- }
- }
-#ifndef NDEBUG
- if( uis.debug ) {
- int x;
- int y;
- int w;
- int h;
-
- if( !( itemptr->flags & QMF_INACTIVE ) ) {
- x = itemptr->left;
- y = itemptr->top;
- w = itemptr->right - itemptr->left + 1;
- h = itemptr->bottom - itemptr->top + 1;
-
- if (itemptr->flags & QMF_HASMOUSEFOCUS) {
- UI_DrawRect(x, y, w, h, colorYellow );
- }
- else {
- UI_DrawRect(x, y, w, h, colorWhite );
- }
- }
- }
-#endif
- }
-
- itemptr = Menu_ItemAtCursor( menu );
- if ( itemptr && itemptr->statusbar)
- itemptr->statusbar( ( void * ) itemptr );
-}
-
-/*
-=================
-Menu_ItemAtCursor
-=================
-*/
-void *Menu_ItemAtCursor( menuframework_s *m )
-{
- if ( m->cursor < 0 || m->cursor >= m->nitems )
- return NULL;
-
- return m->items[m->cursor];
-}
-
-/*
-=================
-Menu_ActivateItem
-=================
-*/
-sfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item ) {
- if ( item->callback ) {
- item->callback( item, QM_ACTIVATED );
- if( !( item->flags & QMF_SILENT ) ) {
- return menu_move_sound;
- }
- }
-
- return 0;
-}
-
-/*
-=================
-Menu_DefaultKey
-=================
-*/
-sfxHandle_t Menu_DefaultKey( menuframework_s *m, int key )
-{
- sfxHandle_t sound = 0;
- menucommon_s *item;
- int cursor_prev;
-
- // menu system keys
- switch ( key )
- {
- case K_MOUSE2:
- case K_ESCAPE:
- UI_PopMenu();
- return menu_out_sound;
- }
-
- if (!m || !m->nitems)
- return 0;
-
- // route key stimulus to widget
- item = Menu_ItemAtCursor( m );
- if (item && !(item->flags & (QMF_GRAYED|QMF_INACTIVE)))
- {
- switch (item->type)
- {
- case MTYPE_SPINCONTROL:
- sound = SpinControl_Key( (menulist_s*)item, key );
- break;
-
- case MTYPE_RADIOBUTTON:
- sound = RadioButton_Key( (menuradiobutton_s*)item, key );
- break;
-
- case MTYPE_SLIDER:
- sound = Slider_Key( (menuslider_s*)item, key );
- break;
-
- case MTYPE_SCROLLLIST:
- sound = ScrollList_Key( (menulist_s*)item, key );
- break;
-
- case MTYPE_FIELD:
- sound = MenuField_Key( (menufield_s*)item, &key );
- break;
- }
-
- if (sound) {
- // key was handled
- return sound;
- }
- }
-
- // default handling
- switch ( key )
- {
-#ifndef NDEBUG
- case K_F11:
- uis.debug ^= 1;
- break;
-
- case K_F12:
- trap_Cmd_ExecuteText(EXEC_APPEND, "screenshot\n");
- break;
-#endif
- case K_KP_UPARROW:
- case K_UPARROW:
- cursor_prev = m->cursor;
- m->cursor_prev = m->cursor;
- m->cursor--;
- Menu_AdjustCursor( m, -1 );
- if ( cursor_prev != m->cursor ) {
- Menu_CursorMoved( m );
- sound = menu_move_sound;
- }
- break;
-
- case K_TAB:
- case K_KP_DOWNARROW:
- case K_DOWNARROW:
- cursor_prev = m->cursor;
- m->cursor_prev = m->cursor;
- m->cursor++;
- Menu_AdjustCursor( m, 1 );
- if ( cursor_prev != m->cursor ) {
- Menu_CursorMoved( m );
- sound = menu_move_sound;
- }
- break;
-
- case K_MOUSE1:
- case K_MOUSE3:
- if (item)
- if ((item->flags & QMF_HASMOUSEFOCUS) && !(item->flags & (QMF_GRAYED|QMF_INACTIVE)))
- return (Menu_ActivateItem( m, item ));
- break;
-
- case K_JOY1:
- case K_JOY2:
- case K_JOY3:
- case K_JOY4:
- case K_AUX1:
- case K_AUX2:
- case K_AUX3:
- case K_AUX4:
- case K_AUX5:
- case K_AUX6:
- case K_AUX7:
- case K_AUX8:
- case K_AUX9:
- case K_AUX10:
- case K_AUX11:
- case K_AUX12:
- case K_AUX13:
- case K_AUX14:
- case K_AUX15:
- case K_AUX16:
- case K_KP_ENTER:
- case K_ENTER:
- if (item)
- if (!(item->flags & (QMF_MOUSEONLY|QMF_GRAYED|QMF_INACTIVE)))
- return (Menu_ActivateItem( m, item ));
- break;
- }
-
- return sound;
-}
-
-/*
-=================
-Menu_Cache
-=================
-*/
-void Menu_Cache( void )
-{
- uis.charset = trap_R_RegisterShaderNoMip( "gfx/2d/bigchars" );
- uis.charsetProp = trap_R_RegisterShaderNoMip( "menu/art/font1_prop.tga" );
- uis.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" );
- uis.charsetPropB = trap_R_RegisterShaderNoMip( "menu/art/font2_prop.tga" );
- uis.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
- uis.rb_on = trap_R_RegisterShaderNoMip( "menu/art/switch_on" );
- uis.rb_off = trap_R_RegisterShaderNoMip( "menu/art/switch_off" );
-
- uis.whiteShader = trap_R_RegisterShaderNoMip( "white" );
- if ( uis.glconfig.hardwareType == GLHW_RAGEPRO ) {
- // the blend effect turns to shit with the normal
- uis.menuBackShader = trap_R_RegisterShaderNoMip( "menubackRagePro" );
- } else {
- uis.menuBackShader = trap_R_RegisterShaderNoMip( "menuback" );
- }
- uis.menuBackNoLogoShader = trap_R_RegisterShaderNoMip( "menubacknologo" );
-
- menu_in_sound = trap_S_RegisterSound( "sound/misc/menu1.wav", qfalse );
- menu_move_sound = trap_S_RegisterSound( "sound/misc/menu2.wav", qfalse );
- menu_out_sound = trap_S_RegisterSound( "sound/misc/menu3.wav", qfalse );
- menu_buzz_sound = trap_S_RegisterSound( "sound/misc/menu4.wav", qfalse );
- weaponChangeSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse );
-
- // need a nonzero sound, make an empty sound for this
- menu_null_sound = -1;
-
- sliderBar = trap_R_RegisterShaderNoMip( "menu/art/slider2" );
- sliderButton_0 = trap_R_RegisterShaderNoMip( "menu/art/sliderbutt_0" );
- sliderButton_1 = trap_R_RegisterShaderNoMip( "menu/art/sliderbutt_1" );
-}
-
diff --git a/engine/code/q3_ui/ui_rankings.c b/engine/code/q3_ui/ui_rankings.c
deleted file mode 100644
index cba8f4b..0000000
--- a/engine/code/q3_ui/ui_rankings.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-//
-// ui_rankings.c
-//
-
-#include "ui_local.h"
-
-
-#define RANKINGS_FRAME "menu/art/cut_frame"
-
-#define ID_LOGIN 100
-#define ID_LOGOUT 101
-#define ID_CREATE 102
-#define ID_SPECTATE 103
-#define ID_SETUP 104
-#define ID_LEAVE 105
-
-
-typedef struct
-{
- menuframework_s menu;
- menubitmap_s frame;
- menutext_s login;
- menutext_s logout;
- menutext_s create;
- menutext_s spectate;
- menutext_s setup;
- menutext_s leave;
-} rankings_t;
-
-static rankings_t s_rankings;
-
-static menuframework_s s_rankings_menu;
-static menuaction_s s_rankings_login;
-static menuaction_s s_rankings_logout;
-static menuaction_s s_rankings_create;
-static menuaction_s s_rankings_spectate;
-static menuaction_s s_rankings_setup;
-static menuaction_s s_rankings_leave;
-
-
-/*
-===============
-Rankings_DrawText
-===============
-*/
-void Rankings_DrawText( void* self )
-{
- menufield_s *f;
- qboolean focus;
- int style;
- char *txt;
- char c;
- float *color;
- int basex, x, y;
-
- f = (menufield_s*)self;
- basex = f->generic.x;
- y = f->generic.y + 4;
- focus = (f->generic.parent->cursor == f->generic.menuPosition);
-
- style = UI_LEFT|UI_SMALLFONT;
- color = text_color_normal;
- if( focus ) {
- style |= UI_PULSE;
- color = text_color_highlight;
- }
-
- // draw the actual text
- txt = f->field.buffer;
- color = g_color_table[ColorIndex(COLOR_WHITE)];
- x = basex;
- while ( (c = *txt) != 0 ) {
- UI_DrawChar( x, y, c, style, color );
- txt++;
- x += SMALLCHAR_WIDTH;
- }
-
- // draw cursor if we have focus
- if( focus ) {
- if ( trap_Key_GetOverstrikeMode() ) {
- c = 11;
- } else {
- c = 10;
- }
-
- style &= ~UI_PULSE;
- style |= UI_BLINK;
-
- UI_DrawChar( basex + f->field.cursor * SMALLCHAR_WIDTH, y, c, style, color_white );
- }
-}
-
-/*
-===============
-Rankings_DrawName
-===============
-*/
-void Rankings_DrawName( void* self )
-{
- menufield_s *f;
- int length;
- char* p;
-
- f = (menufield_s*)self;
-
- // GRANK_FIXME - enforce valid characters
- for( p = f->field.buffer; *p != '\0'; p++ )
- {
- //if( ispunct(*p) || isspace(*p) )
- if( !( ( (*p) >= '0' && (*p) <= '9') || Q_isalpha(*p)) )
- {
- *p = '\0';
- }
- }
-
- // strip color codes
- Q_CleanStr( f->field.buffer );
- length = strlen( f->field.buffer );
- if( f->field.cursor > length )
- {
- f->field.cursor = length;
- }
-
- Rankings_DrawText( f );
-}
-
-#if 0 // old version
-/*
-===============
-Rankings_DrawName
-===============
-*/
-void Rankings_DrawName( void* self )
-{
- menufield_s* f;
- int length;
-
- f = (menufield_s*)self;
-
- // strip color codes
- Q_CleanStr( f->field.buffer );
- length = strlen( f->field.buffer );
- if( f->field.cursor > length )
- {
- f->field.cursor = length;
- }
-
- // show beginning of long names
- /*
- if( Menu_ItemAtCursor( f->generic.parent ) != f )
- {
- if( f->field.scroll > 0 )
- {
- f->field.cursor = 0;
- f->field.scroll = 0;
- }
- }
- */
-
- MenuField_Draw( f );
-}
-#endif
-
-/*
-===============
-Rankings_DrawPassword
-===============
-*/
-void Rankings_DrawPassword( void* self )
-{
- menufield_s* f;
- char password[MAX_EDIT_LINE];
- int length;
- int i;
- char* p;
-
- f = (menufield_s*)self;
-
- // GRANK_FIXME - enforce valid characters
- for( p = f->field.buffer; *p != '\0'; p++ )
- {
- //if( ispunct(*p) || isspace(*p) )
- if( !( ( (*p) >= '0' && (*p) <= '9') || Q_isalpha(*p)) )
- {
- *p = '\0';
- }
- }
-
- length = strlen( f->field.buffer );
- if( f->field.cursor > length )
- {
- f->field.cursor = length;
- }
-
- // save password
- Q_strncpyz( password, f->field.buffer, sizeof(password) );
-
- // mask password with *
- for( i = 0; i < length; i++ )
- {
- f->field.buffer[i] = '*';
- }
-
- // draw masked password
- Rankings_DrawText( f );
- //MenuField_Draw( f );
-
- // restore password
- Q_strncpyz( f->field.buffer, password, sizeof(f->field.buffer) );
-}
-
-/*
-===============
-Rankings_MenuEvent
-===============
-*/
-static void Rankings_MenuEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_LOGIN:
- UI_LoginMenu();
- break;
-
- case ID_LOGOUT:
- // server side masqueraded player logout first
- trap_CL_UI_RankUserRequestLogout();
- UI_ForceMenuOff();
- break;
-
- case ID_CREATE:
- UI_SignupMenu();
- break;
-
- case ID_SPECTATE:
- trap_Cmd_ExecuteText( EXEC_APPEND, "cmd rank_spectate\n" );
- UI_ForceMenuOff();
- break;
-
- case ID_SETUP:
- UI_SetupMenu();
- break;
-
- case ID_LEAVE:
- trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" );
- UI_ForceMenuOff();
- break;
-
- }
-}
-
-
-/*
-===============
-Rankings_MenuInit
-===============
-*/
-void Rankings_MenuInit( void ) {
- grank_status_t status;
- int y;
-
- memset( &s_rankings, 0, sizeof(s_rankings) );
-
- Rankings_Cache();
-
- s_rankings.menu.wrapAround = qtrue;
- s_rankings.menu.fullscreen = qfalse;
-
- s_rankings.frame.generic.type = MTYPE_BITMAP;
- s_rankings.frame.generic.flags = QMF_INACTIVE;
- s_rankings.frame.generic.name = RANKINGS_FRAME;
- s_rankings.frame.generic.x = 142;
- s_rankings.frame.generic.y = 118;
- s_rankings.frame.width = 359;
- s_rankings.frame.height = 256;
-
- y = 194;
-
- s_rankings.login.generic.type = MTYPE_PTEXT;
- s_rankings.login.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_rankings.login.generic.id = ID_LOGIN;
- s_rankings.login.generic.callback = Rankings_MenuEvent;
- s_rankings.login.generic.x = 320;
- s_rankings.login.generic.y = y;
- s_rankings.login.string = "LOGIN";
- s_rankings.login.style = UI_CENTER|UI_SMALLFONT;
- s_rankings.login.color = colorRed;
- y += 20;
-
- s_rankings.logout.generic.type = MTYPE_PTEXT;
- s_rankings.logout.generic.flags = QMF_HIDDEN|QMF_INACTIVE|QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_rankings.logout.generic.id = ID_LOGOUT;
- s_rankings.logout.generic.callback = Rankings_MenuEvent;
- s_rankings.logout.generic.x = 320;
- s_rankings.logout.generic.y = y;
- s_rankings.logout.string = "LOGOUT";
- s_rankings.logout.style = UI_CENTER|UI_SMALLFONT;
- s_rankings.logout.color = colorRed;
-
- s_rankings.create.generic.type = MTYPE_PTEXT;
- s_rankings.create.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_rankings.create.generic.id = ID_CREATE;
- s_rankings.create.generic.callback = Rankings_MenuEvent;
- s_rankings.create.generic.x = 320;
- s_rankings.create.generic.y = y;
- s_rankings.create.string = "SIGN UP";
- s_rankings.create.style = UI_CENTER|UI_SMALLFONT;
- s_rankings.create.color = colorRed;
- y += 20;
-
- s_rankings.spectate.generic.type = MTYPE_PTEXT;
- s_rankings.spectate.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_rankings.spectate.generic.id = ID_SPECTATE;
- s_rankings.spectate.generic.callback = Rankings_MenuEvent;
- s_rankings.spectate.generic.x = 320;
- s_rankings.spectate.generic.y = y;
- s_rankings.spectate.string = "SPECTATE";
- s_rankings.spectate.style = UI_CENTER|UI_SMALLFONT;
- s_rankings.spectate.color = colorRed;
- y += 20;
-
- s_rankings.setup.generic.type = MTYPE_PTEXT;
- s_rankings.setup.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_rankings.setup.generic.id = ID_SETUP;
- s_rankings.setup.generic.callback = Rankings_MenuEvent;
- s_rankings.setup.generic.x = 320;
- s_rankings.setup.generic.y = y;
- s_rankings.setup.string = "SETUP";
- s_rankings.setup.style = UI_CENTER|UI_SMALLFONT;
- s_rankings.setup.color = colorRed;
- y += 20;
-
- s_rankings.leave.generic.type = MTYPE_PTEXT;
- s_rankings.leave.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_rankings.leave.generic.id = ID_LEAVE;
- s_rankings.leave.generic.callback = Rankings_MenuEvent;
- s_rankings.leave.generic.x = 320;
- s_rankings.leave.generic.y = y;
- s_rankings.leave.string = "LEAVE ARENA";
- s_rankings.leave.style = UI_CENTER|UI_SMALLFONT;
- s_rankings.leave.color = colorRed;
- y += 20;
-
- status = (grank_status_t)trap_Cvar_VariableValue("client_status");
- if( (status != QGR_STATUS_NEW) && (status != QGR_STATUS_SPECTATOR) )
- {
- s_rankings.login.generic.flags |= QMF_HIDDEN | QMF_INACTIVE;
- s_rankings.create.generic.flags |= QMF_HIDDEN | QMF_INACTIVE;
- s_rankings.spectate.generic.flags |= QMF_HIDDEN | QMF_INACTIVE;
-
- s_rankings.logout.generic.flags &= ~(QMF_HIDDEN | QMF_INACTIVE);
- }
-
- if ( (status == QGR_STATUS_VALIDATING) ||
- (status == QGR_STATUS_PENDING) ||
- (status == QGR_STATUS_LEAVING) )
- {
- s_rankings.login.generic.flags |= QMF_GRAYED;
- s_rankings.create.generic.flags |= QMF_GRAYED;
- s_rankings.logout.generic.flags |= QMF_GRAYED;
- }
-
- //GRank FIXME -- don't need setup option any more
- s_rankings.setup.generic.flags |= QMF_HIDDEN | QMF_INACTIVE;
-
- Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.frame );
- Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.login );
- Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.logout );
- Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.create );
- Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.spectate );
- Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.setup );
- Menu_AddItem( &s_rankings.menu, (void*) &s_rankings.leave );
-}
-
-
-/*
-===============
-Rankings_Cache
-===============
-*/
-void Rankings_Cache( void ) {
- trap_R_RegisterShaderNoMip( RANKINGS_FRAME );
-}
-
-
-/*
-===============
-UI_RankingsMenu
-===============
-*/
-void UI_RankingsMenu( void ) {
- Rankings_MenuInit();
- UI_PushMenu ( &s_rankings.menu );
-}
-
-
diff --git a/engine/code/q3_ui/ui_rankstatus.c b/engine/code/q3_ui/ui_rankstatus.c
deleted file mode 100644
index c34bb0d..0000000
--- a/engine/code/q3_ui/ui_rankstatus.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-//
-// ui_rankstatus.c
-//
-
-#include "ui_local.h"
-
-
-#define RANKSTATUS_FRAME "menu/art/cut_frame"
-
-#define ID_MESSAGE 100
-#define ID_OK 101
-
-
-typedef struct
-{
- menuframework_s menu;
- menubitmap_s frame;
- menutext_s message;
- menutext_s ok;
-} rankstatus_t;
-
-static rankstatus_t s_rankstatus;
-
-static menuframework_s s_rankstatus_menu;
-static menuaction_s s_rankstatus_ok;
-
-static grank_status_t s_status = 0;
-static char* s_rankstatus_message = NULL;
-
-static vec4_t s_rankingstatus_color_prompt = {1.00, 0.43, 0.00, 1.00};
-
-/*
-===============
-RankStatus_MenuEvent
-===============
-*/
-static void RankStatus_MenuEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_OK:
- UI_PopMenu();
-
- switch( s_status )
- {
- case QGR_STATUS_NO_USER:
- UI_RankingsMenu();
- break;
- case QGR_STATUS_BAD_PASSWORD:
- UI_RankingsMenu();
- UI_LoginMenu();
- break;
- case QGR_STATUS_USER_EXISTS:
- UI_RankingsMenu();
- UI_SignupMenu();
- break;
- case QGR_STATUS_NO_MEMBERSHIP:
- UI_RankingsMenu();
- break;
- case QGR_STATUS_TIMEOUT:
- UI_RankingsMenu();
- break;
- case QGR_STATUS_INVALIDUSER:
- UI_RankingsMenu();
- break;
- case QGR_STATUS_ERROR:
- UI_RankingsMenu();
- break;
- default:
- break;
- }
-
- break;
- }
-}
-
-
-/*
-===============
-RankStatus_MenuInit
-===============
-*/
-void RankStatus_MenuInit( void ) {
- int y;
-
- memset( &s_rankstatus, 0, sizeof(s_rankstatus) );
-
- RankStatus_Cache();
-
- s_rankstatus.menu.wrapAround = qtrue;
- s_rankstatus.menu.fullscreen = qfalse;
-
- s_rankstatus.frame.generic.type = MTYPE_BITMAP;
- s_rankstatus.frame.generic.flags = QMF_INACTIVE;
- s_rankstatus.frame.generic.name = RANKSTATUS_FRAME;
- s_rankstatus.frame.generic.x = 142; //320-233;
- s_rankstatus.frame.generic.y = 118; //240-166;
- s_rankstatus.frame.width = 359; //466;
- s_rankstatus.frame.height = 256; //332;
-
- y = 214;
-
- s_rankstatus.message.generic.type = MTYPE_PTEXT;
- s_rankstatus.message.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
- s_rankstatus.message.generic.id = ID_MESSAGE;
- s_rankstatus.message.generic.x = 320;
- s_rankstatus.message.generic.y = y;
- s_rankstatus.message.string = s_rankstatus_message;
- s_rankstatus.message.style = UI_CENTER|UI_SMALLFONT;
- s_rankstatus.message.color = s_rankingstatus_color_prompt;
- y += 40;
-
- s_rankstatus.ok.generic.type = MTYPE_PTEXT;
- s_rankstatus.ok.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_rankstatus.ok.generic.id = ID_OK;
- s_rankstatus.ok.generic.callback = RankStatus_MenuEvent;
- s_rankstatus.ok.generic.x = 320;
- s_rankstatus.ok.generic.y = y;
- s_rankstatus.ok.string = "OK";
- s_rankstatus.ok.style = UI_CENTER|UI_SMALLFONT;
- s_rankstatus.ok.color = colorRed;
-
- Menu_AddItem( &s_rankstatus.menu, (void*) &s_rankstatus.frame );
- Menu_AddItem( &s_rankstatus.menu, (void*) &s_rankstatus.message );
- Menu_AddItem( &s_rankstatus.menu, (void*) &s_rankstatus.ok );
-}
-
-
-/*
-===============
-RankStatus_Cache
-===============
-*/
-void RankStatus_Cache( void ) {
- trap_R_RegisterShaderNoMip( RANKSTATUS_FRAME );
-}
-
-
-/*
-===============
-UI_RankStatusMenu
-===============
-*/
-void UI_RankStatusMenu( void ) {
-
- s_status = (grank_status_t)trap_Cvar_VariableValue("client_status");
-
- switch( s_status )
- {
- case QGR_STATUS_NEW:
- return;
- case QGR_STATUS_PENDING:
- // GRANK_FIXME
- return;
- case QGR_STATUS_NO_USER:
- // GRANK_FIXME - get this when user exists
- s_rankstatus_message = "Username unavailable";
- break;
- case QGR_STATUS_BAD_PASSWORD:
- s_rankstatus_message = "Invalid password";
- break;
- case QGR_STATUS_TIMEOUT:
- s_rankstatus_message = "Timed out";
- break;
- case QGR_STATUS_NO_MEMBERSHIP:
- s_rankstatus_message = "No membership";
- break;
- case QGR_STATUS_INVALIDUSER:
- s_rankstatus_message = "Validation failed";
- break;
- case QGR_STATUS_ERROR:
- s_rankstatus_message = "Error";
- break;
- case QGR_STATUS_SPECTATOR:
- case QGR_STATUS_ACTIVE:
- UI_ForceMenuOff();
- return;
- default:
- return;
- }
- RankStatus_MenuInit();
- trap_CL_UI_RankUserReset();
- UI_PushMenu ( &s_rankstatus.menu );
-}
-
diff --git a/engine/code/q3_ui/ui_removebots.c b/engine/code/q3_ui/ui_removebots.c
deleted file mode 100644
index f1c5239..0000000
--- a/engine/code/q3_ui/ui_removebots.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-REMOVE BOTS MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define ART_BACKGROUND "menu/art/addbotframe"
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-#define ART_DELETE0 "menu/art/delete_0"
-#define ART_DELETE1 "menu/art/delete_1"
-#define ART_ARROWS "menu/art/arrows_vert_0"
-#define ART_ARROWUP "menu/art/arrows_vert_top"
-#define ART_ARROWDOWN "menu/art/arrows_vert_bot"
-
-#define ID_UP 10
-#define ID_DOWN 11
-#define ID_DELETE 12
-#define ID_BACK 13
-#define ID_BOTNAME0 20
-#define ID_BOTNAME1 21
-#define ID_BOTNAME2 22
-#define ID_BOTNAME3 23
-#define ID_BOTNAME4 24
-#define ID_BOTNAME5 25
-#define ID_BOTNAME6 26
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s background;
-
- menubitmap_s arrows;
- menubitmap_s up;
- menubitmap_s down;
-
- menutext_s bots[7];
-
- menubitmap_s delete;
- menubitmap_s back;
-
- int numBots;
- int baseBotNum;
- int selectedBotNum;
- char botnames[7][32];
- int botClientNums[MAX_BOTS];
-} removeBotsMenuInfo_t;
-
-static removeBotsMenuInfo_t removeBotsMenuInfo;
-
-
-/*
-=================
-UI_RemoveBotsMenu_SetBotNames
-=================
-*/
-static void UI_RemoveBotsMenu_SetBotNames( void ) {
- int n;
- char info[MAX_INFO_STRING];
-
- for ( n = 0; (n < 7) && (removeBotsMenuInfo.baseBotNum + n < removeBotsMenuInfo.numBots); n++ ) {
- trap_GetConfigString( CS_PLAYERS + removeBotsMenuInfo.botClientNums[removeBotsMenuInfo.baseBotNum + n], info, MAX_INFO_STRING );
- Q_strncpyz( removeBotsMenuInfo.botnames[n], Info_ValueForKey( info, "n" ), sizeof(removeBotsMenuInfo.botnames[n]) );
- Q_CleanStr( removeBotsMenuInfo.botnames[n] );
- }
-
-}
-
-
-/*
-=================
-UI_RemoveBotsMenu_DeleteEvent
-=================
-*/
-static void UI_RemoveBotsMenu_DeleteEvent( void* ptr, int event ) {
- if (event != QM_ACTIVATED) {
- return;
- }
-
- trap_Cmd_ExecuteText( EXEC_APPEND, va("clientkick %i\n", removeBotsMenuInfo.botClientNums[removeBotsMenuInfo.baseBotNum + removeBotsMenuInfo.selectedBotNum]) );
-}
-
-
-/*
-=================
-UI_RemoveBotsMenu_BotEvent
-=================
-*/
-static void UI_RemoveBotsMenu_BotEvent( void* ptr, int event ) {
- if (event != QM_ACTIVATED) {
- return;
- }
-
- removeBotsMenuInfo.bots[removeBotsMenuInfo.selectedBotNum].color = color_orange;
- removeBotsMenuInfo.selectedBotNum = ((menucommon_s*)ptr)->id - ID_BOTNAME0;
- removeBotsMenuInfo.bots[removeBotsMenuInfo.selectedBotNum].color = color_white;
-}
-
-
-/*
-=================
-UI_RemoveAddBotsMenu_BackEvent
-=================
-*/
-static void UI_RemoveBotsMenu_BackEvent( void* ptr, int event ) {
- if (event != QM_ACTIVATED) {
- return;
- }
- UI_PopMenu();
-}
-
-
-/*
-=================
-UI_RemoveBotsMenu_UpEvent
-=================
-*/
-static void UI_RemoveBotsMenu_UpEvent( void* ptr, int event ) {
- if (event != QM_ACTIVATED) {
- return;
- }
-
- if( removeBotsMenuInfo.baseBotNum > 0 ) {
- removeBotsMenuInfo.baseBotNum--;
- UI_RemoveBotsMenu_SetBotNames();
- }
-}
-
-
-/*
-=================
-UI_RemoveBotsMenu_DownEvent
-=================
-*/
-static void UI_RemoveBotsMenu_DownEvent( void* ptr, int event ) {
- if (event != QM_ACTIVATED) {
- return;
- }
-
- if( removeBotsMenuInfo.baseBotNum + 7 < removeBotsMenuInfo.numBots ) {
- removeBotsMenuInfo.baseBotNum++;
- UI_RemoveBotsMenu_SetBotNames();
- }
-}
-
-
-/*
-=================
-UI_RemoveBotsMenu_GetBots
-=================
-*/
-static void UI_RemoveBotsMenu_GetBots( void ) {
- int numPlayers;
- int isBot;
- int n;
- char info[MAX_INFO_STRING];
-
- trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
- numPlayers = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
- removeBotsMenuInfo.numBots = 0;
-
- for( n = 0; n < numPlayers; n++ ) {
- trap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING );
-
- isBot = atoi( Info_ValueForKey( info, "skill" ) );
- if( !isBot ) {
- continue;
- }
-
- removeBotsMenuInfo.botClientNums[removeBotsMenuInfo.numBots] = n;
- removeBotsMenuInfo.numBots++;
- }
-}
-
-
-/*
-=================
-UI_RemoveBots_Cache
-=================
-*/
-void UI_RemoveBots_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_BACKGROUND );
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_DELETE0 );
- trap_R_RegisterShaderNoMip( ART_DELETE1 );
-}
-
-
-/*
-=================
-UI_RemoveBotsMenu_Init
-=================
-*/
-static void UI_RemoveBotsMenu_Init( void ) {
- int n;
- int count;
- int y;
-
- memset( &removeBotsMenuInfo, 0 ,sizeof(removeBotsMenuInfo) );
- removeBotsMenuInfo.menu.fullscreen = qfalse;
- removeBotsMenuInfo.menu.wrapAround = qtrue;
-
- UI_RemoveBots_Cache();
-
- UI_RemoveBotsMenu_GetBots();
- UI_RemoveBotsMenu_SetBotNames();
- count = removeBotsMenuInfo.numBots < 7 ? removeBotsMenuInfo.numBots : 7;
-
- removeBotsMenuInfo.banner.generic.type = MTYPE_BTEXT;
- removeBotsMenuInfo.banner.generic.x = 320;
- removeBotsMenuInfo.banner.generic.y = 16;
- removeBotsMenuInfo.banner.string = "REMOVE BOTS";
- removeBotsMenuInfo.banner.color = color_white;
- removeBotsMenuInfo.banner.style = UI_CENTER;
-
- removeBotsMenuInfo.background.generic.type = MTYPE_BITMAP;
- removeBotsMenuInfo.background.generic.name = ART_BACKGROUND;
- removeBotsMenuInfo.background.generic.flags = QMF_INACTIVE;
- removeBotsMenuInfo.background.generic.x = 320-233;
- removeBotsMenuInfo.background.generic.y = 240-166;
- removeBotsMenuInfo.background.width = 466;
- removeBotsMenuInfo.background.height = 332;
-
- removeBotsMenuInfo.arrows.generic.type = MTYPE_BITMAP;
- removeBotsMenuInfo.arrows.generic.name = ART_ARROWS;
- removeBotsMenuInfo.arrows.generic.flags = QMF_INACTIVE;
- removeBotsMenuInfo.arrows.generic.x = 200;
- removeBotsMenuInfo.arrows.generic.y = 128;
- removeBotsMenuInfo.arrows.width = 64;
- removeBotsMenuInfo.arrows.height = 128;
-
- removeBotsMenuInfo.up.generic.type = MTYPE_BITMAP;
- removeBotsMenuInfo.up.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- removeBotsMenuInfo.up.generic.x = 200;
- removeBotsMenuInfo.up.generic.y = 128;
- removeBotsMenuInfo.up.generic.id = ID_UP;
- removeBotsMenuInfo.up.generic.callback = UI_RemoveBotsMenu_UpEvent;
- removeBotsMenuInfo.up.width = 64;
- removeBotsMenuInfo.up.height = 64;
- removeBotsMenuInfo.up.focuspic = ART_ARROWUP;
-
- removeBotsMenuInfo.down.generic.type = MTYPE_BITMAP;
- removeBotsMenuInfo.down.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- removeBotsMenuInfo.down.generic.x = 200;
- removeBotsMenuInfo.down.generic.y = 128+64;
- removeBotsMenuInfo.down.generic.id = ID_DOWN;
- removeBotsMenuInfo.down.generic.callback = UI_RemoveBotsMenu_DownEvent;
- removeBotsMenuInfo.down.width = 64;
- removeBotsMenuInfo.down.height = 64;
- removeBotsMenuInfo.down.focuspic = ART_ARROWDOWN;
-
- for( n = 0, y = 120; n < count; n++, y += 20 ) {
- removeBotsMenuInfo.bots[n].generic.type = MTYPE_PTEXT;
- removeBotsMenuInfo.bots[n].generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- removeBotsMenuInfo.bots[n].generic.id = ID_BOTNAME0 + n;
- removeBotsMenuInfo.bots[n].generic.x = 320 - 56;
- removeBotsMenuInfo.bots[n].generic.y = y;
- removeBotsMenuInfo.bots[n].generic.callback = UI_RemoveBotsMenu_BotEvent;
- removeBotsMenuInfo.bots[n].string = removeBotsMenuInfo.botnames[n];
- removeBotsMenuInfo.bots[n].color = color_orange;
- removeBotsMenuInfo.bots[n].style = UI_LEFT|UI_SMALLFONT;
- }
-
- removeBotsMenuInfo.delete.generic.type = MTYPE_BITMAP;
- removeBotsMenuInfo.delete.generic.name = ART_DELETE0;
- removeBotsMenuInfo.delete.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- removeBotsMenuInfo.delete.generic.id = ID_DELETE;
- removeBotsMenuInfo.delete.generic.callback = UI_RemoveBotsMenu_DeleteEvent;
- removeBotsMenuInfo.delete.generic.x = 320+128-128;
- removeBotsMenuInfo.delete.generic.y = 256+128-64;
- removeBotsMenuInfo.delete.width = 128;
- removeBotsMenuInfo.delete.height = 64;
- removeBotsMenuInfo.delete.focuspic = ART_DELETE1;
-
- removeBotsMenuInfo.back.generic.type = MTYPE_BITMAP;
- removeBotsMenuInfo.back.generic.name = ART_BACK0;
- removeBotsMenuInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- removeBotsMenuInfo.back.generic.id = ID_BACK;
- removeBotsMenuInfo.back.generic.callback = UI_RemoveBotsMenu_BackEvent;
- removeBotsMenuInfo.back.generic.x = 320-128;
- removeBotsMenuInfo.back.generic.y = 256+128-64;
- removeBotsMenuInfo.back.width = 128;
- removeBotsMenuInfo.back.height = 64;
- removeBotsMenuInfo.back.focuspic = ART_BACK1;
-
- Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.background );
- Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.banner );
- Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.arrows );
- Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.up );
- Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.down );
- for( n = 0; n < count; n++ ) {
- Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.bots[n] );
- }
- Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.delete );
- Menu_AddItem( &removeBotsMenuInfo.menu, &removeBotsMenuInfo.back );
-
- removeBotsMenuInfo.baseBotNum = 0;
- removeBotsMenuInfo.selectedBotNum = 0;
- removeBotsMenuInfo.bots[0].color = color_white;
-}
-
-
-/*
-=================
-UI_RemoveBotsMenu
-=================
-*/
-void UI_RemoveBotsMenu( void ) {
- UI_RemoveBotsMenu_Init();
- UI_PushMenu( &removeBotsMenuInfo.menu );
-}
diff --git a/engine/code/q3_ui/ui_saveconfig.c b/engine/code/q3_ui/ui_saveconfig.c
deleted file mode 100644
index c9f0bc2..0000000
--- a/engine/code/q3_ui/ui_saveconfig.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=============================================================================
-
-SAVE CONFIG MENU
-
-=============================================================================
-*/
-
-#include "ui_local.h"
-
-
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-#define ART_SAVE0 "menu/art/save_0"
-#define ART_SAVE1 "menu/art/save_1"
-#define ART_BACKGROUND "menu/art/cut_frame"
-
-#define ID_NAME 10
-#define ID_BACK 11
-#define ID_SAVE 12
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s background;
- menufield_s savename;
- menubitmap_s back;
- menubitmap_s save;
-} saveConfig_t;
-
-static saveConfig_t saveConfig;
-
-
-/*
-===============
-UI_SaveConfigMenu_BackEvent
-===============
-*/
-static void UI_SaveConfigMenu_BackEvent( void *ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- UI_PopMenu();
-}
-
-
-/*
-===============
-UI_SaveConfigMenu_SaveEvent
-===============
-*/
-static void UI_SaveConfigMenu_SaveEvent( void *ptr, int event ) {
- char configname[MAX_QPATH];
-
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- if( !saveConfig.savename.field.buffer[0] ) {
- return;
- }
-
- COM_StripExtension(saveConfig.savename.field.buffer, configname, sizeof(configname));
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "writeconfig %s.cfg\n", configname ) );
- UI_PopMenu();
-}
-
-
-/*
-===============
-UI_SaveConfigMenu_SavenameDraw
-===============
-*/
-static void UI_SaveConfigMenu_SavenameDraw( void *self ) {
- menufield_s *f;
- int style;
- float *color;
-
- f = (menufield_s *)self;
-
- if( f == Menu_ItemAtCursor( &saveConfig.menu ) ) {
- style = UI_LEFT|UI_PULSE|UI_SMALLFONT;
- color = text_color_highlight;
- }
- else {
- style = UI_LEFT|UI_SMALLFONT;
- color = colorRed;
- }
-
- UI_DrawProportionalString( 320, 192, "Enter filename:", UI_CENTER|UI_SMALLFONT, color_orange );
- UI_FillRect( f->generic.x, f->generic.y, f->field.widthInChars*SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, colorBlack );
- MField_Draw( &f->field, f->generic.x, f->generic.y, style, color );
-}
-
-
-/*
-=================
-UI_SaveConfigMenu_Init
-=================
-*/
-static void UI_SaveConfigMenu_Init( void ) {
- memset( &saveConfig, 0, sizeof(saveConfig) );
-
- UI_SaveConfigMenu_Cache();
- saveConfig.menu.wrapAround = qtrue;
- saveConfig.menu.fullscreen = qtrue;
-
- saveConfig.banner.generic.type = MTYPE_BTEXT;
- saveConfig.banner.generic.x = 320;
- saveConfig.banner.generic.y = 16;
- saveConfig.banner.string = "SAVE CONFIG";
- saveConfig.banner.color = color_white;
- saveConfig.banner.style = UI_CENTER;
-
- saveConfig.background.generic.type = MTYPE_BITMAP;
- saveConfig.background.generic.name = ART_BACKGROUND;
- saveConfig.background.generic.flags = QMF_INACTIVE;
- saveConfig.background.generic.x = 142;
- saveConfig.background.generic.y = 118;
- saveConfig.background.width = 359;
- saveConfig.background.height = 256;
-
- saveConfig.savename.generic.type = MTYPE_FIELD;
- saveConfig.savename.generic.flags = QMF_NODEFAULTINIT|QMF_UPPERCASE;
- saveConfig.savename.generic.ownerdraw = UI_SaveConfigMenu_SavenameDraw;
- saveConfig.savename.field.widthInChars = 20;
- saveConfig.savename.field.maxchars = 20;
- saveConfig.savename.generic.x = 240;
- saveConfig.savename.generic.y = 155+72;
- saveConfig.savename.generic.left = 240;
- saveConfig.savename.generic.top = 155+72;
- saveConfig.savename.generic.right = 233 + 20*SMALLCHAR_WIDTH;
- saveConfig.savename.generic.bottom = 155+72 + SMALLCHAR_HEIGHT+2;
-
- saveConfig.back.generic.type = MTYPE_BITMAP;
- saveConfig.back.generic.name = ART_BACK0;
- saveConfig.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- saveConfig.back.generic.id = ID_BACK;
- saveConfig.back.generic.callback = UI_SaveConfigMenu_BackEvent;
- saveConfig.back.generic.x = 0;
- saveConfig.back.generic.y = 480-64;
- saveConfig.back.width = 128;
- saveConfig.back.height = 64;
- saveConfig.back.focuspic = ART_BACK1;
-
- saveConfig.save.generic.type = MTYPE_BITMAP;
- saveConfig.save.generic.name = ART_SAVE0;
- saveConfig.save.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- saveConfig.save.generic.id = ID_SAVE;
- saveConfig.save.generic.callback = UI_SaveConfigMenu_SaveEvent;
- saveConfig.save.generic.x = 640;
- saveConfig.save.generic.y = 480-64;
- saveConfig.save.width = 128;
- saveConfig.save.height = 64;
- saveConfig.save.focuspic = ART_SAVE1;
-
- Menu_AddItem( &saveConfig.menu, &saveConfig.banner );
- Menu_AddItem( &saveConfig.menu, &saveConfig.background );
- Menu_AddItem( &saveConfig.menu, &saveConfig.savename );
- Menu_AddItem( &saveConfig.menu, &saveConfig.back );
- Menu_AddItem( &saveConfig.menu, &saveConfig.save );
-}
-
-
-/*
-=================
-UI_SaveConfigMenu_Cache
-=================
-*/
-void UI_SaveConfigMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_SAVE0 );
- trap_R_RegisterShaderNoMip( ART_SAVE1 );
- trap_R_RegisterShaderNoMip( ART_BACKGROUND );
-}
-
-
-/*
-===============
-UI_SaveConfigMenu
-===============
-*/
-void UI_SaveConfigMenu( void ) {
- UI_SaveConfigMenu_Init();
- UI_PushMenu( &saveConfig.menu );
-}
diff --git a/engine/code/q3_ui/ui_serverinfo.c b/engine/code/q3_ui/ui_serverinfo.c
deleted file mode 100644
index 8cde1cc..0000000
--- a/engine/code/q3_ui/ui_serverinfo.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-#define SERVERINFO_FRAMEL "menu/art/frame2_l"
-#define SERVERINFO_FRAMER "menu/art/frame1_r"
-#define SERVERINFO_BACK0 "menu/art/back_0"
-#define SERVERINFO_BACK1 "menu/art/back_1"
-
-static char* serverinfo_artlist[] =
-{
- SERVERINFO_FRAMEL,
- SERVERINFO_FRAMER,
- SERVERINFO_BACK0,
- SERVERINFO_BACK1,
- NULL
-};
-
-#define ID_ADD 100
-#define ID_BACK 101
-
-typedef struct
-{
- menuframework_s menu;
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
- menubitmap_s back;
- menutext_s add;
- char info[MAX_INFO_STRING];
- int numlines;
-} serverinfo_t;
-
-static serverinfo_t s_serverinfo;
-
-
-/*
-=================
-Favorites_Add
-
-Add current server to favorites
-=================
-*/
-void Favorites_Add( void )
-{
- char adrstr[128];
- char serverbuff[128];
- int i;
- int best;
-
- trap_Cvar_VariableStringBuffer( "cl_currentServerAddress", serverbuff, sizeof(serverbuff) );
- if (!serverbuff[0])
- return;
-
- best = 0;
- for (i=0; i<MAX_FAVORITESERVERS; i++)
- {
- trap_Cvar_VariableStringBuffer( va("server%d",i+1), adrstr, sizeof(adrstr) );
- if (!Q_stricmp(serverbuff,adrstr))
- {
- // already in list
- return;
- }
-
- // use first empty or non-numeric available slot
- if ((adrstr[0] < '0' || adrstr[0] > '9' ) && !best)
- best = i+1;
- }
-
- if (best)
- trap_Cvar_Set( va("server%d",best), serverbuff);
-}
-
-
-/*
-=================
-ServerInfo_Event
-=================
-*/
-static void ServerInfo_Event( void* ptr, int event )
-{
- switch (((menucommon_s*)ptr)->id)
- {
- case ID_ADD:
- if (event != QM_ACTIVATED)
- break;
-
- Favorites_Add();
- UI_PopMenu();
- break;
-
- case ID_BACK:
- if (event != QM_ACTIVATED)
- break;
-
- UI_PopMenu();
- break;
- }
-}
-
-/*
-=================
-ServerInfo_MenuDraw
-=================
-*/
-static void ServerInfo_MenuDraw( void )
-{
- const char *s;
- char key[MAX_INFO_KEY];
- char value[MAX_INFO_VALUE];
- int i = 0, y;
-
- y = SCREEN_HEIGHT/2 - s_serverinfo.numlines*(SMALLCHAR_HEIGHT)/2 - 20;
- s = s_serverinfo.info;
- while ( s && i < s_serverinfo.numlines ) {
- Info_NextPair( &s, key, value );
- if ( !key[0] ) {
- break;
- }
-
- Q_strcat( key, MAX_INFO_KEY, ":" );
-
- UI_DrawString(SCREEN_WIDTH*0.50 - 8,y,key,UI_RIGHT|UI_SMALLFONT,color_red);
- UI_DrawString(SCREEN_WIDTH*0.50 + 8,y,value,UI_LEFT|UI_SMALLFONT,text_color_normal);
-
- y += SMALLCHAR_HEIGHT;
- i++;
- }
-
- Menu_Draw( &s_serverinfo.menu );
-}
-
-/*
-=================
-ServerInfo_MenuKey
-=================
-*/
-static sfxHandle_t ServerInfo_MenuKey( int key )
-{
- return ( Menu_DefaultKey( &s_serverinfo.menu, key ) );
-}
-
-/*
-=================
-ServerInfo_Cache
-=================
-*/
-void ServerInfo_Cache( void )
-{
- int i;
-
- // touch all our pics
- for (i=0; ;i++)
- {
- if (!serverinfo_artlist[i])
- break;
- trap_R_RegisterShaderNoMip(serverinfo_artlist[i]);
- }
-}
-
-/*
-=================
-UI_ServerInfoMenu
-=================
-*/
-void UI_ServerInfoMenu( void )
-{
- const char *s;
- char key[MAX_INFO_KEY];
- char value[MAX_INFO_VALUE];
-
- // zero set all our globals
- memset( &s_serverinfo, 0 ,sizeof(serverinfo_t) );
-
- ServerInfo_Cache();
-
- s_serverinfo.menu.draw = ServerInfo_MenuDraw;
- s_serverinfo.menu.key = ServerInfo_MenuKey;
- s_serverinfo.menu.wrapAround = qtrue;
- s_serverinfo.menu.fullscreen = qtrue;
-
- s_serverinfo.banner.generic.type = MTYPE_BTEXT;
- s_serverinfo.banner.generic.x = 320;
- s_serverinfo.banner.generic.y = 16;
- s_serverinfo.banner.string = "SERVER INFO";
- s_serverinfo.banner.color = color_white;
- s_serverinfo.banner.style = UI_CENTER;
-
- s_serverinfo.framel.generic.type = MTYPE_BITMAP;
- s_serverinfo.framel.generic.name = SERVERINFO_FRAMEL;
- s_serverinfo.framel.generic.flags = QMF_INACTIVE;
- s_serverinfo.framel.generic.x = 0;
- s_serverinfo.framel.generic.y = 78;
- s_serverinfo.framel.width = 256;
- s_serverinfo.framel.height = 329;
-
- s_serverinfo.framer.generic.type = MTYPE_BITMAP;
- s_serverinfo.framer.generic.name = SERVERINFO_FRAMER;
- s_serverinfo.framer.generic.flags = QMF_INACTIVE;
- s_serverinfo.framer.generic.x = 376;
- s_serverinfo.framer.generic.y = 76;
- s_serverinfo.framer.width = 256;
- s_serverinfo.framer.height = 334;
-
- s_serverinfo.add.generic.type = MTYPE_PTEXT;
- s_serverinfo.add.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_serverinfo.add.generic.callback = ServerInfo_Event;
- s_serverinfo.add.generic.id = ID_ADD;
- s_serverinfo.add.generic.x = 320;
- s_serverinfo.add.generic.y = 371;
- s_serverinfo.add.string = "ADD TO FAVORITES";
- s_serverinfo.add.style = UI_CENTER|UI_SMALLFONT;
- s_serverinfo.add.color = color_red;
- if( trap_Cvar_VariableValue( "sv_running" ) ) {
- s_serverinfo.add.generic.flags |= QMF_GRAYED;
- }
-
- s_serverinfo.back.generic.type = MTYPE_BITMAP;
- s_serverinfo.back.generic.name = SERVERINFO_BACK0;
- s_serverinfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_serverinfo.back.generic.callback = ServerInfo_Event;
- s_serverinfo.back.generic.id = ID_BACK;
- s_serverinfo.back.generic.x = 0;
- s_serverinfo.back.generic.y = 480-64;
- s_serverinfo.back.width = 128;
- s_serverinfo.back.height = 64;
- s_serverinfo.back.focuspic = SERVERINFO_BACK1;
-
- trap_GetConfigString( CS_SERVERINFO, s_serverinfo.info, MAX_INFO_STRING );
-
- s_serverinfo.numlines = 0;
- s = s_serverinfo.info;
- while ( s ) {
- Info_NextPair( &s, key, value );
- if ( !key[0] ) {
- break;
- }
- s_serverinfo.numlines++;
- }
-
- if (s_serverinfo.numlines > 16)
- s_serverinfo.numlines = 16;
-
- Menu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.banner );
- Menu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.framel );
- Menu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.framer );
- Menu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.add );
- Menu_AddItem( &s_serverinfo.menu, (void*) &s_serverinfo.back );
-
- UI_PushMenu( &s_serverinfo.menu );
-}
-
-
diff --git a/engine/code/q3_ui/ui_servers2.c b/engine/code/q3_ui/ui_servers2.c
deleted file mode 100644
index 6c7cf16..0000000
--- a/engine/code/q3_ui/ui_servers2.c
+++ /dev/null
@@ -1,1643 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-MULTIPLAYER MENU (SERVER BROWSER)
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define MAX_GLOBALSERVERS 128
-#define MAX_PINGREQUESTS 32
-#define MAX_ADDRESSLENGTH 64
-#define MAX_HOSTNAMELENGTH 22
-#define MAX_MAPNAMELENGTH 16
-#define MAX_LISTBOXITEMS 128
-#define MAX_LOCALSERVERS 128
-#define MAX_STATUSLENGTH 64
-#define MAX_LEAGUELENGTH 28
-#define MAX_LISTBOXWIDTH 68
-
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-#define ART_CREATE0 "menu/art/create_0"
-#define ART_CREATE1 "menu/art/create_1"
-#define ART_SPECIFY0 "menu/art/specify_0"
-#define ART_SPECIFY1 "menu/art/specify_1"
-#define ART_REFRESH0 "menu/art/refresh_0"
-#define ART_REFRESH1 "menu/art/refresh_1"
-#define ART_CONNECT0 "menu/art/fight_0"
-#define ART_CONNECT1 "menu/art/fight_1"
-#define ART_ARROWS0 "menu/art/arrows_vert_0"
-#define ART_ARROWS_UP "menu/art/arrows_vert_top"
-#define ART_ARROWS_DOWN "menu/art/arrows_vert_bot"
-#define ART_UNKNOWNMAP "menu/art/unknownmap"
-#define ART_REMOVE0 "menu/art/delete_0"
-#define ART_REMOVE1 "menu/art/delete_1"
-#define ART_PUNKBUSTER "menu/art/pblogo"
-
-#define ID_MASTER 10
-#define ID_GAMETYPE 11
-#define ID_SORTKEY 12
-#define ID_SHOW_FULL 13
-#define ID_SHOW_EMPTY 14
-#define ID_LIST 15
-#define ID_SCROLL_UP 16
-#define ID_SCROLL_DOWN 17
-#define ID_BACK 18
-#define ID_REFRESH 19
-#define ID_SPECIFY 20
-#define ID_CREATE 21
-#define ID_CONNECT 22
-#define ID_REMOVE 23
-#define ID_PUNKBUSTER 24
-
-#define GR_LOGO 30
-#define GR_LETTERS 31
-
-#define UIAS_LOCAL 0
-#define UIAS_GLOBAL1 1
-#define UIAS_GLOBAL2 2
-#define UIAS_GLOBAL3 3
-#define UIAS_GLOBAL4 4
-#define UIAS_GLOBAL5 5
-#define UIAS_FAVORITES 6
-
-#define SORT_HOST 0
-#define SORT_MAP 1
-#define SORT_CLIENTS 2
-#define SORT_GAME 3
-#define SORT_PING 4
-
-#define GAMES_ALL 0
-#define GAMES_FFA 1
-#define GAMES_TEAMPLAY 2
-#define GAMES_TOURNEY 3
-#define GAMES_CTF 4
-
-static const char *master_items[] = {
- "Local",
- "Internet1",
- "Internet2",
- "Internet3",
- "Internet4",
- "Internet5",
- "Favorites",
- NULL
-};
-
-static const char *servertype_items[] = {
- "All",
- "Free For All",
- "Team Deathmatch",
- "Tournament",
- "Capture the Flag",
- NULL
-};
-
-static const char *sortkey_items[] = {
- "Server Name",
- "Map Name",
- "Open Player Spots",
- "Game Type",
- "Ping Time",
- NULL
-};
-
-static char* gamenames[] = {
- "DM ", // deathmatch
- "1v1", // tournament
- "SP ", // single player
- "Team DM", // team deathmatch
- "CTF", // capture the flag
- "One Flag CTF", // one flag ctf
- "OverLoad", // Overload
- "Harvester", // Harvester
- "Rocket Arena 3", // Rocket Arena 3
- "Q3F", // Q3F
- "Urban Terror", // Urban Terror
- "OSP", // Orange Smoothie Productions
- "???", // unknown
- NULL
-};
-
-static char* netnames[] = {
- "???",
- "UDP",
- "UDP6",
- NULL
-};
-
-static char quake3worldMessage[] = "Visit www.quake3world.com - News, Community, Events, Files";
-
-const char* punkbuster_items[] = {
- "Disabled",
- "Enabled",
- NULL
-};
-
-const char* punkbuster_msg[] = {
- "PunkBuster will be",
- "disabled the next time",
- "Quake III Arena",
- "is started.",
- NULL
-};
-
-typedef struct {
- char adrstr[MAX_ADDRESSLENGTH];
- int start;
-} pinglist_t;
-
-typedef struct servernode_s {
- char adrstr[MAX_ADDRESSLENGTH];
- char hostname[MAX_HOSTNAMELENGTH+3];
- char mapname[MAX_MAPNAMELENGTH];
- int numclients;
- int maxclients;
- int pingtime;
- int gametype;
- char gamename[12];
- int nettype;
- int minPing;
- int maxPing;
- qboolean bPB;
-
-} servernode_t;
-
-typedef struct {
- char buff[MAX_LISTBOXWIDTH];
- servernode_t* servernode;
-} table_t;
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
-
- menulist_s master;
- menulist_s gametype;
- menulist_s sortkey;
- menuradiobutton_s showfull;
- menuradiobutton_s showempty;
-
- menulist_s list;
- menubitmap_s mappic;
- menubitmap_s arrows;
- menubitmap_s up;
- menubitmap_s down;
- menutext_s status;
- menutext_s statusbar;
-
- menubitmap_s remove;
- menubitmap_s back;
- menubitmap_s refresh;
- menubitmap_s specify;
- menubitmap_s create;
- menubitmap_s go;
-
- pinglist_t pinglist[MAX_PINGREQUESTS];
- table_t table[MAX_LISTBOXITEMS];
- char* items[MAX_LISTBOXITEMS];
- int numqueriedservers;
- int *numservers;
- servernode_t *serverlist;
- int currentping;
- qboolean refreshservers;
- int nextpingtime;
- int maxservers;
- int refreshtime;
- char favoriteaddresses[MAX_FAVORITESERVERS][MAX_ADDRESSLENGTH];
- int numfavoriteaddresses;
-
- menulist_s punkbuster;
- menubitmap_s pblogo;
-} arenaservers_t;
-
-static arenaservers_t g_arenaservers;
-
-
-static servernode_t g_globalserverlist[MAX_GLOBALSERVERS];
-static int g_numglobalservers;
-static servernode_t g_localserverlist[MAX_LOCALSERVERS];
-static int g_numlocalservers;
-static servernode_t g_favoriteserverlist[MAX_FAVORITESERVERS];
-static int g_numfavoriteservers;
-static int g_servertype;
-static int g_gametype;
-static int g_sortkey;
-static int g_emptyservers;
-static int g_fullservers;
-
-
-/*
-=================
-ArenaServers_MaxPing
-=================
-*/
-static int ArenaServers_MaxPing( void ) {
- int maxPing;
-
- maxPing = (int)trap_Cvar_VariableValue( "cl_maxPing" );
- if( maxPing < 100 ) {
- maxPing = 100;
- }
- return maxPing;
-}
-
-
-/*
-=================
-ArenaServers_Compare
-=================
-*/
-static int QDECL ArenaServers_Compare( const void *arg1, const void *arg2 ) {
- float f1;
- float f2;
- servernode_t* t1;
- servernode_t* t2;
-
- t1 = (servernode_t *)arg1;
- t2 = (servernode_t *)arg2;
-
- switch( g_sortkey ) {
- case SORT_HOST:
- return Q_stricmp( t1->hostname, t2->hostname );
-
- case SORT_MAP:
- return Q_stricmp( t1->mapname, t2->mapname );
-
- case SORT_CLIENTS:
- f1 = t1->maxclients - t1->numclients;
- if( f1 < 0 ) {
- f1 = 0;
- }
-
- f2 = t2->maxclients - t2->numclients;
- if( f2 < 0 ) {
- f2 = 0;
- }
-
- if( f1 < f2 ) {
- return 1;
- }
- if( f1 == f2 ) {
- return 0;
- }
- return -1;
-
- case SORT_GAME:
- if( t1->gametype < t2->gametype ) {
- return -1;
- }
- if( t1->gametype == t2->gametype ) {
- return 0;
- }
- return 1;
-
- case SORT_PING:
- if( t1->pingtime < t2->pingtime ) {
- return -1;
- }
- if( t1->pingtime > t2->pingtime ) {
- return 1;
- }
- return Q_stricmp( t1->hostname, t2->hostname );
- }
-
- return 0;
-}
-
-
-/*
-=================
-ArenaServers_Go
-=================
-*/
-static void ArenaServers_Go( void ) {
- servernode_t* servernode;
-
- servernode = g_arenaservers.table[g_arenaservers.list.curvalue].servernode;
- if( servernode ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", servernode->adrstr ) );
- }
-}
-
-
-/*
-=================
-ArenaServers_UpdatePicture
-=================
-*/
-static void ArenaServers_UpdatePicture( void ) {
- static char picname[64];
- servernode_t* servernodeptr;
-
- if( !g_arenaservers.list.numitems ) {
- g_arenaservers.mappic.generic.name = NULL;
- }
- else {
- servernodeptr = g_arenaservers.table[g_arenaservers.list.curvalue].servernode;
- Com_sprintf( picname, sizeof(picname), "levelshots/%s.tga", servernodeptr->mapname );
- g_arenaservers.mappic.generic.name = picname;
-
- }
-
- // force shader update during draw
- g_arenaservers.mappic.shader = 0;
-}
-
-
-/*
-=================
-ArenaServers_UpdateMenu
-=================
-*/
-static void ArenaServers_UpdateMenu( void ) {
- int i;
- int j;
- int count;
- char* buff;
- servernode_t* servernodeptr;
- table_t* tableptr;
- char *pingColor;
-
- if( g_arenaservers.numqueriedservers > 0 ) {
- // servers found
- if( g_arenaservers.refreshservers && ( g_arenaservers.currentping <= g_arenaservers.numqueriedservers ) ) {
- // show progress
- Com_sprintf( g_arenaservers.status.string, MAX_STATUSLENGTH, "%d of %d Arena Servers.", g_arenaservers.currentping, g_arenaservers.numqueriedservers);
- g_arenaservers.statusbar.string = "Press SPACE to stop";
- qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);
- }
- else {
- // all servers pinged - enable controls
- g_arenaservers.master.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.gametype.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.sortkey.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.showempty.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.showfull.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.list.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.refresh.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.go.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.punkbuster.generic.flags &= ~QMF_GRAYED;
-
- // update status bar
- if( g_servertype >= UIAS_GLOBAL1 && g_servertype <= UIAS_GLOBAL5 ) {
- g_arenaservers.statusbar.string = quake3worldMessage;
- }
- else {
- g_arenaservers.statusbar.string = "";
- }
-
- }
- }
- else {
- // no servers found
- if( g_arenaservers.refreshservers ) {
- strcpy( g_arenaservers.status.string,"Scanning For Servers." );
- g_arenaservers.statusbar.string = "Press SPACE to stop";
-
- // disable controls during refresh
- g_arenaservers.master.generic.flags |= QMF_GRAYED;
- g_arenaservers.gametype.generic.flags |= QMF_GRAYED;
- g_arenaservers.sortkey.generic.flags |= QMF_GRAYED;
- g_arenaservers.showempty.generic.flags |= QMF_GRAYED;
- g_arenaservers.showfull.generic.flags |= QMF_GRAYED;
- g_arenaservers.list.generic.flags |= QMF_GRAYED;
- g_arenaservers.refresh.generic.flags |= QMF_GRAYED;
- g_arenaservers.go.generic.flags |= QMF_GRAYED;
- g_arenaservers.punkbuster.generic.flags |= QMF_GRAYED;
- }
- else {
- if( g_arenaservers.numqueriedservers < 0 ) {
- strcpy(g_arenaservers.status.string,"No Response From Master Server." );
- }
- else {
- strcpy(g_arenaservers.status.string,"No Servers Found." );
- }
-
- // update status bar
- if( g_servertype >= UIAS_GLOBAL1 && g_servertype <= UIAS_GLOBAL5 ) {
- g_arenaservers.statusbar.string = quake3worldMessage;
- }
- else {
- g_arenaservers.statusbar.string = "";
- }
-
- // end of refresh - set control state
- g_arenaservers.master.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.gametype.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.sortkey.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.showempty.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.showfull.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.list.generic.flags |= QMF_GRAYED;
- g_arenaservers.refresh.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.go.generic.flags |= QMF_GRAYED;
- g_arenaservers.punkbuster.generic.flags &= ~QMF_GRAYED;
- }
-
- // zero out list box
- g_arenaservers.list.numitems = 0;
- g_arenaservers.list.curvalue = 0;
- g_arenaservers.list.top = 0;
-
- // update picture
- ArenaServers_UpdatePicture();
- return;
- }
-
- // build list box strings - apply culling filters
- servernodeptr = g_arenaservers.serverlist;
- count = *g_arenaservers.numservers;
- for( i = 0, j = 0; i < count; i++, servernodeptr++ ) {
- tableptr = &g_arenaservers.table[j];
- tableptr->servernode = servernodeptr;
- buff = tableptr->buff;
-
- // can only cull valid results
- if( !g_emptyservers && !servernodeptr->numclients ) {
- continue;
- }
-
- if( !g_fullservers && ( servernodeptr->numclients == servernodeptr->maxclients ) ) {
- continue;
- }
-
- switch( g_gametype ) {
- case GAMES_ALL:
- break;
-
- case GAMES_FFA:
- if( servernodeptr->gametype != GT_FFA ) {
- continue;
- }
- break;
-
- case GAMES_TEAMPLAY:
- if( servernodeptr->gametype != GT_TEAM ) {
- continue;
- }
- break;
-
- case GAMES_TOURNEY:
- if( servernodeptr->gametype != GT_TOURNAMENT ) {
- continue;
- }
- break;
-
- case GAMES_CTF:
- if( servernodeptr->gametype != GT_CTF ) {
- continue;
- }
- break;
- }
-
- if( servernodeptr->pingtime < servernodeptr->minPing ) {
- pingColor = S_COLOR_BLUE;
- }
- else if( servernodeptr->maxPing && servernodeptr->pingtime > servernodeptr->maxPing ) {
- pingColor = S_COLOR_BLUE;
- }
- else if( servernodeptr->pingtime < 200 ) {
- pingColor = S_COLOR_GREEN;
- }
- else if( servernodeptr->pingtime < 400 ) {
- pingColor = S_COLOR_YELLOW;
- }
- else {
- pingColor = S_COLOR_RED;
- }
-
- Com_sprintf( buff, MAX_LISTBOXWIDTH, "%-20.20s %-12.12s %2d/%2d %-8.8s %3s %s%3d " S_COLOR_YELLOW "%s",
- servernodeptr->hostname, servernodeptr->mapname, servernodeptr->numclients,
- servernodeptr->maxclients, servernodeptr->gamename,
- netnames[servernodeptr->nettype], pingColor, servernodeptr->pingtime, servernodeptr->bPB ? "Yes" : "No" );
- j++;
- }
-
- g_arenaservers.list.numitems = j;
- g_arenaservers.list.curvalue = 0;
- g_arenaservers.list.top = 0;
-
- // update picture
- ArenaServers_UpdatePicture();
-}
-
-
-/*
-=================
-ArenaServers_Remove
-=================
-*/
-static void ArenaServers_Remove( void )
-{
- int i;
- servernode_t* servernodeptr;
- table_t* tableptr;
-
- if (!g_arenaservers.list.numitems)
- return;
-
- // remove selected item from display list
- // items are in scattered order due to sort and cull
- // perform delete on list box contents, resync all lists
-
- tableptr = &g_arenaservers.table[g_arenaservers.list.curvalue];
- servernodeptr = tableptr->servernode;
-
- // find address in master list
- for (i=0; i<g_arenaservers.numfavoriteaddresses; i++)
- {
- if (!Q_stricmp(g_arenaservers.favoriteaddresses[i],servernodeptr->adrstr))
- {
- // delete address from master list
- if (i < g_arenaservers.numfavoriteaddresses-1)
- {
- // shift items up
- memcpy( &g_arenaservers.favoriteaddresses[i], &g_arenaservers.favoriteaddresses[i+1], (g_arenaservers.numfavoriteaddresses - i - 1)* MAX_ADDRESSLENGTH );
- }
- g_arenaservers.numfavoriteaddresses--;
- memset( &g_arenaservers.favoriteaddresses[g_arenaservers.numfavoriteaddresses], 0, MAX_ADDRESSLENGTH );
- break;
- }
- }
-
- // find address in server list
- for (i=0; i<g_numfavoriteservers; i++)
- {
- if (&g_favoriteserverlist[i] == servernodeptr)
- {
-
- // delete address from server list
- if (i < g_numfavoriteservers-1)
- {
- // shift items up
- memcpy( &g_favoriteserverlist[i], &g_favoriteserverlist[i+1], (g_numfavoriteservers - i - 1)*sizeof(servernode_t));
- }
- g_numfavoriteservers--;
- memset( &g_favoriteserverlist[ g_numfavoriteservers ], 0, sizeof(servernode_t));
- break;
- }
- }
-
- g_arenaservers.numqueriedservers = g_arenaservers.numfavoriteaddresses;
- g_arenaservers.currentping = g_arenaservers.numfavoriteaddresses;
-}
-
-
-/*
-=================
-ArenaServers_Insert
-=================
-*/
-static void ArenaServers_Insert( char* adrstr, char* info, int pingtime )
-{
- servernode_t* servernodeptr;
- char* s;
- int i;
-
-
- if ((pingtime >= ArenaServers_MaxPing()) && (g_servertype != UIAS_FAVORITES))
- {
- // slow global or local servers do not get entered
- return;
- }
-
- if (*g_arenaservers.numservers >= g_arenaservers.maxservers) {
- // list full;
- servernodeptr = g_arenaservers.serverlist+(*g_arenaservers.numservers)-1;
- } else {
- // next slot
- servernodeptr = g_arenaservers.serverlist+(*g_arenaservers.numservers);
- (*g_arenaservers.numservers)++;
- }
-
- Q_strncpyz( servernodeptr->adrstr, adrstr, MAX_ADDRESSLENGTH );
-
- Q_strncpyz( servernodeptr->hostname, Info_ValueForKey( info, "hostname"), MAX_HOSTNAMELENGTH );
- Q_CleanStr( servernodeptr->hostname );
- Q_strupr( servernodeptr->hostname );
-
- Q_strncpyz( servernodeptr->mapname, Info_ValueForKey( info, "mapname"), MAX_MAPNAMELENGTH );
- Q_CleanStr( servernodeptr->mapname );
- Q_strupr( servernodeptr->mapname );
-
- servernodeptr->numclients = atoi( Info_ValueForKey( info, "clients") );
- servernodeptr->maxclients = atoi( Info_ValueForKey( info, "sv_maxclients") );
- servernodeptr->pingtime = pingtime;
- servernodeptr->minPing = atoi( Info_ValueForKey( info, "minPing") );
- servernodeptr->maxPing = atoi( Info_ValueForKey( info, "maxPing") );
- servernodeptr->bPB = atoi( Info_ValueForKey( info, "punkbuster") );
-
- /*
- s = Info_ValueForKey( info, "nettype" );
- for (i=0; ;i++)
- {
- if (!netnames[i])
- {
- servernodeptr->nettype = 0;
- break;
- }
- else if (!Q_stricmp( netnames[i], s ))
- {
- servernodeptr->nettype = i;
- break;
- }
- }
- */
- servernodeptr->nettype = atoi(Info_ValueForKey(info, "nettype"));
-
- s = Info_ValueForKey( info, "game");
- i = atoi( Info_ValueForKey( info, "gametype") );
- if( i < 0 ) {
- i = 0;
- }
- else if( i > 11 ) {
- i = 12;
- }
- if( *s ) {
- servernodeptr->gametype = i;//-1;
- Q_strncpyz( servernodeptr->gamename, s, sizeof(servernodeptr->gamename) );
- }
- else {
- servernodeptr->gametype = i;
- Q_strncpyz( servernodeptr->gamename, gamenames[i], sizeof(servernodeptr->gamename) );
- }
-}
-
-
-/*
-=================
-ArenaServers_InsertFavorites
-
-Insert nonresponsive address book entries into display lists.
-=================
-*/
-void ArenaServers_InsertFavorites( void )
-{
- int i;
- int j;
- char info[MAX_INFO_STRING];
-
- // resync existing results with new or deleted cvars
- info[0] = '\0';
- Info_SetValueForKey( info, "hostname", "No Response" );
- for (i=0; i<g_arenaservers.numfavoriteaddresses; i++)
- {
- // find favorite address in refresh list
- for (j=0; j<g_numfavoriteservers; j++)
- if (!Q_stricmp(g_arenaservers.favoriteaddresses[i],g_favoriteserverlist[j].adrstr))
- break;
-
- if ( j >= g_numfavoriteservers)
- {
- // not in list, add it
- ArenaServers_Insert( g_arenaservers.favoriteaddresses[i], info, ArenaServers_MaxPing() );
- }
- }
-}
-
-
-/*
-=================
-ArenaServers_LoadFavorites
-
-Load cvar address book entries into local lists.
-=================
-*/
-void ArenaServers_LoadFavorites( void )
-{
- int i;
- int j;
- int numtempitems;
- char emptyinfo[MAX_INFO_STRING];
- char adrstr[MAX_ADDRESSLENGTH];
- servernode_t templist[MAX_FAVORITESERVERS];
- qboolean found;
-
- found = qfalse;
- emptyinfo[0] = '\0';
-
- // copy the old
- memcpy( templist, g_favoriteserverlist, sizeof(servernode_t)*MAX_FAVORITESERVERS );
- numtempitems = g_numfavoriteservers;
-
- // clear the current for sync
- memset( g_favoriteserverlist, 0, sizeof(servernode_t)*MAX_FAVORITESERVERS );
- g_numfavoriteservers = 0;
-
- // resync existing results with new or deleted cvars
- for (i=0; i<MAX_FAVORITESERVERS; i++)
- {
- trap_Cvar_VariableStringBuffer( va("server%d",i+1), adrstr, MAX_ADDRESSLENGTH );
- if (!adrstr[0])
- continue;
-
- // quick sanity check to avoid slow domain name resolving
- // first character must be numeric
- if (adrstr[0] < '0' || adrstr[0] > '9')
- continue;
-
- // favorite server addresses must be maintained outside refresh list
- // this mimics local and global netadr's stored in client
- // these can be fetched to fill ping list
- strcpy( g_arenaservers.favoriteaddresses[g_numfavoriteservers], adrstr );
-
- // find this server in the old list
- for (j=0; j<numtempitems; j++)
- if (!Q_stricmp( templist[j].adrstr, adrstr ))
- break;
-
- if (j < numtempitems)
- {
- // found server - add exisiting results
- memcpy( &g_favoriteserverlist[g_numfavoriteservers], &templist[j], sizeof(servernode_t) );
- found = qtrue;
- }
- else
- {
- // add new server
- Q_strncpyz( g_favoriteserverlist[g_numfavoriteservers].adrstr, adrstr, MAX_ADDRESSLENGTH );
- g_favoriteserverlist[g_numfavoriteservers].pingtime = ArenaServers_MaxPing();
- }
-
- g_numfavoriteservers++;
- }
-
- g_arenaservers.numfavoriteaddresses = g_numfavoriteservers;
-
- if (!found)
- {
- // no results were found, reset server list
- // list will be automatically refreshed when selected
- g_numfavoriteservers = 0;
- }
-}
-
-
-/*
-=================
-ArenaServers_StopRefresh
-=================
-*/
-static void ArenaServers_StopRefresh( void )
-{
- if (!g_arenaservers.refreshservers)
- // not currently refreshing
- return;
-
- g_arenaservers.refreshservers = qfalse;
-
- if (g_servertype == UIAS_FAVORITES)
- {
- // nonresponsive favorites must be shown
- ArenaServers_InsertFavorites();
- }
-
- // final tally
- if (g_arenaservers.numqueriedservers >= 0)
- {
- g_arenaservers.currentping = *g_arenaservers.numservers;
- g_arenaservers.numqueriedservers = *g_arenaservers.numservers;
- }
-
- // sort
- qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);
-
- ArenaServers_UpdateMenu();
-}
-
-
-/*
-=================
-ArenaServers_DoRefresh
-=================
-*/
-static void ArenaServers_DoRefresh( void )
-{
- int i;
- int j;
- int time;
- int maxPing;
- char adrstr[MAX_ADDRESSLENGTH];
- char info[MAX_INFO_STRING];
-
- if (uis.realtime < g_arenaservers.refreshtime)
- {
- if (g_servertype != UIAS_FAVORITES) {
- if (g_servertype == UIAS_LOCAL) {
- if (!trap_LAN_GetServerCount(g_servertype)) {
- return;
- }
- }
- if (trap_LAN_GetServerCount(g_servertype) < 0) {
- // still waiting for response
- return;
- }
- }
- }
-
- if (uis.realtime < g_arenaservers.nextpingtime)
- {
- // wait for time trigger
- return;
- }
-
- // trigger at 10Hz intervals
- g_arenaservers.nextpingtime = uis.realtime + 10;
-
- // process ping results
- maxPing = ArenaServers_MaxPing();
- for (i=0; i<MAX_PINGREQUESTS; i++)
- {
- trap_LAN_GetPing( i, adrstr, MAX_ADDRESSLENGTH, &time );
- if (!adrstr[0])
- {
- // ignore empty or pending pings
- continue;
- }
-
- // find ping result in our local list
- for (j=0; j<MAX_PINGREQUESTS; j++)
- if (!Q_stricmp( adrstr, g_arenaservers.pinglist[j].adrstr ))
- break;
-
- if (j < MAX_PINGREQUESTS)
- {
- // found it
- if (!time)
- {
- time = uis.realtime - g_arenaservers.pinglist[j].start;
- if (time < maxPing)
- {
- // still waiting
- continue;
- }
- }
-
- if (time > maxPing)
- {
- // stale it out
- info[0] = '\0';
- time = maxPing;
- }
- else
- {
- trap_LAN_GetPingInfo( i, info, MAX_INFO_STRING );
- }
-
- // insert ping results
- ArenaServers_Insert( adrstr, info, time );
-
- // clear this query from internal list
- g_arenaservers.pinglist[j].adrstr[0] = '\0';
- }
-
- // clear this query from external list
- trap_LAN_ClearPing( i );
- }
-
- // get results of servers query
- // counts can increase as servers respond
- if (g_servertype == UIAS_FAVORITES) {
- g_arenaservers.numqueriedservers = g_arenaservers.numfavoriteaddresses;
- } else {
- g_arenaservers.numqueriedservers = trap_LAN_GetServerCount(g_servertype);
- }
-
-// if (g_arenaservers.numqueriedservers > g_arenaservers.maxservers)
-// g_arenaservers.numqueriedservers = g_arenaservers.maxservers;
-
- // send ping requests in reasonable bursts
- // iterate ping through all found servers
- for (i=0; i<MAX_PINGREQUESTS && g_arenaservers.currentping < g_arenaservers.numqueriedservers; i++)
- {
- if (trap_LAN_GetPingQueueCount() >= MAX_PINGREQUESTS)
- {
- // ping queue is full
- break;
- }
-
- // find empty slot
- for (j=0; j<MAX_PINGREQUESTS; j++)
- if (!g_arenaservers.pinglist[j].adrstr[0])
- break;
-
- if (j >= MAX_PINGREQUESTS)
- // no empty slots available yet - wait for timeout
- break;
-
- // get an address to ping
-
- if (g_servertype == UIAS_FAVORITES) {
- strcpy( adrstr, g_arenaservers.favoriteaddresses[g_arenaservers.currentping] );
- } else {
- trap_LAN_GetServerAddressString(g_servertype, g_arenaservers.currentping, adrstr, MAX_ADDRESSLENGTH );
- }
-
- strcpy( g_arenaservers.pinglist[j].adrstr, adrstr );
- g_arenaservers.pinglist[j].start = uis.realtime;
-
- trap_Cmd_ExecuteText( EXEC_NOW, va( "ping %s\n", adrstr ) );
-
- // advance to next server
- g_arenaservers.currentping++;
- }
-
- if (!trap_LAN_GetPingQueueCount())
- {
- // all pings completed
- ArenaServers_StopRefresh();
- return;
- }
-
- // update the user interface with ping status
- ArenaServers_UpdateMenu();
-}
-
-
-/*
-=================
-ArenaServers_StartRefresh
-=================
-*/
-static void ArenaServers_StartRefresh( void )
-{
- int i;
- char myargs[32], protocol[32];
-
- memset( g_arenaservers.serverlist, 0, g_arenaservers.maxservers*sizeof(table_t) );
-
- for (i=0; i<MAX_PINGREQUESTS; i++)
- {
- g_arenaservers.pinglist[i].adrstr[0] = '\0';
- trap_LAN_ClearPing( i );
- }
-
- g_arenaservers.refreshservers = qtrue;
- g_arenaservers.currentping = 0;
- g_arenaservers.nextpingtime = 0;
- *g_arenaservers.numservers = 0;
- g_arenaservers.numqueriedservers = 0;
-
- // allow max 5 seconds for responses
- g_arenaservers.refreshtime = uis.realtime + 5000;
-
- // place menu in zeroed state
- ArenaServers_UpdateMenu();
-
- if( g_servertype == UIAS_LOCAL ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "localservers\n" );
- return;
- }
-
- if( g_servertype >= UIAS_GLOBAL1 && g_servertype <= UIAS_GLOBAL5 ) {
- switch( g_arenaservers.gametype.curvalue ) {
- default:
- case GAMES_ALL:
- myargs[0] = 0;
- break;
-
- case GAMES_FFA:
- strcpy( myargs, " ffa" );
- break;
-
- case GAMES_TEAMPLAY:
- strcpy( myargs, " team" );
- break;
-
- case GAMES_TOURNEY:
- strcpy( myargs, " tourney" );
- break;
-
- case GAMES_CTF:
- strcpy( myargs, " ctf" );
- break;
- }
-
-
- if (g_emptyservers) {
- strcat(myargs, " empty");
- }
-
- if (g_fullservers) {
- strcat(myargs, " full");
- }
-
- protocol[0] = '\0';
- trap_Cvar_VariableStringBuffer( "debug_protocol", protocol, sizeof(protocol) );
- if (strlen(protocol)) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "globalservers %d %s%s\n", g_servertype - 1, protocol, myargs ));
- }
- else {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "globalservers %d %d%s\n", g_servertype - 1, (int)trap_Cvar_VariableValue( "protocol" ), myargs ) );
- }
- }
-}
-
-
-/*
-=================
-ArenaServers_SaveChanges
-=================
-*/
-void ArenaServers_SaveChanges( void )
-{
- int i;
-
- for (i=0; i<g_arenaservers.numfavoriteaddresses; i++)
- trap_Cvar_Set( va("server%d",i+1), g_arenaservers.favoriteaddresses[i] );
-
- for (; i<MAX_FAVORITESERVERS; i++)
- trap_Cvar_Set( va("server%d",i+1), "" );
-}
-
-
-/*
-=================
-ArenaServers_Sort
-=================
-*/
-void ArenaServers_Sort( int type ) {
- if( g_sortkey == type ) {
- return;
- }
-
- g_sortkey = type;
- qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);
-}
-
-
-/*
-=================
-ArenaServers_SetType
-=================
-*/
-int ArenaServers_SetType( int type )
-{
- if(type >= UIAS_GLOBAL1 && type <= UIAS_GLOBAL5)
- {
- char masterstr[2], cvarname[sizeof("sv_master1")];
-
- while(type <= UIAS_GLOBAL5)
- {
- Com_sprintf(cvarname, sizeof(cvarname), "sv_master%d", type);
- trap_Cvar_VariableStringBuffer(cvarname, masterstr, sizeof(masterstr));
- if(*masterstr)
- break;
-
- type++;
- }
- }
-
- g_servertype = type;
-
- switch( type ) {
- default:
- case UIAS_LOCAL:
- g_arenaservers.remove.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- g_arenaservers.serverlist = g_localserverlist;
- g_arenaservers.numservers = &g_numlocalservers;
- g_arenaservers.maxservers = MAX_LOCALSERVERS;
- break;
-
- case UIAS_GLOBAL1:
- case UIAS_GLOBAL2:
- case UIAS_GLOBAL3:
- case UIAS_GLOBAL4:
- case UIAS_GLOBAL5:
- g_arenaservers.remove.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- g_arenaservers.serverlist = g_globalserverlist;
- g_arenaservers.numservers = &g_numglobalservers;
- g_arenaservers.maxservers = MAX_GLOBALSERVERS;
- break;
-
- case UIAS_FAVORITES:
- g_arenaservers.remove.generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);
- g_arenaservers.serverlist = g_favoriteserverlist;
- g_arenaservers.numservers = &g_numfavoriteservers;
- g_arenaservers.maxservers = MAX_FAVORITESERVERS;
- break;
-
- }
-
- if( !*g_arenaservers.numservers ) {
- ArenaServers_StartRefresh();
- }
- else {
- // avoid slow operation, use existing results
- g_arenaservers.currentping = *g_arenaservers.numservers;
- g_arenaservers.numqueriedservers = *g_arenaservers.numservers;
- ArenaServers_UpdateMenu();
- }
- strcpy(g_arenaservers.status.string,"hit refresh to update");
-
- return type;
-}
-
-/*
-=================
-PunkBuster_Confirm
-=================
-*/
-static void Punkbuster_ConfirmEnable( qboolean result ) {
- if (result)
- {
- trap_SetPbClStatus(1);
- }
- g_arenaservers.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "cl_punkbuster" ) );
-}
-
-static void Punkbuster_ConfirmDisable( qboolean result ) {
- if (result)
- {
- trap_SetPbClStatus(0);
- UI_Message( punkbuster_msg );
- }
- g_arenaservers.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "cl_punkbuster" ) );
-}
-
-/*
-=================
-ArenaServers_Event
-=================
-*/
-static void ArenaServers_Event( void* ptr, int event ) {
- int id;
-
- id = ((menucommon_s*)ptr)->id;
-
- if( event != QM_ACTIVATED && id != ID_LIST ) {
- return;
- }
-
- switch( id ) {
- case ID_MASTER:
- g_arenaservers.master.curvalue = ArenaServers_SetType(g_arenaservers.master.curvalue);
- trap_Cvar_SetValue( "ui_browserMaster", g_arenaservers.master.curvalue);
- break;
-
- case ID_GAMETYPE:
- trap_Cvar_SetValue( "ui_browserGameType", g_arenaservers.gametype.curvalue );
- g_gametype = g_arenaservers.gametype.curvalue;
- ArenaServers_UpdateMenu();
- break;
-
- case ID_SORTKEY:
- trap_Cvar_SetValue( "ui_browserSortKey", g_arenaservers.sortkey.curvalue );
- ArenaServers_Sort( g_arenaservers.sortkey.curvalue );
- ArenaServers_UpdateMenu();
- break;
-
- case ID_SHOW_FULL:
- trap_Cvar_SetValue( "ui_browserShowFull", g_arenaservers.showfull.curvalue );
- g_fullservers = g_arenaservers.showfull.curvalue;
- ArenaServers_UpdateMenu();
- break;
-
- case ID_SHOW_EMPTY:
- trap_Cvar_SetValue( "ui_browserShowEmpty", g_arenaservers.showempty.curvalue );
- g_emptyservers = g_arenaservers.showempty.curvalue;
- ArenaServers_UpdateMenu();
- break;
-
- case ID_LIST:
- if( event == QM_GOTFOCUS ) {
- ArenaServers_UpdatePicture();
- }
- break;
-
- case ID_SCROLL_UP:
- ScrollList_Key( &g_arenaservers.list, K_UPARROW );
- break;
-
- case ID_SCROLL_DOWN:
- ScrollList_Key( &g_arenaservers.list, K_DOWNARROW );
- break;
-
- case ID_BACK:
- ArenaServers_StopRefresh();
- ArenaServers_SaveChanges();
- UI_PopMenu();
- break;
-
- case ID_REFRESH:
- ArenaServers_StartRefresh();
- break;
-
- case ID_SPECIFY:
- UI_SpecifyServerMenu();
- break;
-
- case ID_CREATE:
- UI_StartServerMenu( qtrue );
- break;
-
- case ID_CONNECT:
- ArenaServers_Go();
- break;
-
- case ID_REMOVE:
- ArenaServers_Remove();
- ArenaServers_UpdateMenu();
- break;
-
- case ID_PUNKBUSTER:
- if (g_arenaservers.punkbuster.curvalue)
- {
- UI_ConfirmMenu_Style( "Enable Punkbuster?", UI_CENTER|UI_INVERSE|UI_SMALLFONT, 0, Punkbuster_ConfirmEnable );
- }
- else
- {
- UI_ConfirmMenu_Style( "Disable Punkbuster?", UI_CENTER|UI_INVERSE|UI_SMALLFONT, 0, Punkbuster_ConfirmDisable );
- }
- break;
- }
-}
-
-
-/*
-=================
-ArenaServers_MenuDraw
-=================
-*/
-static void ArenaServers_MenuDraw( void )
-{
- if (g_arenaservers.refreshservers)
- ArenaServers_DoRefresh();
-
- Menu_Draw( &g_arenaservers.menu );
-}
-
-
-/*
-=================
-ArenaServers_MenuKey
-=================
-*/
-static sfxHandle_t ArenaServers_MenuKey( int key ) {
- if( key == K_SPACE && g_arenaservers.refreshservers ) {
- ArenaServers_StopRefresh();
- return menu_move_sound;
- }
-
- if( ( key == K_DEL || key == K_KP_DEL ) && ( g_servertype == UIAS_FAVORITES ) &&
- ( Menu_ItemAtCursor( &g_arenaservers.menu) == &g_arenaservers.list ) ) {
- ArenaServers_Remove();
- ArenaServers_UpdateMenu();
- return menu_move_sound;
- }
-
- if( key == K_MOUSE2 || key == K_ESCAPE ) {
- ArenaServers_StopRefresh();
- ArenaServers_SaveChanges();
- }
-
-
- return Menu_DefaultKey( &g_arenaservers.menu, key );
-}
-
-
-/*
-=================
-ArenaServers_MenuInit
-=================
-*/
-static void ArenaServers_MenuInit( void ) {
- int i;
- int y;
- int value;
- static char statusbuffer[MAX_STATUSLENGTH];
-
- // zero set all our globals
- memset( &g_arenaservers, 0 ,sizeof(arenaservers_t) );
-
- ArenaServers_Cache();
-
- g_arenaservers.menu.fullscreen = qtrue;
- g_arenaservers.menu.wrapAround = qtrue;
- g_arenaservers.menu.draw = ArenaServers_MenuDraw;
- g_arenaservers.menu.key = ArenaServers_MenuKey;
-
- g_arenaservers.banner.generic.type = MTYPE_BTEXT;
- g_arenaservers.banner.generic.flags = QMF_CENTER_JUSTIFY;
- g_arenaservers.banner.generic.x = 320;
- g_arenaservers.banner.generic.y = 16;
- g_arenaservers.banner.string = "ARENA SERVERS";
- g_arenaservers.banner.style = UI_CENTER;
- g_arenaservers.banner.color = color_white;
-
- y = 80;
- g_arenaservers.master.generic.type = MTYPE_SPINCONTROL;
- g_arenaservers.master.generic.name = "Servers:";
- g_arenaservers.master.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- g_arenaservers.master.generic.callback = ArenaServers_Event;
- g_arenaservers.master.generic.id = ID_MASTER;
- g_arenaservers.master.generic.x = 320;
- g_arenaservers.master.generic.y = y;
- g_arenaservers.master.itemnames = master_items;
-
- y += SMALLCHAR_HEIGHT;
- g_arenaservers.gametype.generic.type = MTYPE_SPINCONTROL;
- g_arenaservers.gametype.generic.name = "Game Type:";
- g_arenaservers.gametype.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- g_arenaservers.gametype.generic.callback = ArenaServers_Event;
- g_arenaservers.gametype.generic.id = ID_GAMETYPE;
- g_arenaservers.gametype.generic.x = 320;
- g_arenaservers.gametype.generic.y = y;
- g_arenaservers.gametype.itemnames = servertype_items;
-
- y += SMALLCHAR_HEIGHT;
- g_arenaservers.sortkey.generic.type = MTYPE_SPINCONTROL;
- g_arenaservers.sortkey.generic.name = "Sort By:";
- g_arenaservers.sortkey.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- g_arenaservers.sortkey.generic.callback = ArenaServers_Event;
- g_arenaservers.sortkey.generic.id = ID_SORTKEY;
- g_arenaservers.sortkey.generic.x = 320;
- g_arenaservers.sortkey.generic.y = y;
- g_arenaservers.sortkey.itemnames = sortkey_items;
-
- y += SMALLCHAR_HEIGHT;
- g_arenaservers.showfull.generic.type = MTYPE_RADIOBUTTON;
- g_arenaservers.showfull.generic.name = "Show Full:";
- g_arenaservers.showfull.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- g_arenaservers.showfull.generic.callback = ArenaServers_Event;
- g_arenaservers.showfull.generic.id = ID_SHOW_FULL;
- g_arenaservers.showfull.generic.x = 320;
- g_arenaservers.showfull.generic.y = y;
-
- y += SMALLCHAR_HEIGHT;
- g_arenaservers.showempty.generic.type = MTYPE_RADIOBUTTON;
- g_arenaservers.showempty.generic.name = "Show Empty:";
- g_arenaservers.showempty.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- g_arenaservers.showempty.generic.callback = ArenaServers_Event;
- g_arenaservers.showempty.generic.id = ID_SHOW_EMPTY;
- g_arenaservers.showempty.generic.x = 320;
- g_arenaservers.showempty.generic.y = y;
-
- y += 3 * SMALLCHAR_HEIGHT;
- g_arenaservers.list.generic.type = MTYPE_SCROLLLIST;
- g_arenaservers.list.generic.flags = QMF_HIGHLIGHT_IF_FOCUS;
- g_arenaservers.list.generic.id = ID_LIST;
- g_arenaservers.list.generic.callback = ArenaServers_Event;
- g_arenaservers.list.generic.x = 72;
- g_arenaservers.list.generic.y = y;
- g_arenaservers.list.width = MAX_LISTBOXWIDTH;
- g_arenaservers.list.height = 11;
- g_arenaservers.list.itemnames = (const char **)g_arenaservers.items;
- for( i = 0; i < MAX_LISTBOXITEMS; i++ ) {
- g_arenaservers.items[i] = g_arenaservers.table[i].buff;
- }
-
- g_arenaservers.mappic.generic.type = MTYPE_BITMAP;
- g_arenaservers.mappic.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- g_arenaservers.mappic.generic.x = 72;
- g_arenaservers.mappic.generic.y = 80;
- g_arenaservers.mappic.width = 128;
- g_arenaservers.mappic.height = 96;
- g_arenaservers.mappic.errorpic = ART_UNKNOWNMAP;
-
- g_arenaservers.arrows.generic.type = MTYPE_BITMAP;
- g_arenaservers.arrows.generic.name = ART_ARROWS0;
- g_arenaservers.arrows.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- g_arenaservers.arrows.generic.callback = ArenaServers_Event;
- g_arenaservers.arrows.generic.x = 512+48;
- g_arenaservers.arrows.generic.y = 240-64+16;
- g_arenaservers.arrows.width = 64;
- g_arenaservers.arrows.height = 128;
-
- g_arenaservers.up.generic.type = MTYPE_BITMAP;
- g_arenaservers.up.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
- g_arenaservers.up.generic.callback = ArenaServers_Event;
- g_arenaservers.up.generic.id = ID_SCROLL_UP;
- g_arenaservers.up.generic.x = 512+48;
- g_arenaservers.up.generic.y = 240-64+16;
- g_arenaservers.up.width = 64;
- g_arenaservers.up.height = 64;
- g_arenaservers.up.focuspic = ART_ARROWS_UP;
-
- g_arenaservers.down.generic.type = MTYPE_BITMAP;
- g_arenaservers.down.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
- g_arenaservers.down.generic.callback = ArenaServers_Event;
- g_arenaservers.down.generic.id = ID_SCROLL_DOWN;
- g_arenaservers.down.generic.x = 512+48;
- g_arenaservers.down.generic.y = 240+16;
- g_arenaservers.down.width = 64;
- g_arenaservers.down.height = 64;
- g_arenaservers.down.focuspic = ART_ARROWS_DOWN;
-
- y = 376;
- g_arenaservers.status.generic.type = MTYPE_TEXT;
- g_arenaservers.status.generic.x = 320;
- g_arenaservers.status.generic.y = y;
- g_arenaservers.status.string = statusbuffer;
- g_arenaservers.status.style = UI_CENTER|UI_SMALLFONT;
- g_arenaservers.status.color = menu_text_color;
-
- y += SMALLCHAR_HEIGHT;
- g_arenaservers.statusbar.generic.type = MTYPE_TEXT;
- g_arenaservers.statusbar.generic.x = 320;
- g_arenaservers.statusbar.generic.y = y;
- g_arenaservers.statusbar.string = "";
- g_arenaservers.statusbar.style = UI_CENTER|UI_SMALLFONT;
- g_arenaservers.statusbar.color = text_color_normal;
-
- g_arenaservers.remove.generic.type = MTYPE_BITMAP;
- g_arenaservers.remove.generic.name = ART_REMOVE0;
- g_arenaservers.remove.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- g_arenaservers.remove.generic.callback = ArenaServers_Event;
- g_arenaservers.remove.generic.id = ID_REMOVE;
- g_arenaservers.remove.generic.x = 450;
- g_arenaservers.remove.generic.y = 86;
- g_arenaservers.remove.width = 96;
- g_arenaservers.remove.height = 48;
- g_arenaservers.remove.focuspic = ART_REMOVE1;
-
- g_arenaservers.back.generic.type = MTYPE_BITMAP;
- g_arenaservers.back.generic.name = ART_BACK0;
- g_arenaservers.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- g_arenaservers.back.generic.callback = ArenaServers_Event;
- g_arenaservers.back.generic.id = ID_BACK;
- g_arenaservers.back.generic.x = 0;
- g_arenaservers.back.generic.y = 480-64;
- g_arenaservers.back.width = 128;
- g_arenaservers.back.height = 64;
- g_arenaservers.back.focuspic = ART_BACK1;
-
- g_arenaservers.specify.generic.type = MTYPE_BITMAP;
- g_arenaservers.specify.generic.name = ART_SPECIFY0;
- g_arenaservers.specify.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- g_arenaservers.specify.generic.callback = ArenaServers_Event;
- g_arenaservers.specify.generic.id = ID_SPECIFY;
- g_arenaservers.specify.generic.x = 128;
- g_arenaservers.specify.generic.y = 480-64;
- g_arenaservers.specify.width = 128;
- g_arenaservers.specify.height = 64;
- g_arenaservers.specify.focuspic = ART_SPECIFY1;
-
- g_arenaservers.refresh.generic.type = MTYPE_BITMAP;
- g_arenaservers.refresh.generic.name = ART_REFRESH0;
- g_arenaservers.refresh.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- g_arenaservers.refresh.generic.callback = ArenaServers_Event;
- g_arenaservers.refresh.generic.id = ID_REFRESH;
- g_arenaservers.refresh.generic.x = 256;
- g_arenaservers.refresh.generic.y = 480-64;
- g_arenaservers.refresh.width = 128;
- g_arenaservers.refresh.height = 64;
- g_arenaservers.refresh.focuspic = ART_REFRESH1;
-
- g_arenaservers.create.generic.type = MTYPE_BITMAP;
- g_arenaservers.create.generic.name = ART_CREATE0;
- g_arenaservers.create.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- g_arenaservers.create.generic.callback = ArenaServers_Event;
- g_arenaservers.create.generic.id = ID_CREATE;
- g_arenaservers.create.generic.x = 384;
- g_arenaservers.create.generic.y = 480-64;
- g_arenaservers.create.width = 128;
- g_arenaservers.create.height = 64;
- g_arenaservers.create.focuspic = ART_CREATE1;
-
- g_arenaservers.go.generic.type = MTYPE_BITMAP;
- g_arenaservers.go.generic.name = ART_CONNECT0;
- g_arenaservers.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- g_arenaservers.go.generic.callback = ArenaServers_Event;
- g_arenaservers.go.generic.id = ID_CONNECT;
- g_arenaservers.go.generic.x = 640;
- g_arenaservers.go.generic.y = 480-64;
- g_arenaservers.go.width = 128;
- g_arenaservers.go.height = 64;
- g_arenaservers.go.focuspic = ART_CONNECT1;
-
- g_arenaservers.punkbuster.generic.type = MTYPE_SPINCONTROL;
- g_arenaservers.punkbuster.generic.name = "Punkbuster:";
- g_arenaservers.punkbuster.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- g_arenaservers.punkbuster.generic.callback = ArenaServers_Event;
- g_arenaservers.punkbuster.generic.id = ID_PUNKBUSTER;
- g_arenaservers.punkbuster.generic.x = 480+32;
- g_arenaservers.punkbuster.generic.y = 144;
- g_arenaservers.punkbuster.itemnames = punkbuster_items;
-
- g_arenaservers.pblogo.generic.type = MTYPE_BITMAP;
- g_arenaservers.pblogo.generic.name = ART_PUNKBUSTER;
- g_arenaservers.pblogo.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- g_arenaservers.pblogo.generic.x = 526;
- g_arenaservers.pblogo.generic.y = 176;
- g_arenaservers.pblogo.width = 32;
- g_arenaservers.pblogo.height = 16;
- g_arenaservers.pblogo.errorpic = ART_UNKNOWNMAP;
-
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.banner );
-
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.master );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.gametype );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.sortkey );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.showfull);
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.showempty );
-
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.mappic );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.list );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.status );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.statusbar );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.arrows );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.up );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.down );
-
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.remove );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.back );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.specify );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.refresh );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.create );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.go );
-
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.punkbuster );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.pblogo );
-
- ArenaServers_LoadFavorites();
-
- g_servertype = Com_Clamp( 0, 3, ui_browserMaster.integer );
- // hack to get rid of MPlayer stuff
- value = g_servertype;
- if (value >= 1)
- value--;
- g_arenaservers.master.curvalue = value;
-
- g_gametype = Com_Clamp( 0, 4, ui_browserGameType.integer );
- g_arenaservers.gametype.curvalue = g_gametype;
-
- g_sortkey = Com_Clamp( 0, 4, ui_browserSortKey.integer );
- g_arenaservers.sortkey.curvalue = g_sortkey;
-
- g_fullservers = Com_Clamp( 0, 1, ui_browserShowFull.integer );
- g_arenaservers.showfull.curvalue = g_fullservers;
-
- g_emptyservers = Com_Clamp( 0, 1, ui_browserShowEmpty.integer );
- g_arenaservers.showempty.curvalue = g_emptyservers;
-
- g_arenaservers.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "cl_punkbuster" ) );
-
- // force to initial state and refresh
- g_arenaservers.master.curvalue = g_servertype = ArenaServers_SetType(g_servertype);
-
- trap_Cvar_Register(NULL, "debug_protocol", "", 0 );
-}
-
-
-/*
-=================
-ArenaServers_Cache
-=================
-*/
-void ArenaServers_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_CREATE0 );
- trap_R_RegisterShaderNoMip( ART_CREATE1 );
- trap_R_RegisterShaderNoMip( ART_SPECIFY0 );
- trap_R_RegisterShaderNoMip( ART_SPECIFY1 );
- trap_R_RegisterShaderNoMip( ART_REFRESH0 );
- trap_R_RegisterShaderNoMip( ART_REFRESH1 );
- trap_R_RegisterShaderNoMip( ART_CONNECT0 );
- trap_R_RegisterShaderNoMip( ART_CONNECT1 );
- trap_R_RegisterShaderNoMip( ART_ARROWS0 );
- trap_R_RegisterShaderNoMip( ART_ARROWS_UP );
- trap_R_RegisterShaderNoMip( ART_ARROWS_DOWN );
- trap_R_RegisterShaderNoMip( ART_UNKNOWNMAP );
- trap_R_RegisterShaderNoMip( ART_PUNKBUSTER );
-}
-
-
-/*
-=================
-UI_ArenaServersMenu
-=================
-*/
-void UI_ArenaServersMenu( void ) {
- ArenaServers_MenuInit();
- UI_PushMenu( &g_arenaservers.menu );
-}
diff --git a/engine/code/q3_ui/ui_setup.c b/engine/code/q3_ui/ui_setup.c
deleted file mode 100644
index 290d1ce..0000000
--- a/engine/code/q3_ui/ui_setup.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-SETUP MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define SETUP_MENU_VERTICAL_SPACING 34
-
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-#define ART_FRAMEL "menu/art/frame2_l"
-#define ART_FRAMER "menu/art/frame1_r"
-
-#define ID_CUSTOMIZEPLAYER 10
-#define ID_CUSTOMIZECONTROLS 11
-#define ID_SYSTEMCONFIG 12
-#define ID_GAME 13
-#define ID_CDKEY 14
-#define ID_LOAD 15
-#define ID_SAVE 16
-#define ID_DEFAULTS 17
-#define ID_BACK 18
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
- menutext_s setupplayer;
- menutext_s setupcontrols;
- menutext_s setupsystem;
- menutext_s game;
- menutext_s cdkey;
-// menutext_s load;
-// menutext_s save;
- menutext_s defaults;
- menubitmap_s back;
-} setupMenuInfo_t;
-
-static setupMenuInfo_t setupMenuInfo;
-
-
-/*
-=================
-Setup_ResetDefaults_Action
-=================
-*/
-static void Setup_ResetDefaults_Action( qboolean result ) {
- if( !result ) {
- return;
- }
- trap_Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n");
- trap_Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n");
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" );
-}
-
-
-/*
-=================
-Setup_ResetDefaults_Draw
-=================
-*/
-static void Setup_ResetDefaults_Draw( void ) {
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, "WARNING: This will reset *ALL*", UI_CENTER|UI_SMALLFONT, color_yellow );
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, "options to their default values.", UI_CENTER|UI_SMALLFONT, color_yellow );
-}
-
-
-/*
-===============
-UI_SetupMenu_Event
-===============
-*/
-static void UI_SetupMenu_Event( void *ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_CUSTOMIZEPLAYER:
- UI_PlayerSettingsMenu();
- break;
-
- case ID_CUSTOMIZECONTROLS:
- UI_ControlsMenu();
- break;
-
- case ID_SYSTEMCONFIG:
- UI_GraphicsOptionsMenu();
- break;
-
- case ID_GAME:
- UI_PreferencesMenu();
- break;
-
- case ID_CDKEY:
- UI_CDKeyMenu();
- break;
-
-// case ID_LOAD:
-// UI_LoadConfigMenu();
-// break;
-
-// case ID_SAVE:
-// UI_SaveConfigMenu();
-// break;
-
- case ID_DEFAULTS:
- UI_ConfirmMenu( "SET TO DEFAULTS?", Setup_ResetDefaults_Draw, Setup_ResetDefaults_Action );
- break;
-
- case ID_BACK:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-===============
-UI_SetupMenu_Init
-===============
-*/
-static void UI_SetupMenu_Init( void ) {
- int y;
-
- UI_SetupMenu_Cache();
-
- memset( &setupMenuInfo, 0, sizeof(setupMenuInfo) );
- setupMenuInfo.menu.wrapAround = qtrue;
- setupMenuInfo.menu.fullscreen = qtrue;
-
- setupMenuInfo.banner.generic.type = MTYPE_BTEXT;
- setupMenuInfo.banner.generic.x = 320;
- setupMenuInfo.banner.generic.y = 16;
- setupMenuInfo.banner.string = "SETUP";
- setupMenuInfo.banner.color = color_white;
- setupMenuInfo.banner.style = UI_CENTER;
-
- setupMenuInfo.framel.generic.type = MTYPE_BITMAP;
- setupMenuInfo.framel.generic.name = ART_FRAMEL;
- setupMenuInfo.framel.generic.flags = QMF_INACTIVE;
- setupMenuInfo.framel.generic.x = 0;
- setupMenuInfo.framel.generic.y = 78;
- setupMenuInfo.framel.width = 256;
- setupMenuInfo.framel.height = 329;
-
- setupMenuInfo.framer.generic.type = MTYPE_BITMAP;
- setupMenuInfo.framer.generic.name = ART_FRAMER;
- setupMenuInfo.framer.generic.flags = QMF_INACTIVE;
- setupMenuInfo.framer.generic.x = 376;
- setupMenuInfo.framer.generic.y = 76;
- setupMenuInfo.framer.width = 256;
- setupMenuInfo.framer.height = 334;
-
- y = 134;
- setupMenuInfo.setupplayer.generic.type = MTYPE_PTEXT;
- setupMenuInfo.setupplayer.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- setupMenuInfo.setupplayer.generic.x = 320;
- setupMenuInfo.setupplayer.generic.y = y;
- setupMenuInfo.setupplayer.generic.id = ID_CUSTOMIZEPLAYER;
- setupMenuInfo.setupplayer.generic.callback = UI_SetupMenu_Event;
- setupMenuInfo.setupplayer.string = "PLAYER";
- setupMenuInfo.setupplayer.color = color_red;
- setupMenuInfo.setupplayer.style = UI_CENTER;
-
- y += SETUP_MENU_VERTICAL_SPACING;
- setupMenuInfo.setupcontrols.generic.type = MTYPE_PTEXT;
- setupMenuInfo.setupcontrols.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- setupMenuInfo.setupcontrols.generic.x = 320;
- setupMenuInfo.setupcontrols.generic.y = y;
- setupMenuInfo.setupcontrols.generic.id = ID_CUSTOMIZECONTROLS;
- setupMenuInfo.setupcontrols.generic.callback = UI_SetupMenu_Event;
- setupMenuInfo.setupcontrols.string = "CONTROLS";
- setupMenuInfo.setupcontrols.color = color_red;
- setupMenuInfo.setupcontrols.style = UI_CENTER;
-
- y += SETUP_MENU_VERTICAL_SPACING;
- setupMenuInfo.setupsystem.generic.type = MTYPE_PTEXT;
- setupMenuInfo.setupsystem.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- setupMenuInfo.setupsystem.generic.x = 320;
- setupMenuInfo.setupsystem.generic.y = y;
- setupMenuInfo.setupsystem.generic.id = ID_SYSTEMCONFIG;
- setupMenuInfo.setupsystem.generic.callback = UI_SetupMenu_Event;
- setupMenuInfo.setupsystem.string = "SYSTEM";
- setupMenuInfo.setupsystem.color = color_red;
- setupMenuInfo.setupsystem.style = UI_CENTER;
-
- y += SETUP_MENU_VERTICAL_SPACING;
- setupMenuInfo.game.generic.type = MTYPE_PTEXT;
- setupMenuInfo.game.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- setupMenuInfo.game.generic.x = 320;
- setupMenuInfo.game.generic.y = y;
- setupMenuInfo.game.generic.id = ID_GAME;
- setupMenuInfo.game.generic.callback = UI_SetupMenu_Event;
- setupMenuInfo.game.string = "GAME OPTIONS";
- setupMenuInfo.game.color = color_red;
- setupMenuInfo.game.style = UI_CENTER;
-
- y += SETUP_MENU_VERTICAL_SPACING;
- setupMenuInfo.cdkey.generic.type = MTYPE_PTEXT;
- setupMenuInfo.cdkey.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- setupMenuInfo.cdkey.generic.x = 320;
- setupMenuInfo.cdkey.generic.y = y;
- setupMenuInfo.cdkey.generic.id = ID_CDKEY;
- setupMenuInfo.cdkey.generic.callback = UI_SetupMenu_Event;
- setupMenuInfo.cdkey.string = "CD Key";
- setupMenuInfo.cdkey.color = color_red;
- setupMenuInfo.cdkey.style = UI_CENTER;
-
- if( !trap_Cvar_VariableValue( "cl_paused" ) ) {
-#if 0
- y += SETUP_MENU_VERTICAL_SPACING;
- setupMenuInfo.load.generic.type = MTYPE_PTEXT;
- setupMenuInfo.load.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- setupMenuInfo.load.generic.x = 320;
- setupMenuInfo.load.generic.y = y;
- setupMenuInfo.load.generic.id = ID_LOAD;
- setupMenuInfo.load.generic.callback = UI_SetupMenu_Event;
- setupMenuInfo.load.string = "LOAD";
- setupMenuInfo.load.color = color_red;
- setupMenuInfo.load.style = UI_CENTER;
-
- y += SETUP_MENU_VERTICAL_SPACING;
- setupMenuInfo.save.generic.type = MTYPE_PTEXT;
- setupMenuInfo.save.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- setupMenuInfo.save.generic.x = 320;
- setupMenuInfo.save.generic.y = y;
- setupMenuInfo.save.generic.id = ID_SAVE;
- setupMenuInfo.save.generic.callback = UI_SetupMenu_Event;
- setupMenuInfo.save.string = "SAVE";
- setupMenuInfo.save.color = color_red;
- setupMenuInfo.save.style = UI_CENTER;
-#endif
-
- y += SETUP_MENU_VERTICAL_SPACING;
- setupMenuInfo.defaults.generic.type = MTYPE_PTEXT;
- setupMenuInfo.defaults.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- setupMenuInfo.defaults.generic.x = 320;
- setupMenuInfo.defaults.generic.y = y;
- setupMenuInfo.defaults.generic.id = ID_DEFAULTS;
- setupMenuInfo.defaults.generic.callback = UI_SetupMenu_Event;
- setupMenuInfo.defaults.string = "DEFAULTS";
- setupMenuInfo.defaults.color = color_red;
- setupMenuInfo.defaults.style = UI_CENTER;
- }
-
- setupMenuInfo.back.generic.type = MTYPE_BITMAP;
- setupMenuInfo.back.generic.name = ART_BACK0;
- setupMenuInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- setupMenuInfo.back.generic.id = ID_BACK;
- setupMenuInfo.back.generic.callback = UI_SetupMenu_Event;
- setupMenuInfo.back.generic.x = 0;
- setupMenuInfo.back.generic.y = 480-64;
- setupMenuInfo.back.width = 128;
- setupMenuInfo.back.height = 64;
- setupMenuInfo.back.focuspic = ART_BACK1;
-
- Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.banner );
- Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.framel );
- Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.framer );
- Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.setupplayer );
- Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.setupcontrols );
- Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.setupsystem );
- Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.game );
- Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.cdkey );
-// Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.load );
-// Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.save );
- if( !trap_Cvar_VariableValue( "cl_paused" ) ) {
- Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.defaults );
- }
- Menu_AddItem( &setupMenuInfo.menu, &setupMenuInfo.back );
-}
-
-
-/*
-=================
-UI_SetupMenu_Cache
-=================
-*/
-void UI_SetupMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
-}
-
-
-/*
-===============
-UI_SetupMenu
-===============
-*/
-void UI_SetupMenu( void ) {
- UI_SetupMenu_Init();
- UI_PushMenu( &setupMenuInfo.menu );
-}
diff --git a/engine/code/q3_ui/ui_signup.c b/engine/code/q3_ui/ui_signup.c
deleted file mode 100644
index bdb97ec..0000000
--- a/engine/code/q3_ui/ui_signup.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-//
-// ui_signup.c
-//
-
-#include "ui_local.h"
-
-
-#define SIGNUP_FRAME "menu/art/cut_frame"
-
-#define ID_NAME 100
-#define ID_NAME_BOX 101
-#define ID_PASSWORD 102
-#define ID_PASSWORD_BOX 103
-#define ID_AGAIN 104
-#define ID_AGAIN_BOX 105
-#define ID_EMAIL 106
-#define ID_EMAIL_BOX 107
-#define ID_SIGNUP 108
-#define ID_CANCEL 109
-
-
-typedef struct
-{
- menuframework_s menu;
- menubitmap_s frame;
- menutext_s name;
- menufield_s name_box;
- menutext_s password;
- menufield_s password_box;
- menutext_s again;
- menufield_s again_box;
- menutext_s email;
- menufield_s email_box;
- menutext_s signup;
- menutext_s cancel;
-} signup_t;
-
-static signup_t s_signup;
-
-static menuframework_s s_signup_menu;
-static menuaction_s s_signup_signup;
-static menuaction_s s_signup_cancel;
-
-static vec4_t s_signup_color_prompt = {1.00, 0.43, 0.00, 1.00};
-
-/*
-===============
-Signup_MenuEvent
-===============
-*/
-static void Signup_MenuEvent( void* ptr, int event ) {
- //char cmd[1024];
-
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_SIGNUP:
- if( strcmp(s_signup.password_box.field.buffer,
- s_signup.again_box.field.buffer) != 0 )
- {
- // GRANK_FIXME - password mismatch
- break;
- }
- // set name
- //trap_Cvar_Set( "name", s_signup.name_box.field.buffer );
- /*
- trap_Cvar_Set( "rank_name", s_signup.name_box.field.buffer );
- trap_Cvar_Set( "rank_pwd", s_signup.password_box.field.buffer );
- */
-
- // create account
- /*
- sprintf( cmd, "cmd rank_create \"%s\" \"%s\" \"%s\"\n",
- s_signup.name_box.field.buffer,
- s_signup.password_box.field.buffer,
- s_signup.email_box.field.buffer );
- trap_Cmd_ExecuteText( EXEC_APPEND, cmd );
- */
- trap_CL_UI_RankUserCreate(
- s_signup.name_box.field.buffer,
- s_signup.password_box.field.buffer,
- s_signup.email_box.field.buffer );
-
- UI_ForceMenuOff();
- break;
-
- case ID_CANCEL:
- UI_PopMenu();
- break;
- }
-}
-
-/*
-===============
-Signup_MenuInit
-===============
-*/
-void Signup_MenuInit( void ) {
- grank_status_t status;
- int y;
-
- memset( &s_signup, 0, sizeof(s_signup) );
-
- Signup_Cache();
-
- s_signup.menu.wrapAround = qtrue;
- s_signup.menu.fullscreen = qfalse;
-
- s_signup.frame.generic.type = MTYPE_BITMAP;
- s_signup.frame.generic.flags = QMF_INACTIVE;
- s_signup.frame.generic.name = SIGNUP_FRAME;
- s_signup.frame.generic.x = 142; //320-233;
- s_signup.frame.generic.y = 118; //240-166;
- s_signup.frame.width = 359; //466;
- s_signup.frame.height = 256; //332;
-
- y = 194;
-
- s_signup.name.generic.type = MTYPE_PTEXT;
- s_signup.name.generic.flags = QMF_RIGHT_JUSTIFY|QMF_INACTIVE;
- s_signup.name.generic.id = ID_NAME;
- s_signup.name.generic.x = 310;
- s_signup.name.generic.y = y;
- s_signup.name.string = "NAME";
- s_signup.name.style = UI_RIGHT|UI_SMALLFONT;
- s_signup.name.color = s_signup_color_prompt;
-
- s_signup.name_box.generic.type = MTYPE_FIELD;
- s_signup.name_box.generic.ownerdraw = Rankings_DrawName;
- s_signup.name_box.generic.name = "";
- s_signup.name_box.generic.flags = 0;
- s_signup.name_box.generic.x = 330;
- s_signup.name_box.generic.y = y;
- s_signup.name_box.field.widthInChars = 16;
- s_signup.name_box.field.maxchars = 16;
- y += 20;
-
- s_signup.password.generic.type = MTYPE_PTEXT;
- s_signup.password.generic.flags = QMF_RIGHT_JUSTIFY|QMF_INACTIVE;
- s_signup.password.generic.id = ID_PASSWORD;
- s_signup.password.generic.x = 310;
- s_signup.password.generic.y = y;
- s_signup.password.string = "PASSWORD";
- s_signup.password.style = UI_RIGHT|UI_SMALLFONT;
- s_signup.password.color = s_signup_color_prompt;
-
- s_signup.password_box.generic.type = MTYPE_FIELD;
- s_signup.password_box.generic.ownerdraw = Rankings_DrawPassword;
- s_signup.password_box.generic.name = "";
- s_signup.password_box.generic.flags = 0;
- s_signup.password_box.generic.x = 330;
- s_signup.password_box.generic.y = y;
- s_signup.password_box.field.widthInChars = 16;
- s_signup.password_box.field.maxchars = 16;
- y += 20;
-
- s_signup.again.generic.type = MTYPE_PTEXT;
- s_signup.again.generic.flags = QMF_RIGHT_JUSTIFY|QMF_INACTIVE;
- s_signup.again.generic.id = ID_AGAIN;
- s_signup.again.generic.x = 310;
- s_signup.again.generic.y = y;
- s_signup.again.string = "(AGAIN)";
- s_signup.again.style = UI_RIGHT|UI_SMALLFONT;
- s_signup.again.color = s_signup_color_prompt;
-
- s_signup.again_box.generic.type = MTYPE_FIELD;
- s_signup.again_box.generic.ownerdraw = Rankings_DrawPassword;
- s_signup.again_box.generic.name = "";
- s_signup.again_box.generic.flags = 0;
- s_signup.again_box.generic.x = 330;
- s_signup.again_box.generic.y = y;
- s_signup.again_box.field.widthInChars = 16;
- s_signup.again_box.field.maxchars = 16;
- y += 20;
-
- s_signup.email.generic.type = MTYPE_PTEXT;
- s_signup.email.generic.flags = QMF_RIGHT_JUSTIFY|QMF_INACTIVE;
- s_signup.email.generic.id = ID_EMAIL;
- s_signup.email.generic.x = 310;
- s_signup.email.generic.y = y;
- s_signup.email.string = "EMAIL";
- s_signup.email.style = UI_RIGHT|UI_SMALLFONT;
- s_signup.email.color = s_signup_color_prompt;
-
- s_signup.email_box.generic.type = MTYPE_FIELD;
- s_signup.email_box.generic.ownerdraw = Rankings_DrawText;
- s_signup.email_box.generic.name = "";
- s_signup.email_box.generic.flags = 0;
- s_signup.email_box.generic.x = 330;
- s_signup.email_box.generic.y = y;
- s_signup.email_box.field.widthInChars = 16;
- s_signup.email_box.field.maxchars = MAX_EDIT_LINE;
- y += 40;
-
- s_signup.signup.generic.type = MTYPE_PTEXT;
- s_signup.signup.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_signup.signup.generic.id = ID_SIGNUP;
- s_signup.signup.generic.callback = Signup_MenuEvent;
- s_signup.signup.generic.x = 310;
- s_signup.signup.generic.y = y;
- s_signup.signup.string = "SIGN UP";
- s_signup.signup.style = UI_RIGHT|UI_SMALLFONT;
- s_signup.signup.color = colorRed;
-
- s_signup.cancel.generic.type = MTYPE_PTEXT;
- s_signup.cancel.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_signup.cancel.generic.id = ID_CANCEL;
- s_signup.cancel.generic.callback = Signup_MenuEvent;
- s_signup.cancel.generic.x = 330;
- s_signup.cancel.generic.y = y;
- s_signup.cancel.string = "CANCEL";
- s_signup.cancel.style = UI_LEFT|UI_SMALLFONT;
- s_signup.cancel.color = colorRed;
- y += 20;
-
- status = (grank_status_t)trap_Cvar_VariableValue("client_status");
- if( (status != QGR_STATUS_NEW) && (status != QGR_STATUS_SPECTATOR) )
- {
- s_signup.name_box.generic.flags |= QMF_INACTIVE;
- s_signup.password_box.generic.flags |= QMF_INACTIVE;
- s_signup.again_box.generic.flags |= QMF_INACTIVE;
- s_signup.email_box.generic.flags |= QMF_INACTIVE;
- s_signup.signup.generic.flags |= QMF_INACTIVE;
-
- s_signup.signup.color = colorMdGrey;
- }
-
- Menu_AddItem( &s_signup.menu, (void*) &s_signup.frame );
- Menu_AddItem( &s_signup.menu, (void*) &s_signup.name );
- Menu_AddItem( &s_signup.menu, (void*) &s_signup.name_box );
- Menu_AddItem( &s_signup.menu, (void*) &s_signup.password );
- Menu_AddItem( &s_signup.menu, (void*) &s_signup.password_box );
- Menu_AddItem( &s_signup.menu, (void*) &s_signup.again );
- Menu_AddItem( &s_signup.menu, (void*) &s_signup.again_box );
- Menu_AddItem( &s_signup.menu, (void*) &s_signup.email );
- Menu_AddItem( &s_signup.menu, (void*) &s_signup.email_box );
- Menu_AddItem( &s_signup.menu, (void*) &s_signup.signup );
- Menu_AddItem( &s_signup.menu, (void*) &s_signup.cancel );
-}
-
-
-/*
-===============
-Signup_Cache
-===============
-*/
-void Signup_Cache( void ) {
- trap_R_RegisterShaderNoMip( SIGNUP_FRAME );
-}
-
-
-/*
-===============
-UI_SignupMenu
-===============
-*/
-void UI_SignupMenu( void ) {
- Signup_MenuInit();
- UI_PushMenu ( &s_signup.menu );
-}
-
-
diff --git a/engine/code/q3_ui/ui_sound.c b/engine/code/q3_ui/ui_sound.c
deleted file mode 100644
index fcc7f49..0000000
--- a/engine/code/q3_ui/ui_sound.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-SOUND OPTIONS MENU
-
-=======================================================================
-*/
-
-#include "ui_local.h"
-
-
-#define ART_FRAMEL "menu/art/frame2_l"
-#define ART_FRAMER "menu/art/frame1_r"
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-
-#define ID_GRAPHICS 10
-#define ID_DISPLAY 11
-#define ID_SOUND 12
-#define ID_NETWORK 13
-#define ID_EFFECTSVOLUME 14
-#define ID_MUSICVOLUME 15
-#define ID_QUALITY 16
-//#define ID_A3D 17
-#define ID_BACK 18
-
-
-static const char *quality_items[] = {
- "Low", "High", NULL
-};
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menutext_s graphics;
- menutext_s display;
- menutext_s sound;
- menutext_s network;
-
- menuslider_s sfxvolume;
- menuslider_s musicvolume;
- menulist_s quality;
-// menuradiobutton_s a3d;
-
- menubitmap_s back;
-} soundOptionsInfo_t;
-
-static soundOptionsInfo_t soundOptionsInfo;
-
-
-/*
-=================
-UI_SoundOptionsMenu_Event
-=================
-*/
-static void UI_SoundOptionsMenu_Event( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_GRAPHICS:
- UI_PopMenu();
- UI_GraphicsOptionsMenu();
- break;
-
- case ID_DISPLAY:
- UI_PopMenu();
- UI_DisplayOptionsMenu();
- break;
-
- case ID_SOUND:
- break;
-
- case ID_NETWORK:
- UI_PopMenu();
- UI_NetworkOptionsMenu();
- break;
-
- case ID_EFFECTSVOLUME:
- trap_Cvar_SetValue( "s_volume", soundOptionsInfo.sfxvolume.curvalue / 10 );
- break;
-
- case ID_MUSICVOLUME:
- trap_Cvar_SetValue( "s_musicvolume", soundOptionsInfo.musicvolume.curvalue / 10 );
- break;
-
- case ID_QUALITY:
- if( soundOptionsInfo.quality.curvalue ) {
- trap_Cvar_SetValue( "s_khz", 22 );
- trap_Cvar_SetValue( "s_compression", 0 );
- }
- else {
- trap_Cvar_SetValue( "s_khz", 11 );
- trap_Cvar_SetValue( "s_compression", 1 );
- }
- UI_ForceMenuOff();
- trap_Cmd_ExecuteText( EXEC_APPEND, "snd_restart\n" );
- break;
-/*
- case ID_A3D:
- if( soundOptionsInfo.a3d.curvalue ) {
- trap_Cmd_ExecuteText( EXEC_NOW, "s_enable_a3d\n" );
- }
- else {
- trap_Cmd_ExecuteText( EXEC_NOW, "s_disable_a3d\n" );
- }
- soundOptionsInfo.a3d.curvalue = (int)trap_Cvar_VariableValue( "s_usingA3D" );
- break;
-*/
- case ID_BACK:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-===============
-UI_SoundOptionsMenu_Init
-===============
-*/
-static void UI_SoundOptionsMenu_Init( void ) {
- int y;
-
- memset( &soundOptionsInfo, 0, sizeof(soundOptionsInfo) );
-
- UI_SoundOptionsMenu_Cache();
- soundOptionsInfo.menu.wrapAround = qtrue;
- soundOptionsInfo.menu.fullscreen = qtrue;
-
- soundOptionsInfo.banner.generic.type = MTYPE_BTEXT;
- soundOptionsInfo.banner.generic.flags = QMF_CENTER_JUSTIFY;
- soundOptionsInfo.banner.generic.x = 320;
- soundOptionsInfo.banner.generic.y = 16;
- soundOptionsInfo.banner.string = "SYSTEM SETUP";
- soundOptionsInfo.banner.color = color_white;
- soundOptionsInfo.banner.style = UI_CENTER;
-
- soundOptionsInfo.framel.generic.type = MTYPE_BITMAP;
- soundOptionsInfo.framel.generic.name = ART_FRAMEL;
- soundOptionsInfo.framel.generic.flags = QMF_INACTIVE;
- soundOptionsInfo.framel.generic.x = 0;
- soundOptionsInfo.framel.generic.y = 78;
- soundOptionsInfo.framel.width = 256;
- soundOptionsInfo.framel.height = 329;
-
- soundOptionsInfo.framer.generic.type = MTYPE_BITMAP;
- soundOptionsInfo.framer.generic.name = ART_FRAMER;
- soundOptionsInfo.framer.generic.flags = QMF_INACTIVE;
- soundOptionsInfo.framer.generic.x = 376;
- soundOptionsInfo.framer.generic.y = 76;
- soundOptionsInfo.framer.width = 256;
- soundOptionsInfo.framer.height = 334;
-
- soundOptionsInfo.graphics.generic.type = MTYPE_PTEXT;
- soundOptionsInfo.graphics.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- soundOptionsInfo.graphics.generic.id = ID_GRAPHICS;
- soundOptionsInfo.graphics.generic.callback = UI_SoundOptionsMenu_Event;
- soundOptionsInfo.graphics.generic.x = 216;
- soundOptionsInfo.graphics.generic.y = 240 - 2 * PROP_HEIGHT;
- soundOptionsInfo.graphics.string = "GRAPHICS";
- soundOptionsInfo.graphics.style = UI_RIGHT;
- soundOptionsInfo.graphics.color = color_red;
-
- soundOptionsInfo.display.generic.type = MTYPE_PTEXT;
- soundOptionsInfo.display.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- soundOptionsInfo.display.generic.id = ID_DISPLAY;
- soundOptionsInfo.display.generic.callback = UI_SoundOptionsMenu_Event;
- soundOptionsInfo.display.generic.x = 216;
- soundOptionsInfo.display.generic.y = 240 - PROP_HEIGHT;
- soundOptionsInfo.display.string = "DISPLAY";
- soundOptionsInfo.display.style = UI_RIGHT;
- soundOptionsInfo.display.color = color_red;
-
- soundOptionsInfo.sound.generic.type = MTYPE_PTEXT;
- soundOptionsInfo.sound.generic.flags = QMF_RIGHT_JUSTIFY;
- soundOptionsInfo.sound.generic.id = ID_SOUND;
- soundOptionsInfo.sound.generic.callback = UI_SoundOptionsMenu_Event;
- soundOptionsInfo.sound.generic.x = 216;
- soundOptionsInfo.sound.generic.y = 240;
- soundOptionsInfo.sound.string = "SOUND";
- soundOptionsInfo.sound.style = UI_RIGHT;
- soundOptionsInfo.sound.color = color_red;
-
- soundOptionsInfo.network.generic.type = MTYPE_PTEXT;
- soundOptionsInfo.network.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- soundOptionsInfo.network.generic.id = ID_NETWORK;
- soundOptionsInfo.network.generic.callback = UI_SoundOptionsMenu_Event;
- soundOptionsInfo.network.generic.x = 216;
- soundOptionsInfo.network.generic.y = 240 + PROP_HEIGHT;
- soundOptionsInfo.network.string = "NETWORK";
- soundOptionsInfo.network.style = UI_RIGHT;
- soundOptionsInfo.network.color = color_red;
-
- y = 240 - 1.5 * (BIGCHAR_HEIGHT + 2);
- soundOptionsInfo.sfxvolume.generic.type = MTYPE_SLIDER;
- soundOptionsInfo.sfxvolume.generic.name = "Effects Volume:";
- soundOptionsInfo.sfxvolume.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- soundOptionsInfo.sfxvolume.generic.callback = UI_SoundOptionsMenu_Event;
- soundOptionsInfo.sfxvolume.generic.id = ID_EFFECTSVOLUME;
- soundOptionsInfo.sfxvolume.generic.x = 400;
- soundOptionsInfo.sfxvolume.generic.y = y;
- soundOptionsInfo.sfxvolume.minvalue = 0;
- soundOptionsInfo.sfxvolume.maxvalue = 10;
-
- y += BIGCHAR_HEIGHT+2;
- soundOptionsInfo.musicvolume.generic.type = MTYPE_SLIDER;
- soundOptionsInfo.musicvolume.generic.name = "Music Volume:";
- soundOptionsInfo.musicvolume.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- soundOptionsInfo.musicvolume.generic.callback = UI_SoundOptionsMenu_Event;
- soundOptionsInfo.musicvolume.generic.id = ID_MUSICVOLUME;
- soundOptionsInfo.musicvolume.generic.x = 400;
- soundOptionsInfo.musicvolume.generic.y = y;
- soundOptionsInfo.musicvolume.minvalue = 0;
- soundOptionsInfo.musicvolume.maxvalue = 10;
-
- y += BIGCHAR_HEIGHT+2;
- soundOptionsInfo.quality.generic.type = MTYPE_SPINCONTROL;
- soundOptionsInfo.quality.generic.name = "Sound Quality:";
- soundOptionsInfo.quality.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- soundOptionsInfo.quality.generic.callback = UI_SoundOptionsMenu_Event;
- soundOptionsInfo.quality.generic.id = ID_QUALITY;
- soundOptionsInfo.quality.generic.x = 400;
- soundOptionsInfo.quality.generic.y = y;
- soundOptionsInfo.quality.itemnames = quality_items;
-/*
- y += BIGCHAR_HEIGHT+2;
- soundOptionsInfo.a3d.generic.type = MTYPE_RADIOBUTTON;
- soundOptionsInfo.a3d.generic.name = "A3D:";
- soundOptionsInfo.a3d.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- soundOptionsInfo.a3d.generic.callback = UI_SoundOptionsMenu_Event;
- soundOptionsInfo.a3d.generic.id = ID_A3D;
- soundOptionsInfo.a3d.generic.x = 400;
- soundOptionsInfo.a3d.generic.y = y;
-*/
- soundOptionsInfo.back.generic.type = MTYPE_BITMAP;
- soundOptionsInfo.back.generic.name = ART_BACK0;
- soundOptionsInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- soundOptionsInfo.back.generic.callback = UI_SoundOptionsMenu_Event;
- soundOptionsInfo.back.generic.id = ID_BACK;
- soundOptionsInfo.back.generic.x = 0;
- soundOptionsInfo.back.generic.y = 480-64;
- soundOptionsInfo.back.width = 128;
- soundOptionsInfo.back.height = 64;
- soundOptionsInfo.back.focuspic = ART_BACK1;
-
- Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.banner );
- Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.framel );
- Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.framer );
- Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.graphics );
- Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.display );
- Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.sound );
- Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.network );
- Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.sfxvolume );
- Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.musicvolume );
- Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.quality );
-// Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.a3d );
- Menu_AddItem( &soundOptionsInfo.menu, ( void * ) &soundOptionsInfo.back );
-
- soundOptionsInfo.sfxvolume.curvalue = trap_Cvar_VariableValue( "s_volume" ) * 10;
- soundOptionsInfo.musicvolume.curvalue = trap_Cvar_VariableValue( "s_musicvolume" ) * 10;
- soundOptionsInfo.quality.curvalue = !trap_Cvar_VariableValue( "s_compression" );
-// soundOptionsInfo.a3d.curvalue = (int)trap_Cvar_VariableValue( "s_usingA3D" );
-}
-
-
-/*
-===============
-UI_SoundOptionsMenu_Cache
-===============
-*/
-void UI_SoundOptionsMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
-}
-
-
-/*
-===============
-UI_SoundOptionsMenu
-===============
-*/
-void UI_SoundOptionsMenu( void ) {
- UI_SoundOptionsMenu_Init();
- UI_PushMenu( &soundOptionsInfo.menu );
- Menu_SetCursorToItem( &soundOptionsInfo.menu, &soundOptionsInfo.sound );
-}
diff --git a/engine/code/q3_ui/ui_specifyleague.c b/engine/code/q3_ui/ui_specifyleague.c
deleted file mode 100644
index a3d88e9..0000000
--- a/engine/code/q3_ui/ui_specifyleague.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-/*********************************************************************************
- SPECIFY SERVER
-*********************************************************************************/
-
-#define MAX_LISTBOXITEMS 128
-#define MAX_LISTBOXWIDTH 40
-#define MAX_LEAGUENAME 80
-
-#define SPECIFYLEAGUE_FRAMEL "menu/art/frame2_l"
-#define SPECIFYLEAGUE_FRAMER "menu/art/frame1_r"
-#define SPECIFYLEAGUE_BACK0 "menu/art/back_0"
-#define SPECIFYLEAGUE_BACK1 "menu/art/back_1"
-#define SPECIFYLEAGUE_ARROWS0 "menu/art/arrows_vert_0"
-#define SPECIFYLEAGUE_UP "menu/art/arrows_vert_top"
-#define SPECIFYLEAGUE_DOWN "menu/art/arrows_vert_bot"
-#define GLOBALRANKINGS_LOGO "menu/art/gr/grlogo"
-#define GLOBALRANKINGS_LETTERS "menu/art/gr/grletters"
-
-#define ID_SPECIFYLEAGUENAME 100
-#define ID_SPECIFYLEAGUELIST 101
-#define ID_SPECIFYLEAGUEUP 102
-#define ID_SPECIFYLEAGUEDOWN 103
-#define ID_SPECIFYLEAGUEBACK 104
-
-static char* specifyleague_artlist[] =
-{
- SPECIFYLEAGUE_FRAMEL,
- SPECIFYLEAGUE_FRAMER,
- SPECIFYLEAGUE_ARROWS0,
- SPECIFYLEAGUE_UP,
- SPECIFYLEAGUE_DOWN,
- SPECIFYLEAGUE_BACK0,
- SPECIFYLEAGUE_BACK1,
- GLOBALRANKINGS_LOGO,
- GLOBALRANKINGS_LETTERS,
- NULL
-};
-
-static char playername[80];
-
-typedef struct
-{
- menuframework_s menu;
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
- menufield_s rankname;
- menulist_s list;
- menubitmap_s arrows;
- menubitmap_s up;
- menubitmap_s down;
- menubitmap_s back;
- menubitmap_s grlogo;
- menubitmap_s grletters;
-} specifyleague_t;
-
-static specifyleague_t s_specifyleague;
-
-
-typedef struct {
- char buff[MAX_LISTBOXWIDTH];
- char leaguename[MAX_LEAGUENAME];
-} table_t;
-
-table_t league_table[MAX_LISTBOXITEMS];
-char *leaguename_items[MAX_LISTBOXITEMS];
-
-
-static void SpecifyLeague_GetList()
-{
- int count = 0;
- int i;
- /* The Player Name has changed. We need to perform another search */
- Q_strncpyz( playername,
- s_specifyleague.rankname.field.buffer,
- sizeof(playername) );
-
- count = trap_CL_UI_RankGetLeauges( playername );
-
- for(i = 0; i < count; i++)
- {
- char s[MAX_LEAGUENAME];
- const char *var;
- var = va( "leaguename%i", i+1 );
- trap_Cvar_VariableStringBuffer( var, s, sizeof(s) );
- Q_strncpyz(league_table[i].leaguename, s, sizeof(league_table[i].leaguename) );
- Q_strncpyz(league_table[i].buff, league_table[i].leaguename, sizeof(league_table[i].buff) );
- }
-
- s_specifyleague.list.numitems = count;
-}
-
-/*
-=================
-SpecifyLeague_Event
-=================
-*/
-static void SpecifyLeague_Event( void* ptr, int event )
-{
- int id;
- id = ((menucommon_s*)ptr)->id;
- //if( event != QM_ACTIVATED && id != ID_SPECIFYLEAGUELIST ) {
- // return;
- //}
-
- switch (id)
- {
- case ID_SPECIFYLEAGUELIST:
- if( event == QM_GOTFOCUS ) {
- //ArenaServers_UpdatePicture();
- }
- break;
-
- case ID_SPECIFYLEAGUEUP:
- if( event == QM_ACTIVATED )
- ScrollList_Key( &s_specifyleague.list, K_UPARROW );
- break;
-
- case ID_SPECIFYLEAGUEDOWN:
- if( event == QM_ACTIVATED )
- ScrollList_Key( &s_specifyleague.list, K_DOWNARROW );
- break;
-
- case ID_SPECIFYLEAGUENAME:
- if( (event == QM_LOSTFOCUS) &&
- (Q_strncmp(playername,
- s_specifyleague.rankname.field.buffer,
- strlen(s_specifyleague.rankname.field.buffer)) != 0))
- {
- SpecifyLeague_GetList();
- }
- break;
-
- case ID_SPECIFYLEAGUEBACK:
- if( event == QM_ACTIVATED )
- {
- trap_Cvar_Set( "sv_leagueName", league_table[s_specifyleague.list.curvalue].leaguename);
- UI_PopMenu();
- }
- break;
- }
-}
-
-/*
-=================
-SpecifyLeague_MenuInit
-=================
-*/
-void SpecifyLeague_MenuInit( void )
-{
- int i;
- // zero set all our globals
- memset( &s_specifyleague, 0 ,sizeof(specifyleague_t) );
-
- SpecifyLeague_Cache();
-
- s_specifyleague.menu.wrapAround = qtrue;
- s_specifyleague.menu.fullscreen = qtrue;
-
- s_specifyleague.banner.generic.type = MTYPE_BTEXT;
- s_specifyleague.banner.generic.x = 320;
- s_specifyleague.banner.generic.y = 16;
- s_specifyleague.banner.string = "CHOOSE LEAGUE";
- s_specifyleague.banner.color = color_white;
- s_specifyleague.banner.style = UI_CENTER;
-
- s_specifyleague.framel.generic.type = MTYPE_BITMAP;
- s_specifyleague.framel.generic.name = SPECIFYLEAGUE_FRAMEL;
- s_specifyleague.framel.generic.flags = QMF_INACTIVE;
- s_specifyleague.framel.generic.x = 0;
- s_specifyleague.framel.generic.y = 78;
- s_specifyleague.framel.width = 256;
- s_specifyleague.framel.height = 334;
-
- s_specifyleague.framer.generic.type = MTYPE_BITMAP;
- s_specifyleague.framer.generic.name = SPECIFYLEAGUE_FRAMER;
- s_specifyleague.framer.generic.flags = QMF_INACTIVE;
- s_specifyleague.framer.generic.x = 376;
- s_specifyleague.framer.generic.y = 76;
- s_specifyleague.framer.width = 256;
- s_specifyleague.framer.height = 334;
-
- s_specifyleague.grlogo.generic.type = MTYPE_BITMAP;
- s_specifyleague.grlogo.generic.name = GLOBALRANKINGS_LOGO;
- s_specifyleague.grlogo.generic.flags = QMF_INACTIVE;
- s_specifyleague.grlogo.generic.x = 0;
- s_specifyleague.grlogo.generic.y = 0;
- s_specifyleague.grlogo.width = 64;
- s_specifyleague.grlogo.height = 128;
-
- s_specifyleague.rankname.generic.type = MTYPE_FIELD;
- s_specifyleague.rankname.generic.name = "Player Name:";
- s_specifyleague.rankname.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_specifyleague.rankname.generic.callback = SpecifyLeague_Event;
- s_specifyleague.rankname.generic.id = ID_SPECIFYLEAGUENAME;
- s_specifyleague.rankname.generic.x = 226;
- s_specifyleague.rankname.generic.y = 128;
- s_specifyleague.rankname.field.widthInChars = 32;
- s_specifyleague.rankname.field.maxchars = 80;
-
- s_specifyleague.list.generic.type = MTYPE_SCROLLLIST;
- s_specifyleague.list.generic.flags = QMF_HIGHLIGHT_IF_FOCUS;
- s_specifyleague.list.generic.id = ID_SPECIFYLEAGUELIST;
- s_specifyleague.list.generic.callback = SpecifyLeague_Event;
- s_specifyleague.list.generic.x = 160;
- s_specifyleague.list.generic.y = 200;
- s_specifyleague.list.width = MAX_LISTBOXWIDTH;
- s_specifyleague.list.height = 8;
- s_specifyleague.list.itemnames = (const char **)leaguename_items;
- s_specifyleague.list.numitems = 0;
- for( i = 0; i < MAX_LISTBOXITEMS; i++ ) {
- league_table[i].buff[0] = 0;
- league_table[i].leaguename[0] = 0;
- leaguename_items[i] = league_table[i].buff;
- }
-
- s_specifyleague.arrows.generic.type = MTYPE_BITMAP;
- s_specifyleague.arrows.generic.name = SPECIFYLEAGUE_ARROWS0;
- s_specifyleague.arrows.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_specifyleague.arrows.generic.callback = SpecifyLeague_Event;
- s_specifyleague.arrows.generic.x = 512;
- s_specifyleague.arrows.generic.y = 240-64+16;
- s_specifyleague.arrows.width = 64;
- s_specifyleague.arrows.height = 128;
-
- s_specifyleague.up.generic.type = MTYPE_BITMAP;
- s_specifyleague.up.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
- s_specifyleague.up.generic.callback = SpecifyLeague_Event;
- s_specifyleague.up.generic.id = ID_SPECIFYLEAGUEUP;
- s_specifyleague.up.generic.x = 512;
- s_specifyleague.up.generic.y = 240-64+16;
- s_specifyleague.up.width = 64;
- s_specifyleague.up.height = 64;
- s_specifyleague.up.focuspic = SPECIFYLEAGUE_UP;
-
- s_specifyleague.down.generic.type = MTYPE_BITMAP;
- s_specifyleague.down.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
- s_specifyleague.down.generic.callback = SpecifyLeague_Event;
- s_specifyleague.down.generic.id = ID_SPECIFYLEAGUEDOWN;
- s_specifyleague.down.generic.x = 512;
- s_specifyleague.down.generic.y = 240+16;
- s_specifyleague.down.width = 64;
- s_specifyleague.down.height = 64;
- s_specifyleague.down.focuspic = SPECIFYLEAGUE_DOWN;
-
- s_specifyleague.back.generic.type = MTYPE_BITMAP;
- s_specifyleague.back.generic.name = SPECIFYLEAGUE_BACK0;
- s_specifyleague.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_specifyleague.back.generic.callback = SpecifyLeague_Event;
- s_specifyleague.back.generic.id = ID_SPECIFYLEAGUEBACK;
- s_specifyleague.back.generic.x = 0;
- s_specifyleague.back.generic.y = 480-64;
- s_specifyleague.back.width = 128;
- s_specifyleague.back.height = 64;
- s_specifyleague.back.focuspic = SPECIFYLEAGUE_BACK1;
-
- Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.banner );
- Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.framel );
- Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.framer );
- Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.grlogo );
- Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.rankname );
- Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.list );
- Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.arrows );
- Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.up );
- Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.down );
- Menu_AddItem( &s_specifyleague.menu, &s_specifyleague.back );
-
-
- // initialize any menu variables
- Q_strncpyz( s_specifyleague.rankname.field.buffer,
- UI_Cvar_VariableString("name"),
- sizeof(s_specifyleague.rankname.field.buffer) );
-
- Q_strncpyz( playername,
- UI_Cvar_VariableString("name"),
- sizeof(playername) );
-
- SpecifyLeague_GetList();
-}
-
-/*
-=================
-SpecifyLeague_Cache
-=================
-*/
-void SpecifyLeague_Cache( void )
-{
- int i;
-
- // touch all our pics
- for (i=0; ;i++)
- {
- if (!specifyleague_artlist[i])
- break;
- trap_R_RegisterShaderNoMip(specifyleague_artlist[i]);
- }
-}
-
-/*
-=================
-UI_SpecifyLeagueMenu
-=================
-*/
-void UI_SpecifyLeagueMenu( void )
-{
- SpecifyLeague_MenuInit();
- UI_PushMenu( &s_specifyleague.menu );
-}
-
diff --git a/engine/code/q3_ui/ui_specifyserver.c b/engine/code/q3_ui/ui_specifyserver.c
deleted file mode 100644
index 784bc7a..0000000
--- a/engine/code/q3_ui/ui_specifyserver.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-/*********************************************************************************
- SPECIFY SERVER
-*********************************************************************************/
-
-#define SPECIFYSERVER_FRAMEL "menu/art/frame2_l"
-#define SPECIFYSERVER_FRAMER "menu/art/frame1_r"
-#define SPECIFYSERVER_BACK0 "menu/art/back_0"
-#define SPECIFYSERVER_BACK1 "menu/art/back_1"
-#define SPECIFYSERVER_FIGHT0 "menu/art/fight_0"
-#define SPECIFYSERVER_FIGHT1 "menu/art/fight_1"
-
-#define ID_SPECIFYSERVERBACK 102
-#define ID_SPECIFYSERVERGO 103
-
-static char* specifyserver_artlist[] =
-{
- SPECIFYSERVER_FRAMEL,
- SPECIFYSERVER_FRAMER,
- SPECIFYSERVER_BACK0,
- SPECIFYSERVER_BACK1,
- SPECIFYSERVER_FIGHT0,
- SPECIFYSERVER_FIGHT1,
- NULL
-};
-
-typedef struct
-{
- menuframework_s menu;
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
- menufield_s domain;
- menufield_s port;
- menubitmap_s go;
- menubitmap_s back;
-} specifyserver_t;
-
-static specifyserver_t s_specifyserver;
-
-/*
-=================
-SpecifyServer_Event
-=================
-*/
-static void SpecifyServer_Event( void* ptr, int event )
-{
- char buff[256];
-
- switch (((menucommon_s*)ptr)->id)
- {
- case ID_SPECIFYSERVERGO:
- if (event != QM_ACTIVATED)
- break;
-
- if (s_specifyserver.domain.field.buffer[0])
- {
- strcpy(buff,s_specifyserver.domain.field.buffer);
- if (s_specifyserver.port.field.buffer[0])
- Com_sprintf( buff+strlen(buff), 128, ":%s", s_specifyserver.port.field.buffer );
-
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", buff ) );
- }
- break;
-
- case ID_SPECIFYSERVERBACK:
- if (event != QM_ACTIVATED)
- break;
-
- UI_PopMenu();
- break;
- }
-}
-
-/*
-=================
-SpecifyServer_MenuInit
-=================
-*/
-void SpecifyServer_MenuInit( void )
-{
- // zero set all our globals
- memset( &s_specifyserver, 0 ,sizeof(specifyserver_t) );
-
- SpecifyServer_Cache();
-
- s_specifyserver.menu.wrapAround = qtrue;
- s_specifyserver.menu.fullscreen = qtrue;
-
- s_specifyserver.banner.generic.type = MTYPE_BTEXT;
- s_specifyserver.banner.generic.x = 320;
- s_specifyserver.banner.generic.y = 16;
- s_specifyserver.banner.string = "SPECIFY SERVER";
- s_specifyserver.banner.color = color_white;
- s_specifyserver.banner.style = UI_CENTER;
-
- s_specifyserver.framel.generic.type = MTYPE_BITMAP;
- s_specifyserver.framel.generic.name = SPECIFYSERVER_FRAMEL;
- s_specifyserver.framel.generic.flags = QMF_INACTIVE;
- s_specifyserver.framel.generic.x = 0;
- s_specifyserver.framel.generic.y = 78;
- s_specifyserver.framel.width = 256;
- s_specifyserver.framel.height = 329;
-
- s_specifyserver.framer.generic.type = MTYPE_BITMAP;
- s_specifyserver.framer.generic.name = SPECIFYSERVER_FRAMER;
- s_specifyserver.framer.generic.flags = QMF_INACTIVE;
- s_specifyserver.framer.generic.x = 376;
- s_specifyserver.framer.generic.y = 76;
- s_specifyserver.framer.width = 256;
- s_specifyserver.framer.height = 334;
-
- s_specifyserver.domain.generic.type = MTYPE_FIELD;
- s_specifyserver.domain.generic.name = "Address:";
- s_specifyserver.domain.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_specifyserver.domain.generic.x = 206;
- s_specifyserver.domain.generic.y = 220;
- s_specifyserver.domain.field.widthInChars = 38;
- s_specifyserver.domain.field.maxchars = 80;
-
- s_specifyserver.port.generic.type = MTYPE_FIELD;
- s_specifyserver.port.generic.name = "Port:";
- s_specifyserver.port.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT|QMF_NUMBERSONLY;
- s_specifyserver.port.generic.x = 206;
- s_specifyserver.port.generic.y = 250;
- s_specifyserver.port.field.widthInChars = 6;
- s_specifyserver.port.field.maxchars = 5;
-
- s_specifyserver.go.generic.type = MTYPE_BITMAP;
- s_specifyserver.go.generic.name = SPECIFYSERVER_FIGHT0;
- s_specifyserver.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_specifyserver.go.generic.callback = SpecifyServer_Event;
- s_specifyserver.go.generic.id = ID_SPECIFYSERVERGO;
- s_specifyserver.go.generic.x = 640;
- s_specifyserver.go.generic.y = 480-64;
- s_specifyserver.go.width = 128;
- s_specifyserver.go.height = 64;
- s_specifyserver.go.focuspic = SPECIFYSERVER_FIGHT1;
-
- s_specifyserver.back.generic.type = MTYPE_BITMAP;
- s_specifyserver.back.generic.name = SPECIFYSERVER_BACK0;
- s_specifyserver.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_specifyserver.back.generic.callback = SpecifyServer_Event;
- s_specifyserver.back.generic.id = ID_SPECIFYSERVERBACK;
- s_specifyserver.back.generic.x = 0;
- s_specifyserver.back.generic.y = 480-64;
- s_specifyserver.back.width = 128;
- s_specifyserver.back.height = 64;
- s_specifyserver.back.focuspic = SPECIFYSERVER_BACK1;
-
- Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.banner );
- Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.framel );
- Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.framer );
- Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.domain );
- Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.port );
- Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.go );
- Menu_AddItem( &s_specifyserver.menu, &s_specifyserver.back );
-
- Com_sprintf( s_specifyserver.port.field.buffer, 6, "%i", 27960 );
-}
-
-/*
-=================
-SpecifyServer_Cache
-=================
-*/
-void SpecifyServer_Cache( void )
-{
- int i;
-
- // touch all our pics
- for (i=0; ;i++)
- {
- if (!specifyserver_artlist[i])
- break;
- trap_R_RegisterShaderNoMip(specifyserver_artlist[i]);
- }
-}
-
-/*
-=================
-UI_SpecifyServerMenu
-=================
-*/
-void UI_SpecifyServerMenu( void )
-{
- SpecifyServer_MenuInit();
- UI_PushMenu( &s_specifyserver.menu );
-}
-
diff --git a/engine/code/q3_ui/ui_splevel.c b/engine/code/q3_ui/ui_splevel.c
deleted file mode 100644
index 0c3b08f..0000000
--- a/engine/code/q3_ui/ui_splevel.c
+++ /dev/null
@@ -1,1013 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=============================================================================
-
-SINGLE PLAYER LEVEL SELECT MENU
-
-=============================================================================
-*/
-
-#include "ui_local.h"
-
-
-#define ART_LEVELFRAME_FOCUS "menu/art/maps_select"
-#define ART_LEVELFRAME_SELECTED "menu/art/maps_selected"
-#define ART_ARROW "menu/art/narrow_0"
-#define ART_ARROW_FOCUS "menu/art/narrow_1"
-#define ART_MAP_UNKNOWN "menu/art/unknownmap"
-#define ART_MAP_COMPLETE1 "menu/art/level_complete1"
-#define ART_MAP_COMPLETE2 "menu/art/level_complete2"
-#define ART_MAP_COMPLETE3 "menu/art/level_complete3"
-#define ART_MAP_COMPLETE4 "menu/art/level_complete4"
-#define ART_MAP_COMPLETE5 "menu/art/level_complete5"
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-#define ART_FIGHT0 "menu/art/fight_0"
-#define ART_FIGHT1 "menu/art/fight_1"
-#define ART_RESET0 "menu/art/reset_0"
-#define ART_RESET1 "menu/art/reset_1"
-#define ART_CUSTOM0 "menu/art/skirmish_0"
-#define ART_CUSTOM1 "menu/art/skirmish_1"
-
-#define ID_LEFTARROW 10
-#define ID_PICTURE0 11
-#define ID_PICTURE1 12
-#define ID_PICTURE2 13
-#define ID_PICTURE3 14
-#define ID_RIGHTARROW 15
-#define ID_PLAYERPIC 16
-#define ID_AWARD1 17
-#define ID_AWARD2 18
-#define ID_AWARD3 19
-#define ID_AWARD4 20
-#define ID_AWARD5 21
-#define ID_AWARD6 22
-#define ID_BACK 23
-#define ID_RESET 24
-#define ID_CUSTOM 25
-#define ID_NEXT 26
-
-#define PLAYER_Y 314
-#define AWARDS_Y (PLAYER_Y + 26)
-
-
-typedef struct {
- menuframework_s menu;
- menutext_s item_banner;
- menubitmap_s item_leftarrow;
- menubitmap_s item_maps[4];
- menubitmap_s item_rightarrow;
- menubitmap_s item_player;
- menubitmap_s item_awards[6];
- menubitmap_s item_back;
- menubitmap_s item_reset;
- menubitmap_s item_custom;
- menubitmap_s item_next;
- menubitmap_s item_null;
-
- qboolean reinit;
-
- const char * selectedArenaInfo;
- int numMaps;
- char levelPicNames[4][MAX_QPATH];
- char levelNames[4][16];
- int levelScores[4];
- int levelScoresSkill[4];
- qhandle_t levelSelectedPic;
- qhandle_t levelFocusPic;
- qhandle_t levelCompletePic[5];
-
- char playerModel[MAX_QPATH];
- char playerPicName[MAX_QPATH];
- int awardLevels[6];
- sfxHandle_t awardSounds[6];
-
- int numBots;
- qhandle_t botPics[7];
- char botNames[7][10];
-} levelMenuInfo_t;
-
-static levelMenuInfo_t levelMenuInfo;
-
-static int selectedArenaSet;
-static int selectedArena;
-static int currentSet;
-static int currentGame;
-static int trainingTier;
-static int finalTier;
-static int minTier;
-static int maxTier;
-
-
-/*
-=================
-PlayerIcon
-=================
-*/
-static void PlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize ) {
- char *skin;
- char model[MAX_QPATH];
-
- Q_strncpyz( model, modelAndSkin, sizeof(model));
- skin = Q_strrchr( model, '/' );
- if ( skin ) {
- *skin++ = '\0';
- }
- else {
- skin = "default";
- }
-
- Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_%s.tga", model, skin );
-
- if( !trap_R_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, "default" ) != 0 ) {
- Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_default.tga", model );
- }
-}
-
-
-/*
-=================
-PlayerIconhandle
-=================
-*/
-static qhandle_t PlayerIconHandle( const char *modelAndSkin ) {
- char iconName[MAX_QPATH];
-
- PlayerIcon( modelAndSkin, iconName, sizeof(iconName) );
- return trap_R_RegisterShaderNoMip( iconName );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_SetBots
-=================
-*/
-static void UI_SPLevelMenu_SetBots( void ) {
- char *p;
- char *bot;
- char *botInfo;
- char bots[MAX_INFO_STRING];
-
- levelMenuInfo.numBots = 0;
- if ( selectedArenaSet > currentSet ) {
- return;
- }
-
- Q_strncpyz( bots, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "bots" ), sizeof(bots) );
-
- p = &bots[0];
- while( *p && levelMenuInfo.numBots < 7 ) {
- //skip spaces
- while( *p && *p == ' ' ) {
- p++;
- }
- if( !p ) {
- break;
- }
-
- // mark start of bot name
- bot = p;
-
- // skip until space of null
- while( *p && *p != ' ' ) {
- p++;
- }
- if( *p ) {
- *p++ = 0;
- }
-
- botInfo = UI_GetBotInfoByName( bot );
- if(!botInfo)
- {
- botInfo = UI_GetBotInfoByNumber( levelMenuInfo.numBots );
- }
-
- if( botInfo ) {
- levelMenuInfo.botPics[levelMenuInfo.numBots] = PlayerIconHandle( Info_ValueForKey( botInfo, "model" ) );
- Q_strncpyz( levelMenuInfo.botNames[levelMenuInfo.numBots], Info_ValueForKey( botInfo, "name" ), 10 );
- }
- else {
- levelMenuInfo.botPics[levelMenuInfo.numBots] = 0;
- Q_strncpyz( levelMenuInfo.botNames[levelMenuInfo.numBots], bot, 10 );
- }
- Q_CleanStr( levelMenuInfo.botNames[levelMenuInfo.numBots] );
- levelMenuInfo.numBots++;
- }
-}
-
-
-/*
-=================
-UI_SPLevelMenu_SetMenuItems
-=================
-*/
-static void UI_SPLevelMenu_SetMenuArena( int n, int level, const char *arenaInfo ) {
- char map[MAX_QPATH];
-
- Q_strncpyz( map, Info_ValueForKey( arenaInfo, "map" ), sizeof(map) );
-
- Q_strncpyz( levelMenuInfo.levelNames[n], map, sizeof(levelMenuInfo.levelNames[n]) );
- Q_strupr( levelMenuInfo.levelNames[n] );
-
- UI_GetBestScore( level, &levelMenuInfo.levelScores[n], &levelMenuInfo.levelScoresSkill[n] );
- if( levelMenuInfo.levelScores[n] > 8 ) {
- levelMenuInfo.levelScores[n] = 8;
- }
-
- strcpy( levelMenuInfo.levelPicNames[n], va( "levelshots/%s.tga", map ) );
- if( !trap_R_RegisterShaderNoMip( levelMenuInfo.levelPicNames[n] ) ) {
- strcpy( levelMenuInfo.levelPicNames[n], ART_MAP_UNKNOWN );
- }
- levelMenuInfo.item_maps[n].shader = 0;
- if ( selectedArenaSet > currentSet ) {
- levelMenuInfo.item_maps[n].generic.flags |= QMF_GRAYED;
- }
- else {
- levelMenuInfo.item_maps[n].generic.flags &= ~QMF_GRAYED;
- }
-
- levelMenuInfo.item_maps[n].generic.flags &= ~QMF_INACTIVE;
-}
-
-static void UI_SPLevelMenu_SetMenuItems( void ) {
- int n;
- int level;
- const char *arenaInfo;
-
- if ( selectedArenaSet > currentSet ) {
- selectedArena = -1;
- }
- else if ( selectedArena == -1 ) {
- selectedArena = 0;
- }
-
- if( selectedArenaSet == trainingTier || selectedArenaSet == finalTier ) {
- selectedArena = 0;
- }
-
- if( selectedArena != -1 ) {
- trap_Cvar_SetValue( "ui_spSelection", selectedArenaSet * ARENAS_PER_TIER + selectedArena );
- }
-
- if( selectedArenaSet == trainingTier ) {
- arenaInfo = UI_GetSpecialArenaInfo( "training" );
- level = atoi( Info_ValueForKey( arenaInfo, "num" ) );
- UI_SPLevelMenu_SetMenuArena( 0, level, arenaInfo );
- levelMenuInfo.selectedArenaInfo = arenaInfo;
-
- levelMenuInfo.item_maps[0].generic.x = 256;
- Bitmap_Init( &levelMenuInfo.item_maps[0] );
- levelMenuInfo.item_maps[0].generic.bottom += 32;
- levelMenuInfo.numMaps = 1;
-
- levelMenuInfo.item_maps[1].generic.flags |= QMF_INACTIVE;
- levelMenuInfo.item_maps[2].generic.flags |= QMF_INACTIVE;
- levelMenuInfo.item_maps[3].generic.flags |= QMF_INACTIVE;
- levelMenuInfo.levelPicNames[1][0] = 0;
- levelMenuInfo.levelPicNames[2][0] = 0;
- levelMenuInfo.levelPicNames[3][0] = 0;
- levelMenuInfo.item_maps[1].shader = 0;
- levelMenuInfo.item_maps[2].shader = 0;
- levelMenuInfo.item_maps[3].shader = 0;
- }
- else if( selectedArenaSet == finalTier ) {
- arenaInfo = UI_GetSpecialArenaInfo( "final" );
- level = atoi( Info_ValueForKey( arenaInfo, "num" ) );
- UI_SPLevelMenu_SetMenuArena( 0, level, arenaInfo );
- levelMenuInfo.selectedArenaInfo = arenaInfo;
-
- levelMenuInfo.item_maps[0].generic.x = 256;
- Bitmap_Init( &levelMenuInfo.item_maps[0] );
- levelMenuInfo.item_maps[0].generic.bottom += 32;
- levelMenuInfo.numMaps = 1;
-
- levelMenuInfo.item_maps[1].generic.flags |= QMF_INACTIVE;
- levelMenuInfo.item_maps[2].generic.flags |= QMF_INACTIVE;
- levelMenuInfo.item_maps[3].generic.flags |= QMF_INACTIVE;
- levelMenuInfo.levelPicNames[1][0] = 0;
- levelMenuInfo.levelPicNames[2][0] = 0;
- levelMenuInfo.levelPicNames[3][0] = 0;
- levelMenuInfo.item_maps[1].shader = 0;
- levelMenuInfo.item_maps[2].shader = 0;
- levelMenuInfo.item_maps[3].shader = 0;
- }
- else {
- levelMenuInfo.item_maps[0].generic.x = 46;
- Bitmap_Init( &levelMenuInfo.item_maps[0] );
- levelMenuInfo.item_maps[0].generic.bottom += 18;
- levelMenuInfo.numMaps = 4;
-
- for ( n = 0; n < 4; n++ ) {
- level = selectedArenaSet * ARENAS_PER_TIER + n;
- arenaInfo = UI_GetArenaInfoByNumber( level );
- UI_SPLevelMenu_SetMenuArena( n, level, arenaInfo );
- }
-
- if( selectedArena != -1 ) {
- levelMenuInfo.selectedArenaInfo = UI_GetArenaInfoByNumber( selectedArenaSet * ARENAS_PER_TIER + selectedArena );
- }
- }
-
- // enable/disable arrows when they are valid/invalid
- if ( selectedArenaSet == minTier ) {
- levelMenuInfo.item_leftarrow.generic.flags |= ( QMF_INACTIVE | QMF_HIDDEN );
- }
- else {
- levelMenuInfo.item_leftarrow.generic.flags &= ~( QMF_INACTIVE | QMF_HIDDEN );
- }
-
- if ( selectedArenaSet == maxTier ) {
- levelMenuInfo.item_rightarrow.generic.flags |= ( QMF_INACTIVE | QMF_HIDDEN );
- }
- else {
- levelMenuInfo.item_rightarrow.generic.flags &= ~( QMF_INACTIVE | QMF_HIDDEN );
- }
-
- UI_SPLevelMenu_SetBots();
-}
-
-
-/*
-=================
-UI_SPLevelMenu_ResetEvent
-=================
-*/
-static void UI_SPLevelMenu_ResetDraw( void ) {
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, "WARNING: This resets all of the", UI_CENTER|UI_SMALLFONT, color_yellow );
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, "single player game variables.", UI_CENTER|UI_SMALLFONT, color_yellow );
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 2, "Do this only if you want to", UI_CENTER|UI_SMALLFONT, color_yellow );
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 3, "start over from the beginning.", UI_CENTER|UI_SMALLFONT, color_yellow );
-}
-
-static void UI_SPLevelMenu_ResetAction( qboolean result ) {
- if( !result ) {
- return;
- }
-
- // clear game variables
- UI_NewGame();
- trap_Cvar_SetValue( "ui_spSelection", -4 );
-
- // make the level select menu re-initialize
- UI_PopMenu();
- UI_SPLevelMenu();
-}
-
-static void UI_SPLevelMenu_ResetEvent( void* ptr, int event )
-{
- if (event != QM_ACTIVATED) {
- return;
- }
-
- UI_ConfirmMenu( "RESET GAME?", UI_SPLevelMenu_ResetDraw, UI_SPLevelMenu_ResetAction );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_LevelEvent
-=================
-*/
-static void UI_SPLevelMenu_LevelEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- if ( selectedArenaSet == trainingTier || selectedArenaSet == finalTier ) {
- return;
- }
-
- selectedArena = ((menucommon_s*)ptr)->id - ID_PICTURE0;
- levelMenuInfo.selectedArenaInfo = UI_GetArenaInfoByNumber( selectedArenaSet * ARENAS_PER_TIER + selectedArena );
- UI_SPLevelMenu_SetBots();
-
- trap_Cvar_SetValue( "ui_spSelection", selectedArenaSet * ARENAS_PER_TIER + selectedArena );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_LeftArrowEvent
-=================
-*/
-static void UI_SPLevelMenu_LeftArrowEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- if ( selectedArenaSet == minTier ) {
- return;
- }
-
- selectedArenaSet--;
- UI_SPLevelMenu_SetMenuItems();
-}
-
-
-/*
-=================
-UI_SPLevelMenu_RightArrowEvent
-=================
-*/
-static void UI_SPLevelMenu_RightArrowEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- if ( selectedArenaSet == maxTier ) {
- return;
- }
-
- selectedArenaSet++;
- UI_SPLevelMenu_SetMenuItems();
-}
-
-
-/*
-=================
-UI_SPLevelMenu_PlayerEvent
-=================
-*/
-static void UI_SPLevelMenu_PlayerEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- UI_PlayerSettingsMenu();
-}
-
-
-/*
-=================
-UI_SPLevelMenu_AwardEvent
-=================
-*/
-static void UI_SPLevelMenu_AwardEvent( void* ptr, int notification ) {
- int n;
-
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- n = ((menucommon_s*)ptr)->id - ID_AWARD1;
- trap_S_StartLocalSound( levelMenuInfo.awardSounds[n], CHAN_ANNOUNCER );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_NextEvent
-=================
-*/
-static void UI_SPLevelMenu_NextEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- if ( selectedArenaSet > currentSet ) {
- return;
- }
-
- if ( selectedArena == -1 ) {
- selectedArena = 0;
- }
-
- UI_SPSkillMenu( levelMenuInfo.selectedArenaInfo );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_BackEvent
-=================
-*/
-static void UI_SPLevelMenu_BackEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- if ( selectedArena == -1 ) {
- selectedArena = 0;
- }
-
- UI_PopMenu();
-}
-
-
-/*
-=================
-UI_SPLevelMenu_CustomEvent
-=================
-*/
-static void UI_SPLevelMenu_CustomEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- UI_StartServerMenu( qfalse );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_MenuDraw
-=================
-*/
-#define LEVEL_DESC_LEFT_MARGIN 332
-
-static void UI_SPLevelMenu_MenuDraw( void ) {
- int n, i;
- int x, y;
- vec4_t color;
- int level;
-// int fraglimit;
- int pad;
- char buf[MAX_INFO_VALUE];
- char string[64];
-
- if( levelMenuInfo.reinit ) {
- UI_PopMenu();
- UI_SPLevelMenu();
- return;
- }
-
- // draw player name
- trap_Cvar_VariableStringBuffer( "name", string, 32 );
- Q_CleanStr( string );
- UI_DrawProportionalString( 320, PLAYER_Y, string, UI_CENTER|UI_SMALLFONT, color_orange );
-
- // check for model changes
- trap_Cvar_VariableStringBuffer( "model", buf, sizeof(buf) );
- if( Q_stricmp( buf, levelMenuInfo.playerModel ) != 0 ) {
- Q_strncpyz( levelMenuInfo.playerModel, buf, sizeof(levelMenuInfo.playerModel) );
- PlayerIcon( levelMenuInfo.playerModel, levelMenuInfo.playerPicName, sizeof(levelMenuInfo.playerPicName) );
- levelMenuInfo.item_player.shader = 0;
- }
-
- // standard menu drawing
- Menu_Draw( &levelMenuInfo.menu );
-
- // draw player award levels
- y = AWARDS_Y;
- i = 0;
- for( n = 0; n < 6; n++ ) {
- level = levelMenuInfo.awardLevels[n];
- if( level > 0 ) {
- if( i & 1 ) {
- x = 224 - (i - 1 ) / 2 * (48 + 16);
- }
- else {
- x = 368 + i / 2 * (48 + 16);
- }
- i++;
-
- if( level == 1 ) {
- continue;
- }
-
- if( level >= 1000000 ) {
- Com_sprintf( string, sizeof(string), "%im", level / 1000000 );
- }
- else if( level >= 1000 ) {
- Com_sprintf( string, sizeof(string), "%ik", level / 1000 );
- }
- else {
- Com_sprintf( string, sizeof(string), "%i", level );
- }
-
- UI_DrawString( x + 24, y + 48, string, UI_CENTER, color_yellow );
- }
- }
-
- UI_DrawProportionalString( 18, 38, va( "Tier %i", selectedArenaSet + 1 ), UI_LEFT|UI_SMALLFONT, color_orange );
-
- for ( n = 0; n < levelMenuInfo.numMaps; n++ ) {
- x = levelMenuInfo.item_maps[n].generic.x;
- y = levelMenuInfo.item_maps[n].generic.y;
- UI_FillRect( x, y + 96, 128, 18, color_black );
- }
-
- if ( selectedArenaSet > currentSet ) {
- UI_DrawProportionalString( 320, 216, "ACCESS DENIED", UI_CENTER|UI_BIGFONT, color_red );
- return;
- }
-
- // show levelshots for levels of current tier
- Vector4Copy( color_white, color );
- color[3] = 0.5+0.5*sin(uis.realtime/PULSE_DIVISOR);
- for ( n = 0; n < levelMenuInfo.numMaps; n++ ) {
- x = levelMenuInfo.item_maps[n].generic.x;
- y = levelMenuInfo.item_maps[n].generic.y;
-
- UI_DrawString( x + 64, y + 96, levelMenuInfo.levelNames[n], UI_CENTER|UI_SMALLFONT, color_orange );
-
- if( levelMenuInfo.levelScores[n] == 1 ) {
- UI_DrawHandlePic( x, y, 128, 96, levelMenuInfo.levelCompletePic[levelMenuInfo.levelScoresSkill[n] - 1] );
- }
-
- if ( n == selectedArena ) {
- if( Menu_ItemAtCursor( &levelMenuInfo.menu ) == &levelMenuInfo.item_maps[n] ) {
- trap_R_SetColor( color );
- }
- UI_DrawHandlePic( x-1, y-1, 130, 130 - 14, levelMenuInfo.levelSelectedPic );
- trap_R_SetColor( NULL );
- }
- else if( Menu_ItemAtCursor( &levelMenuInfo.menu ) == &levelMenuInfo.item_maps[n] ) {
- trap_R_SetColor( color );
- UI_DrawHandlePic( x-31, y-30, 256, 256-27, levelMenuInfo.levelFocusPic);
- trap_R_SetColor( NULL );
- }
- }
-
- // show map name and long name of selected level
- y = 192;
- Q_strncpyz( buf, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "map" ), 20 );
- Q_strupr( buf );
- Com_sprintf( string, sizeof(string), "%s: %s", buf, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "longname" ) );
- UI_DrawProportionalString( 320, y, string, UI_CENTER|UI_SMALLFONT, color_orange );
-
-// fraglimit = atoi( Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "fraglimit" ) );
-// UI_DrawString( 18, 212, va("Frags %i", fraglimit) , UI_LEFT|UI_SMALLFONT, color_orange );
-
- // draw bot opponents
- y += 24;
- pad = (7 - levelMenuInfo.numBots) * (64 + 26) / 2;
- for( n = 0; n < levelMenuInfo.numBots; n++ ) {
- x = 18 + pad + (64 + 26) * n;
- if( levelMenuInfo.botPics[n] ) {
- UI_DrawHandlePic( x, y, 64, 64, levelMenuInfo.botPics[n]);
- }
- else {
- UI_FillRect( x, y, 64, 64, color_black );
- UI_DrawProportionalString( x+22, y+18, "?", UI_BIGFONT, color_orange );
- }
- UI_DrawString( x, y + 64, levelMenuInfo.botNames[n], UI_SMALLFONT|UI_LEFT, color_orange );
- }
-}
-
-
-/*
-=================
-UI_SPLevelMenu_Cache
-=================
-*/
-void UI_SPLevelMenu_Cache( void ) {
- int n;
-
- trap_R_RegisterShaderNoMip( ART_LEVELFRAME_FOCUS );
- trap_R_RegisterShaderNoMip( ART_LEVELFRAME_SELECTED );
- trap_R_RegisterShaderNoMip( ART_ARROW );
- trap_R_RegisterShaderNoMip( ART_ARROW_FOCUS );
- trap_R_RegisterShaderNoMip( ART_MAP_UNKNOWN );
- trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE1 );
- trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE2 );
- trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE3 );
- trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE4 );
- trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE5 );
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_FIGHT0 );
- trap_R_RegisterShaderNoMip( ART_FIGHT1 );
- trap_R_RegisterShaderNoMip( ART_RESET0 );
- trap_R_RegisterShaderNoMip( ART_RESET1 );
- trap_R_RegisterShaderNoMip( ART_CUSTOM0 );
- trap_R_RegisterShaderNoMip( ART_CUSTOM1 );
-
- for( n = 0; n < 6; n++ ) {
- trap_R_RegisterShaderNoMip( ui_medalPicNames[n] );
- levelMenuInfo.awardSounds[n] = trap_S_RegisterSound( ui_medalSounds[n], qfalse );
- }
-
- levelMenuInfo.levelSelectedPic = trap_R_RegisterShaderNoMip( ART_LEVELFRAME_SELECTED );
- levelMenuInfo.levelFocusPic = trap_R_RegisterShaderNoMip( ART_LEVELFRAME_FOCUS );
- levelMenuInfo.levelCompletePic[0] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE1 );
- levelMenuInfo.levelCompletePic[1] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE2 );
- levelMenuInfo.levelCompletePic[2] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE3 );
- levelMenuInfo.levelCompletePic[3] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE4 );
- levelMenuInfo.levelCompletePic[4] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE5 );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_Init
-=================
-*/
-static void UI_SPLevelMenu_Init( void ) {
- int skill;
- int n;
- int x, y;
- int count;
- char buf[MAX_QPATH];
-
- skill = (int)trap_Cvar_VariableValue( "g_spSkill" );
- if( skill < 1 || skill > 5 ) {
- trap_Cvar_Set( "g_spSkill", "2" );
- skill = 2;
- }
-
- memset( &levelMenuInfo, 0, sizeof(levelMenuInfo) );
- levelMenuInfo.menu.fullscreen = qtrue;
- levelMenuInfo.menu.wrapAround = qtrue;
- levelMenuInfo.menu.draw = UI_SPLevelMenu_MenuDraw;
-
- UI_SPLevelMenu_Cache();
-
- levelMenuInfo.item_banner.generic.type = MTYPE_BTEXT;
- levelMenuInfo.item_banner.generic.x = 320;
- levelMenuInfo.item_banner.generic.y = 16;
- levelMenuInfo.item_banner.string = "CHOOSE LEVEL";
- levelMenuInfo.item_banner.color = color_red;
- levelMenuInfo.item_banner.style = UI_CENTER;
-
- levelMenuInfo.item_leftarrow.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_leftarrow.generic.name = ART_ARROW;
- levelMenuInfo.item_leftarrow.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- levelMenuInfo.item_leftarrow.generic.x = 18;
- levelMenuInfo.item_leftarrow.generic.y = 64;
- levelMenuInfo.item_leftarrow.generic.callback = UI_SPLevelMenu_LeftArrowEvent;
- levelMenuInfo.item_leftarrow.generic.id = ID_LEFTARROW;
- levelMenuInfo.item_leftarrow.width = 16;
- levelMenuInfo.item_leftarrow.height = 114;
- levelMenuInfo.item_leftarrow.focuspic = ART_ARROW_FOCUS;
-
- levelMenuInfo.item_maps[0].generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_maps[0].generic.name = levelMenuInfo.levelPicNames[0];
- levelMenuInfo.item_maps[0].generic.flags = QMF_LEFT_JUSTIFY;
- levelMenuInfo.item_maps[0].generic.x = 46;
- levelMenuInfo.item_maps[0].generic.y = 64;
- levelMenuInfo.item_maps[0].generic.id = ID_PICTURE0;
- levelMenuInfo.item_maps[0].generic.callback = UI_SPLevelMenu_LevelEvent;
- levelMenuInfo.item_maps[0].width = 128;
- levelMenuInfo.item_maps[0].height = 96;
-
- levelMenuInfo.item_maps[1].generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_maps[1].generic.name = levelMenuInfo.levelPicNames[1];
- levelMenuInfo.item_maps[1].generic.flags = QMF_LEFT_JUSTIFY;
- levelMenuInfo.item_maps[1].generic.x = 186;
- levelMenuInfo.item_maps[1].generic.y = 64;
- levelMenuInfo.item_maps[1].generic.id = ID_PICTURE1;
- levelMenuInfo.item_maps[1].generic.callback = UI_SPLevelMenu_LevelEvent;
- levelMenuInfo.item_maps[1].width = 128;
- levelMenuInfo.item_maps[1].height = 96;
-
- levelMenuInfo.item_maps[2].generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_maps[2].generic.name = levelMenuInfo.levelPicNames[2];
- levelMenuInfo.item_maps[2].generic.flags = QMF_LEFT_JUSTIFY;
- levelMenuInfo.item_maps[2].generic.x = 326;
- levelMenuInfo.item_maps[2].generic.y = 64;
- levelMenuInfo.item_maps[2].generic.id = ID_PICTURE2;
- levelMenuInfo.item_maps[2].generic.callback = UI_SPLevelMenu_LevelEvent;
- levelMenuInfo.item_maps[2].width = 128;
- levelMenuInfo.item_maps[2].height = 96;
-
- levelMenuInfo.item_maps[3].generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_maps[3].generic.name = levelMenuInfo.levelPicNames[3];
- levelMenuInfo.item_maps[3].generic.flags = QMF_LEFT_JUSTIFY;
- levelMenuInfo.item_maps[3].generic.x = 466;
- levelMenuInfo.item_maps[3].generic.y = 64;
- levelMenuInfo.item_maps[3].generic.id = ID_PICTURE3;
- levelMenuInfo.item_maps[3].generic.callback = UI_SPLevelMenu_LevelEvent;
- levelMenuInfo.item_maps[3].width = 128;
- levelMenuInfo.item_maps[3].height = 96;
-
- levelMenuInfo.item_rightarrow.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_rightarrow.generic.name = ART_ARROW;
- levelMenuInfo.item_rightarrow.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- levelMenuInfo.item_rightarrow.generic.x = 606;
- levelMenuInfo.item_rightarrow.generic.y = 64;
- levelMenuInfo.item_rightarrow.generic.callback = UI_SPLevelMenu_RightArrowEvent;
- levelMenuInfo.item_rightarrow.generic.id = ID_RIGHTARROW;
- levelMenuInfo.item_rightarrow.width = -16;
- levelMenuInfo.item_rightarrow.height = 114;
- levelMenuInfo.item_rightarrow.focuspic = ART_ARROW_FOCUS;
-
- trap_Cvar_VariableStringBuffer( "model", levelMenuInfo.playerModel, sizeof(levelMenuInfo.playerModel) );
- PlayerIcon( levelMenuInfo.playerModel, levelMenuInfo.playerPicName, sizeof(levelMenuInfo.playerPicName) );
- levelMenuInfo.item_player.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_player.generic.name = levelMenuInfo.playerPicName;
- levelMenuInfo.item_player.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY;
- levelMenuInfo.item_player.generic.x = 288;
- levelMenuInfo.item_player.generic.y = AWARDS_Y;
- levelMenuInfo.item_player.generic.id = ID_PLAYERPIC;
- levelMenuInfo.item_player.generic.callback = UI_SPLevelMenu_PlayerEvent;
- levelMenuInfo.item_player.width = 64;
- levelMenuInfo.item_player.height = 64;
-
- for( n = 0; n < 6; n++ ) {
- levelMenuInfo.awardLevels[n] = UI_GetAwardLevel( n );
- }
- levelMenuInfo.awardLevels[AWARD_FRAGS] = 100 * (levelMenuInfo.awardLevels[AWARD_FRAGS] / 100);
-
- y = AWARDS_Y;
- count = 0;
- for( n = 0; n < 6; n++ ) {
- if( levelMenuInfo.awardLevels[n] ) {
- if( count & 1 ) {
- x = 224 - (count - 1 ) / 2 * (48 + 16);
- }
- else {
- x = 368 + count / 2 * (48 + 16);
- }
-
- levelMenuInfo.item_awards[count].generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_awards[count].generic.name = ui_medalPicNames[n];
- levelMenuInfo.item_awards[count].generic.flags = QMF_LEFT_JUSTIFY|QMF_SILENT|QMF_MOUSEONLY;
- levelMenuInfo.item_awards[count].generic.x = x;
- levelMenuInfo.item_awards[count].generic.y = y;
- levelMenuInfo.item_awards[count].generic.id = ID_AWARD1 + n;
- levelMenuInfo.item_awards[count].generic.callback = UI_SPLevelMenu_AwardEvent;
- levelMenuInfo.item_awards[count].width = 48;
- levelMenuInfo.item_awards[count].height = 48;
- count++;
- }
- }
-
- levelMenuInfo.item_back.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_back.generic.name = ART_BACK0;
- levelMenuInfo.item_back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- levelMenuInfo.item_back.generic.x = 0;
- levelMenuInfo.item_back.generic.y = 480-64;
- levelMenuInfo.item_back.generic.callback = UI_SPLevelMenu_BackEvent;
- levelMenuInfo.item_back.generic.id = ID_BACK;
- levelMenuInfo.item_back.width = 128;
- levelMenuInfo.item_back.height = 64;
- levelMenuInfo.item_back.focuspic = ART_BACK1;
-
- levelMenuInfo.item_reset.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_reset.generic.name = ART_RESET0;
- levelMenuInfo.item_reset.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- levelMenuInfo.item_reset.generic.x = 170;
- levelMenuInfo.item_reset.generic.y = 480-64;
- levelMenuInfo.item_reset.generic.callback = UI_SPLevelMenu_ResetEvent;
- levelMenuInfo.item_reset.generic.id = ID_RESET;
- levelMenuInfo.item_reset.width = 128;
- levelMenuInfo.item_reset.height = 64;
- levelMenuInfo.item_reset.focuspic = ART_RESET1;
-
- levelMenuInfo.item_custom.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_custom.generic.name = ART_CUSTOM0;
- levelMenuInfo.item_custom.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- levelMenuInfo.item_custom.generic.x = 342;
- levelMenuInfo.item_custom.generic.y = 480-64;
- levelMenuInfo.item_custom.generic.callback = UI_SPLevelMenu_CustomEvent;
- levelMenuInfo.item_custom.generic.id = ID_CUSTOM;
- levelMenuInfo.item_custom.width = 128;
- levelMenuInfo.item_custom.height = 64;
- levelMenuInfo.item_custom.focuspic = ART_CUSTOM1;
-
- levelMenuInfo.item_next.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_next.generic.name = ART_FIGHT0;
- levelMenuInfo.item_next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- levelMenuInfo.item_next.generic.x = 640;
- levelMenuInfo.item_next.generic.y = 480-64;
- levelMenuInfo.item_next.generic.callback = UI_SPLevelMenu_NextEvent;
- levelMenuInfo.item_next.generic.id = ID_NEXT;
- levelMenuInfo.item_next.width = 128;
- levelMenuInfo.item_next.height = 64;
- levelMenuInfo.item_next.focuspic = ART_FIGHT1;
-
- levelMenuInfo.item_null.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_null.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;
- levelMenuInfo.item_null.generic.x = 0;
- levelMenuInfo.item_null.generic.y = 0;
- levelMenuInfo.item_null.width = 640;
- levelMenuInfo.item_null.height = 480;
-
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_banner );
-
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_leftarrow );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[0] );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[1] );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[2] );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[3] );
- levelMenuInfo.item_maps[0].generic.bottom += 18;
- levelMenuInfo.item_maps[1].generic.bottom += 18;
- levelMenuInfo.item_maps[2].generic.bottom += 18;
- levelMenuInfo.item_maps[3].generic.bottom += 18;
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_rightarrow );
-
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_player );
-
- for( n = 0; n < count; n++ ) {
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_awards[n] );
- }
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_back );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_reset );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_custom );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_next );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_null );
-
- trap_Cvar_VariableStringBuffer( "ui_spSelection", buf, sizeof(buf) );
- if( *buf ) {
- n = atoi( buf );
- selectedArenaSet = n / ARENAS_PER_TIER;
- selectedArena = n % ARENAS_PER_TIER;
- }
- else {
- selectedArenaSet = currentSet;
- selectedArena = currentGame;
- }
-
- UI_SPLevelMenu_SetMenuItems();
-}
-
-
-/*
-=================
-UI_SPLevelMenu
-=================
-*/
-void UI_SPLevelMenu( void ) {
- int level;
- int trainingLevel;
- const char *arenaInfo;
-
- trainingTier = -1;
- arenaInfo = UI_GetSpecialArenaInfo( "training" );
- if( arenaInfo ) {
- minTier = trainingTier;
- trainingLevel = atoi( Info_ValueForKey( arenaInfo, "num" ) );
- }
- else {
- minTier = 0;
- trainingLevel = -2;
- }
-
- finalTier = UI_GetNumSPTiers();
- arenaInfo = UI_GetSpecialArenaInfo( "final" );
- if( arenaInfo ) {
- maxTier = finalTier;
- }
- else {
- maxTier = finalTier - 1;
- if( maxTier < minTier ) {
- maxTier = minTier;
- }
- }
-
- level = UI_GetCurrentGame();
- if ( level == -1 ) {
- level = UI_GetNumSPArenas() - 1;
- if( maxTier == finalTier ) {
- level++;
- }
- }
-
- if( level == trainingLevel ) {
- currentSet = -1;
- currentGame = 0;
- }
- else {
- currentSet = level / ARENAS_PER_TIER;
- currentGame = level % ARENAS_PER_TIER;
- }
-
- UI_SPLevelMenu_Init();
- UI_PushMenu( &levelMenuInfo.menu );
- Menu_SetCursorToItem( &levelMenuInfo.menu, &levelMenuInfo.item_next );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_f
-=================
-*/
-void UI_SPLevelMenu_f( void ) {
- trap_Key_SetCatcher( KEYCATCH_UI );
- uis.menusp = 0;
- UI_SPLevelMenu();
-}
-
-
-/*
-=================
-UI_SPLevelMenu_ReInit
-=================
-*/
-void UI_SPLevelMenu_ReInit( void ) {
- levelMenuInfo.reinit = qtrue;
-}
diff --git a/engine/code/q3_ui/ui_sppostgame.c b/engine/code/q3_ui/ui_sppostgame.c
deleted file mode 100644
index 3b9c246..0000000
--- a/engine/code/q3_ui/ui_sppostgame.c
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=============================================================================
-
-SINGLE PLAYER POSTGAME MENU
-
-=============================================================================
-*/
-
-#include "ui_local.h"
-
-#define MAX_SCOREBOARD_CLIENTS 8
-
-#define AWARD_PRESENTATION_TIME 2000
-
-#define ART_MENU0 "menu/art/menu_0"
-#define ART_MENU1 "menu/art/menu_1"
-#define ART_REPLAY0 "menu/art/replay_0"
-#define ART_REPLAY1 "menu/art/replay_1"
-#define ART_NEXT0 "menu/art/next_0"
-#define ART_NEXT1 "menu/art/next_1"
-
-#define ID_AGAIN 10
-#define ID_NEXT 11
-#define ID_MENU 12
-
-typedef struct {
- menuframework_s menu;
- menubitmap_s item_again;
- menubitmap_s item_next;
- menubitmap_s item_menu;
-
- int phase;
- int ignoreKeysTime;
- int starttime;
- int scoreboardtime;
- int serverId;
-
- int clientNums[MAX_SCOREBOARD_CLIENTS];
- int ranks[MAX_SCOREBOARD_CLIENTS];
- int scores[MAX_SCOREBOARD_CLIENTS];
-
- char placeNames[3][64];
-
- int level;
- int numClients;
- int won;
- int numAwards;
- int awardsEarned[6];
- int awardsLevels[6];
- qboolean playedSound[6];
- int lastTier;
- sfxHandle_t winnerSound;
-} postgameMenuInfo_t;
-
-static postgameMenuInfo_t postgameMenuInfo;
-static char arenainfo[MAX_INFO_VALUE];
-
-char *ui_medalNames[] = {"Accuracy", "Impressive", "Excellent", "Gauntlet", "Frags", "Perfect"};
-char *ui_medalPicNames[] = {
- "menu/medals/medal_accuracy",
- "menu/medals/medal_impressive",
- "menu/medals/medal_excellent",
- "menu/medals/medal_gauntlet",
- "menu/medals/medal_frags",
- "menu/medals/medal_victory"
-};
-char *ui_medalSounds[] = {
- "sound/feedback/accuracy.wav",
- "sound/feedback/impressive_a.wav",
- "sound/feedback/excellent_a.wav",
- "sound/feedback/gauntlet.wav",
- "sound/feedback/frags.wav",
- "sound/feedback/perfect.wav"
-};
-
-
-/*
-=================
-UI_SPPostgameMenu_AgainEvent
-=================
-*/
-static void UI_SPPostgameMenu_AgainEvent( void* ptr, int event )
-{
- if (event != QM_ACTIVATED) {
- return;
- }
- UI_PopMenu();
- trap_Cmd_ExecuteText( EXEC_APPEND, "map_restart 0\n" );
-}
-
-
-/*
-=================
-UI_SPPostgameMenu_NextEvent
-=================
-*/
-static void UI_SPPostgameMenu_NextEvent( void* ptr, int event ) {
- int currentSet;
- int levelSet;
- int level;
- int currentLevel;
- const char *arenaInfo;
-
- if (event != QM_ACTIVATED) {
- return;
- }
- UI_PopMenu();
-
- // handle specially if we just won the training map
- if( postgameMenuInfo.won == 0 ) {
- level = 0;
- }
- else {
- level = postgameMenuInfo.level + 1;
- }
- levelSet = level / ARENAS_PER_TIER;
-
- currentLevel = UI_GetCurrentGame();
- if( currentLevel == -1 ) {
- currentLevel = postgameMenuInfo.level;
- }
- currentSet = currentLevel / ARENAS_PER_TIER;
-
- if( levelSet > currentSet || levelSet == UI_GetNumSPTiers() ) {
- level = currentLevel;
- }
-
- arenaInfo = UI_GetArenaInfoByNumber( level );
- if ( !arenaInfo ) {
- return;
- }
-
- UI_SPArena_Start( arenaInfo );
-}
-
-
-/*
-=================
-UI_SPPostgameMenu_MenuEvent
-=================
-*/
-static void UI_SPPostgameMenu_MenuEvent( void* ptr, int event )
-{
- if (event != QM_ACTIVATED) {
- return;
- }
- UI_PopMenu();
- trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect; levelselect\n" );
-}
-
-
-/*
-=================
-UI_SPPostgameMenu_MenuKey
-=================
-*/
-static sfxHandle_t UI_SPPostgameMenu_MenuKey( int key ) {
- if ( uis.realtime < postgameMenuInfo.ignoreKeysTime ) {
- return 0;
- }
-
- if( postgameMenuInfo.phase == 1 ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "abort_podium\n" );
- postgameMenuInfo.phase = 2;
- postgameMenuInfo.starttime = uis.realtime;
- postgameMenuInfo.ignoreKeysTime = uis.realtime + 250;
- return 0;
- }
-
- if( postgameMenuInfo.phase == 2 ) {
- postgameMenuInfo.phase = 3;
- postgameMenuInfo.starttime = uis.realtime;
- postgameMenuInfo.ignoreKeysTime = uis.realtime + 250;
- return 0;
- }
-
- if( key == K_ESCAPE || key == K_MOUSE2 ) {
- return 0;
- }
-
- return Menu_DefaultKey( &postgameMenuInfo.menu, key );
-}
-
-
-static int medalLocations[6] = {144, 448, 88, 504, 32, 560};
-
-static void UI_SPPostgameMenu_DrawAwardsMedals( int max ) {
- int n;
- int medal;
- int amount;
- int x, y;
- char buf[16];
-
- for( n = 0; n < max; n++ ) {
- x = medalLocations[n];
- y = 64;
- medal = postgameMenuInfo.awardsEarned[n];
- amount = postgameMenuInfo.awardsLevels[n];
-
- UI_DrawNamedPic( x, y, 48, 48, ui_medalPicNames[medal] );
-
- if( medal == AWARD_ACCURACY ) {
- Com_sprintf( buf, sizeof(buf), "%i%%", amount );
- }
- else {
- if( amount == 1 ) {
- continue;
- }
- Com_sprintf( buf, sizeof(buf), "%i", amount );
- }
-
- UI_DrawString( x + 24, y + 52, buf, UI_CENTER, color_yellow );
- }
-}
-
-
-static void UI_SPPostgameMenu_DrawAwardsPresentation( int timer ) {
- int awardNum;
- int atimer;
- vec4_t color;
-
- awardNum = timer / AWARD_PRESENTATION_TIME;
- atimer = timer % AWARD_PRESENTATION_TIME;
-
- color[0] = color[1] = color[2] = 1.0f;
- color[3] = (float)( AWARD_PRESENTATION_TIME - atimer ) / (float)AWARD_PRESENTATION_TIME;
- UI_DrawProportionalString( 320, 64, ui_medalNames[postgameMenuInfo.awardsEarned[awardNum]], UI_CENTER, color );
-
- UI_SPPostgameMenu_DrawAwardsMedals( awardNum + 1 );
-
- if( !postgameMenuInfo.playedSound[awardNum] ) {
- postgameMenuInfo.playedSound[awardNum] = qtrue;
- trap_S_StartLocalSound( trap_S_RegisterSound( ui_medalSounds[postgameMenuInfo.awardsEarned[awardNum]], qfalse ), CHAN_ANNOUNCER );
- }
-}
-
-
-/*
-=================
-UI_SPPostgameMenu_MenuDrawScoreLine
-=================
-*/
-static void UI_SPPostgameMenu_MenuDrawScoreLine( int n, int y ) {
- int rank;
- char name[64];
- char info[MAX_INFO_STRING];
-
- if( n > (postgameMenuInfo.numClients + 1) ) {
- n -= (postgameMenuInfo.numClients + 2);
- }
-
- if( n >= postgameMenuInfo.numClients ) {
- return;
- }
-
- rank = postgameMenuInfo.ranks[n];
- if( rank & RANK_TIED_FLAG ) {
- UI_DrawString( 640 - 31 * SMALLCHAR_WIDTH, y, "(tie)", UI_LEFT|UI_SMALLFONT, color_white );
- rank &= ~RANK_TIED_FLAG;
- }
- trap_GetConfigString( CS_PLAYERS + postgameMenuInfo.clientNums[n], info, MAX_INFO_STRING );
- Q_strncpyz( name, Info_ValueForKey( info, "n" ), sizeof(name) );
- Q_CleanStr( name );
-
- UI_DrawString( 640 - 25 * SMALLCHAR_WIDTH, y, va( "#%i: %-16s %2i", rank + 1, name, postgameMenuInfo.scores[n] ), UI_LEFT|UI_SMALLFONT, color_white );
-}
-
-
-/*
-=================
-UI_SPPostgameMenu_MenuDraw
-=================
-*/
-static void UI_SPPostgameMenu_MenuDraw( void ) {
- int timer;
- int serverId;
- int n;
- char info[MAX_INFO_STRING];
-
- trap_GetConfigString( CS_SYSTEMINFO, info, sizeof(info) );
- serverId = atoi( Info_ValueForKey( info, "sv_serverid" ) );
- if( serverId != postgameMenuInfo.serverId ) {
- UI_PopMenu();
- return;
- }
-
- // phase 1
- if ( postgameMenuInfo.numClients > 2 ) {
- UI_DrawProportionalString( 510, 480 - 64 - PROP_HEIGHT, postgameMenuInfo.placeNames[2], UI_CENTER, color_white );
- }
- UI_DrawProportionalString( 130, 480 - 64 - PROP_HEIGHT, postgameMenuInfo.placeNames[1], UI_CENTER, color_white );
- UI_DrawProportionalString( 320, 480 - 64 - 2 * PROP_HEIGHT, postgameMenuInfo.placeNames[0], UI_CENTER, color_white );
-
- if( postgameMenuInfo.phase == 1 ) {
- timer = uis.realtime - postgameMenuInfo.starttime;
-
- if( timer >= 1000 && postgameMenuInfo.winnerSound ) {
- trap_S_StartLocalSound( postgameMenuInfo.winnerSound, CHAN_ANNOUNCER );
- postgameMenuInfo.winnerSound = 0;
- }
-
- if( timer < 5000 ) {
- return;
- }
- postgameMenuInfo.phase = 2;
- postgameMenuInfo.starttime = uis.realtime;
- }
-
- // phase 2
- if( postgameMenuInfo.phase == 2 ) {
- timer = uis.realtime - postgameMenuInfo.starttime;
- if( timer >= ( postgameMenuInfo.numAwards * AWARD_PRESENTATION_TIME ) ) {
-
- if( timer < 5000 ) {
- return;
- }
-
- postgameMenuInfo.phase = 3;
- postgameMenuInfo.starttime = uis.realtime;
- }
- else {
- UI_SPPostgameMenu_DrawAwardsPresentation( timer );
- }
- }
-
- // phase 3
- if( postgameMenuInfo.phase == 3 ) {
- if( uis.demoversion ) {
- if( postgameMenuInfo.won == 1 && UI_ShowTierVideo( 8 )) {
- trap_Cvar_Set( "nextmap", "" );
- trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect; cinematic demoEnd.RoQ\n" );
- return;
- }
- }
- else if( postgameMenuInfo.won > -1 && UI_ShowTierVideo( postgameMenuInfo.won + 1 )) {
- if( postgameMenuInfo.won == postgameMenuInfo.lastTier ) {
- trap_Cvar_Set( "nextmap", "" );
- trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect; cinematic end.RoQ\n" );
- return;
- }
-
- trap_Cvar_SetValue( "ui_spSelection", postgameMenuInfo.won * ARENAS_PER_TIER );
- trap_Cvar_Set( "nextmap", "levelselect" );
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "disconnect; cinematic tier%i.RoQ\n", postgameMenuInfo.won + 1 ) );
- return;
- }
-
- postgameMenuInfo.item_again.generic.flags &= ~QMF_INACTIVE;
- postgameMenuInfo.item_next.generic.flags &= ~QMF_INACTIVE;
- postgameMenuInfo.item_menu.generic.flags &= ~QMF_INACTIVE;
-
- UI_SPPostgameMenu_DrawAwardsMedals( postgameMenuInfo.numAwards );
-
- Menu_Draw( &postgameMenuInfo.menu );
- }
-
- // draw the scoreboard
- if( !trap_Cvar_VariableValue( "ui_spScoreboard" ) ) {
- return;
- }
-
- timer = uis.realtime - postgameMenuInfo.scoreboardtime;
- if( postgameMenuInfo.numClients <= 3 ) {
- n = 0;
- }
- else {
- n = timer / 1500 % (postgameMenuInfo.numClients + 2);
- }
- UI_SPPostgameMenu_MenuDrawScoreLine( n, 0 );
- UI_SPPostgameMenu_MenuDrawScoreLine( n + 1, 0 + SMALLCHAR_HEIGHT );
- UI_SPPostgameMenu_MenuDrawScoreLine( n + 2, 0 + 2 * SMALLCHAR_HEIGHT );
-}
-
-
-/*
-=================
-UI_SPPostgameMenu_Cache
-=================
-*/
-void UI_SPPostgameMenu_Cache( void ) {
- int n;
- qboolean buildscript;
-
- buildscript = trap_Cvar_VariableValue("com_buildscript");
-
- trap_R_RegisterShaderNoMip( ART_MENU0 );
- trap_R_RegisterShaderNoMip( ART_MENU1 );
- trap_R_RegisterShaderNoMip( ART_REPLAY0 );
- trap_R_RegisterShaderNoMip( ART_REPLAY1 );
- trap_R_RegisterShaderNoMip( ART_NEXT0 );
- trap_R_RegisterShaderNoMip( ART_NEXT1 );
- for( n = 0; n < 6; n++ ) {
- trap_R_RegisterShaderNoMip( ui_medalPicNames[n] );
- trap_S_RegisterSound( ui_medalSounds[n], qfalse );
- }
-
- if( buildscript ) {
- trap_S_RegisterSound( "music/loss.wav", qfalse );
- trap_S_RegisterSound( "music/win.wav", qfalse );
- trap_S_RegisterSound( "sound/player/announce/youwin.wav", qfalse );
- }
-}
-
-
-/*
-=================
-UI_SPPostgameMenu_Init
-=================
-*/
-static void UI_SPPostgameMenu_Init( void ) {
- postgameMenuInfo.menu.wrapAround = qtrue;
- postgameMenuInfo.menu.key = UI_SPPostgameMenu_MenuKey;
- postgameMenuInfo.menu.draw = UI_SPPostgameMenu_MenuDraw;
- postgameMenuInfo.ignoreKeysTime = uis.realtime + 1500;
-
- UI_SPPostgameMenu_Cache();
-
- postgameMenuInfo.item_menu.generic.type = MTYPE_BITMAP;
- postgameMenuInfo.item_menu.generic.name = ART_MENU0;
- postgameMenuInfo.item_menu.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE;
- postgameMenuInfo.item_menu.generic.x = 0;
- postgameMenuInfo.item_menu.generic.y = 480-64;
- postgameMenuInfo.item_menu.generic.callback = UI_SPPostgameMenu_MenuEvent;
- postgameMenuInfo.item_menu.generic.id = ID_MENU;
- postgameMenuInfo.item_menu.width = 128;
- postgameMenuInfo.item_menu.height = 64;
- postgameMenuInfo.item_menu.focuspic = ART_MENU1;
-
- postgameMenuInfo.item_again.generic.type = MTYPE_BITMAP;
- postgameMenuInfo.item_again.generic.name = ART_REPLAY0;
- postgameMenuInfo.item_again.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE;
- postgameMenuInfo.item_again.generic.x = 320;
- postgameMenuInfo.item_again.generic.y = 480-64;
- postgameMenuInfo.item_again.generic.callback = UI_SPPostgameMenu_AgainEvent;
- postgameMenuInfo.item_again.generic.id = ID_AGAIN;
- postgameMenuInfo.item_again.width = 128;
- postgameMenuInfo.item_again.height = 64;
- postgameMenuInfo.item_again.focuspic = ART_REPLAY1;
-
- postgameMenuInfo.item_next.generic.type = MTYPE_BITMAP;
- postgameMenuInfo.item_next.generic.name = ART_NEXT0;
- postgameMenuInfo.item_next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE;
- postgameMenuInfo.item_next.generic.x = 640;
- postgameMenuInfo.item_next.generic.y = 480-64;
- postgameMenuInfo.item_next.generic.callback = UI_SPPostgameMenu_NextEvent;
- postgameMenuInfo.item_next.generic.id = ID_NEXT;
- postgameMenuInfo.item_next.width = 128;
- postgameMenuInfo.item_next.height = 64;
- postgameMenuInfo.item_next.focuspic = ART_NEXT1;
-
- Menu_AddItem( &postgameMenuInfo.menu, ( void * )&postgameMenuInfo.item_menu );
- Menu_AddItem( &postgameMenuInfo.menu, ( void * )&postgameMenuInfo.item_again );
- Menu_AddItem( &postgameMenuInfo.menu, ( void * )&postgameMenuInfo.item_next );
-}
-
-
-static void Prepname( int index ) {
- int len;
- char name[64];
- char info[MAX_INFO_STRING];
-
- trap_GetConfigString( CS_PLAYERS + postgameMenuInfo.clientNums[index], info, MAX_INFO_STRING );
- Q_strncpyz( name, Info_ValueForKey( info, "n" ), sizeof(name) );
- Q_CleanStr( name );
- len = strlen( name );
-
- while( len && UI_ProportionalStringWidth( name ) > 256 ) {
- len--;
- name[len] = 0;
- }
-
- Q_strncpyz( postgameMenuInfo.placeNames[index], name, sizeof(postgameMenuInfo.placeNames[index]) );
-}
-
-
-/*
-=================
-UI_SPPostgameMenu_f
-=================
-*/
-void UI_SPPostgameMenu_f( void ) {
- int playerGameRank;
- int playerClientNum;
- int n;
- int oldFrags, newFrags;
- const char *arena;
- int awardValues[6];
- char map[MAX_QPATH];
- char info[MAX_INFO_STRING];
-
- memset( &postgameMenuInfo, 0, sizeof(postgameMenuInfo) );
-
- trap_GetConfigString( CS_SYSTEMINFO, info, sizeof(info) );
- postgameMenuInfo.serverId = atoi( Info_ValueForKey( info, "sv_serverid" ) );
-
- trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
- Q_strncpyz( map, Info_ValueForKey( info, "mapname" ), sizeof(map) );
- arena = UI_GetArenaInfoByMap( map );
- if ( !arena ) {
- return;
- }
- Q_strncpyz( arenainfo, arena, sizeof(arenainfo) );
-
- postgameMenuInfo.level = atoi( Info_ValueForKey( arenainfo, "num" ) );
-
- postgameMenuInfo.numClients = atoi( UI_Argv( 1 ) );
- playerClientNum = atoi( UI_Argv( 2 ) );
- playerGameRank = 8; // in case they ended game as a spectator
-
- if( postgameMenuInfo.numClients > MAX_SCOREBOARD_CLIENTS ) {
- postgameMenuInfo.numClients = MAX_SCOREBOARD_CLIENTS;
- }
-
- for( n = 0; n < postgameMenuInfo.numClients; n++ ) {
- postgameMenuInfo.clientNums[n] = atoi( UI_Argv( 8 + n * 3 + 1 ) );
- postgameMenuInfo.ranks[n] = atoi( UI_Argv( 8 + n * 3 + 2 ) );
- postgameMenuInfo.scores[n] = atoi( UI_Argv( 8 + n * 3 + 3 ) );
-
- if( postgameMenuInfo.clientNums[n] == playerClientNum ) {
- playerGameRank = (postgameMenuInfo.ranks[n] & ~RANK_TIED_FLAG) + 1;
- }
- }
-
- UI_SetBestScore( postgameMenuInfo.level, playerGameRank );
-
- // process award stats and prepare presentation data
- awardValues[AWARD_ACCURACY] = atoi( UI_Argv( 3 ) );
- awardValues[AWARD_IMPRESSIVE] = atoi( UI_Argv( 4 ) );
- awardValues[AWARD_EXCELLENT] = atoi( UI_Argv( 5 ) );
- awardValues[AWARD_GAUNTLET] = atoi( UI_Argv( 6 ) );
- awardValues[AWARD_FRAGS] = atoi( UI_Argv( 7 ) );
- awardValues[AWARD_PERFECT] = atoi( UI_Argv( 8 ) );
-
- postgameMenuInfo.numAwards = 0;
-
- if( awardValues[AWARD_ACCURACY] >= 50 ) {
- UI_LogAwardData( AWARD_ACCURACY, 1 );
- postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_ACCURACY;
- postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_ACCURACY];
- postgameMenuInfo.numAwards++;
- }
-
- if( awardValues[AWARD_IMPRESSIVE] ) {
- UI_LogAwardData( AWARD_IMPRESSIVE, awardValues[AWARD_IMPRESSIVE] );
- postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_IMPRESSIVE;
- postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_IMPRESSIVE];
- postgameMenuInfo.numAwards++;
- }
-
- if( awardValues[AWARD_EXCELLENT] ) {
- UI_LogAwardData( AWARD_EXCELLENT, awardValues[AWARD_EXCELLENT] );
- postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_EXCELLENT;
- postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_EXCELLENT];
- postgameMenuInfo.numAwards++;
- }
-
- if( awardValues[AWARD_GAUNTLET] ) {
- UI_LogAwardData( AWARD_GAUNTLET, awardValues[AWARD_GAUNTLET] );
- postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_GAUNTLET;
- postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_GAUNTLET];
- postgameMenuInfo.numAwards++;
- }
-
- oldFrags = UI_GetAwardLevel( AWARD_FRAGS ) / 100;
- UI_LogAwardData( AWARD_FRAGS, awardValues[AWARD_FRAGS] );
- newFrags = UI_GetAwardLevel( AWARD_FRAGS ) / 100;
- if( newFrags > oldFrags ) {
- postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_FRAGS;
- postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = newFrags * 100;
- postgameMenuInfo.numAwards++;
- }
-
- if( awardValues[AWARD_PERFECT] ) {
- UI_LogAwardData( AWARD_PERFECT, 1 );
- postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_PERFECT;
- postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = 1;
- postgameMenuInfo.numAwards++;
- }
-
- if ( playerGameRank == 1 ) {
- postgameMenuInfo.won = UI_TierCompleted( postgameMenuInfo.level );
- }
- else {
- postgameMenuInfo.won = -1;
- }
-
- postgameMenuInfo.starttime = uis.realtime;
- postgameMenuInfo.scoreboardtime = uis.realtime;
-
- trap_Key_SetCatcher( KEYCATCH_UI );
- uis.menusp = 0;
-
- UI_SPPostgameMenu_Init();
- UI_PushMenu( &postgameMenuInfo.menu );
-
- if ( playerGameRank == 1 ) {
- Menu_SetCursorToItem( &postgameMenuInfo.menu, &postgameMenuInfo.item_next );
- }
- else {
- Menu_SetCursorToItem( &postgameMenuInfo.menu, &postgameMenuInfo.item_again );
- }
-
- Prepname( 0 );
- Prepname( 1 );
- Prepname( 2 );
-
- if ( playerGameRank != 1 ) {
- postgameMenuInfo.winnerSound = trap_S_RegisterSound( va( "sound/player/announce/%s_wins.wav", postgameMenuInfo.placeNames[0] ), qfalse );
- trap_Cmd_ExecuteText( EXEC_APPEND, "music music/loss\n" );
- }
- else {
- postgameMenuInfo.winnerSound = trap_S_RegisterSound( "sound/player/announce/youwin.wav", qfalse );
- trap_Cmd_ExecuteText( EXEC_APPEND, "music music/win\n" );
- }
-
- postgameMenuInfo.phase = 1;
-
- postgameMenuInfo.lastTier = UI_GetNumSPTiers();
- if ( UI_GetSpecialArenaInfo( "final" ) ) {
- postgameMenuInfo.lastTier++;
- }
-}
diff --git a/engine/code/q3_ui/ui_spreset.c b/engine/code/q3_ui/ui_spreset.c
deleted file mode 100644
index 35deb7c..0000000
--- a/engine/code/q3_ui/ui_spreset.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-/*
-=======================================================================
-
-RESET MENU
-
-=======================================================================
-*/
-
-#include "ui_local.h"
-
-
-#define ART_FRAME "menu/art/cut_frame"
-
-#define ID_NO 100
-#define ID_YES 101
-
-typedef struct
-{
- menuframework_s menu;
- menutext_s no;
- menutext_s yes;
- int slashX;
-} resetMenu_t;
-
-static resetMenu_t s_reset;
-
-
-/*
-=================
-Reset_MenuEvent
-=================
-*/
-void Reset_MenuEvent(void* ptr, int event) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- UI_PopMenu();
-
- if( ((menucommon_s*)ptr)->id == ID_NO ) {
- return;
- }
-
- // reset the game, pop the level menu and restart it so it updates
- UI_NewGame();
- trap_Cvar_SetValue( "ui_spSelection", 0 );
- UI_PopMenu();
- UI_SPLevelMenu();
-}
-
-
-/*
-=================
-Reset_MenuKey
-=================
-*/
-static sfxHandle_t Reset_MenuKey( int key ) {
- switch ( key ) {
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- key = K_TAB;
- break;
-
- case 'n':
- case 'N':
- Reset_MenuEvent( &s_reset.no, QM_ACTIVATED );
- break;
-
- case 'y':
- case 'Y':
- Reset_MenuEvent( &s_reset.yes, QM_ACTIVATED );
- break;
- }
-
- return Menu_DefaultKey( &s_reset.menu, key );
-}
-
-
-/*
-=================
-Reset_MenuDraw
-=================
-*/
-static void Reset_MenuDraw( void ) {
- UI_DrawNamedPic( 142, 118, 359, 256, ART_FRAME );
- UI_DrawProportionalString( 320, 194 + 10, "RESET GAME?", UI_CENTER|UI_INVERSE, color_red );
- UI_DrawProportionalString( s_reset.slashX, 265, "/", UI_LEFT|UI_INVERSE, color_red );
- Menu_Draw( &s_reset.menu );
-
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, "WARNING: This resets all of the", UI_CENTER|UI_SMALLFONT, color_yellow );
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, "single player game variables.", UI_CENTER|UI_SMALLFONT, color_yellow );
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 2, "Do this only if you want to", UI_CENTER|UI_SMALLFONT, color_yellow );
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 3, "start over from the beginning.", UI_CENTER|UI_SMALLFONT, color_yellow );
-}
-
-
-/*
-=================
-Reset_Cache
-=================
-*/
-void Reset_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_FRAME );
-}
-
-
-/*
-=================
-UI_ResetMenu
-=================
-*/
-void UI_ResetMenu(void) {
- uiClientState_t cstate;
- int n1, n2, n3;
- int l1, l2, l3;
-
- // zero set all our globals
- memset( &s_reset, 0, sizeof(s_reset) );
-
- Reset_Cache();
-
- n1 = UI_ProportionalStringWidth( "YES/NO" );
- n2 = UI_ProportionalStringWidth( "YES" ) + PROP_GAP_WIDTH;
- n3 = UI_ProportionalStringWidth( "/" ) + PROP_GAP_WIDTH;
- l1 = 320 - ( n1 / 2 );
- l2 = l1 + n2;
- l3 = l2 + n3;
- s_reset.slashX = l2;
-
- s_reset.menu.draw = Reset_MenuDraw;
- s_reset.menu.key = Reset_MenuKey;
- s_reset.menu.wrapAround = qtrue;
-
- trap_GetClientState( &cstate );
-
- if ( cstate.connState >= CA_CONNECTED ) {
- // float on top of running game
- s_reset.menu.fullscreen = qfalse;
- }
- else {
- // game not running
- s_reset.menu.fullscreen = qtrue;
- }
-
- s_reset.yes.generic.type = MTYPE_PTEXT;
- s_reset.yes.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_reset.yes.generic.callback = Reset_MenuEvent;
- s_reset.yes.generic.id = ID_YES;
- s_reset.yes.generic.x = l1;
- s_reset.yes.generic.y = 264;
- s_reset.yes.string = "YES";
- s_reset.yes.color = color_red;
- s_reset.yes.style = UI_LEFT;
-
- s_reset.no.generic.type = MTYPE_PTEXT;
- s_reset.no.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_reset.no.generic.callback = Reset_MenuEvent;
- s_reset.no.generic.id = ID_NO;
- s_reset.no.generic.x = l3;
- s_reset.no.generic.y = 264;
- s_reset.no.string = "NO";
- s_reset.no.color = color_red;
- s_reset.no.style = UI_LEFT;
-
- Menu_AddItem( &s_reset.menu, &s_reset.yes );
- Menu_AddItem( &s_reset.menu, &s_reset.no );
-
- UI_PushMenu( &s_reset.menu );
-
- Menu_SetCursorToItem( &s_reset.menu, &s_reset.no );
-}
diff --git a/engine/code/q3_ui/ui_spskill.c b/engine/code/q3_ui/ui_spskill.c
deleted file mode 100644
index 7ae70d8..0000000
--- a/engine/code/q3_ui/ui_spskill.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=============================================================================
-
-SINGLE PLAYER SKILL MENU
-
-=============================================================================
-*/
-
-#include "ui_local.h"
-
-
-#define ART_FRAME "menu/art/cut_frame"
-#define ART_BACK "menu/art/back_0.tga"
-#define ART_BACK_FOCUS "menu/art/back_1.tga"
-#define ART_FIGHT "menu/art/fight_0"
-#define ART_FIGHT_FOCUS "menu/art/fight_1"
-#define ART_MAP_COMPLETE1 "menu/art/level_complete1"
-#define ART_MAP_COMPLETE2 "menu/art/level_complete2"
-#define ART_MAP_COMPLETE3 "menu/art/level_complete3"
-#define ART_MAP_COMPLETE4 "menu/art/level_complete4"
-#define ART_MAP_COMPLETE5 "menu/art/level_complete5"
-
-#define ID_BABY 10
-#define ID_EASY 11
-#define ID_MEDIUM 12
-#define ID_HARD 13
-#define ID_NIGHTMARE 14
-#define ID_BACK 15
-#define ID_FIGHT 16
-
-
-typedef struct {
- menuframework_s menu;
-
- menubitmap_s art_frame;
- menutext_s art_banner;
-
- menutext_s item_baby;
- menutext_s item_easy;
- menutext_s item_medium;
- menutext_s item_hard;
- menutext_s item_nightmare;
-
- menubitmap_s art_skillPic;
- menubitmap_s item_back;
- menubitmap_s item_fight;
-
- const char *arenaInfo;
- qhandle_t skillpics[5];
- sfxHandle_t nightmareSound;
- sfxHandle_t silenceSound;
-} skillMenuInfo_t;
-
-static skillMenuInfo_t skillMenuInfo;
-
-
-static void SetSkillColor( int skill, vec4_t color ) {
- switch( skill ) {
- case 1:
- skillMenuInfo.item_baby.color = color;
- break;
- case 2:
- skillMenuInfo.item_easy.color = color;
- break;
- case 3:
- skillMenuInfo.item_medium.color = color;
- break;
- case 4:
- skillMenuInfo.item_hard.color = color;
- break;
- case 5:
- skillMenuInfo.item_nightmare.color = color;
- break;
- default:
- break;
- }
-}
-
-
-/*
-=================
-UI_SPSkillMenu_SkillEvent
-=================
-*/
-static void UI_SPSkillMenu_SkillEvent( void *ptr, int notification ) {
- int id;
- int skill;
-
- if (notification != QM_ACTIVATED)
- return;
-
- SetSkillColor( (int)trap_Cvar_VariableValue( "g_spSkill" ), color_red );
-
- id = ((menucommon_s*)ptr)->id;
- skill = id - ID_BABY + 1;
- trap_Cvar_SetValue( "g_spSkill", skill );
-
- SetSkillColor( skill, color_white );
- skillMenuInfo.art_skillPic.shader = skillMenuInfo.skillpics[skill - 1];
-
- if( id == ID_NIGHTMARE ) {
- trap_S_StartLocalSound( skillMenuInfo.nightmareSound, CHAN_ANNOUNCER );
- }
- else {
- trap_S_StartLocalSound( skillMenuInfo.silenceSound, CHAN_ANNOUNCER );
- }
-}
-
-
-/*
-=================
-UI_SPSkillMenu_FightEvent
-=================
-*/
-static void UI_SPSkillMenu_FightEvent( void *ptr, int notification ) {
- if (notification != QM_ACTIVATED)
- return;
-
- UI_SPArena_Start( skillMenuInfo.arenaInfo );
-}
-
-
-/*
-=================
-UI_SPSkillMenu_BackEvent
-=================
-*/
-static void UI_SPSkillMenu_BackEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- trap_S_StartLocalSound( skillMenuInfo.silenceSound, CHAN_ANNOUNCER );
- UI_PopMenu();
-}
-
-
-/*
-=================
-UI_SPSkillMenu_Key
-=================
-*/
-static sfxHandle_t UI_SPSkillMenu_Key( int key ) {
- if( key == K_MOUSE2 || key == K_ESCAPE ) {
- trap_S_StartLocalSound( skillMenuInfo.silenceSound, CHAN_ANNOUNCER );
- }
- return Menu_DefaultKey( &skillMenuInfo.menu, key );
-}
-
-
-/*
-=================
-UI_SPSkillMenu_Cache
-=================
-*/
-void UI_SPSkillMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_FRAME );
- trap_R_RegisterShaderNoMip( ART_BACK );
- trap_R_RegisterShaderNoMip( ART_BACK_FOCUS );
- trap_R_RegisterShaderNoMip( ART_FIGHT );
- trap_R_RegisterShaderNoMip( ART_FIGHT_FOCUS );
- skillMenuInfo.skillpics[0] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE1 );
- skillMenuInfo.skillpics[1] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE2 );
- skillMenuInfo.skillpics[2] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE3 );
- skillMenuInfo.skillpics[3] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE4 );
- skillMenuInfo.skillpics[4] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE5 );
-
- skillMenuInfo.nightmareSound = trap_S_RegisterSound( "sound/misc/nightmare.wav", qfalse );
- skillMenuInfo.silenceSound = trap_S_RegisterSound( "sound/misc/silence.wav", qfalse );
-}
-
-
-/*
-=================
-UI_SPSkillMenu_Init
-=================
-*/
-static void UI_SPSkillMenu_Init( void ) {
- int skill;
-
- memset( &skillMenuInfo, 0, sizeof(skillMenuInfo) );
- skillMenuInfo.menu.fullscreen = qtrue;
- skillMenuInfo.menu.key = UI_SPSkillMenu_Key;
-
- UI_SPSkillMenu_Cache();
-
- skillMenuInfo.art_frame.generic.type = MTYPE_BITMAP;
- skillMenuInfo.art_frame.generic.name = ART_FRAME;
- skillMenuInfo.art_frame.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- skillMenuInfo.art_frame.generic.x = 142;
- skillMenuInfo.art_frame.generic.y = 118;
- skillMenuInfo.art_frame.width = 359;
- skillMenuInfo.art_frame.height = 256;
-
- skillMenuInfo.art_banner.generic.type = MTYPE_BTEXT;
- skillMenuInfo.art_banner.generic.flags = QMF_CENTER_JUSTIFY;
- skillMenuInfo.art_banner.generic.x = 320;
- skillMenuInfo.art_banner.generic.y = 16;
- skillMenuInfo.art_banner.string = "DIFFICULTY";
- skillMenuInfo.art_banner.color = color_white;
- skillMenuInfo.art_banner.style = UI_CENTER;
-
- skillMenuInfo.item_baby.generic.type = MTYPE_PTEXT;
- skillMenuInfo.item_baby.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- skillMenuInfo.item_baby.generic.x = 320;
- skillMenuInfo.item_baby.generic.y = 170;
- skillMenuInfo.item_baby.generic.callback = UI_SPSkillMenu_SkillEvent;
- skillMenuInfo.item_baby.generic.id = ID_BABY;
- skillMenuInfo.item_baby.string = "I Can Win";
- skillMenuInfo.item_baby.color = color_red;
- skillMenuInfo.item_baby.style = UI_CENTER;
-
- skillMenuInfo.item_easy.generic.type = MTYPE_PTEXT;
- skillMenuInfo.item_easy.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- skillMenuInfo.item_easy.generic.x = 320;
- skillMenuInfo.item_easy.generic.y = 198;
- skillMenuInfo.item_easy.generic.callback = UI_SPSkillMenu_SkillEvent;
- skillMenuInfo.item_easy.generic.id = ID_EASY;
- skillMenuInfo.item_easy.string = "Bring It On";
- skillMenuInfo.item_easy.color = color_red;
- skillMenuInfo.item_easy.style = UI_CENTER;
-
- skillMenuInfo.item_medium.generic.type = MTYPE_PTEXT;
- skillMenuInfo.item_medium.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- skillMenuInfo.item_medium.generic.x = 320;
- skillMenuInfo.item_medium.generic.y = 227;
- skillMenuInfo.item_medium.generic.callback = UI_SPSkillMenu_SkillEvent;
- skillMenuInfo.item_medium.generic.id = ID_MEDIUM;
- skillMenuInfo.item_medium.string = "Hurt Me Plenty";
- skillMenuInfo.item_medium.color = color_red;
- skillMenuInfo.item_medium.style = UI_CENTER;
-
- skillMenuInfo.item_hard.generic.type = MTYPE_PTEXT;
- skillMenuInfo.item_hard.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- skillMenuInfo.item_hard.generic.x = 320;
- skillMenuInfo.item_hard.generic.y = 255;
- skillMenuInfo.item_hard.generic.callback = UI_SPSkillMenu_SkillEvent;
- skillMenuInfo.item_hard.generic.id = ID_HARD;
- skillMenuInfo.item_hard.string = "Hardcore";
- skillMenuInfo.item_hard.color = color_red;
- skillMenuInfo.item_hard.style = UI_CENTER;
-
- skillMenuInfo.item_nightmare.generic.type = MTYPE_PTEXT;
- skillMenuInfo.item_nightmare.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- skillMenuInfo.item_nightmare.generic.x = 320;
- skillMenuInfo.item_nightmare.generic.y = 283;
- skillMenuInfo.item_nightmare.generic.callback = UI_SPSkillMenu_SkillEvent;
- skillMenuInfo.item_nightmare.generic.id = ID_NIGHTMARE;
- skillMenuInfo.item_nightmare.string = "NIGHTMARE!";
- skillMenuInfo.item_nightmare.color = color_red;
- skillMenuInfo.item_nightmare.style = UI_CENTER;
-
- skillMenuInfo.item_back.generic.type = MTYPE_BITMAP;
- skillMenuInfo.item_back.generic.name = ART_BACK;
- skillMenuInfo.item_back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- skillMenuInfo.item_back.generic.x = 0;
- skillMenuInfo.item_back.generic.y = 480-64;
- skillMenuInfo.item_back.generic.callback = UI_SPSkillMenu_BackEvent;
- skillMenuInfo.item_back.generic.id = ID_BACK;
- skillMenuInfo.item_back.width = 128;
- skillMenuInfo.item_back.height = 64;
- skillMenuInfo.item_back.focuspic = ART_BACK_FOCUS;
-
- skillMenuInfo.art_skillPic.generic.type = MTYPE_BITMAP;
- skillMenuInfo.art_skillPic.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- skillMenuInfo.art_skillPic.generic.x = 320-64;
- skillMenuInfo.art_skillPic.generic.y = 368;
- skillMenuInfo.art_skillPic.width = 128;
- skillMenuInfo.art_skillPic.height = 96;
-
- skillMenuInfo.item_fight.generic.type = MTYPE_BITMAP;
- skillMenuInfo.item_fight.generic.name = ART_FIGHT;
- skillMenuInfo.item_fight.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- skillMenuInfo.item_fight.generic.callback = UI_SPSkillMenu_FightEvent;
- skillMenuInfo.item_fight.generic.id = ID_FIGHT;
- skillMenuInfo.item_fight.generic.x = 640;
- skillMenuInfo.item_fight.generic.y = 480-64;
- skillMenuInfo.item_fight.width = 128;
- skillMenuInfo.item_fight.height = 64;
- skillMenuInfo.item_fight.focuspic = ART_FIGHT_FOCUS;
-
- Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.art_frame );
- Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.art_banner );
- Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_baby );
- Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_easy );
- Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_medium );
- Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_hard );
- Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_nightmare );
- Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.art_skillPic );
- Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_back );
- Menu_AddItem( &skillMenuInfo.menu, ( void * )&skillMenuInfo.item_fight );
-
- skill = (int)Com_Clamp( 1, 5, trap_Cvar_VariableValue( "g_spSkill" ) );
- SetSkillColor( skill, color_white );
- skillMenuInfo.art_skillPic.shader = skillMenuInfo.skillpics[skill - 1];
- if( skill == 5 ) {
- trap_S_StartLocalSound( skillMenuInfo.nightmareSound, CHAN_ANNOUNCER );
- }
-}
-
-
-void UI_SPSkillMenu( const char *arenaInfo ) {
- UI_SPSkillMenu_Init();
- skillMenuInfo.arenaInfo = arenaInfo;
- UI_PushMenu( &skillMenuInfo.menu );
- Menu_SetCursorToItem( &skillMenuInfo.menu, &skillMenuInfo.item_fight );
-}
diff --git a/engine/code/q3_ui/ui_startserver.c b/engine/code/q3_ui/ui_startserver.c
deleted file mode 100644
index b249e0f..0000000
--- a/engine/code/q3_ui/ui_startserver.c
+++ /dev/null
@@ -1,1976 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=============================================================================
-
-START SERVER MENU *****
-
-=============================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define GAMESERVER_BACK0 "menu/art/back_0"
-#define GAMESERVER_BACK1 "menu/art/back_1"
-#define GAMESERVER_NEXT0 "menu/art/next_0"
-#define GAMESERVER_NEXT1 "menu/art/next_1"
-#define GAMESERVER_FRAMEL "menu/art/frame2_l"
-#define GAMESERVER_FRAMER "menu/art/frame1_r"
-#define GAMESERVER_SELECT "menu/art/maps_select"
-#define GAMESERVER_SELECTED "menu/art/maps_selected"
-#define GAMESERVER_FIGHT0 "menu/art/fight_0"
-#define GAMESERVER_FIGHT1 "menu/art/fight_1"
-#define GAMESERVER_UNKNOWNMAP "menu/art/unknownmap"
-#define GAMESERVER_ARROWS "menu/art/gs_arrows_0"
-#define GAMESERVER_ARROWSL "menu/art/gs_arrows_l"
-#define GAMESERVER_ARROWSR "menu/art/gs_arrows_r"
-
-#define MAX_MAPROWS 2
-#define MAX_MAPCOLS 2
-#define MAX_MAPSPERPAGE 4
-
-#define MAX_NAMELENGTH 16
-#define ID_GAMETYPE 10
-#define ID_PICTURES 11 // 12, 13, 14
-#define ID_PREVPAGE 15
-#define ID_NEXTPAGE 16
-#define ID_STARTSERVERBACK 17
-#define ID_STARTSERVERNEXT 18
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menulist_s gametype;
- menubitmap_s mappics[MAX_MAPSPERPAGE];
- menubitmap_s mapbuttons[MAX_MAPSPERPAGE];
- menubitmap_s arrows;
- menubitmap_s prevpage;
- menubitmap_s nextpage;
- menubitmap_s back;
- menubitmap_s next;
-
- menutext_s mapname;
- menubitmap_s item_null;
-
- qboolean multiplayer;
- int currentmap;
- int nummaps;
- int page;
- int maxpages;
- int maplist[MAX_ARENAS];
-} startserver_t;
-
-static startserver_t s_startserver;
-
-static const char *gametype_items[] = {
- "Free For All",
- "Team Deathmatch",
- "Tournament",
- "Capture the Flag",
- NULL
-};
-
-static int gametype_remap[] = {GT_FFA, GT_TEAM, GT_TOURNAMENT, GT_CTF};
-static int gametype_remap2[] = {0, 2, 0, 1, 3};
-
-// use ui_servers2.c definition
-extern const char* punkbuster_items[];
-
-static void UI_ServerOptionsMenu( qboolean multiplayer );
-
-
-/*
-=================
-GametypeBits
-=================
-*/
-static int GametypeBits( char *string ) {
- int bits;
- char *p;
- char *token;
-
- bits = 0;
- p = string;
- while( 1 ) {
- token = COM_ParseExt( &p, qfalse );
- if( token[0] == 0 ) {
- break;
- }
-
- if( Q_stricmp( token, "ffa" ) == 0 ) {
- bits |= 1 << GT_FFA;
- continue;
- }
-
- if( Q_stricmp( token, "tourney" ) == 0 ) {
- bits |= 1 << GT_TOURNAMENT;
- continue;
- }
-
- if( Q_stricmp( token, "single" ) == 0 ) {
- bits |= 1 << GT_SINGLE_PLAYER;
- continue;
- }
-
- if( Q_stricmp( token, "team" ) == 0 ) {
- bits |= 1 << GT_TEAM;
- continue;
- }
-
- if( Q_stricmp( token, "ctf" ) == 0 ) {
- bits |= 1 << GT_CTF;
- continue;
- }
- }
-
- return bits;
-}
-
-
-/*
-=================
-StartServer_Update
-=================
-*/
-static void StartServer_Update( void ) {
- int i;
- int top;
- static char picname[MAX_MAPSPERPAGE][64];
- const char *info;
- char mapname[MAX_NAMELENGTH];
-
- top = s_startserver.page*MAX_MAPSPERPAGE;
-
- for (i=0; i<MAX_MAPSPERPAGE; i++)
- {
- if (top+i >= s_startserver.nummaps)
- break;
-
- info = UI_GetArenaInfoByNumber( s_startserver.maplist[ top + i ]);
- Q_strncpyz( mapname, Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
- Q_strupr( mapname );
-
- Com_sprintf( picname[i], sizeof(picname[i]), "levelshots/%s", mapname );
-
- s_startserver.mappics[i].generic.flags &= ~QMF_HIGHLIGHT;
- s_startserver.mappics[i].generic.name = picname[i];
- s_startserver.mappics[i].shader = 0;
-
- // reset
- s_startserver.mapbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
- s_startserver.mapbuttons[i].generic.flags &= ~QMF_INACTIVE;
- }
-
- for (; i<MAX_MAPSPERPAGE; i++)
- {
- s_startserver.mappics[i].generic.flags &= ~QMF_HIGHLIGHT;
- s_startserver.mappics[i].generic.name = NULL;
- s_startserver.mappics[i].shader = 0;
-
- // disable
- s_startserver.mapbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
- s_startserver.mapbuttons[i].generic.flags |= QMF_INACTIVE;
- }
-
-
- // no servers to start
- if( !s_startserver.nummaps ) {
- s_startserver.next.generic.flags |= QMF_INACTIVE;
-
- // set the map name
- strcpy( s_startserver.mapname.string, "NO MAPS FOUND" );
- }
- else {
- // set the highlight
- s_startserver.next.generic.flags &= ~QMF_INACTIVE;
- i = s_startserver.currentmap - top;
- if ( i >=0 && i < MAX_MAPSPERPAGE )
- {
- s_startserver.mappics[i].generic.flags |= QMF_HIGHLIGHT;
- s_startserver.mapbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
- }
-
- // set the map name
- info = UI_GetArenaInfoByNumber( s_startserver.maplist[ s_startserver.currentmap ]);
- Q_strncpyz( s_startserver.mapname.string, Info_ValueForKey( info, "map" ), MAX_NAMELENGTH);
- }
-
- Q_strupr( s_startserver.mapname.string );
-}
-
-
-/*
-=================
-StartServer_MapEvent
-=================
-*/
-static void StartServer_MapEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED) {
- return;
- }
-
- s_startserver.currentmap = (s_startserver.page*MAX_MAPSPERPAGE) + (((menucommon_s*)ptr)->id - ID_PICTURES);
- StartServer_Update();
-}
-
-
-/*
-=================
-StartServer_GametypeEvent
-=================
-*/
-static void StartServer_GametypeEvent( void* ptr, int event ) {
- int i;
- int count;
- int gamebits;
- int matchbits;
- const char *info;
-
- if( event != QM_ACTIVATED) {
- return;
- }
-
- count = UI_GetNumArenas();
- s_startserver.nummaps = 0;
- matchbits = 1 << gametype_remap[s_startserver.gametype.curvalue];
- if( gametype_remap[s_startserver.gametype.curvalue] == GT_FFA ) {
- matchbits |= ( 1 << GT_SINGLE_PLAYER );
- }
- for( i = 0; i < count; i++ ) {
- info = UI_GetArenaInfoByNumber( i );
-
- gamebits = GametypeBits( Info_ValueForKey( info, "type") );
- if( !( gamebits & matchbits ) ) {
- continue;
- }
-
- s_startserver.maplist[ s_startserver.nummaps ] = i;
- s_startserver.nummaps++;
- }
- s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE;
- s_startserver.page = 0;
- s_startserver.currentmap = 0;
-
- StartServer_Update();
-}
-
-
-/*
-=================
-StartServer_MenuEvent
-=================
-*/
-static void StartServer_MenuEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_PREVPAGE:
- if( s_startserver.page > 0 ) {
- s_startserver.page--;
- StartServer_Update();
- }
- break;
-
- case ID_NEXTPAGE:
- if( s_startserver.page < s_startserver.maxpages - 1 ) {
- s_startserver.page++;
- StartServer_Update();
- }
- break;
-
- case ID_STARTSERVERNEXT:
- trap_Cvar_SetValue( "g_gameType", gametype_remap[s_startserver.gametype.curvalue] );
- UI_ServerOptionsMenu( s_startserver.multiplayer );
- break;
-
- case ID_STARTSERVERBACK:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-===============
-StartServer_LevelshotDraw
-===============
-*/
-static void StartServer_LevelshotDraw( void *self ) {
- menubitmap_s *b;
- int x;
- int y;
- int w;
- int h;
- int n;
- const char *info;
-
- b = (menubitmap_s *)self;
-
- if( !b->generic.name ) {
- return;
- }
-
- if( b->generic.name && !b->shader ) {
- b->shader = trap_R_RegisterShaderNoMip( b->generic.name );
- if( !b->shader && b->errorpic ) {
- b->shader = trap_R_RegisterShaderNoMip( b->errorpic );
- }
- }
-
- if( b->focuspic && !b->focusshader ) {
- b->focusshader = trap_R_RegisterShaderNoMip( b->focuspic );
- }
-
- x = b->generic.x;
- y = b->generic.y;
- w = b->width;
- h = b->height;
- if( b->shader ) {
- UI_DrawHandlePic( x, y, w, h, b->shader );
- }
-
- x = b->generic.x;
- y = b->generic.y + b->height;
- UI_FillRect( x, y, b->width, 28, colorBlack );
-
- x += b->width / 2;
- y += 4;
- n = s_startserver.page * MAX_MAPSPERPAGE + b->generic.id - ID_PICTURES;
-
- info = UI_GetArenaInfoByNumber( s_startserver.maplist[ n ]);
- UI_DrawString( x, y, Info_ValueForKey( info, "map" ), UI_CENTER|UI_SMALLFONT, color_orange );
-
- x = b->generic.x;
- y = b->generic.y;
- w = b->width;
- h = b->height + 28;
- if( b->generic.flags & QMF_HIGHLIGHT ) {
- UI_DrawHandlePic( x, y, w, h, b->focusshader );
- }
-}
-
-
-/*
-=================
-StartServer_MenuInit
-=================
-*/
-static void StartServer_MenuInit( void ) {
- int i;
- int x;
- int y;
- static char mapnamebuffer[64];
-
- // zero set all our globals
- memset( &s_startserver, 0 ,sizeof(startserver_t) );
-
- StartServer_Cache();
-
- s_startserver.menu.wrapAround = qtrue;
- s_startserver.menu.fullscreen = qtrue;
-
- s_startserver.banner.generic.type = MTYPE_BTEXT;
- s_startserver.banner.generic.x = 320;
- s_startserver.banner.generic.y = 16;
- s_startserver.banner.string = "GAME SERVER";
- s_startserver.banner.color = color_white;
- s_startserver.banner.style = UI_CENTER;
-
- s_startserver.framel.generic.type = MTYPE_BITMAP;
- s_startserver.framel.generic.name = GAMESERVER_FRAMEL;
- s_startserver.framel.generic.flags = QMF_INACTIVE;
- s_startserver.framel.generic.x = 0;
- s_startserver.framel.generic.y = 78;
- s_startserver.framel.width = 256;
- s_startserver.framel.height = 329;
-
- s_startserver.framer.generic.type = MTYPE_BITMAP;
- s_startserver.framer.generic.name = GAMESERVER_FRAMER;
- s_startserver.framer.generic.flags = QMF_INACTIVE;
- s_startserver.framer.generic.x = 376;
- s_startserver.framer.generic.y = 76;
- s_startserver.framer.width = 256;
- s_startserver.framer.height = 334;
-
- s_startserver.gametype.generic.type = MTYPE_SPINCONTROL;
- s_startserver.gametype.generic.name = "Game Type:";
- s_startserver.gametype.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_startserver.gametype.generic.callback = StartServer_GametypeEvent;
- s_startserver.gametype.generic.id = ID_GAMETYPE;
- s_startserver.gametype.generic.x = 320 - 24;
- s_startserver.gametype.generic.y = 368;
- s_startserver.gametype.itemnames = gametype_items;
-
- for (i=0; i<MAX_MAPSPERPAGE; i++)
- {
- x = (i % MAX_MAPCOLS) * (128+8) + 188;
- y = (i / MAX_MAPROWS) * (128+8) + 96;
-
- s_startserver.mappics[i].generic.type = MTYPE_BITMAP;
- s_startserver.mappics[i].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_startserver.mappics[i].generic.x = x;
- s_startserver.mappics[i].generic.y = y;
- s_startserver.mappics[i].generic.id = ID_PICTURES+i;
- s_startserver.mappics[i].width = 128;
- s_startserver.mappics[i].height = 96;
- s_startserver.mappics[i].focuspic = GAMESERVER_SELECTED;
- s_startserver.mappics[i].errorpic = GAMESERVER_UNKNOWNMAP;
- s_startserver.mappics[i].generic.ownerdraw = StartServer_LevelshotDraw;
-
- s_startserver.mapbuttons[i].generic.type = MTYPE_BITMAP;
- s_startserver.mapbuttons[i].generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_NODEFAULTINIT;
- s_startserver.mapbuttons[i].generic.id = ID_PICTURES+i;
- s_startserver.mapbuttons[i].generic.callback = StartServer_MapEvent;
- s_startserver.mapbuttons[i].generic.x = x - 30;
- s_startserver.mapbuttons[i].generic.y = y - 32;
- s_startserver.mapbuttons[i].width = 256;
- s_startserver.mapbuttons[i].height = 248;
- s_startserver.mapbuttons[i].generic.left = x;
- s_startserver.mapbuttons[i].generic.top = y;
- s_startserver.mapbuttons[i].generic.right = x + 128;
- s_startserver.mapbuttons[i].generic.bottom = y + 128;
- s_startserver.mapbuttons[i].focuspic = GAMESERVER_SELECT;
- }
-
- s_startserver.arrows.generic.type = MTYPE_BITMAP;
- s_startserver.arrows.generic.name = GAMESERVER_ARROWS;
- s_startserver.arrows.generic.flags = QMF_INACTIVE;
- s_startserver.arrows.generic.x = 260;
- s_startserver.arrows.generic.y = 400;
- s_startserver.arrows.width = 128;
- s_startserver.arrows.height = 32;
-
- s_startserver.prevpage.generic.type = MTYPE_BITMAP;
- s_startserver.prevpage.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_startserver.prevpage.generic.callback = StartServer_MenuEvent;
- s_startserver.prevpage.generic.id = ID_PREVPAGE;
- s_startserver.prevpage.generic.x = 260;
- s_startserver.prevpage.generic.y = 400;
- s_startserver.prevpage.width = 64;
- s_startserver.prevpage.height = 32;
- s_startserver.prevpage.focuspic = GAMESERVER_ARROWSL;
-
- s_startserver.nextpage.generic.type = MTYPE_BITMAP;
- s_startserver.nextpage.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_startserver.nextpage.generic.callback = StartServer_MenuEvent;
- s_startserver.nextpage.generic.id = ID_NEXTPAGE;
- s_startserver.nextpage.generic.x = 321;
- s_startserver.nextpage.generic.y = 400;
- s_startserver.nextpage.width = 64;
- s_startserver.nextpage.height = 32;
- s_startserver.nextpage.focuspic = GAMESERVER_ARROWSR;
-
- s_startserver.mapname.generic.type = MTYPE_PTEXT;
- s_startserver.mapname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
- s_startserver.mapname.generic.x = 320;
- s_startserver.mapname.generic.y = 440;
- s_startserver.mapname.string = mapnamebuffer;
- s_startserver.mapname.style = UI_CENTER|UI_BIGFONT;
- s_startserver.mapname.color = text_color_normal;
-
- s_startserver.back.generic.type = MTYPE_BITMAP;
- s_startserver.back.generic.name = GAMESERVER_BACK0;
- s_startserver.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_startserver.back.generic.callback = StartServer_MenuEvent;
- s_startserver.back.generic.id = ID_STARTSERVERBACK;
- s_startserver.back.generic.x = 0;
- s_startserver.back.generic.y = 480-64;
- s_startserver.back.width = 128;
- s_startserver.back.height = 64;
- s_startserver.back.focuspic = GAMESERVER_BACK1;
-
- s_startserver.next.generic.type = MTYPE_BITMAP;
- s_startserver.next.generic.name = GAMESERVER_NEXT0;
- s_startserver.next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_startserver.next.generic.callback = StartServer_MenuEvent;
- s_startserver.next.generic.id = ID_STARTSERVERNEXT;
- s_startserver.next.generic.x = 640;
- s_startserver.next.generic.y = 480-64;
- s_startserver.next.width = 128;
- s_startserver.next.height = 64;
- s_startserver.next.focuspic = GAMESERVER_NEXT1;
-
- s_startserver.item_null.generic.type = MTYPE_BITMAP;
- s_startserver.item_null.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;
- s_startserver.item_null.generic.x = 0;
- s_startserver.item_null.generic.y = 0;
- s_startserver.item_null.width = 640;
- s_startserver.item_null.height = 480;
-
- Menu_AddItem( &s_startserver.menu, &s_startserver.banner );
- Menu_AddItem( &s_startserver.menu, &s_startserver.framel );
- Menu_AddItem( &s_startserver.menu, &s_startserver.framer );
-
- Menu_AddItem( &s_startserver.menu, &s_startserver.gametype );
- for (i=0; i<MAX_MAPSPERPAGE; i++)
- {
- Menu_AddItem( &s_startserver.menu, &s_startserver.mappics[i] );
- Menu_AddItem( &s_startserver.menu, &s_startserver.mapbuttons[i] );
- }
-
- Menu_AddItem( &s_startserver.menu, &s_startserver.arrows );
- Menu_AddItem( &s_startserver.menu, &s_startserver.prevpage );
- Menu_AddItem( &s_startserver.menu, &s_startserver.nextpage );
- Menu_AddItem( &s_startserver.menu, &s_startserver.back );
- Menu_AddItem( &s_startserver.menu, &s_startserver.next );
- Menu_AddItem( &s_startserver.menu, &s_startserver.mapname );
- Menu_AddItem( &s_startserver.menu, &s_startserver.item_null );
-
- StartServer_GametypeEvent( NULL, QM_ACTIVATED );
-}
-
-
-/*
-=================
-StartServer_Cache
-=================
-*/
-void StartServer_Cache( void )
-{
- int i;
- const char *info;
- qboolean precache;
- char picname[64];
- char mapname[ MAX_NAMELENGTH ];
-
- trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 );
- trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 );
- trap_R_RegisterShaderNoMip( GAMESERVER_NEXT0 );
- trap_R_RegisterShaderNoMip( GAMESERVER_NEXT1 );
- trap_R_RegisterShaderNoMip( GAMESERVER_FRAMEL );
- trap_R_RegisterShaderNoMip( GAMESERVER_FRAMER );
- trap_R_RegisterShaderNoMip( GAMESERVER_SELECT );
- trap_R_RegisterShaderNoMip( GAMESERVER_SELECTED );
- trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );
- trap_R_RegisterShaderNoMip( GAMESERVER_ARROWS );
- trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSL );
- trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSR );
-
- precache = trap_Cvar_VariableValue("com_buildscript");
-
- if( precache ) {
- for( i = 0; i < UI_GetNumArenas(); i++ ) {
- info = UI_GetArenaInfoByNumber( i );
- Q_strncpyz( mapname, Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
- Q_strupr( mapname );
-
- Com_sprintf( picname, sizeof(picname), "levelshots/%s", mapname );
- trap_R_RegisterShaderNoMip(picname);
- }
- }
-}
-
-
-/*
-=================
-UI_StartServerMenu
-=================
-*/
-void UI_StartServerMenu( qboolean multiplayer ) {
- StartServer_MenuInit();
- s_startserver.multiplayer = multiplayer;
- UI_PushMenu( &s_startserver.menu );
-}
-
-
-
-/*
-=============================================================================
-
-SERVER OPTIONS MENU *****
-
-=============================================================================
-*/
-
-#define ID_PLAYER_TYPE 20
-#define ID_MAXCLIENTS 21
-#define ID_DEDICATED 22
-#define ID_GO 23
-#define ID_BACK 24
-
-#define PLAYER_SLOTS 12
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
-
- menubitmap_s mappic;
- menubitmap_s picframe;
-
- menulist_s dedicated;
- menufield_s timelimit;
- menufield_s fraglimit;
- menufield_s flaglimit;
- menuradiobutton_s friendlyfire;
- menufield_s hostname;
- menuradiobutton_s pure;
- menulist_s botSkill;
-
- menutext_s player0;
- menulist_s playerType[PLAYER_SLOTS];
- menutext_s playerName[PLAYER_SLOTS];
- menulist_s playerTeam[PLAYER_SLOTS];
-
- menubitmap_s go;
- menubitmap_s next;
- menubitmap_s back;
-
- qboolean multiplayer;
- int gametype;
- char mapnamebuffer[32];
- char playerNameBuffers[PLAYER_SLOTS][16];
-
- qboolean newBot;
- int newBotIndex;
- char newBotName[16];
-
- menulist_s punkbuster;
-} serveroptions_t;
-
-static serveroptions_t s_serveroptions;
-
-static const char *dedicated_list[] = {
- "No",
- "LAN",
- "Internet",
- NULL
-};
-
-static const char *playerType_list[] = {
- "Open",
- "Bot",
- "----",
- NULL
-};
-
-static const char *playerTeam_list[] = {
- "Blue",
- "Red",
- NULL
-};
-
-static const char *botSkill_list[] = {
- "I Can Win",
- "Bring It On",
- "Hurt Me Plenty",
- "Hardcore",
- "Nightmare!",
- NULL
-};
-
-
-/*
-=================
-BotAlreadySelected
-=================
-*/
-static qboolean BotAlreadySelected( const char *checkName ) {
- int n;
-
- for( n = 1; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue != 1 ) {
- continue;
- }
- if( (s_serveroptions.gametype >= GT_TEAM) &&
- (s_serveroptions.playerTeam[n].curvalue != s_serveroptions.playerTeam[s_serveroptions.newBotIndex].curvalue ) ) {
- continue;
- }
- if( Q_stricmp( checkName, s_serveroptions.playerNameBuffers[n] ) == 0 ) {
- return qtrue;
- }
- }
-
- return qfalse;
-}
-
-
-/*
-=================
-ServerOptions_Start
-=================
-*/
-static void ServerOptions_Start( void ) {
- int timelimit;
- int fraglimit;
- int maxclients;
- int dedicated;
- int friendlyfire;
- int flaglimit;
- int pure;
- int skill;
- int n;
- char buf[64];
- const char *info;
-
- timelimit = atoi( s_serveroptions.timelimit.field.buffer );
- fraglimit = atoi( s_serveroptions.fraglimit.field.buffer );
- flaglimit = atoi( s_serveroptions.flaglimit.field.buffer );
- dedicated = s_serveroptions.dedicated.curvalue;
- friendlyfire = s_serveroptions.friendlyfire.curvalue;
- pure = s_serveroptions.pure.curvalue;
- skill = s_serveroptions.botSkill.curvalue + 1;
-
- //set maxclients
- for( n = 0, maxclients = 0; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue == 2 ) {
- continue;
- }
- if( (s_serveroptions.playerType[n].curvalue == 1) && (s_serveroptions.playerNameBuffers[n][0] == 0) ) {
- continue;
- }
- maxclients++;
- }
-
- switch( s_serveroptions.gametype ) {
- case GT_FFA:
- default:
- trap_Cvar_SetValue( "ui_ffa_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_ffa_timelimit", timelimit );
- break;
-
- case GT_TOURNAMENT:
- trap_Cvar_SetValue( "ui_tourney_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_tourney_timelimit", timelimit );
- break;
-
- case GT_TEAM:
- trap_Cvar_SetValue( "ui_team_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_team_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_team_friendlt", friendlyfire );
- break;
-
- case GT_CTF:
- trap_Cvar_SetValue( "ui_ctf_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_ctf_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_ctf_friendlt", friendlyfire );
- break;
- }
-
- trap_Cvar_SetValue( "sv_maxclients", Com_Clamp( 0, 12, maxclients ) );
- trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, dedicated ) );
- trap_Cvar_SetValue ("timelimit", Com_Clamp( 0, timelimit, timelimit ) );
- trap_Cvar_SetValue ("fraglimit", Com_Clamp( 0, fraglimit, fraglimit ) );
- trap_Cvar_SetValue ("capturelimit", Com_Clamp( 0, flaglimit, flaglimit ) );
- trap_Cvar_SetValue( "g_friendlyfire", friendlyfire );
- trap_Cvar_SetValue( "sv_pure", pure );
- trap_Cvar_Set("sv_hostname", s_serveroptions.hostname.field.buffer );
-
- trap_Cvar_SetValue( "sv_punkbuster", s_serveroptions.punkbuster.curvalue );
-
- // the wait commands will allow the dedicated to take effect
- info = UI_GetArenaInfoByNumber( s_startserver.maplist[ s_startserver.currentmap ]);
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", Info_ValueForKey( info, "map" )));
-
- // add bots
- trap_Cmd_ExecuteText( EXEC_APPEND, "wait 3\n" );
- for( n = 1; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue != 1 ) {
- continue;
- }
- if( s_serveroptions.playerNameBuffers[n][0] == 0 ) {
- continue;
- }
- if( s_serveroptions.playerNameBuffers[n][0] == '-' ) {
- continue;
- }
- if( s_serveroptions.gametype >= GT_TEAM ) {
- Com_sprintf( buf, sizeof(buf), "addbot %s %i %s\n", s_serveroptions.playerNameBuffers[n], skill,
- playerTeam_list[s_serveroptions.playerTeam[n].curvalue] );
- }
- else {
- Com_sprintf( buf, sizeof(buf), "addbot %s %i\n", s_serveroptions.playerNameBuffers[n], skill );
- }
- trap_Cmd_ExecuteText( EXEC_APPEND, buf );
- }
-
- // set player's team
- if( dedicated == 0 && s_serveroptions.gametype >= GT_TEAM ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait 5; team %s\n", playerTeam_list[s_serveroptions.playerTeam[0].curvalue] ) );
- }
-}
-
-
-/*
-=================
-ServerOptions_InitPlayerItems
-=================
-*/
-static void ServerOptions_InitPlayerItems( void ) {
- int n;
- int v;
-
- // init types
- if( s_serveroptions.multiplayer ) {
- v = 0; // open
- }
- else {
- v = 1; // bot
- }
-
- for( n = 0; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerType[n].curvalue = v;
- }
-
- if( s_serveroptions.multiplayer && (s_serveroptions.gametype < GT_TEAM) ) {
- for( n = 8; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerType[n].curvalue = 2;
- }
- }
-
- // if not a dedicated server, first slot is reserved for the human on the server
- if( s_serveroptions.dedicated.curvalue == 0 ) {
- // human
- s_serveroptions.playerType[0].generic.flags |= QMF_INACTIVE;
- s_serveroptions.playerType[0].curvalue = 0;
- trap_Cvar_VariableStringBuffer( "name", s_serveroptions.playerNameBuffers[0], sizeof(s_serveroptions.playerNameBuffers[0]) );
- Q_CleanStr( s_serveroptions.playerNameBuffers[0] );
- }
-
- // init teams
- if( s_serveroptions.gametype >= GT_TEAM ) {
- for( n = 0; n < (PLAYER_SLOTS / 2); n++ ) {
- s_serveroptions.playerTeam[n].curvalue = 0;
- }
- for( ; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerTeam[n].curvalue = 1;
- }
- }
- else {
- for( n = 0; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- }
- }
-}
-
-
-/*
-=================
-ServerOptions_SetPlayerItems
-=================
-*/
-static void ServerOptions_SetPlayerItems( void ) {
- int start;
- int n;
-
- // types
-// for( n = 0; n < PLAYER_SLOTS; n++ ) {
-// if( (!s_serveroptions.multiplayer) && (n > 0) && (s_serveroptions.playerType[n].curvalue == 0) ) {
-// s_serveroptions.playerType[n].curvalue = 1;
-// }
-// }
-
- // names
- if( s_serveroptions.dedicated.curvalue == 0 ) {
- s_serveroptions.player0.string = "Human";
- s_serveroptions.playerName[0].generic.flags &= ~QMF_HIDDEN;
-
- start = 1;
- }
- else {
- s_serveroptions.player0.string = "Open";
- start = 0;
- }
- for( n = start; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue == 1 ) {
- s_serveroptions.playerName[n].generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);
- }
- else {
- s_serveroptions.playerName[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- }
- }
-
- // teams
- if( s_serveroptions.gametype < GT_TEAM ) {
- return;
- }
- for( n = start; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue == 2 ) {
- s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- }
- else {
- s_serveroptions.playerTeam[n].generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);
- }
- }
-}
-
-
-/*
-=================
-ServerOptions_Event
-=================
-*/
-static void ServerOptions_Event( void* ptr, int event ) {
- switch( ((menucommon_s*)ptr)->id ) {
-
- //if( event != QM_ACTIVATED && event != QM_LOSTFOCUS) {
- // return;
- //}
- case ID_PLAYER_TYPE:
- if( event != QM_ACTIVATED ) {
- break;
- }
- ServerOptions_SetPlayerItems();
- break;
-
- case ID_MAXCLIENTS:
- case ID_DEDICATED:
- ServerOptions_SetPlayerItems();
- break;
- case ID_GO:
- if( event != QM_ACTIVATED ) {
- break;
- }
- ServerOptions_Start();
- break;
-
- case ID_STARTSERVERNEXT:
- if( event != QM_ACTIVATED ) {
- break;
- }
- break;
- case ID_BACK:
- if( event != QM_ACTIVATED ) {
- break;
- }
- UI_PopMenu();
- break;
- }
-}
-
-
-static void ServerOptions_PlayerNameEvent( void* ptr, int event ) {
- int n;
-
- if( event != QM_ACTIVATED ) {
- return;
- }
- n = ((menutext_s*)ptr)->generic.id;
- s_serveroptions.newBotIndex = n;
- UI_BotSelectMenu( s_serveroptions.playerNameBuffers[n] );
-}
-
-
-/*
-=================
-ServerOptions_StatusBar
-=================
-*/
-static void ServerOptions_StatusBar( void* ptr ) {
- switch( ((menucommon_s*)ptr)->id ) {
- default:
- UI_DrawString( 320, 440, "0 = NO LIMIT", UI_CENTER|UI_SMALLFONT, colorWhite );
- break;
- }
-}
-
-
-/*
-===============
-ServerOptions_LevelshotDraw
-===============
-*/
-static void ServerOptions_LevelshotDraw( void *self ) {
- menubitmap_s *b;
- int x;
- int y;
-
- // strange place for this, but it works
- if( s_serveroptions.newBot ) {
- Q_strncpyz( s_serveroptions.playerNameBuffers[s_serveroptions.newBotIndex], s_serveroptions.newBotName, 16 );
- s_serveroptions.newBot = qfalse;
- }
-
- b = (menubitmap_s *)self;
-
- Bitmap_Draw( b );
-
- x = b->generic.x;
- y = b->generic.y + b->height;
- UI_FillRect( x, y, b->width, 40, colorBlack );
-
- x += b->width / 2;
- y += 4;
- UI_DrawString( x, y, s_serveroptions.mapnamebuffer, UI_CENTER|UI_SMALLFONT, color_orange );
-
- y += SMALLCHAR_HEIGHT;
- UI_DrawString( x, y, gametype_items[gametype_remap2[s_serveroptions.gametype]], UI_CENTER|UI_SMALLFONT, color_orange );
-}
-
-
-static void ServerOptions_InitBotNames( void ) {
- int count;
- int n;
- const char *arenaInfo;
- const char *botInfo;
- char *p;
- char *bot;
- char bots[MAX_INFO_STRING];
-
- if( s_serveroptions.gametype >= GT_TEAM ) {
- Q_strncpyz( s_serveroptions.playerNameBuffers[1], "grunt", 16 );
- Q_strncpyz( s_serveroptions.playerNameBuffers[2], "major", 16 );
- if( s_serveroptions.gametype == GT_TEAM ) {
- Q_strncpyz( s_serveroptions.playerNameBuffers[3], "visor", 16 );
- }
- else {
- s_serveroptions.playerType[3].curvalue = 2;
- }
- s_serveroptions.playerType[4].curvalue = 2;
- s_serveroptions.playerType[5].curvalue = 2;
-
- Q_strncpyz( s_serveroptions.playerNameBuffers[6], "sarge", 16 );
- Q_strncpyz( s_serveroptions.playerNameBuffers[7], "grunt", 16 );
- Q_strncpyz( s_serveroptions.playerNameBuffers[8], "major", 16 );
- if( s_serveroptions.gametype == GT_TEAM ) {
- Q_strncpyz( s_serveroptions.playerNameBuffers[9], "visor", 16 );
- }
- else {
- s_serveroptions.playerType[9].curvalue = 2;
- }
- s_serveroptions.playerType[10].curvalue = 2;
- s_serveroptions.playerType[11].curvalue = 2;
-
- return;
- }
-
- count = 1; // skip the first slot, reserved for a human
-
- // get info for this map
- arenaInfo = UI_GetArenaInfoByMap( s_serveroptions.mapnamebuffer );
-
- // get the bot info - we'll seed with them if any are listed
- Q_strncpyz( bots, Info_ValueForKey( arenaInfo, "bots" ), sizeof(bots) );
- p = &bots[0];
- while( *p && count < PLAYER_SLOTS ) {
- //skip spaces
- while( *p && *p == ' ' ) {
- p++;
- }
- if( !p ) {
- break;
- }
-
- // mark start of bot name
- bot = p;
-
- // skip until space of null
- while( *p && *p != ' ' ) {
- p++;
- }
- if( *p ) {
- *p++ = 0;
- }
-
- botInfo = UI_GetBotInfoByName( bot );
- if( !botInfo )
- {
- botInfo = UI_GetBotInfoByNumber( count );
- }
- bot = Info_ValueForKey( botInfo, "name" );
-
- Q_strncpyz( s_serveroptions.playerNameBuffers[count], bot, sizeof(s_serveroptions.playerNameBuffers[count]) );
- count++;
- }
-
- // set the rest of the bot slots to "---"
- for( n = count; n < PLAYER_SLOTS; n++ ) {
- strcpy( s_serveroptions.playerNameBuffers[n], "--------" );
- }
-
- // pad up to #8 as open slots
- for( ;count < 8; count++ ) {
- s_serveroptions.playerType[count].curvalue = 0;
- }
-
- // close off the rest by default
- for( ;count < PLAYER_SLOTS; count++ ) {
- if( s_serveroptions.playerType[count].curvalue == 1 ) {
- s_serveroptions.playerType[count].curvalue = 2;
- }
- }
-}
-
-
-/*
-=================
-ServerOptions_SetMenuItems
-=================
-*/
-static void ServerOptions_SetMenuItems( void ) {
- static char picname[64];
- char mapname[MAX_NAMELENGTH];
- const char *info;
-
- switch( s_serveroptions.gametype ) {
- case GT_FFA:
- default:
- Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_fraglimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_timelimit" ) ) );
- break;
-
- case GT_TOURNAMENT:
- Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_fraglimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_timelimit" ) ) );
- break;
-
- case GT_TEAM:
- Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_fraglimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_team_friendly" ) );
- break;
-
- case GT_CTF:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_ctf_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_ctf_friendly" ) );
- break;
- }
-
- Q_strncpyz( s_serveroptions.hostname.field.buffer, UI_Cvar_VariableString( "sv_hostname" ), sizeof( s_serveroptions.hostname.field.buffer ) );
- s_serveroptions.pure.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_pure" ) );
-
- // set the map pic
- info = UI_GetArenaInfoByNumber( s_startserver.maplist[ s_startserver.currentmap ]);
- Q_strncpyz( mapname, Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
- Q_strupr( mapname );
- Com_sprintf( picname, 64, "levelshots/%s", mapname );
- s_serveroptions.mappic.generic.name = picname;
-
- // set the map name
- strcpy( s_serveroptions.mapnamebuffer, s_startserver.mapname.string );
- Q_strupr( s_serveroptions.mapnamebuffer );
-
- // get the player selections initialized
- ServerOptions_InitPlayerItems();
- ServerOptions_SetPlayerItems();
-
- // seed bot names
- ServerOptions_InitBotNames();
- ServerOptions_SetPlayerItems();
-}
-
-/*
-=================
-PlayerName_Draw
-=================
-*/
-static void PlayerName_Draw( void *item ) {
- menutext_s *s;
- float *color;
- int x, y;
- int style;
- qboolean focus;
-
- s = (menutext_s *)item;
-
- x = s->generic.x;
- y = s->generic.y;
-
- style = UI_SMALLFONT;
- focus = (s->generic.parent->cursor == s->generic.menuPosition);
-
- if ( s->generic.flags & QMF_GRAYED )
- color = text_color_disabled;
- else if ( focus )
- {
- color = text_color_highlight;
- style |= UI_PULSE;
- }
- else if ( s->generic.flags & QMF_BLINK )
- {
- color = text_color_highlight;
- style |= UI_BLINK;
- }
- else
- color = text_color_normal;
-
- if ( focus )
- {
- // draw cursor
- UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
- }
-
- UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );
- UI_DrawString( x + SMALLCHAR_WIDTH, y, s->string, style|UI_LEFT, color );
-}
-
-
-/*
-=================
-ServerOptions_MenuInit
-=================
-*/
-#define OPTIONS_X 456
-
-static void ServerOptions_MenuInit( qboolean multiplayer ) {
- int y;
- int n;
-
- memset( &s_serveroptions, 0 ,sizeof(serveroptions_t) );
- s_serveroptions.multiplayer = multiplayer;
- s_serveroptions.gametype = (int)Com_Clamp( 0, 5, trap_Cvar_VariableValue( "g_gameType" ) );
- s_serveroptions.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_punkbuster" ) );
-
- ServerOptions_Cache();
-
- s_serveroptions.menu.wrapAround = qtrue;
- s_serveroptions.menu.fullscreen = qtrue;
-
- s_serveroptions.banner.generic.type = MTYPE_BTEXT;
- s_serveroptions.banner.generic.x = 320;
- s_serveroptions.banner.generic.y = 16;
- s_serveroptions.banner.string = "GAME SERVER";
- s_serveroptions.banner.color = color_white;
- s_serveroptions.banner.style = UI_CENTER;
-
- s_serveroptions.mappic.generic.type = MTYPE_BITMAP;
- s_serveroptions.mappic.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_serveroptions.mappic.generic.x = 352;
- s_serveroptions.mappic.generic.y = 80;
- s_serveroptions.mappic.width = 160;
- s_serveroptions.mappic.height = 120;
- s_serveroptions.mappic.errorpic = GAMESERVER_UNKNOWNMAP;
- s_serveroptions.mappic.generic.ownerdraw = ServerOptions_LevelshotDraw;
-
- s_serveroptions.picframe.generic.type = MTYPE_BITMAP;
- s_serveroptions.picframe.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE|QMF_HIGHLIGHT;
- s_serveroptions.picframe.generic.x = 352 - 38;
- s_serveroptions.picframe.generic.y = 80 - 40;
- s_serveroptions.picframe.width = 320;
- s_serveroptions.picframe.height = 320;
- s_serveroptions.picframe.focuspic = GAMESERVER_SELECT;
-
- y = 272;
- if( s_serveroptions.gametype != GT_CTF ) {
- s_serveroptions.fraglimit.generic.type = MTYPE_FIELD;
- s_serveroptions.fraglimit.generic.name = "Frag Limit:";
- s_serveroptions.fraglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.fraglimit.generic.x = OPTIONS_X;
- s_serveroptions.fraglimit.generic.y = y;
- s_serveroptions.fraglimit.generic.statusbar = ServerOptions_StatusBar;
- s_serveroptions.fraglimit.field.widthInChars = 3;
- s_serveroptions.fraglimit.field.maxchars = 3;
- }
- else {
- s_serveroptions.flaglimit.generic.type = MTYPE_FIELD;
- s_serveroptions.flaglimit.generic.name = "Capture Limit:";
- s_serveroptions.flaglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.flaglimit.generic.x = OPTIONS_X;
- s_serveroptions.flaglimit.generic.y = y;
- s_serveroptions.flaglimit.generic.statusbar = ServerOptions_StatusBar;
- s_serveroptions.flaglimit.field.widthInChars = 3;
- s_serveroptions.flaglimit.field.maxchars = 3;
- }
-
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.timelimit.generic.type = MTYPE_FIELD;
- s_serveroptions.timelimit.generic.name = "Time Limit:";
- s_serveroptions.timelimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.timelimit.generic.x = OPTIONS_X;
- s_serveroptions.timelimit.generic.y = y;
- s_serveroptions.timelimit.generic.statusbar = ServerOptions_StatusBar;
- s_serveroptions.timelimit.field.widthInChars = 3;
- s_serveroptions.timelimit.field.maxchars = 3;
-
- if( s_serveroptions.gametype >= GT_TEAM ) {
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.friendlyfire.generic.type = MTYPE_RADIOBUTTON;
- s_serveroptions.friendlyfire.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.friendlyfire.generic.x = OPTIONS_X;
- s_serveroptions.friendlyfire.generic.y = y;
- s_serveroptions.friendlyfire.generic.name = "Friendly Fire:";
- }
-
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.pure.generic.type = MTYPE_RADIOBUTTON;
- s_serveroptions.pure.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.pure.generic.x = OPTIONS_X;
- s_serveroptions.pure.generic.y = y;
- s_serveroptions.pure.generic.name = "Pure Server:";
-
- if( s_serveroptions.multiplayer ) {
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.dedicated.generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.dedicated.generic.id = ID_DEDICATED;
- s_serveroptions.dedicated.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.dedicated.generic.callback = ServerOptions_Event;
- s_serveroptions.dedicated.generic.x = OPTIONS_X;
- s_serveroptions.dedicated.generic.y = y;
- s_serveroptions.dedicated.generic.name = "Dedicated:";
- s_serveroptions.dedicated.itemnames = dedicated_list;
- }
-
- if( s_serveroptions.multiplayer ) {
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.hostname.generic.type = MTYPE_FIELD;
- s_serveroptions.hostname.generic.name = "Hostname:";
- s_serveroptions.hostname.generic.flags = QMF_SMALLFONT;
- s_serveroptions.hostname.generic.x = OPTIONS_X;
- s_serveroptions.hostname.generic.y = y;
- s_serveroptions.hostname.field.widthInChars = 18;
- s_serveroptions.hostname.field.maxchars = 64;
- }
-
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.punkbuster.generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.punkbuster.generic.name = "Punkbuster:";
- s_serveroptions.punkbuster.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.punkbuster.generic.id = 0;
- s_serveroptions.punkbuster.generic.x = OPTIONS_X;
- s_serveroptions.punkbuster.generic.y = y;
- s_serveroptions.punkbuster.itemnames = punkbuster_items;
-
- y = 80;
- s_serveroptions.botSkill.generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.botSkill.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.botSkill.generic.name = "Bot Skill: ";
- s_serveroptions.botSkill.generic.x = 32 + (strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH;
- s_serveroptions.botSkill.generic.y = y;
- s_serveroptions.botSkill.itemnames = botSkill_list;
- s_serveroptions.botSkill.curvalue = 1;
-
- y += ( 2 * SMALLCHAR_HEIGHT );
- s_serveroptions.player0.generic.type = MTYPE_TEXT;
- s_serveroptions.player0.generic.flags = QMF_SMALLFONT;
- s_serveroptions.player0.generic.x = 32 + SMALLCHAR_WIDTH;
- s_serveroptions.player0.generic.y = y;
- s_serveroptions.player0.color = color_orange;
- s_serveroptions.player0.style = UI_LEFT|UI_SMALLFONT;
-
- for( n = 0; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerType[n].generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.playerType[n].generic.flags = QMF_SMALLFONT;
- s_serveroptions.playerType[n].generic.id = ID_PLAYER_TYPE;
- s_serveroptions.playerType[n].generic.callback = ServerOptions_Event;
- s_serveroptions.playerType[n].generic.x = 32;
- s_serveroptions.playerType[n].generic.y = y;
- s_serveroptions.playerType[n].itemnames = playerType_list;
-
- s_serveroptions.playerName[n].generic.type = MTYPE_TEXT;
- s_serveroptions.playerName[n].generic.flags = QMF_SMALLFONT;
- s_serveroptions.playerName[n].generic.x = 96;
- s_serveroptions.playerName[n].generic.y = y;
- s_serveroptions.playerName[n].generic.callback = ServerOptions_PlayerNameEvent;
- s_serveroptions.playerName[n].generic.id = n;
- s_serveroptions.playerName[n].generic.ownerdraw = PlayerName_Draw;
- s_serveroptions.playerName[n].color = color_orange;
- s_serveroptions.playerName[n].style = UI_SMALLFONT;
- s_serveroptions.playerName[n].string = s_serveroptions.playerNameBuffers[n];
- s_serveroptions.playerName[n].generic.top = s_serveroptions.playerName[n].generic.y;
- s_serveroptions.playerName[n].generic.bottom = s_serveroptions.playerName[n].generic.y + SMALLCHAR_HEIGHT;
- s_serveroptions.playerName[n].generic.left = s_serveroptions.playerName[n].generic.x - SMALLCHAR_HEIGHT/ 2;
- s_serveroptions.playerName[n].generic.right = s_serveroptions.playerName[n].generic.x + 16 * SMALLCHAR_WIDTH;
-
- s_serveroptions.playerTeam[n].generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.playerTeam[n].generic.flags = QMF_SMALLFONT;
- s_serveroptions.playerTeam[n].generic.x = 240;
- s_serveroptions.playerTeam[n].generic.y = y;
- s_serveroptions.playerTeam[n].itemnames = playerTeam_list;
-
- y += ( SMALLCHAR_HEIGHT + 4 );
- }
-
- s_serveroptions.back.generic.type = MTYPE_BITMAP;
- s_serveroptions.back.generic.name = GAMESERVER_BACK0;
- s_serveroptions.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_serveroptions.back.generic.callback = ServerOptions_Event;
- s_serveroptions.back.generic.id = ID_BACK;
- s_serveroptions.back.generic.x = 0;
- s_serveroptions.back.generic.y = 480-64;
- s_serveroptions.back.width = 128;
- s_serveroptions.back.height = 64;
- s_serveroptions.back.focuspic = GAMESERVER_BACK1;
-
- s_serveroptions.next.generic.type = MTYPE_BITMAP;
- s_serveroptions.next.generic.name = GAMESERVER_NEXT0;
- s_serveroptions.next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE|QMF_GRAYED|QMF_HIDDEN;
- s_serveroptions.next.generic.callback = ServerOptions_Event;
- s_serveroptions.next.generic.id = ID_STARTSERVERNEXT;
- s_serveroptions.next.generic.x = 640;
- s_serveroptions.next.generic.y = 480-64-72;
- s_serveroptions.next.generic.statusbar = ServerOptions_StatusBar;
- s_serveroptions.next.width = 128;
- s_serveroptions.next.height = 64;
- s_serveroptions.next.focuspic = GAMESERVER_NEXT1;
-
- s_serveroptions.go.generic.type = MTYPE_BITMAP;
- s_serveroptions.go.generic.name = GAMESERVER_FIGHT0;
- s_serveroptions.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_serveroptions.go.generic.callback = ServerOptions_Event;
- s_serveroptions.go.generic.id = ID_GO;
- s_serveroptions.go.generic.x = 640;
- s_serveroptions.go.generic.y = 480-64;
- s_serveroptions.go.width = 128;
- s_serveroptions.go.height = 64;
- s_serveroptions.go.focuspic = GAMESERVER_FIGHT1;
-
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.banner );
-
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.mappic );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.picframe );
-
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.botSkill );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.player0 );
- for( n = 0; n < PLAYER_SLOTS; n++ ) {
- if( n != 0 ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerType[n] );
- }
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerName[n] );
- if( s_serveroptions.gametype >= GT_TEAM ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerTeam[n] );
- }
- }
-
- if( s_serveroptions.gametype != GT_CTF ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.fraglimit );
- }
- else {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.flaglimit );
- }
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.timelimit );
- if( s_serveroptions.gametype >= GT_TEAM ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.friendlyfire );
- }
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.pure );
- if( s_serveroptions.multiplayer ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.dedicated );
- }
- if( s_serveroptions.multiplayer ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.hostname );
- }
-
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.back );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.next );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.go );
-
- Menu_AddItem( &s_serveroptions.menu, (void*) &s_serveroptions.punkbuster );
-
- ServerOptions_SetMenuItems();
-}
-
-/*
-=================
-ServerOptions_Cache
-=================
-*/
-void ServerOptions_Cache( void ) {
- trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 );
- trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 );
- trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT0 );
- trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT1 );
- trap_R_RegisterShaderNoMip( GAMESERVER_SELECT );
- trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );
-}
-
-
-/*
-=================
-UI_ServerOptionsMenu
-=================
-*/
-static void UI_ServerOptionsMenu( qboolean multiplayer ) {
- ServerOptions_MenuInit( multiplayer );
- UI_PushMenu( &s_serveroptions.menu );
-}
-
-
-
-/*
-=============================================================================
-
-BOT SELECT MENU *****
-
-=============================================================================
-*/
-
-
-#define BOTSELECT_BACK0 "menu/art/back_0"
-#define BOTSELECT_BACK1 "menu/art/back_1"
-#define BOTSELECT_ACCEPT0 "menu/art/accept_0"
-#define BOTSELECT_ACCEPT1 "menu/art/accept_1"
-#define BOTSELECT_SELECT "menu/art/opponents_select"
-#define BOTSELECT_SELECTED "menu/art/opponents_selected"
-#define BOTSELECT_ARROWS "menu/art/gs_arrows_0"
-#define BOTSELECT_ARROWSL "menu/art/gs_arrows_l"
-#define BOTSELECT_ARROWSR "menu/art/gs_arrows_r"
-
-#define PLAYERGRID_COLS 4
-#define PLAYERGRID_ROWS 4
-#define MAX_MODELSPERPAGE (PLAYERGRID_ROWS * PLAYERGRID_COLS)
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
-
- menubitmap_s pics[MAX_MODELSPERPAGE];
- menubitmap_s picbuttons[MAX_MODELSPERPAGE];
- menutext_s picnames[MAX_MODELSPERPAGE];
-
- menubitmap_s arrows;
- menubitmap_s left;
- menubitmap_s right;
-
- menubitmap_s go;
- menubitmap_s back;
-
- int numBots;
- int modelpage;
- int numpages;
- int selectedmodel;
- int sortedBotNums[MAX_BOTS];
- char boticons[MAX_MODELSPERPAGE][MAX_QPATH];
- char botnames[MAX_MODELSPERPAGE][16];
-} botSelectInfo_t;
-
-static botSelectInfo_t botSelectInfo;
-
-
-/*
-=================
-UI_BotSelectMenu_SortCompare
-=================
-*/
-static int QDECL UI_BotSelectMenu_SortCompare( const void *arg1, const void *arg2 ) {
- int num1, num2;
- const char *info1, *info2;
- const char *name1, *name2;
-
- num1 = *(int *)arg1;
- num2 = *(int *)arg2;
-
- info1 = UI_GetBotInfoByNumber( num1 );
- info2 = UI_GetBotInfoByNumber( num2 );
-
- name1 = Info_ValueForKey( info1, "name" );
- name2 = Info_ValueForKey( info2, "name" );
-
- return Q_stricmp( name1, name2 );
-}
-
-
-/*
-=================
-UI_BotSelectMenu_BuildList
-=================
-*/
-static void UI_BotSelectMenu_BuildList( void ) {
- int n;
-
- botSelectInfo.modelpage = 0;
- botSelectInfo.numBots = UI_GetNumBots();
- botSelectInfo.numpages = botSelectInfo.numBots / MAX_MODELSPERPAGE;
- if( botSelectInfo.numBots % MAX_MODELSPERPAGE ) {
- botSelectInfo.numpages++;
- }
-
- // initialize the array
- for( n = 0; n < botSelectInfo.numBots; n++ ) {
- botSelectInfo.sortedBotNums[n] = n;
- }
-
- // now sort it
- qsort( botSelectInfo.sortedBotNums, botSelectInfo.numBots, sizeof(botSelectInfo.sortedBotNums[0]), UI_BotSelectMenu_SortCompare );
-}
-
-
-/*
-=================
-ServerPlayerIcon
-=================
-*/
-static void ServerPlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize ) {
- char *skin;
- char model[MAX_QPATH];
-
- Q_strncpyz( model, modelAndSkin, sizeof(model));
- skin = Q_strrchr( model, '/' );
- if ( skin ) {
- *skin++ = '\0';
- }
- else {
- skin = "default";
- }
-
- Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_%s.tga", model, skin );
-
- if( !trap_R_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, "default" ) != 0 ) {
- Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_default.tga", model );
- }
-}
-
-
-/*
-=================
-UI_BotSelectMenu_UpdateGrid
-=================
-*/
-static void UI_BotSelectMenu_UpdateGrid( void ) {
- const char *info;
- int i;
- int j;
-
- j = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
- for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++, j++) {
- if( j < botSelectInfo.numBots ) {
- info = UI_GetBotInfoByNumber( botSelectInfo.sortedBotNums[j] );
- ServerPlayerIcon( Info_ValueForKey( info, "model" ), botSelectInfo.boticons[i], MAX_QPATH );
- Q_strncpyz( botSelectInfo.botnames[i], Info_ValueForKey( info, "name" ), 16 );
- Q_CleanStr( botSelectInfo.botnames[i] );
- botSelectInfo.pics[i].generic.name = botSelectInfo.boticons[i];
- if( BotAlreadySelected( botSelectInfo.botnames[i] ) ) {
- botSelectInfo.picnames[i].color = color_red;
- }
- else {
- botSelectInfo.picnames[i].color = color_orange;
- }
- botSelectInfo.picbuttons[i].generic.flags &= ~QMF_INACTIVE;
- }
- else {
- // dead slot
- botSelectInfo.pics[i].generic.name = NULL;
- botSelectInfo.picbuttons[i].generic.flags |= QMF_INACTIVE;
- botSelectInfo.botnames[i][0] = 0;
- }
-
- botSelectInfo.pics[i].generic.flags &= ~QMF_HIGHLIGHT;
- botSelectInfo.pics[i].shader = 0;
- botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
- }
-
- // set selected model
- i = botSelectInfo.selectedmodel % MAX_MODELSPERPAGE;
- botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;
- botSelectInfo.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
-
- if( botSelectInfo.numpages > 1 ) {
- if( botSelectInfo.modelpage > 0 ) {
- botSelectInfo.left.generic.flags &= ~QMF_INACTIVE;
- }
- else {
- botSelectInfo.left.generic.flags |= QMF_INACTIVE;
- }
-
- if( botSelectInfo.modelpage < (botSelectInfo.numpages - 1) ) {
- botSelectInfo.right.generic.flags &= ~QMF_INACTIVE;
- }
- else {
- botSelectInfo.right.generic.flags |= QMF_INACTIVE;
- }
- }
- else {
- // hide left/right markers
- botSelectInfo.left.generic.flags |= QMF_INACTIVE;
- botSelectInfo.right.generic.flags |= QMF_INACTIVE;
- }
-}
-
-
-/*
-=================
-UI_BotSelectMenu_Default
-=================
-*/
-static void UI_BotSelectMenu_Default( char *bot ) {
- const char *botInfo;
- const char *test;
- int n;
- int i;
-
- for( n = 0; n < botSelectInfo.numBots; n++ ) {
- botInfo = UI_GetBotInfoByNumber( n );
- test = Info_ValueForKey( botInfo, "name" );
- if( Q_stricmp( bot, test ) == 0 ) {
- break;
- }
- }
- if( n == botSelectInfo.numBots ) {
- botSelectInfo.selectedmodel = 0;
- return;
- }
-
- for( i = 0; i < botSelectInfo.numBots; i++ ) {
- if( botSelectInfo.sortedBotNums[i] == n ) {
- break;
- }
- }
- if( i == botSelectInfo.numBots ) {
- botSelectInfo.selectedmodel = 0;
- return;
- }
-
- botSelectInfo.selectedmodel = i;
-}
-
-
-/*
-=================
-UI_BotSelectMenu_LeftEvent
-=================
-*/
-static void UI_BotSelectMenu_LeftEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- if( botSelectInfo.modelpage > 0 ) {
- botSelectInfo.modelpage--;
- botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
- UI_BotSelectMenu_UpdateGrid();
- }
-}
-
-
-/*
-=================
-UI_BotSelectMenu_RightEvent
-=================
-*/
-static void UI_BotSelectMenu_RightEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- if( botSelectInfo.modelpage < botSelectInfo.numpages - 1 ) {
- botSelectInfo.modelpage++;
- botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
- UI_BotSelectMenu_UpdateGrid();
- }
-}
-
-
-/*
-=================
-UI_BotSelectMenu_BotEvent
-=================
-*/
-static void UI_BotSelectMenu_BotEvent( void* ptr, int event ) {
- int i;
-
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++ ) {
- botSelectInfo.pics[i].generic.flags &= ~QMF_HIGHLIGHT;
- botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
- }
-
- // set selected
- i = ((menucommon_s*)ptr)->id;
- botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;
- botSelectInfo.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
- botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE + i;
-}
-
-
-/*
-=================
-UI_BotSelectMenu_BackEvent
-=================
-*/
-static void UI_BotSelectMenu_BackEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- UI_PopMenu();
-}
-
-
-/*
-=================
-UI_BotSelectMenu_SelectEvent
-=================
-*/
-static void UI_BotSelectMenu_SelectEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- UI_PopMenu();
-
- s_serveroptions.newBot = qtrue;
- Q_strncpyz( s_serveroptions.newBotName, botSelectInfo.botnames[botSelectInfo.selectedmodel % MAX_MODELSPERPAGE], 16 );
-}
-
-
-/*
-=================
-UI_BotSelectMenu_Cache
-=================
-*/
-void UI_BotSelectMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( BOTSELECT_BACK0 );
- trap_R_RegisterShaderNoMip( BOTSELECT_BACK1 );
- trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT0 );
- trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT1 );
- trap_R_RegisterShaderNoMip( BOTSELECT_SELECT );
- trap_R_RegisterShaderNoMip( BOTSELECT_SELECTED );
- trap_R_RegisterShaderNoMip( BOTSELECT_ARROWS );
- trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSL );
- trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSR );
-}
-
-
-static void UI_BotSelectMenu_Init( char *bot ) {
- int i, j, k;
- int x, y;
-
- memset( &botSelectInfo, 0 ,sizeof(botSelectInfo) );
- botSelectInfo.menu.wrapAround = qtrue;
- botSelectInfo.menu.fullscreen = qtrue;
-
- UI_BotSelectMenu_Cache();
-
- botSelectInfo.banner.generic.type = MTYPE_BTEXT;
- botSelectInfo.banner.generic.x = 320;
- botSelectInfo.banner.generic.y = 16;
- botSelectInfo.banner.string = "SELECT BOT";
- botSelectInfo.banner.color = color_white;
- botSelectInfo.banner.style = UI_CENTER;
-
- y = 80;
- for( i = 0, k = 0; i < PLAYERGRID_ROWS; i++) {
- x = 180;
- for( j = 0; j < PLAYERGRID_COLS; j++, k++ ) {
- botSelectInfo.pics[k].generic.type = MTYPE_BITMAP;
- botSelectInfo.pics[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- botSelectInfo.pics[k].generic.x = x;
- botSelectInfo.pics[k].generic.y = y;
- botSelectInfo.pics[k].generic.name = botSelectInfo.boticons[k];
- botSelectInfo.pics[k].width = 64;
- botSelectInfo.pics[k].height = 64;
- botSelectInfo.pics[k].focuspic = BOTSELECT_SELECTED;
- botSelectInfo.pics[k].focuscolor = colorRed;
-
- botSelectInfo.picbuttons[k].generic.type = MTYPE_BITMAP;
- botSelectInfo.picbuttons[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS;
- botSelectInfo.picbuttons[k].generic.callback = UI_BotSelectMenu_BotEvent;
- botSelectInfo.picbuttons[k].generic.id = k;
- botSelectInfo.picbuttons[k].generic.x = x - 16;
- botSelectInfo.picbuttons[k].generic.y = y - 16;
- botSelectInfo.picbuttons[k].generic.left = x;
- botSelectInfo.picbuttons[k].generic.top = y;
- botSelectInfo.picbuttons[k].generic.right = x + 64;
- botSelectInfo.picbuttons[k].generic.bottom = y + 64;
- botSelectInfo.picbuttons[k].width = 128;
- botSelectInfo.picbuttons[k].height = 128;
- botSelectInfo.picbuttons[k].focuspic = BOTSELECT_SELECT;
- botSelectInfo.picbuttons[k].focuscolor = colorRed;
-
- botSelectInfo.picnames[k].generic.type = MTYPE_TEXT;
- botSelectInfo.picnames[k].generic.flags = QMF_SMALLFONT;
- botSelectInfo.picnames[k].generic.x = x + 32;
- botSelectInfo.picnames[k].generic.y = y + 64;
- botSelectInfo.picnames[k].string = botSelectInfo.botnames[k];
- botSelectInfo.picnames[k].color = color_orange;
- botSelectInfo.picnames[k].style = UI_CENTER|UI_SMALLFONT;
-
- x += (64 + 6);
- }
- y += (64 + SMALLCHAR_HEIGHT + 6);
- }
-
- botSelectInfo.arrows.generic.type = MTYPE_BITMAP;
- botSelectInfo.arrows.generic.name = BOTSELECT_ARROWS;
- botSelectInfo.arrows.generic.flags = QMF_INACTIVE;
- botSelectInfo.arrows.generic.x = 260;
- botSelectInfo.arrows.generic.y = 440;
- botSelectInfo.arrows.width = 128;
- botSelectInfo.arrows.height = 32;
-
- botSelectInfo.left.generic.type = MTYPE_BITMAP;
- botSelectInfo.left.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- botSelectInfo.left.generic.callback = UI_BotSelectMenu_LeftEvent;
- botSelectInfo.left.generic.x = 260;
- botSelectInfo.left.generic.y = 440;
- botSelectInfo.left.width = 64;
- botSelectInfo.left.height = 32;
- botSelectInfo.left.focuspic = BOTSELECT_ARROWSL;
-
- botSelectInfo.right.generic.type = MTYPE_BITMAP;
- botSelectInfo.right.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- botSelectInfo.right.generic.callback = UI_BotSelectMenu_RightEvent;
- botSelectInfo.right.generic.x = 321;
- botSelectInfo.right.generic.y = 440;
- botSelectInfo.right.width = 64;
- botSelectInfo.right.height = 32;
- botSelectInfo.right.focuspic = BOTSELECT_ARROWSR;
-
- botSelectInfo.back.generic.type = MTYPE_BITMAP;
- botSelectInfo.back.generic.name = BOTSELECT_BACK0;
- botSelectInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- botSelectInfo.back.generic.callback = UI_BotSelectMenu_BackEvent;
- botSelectInfo.back.generic.x = 0;
- botSelectInfo.back.generic.y = 480-64;
- botSelectInfo.back.width = 128;
- botSelectInfo.back.height = 64;
- botSelectInfo.back.focuspic = BOTSELECT_BACK1;
-
- botSelectInfo.go.generic.type = MTYPE_BITMAP;
- botSelectInfo.go.generic.name = BOTSELECT_ACCEPT0;
- botSelectInfo.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- botSelectInfo.go.generic.callback = UI_BotSelectMenu_SelectEvent;
- botSelectInfo.go.generic.x = 640;
- botSelectInfo.go.generic.y = 480-64;
- botSelectInfo.go.width = 128;
- botSelectInfo.go.height = 64;
- botSelectInfo.go.focuspic = BOTSELECT_ACCEPT1;
-
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.banner );
- for( i = 0; i < MAX_MODELSPERPAGE; i++ ) {
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.pics[i] );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.picbuttons[i] );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.picnames[i] );
- }
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.arrows );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.left );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.right );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.back );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.go );
-
- UI_BotSelectMenu_BuildList();
- UI_BotSelectMenu_Default( bot );
- botSelectInfo.modelpage = botSelectInfo.selectedmodel / MAX_MODELSPERPAGE;
- UI_BotSelectMenu_UpdateGrid();
-}
-
-
-/*
-=================
-UI_BotSelectMenu
-=================
-*/
-void UI_BotSelectMenu( char *bot ) {
- UI_BotSelectMenu_Init( bot );
- UI_PushMenu( &botSelectInfo.menu );
-}
diff --git a/engine/code/q3_ui/ui_team.c b/engine/code/q3_ui/ui_team.c
deleted file mode 100644
index e15dde6..0000000
--- a/engine/code/q3_ui/ui_team.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-//
-// ui_team.c
-//
-
-#include "ui_local.h"
-
-
-#define TEAMMAIN_FRAME "menu/art/cut_frame"
-
-#define ID_JOINRED 100
-#define ID_JOINBLUE 101
-#define ID_JOINGAME 102
-#define ID_SPECTATE 103
-
-
-typedef struct
-{
- menuframework_s menu;
- menubitmap_s frame;
- menutext_s joinred;
- menutext_s joinblue;
- menutext_s joingame;
- menutext_s spectate;
-} teammain_t;
-
-static teammain_t s_teammain;
-
-/*
-===============
-TeamMain_MenuEvent
-===============
-*/
-static void TeamMain_MenuEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_JOINRED:
- trap_Cmd_ExecuteText( EXEC_APPEND, "cmd team red\n" );
- UI_ForceMenuOff();
- break;
-
- case ID_JOINBLUE:
- trap_Cmd_ExecuteText( EXEC_APPEND, "cmd team blue\n" );
- UI_ForceMenuOff();
- break;
-
- case ID_JOINGAME:
- trap_Cmd_ExecuteText( EXEC_APPEND, "cmd team free\n" );
- UI_ForceMenuOff();
- break;
-
- case ID_SPECTATE:
- trap_Cmd_ExecuteText( EXEC_APPEND, "cmd team spectator\n" );
- UI_ForceMenuOff();
- break;
- }
-}
-
-
-/*
-===============
-TeamMain_MenuInit
-===============
-*/
-void TeamMain_MenuInit( void ) {
- int y;
- int gametype;
- char info[MAX_INFO_STRING];
-
- memset( &s_teammain, 0, sizeof(s_teammain) );
-
- TeamMain_Cache();
-
- s_teammain.menu.wrapAround = qtrue;
- s_teammain.menu.fullscreen = qfalse;
-
- s_teammain.frame.generic.type = MTYPE_BITMAP;
- s_teammain.frame.generic.flags = QMF_INACTIVE;
- s_teammain.frame.generic.name = TEAMMAIN_FRAME;
- s_teammain.frame.generic.x = 142;
- s_teammain.frame.generic.y = 118;
- s_teammain.frame.width = 359;
- s_teammain.frame.height = 256;
-
- y = 194;
-
- s_teammain.joinred.generic.type = MTYPE_PTEXT;
- s_teammain.joinred.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_teammain.joinred.generic.id = ID_JOINRED;
- s_teammain.joinred.generic.callback = TeamMain_MenuEvent;
- s_teammain.joinred.generic.x = 320;
- s_teammain.joinred.generic.y = y;
- s_teammain.joinred.string = "JOIN RED";
- s_teammain.joinred.style = UI_CENTER|UI_SMALLFONT;
- s_teammain.joinred.color = colorRed;
- y += 20;
-
- s_teammain.joinblue.generic.type = MTYPE_PTEXT;
- s_teammain.joinblue.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_teammain.joinblue.generic.id = ID_JOINBLUE;
- s_teammain.joinblue.generic.callback = TeamMain_MenuEvent;
- s_teammain.joinblue.generic.x = 320;
- s_teammain.joinblue.generic.y = y;
- s_teammain.joinblue.string = "JOIN BLUE";
- s_teammain.joinblue.style = UI_CENTER|UI_SMALLFONT;
- s_teammain.joinblue.color = colorRed;
- y += 20;
-
- s_teammain.joingame.generic.type = MTYPE_PTEXT;
- s_teammain.joingame.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_teammain.joingame.generic.id = ID_JOINGAME;
- s_teammain.joingame.generic.callback = TeamMain_MenuEvent;
- s_teammain.joingame.generic.x = 320;
- s_teammain.joingame.generic.y = y;
- s_teammain.joingame.string = "JOIN GAME";
- s_teammain.joingame.style = UI_CENTER|UI_SMALLFONT;
- s_teammain.joingame.color = colorRed;
- y += 20;
-
- s_teammain.spectate.generic.type = MTYPE_PTEXT;
- s_teammain.spectate.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_teammain.spectate.generic.id = ID_SPECTATE;
- s_teammain.spectate.generic.callback = TeamMain_MenuEvent;
- s_teammain.spectate.generic.x = 320;
- s_teammain.spectate.generic.y = y;
- s_teammain.spectate.string = "SPECTATE";
- s_teammain.spectate.style = UI_CENTER|UI_SMALLFONT;
- s_teammain.spectate.color = colorRed;
- y += 20;
-
- trap_GetConfigString(CS_SERVERINFO, info, MAX_INFO_STRING);
- gametype = atoi( Info_ValueForKey( info,"g_gametype" ) );
-
- // set initial states
- switch( gametype ) {
- case GT_SINGLE_PLAYER:
- case GT_FFA:
- case GT_TOURNAMENT:
- s_teammain.joinred.generic.flags |= QMF_GRAYED;
- s_teammain.joinblue.generic.flags |= QMF_GRAYED;
- break;
-
- default:
- case GT_TEAM:
- case GT_CTF:
- s_teammain.joingame.generic.flags |= QMF_GRAYED;
- break;
- }
-
- Menu_AddItem( &s_teammain.menu, (void*) &s_teammain.frame );
- Menu_AddItem( &s_teammain.menu, (void*) &s_teammain.joinred );
- Menu_AddItem( &s_teammain.menu, (void*) &s_teammain.joinblue );
- Menu_AddItem( &s_teammain.menu, (void*) &s_teammain.joingame );
- Menu_AddItem( &s_teammain.menu, (void*) &s_teammain.spectate );
-}
-
-
-/*
-===============
-TeamMain_Cache
-===============
-*/
-void TeamMain_Cache( void ) {
- trap_R_RegisterShaderNoMip( TEAMMAIN_FRAME );
-}
-
-
-/*
-===============
-UI_TeamMainMenu
-===============
-*/
-void UI_TeamMainMenu( void ) {
- TeamMain_MenuInit();
- UI_PushMenu ( &s_teammain.menu );
-}
diff --git a/engine/code/q3_ui/ui_teamorders.c b/engine/code/q3_ui/ui_teamorders.c
deleted file mode 100644
index d116e01..0000000
--- a/engine/code/q3_ui/ui_teamorders.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-TEAM ORDERS MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define ART_FRAME "menu/art/addbotframe"
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-
-#define ID_LIST_BOTS 10
-#define ID_LIST_CTF_ORDERS 11
-#define ID_LIST_TEAM_ORDERS 12
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s frame;
-
- menulist_s list;
-
- menubitmap_s back;
-
- int gametype;
- int numBots;
- int selectedBot;
- char *bots[9];
- char botNames[9][16];
-} teamOrdersMenuInfo_t;
-
-static teamOrdersMenuInfo_t teamOrdersMenuInfo;
-
-#define NUM_CTF_ORDERS 7
-static const char *ctfOrders[] = {
- "I Am the Leader",
- "Defend the Base",
- "Follow Me",
- "Get Enemy Flag",
- "Camp Here",
- "Report",
- "I Relinquish Command",
- NULL
-};
-static const char *ctfMessages[] = {
- "i am the leader",
- "%s defend the base",
- "%s follow me",
- "%s get enemy flag",
- "%s camp here",
- "%s report",
- "i stop being the leader",
- NULL
-};
-
-#define NUM_TEAM_ORDERS 6
-static const char *teamOrders[] = {
- "I Am the Leader",
- "Follow Me",
- "Roam",
- "Camp Here",
- "Report",
- "I Relinquish Command",
- NULL
-};
-static const char *teamMessages[] = {
- "i am the leader",
- "%s follow me",
- "%s roam",
- "%s camp here",
- "%s report",
- "i stop being the leader",
- NULL
-};
-
-
-/*
-===============
-UI_TeamOrdersMenu_BackEvent
-===============
-*/
-static void UI_TeamOrdersMenu_BackEvent( void *ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- UI_PopMenu();
-}
-
-
-/*
-===============
-UI_TeamOrdersMenu_SetList
-===============
-*/
-static void UI_TeamOrdersMenu_SetList( int id ) {
- switch( id ) {
- default:
- case ID_LIST_BOTS:
- teamOrdersMenuInfo.list.generic.id = id;
- teamOrdersMenuInfo.list.numitems = teamOrdersMenuInfo.numBots;
- teamOrdersMenuInfo.list.itemnames = (const char **)teamOrdersMenuInfo.bots;
- break;
-
- case ID_LIST_CTF_ORDERS:
- teamOrdersMenuInfo.list.generic.id = id;
- teamOrdersMenuInfo.list.numitems = NUM_CTF_ORDERS;
- teamOrdersMenuInfo.list.itemnames = ctfOrders;
- break;
-
- case ID_LIST_TEAM_ORDERS:
- teamOrdersMenuInfo.list.generic.id = id;
- teamOrdersMenuInfo.list.numitems = NUM_TEAM_ORDERS;
- teamOrdersMenuInfo.list.itemnames = teamOrders;
- break;
- }
-
- teamOrdersMenuInfo.list.generic.bottom = teamOrdersMenuInfo.list.generic.top + teamOrdersMenuInfo.list.numitems * PROP_HEIGHT;
-}
-
-
-/*
-=================
-UI_TeamOrdersMenu_Key
-=================
-*/
-sfxHandle_t UI_TeamOrdersMenu_Key( int key ) {
- menulist_s *l;
- int x;
- int y;
- int index;
-
- l = (menulist_s *)Menu_ItemAtCursor( &teamOrdersMenuInfo.menu );
- if( l != &teamOrdersMenuInfo.list ) {
- return Menu_DefaultKey( &teamOrdersMenuInfo.menu, key );
- }
-
- switch( key ) {
- case K_MOUSE1:
- x = l->generic.left;
- y = l->generic.top;
- if( UI_CursorInRect( x, y, l->generic.right - x, l->generic.bottom - y ) ) {
- index = (uis.cursory - y) / PROP_HEIGHT;
- l->oldvalue = l->curvalue;
- l->curvalue = index;
-
- if( l->generic.callback ) {
- l->generic.callback( l, QM_ACTIVATED );
- return menu_move_sound;
- }
- }
- return menu_null_sound;
-
- case K_KP_UPARROW:
- case K_UPARROW:
- l->oldvalue = l->curvalue;
-
- if( l->curvalue == 0 ) {
- l->curvalue = l->numitems - 1;
- }
- else {
- l->curvalue--;
- }
- return menu_move_sound;
-
- case K_KP_DOWNARROW:
- case K_DOWNARROW:
- l->oldvalue = l->curvalue;
-
- if( l->curvalue == l->numitems - 1 ) {
- l->curvalue = 0;;
- }
- else {
- l->curvalue++;
- }
- return menu_move_sound;
- }
-
- return Menu_DefaultKey( &teamOrdersMenuInfo.menu, key );
-}
-
-
-/*
-=================
-UI_TeamOrdersMenu_ListDraw
-=================
-*/
-static void UI_TeamOrdersMenu_ListDraw( void *self ) {
- menulist_s *l;
- int x;
- int y;
- int i;
- float *color;
- qboolean hasfocus;
- int style;
-
- l = (menulist_s *)self;
-
- hasfocus = (l->generic.parent->cursor == l->generic.menuPosition);
-
- x = 320;//l->generic.x;
- y = l->generic.y;
- for( i = 0; i < l->numitems; i++ ) {
- style = UI_LEFT|UI_SMALLFONT|UI_CENTER;
- if( i == l->curvalue ) {
- color = color_yellow;
- if( hasfocus ) {
- style |= UI_PULSE;
- }
- }
- else {
- color = color_orange;
- }
-
- UI_DrawProportionalString( x, y, l->itemnames[i], style, color );
- y += PROP_HEIGHT;
- }
-}
-
-
-/*
-===============
-UI_TeamOrdersMenu_ListEvent
-===============
-*/
-static void UI_TeamOrdersMenu_ListEvent( void *ptr, int event ) {
- int id;
- int selection;
- char message[256];
-
- if (event != QM_ACTIVATED)
- return;
-
- id = ((menulist_s *)ptr)->generic.id;
- selection = ((menulist_s *)ptr)->curvalue;
-
- if( id == ID_LIST_BOTS ) {
- teamOrdersMenuInfo.selectedBot = selection;
- if( teamOrdersMenuInfo.gametype == GT_CTF ) {
- UI_TeamOrdersMenu_SetList( ID_LIST_CTF_ORDERS );
- }
- else {
- UI_TeamOrdersMenu_SetList( ID_LIST_TEAM_ORDERS );
- }
- return;
- }
-
- if( id == ID_LIST_CTF_ORDERS ) {
- Com_sprintf( message, sizeof(message), ctfMessages[selection], teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.selectedBot] );
- }
- else {
- Com_sprintf( message, sizeof(message), teamMessages[selection], teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.selectedBot] );
- }
-
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "say_team \"%s\"\n", message ) );
- UI_PopMenu();
-}
-
-
-/*
-===============
-UI_TeamOrdersMenu_BuildBotList
-===============
-*/
-static void UI_TeamOrdersMenu_BuildBotList( void ) {
- uiClientState_t cs;
- int numPlayers;
- int isBot;
- int n;
- char playerTeam = '3';
- char botTeam;
- char info[MAX_INFO_STRING];
-
- for( n = 0; n < 9; n++ ) {
- teamOrdersMenuInfo.bots[n] = teamOrdersMenuInfo.botNames[n];
- }
-
- trap_GetClientState( &cs );
-
- Q_strncpyz( teamOrdersMenuInfo.botNames[0], "Everyone", 16 );
- teamOrdersMenuInfo.numBots = 1;
-
- trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
- numPlayers = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
- teamOrdersMenuInfo.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
-
- for( n = 0; n < numPlayers && teamOrdersMenuInfo.numBots < 9; n++ ) {
- trap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING );
-
- if( n == cs.clientNum ) {
- playerTeam = *Info_ValueForKey( info, "t" );
- continue;
- }
-
- isBot = atoi( Info_ValueForKey( info, "skill" ) );
- if( !isBot ) {
- continue;
- }
-
- botTeam = *Info_ValueForKey( info, "t" );
- if( botTeam != playerTeam ) {
- continue;
- }
-
- Q_strncpyz( teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.numBots], Info_ValueForKey( info, "n" ), 16 );
- Q_CleanStr( teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.numBots] );
- teamOrdersMenuInfo.numBots++;
- }
-}
-
-
-/*
-===============
-UI_TeamOrdersMenu_Init
-===============
-*/
-static void UI_TeamOrdersMenu_Init( void ) {
- UI_TeamOrdersMenu_Cache();
-
- memset( &teamOrdersMenuInfo, 0, sizeof(teamOrdersMenuInfo) );
- teamOrdersMenuInfo.menu.fullscreen = qfalse;
- teamOrdersMenuInfo.menu.key = UI_TeamOrdersMenu_Key;
-
- UI_TeamOrdersMenu_BuildBotList();
-
- teamOrdersMenuInfo.banner.generic.type = MTYPE_BTEXT;
- teamOrdersMenuInfo.banner.generic.x = 320;
- teamOrdersMenuInfo.banner.generic.y = 16;
- teamOrdersMenuInfo.banner.string = "TEAM ORDERS";
- teamOrdersMenuInfo.banner.color = color_white;
- teamOrdersMenuInfo.banner.style = UI_CENTER;
-
- teamOrdersMenuInfo.frame.generic.type = MTYPE_BITMAP;
- teamOrdersMenuInfo.frame.generic.flags = QMF_INACTIVE;
- teamOrdersMenuInfo.frame.generic.name = ART_FRAME;
- teamOrdersMenuInfo.frame.generic.x = 320-233;
- teamOrdersMenuInfo.frame.generic.y = 240-166;
- teamOrdersMenuInfo.frame.width = 466;
- teamOrdersMenuInfo.frame.height = 332;
-
- teamOrdersMenuInfo.list.generic.type = MTYPE_SCROLLLIST;
- teamOrdersMenuInfo.list.generic.flags = QMF_PULSEIFFOCUS;
- teamOrdersMenuInfo.list.generic.ownerdraw = UI_TeamOrdersMenu_ListDraw;
- teamOrdersMenuInfo.list.generic.callback = UI_TeamOrdersMenu_ListEvent;
- teamOrdersMenuInfo.list.generic.x = 320-64;
- teamOrdersMenuInfo.list.generic.y = 120;
-
- teamOrdersMenuInfo.back.generic.type = MTYPE_BITMAP;
- teamOrdersMenuInfo.back.generic.name = ART_BACK0;
- teamOrdersMenuInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- teamOrdersMenuInfo.back.generic.callback = UI_TeamOrdersMenu_BackEvent;
- teamOrdersMenuInfo.back.generic.x = 0;
- teamOrdersMenuInfo.back.generic.y = 480-64;
- teamOrdersMenuInfo.back.width = 128;
- teamOrdersMenuInfo.back.height = 64;
- teamOrdersMenuInfo.back.focuspic = ART_BACK1;
-
- Menu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.banner );
- Menu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.frame );
- Menu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.list );
- Menu_AddItem( &teamOrdersMenuInfo.menu, &teamOrdersMenuInfo.back );
-
- teamOrdersMenuInfo.list.generic.left = 220;
- teamOrdersMenuInfo.list.generic.top = teamOrdersMenuInfo.list.generic.y;
- teamOrdersMenuInfo.list.generic.right = 420;
- UI_TeamOrdersMenu_SetList( ID_LIST_BOTS );
-}
-
-
-/*
-=================
-UI_TeamOrdersMenu_Cache
-=================
-*/
-void UI_TeamOrdersMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_FRAME );
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
-}
-
-
-/*
-===============
-UI_TeamOrdersMenu
-===============
-*/
-void UI_TeamOrdersMenu( void ) {
- UI_TeamOrdersMenu_Init();
- UI_PushMenu( &teamOrdersMenuInfo.menu );
-}
-
-
-/*
-===============
-UI_TeamOrdersMenu_f
-===============
-*/
-void UI_TeamOrdersMenu_f( void ) {
- uiClientState_t cs;
- char info[MAX_INFO_STRING];
- int team;
-
- // make sure it's a team game
- trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
- teamOrdersMenuInfo.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
- if( teamOrdersMenuInfo.gametype < GT_TEAM ) {
- return;
- }
-
- // not available to spectators
- trap_GetClientState( &cs );
- trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );
- team = atoi( Info_ValueForKey( info, "t" ) );
- if( team == TEAM_SPECTATOR ) {
- return;
- }
-
- UI_TeamOrdersMenu();
-}
diff --git a/engine/code/q3_ui/ui_video.c b/engine/code/q3_ui/ui_video.c
deleted file mode 100644
index 160037d..0000000
--- a/engine/code/q3_ui/ui_video.c
+++ /dev/null
@@ -1,1289 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-void GraphicsOptions_MenuInit( void );
-
-/*
-=======================================================================
-
-DRIVER INFORMATION MENU
-
-=======================================================================
-*/
-
-
-#define DRIVERINFO_FRAMEL "menu/art/frame2_l"
-#define DRIVERINFO_FRAMER "menu/art/frame1_r"
-#define DRIVERINFO_BACK0 "menu/art/back_0"
-#define DRIVERINFO_BACK1 "menu/art/back_1"
-
-static char* driverinfo_artlist[] =
-{
- DRIVERINFO_FRAMEL,
- DRIVERINFO_FRAMER,
- DRIVERINFO_BACK0,
- DRIVERINFO_BACK1,
- NULL,
-};
-
-#define ID_DRIVERINFOBACK 100
-
-typedef struct
-{
- menuframework_s menu;
- menutext_s banner;
- menubitmap_s back;
- menubitmap_s framel;
- menubitmap_s framer;
- char stringbuff[1024];
- char* strings[64];
- int numstrings;
-} driverinfo_t;
-
-static driverinfo_t s_driverinfo;
-
-/*
-=================
-DriverInfo_Event
-=================
-*/
-static void DriverInfo_Event( void* ptr, int event )
-{
- if (event != QM_ACTIVATED)
- return;
-
- switch (((menucommon_s*)ptr)->id)
- {
- case ID_DRIVERINFOBACK:
- UI_PopMenu();
- break;
- }
-}
-
-/*
-=================
-DriverInfo_MenuDraw
-=================
-*/
-static void DriverInfo_MenuDraw( void )
-{
- int i;
- int y;
-
- Menu_Draw( &s_driverinfo.menu );
-
- UI_DrawString( 320, 80, "VENDOR", UI_CENTER|UI_SMALLFONT, color_red );
- UI_DrawString( 320, 152, "PIXELFORMAT", UI_CENTER|UI_SMALLFONT, color_red );
- UI_DrawString( 320, 192, "EXTENSIONS", UI_CENTER|UI_SMALLFONT, color_red );
-
- UI_DrawString( 320, 80+16, uis.glconfig.vendor_string, UI_CENTER|UI_SMALLFONT, text_color_normal );
- UI_DrawString( 320, 96+16, uis.glconfig.version_string, UI_CENTER|UI_SMALLFONT, text_color_normal );
- UI_DrawString( 320, 112+16, uis.glconfig.renderer_string, UI_CENTER|UI_SMALLFONT, text_color_normal );
- UI_DrawString( 320, 152+16, va ("color(%d-bits) Z(%d-bits) stencil(%d-bits)", uis.glconfig.colorBits, uis.glconfig.depthBits, uis.glconfig.stencilBits), UI_CENTER|UI_SMALLFONT, text_color_normal );
-
- // double column
- y = 192+16;
- for (i=0; i<s_driverinfo.numstrings/2; i++) {
- UI_DrawString( 320-4, y, s_driverinfo.strings[i*2], UI_RIGHT|UI_SMALLFONT, text_color_normal );
- UI_DrawString( 320+4, y, s_driverinfo.strings[i*2+1], UI_LEFT|UI_SMALLFONT, text_color_normal );
- y += SMALLCHAR_HEIGHT;
- }
-
- if (s_driverinfo.numstrings & 1)
- UI_DrawString( 320, y, s_driverinfo.strings[s_driverinfo.numstrings-1], UI_CENTER|UI_SMALLFONT, text_color_normal );
-}
-
-/*
-=================
-DriverInfo_Cache
-=================
-*/
-void DriverInfo_Cache( void )
-{
- int i;
-
- // touch all our pics
- for (i=0; ;i++)
- {
- if (!driverinfo_artlist[i])
- break;
- trap_R_RegisterShaderNoMip(driverinfo_artlist[i]);
- }
-}
-
-/*
-=================
-UI_DriverInfo_Menu
-=================
-*/
-static void UI_DriverInfo_Menu( void )
-{
- char* eptr;
- int i;
- int len;
-
- // zero set all our globals
- memset( &s_driverinfo, 0 ,sizeof(driverinfo_t) );
-
- DriverInfo_Cache();
-
- s_driverinfo.menu.fullscreen = qtrue;
- s_driverinfo.menu.draw = DriverInfo_MenuDraw;
-
- s_driverinfo.banner.generic.type = MTYPE_BTEXT;
- s_driverinfo.banner.generic.x = 320;
- s_driverinfo.banner.generic.y = 16;
- s_driverinfo.banner.string = "DRIVER INFO";
- s_driverinfo.banner.color = color_white;
- s_driverinfo.banner.style = UI_CENTER;
-
- s_driverinfo.framel.generic.type = MTYPE_BITMAP;
- s_driverinfo.framel.generic.name = DRIVERINFO_FRAMEL;
- s_driverinfo.framel.generic.flags = QMF_INACTIVE;
- s_driverinfo.framel.generic.x = 0;
- s_driverinfo.framel.generic.y = 78;
- s_driverinfo.framel.width = 256;
- s_driverinfo.framel.height = 329;
-
- s_driverinfo.framer.generic.type = MTYPE_BITMAP;
- s_driverinfo.framer.generic.name = DRIVERINFO_FRAMER;
- s_driverinfo.framer.generic.flags = QMF_INACTIVE;
- s_driverinfo.framer.generic.x = 376;
- s_driverinfo.framer.generic.y = 76;
- s_driverinfo.framer.width = 256;
- s_driverinfo.framer.height = 334;
-
- s_driverinfo.back.generic.type = MTYPE_BITMAP;
- s_driverinfo.back.generic.name = DRIVERINFO_BACK0;
- s_driverinfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_driverinfo.back.generic.callback = DriverInfo_Event;
- s_driverinfo.back.generic.id = ID_DRIVERINFOBACK;
- s_driverinfo.back.generic.x = 0;
- s_driverinfo.back.generic.y = 480-64;
- s_driverinfo.back.width = 128;
- s_driverinfo.back.height = 64;
- s_driverinfo.back.focuspic = DRIVERINFO_BACK1;
-
- // TTimo: overflow with particularly long GL extensions (such as the gf3)
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=399
- // NOTE: could have pushed the size of stringbuff, but the list is already out of the screen
- // (no matter what your resolution)
- Q_strncpyz(s_driverinfo.stringbuff, uis.glconfig.extensions_string, 1024);
-
- // build null terminated extension strings
- eptr = s_driverinfo.stringbuff;
- while ( s_driverinfo.numstrings<40 && *eptr )
- {
- while ( *eptr && *eptr == ' ' )
- *eptr++ = '\0';
-
- // track start of valid string
- if (*eptr && *eptr != ' ')
- s_driverinfo.strings[s_driverinfo.numstrings++] = eptr;
-
- while ( *eptr && *eptr != ' ' )
- eptr++;
- }
-
- // safety length strings for display
- for (i=0; i<s_driverinfo.numstrings; i++) {
- len = strlen(s_driverinfo.strings[i]);
- if (len > 32) {
- s_driverinfo.strings[i][len-1] = '>';
- s_driverinfo.strings[i][len] = '\0';
- }
- }
-
- Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.banner );
- Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.framel );
- Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.framer );
- Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.back );
-
- UI_PushMenu( &s_driverinfo.menu );
-}
-
-/*
-=======================================================================
-
-GRAPHICS OPTIONS MENU
-
-=======================================================================
-*/
-
-#define GRAPHICSOPTIONS_FRAMEL "menu/art/frame2_l"
-#define GRAPHICSOPTIONS_FRAMER "menu/art/frame1_r"
-#define GRAPHICSOPTIONS_BACK0 "menu/art/back_0"
-#define GRAPHICSOPTIONS_BACK1 "menu/art/back_1"
-#define GRAPHICSOPTIONS_ACCEPT0 "menu/art/accept_0"
-#define GRAPHICSOPTIONS_ACCEPT1 "menu/art/accept_1"
-
-#define ID_BACK2 101
-#define ID_FULLSCREEN 102
-#define ID_LIST 103
-#define ID_MODE 104
-#define ID_DRIVERINFO 105
-#define ID_GRAPHICS 106
-#define ID_DISPLAY 107
-#define ID_SOUND 108
-#define ID_NETWORK 109
-#define ID_RATIO 110
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menutext_s graphics;
- menutext_s display;
- menutext_s sound;
- menutext_s network;
-
- menulist_s list;
- menulist_s ratio;
- menulist_s mode;
- menulist_s driver;
- menuslider_s tq;
- menulist_s fs;
- menulist_s lighting;
- menulist_s allow_extensions;
- menulist_s texturebits;
- menulist_s colordepth;
- menulist_s geometry;
- menulist_s filter;
- menutext_s driverinfo;
-
- menubitmap_s apply;
- menubitmap_s back;
-} graphicsoptions_t;
-
-typedef struct
-{
- int mode;
- qboolean fullscreen;
- int tq;
- int lighting;
- int colordepth;
- int texturebits;
- int geometry;
- int filter;
- int driver;
- qboolean extensions;
-} InitialVideoOptions_s;
-
-static InitialVideoOptions_s s_ivo;
-static graphicsoptions_t s_graphicsoptions;
-
-static InitialVideoOptions_s s_ivo_templates[] =
-{
- {
- 6, qtrue, 3, 0, 2, 2, 2, 1, 0, qtrue
- },
- {
- 4, qtrue, 2, 0, 2, 2, 1, 1, 0, qtrue // JDC: this was tq 3
- },
- {
- 3, qtrue, 2, 0, 0, 0, 1, 0, 0, qtrue
- },
- {
- 2, qtrue, 1, 0, 1, 0, 0, 0, 0, qtrue
- },
- {
- 2, qtrue, 1, 1, 1, 0, 0, 0, 0, qtrue
- },
- {
- 3, qtrue, 1, 0, 0, 0, 1, 0, 0, qtrue
- }
-};
-
-#define NUM_IVO_TEMPLATES ( sizeof( s_ivo_templates ) / sizeof( s_ivo_templates[0] ) )
-
-static const char *builtinResolutions[ ] =
-{
- "320x240",
- "400x300",
- "512x384",
- "640x480",
- "800x600",
- "960x720",
- "1024x768",
- "1152x864",
- "1280x1024",
- "1600x1200",
- "2048x1536",
- "856x480",
- NULL
-};
-
-static const char *knownRatios[ ][2] =
-{
- { "1.25:1", "5:4" },
- { "1.33:1", "4:3" },
- { "1.50:1", "3:2" },
- { "1.56:1", "14:9" },
- { "1.60:1", "16:10" },
- { "1.67:1", "5:3" },
- { "1.78:1", "16:9" },
- { NULL , NULL }
-};
-
-#define MAX_RESOLUTIONS 32
-
-static const char* ratios[ MAX_RESOLUTIONS ];
-static char ratioBuf[ MAX_RESOLUTIONS ][ 8 ];
-static int ratioToRes[ MAX_RESOLUTIONS ];
-static int resToRatio[ MAX_RESOLUTIONS ];
-
-static char resbuf[ MAX_STRING_CHARS ];
-static const char* detectedResolutions[ MAX_RESOLUTIONS ];
-
-static const char** resolutions = builtinResolutions;
-static qboolean resolutionsDetected = qfalse;
-
-/*
-=================
-GraphicsOptions_FindBuiltinResolution
-=================
-*/
-static int GraphicsOptions_FindBuiltinResolution( int mode )
-{
- int i;
-
- if( !resolutionsDetected )
- return mode;
-
- if( mode < 0 )
- return -1;
-
- for( i = 0; builtinResolutions[ i ]; i++ )
- {
- if( !Q_stricmp( builtinResolutions[ i ], detectedResolutions[ mode ] ) )
- return i;
- }
-
- return -1;
-}
-
-/*
-=================
-GraphicsOptions_FindDetectedResolution
-=================
-*/
-static int GraphicsOptions_FindDetectedResolution( int mode )
-{
- int i;
-
- if( !resolutionsDetected )
- return mode;
-
- if( mode < 0 )
- return -1;
-
- for( i = 0; detectedResolutions[ i ]; i++ )
- {
- if( !Q_stricmp( builtinResolutions[ mode ], detectedResolutions[ i ] ) )
- return i;
- }
-
- return -1;
-}
-
-/*
-=================
-GraphicsOptions_GetAspectRatios
-=================
-*/
-static void GraphicsOptions_GetAspectRatios( void )
-{
- int i, r;
-
- // build ratio list from resolutions
- for( r = 0; resolutions[r]; r++ )
- {
- int w, h;
- char *x;
- char str[ sizeof(ratioBuf[0]) ];
-
- // calculate resolution's aspect ratio
- x = strchr( resolutions[r], 'x' ) + 1;
- Q_strncpyz( str, resolutions[r], x-resolutions[r] );
- w = atoi( str );
- h = atoi( x );
- Com_sprintf( str, sizeof(str), "%.2f:1", (float)w / (float)h );
-
- // add ratio to list if it is new
- // establish res/ratio relationship
- for( i = 0; ratioBuf[i][0]; i++ )
- {
- if( !Q_stricmp( str, ratioBuf[i] ) )
- break;
- }
- if( !ratioBuf[i][0] )
- {
- Q_strncpyz( ratioBuf[i], str, sizeof(ratioBuf[i]) );
- ratioToRes[i] = r;
- }
- resToRatio[r] = i;
- }
-
- // prepare itemlist pointer array
- // rename common ratios ("1.33:1" -> "4:3")
- for( r = 0; ratioBuf[r][0]; r++ )
- {
- for( i = 0; knownRatios[i][0]; i++ )
- {
- if( !Q_stricmp( ratioBuf[r], knownRatios[i][0] ) )
- {
- Q_strncpyz( ratioBuf[r], knownRatios[i][1], sizeof(ratioBuf[r]) );
- break;
- }
- }
- ratios[r] = ratioBuf[r];
- }
- ratios[r] = NULL;
-}
-
-/*
-=================
-GraphicsOptions_GetInitialVideo
-=================
-*/
-static void GraphicsOptions_GetInitialVideo( void )
-{
- s_ivo.colordepth = s_graphicsoptions.colordepth.curvalue;
- s_ivo.driver = s_graphicsoptions.driver.curvalue;
- s_ivo.mode = s_graphicsoptions.mode.curvalue;
- s_ivo.fullscreen = s_graphicsoptions.fs.curvalue;
- s_ivo.extensions = s_graphicsoptions.allow_extensions.curvalue;
- s_ivo.tq = s_graphicsoptions.tq.curvalue;
- s_ivo.lighting = s_graphicsoptions.lighting.curvalue;
- s_ivo.geometry = s_graphicsoptions.geometry.curvalue;
- s_ivo.filter = s_graphicsoptions.filter.curvalue;
- s_ivo.texturebits = s_graphicsoptions.texturebits.curvalue;
-}
-
-/*
-=================
-GraphicsOptions_GetResolutions
-=================
-*/
-static void GraphicsOptions_GetResolutions( void )
-{
- Q_strncpyz(resbuf, UI_Cvar_VariableString("r_availableModes"), sizeof(resbuf));
- if(*resbuf)
- {
- char* s = resbuf;
- unsigned int i = 0;
- while( s && i < sizeof(detectedResolutions)/sizeof(detectedResolutions[0])-1)
- {
- detectedResolutions[i++] = s;
- s = strchr(s, ' ');
- if( s )
- *s++ = '\0';
- }
- detectedResolutions[ i ] = NULL;
-
- if( i > 0 )
- {
- resolutions = detectedResolutions;
- resolutionsDetected = qtrue;
- }
- }
-}
-
-/*
-=================
-GraphicsOptions_CheckConfig
-=================
-*/
-static void GraphicsOptions_CheckConfig( void )
-{
- int i;
-
- for ( i = 0; i < NUM_IVO_TEMPLATES-1; i++ )
- {
- if ( s_ivo_templates[i].colordepth != s_graphicsoptions.colordepth.curvalue )
- continue;
- if ( s_ivo_templates[i].driver != s_graphicsoptions.driver.curvalue )
- continue;
- if ( GraphicsOptions_FindDetectedResolution(s_ivo_templates[i].mode) != s_graphicsoptions.mode.curvalue )
- continue;
- if ( s_ivo_templates[i].fullscreen != s_graphicsoptions.fs.curvalue )
- continue;
- if ( s_ivo_templates[i].tq != s_graphicsoptions.tq.curvalue )
- continue;
- if ( s_ivo_templates[i].lighting != s_graphicsoptions.lighting.curvalue )
- continue;
- if ( s_ivo_templates[i].geometry != s_graphicsoptions.geometry.curvalue )
- continue;
- if ( s_ivo_templates[i].filter != s_graphicsoptions.filter.curvalue )
- continue;
-// if ( s_ivo_templates[i].texturebits != s_graphicsoptions.texturebits.curvalue )
-// continue;
- s_graphicsoptions.list.curvalue = i;
- return;
- }
-
- // return 'Custom' ivo template
- s_graphicsoptions.list.curvalue = NUM_IVO_TEMPLATES - 1;
-}
-
-/*
-=================
-GraphicsOptions_UpdateMenuItems
-=================
-*/
-static void GraphicsOptions_UpdateMenuItems( void )
-{
- if ( s_graphicsoptions.driver.curvalue == 1 )
- {
- s_graphicsoptions.fs.curvalue = 1;
- s_graphicsoptions.fs.generic.flags |= QMF_GRAYED;
- s_graphicsoptions.colordepth.curvalue = 1;
- }
- else
- {
- s_graphicsoptions.fs.generic.flags &= ~QMF_GRAYED;
- }
-
- if ( s_graphicsoptions.fs.curvalue == 0 || s_graphicsoptions.driver.curvalue == 1 )
- {
- s_graphicsoptions.colordepth.curvalue = 0;
- s_graphicsoptions.colordepth.generic.flags |= QMF_GRAYED;
- }
- else
- {
- s_graphicsoptions.colordepth.generic.flags &= ~QMF_GRAYED;
- }
-
- if ( s_graphicsoptions.allow_extensions.curvalue == 0 )
- {
- if ( s_graphicsoptions.texturebits.curvalue == 0 )
- {
- s_graphicsoptions.texturebits.curvalue = 1;
- }
- }
-
- s_graphicsoptions.apply.generic.flags |= QMF_HIDDEN|QMF_INACTIVE;
-
- if ( s_ivo.mode != s_graphicsoptions.mode.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.fullscreen != s_graphicsoptions.fs.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.extensions != s_graphicsoptions.allow_extensions.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.tq != s_graphicsoptions.tq.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.lighting != s_graphicsoptions.lighting.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.colordepth != s_graphicsoptions.colordepth.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.driver != s_graphicsoptions.driver.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.texturebits != s_graphicsoptions.texturebits.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.geometry != s_graphicsoptions.geometry.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.filter != s_graphicsoptions.filter.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
-
- GraphicsOptions_CheckConfig();
-}
-
-/*
-=================
-GraphicsOptions_ApplyChanges
-=================
-*/
-static void GraphicsOptions_ApplyChanges( void *unused, int notification )
-{
- if (notification != QM_ACTIVATED)
- return;
-
- switch ( s_graphicsoptions.texturebits.curvalue )
- {
- case 0:
- trap_Cvar_SetValue( "r_texturebits", 0 );
- break;
- case 1:
- trap_Cvar_SetValue( "r_texturebits", 16 );
- break;
- case 2:
- trap_Cvar_SetValue( "r_texturebits", 32 );
- break;
- }
- trap_Cvar_SetValue( "r_picmip", 3 - s_graphicsoptions.tq.curvalue );
- trap_Cvar_SetValue( "r_allowExtensions", s_graphicsoptions.allow_extensions.curvalue );
-
- if( resolutionsDetected )
- {
- // search for builtin mode that matches the detected mode
- int mode;
- if ( s_graphicsoptions.mode.curvalue == -1
- || s_graphicsoptions.mode.curvalue >= sizeof(detectedResolutions)/sizeof(detectedResolutions[0]) )
- s_graphicsoptions.mode.curvalue = 0;
-
- mode = GraphicsOptions_FindBuiltinResolution( s_graphicsoptions.mode.curvalue );
- if( mode == -1 )
- {
- char w[ 16 ], h[ 16 ];
- Q_strncpyz( w, detectedResolutions[ s_graphicsoptions.mode.curvalue ], sizeof( w ) );
- *strchr( w, 'x' ) = 0;
- Q_strncpyz( h,
- strchr( detectedResolutions[ s_graphicsoptions.mode.curvalue ], 'x' ) + 1, sizeof( h ) );
- trap_Cvar_Set( "r_customwidth", w );
- trap_Cvar_Set( "r_customheight", h );
- }
-
- trap_Cvar_SetValue( "r_mode", mode );
- }
- else
- trap_Cvar_SetValue( "r_mode", s_graphicsoptions.mode.curvalue );
-
- trap_Cvar_SetValue( "r_fullscreen", s_graphicsoptions.fs.curvalue );
- trap_Cvar_SetValue( "r_colorbits", 0 );
- trap_Cvar_SetValue( "r_depthbits", 0 );
- trap_Cvar_SetValue( "r_stencilbits", 0 );
- trap_Cvar_SetValue( "r_vertexLight", s_graphicsoptions.lighting.curvalue );
-
- if ( s_graphicsoptions.geometry.curvalue == 2 )
- {
- trap_Cvar_SetValue( "r_lodBias", 0 );
- trap_Cvar_SetValue( "r_subdivisions", 4 );
- }
- else if ( s_graphicsoptions.geometry.curvalue == 1 )
- {
- trap_Cvar_SetValue( "r_lodBias", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 12 );
- }
- else
- {
- trap_Cvar_SetValue( "r_lodBias", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 20 );
- }
-
- if ( s_graphicsoptions.filter.curvalue )
- {
- trap_Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR" );
- }
- else
- {
- trap_Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" );
- }
-
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" );
-}
-
-/*
-=================
-GraphicsOptions_Event
-=================
-*/
-static void GraphicsOptions_Event( void* ptr, int event ) {
- InitialVideoOptions_s *ivo;
-
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_RATIO:
- s_graphicsoptions.mode.curvalue =
- ratioToRes[ s_graphicsoptions.ratio.curvalue ];
- // fall through to apply mode constraints
-
- case ID_MODE:
- // clamp 3dfx video modes
- if ( s_graphicsoptions.driver.curvalue == 1 )
- {
- if ( s_graphicsoptions.mode.curvalue < 2 )
- s_graphicsoptions.mode.curvalue = 2;
- else if ( s_graphicsoptions.mode.curvalue > 6 )
- s_graphicsoptions.mode.curvalue = 6;
- }
- s_graphicsoptions.ratio.curvalue =
- resToRatio[ s_graphicsoptions.mode.curvalue ];
- break;
-
- case ID_LIST:
- ivo = &s_ivo_templates[s_graphicsoptions.list.curvalue];
-
- s_graphicsoptions.mode.curvalue = GraphicsOptions_FindDetectedResolution(ivo->mode);
- s_graphicsoptions.ratio.curvalue =
- resToRatio[ s_graphicsoptions.mode.curvalue ];
- s_graphicsoptions.tq.curvalue = ivo->tq;
- s_graphicsoptions.lighting.curvalue = ivo->lighting;
- s_graphicsoptions.colordepth.curvalue = ivo->colordepth;
- s_graphicsoptions.texturebits.curvalue = ivo->texturebits;
- s_graphicsoptions.geometry.curvalue = ivo->geometry;
- s_graphicsoptions.filter.curvalue = ivo->filter;
- s_graphicsoptions.fs.curvalue = ivo->fullscreen;
- break;
-
- case ID_DRIVERINFO:
- UI_DriverInfo_Menu();
- break;
-
- case ID_BACK2:
- UI_PopMenu();
- break;
-
- case ID_GRAPHICS:
- break;
-
- case ID_DISPLAY:
- UI_PopMenu();
- UI_DisplayOptionsMenu();
- break;
-
- case ID_SOUND:
- UI_PopMenu();
- UI_SoundOptionsMenu();
- break;
-
- case ID_NETWORK:
- UI_PopMenu();
- UI_NetworkOptionsMenu();
- break;
- }
-}
-
-
-/*
-================
-GraphicsOptions_TQEvent
-================
-*/
-static void GraphicsOptions_TQEvent( void *ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- s_graphicsoptions.tq.curvalue = (int)(s_graphicsoptions.tq.curvalue + 0.5);
-}
-
-
-/*
-================
-GraphicsOptions_MenuDraw
-================
-*/
-void GraphicsOptions_MenuDraw (void)
-{
-//APSFIX - rework this
- GraphicsOptions_UpdateMenuItems();
-
- Menu_Draw( &s_graphicsoptions.menu );
-}
-
-/*
-=================
-GraphicsOptions_SetMenuItems
-=================
-*/
-static void GraphicsOptions_SetMenuItems( void )
-{
- s_graphicsoptions.mode.curvalue =
- GraphicsOptions_FindDetectedResolution( trap_Cvar_VariableValue( "r_mode" ) );
-
- if ( s_graphicsoptions.mode.curvalue < 0 )
- {
- if( resolutionsDetected )
- {
- int i;
- char buf[MAX_STRING_CHARS];
- trap_Cvar_VariableStringBuffer("r_customwidth", buf, sizeof(buf)-2);
- buf[strlen(buf)+1] = 0;
- buf[strlen(buf)] = 'x';
- trap_Cvar_VariableStringBuffer("r_customheight", buf+strlen(buf), sizeof(buf)-strlen(buf));
-
- for(i = 0; detectedResolutions[i]; ++i)
- {
- if(!Q_stricmp(buf, detectedResolutions[i]))
- {
- s_graphicsoptions.mode.curvalue = i;
- break;
- }
- }
- if ( s_graphicsoptions.mode.curvalue < 0 )
- s_graphicsoptions.mode.curvalue = 0;
- }
- else
- {
- s_graphicsoptions.mode.curvalue = 3;
- }
- }
- s_graphicsoptions.ratio.curvalue =
- resToRatio[ s_graphicsoptions.mode.curvalue ];
- s_graphicsoptions.fs.curvalue = trap_Cvar_VariableValue("r_fullscreen");
- s_graphicsoptions.allow_extensions.curvalue = trap_Cvar_VariableValue("r_allowExtensions");
- s_graphicsoptions.tq.curvalue = 3-trap_Cvar_VariableValue( "r_picmip");
- if ( s_graphicsoptions.tq.curvalue < 0 )
- {
- s_graphicsoptions.tq.curvalue = 0;
- }
- else if ( s_graphicsoptions.tq.curvalue > 3 )
- {
- s_graphicsoptions.tq.curvalue = 3;
- }
-
- s_graphicsoptions.lighting.curvalue = trap_Cvar_VariableValue( "r_vertexLight" ) != 0;
- switch ( ( int ) trap_Cvar_VariableValue( "r_texturebits" ) )
- {
- default:
- case 0:
- s_graphicsoptions.texturebits.curvalue = 0;
- break;
- case 16:
- s_graphicsoptions.texturebits.curvalue = 1;
- break;
- case 32:
- s_graphicsoptions.texturebits.curvalue = 2;
- break;
- }
-
- if ( !Q_stricmp( UI_Cvar_VariableString( "r_textureMode" ), "GL_LINEAR_MIPMAP_NEAREST" ) )
- {
- s_graphicsoptions.filter.curvalue = 0;
- }
- else
- {
- s_graphicsoptions.filter.curvalue = 1;
- }
-
- if ( trap_Cvar_VariableValue( "r_lodBias" ) > 0 )
- {
- if ( trap_Cvar_VariableValue( "r_subdivisions" ) >= 20 )
- {
- s_graphicsoptions.geometry.curvalue = 0;
- }
- else
- {
- s_graphicsoptions.geometry.curvalue = 1;
- }
- }
- else
- {
- s_graphicsoptions.geometry.curvalue = 2;
- }
-
- switch ( ( int ) trap_Cvar_VariableValue( "r_colorbits" ) )
- {
- default:
- case 0:
- s_graphicsoptions.colordepth.curvalue = 0;
- break;
- case 16:
- s_graphicsoptions.colordepth.curvalue = 1;
- break;
- case 32:
- s_graphicsoptions.colordepth.curvalue = 2;
- break;
- }
-
- if ( s_graphicsoptions.fs.curvalue == 0 )
- {
- s_graphicsoptions.colordepth.curvalue = 0;
- }
- if ( s_graphicsoptions.driver.curvalue == 1 )
- {
- s_graphicsoptions.colordepth.curvalue = 1;
- }
-}
-
-/*
-================
-GraphicsOptions_MenuInit
-================
-*/
-void GraphicsOptions_MenuInit( void )
-{
- static const char *s_driver_names[] =
- {
- "Default",
- "Voodoo",
- NULL
- };
-
- static const char *tq_names[] =
- {
- "Default",
- "16 bit",
- "32 bit",
- NULL
- };
-
- static const char *s_graphics_options_names[] =
- {
- "Very High Quality",
- "High Quality",
- "Normal",
- "Fast",
- "Fastest",
- "Custom",
- NULL
- };
-
- static const char *lighting_names[] =
- {
- "Lightmap",
- "Vertex",
- NULL
- };
-
- static const char *colordepth_names[] =
- {
- "Default",
- "16 bit",
- "32 bit",
- NULL
- };
-
- static const char *filter_names[] =
- {
- "Bilinear",
- "Trilinear",
- NULL
- };
- static const char *quality_names[] =
- {
- "Low",
- "Medium",
- "High",
- NULL
- };
- static const char *enabled_names[] =
- {
- "Off",
- "On",
- NULL
- };
-
- int y;
-
- // zero set all our globals
- memset( &s_graphicsoptions, 0 ,sizeof(graphicsoptions_t) );
-
- GraphicsOptions_GetResolutions();
- GraphicsOptions_GetAspectRatios();
-
- GraphicsOptions_Cache();
-
- s_graphicsoptions.menu.wrapAround = qtrue;
- s_graphicsoptions.menu.fullscreen = qtrue;
- s_graphicsoptions.menu.draw = GraphicsOptions_MenuDraw;
-
- s_graphicsoptions.banner.generic.type = MTYPE_BTEXT;
- s_graphicsoptions.banner.generic.x = 320;
- s_graphicsoptions.banner.generic.y = 16;
- s_graphicsoptions.banner.string = "SYSTEM SETUP";
- s_graphicsoptions.banner.color = color_white;
- s_graphicsoptions.banner.style = UI_CENTER;
-
- s_graphicsoptions.framel.generic.type = MTYPE_BITMAP;
- s_graphicsoptions.framel.generic.name = GRAPHICSOPTIONS_FRAMEL;
- s_graphicsoptions.framel.generic.flags = QMF_INACTIVE;
- s_graphicsoptions.framel.generic.x = 0;
- s_graphicsoptions.framel.generic.y = 78;
- s_graphicsoptions.framel.width = 256;
- s_graphicsoptions.framel.height = 329;
-
- s_graphicsoptions.framer.generic.type = MTYPE_BITMAP;
- s_graphicsoptions.framer.generic.name = GRAPHICSOPTIONS_FRAMER;
- s_graphicsoptions.framer.generic.flags = QMF_INACTIVE;
- s_graphicsoptions.framer.generic.x = 376;
- s_graphicsoptions.framer.generic.y = 76;
- s_graphicsoptions.framer.width = 256;
- s_graphicsoptions.framer.height = 334;
-
- s_graphicsoptions.graphics.generic.type = MTYPE_PTEXT;
- s_graphicsoptions.graphics.generic.flags = QMF_RIGHT_JUSTIFY;
- s_graphicsoptions.graphics.generic.id = ID_GRAPHICS;
- s_graphicsoptions.graphics.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.graphics.generic.x = 216;
- s_graphicsoptions.graphics.generic.y = 240 - 2 * PROP_HEIGHT;
- s_graphicsoptions.graphics.string = "GRAPHICS";
- s_graphicsoptions.graphics.style = UI_RIGHT;
- s_graphicsoptions.graphics.color = color_red;
-
- s_graphicsoptions.display.generic.type = MTYPE_PTEXT;
- s_graphicsoptions.display.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_graphicsoptions.display.generic.id = ID_DISPLAY;
- s_graphicsoptions.display.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.display.generic.x = 216;
- s_graphicsoptions.display.generic.y = 240 - PROP_HEIGHT;
- s_graphicsoptions.display.string = "DISPLAY";
- s_graphicsoptions.display.style = UI_RIGHT;
- s_graphicsoptions.display.color = color_red;
-
- s_graphicsoptions.sound.generic.type = MTYPE_PTEXT;
- s_graphicsoptions.sound.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_graphicsoptions.sound.generic.id = ID_SOUND;
- s_graphicsoptions.sound.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.sound.generic.x = 216;
- s_graphicsoptions.sound.generic.y = 240;
- s_graphicsoptions.sound.string = "SOUND";
- s_graphicsoptions.sound.style = UI_RIGHT;
- s_graphicsoptions.sound.color = color_red;
-
- s_graphicsoptions.network.generic.type = MTYPE_PTEXT;
- s_graphicsoptions.network.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_graphicsoptions.network.generic.id = ID_NETWORK;
- s_graphicsoptions.network.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.network.generic.x = 216;
- s_graphicsoptions.network.generic.y = 240 + PROP_HEIGHT;
- s_graphicsoptions.network.string = "NETWORK";
- s_graphicsoptions.network.style = UI_RIGHT;
- s_graphicsoptions.network.color = color_red;
-
- y = 240 - 7 * (BIGCHAR_HEIGHT + 2);
- s_graphicsoptions.list.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.list.generic.name = "Graphics Settings:";
- s_graphicsoptions.list.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.list.generic.x = 400;
- s_graphicsoptions.list.generic.y = y;
- s_graphicsoptions.list.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.list.generic.id = ID_LIST;
- s_graphicsoptions.list.itemnames = s_graphics_options_names;
- y += 2 * ( BIGCHAR_HEIGHT + 2 );
-
- s_graphicsoptions.driver.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.driver.generic.name = "GL Driver:";
- s_graphicsoptions.driver.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.driver.generic.x = 400;
- s_graphicsoptions.driver.generic.y = y;
- s_graphicsoptions.driver.itemnames = s_driver_names;
- s_graphicsoptions.driver.curvalue = (uis.glconfig.driverType == GLDRV_VOODOO);
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_allowExtensions"
- s_graphicsoptions.allow_extensions.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.allow_extensions.generic.name = "GL Extensions:";
- s_graphicsoptions.allow_extensions.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.allow_extensions.generic.x = 400;
- s_graphicsoptions.allow_extensions.generic.y = y;
- s_graphicsoptions.allow_extensions.itemnames = enabled_names;
- y += BIGCHAR_HEIGHT+2;
-
- s_graphicsoptions.ratio.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.ratio.generic.name = "Aspect Ratio:";
- s_graphicsoptions.ratio.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.ratio.generic.x = 400;
- s_graphicsoptions.ratio.generic.y = y;
- s_graphicsoptions.ratio.itemnames = ratios;
- s_graphicsoptions.ratio.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.ratio.generic.id = ID_RATIO;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_mode"
- s_graphicsoptions.mode.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.mode.generic.name = "Resolution:";
- s_graphicsoptions.mode.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.mode.generic.x = 400;
- s_graphicsoptions.mode.generic.y = y;
- s_graphicsoptions.mode.itemnames = resolutions;
- s_graphicsoptions.mode.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.mode.generic.id = ID_MODE;
- y += BIGCHAR_HEIGHT+2;
-
- // references "r_colorbits"
- s_graphicsoptions.colordepth.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.colordepth.generic.name = "Color Depth:";
- s_graphicsoptions.colordepth.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.colordepth.generic.x = 400;
- s_graphicsoptions.colordepth.generic.y = y;
- s_graphicsoptions.colordepth.itemnames = colordepth_names;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_fullscreen"
- s_graphicsoptions.fs.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.fs.generic.name = "Fullscreen:";
- s_graphicsoptions.fs.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.fs.generic.x = 400;
- s_graphicsoptions.fs.generic.y = y;
- s_graphicsoptions.fs.itemnames = enabled_names;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_vertexLight"
- s_graphicsoptions.lighting.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.lighting.generic.name = "Lighting:";
- s_graphicsoptions.lighting.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.lighting.generic.x = 400;
- s_graphicsoptions.lighting.generic.y = y;
- s_graphicsoptions.lighting.itemnames = lighting_names;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_lodBias" & "subdivisions"
- s_graphicsoptions.geometry.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.geometry.generic.name = "Geometric Detail:";
- s_graphicsoptions.geometry.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.geometry.generic.x = 400;
- s_graphicsoptions.geometry.generic.y = y;
- s_graphicsoptions.geometry.itemnames = quality_names;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_picmip"
- s_graphicsoptions.tq.generic.type = MTYPE_SLIDER;
- s_graphicsoptions.tq.generic.name = "Texture Detail:";
- s_graphicsoptions.tq.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.tq.generic.x = 400;
- s_graphicsoptions.tq.generic.y = y;
- s_graphicsoptions.tq.minvalue = 0;
- s_graphicsoptions.tq.maxvalue = 3;
- s_graphicsoptions.tq.generic.callback = GraphicsOptions_TQEvent;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_textureBits"
- s_graphicsoptions.texturebits.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.texturebits.generic.name = "Texture Quality:";
- s_graphicsoptions.texturebits.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.texturebits.generic.x = 400;
- s_graphicsoptions.texturebits.generic.y = y;
- s_graphicsoptions.texturebits.itemnames = tq_names;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_textureMode"
- s_graphicsoptions.filter.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.filter.generic.name = "Texture Filter:";
- s_graphicsoptions.filter.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.filter.generic.x = 400;
- s_graphicsoptions.filter.generic.y = y;
- s_graphicsoptions.filter.itemnames = filter_names;
- y += 2*BIGCHAR_HEIGHT;
-
- s_graphicsoptions.driverinfo.generic.type = MTYPE_PTEXT;
- s_graphicsoptions.driverinfo.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_graphicsoptions.driverinfo.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.driverinfo.generic.id = ID_DRIVERINFO;
- s_graphicsoptions.driverinfo.generic.x = 320;
- s_graphicsoptions.driverinfo.generic.y = y;
- s_graphicsoptions.driverinfo.string = "Driver Info";
- s_graphicsoptions.driverinfo.style = UI_CENTER|UI_SMALLFONT;
- s_graphicsoptions.driverinfo.color = color_red;
- y += BIGCHAR_HEIGHT+2;
-
- s_graphicsoptions.back.generic.type = MTYPE_BITMAP;
- s_graphicsoptions.back.generic.name = GRAPHICSOPTIONS_BACK0;
- s_graphicsoptions.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_graphicsoptions.back.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.back.generic.id = ID_BACK2;
- s_graphicsoptions.back.generic.x = 0;
- s_graphicsoptions.back.generic.y = 480-64;
- s_graphicsoptions.back.width = 128;
- s_graphicsoptions.back.height = 64;
- s_graphicsoptions.back.focuspic = GRAPHICSOPTIONS_BACK1;
-
- s_graphicsoptions.apply.generic.type = MTYPE_BITMAP;
- s_graphicsoptions.apply.generic.name = GRAPHICSOPTIONS_ACCEPT0;
- s_graphicsoptions.apply.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_HIDDEN|QMF_INACTIVE;
- s_graphicsoptions.apply.generic.callback = GraphicsOptions_ApplyChanges;
- s_graphicsoptions.apply.generic.x = 640;
- s_graphicsoptions.apply.generic.y = 480-64;
- s_graphicsoptions.apply.width = 128;
- s_graphicsoptions.apply.height = 64;
- s_graphicsoptions.apply.focuspic = GRAPHICSOPTIONS_ACCEPT1;
-
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.banner );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.framel );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.framer );
-
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.graphics );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.display );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.sound );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.network );
-
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.list );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.driver );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.allow_extensions );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.ratio );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.mode );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.colordepth );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.fs );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.lighting );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.geometry );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.tq );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.texturebits );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.filter );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.driverinfo );
-
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.back );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.apply );
-
- GraphicsOptions_SetMenuItems();
- GraphicsOptions_GetInitialVideo();
-
- if ( uis.glconfig.driverType == GLDRV_ICD &&
- uis.glconfig.hardwareType == GLHW_3DFX_2D3D )
- {
- s_graphicsoptions.driver.generic.flags |= QMF_HIDDEN|QMF_INACTIVE;
- }
-}
-
-
-/*
-=================
-GraphicsOptions_Cache
-=================
-*/
-void GraphicsOptions_Cache( void ) {
- trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_FRAMEL );
- trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_FRAMER );
- trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_BACK0 );
- trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_BACK1 );
- trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_ACCEPT0 );
- trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_ACCEPT1 );
-}
-
-
-/*
-=================
-UI_GraphicsOptionsMenu
-=================
-*/
-void UI_GraphicsOptionsMenu( void ) {
- GraphicsOptions_MenuInit();
- UI_PushMenu( &s_graphicsoptions.menu );
- Menu_SetCursorToItem( &s_graphicsoptions.menu, &s_graphicsoptions.graphics );
-}
-
diff --git a/engine/code/qcommon/cm_load.c b/engine/code/qcommon/cm_load.c
deleted file mode 100644
index a06358b..0000000
--- a/engine/code/qcommon/cm_load.c
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// cmodel.c -- model loading
-
-#include "cm_local.h"
-
-#ifdef BSPC
-
-#include "../bspc/l_qfiles.h"
-
-void SetPlaneSignbits (cplane_t *out) {
- int bits, j;
-
- // for fast box on planeside test
- bits = 0;
- for (j=0 ; j<3 ; j++) {
- if (out->normal[j] < 0) {
- bits |= 1<<j;
- }
- }
- out->signbits = bits;
-}
-#endif //BSPC
-
-// to allow boxes to be treated as brush models, we allocate
-// some extra indexes along with those needed by the map
-#define BOX_BRUSHES 1
-#define BOX_SIDES 6
-#define BOX_LEAFS 2
-#define BOX_PLANES 12
-
-#define LL(x) x=LittleLong(x)
-
-
-clipMap_t cm;
-int c_pointcontents;
-int c_traces, c_brush_traces, c_patch_traces;
-
-
-byte *cmod_base;
-
-#ifndef BSPC
-cvar_t *cm_noAreas;
-cvar_t *cm_noCurves;
-cvar_t *cm_playerCurveClip;
-#endif
-
-cmodel_t box_model;
-cplane_t *box_planes;
-cbrush_t *box_brush;
-
-
-
-void CM_InitBoxHull (void);
-void CM_FloodAreaConnections (void);
-
-
-/*
-===============================================================================
-
- MAP LOADING
-
-===============================================================================
-*/
-
-/*
-=================
-CMod_LoadShaders
-=================
-*/
-void CMod_LoadShaders( lump_t *l ) {
- dshader_t *in, *out;
- int i, count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in)) {
- Com_Error (ERR_DROP, "CMod_LoadShaders: funny lump size");
- }
- count = l->filelen / sizeof(*in);
-
- if (count < 1) {
- Com_Error (ERR_DROP, "Map with no shaders");
- }
- cm.shaders = Hunk_Alloc( count * sizeof( *cm.shaders ), h_high );
- cm.numShaders = count;
-
- Com_Memcpy( cm.shaders, in, count * sizeof( *cm.shaders ) );
-
- out = cm.shaders;
- for ( i=0 ; i<count ; i++, in++, out++ ) {
- out->contentFlags = LittleLong( out->contentFlags );
- out->surfaceFlags = LittleLong( out->surfaceFlags );
- }
-}
-
-
-/*
-=================
-CMod_LoadSubmodels
-=================
-*/
-void CMod_LoadSubmodels( lump_t *l ) {
- dmodel_t *in;
- cmodel_t *out;
- int i, j, count;
- int *indexes;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "CMod_LoadSubmodels: funny lump size");
- count = l->filelen / sizeof(*in);
-
- if (count < 1)
- Com_Error (ERR_DROP, "Map with no models");
- cm.cmodels = Hunk_Alloc( count * sizeof( *cm.cmodels ), h_high );
- cm.numSubModels = count;
-
- if ( count > MAX_SUBMODELS ) {
- Com_Error( ERR_DROP, "MAX_SUBMODELS exceeded" );
- }
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- out = &cm.cmodels[i];
-
- for (j=0 ; j<3 ; j++)
- { // spread the mins / maxs by a pixel
- out->mins[j] = LittleFloat (in->mins[j]) - 1;
- out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
- }
-
- if ( i == 0 ) {
- continue; // world model doesn't need other info
- }
-
- // make a "leaf" just to hold the model's brushes and surfaces
- out->leaf.numLeafBrushes = LittleLong( in->numBrushes );
- indexes = Hunk_Alloc( out->leaf.numLeafBrushes * 4, h_high );
- out->leaf.firstLeafBrush = indexes - cm.leafbrushes;
- for ( j = 0 ; j < out->leaf.numLeafBrushes ; j++ ) {
- indexes[j] = LittleLong( in->firstBrush ) + j;
- }
-
- out->leaf.numLeafSurfaces = LittleLong( in->numSurfaces );
- indexes = Hunk_Alloc( out->leaf.numLeafSurfaces * 4, h_high );
- out->leaf.firstLeafSurface = indexes - cm.leafsurfaces;
- for ( j = 0 ; j < out->leaf.numLeafSurfaces ; j++ ) {
- indexes[j] = LittleLong( in->firstSurface ) + j;
- }
- }
-}
-
-
-/*
-=================
-CMod_LoadNodes
-
-=================
-*/
-void CMod_LoadNodes( lump_t *l ) {
- dnode_t *in;
- int child;
- cNode_t *out;
- int i, j, count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- if (count < 1)
- Com_Error (ERR_DROP, "Map has no nodes");
- cm.nodes = Hunk_Alloc( count * sizeof( *cm.nodes ), h_high );
- cm.numNodes = count;
-
- out = cm.nodes;
-
- for (i=0 ; i<count ; i++, out++, in++)
- {
- out->plane = cm.planes + LittleLong( in->planeNum );
- for (j=0 ; j<2 ; j++)
- {
- child = LittleLong (in->children[j]);
- out->children[j] = child;
- }
- }
-
-}
-
-/*
-=================
-CM_BoundBrush
-
-=================
-*/
-void CM_BoundBrush( cbrush_t *b ) {
- b->bounds[0][0] = -b->sides[0].plane->dist;
- b->bounds[1][0] = b->sides[1].plane->dist;
-
- b->bounds[0][1] = -b->sides[2].plane->dist;
- b->bounds[1][1] = b->sides[3].plane->dist;
-
- b->bounds[0][2] = -b->sides[4].plane->dist;
- b->bounds[1][2] = b->sides[5].plane->dist;
-}
-
-
-/*
-=================
-CMod_LoadBrushes
-
-=================
-*/
-void CMod_LoadBrushes( lump_t *l ) {
- dbrush_t *in;
- cbrush_t *out;
- int i, count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in)) {
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- }
- count = l->filelen / sizeof(*in);
-
- cm.brushes = Hunk_Alloc( ( BOX_BRUSHES + count ) * sizeof( *cm.brushes ), h_high );
- cm.numBrushes = count;
-
- out = cm.brushes;
-
- for ( i=0 ; i<count ; i++, out++, in++ ) {
- out->sides = cm.brushsides + LittleLong(in->firstSide);
- out->numsides = LittleLong(in->numSides);
-
- out->shaderNum = LittleLong( in->shaderNum );
- if ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) {
- Com_Error( ERR_DROP, "CMod_LoadBrushes: bad shaderNum: %i", out->shaderNum );
- }
- out->contents = cm.shaders[out->shaderNum].contentFlags;
-
- CM_BoundBrush( out );
- }
-
-}
-
-/*
-=================
-CMod_LoadLeafs
-=================
-*/
-void CMod_LoadLeafs (lump_t *l)
-{
- int i;
- cLeaf_t *out;
- dleaf_t *in;
- int count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- if (count < 1)
- Com_Error (ERR_DROP, "Map with no leafs");
-
- cm.leafs = Hunk_Alloc( ( BOX_LEAFS + count ) * sizeof( *cm.leafs ), h_high );
- cm.numLeafs = count;
-
- out = cm.leafs;
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- out->cluster = LittleLong (in->cluster);
- out->area = LittleLong (in->area);
- out->firstLeafBrush = LittleLong (in->firstLeafBrush);
- out->numLeafBrushes = LittleLong (in->numLeafBrushes);
- out->firstLeafSurface = LittleLong (in->firstLeafSurface);
- out->numLeafSurfaces = LittleLong (in->numLeafSurfaces);
-
- if (out->cluster >= cm.numClusters)
- cm.numClusters = out->cluster + 1;
- if (out->area >= cm.numAreas)
- cm.numAreas = out->area + 1;
- }
-
- cm.areas = Hunk_Alloc( cm.numAreas * sizeof( *cm.areas ), h_high );
- cm.areaPortals = Hunk_Alloc( cm.numAreas * cm.numAreas * sizeof( *cm.areaPortals ), h_high );
-}
-
-/*
-=================
-CMod_LoadPlanes
-=================
-*/
-void CMod_LoadPlanes (lump_t *l)
-{
- int i, j;
- cplane_t *out;
- dplane_t *in;
- int count;
- int bits;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- if (count < 1)
- Com_Error (ERR_DROP, "Map with no planes");
- cm.planes = Hunk_Alloc( ( BOX_PLANES + count ) * sizeof( *cm.planes ), h_high );
- cm.numPlanes = count;
-
- out = cm.planes;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- bits = 0;
- for (j=0 ; j<3 ; j++)
- {
- out->normal[j] = LittleFloat (in->normal[j]);
- if (out->normal[j] < 0)
- bits |= 1<<j;
- }
-
- out->dist = LittleFloat (in->dist);
- out->type = PlaneTypeForNormal( out->normal );
- out->signbits = bits;
- }
-}
-
-/*
-=================
-CMod_LoadLeafBrushes
-=================
-*/
-void CMod_LoadLeafBrushes (lump_t *l)
-{
- int i;
- int *out;
- int *in;
- int count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- cm.leafbrushes = Hunk_Alloc( (count + BOX_BRUSHES) * sizeof( *cm.leafbrushes ), h_high );
- cm.numLeafBrushes = count;
-
- out = cm.leafbrushes;
-
- for ( i=0 ; i<count ; i++, in++, out++) {
- *out = LittleLong (*in);
- }
-}
-
-/*
-=================
-CMod_LoadLeafSurfaces
-=================
-*/
-void CMod_LoadLeafSurfaces( lump_t *l )
-{
- int i;
- int *out;
- int *in;
- int count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- cm.leafsurfaces = Hunk_Alloc( count * sizeof( *cm.leafsurfaces ), h_high );
- cm.numLeafSurfaces = count;
-
- out = cm.leafsurfaces;
-
- for ( i=0 ; i<count ; i++, in++, out++) {
- *out = LittleLong (*in);
- }
-}
-
-/*
-=================
-CMod_LoadBrushSides
-=================
-*/
-void CMod_LoadBrushSides (lump_t *l)
-{
- int i;
- cbrushside_t *out;
- dbrushside_t *in;
- int count;
- int num;
-
- in = (void *)(cmod_base + l->fileofs);
- if ( l->filelen % sizeof(*in) ) {
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- }
- count = l->filelen / sizeof(*in);
-
- cm.brushsides = Hunk_Alloc( ( BOX_SIDES + count ) * sizeof( *cm.brushsides ), h_high );
- cm.numBrushSides = count;
-
- out = cm.brushsides;
-
- for ( i=0 ; i<count ; i++, in++, out++) {
- num = LittleLong( in->planeNum );
- out->plane = &cm.planes[num];
- out->shaderNum = LittleLong( in->shaderNum );
- if ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) {
- Com_Error( ERR_DROP, "CMod_LoadBrushSides: bad shaderNum: %i", out->shaderNum );
- }
- out->surfaceFlags = cm.shaders[out->shaderNum].surfaceFlags;
- }
-}
-
-
-/*
-=================
-CMod_LoadEntityString
-=================
-*/
-void CMod_LoadEntityString( lump_t *l ) {
- cm.entityString = Hunk_Alloc( l->filelen, h_high );
- cm.numEntityChars = l->filelen;
- Com_Memcpy (cm.entityString, cmod_base + l->fileofs, l->filelen);
-}
-
-/*
-=================
-CMod_LoadVisibility
-=================
-*/
-#define VIS_HEADER 8
-void CMod_LoadVisibility( lump_t *l ) {
- int len;
- byte *buf;
-
- len = l->filelen;
- if ( !len ) {
- cm.clusterBytes = ( cm.numClusters + 31 ) & ~31;
- cm.visibility = Hunk_Alloc( cm.clusterBytes, h_high );
- Com_Memset( cm.visibility, 255, cm.clusterBytes );
- return;
- }
- buf = cmod_base + l->fileofs;
-
- cm.vised = qtrue;
- cm.visibility = Hunk_Alloc( len, h_high );
- cm.numClusters = LittleLong( ((int *)buf)[0] );
- cm.clusterBytes = LittleLong( ((int *)buf)[1] );
- Com_Memcpy (cm.visibility, buf + VIS_HEADER, len - VIS_HEADER );
-}
-
-//==================================================================
-
-
-/*
-=================
-CMod_LoadPatches
-=================
-*/
-#define MAX_PATCH_VERTS 1024
-void CMod_LoadPatches( lump_t *surfs, lump_t *verts ) {
- drawVert_t *dv, *dv_p;
- dsurface_t *in;
- int count;
- int i, j;
- int c;
- cPatch_t *patch;
- vec3_t points[MAX_PATCH_VERTS];
- int width, height;
- int shaderNum;
-
- in = (void *)(cmod_base + surfs->fileofs);
- if (surfs->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- cm.numSurfaces = count = surfs->filelen / sizeof(*in);
- cm.surfaces = Hunk_Alloc( cm.numSurfaces * sizeof( cm.surfaces[0] ), h_high );
-
- dv = (void *)(cmod_base + verts->fileofs);
- if (verts->filelen % sizeof(*dv))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
-
- // scan through all the surfaces, but only load patches,
- // not planar faces
- for ( i = 0 ; i < count ; i++, in++ ) {
- if ( LittleLong( in->surfaceType ) != MST_PATCH ) {
- continue; // ignore other surfaces
- }
- // FIXME: check for non-colliding patches
-
- cm.surfaces[ i ] = patch = Hunk_Alloc( sizeof( *patch ), h_high );
-
- // load the full drawverts onto the stack
- width = LittleLong( in->patchWidth );
- height = LittleLong( in->patchHeight );
- c = width * height;
- if ( c > MAX_PATCH_VERTS ) {
- Com_Error( ERR_DROP, "ParseMesh: MAX_PATCH_VERTS" );
- }
-
- dv_p = dv + LittleLong( in->firstVert );
- for ( j = 0 ; j < c ; j++, dv_p++ ) {
- points[j][0] = LittleFloat( dv_p->xyz[0] );
- points[j][1] = LittleFloat( dv_p->xyz[1] );
- points[j][2] = LittleFloat( dv_p->xyz[2] );
- }
-
- shaderNum = LittleLong( in->shaderNum );
- patch->contents = cm.shaders[shaderNum].contentFlags;
- patch->surfaceFlags = cm.shaders[shaderNum].surfaceFlags;
-
- // create the internal facet structure
- patch->pc = CM_GeneratePatchCollide( width, height, points );
- }
-}
-
-//==================================================================
-
-unsigned CM_LumpChecksum(lump_t *lump) {
- return LittleLong (Com_BlockChecksum (cmod_base + lump->fileofs, lump->filelen));
-}
-
-unsigned CM_Checksum(dheader_t *header) {
- unsigned checksums[16];
- checksums[0] = CM_LumpChecksum(&header->lumps[LUMP_SHADERS]);
- checksums[1] = CM_LumpChecksum(&header->lumps[LUMP_LEAFS]);
- checksums[2] = CM_LumpChecksum(&header->lumps[LUMP_LEAFBRUSHES]);
- checksums[3] = CM_LumpChecksum(&header->lumps[LUMP_LEAFSURFACES]);
- checksums[4] = CM_LumpChecksum(&header->lumps[LUMP_PLANES]);
- checksums[5] = CM_LumpChecksum(&header->lumps[LUMP_BRUSHSIDES]);
- checksums[6] = CM_LumpChecksum(&header->lumps[LUMP_BRUSHES]);
- checksums[7] = CM_LumpChecksum(&header->lumps[LUMP_MODELS]);
- checksums[8] = CM_LumpChecksum(&header->lumps[LUMP_NODES]);
- checksums[9] = CM_LumpChecksum(&header->lumps[LUMP_SURFACES]);
- checksums[10] = CM_LumpChecksum(&header->lumps[LUMP_DRAWVERTS]);
-
- return LittleLong(Com_BlockChecksum(checksums, 11 * 4));
-}
-
-/*
-==================
-CM_LoadMap
-
-Loads in the map and all submodels
-==================
-*/
-void CM_LoadMap( const char *name, qboolean clientload, int *checksum ) {
- union {
- int *i;
- void *v;
- } buf;
- int i;
- dheader_t header;
- int length;
- static unsigned last_checksum;
-
- if ( !name || !name[0] ) {
- Com_Error( ERR_DROP, "CM_LoadMap: NULL name" );
- }
-
-#ifndef BSPC
- cm_noAreas = Cvar_Get ("cm_noAreas", "0", CVAR_CHEAT);
- cm_noCurves = Cvar_Get ("cm_noCurves", "0", CVAR_CHEAT);
- cm_playerCurveClip = Cvar_Get ("cm_playerCurveClip", "1", CVAR_ARCHIVE|CVAR_CHEAT );
-#endif
- Com_DPrintf( "CM_LoadMap( %s, %i )\n", name, clientload );
-
- if ( !strcmp( cm.name, name ) && clientload ) {
- *checksum = last_checksum;
- return;
- }
-
- // free old stuff
- Com_Memset( &cm, 0, sizeof( cm ) );
- CM_ClearLevelPatches();
-
- if ( !name[0] ) {
- cm.numLeafs = 1;
- cm.numClusters = 1;
- cm.numAreas = 1;
- cm.cmodels = Hunk_Alloc( sizeof( *cm.cmodels ), h_high );
- *checksum = 0;
- return;
- }
-
- //
- // load the file
- //
-#ifndef BSPC
- length = FS_ReadFile( name, &buf.v );
-#else
- length = LoadQuakeFile((quakefile_t *) name, &buf.v);
-#endif
-
- if ( !buf.i ) {
- Com_Error (ERR_DROP, "Couldn't load %s", name);
- }
-
- last_checksum = LittleLong (Com_BlockChecksum (buf.i, length));
- *checksum = last_checksum;
-
- header = *(dheader_t *)buf.i;
- for (i=0 ; i<sizeof(dheader_t)/4 ; i++) {
- ((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
- }
-
- if ( header.version != BSP_VERSION ) {
- Com_Error (ERR_DROP, "CM_LoadMap: %s has wrong version number (%i should be %i)"
- , name, header.version, BSP_VERSION );
- }
-
- cmod_base = (byte *)buf.i;
-
- // load into heap
- CMod_LoadShaders( &header.lumps[LUMP_SHADERS] );
- CMod_LoadLeafs (&header.lumps[LUMP_LEAFS]);
- CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]);
- CMod_LoadLeafSurfaces (&header.lumps[LUMP_LEAFSURFACES]);
- CMod_LoadPlanes (&header.lumps[LUMP_PLANES]);
- CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]);
- CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]);
- CMod_LoadSubmodels (&header.lumps[LUMP_MODELS]);
- CMod_LoadNodes (&header.lumps[LUMP_NODES]);
- CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]);
- CMod_LoadVisibility( &header.lumps[LUMP_VISIBILITY] );
- CMod_LoadPatches( &header.lumps[LUMP_SURFACES], &header.lumps[LUMP_DRAWVERTS] );
-
- // we are NOT freeing the file, because it is cached for the ref
- FS_FreeFile (buf.v);
-
- CM_InitBoxHull ();
-
- CM_FloodAreaConnections ();
-
- // allow this to be cached if it is loaded by the server
- if ( !clientload ) {
- Q_strncpyz( cm.name, name, sizeof( cm.name ) );
- }
-}
-
-/*
-==================
-CM_ClearMap
-==================
-*/
-void CM_ClearMap( void ) {
- Com_Memset( &cm, 0, sizeof( cm ) );
- CM_ClearLevelPatches();
-}
-
-/*
-==================
-CM_ClipHandleToModel
-==================
-*/
-cmodel_t *CM_ClipHandleToModel( clipHandle_t handle ) {
- if ( handle < 0 ) {
- Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i", handle );
- }
- if ( handle < cm.numSubModels ) {
- return &cm.cmodels[handle];
- }
- if ( handle == BOX_MODEL_HANDLE ) {
- return &box_model;
- }
- if ( handle < MAX_SUBMODELS ) {
- Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i < %i < %i",
- cm.numSubModels, handle, MAX_SUBMODELS );
- }
- Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i", handle + MAX_SUBMODELS );
-
- return NULL;
-
-}
-
-/*
-==================
-CM_InlineModel
-==================
-*/
-clipHandle_t CM_InlineModel( int index ) {
- if ( index < 0 || index >= cm.numSubModels ) {
- Com_Error (ERR_DROP, "CM_InlineModel: bad number");
- }
- return index;
-}
-
-int CM_NumClusters( void ) {
- return cm.numClusters;
-}
-
-int CM_NumInlineModels( void ) {
- return cm.numSubModels;
-}
-
-char *CM_EntityString( void ) {
- return cm.entityString;
-}
-
-int CM_LeafCluster( int leafnum ) {
- if (leafnum < 0 || leafnum >= cm.numLeafs) {
- Com_Error (ERR_DROP, "CM_LeafCluster: bad number");
- }
- return cm.leafs[leafnum].cluster;
-}
-
-int CM_LeafArea( int leafnum ) {
- if ( leafnum < 0 || leafnum >= cm.numLeafs ) {
- Com_Error (ERR_DROP, "CM_LeafArea: bad number");
- }
- return cm.leafs[leafnum].area;
-}
-
-//=======================================================================
-
-
-/*
-===================
-CM_InitBoxHull
-
-Set up the planes and nodes so that the six floats of a bounding box
-can just be stored out and get a proper clipping hull structure.
-===================
-*/
-void CM_InitBoxHull (void)
-{
- int i;
- int side;
- cplane_t *p;
- cbrushside_t *s;
-
- box_planes = &cm.planes[cm.numPlanes];
-
- box_brush = &cm.brushes[cm.numBrushes];
- box_brush->numsides = 6;
- box_brush->sides = cm.brushsides + cm.numBrushSides;
- box_brush->contents = CONTENTS_BODY;
-
- box_model.leaf.numLeafBrushes = 1;
-// box_model.leaf.firstLeafBrush = cm.numBrushes;
- box_model.leaf.firstLeafBrush = cm.numLeafBrushes;
- cm.leafbrushes[cm.numLeafBrushes] = cm.numBrushes;
-
- for (i=0 ; i<6 ; i++)
- {
- side = i&1;
-
- // brush sides
- s = &cm.brushsides[cm.numBrushSides+i];
- s->plane = cm.planes + (cm.numPlanes+i*2+side);
- s->surfaceFlags = 0;
-
- // planes
- p = &box_planes[i*2];
- p->type = i>>1;
- p->signbits = 0;
- VectorClear (p->normal);
- p->normal[i>>1] = 1;
-
- p = &box_planes[i*2+1];
- p->type = 3 + (i>>1);
- p->signbits = 0;
- VectorClear (p->normal);
- p->normal[i>>1] = -1;
-
- SetPlaneSignbits( p );
- }
-}
-
-/*
-===================
-CM_TempBoxModel
-
-To keep everything totally uniform, bounding boxes are turned into small
-BSP trees instead of being compared directly.
-Capsules are handled differently though.
-===================
-*/
-clipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs, int capsule ) {
-
- VectorCopy( mins, box_model.mins );
- VectorCopy( maxs, box_model.maxs );
-
- if ( capsule ) {
- return CAPSULE_MODEL_HANDLE;
- }
-
- box_planes[0].dist = maxs[0];
- box_planes[1].dist = -maxs[0];
- box_planes[2].dist = mins[0];
- box_planes[3].dist = -mins[0];
- box_planes[4].dist = maxs[1];
- box_planes[5].dist = -maxs[1];
- box_planes[6].dist = mins[1];
- box_planes[7].dist = -mins[1];
- box_planes[8].dist = maxs[2];
- box_planes[9].dist = -maxs[2];
- box_planes[10].dist = mins[2];
- box_planes[11].dist = -mins[2];
-
- VectorCopy( mins, box_brush->bounds[0] );
- VectorCopy( maxs, box_brush->bounds[1] );
-
- return BOX_MODEL_HANDLE;
-}
-
-/*
-===================
-CM_ModelBounds
-===================
-*/
-void CM_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {
- cmodel_t *cmod;
-
- cmod = CM_ClipHandleToModel( model );
- VectorCopy( cmod->mins, mins );
- VectorCopy( cmod->maxs, maxs );
-}
-
-
diff --git a/engine/code/qcommon/cm_local.h b/engine/code/qcommon/cm_local.h
deleted file mode 100644
index 5848fdc..0000000
--- a/engine/code/qcommon/cm_local.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "q_shared.h"
-#include "qcommon.h"
-#include "cm_polylib.h"
-
-#define MAX_SUBMODELS 256
-#define BOX_MODEL_HANDLE 255
-#define CAPSULE_MODEL_HANDLE 254
-
-
-typedef struct {
- cplane_t *plane;
- int children[2]; // negative numbers are leafs
-} cNode_t;
-
-typedef struct {
- int cluster;
- int area;
-
- int firstLeafBrush;
- int numLeafBrushes;
-
- int firstLeafSurface;
- int numLeafSurfaces;
-} cLeaf_t;
-
-typedef struct cmodel_s {
- vec3_t mins, maxs;
- cLeaf_t leaf; // submodels don't reference the main tree
-} cmodel_t;
-
-typedef struct {
- cplane_t *plane;
- int surfaceFlags;
- int shaderNum;
-} cbrushside_t;
-
-typedef struct {
- int shaderNum; // the shader that determined the contents
- int contents;
- vec3_t bounds[2];
- int numsides;
- cbrushside_t *sides;
- int checkcount; // to avoid repeated testings
-} cbrush_t;
-
-
-typedef struct {
- int checkcount; // to avoid repeated testings
- int surfaceFlags;
- int contents;
- struct patchCollide_s *pc;
-} cPatch_t;
-
-
-typedef struct {
- int floodnum;
- int floodvalid;
-} cArea_t;
-
-typedef struct {
- char name[MAX_QPATH];
-
- int numShaders;
- dshader_t *shaders;
-
- int numBrushSides;
- cbrushside_t *brushsides;
-
- int numPlanes;
- cplane_t *planes;
-
- int numNodes;
- cNode_t *nodes;
-
- int numLeafs;
- cLeaf_t *leafs;
-
- int numLeafBrushes;
- int *leafbrushes;
-
- int numLeafSurfaces;
- int *leafsurfaces;
-
- int numSubModels;
- cmodel_t *cmodels;
-
- int numBrushes;
- cbrush_t *brushes;
-
- int numClusters;
- int clusterBytes;
- byte *visibility;
- qboolean vised; // if false, visibility is just a single cluster of ffs
-
- int numEntityChars;
- char *entityString;
-
- int numAreas;
- cArea_t *areas;
- int *areaPortals; // [ numAreas*numAreas ] reference counts
-
- int numSurfaces;
- cPatch_t **surfaces; // non-patches will be NULL
-
- int floodvalid;
- int checkcount; // incremented on each trace
-} clipMap_t;
-
-
-// keep 1/8 unit away to keep the position valid before network snapping
-// and to avoid various numeric issues
-#define SURFACE_CLIP_EPSILON (0.125)
-
-extern clipMap_t cm;
-extern int c_pointcontents;
-extern int c_traces, c_brush_traces, c_patch_traces;
-extern cvar_t *cm_noAreas;
-extern cvar_t *cm_noCurves;
-extern cvar_t *cm_playerCurveClip;
-
-// cm_test.c
-
-// Used for oriented capsule collision detection
-typedef struct
-{
- qboolean use;
- float radius;
- float halfheight;
- vec3_t offset;
-} sphere_t;
-
-typedef struct {
- vec3_t start;
- vec3_t end;
- vec3_t size[2]; // size of the box being swept through the model
- vec3_t offsets[8]; // [signbits][x] = either size[0][x] or size[1][x]
- float maxOffset; // longest corner length from origin
- vec3_t extents; // greatest of abs(size[0]) and abs(size[1])
- vec3_t bounds[2]; // enclosing box of start and end surrounding by size
- vec3_t modelOrigin;// origin of the model tracing through
- int contents; // ored contents of the model tracing through
- qboolean isPoint; // optimized case
- trace_t trace; // returned from trace call
- sphere_t sphere; // sphere for oriendted capsule collision
-} traceWork_t;
-
-typedef struct leafList_s {
- int count;
- int maxcount;
- qboolean overflowed;
- int *list;
- vec3_t bounds[2];
- int lastLeaf; // for overflows where each leaf can't be stored individually
- void (*storeLeafs)( struct leafList_s *ll, int nodenum );
-} leafList_t;
-
-
-int CM_BoxBrushes( const vec3_t mins, const vec3_t maxs, cbrush_t **list, int listsize );
-
-void CM_StoreLeafs( leafList_t *ll, int nodenum );
-void CM_StoreBrushes( leafList_t *ll, int nodenum );
-
-void CM_BoxLeafnums_r( leafList_t *ll, int nodenum );
-
-cmodel_t *CM_ClipHandleToModel( clipHandle_t handle );
-qboolean CM_BoundsIntersect( const vec3_t mins, const vec3_t maxs, const vec3_t mins2, const vec3_t maxs2 );
-qboolean CM_BoundsIntersectPoint( const vec3_t mins, const vec3_t maxs, const vec3_t point );
-
-// cm_patch.c
-
-struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, vec3_t *points );
-void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
-qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
-void CM_ClearLevelPatches( void );
diff --git a/engine/code/qcommon/cm_patch.c b/engine/code/qcommon/cm_patch.c
deleted file mode 100644
index 77cf368..0000000
--- a/engine/code/qcommon/cm_patch.c
+++ /dev/null
@@ -1,1777 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "cm_local.h"
-#include "cm_patch.h"
-
-/*
-
-This file does not reference any globals, and has these entry points:
-
-void CM_ClearLevelPatches( void );
-struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, const vec3_t *points );
-void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
-qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
-void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, flaot *points) );
-
-
-WARNING: this may misbehave with meshes that have rows or columns that only
-degenerate a few triangles. Completely degenerate rows and columns are handled
-properly.
-*/
-
-/*
-#define MAX_FACETS 1024
-#define MAX_PATCH_PLANES 2048
-
-typedef struct {
- float plane[4];
- int signbits; // signx + (signy<<1) + (signz<<2), used as lookup during collision
-} patchPlane_t;
-
-typedef struct {
- int surfacePlane;
- int numBorders; // 3 or four + 6 axial bevels + 4 or 3 * 4 edge bevels
- int borderPlanes[4+6+16];
- int borderInward[4+6+16];
- qboolean borderNoAdjust[4+6+16];
-} facet_t;
-
-typedef struct patchCollide_s {
- vec3_t bounds[2];
- int numPlanes; // surface planes plus edge planes
- patchPlane_t *planes;
- int numFacets;
- facet_t *facets;
-} patchCollide_t;
-
-
-#define MAX_GRID_SIZE 129
-
-typedef struct {
- int width;
- int height;
- qboolean wrapWidth;
- qboolean wrapHeight;
- vec3_t points[MAX_GRID_SIZE][MAX_GRID_SIZE]; // [width][height]
-} cGrid_t;
-
-#define SUBDIVIDE_DISTANCE 16 //4 // never more than this units away from curve
-#define PLANE_TRI_EPSILON 0.1
-#define WRAP_POINT_EPSILON 0.1
-*/
-
-int c_totalPatchBlocks;
-int c_totalPatchSurfaces;
-int c_totalPatchEdges;
-
-static const patchCollide_t *debugPatchCollide;
-static const facet_t *debugFacet;
-static qboolean debugBlock;
-static vec3_t debugBlockPoints[4];
-
-/*
-=================
-CM_ClearLevelPatches
-=================
-*/
-void CM_ClearLevelPatches( void ) {
- debugPatchCollide = NULL;
- debugFacet = NULL;
-}
-
-/*
-=================
-CM_SignbitsForNormal
-=================
-*/
-static int CM_SignbitsForNormal( vec3_t normal ) {
- int bits, j;
-
- bits = 0;
- for (j=0 ; j<3 ; j++) {
- if ( normal[j] < 0 ) {
- bits |= 1<<j;
- }
- }
- return bits;
-}
-
-/*
-=====================
-CM_PlaneFromPoints
-
-Returns false if the triangle is degenrate.
-The normal will point out of the clock for clockwise ordered points
-=====================
-*/
-static qboolean CM_PlaneFromPoints( vec4_t plane, vec3_t a, vec3_t b, vec3_t c ) {
- vec3_t d1, d2;
-
- VectorSubtract( b, a, d1 );
- VectorSubtract( c, a, d2 );
- CrossProduct( d2, d1, plane );
- if ( VectorNormalize( plane ) == 0 ) {
- return qfalse;
- }
-
- plane[3] = DotProduct( a, plane );
- return qtrue;
-}
-
-
-/*
-================================================================================
-
-GRID SUBDIVISION
-
-================================================================================
-*/
-
-/*
-=================
-CM_NeedsSubdivision
-
-Returns true if the given quadratic curve is not flat enough for our
-collision detection purposes
-=================
-*/
-static qboolean CM_NeedsSubdivision( vec3_t a, vec3_t b, vec3_t c ) {
- vec3_t cmid;
- vec3_t lmid;
- vec3_t delta;
- float dist;
- int i;
-
- // calculate the linear midpoint
- for ( i = 0 ; i < 3 ; i++ ) {
- lmid[i] = 0.5*(a[i] + c[i]);
- }
-
- // calculate the exact curve midpoint
- for ( i = 0 ; i < 3 ; i++ ) {
- cmid[i] = 0.5 * ( 0.5*(a[i] + b[i]) + 0.5*(b[i] + c[i]) );
- }
-
- // see if the curve is far enough away from the linear mid
- VectorSubtract( cmid, lmid, delta );
- dist = VectorLength( delta );
-
- return dist >= SUBDIVIDE_DISTANCE;
-}
-
-/*
-===============
-CM_Subdivide
-
-a, b, and c are control points.
-the subdivided sequence will be: a, out1, out2, out3, c
-===============
-*/
-static void CM_Subdivide( vec3_t a, vec3_t b, vec3_t c, vec3_t out1, vec3_t out2, vec3_t out3 ) {
- int i;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- out1[i] = 0.5 * (a[i] + b[i]);
- out3[i] = 0.5 * (b[i] + c[i]);
- out2[i] = 0.5 * (out1[i] + out3[i]);
- }
-}
-
-/*
-=================
-CM_TransposeGrid
-
-Swaps the rows and columns in place
-=================
-*/
-static void CM_TransposeGrid( cGrid_t *grid ) {
- int i, j, l;
- vec3_t temp;
- qboolean tempWrap;
-
- if ( grid->width > grid->height ) {
- for ( i = 0 ; i < grid->height ; i++ ) {
- for ( j = i + 1 ; j < grid->width ; j++ ) {
- if ( j < grid->height ) {
- // swap the value
- VectorCopy( grid->points[i][j], temp );
- VectorCopy( grid->points[j][i], grid->points[i][j] );
- VectorCopy( temp, grid->points[j][i] );
- } else {
- // just copy
- VectorCopy( grid->points[j][i], grid->points[i][j] );
- }
- }
- }
- } else {
- for ( i = 0 ; i < grid->width ; i++ ) {
- for ( j = i + 1 ; j < grid->height ; j++ ) {
- if ( j < grid->width ) {
- // swap the value
- VectorCopy( grid->points[j][i], temp );
- VectorCopy( grid->points[i][j], grid->points[j][i] );
- VectorCopy( temp, grid->points[i][j] );
- } else {
- // just copy
- VectorCopy( grid->points[i][j], grid->points[j][i] );
- }
- }
- }
- }
-
- l = grid->width;
- grid->width = grid->height;
- grid->height = l;
-
- tempWrap = grid->wrapWidth;
- grid->wrapWidth = grid->wrapHeight;
- grid->wrapHeight = tempWrap;
-}
-
-/*
-===================
-CM_SetGridWrapWidth
-
-If the left and right columns are exactly equal, set grid->wrapWidth qtrue
-===================
-*/
-static void CM_SetGridWrapWidth( cGrid_t *grid ) {
- int i, j;
- float d;
-
- for ( i = 0 ; i < grid->height ; i++ ) {
- for ( j = 0 ; j < 3 ; j++ ) {
- d = grid->points[0][i][j] - grid->points[grid->width-1][i][j];
- if ( d < -WRAP_POINT_EPSILON || d > WRAP_POINT_EPSILON ) {
- break;
- }
- }
- if ( j != 3 ) {
- break;
- }
- }
- if ( i == grid->height ) {
- grid->wrapWidth = qtrue;
- } else {
- grid->wrapWidth = qfalse;
- }
-}
-
-/*
-=================
-CM_SubdivideGridColumns
-
-Adds columns as necessary to the grid until
-all the aproximating points are within SUBDIVIDE_DISTANCE
-from the true curve
-=================
-*/
-static void CM_SubdivideGridColumns( cGrid_t *grid ) {
- int i, j, k;
-
- for ( i = 0 ; i < grid->width - 2 ; ) {
- // grid->points[i][x] is an interpolating control point
- // grid->points[i+1][x] is an aproximating control point
- // grid->points[i+2][x] is an interpolating control point
-
- //
- // first see if we can collapse the aproximating collumn away
- //
- for ( j = 0 ; j < grid->height ; j++ ) {
- if ( CM_NeedsSubdivision( grid->points[i][j], grid->points[i+1][j], grid->points[i+2][j] ) ) {
- break;
- }
- }
- if ( j == grid->height ) {
- // all of the points were close enough to the linear midpoints
- // that we can collapse the entire column away
- for ( j = 0 ; j < grid->height ; j++ ) {
- // remove the column
- for ( k = i + 2 ; k < grid->width ; k++ ) {
- VectorCopy( grid->points[k][j], grid->points[k-1][j] );
- }
- }
-
- grid->width--;
-
- // go to the next curve segment
- i++;
- continue;
- }
-
- //
- // we need to subdivide the curve
- //
- for ( j = 0 ; j < grid->height ; j++ ) {
- vec3_t prev, mid, next;
-
- // save the control points now
- VectorCopy( grid->points[i][j], prev );
- VectorCopy( grid->points[i+1][j], mid );
- VectorCopy( grid->points[i+2][j], next );
-
- // make room for two additional columns in the grid
- // columns i+1 will be replaced, column i+2 will become i+4
- // i+1, i+2, and i+3 will be generated
- for ( k = grid->width - 1 ; k > i + 1 ; k-- ) {
- VectorCopy( grid->points[k][j], grid->points[k+2][j] );
- }
-
- // generate the subdivided points
- CM_Subdivide( prev, mid, next, grid->points[i+1][j], grid->points[i+2][j], grid->points[i+3][j] );
- }
-
- grid->width += 2;
-
- // the new aproximating point at i+1 may need to be removed
- // or subdivided farther, so don't advance i
- }
-}
-
-/*
-======================
-CM_ComparePoints
-======================
-*/
-#define POINT_EPSILON 0.1
-static qboolean CM_ComparePoints( float *a, float *b ) {
- float d;
-
- d = a[0] - b[0];
- if ( d < -POINT_EPSILON || d > POINT_EPSILON ) {
- return qfalse;
- }
- d = a[1] - b[1];
- if ( d < -POINT_EPSILON || d > POINT_EPSILON ) {
- return qfalse;
- }
- d = a[2] - b[2];
- if ( d < -POINT_EPSILON || d > POINT_EPSILON ) {
- return qfalse;
- }
- return qtrue;
-}
-
-/*
-=================
-CM_RemoveDegenerateColumns
-
-If there are any identical columns, remove them
-=================
-*/
-static void CM_RemoveDegenerateColumns( cGrid_t *grid ) {
- int i, j, k;
-
- for ( i = 0 ; i < grid->width - 1 ; i++ ) {
- for ( j = 0 ; j < grid->height ; j++ ) {
- if ( !CM_ComparePoints( grid->points[i][j], grid->points[i+1][j] ) ) {
- break;
- }
- }
-
- if ( j != grid->height ) {
- continue; // not degenerate
- }
-
- for ( j = 0 ; j < grid->height ; j++ ) {
- // remove the column
- for ( k = i + 2 ; k < grid->width ; k++ ) {
- VectorCopy( grid->points[k][j], grid->points[k-1][j] );
- }
- }
- grid->width--;
-
- // check against the next column
- i--;
- }
-}
-
-/*
-================================================================================
-
-PATCH COLLIDE GENERATION
-
-================================================================================
-*/
-
-static int numPlanes;
-static patchPlane_t planes[MAX_PATCH_PLANES];
-
-static int numFacets;
-static facet_t facets[MAX_PATCH_PLANES]; //maybe MAX_FACETS ??
-
-#define NORMAL_EPSILON 0.0001
-#define DIST_EPSILON 0.02
-
-/*
-==================
-CM_PlaneEqual
-==================
-*/
-int CM_PlaneEqual(patchPlane_t *p, float plane[4], int *flipped) {
- float invplane[4];
-
- if (
- fabs(p->plane[0] - plane[0]) < NORMAL_EPSILON
- && fabs(p->plane[1] - plane[1]) < NORMAL_EPSILON
- && fabs(p->plane[2] - plane[2]) < NORMAL_EPSILON
- && fabs(p->plane[3] - plane[3]) < DIST_EPSILON )
- {
- *flipped = qfalse;
- return qtrue;
- }
-
- VectorNegate(plane, invplane);
- invplane[3] = -plane[3];
-
- if (
- fabs(p->plane[0] - invplane[0]) < NORMAL_EPSILON
- && fabs(p->plane[1] - invplane[1]) < NORMAL_EPSILON
- && fabs(p->plane[2] - invplane[2]) < NORMAL_EPSILON
- && fabs(p->plane[3] - invplane[3]) < DIST_EPSILON )
- {
- *flipped = qtrue;
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-==================
-CM_SnapVector
-==================
-*/
-void CM_SnapVector(vec3_t normal) {
- int i;
-
- for (i=0 ; i<3 ; i++)
- {
- if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
- {
- VectorClear (normal);
- normal[i] = 1;
- break;
- }
- if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
- {
- VectorClear (normal);
- normal[i] = -1;
- break;
- }
- }
-}
-
-/*
-==================
-CM_FindPlane2
-==================
-*/
-int CM_FindPlane2(float plane[4], int *flipped) {
- int i;
-
- // see if the points are close enough to an existing plane
- for ( i = 0 ; i < numPlanes ; i++ ) {
- if (CM_PlaneEqual(&planes[i], plane, flipped)) return i;
- }
-
- // add a new plane
- if ( numPlanes == MAX_PATCH_PLANES ) {
- Com_Error( ERR_DROP, "MAX_PATCH_PLANES" );
- }
-
- Vector4Copy( plane, planes[numPlanes].plane );
- planes[numPlanes].signbits = CM_SignbitsForNormal( plane );
-
- numPlanes++;
-
- *flipped = qfalse;
-
- return numPlanes-1;
-}
-
-/*
-==================
-CM_FindPlane
-==================
-*/
-static int CM_FindPlane( float *p1, float *p2, float *p3 ) {
- float plane[4];
- int i;
- float d;
-
- if ( !CM_PlaneFromPoints( plane, p1, p2, p3 ) ) {
- return -1;
- }
-
- // see if the points are close enough to an existing plane
- for ( i = 0 ; i < numPlanes ; i++ ) {
- if ( DotProduct( plane, planes[i].plane ) < 0 ) {
- continue; // allow backwards planes?
- }
-
- d = DotProduct( p1, planes[i].plane ) - planes[i].plane[3];
- if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {
- continue;
- }
-
- d = DotProduct( p2, planes[i].plane ) - planes[i].plane[3];
- if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {
- continue;
- }
-
- d = DotProduct( p3, planes[i].plane ) - planes[i].plane[3];
- if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {
- continue;
- }
-
- // found it
- return i;
- }
-
- // add a new plane
- if ( numPlanes == MAX_PATCH_PLANES ) {
- Com_Error( ERR_DROP, "MAX_PATCH_PLANES" );
- }
-
- Vector4Copy( plane, planes[numPlanes].plane );
- planes[numPlanes].signbits = CM_SignbitsForNormal( plane );
-
- numPlanes++;
-
- return numPlanes-1;
-}
-
-/*
-==================
-CM_PointOnPlaneSide
-==================
-*/
-static int CM_PointOnPlaneSide( float *p, int planeNum ) {
- float *plane;
- float d;
-
- if ( planeNum == -1 ) {
- return SIDE_ON;
- }
- plane = planes[ planeNum ].plane;
-
- d = DotProduct( p, plane ) - plane[3];
-
- if ( d > PLANE_TRI_EPSILON ) {
- return SIDE_FRONT;
- }
-
- if ( d < -PLANE_TRI_EPSILON ) {
- return SIDE_BACK;
- }
-
- return SIDE_ON;
-}
-
-/*
-==================
-CM_GridPlane
-==================
-*/
-static int CM_GridPlane( int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], int i, int j, int tri ) {
- int p;
-
- p = gridPlanes[i][j][tri];
- if ( p != -1 ) {
- return p;
- }
- p = gridPlanes[i][j][!tri];
- if ( p != -1 ) {
- return p;
- }
-
- // should never happen
- Com_Printf( "WARNING: CM_GridPlane unresolvable\n" );
- return -1;
-}
-
-/*
-==================
-CM_EdgePlaneNum
-==================
-*/
-static int CM_EdgePlaneNum( cGrid_t *grid, int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], int i, int j, int k ) {
- float *p1, *p2;
- vec3_t up;
- int p;
-
- switch ( k ) {
- case 0: // top border
- p1 = grid->points[i][j];
- p2 = grid->points[i+1][j];
- p = CM_GridPlane( gridPlanes, i, j, 0 );
- VectorMA( p1, 4, planes[ p ].plane, up );
- return CM_FindPlane( p1, p2, up );
-
- case 2: // bottom border
- p1 = grid->points[i][j+1];
- p2 = grid->points[i+1][j+1];
- p = CM_GridPlane( gridPlanes, i, j, 1 );
- VectorMA( p1, 4, planes[ p ].plane, up );
- return CM_FindPlane( p2, p1, up );
-
- case 3: // left border
- p1 = grid->points[i][j];
- p2 = grid->points[i][j+1];
- p = CM_GridPlane( gridPlanes, i, j, 1 );
- VectorMA( p1, 4, planes[ p ].plane, up );
- return CM_FindPlane( p2, p1, up );
-
- case 1: // right border
- p1 = grid->points[i+1][j];
- p2 = grid->points[i+1][j+1];
- p = CM_GridPlane( gridPlanes, i, j, 0 );
- VectorMA( p1, 4, planes[ p ].plane, up );
- return CM_FindPlane( p1, p2, up );
-
- case 4: // diagonal out of triangle 0
- p1 = grid->points[i+1][j+1];
- p2 = grid->points[i][j];
- p = CM_GridPlane( gridPlanes, i, j, 0 );
- VectorMA( p1, 4, planes[ p ].plane, up );
- return CM_FindPlane( p1, p2, up );
-
- case 5: // diagonal out of triangle 1
- p1 = grid->points[i][j];
- p2 = grid->points[i+1][j+1];
- p = CM_GridPlane( gridPlanes, i, j, 1 );
- VectorMA( p1, 4, planes[ p ].plane, up );
- return CM_FindPlane( p1, p2, up );
-
- }
-
- Com_Error( ERR_DROP, "CM_EdgePlaneNum: bad k" );
- return -1;
-}
-
-/*
-===================
-CM_SetBorderInward
-===================
-*/
-static void CM_SetBorderInward( facet_t *facet, cGrid_t *grid, int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2],
- int i, int j, int which ) {
- int k, l;
- float *points[4];
- int numPoints;
-
- switch ( which ) {
- case -1:
- points[0] = grid->points[i][j];
- points[1] = grid->points[i+1][j];
- points[2] = grid->points[i+1][j+1];
- points[3] = grid->points[i][j+1];
- numPoints = 4;
- break;
- case 0:
- points[0] = grid->points[i][j];
- points[1] = grid->points[i+1][j];
- points[2] = grid->points[i+1][j+1];
- numPoints = 3;
- break;
- case 1:
- points[0] = grid->points[i+1][j+1];
- points[1] = grid->points[i][j+1];
- points[2] = grid->points[i][j];
- numPoints = 3;
- break;
- default:
- Com_Error( ERR_FATAL, "CM_SetBorderInward: bad parameter" );
- numPoints = 0;
- break;
- }
-
- for ( k = 0 ; k < facet->numBorders ; k++ ) {
- int front, back;
-
- front = 0;
- back = 0;
-
- for ( l = 0 ; l < numPoints ; l++ ) {
- int side;
-
- side = CM_PointOnPlaneSide( points[l], facet->borderPlanes[k] );
- if ( side == SIDE_FRONT ) {
- front++;
- } if ( side == SIDE_BACK ) {
- back++;
- }
- }
-
- if ( front && !back ) {
- facet->borderInward[k] = qtrue;
- } else if ( back && !front ) {
- facet->borderInward[k] = qfalse;
- } else if ( !front && !back ) {
- // flat side border
- facet->borderPlanes[k] = -1;
- } else {
- // bisecting side border
- Com_DPrintf( "WARNING: CM_SetBorderInward: mixed plane sides\n" );
- facet->borderInward[k] = qfalse;
- if ( !debugBlock ) {
- debugBlock = qtrue;
- VectorCopy( grid->points[i][j], debugBlockPoints[0] );
- VectorCopy( grid->points[i+1][j], debugBlockPoints[1] );
- VectorCopy( grid->points[i+1][j+1], debugBlockPoints[2] );
- VectorCopy( grid->points[i][j+1], debugBlockPoints[3] );
- }
- }
- }
-}
-
-/*
-==================
-CM_ValidateFacet
-
-If the facet isn't bounded by its borders, we screwed up.
-==================
-*/
-static qboolean CM_ValidateFacet( facet_t *facet ) {
- float plane[4];
- int j;
- winding_t *w;
- vec3_t bounds[2];
-
- if ( facet->surfacePlane == -1 ) {
- return qfalse;
- }
-
- Vector4Copy( planes[ facet->surfacePlane ].plane, plane );
- w = BaseWindingForPlane( plane, plane[3] );
- for ( j = 0 ; j < facet->numBorders && w ; j++ ) {
- if ( facet->borderPlanes[j] == -1 ) {
- FreeWinding( w );
- return qfalse;
- }
- Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane );
- if ( !facet->borderInward[j] ) {
- VectorSubtract( vec3_origin, plane, plane );
- plane[3] = -plane[3];
- }
- ChopWindingInPlace( &w, plane, plane[3], 0.1f );
- }
-
- if ( !w ) {
- return qfalse; // winding was completely chopped away
- }
-
- // see if the facet is unreasonably large
- WindingBounds( w, bounds[0], bounds[1] );
- FreeWinding( w );
-
- for ( j = 0 ; j < 3 ; j++ ) {
- if ( bounds[1][j] - bounds[0][j] > MAX_MAP_BOUNDS ) {
- return qfalse; // we must be missing a plane
- }
- if ( bounds[0][j] >= MAX_MAP_BOUNDS ) {
- return qfalse;
- }
- if ( bounds[1][j] <= -MAX_MAP_BOUNDS ) {
- return qfalse;
- }
- }
- return qtrue; // winding is fine
-}
-
-/*
-==================
-CM_AddFacetBevels
-==================
-*/
-void CM_AddFacetBevels( facet_t *facet ) {
-
- int i, j, k, l;
- int axis, dir, order, flipped;
- float plane[4], d, newplane[4];
- winding_t *w, *w2;
- vec3_t mins, maxs, vec, vec2;
-
- Vector4Copy( planes[ facet->surfacePlane ].plane, plane );
-
- w = BaseWindingForPlane( plane, plane[3] );
- for ( j = 0 ; j < facet->numBorders && w ; j++ ) {
- if (facet->borderPlanes[j] == facet->surfacePlane) continue;
- Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane );
-
- if ( !facet->borderInward[j] ) {
- VectorSubtract( vec3_origin, plane, plane );
- plane[3] = -plane[3];
- }
-
- ChopWindingInPlace( &w, plane, plane[3], 0.1f );
- }
- if ( !w ) {
- return;
- }
-
- WindingBounds(w, mins, maxs);
-
- // add the axial planes
- order = 0;
- for ( axis = 0 ; axis < 3 ; axis++ )
- {
- for ( dir = -1 ; dir <= 1 ; dir += 2, order++ )
- {
- VectorClear(plane);
- plane[axis] = dir;
- if (dir == 1) {
- plane[3] = maxs[axis];
- }
- else {
- plane[3] = -mins[axis];
- }
- //if it's the surface plane
- if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) {
- continue;
- }
- // see if the plane is allready present
- for ( i = 0 ; i < facet->numBorders ; i++ ) {
- if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped))
- break;
- }
-
- if ( i == facet->numBorders ) {
- if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n");
- facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);
- facet->borderNoAdjust[facet->numBorders] = 0;
- facet->borderInward[facet->numBorders] = flipped;
- facet->numBorders++;
- }
- }
- }
- //
- // add the edge bevels
- //
- // test the non-axial plane edges
- for ( j = 0 ; j < w->numpoints ; j++ )
- {
- k = (j+1)%w->numpoints;
- VectorSubtract (w->p[j], w->p[k], vec);
- //if it's a degenerate edge
- if (VectorNormalize (vec) < 0.5)
- continue;
- CM_SnapVector(vec);
- for ( k = 0; k < 3 ; k++ )
- if ( vec[k] == -1 || vec[k] == 1 )
- break; // axial
- if ( k < 3 )
- continue; // only test non-axial edges
-
- // try the six possible slanted axials from this edge
- for ( axis = 0 ; axis < 3 ; axis++ )
- {
- for ( dir = -1 ; dir <= 1 ; dir += 2 )
- {
- // construct a plane
- VectorClear (vec2);
- vec2[axis] = dir;
- CrossProduct (vec, vec2, plane);
- if (VectorNormalize (plane) < 0.5)
- continue;
- plane[3] = DotProduct (w->p[j], plane);
-
- // if all the points of the facet winding are
- // behind this plane, it is a proper edge bevel
- for ( l = 0 ; l < w->numpoints ; l++ )
- {
- d = DotProduct (w->p[l], plane) - plane[3];
- if (d > 0.1)
- break; // point in front
- }
- if ( l < w->numpoints )
- continue;
-
- //if it's the surface plane
- if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) {
- continue;
- }
- // see if the plane is allready present
- for ( i = 0 ; i < facet->numBorders ; i++ ) {
- if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) {
- break;
- }
- }
-
- if ( i == facet->numBorders ) {
- if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n");
- facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);
-
- for ( k = 0 ; k < facet->numBorders ; k++ ) {
- if (facet->borderPlanes[facet->numBorders] ==
- facet->borderPlanes[k]) Com_Printf("WARNING: bevel plane already used\n");
- }
-
- facet->borderNoAdjust[facet->numBorders] = 0;
- facet->borderInward[facet->numBorders] = flipped;
- //
- w2 = CopyWinding(w);
- Vector4Copy(planes[facet->borderPlanes[facet->numBorders]].plane, newplane);
- if (!facet->borderInward[facet->numBorders])
- {
- VectorNegate(newplane, newplane);
- newplane[3] = -newplane[3];
- } //end if
- ChopWindingInPlace( &w2, newplane, newplane[3], 0.1f );
- if (!w2) {
- Com_DPrintf("WARNING: CM_AddFacetBevels... invalid bevel\n");
- continue;
- }
- else {
- FreeWinding(w2);
- }
- //
- facet->numBorders++;
- //already got a bevel
-// break;
- }
- }
- }
- }
- FreeWinding( w );
-
-#ifndef BSPC
- //add opposite plane
- facet->borderPlanes[facet->numBorders] = facet->surfacePlane;
- facet->borderNoAdjust[facet->numBorders] = 0;
- facet->borderInward[facet->numBorders] = qtrue;
- facet->numBorders++;
-#endif //BSPC
-
-}
-
-typedef enum {
- EN_TOP,
- EN_RIGHT,
- EN_BOTTOM,
- EN_LEFT
-} edgeName_t;
-
-/*
-==================
-CM_PatchCollideFromGrid
-==================
-*/
-static void CM_PatchCollideFromGrid( cGrid_t *grid, patchCollide_t *pf ) {
- int i, j;
- float *p1, *p2, *p3;
- int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2];
- facet_t *facet;
- int borders[4];
- int noAdjust[4];
-
- numPlanes = 0;
- numFacets = 0;
-
- // find the planes for each triangle of the grid
- for ( i = 0 ; i < grid->width - 1 ; i++ ) {
- for ( j = 0 ; j < grid->height - 1 ; j++ ) {
- p1 = grid->points[i][j];
- p2 = grid->points[i+1][j];
- p3 = grid->points[i+1][j+1];
- gridPlanes[i][j][0] = CM_FindPlane( p1, p2, p3 );
-
- p1 = grid->points[i+1][j+1];
- p2 = grid->points[i][j+1];
- p3 = grid->points[i][j];
- gridPlanes[i][j][1] = CM_FindPlane( p1, p2, p3 );
- }
- }
-
- // create the borders for each facet
- for ( i = 0 ; i < grid->width - 1 ; i++ ) {
- for ( j = 0 ; j < grid->height - 1 ; j++ ) {
-
- borders[EN_TOP] = -1;
- if ( j > 0 ) {
- borders[EN_TOP] = gridPlanes[i][j-1][1];
- } else if ( grid->wrapHeight ) {
- borders[EN_TOP] = gridPlanes[i][grid->height-2][1];
- }
- noAdjust[EN_TOP] = ( borders[EN_TOP] == gridPlanes[i][j][0] );
- if ( borders[EN_TOP] == -1 || noAdjust[EN_TOP] ) {
- borders[EN_TOP] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 0 );
- }
-
- borders[EN_BOTTOM] = -1;
- if ( j < grid->height - 2 ) {
- borders[EN_BOTTOM] = gridPlanes[i][j+1][0];
- } else if ( grid->wrapHeight ) {
- borders[EN_BOTTOM] = gridPlanes[i][0][0];
- }
- noAdjust[EN_BOTTOM] = ( borders[EN_BOTTOM] == gridPlanes[i][j][1] );
- if ( borders[EN_BOTTOM] == -1 || noAdjust[EN_BOTTOM] ) {
- borders[EN_BOTTOM] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 2 );
- }
-
- borders[EN_LEFT] = -1;
- if ( i > 0 ) {
- borders[EN_LEFT] = gridPlanes[i-1][j][0];
- } else if ( grid->wrapWidth ) {
- borders[EN_LEFT] = gridPlanes[grid->width-2][j][0];
- }
- noAdjust[EN_LEFT] = ( borders[EN_LEFT] == gridPlanes[i][j][1] );
- if ( borders[EN_LEFT] == -1 || noAdjust[EN_LEFT] ) {
- borders[EN_LEFT] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 3 );
- }
-
- borders[EN_RIGHT] = -1;
- if ( i < grid->width - 2 ) {
- borders[EN_RIGHT] = gridPlanes[i+1][j][1];
- } else if ( grid->wrapWidth ) {
- borders[EN_RIGHT] = gridPlanes[0][j][1];
- }
- noAdjust[EN_RIGHT] = ( borders[EN_RIGHT] == gridPlanes[i][j][0] );
- if ( borders[EN_RIGHT] == -1 || noAdjust[EN_RIGHT] ) {
- borders[EN_RIGHT] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 1 );
- }
-
- if ( numFacets == MAX_FACETS ) {
- Com_Error( ERR_DROP, "MAX_FACETS" );
- }
- facet = &facets[numFacets];
- Com_Memset( facet, 0, sizeof( *facet ) );
-
- if ( gridPlanes[i][j][0] == gridPlanes[i][j][1] ) {
- if ( gridPlanes[i][j][0] == -1 ) {
- continue; // degenrate
- }
- facet->surfacePlane = gridPlanes[i][j][0];
- facet->numBorders = 4;
- facet->borderPlanes[0] = borders[EN_TOP];
- facet->borderNoAdjust[0] = noAdjust[EN_TOP];
- facet->borderPlanes[1] = borders[EN_RIGHT];
- facet->borderNoAdjust[1] = noAdjust[EN_RIGHT];
- facet->borderPlanes[2] = borders[EN_BOTTOM];
- facet->borderNoAdjust[2] = noAdjust[EN_BOTTOM];
- facet->borderPlanes[3] = borders[EN_LEFT];
- facet->borderNoAdjust[3] = noAdjust[EN_LEFT];
- CM_SetBorderInward( facet, grid, gridPlanes, i, j, -1 );
- if ( CM_ValidateFacet( facet ) ) {
- CM_AddFacetBevels( facet );
- numFacets++;
- }
- } else {
- // two seperate triangles
- facet->surfacePlane = gridPlanes[i][j][0];
- facet->numBorders = 3;
- facet->borderPlanes[0] = borders[EN_TOP];
- facet->borderNoAdjust[0] = noAdjust[EN_TOP];
- facet->borderPlanes[1] = borders[EN_RIGHT];
- facet->borderNoAdjust[1] = noAdjust[EN_RIGHT];
- facet->borderPlanes[2] = gridPlanes[i][j][1];
- if ( facet->borderPlanes[2] == -1 ) {
- facet->borderPlanes[2] = borders[EN_BOTTOM];
- if ( facet->borderPlanes[2] == -1 ) {
- facet->borderPlanes[2] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 4 );
- }
- }
- CM_SetBorderInward( facet, grid, gridPlanes, i, j, 0 );
- if ( CM_ValidateFacet( facet ) ) {
- CM_AddFacetBevels( facet );
- numFacets++;
- }
-
- if ( numFacets == MAX_FACETS ) {
- Com_Error( ERR_DROP, "MAX_FACETS" );
- }
- facet = &facets[numFacets];
- Com_Memset( facet, 0, sizeof( *facet ) );
-
- facet->surfacePlane = gridPlanes[i][j][1];
- facet->numBorders = 3;
- facet->borderPlanes[0] = borders[EN_BOTTOM];
- facet->borderNoAdjust[0] = noAdjust[EN_BOTTOM];
- facet->borderPlanes[1] = borders[EN_LEFT];
- facet->borderNoAdjust[1] = noAdjust[EN_LEFT];
- facet->borderPlanes[2] = gridPlanes[i][j][0];
- if ( facet->borderPlanes[2] == -1 ) {
- facet->borderPlanes[2] = borders[EN_TOP];
- if ( facet->borderPlanes[2] == -1 ) {
- facet->borderPlanes[2] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 5 );
- }
- }
- CM_SetBorderInward( facet, grid, gridPlanes, i, j, 1 );
- if ( CM_ValidateFacet( facet ) ) {
- CM_AddFacetBevels( facet );
- numFacets++;
- }
- }
- }
- }
-
- // copy the results out
- pf->numPlanes = numPlanes;
- pf->numFacets = numFacets;
- pf->facets = Hunk_Alloc( numFacets * sizeof( *pf->facets ), h_high );
- Com_Memcpy( pf->facets, facets, numFacets * sizeof( *pf->facets ) );
- pf->planes = Hunk_Alloc( numPlanes * sizeof( *pf->planes ), h_high );
- Com_Memcpy( pf->planes, planes, numPlanes * sizeof( *pf->planes ) );
-}
-
-
-/*
-===================
-CM_GeneratePatchCollide
-
-Creates an internal structure that will be used to perform
-collision detection with a patch mesh.
-
-Points is packed as concatenated rows.
-===================
-*/
-struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, vec3_t *points ) {
- patchCollide_t *pf;
- cGrid_t grid;
- int i, j;
-
- if ( width <= 2 || height <= 2 || !points ) {
- Com_Error( ERR_DROP, "CM_GeneratePatchFacets: bad parameters: (%i, %i, %p)",
- width, height, (void *)points );
- }
-
- if ( !(width & 1) || !(height & 1) ) {
- Com_Error( ERR_DROP, "CM_GeneratePatchFacets: even sizes are invalid for quadratic meshes" );
- }
-
- if ( width > MAX_GRID_SIZE || height > MAX_GRID_SIZE ) {
- Com_Error( ERR_DROP, "CM_GeneratePatchFacets: source is > MAX_GRID_SIZE" );
- }
-
- // build a grid
- grid.width = width;
- grid.height = height;
- grid.wrapWidth = qfalse;
- grid.wrapHeight = qfalse;
- for ( i = 0 ; i < width ; i++ ) {
- for ( j = 0 ; j < height ; j++ ) {
- VectorCopy( points[j*width + i], grid.points[i][j] );
- }
- }
-
- // subdivide the grid
- CM_SetGridWrapWidth( &grid );
- CM_SubdivideGridColumns( &grid );
- CM_RemoveDegenerateColumns( &grid );
-
- CM_TransposeGrid( &grid );
-
- CM_SetGridWrapWidth( &grid );
- CM_SubdivideGridColumns( &grid );
- CM_RemoveDegenerateColumns( &grid );
-
- // we now have a grid of points exactly on the curve
- // the aproximate surface defined by these points will be
- // collided against
- pf = Hunk_Alloc( sizeof( *pf ), h_high );
- ClearBounds( pf->bounds[0], pf->bounds[1] );
- for ( i = 0 ; i < grid.width ; i++ ) {
- for ( j = 0 ; j < grid.height ; j++ ) {
- AddPointToBounds( grid.points[i][j], pf->bounds[0], pf->bounds[1] );
- }
- }
-
- c_totalPatchBlocks += ( grid.width - 1 ) * ( grid.height - 1 );
-
- // generate a bsp tree for the surface
- CM_PatchCollideFromGrid( &grid, pf );
-
- // expand by one unit for epsilon purposes
- pf->bounds[0][0] -= 1;
- pf->bounds[0][1] -= 1;
- pf->bounds[0][2] -= 1;
-
- pf->bounds[1][0] += 1;
- pf->bounds[1][1] += 1;
- pf->bounds[1][2] += 1;
-
- return pf;
-}
-
-/*
-================================================================================
-
-TRACE TESTING
-
-================================================================================
-*/
-
-/*
-====================
-CM_TracePointThroughPatchCollide
-
- special case for point traces because the patch collide "brushes" have no volume
-====================
-*/
-void CM_TracePointThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {
- qboolean frontFacing[MAX_PATCH_PLANES];
- float intersection[MAX_PATCH_PLANES];
- float intersect;
- const patchPlane_t *planes;
- const facet_t *facet;
- int i, j, k;
- float offset;
- float d1, d2;
-#ifndef BSPC
- static cvar_t *cv;
-#endif //BSPC
-
-#ifndef BSPC
- if ( !cm_playerCurveClip->integer || !tw->isPoint ) {
- return;
- }
-#endif
-
- // determine the trace's relationship to all planes
- planes = pc->planes;
- for ( i = 0 ; i < pc->numPlanes ; i++, planes++ ) {
- offset = DotProduct( tw->offsets[ planes->signbits ], planes->plane );
- d1 = DotProduct( tw->start, planes->plane ) - planes->plane[3] + offset;
- d2 = DotProduct( tw->end, planes->plane ) - planes->plane[3] + offset;
- if ( d1 <= 0 ) {
- frontFacing[i] = qfalse;
- } else {
- frontFacing[i] = qtrue;
- }
- if ( d1 == d2 ) {
- intersection[i] = 99999;
- } else {
- intersection[i] = d1 / ( d1 - d2 );
- if ( intersection[i] <= 0 ) {
- intersection[i] = 99999;
- }
- }
- }
-
-
- // see if any of the surface planes are intersected
- facet = pc->facets;
- for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {
- if ( !frontFacing[facet->surfacePlane] ) {
- continue;
- }
- intersect = intersection[facet->surfacePlane];
- if ( intersect < 0 ) {
- continue; // surface is behind the starting point
- }
- if ( intersect > tw->trace.fraction ) {
- continue; // already hit something closer
- }
- for ( j = 0 ; j < facet->numBorders ; j++ ) {
- k = facet->borderPlanes[j];
- if ( frontFacing[k] ^ facet->borderInward[j] ) {
- if ( intersection[k] > intersect ) {
- break;
- }
- } else {
- if ( intersection[k] < intersect ) {
- break;
- }
- }
- }
- if ( j == facet->numBorders ) {
- // we hit this facet
-#ifndef BSPC
- if (!cv) {
- cv = Cvar_Get( "r_debugSurfaceUpdate", "1", 0 );
- }
- if (cv->integer) {
- debugPatchCollide = pc;
- debugFacet = facet;
- }
-#endif //BSPC
- planes = &pc->planes[facet->surfacePlane];
-
- // calculate intersection with a slight pushoff
- offset = DotProduct( tw->offsets[ planes->signbits ], planes->plane );
- d1 = DotProduct( tw->start, planes->plane ) - planes->plane[3] + offset;
- d2 = DotProduct( tw->end, planes->plane ) - planes->plane[3] + offset;
- tw->trace.fraction = ( d1 - SURFACE_CLIP_EPSILON ) / ( d1 - d2 );
-
- if ( tw->trace.fraction < 0 ) {
- tw->trace.fraction = 0;
- }
-
- VectorCopy( planes->plane, tw->trace.plane.normal );
- tw->trace.plane.dist = planes->plane[3];
- }
- }
-}
-
-/*
-====================
-CM_CheckFacetPlane
-====================
-*/
-int CM_CheckFacetPlane(float *plane, vec3_t start, vec3_t end, float *enterFrac, float *leaveFrac, int *hit) {
- float d1, d2, f;
-
- *hit = qfalse;
-
- d1 = DotProduct( start, plane ) - plane[3];
- d2 = DotProduct( end, plane ) - plane[3];
-
- // if completely in front of face, no intersection with the entire facet
- if (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 ) ) {
- return qfalse;
- }
-
- // if it doesn't cross the plane, the plane isn't relevent
- if (d1 <= 0 && d2 <= 0 ) {
- return qtrue;
- }
-
- // crosses face
- if (d1 > d2) { // enter
- f = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);
- if ( f < 0 ) {
- f = 0;
- }
- //always favor previous plane hits and thus also the surface plane hit
- if (f > *enterFrac) {
- *enterFrac = f;
- *hit = qtrue;
- }
- } else { // leave
- f = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);
- if ( f > 1 ) {
- f = 1;
- }
- if (f < *leaveFrac) {
- *leaveFrac = f;
- }
- }
- return qtrue;
-}
-
-/*
-====================
-CM_TraceThroughPatchCollide
-====================
-*/
-void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {
- int i, j, hit, hitnum;
- float offset, enterFrac, leaveFrac, t;
- patchPlane_t *planes;
- facet_t *facet;
- float plane[4] = {0, 0, 0, 0}, bestplane[4] = {0, 0, 0, 0};
- vec3_t startp, endp;
-#ifndef BSPC
- static cvar_t *cv;
-#endif //BSPC
-
- if ( !CM_BoundsIntersect( tw->bounds[0], tw->bounds[1],
- pc->bounds[0], pc->bounds[1] ) ) {
- return;
- }
-
- if (tw->isPoint) {
- CM_TracePointThroughPatchCollide( tw, pc );
- return;
- }
-
- facet = pc->facets;
- for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {
- enterFrac = -1.0;
- leaveFrac = 1.0;
- hitnum = -1;
- //
- planes = &pc->planes[ facet->surfacePlane ];
- VectorCopy(planes->plane, plane);
- plane[3] = planes->plane[3];
- if ( tw->sphere.use ) {
- // adjust the plane distance apropriately for radius
- plane[3] += tw->sphere.radius;
-
- // find the closest point on the capsule to the plane
- t = DotProduct( plane, tw->sphere.offset );
- if ( t > 0.0f ) {
- VectorSubtract( tw->start, tw->sphere.offset, startp );
- VectorSubtract( tw->end, tw->sphere.offset, endp );
- }
- else {
- VectorAdd( tw->start, tw->sphere.offset, startp );
- VectorAdd( tw->end, tw->sphere.offset, endp );
- }
- }
- else {
- offset = DotProduct( tw->offsets[ planes->signbits ], plane);
- plane[3] -= offset;
- VectorCopy( tw->start, startp );
- VectorCopy( tw->end, endp );
- }
-
- if (!CM_CheckFacetPlane(plane, startp, endp, &enterFrac, &leaveFrac, &hit)) {
- continue;
- }
- if (hit) {
- Vector4Copy(plane, bestplane);
- }
-
- for ( j = 0; j < facet->numBorders; j++ ) {
- planes = &pc->planes[ facet->borderPlanes[j] ];
- if (facet->borderInward[j]) {
- VectorNegate(planes->plane, plane);
- plane[3] = -planes->plane[3];
- }
- else {
- VectorCopy(planes->plane, plane);
- plane[3] = planes->plane[3];
- }
- if ( tw->sphere.use ) {
- // adjust the plane distance apropriately for radius
- plane[3] += tw->sphere.radius;
-
- // find the closest point on the capsule to the plane
- t = DotProduct( plane, tw->sphere.offset );
- if ( t > 0.0f ) {
- VectorSubtract( tw->start, tw->sphere.offset, startp );
- VectorSubtract( tw->end, tw->sphere.offset, endp );
- }
- else {
- VectorAdd( tw->start, tw->sphere.offset, startp );
- VectorAdd( tw->end, tw->sphere.offset, endp );
- }
- }
- else {
- // NOTE: this works even though the plane might be flipped because the bbox is centered
- offset = DotProduct( tw->offsets[ planes->signbits ], plane);
- plane[3] += fabs(offset);
- VectorCopy( tw->start, startp );
- VectorCopy( tw->end, endp );
- }
-
- if (!CM_CheckFacetPlane(plane, startp, endp, &enterFrac, &leaveFrac, &hit)) {
- break;
- }
- if (hit) {
- hitnum = j;
- Vector4Copy(plane, bestplane);
- }
- }
- if (j < facet->numBorders) continue;
- //never clip against the back side
- if (hitnum == facet->numBorders - 1) continue;
-
- if (enterFrac < leaveFrac && enterFrac >= 0) {
- if (enterFrac < tw->trace.fraction) {
- if (enterFrac < 0) {
- enterFrac = 0;
- }
-#ifndef BSPC
- if (!cv) {
- cv = Cvar_Get( "r_debugSurfaceUpdate", "1", 0 );
- }
- if (cv && cv->integer) {
- debugPatchCollide = pc;
- debugFacet = facet;
- }
-#endif //BSPC
-
- tw->trace.fraction = enterFrac;
- VectorCopy( bestplane, tw->trace.plane.normal );
- tw->trace.plane.dist = bestplane[3];
- }
- }
- }
-}
-
-
-/*
-=======================================================================
-
-POSITION TEST
-
-=======================================================================
-*/
-
-/*
-====================
-CM_PositionTestInPatchCollide
-====================
-*/
-qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {
- int i, j;
- float offset, t;
- patchPlane_t *planes;
- facet_t *facet;
- float plane[4];
- vec3_t startp;
-
- if (tw->isPoint) {
- return qfalse;
- }
- //
- facet = pc->facets;
- for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {
- planes = &pc->planes[ facet->surfacePlane ];
- VectorCopy(planes->plane, plane);
- plane[3] = planes->plane[3];
- if ( tw->sphere.use ) {
- // adjust the plane distance apropriately for radius
- plane[3] += tw->sphere.radius;
-
- // find the closest point on the capsule to the plane
- t = DotProduct( plane, tw->sphere.offset );
- if ( t > 0 ) {
- VectorSubtract( tw->start, tw->sphere.offset, startp );
- }
- else {
- VectorAdd( tw->start, tw->sphere.offset, startp );
- }
- }
- else {
- offset = DotProduct( tw->offsets[ planes->signbits ], plane);
- plane[3] -= offset;
- VectorCopy( tw->start, startp );
- }
-
- if ( DotProduct( plane, startp ) - plane[3] > 0.0f ) {
- continue;
- }
-
- for ( j = 0; j < facet->numBorders; j++ ) {
- planes = &pc->planes[ facet->borderPlanes[j] ];
- if (facet->borderInward[j]) {
- VectorNegate(planes->plane, plane);
- plane[3] = -planes->plane[3];
- }
- else {
- VectorCopy(planes->plane, plane);
- plane[3] = planes->plane[3];
- }
- if ( tw->sphere.use ) {
- // adjust the plane distance apropriately for radius
- plane[3] += tw->sphere.radius;
-
- // find the closest point on the capsule to the plane
- t = DotProduct( plane, tw->sphere.offset );
- if ( t > 0.0f ) {
- VectorSubtract( tw->start, tw->sphere.offset, startp );
- }
- else {
- VectorAdd( tw->start, tw->sphere.offset, startp );
- }
- }
- else {
- // NOTE: this works even though the plane might be flipped because the bbox is centered
- offset = DotProduct( tw->offsets[ planes->signbits ], plane);
- plane[3] += fabs(offset);
- VectorCopy( tw->start, startp );
- }
-
- if ( DotProduct( plane, startp ) - plane[3] > 0.0f ) {
- break;
- }
- }
- if (j < facet->numBorders) {
- continue;
- }
- // inside this patch facet
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-=======================================================================
-
-DEBUGGING
-
-=======================================================================
-*/
-
-
-/*
-==================
-CM_DrawDebugSurface
-
-Called from the renderer
-==================
-*/
-#ifndef BSPC
-void BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *points), int value);
-#endif
-
-void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, float *points) ) {
- static cvar_t *cv;
-#ifndef BSPC
- static cvar_t *cv2;
-#endif
- const patchCollide_t *pc;
- facet_t *facet;
- winding_t *w;
- int i, j, k, n;
- int curplanenum, planenum, curinward, inward;
- float plane[4];
- vec3_t mins = {-15, -15, -28}, maxs = {15, 15, 28};
- //vec3_t mins = {0, 0, 0}, maxs = {0, 0, 0};
- vec3_t v1, v2;
-
-#ifndef BSPC
- if ( !cv2 )
- {
- cv2 = Cvar_Get( "r_debugSurface", "0", 0 );
- }
-
- if (cv2->integer != 1)
- {
- BotDrawDebugPolygons(drawPoly, cv2->integer);
- return;
- }
-#endif
-
- if ( !debugPatchCollide ) {
- return;
- }
-
-#ifndef BSPC
- if ( !cv ) {
- cv = Cvar_Get( "cm_debugSize", "2", 0 );
- }
-#endif
- pc = debugPatchCollide;
-
- for ( i = 0, facet = pc->facets ; i < pc->numFacets ; i++, facet++ ) {
-
- for ( k = 0 ; k < facet->numBorders + 1; k++ ) {
- //
- if (k < facet->numBorders) {
- planenum = facet->borderPlanes[k];
- inward = facet->borderInward[k];
- }
- else {
- planenum = facet->surfacePlane;
- inward = qfalse;
- //continue;
- }
-
- Vector4Copy( pc->planes[ planenum ].plane, plane );
-
- //planenum = facet->surfacePlane;
- if ( inward ) {
- VectorSubtract( vec3_origin, plane, plane );
- plane[3] = -plane[3];
- }
-
- plane[3] += cv->value;
- //*
- for (n = 0; n < 3; n++)
- {
- if (plane[n] > 0) v1[n] = maxs[n];
- else v1[n] = mins[n];
- } //end for
- VectorNegate(plane, v2);
- plane[3] += fabs(DotProduct(v1, v2));
- //*/
-
- w = BaseWindingForPlane( plane, plane[3] );
- for ( j = 0 ; j < facet->numBorders + 1 && w; j++ ) {
- //
- if (j < facet->numBorders) {
- curplanenum = facet->borderPlanes[j];
- curinward = facet->borderInward[j];
- }
- else {
- curplanenum = facet->surfacePlane;
- curinward = qfalse;
- //continue;
- }
- //
- if (curplanenum == planenum) continue;
-
- Vector4Copy( pc->planes[ curplanenum ].plane, plane );
- if ( !curinward ) {
- VectorSubtract( vec3_origin, plane, plane );
- plane[3] = -plane[3];
- }
- // if ( !facet->borderNoAdjust[j] ) {
- plane[3] -= cv->value;
- // }
- for (n = 0; n < 3; n++)
- {
- if (plane[n] > 0) v1[n] = maxs[n];
- else v1[n] = mins[n];
- } //end for
- VectorNegate(plane, v2);
- plane[3] -= fabs(DotProduct(v1, v2));
-
- ChopWindingInPlace( &w, plane, plane[3], 0.1f );
- }
- if ( w ) {
- if ( facet == debugFacet ) {
- drawPoly( 4, w->numpoints, w->p[0] );
- //Com_Printf("blue facet has %d border planes\n", facet->numBorders);
- } else {
- drawPoly( 1, w->numpoints, w->p[0] );
- }
- FreeWinding( w );
- }
- else
- Com_Printf("winding chopped away by border planes\n");
- }
- }
-
- // draw the debug block
- {
- vec3_t v[3];
-
- VectorCopy( debugBlockPoints[0], v[0] );
- VectorCopy( debugBlockPoints[1], v[1] );
- VectorCopy( debugBlockPoints[2], v[2] );
- drawPoly( 2, 3, v[0] );
-
- VectorCopy( debugBlockPoints[2], v[0] );
- VectorCopy( debugBlockPoints[3], v[1] );
- VectorCopy( debugBlockPoints[0], v[2] );
- drawPoly( 2, 3, v[0] );
- }
-
-#if 0
- vec3_t v[4];
-
- v[0][0] = pc->bounds[1][0];
- v[0][1] = pc->bounds[1][1];
- v[0][2] = pc->bounds[1][2];
-
- v[1][0] = pc->bounds[1][0];
- v[1][1] = pc->bounds[0][1];
- v[1][2] = pc->bounds[1][2];
-
- v[2][0] = pc->bounds[0][0];
- v[2][1] = pc->bounds[0][1];
- v[2][2] = pc->bounds[1][2];
-
- v[3][0] = pc->bounds[0][0];
- v[3][1] = pc->bounds[1][1];
- v[3][2] = pc->bounds[1][2];
-
- drawPoly( 4, v[0] );
-#endif
-}
diff --git a/engine/code/qcommon/cm_patch.h b/engine/code/qcommon/cm_patch.h
deleted file mode 100644
index f5ba8b8..0000000
--- a/engine/code/qcommon/cm_patch.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-//#define CULL_BBOX
-
-/*
-
-This file does not reference any globals, and has these entry points:
-
-void CM_ClearLevelPatches( void );
-struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, const vec3_t *points );
-void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
-qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
-void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, flaot *points) );
-
-
-Issues for collision against curved surfaces:
-
-Surface edges need to be handled differently than surface planes
-
-Plane expansion causes raw surfaces to expand past expanded bounding box
-
-Position test of a volume against a surface is tricky.
-
-Position test of a point against a surface is not well defined, because the surface has no volume.
-
-
-Tracing leading edge points instead of volumes?
-Position test by tracing corner to corner? (8*7 traces -- ouch)
-
-coplanar edges
-triangulated patches
-degenerate patches
-
- endcaps
- degenerate
-
-WARNING: this may misbehave with meshes that have rows or columns that only
-degenerate a few triangles. Completely degenerate rows and columns are handled
-properly.
-*/
-
-
-#define MAX_FACETS 1024
-#define MAX_PATCH_PLANES 2048
-
-typedef struct {
- float plane[4];
- int signbits; // signx + (signy<<1) + (signz<<2), used as lookup during collision
-} patchPlane_t;
-
-typedef struct {
- int surfacePlane;
- int numBorders; // 3 or four + 6 axial bevels + 4 or 3 * 4 edge bevels
- int borderPlanes[4+6+16];
- int borderInward[4+6+16];
- qboolean borderNoAdjust[4+6+16];
-} facet_t;
-
-typedef struct patchCollide_s {
- vec3_t bounds[2];
- int numPlanes; // surface planes plus edge planes
- patchPlane_t *planes;
- int numFacets;
- facet_t *facets;
-} patchCollide_t;
-
-
-#define MAX_GRID_SIZE 129
-
-typedef struct {
- int width;
- int height;
- qboolean wrapWidth;
- qboolean wrapHeight;
- vec3_t points[MAX_GRID_SIZE][MAX_GRID_SIZE]; // [width][height]
-} cGrid_t;
-
-#define SUBDIVIDE_DISTANCE 16 //4 // never more than this units away from curve
-#define PLANE_TRI_EPSILON 0.1
-#define WRAP_POINT_EPSILON 0.1
-
-
-struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, vec3_t *points );
diff --git a/engine/code/qcommon/cm_polylib.c b/engine/code/qcommon/cm_polylib.c
deleted file mode 100644
index f4d6ce8..0000000
--- a/engine/code/qcommon/cm_polylib.c
+++ /dev/null
@@ -1,737 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-// this is only used for visualization tools in cm_ debug functions
-
-
-#include "cm_local.h"
-
-
-// counters are only bumped when running single threaded,
-// because they are an awful coherence problem
-int c_active_windings;
-int c_peak_windings;
-int c_winding_allocs;
-int c_winding_points;
-
-void pw(winding_t *w)
-{
- int i;
- for (i=0 ; i<w->numpoints ; i++)
- printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]);
-}
-
-
-/*
-=============
-AllocWinding
-=============
-*/
-winding_t *AllocWinding (int points)
-{
- winding_t *w;
- int s;
-
- c_winding_allocs++;
- c_winding_points += points;
- c_active_windings++;
- if (c_active_windings > c_peak_windings)
- c_peak_windings = c_active_windings;
-
- s = sizeof(vec_t)*3*points + sizeof(int);
- w = Z_Malloc (s);
- Com_Memset (w, 0, s);
- return w;
-}
-
-void FreeWinding (winding_t *w)
-{
- if (*(unsigned *)w == 0xdeaddead)
- Com_Error (ERR_FATAL, "FreeWinding: freed a freed winding");
- *(unsigned *)w = 0xdeaddead;
-
- c_active_windings--;
- Z_Free (w);
-}
-
-/*
-============
-RemoveColinearPoints
-============
-*/
-int c_removed;
-
-void RemoveColinearPoints (winding_t *w)
-{
- int i, j, k;
- vec3_t v1, v2;
- int nump;
- vec3_t p[MAX_POINTS_ON_WINDING];
-
- nump = 0;
- for (i=0 ; i<w->numpoints ; i++)
- {
- j = (i+1)%w->numpoints;
- k = (i+w->numpoints-1)%w->numpoints;
- VectorSubtract (w->p[j], w->p[i], v1);
- VectorSubtract (w->p[i], w->p[k], v2);
- VectorNormalize2(v1,v1);
- VectorNormalize2(v2,v2);
- if (DotProduct(v1, v2) < 0.999)
- {
- VectorCopy (w->p[i], p[nump]);
- nump++;
- }
- }
-
- if (nump == w->numpoints)
- return;
-
- c_removed += w->numpoints - nump;
- w->numpoints = nump;
- Com_Memcpy (w->p, p, nump*sizeof(p[0]));
-}
-
-/*
-============
-WindingPlane
-============
-*/
-void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist)
-{
- vec3_t v1, v2;
-
- VectorSubtract (w->p[1], w->p[0], v1);
- VectorSubtract (w->p[2], w->p[0], v2);
- CrossProduct (v2, v1, normal);
- VectorNormalize2(normal, normal);
- *dist = DotProduct (w->p[0], normal);
-
-}
-
-/*
-=============
-WindingArea
-=============
-*/
-vec_t WindingArea (winding_t *w)
-{
- int i;
- vec3_t d1, d2, cross;
- vec_t total;
-
- total = 0;
- for (i=2 ; i<w->numpoints ; i++)
- {
- VectorSubtract (w->p[i-1], w->p[0], d1);
- VectorSubtract (w->p[i], w->p[0], d2);
- CrossProduct (d1, d2, cross);
- total += 0.5 * VectorLength ( cross );
- }
- return total;
-}
-
-/*
-=============
-WindingBounds
-=============
-*/
-void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs)
-{
- vec_t v;
- int i,j;
-
- mins[0] = mins[1] = mins[2] = MAX_MAP_BOUNDS;
- maxs[0] = maxs[1] = maxs[2] = -MAX_MAP_BOUNDS;
-
- for (i=0 ; i<w->numpoints ; i++)
- {
- for (j=0 ; j<3 ; j++)
- {
- v = w->p[i][j];
- if (v < mins[j])
- mins[j] = v;
- if (v > maxs[j])
- maxs[j] = v;
- }
- }
-}
-
-/*
-=============
-WindingCenter
-=============
-*/
-void WindingCenter (winding_t *w, vec3_t center)
-{
- int i;
- float scale;
-
- VectorCopy (vec3_origin, center);
- for (i=0 ; i<w->numpoints ; i++)
- VectorAdd (w->p[i], center, center);
-
- scale = 1.0/w->numpoints;
- VectorScale (center, scale, center);
-}
-
-/*
-=================
-BaseWindingForPlane
-=================
-*/
-winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)
-{
- int i, x;
- vec_t max, v;
- vec3_t org, vright, vup;
- winding_t *w;
-
-// find the major axis
-
- max = -MAX_MAP_BOUNDS;
- x = -1;
- for (i=0 ; i<3; i++)
- {
- v = fabs(normal[i]);
- if (v > max)
- {
- x = i;
- max = v;
- }
- }
- if (x==-1)
- Com_Error (ERR_DROP, "BaseWindingForPlane: no axis found");
-
- VectorCopy (vec3_origin, vup);
- switch (x)
- {
- case 0:
- case 1:
- vup[2] = 1;
- break;
- case 2:
- vup[0] = 1;
- break;
- }
-
- v = DotProduct (vup, normal);
- VectorMA (vup, -v, normal, vup);
- VectorNormalize2(vup, vup);
-
- VectorScale (normal, dist, org);
-
- CrossProduct (vup, normal, vright);
-
- VectorScale (vup, MAX_MAP_BOUNDS, vup);
- VectorScale (vright, MAX_MAP_BOUNDS, vright);
-
-// project a really big axis aligned box onto the plane
- w = AllocWinding (4);
-
- VectorSubtract (org, vright, w->p[0]);
- VectorAdd (w->p[0], vup, w->p[0]);
-
- VectorAdd (org, vright, w->p[1]);
- VectorAdd (w->p[1], vup, w->p[1]);
-
- VectorAdd (org, vright, w->p[2]);
- VectorSubtract (w->p[2], vup, w->p[2]);
-
- VectorSubtract (org, vright, w->p[3]);
- VectorSubtract (w->p[3], vup, w->p[3]);
-
- w->numpoints = 4;
-
- return w;
-}
-
-/*
-==================
-CopyWinding
-==================
-*/
-winding_t *CopyWinding (winding_t *w)
-{
- unsigned long size;
- winding_t *c;
-
- c = AllocWinding (w->numpoints);
- size = (long)((winding_t *)0)->p[w->numpoints];
- Com_Memcpy (c, w, size);
- return c;
-}
-
-/*
-==================
-ReverseWinding
-==================
-*/
-winding_t *ReverseWinding (winding_t *w)
-{
- int i;
- winding_t *c;
-
- c = AllocWinding (w->numpoints);
- for (i=0 ; i<w->numpoints ; i++)
- {
- VectorCopy (w->p[w->numpoints-1-i], c->p[i]);
- }
- c->numpoints = w->numpoints;
- return c;
-}
-
-
-/*
-=============
-ClipWindingEpsilon
-=============
-*/
-void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
- vec_t epsilon, winding_t **front, winding_t **back)
-{
- vec_t dists[MAX_POINTS_ON_WINDING+4];
- int sides[MAX_POINTS_ON_WINDING+4];
- int counts[3];
- static vec_t dot; // VC 4.2 optimizer bug if not static
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- winding_t *f, *b;
- int maxpts;
-
- counts[0] = counts[1] = counts[2] = 0;
-
-// determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->p[i], normal);
- dot -= dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- *front = *back = NULL;
-
- if (!counts[0])
- {
- *back = CopyWinding (in);
- return;
- }
- if (!counts[1])
- {
- *front = CopyWinding (in);
- return;
- }
-
- maxpts = in->numpoints+4; // cant use counts[0]+2 because
- // of fp grouping errors
-
- *front = f = AllocWinding (maxpts);
- *back = b = AllocWinding (maxpts);
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->p[i];
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- VectorCopy (p1, b->p[b->numpoints]);
- b->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- }
- if (sides[i] == SIDE_BACK)
- {
- VectorCopy (p1, b->p[b->numpoints]);
- b->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- // generate a split point
- p2 = in->p[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (normal[j] == 1)
- mid[j] = dist;
- else if (normal[j] == -1)
- mid[j] = -dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, f->p[f->numpoints]);
- f->numpoints++;
- VectorCopy (mid, b->p[b->numpoints]);
- b->numpoints++;
- }
-
- if (f->numpoints > maxpts || b->numpoints > maxpts)
- Com_Error (ERR_DROP, "ClipWinding: points exceeded estimate");
- if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
- Com_Error (ERR_DROP, "ClipWinding: MAX_POINTS_ON_WINDING");
-}
-
-
-/*
-=============
-ChopWindingInPlace
-=============
-*/
-void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon)
-{
- winding_t *in;
- vec_t dists[MAX_POINTS_ON_WINDING+4];
- int sides[MAX_POINTS_ON_WINDING+4];
- int counts[3];
- static vec_t dot; // VC 4.2 optimizer bug if not static
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- winding_t *f;
- int maxpts;
-
- in = *inout;
- counts[0] = counts[1] = counts[2] = 0;
-
-// determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->p[i], normal);
- dot -= dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- if (!counts[0])
- {
- FreeWinding (in);
- *inout = NULL;
- return;
- }
- if (!counts[1])
- return; // inout stays the same
-
- maxpts = in->numpoints+4; // cant use counts[0]+2 because
- // of fp grouping errors
-
- f = AllocWinding (maxpts);
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->p[i];
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- // generate a split point
- p2 = in->p[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (normal[j] == 1)
- mid[j] = dist;
- else if (normal[j] == -1)
- mid[j] = -dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, f->p[f->numpoints]);
- f->numpoints++;
- }
-
- if (f->numpoints > maxpts)
- Com_Error (ERR_DROP, "ClipWinding: points exceeded estimate");
- if (f->numpoints > MAX_POINTS_ON_WINDING)
- Com_Error (ERR_DROP, "ClipWinding: MAX_POINTS_ON_WINDING");
-
- FreeWinding (in);
- *inout = f;
-}
-
-
-/*
-=================
-ChopWinding
-
-Returns the fragment of in that is on the front side
-of the cliping plane. The original is freed.
-=================
-*/
-winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
-{
- winding_t *f, *b;
-
- ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
- FreeWinding (in);
- if (b)
- FreeWinding (b);
- return f;
-}
-
-
-/*
-=================
-CheckWinding
-
-=================
-*/
-void CheckWinding (winding_t *w)
-{
- int i, j;
- vec_t *p1, *p2;
- vec_t d, edgedist;
- vec3_t dir, edgenormal, facenormal;
- vec_t area;
- vec_t facedist;
-
- if (w->numpoints < 3)
- Com_Error (ERR_DROP, "CheckWinding: %i points",w->numpoints);
-
- area = WindingArea(w);
- if (area < 1)
- Com_Error (ERR_DROP, "CheckWinding: %f area", area);
-
- WindingPlane (w, facenormal, &facedist);
-
- for (i=0 ; i<w->numpoints ; i++)
- {
- p1 = w->p[i];
-
- for (j=0 ; j<3 ; j++)
- if (p1[j] > MAX_MAP_BOUNDS || p1[j] < -MAX_MAP_BOUNDS)
- Com_Error (ERR_DROP, "CheckFace: BUGUS_RANGE: %f",p1[j]);
-
- j = i+1 == w->numpoints ? 0 : i+1;
-
- // check the point is on the face plane
- d = DotProduct (p1, facenormal) - facedist;
- if (d < -ON_EPSILON || d > ON_EPSILON)
- Com_Error (ERR_DROP, "CheckWinding: point off plane");
-
- // check the edge isnt degenerate
- p2 = w->p[j];
- VectorSubtract (p2, p1, dir);
-
- if (VectorLength (dir) < ON_EPSILON)
- Com_Error (ERR_DROP, "CheckWinding: degenerate edge");
-
- CrossProduct (facenormal, dir, edgenormal);
- VectorNormalize2 (edgenormal, edgenormal);
- edgedist = DotProduct (p1, edgenormal);
- edgedist += ON_EPSILON;
-
- // all other points must be on front side
- for (j=0 ; j<w->numpoints ; j++)
- {
- if (j == i)
- continue;
- d = DotProduct (w->p[j], edgenormal);
- if (d > edgedist)
- Com_Error (ERR_DROP, "CheckWinding: non-convex");
- }
- }
-}
-
-
-/*
-============
-WindingOnPlaneSide
-============
-*/
-int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist)
-{
- qboolean front, back;
- int i;
- vec_t d;
-
- front = qfalse;
- back = qfalse;
- for (i=0 ; i<w->numpoints ; i++)
- {
- d = DotProduct (w->p[i], normal) - dist;
- if (d < -ON_EPSILON)
- {
- if (front)
- return SIDE_CROSS;
- back = qtrue;
- continue;
- }
- if (d > ON_EPSILON)
- {
- if (back)
- return SIDE_CROSS;
- front = qtrue;
- continue;
- }
- }
-
- if (back)
- return SIDE_BACK;
- if (front)
- return SIDE_FRONT;
- return SIDE_ON;
-}
-
-
-/*
-=================
-AddWindingToConvexHull
-
-Both w and *hull are on the same plane
-=================
-*/
-#define MAX_HULL_POINTS 128
-void AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal ) {
- int i, j, k;
- float *p, *copy;
- vec3_t dir;
- float d;
- int numHullPoints, numNew;
- vec3_t hullPoints[MAX_HULL_POINTS];
- vec3_t newHullPoints[MAX_HULL_POINTS];
- vec3_t hullDirs[MAX_HULL_POINTS];
- qboolean hullSide[MAX_HULL_POINTS];
- qboolean outside;
-
- if ( !*hull ) {
- *hull = CopyWinding( w );
- return;
- }
-
- numHullPoints = (*hull)->numpoints;
- Com_Memcpy( hullPoints, (*hull)->p, numHullPoints * sizeof(vec3_t) );
-
- for ( i = 0 ; i < w->numpoints ; i++ ) {
- p = w->p[i];
-
- // calculate hull side vectors
- for ( j = 0 ; j < numHullPoints ; j++ ) {
- k = ( j + 1 ) % numHullPoints;
-
- VectorSubtract( hullPoints[k], hullPoints[j], dir );
- VectorNormalize2( dir, dir );
- CrossProduct( normal, dir, hullDirs[j] );
- }
-
- outside = qfalse;
- for ( j = 0 ; j < numHullPoints ; j++ ) {
- VectorSubtract( p, hullPoints[j], dir );
- d = DotProduct( dir, hullDirs[j] );
- if ( d >= ON_EPSILON ) {
- outside = qtrue;
- }
- if ( d >= -ON_EPSILON ) {
- hullSide[j] = qtrue;
- } else {
- hullSide[j] = qfalse;
- }
- }
-
- // if the point is effectively inside, do nothing
- if ( !outside ) {
- continue;
- }
-
- // find the back side to front side transition
- for ( j = 0 ; j < numHullPoints ; j++ ) {
- if ( !hullSide[ j % numHullPoints ] && hullSide[ (j + 1) % numHullPoints ] ) {
- break;
- }
- }
- if ( j == numHullPoints ) {
- continue;
- }
-
- // insert the point here
- VectorCopy( p, newHullPoints[0] );
- numNew = 1;
-
- // copy over all points that aren't double fronts
- j = (j+1)%numHullPoints;
- for ( k = 0 ; k < numHullPoints ; k++ ) {
- if ( hullSide[ (j+k) % numHullPoints ] && hullSide[ (j+k+1) % numHullPoints ] ) {
- continue;
- }
- copy = hullPoints[ (j+k+1) % numHullPoints ];
- VectorCopy( copy, newHullPoints[numNew] );
- numNew++;
- }
-
- numHullPoints = numNew;
- Com_Memcpy( hullPoints, newHullPoints, numHullPoints * sizeof(vec3_t) );
- }
-
- FreeWinding( *hull );
- w = AllocWinding( numHullPoints );
- w->numpoints = numHullPoints;
- *hull = w;
- Com_Memcpy( w->p, hullPoints, numHullPoints * sizeof(vec3_t) );
-}
-
-
diff --git a/engine/code/qcommon/cm_polylib.h b/engine/code/qcommon/cm_polylib.h
deleted file mode 100644
index 66d58d9..0000000
--- a/engine/code/qcommon/cm_polylib.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-// this is only used for visualization tools in cm_ debug functions
-
-typedef struct
-{
- int numpoints;
- vec3_t p[4]; // variable sized
-} winding_t;
-
-#define MAX_POINTS_ON_WINDING 64
-
-#define SIDE_FRONT 0
-#define SIDE_BACK 1
-#define SIDE_ON 2
-#define SIDE_CROSS 3
-
-#define CLIP_EPSILON 0.1f
-
-#define MAX_MAP_BOUNDS 65535
-
-// you can define on_epsilon in the makefile as tighter
-#ifndef ON_EPSILON
-#define ON_EPSILON 0.1f
-#endif
-
-winding_t *AllocWinding (int points);
-vec_t WindingArea (winding_t *w);
-void WindingCenter (winding_t *w, vec3_t center);
-void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
- vec_t epsilon, winding_t **front, winding_t **back);
-winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist);
-winding_t *CopyWinding (winding_t *w);
-winding_t *ReverseWinding (winding_t *w);
-winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist);
-void CheckWinding (winding_t *w);
-void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist);
-void RemoveColinearPoints (winding_t *w);
-int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist);
-void FreeWinding (winding_t *w);
-void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs);
-
-void AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal );
-
-void ChopWindingInPlace (winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon);
-// frees the original if clipped
-
-void pw(winding_t *w);
diff --git a/engine/code/qcommon/cm_public.h b/engine/code/qcommon/cm_public.h
deleted file mode 100644
index f59fb29..0000000
--- a/engine/code/qcommon/cm_public.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "qfiles.h"
-
-
-void CM_LoadMap( const char *name, qboolean clientload, int *checksum);
-void CM_ClearMap( void );
-clipHandle_t CM_InlineModel( int index ); // 0 = world, 1 + are bmodels
-clipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs, int capsule );
-
-void CM_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );
-
-int CM_NumClusters (void);
-int CM_NumInlineModels( void );
-char *CM_EntityString (void);
-
-// returns an ORed contents mask
-int CM_PointContents( const vec3_t p, clipHandle_t model );
-int CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles );
-
-void CM_BoxTrace ( trace_t *results, const vec3_t start, const vec3_t end,
- vec3_t mins, vec3_t maxs,
- clipHandle_t model, int brushmask, int capsule );
-void CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- vec3_t mins, vec3_t maxs,
- clipHandle_t model, int brushmask,
- const vec3_t origin, const vec3_t angles, int capsule );
-
-byte *CM_ClusterPVS (int cluster);
-
-int CM_PointLeafnum( const vec3_t p );
-
-// only returns non-solid leafs
-// overflow if return listsize and if *lastLeaf != list[listsize-1]
-int CM_BoxLeafnums( const vec3_t mins, const vec3_t maxs, int *list,
- int listsize, int *lastLeaf );
-
-int CM_LeafCluster (int leafnum);
-int CM_LeafArea (int leafnum);
-
-void CM_AdjustAreaPortalState( int area1, int area2, qboolean open );
-qboolean CM_AreasConnected( int area1, int area2 );
-
-int CM_WriteAreaBits( byte *buffer, int area );
-
-// cm_tag.c
-int CM_LerpTag( orientation_t *tag, clipHandle_t model, int startFrame, int endFrame,
- float frac, const char *tagName );
-
-
-// cm_marks.c
-int CM_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
- int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );
-
-// cm_patch.c
-void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, float *points) );
diff --git a/engine/code/qcommon/cm_test.c b/engine/code/qcommon/cm_test.c
deleted file mode 100644
index 9fd1ec5..0000000
--- a/engine/code/qcommon/cm_test.c
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "cm_local.h"
-
-
-/*
-==================
-CM_PointLeafnum_r
-
-==================
-*/
-int CM_PointLeafnum_r( const vec3_t p, int num ) {
- float d;
- cNode_t *node;
- cplane_t *plane;
-
- while (num >= 0)
- {
- node = cm.nodes + num;
- plane = node->plane;
-
- if (plane->type < 3)
- d = p[plane->type] - plane->dist;
- else
- d = DotProduct (plane->normal, p) - plane->dist;
- if (d < 0)
- num = node->children[1];
- else
- num = node->children[0];
- }
-
- c_pointcontents++; // optimize counter
-
- return -1 - num;
-}
-
-int CM_PointLeafnum( const vec3_t p ) {
- if ( !cm.numNodes ) { // map not loaded
- return 0;
- }
- return CM_PointLeafnum_r (p, 0);
-}
-
-
-/*
-======================================================================
-
-LEAF LISTING
-
-======================================================================
-*/
-
-
-void CM_StoreLeafs( leafList_t *ll, int nodenum ) {
- int leafNum;
-
- leafNum = -1 - nodenum;
-
- // store the lastLeaf even if the list is overflowed
- if ( cm.leafs[ leafNum ].cluster != -1 ) {
- ll->lastLeaf = leafNum;
- }
-
- if ( ll->count >= ll->maxcount) {
- ll->overflowed = qtrue;
- return;
- }
- ll->list[ ll->count++ ] = leafNum;
-}
-
-void CM_StoreBrushes( leafList_t *ll, int nodenum ) {
- int i, k;
- int leafnum;
- int brushnum;
- cLeaf_t *leaf;
- cbrush_t *b;
-
- leafnum = -1 - nodenum;
-
- leaf = &cm.leafs[leafnum];
-
- for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {
- brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];
- b = &cm.brushes[brushnum];
- if ( b->checkcount == cm.checkcount ) {
- continue; // already checked this brush in another leaf
- }
- b->checkcount = cm.checkcount;
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( b->bounds[0][i] >= ll->bounds[1][i] || b->bounds[1][i] <= ll->bounds[0][i] ) {
- break;
- }
- }
- if ( i != 3 ) {
- continue;
- }
- if ( ll->count >= ll->maxcount) {
- ll->overflowed = qtrue;
- return;
- }
- ((cbrush_t **)ll->list)[ ll->count++ ] = b;
- }
-#if 0
- // store patches?
- for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
- patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstleafsurface + k ] ];
- if ( !patch ) {
- continue;
- }
- }
-#endif
-}
-
-/*
-=============
-CM_BoxLeafnums
-
-Fills in a list of all the leafs touched
-=============
-*/
-void CM_BoxLeafnums_r( leafList_t *ll, int nodenum ) {
- cplane_t *plane;
- cNode_t *node;
- int s;
-
- while (1) {
- if (nodenum < 0) {
- ll->storeLeafs( ll, nodenum );
- return;
- }
-
- node = &cm.nodes[nodenum];
- plane = node->plane;
- s = BoxOnPlaneSide( ll->bounds[0], ll->bounds[1], plane );
- if (s == 1) {
- nodenum = node->children[0];
- } else if (s == 2) {
- nodenum = node->children[1];
- } else {
- // go down both
- CM_BoxLeafnums_r( ll, node->children[0] );
- nodenum = node->children[1];
- }
-
- }
-}
-
-/*
-==================
-CM_BoxLeafnums
-==================
-*/
-int CM_BoxLeafnums( const vec3_t mins, const vec3_t maxs, int *list, int listsize, int *lastLeaf) {
- leafList_t ll;
-
- cm.checkcount++;
-
- VectorCopy( mins, ll.bounds[0] );
- VectorCopy( maxs, ll.bounds[1] );
- ll.count = 0;
- ll.maxcount = listsize;
- ll.list = list;
- ll.storeLeafs = CM_StoreLeafs;
- ll.lastLeaf = 0;
- ll.overflowed = qfalse;
-
- CM_BoxLeafnums_r( &ll, 0 );
-
- *lastLeaf = ll.lastLeaf;
- return ll.count;
-}
-
-/*
-==================
-CM_BoxBrushes
-==================
-*/
-int CM_BoxBrushes( const vec3_t mins, const vec3_t maxs, cbrush_t **list, int listsize ) {
- leafList_t ll;
-
- cm.checkcount++;
-
- VectorCopy( mins, ll.bounds[0] );
- VectorCopy( maxs, ll.bounds[1] );
- ll.count = 0;
- ll.maxcount = listsize;
- ll.list = (void *)list;
- ll.storeLeafs = CM_StoreBrushes;
- ll.lastLeaf = 0;
- ll.overflowed = qfalse;
-
- CM_BoxLeafnums_r( &ll, 0 );
-
- return ll.count;
-}
-
-
-//====================================================================
-
-
-/*
-==================
-CM_PointContents
-
-==================
-*/
-int CM_PointContents( const vec3_t p, clipHandle_t model ) {
- int leafnum;
- int i, k;
- int brushnum;
- cLeaf_t *leaf;
- cbrush_t *b;
- int contents;
- float d;
- cmodel_t *clipm;
-
- if (!cm.numNodes) { // map not loaded
- return 0;
- }
-
- if ( model ) {
- clipm = CM_ClipHandleToModel( model );
- leaf = &clipm->leaf;
- } else {
- leafnum = CM_PointLeafnum_r (p, 0);
- leaf = &cm.leafs[leafnum];
- }
-
- contents = 0;
- for (k=0 ; k<leaf->numLeafBrushes ; k++) {
- brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];
- b = &cm.brushes[brushnum];
-
- if ( !CM_BoundsIntersectPoint( b->bounds[0], b->bounds[1], p ) ) {
- continue;
- }
-
- // see if the point is in the brush
- for ( i = 0 ; i < b->numsides ; i++ ) {
- d = DotProduct( p, b->sides[i].plane->normal );
-// FIXME test for Cash
-// if ( d >= b->sides[i].plane->dist ) {
- if ( d > b->sides[i].plane->dist ) {
- break;
- }
- }
-
- if ( i == b->numsides ) {
- contents |= b->contents;
- }
- }
-
- return contents;
-}
-
-/*
-==================
-CM_TransformedPointContents
-
-Handles offseting and rotation of the end points for moving and
-rotating entities
-==================
-*/
-int CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles) {
- vec3_t p_l;
- vec3_t temp;
- vec3_t forward, right, up;
-
- // subtract origin offset
- VectorSubtract (p, origin, p_l);
-
- // rotate start and end into the models frame of reference
- if ( model != BOX_MODEL_HANDLE &&
- (angles[0] || angles[1] || angles[2]) )
- {
- AngleVectors (angles, forward, right, up);
-
- VectorCopy (p_l, temp);
- p_l[0] = DotProduct (temp, forward);
- p_l[1] = -DotProduct (temp, right);
- p_l[2] = DotProduct (temp, up);
- }
-
- return CM_PointContents( p_l, model );
-}
-
-
-
-/*
-===============================================================================
-
-PVS
-
-===============================================================================
-*/
-
-byte *CM_ClusterPVS (int cluster) {
- if (cluster < 0 || cluster >= cm.numClusters || !cm.vised ) {
- return cm.visibility;
- }
-
- return cm.visibility + cluster * cm.clusterBytes;
-}
-
-
-
-/*
-===============================================================================
-
-AREAPORTALS
-
-===============================================================================
-*/
-
-void CM_FloodArea_r( int areaNum, int floodnum) {
- int i;
- cArea_t *area;
- int *con;
-
- area = &cm.areas[ areaNum ];
-
- if ( area->floodvalid == cm.floodvalid ) {
- if (area->floodnum == floodnum)
- return;
- Com_Error (ERR_DROP, "FloodArea_r: reflooded");
- }
-
- area->floodnum = floodnum;
- area->floodvalid = cm.floodvalid;
- con = cm.areaPortals + areaNum * cm.numAreas;
- for ( i=0 ; i < cm.numAreas ; i++ ) {
- if ( con[i] > 0 ) {
- CM_FloodArea_r( i, floodnum );
- }
- }
-}
-
-/*
-====================
-CM_FloodAreaConnections
-
-====================
-*/
-void CM_FloodAreaConnections( void ) {
- int i;
- cArea_t *area;
- int floodnum;
-
- // all current floods are now invalid
- cm.floodvalid++;
- floodnum = 0;
-
- for (i = 0 ; i < cm.numAreas ; i++) {
- area = &cm.areas[i];
- if (area->floodvalid == cm.floodvalid) {
- continue; // already flooded into
- }
- floodnum++;
- CM_FloodArea_r (i, floodnum);
- }
-
-}
-
-/*
-====================
-CM_AdjustAreaPortalState
-
-====================
-*/
-void CM_AdjustAreaPortalState( int area1, int area2, qboolean open ) {
- if ( area1 < 0 || area2 < 0 ) {
- return;
- }
-
- if ( area1 >= cm.numAreas || area2 >= cm.numAreas ) {
- Com_Error (ERR_DROP, "CM_ChangeAreaPortalState: bad area number");
- }
-
- if ( open ) {
- cm.areaPortals[ area1 * cm.numAreas + area2 ]++;
- cm.areaPortals[ area2 * cm.numAreas + area1 ]++;
- } else {
- cm.areaPortals[ area1 * cm.numAreas + area2 ]--;
- cm.areaPortals[ area2 * cm.numAreas + area1 ]--;
- if ( cm.areaPortals[ area2 * cm.numAreas + area1 ] < 0 ) {
- Com_Error (ERR_DROP, "CM_AdjustAreaPortalState: negative reference count");
- }
- }
-
- CM_FloodAreaConnections ();
-}
-
-/*
-====================
-CM_AreasConnected
-
-====================
-*/
-qboolean CM_AreasConnected( int area1, int area2 ) {
-#ifndef BSPC
- if ( cm_noAreas->integer ) {
- return qtrue;
- }
-#endif
-
- if ( area1 < 0 || area2 < 0 ) {
- return qfalse;
- }
-
- if (area1 >= cm.numAreas || area2 >= cm.numAreas) {
- Com_Error (ERR_DROP, "area >= cm.numAreas");
- }
-
- if (cm.areas[area1].floodnum == cm.areas[area2].floodnum) {
- return qtrue;
- }
- return qfalse;
-}
-
-
-/*
-=================
-CM_WriteAreaBits
-
-Writes a bit vector of all the areas
-that are in the same flood as the area parameter
-Returns the number of bytes needed to hold all the bits.
-
-The bits are OR'd in, so you can CM_WriteAreaBits from multiple
-viewpoints and get the union of all visible areas.
-
-This is used to cull non-visible entities from snapshots
-=================
-*/
-int CM_WriteAreaBits (byte *buffer, int area)
-{
- int i;
- int floodnum;
- int bytes;
-
- bytes = (cm.numAreas+7)>>3;
-
-#ifndef BSPC
- if (cm_noAreas->integer || area == -1)
-#else
- if ( area == -1)
-#endif
- { // for debugging, send everything
- Com_Memset (buffer, 255, bytes);
- }
- else
- {
- floodnum = cm.areas[area].floodnum;
- for (i=0 ; i<cm.numAreas ; i++)
- {
- if (cm.areas[i].floodnum == floodnum || area == -1)
- buffer[i>>3] |= 1<<(i&7);
- }
- }
-
- return bytes;
-}
-
-/*
-====================
-CM_BoundsIntersect
-====================
-*/
-qboolean CM_BoundsIntersect( const vec3_t mins, const vec3_t maxs, const vec3_t mins2, const vec3_t maxs2 )
-{
- if (maxs[0] < mins2[0] - SURFACE_CLIP_EPSILON ||
- maxs[1] < mins2[1] - SURFACE_CLIP_EPSILON ||
- maxs[2] < mins2[2] - SURFACE_CLIP_EPSILON ||
- mins[0] > maxs2[0] + SURFACE_CLIP_EPSILON ||
- mins[1] > maxs2[1] + SURFACE_CLIP_EPSILON ||
- mins[2] > maxs2[2] + SURFACE_CLIP_EPSILON)
- {
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-====================
-CM_BoundsIntersectPoint
-====================
-*/
-qboolean CM_BoundsIntersectPoint( const vec3_t mins, const vec3_t maxs, const vec3_t point )
-{
- if (maxs[0] < point[0] - SURFACE_CLIP_EPSILON ||
- maxs[1] < point[1] - SURFACE_CLIP_EPSILON ||
- maxs[2] < point[2] - SURFACE_CLIP_EPSILON ||
- mins[0] > point[0] + SURFACE_CLIP_EPSILON ||
- mins[1] > point[1] + SURFACE_CLIP_EPSILON ||
- mins[2] > point[2] + SURFACE_CLIP_EPSILON)
- {
- return qfalse;
- }
-
- return qtrue;
-}
diff --git a/engine/code/qcommon/cm_trace.c b/engine/code/qcommon/cm_trace.c
deleted file mode 100644
index e9bffe9..0000000
--- a/engine/code/qcommon/cm_trace.c
+++ /dev/null
@@ -1,1464 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "cm_local.h"
-
-// always use bbox vs. bbox collision and never capsule vs. bbox or vice versa
-//#define ALWAYS_BBOX_VS_BBOX
-// always use capsule vs. capsule collision and never capsule vs. bbox or vice versa
-//#define ALWAYS_CAPSULE_VS_CAPSULE
-
-//#define CAPSULE_DEBUG
-
-/*
-===============================================================================
-
-BASIC MATH
-
-===============================================================================
-*/
-
-/*
-================
-RotatePoint
-================
-*/
-void RotatePoint(vec3_t point, /*const*/ vec3_t matrix[3]) { // FIXME
- vec3_t tvec;
-
- VectorCopy(point, tvec);
- point[0] = DotProduct(matrix[0], tvec);
- point[1] = DotProduct(matrix[1], tvec);
- point[2] = DotProduct(matrix[2], tvec);
-}
-
-/*
-================
-TransposeMatrix
-================
-*/
-void TransposeMatrix(/*const*/ vec3_t matrix[3], vec3_t transpose[3]) { // FIXME
- int i, j;
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 3; j++) {
- transpose[i][j] = matrix[j][i];
- }
- }
-}
-
-/*
-================
-CreateRotationMatrix
-================
-*/
-void CreateRotationMatrix(const vec3_t angles, vec3_t matrix[3]) {
- AngleVectors(angles, matrix[0], matrix[1], matrix[2]);
- VectorInverse(matrix[1]);
-}
-
-/*
-================
-CM_ProjectPointOntoVector
-================
-*/
-void CM_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vDir, vec3_t vProj )
-{
- vec3_t pVec;
-
- VectorSubtract( point, vStart, pVec );
- // project onto the directional vector for this segment
- VectorMA( vStart, DotProduct( pVec, vDir ), vDir, vProj );
-}
-
-/*
-================
-CM_DistanceFromLineSquared
-================
-*/
-float CM_DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2, vec3_t dir) {
- vec3_t proj, t;
- int j;
-
- CM_ProjectPointOntoVector(p, lp1, dir, proj);
- for (j = 0; j < 3; j++)
- if ((proj[j] > lp1[j] && proj[j] > lp2[j]) ||
- (proj[j] < lp1[j] && proj[j] < lp2[j]))
- break;
- if (j < 3) {
- if (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j]))
- VectorSubtract(p, lp1, t);
- else
- VectorSubtract(p, lp2, t);
- return VectorLengthSquared(t);
- }
- VectorSubtract(p, proj, t);
- return VectorLengthSquared(t);
-}
-
-/*
-================
-CM_VectorDistanceSquared
-================
-*/
-float CM_VectorDistanceSquared(vec3_t p1, vec3_t p2) {
- vec3_t dir;
-
- VectorSubtract(p2, p1, dir);
- return VectorLengthSquared(dir);
-}
-
-/*
-================
-SquareRootFloat
-================
-*/
-float SquareRootFloat(float number) {
- floatint_t t;
- float x, y;
- const float f = 1.5F;
-
- x = number * 0.5F;
- t.f = number;
- t.i = 0x5f3759df - ( t.i >> 1 );
- y = t.f;
- y = y * ( f - ( x * y * y ) );
- y = y * ( f - ( x * y * y ) );
- return number * y;
-}
-
-
-/*
-===============================================================================
-
-POSITION TESTING
-
-===============================================================================
-*/
-
-/*
-================
-CM_TestBoxInBrush
-================
-*/
-void CM_TestBoxInBrush( traceWork_t *tw, cbrush_t *brush ) {
- int i;
- cplane_t *plane;
- float dist;
- float d1;
- cbrushside_t *side;
- float t;
- vec3_t startp;
-
- if (!brush->numsides) {
- return;
- }
-
- // special test for axial
- if ( tw->bounds[0][0] > brush->bounds[1][0]
- || tw->bounds[0][1] > brush->bounds[1][1]
- || tw->bounds[0][2] > brush->bounds[1][2]
- || tw->bounds[1][0] < brush->bounds[0][0]
- || tw->bounds[1][1] < brush->bounds[0][1]
- || tw->bounds[1][2] < brush->bounds[0][2]
- ) {
- return;
- }
-
- if ( tw->sphere.use ) {
- // the first six planes are the axial planes, so we only
- // need to test the remainder
- for ( i = 6 ; i < brush->numsides ; i++ ) {
- side = brush->sides + i;
- plane = side->plane;
-
- // adjust the plane distance apropriately for radius
- dist = plane->dist + tw->sphere.radius;
- // find the closest point on the capsule to the plane
- t = DotProduct( plane->normal, tw->sphere.offset );
- if ( t > 0 )
- {
- VectorSubtract( tw->start, tw->sphere.offset, startp );
- }
- else
- {
- VectorAdd( tw->start, tw->sphere.offset, startp );
- }
- d1 = DotProduct( startp, plane->normal ) - dist;
- // if completely in front of face, no intersection
- if ( d1 > 0 ) {
- return;
- }
- }
- } else {
- // the first six planes are the axial planes, so we only
- // need to test the remainder
- for ( i = 6 ; i < brush->numsides ; i++ ) {
- side = brush->sides + i;
- plane = side->plane;
-
- // adjust the plane distance apropriately for mins/maxs
- dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal );
-
- d1 = DotProduct( tw->start, plane->normal ) - dist;
-
- // if completely in front of face, no intersection
- if ( d1 > 0 ) {
- return;
- }
- }
- }
-
- // inside this brush
- tw->trace.startsolid = tw->trace.allsolid = qtrue;
- tw->trace.fraction = 0;
- tw->trace.contents = brush->contents;
-}
-
-
-
-/*
-================
-CM_TestInLeaf
-================
-*/
-void CM_TestInLeaf( traceWork_t *tw, cLeaf_t *leaf ) {
- int k;
- int brushnum;
- cbrush_t *b;
- cPatch_t *patch;
-
- // test box position against all brushes in the leaf
- for (k=0 ; k<leaf->numLeafBrushes ; k++) {
- brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];
- b = &cm.brushes[brushnum];
- if (b->checkcount == cm.checkcount) {
- continue; // already checked this brush in another leaf
- }
- b->checkcount = cm.checkcount;
-
- if ( !(b->contents & tw->contents)) {
- continue;
- }
-
- CM_TestBoxInBrush( tw, b );
- if ( tw->trace.allsolid ) {
- return;
- }
- }
-
- // test against all patches
-#ifdef BSPC
- if (1) {
-#else
- if ( !cm_noCurves->integer ) {
-#endif //BSPC
- for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
- patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ];
- if ( !patch ) {
- continue;
- }
- if ( patch->checkcount == cm.checkcount ) {
- continue; // already checked this brush in another leaf
- }
- patch->checkcount = cm.checkcount;
-
- if ( !(patch->contents & tw->contents)) {
- continue;
- }
-
- if ( CM_PositionTestInPatchCollide( tw, patch->pc ) ) {
- tw->trace.startsolid = tw->trace.allsolid = qtrue;
- tw->trace.fraction = 0;
- tw->trace.contents = patch->contents;
- return;
- }
- }
- }
-}
-
-/*
-==================
-CM_TestCapsuleInCapsule
-
-capsule inside capsule check
-==================
-*/
-void CM_TestCapsuleInCapsule( traceWork_t *tw, clipHandle_t model ) {
- int i;
- vec3_t mins, maxs;
- vec3_t top, bottom;
- vec3_t p1, p2, tmp;
- vec3_t offset, symetricSize[2];
- float radius, halfwidth, halfheight, offs, r;
-
- CM_ModelBounds(model, mins, maxs);
-
- VectorAdd(tw->start, tw->sphere.offset, top);
- VectorSubtract(tw->start, tw->sphere.offset, bottom);
- for ( i = 0 ; i < 3 ; i++ ) {
- offset[i] = ( mins[i] + maxs[i] ) * 0.5;
- symetricSize[0][i] = mins[i] - offset[i];
- symetricSize[1][i] = maxs[i] - offset[i];
- }
- halfwidth = symetricSize[ 1 ][ 0 ];
- halfheight = symetricSize[ 1 ][ 2 ];
- radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
- offs = halfheight - radius;
-
- r = Square(tw->sphere.radius + radius);
- // check if any of the spheres overlap
- VectorCopy(offset, p1);
- p1[2] += offs;
- VectorSubtract(p1, top, tmp);
- if ( VectorLengthSquared(tmp) < r ) {
- tw->trace.startsolid = tw->trace.allsolid = qtrue;
- tw->trace.fraction = 0;
- }
- VectorSubtract(p1, bottom, tmp);
- if ( VectorLengthSquared(tmp) < r ) {
- tw->trace.startsolid = tw->trace.allsolid = qtrue;
- tw->trace.fraction = 0;
- }
- VectorCopy(offset, p2);
- p2[2] -= offs;
- VectorSubtract(p2, top, tmp);
- if ( VectorLengthSquared(tmp) < r ) {
- tw->trace.startsolid = tw->trace.allsolid = qtrue;
- tw->trace.fraction = 0;
- }
- VectorSubtract(p2, bottom, tmp);
- if ( VectorLengthSquared(tmp) < r ) {
- tw->trace.startsolid = tw->trace.allsolid = qtrue;
- tw->trace.fraction = 0;
- }
- // if between cylinder up and lower bounds
- if ( (top[2] >= p1[2] && top[2] <= p2[2]) ||
- (bottom[2] >= p1[2] && bottom[2] <= p2[2]) ) {
- // 2d coordinates
- top[2] = p1[2] = 0;
- // if the cylinders overlap
- VectorSubtract(top, p1, tmp);
- if ( VectorLengthSquared(tmp) < r ) {
- tw->trace.startsolid = tw->trace.allsolid = qtrue;
- tw->trace.fraction = 0;
- }
- }
-}
-
-/*
-==================
-CM_TestBoundingBoxInCapsule
-
-bounding box inside capsule check
-==================
-*/
-void CM_TestBoundingBoxInCapsule( traceWork_t *tw, clipHandle_t model ) {
- vec3_t mins, maxs, offset, size[2];
- clipHandle_t h;
- cmodel_t *cmod;
- int i;
-
- // mins maxs of the capsule
- CM_ModelBounds(model, mins, maxs);
-
- // offset for capsule center
- for ( i = 0 ; i < 3 ; i++ ) {
- offset[i] = ( mins[i] + maxs[i] ) * 0.5;
- size[0][i] = mins[i] - offset[i];
- size[1][i] = maxs[i] - offset[i];
- tw->start[i] -= offset[i];
- tw->end[i] -= offset[i];
- }
-
- // replace the bounding box with the capsule
- tw->sphere.use = qtrue;
- tw->sphere.radius = ( size[1][0] > size[1][2] ) ? size[1][2]: size[1][0];
- tw->sphere.halfheight = size[1][2];
- VectorSet( tw->sphere.offset, 0, 0, size[1][2] - tw->sphere.radius );
-
- // replace the capsule with the bounding box
- h = CM_TempBoxModel(tw->size[0], tw->size[1], qfalse);
- // calculate collision
- cmod = CM_ClipHandleToModel( h );
- CM_TestInLeaf( tw, &cmod->leaf );
-}
-
-/*
-==================
-CM_PositionTest
-==================
-*/
-#define MAX_POSITION_LEAFS 1024
-void CM_PositionTest( traceWork_t *tw ) {
- int leafs[MAX_POSITION_LEAFS];
- int i;
- leafList_t ll;
-
- // identify the leafs we are touching
- VectorAdd( tw->start, tw->size[0], ll.bounds[0] );
- VectorAdd( tw->start, tw->size[1], ll.bounds[1] );
-
- for (i=0 ; i<3 ; i++) {
- ll.bounds[0][i] -= 1;
- ll.bounds[1][i] += 1;
- }
-
- ll.count = 0;
- ll.maxcount = MAX_POSITION_LEAFS;
- ll.list = leafs;
- ll.storeLeafs = CM_StoreLeafs;
- ll.lastLeaf = 0;
- ll.overflowed = qfalse;
-
- cm.checkcount++;
-
- CM_BoxLeafnums_r( &ll, 0 );
-
-
- cm.checkcount++;
-
- // test the contents of the leafs
- for (i=0 ; i < ll.count ; i++) {
- CM_TestInLeaf( tw, &cm.leafs[leafs[i]] );
- if ( tw->trace.allsolid ) {
- break;
- }
- }
-}
-
-/*
-===============================================================================
-
-TRACING
-
-===============================================================================
-*/
-
-
-/*
-================
-CM_TraceThroughPatch
-================
-*/
-
-void CM_TraceThroughPatch( traceWork_t *tw, cPatch_t *patch ) {
- float oldFrac;
-
- c_patch_traces++;
-
- oldFrac = tw->trace.fraction;
-
- CM_TraceThroughPatchCollide( tw, patch->pc );
-
- if ( tw->trace.fraction < oldFrac ) {
- tw->trace.surfaceFlags = patch->surfaceFlags;
- tw->trace.contents = patch->contents;
- }
-}
-
-/*
-================
-CM_TraceThroughBrush
-================
-*/
-void CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) {
- int i;
- cplane_t *plane, *clipplane;
- float dist;
- float enterFrac, leaveFrac;
- float d1, d2;
- qboolean getout, startout;
- float f;
- cbrushside_t *side, *leadside;
- float t;
- vec3_t startp;
- vec3_t endp;
-
- enterFrac = -1.0;
- leaveFrac = 1.0;
- clipplane = NULL;
-
- if ( !brush->numsides ) {
- return;
- }
-
- c_brush_traces++;
-
- getout = qfalse;
- startout = qfalse;
-
- leadside = NULL;
-
- if ( tw->sphere.use ) {
- //
- // compare the trace against all planes of the brush
- // find the latest time the trace crosses a plane towards the interior
- // and the earliest time the trace crosses a plane towards the exterior
- //
- for (i = 0; i < brush->numsides; i++) {
- side = brush->sides + i;
- plane = side->plane;
-
- // adjust the plane distance apropriately for radius
- dist = plane->dist + tw->sphere.radius;
-
- // find the closest point on the capsule to the plane
- t = DotProduct( plane->normal, tw->sphere.offset );
- if ( t > 0 )
- {
- VectorSubtract( tw->start, tw->sphere.offset, startp );
- VectorSubtract( tw->end, tw->sphere.offset, endp );
- }
- else
- {
- VectorAdd( tw->start, tw->sphere.offset, startp );
- VectorAdd( tw->end, tw->sphere.offset, endp );
- }
-
- d1 = DotProduct( startp, plane->normal ) - dist;
- d2 = DotProduct( endp, plane->normal ) - dist;
-
- if (d2 > 0) {
- getout = qtrue; // endpoint is not in solid
- }
- if (d1 > 0) {
- startout = qtrue;
- }
-
- // if completely in front of face, no intersection with the entire brush
- if (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 ) ) {
- return;
- }
-
- // if it doesn't cross the plane, the plane isn't relevent
- if (d1 <= 0 && d2 <= 0 ) {
- continue;
- }
-
- // crosses face
- if (d1 > d2) { // enter
- f = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);
- if ( f < 0 ) {
- f = 0;
- }
- if (f > enterFrac) {
- enterFrac = f;
- clipplane = plane;
- leadside = side;
- }
- } else { // leave
- f = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);
- if ( f > 1 ) {
- f = 1;
- }
- if (f < leaveFrac) {
- leaveFrac = f;
- }
- }
- }
- } else {
- //
- // compare the trace against all planes of the brush
- // find the latest time the trace crosses a plane towards the interior
- // and the earliest time the trace crosses a plane towards the exterior
- //
- for (i = 0; i < brush->numsides; i++) {
- side = brush->sides + i;
- plane = side->plane;
-
- // adjust the plane distance apropriately for mins/maxs
- dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal );
-
- d1 = DotProduct( tw->start, plane->normal ) - dist;
- d2 = DotProduct( tw->end, plane->normal ) - dist;
-
- if (d2 > 0) {
- getout = qtrue; // endpoint is not in solid
- }
- if (d1 > 0) {
- startout = qtrue;
- }
-
- // if completely in front of face, no intersection with the entire brush
- if (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 ) ) {
- return;
- }
-
- // if it doesn't cross the plane, the plane isn't relevent
- if (d1 <= 0 && d2 <= 0 ) {
- continue;
- }
-
- // crosses face
- if (d1 > d2) { // enter
- f = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);
- if ( f < 0 ) {
- f = 0;
- }
- if (f > enterFrac) {
- enterFrac = f;
- clipplane = plane;
- leadside = side;
- }
- } else { // leave
- f = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);
- if ( f > 1 ) {
- f = 1;
- }
- if (f < leaveFrac) {
- leaveFrac = f;
- }
- }
- }
- }
-
- //
- // all planes have been checked, and the trace was not
- // completely outside the brush
- //
- if (!startout) { // original point was inside brush
- tw->trace.startsolid = qtrue;
- if (!getout) {
- tw->trace.allsolid = qtrue;
- tw->trace.fraction = 0;
- tw->trace.contents = brush->contents;
- }
- return;
- }
-
- if (enterFrac < leaveFrac) {
- if (enterFrac > -1 && enterFrac < tw->trace.fraction) {
- if (enterFrac < 0) {
- enterFrac = 0;
- }
- tw->trace.fraction = enterFrac;
- tw->trace.plane = *clipplane;
- tw->trace.surfaceFlags = leadside->surfaceFlags;
- tw->trace.contents = brush->contents;
- }
- }
-}
-
-/*
-================
-CM_TraceThroughLeaf
-================
-*/
-void CM_TraceThroughLeaf( traceWork_t *tw, cLeaf_t *leaf ) {
- int k;
- int brushnum;
- cbrush_t *b;
- cPatch_t *patch;
-
- // trace line against all brushes in the leaf
- for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {
- brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];
-
- b = &cm.brushes[brushnum];
- if ( b->checkcount == cm.checkcount ) {
- continue; // already checked this brush in another leaf
- }
- b->checkcount = cm.checkcount;
-
- if ( !(b->contents & tw->contents) ) {
- continue;
- }
-
- if ( !CM_BoundsIntersect( tw->bounds[0], tw->bounds[1],
- b->bounds[0], b->bounds[1] ) ) {
- continue;
- }
-
- CM_TraceThroughBrush( tw, b );
- if ( !tw->trace.fraction ) {
- return;
- }
- }
-
- // trace line against all patches in the leaf
-#ifdef BSPC
- if (1) {
-#else
- if ( !cm_noCurves->integer ) {
-#endif
- for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
- patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ];
- if ( !patch ) {
- continue;
- }
- if ( patch->checkcount == cm.checkcount ) {
- continue; // already checked this patch in another leaf
- }
- patch->checkcount = cm.checkcount;
-
- if ( !(patch->contents & tw->contents) ) {
- continue;
- }
-
- CM_TraceThroughPatch( tw, patch );
- if ( !tw->trace.fraction ) {
- return;
- }
- }
- }
-}
-
-#define RADIUS_EPSILON 1.0f
-
-/*
-================
-CM_TraceThroughSphere
-
-get the first intersection of the ray with the sphere
-================
-*/
-void CM_TraceThroughSphere( traceWork_t *tw, vec3_t origin, float radius, vec3_t start, vec3_t end ) {
- float l1, l2, length, scale, fraction;
- float a, b, c, d, sqrtd;
- vec3_t v1, dir, intersection;
-
- // if inside the sphere
- VectorSubtract(start, origin, dir);
- l1 = VectorLengthSquared(dir);
- if (l1 < Square(radius)) {
- tw->trace.fraction = 0;
- tw->trace.startsolid = qtrue;
- // test for allsolid
- VectorSubtract(end, origin, dir);
- l1 = VectorLengthSquared(dir);
- if (l1 < Square(radius)) {
- tw->trace.allsolid = qtrue;
- }
- return;
- }
- //
- VectorSubtract(end, start, dir);
- length = VectorNormalize(dir);
- //
- l1 = CM_DistanceFromLineSquared(origin, start, end, dir);
- VectorSubtract(end, origin, v1);
- l2 = VectorLengthSquared(v1);
- // if no intersection with the sphere and the end point is at least an epsilon away
- if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
- return;
- }
- //
- // | origin - (start + t * dir) | = radius
- // a = dir[0]^2 + dir[1]^2 + dir[2]^2;
- // b = 2 * (dir[0] * (start[0] - origin[0]) + dir[1] * (start[1] - origin[1]) + dir[2] * (start[2] - origin[2]));
- // c = (start[0] - origin[0])^2 + (start[1] - origin[1])^2 + (start[2] - origin[2])^2 - radius^2;
- //
- VectorSubtract(start, origin, v1);
- // dir is normalized so a = 1
- a = 1.0f;//dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2];
- b = 2.0f * (dir[0] * v1[0] + dir[1] * v1[1] + dir[2] * v1[2]);
- c = v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);
-
- d = b * b - 4.0f * c;// * a;
- if (d > 0) {
- sqrtd = SquareRootFloat(d);
- // = (- b + sqrtd) * 0.5f; // / (2.0f * a);
- fraction = (- b - sqrtd) * 0.5f; // / (2.0f * a);
- //
- if (fraction < 0) {
- fraction = 0;
- }
- else {
- fraction /= length;
- }
- if ( fraction < tw->trace.fraction ) {
- tw->trace.fraction = fraction;
- VectorSubtract(end, start, dir);
- VectorMA(start, fraction, dir, intersection);
- VectorSubtract(intersection, origin, dir);
- #ifdef CAPSULE_DEBUG
- l2 = VectorLength(dir);
- if (l2 < radius) {
- int bah = 1;
- }
- #endif
- scale = 1 / (radius+RADIUS_EPSILON);
- VectorScale(dir, scale, dir);
- VectorCopy(dir, tw->trace.plane.normal);
- VectorAdd( tw->modelOrigin, intersection, intersection);
- tw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection);
- tw->trace.contents = CONTENTS_BODY;
- }
- }
- else if (d == 0) {
- //t1 = (- b ) / 2;
- // slide along the sphere
- }
- // no intersection at all
-}
-
-/*
-================
-CM_TraceThroughVerticalCylinder
-
-get the first intersection of the ray with the cylinder
-the cylinder extends halfheight above and below the origin
-================
-*/
-void CM_TraceThroughVerticalCylinder( traceWork_t *tw, vec3_t origin, float radius, float halfheight, vec3_t start, vec3_t end) {
- float length, scale, fraction, l1, l2;
- float a, b, c, d, sqrtd;
- vec3_t v1, dir, start2d, end2d, org2d, intersection;
-
- // 2d coordinates
- VectorSet(start2d, start[0], start[1], 0);
- VectorSet(end2d, end[0], end[1], 0);
- VectorSet(org2d, origin[0], origin[1], 0);
- // if between lower and upper cylinder bounds
- if (start[2] <= origin[2] + halfheight &&
- start[2] >= origin[2] - halfheight) {
- // if inside the cylinder
- VectorSubtract(start2d, org2d, dir);
- l1 = VectorLengthSquared(dir);
- if (l1 < Square(radius)) {
- tw->trace.fraction = 0;
- tw->trace.startsolid = qtrue;
- VectorSubtract(end2d, org2d, dir);
- l1 = VectorLengthSquared(dir);
- if (l1 < Square(radius)) {
- tw->trace.allsolid = qtrue;
- }
- return;
- }
- }
- //
- VectorSubtract(end2d, start2d, dir);
- length = VectorNormalize(dir);
- //
- l1 = CM_DistanceFromLineSquared(org2d, start2d, end2d, dir);
- VectorSubtract(end2d, org2d, v1);
- l2 = VectorLengthSquared(v1);
- // if no intersection with the cylinder and the end point is at least an epsilon away
- if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
- return;
- }
- //
- //
- // (start[0] - origin[0] - t * dir[0]) ^ 2 + (start[1] - origin[1] - t * dir[1]) ^ 2 = radius ^ 2
- // (v1[0] + t * dir[0]) ^ 2 + (v1[1] + t * dir[1]) ^ 2 = radius ^ 2;
- // v1[0] ^ 2 + 2 * v1[0] * t * dir[0] + (t * dir[0]) ^ 2 +
- // v1[1] ^ 2 + 2 * v1[1] * t * dir[1] + (t * dir[1]) ^ 2 = radius ^ 2
- // t ^ 2 * (dir[0] ^ 2 + dir[1] ^ 2) + t * (2 * v1[0] * dir[0] + 2 * v1[1] * dir[1]) +
- // v1[0] ^ 2 + v1[1] ^ 2 - radius ^ 2 = 0
- //
- VectorSubtract(start, origin, v1);
- // dir is normalized so we can use a = 1
- a = 1.0f;// * (dir[0] * dir[0] + dir[1] * dir[1]);
- b = 2.0f * (v1[0] * dir[0] + v1[1] * dir[1]);
- c = v1[0] * v1[0] + v1[1] * v1[1] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);
-
- d = b * b - 4.0f * c;// * a;
- if (d > 0) {
- sqrtd = SquareRootFloat(d);
- // = (- b + sqrtd) * 0.5f;// / (2.0f * a);
- fraction = (- b - sqrtd) * 0.5f;// / (2.0f * a);
- //
- if (fraction < 0) {
- fraction = 0;
- }
- else {
- fraction /= length;
- }
- if ( fraction < tw->trace.fraction ) {
- VectorSubtract(end, start, dir);
- VectorMA(start, fraction, dir, intersection);
- // if the intersection is between the cylinder lower and upper bound
- if (intersection[2] <= origin[2] + halfheight &&
- intersection[2] >= origin[2] - halfheight) {
- //
- tw->trace.fraction = fraction;
- VectorSubtract(intersection, origin, dir);
- dir[2] = 0;
- #ifdef CAPSULE_DEBUG
- l2 = VectorLength(dir);
- if (l2 <= radius) {
- int bah = 1;
- }
- #endif
- scale = 1 / (radius+RADIUS_EPSILON);
- VectorScale(dir, scale, dir);
- VectorCopy(dir, tw->trace.plane.normal);
- VectorAdd( tw->modelOrigin, intersection, intersection);
- tw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection);
- tw->trace.contents = CONTENTS_BODY;
- }
- }
- }
- else if (d == 0) {
- //t[0] = (- b ) / 2 * a;
- // slide along the cylinder
- }
- // no intersection at all
-}
-
-/*
-================
-CM_TraceCapsuleThroughCapsule
-
-capsule vs. capsule collision (not rotated)
-================
-*/
-void CM_TraceCapsuleThroughCapsule( traceWork_t *tw, clipHandle_t model ) {
- int i;
- vec3_t mins, maxs;
- vec3_t top, bottom, starttop, startbottom, endtop, endbottom;
- vec3_t offset, symetricSize[2];
- float radius, halfwidth, halfheight, offs, h;
-
- CM_ModelBounds(model, mins, maxs);
- // test trace bounds vs. capsule bounds
- if ( tw->bounds[0][0] > maxs[0] + RADIUS_EPSILON
- || tw->bounds[0][1] > maxs[1] + RADIUS_EPSILON
- || tw->bounds[0][2] > maxs[2] + RADIUS_EPSILON
- || tw->bounds[1][0] < mins[0] - RADIUS_EPSILON
- || tw->bounds[1][1] < mins[1] - RADIUS_EPSILON
- || tw->bounds[1][2] < mins[2] - RADIUS_EPSILON
- ) {
- return;
- }
- // top origin and bottom origin of each sphere at start and end of trace
- VectorAdd(tw->start, tw->sphere.offset, starttop);
- VectorSubtract(tw->start, tw->sphere.offset, startbottom);
- VectorAdd(tw->end, tw->sphere.offset, endtop);
- VectorSubtract(tw->end, tw->sphere.offset, endbottom);
-
- // calculate top and bottom of the capsule spheres to collide with
- for ( i = 0 ; i < 3 ; i++ ) {
- offset[i] = ( mins[i] + maxs[i] ) * 0.5;
- symetricSize[0][i] = mins[i] - offset[i];
- symetricSize[1][i] = maxs[i] - offset[i];
- }
- halfwidth = symetricSize[ 1 ][ 0 ];
- halfheight = symetricSize[ 1 ][ 2 ];
- radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
- offs = halfheight - radius;
- VectorCopy(offset, top);
- top[2] += offs;
- VectorCopy(offset, bottom);
- bottom[2] -= offs;
- // expand radius of spheres
- radius += tw->sphere.radius;
- // if there is horizontal movement
- if ( tw->start[0] != tw->end[0] || tw->start[1] != tw->end[1] ) {
- // height of the expanded cylinder is the height of both cylinders minus the radius of both spheres
- h = halfheight + tw->sphere.halfheight - radius;
- // if the cylinder has a height
- if ( h > 0 ) {
- // test for collisions between the cylinders
- CM_TraceThroughVerticalCylinder(tw, offset, radius, h, tw->start, tw->end);
- }
- }
- // test for collision between the spheres
- CM_TraceThroughSphere(tw, top, radius, startbottom, endbottom);
- CM_TraceThroughSphere(tw, bottom, radius, starttop, endtop);
-}
-
-/*
-================
-CM_TraceBoundingBoxThroughCapsule
-
-bounding box vs. capsule collision
-================
-*/
-void CM_TraceBoundingBoxThroughCapsule( traceWork_t *tw, clipHandle_t model ) {
- vec3_t mins, maxs, offset, size[2];
- clipHandle_t h;
- cmodel_t *cmod;
- int i;
-
- // mins maxs of the capsule
- CM_ModelBounds(model, mins, maxs);
-
- // offset for capsule center
- for ( i = 0 ; i < 3 ; i++ ) {
- offset[i] = ( mins[i] + maxs[i] ) * 0.5;
- size[0][i] = mins[i] - offset[i];
- size[1][i] = maxs[i] - offset[i];
- tw->start[i] -= offset[i];
- tw->end[i] -= offset[i];
- }
-
- // replace the bounding box with the capsule
- tw->sphere.use = qtrue;
- tw->sphere.radius = ( size[1][0] > size[1][2] ) ? size[1][2]: size[1][0];
- tw->sphere.halfheight = size[1][2];
- VectorSet( tw->sphere.offset, 0, 0, size[1][2] - tw->sphere.radius );
-
- // replace the capsule with the bounding box
- h = CM_TempBoxModel(tw->size[0], tw->size[1], qfalse);
- // calculate collision
- cmod = CM_ClipHandleToModel( h );
- CM_TraceThroughLeaf( tw, &cmod->leaf );
-}
-
-//=========================================================================================
-
-/*
-==================
-CM_TraceThroughTree
-
-Traverse all the contacted leafs from the start to the end position.
-If the trace is a point, they will be exactly in order, but for larger
-trace volumes it is possible to hit something in a later leaf with
-a smaller intercept fraction.
-==================
-*/
-void CM_TraceThroughTree( traceWork_t *tw, int num, float p1f, float p2f, vec3_t p1, vec3_t p2) {
- cNode_t *node;
- cplane_t *plane;
- float t1, t2, offset;
- float frac, frac2;
- float idist;
- vec3_t mid;
- int side;
- float midf;
-
- if (tw->trace.fraction <= p1f) {
- return; // already hit something nearer
- }
-
- // if < 0, we are in a leaf node
- if (num < 0) {
- CM_TraceThroughLeaf( tw, &cm.leafs[-1-num] );
- return;
- }
-
- //
- // find the point distances to the seperating plane
- // and the offset for the size of the box
- //
- node = cm.nodes + num;
- plane = node->plane;
-
- // adjust the plane distance apropriately for mins/maxs
- if ( plane->type < 3 ) {
- t1 = p1[plane->type] - plane->dist;
- t2 = p2[plane->type] - plane->dist;
- offset = tw->extents[plane->type];
- } else {
- t1 = DotProduct (plane->normal, p1) - plane->dist;
- t2 = DotProduct (plane->normal, p2) - plane->dist;
- if ( tw->isPoint ) {
- offset = 0;
- } else {
- // this is silly
- offset = 2048;
- }
- }
-
- // see which sides we need to consider
- if ( t1 >= offset + 1 && t2 >= offset + 1 ) {
- CM_TraceThroughTree( tw, node->children[0], p1f, p2f, p1, p2 );
- return;
- }
- if ( t1 < -offset - 1 && t2 < -offset - 1 ) {
- CM_TraceThroughTree( tw, node->children[1], p1f, p2f, p1, p2 );
- return;
- }
-
- // put the crosspoint SURFACE_CLIP_EPSILON pixels on the near side
- if ( t1 < t2 ) {
- idist = 1.0/(t1-t2);
- side = 1;
- frac2 = (t1 + offset + SURFACE_CLIP_EPSILON)*idist;
- frac = (t1 - offset + SURFACE_CLIP_EPSILON)*idist;
- } else if (t1 > t2) {
- idist = 1.0/(t1-t2);
- side = 0;
- frac2 = (t1 - offset - SURFACE_CLIP_EPSILON)*idist;
- frac = (t1 + offset + SURFACE_CLIP_EPSILON)*idist;
- } else {
- side = 0;
- frac = 1;
- frac2 = 0;
- }
-
- // move up to the node
- if ( frac < 0 ) {
- frac = 0;
- }
- if ( frac > 1 ) {
- frac = 1;
- }
-
- midf = p1f + (p2f - p1f)*frac;
-
- mid[0] = p1[0] + frac*(p2[0] - p1[0]);
- mid[1] = p1[1] + frac*(p2[1] - p1[1]);
- mid[2] = p1[2] + frac*(p2[2] - p1[2]);
-
- CM_TraceThroughTree( tw, node->children[side], p1f, midf, p1, mid );
-
-
- // go past the node
- if ( frac2 < 0 ) {
- frac2 = 0;
- }
- if ( frac2 > 1 ) {
- frac2 = 1;
- }
-
- midf = p1f + (p2f - p1f)*frac2;
-
- mid[0] = p1[0] + frac2*(p2[0] - p1[0]);
- mid[1] = p1[1] + frac2*(p2[1] - p1[1]);
- mid[2] = p1[2] + frac2*(p2[2] - p1[2]);
-
- CM_TraceThroughTree( tw, node->children[side^1], midf, p2f, mid, p2 );
-}
-
-
-//======================================================================
-
-
-/*
-==================
-CM_Trace
-==================
-*/
-void CM_Trace( trace_t *results, const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs,
- clipHandle_t model, const vec3_t origin, int brushmask, int capsule, sphere_t *sphere ) {
- int i;
- traceWork_t tw;
- vec3_t offset;
- cmodel_t *cmod;
-
- cmod = CM_ClipHandleToModel( model );
-
- cm.checkcount++; // for multi-check avoidance
-
- c_traces++; // for statistics, may be zeroed
-
- // fill in a default trace
- Com_Memset( &tw, 0, sizeof(tw) );
- tw.trace.fraction = 1; // assume it goes the entire distance until shown otherwise
- VectorCopy(origin, tw.modelOrigin);
-
- if (!cm.numNodes) {
- *results = tw.trace;
-
- return; // map not loaded, shouldn't happen
- }
-
- // allow NULL to be passed in for 0,0,0
- if ( !mins ) {
- mins = vec3_origin;
- }
- if ( !maxs ) {
- maxs = vec3_origin;
- }
-
- // set basic parms
- tw.contents = brushmask;
-
- // adjust so that mins and maxs are always symetric, which
- // avoids some complications with plane expanding of rotated
- // bmodels
- for ( i = 0 ; i < 3 ; i++ ) {
- offset[i] = ( mins[i] + maxs[i] ) * 0.5;
- tw.size[0][i] = mins[i] - offset[i];
- tw.size[1][i] = maxs[i] - offset[i];
- tw.start[i] = start[i] + offset[i];
- tw.end[i] = end[i] + offset[i];
- }
-
- // if a sphere is already specified
- if ( sphere ) {
- tw.sphere = *sphere;
- }
- else {
- tw.sphere.use = capsule;
- tw.sphere.radius = ( tw.size[1][0] > tw.size[1][2] ) ? tw.size[1][2]: tw.size[1][0];
- tw.sphere.halfheight = tw.size[1][2];
- VectorSet( tw.sphere.offset, 0, 0, tw.size[1][2] - tw.sphere.radius );
- }
-
- tw.maxOffset = tw.size[1][0] + tw.size[1][1] + tw.size[1][2];
-
- // tw.offsets[signbits] = vector to apropriate corner from origin
- tw.offsets[0][0] = tw.size[0][0];
- tw.offsets[0][1] = tw.size[0][1];
- tw.offsets[0][2] = tw.size[0][2];
-
- tw.offsets[1][0] = tw.size[1][0];
- tw.offsets[1][1] = tw.size[0][1];
- tw.offsets[1][2] = tw.size[0][2];
-
- tw.offsets[2][0] = tw.size[0][0];
- tw.offsets[2][1] = tw.size[1][1];
- tw.offsets[2][2] = tw.size[0][2];
-
- tw.offsets[3][0] = tw.size[1][0];
- tw.offsets[3][1] = tw.size[1][1];
- tw.offsets[3][2] = tw.size[0][2];
-
- tw.offsets[4][0] = tw.size[0][0];
- tw.offsets[4][1] = tw.size[0][1];
- tw.offsets[4][2] = tw.size[1][2];
-
- tw.offsets[5][0] = tw.size[1][0];
- tw.offsets[5][1] = tw.size[0][1];
- tw.offsets[5][2] = tw.size[1][2];
-
- tw.offsets[6][0] = tw.size[0][0];
- tw.offsets[6][1] = tw.size[1][1];
- tw.offsets[6][2] = tw.size[1][2];
-
- tw.offsets[7][0] = tw.size[1][0];
- tw.offsets[7][1] = tw.size[1][1];
- tw.offsets[7][2] = tw.size[1][2];
-
- //
- // calculate bounds
- //
- if ( tw.sphere.use ) {
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( tw.start[i] < tw.end[i] ) {
- tw.bounds[0][i] = tw.start[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius;
- tw.bounds[1][i] = tw.end[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius;
- } else {
- tw.bounds[0][i] = tw.end[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius;
- tw.bounds[1][i] = tw.start[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius;
- }
- }
- }
- else {
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( tw.start[i] < tw.end[i] ) {
- tw.bounds[0][i] = tw.start[i] + tw.size[0][i];
- tw.bounds[1][i] = tw.end[i] + tw.size[1][i];
- } else {
- tw.bounds[0][i] = tw.end[i] + tw.size[0][i];
- tw.bounds[1][i] = tw.start[i] + tw.size[1][i];
- }
- }
- }
-
- //
- // check for position test special case
- //
- if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) {
- if ( model ) {
-#ifdef ALWAYS_BBOX_VS_BBOX // FIXME - compile time flag?
- if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
- tw.sphere.use = qfalse;
- CM_TestInLeaf( &tw, &cmod->leaf );
- }
- else
-#elif defined(ALWAYS_CAPSULE_VS_CAPSULE)
- if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
- CM_TestCapsuleInCapsule( &tw, model );
- }
- else
-#endif
- if ( model == CAPSULE_MODEL_HANDLE ) {
- if ( tw.sphere.use ) {
- CM_TestCapsuleInCapsule( &tw, model );
- }
- else {
- CM_TestBoundingBoxInCapsule( &tw, model );
- }
- }
- else {
- CM_TestInLeaf( &tw, &cmod->leaf );
- }
- } else {
- CM_PositionTest( &tw );
- }
- } else {
- //
- // check for point special case
- //
- if ( tw.size[0][0] == 0 && tw.size[0][1] == 0 && tw.size[0][2] == 0 ) {
- tw.isPoint = qtrue;
- VectorClear( tw.extents );
- } else {
- tw.isPoint = qfalse;
- tw.extents[0] = tw.size[1][0];
- tw.extents[1] = tw.size[1][1];
- tw.extents[2] = tw.size[1][2];
- }
-
- //
- // general sweeping through world
- //
- if ( model ) {
-#ifdef ALWAYS_BBOX_VS_BBOX
- if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
- tw.sphere.use = qfalse;
- CM_TraceThroughLeaf( &tw, &cmod->leaf );
- }
- else
-#elif defined(ALWAYS_CAPSULE_VS_CAPSULE)
- if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
- CM_TraceCapsuleThroughCapsule( &tw, model );
- }
- else
-#endif
- if ( model == CAPSULE_MODEL_HANDLE ) {
- if ( tw.sphere.use ) {
- CM_TraceCapsuleThroughCapsule( &tw, model );
- }
- else {
- CM_TraceBoundingBoxThroughCapsule( &tw, model );
- }
- }
- else {
- CM_TraceThroughLeaf( &tw, &cmod->leaf );
- }
- } else {
- CM_TraceThroughTree( &tw, 0, 0, 1, tw.start, tw.end );
- }
- }
-
- // generate endpos from the original, unmodified start/end
- if ( tw.trace.fraction == 1 ) {
- VectorCopy (end, tw.trace.endpos);
- } else {
- for ( i=0 ; i<3 ; i++ ) {
- tw.trace.endpos[i] = start[i] + tw.trace.fraction * (end[i] - start[i]);
- }
- }
-
- // If allsolid is set (was entirely inside something solid), the plane is not valid.
- // If fraction == 1.0, we never hit anything, and thus the plane is not valid.
- // Otherwise, the normal on the plane should have unit length
- assert(tw.trace.allsolid ||
- tw.trace.fraction == 1.0 ||
- VectorLengthSquared(tw.trace.plane.normal) > 0.9999);
- *results = tw.trace;
-}
-
-/*
-==================
-CM_BoxTrace
-==================
-*/
-void CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- vec3_t mins, vec3_t maxs,
- clipHandle_t model, int brushmask, int capsule ) {
- CM_Trace( results, start, end, mins, maxs, model, vec3_origin, brushmask, capsule, NULL );
-}
-
-/*
-==================
-CM_TransformedBoxTrace
-
-Handles offseting and rotation of the end points for moving and
-rotating entities
-==================
-*/
-void CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- vec3_t mins, vec3_t maxs,
- clipHandle_t model, int brushmask,
- const vec3_t origin, const vec3_t angles, int capsule ) {
- trace_t trace;
- vec3_t start_l, end_l;
- qboolean rotated;
- vec3_t offset;
- vec3_t symetricSize[2];
- vec3_t matrix[3], transpose[3];
- int i;
- float halfwidth;
- float halfheight;
- float t;
- sphere_t sphere;
-
- if ( !mins ) {
- mins = vec3_origin;
- }
- if ( !maxs ) {
- maxs = vec3_origin;
- }
-
- // adjust so that mins and maxs are always symetric, which
- // avoids some complications with plane expanding of rotated
- // bmodels
- for ( i = 0 ; i < 3 ; i++ ) {
- offset[i] = ( mins[i] + maxs[i] ) * 0.5;
- symetricSize[0][i] = mins[i] - offset[i];
- symetricSize[1][i] = maxs[i] - offset[i];
- start_l[i] = start[i] + offset[i];
- end_l[i] = end[i] + offset[i];
- }
-
- // subtract origin offset
- VectorSubtract( start_l, origin, start_l );
- VectorSubtract( end_l, origin, end_l );
-
- // rotate start and end into the models frame of reference
- if ( model != BOX_MODEL_HANDLE &&
- (angles[0] || angles[1] || angles[2]) ) {
- rotated = qtrue;
- } else {
- rotated = qfalse;
- }
-
- halfwidth = symetricSize[ 1 ][ 0 ];
- halfheight = symetricSize[ 1 ][ 2 ];
-
- sphere.use = capsule;
- sphere.radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
- sphere.halfheight = halfheight;
- t = halfheight - sphere.radius;
-
- if (rotated) {
- // rotation on trace line (start-end) instead of rotating the bmodel
- // NOTE: This is still incorrect for bounding boxes because the actual bounding
- // box that is swept through the model is not rotated. We cannot rotate
- // the bounding box or the bmodel because that would make all the brush
- // bevels invalid.
- // However this is correct for capsules since a capsule itself is rotated too.
- CreateRotationMatrix(angles, matrix);
- RotatePoint(start_l, matrix);
- RotatePoint(end_l, matrix);
- // rotated sphere offset for capsule
- sphere.offset[0] = matrix[0][ 2 ] * t;
- sphere.offset[1] = -matrix[1][ 2 ] * t;
- sphere.offset[2] = matrix[2][ 2 ] * t;
- }
- else {
- VectorSet( sphere.offset, 0, 0, t );
- }
-
- // sweep the box through the model
- CM_Trace( &trace, start_l, end_l, symetricSize[0], symetricSize[1], model, origin, brushmask, capsule, &sphere );
-
- // if the bmodel was rotated and there was a collision
- if ( rotated && trace.fraction != 1.0 ) {
- // rotation of bmodel collision plane
- TransposeMatrix(matrix, transpose);
- RotatePoint(trace.plane.normal, transpose);
- }
-
- // re-calculate the end position of the trace because the trace.endpos
- // calculated by CM_Trace could be rotated and have an offset
- trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
- trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
- trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
-
- *results = trace;
-}
diff --git a/engine/code/qcommon/cmd.c b/engine/code/qcommon/cmd.c
deleted file mode 100644
index f1243b3..0000000
--- a/engine/code/qcommon/cmd.c
+++ /dev/null
@@ -1,796 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// cmd.c -- Quake script command processing module
-
-#include "q_shared.h"
-#include "qcommon.h"
-
-#define MAX_CMD_BUFFER 16384
-#define MAX_CMD_LINE 1024
-
-typedef struct {
- byte *data;
- int maxsize;
- int cursize;
-} cmd_t;
-
-int cmd_wait;
-cmd_t cmd_text;
-byte cmd_text_buf[MAX_CMD_BUFFER];
-
-
-//=============================================================================
-
-/*
-============
-Cmd_Wait_f
-
-Causes execution of the remainder of the command buffer to be delayed until
-next frame. This allows commands like:
-bind g "cmd use rocket ; +attack ; wait ; -attack ; cmd use blaster"
-============
-*/
-void Cmd_Wait_f( void ) {
- if ( Cmd_Argc() == 2 ) {
- cmd_wait = atoi( Cmd_Argv( 1 ) );
- if ( cmd_wait < 0 )
- cmd_wait = 1; // ignore the argument
- } else {
- cmd_wait = 1;
- }
-}
-
-
-/*
-=============================================================================
-
- COMMAND BUFFER
-
-=============================================================================
-*/
-
-/*
-============
-Cbuf_Init
-============
-*/
-void Cbuf_Init (void)
-{
- cmd_text.data = cmd_text_buf;
- cmd_text.maxsize = MAX_CMD_BUFFER;
- cmd_text.cursize = 0;
-}
-
-/*
-============
-Cbuf_AddText
-
-Adds command text at the end of the buffer, does NOT add a final \n
-============
-*/
-void Cbuf_AddText( const char *text ) {
- int l;
-
- l = strlen (text);
-
- if (cmd_text.cursize + l >= cmd_text.maxsize)
- {
- Com_Printf ("Cbuf_AddText: overflow\n");
- return;
- }
- Com_Memcpy(&cmd_text.data[cmd_text.cursize], text, l);
- cmd_text.cursize += l;
-}
-
-
-/*
-============
-Cbuf_InsertText
-
-Adds command text immediately after the current command
-Adds a \n to the text
-============
-*/
-void Cbuf_InsertText( const char *text ) {
- int len;
- int i;
-
- len = strlen( text ) + 1;
- if ( len + cmd_text.cursize > cmd_text.maxsize ) {
- Com_Printf( "Cbuf_InsertText overflowed\n" );
- return;
- }
-
- // move the existing command text
- for ( i = cmd_text.cursize - 1 ; i >= 0 ; i-- ) {
- cmd_text.data[ i + len ] = cmd_text.data[ i ];
- }
-
- // copy the new text in
- Com_Memcpy( cmd_text.data, text, len - 1 );
-
- // add a \n
- cmd_text.data[ len - 1 ] = '\n';
-
- cmd_text.cursize += len;
-}
-
-
-/*
-============
-Cbuf_ExecuteText
-============
-*/
-void Cbuf_ExecuteText (int exec_when, const char *text)
-{
- switch (exec_when)
- {
- case EXEC_NOW:
- if (text && strlen(text) > 0) {
- Com_DPrintf(S_COLOR_YELLOW "EXEC_NOW %s\n", text);
- Cmd_ExecuteString (text);
- } else {
- Cbuf_Execute();
- Com_DPrintf(S_COLOR_YELLOW "EXEC_NOW %s\n", cmd_text.data);
- }
- break;
- case EXEC_INSERT:
- Cbuf_InsertText (text);
- break;
- case EXEC_APPEND:
- Cbuf_AddText (text);
- break;
- default:
- Com_Error (ERR_FATAL, "Cbuf_ExecuteText: bad exec_when");
- }
-}
-
-/*
-============
-Cbuf_Execute
-============
-*/
-void Cbuf_Execute (void)
-{
- int i;
- char *text;
- char line[MAX_CMD_LINE];
- int quotes;
-
- while (cmd_text.cursize)
- {
- if ( cmd_wait > 0 ) {
- // skip out while text still remains in buffer, leaving it
- // for next frame
- cmd_wait--;
- break;
- }
-
- // 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' || text[i] == '\r' )
- break;
- }
-
- if( i >= (MAX_CMD_LINE - 1)) {
- i = MAX_CMD_LINE - 1;
- }
-
- Com_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) 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;
- memmove (text, text+i, cmd_text.cursize);
- }
-
-// execute the command line
-
- Cmd_ExecuteString (line);
- }
-}
-
-
-/*
-==============================================================================
-
- SCRIPT COMMANDS
-
-==============================================================================
-*/
-
-
-/*
-===============
-Cmd_Exec_f
-===============
-*/
-void Cmd_Exec_f( void ) {
- union {
- char *c;
- void *v;
- } f;
- int len;
- char filename[MAX_QPATH];
-
- if (Cmd_Argc () != 2) {
- Com_Printf ("exec <filename> : execute a script file\n");
- return;
- }
-
- Q_strncpyz( filename, Cmd_Argv(1), sizeof( filename ) );
- COM_DefaultExtension( filename, sizeof( filename ), ".cfg" );
- len = FS_ReadFile( filename, &f.v);
- if (!f.c) {
- Com_Printf ("couldn't exec %s\n",Cmd_Argv(1));
- return;
- }
- Com_Printf ("execing %s\n",Cmd_Argv(1));
-
- Cbuf_InsertText (f.c);
-
- FS_FreeFile (f.v);
-}
-
-
-/*
-===============
-Cmd_Vstr_f
-
-Inserts the current value of a variable as command text
-===============
-*/
-void Cmd_Vstr_f( void ) {
- char *v;
-
- if (Cmd_Argc () != 2) {
- Com_Printf ("vstr <variablename> : execute a variable command\n");
- return;
- }
-
- v = Cvar_VariableString( Cmd_Argv( 1 ) );
- Cbuf_InsertText( va("%s\n", v ) );
-}
-
-
-/*
-===============
-Cmd_Echo_f
-
-Just prints the rest of the line to the console
-===============
-*/
-void Cmd_Echo_f (void)
-{
- Com_Printf ("%s\n", Cmd_Args());
-}
-
-
-/*
-=============================================================================
-
- COMMAND EXECUTION
-
-=============================================================================
-*/
-
-typedef struct cmd_function_s
-{
- struct cmd_function_s *next;
- char *name;
- xcommand_t function;
- completionFunc_t complete;
-} cmd_function_t;
-
-
-static int cmd_argc;
-static char *cmd_argv[MAX_STRING_TOKENS]; // points into cmd_tokenized
-static char cmd_tokenized[BIG_INFO_STRING+MAX_STRING_TOKENS]; // will have 0 bytes inserted
-static char cmd_cmd[BIG_INFO_STRING]; // the original command we received (no token processing)
-
-static cmd_function_t *cmd_functions; // possible commands to execute
-
-/*
-============
-Cmd_Argc
-============
-*/
-int Cmd_Argc( void ) {
- return cmd_argc;
-}
-
-/*
-============
-Cmd_Argv
-============
-*/
-char *Cmd_Argv( int arg ) {
- if ( (unsigned)arg >= cmd_argc ) {
- return "";
- }
- return cmd_argv[arg];
-}
-
-/*
-============
-Cmd_ArgvBuffer
-
-The interpreted versions use this because
-they can't have pointers returned to them
-============
-*/
-void Cmd_ArgvBuffer( int arg, char *buffer, int bufferLength ) {
- Q_strncpyz( buffer, Cmd_Argv( arg ), bufferLength );
-}
-
-
-/*
-============
-Cmd_Args
-
-Returns a single string containing argv(1) to argv(argc()-1)
-============
-*/
-char *Cmd_Args( void ) {
- static char cmd_args[MAX_STRING_CHARS];
- int i;
-
- cmd_args[0] = 0;
- for ( i = 1 ; i < cmd_argc ; i++ ) {
- strcat( cmd_args, cmd_argv[i] );
- if ( i != cmd_argc-1 ) {
- strcat( cmd_args, " " );
- }
- }
-
- return cmd_args;
-}
-
-/*
-============
-Cmd_Args
-
-Returns a single string containing argv(arg) to argv(argc()-1)
-============
-*/
-char *Cmd_ArgsFrom( int arg ) {
- static char cmd_args[BIG_INFO_STRING];
- int i;
-
- cmd_args[0] = 0;
- if (arg < 0)
- arg = 0;
- for ( i = arg ; i < cmd_argc ; i++ ) {
- strcat( cmd_args, cmd_argv[i] );
- if ( i != cmd_argc-1 ) {
- strcat( cmd_args, " " );
- }
- }
-
- return cmd_args;
-}
-
-/*
-============
-Cmd_ArgsBuffer
-
-The interpreted versions use this because
-they can't have pointers returned to them
-============
-*/
-void Cmd_ArgsBuffer( char *buffer, int bufferLength ) {
- Q_strncpyz( buffer, Cmd_Args(), bufferLength );
-}
-
-/*
-============
-Cmd_Cmd
-
-Retrieve the unmodified command string
-For rcon use when you want to transmit without altering quoting
-https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543
-============
-*/
-char *Cmd_Cmd(void)
-{
- return cmd_cmd;
-}
-
-/*
- Replace command separators with space to prevent interpretation
- This is a hack to protect buggy qvms
- https://bugzilla.icculus.org/show_bug.cgi?id=3593
-*/
-void Cmd_Args_Sanitize( void ) {
- int i;
- for ( i = 1 ; i < cmd_argc ; i++ ) {
- char* c = cmd_argv[i];
- while ((c = strpbrk(c, "\n\r;"))) {
- *c = ' ';
- ++c;
- }
- }
-}
-
-/*
-============
-Cmd_TokenizeString
-
-Parses the given string into command line tokens.
-The text is copied to a seperate buffer and 0 characters
-are inserted in the apropriate place, The argv array
-will point into this temporary buffer.
-============
-*/
-// NOTE TTimo define that to track tokenization issues
-//#define TKN_DBG
-static void Cmd_TokenizeString2( const char *text_in, qboolean ignoreQuotes ) {
- const char *text;
- char *textOut;
-
-#ifdef TKN_DBG
- // FIXME TTimo blunt hook to try to find the tokenization of userinfo
- Com_DPrintf("Cmd_TokenizeString: %s\n", text_in);
-#endif
-
- // clear previous args
- cmd_argc = 0;
-
- if ( !text_in ) {
- return;
- }
-
- Q_strncpyz( cmd_cmd, text_in, sizeof(cmd_cmd) );
-
- text = text_in;
- textOut = cmd_tokenized;
-
- while ( 1 ) {
- if ( cmd_argc == MAX_STRING_TOKENS ) {
- return; // this is usually something malicious
- }
-
- while ( 1 ) {
- // skip whitespace
- while ( *text && *text <= ' ' ) {
- text++;
- }
- if ( !*text ) {
- return; // all tokens parsed
- }
-
- // skip // comments
- if ( text[0] == '/' && text[1] == '/' ) {
- return; // all tokens parsed
- }
-
- // skip /* */ comments
- if ( text[0] == '/' && text[1] =='*' ) {
- while ( *text && ( text[0] != '*' || text[1] != '/' ) ) {
- text++;
- }
- if ( !*text ) {
- return; // all tokens parsed
- }
- text += 2;
- } else {
- break; // we are ready to parse a token
- }
- }
-
- // handle quoted strings
- // NOTE TTimo this doesn't handle \" escaping
- if ( !ignoreQuotes && *text == '"' ) {
- cmd_argv[cmd_argc] = textOut;
- cmd_argc++;
- text++;
- while ( *text && *text != '"' ) {
- *textOut++ = *text++;
- }
- *textOut++ = 0;
- if ( !*text ) {
- return; // all tokens parsed
- }
- text++;
- continue;
- }
-
- // regular token
- cmd_argv[cmd_argc] = textOut;
- cmd_argc++;
-
- // skip until whitespace, quote, or command
- while ( *text > ' ' ) {
- if ( !ignoreQuotes && text[0] == '"' ) {
- break;
- }
-
- if ( text[0] == '/' && text[1] == '/' ) {
- break;
- }
-
- // skip /* */ comments
- if ( text[0] == '/' && text[1] =='*' ) {
- break;
- }
-
- *textOut++ = *text++;
- }
-
- *textOut++ = 0;
-
- if ( !*text ) {
- return; // all tokens parsed
- }
- }
-
-}
-
-/*
-============
-Cmd_TokenizeString
-============
-*/
-void Cmd_TokenizeString( const char *text_in ) {
- Cmd_TokenizeString2( text_in, qfalse );
-}
-
-/*
-============
-Cmd_TokenizeStringIgnoreQuotes
-============
-*/
-void Cmd_TokenizeStringIgnoreQuotes( const char *text_in ) {
- Cmd_TokenizeString2( text_in, qtrue );
-}
-
-/*
-============
-Cmd_AddCommand
-============
-*/
-void Cmd_AddCommand( const char *cmd_name, xcommand_t function ) {
- cmd_function_t *cmd;
-
- // fail if the command already exists
- for ( cmd = cmd_functions ; cmd ; cmd=cmd->next ) {
- if ( !strcmp( cmd_name, cmd->name ) ) {
- // allow completion-only commands to be silently doubled
- if ( function != NULL ) {
- Com_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
- }
- return;
- }
- }
-
- // use a small malloc to avoid zone fragmentation
- cmd = S_Malloc (sizeof(cmd_function_t));
- cmd->name = CopyString( cmd_name );
- cmd->function = function;
- cmd->complete = NULL;
- cmd->next = cmd_functions;
- cmd_functions = cmd;
-}
-
-/*
-============
-Cmd_SetCommandCompletionFunc
-============
-*/
-void Cmd_SetCommandCompletionFunc( const char *command, completionFunc_t complete ) {
- cmd_function_t *cmd;
-
- for( cmd = cmd_functions; cmd; cmd = cmd->next ) {
- if( !Q_stricmp( command, cmd->name ) ) {
- cmd->complete = complete;
- }
- }
-}
-
-/*
-============
-Cmd_RemoveCommand
-============
-*/
-void Cmd_RemoveCommand( const char *cmd_name ) {
- cmd_function_t *cmd, **back;
-
- back = &cmd_functions;
- while( 1 ) {
- cmd = *back;
- if ( !cmd ) {
- // command wasn't active
- return;
- }
- if ( !strcmp( cmd_name, cmd->name ) ) {
- *back = cmd->next;
- if (cmd->name) {
- Z_Free(cmd->name);
- }
- Z_Free (cmd);
- return;
- }
- back = &cmd->next;
- }
-}
-
-
-/*
-============
-Cmd_CommandCompletion
-============
-*/
-void Cmd_CommandCompletion( void(*callback)(const char *s) ) {
- cmd_function_t *cmd;
-
- for (cmd=cmd_functions ; cmd ; cmd=cmd->next) {
- callback( cmd->name );
- }
-}
-
-/*
-============
-Cmd_CompleteArgument
-============
-*/
-void Cmd_CompleteArgument( const char *command, char *args, int argNum ) {
- cmd_function_t *cmd;
-
- for( cmd = cmd_functions; cmd; cmd = cmd->next ) {
- if( !Q_stricmp( command, cmd->name ) && cmd->complete ) {
- cmd->complete( args, argNum );
- }
- }
-}
-
-
-/*
-============
-Cmd_ExecuteString
-
-A complete command line has been parsed, so try to execute it
-============
-*/
-void Cmd_ExecuteString( const char *text ) {
- cmd_function_t *cmd, **prev;
-
- // execute the command line
- Cmd_TokenizeString( text );
- if ( !Cmd_Argc() ) {
- return; // no tokens
- }
-
- // check registered command functions
- for ( prev = &cmd_functions ; *prev ; prev = &cmd->next ) {
- cmd = *prev;
- if ( !Q_stricmp( cmd_argv[0],cmd->name ) ) {
- // rearrange the links so that the command will be
- // near the head of the list next time it is used
- *prev = cmd->next;
- cmd->next = cmd_functions;
- cmd_functions = cmd;
-
- // perform the action
- if ( !cmd->function ) {
- // let the cgame or game handle it
- break;
- } else {
- cmd->function ();
- }
- return;
- }
- }
-
- // check cvars
- if ( Cvar_Command() ) {
- return;
- }
-
- // check client game commands
- if ( com_cl_running && com_cl_running->integer && CL_GameCommand() ) {
- return;
- }
-
- // check server game commands
- if ( com_sv_running && com_sv_running->integer && SV_GameCommand() ) {
- return;
- }
-
- // check ui commands
- if ( com_cl_running && com_cl_running->integer && UI_GameCommand() ) {
- return;
- }
-
- // send it as a server command if we are connected
- // this will usually result in a chat message
- CL_ForwardCommandToServer ( text );
-}
-
-/*
-============
-Cmd_List_f
-============
-*/
-void Cmd_List_f (void)
-{
- cmd_function_t *cmd;
- int i;
- char *match;
-
- if ( Cmd_Argc() > 1 ) {
- match = Cmd_Argv( 1 );
- } else {
- match = NULL;
- }
-
- i = 0;
- for (cmd=cmd_functions ; cmd ; cmd=cmd->next) {
- if (match && !Com_Filter(match, cmd->name, qfalse)) continue;
-
- Com_Printf ("%s\n", cmd->name);
- i++;
- }
- Com_Printf ("%i commands\n", i);
-}
-
-/*
-==================
-Cmd_CompleteCfgName
-==================
-*/
-void Cmd_CompleteCfgName( char *args, int argNum ) {
- if( argNum == 2 ) {
- Field_CompleteFilename( "", "cfg", qfalse );
- }
-}
-
-/*
-============
-Cmd_Init
-============
-*/
-void Cmd_Init (void) {
- Cmd_AddCommand ("cmdlist",Cmd_List_f);
- Cmd_AddCommand ("exec",Cmd_Exec_f);
- Cmd_SetCommandCompletionFunc( "exec", Cmd_CompleteCfgName );
- Cmd_AddCommand ("vstr",Cmd_Vstr_f);
- Cmd_SetCommandCompletionFunc( "vstr", Cvar_CompleteCvarName );
- Cmd_AddCommand ("echo",Cmd_Echo_f);
- Cmd_AddCommand ("wait", Cmd_Wait_f);
-}
-
diff --git a/engine/code/qcommon/common.c b/engine/code/qcommon/common.c
deleted file mode 100644
index a225aa3..0000000
--- a/engine/code/qcommon/common.c
+++ /dev/null
@@ -1,3453 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// common.c -- misc functions used in client and server
-
-#include "q_shared.h"
-#include "qcommon.h"
-#include <setjmp.h>
-#ifndef _WIN32
-#include <netinet/in.h>
-#include <sys/stat.h> // umask
-#else
-#include <winsock.h>
-#endif
-
-int demo_protocols[] =
-{ 66, 67, 68, 0 };
-
-#define MAX_NUM_ARGVS 50
-
-#define MIN_DEDICATED_COMHUNKMEGS 1
-#define MIN_COMHUNKMEGS 56
-#define DEF_COMHUNKMEGS 64
-#define DEF_COMZONEMEGS 24
-#define DEF_COMHUNKMEGS_S XSTRING(DEF_COMHUNKMEGS)
-#define DEF_COMZONEMEGS_S XSTRING(DEF_COMZONEMEGS)
-
-int com_argc;
-char *com_argv[MAX_NUM_ARGVS+1];
-
-jmp_buf abortframe; // an ERR_DROP occured, exit the entire frame
-
-
-FILE *debuglogfile;
-static fileHandle_t logfile;
-fileHandle_t com_journalFile; // events are written here
-fileHandle_t com_journalDataFile; // config files are written here
-
-cvar_t *com_speeds;
-cvar_t *com_developer;
-cvar_t *com_dedicated;
-cvar_t *com_timescale;
-cvar_t *com_fixedtime;
-cvar_t *com_dropsim; // 0.0 to 1.0, simulated packet drops
-cvar_t *com_journal;
-cvar_t *com_maxfps;
-cvar_t *com_altivec;
-cvar_t *com_timedemo;
-cvar_t *com_sv_running;
-cvar_t *com_cl_running;
-cvar_t *com_logfile; // 1 = buffer log, 2 = flush after each print
-cvar_t *com_showtrace;
-cvar_t *com_version;
-cvar_t *com_blood;
-cvar_t *com_buildScript; // for automated data building scripts
-cvar_t *com_introPlayed;
-cvar_t *cl_paused;
-cvar_t *sv_paused;
-cvar_t *cl_packetdelay;
-cvar_t *sv_packetdelay;
-cvar_t *com_cameraMode;
-cvar_t *com_ansiColor;
-cvar_t *com_unfocused;
-cvar_t *com_maxfpsUnfocused;
-cvar_t *com_minimized;
-cvar_t *com_maxfpsMinimized;
-cvar_t *com_standalone;
-
-// com_speeds times
-int time_game;
-int time_frontend; // renderer frontend time
-int time_backend; // renderer backend time
-
-int com_frameTime;
-int com_frameMsec;
-int com_frameNumber;
-
-qboolean com_errorEntered = qfalse;
-qboolean com_fullyInitialized = qfalse;
-qboolean com_gameRestarting = qfalse;
-
-char com_errorMessage[MAXPRINTMSG];
-
-void Com_WriteConfig_f( void );
-void CIN_CloseAllVideos( void );
-
-//============================================================================
-
-static char *rd_buffer;
-static int rd_buffersize;
-static void (*rd_flush)( char *buffer );
-
-void Com_BeginRedirect (char *buffer, int buffersize, void (*flush)( char *) )
-{
- if (!buffer || !buffersize || !flush)
- return;
- rd_buffer = buffer;
- rd_buffersize = buffersize;
- rd_flush = flush;
-
- *rd_buffer = 0;
-}
-
-void Com_EndRedirect (void)
-{
- if ( rd_flush ) {
- rd_flush(rd_buffer);
- }
-
- rd_buffer = NULL;
- rd_buffersize = 0;
- rd_flush = NULL;
-}
-
-/*
-=============
-Com_Printf
-
-Both client and server can use this, and it will output
-to the apropriate place.
-
-A raw string should NEVER be passed as fmt, because of "%f" type crashers.
-=============
-*/
-void QDECL Com_Printf( const char *fmt, ... ) {
- va_list argptr;
- char msg[MAXPRINTMSG];
- static qboolean opening_qconsole = qfalse;
-
-
- va_start (argptr,fmt);
- Q_vsnprintf (msg, sizeof(msg), fmt, argptr);
- va_end (argptr);
-
- if ( rd_buffer ) {
- if ((strlen (msg) + strlen(rd_buffer)) > (rd_buffersize - 1)) {
- rd_flush(rd_buffer);
- *rd_buffer = 0;
- }
- Q_strcat(rd_buffer, rd_buffersize, msg);
- // TTimo nooo .. that would defeat the purpose
- //rd_flush(rd_buffer);
- //*rd_buffer = 0;
- return;
- }
-
-#ifndef DEDICATED
- CL_ConsolePrint( msg );
-#endif
-
- // echo to dedicated console and early console
- Sys_Print( msg );
-
- // logfile
- if ( com_logfile && com_logfile->integer ) {
- // TTimo: only open the qconsole.log if the filesystem is in an initialized state
- // also, avoid recursing in the qconsole.log opening (i.e. if fs_debug is on)
- if ( !logfile && FS_Initialized() && !opening_qconsole) {
- struct tm *newtime;
- time_t aclock;
-
- opening_qconsole = qtrue;
-
- time( &aclock );
- newtime = localtime( &aclock );
-
- logfile = FS_FOpenFileWrite( "qconsole.log" );
-
- if(logfile)
- {
- Com_Printf( "logfile opened on %s\n", asctime( newtime ) );
-
- if ( com_logfile->integer > 1 )
- {
- // force it to not buffer so we get valid
- // data even if we are crashing
- FS_ForceFlush(logfile);
- }
- }
- else
- {
- Com_Printf("Opening qconsole.log failed!\n");
- Cvar_SetValue("logfile", 0);
- }
-
- opening_qconsole = qfalse;
- }
- if ( logfile && FS_Initialized()) {
- FS_Write(msg, strlen(msg), logfile);
- }
- }
-}
-
-
-/*
-================
-Com_DPrintf
-
-A Com_Printf that only shows up if the "developer" cvar is set
-================
-*/
-void QDECL Com_DPrintf( const char *fmt, ...) {
- va_list argptr;
- char msg[MAXPRINTMSG];
-
- if ( !com_developer || !com_developer->integer ) {
- return; // don't confuse non-developers with techie stuff...
- }
-
- va_start (argptr,fmt);
- Q_vsnprintf (msg, sizeof(msg), fmt, argptr);
- va_end (argptr);
-
- Com_Printf ("%s", msg);
-}
-
-/*
-=============
-Com_Error
-
-Both client and server can use this, and it will
-do the apropriate things.
-=============
-*/
-void QDECL Com_Error( int code, const char *fmt, ... ) {
- va_list argptr;
- static int lastErrorTime;
- static int errorCount;
- static qboolean calledSysError = qfalse;
- int currentTime;
-
- if(com_errorEntered)
- {
- if(!calledSysError)
- {
- calledSysError = qtrue;
- Sys_Error("recursive error after: %s", com_errorMessage);
- }
-
- return;
- }
-
- com_errorEntered = qtrue;
-
- Cvar_Set("com_errorCode", va("%i", code));
-
- // when we are running automated scripts, make sure we
- // know if anything failed
- if ( com_buildScript && com_buildScript->integer ) {
- code = ERR_FATAL;
- }
-
- // if we are getting a solid stream of ERR_DROP, do an ERR_FATAL
- currentTime = Sys_Milliseconds();
- if ( currentTime - lastErrorTime < 100 ) {
- if ( ++errorCount > 3 ) {
- code = ERR_FATAL;
- }
- } else {
- errorCount = 0;
- }
- lastErrorTime = currentTime;
-
- va_start (argptr,fmt);
- Q_vsnprintf (com_errorMessage, sizeof(com_errorMessage),fmt,argptr);
- va_end (argptr);
-
- if (code != ERR_DISCONNECT && code != ERR_NEED_CD)
- Cvar_Set("com_errorMessage", com_errorMessage);
-
- if (code == ERR_DISCONNECT || code == ERR_SERVERDISCONNECT) {
- SV_Shutdown( "Server disconnected" );
- CL_Disconnect( qtrue );
- VM_Forced_Unload_Start();
- CL_FlushMemory( );
- VM_Forced_Unload_Done();
- // make sure we can get at our local stuff
- FS_PureServerSetLoadedPaks("", "");
- com_errorEntered = qfalse;
- longjmp (abortframe, -1);
- } else if (code == ERR_DROP) {
- Com_Printf ("********************\nERROR: %s\n********************\n", com_errorMessage);
- SV_Shutdown (va("Server crashed: %s", com_errorMessage));
- CL_Disconnect( qtrue );
- VM_Forced_Unload_Start();
- CL_FlushMemory( );
- VM_Forced_Unload_Done();
- FS_PureServerSetLoadedPaks("", "");
- com_errorEntered = qfalse;
- longjmp (abortframe, -1);
- } else if ( code == ERR_NEED_CD ) {
- SV_Shutdown( "Server didn't have CD" );
- if ( com_cl_running && com_cl_running->integer ) {
- CL_Disconnect( qtrue );
- VM_Forced_Unload_Start();
- CL_FlushMemory( );
- VM_Forced_Unload_Done();
- CL_CDDialog();
- } else {
- Com_Printf("Server didn't have CD\n" );
- }
- FS_PureServerSetLoadedPaks("", "");
-
- com_errorEntered = qfalse;
- longjmp (abortframe, -1);
- } else {
- CL_Shutdown ();
- SV_Shutdown (va("Server fatal crashed: %s", com_errorMessage));
- }
-
- Com_Shutdown ();
-
- calledSysError = qtrue;
- Sys_Error ("%s", com_errorMessage);
-}
-
-
-/*
-=============
-Com_Quit_f
-
-Both client and server can use this, and it will
-do the apropriate things.
-=============
-*/
-void Com_Quit_f( void ) {
- // don't try to shutdown if we are in a recursive error
- char *p = Cmd_Args( );
- if ( !com_errorEntered ) {
- SV_Shutdown (p[0] ? p : "Server quit");
- CL_Shutdown ();
- Com_Shutdown ();
- FS_Shutdown(qtrue);
- }
- Sys_Quit ();
-}
-
-
-
-/*
-============================================================================
-
-COMMAND LINE FUNCTIONS
-
-+ characters seperate the commandLine string into multiple console
-command lines.
-
-All of these are valid:
-
-quake3 +set test blah +map test
-quake3 set test blah+map test
-quake3 set test blah + map test
-
-============================================================================
-*/
-
-#define MAX_CONSOLE_LINES 32
-int com_numConsoleLines;
-char *com_consoleLines[MAX_CONSOLE_LINES];
-
-/*
-==================
-Com_ParseCommandLine
-
-Break it up into multiple console lines
-==================
-*/
-void Com_ParseCommandLine( char *commandLine ) {
- int inq = 0;
- com_consoleLines[0] = commandLine;
- com_numConsoleLines = 1;
-
- while ( *commandLine ) {
- if (*commandLine == '"') {
- inq = !inq;
- }
- // look for a + seperating character
- // if commandLine came from a file, we might have real line seperators
- if ( (*commandLine == '+' && !inq) || *commandLine == '\n' || *commandLine == '\r' ) {
- if ( com_numConsoleLines == MAX_CONSOLE_LINES ) {
- return;
- }
- com_consoleLines[com_numConsoleLines] = commandLine + 1;
- com_numConsoleLines++;
- *commandLine = 0;
- }
- commandLine++;
- }
-}
-
-
-/*
-===================
-Com_SafeMode
-
-Check for "safe" on the command line, which will
-skip loading of q3config.cfg
-===================
-*/
-qboolean Com_SafeMode( void ) {
- int i;
-
- for ( i = 0 ; i < com_numConsoleLines ; i++ ) {
- Cmd_TokenizeString( com_consoleLines[i] );
- if ( !Q_stricmp( Cmd_Argv(0), "safe" )
- || !Q_stricmp( Cmd_Argv(0), "cvar_restart" ) ) {
- com_consoleLines[i][0] = 0;
- return qtrue;
- }
- }
- return qfalse;
-}
-
-
-/*
-===============
-Com_StartupVariable
-
-Searches for command line parameters that are set commands.
-If match is not NULL, only that cvar will be looked for.
-That is necessary because cddir and basedir need to be set
-before the filesystem is started, but all other sets should
-be after execing the config and default.
-===============
-*/
-void Com_StartupVariable( const char *match ) {
- int i;
- char *s;
- cvar_t *cv;
-
- for (i=0 ; i < com_numConsoleLines ; i++) {
- Cmd_TokenizeString( com_consoleLines[i] );
- if ( strcmp( Cmd_Argv(0), "set" ) ) {
- continue;
- }
-
- s = Cmd_Argv(1);
- if ( !match || !strcmp( s, match ) ) {
- Cvar_Set( s, Cmd_Argv(2) );
- cv = Cvar_Get( s, "", 0 );
- cv->flags |= CVAR_USER_CREATED;
-// com_consoleLines[i] = 0;
- }
- }
-}
-
-
-/*
-=================
-Com_AddStartupCommands
-
-Adds command line parameters as script statements
-Commands are seperated by + signs
-
-Returns qtrue if any late commands were added, which
-will keep the demoloop from immediately starting
-=================
-*/
-qboolean Com_AddStartupCommands( void ) {
- int i;
- qboolean added;
-
- added = qfalse;
- // quote every token, so args with semicolons can work
- for (i=0 ; i < com_numConsoleLines ; i++) {
- if ( !com_consoleLines[i] || !com_consoleLines[i][0] ) {
- continue;
- }
-
- // set commands already added with Com_StartupVariable
- if ( !Q_stricmpn( com_consoleLines[i], "set", 3 ) ) {
- continue;
- }
-
- added = qtrue;
- Cbuf_AddText( com_consoleLines[i] );
- Cbuf_AddText( "\n" );
- }
-
- return added;
-}
-
-
-//============================================================================
-
-void Info_Print( const char *s ) {
- char key[512];
- char value[512];
- char *o;
- int l;
-
- if (*s == '\\')
- s++;
- while (*s)
- {
- o = key;
- while (*s && *s != '\\')
- *o++ = *s++;
-
- l = o - key;
- if (l < 20)
- {
- Com_Memset (o, ' ', 20-l);
- key[20] = 0;
- }
- else
- *o = 0;
- Com_Printf ("%s", key);
-
- if (!*s)
- {
- Com_Printf ("MISSING VALUE\n");
- return;
- }
-
- o = value;
- s++;
- while (*s && *s != '\\')
- *o++ = *s++;
- *o = 0;
-
- if (*s)
- s++;
- Com_Printf ("%s\n", value);
- }
-}
-
-/*
-============
-Com_StringContains
-============
-*/
-char *Com_StringContains(char *str1, char *str2, int casesensitive) {
- int len, i, j;
-
- len = strlen(str1) - strlen(str2);
- for (i = 0; i <= len; i++, str1++) {
- for (j = 0; str2[j]; j++) {
- if (casesensitive) {
- if (str1[j] != str2[j]) {
- break;
- }
- }
- else {
- if (toupper(str1[j]) != toupper(str2[j])) {
- break;
- }
- }
- }
- if (!str2[j]) {
- return str1;
- }
- }
- return NULL;
-}
-
-/*
-============
-Com_Filter
-============
-*/
-int Com_Filter(char *filter, char *name, int casesensitive)
-{
- char buf[MAX_TOKEN_CHARS];
- char *ptr;
- int i, found;
-
- while(*filter) {
- if (*filter == '*') {
- filter++;
- for (i = 0; *filter; i++) {
- if (*filter == '*' || *filter == '?') break;
- buf[i] = *filter;
- filter++;
- }
- buf[i] = '\0';
- if (strlen(buf)) {
- ptr = Com_StringContains(name, buf, casesensitive);
- if (!ptr) return qfalse;
- name = ptr + strlen(buf);
- }
- }
- else if (*filter == '?') {
- filter++;
- name++;
- }
- else if (*filter == '[' && *(filter+1) == '[') {
- filter++;
- }
- else if (*filter == '[') {
- filter++;
- found = qfalse;
- while(*filter && !found) {
- if (*filter == ']' && *(filter+1) != ']') break;
- if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) {
- if (casesensitive) {
- if (*name >= *filter && *name <= *(filter+2)) found = qtrue;
- }
- else {
- if (toupper(*name) >= toupper(*filter) &&
- toupper(*name) <= toupper(*(filter+2))) found = qtrue;
- }
- filter += 3;
- }
- else {
- if (casesensitive) {
- if (*filter == *name) found = qtrue;
- }
- else {
- if (toupper(*filter) == toupper(*name)) found = qtrue;
- }
- filter++;
- }
- }
- if (!found) return qfalse;
- while(*filter) {
- if (*filter == ']' && *(filter+1) != ']') break;
- filter++;
- }
- filter++;
- name++;
- }
- else {
- if (casesensitive) {
- if (*filter != *name) return qfalse;
- }
- else {
- if (toupper(*filter) != toupper(*name)) return qfalse;
- }
- filter++;
- name++;
- }
- }
- return qtrue;
-}
-
-/*
-============
-Com_FilterPath
-============
-*/
-int Com_FilterPath(char *filter, char *name, int casesensitive)
-{
- int i;
- char new_filter[MAX_QPATH];
- char new_name[MAX_QPATH];
-
- for (i = 0; i < MAX_QPATH-1 && filter[i]; i++) {
- if ( filter[i] == '\\' || filter[i] == ':' ) {
- new_filter[i] = '/';
- }
- else {
- new_filter[i] = filter[i];
- }
- }
- new_filter[i] = '\0';
- for (i = 0; i < MAX_QPATH-1 && name[i]; i++) {
- if ( name[i] == '\\' || name[i] == ':' ) {
- new_name[i] = '/';
- }
- else {
- new_name[i] = name[i];
- }
- }
- new_name[i] = '\0';
- return Com_Filter(new_filter, new_name, casesensitive);
-}
-
-/*
-================
-Com_RealTime
-================
-*/
-int Com_RealTime(qtime_t *qtime) {
- time_t t;
- struct tm *tms;
-
- t = time(NULL);
- if (!qtime)
- return t;
- tms = localtime(&t);
- if (tms) {
- qtime->tm_sec = tms->tm_sec;
- qtime->tm_min = tms->tm_min;
- qtime->tm_hour = tms->tm_hour;
- qtime->tm_mday = tms->tm_mday;
- qtime->tm_mon = tms->tm_mon;
- qtime->tm_year = tms->tm_year;
- qtime->tm_wday = tms->tm_wday;
- qtime->tm_yday = tms->tm_yday;
- qtime->tm_isdst = tms->tm_isdst;
- }
- return t;
-}
-
-
-/*
-==============================================================================
-
- ZONE MEMORY ALLOCATION
-
-There is never any space between memblocks, and there will never be two
-contiguous free memblocks.
-
-The rover can be left pointing at a non-empty block
-
-The zone calls are pretty much only used for small strings and structures,
-all big things are allocated on the hunk.
-==============================================================================
-*/
-
-#define ZONEID 0x1d4a11
-#define MINFRAGMENT 64
-
-typedef struct zonedebug_s {
- char *label;
- char *file;
- int line;
- int allocSize;
-} zonedebug_t;
-
-typedef struct memblock_s {
- int size; // including the header and possibly tiny fragments
- int tag; // a tag of 0 is a free block
- struct memblock_s *next, *prev;
- int id; // should be ZONEID
-#ifdef ZONE_DEBUG
- zonedebug_t d;
-#endif
-} memblock_t;
-
-typedef struct {
- int size; // total bytes malloced, including header
- int used; // total bytes used
- memblock_t blocklist; // start / end cap for linked list
- memblock_t *rover;
-} memzone_t;
-
-// main zone for all "dynamic" memory allocation
-memzone_t *mainzone;
-// we also have a small zone for small allocations that would only
-// fragment the main zone (think of cvar and cmd strings)
-memzone_t *smallzone;
-
-void Z_CheckHeap( void );
-
-/*
-========================
-Z_ClearZone
-========================
-*/
-void Z_ClearZone( memzone_t *zone, int size ) {
- memblock_t *block;
-
- // set the entire zone to one free block
-
- zone->blocklist.next = zone->blocklist.prev = block =
- (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
- zone->blocklist.tag = 1; // in use block
- zone->blocklist.id = 0;
- zone->blocklist.size = 0;
- zone->rover = block;
- zone->size = size;
- zone->used = 0;
-
- block->prev = block->next = &zone->blocklist;
- block->tag = 0; // free block
- block->id = ZONEID;
- block->size = size - sizeof(memzone_t);
-}
-
-/*
-========================
-Z_AvailableZoneMemory
-========================
-*/
-int Z_AvailableZoneMemory( memzone_t *zone ) {
- return zone->size - zone->used;
-}
-
-/*
-========================
-Z_AvailableMemory
-========================
-*/
-int Z_AvailableMemory( void ) {
- return Z_AvailableZoneMemory( mainzone );
-}
-
-/*
-========================
-Z_Free
-========================
-*/
-void Z_Free( void *ptr ) {
- memblock_t *block, *other;
- memzone_t *zone;
-
- if (!ptr) {
- Com_Error( ERR_DROP, "Z_Free: NULL pointer" );
- }
-
- block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
- if (block->id != ZONEID) {
- Com_Error( ERR_FATAL, "Z_Free: freed a pointer without ZONEID" );
- }
- if (block->tag == 0) {
- Com_Error( ERR_FATAL, "Z_Free: freed a freed pointer" );
- }
- // if static memory
- if (block->tag == TAG_STATIC) {
- return;
- }
-
- // check the memory trash tester
- if ( *(int *)((byte *)block + block->size - 4 ) != ZONEID ) {
- Com_Error( ERR_FATAL, "Z_Free: memory block wrote past end" );
- }
-
- if (block->tag == TAG_SMALL) {
- zone = smallzone;
- }
- else {
- zone = mainzone;
- }
-
- zone->used -= block->size;
- // set the block to something that should cause problems
- // if it is referenced...
- Com_Memset( ptr, 0xaa, block->size - sizeof( *block ) );
-
- block->tag = 0; // mark as free
-
- other = block->prev;
- if (!other->tag) {
- // merge with previous free block
- other->size += block->size;
- other->next = block->next;
- other->next->prev = other;
- if (block == zone->rover) {
- zone->rover = other;
- }
- block = other;
- }
-
- zone->rover = block;
-
- other = block->next;
- if ( !other->tag ) {
- // merge the next free block onto the end
- block->size += other->size;
- block->next = other->next;
- block->next->prev = block;
- if (other == zone->rover) {
- zone->rover = block;
- }
- }
-}
-
-
-/*
-================
-Z_FreeTags
-================
-*/
-void Z_FreeTags( int tag ) {
- int count;
- memzone_t *zone;
-
- if ( tag == TAG_SMALL ) {
- zone = smallzone;
- }
- else {
- zone = mainzone;
- }
- count = 0;
- // use the rover as our pointer, because
- // Z_Free automatically adjusts it
- zone->rover = zone->blocklist.next;
- do {
- if ( zone->rover->tag == tag ) {
- count++;
- Z_Free( (void *)(zone->rover + 1) );
- continue;
- }
- zone->rover = zone->rover->next;
- } while ( zone->rover != &zone->blocklist );
-}
-
-
-/*
-================
-Z_TagMalloc
-================
-*/
-#ifdef ZONE_DEBUG
-void *Z_TagMallocDebug( int size, int tag, char *label, char *file, int line ) {
-#else
-void *Z_TagMalloc( int size, int tag ) {
-#endif
- int extra, allocSize;
- memblock_t *start, *rover, *new, *base;
- memzone_t *zone;
-
- if (!tag) {
- Com_Error( ERR_FATAL, "Z_TagMalloc: tried to use a 0 tag" );
- }
-
- if ( tag == TAG_SMALL ) {
- zone = smallzone;
- }
- else {
- zone = mainzone;
- }
-
- allocSize = size;
- //
- // scan through the block list looking for the first free block
- // of sufficient size
- //
- size += sizeof(memblock_t); // account for size of block header
- size += 4; // space for memory trash tester
- size = PAD(size, sizeof(intptr_t)); // align to 32/64 bit boundary
-
- base = rover = zone->rover;
- start = base->prev;
-
- do {
- if (rover == start) {
-#ifdef ZONE_DEBUG
- Z_LogHeap();
-#endif
- // scaned all the way around the list
- Com_Error( ERR_FATAL, "Z_Malloc: failed on allocation of %i bytes from the %s zone",
- size, zone == smallzone ? "small" : "main");
- return NULL;
- }
- if (rover->tag) {
- base = rover = rover->next;
- } else {
- rover = rover->next;
- }
- } while (base->tag || base->size < size);
-
- //
- // found a block big enough
- //
- extra = base->size - size;
- if (extra > MINFRAGMENT) {
- // there will be a free fragment after the allocated block
- new = (memblock_t *) ((byte *)base + size );
- new->size = extra;
- new->tag = 0; // free block
- new->prev = base;
- new->id = ZONEID;
- new->next = base->next;
- new->next->prev = new;
- base->next = new;
- base->size = size;
- }
-
- base->tag = tag; // no longer a free block
-
- zone->rover = base->next; // next allocation will start looking here
- zone->used += base->size; //
-
- base->id = ZONEID;
-
-#ifdef ZONE_DEBUG
- base->d.label = label;
- base->d.file = file;
- base->d.line = line;
- base->d.allocSize = allocSize;
-#endif
-
- // marker for memory trash testing
- *(int *)((byte *)base + base->size - 4) = ZONEID;
-
- return (void *) ((byte *)base + sizeof(memblock_t));
-}
-
-/*
-========================
-Z_Malloc
-========================
-*/
-#ifdef ZONE_DEBUG
-void *Z_MallocDebug( int size, char *label, char *file, int line ) {
-#else
-void *Z_Malloc( int size ) {
-#endif
- void *buf;
-
- //Z_CheckHeap (); // DEBUG
-
-#ifdef ZONE_DEBUG
- buf = Z_TagMallocDebug( size, TAG_GENERAL, label, file, line );
-#else
- buf = Z_TagMalloc( size, TAG_GENERAL );
-#endif
- Com_Memset( buf, 0, size );
-
- return buf;
-}
-
-#ifdef ZONE_DEBUG
-void *S_MallocDebug( int size, char *label, char *file, int line ) {
- return Z_TagMallocDebug( size, TAG_SMALL, label, file, line );
-}
-#else
-void *S_Malloc( int size ) {
- return Z_TagMalloc( size, TAG_SMALL );
-}
-#endif
-
-/*
-========================
-Z_CheckHeap
-========================
-*/
-void Z_CheckHeap( void ) {
- memblock_t *block;
-
- for (block = mainzone->blocklist.next ; ; block = block->next) {
- if (block->next == &mainzone->blocklist) {
- break; // all blocks have been hit
- }
- if ( (byte *)block + block->size != (byte *)block->next)
- Com_Error( ERR_FATAL, "Z_CheckHeap: block size does not touch the next block\n" );
- if ( block->next->prev != block) {
- Com_Error( ERR_FATAL, "Z_CheckHeap: next block doesn't have proper back link\n" );
- }
- if ( !block->tag && !block->next->tag ) {
- Com_Error( ERR_FATAL, "Z_CheckHeap: two consecutive free blocks\n" );
- }
- }
-}
-
-/*
-========================
-Z_LogZoneHeap
-========================
-*/
-void Z_LogZoneHeap( memzone_t *zone, char *name ) {
-#ifdef ZONE_DEBUG
- char dump[32], *ptr;
- int i, j;
-#endif
- memblock_t *block;
- char buf[4096];
- int size, allocSize, numBlocks;
-
- if (!logfile || !FS_Initialized())
- return;
- size = allocSize = numBlocks = 0;
- Com_sprintf(buf, sizeof(buf), "\r\n================\r\n%s log\r\n================\r\n", name);
- FS_Write(buf, strlen(buf), logfile);
- for (block = zone->blocklist.next ; block->next != &zone->blocklist; block = block->next) {
- if (block->tag) {
-#ifdef ZONE_DEBUG
- ptr = ((char *) block) + sizeof(memblock_t);
- j = 0;
- for (i = 0; i < 20 && i < block->d.allocSize; i++) {
- if (ptr[i] >= 32 && ptr[i] < 127) {
- dump[j++] = ptr[i];
- }
- else {
- dump[j++] = '_';
- }
- }
- dump[j] = '\0';
- Com_sprintf(buf, sizeof(buf), "size = %8d: %s, line: %d (%s) [%s]\r\n", block->d.allocSize, block->d.file, block->d.line, block->d.label, dump);
- FS_Write(buf, strlen(buf), logfile);
- allocSize += block->d.allocSize;
-#endif
- size += block->size;
- numBlocks++;
- }
- }
-#ifdef ZONE_DEBUG
- // subtract debug memory
- size -= numBlocks * sizeof(zonedebug_t);
-#else
- allocSize = numBlocks * sizeof(memblock_t); // + 32 bit alignment
-#endif
- Com_sprintf(buf, sizeof(buf), "%d %s memory in %d blocks\r\n", size, name, numBlocks);
- FS_Write(buf, strlen(buf), logfile);
- Com_sprintf(buf, sizeof(buf), "%d %s memory overhead\r\n", size - allocSize, name);
- FS_Write(buf, strlen(buf), logfile);
-}
-
-/*
-========================
-Z_LogHeap
-========================
-*/
-void Z_LogHeap( void ) {
- Z_LogZoneHeap( mainzone, "MAIN" );
- Z_LogZoneHeap( smallzone, "SMALL" );
-}
-
-// static mem blocks to reduce a lot of small zone overhead
-typedef struct memstatic_s {
- memblock_t b;
- byte mem[2];
-} memstatic_t;
-
-memstatic_t emptystring =
- { {(sizeof(memblock_t)+2 + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'\0', '\0'} };
-memstatic_t numberstring[] = {
- { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'0', '\0'} },
- { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'1', '\0'} },
- { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'2', '\0'} },
- { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'3', '\0'} },
- { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'4', '\0'} },
- { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'5', '\0'} },
- { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'6', '\0'} },
- { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'7', '\0'} },
- { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'8', '\0'} },
- { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'9', '\0'} }
-};
-
-/*
-========================
-CopyString
-
- NOTE: never write over the memory CopyString returns because
- memory from a memstatic_t might be returned
-========================
-*/
-char *CopyString( const char *in ) {
- char *out;
-
- if (!in[0]) {
- return ((char *)&emptystring) + sizeof(memblock_t);
- }
- else if (!in[1]) {
- if (in[0] >= '0' && in[0] <= '9') {
- return ((char *)&numberstring[in[0]-'0']) + sizeof(memblock_t);
- }
- }
- out = S_Malloc (strlen(in)+1);
- strcpy (out, in);
- return out;
-}
-
-/*
-==============================================================================
-
-Goals:
- reproducable without history effects -- no out of memory errors on weird map to map changes
- allow restarting of the client without fragmentation
- minimize total pages in use at run time
- minimize total pages needed during load time
-
- Single block of memory with stack allocators coming from both ends towards the middle.
-
- One side is designated the temporary memory allocator.
-
- Temporary memory can be allocated and freed in any order.
-
- A highwater mark is kept of the most in use at any time.
-
- When there is no temporary memory allocated, the permanent and temp sides
- can be switched, allowing the already touched temp memory to be used for
- permanent storage.
-
- Temp memory must never be allocated on two ends at once, or fragmentation
- could occur.
-
- If we have any in-use temp memory, additional temp allocations must come from
- that side.
-
- If not, we can choose to make either side the new temp side and push future
- permanent allocations to the other side. Permanent allocations should be
- kept on the side that has the current greatest wasted highwater mark.
-
-==============================================================================
-*/
-
-
-#define HUNK_MAGIC 0x89537892
-#define HUNK_FREE_MAGIC 0x89537893
-
-typedef struct {
- int magic;
- int size;
-} hunkHeader_t;
-
-typedef struct {
- int mark;
- int permanent;
- int temp;
- int tempHighwater;
-} hunkUsed_t;
-
-typedef struct hunkblock_s {
- int size;
- byte printed;
- struct hunkblock_s *next;
- char *label;
- char *file;
- int line;
-} hunkblock_t;
-
-static hunkblock_t *hunkblocks;
-
-static hunkUsed_t hunk_low, hunk_high;
-static hunkUsed_t *hunk_permanent, *hunk_temp;
-
-static byte *s_hunkData = NULL;
-static int s_hunkTotal;
-
-static int s_zoneTotal;
-static int s_smallZoneTotal;
-
-
-/*
-=================
-Com_Meminfo_f
-=================
-*/
-void Com_Meminfo_f( void ) {
- memblock_t *block;
- int zoneBytes, zoneBlocks;
- int smallZoneBytes, smallZoneBlocks;
- int botlibBytes, rendererBytes;
- int unused;
-
- zoneBytes = 0;
- botlibBytes = 0;
- rendererBytes = 0;
- zoneBlocks = 0;
- for (block = mainzone->blocklist.next ; ; block = block->next) {
- if ( Cmd_Argc() != 1 ) {
- Com_Printf ("block:%p size:%7i tag:%3i\n",
- (void *)block, block->size, block->tag);
- }
- if ( block->tag ) {
- zoneBytes += block->size;
- zoneBlocks++;
- if ( block->tag == TAG_BOTLIB ) {
- botlibBytes += block->size;
- } else if ( block->tag == TAG_RENDERER ) {
- rendererBytes += block->size;
- }
- }
-
- if (block->next == &mainzone->blocklist) {
- break; // all blocks have been hit
- }
- if ( (byte *)block + block->size != (byte *)block->next) {
- Com_Printf ("ERROR: block size does not touch the next block\n");
- }
- if ( block->next->prev != block) {
- Com_Printf ("ERROR: next block doesn't have proper back link\n");
- }
- if ( !block->tag && !block->next->tag ) {
- Com_Printf ("ERROR: two consecutive free blocks\n");
- }
- }
-
- smallZoneBytes = 0;
- smallZoneBlocks = 0;
- for (block = smallzone->blocklist.next ; ; block = block->next) {
- if ( block->tag ) {
- smallZoneBytes += block->size;
- smallZoneBlocks++;
- }
-
- if (block->next == &smallzone->blocklist) {
- break; // all blocks have been hit
- }
- }
-
- Com_Printf( "%8i bytes total hunk\n", s_hunkTotal );
- Com_Printf( "%8i bytes total zone\n", s_zoneTotal );
- Com_Printf( "\n" );
- Com_Printf( "%8i low mark\n", hunk_low.mark );
- Com_Printf( "%8i low permanent\n", hunk_low.permanent );
- if ( hunk_low.temp != hunk_low.permanent ) {
- Com_Printf( "%8i low temp\n", hunk_low.temp );
- }
- Com_Printf( "%8i low tempHighwater\n", hunk_low.tempHighwater );
- Com_Printf( "\n" );
- Com_Printf( "%8i high mark\n", hunk_high.mark );
- Com_Printf( "%8i high permanent\n", hunk_high.permanent );
- if ( hunk_high.temp != hunk_high.permanent ) {
- Com_Printf( "%8i high temp\n", hunk_high.temp );
- }
- Com_Printf( "%8i high tempHighwater\n", hunk_high.tempHighwater );
- Com_Printf( "\n" );
- Com_Printf( "%8i total hunk in use\n", hunk_low.permanent + hunk_high.permanent );
- unused = 0;
- if ( hunk_low.tempHighwater > hunk_low.permanent ) {
- unused += hunk_low.tempHighwater - hunk_low.permanent;
- }
- if ( hunk_high.tempHighwater > hunk_high.permanent ) {
- unused += hunk_high.tempHighwater - hunk_high.permanent;
- }
- Com_Printf( "%8i unused highwater\n", unused );
- Com_Printf( "\n" );
- Com_Printf( "%8i bytes in %i zone blocks\n", zoneBytes, zoneBlocks );
- Com_Printf( " %8i bytes in dynamic botlib\n", botlibBytes );
- Com_Printf( " %8i bytes in dynamic renderer\n", rendererBytes );
- Com_Printf( " %8i bytes in dynamic other\n", zoneBytes - ( botlibBytes + rendererBytes ) );
- Com_Printf( " %8i bytes in small Zone memory\n", smallZoneBytes );
-}
-
-/*
-===============
-Com_TouchMemory
-
-Touch all known used data to make sure it is paged in
-===============
-*/
-void Com_TouchMemory( void ) {
- int start, end;
- int i, j;
- int sum;
- memblock_t *block;
-
- Z_CheckHeap();
-
- start = Sys_Milliseconds();
-
- sum = 0;
-
- j = hunk_low.permanent >> 2;
- for ( i = 0 ; i < j ; i+=64 ) { // only need to touch each page
- sum += ((int *)s_hunkData)[i];
- }
-
- i = ( s_hunkTotal - hunk_high.permanent ) >> 2;
- j = hunk_high.permanent >> 2;
- for ( ; i < j ; i+=64 ) { // only need to touch each page
- sum += ((int *)s_hunkData)[i];
- }
-
- for (block = mainzone->blocklist.next ; ; block = block->next) {
- if ( block->tag ) {
- j = block->size >> 2;
- for ( i = 0 ; i < j ; i+=64 ) { // only need to touch each page
- sum += ((int *)block)[i];
- }
- }
- if ( block->next == &mainzone->blocklist ) {
- break; // all blocks have been hit
- }
- }
-
- end = Sys_Milliseconds();
-
- Com_Printf( "Com_TouchMemory: %i msec\n", end - start );
-}
-
-
-
-/*
-=================
-Com_InitZoneMemory
-=================
-*/
-void Com_InitSmallZoneMemory( void ) {
- s_smallZoneTotal = 512 * 1024;
- smallzone = calloc( s_smallZoneTotal, 1 );
- if ( !smallzone ) {
- Com_Error( ERR_FATAL, "Small zone data failed to allocate %1.1f megs", (float)s_smallZoneTotal / (1024*1024) );
- }
- Z_ClearZone( smallzone, s_smallZoneTotal );
-
- return;
-}
-
-void Com_InitZoneMemory( void ) {
- cvar_t *cv;
-
- // Please note: com_zoneMegs can only be set on the command line, and
- // not in q3config.cfg or Com_StartupVariable, as they haven't been
- // executed by this point. It's a chicken and egg problem. We need the
- // memory manager configured to handle those places where you would
- // configure the memory manager.
-
- // allocate the random block zone
- cv = Cvar_Get( "com_zoneMegs", DEF_COMZONEMEGS_S, CVAR_LATCH | CVAR_ARCHIVE );
-
- if ( cv->integer < DEF_COMZONEMEGS ) {
- s_zoneTotal = 1024 * 1024 * DEF_COMZONEMEGS;
- } else {
- s_zoneTotal = cv->integer * 1024 * 1024;
- }
-
- mainzone = calloc( s_zoneTotal, 1 );
- if ( !mainzone ) {
- Com_Error( ERR_FATAL, "Zone data failed to allocate %i megs", s_zoneTotal / (1024*1024) );
- }
- Z_ClearZone( mainzone, s_zoneTotal );
-
-}
-
-/*
-=================
-Hunk_Log
-=================
-*/
-void Hunk_Log( void) {
- hunkblock_t *block;
- char buf[4096];
- int size, numBlocks;
-
- if (!logfile || !FS_Initialized())
- return;
- size = 0;
- numBlocks = 0;
- Com_sprintf(buf, sizeof(buf), "\r\n================\r\nHunk log\r\n================\r\n");
- FS_Write(buf, strlen(buf), logfile);
- for (block = hunkblocks ; block; block = block->next) {
-#ifdef HUNK_DEBUG
- Com_sprintf(buf, sizeof(buf), "size = %8d: %s, line: %d (%s)\r\n", block->size, block->file, block->line, block->label);
- FS_Write(buf, strlen(buf), logfile);
-#endif
- size += block->size;
- numBlocks++;
- }
- Com_sprintf(buf, sizeof(buf), "%d Hunk memory\r\n", size);
- FS_Write(buf, strlen(buf), logfile);
- Com_sprintf(buf, sizeof(buf), "%d hunk blocks\r\n", numBlocks);
- FS_Write(buf, strlen(buf), logfile);
-}
-
-/*
-=================
-Hunk_SmallLog
-=================
-*/
-void Hunk_SmallLog( void) {
- hunkblock_t *block, *block2;
- char buf[4096];
- int size, locsize, numBlocks;
-
- if (!logfile || !FS_Initialized())
- return;
- for (block = hunkblocks ; block; block = block->next) {
- block->printed = qfalse;
- }
- size = 0;
- numBlocks = 0;
- Com_sprintf(buf, sizeof(buf), "\r\n================\r\nHunk Small log\r\n================\r\n");
- FS_Write(buf, strlen(buf), logfile);
- for (block = hunkblocks; block; block = block->next) {
- if (block->printed) {
- continue;
- }
- locsize = block->size;
- for (block2 = block->next; block2; block2 = block2->next) {
- if (block->line != block2->line) {
- continue;
- }
- if (Q_stricmp(block->file, block2->file)) {
- continue;
- }
- size += block2->size;
- locsize += block2->size;
- block2->printed = qtrue;
- }
-#ifdef HUNK_DEBUG
- Com_sprintf(buf, sizeof(buf), "size = %8d: %s, line: %d (%s)\r\n", locsize, block->file, block->line, block->label);
- FS_Write(buf, strlen(buf), logfile);
-#endif
- size += block->size;
- numBlocks++;
- }
- Com_sprintf(buf, sizeof(buf), "%d Hunk memory\r\n", size);
- FS_Write(buf, strlen(buf), logfile);
- Com_sprintf(buf, sizeof(buf), "%d hunk blocks\r\n", numBlocks);
- FS_Write(buf, strlen(buf), logfile);
-}
-
-/*
-=================
-Com_InitZoneMemory
-=================
-*/
-void Com_InitHunkMemory( void ) {
- cvar_t *cv;
- int nMinAlloc;
- char *pMsg = NULL;
-
- // make sure the file system has allocated and "not" freed any temp blocks
- // this allows the config and product id files ( journal files too ) to be loaded
- // by the file system without redunant routines in the file system utilizing different
- // memory systems
- if (FS_LoadStack() != 0) {
- Com_Error( ERR_FATAL, "Hunk initialization failed. File system load stack not zero");
- }
-
- // allocate the stack based hunk allocator
- cv = Cvar_Get( "com_hunkMegs", DEF_COMHUNKMEGS_S, CVAR_LATCH | CVAR_ARCHIVE );
-
- // if we are not dedicated min allocation is 56, otherwise min is 1
- if (com_dedicated && com_dedicated->integer) {
- nMinAlloc = MIN_DEDICATED_COMHUNKMEGS;
- pMsg = "Minimum com_hunkMegs for a dedicated server is %i, allocating %i megs.\n";
- }
- else {
- nMinAlloc = MIN_COMHUNKMEGS;
- pMsg = "Minimum com_hunkMegs is %i, allocating %i megs.\n";
- }
-
- if ( cv->integer < nMinAlloc ) {
- s_hunkTotal = 1024 * 1024 * nMinAlloc;
- Com_Printf(pMsg, nMinAlloc, s_hunkTotal / (1024 * 1024));
- } else {
- s_hunkTotal = cv->integer * 1024 * 1024;
- }
-
- s_hunkData = calloc( s_hunkTotal + 31, 1 );
- if ( !s_hunkData ) {
- Com_Error( ERR_FATAL, "Hunk data failed to allocate %i megs", s_hunkTotal / (1024*1024) );
- }
- // cacheline align
- s_hunkData = (byte *) ( ( (intptr_t)s_hunkData + 31 ) & ~31 );
- Hunk_Clear();
-
- Cmd_AddCommand( "meminfo", Com_Meminfo_f );
-#ifdef ZONE_DEBUG
- Cmd_AddCommand( "zonelog", Z_LogHeap );
-#endif
-#ifdef HUNK_DEBUG
- Cmd_AddCommand( "hunklog", Hunk_Log );
- Cmd_AddCommand( "hunksmalllog", Hunk_SmallLog );
-#endif
-}
-
-/*
-====================
-Hunk_MemoryRemaining
-====================
-*/
-int Hunk_MemoryRemaining( void ) {
- int low, high;
-
- low = hunk_low.permanent > hunk_low.temp ? hunk_low.permanent : hunk_low.temp;
- high = hunk_high.permanent > hunk_high.temp ? hunk_high.permanent : hunk_high.temp;
-
- return s_hunkTotal - ( low + high );
-}
-
-/*
-===================
-Hunk_SetMark
-
-The server calls this after the level and game VM have been loaded
-===================
-*/
-void Hunk_SetMark( void ) {
- hunk_low.mark = hunk_low.permanent;
- hunk_high.mark = hunk_high.permanent;
-}
-
-/*
-=================
-Hunk_ClearToMark
-
-The client calls this before starting a vid_restart or snd_restart
-=================
-*/
-void Hunk_ClearToMark( void ) {
- hunk_low.permanent = hunk_low.temp = hunk_low.mark;
- hunk_high.permanent = hunk_high.temp = hunk_high.mark;
-}
-
-/*
-=================
-Hunk_CheckMark
-=================
-*/
-qboolean Hunk_CheckMark( void ) {
- if( hunk_low.mark || hunk_high.mark ) {
- return qtrue;
- }
- return qfalse;
-}
-
-void CL_ShutdownCGame( void );
-void CL_ShutdownUI( void );
-void SV_ShutdownGameProgs( void );
-
-/*
-=================
-Hunk_Clear
-
-The server calls this before shutting down or loading a new map
-=================
-*/
-void Hunk_Clear( void ) {
-
-#ifndef DEDICATED
- CL_ShutdownCGame();
- CL_ShutdownUI();
-#endif
- SV_ShutdownGameProgs();
-#ifndef DEDICATED
- CIN_CloseAllVideos();
-#endif
- hunk_low.mark = 0;
- hunk_low.permanent = 0;
- hunk_low.temp = 0;
- hunk_low.tempHighwater = 0;
-
- hunk_high.mark = 0;
- hunk_high.permanent = 0;
- hunk_high.temp = 0;
- hunk_high.tempHighwater = 0;
-
- hunk_permanent = &hunk_low;
- hunk_temp = &hunk_high;
-
- Com_Printf( "Hunk_Clear: reset the hunk ok\n" );
- VM_Clear();
-#ifdef HUNK_DEBUG
- hunkblocks = NULL;
-#endif
-}
-
-static void Hunk_SwapBanks( void ) {
- hunkUsed_t *swap;
-
- // can't swap banks if there is any temp already allocated
- if ( hunk_temp->temp != hunk_temp->permanent ) {
- return;
- }
-
- // if we have a larger highwater mark on this side, start making
- // our permanent allocations here and use the other side for temp
- if ( hunk_temp->tempHighwater - hunk_temp->permanent >
- hunk_permanent->tempHighwater - hunk_permanent->permanent ) {
- swap = hunk_temp;
- hunk_temp = hunk_permanent;
- hunk_permanent = swap;
- }
-}
-
-/*
-=================
-Hunk_Alloc
-
-Allocate permanent (until the hunk is cleared) memory
-=================
-*/
-#ifdef HUNK_DEBUG
-void *Hunk_AllocDebug( int size, ha_pref preference, char *label, char *file, int line ) {
-#else
-void *Hunk_Alloc( int size, ha_pref preference ) {
-#endif
- void *buf;
-
- if ( s_hunkData == NULL)
- {
- Com_Error( ERR_FATAL, "Hunk_Alloc: Hunk memory system not initialized" );
- }
-
- // can't do preference if there is any temp allocated
- if (preference == h_dontcare || hunk_temp->temp != hunk_temp->permanent) {
- Hunk_SwapBanks();
- } else {
- if (preference == h_low && hunk_permanent != &hunk_low) {
- Hunk_SwapBanks();
- } else if (preference == h_high && hunk_permanent != &hunk_high) {
- Hunk_SwapBanks();
- }
- }
-
-#ifdef HUNK_DEBUG
- size += sizeof(hunkblock_t);
-#endif
-
- // round to cacheline
- size = (size+31)&~31;
-
- if ( hunk_low.temp + hunk_high.temp + size > s_hunkTotal ) {
-#ifdef HUNK_DEBUG
- Hunk_Log();
- Hunk_SmallLog();
-#endif
- Com_Error( ERR_DROP, "Hunk_Alloc failed on %i", size );
- }
-
- if ( hunk_permanent == &hunk_low ) {
- buf = (void *)(s_hunkData + hunk_permanent->permanent);
- hunk_permanent->permanent += size;
- } else {
- hunk_permanent->permanent += size;
- buf = (void *)(s_hunkData + s_hunkTotal - hunk_permanent->permanent );
- }
-
- hunk_permanent->temp = hunk_permanent->permanent;
-
- Com_Memset( buf, 0, size );
-
-#ifdef HUNK_DEBUG
- {
- hunkblock_t *block;
-
- block = (hunkblock_t *) buf;
- block->size = size - sizeof(hunkblock_t);
- block->file = file;
- block->label = label;
- block->line = line;
- block->next = hunkblocks;
- hunkblocks = block;
- buf = ((byte *) buf) + sizeof(hunkblock_t);
- }
-#endif
- return buf;
-}
-
-/*
-=================
-Hunk_AllocateTempMemory
-
-This is used by the file loading system.
-Multiple files can be loaded in temporary memory.
-When the files-in-use count reaches zero, all temp memory will be deleted
-=================
-*/
-void *Hunk_AllocateTempMemory( int size ) {
- void *buf;
- hunkHeader_t *hdr;
-
- // return a Z_Malloc'd block if the hunk has not been initialized
- // this allows the config and product id files ( journal files too ) to be loaded
- // by the file system without redunant routines in the file system utilizing different
- // memory systems
- if ( s_hunkData == NULL )
- {
- return Z_Malloc(size);
- }
-
- Hunk_SwapBanks();
-
- size = PAD(size, sizeof(intptr_t)) + sizeof( hunkHeader_t );
-
- if ( hunk_temp->temp + hunk_permanent->permanent + size > s_hunkTotal ) {
- Com_Error( ERR_DROP, "Hunk_AllocateTempMemory: failed on %i", size );
- }
-
- if ( hunk_temp == &hunk_low ) {
- buf = (void *)(s_hunkData + hunk_temp->temp);
- hunk_temp->temp += size;
- } else {
- hunk_temp->temp += size;
- buf = (void *)(s_hunkData + s_hunkTotal - hunk_temp->temp );
- }
-
- if ( hunk_temp->temp > hunk_temp->tempHighwater ) {
- hunk_temp->tempHighwater = hunk_temp->temp;
- }
-
- hdr = (hunkHeader_t *)buf;
- buf = (void *)(hdr+1);
-
- hdr->magic = HUNK_MAGIC;
- hdr->size = size;
-
- // don't bother clearing, because we are going to load a file over it
- return buf;
-}
-
-
-/*
-==================
-Hunk_FreeTempMemory
-==================
-*/
-void Hunk_FreeTempMemory( void *buf ) {
- hunkHeader_t *hdr;
-
- // free with Z_Free if the hunk has not been initialized
- // this allows the config and product id files ( journal files too ) to be loaded
- // by the file system without redunant routines in the file system utilizing different
- // memory systems
- if ( s_hunkData == NULL )
- {
- Z_Free(buf);
- return;
- }
-
-
- hdr = ( (hunkHeader_t *)buf ) - 1;
- if ( hdr->magic != HUNK_MAGIC ) {
- Com_Error( ERR_FATAL, "Hunk_FreeTempMemory: bad magic" );
- }
-
- hdr->magic = HUNK_FREE_MAGIC;
-
- // this only works if the files are freed in stack order,
- // otherwise the memory will stay around until Hunk_ClearTempMemory
- if ( hunk_temp == &hunk_low ) {
- if ( hdr == (void *)(s_hunkData + hunk_temp->temp - hdr->size ) ) {
- hunk_temp->temp -= hdr->size;
- } else {
- Com_Printf( "Hunk_FreeTempMemory: not the final block\n" );
- }
- } else {
- if ( hdr == (void *)(s_hunkData + s_hunkTotal - hunk_temp->temp ) ) {
- hunk_temp->temp -= hdr->size;
- } else {
- Com_Printf( "Hunk_FreeTempMemory: not the final block\n" );
- }
- }
-}
-
-
-/*
-=================
-Hunk_ClearTempMemory
-
-The temp space is no longer needed. If we have left more
-touched but unused memory on this side, have future
-permanent allocs use this side.
-=================
-*/
-void Hunk_ClearTempMemory( void ) {
- if ( s_hunkData != NULL ) {
- hunk_temp->temp = hunk_temp->permanent;
- }
-}
-
-/*
-=================
-Hunk_Trash
-=================
-*/
-void Hunk_Trash( void ) {
- int length, i, rnd;
- char *buf, value;
-
- return;
-
- if ( s_hunkData == NULL )
- return;
-
-#ifdef _DEBUG
- Com_Error(ERR_DROP, "hunk trashed\n");
- return;
-#endif
-
- Cvar_Set("com_jp", "1");
- Hunk_SwapBanks();
-
- if ( hunk_permanent == &hunk_low ) {
- buf = (void *)(s_hunkData + hunk_permanent->permanent);
- } else {
- buf = (void *)(s_hunkData + s_hunkTotal - hunk_permanent->permanent );
- }
- length = hunk_permanent->permanent;
-
- if (length > 0x7FFFF) {
- //randomly trash data within buf
- rnd = random() * (length - 0x7FFFF);
- value = 31;
- for (i = 0; i < 0x7FFFF; i++) {
- value *= 109;
- buf[rnd+i] ^= value;
- }
- }
-}
-
-/*
-===================================================================
-
-EVENTS AND JOURNALING
-
-In addition to these events, .cfg files are also copied to the
-journaled file
-===================================================================
-*/
-
-#define MAX_PUSHED_EVENTS 1024
-static int com_pushedEventsHead = 0;
-static int com_pushedEventsTail = 0;
-static sysEvent_t com_pushedEvents[MAX_PUSHED_EVENTS];
-
-/*
-=================
-Com_InitJournaling
-=================
-*/
-void Com_InitJournaling( void ) {
- Com_StartupVariable( "journal" );
- com_journal = Cvar_Get ("journal", "0", CVAR_INIT);
- if ( !com_journal->integer ) {
- return;
- }
-
- if ( com_journal->integer == 1 ) {
- Com_Printf( "Journaling events\n");
- com_journalFile = FS_FOpenFileWrite( "journal.dat" );
- com_journalDataFile = FS_FOpenFileWrite( "journaldata.dat" );
- } else if ( com_journal->integer == 2 ) {
- Com_Printf( "Replaying journaled events\n");
- FS_FOpenFileRead( "journal.dat", &com_journalFile, qtrue );
- FS_FOpenFileRead( "journaldata.dat", &com_journalDataFile, qtrue );
- }
-
- if ( !com_journalFile || !com_journalDataFile ) {
- Cvar_Set( "com_journal", "0" );
- com_journalFile = 0;
- com_journalDataFile = 0;
- Com_Printf( "Couldn't open journal files\n" );
- }
-}
-
-/*
-========================================================================
-
-EVENT LOOP
-
-========================================================================
-*/
-
-#define MAX_QUEUED_EVENTS 256
-#define MASK_QUEUED_EVENTS ( MAX_QUEUED_EVENTS - 1 )
-
-static sysEvent_t eventQueue[ MAX_QUEUED_EVENTS ];
-static int eventHead = 0;
-static int eventTail = 0;
-static byte sys_packetReceived[ MAX_MSGLEN ];
-
-/*
-================
-Com_QueueEvent
-
-A time of 0 will get the current time
-Ptr should either be null, or point to a block of data that can
-be freed by the game later.
-================
-*/
-void Com_QueueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr )
-{
- sysEvent_t *ev;
-
- ev = &eventQueue[ eventHead & MASK_QUEUED_EVENTS ];
-
- if ( eventHead - eventTail >= MAX_QUEUED_EVENTS )
- {
- Com_Printf("Com_QueueEvent: overflow\n");
- // we are discarding an event, but don't leak memory
- if ( ev->evPtr )
- {
- Z_Free( ev->evPtr );
- }
- eventTail++;
- }
-
- eventHead++;
-
- if ( time == 0 )
- {
- time = Sys_Milliseconds();
- }
-
- ev->evTime = time;
- ev->evType = type;
- ev->evValue = value;
- ev->evValue2 = value2;
- ev->evPtrLength = ptrLength;
- ev->evPtr = ptr;
-}
-
-/*
-================
-Com_GetSystemEvent
-
-================
-*/
-sysEvent_t Com_GetSystemEvent( void )
-{
- sysEvent_t ev;
- char *s;
- msg_t netmsg;
- netadr_t adr;
-
- // return if we have data
- if ( eventHead > eventTail )
- {
- eventTail++;
- return eventQueue[ ( eventTail - 1 ) & MASK_QUEUED_EVENTS ];
- }
-
- // check for console commands
- s = Sys_ConsoleInput();
- if ( s )
- {
- char *b;
- int len;
-
- len = strlen( s ) + 1;
- b = Z_Malloc( len );
- strcpy( b, s );
- Com_QueueEvent( 0, SE_CONSOLE, 0, 0, len, b );
- }
-
- // check for network packets
- MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) );
- if ( Sys_GetPacket ( &adr, &netmsg ) )
- {
- netadr_t *buf;
- int len;
-
- // copy out to a seperate buffer for qeueing
- len = sizeof( netadr_t ) + netmsg.cursize;
- buf = Z_Malloc( len );
- *buf = adr;
- memcpy( buf+1, netmsg.data, netmsg.cursize );
- Com_QueueEvent( 0, SE_PACKET, 0, 0, len, buf );
- }
-
- // return if we have data
- if ( eventHead > eventTail )
- {
- eventTail++;
- return eventQueue[ ( eventTail - 1 ) & MASK_QUEUED_EVENTS ];
- }
-
- // create an empty event to return
- memset( &ev, 0, sizeof( ev ) );
- ev.evTime = Sys_Milliseconds();
-
- return ev;
-}
-
-/*
-=================
-Com_GetRealEvent
-=================
-*/
-sysEvent_t Com_GetRealEvent( void ) {
- int r;
- sysEvent_t ev;
-
- // either get an event from the system or the journal file
- if ( com_journal->integer == 2 ) {
- r = FS_Read( &ev, sizeof(ev), com_journalFile );
- if ( r != sizeof(ev) ) {
- Com_Error( ERR_FATAL, "Error reading from journal file" );
- }
- if ( ev.evPtrLength ) {
- ev.evPtr = Z_Malloc( ev.evPtrLength );
- r = FS_Read( ev.evPtr, ev.evPtrLength, com_journalFile );
- if ( r != ev.evPtrLength ) {
- Com_Error( ERR_FATAL, "Error reading from journal file" );
- }
- }
- } else {
- ev = Com_GetSystemEvent();
-
- // write the journal value out if needed
- if ( com_journal->integer == 1 ) {
- r = FS_Write( &ev, sizeof(ev), com_journalFile );
- if ( r != sizeof(ev) ) {
- Com_Error( ERR_FATAL, "Error writing to journal file" );
- }
- if ( ev.evPtrLength ) {
- r = FS_Write( ev.evPtr, ev.evPtrLength, com_journalFile );
- if ( r != ev.evPtrLength ) {
- Com_Error( ERR_FATAL, "Error writing to journal file" );
- }
- }
- }
- }
-
- return ev;
-}
-
-
-/*
-=================
-Com_InitPushEvent
-=================
-*/
-void Com_InitPushEvent( void ) {
- // clear the static buffer array
- // this requires SE_NONE to be accepted as a valid but NOP event
- memset( com_pushedEvents, 0, sizeof(com_pushedEvents) );
- // reset counters while we are at it
- // beware: GetEvent might still return an SE_NONE from the buffer
- com_pushedEventsHead = 0;
- com_pushedEventsTail = 0;
-}
-
-
-/*
-=================
-Com_PushEvent
-=================
-*/
-void Com_PushEvent( sysEvent_t *event ) {
- sysEvent_t *ev;
- static int printedWarning = 0;
-
- ev = &com_pushedEvents[ com_pushedEventsHead & (MAX_PUSHED_EVENTS-1) ];
-
- if ( com_pushedEventsHead - com_pushedEventsTail >= MAX_PUSHED_EVENTS ) {
-
- // don't print the warning constantly, or it can give time for more...
- if ( !printedWarning ) {
- printedWarning = qtrue;
- Com_Printf( "WARNING: Com_PushEvent overflow\n" );
- }
-
- if ( ev->evPtr ) {
- Z_Free( ev->evPtr );
- }
- com_pushedEventsTail++;
- } else {
- printedWarning = qfalse;
- }
-
- *ev = *event;
- com_pushedEventsHead++;
-}
-
-/*
-=================
-Com_GetEvent
-=================
-*/
-sysEvent_t Com_GetEvent( void ) {
- if ( com_pushedEventsHead > com_pushedEventsTail ) {
- com_pushedEventsTail++;
- return com_pushedEvents[ (com_pushedEventsTail-1) & (MAX_PUSHED_EVENTS-1) ];
- }
- return Com_GetRealEvent();
-}
-
-/*
-=================
-Com_RunAndTimeServerPacket
-=================
-*/
-void Com_RunAndTimeServerPacket( netadr_t *evFrom, msg_t *buf ) {
- int t1, t2, msec;
-
- t1 = 0;
-
- if ( com_speeds->integer ) {
- t1 = Sys_Milliseconds ();
- }
-
- SV_PacketEvent( *evFrom, buf );
-
- if ( com_speeds->integer ) {
- t2 = Sys_Milliseconds ();
- msec = t2 - t1;
- if ( com_speeds->integer == 3 ) {
- Com_Printf( "SV_PacketEvent time: %i\n", msec );
- }
- }
-}
-
-/*
-=================
-Com_EventLoop
-
-Returns last event time
-=================
-*/
-int Com_EventLoop( void ) {
- sysEvent_t ev;
- netadr_t evFrom;
- byte bufData[MAX_MSGLEN];
- msg_t buf;
-
- MSG_Init( &buf, bufData, sizeof( bufData ) );
-
- while ( 1 ) {
- NET_FlushPacketQueue();
- ev = Com_GetEvent();
-
- // if no more events are available
- if ( ev.evType == SE_NONE ) {
- // manually send packet events for the loopback channel
- while ( NET_GetLoopPacket( NS_CLIENT, &evFrom, &buf ) ) {
- CL_PacketEvent( evFrom, &buf );
- }
-
- while ( NET_GetLoopPacket( NS_SERVER, &evFrom, &buf ) ) {
- // if the server just shut down, flush the events
- if ( com_sv_running->integer ) {
- Com_RunAndTimeServerPacket( &evFrom, &buf );
- }
- }
-
- return ev.evTime;
- }
-
-
- switch ( ev.evType ) {
- default:
- Com_Error( ERR_FATAL, "Com_EventLoop: bad event type %i", ev.evType );
- break;
- case SE_NONE:
- break;
- case SE_KEY:
- CL_KeyEvent( ev.evValue, ev.evValue2, ev.evTime );
- break;
- case SE_CHAR:
- CL_CharEvent( ev.evValue );
- break;
- case SE_MOUSE:
- CL_MouseEvent( ev.evValue, ev.evValue2, ev.evTime );
- break;
- case SE_JOYSTICK_AXIS:
- CL_JoystickEvent( ev.evValue, ev.evValue2, ev.evTime );
- break;
- case SE_CONSOLE:
- Cbuf_AddText( (char *)ev.evPtr );
- Cbuf_AddText( "\n" );
- break;
- case SE_PACKET:
- // this cvar allows simulation of connections that
- // drop a lot of packets. Note that loopback connections
- // don't go through here at all.
- if ( com_dropsim->value > 0 ) {
- static int seed;
-
- if ( Q_random( &seed ) < com_dropsim->value ) {
- break; // drop this packet
- }
- }
-
- evFrom = *(netadr_t *)ev.evPtr;
- buf.cursize = ev.evPtrLength - sizeof( evFrom );
-
- // we must copy the contents of the message out, because
- // the event buffers are only large enough to hold the
- // exact payload, but channel messages need to be large
- // enough to hold fragment reassembly
- if ( (unsigned)buf.cursize > buf.maxsize ) {
- Com_Printf("Com_EventLoop: oversize packet\n");
- continue;
- }
- Com_Memcpy( buf.data, (byte *)((netadr_t *)ev.evPtr + 1), buf.cursize );
- if ( com_sv_running->integer ) {
- Com_RunAndTimeServerPacket( &evFrom, &buf );
- } else {
- CL_PacketEvent( evFrom, &buf );
- }
- break;
- }
-
- // free any block data
- if ( ev.evPtr ) {
- Z_Free( ev.evPtr );
- }
- }
-
- return 0; // never reached
-}
-
-/*
-================
-Com_Milliseconds
-
-Can be used for profiling, but will be journaled accurately
-================
-*/
-int Com_Milliseconds (void) {
- sysEvent_t ev;
-
- // get events and push them until we get a null event with the current time
- do {
-
- ev = Com_GetRealEvent();
- if ( ev.evType != SE_NONE ) {
- Com_PushEvent( &ev );
- }
- } while ( ev.evType != SE_NONE );
-
- return ev.evTime;
-}
-
-//============================================================================
-
-/*
-=============
-Com_Error_f
-
-Just throw a fatal error to
-test error shutdown procedures
-=============
-*/
-static void Com_Error_f (void) {
- if ( Cmd_Argc() > 1 ) {
- Com_Error( ERR_DROP, "Testing drop error" );
- } else {
- Com_Error( ERR_FATAL, "Testing fatal error" );
- }
-}
-
-
-/*
-=============
-Com_Freeze_f
-
-Just freeze in place for a given number of seconds to test
-error recovery
-=============
-*/
-static void Com_Freeze_f (void) {
- float s;
- int start, now;
-
- if ( Cmd_Argc() != 2 ) {
- Com_Printf( "freeze <seconds>\n" );
- return;
- }
- s = atof( Cmd_Argv(1) );
-
- start = Com_Milliseconds();
-
- while ( 1 ) {
- now = Com_Milliseconds();
- if ( ( now - start ) * 0.001 > s ) {
- break;
- }
- }
-}
-
-/*
-=================
-Com_Crash_f
-
-A way to force a bus error for development reasons
-=================
-*/
-static void Com_Crash_f( void ) {
- * ( int * ) 0 = 0x12345678;
-}
-
-/*
-==================
-Com_Setenv_f
-
-For controlling environment variables
-==================
-*/
-void Com_Setenv_f(void)
-{
- int argc = Cmd_Argc();
- char *arg1 = Cmd_Argv(1);
-
- if(argc > 2)
- {
- char *arg2 = Cmd_ArgsFrom(2);
-
- Sys_SetEnv(arg1, arg2);
- }
- else if(argc == 2)
- {
- char *env = getenv(arg1);
-
- if(env)
- Com_Printf("%s=%s\n", arg1, env);
- else
- Com_Printf("%s undefined\n", arg1);
- }
-}
-
-/*
-==================
-Com_ExecuteCfg
-
-For controlling environment variables
-==================
-*/
-
-void Com_ExecuteCfg(void)
-{
- Cbuf_ExecuteText(EXEC_NOW, "exec default.cfg\n");
- Cbuf_Execute(); // Always execute after exec to prevent text buffer overflowing
-
- if(!Com_SafeMode())
- {
- // skip the q3config.cfg and autoexec.cfg if "safe" is on the command line
- Cbuf_ExecuteText(EXEC_NOW, "exec " Q3CONFIG_CFG "\n");
- Cbuf_Execute();
- Cbuf_ExecuteText(EXEC_NOW, "exec autoexec.cfg\n");
- Cbuf_Execute();
- }
-}
-
-/*
-==================
-Com_GameRestart
-
-Change to a new mod properly with cleaning up cvars before switching.
-==================
-*/
-
-void Com_GameRestart(int checksumFeed, qboolean clientRestart)
-{
- // make sure no recursion can be triggered
- if(!com_gameRestarting && com_fullyInitialized)
- {
- com_gameRestarting = qtrue;
-
- if(clientRestart)
- {
- CL_Disconnect(qfalse);
- CL_ShutdownAll();
- }
-
- // Kill server if we have one
- if(com_sv_running->integer)
- SV_Shutdown("Game directory changed");
-
- FS_Restart(checksumFeed);
-
- // Clean out any user and VM created cvars
- Cvar_Restart(qtrue);
- Com_ExecuteCfg();
-
- // Restart sound subsystem so old handles are flushed
- CL_Snd_Restart();
-
- if(clientRestart)
- CL_StartHunkUsers(qfalse);
-
- com_gameRestarting = qfalse;
- }
-}
-
-/*
-==================
-Com_GameRestart_f
-
-Expose possibility to change current running mod to the user
-==================
-*/
-
-void Com_GameRestart_f(void)
-{
- Cvar_Set("fs_game", Cmd_Argv(1));
-
- Com_GameRestart(0, qtrue);
-}
-
-#ifndef STANDALONE
-
-// TTimo: centralizing the cl_cdkey stuff after I discovered a buffer overflow problem with the dedicated server version
-// not sure it's necessary to have different defaults for regular and dedicated, but I don't want to risk it
-// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=470
-#ifndef DEDICATED
-char cl_cdkey[34] = " ";
-#else
-char cl_cdkey[34] = "123456789";
-#endif
-
-/*
-=================
-Com_ReadCDKey
-=================
-*/
-qboolean CL_CDKeyValidate( const char *key, const char *checksum );
-void Com_ReadCDKey( const char *filename ) {
- fileHandle_t f;
- char buffer[33];
- char fbuffer[MAX_OSPATH];
-
- Com_sprintf(fbuffer, sizeof(fbuffer), "%s/q3key", filename);
-
- FS_SV_FOpenFileRead( fbuffer, &f );
- if ( !f ) {
- Q_strncpyz( cl_cdkey, " ", 17 );
- return;
- }
-
- Com_Memset( buffer, 0, sizeof(buffer) );
-
- FS_Read( buffer, 16, f );
- FS_FCloseFile( f );
-
- if (CL_CDKeyValidate(buffer, NULL)) {
- Q_strncpyz( cl_cdkey, buffer, 17 );
- } else {
- Q_strncpyz( cl_cdkey, " ", 17 );
- }
-}
-
-/*
-=================
-Com_AppendCDKey
-=================
-*/
-void Com_AppendCDKey( const char *filename ) {
- fileHandle_t f;
- char buffer[33];
- char fbuffer[MAX_OSPATH];
-
- Com_sprintf(fbuffer, sizeof(fbuffer), "%s/q3key", filename);
-
- FS_SV_FOpenFileRead( fbuffer, &f );
- if (!f) {
- Q_strncpyz( &cl_cdkey[16], " ", 17 );
- return;
- }
-
- Com_Memset( buffer, 0, sizeof(buffer) );
-
- FS_Read( buffer, 16, f );
- FS_FCloseFile( f );
-
- if (CL_CDKeyValidate(buffer, NULL)) {
- strcat( &cl_cdkey[16], buffer );
- } else {
- Q_strncpyz( &cl_cdkey[16], " ", 17 );
- }
-}
-
-#ifndef DEDICATED
-/*
-=================
-Com_WriteCDKey
-=================
-*/
-static void Com_WriteCDKey( const char *filename, const char *ikey ) {
- fileHandle_t f;
- char fbuffer[MAX_OSPATH];
- char key[17];
-#ifndef _WIN32
- mode_t savedumask;
-#endif
-
-
- Com_sprintf(fbuffer, sizeof(fbuffer), "%s/q3key", filename);
-
-
- Q_strncpyz( key, ikey, 17 );
-
- if(!CL_CDKeyValidate(key, NULL) ) {
- return;
- }
-
-#ifndef _WIN32
- savedumask = umask(0077);
-#endif
- f = FS_SV_FOpenFileWrite( fbuffer );
- if ( !f ) {
- Com_Printf ("Couldn't write CD key to %s.\n", fbuffer );
- goto out;
- }
-
- FS_Write( key, 16, f );
-
- FS_Printf( f, "\n// generated by quake, do not modify\r\n" );
- FS_Printf( f, "// Do not give this file to ANYONE.\r\n" );
- FS_Printf( f, "// id Software and Activision will NOT ask you to send this file to them.\r\n");
-
- FS_FCloseFile( f );
-out:
-#ifndef _WIN32
- umask(savedumask);
-#endif
- return;
-}
-#endif
-
-#endif // STANDALONE
-
-static void Com_DetectAltivec(void)
-{
- // Only detect if user hasn't forcibly disabled it.
- if (com_altivec->integer) {
- static qboolean altivec = qfalse;
- static qboolean detected = qfalse;
- if (!detected) {
- altivec = ( Sys_GetProcessorFeatures( ) & CF_ALTIVEC );
- detected = qtrue;
- }
-
- if (!altivec) {
- Cvar_Set( "com_altivec", "0" ); // we don't have it! Disable support!
- }
- }
-}
-
-/*
-=================
-Com_InitRand
-Seed the random number generator, if possible with an OS supplied random seed.
-=================
-*/
-static void Com_InitRand(void)
-{
- unsigned int seed;
-
- if(Sys_RandomBytes((byte *) &seed, sizeof(seed)))
- srand(seed);
- else
- srand(time(NULL));
-}
-
-/*
-=================
-Com_Init
-=================
-*/
-void Com_Init( char *commandLine ) {
- char *s;
- int qport;
-
- Com_Printf( "%s %s %s\n", Q3_VERSION, PLATFORM_STRING, __DATE__ );
-
- if ( setjmp (abortframe) ) {
- Sys_Error ("Error during initialization");
- }
-
- // Clear queues
- Com_Memset( &eventQueue[ 0 ], 0, MAX_QUEUED_EVENTS * sizeof( sysEvent_t ) );
- Com_Memset( &sys_packetReceived[ 0 ], 0, MAX_MSGLEN * sizeof( byte ) );
-
- // initialize the weak pseudo-random number generator for use later.
- Com_InitRand();
-
- // do this before anything else decides to push events
- Com_InitPushEvent();
-
- Com_InitSmallZoneMemory();
- Cvar_Init ();
-
- // prepare enough of the subsystems to handle
- // cvar and command buffer management
- Com_ParseCommandLine( commandLine );
-
-// Swap_Init ();
- Cbuf_Init ();
-
- // override anything from the config files with command line args
- Com_StartupVariable( NULL );
-
- Com_InitZoneMemory();
- Cmd_Init ();
-
- // get the developer cvar set as early as possible
- Com_StartupVariable( "developer" );
-
- // done early so bind command exists
- CL_InitKeyCommands();
-
- FS_InitFilesystem ();
-
- Com_InitJournaling();
-
- // Add some commands here already so users can use them from config files
- Cmd_AddCommand ("setenv", Com_Setenv_f);
- if (com_developer && com_developer->integer)
- {
- Cmd_AddCommand ("error", Com_Error_f);
- Cmd_AddCommand ("crash", Com_Crash_f);
- Cmd_AddCommand ("freeze", Com_Freeze_f);
- }
- Cmd_AddCommand ("quit", Com_Quit_f);
- Cmd_AddCommand ("changeVectors", MSG_ReportChangeVectors_f );
- Cmd_AddCommand ("writeconfig", Com_WriteConfig_f );
- Cmd_SetCommandCompletionFunc( "writeconfig", Cmd_CompleteCfgName );
- Cmd_AddCommand("game_restart", Com_GameRestart_f);
-
- Com_ExecuteCfg();
-
- // override anything from the config files with command line args
- Com_StartupVariable( NULL );
-
- // get dedicated here for proper hunk megs initialization
-#ifdef DEDICATED
- com_dedicated = Cvar_Get ("dedicated", "1", CVAR_INIT);
- Cvar_CheckRange( com_dedicated, 1, 2, qtrue );
-#else
- com_dedicated = Cvar_Get ("dedicated", "0", CVAR_LATCH);
- Cvar_CheckRange( com_dedicated, 0, 2, qtrue );
-#endif
- // allocate the stack based hunk allocator
- Com_InitHunkMemory();
-
- // if any archived cvars are modified after this, we will trigger a writing
- // of the config file
- cvar_modifiedFlags &= ~CVAR_ARCHIVE;
-
- //
- // init commands and vars
- //
- com_altivec = Cvar_Get ("com_altivec", "1", CVAR_ARCHIVE);
- com_maxfps = Cvar_Get ("com_maxfps", "85", CVAR_ARCHIVE);
- com_blood = Cvar_Get ("com_blood", "1", CVAR_ARCHIVE);
-
- com_developer = Cvar_Get ("developer", "0", CVAR_TEMP );
- com_logfile = Cvar_Get ("logfile", "0", CVAR_TEMP );
-
- com_timescale = Cvar_Get ("timescale", "1", CVAR_CHEAT | CVAR_SYSTEMINFO );
- com_fixedtime = Cvar_Get ("fixedtime", "0", CVAR_CHEAT);
- com_showtrace = Cvar_Get ("com_showtrace", "0", CVAR_CHEAT);
- com_dropsim = Cvar_Get ("com_dropsim", "0", CVAR_CHEAT);
- com_speeds = Cvar_Get ("com_speeds", "0", 0);
- com_timedemo = Cvar_Get ("timedemo", "0", CVAR_CHEAT);
- com_cameraMode = Cvar_Get ("com_cameraMode", "0", CVAR_CHEAT);
-
- cl_paused = Cvar_Get ("cl_paused", "0", CVAR_ROM);
- sv_paused = Cvar_Get ("sv_paused", "0", CVAR_ROM);
- cl_packetdelay = Cvar_Get ("cl_packetdelay", "0", CVAR_CHEAT);
- sv_packetdelay = Cvar_Get ("sv_packetdelay", "0", CVAR_CHEAT);
- com_sv_running = Cvar_Get ("sv_running", "0", CVAR_ROM);
- com_cl_running = Cvar_Get ("cl_running", "0", CVAR_ROM);
- com_buildScript = Cvar_Get( "com_buildScript", "0", 0 );
- com_ansiColor = Cvar_Get( "com_ansiColor", "0", CVAR_ARCHIVE );
-
- com_unfocused = Cvar_Get( "com_unfocused", "0", CVAR_ROM );
- com_maxfpsUnfocused = Cvar_Get( "com_maxfpsUnfocused", "0", CVAR_ARCHIVE );
- com_minimized = Cvar_Get( "com_minimized", "0", CVAR_ROM );
- com_maxfpsMinimized = Cvar_Get( "com_maxfpsMinimized", "0", CVAR_ARCHIVE );
- com_standalone = Cvar_Get( "com_standalone", "0", CVAR_INIT );
-
- com_introPlayed = Cvar_Get( "com_introplayed", "0", CVAR_ARCHIVE);
-
- s = va("%s %s %s", Q3_VERSION, PLATFORM_STRING, __DATE__ );
- com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO );
-
- Sys_Init();
-
- // Pick a random port value
- Com_RandomBytes( (byte*)&qport, sizeof(int) );
- Netchan_Init( qport & 0xffff );
-
- VM_Init();
- SV_Init();
-
- com_dedicated->modified = qfalse;
-#ifndef DEDICATED
- CL_Init();
-#endif
-
- // set com_frameTime so that if a map is started on the
- // command line it will still be able to count on com_frameTime
- // being random enough for a serverid
- com_frameTime = Com_Milliseconds();
-
- // add + commands from command line
- if ( !Com_AddStartupCommands() ) {
- // if the user didn't give any commands, run default action
- if ( !com_dedicated->integer ) {
- Cbuf_AddText ("cinematic idlogo.RoQ\n");
- if( !com_introPlayed->integer ) {
- Cvar_Set( com_introPlayed->name, "1" );
- Cvar_Set( "nextmap", "cinematic intro.RoQ" );
- }
- }
- }
-
- // start in full screen ui mode
- Cvar_Set("r_uiFullScreen", "1");
-
- CL_StartHunkUsers( qfalse );
-
- // make sure single player is off by default
- Cvar_Set("ui_singlePlayerActive", "0");
-
- com_fullyInitialized = qtrue;
-
- // always set the cvar, but only print the info if it makes sense.
- Com_DetectAltivec();
-#if idppc
- Com_Printf ("Altivec support is %s\n", com_altivec->integer ? "enabled" : "disabled");
-#endif
-
- Com_Printf ("--- Common Initialization Complete ---\n");
-}
-
-//==================================================================
-
-void Com_WriteConfigToFile( const char *filename ) {
- fileHandle_t f;
-
- f = FS_FOpenFileWrite( filename );
- if ( !f ) {
- Com_Printf ("Couldn't write %s.\n", filename );
- return;
- }
-
- FS_Printf (f, "// generated by quake, do not modify\n");
- Key_WriteBindings (f);
- Cvar_WriteVariables (f);
- FS_FCloseFile( f );
-}
-
-
-/*
-===============
-Com_WriteConfiguration
-
-Writes key bindings and archived cvars to config file if modified
-===============
-*/
-void Com_WriteConfiguration( void ) {
-#ifndef DEDICATED
- cvar_t *fs;
-#endif
- // if we are quiting without fully initializing, make sure
- // we don't write out anything
- if ( !com_fullyInitialized ) {
- return;
- }
-
- if ( !(cvar_modifiedFlags & CVAR_ARCHIVE ) ) {
- return;
- }
- cvar_modifiedFlags &= ~CVAR_ARCHIVE;
-
- Com_WriteConfigToFile( Q3CONFIG_CFG );
-
- // not needed for dedicated
-#ifndef DEDICATED
- fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
-#ifndef STANDALONE
- if(!Cvar_VariableIntegerValue("com_standalone"))
- {
- if (UI_usesUniqueCDKey() && fs && fs->string[0] != 0) {
- Com_WriteCDKey( fs->string, &cl_cdkey[16] );
- } else {
- Com_WriteCDKey( BASEGAME, cl_cdkey );
- }
- }
-#endif
-#endif
-}
-
-
-/*
-===============
-Com_WriteConfig_f
-
-Write the config file to a specific name
-===============
-*/
-void Com_WriteConfig_f( void ) {
- char filename[MAX_QPATH];
-
- if ( Cmd_Argc() != 2 ) {
- Com_Printf( "Usage: writeconfig <filename>\n" );
- return;
- }
-
- Q_strncpyz( filename, Cmd_Argv(1), sizeof( filename ) );
- COM_DefaultExtension( filename, sizeof( filename ), ".cfg" );
- Com_Printf( "Writing %s.\n", filename );
- Com_WriteConfigToFile( filename );
-}
-
-/*
-================
-Com_ModifyMsec
-================
-*/
-int Com_ModifyMsec( int msec ) {
- int clampTime;
-
- //
- // modify time for debugging values
- //
- if ( com_fixedtime->integer ) {
- msec = com_fixedtime->integer;
- } else if ( com_timescale->value ) {
- msec *= com_timescale->value;
- } else if (com_cameraMode->integer) {
- msec *= com_timescale->value;
- }
-
- // don't let it scale below 1 msec
- if ( msec < 1 && com_timescale->value) {
- msec = 1;
- }
-
- if ( com_dedicated->integer ) {
- // dedicated servers don't want to clamp for a much longer
- // period, because it would mess up all the client's views
- // of time.
- if (com_sv_running->integer && msec > 500)
- Com_Printf( "Hitch warning: %i msec frame time\n", msec );
-
- clampTime = 5000;
- } else
- if ( !com_sv_running->integer ) {
- // clients of remote servers do not want to clamp time, because
- // it would skew their view of the server's time temporarily
- clampTime = 5000;
- } else {
- // for local single player gaming
- // we may want to clamp the time to prevent players from
- // flying off edges when something hitches.
- clampTime = 200;
- }
-
- if ( msec > clampTime ) {
- msec = clampTime;
- }
-
- return msec;
-}
-
-/*
-=================
-Com_Frame
-=================
-*/
-void Com_Frame( void ) {
-
- int msec, minMsec;
- static int lastTime;
- int key;
-
- int timeBeforeFirstEvents;
- int timeBeforeServer;
- int timeBeforeEvents;
- int timeBeforeClient;
- int timeAfter;
-
-
-
-
-
- if ( setjmp (abortframe) ) {
- return; // an ERR_DROP was thrown
- }
-
- timeBeforeFirstEvents =0;
- timeBeforeServer =0;
- timeBeforeEvents =0;
- timeBeforeClient = 0;
- timeAfter = 0;
-
-
- // old net chan encryption key
- key = 0x87243987;
-
- // write config file if anything changed
- Com_WriteConfiguration();
-
- //
- // main event loop
- //
- if ( com_speeds->integer ) {
- timeBeforeFirstEvents = Sys_Milliseconds ();
- }
-
- // we may want to spin here if things are going too fast
- if ( !com_dedicated->integer && !com_timedemo->integer ) {
- if( com_minimized->integer && com_maxfpsMinimized->integer > 0 ) {
- minMsec = 1000 / com_maxfpsMinimized->integer;
- } else if( com_unfocused->integer && com_maxfpsUnfocused->integer > 0 ) {
- minMsec = 1000 / com_maxfpsUnfocused->integer;
- } else if( com_maxfps->integer > 0 ) {
- minMsec = 1000 / com_maxfps->integer;
- } else {
- minMsec = 1;
- }
- } else {
- minMsec = 1;
- }
-
- msec = minMsec;
- do {
- int timeRemaining = minMsec - msec;
-
- // The existing Sys_Sleep implementations aren't really
- // precise enough to be of use beyond 100fps
- // FIXME: implement a more precise sleep (RDTSC or something)
- if( timeRemaining >= 10 )
- Sys_Sleep( timeRemaining );
-
- com_frameTime = Com_EventLoop();
- if ( lastTime > com_frameTime ) {
- lastTime = com_frameTime; // possible on first frame
- }
- msec = com_frameTime - lastTime;
- } while ( msec < minMsec );
- Cbuf_Execute ();
-
- if (com_altivec->modified)
- {
- Com_DetectAltivec();
- com_altivec->modified = qfalse;
- }
-
- lastTime = com_frameTime;
-
- // mess with msec if needed
- com_frameMsec = msec;
- msec = Com_ModifyMsec( msec );
-
- //
- // server side
- //
- if ( com_speeds->integer ) {
- timeBeforeServer = Sys_Milliseconds ();
- }
-
- SV_Frame( msec );
-
- // if "dedicated" has been modified, start up
- // or shut down the client system.
- // Do this after the server may have started,
- // but before the client tries to auto-connect
- if ( com_dedicated->modified ) {
- // get the latched value
- Cvar_Get( "dedicated", "0", 0 );
- com_dedicated->modified = qfalse;
- if ( !com_dedicated->integer ) {
- SV_Shutdown( "dedicated set to 0" );
- CL_FlushMemory();
- }
- }
-
-#ifndef DEDICATED
- //
- // client system
- //
- //
- // run event loop a second time to get server to client packets
- // without a frame of latency
- //
- if ( com_speeds->integer ) {
- timeBeforeEvents = Sys_Milliseconds ();
- }
- Com_EventLoop();
- Cbuf_Execute ();
-
-
- //
- // client side
- //
- if ( com_speeds->integer ) {
- timeBeforeClient = Sys_Milliseconds ();
- }
-
- CL_Frame( msec );
-
- if ( com_speeds->integer ) {
- timeAfter = Sys_Milliseconds ();
- }
-#else
- if ( com_speeds->integer ) {
- timeAfter = Sys_Milliseconds ();
- timeBeforeEvents = timeAfter;
- timeBeforeClient = timeAfter;
- }
-#endif
-
- //
- // report timing information
- //
- if ( com_speeds->integer ) {
- int all, sv, ev, cl;
-
- all = timeAfter - timeBeforeServer;
- sv = timeBeforeEvents - timeBeforeServer;
- ev = timeBeforeServer - timeBeforeFirstEvents + timeBeforeClient - timeBeforeEvents;
- cl = timeAfter - timeBeforeClient;
- sv -= time_game;
- cl -= time_frontend + time_backend;
-
- Com_Printf ("frame:%i all:%3i sv:%3i ev:%3i cl:%3i gm:%3i rf:%3i bk:%3i\n",
- com_frameNumber, all, sv, ev, cl, time_game, time_frontend, time_backend );
- }
-
- //
- // trace optimization tracking
- //
- if ( com_showtrace->integer ) {
-
- extern int c_traces, c_brush_traces, c_patch_traces;
- extern int c_pointcontents;
-
- Com_Printf ("%4i traces (%ib %ip) %4i points\n", c_traces,
- c_brush_traces, c_patch_traces, c_pointcontents);
- c_traces = 0;
- c_brush_traces = 0;
- c_patch_traces = 0;
- c_pointcontents = 0;
- }
-
- // old net chan encryption key
- key = lastTime * 0x87243987;
-
- com_frameNumber++;
-}
-
-/*
-=================
-Com_Shutdown
-=================
-*/
-void Com_Shutdown (void) {
- if (logfile) {
- FS_FCloseFile (logfile);
- logfile = 0;
- }
-
- if ( com_journalFile ) {
- FS_FCloseFile( com_journalFile );
- com_journalFile = 0;
- }
-
-}
-
-//------------------------------------------------------------------------
-
-
-/*
-=====================
-Q_acos
-
-the msvc acos doesn't always return a value between -PI and PI:
-
-int i;
-i = 1065353246;
-acos(*(float*) &i) == -1.#IND0
-
- This should go in q_math but it is too late to add new traps
- to game and ui
-=====================
-*/
-float Q_acos(float c) {
- float angle;
-
- angle = acos(c);
-
- if (angle > M_PI) {
- return (float)M_PI;
- }
- if (angle < -M_PI) {
- return (float)M_PI;
- }
- return angle;
-}
-
-/*
-===========================================
-command line completion
-===========================================
-*/
-
-/*
-==================
-Field_Clear
-==================
-*/
-void Field_Clear( field_t *edit ) {
- memset(edit->buffer, 0, MAX_EDIT_LINE);
- edit->cursor = 0;
- edit->scroll = 0;
-}
-
-static const char *completionString;
-static char shortestMatch[MAX_TOKEN_CHARS];
-static int matchCount;
-// field we are working on, passed to Field_AutoComplete(&g_consoleCommand for instance)
-static field_t *completionField;
-
-/*
-===============
-FindMatches
-
-===============
-*/
-static void FindMatches( const char *s ) {
- int i;
-
- if ( Q_stricmpn( s, completionString, strlen( completionString ) ) ) {
- return;
- }
- matchCount++;
- if ( matchCount == 1 ) {
- Q_strncpyz( shortestMatch, s, sizeof( shortestMatch ) );
- return;
- }
-
- // cut shortestMatch to the amount common with s
- for ( i = 0 ; shortestMatch[i] ; i++ ) {
- if ( i >= strlen( s ) ) {
- shortestMatch[i] = 0;
- break;
- }
-
- if ( tolower(shortestMatch[i]) != tolower(s[i]) ) {
- shortestMatch[i] = 0;
- }
- }
-}
-
-/*
-===============
-PrintMatches
-
-===============
-*/
-static void PrintMatches( const char *s ) {
- if ( !Q_stricmpn( s, shortestMatch, strlen( shortestMatch ) ) ) {
- Com_Printf( " %s\n", s );
- }
-}
-
-/*
-===============
-PrintCvarMatches
-
-===============
-*/
-static void PrintCvarMatches( const char *s ) {
- char value[ TRUNCATE_LENGTH ];
-
- if ( !Q_stricmpn( s, shortestMatch, strlen( shortestMatch ) ) ) {
- Com_TruncateLongString( value, Cvar_VariableString( s ) );
- Com_Printf( " %s = \"%s\"\n", s, value );
- }
-}
-
-/*
-===============
-Field_FindFirstSeparator
-===============
-*/
-static char *Field_FindFirstSeparator( char *s )
-{
- int i;
-
- for( i = 0; i < strlen( s ); i++ )
- {
- if( s[ i ] == ';' )
- return &s[ i ];
- }
-
- return NULL;
-}
-
-/*
-===============
-Field_Complete
-===============
-*/
-static qboolean Field_Complete( void )
-{
- int completionOffset;
-
- if( matchCount == 0 )
- return qtrue;
-
- completionOffset = strlen( completionField->buffer ) - strlen( completionString );
-
- Q_strncpyz( &completionField->buffer[ completionOffset ], shortestMatch,
- sizeof( completionField->buffer ) - completionOffset );
-
- completionField->cursor = strlen( completionField->buffer );
-
- if( matchCount == 1 )
- {
- Q_strcat( completionField->buffer, sizeof( completionField->buffer ), " " );
- completionField->cursor++;
- return qtrue;
- }
-
- Com_Printf( "]%s\n", completionField->buffer );
-
- return qfalse;
-}
-
-#ifndef DEDICATED
-/*
-===============
-Field_CompleteKeyname
-===============
-*/
-void Field_CompleteKeyname( void )
-{
- matchCount = 0;
- shortestMatch[ 0 ] = 0;
-
- Key_KeynameCompletion( FindMatches );
-
- if( !Field_Complete( ) )
- Key_KeynameCompletion( PrintMatches );
-}
-#endif
-
-/*
-===============
-Field_CompleteFilename
-===============
-*/
-void Field_CompleteFilename( const char *dir,
- const char *ext, qboolean stripExt )
-{
- matchCount = 0;
- shortestMatch[ 0 ] = 0;
-
- FS_FilenameCompletion( dir, ext, stripExt, FindMatches );
-
- if( !Field_Complete( ) )
- FS_FilenameCompletion( dir, ext, stripExt, PrintMatches );
-}
-
-/*
-===============
-Field_CompleteCommand
-===============
-*/
-void Field_CompleteCommand( char *cmd,
- qboolean doCommands, qboolean doCvars )
-{
- int completionArgument = 0;
-
- // Skip leading whitespace and quotes
- cmd = Com_SkipCharset( cmd, " \"" );
-
- Cmd_TokenizeStringIgnoreQuotes( cmd );
- completionArgument = Cmd_Argc( );
-
- // If there is trailing whitespace on the cmd
- if( *( cmd + strlen( cmd ) - 1 ) == ' ' )
- {
- completionString = "";
- completionArgument++;
- }
- else
- completionString = Cmd_Argv( completionArgument - 1 );
-
-#ifndef DEDICATED
- // Unconditionally add a '\' to the start of the buffer
- if( completionField->buffer[ 0 ] &&
- completionField->buffer[ 0 ] != '\\' )
- {
- if( completionField->buffer[ 0 ] != '/' )
- {
- // Buffer is full, refuse to complete
- if( strlen( completionField->buffer ) + 1 >=
- sizeof( completionField->buffer ) )
- return;
-
- memmove( &completionField->buffer[ 1 ],
- &completionField->buffer[ 0 ],
- strlen( completionField->buffer ) + 1 );
- completionField->cursor++;
- }
-
- completionField->buffer[ 0 ] = '\\';
- }
-#endif
-
- if( completionArgument > 1 )
- {
- const char *baseCmd = Cmd_Argv( 0 );
- char *p;
-
-#ifndef DEDICATED
- // This should always be true
- if( baseCmd[ 0 ] == '\\' || baseCmd[ 0 ] == '/' )
- baseCmd++;
-#endif
-
- if( ( p = Field_FindFirstSeparator( cmd ) ) )
- Field_CompleteCommand( p + 1, qtrue, qtrue ); // Compound command
- else
- Cmd_CompleteArgument( baseCmd, cmd, completionArgument );
- }
- else
- {
- if( completionString[0] == '\\' || completionString[0] == '/' )
- completionString++;
-
- matchCount = 0;
- shortestMatch[ 0 ] = 0;
-
- if( strlen( completionString ) == 0 )
- return;
-
- if( doCommands )
- Cmd_CommandCompletion( FindMatches );
-
- if( doCvars )
- Cvar_CommandCompletion( FindMatches );
-
- if( !Field_Complete( ) )
- {
- // run through again, printing matches
- if( doCommands )
- Cmd_CommandCompletion( PrintMatches );
-
- if( doCvars )
- Cvar_CommandCompletion( PrintCvarMatches );
- }
- }
-}
-
-/*
-===============
-Field_AutoComplete
-
-Perform Tab expansion
-===============
-*/
-void Field_AutoComplete( field_t *field )
-{
- completionField = field;
-
- Field_CompleteCommand( completionField->buffer, qtrue, qtrue );
-}
-
-/*
-==================
-Com_RandomBytes
-
-fills string array with len radom bytes, peferably from the OS randomizer
-==================
-*/
-void Com_RandomBytes( byte *string, int len )
-{
- int i;
-
- if( Sys_RandomBytes( string, len ) )
- return;
-
- Com_Printf( "Com_RandomBytes: using weak randomization\n" );
- for( i = 0; i < len; i++ )
- string[i] = (unsigned char)( rand() % 255 );
-}
-
diff --git a/engine/code/qcommon/cvar.c b/engine/code/qcommon/cvar.c
deleted file mode 100644
index 8bd1b27..0000000
--- a/engine/code/qcommon/cvar.c
+++ /dev/null
@@ -1,1261 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// cvar.c -- dynamic variable tracking
-
-#include "q_shared.h"
-#include "qcommon.h"
-
-cvar_t *cvar_vars = NULL;
-cvar_t *cvar_cheats;
-int cvar_modifiedFlags;
-
-#define MAX_CVARS 1024
-cvar_t cvar_indexes[MAX_CVARS];
-int cvar_numIndexes;
-
-#define FILE_HASH_SIZE 256
-static cvar_t *hashTable[FILE_HASH_SIZE];
-
-cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force);
-
-/*
-================
-return a hash value for the filename
-================
-*/
-static long generateHashValue( const char *fname ) {
- int i;
- long hash;
- char letter;
-
- hash = 0;
- i = 0;
- while (fname[i] != '\0') {
- letter = tolower(fname[i]);
- hash+=(long)(letter)*(i+119);
- i++;
- }
- hash &= (FILE_HASH_SIZE-1);
- return hash;
-}
-
-/*
-============
-Cvar_ValidateString
-============
-*/
-static qboolean Cvar_ValidateString( const char *s ) {
- if ( !s ) {
- return qfalse;
- }
- if ( strchr( s, '\\' ) ) {
- return qfalse;
- }
- if ( strchr( s, '\"' ) ) {
- return qfalse;
- }
- if ( strchr( s, ';' ) ) {
- return qfalse;
- }
- return qtrue;
-}
-
-/*
-============
-Cvar_FindVar
-============
-*/
-static cvar_t *Cvar_FindVar( const char *var_name ) {
- cvar_t *var;
- long hash;
-
- hash = generateHashValue(var_name);
-
- for (var=hashTable[hash] ; var ; var=var->hashNext) {
- if (!Q_stricmp(var_name, var->name)) {
- return var;
- }
- }
-
- return NULL;
-}
-
-/*
-============
-Cvar_VariableValue
-============
-*/
-float Cvar_VariableValue( const char *var_name ) {
- cvar_t *var;
-
- var = Cvar_FindVar (var_name);
- if (!var)
- return 0;
- return var->value;
-}
-
-
-/*
-============
-Cvar_VariableIntegerValue
-============
-*/
-int Cvar_VariableIntegerValue( const char *var_name ) {
- cvar_t *var;
-
- var = Cvar_FindVar (var_name);
- if (!var)
- return 0;
- return var->integer;
-}
-
-
-/*
-============
-Cvar_VariableString
-============
-*/
-char *Cvar_VariableString( const char *var_name ) {
- cvar_t *var;
-
- var = Cvar_FindVar (var_name);
- if (!var)
- return "";
- return var->string;
-}
-
-
-/*
-============
-Cvar_VariableStringBuffer
-============
-*/
-void Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
- cvar_t *var;
-
- var = Cvar_FindVar (var_name);
- if (!var) {
- *buffer = 0;
- }
- else {
- Q_strncpyz( buffer, var->string, bufsize );
- }
-}
-
-/*
-============
-Cvar_Flags
-============
-*/
-int Cvar_Flags(const char *var_name)
-{
- cvar_t *var;
-
- if(! (var = Cvar_FindVar(var_name)) )
- return CVAR_NONEXISTENT;
- else
- return var->flags;
-}
-
-/*
-============
-Cvar_CommandCompletion
-============
-*/
-void Cvar_CommandCompletion(void (*callback)(const char *s))
-{
- cvar_t *cvar;
-
- for(cvar = cvar_vars; cvar; cvar = cvar->next)
- {
- if(cvar->name)
- callback(cvar->name);
- }
-}
-
-/*
-============
-Cvar_Validate
-============
-*/
-static const char *Cvar_Validate( cvar_t *var,
- const char *value, qboolean warn )
-{
- static char s[ MAX_CVAR_VALUE_STRING ];
- float valuef;
- qboolean changed = qfalse;
-
- if( !var->validate )
- return value;
-
- if( !value )
- return value;
-
- if( Q_isanumber( value ) )
- {
- valuef = atof( value );
-
- if( var->integral )
- {
- if( !Q_isintegral( valuef ) )
- {
- if( warn )
- Com_Printf( "WARNING: cvar '%s' must be integral", var->name );
-
- valuef = (int)valuef;
- changed = qtrue;
- }
- }
- }
- else
- {
- if( warn )
- Com_Printf( "WARNING: cvar '%s' must be numeric", var->name );
-
- valuef = atof( var->resetString );
- changed = qtrue;
- }
-
- if( valuef < var->min )
- {
- if( warn )
- {
- if( changed )
- Com_Printf( " and is" );
- else
- Com_Printf( "WARNING: cvar '%s'", var->name );
-
- if( Q_isintegral( var->min ) )
- Com_Printf( " out of range (min %d)", (int)var->min );
- else
- Com_Printf( " out of range (min %f)", var->min );
- }
-
- valuef = var->min;
- changed = qtrue;
- }
- else if( valuef > var->max )
- {
- if( warn )
- {
- if( changed )
- Com_Printf( " and is" );
- else
- Com_Printf( "WARNING: cvar '%s'", var->name );
-
- if( Q_isintegral( var->max ) )
- Com_Printf( " out of range (max %d)", (int)var->max );
- else
- Com_Printf( " out of range (max %f)", var->max );
- }
-
- valuef = var->max;
- changed = qtrue;
- }
-
- if( changed )
- {
- if( Q_isintegral( valuef ) )
- {
- Com_sprintf( s, sizeof( s ), "%d", (int)valuef );
-
- if( warn )
- Com_Printf( ", setting to %d\n", (int)valuef );
- }
- else
- {
- Com_sprintf( s, sizeof( s ), "%f", valuef );
-
- if( warn )
- Com_Printf( ", setting to %f\n", valuef );
- }
-
- return s;
- }
- else
- return value;
-}
-
-
-/*
-============
-Cvar_Get
-
-If the variable already exists, the value will not be set unless CVAR_ROM
-The flags will be or'ed in if the variable exists.
-============
-*/
-cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
- cvar_t *var;
- long hash;
- int index;
-
- if ( !var_name || ! var_value ) {
- Com_Error( ERR_FATAL, "Cvar_Get: NULL parameter" );
- }
-
- if ( !Cvar_ValidateString( var_name ) ) {
- Com_Printf("invalid cvar name string: %s\n", var_name );
- var_name = "BADNAME";
- }
-
-#if 0 // FIXME: values with backslash happen
- if ( !Cvar_ValidateString( var_value ) ) {
- Com_Printf("invalid cvar value string: %s\n", var_value );
- var_value = "BADVALUE";
- }
-#endif
-
- var = Cvar_FindVar (var_name);
-
- if(var)
- {
- var_value = Cvar_Validate(var, var_value, qfalse);
-
- // if the C code is now specifying a variable that the user already
- // set a value for, take the new value as the reset value
- if(var->flags & CVAR_USER_CREATED)
- {
- var->flags &= ~CVAR_USER_CREATED;
- Z_Free( var->resetString );
- var->resetString = CopyString( var_value );
-
- if(flags & CVAR_ROM)
- {
- // this variable was set by the user,
- // so force it to value given by the engine.
-
- if(var->latchedString)
- Z_Free(var->latchedString);
-
- var->latchedString = CopyString(var_value);
- }
- }
-
- // Make sure the game code cannot mark engine-added variables as gamecode vars
- if(var->flags & CVAR_VM_CREATED)
- {
- if(!(flags & CVAR_VM_CREATED))
- var->flags &= ~CVAR_VM_CREATED;
- }
- else
- {
- if(flags & CVAR_VM_CREATED)
- flags &= ~CVAR_VM_CREATED;
- }
-
- var->flags |= flags;
-
- // only allow one non-empty reset string without a warning
- if ( !var->resetString[0] ) {
- // we don't have a reset string yet
- Z_Free( var->resetString );
- var->resetString = CopyString( var_value );
- } else if ( var_value[0] && strcmp( var->resetString, var_value ) ) {
- Com_DPrintf( "Warning: cvar \"%s\" given initial values: \"%s\" and \"%s\"\n",
- var_name, var->resetString, var_value );
- }
- // if we have a latched string, take that value now
- if ( var->latchedString ) {
- char *s;
-
- s = var->latchedString;
- var->latchedString = NULL; // otherwise cvar_set2 would free it
- Cvar_Set2( var_name, s, qtrue );
- Z_Free( s );
- }
-
- // ZOID--needs to be set so that cvars the game sets as
- // SERVERINFO get sent to clients
- cvar_modifiedFlags |= flags;
-
- return var;
- }
-
- //
- // allocate a new cvar
- //
-
- // find a free cvar
- for(index = 0; index < MAX_CVARS; index++)
- {
- if(!cvar_indexes[index].name)
- break;
- }
-
- if(index >= MAX_CVARS)
- {
- if(!com_errorEntered)
- Com_Error(ERR_FATAL, "Error: Too many cvars, cannot create a new one!");
-
- return NULL;
- }
-
- var = &cvar_indexes[index];
-
- if(index >= cvar_numIndexes)
- cvar_numIndexes = index + 1;
-
- var->name = CopyString (var_name);
- var->string = CopyString (var_value);
- var->modified = qtrue;
- var->modificationCount = 1;
- var->value = atof (var->string);
- var->integer = atoi(var->string);
- var->resetString = CopyString( var_value );
- var->validate = qfalse;
-
- // link the variable in
- var->next = cvar_vars;
- if(cvar_vars)
- cvar_vars->prev = var;
-
- var->prev = NULL;
- cvar_vars = var;
-
- var->flags = flags;
- // note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
- cvar_modifiedFlags |= var->flags;
-
- hash = generateHashValue(var_name);
- var->hashIndex = hash;
-
- var->hashNext = hashTable[hash];
- if(hashTable[hash])
- hashTable[hash]->hashPrev = var;
-
- var->hashPrev = NULL;
- hashTable[hash] = var;
-
- return var;
-}
-
-/*
-============
-Cvar_Print
-
-Prints the value, default, and latched string of the given variable
-============
-*/
-void Cvar_Print( cvar_t *v ) {
- Com_Printf ("\"%s\" is:\"%s" S_COLOR_WHITE "\"",
- v->name, v->string );
-
- if ( !( v->flags & CVAR_ROM ) ) {
- if ( !Q_stricmp( v->string, v->resetString ) ) {
- Com_Printf (", the default" );
- } else {
- Com_Printf (" default:\"%s" S_COLOR_WHITE "\"",
- v->resetString );
- }
- }
-
- Com_Printf ("\n");
-
- if ( v->latchedString ) {
- Com_Printf( "latched: \"%s\"\n", v->latchedString );
- }
-}
-
-/*
-============
-Cvar_Set2
-============
-*/
-cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force ) {
- cvar_t *var;
-
-// Com_DPrintf( "Cvar_Set2: %s %s\n", var_name, value );
-
- if ( !Cvar_ValidateString( var_name ) ) {
- Com_Printf("invalid cvar name string: %s\n", var_name );
- var_name = "BADNAME";
- }
-
-#if 0 // FIXME
- if ( value && !Cvar_ValidateString( value ) ) {
- Com_Printf("invalid cvar value string: %s\n", value );
- var_value = "BADVALUE";
- }
-#endif
-
- var = Cvar_FindVar (var_name);
- if (!var) {
- if ( !value ) {
- return NULL;
- }
- // create it
- if ( !force ) {
- return Cvar_Get( var_name, value, CVAR_USER_CREATED );
- } else {
- return Cvar_Get (var_name, value, 0);
- }
- }
-
- if (!value ) {
- value = var->resetString;
- }
-
- value = Cvar_Validate(var, value, qtrue);
-
- if((var->flags & CVAR_LATCH) && var->latchedString)
- {
- if(!strcmp(value, var->string))
- {
- Z_Free(var->latchedString);
- var->latchedString = NULL;
- return var;
- }
-
- if(!strcmp(value, var->latchedString))
- return var;
- }
- else if(!strcmp(value, var->string))
- return var;
-
- // note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
- cvar_modifiedFlags |= var->flags;
-
- if (!force)
- {
- if (var->flags & CVAR_ROM)
- {
- Com_Printf ("%s is read only.\n", var_name);
- return var;
- }
-
- if (var->flags & CVAR_INIT)
- {
- Com_Printf ("%s is write protected.\n", var_name);
- return var;
- }
-
- if (var->flags & CVAR_LATCH)
- {
- if (var->latchedString)
- {
- if (strcmp(value, var->latchedString) == 0)
- return var;
- Z_Free (var->latchedString);
- }
- else
- {
- if (strcmp(value, var->string) == 0)
- return var;
- }
-
- Com_Printf ("%s will be changed upon restarting.\n", var_name);
- var->latchedString = CopyString(value);
- var->modified = qtrue;
- var->modificationCount++;
- return var;
- }
-
- if ( (var->flags & CVAR_CHEAT) && !cvar_cheats->integer )
- {
- Com_Printf ("%s is cheat protected.\n", var_name);
- return var;
- }
-
- }
- else
- {
- if (var->latchedString)
- {
- Z_Free (var->latchedString);
- var->latchedString = NULL;
- }
- }
-
- if (!strcmp(value, var->string))
- return var; // not changed
-
- var->modified = qtrue;
- var->modificationCount++;
-
- Z_Free (var->string); // free the old value string
-
- var->string = CopyString(value);
- var->value = atof (var->string);
- var->integer = atoi (var->string);
-
- return var;
-}
-
-/*
-============
-Cvar_Set
-============
-*/
-void Cvar_Set( const char *var_name, const char *value) {
- Cvar_Set2 (var_name, value, qtrue);
-}
-
-/*
-============
-Cvar_SetLatched
-============
-*/
-void Cvar_SetLatched( const char *var_name, const char *value) {
- Cvar_Set2 (var_name, value, qfalse);
-}
-
-/*
-============
-Cvar_SetValue
-============
-*/
-void Cvar_SetValue( const char *var_name, float value) {
- char val[32];
-
- if ( value == (int)value ) {
- Com_sprintf (val, sizeof(val), "%i",(int)value);
- } else {
- Com_sprintf (val, sizeof(val), "%f",value);
- }
- Cvar_Set (var_name, val);
-}
-
-
-/*
-============
-Cvar_Reset
-============
-*/
-void Cvar_Reset( const char *var_name ) {
- Cvar_Set2( var_name, NULL, qfalse );
-}
-
-/*
-============
-Cvar_ForceReset
-============
-*/
-void Cvar_ForceReset(const char *var_name)
-{
- Cvar_Set2(var_name, NULL, qtrue);
-}
-
-/*
-============
-Cvar_SetCheatState
-
-Any testing variables will be reset to the safe values
-============
-*/
-void Cvar_SetCheatState(void)
-{
- cvar_t *var;
-
- // set all default vars to the safe value
- for(var = cvar_vars; var ; var = var->next)
- {
- if(var->flags & CVAR_CHEAT)
- {
- // the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here
- // because of a different var->latchedString
- if (var->latchedString)
- {
- Z_Free(var->latchedString);
- var->latchedString = NULL;
- }
- if (strcmp(var->resetString,var->string))
- Cvar_Set(var->name, var->resetString);
- }
- }
-}
-
-/*
-============
-Cvar_Command
-
-Handles variable inspection and changing from the console
-============
-*/
-qboolean Cvar_Command( void ) {
- cvar_t *v;
-
- // check variables
- v = Cvar_FindVar (Cmd_Argv(0));
- if (!v) {
- return qfalse;
- }
-
- // perform a variable print or set
- if ( Cmd_Argc() == 1 ) {
- Cvar_Print( v );
- return qtrue;
- }
-
- // set the value if forcing isn't required
- Cvar_Set2 (v->name, Cmd_Args(), qfalse);
- return qtrue;
-}
-
-
-/*
-============
-Cvar_Print_f
-
-Prints the contents of a cvar
-(preferred over Cvar_Command where cvar names and commands conflict)
-============
-*/
-void Cvar_Print_f(void)
-{
- char *name;
- cvar_t *cv;
-
- if(Cmd_Argc() != 2)
- {
- Com_Printf ("usage: print <variable>\n");
- return;
- }
-
- name = Cmd_Argv(1);
-
- cv = Cvar_FindVar(name);
-
- if(cv)
- Cvar_Print(cv);
- else
- Com_Printf ("Cvar %s does not exist.\n", name);
-}
-
-/*
-============
-Cvar_Toggle_f
-
-Toggles a cvar for easy single key binding, optionally through a list of
-given values
-============
-*/
-void Cvar_Toggle_f( void ) {
- int i, c = Cmd_Argc();
- char *curval;
-
- if(c < 2) {
- Com_Printf("usage: toggle <variable> [value1, value2, ...]\n");
- return;
- }
-
- if(c == 2) {
- Cvar_Set2(Cmd_Argv(1), va("%d",
- !Cvar_VariableValue(Cmd_Argv(1))),
- qfalse);
- return;
- }
-
- if(c == 3) {
- Com_Printf("toggle: nothing to toggle to\n");
- return;
- }
-
- curval = Cvar_VariableString(Cmd_Argv(1));
-
- // don't bother checking the last arg for a match since the desired
- // behaviour is the same as no match (set to the first argument)
- for(i = 2; i + 1 < c; i++) {
- if(strcmp(curval, Cmd_Argv(i)) == 0) {
- Cvar_Set2(Cmd_Argv(1), Cmd_Argv(i + 1), qfalse);
- return;
- }
- }
-
- // fallback
- Cvar_Set2(Cmd_Argv(1), Cmd_Argv(2), qfalse);
-}
-
-/*
-============
-Cvar_Set_f
-
-Allows setting and defining of arbitrary cvars from console, even if they
-weren't declared in C code.
-============
-*/
-void Cvar_Set_f( void ) {
- int c;
- char *cmd;
- cvar_t *v;
-
- c = Cmd_Argc();
- cmd = Cmd_Argv(0);
-
- if ( c < 2 ) {
- Com_Printf ("usage: %s <variable> <value>\n", cmd);
- return;
- }
- if ( c == 2 ) {
- Cvar_Print_f();
- return;
- }
-
- v = Cvar_Set2 (Cmd_Argv(1), Cmd_ArgsFrom(2), qfalse);
- if( !v ) {
- return;
- }
- switch( cmd[3] ) {
- case 'a':
- if( !( v->flags & CVAR_ARCHIVE ) ) {
- v->flags |= CVAR_ARCHIVE;
- cvar_modifiedFlags |= CVAR_ARCHIVE;
- }
- break;
- case 'u':
- if( !( v->flags & CVAR_USERINFO ) ) {
- v->flags |= CVAR_USERINFO;
- cvar_modifiedFlags |= CVAR_USERINFO;
- }
- break;
- case 's':
- if( !( v->flags & CVAR_SERVERINFO ) ) {
- v->flags |= CVAR_SERVERINFO;
- cvar_modifiedFlags |= CVAR_SERVERINFO;
- }
- break;
- }
-}
-
-/*
-============
-Cvar_Reset_f
-============
-*/
-void Cvar_Reset_f( void ) {
- if ( Cmd_Argc() != 2 ) {
- Com_Printf ("usage: reset <variable>\n");
- return;
- }
- Cvar_Reset( Cmd_Argv( 1 ) );
-}
-
-/*
-============
-Cvar_WriteVariables
-
-Appends lines containing "set variable value" for all variables
-with the archive flag set to qtrue.
-============
-*/
-void Cvar_WriteVariables(fileHandle_t f)
-{
- cvar_t *var;
- char buffer[1024];
-
- for (var = cvar_vars; var; var = var->next)
- {
- if(!var->name || Q_stricmp( var->name, "cl_cdkey" ) == 0)
- continue;
-
- if( var->flags & CVAR_ARCHIVE ) {
- // write the latched value, even if it hasn't taken effect yet
- if ( var->latchedString ) {
- if( strlen( var->name ) + strlen( var->latchedString ) + 10 > sizeof( buffer ) ) {
- Com_Printf( S_COLOR_YELLOW "WARNING: value of variable "
- "\"%s\" too long to write to file\n", var->name );
- continue;
- }
- Com_sprintf (buffer, sizeof(buffer), "seta %s \"%s\"\n", var->name, var->latchedString);
- } else {
- if( strlen( var->name ) + strlen( var->string ) + 10 > sizeof( buffer ) ) {
- Com_Printf( S_COLOR_YELLOW "WARNING: value of variable "
- "\"%s\" too long to write to file\n", var->name );
- continue;
- }
- Com_sprintf (buffer, sizeof(buffer), "seta %s \"%s\"\n", var->name, var->string);
- }
- FS_Write( buffer, strlen( buffer ), f );
- }
- }
-}
-
-/*
-============
-Cvar_List_f
-============
-*/
-void Cvar_List_f( void ) {
- cvar_t *var;
- int i;
- char *match;
-
- if ( Cmd_Argc() > 1 ) {
- match = Cmd_Argv( 1 );
- } else {
- match = NULL;
- }
-
- i = 0;
- for (var = cvar_vars ; var ; var = var->next, i++)
- {
- if(!var->name || (match && !Com_Filter(match, var->name, qfalse)))
- continue;
-
- if (var->flags & CVAR_SERVERINFO) {
- Com_Printf("S");
- } else {
- Com_Printf(" ");
- }
- if (var->flags & CVAR_SYSTEMINFO) {
- Com_Printf("s");
- } else {
- Com_Printf(" ");
- }
- if (var->flags & CVAR_USERINFO) {
- Com_Printf("U");
- } else {
- Com_Printf(" ");
- }
- if (var->flags & CVAR_ROM) {
- Com_Printf("R");
- } else {
- Com_Printf(" ");
- }
- if (var->flags & CVAR_INIT) {
- Com_Printf("I");
- } else {
- Com_Printf(" ");
- }
- if (var->flags & CVAR_ARCHIVE) {
- Com_Printf("A");
- } else {
- Com_Printf(" ");
- }
- if (var->flags & CVAR_LATCH) {
- Com_Printf("L");
- } else {
- Com_Printf(" ");
- }
- if (var->flags & CVAR_CHEAT) {
- Com_Printf("C");
- } else {
- Com_Printf(" ");
- }
- if (var->flags & CVAR_USER_CREATED) {
- Com_Printf("?");
- } else {
- Com_Printf(" ");
- }
-
- Com_Printf (" %s \"%s\"\n", var->name, var->string);
- }
-
- Com_Printf ("\n%i total cvars\n", i);
- Com_Printf ("%i cvar indexes\n", cvar_numIndexes);
-}
-
-/*
-============
-Cvar_Unset
-
-Unsets a cvar
-============
-*/
-
-cvar_t *Cvar_Unset(cvar_t *cv)
-{
- cvar_t *next = cv->next;
-
- if(cv->name)
- Z_Free(cv->name);
- if(cv->string)
- Z_Free(cv->string);
- if(cv->latchedString)
- Z_Free(cv->latchedString);
- if(cv->resetString)
- Z_Free(cv->resetString);
-
- if(cv->prev)
- cv->prev->next = cv->next;
- else
- cvar_vars = cv->next;
- if(cv->next)
- cv->next->prev = cv->prev;
-
- if(cv->hashPrev)
- cv->hashPrev->hashNext = cv->hashNext;
- else
- hashTable[cv->hashIndex] = cv->hashNext;
- if(cv->hashNext)
- cv->hashNext->hashPrev = cv->hashPrev;
-
- Com_Memset(cv, '\0', sizeof(*cv));
-
- return next;
-}
-
-/*
-============
-Cvar_Unset_f
-
-Unsets a userdefined cvar
-============
-*/
-
-void Cvar_Unset_f(void)
-{
- cvar_t *cv;
-
- if(Cmd_Argc() != 2)
- {
- Com_Printf("Usage: %s <varname>\n", Cmd_Argv(0));
- return;
- }
-
- cv = Cvar_FindVar(Cmd_Argv(1));
-
- if(!cv)
- return;
-
- if(cv->flags & CVAR_USER_CREATED)
- Cvar_Unset(cv);
- else
- Com_Printf("Error: %s: Variable %s is not user created.\n", Cmd_Argv(0), cv->name);
-}
-
-
-
-/*
-============
-Cvar_Restart
-
-Resets all cvars to their hardcoded values and removes userdefined variables
-and variables added via the VMs if requested.
-============
-*/
-
-void Cvar_Restart(qboolean unsetVM)
-{
- cvar_t *curvar;
-
- curvar = cvar_vars;
-
- while(curvar)
- {
- if((curvar->flags & CVAR_USER_CREATED) ||
- (unsetVM && (curvar->flags & CVAR_VM_CREATED)))
- {
- // throw out any variables the user/vm created
- curvar = Cvar_Unset(curvar);
- continue;
- }
-
- if(!(curvar->flags & (CVAR_ROM | CVAR_INIT | CVAR_NORESTART)))
- {
- // Just reset the rest to their default values.
- Cvar_Set2(curvar->name, curvar->resetString, qfalse);
- }
-
- curvar = curvar->next;
- }
-}
-
-
-/*
-============
-Cvar_Restart_f
-
-Resets all cvars to their hardcoded values
-============
-*/
-void Cvar_Restart_f(void)
-{
- Cvar_Restart(qfalse);
-}
-
-/*
-=====================
-Cvar_InfoString
-=====================
-*/
-char *Cvar_InfoString(int bit)
-{
- static char info[MAX_INFO_STRING];
- cvar_t *var;
-
- info[0] = 0;
-
- for(var = cvar_vars; var; var = var->next)
- {
- if(var->name && (var->flags & bit))
- Info_SetValueForKey (info, var->name, var->string);
- }
-
- return info;
-}
-
-/*
-=====================
-Cvar_InfoString_Big
-
- handles large info strings ( CS_SYSTEMINFO )
-=====================
-*/
-char *Cvar_InfoString_Big(int bit)
-{
- static char info[BIG_INFO_STRING];
- cvar_t *var;
-
- info[0] = 0;
-
- for (var = cvar_vars; var; var = var->next)
- {
- if(var->name && (var->flags & bit))
- Info_SetValueForKey_Big (info, var->name, var->string);
- }
- return info;
-}
-
-
-
-/*
-=====================
-Cvar_InfoStringBuffer
-=====================
-*/
-void Cvar_InfoStringBuffer( int bit, char* buff, int buffsize ) {
- Q_strncpyz(buff,Cvar_InfoString(bit),buffsize);
-}
-
-/*
-=====================
-Cvar_CheckRange
-=====================
-*/
-void Cvar_CheckRange( cvar_t *var, float min, float max, qboolean integral )
-{
- var->validate = qtrue;
- var->min = min;
- var->max = max;
- var->integral = integral;
-
- // Force an initial range check
- Cvar_Set( var->name, var->string );
-}
-
-/*
-=====================
-Cvar_Register
-
-basically a slightly modified Cvar_Get for the interpreted modules
-=====================
-*/
-void Cvar_Register(vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags)
-{
- cvar_t *cv;
-
- cv = Cvar_Get(varName, defaultValue, flags | CVAR_VM_CREATED);
-
- if (!vmCvar)
- return;
-
- vmCvar->handle = cv - cvar_indexes;
- vmCvar->modificationCount = -1;
- Cvar_Update( vmCvar );
-}
-
-
-/*
-=====================
-Cvar_Update
-
-updates an interpreted modules' version of a cvar
-=====================
-*/
-void Cvar_Update( vmCvar_t *vmCvar ) {
- cvar_t *cv = NULL;
- assert(vmCvar);
-
- if ( (unsigned)vmCvar->handle >= cvar_numIndexes ) {
- Com_Error( ERR_DROP, "Cvar_Update: handle out of range" );
- }
-
- cv = cvar_indexes + vmCvar->handle;
-
- if ( cv->modificationCount == vmCvar->modificationCount ) {
- return;
- }
- if ( !cv->string ) {
- return; // variable might have been cleared by a cvar_restart
- }
- vmCvar->modificationCount = cv->modificationCount;
- if ( strlen(cv->string)+1 > MAX_CVAR_VALUE_STRING )
- Com_Error( ERR_DROP, "Cvar_Update: src %s length %zd exceeds MAX_CVAR_VALUE_STRING",
- cv->string,
- strlen(cv->string));
- Q_strncpyz( vmCvar->string, cv->string, MAX_CVAR_VALUE_STRING );
-
- vmCvar->value = cv->value;
- vmCvar->integer = cv->integer;
-}
-
-/*
-==================
-Cvar_CompleteCvarName
-==================
-*/
-void Cvar_CompleteCvarName( char *args, int argNum )
-{
- if( argNum == 2 )
- {
- // Skip "<cmd> "
- char *p = Com_SkipTokens( args, 1, " " );
-
- if( p > args )
- Field_CompleteCommand( p, qfalse, qtrue );
- }
-}
-
-/*
-============
-Cvar_Init
-
-Reads in all archived cvars
-============
-*/
-void Cvar_Init (void)
-{
- Com_Memset(cvar_indexes, '\0', sizeof(cvar_indexes));
- Com_Memset(hashTable, '\0', sizeof(hashTable));
-
- cvar_cheats = Cvar_Get("sv_cheats", "1", CVAR_ROM | CVAR_SYSTEMINFO );
-
- Cmd_AddCommand ("print", Cvar_Print_f);
- Cmd_AddCommand ("toggle", Cvar_Toggle_f);
- Cmd_SetCommandCompletionFunc( "toggle", Cvar_CompleteCvarName );
- Cmd_AddCommand ("set", Cvar_Set_f);
- Cmd_SetCommandCompletionFunc( "set", Cvar_CompleteCvarName );
- Cmd_AddCommand ("sets", Cvar_Set_f);
- Cmd_SetCommandCompletionFunc( "sets", Cvar_CompleteCvarName );
- Cmd_AddCommand ("setu", Cvar_Set_f);
- Cmd_SetCommandCompletionFunc( "setu", Cvar_CompleteCvarName );
- Cmd_AddCommand ("seta", Cvar_Set_f);
- Cmd_SetCommandCompletionFunc( "seta", Cvar_CompleteCvarName );
- Cmd_AddCommand ("reset", Cvar_Reset_f);
- Cmd_SetCommandCompletionFunc( "reset", Cvar_CompleteCvarName );
- Cmd_AddCommand ("unset", Cvar_Unset_f);
- Cmd_SetCommandCompletionFunc("unset", Cvar_CompleteCvarName);
-
- Cmd_AddCommand ("cvarlist", Cvar_List_f);
- Cmd_AddCommand ("cvar_restart", Cvar_Restart_f);
-}
diff --git a/engine/code/qcommon/files.c b/engine/code/qcommon/files.c
deleted file mode 100644
index 0b4a783..0000000
--- a/engine/code/qcommon/files.c
+++ /dev/null
@@ -1,3556 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-/*****************************************************************************
- * name: files.c
- *
- * desc: handle based filesystem for Quake III Arena
- *
- * $Archive: /MissionPack/code/qcommon/files.c $
- *
- *****************************************************************************/
-
-
-#include "q_shared.h"
-#include "qcommon.h"
-#include "unzip.h"
-
-/*
-=============================================================================
-
-QUAKE3 FILESYSTEM
-
-All of Quake's data access is through a hierarchical file system, but the contents of
-the file system can be transparently merged from several sources.
-
-A "qpath" is a reference to game file data. MAX_ZPATH is 256 characters, which must include
-a terminating zero. "..", "\\", and ":" are explicitly illegal in qpaths to prevent any
-references outside the quake directory system.
-
-The "base path" is the path to the directory holding all the game directories and usually
-the executable. It defaults to ".", but can be overridden with a "+set fs_basepath c:\quake3"
-command line to allow code debugging in a different directory. Basepath cannot
-be modified at all after startup. Any files that are created (demos, screenshots,
-etc) will be created reletive to the base path, so base path should usually be writable.
-
-The "home path" is the path used for all write access. On win32 systems we have "base path"
-== "home path", but on *nix systems the base installation is usually readonly, and
-"home path" points to ~/.q3a or similar
-
-The user can also install custom mods and content in "home path", so it should be searched
-along with "home path" and "cd path" for game content.
-
-
-The "base game" is the directory under the paths where data comes from by default, and
-can be either "baseq3" or "demoq3".
-
-The "current game" may be the same as the base game, or it may be the name of another
-directory under the paths that should be searched for files before looking in the base game.
-This is the basis for addons.
-
-Clients automatically set the game directory after receiving a gamestate from a server,
-so only servers need to worry about +set fs_game.
-
-No other directories outside of the base game and current game will ever be referenced by
-filesystem functions.
-
-To save disk space and speed loading, directory trees can be collapsed into zip files.
-The files use a ".pk3" extension to prevent users from unzipping them accidentally, but
-otherwise the are simply normal uncompressed zip files. A game directory can have multiple
-zip files of the form "pak0.pk3", "pak1.pk3", etc. Zip files are searched in decending order
-from the highest number to the lowest, and will always take precedence over the filesystem.
-This allows a pk3 distributed as a patch to override all existing data.
-
-Because we will have updated executables freely available online, there is no point to
-trying to restrict demo / oem versions of the game with code changes. Demo / oem versions
-should be exactly the same executables as release versions, but with different data that
-automatically restricts where game media can come from to prevent add-ons from working.
-
-File search order: when FS_FOpenFileRead gets called it will go through the fs_searchpaths
-structure and stop on the first successful hit. fs_searchpaths is built with successive
-calls to FS_AddGameDirectory
-
-Additionaly, we search in several subdirectories:
-current game is the current mode
-base game is a variable to allow mods based on other mods
-(such as baseq3 + missionpack content combination in a mod for instance)
-BASEGAME is the hardcoded base game ("baseq3")
-
-e.g. the qpath "sound/newstuff/test.wav" would be searched for in the following places:
-
-home path + current game's zip files
-home path + current game's directory
-base path + current game's zip files
-base path + current game's directory
-cd path + current game's zip files
-cd path + current game's directory
-
-home path + base game's zip file
-home path + base game's directory
-base path + base game's zip file
-base path + base game's directory
-cd path + base game's zip file
-cd path + base game's directory
-
-home path + BASEGAME's zip file
-home path + BASEGAME's directory
-base path + BASEGAME's zip file
-base path + BASEGAME's directory
-cd path + BASEGAME's zip file
-cd path + BASEGAME's directory
-
-server download, to be written to home path + current game's directory
-
-
-The filesystem can be safely shutdown and reinitialized with different
-basedir / cddir / game combinations, but all other subsystems that rely on it
-(sound, video) must also be forced to restart.
-
-Because the same files are loaded by both the clip model (CM_) and renderer (TR_)
-subsystems, a simple single-file caching scheme is used. The CM_ subsystems will
-load the file with a request to cache. Only one file will be kept cached at a time,
-so any models that are going to be referenced by both subsystems should alternate
-between the CM_ load function and the ref load function.
-
-TODO: A qpath that starts with a leading slash will always refer to the base game, even if another
-game is currently active. This allows character models, skins, and sounds to be downloaded
-to a common directory no matter which game is active.
-
-How to prevent downloading zip files?
-Pass pk3 file names in systeminfo, and download before FS_Restart()?
-
-Aborting a download disconnects the client from the server.
-
-How to mark files as downloadable? Commercial add-ons won't be downloadable.
-
-Non-commercial downloads will want to download the entire zip file.
-the game would have to be reset to actually read the zip in
-
-Auto-update information
-
-Path separators
-
-Casing
-
- separate server gamedir and client gamedir, so if the user starts
- a local game after having connected to a network game, it won't stick
- with the network game.
-
- allow menu options for game selection?
-
-Read / write config to floppy option.
-
-Different version coexistance?
-
-When building a pak file, make sure a q3config.cfg isn't present in it,
-or configs will never get loaded from disk!
-
- todo:
-
- downloading (outside fs?)
- game directory passing and restarting
-
-=============================================================================
-
-*/
-
-// every time a new demo pk3 file is built, this checksum must be updated.
-// the easiest way to get it is to just run the game and see what it spits out
-#define DEMO_PAK0_CHECKSUM 2985612116u
-static const unsigned pak_checksums[] = {
- 1566731103u,
- 298122907u,
- 412165236u,
- 2991495316u,
- 1197932710u,
- 4087071573u,
- 3709064859u,
- 908855077u,
- 977125798u
-};
-
-// if this is defined, the executable positively won't work with any paks other
-// than the demo pak, even if productid is present. This is only used for our
-// last demo release to prevent the mac and linux users from using the demo
-// executable with the production windows pak before the mac/linux products
-// hit the shelves a little later
-// NOW defined in build files
-//#define PRE_RELEASE_TADEMO
-
-#define MAX_ZPATH 256
-#define MAX_SEARCH_PATHS 4096
-#define MAX_FILEHASH_SIZE 1024
-
-typedef struct fileInPack_s {
- char *name; // name of the file
- unsigned long pos; // file info position in zip
- unsigned long len; // uncompress file size
- struct fileInPack_s* next; // next file in the hash
-} fileInPack_t;
-
-typedef struct {
- char pakFilename[MAX_OSPATH]; // c:\quake3\baseq3\pak0.pk3
- char pakBasename[MAX_OSPATH]; // pak0
- char pakGamename[MAX_OSPATH]; // baseq3
- unzFile handle; // handle to zip file
- int checksum; // regular checksum
- int pure_checksum; // checksum for pure
- int numfiles; // number of files in pk3
- int referenced; // referenced file flags
- int hashSize; // hash table size (power of 2)
- fileInPack_t* *hashTable; // hash table
- fileInPack_t* buildBuffer; // buffer with the filenames etc.
-} pack_t;
-
-typedef struct {
- char path[MAX_OSPATH]; // c:\quake3
- char gamedir[MAX_OSPATH]; // baseq3
-} directory_t;
-
-typedef struct searchpath_s {
- struct searchpath_s *next;
-
- pack_t *pack; // only one of pack / dir will be non NULL
- directory_t *dir;
-} searchpath_t;
-
-static char fs_gamedir[MAX_OSPATH]; // this will be a single file name with no separators
-static cvar_t *fs_debug;
-static cvar_t *fs_homepath;
-
-#ifdef MACOS_X
-// Also search the .app bundle for .pk3 files
-static cvar_t *fs_apppath;
-#endif
-
-static cvar_t *fs_basepath;
-static cvar_t *fs_basegame;
-static cvar_t *fs_gamedirvar;
-static searchpath_t *fs_searchpaths;
-static int fs_readCount; // total bytes read
-static int fs_loadCount; // total files read
-static int fs_loadStack; // total files in memory
-static int fs_packFiles = 0; // total number of files in packs
-
-static int fs_checksumFeed;
-
-typedef union qfile_gus {
- FILE* o;
- unzFile z;
-} qfile_gut;
-
-typedef struct qfile_us {
- qfile_gut file;
- qboolean unique;
-} qfile_ut;
-
-typedef struct {
- qfile_ut handleFiles;
- qboolean handleSync;
- int baseOffset;
- int fileSize;
- int zipFilePos;
- qboolean zipFile;
- qboolean streamed;
- char name[MAX_ZPATH];
-} fileHandleData_t;
-
-static fileHandleData_t fsh[MAX_FILE_HANDLES];
-
-// TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=540
-// wether we did a reorder on the current search path when joining the server
-static qboolean fs_reordered;
-
-// never load anything from pk3 files that are not present at the server when pure
-static int fs_numServerPaks = 0;
-static int fs_serverPaks[MAX_SEARCH_PATHS]; // checksums
-static char *fs_serverPakNames[MAX_SEARCH_PATHS]; // pk3 names
-
-// only used for autodownload, to make sure the client has at least
-// all the pk3 files that are referenced at the server side
-static int fs_numServerReferencedPaks;
-static int fs_serverReferencedPaks[MAX_SEARCH_PATHS]; // checksums
-static char *fs_serverReferencedPakNames[MAX_SEARCH_PATHS]; // pk3 names
-
-// last valid game folder used
-char lastValidBase[MAX_OSPATH];
-char lastValidGame[MAX_OSPATH];
-
-#ifdef FS_MISSING
-FILE* missingFiles = NULL;
-#endif
-
-/* C99 defines __func__ */
-#ifndef __func__
-#define __func__ "(unknown)"
-#endif
-
-/*
-==============
-FS_Initialized
-==============
-*/
-
-qboolean FS_Initialized( void ) {
- return (fs_searchpaths != NULL);
-}
-
-/*
-=================
-FS_PakIsPure
-=================
-*/
-qboolean FS_PakIsPure( pack_t *pack ) {
- int i;
-
- if ( fs_numServerPaks ) {
- for ( i = 0 ; i < fs_numServerPaks ; i++ ) {
- // FIXME: also use hashed file names
- // NOTE TTimo: a pk3 with same checksum but different name would be validated too
- // I don't see this as allowing for any exploit, it would only happen if the client does manips of it's file names 'not a bug'
- if ( pack->checksum == fs_serverPaks[i] ) {
- return qtrue; // on the aproved list
- }
- }
- return qfalse; // not on the pure server pak list
- }
- return qtrue;
-}
-
-
-/*
-=================
-FS_LoadStack
-return load stack
-=================
-*/
-int FS_LoadStack( void )
-{
- return fs_loadStack;
-}
-
-/*
-================
-return a hash value for the filename
-================
-*/
-static long FS_HashFileName( const char *fname, int hashSize ) {
- int i;
- long hash;
- char letter;
-
- hash = 0;
- i = 0;
- while (fname[i] != '\0') {
- letter = tolower(fname[i]);
- if (letter =='.') break; // don't include extension
- if (letter =='\\') letter = '/'; // damn path names
- if (letter == PATH_SEP) letter = '/'; // damn path names
- hash+=(long)(letter)*(i+119);
- i++;
- }
- hash = (hash ^ (hash >> 10) ^ (hash >> 20));
- hash &= (hashSize-1);
- return hash;
-}
-
-static fileHandle_t FS_HandleForFile(void) {
- int i;
-
- for ( i = 1 ; i < MAX_FILE_HANDLES ; i++ ) {
- if ( fsh[i].handleFiles.file.o == NULL ) {
- return i;
- }
- }
- Com_Error( ERR_DROP, "FS_HandleForFile: none free" );
- return 0;
-}
-
-static FILE *FS_FileForHandle( fileHandle_t f ) {
- if ( f < 0 || f > MAX_FILE_HANDLES ) {
- Com_Error( ERR_DROP, "FS_FileForHandle: out of range" );
- }
- if (fsh[f].zipFile == qtrue) {
- Com_Error( ERR_DROP, "FS_FileForHandle: can't get FILE on zip file" );
- }
- if ( ! fsh[f].handleFiles.file.o ) {
- Com_Error( ERR_DROP, "FS_FileForHandle: NULL" );
- }
-
- return fsh[f].handleFiles.file.o;
-}
-
-void FS_ForceFlush( fileHandle_t f ) {
- FILE *file;
-
- file = FS_FileForHandle(f);
- setvbuf( file, NULL, _IONBF, 0 );
-}
-
-/*
-================
-FS_filelength
-
-If this is called on a non-unique FILE (from a pak file),
-it will return the size of the pak file, not the expected
-size of the file.
-================
-*/
-int FS_filelength( fileHandle_t f ) {
- int pos;
- int end;
- FILE* h;
-
- h = FS_FileForHandle(f);
- pos = ftell (h);
- fseek (h, 0, SEEK_END);
- end = ftell (h);
- fseek (h, pos, SEEK_SET);
-
- return end;
-}
-
-/*
-====================
-FS_ReplaceSeparators
-
-Fix things up differently for win/unix/mac
-====================
-*/
-static void FS_ReplaceSeparators( char *path ) {
- char *s;
- qboolean lastCharWasSep = qfalse;
-
- for ( s = path ; *s ; s++ ) {
- if ( *s == '/' || *s == '\\' ) {
- if ( !lastCharWasSep ) {
- *s = PATH_SEP;
- lastCharWasSep = qtrue;
- } else {
- memmove (s, s + 1, strlen (s));
- }
- } else {
- lastCharWasSep = qfalse;
- }
- }
-}
-
-/*
-===================
-FS_BuildOSPath
-
-Qpath may have either forward or backwards slashes
-===================
-*/
-char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ) {
- char temp[MAX_OSPATH];
- static char ospath[2][MAX_OSPATH];
- static int toggle;
-
- toggle ^= 1; // flip-flop to allow two returns without clash
-
- if( !game || !game[0] ) {
- game = fs_gamedir;
- }
-
- Com_sprintf( temp, sizeof(temp), "/%s/%s", game, qpath );
- FS_ReplaceSeparators( temp );
- Com_sprintf( ospath[toggle], sizeof( ospath[0] ), "%s%s", base, temp );
-
- return ospath[toggle];
-}
-
-
-/*
-============
-FS_CreatePath
-
-Creates any directories needed to store the given filename
-============
-*/
-qboolean FS_CreatePath (char *OSPath) {
- char *ofs;
- char path[MAX_OSPATH];
-
- // make absolutely sure that it can't back up the path
- // FIXME: is c: allowed???
- if ( strstr( OSPath, ".." ) || strstr( OSPath, "::" ) ) {
- Com_Printf( "WARNING: refusing to create relative path \"%s\"\n", OSPath );
- return qtrue;
- }
-
- Q_strncpyz( path, OSPath, sizeof( path ) );
- FS_ReplaceSeparators( path );
-
- // Skip creation of the root directory as it will always be there
- ofs = strchr( path, PATH_SEP );
- ofs++;
-
- for (; ofs != NULL && *ofs ; ofs++) {
- if (*ofs == PATH_SEP) {
- // create the directory
- *ofs = 0;
- if (!Sys_Mkdir (path)) {
- Com_Error( ERR_FATAL, "FS_CreatePath: failed to create path \"%s\"\n",
- path );
- }
- *ofs = PATH_SEP;
- }
- }
-
- return qfalse;
-}
-
-/*
-=================
-FS_CheckFilenameIsNotExecutable
-
-ERR_FATAL if trying to maniuplate a file with the platform library extension
-=================
- */
-static void FS_CheckFilenameIsNotExecutable( const char *filename,
- const char *function )
-{
- // Check if the filename ends with the library extension
- if( !Q_stricmp( COM_GetExtension( filename ), DLL_EXT ) )
- {
- Com_Error( ERR_FATAL, "%s: Not allowed to manipulate '%s' due "
- "to %s extension\n", function, filename, DLL_EXT );
- }
-}
-
-
-/*
-=================
-FS_CopyFile
-
-Copy a fully specified file from one place to another
-=================
-*/
-static void FS_CopyFile( char *fromOSPath, char *toOSPath ) {
- FILE *f;
- int len;
- byte *buf;
-
- Com_Printf( "copy %s to %s\n", fromOSPath, toOSPath );
-
- FS_CheckFilenameIsNotExecutable( toOSPath, __func__ );
-
- if (strstr(fromOSPath, "journal.dat") || strstr(fromOSPath, "journaldata.dat")) {
- Com_Printf( "Ignoring journal files\n");
- return;
- }
-
- f = fopen( fromOSPath, "rb" );
- if ( !f ) {
- return;
- }
- fseek (f, 0, SEEK_END);
- len = ftell (f);
- fseek (f, 0, SEEK_SET);
-
- // we are using direct malloc instead of Z_Malloc here, so it
- // probably won't work on a mac... Its only for developers anyway...
- buf = malloc( len );
- if (fread( buf, 1, len, f ) != len)
- Com_Error( ERR_FATAL, "Short read in FS_Copyfiles()\n" );
- fclose( f );
-
- if( FS_CreatePath( toOSPath ) ) {
- return;
- }
-
- f = fopen( toOSPath, "wb" );
- if ( !f ) {
- return;
- }
- if (fwrite( buf, 1, len, f ) != len)
- Com_Error( ERR_FATAL, "Short write in FS_Copyfiles()\n" );
- fclose( f );
- free( buf );
-}
-
-/*
-===========
-FS_Remove
-
-===========
-*/
-void FS_Remove( const char *osPath ) {
- FS_CheckFilenameIsNotExecutable( osPath, __func__ );
-
- remove( osPath );
-}
-
-/*
-===========
-FS_HomeRemove
-
-===========
-*/
-void FS_HomeRemove( const char *homePath ) {
- FS_CheckFilenameIsNotExecutable( homePath, __func__ );
-
- remove( FS_BuildOSPath( fs_homepath->string,
- fs_gamedir, homePath ) );
-}
-
-/*
-================
-FS_FileExists
-
-Tests if the file exists in the current gamedir, this DOES NOT
-search the paths. This is to determine if opening a file to write
-(which always goes into the current gamedir) will cause any overwrites.
-NOTE TTimo: this goes with FS_FOpenFileWrite for opening the file afterwards
-================
-*/
-qboolean FS_FileExists( const char *file )
-{
- FILE *f;
- char *testpath;
-
- testpath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, file );
-
- f = fopen( testpath, "rb" );
- if (f) {
- fclose( f );
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-================
-FS_SV_FileExists
-
-Tests if the file exists
-================
-*/
-qboolean FS_SV_FileExists( const char *file )
-{
- FILE *f;
- char *testpath;
-
- testpath = FS_BuildOSPath( fs_homepath->string, file, "");
- testpath[strlen(testpath)-1] = '\0';
-
- f = fopen( testpath, "rb" );
- if (f) {
- fclose( f );
- return qtrue;
- }
- return qfalse;
-}
-
-
-/*
-===========
-FS_SV_FOpenFileWrite
-
-===========
-*/
-fileHandle_t FS_SV_FOpenFileWrite( const char *filename ) {
- char *ospath;
- fileHandle_t f;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- ospath = FS_BuildOSPath( fs_homepath->string, filename, "" );
- ospath[strlen(ospath)-1] = '\0';
-
- f = FS_HandleForFile();
- fsh[f].zipFile = qfalse;
-
- if ( fs_debug->integer ) {
- Com_Printf( "FS_SV_FOpenFileWrite: %s\n", ospath );
- }
-
- FS_CheckFilenameIsNotExecutable( ospath, __func__ );
-
- if( FS_CreatePath( ospath ) ) {
- return 0;
- }
-
- Com_DPrintf( "writing to: %s\n", ospath );
- fsh[f].handleFiles.file.o = fopen( ospath, "wb" );
-
- Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );
-
- fsh[f].handleSync = qfalse;
- if (!fsh[f].handleFiles.file.o) {
- f = 0;
- }
- return f;
-}
-
-/*
-===========
-FS_SV_FOpenFileRead
-
-Search for a file somewhere below the home path then base path
-in that order
-===========
-*/
-int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ) {
- char *ospath;
- fileHandle_t f = 0;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- f = FS_HandleForFile();
- fsh[f].zipFile = qfalse;
-
- Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );
-
- // don't let sound stutter
- S_ClearSoundBuffer();
-
- // search homepath
- ospath = FS_BuildOSPath( fs_homepath->string, filename, "" );
- // remove trailing slash
- ospath[strlen(ospath)-1] = '\0';
-
- if ( fs_debug->integer ) {
- Com_Printf( "FS_SV_FOpenFileRead (fs_homepath): %s\n", ospath );
- }
-
- fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
- fsh[f].handleSync = qfalse;
- if (!fsh[f].handleFiles.file.o)
- {
- // If fs_homepath == fs_basepath, don't bother
- if (Q_stricmp(fs_homepath->string,fs_basepath->string))
- {
- // search basepath
- ospath = FS_BuildOSPath( fs_basepath->string, filename, "" );
- ospath[strlen(ospath)-1] = '\0';
-
- if ( fs_debug->integer )
- {
- Com_Printf( "FS_SV_FOpenFileRead (fs_basepath): %s\n", ospath );
- }
-
- fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
- fsh[f].handleSync = qfalse;
- }
-
- if ( !fsh[f].handleFiles.file.o )
- {
- f = 0;
- }
- }
-
- *fp = f;
- if (f) {
- return FS_filelength(f);
- }
-
- return -1;
-}
-
-
-/*
-===========
-FS_SV_Rename
-
-===========
-*/
-void FS_SV_Rename( const char *from, const char *to ) {
- char *from_ospath, *to_ospath;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- // don't let sound stutter
- S_ClearSoundBuffer();
-
- from_ospath = FS_BuildOSPath( fs_homepath->string, from, "" );
- to_ospath = FS_BuildOSPath( fs_homepath->string, to, "" );
- from_ospath[strlen(from_ospath)-1] = '\0';
- to_ospath[strlen(to_ospath)-1] = '\0';
-
- if ( fs_debug->integer ) {
- Com_Printf( "FS_SV_Rename: %s --> %s\n", from_ospath, to_ospath );
- }
-
- FS_CheckFilenameIsNotExecutable( to_ospath, __func__ );
-
- if (rename( from_ospath, to_ospath )) {
- // Failed, try copying it and deleting the original
- FS_CopyFile ( from_ospath, to_ospath );
- FS_Remove ( from_ospath );
- }
-}
-
-
-
-/*
-===========
-FS_Rename
-
-===========
-*/
-void FS_Rename( const char *from, const char *to ) {
- char *from_ospath, *to_ospath;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- // don't let sound stutter
- S_ClearSoundBuffer();
-
- from_ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, from );
- to_ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, to );
-
- if ( fs_debug->integer ) {
- Com_Printf( "FS_Rename: %s --> %s\n", from_ospath, to_ospath );
- }
-
- FS_CheckFilenameIsNotExecutable( to_ospath, __func__ );
-
- if (rename( from_ospath, to_ospath )) {
- // Failed, try copying it and deleting the original
- FS_CopyFile ( from_ospath, to_ospath );
- FS_Remove ( from_ospath );
- }
-}
-
-/*
-==============
-FS_FCloseFile
-
-If the FILE pointer is an open pak file, leave it open.
-
-For some reason, other dll's can't just cal fclose()
-on files returned by FS_FOpenFile...
-==============
-*/
-void FS_FCloseFile( fileHandle_t f ) {
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- if (fsh[f].zipFile == qtrue) {
- unzCloseCurrentFile( fsh[f].handleFiles.file.z );
- if ( fsh[f].handleFiles.unique ) {
- unzClose( fsh[f].handleFiles.file.z );
- }
- Com_Memset( &fsh[f], 0, sizeof( fsh[f] ) );
- return;
- }
-
- // we didn't find it as a pak, so close it as a unique file
- if (fsh[f].handleFiles.file.o) {
- fclose (fsh[f].handleFiles.file.o);
- }
- Com_Memset( &fsh[f], 0, sizeof( fsh[f] ) );
-}
-
-/*
-===========
-FS_FOpenFileWrite
-
-===========
-*/
-fileHandle_t FS_FOpenFileWrite( const char *filename ) {
- char *ospath;
- fileHandle_t f;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- f = FS_HandleForFile();
- fsh[f].zipFile = qfalse;
-
- ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename );
-
- if ( fs_debug->integer ) {
- Com_Printf( "FS_FOpenFileWrite: %s\n", ospath );
- }
-
- FS_CheckFilenameIsNotExecutable( ospath, __func__ );
-
- if( FS_CreatePath( ospath ) ) {
- return 0;
- }
-
- // enabling the following line causes a recursive function call loop
- // when running with +set logfile 1 +set developer 1
- //Com_DPrintf( "writing to: %s\n", ospath );
- fsh[f].handleFiles.file.o = fopen( ospath, "wb" );
-
- Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );
-
- fsh[f].handleSync = qfalse;
- if (!fsh[f].handleFiles.file.o) {
- f = 0;
- }
- return f;
-}
-
-/*
-===========
-FS_FOpenFileAppend
-
-===========
-*/
-fileHandle_t FS_FOpenFileAppend( const char *filename ) {
- char *ospath;
- fileHandle_t f;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- f = FS_HandleForFile();
- fsh[f].zipFile = qfalse;
-
- Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );
-
- // don't let sound stutter
- S_ClearSoundBuffer();
-
- ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename );
-
- if ( fs_debug->integer ) {
- Com_Printf( "FS_FOpenFileAppend: %s\n", ospath );
- }
-
- FS_CheckFilenameIsNotExecutable( ospath, __func__ );
-
- if( FS_CreatePath( ospath ) ) {
- return 0;
- }
-
- fsh[f].handleFiles.file.o = fopen( ospath, "ab" );
- fsh[f].handleSync = qfalse;
- if (!fsh[f].handleFiles.file.o) {
- f = 0;
- }
- return f;
-}
-
-/*
-===========
-FS_FilenameCompare
-
-Ignore case and seprator char distinctions
-===========
-*/
-qboolean FS_FilenameCompare( const char *s1, const char *s2 ) {
- int c1, c2;
-
- do {
- c1 = *s1++;
- c2 = *s2++;
-
- if (c1 >= 'a' && c1 <= 'z') {
- c1 -= ('a' - 'A');
- }
- if (c2 >= 'a' && c2 <= 'z') {
- c2 -= ('a' - 'A');
- }
-
- if ( c1 == '\\' || c1 == ':' ) {
- c1 = '/';
- }
- if ( c2 == '\\' || c2 == ':' ) {
- c2 = '/';
- }
-
- if (c1 != c2) {
- return qtrue; // strings not equal
- }
- } while (c1);
-
- return qfalse; // strings are equal
-}
-
-/*
-===========
-FS_FOpenFileRead
-
-Finds the file in the search path.
-Returns filesize and an open FILE pointer.
-Used for streaming data out of either a
-separate file or a ZIP file.
-===========
-*/
-extern qboolean com_fullyInitialized;
-
-int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ) {
- searchpath_t *search;
- char *netpath;
- pack_t *pak;
- fileInPack_t *pakFile;
- directory_t *dir;
- long hash;
- FILE *temp;
- int l;
- char demoExt[16];
-
- hash = 0;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- if ( file == NULL ) {
- // just wants to see if file is there
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- //
- if ( search->pack ) {
- hash = FS_HashFileName(filename, search->pack->hashSize);
- }
- // is the element a pak file?
- if ( search->pack && search->pack->hashTable[hash] ) {
- // look through all the pak file elements
- pak = search->pack;
- pakFile = pak->hashTable[hash];
- do {
- // case and separator insensitive comparisons
- if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
- // found it!
- return qtrue;
- }
- pakFile = pakFile->next;
- } while(pakFile != NULL);
- } else if ( search->dir ) {
- dir = search->dir;
-
- netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
- temp = fopen (netpath, "rb");
- if ( !temp ) {
- continue;
- }
- fclose(temp);
- return qtrue;
- }
- }
- return qfalse;
- }
-
- if ( !filename ) {
- Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed\n" );
- }
-
- Com_sprintf (demoExt, sizeof(demoExt), ".dm_%d",PROTOCOL_VERSION );
- // qpaths are not supposed to have a leading slash
- if ( filename[0] == '/' || filename[0] == '\\' ) {
- filename++;
- }
-
- // make absolutely sure that it can't back up the path.
- // The searchpaths do guarantee that something will always
- // be prepended, so we don't need to worry about "c:" or "//limbo"
- if ( strstr( filename, ".." ) || strstr( filename, "::" ) ) {
- *file = 0;
- return -1;
- }
-
- // make sure the q3key file is only readable by the quake3.exe at initialization
- // any other time the key should only be accessed in memory using the provided functions
- if( com_fullyInitialized && strstr( filename, "q3key" ) ) {
- *file = 0;
- return -1;
- }
-
- //
- // search through the path, one element at a time
- //
-
- *file = FS_HandleForFile();
- fsh[*file].handleFiles.unique = uniqueFILE;
-
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- //
- if ( search->pack ) {
- hash = FS_HashFileName(filename, search->pack->hashSize);
- }
- // is the element a pak file?
- if ( search->pack && search->pack->hashTable[hash] ) {
- // disregard if it doesn't match one of the allowed pure pak files
- if ( !FS_PakIsPure(search->pack) ) {
- continue;
- }
-
- // look through all the pak file elements
- pak = search->pack;
- pakFile = pak->hashTable[hash];
- do {
- // case and separator insensitive comparisons
- if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
- // found it!
-
- // mark the pak as having been referenced and mark specifics on cgame and ui
- // shaders, txt, arena files by themselves do not count as a reference as
- // these are loaded from all pk3s
- // from every pk3 file..
- l = strlen( filename );
- if ( !(pak->referenced & FS_GENERAL_REF)) {
- if ( Q_stricmp(filename + l - 7, ".shader") != 0 &&
- Q_stricmp(filename + l - 4, ".txt") != 0 &&
- Q_stricmp(filename + l - 4, ".cfg") != 0 &&
- Q_stricmp(filename + l - 7, ".config") != 0 &&
- strstr(filename, "levelshots") == NULL &&
- Q_stricmp(filename + l - 4, ".bot") != 0 &&
- Q_stricmp(filename + l - 6, ".arena") != 0 &&
- Q_stricmp(filename + l - 5, ".menu") != 0) {
- pak->referenced |= FS_GENERAL_REF;
- }
- }
-
- if (!(pak->referenced & FS_QAGAME_REF) && strstr(filename, "qagame.qvm")) {
- pak->referenced |= FS_QAGAME_REF;
- }
- if (!(pak->referenced & FS_CGAME_REF) && strstr(filename, "cgame.qvm")) {
- pak->referenced |= FS_CGAME_REF;
- }
- if (!(pak->referenced & FS_UI_REF) && strstr(filename, "ui.qvm")) {
- pak->referenced |= FS_UI_REF;
- }
-
- if ( uniqueFILE ) {
- // open a new file on the pakfile
- fsh[*file].handleFiles.file.z = unzOpen (pak->pakFilename);
- if (fsh[*file].handleFiles.file.z == NULL) {
- Com_Error (ERR_FATAL, "Couldn't open %s", pak->pakFilename);
- }
- } else {
- fsh[*file].handleFiles.file.z = pak->handle;
- }
- Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );
- fsh[*file].zipFile = qtrue;
- // set the file position in the zip file (also sets the current file info)
- unzSetOffset(fsh[*file].handleFiles.file.z, pakFile->pos);
- // open the file in the zip
- unzOpenCurrentFile( fsh[*file].handleFiles.file.z );
- fsh[*file].zipFilePos = pakFile->pos;
-
- if ( fs_debug->integer ) {
- Com_Printf( "FS_FOpenFileRead: %s (found in '%s')\n",
- filename, pak->pakFilename );
- }
- return pakFile->len;
- }
- pakFile = pakFile->next;
- } while(pakFile != NULL);
- } else if ( search->dir ) {
- // check a file in the directory tree
-
- // if we are running restricted, the only files we
- // will allow to come from the directory are .cfg files
- l = strlen( filename );
- // FIXME TTimo I'm not sure about the fs_numServerPaks test
- // if you are using FS_ReadFile to find out if a file exists,
- // this test can make the search fail although the file is in the directory
- // I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8
- // turned out I used FS_FileExists instead
- if ( fs_numServerPaks ) {
-
- if ( Q_stricmp( filename + l - 4, ".cfg" ) // for config files
- && Q_stricmp( filename + l - 5, ".menu" ) // menu files
- && Q_stricmp( filename + l - 5, ".game" ) // menu files
- && Q_stricmp( filename + l - strlen(demoExt), demoExt ) // menu files
- && Q_stricmp( filename + l - 4, ".dat" ) ) { // for journal files
- continue;
- }
- }
-
- dir = search->dir;
-
- netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
- fsh[*file].handleFiles.file.o = fopen (netpath, "rb");
- if ( !fsh[*file].handleFiles.file.o ) {
- continue;
- }
-
- Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );
- fsh[*file].zipFile = qfalse;
- if ( fs_debug->integer ) {
- Com_Printf( "FS_FOpenFileRead: %s (found in '%s/%s')\n", filename,
- dir->path, dir->gamedir );
- }
-
- return FS_filelength (*file);
- }
- }
-
-#ifdef FS_MISSING
- if (missingFiles) {
- fprintf(missingFiles, "%s\n", filename);
- }
-#endif
- *file = 0;
- return -1;
-}
-
-
-/*
-=================
-FS_Read
-
-Properly handles partial reads
-=================
-*/
-int FS_Read2( void *buffer, int len, fileHandle_t f ) {
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- if ( !f ) {
- return 0;
- }
- if (fsh[f].streamed) {
- int r;
- fsh[f].streamed = qfalse;
- r = FS_Read( buffer, len, f );
- fsh[f].streamed = qtrue;
- return r;
- } else {
- return FS_Read( buffer, len, f);
- }
-}
-
-int FS_Read( void *buffer, int len, fileHandle_t f ) {
- int block, remaining;
- int read;
- byte *buf;
- int tries;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- if ( !f ) {
- return 0;
- }
-
- buf = (byte *)buffer;
- fs_readCount += len;
-
- if (fsh[f].zipFile == qfalse) {
- remaining = len;
- tries = 0;
- while (remaining) {
- block = remaining;
- read = fread (buf, 1, block, fsh[f].handleFiles.file.o);
- if (read == 0) {
- // we might have been trying to read from a CD, which
- // sometimes returns a 0 read on windows
- if (!tries) {
- tries = 1;
- } else {
- return len-remaining; //Com_Error (ERR_FATAL, "FS_Read: 0 bytes read");
- }
- }
-
- if (read == -1) {
- Com_Error (ERR_FATAL, "FS_Read: -1 bytes read");
- }
-
- remaining -= read;
- buf += read;
- }
- return len;
- } else {
- return unzReadCurrentFile(fsh[f].handleFiles.file.z, buffer, len);
- }
-}
-
-/*
-=================
-FS_Write
-
-Properly handles partial writes
-=================
-*/
-int FS_Write( const void *buffer, int len, fileHandle_t h ) {
- int block, remaining;
- int written;
- byte *buf;
- int tries;
- FILE *f;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- if ( !h ) {
- return 0;
- }
-
- f = FS_FileForHandle(h);
- buf = (byte *)buffer;
-
- remaining = len;
- tries = 0;
- while (remaining) {
- block = remaining;
- written = fwrite (buf, 1, block, f);
- if (written == 0) {
- if (!tries) {
- tries = 1;
- } else {
- Com_Printf( "FS_Write: 0 bytes written\n" );
- return 0;
- }
- }
-
- if (written == -1) {
- Com_Printf( "FS_Write: -1 bytes written\n" );
- return 0;
- }
-
- remaining -= written;
- buf += written;
- }
- if ( fsh[h].handleSync ) {
- fflush( f );
- }
- return len;
-}
-
-void QDECL FS_Printf( fileHandle_t h, const char *fmt, ... ) {
- va_list argptr;
- char msg[MAXPRINTMSG];
-
- va_start (argptr,fmt);
- Q_vsnprintf (msg, sizeof(msg), fmt, argptr);
- va_end (argptr);
-
- FS_Write(msg, strlen(msg), h);
-}
-
-#define PK3_SEEK_BUFFER_SIZE 65536
-
-/*
-=================
-FS_Seek
-
-=================
-*/
-int FS_Seek( fileHandle_t f, long offset, int origin ) {
- int _origin;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- return -1;
- }
-
- if (fsh[f].streamed) {
- fsh[f].streamed = qfalse;
- FS_Seek( f, offset, origin );
- fsh[f].streamed = qtrue;
- }
-
- if (fsh[f].zipFile == qtrue) {
- //FIXME: this is incomplete and really, really
- //crappy (but better than what was here before)
- byte buffer[PK3_SEEK_BUFFER_SIZE];
- int remainder = offset;
-
- if( offset < 0 || origin == FS_SEEK_END ) {
- Com_Error( ERR_FATAL, "Negative offsets and FS_SEEK_END not implemented "
- "for FS_Seek on pk3 file contents\n" );
- return -1;
- }
-
- switch( origin ) {
- case FS_SEEK_SET:
- unzSetOffset(fsh[f].handleFiles.file.z, fsh[f].zipFilePos);
- unzOpenCurrentFile(fsh[f].handleFiles.file.z);
- //fallthrough
-
- case FS_SEEK_CUR:
- while( remainder > PK3_SEEK_BUFFER_SIZE ) {
- FS_Read( buffer, PK3_SEEK_BUFFER_SIZE, f );
- remainder -= PK3_SEEK_BUFFER_SIZE;
- }
- FS_Read( buffer, remainder, f );
- return offset;
- break;
-
- default:
- Com_Error( ERR_FATAL, "Bad origin in FS_Seek\n" );
- return -1;
- break;
- }
- } else {
- FILE *file;
- file = FS_FileForHandle(f);
- switch( origin ) {
- case FS_SEEK_CUR:
- _origin = SEEK_CUR;
- break;
- case FS_SEEK_END:
- _origin = SEEK_END;
- break;
- case FS_SEEK_SET:
- _origin = SEEK_SET;
- break;
- default:
- _origin = SEEK_CUR;
- Com_Error( ERR_FATAL, "Bad origin in FS_Seek\n" );
- break;
- }
-
- return fseek( file, offset, _origin );
- }
-}
-
-
-/*
-======================================================================================
-
-CONVENIENCE FUNCTIONS FOR ENTIRE FILES
-
-======================================================================================
-*/
-
-int FS_FileIsInPAK(const char *filename, int *pChecksum ) {
- searchpath_t *search;
- pack_t *pak;
- fileInPack_t *pakFile;
- long hash = 0;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- if ( !filename ) {
- Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed\n" );
- }
-
- // qpaths are not supposed to have a leading slash
- if ( filename[0] == '/' || filename[0] == '\\' ) {
- filename++;
- }
-
- // make absolutely sure that it can't back up the path.
- // The searchpaths do guarantee that something will always
- // be prepended, so we don't need to worry about "c:" or "//limbo"
- if ( strstr( filename, ".." ) || strstr( filename, "::" ) ) {
- return -1;
- }
-
- //
- // search through the path, one element at a time
- //
-
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- //
- if (search->pack) {
- hash = FS_HashFileName(filename, search->pack->hashSize);
- }
- // is the element a pak file?
- if ( search->pack && search->pack->hashTable[hash] ) {
- // disregard if it doesn't match one of the allowed pure pak files
- if ( !FS_PakIsPure(search->pack) ) {
- continue;
- }
-
- // look through all the pak file elements
- pak = search->pack;
- pakFile = pak->hashTable[hash];
- do {
- // case and separator insensitive comparisons
- if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
- if (pChecksum) {
- *pChecksum = pak->pure_checksum;
- }
- return 1;
- }
- pakFile = pakFile->next;
- } while(pakFile != NULL);
- }
- }
- return -1;
-}
-
-/*
-============
-FS_ReadFile
-
-Filename are relative to the quake search path
-a null buffer will just return the file length without loading
-============
-*/
-int FS_ReadFile( const char *qpath, void **buffer ) {
- fileHandle_t h;
- byte* buf;
- qboolean isConfig;
- int len;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- if ( !qpath || !qpath[0] ) {
- Com_Error( ERR_FATAL, "FS_ReadFile with empty name\n" );
- }
-
- buf = NULL; // quiet compiler warning
-
- // if this is a .cfg file and we are playing back a journal, read
- // it from the journal file
- if ( strstr( qpath, ".cfg" ) ) {
- isConfig = qtrue;
- if ( com_journal && com_journal->integer == 2 ) {
- int r;
-
- Com_DPrintf( "Loading %s from journal file.\n", qpath );
- r = FS_Read( &len, sizeof( len ), com_journalDataFile );
- if ( r != sizeof( len ) ) {
- if (buffer != NULL) *buffer = NULL;
- return -1;
- }
- // if the file didn't exist when the journal was created
- if (!len) {
- if (buffer == NULL) {
- return 1; // hack for old journal files
- }
- *buffer = NULL;
- return -1;
- }
- if (buffer == NULL) {
- return len;
- }
-
- buf = Hunk_AllocateTempMemory(len+1);
- *buffer = buf;
-
- r = FS_Read( buf, len, com_journalDataFile );
- if ( r != len ) {
- Com_Error( ERR_FATAL, "Read from journalDataFile failed" );
- }
-
- fs_loadCount++;
- fs_loadStack++;
-
- // guarantee that it will have a trailing 0 for string operations
- buf[len] = 0;
-
- return len;
- }
- } else {
- isConfig = qfalse;
- }
-
- // look for it in the filesystem or pack files
- len = FS_FOpenFileRead( qpath, &h, qfalse );
- if ( h == 0 ) {
- if ( buffer ) {
- *buffer = NULL;
- }
- // if we are journalling and it is a config file, write a zero to the journal file
- if ( isConfig && com_journal && com_journal->integer == 1 ) {
- Com_DPrintf( "Writing zero for %s to journal file.\n", qpath );
- len = 0;
- FS_Write( &len, sizeof( len ), com_journalDataFile );
- FS_Flush( com_journalDataFile );
- }
- return -1;
- }
-
- if ( !buffer ) {
- if ( isConfig && com_journal && com_journal->integer == 1 ) {
- Com_DPrintf( "Writing len for %s to journal file.\n", qpath );
- FS_Write( &len, sizeof( len ), com_journalDataFile );
- FS_Flush( com_journalDataFile );
- }
- FS_FCloseFile( h);
- return len;
- }
-
- fs_loadCount++;
- fs_loadStack++;
-
- buf = Hunk_AllocateTempMemory(len+1);
- *buffer = buf;
-
- FS_Read (buf, len, h);
-
- // guarantee that it will have a trailing 0 for string operations
- buf[len] = 0;
- FS_FCloseFile( h );
-
- // if we are journalling and it is a config file, write it to the journal file
- if ( isConfig && com_journal && com_journal->integer == 1 ) {
- Com_DPrintf( "Writing %s to journal file.\n", qpath );
- FS_Write( &len, sizeof( len ), com_journalDataFile );
- FS_Write( buf, len, com_journalDataFile );
- FS_Flush( com_journalDataFile );
- }
- return len;
-}
-
-/*
-=============
-FS_FreeFile
-=============
-*/
-void FS_FreeFile( void *buffer ) {
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
- if ( !buffer ) {
- Com_Error( ERR_FATAL, "FS_FreeFile( NULL )" );
- }
- fs_loadStack--;
-
- Hunk_FreeTempMemory( buffer );
-
- // if all of our temp files are free, clear all of our space
- if ( fs_loadStack == 0 ) {
- Hunk_ClearTempMemory();
- }
-}
-
-/*
-============
-FS_WriteFile
-
-Filename are reletive to the quake search path
-============
-*/
-void FS_WriteFile( const char *qpath, const void *buffer, int size ) {
- fileHandle_t f;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- if ( !qpath || !buffer ) {
- Com_Error( ERR_FATAL, "FS_WriteFile: NULL parameter" );
- }
-
- f = FS_FOpenFileWrite( qpath );
- if ( !f ) {
- Com_Printf( "Failed to open %s\n", qpath );
- return;
- }
-
- FS_Write( buffer, size, f );
-
- FS_FCloseFile( f );
-}
-
-
-
-/*
-==========================================================================
-
-ZIP FILE LOADING
-
-==========================================================================
-*/
-
-/*
-=================
-FS_LoadZipFile
-
-Creates a new pak_t in the search chain for the contents
-of a zip file.
-=================
-*/
-static pack_t *FS_LoadZipFile(const char *zipfile, const char *basename)
-{
- fileInPack_t *buildBuffer;
- pack_t *pack;
- unzFile uf;
- int err;
- unz_global_info gi;
- char filename_inzip[MAX_ZPATH];
- unz_file_info file_info;
- int i, len;
- long hash;
- int fs_numHeaderLongs;
- int *fs_headerLongs;
- char *namePtr;
-
- fs_numHeaderLongs = 0;
-
- uf = unzOpen(zipfile);
- err = unzGetGlobalInfo (uf,&gi);
-
- if (err != UNZ_OK)
- return NULL;
-
- len = 0;
- unzGoToFirstFile(uf);
- for (i = 0; i < gi.number_entry; i++)
- {
- err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
- if (err != UNZ_OK) {
- break;
- }
- len += strlen(filename_inzip) + 1;
- unzGoToNextFile(uf);
- }
-
- buildBuffer = Z_Malloc( (gi.number_entry * sizeof( fileInPack_t )) + len );
- namePtr = ((char *) buildBuffer) + gi.number_entry * sizeof( fileInPack_t );
- fs_headerLongs = Z_Malloc( ( gi.number_entry + 1 ) * sizeof(int) );
- fs_headerLongs[ fs_numHeaderLongs++ ] = LittleLong( fs_checksumFeed );
-
- // get the hash table size from the number of files in the zip
- // because lots of custom pk3 files have less than 32 or 64 files
- for (i = 1; i <= MAX_FILEHASH_SIZE; i <<= 1) {
- if (i > gi.number_entry) {
- break;
- }
- }
-
- pack = Z_Malloc( sizeof( pack_t ) + i * sizeof(fileInPack_t *) );
- pack->hashSize = i;
- pack->hashTable = (fileInPack_t **) (((char *) pack) + sizeof( pack_t ));
- for(i = 0; i < pack->hashSize; i++) {
- pack->hashTable[i] = NULL;
- }
-
- Q_strncpyz( pack->pakFilename, zipfile, sizeof( pack->pakFilename ) );
- Q_strncpyz( pack->pakBasename, basename, sizeof( pack->pakBasename ) );
-
- // strip .pk3 if needed
- if ( strlen( pack->pakBasename ) > 4 && !Q_stricmp( pack->pakBasename + strlen( pack->pakBasename ) - 4, ".pk3" ) ) {
- pack->pakBasename[strlen( pack->pakBasename ) - 4] = 0;
- }
-
- pack->handle = uf;
- pack->numfiles = gi.number_entry;
- unzGoToFirstFile(uf);
-
- for (i = 0; i < gi.number_entry; i++)
- {
- err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
- if (err != UNZ_OK) {
- break;
- }
- if (file_info.uncompressed_size > 0) {
- fs_headerLongs[fs_numHeaderLongs++] = LittleLong(file_info.crc);
- }
- Q_strlwr( filename_inzip );
- hash = FS_HashFileName(filename_inzip, pack->hashSize);
- buildBuffer[i].name = namePtr;
- strcpy( buildBuffer[i].name, filename_inzip );
- namePtr += strlen(filename_inzip) + 1;
- // store the file position in the zip
- buildBuffer[i].pos = unzGetOffset(uf);
- buildBuffer[i].len = file_info.uncompressed_size;
- buildBuffer[i].next = pack->hashTable[hash];
- pack->hashTable[hash] = &buildBuffer[i];
- unzGoToNextFile(uf);
- }
-
- pack->checksum = Com_BlockChecksum( &fs_headerLongs[ 1 ], sizeof(*fs_headerLongs) * ( fs_numHeaderLongs - 1 ) );
- pack->pure_checksum = Com_BlockChecksum( fs_headerLongs, sizeof(*fs_headerLongs) * fs_numHeaderLongs );
- pack->checksum = LittleLong( pack->checksum );
- pack->pure_checksum = LittleLong( pack->pure_checksum );
-
- Z_Free(fs_headerLongs);
-
- pack->buildBuffer = buildBuffer;
- return pack;
-}
-
-/*
-=================
-FS_FreePak
-
-Frees a pak structure and releases all associated resources
-=================
-*/
-
-static void FS_FreePak(pack_t *thepak)
-{
- unzClose(thepak->handle);
- Z_Free(thepak->buildBuffer);
- Z_Free(thepak);
-}
-
-/*
-=================
-FS_GetZipChecksum
-
-Compares whether the given pak file matches a referenced checksum
-=================
-*/
-qboolean FS_CompareZipChecksum(const char *zipfile)
-{
- pack_t *thepak;
- int index, checksum;
-
- thepak = FS_LoadZipFile(zipfile, "");
-
- if(!thepak)
- return qfalse;
-
- checksum = thepak->checksum;
- FS_FreePak(thepak);
-
- for(index = 0; index < fs_numServerReferencedPaks; index++)
- {
- if(checksum == fs_serverReferencedPaks[index])
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-=================================================================================
-
-DIRECTORY SCANNING FUNCTIONS
-
-=================================================================================
-*/
-
-#define MAX_FOUND_FILES 0x1000
-
-static int FS_ReturnPath( const char *zname, char *zpath, int *depth ) {
- int len, at, newdep;
-
- newdep = 0;
- zpath[0] = 0;
- len = 0;
- at = 0;
-
- while(zname[at] != 0)
- {
- if (zname[at]=='/' || zname[at]=='\\') {
- len = at;
- newdep++;
- }
- at++;
- }
- strcpy(zpath, zname);
- zpath[len] = 0;
- *depth = newdep;
-
- return len;
-}
-
-/*
-==================
-FS_AddFileToList
-==================
-*/
-static int FS_AddFileToList( char *name, char *list[MAX_FOUND_FILES], int nfiles ) {
- int i;
-
- if ( nfiles == MAX_FOUND_FILES - 1 ) {
- return nfiles;
- }
- for ( i = 0 ; i < nfiles ; i++ ) {
- if ( !Q_stricmp( name, list[i] ) ) {
- return nfiles; // allready in list
- }
- }
- list[nfiles] = CopyString( name );
- nfiles++;
-
- return nfiles;
-}
-
-/*
-===============
-FS_ListFilteredFiles
-
-Returns a uniqued list of files that match the given criteria
-from all search paths
-===============
-*/
-char **FS_ListFilteredFiles( const char *path, const char *extension, char *filter, int *numfiles ) {
- int nfiles;
- char **listCopy;
- char *list[MAX_FOUND_FILES];
- searchpath_t *search;
- int i;
- int pathLength;
- int extensionLength;
- int length, pathDepth, temp;
- pack_t *pak;
- fileInPack_t *buildBuffer;
- char zpath[MAX_ZPATH];
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- if ( !path ) {
- *numfiles = 0;
- return NULL;
- }
- if ( !extension ) {
- extension = "";
- }
-
- pathLength = strlen( path );
- if ( path[pathLength-1] == '\\' || path[pathLength-1] == '/' ) {
- pathLength--;
- }
- extensionLength = strlen( extension );
- nfiles = 0;
- FS_ReturnPath(path, zpath, &pathDepth);
-
- //
- // search through the path, one element at a time, adding to list
- //
- for (search = fs_searchpaths ; search ; search = search->next) {
- // is the element a pak file?
- if (search->pack) {
-
- //ZOID: If we are pure, don't search for files on paks that
- // aren't on the pure list
- if ( !FS_PakIsPure(search->pack) ) {
- continue;
- }
-
- // look through all the pak file elements
- pak = search->pack;
- buildBuffer = pak->buildBuffer;
- for (i = 0; i < pak->numfiles; i++) {
- char *name;
- int zpathLen, depth;
-
- // check for directory match
- name = buildBuffer[i].name;
- //
- if (filter) {
- // case insensitive
- if (!Com_FilterPath( filter, name, qfalse ))
- continue;
- // unique the match
- nfiles = FS_AddFileToList( name, list, nfiles );
- }
- else {
-
- zpathLen = FS_ReturnPath(name, zpath, &depth);
-
- if ( (depth-pathDepth)>2 || pathLength > zpathLen || Q_stricmpn( name, path, pathLength ) ) {
- continue;
- }
-
- // check for extension match
- length = strlen( name );
- if ( length < extensionLength ) {
- continue;
- }
-
- if ( Q_stricmp( name + length - extensionLength, extension ) ) {
- continue;
- }
- // unique the match
-
- temp = pathLength;
- if (pathLength) {
- temp++; // include the '/'
- }
- nfiles = FS_AddFileToList( name + temp, list, nfiles );
- }
- }
- } else if (search->dir) { // scan for files in the filesystem
- char *netpath;
- int numSysFiles;
- char **sysFiles;
- char *name;
-
- // don't scan directories for files if we are pure or restricted
- if ( fs_numServerPaks ) {
- continue;
- } else {
- netpath = FS_BuildOSPath( search->dir->path, search->dir->gamedir, path );
- sysFiles = Sys_ListFiles( netpath, extension, filter, &numSysFiles, qfalse );
- for ( i = 0 ; i < numSysFiles ; i++ ) {
- // unique the match
- name = sysFiles[i];
- nfiles = FS_AddFileToList( name, list, nfiles );
- }
- Sys_FreeFileList( sysFiles );
- }
- }
- }
-
- // return a copy of the list
- *numfiles = nfiles;
-
- if ( !nfiles ) {
- return NULL;
- }
-
- listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
- for ( i = 0 ; i < nfiles ; i++ ) {
- listCopy[i] = list[i];
- }
- listCopy[i] = NULL;
-
- return listCopy;
-}
-
-/*
-=================
-FS_ListFiles
-=================
-*/
-char **FS_ListFiles( const char *path, const char *extension, int *numfiles ) {
- return FS_ListFilteredFiles( path, extension, NULL, numfiles );
-}
-
-/*
-=================
-FS_FreeFileList
-=================
-*/
-void FS_FreeFileList( char **list ) {
- int i;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
- }
-
- if ( !list ) {
- return;
- }
-
- for ( i = 0 ; list[i] ; i++ ) {
- Z_Free( list[i] );
- }
-
- Z_Free( list );
-}
-
-
-/*
-================
-FS_GetFileList
-================
-*/
-int FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ) {
- int nFiles, i, nTotal, nLen;
- char **pFiles = NULL;
-
- *listbuf = 0;
- nFiles = 0;
- nTotal = 0;
-
- if (Q_stricmp(path, "$modlist") == 0) {
- return FS_GetModList(listbuf, bufsize);
- }
-
- pFiles = FS_ListFiles(path, extension, &nFiles);
-
- for (i =0; i < nFiles; i++) {
- nLen = strlen(pFiles[i]) + 1;
- if (nTotal + nLen + 1 < bufsize) {
- strcpy(listbuf, pFiles[i]);
- listbuf += nLen;
- nTotal += nLen;
- }
- else {
- nFiles = i;
- break;
- }
- }
-
- FS_FreeFileList(pFiles);
-
- return nFiles;
-}
-
-/*
-=======================
-Sys_ConcatenateFileLists
-
-mkv: Naive implementation. Concatenates three lists into a
- new list, and frees the old lists from the heap.
-bk001129 - from cvs1.17 (mkv)
-
-FIXME TTimo those two should move to common.c next to Sys_ListFiles
-=======================
- */
-static unsigned int Sys_CountFileList(char **list)
-{
- int i = 0;
-
- if (list)
- {
- while (*list)
- {
- list++;
- i++;
- }
- }
- return i;
-}
-
-static char** Sys_ConcatenateFileLists( char **list0, char **list1 )
-{
- int totalLength = 0;
- char** cat = NULL, **dst, **src;
-
- totalLength += Sys_CountFileList(list0);
- totalLength += Sys_CountFileList(list1);
-
- /* Create new list. */
- dst = cat = Z_Malloc( ( totalLength + 1 ) * sizeof( char* ) );
-
- /* Copy over lists. */
- if (list0)
- {
- for (src = list0; *src; src++, dst++)
- *dst = *src;
- }
- if (list1)
- {
- for (src = list1; *src; src++, dst++)
- *dst = *src;
- }
-
- // Terminate the list
- *dst = NULL;
-
- // Free our old lists.
- // NOTE: not freeing their content, it's been merged in dst and still being used
- if (list0) Z_Free( list0 );
- if (list1) Z_Free( list1 );
-
- return cat;
-}
-
-/*
-================
-FS_GetModList
-
-Returns a list of mod directory names
-A mod directory is a peer to baseq3 with a pk3 in it
-The directories are searched in base path, cd path and home path
-================
-*/
-int FS_GetModList( char *listbuf, int bufsize ) {
- int nMods, i, j, nTotal, nLen, nPaks, nPotential, nDescLen;
- char **pFiles = NULL;
- char **pPaks = NULL;
- char *name, *path;
- char descPath[MAX_OSPATH];
- fileHandle_t descHandle;
-
- int dummy;
- char **pFiles0 = NULL;
- char **pFiles1 = NULL;
- qboolean bDrop = qfalse;
-
- *listbuf = 0;
- nMods = nPotential = nTotal = 0;
-
- pFiles0 = Sys_ListFiles( fs_homepath->string, NULL, NULL, &dummy, qtrue );
- pFiles1 = Sys_ListFiles( fs_basepath->string, NULL, NULL, &dummy, qtrue );
- // we searched for mods in the three paths
- // it is likely that we have duplicate names now, which we will cleanup below
- pFiles = Sys_ConcatenateFileLists( pFiles0, pFiles1 );
- nPotential = Sys_CountFileList(pFiles);
-
- for ( i = 0 ; i < nPotential ; i++ ) {
- name = pFiles[i];
- // NOTE: cleaner would involve more changes
- // ignore duplicate mod directories
- if (i!=0) {
- bDrop = qfalse;
- for(j=0; j<i; j++)
- {
- if (Q_stricmp(pFiles[j],name)==0) {
- // this one can be dropped
- bDrop = qtrue;
- break;
- }
- }
- }
- if (bDrop) {
- continue;
- }
- // we drop "baseq3" "." and ".."
- if (Q_stricmp(name, BASEGAME) && Q_stricmpn(name, ".", 1)) {
- // now we need to find some .pk3 files to validate the mod
- // NOTE TTimo: (actually I'm not sure why .. what if it's a mod under developement with no .pk3?)
- // we didn't keep the information when we merged the directory names, as to what OS Path it was found under
- // so it could be in base path, cd path or home path
- // we will try each three of them here (yes, it's a bit messy)
- path = FS_BuildOSPath( fs_basepath->string, name, "" );
- nPaks = 0;
- pPaks = Sys_ListFiles(path, ".pk3", NULL, &nPaks, qfalse);
- Sys_FreeFileList( pPaks ); // we only use Sys_ListFiles to check wether .pk3 files are present
-
- /* try on home path */
- if ( nPaks <= 0 )
- {
- path = FS_BuildOSPath( fs_homepath->string, name, "" );
- nPaks = 0;
- pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse );
- Sys_FreeFileList( pPaks );
- }
-
- if (nPaks > 0) {
- nLen = strlen(name) + 1;
- // nLen is the length of the mod path
- // we need to see if there is a description available
- descPath[0] = '\0';
- strcpy(descPath, name);
- strcat(descPath, "/description.txt");
- nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle );
- if ( nDescLen > 0 && descHandle) {
- FILE *file;
- file = FS_FileForHandle(descHandle);
- Com_Memset( descPath, 0, sizeof( descPath ) );
- nDescLen = fread(descPath, 1, 48, file);
- if (nDescLen >= 0) {
- descPath[nDescLen] = '\0';
- }
- FS_FCloseFile(descHandle);
- } else {
- strcpy(descPath, name);
- }
- nDescLen = strlen(descPath) + 1;
-
- if (nTotal + nLen + 1 + nDescLen + 1 < bufsize) {
- strcpy(listbuf, name);
- listbuf += nLen;
- strcpy(listbuf, descPath);
- listbuf += nDescLen;
- nTotal += nLen + nDescLen;
- nMods++;
- }
- else {
- break;
- }
- }
- }
- }
- Sys_FreeFileList( pFiles );
-
- return nMods;
-}
-
-
-
-
-//============================================================================
-
-/*
-================
-FS_Dir_f
-================
-*/
-void FS_Dir_f( void ) {
- char *path;
- char *extension;
- char **dirnames;
- int ndirs;
- int i;
-
- if ( Cmd_Argc() < 2 || Cmd_Argc() > 3 ) {
- Com_Printf( "usage: dir <directory> [extension]\n" );
- return;
- }
-
- if ( Cmd_Argc() == 2 ) {
- path = Cmd_Argv( 1 );
- extension = "";
- } else {
- path = Cmd_Argv( 1 );
- extension = Cmd_Argv( 2 );
- }
-
- Com_Printf( "Directory of %s %s\n", path, extension );
- Com_Printf( "---------------\n" );
-
- dirnames = FS_ListFiles( path, extension, &ndirs );
-
- for ( i = 0; i < ndirs; i++ ) {
- Com_Printf( "%s\n", dirnames[i] );
- }
- FS_FreeFileList( dirnames );
-}
-
-/*
-===========
-FS_ConvertPath
-===========
-*/
-void FS_ConvertPath( char *s ) {
- while (*s) {
- if ( *s == '\\' || *s == ':' ) {
- *s = '/';
- }
- s++;
- }
-}
-
-/*
-===========
-FS_PathCmp
-
-Ignore case and seprator char distinctions
-===========
-*/
-int FS_PathCmp( const char *s1, const char *s2 ) {
- int c1, c2;
-
- do {
- c1 = *s1++;
- c2 = *s2++;
-
- if (c1 >= 'a' && c1 <= 'z') {
- c1 -= ('a' - 'A');
- }
- if (c2 >= 'a' && c2 <= 'z') {
- c2 -= ('a' - 'A');
- }
-
- if ( c1 == '\\' || c1 == ':' ) {
- c1 = '/';
- }
- if ( c2 == '\\' || c2 == ':' ) {
- c2 = '/';
- }
-
- if (c1 < c2) {
- return -1; // strings not equal
- }
- if (c1 > c2) {
- return 1;
- }
- } while (c1);
-
- return 0; // strings are equal
-}
-
-/*
-================
-FS_SortFileList
-================
-*/
-void FS_SortFileList(char **filelist, int numfiles) {
- int i, j, k, numsortedfiles;
- char **sortedlist;
-
- sortedlist = Z_Malloc( ( numfiles + 1 ) * sizeof( *sortedlist ) );
- sortedlist[0] = NULL;
- numsortedfiles = 0;
- for (i = 0; i < numfiles; i++) {
- for (j = 0; j < numsortedfiles; j++) {
- if (FS_PathCmp(filelist[i], sortedlist[j]) < 0) {
- break;
- }
- }
- for (k = numsortedfiles; k > j; k--) {
- sortedlist[k] = sortedlist[k-1];
- }
- sortedlist[j] = filelist[i];
- numsortedfiles++;
- }
- Com_Memcpy(filelist, sortedlist, numfiles * sizeof( *filelist ) );
- Z_Free(sortedlist);
-}
-
-/*
-================
-FS_NewDir_f
-================
-*/
-void FS_NewDir_f( void ) {
- char *filter;
- char **dirnames;
- int ndirs;
- int i;
-
- if ( Cmd_Argc() < 2 ) {
- Com_Printf( "usage: fdir <filter>\n" );
- Com_Printf( "example: fdir *q3dm*.bsp\n");
- return;
- }
-
- filter = Cmd_Argv( 1 );
-
- Com_Printf( "---------------\n" );
-
- dirnames = FS_ListFilteredFiles( "", "", filter, &ndirs );
-
- FS_SortFileList(dirnames, ndirs);
-
- for ( i = 0; i < ndirs; i++ ) {
- FS_ConvertPath(dirnames[i]);
- Com_Printf( "%s\n", dirnames[i] );
- }
- Com_Printf( "%d files listed\n", ndirs );
- FS_FreeFileList( dirnames );
-}
-
-/*
-============
-FS_Path_f
-
-============
-*/
-void FS_Path_f( void ) {
- searchpath_t *s;
- int i;
-
- Com_Printf ("Current search path:\n");
- for (s = fs_searchpaths; s; s = s->next) {
- if (s->pack) {
- Com_Printf ("%s (%i files)\n", s->pack->pakFilename, s->pack->numfiles);
- if ( fs_numServerPaks ) {
- if ( !FS_PakIsPure(s->pack) ) {
- Com_Printf( " not on the pure list\n" );
- } else {
- Com_Printf( " on the pure list\n" );
- }
- }
- } else {
- Com_Printf ("%s/%s\n", s->dir->path, s->dir->gamedir );
- }
- }
-
-
- Com_Printf( "\n" );
- for ( i = 1 ; i < MAX_FILE_HANDLES ; i++ ) {
- if ( fsh[i].handleFiles.file.o ) {
- Com_Printf( "handle %i: %s\n", i, fsh[i].name );
- }
- }
-}
-
-/*
-============
-FS_TouchFile_f
-============
-*/
-void FS_TouchFile_f( void ) {
- fileHandle_t f;
-
- if ( Cmd_Argc() != 2 ) {
- Com_Printf( "Usage: touchFile <file>\n" );
- return;
- }
-
- FS_FOpenFileRead( Cmd_Argv( 1 ), &f, qfalse );
- if ( f ) {
- FS_FCloseFile( f );
- }
-}
-
-//===========================================================================
-
-
-static int QDECL paksort( const void *a, const void *b ) {
- char *aa, *bb;
-
- aa = *(char **)a;
- bb = *(char **)b;
-
- return FS_PathCmp( aa, bb );
-}
-
-/*
-================
-FS_AddGameDirectory
-
-Sets fs_gamedir, adds the directory to the head of the path,
-then loads the zip headers
-================
-*/
-void FS_AddGameDirectory( const char *path, const char *dir ) {
- searchpath_t *sp;
- int i;
- searchpath_t *search;
- pack_t *pak;
- char *pakfile;
- int numfiles;
- char **pakfiles;
-
- // Unique
- for ( sp = fs_searchpaths ; sp ; sp = sp->next ) {
- if ( sp->dir && !Q_stricmp(sp->dir->path, path) && !Q_stricmp(sp->dir->gamedir, dir)) {
- return; // we've already got this one
- }
- }
-
- Q_strncpyz( fs_gamedir, dir, sizeof( fs_gamedir ) );
-
- //
- // add the directory to the search path
- //
- search = Z_Malloc (sizeof(searchpath_t));
- search->dir = Z_Malloc( sizeof( *search->dir ) );
-
- Q_strncpyz( search->dir->path, path, sizeof( search->dir->path ) );
- Q_strncpyz( search->dir->gamedir, dir, sizeof( search->dir->gamedir ) );
- search->next = fs_searchpaths;
- fs_searchpaths = search;
-
- // find all pak files in this directory
- pakfile = FS_BuildOSPath( path, dir, "" );
- pakfile[ strlen(pakfile) - 1 ] = 0; // strip the trailing slash
-
- pakfiles = Sys_ListFiles( pakfile, ".pk3", NULL, &numfiles, qfalse );
-
- qsort( pakfiles, numfiles, sizeof(char*), paksort );
-
- for ( i = 0 ; i < numfiles ; i++ ) {
- pakfile = FS_BuildOSPath( path, dir, pakfiles[i] );
- if ( ( pak = FS_LoadZipFile( pakfile, pakfiles[i] ) ) == 0 )
- continue;
- // store the game name for downloading
- strcpy(pak->pakGamename, dir);
-
- fs_packFiles += pak->numfiles;
-
- search = Z_Malloc (sizeof(searchpath_t));
- search->pack = pak;
- search->next = fs_searchpaths;
- fs_searchpaths = search;
- }
-
- // done
- Sys_FreeFileList( pakfiles );
-}
-
-/*
-================
-FS_idPak
-================
-*/
-qboolean FS_idPak( char *pak, char *base ) {
- int i;
-
- for (i = 0; i < NUM_ID_PAKS; i++) {
- if ( !FS_FilenameCompare(pak, va("%s/pak%d", base, i)) ) {
- break;
- }
- }
- if (i < NUM_ID_PAKS) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-================
-FS_CheckDirTraversal
-
-Check whether the string contains stuff like "../" to prevent directory traversal bugs
-and return qtrue if it does.
-================
-*/
-
-qboolean FS_CheckDirTraversal(const char *checkdir)
-{
- if(strstr(checkdir, "../") || strstr(checkdir, "..\\"))
- return qtrue;
-
- return qfalse;
-}
-
-/*
-================
-FS_ComparePaks
-
-----------------
-dlstring == qtrue
-
-Returns a list of pak files that we should download from the server. They all get stored
-in the current gamedir and an FS_Restart will be fired up after we download them all.
-
-The string is the format:
-
- at remotename@localname [repeat]
-
-static int fs_numServerReferencedPaks;
-static int fs_serverReferencedPaks[MAX_SEARCH_PATHS];
-static char *fs_serverReferencedPakNames[MAX_SEARCH_PATHS];
-
-----------------
-dlstring == qfalse
-
-we are not interested in a download string format, we want something human-readable
-(this is used for diagnostics while connecting to a pure server)
-
-================
-*/
-qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
- searchpath_t *sp;
- qboolean havepak, badchecksum;
- char *origpos = neededpaks;
- int i;
-
- if (!fs_numServerReferencedPaks)
- return qfalse; // Server didn't send any pack information along
-
- *neededpaks = 0;
-
- for ( i = 0 ; i < fs_numServerReferencedPaks ; i++ )
- {
- // Ok, see if we have this pak file
- badchecksum = qfalse;
- havepak = qfalse;
-
- // never autodownload any of the id paks
- if ( FS_idPak(fs_serverReferencedPakNames[i], BASEGAME) || FS_idPak(fs_serverReferencedPakNames[i], "missionpack") ) {
- continue;
- }
-
- // Make sure the server cannot make us write to non-quake3 directories.
- if(FS_CheckDirTraversal(fs_serverReferencedPakNames[i]))
- {
- Com_Printf("WARNING: Invalid download name %s\n", fs_serverReferencedPakNames[i]);
- continue;
- }
-
- for ( sp = fs_searchpaths ; sp ; sp = sp->next ) {
- if ( sp->pack && sp->pack->checksum == fs_serverReferencedPaks[i] ) {
- havepak = qtrue; // This is it!
- break;
- }
- }
-
- if ( !havepak && fs_serverReferencedPakNames[i] && *fs_serverReferencedPakNames[i] ) {
- // Don't got it
-
- if (dlstring)
- {
- // We need this to make sure we won't hit the end of the buffer or the server could
- // overwrite non-pk3 files on clients by writing so much crap into neededpaks that
- // Q_strcat cuts off the .pk3 extension.
-
- origpos += strlen(origpos);
-
- // Remote name
- Q_strcat( neededpaks, len, "@");
- Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
- Q_strcat( neededpaks, len, ".pk3" );
-
- // Local name
- Q_strcat( neededpaks, len, "@");
- // Do we have one with the same name?
- if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
- {
- char st[MAX_ZPATH];
- // We already have one called this, we need to download it to another name
- // Make something up with the checksum in it
- Com_sprintf( st, sizeof( st ), "%s.%08x.pk3", fs_serverReferencedPakNames[i], fs_serverReferencedPaks[i] );
- Q_strcat( neededpaks, len, st );
- }
- else
- {
- Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
- Q_strcat( neededpaks, len, ".pk3" );
- }
-
- // Find out whether it might have overflowed the buffer and don't add this file to the
- // list if that is the case.
- if(strlen(origpos) + (origpos - neededpaks) >= len - 1)
- {
- *origpos = '\0';
- break;
- }
- }
- else
- {
- Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
- Q_strcat( neededpaks, len, ".pk3" );
- // Do we have one with the same name?
- if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
- {
- Q_strcat( neededpaks, len, " (local file exists with wrong checksum)");
- }
- Q_strcat( neededpaks, len, "\n");
- }
- }
- }
-
- if ( *neededpaks ) {
- return qtrue;
- }
-
- return qfalse; // We have them all
-}
-
-/*
-================
-FS_Shutdown
-
-Frees all resources.
-================
-*/
-void FS_Shutdown( qboolean closemfp ) {
- searchpath_t *p, *next;
- int i;
-
- for(i = 0; i < MAX_FILE_HANDLES; i++) {
- if (fsh[i].fileSize) {
- FS_FCloseFile(i);
- }
- }
-
- // free everything
- for(p = fs_searchpaths; p; p = next)
- {
- next = p->next;
-
- if(p->pack)
- FS_FreePak(p->pack);
- if (p->dir)
- Z_Free(p->dir);
-
- Z_Free(p);
- }
-
- // any FS_ calls will now be an error until reinitialized
- fs_searchpaths = NULL;
-
- Cmd_RemoveCommand( "path" );
- Cmd_RemoveCommand( "dir" );
- Cmd_RemoveCommand( "fdir" );
- Cmd_RemoveCommand( "touchFile" );
-
-#ifdef FS_MISSING
- if (closemfp) {
- fclose(missingFiles);
- }
-#endif
-}
-
-#ifndef STANDALONE
-void Com_AppendCDKey( const char *filename );
-void Com_ReadCDKey( const char *filename );
-#endif
-
-/*
-================
-FS_ReorderPurePaks
-NOTE TTimo: the reordering that happens here is not reflected in the cvars (\cvarlist *pak*)
- this can lead to misleading situations, see https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=540
-================
-*/
-static void FS_ReorderPurePaks( void )
-{
- searchpath_t *s;
- int i;
- searchpath_t **p_insert_index, // for linked list reordering
- **p_previous; // when doing the scan
-
- // only relevant when connected to pure server
- if ( !fs_numServerPaks )
- return;
-
- fs_reordered = qfalse;
-
- p_insert_index = &fs_searchpaths; // we insert in order at the beginning of the list
- for ( i = 0 ; i < fs_numServerPaks ; i++ ) {
- p_previous = p_insert_index; // track the pointer-to-current-item
- for (s = *p_insert_index; s; s = s->next) {
- // the part of the list before p_insert_index has been sorted already
- if (s->pack && fs_serverPaks[i] == s->pack->checksum) {
- fs_reordered = qtrue;
- // move this element to the insert list
- *p_previous = s->next;
- s->next = *p_insert_index;
- *p_insert_index = s;
- // increment insert list
- p_insert_index = &s->next;
- break; // iterate to next server pack
- }
- p_previous = &s->next;
- }
- }
-}
-
-/*
-================
-FS_Startup
-================
-*/
-static void FS_Startup( const char *gameName )
-{
- const char *homePath;
-
- Com_Printf( "----- FS_Startup -----\n" );
-
- fs_packFiles = 0;
-
- fs_debug = Cvar_Get( "fs_debug", "0", 0 );
- fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT );
- fs_basegame = Cvar_Get ("fs_basegame", "", CVAR_INIT );
- homePath = Sys_DefaultHomePath();
- if (!homePath || !homePath[0]) {
- homePath = fs_basepath->string;
- }
- fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT );
- fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
-
- // add search path elements in reverse priority order
- if (fs_basepath->string[0]) {
- FS_AddGameDirectory( fs_basepath->string, gameName );
- }
- // fs_homepath is somewhat particular to *nix systems, only add if relevant
-
- #ifdef MACOS_X
- fs_apppath = Cvar_Get ("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT );
- // Make MacOSX also include the base path included with the .app bundle
- if (fs_apppath->string[0])
- FS_AddGameDirectory(fs_apppath->string, gameName);
- #endif
-
- // NOTE: same filtering below for mods and basegame
- if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {
- FS_CreatePath ( fs_homepath->string );
- FS_AddGameDirectory ( fs_homepath->string, gameName );
- }
-
- // check for additional base game so mods can be based upon other mods
- if ( fs_basegame->string[0] && Q_stricmp( fs_basegame->string, gameName ) ) {
- if (fs_basepath->string[0]) {
- FS_AddGameDirectory(fs_basepath->string, fs_basegame->string);
- }
- if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {
- FS_AddGameDirectory(fs_homepath->string, fs_basegame->string);
- }
- }
-
- // check for additional game folder for mods
- if ( fs_gamedirvar->string[0] && Q_stricmp( fs_gamedirvar->string, gameName ) ) {
- if (fs_basepath->string[0]) {
- FS_AddGameDirectory(fs_basepath->string, fs_gamedirvar->string);
- }
- if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {
- FS_AddGameDirectory(fs_homepath->string, fs_gamedirvar->string);
- }
- }
-
-#ifndef STANDALONE
- if(!Cvar_VariableIntegerValue("com_standalone"))
- {
- cvar_t *fs;
-
- Com_ReadCDKey(BASEGAME);
- fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
- if (fs && fs->string[0] != 0) {
- Com_AppendCDKey( fs->string );
- }
- }
-#endif
-
- // add our commands
- Cmd_AddCommand ("path", FS_Path_f);
- Cmd_AddCommand ("dir", FS_Dir_f );
- Cmd_AddCommand ("fdir", FS_NewDir_f );
- Cmd_AddCommand ("touchFile", FS_TouchFile_f );
-
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=506
- // reorder the pure pk3 files according to server order
- FS_ReorderPurePaks();
-
- // print the current search paths
- FS_Path_f();
-
- fs_gamedirvar->modified = qfalse; // We just loaded, it's not modified
-
- Com_Printf( "----------------------\n" );
-
-#ifdef FS_MISSING
- if (missingFiles == NULL) {
- missingFiles = fopen( "\\missing.txt", "ab" );
- }
-#endif
- Com_Printf( "%d files in pk3 files\n", fs_packFiles );
-}
-
-#ifndef STANDALONE
-/*
-===================
-FS_CheckPak0
-
-Checks that pak0.pk3 is present and its checksum is correct
-Note: If you're building a game that doesn't depend on the
-Q3 media pak0.pk3, you'll want to remove this function
-===================
-*/
-static void FS_CheckPak0( void )
-{
- searchpath_t *path;
- qboolean founddemo = qfalse;
- unsigned foundPak = 0;
-
- for( path = fs_searchpaths; path; path = path->next )
- {
- const char* pakBasename = path->pack->pakBasename;
-
- if(!path->pack)
- continue;
-
- if(!Q_stricmpn( path->pack->pakGamename, "demoq3", MAX_OSPATH )
- && !Q_stricmpn( pakBasename, "pak0", MAX_OSPATH ))
- {
- founddemo = qtrue;
-
- if( path->pack->checksum == DEMO_PAK0_CHECKSUM )
- {
- Com_Printf( "\n\n"
- "**************************************************\n"
- "WARNING: It looks like you're using pak0.pk3\n"
- "from the demo. This may work fine, but it is not\n"
- "guaranteed or supported.\n"
- "**************************************************\n\n\n" );
- }
- }
-
- else if(!Q_stricmpn( path->pack->pakGamename, BASEGAME, MAX_OSPATH )
- && strlen(pakBasename) == 4 && !Q_stricmpn( pakBasename, "pak", 3 )
- && pakBasename[3] >= '0' && pakBasename[3] <= '8')
- {
- if( path->pack->checksum != pak_checksums[pakBasename[3]-'0'] )
- {
- if(pakBasename[0] == '0')
- {
- Com_Printf("\n\n"
- "**************************************************\n"
- "WARNING: pak0.pk3 is present but its checksum (%u)\n"
- "is not correct. Please re-copy pak0.pk3 from your\n"
- "legitimate Q3 CDROM.\n"
- "**************************************************\n\n\n",
- path->pack->checksum );
- }
- else
- {
- Com_Printf("\n\n"
- "**************************************************\n"
- "WARNING: pak%d.pk3 is present but its checksum (%u)\n"
- "is not correct. Please re-install the point release\n"
- "**************************************************\n\n\n",
- pakBasename[3]-'0', path->pack->checksum );
- }
- }
-
- foundPak |= 1<<(pakBasename[3]-'0');
- }
- }
-
- if( (!Cvar_VariableIntegerValue("com_standalone") ||
- !fs_gamedirvar->string[0] ||
- !Q_stricmp(fs_gamedirvar->string, BASEGAME) ||
- !Q_stricmp(fs_gamedirvar->string, "missionpack") )
- &&
- (!founddemo && (foundPak & 0x1ff) != 0x1ff) )
- {
- char errorText[MAX_STRING_CHARS] = "";
-
- if((foundPak&1) != 1 )
- {
- Q_strcat(errorText, sizeof(errorText),
- "\"pak0.pk3\" is missing. Please copy it "
- "from your legitimate Q3 CDROM. ");
- }
-
- if((foundPak&0x1fe) != 0x1fe )
- {
- Q_strcat(errorText, sizeof(errorText),
- "Point Release files are missing. Please "
- "re-install the 1.32 point release. ");
- }
-
- Q_strcat(errorText, sizeof(errorText),
- va("Also check that your ioq3 executable is in "
- "the correct place and that every file "
- "in the \"%s\" directory is present and readable", BASEGAME));
-
- Com_Error(ERR_FATAL, "%s", errorText);
- }
-
- if(foundPak & 1)
- Cvar_Set("com_standalone", "0");
-}
-#endif
-
-/*
-=====================
-FS_GamePureChecksum
-
-Returns the checksum of the pk3 from which the server loaded the qagame.qvm
-=====================
-*/
-const char *FS_GamePureChecksum( void ) {
- static char info[MAX_STRING_TOKENS];
- searchpath_t *search;
-
- info[0] = 0;
-
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- // is the element a pak file?
- if ( search->pack ) {
- if (search->pack->referenced & FS_QAGAME_REF) {
- Com_sprintf(info, sizeof(info), "%d", search->pack->checksum);
- }
- }
- }
-
- return info;
-}
-
-/*
-=====================
-FS_LoadedPakChecksums
-
-Returns a space separated string containing the checksums of all loaded pk3 files.
-Servers with sv_pure set will get this string and pass it to clients.
-=====================
-*/
-const char *FS_LoadedPakChecksums( void ) {
- static char info[BIG_INFO_STRING];
- searchpath_t *search;
-
- info[0] = 0;
-
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- // is the element a pak file?
- if ( !search->pack ) {
- continue;
- }
-
- Q_strcat( info, sizeof( info ), va("%i ", search->pack->checksum ) );
- }
-
- return info;
-}
-
-/*
-=====================
-FS_LoadedPakNames
-
-Returns a space separated string containing the names of all loaded pk3 files.
-Servers with sv_pure set will get this string and pass it to clients.
-=====================
-*/
-const char *FS_LoadedPakNames( void ) {
- static char info[BIG_INFO_STRING];
- searchpath_t *search;
-
- info[0] = 0;
-
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- // is the element a pak file?
- if ( !search->pack ) {
- continue;
- }
-
- if (*info) {
- Q_strcat(info, sizeof( info ), " " );
- }
- Q_strcat( info, sizeof( info ), search->pack->pakBasename );
- }
-
- return info;
-}
-
-/*
-=====================
-FS_LoadedPakPureChecksums
-
-Returns a space separated string containing the pure checksums of all loaded pk3 files.
-Servers with sv_pure use these checksums to compare with the checksums the clients send
-back to the server.
-=====================
-*/
-const char *FS_LoadedPakPureChecksums( void ) {
- static char info[BIG_INFO_STRING];
- searchpath_t *search;
-
- info[0] = 0;
-
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- // is the element a pak file?
- if ( !search->pack ) {
- continue;
- }
-
- Q_strcat( info, sizeof( info ), va("%i ", search->pack->pure_checksum ) );
- }
-
- return info;
-}
-
-/*
-=====================
-FS_ReferencedPakChecksums
-
-Returns a space separated string containing the checksums of all referenced pk3 files.
-The server will send this to the clients so they can check which files should be auto-downloaded.
-=====================
-*/
-const char *FS_ReferencedPakChecksums( void ) {
- static char info[BIG_INFO_STRING];
- searchpath_t *search;
-
- info[0] = 0;
-
-
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- // is the element a pak file?
- if ( search->pack ) {
- if (search->pack->referenced || Q_stricmpn(search->pack->pakGamename, BASEGAME, strlen(BASEGAME))) {
- Q_strcat( info, sizeof( info ), va("%i ", search->pack->checksum ) );
- }
- }
- }
-
- return info;
-}
-
-/*
-=====================
-FS_ReferencedPakPureChecksums
-
-Returns a space separated string containing the pure checksums of all referenced pk3 files.
-Servers with sv_pure set will get this string back from clients for pure validation
-
-The string has a specific order, "cgame ui @ ref1 ref2 ref3 ..."
-=====================
-*/
-const char *FS_ReferencedPakPureChecksums( void ) {
- static char info[BIG_INFO_STRING];
- searchpath_t *search;
- int nFlags, numPaks, checksum;
-
- info[0] = 0;
-
- checksum = fs_checksumFeed;
- numPaks = 0;
- for (nFlags = FS_CGAME_REF; nFlags; nFlags = nFlags >> 1) {
- if (nFlags & FS_GENERAL_REF) {
- // add a delimter between must haves and general refs
- //Q_strcat(info, sizeof(info), "@ ");
- info[strlen(info)+1] = '\0';
- info[strlen(info)+2] = '\0';
- info[strlen(info)] = '@';
- info[strlen(info)] = ' ';
- }
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- // is the element a pak file and has it been referenced based on flag?
- if ( search->pack && (search->pack->referenced & nFlags)) {
- Q_strcat( info, sizeof( info ), va("%i ", search->pack->pure_checksum ) );
- if (nFlags & (FS_CGAME_REF | FS_UI_REF)) {
- break;
- }
- checksum ^= search->pack->pure_checksum;
- numPaks++;
- }
- }
- }
- // last checksum is the encoded number of referenced pk3s
- checksum ^= numPaks;
- Q_strcat( info, sizeof( info ), va("%i ", checksum ) );
-
- return info;
-}
-
-/*
-=====================
-FS_ReferencedPakNames
-
-Returns a space separated string containing the names of all referenced pk3 files.
-The server will send this to the clients so they can check which files should be auto-downloaded.
-=====================
-*/
-const char *FS_ReferencedPakNames( void ) {
- static char info[BIG_INFO_STRING];
- searchpath_t *search;
-
- info[0] = 0;
-
- // we want to return ALL pk3's from the fs_game path
- // and referenced one's from baseq3
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- // is the element a pak file?
- if ( search->pack ) {
- if (search->pack->referenced || Q_stricmpn(search->pack->pakGamename, BASEGAME, strlen(BASEGAME))) {
- if (*info) {
- Q_strcat(info, sizeof( info ), " " );
- }
- Q_strcat( info, sizeof( info ), search->pack->pakGamename );
- Q_strcat( info, sizeof( info ), "/" );
- Q_strcat( info, sizeof( info ), search->pack->pakBasename );
- }
- }
- }
-
- return info;
-}
-
-/*
-=====================
-FS_ClearPakReferences
-=====================
-*/
-void FS_ClearPakReferences( int flags ) {
- searchpath_t *search;
-
- if ( !flags ) {
- flags = -1;
- }
- for ( search = fs_searchpaths; search; search = search->next ) {
- // is the element a pak file and has it been referenced?
- if ( search->pack ) {
- search->pack->referenced &= ~flags;
- }
- }
-}
-
-
-/*
-=====================
-FS_PureServerSetLoadedPaks
-
-If the string is empty, all data sources will be allowed.
-If not empty, only pk3 files that match one of the space
-separated checksums will be checked for files, with the
-exception of .cfg and .dat files.
-=====================
-*/
-void FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames ) {
- int i, c, d;
-
- Cmd_TokenizeString( pakSums );
-
- c = Cmd_Argc();
- if ( c > MAX_SEARCH_PATHS ) {
- c = MAX_SEARCH_PATHS;
- }
-
- fs_numServerPaks = c;
-
- for ( i = 0 ; i < c ; i++ ) {
- fs_serverPaks[i] = atoi( Cmd_Argv( i ) );
- }
-
- if (fs_numServerPaks) {
- Com_DPrintf( "Connected to a pure server.\n" );
- }
- else
- {
- if (fs_reordered)
- {
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=540
- // force a restart to make sure the search order will be correct
- Com_DPrintf( "FS search reorder is required\n" );
- FS_Restart(fs_checksumFeed);
- return;
- }
- }
-
- for ( i = 0 ; i < c ; i++ ) {
- if (fs_serverPakNames[i]) {
- Z_Free(fs_serverPakNames[i]);
- }
- fs_serverPakNames[i] = NULL;
- }
- if ( pakNames && *pakNames ) {
- Cmd_TokenizeString( pakNames );
-
- d = Cmd_Argc();
- if ( d > MAX_SEARCH_PATHS ) {
- d = MAX_SEARCH_PATHS;
- }
-
- for ( i = 0 ; i < d ; i++ ) {
- fs_serverPakNames[i] = CopyString( Cmd_Argv( i ) );
- }
- }
-}
-
-/*
-=====================
-FS_PureServerSetReferencedPaks
-
-The checksums and names of the pk3 files referenced at the server
-are sent to the client and stored here. The client will use these
-checksums to see if any pk3 files need to be auto-downloaded.
-=====================
-*/
-void FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames ) {
- int i, c, d = 0;
-
- Cmd_TokenizeString( pakSums );
-
- c = Cmd_Argc();
- if ( c > MAX_SEARCH_PATHS ) {
- c = MAX_SEARCH_PATHS;
- }
-
- for ( i = 0 ; i < c ; i++ ) {
- fs_serverReferencedPaks[i] = atoi( Cmd_Argv( i ) );
- }
-
- for (i = 0 ; i < sizeof(fs_serverReferencedPakNames) / sizeof(*fs_serverReferencedPakNames); i++)
- {
- if(fs_serverReferencedPakNames[i])
- Z_Free(fs_serverReferencedPakNames[i]);
-
- fs_serverReferencedPakNames[i] = NULL;
- }
-
- if ( pakNames && *pakNames ) {
- Cmd_TokenizeString( pakNames );
-
- d = Cmd_Argc();
-
- if(d > c)
- d = c;
-
- for ( i = 0 ; i < d ; i++ ) {
- fs_serverReferencedPakNames[i] = CopyString( Cmd_Argv( i ) );
- }
- }
-
- // ensure that there are as many checksums as there are pak names.
- if(d < c)
- c = d;
-
- fs_numServerReferencedPaks = c;
-}
-
-/*
-================
-FS_InitFilesystem
-
-Called only at inital startup, not when the filesystem
-is resetting due to a game change
-================
-*/
-void FS_InitFilesystem( void ) {
- // allow command line parms to override our defaults
- // we have to specially handle this, because normal command
- // line variable sets don't happen until after the filesystem
- // has already been initialized
- Com_StartupVariable( "fs_basepath" );
- Com_StartupVariable( "fs_homepath" );
- Com_StartupVariable( "fs_game" );
-
- // try to start up normally
- FS_Startup( BASEGAME );
-
-#ifndef STANDALONE
- FS_CheckPak0( );
-#endif
-
- // if we can't find default.cfg, assume that the paths are
- // busted and error out now, rather than getting an unreadable
- // graphics screen when the font fails to load
- if ( FS_ReadFile( "default.cfg", NULL ) <= 0 ) {
- Com_Error( ERR_FATAL, "Couldn't load default.cfg" );
- }
-
- Q_strncpyz(lastValidBase, fs_basepath->string, sizeof(lastValidBase));
- Q_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame));
-}
-
-
-/*
-================
-FS_Restart
-================
-*/
-void FS_Restart( int checksumFeed ) {
-
- // free anything we currently have loaded
- FS_Shutdown(qfalse);
-
- // set the checksum feed
- fs_checksumFeed = checksumFeed;
-
- // clear pak references
- FS_ClearPakReferences(0);
-
- // try to start up normally
- FS_Startup( BASEGAME );
-
-#ifndef STANDALONE
- FS_CheckPak0( );
-#endif
-
- // if we can't find default.cfg, assume that the paths are
- // busted and error out now, rather than getting an unreadable
- // graphics screen when the font fails to load
- if ( FS_ReadFile( "default.cfg", NULL ) <= 0 ) {
- // this might happen when connecting to a pure server not using BASEGAME/pak0.pk3
- // (for instance a TA demo server)
- if (lastValidBase[0]) {
- FS_PureServerSetLoadedPaks("", "");
- Cvar_Set("fs_basepath", lastValidBase);
- Cvar_Set("fs_gamedirvar", lastValidGame);
- lastValidBase[0] = '\0';
- lastValidGame[0] = '\0';
- FS_Restart(checksumFeed);
- Com_Error( ERR_DROP, "Invalid game folder\n" );
- return;
- }
- Com_Error( ERR_FATAL, "Couldn't load default.cfg" );
- }
-
- if ( Q_stricmp(fs_gamedirvar->string, lastValidGame) ) {
- // skip the q3config.cfg if "safe" is on the command line
- if ( !Com_SafeMode() ) {
- Cbuf_AddText ("exec " Q3CONFIG_CFG "\n");
- }
- }
-
- Q_strncpyz(lastValidBase, fs_basepath->string, sizeof(lastValidBase));
- Q_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame));
-
-}
-
-/*
-=================
-FS_ConditionalRestart
-restart if necessary
-=================
-*/
-qboolean FS_ConditionalRestart(int checksumFeed)
-{
- if(fs_gamedirvar->modified)
- {
- Com_GameRestart(checksumFeed, qfalse);
- return qtrue;
- }
-
- else if(checksumFeed != fs_checksumFeed)
- {
- FS_Restart(checksumFeed);
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-========================================================================================
-
-Handle based file calls for virtual machines
-
-========================================================================================
-*/
-
-int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
- int r;
- qboolean sync;
-
- sync = qfalse;
-
- switch( mode ) {
- case FS_READ:
- r = FS_FOpenFileRead( qpath, f, qtrue );
- break;
- case FS_WRITE:
- *f = FS_FOpenFileWrite( qpath );
- r = 0;
- if (*f == 0) {
- r = -1;
- }
- break;
- case FS_APPEND_SYNC:
- sync = qtrue;
- case FS_APPEND:
- *f = FS_FOpenFileAppend( qpath );
- r = 0;
- if (*f == 0) {
- r = -1;
- }
- break;
- default:
- Com_Error( ERR_FATAL, "FS_FOpenFileByMode: bad mode" );
- return -1;
- }
-
- if (!f) {
- return r;
- }
-
- if ( *f ) {
- if (fsh[*f].zipFile == qtrue) {
- fsh[*f].baseOffset = unztell(fsh[*f].handleFiles.file.z);
- } else {
- fsh[*f].baseOffset = ftell(fsh[*f].handleFiles.file.o);
- }
- fsh[*f].fileSize = r;
- fsh[*f].streamed = qfalse;
-
- if (mode == FS_READ) {
- fsh[*f].streamed = qtrue;
- }
- }
- fsh[*f].handleSync = sync;
-
- return r;
-}
-
-int FS_FTell( fileHandle_t f ) {
- int pos;
- if (fsh[f].zipFile == qtrue) {
- pos = unztell(fsh[f].handleFiles.file.z);
- } else {
- pos = ftell(fsh[f].handleFiles.file.o);
- }
- return pos;
-}
-
-void FS_Flush( fileHandle_t f ) {
- fflush(fsh[f].handleFiles.file.o);
-}
-
-void FS_FilenameCompletion( const char *dir, const char *ext,
- qboolean stripExt, void(*callback)(const char *s) ) {
- char **filenames;
- int nfiles;
- int i;
- char filename[ MAX_STRING_CHARS ];
-
- filenames = FS_ListFilteredFiles( dir, ext, NULL, &nfiles );
-
- FS_SortFileList( filenames, nfiles );
-
- for( i = 0; i < nfiles; i++ ) {
- FS_ConvertPath( filenames[ i ] );
- Q_strncpyz( filename, filenames[ i ], MAX_STRING_CHARS );
-
- if( stripExt ) {
- COM_StripExtension(filename, filename, sizeof(filename));
- }
-
- callback( filename );
- }
- FS_FreeFileList( filenames );
-}
diff --git a/engine/code/qcommon/huffman.c b/engine/code/qcommon/huffman.c
deleted file mode 100644
index 2ff4ae5..0000000
--- a/engine/code/qcommon/huffman.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/* This is based on the Adaptive Huffman algorithm described in Sayood's Data
- * Compression book. The ranks are not actually stored, but implicitly defined
- * by the location of a node within a doubly-linked list */
-
-#include "q_shared.h"
-#include "qcommon.h"
-
-static int bloc = 0;
-
-void Huff_putBit( int bit, byte *fout, int *offset) {
- bloc = *offset;
- if ((bloc&7) == 0) {
- fout[(bloc>>3)] = 0;
- }
- fout[(bloc>>3)] |= bit << (bloc&7);
- bloc++;
- *offset = bloc;
-}
-
-int Huff_getBloc(void)
-{
- return bloc;
-}
-
-void Huff_setBloc(int _bloc)
-{
- bloc = _bloc;
-}
-
-int Huff_getBit( byte *fin, int *offset) {
- int t;
- bloc = *offset;
- t = (fin[(bloc>>3)] >> (bloc&7)) & 0x1;
- bloc++;
- *offset = bloc;
- return t;
-}
-
-/* Add a bit to the output file (buffered) */
-static void add_bit (char bit, byte *fout) {
- if ((bloc&7) == 0) {
- fout[(bloc>>3)] = 0;
- }
- fout[(bloc>>3)] |= bit << (bloc&7);
- bloc++;
-}
-
-/* Receive one bit from the input file (buffered) */
-static int get_bit (byte *fin) {
- int t;
- t = (fin[(bloc>>3)] >> (bloc&7)) & 0x1;
- bloc++;
- return t;
-}
-
-static node_t **get_ppnode(huff_t* huff) {
- node_t **tppnode;
- if (!huff->freelist) {
- return &(huff->nodePtrs[huff->blocPtrs++]);
- } else {
- tppnode = huff->freelist;
- huff->freelist = (node_t **)*tppnode;
- return tppnode;
- }
-}
-
-static void free_ppnode(huff_t* huff, node_t **ppnode) {
- *ppnode = (node_t *)huff->freelist;
- huff->freelist = ppnode;
-}
-
-/* Swap the location of these two nodes in the tree */
-static void swap (huff_t* huff, node_t *node1, node_t *node2) {
- node_t *par1, *par2;
-
- par1 = node1->parent;
- par2 = node2->parent;
-
- if (par1) {
- if (par1->left == node1) {
- par1->left = node2;
- } else {
- par1->right = node2;
- }
- } else {
- huff->tree = node2;
- }
-
- if (par2) {
- if (par2->left == node2) {
- par2->left = node1;
- } else {
- par2->right = node1;
- }
- } else {
- huff->tree = node1;
- }
-
- node1->parent = par2;
- node2->parent = par1;
-}
-
-/* Swap these two nodes in the linked list (update ranks) */
-static void swaplist(node_t *node1, node_t *node2) {
- node_t *par1;
-
- par1 = node1->next;
- node1->next = node2->next;
- node2->next = par1;
-
- par1 = node1->prev;
- node1->prev = node2->prev;
- node2->prev = par1;
-
- if (node1->next == node1) {
- node1->next = node2;
- }
- if (node2->next == node2) {
- node2->next = node1;
- }
- if (node1->next) {
- node1->next->prev = node1;
- }
- if (node2->next) {
- node2->next->prev = node2;
- }
- if (node1->prev) {
- node1->prev->next = node1;
- }
- if (node2->prev) {
- node2->prev->next = node2;
- }
-}
-
-/* Do the increments */
-static void increment(huff_t* huff, node_t *node) {
- node_t *lnode;
-
- if (!node) {
- return;
- }
-
- if (node->next != NULL && node->next->weight == node->weight) {
- lnode = *node->head;
- if (lnode != node->parent) {
- swap(huff, lnode, node);
- }
- swaplist(lnode, node);
- }
- if (node->prev && node->prev->weight == node->weight) {
- *node->head = node->prev;
- } else {
- *node->head = NULL;
- free_ppnode(huff, node->head);
- }
- node->weight++;
- if (node->next && node->next->weight == node->weight) {
- node->head = node->next->head;
- } else {
- node->head = get_ppnode(huff);
- *node->head = node;
- }
- if (node->parent) {
- increment(huff, node->parent);
- if (node->prev == node->parent) {
- swaplist(node, node->parent);
- if (*node->head == node) {
- *node->head = node->parent;
- }
- }
- }
-}
-
-void Huff_addRef(huff_t* huff, byte ch) {
- node_t *tnode, *tnode2;
- if (huff->loc[ch] == NULL) { /* if this is the first transmission of this node */
- tnode = &(huff->nodeList[huff->blocNode++]);
- tnode2 = &(huff->nodeList[huff->blocNode++]);
-
- tnode2->symbol = INTERNAL_NODE;
- tnode2->weight = 1;
- tnode2->next = huff->lhead->next;
- if (huff->lhead->next) {
- huff->lhead->next->prev = tnode2;
- if (huff->lhead->next->weight == 1) {
- tnode2->head = huff->lhead->next->head;
- } else {
- tnode2->head = get_ppnode(huff);
- *tnode2->head = tnode2;
- }
- } else {
- tnode2->head = get_ppnode(huff);
- *tnode2->head = tnode2;
- }
- huff->lhead->next = tnode2;
- tnode2->prev = huff->lhead;
-
- tnode->symbol = ch;
- tnode->weight = 1;
- tnode->next = huff->lhead->next;
- if (huff->lhead->next) {
- huff->lhead->next->prev = tnode;
- if (huff->lhead->next->weight == 1) {
- tnode->head = huff->lhead->next->head;
- } else {
- /* this should never happen */
- tnode->head = get_ppnode(huff);
- *tnode->head = tnode2;
- }
- } else {
- /* this should never happen */
- tnode->head = get_ppnode(huff);
- *tnode->head = tnode;
- }
- huff->lhead->next = tnode;
- tnode->prev = huff->lhead;
- tnode->left = tnode->right = NULL;
-
- if (huff->lhead->parent) {
- if (huff->lhead->parent->left == huff->lhead) { /* lhead is guaranteed to by the NYT */
- huff->lhead->parent->left = tnode2;
- } else {
- huff->lhead->parent->right = tnode2;
- }
- } else {
- huff->tree = tnode2;
- }
-
- tnode2->right = tnode;
- tnode2->left = huff->lhead;
-
- tnode2->parent = huff->lhead->parent;
- huff->lhead->parent = tnode->parent = tnode2;
-
- huff->loc[ch] = tnode;
-
- increment(huff, tnode2->parent);
- } else {
- increment(huff, huff->loc[ch]);
- }
-}
-
-/* Get a symbol */
-int Huff_Receive (node_t *node, int *ch, byte *fin) {
- while (node && node->symbol == INTERNAL_NODE) {
- if (get_bit(fin)) {
- node = node->right;
- } else {
- node = node->left;
- }
- }
- if (!node) {
- return 0;
-// Com_Error(ERR_DROP, "Illegal tree!\n");
- }
- return (*ch = node->symbol);
-}
-
-/* Get a symbol */
-void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) {
- bloc = *offset;
- while (node && node->symbol == INTERNAL_NODE) {
- if (get_bit(fin)) {
- node = node->right;
- } else {
- node = node->left;
- }
- }
- if (!node) {
- *ch = 0;
- return;
-// Com_Error(ERR_DROP, "Illegal tree!\n");
- }
- *ch = node->symbol;
- *offset = bloc;
-}
-
-/* Send the prefix code for this node */
-static void send(node_t *node, node_t *child, byte *fout) {
- if (node->parent) {
- send(node->parent, node, fout);
- }
- if (child) {
- if (node->right == child) {
- add_bit(1, fout);
- } else {
- add_bit(0, fout);
- }
- }
-}
-
-/* Send a symbol */
-void Huff_transmit (huff_t *huff, int ch, byte *fout) {
- int i;
- if (huff->loc[ch] == NULL) {
- /* node_t hasn't been transmitted, send a NYT, then the symbol */
- Huff_transmit(huff, NYT, fout);
- for (i = 7; i >= 0; i--) {
- add_bit((char)((ch >> i) & 0x1), fout);
- }
- } else {
- send(huff->loc[ch], NULL, fout);
- }
-}
-
-void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset) {
- bloc = *offset;
- send(huff->loc[ch], NULL, fout);
- *offset = bloc;
-}
-
-void Huff_Decompress(msg_t *mbuf, int offset) {
- int ch, cch, i, j, size;
- byte seq[65536];
- byte* buffer;
- huff_t huff;
-
- size = mbuf->cursize - offset;
- buffer = mbuf->data + offset;
-
- if ( size <= 0 ) {
- return;
- }
-
- Com_Memset(&huff, 0, sizeof(huff_t));
- // Initialize the tree & list with the NYT node
- huff.tree = huff.lhead = huff.ltail = huff.loc[NYT] = &(huff.nodeList[huff.blocNode++]);
- huff.tree->symbol = NYT;
- huff.tree->weight = 0;
- huff.lhead->next = huff.lhead->prev = NULL;
- huff.tree->parent = huff.tree->left = huff.tree->right = NULL;
-
- cch = buffer[0]*256 + buffer[1];
- // don't overflow with bad messages
- if ( cch > mbuf->maxsize - offset ) {
- cch = mbuf->maxsize - offset;
- }
- bloc = 16;
-
- for ( j = 0; j < cch; j++ ) {
- ch = 0;
- // don't overflow reading from the messages
- // FIXME: would it be better to have a overflow check in get_bit ?
- if ( (bloc >> 3) > size ) {
- seq[j] = 0;
- break;
- }
- Huff_Receive(huff.tree, &ch, buffer); /* Get a character */
- if ( ch == NYT ) { /* We got a NYT, get the symbol associated with it */
- ch = 0;
- for ( i = 0; i < 8; i++ ) {
- ch = (ch<<1) + get_bit(buffer);
- }
- }
-
- seq[j] = ch; /* Write symbol */
-
- Huff_addRef(&huff, (byte)ch); /* Increment node */
- }
- mbuf->cursize = cch + offset;
- Com_Memcpy(mbuf->data + offset, seq, cch);
-}
-
-extern int oldsize;
-
-void Huff_Compress(msg_t *mbuf, int offset) {
- int i, ch, size;
- byte seq[65536];
- byte* buffer;
- huff_t huff;
-
- size = mbuf->cursize - offset;
- buffer = mbuf->data+ + offset;
-
- if (size<=0) {
- return;
- }
-
- Com_Memset(&huff, 0, sizeof(huff_t));
- // Add the NYT (not yet transmitted) node into the tree/list */
- huff.tree = huff.lhead = huff.loc[NYT] = &(huff.nodeList[huff.blocNode++]);
- huff.tree->symbol = NYT;
- huff.tree->weight = 0;
- huff.lhead->next = huff.lhead->prev = NULL;
- huff.tree->parent = huff.tree->left = huff.tree->right = NULL;
- huff.loc[NYT] = huff.tree;
-
- seq[0] = (size>>8);
- seq[1] = size&0xff;
-
- bloc = 16;
-
- for (i=0; i<size; i++ ) {
- ch = buffer[i];
- Huff_transmit(&huff, ch, seq); /* Transmit symbol */
- Huff_addRef(&huff, (byte)ch); /* Do update */
- }
-
- bloc += 8; // next byte
-
- mbuf->cursize = (bloc>>3) + offset;
- Com_Memcpy(mbuf->data+offset, seq, (bloc>>3));
-}
-
-void Huff_Init(huffman_t *huff) {
-
- Com_Memset(&huff->compressor, 0, sizeof(huff_t));
- Com_Memset(&huff->decompressor, 0, sizeof(huff_t));
-
- // Initialize the tree & list with the NYT node
- huff->decompressor.tree = huff->decompressor.lhead = huff->decompressor.ltail = huff->decompressor.loc[NYT] = &(huff->decompressor.nodeList[huff->decompressor.blocNode++]);
- huff->decompressor.tree->symbol = NYT;
- huff->decompressor.tree->weight = 0;
- huff->decompressor.lhead->next = huff->decompressor.lhead->prev = NULL;
- huff->decompressor.tree->parent = huff->decompressor.tree->left = huff->decompressor.tree->right = NULL;
-
- // Add the NYT (not yet transmitted) node into the tree/list */
- huff->compressor.tree = huff->compressor.lhead = huff->compressor.loc[NYT] = &(huff->compressor.nodeList[huff->compressor.blocNode++]);
- huff->compressor.tree->symbol = NYT;
- huff->compressor.tree->weight = 0;
- huff->compressor.lhead->next = huff->compressor.lhead->prev = NULL;
- huff->compressor.tree->parent = huff->compressor.tree->left = huff->compressor.tree->right = NULL;
- huff->compressor.loc[NYT] = huff->compressor.tree;
-}
-
diff --git a/engine/code/qcommon/ioapi.c b/engine/code/qcommon/ioapi.c
deleted file mode 100644
index aab3c00..0000000
--- a/engine/code/qcommon/ioapi.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/* ioapi.c -- IO base function header for compress/uncompress .zip
- files using zlib + zip or unzip API
-
- Version 1.01e, February 12th, 2005
-
- Copyright (C) 1998-2005 Gilles Vollant
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef USE_LOCAL_HEADERS
-#include "../zlib/zlib.h"
-#else
-#include <zlib.h>
-#endif
-
-#include "ioapi.h"
-
-
-
-/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
-
-#ifndef SEEK_CUR
-#define SEEK_CUR 1
-#endif
-
-#ifndef SEEK_END
-#define SEEK_END 2
-#endif
-
-#ifndef SEEK_SET
-#define SEEK_SET 0
-#endif
-
-voidpf ZCALLBACK fopen_file_func OF((
- voidpf opaque,
- const char* filename,
- int mode));
-
-uLong ZCALLBACK fread_file_func OF((
- voidpf opaque,
- voidpf stream,
- void* buf,
- uLong size));
-
-uLong ZCALLBACK fwrite_file_func OF((
- voidpf opaque,
- voidpf stream,
- const void* buf,
- uLong size));
-
-long ZCALLBACK ftell_file_func OF((
- voidpf opaque,
- voidpf stream));
-
-long ZCALLBACK fseek_file_func OF((
- voidpf opaque,
- voidpf stream,
- uLong offset,
- int origin));
-
-int ZCALLBACK fclose_file_func OF((
- voidpf opaque,
- voidpf stream));
-
-int ZCALLBACK ferror_file_func OF((
- voidpf opaque,
- voidpf stream));
-
-
-voidpf ZCALLBACK fopen_file_func (opaque, filename, mode)
- voidpf opaque;
- const char* filename;
- int mode;
-{
- FILE* file = NULL;
- const char* mode_fopen = NULL;
- if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
- mode_fopen = "rb";
- else
- if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
- mode_fopen = "r+b";
- else
- if (mode & ZLIB_FILEFUNC_MODE_CREATE)
- mode_fopen = "wb";
-
- if ((filename!=NULL) && (mode_fopen != NULL))
- file = fopen(filename, mode_fopen);
- return file;
-}
-
-
-uLong ZCALLBACK fread_file_func (opaque, stream, buf, size)
- voidpf opaque;
- voidpf stream;
- void* buf;
- uLong size;
-{
- uLong ret;
- ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
- return ret;
-}
-
-
-uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size)
- voidpf opaque;
- voidpf stream;
- const void* buf;
- uLong size;
-{
- uLong ret;
- ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
- return ret;
-}
-
-long ZCALLBACK ftell_file_func (opaque, stream)
- voidpf opaque;
- voidpf stream;
-{
- long ret;
- ret = ftell((FILE *)stream);
- return ret;
-}
-
-long ZCALLBACK fseek_file_func (opaque, stream, offset, origin)
- voidpf opaque;
- voidpf stream;
- uLong offset;
- int origin;
-{
- int fseek_origin=0;
- long ret;
- switch (origin)
- {
- case ZLIB_FILEFUNC_SEEK_CUR :
- fseek_origin = SEEK_CUR;
- break;
- case ZLIB_FILEFUNC_SEEK_END :
- fseek_origin = SEEK_END;
- break;
- case ZLIB_FILEFUNC_SEEK_SET :
- fseek_origin = SEEK_SET;
- break;
- default: return -1;
- }
- ret = 0;
- fseek((FILE *)stream, offset, fseek_origin);
- return ret;
-}
-
-int ZCALLBACK fclose_file_func (opaque, stream)
- voidpf opaque;
- voidpf stream;
-{
- int ret;
- ret = fclose((FILE *)stream);
- return ret;
-}
-
-int ZCALLBACK ferror_file_func (opaque, stream)
- voidpf opaque;
- voidpf stream;
-{
- int ret;
- ret = ferror((FILE *)stream);
- return ret;
-}
-
-void fill_fopen_filefunc (pzlib_filefunc_def)
- zlib_filefunc_def* pzlib_filefunc_def;
-{
- pzlib_filefunc_def->zopen_file = fopen_file_func;
- pzlib_filefunc_def->zread_file = fread_file_func;
- pzlib_filefunc_def->zwrite_file = fwrite_file_func;
- pzlib_filefunc_def->ztell_file = ftell_file_func;
- pzlib_filefunc_def->zseek_file = fseek_file_func;
- pzlib_filefunc_def->zclose_file = fclose_file_func;
- pzlib_filefunc_def->zerror_file = ferror_file_func;
- pzlib_filefunc_def->opaque = NULL;
-}
diff --git a/engine/code/qcommon/ioapi.h b/engine/code/qcommon/ioapi.h
deleted file mode 100644
index 7d457ba..0000000
--- a/engine/code/qcommon/ioapi.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* ioapi.h -- IO base function header for compress/uncompress .zip
- files using zlib + zip or unzip API
-
- Version 1.01e, February 12th, 2005
-
- Copyright (C) 1998-2005 Gilles Vollant
-*/
-
-#ifndef _ZLIBIOAPI_H
-#define _ZLIBIOAPI_H
-
-
-#define ZLIB_FILEFUNC_SEEK_CUR (1)
-#define ZLIB_FILEFUNC_SEEK_END (2)
-#define ZLIB_FILEFUNC_SEEK_SET (0)
-
-#define ZLIB_FILEFUNC_MODE_READ (1)
-#define ZLIB_FILEFUNC_MODE_WRITE (2)
-#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
-
-#define ZLIB_FILEFUNC_MODE_EXISTING (4)
-#define ZLIB_FILEFUNC_MODE_CREATE (8)
-
-
-#ifndef ZCALLBACK
-
-#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
-#define ZCALLBACK CALLBACK
-#else
-#define ZCALLBACK
-#endif
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
-typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
-typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
-typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
-typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
-typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
-typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
-
-typedef struct zlib_filefunc_def_s
-{
- open_file_func zopen_file;
- read_file_func zread_file;
- write_file_func zwrite_file;
- tell_file_func ztell_file;
- seek_file_func zseek_file;
- close_file_func zclose_file;
- testerror_file_func zerror_file;
- voidpf opaque;
-} zlib_filefunc_def;
-
-
-
-void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
-
-#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size))
-#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size))
-#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream))
-#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode))
-#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream))
-#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream))
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
diff --git a/engine/code/qcommon/md4.c b/engine/code/qcommon/md4.c
deleted file mode 100644
index 838b062..0000000
--- a/engine/code/qcommon/md4.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- mdfour.c
-
- An implementation of MD4 designed for use in the samba SMB
- authentication protocol
-
- Copyright (C) 1997-1998 Andrew Tridgell
-
- 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:
-
- Free Software Foundation, Inc.
- 59 Temple Place - Suite 330
- Boston, MA 02111-1307, USA
-
- $Id: mdfour.c,v 1.1 2002/08/23 22:03:27 abster Exp $
-*/
-
-#include "q_shared.h"
-#include "qcommon.h"
-
-struct mdfour {
- uint32_t A, B, C, D;
- uint32_t totalN;
-};
-
-
-/* NOTE: This code makes no attempt to be fast!
-
- It assumes that a int is at least 32 bits long
-*/
-
-static struct mdfour *m;
-
-#define F(X,Y,Z) (((X)&(Y)) | ((~(X))&(Z)))
-#define G(X,Y,Z) (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)))
-#define H(X,Y,Z) ((X)^(Y)^(Z))
-#define lshift(x,s) (((x)<<(s)) | ((x)>>(32-(s))))
-
-#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
-#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + 0x5A827999,s)
-#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + 0x6ED9EBA1,s)
-
-/* this applies md4 to 64 byte chunks */
-static void mdfour64(uint32_t *M)
-{
- int j;
- uint32_t AA, BB, CC, DD;
- uint32_t X[16];
- uint32_t A,B,C,D;
-
- for (j=0;j<16;j++)
- X[j] = M[j];
-
- A = m->A; B = m->B; C = m->C; D = m->D;
- AA = A; BB = B; CC = C; DD = D;
-
- ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
- ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
- ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
- ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
- ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
- ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
- ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
- ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
-
- ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
- ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
- ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
- ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
- ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
- ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
- ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
- ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
-
- ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
- ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
- ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
- ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
- ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
- ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
- ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
- ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
-
- A += AA; B += BB; C += CC; D += DD;
-
- for (j=0;j<16;j++)
- X[j] = 0;
-
- m->A = A; m->B = B; m->C = C; m->D = D;
-}
-
-static void copy64(uint32_t *M, byte *in)
-{
- int i;
-
- for (i=0;i<16;i++)
- M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
- (in[i*4+1]<<8) | (in[i*4+0]<<0);
-}
-
-static void copy4(byte *out,uint32_t x)
-{
- out[0] = x&0xFF;
- out[1] = (x>>8)&0xFF;
- out[2] = (x>>16)&0xFF;
- out[3] = (x>>24)&0xFF;
-}
-
-void mdfour_begin(struct mdfour *md)
-{
- md->A = 0x67452301;
- md->B = 0xefcdab89;
- md->C = 0x98badcfe;
- md->D = 0x10325476;
- md->totalN = 0;
-}
-
-
-static void mdfour_tail(byte *in, int n)
-{
- byte buf[128];
- uint32_t M[16];
- uint32_t b;
-
- m->totalN += n;
-
- b = m->totalN * 8;
-
- Com_Memset(buf, 0, 128);
- if (n) Com_Memcpy(buf, in, n);
- buf[n] = 0x80;
-
- if (n <= 55) {
- copy4(buf+56, b);
- copy64(M, buf);
- mdfour64(M);
- } else {
- copy4(buf+120, b);
- copy64(M, buf);
- mdfour64(M);
- copy64(M, buf+64);
- mdfour64(M);
- }
-}
-
-static void mdfour_update(struct mdfour *md, byte *in, int n)
-{
- uint32_t M[16];
-
- m = md;
-
- if (n == 0) mdfour_tail(in, n);
-
- while (n >= 64) {
- copy64(M, in);
- mdfour64(M);
- in += 64;
- n -= 64;
- m->totalN += 64;
- }
-
- mdfour_tail(in, n);
-}
-
-
-static void mdfour_result(struct mdfour *md, byte *out)
-{
- m = md;
-
- copy4(out, m->A);
- copy4(out+4, m->B);
- copy4(out+8, m->C);
- copy4(out+12, m->D);
-}
-
-static void mdfour(byte *out, byte *in, int n)
-{
- struct mdfour md;
- mdfour_begin(&md);
- mdfour_update(&md, in, n);
- mdfour_result(&md, out);
-}
-
-//===================================================================
-
-unsigned Com_BlockChecksum (const void *buffer, int length)
-{
- int digest[4];
- unsigned val;
-
- mdfour( (byte *)digest, (byte *)buffer, length );
-
- val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
-
- return val;
-}
diff --git a/engine/code/qcommon/md5.c b/engine/code/qcommon/md5.c
deleted file mode 100644
index 5cf12bb..0000000
--- a/engine/code/qcommon/md5.c
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest. This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to MD5Init, call MD5Update as
- * needed on buffers full of bytes, and then call MD5Final, which
- * will fill a supplied 16-byte array with the digest.
- */
-#include "q_shared.h"
-#include "qcommon.h"
-
-typedef struct MD5Context {
- uint32_t buf[4];
- uint32_t bits[2];
- unsigned char in[64];
-} MD5_CTX;
-
-#ifndef Q3_BIG_ENDIAN
- #define byteReverse(buf, len) /* Nothing */
-#else
- static void byteReverse(unsigned char *buf, unsigned longs);
-
- /*
- * Note: this code is harmless on little-endian machines.
- */
- static void byteReverse(unsigned char *buf, unsigned longs)
- {
- uint32_t t;
- do {
- t = (uint32_t)
- ((unsigned) buf[3] << 8 | buf[2]) << 16 |
- ((unsigned) buf[1] << 8 | buf[0]);
- *(uint32_t *) buf = t;
- buf += 4;
- } while (--longs);
- }
-#endif // Q3_BIG_ENDIAN
-
-/*
- * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
- * initialization constants.
- */
-static void MD5Init(struct MD5Context *ctx)
-{
- ctx->buf[0] = 0x67452301;
- ctx->buf[1] = 0xefcdab89;
- ctx->buf[2] = 0x98badcfe;
- ctx->buf[3] = 0x10325476;
-
- ctx->bits[0] = 0;
- ctx->bits[1] = 0;
-}
-/* The four core functions - F1 is optimized somewhat */
-
-/* #define F1(x, y, z) (x & y | ~x & z) */
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-/* This is the central step in the MD5 algorithm. */
-#define MD5STEP(f, w, x, y, z, data, s) \
- ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
-
-/*
- * The core of the MD5 algorithm, this alters an existing MD5 hash to
- * reflect the addition of 16 longwords of new data. MD5Update blocks
- * the data and converts bytes into longwords for this routine.
- */
-static void MD5Transform(uint32_t buf[4],
- uint32_t const in[16])
-{
- register uint32_t a, b, c, d;
-
- a = buf[0];
- b = buf[1];
- c = buf[2];
- d = buf[3];
-
- MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
- MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
- MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
- MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
- MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
- MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
- MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
- MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
- MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
- MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
- MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
- MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
- MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
- MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
- MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
- MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
- MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
- MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
- MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
- MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
- MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
- MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
- MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
- MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
- MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
- MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
- MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
- MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
- MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
- MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
- MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
- MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
- MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
- MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
- MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
- MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
- MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
- MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
- MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
- MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
- MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
- MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
- MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
- MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
- MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
- MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
- MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
- MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
- MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
- MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
- MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
- MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
- MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
- MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
- MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
- MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
- MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
- MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
- MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
- MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
- MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
- MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
- MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
- MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
- buf[0] += a;
- buf[1] += b;
- buf[2] += c;
- buf[3] += d;
-}
-
-/*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- */
-static void MD5Update(struct MD5Context *ctx, unsigned char const *buf,
- unsigned len)
-{
- uint32_t t;
-
- /* Update bitcount */
-
- t = ctx->bits[0];
- if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
- ctx->bits[1]++; /* Carry from low to high */
- ctx->bits[1] += len >> 29;
-
- t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
-
- /* Handle any leading odd-sized chunks */
-
- if (t) {
- unsigned char *p = (unsigned char *) ctx->in + t;
-
- t = 64 - t;
- if (len < t) {
- memcpy(p, buf, len);
- return;
- }
- memcpy(p, buf, t);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- buf += t;
- len -= t;
- }
- /* Process data in 64-byte chunks */
-
- while (len >= 64) {
- memcpy(ctx->in, buf, 64);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- buf += 64;
- len -= 64;
- }
-
- /* Handle any remaining bytes of data. */
-
- memcpy(ctx->in, buf, len);
-}
-
-
-/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
- * 1 0* (64-bit count of bits processed, MSB-first)
- */
-static void MD5Final(struct MD5Context *ctx, unsigned char *digest)
-{
- unsigned count;
- unsigned char *p;
-
- /* Compute number of bytes mod 64 */
- count = (ctx->bits[0] >> 3) & 0x3F;
-
- /* Set the first char of padding to 0x80. This is safe since there is
- always at least one byte free */
- p = ctx->in + count;
- *p++ = 0x80;
-
- /* Bytes of padding needed to make 64 bytes */
- count = 64 - 1 - count;
-
- /* Pad out to 56 mod 64 */
- if (count < 8) {
- /* Two lots of padding: Pad the first block to 64 bytes */
- memset(p, 0, count);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
-
- /* Now fill the next block with 56 bytes */
- memset(ctx->in, 0, 56);
- } else {
- /* Pad block to 56 bytes */
- memset(p, 0, count - 8);
- }
- byteReverse(ctx->in, 14);
-
- /* Append length in bits and transform */
- ((uint32_t *) ctx->in)[14] = ctx->bits[0];
- ((uint32_t *) ctx->in)[15] = ctx->bits[1];
-
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- byteReverse((unsigned char *) ctx->buf, 4);
-
- if (digest!=NULL)
- memcpy(digest, ctx->buf, 16);
- memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
-}
-
-
-char *Com_MD5File( const char *fn, int length, const char *prefix, int prefix_len )
-{
- static char final[33] = {""};
- unsigned char digest[16] = {""};
- fileHandle_t f;
- MD5_CTX md5;
- byte buffer[2048];
- int i;
- int filelen = 0;
- int r = 0;
- int total = 0;
-
- Q_strncpyz( final, "", sizeof( final ) );
-
- filelen = FS_SV_FOpenFileRead( fn, &f );
-
- if( !f ) {
- return final;
- }
- if( filelen < 1 ) {
- FS_FCloseFile( f );
- return final;
- }
- if(filelen < length || !length) {
- length = filelen;
- }
-
- MD5Init(&md5);
-
- if( prefix_len && *prefix )
- MD5Update(&md5 , (unsigned char *)prefix, prefix_len);
-
- for(;;) {
- r = FS_Read2(buffer, sizeof(buffer), f);
- if(r < 1)
- break;
- if(r + total > length)
- r = length - total;
- total += r;
- MD5Update(&md5 , buffer, r);
- if(r < sizeof(buffer) || total >= length)
- break;
- }
- FS_FCloseFile(f);
- MD5Final(&md5, digest);
- final[0] = '\0';
- for(i = 0; i < 16; i++) {
- Q_strcat(final, sizeof(final), va("%02X", digest[i]));
- }
- return final;
-}
diff --git a/engine/code/qcommon/msg.c b/engine/code/qcommon/msg.c
deleted file mode 100644
index 04fb424..0000000
--- a/engine/code/qcommon/msg.c
+++ /dev/null
@@ -1,1786 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "q_shared.h"
-#include "qcommon.h"
-
-static huffman_t msgHuff;
-
-static qboolean msgInit = qfalse;
-
-int pcount[256];
-
-/*
-==============================================================================
-
- MESSAGE IO FUNCTIONS
-
-Handles byte ordering and avoids alignment errors
-==============================================================================
-*/
-
-int oldsize = 0;
-
-void MSG_initHuffman( void );
-
-void MSG_Init( msg_t *buf, byte *data, int length ) {
- if (!msgInit) {
- MSG_initHuffman();
- }
- Com_Memset (buf, 0, sizeof(*buf));
- buf->data = data;
- buf->maxsize = length;
-}
-
-void MSG_InitOOB( msg_t *buf, byte *data, int length ) {
- if (!msgInit) {
- MSG_initHuffman();
- }
- Com_Memset (buf, 0, sizeof(*buf));
- buf->data = data;
- buf->maxsize = length;
- buf->oob = qtrue;
-}
-
-void MSG_Clear( msg_t *buf ) {
- buf->cursize = 0;
- buf->overflowed = qfalse;
- buf->bit = 0; //<- in bits
-}
-
-
-void MSG_Bitstream( msg_t *buf ) {
- buf->oob = qfalse;
-}
-
-void MSG_BeginReading( msg_t *msg ) {
- msg->readcount = 0;
- msg->bit = 0;
- msg->oob = qfalse;
-}
-
-void MSG_BeginReadingOOB( msg_t *msg ) {
- msg->readcount = 0;
- msg->bit = 0;
- msg->oob = qtrue;
-}
-
-void MSG_Copy(msg_t *buf, byte *data, int length, msg_t *src)
-{
- if (length<src->cursize) {
- Com_Error( ERR_DROP, "MSG_Copy: can't copy into a smaller msg_t buffer");
- }
- Com_Memcpy(buf, src, sizeof(msg_t));
- buf->data = data;
- Com_Memcpy(buf->data, src->data, src->cursize);
-}
-
-/*
-=============================================================================
-
-bit functions
-
-=============================================================================
-*/
-
-int overflows;
-
-// negative bit values include signs
-void MSG_WriteBits( msg_t *msg, int value, int bits ) {
- int i;
-// FILE* fp;
-
- oldsize += bits;
-
- // this isn't an exact overflow check, but close enough
- if ( msg->maxsize - msg->cursize < 4 ) {
- msg->overflowed = qtrue;
- return;
- }
-
- if ( bits == 0 || bits < -31 || bits > 32 ) {
- Com_Error( ERR_DROP, "MSG_WriteBits: bad bits %i", bits );
- }
-
- // check for overflows
- if ( bits != 32 ) {
- if ( bits > 0 ) {
- if ( value > ( ( 1 << bits ) - 1 ) || value < 0 ) {
- overflows++;
- }
- } else {
- int r;
-
- r = 1 << (bits-1);
-
- if ( value > r - 1 || value < -r ) {
- overflows++;
- }
- }
- }
- if ( bits < 0 ) {
- bits = -bits;
- }
- if (msg->oob) {
- if (bits==8) {
- msg->data[msg->cursize] = value;
- msg->cursize += 1;
- msg->bit += 8;
- } else if (bits==16) {
- unsigned short *sp = (unsigned short *)&msg->data[msg->cursize];
- *sp = LittleShort(value);
- msg->cursize += 2;
- msg->bit += 16;
- } else if (bits==32) {
- unsigned int *ip = (unsigned int *)&msg->data[msg->cursize];
- *ip = LittleLong(value);
- msg->cursize += 4;
- msg->bit += 32;
- } else {
- Com_Error(ERR_DROP, "can't read %d bits\n", bits);
- }
- } else {
-// fp = fopen("c:\\netchan.bin", "a");
- value &= (0xffffffff>>(32-bits));
- if (bits&7) {
- int nbits;
- nbits = bits&7;
- for(i=0;i<nbits;i++) {
- Huff_putBit((value&1), msg->data, &msg->bit);
- value = (value>>1);
- }
- bits = bits - nbits;
- }
- if (bits) {
- for(i=0;i<bits;i+=8) {
-// fwrite(bp, 1, 1, fp);
- Huff_offsetTransmit (&msgHuff.compressor, (value&0xff), msg->data, &msg->bit);
- value = (value>>8);
- }
- }
- msg->cursize = (msg->bit>>3)+1;
-// fclose(fp);
- }
-}
-
-int MSG_ReadBits( msg_t *msg, int bits ) {
- int value;
- int get;
- qboolean sgn;
- int i, nbits;
-// FILE* fp;
-
- value = 0;
-
- if ( bits < 0 ) {
- bits = -bits;
- sgn = qtrue;
- } else {
- sgn = qfalse;
- }
-
- if (msg->oob) {
- if (bits==8) {
- value = msg->data[msg->readcount];
- msg->readcount += 1;
- msg->bit += 8;
- } else if (bits==16) {
- unsigned short *sp = (unsigned short *)&msg->data[msg->readcount];
- value = LittleShort(*sp);
- msg->readcount += 2;
- msg->bit += 16;
- } else if (bits==32) {
- unsigned int *ip = (unsigned int *)&msg->data[msg->readcount];
- value = LittleLong(*ip);
- msg->readcount += 4;
- msg->bit += 32;
- } else {
- Com_Error(ERR_DROP, "can't read %d bits\n", bits);
- }
- } else {
- nbits = 0;
- if (bits&7) {
- nbits = bits&7;
- for(i=0;i<nbits;i++) {
- value |= (Huff_getBit(msg->data, &msg->bit)<<i);
- }
- bits = bits - nbits;
- }
- if (bits) {
-// fp = fopen("c:\\netchan.bin", "a");
- for(i=0;i<bits;i+=8) {
- Huff_offsetReceive (msgHuff.decompressor.tree, &get, msg->data, &msg->bit);
-// fwrite(&get, 1, 1, fp);
- value |= (get<<(i+nbits));
- }
-// fclose(fp);
- }
- msg->readcount = (msg->bit>>3)+1;
- }
- if ( sgn ) {
- if ( value & ( 1 << ( bits - 1 ) ) ) {
- value |= -1 ^ ( ( 1 << bits ) - 1 );
- }
- }
-
- return value;
-}
-
-
-
-//================================================================================
-
-//
-// writing functions
-//
-
-void MSG_WriteChar( msg_t *sb, int c ) {
-#ifdef PARANOID
- if (c < -128 || c > 127)
- Com_Error (ERR_FATAL, "MSG_WriteChar: range error");
-#endif
-
- MSG_WriteBits( sb, c, 8 );
-}
-
-void MSG_WriteByte( msg_t *sb, int c ) {
-#ifdef PARANOID
- if (c < 0 || c > 255)
- Com_Error (ERR_FATAL, "MSG_WriteByte: range error");
-#endif
-
- MSG_WriteBits( sb, c, 8 );
-}
-
-void MSG_WriteData( msg_t *buf, const void *data, int length ) {
- int i;
- for(i=0;i<length;i++) {
- MSG_WriteByte(buf, ((byte *)data)[i]);
- }
-}
-
-void MSG_WriteShort( msg_t *sb, int c ) {
-#ifdef PARANOID
- if (c < ((short)0x8000) || c > (short)0x7fff)
- Com_Error (ERR_FATAL, "MSG_WriteShort: range error");
-#endif
-
- MSG_WriteBits( sb, c, 16 );
-}
-
-void MSG_WriteLong( msg_t *sb, int c ) {
- MSG_WriteBits( sb, c, 32 );
-}
-
-void MSG_WriteFloat( msg_t *sb, float f ) {
- floatint_t dat;
- dat.f = f;
- MSG_WriteBits( sb, dat.i, 32 );
-}
-
-void MSG_WriteString( msg_t *sb, const char *s ) {
- if ( !s ) {
- MSG_WriteData (sb, "", 1);
- } else {
- int l,i;
- char string[MAX_STRING_CHARS];
-
- l = strlen( s );
- if ( l >= MAX_STRING_CHARS ) {
- Com_Printf( "MSG_WriteString: MAX_STRING_CHARS" );
- MSG_WriteData (sb, "", 1);
- return;
- }
- Q_strncpyz( string, s, sizeof( string ) );
-
- // get rid of 0x80+ and '%' chars, because old clients don't like them
- for ( i = 0 ; i < l ; i++ ) {
- if ( ((byte *)string)[i] > 127 || string[i] == '%' ) {
- string[i] = '.';
- }
- }
-
- MSG_WriteData (sb, string, l+1);
- }
-}
-
-void MSG_WriteBigString( msg_t *sb, const char *s ) {
- if ( !s ) {
- MSG_WriteData (sb, "", 1);
- } else {
- int l,i;
- char string[BIG_INFO_STRING];
-
- l = strlen( s );
- if ( l >= BIG_INFO_STRING ) {
- Com_Printf( "MSG_WriteString: BIG_INFO_STRING" );
- MSG_WriteData (sb, "", 1);
- return;
- }
- Q_strncpyz( string, s, sizeof( string ) );
-
- // get rid of 0x80+ and '%' chars, because old clients don't like them
- for ( i = 0 ; i < l ; i++ ) {
- if ( ((byte *)string)[i] > 127 || string[i] == '%' ) {
- string[i] = '.';
- }
- }
-
- MSG_WriteData (sb, string, l+1);
- }
-}
-
-void MSG_WriteAngle( msg_t *sb, float f ) {
- MSG_WriteByte (sb, (int)(f*256/360) & 255);
-}
-
-void MSG_WriteAngle16( msg_t *sb, float f ) {
- MSG_WriteShort (sb, ANGLE2SHORT(f));
-}
-
-
-//============================================================
-
-//
-// reading functions
-//
-
-// returns -1 if no more characters are available
-int MSG_ReadChar (msg_t *msg ) {
- int c;
-
- c = (signed char)MSG_ReadBits( msg, 8 );
- if ( msg->readcount > msg->cursize ) {
- c = -1;
- }
-
- return c;
-}
-
-int MSG_ReadByte( msg_t *msg ) {
- int c;
-
- c = (unsigned char)MSG_ReadBits( msg, 8 );
- if ( msg->readcount > msg->cursize ) {
- c = -1;
- }
- return c;
-}
-
-int MSG_LookaheadByte( msg_t *msg ) {
- const int bloc = Huff_getBloc();
- const int readcount = msg->readcount;
- const int bit = msg->bit;
- int c = MSG_ReadByte(msg);
- Huff_setBloc(bloc);
- msg->readcount = readcount;
- msg->bit = bit;
- return c;
-}
-
-int MSG_ReadShort( msg_t *msg ) {
- int c;
-
- c = (short)MSG_ReadBits( msg, 16 );
- if ( msg->readcount > msg->cursize ) {
- c = -1;
- }
-
- return c;
-}
-
-int MSG_ReadLong( msg_t *msg ) {
- int c;
-
- c = MSG_ReadBits( msg, 32 );
- if ( msg->readcount > msg->cursize ) {
- c = -1;
- }
-
- return c;
-}
-
-float MSG_ReadFloat( msg_t *msg ) {
- floatint_t dat;
-
- dat.i = MSG_ReadBits( msg, 32 );
- if ( msg->readcount > msg->cursize ) {
- dat.f = -1;
- }
-
- return dat.f;
-}
-
-char *MSG_ReadString( msg_t *msg ) {
- static char string[MAX_STRING_CHARS];
- int l,c;
-
- l = 0;
- do {
- c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds
- if ( c == -1 || c == 0 ) {
- break;
- }
- // translate all fmt spec to avoid crash bugs
- if ( c == '%' ) {
- c = '.';
- }
- // don't allow higher ascii values
- if ( c > 127 ) {
- c = '.';
- }
-
- string[l] = c;
- l++;
- } while (l < sizeof(string)-1);
-
- string[l] = 0;
-
- return string;
-}
-
-char *MSG_ReadBigString( msg_t *msg ) {
- static char string[BIG_INFO_STRING];
- int l,c;
-
- l = 0;
- do {
- c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds
- if ( c == -1 || c == 0 ) {
- break;
- }
- // translate all fmt spec to avoid crash bugs
- if ( c == '%' ) {
- c = '.';
- }
- // don't allow higher ascii values
- if ( c > 127 ) {
- c = '.';
- }
-
- string[l] = c;
- l++;
- } while (l < sizeof(string)-1);
-
- string[l] = 0;
-
- return string;
-}
-
-char *MSG_ReadStringLine( msg_t *msg ) {
- static char string[MAX_STRING_CHARS];
- int l,c;
-
- l = 0;
- do {
- c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds
- if (c == -1 || c == 0 || c == '\n') {
- break;
- }
- // translate all fmt spec to avoid crash bugs
- if ( c == '%' ) {
- c = '.';
- }
- // don't allow higher ascii values
- if ( c > 127 ) {
- c = '.';
- }
-
- string[l] = c;
- l++;
- } while (l < sizeof(string)-1);
-
- string[l] = 0;
-
- return string;
-}
-
-float MSG_ReadAngle16( msg_t *msg ) {
- return SHORT2ANGLE(MSG_ReadShort(msg));
-}
-
-void MSG_ReadData( msg_t *msg, void *data, int len ) {
- int i;
-
- for (i=0 ; i<len ; i++) {
- ((byte *)data)[i] = MSG_ReadByte (msg);
- }
-}
-
-// a string hasher which gives the same hash value even if the
-// string is later modified via the legacy MSG read/write code
-int MSG_HashKey(const char *string, int maxlen) {
- int hash, i;
-
- hash = 0;
- for (i = 0; i < maxlen && string[i] != '\0'; i++) {
- if (string[i] & 0x80 || string[i] == '%')
- hash += '.' * (119 + i);
- else
- hash += string[i] * (119 + i);
- }
- hash = (hash ^ (hash >> 10) ^ (hash >> 20));
- return hash;
-}
-
-/*
-=============================================================================
-
-delta functions
-
-=============================================================================
-*/
-
-extern cvar_t *cl_shownet;
-
-#define LOG(x) if( cl_shownet->integer == 4 ) { Com_Printf("%s ", x ); };
-
-void MSG_WriteDelta( msg_t *msg, int oldV, int newV, int bits ) {
- if ( oldV == newV ) {
- MSG_WriteBits( msg, 0, 1 );
- return;
- }
- MSG_WriteBits( msg, 1, 1 );
- MSG_WriteBits( msg, newV, bits );
-}
-
-int MSG_ReadDelta( msg_t *msg, int oldV, int bits ) {
- if ( MSG_ReadBits( msg, 1 ) ) {
- return MSG_ReadBits( msg, bits );
- }
- return oldV;
-}
-
-void MSG_WriteDeltaFloat( msg_t *msg, float oldV, float newV ) {
- floatint_t fi;
- if ( oldV == newV ) {
- MSG_WriteBits( msg, 0, 1 );
- return;
- }
- fi.f = newV;
- MSG_WriteBits( msg, 1, 1 );
- MSG_WriteBits( msg, fi.i, 32 );
-}
-
-float MSG_ReadDeltaFloat( msg_t *msg, float oldV ) {
- if ( MSG_ReadBits( msg, 1 ) ) {
- floatint_t fi;
-
- fi.i = MSG_ReadBits( msg, 32 );
- return fi.f;
- }
- return oldV;
-}
-
-/*
-=============================================================================
-
-delta functions with keys
-
-=============================================================================
-*/
-
-int kbitmask[32] = {
- 0x00000001, 0x00000003, 0x00000007, 0x0000000F,
- 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
- 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
- 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
- 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
- 0x001FFFFf, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
- 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
- 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
-};
-
-void MSG_WriteDeltaKey( msg_t *msg, int key, int oldV, int newV, int bits ) {
- if ( oldV == newV ) {
- MSG_WriteBits( msg, 0, 1 );
- return;
- }
- MSG_WriteBits( msg, 1, 1 );
- MSG_WriteBits( msg, newV ^ key, bits );
-}
-
-int MSG_ReadDeltaKey( msg_t *msg, int key, int oldV, int bits ) {
- if ( MSG_ReadBits( msg, 1 ) ) {
- return MSG_ReadBits( msg, bits ) ^ (key & kbitmask[bits]);
- }
- return oldV;
-}
-
-void MSG_WriteDeltaKeyFloat( msg_t *msg, int key, float oldV, float newV ) {
- floatint_t fi;
- if ( oldV == newV ) {
- MSG_WriteBits( msg, 0, 1 );
- return;
- }
- fi.f = newV;
- MSG_WriteBits( msg, 1, 1 );
- MSG_WriteBits( msg, fi.i ^ key, 32 );
-}
-
-float MSG_ReadDeltaKeyFloat( msg_t *msg, int key, float oldV ) {
- if ( MSG_ReadBits( msg, 1 ) ) {
- floatint_t fi;
-
- fi.i = MSG_ReadBits( msg, 32 ) ^ key;
- return fi.f;
- }
- return oldV;
-}
-
-
-/*
-============================================================================
-
-usercmd_t communication
-
-============================================================================
-*/
-
-// ms is allways sent, the others are optional
-#define CM_ANGLE1 (1<<0)
-#define CM_ANGLE2 (1<<1)
-#define CM_ANGLE3 (1<<2)
-#define CM_FORWARD (1<<3)
-#define CM_SIDE (1<<4)
-#define CM_UP (1<<5)
-#define CM_BUTTONS (1<<6)
-#define CM_WEAPON (1<<7)
-
-/*
-=====================
-MSG_WriteDeltaUsercmd
-=====================
-*/
-void MSG_WriteDeltaUsercmd( msg_t *msg, usercmd_t *from, usercmd_t *to ) {
- if ( to->serverTime - from->serverTime < 256 ) {
- MSG_WriteBits( msg, 1, 1 );
- MSG_WriteBits( msg, to->serverTime - from->serverTime, 8 );
- } else {
- MSG_WriteBits( msg, 0, 1 );
- MSG_WriteBits( msg, to->serverTime, 32 );
- }
- MSG_WriteDelta( msg, from->angles[0], to->angles[0], 16 );
- MSG_WriteDelta( msg, from->angles[1], to->angles[1], 16 );
- MSG_WriteDelta( msg, from->angles[2], to->angles[2], 16 );
- MSG_WriteDelta( msg, from->forwardmove, to->forwardmove, 8 );
- MSG_WriteDelta( msg, from->rightmove, to->rightmove, 8 );
- MSG_WriteDelta( msg, from->upmove, to->upmove, 8 );
- MSG_WriteDelta( msg, from->buttons, to->buttons, 16 );
- MSG_WriteDelta( msg, from->weapon, to->weapon, 8 );
-}
-
-
-/*
-=====================
-MSG_ReadDeltaUsercmd
-=====================
-*/
-void MSG_ReadDeltaUsercmd( msg_t *msg, usercmd_t *from, usercmd_t *to ) {
- if ( MSG_ReadBits( msg, 1 ) ) {
- to->serverTime = from->serverTime + MSG_ReadBits( msg, 8 );
- } else {
- to->serverTime = MSG_ReadBits( msg, 32 );
- }
- to->angles[0] = MSG_ReadDelta( msg, from->angles[0], 16);
- to->angles[1] = MSG_ReadDelta( msg, from->angles[1], 16);
- to->angles[2] = MSG_ReadDelta( msg, from->angles[2], 16);
- to->forwardmove = MSG_ReadDelta( msg, from->forwardmove, 8);
- to->rightmove = MSG_ReadDelta( msg, from->rightmove, 8);
- to->upmove = MSG_ReadDelta( msg, from->upmove, 8);
- to->buttons = MSG_ReadDelta( msg, from->buttons, 16);
- to->weapon = MSG_ReadDelta( msg, from->weapon, 8);
-}
-
-/*
-=====================
-MSG_WriteDeltaUsercmd
-=====================
-*/
-void MSG_WriteDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to ) {
- if ( to->serverTime - from->serverTime < 256 ) {
- MSG_WriteBits( msg, 1, 1 );
- MSG_WriteBits( msg, to->serverTime - from->serverTime, 8 );
- } else {
- MSG_WriteBits( msg, 0, 1 );
- MSG_WriteBits( msg, to->serverTime, 32 );
- }
- if (from->angles[0] == to->angles[0] &&
- from->angles[1] == to->angles[1] &&
- from->angles[2] == to->angles[2] &&
- from->forwardmove == to->forwardmove &&
- from->rightmove == to->rightmove &&
- from->upmove == to->upmove &&
- from->buttons == to->buttons &&
- from->weapon == to->weapon) {
- MSG_WriteBits( msg, 0, 1 ); // no change
- oldsize += 7;
- return;
- }
- key ^= to->serverTime;
- MSG_WriteBits( msg, 1, 1 );
- MSG_WriteDeltaKey( msg, key, from->angles[0], to->angles[0], 16 );
- MSG_WriteDeltaKey( msg, key, from->angles[1], to->angles[1], 16 );
- MSG_WriteDeltaKey( msg, key, from->angles[2], to->angles[2], 16 );
- MSG_WriteDeltaKey( msg, key, from->forwardmove, to->forwardmove, 8 );
- MSG_WriteDeltaKey( msg, key, from->rightmove, to->rightmove, 8 );
- MSG_WriteDeltaKey( msg, key, from->upmove, to->upmove, 8 );
- MSG_WriteDeltaKey( msg, key, from->buttons, to->buttons, 16 );
- MSG_WriteDeltaKey( msg, key, from->weapon, to->weapon, 8 );
-}
-
-
-/*
-=====================
-MSG_ReadDeltaUsercmd
-=====================
-*/
-void MSG_ReadDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to ) {
- if ( MSG_ReadBits( msg, 1 ) ) {
- to->serverTime = from->serverTime + MSG_ReadBits( msg, 8 );
- } else {
- to->serverTime = MSG_ReadBits( msg, 32 );
- }
- if ( MSG_ReadBits( msg, 1 ) ) {
- key ^= to->serverTime;
- to->angles[0] = MSG_ReadDeltaKey( msg, key, from->angles[0], 16);
- to->angles[1] = MSG_ReadDeltaKey( msg, key, from->angles[1], 16);
- to->angles[2] = MSG_ReadDeltaKey( msg, key, from->angles[2], 16);
- to->forwardmove = MSG_ReadDeltaKey( msg, key, from->forwardmove, 8);
- to->rightmove = MSG_ReadDeltaKey( msg, key, from->rightmove, 8);
- to->upmove = MSG_ReadDeltaKey( msg, key, from->upmove, 8);
- to->buttons = MSG_ReadDeltaKey( msg, key, from->buttons, 16);
- to->weapon = MSG_ReadDeltaKey( msg, key, from->weapon, 8);
- } else {
- to->angles[0] = from->angles[0];
- to->angles[1] = from->angles[1];
- to->angles[2] = from->angles[2];
- to->forwardmove = from->forwardmove;
- to->rightmove = from->rightmove;
- to->upmove = from->upmove;
- to->buttons = from->buttons;
- to->weapon = from->weapon;
- }
-}
-
-/*
-=============================================================================
-
-entityState_t communication
-
-=============================================================================
-*/
-
-/*
-=================
-MSG_ReportChangeVectors_f
-
-Prints out a table from the current statistics for copying to code
-=================
-*/
-void MSG_ReportChangeVectors_f( void ) {
- int i;
- for(i=0;i<256;i++) {
- if (pcount[i]) {
- Com_Printf("%d used %d\n", i, pcount[i]);
- }
- }
-}
-
-typedef struct {
- char *name;
- int offset;
- int bits; // 0 = float
-} netField_t;
-
-// using the stringizing operator to save typing...
-#define NETF(x) #x,(size_t)&((entityState_t*)0)->x
-
-netField_t entityStateFields[] =
-{
-{ NETF(pos.trTime), 32 },
-{ NETF(pos.trBase[0]), 0 },
-{ NETF(pos.trBase[1]), 0 },
-{ NETF(pos.trDelta[0]), 0 },
-{ NETF(pos.trDelta[1]), 0 },
-{ NETF(pos.trBase[2]), 0 },
-{ NETF(apos.trBase[1]), 0 },
-{ NETF(pos.trDelta[2]), 0 },
-{ NETF(apos.trBase[0]), 0 },
-{ NETF(event), 10 },
-{ NETF(angles2[1]), 0 },
-{ NETF(eType), 8 },
-{ NETF(torsoAnim), 8 },
-{ NETF(eventParm), 8 },
-{ NETF(legsAnim), 8 },
-{ NETF(groundEntityNum), GENTITYNUM_BITS },
-{ NETF(pos.trType), 8 },
-{ NETF(eFlags), 19 },
-{ NETF(otherEntityNum), GENTITYNUM_BITS },
-{ NETF(weapon), 8 },
-{ NETF(clientNum), 8 },
-{ NETF(angles[1]), 0 },
-{ NETF(pos.trDuration), 32 },
-{ NETF(apos.trType), 8 },
-{ NETF(origin[0]), 0 },
-{ NETF(origin[1]), 0 },
-{ NETF(origin[2]), 0 },
-{ NETF(solid), 24 },
-{ NETF(powerups), MAX_POWERUPS },
-{ NETF(modelindex), 8 },
-{ NETF(otherEntityNum2), GENTITYNUM_BITS },
-{ NETF(loopSound), 8 },
-{ NETF(generic1), 8 },
-{ NETF(origin2[2]), 0 },
-{ NETF(origin2[0]), 0 },
-{ NETF(origin2[1]), 0 },
-{ NETF(modelindex2), 8 },
-{ NETF(angles[0]), 0 },
-{ NETF(time), 32 },
-{ NETF(apos.trTime), 32 },
-{ NETF(apos.trDuration), 32 },
-{ NETF(apos.trBase[2]), 0 },
-{ NETF(apos.trDelta[0]), 0 },
-{ NETF(apos.trDelta[1]), 0 },
-{ NETF(apos.trDelta[2]), 0 },
-{ NETF(time2), 32 },
-{ NETF(angles[2]), 0 },
-{ NETF(angles2[0]), 0 },
-{ NETF(angles2[2]), 0 },
-{ NETF(constantLight), 32 },
-{ NETF(frame), 16 }
-};
-
-
-// if (int)f == f and (int)f + ( 1<<(FLOAT_INT_BITS-1) ) < ( 1 << FLOAT_INT_BITS )
-// the float will be sent with FLOAT_INT_BITS, otherwise all 32 bits will be sent
-#define FLOAT_INT_BITS 13
-#define FLOAT_INT_BIAS (1<<(FLOAT_INT_BITS-1))
-
-/*
-==================
-MSG_WriteDeltaEntity
-
-Writes part of a packetentities message, including the entity number.
-Can delta from either a baseline or a previous packet_entity
-If to is NULL, a remove entity update will be sent
-If force is not set, then nothing at all will be generated if the entity is
-identical, under the assumption that the in-order delta code will catch it.
-==================
-*/
-void MSG_WriteDeltaEntity( msg_t *msg, struct entityState_s *from, struct entityState_s *to,
- qboolean force ) {
- int i, lc;
- int numFields;
- netField_t *field;
- int trunc;
- float fullFloat;
- int *fromF, *toF;
-
- numFields = sizeof(entityStateFields)/sizeof(entityStateFields[0]);
-
- // all fields should be 32 bits to avoid any compiler packing issues
- // the "number" field is not part of the field list
- // if this assert fails, someone added a field to the entityState_t
- // struct without updating the message fields
- assert( numFields + 1 == sizeof( *from )/4 );
-
- // a NULL to is a delta remove message
- if ( to == NULL ) {
- if ( from == NULL ) {
- return;
- }
- MSG_WriteBits( msg, from->number, GENTITYNUM_BITS );
- MSG_WriteBits( msg, 1, 1 );
- return;
- }
-
- if ( to->number < 0 || to->number >= MAX_GENTITIES ) {
- Com_Error (ERR_FATAL, "MSG_WriteDeltaEntity: Bad entity number: %i", to->number );
- }
-
- lc = 0;
- // build the change vector as bytes so it is endien independent
- for ( i = 0, field = entityStateFields ; i < numFields ; i++, field++ ) {
- fromF = (int *)( (byte *)from + field->offset );
- toF = (int *)( (byte *)to + field->offset );
- if ( *fromF != *toF ) {
- lc = i+1;
- }
- }
-
- if ( lc == 0 ) {
- // nothing at all changed
- if ( !force ) {
- return; // nothing at all
- }
- // write two bits for no change
- MSG_WriteBits( msg, to->number, GENTITYNUM_BITS );
- MSG_WriteBits( msg, 0, 1 ); // not removed
- MSG_WriteBits( msg, 0, 1 ); // no delta
- return;
- }
-
- MSG_WriteBits( msg, to->number, GENTITYNUM_BITS );
- MSG_WriteBits( msg, 0, 1 ); // not removed
- MSG_WriteBits( msg, 1, 1 ); // we have a delta
-
- MSG_WriteByte( msg, lc ); // # of changes
-
- oldsize += numFields;
-
- for ( i = 0, field = entityStateFields ; i < lc ; i++, field++ ) {
- fromF = (int *)( (byte *)from + field->offset );
- toF = (int *)( (byte *)to + field->offset );
-
- if ( *fromF == *toF ) {
- MSG_WriteBits( msg, 0, 1 ); // no change
- continue;
- }
-
- MSG_WriteBits( msg, 1, 1 ); // changed
-
- if ( field->bits == 0 ) {
- // float
- fullFloat = *(float *)toF;
- trunc = (int)fullFloat;
-
- if (fullFloat == 0.0f) {
- MSG_WriteBits( msg, 0, 1 );
- oldsize += FLOAT_INT_BITS;
- } else {
- MSG_WriteBits( msg, 1, 1 );
- if ( trunc == fullFloat && trunc + FLOAT_INT_BIAS >= 0 &&
- trunc + FLOAT_INT_BIAS < ( 1 << FLOAT_INT_BITS ) ) {
- // send as small integer
- MSG_WriteBits( msg, 0, 1 );
- MSG_WriteBits( msg, trunc + FLOAT_INT_BIAS, FLOAT_INT_BITS );
- } else {
- // send as full floating point value
- MSG_WriteBits( msg, 1, 1 );
- MSG_WriteBits( msg, *toF, 32 );
- }
- }
- } else {
- if (*toF == 0) {
- MSG_WriteBits( msg, 0, 1 );
- } else {
- MSG_WriteBits( msg, 1, 1 );
- // integer
- MSG_WriteBits( msg, *toF, field->bits );
- }
- }
- }
-}
-
-/*
-==================
-MSG_ReadDeltaEntity
-
-The entity number has already been read from the message, which
-is how the from state is identified.
-
-If the delta removes the entity, entityState_t->number will be set to MAX_GENTITIES-1
-
-Can go from either a baseline or a previous packet_entity
-==================
-*/
-void MSG_ReadDeltaEntity( msg_t *msg, entityState_t *from, entityState_t *to,
- int number) {
- int i, lc;
- int numFields;
- netField_t *field;
- int *fromF, *toF;
- int print;
- int trunc;
- int startBit, endBit;
-
- if ( number < 0 || number >= MAX_GENTITIES) {
- Com_Error( ERR_DROP, "Bad delta entity number: %i", number );
- }
-
- if ( msg->bit == 0 ) {
- startBit = msg->readcount * 8 - GENTITYNUM_BITS;
- } else {
- startBit = ( msg->readcount - 1 ) * 8 + msg->bit - GENTITYNUM_BITS;
- }
-
- // check for a remove
- if ( MSG_ReadBits( msg, 1 ) == 1 ) {
- Com_Memset( to, 0, sizeof( *to ) );
- to->number = MAX_GENTITIES - 1;
- if ( cl_shownet->integer >= 2 || cl_shownet->integer == -1 ) {
- Com_Printf( "%3i: #%-3i remove\n", msg->readcount, number );
- }
- return;
- }
-
- // check for no delta
- if ( MSG_ReadBits( msg, 1 ) == 0 ) {
- *to = *from;
- to->number = number;
- return;
- }
-
- numFields = sizeof(entityStateFields)/sizeof(entityStateFields[0]);
- lc = MSG_ReadByte(msg);
-
- // shownet 2/3 will interleave with other printed info, -1 will
- // just print the delta records`
- if ( cl_shownet->integer >= 2 || cl_shownet->integer == -1 ) {
- print = 1;
- Com_Printf( "%3i: #%-3i ", msg->readcount, to->number );
- } else {
- print = 0;
- }
-
- to->number = number;
-
- for ( i = 0, field = entityStateFields ; i < lc ; i++, field++ ) {
- fromF = (int *)( (byte *)from + field->offset );
- toF = (int *)( (byte *)to + field->offset );
-
- if ( ! MSG_ReadBits( msg, 1 ) ) {
- // no change
- *toF = *fromF;
- } else {
- if ( field->bits == 0 ) {
- // float
- if ( MSG_ReadBits( msg, 1 ) == 0 ) {
- *(float *)toF = 0.0f;
- } else {
- if ( MSG_ReadBits( msg, 1 ) == 0 ) {
- // integral float
- trunc = MSG_ReadBits( msg, FLOAT_INT_BITS );
- // bias to allow equal parts positive and negative
- trunc -= FLOAT_INT_BIAS;
- *(float *)toF = trunc;
- if ( print ) {
- Com_Printf( "%s:%i ", field->name, trunc );
- }
- } else {
- // full floating point value
- *toF = MSG_ReadBits( msg, 32 );
- if ( print ) {
- Com_Printf( "%s:%f ", field->name, *(float *)toF );
- }
- }
- }
- } else {
- if ( MSG_ReadBits( msg, 1 ) == 0 ) {
- *toF = 0;
- } else {
- // integer
- *toF = MSG_ReadBits( msg, field->bits );
- if ( print ) {
- Com_Printf( "%s:%i ", field->name, *toF );
- }
- }
- }
-// pcount[i]++;
- }
- }
- for ( i = lc, field = &entityStateFields[lc] ; i < numFields ; i++, field++ ) {
- fromF = (int *)( (byte *)from + field->offset );
- toF = (int *)( (byte *)to + field->offset );
- // no change
- *toF = *fromF;
- }
-
- if ( print ) {
- if ( msg->bit == 0 ) {
- endBit = msg->readcount * 8 - GENTITYNUM_BITS;
- } else {
- endBit = ( msg->readcount - 1 ) * 8 + msg->bit - GENTITYNUM_BITS;
- }
- Com_Printf( " (%i bits)\n", endBit - startBit );
- }
-}
-
-
-/*
-============================================================================
-
-plyer_state_t communication
-
-============================================================================
-*/
-
-// using the stringizing operator to save typing...
-#define PSF(x) #x,(size_t)&((playerState_t*)0)->x
-
-netField_t playerStateFields[] =
-{
-{ PSF(commandTime), 32 },
-{ PSF(origin[0]), 0 },
-{ PSF(origin[1]), 0 },
-{ PSF(bobCycle), 8 },
-{ PSF(velocity[0]), 0 },
-{ PSF(velocity[1]), 0 },
-{ PSF(viewangles[1]), 0 },
-{ PSF(viewangles[0]), 0 },
-{ PSF(weaponTime), -16 },
-{ PSF(origin[2]), 0 },
-{ PSF(velocity[2]), 0 },
-{ PSF(legsTimer), 8 },
-{ PSF(pm_time), -16 },
-{ PSF(eventSequence), 16 },
-{ PSF(torsoAnim), 8 },
-{ PSF(movementDir), 4 },
-{ PSF(events[0]), 8 },
-{ PSF(legsAnim), 8 },
-{ PSF(events[1]), 8 },
-{ PSF(pm_flags), 16 },
-{ PSF(groundEntityNum), GENTITYNUM_BITS },
-{ PSF(weaponstate), 4 },
-{ PSF(eFlags), 16 },
-{ PSF(externalEvent), 10 },
-{ PSF(gravity), 16 },
-{ PSF(speed), 16 },
-{ PSF(delta_angles[1]), 16 },
-{ PSF(externalEventParm), 8 },
-{ PSF(viewheight), -8 },
-{ PSF(damageEvent), 8 },
-{ PSF(damageYaw), 8 },
-{ PSF(damagePitch), 8 },
-{ PSF(damageCount), 8 },
-{ PSF(generic1), 8 },
-{ PSF(pm_type), 8 },
-{ PSF(delta_angles[0]), 16 },
-{ PSF(delta_angles[2]), 16 },
-{ PSF(torsoTimer), 12 },
-{ PSF(eventParms[0]), 8 },
-{ PSF(eventParms[1]), 8 },
-{ PSF(clientNum), 8 },
-{ PSF(weapon), 5 },
-{ PSF(viewangles[2]), 0 },
-{ PSF(grapplePoint[0]), 0 },
-{ PSF(grapplePoint[1]), 0 },
-{ PSF(grapplePoint[2]), 0 },
-{ PSF(jumppad_ent), 10 },
-{ PSF(loopSound), 16 }
-};
-
-/*
-=============
-MSG_WriteDeltaPlayerstate
-
-=============
-*/
-void MSG_WriteDeltaPlayerstate( msg_t *msg, struct playerState_s *from, struct playerState_s *to ) {
- int i;
- playerState_t dummy;
- int statsbits;
- int persistantbits;
- int ammobits;
- int powerupbits;
- int numFields;
- int c;
- netField_t *field;
- int *fromF, *toF;
- float fullFloat;
- int trunc, lc;
-
- if (!from) {
- from = &dummy;
- Com_Memset (&dummy, 0, sizeof(dummy));
- }
-
- c = msg->cursize;
-
- numFields = sizeof( playerStateFields ) / sizeof( playerStateFields[0] );
-
- lc = 0;
- for ( i = 0, field = playerStateFields ; i < numFields ; i++, field++ ) {
- fromF = (int *)( (byte *)from + field->offset );
- toF = (int *)( (byte *)to + field->offset );
- if ( *fromF != *toF ) {
- lc = i+1;
- }
- }
-
- MSG_WriteByte( msg, lc ); // # of changes
-
- oldsize += numFields - lc;
-
- for ( i = 0, field = playerStateFields ; i < lc ; i++, field++ ) {
- fromF = (int *)( (byte *)from + field->offset );
- toF = (int *)( (byte *)to + field->offset );
-
- if ( *fromF == *toF ) {
- MSG_WriteBits( msg, 0, 1 ); // no change
- continue;
- }
-
- MSG_WriteBits( msg, 1, 1 ); // changed
-// pcount[i]++;
-
- if ( field->bits == 0 ) {
- // float
- fullFloat = *(float *)toF;
- trunc = (int)fullFloat;
-
- if ( trunc == fullFloat && trunc + FLOAT_INT_BIAS >= 0 &&
- trunc + FLOAT_INT_BIAS < ( 1 << FLOAT_INT_BITS ) ) {
- // send as small integer
- MSG_WriteBits( msg, 0, 1 );
- MSG_WriteBits( msg, trunc + FLOAT_INT_BIAS, FLOAT_INT_BITS );
- } else {
- // send as full floating point value
- MSG_WriteBits( msg, 1, 1 );
- MSG_WriteBits( msg, *toF, 32 );
- }
- } else {
- // integer
- MSG_WriteBits( msg, *toF, field->bits );
- }
- }
- c = msg->cursize - c;
-
-
- //
- // send the arrays
- //
- statsbits = 0;
- for (i=0 ; i<MAX_STATS ; i++) {
- if (to->stats[i] != from->stats[i]) {
- statsbits |= 1<<i;
- }
- }
- persistantbits = 0;
- for (i=0 ; i<MAX_PERSISTANT ; i++) {
- if (to->persistant[i] != from->persistant[i]) {
- persistantbits |= 1<<i;
- }
- }
- ammobits = 0;
- for (i=0 ; i<MAX_WEAPONS ; i++) {
- if (to->ammo[i] != from->ammo[i]) {
- ammobits |= 1<<i;
- }
- }
- powerupbits = 0;
- for (i=0 ; i<MAX_POWERUPS ; i++) {
- if (to->powerups[i] != from->powerups[i]) {
- powerupbits |= 1<<i;
- }
- }
-
- if (!statsbits && !persistantbits && !ammobits && !powerupbits) {
- MSG_WriteBits( msg, 0, 1 ); // no change
- oldsize += 4;
- return;
- }
- MSG_WriteBits( msg, 1, 1 ); // changed
-
- if ( statsbits ) {
- MSG_WriteBits( msg, 1, 1 ); // changed
- MSG_WriteBits( msg, statsbits, MAX_STATS );
- for (i=0 ; i<MAX_STATS ; i++)
- if (statsbits & (1<<i) )
- MSG_WriteShort (msg, to->stats[i]);
- } else {
- MSG_WriteBits( msg, 0, 1 ); // no change
- }
-
-
- if ( persistantbits ) {
- MSG_WriteBits( msg, 1, 1 ); // changed
- MSG_WriteBits( msg, persistantbits, MAX_PERSISTANT );
- for (i=0 ; i<MAX_PERSISTANT ; i++)
- if (persistantbits & (1<<i) )
- MSG_WriteShort (msg, to->persistant[i]);
- } else {
- MSG_WriteBits( msg, 0, 1 ); // no change
- }
-
-
- if ( ammobits ) {
- MSG_WriteBits( msg, 1, 1 ); // changed
- MSG_WriteBits( msg, ammobits, MAX_WEAPONS );
- for (i=0 ; i<MAX_WEAPONS ; i++)
- if (ammobits & (1<<i) )
- MSG_WriteShort (msg, to->ammo[i]);
- } else {
- MSG_WriteBits( msg, 0, 1 ); // no change
- }
-
-
- if ( powerupbits ) {
- MSG_WriteBits( msg, 1, 1 ); // changed
- MSG_WriteBits( msg, powerupbits, MAX_POWERUPS );
- for (i=0 ; i<MAX_POWERUPS ; i++)
- if (powerupbits & (1<<i) )
- MSG_WriteLong( msg, to->powerups[i] );
- } else {
- MSG_WriteBits( msg, 0, 1 ); // no change
- }
-}
-
-
-/*
-===================
-MSG_ReadDeltaPlayerstate
-===================
-*/
-void MSG_ReadDeltaPlayerstate (msg_t *msg, playerState_t *from, playerState_t *to ) {
- int i, lc;
- int bits;
- netField_t *field;
- int numFields;
- int startBit, endBit;
- int print;
- int *fromF, *toF;
- int trunc;
- playerState_t dummy;
-
- if ( !from ) {
- from = &dummy;
- Com_Memset( &dummy, 0, sizeof( dummy ) );
- }
- *to = *from;
-
- if ( msg->bit == 0 ) {
- startBit = msg->readcount * 8 - GENTITYNUM_BITS;
- } else {
- startBit = ( msg->readcount - 1 ) * 8 + msg->bit - GENTITYNUM_BITS;
- }
-
- // shownet 2/3 will interleave with other printed info, -2 will
- // just print the delta records
- if ( cl_shownet->integer >= 2 || cl_shownet->integer == -2 ) {
- print = 1;
- Com_Printf( "%3i: playerstate ", msg->readcount );
- } else {
- print = 0;
- }
-
- numFields = sizeof( playerStateFields ) / sizeof( playerStateFields[0] );
- lc = MSG_ReadByte(msg);
-
- for ( i = 0, field = playerStateFields ; i < lc ; i++, field++ ) {
- fromF = (int *)( (byte *)from + field->offset );
- toF = (int *)( (byte *)to + field->offset );
-
- if ( ! MSG_ReadBits( msg, 1 ) ) {
- // no change
- *toF = *fromF;
- } else {
- if ( field->bits == 0 ) {
- // float
- if ( MSG_ReadBits( msg, 1 ) == 0 ) {
- // integral float
- trunc = MSG_ReadBits( msg, FLOAT_INT_BITS );
- // bias to allow equal parts positive and negative
- trunc -= FLOAT_INT_BIAS;
- *(float *)toF = trunc;
- if ( print ) {
- Com_Printf( "%s:%i ", field->name, trunc );
- }
- } else {
- // full floating point value
- *toF = MSG_ReadBits( msg, 32 );
- if ( print ) {
- Com_Printf( "%s:%f ", field->name, *(float *)toF );
- }
- }
- } else {
- // integer
- *toF = MSG_ReadBits( msg, field->bits );
- if ( print ) {
- Com_Printf( "%s:%i ", field->name, *toF );
- }
- }
- }
- }
- for ( i=lc,field = &playerStateFields[lc];i<numFields; i++, field++) {
- fromF = (int *)( (byte *)from + field->offset );
- toF = (int *)( (byte *)to + field->offset );
- // no change
- *toF = *fromF;
- }
-
-
- // read the arrays
- if (MSG_ReadBits( msg, 1 ) ) {
- // parse stats
- if ( MSG_ReadBits( msg, 1 ) ) {
- LOG("PS_STATS");
- bits = MSG_ReadBits (msg, MAX_STATS);
- for (i=0 ; i<MAX_STATS ; i++) {
- if (bits & (1<<i) ) {
- to->stats[i] = MSG_ReadShort(msg);
- }
- }
- }
-
- // parse persistant stats
- if ( MSG_ReadBits( msg, 1 ) ) {
- LOG("PS_PERSISTANT");
- bits = MSG_ReadBits (msg, MAX_PERSISTANT);
- for (i=0 ; i<MAX_PERSISTANT ; i++) {
- if (bits & (1<<i) ) {
- to->persistant[i] = MSG_ReadShort(msg);
- }
- }
- }
-
- // parse ammo
- if ( MSG_ReadBits( msg, 1 ) ) {
- LOG("PS_AMMO");
- bits = MSG_ReadBits (msg, MAX_WEAPONS);
- for (i=0 ; i<MAX_WEAPONS ; i++) {
- if (bits & (1<<i) ) {
- to->ammo[i] = MSG_ReadShort(msg);
- }
- }
- }
-
- // parse powerups
- if ( MSG_ReadBits( msg, 1 ) ) {
- LOG("PS_POWERUPS");
- bits = MSG_ReadBits (msg, MAX_POWERUPS);
- for (i=0 ; i<MAX_POWERUPS ; i++) {
- if (bits & (1<<i) ) {
- to->powerups[i] = MSG_ReadLong(msg);
- }
- }
- }
- }
-
- if ( print ) {
- if ( msg->bit == 0 ) {
- endBit = msg->readcount * 8 - GENTITYNUM_BITS;
- } else {
- endBit = ( msg->readcount - 1 ) * 8 + msg->bit - GENTITYNUM_BITS;
- }
- Com_Printf( " (%i bits)\n", endBit - startBit );
- }
-}
-
-int msg_hData[256] = {
-250315, // 0
-41193, // 1
-6292, // 2
-7106, // 3
-3730, // 4
-3750, // 5
-6110, // 6
-23283, // 7
-33317, // 8
-6950, // 9
-7838, // 10
-9714, // 11
-9257, // 12
-17259, // 13
-3949, // 14
-1778, // 15
-8288, // 16
-1604, // 17
-1590, // 18
-1663, // 19
-1100, // 20
-1213, // 21
-1238, // 22
-1134, // 23
-1749, // 24
-1059, // 25
-1246, // 26
-1149, // 27
-1273, // 28
-4486, // 29
-2805, // 30
-3472, // 31
-21819, // 32
-1159, // 33
-1670, // 34
-1066, // 35
-1043, // 36
-1012, // 37
-1053, // 38
-1070, // 39
-1726, // 40
-888, // 41
-1180, // 42
-850, // 43
-960, // 44
-780, // 45
-1752, // 46
-3296, // 47
-10630, // 48
-4514, // 49
-5881, // 50
-2685, // 51
-4650, // 52
-3837, // 53
-2093, // 54
-1867, // 55
-2584, // 56
-1949, // 57
-1972, // 58
-940, // 59
-1134, // 60
-1788, // 61
-1670, // 62
-1206, // 63
-5719, // 64
-6128, // 65
-7222, // 66
-6654, // 67
-3710, // 68
-3795, // 69
-1492, // 70
-1524, // 71
-2215, // 72
-1140, // 73
-1355, // 74
-971, // 75
-2180, // 76
-1248, // 77
-1328, // 78
-1195, // 79
-1770, // 80
-1078, // 81
-1264, // 82
-1266, // 83
-1168, // 84
-965, // 85
-1155, // 86
-1186, // 87
-1347, // 88
-1228, // 89
-1529, // 90
-1600, // 91
-2617, // 92
-2048, // 93
-2546, // 94
-3275, // 95
-2410, // 96
-3585, // 97
-2504, // 98
-2800, // 99
-2675, // 100
-6146, // 101
-3663, // 102
-2840, // 103
-14253, // 104
-3164, // 105
-2221, // 106
-1687, // 107
-3208, // 108
-2739, // 109
-3512, // 110
-4796, // 111
-4091, // 112
-3515, // 113
-5288, // 114
-4016, // 115
-7937, // 116
-6031, // 117
-5360, // 118
-3924, // 119
-4892, // 120
-3743, // 121
-4566, // 122
-4807, // 123
-5852, // 124
-6400, // 125
-6225, // 126
-8291, // 127
-23243, // 128
-7838, // 129
-7073, // 130
-8935, // 131
-5437, // 132
-4483, // 133
-3641, // 134
-5256, // 135
-5312, // 136
-5328, // 137
-5370, // 138
-3492, // 139
-2458, // 140
-1694, // 141
-1821, // 142
-2121, // 143
-1916, // 144
-1149, // 145
-1516, // 146
-1367, // 147
-1236, // 148
-1029, // 149
-1258, // 150
-1104, // 151
-1245, // 152
-1006, // 153
-1149, // 154
-1025, // 155
-1241, // 156
-952, // 157
-1287, // 158
-997, // 159
-1713, // 160
-1009, // 161
-1187, // 162
-879, // 163
-1099, // 164
-929, // 165
-1078, // 166
-951, // 167
-1656, // 168
-930, // 169
-1153, // 170
-1030, // 171
-1262, // 172
-1062, // 173
-1214, // 174
-1060, // 175
-1621, // 176
-930, // 177
-1106, // 178
-912, // 179
-1034, // 180
-892, // 181
-1158, // 182
-990, // 183
-1175, // 184
-850, // 185
-1121, // 186
-903, // 187
-1087, // 188
-920, // 189
-1144, // 190
-1056, // 191
-3462, // 192
-2240, // 193
-4397, // 194
-12136, // 195
-7758, // 196
-1345, // 197
-1307, // 198
-3278, // 199
-1950, // 200
-886, // 201
-1023, // 202
-1112, // 203
-1077, // 204
-1042, // 205
-1061, // 206
-1071, // 207
-1484, // 208
-1001, // 209
-1096, // 210
-915, // 211
-1052, // 212
-995, // 213
-1070, // 214
-876, // 215
-1111, // 216
-851, // 217
-1059, // 218
-805, // 219
-1112, // 220
-923, // 221
-1103, // 222
-817, // 223
-1899, // 224
-1872, // 225
-976, // 226
-841, // 227
-1127, // 228
-956, // 229
-1159, // 230
-950, // 231
-7791, // 232
-954, // 233
-1289, // 234
-933, // 235
-1127, // 236
-3207, // 237
-1020, // 238
-927, // 239
-1355, // 240
-768, // 241
-1040, // 242
-745, // 243
-952, // 244
-805, // 245
-1073, // 246
-740, // 247
-1013, // 248
-805, // 249
-1008, // 250
-796, // 251
-996, // 252
-1057, // 253
-11457, // 254
-13504, // 255
-};
-
-void MSG_initHuffman( void ) {
- int i,j;
-
- msgInit = qtrue;
- Huff_Init(&msgHuff);
- for(i=0;i<256;i++) {
- for (j=0;j<msg_hData[i];j++) {
- Huff_addRef(&msgHuff.compressor, (byte)i); // Do update
- Huff_addRef(&msgHuff.decompressor, (byte)i); // Do update
- }
- }
-}
-
-/*
-void MSG_NUinitHuffman() {
- byte *data;
- int size, i, ch;
- int array[256];
-
- msgInit = qtrue;
-
- Huff_Init(&msgHuff);
- // load it in
- size = FS_ReadFile( "netchan/netchan.bin", (void **)&data );
-
- for(i=0;i<256;i++) {
- array[i] = 0;
- }
- for(i=0;i<size;i++) {
- ch = data[i];
- Huff_addRef(&msgHuff.compressor, ch); // Do update
- Huff_addRef(&msgHuff.decompressor, ch); // Do update
- array[ch]++;
- }
- Com_Printf("msg_hData {\n");
- for(i=0;i<256;i++) {
- if (array[i] == 0) {
- Huff_addRef(&msgHuff.compressor, i); // Do update
- Huff_addRef(&msgHuff.decompressor, i); // Do update
- }
- Com_Printf("%d, // %d\n", array[i], i);
- }
- Com_Printf("};\n");
- FS_FreeFile( data );
- Cbuf_AddText( "condump dump.txt\n" );
-}
-*/
-
-//===========================================================================
diff --git a/engine/code/qcommon/net_chan.c b/engine/code/qcommon/net_chan.c
deleted file mode 100644
index 5b359f9..0000000
--- a/engine/code/qcommon/net_chan.c
+++ /dev/null
@@ -1,740 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "q_shared.h"
-#include "qcommon.h"
-
-/*
-
-packet header
--------------
-4 outgoing sequence. high bit will be set if this is a fragmented message
-[2 qport (only for client to server)]
-[2 fragment start byte]
-[2 fragment length. if < FRAGMENT_SIZE, this is the last fragment]
-
-if the sequence number is -1, the packet should be handled as an out-of-band
-message instead of as part of a netcon.
-
-All fragments will have the same sequence numbers.
-
-The qport field is a workaround for bad address translating routers that
-sometimes remap the client's source port on a packet during gameplay.
-
-If the base part of the net address matches and the qport matches, then the
-channel matches even if the IP port differs. The IP port should be updated
-to the new value before sending out any replies.
-
-*/
-
-
-#define MAX_PACKETLEN 1400 // max size of a network packet
-
-#define FRAGMENT_SIZE (MAX_PACKETLEN - 100)
-#define PACKET_HEADER 10 // two ints and a short
-
-#define FRAGMENT_BIT (1<<31)
-
-cvar_t *showpackets;
-cvar_t *showdrop;
-cvar_t *qport;
-
-static char *netsrcString[2] = {
- "client",
- "server"
-};
-
-/*
-===============
-Netchan_Init
-
-===============
-*/
-void Netchan_Init( int port ) {
- port &= 0xffff;
- showpackets = Cvar_Get ("showpackets", "0", CVAR_TEMP );
- showdrop = Cvar_Get ("showdrop", "0", CVAR_TEMP );
- qport = Cvar_Get ("net_qport", va("%i", port), CVAR_INIT );
-}
-
-/*
-==============
-Netchan_Setup
-
-called to open a channel to a remote system
-==============
-*/
-void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport ) {
- Com_Memset (chan, 0, sizeof(*chan));
-
- chan->sock = sock;
- chan->remoteAddress = adr;
- chan->qport = qport;
- chan->incomingSequence = 0;
- chan->outgoingSequence = 1;
-}
-
-// TTimo: unused, commenting out to make gcc happy
-#if 0
-/*
-==============
-Netchan_ScramblePacket
-
-A probably futile attempt to make proxy hacking somewhat
-more difficult.
-==============
-*/
-#define SCRAMBLE_START 6
-static void Netchan_ScramblePacket( msg_t *buf ) {
- unsigned seed;
- int i, j, c, mask, temp;
- int seq[MAX_PACKETLEN];
-
- seed = ( LittleLong( *(unsigned *)buf->data ) * 3 ) ^ ( buf->cursize * 123 );
- c = buf->cursize;
- if ( c <= SCRAMBLE_START ) {
- return;
- }
- if ( c > MAX_PACKETLEN ) {
- Com_Error( ERR_DROP, "MAX_PACKETLEN" );
- }
-
- // generate a sequence of "random" numbers
- for (i = 0 ; i < c ; i++) {
- seed = (119 * seed + 1);
- seq[i] = seed;
- }
-
- // transpose each character
- for ( mask = 1 ; mask < c-SCRAMBLE_START ; mask = ( mask << 1 ) + 1 ) {
- }
- mask >>= 1;
- for (i = SCRAMBLE_START ; i < c ; i++) {
- j = SCRAMBLE_START + ( seq[i] & mask );
- temp = buf->data[j];
- buf->data[j] = buf->data[i];
- buf->data[i] = temp;
- }
-
- // byte xor the data after the header
- for (i = SCRAMBLE_START ; i < c ; i++) {
- buf->data[i] ^= seq[i];
- }
-}
-
-static void Netchan_UnScramblePacket( msg_t *buf ) {
- unsigned seed;
- int i, j, c, mask, temp;
- int seq[MAX_PACKETLEN];
-
- seed = ( LittleLong( *(unsigned *)buf->data ) * 3 ) ^ ( buf->cursize * 123 );
- c = buf->cursize;
- if ( c <= SCRAMBLE_START ) {
- return;
- }
- if ( c > MAX_PACKETLEN ) {
- Com_Error( ERR_DROP, "MAX_PACKETLEN" );
- }
-
- // generate a sequence of "random" numbers
- for (i = 0 ; i < c ; i++) {
- seed = (119 * seed + 1);
- seq[i] = seed;
- }
-
- // byte xor the data after the header
- for (i = SCRAMBLE_START ; i < c ; i++) {
- buf->data[i] ^= seq[i];
- }
-
- // transpose each character in reverse order
- for ( mask = 1 ; mask < c-SCRAMBLE_START ; mask = ( mask << 1 ) + 1 ) {
- }
- mask >>= 1;
- for (i = c-1 ; i >= SCRAMBLE_START ; i--) {
- j = SCRAMBLE_START + ( seq[i] & mask );
- temp = buf->data[j];
- buf->data[j] = buf->data[i];
- buf->data[i] = temp;
- }
-}
-#endif
-
-/*
-=================
-Netchan_TransmitNextFragment
-
-Send one fragment of the current message
-=================
-*/
-void Netchan_TransmitNextFragment( netchan_t *chan ) {
- msg_t send;
- byte send_buf[MAX_PACKETLEN];
- int fragmentLength;
-
- // write the packet header
- MSG_InitOOB (&send, send_buf, sizeof(send_buf)); // <-- only do the oob here
-
- MSG_WriteLong( &send, chan->outgoingSequence | FRAGMENT_BIT );
-
- // send the qport if we are a client
- if ( chan->sock == NS_CLIENT ) {
- MSG_WriteShort( &send, qport->integer );
- }
-
- // copy the reliable message to the packet first
- fragmentLength = FRAGMENT_SIZE;
- if ( chan->unsentFragmentStart + fragmentLength > chan->unsentLength ) {
- fragmentLength = chan->unsentLength - chan->unsentFragmentStart;
- }
-
- MSG_WriteShort( &send, chan->unsentFragmentStart );
- MSG_WriteShort( &send, fragmentLength );
- MSG_WriteData( &send, chan->unsentBuffer + chan->unsentFragmentStart, fragmentLength );
-
- // send the datagram
- NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );
-
- if ( showpackets->integer ) {
- Com_Printf ("%s send %4i : s=%i fragment=%i,%i\n"
- , netsrcString[ chan->sock ]
- , send.cursize
- , chan->outgoingSequence
- , chan->unsentFragmentStart, fragmentLength);
- }
-
- chan->unsentFragmentStart += fragmentLength;
-
- // this exit condition is a little tricky, because a packet
- // that is exactly the fragment length still needs to send
- // a second packet of zero length so that the other side
- // can tell there aren't more to follow
- if ( chan->unsentFragmentStart == chan->unsentLength && fragmentLength != FRAGMENT_SIZE ) {
- chan->outgoingSequence++;
- chan->unsentFragments = qfalse;
- }
-}
-
-
-/*
-===============
-Netchan_Transmit
-
-Sends a message to a connection, fragmenting if necessary
-A 0 length will still generate a packet.
-================
-*/
-void Netchan_Transmit( netchan_t *chan, int length, const byte *data ) {
- msg_t send;
- byte send_buf[MAX_PACKETLEN];
-
- if ( length > MAX_MSGLEN ) {
- Com_Error( ERR_DROP, "Netchan_Transmit: length = %i", length );
- }
- chan->unsentFragmentStart = 0;
-
- // fragment large reliable messages
- if ( length >= FRAGMENT_SIZE ) {
- chan->unsentFragments = qtrue;
- chan->unsentLength = length;
- Com_Memcpy( chan->unsentBuffer, data, length );
-
- // only send the first fragment now
- Netchan_TransmitNextFragment( chan );
-
- return;
- }
-
- // write the packet header
- MSG_InitOOB (&send, send_buf, sizeof(send_buf));
-
- MSG_WriteLong( &send, chan->outgoingSequence );
- chan->outgoingSequence++;
-
- // send the qport if we are a client
- if ( chan->sock == NS_CLIENT ) {
- MSG_WriteShort( &send, qport->integer );
- }
-
- MSG_WriteData( &send, data, length );
-
- // send the datagram
- NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );
-
- if ( showpackets->integer ) {
- Com_Printf( "%s send %4i : s=%i ack=%i\n"
- , netsrcString[ chan->sock ]
- , send.cursize
- , chan->outgoingSequence - 1
- , chan->incomingSequence );
- }
-}
-
-/*
-=================
-Netchan_Process
-
-Returns qfalse if the message should not be processed due to being
-out of order or a fragment.
-
-Msg must be large enough to hold MAX_MSGLEN, because if this is the
-final fragment of a multi-part message, the entire thing will be
-copied out.
-=================
-*/
-qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) {
- int sequence;
- int qport;
- int fragmentStart, fragmentLength;
- qboolean fragmented;
-
- // XOR unscramble all data in the packet after the header
-// Netchan_UnScramblePacket( msg );
-
- // get sequence numbers
- MSG_BeginReadingOOB( msg );
- sequence = MSG_ReadLong( msg );
-
- // check for fragment information
- if ( sequence & FRAGMENT_BIT ) {
- sequence &= ~FRAGMENT_BIT;
- fragmented = qtrue;
- } else {
- fragmented = qfalse;
- }
-
- // read the qport if we are a server
- if ( chan->sock == NS_SERVER ) {
- qport = MSG_ReadShort( msg );
- }
-
- // read the fragment information
- if ( fragmented ) {
- fragmentStart = MSG_ReadShort( msg );
- fragmentLength = MSG_ReadShort( msg );
- } else {
- fragmentStart = 0; // stop warning message
- fragmentLength = 0;
- }
-
- if ( showpackets->integer ) {
- if ( fragmented ) {
- Com_Printf( "%s recv %4i : s=%i fragment=%i,%i\n"
- , netsrcString[ chan->sock ]
- , msg->cursize
- , sequence
- , fragmentStart, fragmentLength );
- } else {
- Com_Printf( "%s recv %4i : s=%i\n"
- , netsrcString[ chan->sock ]
- , msg->cursize
- , sequence );
- }
- }
-
- //
- // discard out of order or duplicated packets
- //
- if ( sequence <= chan->incomingSequence ) {
- if ( showdrop->integer || showpackets->integer ) {
- Com_Printf( "%s:Out of order packet %i at %i\n"
- , NET_AdrToString( chan->remoteAddress )
- , sequence
- , chan->incomingSequence );
- }
- return qfalse;
- }
-
- //
- // dropped packets don't keep the message from being used
- //
- chan->dropped = sequence - (chan->incomingSequence+1);
- if ( chan->dropped > 0 ) {
- if ( showdrop->integer || showpackets->integer ) {
- Com_Printf( "%s:Dropped %i packets at %i\n"
- , NET_AdrToString( chan->remoteAddress )
- , chan->dropped
- , sequence );
- }
- }
-
-
- //
- // if this is the final framgent of a reliable message,
- // bump incoming_reliable_sequence
- //
- if ( fragmented ) {
- // TTimo
- // make sure we add the fragments in correct order
- // either a packet was dropped, or we received this one too soon
- // we don't reconstruct the fragments. we will wait till this fragment gets to us again
- // (NOTE: we could probably try to rebuild by out of order chunks if needed)
- if ( sequence != chan->fragmentSequence ) {
- chan->fragmentSequence = sequence;
- chan->fragmentLength = 0;
- }
-
- // if we missed a fragment, dump the message
- if ( fragmentStart != chan->fragmentLength ) {
- if ( showdrop->integer || showpackets->integer ) {
- Com_Printf( "%s:Dropped a message fragment\n"
- , NET_AdrToString( chan->remoteAddress ));
- }
- // we can still keep the part that we have so far,
- // so we don't need to clear chan->fragmentLength
- return qfalse;
- }
-
- // copy the fragment to the fragment buffer
- if ( fragmentLength < 0 || msg->readcount + fragmentLength > msg->cursize ||
- chan->fragmentLength + fragmentLength > sizeof( chan->fragmentBuffer ) ) {
- if ( showdrop->integer || showpackets->integer ) {
- Com_Printf ("%s:illegal fragment length\n"
- , NET_AdrToString (chan->remoteAddress ) );
- }
- return qfalse;
- }
-
- Com_Memcpy( chan->fragmentBuffer + chan->fragmentLength,
- msg->data + msg->readcount, fragmentLength );
-
- chan->fragmentLength += fragmentLength;
-
- // if this wasn't the last fragment, don't process anything
- if ( fragmentLength == FRAGMENT_SIZE ) {
- return qfalse;
- }
-
- if ( chan->fragmentLength > msg->maxsize ) {
- Com_Printf( "%s:fragmentLength %i > msg->maxsize\n"
- , NET_AdrToString (chan->remoteAddress ),
- chan->fragmentLength );
- return qfalse;
- }
-
- // copy the full message over the partial fragment
-
- // make sure the sequence number is still there
- *(int *)msg->data = LittleLong( sequence );
-
- Com_Memcpy( msg->data + 4, chan->fragmentBuffer, chan->fragmentLength );
- msg->cursize = chan->fragmentLength + 4;
- chan->fragmentLength = 0;
- msg->readcount = 4; // past the sequence number
- msg->bit = 32; // past the sequence number
-
- // TTimo
- // clients were not acking fragmented messages
- chan->incomingSequence = sequence;
-
- return qtrue;
- }
-
- //
- // the message can now be read from the current message pointer
- //
- chan->incomingSequence = sequence;
-
- return qtrue;
-}
-
-
-//==============================================================================
-
-
-/*
-=============================================================================
-
-LOOPBACK BUFFERS FOR LOCAL PLAYER
-
-=============================================================================
-*/
-
-// there needs to be enough loopback messages to hold a complete
-// gamestate of maximum size
-#define MAX_LOOPBACK 16
-
-typedef struct {
- byte data[MAX_PACKETLEN];
- int datalen;
-} loopmsg_t;
-
-typedef struct {
- loopmsg_t msgs[MAX_LOOPBACK];
- int get, send;
-} loopback_t;
-
-loopback_t loopbacks[2];
-
-
-qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, msg_t *net_message)
-{
- int i;
- loopback_t *loop;
-
- loop = &loopbacks[sock];
-
- if (loop->send - loop->get > MAX_LOOPBACK)
- loop->get = loop->send - MAX_LOOPBACK;
-
- if (loop->get >= loop->send)
- return qfalse;
-
- i = loop->get & (MAX_LOOPBACK-1);
- loop->get++;
-
- Com_Memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
- net_message->cursize = loop->msgs[i].datalen;
- Com_Memset (net_from, 0, sizeof(*net_from));
- net_from->type = NA_LOOPBACK;
- return qtrue;
-
-}
-
-
-void NET_SendLoopPacket (netsrc_t sock, int length, const void *data, netadr_t to)
-{
- int i;
- loopback_t *loop;
-
- loop = &loopbacks[sock^1];
-
- i = loop->send & (MAX_LOOPBACK-1);
- loop->send++;
-
- Com_Memcpy (loop->msgs[i].data, data, length);
- loop->msgs[i].datalen = length;
-}
-
-//=============================================================================
-
-typedef struct packetQueue_s {
- struct packetQueue_s *next;
- int length;
- byte *data;
- netadr_t to;
- int release;
-} packetQueue_t;
-
-packetQueue_t *packetQueue = NULL;
-
-static void NET_QueuePacket( int length, const void *data, netadr_t to,
- int offset )
-{
- packetQueue_t *new, *next = packetQueue;
-
- if(offset > 999)
- offset = 999;
-
- new = S_Malloc(sizeof(packetQueue_t));
- new->data = S_Malloc(length);
- Com_Memcpy(new->data, data, length);
- new->length = length;
- new->to = to;
- new->release = Sys_Milliseconds() + (int)((float)offset / com_timescale->value);
- new->next = NULL;
-
- if(!packetQueue) {
- packetQueue = new;
- return;
- }
- while(next) {
- if(!next->next) {
- next->next = new;
- return;
- }
- next = next->next;
- }
-}
-
-void NET_FlushPacketQueue(void)
-{
- packetQueue_t *last;
- int now;
-
- while(packetQueue) {
- now = Sys_Milliseconds();
- if(packetQueue->release >= now)
- break;
- Sys_SendPacket(packetQueue->length, packetQueue->data,
- packetQueue->to);
- last = packetQueue;
- packetQueue = packetQueue->next;
- Z_Free(last->data);
- Z_Free(last);
- }
-}
-
-void NET_SendPacket( netsrc_t sock, int length, const void *data, netadr_t to ) {
-
- // sequenced packets are shown in netchan, so just show oob
- if ( showpackets->integer && *(int *)data == -1 ) {
- Com_Printf ("send packet %4i\n", length);
- }
-
- if ( to.type == NA_LOOPBACK ) {
- NET_SendLoopPacket (sock, length, data, to);
- return;
- }
- if ( to.type == NA_BOT ) {
- return;
- }
- if ( to.type == NA_BAD ) {
- return;
- }
-
- if ( sock == NS_CLIENT && cl_packetdelay->integer > 0 ) {
- NET_QueuePacket( length, data, to, cl_packetdelay->integer );
- }
- else if ( sock == NS_SERVER && sv_packetdelay->integer > 0 ) {
- NET_QueuePacket( length, data, to, sv_packetdelay->integer );
- }
- else {
- Sys_SendPacket( length, data, to );
- }
-}
-
-/*
-===============
-NET_OutOfBandPrint
-
-Sends a text message in an out-of-band datagram
-================
-*/
-void QDECL NET_OutOfBandPrint( netsrc_t sock, netadr_t adr, const char *format, ... ) {
- va_list argptr;
- char string[MAX_MSGLEN];
-
-
- // set the header
- string[0] = -1;
- string[1] = -1;
- string[2] = -1;
- string[3] = -1;
-
- va_start( argptr, format );
- Q_vsnprintf( string+4, sizeof(string)-4, format, argptr );
- va_end( argptr );
-
- // send the datagram
- NET_SendPacket( sock, strlen( string ), string, adr );
-}
-
-/*
-===============
-NET_OutOfBandPrint
-
-Sends a data message in an out-of-band datagram (only used for "connect")
-================
-*/
-void QDECL NET_OutOfBandData( netsrc_t sock, netadr_t adr, byte *format, int len ) {
- byte string[MAX_MSGLEN*2];
- int i;
- msg_t mbuf;
-
- // set the header
- string[0] = 0xff;
- string[1] = 0xff;
- string[2] = 0xff;
- string[3] = 0xff;
-
- for(i=0;i<len;i++) {
- string[i+4] = format[i];
- }
-
- mbuf.data = string;
- mbuf.cursize = len+4;
- Huff_Compress( &mbuf, 12);
- // send the datagram
- NET_SendPacket( sock, mbuf.cursize, mbuf.data, adr );
-}
-
-/*
-=============
-NET_StringToAdr
-
-Traps "localhost" for loopback, passes everything else to system
-return 0 on address not found, 1 on address found with port, 2 on address found without port.
-=============
-*/
-int NET_StringToAdr( const char *s, netadr_t *a, netadrtype_t family )
-{
- char base[MAX_STRING_CHARS], *search;
- char *port = NULL;
-
- if (!strcmp (s, "localhost")) {
- Com_Memset (a, 0, sizeof(*a));
- a->type = NA_LOOPBACK;
-// as NA_LOOPBACK doesn't require ports report port was given.
- return 1;
- }
-
- Q_strncpyz( base, s, sizeof( base ) );
-
- if(*base == '[' || Q_CountChar(base, ':') > 1)
- {
- // This is an ipv6 address, handle it specially.
- search = strchr(base, ']');
- if(search)
- {
- *search = '\0';
- search++;
-
- if(*search == ':')
- port = search + 1;
- }
-
- if(*base == '[')
- search = base + 1;
- else
- search = base;
- }
- else
- {
- // look for a port number
- port = strchr( base, ':' );
-
- if ( port ) {
- *port = '\0';
- port++;
- }
-
- search = base;
- }
-
- if(!Sys_StringToAdr(search, a, family))
- {
- a->type = NA_BAD;
- return 0;
- }
-
- if(port)
- {
- a->port = BigShort((short) atoi(port));
- return 1;
- }
- else
- {
- a->port = BigShort(PORT_SERVER);
- return 2;
- }
-}
diff --git a/engine/code/qcommon/net_ip.c b/engine/code/qcommon/net_ip.c
deleted file mode 100644
index 7ffb8a8..0000000
--- a/engine/code/qcommon/net_ip.c
+++ /dev/null
@@ -1,1684 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-
-#ifdef _WIN32
-# include <winsock2.h>
-# include <ws2tcpip.h>
-# if WINVER < 0x501
-# ifdef __MINGW32__
- // wspiapi.h isn't available on MinGW, so if it's
- // present it's because the end user has added it
- // and we should look for it in our tree
-# include "wspiapi.h"
-# else
-# include <wspiapi.h>
-# endif
-# else
-# include <ws2spi.h>
-# endif
-
-typedef int socklen_t;
-# ifdef ADDRESS_FAMILY
-# define sa_family_t ADDRESS_FAMILY
-# else
-typedef unsigned short sa_family_t;
-# endif
-
-# define EAGAIN WSAEWOULDBLOCK
-# define EADDRNOTAVAIL WSAEADDRNOTAVAIL
-# define EAFNOSUPPORT WSAEAFNOSUPPORT
-# define ECONNRESET WSAECONNRESET
-# define socketError WSAGetLastError( )
-
-static WSADATA winsockdata;
-static qboolean winsockInitialized = qfalse;
-
-#else
-
-# if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
- // needed for socklen_t on OSX 10.2
-# define _BSD_SOCKLEN_T_
-# endif
-
-# include <arpa/inet.h>
-# include <errno.h>
-# include <netdb.h>
-# include <netinet/in.h>
-# include <sys/socket.h>
-# include <net/if.h>
-# include <sys/ioctl.h>
-# include <sys/types.h>
-# include <sys/time.h>
-# include <unistd.h>
-# if !defined(__sun) && !defined(__sgi)
-# include <ifaddrs.h>
-# endif
-
-# ifdef __sun
-# include <sys/filio.h>
-# endif
-
-typedef int SOCKET;
-# define INVALID_SOCKET -1
-# define SOCKET_ERROR -1
-# define closesocket close
-# define ioctlsocket ioctl
-# define socketError errno
-
-#endif
-
-static qboolean usingSocks = qfalse;
-static int networkingEnabled = 0;
-
-static cvar_t *net_enabled;
-
-static cvar_t *net_socksEnabled;
-static cvar_t *net_socksServer;
-static cvar_t *net_socksPort;
-static cvar_t *net_socksUsername;
-static cvar_t *net_socksPassword;
-
-static cvar_t *net_ip;
-static cvar_t *net_ip6;
-static cvar_t *net_port;
-static cvar_t *net_port6;
-static cvar_t *net_mcast6addr;
-static cvar_t *net_mcast6iface;
-
-static struct sockaddr socksRelayAddr;
-
-static SOCKET ip_socket = INVALID_SOCKET;
-static SOCKET ip6_socket = INVALID_SOCKET;
-static SOCKET socks_socket = INVALID_SOCKET;
-static SOCKET multicast6_socket = INVALID_SOCKET;
-
-// Keep track of currently joined multicast group.
-static struct ipv6_mreq curgroup;
-// And the currently bound address.
-static struct sockaddr_in6 boundto;
-
-#ifndef IF_NAMESIZE
- #define IF_NAMESIZE 16
-#endif
-
-// use an admin local address per default so that network admins can decide on how to handle quake3 traffic.
-#define NET_MULTICAST_IP6 "ff04::696f:7175:616b:6533"
-
-#define MAX_IPS 32
-
-typedef struct
-{
- char ifname[IF_NAMESIZE];
-
- netadrtype_t type;
- sa_family_t family;
- struct sockaddr_storage addr;
- struct sockaddr_storage netmask;
-} nip_localaddr_t;
-
-static nip_localaddr_t localIP[MAX_IPS];
-static int numIP;
-
-
-//=============================================================================
-
-
-/*
-====================
-NET_ErrorString
-====================
-*/
-char *NET_ErrorString( void ) {
-#ifdef _WIN32
- //FIXME: replace with FormatMessage?
- switch( socketError ) {
- case WSAEINTR: return "WSAEINTR";
- case WSAEBADF: return "WSAEBADF";
- case WSAEACCES: return "WSAEACCES";
- case WSAEDISCON: return "WSAEDISCON";
- case WSAEFAULT: return "WSAEFAULT";
- case WSAEINVAL: return "WSAEINVAL";
- case WSAEMFILE: return "WSAEMFILE";
- case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
- case WSAEINPROGRESS: return "WSAEINPROGRESS";
- case WSAEALREADY: return "WSAEALREADY";
- case WSAENOTSOCK: return "WSAENOTSOCK";
- case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
- case WSAEMSGSIZE: return "WSAEMSGSIZE";
- case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
- case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
- case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
- case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
- case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
- case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
- case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
- case WSAEADDRINUSE: return "WSAEADDRINUSE";
- case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
- case WSAENETDOWN: return "WSAENETDOWN";
- case WSAENETUNREACH: return "WSAENETUNREACH";
- case WSAENETRESET: return "WSAENETRESET";
- case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
- case WSAECONNRESET: return "WSAECONNRESET";
- case WSAENOBUFS: return "WSAENOBUFS";
- case WSAEISCONN: return "WSAEISCONN";
- case WSAENOTCONN: return "WSAENOTCONN";
- case WSAESHUTDOWN: return "WSAESHUTDOWN";
- case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
- case WSAETIMEDOUT: return "WSAETIMEDOUT";
- case WSAECONNREFUSED: return "WSAECONNREFUSED";
- case WSAELOOP: return "WSAELOOP";
- case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
- case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
- case WSASYSNOTREADY: return "WSASYSNOTREADY";
- case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
- case WSANOTINITIALISED: return "WSANOTINITIALISED";
- case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
- case WSATRY_AGAIN: return "WSATRY_AGAIN";
- case WSANO_RECOVERY: return "WSANO_RECOVERY";
- case WSANO_DATA: return "WSANO_DATA";
- default: return "NO ERROR";
- }
-#else
- return strerror (errno);
-#endif
-}
-
-static void NetadrToSockadr( netadr_t *a, struct sockaddr *s ) {
- if( a->type == NA_BROADCAST ) {
- ((struct sockaddr_in *)s)->sin_family = AF_INET;
- ((struct sockaddr_in *)s)->sin_port = a->port;
- ((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
- }
- else if( a->type == NA_IP ) {
- ((struct sockaddr_in *)s)->sin_family = AF_INET;
- ((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
- ((struct sockaddr_in *)s)->sin_port = a->port;
- }
- else if( a->type == NA_IP6 ) {
- ((struct sockaddr_in6 *)s)->sin6_family = AF_INET6;
- ((struct sockaddr_in6 *)s)->sin6_addr = * ((struct in6_addr *) &a->ip6);
- ((struct sockaddr_in6 *)s)->sin6_port = a->port;
- ((struct sockaddr_in6 *)s)->sin6_scope_id = a->scope_id;
- }
- else if(a->type == NA_MULTICAST6)
- {
- ((struct sockaddr_in6 *)s)->sin6_family = AF_INET6;
- ((struct sockaddr_in6 *)s)->sin6_addr = curgroup.ipv6mr_multiaddr;
- ((struct sockaddr_in6 *)s)->sin6_port = a->port;
- }
-}
-
-
-static void SockadrToNetadr( struct sockaddr *s, netadr_t *a ) {
- if (s->sa_family == AF_INET) {
- a->type = NA_IP;
- *(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
- a->port = ((struct sockaddr_in *)s)->sin_port;
- }
- else if(s->sa_family == AF_INET6)
- {
- a->type = NA_IP6;
- memcpy(a->ip6, &((struct sockaddr_in6 *)s)->sin6_addr, sizeof(a->ip6));
- a->port = ((struct sockaddr_in6 *)s)->sin6_port;
- a->scope_id = ((struct sockaddr_in6 *)s)->sin6_scope_id;
- }
-}
-
-
-static struct addrinfo *SearchAddrInfo(struct addrinfo *hints, sa_family_t family)
-{
- while(hints)
- {
- if(hints->ai_family == family)
- return hints;
-
- hints = hints->ai_next;
- }
-
- return NULL;
-}
-
-/*
-=============
-Sys_StringToSockaddr
-=============
-*/
-static qboolean Sys_StringToSockaddr(const char *s, struct sockaddr *sadr, int sadr_len, sa_family_t family)
-{
- struct addrinfo hints;
- struct addrinfo *res = NULL;
- struct addrinfo *search = NULL;
- struct addrinfo *hintsp;
- int retval;
-
- memset(sadr, '\0', sizeof(*sadr));
- memset(&hints, '\0', sizeof(hints));
-
- hintsp = &hints;
- hintsp->ai_family = family;
- hintsp->ai_socktype = SOCK_DGRAM;
-
- retval = getaddrinfo(s, NULL, hintsp, &res);
-
- if(!retval)
- {
- if(family == AF_UNSPEC)
- {
- // Decide here and now which protocol family to use
- if(net_enabled->integer & NET_PRIOV6)
- {
- if(net_enabled->integer & NET_ENABLEV6)
- search = SearchAddrInfo(res, AF_INET6);
-
- if(!search && (net_enabled->integer & NET_ENABLEV4))
- search = SearchAddrInfo(res, AF_INET);
- }
- else
- {
- if(net_enabled->integer & NET_ENABLEV4)
- search = SearchAddrInfo(res, AF_INET);
-
- if(!search && (net_enabled->integer & NET_ENABLEV6))
- search = SearchAddrInfo(res, AF_INET6);
- }
- }
- else
- search = SearchAddrInfo(res, family);
-
- if(search)
- {
- if(res->ai_addrlen > sadr_len)
- res->ai_addrlen = sadr_len;
-
- memcpy(sadr, res->ai_addr, res->ai_addrlen);
- freeaddrinfo(res);
-
- return qtrue;
- }
- else
- Com_Printf("Sys_StringToSockaddr: Error resolving %s: No address of required type found.\n", s);
- }
- else
- Com_Printf("Sys_StringToSockaddr: Error resolving %s: %s\n", s, gai_strerror(retval));
-
- if(res)
- freeaddrinfo(res);
-
- return qfalse;
-}
-
-/*
-=============
-Sys_SockaddrToString
-=============
-*/
-static void Sys_SockaddrToString(char *dest, int destlen, struct sockaddr *input)
-{
- socklen_t inputlen;
-
- if (input->sa_family == AF_INET6)
- inputlen = sizeof(struct sockaddr_in6);
- else
- inputlen = sizeof(struct sockaddr_in);
-
- if(getnameinfo(input, inputlen, dest, destlen, NULL, 0, NI_NUMERICHOST) && destlen > 0)
- *dest = '\0';
-}
-
-/*
-=============
-Sys_StringToAdr
-=============
-*/
-qboolean Sys_StringToAdr( const char *s, netadr_t *a, netadrtype_t family ) {
- struct sockaddr_storage sadr;
- sa_family_t fam;
-
- switch(family)
- {
- case NA_IP:
- fam = AF_INET;
- break;
- case NA_IP6:
- fam = AF_INET6;
- break;
- default:
- fam = AF_UNSPEC;
- break;
- }
- if( !Sys_StringToSockaddr(s, (struct sockaddr *) &sadr, sizeof(sadr), fam ) ) {
- return qfalse;
- }
-
- SockadrToNetadr( (struct sockaddr *) &sadr, a );
- return qtrue;
-}
-
-/*
-===================
-NET_CompareBaseAdrMask
-
-Compare without port, and up to the bit number given in netmask.
-===================
-*/
-qboolean NET_CompareBaseAdrMask(netadr_t a, netadr_t b, int netmask)
-{
- qboolean differed;
- byte cmpmask, *addra, *addrb;
- int curbyte;
-
- if (a.type != b.type)
- return qfalse;
-
- if (a.type == NA_LOOPBACK)
- return qtrue;
-
- if(a.type == NA_IP)
- {
- addra = (byte *) &a.ip;
- addrb = (byte *) &b.ip;
-
- if(netmask < 0 || netmask > 32)
- netmask = 32;
- }
- else if(a.type == NA_IP6)
- {
- addra = (byte *) &a.ip6;
- addrb = (byte *) &b.ip6;
-
- if(netmask < 0 || netmask > 128)
- netmask = 128;
- }
- else
- {
- Com_Printf ("NET_CompareBaseAdr: bad address type\n");
- return qfalse;
- }
-
- differed = qfalse;
- curbyte = 0;
-
- while(netmask > 7)
- {
- if(addra[curbyte] != addrb[curbyte])
- {
- differed = qtrue;
- break;
- }
-
- curbyte++;
- netmask -= 8;
- }
-
- if(differed)
- return qfalse;
-
- if(netmask)
- {
- cmpmask = (1 << netmask) - 1;
- cmpmask <<= 8 - netmask;
-
- if((addra[curbyte] & cmpmask) == (addrb[curbyte] & cmpmask))
- return qtrue;
- }
- else
- return qtrue;
-
- return qfalse;
-}
-
-
-/*
-===================
-NET_CompareBaseAdr
-
-Compares without the port
-===================
-*/
-qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
-{
- return NET_CompareBaseAdrMask(a, b, -1);
-}
-
-const char *NET_AdrToString (netadr_t a)
-{
- static char s[NET_ADDRSTRMAXLEN];
-
- if (a.type == NA_LOOPBACK)
- Com_sprintf (s, sizeof(s), "loopback");
- else if (a.type == NA_BOT)
- Com_sprintf (s, sizeof(s), "bot");
- else if (a.type == NA_IP || a.type == NA_IP6)
- {
- struct sockaddr_storage sadr;
-
- memset(&sadr, 0, sizeof(sadr));
- NetadrToSockadr(&a, (struct sockaddr *) &sadr);
- Sys_SockaddrToString(s, sizeof(s), (struct sockaddr *) &sadr);
- }
-
- return s;
-}
-
-const char *NET_AdrToStringwPort (netadr_t a)
-{
- static char s[NET_ADDRSTRMAXLEN];
-
- if (a.type == NA_LOOPBACK)
- Com_sprintf (s, sizeof(s), "loopback");
- else if (a.type == NA_BOT)
- Com_sprintf (s, sizeof(s), "bot");
- else if(a.type == NA_IP)
- Com_sprintf(s, sizeof(s), "%s:%hu", NET_AdrToString(a), ntohs(a.port));
- else if(a.type == NA_IP6)
- Com_sprintf(s, sizeof(s), "[%s]:%hu", NET_AdrToString(a), ntohs(a.port));
-
- return s;
-}
-
-
-qboolean NET_CompareAdr (netadr_t a, netadr_t b)
-{
- if(!NET_CompareBaseAdr(a, b))
- return qfalse;
-
- if (a.type == NA_IP || a.type == NA_IP6)
- {
- if (a.port == b.port)
- return qtrue;
- }
- else
- return qtrue;
-
- return qfalse;
-}
-
-
-qboolean NET_IsLocalAddress( netadr_t adr ) {
- return adr.type == NA_LOOPBACK;
-}
-
-//=============================================================================
-
-/*
-==================
-Sys_GetPacket
-
-Never called by the game logic, just the system event queing
-==================
-*/
-#ifdef _DEBUG
-int recvfromCount;
-#endif
-
-qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) {
- int ret;
- struct sockaddr_storage from;
- socklen_t fromlen;
- int err;
-
-#ifdef _DEBUG
- recvfromCount++; // performance check
-#endif
-
- if(ip_socket != INVALID_SOCKET)
- {
- fromlen = sizeof(from);
- ret = recvfrom( ip_socket, (void *)net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen );
-
- if (ret == SOCKET_ERROR)
- {
- err = socketError;
-
- if( err != EAGAIN && err != ECONNRESET )
- Com_Printf( "NET_GetPacket: %s\n", NET_ErrorString() );
- }
- else
- {
-
- memset( ((struct sockaddr_in *)&from)->sin_zero, 0, 8 );
-
- if ( usingSocks && memcmp( &from, &socksRelayAddr, fromlen ) == 0 ) {
- if ( ret < 10 || net_message->data[0] != 0 || net_message->data[1] != 0 || net_message->data[2] != 0 || net_message->data[3] != 1 ) {
- return qfalse;
- }
- net_from->type = NA_IP;
- net_from->ip[0] = net_message->data[4];
- net_from->ip[1] = net_message->data[5];
- net_from->ip[2] = net_message->data[6];
- net_from->ip[3] = net_message->data[7];
- net_from->port = *(short *)&net_message->data[8];
- net_message->readcount = 10;
- }
- else {
- SockadrToNetadr( (struct sockaddr *) &from, net_from );
- net_message->readcount = 0;
- }
-
- if( ret == net_message->maxsize ) {
- Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
- return qfalse;
- }
-
- net_message->cursize = ret;
- return qtrue;
- }
- }
-
- if(ip6_socket != INVALID_SOCKET)
- {
- fromlen = sizeof(from);
- ret = recvfrom(ip6_socket, (void *)net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen);
-
- if (ret == SOCKET_ERROR)
- {
- err = socketError;
-
- if( err != EAGAIN && err != ECONNRESET )
- Com_Printf( "NET_GetPacket: %s\n", NET_ErrorString() );
- }
- else
- {
- SockadrToNetadr((struct sockaddr *) &from, net_from);
- net_message->readcount = 0;
-
- if(ret == net_message->maxsize)
- {
- Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
- return qfalse;
- }
-
- net_message->cursize = ret;
- return qtrue;
- }
- }
-
- if(multicast6_socket != INVALID_SOCKET && multicast6_socket != ip6_socket)
- {
- fromlen = sizeof(from);
- ret = recvfrom(multicast6_socket, (void *)net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen);
-
- if (ret == SOCKET_ERROR)
- {
- err = socketError;
-
- if( err != EAGAIN && err != ECONNRESET )
- Com_Printf( "NET_GetPacket: %s\n", NET_ErrorString() );
- }
- else
- {
- SockadrToNetadr((struct sockaddr *) &from, net_from);
- net_message->readcount = 0;
-
- if(ret == net_message->maxsize)
- {
- Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
- return qfalse;
- }
-
- net_message->cursize = ret;
- return qtrue;
- }
- }
-
-
- return qfalse;
-}
-
-//=============================================================================
-
-static char socksBuf[4096];
-
-/*
-==================
-Sys_SendPacket
-==================
-*/
-void Sys_SendPacket( int length, const void *data, netadr_t to ) {
- int ret = SOCKET_ERROR;
- struct sockaddr_storage addr;
-
- if( to.type != NA_BROADCAST && to.type != NA_IP && to.type != NA_IP6 && to.type != NA_MULTICAST6)
- {
- Com_Error( ERR_FATAL, "Sys_SendPacket: bad address type" );
- return;
- }
-
- if( (ip_socket == INVALID_SOCKET && to.type == NA_IP) ||
- (ip6_socket == INVALID_SOCKET && to.type == NA_IP6) ||
- (ip6_socket == INVALID_SOCKET && to.type == NA_MULTICAST6) )
- return;
-
- if(to.type == NA_MULTICAST6 && (net_enabled->integer & NET_DISABLEMCAST))
- return;
-
- memset(&addr, 0, sizeof(addr));
- NetadrToSockadr( &to, (struct sockaddr *) &addr );
-
- if( usingSocks && to.type == NA_IP ) {
- socksBuf[0] = 0; // reserved
- socksBuf[1] = 0;
- socksBuf[2] = 0; // fragment (not fragmented)
- socksBuf[3] = 1; // address type: IPV4
- *(int *)&socksBuf[4] = ((struct sockaddr_in *)&addr)->sin_addr.s_addr;
- *(short *)&socksBuf[8] = ((struct sockaddr_in *)&addr)->sin_port;
- memcpy( &socksBuf[10], data, length );
- ret = sendto( ip_socket, socksBuf, length+10, 0, &socksRelayAddr, sizeof(socksRelayAddr) );
- }
- else {
- if(addr.ss_family == AF_INET)
- ret = sendto( ip_socket, data, length, 0, (struct sockaddr *) &addr, sizeof(struct sockaddr_in) );
- else if(addr.ss_family == AF_INET6)
- ret = sendto( ip6_socket, data, length, 0, (struct sockaddr *) &addr, sizeof(struct sockaddr_in6) );
- }
- if( ret == SOCKET_ERROR ) {
- int err = socketError;
-
- // wouldblock is silent
- if( err == EAGAIN ) {
- return;
- }
-
- // some PPP links do not allow broadcasts and return an error
- if( ( err == EADDRNOTAVAIL ) && ( ( to.type == NA_BROADCAST ) ) ) {
- return;
- }
-
- Com_Printf( "NET_SendPacket: %s\n", NET_ErrorString() );
- }
-}
-
-
-//=============================================================================
-
-/*
-==================
-Sys_IsLANAddress
-
-LAN clients will have their rate var ignored
-==================
-*/
-qboolean Sys_IsLANAddress( netadr_t adr ) {
- int index, run, addrsize;
- qboolean differed;
- byte *compareadr, *comparemask, *compareip;
-
- if( adr.type == NA_LOOPBACK ) {
- return qtrue;
- }
-
- if( adr.type == NA_IP )
- {
- // RFC1918:
- // 10.0.0.0 - 10.255.255.255 (10/8 prefix)
- // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
- // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
- if(adr.ip[0] == 10)
- return qtrue;
- if(adr.ip[0] == 172 && (adr.ip[1]&0xf0) == 16)
- return qtrue;
- if(adr.ip[0] == 192 && adr.ip[1] == 168)
- return qtrue;
-
- if(adr.ip[0] == 127)
- return qtrue;
- }
- else if(adr.type == NA_IP6)
- {
- if(adr.ip6[0] == 0xfe && (adr.ip6[1] & 0xc0) == 0x80)
- return qtrue;
- if((adr.ip6[0] & 0xfe) == 0xfc)
- return qtrue;
- }
-
- // Now compare against the networks this computer is member of.
- for(index = 0; index < numIP; index++)
- {
- if(localIP[index].type == adr.type)
- {
- if(adr.type == NA_IP)
- {
- compareip = (byte *) &((struct sockaddr_in *) &localIP[index].addr)->sin_addr.s_addr;
- comparemask = (byte *) &((struct sockaddr_in *) &localIP[index].netmask)->sin_addr.s_addr;
- compareadr = adr.ip;
-
- addrsize = sizeof(adr.ip);
- }
- else
- {
- // TODO? should we check the scope_id here?
-
- compareip = (byte *) &((struct sockaddr_in6 *) &localIP[index].addr)->sin6_addr;
- comparemask = (byte *) &((struct sockaddr_in6 *) &localIP[index].netmask)->sin6_addr;
- compareadr = adr.ip6;
-
- addrsize = sizeof(adr.ip6);
- }
-
- differed = qfalse;
- for(run = 0; run < addrsize; run++)
- {
- if((compareip[run] & comparemask[run]) != (compareadr[run] & comparemask[run]))
- {
- differed = qtrue;
- break;
- }
- }
-
- if(!differed)
- return qtrue;
-
- }
- }
-
- return qfalse;
-}
-
-/*
-==================
-Sys_ShowIP
-==================
-*/
-void Sys_ShowIP(void) {
- int i;
- char addrbuf[NET_ADDRSTRMAXLEN];
-
- for(i = 0; i < numIP; i++)
- {
- Sys_SockaddrToString(addrbuf, sizeof(addrbuf), (struct sockaddr *) &localIP[i].addr);
-
- if(localIP[i].type == NA_IP)
- Com_Printf( "IP: %s\n", addrbuf);
- else if(localIP[i].type == NA_IP6)
- Com_Printf( "IP6: %s\n", addrbuf);
- }
-}
-
-
-//=============================================================================
-
-
-/*
-====================
-NET_IPSocket
-====================
-*/
-int NET_IPSocket( char *net_interface, int port, int *err ) {
- SOCKET newsocket;
- struct sockaddr_in address;
- u_long _true = 1;
- int i = 1;
-
- *err = 0;
-
- if( net_interface ) {
- Com_Printf( "Opening IP socket: %s:%i\n", net_interface, port );
- }
- else {
- Com_Printf( "Opening IP socket: 0.0.0.0:%i\n", port );
- }
-
- if( ( newsocket = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) {
- *err = socketError;
- Com_Printf( "WARNING: NET_IPSocket: socket: %s\n", NET_ErrorString() );
- return newsocket;
- }
- // make it non-blocking
- if( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) {
- Com_Printf( "WARNING: NET_IPSocket: ioctl FIONBIO: %s\n", NET_ErrorString() );
- *err = socketError;
- closesocket(newsocket);
- return INVALID_SOCKET;
- }
-
- // make it broadcast capable
- if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *) &i, sizeof(i) ) == SOCKET_ERROR ) {
- Com_Printf( "WARNING: NET_IPSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString() );
-
- // it is not that bad if this one fails.
-// return newsocket;
- }
-
- if( !net_interface || !net_interface[0]) {
- address.sin_family = AF_INET;
- address.sin_addr.s_addr = INADDR_ANY;
- }
- else
- {
- if(!Sys_StringToSockaddr( net_interface, (struct sockaddr *)&address, sizeof(address), AF_INET))
- {
- closesocket(newsocket);
- return INVALID_SOCKET;
- }
- }
-
- if( port == PORT_ANY ) {
- address.sin_port = 0;
- }
- else {
- address.sin_port = htons( (short)port );
- }
-
- if( bind( newsocket, (void *)&address, sizeof(address) ) == SOCKET_ERROR ) {
- Com_Printf( "WARNING: NET_IPSocket: bind: %s\n", NET_ErrorString() );
- *err = socketError;
- closesocket( newsocket );
- return INVALID_SOCKET;
- }
-
- return newsocket;
-}
-
-/*
-====================
-NET_IP6Socket
-====================
-*/
-int NET_IP6Socket( char *net_interface, int port, struct sockaddr_in6 *bindto, int *err ) {
- SOCKET newsocket;
- struct sockaddr_in6 address;
- u_long _true = 1;
-
- *err = 0;
-
- if( net_interface )
- {
- // Print the name in brackets if there is a colon:
- if(Q_CountChar(net_interface, ':'))
- Com_Printf( "Opening IP6 socket: [%s]:%i\n", net_interface, port );
- else
- Com_Printf( "Opening IP6 socket: %s:%i\n", net_interface, port );
- }
- else
- Com_Printf( "Opening IP6 socket: [::]:%i\n", port );
-
- if( ( newsocket = socket( PF_INET6, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) {
- *err = socketError;
- Com_Printf( "WARNING: NET_IP6Socket: socket: %s\n", NET_ErrorString() );
- return newsocket;
- }
-
- // make it non-blocking
- if( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) {
- Com_Printf( "WARNING: NET_IP6Socket: ioctl FIONBIO: %s\n", NET_ErrorString() );
- *err = socketError;
- closesocket(newsocket);
- return INVALID_SOCKET;
- }
-
-#ifdef IPV6_V6ONLY
- {
- int i = 1;
-
- // ipv4 addresses should not be allowed to connect via this socket.
- if(setsockopt(newsocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &i, sizeof(i)) == SOCKET_ERROR)
- {
- // win32 systems don't seem to support this anyways.
- Com_DPrintf("WARNING: NET_IP6Socket: setsockopt IPV6_V6ONLY: %s\n", NET_ErrorString());
- }
- }
-#endif
-
- if( !net_interface || !net_interface[0]) {
- address.sin6_family = AF_INET6;
- address.sin6_addr = in6addr_any;
- }
- else
- {
- if(!Sys_StringToSockaddr( net_interface, (struct sockaddr *)&address, sizeof(address), AF_INET6))
- {
- closesocket(newsocket);
- return INVALID_SOCKET;
- }
- }
-
- if( port == PORT_ANY ) {
- address.sin6_port = 0;
- }
- else {
- address.sin6_port = htons( (short)port );
- }
-
- if( bind( newsocket, (void *)&address, sizeof(address) ) == SOCKET_ERROR ) {
- Com_Printf( "WARNING: NET_IP6Socket: bind: %s\n", NET_ErrorString() );
- *err = socketError;
- closesocket( newsocket );
- return INVALID_SOCKET;
- }
-
- if(bindto)
- *bindto = address;
-
- return newsocket;
-}
-
-/*
-====================
-NET_SetMulticast
-Set the current multicast group
-====================
-*/
-void NET_SetMulticast6(void)
-{
- struct sockaddr_in6 addr;
-
- if(!*net_mcast6addr->string || !Sys_StringToSockaddr(net_mcast6addr->string, (struct sockaddr *) &addr, sizeof(addr), AF_INET6))
- {
- Com_Printf("WARNING: NET_JoinMulticast6: Incorrect multicast address given, "
- "please set cvar %s to a sane value.\n", net_mcast6addr->name);
-
- Cvar_SetValue(net_enabled->name, net_enabled->integer | NET_DISABLEMCAST);
-
- return;
- }
-
- memcpy(&curgroup.ipv6mr_multiaddr, &addr.sin6_addr, sizeof(curgroup.ipv6mr_multiaddr));
-
- if(*net_mcast6iface->string)
- {
-#ifdef _WIN32
- curgroup.ipv6mr_interface = net_mcast6iface->integer;
-#else
- curgroup.ipv6mr_interface = if_nametoindex(net_mcast6iface->string);
-#endif
- }
- else
- curgroup.ipv6mr_interface = 0;
-}
-
-/*
-====================
-NET_JoinMulticast
-Join an ipv6 multicast group
-====================
-*/
-void NET_JoinMulticast6(void)
-{
- int err;
-
- if(ip6_socket == INVALID_SOCKET || multicast6_socket != INVALID_SOCKET || (net_enabled->integer & NET_DISABLEMCAST))
- return;
-
- if(IN6_IS_ADDR_MULTICAST(&boundto.sin6_addr) || IN6_IS_ADDR_UNSPECIFIED(&boundto.sin6_addr))
- {
- // The way the socket was bound does not prohibit receiving multi-cast packets. So we don't need to open a new one.
- multicast6_socket = ip6_socket;
- }
- else
- {
- if((multicast6_socket = NET_IP6Socket(net_mcast6addr->string, ntohs(boundto.sin6_port), NULL, &err)) == INVALID_SOCKET)
- {
- // If the OS does not support binding to multicast addresses, like WinXP, at least try with the normal file descriptor.
- multicast6_socket = ip6_socket;
- }
- }
-
- if(curgroup.ipv6mr_interface)
- {
- if (setsockopt(multicast6_socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
- (char *) &curgroup.ipv6mr_interface, sizeof(curgroup.ipv6mr_interface)) < 0)
- {
- Com_Printf("NET_JoinMulticast6: Couldn't set scope on multicast socket: %s\n", NET_ErrorString());
-
- if(multicast6_socket != ip6_socket)
- {
- closesocket(multicast6_socket);
- multicast6_socket = INVALID_SOCKET;
- return;
- }
- }
- }
-
- if (setsockopt(multicast6_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &curgroup, sizeof(curgroup)))
- {
- Com_Printf("NET_JoinMulticast6: Couldn't join multicast group: %s\n", NET_ErrorString());
-
- if(multicast6_socket != ip6_socket)
- {
- closesocket(multicast6_socket);
- multicast6_socket = INVALID_SOCKET;
- return;
- }
- }
-}
-
-void NET_LeaveMulticast6()
-{
- if(multicast6_socket != INVALID_SOCKET)
- {
- if(multicast6_socket != ip6_socket)
- closesocket(multicast6_socket);
- else
- setsockopt(multicast6_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *) &curgroup, sizeof(curgroup));
-
- multicast6_socket = INVALID_SOCKET;
- }
-}
-
-/*
-====================
-NET_OpenSocks
-====================
-*/
-void NET_OpenSocks( int port ) {
- struct sockaddr_in address;
- int err;
- struct hostent *h;
- int len;
- qboolean rfc1929;
- unsigned char buf[64];
-
- usingSocks = qfalse;
-
- Com_Printf( "Opening connection to SOCKS server.\n" );
-
- if ( ( socks_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == INVALID_SOCKET ) {
- err = socketError;
- Com_Printf( "WARNING: NET_OpenSocks: socket: %s\n", NET_ErrorString() );
- return;
- }
-
- h = gethostbyname( net_socksServer->string );
- if ( h == NULL ) {
- err = socketError;
- Com_Printf( "WARNING: NET_OpenSocks: gethostbyname: %s\n", NET_ErrorString() );
- return;
- }
- if ( h->h_addrtype != AF_INET ) {
- Com_Printf( "WARNING: NET_OpenSocks: gethostbyname: address type was not AF_INET\n" );
- return;
- }
- address.sin_family = AF_INET;
- address.sin_addr.s_addr = *(int *)h->h_addr_list[0];
- address.sin_port = htons( (short)net_socksPort->integer );
-
- if ( connect( socks_socket, (struct sockaddr *)&address, sizeof( address ) ) == SOCKET_ERROR ) {
- err = socketError;
- Com_Printf( "NET_OpenSocks: connect: %s\n", NET_ErrorString() );
- return;
- }
-
- // send socks authentication handshake
- if ( *net_socksUsername->string || *net_socksPassword->string ) {
- rfc1929 = qtrue;
- }
- else {
- rfc1929 = qfalse;
- }
-
- buf[0] = 5; // SOCKS version
- // method count
- if ( rfc1929 ) {
- buf[1] = 2;
- len = 4;
- }
- else {
- buf[1] = 1;
- len = 3;
- }
- buf[2] = 0; // method #1 - method id #00: no authentication
- if ( rfc1929 ) {
- buf[2] = 2; // method #2 - method id #02: username/password
- }
- if ( send( socks_socket, (void *)buf, len, 0 ) == SOCKET_ERROR ) {
- err = socketError;
- Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
- return;
- }
-
- // get the response
- len = recv( socks_socket, (void *)buf, 64, 0 );
- if ( len == SOCKET_ERROR ) {
- err = socketError;
- Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
- return;
- }
- if ( len != 2 || buf[0] != 5 ) {
- Com_Printf( "NET_OpenSocks: bad response\n" );
- return;
- }
- switch( buf[1] ) {
- case 0: // no authentication
- break;
- case 2: // username/password authentication
- break;
- default:
- Com_Printf( "NET_OpenSocks: request denied\n" );
- return;
- }
-
- // do username/password authentication if needed
- if ( buf[1] == 2 ) {
- int ulen;
- int plen;
-
- // build the request
- ulen = strlen( net_socksUsername->string );
- plen = strlen( net_socksPassword->string );
-
- buf[0] = 1; // username/password authentication version
- buf[1] = ulen;
- if ( ulen ) {
- memcpy( &buf[2], net_socksUsername->string, ulen );
- }
- buf[2 + ulen] = plen;
- if ( plen ) {
- memcpy( &buf[3 + ulen], net_socksPassword->string, plen );
- }
-
- // send it
- if ( send( socks_socket, (void *)buf, 3 + ulen + plen, 0 ) == SOCKET_ERROR ) {
- err = socketError;
- Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
- return;
- }
-
- // get the response
- len = recv( socks_socket, (void *)buf, 64, 0 );
- if ( len == SOCKET_ERROR ) {
- err = socketError;
- Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
- return;
- }
- if ( len != 2 || buf[0] != 1 ) {
- Com_Printf( "NET_OpenSocks: bad response\n" );
- return;
- }
- if ( buf[1] != 0 ) {
- Com_Printf( "NET_OpenSocks: authentication failed\n" );
- return;
- }
- }
-
- // send the UDP associate request
- buf[0] = 5; // SOCKS version
- buf[1] = 3; // command: UDP associate
- buf[2] = 0; // reserved
- buf[3] = 1; // address type: IPV4
- *(int *)&buf[4] = INADDR_ANY;
- *(short *)&buf[8] = htons( (short)port ); // port
- if ( send( socks_socket, (void *)buf, 10, 0 ) == SOCKET_ERROR ) {
- err = socketError;
- Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
- return;
- }
-
- // get the response
- len = recv( socks_socket, (void *)buf, 64, 0 );
- if( len == SOCKET_ERROR ) {
- err = socketError;
- Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
- return;
- }
- if( len < 2 || buf[0] != 5 ) {
- Com_Printf( "NET_OpenSocks: bad response\n" );
- return;
- }
- // check completion code
- if( buf[1] != 0 ) {
- Com_Printf( "NET_OpenSocks: request denied: %i\n", buf[1] );
- return;
- }
- if( buf[3] != 1 ) {
- Com_Printf( "NET_OpenSocks: relay address is not IPV4: %i\n", buf[3] );
- return;
- }
- ((struct sockaddr_in *)&socksRelayAddr)->sin_family = AF_INET;
- ((struct sockaddr_in *)&socksRelayAddr)->sin_addr.s_addr = *(int *)&buf[4];
- ((struct sockaddr_in *)&socksRelayAddr)->sin_port = *(short *)&buf[8];
- memset( ((struct sockaddr_in *)&socksRelayAddr)->sin_zero, 0, 8 );
-
- usingSocks = qtrue;
-}
-
-
-/*
-=====================
-NET_GetLocalAddress
-=====================
-*/
-void NET_AddLocalAddress(char *ifname, struct sockaddr *addr, struct sockaddr *netmask)
-{
- int addrlen;
- sa_family_t family;
-
- // only add addresses that have all required info.
- if(!addr || !netmask || !ifname)
- return;
-
- family = addr->sa_family;
-
- if(numIP < MAX_IPS)
- {
- if(family == AF_INET)
- {
- addrlen = sizeof(struct sockaddr_in);
- localIP[numIP].type = NA_IP;
- }
- else if(family == AF_INET6)
- {
- addrlen = sizeof(struct sockaddr_in6);
- localIP[numIP].type = NA_IP6;
- }
- else
- return;
-
- Q_strncpyz(localIP[numIP].ifname, ifname, sizeof(localIP[numIP].ifname));
-
- localIP[numIP].family = family;
-
- memcpy(&localIP[numIP].addr, addr, addrlen);
- memcpy(&localIP[numIP].netmask, netmask, addrlen);
-
- numIP++;
- }
-}
-
-#if defined(__linux__) || defined(MACOSX) || defined(__BSD__)
-void NET_GetLocalAddress(void)
-{
- struct ifaddrs *ifap, *search;
-
- if(getifaddrs(&ifap))
- Com_Printf("NET_GetLocalAddress: Unable to get list of network interfaces: %s\n", NET_ErrorString());
- else
- {
- for(search = ifap; search; search = search->ifa_next)
- {
- // Only add interfaces that are up.
- if(ifap->ifa_flags & IFF_UP)
- NET_AddLocalAddress(search->ifa_name, search->ifa_addr, search->ifa_netmask);
- }
-
- freeifaddrs(ifap);
-
- Sys_ShowIP();
- }
-}
-#else
-void NET_GetLocalAddress( void ) {
- char hostname[256];
- struct addrinfo hint;
- struct addrinfo *res = NULL;
-
- if(gethostname( hostname, 256 ) == SOCKET_ERROR)
- return;
-
- Com_Printf( "Hostname: %s\n", hostname );
-
- memset(&hint, 0, sizeof(hint));
-
- hint.ai_family = AF_UNSPEC;
- hint.ai_socktype = SOCK_DGRAM;
-
- if(!getaddrinfo(hostname, NULL, &hint, &res))
- {
- struct sockaddr_in mask4;
- struct sockaddr_in6 mask6;
- struct addrinfo *search;
-
- /* On operating systems where it's more difficult to find out the configured interfaces, we'll just assume a
- * netmask with all bits set. */
-
- memset(&mask4, 0, sizeof(mask4));
- memset(&mask6, 0, sizeof(mask6));
- mask4.sin_family = AF_INET;
- memset(&mask4.sin_addr.s_addr, 0xFF, sizeof(mask4.sin_addr.s_addr));
- mask6.sin6_family = AF_INET6;
- memset(&mask6.sin6_addr, 0xFF, sizeof(mask6.sin6_addr));
-
- // add all IPs from returned list.
- for(search = res; search; search = search->ai_next)
- {
- if(search->ai_family == AF_INET)
- NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask4);
- else if(search->ai_family == AF_INET6)
- NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask6);
- }
-
- Sys_ShowIP();
- }
-
- if(res)
- freeaddrinfo(res);
-}
-#endif
-
-/*
-====================
-NET_OpenIP
-====================
-*/
-void NET_OpenIP( void ) {
- int i;
- int err;
- int port;
- int port6;
-
- port = net_port->integer;
- port6 = net_port6->integer;
-
- NET_GetLocalAddress();
-
- // automatically scan for a valid port, so multiple
- // dedicated servers can be started without requiring
- // a different net_port for each one
-
- if(net_enabled->integer & NET_ENABLEV6)
- {
- for( i = 0 ; i < 10 ; i++ )
- {
- ip6_socket = NET_IP6Socket(net_ip6->string, port6 + i, &boundto, &err);
- if (ip6_socket != INVALID_SOCKET)
- {
- Cvar_SetValue( "net_port6", port6 + i );
- break;
- }
- else
- {
- if(err == EAFNOSUPPORT)
- break;
- }
- }
- if(ip6_socket == INVALID_SOCKET)
- Com_Printf( "WARNING: Couldn't bind to a v6 ip address.\n");
- }
-
- if(net_enabled->integer & NET_ENABLEV4)
- {
- for( i = 0 ; i < 10 ; i++ ) {
- ip_socket = NET_IPSocket( net_ip->string, port + i, &err );
- if (ip_socket != INVALID_SOCKET) {
- Cvar_SetValue( "net_port", port + i );
-
- if (net_socksEnabled->integer)
- NET_OpenSocks( port + i );
-
- break;
- }
- else
- {
- if(err == EAFNOSUPPORT)
- break;
- }
- }
-
- if(ip_socket == INVALID_SOCKET)
- Com_Printf( "WARNING: Couldn't bind to a v4 ip address.\n");
- }
-}
-
-
-//===================================================================
-
-
-/*
-====================
-NET_GetCvars
-====================
-*/
-static qboolean NET_GetCvars( void ) {
- int modified;
-
-#ifdef DEDICATED
- // I want server owners to explicitly turn on ipv6 support.
- net_enabled = Cvar_Get( "net_enabled", "1", CVAR_LATCH | CVAR_ARCHIVE );
-#else
- /* End users have it enabled so they can connect to ipv6-only hosts, but ipv4 will be
- * used if available due to ping */
- net_enabled = Cvar_Get( "net_enabled", "3", CVAR_LATCH | CVAR_ARCHIVE );
-#endif
- modified = net_enabled->modified;
- net_enabled->modified = qfalse;
-
- net_ip = Cvar_Get( "net_ip", "0.0.0.0", CVAR_LATCH );
- modified += net_ip->modified;
- net_ip->modified = qfalse;
-
- net_ip6 = Cvar_Get( "net_ip6", "::", CVAR_LATCH );
- modified += net_ip6->modified;
- net_ip6->modified = qfalse;
-
- net_port = Cvar_Get( "net_port", va( "%i", PORT_SERVER ), CVAR_LATCH );
- modified += net_port->modified;
- net_port->modified = qfalse;
-
- net_port6 = Cvar_Get( "net_port6", va( "%i", PORT_SERVER ), CVAR_LATCH );
- modified += net_port6->modified;
- net_port6->modified = qfalse;
-
- // Some cvars for configuring multicast options which facilitates scanning for servers on local subnets.
- net_mcast6addr = Cvar_Get( "net_mcast6addr", NET_MULTICAST_IP6, CVAR_LATCH | CVAR_ARCHIVE );
- modified += net_mcast6addr->modified;
- net_mcast6addr->modified = qfalse;
-
-#ifdef _WIN32
- net_mcast6iface = Cvar_Get( "net_mcast6iface", "0", CVAR_LATCH | CVAR_ARCHIVE );
-#else
- net_mcast6iface = Cvar_Get( "net_mcast6iface", "", CVAR_LATCH | CVAR_ARCHIVE );
-#endif
- modified += net_mcast6iface->modified;
- net_mcast6iface->modified = qfalse;
-
- net_socksEnabled = Cvar_Get( "net_socksEnabled", "0", CVAR_LATCH | CVAR_ARCHIVE );
- modified += net_socksEnabled->modified;
- net_socksEnabled->modified = qfalse;
-
- net_socksServer = Cvar_Get( "net_socksServer", "", CVAR_LATCH | CVAR_ARCHIVE );
- modified += net_socksServer->modified;
- net_socksServer->modified = qfalse;
-
- net_socksPort = Cvar_Get( "net_socksPort", "1080", CVAR_LATCH | CVAR_ARCHIVE );
- modified += net_socksPort->modified;
- net_socksPort->modified = qfalse;
-
- net_socksUsername = Cvar_Get( "net_socksUsername", "", CVAR_LATCH | CVAR_ARCHIVE );
- modified += net_socksUsername->modified;
- net_socksUsername->modified = qfalse;
-
- net_socksPassword = Cvar_Get( "net_socksPassword", "", CVAR_LATCH | CVAR_ARCHIVE );
- modified += net_socksPassword->modified;
- net_socksPassword->modified = qfalse;
-
- return modified ? qtrue : qfalse;
-}
-
-
-/*
-====================
-NET_Config
-====================
-*/
-void NET_Config( qboolean enableNetworking ) {
- qboolean modified;
- qboolean stop;
- qboolean start;
-
- // get any latched changes to cvars
- modified = NET_GetCvars();
-
- if( !net_enabled->integer ) {
- enableNetworking = 0;
- }
-
- // if enable state is the same and no cvars were modified, we have nothing to do
- if( enableNetworking == networkingEnabled && !modified ) {
- return;
- }
-
- if( enableNetworking == networkingEnabled ) {
- if( enableNetworking ) {
- stop = qtrue;
- start = qtrue;
- }
- else {
- stop = qfalse;
- start = qfalse;
- }
- }
- else {
- if( enableNetworking ) {
- stop = qfalse;
- start = qtrue;
- }
- else {
- stop = qtrue;
- start = qfalse;
- }
- networkingEnabled = enableNetworking;
- }
-
- if( stop ) {
- if ( ip_socket != INVALID_SOCKET ) {
- closesocket( ip_socket );
- ip_socket = INVALID_SOCKET;
- }
-
- if(multicast6_socket)
- {
- if(multicast6_socket != ip6_socket)
- closesocket(multicast6_socket);
-
- multicast6_socket = INVALID_SOCKET;
- }
-
- if ( ip6_socket != INVALID_SOCKET ) {
- closesocket( ip6_socket );
- ip6_socket = INVALID_SOCKET;
- }
-
- if ( socks_socket != INVALID_SOCKET ) {
- closesocket( socks_socket );
- socks_socket = INVALID_SOCKET;
- }
-
- }
-
- if( start )
- {
- if (net_enabled->integer)
- {
- NET_OpenIP();
- NET_SetMulticast6();
- }
- }
-}
-
-
-/*
-====================
-NET_Init
-====================
-*/
-void NET_Init( void ) {
-#ifdef _WIN32
- int r;
-
- r = WSAStartup( MAKEWORD( 1, 1 ), &winsockdata );
- if( r ) {
- Com_Printf( "WARNING: Winsock initialization failed, returned %d\n", r );
- return;
- }
-
- winsockInitialized = qtrue;
- Com_Printf( "Winsock Initialized\n" );
-#endif
-
- NET_Config( qtrue );
-
- Cmd_AddCommand ("net_restart", NET_Restart_f);
-}
-
-
-/*
-====================
-NET_Shutdown
-====================
-*/
-void NET_Shutdown( void ) {
- if ( !networkingEnabled ) {
- return;
- }
-
- NET_Config( qfalse );
-
-#ifdef _WIN32
- WSACleanup();
- winsockInitialized = qfalse;
-#endif
-}
-
-
-/*
-====================
-NET_Sleep
-
-Sleeps msec or until something happens on the network
-====================
-*/
-void NET_Sleep( int msec ) {
- struct timeval timeout;
- fd_set fdset;
- int highestfd = -1;
-
- if (!com_dedicated->integer)
- return; // we're not a server, just run full speed
-
- if (ip_socket == INVALID_SOCKET && ip6_socket == INVALID_SOCKET)
- return;
-
- if (msec < 0 )
- return;
-
- FD_ZERO(&fdset);
-
- if(ip_socket != INVALID_SOCKET)
- {
- FD_SET(ip_socket, &fdset);
-
- highestfd = ip_socket;
- }
- if(ip6_socket != INVALID_SOCKET)
- {
- FD_SET(ip6_socket, &fdset);
-
- if(ip6_socket > highestfd)
- highestfd = ip6_socket;
- }
-
- timeout.tv_sec = msec/1000;
- timeout.tv_usec = (msec%1000)*1000;
- select(highestfd + 1, &fdset, NULL, NULL, &timeout);
-}
-
-
-/*
-====================
-NET_Restart_f
-====================
-*/
-void NET_Restart_f( void ) {
- NET_Config( networkingEnabled );
-}
diff --git a/engine/code/qcommon/puff.c b/engine/code/qcommon/puff.c
deleted file mode 100644
index 721854d..0000000
--- a/engine/code/qcommon/puff.c
+++ /dev/null
@@ -1,758 +0,0 @@
-/*
- * This is a modified version of Mark Adlers work,
- * see below for the original copyright.
- * 2006 - Joerg Dietrich <dietrich_joerg at gmx.de>
- */
-
-/*
- * puff.c
- * Copyright (C) 2002-2004 Mark Adler
- * For conditions of distribution and use, see copyright notice in puff.h
- * version 1.8, 9 Jan 2004
- *
- * puff.c is a simple inflate written to be an unambiguous way to specify the
- * deflate format. It is not written for speed but rather simplicity. As a
- * side benefit, this code might actually be useful when small code is more
- * important than speed, such as bootstrap applications. For typical deflate
- * data, zlib's inflate() is about four times as fast as puff(). zlib's
- * inflate compiles to around 20K on my machine, whereas puff.c compiles to
- * around 4K on my machine (a PowerPC using GNU cc). If the faster decode()
- * function here is used, then puff() is only twice as slow as zlib's
- * inflate().
- *
- * All dynamically allocated memory comes from the stack. The stack required
- * is less than 2K bytes. This code is compatible with 16-bit int's and
- * assumes that long's are at least 32 bits. puff.c uses the short data type,
- * assumed to be 16 bits, for arrays in order to to conserve memory. The code
- * works whether integers are stored big endian or little endian.
- *
- * In the comments below are "Format notes" that describe the inflate process
- * and document some of the less obvious aspects of the format. This source
- * code is meant to supplement RFC 1951, which formally describes the deflate
- * format:
- *
- * http://www.zlib.org/rfc-deflate.html
- */
-
-/*
- * Change history:
- *
- * 1.0 10 Feb 2002 - First version
- * 1.1 17 Feb 2002 - Clarifications of some comments and notes
- * - Update puff() dest and source pointers on negative
- * errors to facilitate debugging deflators
- * - Remove longest from struct huffman -- not needed
- * - Simplify offs[] index in construct()
- * - Add input size and checking, using longjmp() to
- * maintain easy readability
- * - Use short data type for large arrays
- * - Use pointers instead of long to specify source and
- * destination sizes to avoid arbitrary 4 GB limits
- * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!),
- * but leave simple version for readabilty
- * - Make sure invalid distances detected if pointers
- * are 16 bits
- * - Fix fixed codes table error
- * - Provide a scanning mode for determining size of
- * uncompressed data
- * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Jean-loup]
- * - Add a puff.h file for the interface
- * - Add braces in puff() for else do [Jean-loup]
- * - Use indexes instead of pointers for readability
- * 1.4 31 Mar 2002 - Simplify construct() code set check
- * - Fix some comments
- * - Add FIXLCODES #define
- * 1.5 6 Apr 2002 - Minor comment fixes
- * 1.6 7 Aug 2002 - Minor format changes
- * 1.7 3 Mar 2003 - Added test code for distribution
- * - Added zlib-like license
- * 1.8 9 Jan 2004 - Added some comments on no distance codes case
- */
-
-#include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */
-#include "puff.h" /* prototype for puff() */
-
-#define local static /* for local function definitions */
-
-/*
- * Maximums for allocations and loops. It is not useful to change these --
- * they are fixed by the deflate format.
- */
-#define MAXBITS 15 /* maximum bits in a code */
-#define MAXLCODES 286 /* maximum number of literal/length codes */
-#define MAXDCODES 30 /* maximum number of distance codes */
-#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */
-#define FIXLCODES 288 /* number of fixed literal/length codes */
-
-/* input and output state */
-struct state {
- /* output state */
- uint8_t *out; /* output buffer */
- uint32_t outlen; /* available space at out */
- uint32_t outcnt; /* bytes written to out so far */
-
- /* input state */
- uint8_t *in; /* input buffer */
- uint32_t inlen; /* available input at in */
- uint32_t incnt; /* bytes read so far */
- int32_t bitbuf; /* bit buffer */
- int32_t bitcnt; /* number of bits in bit buffer */
-
- /* input limit error return state for bits() and decode() */
- jmp_buf env;
-};
-
-/*
- * Return need bits from the input stream. This always leaves less than
- * eight bits in the buffer. bits() works properly for need == 0.
- *
- * Format notes:
- *
- * - Bits are stored in bytes from the least significant bit to the most
- * significant bit. Therefore bits are dropped from the bottom of the bit
- * buffer, using shift right, and new bytes are appended to the top of the
- * bit buffer, using shift left.
- */
-local int32_t bits(struct state *s, int32_t need)
-{
- int32_t val; /* bit accumulator (can use up to 20 bits) */
-
- /* load at least need bits into val */
- val = s->bitbuf;
- while (s->bitcnt < need) {
- if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */
- val |= (int32_t)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */
- s->bitcnt += 8;
- }
-
- /* drop need bits and update buffer, always zero to seven bits left */
- s->bitbuf = (int32_t)(val >> need);
- s->bitcnt -= need;
-
- /* return need bits, zeroing the bits above that */
- return (int32_t)(val & ((1L << need) - 1));
-}
-
-/*
- * Process a stored block.
- *
- * Format notes:
- *
- * - After the two-bit stored block type (00), the stored block length and
- * stored bytes are byte-aligned for fast copying. Therefore any leftover
- * bits in the byte that has the last bit of the type, as many as seven, are
- * discarded. The value of the discarded bits are not defined and should not
- * be checked against any expectation.
- *
- * - The second inverted copy of the stored block length does not have to be
- * checked, but it's probably a good idea to do so anyway.
- *
- * - A stored block can have zero length. This is sometimes used to byte-align
- * subsets of the compressed data for random access or partial recovery.
- */
-local int32_t stored(struct state *s)
-{
- uint32_t len; /* length of stored block */
-
- /* discard leftover bits from current byte (assumes s->bitcnt < 8) */
- s->bitbuf = 0;
- s->bitcnt = 0;
-
- /* get length and check against its one's complement */
- if (s->incnt + 4 > s->inlen) return 2; /* not enough input */
- len = s->in[s->incnt++];
- len |= s->in[s->incnt++] << 8;
- if (s->in[s->incnt++] != (~len & 0xff) ||
- s->in[s->incnt++] != ((~len >> 8) & 0xff))
- return -2; /* didn't match complement! */
-
- /* copy len bytes from in to out */
- if (s->incnt + len > s->inlen) return 2; /* not enough input */
- if (s->out != NULL) {
- if (s->outcnt + len > s->outlen)
- return 1; /* not enough output space */
- while (len--)
- s->out[s->outcnt++] = s->in[s->incnt++];
- }
- else { /* just scanning */
- s->outcnt += len;
- s->incnt += len;
- }
-
- /* done with a valid stored block */
- return 0;
-}
-
-/*
- * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of
- * each length, which for a canonical code are stepped through in order.
- * symbol[] are the symbol values in canonical order, where the number of
- * entries is the sum of the counts in count[]. The decoding process can be
- * seen in the function decode() below.
- */
-struct huffman {
- int16_t *count; /* number of symbols of each length */
- int16_t *symbol; /* canonically ordered symbols */
-};
-
-/*
- * Decode a code from the stream s using huffman table h. Return the symbol or
- * a negative value if there is an error. If all of the lengths are zero, i.e.
- * an empty code, or if the code is incomplete and an invalid code is received,
- * then -9 is returned after reading MAXBITS bits.
- *
- * Format notes:
- *
- * - The codes as stored in the compressed data are bit-reversed relative to
- * a simple integer ordering of codes of the same lengths. Hence below the
- * bits are pulled from the compressed data one at a time and used to
- * build the code value reversed from what is in the stream in order to
- * permit simple integer comparisons for decoding. A table-based decoding
- * scheme (as used in zlib) does not need to do this reversal.
- *
- * - The first code for the shortest length is all zeros. Subsequent codes of
- * the same length are simply integer increments of the previous code. When
- * moving up a length, a zero bit is appended to the code. For a complete
- * code, the last code of the longest length will be all ones.
- *
- * - Incomplete codes are handled by this decoder, since they are permitted
- * in the deflate format. See the format notes for fixed() and dynamic().
- */
-local int32_t decode(struct state *s, struct huffman *h)
-{
- int32_t len; /* current number of bits in code */
- int32_t code; /* len bits being decoded */
- int32_t first; /* first code of length len */
- int32_t count; /* number of codes of length len */
- int32_t index; /* index of first code of length len in symbol table */
- int32_t bitbuf; /* bits from stream */
- int32_t left; /* bits left in next or left to process */
- int16_t *next; /* next number of codes */
-
- bitbuf = s->bitbuf;
- left = s->bitcnt;
- code = first = index = 0;
- len = 1;
- next = h->count + 1;
- while (1) {
- while (left--) {
- code |= bitbuf & 1;
- bitbuf >>= 1;
- count = *next++;
- if (code < first + count) { /* if length len, return symbol */
- s->bitbuf = bitbuf;
- s->bitcnt = (s->bitcnt - len) & 7;
- return h->symbol[index + (code - first)];
- }
- index += count; /* else update for next length */
- first += count;
- first <<= 1;
- code <<= 1;
- len++;
- }
- left = (MAXBITS+1) - len;
- if (left == 0) break;
- if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */
- bitbuf = s->in[s->incnt++];
- if (left > 8) left = 8;
- }
- return -9; /* ran out of codes */
-}
-
-/*
- * Given the list of code lengths length[0..n-1] representing a canonical
- * Huffman code for n symbols, construct the tables required to decode those
- * codes. Those tables are the number of codes of each length, and the symbols
- * sorted by length, retaining their original order within each length. The
- * return value is zero for a complete code set, negative for an over-
- * subscribed code set, and positive for an incomplete code set. The tables
- * can be used if the return value is zero or positive, but they cannot be used
- * if the return value is negative. If the return value is zero, it is not
- * possible for decode() using that table to return an error--any stream of
- * enough bits will resolve to a symbol. If the return value is positive, then
- * it is possible for decode() using that table to return an error for received
- * codes past the end of the incomplete lengths.
- *
- * Not used by decode(), but used for error checking, h->count[0] is the number
- * of the n symbols not in the code. So n - h->count[0] is the number of
- * codes. This is useful for checking for incomplete codes that have more than
- * one symbol, which is an error in a dynamic block.
- *
- * Assumption: for all i in 0..n-1, 0 <= length[i] <= MAXBITS
- * This is assured by the construction of the length arrays in dynamic() and
- * fixed() and is not verified by construct().
- *
- * Format notes:
- *
- * - Permitted and expected examples of incomplete codes are one of the fixed
- * codes and any code with a single symbol which in deflate is coded as one
- * bit instead of zero bits. See the format notes for fixed() and dynamic().
- *
- * - Within a given code length, the symbols are kept in ascending order for
- * the code bits definition.
- */
-local int32_t construct(struct huffman *h, int16_t *length, int32_t n)
-{
- int32_t symbol; /* current symbol when stepping through length[] */
- int32_t len; /* current length when stepping through h->count[] */
- int32_t left; /* number of possible codes left of current length */
- int16_t offs[MAXBITS+1]; /* offsets in symbol table for each length */
-
- /* count number of codes of each length */
- for (len = 0; len <= MAXBITS; len++)
- h->count[len] = 0;
- for (symbol = 0; symbol < n; symbol++)
- (h->count[length[symbol]])++; /* assumes lengths are within bounds */
- if (h->count[0] == n) /* no codes! */
- return 0; /* complete, but decode() will fail */
-
- /* check for an over-subscribed or incomplete set of lengths */
- left = 1; /* one possible code of zero length */
- for (len = 1; len <= MAXBITS; len++) {
- left <<= 1; /* one more bit, double codes left */
- left -= h->count[len]; /* deduct count from possible codes */
- if (left < 0) return left; /* over-subscribed--return negative */
- } /* left > 0 means incomplete */
-
- /* generate offsets into symbol table for each length for sorting */
- offs[1] = 0;
- for (len = 1; len < MAXBITS; len++)
- offs[len + 1] = offs[len] + h->count[len];
-
- /*
- * put symbols in table sorted by length, by symbol order within each
- * length
- */
- for (symbol = 0; symbol < n; symbol++)
- if (length[symbol] != 0)
- h->symbol[offs[length[symbol]]++] = symbol;
-
- /* return zero for complete set, positive for incomplete set */
- return left;
-}
-
-/*
- * Decode literal/length and distance codes until an end-of-block code.
- *
- * Format notes:
- *
- * - Compressed data that is after the block type if fixed or after the code
- * description if dynamic is a combination of literals and length/distance
- * pairs terminated by and end-of-block code. Literals are simply Huffman
- * coded bytes. A length/distance pair is a coded length followed by a
- * coded distance to represent a string that occurs earlier in the
- * uncompressed data that occurs again at the current location.
- *
- * - Literals, lengths, and the end-of-block code are combined into a single
- * code of up to 286 symbols. They are 256 literals (0..255), 29 length
- * symbols (257..285), and the end-of-block symbol (256).
- *
- * - There are 256 possible lengths (3..258), and so 29 symbols are not enough
- * to represent all of those. Lengths 3..10 and 258 are in fact represented
- * by just a length symbol. Lengths 11..257 are represented as a symbol and
- * some number of extra bits that are added as an integer to the base length
- * of the length symbol. The number of extra bits is determined by the base
- * length symbol. These are in the static arrays below, lens[] for the base
- * lengths and lext[] for the corresponding number of extra bits.
- *
- * - The reason that 258 gets its own symbol is that the longest length is used
- * often in highly redundant files. Note that 258 can also be coded as the
- * base value 227 plus the maximum extra value of 31. While a good deflate
- * should never do this, it is not an error, and should be decoded properly.
- *
- * - If a length is decoded, including its extra bits if any, then it is
- * followed a distance code. There are up to 30 distance symbols. Again
- * there are many more possible distances (1..32768), so extra bits are added
- * to a base value represented by the symbol. The distances 1..4 get their
- * own symbol, but the rest require extra bits. The base distances and
- * corresponding number of extra bits are below in the static arrays dist[]
- * and dext[].
- *
- * - Literal bytes are simply written to the output. A length/distance pair is
- * an instruction to copy previously uncompressed bytes to the output. The
- * copy is from distance bytes back in the output stream, copying for length
- * bytes.
- *
- * - Distances pointing before the beginning of the output data are not
- * permitted.
- *
- * - Overlapped copies, where the length is greater than the distance, are
- * allowed and common. For example, a distance of one and a length of 258
- * simply copies the last byte 258 times. A distance of four and a length of
- * twelve copies the last four bytes three times. A simple forward copy
- * ignoring whether the length is greater than the distance or not implements
- * this correctly. You should not use memcpy() since its behavior is not
- * defined for overlapped arrays. You should not use memmove() or bcopy()
- * since though their behavior -is- defined for overlapping arrays, it is
- * defined to do the wrong thing in this case.
- */
-local int32_t codes(struct state *s,
- struct huffman *lencode,
- struct huffman *distcode)
-{
- int32_t symbol; /* decoded symbol */
- int32_t len; /* length for copy */
- uint32_t dist; /* distance for copy */
- static const int16_t lens[29] = { /* Size base for length codes 257..285 */
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
- 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
- static const int16_t lext[29] = { /* Extra bits for length codes 257..285 */
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
- 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
- static const int16_t dists[30] = { /* Offset base for distance codes 0..29 */
- 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
- 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
- 8193, 12289, 16385, 24577};
- static const int16_t dext[30] = { /* Extra bits for distance codes 0..29 */
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
- 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
- 12, 12, 13, 13};
-
- /* decode literals and length/distance pairs */
- do {
- symbol = decode(s, lencode);
- if (symbol < 0) return symbol; /* invalid symbol */
- if (symbol < 256) { /* literal: symbol is the byte */
- /* write out the literal */
- if (s->out != NULL) {
- if (s->outcnt == s->outlen) return 1;
- s->out[s->outcnt] = symbol;
- }
- s->outcnt++;
- }
- else if (symbol > 256) { /* length */
- /* get and compute length */
- symbol -= 257;
- if (symbol >= 29) return -9; /* invalid fixed code */
- len = lens[symbol] + bits(s, lext[symbol]);
-
- /* get and check distance */
- symbol = decode(s, distcode);
- if (symbol < 0) return symbol; /* invalid symbol */
- dist = dists[symbol] + bits(s, dext[symbol]);
- if (dist > s->outcnt)
- return -10; /* distance too far back */
-
- /* copy length bytes from distance bytes back */
- if (s->out != NULL) {
- if (s->outcnt + len > s->outlen) return 1;
- while (len--) {
- s->out[s->outcnt] = s->out[s->outcnt - dist];
- s->outcnt++;
- }
- }
- else
- s->outcnt += len;
- }
- } while (symbol != 256); /* end of block symbol */
-
- /* done with a valid fixed or dynamic block */
- return 0;
-}
-
-/*
- * Process a fixed codes block.
- *
- * Format notes:
- *
- * - This block type can be useful for compressing small amounts of data for
- * which the size of the code descriptions in a dynamic block exceeds the
- * benefit of custom codes for that block. For fixed codes, no bits are
- * spent on code descriptions. Instead the code lengths for literal/length
- * codes and distance codes are fixed. The specific lengths for each symbol
- * can be seen in the "for" loops below.
- *
- * - The literal/length code is complete, but has two symbols that are invalid
- * and should result in an error if received. This cannot be implemented
- * simply as an incomplete code since those two symbols are in the "middle"
- * of the code. They are eight bits long and the longest literal/length\
- * code is nine bits. Therefore the code must be constructed with those
- * symbols, and the invalid symbols must be detected after decoding.
- *
- * - The fixed distance codes also have two invalid symbols that should result
- * in an error if received. Since all of the distance codes are the same
- * length, this can be implemented as an incomplete code. Then the invalid
- * codes are detected while decoding.
- */
-local int32_t fixed(struct state *s)
-{
- static int32_t virgin = 1;
- static int16_t lencnt[MAXBITS+1], lensym[FIXLCODES];
- static int16_t distcnt[MAXBITS+1], distsym[MAXDCODES];
- static struct huffman lencode = {lencnt, lensym};
- static struct huffman distcode = {distcnt, distsym};
-
- /* build fixed huffman tables if first call (may not be thread safe) */
- if (virgin) {
- int32_t symbol;
- int16_t lengths[FIXLCODES];
-
- /* literal/length table */
- for (symbol = 0; symbol < 144; symbol++)
- lengths[symbol] = 8;
- for (; symbol < 256; symbol++)
- lengths[symbol] = 9;
- for (; symbol < 280; symbol++)
- lengths[symbol] = 7;
- for (; symbol < FIXLCODES; symbol++)
- lengths[symbol] = 8;
- construct(&lencode, lengths, FIXLCODES);
-
- /* distance table */
- for (symbol = 0; symbol < MAXDCODES; symbol++)
- lengths[symbol] = 5;
- construct(&distcode, lengths, MAXDCODES);
-
- /* do this just once */
- virgin = 0;
- }
-
- /* decode data until end-of-block code */
- return codes(s, &lencode, &distcode);
-}
-
-/*
- * Process a dynamic codes block.
- *
- * Format notes:
- *
- * - A dynamic block starts with a description of the literal/length and
- * distance codes for that block. New dynamic blocks allow the compressor to
- * rapidly adapt to changing data with new codes optimized for that data.
- *
- * - The codes used by the deflate format are "canonical", which means that
- * the actual bits of the codes are generated in an unambiguous way simply
- * from the number of bits in each code. Therefore the code descriptions
- * are simply a list of code lengths for each symbol.
- *
- * - The code lengths are stored in order for the symbols, so lengths are
- * provided for each of the literal/length symbols, and for each of the
- * distance symbols.
- *
- * - If a symbol is not used in the block, this is represented by a zero as
- * as the code length. This does not mean a zero-length code, but rather
- * that no code should be created for this symbol. There is no way in the
- * deflate format to represent a zero-length code.
- *
- * - The maximum number of bits in a code is 15, so the possible lengths for
- * any code are 1..15.
- *
- * - The fact that a length of zero is not permitted for a code has an
- * interesting consequence. Normally if only one symbol is used for a given
- * code, then in fact that code could be represented with zero bits. However
- * in deflate, that code has to be at least one bit. So for example, if
- * only a single distance base symbol appears in a block, then it will be
- * represented by a single code of length one, in particular one 0 bit. This
- * is an incomplete code, since if a 1 bit is received, it has no meaning,
- * and should result in an error. So incomplete distance codes of one symbol
- * should be permitted, and the receipt of invalid codes should be handled.
- *
- * - It is also possible to have a single literal/length code, but that code
- * must be the end-of-block code, since every dynamic block has one. This
- * is not the most efficient way to create an empty block (an empty fixed
- * block is fewer bits), but it is allowed by the format. So incomplete
- * literal/length codes of one symbol should also be permitted.
- *
- * - If there are only literal codes and no lengths, then there are no distance
- * codes. This is represented by one distance code with zero bits.
- *
- * - The list of up to 286 length/literal lengths and up to 30 distance lengths
- * are themselves compressed using Huffman codes and run-length encoding. In
- * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means
- * that length, and the symbols 16, 17, and 18 are run-length instructions.
- * Each of 16, 17, and 18 are follwed by extra bits to define the length of
- * the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10
- * zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols
- * are common, hence the special coding for zero lengths.
- *
- * - The symbols for 0..18 are Huffman coded, and so that code must be
- * described first. This is simply a sequence of up to 19 three-bit values
- * representing no code (0) or the code length for that symbol (1..7).
- *
- * - A dynamic block starts with three fixed-size counts from which is computed
- * the number of literal/length code lengths, the number of distance code
- * lengths, and the number of code length code lengths (ok, you come up with
- * a better name!) in the code descriptions. For the literal/length and
- * distance codes, lengths after those provided are considered zero, i.e. no
- * code. The code length code lengths are received in a permuted order (see
- * the order[] array below) to make a short code length code length list more
- * likely. As it turns out, very short and very long codes are less likely
- * to be seen in a dynamic code description, hence what may appear initially
- * to be a peculiar ordering.
- *
- * - Given the number of literal/length code lengths (nlen) and distance code
- * lengths (ndist), then they are treated as one long list of nlen + ndist
- * code lengths. Therefore run-length coding can and often does cross the
- * boundary between the two sets of lengths.
- *
- * - So to summarize, the code description at the start of a dynamic block is
- * three counts for the number of code lengths for the literal/length codes,
- * the distance codes, and the code length codes. This is followed by the
- * code length code lengths, three bits each. This is used to construct the
- * code length code which is used to read the remainder of the lengths. Then
- * the literal/length code lengths and distance lengths are read as a single
- * set of lengths using the code length codes. Codes are constructed from
- * the resulting two sets of lengths, and then finally you can start
- * decoding actual compressed data in the block.
- *
- * - For reference, a "typical" size for the code description in a dynamic
- * block is around 80 bytes.
- */
-local int32_t dynamic(struct state *s)
-{
- int32_t nlen, ndist, ncode; /* number of lengths in descriptor */
- int32_t index; /* index of lengths[] */
- int32_t err; /* construct() return value */
- int16_t lengths[MAXCODES]; /* descriptor code lengths */
- int16_t lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */
- int16_t distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */
- struct huffman lencode = {lencnt, lensym}; /* length code */
- struct huffman distcode = {distcnt, distsym}; /* distance code */
- static const int16_t order[19] = /* permutation of code length codes */
- {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-
- /* get number of lengths in each table, check lengths */
- nlen = bits(s, 5) + 257;
- ndist = bits(s, 5) + 1;
- ncode = bits(s, 4) + 4;
- if (nlen > MAXLCODES || ndist > MAXDCODES)
- return -3; /* bad counts */
-
- /* read code length code lengths (really), missing lengths are zero */
- for (index = 0; index < ncode; index++)
- lengths[order[index]] = bits(s, 3);
- for (; index < 19; index++)
- lengths[order[index]] = 0;
-
- /* build huffman table for code lengths codes (use lencode temporarily) */
- err = construct(&lencode, lengths, 19);
- if (err != 0) return -4; /* require complete code set here */
-
- /* read length/literal and distance code length tables */
- index = 0;
- while (index < nlen + ndist) {
- int32_t symbol; /* decoded value */
- int32_t len; /* last length to repeat */
-
- symbol = decode(s, &lencode);
- if (symbol < 16) /* length in 0..15 */
- lengths[index++] = symbol;
- else { /* repeat instruction */
- len = 0; /* assume repeating zeros */
- if (symbol == 16) { /* repeat last length 3..6 times */
- if (index == 0) return -5; /* no last length! */
- len = lengths[index - 1]; /* last length */
- symbol = 3 + bits(s, 2);
- }
- else if (symbol == 17) /* repeat zero 3..10 times */
- symbol = 3 + bits(s, 3);
- else /* == 18, repeat zero 11..138 times */
- symbol = 11 + bits(s, 7);
- if (index + symbol > nlen + ndist)
- return -6; /* too many lengths! */
- while (symbol--) /* repeat last or zero symbol times */
- lengths[index++] = len;
- }
- }
-
- /* build huffman table for literal/length codes */
- err = construct(&lencode, lengths, nlen);
- if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1))
- return -7; /* only allow incomplete codes if just one code */
-
- /* build huffman table for distance codes */
- err = construct(&distcode, lengths + nlen, ndist);
- if (err < 0 || (err > 0 && ndist - distcode.count[0] != 1))
- return -8; /* only allow incomplete codes if just one code */
-
- /* decode data until end-of-block code */
- return codes(s, &lencode, &distcode);
-}
-
-/*
- * Inflate source to dest. On return, destlen and sourcelen are updated to the
- * size of the uncompressed data and the size of the deflate data respectively.
- * On success, the return value of puff() is zero. If there is an error in the
- * source data, i.e. it is not in the deflate format, then a negative value is
- * returned. If there is not enough input available or there is not enough
- * output space, then a positive error is returned. In that case, destlen and
- * sourcelen are not updated to facilitate retrying from the beginning with the
- * provision of more input data or more output space. In the case of invalid
- * inflate data (a negative error), the dest and source pointers are updated to
- * facilitate the debugging of deflators.
- *
- * puff() also has a mode to determine the size of the uncompressed output with
- * no output written. For this dest must be (uint8_t *)0. In this case,
- * the input value of *destlen is ignored, and on return *destlen is set to the
- * size of the uncompressed output.
- *
- * The return codes are:
- *
- * 2: available inflate data did not terminate
- * 1: output space exhausted before completing inflate
- * 0: successful inflate
- * -1: invalid block type (type == 3)
- * -2: stored block length did not match one's complement
- * -3: dynamic block code description: too many length or distance codes
- * -4: dynamic block code description: code lengths codes incomplete
- * -5: dynamic block code description: repeat lengths with no first length
- * -6: dynamic block code description: repeat more than specified lengths
- * -7: dynamic block code description: invalid literal/length code lengths
- * -8: dynamic block code description: invalid distance code lengths
- * -9: invalid literal/length or distance code in fixed or dynamic block
- * -10: distance is too far back in fixed or dynamic block
- *
- * Format notes:
- *
- * - Three bits are read for each block to determine the kind of block and
- * whether or not it is the last block. Then the block is decoded and the
- * process repeated if it was not the last block.
- *
- * - The leftover bits in the last byte of the deflate data after the last
- * block (if it was a fixed or dynamic block) are undefined and have no
- * expected values to check.
- */
-int32_t puff(uint8_t *dest, /* pointer to destination pointer */
- uint32_t *destlen, /* amount of output space */
- uint8_t *source, /* pointer to source data pointer */
- uint32_t *sourcelen) /* amount of input available */
-{
- struct state s; /* input/output state */
- int32_t last, type; /* block information */
- int32_t err; /* return value */
-
- /* initialize output state */
- s.out = dest;
- s.outlen = *destlen; /* ignored if dest is NULL */
- s.outcnt = 0;
-
- /* initialize input state */
- s.in = source;
- s.inlen = *sourcelen;
- s.incnt = 0;
- s.bitbuf = 0;
- s.bitcnt = 0;
-
- /* return if bits() or decode() tries to read past available input */
- if (setjmp(s.env) != 0) /* if came back here via longjmp() */
- err = 2; /* then skip do-loop, return error */
- else {
- /* process blocks until last block or error */
- do {
- last = bits(&s, 1); /* one if last block */
- type = bits(&s, 2); /* block type 0..3 */
- err = type == 0 ? stored(&s) :
- (type == 1 ? fixed(&s) :
- (type == 2 ? dynamic(&s) :
- -1)); /* type == 3, invalid */
- if (err != 0) break; /* return with error */
- } while (!last);
- }
-
- /* update the lengths and return */
- if (err <= 0) {
- *destlen = s.outcnt;
- *sourcelen = s.incnt;
- }
- return err;
-}
diff --git a/engine/code/qcommon/puff.h b/engine/code/qcommon/puff.h
deleted file mode 100644
index 14070f6..0000000
--- a/engine/code/qcommon/puff.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * This is a modified version of Mark Adlers work,
- * see below for the original copyright.
- * 2006 - Joerg Dietrich <dietrich_joerg at gmx.de>
- */
-
-/* puff.h
- Copyright (C) 2002, 2003 Mark Adler, all rights reserved
- version 1.7, 3 Mar 2002
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the author be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-
- Mark Adler madler at alumni.caltech.edu
- */
-
-#ifndef __PUFF_H
-#define __PUFF_H
-
-#include "q_shared.h" /* for definitions of the <stdint.h> types */
-
-/*
- * See puff.c for purpose and usage.
- */
-int32_t puff(uint8_t *dest, /* pointer to destination pointer */
- uint32_t *destlen, /* amount of output space */
- uint8_t *source, /* pointer to source data pointer */
- uint32_t *sourcelen); /* amount of input available */
-
-#endif // __PUFF_H
diff --git a/engine/code/qcommon/q_math.c b/engine/code/qcommon/q_math.c
deleted file mode 100644
index d2e0187..0000000
--- a/engine/code/qcommon/q_math.c
+++ /dev/null
@@ -1,1009 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// q_math.c -- stateless support routines that are included in each code module
-
-// Some of the vector functions are static inline in q_shared.h. q3asm
-// doesn't understand static functions though, so we only want them in
-// one file. That's what this is about.
-#ifdef Q3_VM
-#define __Q3_VM_MATH
-#endif
-
-#include "q_shared.h"
-
-vec3_t vec3_origin = {0,0,0};
-vec3_t axisDefault[3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
-
-
-vec4_t colorBlack = {0, 0, 0, 1};
-vec4_t colorRed = {1, 0, 0, 1};
-vec4_t colorGreen = {0, 1, 0, 1};
-vec4_t colorBlue = {0, 0, 1, 1};
-vec4_t colorYellow = {1, 1, 0, 1};
-vec4_t colorMagenta= {1, 0, 1, 1};
-vec4_t colorCyan = {0, 1, 1, 1};
-vec4_t colorWhite = {1, 1, 1, 1};
-vec4_t colorLtGrey = {0.75, 0.75, 0.75, 1};
-vec4_t colorMdGrey = {0.5, 0.5, 0.5, 1};
-vec4_t colorDkGrey = {0.25, 0.25, 0.25, 1};
-
-vec4_t g_color_table[8] =
- {
- {0.0, 0.0, 0.0, 1.0},
- {1.0, 0.0, 0.0, 1.0},
- {0.0, 1.0, 0.0, 1.0},
- {1.0, 1.0, 0.0, 1.0},
- {0.0, 0.0, 1.0, 1.0},
- {0.0, 1.0, 1.0, 1.0},
- {1.0, 0.0, 1.0, 1.0},
- {1.0, 1.0, 1.0, 1.0},
- };
-
-
-vec3_t bytedirs[NUMVERTEXNORMALS] =
-{
-{-0.525731f, 0.000000f, 0.850651f}, {-0.442863f, 0.238856f, 0.864188f},
-{-0.295242f, 0.000000f, 0.955423f}, {-0.309017f, 0.500000f, 0.809017f},
-{-0.162460f, 0.262866f, 0.951056f}, {0.000000f, 0.000000f, 1.000000f},
-{0.000000f, 0.850651f, 0.525731f}, {-0.147621f, 0.716567f, 0.681718f},
-{0.147621f, 0.716567f, 0.681718f}, {0.000000f, 0.525731f, 0.850651f},
-{0.309017f, 0.500000f, 0.809017f}, {0.525731f, 0.000000f, 0.850651f},
-{0.295242f, 0.000000f, 0.955423f}, {0.442863f, 0.238856f, 0.864188f},
-{0.162460f, 0.262866f, 0.951056f}, {-0.681718f, 0.147621f, 0.716567f},
-{-0.809017f, 0.309017f, 0.500000f},{-0.587785f, 0.425325f, 0.688191f},
-{-0.850651f, 0.525731f, 0.000000f},{-0.864188f, 0.442863f, 0.238856f},
-{-0.716567f, 0.681718f, 0.147621f},{-0.688191f, 0.587785f, 0.425325f},
-{-0.500000f, 0.809017f, 0.309017f}, {-0.238856f, 0.864188f, 0.442863f},
-{-0.425325f, 0.688191f, 0.587785f}, {-0.716567f, 0.681718f, -0.147621f},
-{-0.500000f, 0.809017f, -0.309017f}, {-0.525731f, 0.850651f, 0.000000f},
-{0.000000f, 0.850651f, -0.525731f}, {-0.238856f, 0.864188f, -0.442863f},
-{0.000000f, 0.955423f, -0.295242f}, {-0.262866f, 0.951056f, -0.162460f},
-{0.000000f, 1.000000f, 0.000000f}, {0.000000f, 0.955423f, 0.295242f},
-{-0.262866f, 0.951056f, 0.162460f}, {0.238856f, 0.864188f, 0.442863f},
-{0.262866f, 0.951056f, 0.162460f}, {0.500000f, 0.809017f, 0.309017f},
-{0.238856f, 0.864188f, -0.442863f},{0.262866f, 0.951056f, -0.162460f},
-{0.500000f, 0.809017f, -0.309017f},{0.850651f, 0.525731f, 0.000000f},
-{0.716567f, 0.681718f, 0.147621f}, {0.716567f, 0.681718f, -0.147621f},
-{0.525731f, 0.850651f, 0.000000f}, {0.425325f, 0.688191f, 0.587785f},
-{0.864188f, 0.442863f, 0.238856f}, {0.688191f, 0.587785f, 0.425325f},
-{0.809017f, 0.309017f, 0.500000f}, {0.681718f, 0.147621f, 0.716567f},
-{0.587785f, 0.425325f, 0.688191f}, {0.955423f, 0.295242f, 0.000000f},
-{1.000000f, 0.000000f, 0.000000f}, {0.951056f, 0.162460f, 0.262866f},
-{0.850651f, -0.525731f, 0.000000f},{0.955423f, -0.295242f, 0.000000f},
-{0.864188f, -0.442863f, 0.238856f}, {0.951056f, -0.162460f, 0.262866f},
-{0.809017f, -0.309017f, 0.500000f}, {0.681718f, -0.147621f, 0.716567f},
-{0.850651f, 0.000000f, 0.525731f}, {0.864188f, 0.442863f, -0.238856f},
-{0.809017f, 0.309017f, -0.500000f}, {0.951056f, 0.162460f, -0.262866f},
-{0.525731f, 0.000000f, -0.850651f}, {0.681718f, 0.147621f, -0.716567f},
-{0.681718f, -0.147621f, -0.716567f},{0.850651f, 0.000000f, -0.525731f},
-{0.809017f, -0.309017f, -0.500000f}, {0.864188f, -0.442863f, -0.238856f},
-{0.951056f, -0.162460f, -0.262866f}, {0.147621f, 0.716567f, -0.681718f},
-{0.309017f, 0.500000f, -0.809017f}, {0.425325f, 0.688191f, -0.587785f},
-{0.442863f, 0.238856f, -0.864188f}, {0.587785f, 0.425325f, -0.688191f},
-{0.688191f, 0.587785f, -0.425325f}, {-0.147621f, 0.716567f, -0.681718f},
-{-0.309017f, 0.500000f, -0.809017f}, {0.000000f, 0.525731f, -0.850651f},
-{-0.525731f, 0.000000f, -0.850651f}, {-0.442863f, 0.238856f, -0.864188f},
-{-0.295242f, 0.000000f, -0.955423f}, {-0.162460f, 0.262866f, -0.951056f},
-{0.000000f, 0.000000f, -1.000000f}, {0.295242f, 0.000000f, -0.955423f},
-{0.162460f, 0.262866f, -0.951056f}, {-0.442863f, -0.238856f, -0.864188f},
-{-0.309017f, -0.500000f, -0.809017f}, {-0.162460f, -0.262866f, -0.951056f},
-{0.000000f, -0.850651f, -0.525731f}, {-0.147621f, -0.716567f, -0.681718f},
-{0.147621f, -0.716567f, -0.681718f}, {0.000000f, -0.525731f, -0.850651f},
-{0.309017f, -0.500000f, -0.809017f}, {0.442863f, -0.238856f, -0.864188f},
-{0.162460f, -0.262866f, -0.951056f}, {0.238856f, -0.864188f, -0.442863f},
-{0.500000f, -0.809017f, -0.309017f}, {0.425325f, -0.688191f, -0.587785f},
-{0.716567f, -0.681718f, -0.147621f}, {0.688191f, -0.587785f, -0.425325f},
-{0.587785f, -0.425325f, -0.688191f}, {0.000000f, -0.955423f, -0.295242f},
-{0.000000f, -1.000000f, 0.000000f}, {0.262866f, -0.951056f, -0.162460f},
-{0.000000f, -0.850651f, 0.525731f}, {0.000000f, -0.955423f, 0.295242f},
-{0.238856f, -0.864188f, 0.442863f}, {0.262866f, -0.951056f, 0.162460f},
-{0.500000f, -0.809017f, 0.309017f}, {0.716567f, -0.681718f, 0.147621f},
-{0.525731f, -0.850651f, 0.000000f}, {-0.238856f, -0.864188f, -0.442863f},
-{-0.500000f, -0.809017f, -0.309017f}, {-0.262866f, -0.951056f, -0.162460f},
-{-0.850651f, -0.525731f, 0.000000f}, {-0.716567f, -0.681718f, -0.147621f},
-{-0.716567f, -0.681718f, 0.147621f}, {-0.525731f, -0.850651f, 0.000000f},
-{-0.500000f, -0.809017f, 0.309017f}, {-0.238856f, -0.864188f, 0.442863f},
-{-0.262866f, -0.951056f, 0.162460f}, {-0.864188f, -0.442863f, 0.238856f},
-{-0.809017f, -0.309017f, 0.500000f}, {-0.688191f, -0.587785f, 0.425325f},
-{-0.681718f, -0.147621f, 0.716567f}, {-0.442863f, -0.238856f, 0.864188f},
-{-0.587785f, -0.425325f, 0.688191f}, {-0.309017f, -0.500000f, 0.809017f},
-{-0.147621f, -0.716567f, 0.681718f}, {-0.425325f, -0.688191f, 0.587785f},
-{-0.162460f, -0.262866f, 0.951056f}, {0.442863f, -0.238856f, 0.864188f},
-{0.162460f, -0.262866f, 0.951056f}, {0.309017f, -0.500000f, 0.809017f},
-{0.147621f, -0.716567f, 0.681718f}, {0.000000f, -0.525731f, 0.850651f},
-{0.425325f, -0.688191f, 0.587785f}, {0.587785f, -0.425325f, 0.688191f},
-{0.688191f, -0.587785f, 0.425325f}, {-0.955423f, 0.295242f, 0.000000f},
-{-0.951056f, 0.162460f, 0.262866f}, {-1.000000f, 0.000000f, 0.000000f},
-{-0.850651f, 0.000000f, 0.525731f}, {-0.955423f, -0.295242f, 0.000000f},
-{-0.951056f, -0.162460f, 0.262866f}, {-0.864188f, 0.442863f, -0.238856f},
-{-0.951056f, 0.162460f, -0.262866f}, {-0.809017f, 0.309017f, -0.500000f},
-{-0.864188f, -0.442863f, -0.238856f}, {-0.951056f, -0.162460f, -0.262866f},
-{-0.809017f, -0.309017f, -0.500000f}, {-0.681718f, 0.147621f, -0.716567f},
-{-0.681718f, -0.147621f, -0.716567f}, {-0.850651f, 0.000000f, -0.525731f},
-{-0.688191f, 0.587785f, -0.425325f}, {-0.587785f, 0.425325f, -0.688191f},
-{-0.425325f, 0.688191f, -0.587785f}, {-0.425325f, -0.688191f, -0.587785f},
-{-0.587785f, -0.425325f, -0.688191f}, {-0.688191f, -0.587785f, -0.425325f}
-};
-
-//==============================================================
-
-int Q_rand( int *seed ) {
- *seed = (69069 * *seed + 1);
- return *seed;
-}
-
-float Q_random( int *seed ) {
- return ( Q_rand( seed ) & 0xffff ) / (float)0x10000;
-}
-
-float Q_crandom( int *seed ) {
- return 2.0 * ( Q_random( seed ) - 0.5 );
-}
-
-//=======================================================
-
-signed char ClampChar( int i ) {
- if ( i < -128 ) {
- return -128;
- }
- if ( i > 127 ) {
- return 127;
- }
- return i;
-}
-
-signed short ClampShort( int i ) {
- if ( i < -32768 ) {
- return -32768;
- }
- if ( i > 0x7fff ) {
- return 0x7fff;
- }
- return i;
-}
-
-
-// this isn't a real cheap function to call!
-int DirToByte( vec3_t dir ) {
- int i, best;
- float d, bestd;
-
- if ( !dir ) {
- return 0;
- }
-
- bestd = 0;
- best = 0;
- for (i=0 ; i<NUMVERTEXNORMALS ; i++)
- {
- d = DotProduct (dir, bytedirs[i]);
- if (d > bestd)
- {
- bestd = d;
- best = i;
- }
- }
-
- return best;
-}
-
-void ByteToDir( int b, vec3_t dir ) {
- if ( b < 0 || b >= NUMVERTEXNORMALS ) {
- VectorCopy( vec3_origin, dir );
- return;
- }
- VectorCopy (bytedirs[b], dir);
-}
-
-
-unsigned ColorBytes3 (float r, float g, float b) {
- unsigned i;
-
- ( (byte *)&i )[0] = r * 255;
- ( (byte *)&i )[1] = g * 255;
- ( (byte *)&i )[2] = b * 255;
-
- return i;
-}
-
-unsigned ColorBytes4 (float r, float g, float b, float a) {
- unsigned i;
-
- ( (byte *)&i )[0] = r * 255;
- ( (byte *)&i )[1] = g * 255;
- ( (byte *)&i )[2] = b * 255;
- ( (byte *)&i )[3] = a * 255;
-
- return i;
-}
-
-float NormalizeColor( const vec3_t in, vec3_t out ) {
- float max;
-
- max = in[0];
- if ( in[1] > max ) {
- max = in[1];
- }
- if ( in[2] > max ) {
- max = in[2];
- }
-
- if ( !max ) {
- VectorClear( out );
- } else {
- out[0] = in[0] / max;
- out[1] = in[1] / max;
- out[2] = in[2] / max;
- }
- return max;
-}
-
-
-/*
-=====================
-PlaneFromPoints
-
-Returns false if the triangle is degenrate.
-The normal will point out of the clock for clockwise ordered points
-=====================
-*/
-qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ) {
- vec3_t d1, d2;
-
- VectorSubtract( b, a, d1 );
- VectorSubtract( c, a, d2 );
- CrossProduct( d2, d1, plane );
- if ( VectorNormalize( plane ) == 0 ) {
- return qfalse;
- }
-
- plane[3] = DotProduct( a, plane );
- return qtrue;
-}
-
-/*
-===============
-RotatePointAroundVector
-
-This is not implemented very well...
-===============
-*/
-void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point,
- float degrees ) {
- float m[3][3];
- float im[3][3];
- float zrot[3][3];
- float tmpmat[3][3];
- float rot[3][3];
- int i;
- vec3_t vr, vup, vf;
- float rad;
-
- vf[0] = dir[0];
- vf[1] = dir[1];
- vf[2] = dir[2];
-
- PerpendicularVector( vr, dir );
- CrossProduct( vr, vf, vup );
-
- m[0][0] = vr[0];
- m[1][0] = vr[1];
- m[2][0] = vr[2];
-
- m[0][1] = vup[0];
- m[1][1] = vup[1];
- m[2][1] = vup[2];
-
- m[0][2] = vf[0];
- m[1][2] = vf[1];
- m[2][2] = vf[2];
-
- memcpy( im, m, sizeof( im ) );
-
- im[0][1] = m[1][0];
- im[0][2] = m[2][0];
- im[1][0] = m[0][1];
- im[1][2] = m[2][1];
- im[2][0] = m[0][2];
- im[2][1] = m[1][2];
-
- memset( zrot, 0, sizeof( zrot ) );
- zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;
-
- rad = DEG2RAD( degrees );
- zrot[0][0] = cos( rad );
- zrot[0][1] = sin( rad );
- zrot[1][0] = -sin( rad );
- zrot[1][1] = cos( rad );
-
- MatrixMultiply( m, zrot, tmpmat );
- MatrixMultiply( tmpmat, im, rot );
-
- for ( i = 0; i < 3; i++ ) {
- dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
- }
-}
-
-/*
-===============
-RotateAroundDirection
-===============
-*/
-void RotateAroundDirection( vec3_t axis[3], float yaw ) {
-
- // create an arbitrary axis[1]
- PerpendicularVector( axis[1], axis[0] );
-
- // rotate it around axis[0] by yaw
- if ( yaw ) {
- vec3_t temp;
-
- VectorCopy( axis[1], temp );
- RotatePointAroundVector( axis[1], axis[0], temp, yaw );
- }
-
- // cross to get axis[2]
- CrossProduct( axis[0], axis[1], axis[2] );
-}
-
-
-
-void vectoangles( const vec3_t value1, vec3_t angles ) {
- float forward;
- float yaw, pitch;
-
- if ( value1[1] == 0 && value1[0] == 0 ) {
- yaw = 0;
- if ( value1[2] > 0 ) {
- pitch = 90;
- }
- else {
- pitch = 270;
- }
- }
- else {
- if ( value1[0] ) {
- yaw = ( atan2 ( value1[1], value1[0] ) * 180 / M_PI );
- }
- else if ( value1[1] > 0 ) {
- yaw = 90;
- }
- else {
- yaw = 270;
- }
- if ( yaw < 0 ) {
- yaw += 360;
- }
-
- forward = sqrt ( value1[0]*value1[0] + value1[1]*value1[1] );
- pitch = ( atan2(value1[2], forward) * 180 / M_PI );
- if ( pitch < 0 ) {
- pitch += 360;
- }
- }
-
- angles[PITCH] = -pitch;
- angles[YAW] = yaw;
- angles[ROLL] = 0;
-}
-
-
-/*
-=================
-AnglesToAxis
-=================
-*/
-void AnglesToAxis( const vec3_t angles, vec3_t axis[3] ) {
- vec3_t right;
-
- // angle vectors returns "right" instead of "y axis"
- AngleVectors( angles, axis[0], right, axis[2] );
- VectorSubtract( vec3_origin, right, axis[1] );
-}
-
-void AxisClear( vec3_t axis[3] ) {
- axis[0][0] = 1;
- axis[0][1] = 0;
- axis[0][2] = 0;
- axis[1][0] = 0;
- axis[1][1] = 1;
- axis[1][2] = 0;
- axis[2][0] = 0;
- axis[2][1] = 0;
- axis[2][2] = 1;
-}
-
-void AxisCopy( vec3_t in[3], vec3_t out[3] ) {
- VectorCopy( in[0], out[0] );
- VectorCopy( in[1], out[1] );
- VectorCopy( in[2], out[2] );
-}
-
-void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )
-{
- float d;
- vec3_t n;
- float inv_denom;
-
- inv_denom = DotProduct( normal, normal );
-#ifndef Q3_VM
- assert( Q_fabs(inv_denom) != 0.0f ); // zero vectors get here
-#endif
- inv_denom = 1.0f / inv_denom;
-
- d = DotProduct( normal, p ) * inv_denom;
-
- n[0] = normal[0] * inv_denom;
- n[1] = normal[1] * inv_denom;
- n[2] = normal[2] * inv_denom;
-
- dst[0] = p[0] - d * n[0];
- dst[1] = p[1] - d * n[1];
- dst[2] = p[2] - d * n[2];
-}
-
-/*
-================
-MakeNormalVectors
-
-Given a normalized forward vector, create two
-other perpendicular vectors
-================
-*/
-void MakeNormalVectors( const vec3_t forward, vec3_t right, vec3_t up) {
- float d;
-
- // this rotate and negate guarantees a vector
- // not colinear with the original
- right[1] = -forward[0];
- right[2] = forward[1];
- right[0] = forward[2];
-
- d = DotProduct (right, forward);
- VectorMA (right, -d, forward, right);
- VectorNormalize (right);
- CrossProduct (right, forward, up);
-}
-
-
-void VectorRotate( vec3_t in, vec3_t matrix[3], vec3_t out )
-{
- out[0] = DotProduct( in, matrix[0] );
- out[1] = DotProduct( in, matrix[1] );
- out[2] = DotProduct( in, matrix[2] );
-}
-
-//============================================================================
-
-#if !idppc
-/*
-** float q_rsqrt( float number )
-*/
-float Q_rsqrt( float number )
-{
- floatint_t t;
- float x2, y;
- const float threehalfs = 1.5F;
-
- x2 = number * 0.5F;
- t.f = number;
- t.i = 0x5f3759df - ( t.i >> 1 ); // what the fuck?
- y = t.f;
- y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
-// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
-
- return y;
-}
-
-float Q_fabs( float f ) {
- floatint_t fi;
- fi.f = f;
- fi.i &= 0x7FFFFFFF;
- return fi.f;
-}
-#endif
-
-//============================================================
-
-/*
-===============
-LerpAngle
-
-===============
-*/
-float LerpAngle (float from, float to, float frac) {
- float a;
-
- if ( to - from > 180 ) {
- to -= 360;
- }
- if ( to - from < -180 ) {
- to += 360;
- }
- a = from + frac * (to - from);
-
- return a;
-}
-
-
-/*
-=================
-AngleSubtract
-
-Always returns a value from -180 to 180
-=================
-*/
-float AngleSubtract( float a1, float a2 ) {
- float a;
-
- a = a1 - a2;
- while ( a > 180 ) {
- a -= 360;
- }
- while ( a < -180 ) {
- a += 360;
- }
- return a;
-}
-
-
-void AnglesSubtract( vec3_t v1, vec3_t v2, vec3_t v3 ) {
- v3[0] = AngleSubtract( v1[0], v2[0] );
- v3[1] = AngleSubtract( v1[1], v2[1] );
- v3[2] = AngleSubtract( v1[2], v2[2] );
-}
-
-
-float AngleMod(float a) {
- a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535);
- return a;
-}
-
-
-/*
-=================
-AngleNormalize360
-
-returns angle normalized to the range [0 <= angle < 360]
-=================
-*/
-float AngleNormalize360 ( float angle ) {
- return (360.0 / 65536) * ((int)(angle * (65536 / 360.0)) & 65535);
-}
-
-
-/*
-=================
-AngleNormalize180
-
-returns angle normalized to the range [-180 < angle <= 180]
-=================
-*/
-float AngleNormalize180 ( float angle ) {
- angle = AngleNormalize360( angle );
- if ( angle > 180.0 ) {
- angle -= 360.0;
- }
- return angle;
-}
-
-
-/*
-=================
-AngleDelta
-
-returns the normalized delta from angle1 to angle2
-=================
-*/
-float AngleDelta ( float angle1, float angle2 ) {
- return AngleNormalize180( angle1 - angle2 );
-}
-
-
-//============================================================
-
-
-/*
-=================
-SetPlaneSignbits
-=================
-*/
-void SetPlaneSignbits (cplane_t *out) {
- int bits, j;
-
- // for fast box on planeside test
- bits = 0;
- for (j=0 ; j<3 ; j++) {
- if (out->normal[j] < 0) {
- bits |= 1<<j;
- }
- }
- out->signbits = bits;
-}
-
-
-/*
-==================
-BoxOnPlaneSide
-
-Returns 1, 2, or 1 + 2
-==================
-*/
-int BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, struct cplane_s *p)
-{
- float dist[2];
- int sides, b, i;
-
- // fast axial cases
- if (p->type < 3)
- {
- if (p->dist <= emins[p->type])
- return 1;
- if (p->dist >= emaxs[p->type])
- return 2;
- return 3;
- }
-
- // general case
- dist[0] = dist[1] = 0;
- if (p->signbits < 8) // >= 8: default case is original code (dist[0]=dist[1]=0)
- {
- for (i=0 ; i<3 ; i++)
- {
- b = (p->signbits >> i) & 1;
- dist[ b] += p->normal[i]*emaxs[i];
- dist[!b] += p->normal[i]*emins[i];
- }
- }
-
- sides = 0;
- if (dist[0] >= p->dist)
- sides = 1;
- if (dist[1] < p->dist)
- sides |= 2;
-
- return sides;
-}
-
-
-/*
-=================
-RadiusFromBounds
-=================
-*/
-float RadiusFromBounds( const vec3_t mins, const vec3_t maxs ) {
- int i;
- vec3_t corner;
- float a, b;
-
- for (i=0 ; i<3 ; i++) {
- a = fabs( mins[i] );
- b = fabs( maxs[i] );
- corner[i] = a > b ? a : b;
- }
-
- return VectorLength (corner);
-}
-
-
-void ClearBounds( vec3_t mins, vec3_t maxs ) {
- mins[0] = mins[1] = mins[2] = 99999;
- maxs[0] = maxs[1] = maxs[2] = -99999;
-}
-
-void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs ) {
- if ( v[0] < mins[0] ) {
- mins[0] = v[0];
- }
- if ( v[0] > maxs[0]) {
- maxs[0] = v[0];
- }
-
- if ( v[1] < mins[1] ) {
- mins[1] = v[1];
- }
- if ( v[1] > maxs[1]) {
- maxs[1] = v[1];
- }
-
- if ( v[2] < mins[2] ) {
- mins[2] = v[2];
- }
- if ( v[2] > maxs[2]) {
- maxs[2] = v[2];
- }
-}
-
-qboolean BoundsIntersect(const vec3_t mins, const vec3_t maxs,
- const vec3_t mins2, const vec3_t maxs2)
-{
- if ( maxs[0] < mins2[0] ||
- maxs[1] < mins2[1] ||
- maxs[2] < mins2[2] ||
- mins[0] > maxs2[0] ||
- mins[1] > maxs2[1] ||
- mins[2] > maxs2[2])
- {
- return qfalse;
- }
-
- return qtrue;
-}
-
-qboolean BoundsIntersectSphere(const vec3_t mins, const vec3_t maxs,
- const vec3_t origin, vec_t radius)
-{
- if ( origin[0] - radius > maxs[0] ||
- origin[0] + radius < mins[0] ||
- origin[1] - radius > maxs[1] ||
- origin[1] + radius < mins[1] ||
- origin[2] - radius > maxs[2] ||
- origin[2] + radius < mins[2])
- {
- return qfalse;
- }
-
- return qtrue;
-}
-
-qboolean BoundsIntersectPoint(const vec3_t mins, const vec3_t maxs,
- const vec3_t origin)
-{
- if ( origin[0] > maxs[0] ||
- origin[0] < mins[0] ||
- origin[1] > maxs[1] ||
- origin[1] < mins[1] ||
- origin[2] > maxs[2] ||
- origin[2] < mins[2])
- {
- return qfalse;
- }
-
- return qtrue;
-}
-
-vec_t VectorNormalize( vec3_t v ) {
- // NOTE: TTimo - Apple G4 altivec source uses double?
- float length, ilength;
-
- length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- length = sqrt (length);
-
- if ( length ) {
- ilength = 1/length;
- v[0] *= ilength;
- v[1] *= ilength;
- v[2] *= ilength;
- }
-
- return length;
-}
-
-vec_t VectorNormalize2( const vec3_t v, vec3_t out) {
- float length, ilength;
-
- length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
- length = sqrt (length);
-
- if (length)
- {
- ilength = 1/length;
- out[0] = v[0]*ilength;
- out[1] = v[1]*ilength;
- out[2] = v[2]*ilength;
- } else {
- VectorClear( out );
- }
-
- return length;
-
-}
-
-void _VectorMA( const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc) {
- vecc[0] = veca[0] + scale*vecb[0];
- vecc[1] = veca[1] + scale*vecb[1];
- vecc[2] = veca[2] + scale*vecb[2];
-}
-
-
-vec_t _DotProduct( const vec3_t v1, const vec3_t v2 ) {
- return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
-}
-
-void _VectorSubtract( const vec3_t veca, const vec3_t vecb, vec3_t out ) {
- out[0] = veca[0]-vecb[0];
- out[1] = veca[1]-vecb[1];
- out[2] = veca[2]-vecb[2];
-}
-
-void _VectorAdd( const vec3_t veca, const vec3_t vecb, vec3_t out ) {
- out[0] = veca[0]+vecb[0];
- out[1] = veca[1]+vecb[1];
- out[2] = veca[2]+vecb[2];
-}
-
-void _VectorCopy( const vec3_t in, vec3_t out ) {
- out[0] = in[0];
- out[1] = in[1];
- out[2] = in[2];
-}
-
-void _VectorScale( const vec3_t in, vec_t scale, vec3_t out ) {
- out[0] = in[0]*scale;
- out[1] = in[1]*scale;
- out[2] = in[2]*scale;
-}
-
-void Vector4Scale( const vec4_t in, vec_t scale, vec4_t out ) {
- out[0] = in[0]*scale;
- out[1] = in[1]*scale;
- out[2] = in[2]*scale;
- out[3] = in[3]*scale;
-}
-
-
-int Q_log2( int val ) {
- int answer;
-
- answer = 0;
- while ( ( val>>=1 ) != 0 ) {
- answer++;
- }
- return answer;
-}
-
-
-
-/*
-=================
-PlaneTypeForNormal
-=================
-*/
-/*
-int PlaneTypeForNormal (vec3_t normal) {
- if ( normal[0] == 1.0 )
- return PLANE_X;
- if ( normal[1] == 1.0 )
- return PLANE_Y;
- if ( normal[2] == 1.0 )
- return PLANE_Z;
-
- return PLANE_NON_AXIAL;
-}
-*/
-
-
-/*
-================
-MatrixMultiply
-================
-*/
-void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]) {
- out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
- in1[0][2] * in2[2][0];
- out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
- in1[0][2] * in2[2][1];
- out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
- in1[0][2] * in2[2][2];
- out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
- in1[1][2] * in2[2][0];
- out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
- in1[1][2] * in2[2][1];
- out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
- in1[1][2] * in2[2][2];
- out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
- in1[2][2] * in2[2][0];
- out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
- in1[2][2] * in2[2][1];
- out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
- in1[2][2] * in2[2][2];
-}
-
-
-void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) {
- float angle;
- static float sr, sp, sy, cr, cp, cy;
- // static to help MS compiler fp bugs
-
- angle = angles[YAW] * (M_PI*2 / 360);
- sy = sin(angle);
- cy = cos(angle);
- angle = angles[PITCH] * (M_PI*2 / 360);
- sp = sin(angle);
- cp = cos(angle);
- angle = angles[ROLL] * (M_PI*2 / 360);
- sr = sin(angle);
- cr = cos(angle);
-
- if (forward)
- {
- forward[0] = cp*cy;
- forward[1] = cp*sy;
- forward[2] = -sp;
- }
- if (right)
- {
- right[0] = (-1*sr*sp*cy+-1*cr*-sy);
- right[1] = (-1*sr*sp*sy+-1*cr*cy);
- right[2] = -1*sr*cp;
- }
- if (up)
- {
- up[0] = (cr*sp*cy+-sr*-sy);
- up[1] = (cr*sp*sy+-sr*cy);
- up[2] = cr*cp;
- }
-}
-
-/*
-** assumes "src" is normalized
-*/
-void PerpendicularVector( vec3_t dst, const vec3_t src )
-{
- int pos;
- int i;
- float minelem = 1.0F;
- vec3_t tempvec;
-
- /*
- ** find the smallest magnitude axially aligned vector
- */
- for ( pos = 0, i = 0; i < 3; i++ )
- {
- if ( fabs( src[i] ) < minelem )
- {
- pos = i;
- minelem = fabs( src[i] );
- }
- }
- tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
- tempvec[pos] = 1.0F;
-
- /*
- ** project the point onto the plane defined by src
- */
- ProjectPointOnPlane( dst, tempvec, src );
-
- /*
- ** normalize the result
- */
- VectorNormalize( dst );
-}
-
-/*
-================
-Q_isnan
-
-Don't pass doubles to this
-================
-*/
-int Q_isnan( float x )
-{
- floatint_t fi;
-
- fi.f = x;
- fi.ui &= 0x7FFFFFFF;
- fi.ui = 0x7F800000 - fi.ui;
-
- return (int)( (unsigned int)fi.ui >> 31 );
-}
diff --git a/engine/code/qcommon/q_platform.h b/engine/code/qcommon/q_platform.h
deleted file mode 100644
index b744205..0000000
--- a/engine/code/qcommon/q_platform.h
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#ifndef __Q_PLATFORM_H
-#define __Q_PLATFORM_H
-
-// this is for determining if we have an asm version of a C function
-#ifdef Q3_VM
-
-#define id386 0
-#define idppc 0
-#define idppc_altivec 0
-#define idsparc 0
-
-#else
-
-#if (defined _M_IX86 || defined __i386__) && !defined(C_ONLY)
-#define id386 1
-#else
-#define id386 0
-#endif
-
-#if (defined(powerc) || defined(powerpc) || defined(ppc) || \
- defined(__ppc) || defined(__ppc__)) && !defined(C_ONLY)
-#define idppc 1
-#if defined(__VEC__)
-#define idppc_altivec 1
-#ifdef MACOS_X // Apple's GCC does this differently than the FSF.
-#define VECCONST_UINT8(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) \
- (vector unsigned char) (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p)
-#else
-#define VECCONST_UINT8(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) \
- (vector unsigned char) {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p}
-#endif
-#else
-#define idppc_altivec 0
-#endif
-#else
-#define idppc 0
-#define idppc_altivec 0
-#endif
-
-#if defined(__sparc__) && !defined(C_ONLY)
-#define idsparc 1
-#else
-#define idsparc 0
-#endif
-
-#endif
-
-#ifndef __ASM_I386__ // don't include the C bits if included from qasm.h
-
-// for windows fastcall option
-#define QDECL
-
-//================================================================= WIN32 ===
-
-#ifdef _WIN32
-
-#undef QDECL
-#define QDECL __cdecl
-
-#if defined( _MSC_VER )
-#define OS_STRING "win_msvc"
-#elif defined __MINGW32__
-#define OS_STRING "win_mingw"
-#endif
-
-#define ID_INLINE __inline
-#define PATH_SEP '\\'
-
-#if defined( _M_IX86 ) || defined( __i386__ )
-#define ARCH_STRING "x86"
-#elif defined _M_ALPHA
-#define ARCH_STRING "AXP"
-#endif
-
-#define Q3_LITTLE_ENDIAN
-
-#define DLL_EXT ".dll"
-
-#endif
-
-//============================================================== MAC OS X ===
-
-#if defined(MACOS_X) || defined(__APPLE_CC__)
-
-// make sure this is defined, just for sanity's sake...
-#ifndef MACOS_X
-#define MACOS_X
-#endif
-
-#define OS_STRING "macosx"
-#define ID_INLINE inline
-#define PATH_SEP '/'
-
-#ifdef __ppc__
-#define ARCH_STRING "ppc"
-#define Q3_BIG_ENDIAN
-#elif defined __i386__
-#define ARCH_STRING "i386"
-#define Q3_LITTLE_ENDIAN
-#endif
-
-#define DLL_EXT ".dylib"
-
-#endif
-
-//================================================================= LINUX ===
-
-#ifdef __linux__
-
-#include <endian.h>
-
-#define OS_STRING "linux"
-#define ID_INLINE inline
-#define PATH_SEP '/'
-
-#if defined __i386__
-#define ARCH_STRING "i386"
-#elif defined __x86_64__
-#define ARCH_STRING "x86_64"
-#elif defined __powerpc64__
-#define ARCH_STRING "ppc64"
-#elif defined __powerpc__
-#define ARCH_STRING "ppc"
-#elif defined __s390__
-#define ARCH_STRING "s390"
-#elif defined __s390x__
-#define ARCH_STRING "s390x"
-#elif defined __ia64__
-#define ARCH_STRING "ia64"
-#elif defined __alpha__
-#define ARCH_STRING "alpha"
-#elif defined __sparc__
-#define ARCH_STRING "sparc"
-#elif defined __arm__
-#define ARCH_STRING "arm"
-#elif defined __cris__
-#define ARCH_STRING "cris"
-#elif defined __hppa__
-#define ARCH_STRING "hppa"
-#elif defined __mips__
-#define ARCH_STRING "mips"
-#elif defined __sh__
-#define ARCH_STRING "sh"
-#endif
-
-#if __FLOAT_WORD_ORDER == __BIG_ENDIAN
-#define Q3_BIG_ENDIAN
-#else
-#define Q3_LITTLE_ENDIAN
-#endif
-
-#define DLL_EXT ".so"
-
-#endif
-
-//=================================================================== BSD ===
-
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
-
-#include <sys/types.h>
-#include <machine/endian.h>
-
-#ifndef __BSD__
- #define __BSD__
-#endif
-
-#if defined(__FreeBSD__)
-#define OS_STRING "freebsd"
-#elif defined(__OpenBSD__)
-#define OS_STRING "openbsd"
-#elif defined(__NetBSD__)
-#define OS_STRING "netbsd"
-#endif
-
-#define ID_INLINE inline
-#define PATH_SEP '/'
-
-#ifdef __i386__
-#define ARCH_STRING "i386"
-#elif defined __amd64__
-#define ARCH_STRING "x86_64"
-#elif defined __axp__
-#define ARCH_STRING "alpha"
-#endif
-
-#if BYTE_ORDER == BIG_ENDIAN
-#define Q3_BIG_ENDIAN
-#else
-#define Q3_LITTLE_ENDIAN
-#endif
-
-#define DLL_EXT ".so"
-
-#endif
-
-//================================================================= SUNOS ===
-
-#ifdef __sun
-
-#include <stdint.h>
-#include <sys/byteorder.h>
-
-#define OS_STRING "solaris"
-#define ID_INLINE inline
-#define PATH_SEP '/'
-
-#ifdef __i386__
-#define ARCH_STRING "i386"
-#elif defined __sparc
-#define ARCH_STRING "sparc"
-#endif
-
-#if defined( _BIG_ENDIAN )
-#define Q3_BIG_ENDIAN
-#elif defined( _LITTLE_ENDIAN )
-#define Q3_LITTLE_ENDIAN
-#endif
-
-#define DLL_EXT ".so"
-
-#endif
-
-//================================================================== IRIX ===
-
-#ifdef __sgi
-
-#define OS_STRING "irix"
-#define ID_INLINE __inline
-#define PATH_SEP '/'
-
-#define ARCH_STRING "mips"
-
-#define Q3_BIG_ENDIAN // SGI's MIPS are always big endian
-
-#define DLL_EXT ".so"
-
-#endif
-
-//================================================================== Q3VM ===
-
-#ifdef Q3_VM
-
-#define OS_STRING "q3vm"
-#define ID_INLINE
-#define PATH_SEP '/'
-
-#define ARCH_STRING "bytecode"
-
-#define DLL_EXT ".qvm"
-
-#endif
-
-//===========================================================================
-
-//catch missing defines in above blocks
-#if !defined( OS_STRING )
-#error "Operating system not supported"
-#endif
-
-#if !defined( ARCH_STRING )
-#error "Architecture not supported"
-#endif
-
-#ifndef ID_INLINE
-#error "ID_INLINE not defined"
-#endif
-
-#ifndef PATH_SEP
-#error "PATH_SEP not defined"
-#endif
-
-#ifndef DLL_EXT
-#error "DLL_EXT not defined"
-#endif
-
-
-//endianness
-short ShortSwap (short l);
-int LongSwap (int l);
-float FloatSwap (const float *f);
-
-#if defined( Q3_BIG_ENDIAN ) && defined( Q3_LITTLE_ENDIAN )
-#error "Endianness defined as both big and little"
-#elif defined( Q3_BIG_ENDIAN )
-
-#define LittleShort(x) ShortSwap(x)
-#define LittleLong(x) LongSwap(x)
-#define LittleFloat(x) FloatSwap(&x)
-#define BigShort
-#define BigLong
-#define BigFloat
-
-#elif defined( Q3_LITTLE_ENDIAN )
-
-#define LittleShort
-#define LittleLong
-#define LittleFloat
-#define BigShort(x) ShortSwap(x)
-#define BigLong(x) LongSwap(x)
-#define BigFloat(x) FloatSwap(&x)
-
-#elif defined( Q3_VM )
-
-#define LittleShort
-#define LittleLong
-#define LittleFloat
-#define BigShort
-#define BigLong
-#define BigFloat
-
-#else
-#error "Endianness not defined"
-#endif
-
-
-//platform string
-#ifdef NDEBUG
-#define PLATFORM_STRING OS_STRING "-" ARCH_STRING
-#else
-#define PLATFORM_STRING OS_STRING "-" ARCH_STRING "-debug"
-#endif
-
-#endif
-
-#endif
diff --git a/engine/code/qcommon/q_shared.c b/engine/code/qcommon/q_shared.c
deleted file mode 100644
index 550d100..0000000
--- a/engine/code/qcommon/q_shared.c
+++ /dev/null
@@ -1,1393 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// q_shared.c -- stateless support routines that are included in each code dll
-#include "q_shared.h"
-
-float Com_Clamp( float min, float max, float value ) {
- if ( value < min ) {
- return min;
- }
- if ( value > max ) {
- return max;
- }
- return value;
-}
-
-
-/*
-============
-COM_SkipPath
-============
-*/
-char *COM_SkipPath (char *pathname)
-{
- char *last;
-
- last = pathname;
- while (*pathname)
- {
- if (*pathname=='/')
- last = pathname+1;
- pathname++;
- }
- return last;
-}
-
-/*
-============
-COM_GetExtension
-============
-*/
-const char *COM_GetExtension( const char *name ) {
- int length, i;
-
- length = strlen(name)-1;
- i = length;
-
- while (name[i] != '.')
- {
- i--;
- if (name[i] == '/' || i == 0)
- return ""; // no extension
- }
-
- return &name[i+1];
-}
-
-
-/*
-============
-COM_StripExtension
-============
-*/
-void COM_StripExtension( const char *in, char *out, int destsize ) {
- int length;
-
- Q_strncpyz(out, in, destsize);
-
- length = strlen(out)-1;
- while (length > 0 && out[length] != '.')
- {
- length--;
- if (out[length] == '/')
- return; // no extension
- }
- if (length)
- out[length] = 0;
-}
-
-
-/*
-==================
-COM_DefaultExtension
-==================
-*/
-void COM_DefaultExtension (char *path, int maxSize, const char *extension ) {
- char oldPath[MAX_QPATH];
- char *src;
-
-//
-// if path doesn't have a .EXT, append extension
-// (extension should include the .)
-//
- src = path + strlen(path) - 1;
-
- while (*src != '/' && src != path) {
- if ( *src == '.' ) {
- return; // it has an extension
- }
- src--;
- }
-
- Q_strncpyz( oldPath, path, sizeof( oldPath ) );
- Com_sprintf( path, maxSize, "%s%s", oldPath, extension );
-}
-
-/*
-============================================================================
-
- BYTE ORDER FUNCTIONS
-
-============================================================================
-*/
-/*
-// can't just use function pointers, or dll linkage can
-// mess up when qcommon is included in multiple places
-static short (*_BigShort) (short l);
-static short (*_LittleShort) (short l);
-static int (*_BigLong) (int l);
-static int (*_LittleLong) (int l);
-static qint64 (*_BigLong64) (qint64 l);
-static qint64 (*_LittleLong64) (qint64 l);
-static float (*_BigFloat) (const float *l);
-static float (*_LittleFloat) (const float *l);
-
-short BigShort(short l){return _BigShort(l);}
-short LittleShort(short l) {return _LittleShort(l);}
-int BigLong (int l) {return _BigLong(l);}
-int LittleLong (int l) {return _LittleLong(l);}
-qint64 BigLong64 (qint64 l) {return _BigLong64(l);}
-qint64 LittleLong64 (qint64 l) {return _LittleLong64(l);}
-float BigFloat (const float *l) {return _BigFloat(l);}
-float LittleFloat (const float *l) {return _LittleFloat(l);}
-*/
-
-short ShortSwap (short l)
-{
- byte b1,b2;
-
- b1 = l&255;
- b2 = (l>>8)&255;
-
- return (b1<<8) + b2;
-}
-
-short ShortNoSwap (short l)
-{
- return l;
-}
-
-int LongSwap (int l)
-{
- byte b1,b2,b3,b4;
-
- b1 = l&255;
- b2 = (l>>8)&255;
- b3 = (l>>16)&255;
- b4 = (l>>24)&255;
-
- return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
-}
-
-int LongNoSwap (int l)
-{
- return l;
-}
-
-qint64 Long64Swap (qint64 ll)
-{
- qint64 result;
-
- result.b0 = ll.b7;
- result.b1 = ll.b6;
- result.b2 = ll.b5;
- result.b3 = ll.b4;
- result.b4 = ll.b3;
- result.b5 = ll.b2;
- result.b6 = ll.b1;
- result.b7 = ll.b0;
-
- return result;
-}
-
-qint64 Long64NoSwap (qint64 ll)
-{
- return ll;
-}
-
-float FloatSwap (const float *f) {
- floatint_t out;
-
- out.f = *f;
- out.ui = LongSwap(out.ui);
-
- return out.f;
-}
-
-float FloatNoSwap (const float *f)
-{
- return *f;
-}
-
-/*
-================
-Swap_Init
-================
-*/
-/*
-void Swap_Init (void)
-{
- byte swaptest[2] = {1,0};
-
-// set the byte swapping variables in a portable manner
- if ( *(short *)swaptest == 1)
- {
- _BigShort = ShortSwap;
- _LittleShort = ShortNoSwap;
- _BigLong = LongSwap;
- _LittleLong = LongNoSwap;
- _BigLong64 = Long64Swap;
- _LittleLong64 = Long64NoSwap;
- _BigFloat = FloatSwap;
- _LittleFloat = FloatNoSwap;
- }
- else
- {
- _BigShort = ShortNoSwap;
- _LittleShort = ShortSwap;
- _BigLong = LongNoSwap;
- _LittleLong = LongSwap;
- _BigLong64 = Long64NoSwap;
- _LittleLong64 = Long64Swap;
- _BigFloat = FloatNoSwap;
- _LittleFloat = FloatSwap;
- }
-
-}
-*/
-
-/*
-============================================================================
-
-PARSING
-
-============================================================================
-*/
-
-static char com_token[MAX_TOKEN_CHARS];
-static char com_parsename[MAX_TOKEN_CHARS];
-static int com_lines;
-
-void COM_BeginParseSession( const char *name )
-{
- com_lines = 0;
- Com_sprintf(com_parsename, sizeof(com_parsename), "%s", name);
-}
-
-int COM_GetCurrentParseLine( void )
-{
- return com_lines;
-}
-
-char *COM_Parse( char **data_p )
-{
- return COM_ParseExt( data_p, qtrue );
-}
-
-void COM_ParseError( char *format, ... )
-{
- va_list argptr;
- static char string[4096];
-
- va_start (argptr, format);
- Q_vsnprintf (string, sizeof(string), format, argptr);
- va_end (argptr);
-
- Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, com_lines, string);
-}
-
-void COM_ParseWarning( char *format, ... )
-{
- va_list argptr;
- static char string[4096];
-
- va_start (argptr, format);
- Q_vsnprintf (string, sizeof(string), format, argptr);
- va_end (argptr);
-
- Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, com_lines, string);
-}
-
-/*
-==============
-COM_Parse
-
-Parse a token out of a string
-Will never return NULL, just empty strings
-
-If "allowLineBreaks" is qtrue then an empty
-string will be returned if the next token is
-a newline.
-==============
-*/
-static char *SkipWhitespace( char *data, qboolean *hasNewLines ) {
- int c;
-
- while( (c = *data) <= ' ') {
- if( !c ) {
- return NULL;
- }
- if( c == '\n' ) {
- com_lines++;
- *hasNewLines = qtrue;
- }
- data++;
- }
-
- return data;
-}
-
-int COM_Compress( char *data_p ) {
- char *in, *out;
- int c;
- qboolean newline = qfalse, whitespace = qfalse;
-
- in = out = data_p;
- if (in) {
- while ((c = *in) != 0) {
- // skip double slash comments
- if ( c == '/' && in[1] == '/' ) {
- while (*in && *in != '\n') {
- in++;
- }
- // skip /* */ comments
- } else if ( c == '/' && in[1] == '*' ) {
- while ( *in && ( *in != '*' || in[1] != '/' ) )
- in++;
- if ( *in )
- in += 2;
- // record when we hit a newline
- } else if ( c == '\n' || c == '\r' ) {
- newline = qtrue;
- in++;
- // record when we hit whitespace
- } else if ( c == ' ' || c == '\t') {
- whitespace = qtrue;
- in++;
- // an actual token
- } else {
- // if we have a pending newline, emit it (and it counts as whitespace)
- if (newline) {
- *out++ = '\n';
- newline = qfalse;
- whitespace = qfalse;
- } if (whitespace) {
- *out++ = ' ';
- whitespace = qfalse;
- }
-
- // copy quoted strings unmolested
- if (c == '"') {
- *out++ = c;
- in++;
- while (1) {
- c = *in;
- if (c && c != '"') {
- *out++ = c;
- in++;
- } else {
- break;
- }
- }
- if (c == '"') {
- *out++ = c;
- in++;
- }
- } else {
- *out = c;
- out++;
- in++;
- }
- }
- }
- }
- *out = 0;
- return out - data_p;
-}
-
-char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
-{
- int c = 0, len;
- qboolean hasNewLines = qfalse;
- char *data;
-
- data = *data_p;
- len = 0;
- com_token[0] = 0;
-
- // make sure incoming data is valid
- if ( !data )
- {
- *data_p = NULL;
- return com_token;
- }
-
- while ( 1 )
- {
- // skip whitespace
- data = SkipWhitespace( data, &hasNewLines );
- if ( !data )
- {
- *data_p = NULL;
- return com_token;
- }
- if ( hasNewLines && !allowLineBreaks )
- {
- *data_p = data;
- return com_token;
- }
-
- c = *data;
-
- // skip double slash comments
- if ( c == '/' && data[1] == '/' )
- {
- data += 2;
- while (*data && *data != '\n') {
- data++;
- }
- }
- // skip /* */ comments
- else if ( c=='/' && data[1] == '*' )
- {
- data += 2;
- while ( *data && ( *data != '*' || data[1] != '/' ) )
- {
- data++;
- }
- if ( *data )
- {
- data += 2;
- }
- }
- else
- {
- break;
- }
- }
-
- // handle quoted strings
- if (c == '\"')
- {
- data++;
- while (1)
- {
- c = *data++;
- if (c=='\"' || !c)
- {
- com_token[len] = 0;
- *data_p = ( char * ) data;
- return com_token;
- }
- if (len < MAX_TOKEN_CHARS - 1)
- {
- com_token[len] = c;
- len++;
- }
- }
- }
-
- // parse a regular word
- do
- {
- if (len < MAX_TOKEN_CHARS - 1)
- {
- com_token[len] = c;
- len++;
- }
- data++;
- c = *data;
- if ( c == '\n' )
- com_lines++;
- } while (c>32);
-
- com_token[len] = 0;
-
- *data_p = ( char * ) data;
- return com_token;
-}
-
-/*
-==================
-COM_MatchToken
-==================
-*/
-void COM_MatchToken( char **buf_p, char *match ) {
- char *token;
-
- token = COM_Parse( buf_p );
- if ( strcmp( token, match ) ) {
- Com_Error( ERR_DROP, "MatchToken: %s != %s", token, match );
- }
-}
-
-
-/*
-=================
-SkipBracedSection
-
-The next token should be an open brace.
-Skips until a matching close brace is found.
-Internal brace depths are properly skipped.
-=================
-*/
-void SkipBracedSection (char **program) {
- char *token;
- int depth;
-
- depth = 0;
- do {
- token = COM_ParseExt( program, qtrue );
- if( token[1] == 0 ) {
- if( token[0] == '{' ) {
- depth++;
- }
- else if( token[0] == '}' ) {
- depth--;
- }
- }
- } while( depth && *program );
-}
-
-/*
-=================
-SkipRestOfLine
-=================
-*/
-void SkipRestOfLine ( char **data ) {
- char *p;
- int c;
-
- p = *data;
- while ( (c = *p++) != 0 ) {
- if ( c == '\n' ) {
- com_lines++;
- break;
- }
- }
-
- *data = p;
-}
-
-
-void Parse1DMatrix (char **buf_p, int x, float *m) {
- char *token;
- int i;
-
- COM_MatchToken( buf_p, "(" );
-
- for (i = 0 ; i < x ; i++) {
- token = COM_Parse(buf_p);
- m[i] = atof(token);
- }
-
- COM_MatchToken( buf_p, ")" );
-}
-
-void Parse2DMatrix (char **buf_p, int y, int x, float *m) {
- int i;
-
- COM_MatchToken( buf_p, "(" );
-
- for (i = 0 ; i < y ; i++) {
- Parse1DMatrix (buf_p, x, m + i * x);
- }
-
- COM_MatchToken( buf_p, ")" );
-}
-
-void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m) {
- int i;
-
- COM_MatchToken( buf_p, "(" );
-
- for (i = 0 ; i < z ; i++) {
- Parse2DMatrix (buf_p, y, x, m + i * x*y);
- }
-
- COM_MatchToken( buf_p, ")" );
-}
-
-/*
-===================
-Com_HexStrToInt
-===================
-*/
-int Com_HexStrToInt( const char *str )
-{
- if ( !str || !str[ 0 ] )
- return -1;
-
- // check for hex code
- if( str[ 0 ] == '0' && str[ 1 ] == 'x' )
- {
- int i, n = 0;
-
- for( i = 2; i < strlen( str ); i++ )
- {
- char digit;
-
- n *= 16;
-
- digit = tolower( str[ i ] );
-
- if( digit >= '0' && digit <= '9' )
- digit -= '0';
- else if( digit >= 'a' && digit <= 'f' )
- digit = digit - 'a' + 10;
- else
- return -1;
-
- n += digit;
- }
-
- return n;
- }
-
- return -1;
-}
-
-/*
-============================================================================
-
- LIBRARY REPLACEMENT FUNCTIONS
-
-============================================================================
-*/
-
-int Q_isprint( int c )
-{
- if ( c >= 0x20 && c <= 0x7E )
- return ( 1 );
- return ( 0 );
-}
-
-int Q_islower( int c )
-{
- if (c >= 'a' && c <= 'z')
- return ( 1 );
- return ( 0 );
-}
-
-int Q_isupper( int c )
-{
- if (c >= 'A' && c <= 'Z')
- return ( 1 );
- return ( 0 );
-}
-
-int Q_isalpha( int c )
-{
- if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
- return ( 1 );
- return ( 0 );
-}
-
-char* Q_strrchr( const char* string, int c )
-{
- char cc = c;
- char *s;
- char *sp=(char *)0;
-
- s = (char*)string;
-
- while (*s)
- {
- if (*s == cc)
- sp = s;
- s++;
- }
- if (cc == 0)
- sp = s;
-
- return sp;
-}
-
-qboolean Q_isanumber( const char *s )
-{
-#ifdef Q3_VM
- //FIXME: implement
- return qfalse;
-#else
- char *p;
- double d;
-
- if( *s == '\0' )
- return qfalse;
-
- d = strtod( s, &p );
-
- return *p == '\0';
-#endif
-}
-
-qboolean Q_isintegral( float f )
-{
- return (int)f == f;
-}
-
-/*
-=============
-Q_strncpyz
-
-Safe strncpy that ensures a trailing zero
-=============
-*/
-void Q_strncpyz( char *dest, const char *src, int destsize ) {
- if ( !dest ) {
- Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" );
- }
- if ( !src ) {
- Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
- }
- if ( destsize < 1 ) {
- Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
- }
-
- strncpy( dest, src, destsize-1 );
- dest[destsize-1] = 0;
-}
-
-int Q_stricmpn (const char *s1, const char *s2, int n) {
- int c1, c2;
-
- if ( s1 == NULL ) {
- if ( s2 == NULL )
- return 0;
- else
- return -1;
- }
- else if ( s2==NULL )
- return 1;
-
-
-
- do {
- c1 = *s1++;
- c2 = *s2++;
-
- if (!n--) {
- return 0; // strings are equal until end point
- }
-
- if (c1 != c2) {
- if (c1 >= 'a' && c1 <= 'z') {
- c1 -= ('a' - 'A');
- }
- if (c2 >= 'a' && c2 <= 'z') {
- c2 -= ('a' - 'A');
- }
- if (c1 != c2) {
- return c1 < c2 ? -1 : 1;
- }
- }
- } while (c1);
-
- return 0; // strings are equal
-}
-
-int Q_strncmp (const char *s1, const char *s2, int n) {
- int c1, c2;
-
- do {
- c1 = *s1++;
- c2 = *s2++;
-
- if (!n--) {
- return 0; // strings are equal until end point
- }
-
- if (c1 != c2) {
- return c1 < c2 ? -1 : 1;
- }
- } while (c1);
-
- return 0; // strings are equal
-}
-
-int Q_stricmp (const char *s1, const char *s2) {
- return (s1 && s2) ? Q_stricmpn (s1, s2, 99999) : -1;
-}
-
-
-char *Q_strlwr( char *s1 ) {
- char *s;
-
- s = s1;
- while ( *s ) {
- *s = tolower(*s);
- s++;
- }
- return s1;
-}
-
-char *Q_strupr( char *s1 ) {
- char *s;
-
- s = s1;
- while ( *s ) {
- *s = toupper(*s);
- s++;
- }
- return s1;
-}
-
-
-// never goes past bounds or leaves without a terminating 0
-void Q_strcat( char *dest, int size, const char *src ) {
- int l1;
-
- l1 = strlen( dest );
- if ( l1 >= size ) {
- Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
- }
- Q_strncpyz( dest + l1, src, size - l1 );
-}
-
-/*
-* Find the first occurrence of find in s.
-*/
-const char *Q_stristr( const char *s, const char *find)
-{
- char c, sc;
- size_t len;
-
- if ((c = *find++) != 0)
- {
- if (c >= 'a' && c <= 'z')
- {
- c -= ('a' - 'A');
- }
- len = strlen(find);
- do
- {
- do
- {
- if ((sc = *s++) == 0)
- return NULL;
- if (sc >= 'a' && sc <= 'z')
- {
- sc -= ('a' - 'A');
- }
- } while (sc != c);
- } while (Q_stricmpn(s, find, len) != 0);
- s--;
- }
- return s;
-}
-
-
-int Q_PrintStrlen( const char *string ) {
- int len;
- const char *p;
-
- if( !string ) {
- return 0;
- }
-
- len = 0;
- p = string;
- while( *p ) {
- if( Q_IsColorString( p ) ) {
- p += 2;
- continue;
- }
- p++;
- len++;
- }
-
- return len;
-}
-
-
-char *Q_CleanStr( char *string ) {
- char* d;
- char* s;
- int c;
-
- s = string;
- d = string;
- while ((c = *s) != 0 ) {
- if ( Q_IsColorString( s ) ) {
- s++;
- }
- else if ( c >= 0x20 && c <= 0x7E ) {
- *d++ = c;
- }
- s++;
- }
- *d = '\0';
-
- return string;
-}
-
-int Q_CountChar(const char *string, char tocount)
-{
- int count;
-
- for(count = 0; *string; string++)
- {
- if(*string == tocount)
- count++;
- }
-
- return count;
-}
-
-void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {
- int len;
- va_list argptr;
- char bigbuffer[32000]; // big, but small enough to fit in PPC stack
-
- va_start (argptr,fmt);
- len = Q_vsnprintf (bigbuffer, sizeof(bigbuffer), fmt,argptr);
- va_end (argptr);
- if ( len >= sizeof( bigbuffer ) ) {
- Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
- }
- if (len >= size) {
- Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
-#ifdef _DEBUG
- __asm {
- int 3;
- }
-#endif
- }
- Q_strncpyz (dest, bigbuffer, size );
-}
-
-
-/*
-============
-va
-
-does a varargs printf into a temp buffer, so I don't need to have
-varargs versions of all text functions.
-============
-*/
-char * QDECL va( char *format, ... ) {
- va_list argptr;
- static char string[2][32000]; // in case va is called by nested functions
- static int index = 0;
- char *buf;
-
- buf = string[index & 1];
- index++;
-
- va_start (argptr, format);
- Q_vsnprintf (buf, sizeof(*string), format, argptr);
- va_end (argptr);
-
- return buf;
-}
-
-/*
-============
-Com_TruncateLongString
-
-Assumes buffer is atleast TRUNCATE_LENGTH big
-============
-*/
-void Com_TruncateLongString( char *buffer, const char *s )
-{
- int length = strlen( s );
-
- if( length <= TRUNCATE_LENGTH )
- Q_strncpyz( buffer, s, TRUNCATE_LENGTH );
- else
- {
- Q_strncpyz( buffer, s, ( TRUNCATE_LENGTH / 2 ) - 3 );
- Q_strcat( buffer, TRUNCATE_LENGTH, " ... " );
- Q_strcat( buffer, TRUNCATE_LENGTH, s + length - ( TRUNCATE_LENGTH / 2 ) + 3 );
- }
-}
-
-/*
-=====================================================================
-
- INFO STRINGS
-
-=====================================================================
-*/
-
-/*
-===============
-Info_ValueForKey
-
-Searches the string for the given
-key and returns the associated value, or an empty string.
-FIXME: overflow check?
-===============
-*/
-char *Info_ValueForKey( const char *s, const char *key ) {
- char pkey[BIG_INFO_KEY];
- static char value[2][BIG_INFO_VALUE]; // use two buffers so compares
- // work without stomping on each other
- static int valueindex = 0;
- char *o;
-
- if ( !s || !key ) {
- return "";
- }
-
- if ( strlen( s ) >= BIG_INFO_STRING ) {
- Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
- }
-
- valueindex ^= 1;
- if (*s == '\\')
- s++;
- while (1)
- {
- o = pkey;
- while (*s != '\\')
- {
- if (!*s)
- return "";
- *o++ = *s++;
- }
- *o = 0;
- s++;
-
- o = value[valueindex];
-
- while (*s != '\\' && *s)
- {
- *o++ = *s++;
- }
- *o = 0;
-
- if (!Q_stricmp (key, pkey) )
- return value[valueindex];
-
- if (!*s)
- break;
- s++;
- }
-
- return "";
-}
-
-
-/*
-===================
-Info_NextPair
-
-Used to itterate through all the key/value pairs in an info string
-===================
-*/
-void Info_NextPair( const char **head, char *key, char *value ) {
- char *o;
- const char *s;
-
- s = *head;
-
- if ( *s == '\\' ) {
- s++;
- }
- key[0] = 0;
- value[0] = 0;
-
- o = key;
- while ( *s != '\\' ) {
- if ( !*s ) {
- *o = 0;
- *head = s;
- return;
- }
- *o++ = *s++;
- }
- *o = 0;
- s++;
-
- o = value;
- while ( *s != '\\' && *s ) {
- *o++ = *s++;
- }
- *o = 0;
-
- *head = s;
-}
-
-
-/*
-===================
-Info_RemoveKey
-===================
-*/
-void Info_RemoveKey( char *s, const char *key ) {
- char *start;
- char pkey[MAX_INFO_KEY];
- char value[MAX_INFO_VALUE];
- char *o;
-
- if ( strlen( s ) >= MAX_INFO_STRING ) {
- Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
- }
-
- if (strchr (key, '\\')) {
- return;
- }
-
- while (1)
- {
- start = s;
- if (*s == '\\')
- s++;
- o = pkey;
- while (*s != '\\')
- {
- if (!*s)
- return;
- *o++ = *s++;
- }
- *o = 0;
- s++;
-
- o = value;
- while (*s != '\\' && *s)
- {
- if (!*s)
- return;
- *o++ = *s++;
- }
- *o = 0;
-
- if (!strcmp (key, pkey) )
- {
- memmove(start, s, strlen(s) + 1); // remove this part
-
- return;
- }
-
- if (!*s)
- return;
- }
-
-}
-
-/*
-===================
-Info_RemoveKey_Big
-===================
-*/
-void Info_RemoveKey_Big( char *s, const char *key ) {
- char *start;
- char pkey[BIG_INFO_KEY];
- char value[BIG_INFO_VALUE];
- char *o;
-
- if ( strlen( s ) >= BIG_INFO_STRING ) {
- Com_Error( ERR_DROP, "Info_RemoveKey_Big: oversize infostring" );
- }
-
- if (strchr (key, '\\')) {
- return;
- }
-
- while (1)
- {
- start = s;
- if (*s == '\\')
- s++;
- o = pkey;
- while (*s != '\\')
- {
- if (!*s)
- return;
- *o++ = *s++;
- }
- *o = 0;
- s++;
-
- o = value;
- while (*s != '\\' && *s)
- {
- if (!*s)
- return;
- *o++ = *s++;
- }
- *o = 0;
-
- if (!strcmp (key, pkey) )
- {
- strcpy (start, s); // remove this part
- return;
- }
-
- if (!*s)
- return;
- }
-
-}
-
-
-
-
-/*
-==================
-Info_Validate
-
-Some characters are illegal in info strings because they
-can mess up the server's parsing
-==================
-*/
-qboolean Info_Validate( const char *s ) {
- if ( strchr( s, '\"' ) ) {
- return qfalse;
- }
- if ( strchr( s, ';' ) ) {
- return qfalse;
- }
- return qtrue;
-}
-
-/*
-==================
-Info_SetValueForKey
-
-Changes or adds a key/value pair
-==================
-*/
-void Info_SetValueForKey( char *s, const char *key, const char *value ) {
- char newi[MAX_INFO_STRING];
- const char* blacklist = "\\;\"";
-
- if ( strlen( s ) >= MAX_INFO_STRING ) {
- Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
- }
-
- for(; *blacklist; ++blacklist)
- {
- if (strchr (key, *blacklist) || strchr (value, *blacklist))
- {
- Com_Printf (S_COLOR_YELLOW "Can't use keys or values with a '%c': %s = %s\n", *blacklist, key, value);
- return;
- }
- }
-
- Info_RemoveKey (s, key);
- if (!value || !strlen(value))
- return;
-
- Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
-
- if (strlen(newi) + strlen(s) >= MAX_INFO_STRING)
- {
- Com_Printf ("Info string length exceeded\n");
- return;
- }
-
- strcat (newi, s);
- strcpy (s, newi);
-}
-
-/*
-==================
-Info_SetValueForKey_Big
-
-Changes or adds a key/value pair
-==================
-*/
-void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
- char newi[BIG_INFO_STRING];
- const char* blacklist = "\\;\"";
-
- if ( strlen( s ) >= BIG_INFO_STRING ) {
- Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
- }
-
- for(; *blacklist; ++blacklist)
- {
- if (strchr (key, *blacklist) || strchr (value, *blacklist))
- {
- Com_Printf (S_COLOR_YELLOW "Can't use keys or values with a '%c': %s = %s\n", *blacklist, key, value);
- return;
- }
- }
-
- Info_RemoveKey_Big (s, key);
- if (!value || !strlen(value))
- return;
-
- Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
-
- if (strlen(newi) + strlen(s) >= BIG_INFO_STRING)
- {
- Com_Printf ("BIG Info string length exceeded\n");
- return;
- }
-
- strcat (s, newi);
-}
-
-
-
-
-//====================================================================
-
-/*
-==================
-Com_CharIsOneOfCharset
-==================
-*/
-static qboolean Com_CharIsOneOfCharset( char c, char *set )
-{
- int i;
-
- for( i = 0; i < strlen( set ); i++ )
- {
- if( set[ i ] == c )
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-==================
-Com_SkipCharset
-==================
-*/
-char *Com_SkipCharset( char *s, char *sep )
-{
- char *p = s;
-
- while( p )
- {
- if( Com_CharIsOneOfCharset( *p, sep ) )
- p++;
- else
- break;
- }
-
- return p;
-}
-
-/*
-==================
-Com_SkipTokens
-==================
-*/
-char *Com_SkipTokens( char *s, int numTokens, char *sep )
-{
- int sepCount = 0;
- char *p = s;
-
- while( sepCount < numTokens )
- {
- if( Com_CharIsOneOfCharset( *p++, sep ) )
- {
- sepCount++;
- while( Com_CharIsOneOfCharset( *p, sep ) )
- p++;
- }
- else if( *p == '\0' )
- break;
- }
-
- if( sepCount == numTokens )
- return p;
- else
- return s;
-}
diff --git a/engine/code/qcommon/q_shared.h b/engine/code/qcommon/q_shared.h
deleted file mode 100644
index 6942a62..0000000
--- a/engine/code/qcommon/q_shared.h
+++ /dev/null
@@ -1,1302 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#ifndef __Q_SHARED_H
-#define __Q_SHARED_H
-
-// q_shared.h -- included first by ALL program modules.
-// A user mod should never modify this file
-
-#ifdef STANDALONE
- #define PRODUCT_NAME "iofoo3"
- #define BASEGAME "foobar"
- #define CLIENT_WINDOW_TITLE "changeme"
- #define CLIENT_WINDOW_MIN_TITLE "changeme2"
- #define GAMENAME_FOR_MASTER "iofoo3" // must NOT contain whitespaces
-#else
- #define PRODUCT_NAME "ioq3"
- #define BASEGAME "baseq3"
- #define CLIENT_WINDOW_TITLE "ioquake3"
- #define CLIENT_WINDOW_MIN_TITLE "ioq3"
- #define GAMENAME_FOR_MASTER "Quake3Arena"
-#endif
-
-#ifdef _MSC_VER
- #define PRODUCT_VERSION "1.35"
-#endif
-
-#define Q3_VERSION PRODUCT_NAME " " PRODUCT_VERSION
-
-#define MAX_TEAMNAME 32
-
-#ifdef _MSC_VER
-
-#pragma warning(disable : 4018) // signed/unsigned mismatch
-#pragma warning(disable : 4032)
-#pragma warning(disable : 4051)
-#pragma warning(disable : 4057) // slightly different base types
-#pragma warning(disable : 4100) // unreferenced formal parameter
-#pragma warning(disable : 4115)
-#pragma warning(disable : 4125) // decimal digit terminates octal escape sequence
-#pragma warning(disable : 4127) // conditional expression is constant
-#pragma warning(disable : 4136)
-#pragma warning(disable : 4152) // nonstandard extension, function/data pointer conversion in expression
-//#pragma warning(disable : 4201)
-//#pragma warning(disable : 4214)
-#pragma warning(disable : 4244)
-#pragma warning(disable : 4142) // benign redefinition
-//#pragma warning(disable : 4305) // truncation from const double to float
-//#pragma warning(disable : 4310) // cast truncates constant value
-//#pragma warning(disable: 4505) // unreferenced local function has been removed
-#pragma warning(disable : 4514)
-#pragma warning(disable : 4702) // unreachable code
-#pragma warning(disable : 4711) // selected for automatic inline expansion
-#pragma warning(disable : 4220) // varargs matches remaining parameters
-//#pragma intrinsic( memset, memcpy )
-#endif
-
-//Ignore __attribute__ on non-gcc platforms
-#ifndef __GNUC__
-#ifndef __attribute__
-#define __attribute__(x)
-#endif
-#endif
-
-#if (defined _MSC_VER)
-#define Q_EXPORT __declspec(dllexport)
-#elif (defined __SUNPRO_C)
-#define Q_EXPORT __global
-#elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun))
-#define Q_EXPORT __attribute__((visibility("default")))
-#else
-#define Q_EXPORT
-#endif
-
-/**********************************************************************
- VM Considerations
-
- The VM can not use the standard system headers because we aren't really
- using the compiler they were meant for. We use bg_lib.h which contains
- prototypes for the functions we define for our own use in bg_lib.c.
-
- When writing mods, please add needed headers HERE, do not start including
- stuff like <stdio.h> in the various .c files that make up each of the VMs
- since you will be including system headers files can will have issues.
-
- Remember, if you use a C library function that is not defined in bg_lib.c,
- you will have to add your own version for support in the VM.
-
- **********************************************************************/
-
-#ifdef Q3_VM
-
-#include "../game/bg_lib.h"
-
-typedef int intptr_t;
-
-#else
-
-#include <assert.h>
-#include <math.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
-#include <ctype.h>
-#include <limits.h>
-
-// vsnprintf is ISO/IEC 9899:1999
-// abstracting this to make it portable
-#ifdef _WIN32
- #define Q_vsnprintf _vsnprintf
- #define Q_snprintf _snprintf
-#else
- #define Q_vsnprintf vsnprintf
- #define Q_snprintf snprintf
-#endif
-
-#ifdef _MSC_VER
- #include <io.h>
-
- typedef __int64 int64_t;
- typedef __int32 int32_t;
- typedef __int16 int16_t;
- typedef __int8 int8_t;
- typedef unsigned __int64 uint64_t;
- typedef unsigned __int32 uint32_t;
- typedef unsigned __int16 uint16_t;
- typedef unsigned __int8 uint8_t;
-#else
- #include <stdint.h>
-#endif
-
-#endif
-
-
-#include "q_platform.h"
-
-//=============================================================
-
-typedef unsigned char byte;
-
-typedef enum {qfalse, qtrue} qboolean;
-
-typedef union {
- float f;
- int i;
- unsigned int ui;
-} floatint_t;
-
-typedef int qhandle_t;
-typedef int sfxHandle_t;
-typedef int fileHandle_t;
-typedef int clipHandle_t;
-
-#define PAD(x,y) (((x)+(y)-1) & ~((y)-1))
-
-#ifdef __GNUC__
-#define ALIGN(x) __attribute__((aligned(x)))
-#else
-#define ALIGN(x)
-#endif
-
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
-#define STRING(s) #s
-// expand constants before stringifying them
-#define XSTRING(s) STRING(s)
-
-#define MAX_QINT 0x7fffffff
-#define MIN_QINT (-MAX_QINT-1)
-
-
-// angle indexes
-#define PITCH 0 // up / down
-#define YAW 1 // left / right
-#define ROLL 2 // fall over
-
-// the game guarantees that no string from the network will ever
-// exceed MAX_STRING_CHARS
-#define MAX_STRING_CHARS 1024 // max length of a string passed to Cmd_TokenizeString
-#define MAX_STRING_TOKENS 1024 // max tokens resulting from Cmd_TokenizeString
-#define MAX_TOKEN_CHARS 1024 // max length of an individual token
-
-#define MAX_INFO_STRING 1024
-#define MAX_INFO_KEY 1024
-#define MAX_INFO_VALUE 1024
-
-#define BIG_INFO_STRING 8192 // used for system info key only
-#define BIG_INFO_KEY 8192
-#define BIG_INFO_VALUE 8192
-
-
-#define MAX_QPATH 64 // max length of a quake game pathname
-#ifdef PATH_MAX
-#define MAX_OSPATH PATH_MAX
-#else
-#define MAX_OSPATH 256 // max length of a filesystem pathname
-#endif
-
-#define MAX_NAME_LENGTH 32 // max length of a client name
-
-#define MAX_SAY_TEXT 150
-
-// paramters for command buffer stuffing
-typedef enum {
- EXEC_NOW, // don't return until completed, a VM should NEVER use this,
- // because some commands might cause the VM to be unloaded...
- EXEC_INSERT, // insert at current position, but don't run yet
- EXEC_APPEND // add to end of the command buffer (normal case)
-} cbufExec_t;
-
-
-//
-// these aren't needed by any of the VMs. put in another header?
-//
-#define MAX_MAP_AREA_BYTES 32 // bit vector of area visibility
-
-
-// print levels from renderer (FIXME: set up for game / cgame?)
-typedef enum {
- PRINT_ALL,
- PRINT_DEVELOPER, // only print when "developer 1"
- PRINT_WARNING,
- PRINT_ERROR
-} printParm_t;
-
-
-#ifdef ERR_FATAL
-#undef ERR_FATAL // this is be defined in malloc.h
-#endif
-
-// parameters to the main Error routine
-typedef enum {
- ERR_FATAL, // exit the entire game with a popup window
- ERR_DROP, // print to console and disconnect from game
- ERR_SERVERDISCONNECT, // don't kill server
- ERR_DISCONNECT, // client disconnected from the server
- ERR_NEED_CD // pop up the need-cd dialog
-} errorParm_t;
-
-
-// font rendering values used by ui and cgame
-
-#define PROP_GAP_WIDTH 3
-#define PROP_SPACE_WIDTH 8
-#define PROP_HEIGHT 27
-#define PROP_SMALL_SIZE_SCALE 0.75
-
-#define BLINK_DIVISOR 200
-#define PULSE_DIVISOR 75
-
-#define UI_LEFT 0x00000000 // default
-#define UI_CENTER 0x00000001
-#define UI_RIGHT 0x00000002
-#define UI_FORMATMASK 0x00000007
-#define UI_SMALLFONT 0x00000010
-#define UI_BIGFONT 0x00000020 // default
-#define UI_GIANTFONT 0x00000040
-#define UI_DROPSHADOW 0x00000800
-#define UI_BLINK 0x00001000
-#define UI_INVERSE 0x00002000
-#define UI_PULSE 0x00004000
-
-#if defined(_DEBUG) && !defined(BSPC)
- #define HUNK_DEBUG
-#endif
-
-typedef enum {
- h_high,
- h_low,
- h_dontcare
-} ha_pref;
-
-#ifdef HUNK_DEBUG
-#define Hunk_Alloc( size, preference ) Hunk_AllocDebug(size, preference, #size, __FILE__, __LINE__)
-void *Hunk_AllocDebug( int size, ha_pref preference, char *label, char *file, int line );
-#else
-void *Hunk_Alloc( int size, ha_pref preference );
-#endif
-
-#define Com_Memset memset
-#define Com_Memcpy memcpy
-
-#define CIN_system 1
-#define CIN_loop 2
-#define CIN_hold 4
-#define CIN_silent 8
-#define CIN_shader 16
-
-/*
-==============================================================
-
-MATHLIB
-
-==============================================================
-*/
-
-
-typedef float vec_t;
-typedef vec_t vec2_t[2];
-typedef vec_t vec3_t[3];
-typedef vec_t vec4_t[4];
-typedef vec_t vec5_t[5];
-
-typedef int fixed4_t;
-typedef int fixed8_t;
-typedef int fixed16_t;
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846f // matches value in gcc v2 math.h
-#endif
-
-#define NUMVERTEXNORMALS 162
-extern vec3_t bytedirs[NUMVERTEXNORMALS];
-
-// all drawing is done to a 640*480 virtual screen size
-// and will be automatically scaled to the real resolution
-#define SCREEN_WIDTH 640
-#define SCREEN_HEIGHT 480
-
-#define TINYCHAR_WIDTH (SMALLCHAR_WIDTH)
-#define TINYCHAR_HEIGHT (SMALLCHAR_HEIGHT/2)
-
-#define SMALLCHAR_WIDTH 8
-#define SMALLCHAR_HEIGHT 16
-
-#define BIGCHAR_WIDTH 16
-#define BIGCHAR_HEIGHT 16
-
-#define GIANTCHAR_WIDTH 32
-#define GIANTCHAR_HEIGHT 48
-
-extern vec4_t colorBlack;
-extern vec4_t colorRed;
-extern vec4_t colorGreen;
-extern vec4_t colorBlue;
-extern vec4_t colorYellow;
-extern vec4_t colorMagenta;
-extern vec4_t colorCyan;
-extern vec4_t colorWhite;
-extern vec4_t colorLtGrey;
-extern vec4_t colorMdGrey;
-extern vec4_t colorDkGrey;
-
-#define Q_COLOR_ESCAPE '^'
-#define Q_IsColorString(p) ((p) && *(p) == Q_COLOR_ESCAPE && *((p)+1) && isalnum(*((p)+1))) // ^[0-9a-zA-Z]
-
-#define COLOR_BLACK '0'
-#define COLOR_RED '1'
-#define COLOR_GREEN '2'
-#define COLOR_YELLOW '3'
-#define COLOR_BLUE '4'
-#define COLOR_CYAN '5'
-#define COLOR_MAGENTA '6'
-#define COLOR_WHITE '7'
-#define ColorIndex(c) (((c) - '0') & 0x07)
-
-#define S_COLOR_BLACK "^0"
-#define S_COLOR_RED "^1"
-#define S_COLOR_GREEN "^2"
-#define S_COLOR_YELLOW "^3"
-#define S_COLOR_BLUE "^4"
-#define S_COLOR_CYAN "^5"
-#define S_COLOR_MAGENTA "^6"
-#define S_COLOR_WHITE "^7"
-
-extern vec4_t g_color_table[8];
-
-#define MAKERGB( v, r, g, b ) v[0]=r;v[1]=g;v[2]=b
-#define MAKERGBA( v, r, g, b, a ) v[0]=r;v[1]=g;v[2]=b;v[3]=a
-
-#define DEG2RAD( a ) ( ( (a) * M_PI ) / 180.0F )
-#define RAD2DEG( a ) ( ( (a) * 180.0f ) / M_PI )
-
-struct cplane_s;
-
-extern vec3_t vec3_origin;
-extern vec3_t axisDefault[3];
-
-#define nanmask (255<<23)
-
-#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
-
-#if idppc
-
-static ID_INLINE float Q_rsqrt( float number ) {
- float x = 0.5f * number;
- float y;
-#ifdef __GNUC__
- asm("frsqrte %0,%1" : "=f" (y) : "f" (number));
-#else
- y = __frsqrte( number );
-#endif
- return y * (1.5f - (x * y * y));
- }
-
-#ifdef __GNUC__
-static ID_INLINE float Q_fabs(float x) {
- float abs_x;
-
- asm("fabs %0,%1" : "=f" (abs_x) : "f" (x));
- return abs_x;
-}
-#else
-#define Q_fabs __fabsf
-#endif
-
-#else
-float Q_fabs( float f );
-float Q_rsqrt( float f ); // reciprocal square root
-#endif
-
-#define SQRTFAST( x ) ( (x) * Q_rsqrt( x ) )
-
-signed char ClampChar( int i );
-signed short ClampShort( int i );
-
-// this isn't a real cheap function to call!
-int DirToByte( vec3_t dir );
-void ByteToDir( int b, vec3_t dir );
-
-#if 1
-
-#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
-#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2])
-#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2])
-#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2])
-#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s))
-#define VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s))
-
-#else
-
-#define DotProduct(x,y) _DotProduct(x,y)
-#define VectorSubtract(a,b,c) _VectorSubtract(a,b,c)
-#define VectorAdd(a,b,c) _VectorAdd(a,b,c)
-#define VectorCopy(a,b) _VectorCopy(a,b)
-#define VectorScale(v, s, o) _VectorScale(v,s,o)
-#define VectorMA(v, s, b, o) _VectorMA(v,s,b,o)
-
-#endif
-
-#ifdef Q3_VM
-#ifdef VectorCopy
-#undef VectorCopy
-// this is a little hack to get more efficient copies in our interpreter
-typedef struct {
- float v[3];
-} vec3struct_t;
-#define VectorCopy(a,b) (*(vec3struct_t *)b=*(vec3struct_t *)a)
-#endif
-#endif
-
-#define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0)
-#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2])
-#define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z))
-#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
-
-#define SnapVector(v) {v[0]=((int)(v[0]));v[1]=((int)(v[1]));v[2]=((int)(v[2]));}
-// just in case you do't want to use the macros
-vec_t _DotProduct( const vec3_t v1, const vec3_t v2 );
-void _VectorSubtract( const vec3_t veca, const vec3_t vecb, vec3_t out );
-void _VectorAdd( const vec3_t veca, const vec3_t vecb, vec3_t out );
-void _VectorCopy( const vec3_t in, vec3_t out );
-void _VectorScale( const vec3_t in, float scale, vec3_t out );
-void _VectorMA( const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc );
-
-unsigned ColorBytes3 (float r, float g, float b);
-unsigned ColorBytes4 (float r, float g, float b, float a);
-
-float NormalizeColor( const vec3_t in, vec3_t out );
-
-float RadiusFromBounds( const vec3_t mins, const vec3_t maxs );
-void ClearBounds( vec3_t mins, vec3_t maxs );
-void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs );
-
-#if !defined( Q3_VM ) || ( defined( Q3_VM ) && defined( __Q3_VM_MATH ) )
-static ID_INLINE int VectorCompare( const vec3_t v1, const vec3_t v2 ) {
- if (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2]) {
- return 0;
- }
- return 1;
-}
-
-static ID_INLINE vec_t VectorLength( const vec3_t v ) {
- return (vec_t)sqrt (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
-}
-
-static ID_INLINE vec_t VectorLengthSquared( const vec3_t v ) {
- return (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
-}
-
-static ID_INLINE vec_t Distance( const vec3_t p1, const vec3_t p2 ) {
- vec3_t v;
-
- VectorSubtract (p2, p1, v);
- return VectorLength( v );
-}
-
-static ID_INLINE vec_t DistanceSquared( const vec3_t p1, const vec3_t p2 ) {
- vec3_t v;
-
- VectorSubtract (p2, p1, v);
- return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
-}
-
-// fast vector normalize routine that does not check to make sure
-// that length != 0, nor does it return length, uses rsqrt approximation
-static ID_INLINE void VectorNormalizeFast( vec3_t v )
-{
- float ilength;
-
- ilength = Q_rsqrt( DotProduct( v, v ) );
-
- v[0] *= ilength;
- v[1] *= ilength;
- v[2] *= ilength;
-}
-
-static ID_INLINE void VectorInverse( vec3_t v ){
- v[0] = -v[0];
- v[1] = -v[1];
- v[2] = -v[2];
-}
-
-static ID_INLINE void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross ) {
- cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
- cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
- cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
-}
-
-#else
-int VectorCompare( const vec3_t v1, const vec3_t v2 );
-
-vec_t VectorLength( const vec3_t v );
-
-vec_t VectorLengthSquared( const vec3_t v );
-
-vec_t Distance( const vec3_t p1, const vec3_t p2 );
-
-vec_t DistanceSquared( const vec3_t p1, const vec3_t p2 );
-
-void VectorNormalizeFast( vec3_t v );
-
-void VectorInverse( vec3_t v );
-
-void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross );
-
-#endif
-
-vec_t VectorNormalize (vec3_t v); // returns vector length
-vec_t VectorNormalize2( const vec3_t v, vec3_t out );
-void Vector4Scale( const vec4_t in, vec_t scale, vec4_t out );
-void VectorRotate( vec3_t in, vec3_t matrix[3], vec3_t out );
-int Q_log2(int val);
-
-float Q_acos(float c);
-
-int Q_rand( int *seed );
-float Q_random( int *seed );
-float Q_crandom( int *seed );
-
-#define random() ((rand () & 0x7fff) / ((float)0x7fff))
-#define crandom() (2.0 * (random() - 0.5))
-
-void vectoangles( const vec3_t value1, vec3_t angles);
-void AnglesToAxis( const vec3_t angles, vec3_t axis[3] );
-
-void AxisClear( vec3_t axis[3] );
-void AxisCopy( vec3_t in[3], vec3_t out[3] );
-
-void SetPlaneSignbits( struct cplane_s *out );
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *plane);
-
-qboolean BoundsIntersect(const vec3_t mins, const vec3_t maxs,
- const vec3_t mins2, const vec3_t maxs2);
-qboolean BoundsIntersectSphere(const vec3_t mins, const vec3_t maxs,
- const vec3_t origin, vec_t radius);
-qboolean BoundsIntersectPoint(const vec3_t mins, const vec3_t maxs,
- const vec3_t origin);
-
-float AngleMod(float a);
-float LerpAngle (float from, float to, float frac);
-float AngleSubtract( float a1, float a2 );
-void AnglesSubtract( vec3_t v1, vec3_t v2, vec3_t v3 );
-
-float AngleNormalize360 ( float angle );
-float AngleNormalize180 ( float angle );
-float AngleDelta ( float angle1, float angle2 );
-
-qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c );
-void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal );
-void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
-void RotateAroundDirection( vec3_t axis[3], float yaw );
-void MakeNormalVectors( const vec3_t forward, vec3_t right, vec3_t up );
-// perpendicular vector could be replaced by this
-
-//int PlaneTypeForNormal (vec3_t normal);
-
-void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]);
-void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
-void PerpendicularVector( vec3_t dst, const vec3_t src );
-int Q_isnan( float x );
-
-
-//=============================================
-
-float Com_Clamp( float min, float max, float value );
-
-char *COM_SkipPath( char *pathname );
-const char *COM_GetExtension( const char *name );
-void COM_StripExtension(const char *in, char *out, int destsize);
-void COM_DefaultExtension( char *path, int maxSize, const char *extension );
-
-void COM_BeginParseSession( const char *name );
-int COM_GetCurrentParseLine( void );
-char *COM_Parse( char **data_p );
-char *COM_ParseExt( char **data_p, qboolean allowLineBreak );
-int COM_Compress( char *data_p );
-void COM_ParseError( char *format, ... ) __attribute__ ((format (printf, 1, 2)));
-void COM_ParseWarning( char *format, ... ) __attribute__ ((format (printf, 1, 2)));
-//int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] );
-
-#define MAX_TOKENLENGTH 1024
-
-#ifndef TT_STRING
-//token types
-#define TT_STRING 1 // string
-#define TT_LITERAL 2 // literal
-#define TT_NUMBER 3 // number
-#define TT_NAME 4 // name
-#define TT_PUNCTUATION 5 // punctuation
-#endif
-
-typedef struct pc_token_s
-{
- int type;
- int subtype;
- int intvalue;
- float floatvalue;
- char string[MAX_TOKENLENGTH];
-} pc_token_t;
-
-// data is an in/out parm, returns a parsed out token
-
-void COM_MatchToken( char**buf_p, char *match );
-
-void SkipBracedSection (char **program);
-void SkipRestOfLine ( char **data );
-
-void Parse1DMatrix (char **buf_p, int x, float *m);
-void Parse2DMatrix (char **buf_p, int y, int x, float *m);
-void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m);
-int Com_HexStrToInt( const char *str );
-
-void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
-
-char *Com_SkipTokens( char *s, int numTokens, char *sep );
-char *Com_SkipCharset( char *s, char *sep );
-
-void Com_RandomBytes( byte *string, int len );
-
-// mode parm for FS_FOpenFile
-typedef enum {
- FS_READ,
- FS_WRITE,
- FS_APPEND,
- FS_APPEND_SYNC
-} fsMode_t;
-
-typedef enum {
- FS_SEEK_CUR,
- FS_SEEK_END,
- FS_SEEK_SET
-} fsOrigin_t;
-
-//=============================================
-
-int Q_isprint( int c );
-int Q_islower( int c );
-int Q_isupper( int c );
-int Q_isalpha( int c );
-qboolean Q_isanumber( const char *s );
-qboolean Q_isintegral( float f );
-
-// portable case insensitive compare
-int Q_stricmp (const char *s1, const char *s2);
-int Q_strncmp (const char *s1, const char *s2, int n);
-int Q_stricmpn (const char *s1, const char *s2, int n);
-char *Q_strlwr( char *s1 );
-char *Q_strupr( char *s1 );
-char *Q_strrchr( const char* string, int c );
-const char *Q_stristr( const char *s, const char *find);
-
-// buffer size safe library replacements
-void Q_strncpyz( char *dest, const char *src, int destsize );
-void Q_strcat( char *dest, int size, const char *src );
-
-// strlen that discounts Quake color sequences
-int Q_PrintStrlen( const char *string );
-// removes color sequences from string
-char *Q_CleanStr( char *string );
-// Count the number of char tocount encountered in string
-int Q_CountChar(const char *string, char tocount);
-
-//=============================================
-
-// 64-bit integers for global rankings interface
-// implemented as a struct for qvm compatibility
-typedef struct
-{
- byte b0;
- byte b1;
- byte b2;
- byte b3;
- byte b4;
- byte b5;
- byte b6;
- byte b7;
-} qint64;
-
-//=============================================
-/*
-short BigShort(short l);
-short LittleShort(short l);
-int BigLong (int l);
-int LittleLong (int l);
-qint64 BigLong64 (qint64 l);
-qint64 LittleLong64 (qint64 l);
-float BigFloat (const float *l);
-float LittleFloat (const float *l);
-
-void Swap_Init (void);
-*/
-char * QDECL va(char *format, ...) __attribute__ ((format (printf, 1, 2)));
-
-#define TRUNCATE_LENGTH 64
-void Com_TruncateLongString( char *buffer, const char *s );
-
-//=============================================
-
-//
-// key / value info strings
-//
-char *Info_ValueForKey( const char *s, const char *key );
-void Info_RemoveKey( char *s, const char *key );
-void Info_RemoveKey_big( char *s, const char *key );
-void Info_SetValueForKey( char *s, const char *key, const char *value );
-void Info_SetValueForKey_Big( char *s, const char *key, const char *value );
-qboolean Info_Validate( const char *s );
-void Info_NextPair( const char **s, char *key, char *value );
-
-// this is only here so the functions in q_shared.c and bg_*.c can link
-void QDECL Com_Error( int level, const char *error, ... ) __attribute__ ((format (printf, 2, 3)));
-void QDECL Com_Printf( const char *msg, ... ) __attribute__ ((format (printf, 1, 2)));
-
-
-/*
-==========================================================
-
-CVARS (console variables)
-
-Many variables can be used for cheating purposes, so when
-cheats is zero, force all unspecified variables to their
-default values.
-==========================================================
-*/
-
-#define CVAR_ARCHIVE 0x0001 // set to cause it to be saved to vars.rc
- // used for system variables, not for player
- // specific configurations
-#define CVAR_USERINFO 0x0002 // sent to server on connect or change
-#define CVAR_SERVERINFO 0x0004 // sent in response to front end requests
-#define CVAR_SYSTEMINFO 0x0008 // these cvars will be duplicated on all clients
-#define CVAR_INIT 0x0010 // don't allow change from console at all,
- // but can be set from the command line
-#define CVAR_LATCH 0x0020 // will only change when C code next does
- // a Cvar_Get(), so it can't be changed
- // without proper initialization. modified
- // will be set, even though the value hasn't
- // changed yet
-#define CVAR_ROM 0x0040 // display only, cannot be set by user at all
-#define CVAR_USER_CREATED 0x0080 // created by a set command
-#define CVAR_TEMP 0x0100 // can be set even when cheats are disabled, but is not archived
-#define CVAR_CHEAT 0x0200 // can not be changed if cheats are disabled
-#define CVAR_NORESTART 0x0400 // do not clear when a cvar_restart is issued
-
-#define CVAR_SERVER_CREATED 0x0800 // cvar was created by a server the client connected to.
-#define CVAR_VM_CREATED 0x1000 // cvar was created exclusively in one of the VMs.
-#define CVAR_NONEXISTENT 0xFFFFFFFF // Cvar doesn't exist.
-
-// nothing outside the Cvar_*() functions should modify these fields!
-typedef struct cvar_s cvar_t;
-
-struct cvar_s {
- char *name;
- char *string;
- char *resetString; // cvar_restart will reset to this value
- char *latchedString; // for CVAR_LATCH vars
- int flags;
- qboolean modified; // set each time the cvar is changed
- int modificationCount; // incremented each time the cvar is changed
- float value; // atof( string )
- int integer; // atoi( string )
- qboolean validate;
- qboolean integral;
- float min;
- float max;
-
- cvar_t *next;
- cvar_t *prev;
- cvar_t *hashNext;
- cvar_t *hashPrev;
- int hashIndex;
-};
-
-#define MAX_CVAR_VALUE_STRING 256
-
-typedef int cvarHandle_t;
-
-// the modules that run in the virtual machine can't access the cvar_t directly,
-// so they must ask for structured updates
-typedef struct {
- cvarHandle_t handle;
- int modificationCount;
- float value;
- int integer;
- char string[MAX_CVAR_VALUE_STRING];
-} vmCvar_t;
-
-/*
-==============================================================
-
-COLLISION DETECTION
-
-==============================================================
-*/
-
-#include "surfaceflags.h" // shared with the q3map utility
-
-// plane types are used to speed some tests
-// 0-2 are axial planes
-#define PLANE_X 0
-#define PLANE_Y 1
-#define PLANE_Z 2
-#define PLANE_NON_AXIAL 3
-
-
-/*
-=================
-PlaneTypeForNormal
-=================
-*/
-
-#define PlaneTypeForNormal(x) (x[0] == 1.0 ? PLANE_X : (x[1] == 1.0 ? PLANE_Y : (x[2] == 1.0 ? PLANE_Z : PLANE_NON_AXIAL) ) )
-
-// plane_t structure
-// !!! if this is changed, it must be changed in asm code too !!!
-typedef struct cplane_s {
- vec3_t normal;
- float dist;
- byte type; // for fast side tests: 0,1,2 = axial, 3 = nonaxial
- byte signbits; // signx + (signy<<1) + (signz<<2), used as lookup during collision
- byte pad[2];
-} cplane_t;
-
-
-// a trace is returned when a box is swept through the world
-typedef struct {
- qboolean allsolid; // if true, plane is not valid
- qboolean startsolid; // if true, the initial point was in a solid area
- float fraction; // time completed, 1.0 = didn't hit anything
- vec3_t endpos; // final position
- cplane_t plane; // surface normal at impact, transformed to world space
- int surfaceFlags; // surface hit
- int contents; // contents on other side of surface hit
- int entityNum; // entity the contacted sirface is a part of
-} trace_t;
-
-// trace->entityNum can also be 0 to (MAX_GENTITIES-1)
-// or ENTITYNUM_NONE, ENTITYNUM_WORLD
-
-
-// markfragments are returned by CM_MarkFragments()
-typedef struct {
- int firstPoint;
- int numPoints;
-} markFragment_t;
-
-
-
-typedef struct {
- vec3_t origin;
- vec3_t axis[3];
-} orientation_t;
-
-//=====================================================================
-
-
-// in order from highest priority to lowest
-// if none of the catchers are active, bound key strings will be executed
-#define KEYCATCH_CONSOLE 0x0001
-#define KEYCATCH_UI 0x0002
-#define KEYCATCH_MESSAGE 0x0004
-#define KEYCATCH_CGAME 0x0008
-
-
-// sound channels
-// channel 0 never willingly overrides
-// other channels will allways override a playing sound on that channel
-typedef enum {
- CHAN_AUTO,
- CHAN_LOCAL, // menu sounds, etc
- CHAN_WEAPON,
- CHAN_VOICE,
- CHAN_ITEM,
- CHAN_BODY,
- CHAN_LOCAL_SOUND, // chat messages, etc
- CHAN_ANNOUNCER // announcer voices, etc
-} soundChannel_t;
-
-
-/*
-========================================================================
-
- ELEMENTS COMMUNICATED ACROSS THE NET
-
-========================================================================
-*/
-
-#define ANGLE2SHORT(x) ((int)((x)*65536/360) & 65535)
-#define SHORT2ANGLE(x) ((x)*(360.0/65536))
-
-#define SNAPFLAG_RATE_DELAYED 1
-#define SNAPFLAG_NOT_ACTIVE 2 // snapshot used during connection and for zombies
-#define SNAPFLAG_SERVERCOUNT 4 // toggled every map_restart so transitions can be detected
-
-//
-// per-level limits
-//
-#define MAX_CLIENTS 64 // absolute limit
-#define MAX_LOCATIONS 64
-
-#define GENTITYNUM_BITS 10 // don't need to send any more
-#define MAX_GENTITIES (1<<GENTITYNUM_BITS)
-
-// entitynums are communicated with GENTITY_BITS, so any reserved
-// values that are going to be communcated over the net need to
-// also be in this range
-#define ENTITYNUM_NONE (MAX_GENTITIES-1)
-#define ENTITYNUM_WORLD (MAX_GENTITIES-2)
-#define ENTITYNUM_MAX_NORMAL (MAX_GENTITIES-2)
-
-
-#define MAX_MODELS 256 // these are sent over the net as 8 bits
-#define MAX_SOUNDS 256 // so they cannot be blindly increased
-
-
-#define MAX_CONFIGSTRINGS 1024
-
-// these are the only configstrings that the system reserves, all the
-// other ones are strictly for servergame to clientgame communication
-#define CS_SERVERINFO 0 // an info string with all the serverinfo cvars
-#define CS_SYSTEMINFO 1 // an info string for server system to client system configuration (timescale, etc)
-
-#define RESERVED_CONFIGSTRINGS 2 // game can't modify below this, only the system can
-
-#define MAX_GAMESTATE_CHARS 16000
-typedef struct {
- int stringOffsets[MAX_CONFIGSTRINGS];
- char stringData[MAX_GAMESTATE_CHARS];
- int dataCount;
-} gameState_t;
-
-//=========================================================
-
-// bit field limits
-#define MAX_STATS 16
-#define MAX_PERSISTANT 16
-#define MAX_POWERUPS 16
-#define MAX_WEAPONS 16
-
-#define MAX_PS_EVENTS 2
-
-#define PS_PMOVEFRAMECOUNTBITS 6
-
-// playerState_t is the information needed by both the client and server
-// to predict player motion and actions
-// nothing outside of pmove should modify these, or some degree of prediction error
-// will occur
-
-// you can't add anything to this without modifying the code in msg.c
-
-// playerState_t is a full superset of entityState_t as it is used by players,
-// so if a playerState_t is transmitted, the entityState_t can be fully derived
-// from it.
-typedef struct playerState_s {
- int commandTime; // cmd->serverTime of last executed command
- int pm_type;
- int bobCycle; // for view bobbing and footstep generation
- int pm_flags; // ducked, jump_held, etc
- int pm_time;
-
- vec3_t origin;
- vec3_t velocity;
- int weaponTime;
- int gravity;
- int speed;
- int delta_angles[3]; // add to command angles to get view direction
- // changed by spawns, rotating objects, and teleporters
-
- int groundEntityNum;// ENTITYNUM_NONE = in air
-
- int legsTimer; // don't change low priority animations until this runs out
- int legsAnim; // mask off ANIM_TOGGLEBIT
-
- int torsoTimer; // don't change low priority animations until this runs out
- int torsoAnim; // mask off ANIM_TOGGLEBIT
-
- int movementDir; // a number 0 to 7 that represents the reletive angle
- // of movement to the view angle (axial and diagonals)
- // when at rest, the value will remain unchanged
- // used to twist the legs during strafing
-
- vec3_t grapplePoint; // location of grapple to pull towards if PMF_GRAPPLE_PULL
-
- int eFlags; // copied to entityState_t->eFlags
-
- int eventSequence; // pmove generated events
- int events[MAX_PS_EVENTS];
- int eventParms[MAX_PS_EVENTS];
-
- int externalEvent; // events set on player from another source
- int externalEventParm;
- int externalEventTime;
-
- int clientNum; // ranges from 0 to MAX_CLIENTS-1
- int weapon; // copied to entityState_t->weapon
- int weaponstate;
-
- vec3_t viewangles; // for fixed views
- int viewheight;
-
- // damage feedback
- int damageEvent; // when it changes, latch the other parms
- int damageYaw;
- int damagePitch;
- int damageCount;
-
- int stats[MAX_STATS];
- int persistant[MAX_PERSISTANT]; // stats that aren't cleared on death
- int powerups[MAX_POWERUPS]; // level.time that the powerup runs out
- int ammo[MAX_WEAPONS];
-
- int generic1;
- int loopSound;
- int jumppad_ent; // jumppad entity hit this frame
-
- // not communicated over the net at all
- int ping; // server to game info for scoreboard
- int pmove_framecount; // FIXME: don't transmit over the network
- int jumppad_frame;
- int entityEventSequence;
-} playerState_t;
-
-
-//====================================================================
-
-
-//
-// usercmd_t->button bits, many of which are generated by the client system,
-// so they aren't game/cgame only definitions
-//
-#define BUTTON_ATTACK 1
-#define BUTTON_TALK 2 // displays talk balloon and disables actions
-#define BUTTON_USE_HOLDABLE 4
-#define BUTTON_GESTURE 8
-#define BUTTON_WALKING 16 // walking can't just be infered from MOVE_RUN
- // because a key pressed late in the frame will
- // only generate a small move value for that frame
- // walking will use different animations and
- // won't generate footsteps
-#define BUTTON_AFFIRMATIVE 32
-#define BUTTON_NEGATIVE 64
-
-#define BUTTON_GETFLAG 128
-#define BUTTON_GUARDBASE 256
-#define BUTTON_PATROL 512
-#define BUTTON_FOLLOWME 1024
-
-#define BUTTON_ANY 2048 // any key whatsoever
-
-#define MOVE_RUN 120 // if forwardmove or rightmove are >= MOVE_RUN,
- // then BUTTON_WALKING should be set
-
-// usercmd_t is sent to the server each client frame
-typedef struct usercmd_s {
- int serverTime;
- int angles[3];
- int buttons;
- byte weapon; // weapon
- signed char forwardmove, rightmove, upmove;
-} usercmd_t;
-
-//===================================================================
-
-// if entityState->solid == SOLID_BMODEL, modelindex is an inline model number
-#define SOLID_BMODEL 0xffffff
-
-typedef enum {
- TR_STATIONARY,
- TR_INTERPOLATE, // non-parametric, but interpolate between snapshots
- TR_LINEAR,
- TR_LINEAR_STOP,
- TR_SINE, // value = base + sin( time / duration ) * delta
- TR_GRAVITY
-} trType_t;
-
-typedef struct {
- trType_t trType;
- int trTime;
- int trDuration; // if non 0, trTime + trDuration = stop time
- vec3_t trBase;
- vec3_t trDelta; // velocity, etc
-} trajectory_t;
-
-// entityState_t is the information conveyed from the server
-// in an update message about entities that the client will
-// need to render in some way
-// Different eTypes may use the information in different ways
-// The messages are delta compressed, so it doesn't really matter if
-// the structure size is fairly large
-
-typedef struct entityState_s {
- int number; // entity index
- int eType; // entityType_t
- int eFlags;
-
- trajectory_t pos; // for calculating position
- trajectory_t apos; // for calculating angles
-
- int time;
- int time2;
-
- vec3_t origin;
- vec3_t origin2;
-
- vec3_t angles;
- vec3_t angles2;
-
- int otherEntityNum; // shotgun sources, etc
- int otherEntityNum2;
-
- int groundEntityNum; // -1 = in air
-
- int constantLight; // r + (g<<8) + (b<<16) + (intensity<<24)
- int loopSound; // constantly loop this sound
-
- int modelindex;
- int modelindex2;
- int clientNum; // 0 to (MAX_CLIENTS - 1), for players and corpses
- int frame;
-
- int solid; // for client side prediction, trap_linkentity sets this properly
-
- int event; // impulse events -- muzzle flashes, footsteps, etc
- int eventParm;
-
- // for players
- int powerups; // bit flags
- int weapon; // determines weapon and flash model, etc
- int legsAnim; // mask off ANIM_TOGGLEBIT
- int torsoAnim; // mask off ANIM_TOGGLEBIT
-
- int generic1;
-} entityState_t;
-
-typedef enum {
- CA_UNINITIALIZED,
- CA_DISCONNECTED, // not talking to a server
- CA_AUTHORIZING, // not used any more, was checking cd key
- CA_CONNECTING, // sending request packets to the server
- CA_CHALLENGING, // sending challenge packets to the server
- CA_CONNECTED, // netchan_t established, getting gamestate
- CA_LOADING, // only during cgame initialization, never during main loop
- CA_PRIMED, // got gamestate, waiting for first frame
- CA_ACTIVE, // game views should be displayed
- CA_CINEMATIC // playing a cinematic or a static pic, not connected to a server
-} connstate_t;
-
-// font support
-
-#define GLYPH_START 0
-#define GLYPH_END 255
-#define GLYPH_CHARSTART 32
-#define GLYPH_CHAREND 127
-#define GLYPHS_PER_FONT GLYPH_END - GLYPH_START + 1
-typedef struct {
- int height; // number of scan lines
- int top; // top of glyph in buffer
- int bottom; // bottom of glyph in buffer
- int pitch; // width for copying
- int xSkip; // x adjustment
- int imageWidth; // width of actual image
- int imageHeight; // height of actual image
- float s; // x offset in image where glyph starts
- float t; // y offset in image where glyph starts
- float s2;
- float t2;
- qhandle_t glyph; // handle to the shader with the glyph
- char shaderName[32];
-} glyphInfo_t;
-
-typedef struct {
- glyphInfo_t glyphs [GLYPHS_PER_FONT];
- float glyphScale;
- char name[MAX_QPATH];
-} fontInfo_t;
-
-#define Square(x) ((x)*(x))
-
-// real time
-//=============================================
-
-
-typedef struct qtime_s {
- int tm_sec; /* seconds after the minute - [0,59] */
- int tm_min; /* minutes after the hour - [0,59] */
- int tm_hour; /* hours since midnight - [0,23] */
- int tm_mday; /* day of the month - [1,31] */
- int tm_mon; /* months since January - [0,11] */
- int tm_year; /* years since 1900 */
- int tm_wday; /* days since Sunday - [0,6] */
- int tm_yday; /* days since January 1 - [0,365] */
- int tm_isdst; /* daylight savings time flag */
-} qtime_t;
-
-
-// server browser sources
-// TTimo: AS_MPLAYER is no longer used
-#define AS_LOCAL 0
-#define AS_MPLAYER 1
-#define AS_GLOBAL 2
-#define AS_FAVORITES 3
-
-
-// cinematic states
-typedef enum {
- FMV_IDLE,
- FMV_PLAY, // play
- FMV_EOF, // all other conditions, i.e. stop/EOF/abort
- FMV_ID_BLT,
- FMV_ID_IDLE,
- FMV_LOOPED,
- FMV_ID_WAIT
-} e_status;
-
-typedef enum _flag_status {
- FLAG_ATBASE = 0,
- FLAG_TAKEN, // CTF
- FLAG_TAKEN_RED, // One Flag CTF
- FLAG_TAKEN_BLUE, // One Flag CTF
- FLAG_DROPPED
-} flagStatus_t;
-
-
-
-#define MAX_GLOBAL_SERVERS 4096
-#define MAX_OTHER_SERVERS 128
-#define MAX_PINGREQUESTS 32
-#define MAX_SERVERSTATUSREQUESTS 16
-
-#define SAY_ALL 0
-#define SAY_TEAM 1
-#define SAY_TELL 2
-
-#define CDKEY_LEN 16
-#define CDCHKSUM_LEN 2
-
-
-#endif // __Q_SHARED_H
diff --git a/engine/code/qcommon/qcommon.h b/engine/code/qcommon/qcommon.h
deleted file mode 100644
index de1dba0..0000000
--- a/engine/code/qcommon/qcommon.h
+++ /dev/null
@@ -1,1167 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// qcommon.h -- definitions common between client and server, but not game.or ref modules
-#ifndef _QCOMMON_H_
-#define _QCOMMON_H_
-
-#include "../qcommon/cm_public.h"
-
-//Ignore __attribute__ on non-gcc platforms
-#ifndef __GNUC__
-#ifndef __attribute__
-#define __attribute__(x)
-#endif
-#endif
-
-//#define PRE_RELEASE_DEMO
-
-//============================================================================
-
-//
-// msg.c
-//
-typedef struct {
- qboolean allowoverflow; // if false, do a Com_Error
- qboolean overflowed; // set to true if the buffer size failed (with allowoverflow set)
- qboolean oob; // set to true if the buffer size failed (with allowoverflow set)
- byte *data;
- int maxsize;
- int cursize;
- int readcount;
- int bit; // for bitwise reads and writes
-} msg_t;
-
-void MSG_Init (msg_t *buf, byte *data, int length);
-void MSG_InitOOB( msg_t *buf, byte *data, int length );
-void MSG_Clear (msg_t *buf);
-void MSG_WriteData (msg_t *buf, const void *data, int length);
-void MSG_Bitstream( msg_t *buf );
-
-// TTimo
-// copy a msg_t in case we need to store it as is for a bit
-// (as I needed this to keep an msg_t from a static var for later use)
-// sets data buffer as MSG_Init does prior to do the copy
-void MSG_Copy(msg_t *buf, byte *data, int length, msg_t *src);
-
-struct usercmd_s;
-struct entityState_s;
-struct playerState_s;
-
-void MSG_WriteBits( msg_t *msg, int value, int bits );
-
-void MSG_WriteChar (msg_t *sb, int c);
-void MSG_WriteByte (msg_t *sb, int c);
-void MSG_WriteShort (msg_t *sb, int c);
-void MSG_WriteLong (msg_t *sb, int c);
-void MSG_WriteFloat (msg_t *sb, float f);
-void MSG_WriteString (msg_t *sb, const char *s);
-void MSG_WriteBigString (msg_t *sb, const char *s);
-void MSG_WriteAngle16 (msg_t *sb, float f);
-int MSG_HashKey(const char *string, int maxlen);
-
-void MSG_BeginReading (msg_t *sb);
-void MSG_BeginReadingOOB(msg_t *sb);
-
-int MSG_ReadBits( msg_t *msg, int bits );
-
-int MSG_ReadChar (msg_t *sb);
-int MSG_ReadByte (msg_t *sb);
-int MSG_ReadShort (msg_t *sb);
-int MSG_ReadLong (msg_t *sb);
-float MSG_ReadFloat (msg_t *sb);
-char *MSG_ReadString (msg_t *sb);
-char *MSG_ReadBigString (msg_t *sb);
-char *MSG_ReadStringLine (msg_t *sb);
-float MSG_ReadAngle16 (msg_t *sb);
-void MSG_ReadData (msg_t *sb, void *buffer, int size);
-int MSG_LookaheadByte (msg_t *msg);
-
-void MSG_WriteDeltaUsercmd( msg_t *msg, struct usercmd_s *from, struct usercmd_s *to );
-void MSG_ReadDeltaUsercmd( msg_t *msg, struct usercmd_s *from, struct usercmd_s *to );
-
-void MSG_WriteDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to );
-void MSG_ReadDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to );
-
-void MSG_WriteDeltaEntity( msg_t *msg, struct entityState_s *from, struct entityState_s *to
- , qboolean force );
-void MSG_ReadDeltaEntity( msg_t *msg, entityState_t *from, entityState_t *to,
- int number );
-
-void MSG_WriteDeltaPlayerstate( msg_t *msg, struct playerState_s *from, struct playerState_s *to );
-void MSG_ReadDeltaPlayerstate( msg_t *msg, struct playerState_s *from, struct playerState_s *to );
-
-
-void MSG_ReportChangeVectors_f( void );
-
-//============================================================================
-
-/*
-==============================================================
-
-NET
-
-==============================================================
-*/
-
-#define NET_ENABLEV4 0x01
-#define NET_ENABLEV6 0x02
-// if this flag is set, always attempt ipv6 connections instead of ipv4 if a v6 address is found.
-#define NET_PRIOV6 0x04
-// disables ipv6 multicast support if set.
-#define NET_DISABLEMCAST 0x08
-
-
-#define PACKET_BACKUP 32 // number of old messages that must be kept on client and
- // server for delta comrpession and ping estimation
-#define PACKET_MASK (PACKET_BACKUP-1)
-
-#define MAX_PACKET_USERCMDS 32 // max number of usercmd_t in a packet
-
-#define PORT_ANY -1
-
-#define MAX_RELIABLE_COMMANDS 64 // max string commands buffered for restransmit
-
-typedef enum {
- NA_BAD = 0, // an address lookup failed
- NA_BOT,
- NA_LOOPBACK,
- NA_BROADCAST,
- NA_IP,
- NA_IP6,
- NA_MULTICAST6,
- NA_UNSPEC
-} netadrtype_t;
-
-typedef enum {
- NS_CLIENT,
- NS_SERVER
-} netsrc_t;
-
-#define NET_ADDRSTRMAXLEN 48 // maximum length of an IPv6 address string including trailing '\0'
-typedef struct {
- netadrtype_t type;
-
- byte ip[4];
- byte ip6[16];
-
- unsigned short port;
- unsigned long scope_id; // Needed for IPv6 link-local addresses
-} netadr_t;
-
-void NET_Init( void );
-void NET_Shutdown( void );
-void NET_Restart_f( void );
-void NET_Config( qboolean enableNetworking );
-void NET_FlushPacketQueue(void);
-void NET_SendPacket (netsrc_t sock, int length, const void *data, netadr_t to);
-void QDECL NET_OutOfBandPrint( netsrc_t net_socket, netadr_t adr, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
-void QDECL NET_OutOfBandData( netsrc_t sock, netadr_t adr, byte *format, int len );
-
-qboolean NET_CompareAdr (netadr_t a, netadr_t b);
-qboolean NET_CompareBaseAdrMask(netadr_t a, netadr_t b, int netmask);
-qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b);
-qboolean NET_IsLocalAddress (netadr_t adr);
-const char *NET_AdrToString (netadr_t a);
-const char *NET_AdrToStringwPort (netadr_t a);
-int NET_StringToAdr ( const char *s, netadr_t *a, netadrtype_t family);
-qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, msg_t *net_message);
-void NET_JoinMulticast6(void);
-void NET_LeaveMulticast6(void);
-void NET_Sleep(int msec);
-
-
-#define MAX_MSGLEN 16384 // max length of a message, which may
- // be fragmented into multiple packets
-
-#define MAX_DOWNLOAD_WINDOW 8 // max of eight download frames
-#define MAX_DOWNLOAD_BLKSIZE 2048 // 2048 byte block chunks
-
-
-/*
-Netchan handles packet fragmentation and out of order / duplicate suppression
-*/
-
-typedef struct {
- netsrc_t sock;
-
- int dropped; // between last packet and previous
-
- netadr_t remoteAddress;
- int qport; // qport value to write when transmitting
-
- // sequencing variables
- int incomingSequence;
- int outgoingSequence;
-
- // incoming fragment assembly buffer
- int fragmentSequence;
- int fragmentLength;
- byte fragmentBuffer[MAX_MSGLEN];
-
- // outgoing fragment buffer
- // we need to space out the sending of large fragmented messages
- qboolean unsentFragments;
- int unsentFragmentStart;
- int unsentLength;
- byte unsentBuffer[MAX_MSGLEN];
-} netchan_t;
-
-void Netchan_Init( int qport );
-void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport );
-
-void Netchan_Transmit( netchan_t *chan, int length, const byte *data );
-void Netchan_TransmitNextFragment( netchan_t *chan );
-
-qboolean Netchan_Process( netchan_t *chan, msg_t *msg );
-
-
-/*
-==============================================================
-
-PROTOCOL
-
-==============================================================
-*/
-
-#define PROTOCOL_VERSION 68
-// 1.31 - 67
-
-// maintain a list of compatible protocols for demo playing
-// NOTE: that stuff only works with two digits protocols
-extern int demo_protocols[];
-
-#define UPDATE_SERVER_NAME "update.quake3arena.com"
-// override on command line, config files etc.
-#ifndef MASTER_SERVER_NAME
-#define MASTER_SERVER_NAME "master.quake3arena.com"
-#endif
-
-#ifndef STANDALONE
- #ifndef AUTHORIZE_SERVER_NAME
- #define AUTHORIZE_SERVER_NAME "authorize.quake3arena.com"
- #endif
- #ifndef PORT_AUTHORIZE
- #define PORT_AUTHORIZE 27952
- #endif
-#endif
-
-#define PORT_MASTER 27950
-#define PORT_UPDATE 27951
-#define PORT_SERVER 27960
-#define NUM_SERVER_PORTS 4 // broadcast scan this many ports after
- // PORT_SERVER so a single machine can
- // run multiple servers
-
-
-// the svc_strings[] array in cl_parse.c should mirror this
-//
-// server to client
-//
-enum svc_ops_e {
- svc_bad,
- svc_nop,
- svc_gamestate,
- svc_configstring, // [short] [string] only in gamestate messages
- svc_baseline, // only in gamestate messages
- svc_serverCommand, // [string] to be executed by client game module
- svc_download, // [short] size [size bytes]
- svc_snapshot,
- svc_EOF,
-
- // svc_extension follows a svc_EOF, followed by another svc_* ...
- // this keeps legacy clients compatible.
- svc_extension,
- svc_voip, // not wrapped in USE_VOIP, so this value is reserved.
-};
-
-
-//
-// client to server
-//
-enum clc_ops_e {
- clc_bad,
- clc_nop,
- clc_move, // [[usercmd_t]
- clc_moveNoDelta, // [[usercmd_t]
- clc_clientCommand, // [string] message
- clc_EOF,
-
- // clc_extension follows a clc_EOF, followed by another clc_* ...
- // this keeps legacy servers compatible.
- clc_extension,
- clc_voip, // not wrapped in USE_VOIP, so this value is reserved.
-};
-
-/*
-==============================================================
-
-VIRTUAL MACHINE
-
-==============================================================
-*/
-
-typedef struct vm_s vm_t;
-
-typedef enum {
- VMI_NATIVE,
- VMI_BYTECODE,
- VMI_COMPILED
-} vmInterpret_t;
-
-typedef enum {
- TRAP_MEMSET = 100,
- TRAP_MEMCPY,
- TRAP_STRNCPY,
- TRAP_SIN,
- TRAP_COS,
- TRAP_ATAN2,
- TRAP_SQRT,
- TRAP_MATRIXMULTIPLY,
- TRAP_ANGLEVECTORS,
- TRAP_PERPENDICULARVECTOR,
- TRAP_FLOOR,
- TRAP_CEIL,
-
- TRAP_TESTPRINTINT,
- TRAP_TESTPRINTFLOAT
-} sharedTraps_t;
-
-void VM_Init( void );
-vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *),
- vmInterpret_t interpret );
-// module should be bare: "cgame", not "cgame.dll" or "vm/cgame.qvm"
-
-void VM_Free( vm_t *vm );
-void VM_Clear(void);
-void VM_Forced_Unload_Start(void);
-void VM_Forced_Unload_Done(void);
-vm_t *VM_Restart( vm_t *vm );
-
-intptr_t QDECL VM_Call( vm_t *vm, int callNum, ... );
-
-void VM_Debug( int level );
-
-void *VM_ArgPtr( intptr_t intValue );
-void *VM_ExplicitArgPtr( vm_t *vm, intptr_t intValue );
-
-#define VMA(x) VM_ArgPtr(args[x])
-static ID_INLINE float _vmf(intptr_t x)
-{
- floatint_t fi;
- fi.i = (int) x;
- return fi.f;
-}
-#define VMF(x) _vmf(args[x])
-
-
-/*
-==============================================================
-
-CMD
-
-Command text buffering 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 entire text
-files can be execed.
-
-*/
-
-void Cbuf_Init (void);
-// allocates an initial text buffer that will grow as needed
-
-void Cbuf_AddText( const char *text );
-// Adds command text at the end of the buffer, does NOT add a final \n
-
-void Cbuf_ExecuteText( int exec_when, const char *text );
-// this can be used in place of either Cbuf_AddText or Cbuf_InsertText
-
-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, or current args will be destroyed.
-
-//===========================================================================
-
-/*
-
-Command execution takes a null terminated string, breaks it into tokens,
-then searches for a command or variable that matches the first token.
-
-*/
-
-typedef void (*xcommand_t) (void);
-
-void Cmd_Init (void);
-
-void Cmd_AddCommand( const 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
-// if function is NULL, the command will be forwarded to the server
-// as a clc_clientCommand instead of executed locally
-
-void Cmd_RemoveCommand( const char *cmd_name );
-
-typedef void (*completionFunc_t)( char *args, int argNum );
-
-void Cmd_CommandCompletion( void(*callback)(const char *s) );
-// callback with each valid string
-void Cmd_SetCommandCompletionFunc( const char *command,
- completionFunc_t complete );
-void Cmd_CompleteArgument( const char *command, char *args, int argNum );
-void Cmd_CompleteCfgName( char *args, int argNum );
-
-int Cmd_Argc (void);
-char *Cmd_Argv (int arg);
-void Cmd_ArgvBuffer( int arg, char *buffer, int bufferLength );
-char *Cmd_Args (void);
-char *Cmd_ArgsFrom( int arg );
-void Cmd_ArgsBuffer( char *buffer, int bufferLength );
-char *Cmd_Cmd (void);
-void Cmd_Args_Sanitize( 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.
-
-void Cmd_TokenizeString( const char *text );
-void Cmd_TokenizeStringIgnoreQuotes( const char *text_in );
-// Takes a null terminated string. Does not need to be /n terminated.
-// breaks the string up into arg tokens.
-
-void Cmd_ExecuteString( const char *text );
-// Parses a single line of text into arguments and tries to execute it
-// as if it was typed at the console
-
-
-/*
-==============================================================
-
-CVAR
-
-==============================================================
-*/
-
-/*
-
-cvar_t variables are used to hold scalar or string variables that can be changed
-or displayed at the console or prog code as well as accessed directly
-in C code.
-
-The user can access cvars from the console in three ways:
-r_draworder prints the current value
-r_draworder 0 sets the current value to 0
-set r_draworder 0 as above, but creates the cvar if not present
-
-Cvars are restricted from having the same names as commands to keep this
-interface from being ambiguous.
-
-The are also occasionally used to communicated information between different
-modules of the program.
-
-*/
-
-cvar_t *Cvar_Get( const char *var_name, const char *value, int flags );
-// creates the variable if it doesn't exist, or returns the existing one
-// if it exists, the value will not be changed, but flags will be ORed in
-// that allows variables to be unarchived without needing bitflags
-// if value is "", the value will not override a previously set value.
-
-void Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
-// basically a slightly modified Cvar_Get for the interpreted modules
-
-void Cvar_Update( vmCvar_t *vmCvar );
-// updates an interpreted modules' version of a cvar
-
-void Cvar_Set( const char *var_name, const char *value );
-// will create the variable with no flags if it doesn't exist
-
-void Cvar_SetLatched( const char *var_name, const char *value);
-// don't set the cvar immediately
-
-void Cvar_SetValue( const char *var_name, float value );
-// expands value to a string and calls Cvar_Set
-
-float Cvar_VariableValue( const char *var_name );
-int Cvar_VariableIntegerValue( const char *var_name );
-// returns 0 if not defined or non numeric
-
-char *Cvar_VariableString( const char *var_name );
-void Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-// returns an empty string if not defined
-
-int Cvar_Flags(const char *var_name);
-// returns CVAR_NONEXISTENT if cvar doesn't exist or the flags of that particular CVAR.
-
-void Cvar_CommandCompletion( void(*callback)(const char *s) );
-// callback with each valid string
-
-void Cvar_Reset( const char *var_name );
-void Cvar_ForceReset(const char *var_name);
-
-void Cvar_SetCheatState( void );
-// reset all testing vars to a safe value
-
-qboolean Cvar_Command( void );
-// called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known
-// command. Returns true if the command was a variable reference that
-// was handled. (print or change)
-
-void Cvar_WriteVariables( fileHandle_t f );
-// writes lines containing "set variable value" for all variables
-// with the archive flag set to true.
-
-void Cvar_Init( void );
-
-char *Cvar_InfoString( int bit );
-char *Cvar_InfoString_Big( int bit );
-// returns an info string containing all the cvars that have the given bit set
-// in their flags ( CVAR_USERINFO, CVAR_SERVERINFO, CVAR_SYSTEMINFO, etc )
-void Cvar_InfoStringBuffer( int bit, char *buff, int buffsize );
-void Cvar_CheckRange( cvar_t *cv, float minVal, float maxVal, qboolean shouldBeIntegral );
-
-void Cvar_Restart(qboolean unsetVM);
-void Cvar_Restart_f( void );
-
-void Cvar_CompleteCvarName( char *args, int argNum );
-
-extern int cvar_modifiedFlags;
-// whenever a cvar is modifed, its flags will be OR'd into this, so
-// a single check can determine if any CVAR_USERINFO, CVAR_SERVERINFO,
-// etc, variables have been modified since the last check. The bit
-// can then be cleared to allow another change detection.
-
-/*
-==============================================================
-
-FILESYSTEM
-
-No stdio calls should be used by any part of the game, because
-we need to deal with all sorts of directory and seperator char
-issues.
-==============================================================
-*/
-
-// referenced flags
-// these are in loop specific order so don't change the order
-#define FS_GENERAL_REF 0x01
-#define FS_UI_REF 0x02
-#define FS_CGAME_REF 0x04
-#define FS_QAGAME_REF 0x08
-// number of id paks that will never be autodownloaded from baseq3
-#define NUM_ID_PAKS 9
-
-#define MAX_FILE_HANDLES 64
-
-#ifdef DEDICATED
-# define Q3CONFIG_CFG "q3config_server.cfg"
-#else
-# define Q3CONFIG_CFG "q3config.cfg"
-#endif
-
-qboolean FS_Initialized( void );
-
-void FS_InitFilesystem ( void );
-void FS_Shutdown( qboolean closemfp );
-
-qboolean FS_ConditionalRestart( int checksumFeed );
-void FS_Restart( int checksumFeed );
-// shutdown and restart the filesystem so changes to fs_gamedir can take effect
-
-void FS_AddGameDirectory( const char *path, const char *dir );
-
-char **FS_ListFiles( const char *directory, const char *extension, int *numfiles );
-// directory should not have either a leading or trailing /
-// if extension is "/", only subdirectories will be returned
-// the returned files will not include any directories or /
-
-void FS_FreeFileList( char **list );
-
-qboolean FS_FileExists( const char *file );
-
-qboolean FS_CreatePath (char *OSPath);
-char *FS_BuildOSPath( const char *base, const char *game, const char *qpath );
-qboolean FS_CompareZipChecksum(const char *zipfile);
-
-int FS_LoadStack( void );
-
-int FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
-int FS_GetModList( char *listbuf, int bufsize );
-
-fileHandle_t FS_FOpenFileWrite( const char *qpath );
-fileHandle_t FS_FOpenFileAppend( const char *filename );
-// will properly create any needed paths and deal with seperater character issues
-
-fileHandle_t FS_SV_FOpenFileWrite( const char *filename );
-int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp );
-void FS_SV_Rename( const char *from, const char *to );
-int FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFILE );
-// if uniqueFILE is true, then a new FILE will be fopened even if the file
-// is found in an already open pak file. If uniqueFILE is false, you must call
-// FS_FCloseFile instead of fclose, otherwise the pak FILE would be improperly closed
-// It is generally safe to always set uniqueFILE to true, because the majority of
-// file IO goes through FS_ReadFile, which Does The Right Thing already.
-
-int FS_FileIsInPAK(const char *filename, int *pChecksum );
-// returns 1 if a file is in the PAK file, otherwise -1
-
-int FS_Write( const void *buffer, int len, fileHandle_t f );
-
-int FS_Read2( void *buffer, int len, fileHandle_t f );
-int FS_Read( void *buffer, int len, fileHandle_t f );
-// properly handles partial reads and reads from other dlls
-
-void FS_FCloseFile( fileHandle_t f );
-// note: you can't just fclose from another DLL, due to MS libc issues
-
-int FS_ReadFile( const char *qpath, void **buffer );
-// returns the length of the file
-// a null buffer will just return the file length without loading
-// as a quick check for existance. -1 length == not present
-// A 0 byte will always be appended at the end, so string ops are safe.
-// the buffer should be considered read-only, because it may be cached
-// for other uses.
-
-void FS_ForceFlush( fileHandle_t f );
-// forces flush on files we're writing to.
-
-void FS_FreeFile( void *buffer );
-// frees the memory returned by FS_ReadFile
-
-void FS_WriteFile( const char *qpath, const void *buffer, int size );
-// writes a complete file, creating any subdirectories needed
-
-int FS_filelength( fileHandle_t f );
-// doesn't work for files that are opened from a pack file
-
-int FS_FTell( fileHandle_t f );
-// where are we?
-
-void FS_Flush( fileHandle_t f );
-
-void QDECL FS_Printf( fileHandle_t f, const char *fmt, ... ) __attribute__ ((format (printf, 2, 3)));
-// like fprintf
-
-int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode );
-// opens a file for reading, writing, or appending depending on the value of mode
-
-int FS_Seek( fileHandle_t f, long offset, int origin );
-// seek on a file (doesn't work for zip files!!!!!!!!)
-
-qboolean FS_FilenameCompare( const char *s1, const char *s2 );
-
-const char *FS_GamePureChecksum( void );
-// Returns the checksum of the pk3 from which the server loaded the qagame.qvm
-
-const char *FS_LoadedPakNames( void );
-const char *FS_LoadedPakChecksums( void );
-const char *FS_LoadedPakPureChecksums( void );
-// Returns a space separated string containing the checksums of all loaded pk3 files.
-// Servers with sv_pure set will get this string and pass it to clients.
-
-const char *FS_ReferencedPakNames( void );
-const char *FS_ReferencedPakChecksums( void );
-const char *FS_ReferencedPakPureChecksums( void );
-// Returns a space separated string containing the checksums of all loaded
-// AND referenced pk3 files. Servers with sv_pure set will get this string
-// back from clients for pure validation
-
-void FS_ClearPakReferences( int flags );
-// clears referenced booleans on loaded pk3s
-
-void FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames );
-void FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames );
-// If the string is empty, all data sources will be allowed.
-// If not empty, only pk3 files that match one of the space
-// separated checksums will be checked for files, with the
-// sole exception of .cfg files.
-
-qboolean FS_CheckDirTraversal(const char *checkdir);
-qboolean FS_idPak( char *pak, char *base );
-qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring );
-
-void FS_Rename( const char *from, const char *to );
-
-void FS_Remove( const char *osPath );
-void FS_HomeRemove( const char *homePath );
-
-void FS_FilenameCompletion( const char *dir, const char *ext,
- qboolean stripExt, void(*callback)(const char *s) );
-
-/*
-==============================================================
-
-Edit fields and command line history/completion
-
-==============================================================
-*/
-
-#define MAX_EDIT_LINE 256
-typedef struct {
- int cursor;
- int scroll;
- int widthInChars;
- char buffer[MAX_EDIT_LINE];
-} field_t;
-
-void Field_Clear( field_t *edit );
-void Field_AutoComplete( field_t *edit );
-void Field_CompleteKeyname( void );
-void Field_CompleteFilename( const char *dir,
- const char *ext, qboolean stripExt );
-void Field_CompleteCommand( char *cmd,
- qboolean doCommands, qboolean doCvars );
-
-/*
-==============================================================
-
-MISC
-
-==============================================================
-*/
-
-// centralizing the declarations for cl_cdkey
-// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=470
-extern char cl_cdkey[34];
-
-// returned by Sys_GetProcessorFeatures
-typedef enum
-{
- CF_RDTSC = 1 << 0,
- CF_MMX = 1 << 1,
- CF_MMX_EXT = 1 << 2,
- CF_3DNOW = 1 << 3,
- CF_3DNOW_EXT = 1 << 4,
- CF_SSE = 1 << 5,
- CF_SSE2 = 1 << 6,
- CF_ALTIVEC = 1 << 7
-} cpuFeatures_t;
-
-// centralized and cleaned, that's the max string you can send to a Com_Printf / Com_DPrintf (above gets truncated)
-#define MAXPRINTMSG 4096
-
-
-typedef enum {
- // SE_NONE must be zero
- SE_NONE = 0, // evTime is still valid
- SE_KEY, // evValue is a key code, evValue2 is the down flag
- SE_CHAR, // evValue is an ascii char
- SE_MOUSE, // evValue and evValue2 are reletive signed x / y moves
- SE_JOYSTICK_AXIS, // evValue is an axis number and evValue2 is the current state (-127 to 127)
- SE_CONSOLE, // evPtr is a char*
- SE_PACKET // evPtr is a netadr_t followed by data bytes to evPtrLength
-} sysEventType_t;
-
-typedef struct {
- int evTime;
- sysEventType_t evType;
- int evValue, evValue2;
- int evPtrLength; // bytes of data pointed to by evPtr, for journaling
- void *evPtr; // this must be manually freed if not NULL
-} sysEvent_t;
-
-void Com_QueueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr );
-int Com_EventLoop( void );
-sysEvent_t Com_GetSystemEvent( void );
-
-char *CopyString( const char *in );
-void Info_Print( const char *s );
-
-void Com_BeginRedirect (char *buffer, int buffersize, void (*flush)(char *));
-void Com_EndRedirect( void );
-void QDECL Com_Printf( const char *fmt, ... ) __attribute__ ((format (printf, 1, 2)));
-void QDECL Com_DPrintf( const char *fmt, ... ) __attribute__ ((format (printf, 1, 2)));
-void QDECL Com_Error( int code, const char *fmt, ... ) __attribute__ ((format (printf, 2, 3)));
-void Com_Quit_f( void );
-void Com_GameRestart(int checksumFeed, qboolean clientRestart);
-
-int Com_Milliseconds( void ); // will be journaled properly
-unsigned Com_BlockChecksum( const void *buffer, int length );
-char *Com_MD5File(const char *filename, int length, const char *prefix, int prefix_len);
-int Com_Filter(char *filter, char *name, int casesensitive);
-int Com_FilterPath(char *filter, char *name, int casesensitive);
-int Com_RealTime(qtime_t *qtime);
-qboolean Com_SafeMode( void );
-
-void Com_StartupVariable( const char *match );
-// checks for and removes command line "+set var arg" constructs
-// if match is NULL, all set commands will be executed, otherwise
-// only a set with the exact name. Only used during startup.
-
-
-extern cvar_t *com_developer;
-extern cvar_t *com_dedicated;
-extern cvar_t *com_speeds;
-extern cvar_t *com_timescale;
-extern cvar_t *com_sv_running;
-extern cvar_t *com_cl_running;
-extern cvar_t *com_version;
-extern cvar_t *com_blood;
-extern cvar_t *com_buildScript; // for building release pak files
-extern cvar_t *com_journal;
-extern cvar_t *com_cameraMode;
-extern cvar_t *com_ansiColor;
-extern cvar_t *com_unfocused;
-extern cvar_t *com_maxfpsUnfocused;
-extern cvar_t *com_minimized;
-extern cvar_t *com_maxfpsMinimized;
-extern cvar_t *com_altivec;
-
-// both client and server must agree to pause
-extern cvar_t *cl_paused;
-extern cvar_t *sv_paused;
-
-extern cvar_t *cl_packetdelay;
-extern cvar_t *sv_packetdelay;
-
-// com_speeds times
-extern int time_game;
-extern int time_frontend;
-extern int time_backend; // renderer backend time
-
-extern int com_frameTime;
-extern int com_frameMsec;
-
-extern qboolean com_errorEntered;
-
-extern fileHandle_t com_journalFile;
-extern fileHandle_t com_journalDataFile;
-
-typedef enum {
- TAG_FREE,
- TAG_GENERAL,
- TAG_BOTLIB,
- TAG_RENDERER,
- TAG_SMALL,
- TAG_STATIC
-} memtag_t;
-
-/*
-
---- low memory ----
-server vm
-server clipmap
----mark---
-renderer initialization (shaders, etc)
-UI vm
-cgame vm
-renderer map
-renderer models
-
----free---
-
-temp file loading
---- high memory ---
-
-*/
-
-#if defined(_DEBUG) && !defined(BSPC)
- #define ZONE_DEBUG
-#endif
-
-#ifdef ZONE_DEBUG
-#define Z_TagMalloc(size, tag) Z_TagMallocDebug(size, tag, #size, __FILE__, __LINE__)
-#define Z_Malloc(size) Z_MallocDebug(size, #size, __FILE__, __LINE__)
-#define S_Malloc(size) S_MallocDebug(size, #size, __FILE__, __LINE__)
-void *Z_TagMallocDebug( int size, int tag, char *label, char *file, int line ); // NOT 0 filled memory
-void *Z_MallocDebug( int size, char *label, char *file, int line ); // returns 0 filled memory
-void *S_MallocDebug( int size, char *label, char *file, int line ); // returns 0 filled memory
-#else
-void *Z_TagMalloc( int size, int tag ); // NOT 0 filled memory
-void *Z_Malloc( int size ); // returns 0 filled memory
-void *S_Malloc( int size ); // NOT 0 filled memory only for small allocations
-#endif
-void Z_Free( void *ptr );
-void Z_FreeTags( int tag );
-int Z_AvailableMemory( void );
-void Z_LogHeap( void );
-
-void Hunk_Clear( void );
-void Hunk_ClearToMark( void );
-void Hunk_SetMark( void );
-qboolean Hunk_CheckMark( void );
-void Hunk_ClearTempMemory( void );
-void *Hunk_AllocateTempMemory( int size );
-void Hunk_FreeTempMemory( void *buf );
-int Hunk_MemoryRemaining( void );
-void Hunk_Log( void);
-void Hunk_Trash( void );
-
-void Com_TouchMemory( void );
-
-// commandLine should not include the executable name (argv[0])
-void Com_Init( char *commandLine );
-void Com_Frame( void );
-void Com_Shutdown( void );
-
-
-/*
-==============================================================
-
-CLIENT / SERVER SYSTEMS
-
-==============================================================
-*/
-
-//
-// client interface
-//
-void CL_InitKeyCommands( void );
-// the keyboard binding interface must be setup before execing
-// config files, but the rest of client startup will happen later
-
-void CL_Init( void );
-void CL_Disconnect( qboolean showMainMenu );
-void CL_Shutdown( void );
-void CL_Frame( int msec );
-qboolean CL_GameCommand( void );
-void CL_KeyEvent (int key, qboolean down, unsigned time);
-
-void CL_CharEvent( int key );
-// char events are for field typing, not game control
-
-void CL_MouseEvent( int dx, int dy, int time );
-
-void CL_JoystickEvent( int axis, int value, int time );
-
-void CL_PacketEvent( netadr_t from, msg_t *msg );
-
-void CL_ConsolePrint( char *text );
-
-void CL_MapLoading( void );
-// do a screen update before starting to load a map
-// when the server is going to load a new map, the entire hunk
-// will be cleared, so the client must shutdown cgame, ui, and
-// the renderer
-
-void CL_ForwardCommandToServer( const char *string );
-// adds the current command line as a clc_clientCommand 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 CL_CDDialog( void );
-// bring up the "need a cd to play" dialog
-
-void CL_ShutdownAll( void );
-// shutdown all the client stuff
-
-void CL_FlushMemory( void );
-// dump all memory on an error
-
-void CL_StartHunkUsers( qboolean rendererOnly );
-// start all the client stuff using the hunk
-
-void CL_Snd_Restart(void);
-// Restart sound subsystem
-
-void Key_KeynameCompletion( void(*callback)(const char *s) );
-// for keyname autocompletion
-
-void Key_WriteBindings( fileHandle_t f );
-// for writing the config files
-
-void S_ClearSoundBuffer( void );
-// call before filesystem access
-
-void SCR_DebugGraph (float value, int color); // FIXME: move logging to common?
-
-//
-// server interface
-//
-void SV_Init( void );
-void SV_Shutdown( char *finalmsg );
-void SV_Frame( int msec );
-void SV_PacketEvent( netadr_t from, msg_t *msg );
-qboolean SV_GameCommand( void );
-
-
-//
-// UI interface
-//
-qboolean UI_GameCommand( void );
-qboolean UI_usesUniqueCDKey(void);
-
-/*
-==============================================================
-
-NON-PORTABLE SYSTEM SERVICES
-
-==============================================================
-*/
-
-typedef enum {
- AXIS_SIDE,
- AXIS_FORWARD,
- AXIS_UP,
- AXIS_ROLL,
- AXIS_YAW,
- AXIS_PITCH,
- MAX_JOYSTICK_AXIS
-} joystickAxis_t;
-
-void Sys_Init (void);
-
-// general development dll loading for virtual machine testing
-void * QDECL Sys_LoadDll( const char *name, char *fqpath , intptr_t (QDECL **entryPoint)(int, ...),
- intptr_t (QDECL *systemcalls)(intptr_t, ...) );
-void Sys_UnloadDll( void *dllHandle );
-
-void Sys_UnloadGame( void );
-void *Sys_GetGameAPI( void *parms );
-
-void Sys_UnloadCGame( void );
-void *Sys_GetCGameAPI( void );
-
-void Sys_UnloadUI( void );
-void *Sys_GetUIAPI( void );
-
-//bot libraries
-void Sys_UnloadBotLib( void );
-void *Sys_GetBotLibAPI( void *parms );
-
-char *Sys_GetCurrentUser( void );
-
-void QDECL Sys_Error( const char *error, ...) __attribute__ ((format (printf, 1, 2)));
-void Sys_Quit (void);
-char *Sys_GetClipboardData( void ); // note that this isn't journaled...
-
-void Sys_Print( const char *msg );
-
-// Sys_Milliseconds should only be used for profiling purposes,
-// any game related timing information should come from event timestamps
-int Sys_Milliseconds (void);
-
-void Sys_SnapVector( float *v );
-
-qboolean Sys_RandomBytes( byte *string, int len );
-
-// the system console is shown when a dedicated server is running
-void Sys_DisplaySystemConsole( qboolean show );
-
-cpuFeatures_t Sys_GetProcessorFeatures( void );
-
-void Sys_SetErrorText( const char *text );
-
-void Sys_SendPacket( int length, const void *data, netadr_t to );
-qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message );
-
-qboolean Sys_StringToAdr( const char *s, netadr_t *a, netadrtype_t family );
-//Does NOT parse port numbers, only base addresses.
-
-qboolean Sys_IsLANAddress (netadr_t adr);
-void Sys_ShowIP(void);
-
-qboolean Sys_Mkdir( const char *path );
-char *Sys_Cwd( void );
-void Sys_SetDefaultInstallPath(const char *path);
-char *Sys_DefaultInstallPath(void);
-
-#ifdef MACOS_X
-char *Sys_DefaultAppPath(void);
-#endif
-
-void Sys_SetDefaultHomePath(const char *path);
-char *Sys_DefaultHomePath(void);
-const char *Sys_Dirname( char *path );
-const char *Sys_Basename( char *path );
-char *Sys_ConsoleInput(void);
-
-char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs );
-void Sys_FreeFileList( char **list );
-void Sys_Sleep(int msec);
-
-qboolean Sys_LowPhysicalMemory( void );
-
-void Sys_SetEnv(const char *name, const char *value);
-
-/* This is based on the Adaptive Huffman algorithm described in Sayood's Data
- * Compression book. The ranks are not actually stored, but implicitly defined
- * by the location of a node within a doubly-linked list */
-
-#define NYT HMAX /* NYT = Not Yet Transmitted */
-#define INTERNAL_NODE (HMAX+1)
-
-typedef struct nodetype {
- struct nodetype *left, *right, *parent; /* tree structure */
- struct nodetype *next, *prev; /* doubly-linked list */
- struct nodetype **head; /* highest ranked node in block */
- int weight;
- int symbol;
-} node_t;
-
-#define HMAX 256 /* Maximum symbol */
-
-typedef struct {
- int blocNode;
- int blocPtrs;
-
- node_t* tree;
- node_t* lhead;
- node_t* ltail;
- node_t* loc[HMAX+1];
- node_t** freelist;
-
- node_t nodeList[768];
- node_t* nodePtrs[768];
-} huff_t;
-
-typedef struct {
- huff_t compressor;
- huff_t decompressor;
-} huffman_t;
-
-void Huff_Compress(msg_t *buf, int offset);
-void Huff_Decompress(msg_t *buf, int offset);
-void Huff_Init(huffman_t *huff);
-void Huff_addRef(huff_t* huff, byte ch);
-int Huff_Receive (node_t *node, int *ch, byte *fin);
-void Huff_transmit (huff_t *huff, int ch, byte *fout);
-void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset);
-void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset);
-void Huff_putBit( int bit, byte *fout, int *offset);
-int Huff_getBit( byte *fout, int *offset);
-
-// don't use if you don't know what you're doing.
-int Huff_getBloc(void);
-void Huff_setBloc(int _bloc);
-
-
-extern huffman_t clientHuffTables;
-
-#define SV_ENCODE_START 4
-#define SV_DECODE_START 12
-#define CL_ENCODE_START 12
-#define CL_DECODE_START 4
-
-// flags for sv_allowDownload and cl_allowDownload
-#define DLF_ENABLE 1
-#define DLF_NO_REDIRECT 2
-#define DLF_NO_UDP 4
-#define DLF_NO_DISCONNECT 8
-
-#endif // _QCOMMON_H_
diff --git a/engine/code/qcommon/unzip.c b/engine/code/qcommon/unzip.c
deleted file mode 100644
index d0b3d2a..0000000
--- a/engine/code/qcommon/unzip.c
+++ /dev/null
@@ -1,1621 +0,0 @@
-/* unzip.c -- IO for uncompress .zip files using zlib
- Version 1.01e, February 12th, 2005
-
- Copyright (C) 1998-2005 Gilles Vollant
-
- Read unzip.h for more info
-*/
-
-/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of
-compatibility with older software. The following is from the original crypt.c. Code
-woven in by Terry Thorsen 1/2003.
-*/
-/*
- Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
-
- See the accompanying file LICENSE, version 2000-Apr-09 or later
- (the contents of which are also included in zip.h) for terms of use.
- If, for some reason, all these files are missing, the Info-ZIP license
- also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
-*/
-/*
- crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h]
-
- The encryption/decryption parts of this source code (as opposed to the
- non-echoing password parts) were originally written in Europe. The
- whole source package can be freely distributed, including from the USA.
- (Prior to January 2000, re-export from the US was a violation of US law.)
- */
-
-/*
- This encryption code is a direct transcription of the algorithm from
- Roger Schlafly, described by Phil Katz in the file appnote.txt. This
- file (appnote.txt) is distributed with the PKZIP program (even in the
- version without encryption capabilities).
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "unzip.h"
-
-#ifdef STDC
-# include <stddef.h>
-# include <string.h>
-# include <stdlib.h>
-#endif
-#ifdef NO_ERRNO_H
- extern int errno;
-#else
-# include <errno.h>
-#endif
-
-
-#ifndef local
-# define local static
-#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
-
-
-#ifndef CASESENSITIVITYDEFAULT_NO
-# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)
-# define CASESENSITIVITYDEFAULT_NO
-# endif
-#endif
-
-
-#ifndef UNZ_BUFSIZE
-#define UNZ_BUFSIZE (16384)
-#endif
-
-#ifndef UNZ_MAXFILENAMEINZIP
-#define UNZ_MAXFILENAMEINZIP (256)
-#endif
-
-#ifndef ALLOC
-# define ALLOC(size) (malloc(size))
-#endif
-#ifndef TRYFREE
-# define TRYFREE(p) {if (p) free(p);}
-#endif
-
-#define SIZECENTRALDIRITEM (0x2e)
-#define SIZEZIPLOCALHEADER (0x1e)
-
-
-
-
-const char unz_copyright[] =
- " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
-
-/* unz_file_info_interntal contain internal info about a file in zipfile*/
-typedef struct unz_file_info_internal_s
-{
- uLong offset_curfile;/* relative offset of local header 4 bytes */
-} unz_file_info_internal;
-
-
-/* file_in_zip_read_info_s contain internal information about a file in zipfile,
- when reading and decompress it */
-typedef struct
-{
- char *read_buffer; /* internal buffer for compressed data */
- z_stream stream; /* zLib stream structure for inflate */
-
- uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
- uLong stream_initialised; /* flag set if stream structure is initialised*/
-
- uLong offset_local_extrafield;/* offset of the local extra field */
- uInt size_local_extrafield;/* size of the local extra field */
- uLong pos_local_extrafield; /* position in the local extra field in read*/
-
- uLong crc32; /* crc32 of all data uncompressed */
- uLong crc32_wait; /* crc32 we must obtain after decompress all */
- uLong rest_read_compressed; /* number of byte to be decompressed */
- uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/
- zlib_filefunc_def z_filefunc;
- voidpf filestream; /* io structore of the zipfile */
- uLong compression_method; /* compression method (0==store) */
- uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
- int raw;
-} file_in_zip_read_info_s;
-
-
-/* unz_s contain internal information about the zipfile
-*/
-typedef struct
-{
- zlib_filefunc_def z_filefunc;
- voidpf filestream; /* io structore of the zipfile */
- unz_global_info gi; /* public global information */
- uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
- uLong num_file; /* number of the current file in the zipfile*/
- uLong pos_in_central_dir; /* pos of the current file in the central dir*/
- uLong current_file_ok; /* flag about the usability of the current file*/
- uLong central_pos; /* position of the beginning of the central dir*/
-
- uLong size_central_dir; /* size of the central directory */
- uLong offset_central_dir; /* offset of start of central directory with
- respect to the starting disk number */
-
- unz_file_info cur_file_info; /* public info about the current file in zip*/
- unz_file_info_internal cur_file_info_internal; /* private info about it*/
- file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current
- file if we are decompressing it */
- int encrypted;
-# ifndef NOUNCRYPT
- unsigned long keys[3]; /* keys defining the pseudo-random sequence */
- const unsigned long* pcrc_32_tab;
-# endif
-} unz_s;
-
-
-#ifndef NOUNCRYPT
-#include "crypt.h"
-#endif
-
-/* ===========================================================================
- Read a byte from a gz_stream; update next_in and avail_in. Return EOF
- for end of file.
- IN assertion: the stream s has been sucessfully opened for reading.
-*/
-
-
-local int unzlocal_getByte OF((
- const zlib_filefunc_def* pzlib_filefunc_def,
- voidpf filestream,
- int *pi));
-
-local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi)
- const zlib_filefunc_def* pzlib_filefunc_def;
- voidpf filestream;
- int *pi;
-{
- unsigned char c;
- int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1);
- if (err==1)
- {
- *pi = (int)c;
- return UNZ_OK;
- }
- else
- {
- if (ZERROR(*pzlib_filefunc_def,filestream))
- return UNZ_ERRNO;
- else
- return UNZ_EOF;
- }
-}
-
-
-/* ===========================================================================
- Reads a long in LSB order from the given gz_stream. Sets
-*/
-local int unzlocal_getShort OF((
- const zlib_filefunc_def* pzlib_filefunc_def,
- voidpf filestream,
- uLong *pX));
-
-local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX)
- const zlib_filefunc_def* pzlib_filefunc_def;
- voidpf filestream;
- uLong *pX;
-{
- uLong x ;
- int i = 0;
- int err;
-
- err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
- x = (uLong)i;
-
- if (err==UNZ_OK)
- err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
- x += ((uLong)i)<<8;
-
- if (err==UNZ_OK)
- *pX = x;
- else
- *pX = 0;
- return err;
-}
-
-local int unzlocal_getLong OF((
- const zlib_filefunc_def* pzlib_filefunc_def,
- voidpf filestream,
- uLong *pX));
-
-local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX)
- const zlib_filefunc_def* pzlib_filefunc_def;
- voidpf filestream;
- uLong *pX;
-{
- uLong x ;
- int i = 0;
- int err;
-
- err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
- x = (uLong)i;
-
- if (err==UNZ_OK)
- err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
- x += ((uLong)i)<<8;
-
- if (err==UNZ_OK)
- err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
- x += ((uLong)i)<<16;
-
- if (err==UNZ_OK)
- err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
- x += ((uLong)i)<<24;
-
- if (err==UNZ_OK)
- *pX = x;
- else
- *pX = 0;
- return err;
-}
-
-local int strcmpcasenosensitive_internal OF((
- const char* fileName1,
- const char* fileName2));
-
-/* My own strcmpi / strcasecmp */
-local int strcmpcasenosensitive_internal (fileName1,fileName2)
- const char* fileName1;
- const char* fileName2;
-{
- for (;;)
- {
- char c1=*(fileName1++);
- char c2=*(fileName2++);
- if ((c1>='a') && (c1<='z'))
- c1 -= 0x20;
- if ((c2>='a') && (c2<='z'))
- c2 -= 0x20;
- if (c1=='\0')
- return ((c2=='\0') ? 0 : -1);
- if (c2=='\0')
- return 1;
- if (c1<c2)
- return -1;
- if (c1>c2)
- return 1;
- }
-}
-
-
-#ifdef CASESENSITIVITYDEFAULT_NO
-#define CASESENSITIVITYDEFAULTVALUE 2
-#else
-#define CASESENSITIVITYDEFAULTVALUE 1
-#endif
-
-#ifndef STRCMPCASENOSENTIVEFUNCTION
-#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
-#endif
-
-/*
- Compare two filename (fileName1,fileName2).
- If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
- If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
- or strcasecmp)
- If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
- (like 1 on Unix, 2 on Windows)
-
-*/
-extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity)
- const char* fileName1;
- const char* fileName2;
- int iCaseSensitivity;
-{
- if (iCaseSensitivity==0)
- iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
-
- if (iCaseSensitivity==1)
- return strcmp(fileName1,fileName2);
-
- return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
-}
-
-#ifndef BUFREADCOMMENT
-#define BUFREADCOMMENT (0x400)
-#endif
-
-/*
- Locate the Central directory of a zipfile (at the end, just before
- the global comment)
-*/
-local uLong unzlocal_SearchCentralDir OF((
- const zlib_filefunc_def* pzlib_filefunc_def,
- voidpf filestream));
-
-local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream)
- const zlib_filefunc_def* pzlib_filefunc_def;
- voidpf filestream;
-{
- unsigned char* buf;
- uLong uSizeFile;
- uLong uBackRead;
- uLong uMaxBack=0xffff; /* maximum size of global comment */
- uLong uPosFound=0;
-
- if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
- return 0;
-
-
- uSizeFile = ZTELL(*pzlib_filefunc_def,filestream);
-
- if (uMaxBack>uSizeFile)
- uMaxBack = uSizeFile;
-
- buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
- if (buf==NULL)
- return 0;
-
- uBackRead = 4;
- while (uBackRead<uMaxBack)
- {
- uLong uReadSize,uReadPos ;
- int i;
- if (uBackRead+BUFREADCOMMENT>uMaxBack)
- uBackRead = uMaxBack;
- else
- uBackRead+=BUFREADCOMMENT;
- uReadPos = uSizeFile-uBackRead ;
-
- uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
- (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
- if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
- break;
-
- if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
- break;
-
- for (i=(int)uReadSize-3; (i--)>0;)
- if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
- ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
- {
- uPosFound = uReadPos+i;
- break;
- }
-
- if (uPosFound!=0)
- break;
- }
- TRYFREE(buf);
- return uPosFound;
-}
-
-/*
- Open a Zip file. path contain the full pathname (by example,
- on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer
- "zlib/zlib114.zip".
- If the zipfile cannot be opened (file doesn't exist or in not valid), the
- return value is NULL.
- Else, the return value is a unzFile Handle, usable with other function
- of this unzip package.
-*/
-extern unzFile ZEXPORT unzOpen2 (path, pzlib_filefunc_def)
- const char *path;
- zlib_filefunc_def* pzlib_filefunc_def;
-{
- unz_s us;
- unz_s *s;
- uLong central_pos,uL;
-
- uLong number_disk; /* number of the current dist, used for
- spaning ZIP, unsupported, always 0*/
- uLong number_disk_with_CD; /* number the the disk with central dir, used
- for spaning ZIP, unsupported, always 0*/
- uLong number_entry_CD; /* total number of entries in
- the central dir
- (same than number_entry on nospan) */
-
- int err=UNZ_OK;
-
- if (unz_copyright[0]!=' ')
- return NULL;
-
- if (pzlib_filefunc_def==NULL)
- fill_fopen_filefunc(&us.z_filefunc);
- else
- us.z_filefunc = *pzlib_filefunc_def;
-
- us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque,
- path,
- ZLIB_FILEFUNC_MODE_READ |
- ZLIB_FILEFUNC_MODE_EXISTING);
- if (us.filestream==NULL)
- return NULL;
-
- central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream);
- if (central_pos==0)
- err=UNZ_ERRNO;
-
- if (ZSEEK(us.z_filefunc, us.filestream,
- central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
- err=UNZ_ERRNO;
-
- /* the signature, already checked */
- if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
- err=UNZ_ERRNO;
-
- /* number of this disk */
- if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
- err=UNZ_ERRNO;
-
- /* number of the disk with the start of the central directory */
- if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
- err=UNZ_ERRNO;
-
- /* total number of entries in the central dir on this disk */
- if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK)
- err=UNZ_ERRNO;
-
- /* total number of entries in the central dir */
- if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK)
- err=UNZ_ERRNO;
-
- if ((number_entry_CD!=us.gi.number_entry) ||
- (number_disk_with_CD!=0) ||
- (number_disk!=0))
- err=UNZ_BADZIPFILE;
-
- /* size of the central directory */
- if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK)
- err=UNZ_ERRNO;
-
- /* offset of start of central directory with respect to the
- starting disk number */
- if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK)
- err=UNZ_ERRNO;
-
- /* zipfile comment length */
- if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK)
- err=UNZ_ERRNO;
-
- if ((central_pos<us.offset_central_dir+us.size_central_dir) &&
- (err==UNZ_OK))
- err=UNZ_BADZIPFILE;
-
- if (err!=UNZ_OK)
- {
- ZCLOSE(us.z_filefunc, us.filestream);
- return NULL;
- }
-
- us.byte_before_the_zipfile = central_pos -
- (us.offset_central_dir+us.size_central_dir);
- us.central_pos = central_pos;
- us.pfile_in_zip_read = NULL;
- us.encrypted = 0;
-
-
- s=(unz_s*)ALLOC(sizeof(unz_s));
- *s=us;
- unzGoToFirstFile((unzFile)s);
- return (unzFile)s;
-}
-
-
-extern unzFile ZEXPORT unzOpen (path)
- const char *path;
-{
- return unzOpen2(path, NULL);
-}
-
-/*
- Close a ZipFile opened with unzipOpen.
- If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
- these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
- return UNZ_OK if there is no problem. */
-extern int ZEXPORT unzClose (file)
- unzFile file;
-{
- unz_s* s;
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
-
- if (s->pfile_in_zip_read!=NULL)
- unzCloseCurrentFile(file);
-
- ZCLOSE(s->z_filefunc, s->filestream);
- TRYFREE(s);
- return UNZ_OK;
-}
-
-
-/*
- Write info about the ZipFile in the *pglobal_info structure.
- No preparation of the structure is needed
- return UNZ_OK if there is no problem. */
-extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info)
- unzFile file;
- unz_global_info *pglobal_info;
-{
- unz_s* s;
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
- *pglobal_info=s->gi;
- return UNZ_OK;
-}
-
-
-/*
- Translate date/time from Dos format to tm_unz (readable more easilty)
-*/
-
-local void unzlocal_DosDateToTmuDate OF((
- uLong ulDosDate,
- tm_unz* ptm));
-
-
-local void unzlocal_DosDateToTmuDate (ulDosDate, ptm)
- uLong ulDosDate;
- tm_unz* ptm;
-{
- uLong uDate;
- uDate = (uLong)(ulDosDate>>16);
- ptm->tm_mday = (uInt)(uDate&0x1f) ;
- ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ;
- ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
-
- ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
- ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ;
- ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ;
-}
-
-/*
- Get Info about the current file in the zipfile, with internal only info
-*/
-local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
- unz_file_info *pfile_info,
- unz_file_info_internal
- *pfile_info_internal,
- char *szFileName,
- uLong fileNameBufferSize,
- void *extraField,
- uLong extraFieldBufferSize,
- char *szComment,
- uLong commentBufferSize));
-
-local int unzlocal_GetCurrentFileInfoInternal (file,
- pfile_info,
- pfile_info_internal,
- szFileName, fileNameBufferSize,
- extraField, extraFieldBufferSize,
- szComment, commentBufferSize)
- unzFile file;
- unz_file_info *pfile_info;
- unz_file_info_internal *pfile_info_internal;
- char *szFileName;
- uLong fileNameBufferSize;
- void *extraField;
- uLong extraFieldBufferSize;
- char *szComment;
- uLong commentBufferSize;
-{
- unz_s* s;
- unz_file_info file_info;
- unz_file_info_internal file_info_internal;
- int err=UNZ_OK;
- uLong uMagic;
- long lSeek=0;
-
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
- if (ZSEEK(s->z_filefunc, s->filestream,
- s->pos_in_central_dir+s->byte_before_the_zipfile,
- ZLIB_FILEFUNC_SEEK_SET)!=0)
- err=UNZ_ERRNO;
-
-
- /* we check the magic */
- if (err==UNZ_OK)
- {
- if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
- err=UNZ_ERRNO;
- else if (uMagic!=0x02014b50)
- err=UNZ_BADZIPFILE;
- }
-
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK)
- err=UNZ_ERRNO;
-
- unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
-
- if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)
- err=UNZ_ERRNO;
-
- lSeek+=file_info.size_filename;
- if ((err==UNZ_OK) && (szFileName!=NULL))
- {
- uLong uSizeRead ;
- if (file_info.size_filename<fileNameBufferSize)
- {
- *(szFileName+file_info.size_filename)='\0';
- uSizeRead = file_info.size_filename;
- }
- else
- uSizeRead = fileNameBufferSize;
-
- if ((file_info.size_filename>0) && (fileNameBufferSize>0))
- if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead)
- err=UNZ_ERRNO;
- lSeek -= uSizeRead;
- }
-
-
- if ((err==UNZ_OK) && (extraField!=NULL))
- {
- uLong uSizeRead ;
- if (file_info.size_file_extra<extraFieldBufferSize)
- uSizeRead = file_info.size_file_extra;
- else
- uSizeRead = extraFieldBufferSize;
-
- if (lSeek!=0)
- {
- if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
- lSeek=0;
- else
- err=UNZ_ERRNO;
- }
- if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
- if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead)
- err=UNZ_ERRNO;
- lSeek += file_info.size_file_extra - uSizeRead;
- }
- else
- lSeek+=file_info.size_file_extra;
-
-
- if ((err==UNZ_OK) && (szComment!=NULL))
- {
- uLong uSizeRead ;
- if (file_info.size_file_comment<commentBufferSize)
- {
- *(szComment+file_info.size_file_comment)='\0';
- uSizeRead = file_info.size_file_comment;
- }
- else
- uSizeRead = commentBufferSize;
-
- if (lSeek!=0)
- {
- if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
- lSeek=0;
- else
- err=UNZ_ERRNO;
- }
- if ((file_info.size_file_comment>0) && (commentBufferSize>0))
- if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
- err=UNZ_ERRNO;
- lSeek+=file_info.size_file_comment - uSizeRead;
- }
- else
- lSeek+=file_info.size_file_comment;
-
- if ((err==UNZ_OK) && (pfile_info!=NULL))
- *pfile_info=file_info;
-
- if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
- *pfile_info_internal=file_info_internal;
-
- return err;
-}
-
-
-
-/*
- Write info about the ZipFile in the *pglobal_info structure.
- No preparation of the structure is needed
- return UNZ_OK if there is no problem.
-*/
-extern int ZEXPORT unzGetCurrentFileInfo (file,
- pfile_info,
- szFileName, fileNameBufferSize,
- extraField, extraFieldBufferSize,
- szComment, commentBufferSize)
- unzFile file;
- unz_file_info *pfile_info;
- char *szFileName;
- uLong fileNameBufferSize;
- void *extraField;
- uLong extraFieldBufferSize;
- char *szComment;
- uLong commentBufferSize;
-{
- return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,
- szFileName,fileNameBufferSize,
- extraField,extraFieldBufferSize,
- szComment,commentBufferSize);
-}
-
-/*
- Set the current file of the zipfile to the first file.
- return UNZ_OK if there is no problem
-*/
-extern int ZEXPORT unzGoToFirstFile (file)
- unzFile file;
-{
- int err=UNZ_OK;
- unz_s* s;
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
- s->pos_in_central_dir=s->offset_central_dir;
- s->num_file=0;
- err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
- &s->cur_file_info_internal,
- NULL,0,NULL,0,NULL,0);
- s->current_file_ok = (err == UNZ_OK);
- return err;
-}
-
-/*
- Set the current file of the zipfile to the next file.
- return UNZ_OK if there is no problem
- return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
-*/
-extern int ZEXPORT unzGoToNextFile (file)
- unzFile file;
-{
- unz_s* s;
- int err;
-
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
- if (!s->current_file_ok)
- return UNZ_END_OF_LIST_OF_FILE;
- if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */
- if (s->num_file+1==s->gi.number_entry)
- return UNZ_END_OF_LIST_OF_FILE;
-
- s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
- s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
- s->num_file++;
- err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
- &s->cur_file_info_internal,
- NULL,0,NULL,0,NULL,0);
- s->current_file_ok = (err == UNZ_OK);
- return err;
-}
-
-
-/*
- Try locate the file szFileName in the zipfile.
- For the iCaseSensitivity signification, see unzipStringFileNameCompare
-
- return value :
- UNZ_OK if the file is found. It becomes the current file.
- UNZ_END_OF_LIST_OF_FILE if the file is not found
-*/
-extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity)
- unzFile file;
- const char *szFileName;
- int iCaseSensitivity;
-{
- unz_s* s;
- int err;
-
- /* We remember the 'current' position in the file so that we can jump
- * back there if we fail.
- */
- unz_file_info cur_file_infoSaved;
- unz_file_info_internal cur_file_info_internalSaved;
- uLong num_fileSaved;
- uLong pos_in_central_dirSaved;
-
-
- if (file==NULL)
- return UNZ_PARAMERROR;
-
- if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
- return UNZ_PARAMERROR;
-
- s=(unz_s*)file;
- if (!s->current_file_ok)
- return UNZ_END_OF_LIST_OF_FILE;
-
- /* Save the current state */
- num_fileSaved = s->num_file;
- pos_in_central_dirSaved = s->pos_in_central_dir;
- cur_file_infoSaved = s->cur_file_info;
- cur_file_info_internalSaved = s->cur_file_info_internal;
-
- err = unzGoToFirstFile(file);
-
- while (err == UNZ_OK)
- {
- char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
- err = unzGetCurrentFileInfo(file,NULL,
- szCurrentFileName,sizeof(szCurrentFileName)-1,
- NULL,0,NULL,0);
- if (err == UNZ_OK)
- {
- if (unzStringFileNameCompare(szCurrentFileName,
- szFileName,iCaseSensitivity)==0)
- return UNZ_OK;
- err = unzGoToNextFile(file);
- }
- }
-
- /* We failed, so restore the state of the 'current file' to where we
- * were.
- */
- s->num_file = num_fileSaved ;
- s->pos_in_central_dir = pos_in_central_dirSaved ;
- s->cur_file_info = cur_file_infoSaved;
- s->cur_file_info_internal = cur_file_info_internalSaved;
- return err;
-}
-
-
-/*
-///////////////////////////////////////////
-// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net)
-// I need random access
-//
-// Further optimization could be realized by adding an ability
-// to cache the directory in memory. The goal being a single
-// comprehensive file read to put the file I need in a memory.
-*/
-
-/*
-typedef struct unz_file_pos_s
-{
- uLong pos_in_zip_directory; // offset in file
- uLong num_of_file; // # of file
-} unz_file_pos;
-*/
-
-extern int ZEXPORT unzGetFilePos(file, file_pos)
- unzFile file;
- unz_file_pos* file_pos;
-{
- unz_s* s;
-
- if (file==NULL || file_pos==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
- if (!s->current_file_ok)
- return UNZ_END_OF_LIST_OF_FILE;
-
- file_pos->pos_in_zip_directory = s->pos_in_central_dir;
- file_pos->num_of_file = s->num_file;
-
- return UNZ_OK;
-}
-
-extern int ZEXPORT unzGoToFilePos(file, file_pos)
- unzFile file;
- unz_file_pos* file_pos;
-{
- unz_s* s;
- int err;
-
- if (file==NULL || file_pos==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
-
- /* jump to the right spot */
- s->pos_in_central_dir = file_pos->pos_in_zip_directory;
- s->num_file = file_pos->num_of_file;
-
- /* set the current file */
- err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
- &s->cur_file_info_internal,
- NULL,0,NULL,0,NULL,0);
- /* return results */
- s->current_file_ok = (err == UNZ_OK);
- return err;
-}
-
-/*
-// Unzip Helper Functions - should be here?
-///////////////////////////////////////////
-*/
-
-/*
- Read the local header of the current zipfile
- Check the coherency of the local header and info in the end of central
- directory about this file
- store in *piSizeVar the size of extra info in local header
- (filename and size of extra field data)
-*/
-
-local int unzlocal_CheckCurrentFileCoherencyHeader OF((
- unz_s* s,
- uInt* piSizeVar,
- uLong *poffset_local_extrafield,
- uInt *psize_local_extrafield));
-
-
-local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,
- poffset_local_extrafield,
- psize_local_extrafield)
- unz_s* s;
- uInt* piSizeVar;
- uLong *poffset_local_extrafield;
- uInt *psize_local_extrafield;
-{
- uLong uMagic,uData,uFlags;
- uLong size_filename;
- uLong size_extra_field;
- int err=UNZ_OK;
-
- *piSizeVar = 0;
- *poffset_local_extrafield = 0;
- *psize_local_extrafield = 0;
-
- if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile +
- s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
- return UNZ_ERRNO;
-
-
- if (err==UNZ_OK)
- {
- if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
- err=UNZ_ERRNO;
- else if (uMagic!=0x04034b50)
- err=UNZ_BADZIPFILE;
- }
-
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
- err=UNZ_ERRNO;
-/*
- else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
- err=UNZ_BADZIPFILE;
-*/
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK)
- err=UNZ_ERRNO;
-
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
- err=UNZ_ERRNO;
- else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
- err=UNZ_BADZIPFILE;
-
- if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
- (s->cur_file_info.compression_method!=Z_DEFLATED))
- err=UNZ_BADZIPFILE;
-
- if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */
- err=UNZ_ERRNO;
-
- if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */
- err=UNZ_ERRNO;
- else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
- ((uFlags & 8)==0))
- err=UNZ_BADZIPFILE;
-
- if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */
- err=UNZ_ERRNO;
- else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
- ((uFlags & 8)==0))
- err=UNZ_BADZIPFILE;
-
- if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */
- err=UNZ_ERRNO;
- else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) &&
- ((uFlags & 8)==0))
- err=UNZ_BADZIPFILE;
-
-
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK)
- err=UNZ_ERRNO;
- else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
- err=UNZ_BADZIPFILE;
-
- *piSizeVar += (uInt)size_filename;
-
- if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK)
- err=UNZ_ERRNO;
- *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
- SIZEZIPLOCALHEADER + size_filename;
- *psize_local_extrafield = (uInt)size_extra_field;
-
- *piSizeVar += (uInt)size_extra_field;
-
- return err;
-}
-
-/*
- Open for reading data the current file in the zipfile.
- If there is no error and the file is opened, the return value is UNZ_OK.
-*/
-extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password)
- unzFile file;
- int* method;
- int* level;
- int raw;
- const char* password;
-{
- int err=UNZ_OK;
- uInt iSizeVar;
- unz_s* s;
- file_in_zip_read_info_s* pfile_in_zip_read_info;
- uLong offset_local_extrafield; /* offset of the local extra field */
- uInt size_local_extrafield; /* size of the local extra field */
-# ifndef NOUNCRYPT
- char source[12];
-# else
- if (password != NULL)
- return UNZ_PARAMERROR;
-# endif
-
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
- if (!s->current_file_ok)
- return UNZ_PARAMERROR;
-
- if (s->pfile_in_zip_read != NULL)
- unzCloseCurrentFile(file);
-
- if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
- &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
- return UNZ_BADZIPFILE;
-
- pfile_in_zip_read_info = (file_in_zip_read_info_s*)
- ALLOC(sizeof(file_in_zip_read_info_s));
- if (pfile_in_zip_read_info==NULL)
- return UNZ_INTERNALERROR;
-
- pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
- pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
- pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
- pfile_in_zip_read_info->pos_local_extrafield=0;
- pfile_in_zip_read_info->raw=raw;
-
- if (pfile_in_zip_read_info->read_buffer==NULL)
- {
- TRYFREE(pfile_in_zip_read_info);
- return UNZ_INTERNALERROR;
- }
-
- pfile_in_zip_read_info->stream_initialised=0;
-
- if (method!=NULL)
- *method = (int)s->cur_file_info.compression_method;
-
- if (level!=NULL)
- {
- *level = 6;
- switch (s->cur_file_info.flag & 0x06)
- {
- case 6 : *level = 1; break;
- case 4 : *level = 2; break;
- case 2 : *level = 9; break;
- }
- }
-
- if ((s->cur_file_info.compression_method!=0) &&
- (s->cur_file_info.compression_method!=Z_DEFLATED))
- err=UNZ_BADZIPFILE;
-
- pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
- pfile_in_zip_read_info->crc32=0;
- pfile_in_zip_read_info->compression_method =
- s->cur_file_info.compression_method;
- pfile_in_zip_read_info->filestream=s->filestream;
- pfile_in_zip_read_info->z_filefunc=s->z_filefunc;
- pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
-
- pfile_in_zip_read_info->stream.total_out = 0;
-
- if ((s->cur_file_info.compression_method==Z_DEFLATED) &&
- (!raw))
- {
- pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
- pfile_in_zip_read_info->stream.zfree = (free_func)0;
- pfile_in_zip_read_info->stream.opaque = (voidpf)0;
- pfile_in_zip_read_info->stream.next_in = (voidpf)0;
- pfile_in_zip_read_info->stream.avail_in = 0;
-
- err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
- if (err == Z_OK)
- pfile_in_zip_read_info->stream_initialised=1;
- else
- {
- TRYFREE(pfile_in_zip_read_info);
- return err;
- }
- /* windowBits is passed < 0 to tell that there is no zlib header.
- * Note that in this case inflate *requires* an extra "dummy" byte
- * after the compressed stream in order to complete decompression and
- * return Z_STREAM_END.
- * In unzip, i don't wait absolutely Z_STREAM_END because I known the
- * size of both compressed and uncompressed data
- */
- }
- pfile_in_zip_read_info->rest_read_compressed =
- s->cur_file_info.compressed_size ;
- pfile_in_zip_read_info->rest_read_uncompressed =
- s->cur_file_info.uncompressed_size ;
-
-
- pfile_in_zip_read_info->pos_in_zipfile =
- s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
- iSizeVar;
-
- pfile_in_zip_read_info->stream.avail_in = (uInt)0;
-
- s->pfile_in_zip_read = pfile_in_zip_read_info;
-
-# ifndef NOUNCRYPT
- if (password != NULL)
- {
- int i;
- s->pcrc_32_tab = get_crc_table();
- init_keys(password,s->keys,s->pcrc_32_tab);
- if (ZSEEK(s->z_filefunc, s->filestream,
- s->pfile_in_zip_read->pos_in_zipfile +
- s->pfile_in_zip_read->byte_before_the_zipfile,
- SEEK_SET)!=0)
- return UNZ_INTERNALERROR;
- if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12)
- return UNZ_INTERNALERROR;
-
- for (i = 0; i<12; i++)
- zdecode(s->keys,s->pcrc_32_tab,source[i]);
-
- s->pfile_in_zip_read->pos_in_zipfile+=12;
- s->encrypted=1;
- }
-# endif
-
-
- return UNZ_OK;
-}
-
-extern int ZEXPORT unzOpenCurrentFile (file)
- unzFile file;
-{
- return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
-}
-
-extern int ZEXPORT unzOpenCurrentFilePassword (file, password)
- unzFile file;
- const char* password;
-{
- return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
-}
-
-extern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw)
- unzFile file;
- int* method;
- int* level;
- int raw;
-{
- return unzOpenCurrentFile3(file, method, level, raw, NULL);
-}
-
-/*
- Read bytes from the current file.
- buf contain buffer where data must be copied
- len the size of buf.
-
- return the number of byte copied if somes bytes are copied
- return 0 if the end of file was reached
- return <0 with error code if there is an error
- (UNZ_ERRNO for IO error, or zLib error for uncompress error)
-*/
-extern int ZEXPORT unzReadCurrentFile (file, buf, len)
- unzFile file;
- voidp buf;
- unsigned len;
-{
- int err=UNZ_OK;
- uInt iRead = 0;
- unz_s* s;
- file_in_zip_read_info_s* pfile_in_zip_read_info;
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
- pfile_in_zip_read_info=s->pfile_in_zip_read;
-
- if (pfile_in_zip_read_info==NULL)
- return UNZ_PARAMERROR;
-
-
- if ((pfile_in_zip_read_info->read_buffer == NULL))
- return UNZ_END_OF_LIST_OF_FILE;
- if (len==0)
- return 0;
-
- pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
-
- pfile_in_zip_read_info->stream.avail_out = (uInt)len;
-
- if ((len>pfile_in_zip_read_info->rest_read_uncompressed) &&
- (!(pfile_in_zip_read_info->raw)))
- pfile_in_zip_read_info->stream.avail_out =
- (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
-
- if ((len>pfile_in_zip_read_info->rest_read_compressed+
- pfile_in_zip_read_info->stream.avail_in) &&
- (pfile_in_zip_read_info->raw))
- pfile_in_zip_read_info->stream.avail_out =
- (uInt)pfile_in_zip_read_info->rest_read_compressed+
- pfile_in_zip_read_info->stream.avail_in;
-
- while (pfile_in_zip_read_info->stream.avail_out>0)
- {
- if ((pfile_in_zip_read_info->stream.avail_in==0) &&
- (pfile_in_zip_read_info->rest_read_compressed>0))
- {
- uInt uReadThis = UNZ_BUFSIZE;
- if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
- uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
- if (uReadThis == 0)
- return UNZ_EOF;
- if (ZSEEK(pfile_in_zip_read_info->z_filefunc,
- pfile_in_zip_read_info->filestream,
- pfile_in_zip_read_info->pos_in_zipfile +
- pfile_in_zip_read_info->byte_before_the_zipfile,
- ZLIB_FILEFUNC_SEEK_SET)!=0)
- return UNZ_ERRNO;
- if (ZREAD(pfile_in_zip_read_info->z_filefunc,
- pfile_in_zip_read_info->filestream,
- pfile_in_zip_read_info->read_buffer,
- uReadThis)!=uReadThis)
- return UNZ_ERRNO;
-
-
-# ifndef NOUNCRYPT
- if(s->encrypted)
- {
- uInt i;
- for(i=0;i<uReadThis;i++)
- pfile_in_zip_read_info->read_buffer[i] =
- zdecode(s->keys,s->pcrc_32_tab,
- pfile_in_zip_read_info->read_buffer[i]);
- }
-# endif
-
-
- pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
-
- pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
-
- pfile_in_zip_read_info->stream.next_in =
- (Bytef*)pfile_in_zip_read_info->read_buffer;
- pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
- }
-
- if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw))
- {
- uInt uDoCopy,i ;
-
- if ((pfile_in_zip_read_info->stream.avail_in == 0) &&
- (pfile_in_zip_read_info->rest_read_compressed == 0))
- return (iRead==0) ? UNZ_EOF : iRead;
-
- if (pfile_in_zip_read_info->stream.avail_out <
- pfile_in_zip_read_info->stream.avail_in)
- uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
- else
- uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
-
- for (i=0;i<uDoCopy;i++)
- *(pfile_in_zip_read_info->stream.next_out+i) =
- *(pfile_in_zip_read_info->stream.next_in+i);
-
- pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
- pfile_in_zip_read_info->stream.next_out,
- uDoCopy);
- pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
- pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
- pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
- pfile_in_zip_read_info->stream.next_out += uDoCopy;
- pfile_in_zip_read_info->stream.next_in += uDoCopy;
- pfile_in_zip_read_info->stream.total_out += uDoCopy;
- iRead += uDoCopy;
- }
- else
- {
- uLong uTotalOutBefore,uTotalOutAfter;
- const Bytef *bufBefore;
- uLong uOutThis;
- int flush=Z_SYNC_FLUSH;
-
- uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
- bufBefore = pfile_in_zip_read_info->stream.next_out;
-
- /*
- if ((pfile_in_zip_read_info->rest_read_uncompressed ==
- pfile_in_zip_read_info->stream.avail_out) &&
- (pfile_in_zip_read_info->rest_read_compressed == 0))
- flush = Z_FINISH;
- */
- err=inflate(&pfile_in_zip_read_info->stream,flush);
-
- if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL))
- err = Z_DATA_ERROR;
-
- uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
- uOutThis = uTotalOutAfter-uTotalOutBefore;
-
- pfile_in_zip_read_info->crc32 =
- crc32(pfile_in_zip_read_info->crc32,bufBefore,
- (uInt)(uOutThis));
-
- pfile_in_zip_read_info->rest_read_uncompressed -=
- uOutThis;
-
- iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
-
- if (err==Z_STREAM_END)
- return (iRead==0) ? UNZ_EOF : iRead;
- if (err!=Z_OK)
- break;
- }
- }
-
- if (err==Z_OK)
- return iRead;
- return err;
-}
-
-
-/*
- Give the current position in uncompressed data
-*/
-extern z_off_t ZEXPORT unztell (file)
- unzFile file;
-{
- unz_s* s;
- file_in_zip_read_info_s* pfile_in_zip_read_info;
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
- pfile_in_zip_read_info=s->pfile_in_zip_read;
-
- if (pfile_in_zip_read_info==NULL)
- return UNZ_PARAMERROR;
-
- return (z_off_t)pfile_in_zip_read_info->stream.total_out;
-}
-
-
-/*
- return 1 if the end of file was reached, 0 elsewhere
-*/
-extern int ZEXPORT unzeof (file)
- unzFile file;
-{
- unz_s* s;
- file_in_zip_read_info_s* pfile_in_zip_read_info;
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
- pfile_in_zip_read_info=s->pfile_in_zip_read;
-
- if (pfile_in_zip_read_info==NULL)
- return UNZ_PARAMERROR;
-
- if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
- return 1;
- else
- return 0;
-}
-
-
-
-/*
- Read extra field from the current file (opened by unzOpenCurrentFile)
- This is the local-header version of the extra field (sometimes, there is
- more info in the local-header version than in the central-header)
-
- if buf==NULL, it return the size of the local extra field that can be read
-
- if buf!=NULL, len is the size of the buffer, the extra header is copied in
- buf.
- the return value is the number of bytes copied in buf, or (if <0)
- the error code
-*/
-extern int ZEXPORT unzGetLocalExtrafield (file,buf,len)
- unzFile file;
- voidp buf;
- unsigned len;
-{
- unz_s* s;
- file_in_zip_read_info_s* pfile_in_zip_read_info;
- uInt read_now;
- uLong size_to_read;
-
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
- pfile_in_zip_read_info=s->pfile_in_zip_read;
-
- if (pfile_in_zip_read_info==NULL)
- return UNZ_PARAMERROR;
-
- size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
- pfile_in_zip_read_info->pos_local_extrafield);
-
- if (buf==NULL)
- return (int)size_to_read;
-
- if (len>size_to_read)
- read_now = (uInt)size_to_read;
- else
- read_now = (uInt)len ;
-
- if (read_now==0)
- return 0;
-
- if (ZSEEK(pfile_in_zip_read_info->z_filefunc,
- pfile_in_zip_read_info->filestream,
- pfile_in_zip_read_info->offset_local_extrafield +
- pfile_in_zip_read_info->pos_local_extrafield,
- ZLIB_FILEFUNC_SEEK_SET)!=0)
- return UNZ_ERRNO;
-
- if (ZREAD(pfile_in_zip_read_info->z_filefunc,
- pfile_in_zip_read_info->filestream,
- buf,read_now)!=read_now)
- return UNZ_ERRNO;
-
- return (int)read_now;
-}
-
-/*
- Close the file in zip opened with unzipOpenCurrentFile
- Return UNZ_CRCERROR if all the file was read but the CRC is not good
-*/
-extern int ZEXPORT unzCloseCurrentFile (file)
- unzFile file;
-{
- int err=UNZ_OK;
-
- unz_s* s;
- file_in_zip_read_info_s* pfile_in_zip_read_info;
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
- pfile_in_zip_read_info=s->pfile_in_zip_read;
-
- if (pfile_in_zip_read_info==NULL)
- return UNZ_PARAMERROR;
-
-
- if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
- (!pfile_in_zip_read_info->raw))
- {
- if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
- err=UNZ_CRCERROR;
- }
-
-
- TRYFREE(pfile_in_zip_read_info->read_buffer);
- pfile_in_zip_read_info->read_buffer = NULL;
- if (pfile_in_zip_read_info->stream_initialised)
- inflateEnd(&pfile_in_zip_read_info->stream);
-
- pfile_in_zip_read_info->stream_initialised = 0;
- TRYFREE(pfile_in_zip_read_info);
-
- s->pfile_in_zip_read=NULL;
-
- return err;
-}
-
-
-/*
- Get the global comment string of the ZipFile, in the szComment buffer.
- uSizeBuf is the size of the szComment buffer.
- return the number of byte copied or an error code <0
-*/
-extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf)
- unzFile file;
- char *szComment;
- uLong uSizeBuf;
-{
- unz_s* s;
- uLong uReadThis ;
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
-
- uReadThis = uSizeBuf;
- if (uReadThis>s->gi.size_comment)
- uReadThis = s->gi.size_comment;
-
- if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0)
- return UNZ_ERRNO;
-
- if (uReadThis>0)
- {
- *szComment='\0';
- if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis)
- return UNZ_ERRNO;
- }
-
- if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
- *(szComment+s->gi.size_comment)='\0';
- return (int)uReadThis;
-}
-
-/* Additions by RX '2004 */
-extern uLong ZEXPORT unzGetOffset (file)
- unzFile file;
-{
- unz_s* s;
-
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
- if (!s->current_file_ok)
- return 0;
- if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff)
- if (s->num_file==s->gi.number_entry)
- return 0;
- return s->pos_in_central_dir;
-}
-
-extern int ZEXPORT unzSetOffset (file, pos)
- unzFile file;
- uLong pos;
-{
- unz_s* s;
- int err;
-
- if (file==NULL)
- return UNZ_PARAMERROR;
- s=(unz_s*)file;
-
- s->pos_in_central_dir = pos;
- s->num_file = s->gi.number_entry; /* hack */
- err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
- &s->cur_file_info_internal,
- NULL,0,NULL,0,NULL,0);
- s->current_file_ok = (err == UNZ_OK);
- return err;
-}
diff --git a/engine/code/qcommon/unzip.h b/engine/code/qcommon/unzip.h
deleted file mode 100644
index b4a839b..0000000
--- a/engine/code/qcommon/unzip.h
+++ /dev/null
@@ -1,355 +0,0 @@
-/* unzip.h -- IO for uncompress .zip files using zlib
- Version 1.01e, February 12th, 2005
-
- Copyright (C) 1998-2005 Gilles Vollant
-
- This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
- WinZip, InfoZip tools and compatible.
-
- Multi volume ZipFile (span) are not supported.
- Encryption compatible with pkzip 2.04g only supported
- Old compressions used by old PKZip 1.x are not supported
-
-
- I WAIT FEEDBACK at mail info at winimage.com
- Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
-
- Condition of use and distribution are the same than zlib :
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-
-
-*/
-
-/* for more info about .ZIP format, see
- http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
- http://www.info-zip.org/pub/infozip/doc/
- PkWare has also a specification at :
- ftp://ftp.pkware.com/probdesc.zip
-*/
-
-#ifndef _unz_H
-#define _unz_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef USE_LOCAL_HEADERS
- #include "../zlib/zlib.h"
-#else
- #include <zlib.h>
-#endif
-#include "ioapi.h"
-
-#define NOUNCRYPT
-
-#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
-/* like the STRICT of WIN32, we define a pointer that cannot be converted
- from (void*) without cast */
-typedef struct TagunzFile__ { int unused; } unzFile__;
-typedef unzFile__ *unzFile;
-#else
-typedef voidp unzFile;
-#endif
-
-
-#define UNZ_OK (0)
-#define UNZ_END_OF_LIST_OF_FILE (-100)
-#define UNZ_ERRNO (Z_ERRNO)
-#define UNZ_EOF (0)
-#define UNZ_PARAMERROR (-102)
-#define UNZ_BADZIPFILE (-103)
-#define UNZ_INTERNALERROR (-104)
-#define UNZ_CRCERROR (-105)
-
-/* tm_unz contain date/time info */
-typedef struct tm_unz_s
-{
- uInt tm_sec; /* seconds after the minute - [0,59] */
- uInt tm_min; /* minutes after the hour - [0,59] */
- uInt tm_hour; /* hours since midnight - [0,23] */
- uInt tm_mday; /* day of the month - [1,31] */
- uInt tm_mon; /* months since January - [0,11] */
- uInt tm_year; /* years - [1980..2044] */
-} tm_unz;
-
-/* unz_global_info structure contain global data about the ZIPfile
- These data comes from the end of central dir */
-typedef struct unz_global_info_s
-{
- uLong number_entry; /* total number of entries in
- the central dir on this disk */
- uLong size_comment; /* size of the global comment of the zipfile */
-} unz_global_info;
-
-
-/* unz_file_info contain information about a file in the zipfile */
-typedef struct unz_file_info_s
-{
- uLong version; /* version made by 2 bytes */
- uLong version_needed; /* version needed to extract 2 bytes */
- uLong flag; /* general purpose bit flag 2 bytes */
- uLong compression_method; /* compression method 2 bytes */
- uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
- uLong crc; /* crc-32 4 bytes */
- uLong compressed_size; /* compressed size 4 bytes */
- uLong uncompressed_size; /* uncompressed size 4 bytes */
- uLong size_filename; /* filename length 2 bytes */
- uLong size_file_extra; /* extra field length 2 bytes */
- uLong size_file_comment; /* file comment length 2 bytes */
-
- uLong disk_num_start; /* disk number start 2 bytes */
- uLong internal_fa; /* internal file attributes 2 bytes */
- uLong external_fa; /* external file attributes 4 bytes */
-
- tm_unz tmu_date;
-} unz_file_info;
-
-extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
- const char* fileName2,
- int iCaseSensitivity));
-/*
- Compare two filename (fileName1,fileName2).
- If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
- If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
- or strcasecmp)
- If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
- (like 1 on Unix, 2 on Windows)
-*/
-
-
-extern unzFile ZEXPORT unzOpen OF((const char *path));
-/*
- Open a Zip file. path contain the full pathname (by example,
- on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
- "zlib/zlib113.zip".
- If the zipfile cannot be opened (file don't exist or in not valid), the
- return value is NULL.
- Else, the return value is a unzFile Handle, usable with other function
- of this unzip package.
-*/
-
-extern unzFile ZEXPORT unzOpen2 OF((const char *path,
- zlib_filefunc_def* pzlib_filefunc_def));
-/*
- Open a Zip file, like unzOpen, but provide a set of file low level API
- for read/write the zip file (see ioapi.h)
-*/
-
-extern int ZEXPORT unzClose OF((unzFile file));
-/*
- Close a ZipFile opened with unzipOpen.
- If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
- these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
- return UNZ_OK if there is no problem. */
-
-extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
- unz_global_info *pglobal_info));
-/*
- Write info about the ZipFile in the *pglobal_info structure.
- No preparation of the structure is needed
- return UNZ_OK if there is no problem. */
-
-
-extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
- char *szComment,
- uLong uSizeBuf));
-/*
- Get the global comment string of the ZipFile, in the szComment buffer.
- uSizeBuf is the size of the szComment buffer.
- return the number of byte copied or an error code <0
-*/
-
-
-/***************************************************************************/
-/* Unzip package allow you browse the directory of the zipfile */
-
-extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
-/*
- Set the current file of the zipfile to the first file.
- return UNZ_OK if there is no problem
-*/
-
-extern int ZEXPORT unzGoToNextFile OF((unzFile file));
-/*
- Set the current file of the zipfile to the next file.
- return UNZ_OK if there is no problem
- return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
-*/
-
-extern int ZEXPORT unzLocateFile OF((unzFile file,
- const char *szFileName,
- int iCaseSensitivity));
-/*
- Try locate the file szFileName in the zipfile.
- For the iCaseSensitivity signification, see unzStringFileNameCompare
-
- return value :
- UNZ_OK if the file is found. It becomes the current file.
- UNZ_END_OF_LIST_OF_FILE if the file is not found
-*/
-
-
-/* ****************************************** */
-/* Ryan supplied functions */
-/* unz_file_info contain information about a file in the zipfile */
-typedef struct unz_file_pos_s
-{
- uLong pos_in_zip_directory; /* offset in zip file directory */
- uLong num_of_file; /* # of file */
-} unz_file_pos;
-
-extern int ZEXPORT unzGetFilePos(
- unzFile file,
- unz_file_pos* file_pos);
-
-extern int ZEXPORT unzGoToFilePos(
- unzFile file,
- unz_file_pos* file_pos);
-
-/* ****************************************** */
-
-extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
- unz_file_info *pfile_info,
- char *szFileName,
- uLong fileNameBufferSize,
- void *extraField,
- uLong extraFieldBufferSize,
- char *szComment,
- uLong commentBufferSize));
-/*
- Get Info about the current file
- if pfile_info!=NULL, the *pfile_info structure will contain somes info about
- the current file
- if szFileName!=NULL, the filemane string will be copied in szFileName
- (fileNameBufferSize is the size of the buffer)
- if extraField!=NULL, the extra field information will be copied in extraField
- (extraFieldBufferSize is the size of the buffer).
- This is the Central-header version of the extra field
- if szComment!=NULL, the comment string of the file will be copied in szComment
- (commentBufferSize is the size of the buffer)
-*/
-
-/***************************************************************************/
-/* for reading the content of the current zipfile, you can open it, read data
- from it, and close it (you can close it before reading all the file)
- */
-
-extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
-/*
- Open for reading data the current file in the zipfile.
- If there is no error, the return value is UNZ_OK.
-*/
-
-extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
- const char* password));
-/*
- Open for reading data the current file in the zipfile.
- password is a crypting password
- If there is no error, the return value is UNZ_OK.
-*/
-
-extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
- int* method,
- int* level,
- int raw));
-/*
- Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
- if raw==1
- *method will receive method of compression, *level will receive level of
- compression
- note : you can set level parameter as NULL (if you did not want known level,
- but you CANNOT set method parameter as NULL
-*/
-
-extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
- int* method,
- int* level,
- int raw,
- const char* password));
-/*
- Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
- if raw==1
- *method will receive method of compression, *level will receive level of
- compression
- note : you can set level parameter as NULL (if you did not want known level,
- but you CANNOT set method parameter as NULL
-*/
-
-
-extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
-/*
- Close the file in zip opened with unzOpenCurrentFile
- Return UNZ_CRCERROR if all the file was read but the CRC is not good
-*/
-
-extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
- voidp buf,
- unsigned len));
-/*
- Read bytes from the current file (opened by unzOpenCurrentFile)
- buf contain buffer where data must be copied
- len the size of buf.
-
- return the number of byte copied if somes bytes are copied
- return 0 if the end of file was reached
- return <0 with error code if there is an error
- (UNZ_ERRNO for IO error, or zLib error for uncompress error)
-*/
-
-extern z_off_t ZEXPORT unztell OF((unzFile file));
-/*
- Give the current position in uncompressed data
-*/
-
-extern int ZEXPORT unzeof OF((unzFile file));
-/*
- return 1 if the end of file was reached, 0 elsewhere
-*/
-
-extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
- voidp buf,
- unsigned len));
-/*
- Read extra field from the current file (opened by unzOpenCurrentFile)
- This is the local-header version of the extra field (sometimes, there is
- more info in the local-header version than in the central-header)
-
- if buf==NULL, it return the size of the local extra field
-
- if buf!=NULL, len is the size of the buffer, the extra header is copied in
- buf.
- the return value is the number of bytes copied in buf, or (if <0)
- the error code
-*/
-
-/***************************************************************************/
-
-/* Get the current file offset */
-extern uLong ZEXPORT unzGetOffset (unzFile file);
-
-/* Set the current file offset */
-extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
-
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _unz_H */
diff --git a/engine/code/qcommon/vm.c b/engine/code/qcommon/vm.c
deleted file mode 100644
index 2ccc24f..0000000
--- a/engine/code/qcommon/vm.c
+++ /dev/null
@@ -1,913 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// vm.c -- virtual machine
-
-/*
-
-
-intermix code and data
-symbol table
-
-a dll has one imported function: VM_SystemCall
-and one exported function: Perform
-
-
-*/
-
-#include "vm_local.h"
-
-
-vm_t *currentVM = NULL;
-vm_t *lastVM = NULL;
-int vm_debugLevel;
-
-// used by Com_Error to get rid of running vm's before longjmp
-static int forced_unload;
-
-#define MAX_VM 3
-vm_t vmTable[MAX_VM];
-
-
-void VM_VmInfo_f( void );
-void VM_VmProfile_f( void );
-
-
-
-#if 0 // 64bit!
-// converts a VM pointer to a C pointer and
-// checks to make sure that the range is acceptable
-void *VM_VM2C( vmptr_t p, int length ) {
- return (void *)p;
-}
-#endif
-
-void VM_Debug( int level ) {
- vm_debugLevel = level;
-}
-
-/*
-==============
-VM_Init
-==============
-*/
-void VM_Init( void ) {
- Cvar_Get( "vm_cgame", "2", CVAR_ARCHIVE ); // !@# SHIP WITH SET TO 2
- Cvar_Get( "vm_game", "2", CVAR_ARCHIVE ); // !@# SHIP WITH SET TO 2
- Cvar_Get( "vm_ui", "2", CVAR_ARCHIVE ); // !@# SHIP WITH SET TO 2
-
- Cmd_AddCommand ("vmprofile", VM_VmProfile_f );
- Cmd_AddCommand ("vminfo", VM_VmInfo_f );
-
- Com_Memset( vmTable, 0, sizeof( vmTable ) );
-}
-
-
-/*
-===============
-VM_ValueToSymbol
-
-Assumes a program counter value
-===============
-*/
-const char *VM_ValueToSymbol( vm_t *vm, int value ) {
- vmSymbol_t *sym;
- static char text[MAX_TOKEN_CHARS];
-
- sym = vm->symbols;
- if ( !sym ) {
- return "NO SYMBOLS";
- }
-
- // find the symbol
- while ( sym->next && sym->next->symValue <= value ) {
- sym = sym->next;
- }
-
- if ( value == sym->symValue ) {
- return sym->symName;
- }
-
- Com_sprintf( text, sizeof( text ), "%s+%i", sym->symName, value - sym->symValue );
-
- return text;
-}
-
-/*
-===============
-VM_ValueToFunctionSymbol
-
-For profiling, find the symbol behind this value
-===============
-*/
-vmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value ) {
- vmSymbol_t *sym;
- static vmSymbol_t nullSym;
-
- sym = vm->symbols;
- if ( !sym ) {
- return &nullSym;
- }
-
- while ( sym->next && sym->next->symValue <= value ) {
- sym = sym->next;
- }
-
- return sym;
-}
-
-
-/*
-===============
-VM_SymbolToValue
-===============
-*/
-int VM_SymbolToValue( vm_t *vm, const char *symbol ) {
- vmSymbol_t *sym;
-
- for ( sym = vm->symbols ; sym ; sym = sym->next ) {
- if ( !strcmp( symbol, sym->symName ) ) {
- return sym->symValue;
- }
- }
- return 0;
-}
-
-
-/*
-=====================
-VM_SymbolForCompiledPointer
-=====================
-*/
-#if 0 // 64bit!
-const char *VM_SymbolForCompiledPointer( vm_t *vm, void *code ) {
- int i;
-
- if ( code < (void *)vm->codeBase ) {
- return "Before code block";
- }
- if ( code >= (void *)(vm->codeBase + vm->codeLength) ) {
- return "After code block";
- }
-
- // find which original instruction it is after
- for ( i = 0 ; i < vm->codeLength ; i++ ) {
- if ( (void *)vm->instructionPointers[i] > code ) {
- break;
- }
- }
- i--;
-
- // now look up the bytecode instruction pointer
- return VM_ValueToSymbol( vm, i );
-}
-#endif
-
-
-
-/*
-===============
-ParseHex
-===============
-*/
-int ParseHex( const char *text ) {
- int value;
- int c;
-
- value = 0;
- while ( ( c = *text++ ) != 0 ) {
- if ( c >= '0' && c <= '9' ) {
- value = value * 16 + c - '0';
- continue;
- }
- if ( c >= 'a' && c <= 'f' ) {
- value = value * 16 + 10 + c - 'a';
- continue;
- }
- if ( c >= 'A' && c <= 'F' ) {
- value = value * 16 + 10 + c - 'A';
- continue;
- }
- }
-
- return value;
-}
-
-/*
-===============
-VM_LoadSymbols
-===============
-*/
-void VM_LoadSymbols( vm_t *vm ) {
- int len;
- union {
- char *c;
- void *v;
- } mapfile;
- char *text_p, *token;
- char name[MAX_QPATH];
- char symbols[MAX_QPATH];
- vmSymbol_t **prev, *sym;
- int count;
- int value;
- int chars;
- int segment;
- int numInstructions;
-
- // don't load symbols if not developer
- if ( !com_developer->integer ) {
- return;
- }
-
- COM_StripExtension(vm->name, name, sizeof(name));
- Com_sprintf( symbols, sizeof( symbols ), "vm/%s.map", name );
- len = FS_ReadFile( symbols, &mapfile.v );
- if ( !mapfile.c ) {
- Com_Printf( "Couldn't load symbol file: %s\n", symbols );
- return;
- }
-
- numInstructions = vm->instructionCount;
-
- // parse the symbols
- text_p = mapfile.c;
- prev = &vm->symbols;
- count = 0;
-
- while ( 1 ) {
- token = COM_Parse( &text_p );
- if ( !token[0] ) {
- break;
- }
- segment = ParseHex( token );
- if ( segment ) {
- COM_Parse( &text_p );
- COM_Parse( &text_p );
- continue; // only load code segment values
- }
-
- token = COM_Parse( &text_p );
- if ( !token[0] ) {
- Com_Printf( "WARNING: incomplete line at end of file\n" );
- break;
- }
- value = ParseHex( token );
-
- token = COM_Parse( &text_p );
- if ( !token[0] ) {
- Com_Printf( "WARNING: incomplete line at end of file\n" );
- break;
- }
- chars = strlen( token );
- sym = Hunk_Alloc( sizeof( *sym ) + chars, h_high );
- *prev = sym;
- prev = &sym->next;
- sym->next = NULL;
-
- // convert value from an instruction number to a code offset
- if ( value >= 0 && value < numInstructions ) {
- value = vm->instructionPointers[value];
- }
-
- sym->symValue = value;
- Q_strncpyz( sym->symName, token, chars + 1 );
-
- count++;
- }
-
- vm->numSymbols = count;
- Com_Printf( "%i symbols parsed from %s\n", count, symbols );
- FS_FreeFile( mapfile.v );
-}
-
-/*
-============
-VM_DllSyscall
-
-Dlls will call this directly
-
- rcg010206 The horror; the horror.
-
- The syscall mechanism relies on stack manipulation to get it's args.
- This is likely due to C's inability to pass "..." parameters to
- a function in one clean chunk. On PowerPC Linux, these parameters
- are not necessarily passed on the stack, so while (&arg[0] == arg)
- is true, (&arg[1] == 2nd function parameter) is not necessarily
- accurate, as arg's value might have been stored to the stack or
- other piece of scratch memory to give it a valid address, but the
- next parameter might still be sitting in a register.
-
- Quake's syscall system also assumes that the stack grows downward,
- and that any needed types can be squeezed, safely, into a signed int.
-
- This hack below copies all needed values for an argument to a
- array in memory, so that Quake can get the correct values. This can
- also be used on systems where the stack grows upwards, as the
- presumably standard and safe stdargs.h macros are used.
-
- As for having enough space in a signed int for your datatypes, well,
- it might be better to wait for DOOM 3 before you start porting. :)
-
- The original code, while probably still inherently dangerous, seems
- to work well enough for the platforms it already works on. Rather
- than add the performance hit for those platforms, the original code
- is still in use there.
-
- For speed, we just grab 15 arguments, and don't worry about exactly
- how many the syscall actually needs; the extra is thrown away.
-
-============
-*/
-intptr_t QDECL VM_DllSyscall( intptr_t arg, ... ) {
-#if !id386
- // rcg010206 - see commentary above
- intptr_t args[16];
- int i;
- va_list ap;
-
- args[0] = arg;
-
- va_start(ap, arg);
- for (i = 1; i < sizeof (args) / sizeof (args[i]); i++)
- args[i] = va_arg(ap, intptr_t);
- va_end(ap);
-
- return currentVM->systemCall( args );
-#else // original id code
- return currentVM->systemCall( &arg );
-#endif
-}
-
-
-/*
-=================
-VM_LoadQVM
-
-Load a .qvm file
-=================
-*/
-vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
- int length;
- int dataLength;
- int i;
- char filename[MAX_QPATH];
- union {
- vmHeader_t *h;
- void *v;
- } header;
-
- // load the image
- Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name );
- Com_Printf( "Loading vm file %s...\n", filename );
- length = FS_ReadFile( filename, &header.v );
- if ( !header.h ) {
- Com_Printf( "Failed.\n" );
- VM_Free( vm );
- return NULL;
- }
-
- if( LittleLong( header.h->vmMagic ) == VM_MAGIC_VER2 ) {
- Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" );
-
- // byte swap the header
- for ( i = 0 ; i < sizeof( vmHeader_t ) / 4 ; i++ ) {
- ((int *)header.h)[i] = LittleLong( ((int *)header.h)[i] );
- }
-
- // validate
- if ( header.h->jtrgLength < 0
- || header.h->bssLength < 0
- || header.h->dataLength < 0
- || header.h->litLength < 0
- || header.h->codeLength <= 0 ) {
- VM_Free( vm );
- Com_Error( ERR_FATAL, "%s has bad header", filename );
- }
- } else if( LittleLong( header.h->vmMagic ) == VM_MAGIC ) {
- // byte swap the header
- // sizeof( vmHeader_t ) - sizeof( int ) is the 1.32b vm header size
- for ( i = 0 ; i < ( sizeof( vmHeader_t ) - sizeof( int ) ) / 4 ; i++ ) {
- ((int *)header.h)[i] = LittleLong( ((int *)header.h)[i] );
- }
-
- // validate
- if ( header.h->bssLength < 0
- || header.h->dataLength < 0
- || header.h->litLength < 0
- || header.h->codeLength <= 0 ) {
- VM_Free( vm );
- Com_Error( ERR_FATAL, "%s has bad header", filename );
- }
- } else {
- VM_Free( vm );
- Com_Error( ERR_FATAL, "%s does not have a recognisable "
- "magic number in its header", filename );
- }
-
- // round up to next power of 2 so all data operations can
- // be mask protected
- dataLength = header.h->dataLength + header.h->litLength +
- header.h->bssLength;
- for ( i = 0 ; dataLength > ( 1 << i ) ; i++ ) {
- }
- dataLength = 1 << i;
-
- if( alloc ) {
- // allocate zero filled space for initialized and uninitialized data
- vm->dataBase = Hunk_Alloc( dataLength, h_high );
- vm->dataMask = dataLength - 1;
- } else {
- // clear the data
- Com_Memset( vm->dataBase, 0, dataLength );
- }
-
- // copy the intialized data
- Com_Memcpy( vm->dataBase, (byte *)header.h + header.h->dataOffset,
- header.h->dataLength + header.h->litLength );
-
- // byte swap the longs
- for ( i = 0 ; i < header.h->dataLength ; i += 4 ) {
- *(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) );
- }
-
- if( header.h->vmMagic == VM_MAGIC_VER2 ) {
- vm->numJumpTableTargets = header.h->jtrgLength >> 2;
- Com_Printf( "Loading %d jump table targets\n", vm->numJumpTableTargets );
-
- if( alloc ) {
- vm->jumpTableTargets = Hunk_Alloc( header.h->jtrgLength, h_high );
- } else {
- Com_Memset( vm->jumpTableTargets, 0, header.h->jtrgLength );
- }
-
- Com_Memcpy( vm->jumpTableTargets, (byte *)header.h + header.h->dataOffset +
- header.h->dataLength + header.h->litLength, header.h->jtrgLength );
-
- // byte swap the longs
- for ( i = 0 ; i < header.h->jtrgLength ; i += 4 ) {
- *(int *)(vm->jumpTableTargets + i) = LittleLong( *(int *)(vm->jumpTableTargets + i ) );
- }
- }
-
- return header.h;
-}
-
-/*
-=================
-VM_Restart
-
-Reload the data, but leave everything else in place
-This allows a server to do a map_restart without changing memory allocation
-=================
-*/
-vm_t *VM_Restart( vm_t *vm ) {
- vmHeader_t *header;
-
- // DLL's can't be restarted in place
- if ( vm->dllHandle ) {
- char name[MAX_QPATH];
- intptr_t (*systemCall)( intptr_t *parms );
-
- systemCall = vm->systemCall;
- Q_strncpyz( name, vm->name, sizeof( name ) );
-
- VM_Free( vm );
-
- vm = VM_Create( name, systemCall, VMI_NATIVE );
- return vm;
- }
-
- // load the image
- Com_Printf( "VM_Restart()\n" );
-
- if( !( header = VM_LoadQVM( vm, qfalse ) ) ) {
- Com_Error( ERR_DROP, "VM_Restart failed.\n" );
- return NULL;
- }
-
- // free the original file
- FS_FreeFile( header );
-
- return vm;
-}
-
-/*
-================
-VM_Create
-
-If image ends in .qvm it will be interpreted, otherwise
-it will attempt to load as a system dll
-================
-*/
-vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *),
- vmInterpret_t interpret ) {
- vm_t *vm;
- vmHeader_t *header;
- int i, remaining;
-
- if ( !module || !module[0] || !systemCalls ) {
- Com_Error( ERR_FATAL, "VM_Create: bad parms" );
- }
-
- remaining = Hunk_MemoryRemaining();
-
- // see if we already have the VM
- for ( i = 0 ; i < MAX_VM ; i++ ) {
- if (!Q_stricmp(vmTable[i].name, module)) {
- vm = &vmTable[i];
- return vm;
- }
- }
-
- // find a free vm
- for ( i = 0 ; i < MAX_VM ; i++ ) {
- if ( !vmTable[i].name[0] ) {
- break;
- }
- }
-
- if ( i == MAX_VM ) {
- Com_Error( ERR_FATAL, "VM_Create: no free vm_t" );
- }
-
- vm = &vmTable[i];
-
- Q_strncpyz( vm->name, module, sizeof( vm->name ) );
- vm->systemCall = systemCalls;
-
- if ( interpret == VMI_NATIVE ) {
- // try to load as a system dll
- Com_Printf( "Loading dll file %s.\n", vm->name );
- vm->dllHandle = Sys_LoadDll( module, vm->fqpath , &vm->entryPoint, VM_DllSyscall );
- if ( vm->dllHandle ) {
- return vm;
- }
-
- Com_Printf( "Failed to load dll, looking for qvm.\n" );
- interpret = VMI_COMPILED;
- }
-
- // load the image
- if( !( header = VM_LoadQVM( vm, qtrue ) ) ) {
- return NULL;
- }
-
- // allocate space for the jump targets, which will be filled in by the compile/prep functions
- vm->instructionCount = header->instructionCount;
- vm->instructionPointers = Hunk_Alloc( vm->instructionCount*4, h_high );
-
- // copy or compile the instructions
- vm->codeLength = header->codeLength;
-
- vm->compiled = qfalse;
-
-#ifdef NO_VM_COMPILED
- if(interpret >= VMI_COMPILED) {
- Com_Printf("Architecture doesn't have a bytecode compiler, using interpreter\n");
- interpret = VMI_BYTECODE;
- }
-#else
- if ( interpret >= VMI_COMPILED ) {
- vm->compiled = qtrue;
- VM_Compile( vm, header );
- }
-#endif
- // VM_Compile may have reset vm->compiled if compilation failed
- if (!vm->compiled)
- {
- VM_PrepareInterpreter( vm, header );
- }
-
- // free the original file
- FS_FreeFile( header );
-
- // load the map file
- VM_LoadSymbols( vm );
-
- // the stack is implicitly at the end of the image
- vm->programStack = vm->dataMask + 1;
- vm->stackBottom = vm->programStack - PROGRAM_STACK_SIZE;
-
- Com_Printf("%s loaded in %d bytes on the hunk\n", module, remaining - Hunk_MemoryRemaining());
-
- return vm;
-}
-
-/*
-==============
-VM_Free
-==============
-*/
-void VM_Free( vm_t *vm ) {
-
- if(!vm) {
- return;
- }
-
- if(vm->callLevel) {
- if(!forced_unload) {
- Com_Error( ERR_FATAL, "VM_Free(%s) on running vm", vm->name );
- return;
- } else {
- Com_Printf( "forcefully unloading %s vm\n", vm->name );
- }
- }
-
- if(vm->destroy)
- vm->destroy(vm);
-
- if ( vm->dllHandle ) {
- Sys_UnloadDll( vm->dllHandle );
- Com_Memset( vm, 0, sizeof( *vm ) );
- }
-#if 0 // now automatically freed by hunk
- if ( vm->codeBase ) {
- Z_Free( vm->codeBase );
- }
- if ( vm->dataBase ) {
- Z_Free( vm->dataBase );
- }
- if ( vm->instructionPointers ) {
- Z_Free( vm->instructionPointers );
- }
-#endif
- Com_Memset( vm, 0, sizeof( *vm ) );
-
- currentVM = NULL;
- lastVM = NULL;
-}
-
-void VM_Clear(void) {
- int i;
- for (i=0;i<MAX_VM; i++) {
- VM_Free(&vmTable[i]);
- }
-}
-
-void VM_Forced_Unload_Start(void) {
- forced_unload = 1;
-}
-
-void VM_Forced_Unload_Done(void) {
- forced_unload = 0;
-}
-
-void *VM_ArgPtr( intptr_t intValue ) {
- if ( !intValue ) {
- return NULL;
- }
- // currentVM is missing on reconnect
- if ( currentVM==NULL )
- return NULL;
-
- if ( currentVM->entryPoint ) {
- return (void *)(currentVM->dataBase + intValue);
- }
- else {
- return (void *)(currentVM->dataBase + (intValue & currentVM->dataMask));
- }
-}
-
-void *VM_ExplicitArgPtr( vm_t *vm, intptr_t intValue ) {
- if ( !intValue ) {
- return NULL;
- }
-
- // currentVM is missing on reconnect here as well?
- if ( currentVM==NULL )
- return NULL;
-
- //
- if ( vm->entryPoint ) {
- return (void *)(vm->dataBase + intValue);
- }
- else {
- return (void *)(vm->dataBase + (intValue & vm->dataMask));
- }
-}
-
-
-/*
-==============
-VM_Call
-
-
-Upon a system call, the stack will look like:
-
-sp+32 parm1
-sp+28 parm0
-sp+24 return value
-sp+20 return address
-sp+16 local1
-sp+14 local0
-sp+12 arg1
-sp+8 arg0
-sp+4 return stack
-sp return address
-
-An interpreted function will immediately execute
-an OP_ENTER instruction, which will subtract space for
-locals from sp
-==============
-*/
-
-intptr_t QDECL VM_Call( vm_t *vm, int callnum, ... ) {
- vm_t *oldVM;
- intptr_t r;
- int i;
-
- if ( !vm ) {
- Com_Error( ERR_FATAL, "VM_Call with NULL vm" );
- }
-
- oldVM = currentVM;
- currentVM = vm;
- lastVM = vm;
-
- if ( vm_debugLevel ) {
- Com_Printf( "VM_Call( %d )\n", callnum );
- }
-
- ++vm->callLevel;
- // if we have a dll loaded, call it directly
- if ( vm->entryPoint ) {
- //rcg010207 - see dissertation at top of VM_DllSyscall() in this file.
- int args[10];
- va_list ap;
- va_start(ap, callnum);
- for (i = 0; i < sizeof (args) / sizeof (args[i]); i++) {
- args[i] = va_arg(ap, int);
- }
- va_end(ap);
-
- r = vm->entryPoint( callnum, args[0], args[1], args[2], args[3],
- args[4], args[5], args[6], args[7],
- args[8], args[9]);
- } else {
-#if id386 || idsparc // i386/sparc calling convention doesn't need conversion
-#ifndef NO_VM_COMPILED
- if ( vm->compiled )
- r = VM_CallCompiled( vm, (int*)&callnum );
- else
-#endif
- r = VM_CallInterpreted( vm, (int*)&callnum );
-#else
- struct {
- int callnum;
- int args[10];
- } a;
- va_list ap;
-
- a.callnum = callnum;
- va_start(ap, callnum);
- for (i = 0; i < sizeof (a.args) / sizeof (a.args[0]); i++) {
- a.args[i] = va_arg(ap, int);
- }
- va_end(ap);
-#ifndef NO_VM_COMPILED
- if ( vm->compiled )
- r = VM_CallCompiled( vm, &a.callnum );
- else
-#endif
- r = VM_CallInterpreted( vm, &a.callnum );
-#endif
- }
- --vm->callLevel;
-
- if ( oldVM != NULL )
- currentVM = oldVM;
- return r;
-}
-
-//=================================================================
-
-static int QDECL VM_ProfileSort( const void *a, const void *b ) {
- vmSymbol_t *sa, *sb;
-
- sa = *(vmSymbol_t **)a;
- sb = *(vmSymbol_t **)b;
-
- if ( sa->profileCount < sb->profileCount ) {
- return -1;
- }
- if ( sa->profileCount > sb->profileCount ) {
- return 1;
- }
- return 0;
-}
-
-/*
-==============
-VM_VmProfile_f
-
-==============
-*/
-void VM_VmProfile_f( void ) {
- vm_t *vm;
- vmSymbol_t **sorted, *sym;
- int i;
- double total;
-
- if ( !lastVM ) {
- return;
- }
-
- vm = lastVM;
-
- if ( !vm->numSymbols ) {
- return;
- }
-
- sorted = Z_Malloc( vm->numSymbols * sizeof( *sorted ) );
- sorted[0] = vm->symbols;
- total = sorted[0]->profileCount;
- for ( i = 1 ; i < vm->numSymbols ; i++ ) {
- sorted[i] = sorted[i-1]->next;
- total += sorted[i]->profileCount;
- }
-
- qsort( sorted, vm->numSymbols, sizeof( *sorted ), VM_ProfileSort );
-
- for ( i = 0 ; i < vm->numSymbols ; i++ ) {
- int perc;
-
- sym = sorted[i];
-
- perc = 100 * (float) sym->profileCount / total;
- Com_Printf( "%2i%% %9i %s\n", perc, sym->profileCount, sym->symName );
- sym->profileCount = 0;
- }
-
- Com_Printf(" %9.0f total\n", total );
-
- Z_Free( sorted );
-}
-
-/*
-==============
-VM_VmInfo_f
-
-==============
-*/
-void VM_VmInfo_f( void ) {
- vm_t *vm;
- int i;
-
- Com_Printf( "Registered virtual machines:\n" );
- for ( i = 0 ; i < MAX_VM ; i++ ) {
- vm = &vmTable[i];
- if ( !vm->name[0] ) {
- break;
- }
- Com_Printf( "%s : ", vm->name );
- if ( vm->dllHandle ) {
- Com_Printf( "native\n" );
- continue;
- }
- if ( vm->compiled ) {
- Com_Printf( "compiled on load\n" );
- } else {
- Com_Printf( "interpreted\n" );
- }
- Com_Printf( " code length : %7i\n", vm->codeLength );
- Com_Printf( " table length: %7i\n", vm->instructionCount*4 );
- Com_Printf( " data length : %7i\n", vm->dataMask + 1 );
- }
-}
-
-/*
-===============
-VM_LogSyscalls
-
-Insert calls to this while debugging the vm compiler
-===============
-*/
-void VM_LogSyscalls( int *args ) {
- static int callnum;
- static FILE *f;
-
- if ( !f ) {
- f = fopen("syscalls.log", "w" );
- }
- callnum++;
- fprintf(f, "%i: %p (%i) = %i %i %i %i\n", callnum, (void*)(args - (int *)currentVM->dataBase),
- args[0], args[1], args[2], args[3], args[4] );
-}
diff --git a/engine/code/qcommon/vm_interpreted.c b/engine/code/qcommon/vm_interpreted.c
deleted file mode 100644
index a31c719..0000000
--- a/engine/code/qcommon/vm_interpreted.c
+++ /dev/null
@@ -1,906 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "vm_local.h"
-
-//#define DEBUG_VM
-#ifdef DEBUG_VM
-static char *opnames[256] = {
- "OP_UNDEF",
-
- "OP_IGNORE",
-
- "OP_BREAK",
-
- "OP_ENTER",
- "OP_LEAVE",
- "OP_CALL",
- "OP_PUSH",
- "OP_POP",
-
- "OP_CONST",
-
- "OP_LOCAL",
-
- "OP_JUMP",
-
- //-------------------
-
- "OP_EQ",
- "OP_NE",
-
- "OP_LTI",
- "OP_LEI",
- "OP_GTI",
- "OP_GEI",
-
- "OP_LTU",
- "OP_LEU",
- "OP_GTU",
- "OP_GEU",
-
- "OP_EQF",
- "OP_NEF",
-
- "OP_LTF",
- "OP_LEF",
- "OP_GTF",
- "OP_GEF",
-
- //-------------------
-
- "OP_LOAD1",
- "OP_LOAD2",
- "OP_LOAD4",
- "OP_STORE1",
- "OP_STORE2",
- "OP_STORE4",
- "OP_ARG",
-
- "OP_BLOCK_COPY",
-
- //-------------------
-
- "OP_SEX8",
- "OP_SEX16",
-
- "OP_NEGI",
- "OP_ADD",
- "OP_SUB",
- "OP_DIVI",
- "OP_DIVU",
- "OP_MODI",
- "OP_MODU",
- "OP_MULI",
- "OP_MULU",
-
- "OP_BAND",
- "OP_BOR",
- "OP_BXOR",
- "OP_BCOM",
-
- "OP_LSH",
- "OP_RSHI",
- "OP_RSHU",
-
- "OP_NEGF",
- "OP_ADDF",
- "OP_SUBF",
- "OP_DIVF",
- "OP_MULF",
-
- "OP_CVIF",
- "OP_CVFI"
-};
-#endif
-
-#if idppc
-
-//FIXME: these, um... look the same to me
-#if defined(__GNUC__)
-static ID_INLINE unsigned int loadWord(void *addr) {
- unsigned int word;
-
- asm("lwbrx %0,0,%1" : "=r" (word) : "r" (addr));
- return word;
-}
-#else
-static ID_INLINE unsigned int __lwbrx(register void *addr,
- register int offset) {
- register unsigned int word;
-
- asm("lwbrx %0,%2,%1" : "=r" (word) : "r" (addr), "b" (offset));
- return word;
-}
-#define loadWord(addr) __lwbrx(addr,0)
-#endif
-
-#else
- static ID_INLINE int loadWord(void *addr) {
- int word;
- memcpy(&word, addr, 4);
- return LittleLong(word);
- }
-#endif
-
-char *VM_Indent( vm_t *vm ) {
- static char *string = " ";
- if ( vm->callLevel > 20 ) {
- return string;
- }
- return string + 2 * ( 20 - vm->callLevel );
-}
-
-void VM_StackTrace( vm_t *vm, int programCounter, int programStack ) {
- int count;
-
- count = 0;
- do {
- Com_Printf( "%s\n", VM_ValueToSymbol( vm, programCounter ) );
- programStack = *(int *)&vm->dataBase[programStack+4];
- programCounter = *(int *)&vm->dataBase[programStack];
- } while ( programCounter != -1 && ++count < 32 );
-
-}
-
-
-/*
-====================
-VM_PrepareInterpreter
-====================
-*/
-void VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header ) {
- int op;
- int byte_pc;
- int int_pc;
- byte *code;
- int instruction;
- int *codeBase;
-
- vm->codeBase = Hunk_Alloc( vm->codeLength*4, h_high ); // we're now int aligned
-// memcpy( vm->codeBase, (byte *)header + header->codeOffset, vm->codeLength );
-
- // we don't need to translate the instructions, but we still need
- // to find each instructions starting point for jumps
- int_pc = byte_pc = 0;
- instruction = 0;
- code = (byte *)header + header->codeOffset;
- codeBase = (int *)vm->codeBase;
-
- // Copy and expand instructions to words while building instruction table
- while ( instruction < header->instructionCount ) {
- vm->instructionPointers[ instruction ] = int_pc;
- instruction++;
-
- op = (int)code[ byte_pc ];
- codeBase[int_pc] = op;
- if ( byte_pc > header->codeLength ) {
- Com_Error( ERR_FATAL, "VM_PrepareInterpreter: pc > header->codeLength" );
- }
-
- byte_pc++;
- int_pc++;
-
- // these are the only opcodes that aren't a single byte
- switch ( op ) {
- case OP_ENTER:
- case OP_CONST:
- case OP_LOCAL:
- case OP_LEAVE:
- case OP_EQ:
- case OP_NE:
- case OP_LTI:
- case OP_LEI:
- case OP_GTI:
- case OP_GEI:
- case OP_LTU:
- case OP_LEU:
- case OP_GTU:
- case OP_GEU:
- case OP_EQF:
- case OP_NEF:
- case OP_LTF:
- case OP_LEF:
- case OP_GTF:
- case OP_GEF:
- case OP_BLOCK_COPY:
- codeBase[int_pc] = loadWord(&code[byte_pc]);
- byte_pc += 4;
- int_pc++;
- break;
- case OP_ARG:
- codeBase[int_pc] = (int)code[byte_pc];
- byte_pc++;
- int_pc++;
- break;
- default:
- break;
- }
-
- }
- int_pc = 0;
- instruction = 0;
- code = (byte *)header + header->codeOffset;
-
- // Now that the code has been expanded to int-sized opcodes, we'll translate instruction index
- //into an index into codeBase[], which contains opcodes and operands.
- while ( instruction < header->instructionCount ) {
- op = codeBase[ int_pc ];
- instruction++;
- int_pc++;
-
- switch ( op ) {
- // These ops need to translate addresses in jumps from instruction index to int index
- case OP_EQ:
- case OP_NE:
- case OP_LTI:
- case OP_LEI:
- case OP_GTI:
- case OP_GEI:
- case OP_LTU:
- case OP_LEU:
- case OP_GTU:
- case OP_GEU:
- case OP_EQF:
- case OP_NEF:
- case OP_LTF:
- case OP_LEF:
- case OP_GTF:
- case OP_GEF:
- // codeBase[pc] is the instruction index. Convert that into an offset into
- //the int-aligned codeBase[] by the lookup table.
- codeBase[int_pc] = vm->instructionPointers[codeBase[int_pc]];
- int_pc++;
- break;
-
- // These opcodes have an operand that isn't an instruction index
- case OP_ENTER:
- case OP_CONST:
- case OP_LOCAL:
- case OP_LEAVE:
- case OP_BLOCK_COPY:
- case OP_ARG:
- int_pc++;
- break;
-
- default:
- break;
- }
-
- }
-}
-
-/*
-==============
-VM_Call
-
-
-Upon a system call, the stack will look like:
-
-sp+32 parm1
-sp+28 parm0
-sp+24 return stack
-sp+20 return address
-sp+16 local1
-sp+14 local0
-sp+12 arg1
-sp+8 arg0
-sp+4 return stack
-sp return address
-
-An interpreted function will immediately execute
-an OP_ENTER instruction, which will subtract space for
-locals from sp
-==============
-*/
-
-#define DEBUGSTR va("%s%i", VM_Indent(vm), opStack-stack )
-
-int VM_CallInterpreted( vm_t *vm, int *args ) {
- int stack[OPSTACK_SIZE];
- int *opStack;
- int programCounter;
- int programStack;
- int stackOnEntry;
- byte *image;
- int *codeImage;
- int v1;
- int dataMask;
-#ifdef DEBUG_VM
- vmSymbol_t *profileSymbol;
-#endif
-
- // interpret the code
- vm->currentlyInterpreting = qtrue;
-
- // we might be called recursively, so this might not be the very top
- programStack = stackOnEntry = vm->programStack;
-
-#ifdef DEBUG_VM
- profileSymbol = VM_ValueToFunctionSymbol( vm, 0 );
- // uncomment this for debugging breakpoints
- vm->breakFunction = 0;
-#endif
- // set up the stack frame
-
- image = vm->dataBase;
- codeImage = (int *)vm->codeBase;
- dataMask = vm->dataMask;
-
- // leave a free spot at start of stack so
- // that as long as opStack is valid, opStack-1 will
- // not corrupt anything
- opStack = stack;
- programCounter = 0;
-
- programStack -= 48;
-
- *(int *)&image[ programStack + 44] = args[9];
- *(int *)&image[ programStack + 40] = args[8];
- *(int *)&image[ programStack + 36] = args[7];
- *(int *)&image[ programStack + 32] = args[6];
- *(int *)&image[ programStack + 28] = args[5];
- *(int *)&image[ programStack + 24] = args[4];
- *(int *)&image[ programStack + 20] = args[3];
- *(int *)&image[ programStack + 16] = args[2];
- *(int *)&image[ programStack + 12] = args[1];
- *(int *)&image[ programStack + 8 ] = args[0];
- *(int *)&image[ programStack + 4 ] = 0; // return stack
- *(int *)&image[ programStack ] = -1; // will terminate the loop on return
-
- VM_Debug(0);
-
-// vm_debugLevel=2;
- // main interpreter loop, will exit when a LEAVE instruction
- // grabs the -1 program counter
-
-#define r2 codeImage[programCounter]
-
- while ( 1 ) {
- int opcode, r0, r1;
-// unsigned int r2;
-
-nextInstruction:
- r0 = ((int *)opStack)[0];
- r1 = ((int *)opStack)[-1];
-nextInstruction2:
-#ifdef DEBUG_VM
- if ( (unsigned)programCounter >= vm->codeLength ) {
- Com_Error( ERR_DROP, "VM pc out of range" );
- }
-
- if ( opStack < stack ) {
- Com_Error( ERR_DROP, "VM opStack underflow" );
- }
- if ( opStack >= stack+OPSTACK_SIZE ) {
- Com_Error( ERR_DROP, "VM opStack overflow" );
- }
-
- if ( programStack <= vm->stackBottom ) {
- Com_Error( ERR_DROP, "VM stack overflow" );
- }
-
- if ( programStack & 3 ) {
- Com_Error( ERR_DROP, "VM program stack misaligned" );
- }
-
- if ( vm_debugLevel > 1 ) {
- Com_Printf( "%s %s\n", DEBUGSTR, opnames[opcode] );
- }
- profileSymbol->profileCount++;
-#endif
- opcode = codeImage[ programCounter++ ];
-
- switch ( opcode ) {
-#ifdef DEBUG_VM
- default:
- Com_Error( ERR_DROP, "Bad VM instruction" ); // this should be scanned on load!
-#endif
- case OP_BREAK:
- vm->breakCount++;
- goto nextInstruction2;
- case OP_CONST:
- opStack++;
- r1 = r0;
- r0 = *opStack = r2;
-
- programCounter += 1;
- goto nextInstruction2;
- case OP_LOCAL:
- opStack++;
- r1 = r0;
- r0 = *opStack = r2+programStack;
-
- programCounter += 1;
- goto nextInstruction2;
-
- case OP_LOAD4:
-#ifdef DEBUG_VM
- if ( *opStack & 3 ) {
- Com_Error( ERR_DROP, "OP_LOAD4 misaligned" );
- }
-#endif
- r0 = *opStack = *(int *)&image[ r0&dataMask&~3 ];
- goto nextInstruction2;
- case OP_LOAD2:
- r0 = *opStack = *(unsigned short *)&image[ r0&dataMask&~1 ];
- goto nextInstruction2;
- case OP_LOAD1:
- r0 = *opStack = image[ r0&dataMask ];
- goto nextInstruction2;
-
- case OP_STORE4:
- *(int *)&image[ r1&(dataMask & ~3) ] = r0;
- opStack -= 2;
- goto nextInstruction;
- case OP_STORE2:
- *(short *)&image[ r1&(dataMask & ~1) ] = r0;
- opStack -= 2;
- goto nextInstruction;
- case OP_STORE1:
- image[ r1&dataMask ] = r0;
- opStack -= 2;
- goto nextInstruction;
-
- case OP_ARG:
- // single byte offset from programStack
- *(int *)&image[ (codeImage[programCounter] + programStack)&dataMask&~3 ] = r0;
- opStack--;
- programCounter += 1;
- goto nextInstruction;
-
- case OP_BLOCK_COPY:
- {
- int *src, *dest;
- int count, srci, desti;
-
- count = r2;
- // MrE: copy range check
- srci = r0 & dataMask;
- desti = r1 & dataMask;
- count = ((srci + count) & dataMask) - srci;
- count = ((desti + count) & dataMask) - desti;
-
- src = (int *)&image[ srci ];
- dest = (int *)&image[ desti ];
-
- memcpy(dest, src, count);
- programCounter += 1;
- opStack -= 2;
- }
- goto nextInstruction;
-
- case OP_CALL:
- // save current program counter
- *(int *)&image[ programStack ] = programCounter;
-
- // jump to the location on the stack
- programCounter = r0;
- opStack--;
- if ( programCounter < 0 ) {
- // system call
- int r;
-// int temp;
-#ifdef DEBUG_VM
- int stomped;
-
- if ( vm_debugLevel ) {
- Com_Printf( "%s---> systemcall(%i)\n", DEBUGSTR, -1 - programCounter );
- }
-#endif
- // save the stack to allow recursive VM entry
-// temp = vm->callLevel;
- vm->programStack = programStack - 4;
-#ifdef DEBUG_VM
- stomped = *(int *)&image[ programStack + 4 ];
-#endif
- *(int *)&image[ programStack + 4 ] = -1 - programCounter;
-
-//VM_LogSyscalls( (int *)&image[ programStack + 4 ] );
- {
- intptr_t* argptr = (intptr_t *)&image[ programStack + 4 ];
- #if __WORDSIZE == 64
- // the vm has ints on the stack, we expect
- // longs so we have to convert it
- intptr_t argarr[16];
- int i;
- for (i = 0; i < 16; ++i) {
- argarr[i] = *(int*)&image[ programStack + 4 + 4*i ];
- }
- argptr = argarr;
- #endif
- r = vm->systemCall( argptr );
- }
-
-#ifdef DEBUG_VM
- // this is just our stack frame pointer, only needed
- // for debugging
- *(int *)&image[ programStack + 4 ] = stomped;
-#endif
-
- // save return value
- opStack++;
- *opStack = r;
- programCounter = *(int *)&image[ programStack ];
-// vm->callLevel = temp;
-#ifdef DEBUG_VM
- if ( vm_debugLevel ) {
- Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) );
- }
-#endif
- } else if ( (unsigned)programCounter >= vm->instructionCount ) {
- Com_Error( ERR_DROP, "VM program counter out of range in OP_CALL" );
- } else {
- programCounter = vm->instructionPointers[ programCounter ];
- }
- goto nextInstruction;
-
- // push and pop are only needed for discarded or bad function return values
- case OP_PUSH:
- opStack++;
- goto nextInstruction;
- case OP_POP:
- opStack--;
- goto nextInstruction;
-
- case OP_ENTER:
-#ifdef DEBUG_VM
- profileSymbol = VM_ValueToFunctionSymbol( vm, programCounter );
-#endif
- // get size of stack frame
- v1 = r2;
-
- programCounter += 1;
- programStack -= v1;
-#ifdef DEBUG_VM
- // save old stack frame for debugging traces
- *(int *)&image[programStack+4] = programStack + v1;
- if ( vm_debugLevel ) {
- Com_Printf( "%s---> %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter - 5 ) );
- if ( vm->breakFunction && programCounter - 5 == vm->breakFunction ) {
- // this is to allow setting breakpoints here in the debugger
- vm->breakCount++;
-// vm_debugLevel = 2;
-// VM_StackTrace( vm, programCounter, programStack );
- }
-// vm->callLevel++;
- }
-#endif
- goto nextInstruction;
- case OP_LEAVE:
- // remove our stack frame
- v1 = r2;
-
- programStack += v1;
-
- // grab the saved program counter
- programCounter = *(int *)&image[ programStack ];
-#ifdef DEBUG_VM
- profileSymbol = VM_ValueToFunctionSymbol( vm, programCounter );
- if ( vm_debugLevel ) {
-// vm->callLevel--;
- Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) );
- }
-#endif
- // check for leaving the VM
- if ( programCounter == -1 ) {
- goto done;
- } else if ( (unsigned)programCounter >= vm->codeLength ) {
- Com_Error( ERR_DROP, "VM program counter out of range in OP_LEAVE" );
- }
- goto nextInstruction;
-
- /*
- ===================================================================
- BRANCHES
- ===================================================================
- */
-
- case OP_JUMP:
- if ( (unsigned)r0 >= vm->instructionCount )
- Com_Error( ERR_DROP, "VM program counter out of range in OP_JUMP" );
-
- programCounter = vm->instructionPointers[ r0 ];
-
- opStack--;
- goto nextInstruction;
-
- case OP_EQ:
- opStack -= 2;
- if ( r1 == r0 ) {
- programCounter = r2; //vm->instructionPointers[r2];
- goto nextInstruction;
- } else {
- programCounter += 1;
- goto nextInstruction;
- }
-
- case OP_NE:
- opStack -= 2;
- if ( r1 != r0 ) {
- programCounter = r2; //vm->instructionPointers[r2];
- goto nextInstruction;
- } else {
- programCounter += 1;
- goto nextInstruction;
- }
-
- case OP_LTI:
- opStack -= 2;
- if ( r1 < r0 ) {
- programCounter = r2; //vm->instructionPointers[r2];
- goto nextInstruction;
- } else {
- programCounter += 1;
- goto nextInstruction;
- }
-
- case OP_LEI:
- opStack -= 2;
- if ( r1 <= r0 ) {
- programCounter = r2; //vm->instructionPointers[r2];
- goto nextInstruction;
- } else {
- programCounter += 1;
- goto nextInstruction;
- }
-
- case OP_GTI:
- opStack -= 2;
- if ( r1 > r0 ) {
- programCounter = r2; //vm->instructionPointers[r2];
- goto nextInstruction;
- } else {
- programCounter += 1;
- goto nextInstruction;
- }
-
- case OP_GEI:
- opStack -= 2;
- if ( r1 >= r0 ) {
- programCounter = r2; //vm->instructionPointers[r2];
- goto nextInstruction;
- } else {
- programCounter += 1;
- goto nextInstruction;
- }
-
- case OP_LTU:
- opStack -= 2;
- if ( ((unsigned)r1) < ((unsigned)r0) ) {
- programCounter = r2; //vm->instructionPointers[r2];
- goto nextInstruction;
- } else {
- programCounter += 1;
- goto nextInstruction;
- }
-
- case OP_LEU:
- opStack -= 2;
- if ( ((unsigned)r1) <= ((unsigned)r0) ) {
- programCounter = r2; //vm->instructionPointers[r2];
- goto nextInstruction;
- } else {
- programCounter += 1;
- goto nextInstruction;
- }
-
- case OP_GTU:
- opStack -= 2;
- if ( ((unsigned)r1) > ((unsigned)r0) ) {
- programCounter = r2; //vm->instructionPointers[r2];
- goto nextInstruction;
- } else {
- programCounter += 1;
- goto nextInstruction;
- }
-
- case OP_GEU:
- opStack -= 2;
- if ( ((unsigned)r1) >= ((unsigned)r0) ) {
- programCounter = r2; //vm->instructionPointers[r2];
- goto nextInstruction;
- } else {
- programCounter += 1;
- goto nextInstruction;
- }
-
- case OP_EQF:
- if ( ((float *)opStack)[-1] == *(float *)opStack ) {
- programCounter = r2; //vm->instructionPointers[r2];
- opStack -= 2;
- goto nextInstruction;
- } else {
- programCounter += 1;
- opStack -= 2;
- goto nextInstruction;
- }
-
- case OP_NEF:
- if ( ((float *)opStack)[-1] != *(float *)opStack ) {
- programCounter = r2; //vm->instructionPointers[r2];
- opStack -= 2;
- goto nextInstruction;
- } else {
- programCounter += 1;
- opStack -= 2;
- goto nextInstruction;
- }
-
- case OP_LTF:
- if ( ((float *)opStack)[-1] < *(float *)opStack ) {
- programCounter = r2; //vm->instructionPointers[r2];
- opStack -= 2;
- goto nextInstruction;
- } else {
- programCounter += 1;
- opStack -= 2;
- goto nextInstruction;
- }
-
- case OP_LEF:
- if ( ((float *)opStack)[-1] <= *(float *)opStack ) {
- programCounter = r2; //vm->instructionPointers[r2];
- opStack -= 2;
- goto nextInstruction;
- } else {
- programCounter += 1;
- opStack -= 2;
- goto nextInstruction;
- }
-
- case OP_GTF:
- if ( ((float *)opStack)[-1] > *(float *)opStack ) {
- programCounter = r2; //vm->instructionPointers[r2];
- opStack -= 2;
- goto nextInstruction;
- } else {
- programCounter += 1;
- opStack -= 2;
- goto nextInstruction;
- }
-
- case OP_GEF:
- if ( ((float *)opStack)[-1] >= *(float *)opStack ) {
- programCounter = r2; //vm->instructionPointers[r2];
- opStack -= 2;
- goto nextInstruction;
- } else {
- programCounter += 1;
- opStack -= 2;
- goto nextInstruction;
- }
-
-
- //===================================================================
-
- case OP_NEGI:
- *opStack = -r0;
- goto nextInstruction;
- case OP_ADD:
- opStack[-1] = r1 + r0;
- opStack--;
- goto nextInstruction;
- case OP_SUB:
- opStack[-1] = r1 - r0;
- opStack--;
- goto nextInstruction;
- case OP_DIVI:
- opStack[-1] = r1 / r0;
- opStack--;
- goto nextInstruction;
- case OP_DIVU:
- opStack[-1] = ((unsigned)r1) / ((unsigned)r0);
- opStack--;
- goto nextInstruction;
- case OP_MODI:
- opStack[-1] = r1 % r0;
- opStack--;
- goto nextInstruction;
- case OP_MODU:
- opStack[-1] = ((unsigned)r1) % (unsigned)r0;
- opStack--;
- goto nextInstruction;
- case OP_MULI:
- opStack[-1] = r1 * r0;
- opStack--;
- goto nextInstruction;
- case OP_MULU:
- opStack[-1] = ((unsigned)r1) * ((unsigned)r0);
- opStack--;
- goto nextInstruction;
-
- case OP_BAND:
- opStack[-1] = ((unsigned)r1) & ((unsigned)r0);
- opStack--;
- goto nextInstruction;
- case OP_BOR:
- opStack[-1] = ((unsigned)r1) | ((unsigned)r0);
- opStack--;
- goto nextInstruction;
- case OP_BXOR:
- opStack[-1] = ((unsigned)r1) ^ ((unsigned)r0);
- opStack--;
- goto nextInstruction;
- case OP_BCOM:
- *opStack = ~ ((unsigned)r0);
- goto nextInstruction;
-
- case OP_LSH:
- opStack[-1] = r1 << r0;
- opStack--;
- goto nextInstruction;
- case OP_RSHI:
- opStack[-1] = r1 >> r0;
- opStack--;
- goto nextInstruction;
- case OP_RSHU:
- opStack[-1] = ((unsigned)r1) >> r0;
- opStack--;
- goto nextInstruction;
-
- case OP_NEGF:
- *(float *)opStack = -*(float *)opStack;
- goto nextInstruction;
- case OP_ADDF:
- *(float *)(opStack-1) = *(float *)(opStack-1) + *(float *)opStack;
- opStack--;
- goto nextInstruction;
- case OP_SUBF:
- *(float *)(opStack-1) = *(float *)(opStack-1) - *(float *)opStack;
- opStack--;
- goto nextInstruction;
- case OP_DIVF:
- *(float *)(opStack-1) = *(float *)(opStack-1) / *(float *)opStack;
- opStack--;
- goto nextInstruction;
- case OP_MULF:
- *(float *)(opStack-1) = *(float *)(opStack-1) * *(float *)opStack;
- opStack--;
- goto nextInstruction;
-
- case OP_CVIF:
- *(float *)opStack = (float)*opStack;
- goto nextInstruction;
- case OP_CVFI:
- *opStack = (int) *(float *)opStack;
- goto nextInstruction;
- case OP_SEX8:
- *opStack = (signed char)*opStack;
- goto nextInstruction;
- case OP_SEX16:
- *opStack = (short)*opStack;
- goto nextInstruction;
- }
- }
-
-done:
- vm->currentlyInterpreting = qfalse;
-
- if ( opStack != &stack[1] ) {
- Com_Error( ERR_DROP, "Interpreter error: opStack = %ld", (long int) (opStack - stack) );
- }
-
- vm->programStack = stackOnEntry;
-
- // return the result
- return *opStack;
-}
diff --git a/engine/code/qcommon/vm_local.h b/engine/code/qcommon/vm_local.h
deleted file mode 100644
index 8912771..0000000
--- a/engine/code/qcommon/vm_local.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "q_shared.h"
-#include "qcommon.h"
-
-#define OPSTACK_SIZE 256
-#define OPSTACK_MASK (OPSTACK_SIZE-1)
-
-// don't change
-// Hardcoded in q3asm an reserved at end of bss
-#define PROGRAM_STACK_SIZE 0x10000
-#define PROGRAM_STACK_MASK (PROGRAM_STACK_SIZE-1)
-
-typedef enum {
- OP_UNDEF,
-
- OP_IGNORE,
-
- OP_BREAK,
-
- OP_ENTER,
- OP_LEAVE,
- OP_CALL,
- OP_PUSH,
- OP_POP,
-
- OP_CONST,
- OP_LOCAL,
-
- OP_JUMP,
-
- //-------------------
-
- OP_EQ,
- OP_NE,
-
- OP_LTI,
- OP_LEI,
- OP_GTI,
- OP_GEI,
-
- OP_LTU,
- OP_LEU,
- OP_GTU,
- OP_GEU,
-
- OP_EQF,
- OP_NEF,
-
- OP_LTF,
- OP_LEF,
- OP_GTF,
- OP_GEF,
-
- //-------------------
-
- OP_LOAD1,
- OP_LOAD2,
- OP_LOAD4,
- OP_STORE1,
- OP_STORE2,
- OP_STORE4, // *(stack[top-1]) = stack[top]
- OP_ARG,
-
- OP_BLOCK_COPY,
-
- //-------------------
-
- OP_SEX8,
- OP_SEX16,
-
- OP_NEGI,
- OP_ADD,
- OP_SUB,
- OP_DIVI,
- OP_DIVU,
- OP_MODI,
- OP_MODU,
- OP_MULI,
- OP_MULU,
-
- OP_BAND,
- OP_BOR,
- OP_BXOR,
- OP_BCOM,
-
- OP_LSH,
- OP_RSHI,
- OP_RSHU,
-
- OP_NEGF,
- OP_ADDF,
- OP_SUBF,
- OP_DIVF,
- OP_MULF,
-
- OP_CVIF,
- OP_CVFI
-} opcode_t;
-
-
-
-typedef int vmptr_t;
-
-typedef struct vmSymbol_s {
- struct vmSymbol_s *next;
- int symValue;
- int profileCount;
- char symName[1]; // variable sized
-} vmSymbol_t;
-
-#define VM_OFFSET_PROGRAM_STACK 0
-#define VM_OFFSET_SYSTEM_CALL 4
-
-struct vm_s {
- // DO NOT MOVE OR CHANGE THESE WITHOUT CHANGING THE VM_OFFSET_* DEFINES
- // USED BY THE ASM CODE
- int programStack; // the vm may be recursively entered
- intptr_t (*systemCall)( intptr_t *parms );
-
- //------------------------------------
-
- char name[MAX_QPATH];
-
- // for dynamic linked modules
- void *dllHandle;
- intptr_t (QDECL *entryPoint)( int callNum, ... );
- void (*destroy)(vm_t* self);
-
- // for interpreted modules
- qboolean currentlyInterpreting;
-
- qboolean compiled;
- byte *codeBase;
- int codeLength;
-
- int *instructionPointers;
- int instructionCount;
-
- byte *dataBase;
- int dataMask;
-
- int stackBottom; // if programStack < stackBottom, error
-
- int numSymbols;
- struct vmSymbol_s *symbols;
-
- int callLevel; // counts recursive VM_Call
- int breakFunction; // increment breakCount on function entry to this
- int breakCount;
-
- char fqpath[MAX_QPATH+1] ;
-
- byte *jumpTableTargets;
- int numJumpTableTargets;
-};
-
-
-extern vm_t *currentVM;
-extern int vm_debugLevel;
-
-void VM_Compile( vm_t *vm, vmHeader_t *header );
-int VM_CallCompiled( vm_t *vm, int *args );
-
-void VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header );
-int VM_CallInterpreted( vm_t *vm, int *args );
-
-vmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value );
-int VM_SymbolToValue( vm_t *vm, const char *symbol );
-const char *VM_ValueToSymbol( vm_t *vm, int value );
-void VM_LogSyscalls( int *args );
diff --git a/engine/code/qcommon/vm_none.c b/engine/code/qcommon/vm_none.c
deleted file mode 100644
index c7e5ba0..0000000
--- a/engine/code/qcommon/vm_none.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "vm_local.h"
-
-int VM_CallCompiled( vm_t *vm, int *args ) {
- exit(99);
- return 0;
-}
-
-void VM_Compile( vm_t *vm, vmHeader_t *header ) {
- exit(99);
-}
diff --git a/engine/code/qcommon/vm_powerpc.c b/engine/code/qcommon/vm_powerpc.c
deleted file mode 100644
index 76bb984..0000000
--- a/engine/code/qcommon/vm_powerpc.c
+++ /dev/null
@@ -1,2170 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 2008 Przemyslaw Iskra <sparky at pld-linux.org>
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include <sys/types.h> /* needed by sys/mman.h on OSX */
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <time.h>
-#include <stddef.h>
-
-#ifndef MAP_ANONYMOUS
-# define MAP_ANONYMOUS MAP_ANON
-#endif
-
-#include "vm_local.h"
-#include "vm_powerpc_asm.h"
-
-/*
- * VM_TIMES enables showing information about time spent inside
- * and outside generated code
- */
-//#define VM_TIMES
-#ifdef VM_TIMES
-#include <sys/times.h>
-static clock_t time_outside_vm = 0;
-static clock_t time_total_vm = 0;
-#endif
-
-/* exit() won't be called but use it because it is marked with noreturn */
-#define DIE( reason ) \
- do { \
- Com_Error(ERR_DROP, "vm_powerpc compiler error: " reason "\n"); \
- exit(1); \
- } while(0)
-
-/*
- * vm_powerpc uses large quantities of memory during compilation,
- * Z_Malloc memory may not be enough for some big qvm files
- */
-
-//#define VM_SYSTEM_MALLOC
-#ifdef VM_SYSTEM_MALLOC
-static inline void *
-PPC_Malloc( size_t size )
-{
- void *mem = malloc( size );
- if ( ! mem )
- DIE( "Not enough memory" );
-
- return mem;
-}
-# define PPC_Free free
-#else
-# define PPC_Malloc Z_Malloc
-# define PPC_Free Z_Free
-#endif
-
-/*
- * optimizations:
- * - hole: bubble optimization (OP_CONST+instruction)
- * - copy: inline OP_BLOCK_COPY for lengths under 16/32 bytes
- * - mask: use rlwinm instruction as dataMask
- */
-
-#ifdef __OPTIMIZE__
-# define OPTIMIZE_HOLE 1
-# define OPTIMIZE_COPY 1
-# define OPTIMIZE_MASK 1
-#else
-# define OPTIMIZE_HOLE 0
-# define OPTIMIZE_COPY 0
-# define OPTIMIZE_MASK 0
-#endif
-
-/*
- * SUPPORTED TARGETS:
- * - Linux 32 bits
- * ( http://refspecs.freestandards.org/elf/elfspec_ppc.pdf )
- * * LR at r0 + 4
- * * Local variable space not needed
- * -> store caller safe regs at 16+
- *
- * - Linux 64 bits (not fully conformant)
- * ( http://www.ibm.com/developerworks/linux/library/l-powasm4.html )
- * * needs "official procedure descriptors" (only first function has one)
- * * LR at r0 + 16
- * * local variable space required, min 64 bytes, starts at 48
- * -> store caller safe regs at 128+
- *
- * - OS X 32 bits
- * ( http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/Articles/32bitPowerPC.html )
- * * LR at r0 + 8
- * * local variable space required, min 32 bytes (?), starts at 24
- * -> store caller safe regs at 64+
- *
- * - OS X 64 bits (completely untested)
- * ( http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/Articles/64bitPowerPC.html )
- * * LR at r0 + 16
- * * local variable space required, min 64 bytes (?), starts at 48
- * -> store caller safe regs at 128+
- */
-
-/* Select Length - first value on 32 bits, second on 64 */
-#ifdef __PPC64__
-# define SL( a, b ) (b)
-#else
-# define SL( a, b ) (a)
-#endif
-
-/* Select ABI - first for ELF, second for OS X */
-#ifdef __ELF__
-# define SA( a, b ) (a)
-#else
-# define SA( a, b ) (b)
-#endif
-
-#define ELF32 SL( SA( 1, 0 ), 0 )
-#define ELF64 SL( 0, SA( 1, 0 ) )
-#define OSX32 SL( SA( 0, 1 ), 0 )
-#define OSX64 SL( 0, SA( 0, 1 ) )
-
-/* native length load/store instructions ( L stands for long ) */
-#define iSTLU SL( iSTWU, iSTDU )
-#define iSTL SL( iSTW, iSTD )
-#define iLL SL( iLWZ, iLD )
-#define iLLX SL( iLWZX, iLDX )
-
-/* register length */
-#define GPRLEN SL( 4, 8 )
-#define FPRLEN (8)
-/* shift that many bits to obtain value miltiplied by GPRLEN */
-#define GPRLEN_SHIFT SL( 2, 3 )
-
-/* Link register position */
-#define STACK_LR SL( SA( 4, 8 ), 16 )
-/* register save position */
-#define STACK_SAVE SL( SA( 16, 64 ), 128 )
-/* temporary space, for float<->int exchange */
-#define STACK_TEMP SL( SA( 8, 24 ), 48 )
-/* red zone temporary space, used instead of STACK_TEMP if stack isn't
- * prepared properly */
-#define STACK_RTEMP (-16)
-
-#if ELF64
-/*
- * Official Procedure Descriptor
- * we need to prepare one for generated code if we want to call it
- * as function
- */
-typedef struct {
- void *function;
- void *toc;
- void *env;
-} opd_t;
-#endif
-
-
-/*
- * opcode information table:
- * - length of immediate value
- * - returned register type
- * - required register(s) type
- */
-#define opImm0 0x0000 /* no immediate */
-#define opImm1 0x0001 /* 1 byte immadiate value after opcode */
-#define opImm4 0x0002 /* 4 bytes immediate value after opcode */
-
-#define opRet0 0x0000 /* returns nothing */
-#define opRetI 0x0004 /* returns integer */
-#define opRetF 0x0008 /* returns float */
-#define opRetIF (opRetI | opRetF) /* returns integer or float */
-
-#define opArg0 0x0000 /* requires nothing */
-#define opArgI 0x0010 /* requires integer(s) */
-#define opArgF 0x0020 /* requires float(s) */
-#define opArgIF (opArgI | opArgF) /* requires integer or float */
-
-#define opArg2I 0x0040 /* requires second argument, integer */
-#define opArg2F 0x0080 /* requires second argument, float */
-#define opArg2IF (opArg2I | opArg2F) /* requires second argument, integer or float */
-
-static const unsigned char vm_opInfo[256] =
-{
- [OP_UNDEF] = opImm0,
- [OP_IGNORE] = opImm0,
- [OP_BREAK] = opImm0,
- [OP_ENTER] = opImm4,
- /* OP_LEAVE has to accept floats, they will be converted to ints */
- [OP_LEAVE] = opImm4 | opRet0 | opArgIF,
- /* only STORE4 and POP use values from OP_CALL,
- * no need to convert floats back */
- [OP_CALL] = opImm0 | opRetI | opArgI,
- [OP_PUSH] = opImm0 | opRetIF,
- [OP_POP] = opImm0 | opRet0 | opArgIF,
- [OP_CONST] = opImm4 | opRetIF,
- [OP_LOCAL] = opImm4 | opRetI,
- [OP_JUMP] = opImm0 | opRet0 | opArgI,
-
- [OP_EQ] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_NE] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_LTI] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_LEI] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_GTI] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_GEI] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_LTU] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_LEU] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_GTU] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_GEU] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_EQF] = opImm4 | opRet0 | opArgF | opArg2F,
- [OP_NEF] = opImm4 | opRet0 | opArgF | opArg2F,
- [OP_LTF] = opImm4 | opRet0 | opArgF | opArg2F,
- [OP_LEF] = opImm4 | opRet0 | opArgF | opArg2F,
- [OP_GTF] = opImm4 | opRet0 | opArgF | opArg2F,
- [OP_GEF] = opImm4 | opRet0 | opArgF | opArg2F,
-
- [OP_LOAD1] = opImm0 | opRetI | opArgI,
- [OP_LOAD2] = opImm0 | opRetI | opArgI,
- [OP_LOAD4] = opImm0 | opRetIF| opArgI,
- [OP_STORE1] = opImm0 | opRet0 | opArgI | opArg2I,
- [OP_STORE2] = opImm0 | opRet0 | opArgI | opArg2I,
- [OP_STORE4] = opImm0 | opRet0 | opArgIF| opArg2I,
- [OP_ARG] = opImm1 | opRet0 | opArgIF,
- [OP_BLOCK_COPY] = opImm4 | opRet0 | opArgI | opArg2I,
-
- [OP_SEX8] = opImm0 | opRetI | opArgI,
- [OP_SEX16] = opImm0 | opRetI | opArgI,
- [OP_NEGI] = opImm0 | opRetI | opArgI,
- [OP_ADD] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_SUB] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_DIVI] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_DIVU] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_MODI] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_MODU] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_MULI] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_MULU] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_BAND] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_BOR] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_BXOR] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_BCOM] = opImm0 | opRetI | opArgI,
- [OP_LSH] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_RSHI] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_RSHU] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_NEGF] = opImm0 | opRetF | opArgF,
- [OP_ADDF] = opImm0 | opRetF | opArgF | opArg2F,
- [OP_SUBF] = opImm0 | opRetF | opArgF | opArg2F,
- [OP_DIVF] = opImm0 | opRetF | opArgF | opArg2F,
- [OP_MULF] = opImm0 | opRetF | opArgF | opArg2F,
- [OP_CVIF] = opImm0 | opRetF | opArgI,
- [OP_CVFI] = opImm0 | opRetI | opArgF,
-};
-
-/*
- * source instruction data
- */
-typedef struct source_instruction_s source_instruction_t;
-struct source_instruction_s {
- // opcode
- unsigned long int op;
-
- // number of instruction
- unsigned long int i_count;
-
- // immediate value (if any)
- union {
- unsigned int i;
- signed int si;
- signed short ss[2];
- unsigned short us[2];
- unsigned char b;
- } arg;
-
- // required and returned registers
- unsigned char regA1;
- unsigned char regA2;
- unsigned char regR;
- unsigned char regPos;
-
- // next instruction
- source_instruction_t *next;
-};
-
-
-
-/*
- * read-only data needed by the generated code
- */
-typedef struct VM_Data {
- // length of this struct + data
- size_t dataLength;
- // compiled code size (in bytes)
- // it only is code size, without the data
- size_t codeLength;
-
- // function pointers, no use to waste registers for them
- long int (* AsmCall)( int, int );
- void (* BlockCopy )( unsigned int, unsigned int, unsigned int );
-
- // instruction pointers, rarely used so don't waste register
- ppc_instruction_t *iPointers;
-
- // data mask for load and store, not used if optimized
- unsigned int dataMask;
-
- // fixed number used to convert from integer to float
- unsigned int floatBase; // 0x59800004
-
-#if ELF64
- // official procedure descriptor
- opd_t opd;
-#endif
-
- // additional constants, for floating point OP_CONST
- // this data has dynamic length, thus '0' here
- unsigned int data[0];
-} vm_data_t;
-
-#ifdef offsetof
-# define VM_Data_Offset( field ) offsetof( vm_data_t, field )
-#else
-# define OFFSET( structName, field ) \
- ( (void *)&(((structName *)NULL)->field) - NULL )
-# define VM_Data_Offset( field ) OFFSET( vm_data_t, field )
-#endif
-
-
-/*
- * functions used by generated code
- */
-static long int
-VM_AsmCall( int callSyscallInvNum, int callProgramStack )
-{
- vm_t *savedVM = currentVM;
- long int i, ret;
-#ifdef VM_TIMES
- struct tms start_time, stop_time;
- clock_t saved_time = time_outside_vm;
- times( &start_time );
-#endif
-
- // save the stack to allow recursive VM entry
- currentVM->programStack = callProgramStack - 4;
-
- // we need to convert ints to longs on 64bit powerpcs
- if ( sizeof( intptr_t ) == sizeof( int ) ) {
- intptr_t *argPosition = (intptr_t *)((byte *)currentVM->dataBase + callProgramStack + 4);
-
- // generated code does not invert syscall number
- argPosition[ 0 ] = -1 - callSyscallInvNum;
-
- ret = currentVM->systemCall( argPosition );
- } else {
- intptr_t args[11];
-
- // generated code does not invert syscall number
- args[0] = -1 - callSyscallInvNum;
-
- int *argPosition = (int *)((byte *)currentVM->dataBase + callProgramStack + 4);
- for( i = 1; i < 11; i++ )
- args[ i ] = argPosition[ i ];
-
- ret = currentVM->systemCall( args );
- }
-
- currentVM = savedVM;
-
-#ifdef VM_TIMES
- times( &stop_time );
- time_outside_vm = saved_time + ( stop_time.tms_utime - start_time.tms_utime );
-#endif
-
- return ret;
-}
-
-static void
-VM_BlockCopy( unsigned int dest, unsigned int src, unsigned int count )
-{
- unsigned dataMask = currentVM->dataMask;
-
- if ( (dest & dataMask) != dest
- || (src & dataMask) != src
- || ((dest+count) & dataMask) != dest + count
- || ((src+count) & dataMask) != src + count)
- {
- DIE( "OP_BLOCK_COPY out of range!");
- }
-
- memcpy( currentVM->dataBase+dest, currentVM->dataBase+src, count );
-}
-
-
-/*
- * code-block descriptors
- */
-typedef struct dest_instruction dest_instruction_t;
-typedef struct symbolic_jump symbolic_jump_t;
-
-struct symbolic_jump {
- // number of source instruction it has to jump to
- unsigned long int jump_to;
-
- // jump condition true/false, (4*cr7+(eq|gt..))
- long int bo, bi;
-
- // extensions / modifiers (branch-link)
- unsigned long ext;
-
- // dest_instruction refering to this jump
- dest_instruction_t *parent;
-
- // next jump
- symbolic_jump_t *nextJump;
-};
-
-struct dest_instruction {
- // position in the output chain
- unsigned long int count;
-
- // source instruction number
- unsigned long int i_count;
-
- // exact (for instructins), or maximum (for jump) length
- unsigned short length;
-
- dest_instruction_t *next;
-
- // if the instruction is a jump than jump will be non NULL
- symbolic_jump_t *jump;
-
- // if jump is NULL than all the instructions will be here
- ppc_instruction_t code[0];
-};
-
-// first and last instruction,
-// di_first is a dummy instruction
-static dest_instruction_t *di_first = NULL, *di_last = NULL;
-// number of instructions
-static unsigned long int di_count = 0;
-// pointers needed to compute local jumps, those aren't pointers to
-// actual instructions, just used to check how long the jump is going
-// to be and whether it is positive or negative
-static dest_instruction_t **di_pointers = NULL;
-
-// output instructions which does not come from source code
-// use false i_count value
-#define FALSE_ICOUNT 0xffffffff
-
-
-/*
- * append specified instructions at the end of instruction chain
- */
-static void
-PPC_Append(
- dest_instruction_t *di_now,
- unsigned long int i_count
- )
-{
- di_now->count = di_count++;
- di_now->i_count = i_count;
- di_now->next = NULL;
-
- di_last->next = di_now;
- di_last = di_now;
-
- if ( i_count != FALSE_ICOUNT ) {
- if ( ! di_pointers[ i_count ] )
- di_pointers[ i_count ] = di_now;
- }
-}
-
-/*
- * make space for instructions and append
- */
-static void
-PPC_AppendInstructions(
- unsigned long int i_count,
- size_t num_instructions,
- const ppc_instruction_t *is
- )
-{
- if ( num_instructions < 0 )
- num_instructions = 0;
- size_t iBytes = sizeof( ppc_instruction_t ) * num_instructions;
- dest_instruction_t *di_now = PPC_Malloc( sizeof( dest_instruction_t ) + iBytes );
-
- di_now->length = num_instructions;
- di_now->jump = NULL;
-
- if ( iBytes > 0 )
- memcpy( &(di_now->code[0]), is, iBytes );
-
- PPC_Append( di_now, i_count );
-}
-
-/*
- * create symbolic jump and append
- */
-static symbolic_jump_t *sj_first = NULL, *sj_last = NULL;
-static void
-PPC_PrepareJump(
- unsigned long int i_count,
- unsigned long int dest,
- long int bo,
- long int bi,
- unsigned long int ext
- )
-{
- dest_instruction_t *di_now = PPC_Malloc( sizeof( dest_instruction_t ) );
- symbolic_jump_t *sj = PPC_Malloc( sizeof( symbolic_jump_t ) );
-
- sj->jump_to = dest;
- sj->bo = bo;
- sj->bi = bi;
- sj->ext = ext;
- sj->parent = di_now;
- sj->nextJump = NULL;
-
- sj_last->nextJump = sj;
- sj_last = sj;
-
- di_now->length = (bo == branchAlways ? 1 : 2);
- di_now->jump = sj;
-
- PPC_Append( di_now, i_count );
-}
-
-/*
- * simplyfy instruction emission
- */
-#define emitStart( i_cnt ) \
- unsigned long int i_count = i_cnt; \
- size_t num_instructions = 0; \
- long int force_emit = 0; \
- ppc_instruction_t instructions[50];
-
-#define pushIn( inst ) \
- (instructions[ num_instructions++ ] = inst)
-#define in( inst, args... ) pushIn( IN( inst, args ) )
-
-#define emitEnd() \
- do{ \
- if ( num_instructions || force_emit ) \
- PPC_AppendInstructions( i_count, num_instructions, instructions );\
- num_instructions = 0; \
- } while(0)
-
-#define emitJump( dest, bo, bi, ext ) \
- do { \
- emitEnd(); \
- PPC_PrepareJump( i_count, dest, bo, bi, ext ); \
- } while(0)
-
-
-/*
- * definitions for creating .data section,
- * used in cases where constant float is needed
- */
-#define LOCAL_DATA_CHUNK 50
-typedef struct local_data_s local_data_t;
-struct local_data_s {
- // number of data in this structure
- long int count;
-
- // data placeholder
- unsigned int data[ LOCAL_DATA_CHUNK ];
-
- // next chunk, if this one wasn't enough
- local_data_t *next;
-};
-
-// first data chunk
-static local_data_t *data_first = NULL;
-// total number of data
-static long int data_acc = 0;
-
-/*
- * append the data and return its offset
- */
-static size_t
-PPC_PushData( unsigned int datum )
-{
- local_data_t *d_now = data_first;
- long int accumulated = 0;
-
- // check whether we have this one already
- do {
- long int i;
- for ( i = 0; i < d_now->count; i++ ) {
- if ( d_now->data[ i ] == datum ) {
- accumulated += i;
- return VM_Data_Offset( data[ accumulated ] );
- }
- }
- if ( !d_now->next )
- break;
-
- accumulated += d_now->count;
- d_now = d_now->next;
- } while (1);
-
- // not found, need to append
- accumulated += d_now->count;
-
- // last chunk is full, create new one
- if ( d_now->count >= LOCAL_DATA_CHUNK ) {
- d_now->next = PPC_Malloc( sizeof( local_data_t ) );
- d_now = d_now->next;
- d_now->count = 0;
- d_now->next = NULL;
- }
-
- d_now->data[ d_now->count ] = datum;
- d_now->count += 1;
-
- data_acc = accumulated + 1;
-
- return VM_Data_Offset( data[ accumulated ] );
-}
-
-/*
- * find leading zeros in dataMask to implement it with
- * "rotate and mask" instruction
- */
-static long int fastMaskHi = 0, fastMaskLo = 31;
-static void
-PPC_MakeFastMask( int mask )
-{
-#if defined( __GNUC__ ) && ( __GNUC__ >= 4 || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 4 ) )
- /* count leading zeros */
- fastMaskHi = __builtin_clz( mask );
-
- /* count trailing zeros */
- fastMaskLo = 31 - __builtin_ctz( mask );
-#else
- fastMaskHi = 0;
- while ( ( mask & ( 0x80000000 >> fastMaskHi ) ) == 0 )
- fastMaskHi++;
-
- fastMaskLo = 31;
- while ( ( mask & ( 0x80000000 >> fastMaskLo ) ) == 0 )
- fastMaskLo--;
-#endif
-}
-
-
-/*
- * register definitions
- */
-
-/* registers which are global for generated code */
-
-// pointer to VM_Data (constant)
-#define rVMDATA r14
-// vm->dataBase (constant)
-#define rDATABASE r15
-// programStack (variable)
-#define rPSTACK r16
-
-/*
- * function local registers,
- *
- * normally only volatile registers are used, but if there aren't enough
- * or function has to preserve some value while calling annother one
- * then caller safe registers are used as well
- */
-static const long int gpr_list[] = {
- /* caller safe registers, normally only one is used */
- r24, r23, r22, r21,
- r20, r19, r18, r17,
- /* volatile registers (preferred),
- * normally no more than 5 is used */
- r3, r4, r5, r6,
- r7, r8, r9, r10,
-};
-static const long int gpr_vstart = 8; /* position of first volatile register */
-static const long int gpr_total = sizeof( gpr_list ) / sizeof( gpr_list[0] );
-
-static const long int fpr_list[] = {
- /* static registers, normally none is used */
- f20, f21, f19, f18,
- f17, f16, f15, f14,
- /* volatile registers (preferred),
- * normally no more than 7 is used */
- f0, f1, f2, f3,
- f4, f5, f6, f7,
- f8, f9, f10, f11,
- f12, f13,
-};
-static const long int fpr_vstart = 8;
-static const long int fpr_total = sizeof( fpr_list ) / sizeof( fpr_list[0] );
-
-/*
- * prepare some dummy structures and emit init code
- */
-static void
-PPC_CompileInit( void )
-{
- di_first = di_last = PPC_Malloc( sizeof( dest_instruction_t ) );
- di_first->count = 0;
- di_first->next = NULL;
- di_first->jump = NULL;
-
- sj_first = sj_last = PPC_Malloc( sizeof( symbolic_jump_t ) );
- sj_first->nextJump = NULL;
-
- data_first = PPC_Malloc( sizeof( local_data_t ) );
- data_first->count = 0;
- data_first->next = NULL;
-
- /*
- * init function:
- * saves old values of global registers and sets our values
- * function prototype is:
- * int begin( void *data, int programStack, void *vm->dataBase )
- */
-
- /* first instruction must not be placed on instruction list */
- emitStart( FALSE_ICOUNT );
-
- long int stack = STACK_SAVE + 4 * GPRLEN;
-
- in( iMFLR, r0 );
- in( iSTLU, r1, -stack, r1 );
- in( iSTL, rVMDATA, STACK_SAVE + 0 * GPRLEN, r1 );
- in( iSTL, rPSTACK, STACK_SAVE + 1 * GPRLEN, r1 );
- in( iSTL, rDATABASE, STACK_SAVE + 2 * GPRLEN, r1 );
- in( iSTL, r0, stack + STACK_LR, r1 );
- in( iMR, rVMDATA, r3 );
- in( iMR, rPSTACK, r4 );
- in( iMR, rDATABASE, r5 );
- in( iBL, +4*8 ); // LINK JUMP: first generated instruction | XXX jump !
- in( iLL, rVMDATA, STACK_SAVE + 0 * GPRLEN, r1 );
- in( iLL, rPSTACK, STACK_SAVE + 1 * GPRLEN, r1 );
- in( iLL, rDATABASE, STACK_SAVE + 2 * GPRLEN, r1 );
- in( iLL, r0, stack + STACK_LR, r1 );
- in( iMTLR, r0 );
- in( iADDI, r1, r1, stack );
- in( iBLR );
-
- emitEnd();
-}
-
-// rFIRST is the copy of the top value on the opstack
-#define rFIRST (gpr_list[ gpr_pos - 1])
-// second value on the opstack
-#define rSECOND (gpr_list[ gpr_pos - 2 ])
-// temporary registers, not on the opstack
-#define rTEMP(x) (gpr_list[ gpr_pos + x ])
-#define rTMP rTEMP(0)
-
-#define fFIRST (fpr_list[ fpr_pos - 1 ])
-#define fSECOND (fpr_list[ fpr_pos - 2 ])
-#define fTEMP(x) (fpr_list[ fpr_pos + x ])
-#define fTMP fTEMP(0)
-
-// register types
-#define rTYPE_STATIC 0x01
-#define rTYPE_FLOAT 0x02
-
-// what type should this opcode return
-#define RET_INT ( !(i_now->regR & rTYPE_FLOAT) )
-#define RET_FLOAT ( i_now->regR & rTYPE_FLOAT )
-// what type should it accept
-#define ARG_INT ( ! i_now->regA1 )
-#define ARG_FLOAT ( i_now->regA1 )
-#define ARG2_INT ( ! i_now->regA2 )
-#define ARG2_FLOAT ( i_now->regA2 )
-
-/*
- * emit OP_CONST, called if nothing has used the const value directly
- */
-static void
-PPC_EmitConst( source_instruction_t * const i_const )
-{
- emitStart( i_const->i_count );
-
- if ( !(i_const->regR & rTYPE_FLOAT) ) {
- // gpr_pos needed for "rFIRST" to work
- long int gpr_pos = i_const->regPos;
-
- if ( i_const->arg.si >= -0x8000 && i_const->arg.si < 0x8000 ) {
- in( iLI, rFIRST, i_const->arg.si );
- } else if ( i_const->arg.i < 0x10000 ) {
- in( iLI, rFIRST, 0 );
- in( iORI, rFIRST, rFIRST, i_const->arg.i );
- } else {
- in( iLIS, rFIRST, i_const->arg.ss[ 0 ] );
- if ( i_const->arg.us[ 1 ] != 0 )
- in( iORI, rFIRST, rFIRST, i_const->arg.us[ 1 ] );
- }
-
- } else {
- // fpr_pos needed for "fFIRST" to work
- long int fpr_pos = i_const->regPos;
-
- // there's no good way to generate the data,
- // just read it from data section
- in( iLFS, fFIRST, PPC_PushData( i_const->arg.i ), rVMDATA );
- }
-
- emitEnd();
-}
-#define MAYBE_EMIT_CONST() if ( i_const ) PPC_EmitConst( i_const )
-
-/*
- * emit empty instruction, just sets the needed pointers
- */
-static inline void
-PPC_EmitNull( source_instruction_t * const i_null )
-{
- PPC_AppendInstructions( i_null->i_count, 0, NULL );
-}
-#define EMIT_FALSE_CONST() PPC_EmitNull( i_const )
-
-
-/*
- * analize function for register usage and whether it needs stack (r1) prepared
- */
-static void
-VM_AnalyzeFunction(
- source_instruction_t * const i_first,
- long int *prepareStack,
- long int *gpr_start_pos,
- long int *fpr_start_pos
- )
-{
- source_instruction_t *i_now = i_first;
-
- source_instruction_t *value_provider[20] = { NULL };
- unsigned long int opstack_depth = 0;
-
- /*
- * first step:
- * remember what codes returned some value and mark the value type
- * when we get to know what it should be
- */
- while ( (i_now = i_now->next) ) {
- unsigned long int op = i_now->op;
- unsigned long int opi = vm_opInfo[ op ];
-
- if ( opi & opArgIF ) {
- assert( opstack_depth > 0 );
-
- opstack_depth--;
- source_instruction_t *vp = value_provider[ opstack_depth ];
- unsigned long int vpopi = vm_opInfo[ vp->op ];
-
- if ( (opi & opArgI) && (vpopi & opRetI) ) {
- // instruction accepts integer, provider returns integer
- //vp->regR |= rTYPE_INT;
- //i_now->regA1 = rTYPE_INT;
- } else if ( (opi & opArgF) && (vpopi & opRetF) ) {
- // instruction accepts float, provider returns float
- vp->regR |= rTYPE_FLOAT; // use OR here - could be marked as static
- i_now->regA1 = rTYPE_FLOAT;
- } else {
- // instruction arg type does not agree with
- // provider return type
- DIE( "unrecognized instruction combination" );
- }
-
- }
- if ( opi & opArg2IF ) {
- assert( opstack_depth > 0 );
-
- opstack_depth--;
- source_instruction_t *vp = value_provider[ opstack_depth ];
- unsigned long int vpopi = vm_opInfo[ vp->op ];
-
- if ( (opi & opArg2I) && (vpopi & opRetI) ) {
- // instruction accepts integer, provider returns integer
- //vp->regR |= rTYPE_INT;
- //i_now->regA2 = rTYPE_INT;
- } else if ( (opi & opArg2F) && (vpopi & opRetF) ) {
- // instruction accepts float, provider returns float
- vp->regR |= rTYPE_FLOAT; // use OR here - could be marked as static
- i_now->regA2 = rTYPE_FLOAT;
- } else {
- // instruction arg type does not agree with
- // provider return type
- DIE( "unrecognized instruction combination" );
- }
- }
-
-
- if (
- ( op == OP_CALL )
- ||
- ( op == OP_BLOCK_COPY && ( i_now->arg.i > SL( 16, 32 ) || !OPTIMIZE_COPY ) )
- ) {
- long int i;
- *prepareStack = 1;
- // force caller safe registers so we won't have to save them
- for ( i = 0; i < opstack_depth; i++ ) {
- source_instruction_t *vp = value_provider[ i ];
- vp->regR |= rTYPE_STATIC;
- }
- }
-
-
- if ( opi & opRetIF ) {
- value_provider[ opstack_depth ] = i_now;
- opstack_depth++;
- }
- }
-
- /*
- * second step:
- * now that we know register types; compute exactly how many registers
- * of each type we need
- */
-
- i_now = i_first;
- long int needed_reg[4] = {0,0,0,0}, max_reg[4] = {0,0,0,0};
- opstack_depth = 0;
- while ( (i_now = i_now->next) ) {
- unsigned long int op = i_now->op;
- unsigned long int opi = vm_opInfo[ op ];
-
- if ( opi & opArgIF ) {
- assert( opstack_depth > 0 );
- opstack_depth--;
- source_instruction_t *vp = value_provider[ opstack_depth ];
-
- needed_reg[ ( vp->regR & 2 ) ] -= 1;
- if ( vp->regR & 1 ) // static
- needed_reg[ ( vp->regR & 3 ) ] -= 1;
- }
- if ( opi & opArg2IF ) {
- assert( opstack_depth > 0 );
- opstack_depth--;
- source_instruction_t *vp = value_provider[ opstack_depth ];
-
- needed_reg[ ( vp->regR & 2 ) ] -= 1;
- if ( vp->regR & 1 ) // static
- needed_reg[ ( vp->regR & 3 ) ] -= 1;
- }
-
- if ( opi & opRetIF ) {
- long int i;
- value_provider[ opstack_depth ] = i_now;
- opstack_depth++;
-
- i = i_now->regR & 2;
- needed_reg[ i ] += 1;
- if ( max_reg[ i ] < needed_reg[ i ] )
- max_reg[ i ] = needed_reg[ i ];
-
- i = i_now->regR & 3;
- if ( i & 1 ) {
- needed_reg[ i ] += 1;
- if ( max_reg[ i ] < needed_reg[ i ] )
- max_reg[ i ] = needed_reg[ i ];
- }
- }
- }
-
- long int gpr_start = gpr_vstart;
- const long int gpr_volatile = gpr_total - gpr_vstart;
- if ( max_reg[ 1 ] > 0 || max_reg[ 0 ] > gpr_volatile ) {
- // max_reg[ 0 ] - all gprs needed
- // max_reg[ 1 ] - static gprs needed
- long int max = max_reg[ 0 ] - gpr_volatile;
- if ( max_reg[ 1 ] > max )
- max = max_reg[ 1 ];
- if ( max > gpr_vstart ) {
- /* error */
- DIE( "Need more GPRs" );
- }
-
- gpr_start -= max;
-
- // need stack to save caller safe registers
- *prepareStack = 1;
- }
- *gpr_start_pos = gpr_start;
-
- long int fpr_start = fpr_vstart;
- const long int fpr_volatile = fpr_total - fpr_vstart;
- if ( max_reg[ 3 ] > 0 || max_reg[ 2 ] > fpr_volatile ) {
- // max_reg[ 2 ] - all fprs needed
- // max_reg[ 3 ] - static fprs needed
- long int max = max_reg[ 2 ] - fpr_volatile;
- if ( max_reg[ 3 ] > max )
- max = max_reg[ 3 ];
- if ( max > fpr_vstart ) {
- /* error */
- DIE( "Need more FPRs" );
- }
-
- fpr_start -= max;
-
- // need stack to save caller safe registers
- *prepareStack = 1;
- }
- *fpr_start_pos = fpr_start;
-}
-
-/*
- * translate opcodes to ppc instructions,
- * it works on functions, not on whole code at once
- */
-static void
-VM_CompileFunction( source_instruction_t * const i_first )
-{
- long int prepareStack = 0;
- long int gpr_start_pos, fpr_start_pos;
-
- VM_AnalyzeFunction( i_first, &prepareStack, &gpr_start_pos, &fpr_start_pos );
-
- long int gpr_pos = gpr_start_pos, fpr_pos = fpr_start_pos;
-
- // OP_CONST combines well with many opcodes so we treat it in a special way
- source_instruction_t *i_const = NULL;
- source_instruction_t *i_now = i_first;
-
- // how big the stack has to be
- long int save_space = STACK_SAVE;
- {
- if ( gpr_start_pos < gpr_vstart )
- save_space += (gpr_vstart - gpr_start_pos) * GPRLEN;
- save_space = ( save_space + 15 ) & ~0x0f;
-
- if ( fpr_start_pos < fpr_vstart )
- save_space += (fpr_vstart - fpr_start_pos) * FPRLEN;
- save_space = ( save_space + 15 ) & ~0x0f;
- }
-
- long int stack_temp = prepareStack ? STACK_TEMP : STACK_RTEMP;
-
- while ( (i_now = i_now->next) ) {
- emitStart( i_now->i_count );
-
- switch ( i_now->op )
- {
- default:
- case OP_UNDEF:
- case OP_IGNORE:
- MAYBE_EMIT_CONST();
- in( iNOP );
- break;
-
- case OP_BREAK:
- MAYBE_EMIT_CONST();
- // force SEGV
- in( iLWZ, r0, 0, r0 );
- break;
-
- case OP_ENTER:
- if ( i_const )
- DIE( "Weird opcode order" );
-
- // don't prepare stack if not needed
- if ( prepareStack ) {
- long int i, save_pos = STACK_SAVE;
-
- in( iMFLR, r0 );
- in( iSTLU, r1, -save_space, r1 );
- in( iSTL, r0, save_space + STACK_LR, r1 );
-
- /* save registers */
- for ( i = gpr_start_pos; i < gpr_vstart; i++ ) {
- in( iSTL, gpr_list[ i ], save_pos, r1 );
- save_pos += GPRLEN;
- }
- save_pos = ( save_pos + 15 ) & ~0x0f;
-
- for ( i = fpr_start_pos; i < fpr_vstart; i++ ) {
- in( iSTFD, fpr_list[ i ], save_pos, r1 );
- save_pos += FPRLEN;
- }
- prepareStack = 2;
- }
-
- in( iADDI, rPSTACK, rPSTACK, - i_now->arg.si );
- break;
-
- case OP_LEAVE:
- if ( i_const ) {
- EMIT_FALSE_CONST();
-
- if ( i_const->regR & rTYPE_FLOAT)
- DIE( "constant float in OP_LEAVE" );
-
- if ( i_const->arg.si >= -0x8000 && i_const->arg.si < 0x8000 ) {
- in( iLI, r3, i_const->arg.si );
- } else if ( i_const->arg.i < 0x10000 ) {
- in( iLI, r3, 0 );
- in( iORI, r3, r3, i_const->arg.i );
- } else {
- in( iLIS, r3, i_const->arg.ss[ 0 ] );
- if ( i_const->arg.us[ 1 ] != 0 )
- in( iORI, r3, r3, i_const->arg.us[ 1 ] );
- }
- gpr_pos--;
- } else {
- MAYBE_EMIT_CONST();
-
- /* place return value in r3 */
- if ( ARG_INT ) {
- if ( rFIRST != r3 )
- in( iMR, r3, rFIRST );
- gpr_pos--;
- } else {
- in( iSTFS, fFIRST, stack_temp, r1 );
- in( iLWZ, r3, stack_temp, r1 );
- fpr_pos--;
- }
- }
-
- // don't undo stack if not prepared
- if ( prepareStack >= 2 ) {
- long int i, save_pos = STACK_SAVE;
-
- in( iLL, r0, save_space + STACK_LR, r1 );
-
-
- /* restore registers */
- for ( i = gpr_start_pos; i < gpr_vstart; i++ ) {
- in( iLL, gpr_list[ i ], save_pos, r1 );
- save_pos += GPRLEN;
- }
- save_pos = ( save_pos + 15 ) & ~0x0f;
- for ( i = fpr_start_pos; i < fpr_vstart; i++ ) {
- in( iLFD, fpr_list[ i ], save_pos, r1 );
- save_pos += FPRLEN;
- }
-
- in( iMTLR, r0 );
- in( iADDI, r1, r1, save_space );
- }
- in( iADDI, rPSTACK, rPSTACK, i_now->arg.si);
- in( iBLR );
- assert( gpr_pos == gpr_start_pos );
- assert( fpr_pos == fpr_start_pos );
- break;
-
- case OP_CALL:
- if ( i_const ) {
- EMIT_FALSE_CONST();
-
- if ( i_const->arg.si >= 0 ) {
- emitJump(
- i_const->arg.i,
- branchAlways, 0, branchExtLink
- );
- } else {
- /* syscall */
- in( iLL, r0, VM_Data_Offset( AsmCall ), rVMDATA );
-
- in( iLI, r3, i_const->arg.si ); // negative value
- in( iMR, r4, rPSTACK ); // push PSTACK on argument list
-
- in( iMTCTR, r0 );
- in( iBCTRL );
- }
- if ( rFIRST != r3 )
- in( iMR, rFIRST, r3 );
- } else {
- MAYBE_EMIT_CONST();
-
- in( iCMPWI, cr7, rFIRST, 0 );
- in( iBLTm, cr7, +4*5 /* syscall */ ); // XXX jump !
- /* instruction call */
-
- // get instruction address
- in( iLL, r0, VM_Data_Offset( iPointers ), rVMDATA );
- in( iRLWINM, rFIRST, rFIRST, GPRLEN_SHIFT, 0, 31-GPRLEN_SHIFT ); // mul * GPRLEN
- in( iLLX, r0, rFIRST, r0 ); // load pointer
-
- in( iB, +4*(3 + (rFIRST != r3 ? 1 : 0) ) ); // XXX jump !
-
- /* syscall */
- in( iLL, r0, VM_Data_Offset( AsmCall ), rVMDATA ); // get asmCall pointer
- /* rFIRST can be r3 or some static register */
- if ( rFIRST != r3 )
- in( iMR, r3, rFIRST ); // push OPSTACK top value on argument list
- in( iMR, r4, rPSTACK ); // push PSTACK on argument list
-
- /* common code */
- in( iMTCTR, r0 );
- in( iBCTRL );
-
- if ( rFIRST != r3 )
- in( iMR, rFIRST, r3 ); // push return value on the top of the opstack
- }
- break;
-
- case OP_PUSH:
- MAYBE_EMIT_CONST();
- if ( RET_INT )
- gpr_pos++;
- else
- fpr_pos++;
- /* no instructions here */
- force_emit = 1;
- break;
-
- case OP_POP:
- MAYBE_EMIT_CONST();
- if ( ARG_INT )
- gpr_pos--;
- else
- fpr_pos--;
- /* no instructions here */
- force_emit = 1;
- break;
-
- case OP_CONST:
- MAYBE_EMIT_CONST();
- /* nothing here */
- break;
-
- case OP_LOCAL:
- MAYBE_EMIT_CONST();
- {
- signed long int hi, lo;
- hi = i_now->arg.ss[ 0 ];
- lo = i_now->arg.ss[ 1 ];
- if ( lo < 0 )
- hi += 1;
-
- gpr_pos++;
- if ( hi == 0 ) {
- in( iADDI, rFIRST, rPSTACK, lo );
- } else {
- in( iADDIS, rFIRST, rPSTACK, hi );
- if ( lo != 0 )
- in( iADDI, rFIRST, rFIRST, lo );
- }
- }
- break;
-
- case OP_JUMP:
- if ( i_const ) {
- EMIT_FALSE_CONST();
-
- emitJump(
- i_const->arg.i,
- branchAlways, 0, 0
- );
- } else {
- MAYBE_EMIT_CONST();
-
- in( iLL, r0, VM_Data_Offset( iPointers ), rVMDATA );
- in( iRLWINM, rFIRST, rFIRST, GPRLEN_SHIFT, 0, 31-GPRLEN_SHIFT ); // mul * GPRLEN
- in( iLLX, r0, rFIRST, r0 ); // load pointer
- in( iMTCTR, r0 );
- in( iBCTR );
- }
- gpr_pos--;
- break;
-
- case OP_EQ:
- case OP_NE:
- if ( i_const && i_const->arg.si >= -0x8000 && i_const->arg.si < 0x10000 ) {
- EMIT_FALSE_CONST();
- if ( i_const->arg.si >= 0x8000 )
- in( iCMPLWI, cr7, rSECOND, i_const->arg.i );
- else
- in( iCMPWI, cr7, rSECOND, i_const->arg.si );
- } else {
- MAYBE_EMIT_CONST();
- in( iCMPW, cr7, rSECOND, rFIRST );
- }
- emitJump(
- i_now->arg.i,
- (i_now->op == OP_EQ ? branchTrue : branchFalse),
- 4*cr7+eq, 0
- );
- gpr_pos -= 2;
- break;
-
- case OP_LTI:
- case OP_GEI:
- if ( i_const && i_const->arg.si >= -0x8000 && i_const->arg.si < 0x8000 ) {
- EMIT_FALSE_CONST();
- in( iCMPWI, cr7, rSECOND, i_const->arg.si );
- } else {
- MAYBE_EMIT_CONST();
- in( iCMPW, cr7, rSECOND, rFIRST );
- }
- emitJump(
- i_now->arg.i,
- ( i_now->op == OP_LTI ? branchTrue : branchFalse ),
- 4*cr7+lt, 0
- );
- gpr_pos -= 2;
- break;
-
- case OP_GTI:
- case OP_LEI:
- if ( i_const && i_const->arg.si >= -0x8000 && i_const->arg.si < 0x8000 ) {
- EMIT_FALSE_CONST();
- in( iCMPWI, cr7, rSECOND, i_const->arg.si );
- } else {
- MAYBE_EMIT_CONST();
- in( iCMPW, cr7, rSECOND, rFIRST );
- }
- emitJump(
- i_now->arg.i,
- ( i_now->op == OP_GTI ? branchTrue : branchFalse ),
- 4*cr7+gt, 0
- );
- gpr_pos -= 2;
- break;
-
- case OP_LTU:
- case OP_GEU:
- if ( i_const && i_const->arg.i < 0x10000 ) {
- EMIT_FALSE_CONST();
- in( iCMPLWI, cr7, rSECOND, i_const->arg.i );
- } else {
- MAYBE_EMIT_CONST();
- in( iCMPLW, cr7, rSECOND, rFIRST );
- }
- emitJump(
- i_now->arg.i,
- ( i_now->op == OP_LTU ? branchTrue : branchFalse ),
- 4*cr7+lt, 0
- );
- gpr_pos -= 2;
- break;
-
- case OP_GTU:
- case OP_LEU:
- if ( i_const && i_const->arg.i < 0x10000 ) {
- EMIT_FALSE_CONST();
- in( iCMPLWI, cr7, rSECOND, i_const->arg.i );
- } else {
- MAYBE_EMIT_CONST();
- in( iCMPLW, cr7, rSECOND, rFIRST );
- }
- emitJump(
- i_now->arg.i,
- ( i_now->op == OP_GTU ? branchTrue : branchFalse ),
- 4*cr7+gt, 0
- );
- gpr_pos -= 2;
- break;
-
- case OP_EQF:
- case OP_NEF:
- MAYBE_EMIT_CONST();
- in( iFCMPU, cr7, fSECOND, fFIRST );
- emitJump(
- i_now->arg.i,
- ( i_now->op == OP_EQF ? branchTrue : branchFalse ),
- 4*cr7+eq, 0
- );
- fpr_pos -= 2;
- break;
-
- case OP_LTF:
- case OP_GEF:
- MAYBE_EMIT_CONST();
- in( iFCMPU, cr7, fSECOND, fFIRST );
- emitJump(
- i_now->arg.i,
- ( i_now->op == OP_LTF ? branchTrue : branchFalse ),
- 4*cr7+lt, 0
- );
- fpr_pos -= 2;
- break;
-
- case OP_GTF:
- case OP_LEF:
- MAYBE_EMIT_CONST();
- in( iFCMPU, cr7, fSECOND, fFIRST );
- emitJump(
- i_now->arg.i,
- ( i_now->op == OP_GTF ? branchTrue : branchFalse ),
- 4*cr7+gt, 0
- );
- fpr_pos -= 2;
- break;
-
- case OP_LOAD1:
- MAYBE_EMIT_CONST();
-#if OPTIMIZE_MASK
- in( iRLWINM, rFIRST, rFIRST, 0, fastMaskHi, fastMaskLo );
-#else
- in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
- in( iAND, rFIRST, rFIRST, r0 );
-#endif
- in( iLBZX, rFIRST, rFIRST, rDATABASE );
- break;
-
- case OP_LOAD2:
- MAYBE_EMIT_CONST();
-#if OPTIMIZE_MASK
- in( iRLWINM, rFIRST, rFIRST, 0, fastMaskHi, fastMaskLo );
-#else
- in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
- in( iAND, rFIRST, rFIRST, r0 );
-#endif
- in( iLHZX, rFIRST, rFIRST, rDATABASE );
- break;
-
- case OP_LOAD4:
- MAYBE_EMIT_CONST();
-#if OPTIMIZE_MASK
- in( iRLWINM, rFIRST, rFIRST, 0, fastMaskHi, fastMaskLo );
-#else
- in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
- in( iAND, rFIRST, rFIRST, r0 );
-#endif
- if ( RET_INT ) {
- in( iLWZX, rFIRST, rFIRST, rDATABASE );
- } else {
- fpr_pos++;
- in( iLFSX, fFIRST, rFIRST, rDATABASE );
- gpr_pos--;
- }
- break;
-
- case OP_STORE1:
- MAYBE_EMIT_CONST();
-#if OPTIMIZE_MASK
- in( iRLWINM, rSECOND, rSECOND, 0, fastMaskHi, fastMaskLo );
-#else
- in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
- in( iAND, rSECOND, rSECOND, r0 );
-#endif
- in( iSTBX, rFIRST, rSECOND, rDATABASE );
- gpr_pos -= 2;
- break;
-
- case OP_STORE2:
- MAYBE_EMIT_CONST();
-#if OPTIMIZE_MASK
- in( iRLWINM, rSECOND, rSECOND, 0, fastMaskHi, fastMaskLo );
-#else
- in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
- in( iAND, rSECOND, rSECOND, r0 );
-#endif
- in( iSTHX, rFIRST, rSECOND, rDATABASE );
- gpr_pos -= 2;
- break;
-
- case OP_STORE4:
- MAYBE_EMIT_CONST();
- if ( ARG_INT ) {
-#if OPTIMIZE_MASK
- in( iRLWINM, rSECOND, rSECOND, 0, fastMaskHi, fastMaskLo );
-#else
- in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
- in( iAND, rSECOND, rSECOND, r0 );
-#endif
-
- in( iSTWX, rFIRST, rSECOND, rDATABASE );
- gpr_pos--;
- } else {
-#if OPTIMIZE_MASK
- in( iRLWINM, rFIRST, rFIRST, 0, fastMaskHi, fastMaskLo );
-#else
- in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
- in( iAND, rFIRST, rFIRST, r0 );
-#endif
-
- in( iSTFSX, fFIRST, rFIRST, rDATABASE );
- fpr_pos--;
- }
- gpr_pos--;
- break;
-
- case OP_ARG:
- MAYBE_EMIT_CONST();
- in( iADDI, r0, rPSTACK, i_now->arg.b );
- if ( ARG_INT ) {
- in( iSTWX, rFIRST, rDATABASE, r0 );
- gpr_pos--;
- } else {
- in( iSTFSX, fFIRST, rDATABASE, r0 );
- fpr_pos--;
- }
- break;
-
- case OP_BLOCK_COPY:
- MAYBE_EMIT_CONST();
-#if OPTIMIZE_COPY
- if ( i_now->arg.i <= SL( 16, 32 ) ) {
- /* block is very short so copy it in-place */
-
- unsigned int len = i_now->arg.i;
- unsigned int copied = 0, left = len;
-
- in( iADD, rFIRST, rFIRST, rDATABASE );
- in( iADD, rSECOND, rSECOND, rDATABASE );
-
- if ( len >= GPRLEN ) {
- long int i, words = len / GPRLEN;
- in( iLL, r0, 0, rFIRST );
- for ( i = 1; i < words; i++ )
- in( iLL, rTEMP( i - 1 ), GPRLEN * i, rFIRST );
-
- in( iSTL, r0, 0, rSECOND );
- for ( i = 1; i < words; i++ )
- in( iSTL, rTEMP( i - 1 ), GPRLEN * i, rSECOND );
-
- copied += words * GPRLEN;
- left -= copied;
- }
-
- if ( SL( 0, left >= 4 ) ) {
- in( iLWZ, r0, copied+0, rFIRST );
- in( iSTW, r0, copied+0, rSECOND );
- copied += 4;
- left -= 4;
- }
- if ( left >= 4 ) {
- DIE("Bug in OP_BLOCK_COPY");
- }
- if ( left == 3 ) {
- in( iLHZ, r0, copied+0, rFIRST );
- in( iLBZ, rTMP, copied+2, rFIRST );
- in( iSTH, r0, copied+0, rSECOND );
- in( iSTB, rTMP, copied+2, rSECOND );
- } else if ( left == 2 ) {
- in( iLHZ, r0, copied+0, rFIRST );
- in( iSTH, r0, copied+0, rSECOND );
- } else if ( left == 1 ) {
- in( iLBZ, r0, copied+0, rFIRST );
- in( iSTB, r0, copied+0, rSECOND );
- }
- } else
-#endif
- {
- unsigned long int r5_ori = 0;
- if ( i_now->arg.si >= -0x8000 && i_now->arg.si < 0x8000 ) {
- in( iLI, r5, i_now->arg.si );
- } else if ( i_now->arg.i < 0x10000 ) {
- in( iLI, r5, 0 );
- r5_ori = i_now->arg.i;
- } else {
- in( iLIS, r5, i_now->arg.ss[ 0 ] );
- r5_ori = i_now->arg.us[ 1 ];
- }
-
- in( iLL, r0, VM_Data_Offset( BlockCopy ), rVMDATA ); // get blockCopy pointer
-
- if ( r5_ori )
- in( iORI, r5, r5, r5_ori );
-
- in( iMTCTR, r0 );
-
- if ( rFIRST != r4 )
- in( iMR, r4, rFIRST );
- if ( rSECOND != r3 )
- in( iMR, r3, rSECOND );
-
- in( iBCTRL );
- }
-
- gpr_pos -= 2;
- break;
-
- case OP_SEX8:
- MAYBE_EMIT_CONST();
- in( iEXTSB, rFIRST, rFIRST );
- break;
-
- case OP_SEX16:
- MAYBE_EMIT_CONST();
- in( iEXTSH, rFIRST, rFIRST );
- break;
-
- case OP_NEGI:
- MAYBE_EMIT_CONST();
- in( iNEG, rFIRST, rFIRST );
- break;
-
- case OP_ADD:
- if ( i_const ) {
- EMIT_FALSE_CONST();
-
- signed short int hi, lo;
- hi = i_const->arg.ss[ 0 ];
- lo = i_const->arg.ss[ 1 ];
- if ( lo < 0 )
- hi += 1;
-
- if ( hi != 0 )
- in( iADDIS, rSECOND, rSECOND, hi );
- if ( lo != 0 )
- in( iADDI, rSECOND, rSECOND, lo );
-
- // if both are zero no instruction will be written
- if ( hi == 0 && lo == 0 )
- force_emit = 1;
- } else {
- MAYBE_EMIT_CONST();
- in( iADD, rSECOND, rSECOND, rFIRST );
- }
- gpr_pos--;
- break;
-
- case OP_SUB:
- MAYBE_EMIT_CONST();
- in( iSUB, rSECOND, rSECOND, rFIRST );
- gpr_pos--;
- break;
-
- case OP_DIVI:
- MAYBE_EMIT_CONST();
- in( iDIVW, rSECOND, rSECOND, rFIRST );
- gpr_pos--;
- break;
-
- case OP_DIVU:
- MAYBE_EMIT_CONST();
- in( iDIVWU, rSECOND, rSECOND, rFIRST );
- gpr_pos--;
- break;
-
- case OP_MODI:
- MAYBE_EMIT_CONST();
- in( iDIVW, r0, rSECOND, rFIRST );
- in( iMULLW, r0, r0, rFIRST );
- in( iSUB, rSECOND, rSECOND, r0 );
- gpr_pos--;
- break;
-
- case OP_MODU:
- MAYBE_EMIT_CONST();
- in( iDIVWU, r0, rSECOND, rFIRST );
- in( iMULLW, r0, r0, rFIRST );
- in( iSUB, rSECOND, rSECOND, r0 );
- gpr_pos--;
- break;
-
- case OP_MULI:
- case OP_MULU:
- MAYBE_EMIT_CONST();
- in( iMULLW, rSECOND, rSECOND, rFIRST );
- gpr_pos--;
- break;
-
- case OP_BAND:
- MAYBE_EMIT_CONST();
- in( iAND, rSECOND, rSECOND, rFIRST );
- gpr_pos--;
- break;
-
- case OP_BOR:
- MAYBE_EMIT_CONST();
- in( iOR, rSECOND, rSECOND, rFIRST );
- gpr_pos--;
- break;
-
- case OP_BXOR:
- MAYBE_EMIT_CONST();
- in( iXOR, rSECOND, rSECOND, rFIRST );
- gpr_pos--;
- break;
-
- case OP_BCOM:
- MAYBE_EMIT_CONST();
- in( iNOT, rFIRST, rFIRST );
- break;
-
- case OP_LSH:
- MAYBE_EMIT_CONST();
- in( iSLW, rSECOND, rSECOND, rFIRST );
- gpr_pos--;
- break;
-
- case OP_RSHI:
- MAYBE_EMIT_CONST();
- in( iSRAW, rSECOND, rSECOND, rFIRST );
- gpr_pos--;
- break;
-
- case OP_RSHU:
- MAYBE_EMIT_CONST();
- in( iSRW, rSECOND, rSECOND, rFIRST );
- gpr_pos--;
- break;
-
- case OP_NEGF:
- MAYBE_EMIT_CONST();
- in( iFNEG, fFIRST, fFIRST );
- break;
-
- case OP_ADDF:
- MAYBE_EMIT_CONST();
- in( iFADDS, fSECOND, fSECOND, fFIRST );
- fpr_pos--;
- break;
-
- case OP_SUBF:
- MAYBE_EMIT_CONST();
- in( iFSUBS, fSECOND, fSECOND, fFIRST );
- fpr_pos--;
- break;
-
- case OP_DIVF:
- MAYBE_EMIT_CONST();
- in( iFDIVS, fSECOND, fSECOND, fFIRST );
- fpr_pos--;
- break;
-
- case OP_MULF:
- MAYBE_EMIT_CONST();
- in( iFMULS, fSECOND, fSECOND, fFIRST );
- fpr_pos--;
- break;
-
- case OP_CVIF:
- MAYBE_EMIT_CONST();
- fpr_pos++;
- in( iXORIS, rFIRST, rFIRST, 0x8000 );
- in( iLIS, r0, 0x4330 );
- in( iSTW, rFIRST, stack_temp + 4, r1 );
- in( iSTW, r0, stack_temp, r1 );
- in( iLFS, fTMP, VM_Data_Offset( floatBase ), rVMDATA );
- in( iLFD, fFIRST, stack_temp, r1 );
- in( iFSUB, fFIRST, fFIRST, fTMP );
- in( iFRSP, fFIRST, fFIRST );
- gpr_pos--;
- break;
-
- case OP_CVFI:
- MAYBE_EMIT_CONST();
- gpr_pos++;
- in( iFCTIWZ, fFIRST, fFIRST );
- in( iSTFD, fFIRST, stack_temp, r1 );
- in( iLWZ, rFIRST, stack_temp + 4, r1 );
- fpr_pos--;
- break;
- }
-
- i_const = NULL;
-
- if ( i_now->op != OP_CONST ) {
- // emit the instructions if it isn't OP_CONST
- emitEnd();
- } else {
- // mark in what register the value should be saved
- if ( RET_INT )
- i_now->regPos = ++gpr_pos;
- else
- i_now->regPos = ++fpr_pos;
-
-#if OPTIMIZE_HOLE
- i_const = i_now;
-#else
- PPC_EmitConst( i_now );
-#endif
- }
- }
- if ( i_const )
- DIE( "left (unused) OP_CONST" );
-
- {
- // free opcode information, don't free first dummy one
- source_instruction_t *i_next = i_first->next;
- while ( i_next ) {
- i_now = i_next;
- i_next = i_now->next;
- PPC_Free( i_now );
- }
- }
-}
-
-
-/*
- * check which jumps are short enough to use signed 16bit immediate branch
- */
-static void
-PPC_ShrinkJumps( void )
-{
- symbolic_jump_t *sj_now = sj_first;
- while ( (sj_now = sj_now->nextJump) ) {
- if ( sj_now->bo == branchAlways )
- // non-conditional branch has 26bit immediate
- sj_now->parent->length = 1;
-
- else {
- dest_instruction_t *di = di_pointers[ sj_now->jump_to ];
- dest_instruction_t *ji = sj_now->parent;
- long int jump_length = 0;
- if ( ! di )
- DIE( "No instruction to jump to" );
- if ( ji->count > di->count ) {
- do {
- jump_length += di->length;
- } while ( ( di = di->next ) != ji );
- } else {
- jump_length = 1;
- while ( ( ji = ji->next ) != di )
- jump_length += ji->length;
- }
- if ( jump_length < 0x2000 )
- // jump is short, use normal instruction
- sj_now->parent->length = 1;
- }
- }
-}
-
-/*
- * puts all the data in one place, it consists of many different tasks
- */
-static void
-PPC_ComputeCode( vm_t *vm )
-{
- dest_instruction_t *di_now = di_first;
-
- unsigned long int codeInstructions = 0;
- // count total instruciton number
- while ( (di_now = di_now->next ) )
- codeInstructions += di_now->length;
-
- size_t codeLength = sizeof( vm_data_t )
- + sizeof( unsigned int ) * data_acc
- + sizeof( ppc_instruction_t ) * codeInstructions;
-
- // get the memory for the generated code, smarter ppcs need the
- // mem to be marked as executable (whill change later)
- unsigned char *dataAndCode = mmap( NULL, codeLength,
- PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0 );
-
- if ( ! dataAndCode )
- DIE( "Not enough memory" );
-
- ppc_instruction_t *codeNow, *codeBegin;
- codeNow = codeBegin = (ppc_instruction_t *)( dataAndCode + VM_Data_Offset( data[ data_acc ] ) );
-
- ppc_instruction_t nop = IN( iNOP );
-
- // copy instructions to the destination
- // fills the jump instructions with nops
- // saves pointers of all instructions
- di_now = di_first;
- while ( (di_now = di_now->next ) ) {
- unsigned long int i_count = di_now->i_count;
- if ( i_count != FALSE_ICOUNT ) {
- if ( ! di_pointers[ i_count ] )
- di_pointers[ i_count ] = (void *) codeNow;
- }
-
- if ( di_now->jump == NULL ) {
- memcpy( codeNow, &(di_now->code[0]), di_now->length * sizeof( ppc_instruction_t ) );
- codeNow += di_now->length;
- } else {
- long int i;
- symbolic_jump_t *sj;
- for ( i = 0; i < di_now->length; i++ )
- codeNow[ i ] = nop;
- codeNow += di_now->length;
-
- sj = di_now->jump;
- // save position of jumping instruction
- sj->parent = (void *)(codeNow - 1);
- }
- }
-
- // compute the jumps and write corresponding instructions
- symbolic_jump_t *sj_now = sj_first;
- while ( (sj_now = sj_now->nextJump ) ) {
- ppc_instruction_t *jumpFrom = (void *) sj_now->parent;
- ppc_instruction_t *jumpTo = (void *) di_pointers[ sj_now->jump_to ];
- signed long int jumpLength = jumpTo - jumpFrom;
-
- // if jump is short, just write it
- if ( jumpLength >= - 8192 && jumpLength < 8192 ) {
- powerpc_iname_t branchConditional = sj_now->ext & branchExtLink ? iBCL : iBC;
- *jumpFrom = IN( branchConditional, sj_now->bo, sj_now->bi, jumpLength * 4 );
- continue;
- }
-
- // jump isn't short so write it as two instructions
- //
- // the letter one is a non-conditional branch instruction which
- // accepts immediate values big enough (26 bits)
- *jumpFrom = IN( (sj_now->ext & branchExtLink ? iBL : iB), jumpLength * 4 );
- if ( sj_now->bo == branchAlways )
- continue;
-
- // there should have been additional space prepared for this case
- if ( jumpFrom[ -1 ] != nop )
- DIE( "additional space for long jump not prepared" );
-
- // invert instruction condition
- long int bo = 0;
- switch ( sj_now->bo ) {
- case branchTrue:
- bo = branchFalse;
- break;
- case branchFalse:
- bo = branchTrue;
- break;
- default:
- DIE( "unrecognized branch type" );
- break;
- }
-
- // the former instruction is an inverted conditional branch which
- // jumps over the non-conditional one
- jumpFrom[ -1 ] = IN( iBC, bo, sj_now->bi, +2*4 );
- }
-
- vm->codeBase = dataAndCode;
- vm->codeLength = codeLength;
-
- vm_data_t *data = (vm_data_t *)dataAndCode;
-
-#if ELF64
- // prepare Official Procedure Descriptor for the generated code
- // and retrieve real function pointer for helper functions
-
- opd_t *ac = (void *)VM_AsmCall, *bc = (void *)VM_BlockCopy;
- data->opd.function = codeBegin;
- // trick it into using the same TOC
- // this way we won't have to switch TOC before calling AsmCall or BlockCopy
- data->opd.toc = ac->toc;
- data->opd.env = ac->env;
-
- data->AsmCall = ac->function;
- data->BlockCopy = bc->function;
-#else
- data->AsmCall = VM_AsmCall;
- data->BlockCopy = VM_BlockCopy;
-#endif
-
- data->dataMask = vm->dataMask;
- data->iPointers = (ppc_instruction_t *)vm->instructionPointers;
- data->dataLength = VM_Data_Offset( data[ data_acc ] );
- data->codeLength = ( codeNow - codeBegin ) * sizeof( ppc_instruction_t );
- data->floatBase = 0x59800004;
-
-
- /* write dynamic data (float constants) */
- {
- local_data_t *d_next, *d_now = data_first;
- long int accumulated = 0;
-
- do {
- long int i;
- for ( i = 0; i < d_now->count; i++ )
- data->data[ accumulated + i ] = d_now->data[ i ];
-
- accumulated += d_now->count;
- d_next = d_now->next;
- PPC_Free( d_now );
-
- if ( !d_next )
- break;
- d_now = d_next;
- } while (1);
- data_first = NULL;
- }
-
- /* free most of the compilation memory */
- {
- di_now = di_first->next;
- PPC_Free( di_first );
- PPC_Free( sj_first );
-
- while ( di_now ) {
- di_first = di_now->next;
- if ( di_now->jump )
- PPC_Free( di_now->jump );
- PPC_Free( di_now );
- di_now = di_first;
- }
- }
-
- return;
-}
-
-static void
-VM_Destroy_Compiled( vm_t *self )
-{
- if ( self->codeBase ) {
- if ( munmap( self->codeBase, self->codeLength ) )
- Com_Printf( S_COLOR_RED "Memory unmap failed, possible memory leak\n" );
- }
- self->codeBase = NULL;
-}
-
-void
-VM_Compile( vm_t *vm, vmHeader_t *header )
-{
- long int pc = 0;
- unsigned long int i_count;
- char* code;
- struct timeval tvstart = {0, 0};
- source_instruction_t *i_first /* dummy */, *i_last = NULL, *i_now;
-
- vm->compiled = qfalse;
-
- gettimeofday(&tvstart, NULL);
-
- PPC_MakeFastMask( vm->dataMask );
-
- i_first = PPC_Malloc( sizeof( source_instruction_t ) );
- i_first->next = NULL;
-
- // realloc instructionPointers with correct size
- // use Z_Malloc so vm.c will be able to free the memory
- if ( sizeof( void * ) != sizeof( int ) ) {
- Z_Free( vm->instructionPointers );
- vm->instructionPointers = Z_Malloc( header->instructionCount * sizeof( void * ) );
- }
- di_pointers = (void *)vm->instructionPointers;
- memset( di_pointers, 0, header->instructionCount * sizeof( void * ) );
-
-
- PPC_CompileInit();
-
- /*
- * read the input program
- * divide it into functions and send each function to compiler
- */
- code = (char *)header + header->codeOffset;
- for ( i_count = 0; i_count < header->instructionCount; ++i_count )
- {
- unsigned char op = code[ pc++ ];
-
- if ( op == OP_ENTER ) {
- if ( i_first->next )
- VM_CompileFunction( i_first );
- i_first->next = NULL;
- i_last = i_first;
- }
-
- i_now = PPC_Malloc( sizeof( source_instruction_t ) );
- i_now->op = op;
- i_now->i_count = i_count;
- i_now->arg.i = 0;
- i_now->regA1 = 0;
- i_now->regA2 = 0;
- i_now->regR = 0;
- i_now->regPos = 0;
- i_now->next = NULL;
-
- if ( vm_opInfo[op] & opImm4 ) {
- union {
- unsigned char b[4];
- unsigned int i;
- } c = { { code[ pc + 3 ], code[ pc + 2 ], code[ pc + 1 ], code[ pc + 0 ] }, };
-
- i_now->arg.i = c.i;
- pc += 4;
- } else if ( vm_opInfo[op] & opImm1 ) {
- i_now->arg.b = code[ pc++ ];
- }
-
- i_last->next = i_now;
- i_last = i_now;
- }
- VM_CompileFunction( i_first );
- PPC_Free( i_first );
-
- PPC_ShrinkJumps();
- memset( di_pointers, 0, header->instructionCount * sizeof( void * ) );
- PPC_ComputeCode( vm );
-
- /* check for uninitialized pointers */
-#ifdef DEBUG_VM
- long int i;
- for ( i = 0; i < header->instructionCount; i++ )
- if ( di_pointers[ i ] == 0 )
- Com_Printf( S_COLOR_RED "Pointer %ld not initialized !\n", i );
-#endif
-
- /* mark memory as executable and not writeable */
- if ( mprotect( vm->codeBase, vm->codeLength, PROT_READ|PROT_EXEC ) ) {
-
- // it has failed, make sure memory is unmapped before throwing the error
- VM_Destroy_Compiled( vm );
- DIE( "mprotect failed" );
- }
-
- vm->destroy = VM_Destroy_Compiled;
- vm->compiled = qtrue;
-
- {
- struct timeval tvdone = {0, 0};
- struct timeval dur = {0, 0};
- Com_Printf( "VM file %s compiled to %i bytes of code (%p - %p)\n",
- vm->name, vm->codeLength, vm->codeBase, vm->codeBase+vm->codeLength );
-
- gettimeofday(&tvdone, NULL);
- timersub(&tvdone, &tvstart, &dur);
- Com_Printf( "compilation took %lu.%06lu seconds\n",
- (long unsigned int)dur.tv_sec, (long unsigned int)dur.tv_usec );
- }
-}
-
-int
-VM_CallCompiled( vm_t *vm, int *args )
-{
- int retVal;
- int *argPointer;
-
- vm_data_t *vm_dataAndCode = (void *)( vm->codeBase );
- int programStack = vm->programStack;
- int stackOnEntry = programStack;
-
- byte *image = vm->dataBase;
-
- currentVM = vm;
-
- vm->currentlyInterpreting = qtrue;
-
- programStack -= 48;
- argPointer = (int *)&image[ programStack + 8 ];
- memcpy( argPointer, args, 4 * 9 );
- argPointer[ -1 ] = 0;
- argPointer[ -2 ] = -1;
-
-#ifdef VM_TIMES
- struct tms start_time, stop_time;
- clock_t time_diff;
-
- times( &start_time );
- time_outside_vm = 0;
-#endif
-
- /* call generated code */
- {
- int ( *entry )( void *, int, void * );
-#ifdef __PPC64__
- entry = (void *)&(vm_dataAndCode->opd);
-#else
- entry = (void *)(vm->codeBase + vm_dataAndCode->dataLength);
-#endif
- retVal = entry( vm->codeBase, programStack, vm->dataBase );
- }
-
-#ifdef VM_TIMES
- times( &stop_time );
- time_diff = stop_time.tms_utime - start_time.tms_utime;
- time_total_vm += time_diff - time_outside_vm;
- if ( time_diff > 100 ) {
- printf( "App clock: %ld, vm total: %ld, vm this: %ld, vm real: %ld, vm out: %ld\n"
- "Inside VM %f%% of app time\n",
- stop_time.tms_utime,
- time_total_vm,
- time_diff,
- time_diff - time_outside_vm,
- time_outside_vm,
- (double)100 * time_total_vm / stop_time.tms_utime );
- }
-#endif
-
- vm->programStack = stackOnEntry;
- vm->currentlyInterpreting = qfalse;
-
- return retVal;
-}
diff --git a/engine/code/qcommon/vm_powerpc_asm.c b/engine/code/qcommon/vm_powerpc_asm.c
deleted file mode 100644
index 64c5977..0000000
--- a/engine/code/qcommon/vm_powerpc_asm.c
+++ /dev/null
@@ -1,1009 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 2008 Przemyslaw Iskra <sparky at pld-linux.org>
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-
- * File includes code from GNU binutils, exactly:
- * - include/opcode/ppc.h - licensed under GPL v1 or later
- * - opcodes/ppc-opc.c - licensed under GPL v2 or later
- *
- * ppc.h -- Header file for PowerPC opcode table
- * Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- * 2007 Free Software Foundation, Inc.
- * Written by Ian Lance Taylor, Cygnus Suppor
- *
- * This file is part of GDB, GAS, and the GNU binutils.
- *
- * ppc-opc.c -- PowerPC opcode list
- * Copyright 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004,
- * 2005, 2006, 2007 Free Software Foundation, Inc.
- * Written by Ian Lance Taylor, Cygnus Support
- *
- * This file is part of GDB, GAS, and the GNU binutils.
- *
- */
-
-#include "vm_powerpc_asm.h"
-
-#include <string.h>
-#include <stdio.h>
-#include <inttypes.h>
-
-/* return nop on error */
-#define ASM_ERROR_OPC (0x60000000)
-
-/*
- * BEGIN OF ppc.h
- */
-
-#define ppc_cpu_t int
-
-struct powerpc_opcode
-{
- const char *name;
- unsigned long opcode;
- unsigned long mask;
- ppc_cpu_t flags;
- unsigned char operands[8];
-};
-
-static const struct powerpc_opcode powerpc_opcodes[];
-static const int powerpc_num_opcodes;
-
-#define PPC_OPCODE_PPC 1
-#define PPC_OPCODE_POWER 2
-#define PPC_OPCODE_POWER2 4
-#define PPC_OPCODE_32 8
-#define PPC_OPCODE_64 0x10
-#define PPC_OPCODE_601 0x20
-#define PPC_OPCODE_COMMON 0x40
-#define PPC_OPCODE_ANY 0x80
-#define PPC_OPCODE_64_BRIDGE 0x100
-#define PPC_OPCODE_ALTIVEC 0x200
-#define PPC_OPCODE_403 0x400
-#define PPC_OPCODE_BOOKE 0x800
-#define PPC_OPCODE_BOOKE64 0x1000
-#define PPC_OPCODE_440 0x2000
-#define PPC_OPCODE_POWER4 0x4000
-#define PPC_OPCODE_NOPOWER4 0x8000
-#define PPC_OPCODE_CLASSIC 0x10000
-#define PPC_OPCODE_SPE 0x20000
-#define PPC_OPCODE_ISEL 0x40000
-#define PPC_OPCODE_EFS 0x80000
-#define PPC_OPCODE_BRLOCK 0x100000
-#define PPC_OPCODE_PMR 0x200000
-#define PPC_OPCODE_CACHELCK 0x400000
-#define PPC_OPCODE_RFMCI 0x800000
-#define PPC_OPCODE_POWER5 0x1000000
-#define PPC_OPCODE_E300 0x2000000
-#define PPC_OPCODE_POWER6 0x4000000
-#define PPC_OPCODE_CELL 0x8000000
-#define PPC_OPCODE_PPCPS 0x10000000
-#define PPC_OPCODE_E500MC 0x20000000
-#define PPC_OPCODE_405 0x40000000
-#define PPC_OPCODE_VSX 0x80000000
-
-#define PPC_OP(i) (((i) >> 26) & 0x3f)
-
-struct powerpc_operand
-{
- unsigned int bitm;
- int shift;
- unsigned long (*insert)
- (unsigned long, long, int, const char **);
- unsigned long flags;
-};
-
-static const struct powerpc_operand powerpc_operands[];
-static const unsigned int num_powerpc_operands;
-
-#define PPC_OPERAND_SIGNED (0x1)
-#define PPC_OPERAND_SIGNOPT (0x2)
-#define PPC_OPERAND_FAKE (0x4)
-#define PPC_OPERAND_PARENS (0x8)
-#define PPC_OPERAND_CR (0x10)
-#define PPC_OPERAND_GPR (0x20)
-#define PPC_OPERAND_GPR_0 (0x40)
-#define PPC_OPERAND_FPR (0x80)
-#define PPC_OPERAND_RELATIVE (0x100)
-#define PPC_OPERAND_ABSOLUTE (0x200)
-#define PPC_OPERAND_OPTIONAL (0x400)
-#define PPC_OPERAND_NEXT (0x800)
-#define PPC_OPERAND_NEGATIVE (0x1000)
-#define PPC_OPERAND_VR (0x2000)
-#define PPC_OPERAND_DS (0x4000)
-#define PPC_OPERAND_DQ (0x8000)
-#define PPC_OPERAND_PLUS1 (0x10000)
-#define PPC_OPERAND_FSL (0x20000)
-#define PPC_OPERAND_FCR (0x40000)
-#define PPC_OPERAND_UDI (0x80000)
-#define PPC_OPERAND_VSR (0x100000)
-
-/*
- * END OF ppc.h
- */
-
-#define PPC_DEST_ARCH PPC_OPCODE_PPC
-
-ppc_instruction_t
-asm_instruction( powerpc_iname_t sname, const int argc, const long int *argv )
-{
- const char *errmsg = NULL;
- const char *name;
- unsigned long int ret;
- const struct powerpc_opcode *opcode = NULL;
- int argi, argj;
-
- opcode = &powerpc_opcodes[ sname ];
- name = opcode->name;
-
- if ( ! opcode ) {
- printf( "Can't find opcode %d\n", sname );
- return ASM_ERROR_OPC;
- }
- if ( ( opcode->flags & PPC_DEST_ARCH ) != PPC_DEST_ARCH ) {
- printf( "opcode %s not defined for this arch\n", name );
- return ASM_ERROR_OPC;
- }
-
- ret = opcode->opcode;
-
- argi = argj = 0;
- while ( opcode->operands[ argi ] != 0 ) {
- long int op = 0;
- const struct powerpc_operand *operand = &powerpc_operands[ opcode->operands[ argi ] ];
-
- if ( ! (operand->flags & PPC_OPERAND_FAKE) ) {
- if ( argj >= argc ) {
- printf( "Not enough arguments for %s, got %d\n", name, argc );
- return ASM_ERROR_OPC;
- }
-
- op = argv[ argj++ ];
- }
-
- if ( operand->insert ) {
- errmsg = NULL;
- ret = operand->insert( ret, op, PPC_DEST_ARCH, &errmsg );
- if ( errmsg ) {
- printf( "%s: error while inserting operand %d (0x%.2lx): %s\n",
- name, argi, op, errmsg );
- }
- } else {
- unsigned long int opu = *(unsigned long int *)&op;
- unsigned long int bitm = operand->bitm;
- unsigned long int bitm_full = bitm | ( bitm & 1 ? 0 : 0xf );
-
- if ( operand->flags & PPC_OPERAND_SIGNED ) {
- bitm_full >>= 1;
-
- if ( ( opu & ~bitm_full ) != 0 && ( opu | bitm_full ) != -1 )
- printf( "%s: signed operand nr.%d to wide. op: %.8lx, mask: %.8lx\n",
- name, argi, opu, bitm );
- } else {
- if ( ( opu & ~bitm_full ) != 0 )
- printf( "%s: unsigned operand nr.%d to wide. op: %.8lx, mask: %.8lx\n",
- name, argi, opu, bitm );
- }
- if ( (bitm & 1) == 0 ) {
- if ( opu & 0xf & ~bitm )
- printf( "%s: operand nr.%d not aligned correctly. op: %.8lx, mask: %.8lx\n",
- name, argi, opu, bitm );
- }
-
- ret |= ( op & operand->bitm ) << operand->shift;
- }
- argi++;
- }
- if ( argc > argj ) {
- printf( "Too many arguments for %s, got %d\n", name, argc );
- return ASM_ERROR_OPC;
- }
-
- return ret;
-}
-
-
-/*
- * BEGIN OF ppc-opc.c
- */
-
-#define ATTRIBUTE_UNUSED
-#define _(x) (x)
-
-/* Local insertion and extraction functions. */
-
-static unsigned long insert_bdm (unsigned long, long, int, const char **);
-static unsigned long insert_bo (unsigned long, long, int, const char **);
-static unsigned long insert_ras (unsigned long, long, int, const char **);
-static unsigned long insert_rbs (unsigned long, long, int, const char **);
-
-/* The operands table.
-
- The fields are bitm, shift, insert, extract, flags.
- */
-
-static const struct powerpc_operand powerpc_operands[] =
-{
- /* The zero index is used to indicate the end of the list of
- operands. */
-#define UNUSED 0
- { 0, 0, NULL, 0 },
-
- /* The BA field in an XL form instruction. */
-#define BA UNUSED + 1
- /* The BI field in a B form or XL form instruction. */
-#define BI BA
-#define BI_MASK (0x1f << 16)
- { 0x1f, 16, NULL, PPC_OPERAND_CR },
-
- /* The BD field in a B form instruction. The lower two bits are
- forced to zero. */
-#define BD BA + 1
- { 0xfffc, 0, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
-
- /* The BD field in a B form instruction when the - modifier is used.
- This sets the y bit of the BO field appropriately. */
-#define BDM BD + 1
- { 0xfffc, 0, insert_bdm,
- PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
-
- /* The BF field in an X or XL form instruction. */
-#define BF BDM + 1
- /* The CRFD field in an X form instruction. */
-#define CRFD BF
- { 0x7, 23, NULL, PPC_OPERAND_CR },
-
- /* An optional BF field. This is used for comparison instructions,
- in which an omitted BF field is taken as zero. */
-#define OBF BF + 1
- { 0x7, 23, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
-
- /* The BO field in a B form instruction. Certain values are
- illegal. */
-#define BO OBF + 1
-#define BO_MASK (0x1f << 21)
- { 0x1f, 21, insert_bo, 0 },
-
- /* The condition register number portion of the BI field in a B form
- or XL form instruction. This is used for the extended
- conditional branch mnemonics, which set the lower two bits of the
- BI field. This field is optional. */
-#define CR BO + 1
- { 0x7, 18, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
-
- /* The D field in a D form instruction. This is a displacement off
- a register, and implies that the next operand is a register in
- parentheses. */
-#define D CR + 1
- { 0xffff, 0, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
-
- /* The DS field in a DS form instruction. This is like D, but the
- lower two bits are forced to zero. */
-#define DS D + 1
- { 0xfffc, 0, NULL,
- PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DS },
-
- /* The FRA field in an X or A form instruction. */
-#define FRA DS + 1
-#define FRA_MASK (0x1f << 16)
- { 0x1f, 16, NULL, PPC_OPERAND_FPR },
-
- /* The FRB field in an X or A form instruction. */
-#define FRB FRA + 1
-#define FRB_MASK (0x1f << 11)
- { 0x1f, 11, NULL, PPC_OPERAND_FPR },
-
- /* The FRC field in an A form instruction. */
-#define FRC FRB + 1
-#define FRC_MASK (0x1f << 6)
- { 0x1f, 6, NULL, PPC_OPERAND_FPR },
-
- /* The FRS field in an X form instruction or the FRT field in a D, X
- or A form instruction. */
-#define FRS FRC + 1
-#define FRT FRS
- { 0x1f, 21, NULL, PPC_OPERAND_FPR },
-
- /* The LI field in an I form instruction. The lower two bits are
- forced to zero. */
-#define LI FRS + 1
- { 0x3fffffc, 0, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
-
- /* The ME field in an M form instruction. */
-#define ME LI + 1
-#define ME_MASK (0x1f << 1)
- { 0x1f, 1, NULL, 0 },
-
- /* The MB and ME fields in an M form instruction expressed a single
- operand which is a bitmask indicating which bits to select. This
- is a two operand form using PPC_OPERAND_NEXT. See the
- description in opcode/ppc.h for what this means. */
-#define MBE ME + 1
- { 0x1f, 6, NULL, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT },
-
- /* The RA field in an D, DS, DQ, X, XO, M, or MDS form instruction. */
-#define RA MBE + 1
-#define RA_MASK (0x1f << 16)
- { 0x1f, 16, NULL, PPC_OPERAND_GPR },
-
- /* As above, but 0 in the RA field means zero, not r0. */
-#define RA0 RA + 1
- { 0x1f, 16, NULL, PPC_OPERAND_GPR_0 },
-
- /* The RA field in a D or X form instruction which is an updating
- store or an updating floating point load, which means that the RA
- field may not be zero. */
-#define RAS RA0 + 1
- { 0x1f, 16, insert_ras, PPC_OPERAND_GPR_0 },
-
- /* The RB field in an X, XO, M, or MDS form instruction. */
-#define RB RAS + 1
-#define RB_MASK (0x1f << 11)
- { 0x1f, 11, NULL, PPC_OPERAND_GPR },
-
- /* The RB field in an X form instruction when it must be the same as
- the RS field in the instruction. This is used for extended
- mnemonics like mr. */
-#define RBS RB + 1
- { 0x1f, 11, insert_rbs, PPC_OPERAND_FAKE },
-
- /* The RS field in a D, DS, X, XFX, XS, M, MD or MDS form
- instruction or the RT field in a D, DS, X, XFX or XO form
- instruction. */
-#define RS RBS + 1
-#define RT RS
-#define RT_MASK (0x1f << 21)
- { 0x1f, 21, NULL, PPC_OPERAND_GPR },
-
- /* The SH field in an X or M form instruction. */
-#define SH RS + 1
-#define SH_MASK (0x1f << 11)
- /* The other UIMM field in a EVX form instruction. */
-#define EVUIMM SH
- { 0x1f, 11, NULL, 0 },
-
- /* The SI field in a D form instruction. */
-#define SI SH + 1
- { 0xffff, 0, NULL, PPC_OPERAND_SIGNED },
-
- /* The UI field in a D form instruction. */
-#define UI SI + 1
- { 0xffff, 0, NULL, 0 },
-
-};
-
-static const unsigned int num_powerpc_operands =
- (sizeof (powerpc_operands) / sizeof (powerpc_operands[0]));
-
-/* The functions used to insert and extract complicated operands. */
-
-/* The BD field in a B form instruction when the - modifier is used.
- This modifier means that the branch is not expected to be taken.
- For chips built to versions of the architecture prior to version 2
- (ie. not Power4 compatible), we set the y bit of the BO field to 1
- if the offset is negative. When extracting, we require that the y
- bit be 1 and that the offset be positive, since if the y bit is 0
- we just want to print the normal form of the instruction.
- Power4 compatible targets use two bits, "a", and "t", instead of
- the "y" bit. "at" == 00 => no hint, "at" == 01 => unpredictable,
- "at" == 10 => not taken, "at" == 11 => taken. The "t" bit is 00001
- in BO field, the "a" bit is 00010 for branch on CR(BI) and 01000
- for branch on CTR. We only handle the taken/not-taken hint here.
- Note that we don't relax the conditions tested here when
- disassembling with -Many because insns using extract_bdm and
- extract_bdp always occur in pairs. One or the other will always
- be valid. */
-
-static unsigned long
-insert_bdm (unsigned long insn,
- long value,
- int dialect,
- const char **errmsg ATTRIBUTE_UNUSED)
-{
- if ((dialect & PPC_OPCODE_POWER4) == 0)
- {
- if ((value & 0x8000) != 0)
- insn |= 1 << 21;
- }
- else
- {
- if ((insn & (0x14 << 21)) == (0x04 << 21))
- insn |= 0x02 << 21;
- else if ((insn & (0x14 << 21)) == (0x10 << 21))
- insn |= 0x08 << 21;
- }
- return insn | (value & 0xfffc);
-}
-
-
-/* Check for legal values of a BO field. */
-
-static int
-valid_bo (long value, int dialect, int extract)
-{
- if ((dialect & PPC_OPCODE_POWER4) == 0)
- {
- int valid;
- /* Certain encodings have bits that are required to be zero.
- These are (z must be zero, y may be anything):
- 001zy
- 011zy
- 1z00y
- 1z01y
- 1z1zz
- */
- switch (value & 0x14)
- {
- default:
- case 0:
- valid = 1;
- break;
- case 0x4:
- valid = (value & 0x2) == 0;
- break;
- case 0x10:
- valid = (value & 0x8) == 0;
- break;
- case 0x14:
- valid = value == 0x14;
- break;
- }
- /* When disassembling with -Many, accept power4 encodings too. */
- if (valid
- || (dialect & PPC_OPCODE_ANY) == 0
- || !extract)
- return valid;
- }
-
- /* Certain encodings have bits that are required to be zero.
- These are (z must be zero, a & t may be anything):
- 0000z
- 0001z
- 0100z
- 0101z
- 001at
- 011at
- 1a00t
- 1a01t
- 1z1zz
- */
- if ((value & 0x14) == 0)
- return (value & 0x1) == 0;
- else if ((value & 0x14) == 0x14)
- return value == 0x14;
- else
- return 1;
-}
-
-/* The BO field in a B form instruction. Warn about attempts to set
- the field to an illegal value. */
-
-static unsigned long
-insert_bo (unsigned long insn,
- long value,
- int dialect,
- const char **errmsg)
-{
- if (!valid_bo (value, dialect, 0))
- *errmsg = _("invalid conditional option");
- return insn | ((value & 0x1f) << 21);
-}
-
-/* The RA field in a D or X form instruction which is an updating
- store or an updating floating point load, which means that the RA
- field may not be zero. */
-
-static unsigned long
-insert_ras (unsigned long insn,
- long value,
- int dialect ATTRIBUTE_UNUSED,
- const char **errmsg)
-{
- if (value == 0)
- *errmsg = _("invalid register operand when updating");
- return insn | ((value & 0x1f) << 16);
-}
-
-/* The RB field in an X form instruction when it must be the same as
- the RS field in the instruction. This is used for extended
- mnemonics like mr. This operand is marked FAKE. The insertion
- function just copies the BT field into the BA field, and the
- extraction function just checks that the fields are the same. */
-
-static unsigned long
-insert_rbs (unsigned long insn,
- long value ATTRIBUTE_UNUSED,
- int dialect ATTRIBUTE_UNUSED,
- const char **errmsg ATTRIBUTE_UNUSED)
-{
- return insn | (((insn >> 21) & 0x1f) << 11);
-}
-
-
-/* Macros used to form opcodes. */
-
-/* The main opcode. */
-#define OP(x) ((((unsigned long)(x)) & 0x3f) << 26)
-#define OP_MASK OP (0x3f)
-
-/* The main opcode combined with a trap code in the TO field of a D
- form instruction. Used for extended mnemonics for the trap
- instructions. */
-#define OPTO(x,to) (OP (x) | ((((unsigned long)(to)) & 0x1f) << 21))
-#define OPTO_MASK (OP_MASK | TO_MASK)
-
-/* The main opcode combined with a comparison size bit in the L field
- of a D form or X form instruction. Used for extended mnemonics for
- the comparison instructions. */
-#define OPL(x,l) (OP (x) | ((((unsigned long)(l)) & 1) << 21))
-#define OPL_MASK OPL (0x3f,1)
-
-/* An A form instruction. */
-#define A(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1) | (((unsigned long)(rc)) & 1))
-#define A_MASK A (0x3f, 0x1f, 1)
-
-/* An A_MASK with the FRB field fixed. */
-#define AFRB_MASK (A_MASK | FRB_MASK)
-
-/* An A_MASK with the FRC field fixed. */
-#define AFRC_MASK (A_MASK | FRC_MASK)
-
-/* An A_MASK with the FRA and FRC fields fixed. */
-#define AFRAFRC_MASK (A_MASK | FRA_MASK | FRC_MASK)
-
-/* An AFRAFRC_MASK, but with L bit clear. */
-#define AFRALFRC_MASK (AFRAFRC_MASK & ~((unsigned long) 1 << 16))
-
-/* A B form instruction. */
-#define B(op, aa, lk) (OP (op) | ((((unsigned long)(aa)) & 1) << 1) | ((lk) & 1))
-#define B_MASK B (0x3f, 1, 1)
-
-/* A B form instruction setting the BO field. */
-#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21))
-#define BBO_MASK BBO (0x3f, 0x1f, 1, 1)
-
-/* A BBO_MASK with the y bit of the BO field removed. This permits
- matching a conditional branch regardless of the setting of the y
- bit. Similarly for the 'at' bits used for power4 branch hints. */
-#define Y_MASK (((unsigned long) 1) << 21)
-#define AT1_MASK (((unsigned long) 3) << 21)
-#define AT2_MASK (((unsigned long) 9) << 21)
-#define BBOY_MASK (BBO_MASK &~ Y_MASK)
-#define BBOAT_MASK (BBO_MASK &~ AT1_MASK)
-
-/* A B form instruction setting the BO field and the condition bits of
- the BI field. */
-#define BBOCB(op, bo, cb, aa, lk) \
- (BBO ((op), (bo), (aa), (lk)) | ((((unsigned long)(cb)) & 0x3) << 16))
-#define BBOCB_MASK BBOCB (0x3f, 0x1f, 0x3, 1, 1)
-
-/* A BBOCB_MASK with the y bit of the BO field removed. */
-#define BBOYCB_MASK (BBOCB_MASK &~ Y_MASK)
-#define BBOATCB_MASK (BBOCB_MASK &~ AT1_MASK)
-#define BBOAT2CB_MASK (BBOCB_MASK &~ AT2_MASK)
-
-/* A BBOYCB_MASK in which the BI field is fixed. */
-#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK)
-#define BBOATBI_MASK (BBOAT2CB_MASK | BI_MASK)
-
-/* An Context form instruction. */
-#define CTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7))
-#define CTX_MASK CTX(0x3f, 0x7)
-
-/* An User Context form instruction. */
-#define UCTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f))
-#define UCTX_MASK UCTX(0x3f, 0x1f)
-
-/* The main opcode mask with the RA field clear. */
-#define DRA_MASK (OP_MASK | RA_MASK)
-
-/* A DS form instruction. */
-#define DSO(op, xop) (OP (op) | ((xop) & 0x3))
-#define DS_MASK DSO (0x3f, 3)
-
-/* A DE form instruction. */
-#define DEO(op, xop) (OP (op) | ((xop) & 0xf))
-#define DE_MASK DEO (0x3e, 0xf)
-
-/* An EVSEL form instruction. */
-#define EVSEL(op, xop) (OP (op) | (((unsigned long)(xop)) & 0xff) << 3)
-#define EVSEL_MASK EVSEL(0x3f, 0xff)
-
-/* An M form instruction. */
-#define M(op, rc) (OP (op) | ((rc) & 1))
-#define M_MASK M (0x3f, 1)
-
-/* An M form instruction with the ME field specified. */
-#define MME(op, me, rc) (M ((op), (rc)) | ((((unsigned long)(me)) & 0x1f) << 1))
-
-/* An M_MASK with the MB and ME fields fixed. */
-#define MMBME_MASK (M_MASK | MB_MASK | ME_MASK)
-
-/* An M_MASK with the SH and ME fields fixed. */
-#define MSHME_MASK (M_MASK | SH_MASK | ME_MASK)
-
-/* An MD form instruction. */
-#define MD(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x7) << 2) | ((rc) & 1))
-#define MD_MASK MD (0x3f, 0x7, 1)
-
-/* An MD_MASK with the MB field fixed. */
-#define MDMB_MASK (MD_MASK | MB6_MASK)
-
-/* An MD_MASK with the SH field fixed. */
-#define MDSH_MASK (MD_MASK | SH6_MASK)
-
-/* An MDS form instruction. */
-#define MDS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0xf) << 1) | ((rc) & 1))
-#define MDS_MASK MDS (0x3f, 0xf, 1)
-
-/* An MDS_MASK with the MB field fixed. */
-#define MDSMB_MASK (MDS_MASK | MB6_MASK)
-
-/* An SC form instruction. */
-#define SC(op, sa, lk) (OP (op) | ((((unsigned long)(sa)) & 1) << 1) | ((lk) & 1))
-#define SC_MASK (OP_MASK | (((unsigned long)0x3ff) << 16) | (((unsigned long)1) << 1) | 1)
-
-/* An VX form instruction. */
-#define VX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7ff))
-
-/* The mask for an VX form instruction. */
-#define VX_MASK VX(0x3f, 0x7ff)
-
-/* An VA form instruction. */
-#define VXA(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x03f))
-
-/* The mask for an VA form instruction. */
-#define VXA_MASK VXA(0x3f, 0x3f)
-
-/* An VXR form instruction. */
-#define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff))
-
-/* The mask for a VXR form instruction. */
-#define VXR_MASK VXR(0x3f, 0x3ff, 1)
-
-/* An X form instruction. */
-#define X(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1))
-
-/* A Z form instruction. */
-#define Z(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1))
-
-/* An X form instruction with the RC bit specified. */
-#define XRC(op, xop, rc) (X ((op), (xop)) | ((rc) & 1))
-
-/* A Z form instruction with the RC bit specified. */
-#define ZRC(op, xop, rc) (Z ((op), (xop)) | ((rc) & 1))
-
-/* The mask for an X form instruction. */
-#define X_MASK XRC (0x3f, 0x3ff, 1)
-
-/* The mask for a Z form instruction. */
-#define Z_MASK ZRC (0x3f, 0x1ff, 1)
-#define Z2_MASK ZRC (0x3f, 0xff, 1)
-
-/* An X_MASK with the RA field fixed. */
-#define XRA_MASK (X_MASK | RA_MASK)
-
-/* An XRA_MASK with the W field clear. */
-#define XWRA_MASK (XRA_MASK & ~((unsigned long) 1 << 16))
-
-/* An X_MASK with the RB field fixed. */
-#define XRB_MASK (X_MASK | RB_MASK)
-
-/* An X_MASK with the RT field fixed. */
-#define XRT_MASK (X_MASK | RT_MASK)
-
-/* An XRT_MASK mask with the L bits clear. */
-#define XLRT_MASK (XRT_MASK & ~((unsigned long) 0x3 << 21))
-
-/* An X_MASK with the RA and RB fields fixed. */
-#define XRARB_MASK (X_MASK | RA_MASK | RB_MASK)
-
-/* An XRARB_MASK, but with the L bit clear. */
-#define XRLARB_MASK (XRARB_MASK & ~((unsigned long) 1 << 16))
-
-/* An X_MASK with the RT and RA fields fixed. */
-#define XRTRA_MASK (X_MASK | RT_MASK | RA_MASK)
-
-/* An XRTRA_MASK, but with L bit clear. */
-#define XRTLRA_MASK (XRTRA_MASK & ~((unsigned long) 1 << 21))
-
-/* An X form instruction with the L bit specified. */
-#define XOPL(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 1) << 21))
-
-/* The mask for an X form comparison instruction. */
-#define XCMP_MASK (X_MASK | (((unsigned long)1) << 22))
-
-/* The mask for an X form comparison instruction with the L field
- fixed. */
-#define XCMPL_MASK (XCMP_MASK | (((unsigned long)1) << 21))
-
-/* An X form trap instruction with the TO field specified. */
-#define XTO(op, xop, to) (X ((op), (xop)) | ((((unsigned long)(to)) & 0x1f) << 21))
-#define XTO_MASK (X_MASK | TO_MASK)
-
-/* An X form tlb instruction with the SH field specified. */
-#define XTLB(op, xop, sh) (X ((op), (xop)) | ((((unsigned long)(sh)) & 0x1f) << 11))
-#define XTLB_MASK (X_MASK | SH_MASK)
-
-/* An X form sync instruction. */
-#define XSYNC(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 3) << 21))
-
-/* An X form sync instruction with everything filled in except the LS field. */
-#define XSYNC_MASK (0xff9fffff)
-
-/* An X_MASK, but with the EH bit clear. */
-#define XEH_MASK (X_MASK & ~((unsigned long )1))
-
-/* An X form AltiVec dss instruction. */
-#define XDSS(op, xop, a) (X ((op), (xop)) | ((((unsigned long)(a)) & 1) << 25))
-#define XDSS_MASK XDSS(0x3f, 0x3ff, 1)
-
-/* An XFL form instruction. */
-#define XFL(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1) | (((unsigned long)(rc)) & 1))
-#define XFL_MASK XFL (0x3f, 0x3ff, 1)
-
-/* An X form isel instruction. */
-#define XISEL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1))
-#define XISEL_MASK XISEL(0x3f, 0x1f)
-
-/* An XL form instruction with the LK field set to 0. */
-#define XL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1))
-
-/* An XL form instruction which uses the LK field. */
-#define XLLK(op, xop, lk) (XL ((op), (xop)) | ((lk) & 1))
-
-/* The mask for an XL form instruction. */
-#define XL_MASK XLLK (0x3f, 0x3ff, 1)
-
-/* An XL form instruction which explicitly sets the BO field. */
-#define XLO(op, bo, xop, lk) \
- (XLLK ((op), (xop), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21))
-#define XLO_MASK (XL_MASK | BO_MASK)
-
-/* An XL form instruction which explicitly sets the y bit of the BO
- field. */
-#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | ((((unsigned long)(y)) & 1) << 21))
-#define XLYLK_MASK (XL_MASK | Y_MASK)
-
-/* An XL form instruction which sets the BO field and the condition
- bits of the BI field. */
-#define XLOCB(op, bo, cb, xop, lk) \
- (XLO ((op), (bo), (xop), (lk)) | ((((unsigned long)(cb)) & 3) << 16))
-#define XLOCB_MASK XLOCB (0x3f, 0x1f, 0x3, 0x3ff, 1)
-
-#define BB_MASK (0x1f << 11)
-/* An XL_MASK or XLYLK_MASK or XLOCB_MASK with the BB field fixed. */
-#define XLBB_MASK (XL_MASK | BB_MASK)
-#define XLYBB_MASK (XLYLK_MASK | BB_MASK)
-#define XLBOCBBB_MASK (XLOCB_MASK | BB_MASK)
-
-/* A mask for branch instructions using the BH field. */
-#define XLBH_MASK (XL_MASK | (0x1c << 11))
-
-/* An XL_MASK with the BO and BB fields fixed. */
-#define XLBOBB_MASK (XL_MASK | BO_MASK | BB_MASK)
-
-/* An XL_MASK with the BO, BI and BB fields fixed. */
-#define XLBOBIBB_MASK (XL_MASK | BO_MASK | BI_MASK | BB_MASK)
-
-/* An XO form instruction. */
-#define XO(op, xop, oe, rc) \
- (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1) | ((((unsigned long)(oe)) & 1) << 10) | (((unsigned long)(rc)) & 1))
-#define XO_MASK XO (0x3f, 0x1ff, 1, 1)
-
-/* An XO_MASK with the RB field fixed. */
-#define XORB_MASK (XO_MASK | RB_MASK)
-
-/* An XS form instruction. */
-#define XS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 2) | (((unsigned long)(rc)) & 1))
-#define XS_MASK XS (0x3f, 0x1ff, 1)
-
-/* A mask for the FXM version of an XFX form instruction. */
-#define XFXFXM_MASK (X_MASK | (1 << 11) | (1 << 20))
-
-/* An XFX form instruction with the FXM field filled in. */
-#define XFXM(op, xop, fxm, p4) \
- (X ((op), (xop)) | ((((unsigned long)(fxm)) & 0xff) << 12) \
- | ((unsigned long)(p4) << 20))
-
-#define SPR_MASK (0x3ff << 11)
-/* An XFX form instruction with the SPR field filled in. */
-#define XSPR(op, xop, spr) \
- (X ((op), (xop)) | ((((unsigned long)(spr)) & 0x1f) << 16) | ((((unsigned long)(spr)) & 0x3e0) << 6))
-#define XSPR_MASK (X_MASK | SPR_MASK)
-
-/* An XFX form instruction with the SPR field filled in except for the
- SPRBAT field. */
-#define XSPRBAT_MASK (XSPR_MASK &~ SPRBAT_MASK)
-
-/* An XFX form instruction with the SPR field filled in except for the
- SPRG field. */
-#define XSPRG_MASK (XSPR_MASK & ~(0x1f << 16))
-
-/* An X form instruction with everything filled in except the E field. */
-#define XE_MASK (0xffff7fff)
-
-/* An X form user context instruction. */
-#define XUC(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f))
-#define XUC_MASK XUC(0x3f, 0x1f)
-
-/* The BO encodings used in extended conditional branch mnemonics. */
-#define BODNZF (0x0)
-#define BODNZFP (0x1)
-#define BODZF (0x2)
-#define BODZFP (0x3)
-#define BODNZT (0x8)
-#define BODNZTP (0x9)
-#define BODZT (0xa)
-#define BODZTP (0xb)
-
-#define BOF (0x4)
-#define BOFP (0x5)
-#define BOFM4 (0x6)
-#define BOFP4 (0x7)
-#define BOT (0xc)
-#define BOTP (0xd)
-#define BOTM4 (0xe)
-#define BOTP4 (0xf)
-
-#define BODNZ (0x10)
-#define BODNZP (0x11)
-#define BODZ (0x12)
-#define BODZP (0x13)
-#define BODNZM4 (0x18)
-#define BODNZP4 (0x19)
-#define BODZM4 (0x1a)
-#define BODZP4 (0x1b)
-
-#define BOU (0x14)
-
-/* The BI condition bit encodings used in extended conditional branch
- mnemonics. */
-#define CBLT (0)
-#define CBGT (1)
-#define CBEQ (2)
-#define CBSO (3)
-
-/* The TO encodings used in extended trap mnemonics. */
-#define TOLGT (0x1)
-#define TOLLT (0x2)
-#define TOEQ (0x4)
-#define TOLGE (0x5)
-#define TOLNL (0x5)
-#define TOLLE (0x6)
-#define TOLNG (0x6)
-#define TOGT (0x8)
-#define TOGE (0xc)
-#define TONL (0xc)
-#define TOLT (0x10)
-#define TOLE (0x14)
-#define TONG (0x14)
-#define TONE (0x18)
-#define TOU (0x1f)
-
-/* Smaller names for the flags so each entry in the opcodes table will
- fit on a single line. */
-#undef PPC
-#define PPC PPC_OPCODE_PPC
-#define PPCCOM PPC_OPCODE_PPC | PPC_OPCODE_COMMON
-#define PPC64 PPC_OPCODE_64 | PPC_OPCODE_PPC
-#define COM PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON
-#define COM32 PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_32
-
-/* The opcode table.
-
- The format of the opcode table is:
-
- NAME OPCODE MASK FLAGS { OPERANDS }
-
- NAME is the name of the instruction.
- OPCODE is the instruction opcode.
- MASK is the opcode mask; this is used to tell the disassembler
- which bits in the actual opcode must match OPCODE.
- FLAGS are flags indicated what processors support the instruction.
- OPERANDS is the list of operands.
-
- The disassembler reads the table in order and prints the first
- instruction which matches, so this table is sorted to put more
- specific instructions before more general instructions. It is also
- sorted by major opcode. */
-
-static const struct powerpc_opcode powerpc_opcodes[] = {
-
-{ "cmplwi", OPL(10,0), OPL_MASK, PPCCOM, { OBF, RA, UI } },
-{ "cmpwi", OPL(11,0), OPL_MASK, PPCCOM, { OBF, RA, SI } },
-{ "cmpw", XOPL(31,0,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } },
-{ "cmplw", XOPL(31,32,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } },
-{ "fcmpu", X(63,0), X_MASK|(3<<21), COM, { BF, FRA, FRB } },
-
-{ "li", OP(14), DRA_MASK, PPCCOM, { RT, SI } },
-{ "lis", OP(15), DRA_MASK, PPCCOM, { RT, SI } },
-
-{ "addi", OP(14), OP_MASK, PPCCOM, { RT, RA0, SI } },
-{ "addis", OP(15), OP_MASK, PPCCOM, { RT,RA0,SI } },
-{ "blt-", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } },
-{ "bc", B(16,0,0), B_MASK, COM, { BO, BI, BD } },
-{ "bcl", B(16,0,1), B_MASK, COM, { BO, BI, BD } },
-{ "b", B(18,0,0), B_MASK, COM, { LI } },
-{ "bl", B(18,0,1), B_MASK, COM, { LI } },
-{ "blr", XLO(19,BOU,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } },
-{ "bctr", XLO(19,BOU,528,0), XLBOBIBB_MASK, COM, { 0 } },
-{ "bctrl", XLO(19,BOU,528,1), XLBOBIBB_MASK, COM, { 0 } },
-
-{ "rlwinm", M(21,0), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } },
-{ "nop", OP(24), 0xffffffff, PPCCOM, { 0 } },
-{ "ori", OP(24), OP_MASK, PPCCOM, { RA, RS, UI } },
-{ "xoris", OP(27), OP_MASK, PPCCOM, { RA, RS, UI } },
-{ "ldx", X(31,21), X_MASK, PPC64, { RT, RA0, RB } },
-{ "lwzx", X(31,23), X_MASK, PPCCOM, { RT, RA0, RB } },
-{ "slw", XRC(31,24,0), X_MASK, PPCCOM, { RA, RS, RB } },
-{ "and", XRC(31,28,0), X_MASK, COM, { RA, RS, RB } },
-{ "sub", XO(31,40,0,0), XO_MASK, PPC, { RT, RB, RA } },
-{ "lbzx", X(31,87), X_MASK, COM, { RT, RA0, RB } },
-{ "neg", XO(31,104,0,0), XORB_MASK, COM, { RT, RA } },
-{ "not", XRC(31,124,0), X_MASK, COM, { RA, RS, RBS } },
-{ "stwx", X(31,151), X_MASK, PPCCOM, { RS, RA0, RB } },
-{ "stbx", X(31,215), X_MASK, COM, { RS, RA0, RB } },
-{ "mullw", XO(31,235,0,0), XO_MASK, PPCCOM, { RT, RA, RB } },
-{ "add", XO(31,266,0,0), XO_MASK, PPCCOM, { RT, RA, RB } },
-{ "lhzx", X(31,279), X_MASK, COM, { RT, RA0, RB } },
-{ "xor", XRC(31,316,0), X_MASK, COM, { RA, RS, RB } },
-{ "mflr", XSPR(31,339,8), XSPR_MASK, COM, { RT } },
-{ "sthx", X(31,407), X_MASK, COM, { RS, RA0, RB } },
-{ "mr", XRC(31,444,0), X_MASK, COM, { RA, RS, RBS } },
-{ "or", XRC(31,444,0), X_MASK, COM, { RA, RS, RB } },
-{ "divwu", XO(31,459,0,0), XO_MASK, PPC, { RT, RA, RB } },
-{ "mtlr", XSPR(31,467,8), XSPR_MASK, COM, { RS } },
-{ "mtctr", XSPR(31,467,9), XSPR_MASK, COM, { RS } },
-{ "divw", XO(31,491,0,0), XO_MASK, PPC, { RT, RA, RB } },
-{ "lfsx", X(31,535), X_MASK, COM, { FRT, RA0, RB } },
-{ "srw", XRC(31,536,0), X_MASK, PPCCOM, { RA, RS, RB } },
-{ "stfsx", X(31,663), X_MASK, COM, { FRS, RA0, RB } },
-{ "sraw", XRC(31,792,0), X_MASK, PPCCOM, { RA, RS, RB } },
-{ "extsh", XRC(31,922,0), XRB_MASK, PPCCOM, { RA, RS } },
-{ "extsb", XRC(31,954,0), XRB_MASK, PPC, { RA, RS} },
-
-{ "lwz", OP(32), OP_MASK, PPCCOM, { RT, D, RA0 } },
-{ "lbz", OP(34), OP_MASK, COM, { RT, D, RA0 } },
-{ "stw", OP(36), OP_MASK, PPCCOM, { RS, D, RA0 } },
-{ "stwu", OP(37), OP_MASK, PPCCOM, { RS, D, RAS } },
-{ "stb", OP(38), OP_MASK, COM, { RS, D, RA0 } },
-{ "lhz", OP(40), OP_MASK, COM, { RT, D, RA0 } },
-{ "sth", OP(44), OP_MASK, COM, { RS, D, RA0 } },
-{ "lfs", OP(48), OP_MASK, COM, { FRT, D, RA0 } },
-{ "lfd", OP(50), OP_MASK, COM, { FRT, D, RA0 } },
-{ "stfs", OP(52), OP_MASK, COM, { FRS, D, RA0 } },
-{ "stfd", OP(54), OP_MASK, COM, { FRS, D, RA0 } },
-{ "ld", DSO(58,0), DS_MASK, PPC64, { RT, DS, RA0 } },
-
-{ "fdivs", A(59,18,0), AFRC_MASK, PPC, { FRT, FRA, FRB } },
-{ "fsubs", A(59,20,0), AFRC_MASK, PPC, { FRT, FRA, FRB } },
-{ "fadds", A(59,21,0), AFRC_MASK, PPC, { FRT, FRA, FRB } },
-{ "fmuls", A(59,25,0), AFRB_MASK, PPC, { FRT, FRA, FRC } },
-{ "std", DSO(62,0), DS_MASK, PPC64, { RS, DS, RA0 } },
-{ "stdu", DSO(62,1), DS_MASK, PPC64, { RS, DS, RAS } },
-{ "frsp", XRC(63,12,0), XRA_MASK, COM, { FRT, FRB } },
-{ "fctiwz", XRC(63,15,0), XRA_MASK, PPCCOM, { FRT, FRB } },
-{ "fsub", A(63,20,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } },
-{ "fneg", XRC(63,40,0), XRA_MASK, COM, { FRT, FRB } },
-};
-
-static const int powerpc_num_opcodes =
- sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
diff --git a/engine/code/qcommon/vm_powerpc_asm.h b/engine/code/qcommon/vm_powerpc_asm.h
deleted file mode 100644
index 9bccf18..0000000
--- a/engine/code/qcommon/vm_powerpc_asm.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 2008 Przemyslaw Iskra <sparky at pld-linux.org>
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#ifndef VM_POWERPC_ASM_H
-#define VM_POWERPC_ASM_H
-
-/*
- * Register information according to:
- * http://refspecs.freestandards.org/elf/elfspec_ppc.pdf
- */
-
-#define r0 0 // volatile
-#define r1 1 // caller safe ( stack pointer )
-#define r2 2 // reserved
-#define r3 3 // callee safe
-#define r4 4 // callee safe
-#define r5 5 // callee safe
-#define r6 6 // callee safe
-#define r7 7 // callee safe
-#define r8 8 // callee safe
-#define r9 9 // callee safe
-#define r10 10 // callee safe
-#define r11 11 // volatile
-#define r12 12 // volatile
-#define r13 13 // reserved ( small data area )
-#define r14 14 // caller safe
-#define r15 15 // caller safe
-#define r16 16 // caller safe
-#define r17 17 // caller safe
-#define r18 18 // caller safe
-#define r19 19 // caller safe
-#define r20 20 // caller safe
-#define r21 21 // caller safe
-#define r22 22 // caller safe
-#define r23 23 // caller safe
-#define r24 24 // caller safe
-#define r25 25 // caller safe
-#define r26 26 // caller safe
-#define r27 27 // caller safe
-#define r28 28 // caller safe
-#define r29 29 // caller safe
-#define r30 30 // caller safe
-#define r31 31 // caller safe ( environment pointers )
-
-#define f0 0 // callee safe
-#define f1 1 // callee safe
-#define f2 2 // callee safe
-#define f3 3 // callee safe
-#define f4 4 // callee safe
-#define f5 5 // callee safe
-#define f6 6 // callee safe
-#define f7 7 // callee safe
-#define f8 8 // callee safe
-#define f9 9 // callee safe
-#define f10 10 // callee safe
-#define f11 11 // callee safe
-#define f12 12 // callee safe
-#define f13 13 // callee safe
-#define f14 14 // caller safe
-#define f15 15 // caller safe
-#define f16 16 // caller safe
-#define f17 17 // caller safe
-#define f18 18 // caller safe
-#define f19 19 // caller safe
-#define f20 20 // caller safe
-#define f21 21 // caller safe
-#define f22 22 // caller safe
-#define f23 23 // caller safe
-#define f24 24 // caller safe
-#define f25 25 // caller safe
-#define f26 26 // caller safe
-#define f27 27 // caller safe
-#define f28 28 // caller safe
-#define f29 29 // caller safe
-#define f30 30 // caller safe
-#define f31 31 // caller safe
-
-#define cr0 0 // volatile
-#define cr1 1 // volatile
-#define cr2 2 // caller safe
-#define cr3 3 // caller safe
-#define cr4 4 // caller safe
-#define cr5 5 // volatile
-#define cr6 6 // volatile
-#define cr7 7 // volatile
-
-#define lt 0
-#define gt 1
-#define eq 2
-#define so 3
-
-// branch bo field values
-#define branchLikely 1
-#define branchFalse 4
-#define branchTrue 12
-#define branchAlways 20
-
-// branch extensions (change branch type)
-#define branchExtLink 0x0001
-
-
-/*
- * This list must match exactly the powerpc_opcodes list from vm_powerpc_asm.c
- * If you're changing the original list remember to regenerate this one. You
- * may do so using this perl script:
- perl -p -e 'BEGIN{%t=("-"=>m=>"+"=>p=>"."=>d=>);$l=""}$o=0 if/^}/;
- if($o && s/^{ "(.*?)([\.+-])?".+/i\U$1\E$t{$2}/s){$_.="_" while$l{$_};
- $l{$_}=1;if(length $l.$_ > 70){$s=$_;$_="\t$l\n";$l="$s,"}else
- {$l.=" $_,";$_=undef}}else{$o=1 if/powerpc_opcodes.*=/;$_=undef};
- END{print "\t$l\n"}' < vm_powerpc_asm.c
- */
-
-typedef enum powerpc_iname {
- iCMPLWI, iCMPWI, iCMPW, iCMPLW, iFCMPU, iLI, iLIS, iADDI, iADDIS,
- iBLTm, iBC, iBCL, iB, iBL, iBLR, iBCTR, iBCTRL, iRLWINM, iNOP, iORI,
- iXORIS, iLDX, iLWZX, iSLW, iAND, iSUB, iLBZX, iNEG, iNOT, iSTWX, iSTBX,
- iMULLW, iADD, iLHZX, iXOR, iMFLR, iSTHX, iMR, iOR, iDIVWU, iMTLR,
- iMTCTR, iDIVW, iLFSX, iSRW, iSTFSX, iSRAW, iEXTSH, iEXTSB, iLWZ, iLBZ,
- iSTW, iSTWU, iSTB, iLHZ, iSTH, iLFS, iLFD, iSTFS, iSTFD, iLD, iFDIVS,
- iFSUBS, iFADDS, iFMULS, iSTD, iSTDU, iFRSP, iFCTIWZ, iFSUB, iFNEG,
-} powerpc_iname_t;
-
-#include <stdint.h>
-
-typedef uint32_t ppc_instruction_t;
-
-extern ppc_instruction_t
-asm_instruction( powerpc_iname_t, const int, const long int * );
-
-#define IN( inst, args... ) \
-({\
- const long int argv[] = { args };\
- const int argc = sizeof( argv ) / sizeof( argv[0] ); \
- asm_instruction( inst, argc, argv );\
-})
-
-#endif
diff --git a/engine/code/qcommon/vm_sparc.c b/engine/code/qcommon/vm_sparc.c
deleted file mode 100644
index 39f2202..0000000
--- a/engine/code/qcommon/vm_sparc.c
+++ /dev/null
@@ -1,1648 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 2009 David S. Miller <davem at davemloft.net>
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/* This code is based almost entirely upon the vm_powerpc.c code by
- * Przemyslaw Iskra. All I did was make it work on Sparc :-) -DaveM
- */
-
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <time.h>
-#include <stddef.h>
-
-#include "vm_local.h"
-#include "vm_sparc.h"
-
-/* exit() won't be called but use it because it is marked with noreturn */
-#define DIE( reason ) \
- do { \
- Com_Error(ERR_DROP, "vm_sparc compiler error: " reason "\n"); \
- exit(1); \
- } while(0)
-
-/* Select Length - first value on 32 bits, second on 64 */
-#ifdef __arch64__
-#define SL(a, b) (b)
-#else
-#define SL(a, b) (a)
-#endif
-
-#define rTMP G1
-#define rVMDATA G2
-#define rPSTACK G3
-#define rDATABASE G4
-#define rDATAMASK G5
-
-struct sparc_opcode {
- const char *name;
- unsigned int opcode;
- unsigned int mask;
- unsigned char args[4];
-#define ARG_NONE 0
-#define ARG_RS1 1
-#define ARG_RS2 2
-#define ARG_RD 3
-#define ARG_SIMM13 4
-#define ARG_DISP30 5
-#define ARG_IMM22 6
-#define ARG_DISP22 7
-#define ARG_SWTRAP 8
-};
-
-#define ARG_RS1_RS2_RD { ARG_RS1, ARG_RS2, ARG_RD }
-#define ARG_RS1_SIMM13_RD { ARG_RS1, ARG_SIMM13, ARG_RD }
-#define ARG_RS1_RS2 { ARG_RS1, ARG_RS2 }
-#define ARG_RS2_RD { ARG_RS2, ARG_RD }
-
-#define OP_MASK 0xc0000000
-#define OP2_MASK 0x01c00000
-#define OP3_MASK 0x01f80000
-#define OPF_MASK 0x00003fe0
-
-#define IMM 0x00002000
-
-#define FMT1(op) ((op) << 30), OP_MASK
-#define FMT2(op,op2) ((op) << 30)|((op2)<<22), (OP_MASK | OP2_MASK)
-#define FMT3(op,op3) ((op) << 30)|((op3)<<19), (OP_MASK | OP3_MASK | IMM)
-#define FMT3I(op,op3) ((op) << 30)|((op3)<<19)|IMM, (OP_MASK | OP3_MASK | IMM)
-#define FMT3F(op,op3,opf) ((op) << 30)|((op3)<<19)|((opf)<<5), \
- (OP_MASK | OP3_MASK | OPF_MASK)
-
-#define BICC(A,COND) FMT2(0,((A<<7)|(COND<<3)|0x2))
-#define BFCC(A,COND) FMT2(0,((A<<7)|(COND<<3)|0x6))
-#define TICC(COND) FMT3I(0,((COND<<6)|0x3a))
-
-enum sparc_iname {
- CALL, NOP, SETHI,
-
- BA, BN, BNE, BE, BG, BLE, BGE, BL, BGU, BLEU, BCC, BCS,
- BPOS, BNEG, BVC, BVS,
-
- ADDI, ADD,
- ANDI, AND,
- ORI, OR,
- XORI, XOR,
- SUBI, SUB,
- ANDNI, ANDN,
- ORNI, ORN,
- XNORI, XNOR,
-
- UMULI, UMUL,
- SMULI, SMUL,
- UDIVI, UDIV,
- SDIVI, SDIV,
-
- SUBCCI, SUBCC,
-
- SLLI, SLL,
- SRLI, SRL,
- SRAI, SRA,
-
- WRI, WR,
-
- SAVEI, SAVE,
- RESTOREI, RESTORE,
-
- TA,
-
- JMPLI, JMPL,
-
- LDXI, LDX,
- LDUWI, LDUW,
- LDUHI, LDUH,
- LDUBI, LDUB,
-
- STXI, STX,
- STWI, STW,
- STHI, STH,
- STBI, STB,
-
- LDFI, LDF,
- STFI, STF,
-
- FADD, FSUB, FCMP, FSTOI, FITOS, FNEG, FDIV, FMUL,
- FBE, FBNE, FBL, FBGE, FBG, FBLE,
-};
-
-#define LDLI SL(LDUWI, LDXI)
-#define LDL SL(LDUW, LDX)
-#define STLI SL(STWI, STXI)
-#define STL SL(STW, STX)
-
-#define SPARC_NOP 0x01000000
-
-static const struct sparc_opcode sparc_opcodes[] = {
- { "call", FMT1(1), { ARG_DISP30 }, },
- { "nop", SPARC_NOP, 0xffffffff, { ARG_NONE }, }, /* sethi %hi(0), %g0 */
- { "sethi", FMT2(0,4), { ARG_IMM22, ARG_RD }, },
- { "ba", BICC(0,8), { ARG_DISP22 }, },
- { "bn", BICC(0,0), { ARG_DISP22 }, },
- { "bne", BICC(0,9), { ARG_DISP22 }, },
- { "be", BICC(0,1), { ARG_DISP22 }, },
- { "bg", BICC(0,10), { ARG_DISP22 }, },
- { "ble", BICC(0,2), { ARG_DISP22 }, },
- { "bge", BICC(0,11), { ARG_DISP22 }, },
- { "bl", BICC(0,3), { ARG_DISP22 }, },
- { "bgu", BICC(0,12), { ARG_DISP22 }, },
- { "bleu", BICC(0,4), { ARG_DISP22 }, },
- { "bcc", BICC(0,13), { ARG_DISP22 }, },
- { "bcs", BICC(0,5), { ARG_DISP22 }, },
- { "bpos", BICC(0,14), { ARG_DISP22 }, },
- { "bneg", BICC(0,6), { ARG_DISP22 }, },
- { "bvc", BICC(0,15), { ARG_DISP22 }, },
- { "bvs", BICC(0,7), { ARG_DISP22 }, },
-
- { "add", FMT3I(2, 0x00), ARG_RS1_SIMM13_RD, },
- { "add", FMT3 (2, 0x00), ARG_RS1_RS2_RD, },
- { "and", FMT3I(2, 0x01), ARG_RS1_SIMM13_RD, },
- { "and", FMT3 (2, 0x01), ARG_RS1_RS2_RD, },
- { "or", FMT3I(2, 0x02), ARG_RS1_SIMM13_RD, },
- { "or", FMT3 (2, 0x02), ARG_RS1_RS2_RD, },
- { "xor", FMT3I(2, 0x03), ARG_RS1_SIMM13_RD, },
- { "xor", FMT3 (2, 0x03), ARG_RS1_RS2_RD, },
- { "sub", FMT3I(2, 0x04), ARG_RS1_SIMM13_RD, },
- { "sub", FMT3 (2, 0x04), ARG_RS1_RS2_RD, },
- { "andn", FMT3I(2, 0x05), ARG_RS1_SIMM13_RD, },
- { "andn", FMT3 (2, 0x05), ARG_RS1_RS2_RD, },
- { "orn", FMT3I(2, 0x06), ARG_RS1_SIMM13_RD, },
- { "orn", FMT3 (2, 0x06), ARG_RS1_RS2_RD, },
- { "xnor", FMT3I(2, 0x07), ARG_RS1_SIMM13_RD, },
- { "xnor", FMT3 (2, 0x07), ARG_RS1_RS2_RD, },
-
- { "umul", FMT3I(2, 0x0a), ARG_RS1_SIMM13_RD, },
- { "umul", FMT3 (2, 0x0a), ARG_RS1_RS2_RD, },
- { "smul", FMT3I(2, 0x0b), ARG_RS1_SIMM13_RD, },
- { "smul", FMT3 (2, 0x0b), ARG_RS1_RS2_RD, },
- { "udiv", FMT3I(2, 0x0e), ARG_RS1_SIMM13_RD, },
- { "udiv", FMT3 (2, 0x0e), ARG_RS1_RS2_RD, },
- { "sdiv", FMT3I(2, 0x0f), ARG_RS1_SIMM13_RD, },
- { "sdiv", FMT3 (2, 0x0f), ARG_RS1_RS2_RD, },
-
- { "subcc", FMT3I(2, 0x14), ARG_RS1_SIMM13_RD, },
- { "subcc", FMT3 (2, 0x14), ARG_RS1_RS2_RD, },
-
- { "sll", FMT3I(2, 0x25), ARG_RS1_SIMM13_RD, },
- { "sll", FMT3 (2, 0x25), ARG_RS1_RS2_RD, },
- { "srl", FMT3I(2, 0x26), ARG_RS1_SIMM13_RD, },
- { "srl", FMT3 (2, 0x26), ARG_RS1_RS2_RD, },
- { "sra", FMT3I(2, 0x27), ARG_RS1_SIMM13_RD, },
- { "sra", FMT3 (2, 0x27), ARG_RS1_RS2_RD, },
-
- { "wr", FMT3I(2, 0x30), ARG_RS1_SIMM13_RD, },
- { "wr", FMT3 (2, 0x30), ARG_RS1_SIMM13_RD, },
-
- { "save", FMT3I(2,0x3c), ARG_RS1_SIMM13_RD, },
- { "save", FMT3 (2,0x3c), ARG_RS1_RS2_RD, },
- { "restore", FMT3I(2,0x3d), ARG_RS1_SIMM13_RD, },
- { "restore", FMT3 (2,0x3d), ARG_RS1_RS2_RD, },
- { "ta", TICC(8), { ARG_SWTRAP, ARG_NONE }, },
- { "jmpl", FMT3I(2,0x38), ARG_RS1_SIMM13_RD, },
- { "jmpl", FMT3 (2,0x38), ARG_RS1_RS2_RD, },
-
- { "ldx", FMT3I(3,0x0b), ARG_RS1_SIMM13_RD, },
- { "ldx", FMT3 (3,0x0b), ARG_RS1_RS2_RD, },
- { "lduw", FMT3I(3,0x00), ARG_RS1_SIMM13_RD, },
- { "lduw", FMT3 (3,0x00), ARG_RS1_RS2_RD, },
- { "lduh", FMT3I(3,0x02), ARG_RS1_SIMM13_RD, },
- { "lduh", FMT3 (3,0x02), ARG_RS1_RS2_RD, },
- { "ldub", FMT3I(3,0x01), ARG_RS1_SIMM13_RD, },
- { "ldub", FMT3 (3,0x01), ARG_RS1_RS2_RD, },
-
- { "stx", FMT3I(3,0x0e), ARG_RS1_SIMM13_RD, },
- { "stx", FMT3 (3,0x0e), ARG_RS1_RS2_RD, },
- { "stw", FMT3I(3,0x04), ARG_RS1_SIMM13_RD, },
- { "stw", FMT3 (3,0x04), ARG_RS1_RS2_RD, },
- { "sth", FMT3I(3,0x06), ARG_RS1_SIMM13_RD, },
- { "sth", FMT3 (3,0x06), ARG_RS1_RS2_RD, },
- { "stb", FMT3I(3,0x05), ARG_RS1_SIMM13_RD, },
- { "stb", FMT3 (3,0x05), ARG_RS1_RS2_RD, },
-
- { "ldf", FMT3I(3,0x20), ARG_RS1_SIMM13_RD, },
- { "ldf", FMT3 (3,0x20), ARG_RS1_RS2_RD, },
- { "stf", FMT3I(3,0x24), ARG_RS1_SIMM13_RD, },
- { "stf", FMT3 (3,0x24), ARG_RS1_RS2_RD, },
-
- { "fadd", FMT3F(2,0x34,0x041), ARG_RS1_RS2_RD, },
- { "fsub", FMT3F(2,0x34,0x045), ARG_RS1_RS2_RD, },
- { "fcmp", FMT3F(2,0x35,0x051), ARG_RS1_RS2, },
- { "fstoi", FMT3F(2,0x34,0x0d1), ARG_RS2_RD, },
- { "fitos", FMT3F(2,0x34,0x0c4), ARG_RS2_RD, },
-
- { "fneg", FMT3F(2,0x34,0x005), ARG_RS2_RD, },
- { "fdiv", FMT3F(2,0x34,0x04d), ARG_RS1_RS2_RD, },
- { "fmul", FMT3F(2,0x34,0x049), ARG_RS1_RS2_RD, },
-
- { "fbe", BFCC(0,9), { ARG_DISP22 }, },
- { "fbne", BFCC(0,1), { ARG_DISP22 }, },
- { "fbl", BFCC(0,4), { ARG_DISP22 }, },
- { "fbge", BFCC(0,11), { ARG_DISP22 }, },
- { "fbg", BFCC(0,6), { ARG_DISP22 }, },
- { "fble", BFCC(0,13), { ARG_DISP22 }, },
-};
-#define SPARC_NUM_OPCODES (sizeof(sparc_opcodes) / sizeof(sparc_opcodes[0]))
-
-#define RS1(X) (((X) & 0x1f) << 14)
-#define RS2(X) (((X) & 0x1f) << 0)
-#define RD(X) (((X) & 0x1f) << 25)
-#define SIMM13(X) (((X) & 0x1fff) << 0)
-#define IMM22(X) (((X) & 0x3fffff) << 0)
-#define DISP30(X) ((((X) >> 2) & 0x3fffffff) << 0)
-#define DISP22(X) ((((X) >> 2) & 0x3fffff) << 0)
-#define SWTRAP(X) (((X) & 0x7f) << 0)
-
-#define SIMM13_P(X) ((unsigned int) (X) + 0x1000 < 0x2000)
-
-static void vimm(unsigned int val, int bits, int shift, int sgned, int arg_index)
-{
- unsigned int orig_val = val;
- int orig_bits = bits;
-
- if (sgned) {
- int x = (int) val;
- if (x < 0)
- x = -x;
- val = (unsigned int) x;
- bits--;
- }
- if (val & ~((1U << bits) - 1U)) {
- Com_Printf("VM ERROR: immediate value 0x%08x out of %d bit range\n",
- orig_val, orig_bits);
- DIE("sparc VM bug");
- }
-}
-
-static unsigned int sparc_assemble(enum sparc_iname iname, const int argc, const int *argv)
-{
- const struct sparc_opcode *op = &sparc_opcodes[iname];
- unsigned int insn = op->opcode;
- int i, flt, rd_flt;
-
- flt = (op->name[0] == 'f');
- rd_flt = flt || (op->name[2] == 'f');
-
- for (i = 0; op->args[i] != ARG_NONE; i++) {
- int val = argv[i];
-
- switch (op->args[i]) {
- case ARG_RS1: insn |= RS1(val); break;
- case ARG_RS2: insn |= RS2(val); break;
- case ARG_RD: insn |= RD(val); break;
- case ARG_SIMM13: insn |= SIMM13(val); vimm(val,13,0,1,i); break;
- case ARG_DISP30: insn |= DISP30(val); vimm(val,30,0,1,i); break;
- case ARG_IMM22: insn |= IMM22(val); vimm(val,22,0,0,i); break;
- case ARG_DISP22: insn |= DISP22(val); vimm(val,22,0,1,i); break;
- case ARG_SWTRAP: insn |= SWTRAP(val); vimm(val,7,0,0,i); break;
- }
- }
-
- return insn;
-}
-
-#define IN(inst, args...) \
-({ const int argv[] = { args }; \
- const int argc = sizeof(argv) / sizeof(argv[0]); \
- sparc_assemble(inst, argc, argv); \
-})
-
-#if 0
-static void pgreg(int reg_num, int arg_index, int flt)
-{
- if (!flt) {
- const char *fmt[] = { "%g", "%o", "%l", "%i" };
-
- Com_Printf("%s%s%d",
- (arg_index ? ", " : ""),
- fmt[reg_num >> 3], reg_num & 7);
- } else
- Com_Printf("%s%%f%d", (arg_index ? ", " : ""), reg_num);
-}
-
-static void pimm(unsigned int val, int bits, int shift, int sgned, int arg_index)
-
-{
- val >>= shift;
- val &= ((1 << bits) - 1);
- if (sgned) {
- int sval = val << (32 - bits);
- sval >>= (32 - bits);
- Com_Printf("%s%d",
- (arg_index ? ", " : ""), sval);
- } else
- Com_Printf("%s0x%08x",
- (arg_index ? ", " : ""), val);
-}
-
-static void sparc_disassemble(unsigned int insn)
-{
- int op_idx;
-
- for (op_idx = 0; op_idx < SPARC_NUM_OPCODES; op_idx++) {
- const struct sparc_opcode *op = &sparc_opcodes[op_idx];
- int i, flt, rd_flt;
-
- if ((insn & op->mask) != op->opcode)
- continue;
-
- flt = (op->name[0] == 'f');
- rd_flt = flt || (op->name[2] == 'f');
-
- Com_Printf("ASM: %7s\t", op->name);
- for (i = 0; op->args[i] != ARG_NONE; i++) {
- switch (op->args[i]) {
- case ARG_RS1: pgreg((insn >> 14) & 0x1f, i, flt); break;
- case ARG_RS2: pgreg((insn >> 0) & 0x1f, i, flt); break;
- case ARG_RD: pgreg((insn >> 25) & 0x1f, i, rd_flt); break;
- case ARG_SIMM13: pimm(insn, 13, 0, 1, i); break;
- case ARG_DISP30: pimm(insn, 30, 0, 0, i); break;
- case ARG_IMM22: pimm(insn, 22, 0, 0, i); break;
- case ARG_DISP22: pimm(insn, 22, 0, 0, i); break;
- case ARG_SWTRAP: pimm(insn, 7, 0, 0, i); break;
- }
- }
- Com_Printf("\n");
- return;
- }
-}
-#endif
-
-/*
- * opcode information table:
- * - length of immediate value
- * - returned register type
- * - required register(s) type
- */
-#define opImm0 0x0000 /* no immediate */
-#define opImm1 0x0001 /* 1 byte immadiate value after opcode */
-#define opImm4 0x0002 /* 4 bytes immediate value after opcode */
-
-#define opRet0 0x0000 /* returns nothing */
-#define opRetI 0x0004 /* returns integer */
-#define opRetF 0x0008 /* returns float */
-#define opRetIF (opRetI | opRetF) /* returns integer or float */
-
-#define opArg0 0x0000 /* requires nothing */
-#define opArgI 0x0010 /* requires integer(s) */
-#define opArgF 0x0020 /* requires float(s) */
-#define opArgIF (opArgI | opArgF) /* requires integer or float */
-
-#define opArg2I 0x0040 /* requires second argument, integer */
-#define opArg2F 0x0080 /* requires second argument, float */
-#define opArg2IF (opArg2I | opArg2F) /* requires second argument, integer or float */
-
-static const unsigned char vm_opInfo[256] =
-{
- [OP_UNDEF] = opImm0,
- [OP_IGNORE] = opImm0,
- [OP_BREAK] = opImm0,
- [OP_ENTER] = opImm4,
- /* OP_LEAVE has to accept floats, they will be converted to ints */
- [OP_LEAVE] = opImm4 | opRet0 | opArgIF,
- /* only STORE4 and POP use values from OP_CALL,
- * no need to convert floats back */
- [OP_CALL] = opImm0 | opRetI | opArgI,
- [OP_PUSH] = opImm0 | opRetIF,
- [OP_POP] = opImm0 | opRet0 | opArgIF,
- [OP_CONST] = opImm4 | opRetIF,
- [OP_LOCAL] = opImm4 | opRetI,
- [OP_JUMP] = opImm0 | opRet0 | opArgI,
-
- [OP_EQ] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_NE] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_LTI] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_LEI] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_GTI] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_GEI] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_LTU] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_LEU] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_GTU] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_GEU] = opImm4 | opRet0 | opArgI | opArg2I,
- [OP_EQF] = opImm4 | opRet0 | opArgF | opArg2F,
- [OP_NEF] = opImm4 | opRet0 | opArgF | opArg2F,
- [OP_LTF] = opImm4 | opRet0 | opArgF | opArg2F,
- [OP_LEF] = opImm4 | opRet0 | opArgF | opArg2F,
- [OP_GTF] = opImm4 | opRet0 | opArgF | opArg2F,
- [OP_GEF] = opImm4 | opRet0 | opArgF | opArg2F,
-
- [OP_LOAD1] = opImm0 | opRetI | opArgI,
- [OP_LOAD2] = opImm0 | opRetI | opArgI,
- [OP_LOAD4] = opImm0 | opRetIF| opArgI,
- [OP_STORE1] = opImm0 | opRet0 | opArgI | opArg2I,
- [OP_STORE2] = opImm0 | opRet0 | opArgI | opArg2I,
- [OP_STORE4] = opImm0 | opRet0 | opArgIF| opArg2I,
- [OP_ARG] = opImm1 | opRet0 | opArgIF,
- [OP_BLOCK_COPY] = opImm4 | opRet0 | opArgI | opArg2I,
-
- [OP_SEX8] = opImm0 | opRetI | opArgI,
- [OP_SEX16] = opImm0 | opRetI | opArgI,
- [OP_NEGI] = opImm0 | opRetI | opArgI,
- [OP_ADD] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_SUB] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_DIVI] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_DIVU] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_MODI] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_MODU] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_MULI] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_MULU] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_BAND] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_BOR] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_BXOR] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_BCOM] = opImm0 | opRetI | opArgI,
- [OP_LSH] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_RSHI] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_RSHU] = opImm0 | opRetI | opArgI | opArg2I,
- [OP_NEGF] = opImm0 | opRetF | opArgF,
- [OP_ADDF] = opImm0 | opRetF | opArgF | opArg2F,
- [OP_SUBF] = opImm0 | opRetF | opArgF | opArg2F,
- [OP_DIVF] = opImm0 | opRetF | opArgF | opArg2F,
- [OP_MULF] = opImm0 | opRetF | opArgF | opArg2F,
- [OP_CVIF] = opImm0 | opRetF | opArgI,
- [OP_CVFI] = opImm0 | opRetI | opArgF,
-};
-
-static const char *opnames[256] = {
- "OP_UNDEF", "OP_IGNORE", "OP_BREAK", "OP_ENTER", "OP_LEAVE", "OP_CALL",
- "OP_PUSH", "OP_POP", "OP_CONST", "OP_LOCAL", "OP_JUMP",
- "OP_EQ", "OP_NE", "OP_LTI", "OP_LEI", "OP_GTI", "OP_GEI",
- "OP_LTU", "OP_LEU", "OP_GTU", "OP_GEU", "OP_EQF", "OP_NEF",
- "OP_LTF", "OP_LEF", "OP_GTF", "OP_GEF",
- "OP_LOAD1", "OP_LOAD2", "OP_LOAD4", "OP_STORE1", "OP_STORE2",
- "OP_STORE4", "OP_ARG", "OP_BLOCK_COPY",
- "OP_SEX8", "OP_SEX16",
- "OP_NEGI", "OP_ADD", "OP_SUB", "OP_DIVI", "OP_DIVU",
- "OP_MODI", "OP_MODU", "OP_MULI", "OP_MULU", "OP_BAND",
- "OP_BOR", "OP_BXOR", "OP_BCOM", "OP_LSH", "OP_RSHI", "OP_RSHU",
- "OP_NEGF", "OP_ADDF", "OP_SUBF", "OP_DIVF", "OP_MULF",
- "OP_CVIF", "OP_CVFI",
-};
-
-static void VM_Destroy_Compiled(vm_t *vm)
-{
- if (vm->codeBase) {
- if (munmap(vm->codeBase, vm->codeLength))
- Com_Printf(S_COLOR_RED "Memory unmap failed, possible memory leak\n");
- }
- vm->codeBase = NULL;
-}
-
-typedef struct VM_Data {
- unsigned int dataLength;
- unsigned int codeLength;
- unsigned int *CallThunk;
- int (*AsmCall)(int, int);
- void (*BlockCopy)(unsigned int, unsigned int, unsigned int);
- unsigned int *iPointers;
- unsigned int data[0];
-} vm_data_t;
-
-#ifdef offsetof
-# define VM_Data_Offset(field) offsetof(vm_data_t, field)
-#else
-# define OFFSET(structName, field) \
- ((void *)&(((structName *)NULL)->field) - NULL)
-# define VM_Data_Offset(field) OFFSET(vm_data_t, field)
-#endif
-
-struct src_insn {
- unsigned char op;
- unsigned int i_count;
-
- union {
- unsigned int i;
- signed int si;
- signed short ss[2];
- unsigned short us[2];
- unsigned char b;
- } arg;
-
- unsigned char dst_reg_flags;
- unsigned char src1_reg_flags;
- unsigned char src2_reg_flags;
-#define REG_FLAGS_FLOAT 0x1
-
- struct src_insn *next;
-};
-
-struct dst_insn;
-struct jump_insn {
- enum sparc_iname jump_iname;
- int jump_dest_insn;
- struct dst_insn *parent;
- struct jump_insn *next;
-};
-
-struct dst_insn {
- struct dst_insn *next;
-
- unsigned int count;
- unsigned int i_count;
-
- struct jump_insn *jump;
- unsigned int length;
- unsigned int code[0];
-};
-
-#define HUNK_SIZE 29
-struct data_hunk {
- struct data_hunk *next;
- int count;
- unsigned int data[HUNK_SIZE];
-};
-
-struct func_info {
- struct src_insn *first;
- struct src_insn *last;
- int has_call;
- int need_float_tmp;
-
- struct src_insn *cached_const;
-
- int stack_space;
- int gpr_pos;
-#define rFIRST(fp) ((fp)->gpr_pos - 1)
-#define rSECOND(fp) ((fp)->gpr_pos - 2)
-#define POP_GPR(fp) ((fp)->gpr_pos--)
-#define PUSH_GPR(fp) ((fp)->gpr_pos++)
-
- int fpr_pos;
-#define fFIRST(fp) ((fp)->fpr_pos - 1)
-#define fSECOND(fp) ((fp)->fpr_pos - 2)
-#define POP_FPR(fp) ((fp)->fpr_pos--)
-#define PUSH_FPR(fp) ((fp)->fpr_pos++)
-
-#define INSN_BUF_SIZE 50
- unsigned int insn_buf[INSN_BUF_SIZE];
- int insn_index;
-
- int saved_icount;
- int force_emit;
-
- struct jump_insn *jump_first;
- struct jump_insn *jump_last;
-
- struct dst_insn *dst_first;
- struct dst_insn *dst_last;
- int dst_count;
-
- struct dst_insn **dst_by_i_count;
-
- struct data_hunk *data_first;
- int data_num;
-};
-
-#define THUNK_ICOUNT -1
-
-static unsigned int sparc_push_data(struct func_info * const fp, unsigned int val)
-{
- struct data_hunk *last, *dp = fp->data_first;
- int off = 0;
-
- last = NULL;
- while (dp) {
- int i;
-
- for (i = 0; i < dp->count; i++) {
- if (dp->data[i] == val) {
- off += i;
- return VM_Data_Offset(data[off]);
- }
- }
- off += dp->count;
- last = dp;
- dp = dp->next;
- }
-
- dp = last;
- if (!dp || dp->count >= HUNK_SIZE) {
- struct data_hunk *new = Z_Malloc(sizeof(*new));
- if (!dp)
- fp->data_first = new;
- else
- dp->next = new;
- dp = new;
- dp->count = 0;
- dp->next = NULL;
- }
- dp->data[dp->count++] = val;
- fp->data_num = off + 1;
- return VM_Data_Offset(data[off]);
-}
-
-static void dst_insn_insert_tail(struct func_info * const fp,
- struct dst_insn *dp)
-{
- if (!fp->dst_first) {
- fp->dst_first = fp->dst_last = dp;
- } else {
- fp->dst_last->next = dp;
- fp->dst_last = dp;
- }
-}
-
-static void jump_insn_insert_tail(struct func_info * const fp,
- struct jump_insn *jp)
-{
- if (!fp->jump_first) {
- fp->jump_first = fp->jump_last = jp;
- } else {
- fp->jump_last->next = jp;
- fp->jump_last = jp;
- }
-}
-
-static struct dst_insn *dst_new(struct func_info * const fp, unsigned int length,
- struct jump_insn *jp, int insns_size)
-{
- struct dst_insn *dp = Z_Malloc(sizeof(struct dst_insn) + insns_size);
-
- dp->length = length;
- dp->jump = jp;
- dp->count = fp->dst_count++;
- dp->i_count = fp->saved_icount;
- dp->next = NULL;
- if (fp->saved_icount != THUNK_ICOUNT)
- fp->dst_by_i_count[fp->saved_icount] = dp;
-
- return dp;
-}
-
-static void dst_insn_append(struct func_info * const fp)
-{
- int insns_size = (sizeof(unsigned int) * fp->insn_index);
- struct dst_insn *dp;
-
- dp = dst_new(fp, fp->insn_index, NULL, insns_size);
- if (insns_size)
- memcpy(&dp->code[0], fp->insn_buf, insns_size);
- dst_insn_insert_tail(fp, dp);
-
- fp->insn_index = 0;
-}
-
-static void jump_insn_append(struct func_info * const fp, enum sparc_iname iname, int dest)
-{
- struct jump_insn *jp = Z_Malloc(sizeof(*jp));
- struct dst_insn *dp;
-
- dp = dst_new(fp, 2, jp, 0);
-
- jp->jump_iname = iname;
- jp->jump_dest_insn = dest;
- jp->parent = dp;
- jp->next = NULL;
-
- jump_insn_insert_tail(fp, jp);
- dst_insn_insert_tail(fp, dp);
-}
-
-static void start_emit(struct func_info * const fp, int i_count)
-{
- fp->saved_icount = i_count;
- fp->insn_index = 0;
- fp->force_emit = 0;
-}
-
-static void __do_emit_one(struct func_info * const fp, unsigned int insn)
-{
- fp->insn_buf[fp->insn_index++] = insn;
-}
-
-#define in(inst, args...) __do_emit_one(fp, IN(inst, args))
-
-static void end_emit(struct func_info * const fp)
-{
- if (fp->insn_index || fp->force_emit)
- dst_insn_append(fp);
-}
-
-static void emit_jump(struct func_info * const fp, enum sparc_iname iname, int dest)
-{
- end_emit(fp);
- jump_insn_append(fp, iname, dest);
-}
-
-static void analyze_function(struct func_info * const fp)
-{
- struct src_insn *value_provider[20] = { NULL };
- struct src_insn *sp = fp->first;
- int opstack_depth = 0;
-
- while ((sp = sp->next) != NULL) {
- unsigned char opi, op = sp->op;
-
- opi = vm_opInfo[op];
- if (opi & opArgIF) {
- struct src_insn *vp = value_provider[--opstack_depth];
- unsigned char vpopi = vm_opInfo[vp->op];
-
- if ((opi & opArgI) && (vpopi & opRetI)) {
- /* src1 and dst are integers */
- } else if ((opi & opArgF) && (vpopi & opRetF)) {
- /* src1 and dst are floats */
- vp->dst_reg_flags |= REG_FLAGS_FLOAT;
- sp->src1_reg_flags = REG_FLAGS_FLOAT;
- } else {
- /* illegal combination */
- DIE("unrecognized instruction combination");
- }
- }
- if (opi & opArg2IF) {
- struct src_insn *vp = value_provider[--opstack_depth];
- unsigned char vpopi = vm_opInfo[vp->op];
-
- if ((opi & opArg2I) && (vpopi & opRetI)) {
- /* src2 and dst are integers */
- } else if ( (opi & opArg2F) && (vpopi & opRetF) ) {
- /* src2 and dst are floats */
- vp->dst_reg_flags |= REG_FLAGS_FLOAT;
- sp->src2_reg_flags = REG_FLAGS_FLOAT;
- } else {
- /* illegal combination */
- DIE("unrecognized instruction combination");
- }
- }
- if (opi & opRetIF) {
- value_provider[opstack_depth] = sp;
- opstack_depth++;
- }
- }
-}
-
-static int asmcall(int call, int pstack)
-{
- vm_t *savedVM = currentVM;
- int i, ret;
-
- currentVM->programStack = pstack - 4;
- if (sizeof(intptr_t) == sizeof(int)) {
- intptr_t *argPosition = (intptr_t *)((byte *)currentVM->dataBase + pstack + 4);
- argPosition[0] = -1 - call;
- ret = currentVM->systemCall(argPosition);
- } else {
- intptr_t args[11];
-
- args[0] = -1 - call;
- int *argPosition = (int *)((byte *)currentVM->dataBase + pstack + 4);
- for( i = 1; i < 11; i++ )
- args[i] = argPosition[i];
-
- ret = currentVM->systemCall(args);
- }
-
- currentVM = savedVM;
-
- return ret;
-}
-
-static void blockcopy(unsigned int dest, unsigned int src, unsigned int count)
-{
- unsigned int dataMask = currentVM->dataMask;
-
- if ((dest & dataMask) != dest ||
- (src & dataMask) != src ||
- ((dest+count) & dataMask) != dest + count ||
- ((src+count) & dataMask) != src + count) {
- DIE("OP_BLOCK_COPY out of range!");
- }
-
- memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count);
-}
-
-static void do_emit_const(struct func_info * const fp, struct src_insn *sp)
-{
- start_emit(fp, sp->i_count);
- if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
- in(LDFI, rVMDATA, sparc_push_data(fp, sp->arg.i), fFIRST(fp));
- } else {
- if ((sp->arg.i & ~0x3ff) == 0) {
- in(ORI, G0, sp->arg.i & 0x3ff, rFIRST(fp));
- } else if ((sp->arg.i & 0x3ff) == 0) {
- in(SETHI, sp->arg.i >> 10, rFIRST(fp));
- } else {
- in(SETHI, sp->arg.i >> 10, rFIRST(fp));
- in(ORI, rFIRST(fp), sp->arg.i & 0x3ff, rFIRST(fp));
- }
- }
- end_emit(fp);
-}
-
-#define MAYBE_EMIT_CONST(fp) \
-do { if ((fp)->cached_const) { \
- int saved_i_count = (fp)->saved_icount; \
- do_emit_const(fp, (fp)->cached_const); \
- (fp)->saved_icount = saved_i_count; \
- } \
-} while (0)
-
-#define EMIT_FALSE_CONST(fp) \
-do { int saved_i_count = (fp)->saved_icount; \
- (fp)->saved_icount = (fp)->cached_const->i_count; \
- dst_insn_append(fp); \
- (fp)->saved_icount = saved_i_count; \
-} while (0)
-
-static void compile_one_insn(struct func_info * const fp, struct src_insn *sp)
-{
- start_emit(fp, sp->i_count);
-
- switch (sp->op) {
- default:
- Com_Printf("VM: Unhandled opcode 0x%02x[%s]\n",
- sp->op,
- opnames[sp->op] ? opnames[sp->op] : "UNKNOWN");
- DIE("Unsupported opcode");
- break;
-
- case OP_ENTER: {
- int stack = SL(64, 128);
-
- if (fp->need_float_tmp)
- stack += 16;
-
- in(SAVEI, O6, -stack, O6);
- if (!SIMM13_P(sp->arg.si)) {
- in(SETHI, sp->arg.i >> 10, rTMP);
- in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
- in(SUB, rPSTACK, rTMP, rPSTACK);
- } else
- in(SUBI, rPSTACK, sp->arg.si, rPSTACK);
- break;
- }
- case OP_LEAVE:
- if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
- EMIT_FALSE_CONST(fp);
- if (fp->cached_const->src1_reg_flags & REG_FLAGS_FLOAT)
- DIE("constant float in OP_LEAVE");
-
- if (!SIMM13_P(sp->arg.si)) {
- in(SETHI, sp->arg.i >> 10, rTMP);
- in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
- in(ADD, rPSTACK, rTMP, rPSTACK);
- } else
- in(ADDI, rPSTACK, sp->arg.si, rPSTACK);
- in(JMPLI, I7, 8, G0);
- in(RESTOREI, G0, fp->cached_const->arg.si, O0);
- POP_GPR(fp);
- } else {
- MAYBE_EMIT_CONST(fp);
- if (!SIMM13_P(sp->arg.si)) {
- in(SETHI, sp->arg.i >> 10, rTMP);
- in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
- in(ADD, rPSTACK, rTMP, rPSTACK);
- } else
- in(ADDI, rPSTACK, sp->arg.si, rPSTACK);
- if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
- in(STFI, O6, SL(64, 128), fFIRST(fp));
- in(LDUWI, O6, SL(64, 128), O0);
- in(JMPLI, I7, 8, G0);
- in(RESTORE, O0, G0, O0);
- POP_FPR(fp);
- } else {
- in(JMPLI, I7, 8, G0);
- in(RESTORE, rFIRST(fp), G0, O0);
- POP_GPR(fp);
- }
- }
- assert(fp->gpr_pos == L0);
- assert(fp->fpr_pos == F0);
- break;
- case OP_JUMP:
- if (fp->cached_const) {
- EMIT_FALSE_CONST(fp);
- emit_jump(fp, BA, fp->cached_const->arg.i);
- } else {
- MAYBE_EMIT_CONST(fp);
- in(LDLI, rVMDATA, VM_Data_Offset(iPointers), rTMP);
- in(SLLI, rFIRST(fp), 2, rFIRST(fp));
- in(LDL, rTMP, rFIRST(fp), rTMP);
- in(JMPL, rTMP, G0, G0);
- in(NOP);
- }
- POP_GPR(fp);
- break;
- case OP_CALL:
- if (fp->cached_const) {
- EMIT_FALSE_CONST(fp);
- if (fp->cached_const->arg.si >= 0) {
- emit_jump(fp, CALL, fp->cached_const->arg.i);
- } else {
- in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
- in(LDLI, rVMDATA, VM_Data_Offset(AsmCall), O3);
- in(ORI, G0, fp->cached_const->arg.si, O0);
- in(JMPL, rTMP, G0, O7);
- in(OR, G0, rPSTACK, O1);
- }
- in(OR, G0, O0, rFIRST(fp));
- } else {
- MAYBE_EMIT_CONST(fp);
- in(SUBCCI, rFIRST(fp), 0, G0);
- in(BL, +4*7);
- in(NOP);
-
- /* normal call */
- in(LDLI, rVMDATA, VM_Data_Offset(iPointers), O5);
- in(SLLI, rFIRST(fp), 2, rFIRST(fp));
- in(LDL, O5, rFIRST(fp), rTMP);
- in(BA, +4*4);
- in(NOP);
-
- /* syscall */
- in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
- in(LDLI, rVMDATA, VM_Data_Offset(AsmCall), O3);
-
- in(OR, G0, rFIRST(fp), O0);
- in(JMPL, rTMP, G0, O7);
- in(OR, G0, rPSTACK, O1);
-
- /* return value */
- in(OR, G0, O0, rFIRST(fp));
- }
- break;
- case OP_BLOCK_COPY:
- MAYBE_EMIT_CONST(fp);
- in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
- in(LDLI, rVMDATA, VM_Data_Offset(BlockCopy), O3);
- in(OR, G0, rSECOND(fp), O0);
- in(OR, G0, rFIRST(fp), O1);
- if ((sp->arg.i & ~0x3ff) == 0) {
- in(ORI, G0, sp->arg.i & 0x3ff, O2);
- } else if ((sp->arg.i & 0x3ff) == 0) {
- in(SETHI, sp->arg.i >> 10, O2);
- } else {
- in(SETHI, sp->arg.i >> 10, O2);
- in(ORI, O2, sp->arg.i & 0x3ff, O2);
- }
- in(JMPL, rTMP, G0, O7);
- in(NOP);
- POP_GPR(fp);
- POP_GPR(fp);
- break;
-
- case OP_PUSH:
- MAYBE_EMIT_CONST(fp);
- if (sp->dst_reg_flags & REG_FLAGS_FLOAT)
- PUSH_FPR(fp);
- else
- PUSH_GPR(fp);
- fp->force_emit = 1;
- break;
- case OP_POP:
- MAYBE_EMIT_CONST(fp);
- if (sp->src1_reg_flags & REG_FLAGS_FLOAT)
- POP_FPR(fp);
- else
- POP_GPR(fp);
- fp->force_emit = 1;
- break;
- case OP_ARG:
- MAYBE_EMIT_CONST(fp);
- in(ADDI, rPSTACK, sp->arg.b, rTMP);
- if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
- in(STF, rDATABASE, rTMP, fFIRST(fp));
- POP_FPR(fp);
- } else {
- in(STW, rDATABASE, rTMP, rFIRST(fp));
- POP_GPR(fp);
- }
- break;
- case OP_IGNORE:
- MAYBE_EMIT_CONST(fp);
- in(NOP);
- break;
- case OP_BREAK:
- MAYBE_EMIT_CONST(fp);
- in(TA, 0x5);
- break;
- case OP_LOCAL:
- MAYBE_EMIT_CONST(fp);
- PUSH_GPR(fp);
- if (!SIMM13_P(sp->arg.i)) {
- in(SETHI, sp->arg.i >> 10, rTMP);
- in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
- in(ADD, rPSTACK, rTMP, rFIRST(fp));
- } else
- in(ADDI, rPSTACK, sp->arg.i, rFIRST(fp));
- break;
- case OP_CONST:
- MAYBE_EMIT_CONST(fp);
- break;
- case OP_LOAD4:
- MAYBE_EMIT_CONST(fp);
- in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
- if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
- PUSH_FPR(fp);
- in(LDF, rFIRST(fp), rDATABASE, fFIRST(fp));
- POP_GPR(fp);
- } else {
- in(LDUW, rFIRST(fp), rDATABASE, rFIRST(fp));
- }
- break;
- case OP_LOAD2:
- MAYBE_EMIT_CONST(fp);
- in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
- in(LDUH, rFIRST(fp), rDATABASE, rFIRST(fp));
- break;
- case OP_LOAD1:
- MAYBE_EMIT_CONST(fp);
- in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
- in(LDUB, rFIRST(fp), rDATABASE, rFIRST(fp));
- break;
- case OP_STORE4:
- MAYBE_EMIT_CONST(fp);
- if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
- in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
- in(STF, rFIRST(fp), rDATABASE, fFIRST(fp));
- POP_FPR(fp);
- } else {
- in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
- in(STW, rSECOND(fp), rDATABASE, rFIRST(fp));
- POP_GPR(fp);
- }
- POP_GPR(fp);
- break;
- case OP_STORE2:
- MAYBE_EMIT_CONST(fp);
- in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
- in(STH, rSECOND(fp), rDATABASE, rFIRST(fp));
- POP_GPR(fp);
- POP_GPR(fp);
- break;
- case OP_STORE1:
- MAYBE_EMIT_CONST(fp);
- in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
- in(STB, rSECOND(fp), rDATABASE, rFIRST(fp));
- POP_GPR(fp);
- POP_GPR(fp);
- break;
- case OP_EQ:
- case OP_NE:
- case OP_LTI:
- case OP_GEI:
- case OP_GTI:
- case OP_LEI:
- case OP_LTU:
- case OP_GEU:
- case OP_GTU:
- case OP_LEU: {
- enum sparc_iname iname = BA;
-
- if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
- EMIT_FALSE_CONST(fp);
- in(SUBCCI, rSECOND(fp), fp->cached_const->arg.si, G0);
- } else {
- MAYBE_EMIT_CONST(fp);
- in(SUBCC, rSECOND(fp), rFIRST(fp), G0);
- }
- switch(sp->op) {
- case OP_EQ: iname = BE; break;
- case OP_NE: iname = BNE; break;
- case OP_LTI: iname = BL; break;
- case OP_GEI: iname = BGE; break;
- case OP_GTI: iname = BG; break;
- case OP_LEI: iname = BLE; break;
- case OP_LTU: iname = BCS; break;
- case OP_GEU: iname = BCC; break;
- case OP_GTU: iname = BGU; break;
- case OP_LEU: iname = BLEU; break;
- }
- emit_jump(fp, iname, sp->arg.i);
- POP_GPR(fp);
- POP_GPR(fp);
- break;
- }
-
- case OP_SEX8:
- MAYBE_EMIT_CONST(fp);
- in(SLLI, rFIRST(fp), 24, rFIRST(fp));
- in(SRAI, rFIRST(fp), 24, rFIRST(fp));
- break;
- case OP_SEX16:
- MAYBE_EMIT_CONST(fp);
- in(SLLI, rFIRST(fp), 16, rFIRST(fp));
- in(SRAI, rFIRST(fp), 16, rFIRST(fp));
- break;
- case OP_NEGI:
- MAYBE_EMIT_CONST(fp);
- in(SUB, G0, rFIRST(fp), rFIRST(fp));
- break;
- case OP_ADD:
- if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
- EMIT_FALSE_CONST(fp);
- in(ADDI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
- } else {
- MAYBE_EMIT_CONST(fp);
- in(ADD, rSECOND(fp), rFIRST(fp), rSECOND(fp));
- }
- POP_GPR(fp);
- break;
- case OP_SUB:
- if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
- EMIT_FALSE_CONST(fp);
- in(SUBI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
- } else {
- MAYBE_EMIT_CONST(fp);
- in(SUB, rSECOND(fp), rFIRST(fp), rSECOND(fp));
- }
- POP_GPR(fp);
- break;
- case OP_DIVI:
- MAYBE_EMIT_CONST(fp);
- in(SRAI, rSECOND(fp), 31, rTMP);
- in(WRI, rTMP, 0, Y_REG);
- in(SDIV, rSECOND(fp), rFIRST(fp), rSECOND(fp));
- POP_GPR(fp);
- break;
- case OP_DIVU:
- MAYBE_EMIT_CONST(fp);
- in(WRI, G0, 0, Y_REG);
- in(UDIV, rSECOND(fp), rFIRST(fp), rSECOND(fp));
- POP_GPR(fp);
- break;
- case OP_MODI:
- MAYBE_EMIT_CONST(fp);
- in(SRAI, rSECOND(fp), 31, rTMP);
- in(WRI, rTMP, 0, Y_REG);
- in(SDIV, rSECOND(fp), rFIRST(fp), rTMP);
- in(SMUL, rTMP, rFIRST(fp), rTMP);
- in(SUB, rSECOND(fp), rTMP, rSECOND(fp));
- POP_GPR(fp);
- break;
- case OP_MODU:
- MAYBE_EMIT_CONST(fp);
- in(WRI, G0, 0, Y_REG);
- in(UDIV, rSECOND(fp), rFIRST(fp), rTMP);
- in(SMUL, rTMP, rFIRST(fp), rTMP);
- in(SUB, rSECOND(fp), rTMP, rSECOND(fp));
- POP_GPR(fp);
- break;
- case OP_MULI:
- MAYBE_EMIT_CONST(fp);
- in(SMUL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
- POP_GPR(fp);
- break;
- case OP_MULU:
- MAYBE_EMIT_CONST(fp);
- in(UMUL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
- POP_GPR(fp);
- break;
- case OP_BAND:
- MAYBE_EMIT_CONST(fp);
- in(AND, rSECOND(fp), rFIRST(fp), rSECOND(fp));
- POP_GPR(fp);
- break;
- case OP_BOR:
- MAYBE_EMIT_CONST(fp);
- in(OR, rSECOND(fp), rFIRST(fp), rSECOND(fp));
- POP_GPR(fp);
- break;
- case OP_BXOR:
- MAYBE_EMIT_CONST(fp);
- in(XOR, rSECOND(fp), rFIRST(fp), rSECOND(fp));
- POP_GPR(fp);
- break;
- case OP_BCOM:
- MAYBE_EMIT_CONST(fp);
- in(XNOR, rFIRST(fp), G0, rFIRST(fp));
- break;
- case OP_LSH:
- if (fp->cached_const) {
- EMIT_FALSE_CONST(fp);
- in(SLLI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
- } else {
- MAYBE_EMIT_CONST(fp);
- in(SLL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
- }
- POP_GPR(fp);
- break;
- case OP_RSHI:
- if (fp->cached_const) {
- EMIT_FALSE_CONST(fp);
- in(SRAI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
- } else {
- MAYBE_EMIT_CONST(fp);
- in(SRA, rSECOND(fp), rFIRST(fp), rSECOND(fp));
- }
- POP_GPR(fp);
- break;
- case OP_RSHU:
- if (fp->cached_const) {
- EMIT_FALSE_CONST(fp);
- in(SRLI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
- } else {
- MAYBE_EMIT_CONST(fp);
- in(SRL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
- }
- POP_GPR(fp);
- break;
-
- case OP_NEGF:
- MAYBE_EMIT_CONST(fp);
- in(FNEG, fFIRST(fp), fFIRST(fp));
- break;
- case OP_ADDF:
- MAYBE_EMIT_CONST(fp);
- in(FADD, fSECOND(fp), fFIRST(fp), fSECOND(fp));
- POP_FPR(fp);
- break;
- case OP_SUBF:
- MAYBE_EMIT_CONST(fp);
- in(FSUB, fSECOND(fp), fFIRST(fp), fSECOND(fp));
- POP_FPR(fp);
- break;
- case OP_DIVF:
- MAYBE_EMIT_CONST(fp);
- in(FDIV, fSECOND(fp), fFIRST(fp), fSECOND(fp));
- POP_FPR(fp);
- break;
- case OP_MULF:
- MAYBE_EMIT_CONST(fp);
- in(FMUL, fSECOND(fp), fFIRST(fp), fSECOND(fp));
- POP_FPR(fp);
- break;
-
- case OP_EQF:
- case OP_NEF:
- case OP_LTF:
- case OP_GEF:
- case OP_GTF:
- case OP_LEF: {
- enum sparc_iname iname = FBE;
-
- MAYBE_EMIT_CONST(fp);
- in(FCMP, fSECOND(fp), fFIRST(fp));
- switch(sp->op) {
- case OP_EQF: iname = FBE; break;
- case OP_NEF: iname = FBNE; break;
- case OP_LTF: iname = FBL; break;
- case OP_GEF: iname = FBGE; break;
- case OP_GTF: iname = FBG; break;
- case OP_LEF: iname = FBLE; break;
- }
- emit_jump(fp, iname, sp->arg.i);
- POP_FPR(fp);
- POP_FPR(fp);
- break;
- }
- case OP_CVIF:
- MAYBE_EMIT_CONST(fp);
- PUSH_FPR(fp);
- in(STWI, O6, SL(64, 128), rFIRST(fp));
- in(LDFI, O6, SL(64, 128), fFIRST(fp));
- in(FITOS, fFIRST(fp), fFIRST(fp));
- POP_GPR(fp);
- break;
- case OP_CVFI:
- MAYBE_EMIT_CONST(fp);
- PUSH_GPR(fp);
- in(FSTOI, fFIRST(fp), fFIRST(fp));
- in(STFI, O6, SL(64, 128), fFIRST(fp));
- in(LDUWI, O6, SL(64, 128), rFIRST(fp));
- POP_FPR(fp);
- break;
- }
- if (sp->op != OP_CONST) {
- fp->cached_const = NULL;
- end_emit(fp);
- } else {
- fp->cached_const = sp;
- if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
- PUSH_FPR(fp);
- } else {
- PUSH_GPR(fp);
- }
- }
- end_emit(fp);
-}
-
-static void free_source_insns(struct func_info * const fp)
-{
- struct src_insn *sp = fp->first->next;
-
- while (sp) {
- struct src_insn *next = sp->next;
- Z_Free(sp);
- sp = next;
- }
-}
-
-static void compile_function(struct func_info * const fp)
-{
- struct src_insn *sp;
-
- analyze_function(fp);
-
- fp->gpr_pos = L0;
- fp->fpr_pos = F0;
- fp->insn_index = 0;
-
- fp->stack_space = SL(64, 128);
- fp->cached_const = NULL;
-
- sp = fp->first;
- while ((sp = sp->next) != NULL)
- compile_one_insn(fp, sp);
-
- free_source_insns(fp);
-}
-
-/* We have two thunks for sparc. The first is for the entry into
- * the VM, where setup the fixed global registers. The second is
- * for calling out to C code from the VM, where we need to preserve
- * those fixed globals across the call.
- */
-static void emit_vm_thunk(struct func_info * const fp)
-{
- /* int vm_thunk(void *vmdata, int programstack, void *database, int datamask) */
- start_emit(fp, THUNK_ICOUNT);
-
- in(OR, G0, O0, rVMDATA);
- in(OR, G0, O1, rPSTACK);
- in(OR, G0, O2, rDATABASE);
- in(BA, +4*17);
- in(OR, G0, O3, rDATAMASK);
-
- /* int call_thunk(int arg0, int arg1, int arg2, int (*func)(int int int)) */
-#define CALL_THUNK_INSN_OFFSET 5
- in(SAVEI, O6, -SL(64, 128), O6);
-
- in(OR, G0, rVMDATA, L0);
- in(OR, G0, rPSTACK, L1);
- in(OR, G0, rDATABASE, L2);
- in(OR, G0, rDATAMASK, L3);
-
- in(OR, G0, I0, O0);
- in(OR, G0, I1, O1);
- in(JMPL, I3, G0, O7);
- in(OR, G0, I2, O2);
-
- in(OR, G0, L0, rVMDATA);
- in(OR, G0, L1, rPSTACK);
- in(OR, G0, L2, rDATABASE);
- in(OR, G0, L3, rDATAMASK);
-
- in(JMPLI, I7, 8, G0);
- in(RESTORE, O0, G0, O0);
-
- end_emit(fp);
-}
-
-static void sparc_compute_code(vm_t *vm, struct func_info * const fp)
-{
- struct dst_insn *dp = fp->dst_first;
- unsigned int *code_now, *code_begin;
- unsigned char *data_and_code;
- unsigned int code_length;
- int code_insns = 0, off;
- struct data_hunk *dhp;
- struct jump_insn *jp;
- vm_data_t *data;
-
- while (dp) {
- code_insns += dp->length;
- dp = dp->next;
- }
-
- code_length = (sizeof(vm_data_t) +
- (fp->data_num * sizeof(unsigned int)) +
- (code_insns * sizeof(unsigned int)));
-
- data_and_code = mmap(NULL, code_length, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS, -1, 0);
- if (!data_and_code)
- DIE("Not enough memory");
-
- code_now = code_begin = (unsigned int *)
- (data_and_code + VM_Data_Offset(data[fp->data_num]));
-
- dp = fp->dst_first;
- while (dp) {
- int i_count = dp->i_count;
-
- if (i_count != THUNK_ICOUNT) {
- if (!fp->dst_by_i_count[i_count])
- fp->dst_by_i_count[i_count] = (void *) code_now;
- }
- if (!dp->jump) {
- memcpy(code_now, &dp->code[0], dp->length * sizeof(unsigned int));
- code_now += dp->length;
- } else {
- int i;
-
- dp->jump->parent = (void *) code_now;
-
- for (i = 0; i < dp->length; i++)
- code_now[i] = SPARC_NOP;
- code_now += dp->length;
- }
-
- dp = dp->next;
- }
-
- jp = fp->jump_first;
- while (jp) {
- unsigned int *from = (void *) jp->parent;
- unsigned int *to = (void *) fp->dst_by_i_count[jp->jump_dest_insn];
- signed int disp = (to - from);
-
- *from = IN(jp->jump_iname, disp << 2);
-
- jp = jp->next;
- }
-
- vm->codeBase = data_and_code;
- vm->codeLength = code_length;
-
- data = (vm_data_t *) data_and_code;
- data->CallThunk = code_begin + CALL_THUNK_INSN_OFFSET;
- data->AsmCall = asmcall;
- data->BlockCopy = blockcopy;
- data->iPointers = (unsigned int *) vm->instructionPointers;
- data->dataLength = VM_Data_Offset(data[fp->data_num]);
- data->codeLength = (code_now - code_begin) * sizeof(unsigned int);
-
-#if 0
- {
- unsigned int *insn = code_begin;
- int i;
-
- Com_Printf("INSN DUMP\n");
- for (i = 0; i < data->codeLength / 4; i+= 8) {
- Com_Printf("\t.word\t0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
- insn[i + 0], insn[i + 1],
- insn[i + 2], insn[i + 3],
- insn[i + 4], insn[i + 5],
- insn[i + 6], insn[i + 7]);
- }
- }
-#endif
-
- dhp = fp->data_first;
- off = 0;
- while (dhp) {
- struct data_hunk *next = dhp->next;
- int i;
-
- for (i = 0; i < dhp->count; i++)
- data->data[off + i] = dhp->data[i];
-
- off += dhp->count;
-
- Z_Free(dhp);
-
- dhp = next;
- }
- fp->data_first = NULL;
- fp->data_num = 0;
-
- dp = fp->dst_first;
- while (dp) {
- struct dst_insn *next = dp->next;
- if (dp->jump)
- Z_Free(dp->jump);
- Z_Free(dp);
- dp = next;
- }
- fp->dst_first = fp->dst_last = NULL;
-}
-
-void VM_Compile(vm_t *vm, vmHeader_t *header)
-{
- struct func_info fi;
- unsigned char *code;
- int i_count, pc, i;
-
- memset(&fi, 0, sizeof(fi));
-
- fi.first = Z_Malloc(sizeof(struct src_insn));
- fi.first->next = NULL;
-
-#ifdef __arch64__
- Z_Free(vm->instructionPointers);
- vm->instructionPointers = Z_Malloc(header->instructionCount *
- sizeof(void *));
-#endif
-
- fi.dst_by_i_count = (struct dst_insn **) vm->instructionPointers;
- memset(fi.dst_by_i_count, 0, header->instructionCount * sizeof(void *));
-
- vm->compiled = qfalse;
-
- emit_vm_thunk(&fi);
-
- code = (unsigned char *) header + header->codeOffset;
- pc = 0;
-
- for (i_count = 0; i_count < header->instructionCount; i_count++) {
- unsigned char opi, op = code[pc++];
- struct src_insn *sp;
-
- if (op == OP_CALL || op == OP_BLOCK_COPY)
- fi.has_call = 1;
- opi = vm_opInfo[op];
- if (op == OP_CVIF || op == OP_CVFI ||
- (op == OP_LEAVE && (opi & opArgF)))
- fi.need_float_tmp = 1;
-
- if (op == OP_ENTER) {
- if (fi.first->next)
- compile_function(&fi);
- fi.first->next = NULL;
- fi.last = fi.first;
- fi.has_call = fi.need_float_tmp = 0;
- }
-
- sp = Z_Malloc(sizeof(*sp));
- sp->op = op;
- sp->i_count = i_count;
- sp->arg.i = 0;
- sp->next = NULL;
-
- if (vm_opInfo[op] & opImm4) {
- union {
- unsigned char b[4];
- unsigned int i;
- } c = { { code[ pc + 3 ], code[ pc + 2 ],
- code[ pc + 1 ], code[ pc + 0 ] }, };
-
- sp->arg.i = c.i;
- pc += 4;
- } else if (vm_opInfo[op] & opImm1) {
- sp->arg.b = code[pc++];
- }
-
- fi.last->next = sp;
- fi.last = sp;
- }
- compile_function(&fi);
-
- Z_Free(fi.first);
-
- memset(fi.dst_by_i_count, 0, header->instructionCount * sizeof(void *));
- sparc_compute_code(vm, &fi);
-
- for (i = 0; i < header->instructionCount; i++) {
- if (!fi.dst_by_i_count[i]) {
- Com_Printf(S_COLOR_RED "Pointer %d not initialized !\n", i);
- DIE("sparc JIT bug");
- }
- }
-
- if (mprotect(vm->codeBase, vm->codeLength, PROT_READ|PROT_EXEC)) {
- VM_Destroy_Compiled(vm);
- DIE("mprotect failed");
- }
-
- vm->destroy = VM_Destroy_Compiled;
- vm->compiled = qtrue;
-}
-
-int VM_CallCompiled(vm_t *vm, int *args)
-{
- vm_data_t *vm_dataAndCode = (void *) vm->codeBase;
- int programStack = vm->programStack;
- int stackOnEntry = programStack;
- byte *image = vm->dataBase;
- int *argPointer;
- int retVal;
-
- currentVM = vm;
-
- vm->currentlyInterpreting = qtrue;
-
- programStack -= 48;
- argPointer = (int *)&image[ programStack + 8 ];
- memcpy( argPointer, args, 4 * 9 );
- argPointer[-1] = 0;
- argPointer[-2] = -1;
-
- /* call generated code */
- {
- int (*entry)(void *, int, void *, int);
- entry = (void *)(vm->codeBase + vm_dataAndCode->dataLength);
- retVal = entry(vm->codeBase, programStack, vm->dataBase, vm->dataMask);
- }
-
- vm->programStack = stackOnEntry;
- vm->currentlyInterpreting = qfalse;
-
- return retVal;
-}
diff --git a/engine/code/qcommon/vm_sparc.h b/engine/code/qcommon/vm_sparc.h
deleted file mode 100644
index dbed627..0000000
--- a/engine/code/qcommon/vm_sparc.h
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef VM_SPARC_H
-#define VM_SPARC_H
-
-/* integer regs */
-#define G0 0
-#define G1 1
-#define G2 2
-#define G3 3
-#define G4 4
-#define G5 5
-#define G6 6
-#define G7 7
-#define O0 8
-#define O1 9
-#define O2 10
-#define O3 11
-#define O4 12
-#define O5 13
-#define O6 14
-#define O7 15
-#define L0 16
-#define L1 17
-#define L2 18
-#define L3 19
-#define L4 20
-#define L5 21
-#define L6 22
-#define L7 23
-#define I0 24
-#define I1 25
-#define I2 26
-#define I3 27
-#define I4 28
-#define I5 29
-#define I6 30
-#define I7 31
-
-/* float regs */
-#define F0 0
-#define F1 1
-#define F2 2
-#define F3 3
-#define F4 4
-#define F5 5
-#define F6 6
-#define F7 7
-#define F8 8
-#define F9 9
-#define F10 10
-#define F11 11
-#define F12 12
-#define F13 13
-#define F14 14
-#define F15 15
-#define F16 16
-#define F17 17
-#define F18 18
-#define F19 19
-#define F20 20
-#define F21 21
-#define F22 22
-#define F23 23
-#define F24 24
-#define F25 25
-#define F26 26
-#define F27 27
-#define F28 28
-#define F29 29
-#define F30 30
-#define F31 31
-
-/* state registers */
-#define Y_REG 0
-#define CCR_REG 2
-#define ASI_REG 3
-#define FPRS_REG 6
-
-#endif
diff --git a/engine/code/qcommon/vm_x86.c b/engine/code/qcommon/vm_x86.c
deleted file mode 100644
index 00b5f54..0000000
--- a/engine/code/qcommon/vm_x86.c
+++ /dev/null
@@ -1,1235 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// vm_x86.c -- load time compiler and execution environment for x86
-
-#include "vm_local.h"
-#ifdef _WIN32
-#include <windows.h>
-#endif
-
-#ifdef __FreeBSD__
-#include <sys/types.h>
-#endif
-
-#ifndef _WIN32
-#include <sys/mman.h> // for PROT_ stuff
-#endif
-
-/* need this on NX enabled systems (i386 with PAE kernel or
- * noexec32=on x86_64) */
-#ifdef __linux__
-#define VM_X86_MMAP
-#endif
-
-static void VM_Destroy_Compiled(vm_t* self);
-
-/*
-
- eax scratch
- ebx scratch
- ecx scratch (required for shifts)
- edx scratch (required for divisions)
- esi program stack
- edi opstack
-
-*/
-
-static byte *buf = NULL;
-static byte *jused = NULL;
-static int compiledOfs = 0;
-static byte *code = NULL;
-static int pc = 0;
-
-static int *instructionPointers = NULL;
-
-#define FTOL_PTR
-
-#ifdef _MSC_VER
-
-#if defined( FTOL_PTR )
-int _ftol( float );
-static int ftolPtr = (int)_ftol;
-#endif
-
-#else // _MSC_VER
-
-#if defined( FTOL_PTR )
-
-int qftol( void );
-int qftol027F( void );
-int qftol037F( void );
-int qftol0E7F( void );
-int qftol0F7F( void );
-
-
-static int ftolPtr = (int)qftol0F7F;
-#endif // FTOL_PTR
-
-#endif
-
-void AsmCall(void);
-static void (*const asmCallPtr)(void) = AsmCall;
-
-
-static int callMask = 0;
-
-static int instruction, pass;
-static int lastConst = 0;
-static int oc0, oc1, pop0, pop1;
-
-typedef enum
-{
- LAST_COMMAND_NONE = 0,
- LAST_COMMAND_MOV_EDI_EAX,
- LAST_COMMAND_SUB_DI_4,
- LAST_COMMAND_SUB_DI_8,
-} ELastCommand;
-
-static ELastCommand LastCommand;
-
-/*
-=================
-AsmCall
-=================
-*/
-#ifdef _MSC_VER
-__declspec( naked ) void AsmCall( void ) {
-int programStack;
-int *opStack;
-int syscallNum;
-vm_t* savedVM;
-
-__asm {
- mov eax, dword ptr [edi]
- sub edi, 4
- test eax,eax
- jl systemCall
- // calling another vm function
- shl eax,2
- add eax, dword ptr [instructionPointers]
- call dword ptr [eax]
- mov eax, dword ptr [edi]
- and eax, [callMask]
- ret
-systemCall:
-
- // convert negative num to system call number
- // and store right before the first arg
- not eax
-
- push ebp
- mov ebp, esp
- sub esp, __LOCAL_SIZE
-
- mov dword ptr syscallNum, eax // so C code can get at it
- mov dword ptr programStack, esi // so C code can get at it
- mov dword ptr opStack, edi
-
- push ecx
- push esi // we may call recursively, so the
- push edi // statics aren't guaranteed to be around
-}
-
- savedVM = currentVM;
-
- // save the stack to allow recursive VM entry
- currentVM->programStack = programStack - 4;
- *(int *)((byte *)currentVM->dataBase + programStack + 4) = syscallNum;
-//VM_LogSyscalls( (int *)((byte *)currentVM->dataBase + programStack + 4) );
- *(opStack+1) = currentVM->systemCall( (int *)((byte *)currentVM->dataBase + programStack + 4) );
-
- currentVM = savedVM;
-
-_asm {
- pop edi
- pop esi
- pop ecx
- add edi, 4 // we added the return value
-
- mov esp, ebp
- pop ebp
-
- ret
-}
-
-}
-
-#else //!_MSC_VER
-
-#if defined(__MINGW32__) || defined(MACOS_X) // _ is prepended to compiled symbols
-#define CMANGVAR(sym) "_"#sym
-#define CMANGFUNC(sym) "_"#sym
-#elif defined(__ICC) && (__ICC >= 1000)
-#define CMANGVAR(sym) #sym".0"
-#define CMANGFUNC(sym) #sym
-#else
-#define CMANGVAR(sym) #sym
-#define CMANGFUNC(sym) #sym
-#endif
-
-static void __attribute__((cdecl, used)) CallAsmCall(int const syscallNum,
- int const programStack, int* const opStack)
-{
- vm_t *const vm = currentVM;
- intptr_t *const data = (intptr_t*)(vm->dataBase + programStack + 4);
-
- // save the stack to allow recursive VM entry
- vm->programStack = programStack - 4;
- *data = syscallNum;
- opStack[1] = vm->systemCall(data);
-
- currentVM = vm;
-}
-
-__asm__(
- ".text\n\t"
- ".p2align 4,,15\n\t"
-#if defined __ELF__
- ".type " CMANGFUNC(AsmCall) ", @function\n"
-#endif
- CMANGFUNC(AsmCall) ":\n\t"
- "movl (%edi), %eax\n\t"
- "subl $4, %edi\n\t"
- "testl %eax, %eax\n\t"
- "jl 0f\n\t"
- "shll $2, %eax\n\t"
- "addl " CMANGVAR(instructionPointers) ", %eax\n\t"
- "call *(%eax)\n\t"
- "movl (%edi), %eax\n\t"
- "andl " CMANGVAR(callMask) ", %eax\n\t"
- "ret\n"
- "0:\n\t" // system call
- "notl %eax\n\t"
- "pushl %ebp\n\t"
- "movl %esp, %ebp\n\t"
- "andl $-16, %esp\n\t" // align the stack so engine can use sse
- "pushl %ecx\n\t"
- "pushl %edi\n\t" // opStack
- "pushl %esi\n\t" // programStack
- "pushl %eax\n\t" // syscallNum
- "call " CMANGFUNC(CallAsmCall) "\n\t"
- "addl $12, %esp\n\t"
- "popl %ecx\n\t"
- "movl %ebp, %esp\n\t"
- "popl %ebp\n\t"
- "addl $4, %edi\n\t"
- "ret\n\t"
-#if defined __ELF__
- ".size " CMANGFUNC(AsmCall)", .-" CMANGFUNC(AsmCall)
-#endif
-);
-
-#endif
-
-static int Constant4( void ) {
- int v;
-
- v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24);
- pc += 4;
- return v;
-}
-
-static int Constant1( void ) {
- int v;
-
- v = code[pc];
- pc += 1;
- return v;
-}
-
-static void Emit1( int v )
-{
- buf[ compiledOfs ] = v;
- compiledOfs++;
-
- LastCommand = LAST_COMMAND_NONE;
-}
-
-#if 0
-static void Emit2( int v ) {
- Emit1( v & 255 );
- Emit1( ( v >> 8 ) & 255 );
-}
-#endif
-
-static void Emit4( int v ) {
- Emit1( v & 255 );
- Emit1( ( v >> 8 ) & 255 );
- Emit1( ( v >> 16 ) & 255 );
- Emit1( ( v >> 24 ) & 255 );
-}
-
-static int Hex( int c ) {
- if ( c >= 'a' && c <= 'f' ) {
- return 10 + c - 'a';
- }
- if ( c >= 'A' && c <= 'F' ) {
- return 10 + c - 'A';
- }
- if ( c >= '0' && c <= '9' ) {
- return c - '0';
- }
-
- Com_Error( ERR_DROP, "Hex: bad char '%c'", c );
-
- return 0;
-}
-static void EmitString( const char *string ) {
- int c1, c2;
- int v;
-
- while ( 1 ) {
- c1 = string[0];
- c2 = string[1];
-
- v = ( Hex( c1 ) << 4 ) | Hex( c2 );
- Emit1( v );
-
- if ( !string[2] ) {
- break;
- }
- string += 3;
- }
-}
-
-
-
-static void EmitCommand(ELastCommand command)
-{
- switch(command)
- {
- case LAST_COMMAND_MOV_EDI_EAX:
- EmitString( "89 07" ); // mov dword ptr [edi], eax
- break;
-
- case LAST_COMMAND_SUB_DI_4:
- EmitString( "83 EF 04" ); // sub edi, 4
- break;
-
- case LAST_COMMAND_SUB_DI_8:
- EmitString( "83 EF 08" ); // sub edi, 8
- break;
- default:
- break;
- }
- LastCommand = command;
-}
-
-static void EmitAddEDI4(vm_t *vm) {
- if (LastCommand == LAST_COMMAND_SUB_DI_4 && jused[instruction-1] == 0)
- { // sub di,4
- compiledOfs -= 3;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- return;
- }
- if (LastCommand == LAST_COMMAND_SUB_DI_8 && jused[instruction-1] == 0)
- { // sub di,8
- compiledOfs -= 3;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- EmitString( "83 EF 04" ); // sub edi,4
- return;
- }
- EmitString( "83 C7 04" ); // add edi,4
-}
-
-static void EmitMovEAXEDI(vm_t *vm) {
- if (LastCommand == LAST_COMMAND_MOV_EDI_EAX)
- { // mov [edi], eax
- compiledOfs -= 2;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- return;
- }
- if (pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU ||
- pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 )
- {
- return;
- }
- if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 )
- { // mov edi, 0x123456
- compiledOfs -= 6;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- EmitString( "B8" ); // mov eax, 0x12345678
- Emit4( lastConst );
- return;
- }
- EmitString( "8B 07" ); // mov eax, dword ptr [edi]
-}
-
-qboolean EmitMovEBXEDI(vm_t *vm, int andit) {
- if (LastCommand == LAST_COMMAND_MOV_EDI_EAX)
- { // mov [edi], eax
- compiledOfs -= 2;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- EmitString( "8B D8"); // mov bx, eax
- return qfalse;
- }
- if (pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU ||
- pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 )
- {
- EmitString( "8B D8"); // mov bx, eax
- return qfalse;
- }
- if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 )
- { // mov edi, 0x123456
- compiledOfs -= 6;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- EmitString( "BB" ); // mov ebx, 0x12345678
- if (andit) {
- Emit4( lastConst & andit );
- } else {
- Emit4( lastConst );
- }
- return qtrue;
- }
-
- EmitString( "8B 1F" ); // mov ebx, dword ptr [edi]
- return qfalse;
-}
-
-#define JUSED(x) \
- do { \
- if (x < 0 || x >= jusedSize) { \
- Com_Error( ERR_DROP, \
- "VM_CompileX86: jump target out of range at offset %d", pc ); \
- } \
- jused[x] = 1; \
- } while(0)
-
-/*
-=================
-VM_Compile
-=================
-*/
-void VM_Compile( vm_t *vm, vmHeader_t *header ) {
- int op;
- int maxLength;
- int v;
- int i;
- qboolean opt;
- int jusedSize = header->instructionCount + 2;
-
- // allocate a very large temp buffer, we will shrink it later
- maxLength = header->codeLength * 8;
- buf = Z_Malloc( maxLength );
- jused = Z_Malloc(jusedSize);
-
- Com_Memset(jused, 0, jusedSize);
-
- // ensure that the optimisation pass knows about all the jump
- // table targets
- for( i = 0; i < vm->numJumpTableTargets; i++ ) {
- jused[ *(int *)(vm->jumpTableTargets + ( i * sizeof( int ) ) ) ] = 1;
- }
-
- for(pass=0;pass<2;pass++) {
- oc0 = -23423;
- oc1 = -234354;
- pop0 = -43435;
- pop1 = -545455;
-
- // translate all instructions
- pc = 0;
- instruction = 0;
- code = (byte *)header + header->codeOffset;
- compiledOfs = 0;
-
- LastCommand = LAST_COMMAND_NONE;
-
- while ( instruction < header->instructionCount ) {
- if ( compiledOfs > maxLength - 16 ) {
- Com_Error( ERR_FATAL, "VM_CompileX86: maxLength exceeded" );
- }
-
- vm->instructionPointers[ instruction ] = compiledOfs;
- instruction++;
-
- if ( pc > header->codeLength ) {
- Com_Error( ERR_FATAL, "VM_CompileX86: pc > header->codeLength" );
- }
-
- op = code[ pc ];
- pc++;
- switch ( op ) {
- case 0:
- break;
- case OP_BREAK:
- EmitString( "CC" ); // int 3
- break;
- case OP_ENTER:
- EmitString( "81 EE" ); // sub esi, 0x12345678
- Emit4( Constant4() );
- break;
- case OP_CONST:
- if (code[pc+4] == OP_LOAD4) {
- EmitAddEDI4(vm);
- EmitString( "BB" ); // mov ebx, 0x12345678
- Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase);
- EmitString( "8B 03" ); // mov eax, dword ptr [ebx]
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
- pc++; // OP_LOAD4
- instruction += 1;
- break;
- }
- if (code[pc+4] == OP_LOAD2) {
- EmitAddEDI4(vm);
- EmitString( "BB" ); // mov ebx, 0x12345678
- Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase);
- EmitString( "0F B7 03" ); // movzx eax, word ptr [ebx]
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
- pc++; // OP_LOAD4
- instruction += 1;
- break;
- }
- if (code[pc+4] == OP_LOAD1) {
- EmitAddEDI4(vm);
- EmitString( "BB" ); // mov ebx, 0x12345678
- Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase);
- EmitString( "0F B6 03" ); // movzx eax, byte ptr [ebx]
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
- pc++; // OP_LOAD4
- instruction += 1;
- break;
- }
- if (code[pc+4] == OP_STORE4) {
- opt = EmitMovEBXEDI(vm, (vm->dataMask & ~3));
- EmitString( "B8" ); // mov eax, 0x12345678
- Emit4( Constant4() );
-// if (!opt) {
-// EmitString( "81 E3" ); // and ebx, 0x12345678
-// Emit4( vm->dataMask & ~3 );
-// }
- EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- pc++; // OP_STORE4
- instruction += 1;
- break;
- }
- if (code[pc+4] == OP_STORE2) {
- opt = EmitMovEBXEDI(vm, (vm->dataMask & ~1));
- EmitString( "B8" ); // mov eax, 0x12345678
- Emit4( Constant4() );
-// if (!opt) {
-// EmitString( "81 E3" ); // and ebx, 0x12345678
-// Emit4( vm->dataMask & ~1 );
-// }
- EmitString( "66 89 83" ); // mov word ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- pc++; // OP_STORE4
- instruction += 1;
- break;
- }
- if (code[pc+4] == OP_STORE1) {
- opt = EmitMovEBXEDI(vm, vm->dataMask);
- EmitString( "B8" ); // mov eax, 0x12345678
- Emit4( Constant4() );
-// if (!opt) {
-// EmitString( "81 E3" ); // and ebx, 0x12345678
-// Emit4( vm->dataMask );
-// }
- EmitString( "88 83" ); // mov byte ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- pc++; // OP_STORE4
- instruction += 1;
- break;
- }
- if (code[pc+4] == OP_ADD) {
- EmitString( "81 07" ); // add dword ptr [edi], 0x1234567
- Emit4( Constant4() );
- pc++; // OP_ADD
- instruction += 1;
- break;
- }
- if (code[pc+4] == OP_SUB) {
- EmitString( "81 2F" ); // sub dword ptr [edi], 0x1234567
- Emit4( Constant4() );
- pc++; // OP_ADD
- instruction += 1;
- break;
- }
- EmitAddEDI4(vm);
- EmitString( "C7 07" ); // mov dword ptr [edi], 0x12345678
- lastConst = Constant4();
- Emit4( lastConst );
- if (code[pc] == OP_JUMP) {
- JUSED(lastConst);
- }
- break;
- case OP_LOCAL:
- EmitAddEDI4(vm);
- EmitString( "8D 86" ); // lea eax, [0x12345678 + esi]
- oc0 = oc1;
- oc1 = Constant4();
- Emit4( oc1 );
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
- break;
- case OP_ARG:
- EmitMovEAXEDI(vm); // mov eax,dword ptr [edi]
- EmitString( "89 86" ); // mov dword ptr [esi+database],eax
- // FIXME: range check
- Emit4( Constant1() + (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_CALL:
- EmitString( "C7 86" ); // mov dword ptr [esi+database],0x12345678
- Emit4( (int)vm->dataBase );
- Emit4( pc );
- EmitString( "FF 15" ); // call asmCallPtr
- Emit4( (int)&asmCallPtr );
- break;
- case OP_PUSH:
- EmitAddEDI4(vm);
- break;
- case OP_POP:
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_LEAVE:
- v = Constant4();
- EmitString( "81 C6" ); // add esi, 0x12345678
- Emit4( v );
- EmitString( "C3" ); // ret
- break;
- case OP_LOAD4:
- if (code[pc] == OP_CONST && code[pc+5] == OP_ADD && code[pc+6] == OP_STORE4) {
- if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
- compiledOfs -= 11;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- }
- pc++; // OP_CONST
- v = Constant4();
- EmitMovEBXEDI(vm, vm->dataMask);
- if (v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
- EmitString( "FF 83"); // inc dword ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- } else {
- EmitString( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- EmitString( "05" ); // add eax, const
- Emit4( v );
- if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
- EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- } else {
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- EmitString( "8B 1F" ); // mov ebx, dword ptr [edi]
- EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- }
- }
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- pc++; // OP_ADD
- pc++; // OP_STORE
- instruction += 3;
- break;
- }
-
- if (code[pc] == OP_CONST && code[pc+5] == OP_SUB && code[pc+6] == OP_STORE4) {
- if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
- compiledOfs -= 11;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- }
- EmitMovEBXEDI(vm, vm->dataMask);
- EmitString( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- pc++; // OP_CONST
- v = Constant4();
- if (v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
- EmitString( "FF 8B"); // dec dword ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- } else {
- EmitString( "2D" ); // sub eax, const
- Emit4( v );
- if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
- EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- } else {
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- EmitString( "8B 1F" ); // mov ebx, dword ptr [edi]
- EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- }
- }
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- pc++; // OP_SUB
- pc++; // OP_STORE
- instruction += 3;
- break;
- }
-
- if (buf[compiledOfs-2] == 0x89 && buf[compiledOfs-1] == 0x07) {
- compiledOfs -= 2;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- EmitString( "8B 80"); // mov eax, dword ptr [eax + 0x1234567]
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
- break;
- }
- EmitMovEBXEDI(vm, vm->dataMask);
- EmitString( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
- break;
- case OP_LOAD2:
- EmitMovEBXEDI(vm, vm->dataMask);
- EmitString( "0F B7 83" ); // movzx eax, word ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
- break;
- case OP_LOAD1:
- EmitMovEBXEDI(vm, vm->dataMask);
- EmitString( "0F B6 83" ); // movzx eax, byte ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
- break;
- case OP_STORE4:
- EmitMovEAXEDI(vm);
- EmitString( "8B 5F FC" ); // mov ebx, dword ptr [edi-4]
-// if (pop1 != OP_CALL) {
-// EmitString( "81 E3" ); // and ebx, 0x12345678
-// Emit4( vm->dataMask & ~3 );
-// }
- EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- break;
- case OP_STORE2:
- EmitMovEAXEDI(vm);
- EmitString( "8B 5F FC" ); // mov ebx, dword ptr [edi-4]
-// EmitString( "81 E3" ); // and ebx, 0x12345678
-// Emit4( vm->dataMask & ~1 );
- EmitString( "66 89 83" ); // mov word ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- break;
- case OP_STORE1:
- EmitMovEAXEDI(vm);
- EmitString( "8B 5F FC" ); // mov ebx, dword ptr [edi-4]
-// EmitString( "81 E3" ); // and ebx, 0x12345678
-// Emit4( vm->dataMask );
- EmitString( "88 83" ); // mov byte ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- break;
-
- case OP_EQ:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
- EmitString( "75 06" ); // jne +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_NE:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
- EmitString( "74 06" ); // je +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_LTI:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
- EmitString( "7D 06" ); // jnl +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_LEI:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
- EmitString( "7F 06" ); // jnle +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_GTI:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
- EmitString( "7E 06" ); // jng +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_GEI:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
- EmitString( "7C 06" ); // jnge +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_LTU:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
- EmitString( "73 06" ); // jnb +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_LEU:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
- EmitString( "77 06" ); // jnbe +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_GTU:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
- EmitString( "76 06" ); // jna +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_GEU:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
- EmitString( "72 06" ); // jnae +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_EQF:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
- EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
- EmitString( "DF E0" ); // fnstsw ax
- EmitString( "F6 C4 40" ); // test ah,0x40
- EmitString( "74 06" ); // je +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_NEF:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
- EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
- EmitString( "DF E0" ); // fnstsw ax
- EmitString( "F6 C4 40" ); // test ah,0x40
- EmitString( "75 06" ); // jne +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_LTF:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
- EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
- EmitString( "DF E0" ); // fnstsw ax
- EmitString( "F6 C4 01" ); // test ah,0x01
- EmitString( "74 06" ); // je +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_LEF:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
- EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
- EmitString( "DF E0" ); // fnstsw ax
- EmitString( "F6 C4 41" ); // test ah,0x41
- EmitString( "74 06" ); // je +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_GTF:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
- EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
- EmitString( "DF E0" ); // fnstsw ax
- EmitString( "F6 C4 41" ); // test ah,0x41
- EmitString( "75 06" ); // jne +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_GEF:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
- EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
- EmitString( "DF E0" ); // fnstsw ax
- EmitString( "F6 C4 01" ); // test ah,0x01
- EmitString( "75 06" ); // jne +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
- case OP_NEGI:
- EmitString( "F7 1F" ); // neg dword ptr [edi]
- break;
- case OP_ADD:
- EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
- EmitString( "01 47 FC" ); // add dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_SUB:
- EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
- EmitString( "29 47 FC" ); // sub dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_DIVI:
- EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
- EmitString( "99" ); // cdq
- EmitString( "F7 3F" ); // idiv dword ptr [edi]
- EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_DIVU:
- EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
- EmitString( "33 D2" ); // xor edx, edx
- EmitString( "F7 37" ); // div dword ptr [edi]
- EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_MODI:
- EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
- EmitString( "99" ); // cdq
- EmitString( "F7 3F" ); // idiv dword ptr [edi]
- EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_MODU:
- EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
- EmitString( "33 D2" ); // xor edx, edx
- EmitString( "F7 37" ); // div dword ptr [edi]
- EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_MULI:
- EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
- EmitString( "F7 2F" ); // imul dword ptr [edi]
- EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_MULU:
- EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
- EmitString( "F7 27" ); // mul dword ptr [edi]
- EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_BAND:
- EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
- EmitString( "21 47 FC" ); // and dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_BOR:
- EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
- EmitString( "09 47 FC" ); // or dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_BXOR:
- EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
- EmitString( "31 47 FC" ); // xor dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_BCOM:
- EmitString( "F7 17" ); // not dword ptr [edi]
- break;
- case OP_LSH:
- EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
- EmitString( "D3 67 FC" ); // shl dword ptr [edi-4], cl
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_RSHI:
- EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
- EmitString( "D3 7F FC" ); // sar dword ptr [edi-4], cl
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_RSHU:
- EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
- EmitString( "D3 6F FC" ); // shr dword ptr [edi-4], cl
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_NEGF:
- EmitString( "D9 07" ); // fld dword ptr [edi]
- EmitString( "D9 E0" ); // fchs
- EmitString( "D9 1F" ); // fstp dword ptr [edi]
- break;
- case OP_ADDF:
- EmitString( "D9 47 FC" ); // fld dword ptr [edi-4]
- EmitString( "D8 07" ); // fadd dword ptr [edi]
- EmitString( "D9 5F FC" ); // fstp dword ptr [edi-4]
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- break;
- case OP_SUBF:
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- EmitString( "D9 07" ); // fld dword ptr [edi]
- EmitString( "D8 67 04" ); // fsub dword ptr [edi+4]
- EmitString( "D9 1F" ); // fstp dword ptr [edi]
- break;
- case OP_DIVF:
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- EmitString( "D9 07" ); // fld dword ptr [edi]
- EmitString( "D8 77 04" ); // fdiv dword ptr [edi+4]
- EmitString( "D9 1F" ); // fstp dword ptr [edi]
- break;
- case OP_MULF:
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- EmitString( "D9 07" ); // fld dword ptr [edi]
- EmitString( "D8 4f 04" ); // fmul dword ptr [edi+4]
- EmitString( "D9 1F" ); // fstp dword ptr [edi]
- break;
- case OP_CVIF:
- EmitString( "DB 07" ); // fild dword ptr [edi]
- EmitString( "D9 1F" ); // fstp dword ptr [edi]
- break;
- case OP_CVFI:
-#ifndef FTOL_PTR // WHENHELLISFROZENOVER
- // not IEEE complient, but simple and fast
- EmitString( "D9 07" ); // fld dword ptr [edi]
- EmitString( "DB 1F" ); // fistp dword ptr [edi]
-#else // FTOL_PTR
- // call the library conversion function
- EmitString( "D9 07" ); // fld dword ptr [edi]
- EmitString( "FF 15" ); // call ftolPtr
- Emit4( (int)&ftolPtr );
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
-#endif
- break;
- case OP_SEX8:
- EmitString( "0F BE 07" ); // movsx eax, byte ptr [edi]
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
- break;
- case OP_SEX16:
- EmitString( "0F BF 07" ); // movsx eax, word ptr [edi]
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
- break;
-
- case OP_BLOCK_COPY:
- // FIXME: range check
- EmitString( "56" ); // push esi
- EmitString( "57" ); // push edi
- EmitString( "8B 37" ); // mov esi,[edi]
- EmitString( "8B 7F FC" ); // mov edi,[edi-4]
- EmitString( "B9" ); // mov ecx,0x12345678
- Emit4( Constant4() >> 2 );
- EmitString( "B8" ); // mov eax, datamask
- Emit4( vm->dataMask );
- EmitString( "BB" ); // mov ebx, database
- Emit4( (int)vm->dataBase );
- EmitString( "23 F0" ); // and esi, eax
- EmitString( "03 F3" ); // add esi, ebx
- EmitString( "23 F8" ); // and edi, eax
- EmitString( "03 FB" ); // add edi, ebx
- EmitString( "F3 A5" ); // rep movsd
- EmitString( "5F" ); // pop edi
- EmitString( "5E" ); // pop esi
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- break;
-
- case OP_JUMP:
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- EmitString( "8B 47 04" ); // mov eax,dword ptr [edi+4]
- // FIXME: range check
- EmitString( "FF 24 85" ); // jmp dword ptr [instructionPointers + eax * 4]
- Emit4( (int)vm->instructionPointers );
- break;
- default:
- Com_Error( ERR_DROP, "VM_CompileX86: bad opcode %i at offset %i", op, pc );
- }
- pop0 = pop1;
- pop1 = op;
- }
- }
-
- // copy to an exact size buffer on the hunk
- vm->codeLength = compiledOfs;
-#ifdef VM_X86_MMAP
- vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
- if(vm->codeBase == (void*)-1)
- Com_Error(ERR_DROP, "VM_CompileX86: can't mmap memory");
-#elif _WIN32
- // allocate memory with EXECUTE permissions under windows.
- vm->codeBase = VirtualAlloc(NULL, compiledOfs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
- if(!vm->codeBase)
- Com_Error(ERR_DROP, "VM_CompileX86: VirtualAlloc failed");
-#else
- vm->codeBase = malloc(compiledOfs);
-#endif
-
- Com_Memcpy( vm->codeBase, buf, compiledOfs );
-
-#ifdef VM_X86_MMAP
- if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC))
- Com_Error(ERR_DROP, "VM_CompileX86: mprotect failed");
-#elif _WIN32
- {
- DWORD oldProtect = 0;
-
- // remove write permissions.
- if(!VirtualProtect(vm->codeBase, compiledOfs, PAGE_EXECUTE_READ, &oldProtect))
- Com_Error(ERR_DROP, "VM_CompileX86: VirtualProtect failed");
- }
-#endif
-
- Z_Free( buf );
- Z_Free( jused );
- Com_Printf( "VM file %s compiled to %i bytes of code\n", vm->name, compiledOfs );
-
- vm->destroy = VM_Destroy_Compiled;
-
- // offset all the instruction pointers for the new location
- for ( i = 0 ; i < header->instructionCount ; i++ ) {
- vm->instructionPointers[i] += (int)vm->codeBase;
- }
-}
-
-void VM_Destroy_Compiled(vm_t* self)
-{
-#ifdef VM_X86_MMAP
- munmap(self->codeBase, self->codeLength);
-#elif _WIN32
- VirtualFree(self->codeBase, 0, MEM_RELEASE);
-#else
- free(self->codeBase);
-#endif
-}
-
-/*
-==============
-VM_CallCompiled
-
-This function is called directly by the generated code
-==============
-*/
-int VM_CallCompiled( vm_t *vm, int *args ) {
- int stack[1024];
- int programCounter;
- int programStack;
- int stackOnEntry;
- byte *image;
- void *opStack;
- int *oldInstructionPointers;
-
- oldInstructionPointers = instructionPointers;
-
- currentVM = vm;
- instructionPointers = vm->instructionPointers;
-
- // interpret the code
- vm->currentlyInterpreting = qtrue;
-
- callMask = vm->dataMask;
-
- // we might be called recursively, so this might not be the very top
- programStack = vm->programStack;
- stackOnEntry = programStack;
-
- // set up the stack frame
- image = vm->dataBase;
-
- programCounter = 0;
-
- programStack -= 48;
-
- *(int *)&image[ programStack + 44] = args[9];
- *(int *)&image[ programStack + 40] = args[8];
- *(int *)&image[ programStack + 36] = args[7];
- *(int *)&image[ programStack + 32] = args[6];
- *(int *)&image[ programStack + 28] = args[5];
- *(int *)&image[ programStack + 24] = args[4];
- *(int *)&image[ programStack + 20] = args[3];
- *(int *)&image[ programStack + 16] = args[2];
- *(int *)&image[ programStack + 12] = args[1];
- *(int *)&image[ programStack + 8 ] = args[0];
- *(int *)&image[ programStack + 4 ] = 0; // return stack
- *(int *)&image[ programStack ] = -1; // will terminate the loop on return
-
- // off we go into generated code...
- opStack = &stack;
-
- {
-#ifdef _MSC_VER
- void *entryPoint = vm->codeBase;
-
- __asm {
- pushad
- mov esi, programStack
- mov edi, opStack
- call entryPoint
- mov programStack, esi
- mov opStack, edi
- popad
- }
-#else
- /* These registers are used as scratch registers and are destroyed after the
- * call. Do not use clobber, so they can be used as input for the asm. */
- unsigned eax;
- unsigned ebx;
- unsigned ecx;
- unsigned edx;
-
- __asm__ volatile(
- "call *%6"
- : "+S" (programStack), "+D" (opStack),
- "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
- : "mr" (vm->codeBase)
- : "cc", "memory"
- );
-#endif
- }
-
- if ( opStack != &stack[1] ) {
- Com_Error( ERR_DROP, "opStack corrupted in compiled code" );
- }
- if ( programStack != stackOnEntry - 48 ) {
- Com_Error( ERR_DROP, "programStack corrupted in compiled code" );
- }
-
- vm->programStack = stackOnEntry;
-
- // in case we were recursively called by another vm
- instructionPointers = oldInstructionPointers;
-
- return *(int *)opStack;
-}
diff --git a/engine/code/qcommon/vm_x86_64.c b/engine/code/qcommon/vm_x86_64.c
deleted file mode 100644
index 0efc877..0000000
--- a/engine/code/qcommon/vm_x86_64.c
+++ /dev/null
@@ -1,1047 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2005 Ludwig Nussel <ludwig.nussel at web.de>
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// vm_x86_64.c -- load time compiler and execution environment for x86-64
-
-#include "vm_local.h"
-
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <time.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdarg.h>
-
-//#define DEBUG_VM
-
-#ifdef DEBUG_VM
-#define Dfprintf(fd, args...) fprintf(fd, ##args)
-static FILE* qdasmout;
-#else
-#define Dfprintf(args...)
-#endif
-
-#define VM_X86_64_MMAP
-
-void assembler_set_output(char* buf);
-size_t assembler_get_code_size(void);
-void assembler_init(int pass);
-void assemble_line(const char* input, size_t len);
-
-static void VM_Destroy_Compiled(vm_t* self);
-
-/*
-
- |=====================|
- ^ dataMask ^- programStack rdi
- |
- +- r8
-
- eax scratch
- ebx scratch
- ecx scratch (required for shifts)
- edx scratch (required for divisions)
- rsi stack pointer (opStack)
- rdi program frame pointer (programStack)
- r8 pointer data (vm->dataBase)
- r10 start of generated code
-*/
-
-
-static long callAsmCall(long callProgramStack, long callSyscallNum)
-{
- vm_t *savedVM;
- long ret = 0x77;
- long args[11];
-// int iargs[11];
- int i;
-
-// Dfprintf(stderr, "callAsmCall(%ld, %ld)\n", callProgramStack, callSyscallNum);
-// Com_Printf("-> callAsmCall %s, level %d, num %ld\n", currentVM->name, currentVM->callLevel, callSyscallNum);
-
- savedVM = currentVM;
-
- // save the stack to allow recursive VM entry
- currentVM->programStack = callProgramStack - 4;
-
- args[0] = callSyscallNum;
-// iargs[0] = callSyscallNum;
- for(i = 0; i < 10; ++i)
- {
-// iargs[i+1] = *(int *)((byte *)currentVM->dataBase + callProgramStack + 8 + 4*i);
- args[i+1] = *(int *)((byte *)currentVM->dataBase + callProgramStack + 8 + 4*i);
- }
- ret = currentVM->systemCall(args);
-
- currentVM = savedVM;
-// Com_Printf("<- callAsmCall %s, level %d, num %ld\n", currentVM->name, currentVM->callLevel, callSyscallNum);
-
- return ret;
-}
-
-#ifdef DEBUG_VM
-static char *opnames[256] = {
- "OP_UNDEF",
-
- "OP_IGNORE",
-
- "OP_BREAK",
-
- "OP_ENTER",
- "OP_LEAVE",
- "OP_CALL",
- "OP_PUSH",
- "OP_POP",
-
- "OP_CONST",
-
- "OP_LOCAL",
-
- "OP_JUMP",
-
- //-------------------
-
- "OP_EQ",
- "OP_NE",
-
- "OP_LTI",
- "OP_LEI",
- "OP_GTI",
- "OP_GEI",
-
- "OP_LTU",
- "OP_LEU",
- "OP_GTU",
- "OP_GEU",
-
- "OP_EQF",
- "OP_NEF",
-
- "OP_LTF",
- "OP_LEF",
- "OP_GTF",
- "OP_GEF",
-
- //-------------------
-
- "OP_LOAD1",
- "OP_LOAD2",
- "OP_LOAD4",
- "OP_STORE1",
- "OP_STORE2",
- "OP_STORE4",
- "OP_ARG",
-
- "OP_BLOCK_COPY",
-
- //-------------------
-
- "OP_SEX8",
- "OP_SEX16",
-
- "OP_NEGI",
- "OP_ADD",
- "OP_SUB",
- "OP_DIVI",
- "OP_DIVU",
- "OP_MODI",
- "OP_MODU",
- "OP_MULI",
- "OP_MULU",
-
- "OP_BAND",
- "OP_BOR",
- "OP_BXOR",
- "OP_BCOM",
-
- "OP_LSH",
- "OP_RSHI",
- "OP_RSHU",
-
- "OP_NEGF",
- "OP_ADDF",
- "OP_SUBF",
- "OP_DIVF",
- "OP_MULF",
-
- "OP_CVIF",
- "OP_CVFI"
-};
-#endif // DEBUG_VM
-
-static unsigned char op_argsize[256] =
-{
- [OP_ENTER] = 4,
- [OP_LEAVE] = 4,
- [OP_CONST] = 4,
- [OP_LOCAL] = 4,
- [OP_EQ] = 4,
- [OP_NE] = 4,
- [OP_LTI] = 4,
- [OP_LEI] = 4,
- [OP_GTI] = 4,
- [OP_GEI] = 4,
- [OP_LTU] = 4,
- [OP_LEU] = 4,
- [OP_GTU] = 4,
- [OP_GEU] = 4,
- [OP_EQF] = 4,
- [OP_NEF] = 4,
- [OP_LTF] = 4,
- [OP_LEF] = 4,
- [OP_GTF] = 4,
- [OP_GEF] = 4,
- [OP_ARG] = 1,
- [OP_BLOCK_COPY] = 4,
-};
-
-void emit(const char* fmt, ...)
-{
- va_list ap;
- char line[4096];
- va_start(ap, fmt);
- Q_vsnprintf(line, sizeof(line), fmt, ap);
- va_end(ap);
- assemble_line(line, strlen(line));
-}
-
-#define CHECK_INSTR_REG(reg) \
- emit("cmpl $%u, %%"#reg, header->instructionCount); \
- emit("jb jmp_ok_i_%08x", instruction); \
- emit("movq $%lu, %%rax", (unsigned long)jmpviolation); \
- emit("callq *%%rax"); \
- emit("jmp_ok_i_%08x:", instruction);
-
-#define PREPARE_JMP(reg) \
- CHECK_INSTR_REG(reg) \
- emit("movq $%lu, %%rbx", (unsigned long)vm->instructionPointers); \
- emit("movl (%%rbx, %%rax, 4), %%eax"); \
- emit("addq %%r10, %%rax");
-
-#define CHECK_INSTR(nr) \
- do { if(nr < 0 || nr >= header->instructionCount) { \
- Com_Error( ERR_DROP, \
- "%s: jump target 0x%x out of range at offset %d", __func__, nr, pc ); \
- } } while(0)
-
-#define JMPIARG \
- CHECK_INSTR(iarg); \
- emit("movq $%lu, %%rax", vm->codeBase+vm->instructionPointers[iarg]); \
- emit("jmpq *%%rax");
-
-#define CONST_OPTIMIZE
-#ifdef CONST_OPTIMIZE
-#define MAYBE_EMIT_CONST() \
- if (got_const) \
- { \
- got_const = 0; \
- vm->instructionPointers[instruction-1] = assembler_get_code_size(); \
- emit("addq $4, %%rsi"); \
- emit("movl $%d, 0(%%rsi)", const_value); \
- }
-#else
-#define MAYBE_EMIT_CONST()
-#endif
-
-// integer compare and jump
-#define IJ(op) \
- MAYBE_EMIT_CONST(); \
- emit("subq $8, %%rsi"); \
- emit("movl 4(%%rsi), %%eax"); \
- emit("cmpl 8(%%rsi), %%eax"); \
- emit(op " i_%08x", instruction+1); \
- JMPIARG \
- neednilabel = 1;
-
-#ifdef USE_X87
-#define FJ(bits, op) \
- MAYBE_EMIT_CONST(); \
- emit("subq $8, %%rsi");\
- emit("flds 4(%%rsi)");\
- emit("fcomps 8(%%rsi)");\
- emit("fnstsw %%ax");\
- emit("testb $" #bits ", %%ah");\
- emit(op " i_%08x", instruction+1);\
- JMPIARG \
- neednilabel = 1;
-#define XJ(x)
-#else
-#define FJ(x, y)
-#define XJ(op) \
- MAYBE_EMIT_CONST(); \
- emit("subq $8, %%rsi");\
- emit("movss 4(%%rsi), %%xmm0");\
- emit("ucomiss 8(%%rsi), %%xmm0");\
- emit("jp i_%08x", instruction+1);\
- emit(op " i_%08x", instruction+1);\
- JMPIARG \
- neednilabel = 1;
-#endif
-
-#define SIMPLE(op) \
- MAYBE_EMIT_CONST(); \
- emit("subq $4, %%rsi"); \
- emit("movl 4(%%rsi), %%eax"); \
- emit(op " %%eax, 0(%%rsi)");
-
-#ifdef USE_X87
-#define FSIMPLE(op) \
- MAYBE_EMIT_CONST(); \
- emit("subq $4, %%rsi"); \
- emit("flds 0(%%rsi)"); \
- emit(op " 4(%%rsi)"); \
- emit("fstps 0(%%rsi)");
-#define XSIMPLE(op)
-#else
-#define FSIMPLE(op)
-#define XSIMPLE(op) \
- MAYBE_EMIT_CONST(); \
- emit("subq $4, %%rsi"); \
- emit("movss 0(%%rsi), %%xmm0"); \
- emit(op " 4(%%rsi), %%xmm0"); \
- emit("movss %%xmm0, 0(%%rsi)");
-#endif
-
-#define SHIFT(op) \
- MAYBE_EMIT_CONST(); \
- emit("subq $4, %%rsi"); \
- emit("movl 4(%%rsi), %%ecx"); \
- emit("movl 0(%%rsi), %%eax"); \
- emit(op " %%cl, %%eax"); \
- emit("movl %%eax, 0(%%rsi)");
-
-#ifdef DEBUG_VM
-#define RANGECHECK(reg, bytes) \
- emit("movl %%" #reg ", %%ecx"); \
- emit("andl $0x%x, %%ecx", vm->dataMask &~(bytes-1)); \
- emit("cmpl %%" #reg ", %%ecx"); \
- emit("jz rc_ok_i_%08x", instruction); \
- emit("movq $%lu, %%rax", (unsigned long)memviolation); \
- emit("callq *%%rax"); \
- emit("rc_ok_i_%08x:", instruction);
-#elif 1
-// check is too expensive, so just confine memory access
-#define RANGECHECK(reg, bytes) \
- emit("andl $0x%x, %%" #reg, vm->dataMask &~(bytes-1));
-#else
-#define RANGECHECK(reg, bytes)
-#endif
-
-#ifdef DEBUG_VM
-#define NOTIMPL(x) \
- do { Com_Error(ERR_DROP, "instruction not implemented: %s\n", opnames[x]); } while(0)
-#else
-#define NOTIMPL(x) \
- do { Com_Printf(S_COLOR_RED "instruction not implemented: %x\n", x); vm->compiled = qfalse; return; } while(0)
-#endif
-
-static void* getentrypoint(vm_t* vm)
-{
- return vm->codeBase;
-}
-
-static void block_copy_vm(unsigned dest, unsigned src, unsigned count)
-{
- unsigned dataMask = currentVM->dataMask;
-
- if ((dest & dataMask) != dest
- || (src & dataMask) != src
- || ((dest+count) & dataMask) != dest + count
- || ((src+count) & dataMask) != src + count)
- {
- Com_Error(ERR_DROP, "OP_BLOCK_COPY out of range!\n");
- }
-
- memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count);
-}
-
-static void eop(void)
-{
- Com_Error(ERR_DROP, "end of program reached without return!\n");
- exit(1);
-}
-
-static void jmpviolation(void)
-{
- Com_Error(ERR_DROP, "program tried to execute code outside VM\n");
- exit(1);
-}
-
-#ifdef DEBUG_VM
-static void memviolation(void)
-{
- Com_Error(ERR_DROP, "program tried to access memory outside VM\n");
- exit(1);
-}
-#endif
-
-/*
-=================
-VM_Compile
-=================
-*/
-void VM_Compile( vm_t *vm, vmHeader_t *header ) {
- unsigned char op;
- int pc;
- unsigned instruction;
- char* code;
- unsigned iarg = 0;
- unsigned char barg = 0;
- int neednilabel = 0;
- struct timeval tvstart = {0, 0};
-#ifdef DEBUG_VM
- char fn_d[MAX_QPATH]; // disassembled
-#endif
-
- int pass;
- size_t compiledOfs = 0;
-
- // const optimization
- unsigned got_const = 0, const_value = 0;
-
- gettimeofday(&tvstart, NULL);
-
- for (pass = 0; pass < 2; ++pass) {
-
- if(pass)
- {
- compiledOfs = assembler_get_code_size();
- vm->codeLength = compiledOfs;
- vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
- if(vm->codeBase == (void*)-1)
- Com_Error(ERR_DROP, "VM_CompileX86: can't mmap memory");
-
- assembler_set_output((char*)vm->codeBase);
- }
-
- assembler_init(pass);
-
-#ifdef DEBUG_VM
- strcpy(fn_d,vm->name);
- strcat(fn_d, ".qdasm");
-
- qdasmout = fopen(fn_d, "w");
-#endif
-
- // translate all instructions
- pc = 0;
- code = (char *)header + header->codeOffset;
-
- for ( instruction = 0; instruction < header->instructionCount; ++instruction )
- {
- op = code[ pc ];
- ++pc;
-
- vm->instructionPointers[instruction] = assembler_get_code_size();
-
- /* store current instruction number in r15 for debugging */
-#if DEBUG_VM0
- emit("nop");
- emit("movq $%d, %%r15", instruction);
- emit("nop");
-#endif
-
- if(op_argsize[op] == 4)
- {
- iarg = *(int*)(code+pc);
- pc += 4;
- Dfprintf(qdasmout, "%s %8u\n", opnames[op], iarg);
- }
- else if(op_argsize[op] == 1)
- {
- barg = code[pc++];
- Dfprintf(qdasmout, "%s %8hhu\n", opnames[op], barg);
- }
- else
- {
- Dfprintf(qdasmout, "%s\n", opnames[op]);
- }
-
- if(neednilabel)
- {
- emit("i_%08x:", instruction);
- neednilabel = 0;
- }
-
- switch ( op )
- {
- case OP_UNDEF:
- NOTIMPL(op);
- break;
- case OP_IGNORE:
- MAYBE_EMIT_CONST();
- emit("nop");
- break;
- case OP_BREAK:
- MAYBE_EMIT_CONST();
- emit("int3");
- break;
- case OP_ENTER:
- MAYBE_EMIT_CONST();
- emit("subl $%d, %%edi", iarg);
- break;
- case OP_LEAVE:
- MAYBE_EMIT_CONST();
- emit("addl $%d, %%edi", iarg); // get rid of stack frame
- emit("ret");
- break;
- case OP_CALL:
- RANGECHECK(edi, 4);
- emit("movl $%d, 0(%%r8, %%rdi, 1)", instruction+1); // save next instruction
- if(got_const)
- {
- if ((int)const_value < 0)
- goto emit_do_syscall;
-
- CHECK_INSTR(const_value);
- emit("movq $%lu, %%rax", vm->codeBase+vm->instructionPointers[const_value]);
- emit("callq *%%rax");
- got_const = 0;
- break;
- }
- else
- {
- MAYBE_EMIT_CONST();
- emit("movl 0(%%rsi), %%eax"); // get instr from stack
- emit("subq $4, %%rsi");
-
- emit("orl %%eax, %%eax");
- emit("jl callSyscall%d", instruction);
-
- PREPARE_JMP(eax);
- emit("callq *%%rax");
-
- emit("jmp i_%08x", instruction+1);
- emit("callSyscall%d:", instruction);
- }
-emit_do_syscall:
-// emit("fnsave 4(%%rsi)");
- emit("push %%rsi");
- emit("push %%rdi");
- emit("push %%r8");
- emit("push %%r9");
- emit("push %%r10");
- emit("movq %%rsp, %%rbx"); // we need to align the stack pointer
- emit("subq $8, %%rbx"); // |
- emit("andq $127, %%rbx"); // |
- emit("subq %%rbx, %%rsp"); // <-+
- emit("push %%rbx");
- if(got_const) {
- got_const = 0;
- emit("movq $%u, %%rsi", -1-const_value); // second argument in rsi
- } else {
- emit("negl %%eax"); // convert to actual number
- emit("decl %%eax");
- // first argument already in rdi
- emit("movq %%rax, %%rsi"); // second argument in rsi
- }
- emit("movq $%lu, %%rax", (unsigned long)callAsmCall);
- emit("callq *%%rax");
- emit("pop %%rbx");
- emit("addq %%rbx, %%rsp");
- emit("pop %%r10");
- emit("pop %%r9");
- emit("pop %%r8");
- emit("pop %%rdi");
- emit("pop %%rsi");
-// emit("frstor 4(%%rsi)");
- emit("addq $4, %%rsi");
- emit("movl %%eax, (%%rsi)"); // store return value
- neednilabel = 1;
- break;
- case OP_PUSH:
- MAYBE_EMIT_CONST();
- emit("addq $4, %%rsi");
- break;
- case OP_POP:
- MAYBE_EMIT_CONST();
- emit("subq $4, %%rsi");
- break;
- case OP_CONST:
- MAYBE_EMIT_CONST();
-#ifdef CONST_OPTIMIZE
- got_const = 1;
- const_value = iarg;
-#else
- emit("addq $4, %%rsi");
- emit("movl $%d, 0(%%rsi)", iarg);
-#endif
- break;
- case OP_LOCAL:
- MAYBE_EMIT_CONST();
- emit("movl %%edi, %%ebx");
- emit("addl $%d,%%ebx", iarg);
- emit("addq $4, %%rsi");
- emit("movl %%ebx, 0(%%rsi)");
- break;
- case OP_JUMP:
- if(got_const) {
- iarg = const_value;
- got_const = 0;
- JMPIARG;
- } else {
- emit("movl 0(%%rsi), %%eax"); // get instr from stack
- emit("subq $4, %%rsi");
-
- PREPARE_JMP(eax);
- emit("jmp *%%rax");
- }
- break;
- case OP_EQ:
- IJ("jne");
- break;
- case OP_NE:
- IJ("je");
- break;
- case OP_LTI:
- IJ("jnl");
- break;
- case OP_LEI:
- IJ("jnle");
- break;
- case OP_GTI:
- IJ("jng");
- break;
- case OP_GEI:
- IJ("jnge");
- break;
- case OP_LTU:
- IJ("jnb");
- break;
- case OP_LEU:
- IJ("jnbe");
- break;
- case OP_GTU:
- IJ("jna");
- break;
- case OP_GEU:
- IJ("jnae");
- break;
- case OP_EQF:
- FJ(0x40, "jz");
- XJ("jnz");
- break;
- case OP_NEF:
- FJ(0x40, "jnz");
-#ifndef USE_X87
- MAYBE_EMIT_CONST();
- emit("subq $8, %%rsi");
- emit("movss 4(%%rsi), %%xmm0");
- emit("ucomiss 8(%%rsi), %%xmm0");
- emit("jp dojump_i_%08x", instruction);
- emit("jz i_%08x", instruction+1);
- emit("dojump_i_%08x:", instruction);
- JMPIARG
- neednilabel = 1;
-#endif
- break;
- case OP_LTF:
- FJ(0x01, "jz");
- XJ("jnc");
- break;
- case OP_LEF:
- FJ(0x41, "jz");
- XJ("ja");
- break;
- case OP_GTF:
- FJ(0x41, "jnz");
- XJ("jbe");
- break;
- case OP_GEF:
- FJ(0x01, "jnz");
- XJ("jb");
- break;
- case OP_LOAD1:
- MAYBE_EMIT_CONST();
- emit("movl 0(%%rsi), %%eax"); // get value from stack
- RANGECHECK(eax, 1);
- emit("movb 0(%%r8, %%rax, 1), %%al"); // deref into eax
- emit("andq $255, %%rax");
- emit("movl %%eax, 0(%%rsi)"); // store on stack
- break;
- case OP_LOAD2:
- MAYBE_EMIT_CONST();
- emit("movl 0(%%rsi), %%eax"); // get value from stack
- RANGECHECK(eax, 2);
- emit("movw 0(%%r8, %%rax, 1), %%ax"); // deref into eax
- emit("movl %%eax, 0(%%rsi)"); // store on stack
- break;
- case OP_LOAD4:
- MAYBE_EMIT_CONST();
- emit("movl 0(%%rsi), %%eax"); // get value from stack
- RANGECHECK(eax, 4); // not a pointer!?
- emit("movl 0(%%r8, %%rax, 1), %%eax"); // deref into eax
- emit("movl %%eax, 0(%%rsi)"); // store on stack
- break;
- case OP_STORE1:
- MAYBE_EMIT_CONST();
- emit("movl 0(%%rsi), %%eax"); // get value from stack
- emit("andq $255, %%rax");
- emit("movl -4(%%rsi), %%ebx"); // get pointer from stack
- RANGECHECK(ebx, 1);
- emit("movb %%al, 0(%%r8, %%rbx, 1)"); // store in memory
- emit("subq $8, %%rsi");
- break;
- case OP_STORE2:
- MAYBE_EMIT_CONST();
- emit("movl 0(%%rsi), %%eax"); // get value from stack
- emit("movl -4(%%rsi), %%ebx"); // get pointer from stack
- RANGECHECK(ebx, 2);
- emit("movw %%ax, 0(%%r8, %%rbx, 1)"); // store in memory
- emit("subq $8, %%rsi");
- break;
- case OP_STORE4:
- MAYBE_EMIT_CONST();
- emit("movl -4(%%rsi), %%ebx"); // get pointer from stack
- RANGECHECK(ebx, 4);
- emit("movl 0(%%rsi), %%ecx"); // get value from stack
- emit("movl %%ecx, 0(%%r8, %%rbx, 1)"); // store in memory
- emit("subq $8, %%rsi");
- break;
- case OP_ARG:
- MAYBE_EMIT_CONST();
- emit("subq $4, %%rsi");
- emit("movl 4(%%rsi), %%eax"); // get value from stack
- emit("movl $0x%hhx, %%ebx", barg);
- emit("addl %%edi, %%ebx");
- RANGECHECK(ebx, 4);
- emit("movl %%eax, 0(%%r8,%%rbx, 1)"); // store in args space
- break;
- case OP_BLOCK_COPY:
-
- MAYBE_EMIT_CONST();
- emit("subq $8, %%rsi");
- emit("push %%rsi");
- emit("push %%rdi");
- emit("push %%r8");
- emit("push %%r9");
- emit("push %%r10");
- emit("movl 4(%%rsi), %%edi"); // 1st argument dest
- emit("movl 8(%%rsi), %%esi"); // 2nd argument src
- emit("movl $%d, %%edx", iarg); // 3rd argument count
- emit("movq $%lu, %%rax", (unsigned long)block_copy_vm);
- emit("callq *%%rax");
- emit("pop %%r10");
- emit("pop %%r9");
- emit("pop %%r8");
- emit("pop %%rdi");
- emit("pop %%rsi");
-
- break;
- case OP_SEX8:
- MAYBE_EMIT_CONST();
- emit("movw 0(%%rsi), %%ax");
- emit("andq $255, %%rax");
- emit("cbw");
- emit("cwde");
- emit("movl %%eax, 0(%%rsi)");
- break;
- case OP_SEX16:
- MAYBE_EMIT_CONST();
- emit("movw 0(%%rsi), %%ax");
- emit("cwde");
- emit("movl %%eax, 0(%%rsi)");
- break;
- case OP_NEGI:
- MAYBE_EMIT_CONST();
- emit("negl 0(%%rsi)");
- break;
- case OP_ADD:
- SIMPLE("addl");
- break;
- case OP_SUB:
- SIMPLE("subl");
- break;
- case OP_DIVI:
- MAYBE_EMIT_CONST();
- emit("subq $4, %%rsi");
- emit("movl 0(%%rsi), %%eax");
- emit("cdq");
- emit("idivl 4(%%rsi)");
- emit("movl %%eax, 0(%%rsi)");
- break;
- case OP_DIVU:
- MAYBE_EMIT_CONST();
- emit("subq $4, %%rsi");
- emit("movl 0(%%rsi), %%eax");
- emit("xorq %%rdx, %%rdx");
- emit("divl 4(%%rsi)");
- emit("movl %%eax, 0(%%rsi)");
- break;
- case OP_MODI:
- MAYBE_EMIT_CONST();
- emit("subq $4, %%rsi");
- emit("movl 0(%%rsi), %%eax");
- emit("xorl %%edx, %%edx");
- emit("cdq");
- emit("idivl 4(%%rsi)");
- emit("movl %%edx, 0(%%rsi)");
- break;
- case OP_MODU:
- MAYBE_EMIT_CONST();
- emit("subq $4, %%rsi");
- emit("movl 0(%%rsi), %%eax");
- emit("xorl %%edx, %%edx");
- emit("divl 4(%%rsi)");
- emit("movl %%edx, 0(%%rsi)");
- break;
- case OP_MULI:
- MAYBE_EMIT_CONST();
- emit("subq $4, %%rsi");
- emit("movl 0(%%rsi), %%eax");
- emit("imull 4(%%rsi)");
- emit("movl %%eax, 0(%%rsi)");
- break;
- case OP_MULU:
- MAYBE_EMIT_CONST();
- emit("subq $4, %%rsi");
- emit("movl 0(%%rsi), %%eax");
- emit("mull 4(%%rsi)");
- emit("movl %%eax, 0(%%rsi)");
- break;
- case OP_BAND:
- SIMPLE("andl");
- break;
- case OP_BOR:
- SIMPLE("orl");
- break;
- case OP_BXOR:
- SIMPLE("xorl");
- break;
- case OP_BCOM:
- MAYBE_EMIT_CONST();
- emit("notl 0(%%rsi)");
- break;
- case OP_LSH:
- SHIFT("shl");
- break;
- case OP_RSHI:
- SHIFT("sarl");
- break;
- case OP_RSHU:
- SHIFT("shrl");
- break;
- case OP_NEGF:
- MAYBE_EMIT_CONST();
-#ifdef USE_X87
- emit("flds 0(%%rsi)");
- emit("fchs");
- emit("fstps 0(%%rsi)");
-#else
- emit("movl $0x80000000, %%eax");
- emit("xorl %%eax, 0(%%rsi)");
-#endif
- break;
- case OP_ADDF:
- FSIMPLE("fadds");
- XSIMPLE("addss");
- break;
- case OP_SUBF:
- FSIMPLE("fsubs");
- XSIMPLE("subss");
- break;
- case OP_DIVF:
- FSIMPLE("fdivs");
- XSIMPLE("divss");
- break;
- case OP_MULF:
- FSIMPLE("fmuls");
- XSIMPLE("mulss");
- break;
- case OP_CVIF:
- MAYBE_EMIT_CONST();
-#ifdef USE_X87
- emit("filds 0(%%rsi)");
- emit("fstps 0(%%rsi)");
-#else
- emit("movl 0(%%rsi), %%eax");
- emit("cvtsi2ss %%eax, %%xmm0");
- emit("movss %%xmm0, 0(%%rsi)");
-#endif
- break;
- case OP_CVFI:
- MAYBE_EMIT_CONST();
-#ifdef USE_X87
- emit("flds 0(%%rsi)");
- emit("fnstcw 4(%%rsi)");
- emit("movw $0x0F7F, 8(%%rsi)"); // round toward zero
- emit("fldcw 8(%%rsi)");
- emit("fistpl 0(%%rsi)");
- emit("fldcw 4(%%rsi)");
-#else
- emit("movss 0(%%rsi), %%xmm0");
- emit("cvttss2si %%xmm0, %%eax");
- emit("movl %%eax, 0(%%rsi)");
-#endif
- break;
- default:
- NOTIMPL(op);
- break;
- }
-
-
- }
-
- if(got_const) {
- Com_Error(ERR_DROP, "leftover const\n");
- }
-
- emit("movq $%lu, %%rax", (unsigned long)eop);
- emit("callq *%%rax");
-
- } // pass loop
-
- assembler_init(0);
-
- if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC))
- Com_Error(ERR_DROP, "VM_CompileX86: mprotect failed");
-
- vm->destroy = VM_Destroy_Compiled;
-
-#ifdef DEBUG_VM
- fflush(qdasmout);
- fclose(qdasmout);
-
-#if 0
- strcpy(fn_d,vm->name);
- strcat(fn_d, ".bin");
- qdasmout = fopen(fn_d, "w");
- fwrite(vm->codeBase, compiledOfs, 1, qdasmout);
- fflush(qdasmout);
- fclose(qdasmout);
-#endif
-#endif
-
- if(vm->compiled)
- {
- struct timeval tvdone = {0, 0};
- struct timeval dur = {0, 0};
- Com_Printf( "VM file %s compiled to %i bytes of code (%p - %p)\n", vm->name, vm->codeLength, vm->codeBase, vm->codeBase+vm->codeLength );
-
- gettimeofday(&tvdone, NULL);
- timersub(&tvdone, &tvstart, &dur);
- Com_Printf( "compilation took %lu.%06lu seconds\n", dur.tv_sec, dur.tv_usec );
- }
-}
-
-
-void VM_Destroy_Compiled(vm_t* self)
-{
-#ifdef _WIN32
- VirtualFree(self->codeBase, 0, MEM_RELEASE);
-#else
- munmap(self->codeBase, self->codeLength);
-#endif
-}
-
-/*
-==============
-VM_CallCompiled
-
-This function is called directly by the generated code
-==============
-*/
-
-#ifdef DEBUG_VM
-static char* memData;
-#endif
-
-int VM_CallCompiled( vm_t *vm, int *args ) {
- int programCounter;
- int programStack;
- int stackOnEntry;
- byte *image;
- void *entryPoint;
- void *opStack;
- int stack[1024] = { 0xDEADBEEF };
-
- currentVM = vm;
-
-// Com_Printf("entering %s level %d, call %d, arg1 = 0x%x\n", vm->name, vm->callLevel, args[0], args[1]);
-
- // interpret the code
- vm->currentlyInterpreting = qtrue;
-
-// callMask = vm->dataMask;
-
- // we might be called recursively, so this might not be the very top
- programStack = vm->programStack;
- stackOnEntry = programStack;
-
- // set up the stack frame
- image = vm->dataBase;
-#ifdef DEBUG_VM
- memData = (char*)image;
-#endif
-
- programCounter = 0;
-
- programStack -= 48;
-
- *(int *)&image[ programStack + 44] = args[9];
- *(int *)&image[ programStack + 40] = args[8];
- *(int *)&image[ programStack + 36] = args[7];
- *(int *)&image[ programStack + 32] = args[6];
- *(int *)&image[ programStack + 28] = args[5];
- *(int *)&image[ programStack + 24] = args[4];
- *(int *)&image[ programStack + 20] = args[3];
- *(int *)&image[ programStack + 16] = args[2];
- *(int *)&image[ programStack + 12] = args[1];
- *(int *)&image[ programStack + 8 ] = args[0];
- *(int *)&image[ programStack + 4 ] = 0x77777777; // return stack
- *(int *)&image[ programStack ] = -1; // will terminate the loop on return
-
- // off we go into generated code...
- entryPoint = getentrypoint(vm);
- opStack = &stack;
-
- __asm__ __volatile__ (
- " movq %5,%%rsi \r\n" \
- " movl %4,%%edi \r\n" \
- " movq %2,%%r10 \r\n" \
- " movq %3,%%r8 \r\n" \
- " subq $24, %%rsp # fix alignment as call pushes one value \r\n" \
- " callq *%%r10 \r\n" \
- " addq $24, %%rsp \r\n" \
- " movl %%edi, %0 \r\n" \
- " movq %%rsi, %1 \r\n" \
- : "=m" (programStack), "=m" (opStack)
- : "m" (entryPoint), "m" (vm->dataBase), "m" (programStack), "m" (opStack)
- : "%rsi", "%rdi", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r10", "%r15", "%xmm0"
- );
-
- if ( opStack != &stack[1] ) {
- Com_Error( ERR_DROP, "opStack corrupted in compiled code (offset %ld)\n", (long int) ((void *) &stack[1] - opStack));
- }
- if ( programStack != stackOnEntry - 48 ) {
- Com_Error( ERR_DROP, "programStack corrupted in compiled code\n" );
- }
-
-// Com_Printf("exiting %s level %d\n", vm->name, vm->callLevel);
- vm->programStack = stackOnEntry;
-
- return *(int *)opStack;
-}
diff --git a/engine/code/qcommon/vm_x86_64_assembler.c b/engine/code/qcommon/vm_x86_64_assembler.c
deleted file mode 100644
index 346680e..0000000
--- a/engine/code/qcommon/vm_x86_64_assembler.c
+++ /dev/null
@@ -1,1434 +0,0 @@
-/*
-===========================================================================
-vm_x86_64_assembler.c -- assembler for x86-64
-
-Copyright (C) 2007 Ludwig Nussel <ludwig.nussel at suse.de>, Novell inc.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned int u32;
-typedef unsigned long u64;
-
-static char* out;
-static unsigned compiledOfs;
-static unsigned assembler_pass;
-
-static const char* cur_line;
-
-static FILE* fout;
-
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-
-#define crap(fmt, args...) do { \
- _crap(__FUNCTION__, fmt, ##args); \
-} while(0)
-
-#define CRAP_INVALID_ARGS crap("invalid arguments %s, %s", argtype2str(arg1.type),argtype2str(arg2.type));
-
-#ifdef DEBUG
-#define debug(fmt, args...) printf(fmt, ##args)
-#else
-#define debug(fmt, args...)
-#endif
-
-static void _crap(const char* func, const char* fmt, ...)
-{
- va_list ap;
- fprintf(stderr, "%s() - ", func);
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fputc('\n', stderr);
- if(cur_line && cur_line[0])
- fprintf(stderr, "-> %s\n", cur_line);
- exit(1);
-}
-
-static void emit1(unsigned char v)
-{
- int writecnt;
-
- if(assembler_pass)
- {
- out[compiledOfs++] = v;
-
- if(fout)
- writecnt = fwrite(&v, 1, 1, fout);
-
- debug("%02hhx ", v);
- }
- else
- {
- ++compiledOfs;
- }
-}
-
-static inline void emit2(u16 v)
-{
- emit1(v&0xFF);
- emit1((v>>8)&0xFF);
-}
-
-static inline void emit4(u32 v)
-{
- emit1(v&0xFF);
- emit1((v>>8)&0xFF);
- emit1((v>>16)&0xFF);
- emit1((v>>24)&0xFF);
-}
-
-static inline void emit8(u64 v)
-{
- emit4(v&0xFFFFFFFF);
- emit4((v>>32)&0xFFFFFFFF);
-}
-
-enum {
- REX_W = 0x08,
- REX_R = 0x04,
- REX_X = 0x02,
- REX_B = 0x01,
-};
-
-enum {
- MODRM_MOD_00 = 0x00,
- MODRM_MOD_01 = 0x01 << 6,
- MODRM_MOD_10 = 0x02 << 6,
- MODRM_MOD_11 = 0x03 << 6,
- MODRM_RM_SIB = 0x04,
-};
-
-typedef enum
-{
- T_NONE = 0x00,
- T_REGISTER = 0x01,
- T_IMMEDIATE = 0x02,
- T_MEMORY = 0x04,
- T_LABEL = 0x08,
- T_ABSOLUTE = 0x80
-} argtype_t;
-
-typedef enum {
- R_8 = 0x100,
- R_16 = 0x200,
- R_64 = 0x800,
- R_MSZ = 0xF00, // size mask
- R_XMM = 0x2000, // xmm register. year, sucks
- R_EAX = 0x00,
- R_EBX = 0x03,
- R_ECX = 0x01,
- R_EDX = 0x02,
- R_ESI = 0x06,
- R_EDI = 0x07,
- R_ESP = 0x04,
- R_RAX = R_EAX | R_64,
- R_RBX = R_EBX | R_64,
- R_RCX = R_ECX | R_64,
- R_RDX = R_EDX | R_64,
- R_RSI = R_ESI | R_64,
- R_RDI = R_EDI | R_64,
- R_RSP = R_ESP | R_64,
- R_R8 = 0x08 | R_64,
- R_R9 = 0x09 | R_64,
- R_R10 = 0x0A | R_64,
- R_R15 = 0x0F | R_64,
- R_AL = R_EAX | R_8,
- R_AX = R_EAX | R_16,
- R_CL = R_ECX | R_8,
- R_XMM0 = 0x00 | R_XMM,
- R_MGP = 0x0F, // mask for general purpose registers
-} reg_t;
-
-typedef enum {
- MODRM_SIB = 0,
- MODRM_NOSIB = 0x3,
-} modrm_sib_t;
-
-typedef struct {
- unsigned disp;
- argtype_t basetype;
- union {
- u64 imm;
- reg_t reg;
- } base;
- argtype_t indextype;
- union {
- u64 imm;
- reg_t reg;
- } index;
- unsigned scale;
-} memref_t;
-
-#define LABELLEN 32
-
-typedef struct {
- argtype_t type;
- union {
- u64 imm;
- reg_t reg;
- memref_t mem;
- char label[LABELLEN];
- } v;
- int absolute:1;
-} arg_t;
-
-typedef void (*emitfunc)(const char* op, arg_t arg1, arg_t arg2, void* data);
-
-typedef struct {
- char* mnemonic;
- emitfunc func;
- void* data;
-} op_t;
-
-typedef struct {
- u8 xmmprefix;
- u8 subcode; // in modrm
- u8 rmcode; // opcode for reg/mem, reg
- u8 mrcode; // opcode for reg, reg/mem
- u8 rcode8; // opcode for reg8/mem8
- u8 rcode; // opcode for reg/mem
-} opparam_t;
-
-/* ************************* */
-
-static unsigned hashkey(const char *string, unsigned len) {
- unsigned register hash, i;
-
- hash = 0;
- for (i = 0; i < len && string[i] != '\0'; ++i) {
- hash += string[i] * (119 + i);
- }
- hash = (hash ^ (hash >> 10) ^ (hash >> 20));
- return hash;
-}
-
-struct hashentry {
- char* label;
- unsigned address;
- struct hashentry* next;
-};
-static struct hashentry* labelhash[1021];
-
-// no dup check!
-static void hash_add_label(const char* label, unsigned address)
-{
- struct hashentry* h;
- unsigned i = hashkey(label, -1U);
- i %= sizeof(labelhash)/sizeof(labelhash[0]);
- h = malloc(sizeof(struct hashentry));
- h->label = strdup(label);
- h->address = address;
- h->next = labelhash[i];
- labelhash[i] = h;
-}
-
-static unsigned lookup_label(const char* label)
-{
- struct hashentry* h;
- unsigned i = hashkey(label, -1U);
- i %= sizeof(labelhash)/sizeof(labelhash[0]);
- for(h = labelhash[i]; h; h = h->next )
- {
- if(!strcmp(h->label, label))
- return h->address;
- }
- if(assembler_pass)
- crap("label %s undefined", label);
- return 0;
-}
-
-static void labelhash_free(void)
-{
- struct hashentry* h;
- unsigned i;
- unsigned z = 0, min = -1U, max = 0, t = 0;
- for ( i = 0; i < sizeof(labelhash)/sizeof(labelhash[0]); ++i)
- {
- unsigned n = 0;
- h = labelhash[i];
- while(h)
- {
- struct hashentry* next = h->next;
- free(h->label);
- free(h);
- h = next;
- ++n;
- }
- t+=n;
- if(!n) ++z;
- //else printf("%u\n", n);
- min = MIN(min, n);
- max = MAX(max, n);
- }
- printf("total %u, hsize %lu, zero %u, min %u, max %u\n", t, sizeof(labelhash)/sizeof(labelhash[0]), z, min, max);
- memset(labelhash, 0, sizeof(labelhash));
-}
-
-/* ************************* */
-
-
-static const char* argtype2str(argtype_t t)
-{
- switch(t)
- {
- case T_NONE: return "none";
- case T_REGISTER: return "register";
- case T_IMMEDIATE: return "immediate";
- case T_MEMORY: return "memory";
- case T_LABEL: return "label";
- default: crap("invalid type");
- }
- /* not reached */
- return T_NONE;
-}
-
-/* ************************* */
-
-static inline int iss8(u64 v)
-{
- return (labs(v) <= 0x80);
-}
-
-static inline int isu8(u64 v)
-{
- return (v <= 0xff);
-}
-
-static inline int iss16(u64 v)
-{
- return (labs(v) <= 0x8000);
-}
-
-static inline int isu16(u64 v)
-{
- return (v <= 0xffff);
-}
-
-static inline int iss32(u64 v)
-{
- return (labs(v) <= 0x80000000);
-}
-
-static inline int isu32(u64 v)
-{
- return (v <= 0xffffffff);
-}
-
-static void emit_opsingle(const char* mnemonic, arg_t arg1, arg_t arg2, void* data)
-{
- u8 op = (u8)((unsigned long) data);
-
- if(arg1.type != T_NONE || arg2.type != T_NONE)
- CRAP_INVALID_ARGS;
-
- emit1(op);
-}
-
-static void emit_opsingle16(const char* mnemonic, arg_t arg1, arg_t arg2, void* data)
-{
- emit1(0x66);
- emit_opsingle(mnemonic, arg1, arg2, data);
-}
-
-static void compute_rexmodrmsib(u8* rex_r, u8* modrm_r, u8* sib_r, arg_t* arg1, arg_t* arg2)
-{
- u8 rex = 0;
- u8 modrm = 0;
- u8 sib = 0;
-
- if((arg1->type == T_REGISTER && arg2->type == T_REGISTER)
- && ((arg1->v.reg & R_MSZ) != (arg2->v.reg & R_MSZ))
- && !((arg1->v.reg & R_XMM) || (arg2->v.reg & R_XMM)))
- crap("both registers must be of same width");
-
- if((arg1->type == T_REGISTER && arg1->v.reg & R_64)
- || (arg2->type == T_REGISTER && arg2->v.reg & R_64))
- {
- rex |= REX_W;
- }
-
- if(arg1->type == T_REGISTER)
- {
- if((arg1->v.reg & R_MGP) > 0x07)
- rex |= REX_R;
-
- modrm |= (arg1->v.reg & 0x07) << 3;
- }
-
- if(arg2->type == T_REGISTER)
- {
- if((arg2->v.reg & R_MGP) > 0x07)
- rex |= REX_B;
-
- modrm |= (arg2->v.reg & 0x07);
- }
-
- if(arg2->type == T_MEMORY)
- {
- if((arg2->v.mem.basetype == T_REGISTER && !(arg2->v.mem.base.reg & R_64))
- || (arg2->v.mem.indextype == T_REGISTER && !(arg2->v.mem.index.reg & R_64)))
- {
- crap("only 64bit base/index registers are %x %x", arg2->v.mem.base.reg, arg2->v.mem.index.reg);
- }
-
- if(arg2->v.mem.indextype == T_REGISTER)
- {
- modrm |= MODRM_RM_SIB;
- if(!arg2->v.mem.disp)
- {
- modrm |= MODRM_MOD_00;
- }
- else if(iss8(arg2->v.mem.disp))
- {
- modrm |= MODRM_MOD_01;
- }
- else if(isu32(arg2->v.mem.disp))
- {
- modrm |= MODRM_MOD_10;
- }
- else
- {
- crap("invalid displacement");
- }
-
- if((arg2->v.mem.index.reg & R_MGP) > 0x07)
- rex |= REX_X;
-
- if((arg2->v.mem.base.reg & R_MGP) > 0x07)
- rex |= REX_B;
-
- if(arg2->v.mem.basetype != T_REGISTER)
- crap("base must be register");
- switch(arg2->v.mem.scale)
- {
- case 1: break;
- case 2: sib |= 1 << 6; break;
- case 4: sib |= 2 << 6; break;
- case 8: sib |= 3 << 6; break;
- }
- sib |= (arg2->v.mem.index.reg & 0x07) << 3;
- sib |= (arg2->v.mem.base.reg & 0x07);
- }
- else if(arg2->v.mem.indextype == T_NONE)
- {
- if(!arg2->v.mem.disp)
- {
- modrm |= MODRM_MOD_00;
- }
- else if(iss8(arg2->v.mem.disp))
- {
- modrm |= MODRM_MOD_01;
- }
- else if(isu32(arg2->v.mem.disp))
- {
- modrm |= MODRM_MOD_10;
- }
- else
- {
- crap("invalid displacement");
- }
-
- if(arg2->v.mem.basetype != T_REGISTER)
- crap("todo: base != register");
-
- if((arg2->v.mem.base.reg & R_MGP) > 0x07)
- rex |= REX_B;
-
- modrm |= arg2->v.mem.base.reg & 0x07;
- }
- else
- {
- crap("invalid indextype");
- }
- }
- else
- {
- modrm |= MODRM_MOD_11;
- }
-
- if(rex)
- rex |= 0x40; // XXX
-
- *rex_r = rex;
- *modrm_r = modrm;
- *sib_r = sib;
-}
-
-static void maybe_emit_displacement(arg_t* arg)
-{
- if(arg->type != T_MEMORY)
- return;
-
- if(arg->v.mem.disp)
- {
- if(iss8(arg->v.mem.disp))
- {
- emit1((u8)arg->v.mem.disp);
- }
- else if(isu32(arg->v.mem.disp))
- {
- emit4(arg->v.mem.disp);
- }
- else
- {
- crap("invalid displacement");
- }
- }
-}
-
-/* one byte operator with register added to operator */
-static void emit_opreg(const char* mnemonic, arg_t arg1, arg_t arg2, void* data)
-{
- u8 op = (u8)((unsigned long) data);
-
- if(arg1.type != T_REGISTER || arg2.type != T_NONE)
- CRAP_INVALID_ARGS;
-
- if((arg1.v.reg & R_MGP) > 0x07)
- emit1(0x40 | REX_B);
-
- op |= (arg1.v.reg & 0x07);
-
- emit1(op);
-}
-
-/* operator which operates on reg/mem */
-static void emit_op_rm(const char* mnemonic, arg_t arg1, arg_t arg2, void* data)
-{
- u8 rex, modrm, sib;
- opparam_t* params = data;
-
- if((arg1.type != T_REGISTER && arg1.type != T_MEMORY) || arg2.type != T_NONE)
- CRAP_INVALID_ARGS;
-
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1);
-
- modrm |= params->subcode << 3;
-
- if(arg1.v.reg & R_16)
- emit1(0x66);
-
- if(rex) emit1(rex);
- if(arg1.v.reg & R_8)
- emit1(params->rcode8); // op reg8/mem8,
- else
- emit1(params->rcode); // op reg/mem,
- emit1(modrm);
- if((modrm & 0x07) == MODRM_RM_SIB)
- emit1(sib);
-
- maybe_emit_displacement(&arg1);
-}
-
-/* operator which operates on reg/mem with cl */
-static void emit_op_rm_cl(const char* mnemonic, arg_t arg1, arg_t arg2, void* data)
-{
- u8 rex, modrm, sib;
- opparam_t* params = data;
-
- if(arg2.type != T_REGISTER || arg1.type != T_REGISTER)
- CRAP_INVALID_ARGS;
-
- if((arg1.v.reg & R_MGP) != R_ECX && !(arg1.v.reg & R_8))
- crap("only cl register is valid");
-
- arg1.type = T_NONE; // don't complain, we know it's cl anyways
-
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2);
-
- modrm |= params->subcode << 3;
-
- if(arg2.v.reg & R_16)
- emit1(0x66);
-
- if(rex) emit1(rex);
- if(arg2.v.reg & R_8)
- emit1(params->rcode8); // op reg8/mem8,
- else
- emit1(params->rcode); // op reg/mem,
- emit1(modrm);
- if((modrm & 0x07) == MODRM_RM_SIB)
- emit1(sib);
-
- maybe_emit_displacement(&arg2);
-}
-
-static void emit_mov(const char* mnemonic, arg_t arg1, arg_t arg2, void* data)
-{
- u8 rex = 0;
- u8 modrm = 0;
- u8 sib = 0;
-
- if(arg1.type == T_IMMEDIATE && arg2.type == T_REGISTER)
- {
- u8 op = 0xb8;
-
- if(arg2.v.reg & R_8)
- {
- if(!isu8(arg1.v.imm))
- crap("value too large for 8bit register");
-
- op = 0xb0;
- }
- else if(arg2.v.reg & R_16)
- {
- if(!isu16(arg1.v.imm))
- crap("value too large for 16bit register");
- emit1(0x66);
- }
- else if(!(arg2.v.reg & R_64))
- {
- if(!isu32(arg1.v.imm))
- crap("value too large for 32bit register");
- }
-
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2);
-
- if(rex) emit1(rex);
-
- op |= (arg2.v.reg & 0x07);
-
- emit1(op);
-
- if(arg2.v.reg & R_8) emit1(arg1.v.imm);
- else if(arg2.v.reg & R_16) emit2(arg1.v.imm);
- else if(arg2.v.reg & R_64) emit8(arg1.v.imm);
- else emit4(arg1.v.imm);
- }
- else if(arg1.type == T_IMMEDIATE && arg2.type == T_MEMORY)
- {
- if(!iss32(arg1.v.imm))
- {
- crap("only 32bit immediates supported");
- }
-
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2);
- if(rex) emit1(rex);
- emit1(0xc7); // mov reg/mem, imm
- emit1(modrm);
- if((modrm & 0x07) == MODRM_RM_SIB)
- emit1(sib);
-
- emit4(arg1.v.imm);
- }
- else if(arg1.type == T_REGISTER && arg2.type == T_REGISTER) // XXX: same as next
- {
- if(arg1.type != T_REGISTER || arg2.type != T_REGISTER)
- crap("both args must be registers");
-
- if((arg1.v.reg & R_MSZ) != (arg2.v.reg & R_MSZ))
- crap("both registers must be same width");
-
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2);
-
- if(rex) emit1(rex);
- emit1(0x89); // mov reg reg/mem,
- emit1(modrm);
- }
- else if(arg1.type == T_REGISTER && arg2.type == T_MEMORY)
- {
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2);
-
- if(arg1.v.reg & R_16)
- emit1(0x66);
-
- if(rex) emit1(rex);
- if(arg1.v.reg & R_8)
- emit1(0x88); // mov reg reg/mem,
- else
- emit1(0x89); // mov reg reg/mem,
- emit1(modrm);
- if((modrm & 0x07) == MODRM_RM_SIB)
- emit1(sib);
-
- maybe_emit_displacement(&arg2);
- }
- else if(arg1.type == T_MEMORY && arg2.type == T_REGISTER)
- {
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1);
-
- if(arg2.v.reg & R_16)
- emit1(0x66);
-
- if(rex) emit1(rex);
- if(arg2.v.reg & R_8)
- emit1(0x8a); // mov reg/mem, reg
- else
- emit1(0x8b); // mov reg/mem, reg
- emit1(modrm);
- if((modrm & 0x07) == MODRM_RM_SIB)
- emit1(sib);
-
- maybe_emit_displacement(&arg1);
- }
- else
- CRAP_INVALID_ARGS;
-}
-
-static void emit_subaddand(const char* mnemonic, arg_t arg1, arg_t arg2, void* data)
-{
- u8 rex = 0;
- u8 modrm = 0;
- u8 sib = 0;
-
- opparam_t* params = data;
-
- if(arg1.type == T_IMMEDIATE && arg2.type == T_REGISTER)
- {
- if(!iss32(arg1.v.imm))
- {
- crap("only 8 and 32 bit immediates supported");
- }
-
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2);
-
- modrm |= params->subcode << 3;
-
- if(rex) emit1(rex);
-#if 0
- if(isu8(arg1.v.imm))
- {
- emit1(0x83); // sub reg/mem, imm8
- emit1(modrm);
- emit1(arg1.v.imm&0xFF);
- }
- else
-#endif
- {
- emit1(0x81); // sub reg/mem, imm32
- emit1(modrm);
- emit4(arg1.v.imm);
- }
- }
- else if(arg1.type == T_REGISTER && (arg2.type == T_MEMORY || arg2.type == T_REGISTER))
- {
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2);
-
- if(rex) emit1(rex);
- emit1(params->rmcode); // sub reg/mem, reg
- emit1(modrm);
- if(arg2.type == T_MEMORY && (modrm & 0x07) == MODRM_RM_SIB)
- emit1(sib);
-
- maybe_emit_displacement(&arg2);
- }
- else if(arg1.type == T_MEMORY && arg2.type == T_REGISTER && params->mrcode)
- {
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1);
-
- if(rex) emit1(rex);
- emit1(params->mrcode); // sub reg, reg/mem
- emit1(modrm);
- if((modrm & 0x07) == MODRM_RM_SIB)
- emit1(sib);
-
- maybe_emit_displacement(&arg1);
- }
- else
- CRAP_INVALID_ARGS;
-}
-
-static void emit_condjump(const char* mnemonic, arg_t arg1, arg_t arg2, void* data)
-{
- unsigned off;
- int disp;
- unsigned char opcode = (unsigned char)(((unsigned long)data)&0xFF);
-
- if(arg1.type != T_LABEL || arg2.type != T_NONE)
- crap("%s: argument must be label", mnemonic);
-
- emit1(opcode);
-
- off = lookup_label(arg1.v.label);
- disp = off-(compiledOfs+1);
- if(assembler_pass && abs(disp) > 127)
- crap("cannot jump that far (%x -> %x = %x)", compiledOfs, off, disp);
-
- emit1(disp);
-}
-
-static void emit_jmp(const char* mnemonic, arg_t arg1, arg_t arg2, void* data)
-{
- if((arg1.type != T_LABEL && arg1.type != T_REGISTER && arg1.type != T_MEMORY) || arg2.type != T_NONE)
- CRAP_INVALID_ARGS;
-
- if(arg1.type == T_LABEL)
- {
- unsigned off;
- int disp;
-
- off = lookup_label(arg1.v.label);
- disp = off-(compiledOfs+5);
- emit1(0xe9);
- emit4(disp);
- }
- else
- {
- u8 rex, modrm, sib;
-
- if(arg1.type == T_REGISTER)
- {
- if(!arg1.absolute)
- crap("jmp must be absolute");
-
- if((arg1.v.reg & R_64) != R_64)
- crap("register must be 64bit");
-
- arg1.v.reg ^= R_64; // no rex required for call
- }
-
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1);
-
- modrm |= 0x4 << 3;
-
- if(rex) emit1(rex);
- emit1(0xff);
- emit1(modrm);
- if((modrm & 0x07) == MODRM_RM_SIB)
- emit1(sib);
- maybe_emit_displacement(&arg1);
- }
-}
-
-static void emit_call(const char* mnemonic, arg_t arg1, arg_t arg2, void* data)
-{
- u8 rex, modrm, sib;
-
- if((arg1.type != T_REGISTER && arg1.type != T_IMMEDIATE) || arg2.type != T_NONE)
- CRAP_INVALID_ARGS;
-
- if(arg1.type == T_REGISTER)
- {
- if(!arg1.absolute)
- crap("call must be absolute");
-
- if((arg1.v.reg & R_64) != R_64)
- crap("register must be 64bit");
-
- arg1.v.reg ^= R_64; // no rex required for call
-
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1);
-
- modrm |= 0x2 << 3;
-
- if(rex) emit1(rex);
- emit1(0xff);
- emit1(modrm);
- }
- else
- {
- if(!isu32(arg1.v.imm))
- crap("must be 32bit argument");
- emit1(0xe8);
- emit4(arg1.v.imm);
- }
-}
-
-
-static void emit_twobyte(const char* mnemonic, arg_t arg1, arg_t arg2, void* data)
-{
- u8 rex, modrm, sib;
-
- opparam_t* params = data;
-
- if(arg1.type == T_REGISTER && (arg2.type == T_MEMORY || arg2.type == T_REGISTER))
- {
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2);
-
- if(params->xmmprefix) emit1(params->xmmprefix);
- if(rex) emit1(rex);
- emit1(0x0f);
- emit1(params->rmcode); // sub reg/mem, reg
- emit1(modrm);
- if((modrm & 0x07) == MODRM_RM_SIB)
- emit1(sib);
-
- maybe_emit_displacement(&arg2);
- }
- else if(arg1.type == T_MEMORY && arg2.type == T_REGISTER && params->mrcode)
- {
- compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1);
-
- if(params->xmmprefix) emit1(params->xmmprefix);
- if(rex) emit1(rex);
- emit1(0x0f);
- emit1(params->mrcode); // sub reg, reg/mem
- emit1(modrm);
- if((modrm & 0x07) == MODRM_RM_SIB)
- emit1(sib);
-
- maybe_emit_displacement(&arg1);
- }
- else
- CRAP_INVALID_ARGS;
-}
-
-static opparam_t params_add = { subcode: 0, rmcode: 0x01, };
-static opparam_t params_or = { subcode: 1, rmcode: 0x09, };
-static opparam_t params_and = { subcode: 4, rmcode: 0x21, };
-static opparam_t params_sub = { subcode: 5, rmcode: 0x29, };
-static opparam_t params_xor = { subcode: 6, rmcode: 0x31, };
-static opparam_t params_cmp = { subcode: 7, rmcode: 0x39, mrcode: 0x3b, };
-static opparam_t params_dec = { subcode: 1, rcode: 0xff, rcode8: 0xfe, };
-static opparam_t params_sar = { subcode: 7, rcode: 0xd3, rcode8: 0xd2, };
-static opparam_t params_shl = { subcode: 4, rcode: 0xd3, rcode8: 0xd2, };
-static opparam_t params_shr = { subcode: 5, rcode: 0xd3, rcode8: 0xd2, };
-static opparam_t params_idiv = { subcode: 7, rcode: 0xf7, rcode8: 0xf6, };
-static opparam_t params_div = { subcode: 6, rcode: 0xf7, rcode8: 0xf6, };
-static opparam_t params_imul = { subcode: 5, rcode: 0xf7, rcode8: 0xf6, };
-static opparam_t params_mul = { subcode: 4, rcode: 0xf7, rcode8: 0xf6, };
-static opparam_t params_neg = { subcode: 3, rcode: 0xf7, rcode8: 0xf6, };
-static opparam_t params_not = { subcode: 2, rcode: 0xf7, rcode8: 0xf6, };
-
-static opparam_t params_cvtsi2ss = { xmmprefix: 0xf3, rmcode: 0x2a };
-static opparam_t params_cvttss2si = { xmmprefix: 0xf3, rmcode: 0x2c };
-static opparam_t params_addss = { xmmprefix: 0xf3, mrcode: 0x58 };
-static opparam_t params_divss = { xmmprefix: 0xf3, mrcode: 0x5e };
-static opparam_t params_movss = { xmmprefix: 0xf3, mrcode: 0x10, rmcode: 0x11 };
-static opparam_t params_mulss = { xmmprefix: 0xf3, mrcode: 0x59 };
-static opparam_t params_subss = { xmmprefix: 0xf3, mrcode: 0x5c };
-static opparam_t params_ucomiss = { mrcode: 0x2e };
-
-static int ops_sorted = 0;
-static op_t ops[] = {
- { "addl", emit_subaddand, ¶ms_add },
- { "addq", emit_subaddand, ¶ms_add },
- { "addss", emit_twobyte, ¶ms_addss },
- { "andl", emit_subaddand, ¶ms_and },
- { "andq", emit_subaddand, ¶ms_and },
- { "callq", emit_call, NULL },
- { "cbw", emit_opsingle16, (void*)0x98 },
- { "cdq", emit_opsingle, (void*)0x99 },
- { "cmpl", emit_subaddand, ¶ms_cmp },
- { "cmpq", emit_subaddand, ¶ms_cmp },
- { "cvtsi2ss", emit_twobyte, ¶ms_cvtsi2ss },
- { "cvttss2si", emit_twobyte, ¶ms_cvttss2si },
- { "cwde", emit_opsingle, (void*)0x98 },
- { "decl", emit_op_rm, ¶ms_dec },
- { "decq", emit_op_rm, ¶ms_dec },
- { "divl", emit_op_rm, ¶ms_div },
- { "divq", emit_op_rm, ¶ms_div },
- { "divss", emit_twobyte, ¶ms_divss },
- { "idivl", emit_op_rm, ¶ms_idiv },
- { "imull", emit_op_rm, ¶ms_imul },
- { "int3", emit_opsingle, (void*)0xcc },
- { "ja", emit_condjump, (void*)0x77 },
- { "jbe", emit_condjump, (void*)0x76 },
- { "jb", emit_condjump, (void*)0x72 },
- { "je", emit_condjump, (void*)0x74 },
- { "jl", emit_condjump, (void*)0x7c },
- { "jmp", emit_jmp, NULL },
- { "jmpq", emit_jmp, NULL },
- { "jnae", emit_condjump, (void*)0x72 },
- { "jna", emit_condjump, (void*)0x76 },
- { "jnbe", emit_condjump, (void*)0x77 },
- { "jnb", emit_condjump, (void*)0x73 },
- { "jnc", emit_condjump, (void*)0x73 },
- { "jne", emit_condjump, (void*)0x75 },
- { "jnge", emit_condjump, (void*)0x7c },
- { "jng", emit_condjump, (void*)0x7e },
- { "jnle", emit_condjump, (void*)0x7f },
- { "jnl", emit_condjump, (void*)0x7d },
- { "jnz", emit_condjump, (void*)0x75 },
- { "jp", emit_condjump, (void*)0x7a },
- { "jz", emit_condjump, (void*)0x74 },
- { "movb", emit_mov, NULL },
- { "movl", emit_mov, NULL },
- { "movq", emit_mov, NULL },
- { "movss", emit_twobyte, ¶ms_movss },
- { "movw", emit_mov, NULL },
- { "mull", emit_op_rm, ¶ms_mul },
- { "mulss", emit_twobyte, ¶ms_mulss },
- { "negl", emit_op_rm, ¶ms_neg },
- { "negq", emit_op_rm, ¶ms_neg },
- { "nop", emit_opsingle, (void*)0x90 },
- { "notl", emit_op_rm, ¶ms_not },
- { "notq", emit_op_rm, ¶ms_not },
- { "or", emit_subaddand, ¶ms_or },
- { "orl", emit_subaddand, ¶ms_or },
- { "pop", emit_opreg, (void*)0x58 },
- { "push", emit_opreg, (void*)0x50 },
- { "ret", emit_opsingle, (void*)0xc3 },
- { "sarl", emit_op_rm_cl, ¶ms_sar },
- { "shl", emit_op_rm_cl, ¶ms_shl },
- { "shrl", emit_op_rm_cl, ¶ms_shr },
- { "subl", emit_subaddand, ¶ms_sub },
- { "subq", emit_subaddand, ¶ms_sub },
- { "subss", emit_twobyte, ¶ms_subss },
- { "ucomiss", emit_twobyte, ¶ms_ucomiss },
- { "xorl", emit_subaddand, ¶ms_xor },
- { "xorq", emit_subaddand, ¶ms_xor },
- { NULL, NULL, NULL }
-};
-
-static int opsort(const void* A, const void* B)
-{
- const op_t* a = A;
- const op_t* b = B;
- return strcmp(a->mnemonic, b->mnemonic);
-}
-
-static op_t* getop(const char* n)
-{
-#if 0
- op_t* o = ops;
- while(o->mnemonic)
- {
- if(!strcmp(o->mnemonic, n))
- return o;
- ++o;
- }
-
-#else
- unsigned m, t, b;
- int r;
- t = sizeof(ops)/sizeof(ops[0])-1;
- b = 0;
-
- while(b <= t)
- {
- m = ((t-b)>>1) + b;
- if((r = strcmp(ops[m].mnemonic, n)) == 0)
- {
- return &ops[m];
- }
- else if(r < 0)
- {
- b = m + 1;
- }
- else
- {
- t = m - 1;
- }
- }
-#endif
-
- return NULL;
-}
-
-static reg_t parsereg(const char* str)
-{
- const char* s = str;
- if(*s == 'a' && s[1] == 'l' && !s[2])
- {
- return R_AL;
- }
- else if(*s == 'a' && s[1] == 'x' && !s[2])
- {
- return R_AX;
- }
- if(*s == 'c' && s[1] == 'l' && !s[2])
- {
- return R_CL;
- }
- if(*s == 'x')
- {
- if(!strcmp(s, "xmm0"))
- return R_XMM0;
- }
- else if(*s == 'r' && s[1])
- {
- ++s;
- if(s[1] == 'x')
- {
- switch(*s++)
- {
- case 'a': return R_RAX;
- case 'b': return R_RBX;
- case 'c': return R_RCX;
- case 'd': return R_RDX;
- }
- }
- else if(s[1] == 'i')
- {
- switch(*s++)
- {
- case 's': return R_RSI;
- case 'd': return R_RDI;
- }
- }
- else if(s[0] == 's' && s[1] == 'p' && !s[2])
- {
- return R_RSP;
- }
- else if(*s == '8' && !s[1])
- return R_R8;
- else if(*s == '9' && !s[1])
- return R_R9;
- else if(*s == '1' && s[1] == '0')
- return R_R10;
- else if(*s == '1' && s[1] == '5')
- return R_R15;
- }
- else if(*s == 'e' && s[1])
- {
- ++s;
- if(s[1] == 'x')
- {
- switch(*s++)
- {
- case 'a': return R_EAX;
- case 'b': return R_EBX;
- case 'c': return R_ECX;
- case 'd': return R_EDX;
- }
- }
- else if(s[1] == 'i')
- {
- switch(*s++)
- {
- case 's': return R_ESI;
- case 'd': return R_EDI;
- }
- }
- }
-
- crap("invalid register %s", str);
-
- return 0;
-}
-
-typedef enum {
- TOK_LABEL = 0x80,
- TOK_INT = 0x81,
- TOK_END = 0x82,
- TOK_INVALID = 0x83,
-} token_t;
-
-static unsigned char nexttok(const char** str, char* label, u64* val)
-{
- const char* s = *str;
-
- if(label) *label = 0;
- if(val) *val = 0;
-
- while(*s && *s == ' ') ++s;
-
- if(!*s)
- {
- return TOK_END;
- }
- else if(*s == '$' || *s == '*' || *s == '%' || *s == '-' || *s == ')' || *s == '(' || *s == ',')
- {
- *str = s+1;
- return *s;
- }
- else if(*s >= 'a' && *s <= 'z')
- {
- size_t a = strspn(s+1, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_");
- if(a+1 >= LABELLEN)
- crap("label %s too long", s);
- if(label)
- {
- strncpy(label, s, a+1);
- label[a+1] = 0;
- }
- *str = s+a+1;
- return TOK_LABEL;
- }
- else if(*s >= '0' && *s <= '9')
- {
- char* endptr = NULL;
- u64 v = strtol(s, &endptr, 0);
- if(endptr && (endptr-s == 0))
- crap("invalid integer %s", s);
- if(val) *val = v;
- *str = endptr;
- return TOK_INT;
- }
- crap("can't parse '%s'", *str);
- return TOK_INVALID;
-}
-
-static arg_t parsearg(const char** str)
-{
- arg_t arg;
- const char* s = *str;
- char label[20];
- u64 val;
- int negative = 1;
- unsigned ttype;
-
- arg.type = T_NONE;
- arg.absolute = 0;
-
- while(*s && *s == ' ') ++s;
-
- switch(nexttok(&s, label, &val))
- {
- case '$' :
- ttype = nexttok(&s, NULL, &val);
- if(ttype == '-')
- {
- negative = -1;
- ttype = nexttok(&s, NULL, &val);
- }
- if(ttype != TOK_INT)
- crap("expected integer");
- arg.type = T_IMMEDIATE;
- arg.v.imm = negative * val;
- break;
- case '*' :
- if((ttype = nexttok(&s, NULL, NULL)) != '%')
- {
- if(ttype == '(')
- goto tok_memory;
- crap("expected '%%'");
- }
- arg.absolute = 1;
- /* fall through */
- case '%' :
- if(nexttok(&s, label, &val) != TOK_LABEL)
- crap("expected label");
- arg.type = T_REGISTER;
- arg.v.reg = parsereg(label);
- break;
- case TOK_LABEL:
- arg.type = T_LABEL;
- strncpy(arg.v.label, label, LABELLEN);
- break;
- case '-':
- negative = -1;
- if(nexttok(&s, NULL, &val) != TOK_INT)
- crap("expected integer");
- /* fall through */
- case TOK_INT:
- if(nexttok(&s, label, NULL) != '(')
- crap("expected '('"); // mov to/from fixed address not supported
- /* fall through */
- case '(':
-tok_memory:
- arg.type = T_MEMORY;
- arg.v.mem.indextype = T_NONE;
- arg.v.mem.disp = negative * val;
- ttype = nexttok(&s, label, &val);
- if(ttype == '%' && nexttok(&s, label, &val) != TOK_LABEL)
- {
- crap("expected register");
- }
- if (ttype == '%')
- {
- arg.v.mem.basetype = T_REGISTER;
- arg.v.mem.base.reg = parsereg(label);
- }
- else if (ttype == TOK_INT)
- {
- arg.v.mem.basetype = T_IMMEDIATE;
- arg.v.mem.base.imm = val;
- }
- if((ttype = nexttok(&s, NULL, NULL)) == ',')
- {
- ttype = nexttok(&s, label, &val);
- if(ttype == '%' && nexttok(&s, label, &val) != TOK_LABEL)
- {
- crap("expected register");
- }
- if (ttype == '%')
- {
- arg.v.mem.indextype = T_REGISTER;
- arg.v.mem.index.reg = parsereg(label);
- }
- else if (ttype == TOK_INT)
- {
- crap("index must be register");
- arg.v.mem.indextype = T_IMMEDIATE;
- arg.v.mem.index.imm = val;
- }
- if(nexttok(&s, NULL, NULL) != ',')
- crap("expected ','");
- if(nexttok(&s, NULL, &val) != TOK_INT)
- crap("expected integer");
- if(val != 1 && val != 2 && val != 4 && val != 8)
- crap("scale must 1, 2, 4 or 8");
- arg.v.mem.scale = val;
-
- ttype = nexttok(&s, NULL, NULL);
- }
- if(ttype != ')')
- {
- crap("expected ')' or ','");
- }
- break;
- default:
- crap("invalid token %hhu in %s", *(unsigned char*)s, *str);
- break;
- }
-
- *str = s;
-
- return arg;
-}
-
-/* ************************* */
-
-void assembler_init(int pass)
-{
- compiledOfs = 0;
- assembler_pass = pass;
- if(!pass)
- {
- labelhash_free();
- cur_line = NULL;
- }
- if(!ops_sorted)
- {
- ops_sorted = 1;
- qsort(ops, sizeof(ops)/sizeof(ops[0])-1, sizeof(ops[0]), opsort);
- }
-}
-
-size_t assembler_get_code_size(void)
-{
- return compiledOfs;
-}
-
-void assembler_set_output(char* buf)
-{
- out = buf;
-}
-
-void assemble_line(const char* input, size_t len)
-{
- char line[4096];
- char* s;
- op_t* o;
- char* opn;
- arg_t arg1, arg2;
-
- arg1.type = T_NONE;
- arg2.type = T_NONE;
- opn = NULL;
- o = NULL;
-
- if(len < 1)
- return;
-
- if(len >= sizeof(line))
- crap("line too long");
-
- memcpy(line, input, sizeof(line));
- cur_line = input;
-
- if(line[len-1] == '\n') line[--len] = 0;
- if(line[len-1] == ':')
- {
- line[--len] = 0;
- if(assembler_pass)
- debug("%s: 0x%x\n", line, compiledOfs);
- else
- hash_add_label(line, compiledOfs);
- }
- else
- {
- opn = line;
- s = strchr(line, ' ');
- if(s)
- {
- *s++ = 0;
- arg1 = parsearg((const char**)&s);
- if(*s)
- {
- if(*s != ',')
- crap("expected ',', got '%c'", *s);
- ++s;
- arg2 = parsearg((const char**)&s);
- }
- }
-
- if(!opn)
- {
- crap("no operator in %s", line);
- }
-
- o = getop(opn);
- if(!o)
- {
- crap("cannot handle op %s", opn);
- }
- o->func(opn, arg1, arg2, o->data);
- if(assembler_pass)
- debug(" - %s%s", cur_line, cur_line[strlen(cur_line)-1]=='\n'?"":"\n");
- }
-}
-
-#ifdef SA_STANDALONE
-int main(int argc, char* argv[])
-{
- char line[4096];
- size_t len;
- int pass;
- FILE* file = NULL;
-
- if(argc < 2)
- {
- crap("specify file");
- }
-
- file = fopen(argv[1], "r");
- if(!file)
- {
- crap("can't open file");
- }
-
- if(argc > 2)
- {
- fout = fopen(argv[2], "w");
- if(!fout)
- {
- crap("can't open %s for writing", argv[2]);
- }
- }
-
- for(pass = 0; pass < 2; ++pass)
- {
- if(fseek(file, 0, SEEK_SET))
- crap("can't rewind file");
-
- if(pass)
- {
- char* b = malloc(assembler_get_code_size());
- if(!b)
- crap("cannot allocate memory");
- assembler_set_output(b);
- }
-
- assembler_init(pass);
-
- while(fgets(line, sizeof(line), file))
- {
- len = strlen(line);
- if(!len) continue;
-
- assemble_line(line, len);
- }
- }
-
- assembler_init(0);
-
- fclose(file);
-
- return 0;
-}
-#endif
diff --git a/engine/code/renderer/qgl.h b/engine/code/renderer/qgl.h
deleted file mode 100644
index 5296193..0000000
--- a/engine/code/renderer/qgl.h
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-/*
-** QGL.H
-*/
-
-#ifndef __QGL_H__
-#define __QGL_H__
-
-#ifdef USE_LOCAL_HEADERS
-# include "SDL_opengl.h"
-#else
-# include <SDL_opengl.h>
-#endif
-
-extern void (APIENTRYP qglActiveTextureARB) (GLenum texture);
-extern void (APIENTRYP qglClientActiveTextureARB) (GLenum texture);
-extern void (APIENTRYP qglMultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t);
-
-extern void (APIENTRYP qglLockArraysEXT) (GLint first, GLsizei count);
-extern void (APIENTRYP qglUnlockArraysEXT) (void);
-
-
-//===========================================================================
-
-#define qglAccum glAccum
-#define qglAlphaFunc glAlphaFunc
-#define qglAreTexturesResident glAreTexturesResident
-#define qglArrayElement glArrayElement
-#define qglBegin glBegin
-#define qglBindTexture glBindTexture
-#define qglBitmap glBitmap
-#define qglBlendFunc glBlendFunc
-#define qglCallList glCallList
-#define qglCallLists glCallLists
-#define qglClear glClear
-#define qglClearAccum glClearAccum
-#define qglClearColor glClearColor
-#define qglClearDepth glClearDepth
-#define qglClearIndex glClearIndex
-#define qglClearStencil glClearStencil
-#define qglClipPlane glClipPlane
-#define qglColor3b glColor3b
-#define qglColor3bv glColor3bv
-#define qglColor3d glColor3d
-#define qglColor3dv glColor3dv
-#define qglColor3f glColor3f
-#define qglColor3fv glColor3fv
-#define qglColor3i glColor3i
-#define qglColor3iv glColor3iv
-#define qglColor3s glColor3s
-#define qglColor3sv glColor3sv
-#define qglColor3ub glColor3ub
-#define qglColor3ubv glColor3ubv
-#define qglColor3ui glColor3ui
-#define qglColor3uiv glColor3uiv
-#define qglColor3us glColor3us
-#define qglColor3usv glColor3usv
-#define qglColor4b glColor4b
-#define qglColor4bv glColor4bv
-#define qglColor4d glColor4d
-#define qglColor4dv glColor4dv
-#define qglColor4f glColor4f
-#define qglColor4fv glColor4fv
-#define qglColor4i glColor4i
-#define qglColor4iv glColor4iv
-#define qglColor4s glColor4s
-#define qglColor4sv glColor4sv
-#define qglColor4ub glColor4ub
-#define qglColor4ubv glColor4ubv
-#define qglColor4ui glColor4ui
-#define qglColor4uiv glColor4uiv
-#define qglColor4us glColor4us
-#define qglColor4usv glColor4usv
-#define qglColorMask glColorMask
-#define qglColorMaterial glColorMaterial
-#define qglColorPointer glColorPointer
-#define qglCopyPixels glCopyPixels
-#define qglCopyTexImage1D glCopyTexImage1D
-#define qglCopyTexImage2D glCopyTexImage2D
-#define qglCopyTexSubImage1D glCopyTexSubImage1D
-#define qglCopyTexSubImage2D glCopyTexSubImage2D
-#define qglCullFace glCullFace
-#define qglDeleteLists glDeleteLists
-#define qglDeleteTextures glDeleteTextures
-#define qglDepthFunc glDepthFunc
-#define qglDepthMask glDepthMask
-#define qglDepthRange glDepthRange
-#define qglDisable glDisable
-#define qglDisableClientState glDisableClientState
-#define qglDrawArrays glDrawArrays
-#define qglDrawBuffer glDrawBuffer
-#define qglDrawElements glDrawElements
-#define qglDrawPixels glDrawPixels
-#define qglEdgeFlag glEdgeFlag
-#define qglEdgeFlagPointer glEdgeFlagPointer
-#define qglEdgeFlagv glEdgeFlagv
-#define qglEnable glEnable
-#define qglEnableClientState glEnableClientState
-#define qglEnd glEnd
-#define qglEndList glEndList
-#define qglEvalCoord1d glEvalCoord1d
-#define qglEvalCoord1dv glEvalCoord1dv
-#define qglEvalCoord1f glEvalCoord1f
-#define qglEvalCoord1fv glEvalCoord1fv
-#define qglEvalCoord2d glEvalCoord2d
-#define qglEvalCoord2dv glEvalCoord2dv
-#define qglEvalCoord2f glEvalCoord2f
-#define qglEvalCoord2fv glEvalCoord2fv
-#define qglEvalMesh1 glEvalMesh1
-#define qglEvalMesh2 glEvalMesh2
-#define qglEvalPoint1 glEvalPoint1
-#define qglEvalPoint2 glEvalPoint2
-#define qglFeedbackBuffer glFeedbackBuffer
-#define qglFinish glFinish
-#define qglFlush glFlush
-#define qglFogf glFogf
-#define qglFogfv glFogfv
-#define qglFogi glFogi
-#define qglFogiv glFogiv
-#define qglFrontFace glFrontFace
-#define qglFrustum glFrustum
-#define qglGenLists glGenLists
-#define qglGenTextures glGenTextures
-#define qglGetBooleanv glGetBooleanv
-#define qglGetClipPlane glGetClipPlane
-#define qglGetDoublev glGetDoublev
-#define qglGetError glGetError
-#define qglGetFloatv glGetFloatv
-#define qglGetIntegerv glGetIntegerv
-#define qglGetLightfv glGetLightfv
-#define qglGetLightiv glGetLightiv
-#define qglGetMapdv glGetMapdv
-#define qglGetMapfv glGetMapfv
-#define qglGetMapiv glGetMapiv
-#define qglGetMaterialfv glGetMaterialfv
-#define qglGetMaterialiv glGetMaterialiv
-#define qglGetPixelMapfv glGetPixelMapfv
-#define qglGetPixelMapuiv glGetPixelMapuiv
-#define qglGetPixelMapusv glGetPixelMapusv
-#define qglGetPointerv glGetPointerv
-#define qglGetPolygonStipple glGetPolygonStipple
-#define qglGetString glGetString
-#define qglGetTexGendv glGetTexGendv
-#define qglGetTexGenfv glGetTexGenfv
-#define qglGetTexGeniv glGetTexGeniv
-#define qglGetTexImage glGetTexImage
-#define qglGetTexLevelParameterfv glGetTexLevelParameterfv
-#define qglGetTexLevelParameteriv glGetTexLevelParameteriv
-#define qglGetTexParameterfv glGetTexParameterfv
-#define qglGetTexParameteriv glGetTexParameteriv
-#define qglHint glHint
-#define qglIndexMask glIndexMask
-#define qglIndexPointer glIndexPointer
-#define qglIndexd glIndexd
-#define qglIndexdv glIndexdv
-#define qglIndexf glIndexf
-#define qglIndexfv glIndexfv
-#define qglIndexi glIndexi
-#define qglIndexiv glIndexiv
-#define qglIndexs glIndexs
-#define qglIndexsv glIndexsv
-#define qglIndexub glIndexub
-#define qglIndexubv glIndexubv
-#define qglInitNames glInitNames
-#define qglInterleavedArrays glInterleavedArrays
-#define qglIsEnabled glIsEnabled
-#define qglIsList glIsList
-#define qglIsTexture glIsTexture
-#define qglLightModelf glLightModelf
-#define qglLightModelfv glLightModelfv
-#define qglLightModeli glLightModeli
-#define qglLightModeliv glLightModeliv
-#define qglLightf glLightf
-#define qglLightfv glLightfv
-#define qglLighti glLighti
-#define qglLightiv glLightiv
-#define qglLineStipple glLineStipple
-#define qglLineWidth glLineWidth
-#define qglListBase glListBase
-#define qglLoadIdentity glLoadIdentity
-#define qglLoadMatrixd glLoadMatrixd
-#define qglLoadMatrixf glLoadMatrixf
-#define qglLoadName glLoadName
-#define qglLogicOp glLogicOp
-#define qglMap1d glMap1d
-#define qglMap1f glMap1f
-#define qglMap2d glMap2d
-#define qglMap2f glMap2f
-#define qglMapGrid1d glMapGrid1d
-#define qglMapGrid1f glMapGrid1f
-#define qglMapGrid2d glMapGrid2d
-#define qglMapGrid2f glMapGrid2f
-#define qglMaterialf glMaterialf
-#define qglMaterialfv glMaterialfv
-#define qglMateriali glMateriali
-#define qglMaterialiv glMaterialiv
-#define qglMatrixMode glMatrixMode
-#define qglMultMatrixd glMultMatrixd
-#define qglMultMatrixf glMultMatrixf
-#define qglNewList glNewList
-#define qglNormal3b glNormal3b
-#define qglNormal3bv glNormal3bv
-#define qglNormal3d glNormal3d
-#define qglNormal3dv glNormal3dv
-#define qglNormal3f glNormal3f
-#define qglNormal3fv glNormal3fv
-#define qglNormal3i glNormal3i
-#define qglNormal3iv glNormal3iv
-#define qglNormal3s glNormal3s
-#define qglNormal3sv glNormal3sv
-#define qglNormalPointer glNormalPointer
-#define qglOrtho glOrtho
-#define qglPassThrough glPassThrough
-#define qglPixelMapfv glPixelMapfv
-#define qglPixelMapuiv glPixelMapuiv
-#define qglPixelMapusv glPixelMapusv
-#define qglPixelStoref glPixelStoref
-#define qglPixelStorei glPixelStorei
-#define qglPixelTransferf glPixelTransferf
-#define qglPixelTransferi glPixelTransferi
-#define qglPixelZoom glPixelZoom
-#define qglPointSize glPointSize
-#define qglPolygonMode glPolygonMode
-#define qglPolygonOffset glPolygonOffset
-#define qglPolygonStipple glPolygonStipple
-#define qglPopAttrib glPopAttrib
-#define qglPopClientAttrib glPopClientAttrib
-#define qglPopMatrix glPopMatrix
-#define qglPopName glPopName
-#define qglPrioritizeTextures glPrioritizeTextures
-#define qglPushAttrib glPushAttrib
-#define qglPushClientAttrib glPushClientAttrib
-#define qglPushMatrix glPushMatrix
-#define qglPushName glPushName
-#define qglRasterPos2d glRasterPos2d
-#define qglRasterPos2dv glRasterPos2dv
-#define qglRasterPos2f glRasterPos2f
-#define qglRasterPos2fv glRasterPos2fv
-#define qglRasterPos2i glRasterPos2i
-#define qglRasterPos2iv glRasterPos2iv
-#define qglRasterPos2s glRasterPos2s
-#define qglRasterPos2sv glRasterPos2sv
-#define qglRasterPos3d glRasterPos3d
-#define qglRasterPos3dv glRasterPos3dv
-#define qglRasterPos3f glRasterPos3f
-#define qglRasterPos3fv glRasterPos3fv
-#define qglRasterPos3i glRasterPos3i
-#define qglRasterPos3iv glRasterPos3iv
-#define qglRasterPos3s glRasterPos3s
-#define qglRasterPos3sv glRasterPos3sv
-#define qglRasterPos4d glRasterPos4d
-#define qglRasterPos4dv glRasterPos4dv
-#define qglRasterPos4f glRasterPos4f
-#define qglRasterPos4fv glRasterPos4fv
-#define qglRasterPos4i glRasterPos4i
-#define qglRasterPos4iv glRasterPos4iv
-#define qglRasterPos4s glRasterPos4s
-#define qglRasterPos4sv glRasterPos4sv
-#define qglReadBuffer glReadBuffer
-#define qglReadPixels glReadPixels
-#define qglRectd glRectd
-#define qglRectdv glRectdv
-#define qglRectf glRectf
-#define qglRectfv glRectfv
-#define qglRecti glRecti
-#define qglRectiv glRectiv
-#define qglRects glRects
-#define qglRectsv glRectsv
-#define qglRenderMode glRenderMode
-#define qglRotated glRotated
-#define qglRotatef glRotatef
-#define qglScaled glScaled
-#define qglScalef glScalef
-#define qglScissor glScissor
-#define qglSelectBuffer glSelectBuffer
-#define qglShadeModel glShadeModel
-#define qglStencilFunc glStencilFunc
-#define qglStencilMask glStencilMask
-#define qglStencilOp glStencilOp
-#define qglTexCoord1d glTexCoord1d
-#define qglTexCoord1dv glTexCoord1dv
-#define qglTexCoord1f glTexCoord1f
-#define qglTexCoord1fv glTexCoord1fv
-#define qglTexCoord1i glTexCoord1i
-#define qglTexCoord1iv glTexCoord1iv
-#define qglTexCoord1s glTexCoord1s
-#define qglTexCoord1sv glTexCoord1sv
-#define qglTexCoord2d glTexCoord2d
-#define qglTexCoord2dv glTexCoord2dv
-#define qglTexCoord2f glTexCoord2f
-#define qglTexCoord2fv glTexCoord2fv
-#define qglTexCoord2i glTexCoord2i
-#define qglTexCoord2iv glTexCoord2iv
-#define qglTexCoord2s glTexCoord2s
-#define qglTexCoord2sv glTexCoord2sv
-#define qglTexCoord3d glTexCoord3d
-#define qglTexCoord3dv glTexCoord3dv
-#define qglTexCoord3f glTexCoord3f
-#define qglTexCoord3fv glTexCoord3fv
-#define qglTexCoord3i glTexCoord3i
-#define qglTexCoord3iv glTexCoord3iv
-#define qglTexCoord3s glTexCoord3s
-#define qglTexCoord3sv glTexCoord3sv
-#define qglTexCoord4d glTexCoord4d
-#define qglTexCoord4dv glTexCoord4dv
-#define qglTexCoord4f glTexCoord4f
-#define qglTexCoord4fv glTexCoord4fv
-#define qglTexCoord4i glTexCoord4i
-#define qglTexCoord4iv glTexCoord4iv
-#define qglTexCoord4s glTexCoord4s
-#define qglTexCoord4sv glTexCoord4sv
-#define qglTexCoordPointer glTexCoordPointer
-#define qglTexEnvf glTexEnvf
-#define qglTexEnvfv glTexEnvfv
-#define qglTexEnvi glTexEnvi
-#define qglTexEnviv glTexEnviv
-#define qglTexGend glTexGend
-#define qglTexGendv glTexGendv
-#define qglTexGenf glTexGenf
-#define qglTexGenfv glTexGenfv
-#define qglTexGeni glTexGeni
-#define qglTexGeniv glTexGeniv
-#define qglTexImage1D glTexImage1D
-#define qglTexImage2D glTexImage2D
-#define qglTexParameterf glTexParameterf
-#define qglTexParameterfv glTexParameterfv
-#define qglTexParameteri glTexParameteri
-#define qglTexParameteriv glTexParameteriv
-#define qglTexSubImage1D glTexSubImage1D
-#define qglTexSubImage2D glTexSubImage2D
-#define qglTranslated glTranslated
-#define qglTranslatef glTranslatef
-#define qglVertex2d glVertex2d
-#define qglVertex2dv glVertex2dv
-#define qglVertex2f glVertex2f
-#define qglVertex2fv glVertex2fv
-#define qglVertex2i glVertex2i
-#define qglVertex2iv glVertex2iv
-#define qglVertex2s glVertex2s
-#define qglVertex2sv glVertex2sv
-#define qglVertex3d glVertex3d
-#define qglVertex3dv glVertex3dv
-#define qglVertex3f glVertex3f
-#define qglVertex3fv glVertex3fv
-#define qglVertex3i glVertex3i
-#define qglVertex3iv glVertex3iv
-#define qglVertex3s glVertex3s
-#define qglVertex3sv glVertex3sv
-#define qglVertex4d glVertex4d
-#define qglVertex4dv glVertex4dv
-#define qglVertex4f glVertex4f
-#define qglVertex4fv glVertex4fv
-#define qglVertex4i glVertex4i
-#define qglVertex4iv glVertex4iv
-#define qglVertex4s glVertex4s
-#define qglVertex4sv glVertex4sv
-#define qglVertexPointer glVertexPointer
-#define qglViewport glViewport
-
-#endif
diff --git a/engine/code/renderer/tr_animation.c b/engine/code/renderer/tr_animation.c
deleted file mode 100644
index 8f42456..0000000
--- a/engine/code/renderer/tr_animation.c
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "tr_local.h"
-
-/*
-
-All bones should be an identity orientation to display the mesh exactly
-as it is specified.
-
-For all other frames, the bones represent the transformation from the
-orientation of the bone in the base frame to the orientation in this
-frame.
-
-*/
-
-/*
-==============
-R_AddAnimSurfaces
-==============
-*/
-void R_AddAnimSurfaces( trRefEntity_t *ent ) {
- md4Header_t *header;
- md4Surface_t *surface;
- md4LOD_t *lod;
- shader_t *shader;
- int i;
-
- header = (md4Header_t *) tr.currentModel->md4;
- lod = (md4LOD_t *)( (byte *)header + header->ofsLODs );
-
- surface = (md4Surface_t *)( (byte *)lod + lod->ofsSurfaces );
- for ( i = 0 ; i < lod->numSurfaces ; i++ ) {
- shader = R_GetShaderByHandle( surface->shaderIndex );
- R_AddDrawSurf( (void *)surface, shader, 0 /*fogNum*/, qfalse );
- surface = (md4Surface_t *)( (byte *)surface + surface->ofsEnd );
- }
-}
-
-/*
-==============
-RB_SurfaceAnim
-==============
-*/
-void RB_SurfaceAnim( md4Surface_t *surface ) {
- int i, j, k;
- float frontlerp, backlerp;
- int *triangles;
- int indexes;
- int baseIndex, baseVertex;
- int numVerts;
- md4Vertex_t *v;
- md4Bone_t bones[MD4_MAX_BONES];
- md4Bone_t *bonePtr, *bone;
- md4Header_t *header;
- md4Frame_t *frame;
- md4Frame_t *oldFrame;
- int frameSize;
-
-
- if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) {
- backlerp = 0;
- frontlerp = 1;
- } else {
- backlerp = backEnd.currentEntity->e.backlerp;
- frontlerp = 1.0f - backlerp;
- }
- header = (md4Header_t *)((byte *)surface + surface->ofsHeader);
-
- frameSize = (size_t)( &((md4Frame_t *)0)->bones[ header->numBones ] );
-
- frame = (md4Frame_t *)((byte *)header + header->ofsFrames +
- backEnd.currentEntity->e.frame * frameSize );
- oldFrame = (md4Frame_t *)((byte *)header + header->ofsFrames +
- backEnd.currentEntity->e.oldframe * frameSize );
-
- RB_CheckOverflow( surface->numVerts, surface->numTriangles * 3 );
-
- triangles = (int *) ((byte *)surface + surface->ofsTriangles);
- indexes = surface->numTriangles * 3;
- baseIndex = tess.numIndexes;
- baseVertex = tess.numVertexes;
- for (j = 0 ; j < indexes ; j++) {
- tess.indexes[baseIndex + j] = baseIndex + triangles[j];
- }
- tess.numIndexes += indexes;
-
- //
- // lerp all the needed bones
- //
- if ( !backlerp ) {
- // no lerping needed
- bonePtr = frame->bones;
- } else {
- bonePtr = bones;
- for ( i = 0 ; i < header->numBones*12 ; i++ ) {
- ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i]
- + backlerp * ((float *)oldFrame->bones)[i];
- }
- }
-
- //
- // deform the vertexes by the lerped bones
- //
- numVerts = surface->numVerts;
- // FIXME
- // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left
- // in for reference.
- //v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts + 12);
- v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts);
- for ( j = 0; j < numVerts; j++ ) {
- vec3_t tempVert, tempNormal;
- md4Weight_t *w;
-
- VectorClear( tempVert );
- VectorClear( tempNormal );
- w = v->weights;
- for ( k = 0 ; k < v->numWeights ; k++, w++ ) {
- bone = bonePtr + w->boneIndex;
-
- tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] );
- tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] );
- tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] );
-
- tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal );
- tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal );
- tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal );
- }
-
- tess.xyz[baseVertex + j][0] = tempVert[0];
- tess.xyz[baseVertex + j][1] = tempVert[1];
- tess.xyz[baseVertex + j][2] = tempVert[2];
-
- tess.normal[baseVertex + j][0] = tempNormal[0];
- tess.normal[baseVertex + j][1] = tempNormal[1];
- tess.normal[baseVertex + j][2] = tempNormal[2];
-
- tess.texCoords[baseVertex + j][0][0] = v->texCoords[0];
- tess.texCoords[baseVertex + j][0][1] = v->texCoords[1];
-
- // FIXME
- // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left
- // in for reference.
- //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 );
- v = (md4Vertex_t *)&v->weights[v->numWeights];
- }
-
- tess.numVertexes += surface->numVerts;
-}
-
-
-#ifdef RAVENMD4
-
-// copied and adapted from tr_mesh.c
-
-/*
-=============
-R_MDRCullModel
-=============
-*/
-
-static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) {
- vec3_t bounds[2];
- mdrFrame_t *oldFrame, *newFrame;
- int i, frameSize;
-
- frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
-
- // compute frame pointers
- newFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
- oldFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe);
-
- // cull bounding sphere ONLY if this is not an upscaled entity
- if ( !ent->e.nonNormalizedAxes )
- {
- if ( ent->e.frame == ent->e.oldframe )
- {
- switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
- {
- // Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend
- // we do. After all, the purpose of md4s are not that different, are they?
-
- case CULL_OUT:
- tr.pc.c_sphere_cull_md3_out++;
- return CULL_OUT;
-
- case CULL_IN:
- tr.pc.c_sphere_cull_md3_in++;
- return CULL_IN;
-
- case CULL_CLIP:
- tr.pc.c_sphere_cull_md3_clip++;
- break;
- }
- }
- else
- {
- int sphereCull, sphereCullB;
-
- sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
- if ( newFrame == oldFrame ) {
- sphereCullB = sphereCull;
- } else {
- sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
- }
-
- if ( sphereCull == sphereCullB )
- {
- if ( sphereCull == CULL_OUT )
- {
- tr.pc.c_sphere_cull_md3_out++;
- return CULL_OUT;
- }
- else if ( sphereCull == CULL_IN )
- {
- tr.pc.c_sphere_cull_md3_in++;
- return CULL_IN;
- }
- else
- {
- tr.pc.c_sphere_cull_md3_clip++;
- }
- }
- }
- }
-
- // calculate a bounding box in the current coordinate system
- for (i = 0 ; i < 3 ; i++) {
- bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
- bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
- }
-
- switch ( R_CullLocalBox( bounds ) )
- {
- case CULL_IN:
- tr.pc.c_box_cull_md3_in++;
- return CULL_IN;
- case CULL_CLIP:
- tr.pc.c_box_cull_md3_clip++;
- return CULL_CLIP;
- case CULL_OUT:
- default:
- tr.pc.c_box_cull_md3_out++;
- return CULL_OUT;
- }
-}
-
-/*
-=================
-R_MDRComputeFogNum
-
-=================
-*/
-
-int R_MDRComputeFogNum( mdrHeader_t *header, trRefEntity_t *ent ) {
- int i, j;
- fog_t *fog;
- mdrFrame_t *mdrFrame;
- vec3_t localOrigin;
- int frameSize;
-
- if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
- return 0;
- }
-
- frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
-
- // FIXME: non-normalized axis issues
- mdrFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
- VectorAdd( ent->e.origin, mdrFrame->localOrigin, localOrigin );
- for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
- fog = &tr.world->fogs[i];
- for ( j = 0 ; j < 3 ; j++ ) {
- if ( localOrigin[j] - mdrFrame->radius >= fog->bounds[1][j] ) {
- break;
- }
- if ( localOrigin[j] + mdrFrame->radius <= fog->bounds[0][j] ) {
- break;
- }
- }
- if ( j == 3 ) {
- return i;
- }
- }
-
- return 0;
-}
-
-
-/*
-==============
-R_MDRAddAnimSurfaces
-==============
-*/
-
-// much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c
-
-void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
- mdrHeader_t *header;
- mdrSurface_t *surface;
- mdrLOD_t *lod;
- shader_t *shader;
- skin_t *skin;
- int i, j;
- int lodnum = 0;
- int fogNum = 0;
- int cull;
- qboolean personalModel;
-
- header = (mdrHeader_t *) tr.currentModel->md4;
-
- personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
-
- if ( ent->e.renderfx & RF_WRAP_FRAMES )
- {
- ent->e.frame %= header->numFrames;
- ent->e.oldframe %= header->numFrames;
- }
-
- //
- // Validate the frames so there is no chance of a crash.
- // This will write directly into the entity structure, so
- // when the surfaces are rendered, they don't need to be
- // range checked again.
- //
- if ((ent->e.frame >= header->numFrames)
- || (ent->e.frame < 0)
- || (ent->e.oldframe >= header->numFrames)
- || (ent->e.oldframe < 0) )
- {
- ri.Printf( PRINT_DEVELOPER, "R_MDRAddAnimSurfaces: no such frame %d to %d for '%s'\n",
- ent->e.oldframe, ent->e.frame, tr.currentModel->name );
- ent->e.frame = 0;
- ent->e.oldframe = 0;
- }
-
- //
- // cull the entire model if merged bounding box of both frames
- // is outside the view frustum.
- //
- cull = R_MDRCullModel (header, ent);
- if ( cull == CULL_OUT ) {
- return;
- }
-
- // figure out the current LOD of the model we're rendering, and set the lod pointer respectively.
- lodnum = R_ComputeLOD(ent);
- // check whether this model has as that many LODs at all. If not, try the closest thing we got.
- if(header->numLODs <= 0)
- return;
- if(header->numLODs <= lodnum)
- lodnum = header->numLODs - 1;
-
- lod = (mdrLOD_t *)( (byte *)header + header->ofsLODs);
- for(i = 0; i < lodnum; i++)
- {
- lod = (mdrLOD_t *) ((byte *) lod + lod->ofsEnd);
- }
-
- // set up lighting
- if ( !personalModel || r_shadows->integer > 1 )
- {
- R_SetupEntityLighting( &tr.refdef, ent );
- }
-
- // fogNum?
- fogNum = R_MDRComputeFogNum( header, ent );
-
- surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces );
-
- for ( i = 0 ; i < lod->numSurfaces ; i++ )
- {
-
- if(ent->e.customShader)
- shader = R_GetShaderByHandle(ent->e.customShader);
- else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins)
- {
- skin = R_GetSkinByHandle(ent->e.customSkin);
- shader = tr.defaultShader;
-
- for(j = 0; j < skin->numSurfaces; j++)
- {
- if (!strcmp(skin->surfaces[j]->name, surface->name))
- {
- shader = skin->surfaces[j]->shader;
- break;
- }
- }
- }
- else if(surface->shaderIndex > 0)
- shader = R_GetShaderByHandle( surface->shaderIndex );
- else
- shader = tr.defaultShader;
-
- // we will add shadows even if the main object isn't visible in the view
-
- // stencil shadows can't do personal models unless I polyhedron clip
- if ( !personalModel
- && r_shadows->integer == 2
- && fogNum == 0
- && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
- && shader->sort == SS_OPAQUE )
- {
- R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse );
- }
-
- // projection shadows work fine with personal models
- if ( r_shadows->integer == 3
- && fogNum == 0
- && (ent->e.renderfx & RF_SHADOW_PLANE )
- && shader->sort == SS_OPAQUE )
- {
- R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
- }
-
- if (!personalModel)
- R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse );
-
- surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
- }
-}
-
-/*
-==============
-RB_MDRSurfaceAnim
-==============
-*/
-void RB_MDRSurfaceAnim( md4Surface_t *surface )
-{
- int i, j, k;
- float frontlerp, backlerp;
- int *triangles;
- int indexes;
- int baseIndex, baseVertex;
- int numVerts;
- mdrVertex_t *v;
- mdrHeader_t *header;
- mdrFrame_t *frame;
- mdrFrame_t *oldFrame;
- mdrBone_t bones[MD4_MAX_BONES], *bonePtr, *bone;
-
- int frameSize;
-
- // don't lerp if lerping off, or this is the only frame, or the last frame...
- //
- if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame)
- {
- backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used
- frontlerp = 1;
- }
- else
- {
- backlerp = backEnd.currentEntity->e.backlerp;
- frontlerp = 1.0f - backlerp;
- }
-
- header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader);
-
- frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
-
- frame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
- backEnd.currentEntity->e.frame * frameSize );
- oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
- backEnd.currentEntity->e.oldframe * frameSize );
-
- RB_CheckOverflow( surface->numVerts, surface->numTriangles );
-
- triangles = (int *) ((byte *)surface + surface->ofsTriangles);
- indexes = surface->numTriangles * 3;
- baseIndex = tess.numIndexes;
- baseVertex = tess.numVertexes;
-
- // Set up all triangles.
- for (j = 0 ; j < indexes ; j++)
- {
- tess.indexes[baseIndex + j] = baseVertex + triangles[j];
- }
- tess.numIndexes += indexes;
-
- //
- // lerp all the needed bones
- //
- if ( !backlerp )
- {
- // no lerping needed
- bonePtr = frame->bones;
- }
- else
- {
- bonePtr = bones;
-
- for ( i = 0 ; i < header->numBones*12 ; i++ )
- {
- ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i];
- }
- }
-
- //
- // deform the vertexes by the lerped bones
- //
- numVerts = surface->numVerts;
- v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts);
- for ( j = 0; j < numVerts; j++ )
- {
- vec3_t tempVert, tempNormal;
- mdrWeight_t *w;
-
- VectorClear( tempVert );
- VectorClear( tempNormal );
- w = v->weights;
- for ( k = 0 ; k < v->numWeights ; k++, w++ )
- {
- bone = bonePtr + w->boneIndex;
-
- tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] );
- tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] );
- tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] );
-
- tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal );
- tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal );
- tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal );
- }
-
- tess.xyz[baseVertex + j][0] = tempVert[0];
- tess.xyz[baseVertex + j][1] = tempVert[1];
- tess.xyz[baseVertex + j][2] = tempVert[2];
-
- tess.normal[baseVertex + j][0] = tempNormal[0];
- tess.normal[baseVertex + j][1] = tempNormal[1];
- tess.normal[baseVertex + j][2] = tempNormal[2];
-
- tess.texCoords[baseVertex + j][0][0] = v->texCoords[0];
- tess.texCoords[baseVertex + j][0][1] = v->texCoords[1];
-
- v = (mdrVertex_t *)&v->weights[v->numWeights];
- }
-
- tess.numVertexes += surface->numVerts;
-}
-
-
-#define MC_MASK_X ((1<<(MC_BITS_X))-1)
-#define MC_MASK_Y ((1<<(MC_BITS_Y))-1)
-#define MC_MASK_Z ((1<<(MC_BITS_Z))-1)
-#define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1)
-
-#define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2))
-
-#define MC_POS_X (0)
-#define MC_SHIFT_X (0)
-
-#define MC_POS_Y ((((MC_BITS_X))/8))
-#define MC_SHIFT_Y ((((MC_BITS_X)%8)))
-
-#define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8))
-#define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8)))
-
-#define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8))
-#define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8)))
-
-#define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8))
-#define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8)))
-
-#define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8))
-#define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8)))
-
-#define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8))
-#define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8)))
-
-#define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8))
-#define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8)))
-
-#define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8))
-#define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8)))
-
-#define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8))
-#define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8)))
-
-#define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8))
-#define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8)))
-
-#define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8))
-#define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8)))
-
-void MC_UnCompress(float mat[3][4],const unsigned char * comp)
-{
- int val;
-
- val=(int)((unsigned short *)(comp))[0];
- val-=1<<(MC_BITS_X-1);
- mat[0][3]=((float)(val))*MC_SCALE_X;
-
- val=(int)((unsigned short *)(comp))[1];
- val-=1<<(MC_BITS_Y-1);
- mat[1][3]=((float)(val))*MC_SCALE_Y;
-
- val=(int)((unsigned short *)(comp))[2];
- val-=1<<(MC_BITS_Z-1);
- mat[2][3]=((float)(val))*MC_SCALE_Z;
-
- val=(int)((unsigned short *)(comp))[3];
- val-=1<<(MC_BITS_VECT-1);
- mat[0][0]=((float)(val))*MC_SCALE_VECT;
-
- val=(int)((unsigned short *)(comp))[4];
- val-=1<<(MC_BITS_VECT-1);
- mat[0][1]=((float)(val))*MC_SCALE_VECT;
-
- val=(int)((unsigned short *)(comp))[5];
- val-=1<<(MC_BITS_VECT-1);
- mat[0][2]=((float)(val))*MC_SCALE_VECT;
-
-
- val=(int)((unsigned short *)(comp))[6];
- val-=1<<(MC_BITS_VECT-1);
- mat[1][0]=((float)(val))*MC_SCALE_VECT;
-
- val=(int)((unsigned short *)(comp))[7];
- val-=1<<(MC_BITS_VECT-1);
- mat[1][1]=((float)(val))*MC_SCALE_VECT;
-
- val=(int)((unsigned short *)(comp))[8];
- val-=1<<(MC_BITS_VECT-1);
- mat[1][2]=((float)(val))*MC_SCALE_VECT;
-
-
- val=(int)((unsigned short *)(comp))[9];
- val-=1<<(MC_BITS_VECT-1);
- mat[2][0]=((float)(val))*MC_SCALE_VECT;
-
- val=(int)((unsigned short *)(comp))[10];
- val-=1<<(MC_BITS_VECT-1);
- mat[2][1]=((float)(val))*MC_SCALE_VECT;
-
- val=(int)((unsigned short *)(comp))[11];
- val-=1<<(MC_BITS_VECT-1);
- mat[2][2]=((float)(val))*MC_SCALE_VECT;
-}
-#endif
diff --git a/engine/code/renderer/tr_backend.c b/engine/code/renderer/tr_backend.c
deleted file mode 100644
index 30c9368..0000000
--- a/engine/code/renderer/tr_backend.c
+++ /dev/null
@@ -1,1209 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "tr_local.h"
-
-backEndData_t *backEndData[SMP_FRAMES];
-backEndState_t backEnd;
-
-
-static float s_flipMatrix[16] = {
- // convert from our coordinate system (looking down X)
- // to OpenGL's coordinate system (looking down -Z)
- 0, 0, -1, 0,
- -1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 0, 1
-};
-
-
-/*
-** GL_Bind
-*/
-void GL_Bind( image_t *image ) {
- int texnum;
-
- if ( !image ) {
- ri.Printf( PRINT_WARNING, "GL_Bind: NULL image\n" );
- texnum = tr.defaultImage->texnum;
- } else {
- texnum = image->texnum;
- }
-
- if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option
- texnum = tr.dlightImage->texnum;
- }
-
- if ( glState.currenttextures[glState.currenttmu] != texnum ) {
- image->frameUsed = tr.frameCount;
- glState.currenttextures[glState.currenttmu] = texnum;
- qglBindTexture (GL_TEXTURE_2D, texnum);
- }
-}
-
-/*
-** GL_SelectTexture
-*/
-void GL_SelectTexture( int unit )
-{
- if ( glState.currenttmu == unit )
- {
- return;
- }
-
- if ( unit == 0 )
- {
- qglActiveTextureARB( GL_TEXTURE0_ARB );
- GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE0_ARB )\n" );
- qglClientActiveTextureARB( GL_TEXTURE0_ARB );
- GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE0_ARB )\n" );
- }
- else if ( unit == 1 )
- {
- qglActiveTextureARB( GL_TEXTURE1_ARB );
- GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE1_ARB )\n" );
- qglClientActiveTextureARB( GL_TEXTURE1_ARB );
- GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE1_ARB )\n" );
- } else {
- ri.Error( ERR_DROP, "GL_SelectTexture: unit = %i", unit );
- }
-
- glState.currenttmu = unit;
-}
-
-
-/*
-** GL_BindMultitexture
-*/
-void GL_BindMultitexture( image_t *image0, GLuint env0, image_t *image1, GLuint env1 ) {
- int texnum0, texnum1;
-
- texnum0 = image0->texnum;
- texnum1 = image1->texnum;
-
- if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option
- texnum0 = texnum1 = tr.dlightImage->texnum;
- }
-
- if ( glState.currenttextures[1] != texnum1 ) {
- GL_SelectTexture( 1 );
- image1->frameUsed = tr.frameCount;
- glState.currenttextures[1] = texnum1;
- qglBindTexture( GL_TEXTURE_2D, texnum1 );
- }
- if ( glState.currenttextures[0] != texnum0 ) {
- GL_SelectTexture( 0 );
- image0->frameUsed = tr.frameCount;
- glState.currenttextures[0] = texnum0;
- qglBindTexture( GL_TEXTURE_2D, texnum0 );
- }
-}
-
-
-/*
-** GL_Cull
-*/
-void GL_Cull( int cullType ) {
- if ( glState.faceCulling == cullType ) {
- return;
- }
-
- glState.faceCulling = cullType;
-
- if ( cullType == CT_TWO_SIDED )
- {
- qglDisable( GL_CULL_FACE );
- }
- else
- {
- qglEnable( GL_CULL_FACE );
-
- if ( cullType == CT_BACK_SIDED )
- {
- if ( backEnd.viewParms.isMirror )
- {
- qglCullFace( GL_FRONT );
- }
- else
- {
- qglCullFace( GL_BACK );
- }
- }
- else
- {
- if ( backEnd.viewParms.isMirror )
- {
- qglCullFace( GL_BACK );
- }
- else
- {
- qglCullFace( GL_FRONT );
- }
- }
- }
-}
-
-/*
-** GL_TexEnv
-*/
-void GL_TexEnv( int env )
-{
- if ( env == glState.texEnv[glState.currenttmu] )
- {
- return;
- }
-
- glState.texEnv[glState.currenttmu] = env;
-
-
- switch ( env )
- {
- case GL_MODULATE:
- qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
- break;
- case GL_REPLACE:
- qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
- break;
- case GL_DECAL:
- qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
- break;
- case GL_ADD:
- qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
- break;
- default:
- ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed\n", env );
- break;
- }
-}
-
-/*
-** GL_State
-**
-** This routine is responsible for setting the most commonly changed state
-** in Q3.
-*/
-void GL_State( unsigned long stateBits )
-{
- unsigned long diff = stateBits ^ glState.glStateBits;
-
- if ( !diff )
- {
- return;
- }
-
- //
- // check depthFunc bits
- //
- if ( diff & GLS_DEPTHFUNC_EQUAL )
- {
- if ( stateBits & GLS_DEPTHFUNC_EQUAL )
- {
- qglDepthFunc( GL_EQUAL );
- }
- else
- {
- qglDepthFunc( GL_LEQUAL );
- }
- }
-
- //
- // check blend bits
- //
- if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )
- {
- GLenum srcFactor, dstFactor;
-
- if ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )
- {
- switch ( stateBits & GLS_SRCBLEND_BITS )
- {
- case GLS_SRCBLEND_ZERO:
- srcFactor = GL_ZERO;
- break;
- case GLS_SRCBLEND_ONE:
- srcFactor = GL_ONE;
- break;
- case GLS_SRCBLEND_DST_COLOR:
- srcFactor = GL_DST_COLOR;
- break;
- case GLS_SRCBLEND_ONE_MINUS_DST_COLOR:
- srcFactor = GL_ONE_MINUS_DST_COLOR;
- break;
- case GLS_SRCBLEND_SRC_ALPHA:
- srcFactor = GL_SRC_ALPHA;
- break;
- case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA:
- srcFactor = GL_ONE_MINUS_SRC_ALPHA;
- break;
- case GLS_SRCBLEND_DST_ALPHA:
- srcFactor = GL_DST_ALPHA;
- break;
- case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA:
- srcFactor = GL_ONE_MINUS_DST_ALPHA;
- break;
- case GLS_SRCBLEND_ALPHA_SATURATE:
- srcFactor = GL_SRC_ALPHA_SATURATE;
- break;
- default:
- srcFactor = GL_ONE; // to get warning to shut up
- ri.Error( ERR_DROP, "GL_State: invalid src blend state bits\n" );
- break;
- }
-
- switch ( stateBits & GLS_DSTBLEND_BITS )
- {
- case GLS_DSTBLEND_ZERO:
- dstFactor = GL_ZERO;
- break;
- case GLS_DSTBLEND_ONE:
- dstFactor = GL_ONE;
- break;
- case GLS_DSTBLEND_SRC_COLOR:
- dstFactor = GL_SRC_COLOR;
- break;
- case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR:
- dstFactor = GL_ONE_MINUS_SRC_COLOR;
- break;
- case GLS_DSTBLEND_SRC_ALPHA:
- dstFactor = GL_SRC_ALPHA;
- break;
- case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA:
- dstFactor = GL_ONE_MINUS_SRC_ALPHA;
- break;
- case GLS_DSTBLEND_DST_ALPHA:
- dstFactor = GL_DST_ALPHA;
- break;
- case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA:
- dstFactor = GL_ONE_MINUS_DST_ALPHA;
- break;
- default:
- dstFactor = GL_ONE; // to get warning to shut up
- ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits\n" );
- break;
- }
-
- qglEnable( GL_BLEND );
- qglBlendFunc( srcFactor, dstFactor );
- }
- else
- {
- qglDisable( GL_BLEND );
- }
- }
-
- //
- // check depthmask
- //
- if ( diff & GLS_DEPTHMASK_TRUE )
- {
- if ( stateBits & GLS_DEPTHMASK_TRUE )
- {
- qglDepthMask( GL_TRUE );
- }
- else
- {
- qglDepthMask( GL_FALSE );
- }
- }
-
- //
- // fill/line mode
- //
- if ( diff & GLS_POLYMODE_LINE )
- {
- if ( stateBits & GLS_POLYMODE_LINE )
- {
- qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
- }
- else
- {
- qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
- }
- }
-
- //
- // depthtest
- //
- if ( diff & GLS_DEPTHTEST_DISABLE )
- {
- if ( stateBits & GLS_DEPTHTEST_DISABLE )
- {
- qglDisable( GL_DEPTH_TEST );
- }
- else
- {
- qglEnable( GL_DEPTH_TEST );
- }
- }
-
- //
- // alpha test
- //
- if ( diff & GLS_ATEST_BITS )
- {
- switch ( stateBits & GLS_ATEST_BITS )
- {
- case 0:
- qglDisable( GL_ALPHA_TEST );
- break;
- case GLS_ATEST_GT_0:
- qglEnable( GL_ALPHA_TEST );
- qglAlphaFunc( GL_GREATER, 0.0f );
- break;
- case GLS_ATEST_LT_80:
- qglEnable( GL_ALPHA_TEST );
- qglAlphaFunc( GL_LESS, 0.5f );
- break;
- case GLS_ATEST_GE_80:
- qglEnable( GL_ALPHA_TEST );
- qglAlphaFunc( GL_GEQUAL, 0.5f );
- break;
- default:
- assert( 0 );
- break;
- }
- }
-
- glState.glStateBits = stateBits;
-}
-
-
-
-/*
-================
-RB_Hyperspace
-
-A player has predicted a teleport, but hasn't arrived yet
-================
-*/
-static void RB_Hyperspace( void ) {
- float c;
-
- if ( !backEnd.isHyperspace ) {
- // do initialization shit
- }
-
- c = ( backEnd.refdef.time & 255 ) / 255.0f;
- qglClearColor( c, c, c, 1 );
- qglClear( GL_COLOR_BUFFER_BIT );
-
- backEnd.isHyperspace = qtrue;
-}
-
-
-static void SetViewportAndScissor( void ) {
- qglMatrixMode(GL_PROJECTION);
- qglLoadMatrixf( backEnd.viewParms.projectionMatrix );
- qglMatrixMode(GL_MODELVIEW);
-
- // set the window clipping
- qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY,
- backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight );
- qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY,
- backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight );
-}
-
-/*
-=================
-RB_BeginDrawingView
-
-Any mirrored or portaled views have already been drawn, so prepare
-to actually render the visible surfaces for this view
-=================
-*/
-void RB_BeginDrawingView (void) {
- int clearBits = 0;
-
- // sync with gl if needed
- if ( r_finish->integer == 1 && !glState.finishCalled ) {
- qglFinish ();
- glState.finishCalled = qtrue;
- }
- if ( r_finish->integer == 0 ) {
- glState.finishCalled = qtrue;
- }
-
- // we will need to change the projection matrix before drawing
- // 2D images again
- backEnd.projection2D = qfalse;
-
- //
- // set the modelview matrix for the viewer
- //
- SetViewportAndScissor();
-
- // ensures that depth writes are enabled for the depth clear
- GL_State( GLS_DEFAULT );
- // clear relevant buffers
- clearBits = GL_DEPTH_BUFFER_BIT;
-
- if ( r_measureOverdraw->integer || r_shadows->integer == 2 )
- {
- clearBits |= GL_STENCIL_BUFFER_BIT;
- }
- if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) )
- {
- clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used
-#ifdef _DEBUG
- qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f ); // FIXME: get color of sky
-#else
- qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky
-#endif
- }
- qglClear( clearBits );
-
- if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) )
- {
- RB_Hyperspace();
- return;
- }
- else
- {
- backEnd.isHyperspace = qfalse;
- }
-
- glState.faceCulling = -1; // force face culling to set next time
-
- // we will only draw a sun if there was sky rendered in this view
- backEnd.skyRenderedThisView = qfalse;
-
- // clip to the plane of the portal
- if ( backEnd.viewParms.isPortal ) {
- float plane[4];
- double plane2[4];
-
- plane[0] = backEnd.viewParms.portalPlane.normal[0];
- plane[1] = backEnd.viewParms.portalPlane.normal[1];
- plane[2] = backEnd.viewParms.portalPlane.normal[2];
- plane[3] = backEnd.viewParms.portalPlane.dist;
-
- plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane);
- plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane);
- plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane);
- plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3];
-
- qglLoadMatrixf( s_flipMatrix );
- qglClipPlane (GL_CLIP_PLANE0, plane2);
- qglEnable (GL_CLIP_PLANE0);
- } else {
- qglDisable (GL_CLIP_PLANE0);
- }
-}
-
-
-#define MAC_EVENT_PUMP_MSEC 5
-
-/*
-==================
-RB_RenderDrawSurfList
-==================
-*/
-void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
- shader_t *shader, *oldShader;
- int fogNum, oldFogNum;
- int entityNum, oldEntityNum;
- int dlighted, oldDlighted;
- qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair;
- int i;
- drawSurf_t *drawSurf;
- int oldSort;
- float originalTime;
-
- // save original time for entity shader offsets
- originalTime = backEnd.refdef.floatTime;
-
- // clear the z buffer, set the modelview, etc
- RB_BeginDrawingView ();
-
- // draw everything
- oldEntityNum = -1;
- backEnd.currentEntity = &tr.worldEntity;
- oldShader = NULL;
- oldFogNum = -1;
- oldDepthRange = qfalse;
- wasCrosshair = qfalse;
- oldDlighted = qfalse;
- oldSort = -1;
- depthRange = qfalse;
-
- backEnd.pc.c_surfaces += numDrawSurfs;
-
- for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) {
- if ( drawSurf->sort == oldSort ) {
- // fast path, same as previous sort
- rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
- continue;
- }
- oldSort = drawSurf->sort;
- R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );
-
- //
- // change the tess parameters if needed
- // a "entityMergable" shader is a shader that can have surfaces from seperate
- // entities merged into a single batch, like smoke and blood puff sprites
- if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted
- || ( entityNum != oldEntityNum && !shader->entityMergable ) ) {
- if (oldShader != NULL) {
- RB_EndSurface();
- }
- RB_BeginSurface( shader, fogNum );
- oldShader = shader;
- oldFogNum = fogNum;
- oldDlighted = dlighted;
- }
-
- //
- // change the modelview matrix if needed
- //
- if ( entityNum != oldEntityNum ) {
- depthRange = isCrosshair = qfalse;
-
- if ( entityNum != ENTITYNUM_WORLD ) {
- backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
- backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime;
- // we have to reset the shaderTime as well otherwise image animations start
- // from the wrong frame
- tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
-
- // set up the transformation matrix
- R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or );
-
- // set up the dynamic lighting if needed
- if ( backEnd.currentEntity->needDlights ) {
- R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );
- }
-
- if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK)
- {
- // hack the depth range to prevent view model from poking into walls
- depthRange = qtrue;
-
- if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR)
- isCrosshair = qtrue;
- }
- } else {
- backEnd.currentEntity = &tr.worldEntity;
- backEnd.refdef.floatTime = originalTime;
- backEnd.or = backEnd.viewParms.world;
- // we have to reset the shaderTime as well otherwise image animations on
- // the world (like water) continue with the wrong frame
- tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
- R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );
- }
-
- qglLoadMatrixf( backEnd.or.modelMatrix );
-
- //
- // change depthrange. Also change projection matrix so first person weapon does not look like coming
- // out of the screen.
- //
- if (oldDepthRange != depthRange || wasCrosshair != isCrosshair)
- {
- if (depthRange)
- {
- if(backEnd.viewParms.stereoFrame != STEREO_CENTER)
- {
- if(isCrosshair)
- {
- if(oldDepthRange)
- {
- // was not a crosshair but now is, change back proj matrix
- qglMatrixMode(GL_PROJECTION);
- qglLoadMatrixf(backEnd.viewParms.projectionMatrix);
- qglMatrixMode(GL_MODELVIEW);
- }
- }
- else
- {
- viewParms_t temp = backEnd.viewParms;
-
- R_SetupProjection(&temp, r_znear->value, qfalse);
-
- qglMatrixMode(GL_PROJECTION);
- qglLoadMatrixf(temp.projectionMatrix);
- qglMatrixMode(GL_MODELVIEW);
- }
- }
-
- if(!oldDepthRange)
- qglDepthRange (0, 0.3);
- }
- else
- {
- if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER)
- {
- qglMatrixMode(GL_PROJECTION);
- qglLoadMatrixf(backEnd.viewParms.projectionMatrix);
- qglMatrixMode(GL_MODELVIEW);
- }
-
- qglDepthRange (0, 1);
- }
-
- oldDepthRange = depthRange;
- wasCrosshair = isCrosshair;
- }
-
- oldEntityNum = entityNum;
- }
-
- // add the triangles for this surface
- rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
- }
-
- backEnd.refdef.floatTime = originalTime;
-
- // draw the contents of the last shader batch
- if (oldShader != NULL) {
- RB_EndSurface();
- }
-
- // go back to the world modelview matrix
- qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
- if ( depthRange ) {
- qglDepthRange (0, 1);
- }
-
-#if 0
- RB_DrawSun();
-#endif
- // darken down any stencil shadows
- RB_ShadowFinish();
-
- // add light flares on lights that aren't obscured
- RB_RenderFlares();
-}
-
-
-/*
-============================================================================
-
-RENDER BACK END THREAD FUNCTIONS
-
-============================================================================
-*/
-
-/*
-================
-RB_SetGL2D
-
-================
-*/
-void RB_SetGL2D (void) {
- backEnd.projection2D = qtrue;
-
- // set 2D virtual screen size
- qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
- qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
- qglMatrixMode(GL_PROJECTION);
- qglLoadIdentity ();
- qglOrtho (0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1);
- qglMatrixMode(GL_MODELVIEW);
- qglLoadIdentity ();
-
- GL_State( GLS_DEPTHTEST_DISABLE |
- GLS_SRCBLEND_SRC_ALPHA |
- GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
-
- qglDisable( GL_CULL_FACE );
- qglDisable( GL_CLIP_PLANE0 );
-
- // set time for 2D shaders
- backEnd.refdef.time = ri.Milliseconds();
- backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f;
-}
-
-
-/*
-=============
-RE_StretchRaw
-
-FIXME: not exactly backend
-Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
-Used for cinematics.
-=============
-*/
-void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
- int i, j;
- int start, end;
-
- if ( !tr.registered ) {
- return;
- }
- R_SyncRenderThread();
-
- // we definately want to sync every frame for the cinematics
- qglFinish();
-
- start = end = 0;
- if ( r_speeds->integer ) {
- start = ri.Milliseconds();
- }
-
- // make sure rows and cols are powers of 2
- for ( i = 0 ; ( 1 << i ) < cols ; i++ ) {
- }
- for ( j = 0 ; ( 1 << j ) < rows ; j++ ) {
- }
- if ( ( 1 << i ) != cols || ( 1 << j ) != rows) {
- ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows);
- }
-
- GL_Bind( tr.scratchImage[client] );
-
- // if the scratchImage isn't in the format we want, specify it as a new texture
- if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
- tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
- tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
- qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
- } else {
- if (dirty) {
- // otherwise, just subimage upload it so that drivers can tell we are going to be changing
- // it and don't try and do a texture compression
- qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
- }
- }
-
- if ( r_speeds->integer ) {
- end = ri.Milliseconds();
- ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start );
- }
-
- RB_SetGL2D();
-
- qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );
-
- qglBegin (GL_QUADS);
- qglTexCoord2f ( 0.5f / cols, 0.5f / rows );
- qglVertex2f (x, y);
- qglTexCoord2f ( ( cols - 0.5f ) / cols , 0.5f / rows );
- qglVertex2f (x+w, y);
- qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows );
- qglVertex2f (x+w, y+h);
- qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows );
- qglVertex2f (x, y+h);
- qglEnd ();
-}
-
-void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
-
- GL_Bind( tr.scratchImage[client] );
-
- // if the scratchImage isn't in the format we want, specify it as a new texture
- if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
- tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
- tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
- qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
- } else {
- if (dirty) {
- // otherwise, just subimage upload it so that drivers can tell we are going to be changing
- // it and don't try and do a texture compression
- qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
- }
- }
-}
-
-
-/*
-=============
-RB_SetColor
-
-=============
-*/
-const void *RB_SetColor( const void *data ) {
- const setColorCommand_t *cmd;
-
- cmd = (const setColorCommand_t *)data;
-
- backEnd.color2D[0] = cmd->color[0] * 255;
- backEnd.color2D[1] = cmd->color[1] * 255;
- backEnd.color2D[2] = cmd->color[2] * 255;
- backEnd.color2D[3] = cmd->color[3] * 255;
-
- return (const void *)(cmd + 1);
-}
-
-/*
-=============
-RB_StretchPic
-=============
-*/
-const void *RB_StretchPic ( const void *data ) {
- const stretchPicCommand_t *cmd;
- shader_t *shader;
- int numVerts, numIndexes;
-
- cmd = (const stretchPicCommand_t *)data;
-
- if ( !backEnd.projection2D ) {
- RB_SetGL2D();
- }
-
- shader = cmd->shader;
- if ( shader != tess.shader ) {
- if ( tess.numIndexes ) {
- RB_EndSurface();
- }
- backEnd.currentEntity = &backEnd.entity2D;
- RB_BeginSurface( shader, 0 );
- }
-
- RB_CHECKOVERFLOW( 4, 6 );
- numVerts = tess.numVertexes;
- numIndexes = tess.numIndexes;
-
- tess.numVertexes += 4;
- tess.numIndexes += 6;
-
- tess.indexes[ numIndexes ] = numVerts + 3;
- tess.indexes[ numIndexes + 1 ] = numVerts + 0;
- tess.indexes[ numIndexes + 2 ] = numVerts + 2;
- tess.indexes[ numIndexes + 3 ] = numVerts + 2;
- tess.indexes[ numIndexes + 4 ] = numVerts + 0;
- tess.indexes[ numIndexes + 5 ] = numVerts + 1;
-
- *(int *)tess.vertexColors[ numVerts ] =
- *(int *)tess.vertexColors[ numVerts + 1 ] =
- *(int *)tess.vertexColors[ numVerts + 2 ] =
- *(int *)tess.vertexColors[ numVerts + 3 ] = *(int *)backEnd.color2D;
-
- tess.xyz[ numVerts ][0] = cmd->x;
- tess.xyz[ numVerts ][1] = cmd->y;
- tess.xyz[ numVerts ][2] = 0;
-
- tess.texCoords[ numVerts ][0][0] = cmd->s1;
- tess.texCoords[ numVerts ][0][1] = cmd->t1;
-
- tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w;
- tess.xyz[ numVerts + 1 ][1] = cmd->y;
- tess.xyz[ numVerts + 1 ][2] = 0;
-
- tess.texCoords[ numVerts + 1 ][0][0] = cmd->s2;
- tess.texCoords[ numVerts + 1 ][0][1] = cmd->t1;
-
- tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w;
- tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h;
- tess.xyz[ numVerts + 2 ][2] = 0;
-
- tess.texCoords[ numVerts + 2 ][0][0] = cmd->s2;
- tess.texCoords[ numVerts + 2 ][0][1] = cmd->t2;
-
- tess.xyz[ numVerts + 3 ][0] = cmd->x;
- tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h;
- tess.xyz[ numVerts + 3 ][2] = 0;
-
- tess.texCoords[ numVerts + 3 ][0][0] = cmd->s1;
- tess.texCoords[ numVerts + 3 ][0][1] = cmd->t2;
-
- return (const void *)(cmd + 1);
-}
-
-
-/*
-=============
-RB_DrawSurfs
-
-=============
-*/
-const void *RB_DrawSurfs( const void *data ) {
- const drawSurfsCommand_t *cmd;
-
- // finish any 2D drawing if needed
- if ( tess.numIndexes ) {
- RB_EndSurface();
- }
-
- cmd = (const drawSurfsCommand_t *)data;
-
- backEnd.refdef = cmd->refdef;
- backEnd.viewParms = cmd->viewParms;
-
- RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs );
-
- return (const void *)(cmd + 1);
-}
-
-
-/*
-=============
-RB_DrawBuffer
-
-=============
-*/
-const void *RB_DrawBuffer( const void *data ) {
- const drawBufferCommand_t *cmd;
-
- cmd = (const drawBufferCommand_t *)data;
-
- qglDrawBuffer( cmd->buffer );
-
- // clear screen for debugging
- if ( r_clear->integer ) {
- qglClearColor( 1, 0, 0.5, 1 );
- qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
- }
-
- return (const void *)(cmd + 1);
-}
-
-/*
-===============
-RB_ShowImages
-
-Draw all the images to the screen, on top of whatever
-was there. This is used to test for texture thrashing.
-
-Also called by RE_EndRegistration
-===============
-*/
-void RB_ShowImages( void ) {
- int i;
- image_t *image;
- float x, y, w, h;
- int start, end;
-
- if ( !backEnd.projection2D ) {
- RB_SetGL2D();
- }
-
- qglClear( GL_COLOR_BUFFER_BIT );
-
- qglFinish();
-
- start = ri.Milliseconds();
-
- for ( i=0 ; i<tr.numImages ; i++ ) {
- image = tr.images[i];
-
- w = glConfig.vidWidth / 20;
- h = glConfig.vidHeight / 15;
- x = i % 20 * w;
- y = i / 20 * h;
-
- // show in proportional size in mode 2
- if ( r_showImages->integer == 2 ) {
- w *= image->uploadWidth / 512.0f;
- h *= image->uploadHeight / 512.0f;
- }
-
- GL_Bind( image );
- qglBegin (GL_QUADS);
- qglTexCoord2f( 0, 0 );
- qglVertex2f( x, y );
- qglTexCoord2f( 1, 0 );
- qglVertex2f( x + w, y );
- qglTexCoord2f( 1, 1 );
- qglVertex2f( x + w, y + h );
- qglTexCoord2f( 0, 1 );
- qglVertex2f( x, y + h );
- qglEnd();
- }
-
- qglFinish();
-
- end = ri.Milliseconds();
- ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start );
-
-}
-
-/*
-=============
-RB_ColorMask
-
-=============
-*/
-const void *RB_ColorMask(const void *data)
-{
- const colorMaskCommand_t *cmd = data;
-
- qglColorMask(cmd->rgba[0], cmd->rgba[1], cmd->rgba[2], cmd->rgba[3]);
-
- return (const void *)(cmd + 1);
-}
-
-/*
-=============
-RB_ClearDepth
-
-=============
-*/
-const void *RB_ClearDepth(const void *data)
-{
- const clearDepthCommand_t *cmd = data;
-
- if(tess.numIndexes)
- RB_EndSurface();
-
- // texture swapping test
- if (r_showImages->integer)
- RB_ShowImages();
-
- qglClear(GL_DEPTH_BUFFER_BIT);
-
- return (const void *)(cmd + 1);
-}
-
-/*
-=============
-RB_SwapBuffers
-
-=============
-*/
-const void *RB_SwapBuffers( const void *data ) {
- const swapBuffersCommand_t *cmd;
-
- // finish any 2D drawing if needed
- if ( tess.numIndexes ) {
- RB_EndSurface();
- }
-
- // texture swapping test
- if ( r_showImages->integer ) {
- RB_ShowImages();
- }
-
- cmd = (const swapBuffersCommand_t *)data;
-
- // we measure overdraw by reading back the stencil buffer and
- // counting up the number of increments that have happened
- if ( r_measureOverdraw->integer ) {
- int i;
- long sum = 0;
- unsigned char *stencilReadback;
-
- stencilReadback = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight );
- qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback );
-
- for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) {
- sum += stencilReadback[i];
- }
-
- backEnd.pc.c_overDraw += sum;
- ri.Hunk_FreeTempMemory( stencilReadback );
- }
-
-
- if ( !glState.finishCalled ) {
- qglFinish();
- }
-
- GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" );
-
- GLimp_EndFrame();
-
- backEnd.projection2D = qfalse;
-
- return (const void *)(cmd + 1);
-}
-
-/*
-====================
-RB_ExecuteRenderCommands
-
-This function will be called synchronously if running without
-smp extensions, or asynchronously by another thread.
-====================
-*/
-void RB_ExecuteRenderCommands( const void *data ) {
- int t1, t2;
-
- t1 = ri.Milliseconds ();
-
- if ( !r_smp->integer || data == backEndData[0]->commands.cmds ) {
- backEnd.smpFrame = 0;
- } else {
- backEnd.smpFrame = 1;
- }
-
- while ( 1 ) {
- switch ( *(const int *)data ) {
- case RC_SET_COLOR:
- data = RB_SetColor( data );
- break;
- case RC_STRETCH_PIC:
- data = RB_StretchPic( data );
- break;
- case RC_DRAW_SURFS:
- data = RB_DrawSurfs( data );
- break;
- case RC_DRAW_BUFFER:
- data = RB_DrawBuffer( data );
- break;
- case RC_SWAP_BUFFERS:
- data = RB_SwapBuffers( data );
- break;
- case RC_SCREENSHOT:
- data = RB_TakeScreenshotCmd( data );
- break;
- case RC_VIDEOFRAME:
- data = RB_TakeVideoFrameCmd( data );
- break;
- case RC_COLORMASK:
- data = RB_ColorMask(data);
- break;
- case RC_CLEARDEPTH:
- data = RB_ClearDepth(data);
- break;
- case RC_END_OF_LIST:
- default:
- // stop rendering on this thread
- t2 = ri.Milliseconds ();
- backEnd.pc.msec = t2 - t1;
- return;
- }
- }
-
-}
-
-
-/*
-================
-RB_RenderThread
-================
-*/
-void RB_RenderThread( void ) {
- const void *data;
-
- // wait for either a rendering command or a quit command
- while ( 1 ) {
- // sleep until we have work to do
- data = GLimp_RendererSleep();
-
- if ( !data ) {
- return; // all done, renderer is shutting down
- }
-
- renderThreadActive = qtrue;
-
- RB_ExecuteRenderCommands( data );
-
- renderThreadActive = qfalse;
- }
-}
-
diff --git a/engine/code/renderer/tr_bsp.c b/engine/code/renderer/tr_bsp.c
deleted file mode 100644
index 8e0031b..0000000
--- a/engine/code/renderer/tr_bsp.c
+++ /dev/null
@@ -1,1871 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_map.c
-
-#include "tr_local.h"
-
-/*
-
-Loads and prepares a map file for scene rendering.
-
-A single entry point:
-
-void RE_LoadWorldMap( const char *name );
-
-*/
-
-static world_t s_worldData;
-static byte *fileBase;
-
-int c_subdivisions;
-int c_gridVerts;
-
-//===============================================================================
-
-static void HSVtoRGB( float h, float s, float v, float rgb[3] )
-{
- int i;
- float f;
- float p, q, t;
-
- h *= 5;
-
- i = floor( h );
- f = h - i;
-
- p = v * ( 1 - s );
- q = v * ( 1 - s * f );
- t = v * ( 1 - s * ( 1 - f ) );
-
- switch ( i )
- {
- case 0:
- rgb[0] = v;
- rgb[1] = t;
- rgb[2] = p;
- break;
- case 1:
- rgb[0] = q;
- rgb[1] = v;
- rgb[2] = p;
- break;
- case 2:
- rgb[0] = p;
- rgb[1] = v;
- rgb[2] = t;
- break;
- case 3:
- rgb[0] = p;
- rgb[1] = q;
- rgb[2] = v;
- break;
- case 4:
- rgb[0] = t;
- rgb[1] = p;
- rgb[2] = v;
- break;
- case 5:
- rgb[0] = v;
- rgb[1] = p;
- rgb[2] = q;
- break;
- }
-}
-
-/*
-===============
-R_ColorShiftLightingBytes
-
-===============
-*/
-static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) {
- int shift, r, g, b;
-
- // shift the color data based on overbright range
- shift = r_mapOverBrightBits->integer - tr.overbrightBits;
-
- // shift the data based on overbright range
- r = in[0] << shift;
- g = in[1] << shift;
- b = in[2] << shift;
-
- // normalize by color instead of saturating to white
- if ( ( r | g | b ) > 255 ) {
- int max;
-
- max = r > g ? r : g;
- max = max > b ? max : b;
- r = r * 255 / max;
- g = g * 255 / max;
- b = b * 255 / max;
- }
-
- out[0] = r;
- out[1] = g;
- out[2] = b;
- out[3] = in[3];
-}
-
-/*
-===============
-R_LoadLightmaps
-
-===============
-*/
-#define LIGHTMAP_SIZE 128
-static void R_LoadLightmaps( lump_t *l ) {
- byte *buf, *buf_p;
- int len;
- byte image[LIGHTMAP_SIZE*LIGHTMAP_SIZE*4];
- int i, j;
- float maxIntensity = 0;
- double sumIntensity = 0;
-
- len = l->filelen;
- if ( !len ) {
- return;
- }
- buf = fileBase + l->fileofs;
-
- // we are about to upload textures
- R_SyncRenderThread();
-
- // create all the lightmaps
- tr.numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3);
- if ( tr.numLightmaps == 1 ) {
- //FIXME: HACK: maps with only one lightmap turn up fullbright for some reason.
- //this avoids this, but isn't the correct solution.
- tr.numLightmaps++;
- } else if ( tr.numLightmaps >= MAX_LIGHTMAPS ) { // 20051020 misantropia
- ri.Printf( PRINT_WARNING, "WARNING: number of lightmaps > MAX_LIGHTMAPS\n" );
- tr.numLightmaps = MAX_LIGHTMAPS;
- }
-
- // if we are in r_vertexLight mode, we don't need the lightmaps at all
- if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
- return;
- }
-
- for ( i = 0 ; i < tr.numLightmaps ; i++ ) {
- // expand the 24 bit on-disk to 32 bit
- buf_p = buf + i * LIGHTMAP_SIZE*LIGHTMAP_SIZE * 3;
-
- if ( r_lightmap->integer == 2 )
- { // color code by intensity as development tool (FIXME: check range)
- for ( j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ )
- {
- float r = buf_p[j*3+0];
- float g = buf_p[j*3+1];
- float b = buf_p[j*3+2];
- float intensity;
- float out[3] = {0.0, 0.0, 0.0};
-
- intensity = 0.33f * r + 0.685f * g + 0.063f * b;
-
- if ( intensity > 255 )
- intensity = 1.0f;
- else
- intensity /= 255.0f;
-
- if ( intensity > maxIntensity )
- maxIntensity = intensity;
-
- HSVtoRGB( intensity, 1.00, 0.50, out );
-
- image[j*4+0] = out[0] * 255;
- image[j*4+1] = out[1] * 255;
- image[j*4+2] = out[2] * 255;
- image[j*4+3] = 255;
-
- sumIntensity += intensity;
- }
- } else {
- for ( j = 0 ; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) {
- R_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] );
- image[j*4+3] = 255;
- }
- }
- tr.lightmaps[i] = R_CreateImage( va("*lightmap%d",i), image,
- LIGHTMAP_SIZE, LIGHTMAP_SIZE, qfalse, qfalse, GL_CLAMP_TO_EDGE );
- }
-
- if ( r_lightmap->integer == 2 ) {
- ri.Printf( PRINT_ALL, "Brightest lightmap value: %d\n", ( int ) ( maxIntensity * 255 ) );
- }
-}
-
-
-/*
-=================
-RE_SetWorldVisData
-
-This is called by the clipmodel subsystem so we can share the 1.8 megs of
-space in big maps...
-=================
-*/
-void RE_SetWorldVisData( const byte *vis ) {
- tr.externalVisData = vis;
-}
-
-
-/*
-=================
-R_LoadVisibility
-=================
-*/
-static void R_LoadVisibility( lump_t *l ) {
- int len;
- byte *buf;
-
- len = ( s_worldData.numClusters + 63 ) & ~63;
- s_worldData.novis = ri.Hunk_Alloc( len, h_low );
- Com_Memset( s_worldData.novis, 0xff, len );
-
- len = l->filelen;
- if ( !len ) {
- return;
- }
- buf = fileBase + l->fileofs;
-
- s_worldData.numClusters = LittleLong( ((int *)buf)[0] );
- s_worldData.clusterBytes = LittleLong( ((int *)buf)[1] );
-
- // CM_Load should have given us the vis data to share, so
- // we don't need to allocate another copy
- if ( tr.externalVisData ) {
- s_worldData.vis = tr.externalVisData;
- } else {
- byte *dest;
-
- dest = ri.Hunk_Alloc( len - 8, h_low );
- Com_Memcpy( dest, buf + 8, len - 8 );
- s_worldData.vis = dest;
- }
-}
-
-//===============================================================================
-
-
-/*
-===============
-ShaderForShaderNum
-===============
-*/
-static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) {
- shader_t *shader;
- dshader_t *dsh;
-
- shaderNum = LittleLong( shaderNum );
- if ( shaderNum < 0 || shaderNum >= s_worldData.numShaders ) {
- ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", shaderNum );
- }
- dsh = &s_worldData.shaders[ shaderNum ];
-
- if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
- lightmapNum = LIGHTMAP_BY_VERTEX;
- }
-
- if ( r_fullbright->integer ) {
- lightmapNum = LIGHTMAP_WHITEIMAGE;
- }
-
- shader = R_FindShader( dsh->shader, lightmapNum, qtrue );
-
- // if the shader had errors, just use default shader
- if ( shader->defaultShader ) {
- return tr.defaultShader;
- }
-
- return shader;
-}
-
-/*
-===============
-ParseFace
-===============
-*/
-static void ParseFace( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
- int i, j;
- srfSurfaceFace_t *cv;
- int numPoints, numIndexes;
- int lightmapNum;
- int sfaceSize, ofsIndexes;
-
- lightmapNum = LittleLong( ds->lightmapNum );
-
- // get fog volume
- surf->fogIndex = LittleLong( ds->fogNum ) + 1;
-
- // get shader value
- surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum );
- if ( r_singleShader->integer && !surf->shader->isSky ) {
- surf->shader = tr.defaultShader;
- }
-
- numPoints = LittleLong( ds->numVerts );
- if (numPoints > MAX_FACE_POINTS) {
- ri.Printf( PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numPoints);
- numPoints = MAX_FACE_POINTS;
- surf->shader = tr.defaultShader;
- }
-
- numIndexes = LittleLong( ds->numIndexes );
-
- // create the srfSurfaceFace_t
- sfaceSize = ( size_t ) &((srfSurfaceFace_t *)0)->points[numPoints];
- ofsIndexes = sfaceSize;
- sfaceSize += sizeof( int ) * numIndexes;
-
- cv = ri.Hunk_Alloc( sfaceSize, h_low );
- cv->surfaceType = SF_FACE;
- cv->numPoints = numPoints;
- cv->numIndices = numIndexes;
- cv->ofsIndices = ofsIndexes;
-
- verts += LittleLong( ds->firstVert );
- for ( i = 0 ; i < numPoints ; i++ ) {
- for ( j = 0 ; j < 3 ; j++ ) {
- cv->points[i][j] = LittleFloat( verts[i].xyz[j] );
- }
- for ( j = 0 ; j < 2 ; j++ ) {
- cv->points[i][3+j] = LittleFloat( verts[i].st[j] );
- cv->points[i][5+j] = LittleFloat( verts[i].lightmap[j] );
- }
- R_ColorShiftLightingBytes( verts[i].color, (byte *)&cv->points[i][7] );
- }
-
- indexes += LittleLong( ds->firstIndex );
- for ( i = 0 ; i < numIndexes ; i++ ) {
- ((int *)((byte *)cv + cv->ofsIndices ))[i] = LittleLong( indexes[ i ] );
- }
-
- // take the plane information from the lightmap vector
- for ( i = 0 ; i < 3 ; i++ ) {
- cv->plane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] );
- }
- cv->plane.dist = DotProduct( cv->points[0], cv->plane.normal );
- SetPlaneSignbits( &cv->plane );
- cv->plane.type = PlaneTypeForNormal( cv->plane.normal );
-
- surf->data = (surfaceType_t *)cv;
-}
-
-
-/*
-===============
-ParseMesh
-===============
-*/
-static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) {
- srfGridMesh_t *grid;
- int i, j;
- int width, height, numPoints;
- drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE];
- int lightmapNum;
- vec3_t bounds[2];
- vec3_t tmpVec;
- static surfaceType_t skipData = SF_SKIP;
-
- lightmapNum = LittleLong( ds->lightmapNum );
-
- // get fog volume
- surf->fogIndex = LittleLong( ds->fogNum ) + 1;
-
- // get shader value
- surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum );
- if ( r_singleShader->integer && !surf->shader->isSky ) {
- surf->shader = tr.defaultShader;
- }
-
- // we may have a nodraw surface, because they might still need to
- // be around for movement clipping
- if ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) {
- surf->data = &skipData;
- return;
- }
-
- width = LittleLong( ds->patchWidth );
- height = LittleLong( ds->patchHeight );
-
- verts += LittleLong( ds->firstVert );
- numPoints = width * height;
- for ( i = 0 ; i < numPoints ; i++ ) {
- for ( j = 0 ; j < 3 ; j++ ) {
- points[i].xyz[j] = LittleFloat( verts[i].xyz[j] );
- points[i].normal[j] = LittleFloat( verts[i].normal[j] );
- }
- for ( j = 0 ; j < 2 ; j++ ) {
- points[i].st[j] = LittleFloat( verts[i].st[j] );
- points[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] );
- }
- R_ColorShiftLightingBytes( verts[i].color, points[i].color );
- }
-
- // pre-tesseleate
- grid = R_SubdividePatchToGrid( width, height, points );
- surf->data = (surfaceType_t *)grid;
-
- // copy the level of detail origin, which is the center
- // of the group of all curves that must subdivide the same
- // to avoid cracking
- for ( i = 0 ; i < 3 ; i++ ) {
- bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] );
- bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] );
- }
- VectorAdd( bounds[0], bounds[1], bounds[1] );
- VectorScale( bounds[1], 0.5f, grid->lodOrigin );
- VectorSubtract( bounds[0], grid->lodOrigin, tmpVec );
- grid->lodRadius = VectorLength( tmpVec );
-}
-
-/*
-===============
-ParseTriSurf
-===============
-*/
-static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
- srfTriangles_t *tri;
- int i, j;
- int numVerts, numIndexes;
-
- // get fog volume
- surf->fogIndex = LittleLong( ds->fogNum ) + 1;
-
- // get shader
- surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );
- if ( r_singleShader->integer && !surf->shader->isSky ) {
- surf->shader = tr.defaultShader;
- }
-
- numVerts = LittleLong( ds->numVerts );
- numIndexes = LittleLong( ds->numIndexes );
-
- tri = ri.Hunk_Alloc( sizeof( *tri ) + numVerts * sizeof( tri->verts[0] )
- + numIndexes * sizeof( tri->indexes[0] ), h_low );
- tri->surfaceType = SF_TRIANGLES;
- tri->numVerts = numVerts;
- tri->numIndexes = numIndexes;
- tri->verts = (drawVert_t *)(tri + 1);
- tri->indexes = (int *)(tri->verts + tri->numVerts );
-
- surf->data = (surfaceType_t *)tri;
-
- // copy vertexes
- ClearBounds( tri->bounds[0], tri->bounds[1] );
- verts += LittleLong( ds->firstVert );
- for ( i = 0 ; i < numVerts ; i++ ) {
- for ( j = 0 ; j < 3 ; j++ ) {
- tri->verts[i].xyz[j] = LittleFloat( verts[i].xyz[j] );
- tri->verts[i].normal[j] = LittleFloat( verts[i].normal[j] );
- }
- AddPointToBounds( tri->verts[i].xyz, tri->bounds[0], tri->bounds[1] );
- for ( j = 0 ; j < 2 ; j++ ) {
- tri->verts[i].st[j] = LittleFloat( verts[i].st[j] );
- tri->verts[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] );
- }
-
- R_ColorShiftLightingBytes( verts[i].color, tri->verts[i].color );
- }
-
- // copy indexes
- indexes += LittleLong( ds->firstIndex );
- for ( i = 0 ; i < numIndexes ; i++ ) {
- tri->indexes[i] = LittleLong( indexes[i] );
- if ( tri->indexes[i] < 0 || tri->indexes[i] >= numVerts ) {
- ri.Error( ERR_DROP, "Bad index in triangle surface" );
- }
- }
-}
-
-/*
-===============
-ParseFlare
-===============
-*/
-static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
- srfFlare_t *flare;
- int i;
-
- // get fog volume
- surf->fogIndex = LittleLong( ds->fogNum ) + 1;
-
- // get shader
- surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );
- if ( r_singleShader->integer && !surf->shader->isSky ) {
- surf->shader = tr.defaultShader;
- }
-
- flare = ri.Hunk_Alloc( sizeof( *flare ), h_low );
- flare->surfaceType = SF_FLARE;
-
- surf->data = (surfaceType_t *)flare;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- flare->origin[i] = LittleFloat( ds->lightmapOrigin[i] );
- flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] );
- flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] );
- }
-}
-
-
-/*
-=================
-R_MergedWidthPoints
-
-returns true if there are grid points merged on a width edge
-=================
-*/
-int R_MergedWidthPoints(srfGridMesh_t *grid, int offset) {
- int i, j;
-
- for (i = 1; i < grid->width-1; i++) {
- for (j = i + 1; j < grid->width-1; j++) {
- if ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue;
- if ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue;
- if ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue;
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-=================
-R_MergedHeightPoints
-
-returns true if there are grid points merged on a height edge
-=================
-*/
-int R_MergedHeightPoints(srfGridMesh_t *grid, int offset) {
- int i, j;
-
- for (i = 1; i < grid->height-1; i++) {
- for (j = i + 1; j < grid->height-1; j++) {
- if ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue;
- if ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue;
- if ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue;
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-=================
-R_FixSharedVertexLodError_r
-
-NOTE: never sync LoD through grid edges with merged points!
-
-FIXME: write generalized version that also avoids cracks between a patch and one that meets half way?
-=================
-*/
-void R_FixSharedVertexLodError_r( int start, srfGridMesh_t *grid1 ) {
- int j, k, l, m, n, offset1, offset2, touch;
- srfGridMesh_t *grid2;
-
- for ( j = start; j < s_worldData.numsurfaces; j++ ) {
- //
- grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data;
- // if this surface is not a grid
- if ( grid2->surfaceType != SF_GRID ) continue;
- // if the LOD errors are already fixed for this patch
- if ( grid2->lodFixed == 2 ) continue;
- // grids in the same LOD group should have the exact same lod radius
- if ( grid1->lodRadius != grid2->lodRadius ) continue;
- // grids in the same LOD group should have the exact same lod origin
- if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue;
- if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue;
- if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue;
- //
- touch = qfalse;
- for (n = 0; n < 2; n++) {
- //
- if (n) offset1 = (grid1->height-1) * grid1->width;
- else offset1 = 0;
- if (R_MergedWidthPoints(grid1, offset1)) continue;
- for (k = 1; k < grid1->width-1; k++) {
- for (m = 0; m < 2; m++) {
-
- if (m) offset2 = (grid2->height-1) * grid2->width;
- else offset2 = 0;
- if (R_MergedWidthPoints(grid2, offset2)) continue;
- for ( l = 1; l < grid2->width-1; l++) {
- //
- if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;
- if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;
- if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;
- // ok the points are equal and should have the same lod error
- grid2->widthLodError[l] = grid1->widthLodError[k];
- touch = qtrue;
- }
- }
- for (m = 0; m < 2; m++) {
-
- if (m) offset2 = grid2->width-1;
- else offset2 = 0;
- if (R_MergedHeightPoints(grid2, offset2)) continue;
- for ( l = 1; l < grid2->height-1; l++) {
- //
- if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;
- if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;
- if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;
- // ok the points are equal and should have the same lod error
- grid2->heightLodError[l] = grid1->widthLodError[k];
- touch = qtrue;
- }
- }
- }
- }
- for (n = 0; n < 2; n++) {
- //
- if (n) offset1 = grid1->width-1;
- else offset1 = 0;
- if (R_MergedHeightPoints(grid1, offset1)) continue;
- for (k = 1; k < grid1->height-1; k++) {
- for (m = 0; m < 2; m++) {
-
- if (m) offset2 = (grid2->height-1) * grid2->width;
- else offset2 = 0;
- if (R_MergedWidthPoints(grid2, offset2)) continue;
- for ( l = 1; l < grid2->width-1; l++) {
- //
- if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;
- if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;
- if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;
- // ok the points are equal and should have the same lod error
- grid2->widthLodError[l] = grid1->heightLodError[k];
- touch = qtrue;
- }
- }
- for (m = 0; m < 2; m++) {
-
- if (m) offset2 = grid2->width-1;
- else offset2 = 0;
- if (R_MergedHeightPoints(grid2, offset2)) continue;
- for ( l = 1; l < grid2->height-1; l++) {
- //
- if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;
- if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;
- if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;
- // ok the points are equal and should have the same lod error
- grid2->heightLodError[l] = grid1->heightLodError[k];
- touch = qtrue;
- }
- }
- }
- }
- if (touch) {
- grid2->lodFixed = 2;
- R_FixSharedVertexLodError_r ( start, grid2 );
- //NOTE: this would be correct but makes things really slow
- //grid2->lodFixed = 1;
- }
- }
-}
-
-/*
-=================
-R_FixSharedVertexLodError
-
-This function assumes that all patches in one group are nicely stitched together for the highest LoD.
-If this is not the case this function will still do its job but won't fix the highest LoD cracks.
-=================
-*/
-void R_FixSharedVertexLodError( void ) {
- int i;
- srfGridMesh_t *grid1;
-
- for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
- //
- grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data;
- // if this surface is not a grid
- if ( grid1->surfaceType != SF_GRID )
- continue;
- //
- if ( grid1->lodFixed )
- continue;
- //
- grid1->lodFixed = 2;
- // recursively fix other patches in the same LOD group
- R_FixSharedVertexLodError_r( i + 1, grid1);
- }
-}
-
-
-/*
-===============
-R_StitchPatches
-===============
-*/
-int R_StitchPatches( int grid1num, int grid2num ) {
- float *v1, *v2;
- srfGridMesh_t *grid1, *grid2;
- int k, l, m, n, offset1, offset2, row, column;
-
- grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data;
- grid2 = (srfGridMesh_t *) s_worldData.surfaces[grid2num].data;
- for (n = 0; n < 2; n++) {
- //
- if (n) offset1 = (grid1->height-1) * grid1->width;
- else offset1 = 0;
- if (R_MergedWidthPoints(grid1, offset1))
- continue;
- for (k = 0; k < grid1->width-2; k += 2) {
-
- for (m = 0; m < 2; m++) {
-
- if ( grid2->width >= MAX_GRID_SIZE )
- break;
- if (m) offset2 = (grid2->height-1) * grid2->width;
- else offset2 = 0;
- for ( l = 0; l < grid2->width-1; l++) {
- //
- v1 = grid1->verts[k + offset1].xyz;
- v2 = grid2->verts[l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[k + 2 + offset1].xyz;
- v2 = grid2->verts[l + 1 + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[l + offset2].xyz;
- v2 = grid2->verts[l + 1 + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert column into grid2 right after after column l
- if (m) row = grid2->height-1;
- else row = 0;
- grid2 = R_GridInsertColumn( grid2, l+1, row,
- grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- for (m = 0; m < 2; m++) {
-
- if (grid2->height >= MAX_GRID_SIZE)
- break;
- if (m) offset2 = grid2->width-1;
- else offset2 = 0;
- for ( l = 0; l < grid2->height-1; l++) {
- //
- v1 = grid1->verts[k + offset1].xyz;
- v2 = grid2->verts[grid2->width * l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[k + 2 + offset1].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[grid2->width * l + offset2].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert row into grid2 right after after row l
- if (m) column = grid2->width-1;
- else column = 0;
- grid2 = R_GridInsertRow( grid2, l+1, column,
- grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- }
- }
- for (n = 0; n < 2; n++) {
- //
- if (n) offset1 = grid1->width-1;
- else offset1 = 0;
- if (R_MergedHeightPoints(grid1, offset1))
- continue;
- for (k = 0; k < grid1->height-2; k += 2) {
- for (m = 0; m < 2; m++) {
-
- if ( grid2->width >= MAX_GRID_SIZE )
- break;
- if (m) offset2 = (grid2->height-1) * grid2->width;
- else offset2 = 0;
- for ( l = 0; l < grid2->width-1; l++) {
- //
- v1 = grid1->verts[grid1->width * k + offset1].xyz;
- v2 = grid2->verts[l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
- v2 = grid2->verts[l + 1 + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[l + offset2].xyz;
- v2 = grid2->verts[(l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert column into grid2 right after after column l
- if (m) row = grid2->height-1;
- else row = 0;
- grid2 = R_GridInsertColumn( grid2, l+1, row,
- grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- for (m = 0; m < 2; m++) {
-
- if (grid2->height >= MAX_GRID_SIZE)
- break;
- if (m) offset2 = grid2->width-1;
- else offset2 = 0;
- for ( l = 0; l < grid2->height-1; l++) {
- //
- v1 = grid1->verts[grid1->width * k + offset1].xyz;
- v2 = grid2->verts[grid2->width * l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[grid2->width * l + offset2].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert row into grid2 right after after row l
- if (m) column = grid2->width-1;
- else column = 0;
- grid2 = R_GridInsertRow( grid2, l+1, column,
- grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- }
- }
- for (n = 0; n < 2; n++) {
- //
- if (n) offset1 = (grid1->height-1) * grid1->width;
- else offset1 = 0;
- if (R_MergedWidthPoints(grid1, offset1))
- continue;
- for (k = grid1->width-1; k > 1; k -= 2) {
-
- for (m = 0; m < 2; m++) {
-
- if ( grid2->width >= MAX_GRID_SIZE )
- break;
- if (m) offset2 = (grid2->height-1) * grid2->width;
- else offset2 = 0;
- for ( l = 0; l < grid2->width-1; l++) {
- //
- v1 = grid1->verts[k + offset1].xyz;
- v2 = grid2->verts[l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[k - 2 + offset1].xyz;
- v2 = grid2->verts[l + 1 + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[l + offset2].xyz;
- v2 = grid2->verts[(l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert column into grid2 right after after column l
- if (m) row = grid2->height-1;
- else row = 0;
- grid2 = R_GridInsertColumn( grid2, l+1, row,
- grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- for (m = 0; m < 2; m++) {
-
- if (grid2->height >= MAX_GRID_SIZE)
- break;
- if (m) offset2 = grid2->width-1;
- else offset2 = 0;
- for ( l = 0; l < grid2->height-1; l++) {
- //
- v1 = grid1->verts[k + offset1].xyz;
- v2 = grid2->verts[grid2->width * l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[k - 2 + offset1].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[grid2->width * l + offset2].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert row into grid2 right after after row l
- if (m) column = grid2->width-1;
- else column = 0;
- grid2 = R_GridInsertRow( grid2, l+1, column,
- grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]);
- if (!grid2)
- break;
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- }
- }
- for (n = 0; n < 2; n++) {
- //
- if (n) offset1 = grid1->width-1;
- else offset1 = 0;
- if (R_MergedHeightPoints(grid1, offset1))
- continue;
- for (k = grid1->height-1; k > 1; k -= 2) {
- for (m = 0; m < 2; m++) {
-
- if ( grid2->width >= MAX_GRID_SIZE )
- break;
- if (m) offset2 = (grid2->height-1) * grid2->width;
- else offset2 = 0;
- for ( l = 0; l < grid2->width-1; l++) {
- //
- v1 = grid1->verts[grid1->width * k + offset1].xyz;
- v2 = grid2->verts[l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;
- v2 = grid2->verts[l + 1 + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[l + offset2].xyz;
- v2 = grid2->verts[(l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert column into grid2 right after after column l
- if (m) row = grid2->height-1;
- else row = 0;
- grid2 = R_GridInsertColumn( grid2, l+1, row,
- grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- for (m = 0; m < 2; m++) {
-
- if (grid2->height >= MAX_GRID_SIZE)
- break;
- if (m) offset2 = grid2->width-1;
- else offset2 = 0;
- for ( l = 0; l < grid2->height-1; l++) {
- //
- v1 = grid1->verts[grid1->width * k + offset1].xyz;
- v2 = grid2->verts[grid2->width * l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[grid2->width * l + offset2].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert row into grid2 right after after row l
- if (m) column = grid2->width-1;
- else column = 0;
- grid2 = R_GridInsertRow( grid2, l+1, column,
- grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- }
- }
- return qfalse;
-}
-
-/*
-===============
-R_TryStitchPatch
-
-This function will try to stitch patches in the same LoD group together for the highest LoD.
-
-Only single missing vertice cracks will be fixed.
-
-Vertices will be joined at the patch side a crack is first found, at the other side
-of the patch (on the same row or column) the vertices will not be joined and cracks
-might still appear at that side.
-===============
-*/
-int R_TryStitchingPatch( int grid1num ) {
- int j, numstitches;
- srfGridMesh_t *grid1, *grid2;
-
- numstitches = 0;
- grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data;
- for ( j = 0; j < s_worldData.numsurfaces; j++ ) {
- //
- grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data;
- // if this surface is not a grid
- if ( grid2->surfaceType != SF_GRID ) continue;
- // grids in the same LOD group should have the exact same lod radius
- if ( grid1->lodRadius != grid2->lodRadius ) continue;
- // grids in the same LOD group should have the exact same lod origin
- if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue;
- if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue;
- if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue;
- //
- while (R_StitchPatches(grid1num, j))
- {
- numstitches++;
- }
- }
- return numstitches;
-}
-
-/*
-===============
-R_StitchAllPatches
-===============
-*/
-void R_StitchAllPatches( void ) {
- int i, stitched, numstitches;
- srfGridMesh_t *grid1;
-
- numstitches = 0;
- do
- {
- stitched = qfalse;
- for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
- //
- grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data;
- // if this surface is not a grid
- if ( grid1->surfaceType != SF_GRID )
- continue;
- //
- if ( grid1->lodStitched )
- continue;
- //
- grid1->lodStitched = qtrue;
- stitched = qtrue;
- //
- numstitches += R_TryStitchingPatch( i );
- }
- }
- while (stitched);
- ri.Printf( PRINT_ALL, "stitched %d LoD cracks\n", numstitches );
-}
-
-/*
-===============
-R_MovePatchSurfacesToHunk
-===============
-*/
-void R_MovePatchSurfacesToHunk(void) {
- int i, size;
- srfGridMesh_t *grid, *hunkgrid;
-
- for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
- //
- grid = (srfGridMesh_t *) s_worldData.surfaces[i].data;
- // if this surface is not a grid
- if ( grid->surfaceType != SF_GRID )
- continue;
- //
- size = (grid->width * grid->height - 1) * sizeof( drawVert_t ) + sizeof( *grid );
- hunkgrid = ri.Hunk_Alloc( size, h_low );
- Com_Memcpy(hunkgrid, grid, size);
-
- hunkgrid->widthLodError = ri.Hunk_Alloc( grid->width * 4, h_low );
- Com_Memcpy( hunkgrid->widthLodError, grid->widthLodError, grid->width * 4 );
-
- hunkgrid->heightLodError = ri.Hunk_Alloc( grid->height * 4, h_low );
- Com_Memcpy( hunkgrid->heightLodError, grid->heightLodError, grid->height * 4 );
-
- R_FreeSurfaceGridMesh( grid );
-
- s_worldData.surfaces[i].data = (void *) hunkgrid;
- }
-}
-
-/*
-===============
-R_LoadSurfaces
-===============
-*/
-static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) {
- dsurface_t *in;
- msurface_t *out;
- drawVert_t *dv;
- int *indexes;
- int count;
- int numFaces, numMeshes, numTriSurfs, numFlares;
- int i;
-
- numFaces = 0;
- numMeshes = 0;
- numTriSurfs = 0;
- numFlares = 0;
-
- in = (void *)(fileBase + surfs->fileofs);
- if (surfs->filelen % sizeof(*in))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- count = surfs->filelen / sizeof(*in);
-
- dv = (void *)(fileBase + verts->fileofs);
- if (verts->filelen % sizeof(*dv))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
-
- indexes = (void *)(fileBase + indexLump->fileofs);
- if ( indexLump->filelen % sizeof(*indexes))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
-
- out = ri.Hunk_Alloc ( count * sizeof(*out), h_low );
-
- s_worldData.surfaces = out;
- s_worldData.numsurfaces = count;
-
- for ( i = 0 ; i < count ; i++, in++, out++ ) {
- switch ( LittleLong( in->surfaceType ) ) {
- case MST_PATCH:
- ParseMesh ( in, dv, out );
- numMeshes++;
- break;
- case MST_TRIANGLE_SOUP:
- ParseTriSurf( in, dv, out, indexes );
- numTriSurfs++;
- break;
- case MST_PLANAR:
- ParseFace( in, dv, out, indexes );
- numFaces++;
- break;
- case MST_FLARE:
- ParseFlare( in, dv, out, indexes );
- numFlares++;
- break;
- default:
- ri.Error( ERR_DROP, "Bad surfaceType" );
- }
- }
-
-#ifdef PATCH_STITCHING
- R_StitchAllPatches();
-#endif
-
- R_FixSharedVertexLodError();
-
-#ifdef PATCH_STITCHING
- R_MovePatchSurfacesToHunk();
-#endif
-
- ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n",
- numFaces, numMeshes, numTriSurfs, numFlares );
-}
-
-
-
-/*
-=================
-R_LoadSubmodels
-=================
-*/
-static void R_LoadSubmodels( lump_t *l ) {
- dmodel_t *in;
- bmodel_t *out;
- int i, j, count;
-
- in = (void *)(fileBase + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- count = l->filelen / sizeof(*in);
-
- s_worldData.bmodels = out = ri.Hunk_Alloc( count * sizeof(*out), h_low );
-
- for ( i=0 ; i<count ; i++, in++, out++ ) {
- model_t *model;
-
- model = R_AllocModel();
-
- assert( model != NULL ); // this should never happen
- if ( model == NULL ) {
- ri.Error(ERR_DROP, "R_LoadSubmodels: R_AllocModel() failed");
- }
-
- model->type = MOD_BRUSH;
- model->bmodel = out;
- Com_sprintf( model->name, sizeof( model->name ), "*%d", i );
-
- for (j=0 ; j<3 ; j++) {
- out->bounds[0][j] = LittleFloat (in->mins[j]);
- out->bounds[1][j] = LittleFloat (in->maxs[j]);
- }
-
- out->firstSurface = s_worldData.surfaces + LittleLong( in->firstSurface );
- out->numSurfaces = LittleLong( in->numSurfaces );
- }
-}
-
-
-
-//==================================================================
-
-/*
-=================
-R_SetParent
-=================
-*/
-static void R_SetParent (mnode_t *node, mnode_t *parent)
-{
- node->parent = parent;
- if (node->contents != -1)
- return;
- R_SetParent (node->children[0], node);
- R_SetParent (node->children[1], node);
-}
-
-/*
-=================
-R_LoadNodesAndLeafs
-=================
-*/
-static void R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump) {
- int i, j, p;
- dnode_t *in;
- dleaf_t *inLeaf;
- mnode_t *out;
- int numNodes, numLeafs;
-
- in = (void *)(fileBase + nodeLump->fileofs);
- if (nodeLump->filelen % sizeof(dnode_t) ||
- leafLump->filelen % sizeof(dleaf_t) ) {
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- }
- numNodes = nodeLump->filelen / sizeof(dnode_t);
- numLeafs = leafLump->filelen / sizeof(dleaf_t);
-
- out = ri.Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), h_low);
-
- s_worldData.nodes = out;
- s_worldData.numnodes = numNodes + numLeafs;
- s_worldData.numDecisionNodes = numNodes;
-
- // load nodes
- for ( i=0 ; i<numNodes; i++, in++, out++)
- {
- for (j=0 ; j<3 ; j++)
- {
- out->mins[j] = LittleLong (in->mins[j]);
- out->maxs[j] = LittleLong (in->maxs[j]);
- }
-
- p = LittleLong(in->planeNum);
- out->plane = s_worldData.planes + p;
-
- out->contents = CONTENTS_NODE; // differentiate from leafs
-
- for (j=0 ; j<2 ; j++)
- {
- p = LittleLong (in->children[j]);
- if (p >= 0)
- out->children[j] = s_worldData.nodes + p;
- else
- out->children[j] = s_worldData.nodes + numNodes + (-1 - p);
- }
- }
-
- // load leafs
- inLeaf = (void *)(fileBase + leafLump->fileofs);
- for ( i=0 ; i<numLeafs ; i++, inLeaf++, out++)
- {
- for (j=0 ; j<3 ; j++)
- {
- out->mins[j] = LittleLong (inLeaf->mins[j]);
- out->maxs[j] = LittleLong (inLeaf->maxs[j]);
- }
-
- out->cluster = LittleLong(inLeaf->cluster);
- out->area = LittleLong(inLeaf->area);
-
- if ( out->cluster >= s_worldData.numClusters ) {
- s_worldData.numClusters = out->cluster + 1;
- }
-
- out->firstmarksurface = s_worldData.marksurfaces +
- LittleLong(inLeaf->firstLeafSurface);
- out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces);
- }
-
- // chain decendants
- R_SetParent (s_worldData.nodes, NULL);
-}
-
-//=============================================================================
-
-/*
-=================
-R_LoadShaders
-=================
-*/
-static void R_LoadShaders( lump_t *l ) {
- int i, count;
- dshader_t *in, *out;
-
- in = (void *)(fileBase + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- count = l->filelen / sizeof(*in);
- out = ri.Hunk_Alloc ( count*sizeof(*out), h_low );
-
- s_worldData.shaders = out;
- s_worldData.numShaders = count;
-
- Com_Memcpy( out, in, count*sizeof(*out) );
-
- for ( i=0 ; i<count ; i++ ) {
- out[i].surfaceFlags = LittleLong( out[i].surfaceFlags );
- out[i].contentFlags = LittleLong( out[i].contentFlags );
- }
-}
-
-
-/*
-=================
-R_LoadMarksurfaces
-=================
-*/
-static void R_LoadMarksurfaces (lump_t *l)
-{
- int i, j, count;
- int *in;
- msurface_t **out;
-
- in = (void *)(fileBase + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- count = l->filelen / sizeof(*in);
- out = ri.Hunk_Alloc ( count*sizeof(*out), h_low);
-
- s_worldData.marksurfaces = out;
- s_worldData.nummarksurfaces = count;
-
- for ( i=0 ; i<count ; i++)
- {
- j = LittleLong(in[i]);
- out[i] = s_worldData.surfaces + j;
- }
-}
-
-
-/*
-=================
-R_LoadPlanes
-=================
-*/
-static void R_LoadPlanes( lump_t *l ) {
- int i, j;
- cplane_t *out;
- dplane_t *in;
- int count;
- int bits;
-
- in = (void *)(fileBase + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- count = l->filelen / sizeof(*in);
- out = ri.Hunk_Alloc ( count*2*sizeof(*out), h_low);
-
- s_worldData.planes = out;
- s_worldData.numplanes = count;
-
- for ( i=0 ; i<count ; i++, in++, out++) {
- bits = 0;
- for (j=0 ; j<3 ; j++) {
- out->normal[j] = LittleFloat (in->normal[j]);
- if (out->normal[j] < 0) {
- bits |= 1<<j;
- }
- }
-
- out->dist = LittleFloat (in->dist);
- out->type = PlaneTypeForNormal( out->normal );
- out->signbits = bits;
- }
-}
-
-/*
-=================
-R_LoadFogs
-
-=================
-*/
-static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) {
- int i;
- fog_t *out;
- dfog_t *fogs;
- dbrush_t *brushes, *brush;
- dbrushside_t *sides;
- int count, brushesCount, sidesCount;
- int sideNum;
- int planeNum;
- shader_t *shader;
- float d;
- int firstSide;
-
- fogs = (void *)(fileBase + l->fileofs);
- if (l->filelen % sizeof(*fogs)) {
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- }
- count = l->filelen / sizeof(*fogs);
-
- // create fog strucutres for them
- s_worldData.numfogs = count + 1;
- s_worldData.fogs = ri.Hunk_Alloc ( s_worldData.numfogs*sizeof(*out), h_low);
- out = s_worldData.fogs + 1;
-
- if ( !count ) {
- return;
- }
-
- brushes = (void *)(fileBase + brushesLump->fileofs);
- if (brushesLump->filelen % sizeof(*brushes)) {
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- }
- brushesCount = brushesLump->filelen / sizeof(*brushes);
-
- sides = (void *)(fileBase + sidesLump->fileofs);
- if (sidesLump->filelen % sizeof(*sides)) {
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- }
- sidesCount = sidesLump->filelen / sizeof(*sides);
-
- for ( i=0 ; i<count ; i++, fogs++) {
- out->originalBrushNumber = LittleLong( fogs->brushNum );
-
- if ( (unsigned)out->originalBrushNumber >= brushesCount ) {
- ri.Error( ERR_DROP, "fog brushNumber out of range" );
- }
- brush = brushes + out->originalBrushNumber;
-
- firstSide = LittleLong( brush->firstSide );
-
- if ( (unsigned)firstSide > sidesCount - 6 ) {
- ri.Error( ERR_DROP, "fog brush sideNumber out of range" );
- }
-
- // brushes are always sorted with the axial sides first
- sideNum = firstSide + 0;
- planeNum = LittleLong( sides[ sideNum ].planeNum );
- out->bounds[0][0] = -s_worldData.planes[ planeNum ].dist;
-
- sideNum = firstSide + 1;
- planeNum = LittleLong( sides[ sideNum ].planeNum );
- out->bounds[1][0] = s_worldData.planes[ planeNum ].dist;
-
- sideNum = firstSide + 2;
- planeNum = LittleLong( sides[ sideNum ].planeNum );
- out->bounds[0][1] = -s_worldData.planes[ planeNum ].dist;
-
- sideNum = firstSide + 3;
- planeNum = LittleLong( sides[ sideNum ].planeNum );
- out->bounds[1][1] = s_worldData.planes[ planeNum ].dist;
-
- sideNum = firstSide + 4;
- planeNum = LittleLong( sides[ sideNum ].planeNum );
- out->bounds[0][2] = -s_worldData.planes[ planeNum ].dist;
-
- sideNum = firstSide + 5;
- planeNum = LittleLong( sides[ sideNum ].planeNum );
- out->bounds[1][2] = s_worldData.planes[ planeNum ].dist;
-
- // get information from the shader for fog parameters
- shader = R_FindShader( fogs->shader, LIGHTMAP_NONE, qtrue );
-
- out->parms = shader->fogParms;
-
- out->colorInt = ColorBytes4 ( shader->fogParms.color[0] * tr.identityLight,
- shader->fogParms.color[1] * tr.identityLight,
- shader->fogParms.color[2] * tr.identityLight, 1.0 );
-
- d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque;
- out->tcScale = 1.0f / ( d * 8 );
-
- // set the gradient vector
- sideNum = LittleLong( fogs->visibleSide );
-
- if ( sideNum == -1 ) {
- out->hasSurface = qfalse;
- } else {
- out->hasSurface = qtrue;
- planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum );
- VectorSubtract( vec3_origin, s_worldData.planes[ planeNum ].normal, out->surface );
- out->surface[3] = -s_worldData.planes[ planeNum ].dist;
- }
-
- out++;
- }
-
-}
-
-
-/*
-================
-R_LoadLightGrid
-
-================
-*/
-void R_LoadLightGrid( lump_t *l ) {
- int i;
- vec3_t maxs;
- int numGridPoints;
- world_t *w;
- float *wMins, *wMaxs;
-
- w = &s_worldData;
-
- w->lightGridInverseSize[0] = 1.0f / w->lightGridSize[0];
- w->lightGridInverseSize[1] = 1.0f / w->lightGridSize[1];
- w->lightGridInverseSize[2] = 1.0f / w->lightGridSize[2];
-
- wMins = w->bmodels[0].bounds[0];
- wMaxs = w->bmodels[0].bounds[1];
-
- for ( i = 0 ; i < 3 ; i++ ) {
- w->lightGridOrigin[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] );
- maxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] );
- w->lightGridBounds[i] = (maxs[i] - w->lightGridOrigin[i])/w->lightGridSize[i] + 1;
- }
-
- numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2];
-
- if ( l->filelen != numGridPoints * 8 ) {
- ri.Printf( PRINT_WARNING, "WARNING: light grid mismatch\n" );
- w->lightGridData = NULL;
- return;
- }
-
- w->lightGridData = ri.Hunk_Alloc( l->filelen, h_low );
- Com_Memcpy( w->lightGridData, (void *)(fileBase + l->fileofs), l->filelen );
-
- // deal with overbright bits
- for ( i = 0 ; i < numGridPoints ; i++ ) {
- R_ColorShiftLightingBytes( &w->lightGridData[i*8], &w->lightGridData[i*8] );
- R_ColorShiftLightingBytes( &w->lightGridData[i*8+3], &w->lightGridData[i*8+3] );
- }
-}
-
-/*
-================
-R_LoadEntities
-================
-*/
-void R_LoadEntities( lump_t *l ) {
- char *p, *token, *s;
- char keyname[MAX_TOKEN_CHARS];
- char value[MAX_TOKEN_CHARS];
- world_t *w;
-
- w = &s_worldData;
- w->lightGridSize[0] = 64;
- w->lightGridSize[1] = 64;
- w->lightGridSize[2] = 128;
-
- p = (char *)(fileBase + l->fileofs);
-
- // store for reference by the cgame
- w->entityString = ri.Hunk_Alloc( l->filelen + 1, h_low );
- strcpy( w->entityString, p );
- w->entityParsePoint = w->entityString;
-
- token = COM_ParseExt( &p, qtrue );
- if (!*token || *token != '{') {
- return;
- }
-
- // only parse the world spawn
- while ( 1 ) {
- // parse key
- token = COM_ParseExt( &p, qtrue );
-
- if ( !*token || *token == '}' ) {
- break;
- }
- Q_strncpyz(keyname, token, sizeof(keyname));
-
- // parse value
- token = COM_ParseExt( &p, qtrue );
-
- if ( !*token || *token == '}' ) {
- break;
- }
- Q_strncpyz(value, token, sizeof(value));
-
- // check for remapping of shaders for vertex lighting
- s = "vertexremapshader";
- if (!Q_strncmp(keyname, s, strlen(s)) ) {
- s = strchr(value, ';');
- if (!s) {
- ri.Printf( PRINT_WARNING, "WARNING: no semi colon in vertexshaderremap '%s'\n", value );
- break;
- }
- *s++ = 0;
- if (r_vertexLight->integer) {
- R_RemapShader(value, s, "0");
- }
- continue;
- }
- // check for remapping of shaders
- s = "remapshader";
- if (!Q_strncmp(keyname, s, strlen(s)) ) {
- s = strchr(value, ';');
- if (!s) {
- ri.Printf( PRINT_WARNING, "WARNING: no semi colon in shaderremap '%s'\n", value );
- break;
- }
- *s++ = 0;
- R_RemapShader(value, s, "0");
- continue;
- }
- // check for a different grid size
- if (!Q_stricmp(keyname, "gridsize")) {
- sscanf(value, "%f %f %f", &w->lightGridSize[0], &w->lightGridSize[1], &w->lightGridSize[2] );
- continue;
- }
- }
-}
-
-/*
-=================
-R_GetEntityToken
-=================
-*/
-qboolean R_GetEntityToken( char *buffer, int size ) {
- const char *s;
-
- s = COM_Parse( &s_worldData.entityParsePoint );
- Q_strncpyz( buffer, s, size );
- if ( !s_worldData.entityParsePoint || !s[0] ) {
- s_worldData.entityParsePoint = s_worldData.entityString;
- return qfalse;
- } else {
- return qtrue;
- }
-}
-
-/*
-=================
-RE_LoadWorldMap
-
-Called directly from cgame
-=================
-*/
-void RE_LoadWorldMap( const char *name ) {
- int i;
- dheader_t *header;
- union {
- byte *b;
- void *v;
- } buffer;
- byte *startMarker;
-
- if ( tr.worldMapLoaded ) {
- ri.Error( ERR_DROP, "ERROR: attempted to redundantly load world map\n" );
- }
-
- // set default sun direction to be used if it isn't
- // overridden by a shader
- tr.sunDirection[0] = 0.45f;
- tr.sunDirection[1] = 0.3f;
- tr.sunDirection[2] = 0.9f;
-
- VectorNormalize( tr.sunDirection );
-
- tr.worldMapLoaded = qtrue;
-
- // load it
- ri.FS_ReadFile( name, &buffer.v );
- if ( !buffer.b ) {
- ri.Error (ERR_DROP, "RE_LoadWorldMap: %s not found", name);
- }
-
- // clear tr.world so if the level fails to load, the next
- // try will not look at the partially loaded version
- tr.world = NULL;
-
- Com_Memset( &s_worldData, 0, sizeof( s_worldData ) );
- Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) );
-
- Q_strncpyz( s_worldData.baseName, COM_SkipPath( s_worldData.name ), sizeof( s_worldData.name ) );
- COM_StripExtension(s_worldData.baseName, s_worldData.baseName, sizeof(s_worldData.baseName));
-
- startMarker = ri.Hunk_Alloc(0, h_low);
- c_gridVerts = 0;
-
- header = (dheader_t *)buffer.b;
- fileBase = (byte *)header;
-
- i = LittleLong (header->version);
- if ( i != BSP_VERSION ) {
- ri.Error (ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be %i)",
- name, i, BSP_VERSION);
- }
-
- // swap all the lumps
- for (i=0 ; i<sizeof(dheader_t)/4 ; i++) {
- ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
- }
-
- // load into heap
- R_LoadShaders( &header->lumps[LUMP_SHADERS] );
- R_LoadLightmaps( &header->lumps[LUMP_LIGHTMAPS] );
- R_LoadPlanes (&header->lumps[LUMP_PLANES]);
- R_LoadFogs( &header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES] );
- R_LoadSurfaces( &header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES] );
- R_LoadMarksurfaces (&header->lumps[LUMP_LEAFSURFACES]);
- R_LoadNodesAndLeafs (&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS]);
- R_LoadSubmodels (&header->lumps[LUMP_MODELS]);
- R_LoadVisibility( &header->lumps[LUMP_VISIBILITY] );
- R_LoadEntities( &header->lumps[LUMP_ENTITIES] );
- R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] );
-
- s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker;
-
- // only set tr.world now that we know the entire level has loaded properly
- tr.world = &s_worldData;
-
- ri.FS_FreeFile( buffer.v );
-}
-
diff --git a/engine/code/renderer/tr_cmds.c b/engine/code/renderer/tr_cmds.c
deleted file mode 100644
index 247ea73..0000000
--- a/engine/code/renderer/tr_cmds.c
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "tr_local.h"
-
-volatile renderCommandList_t *renderCommandList;
-
-volatile qboolean renderThreadActive;
-
-
-/*
-=====================
-R_PerformanceCounters
-=====================
-*/
-void R_PerformanceCounters( void ) {
- if ( !r_speeds->integer ) {
- // clear the counters even if we aren't printing
- Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
- Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
- return;
- }
-
- if (r_speeds->integer == 1) {
- ri.Printf (PRINT_ALL, "%i/%i shaders/surfs %i leafs %i verts %i/%i tris %.2f mtex %.2f dc\n",
- backEnd.pc.c_shaders, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes,
- backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3,
- R_SumOfUsedImages()/(1000000.0f), backEnd.pc.c_overDraw / (float)(glConfig.vidWidth * glConfig.vidHeight) );
- } else if (r_speeds->integer == 2) {
- ri.Printf (PRINT_ALL, "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
- tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out,
- tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out );
- ri.Printf (PRINT_ALL, "(md3) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
- tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out,
- tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out );
- } else if (r_speeds->integer == 3) {
- ri.Printf (PRINT_ALL, "viewcluster: %i\n", tr.viewCluster );
- } else if (r_speeds->integer == 4) {
- if ( backEnd.pc.c_dlightVertexes ) {
- ri.Printf (PRINT_ALL, "dlight srf:%i culled:%i verts:%i tris:%i\n",
- tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled,
- backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 );
- }
- }
- else if (r_speeds->integer == 5 )
- {
- ri.Printf( PRINT_ALL, "zFar: %.0f\n", tr.viewParms.zFar );
- }
- else if (r_speeds->integer == 6 )
- {
- ri.Printf( PRINT_ALL, "flare adds:%i tests:%i renders:%i\n",
- backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders );
- }
-
- Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
- Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
-}
-
-
-/*
-====================
-R_InitCommandBuffers
-====================
-*/
-void R_InitCommandBuffers( void ) {
- glConfig.smpActive = qfalse;
- if ( r_smp->integer ) {
- ri.Printf( PRINT_ALL, "Trying SMP acceleration...\n" );
- if ( GLimp_SpawnRenderThread( RB_RenderThread ) ) {
- ri.Printf( PRINT_ALL, "...succeeded.\n" );
- glConfig.smpActive = qtrue;
- } else {
- ri.Printf( PRINT_ALL, "...failed.\n" );
- }
- }
-}
-
-/*
-====================
-R_ShutdownCommandBuffers
-====================
-*/
-void R_ShutdownCommandBuffers( void ) {
- // kill the rendering thread
- if ( glConfig.smpActive ) {
- GLimp_WakeRenderer( NULL );
- glConfig.smpActive = qfalse;
- }
-}
-
-/*
-====================
-R_IssueRenderCommands
-====================
-*/
-int c_blockedOnRender;
-int c_blockedOnMain;
-
-void R_IssueRenderCommands( qboolean runPerformanceCounters ) {
- renderCommandList_t *cmdList;
-
- cmdList = &backEndData[tr.smpFrame]->commands;
- assert(cmdList);
- // add an end-of-list command
- *(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST;
-
- // clear it out, in case this is a sync and not a buffer flip
- cmdList->used = 0;
-
- if ( glConfig.smpActive ) {
- // if the render thread is not idle, wait for it
- if ( renderThreadActive ) {
- c_blockedOnRender++;
- if ( r_showSmp->integer ) {
- ri.Printf( PRINT_ALL, "R" );
- }
- } else {
- c_blockedOnMain++;
- if ( r_showSmp->integer ) {
- ri.Printf( PRINT_ALL, "." );
- }
- }
-
- // sleep until the renderer has completed
- GLimp_FrontEndSleep();
- }
-
- // at this point, the back end thread is idle, so it is ok
- // to look at it's performance counters
- if ( runPerformanceCounters ) {
- R_PerformanceCounters();
- }
-
- // actually start the commands going
- if ( !r_skipBackEnd->integer ) {
- // let it start on the new batch
- if ( !glConfig.smpActive ) {
- RB_ExecuteRenderCommands( cmdList->cmds );
- } else {
- GLimp_WakeRenderer( cmdList );
- }
- }
-}
-
-
-/*
-====================
-R_SyncRenderThread
-
-Issue any pending commands and wait for them to complete.
-After exiting, the render thread will have completed its work
-and will remain idle and the main thread is free to issue
-OpenGL calls until R_IssueRenderCommands is called.
-====================
-*/
-void R_SyncRenderThread( void ) {
- if ( !tr.registered ) {
- return;
- }
- R_IssueRenderCommands( qfalse );
-
- if ( !glConfig.smpActive ) {
- return;
- }
- GLimp_FrontEndSleep();
-}
-
-/*
-============
-R_GetCommandBuffer
-
-make sure there is enough command space, waiting on the
-render thread if needed.
-============
-*/
-void *R_GetCommandBuffer( int bytes ) {
- renderCommandList_t *cmdList;
-
- cmdList = &backEndData[tr.smpFrame]->commands;
-
- // always leave room for the end of list command
- if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) {
- if ( bytes > MAX_RENDER_COMMANDS - 4 ) {
- ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes );
- }
- // if we run out of room, just start dropping commands
- return NULL;
- }
-
- cmdList->used += bytes;
-
- return cmdList->cmds + cmdList->used - bytes;
-}
-
-
-/*
-=============
-R_AddDrawSurfCmd
-
-=============
-*/
-void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) {
- drawSurfsCommand_t *cmd;
-
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
- if ( !cmd ) {
- return;
- }
- cmd->commandId = RC_DRAW_SURFS;
-
- cmd->drawSurfs = drawSurfs;
- cmd->numDrawSurfs = numDrawSurfs;
-
- cmd->refdef = tr.refdef;
- cmd->viewParms = tr.viewParms;
-}
-
-
-/*
-=============
-RE_SetColor
-
-Passing NULL will set the color to white
-=============
-*/
-void RE_SetColor( const float *rgba ) {
- setColorCommand_t *cmd;
-
- if ( !tr.registered ) {
- return;
- }
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
- if ( !cmd ) {
- return;
- }
- cmd->commandId = RC_SET_COLOR;
- if ( !rgba ) {
- static float colorWhite[4] = { 1, 1, 1, 1 };
-
- rgba = colorWhite;
- }
-
- cmd->color[0] = rgba[0];
- cmd->color[1] = rgba[1];
- cmd->color[2] = rgba[2];
- cmd->color[3] = rgba[3];
-}
-
-
-/*
-=============
-RE_StretchPic
-=============
-*/
-void RE_StretchPic ( float x, float y, float w, float h,
- float s1, float t1, float s2, float t2, qhandle_t hShader ) {
- stretchPicCommand_t *cmd;
-
- if (!tr.registered) {
- return;
- }
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
- if ( !cmd ) {
- return;
- }
- cmd->commandId = RC_STRETCH_PIC;
- cmd->shader = R_GetShaderByHandle( hShader );
- cmd->x = x;
- cmd->y = y;
- cmd->w = w;
- cmd->h = h;
- cmd->s1 = s1;
- cmd->t1 = t1;
- cmd->s2 = s2;
- cmd->t2 = t2;
-}
-
-#define MODE_RED_CYAN 1
-#define MODE_RED_BLUE 2
-#define MODE_RED_GREEN 3
-#define MODE_MAX MODE_RED_GREEN
-
-void R_SetColorMode(GLboolean *rgba, stereoFrame_t stereoFrame, int colormode)
-{
- rgba[0] = rgba[1] = rgba[2] = rgba[3] = GL_TRUE;
-
- if(colormode > MODE_MAX)
- {
- if(stereoFrame == STEREO_LEFT)
- stereoFrame = STEREO_RIGHT;
- else if(stereoFrame == STEREO_RIGHT)
- stereoFrame = STEREO_LEFT;
-
- colormode -= MODE_MAX;
- }
-
- if(stereoFrame == STEREO_LEFT)
- rgba[1] = rgba[2] = GL_FALSE;
- else if(stereoFrame == STEREO_RIGHT)
- {
- rgba[0] = GL_FALSE;
-
- if(colormode == MODE_RED_BLUE)
- rgba[1] = GL_FALSE;
- else if(colormode == MODE_RED_GREEN)
- rgba[2] = GL_FALSE;
- }
-}
-
-
-/*
-====================
-RE_BeginFrame
-
-If running in stereo, RE_BeginFrame will be called twice
-for each RE_EndFrame
-====================
-*/
-void RE_BeginFrame( stereoFrame_t stereoFrame ) {
- drawBufferCommand_t *cmd = NULL;
- colorMaskCommand_t *colcmd = NULL;
-
- if ( !tr.registered ) {
- return;
- }
- glState.finishCalled = qfalse;
-
- tr.frameCount++;
- tr.frameSceneNum = 0;
-
- //
- // do overdraw measurement
- //
- if ( r_measureOverdraw->integer )
- {
- if ( glConfig.stencilBits < 4 )
- {
- ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits );
- ri.Cvar_Set( "r_measureOverdraw", "0" );
- r_measureOverdraw->modified = qfalse;
- }
- else if ( r_shadows->integer == 2 )
- {
- ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" );
- ri.Cvar_Set( "r_measureOverdraw", "0" );
- r_measureOverdraw->modified = qfalse;
- }
- else
- {
- R_SyncRenderThread();
- qglEnable( GL_STENCIL_TEST );
- qglStencilMask( ~0U );
- qglClearStencil( 0U );
- qglStencilFunc( GL_ALWAYS, 0U, ~0U );
- qglStencilOp( GL_KEEP, GL_INCR, GL_INCR );
- }
- r_measureOverdraw->modified = qfalse;
- }
- else
- {
- // this is only reached if it was on and is now off
- if ( r_measureOverdraw->modified ) {
- R_SyncRenderThread();
- qglDisable( GL_STENCIL_TEST );
- }
- r_measureOverdraw->modified = qfalse;
- }
-
- //
- // texturemode stuff
- //
- if ( r_textureMode->modified ) {
- R_SyncRenderThread();
- GL_TextureMode( r_textureMode->string );
- r_textureMode->modified = qfalse;
- }
-
- //
- // gamma stuff
- //
- if ( r_gamma->modified ) {
- r_gamma->modified = qfalse;
-
- R_SyncRenderThread();
- R_SetColorMappings();
- }
-
- // check for errors
- if ( !r_ignoreGLErrors->integer )
- {
- int err;
-
- R_SyncRenderThread();
- if ((err = qglGetError()) != GL_NO_ERROR)
- ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!\n", err);
- }
-
- if (glConfig.stereoEnabled) {
- if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
- return;
-
- cmd->commandId = RC_DRAW_BUFFER;
-
- if ( stereoFrame == STEREO_LEFT ) {
- cmd->buffer = (int)GL_BACK_LEFT;
- } else if ( stereoFrame == STEREO_RIGHT ) {
- cmd->buffer = (int)GL_BACK_RIGHT;
- } else {
- ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
- }
- }
- else
- {
- if(r_anaglyphMode->integer)
- {
- if(r_anaglyphMode->modified)
- {
- // clear both, front and backbuffer.
- qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
-
- qglDrawBuffer(GL_FRONT);
- qglClear(GL_COLOR_BUFFER_BIT);
- qglDrawBuffer(GL_BACK);
- qglClear(GL_COLOR_BUFFER_BIT);
-
- r_anaglyphMode->modified = qfalse;
- }
-
- if(stereoFrame == STEREO_LEFT)
- {
- if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
- return;
-
- if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
- return;
- }
- else if(stereoFrame == STEREO_RIGHT)
- {
- clearDepthCommand_t *cldcmd;
-
- if( !(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd))) )
- return;
-
- cldcmd->commandId = RC_CLEARDEPTH;
-
- if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
- return;
- }
- else
- ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
-
- R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer);
- colcmd->commandId = RC_COLORMASK;
- }
- else
- {
- if(stereoFrame != STEREO_CENTER)
- ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );
-
- if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
- return;
- }
-
- if(cmd)
- {
- cmd->commandId = RC_DRAW_BUFFER;
-
- if(r_anaglyphMode->modified)
- {
- qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- r_anaglyphMode->modified = qfalse;
- }
-
- if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
- cmd->buffer = (int)GL_FRONT;
- else
- cmd->buffer = (int)GL_BACK;
- }
- }
-
- tr.refdef.stereoFrame = stereoFrame;
-}
-
-
-/*
-=============
-RE_EndFrame
-
-Returns the number of msec spent in the back end
-=============
-*/
-void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
- swapBuffersCommand_t *cmd;
-
- if ( !tr.registered ) {
- return;
- }
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
- if ( !cmd ) {
- return;
- }
- cmd->commandId = RC_SWAP_BUFFERS;
-
- R_IssueRenderCommands( qtrue );
-
- // use the other buffers next frame, because another CPU
- // may still be rendering into the current ones
- R_ToggleSmpFrame();
-
- if ( frontEndMsec ) {
- *frontEndMsec = tr.frontEndMsec;
- }
- tr.frontEndMsec = 0;
- if ( backEndMsec ) {
- *backEndMsec = backEnd.pc.msec;
- }
- backEnd.pc.msec = 0;
-}
-
-/*
-=============
-RE_TakeVideoFrame
-=============
-*/
-void RE_TakeVideoFrame( int width, int height,
- byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg )
-{
- videoFrameCommand_t *cmd;
-
- if( !tr.registered ) {
- return;
- }
-
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
- if( !cmd ) {
- return;
- }
-
- cmd->commandId = RC_VIDEOFRAME;
-
- cmd->width = width;
- cmd->height = height;
- cmd->captureBuffer = captureBuffer;
- cmd->encodeBuffer = encodeBuffer;
- cmd->motionJpeg = motionJpeg;
-}
diff --git a/engine/code/renderer/tr_curve.c b/engine/code/renderer/tr_curve.c
deleted file mode 100644
index 7eb1b4c..0000000
--- a/engine/code/renderer/tr_curve.c
+++ /dev/null
@@ -1,626 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "tr_local.h"
-
-/*
-
-This file does all of the processing necessary to turn a raw grid of points
-read from the map file into a srfGridMesh_t ready for rendering.
-
-The level of detail solution is direction independent, based only on subdivided
-distance from the true curve.
-
-Only a single entry point:
-
-srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
- drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
-
-*/
-
-
-/*
-============
-LerpDrawVert
-============
-*/
-static void LerpDrawVert( drawVert_t *a, drawVert_t *b, drawVert_t *out ) {
- out->xyz[0] = 0.5f * (a->xyz[0] + b->xyz[0]);
- out->xyz[1] = 0.5f * (a->xyz[1] + b->xyz[1]);
- out->xyz[2] = 0.5f * (a->xyz[2] + b->xyz[2]);
-
- out->st[0] = 0.5f * (a->st[0] + b->st[0]);
- out->st[1] = 0.5f * (a->st[1] + b->st[1]);
-
- out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]);
- out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]);
-
- out->color[0] = (a->color[0] + b->color[0]) >> 1;
- out->color[1] = (a->color[1] + b->color[1]) >> 1;
- out->color[2] = (a->color[2] + b->color[2]) >> 1;
- out->color[3] = (a->color[3] + b->color[3]) >> 1;
-}
-
-/*
-============
-Transpose
-============
-*/
-static void Transpose( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
- int i, j;
- drawVert_t temp;
-
- if ( width > height ) {
- for ( i = 0 ; i < height ; i++ ) {
- for ( j = i + 1 ; j < width ; j++ ) {
- if ( j < height ) {
- // swap the value
- temp = ctrl[j][i];
- ctrl[j][i] = ctrl[i][j];
- ctrl[i][j] = temp;
- } else {
- // just copy
- ctrl[j][i] = ctrl[i][j];
- }
- }
- }
- } else {
- for ( i = 0 ; i < width ; i++ ) {
- for ( j = i + 1 ; j < height ; j++ ) {
- if ( j < width ) {
- // swap the value
- temp = ctrl[i][j];
- ctrl[i][j] = ctrl[j][i];
- ctrl[j][i] = temp;
- } else {
- // just copy
- ctrl[i][j] = ctrl[j][i];
- }
- }
- }
- }
-
-}
-
-
-/*
-=================
-MakeMeshNormals
-
-Handles all the complicated wrapping and degenerate cases
-=================
-*/
-static void MakeMeshNormals( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
- int i, j, k, dist;
- vec3_t normal;
- vec3_t sum;
- int count = 0;
- vec3_t base;
- vec3_t delta;
- int x, y;
- drawVert_t *dv;
- vec3_t around[8], temp;
- qboolean good[8];
- qboolean wrapWidth, wrapHeight;
- float len;
-static int neighbors[8][2] = {
- {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
- };
-
- wrapWidth = qfalse;
- for ( i = 0 ; i < height ; i++ ) {
- VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta );
- len = VectorLengthSquared( delta );
- if ( len > 1.0 ) {
- break;
- }
- }
- if ( i == height ) {
- wrapWidth = qtrue;
- }
-
- wrapHeight = qfalse;
- for ( i = 0 ; i < width ; i++ ) {
- VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta );
- len = VectorLengthSquared( delta );
- if ( len > 1.0 ) {
- break;
- }
- }
- if ( i == width) {
- wrapHeight = qtrue;
- }
-
-
- for ( i = 0 ; i < width ; i++ ) {
- for ( j = 0 ; j < height ; j++ ) {
- count = 0;
- dv = &ctrl[j][i];
- VectorCopy( dv->xyz, base );
- for ( k = 0 ; k < 8 ; k++ ) {
- VectorClear( around[k] );
- good[k] = qfalse;
-
- for ( dist = 1 ; dist <= 3 ; dist++ ) {
- x = i + neighbors[k][0] * dist;
- y = j + neighbors[k][1] * dist;
- if ( wrapWidth ) {
- if ( x < 0 ) {
- x = width - 1 + x;
- } else if ( x >= width ) {
- x = 1 + x - width;
- }
- }
- if ( wrapHeight ) {
- if ( y < 0 ) {
- y = height - 1 + y;
- } else if ( y >= height ) {
- y = 1 + y - height;
- }
- }
-
- if ( x < 0 || x >= width || y < 0 || y >= height ) {
- break; // edge of patch
- }
- VectorSubtract( ctrl[y][x].xyz, base, temp );
- if ( VectorNormalize2( temp, temp ) == 0 ) {
- continue; // degenerate edge, get more dist
- } else {
- good[k] = qtrue;
- VectorCopy( temp, around[k] );
- break; // good edge
- }
- }
- }
-
- VectorClear( sum );
- for ( k = 0 ; k < 8 ; k++ ) {
- if ( !good[k] || !good[(k+1)&7] ) {
- continue; // didn't get two points
- }
- CrossProduct( around[(k+1)&7], around[k], normal );
- if ( VectorNormalize2( normal, normal ) == 0 ) {
- continue;
- }
- VectorAdd( normal, sum, sum );
- count++;
- }
- if ( count == 0 ) {
-//printf("bad normal\n");
- count = 1;
- }
- VectorNormalize2( sum, dv->normal );
- }
- }
-}
-
-
-/*
-============
-InvertCtrl
-============
-*/
-static void InvertCtrl( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
- int i, j;
- drawVert_t temp;
-
- for ( i = 0 ; i < height ; i++ ) {
- for ( j = 0 ; j < width/2 ; j++ ) {
- temp = ctrl[i][j];
- ctrl[i][j] = ctrl[i][width-1-j];
- ctrl[i][width-1-j] = temp;
- }
- }
-}
-
-
-/*
-=================
-InvertErrorTable
-=================
-*/
-static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) {
- int i;
- float copy[2][MAX_GRID_SIZE];
-
- Com_Memcpy( copy, errorTable, sizeof( copy ) );
-
- for ( i = 0 ; i < width ; i++ ) {
- errorTable[1][i] = copy[0][i]; //[width-1-i];
- }
-
- for ( i = 0 ; i < height ; i++ ) {
- errorTable[0][i] = copy[1][height-1-i];
- }
-
-}
-
-/*
-==================
-PutPointsOnCurve
-==================
-*/
-static void PutPointsOnCurve( drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
- int width, int height ) {
- int i, j;
- drawVert_t prev, next;
-
- for ( i = 0 ; i < width ; i++ ) {
- for ( j = 1 ; j < height ; j += 2 ) {
- LerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev );
- LerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next );
- LerpDrawVert( &prev, &next, &ctrl[j][i] );
- }
- }
-
-
- for ( j = 0 ; j < height ; j++ ) {
- for ( i = 1 ; i < width ; i += 2 ) {
- LerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev );
- LerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next );
- LerpDrawVert( &prev, &next, &ctrl[j][i] );
- }
- }
-}
-
-/*
-=================
-R_CreateSurfaceGridMesh
-=================
-*/
-srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height,
- drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE] ) {
- int i, j, size;
- drawVert_t *vert;
- vec3_t tmpVec;
- srfGridMesh_t *grid;
-
- // copy the results out to a grid
- size = (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid );
-
-#ifdef PATCH_STITCHING
- grid = /*ri.Hunk_Alloc*/ ri.Malloc( size );
- Com_Memset(grid, 0, size);
-
- grid->widthLodError = /*ri.Hunk_Alloc*/ ri.Malloc( width * 4 );
- Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
-
- grid->heightLodError = /*ri.Hunk_Alloc*/ ri.Malloc( height * 4 );
- Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
-#else
- grid = ri.Hunk_Alloc( size );
- Com_Memset(grid, 0, size);
-
- grid->widthLodError = ri.Hunk_Alloc( width * 4 );
- Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
-
- grid->heightLodError = ri.Hunk_Alloc( height * 4 );
- Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
-#endif
-
- grid->width = width;
- grid->height = height;
- grid->surfaceType = SF_GRID;
- ClearBounds( grid->meshBounds[0], grid->meshBounds[1] );
- for ( i = 0 ; i < width ; i++ ) {
- for ( j = 0 ; j < height ; j++ ) {
- vert = &grid->verts[j*width+i];
- *vert = ctrl[j][i];
- AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] );
- }
- }
-
- // compute local origin and bounds
- VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin );
- VectorScale( grid->localOrigin, 0.5f, grid->localOrigin );
- VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec );
- grid->meshRadius = VectorLength( tmpVec );
-
- VectorCopy( grid->localOrigin, grid->lodOrigin );
- grid->lodRadius = grid->meshRadius;
- //
- return grid;
-}
-
-/*
-=================
-R_FreeSurfaceGridMesh
-=================
-*/
-void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) {
- ri.Free(grid->widthLodError);
- ri.Free(grid->heightLodError);
- ri.Free(grid);
-}
-
-/*
-=================
-R_SubdividePatchToGrid
-=================
-*/
-srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
- drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
- int i, j, k, l;
- drawVert_t_cleared( prev );
- drawVert_t_cleared( next );
- drawVert_t_cleared( mid );
- float len, maxLen;
- int dir;
- int t;
- drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
- float errorTable[2][MAX_GRID_SIZE];
-
- for ( i = 0 ; i < width ; i++ ) {
- for ( j = 0 ; j < height ; j++ ) {
- ctrl[j][i] = points[j*width+i];
- }
- }
-
- for ( dir = 0 ; dir < 2 ; dir++ ) {
-
- for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) {
- errorTable[dir][j] = 0;
- }
-
- // horizontal subdivisions
- for ( j = 0 ; j + 2 < width ; j += 2 ) {
- // check subdivided midpoints against control points
-
- // FIXME: also check midpoints of adjacent patches against the control points
- // this would basically stitch all patches in the same LOD group together.
-
- maxLen = 0;
- for ( i = 0 ; i < height ; i++ ) {
- vec3_t midxyz;
- vec3_t midxyz2;
- vec3_t dir;
- vec3_t projected;
- float d;
-
- // calculate the point on the curve
- for ( l = 0 ; l < 3 ; l++ ) {
- midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2
- + ctrl[i][j+2].xyz[l] ) * 0.25f;
- }
-
- // see how far off the line it is
- // using dist-from-line will not account for internal
- // texture warping, but it gives a lot less polygons than
- // dist-from-midpoint
- VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz );
- VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir );
- VectorNormalize( dir );
-
- d = DotProduct( midxyz, dir );
- VectorScale( dir, d, projected );
- VectorSubtract( midxyz, projected, midxyz2);
- len = VectorLengthSquared( midxyz2 ); // we will do the sqrt later
- if ( len > maxLen ) {
- maxLen = len;
- }
- }
-
- maxLen = sqrt(maxLen);
-
- // if all the points are on the lines, remove the entire columns
- if ( maxLen < 0.1f ) {
- errorTable[dir][j+1] = 999;
- continue;
- }
-
- // see if we want to insert subdivided columns
- if ( width + 2 > MAX_GRID_SIZE ) {
- errorTable[dir][j+1] = 1.0f/maxLen;
- continue; // can't subdivide any more
- }
-
- if ( maxLen <= r_subdivisions->value ) {
- errorTable[dir][j+1] = 1.0f/maxLen;
- continue; // didn't need subdivision
- }
-
- errorTable[dir][j+2] = 1.0f/maxLen;
-
- // insert two columns and replace the peak
- width += 2;
- for ( i = 0 ; i < height ; i++ ) {
- LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev );
- LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next );
- LerpDrawVert( &prev, &next, &mid );
-
- for ( k = width - 1 ; k > j + 3 ; k-- ) {
- ctrl[i][k] = ctrl[i][k-2];
- }
- ctrl[i][j + 1] = prev;
- ctrl[i][j + 2] = mid;
- ctrl[i][j + 3] = next;
- }
-
- // back up and recheck this set again, it may need more subdivision
- j -= 2;
-
- }
-
- Transpose( width, height, ctrl );
- t = width;
- width = height;
- height = t;
- }
-
-
- // put all the aproximating points on the curve
- PutPointsOnCurve( ctrl, width, height );
-
- // cull out any rows or columns that are colinear
- for ( i = 1 ; i < width-1 ; i++ ) {
- if ( errorTable[0][i] != 999 ) {
- continue;
- }
- for ( j = i+1 ; j < width ; j++ ) {
- for ( k = 0 ; k < height ; k++ ) {
- ctrl[k][j-1] = ctrl[k][j];
- }
- errorTable[0][j-1] = errorTable[0][j];
- }
- width--;
- }
-
- for ( i = 1 ; i < height-1 ; i++ ) {
- if ( errorTable[1][i] != 999 ) {
- continue;
- }
- for ( j = i+1 ; j < height ; j++ ) {
- for ( k = 0 ; k < width ; k++ ) {
- ctrl[j-1][k] = ctrl[j][k];
- }
- errorTable[1][j-1] = errorTable[1][j];
- }
- height--;
- }
-
-#if 1
- // flip for longest tristrips as an optimization
- // the results should be visually identical with or
- // without this step
- if ( height > width ) {
- Transpose( width, height, ctrl );
- InvertErrorTable( errorTable, width, height );
- t = width;
- width = height;
- height = t;
- InvertCtrl( width, height, ctrl );
- }
-#endif
-
- // calculate normals
- MakeMeshNormals( width, height, ctrl );
-
- return R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
-}
-
-/*
-===============
-R_GridInsertColumn
-===============
-*/
-srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ) {
- int i, j;
- int width, height, oldwidth;
- drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
- float errorTable[2][MAX_GRID_SIZE];
- float lodRadius;
- vec3_t lodOrigin;
-
- oldwidth = 0;
- width = grid->width + 1;
- if (width > MAX_GRID_SIZE)
- return NULL;
- height = grid->height;
- for (i = 0; i < width; i++) {
- if (i == column) {
- //insert new column
- for (j = 0; j < grid->height; j++) {
- LerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] );
- if (j == row)
- VectorCopy(point, ctrl[j][i].xyz);
- }
- errorTable[0][i] = loderror;
- continue;
- }
- errorTable[0][i] = grid->widthLodError[oldwidth];
- for (j = 0; j < grid->height; j++) {
- ctrl[j][i] = grid->verts[j * grid->width + oldwidth];
- }
- oldwidth++;
- }
- for (j = 0; j < grid->height; j++) {
- errorTable[1][j] = grid->heightLodError[j];
- }
- // put all the aproximating points on the curve
- //PutPointsOnCurve( ctrl, width, height );
- // calculate normals
- MakeMeshNormals( width, height, ctrl );
-
- VectorCopy(grid->lodOrigin, lodOrigin);
- lodRadius = grid->lodRadius;
- // free the old grid
- R_FreeSurfaceGridMesh(grid);
- // create a new grid
- grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
- grid->lodRadius = lodRadius;
- VectorCopy(lodOrigin, grid->lodOrigin);
- return grid;
-}
-
-/*
-===============
-R_GridInsertRow
-===============
-*/
-srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ) {
- int i, j;
- int width, height, oldheight;
- drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
- float errorTable[2][MAX_GRID_SIZE];
- float lodRadius;
- vec3_t lodOrigin;
-
- oldheight = 0;
- width = grid->width;
- height = grid->height + 1;
- if (height > MAX_GRID_SIZE)
- return NULL;
- for (i = 0; i < height; i++) {
- if (i == row) {
- //insert new row
- for (j = 0; j < grid->width; j++) {
- LerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] );
- if (j == column)
- VectorCopy(point, ctrl[i][j].xyz);
- }
- errorTable[1][i] = loderror;
- continue;
- }
- errorTable[1][i] = grid->heightLodError[oldheight];
- for (j = 0; j < grid->width; j++) {
- ctrl[i][j] = grid->verts[oldheight * grid->width + j];
- }
- oldheight++;
- }
- for (j = 0; j < grid->width; j++) {
- errorTable[0][j] = grid->widthLodError[j];
- }
- // put all the aproximating points on the curve
- //PutPointsOnCurve( ctrl, width, height );
- // calculate normals
- MakeMeshNormals( width, height, ctrl );
-
- VectorCopy(grid->lodOrigin, lodOrigin);
- lodRadius = grid->lodRadius;
- // free the old grid
- R_FreeSurfaceGridMesh(grid);
- // create a new grid
- grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
- grid->lodRadius = lodRadius;
- VectorCopy(lodOrigin, grid->lodOrigin);
- return grid;
-}
diff --git a/engine/code/renderer/tr_flares.c b/engine/code/renderer/tr_flares.c
deleted file mode 100644
index 0e650f2..0000000
--- a/engine/code/renderer/tr_flares.c
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_flares.c
-
-#include "tr_local.h"
-
-/*
-=============================================================================
-
-LIGHT FLARES
-
-A light flare is an effect that takes place inside the eye when bright light
-sources are visible. The size of the flare reletive to the screen is nearly
-constant, irrespective of distance, but the intensity should be proportional to the
-projected area of the light source.
-
-A surface that has been flagged as having a light flare will calculate the depth
-buffer value that it's midpoint should have when the surface is added.
-
-After all opaque surfaces have been rendered, the depth buffer is read back for
-each flare in view. If the point has not been obscured by a closer surface, the
-flare should be drawn.
-
-Surfaces that have a repeated texture should never be flagged as flaring, because
-there will only be a single flare added at the midpoint of the polygon.
-
-To prevent abrupt popping, the intensity of the flare is interpolated up and
-down as it changes visibility. This involves scene to scene state, unlike almost
-all other aspects of the renderer, and is complicated by the fact that a single
-frame may have multiple scenes.
-
-RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially
-up to five or more times in a frame with 3D status bar icons).
-
-=============================================================================
-*/
-
-
-// flare states maintain visibility over multiple frames for fading
-// layers: view, mirror, menu
-typedef struct flare_s {
- struct flare_s *next; // for active chain
-
- int addedFrame;
-
- qboolean inPortal; // true if in a portal view of the scene
- int frameSceneNum;
- void *surface;
- int fogNum;
-
- int fadeTime;
-
- qboolean visible; // state of last test
- float drawIntensity; // may be non 0 even if !visible due to fading
-
- int windowX, windowY;
- float eyeZ;
-
- vec3_t origin;
- vec3_t color;
-} flare_t;
-
-#define MAX_FLARES 128
-
-flare_t r_flareStructs[MAX_FLARES];
-flare_t *r_activeFlares, *r_inactiveFlares;
-
-int flareCoeff;
-
-/*
-==================
-R_ClearFlares
-==================
-*/
-void R_ClearFlares( void ) {
- int i;
-
- Com_Memset( r_flareStructs, 0, sizeof( r_flareStructs ) );
- r_activeFlares = NULL;
- r_inactiveFlares = NULL;
-
- for ( i = 0 ; i < MAX_FLARES ; i++ ) {
- r_flareStructs[i].next = r_inactiveFlares;
- r_inactiveFlares = &r_flareStructs[i];
- }
-}
-
-
-/*
-==================
-RB_AddFlare
-
-This is called at surface tesselation time
-==================
-*/
-void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) {
- int i;
- flare_t *f, *oldest;
- vec3_t local;
- float d = 1;
- vec4_t eye, clip, normalized, window;
-
- backEnd.pc.c_flareAdds++;
-
- if(normal && (normal[0] || normal[1] || normal[2]))
- {
- VectorSubtract( backEnd.viewParms.or.origin, point, local );
- VectorNormalizeFast(local);
- d = DotProduct(local, normal);
-
- // If the viewer is behind the flare don't add it.
- if(d < 0)
- return;
- }
-
- // if the point is off the screen, don't bother adding it
- // calculate screen coordinates and depth
- R_TransformModelToClip( point, backEnd.or.modelMatrix,
- backEnd.viewParms.projectionMatrix, eye, clip );
-
- // check to see if the point is completely off screen
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) {
- return;
- }
- }
-
- R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window );
-
- if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth
- || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) {
- return; // shouldn't happen, since we check the clip[] above, except for FP rounding
- }
-
- // see if a flare with a matching surface, scene, and view exists
- oldest = r_flareStructs;
- for ( f = r_activeFlares ; f ; f = f->next ) {
- if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum
- && f->inPortal == backEnd.viewParms.isPortal ) {
- break;
- }
- }
-
- // allocate a new one
- if (!f ) {
- if ( !r_inactiveFlares ) {
- // the list is completely full
- return;
- }
- f = r_inactiveFlares;
- r_inactiveFlares = r_inactiveFlares->next;
- f->next = r_activeFlares;
- r_activeFlares = f;
-
- f->surface = surface;
- f->frameSceneNum = backEnd.viewParms.frameSceneNum;
- f->inPortal = backEnd.viewParms.isPortal;
- f->addedFrame = -1;
- }
-
- if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) {
- f->visible = qfalse;
- f->fadeTime = backEnd.refdef.time - 2000;
- }
-
- f->addedFrame = backEnd.viewParms.frameCount;
- f->fogNum = fogNum;
-
- VectorCopy(point, f->origin);
- VectorCopy( color, f->color );
-
- // fade the intensity of the flare down as the
- // light surface turns away from the viewer
- VectorScale( f->color, d, f->color );
-
- // save info needed to test
- f->windowX = backEnd.viewParms.viewportX + window[0];
- f->windowY = backEnd.viewParms.viewportY + window[1];
-
- f->eyeZ = eye[2];
-}
-
-/*
-==================
-RB_AddDlightFlares
-==================
-*/
-void RB_AddDlightFlares( void ) {
- dlight_t *l;
- int i, j, k;
- fog_t *fog = NULL;
-
- if ( !r_flares->integer ) {
- return;
- }
-
- l = backEnd.refdef.dlights;
-
- if(tr.world)
- fog = tr.world->fogs;
-
- for (i=0 ; i<backEnd.refdef.num_dlights ; i++, l++) {
-
- if(fog)
- {
- // find which fog volume the light is in
- for ( j = 1 ; j < tr.world->numfogs ; j++ ) {
- fog = &tr.world->fogs[j];
- for ( k = 0 ; k < 3 ; k++ ) {
- if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) {
- break;
- }
- }
- if ( k == 3 ) {
- break;
- }
- }
- if ( j == tr.world->numfogs ) {
- j = 0;
- }
- }
- else
- j = 0;
-
- RB_AddFlare( (void *)l, j, l->origin, l->color, NULL );
- }
-}
-
-/*
-===============================================================================
-
-FLARE BACK END
-
-===============================================================================
-*/
-
-/*
-==================
-RB_TestFlare
-==================
-*/
-void RB_TestFlare( flare_t *f ) {
- float depth;
- qboolean visible;
- float fade;
- float screenZ;
-
- backEnd.pc.c_flareTests++;
-
- // doing a readpixels is as good as doing a glFinish(), so
- // don't bother with another sync
- glState.finishCalled = qfalse;
-
- // read back the z buffer contents
- qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth );
-
- screenZ = backEnd.viewParms.projectionMatrix[14] /
- ( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] );
-
- visible = ( -f->eyeZ - -screenZ ) < 24;
-
- if ( visible ) {
- if ( !f->visible ) {
- f->visible = qtrue;
- f->fadeTime = backEnd.refdef.time - 1;
- }
- fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value;
- } else {
- if ( f->visible ) {
- f->visible = qfalse;
- f->fadeTime = backEnd.refdef.time - 1;
- }
- fade = 1.0f - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value;
- }
-
- if ( fade < 0 ) {
- fade = 0;
- }
- if ( fade > 1 ) {
- fade = 1;
- }
-
- f->drawIntensity = fade;
-}
-
-
-/*
-==================
-RB_RenderFlare
-==================
-*/
-void RB_RenderFlare( flare_t *f ) {
- float size;
- vec3_t color;
- int iColor[3];
- float distance, intensity, factor;
- byte fogFactors[3] = {255, 255, 255};
-
- backEnd.pc.c_flareRenders++;
-
- // We don't want too big values anyways when dividing by distance.
- if(f->eyeZ > -1.0f)
- distance = 1.0f;
- else
- distance = -f->eyeZ;
-
- // calculate the flare size..
- size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / distance );
-
-/*
- * This is an alternative to intensity scaling. It changes the size of the flare on screen instead
- * with growing distance. See in the description at the top why this is not the way to go.
- // size will change ~ 1/r.
- size = backEnd.viewParms.viewportWidth * (r_flareSize->value / (distance * -2.0f));
-*/
-
-/*
- * As flare sizes stay nearly constant with increasing distance we must decrease the intensity
- * to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be
- * got by considering the ratio of
- * (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare)
- * An important requirement is:
- * intensity <= 1 for all distances.
- *
- * The formula used here to compute the intensity is as follows:
- * intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2
- * As you can see, the intensity will have a max. of 1 when the distance is 0.
- * The coefficient flareCoeff will determine the falloff speed with increasing distance.
- */
-
- factor = distance + size * sqrt(flareCoeff);
-
- intensity = flareCoeff * size * size / (factor * factor);
-
- VectorScale(f->color, f->drawIntensity * intensity, color);
-
-// Calculations for fogging
- if(tr.world && f->fogNum < tr.world->numfogs)
- {
- tess.numVertexes = 1;
- VectorCopy(f->origin, tess.xyz[0]);
- tess.fogNum = f->fogNum;
-
- RB_CalcModulateColorsByFog(fogFactors);
-
- // We don't need to render the flare if colors are 0 anyways.
- if(!(fogFactors[0] || fogFactors[1] || fogFactors[2]))
- return;
- }
-
- iColor[0] = color[0] * fogFactors[0];
- iColor[1] = color[1] * fogFactors[1];
- iColor[2] = color[2] * fogFactors[2];
-
- RB_BeginSurface( tr.flareShader, f->fogNum );
-
- // FIXME: use quadstamp?
- tess.xyz[tess.numVertexes][0] = f->windowX - size;
- tess.xyz[tess.numVertexes][1] = f->windowY - size;
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = iColor[0];
- tess.vertexColors[tess.numVertexes][1] = iColor[1];
- tess.vertexColors[tess.numVertexes][2] = iColor[2];
- tess.vertexColors[tess.numVertexes][3] = 255;
- tess.numVertexes++;
-
- tess.xyz[tess.numVertexes][0] = f->windowX - size;
- tess.xyz[tess.numVertexes][1] = f->windowY + size;
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = iColor[0];
- tess.vertexColors[tess.numVertexes][1] = iColor[1];
- tess.vertexColors[tess.numVertexes][2] = iColor[2];
- tess.vertexColors[tess.numVertexes][3] = 255;
- tess.numVertexes++;
-
- tess.xyz[tess.numVertexes][0] = f->windowX + size;
- tess.xyz[tess.numVertexes][1] = f->windowY + size;
- tess.texCoords[tess.numVertexes][0][0] = 1;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = iColor[0];
- tess.vertexColors[tess.numVertexes][1] = iColor[1];
- tess.vertexColors[tess.numVertexes][2] = iColor[2];
- tess.vertexColors[tess.numVertexes][3] = 255;
- tess.numVertexes++;
-
- tess.xyz[tess.numVertexes][0] = f->windowX + size;
- tess.xyz[tess.numVertexes][1] = f->windowY - size;
- tess.texCoords[tess.numVertexes][0][0] = 1;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = iColor[0];
- tess.vertexColors[tess.numVertexes][1] = iColor[1];
- tess.vertexColors[tess.numVertexes][2] = iColor[2];
- tess.vertexColors[tess.numVertexes][3] = 255;
- tess.numVertexes++;
-
- tess.indexes[tess.numIndexes++] = 0;
- tess.indexes[tess.numIndexes++] = 1;
- tess.indexes[tess.numIndexes++] = 2;
- tess.indexes[tess.numIndexes++] = 0;
- tess.indexes[tess.numIndexes++] = 2;
- tess.indexes[tess.numIndexes++] = 3;
-
- RB_EndSurface();
-}
-
-/*
-==================
-RB_RenderFlares
-
-Because flares are simulating an occular effect, they should be drawn after
-everything (all views) in the entire frame has been drawn.
-
-Because of the way portals use the depth buffer to mark off areas, the
-needed information would be lost after each view, so we are forced to draw
-flares after each view.
-
-The resulting artifact is that flares in mirrors or portals don't dim properly
-when occluded by something in the main view, and portal flares that should
-extend past the portal edge will be overwritten.
-==================
-*/
-void RB_RenderFlares (void) {
- flare_t *f;
- flare_t **prev;
- qboolean draw;
-
- if ( !r_flares->integer ) {
- return;
- }
-
- if(r_flareCoeff->modified)
- {
- if(r_flareCoeff->value == 0.0f)
- flareCoeff = atof(FLARE_STDCOEFF);
- else
- flareCoeff = r_flareCoeff->value;
-
- r_flareCoeff->modified = qfalse;
- }
-
- // Reset currentEntity to world so that any previously referenced entities
- // don't have influence on the rendering of these flares (i.e. RF_ renderer flags).
- backEnd.currentEntity = &tr.worldEntity;
- backEnd.or = backEnd.viewParms.world;
-
-// RB_AddDlightFlares();
-
- // perform z buffer readback on each flare in this view
- draw = qfalse;
- prev = &r_activeFlares;
- while ( ( f = *prev ) != NULL ) {
- // throw out any flares that weren't added last frame
- if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) {
- *prev = f->next;
- f->next = r_inactiveFlares;
- r_inactiveFlares = f;
- continue;
- }
-
- // don't draw any here that aren't from this scene / portal
- f->drawIntensity = 0;
- if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
- && f->inPortal == backEnd.viewParms.isPortal ) {
- RB_TestFlare( f );
- if ( f->drawIntensity ) {
- draw = qtrue;
- } else {
- // this flare has completely faded out, so remove it from the chain
- *prev = f->next;
- f->next = r_inactiveFlares;
- r_inactiveFlares = f;
- continue;
- }
- }
-
- prev = &f->next;
- }
-
- if ( !draw ) {
- return; // none visible
- }
-
- if ( backEnd.viewParms.isPortal ) {
- qglDisable (GL_CLIP_PLANE0);
- }
-
- qglPushMatrix();
- qglLoadIdentity();
- qglMatrixMode( GL_PROJECTION );
- qglPushMatrix();
- qglLoadIdentity();
- qglOrtho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
- backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
- -99999, 99999 );
-
- for ( f = r_activeFlares ; f ; f = f->next ) {
- if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
- && f->inPortal == backEnd.viewParms.isPortal
- && f->drawIntensity ) {
- RB_RenderFlare( f );
- }
- }
-
- qglPopMatrix();
- qglMatrixMode( GL_MODELVIEW );
- qglPopMatrix();
-}
-
diff --git a/engine/code/renderer/tr_font.c b/engine/code/renderer/tr_font.c
deleted file mode 100644
index bdb4251..0000000
--- a/engine/code/renderer/tr_font.c
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_font.c
-//
-//
-// The font system uses FreeType 2.x to render TrueType fonts for use within the game.
-// As of this writing ( Nov, 2000 ) Team Arena uses these fonts for all of the ui and
-// about 90% of the cgame presentation. A few areas of the CGAME were left uses the old
-// fonts since the code is shared with standard Q3A.
-//
-// If you include this font rendering code in a commercial product you MUST include the
-// following somewhere with your product, see www.freetype.org for specifics or changes.
-// The Freetype code also uses some hinting techniques that MIGHT infringe on patents
-// held by apple so be aware of that also.
-//
-// As of Q3A 1.25+ and Team Arena, we are shipping the game with the font rendering code
-// disabled. This removes any potential patent issues and it keeps us from having to
-// distribute an actual TrueTrype font which is 1. expensive to do and 2. seems to require
-// an act of god to accomplish.
-//
-// What we did was pre-render the fonts using FreeType ( which is why we leave the FreeType
-// credit in the credits ) and then saved off the glyph data and then hand touched up the
-// font bitmaps so they scale a bit better in GL.
-//
-// There are limitations in the way fonts are saved and reloaded in that it is based on
-// point size and not name. So if you pre-render Helvetica in 18 point and Impact in 18 point
-// you will end up with a single 18 point data file and image set. Typically you will want to
-// choose 3 sizes to best approximate the scaling you will be doing in the ui scripting system
-//
-// In the UI Scripting code, a scale of 1.0 is equal to a 48 point font. In Team Arena, we
-// use three or four scales, most of them exactly equaling the specific rendered size. We
-// rendered three sizes in Team Arena, 12, 16, and 20.
-//
-// To generate new font data you need to go through the following steps.
-// 1. delete the fontImage_x_xx.tga files and fontImage_xx.dat files from the fonts path.
-// 2. in a ui script, specificy a font, smallFont, and bigFont keyword with font name and
-// point size. the original TrueType fonts must exist in fonts at this point.
-// 3. run the game, you should see things normally.
-// 4. Exit the game and there will be three dat files and at least three tga files. The
-// tga's are in 256x256 pages so if it takes three images to render a 24 point font you
-// will end up with fontImage_0_24.tga through fontImage_2_24.tga
-// 5. You will need to flip the tga's in Photoshop as the tga output code writes them upside
-// down.
-// 6. In future runs of the game, the system looks for these images and data files when a s
-// specific point sized font is rendered and loads them for use.
-// 7. Because of the original beta nature of the FreeType code you will probably want to hand
-// touch the font bitmaps.
-//
-// Currently a define in the project turns on or off the FreeType code which is currently
-// defined out. To pre-render new fonts you need enable the define ( BUILD_FREETYPE ) and
-// uncheck the exclude from build check box in the FreeType2 area of the Renderer project.
-
-
-#include "tr_local.h"
-#include "../qcommon/qcommon.h"
-
-#ifdef BUILD_FREETYPE
-#include <ft2build.h>
-#include <freetype/fterrors.h>
-#include <freetype/ftsystem.h>
-#include <freetype/ftimage.h>
-#include <freetype/freetype.h>
-#include <freetype/ftoutln.h>
-
-#define _FLOOR(x) ((x) & -64)
-#define _CEIL(x) (((x)+63) & -64)
-#define _TRUNC(x) ((x) >> 6)
-
-FT_Library ftLibrary = NULL;
-#endif
-
-#define MAX_FONTS 6
-static int registeredFontCount = 0;
-static fontInfo_t registeredFont[MAX_FONTS];
-
-#ifdef BUILD_FREETYPE
-void R_GetGlyphInfo(FT_GlyphSlot glyph, int *left, int *right, int *width, int *top, int *bottom, int *height, int *pitch) {
-
- *left = _FLOOR( glyph->metrics.horiBearingX );
- *right = _CEIL( glyph->metrics.horiBearingX + glyph->metrics.width );
- *width = _TRUNC(*right - *left);
-
- *top = _CEIL( glyph->metrics.horiBearingY );
- *bottom = _FLOOR( glyph->metrics.horiBearingY - glyph->metrics.height );
- *height = _TRUNC( *top - *bottom );
- *pitch = ( qtrue ? (*width+3) & -4 : (*width+7) >> 3 );
-}
-
-
-FT_Bitmap *R_RenderGlyph(FT_GlyphSlot glyph, glyphInfo_t* glyphOut) {
-
- FT_Bitmap *bit2;
- int left, right, width, top, bottom, height, pitch, size;
-
- R_GetGlyphInfo(glyph, &left, &right, &width, &top, &bottom, &height, &pitch);
-
- if ( glyph->format == ft_glyph_format_outline ) {
- size = pitch*height;
-
- bit2 = Z_Malloc(sizeof(FT_Bitmap));
-
- bit2->width = width;
- bit2->rows = height;
- bit2->pitch = pitch;
- bit2->pixel_mode = ft_pixel_mode_grays;
- //bit2->pixel_mode = ft_pixel_mode_mono;
- bit2->buffer = Z_Malloc(pitch*height);
- bit2->num_grays = 256;
-
- Com_Memset( bit2->buffer, 0, size );
-
- FT_Outline_Translate( &glyph->outline, -left, -bottom );
-
- FT_Outline_Get_Bitmap( ftLibrary, &glyph->outline, bit2 );
-
- glyphOut->height = height;
- glyphOut->pitch = pitch;
- glyphOut->top = (glyph->metrics.horiBearingY >> 6) + 1;
- glyphOut->bottom = bottom;
-
- return bit2;
- }
- else {
- ri.Printf(PRINT_ALL, "Non-outline fonts are not supported\n");
- }
- return NULL;
-}
-
-void WriteTGA (char *filename, byte *data, int width, int height) {
- byte *buffer;
- int i, c;
-
- buffer = Z_Malloc(width*height*4 + 18);
- Com_Memset (buffer, 0, 18);
- buffer[2] = 2; // uncompressed type
- buffer[12] = width&255;
- buffer[13] = width>>8;
- buffer[14] = height&255;
- buffer[15] = height>>8;
- buffer[16] = 32; // pixel size
-
- // swap rgb to bgr
- c = 18 + width * height * 4;
- for (i=18 ; i<c ; i+=4)
- {
- buffer[i] = data[i-18+2]; // blue
- buffer[i+1] = data[i-18+1]; // green
- buffer[i+2] = data[i-18+0]; // red
- buffer[i+3] = data[i-18+3]; // alpha
- }
-
- ri.FS_WriteFile(filename, buffer, c);
-
- //f = fopen (filename, "wb");
- //fwrite (buffer, 1, c, f);
- //fclose (f);
-
- Z_Free (buffer);
-}
-
-static glyphInfo_t *RE_ConstructGlyphInfo(unsigned char *imageOut, int *xOut, int *yOut, int *maxHeight, FT_Face face, const unsigned char c, qboolean calcHeight) {
- int i;
- static glyphInfo_t glyph;
- unsigned char *src, *dst;
- float scaled_width, scaled_height;
- FT_Bitmap *bitmap = NULL;
-
- Com_Memset(&glyph, 0, sizeof(glyphInfo_t));
- // make sure everything is here
- if (face != NULL) {
- FT_Load_Glyph(face, FT_Get_Char_Index( face, c), FT_LOAD_DEFAULT );
- bitmap = R_RenderGlyph(face->glyph, &glyph);
- if (bitmap) {
- glyph.xSkip = (face->glyph->metrics.horiAdvance >> 6) + 1;
- } else {
- return &glyph;
- }
-
- if (glyph.height > *maxHeight) {
- *maxHeight = glyph.height;
- }
-
- if (calcHeight) {
- Z_Free(bitmap->buffer);
- Z_Free(bitmap);
- return &glyph;
- }
-
-/*
- // need to convert to power of 2 sizes so we do not get
- // any scaling from the gl upload
- for (scaled_width = 1 ; scaled_width < glyph.pitch ; scaled_width<<=1)
- ;
- for (scaled_height = 1 ; scaled_height < glyph.height ; scaled_height<<=1)
- ;
-*/
-
- scaled_width = glyph.pitch;
- scaled_height = glyph.height;
-
- // we need to make sure we fit
- if (*xOut + scaled_width + 1 >= 255) {
- if (*yOut + *maxHeight + 1 >= 255) {
- *yOut = -1;
- *xOut = -1;
- Z_Free(bitmap->buffer);
- Z_Free(bitmap);
- return &glyph;
- } else {
- *xOut = 0;
- *yOut += *maxHeight + 1;
- }
- } else if (*yOut + *maxHeight + 1 >= 255) {
- *yOut = -1;
- *xOut = -1;
- Z_Free(bitmap->buffer);
- Z_Free(bitmap);
- return &glyph;
- }
-
-
- src = bitmap->buffer;
- dst = imageOut + (*yOut * 256) + *xOut;
-
- if (bitmap->pixel_mode == ft_pixel_mode_mono) {
- for (i = 0; i < glyph.height; i++) {
- int j;
- unsigned char *_src = src;
- unsigned char *_dst = dst;
- unsigned char mask = 0x80;
- unsigned char val = *_src;
- for (j = 0; j < glyph.pitch; j++) {
- if (mask == 0x80) {
- val = *_src++;
- }
- if (val & mask) {
- *_dst = 0xff;
- }
- mask >>= 1;
-
- if ( mask == 0 ) {
- mask = 0x80;
- }
- _dst++;
- }
-
- src += glyph.pitch;
- dst += 256;
-
- }
- } else {
- for (i = 0; i < glyph.height; i++) {
- Com_Memcpy(dst, src, glyph.pitch);
- src += glyph.pitch;
- dst += 256;
- }
- }
-
- // we now have an 8 bit per pixel grey scale bitmap
- // that is width wide and pf->ftSize->metrics.y_ppem tall
-
- glyph.imageHeight = scaled_height;
- glyph.imageWidth = scaled_width;
- glyph.s = (float)*xOut / 256;
- glyph.t = (float)*yOut / 256;
- glyph.s2 = glyph.s + (float)scaled_width / 256;
- glyph.t2 = glyph.t + (float)scaled_height / 256;
-
- *xOut += scaled_width + 1;
- }
-
- Z_Free(bitmap->buffer);
- Z_Free(bitmap);
-
- return &glyph;
-}
-#endif
-
-static int fdOffset;
-static byte *fdFile;
-
-int readInt( void ) {
- int i = fdFile[fdOffset]+(fdFile[fdOffset+1]<<8)+(fdFile[fdOffset+2]<<16)+(fdFile[fdOffset+3]<<24);
- fdOffset += 4;
- return i;
-}
-
-typedef union {
- byte fred[4];
- float ffred;
-} poor;
-
-float readFloat( void ) {
- poor me;
-#if defined Q3_BIG_ENDIAN
- me.fred[0] = fdFile[fdOffset+3];
- me.fred[1] = fdFile[fdOffset+2];
- me.fred[2] = fdFile[fdOffset+1];
- me.fred[3] = fdFile[fdOffset+0];
-#elif defined Q3_LITTLE_ENDIAN
- me.fred[0] = fdFile[fdOffset+0];
- me.fred[1] = fdFile[fdOffset+1];
- me.fred[2] = fdFile[fdOffset+2];
- me.fred[3] = fdFile[fdOffset+3];
-#endif
- fdOffset += 4;
- return me.ffred;
-}
-
-void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {
-#ifdef BUILD_FREETYPE
- FT_Face face;
- int j, k, xOut, yOut, lastStart, imageNumber;
- int scaledSize, newSize, maxHeight, left, satLevels;
- unsigned char *out, *imageBuff;
- glyphInfo_t *glyph;
- image_t *image;
- qhandle_t h;
- float max;
-#endif
- void *faceData;
- int i, len;
- char name[1024];
- float dpi = 72; //
- float glyphScale = 72.0f / dpi; // change the scale to be relative to 1 based on 72 dpi ( so dpi of 144 means a scale of .5 )
-
-
- if (!fontName) {
- ri.Printf(PRINT_ALL, "RE_RegisterFont: called with empty name\n");
- return;
- }
-
- if (pointSize <= 0) {
- pointSize = 12;
- }
- // we also need to adjust the scale based on point size relative to 48 points as the ui scaling is based on a 48 point font
- glyphScale *= 48.0f / pointSize;
-
- // make sure the render thread is stopped
- R_SyncRenderThread();
-
- if (registeredFontCount >= MAX_FONTS) {
- ri.Printf(PRINT_ALL, "RE_RegisterFont: Too many fonts registered already.\n");
- return;
- }
-
- Com_sprintf(name, sizeof(name), "fonts/fontImage_%i.dat",pointSize);
- for (i = 0; i < registeredFontCount; i++) {
- if (Q_stricmp(name, registeredFont[i].name) == 0) {
- Com_Memcpy(font, ®isteredFont[i], sizeof(fontInfo_t));
- return;
- }
- }
-
- len = ri.FS_ReadFile(name, NULL);
- if (len == sizeof(fontInfo_t)) {
- ri.FS_ReadFile(name, &faceData);
- fdOffset = 0;
- fdFile = faceData;
- for(i=0; i<GLYPHS_PER_FONT; i++) {
- font->glyphs[i].height = readInt();
- font->glyphs[i].top = readInt();
- font->glyphs[i].bottom = readInt();
- font->glyphs[i].pitch = readInt();
- font->glyphs[i].xSkip = readInt();
- font->glyphs[i].imageWidth = readInt();
- font->glyphs[i].imageHeight = readInt();
- font->glyphs[i].s = readFloat();
- font->glyphs[i].t = readFloat();
- font->glyphs[i].s2 = readFloat();
- font->glyphs[i].t2 = readFloat();
- font->glyphs[i].glyph = readInt();
- Com_Memcpy(font->glyphs[i].shaderName, &fdFile[fdOffset], 32);
- fdOffset += 32;
- }
- font->glyphScale = readFloat();
- Com_Memcpy(font->name, &fdFile[fdOffset], MAX_QPATH);
-
-// Com_Memcpy(font, faceData, sizeof(fontInfo_t));
- Q_strncpyz(font->name, name, sizeof(font->name));
- for (i = GLYPH_START; i < GLYPH_END; i++) {
- font->glyphs[i].glyph = RE_RegisterShaderNoMip(font->glyphs[i].shaderName);
- }
- Com_Memcpy(®isteredFont[registeredFontCount++], font, sizeof(fontInfo_t));
- return;
- }
-
-#ifndef BUILD_FREETYPE
- ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType code not available\n");
-#else
- if (ftLibrary == NULL) {
- ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType not initialized.\n");
- return;
- }
-
- len = ri.FS_ReadFile(fontName, &faceData);
- if (len <= 0) {
- ri.Printf(PRINT_ALL, "RE_RegisterFont: Unable to read font file\n");
- return;
- }
-
- // allocate on the stack first in case we fail
- if (FT_New_Memory_Face( ftLibrary, faceData, len, 0, &face )) {
- ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType2, unable to allocate new face.\n");
- return;
- }
-
-
- if (FT_Set_Char_Size( face, pointSize << 6, pointSize << 6, dpi, dpi)) {
- ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType2, Unable to set face char size.\n");
- return;
- }
-
- //*font = ®isteredFonts[registeredFontCount++];
-
- // make a 256x256 image buffer, once it is full, register it, clean it and keep going
- // until all glyphs are rendered
-
- out = Z_Malloc(1024*1024);
- if (out == NULL) {
- ri.Printf(PRINT_ALL, "RE_RegisterFont: Z_Malloc failure during output image creation.\n");
- return;
- }
- Com_Memset(out, 0, 1024*1024);
-
- maxHeight = 0;
-
- for (i = GLYPH_START; i < GLYPH_END; i++) {
- glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qtrue);
- }
-
- xOut = 0;
- yOut = 0;
- i = GLYPH_START;
- lastStart = i;
- imageNumber = 0;
-
- while ( i <= GLYPH_END ) {
-
- glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qfalse);
-
- if (xOut == -1 || yOut == -1 || i == GLYPH_END) {
- // ran out of room
- // we need to create an image from the bitmap, set all the handles in the glyphs to this point
- //
-
- scaledSize = 256*256;
- newSize = scaledSize * 4;
- imageBuff = Z_Malloc(newSize);
- left = 0;
- max = 0;
- satLevels = 255;
- for ( k = 0; k < (scaledSize) ; k++ ) {
- if (max < out[k]) {
- max = out[k];
- }
- }
-
- if (max > 0) {
- max = 255/max;
- }
-
- for ( k = 0; k < (scaledSize) ; k++ ) {
- imageBuff[left++] = 255;
- imageBuff[left++] = 255;
- imageBuff[left++] = 255;
-
- imageBuff[left++] = ((float)out[k] * max);
- }
-
- Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i.tga", imageNumber++, pointSize);
- if (r_saveFontData->integer) {
- WriteTGA(name, imageBuff, 256, 256);
- }
-
- //Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i", imageNumber++, pointSize);
- image = R_CreateImage(name, imageBuff, 256, 256, qfalse, qfalse, GL_CLAMP_TO_EDGE);
- h = RE_RegisterShaderFromImage(name, LIGHTMAP_2D, image, qfalse);
- for (j = lastStart; j < i; j++) {
- font->glyphs[j].glyph = h;
- Q_strncpyz(font->glyphs[j].shaderName, name, sizeof(font->glyphs[j].shaderName));
- }
- lastStart = i;
- Com_Memset(out, 0, 1024*1024);
- xOut = 0;
- yOut = 0;
- Z_Free(imageBuff);
- i++;
- } else {
- Com_Memcpy(&font->glyphs[i], glyph, sizeof(glyphInfo_t));
- i++;
- }
- }
-
- registeredFont[registeredFontCount].glyphScale = glyphScale;
- font->glyphScale = glyphScale;
- Com_Memcpy(®isteredFont[registeredFontCount++], font, sizeof(fontInfo_t));
-
- if (r_saveFontData->integer) {
- ri.FS_WriteFile(va("fonts/fontImage_%i.dat", pointSize), font, sizeof(fontInfo_t));
- }
-
- Z_Free(out);
-
- ri.FS_FreeFile(faceData);
-#endif
-}
-
-
-
-void R_InitFreeType(void) {
-#ifdef BUILD_FREETYPE
- if (FT_Init_FreeType( &ftLibrary )) {
- ri.Printf(PRINT_ALL, "R_InitFreeType: Unable to initialize FreeType.\n");
- }
-#endif
- registeredFontCount = 0;
-}
-
-
-void R_DoneFreeType(void) {
-#ifdef BUILD_FREETYPE
- if (ftLibrary) {
- FT_Done_FreeType( ftLibrary );
- ftLibrary = NULL;
- }
-#endif
- registeredFontCount = 0;
-}
-
diff --git a/engine/code/renderer/tr_image.c b/engine/code/renderer/tr_image.c
deleted file mode 100644
index c86e32a..0000000
--- a/engine/code/renderer/tr_image.c
+++ /dev/null
@@ -1,1585 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_image.c
-#include "tr_local.h"
-
-static byte s_intensitytable[256];
-static unsigned char s_gammatable[256];
-
-int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
-int gl_filter_max = GL_LINEAR;
-
-#define FILE_HASH_SIZE 1024
-static image_t* hashTable[FILE_HASH_SIZE];
-
-/*
-** R_GammaCorrect
-*/
-void R_GammaCorrect( byte *buffer, int bufSize ) {
- int i;
-
- for ( i = 0; i < bufSize; i++ ) {
- buffer[i] = s_gammatable[buffer[i]];
- }
-}
-
-typedef struct {
- char *name;
- int minimize, maximize;
-} textureMode_t;
-
-textureMode_t modes[] = {
- {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
- {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
- {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
- {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
- {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
- {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
-};
-
-/*
-================
-return a hash value for the filename
-================
-*/
-static long generateHashValue( const char *fname ) {
- int i;
- long hash;
- char letter;
-
- hash = 0;
- i = 0;
- while (fname[i] != '\0') {
- letter = tolower(fname[i]);
- if (letter =='.') break; // don't include extension
- if (letter =='\\') letter = '/'; // damn path names
- hash+=(long)(letter)*(i+119);
- i++;
- }
- hash &= (FILE_HASH_SIZE-1);
- return hash;
-}
-
-/*
-===============
-GL_TextureMode
-===============
-*/
-void GL_TextureMode( const char *string ) {
- int i;
- image_t *glt;
-
- for ( i=0 ; i< 6 ; i++ ) {
- if ( !Q_stricmp( modes[i].name, string ) ) {
- break;
- }
- }
-
- // hack to prevent trilinear from being set on voodoo,
- // because their driver freaks...
- if ( i == 5 && glConfig.hardwareType == GLHW_3DFX_2D3D ) {
- ri.Printf( PRINT_ALL, "Refusing to set trilinear on a voodoo.\n" );
- i = 3;
- }
-
-
- if ( i == 6 ) {
- ri.Printf (PRINT_ALL, "bad filter name\n");
- return;
- }
-
- gl_filter_min = modes[i].minimize;
- gl_filter_max = modes[i].maximize;
-
- // change all the existing mipmap texture objects
- for ( i = 0 ; i < tr.numImages ; i++ ) {
- glt = tr.images[ i ];
- if ( glt->mipmap ) {
- GL_Bind (glt);
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
- }
- }
-}
-
-/*
-===============
-R_SumOfUsedImages
-===============
-*/
-int R_SumOfUsedImages( void ) {
- int total;
- int i;
-
- total = 0;
- for ( i = 0; i < tr.numImages; i++ ) {
- if ( tr.images[i]->frameUsed == tr.frameCount ) {
- total += tr.images[i]->uploadWidth * tr.images[i]->uploadHeight;
- }
- }
-
- return total;
-}
-
-/*
-===============
-R_ImageList_f
-===============
-*/
-void R_ImageList_f( void ) {
- int i;
- image_t *image;
- int texels;
- const char *yesno[] = {
- "no ", "yes"
- };
-
- ri.Printf (PRINT_ALL, "\n -w-- -h-- -mm- -TMU- -if-- wrap --name-------\n");
- texels = 0;
-
- for ( i = 0 ; i < tr.numImages ; i++ ) {
- image = tr.images[ i ];
-
- texels += image->uploadWidth*image->uploadHeight;
- ri.Printf (PRINT_ALL, "%4i: %4i %4i %s %d ",
- i, image->uploadWidth, image->uploadHeight, yesno[image->mipmap], image->TMU );
- switch ( image->internalFormat ) {
- case 1:
- ri.Printf( PRINT_ALL, "I " );
- break;
- case 2:
- ri.Printf( PRINT_ALL, "IA " );
- break;
- case 3:
- ri.Printf( PRINT_ALL, "RGB " );
- break;
- case 4:
- ri.Printf( PRINT_ALL, "RGBA " );
- break;
- case GL_RGBA8:
- ri.Printf( PRINT_ALL, "RGBA8" );
- break;
- case GL_RGB8:
- ri.Printf( PRINT_ALL, "RGB8" );
- break;
- case GL_RGB4_S3TC:
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- ri.Printf( PRINT_ALL, "S3TC " );
- break;
- case GL_RGBA4:
- ri.Printf( PRINT_ALL, "RGBA4" );
- break;
- case GL_RGB5:
- ri.Printf( PRINT_ALL, "RGB5 " );
- break;
- default:
- ri.Printf( PRINT_ALL, "???? " );
- }
-
- switch ( image->wrapClampMode ) {
- case GL_REPEAT:
- ri.Printf( PRINT_ALL, "rept " );
- break;
- case GL_CLAMP_TO_EDGE:
- ri.Printf( PRINT_ALL, "clmp " );
- break;
- default:
- ri.Printf( PRINT_ALL, "%4i ", image->wrapClampMode );
- break;
- }
-
- ri.Printf( PRINT_ALL, " %s\n", image->imgName );
- }
- ri.Printf (PRINT_ALL, " ---------\n");
- ri.Printf (PRINT_ALL, " %i total texels (not including mipmaps)\n", texels);
- ri.Printf (PRINT_ALL, " %i total images\n\n", tr.numImages );
-}
-
-//=======================================================================
-
-/*
-================
-ResampleTexture
-
-Used to resample images in a more general than quartering fashion.
-
-This will only be filtered properly if the resampled size
-is greater than half the original size.
-
-If a larger shrinking is needed, use the mipmap function
-before or after.
-================
-*/
-static void ResampleTexture( unsigned *in, int inwidth, int inheight, unsigned *out,
- int outwidth, int outheight ) {
- int i, j;
- unsigned *inrow, *inrow2;
- unsigned frac, fracstep;
- unsigned p1[2048], p2[2048];
- byte *pix1, *pix2, *pix3, *pix4;
-
- if (outwidth>2048)
- ri.Error(ERR_DROP, "ResampleTexture: max width");
-
- fracstep = inwidth*0x10000/outwidth;
-
- frac = fracstep>>2;
- for ( i=0 ; i<outwidth ; i++ ) {
- p1[i] = 4*(frac>>16);
- frac += fracstep;
- }
- frac = 3*(fracstep>>2);
- for ( i=0 ; i<outwidth ; i++ ) {
- p2[i] = 4*(frac>>16);
- frac += fracstep;
- }
-
- for (i=0 ; i<outheight ; i++, out += outwidth) {
- inrow = in + inwidth*(int)((i+0.25)*inheight/outheight);
- inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight);
- frac = fracstep >> 1;
- for (j=0 ; j<outwidth ; j++) {
- pix1 = (byte *)inrow + p1[j];
- pix2 = (byte *)inrow + p2[j];
- pix3 = (byte *)inrow2 + p1[j];
- pix4 = (byte *)inrow2 + p2[j];
- ((byte *)(out+j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>2;
- ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2;
- ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2;
- ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2;
- }
- }
-}
-
-/*
-================
-R_LightScaleTexture
-
-Scale up the pixel values in a texture to increase the
-lighting range
-================
-*/
-void R_LightScaleTexture (unsigned *in, int inwidth, int inheight, qboolean only_gamma )
-{
- if ( only_gamma )
- {
- if ( !glConfig.deviceSupportsGamma )
- {
- int i, c;
- byte *p;
-
- p = (byte *)in;
-
- c = inwidth*inheight;
- for (i=0 ; i<c ; i++, p+=4)
- {
- p[0] = s_gammatable[p[0]];
- p[1] = s_gammatable[p[1]];
- p[2] = s_gammatable[p[2]];
- }
- }
- }
- else
- {
- int i, c;
- byte *p;
-
- p = (byte *)in;
-
- c = inwidth*inheight;
-
- if ( glConfig.deviceSupportsGamma )
- {
- for (i=0 ; i<c ; i++, p+=4)
- {
- p[0] = s_intensitytable[p[0]];
- p[1] = s_intensitytable[p[1]];
- p[2] = s_intensitytable[p[2]];
- }
- }
- else
- {
- for (i=0 ; i<c ; i++, p+=4)
- {
- p[0] = s_gammatable[s_intensitytable[p[0]]];
- p[1] = s_gammatable[s_intensitytable[p[1]]];
- p[2] = s_gammatable[s_intensitytable[p[2]]];
- }
- }
- }
-}
-
-
-/*
-================
-R_MipMap2
-
-Operates in place, quartering the size of the texture
-Proper linear filter
-================
-*/
-static void R_MipMap2( unsigned *in, int inWidth, int inHeight ) {
- int i, j, k;
- byte *outpix;
- int inWidthMask, inHeightMask;
- int total;
- int outWidth, outHeight;
- unsigned *temp;
-
- outWidth = inWidth >> 1;
- outHeight = inHeight >> 1;
- temp = ri.Hunk_AllocateTempMemory( outWidth * outHeight * 4 );
-
- inWidthMask = inWidth - 1;
- inHeightMask = inHeight - 1;
-
- for ( i = 0 ; i < outHeight ; i++ ) {
- for ( j = 0 ; j < outWidth ; j++ ) {
- outpix = (byte *) ( temp + i * outWidth + j );
- for ( k = 0 ; k < 4 ; k++ ) {
- total =
- 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
- 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
- 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
- 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
-
- 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
- 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
- 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
- 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
-
- 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
- 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
- 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
- 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
-
- 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
- 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
- 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
- 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k];
- outpix[k] = total / 36;
- }
- }
- }
-
- Com_Memcpy( in, temp, outWidth * outHeight * 4 );
- ri.Hunk_FreeTempMemory( temp );
-}
-
-/*
-================
-R_MipMap
-
-Operates in place, quartering the size of the texture
-================
-*/
-static void R_MipMap (byte *in, int width, int height) {
- int i, j;
- byte *out;
- int row;
-
- if ( !r_simpleMipMaps->integer ) {
- R_MipMap2( (unsigned *)in, width, height );
- return;
- }
-
- if ( width == 1 && height == 1 ) {
- return;
- }
-
- row = width * 4;
- out = in;
- width >>= 1;
- height >>= 1;
-
- if ( width == 0 || height == 0 ) {
- width += height; // get largest
- for (i=0 ; i<width ; i++, out+=4, in+=8 ) {
- out[0] = ( in[0] + in[4] )>>1;
- out[1] = ( in[1] + in[5] )>>1;
- out[2] = ( in[2] + in[6] )>>1;
- out[3] = ( in[3] + in[7] )>>1;
- }
- return;
- }
-
- for (i=0 ; i<height ; i++, in+=row) {
- for (j=0 ; j<width ; j++, out+=4, in+=8) {
- out[0] = (in[0] + in[4] + in[row+0] + in[row+4])>>2;
- out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2;
- out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2;
- out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2;
- }
- }
-}
-
-
-/*
-==================
-R_BlendOverTexture
-
-Apply a color blend over a set of pixels
-==================
-*/
-static void R_BlendOverTexture( byte *data, int pixelCount, byte blend[4] ) {
- int i;
- int inverseAlpha;
- int premult[3];
-
- inverseAlpha = 255 - blend[3];
- premult[0] = blend[0] * blend[3];
- premult[1] = blend[1] * blend[3];
- premult[2] = blend[2] * blend[3];
-
- for ( i = 0 ; i < pixelCount ; i++, data+=4 ) {
- data[0] = ( data[0] * inverseAlpha + premult[0] ) >> 9;
- data[1] = ( data[1] * inverseAlpha + premult[1] ) >> 9;
- data[2] = ( data[2] * inverseAlpha + premult[2] ) >> 9;
- }
-}
-
-byte mipBlendColors[16][4] = {
- {0,0,0,0},
- {255,0,0,128},
- {0,255,0,128},
- {0,0,255,128},
- {255,0,0,128},
- {0,255,0,128},
- {0,0,255,128},
- {255,0,0,128},
- {0,255,0,128},
- {0,0,255,128},
- {255,0,0,128},
- {0,255,0,128},
- {0,0,255,128},
- {255,0,0,128},
- {0,255,0,128},
- {0,0,255,128},
-};
-
-
-/*
-===============
-Upload32
-
-===============
-*/
-extern qboolean charSet;
-static void Upload32( unsigned *data,
- int width, int height,
- qboolean mipmap,
- qboolean picmip,
- qboolean lightMap,
- int *format,
- int *pUploadWidth, int *pUploadHeight )
-{
- int samples;
- unsigned *scaledBuffer = NULL;
- unsigned *resampledBuffer = NULL;
- int scaled_width, scaled_height;
- int i, c;
- byte *scan;
- GLenum internalFormat = GL_RGB;
- float rMax = 0, gMax = 0, bMax = 0;
-
- //
- // convert to exact power of 2 sizes
- //
- for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
- ;
- for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
- ;
- if ( r_roundImagesDown->integer && scaled_width > width )
- scaled_width >>= 1;
- if ( r_roundImagesDown->integer && scaled_height > height )
- scaled_height >>= 1;
-
- if ( scaled_width != width || scaled_height != height ) {
- resampledBuffer = ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 );
- ResampleTexture (data, width, height, resampledBuffer, scaled_width, scaled_height);
- data = resampledBuffer;
- width = scaled_width;
- height = scaled_height;
- }
-
- //
- // perform optional picmip operation
- //
- if ( picmip ) {
- scaled_width >>= r_picmip->integer;
- scaled_height >>= r_picmip->integer;
- }
-
- //
- // clamp to minimum size
- //
- if (scaled_width < 1) {
- scaled_width = 1;
- }
- if (scaled_height < 1) {
- scaled_height = 1;
- }
-
- //
- // clamp to the current upper OpenGL limit
- // scale both axis down equally so we don't have to
- // deal with a half mip resampling
- //
- while ( scaled_width > glConfig.maxTextureSize
- || scaled_height > glConfig.maxTextureSize ) {
- scaled_width >>= 1;
- scaled_height >>= 1;
- }
-
- scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height );
-
- //
- // scan the texture for each channel's max values
- // and verify if the alpha channel is being used or not
- //
- c = width*height;
- scan = ((byte *)data);
- samples = 3;
-
- if(lightMap)
- {
- if(r_greyscale->integer)
- internalFormat = GL_LUMINANCE;
- else
- internalFormat = GL_RGB;
- }
- else
- {
- for ( i = 0; i < c; i++ )
- {
- if ( scan[i*4+0] > rMax )
- {
- rMax = scan[i*4+0];
- }
- if ( scan[i*4+1] > gMax )
- {
- gMax = scan[i*4+1];
- }
- if ( scan[i*4+2] > bMax )
- {
- bMax = scan[i*4+2];
- }
- if ( scan[i*4 + 3] != 255 )
- {
- samples = 4;
- break;
- }
- }
- // select proper internal format
- if ( samples == 3 )
- {
- if(r_greyscale->integer)
- {
- if(r_texturebits->integer == 16)
- internalFormat = GL_LUMINANCE8;
- else if(r_texturebits->integer == 32)
- internalFormat = GL_LUMINANCE16;
- else
- internalFormat = GL_LUMINANCE;
- }
- else
- {
- if ( glConfig.textureCompression == TC_S3TC_ARB )
- {
- internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
- }
- else if ( glConfig.textureCompression == TC_S3TC )
- {
- internalFormat = GL_RGB4_S3TC;
- }
- else if ( r_texturebits->integer == 16 )
- {
- internalFormat = GL_RGB5;
- }
- else if ( r_texturebits->integer == 32 )
- {
- internalFormat = GL_RGB8;
- }
- else
- {
- internalFormat = GL_RGB;
- }
- }
- }
- else if ( samples == 4 )
- {
- if(r_greyscale->integer)
- {
- if(r_texturebits->integer == 16)
- internalFormat = GL_LUMINANCE8_ALPHA8;
- else if(r_texturebits->integer == 32)
- internalFormat = GL_LUMINANCE16_ALPHA16;
- else
- internalFormat = GL_LUMINANCE_ALPHA;
- }
- else
- {
- if ( r_texturebits->integer == 16 )
- {
- internalFormat = GL_RGBA4;
- }
- else if ( r_texturebits->integer == 32 )
- {
- internalFormat = GL_RGBA8;
- }
- else
- {
- internalFormat = GL_RGBA;
- }
- }
- }
- }
-
- // copy or resample data as appropriate for first MIP level
- if ( ( scaled_width == width ) &&
- ( scaled_height == height ) ) {
- if (!mipmap)
- {
- qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
- *pUploadWidth = scaled_width;
- *pUploadHeight = scaled_height;
- *format = internalFormat;
-
- goto done;
- }
- Com_Memcpy (scaledBuffer, data, width*height*4);
- }
- else
- {
- // use the normal mip-mapping function to go down from here
- while ( width > scaled_width || height > scaled_height ) {
- R_MipMap( (byte *)data, width, height );
- width >>= 1;
- height >>= 1;
- if ( width < 1 ) {
- width = 1;
- }
- if ( height < 1 ) {
- height = 1;
- }
- }
- Com_Memcpy( scaledBuffer, data, width * height * 4 );
- }
-
- R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !mipmap );
-
- *pUploadWidth = scaled_width;
- *pUploadHeight = scaled_height;
- *format = internalFormat;
-
- qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer );
-
- if (mipmap)
- {
- int miplevel;
-
- miplevel = 0;
- while (scaled_width > 1 || scaled_height > 1)
- {
- R_MipMap( (byte *)scaledBuffer, scaled_width, scaled_height );
- scaled_width >>= 1;
- scaled_height >>= 1;
- if (scaled_width < 1)
- scaled_width = 1;
- if (scaled_height < 1)
- scaled_height = 1;
- miplevel++;
-
- if ( r_colorMipLevels->integer ) {
- R_BlendOverTexture( (byte *)scaledBuffer, scaled_width * scaled_height, mipBlendColors[miplevel] );
- }
-
- qglTexImage2D (GL_TEXTURE_2D, miplevel, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer );
- }
- }
-done:
-
- if (mipmap)
- {
- if ( textureFilterAnisotropic )
- qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
- (GLint)Com_Clamp( 1, maxAnisotropy, r_ext_max_anisotropy->integer ) );
-
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
- }
- else
- {
- if ( textureFilterAnisotropic )
- qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 );
-
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- }
-
- GL_CheckErrors();
-
- if ( scaledBuffer != 0 )
- ri.Hunk_FreeTempMemory( scaledBuffer );
- if ( resampledBuffer != 0 )
- ri.Hunk_FreeTempMemory( resampledBuffer );
-}
-
-
-/*
-================
-R_CreateImage
-
-This is the only way any image_t are created
-================
-*/
-image_t *R_CreateImage( const char *name, const byte *pic, int width, int height,
- qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) {
- image_t *image;
- qboolean isLightmap = qfalse;
- long hash;
-
- if (strlen(name) >= MAX_QPATH ) {
- ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long\n", name);
- }
- if ( !strncmp( name, "*lightmap", 9 ) ) {
- isLightmap = qtrue;
- }
-
- if ( tr.numImages == MAX_DRAWIMAGES ) {
- ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit\n");
- }
-
- image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low );
- image->texnum = 1024 + tr.numImages;
- tr.numImages++;
-
- image->mipmap = mipmap;
- image->allowPicmip = allowPicmip;
-
- strcpy (image->imgName, name);
-
- image->width = width;
- image->height = height;
- image->wrapClampMode = glWrapClampMode;
-
- // lightmaps are always allocated on TMU 1
- if ( qglActiveTextureARB && isLightmap ) {
- image->TMU = 1;
- } else {
- image->TMU = 0;
- }
-
- if ( qglActiveTextureARB ) {
- GL_SelectTexture( image->TMU );
- }
-
- GL_Bind(image);
-
- Upload32( (unsigned *)pic, image->width, image->height,
- image->mipmap,
- allowPicmip,
- isLightmap,
- &image->internalFormat,
- &image->uploadWidth,
- &image->uploadHeight );
-
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode );
-
- qglBindTexture( GL_TEXTURE_2D, 0 );
-
- if ( image->TMU == 1 ) {
- GL_SelectTexture( 0 );
- }
-
- hash = generateHashValue(name);
- image->next = hashTable[hash];
- hashTable[hash] = image;
-
- return image;
-}
-
-//===================================================================
-
-typedef struct
-{
- char *ext;
- void (*ImageLoader)( const char *, unsigned char **, int *, int * );
-} imageExtToLoaderMap_t;
-
-// Note that the ordering indicates the order of preference used
-// when there are multiple images of different formats available
-static imageExtToLoaderMap_t imageLoaders[ ] =
-{
- { "tga", R_LoadTGA },
- { "jpg", R_LoadJPG },
- { "jpeg", R_LoadJPG },
- { "png", R_LoadPNG },
- { "pcx", R_LoadPCX },
- { "bmp", R_LoadBMP }
-};
-
-static int numImageLoaders = sizeof( imageLoaders ) /
- sizeof( imageLoaders[ 0 ] );
-
-/*
-=================
-R_LoadImage
-
-Loads any of the supported image types into a cannonical
-32 bit format.
-=================
-*/
-void R_LoadImage( const char *name, byte **pic, int *width, int *height )
-{
- qboolean orgNameFailed = qfalse;
- int i;
- char localName[ MAX_QPATH ];
- const char *ext;
-
- *pic = NULL;
- *width = 0;
- *height = 0;
-
- Q_strncpyz( localName, name, MAX_QPATH );
-
- ext = COM_GetExtension( localName );
-
- if( *ext )
- {
- // Look for the correct loader and use it
- for( i = 0; i < numImageLoaders; i++ )
- {
- if( !Q_stricmp( ext, imageLoaders[ i ].ext ) )
- {
- // Load
- imageLoaders[ i ].ImageLoader( localName, pic, width, height );
- break;
- }
- }
-
- // A loader was found
- if( i < numImageLoaders )
- {
- if( *pic == NULL )
- {
- // Loader failed, most likely because the file isn't there;
- // try again without the extension
- orgNameFailed = qtrue;
- COM_StripExtension( name, localName, MAX_QPATH );
- }
- else
- {
- // Something loaded
- return;
- }
- }
- }
-
- // Try and find a suitable match using all
- // the image formats supported
- for( i = 0; i < numImageLoaders; i++ )
- {
- char *altName = va( "%s.%s", localName, imageLoaders[ i ].ext );
-
- // Load
- imageLoaders[ i ].ImageLoader( altName, pic, width, height );
-
- if( *pic )
- {
- if( orgNameFailed )
- {
- ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n",
- name, altName );
- }
-
- break;
- }
- }
-}
-
-
-/*
-===============
-R_FindImageFile
-
-Finds or loads the given image.
-Returns NULL if it fails, not a default image.
-==============
-*/
-image_t *R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) {
- image_t *image;
- int width, height;
- byte *pic;
- long hash;
-
- if (!name) {
- return NULL;
- }
-
- hash = generateHashValue(name);
-
- //
- // see if the image is already loaded
- //
- for (image=hashTable[hash]; image; image=image->next) {
- if ( !strcmp( name, image->imgName ) ) {
- // the white image can be used with any set of parms, but other mismatches are errors
- if ( strcmp( name, "*white" ) ) {
- if ( image->mipmap != mipmap ) {
- ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed mipmap parm\n", name );
- }
- if ( image->allowPicmip != allowPicmip ) {
- ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed allowPicmip parm\n", name );
- }
- if ( image->wrapClampMode != glWrapClampMode ) {
- ri.Printf( PRINT_ALL, "WARNING: reused image %s with mixed glWrapClampMode parm\n", name );
- }
- }
- return image;
- }
- }
-
- //
- // load the pic from disk
- //
- R_LoadImage( name, &pic, &width, &height );
- if ( pic == NULL ) {
- return NULL;
- }
-
- image = R_CreateImage( ( char * ) name, pic, width, height, mipmap, allowPicmip, glWrapClampMode );
- ri.Free( pic );
- return image;
-}
-
-
-/*
-================
-R_CreateDlightImage
-================
-*/
-#define DLIGHT_SIZE 16
-static void R_CreateDlightImage( void ) {
- int x,y;
- byte data[DLIGHT_SIZE][DLIGHT_SIZE][4];
- int b;
-
- // make a centered inverse-square falloff blob for dynamic lighting
- for (x=0 ; x<DLIGHT_SIZE ; x++) {
- for (y=0 ; y<DLIGHT_SIZE ; y++) {
- float d;
-
- d = ( DLIGHT_SIZE/2 - 0.5f - x ) * ( DLIGHT_SIZE/2 - 0.5f - x ) +
- ( DLIGHT_SIZE/2 - 0.5f - y ) * ( DLIGHT_SIZE/2 - 0.5f - y );
- b = 4000 / d;
- if (b > 255) {
- b = 255;
- } else if ( b < 75 ) {
- b = 0;
- }
- data[y][x][0] =
- data[y][x][1] =
- data[y][x][2] = b;
- data[y][x][3] = 255;
- }
- }
- tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, qfalse, qfalse, GL_CLAMP_TO_EDGE );
-}
-
-
-/*
-=================
-R_InitFogTable
-=================
-*/
-void R_InitFogTable( void ) {
- int i;
- float d;
- float exp;
-
- exp = 0.5;
-
- for ( i = 0 ; i < FOG_TABLE_SIZE ; i++ ) {
- d = pow ( (float)i/(FOG_TABLE_SIZE-1), exp );
-
- tr.fogTable[i] = d;
- }
-}
-
-/*
-================
-R_FogFactor
-
-Returns a 0.0 to 1.0 fog density value
-This is called for each texel of the fog texture on startup
-and for each vertex of transparent shaders in fog dynamically
-================
-*/
-float R_FogFactor( float s, float t ) {
- float d;
-
- s -= 1.0/512;
- if ( s < 0 ) {
- return 0;
- }
- if ( t < 1.0/32 ) {
- return 0;
- }
- if ( t < 31.0/32 ) {
- s *= (t - 1.0f/32.0f) / (30.0f/32.0f);
- }
-
- // we need to leave a lot of clamp range
- s *= 8;
-
- if ( s > 1.0 ) {
- s = 1.0;
- }
-
- d = tr.fogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ];
-
- return d;
-}
-
-/*
-================
-R_CreateFogImage
-================
-*/
-#define FOG_S 256
-#define FOG_T 32
-static void R_CreateFogImage( void ) {
- int x,y;
- byte *data;
- float g;
- float d;
- float borderColor[4];
-
- data = ri.Hunk_AllocateTempMemory( FOG_S * FOG_T * 4 );
-
- g = 2.0;
-
- // S is distance, T is depth
- for (x=0 ; x<FOG_S ; x++) {
- for (y=0 ; y<FOG_T ; y++) {
- d = R_FogFactor( ( x + 0.5f ) / FOG_S, ( y + 0.5f ) / FOG_T );
-
- data[(y*FOG_S+x)*4+0] =
- data[(y*FOG_S+x)*4+1] =
- data[(y*FOG_S+x)*4+2] = 255;
- data[(y*FOG_S+x)*4+3] = 255*d;
- }
- }
- // standard openGL clamping doesn't really do what we want -- it includes
- // the border color at the edges. OpenGL 1.2 has clamp-to-edge, which does
- // what we want.
- tr.fogImage = R_CreateImage("*fog", (byte *)data, FOG_S, FOG_T, qfalse, qfalse, GL_CLAMP_TO_EDGE );
- ri.Hunk_FreeTempMemory( data );
-
- borderColor[0] = 1.0;
- borderColor[1] = 1.0;
- borderColor[2] = 1.0;
- borderColor[3] = 1;
-
- qglTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor );
-}
-
-/*
-==================
-R_CreateDefaultImage
-==================
-*/
-#define DEFAULT_SIZE 16
-static void R_CreateDefaultImage( void ) {
- int x;
- byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
-
- // the default image will be a box, to allow you to see the mapping coordinates
- Com_Memset( data, 32, sizeof( data ) );
- for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) {
- data[0][x][0] =
- data[0][x][1] =
- data[0][x][2] =
- data[0][x][3] = 255;
-
- data[x][0][0] =
- data[x][0][1] =
- data[x][0][2] =
- data[x][0][3] = 255;
-
- data[DEFAULT_SIZE-1][x][0] =
- data[DEFAULT_SIZE-1][x][1] =
- data[DEFAULT_SIZE-1][x][2] =
- data[DEFAULT_SIZE-1][x][3] = 255;
-
- data[x][DEFAULT_SIZE-1][0] =
- data[x][DEFAULT_SIZE-1][1] =
- data[x][DEFAULT_SIZE-1][2] =
- data[x][DEFAULT_SIZE-1][3] = 255;
- }
- tr.defaultImage = R_CreateImage("*default", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qtrue, qfalse, GL_REPEAT );
-}
-
-/*
-==================
-R_CreateBuiltinImages
-==================
-*/
-void R_CreateBuiltinImages( void ) {
- int x,y;
- byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
-
- R_CreateDefaultImage();
-
- // we use a solid white image instead of disabling texturing
- Com_Memset( data, 255, sizeof( data ) );
- tr.whiteImage = R_CreateImage("*white", (byte *)data, 8, 8, qfalse, qfalse, GL_REPEAT );
-
- // with overbright bits active, we need an image which is some fraction of full color,
- // for default lightmaps, etc
- for (x=0 ; x<DEFAULT_SIZE ; x++) {
- for (y=0 ; y<DEFAULT_SIZE ; y++) {
- data[y][x][0] =
- data[y][x][1] =
- data[y][x][2] = tr.identityLightByte;
- data[y][x][3] = 255;
- }
- }
-
- tr.identityLightImage = R_CreateImage("*identityLight", (byte *)data, 8, 8, qfalse, qfalse, GL_REPEAT );
-
-
- for(x=0;x<32;x++) {
- // scratchimage is usually used for cinematic drawing
- tr.scratchImage[x] = R_CreateImage("*scratch", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qfalse, qtrue, GL_CLAMP_TO_EDGE );
- }
-
- R_CreateDlightImage();
- R_CreateFogImage();
-}
-
-
-/*
-===============
-R_SetColorMappings
-===============
-*/
-void R_SetColorMappings( void ) {
- int i, j;
- float g;
- int inf;
- int shift;
-
- // setup the overbright lighting
- tr.overbrightBits = r_overBrightBits->integer;
- if ( !glConfig.deviceSupportsGamma ) {
- tr.overbrightBits = 0; // need hardware gamma for overbright
- }
-
- // never overbright in windowed mode
- if ( !glConfig.isFullscreen )
- {
- tr.overbrightBits = 0;
- }
-
- // allow 2 overbright bits in 24 bit, but only 1 in 16 bit
- if ( glConfig.colorBits > 16 ) {
- if ( tr.overbrightBits > 2 ) {
- tr.overbrightBits = 2;
- }
- } else {
- if ( tr.overbrightBits > 1 ) {
- tr.overbrightBits = 1;
- }
- }
- if ( tr.overbrightBits < 0 ) {
- tr.overbrightBits = 0;
- }
-
- tr.identityLight = 1.0f / ( 1 << tr.overbrightBits );
- tr.identityLightByte = 255 * tr.identityLight;
-
-
- if ( r_intensity->value <= 1 ) {
- ri.Cvar_Set( "r_intensity", "1" );
- }
-
- if ( r_gamma->value < 0.5f ) {
- ri.Cvar_Set( "r_gamma", "0.5" );
- } else if ( r_gamma->value > 3.0f ) {
- ri.Cvar_Set( "r_gamma", "3.0" );
- }
-
- g = r_gamma->value;
-
- shift = tr.overbrightBits;
-
- for ( i = 0; i < 256; i++ ) {
- if ( g == 1 ) {
- inf = i;
- } else {
- inf = 255 * pow ( i/255.0f, 1.0f / g ) + 0.5f;
- }
- inf <<= shift;
- if (inf < 0) {
- inf = 0;
- }
- if (inf > 255) {
- inf = 255;
- }
- s_gammatable[i] = inf;
- }
-
- for (i=0 ; i<256 ; i++) {
- j = i * r_intensity->value;
- if (j > 255) {
- j = 255;
- }
- s_intensitytable[i] = j;
- }
-
- if ( glConfig.deviceSupportsGamma )
- {
- GLimp_SetGamma( s_gammatable, s_gammatable, s_gammatable );
- }
-}
-
-/*
-===============
-R_InitImages
-===============
-*/
-void R_InitImages( void ) {
- Com_Memset(hashTable, 0, sizeof(hashTable));
- // build brightness translation tables
- R_SetColorMappings();
-
- // create default texture and white texture
- R_CreateBuiltinImages();
-}
-
-/*
-===============
-R_DeleteTextures
-===============
-*/
-void R_DeleteTextures( void ) {
- int i;
-
- for ( i=0; i<tr.numImages ; i++ ) {
- qglDeleteTextures( 1, &tr.images[i]->texnum );
- }
- Com_Memset( tr.images, 0, sizeof( tr.images ) );
-
- tr.numImages = 0;
-
- Com_Memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) );
- if ( qglActiveTextureARB ) {
- GL_SelectTexture( 1 );
- qglBindTexture( GL_TEXTURE_2D, 0 );
- GL_SelectTexture( 0 );
- qglBindTexture( GL_TEXTURE_2D, 0 );
- } else {
- qglBindTexture( GL_TEXTURE_2D, 0 );
- }
-}
-
-/*
-============================================================================
-
-SKINS
-
-============================================================================
-*/
-
-/*
-==================
-CommaParse
-
-This is unfortunate, but the skin files aren't
-compatable with our normal parsing rules.
-==================
-*/
-static char *CommaParse( char **data_p ) {
- int c = 0, len;
- char *data;
- static char com_token[MAX_TOKEN_CHARS];
-
- data = *data_p;
- len = 0;
- com_token[0] = 0;
-
- // make sure incoming data is valid
- if ( !data ) {
- *data_p = NULL;
- return com_token;
- }
-
- while ( 1 ) {
- // skip whitespace
- while( (c = *data) <= ' ') {
- if( !c ) {
- break;
- }
- data++;
- }
-
-
- c = *data;
-
- // skip double slash comments
- if ( c == '/' && data[1] == '/' )
- {
- while (*data && *data != '\n')
- data++;
- }
- // skip /* */ comments
- else if ( c=='/' && data[1] == '*' )
- {
- while ( *data && ( *data != '*' || data[1] != '/' ) )
- {
- data++;
- }
- if ( *data )
- {
- data += 2;
- }
- }
- else
- {
- break;
- }
- }
-
- if ( c == 0 ) {
- return "";
- }
-
- // handle quoted strings
- if (c == '\"')
- {
- data++;
- while (1)
- {
- c = *data++;
- if (c=='\"' || !c)
- {
- com_token[len] = 0;
- *data_p = ( char * ) data;
- return com_token;
- }
- if (len < MAX_TOKEN_CHARS)
- {
- com_token[len] = c;
- len++;
- }
- }
- }
-
- // parse a regular word
- do
- {
- if (len < MAX_TOKEN_CHARS)
- {
- com_token[len] = c;
- len++;
- }
- data++;
- c = *data;
- } while (c>32 && c != ',' );
-
- if (len == MAX_TOKEN_CHARS)
- {
-// Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
- len = 0;
- }
- com_token[len] = 0;
-
- *data_p = ( char * ) data;
- return com_token;
-}
-
-
-/*
-===============
-RE_RegisterSkin
-
-===============
-*/
-qhandle_t RE_RegisterSkin( const char *name ) {
- qhandle_t hSkin;
- skin_t *skin;
- skinSurface_t *surf;
- union {
- char *c;
- void *v;
- } text;
- char *text_p;
- char *token;
- char surfName[MAX_QPATH];
-
- if ( !name || !name[0] ) {
- Com_Printf( "Empty name passed to RE_RegisterSkin\n" );
- return 0;
- }
-
- if ( strlen( name ) >= MAX_QPATH ) {
- Com_Printf( "Skin name exceeds MAX_QPATH\n" );
- return 0;
- }
-
-
- // see if the skin is already loaded
- for ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) {
- skin = tr.skins[hSkin];
- if ( !Q_stricmp( skin->name, name ) ) {
- if( skin->numSurfaces == 0 ) {
- return 0; // default skin
- }
- return hSkin;
- }
- }
-
- // allocate a new skin
- if ( tr.numSkins == MAX_SKINS ) {
- ri.Printf( PRINT_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name );
- return 0;
- }
- tr.numSkins++;
- skin = ri.Hunk_Alloc( sizeof( skin_t ), h_low );
- tr.skins[hSkin] = skin;
- Q_strncpyz( skin->name, name, sizeof( skin->name ) );
- skin->numSurfaces = 0;
-
- // make sure the render thread is stopped
- R_SyncRenderThread();
-
- // If not a .skin file, load as a single shader
- if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) {
- skin->numSurfaces = 1;
- skin->surfaces[0] = ri.Hunk_Alloc( sizeof(skin->surfaces[0]), h_low );
- skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
- return hSkin;
- }
-
- // load and parse the skin file
- ri.FS_ReadFile( name, &text.v );
- if ( !text.c ) {
- return 0;
- }
-
- text_p = text.c;
- while ( text_p && *text_p ) {
- // get surface name
- token = CommaParse( &text_p );
- Q_strncpyz( surfName, token, sizeof( surfName ) );
-
- if ( !token[0] ) {
- break;
- }
- // lowercase the surface name so skin compares are faster
- Q_strlwr( surfName );
-
- if ( *text_p == ',' ) {
- text_p++;
- }
-
- if ( strstr( token, "tag_" ) ) {
- continue;
- }
-
- // parse the shader name
- token = CommaParse( &text_p );
-
- surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
- Q_strncpyz( surf->name, surfName, sizeof( surf->name ) );
- surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue );
- skin->numSurfaces++;
- }
-
- ri.FS_FreeFile( text.v );
-
-
- // never let a skin have 0 shaders
- if ( skin->numSurfaces == 0 ) {
- return 0; // use default skin
- }
-
- return hSkin;
-}
-
-
-/*
-===============
-R_InitSkins
-===============
-*/
-void R_InitSkins( void ) {
- skin_t *skin;
-
- tr.numSkins = 1;
-
- // make the default skin have all default shaders
- skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low );
- Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name ) );
- skin->numSurfaces = 1;
- skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces ), h_low );
- skin->surfaces[0]->shader = tr.defaultShader;
-}
-
-/*
-===============
-R_GetSkinByHandle
-===============
-*/
-skin_t *R_GetSkinByHandle( qhandle_t hSkin ) {
- if ( hSkin < 1 || hSkin >= tr.numSkins ) {
- return tr.skins[0];
- }
- return tr.skins[ hSkin ];
-}
-
-/*
-===============
-R_SkinList_f
-===============
-*/
-void R_SkinList_f( void ) {
- int i, j;
- skin_t *skin;
-
- ri.Printf (PRINT_ALL, "------------------\n");
-
- for ( i = 0 ; i < tr.numSkins ; i++ ) {
- skin = tr.skins[i];
-
- ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name );
- for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
- ri.Printf( PRINT_ALL, " %s = %s\n",
- skin->surfaces[j]->name, skin->surfaces[j]->shader->name );
- }
- }
- ri.Printf (PRINT_ALL, "------------------\n");
-}
-
diff --git a/engine/code/renderer/tr_image_bmp.c b/engine/code/renderer/tr_image_bmp.c
deleted file mode 100644
index 0b78abb..0000000
--- a/engine/code/renderer/tr_image_bmp.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "tr_local.h"
-
-typedef struct
-{
- char id[2];
- unsigned fileSize;
- unsigned reserved0;
- unsigned bitmapDataOffset;
- unsigned bitmapHeaderSize;
- unsigned width;
- unsigned height;
- unsigned short planes;
- unsigned short bitsPerPixel;
- unsigned compression;
- unsigned bitmapDataSize;
- unsigned hRes;
- unsigned vRes;
- unsigned colors;
- unsigned importantColors;
- unsigned char palette[256][4];
-} BMPHeader_t;
-
-void R_LoadBMP( const char *name, byte **pic, int *width, int *height )
-{
- int columns, rows;
- unsigned numPixels;
- byte *pixbuf;
- int row, column;
- byte *buf_p;
- byte *end;
- union {
- byte *b;
- void *v;
- } buffer;
- int length;
- BMPHeader_t bmpHeader;
- byte *bmpRGBA;
-
- *pic = NULL;
-
- if(width)
- *width = 0;
-
- if(height)
- *height = 0;
-
- //
- // load the file
- //
- length = ri.FS_ReadFile( ( char * ) name, &buffer.v);
- if (!buffer.b || length < 0) {
- return;
- }
-
- if (length < 54)
- {
- ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name );
- }
-
- buf_p = buffer.b;
- end = buffer.b + length;
-
- bmpHeader.id[0] = *buf_p++;
- bmpHeader.id[1] = *buf_p++;
- bmpHeader.fileSize = LittleLong( * ( int * ) buf_p );
- buf_p += 4;
- bmpHeader.reserved0 = LittleLong( * ( int * ) buf_p );
- buf_p += 4;
- bmpHeader.bitmapDataOffset = LittleLong( * ( int * ) buf_p );
- buf_p += 4;
- bmpHeader.bitmapHeaderSize = LittleLong( * ( int * ) buf_p );
- buf_p += 4;
- bmpHeader.width = LittleLong( * ( int * ) buf_p );
- buf_p += 4;
- bmpHeader.height = LittleLong( * ( int * ) buf_p );
- buf_p += 4;
- bmpHeader.planes = LittleShort( * ( short * ) buf_p );
- buf_p += 2;
- bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p );
- buf_p += 2;
- bmpHeader.compression = LittleLong( * ( int * ) buf_p );
- buf_p += 4;
- bmpHeader.bitmapDataSize = LittleLong( * ( int * ) buf_p );
- buf_p += 4;
- bmpHeader.hRes = LittleLong( * ( int * ) buf_p );
- buf_p += 4;
- bmpHeader.vRes = LittleLong( * ( int * ) buf_p );
- buf_p += 4;
- bmpHeader.colors = LittleLong( * ( int * ) buf_p );
- buf_p += 4;
- bmpHeader.importantColors = LittleLong( * ( int * ) buf_p );
- buf_p += 4;
-
- if ( bmpHeader.bitsPerPixel == 8 )
- {
- if (buf_p + sizeof(bmpHeader.palette) > end)
- ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name );
-
- Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
- buf_p += sizeof(bmpHeader.palette);
- }
-
- if (buffer.b + bmpHeader.bitmapDataOffset > end)
- {
- ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)\n", name );
- }
-
- buf_p = buffer.b + bmpHeader.bitmapDataOffset;
-
- if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' )
- {
- ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)\n", name );
- }
- if ( bmpHeader.fileSize != length )
- {
- ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%u vs. %u) (%s)\n", bmpHeader.fileSize, length, name );
- }
- if ( bmpHeader.compression != 0 )
- {
- ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)\n", name );
- }
- if ( bmpHeader.bitsPerPixel < 8 )
- {
- ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name );
- }
-
- switch ( bmpHeader.bitsPerPixel )
- {
- case 8:
- case 16:
- case 24:
- case 32:
- break;
- default:
- ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%hu' in file '%s'\n", bmpHeader.bitsPerPixel, name );
- break;
- }
-
- columns = bmpHeader.width;
- rows = bmpHeader.height;
- if ( rows < 0 )
- rows = -rows;
- numPixels = columns * rows;
-
- if(columns <= 0 || !rows || numPixels > 0x1FFFFFFF // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF
- || ((numPixels * 4) / columns) / 4 != rows)
- {
- ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size\n", name);
- }
- if(buf_p + numPixels*bmpHeader.bitsPerPixel/8 > end)
- {
- ri.Error (ERR_DROP, "LoadBMP: file truncated (%s)\n", name);
- }
-
- if ( width )
- *width = columns;
- if ( height )
- *height = rows;
-
- bmpRGBA = ri.Malloc( numPixels * 4 );
- *pic = bmpRGBA;
-
-
- for ( row = rows-1; row >= 0; row-- )
- {
- pixbuf = bmpRGBA + row*columns*4;
-
- for ( column = 0; column < columns; column++ )
- {
- unsigned char red, green, blue, alpha;
- int palIndex;
- unsigned short shortPixel;
-
- switch ( bmpHeader.bitsPerPixel )
- {
- case 8:
- palIndex = *buf_p++;
- *pixbuf++ = bmpHeader.palette[palIndex][2];
- *pixbuf++ = bmpHeader.palette[palIndex][1];
- *pixbuf++ = bmpHeader.palette[palIndex][0];
- *pixbuf++ = 0xff;
- break;
- case 16:
- shortPixel = * ( unsigned short * ) pixbuf;
- pixbuf += 2;
- *pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7;
- *pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2;
- *pixbuf++ = ( shortPixel & ( 31 ) ) << 3;
- *pixbuf++ = 0xff;
- break;
-
- case 24:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alpha = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = alpha;
- break;
- }
- }
- }
-
- ri.FS_FreeFile( buffer.v );
-
-}
diff --git a/engine/code/renderer/tr_image_jpg.c b/engine/code/renderer/tr_image_jpg.c
deleted file mode 100644
index 2e1a52a..0000000
--- a/engine/code/renderer/tr_image_jpg.c
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "tr_local.h"
-
-/*
- * Include file for users of JPEG library.
- * You will need to have included system headers that define at least
- * the typedefs FILE and size_t before you can include jpeglib.h.
- * (stdio.h is sufficient on ANSI-conforming systems.)
- * You may also wish to include "jerror.h".
- */
-
-#define JPEG_INTERNALS
-#include "../jpeg-6b/jpeglib.h"
-
-void R_LoadJPG( const char *filename, unsigned char **pic, int *width, int *height ) {
- /* This struct contains the JPEG decompression parameters and pointers to
- * working space (which is allocated as needed by the JPEG library).
- */
- struct jpeg_decompress_struct cinfo = {NULL};
- /* We use our private extension JPEG error handler.
- * Note that this struct must live as long as the main JPEG parameter
- * struct, to avoid dangling-pointer problems.
- */
- /* This struct represents a JPEG error handler. It is declared separately
- * because applications often want to supply a specialized error handler
- * (see the second half of this file for an example). But here we just
- * take the easy way out and use the standard error handler, which will
- * print a message on stderr and call exit() if compression fails.
- * Note that this struct must live as long as the main JPEG parameter
- * struct, to avoid dangling-pointer problems.
- */
- struct jpeg_error_mgr jerr;
- /* More stuff */
- JSAMPARRAY buffer; /* Output row buffer */
- unsigned row_stride; /* physical row width in output buffer */
- unsigned pixelcount, memcount;
- unsigned char *out;
- int len;
- union {
- byte *b;
- void *v;
- } fbuffer;
- byte *buf;
-
- /* In this example we want to open the input file before doing anything else,
- * so that the setjmp() error recovery below can assume the file is open.
- * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
- * requires it in order to read binary files.
- */
-
- len = ri.FS_ReadFile ( ( char * ) filename, &fbuffer.v);
- if (!fbuffer.b || len < 0) {
- return;
- }
-
- /* Step 1: allocate and initialize JPEG decompression object */
-
- /* We have to set up the error handler first, in case the initialization
- * step fails. (Unlikely, but it could happen if you are out of memory.)
- * This routine fills in the contents of struct jerr, and returns jerr's
- * address which we place into the link field in cinfo.
- */
- cinfo.err = jpeg_std_error(&jerr);
-
- /* Now we can initialize the JPEG decompression object. */
- jpeg_create_decompress(&cinfo);
-
- /* Step 2: specify data source (eg, a file) */
-
- jpeg_mem_src(&cinfo, fbuffer.b, len);
-
- /* Step 3: read file parameters with jpeg_read_header() */
-
- (void) jpeg_read_header(&cinfo, TRUE);
- /* We can ignore the return value from jpeg_read_header since
- * (a) suspension is not possible with the stdio data source, and
- * (b) we passed TRUE to reject a tables-only JPEG file as an error.
- * See libjpeg.doc for more info.
- */
-
- /* Step 4: set parameters for decompression */
-
- /* In this example, we don't need to change any of the defaults set by
- * jpeg_read_header(), so we do nothing here.
- */
-
- /* Step 5: Start decompressor */
-
- (void) jpeg_start_decompress(&cinfo);
- /* We can ignore the return value since suspension is not possible
- * with the stdio data source.
- */
-
- /* We may need to do some setup of our own at this point before reading
- * the data. After jpeg_start_decompress() we have the correct scaled
- * output image dimensions available, as well as the output colormap
- * if we asked for color quantization.
- * In this example, we need to make an output work buffer of the right size.
- */
- /* JSAMPLEs per row in output buffer */
-
- pixelcount = cinfo.output_width * cinfo.output_height;
-
- if(!cinfo.output_width || !cinfo.output_height
- || ((pixelcount * 4) / cinfo.output_width) / 4 != cinfo.output_height
- || pixelcount > 0x1FFFFFFF || cinfo.output_components > 4) // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF
- {
- ri.Error (ERR_DROP, "LoadJPG: %s has an invalid image size: %dx%d*4=%d, components: %d\n", filename,
- cinfo.output_width, cinfo.output_height, pixelcount * 4, cinfo.output_components);
- }
-
- memcount = pixelcount * 4;
- row_stride = cinfo.output_width * cinfo.output_components;
-
- out = ri.Malloc(memcount);
-
- *width = cinfo.output_width;
- *height = cinfo.output_height;
-
- /* Step 6: while (scan lines remain to be read) */
- /* jpeg_read_scanlines(...); */
-
- /* Here we use the library's state variable cinfo.output_scanline as the
- * loop counter, so that we don't have to keep track ourselves.
- */
- while (cinfo.output_scanline < cinfo.output_height) {
- /* jpeg_read_scanlines expects an array of pointers to scanlines.
- * Here the array is only one element long, but you could ask for
- * more than one scanline at a time if that's more convenient.
- */
- buf = ((out+(row_stride*cinfo.output_scanline)));
- buffer = &buf;
- (void) jpeg_read_scanlines(&cinfo, buffer, 1);
- }
-
- buf = out;
-
- // If we are processing an 8-bit JPEG (greyscale), we'll have to convert
- // the greyscale values to RGBA.
- if(cinfo.output_components == 1)
- {
- int sindex = pixelcount, dindex = memcount;
- unsigned char greyshade;
-
- // Only pixelcount number of bytes have been written.
- // Expand the color values over the rest of the buffer, starting
- // from the end.
- do
- {
- greyshade = buf[--sindex];
-
- buf[--dindex] = 255;
- buf[--dindex] = greyshade;
- buf[--dindex] = greyshade;
- buf[--dindex] = greyshade;
- } while(sindex);
- }
- else
- {
- // clear all the alphas to 255
- int i;
-
- for ( i = 3 ; i < memcount ; i+=4 )
- {
- buf[i] = 255;
- }
- }
-
- *pic = out;
-
- /* Step 7: Finish decompression */
-
- (void) jpeg_finish_decompress(&cinfo);
- /* We can ignore the return value since suspension is not possible
- * with the stdio data source.
- */
-
- /* Step 8: Release JPEG decompression object */
-
- /* This is an important step since it will release a good deal of memory. */
- jpeg_destroy_decompress(&cinfo);
-
- /* After finish_decompress, we can close the input file.
- * Here we postpone it until after no more JPEG errors are possible,
- * so as to simplify the setjmp error logic above. (Actually, I don't
- * think that jpeg_destroy can do an error exit, but why assume anything...)
- */
- ri.FS_FreeFile (fbuffer.v);
-
- /* At this point you may want to check to see whether any corrupt-data
- * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
- */
-
- /* And we're done! */
-}
-
-
-/* Expanded data destination object for stdio output */
-
-typedef struct {
- struct jpeg_destination_mgr pub; /* public fields */
-
- byte* outfile; /* target stream */
- int size;
-} my_destination_mgr;
-
-typedef my_destination_mgr * my_dest_ptr;
-
-
-/*
- * Initialize destination --- called by jpeg_start_compress
- * before any data is actually written.
- */
-
-static void
-init_destination (j_compress_ptr cinfo)
-{
- my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
-
- dest->pub.next_output_byte = dest->outfile;
- dest->pub.free_in_buffer = dest->size;
-}
-
-
-/*
- * Empty the output buffer --- called whenever buffer fills up.
- *
- * In typical applications, this should write the entire output buffer
- * (ignoring the current state of next_output_byte & free_in_buffer),
- * reset the pointer & count to the start of the buffer, and return TRUE
- * indicating that the buffer has been dumped.
- *
- * In applications that need to be able to suspend compression due to output
- * overrun, a FALSE return indicates that the buffer cannot be emptied now.
- * In this situation, the compressor will return to its caller (possibly with
- * an indication that it has not accepted all the supplied scanlines). The
- * application should resume compression after it has made more room in the
- * output buffer. Note that there are substantial restrictions on the use of
- * suspension --- see the documentation.
- *
- * When suspending, the compressor will back up to a convenient restart point
- * (typically the start of the current MCU). next_output_byte & free_in_buffer
- * indicate where the restart point will be if the current call returns FALSE.
- * Data beyond this point will be regenerated after resumption, so do not
- * write it out when emptying the buffer externally.
- */
-
-static boolean
-empty_output_buffer (j_compress_ptr cinfo)
-{
- return TRUE;
-}
-
-/*
- * Terminate destination --- called by jpeg_finish_compress
- * after all data has been written. Usually needs to flush buffer.
- *
- * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
- * application must deal with any cleanup that should happen even
- * for error exit.
- */
-
-static int hackSize;
-
-static void
-term_destination (j_compress_ptr cinfo)
-{
- my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
- size_t datacount = dest->size - dest->pub.free_in_buffer;
- hackSize = datacount;
-}
-
-
-/*
- * Prepare for output to a stdio stream.
- * The caller must have already opened the stream, and is responsible
- * for closing it after finishing compression.
- */
-
-static void
-jpegDest (j_compress_ptr cinfo, byte* outfile, int size)
-{
- my_dest_ptr dest;
-
- /* The destination object is made permanent so that multiple JPEG images
- * can be written to the same file without re-executing jpeg_stdio_dest.
- * This makes it dangerous to use this manager and a different destination
- * manager serially with the same JPEG object, because their private object
- * sizes may be different. Caveat programmer.
- */
- if (cinfo->dest == NULL) { /* first time for this JPEG object? */
- cinfo->dest = (struct jpeg_destination_mgr *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- sizeof(my_destination_mgr));
- }
-
- dest = (my_dest_ptr) cinfo->dest;
- dest->pub.init_destination = init_destination;
- dest->pub.empty_output_buffer = empty_output_buffer;
- dest->pub.term_destination = term_destination;
- dest->outfile = outfile;
- dest->size = size;
-}
-
-void SaveJPG(char * filename, int quality, int image_width, int image_height, unsigned char *image_buffer) {
- /* This struct contains the JPEG compression parameters and pointers to
- * working space (which is allocated as needed by the JPEG library).
- * It is possible to have several such structures, representing multiple
- * compression/decompression processes, in existence at once. We refer
- * to any one struct (and its associated working data) as a "JPEG object".
- */
- struct jpeg_compress_struct cinfo;
- /* This struct represents a JPEG error handler. It is declared separately
- * because applications often want to supply a specialized error handler
- * (see the second half of this file for an example). But here we just
- * take the easy way out and use the standard error handler, which will
- * print a message on stderr and call exit() if compression fails.
- * Note that this struct must live as long as the main JPEG parameter
- * struct, to avoid dangling-pointer problems.
- */
- struct jpeg_error_mgr jerr;
- /* More stuff */
- JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
- int row_stride; /* physical row width in image buffer */
- unsigned char *out;
-
- /* Step 1: allocate and initialize JPEG compression object */
-
- /* We have to set up the error handler first, in case the initialization
- * step fails. (Unlikely, but it could happen if you are out of memory.)
- * This routine fills in the contents of struct jerr, and returns jerr's
- * address which we place into the link field in cinfo.
- */
- cinfo.err = jpeg_std_error(&jerr);
- /* Now we can initialize the JPEG compression object. */
- jpeg_create_compress(&cinfo);
-
- /* Step 2: specify data destination (eg, a file) */
- /* Note: steps 2 and 3 can be done in either order. */
-
- /* Here we use the library-supplied code to send compressed data to a
- * stdio stream. You can also write your own code to do something else.
- * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
- * requires it in order to write binary files.
- */
- out = ri.Hunk_AllocateTempMemory(image_width*image_height*4);
- jpegDest(&cinfo, out, image_width*image_height*4);
-
- /* Step 3: set parameters for compression */
-
- /* First we supply a description of the input image.
- * Four fields of the cinfo struct must be filled in:
- */
- cinfo.image_width = image_width; /* image width and height, in pixels */
- cinfo.image_height = image_height;
- cinfo.input_components = 4; /* # of color components per pixel */
- cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
- /* Now use the library's routine to set default compression parameters.
- * (You must set at least cinfo.in_color_space before calling this,
- * since the defaults depend on the source color space.)
- */
- jpeg_set_defaults(&cinfo);
- /* Now you can set any non-default parameters you wish to.
- * Here we just illustrate the use of quality (quantization table) scaling:
- */
- jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
- /* If quality is set high, disable chroma subsampling */
- if (quality >= 85) {
- cinfo.comp_info[0].h_samp_factor = 1;
- cinfo.comp_info[0].v_samp_factor = 1;
- }
-
- /* Step 4: Start compressor */
-
- /* TRUE ensures that we will write a complete interchange-JPEG file.
- * Pass TRUE unless you are very sure of what you're doing.
- */
- jpeg_start_compress(&cinfo, TRUE);
-
- /* Step 5: while (scan lines remain to be written) */
- /* jpeg_write_scanlines(...); */
-
- /* Here we use the library's state variable cinfo.next_scanline as the
- * loop counter, so that we don't have to keep track ourselves.
- * To keep things simple, we pass one scanline per call; you can pass
- * more if you wish, though.
- */
- row_stride = image_width * 4; /* JSAMPLEs per row in image_buffer */
-
- while (cinfo.next_scanline < cinfo.image_height) {
- /* jpeg_write_scanlines expects an array of pointers to scanlines.
- * Here the array is only one element long, but you could pass
- * more than one scanline at a time if that's more convenient.
- */
- row_pointer[0] = & image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride];
- (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
- }
-
- /* Step 6: Finish compression */
-
- jpeg_finish_compress(&cinfo);
- /* After finish_compress, we can close the output file. */
- ri.FS_WriteFile( filename, out, hackSize );
-
- ri.Hunk_FreeTempMemory(out);
-
- /* Step 7: release JPEG compression object */
-
- /* This is an important step since it will release a good deal of memory. */
- jpeg_destroy_compress(&cinfo);
-
- /* And we're done! */
-}
-
-/*
-=================
-SaveJPGToBuffer
-=================
-*/
-int SaveJPGToBuffer( byte *buffer, int quality,
- int image_width, int image_height,
- byte *image_buffer )
-{
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
- JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
- int row_stride; /* physical row width in image buffer */
-
- /* Step 1: allocate and initialize JPEG compression object */
- cinfo.err = jpeg_std_error(&jerr);
- /* Now we can initialize the JPEG compression object. */
- jpeg_create_compress(&cinfo);
-
- /* Step 2: specify data destination (eg, a file) */
- /* Note: steps 2 and 3 can be done in either order. */
- jpegDest(&cinfo, buffer, image_width*image_height*4);
-
- /* Step 3: set parameters for compression */
- cinfo.image_width = image_width; /* image width and height, in pixels */
- cinfo.image_height = image_height;
- cinfo.input_components = 4; /* # of color components per pixel */
- cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
-
- jpeg_set_defaults(&cinfo);
- jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
- /* If quality is set high, disable chroma subsampling */
- if (quality >= 85) {
- cinfo.comp_info[0].h_samp_factor = 1;
- cinfo.comp_info[0].v_samp_factor = 1;
- }
-
- /* Step 4: Start compressor */
- jpeg_start_compress(&cinfo, TRUE);
-
- /* Step 5: while (scan lines remain to be written) */
- /* jpeg_write_scanlines(...); */
- row_stride = image_width * 4; /* JSAMPLEs per row in image_buffer */
-
- while (cinfo.next_scanline < cinfo.image_height) {
- /* jpeg_write_scanlines expects an array of pointers to scanlines.
- * Here the array is only one element long, but you could pass
- * more than one scanline at a time if that's more convenient.
- */
- row_pointer[0] = & image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride];
- (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
- }
-
- /* Step 6: Finish compression */
- jpeg_finish_compress(&cinfo);
-
- /* Step 7: release JPEG compression object */
- jpeg_destroy_compress(&cinfo);
-
- /* And we're done! */
- return hackSize;
-}
diff --git a/engine/code/renderer/tr_image_pcx.c b/engine/code/renderer/tr_image_pcx.c
deleted file mode 100644
index d1b1a5e..0000000
--- a/engine/code/renderer/tr_image_pcx.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
- 2008 Ludwig Nussel
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "tr_local.h"
-
-/*
-========================================================================
-
-PCX files are used for 8 bit images
-
-========================================================================
-*/
-
-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;
- unsigned short hscreensize, vscreensize;
- char filler[54];
- unsigned char data[];
-} pcx_t;
-
-void R_LoadPCX ( const char *filename, byte **pic, int *width, int *height)
-{
- union {
- byte *b;
- void *v;
- } raw;
- byte *end;
- pcx_t *pcx;
- int len;
- unsigned char dataByte = 0, runLength = 0;
- byte *out, *pix;
- unsigned short w, h;
- byte *pic8;
- byte *palette;
- int i;
- unsigned size = 0;
-
- if (width)
- *width = 0;
- if (height)
- *height = 0;
- *pic = NULL;
-
- //
- // load the file
- //
- len = ri.FS_ReadFile( ( char * ) filename, &raw.v);
- if (!raw.b || len < 0) {
- return;
- }
-
- if((unsigned)len < sizeof(pcx_t))
- {
- ri.Printf (PRINT_ALL, "PCX truncated: %s\n", filename);
- ri.FS_FreeFile (raw.v);
- return;
- }
-
- //
- // parse the PCX file
- //
- pcx = (pcx_t *)raw.b;
- end = raw.b+len;
-
- w = LittleShort(pcx->xmax)+1;
- h = LittleShort(pcx->ymax)+1;
- size = w*h;
-
- if (pcx->manufacturer != 0x0a
- || pcx->version != 5
- || pcx->encoding != 1
- || pcx->color_planes != 1
- || pcx->bits_per_pixel != 8
- || w >= 1024
- || h >= 1024)
- {
- ri.Printf (PRINT_ALL, "Bad or unsupported pcx file %s (%dx%d@%d)\n", filename, w, h, pcx->bits_per_pixel);
- return;
- }
-
- pix = pic8 = ri.Malloc ( size );
-
- raw.b = pcx->data;
- // FIXME: should use bytes_per_line but original q3 didn't do that either
- while(pix < pic8+size)
- {
- if(runLength > 0) {
- *pix++ = dataByte;
- --runLength;
- continue;
- }
-
- if(raw.b+1 > end)
- break;
- dataByte = *raw.b++;
-
- if((dataByte & 0xC0) == 0xC0)
- {
- if(raw.b+1 > end)
- break;
- runLength = dataByte & 0x3F;
- dataByte = *raw.b++;
- }
- else
- runLength = 1;
- }
-
- if(pix < pic8+size)
- {
- ri.Printf (PRINT_ALL, "PCX file truncated: %s\n", filename);
- ri.FS_FreeFile (pcx);
- ri.Free (pic8);
- }
-
- if (raw.b-(byte*)pcx >= end - (byte*)769 || end[-769] != 0x0c)
- {
- ri.Printf (PRINT_ALL, "PCX missing palette: %s\n", filename);
- ri.FS_FreeFile (pcx);
- ri.Free (pic8);
- return;
- }
-
- palette = end-768;
-
- pix = out = ri.Malloc(4 * size );
- for (i = 0 ; i < size ; i++)
- {
- unsigned char p = pic8[i];
- pix[0] = palette[p*3];
- pix[1] = palette[p*3 + 1];
- pix[2] = palette[p*3 + 2];
- pix[3] = 255;
- pix += 4;
- }
-
- if (width)
- *width = w;
- if (height)
- *height = h;
-
- *pic = out;
-
- ri.FS_FreeFile (pcx);
- ri.Free (pic8);
-}
diff --git a/engine/code/renderer/tr_image_png.c b/engine/code/renderer/tr_image_png.c
deleted file mode 100644
index ef44c16..0000000
--- a/engine/code/renderer/tr_image_png.c
+++ /dev/null
@@ -1,2488 +0,0 @@
-/*
-===========================================================================
-ioquake3 png decoder
-Copyright (C) 2007,2008 Joerg Dietrich
-
-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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-===========================================================================
-*/
-
-#include "tr_local.h"
-
-#include "../qcommon/puff.h"
-
-// we could limit the png size to a lower value here
-#ifndef INT_MAX
-#define INT_MAX 0x1fffffff
-#endif
-
-/*
-=================
-PNG LOADING
-=================
-*/
-
-/*
- * Quake 3 image format : RGBA
- */
-
-#define Q3IMAGE_BYTESPERPIXEL (4)
-
-/*
- * PNG specifications
- */
-
-/*
- * The first 8 Bytes of every PNG-File are a fixed signature
- * to identify the file as a PNG.
- */
-
-#define PNG_Signature "\x89\x50\x4E\x47\xD\xA\x1A\xA"
-#define PNG_Signature_Size (8)
-
-/*
- * After the signature diverse chunks follow.
- * A chunk consists of a header and if Length
- * is bigger than 0 a body and a CRC of the body follow.
- */
-
-struct PNG_ChunkHeader
-{
- uint32_t Length;
- uint32_t Type;
-};
-
-#define PNG_ChunkHeader_Size (8)
-
-typedef uint32_t PNG_ChunkCRC;
-
-#define PNG_ChunkCRC_Size (4)
-
-/*
- * We use the following ChunkTypes.
- * All others are ignored.
- */
-
-#define MAKE_CHUNKTYPE(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | ((d)))
-
-#define PNG_ChunkType_IHDR MAKE_CHUNKTYPE('I', 'H', 'D', 'R')
-#define PNG_ChunkType_PLTE MAKE_CHUNKTYPE('P', 'L', 'T', 'E')
-#define PNG_ChunkType_IDAT MAKE_CHUNKTYPE('I', 'D', 'A', 'T')
-#define PNG_ChunkType_IEND MAKE_CHUNKTYPE('I', 'E', 'N', 'D')
-#define PNG_ChunkType_tRNS MAKE_CHUNKTYPE('t', 'R', 'N', 'S')
-
-/*
- * Per specification the first chunk after the signature SHALL be IHDR.
- */
-
-struct PNG_Chunk_IHDR
-{
- uint32_t Width;
- uint32_t Height;
- uint8_t BitDepth;
- uint8_t ColourType;
- uint8_t CompressionMethod;
- uint8_t FilterMethod;
- uint8_t InterlaceMethod;
-};
-
-#define PNG_Chunk_IHDR_Size (13)
-
-/*
- * ColourTypes
- */
-
-#define PNG_ColourType_Grey (0)
-#define PNG_ColourType_True (2)
-#define PNG_ColourType_Indexed (3)
-#define PNG_ColourType_GreyAlpha (4)
-#define PNG_ColourType_TrueAlpha (6)
-
-/*
- * number of colour components
- *
- * Grey : 1 grey
- * True : 1 R, 1 G, 1 B
- * Indexed : 1 index
- * GreyAlpha : 1 grey, 1 alpha
- * TrueAlpha : 1 R, 1 G, 1 B, 1 alpha
- */
-
-#define PNG_NumColourComponents_Grey (1)
-#define PNG_NumColourComponents_True (3)
-#define PNG_NumColourComponents_Indexed (1)
-#define PNG_NumColourComponents_GreyAlpha (2)
-#define PNG_NumColourComponents_TrueAlpha (4)
-
-/*
- * For the different ColourTypes
- * different BitDepths are specified.
- */
-
-#define PNG_BitDepth_1 ( 1)
-#define PNG_BitDepth_2 ( 2)
-#define PNG_BitDepth_4 ( 4)
-#define PNG_BitDepth_8 ( 8)
-#define PNG_BitDepth_16 (16)
-
-/*
- * Only one valid CompressionMethod is standardized.
- */
-
-#define PNG_CompressionMethod_0 (0)
-
-/*
- * Only one valid FilterMethod is currently standardized.
- */
-
-#define PNG_FilterMethod_0 (0)
-
-/*
- * This FilterMethod defines 5 FilterTypes
- */
-
-#define PNG_FilterType_None (0)
-#define PNG_FilterType_Sub (1)
-#define PNG_FilterType_Up (2)
-#define PNG_FilterType_Average (3)
-#define PNG_FilterType_Paeth (4)
-
-/*
- * Two InterlaceMethods are standardized :
- * 0 - NonInterlaced
- * 1 - Interlaced
- */
-
-#define PNG_InterlaceMethod_NonInterlaced (0)
-#define PNG_InterlaceMethod_Interlaced (1)
-
-/*
- * The Adam7 interlace method uses 7 passes.
- */
-
-#define PNG_Adam7_NumPasses (7)
-
-/*
- * The compressed data starts with a header ...
- */
-
-struct PNG_ZlibHeader
-{
- uint8_t CompressionMethod;
- uint8_t Flags;
-};
-
-#define PNG_ZlibHeader_Size (2)
-
-/*
- * ... and is followed by a check value
- */
-
-#define PNG_ZlibCheckValue_Size (4)
-
-/*
- * Some support functions for buffered files follow.
- */
-
-/*
- * buffered file representation
- */
-
-struct BufferedFile
-{
- byte *Buffer;
- int Length;
- byte *Ptr;
- int BytesLeft;
-};
-
-/*
- * Read a file into a buffer.
- */
-
-static struct BufferedFile *ReadBufferedFile(const char *name)
-{
- struct BufferedFile *BF;
- union {
- byte *b;
- void *v;
- } buffer;
-
- /*
- * input verification
- */
-
- if(!name)
- {
- return(NULL);
- }
-
- /*
- * Allocate control struct.
- */
-
- BF = ri.Malloc(sizeof(struct BufferedFile));
- if(!BF)
- {
- return(NULL);
- }
-
- /*
- * Initialize the structs components.
- */
-
- BF->Length = 0;
- BF->Buffer = NULL;
- BF->Ptr = NULL;
- BF->BytesLeft = 0;
-
- /*
- * Read the file.
- */
-
- BF->Length = ri.FS_ReadFile((char *) name, &buffer.v);
- BF->Buffer = buffer.b;
-
- /*
- * Did we get it? Is it big enough?
- */
-
- if(!(BF->Buffer && (BF->Length > 0)))
- {
- ri.Free(BF);
-
- return(NULL);
- }
-
- /*
- * Set the pointers and counters.
- */
-
- BF->Ptr = BF->Buffer;
- BF->BytesLeft = BF->Length;
-
- return(BF);
-}
-
-/*
- * Close a buffered file.
- */
-
-static void CloseBufferedFile(struct BufferedFile *BF)
-{
- if(BF)
- {
- if(BF->Buffer)
- {
- ri.FS_FreeFile(BF->Buffer);
- }
-
- ri.Free(BF);
- }
-}
-
-/*
- * Get a pointer to the requested bytes.
- */
-
-static void *BufferedFileRead(struct BufferedFile *BF, unsigned Length)
-{
- void *RetVal;
-
- /*
- * input verification
- */
-
- if(!(BF && Length))
- {
- return(NULL);
- }
-
- /*
- * not enough bytes left
- */
-
- if(Length > BF->BytesLeft)
- {
- return(NULL);
- }
-
- /*
- * the pointer to the requested data
- */
-
- RetVal = BF->Ptr;
-
- /*
- * Raise the pointer and counter.
- */
-
- BF->Ptr += Length;
- BF->BytesLeft -= Length;
-
- return(RetVal);
-}
-
-/*
- * Rewind the buffer.
- */
-
-static qboolean BufferedFileRewind(struct BufferedFile *BF, unsigned Offset)
-{
- unsigned BytesRead;
-
- /*
- * input verification
- */
-
- if(!BF)
- {
- return(qfalse);
- }
-
- /*
- * special trick to rewind to the beginning of the buffer
- */
-
- if(Offset == (unsigned)-1)
- {
- BF->Ptr = BF->Buffer;
- BF->BytesLeft = BF->Length;
-
- return(qtrue);
- }
-
- /*
- * How many bytes do we have already read?
- */
-
- BytesRead = BF->Ptr - BF->Buffer;
-
- /*
- * We can only rewind to the beginning of the BufferedFile.
- */
-
- if(Offset > BytesRead)
- {
- return(qfalse);
- }
-
- /*
- * lower the pointer and counter.
- */
-
- BF->Ptr -= Offset;
- BF->BytesLeft += Offset;
-
- return(qtrue);
-}
-
-/*
- * Skip some bytes.
- */
-
-static qboolean BufferedFileSkip(struct BufferedFile *BF, unsigned Offset)
-{
- /*
- * input verification
- */
-
- if(!BF)
- {
- return(qfalse);
- }
-
- /*
- * We can only skip to the end of the BufferedFile.
- */
-
- if(Offset > BF->BytesLeft)
- {
- return(qfalse);
- }
-
- /*
- * lower the pointer and counter.
- */
-
- BF->Ptr += Offset;
- BF->BytesLeft -= Offset;
-
- return(qtrue);
-}
-
-/*
- * Find a chunk
- */
-
-static qboolean FindChunk(struct BufferedFile *BF, uint32_t ChunkType)
-{
- struct PNG_ChunkHeader *CH;
-
- uint32_t Length;
- uint32_t Type;
-
- /*
- * input verification
- */
-
- if(!BF)
- {
- return(qfalse);
- }
-
- /*
- * cycle trough the chunks
- */
-
- while(qtrue)
- {
- /*
- * Read the chunk-header.
- */
-
- CH = BufferedFileRead(BF, PNG_ChunkHeader_Size);
- if(!CH)
- {
- return(qfalse);
- }
-
- /*
- * Do not swap the original types
- * they might be needed later.
- */
-
- Length = BigLong(CH->Length);
- Type = BigLong(CH->Type);
-
- /*
- * We found it!
- */
-
- if(Type == ChunkType)
- {
- /*
- * Rewind to the start of the chunk.
- */
-
- BufferedFileRewind(BF, PNG_ChunkHeader_Size);
-
- break;
- }
- else
- {
- /*
- * Skip the rest of the chunk.
- */
-
- if(Length)
- {
- if(!BufferedFileSkip(BF, Length + PNG_ChunkCRC_Size))
- {
- return(qfalse);
- }
- }
- }
- }
-
- return(qtrue);
-}
-
-/*
- * Decompress all IDATs
- */
-
-static uint32_t DecompressIDATs(struct BufferedFile *BF, uint8_t **Buffer)
-{
- uint8_t *DecompressedData;
- uint32_t DecompressedDataLength;
-
- uint8_t *CompressedData;
- uint8_t *CompressedDataPtr;
- uint32_t CompressedDataLength;
-
- struct PNG_ChunkHeader *CH;
-
- uint32_t Length;
- uint32_t Type;
-
- int BytesToRewind;
-
- int32_t puffResult;
- uint8_t *puffDest;
- uint32_t puffDestLen;
- uint8_t *puffSrc;
- uint32_t puffSrcLen;
-
- /*
- * input verification
- */
-
- if(!(BF && Buffer))
- {
- return(-1);
- }
-
- /*
- * some zeroing
- */
-
- DecompressedData = NULL;
- DecompressedDataLength = 0;
- *Buffer = DecompressedData;
-
- CompressedData = NULL;
- CompressedDataLength = 0;
-
- BytesToRewind = 0;
-
- /*
- * Find the first IDAT chunk.
- */
-
- if(!FindChunk(BF, PNG_ChunkType_IDAT))
- {
- return(-1);
- }
-
- /*
- * Count the size of the uncompressed data
- */
-
- while(qtrue)
- {
- /*
- * Read chunk header
- */
-
- CH = BufferedFileRead(BF, PNG_ChunkHeader_Size);
- if(!CH)
- {
- /*
- * Rewind to the start of this adventure
- * and return unsuccessfull
- */
-
- BufferedFileRewind(BF, BytesToRewind);
-
- return(-1);
- }
-
- /*
- * Length and Type of chunk
- */
-
- Length = BigLong(CH->Length);
- Type = BigLong(CH->Type);
-
- /*
- * We have reached the end of the IDAT chunks
- */
-
- if(!(Type == PNG_ChunkType_IDAT))
- {
- BufferedFileRewind(BF, PNG_ChunkHeader_Size);
-
- break;
- }
-
- /*
- * Add chunk header to count.
- */
-
- BytesToRewind += PNG_ChunkHeader_Size;
-
- /*
- * Skip to next chunk
- */
-
- if(Length)
- {
- if(!BufferedFileSkip(BF, Length + PNG_ChunkCRC_Size))
- {
- BufferedFileRewind(BF, BytesToRewind);
-
- return(-1);
- }
-
- BytesToRewind += Length + PNG_ChunkCRC_Size;
- CompressedDataLength += Length;
- }
- }
-
- BufferedFileRewind(BF, BytesToRewind);
-
- CompressedData = ri.Malloc(CompressedDataLength);
- if(!CompressedData)
- {
- return(-1);
- }
-
- CompressedDataPtr = CompressedData;
-
- /*
- * Collect the compressed Data
- */
-
- while(qtrue)
- {
- /*
- * Read chunk header
- */
-
- CH = BufferedFileRead(BF, PNG_ChunkHeader_Size);
- if(!CH)
- {
- ri.Free(CompressedData);
-
- return(-1);
- }
-
- /*
- * Length and Type of chunk
- */
-
- Length = BigLong(CH->Length);
- Type = BigLong(CH->Type);
-
- /*
- * We have reached the end of the IDAT chunks
- */
-
- if(!(Type == PNG_ChunkType_IDAT))
- {
- BufferedFileRewind(BF, PNG_ChunkHeader_Size);
-
- break;
- }
-
- /*
- * Copy the Data
- */
-
- if(Length)
- {
- uint8_t *OrigCompressedData;
-
- OrigCompressedData = BufferedFileRead(BF, Length);
- if(!OrigCompressedData)
- {
- ri.Free(CompressedData);
-
- return(-1);
- }
-
- if(!BufferedFileSkip(BF, PNG_ChunkCRC_Size))
- {
- ri.Free(CompressedData);
-
- return(-1);
- }
-
- memcpy(CompressedDataPtr, OrigCompressedData, Length);
- CompressedDataPtr += Length;
- }
- }
-
- /*
- * Let puff() calculate the decompressed data length.
- */
-
- puffDest = NULL;
- puffDestLen = 0;
-
- /*
- * The zlib header and checkvalue don't belong to the compressed data.
- */
-
- puffSrc = CompressedData + PNG_ZlibHeader_Size;
- puffSrcLen = CompressedDataLength - PNG_ZlibHeader_Size - PNG_ZlibCheckValue_Size;
-
- /*
- * first puff() to calculate the size of the uncompressed data
- */
-
- puffResult = puff(puffDest, &puffDestLen, puffSrc, &puffSrcLen);
- if(!((puffResult == 0) && (puffDestLen > 0)))
- {
- ri.Free(CompressedData);
-
- return(-1);
- }
-
- /*
- * Allocate the buffer for the uncompressed data.
- */
-
- DecompressedData = ri.Malloc(puffDestLen);
- if(!DecompressedData)
- {
- ri.Free(CompressedData);
-
- return(-1);
- }
-
- /*
- * Set the input again in case something was changed by the last puff() .
- */
-
- puffDest = DecompressedData;
- puffSrc = CompressedData + PNG_ZlibHeader_Size;
- puffSrcLen = CompressedDataLength - PNG_ZlibHeader_Size - PNG_ZlibCheckValue_Size;
-
- /*
- * decompression puff()
- */
-
- puffResult = puff(puffDest, &puffDestLen, puffSrc, &puffSrcLen);
-
- /*
- * The compressed data is not needed anymore.
- */
-
- ri.Free(CompressedData);
-
- /*
- * Check if the last puff() was successfull.
- */
-
- if(!((puffResult == 0) && (puffDestLen > 0)))
- {
- ri.Free(DecompressedData);
-
- return(-1);
- }
-
- /*
- * Set the output of this function.
- */
-
- DecompressedDataLength = puffDestLen;
- *Buffer = DecompressedData;
-
- return(DecompressedDataLength);
-}
-
-/*
- * the Paeth predictor
- */
-
-static uint8_t PredictPaeth(uint8_t a, uint8_t b, uint8_t c)
-{
- /*
- * a == Left
- * b == Up
- * c == UpLeft
- */
-
- uint8_t Pr;
- int p;
- int pa, pb, pc;
-
- Pr = 0;
-
- p = ((int) a) + ((int) b) - ((int) c);
- pa = abs(p - ((int) a));
- pb = abs(p - ((int) b));
- pc = abs(p - ((int) c));
-
- if((pa <= pb) && (pa <= pc))
- {
- Pr = a;
- }
- else if(pb <= pc)
- {
- Pr = b;
- }
- else
- {
- Pr = c;
- }
-
- return(Pr);
-
-}
-
-/*
- * Reverse the filters.
- */
-
-static qboolean UnfilterImage(uint8_t *DecompressedData,
- uint32_t ImageHeight,
- uint32_t BytesPerScanline,
- uint32_t BytesPerPixel)
-{
- uint8_t *DecompPtr;
- uint8_t FilterType;
- uint8_t *PixelLeft, *PixelUp, *PixelUpLeft;
- uint32_t w, h, p;
-
- /*
- * some zeros for the filters
- */
-
- uint8_t Zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0};
-
- /*
- * input verification
- */
-
- if(!(DecompressedData && BytesPerPixel))
- {
- return(qfalse);
- }
-
- /*
- * ImageHeight and BytesPerScanline can be zero in small interlaced images.
- */
-
- if((!ImageHeight) || (!BytesPerScanline))
- {
- return(qtrue);
- }
-
- /*
- * Set the pointer to the start of the decompressed Data.
- */
-
- DecompPtr = DecompressedData;
-
- /*
- * Un-filtering is done in place.
- */
-
- /*
- * Go trough all scanlines.
- */
-
- for(h = 0; h < ImageHeight; h++)
- {
- /*
- * Every scanline starts with a FilterType byte.
- */
-
- FilterType = *DecompPtr;
- DecompPtr++;
-
- /*
- * Left pixel of the first byte in a scanline is zero.
- */
-
- PixelLeft = Zeros;
-
- /*
- * Set PixelUp to previous line only if we are on the second line or above.
- *
- * Plus one byte for the FilterType
- */
-
- if(h > 0)
- {
- PixelUp = DecompPtr - (BytesPerScanline + 1);
- }
- else
- {
- PixelUp = Zeros;
- }
-
- /*
- * The pixel left to the first pixel of the previous scanline is zero too.
- */
-
- PixelUpLeft = Zeros;
-
- /*
- * Cycle trough all pixels of the scanline.
- */
-
- for(w = 0; w < (BytesPerScanline / BytesPerPixel); w++)
- {
- /*
- * Cycle trough the bytes of the pixel.
- */
-
- for(p = 0; p < BytesPerPixel; p++)
- {
- switch(FilterType)
- {
- case PNG_FilterType_None :
- {
- /*
- * The byte is unfiltered.
- */
-
- break;
- }
-
- case PNG_FilterType_Sub :
- {
- DecompPtr[p] += PixelLeft[p];
-
- break;
- }
-
- case PNG_FilterType_Up :
- {
- DecompPtr[p] += PixelUp[p];
-
- break;
- }
-
- case PNG_FilterType_Average :
- {
- DecompPtr[p] += ((uint8_t) ((((uint16_t) PixelLeft[p]) + ((uint16_t) PixelUp[p])) / 2));
-
- break;
- }
-
- case PNG_FilterType_Paeth :
- {
- DecompPtr[p] += PredictPaeth(PixelLeft[p], PixelUp[p], PixelUpLeft[p]);
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
- }
-
- PixelLeft = DecompPtr;
-
- /*
- * We only have a upleft pixel if we are on the second line or above.
- */
-
- if(h > 0)
- {
- PixelUpLeft = DecompPtr - (BytesPerScanline + 1);
- }
-
- /*
- * Skip to the next pixel.
- */
-
- DecompPtr += BytesPerPixel;
-
- /*
- * We only have a previous line if we are on the second line and above.
- */
-
- if(h > 0)
- {
- PixelUp = DecompPtr - (BytesPerScanline + 1);
- }
- }
- }
-
- return(qtrue);
-}
-
-/*
- * Convert a raw input pixel to Quake 3 RGA format.
- */
-
-static qboolean ConvertPixel(struct PNG_Chunk_IHDR *IHDR,
- byte *OutPtr,
- uint8_t *DecompPtr,
- qboolean HasTransparentColour,
- uint8_t *TransparentColour,
- uint8_t *OutPal)
-{
- /*
- * input verification
- */
-
- if(!(IHDR && OutPtr && DecompPtr && TransparentColour && OutPal))
- {
- return(qfalse);
- }
-
- switch(IHDR->ColourType)
- {
- case PNG_ColourType_Grey :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_1 :
- case PNG_BitDepth_2 :
- case PNG_BitDepth_4 :
- {
- uint8_t Step;
- uint8_t GreyValue;
-
- Step = 0xFF / ((1 << IHDR->BitDepth) - 1);
-
- GreyValue = DecompPtr[0] * Step;
-
- OutPtr[0] = GreyValue;
- OutPtr[1] = GreyValue;
- OutPtr[2] = GreyValue;
- OutPtr[3] = 0xFF;
-
- /*
- * Grey supports full transparency for one specified colour
- */
-
- if(HasTransparentColour)
- {
- if(TransparentColour[1] == DecompPtr[0])
- {
- OutPtr[3] = 0x00;
- }
- }
-
-
- break;
- }
-
- case PNG_BitDepth_8 :
- case PNG_BitDepth_16 :
- {
- OutPtr[0] = DecompPtr[0];
- OutPtr[1] = DecompPtr[0];
- OutPtr[2] = DecompPtr[0];
- OutPtr[3] = 0xFF;
-
- /*
- * Grey supports full transparency for one specified colour
- */
-
- if(HasTransparentColour)
- {
- if(IHDR->BitDepth == PNG_BitDepth_8)
- {
- if(TransparentColour[1] == DecompPtr[0])
- {
- OutPtr[3] = 0x00;
- }
- }
- else
- {
- if((TransparentColour[0] == DecompPtr[0]) && (TransparentColour[1] == DecompPtr[1]))
- {
- OutPtr[3] = 0x00;
- }
- }
- }
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- case PNG_ColourType_True :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_8 :
- {
- OutPtr[0] = DecompPtr[0];
- OutPtr[1] = DecompPtr[1];
- OutPtr[2] = DecompPtr[2];
- OutPtr[3] = 0xFF;
-
- /*
- * True supports full transparency for one specified colour
- */
-
- if(HasTransparentColour)
- {
- if((TransparentColour[1] == DecompPtr[0]) &&
- (TransparentColour[3] == DecompPtr[1]) &&
- (TransparentColour[5] == DecompPtr[2]))
- {
- OutPtr[3] = 0x00;
- }
- }
-
- break;
- }
-
- case PNG_BitDepth_16 :
- {
- /*
- * We use only the upper byte.
- */
-
- OutPtr[0] = DecompPtr[0];
- OutPtr[1] = DecompPtr[2];
- OutPtr[2] = DecompPtr[4];
- OutPtr[3] = 0xFF;
-
- /*
- * True supports full transparency for one specified colour
- */
-
- if(HasTransparentColour)
- {
- if((TransparentColour[0] == DecompPtr[0]) && (TransparentColour[1] == DecompPtr[1]) &&
- (TransparentColour[2] == DecompPtr[2]) && (TransparentColour[3] == DecompPtr[3]) &&
- (TransparentColour[4] == DecompPtr[4]) && (TransparentColour[5] == DecompPtr[5]))
- {
- OutPtr[3] = 0x00;
- }
- }
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- case PNG_ColourType_Indexed :
- {
- OutPtr[0] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 0];
- OutPtr[1] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 1];
- OutPtr[2] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 2];
- OutPtr[3] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 3];
-
- break;
- }
-
- case PNG_ColourType_GreyAlpha :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_8 :
- {
- OutPtr[0] = DecompPtr[0];
- OutPtr[1] = DecompPtr[0];
- OutPtr[2] = DecompPtr[0];
- OutPtr[3] = DecompPtr[1];
-
- break;
- }
-
- case PNG_BitDepth_16 :
- {
- /*
- * We use only the upper byte.
- */
-
- OutPtr[0] = DecompPtr[0];
- OutPtr[1] = DecompPtr[0];
- OutPtr[2] = DecompPtr[0];
- OutPtr[3] = DecompPtr[2];
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- case PNG_ColourType_TrueAlpha :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_8 :
- {
- OutPtr[0] = DecompPtr[0];
- OutPtr[1] = DecompPtr[1];
- OutPtr[2] = DecompPtr[2];
- OutPtr[3] = DecompPtr[3];
-
- break;
- }
-
- case PNG_BitDepth_16 :
- {
- /*
- * We use only the upper byte.
- */
-
- OutPtr[0] = DecompPtr[0];
- OutPtr[1] = DecompPtr[2];
- OutPtr[2] = DecompPtr[4];
- OutPtr[3] = DecompPtr[6];
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- return(qtrue);
-}
-
-
-/*
- * Decode a non-interlaced image.
- */
-
-static qboolean DecodeImageNonInterlaced(struct PNG_Chunk_IHDR *IHDR,
- byte *OutBuffer,
- uint8_t *DecompressedData,
- uint32_t DecompressedDataLength,
- qboolean HasTransparentColour,
- uint8_t *TransparentColour,
- uint8_t *OutPal)
-{
- uint32_t IHDR_Width;
- uint32_t IHDR_Height;
- uint32_t BytesPerScanline, BytesPerPixel, PixelsPerByte;
- uint32_t w, h, p;
- byte *OutPtr;
- uint8_t *DecompPtr;
-
- /*
- * input verification
- */
-
- if(!(IHDR && OutBuffer && DecompressedData && DecompressedDataLength && TransparentColour && OutPal))
- {
- return(qfalse);
- }
-
- /*
- * byte swapping
- */
-
- IHDR_Width = BigLong(IHDR->Width);
- IHDR_Height = BigLong(IHDR->Height);
-
- /*
- * information for un-filtering
- */
-
- switch(IHDR->ColourType)
- {
- case PNG_ColourType_Grey :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_1 :
- case PNG_BitDepth_2 :
- case PNG_BitDepth_4 :
- {
- BytesPerPixel = 1;
- PixelsPerByte = 8 / IHDR->BitDepth;
-
- break;
- }
-
- case PNG_BitDepth_8 :
- case PNG_BitDepth_16 :
- {
- BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_Grey;
- PixelsPerByte = 1;
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- case PNG_ColourType_True :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_8 :
- case PNG_BitDepth_16 :
- {
- BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_True;
- PixelsPerByte = 1;
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- case PNG_ColourType_Indexed :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_1 :
- case PNG_BitDepth_2 :
- case PNG_BitDepth_4 :
- {
- BytesPerPixel = 1;
- PixelsPerByte = 8 / IHDR->BitDepth;
-
- break;
- }
-
- case PNG_BitDepth_8 :
- {
- BytesPerPixel = PNG_NumColourComponents_Indexed;
- PixelsPerByte = 1;
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- case PNG_ColourType_GreyAlpha :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_8 :
- case PNG_BitDepth_16 :
- {
- BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_GreyAlpha;
- PixelsPerByte = 1;
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- case PNG_ColourType_TrueAlpha :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_8 :
- case PNG_BitDepth_16 :
- {
- BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_TrueAlpha;
- PixelsPerByte = 1;
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- /*
- * Calculate the size of one scanline
- */
-
- BytesPerScanline = (IHDR_Width * BytesPerPixel + (PixelsPerByte - 1)) / PixelsPerByte;
-
- /*
- * Check if we have enough data for the whole image.
- */
-
- if(!(DecompressedDataLength == ((BytesPerScanline + 1) * IHDR_Height)))
- {
- return(qfalse);
- }
-
- /*
- * Unfilter the image.
- */
-
- if(!UnfilterImage(DecompressedData, IHDR_Height, BytesPerScanline, BytesPerPixel))
- {
- return(qfalse);
- }
-
- /*
- * Set the working pointers to the beginning of the buffers.
- */
-
- OutPtr = OutBuffer;
- DecompPtr = DecompressedData;
-
- /*
- * Create the output image.
- */
-
- for(h = 0; h < IHDR_Height; h++)
- {
- /*
- * Count the pixels on the scanline for those multipixel bytes
- */
-
- uint32_t CurrPixel;
-
- /*
- * skip FilterType
- */
-
- DecompPtr++;
-
- /*
- * Reset the pixel count.
- */
-
- CurrPixel = 0;
-
- for(w = 0; w < (BytesPerScanline / BytesPerPixel); w++)
- {
- if(PixelsPerByte > 1)
- {
- uint8_t Mask;
- uint32_t Shift;
- uint8_t SinglePixel;
-
- for(p = 0; p < PixelsPerByte; p++)
- {
- if(CurrPixel < IHDR_Width)
- {
- Mask = (1 << IHDR->BitDepth) - 1;
- Shift = (PixelsPerByte - 1 - p) * IHDR->BitDepth;
-
- SinglePixel = ((DecompPtr[0] & (Mask << Shift)) >> Shift);
-
- if(!ConvertPixel(IHDR, OutPtr, &SinglePixel, HasTransparentColour, TransparentColour, OutPal))
- {
- return(qfalse);
- }
-
- OutPtr += Q3IMAGE_BYTESPERPIXEL;
- CurrPixel++;
- }
- }
-
- }
- else
- {
- if(!ConvertPixel(IHDR, OutPtr, DecompPtr, HasTransparentColour, TransparentColour, OutPal))
- {
- return(qfalse);
- }
-
-
- OutPtr += Q3IMAGE_BYTESPERPIXEL;
- }
-
- DecompPtr += BytesPerPixel;
- }
- }
-
- return(qtrue);
-}
-
-/*
- * Decode an interlaced image.
- */
-
-static qboolean DecodeImageInterlaced(struct PNG_Chunk_IHDR *IHDR,
- byte *OutBuffer,
- uint8_t *DecompressedData,
- uint32_t DecompressedDataLength,
- qboolean HasTransparentColour,
- uint8_t *TransparentColour,
- uint8_t *OutPal)
-{
- uint32_t IHDR_Width;
- uint32_t IHDR_Height;
- uint32_t BytesPerScanline[PNG_Adam7_NumPasses], BytesPerPixel, PixelsPerByte;
- uint32_t PassWidth[PNG_Adam7_NumPasses], PassHeight[PNG_Adam7_NumPasses];
- uint32_t WSkip[PNG_Adam7_NumPasses], WOffset[PNG_Adam7_NumPasses], HSkip[PNG_Adam7_NumPasses], HOffset[PNG_Adam7_NumPasses];
- uint32_t w, h, p, a;
- byte *OutPtr;
- uint8_t *DecompPtr;
- uint32_t TargetLength;
-
- /*
- * input verification
- */
-
- if(!(IHDR && OutBuffer && DecompressedData && DecompressedDataLength && TransparentColour && OutPal))
- {
- return(qfalse);
- }
-
- /*
- * byte swapping
- */
-
- IHDR_Width = BigLong(IHDR->Width);
- IHDR_Height = BigLong(IHDR->Height);
-
- /*
- * Skip and Offset for the passes.
- */
-
- WSkip[0] = 8;
- WOffset[0] = 0;
- HSkip[0] = 8;
- HOffset[0] = 0;
-
- WSkip[1] = 8;
- WOffset[1] = 4;
- HSkip[1] = 8;
- HOffset[1] = 0;
-
- WSkip[2] = 4;
- WOffset[2] = 0;
- HSkip[2] = 8;
- HOffset[2] = 4;
-
- WSkip[3] = 4;
- WOffset[3] = 2;
- HSkip[3] = 4;
- HOffset[3] = 0;
-
- WSkip[4] = 2;
- WOffset[4] = 0;
- HSkip[4] = 4;
- HOffset[4] = 2;
-
- WSkip[5] = 2;
- WOffset[5] = 1;
- HSkip[5] = 2;
- HOffset[5] = 0;
-
- WSkip[6] = 1;
- WOffset[6] = 0;
- HSkip[6] = 2;
- HOffset[6] = 1;
-
- /*
- * Calculate the sizes of the passes.
- */
-
- PassWidth[0] = (IHDR_Width + 7) / 8;
- PassHeight[0] = (IHDR_Height + 7) / 8;
-
- PassWidth[1] = (IHDR_Width + 3) / 8;
- PassHeight[1] = (IHDR_Height + 7) / 8;
-
- PassWidth[2] = (IHDR_Width + 3) / 4;
- PassHeight[2] = (IHDR_Height + 3) / 8;
-
- PassWidth[3] = (IHDR_Width + 1) / 4;
- PassHeight[3] = (IHDR_Height + 3) / 4;
-
- PassWidth[4] = (IHDR_Width + 1) / 2;
- PassHeight[4] = (IHDR_Height + 1) / 4;
-
- PassWidth[5] = (IHDR_Width + 0) / 2;
- PassHeight[5] = (IHDR_Height + 1) / 2;
-
- PassWidth[6] = (IHDR_Width + 0) / 1;
- PassHeight[6] = (IHDR_Height + 0) / 2;
-
- /*
- * information for un-filtering
- */
-
- switch(IHDR->ColourType)
- {
- case PNG_ColourType_Grey :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_1 :
- case PNG_BitDepth_2 :
- case PNG_BitDepth_4 :
- {
- BytesPerPixel = 1;
- PixelsPerByte = 8 / IHDR->BitDepth;
-
- break;
- }
-
- case PNG_BitDepth_8 :
- case PNG_BitDepth_16 :
- {
- BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_Grey;
- PixelsPerByte = 1;
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- case PNG_ColourType_True :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_8 :
- case PNG_BitDepth_16 :
- {
- BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_True;
- PixelsPerByte = 1;
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- case PNG_ColourType_Indexed :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_1 :
- case PNG_BitDepth_2 :
- case PNG_BitDepth_4 :
- {
- BytesPerPixel = 1;
- PixelsPerByte = 8 / IHDR->BitDepth;
-
- break;
- }
-
- case PNG_BitDepth_8 :
- {
- BytesPerPixel = PNG_NumColourComponents_Indexed;
- PixelsPerByte = 1;
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- case PNG_ColourType_GreyAlpha :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_8 :
- case PNG_BitDepth_16 :
- {
- BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_GreyAlpha;
- PixelsPerByte = 1;
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- case PNG_ColourType_TrueAlpha :
- {
- switch(IHDR->BitDepth)
- {
- case PNG_BitDepth_8 :
- case PNG_BitDepth_16 :
- {
- BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_TrueAlpha;
- PixelsPerByte = 1;
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- break;
- }
-
- default :
- {
- return(qfalse);
- }
- }
-
- /*
- * Calculate the size of the scanlines per pass
- */
-
- for(a = 0; a < PNG_Adam7_NumPasses; a++)
- {
- BytesPerScanline[a] = (PassWidth[a] * BytesPerPixel + (PixelsPerByte - 1)) / PixelsPerByte;
- }
-
- /*
- * Calculate the size of all passes
- */
-
- TargetLength = 0;
-
- for(a = 0; a < PNG_Adam7_NumPasses; a++)
- {
- TargetLength += ((BytesPerScanline[a] + (BytesPerScanline[a] ? 1 : 0)) * PassHeight[a]);
- }
-
- /*
- * Check if we have enough data for the whole image.
- */
-
- if(!(DecompressedDataLength == TargetLength))
- {
- return(qfalse);
- }
-
- /*
- * Unfilter the image.
- */
-
- DecompPtr = DecompressedData;
-
- for(a = 0; a < PNG_Adam7_NumPasses; a++)
- {
- if(!UnfilterImage(DecompPtr, PassHeight[a], BytesPerScanline[a], BytesPerPixel))
- {
- return(qfalse);
- }
-
- DecompPtr += ((BytesPerScanline[a] + (BytesPerScanline[a] ? 1 : 0)) * PassHeight[a]);
- }
-
- /*
- * Set the working pointers to the beginning of the buffers.
- */
-
- DecompPtr = DecompressedData;
-
- /*
- * Create the output image.
- */
-
- for(a = 0; a < PNG_Adam7_NumPasses; a++)
- {
- for(h = 0; h < PassHeight[a]; h++)
- {
- /*
- * Count the pixels on the scanline for those multipixel bytes
- */
-
- uint32_t CurrPixel;
-
- /*
- * skip FilterType
- * but only when the pass has a width bigger than zero
- */
-
- if(BytesPerScanline[a])
- {
- DecompPtr++;
- }
-
- /*
- * Reset the pixel count.
- */
-
- CurrPixel = 0;
-
- for(w = 0; w < (BytesPerScanline[a] / BytesPerPixel); w++)
- {
- if(PixelsPerByte > 1)
- {
- uint8_t Mask;
- uint32_t Shift;
- uint8_t SinglePixel;
-
- for(p = 0; p < PixelsPerByte; p++)
- {
- if(CurrPixel < PassWidth[a])
- {
- Mask = (1 << IHDR->BitDepth) - 1;
- Shift = (PixelsPerByte - 1 - p) * IHDR->BitDepth;
-
- SinglePixel = ((DecompPtr[0] & (Mask << Shift)) >> Shift);
-
- OutPtr = OutBuffer + (((((h * HSkip[a]) + HOffset[a]) * IHDR_Width) + ((CurrPixel * WSkip[a]) + WOffset[a])) * Q3IMAGE_BYTESPERPIXEL);
-
- if(!ConvertPixel(IHDR, OutPtr, &SinglePixel, HasTransparentColour, TransparentColour, OutPal))
- {
- return(qfalse);
- }
-
- CurrPixel++;
- }
- }
-
- }
- else
- {
- OutPtr = OutBuffer + (((((h * HSkip[a]) + HOffset[a]) * IHDR_Width) + ((w * WSkip[a]) + WOffset[a])) * Q3IMAGE_BYTESPERPIXEL);
-
- if(!ConvertPixel(IHDR, OutPtr, DecompPtr, HasTransparentColour, TransparentColour, OutPal))
- {
- return(qfalse);
- }
- }
-
- DecompPtr += BytesPerPixel;
- }
- }
- }
-
- return(qtrue);
-}
-
-/*
- * The PNG loader
- */
-
-void R_LoadPNG(const char *name, byte **pic, int *width, int *height)
-{
- struct BufferedFile *ThePNG;
- byte *OutBuffer;
- uint8_t *Signature;
- struct PNG_ChunkHeader *CH;
- uint32_t ChunkHeaderLength;
- uint32_t ChunkHeaderType;
- struct PNG_Chunk_IHDR *IHDR;
- uint32_t IHDR_Width;
- uint32_t IHDR_Height;
- PNG_ChunkCRC *CRC;
- uint8_t *InPal;
- uint8_t *DecompressedData;
- uint32_t DecompressedDataLength;
- uint32_t i;
-
- /*
- * palette with 256 RGBA entries
- */
-
- uint8_t OutPal[1024];
-
- /*
- * transparent colour from the tRNS chunk
- */
-
- qboolean HasTransparentColour = qfalse;
- uint8_t TransparentColour[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-
- /*
- * input verification
- */
-
- if(!(name && pic))
- {
- return;
- }
-
- /*
- * Zero out return values.
- */
-
- *pic = NULL;
-
- if(width)
- {
- *width = 0;
- }
-
- if(height)
- {
- *height = 0;
- }
-
- /*
- * Read the file.
- */
-
- ThePNG = ReadBufferedFile(name);
- if(!ThePNG)
- {
- return;
- }
-
- /*
- * Read the siganture of the file.
- */
-
- Signature = BufferedFileRead(ThePNG, PNG_Signature_Size);
- if(!Signature)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Is it a PNG?
- */
-
- if(memcmp(Signature, PNG_Signature, PNG_Signature_Size))
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Read the first chunk-header.
- */
-
- CH = BufferedFileRead(ThePNG, PNG_ChunkHeader_Size);
- if(!CH)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * PNG multi-byte types are in Big Endian
- */
-
- ChunkHeaderLength = BigLong(CH->Length);
- ChunkHeaderType = BigLong(CH->Type);
-
- /*
- * Check if the first chunk is an IHDR.
- */
-
- if(!((ChunkHeaderType == PNG_ChunkType_IHDR) && (ChunkHeaderLength == PNG_Chunk_IHDR_Size)))
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Read the IHDR.
- */
-
- IHDR = BufferedFileRead(ThePNG, PNG_Chunk_IHDR_Size);
- if(!IHDR)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Read the CRC for IHDR
- */
-
- CRC = BufferedFileRead(ThePNG, PNG_ChunkCRC_Size);
- if(!CRC)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Here we could check the CRC if we wanted to.
- */
-
- /*
- * multi-byte type swapping
- */
-
- IHDR_Width = BigLong(IHDR->Width);
- IHDR_Height = BigLong(IHDR->Height);
-
- /*
- * Check if Width and Height are valid.
- */
-
- if(!((IHDR_Width > 0) && (IHDR_Height > 0))
- || IHDR_Width > INT_MAX / Q3IMAGE_BYTESPERPIXEL / IHDR_Height)
- {
- CloseBufferedFile(ThePNG);
-
- Com_Printf(S_COLOR_YELLOW "%s: invalid image size\n", name);
-
- return;
- }
-
- /*
- * Do we need to check if the dimensions of the image are valid for Quake3?
- */
-
- /*
- * Check if CompressionMethod and FilterMethod are valid.
- */
-
- if(!((IHDR->CompressionMethod == PNG_CompressionMethod_0) && (IHDR->FilterMethod == PNG_FilterMethod_0)))
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Check if InterlaceMethod is valid.
- */
-
- if(!((IHDR->InterlaceMethod == PNG_InterlaceMethod_NonInterlaced) || (IHDR->InterlaceMethod == PNG_InterlaceMethod_Interlaced)))
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Read palette for an indexed image.
- */
-
- if(IHDR->ColourType == PNG_ColourType_Indexed)
- {
- /*
- * We need the palette first.
- */
-
- if(!FindChunk(ThePNG, PNG_ChunkType_PLTE))
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Read the chunk-header.
- */
-
- CH = BufferedFileRead(ThePNG, PNG_ChunkHeader_Size);
- if(!CH)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * PNG multi-byte types are in Big Endian
- */
-
- ChunkHeaderLength = BigLong(CH->Length);
- ChunkHeaderType = BigLong(CH->Type);
-
- /*
- * Check if the chunk is an PLTE.
- */
-
- if(!(ChunkHeaderType == PNG_ChunkType_PLTE))
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Check if Length is divisible by 3
- */
-
- if(ChunkHeaderLength % 3)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Read the raw palette data
- */
-
- InPal = BufferedFileRead(ThePNG, ChunkHeaderLength);
- if(!InPal)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Read the CRC for the palette
- */
-
- CRC = BufferedFileRead(ThePNG, PNG_ChunkCRC_Size);
- if(!CRC)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Set some default values.
- */
-
- for(i = 0; i < 256; i++)
- {
- OutPal[i * Q3IMAGE_BYTESPERPIXEL + 0] = 0x00;
- OutPal[i * Q3IMAGE_BYTESPERPIXEL + 1] = 0x00;
- OutPal[i * Q3IMAGE_BYTESPERPIXEL + 2] = 0x00;
- OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = 0xFF;
- }
-
- /*
- * Convert to the Quake3 RGBA-format.
- */
-
- for(i = 0; i < (ChunkHeaderLength / 3); i++)
- {
- OutPal[i * Q3IMAGE_BYTESPERPIXEL + 0] = InPal[i*3+0];
- OutPal[i * Q3IMAGE_BYTESPERPIXEL + 1] = InPal[i*3+1];
- OutPal[i * Q3IMAGE_BYTESPERPIXEL + 2] = InPal[i*3+2];
- OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = 0xFF;
- }
- }
-
- /*
- * transparency information is sometimes stored in an tRNS chunk
- */
-
- /*
- * Let's see if there is a tRNS chunk
- */
-
- if(FindChunk(ThePNG, PNG_ChunkType_tRNS))
- {
- uint8_t *Trans;
-
- /*
- * Read the chunk-header.
- */
-
- CH = BufferedFileRead(ThePNG, PNG_ChunkHeader_Size);
- if(!CH)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * PNG multi-byte types are in Big Endian
- */
-
- ChunkHeaderLength = BigLong(CH->Length);
- ChunkHeaderType = BigLong(CH->Type);
-
- /*
- * Check if the chunk is an tRNS.
- */
-
- if(!(ChunkHeaderType == PNG_ChunkType_tRNS))
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Read the transparency information.
- */
-
- Trans = BufferedFileRead(ThePNG, ChunkHeaderLength);
- if(!Trans)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Read the CRC.
- */
-
- CRC = BufferedFileRead(ThePNG, PNG_ChunkCRC_Size);
- if(!CRC)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Only for Grey, True and Indexed ColourType should tRNS exist.
- */
-
- switch(IHDR->ColourType)
- {
- case PNG_ColourType_Grey :
- {
- if(!ChunkHeaderLength == 2)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- HasTransparentColour = qtrue;
-
- /*
- * Grey can have one colour which is completely transparent.
- * This colour is always stored in 16 bits.
- */
-
- TransparentColour[0] = Trans[0];
- TransparentColour[1] = Trans[1];
-
- break;
- }
-
- case PNG_ColourType_True :
- {
- if(!ChunkHeaderLength == 6)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- HasTransparentColour = qtrue;
-
- /*
- * True can have one colour which is completely transparent.
- * This colour is always stored in 16 bits.
- */
-
- TransparentColour[0] = Trans[0];
- TransparentColour[1] = Trans[1];
- TransparentColour[2] = Trans[2];
- TransparentColour[3] = Trans[3];
- TransparentColour[4] = Trans[4];
- TransparentColour[5] = Trans[5];
-
- break;
- }
-
- case PNG_ColourType_Indexed :
- {
- /*
- * Maximum of 256 one byte transparency entries.
- */
-
- if(ChunkHeaderLength > 256)
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- HasTransparentColour = qtrue;
-
- /*
- * alpha values for palette entries
- */
-
- for(i = 0; i < ChunkHeaderLength; i++)
- {
- OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = Trans[i];
- }
-
- break;
- }
-
- /*
- * All other ColourTypes should not have tRNS chunks
- */
-
- default :
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
- }
- }
-
- /*
- * Rewind to the start of the file.
- */
-
- if(!BufferedFileRewind(ThePNG, -1))
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Skip the signature
- */
-
- if(!BufferedFileSkip(ThePNG, PNG_Signature_Size))
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Decompress all IDAT chunks
- */
-
- DecompressedDataLength = DecompressIDATs(ThePNG, &DecompressedData);
- if(!(DecompressedDataLength && DecompressedData))
- {
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Allocate output buffer.
- */
-
- OutBuffer = ri.Malloc(IHDR_Width * IHDR_Height * Q3IMAGE_BYTESPERPIXEL);
- if(!OutBuffer)
- {
- ri.Free(DecompressedData);
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- /*
- * Interlaced and Non-interlaced images need to be handled differently.
- */
-
- switch(IHDR->InterlaceMethod)
- {
- case PNG_InterlaceMethod_NonInterlaced :
- {
- if(!DecodeImageNonInterlaced(IHDR, OutBuffer, DecompressedData, DecompressedDataLength, HasTransparentColour, TransparentColour, OutPal))
- {
- ri.Free(OutBuffer);
- ri.Free(DecompressedData);
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- break;
- }
-
- case PNG_InterlaceMethod_Interlaced :
- {
- if(!DecodeImageInterlaced(IHDR, OutBuffer, DecompressedData, DecompressedDataLength, HasTransparentColour, TransparentColour, OutPal))
- {
- ri.Free(OutBuffer);
- ri.Free(DecompressedData);
- CloseBufferedFile(ThePNG);
-
- return;
- }
-
- break;
- }
-
- default :
- {
- ri.Free(OutBuffer);
- ri.Free(DecompressedData);
- CloseBufferedFile(ThePNG);
-
- return;
- }
- }
-
- /*
- * update the pointer to the image data
- */
-
- *pic = OutBuffer;
-
- /*
- * Fill width and height.
- */
-
- if(width)
- {
- *width = IHDR_Width;
- }
-
- if(height)
- {
- *height = IHDR_Height;
- }
-
- /*
- * DecompressedData is not needed anymore.
- */
-
- ri.Free(DecompressedData);
-
- /*
- * We have all data, so close the file.
- */
-
- CloseBufferedFile(ThePNG);
-}
diff --git a/engine/code/renderer/tr_image_tga.c b/engine/code/renderer/tr_image_tga.c
deleted file mode 100644
index e66e60d..0000000
--- a/engine/code/renderer/tr_image_tga.c
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "tr_local.h"
-
-/*
-========================================================================
-
-TGA files are used for 24/32 bit images
-
-========================================================================
-*/
-
-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;
-
-void R_LoadTGA ( const char *name, byte **pic, int *width, int *height)
-{
- unsigned columns, rows, numPixels;
- byte *pixbuf;
- int row, column;
- byte *buf_p;
- byte *end;
- union {
- byte *b;
- void *v;
- } buffer;
- TargaHeader targa_header;
- byte *targa_rgba;
- int length;
-
- *pic = NULL;
-
- if(width)
- *width = 0;
- if(height)
- *height = 0;
-
- //
- // load the file
- //
- length = ri.FS_ReadFile ( ( char * ) name, &buffer.v);
- if (!buffer.b || length < 0) {
- return;
- }
-
- if(length < 18)
- {
- ri.Error( ERR_DROP, "LoadTGA: header too short (%s)\n", name );
- }
-
- buf_p = buffer.b;
- end = buffer.b + length;
-
- targa_header.id_length = buf_p[0];
- targa_header.colormap_type = buf_p[1];
- targa_header.image_type = buf_p[2];
-
- memcpy(&targa_header.colormap_index, &buf_p[3], 2);
- memcpy(&targa_header.colormap_length, &buf_p[5], 2);
- targa_header.colormap_size = buf_p[7];
- memcpy(&targa_header.x_origin, &buf_p[8], 2);
- memcpy(&targa_header.y_origin, &buf_p[10], 2);
- memcpy(&targa_header.width, &buf_p[12], 2);
- memcpy(&targa_header.height, &buf_p[14], 2);
- targa_header.pixel_size = buf_p[16];
- targa_header.attributes = buf_p[17];
-
- targa_header.colormap_index = LittleShort(targa_header.colormap_index);
- targa_header.colormap_length = LittleShort(targa_header.colormap_length);
- targa_header.x_origin = LittleShort(targa_header.x_origin);
- targa_header.y_origin = LittleShort(targa_header.y_origin);
- targa_header.width = LittleShort(targa_header.width);
- targa_header.height = LittleShort(targa_header.height);
-
- buf_p += 18;
-
- if (targa_header.image_type!=2
- && targa_header.image_type!=10
- && targa_header.image_type != 3 )
- {
- ri.Error (ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
- }
-
- if ( targa_header.colormap_type != 0 )
- {
- ri.Error( ERR_DROP, "LoadTGA: colormaps not supported\n" );
- }
-
- if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 )
- {
- ri.Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
- }
-
- columns = targa_header.width;
- rows = targa_header.height;
- numPixels = columns * rows * 4;
-
- if(!columns || !rows || numPixels > 0x7FFFFFFF || numPixels / columns / 4 != rows)
- {
- ri.Error (ERR_DROP, "LoadTGA: %s has an invalid image size\n", name);
- }
-
-
- targa_rgba = ri.Malloc (numPixels);
-
- if (targa_header.id_length != 0)
- {
- if (buf_p + targa_header.id_length > end)
- ri.Error( ERR_DROP, "LoadTGA: header too short (%s)\n", name );
-
- buf_p += targa_header.id_length; // skip TARGA image comment
- }
-
- if ( targa_header.image_type==2 || targa_header.image_type == 3 )
- {
- if(buf_p + columns*rows*targa_header.pixel_size/8 > end)
- {
- ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name);
- }
-
- // Uncompressed RGB or gray scale image
- for(row=rows-1; row>=0; row--)
- {
- pixbuf = targa_rgba + row*columns*4;
- for(column=0; column<columns; column++)
- {
- unsigned char red,green,blue,alphabyte;
- switch (targa_header.pixel_size)
- {
-
- case 8:
- blue = *buf_p++;
- green = blue;
- red = blue;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
-
- case 24:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = alphabyte;
- break;
- default:
- ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
- break;
- }
- }
- }
- }
- else if (targa_header.image_type==10) { // Runlength encoded RGB images
- unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
-
- red = 0;
- green = 0;
- blue = 0;
- alphabyte = 0xff;
-
- for(row=rows-1; row>=0; row--) {
- pixbuf = targa_rgba + row*columns*4;
- for(column=0; column<columns; ) {
- if(buf_p + 1 > end)
- ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name);
- packetHeader= *buf_p++;
- packetSize = 1 + (packetHeader & 0x7f);
- if (packetHeader & 0x80) { // run-length packet
- if(buf_p + targa_header.pixel_size/8 > end)
- ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name);
- switch (targa_header.pixel_size) {
- case 24:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = *buf_p++;
- break;
- default:
- ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
- break;
- }
-
- for(j=0;j<packetSize;j++) {
- *pixbuf++=red;
- *pixbuf++=green;
- *pixbuf++=blue;
- *pixbuf++=alphabyte;
- column++;
- if (column==columns) { // run spans across rows
- column=0;
- if (row>0)
- row--;
- else
- goto breakOut;
- pixbuf = targa_rgba + row*columns*4;
- }
- }
- }
- else { // non run-length packet
-
- if(buf_p + targa_header.pixel_size/8*packetSize > end)
- ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name);
- for(j=0;j<packetSize;j++) {
- switch (targa_header.pixel_size) {
- case 24:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = alphabyte;
- break;
- default:
- ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
- break;
- }
- column++;
- if (column==columns) { // pixel packet run spans across rows
- column=0;
- if (row>0)
- row--;
- else
- goto breakOut;
- pixbuf = targa_rgba + row*columns*4;
- }
- }
- }
- }
- breakOut:;
- }
- }
-
-#if 0
- // TTimo: this is the chunk of code to ensure a behavior that meets TGA specs
- // bit 5 set => top-down
- if (targa_header.attributes & 0x20) {
- unsigned char *flip = (unsigned char*)malloc (columns*4);
- unsigned char *src, *dst;
-
- for (row = 0; row < rows/2; row++) {
- src = targa_rgba + row * 4 * columns;
- dst = targa_rgba + (rows - row - 1) * 4 * columns;
-
- memcpy (flip, src, columns*4);
- memcpy (src, dst, columns*4);
- memcpy (dst, flip, columns*4);
- }
- free (flip);
- }
-#endif
- // instead we just print a warning
- if (targa_header.attributes & 0x20) {
- ri.Printf( PRINT_WARNING, "WARNING: '%s' TGA file header declares top-down image, ignoring\n", name);
- }
-
- if (width)
- *width = columns;
- if (height)
- *height = rows;
-
- *pic = targa_rgba;
-
- ri.FS_FreeFile (buffer.v);
-}
diff --git a/engine/code/renderer/tr_init.c b/engine/code/renderer/tr_init.c
deleted file mode 100644
index 8c0cf68..0000000
--- a/engine/code/renderer/tr_init.c
+++ /dev/null
@@ -1,1245 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_init.c -- functions that are not called every frame
-
-#include "tr_local.h"
-
-glconfig_t glConfig;
-qboolean textureFilterAnisotropic = qfalse;
-int maxAnisotropy = 0;
-float displayAspect = 0.0f;
-
-glstate_t glState;
-
-static void GfxInfo_f( void );
-
-cvar_t *r_flareSize;
-cvar_t *r_flareFade;
-cvar_t *r_flareCoeff;
-
-cvar_t *r_railWidth;
-cvar_t *r_railCoreWidth;
-cvar_t *r_railSegmentLength;
-
-cvar_t *r_ignoreFastPath;
-
-cvar_t *r_verbose;
-cvar_t *r_ignore;
-
-cvar_t *r_detailTextures;
-
-cvar_t *r_znear;
-cvar_t *r_zproj;
-cvar_t *r_stereoSeparation;
-
-cvar_t *r_smp;
-cvar_t *r_showSmp;
-cvar_t *r_skipBackEnd;
-
-cvar_t *r_stereoEnabled;
-cvar_t *r_anaglyphMode;
-
-cvar_t *r_greyscale;
-
-cvar_t *r_ignorehwgamma;
-cvar_t *r_measureOverdraw;
-
-cvar_t *r_inGameVideo;
-cvar_t *r_fastsky;
-cvar_t *r_drawSun;
-cvar_t *r_dynamiclight;
-cvar_t *r_dlightBacks;
-
-cvar_t *r_lodbias;
-cvar_t *r_lodscale;
-
-cvar_t *r_norefresh;
-cvar_t *r_drawentities;
-cvar_t *r_drawworld;
-cvar_t *r_speeds;
-cvar_t *r_fullbright;
-cvar_t *r_novis;
-cvar_t *r_nocull;
-cvar_t *r_facePlaneCull;
-cvar_t *r_showcluster;
-cvar_t *r_nocurves;
-
-cvar_t *r_allowExtensions;
-
-cvar_t *r_ext_compressed_textures;
-cvar_t *r_ext_multitexture;
-cvar_t *r_ext_compiled_vertex_array;
-cvar_t *r_ext_texture_env_add;
-cvar_t *r_ext_texture_filter_anisotropic;
-cvar_t *r_ext_max_anisotropy;
-
-cvar_t *r_ignoreGLErrors;
-cvar_t *r_logFile;
-
-cvar_t *r_stencilbits;
-cvar_t *r_depthbits;
-cvar_t *r_colorbits;
-cvar_t *r_primitives;
-cvar_t *r_texturebits;
-cvar_t *r_ext_multisample;
-
-cvar_t *r_drawBuffer;
-cvar_t *r_lightmap;
-cvar_t *r_vertexLight;
-cvar_t *r_uiFullScreen;
-cvar_t *r_shadows;
-cvar_t *r_flares;
-cvar_t *r_mode;
-cvar_t *r_nobind;
-cvar_t *r_singleShader;
-cvar_t *r_roundImagesDown;
-cvar_t *r_colorMipLevels;
-cvar_t *r_picmip;
-cvar_t *r_showtris;
-cvar_t *r_showsky;
-cvar_t *r_shownormals;
-cvar_t *r_finish;
-cvar_t *r_clear;
-cvar_t *r_swapInterval;
-cvar_t *r_textureMode;
-cvar_t *r_offsetFactor;
-cvar_t *r_offsetUnits;
-cvar_t *r_gamma;
-cvar_t *r_intensity;
-cvar_t *r_lockpvs;
-cvar_t *r_noportals;
-cvar_t *r_portalOnly;
-
-cvar_t *r_subdivisions;
-cvar_t *r_lodCurveError;
-
-cvar_t *r_fullscreen;
-cvar_t *r_noborder;
-
-cvar_t *r_customwidth;
-cvar_t *r_customheight;
-cvar_t *r_customPixelAspect;
-
-cvar_t *r_overBrightBits;
-cvar_t *r_mapOverBrightBits;
-
-cvar_t *r_debugSurface;
-cvar_t *r_simpleMipMaps;
-
-cvar_t *r_showImages;
-
-cvar_t *r_ambientScale;
-cvar_t *r_directedScale;
-cvar_t *r_debugLight;
-cvar_t *r_debugSort;
-cvar_t *r_printShaders;
-cvar_t *r_saveFontData;
-
-cvar_t *r_marksOnTriangleMeshes;
-
-cvar_t *r_maxpolys;
-int max_polys;
-cvar_t *r_maxpolyverts;
-int max_polyverts;
-
-/*
-** InitOpenGL
-**
-** This function is responsible for initializing a valid OpenGL subsystem. This
-** is done by calling GLimp_Init (which gives us a working OGL subsystem) then
-** setting variables, checking GL constants, and reporting the gfx system config
-** to the user.
-*/
-static void InitOpenGL( void )
-{
- char renderer_buffer[1024];
-
- //
- // initialize OS specific portions of the renderer
- //
- // GLimp_Init directly or indirectly references the following cvars:
- // - r_fullscreen
- // - r_mode
- // - r_(color|depth|stencil)bits
- // - r_ignorehwgamma
- // - r_gamma
- //
-
- if ( glConfig.vidWidth == 0 )
- {
- GLint temp;
-
- GLimp_Init();
-
- strcpy( renderer_buffer, glConfig.renderer_string );
- Q_strlwr( renderer_buffer );
-
- // OpenGL driver constants
- qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp );
- glConfig.maxTextureSize = temp;
-
- // stubbed or broken drivers may have reported 0...
- if ( glConfig.maxTextureSize <= 0 )
- {
- glConfig.maxTextureSize = 0;
- }
- }
-
- // init command buffers and SMP
- R_InitCommandBuffers();
-
- // print info
- GfxInfo_f();
-
- // set default state
- GL_SetDefaultState();
-}
-
-/*
-==================
-GL_CheckErrors
-==================
-*/
-void GL_CheckErrors( void ) {
- int err;
- char s[64];
-
- err = qglGetError();
- if ( err == GL_NO_ERROR ) {
- return;
- }
- if ( r_ignoreGLErrors->integer ) {
- return;
- }
- switch( err ) {
- case GL_INVALID_ENUM:
- strcpy( s, "GL_INVALID_ENUM" );
- break;
- case GL_INVALID_VALUE:
- strcpy( s, "GL_INVALID_VALUE" );
- break;
- case GL_INVALID_OPERATION:
- strcpy( s, "GL_INVALID_OPERATION" );
- break;
- case GL_STACK_OVERFLOW:
- strcpy( s, "GL_STACK_OVERFLOW" );
- break;
- case GL_STACK_UNDERFLOW:
- strcpy( s, "GL_STACK_UNDERFLOW" );
- break;
- case GL_OUT_OF_MEMORY:
- strcpy( s, "GL_OUT_OF_MEMORY" );
- break;
- default:
- Com_sprintf( s, sizeof(s), "%i", err);
- break;
- }
-
- ri.Error( ERR_FATAL, "GL_CheckErrors: %s", s );
-}
-
-
-/*
-** R_GetModeInfo
-*/
-typedef struct vidmode_s
-{
- const char *description;
- int width, height;
- float pixelAspect; // pixel width / height
-} vidmode_t;
-
-vidmode_t r_vidModes[] =
-{
- { "Mode 0: 320x240", 320, 240, 1 },
- { "Mode 1: 400x300", 400, 300, 1 },
- { "Mode 2: 512x384", 512, 384, 1 },
- { "Mode 3: 640x480", 640, 480, 1 },
- { "Mode 4: 800x600", 800, 600, 1 },
- { "Mode 5: 960x720", 960, 720, 1 },
- { "Mode 6: 1024x768", 1024, 768, 1 },
- { "Mode 7: 1152x864", 1152, 864, 1 },
- { "Mode 8: 1280x1024", 1280, 1024, 1 },
- { "Mode 9: 1600x1200", 1600, 1200, 1 },
- { "Mode 10: 2048x1536", 2048, 1536, 1 },
- { "Mode 11: 856x480 (wide)",856, 480, 1 }
-};
-static int s_numVidModes = ( sizeof( r_vidModes ) / sizeof( r_vidModes[0] ) );
-
-qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ) {
- vidmode_t *vm;
- float pixelAspect;
-
- if ( mode < -1 ) {
- return qfalse;
- }
- if ( mode >= s_numVidModes ) {
- return qfalse;
- }
-
- if ( mode == -1 ) {
- *width = r_customwidth->integer;
- *height = r_customheight->integer;
- pixelAspect = r_customPixelAspect->value;
- } else {
- vm = &r_vidModes[mode];
-
- *width = vm->width;
- *height = vm->height;
- pixelAspect = vm->pixelAspect;
- }
-
- *windowAspect = (float)*width / ( *height * pixelAspect );
-
- return qtrue;
-}
-
-/*
-** R_ModeList_f
-*/
-static void R_ModeList_f( void )
-{
- int i;
-
- ri.Printf( PRINT_ALL, "\n" );
- for ( i = 0; i < s_numVidModes; i++ )
- {
- ri.Printf( PRINT_ALL, "%s\n", r_vidModes[i].description );
- }
- ri.Printf( PRINT_ALL, "\n" );
-}
-
-
-/*
-==============================================================================
-
- SCREEN SHOTS
-
-NOTE TTimo
-some thoughts about the screenshots system:
-screenshots get written in fs_homepath + fs_gamedir
-vanilla q3 .. baseq3/screenshots/ *.tga
-team arena .. missionpack/screenshots/ *.tga
-
-two commands: "screenshot" and "screenshotJPEG"
-we use statics to store a count and start writing the first screenshot/screenshot????.tga (.jpg) available
-(with FS_FileExists / FS_FOpenFileWrite calls)
-FIXME: the statics don't get a reinit between fs_game changes
-
-==============================================================================
-*/
-
-/*
-==================
-RB_TakeScreenshot
-==================
-*/
-void RB_TakeScreenshot( int x, int y, int width, int height, char *fileName ) {
- byte *buffer;
- int i, c, temp;
-
- buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*3+18);
-
- Com_Memset (buffer, 0, 18);
- buffer[2] = 2; // uncompressed type
- buffer[12] = width & 255;
- buffer[13] = width >> 8;
- buffer[14] = height & 255;
- buffer[15] = height >> 8;
- buffer[16] = 24; // pixel size
-
- qglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 );
-
- // swap rgb to bgr
- c = 18 + width * height * 3;
- for (i=18 ; i<c ; i+=3) {
- temp = buffer[i];
- buffer[i] = buffer[i+2];
- buffer[i+2] = temp;
- }
-
- // gamma correct
- if ( glConfig.deviceSupportsGamma ) {
- R_GammaCorrect( buffer + 18, glConfig.vidWidth * glConfig.vidHeight * 3 );
- }
-
- ri.FS_WriteFile( fileName, buffer, c );
-
- ri.Hunk_FreeTempMemory( buffer );
-}
-
-/*
-==================
-RB_TakeScreenshotJPEG
-==================
-*/
-void RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName ) {
- byte *buffer;
-
- buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4);
-
- qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
-
- // gamma correct
- if ( glConfig.deviceSupportsGamma ) {
- R_GammaCorrect( buffer, glConfig.vidWidth * glConfig.vidHeight * 4 );
- }
-
- ri.FS_WriteFile( fileName, buffer, 1 ); // create path
- SaveJPG( fileName, 90, glConfig.vidWidth, glConfig.vidHeight, buffer);
-
- ri.Hunk_FreeTempMemory( buffer );
-}
-
-/*
-==================
-RB_TakeScreenshotCmd
-==================
-*/
-const void *RB_TakeScreenshotCmd( const void *data ) {
- const screenshotCommand_t *cmd;
-
- cmd = (const screenshotCommand_t *)data;
-
- if (cmd->jpeg)
- RB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);
- else
- RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);
-
- return (const void *)(cmd + 1);
-}
-
-/*
-==================
-R_TakeScreenshot
-==================
-*/
-void R_TakeScreenshot( int x, int y, int width, int height, char *name, qboolean jpeg ) {
- static char fileName[MAX_OSPATH]; // bad things if two screenshots per frame?
- screenshotCommand_t *cmd;
-
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
- if ( !cmd ) {
- return;
- }
- cmd->commandId = RC_SCREENSHOT;
-
- cmd->x = x;
- cmd->y = y;
- cmd->width = width;
- cmd->height = height;
- Q_strncpyz( fileName, name, sizeof(fileName) );
- cmd->fileName = fileName;
- cmd->jpeg = jpeg;
-}
-
-/*
-==================
-R_ScreenshotFilename
-==================
-*/
-void R_ScreenshotFilename( int lastNumber, char *fileName ) {
- int a,b,c,d;
-
- if ( lastNumber < 0 || lastNumber > 9999 ) {
- Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.tga" );
- return;
- }
-
- a = lastNumber / 1000;
- lastNumber -= a*1000;
- b = lastNumber / 100;
- lastNumber -= b*100;
- c = lastNumber / 10;
- lastNumber -= c*10;
- d = lastNumber;
-
- Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.tga"
- , a, b, c, d );
-}
-
-/*
-==================
-R_ScreenshotFilename
-==================
-*/
-void R_ScreenshotFilenameJPEG( int lastNumber, char *fileName ) {
- int a,b,c,d;
-
- if ( lastNumber < 0 || lastNumber > 9999 ) {
- Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.jpg" );
- return;
- }
-
- a = lastNumber / 1000;
- lastNumber -= a*1000;
- b = lastNumber / 100;
- lastNumber -= b*100;
- c = lastNumber / 10;
- lastNumber -= c*10;
- d = lastNumber;
-
- Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.jpg"
- , a, b, c, d );
-}
-
-/*
-====================
-R_LevelShot
-
-levelshots are specialized 128*128 thumbnails for
-the menu system, sampled down from full screen distorted images
-====================
-*/
-void R_LevelShot( void ) {
- char checkname[MAX_OSPATH];
- byte *buffer;
- byte *source;
- byte *src, *dst;
- int x, y;
- int r, g, b;
- float xScale, yScale;
- int xx, yy;
-
- Com_sprintf(checkname, sizeof(checkname), "levelshots/%s.tga", tr.world->baseName);
-
- source = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight * 3 );
-
- buffer = ri.Hunk_AllocateTempMemory( 128 * 128*3 + 18);
- Com_Memset (buffer, 0, 18);
- buffer[2] = 2; // uncompressed type
- buffer[12] = 128;
- buffer[14] = 128;
- buffer[16] = 24; // pixel size
-
- qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source );
-
- // resample from source
- xScale = glConfig.vidWidth / 512.0f;
- yScale = glConfig.vidHeight / 384.0f;
- for ( y = 0 ; y < 128 ; y++ ) {
- for ( x = 0 ; x < 128 ; x++ ) {
- r = g = b = 0;
- for ( yy = 0 ; yy < 3 ; yy++ ) {
- for ( xx = 0 ; xx < 4 ; xx++ ) {
- src = source + 3 * ( glConfig.vidWidth * (int)( (y*3+yy)*yScale ) + (int)( (x*4+xx)*xScale ) );
- r += src[0];
- g += src[1];
- b += src[2];
- }
- }
- dst = buffer + 18 + 3 * ( y * 128 + x );
- dst[0] = b / 12;
- dst[1] = g / 12;
- dst[2] = r / 12;
- }
- }
-
- // gamma correct
- if ( glConfig.deviceSupportsGamma ) {
- R_GammaCorrect( buffer + 18, 128 * 128 * 3 );
- }
-
- ri.FS_WriteFile( checkname, buffer, 128 * 128*3 + 18 );
-
- ri.Hunk_FreeTempMemory( buffer );
- ri.Hunk_FreeTempMemory( source );
-
- ri.Printf( PRINT_ALL, "Wrote %s\n", checkname );
-}
-
-/*
-==================
-R_ScreenShot_f
-
-screenshot
-screenshot [silent]
-screenshot [levelshot]
-screenshot [filename]
-
-Doesn't print the pacifier message if there is a second arg
-==================
-*/
-void R_ScreenShot_f (void) {
- char checkname[MAX_OSPATH];
- static int lastNumber = -1;
- qboolean silent;
-
- if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) {
- R_LevelShot();
- return;
- }
-
- if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) {
- silent = qtrue;
- } else {
- silent = qfalse;
- }
-
- if ( ri.Cmd_Argc() == 2 && !silent ) {
- // explicit filename
- Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.tga", ri.Cmd_Argv( 1 ) );
- } else {
- // scan for a free filename
-
- // if we have saved a previous screenshot, don't scan
- // again, because recording demo avis can involve
- // thousands of shots
- if ( lastNumber == -1 ) {
- lastNumber = 0;
- }
- // scan for a free number
- for ( ; lastNumber <= 9999 ; lastNumber++ ) {
- R_ScreenshotFilename( lastNumber, checkname );
-
- if (!ri.FS_FileExists( checkname ))
- {
- break; // file doesn't exist
- }
- }
-
- if ( lastNumber >= 9999 ) {
- ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n");
- return;
- }
-
- lastNumber++;
- }
-
- R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qfalse );
-
- if ( !silent ) {
- ri.Printf (PRINT_ALL, "Wrote %s\n", checkname);
- }
-}
-
-void R_ScreenShotJPEG_f (void) {
- char checkname[MAX_OSPATH];
- static int lastNumber = -1;
- qboolean silent;
-
- if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) {
- R_LevelShot();
- return;
- }
-
- if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) {
- silent = qtrue;
- } else {
- silent = qfalse;
- }
-
- if ( ri.Cmd_Argc() == 2 && !silent ) {
- // explicit filename
- Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.jpg", ri.Cmd_Argv( 1 ) );
- } else {
- // scan for a free filename
-
- // if we have saved a previous screenshot, don't scan
- // again, because recording demo avis can involve
- // thousands of shots
- if ( lastNumber == -1 ) {
- lastNumber = 0;
- }
- // scan for a free number
- for ( ; lastNumber <= 9999 ; lastNumber++ ) {
- R_ScreenshotFilenameJPEG( lastNumber, checkname );
-
- if (!ri.FS_FileExists( checkname ))
- {
- break; // file doesn't exist
- }
- }
-
- if ( lastNumber == 10000 ) {
- ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n");
- return;
- }
-
- lastNumber++;
- }
-
- R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qtrue );
-
- if ( !silent ) {
- ri.Printf (PRINT_ALL, "Wrote %s\n", checkname);
- }
-}
-
-//============================================================================
-
-/*
-==================
-RB_TakeVideoFrameCmd
-==================
-*/
-const void *RB_TakeVideoFrameCmd( const void *data )
-{
- const videoFrameCommand_t *cmd;
- int frameSize;
- int i;
-
- cmd = (const videoFrameCommand_t *)data;
-
- qglReadPixels( 0, 0, cmd->width, cmd->height, GL_RGBA,
- GL_UNSIGNED_BYTE, cmd->captureBuffer );
-
- // gamma correct
- if( glConfig.deviceSupportsGamma )
- R_GammaCorrect( cmd->captureBuffer, cmd->width * cmd->height * 4 );
-
- if( cmd->motionJpeg )
- {
- frameSize = SaveJPGToBuffer( cmd->encodeBuffer, 90,
- cmd->width, cmd->height, cmd->captureBuffer );
- ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize );
- }
- else
- {
- frameSize = cmd->width * cmd->height;
-
- for( i = 0; i < frameSize; i++) // Pack to 24bpp and swap R and B
- {
- cmd->encodeBuffer[ i*3 ] = cmd->captureBuffer[ i*4 + 2 ];
- cmd->encodeBuffer[ i*3 + 1 ] = cmd->captureBuffer[ i*4 + 1 ];
- cmd->encodeBuffer[ i*3 + 2 ] = cmd->captureBuffer[ i*4 ];
- }
-
- ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize * 3 );
- }
-
- return (const void *)(cmd + 1);
-}
-
-//============================================================================
-
-/*
-** GL_SetDefaultState
-*/
-void GL_SetDefaultState( void )
-{
- qglClearDepth( 1.0f );
-
- qglCullFace(GL_FRONT);
-
- qglColor4f (1,1,1,1);
-
- // initialize downstream texture unit if we're running
- // in a multitexture environment
- if ( qglActiveTextureARB ) {
- GL_SelectTexture( 1 );
- GL_TextureMode( r_textureMode->string );
- GL_TexEnv( GL_MODULATE );
- qglDisable( GL_TEXTURE_2D );
- GL_SelectTexture( 0 );
- }
-
- qglEnable(GL_TEXTURE_2D);
- GL_TextureMode( r_textureMode->string );
- GL_TexEnv( GL_MODULATE );
-
- qglShadeModel( GL_SMOOTH );
- qglDepthFunc( GL_LEQUAL );
-
- // the vertex array is always enabled, but the color and texture
- // arrays are enabled and disabled around the compiled vertex array call
- qglEnableClientState (GL_VERTEX_ARRAY);
-
- //
- // make sure our GL state vector is set correctly
- //
- glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE;
-
- qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
- qglDepthMask( GL_TRUE );
- qglDisable( GL_DEPTH_TEST );
- qglEnable( GL_SCISSOR_TEST );
- qglDisable( GL_CULL_FACE );
- qglDisable( GL_BLEND );
-}
-
-
-/*
-================
-GfxInfo_f
-================
-*/
-void GfxInfo_f( void )
-{
- const char *enablestrings[] =
- {
- "disabled",
- "enabled"
- };
- const char *fsstrings[] =
- {
- "windowed",
- "fullscreen"
- };
-
- ri.Printf( PRINT_ALL, "\nGL_VENDOR: %s\n", glConfig.vendor_string );
- ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string );
- ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string );
- ri.Printf( PRINT_ALL, "GL_EXTENSIONS: %s\n", glConfig.extensions_string );
- ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize );
- ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_UNITS_ARB: %d\n", glConfig.numTextureUnits );
- ri.Printf( PRINT_ALL, "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits );
- ri.Printf( PRINT_ALL, "MODE: %d, %d x %d %s hz:", r_mode->integer, glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen->integer == 1] );
- if ( glConfig.displayFrequency )
- {
- ri.Printf( PRINT_ALL, "%d\n", glConfig.displayFrequency );
- }
- else
- {
- ri.Printf( PRINT_ALL, "N/A\n" );
- }
- if ( glConfig.deviceSupportsGamma )
- {
- ri.Printf( PRINT_ALL, "GAMMA: hardware w/ %d overbright bits\n", tr.overbrightBits );
- }
- else
- {
- ri.Printf( PRINT_ALL, "GAMMA: software w/ %d overbright bits\n", tr.overbrightBits );
- }
-
- // rendering primitives
- {
- int primitives;
-
- // default is to use triangles if compiled vertex arrays are present
- ri.Printf( PRINT_ALL, "rendering primitives: " );
- primitives = r_primitives->integer;
- if ( primitives == 0 ) {
- if ( qglLockArraysEXT ) {
- primitives = 2;
- } else {
- primitives = 1;
- }
- }
- if ( primitives == -1 ) {
- ri.Printf( PRINT_ALL, "none\n" );
- } else if ( primitives == 2 ) {
- ri.Printf( PRINT_ALL, "single glDrawElements\n" );
- } else if ( primitives == 1 ) {
- ri.Printf( PRINT_ALL, "multiple glArrayElement\n" );
- } else if ( primitives == 3 ) {
- ri.Printf( PRINT_ALL, "multiple glColor4ubv + glTexCoord2fv + glVertex3fv\n" );
- }
- }
-
- ri.Printf( PRINT_ALL, "texturemode: %s\n", r_textureMode->string );
- ri.Printf( PRINT_ALL, "picmip: %d\n", r_picmip->integer );
- ri.Printf( PRINT_ALL, "texture bits: %d\n", r_texturebits->integer );
- ri.Printf( PRINT_ALL, "multitexture: %s\n", enablestrings[qglActiveTextureARB != 0] );
- ri.Printf( PRINT_ALL, "compiled vertex arrays: %s\n", enablestrings[qglLockArraysEXT != 0 ] );
- ri.Printf( PRINT_ALL, "texenv add: %s\n", enablestrings[glConfig.textureEnvAddAvailable != 0] );
- ri.Printf( PRINT_ALL, "compressed textures: %s\n", enablestrings[glConfig.textureCompression!=TC_NONE] );
- if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 )
- {
- ri.Printf( PRINT_ALL, "HACK: using vertex lightmap approximation\n" );
- }
- if ( glConfig.hardwareType == GLHW_RAGEPRO )
- {
- ri.Printf( PRINT_ALL, "HACK: ragePro approximations\n" );
- }
- if ( glConfig.hardwareType == GLHW_RIVA128 )
- {
- ri.Printf( PRINT_ALL, "HACK: riva128 approximations\n" );
- }
- if ( glConfig.smpActive ) {
- ri.Printf( PRINT_ALL, "Using dual processor acceleration\n" );
- }
- if ( r_finish->integer ) {
- ri.Printf( PRINT_ALL, "Forcing glFinish\n" );
- }
-}
-
-/*
-===============
-R_Register
-===============
-*/
-void R_Register( void )
-{
- //
- // latched and archived variables
- //
- r_allowExtensions = ri.Cvar_Get( "r_allowExtensions", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compressed_textures", "0", CVAR_ARCHIVE | CVAR_LATCH );
- r_ext_multitexture = ri.Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH);
- r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH);
-
- r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic",
- "0", CVAR_ARCHIVE | CVAR_LATCH );
- r_ext_max_anisotropy = ri.Cvar_Get( "r_ext_max_anisotropy", "2", CVAR_ARCHIVE | CVAR_LATCH );
-
- r_picmip = ri.Cvar_Get ("r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH );
- ri.Cvar_CheckRange( r_picmip, 0, 16, qtrue );
- r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_texturebits = ri.Cvar_Get( "r_texturebits", "0", CVAR_ARCHIVE | CVAR_LATCH );
- r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
- r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH );
- r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
- r_ext_multisample = ri.Cvar_Get( "r_ext_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH );
- ri.Cvar_CheckRange( r_ext_multisample, 0, 4, qtrue );
- r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH);
- r_mode = ri.Cvar_Get( "r_mode", "3", CVAR_ARCHIVE | CVAR_LATCH );
- r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE );
- r_noborder = Cvar_Get("r_noborder", "0", CVAR_ARCHIVE);
- r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_ARCHIVE | CVAR_LATCH );
- r_customheight = ri.Cvar_Get( "r_customheight", "1024", CVAR_ARCHIVE | CVAR_LATCH );
- r_customPixelAspect = ri.Cvar_Get( "r_customPixelAspect", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_simpleMipMaps = ri.Cvar_Get( "r_simpleMipMaps", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_vertexLight = ri.Cvar_Get( "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH );
- r_uiFullScreen = ri.Cvar_Get( "r_uifullscreen", "0", 0);
- r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH);
- r_smp = ri.Cvar_Get( "r_smp", "0", CVAR_ARCHIVE | CVAR_LATCH);
- r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH);
- r_ignoreFastPath = ri.Cvar_Get( "r_ignoreFastPath", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH);
-
- //
- // temporary latched variables that can only change over a restart
- //
- r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT );
- r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH );
- r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH );
- r_singleShader = ri.Cvar_Get ("r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH );
-
- //
- // archived variables that can change at any time
- //
- r_lodCurveError = ri.Cvar_Get( "r_lodCurveError", "250", CVAR_ARCHIVE|CVAR_CHEAT );
- r_lodbias = ri.Cvar_Get( "r_lodbias", "0", CVAR_ARCHIVE );
- r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE );
- r_znear = ri.Cvar_Get( "r_znear", "4", CVAR_CHEAT );
- ri.Cvar_CheckRange( r_znear, 0.001f, 200, qfalse );
- r_zproj = ri.Cvar_Get( "r_zproj", "64", CVAR_ARCHIVE );
- r_stereoSeparation = ri.Cvar_Get( "r_stereoSeparation", "64", CVAR_ARCHIVE );
- r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE );
- r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE );
- r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE );
- r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE );
- r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE );
- r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE );
- r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE);
- r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE );
- r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0",
- CVAR_ARCHIVE | CVAR_LATCH );
- r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE );
- r_facePlaneCull = ri.Cvar_Get ("r_facePlaneCull", "1", CVAR_ARCHIVE );
-
- r_railWidth = ri.Cvar_Get( "r_railWidth", "16", CVAR_ARCHIVE );
- r_railCoreWidth = ri.Cvar_Get( "r_railCoreWidth", "6", CVAR_ARCHIVE );
- r_railSegmentLength = ri.Cvar_Get( "r_railSegmentLength", "32", CVAR_ARCHIVE );
-
- r_primitives = ri.Cvar_Get( "r_primitives", "0", CVAR_ARCHIVE );
-
- r_ambientScale = ri.Cvar_Get( "r_ambientScale", "0.6", CVAR_CHEAT );
- r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT );
-
- r_anaglyphMode = ri.Cvar_Get("r_anaglyphMode", "0", CVAR_ARCHIVE);
-
- //
- // temporary variables that can change at any time
- //
- r_showImages = ri.Cvar_Get( "r_showImages", "0", CVAR_TEMP );
-
- r_debugLight = ri.Cvar_Get( "r_debuglight", "0", CVAR_TEMP );
- r_debugSort = ri.Cvar_Get( "r_debugSort", "0", CVAR_CHEAT );
- r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 );
- r_saveFontData = ri.Cvar_Get( "r_saveFontData", "0", 0 );
-
- r_nocurves = ri.Cvar_Get ("r_nocurves", "0", CVAR_CHEAT );
- r_drawworld = ri.Cvar_Get ("r_drawworld", "1", CVAR_CHEAT );
- r_lightmap = ri.Cvar_Get ("r_lightmap", "0", 0 );
- r_portalOnly = ri.Cvar_Get ("r_portalOnly", "0", CVAR_CHEAT );
-
- r_flareSize = ri.Cvar_Get ("r_flareSize", "40", CVAR_CHEAT);
- r_flareFade = ri.Cvar_Get ("r_flareFade", "7", CVAR_CHEAT);
- r_flareCoeff = ri.Cvar_Get ("r_flareCoeff", FLARE_STDCOEFF, CVAR_CHEAT);
-
- r_showSmp = ri.Cvar_Get ("r_showSmp", "0", CVAR_CHEAT);
- r_skipBackEnd = ri.Cvar_Get ("r_skipBackEnd", "0", CVAR_CHEAT);
-
- r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT );
- r_lodscale = ri.Cvar_Get( "r_lodscale", "5", CVAR_CHEAT );
- r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT);
- r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT );
- r_ignore = ri.Cvar_Get( "r_ignore", "1", CVAR_CHEAT );
- r_nocull = ri.Cvar_Get ("r_nocull", "0", CVAR_CHEAT);
- r_novis = ri.Cvar_Get ("r_novis", "0", CVAR_CHEAT);
- r_showcluster = ri.Cvar_Get ("r_showcluster", "0", CVAR_CHEAT);
- r_speeds = ri.Cvar_Get ("r_speeds", "0", CVAR_CHEAT);
- r_verbose = ri.Cvar_Get( "r_verbose", "0", CVAR_CHEAT );
- r_logFile = ri.Cvar_Get( "r_logFile", "0", CVAR_CHEAT );
- r_debugSurface = ri.Cvar_Get ("r_debugSurface", "0", CVAR_CHEAT);
- r_nobind = ri.Cvar_Get ("r_nobind", "0", CVAR_CHEAT);
- r_showtris = ri.Cvar_Get ("r_showtris", "0", CVAR_CHEAT);
- r_showsky = ri.Cvar_Get ("r_showsky", "0", CVAR_CHEAT);
- r_shownormals = ri.Cvar_Get ("r_shownormals", "0", CVAR_CHEAT);
- r_clear = ri.Cvar_Get ("r_clear", "0", CVAR_CHEAT);
- r_offsetFactor = ri.Cvar_Get( "r_offsetfactor", "-1", CVAR_CHEAT );
- r_offsetUnits = ri.Cvar_Get( "r_offsetunits", "-2", CVAR_CHEAT );
- r_drawBuffer = ri.Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT );
- r_lockpvs = ri.Cvar_Get ("r_lockpvs", "0", CVAR_CHEAT);
- r_noportals = ri.Cvar_Get ("r_noportals", "0", CVAR_CHEAT);
- r_shadows = ri.Cvar_Get( "cg_shadows", "1", 0 );
-
- r_marksOnTriangleMeshes = ri.Cvar_Get("r_marksOnTriangleMeshes", "0", CVAR_ARCHIVE);
-
- r_maxpolys = ri.Cvar_Get( "r_maxpolys", va("%d", MAX_POLYS), 0);
- r_maxpolyverts = ri.Cvar_Get( "r_maxpolyverts", va("%d", MAX_POLYVERTS), 0);
-
- // make sure all the commands added here are also
- // removed in R_Shutdown
- ri.Cmd_AddCommand( "imagelist", R_ImageList_f );
- ri.Cmd_AddCommand( "shaderlist", R_ShaderList_f );
- ri.Cmd_AddCommand( "skinlist", R_SkinList_f );
- ri.Cmd_AddCommand( "modellist", R_Modellist_f );
- ri.Cmd_AddCommand( "modelist", R_ModeList_f );
- ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f );
- ri.Cmd_AddCommand( "screenshotJPEG", R_ScreenShotJPEG_f );
- ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f );
-}
-
-/*
-===============
-R_Init
-===============
-*/
-void R_Init( void ) {
- int err;
- int i;
- byte *ptr;
-
- ri.Printf( PRINT_ALL, "----- R_Init -----\n" );
-
- // clear all our internal state
- Com_Memset( &tr, 0, sizeof( tr ) );
- Com_Memset( &backEnd, 0, sizeof( backEnd ) );
- Com_Memset( &tess, 0, sizeof( tess ) );
-
- if(sizeof(glconfig_t) != 11332)
- {
- ri.Error( ERR_FATAL, "Mod ABI incompatible: sizeof(glconfig_t) == %zd != 11332", sizeof(glconfig_t));
- }
-
-// Swap_Init();
-
- if ( (intptr_t)tess.xyz & 15 ) {
- Com_Printf( "WARNING: tess.xyz not 16 byte aligned\n" );
- }
- Com_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) );
-
- //
- // init function tables
- //
- for ( i = 0; i < FUNCTABLE_SIZE; i++ )
- {
- tr.sinTable[i] = sin( DEG2RAD( i * 360.0f / ( ( float ) ( FUNCTABLE_SIZE - 1 ) ) ) );
- tr.squareTable[i] = ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f;
- tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE;
- tr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i];
-
- if ( i < FUNCTABLE_SIZE / 2 )
- {
- if ( i < FUNCTABLE_SIZE / 4 )
- {
- tr.triangleTable[i] = ( float ) i / ( FUNCTABLE_SIZE / 4 );
- }
- else
- {
- tr.triangleTable[i] = 1.0f - tr.triangleTable[i-FUNCTABLE_SIZE / 4];
- }
- }
- else
- {
- tr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2];
- }
- }
-
- R_InitFogTable();
-
- R_NoiseInit();
-
- R_Register();
-
- max_polys = r_maxpolys->integer;
- if (max_polys < MAX_POLYS)
- max_polys = MAX_POLYS;
-
- max_polyverts = r_maxpolyverts->integer;
- if (max_polyverts < MAX_POLYVERTS)
- max_polyverts = MAX_POLYVERTS;
-
- ptr = ri.Hunk_Alloc( sizeof( *backEndData[0] ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low);
- backEndData[0] = (backEndData_t *) ptr;
- backEndData[0]->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData[0] ));
- backEndData[0]->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData[0] ) + sizeof(srfPoly_t) * max_polys);
- if ( r_smp->integer ) {
- ptr = ri.Hunk_Alloc( sizeof( *backEndData[1] ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low);
- backEndData[1] = (backEndData_t *) ptr;
- backEndData[1]->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData[1] ));
- backEndData[1]->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData[1] ) + sizeof(srfPoly_t) * max_polys);
- } else {
- backEndData[1] = NULL;
- }
- R_ToggleSmpFrame();
-
- InitOpenGL();
-
- R_InitImages();
-
- R_InitShaders();
-
- R_InitSkins();
-
- R_ModelInit();
-
- R_InitFreeType();
-
-
- err = qglGetError();
- if ( err != GL_NO_ERROR )
- ri.Printf (PRINT_ALL, "glGetError() = 0x%x\n", err);
-
- ri.Printf( PRINT_ALL, "----- finished R_Init -----\n" );
-}
-
-/*
-===============
-RE_Shutdown
-===============
-*/
-void RE_Shutdown( qboolean destroyWindow ) {
-
- ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow );
-
- ri.Cmd_RemoveCommand ("modellist");
- ri.Cmd_RemoveCommand ("screenshotJPEG");
- ri.Cmd_RemoveCommand ("screenshot");
- ri.Cmd_RemoveCommand ("imagelist");
- ri.Cmd_RemoveCommand ("shaderlist");
- ri.Cmd_RemoveCommand ("skinlist");
- ri.Cmd_RemoveCommand ("gfxinfo");
- ri.Cmd_RemoveCommand( "modelist" );
- ri.Cmd_RemoveCommand( "shaderstate" );
-
-
- if ( tr.registered ) {
- R_SyncRenderThread();
- R_ShutdownCommandBuffers();
- R_DeleteTextures();
- }
-
- R_DoneFreeType();
-
- // shut down platform specific OpenGL stuff
- if ( destroyWindow ) {
- GLimp_Shutdown();
- }
-
- tr.registered = qfalse;
-}
-
-
-/*
-=============
-RE_EndRegistration
-
-Touch all images to make sure they are resident
-=============
-*/
-void RE_EndRegistration( void ) {
- R_SyncRenderThread();
- if (!Sys_LowPhysicalMemory()) {
- RB_ShowImages();
- }
-}
-
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-GetRefAPI
-
-@@@@@@@@@@@@@@@@@@@@@
-*/
-refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) {
- static refexport_t re;
-
- ri = *rimp;
-
- Com_Memset( &re, 0, sizeof( re ) );
-
- if ( apiVersion != REF_API_VERSION ) {
- ri.Printf(PRINT_ALL, "Mismatched REF_API_VERSION: expected %i, got %i\n",
- REF_API_VERSION, apiVersion );
- return NULL;
- }
-
- // the RE_ functions are Renderer Entry points
-
- re.Shutdown = RE_Shutdown;
-
- re.BeginRegistration = RE_BeginRegistration;
- re.RegisterModel = RE_RegisterModel;
- re.RegisterSkin = RE_RegisterSkin;
- re.RegisterShader = RE_RegisterShader;
- re.RegisterShaderNoMip = RE_RegisterShaderNoMip;
- re.LoadWorld = RE_LoadWorldMap;
- re.SetWorldVisData = RE_SetWorldVisData;
- re.EndRegistration = RE_EndRegistration;
-
- re.BeginFrame = RE_BeginFrame;
- re.EndFrame = RE_EndFrame;
-
- re.MarkFragments = R_MarkFragments;
- re.LerpTag = R_LerpTag;
- re.ModelBounds = R_ModelBounds;
-
- re.ClearScene = RE_ClearScene;
- re.AddRefEntityToScene = RE_AddRefEntityToScene;
- re.AddPolyToScene = RE_AddPolyToScene;
- re.LightForPoint = R_LightForPoint;
- re.AddLightToScene = RE_AddLightToScene;
- re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene;
- re.RenderScene = RE_RenderScene;
-
- re.SetColor = RE_SetColor;
- re.DrawStretchPic = RE_StretchPic;
- re.DrawStretchRaw = RE_StretchRaw;
- re.UploadCinematic = RE_UploadCinematic;
-
- re.RegisterFont = RE_RegisterFont;
- re.RemapShader = R_RemapShader;
- re.GetEntityToken = R_GetEntityToken;
- re.inPVS = R_inPVS;
-
- re.TakeVideoFrame = RE_TakeVideoFrame;
-
- return &re;
-}
diff --git a/engine/code/renderer/tr_light.c b/engine/code/renderer/tr_light.c
deleted file mode 100644
index 4cc9cf2..0000000
--- a/engine/code/renderer/tr_light.c
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_light.c
-
-#include "tr_local.h"
-
-#define DLIGHT_AT_RADIUS 16
-// at the edge of a dlight's influence, this amount of light will be added
-
-#define DLIGHT_MINIMUM_RADIUS 16
-// never calculate a range less than this to prevent huge light numbers
-
-
-/*
-===============
-R_TransformDlights
-
-Transforms the origins of an array of dlights.
-Used by both the front end (for DlightBmodel) and
-the back end (before doing the lighting calculation)
-===============
-*/
-void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or) {
- int i;
- vec3_t temp;
-
- for ( i = 0 ; i < count ; i++, dl++ ) {
- VectorSubtract( dl->origin, or->origin, temp );
- dl->transformed[0] = DotProduct( temp, or->axis[0] );
- dl->transformed[1] = DotProduct( temp, or->axis[1] );
- dl->transformed[2] = DotProduct( temp, or->axis[2] );
- }
-}
-
-/*
-=============
-R_DlightBmodel
-
-Determine which dynamic lights may effect this bmodel
-=============
-*/
-void R_DlightBmodel( bmodel_t *bmodel ) {
- int i, j;
- dlight_t *dl;
- int mask;
- msurface_t *surf;
-
- // transform all the lights
- R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.or );
-
- mask = 0;
- for ( i=0 ; i<tr.refdef.num_dlights ; i++ ) {
- dl = &tr.refdef.dlights[i];
-
- // see if the point is close enough to the bounds to matter
- for ( j = 0 ; j < 3 ; j++ ) {
- if ( dl->transformed[j] - bmodel->bounds[1][j] > dl->radius ) {
- break;
- }
- if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) {
- break;
- }
- }
- if ( j < 3 ) {
- continue;
- }
-
- // we need to check this light
- mask |= 1 << i;
- }
-
- tr.currentEntity->needDlights = (mask != 0);
-
- // set the dlight bits in all the surfaces
- for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
- surf = bmodel->firstSurface + i;
-
- if ( *surf->data == SF_FACE ) {
- ((srfSurfaceFace_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask;
- } else if ( *surf->data == SF_GRID ) {
- ((srfGridMesh_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask;
- } else if ( *surf->data == SF_TRIANGLES ) {
- ((srfTriangles_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask;
- }
- }
-}
-
-
-/*
-=============================================================================
-
-LIGHT SAMPLING
-
-=============================================================================
-*/
-
-extern cvar_t *r_ambientScale;
-extern cvar_t *r_directedScale;
-extern cvar_t *r_debugLight;
-
-/*
-=================
-R_SetupEntityLightingGrid
-
-=================
-*/
-static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {
- vec3_t lightOrigin;
- int pos[3];
- int i, j;
- byte *gridData;
- float frac[3];
- int gridStep[3];
- vec3_t direction;
- float totalFactor;
-
- if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
- // seperate lightOrigins are needed so an object that is
- // sinking into the ground can still be lit, and so
- // multi-part models can be lit identically
- VectorCopy( ent->e.lightingOrigin, lightOrigin );
- } else {
- VectorCopy( ent->e.origin, lightOrigin );
- }
-
- VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin );
- for ( i = 0 ; i < 3 ; i++ ) {
- float v;
-
- v = lightOrigin[i]*tr.world->lightGridInverseSize[i];
- pos[i] = floor( v );
- frac[i] = v - pos[i];
- if ( pos[i] < 0 ) {
- pos[i] = 0;
- } else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) {
- pos[i] = tr.world->lightGridBounds[i] - 1;
- }
- }
-
- VectorClear( ent->ambientLight );
- VectorClear( ent->directedLight );
- VectorClear( direction );
-
- assert( tr.world->lightGridData ); // NULL with -nolight maps
-
- // trilerp the light value
- gridStep[0] = 8;
- gridStep[1] = 8 * tr.world->lightGridBounds[0];
- gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
- gridData = tr.world->lightGridData + pos[0] * gridStep[0]
- + pos[1] * gridStep[1] + pos[2] * gridStep[2];
-
- totalFactor = 0;
- for ( i = 0 ; i < 8 ; i++ ) {
- float factor;
- byte *data;
- int lat, lng;
- vec3_t normal;
- #if idppc
- float d0, d1, d2, d3, d4, d5;
- #endif
- factor = 1.0;
- data = gridData;
- for ( j = 0 ; j < 3 ; j++ ) {
- if ( i & (1<<j) ) {
- factor *= frac[j];
- data += gridStep[j];
- } else {
- factor *= (1.0f - frac[j]);
- }
- }
-
- if ( !(data[0]+data[1]+data[2]) ) {
- continue; // ignore samples in walls
- }
- totalFactor += factor;
- #if idppc
- d0 = data[0]; d1 = data[1]; d2 = data[2];
- d3 = data[3]; d4 = data[4]; d5 = data[5];
-
- ent->ambientLight[0] += factor * d0;
- ent->ambientLight[1] += factor * d1;
- ent->ambientLight[2] += factor * d2;
-
- ent->directedLight[0] += factor * d3;
- ent->directedLight[1] += factor * d4;
- ent->directedLight[2] += factor * d5;
- #else
- ent->ambientLight[0] += factor * data[0];
- ent->ambientLight[1] += factor * data[1];
- ent->ambientLight[2] += factor * data[2];
-
- ent->directedLight[0] += factor * data[3];
- ent->directedLight[1] += factor * data[4];
- ent->directedLight[2] += factor * data[5];
- #endif
- lat = data[7];
- lng = data[6];
- lat *= (FUNCTABLE_SIZE/256);
- lng *= (FUNCTABLE_SIZE/256);
-
- // decode X as cos( lat ) * sin( long )
- // decode Y as sin( lat ) * sin( long )
- // decode Z as cos( long )
-
- normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
- normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
- normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
- VectorMA( direction, factor, normal, direction );
- }
-
- if ( totalFactor > 0 && totalFactor < 0.99 ) {
- totalFactor = 1.0f / totalFactor;
- VectorScale( ent->ambientLight, totalFactor, ent->ambientLight );
- VectorScale( ent->directedLight, totalFactor, ent->directedLight );
- }
-
- VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
- VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );
-
- VectorNormalize2( direction, ent->lightDir );
-}
-
-
-/*
-===============
-LogLight
-===============
-*/
-static void LogLight( trRefEntity_t *ent ) {
- int max1, max2;
-
- if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) {
- return;
- }
-
- max1 = ent->ambientLight[0];
- if ( ent->ambientLight[1] > max1 ) {
- max1 = ent->ambientLight[1];
- } else if ( ent->ambientLight[2] > max1 ) {
- max1 = ent->ambientLight[2];
- }
-
- max2 = ent->directedLight[0];
- if ( ent->directedLight[1] > max2 ) {
- max2 = ent->directedLight[1];
- } else if ( ent->directedLight[2] > max2 ) {
- max2 = ent->directedLight[2];
- }
-
- ri.Printf( PRINT_ALL, "amb:%i dir:%i\n", max1, max2 );
-}
-
-/*
-=================
-R_SetupEntityLighting
-
-Calculates all the lighting values that will be used
-by the Calc_* functions
-=================
-*/
-void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
- int i;
- dlight_t *dl;
- float power;
- vec3_t dir;
- float d;
- vec3_t lightDir;
- vec3_t lightOrigin;
-
- // lighting calculations
- if ( ent->lightingCalculated ) {
- return;
- }
- ent->lightingCalculated = qtrue;
-
- //
- // trace a sample point down to find ambient light
- //
- if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
- // seperate lightOrigins are needed so an object that is
- // sinking into the ground can still be lit, and so
- // multi-part models can be lit identically
- VectorCopy( ent->e.lightingOrigin, lightOrigin );
- } else {
- VectorCopy( ent->e.origin, lightOrigin );
- }
-
- // if NOWORLDMODEL, only use dynamic lights (menu system, etc)
- if ( !(refdef->rdflags & RDF_NOWORLDMODEL )
- && tr.world->lightGridData ) {
- R_SetupEntityLightingGrid( ent );
- } else {
- ent->ambientLight[0] = ent->ambientLight[1] =
- ent->ambientLight[2] = tr.identityLight * 150;
- ent->directedLight[0] = ent->directedLight[1] =
- ent->directedLight[2] = tr.identityLight * 150;
- VectorCopy( tr.sunDirection, ent->lightDir );
- }
-
- // bonus items and view weapons have a fixed minimum add
- if ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) {
- // give everything a minimum light add
- ent->ambientLight[0] += tr.identityLight * 32;
- ent->ambientLight[1] += tr.identityLight * 32;
- ent->ambientLight[2] += tr.identityLight * 32;
- }
-
- //
- // modify the light by dynamic lights
- //
- d = VectorLength( ent->directedLight );
- VectorScale( ent->lightDir, d, lightDir );
-
- for ( i = 0 ; i < refdef->num_dlights ; i++ ) {
- dl = &refdef->dlights[i];
- VectorSubtract( dl->origin, lightOrigin, dir );
- d = VectorNormalize( dir );
-
- power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius );
- if ( d < DLIGHT_MINIMUM_RADIUS ) {
- d = DLIGHT_MINIMUM_RADIUS;
- }
- d = power / ( d * d );
-
- VectorMA( ent->directedLight, d, dl->color, ent->directedLight );
- VectorMA( lightDir, d, dir, lightDir );
- }
-
- // clamp ambient
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( ent->ambientLight[i] > tr.identityLightByte ) {
- ent->ambientLight[i] = tr.identityLightByte;
- }
- }
-
- if ( r_debugLight->integer ) {
- LogLight( ent );
- }
-
- // save out the byte packet version
- ((byte *)&ent->ambientLightInt)[0] = myftol( ent->ambientLight[0] );
- ((byte *)&ent->ambientLightInt)[1] = myftol( ent->ambientLight[1] );
- ((byte *)&ent->ambientLightInt)[2] = myftol( ent->ambientLight[2] );
- ((byte *)&ent->ambientLightInt)[3] = 0xff;
-
- // transform the direction to local space
- VectorNormalize( lightDir );
- ent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] );
- ent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] );
- ent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] );
-}
-
-/*
-=================
-R_LightForPoint
-=================
-*/
-int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir )
-{
- trRefEntity_t ent;
-
- if ( tr.world->lightGridData == NULL )
- return qfalse;
-
- Com_Memset(&ent, 0, sizeof(ent));
- VectorCopy( point, ent.e.origin );
- R_SetupEntityLightingGrid( &ent );
- VectorCopy(ent.ambientLight, ambientLight);
- VectorCopy(ent.directedLight, directedLight);
- VectorCopy(ent.lightDir, lightDir);
-
- return qtrue;
-}
diff --git a/engine/code/renderer/tr_local.h b/engine/code/renderer/tr_local.h
deleted file mode 100644
index 098afd7..0000000
--- a/engine/code/renderer/tr_local.h
+++ /dev/null
@@ -1,1715 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-
-#ifndef TR_LOCAL_H
-#define TR_LOCAL_H
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qfiles.h"
-#include "../qcommon/qcommon.h"
-#include "tr_public.h"
-#include "qgl.h"
-
-#define GL_INDEX_TYPE GL_UNSIGNED_INT
-typedef unsigned int glIndex_t;
-
-// fast float to int conversion
-#if id386 && !defined(__GNUC__)
-long myftol( float f );
-#else
-#define myftol(x) ((int)(x))
-#endif
-
-
-// everything that is needed by the backend needs
-// to be double buffered to allow it to run in
-// parallel on a dual cpu machine
-#define SMP_FRAMES 2
-
-// 12 bits
-// see QSORT_SHADERNUM_SHIFT
-#define MAX_SHADERS 16384
-
-//#define MAX_SHADER_STATES 2048
-#define MAX_STATES_PER_SHADER 32
-#define MAX_STATE_NAME 32
-
-// can't be increased without changing bit packing for drawsurfs
-
-
-typedef struct dlight_s {
- vec3_t origin;
- vec3_t color; // range from 0.0 to 1.0, should be color normalized
- float radius;
-
- vec3_t transformed; // origin in local coordinate system
- int additive; // texture detail is lost tho when the lightmap is dark
-} dlight_t;
-
-
-// a trRefEntity_t has all the information passed in by
-// the client game, as well as some locally derived info
-typedef struct {
- refEntity_t e;
-
- float axisLength; // compensate for non-normalized axis
-
- qboolean needDlights; // true for bmodels that touch a dlight
- qboolean lightingCalculated;
- vec3_t lightDir; // normalized direction towards light
- vec3_t ambientLight; // color normalized to 0-255
- int ambientLightInt; // 32 bit rgba packed
- vec3_t directedLight;
-} trRefEntity_t;
-
-
-typedef struct {
- vec3_t origin; // in world coordinates
- vec3_t axis[3]; // orientation in world
- vec3_t viewOrigin; // viewParms->or.origin in local coordinates
- float modelMatrix[16];
-} orientationr_t;
-
-typedef struct image_s {
- char imgName[MAX_QPATH]; // game path, including extension
- int width, height; // source image
- int uploadWidth, uploadHeight; // after power of two and picmip but not including clamp to MAX_TEXTURE_SIZE
- GLuint texnum; // gl texture binding
-
- int frameUsed; // for texture usage in frame statistics
-
- int internalFormat;
- int TMU; // only needed for voodoo2
-
- qboolean mipmap;
- qboolean allowPicmip;
- int wrapClampMode; // GL_CLAMP_TO_EDGE or GL_REPEAT
-
- struct image_s* next;
-} image_t;
-
-//===============================================================================
-
-typedef enum {
- SS_BAD,
- SS_PORTAL, // mirrors, portals, viewscreens
- SS_ENVIRONMENT, // sky box
- SS_OPAQUE, // opaque
-
- SS_DECAL, // scorch marks, etc.
- SS_SEE_THROUGH, // ladders, grates, grills that may have small blended edges
- // in addition to alpha test
- SS_BANNER,
-
- SS_FOG,
-
- SS_UNDERWATER, // for items that should be drawn in front of the water plane
-
- SS_BLEND0, // regular transparency and filters
- SS_BLEND1, // generally only used for additive type effects
- SS_BLEND2,
- SS_BLEND3,
-
- SS_BLEND6,
- SS_STENCIL_SHADOW,
- SS_ALMOST_NEAREST, // gun smoke puffs
-
- SS_NEAREST // blood blobs
-} shaderSort_t;
-
-
-#define MAX_SHADER_STAGES 8
-
-typedef enum {
- GF_NONE,
-
- GF_SIN,
- GF_SQUARE,
- GF_TRIANGLE,
- GF_SAWTOOTH,
- GF_INVERSE_SAWTOOTH,
-
- GF_NOISE
-
-} genFunc_t;
-
-
-typedef enum {
- DEFORM_NONE,
- DEFORM_WAVE,
- DEFORM_NORMALS,
- DEFORM_BULGE,
- DEFORM_MOVE,
- DEFORM_PROJECTION_SHADOW,
- DEFORM_AUTOSPRITE,
- DEFORM_AUTOSPRITE2,
- DEFORM_TEXT0,
- DEFORM_TEXT1,
- DEFORM_TEXT2,
- DEFORM_TEXT3,
- DEFORM_TEXT4,
- DEFORM_TEXT5,
- DEFORM_TEXT6,
- DEFORM_TEXT7
-} deform_t;
-
-typedef enum {
- AGEN_IDENTITY,
- AGEN_SKIP,
- AGEN_ENTITY,
- AGEN_ONE_MINUS_ENTITY,
- AGEN_VERTEX,
- AGEN_ONE_MINUS_VERTEX,
- AGEN_LIGHTING_SPECULAR,
- AGEN_WAVEFORM,
- AGEN_PORTAL,
- AGEN_CONST
-} alphaGen_t;
-
-typedef enum {
- CGEN_BAD,
- CGEN_IDENTITY_LIGHTING, // tr.identityLight
- CGEN_IDENTITY, // always (1,1,1,1)
- CGEN_ENTITY, // grabbed from entity's modulate field
- CGEN_ONE_MINUS_ENTITY, // grabbed from 1 - entity.modulate
- CGEN_EXACT_VERTEX, // tess.vertexColors
- CGEN_VERTEX, // tess.vertexColors * tr.identityLight
- CGEN_ONE_MINUS_VERTEX,
- CGEN_WAVEFORM, // programmatically generated
- CGEN_LIGHTING_DIFFUSE,
- CGEN_FOG, // standard fog
- CGEN_CONST // fixed color
-} colorGen_t;
-
-typedef enum {
- TCGEN_BAD,
- TCGEN_IDENTITY, // clear to 0,0
- TCGEN_LIGHTMAP,
- TCGEN_TEXTURE,
- TCGEN_ENVIRONMENT_MAPPED,
- TCGEN_FOG,
- TCGEN_VECTOR // S and T from world coordinates
-} texCoordGen_t;
-
-typedef enum {
- ACFF_NONE,
- ACFF_MODULATE_RGB,
- ACFF_MODULATE_RGBA,
- ACFF_MODULATE_ALPHA
-} acff_t;
-
-typedef struct {
- genFunc_t func;
-
- float base;
- float amplitude;
- float phase;
- float frequency;
-} waveForm_t;
-
-#define TR_MAX_TEXMODS 4
-
-typedef enum {
- TMOD_NONE,
- TMOD_TRANSFORM,
- TMOD_TURBULENT,
- TMOD_SCROLL,
- TMOD_SCALE,
- TMOD_STRETCH,
- TMOD_ROTATE,
- TMOD_ENTITY_TRANSLATE
-} texMod_t;
-
-#define MAX_SHADER_DEFORMS 3
-typedef struct {
- deform_t deformation; // vertex coordinate modification type
-
- vec3_t moveVector;
- waveForm_t deformationWave;
- float deformationSpread;
-
- float bulgeWidth;
- float bulgeHeight;
- float bulgeSpeed;
-} deformStage_t;
-
-
-typedef struct {
- texMod_t type;
-
- // used for TMOD_TURBULENT and TMOD_STRETCH
- waveForm_t wave;
-
- // used for TMOD_TRANSFORM
- float matrix[2][2]; // s' = s * m[0][0] + t * m[1][0] + trans[0]
- float translate[2]; // t' = s * m[0][1] + t * m[0][1] + trans[1]
-
- // used for TMOD_SCALE
- float scale[2]; // s *= scale[0]
- // t *= scale[1]
-
- // used for TMOD_SCROLL
- float scroll[2]; // s' = s + scroll[0] * time
- // t' = t + scroll[1] * time
-
- // + = clockwise
- // - = counterclockwise
- float rotateSpeed;
-
-} texModInfo_t;
-
-
-#define MAX_IMAGE_ANIMATIONS 8
-
-typedef struct {
- image_t *image[MAX_IMAGE_ANIMATIONS];
- int numImageAnimations;
- float imageAnimationSpeed;
-
- texCoordGen_t tcGen;
- vec3_t tcGenVectors[2];
-
- int numTexMods;
- texModInfo_t *texMods;
-
- int videoMapHandle;
- qboolean isLightmap;
- qboolean vertexLightmap;
- qboolean isVideoMap;
-} textureBundle_t;
-
-#define NUM_TEXTURE_BUNDLES 2
-
-typedef struct {
- qboolean active;
-
- textureBundle_t bundle[NUM_TEXTURE_BUNDLES];
-
- waveForm_t rgbWave;
- colorGen_t rgbGen;
-
- waveForm_t alphaWave;
- alphaGen_t alphaGen;
-
- byte constantColor[4]; // for CGEN_CONST and AGEN_CONST
-
- unsigned stateBits; // GLS_xxxx mask
-
- acff_t adjustColorsForFog;
-
- qboolean isDetail;
-} shaderStage_t;
-
-struct shaderCommands_s;
-
-// any change in the LIGHTMAP_* defines here MUST be reflected in
-// R_FindShader() in tr_bsp.c
-#define LIGHTMAP_2D -4 // shader is for 2D rendering
-#define LIGHTMAP_BY_VERTEX -3 // pre-lit triangle models
-#define LIGHTMAP_WHITEIMAGE -2
-#define LIGHTMAP_NONE -1
-
-typedef enum {
- CT_FRONT_SIDED,
- CT_BACK_SIDED,
- CT_TWO_SIDED
-} cullType_t;
-
-typedef enum {
- FP_NONE, // surface is translucent and will just be adjusted properly
- FP_EQUAL, // surface is opaque but possibly alpha tested
- FP_LE // surface is trnaslucent, but still needs a fog pass (fog surface)
-} fogPass_t;
-
-typedef struct {
- float cloudHeight;
- image_t *outerbox[6], *innerbox[6];
-} skyParms_t;
-
-typedef struct {
- vec3_t color;
- float depthForOpaque;
-} fogParms_t;
-
-
-typedef struct shader_s {
- char name[MAX_QPATH]; // game path, including extension
- int lightmapIndex; // for a shader to match, both name and lightmapIndex must match
-
- int index; // this shader == tr.shaders[index]
- int sortedIndex; // this shader == tr.sortedShaders[sortedIndex]
-
- float sort; // lower numbered shaders draw before higher numbered
-
- qboolean defaultShader; // we want to return index 0 if the shader failed to
- // load for some reason, but R_FindShader should
- // still keep a name allocated for it, so if
- // something calls RE_RegisterShader again with
- // the same name, we don't try looking for it again
-
- qboolean explicitlyDefined; // found in a .shader file
-
- int surfaceFlags; // if explicitlyDefined, this will have SURF_* flags
- int contentFlags;
-
- qboolean entityMergable; // merge across entites optimizable (smoke, blood)
-
- qboolean isSky;
- skyParms_t sky;
- fogParms_t fogParms;
-
- float portalRange; // distance to fog out at
-
- int multitextureEnv; // 0, GL_MODULATE, GL_ADD (FIXME: put in stage)
-
- cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED
- qboolean polygonOffset; // set for decals and other items that must be offset
- qboolean noMipMaps; // for console fonts, 2D elements, etc.
- qboolean noPicMip; // for images that must always be full resolution
-
- fogPass_t fogPass; // draw a blended pass, possibly with depth test equals
-
- qboolean needsNormal; // not all shaders will need all data to be gathered
- qboolean needsST1;
- qboolean needsST2;
- qboolean needsColor;
-
- int numDeforms;
- deformStage_t deforms[MAX_SHADER_DEFORMS];
-
- int numUnfoggedPasses;
- shaderStage_t *stages[MAX_SHADER_STAGES];
-
- void (*optimalStageIteratorFunc)( void );
-
- float clampTime; // time this shader is clamped to
- float timeOffset; // current time offset for this shader
-
- int numStates; // if non-zero this is a state shader
- struct shader_s *currentShader; // current state if this is a state shader
- struct shader_s *parentShader; // current state if this is a state shader
- int currentState; // current state index for cycle purposes
- long expireTime; // time in milliseconds this expires
-
- struct shader_s *remappedShader; // current shader this one is remapped too
-
- int shaderStates[MAX_STATES_PER_SHADER]; // index to valid shader states
-
- struct shader_s *next;
-} shader_t;
-
-typedef struct shaderState_s {
- char shaderName[MAX_QPATH]; // name of shader this state belongs to
- char name[MAX_STATE_NAME]; // name of this state
- char stateShader[MAX_QPATH]; // shader this name invokes
- int cycleTime; // time this cycle lasts, <= 0 is forever
- shader_t *shader;
-} shaderState_t;
-
-
-// trRefdef_t holds everything that comes in refdef_t,
-// as well as the locally generated scene information
-typedef struct {
- int x, y, width, height;
- float fov_x, fov_y;
- vec3_t vieworg;
- vec3_t viewaxis[3]; // transformation matrix
-
- stereoFrame_t stereoFrame;
-
- int time; // time in milliseconds for shader effects and other time dependent rendering issues
- int rdflags; // RDF_NOWORLDMODEL, etc
-
- // 1 bits will prevent the associated area from rendering at all
- byte areamask[MAX_MAP_AREA_BYTES];
- qboolean areamaskModified; // qtrue if areamask changed since last scene
-
- float floatTime; // tr.refdef.time / 1000.0
-
- // text messages for deform text shaders
- char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH];
-
- int num_entities;
- trRefEntity_t *entities;
-
- int num_dlights;
- struct dlight_s *dlights;
-
- int numPolys;
- struct srfPoly_s *polys;
-
- int numDrawSurfs;
- struct drawSurf_s *drawSurfs;
-
-
-} trRefdef_t;
-
-
-//=================================================================================
-
-// skins allow models to be retextured without modifying the model file
-typedef struct {
- char name[MAX_QPATH];
- shader_t *shader;
-} skinSurface_t;
-
-typedef struct skin_s {
- char name[MAX_QPATH]; // game path, including extension
- int numSurfaces;
- skinSurface_t *surfaces[MD3_MAX_SURFACES];
-} skin_t;
-
-
-typedef struct {
- int originalBrushNumber;
- vec3_t bounds[2];
-
- unsigned colorInt; // in packed byte format
- float tcScale; // texture coordinate vector scales
- fogParms_t parms;
-
- // for clipping distance in fog when outside
- qboolean hasSurface;
- float surface[4];
-} fog_t;
-
-typedef struct {
- orientationr_t or;
- orientationr_t world;
- vec3_t pvsOrigin; // may be different than or.origin for portals
- qboolean isPortal; // true if this view is through a portal
- qboolean isMirror; // the portal is a mirror, invert the face culling
- int frameSceneNum; // copied from tr.frameSceneNum
- int frameCount; // copied from tr.frameCount
- cplane_t portalPlane; // clip anything behind this if mirroring
- int viewportX, viewportY, viewportWidth, viewportHeight;
- float fovX, fovY;
- float projectionMatrix[16];
- cplane_t frustum[4];
- vec3_t visBounds[2];
- float zFar;
- stereoFrame_t stereoFrame;
-} viewParms_t;
-
-
-/*
-==============================================================================
-
-SURFACES
-
-==============================================================================
-*/
-
-// any changes in surfaceType must be mirrored in rb_surfaceTable[]
-typedef enum {
- SF_BAD,
- SF_SKIP, // ignore
- SF_FACE,
- SF_GRID,
- SF_TRIANGLES,
- SF_POLY,
- SF_MD3,
- SF_MD4,
-#ifdef RAVENMD4
- SF_MDR,
-#endif
- SF_FLARE,
- SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
- SF_DISPLAY_LIST,
-
- SF_NUM_SURFACE_TYPES,
- SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
-} surfaceType_t;
-
-typedef struct drawSurf_s {
- unsigned sort; // bit combination for fast compares
- surfaceType_t *surface; // any of surface*_t
-} drawSurf_t;
-
-#define MAX_FACE_POINTS 64
-
-#define MAX_PATCH_SIZE 32 // max dimensions of a patch mesh in map file
-#define MAX_GRID_SIZE 65 // max dimensions of a grid mesh in memory
-
-// when cgame directly specifies a polygon, it becomes a srfPoly_t
-// as soon as it is called
-typedef struct srfPoly_s {
- surfaceType_t surfaceType;
- qhandle_t hShader;
- int fogIndex;
- int numVerts;
- polyVert_t *verts;
-} srfPoly_t;
-
-typedef struct srfDisplayList_s {
- surfaceType_t surfaceType;
- int listNum;
-} srfDisplayList_t;
-
-
-typedef struct srfFlare_s {
- surfaceType_t surfaceType;
- vec3_t origin;
- vec3_t normal;
- vec3_t color;
-} srfFlare_t;
-
-typedef struct srfGridMesh_s {
- surfaceType_t surfaceType;
-
- // dynamic lighting information
- int dlightBits[SMP_FRAMES];
-
- // culling information
- vec3_t meshBounds[2];
- vec3_t localOrigin;
- float meshRadius;
-
- // lod information, which may be different
- // than the culling information to allow for
- // groups of curves that LOD as a unit
- vec3_t lodOrigin;
- float lodRadius;
- int lodFixed;
- int lodStitched;
-
- // vertexes
- int width, height;
- float *widthLodError;
- float *heightLodError;
- drawVert_t verts[1]; // variable sized
-} srfGridMesh_t;
-
-
-
-#define VERTEXSIZE 8
-typedef struct {
- surfaceType_t surfaceType;
- cplane_t plane;
-
- // dynamic lighting information
- int dlightBits[SMP_FRAMES];
-
- // triangle definitions (no normals at points)
- int numPoints;
- int numIndices;
- int ofsIndices;
- float points[1][VERTEXSIZE]; // variable sized
- // there is a variable length list of indices here also
-} srfSurfaceFace_t;
-
-
-// misc_models in maps are turned into direct geometry by q3map
-typedef struct {
- surfaceType_t surfaceType;
-
- // dynamic lighting information
- int dlightBits[SMP_FRAMES];
-
- // culling information (FIXME: use this!)
- vec3_t bounds[2];
- vec3_t localOrigin;
- float radius;
-
- // triangle definitions
- int numIndexes;
- int *indexes;
-
- int numVerts;
- drawVert_t *verts;
-} srfTriangles_t;
-
-
-extern void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])(void *);
-
-/*
-==============================================================================
-
-BRUSH MODELS
-
-==============================================================================
-*/
-
-
-//
-// in memory representation
-//
-
-#define SIDE_FRONT 0
-#define SIDE_BACK 1
-#define SIDE_ON 2
-
-typedef struct msurface_s {
- int viewCount; // if == tr.viewCount, already added
- struct shader_s *shader;
- int fogIndex;
-
- surfaceType_t *data; // any of srf*_t
-} msurface_t;
-
-
-
-#define CONTENTS_NODE -1
-typedef struct mnode_s {
- // common with leaf and node
- int contents; // -1 for nodes, to differentiate from leafs
- int visframe; // node needs to be traversed if current
- vec3_t mins, maxs; // for bounding box culling
- struct mnode_s *parent;
-
- // node specific
- cplane_t *plane;
- struct mnode_s *children[2];
-
- // leaf specific
- int cluster;
- int area;
-
- msurface_t **firstmarksurface;
- int nummarksurfaces;
-} mnode_t;
-
-typedef struct {
- vec3_t bounds[2]; // for culling
- msurface_t *firstSurface;
- int numSurfaces;
-} bmodel_t;
-
-typedef struct {
- char name[MAX_QPATH]; // ie: maps/tim_dm2.bsp
- char baseName[MAX_QPATH]; // ie: tim_dm2
-
- int dataSize;
-
- int numShaders;
- dshader_t *shaders;
-
- bmodel_t *bmodels;
-
- int numplanes;
- cplane_t *planes;
-
- int numnodes; // includes leafs
- int numDecisionNodes;
- mnode_t *nodes;
-
- int numsurfaces;
- msurface_t *surfaces;
-
- int nummarksurfaces;
- msurface_t **marksurfaces;
-
- int numfogs;
- fog_t *fogs;
-
- vec3_t lightGridOrigin;
- vec3_t lightGridSize;
- vec3_t lightGridInverseSize;
- int lightGridBounds[3];
- byte *lightGridData;
-
-
- int numClusters;
- int clusterBytes;
- const byte *vis; // may be passed in by CM_LoadMap to save space
-
- byte *novis; // clusterBytes of 0xff
-
- char *entityString;
- char *entityParsePoint;
-} world_t;
-
-//======================================================================
-
-typedef enum {
- MOD_BAD,
- MOD_BRUSH,
- MOD_MESH,
- MOD_MD4,
-#ifdef RAVENMD4
- MOD_MDR
-#endif
-} modtype_t;
-
-typedef struct model_s {
- char name[MAX_QPATH];
- modtype_t type;
- int index; // model = tr.models[model->index]
-
- int dataSize; // just for listing purposes
- bmodel_t *bmodel; // only if type == MOD_BRUSH
- md3Header_t *md3[MD3_MAX_LODS]; // only if type == MOD_MESH
- void *md4; // only if type == (MOD_MD4 | MOD_MDR)
-
- int numLods;
-} model_t;
-
-
-#define MAX_MOD_KNOWN 1024
-
-void R_ModelInit (void);
-model_t *R_GetModelByHandle( qhandle_t hModel );
-int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame,
- float frac, const char *tagName );
-void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs );
-
-void R_Modellist_f (void);
-
-//====================================================
-extern refimport_t ri;
-
-#define MAX_DRAWIMAGES 2048
-#define MAX_LIGHTMAPS 256
-#define MAX_SKINS 1024
-
-
-#define MAX_DRAWSURFS 0x10000
-#define DRAWSURF_MASK (MAX_DRAWSURFS-1)
-
-/*
-
-the drawsurf sort data is packed into a single 32 bit value so it can be
-compared quickly during the qsorting process
-
-the bits are allocated as follows:
-
-21 - 31 : sorted shader index
-11 - 20 : entity index
-2 - 6 : fog index
-//2 : used to be clipped flag REMOVED - 03.21.00 rad
-0 - 1 : dlightmap index
-
- TTimo - 1.32
-17-31 : sorted shader index
-7-16 : entity index
-2-6 : fog index
-0-1 : dlightmap index
-*/
-#define QSORT_SHADERNUM_SHIFT 17
-#define QSORT_ENTITYNUM_SHIFT 7
-#define QSORT_FOGNUM_SHIFT 2
-
-extern int gl_filter_min, gl_filter_max;
-
-/*
-** performanceCounters_t
-*/
-typedef struct {
- int c_sphere_cull_patch_in, c_sphere_cull_patch_clip, c_sphere_cull_patch_out;
- int c_box_cull_patch_in, c_box_cull_patch_clip, c_box_cull_patch_out;
- int c_sphere_cull_md3_in, c_sphere_cull_md3_clip, c_sphere_cull_md3_out;
- int c_box_cull_md3_in, c_box_cull_md3_clip, c_box_cull_md3_out;
-
- int c_leafs;
- int c_dlightSurfaces;
- int c_dlightSurfacesCulled;
-} frontEndCounters_t;
-
-#define FOG_TABLE_SIZE 256
-#define FUNCTABLE_SIZE 1024
-#define FUNCTABLE_SIZE2 10
-#define FUNCTABLE_MASK (FUNCTABLE_SIZE-1)
-
-
-// the renderer front end should never modify glstate_t
-typedef struct {
- int currenttextures[2];
- int currenttmu;
- qboolean finishCalled;
- int texEnv[2];
- int faceCulling;
- unsigned long glStateBits;
-} glstate_t;
-
-
-typedef struct {
- int c_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes;
- float c_overDraw;
-
- int c_dlightVertexes;
- int c_dlightIndexes;
-
- int c_flareAdds;
- int c_flareTests;
- int c_flareRenders;
-
- int msec; // total msec for backend run
-} backEndCounters_t;
-
-// all state modified by the back end is seperated
-// from the front end state
-typedef struct {
- int smpFrame;
- trRefdef_t refdef;
- viewParms_t viewParms;
- orientationr_t or;
- backEndCounters_t pc;
- qboolean isHyperspace;
- trRefEntity_t *currentEntity;
- qboolean skyRenderedThisView; // flag for drawing sun
-
- qboolean projection2D; // if qtrue, drawstretchpic doesn't need to change modes
- byte color2D[4];
- qboolean vertexes2D; // shader needs to be finished
- trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering
-} backEndState_t;
-
-/*
-** trGlobals_t
-**
-** Most renderer globals are defined here.
-** backend functions should never modify any of these fields,
-** but may read fields that aren't dynamically modified
-** by the frontend.
-*/
-typedef struct {
- qboolean registered; // cleared at shutdown, set at beginRegistration
-
- int visCount; // incremented every time a new vis cluster is entered
- int frameCount; // incremented every frame
- int sceneCount; // incremented every scene
- int viewCount; // incremented every view (twice a scene if portaled)
- // and every R_MarkFragments call
-
- int smpFrame; // toggles from 0 to 1 every endFrame
-
- int frameSceneNum; // zeroed at RE_BeginFrame
-
- qboolean worldMapLoaded;
- world_t *world;
-
- const byte *externalVisData; // from RE_SetWorldVisData, shared with CM_Load
-
- image_t *defaultImage;
- image_t *scratchImage[32];
- image_t *fogImage;
- image_t *dlightImage; // inverse-quare highlight for projective adding
- image_t *flareImage;
- image_t *whiteImage; // full of 0xff
- image_t *identityLightImage; // full of tr.identityLightByte
-
- shader_t *defaultShader;
- shader_t *shadowShader;
- shader_t *projectionShadowShader;
-
- shader_t *flareShader;
- shader_t *sunShader;
-
- int numLightmaps;
- image_t *lightmaps[MAX_LIGHTMAPS];
-
- trRefEntity_t *currentEntity;
- trRefEntity_t worldEntity; // point currentEntity at this when rendering world
- int currentEntityNum;
- int shiftedEntityNum; // currentEntityNum << QSORT_ENTITYNUM_SHIFT
- model_t *currentModel;
-
- viewParms_t viewParms;
-
- float identityLight; // 1.0 / ( 1 << overbrightBits )
- int identityLightByte; // identityLight * 255
- int overbrightBits; // r_overbrightBits->integer, but set to 0 if no hw gamma
-
- orientationr_t or; // for current entity
-
- trRefdef_t refdef;
-
- int viewCluster;
-
- vec3_t sunLight; // from the sky shader for this level
- vec3_t sunDirection;
-
- frontEndCounters_t pc;
- int frontEndMsec; // not in pc due to clearing issue
-
- //
- // put large tables at the end, so most elements will be
- // within the +/32K indexed range on risc processors
- //
- model_t *models[MAX_MOD_KNOWN];
- int numModels;
-
- int numImages;
- image_t *images[MAX_DRAWIMAGES];
-
- // shader indexes from other modules will be looked up in tr.shaders[]
- // shader indexes from drawsurfs will be looked up in sortedShaders[]
- // lower indexed sortedShaders must be rendered first (opaque surfaces before translucent)
- int numShaders;
- shader_t *shaders[MAX_SHADERS];
- shader_t *sortedShaders[MAX_SHADERS];
-
- int numSkins;
- skin_t *skins[MAX_SKINS];
-
- float sinTable[FUNCTABLE_SIZE];
- float squareTable[FUNCTABLE_SIZE];
- float triangleTable[FUNCTABLE_SIZE];
- float sawToothTable[FUNCTABLE_SIZE];
- float inverseSawToothTable[FUNCTABLE_SIZE];
- float fogTable[FOG_TABLE_SIZE];
-} trGlobals_t;
-
-extern backEndState_t backEnd;
-extern trGlobals_t tr;
-extern glconfig_t glConfig; // outside of TR since it shouldn't be cleared during ref re-init
-extern glstate_t glState; // outside of TR since it shouldn't be cleared during ref re-init
-
-// These two variables should live inside glConfig but can't because of compatibility issues to the original ID vms.
-// If you release a stand-alone game and your mod uses tr_types.h from this build you can safely move them to
-// the glconfig_t struct.
-extern qboolean textureFilterAnisotropic;
-extern int maxAnisotropy;
-extern float displayAspect;
-
-
-//
-// cvars
-//
-extern cvar_t *r_flareSize;
-extern cvar_t *r_flareFade;
-// coefficient for the flare intensity falloff function.
-#define FLARE_STDCOEFF "150"
-extern cvar_t *r_flareCoeff;
-
-extern cvar_t *r_railWidth;
-extern cvar_t *r_railCoreWidth;
-extern cvar_t *r_railSegmentLength;
-
-extern cvar_t *r_ignore; // used for debugging anything
-extern cvar_t *r_verbose; // used for verbose debug spew
-extern cvar_t *r_ignoreFastPath; // allows us to ignore our Tess fast paths
-
-extern cvar_t *r_znear; // near Z clip plane
-extern cvar_t *r_zproj; // z distance of projection plane
-extern cvar_t *r_stereoSeparation; // separation of cameras for stereo rendering
-
-extern cvar_t *r_stencilbits; // number of desired stencil bits
-extern cvar_t *r_depthbits; // number of desired depth bits
-extern cvar_t *r_colorbits; // number of desired color bits, only relevant for fullscreen
-extern cvar_t *r_texturebits; // number of desired texture bits
-extern cvar_t *r_ext_multisample;
- // 0 = use framebuffer depth
- // 16 = use 16-bit textures
- // 32 = use 32-bit textures
- // all else = error
-
-extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measurement
-
-extern cvar_t *r_lodbias; // push/pull LOD transitions
-extern cvar_t *r_lodscale;
-
-extern cvar_t *r_primitives; // "0" = based on compiled vertex array existance
- // "1" = glDrawElemet tristrips
- // "2" = glDrawElements triangles
- // "-1" = no drawing
-
-extern cvar_t *r_inGameVideo; // controls whether in game video should be draw
-extern cvar_t *r_fastsky; // controls whether sky should be cleared or drawn
-extern cvar_t *r_drawSun; // controls drawing of sun quad
-extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled
-extern cvar_t *r_dlightBacks; // dlight non-facing surfaces for continuity
-
-extern cvar_t *r_norefresh; // bypasses the ref rendering
-extern cvar_t *r_drawentities; // disable/enable entity rendering
-extern cvar_t *r_drawworld; // disable/enable world rendering
-extern cvar_t *r_speeds; // various levels of information display
-extern cvar_t *r_detailTextures; // enables/disables detail texturing stages
-extern cvar_t *r_novis; // disable/enable usage of PVS
-extern cvar_t *r_nocull;
-extern cvar_t *r_facePlaneCull; // enables culling of planar surfaces with back side test
-extern cvar_t *r_nocurves;
-extern cvar_t *r_showcluster;
-
-extern cvar_t *r_mode; // video mode
-extern cvar_t *r_fullscreen;
-extern cvar_t *r_noborder;
-extern cvar_t *r_gamma;
-extern cvar_t *r_ignorehwgamma; // overrides hardware gamma capabilities
-
-extern cvar_t *r_allowExtensions; // global enable/disable of OpenGL extensions
-extern cvar_t *r_ext_compressed_textures; // these control use of specific extensions
-extern cvar_t *r_ext_multitexture;
-extern cvar_t *r_ext_compiled_vertex_array;
-extern cvar_t *r_ext_texture_env_add;
-
-extern cvar_t *r_ext_texture_filter_anisotropic;
-extern cvar_t *r_ext_max_anisotropy;
-
-extern cvar_t *r_nobind; // turns off binding to appropriate textures
-extern cvar_t *r_singleShader; // make most world faces use default shader
-extern cvar_t *r_roundImagesDown;
-extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage
-extern cvar_t *r_picmip; // controls picmip values
-extern cvar_t *r_finish;
-extern cvar_t *r_drawBuffer;
-extern cvar_t *r_glDriver;
-extern cvar_t *r_swapInterval;
-extern cvar_t *r_textureMode;
-extern cvar_t *r_offsetFactor;
-extern cvar_t *r_offsetUnits;
-
-extern cvar_t *r_fullbright; // avoid lightmap pass
-extern cvar_t *r_lightmap; // render lightmaps only
-extern cvar_t *r_vertexLight; // vertex lighting mode for better performance
-extern cvar_t *r_uiFullScreen; // ui is running fullscreen
-
-extern cvar_t *r_logFile; // number of frames to emit GL logs
-extern cvar_t *r_showtris; // enables wireframe rendering of the world
-extern cvar_t *r_showsky; // forces sky in front of all surfaces
-extern cvar_t *r_shownormals; // draws wireframe normals
-extern cvar_t *r_clear; // force screen clear every frame
-
-extern cvar_t *r_shadows; // controls shadows: 0 = none, 1 = blur, 2 = stencil, 3 = black planar projection
-extern cvar_t *r_flares; // light flares
-
-extern cvar_t *r_intensity;
-
-extern cvar_t *r_lockpvs;
-extern cvar_t *r_noportals;
-extern cvar_t *r_portalOnly;
-
-extern cvar_t *r_subdivisions;
-extern cvar_t *r_lodCurveError;
-extern cvar_t *r_smp;
-extern cvar_t *r_showSmp;
-extern cvar_t *r_skipBackEnd;
-
-extern cvar_t *r_stereoEnabled;
-extern cvar_t *r_anaglyphMode;
-
-extern cvar_t *r_greyscale;
-
-extern cvar_t *r_ignoreGLErrors;
-
-extern cvar_t *r_overBrightBits;
-extern cvar_t *r_mapOverBrightBits;
-
-extern cvar_t *r_debugSurface;
-extern cvar_t *r_simpleMipMaps;
-
-extern cvar_t *r_showImages;
-extern cvar_t *r_debugSort;
-
-extern cvar_t *r_printShaders;
-extern cvar_t *r_saveFontData;
-
-extern cvar_t *r_marksOnTriangleMeshes;
-
-extern cvar_t *r_GLlibCoolDownMsec;
-
-//====================================================================
-
-float R_NoiseGet4f( float x, float y, float z, float t );
-void R_NoiseInit( void );
-
-void R_SwapBuffers( int );
-
-void R_RenderView( viewParms_t *parms );
-
-void R_AddMD3Surfaces( trRefEntity_t *e );
-void R_AddNullModelSurfaces( trRefEntity_t *e );
-void R_AddBeamSurfaces( trRefEntity_t *e );
-void R_AddRailSurfaces( trRefEntity_t *e, qboolean isUnderwater );
-void R_AddLightningBoltSurfaces( trRefEntity_t *e );
-
-void R_AddPolygonSurfaces( void );
-
-void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
- int *fogNum, int *dlightMap );
-
-void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap );
-
-
-#define CULL_IN 0 // completely unclipped
-#define CULL_CLIP 1 // clipped by one or more planes
-#define CULL_OUT 2 // completely outside the clipping planes
-void R_LocalNormalToWorld (vec3_t local, vec3_t world);
-void R_LocalPointToWorld (vec3_t local, vec3_t world);
-int R_CullLocalBox (vec3_t bounds[2]);
-int R_CullPointAndRadius( vec3_t origin, float radius );
-int R_CullLocalPointAndRadius( vec3_t origin, float radius );
-
-void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum);
-void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *or );
-
-/*
-** GL wrapper/helper functions
-*/
-void GL_Bind( image_t *image );
-void GL_SetDefaultState (void);
-void GL_SelectTexture( int unit );
-void GL_TextureMode( const char *string );
-void GL_CheckErrors( void );
-void GL_State( unsigned long stateVector );
-void GL_TexEnv( int env );
-void GL_Cull( int cullType );
-
-#define GLS_SRCBLEND_ZERO 0x00000001
-#define GLS_SRCBLEND_ONE 0x00000002
-#define GLS_SRCBLEND_DST_COLOR 0x00000003
-#define GLS_SRCBLEND_ONE_MINUS_DST_COLOR 0x00000004
-#define GLS_SRCBLEND_SRC_ALPHA 0x00000005
-#define GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA 0x00000006
-#define GLS_SRCBLEND_DST_ALPHA 0x00000007
-#define GLS_SRCBLEND_ONE_MINUS_DST_ALPHA 0x00000008
-#define GLS_SRCBLEND_ALPHA_SATURATE 0x00000009
-#define GLS_SRCBLEND_BITS 0x0000000f
-
-#define GLS_DSTBLEND_ZERO 0x00000010
-#define GLS_DSTBLEND_ONE 0x00000020
-#define GLS_DSTBLEND_SRC_COLOR 0x00000030
-#define GLS_DSTBLEND_ONE_MINUS_SRC_COLOR 0x00000040
-#define GLS_DSTBLEND_SRC_ALPHA 0x00000050
-#define GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA 0x00000060
-#define GLS_DSTBLEND_DST_ALPHA 0x00000070
-#define GLS_DSTBLEND_ONE_MINUS_DST_ALPHA 0x00000080
-#define GLS_DSTBLEND_BITS 0x000000f0
-
-#define GLS_DEPTHMASK_TRUE 0x00000100
-
-#define GLS_POLYMODE_LINE 0x00001000
-
-#define GLS_DEPTHTEST_DISABLE 0x00010000
-#define GLS_DEPTHFUNC_EQUAL 0x00020000
-
-#define GLS_ATEST_GT_0 0x10000000
-#define GLS_ATEST_LT_80 0x20000000
-#define GLS_ATEST_GE_80 0x40000000
-#define GLS_ATEST_BITS 0x70000000
-
-#define GLS_DEFAULT GLS_DEPTHMASK_TRUE
-
-void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);
-void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);
-
-void RE_BeginFrame( stereoFrame_t stereoFrame );
-void RE_BeginRegistration( glconfig_t *glconfig );
-void RE_LoadWorldMap( const char *mapname );
-void RE_SetWorldVisData( const byte *vis );
-qhandle_t RE_RegisterModel( const char *name );
-qhandle_t RE_RegisterSkin( const char *name );
-void RE_Shutdown( qboolean destroyWindow );
-
-qboolean R_GetEntityToken( char *buffer, int size );
-
-model_t *R_AllocModel( void );
-
-void R_Init( void );
-image_t *R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode );
-
-image_t *R_CreateImage( const char *name, const byte *pic, int width, int height, qboolean mipmap
- , qboolean allowPicmip, int wrapClampMode );
-qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode );
-
-void R_SetColorMappings( void );
-void R_GammaCorrect( byte *buffer, int bufSize );
-
-void R_ImageList_f( void );
-void R_SkinList_f( void );
-// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516
-const void *RB_TakeScreenshotCmd( const void *data );
-void R_ScreenShot_f( void );
-
-void R_InitFogTable( void );
-float R_FogFactor( float s, float t );
-void R_InitImages( void );
-void R_DeleteTextures( void );
-int R_SumOfUsedImages( void );
-void R_InitSkins( void );
-skin_t *R_GetSkinByHandle( qhandle_t hSkin );
-
-int R_ComputeLOD( trRefEntity_t *ent );
-
-const void *RB_TakeVideoFrameCmd( const void *data );
-
-//
-// tr_shader.c
-//
-qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex );
-qhandle_t RE_RegisterShader( const char *name );
-qhandle_t RE_RegisterShaderNoMip( const char *name );
-qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage);
-
-shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage );
-shader_t *R_GetShaderByHandle( qhandle_t hShader );
-shader_t *R_GetShaderByState( int index, long *cycleTime );
-shader_t *R_FindShaderByName( const char *name );
-void R_InitShaders( void );
-void R_ShaderList_f( void );
-void R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset);
-
-/*
-====================================================================
-
-IMPLEMENTATION SPECIFIC FUNCTIONS
-
-====================================================================
-*/
-
-void GLimp_Init( void );
-void GLimp_Shutdown( void );
-void GLimp_EndFrame( void );
-
-qboolean GLimp_SpawnRenderThread( void (*function)( void ) );
-void *GLimp_RendererSleep( void );
-void GLimp_FrontEndSleep( void );
-void GLimp_WakeRenderer( void *data );
-
-void GLimp_LogComment( char *comment );
-
-// NOTE TTimo linux works with float gamma value, not the gamma table
-// the params won't be used, getting the r_gamma cvar directly
-void GLimp_SetGamma( unsigned char red[256],
- unsigned char green[256],
- unsigned char blue[256] );
-
-
-/*
-====================================================================
-
-TESSELATOR/SHADER DECLARATIONS
-
-====================================================================
-*/
-typedef byte color4ub_t[4];
-
-typedef struct stageVars
-{
- color4ub_t colors[SHADER_MAX_VERTEXES];
- vec2_t texcoords[NUM_TEXTURE_BUNDLES][SHADER_MAX_VERTEXES];
-} stageVars_t;
-
-
-typedef struct shaderCommands_s
-{
- glIndex_t indexes[SHADER_MAX_INDEXES] ALIGN(16);
- vec4_t xyz[SHADER_MAX_VERTEXES] ALIGN(16);
- vec4_t normal[SHADER_MAX_VERTEXES] ALIGN(16);
- vec2_t texCoords[SHADER_MAX_VERTEXES][2] ALIGN(16);
- color4ub_t vertexColors[SHADER_MAX_VERTEXES] ALIGN(16);
- int vertexDlightBits[SHADER_MAX_VERTEXES] ALIGN(16);
-
- stageVars_t svars ALIGN(16);
-
- color4ub_t constantColor255[SHADER_MAX_VERTEXES] ALIGN(16);
-
- shader_t *shader;
- float shaderTime;
- int fogNum;
-
- int dlightBits; // or together of all vertexDlightBits
-
- int numIndexes;
- int numVertexes;
-
- // info extracted from current shader
- int numPasses;
- void (*currentStageIteratorFunc)( void );
- shaderStage_t **xstages;
-} shaderCommands_t;
-
-extern shaderCommands_t tess;
-
-void RB_BeginSurface(shader_t *shader, int fogNum );
-void RB_EndSurface(void);
-void RB_CheckOverflow( int verts, int indexes );
-#define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);}
-
-void RB_StageIteratorGeneric( void );
-void RB_StageIteratorSky( void );
-void RB_StageIteratorVertexLitTexture( void );
-void RB_StageIteratorLightmappedMultitexture( void );
-
-void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color );
-void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 );
-
-void RB_ShowImages( void );
-
-
-/*
-============================================================
-
-WORLD MAP
-
-============================================================
-*/
-
-void R_AddBrushModelSurfaces( trRefEntity_t *e );
-void R_AddWorldSurfaces( void );
-qboolean R_inPVS( const vec3_t p1, const vec3_t p2 );
-
-
-/*
-============================================================
-
-FLARES
-
-============================================================
-*/
-
-void R_ClearFlares( void );
-
-void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal );
-void RB_AddDlightFlares( void );
-void RB_RenderFlares (void);
-
-/*
-============================================================
-
-LIGHTS
-
-============================================================
-*/
-
-void R_DlightBmodel( bmodel_t *bmodel );
-void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent );
-void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or );
-int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
-
-
-/*
-============================================================
-
-SHADOWS
-
-============================================================
-*/
-
-void RB_ShadowTessEnd( void );
-void RB_ShadowFinish( void );
-void RB_ProjectionShadowDeform( void );
-
-/*
-============================================================
-
-SKIES
-
-============================================================
-*/
-
-void R_BuildCloudData( shaderCommands_t *shader );
-void R_InitSkyTexCoords( float cloudLayerHeight );
-void R_DrawSkyBox( shaderCommands_t *shader );
-void RB_DrawSun( void );
-void RB_ClipSkyPolygons( shaderCommands_t *shader );
-
-/*
-============================================================
-
-CURVE TESSELATION
-
-============================================================
-*/
-
-#define PATCH_STITCHING
-
-srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
- drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] );
-srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror );
-srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror );
-void R_FreeSurfaceGridMesh( srfGridMesh_t *grid );
-
-/*
-============================================================
-
-MARKERS, POLYGON PROJECTION ON WORLD POLYGONS
-
-============================================================
-*/
-
-int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
- int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );
-
-
-/*
-============================================================
-
-SCENE GENERATION
-
-============================================================
-*/
-
-void R_ToggleSmpFrame( void );
-
-void RE_ClearScene( void );
-void RE_AddRefEntityToScene( const refEntity_t *ent );
-void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );
-void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
-void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b );
-void RE_RenderScene( const refdef_t *fd );
-
-#ifdef RAVENMD4
-/*
-=============================================================
-
-UNCOMPRESSING BONES
-
-=============================================================
-*/
-
-#define MC_BITS_X (16)
-#define MC_BITS_Y (16)
-#define MC_BITS_Z (16)
-#define MC_BITS_VECT (16)
-
-#define MC_SCALE_X (1.0f/64)
-#define MC_SCALE_Y (1.0f/64)
-#define MC_SCALE_Z (1.0f/64)
-
-void MC_UnCompress(float mat[3][4],const unsigned char * comp);
-#endif
-
-/*
-=============================================================
-
-ANIMATED MODELS
-
-=============================================================
-*/
-
-// void R_MakeAnimModel( model_t *model ); haven't seen this one really, so not needed I guess.
-void R_AddAnimSurfaces( trRefEntity_t *ent );
-void RB_SurfaceAnim( md4Surface_t *surfType );
-#ifdef RAVENMD4
-void R_MDRAddAnimSurfaces( trRefEntity_t *ent );
-void RB_MDRSurfaceAnim( md4Surface_t *surface );
-#endif
-
-/*
-=============================================================
-
-IMAGE LOADERS
-
-=============================================================
-*/
-
-void R_LoadBMP( const char *name, byte **pic, int *width, int *height );
-void R_LoadJPG( const char *name, byte **pic, int *width, int *height );
-void R_LoadPCX( const char *name, byte **pic, int *width, int *height );
-void R_LoadPNG( const char *name, byte **pic, int *width, int *height );
-void R_LoadTGA( const char *name, byte **pic, int *width, int *height );
-
-/*
-=============================================================
-=============================================================
-*/
-void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
- vec4_t eye, vec4_t dst );
-void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window );
-
-void RB_DeformTessGeometry( void );
-
-void RB_CalcEnvironmentTexCoords( float *dstTexCoords );
-void RB_CalcFogTexCoords( float *dstTexCoords );
-void RB_CalcScrollTexCoords( const float scroll[2], float *dstTexCoords );
-void RB_CalcRotateTexCoords( float rotSpeed, float *dstTexCoords );
-void RB_CalcScaleTexCoords( const float scale[2], float *dstTexCoords );
-void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *dstTexCoords );
-void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *dstTexCoords );
-void RB_CalcModulateColorsByFog( unsigned char *dstColors );
-void RB_CalcModulateAlphasByFog( unsigned char *dstColors );
-void RB_CalcModulateRGBAsByFog( unsigned char *dstColors );
-void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors );
-void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors );
-void RB_CalcAlphaFromEntity( unsigned char *dstColors );
-void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors );
-void RB_CalcStretchTexCoords( const waveForm_t *wf, float *texCoords );
-void RB_CalcColorFromEntity( unsigned char *dstColors );
-void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors );
-void RB_CalcSpecularAlpha( unsigned char *alphas );
-void RB_CalcDiffuseColor( unsigned char *colors );
-
-/*
-=============================================================
-
-RENDERER BACK END FUNCTIONS
-
-=============================================================
-*/
-
-void RB_RenderThread( void );
-void RB_ExecuteRenderCommands( const void *data );
-
-/*
-=============================================================
-
-RENDERER BACK END COMMAND QUEUE
-
-=============================================================
-*/
-
-#define MAX_RENDER_COMMANDS 0x40000
-
-typedef struct {
- byte cmds[MAX_RENDER_COMMANDS];
- int used;
-} renderCommandList_t;
-
-typedef struct {
- int commandId;
- float color[4];
-} setColorCommand_t;
-
-typedef struct {
- int commandId;
- int buffer;
-} drawBufferCommand_t;
-
-typedef struct {
- int commandId;
- image_t *image;
- int width;
- int height;
- void *data;
-} subImageCommand_t;
-
-typedef struct {
- int commandId;
-} swapBuffersCommand_t;
-
-typedef struct {
- int commandId;
- int buffer;
-} endFrameCommand_t;
-
-typedef struct {
- int commandId;
- shader_t *shader;
- float x, y;
- float w, h;
- float s1, t1;
- float s2, t2;
-} stretchPicCommand_t;
-
-typedef struct {
- int commandId;
- trRefdef_t refdef;
- viewParms_t viewParms;
- drawSurf_t *drawSurfs;
- int numDrawSurfs;
-} drawSurfsCommand_t;
-
-typedef struct {
- int commandId;
- int x;
- int y;
- int width;
- int height;
- char *fileName;
- qboolean jpeg;
-} screenshotCommand_t;
-
-typedef struct {
- int commandId;
- int width;
- int height;
- byte *captureBuffer;
- byte *encodeBuffer;
- qboolean motionJpeg;
-} videoFrameCommand_t;
-
-typedef struct
-{
- int commandId;
-
- GLboolean rgba[4];
-} colorMaskCommand_t;
-
-typedef struct
-{
- int commandId;
-} clearDepthCommand_t;
-
-typedef enum {
- RC_END_OF_LIST,
- RC_SET_COLOR,
- RC_STRETCH_PIC,
- RC_DRAW_SURFS,
- RC_DRAW_BUFFER,
- RC_SWAP_BUFFERS,
- RC_SCREENSHOT,
- RC_VIDEOFRAME,
- RC_COLORMASK,
- RC_CLEARDEPTH
-} renderCommand_t;
-
-
-// these are sort of arbitrary limits.
-// the limits apply to the sum of all scenes in a frame --
-// the main view, all the 3D icons, etc
-#define MAX_POLYS 600
-#define MAX_POLYVERTS 3000
-
-// all of the information needed by the back end must be
-// contained in a backEndData_t. This entire structure is
-// duplicated so the front and back end can run in parallel
-// on an SMP machine
-typedef struct {
- drawSurf_t drawSurfs[MAX_DRAWSURFS];
- dlight_t dlights[MAX_DLIGHTS];
- trRefEntity_t entities[MAX_ENTITIES];
- srfPoly_t *polys;//[MAX_POLYS];
- polyVert_t *polyVerts;//[MAX_POLYVERTS];
- renderCommandList_t commands;
-} backEndData_t;
-
-extern int max_polys;
-extern int max_polyverts;
-
-extern backEndData_t *backEndData[SMP_FRAMES]; // the second one may not be allocated
-
-extern volatile renderCommandList_t *renderCommandList;
-
-extern volatile qboolean renderThreadActive;
-
-
-void *R_GetCommandBuffer( int bytes );
-void RB_ExecuteRenderCommands( const void *data );
-
-void R_InitCommandBuffers( void );
-void R_ShutdownCommandBuffers( void );
-
-void R_SyncRenderThread( void );
-
-void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs );
-
-void RE_SetColor( const float *rgba );
-void RE_StretchPic ( float x, float y, float w, float h,
- float s1, float t1, float s2, float t2, qhandle_t hShader );
-void RE_BeginFrame( stereoFrame_t stereoFrame );
-void RE_EndFrame( int *frontEndMsec, int *backEndMsec );
-void SaveJPG(char * filename, int quality, int image_width, int image_height, unsigned char *image_buffer);
-int SaveJPGToBuffer( byte *buffer, int quality,
- int image_width, int image_height,
- byte *image_buffer );
-void RE_TakeVideoFrame( int width, int height,
- byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg );
-
-// font stuff
-void R_InitFreeType( void );
-void R_DoneFreeType( void );
-void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font);
-
-
-#endif //TR_LOCAL_H
diff --git a/engine/code/renderer/tr_main.c b/engine/code/renderer/tr_main.c
deleted file mode 100644
index e7c0542..0000000
--- a/engine/code/renderer/tr_main.c
+++ /dev/null
@@ -1,1402 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_main.c -- main control flow for each frame
-
-#include "tr_local.h"
-
-#include <string.h> // memcpy
-
-trGlobals_t tr;
-
-static float s_flipMatrix[16] = {
- // convert from our coordinate system (looking down X)
- // to OpenGL's coordinate system (looking down -Z)
- 0, 0, -1, 0,
- -1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 0, 1
-};
-
-
-refimport_t ri;
-
-// entities that will have procedurally generated surfaces will just
-// point at this for their sorting surface
-surfaceType_t entitySurface = SF_ENTITY;
-
-/*
-=================
-R_CullLocalBox
-
-Returns CULL_IN, CULL_CLIP, or CULL_OUT
-=================
-*/
-int R_CullLocalBox (vec3_t bounds[2]) {
- int i, j;
- vec3_t transformed[8];
- float dists[8];
- vec3_t v;
- cplane_t *frust;
- int anyBack;
- int front, back;
-
- if ( r_nocull->integer ) {
- return CULL_CLIP;
- }
-
- // transform into world space
- for (i = 0 ; i < 8 ; i++) {
- v[0] = bounds[i&1][0];
- v[1] = bounds[(i>>1)&1][1];
- v[2] = bounds[(i>>2)&1][2];
-
- VectorCopy( tr.or.origin, transformed[i] );
- VectorMA( transformed[i], v[0], tr.or.axis[0], transformed[i] );
- VectorMA( transformed[i], v[1], tr.or.axis[1], transformed[i] );
- VectorMA( transformed[i], v[2], tr.or.axis[2], transformed[i] );
- }
-
- // check against frustum planes
- anyBack = 0;
- for (i = 0 ; i < 4 ; i++) {
- frust = &tr.viewParms.frustum[i];
-
- front = back = 0;
- for (j = 0 ; j < 8 ; j++) {
- dists[j] = DotProduct(transformed[j], frust->normal);
- if ( dists[j] > frust->dist ) {
- front = 1;
- if ( back ) {
- break; // a point is in front
- }
- } else {
- back = 1;
- }
- }
- if ( !front ) {
- // all points were behind one of the planes
- return CULL_OUT;
- }
- anyBack |= back;
- }
-
- if ( !anyBack ) {
- return CULL_IN; // completely inside frustum
- }
-
- return CULL_CLIP; // partially clipped
-}
-
-/*
-** R_CullLocalPointAndRadius
-*/
-int R_CullLocalPointAndRadius( vec3_t pt, float radius )
-{
- vec3_t transformed;
-
- R_LocalPointToWorld( pt, transformed );
-
- return R_CullPointAndRadius( transformed, radius );
-}
-
-/*
-** R_CullPointAndRadius
-*/
-int R_CullPointAndRadius( vec3_t pt, float radius )
-{
- int i;
- float dist;
- cplane_t *frust;
- qboolean mightBeClipped = qfalse;
-
- if ( r_nocull->integer ) {
- return CULL_CLIP;
- }
-
- // check against frustum planes
- for (i = 0 ; i < 4 ; i++)
- {
- frust = &tr.viewParms.frustum[i];
-
- dist = DotProduct( pt, frust->normal) - frust->dist;
- if ( dist < -radius )
- {
- return CULL_OUT;
- }
- else if ( dist <= radius )
- {
- mightBeClipped = qtrue;
- }
- }
-
- if ( mightBeClipped )
- {
- return CULL_CLIP;
- }
-
- return CULL_IN; // completely inside frustum
-}
-
-
-/*
-=================
-R_LocalNormalToWorld
-
-=================
-*/
-void R_LocalNormalToWorld (vec3_t local, vec3_t world) {
- world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0];
- world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1];
- world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2];
-}
-
-/*
-=================
-R_LocalPointToWorld
-
-=================
-*/
-void R_LocalPointToWorld (vec3_t local, vec3_t world) {
- world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0] + tr.or.origin[0];
- world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1] + tr.or.origin[1];
- world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2] + tr.or.origin[2];
-}
-
-/*
-=================
-R_WorldToLocal
-
-=================
-*/
-void R_WorldToLocal (vec3_t world, vec3_t local) {
- local[0] = DotProduct(world, tr.or.axis[0]);
- local[1] = DotProduct(world, tr.or.axis[1]);
- local[2] = DotProduct(world, tr.or.axis[2]);
-}
-
-/*
-==========================
-R_TransformModelToClip
-
-==========================
-*/
-void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
- vec4_t eye, vec4_t dst ) {
- int i;
-
- for ( i = 0 ; i < 4 ; i++ ) {
- eye[i] =
- src[0] * modelMatrix[ i + 0 * 4 ] +
- src[1] * modelMatrix[ i + 1 * 4 ] +
- src[2] * modelMatrix[ i + 2 * 4 ] +
- 1 * modelMatrix[ i + 3 * 4 ];
- }
-
- for ( i = 0 ; i < 4 ; i++ ) {
- dst[i] =
- eye[0] * projectionMatrix[ i + 0 * 4 ] +
- eye[1] * projectionMatrix[ i + 1 * 4 ] +
- eye[2] * projectionMatrix[ i + 2 * 4 ] +
- eye[3] * projectionMatrix[ i + 3 * 4 ];
- }
-}
-
-/*
-==========================
-R_TransformClipToWindow
-
-==========================
-*/
-void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) {
- normalized[0] = clip[0] / clip[3];
- normalized[1] = clip[1] / clip[3];
- normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] );
-
- window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth;
- window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight;
- window[2] = normalized[2];
-
- window[0] = (int) ( window[0] + 0.5 );
- window[1] = (int) ( window[1] + 0.5 );
-}
-
-
-/*
-==========================
-myGlMultMatrix
-
-==========================
-*/
-void myGlMultMatrix( const float *a, const float *b, float *out ) {
- int i, j;
-
- for ( i = 0 ; i < 4 ; i++ ) {
- for ( j = 0 ; j < 4 ; j++ ) {
- out[ i * 4 + j ] =
- a [ i * 4 + 0 ] * b [ 0 * 4 + j ]
- + a [ i * 4 + 1 ] * b [ 1 * 4 + j ]
- + a [ i * 4 + 2 ] * b [ 2 * 4 + j ]
- + a [ i * 4 + 3 ] * b [ 3 * 4 + j ];
- }
- }
-}
-
-/*
-=================
-R_RotateForEntity
-
-Generates an orientation for an entity and viewParms
-Does NOT produce any GL calls
-Called by both the front end and the back end
-=================
-*/
-void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,
- orientationr_t *or ) {
- float glMatrix[16];
- vec3_t delta;
- float axisLength;
-
- if ( ent->e.reType != RT_MODEL ) {
- *or = viewParms->world;
- return;
- }
-
- VectorCopy( ent->e.origin, or->origin );
-
- VectorCopy( ent->e.axis[0], or->axis[0] );
- VectorCopy( ent->e.axis[1], or->axis[1] );
- VectorCopy( ent->e.axis[2], or->axis[2] );
-
- glMatrix[0] = or->axis[0][0];
- glMatrix[4] = or->axis[1][0];
- glMatrix[8] = or->axis[2][0];
- glMatrix[12] = or->origin[0];
-
- glMatrix[1] = or->axis[0][1];
- glMatrix[5] = or->axis[1][1];
- glMatrix[9] = or->axis[2][1];
- glMatrix[13] = or->origin[1];
-
- glMatrix[2] = or->axis[0][2];
- glMatrix[6] = or->axis[1][2];
- glMatrix[10] = or->axis[2][2];
- glMatrix[14] = or->origin[2];
-
- glMatrix[3] = 0;
- glMatrix[7] = 0;
- glMatrix[11] = 0;
- glMatrix[15] = 1;
-
- myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, or->modelMatrix );
-
- // calculate the viewer origin in the model's space
- // needed for fog, specular, and environment mapping
- VectorSubtract( viewParms->or.origin, or->origin, delta );
-
- // compensate for scale in the axes if necessary
- if ( ent->e.nonNormalizedAxes ) {
- axisLength = VectorLength( ent->e.axis[0] );
- if ( !axisLength ) {
- axisLength = 0;
- } else {
- axisLength = 1.0f / axisLength;
- }
- } else {
- axisLength = 1.0f;
- }
-
- or->viewOrigin[0] = DotProduct( delta, or->axis[0] ) * axisLength;
- or->viewOrigin[1] = DotProduct( delta, or->axis[1] ) * axisLength;
- or->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength;
-}
-
-/*
-=================
-R_RotateForViewer
-
-Sets up the modelview matrix for a given viewParm
-=================
-*/
-void R_RotateForViewer (void)
-{
- float viewerMatrix[16];
- vec3_t origin;
-
- Com_Memset (&tr.or, 0, sizeof(tr.or));
- tr.or.axis[0][0] = 1;
- tr.or.axis[1][1] = 1;
- tr.or.axis[2][2] = 1;
- VectorCopy (tr.viewParms.or.origin, tr.or.viewOrigin);
-
- // transform by the camera placement
- VectorCopy( tr.viewParms.or.origin, origin );
-
- viewerMatrix[0] = tr.viewParms.or.axis[0][0];
- viewerMatrix[4] = tr.viewParms.or.axis[0][1];
- viewerMatrix[8] = tr.viewParms.or.axis[0][2];
- viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8];
-
- viewerMatrix[1] = tr.viewParms.or.axis[1][0];
- viewerMatrix[5] = tr.viewParms.or.axis[1][1];
- viewerMatrix[9] = tr.viewParms.or.axis[1][2];
- viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9];
-
- viewerMatrix[2] = tr.viewParms.or.axis[2][0];
- viewerMatrix[6] = tr.viewParms.or.axis[2][1];
- viewerMatrix[10] = tr.viewParms.or.axis[2][2];
- viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10];
-
- viewerMatrix[3] = 0;
- viewerMatrix[7] = 0;
- viewerMatrix[11] = 0;
- viewerMatrix[15] = 1;
-
- // convert from our coordinate system (looking down X)
- // to OpenGL's coordinate system (looking down -Z)
- myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.or.modelMatrix );
-
- tr.viewParms.world = tr.or;
-
-}
-
-/*
-** SetFarClip
-*/
-static void R_SetFarClip( void )
-{
- float farthestCornerDistance = 0;
- int i;
-
- // if not rendering the world (icons, menus, etc)
- // set a 2k far clip plane
- if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
- tr.viewParms.zFar = 2048;
- return;
- }
-
- //
- // set far clipping planes dynamically
- //
- farthestCornerDistance = 0;
- for ( i = 0; i < 8; i++ )
- {
- vec3_t v;
- vec3_t vecTo;
- float distance;
-
- if ( i & 1 )
- {
- v[0] = tr.viewParms.visBounds[0][0];
- }
- else
- {
- v[0] = tr.viewParms.visBounds[1][0];
- }
-
- if ( i & 2 )
- {
- v[1] = tr.viewParms.visBounds[0][1];
- }
- else
- {
- v[1] = tr.viewParms.visBounds[1][1];
- }
-
- if ( i & 4 )
- {
- v[2] = tr.viewParms.visBounds[0][2];
- }
- else
- {
- v[2] = tr.viewParms.visBounds[1][2];
- }
-
- VectorSubtract( v, tr.viewParms.or.origin, vecTo );
-
- distance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2];
-
- if ( distance > farthestCornerDistance )
- {
- farthestCornerDistance = distance;
- }
- }
- tr.viewParms.zFar = sqrt( farthestCornerDistance );
-}
-
-/*
-=================
-R_SetupFrustum
-
-Set up the culling frustum planes for the current view using the results we got from computing the first two rows of
-the projection matrix.
-=================
-*/
-void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, float zProj, float stereoSep)
-{
- vec3_t ofsorigin;
- float oppleg, adjleg, length;
- int i;
-
- if(stereoSep == 0 && xmin == -xmax)
- {
- // symmetric case can be simplified
- VectorCopy(dest->or.origin, ofsorigin);
-
- length = sqrt(xmax * xmax + zProj * zProj);
- oppleg = xmax / length;
- adjleg = zProj / length;
-
- VectorScale(dest->or.axis[0], oppleg, dest->frustum[0].normal);
- VectorMA(dest->frustum[0].normal, adjleg, dest->or.axis[1], dest->frustum[0].normal);
-
- VectorScale(dest->or.axis[0], oppleg, dest->frustum[1].normal);
- VectorMA(dest->frustum[1].normal, -adjleg, dest->or.axis[1], dest->frustum[1].normal);
- }
- else
- {
- // In stereo rendering, due to the modification of the projection matrix, dest->or.origin is not the
- // actual origin that we're rendering so offset the tip of the view pyramid.
- VectorMA(dest->or.origin, stereoSep, dest->or.axis[1], ofsorigin);
-
- oppleg = xmax + stereoSep;
- length = sqrt(oppleg * oppleg + zProj * zProj);
- VectorScale(dest->or.axis[0], oppleg / length, dest->frustum[0].normal);
- VectorMA(dest->frustum[0].normal, zProj / length, dest->or.axis[1], dest->frustum[0].normal);
-
- oppleg = xmin + stereoSep;
- length = sqrt(oppleg * oppleg + zProj * zProj);
- VectorScale(dest->or.axis[0], -oppleg / length, dest->frustum[1].normal);
- VectorMA(dest->frustum[1].normal, -zProj / length, dest->or.axis[1], dest->frustum[1].normal);
- }
-
- length = sqrt(ymax * ymax + zProj * zProj);
- oppleg = ymax / length;
- adjleg = zProj / length;
-
- VectorScale(dest->or.axis[0], oppleg, dest->frustum[2].normal);
- VectorMA(dest->frustum[2].normal, adjleg, dest->or.axis[2], dest->frustum[2].normal);
-
- VectorScale(dest->or.axis[0], oppleg, dest->frustum[3].normal);
- VectorMA(dest->frustum[3].normal, -adjleg, dest->or.axis[2], dest->frustum[3].normal);
-
- for (i=0 ; i<4 ; i++) {
- dest->frustum[i].type = PLANE_NON_AXIAL;
- dest->frustum[i].dist = DotProduct (ofsorigin, dest->frustum[i].normal);
- SetPlaneSignbits( &dest->frustum[i] );
- }
-}
-
-/*
-===============
-R_SetupProjection
-===============
-*/
-void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum)
-{
- float xmin, xmax, ymin, ymax;
- float width, height, stereoSep = r_stereoSeparation->value;
-
- /*
- * offset the view origin of the viewer for stereo rendering
- * by setting the projection matrix appropriately.
- */
-
- if(stereoSep != 0)
- {
- if(dest->stereoFrame == STEREO_LEFT)
- stereoSep = zProj / stereoSep;
- else if(dest->stereoFrame == STEREO_RIGHT)
- stereoSep = zProj / -stereoSep;
- else
- stereoSep = 0;
- }
-
- ymax = zProj * tan(dest->fovY * M_PI / 360.0f);
- ymin = -ymax;
-
- xmax = zProj * tan(dest->fovX * M_PI / 360.0f);
- xmin = -xmax;
-
- width = xmax - xmin;
- height = ymax - ymin;
-
- dest->projectionMatrix[0] = 2 * zProj / width;
- dest->projectionMatrix[4] = 0;
- dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width;
- dest->projectionMatrix[12] = 2 * zProj * stereoSep / width;
-
- dest->projectionMatrix[1] = 0;
- dest->projectionMatrix[5] = 2 * zProj / height;
- dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
- dest->projectionMatrix[13] = 0;
-
- dest->projectionMatrix[3] = 0;
- dest->projectionMatrix[7] = 0;
- dest->projectionMatrix[11] = -1;
- dest->projectionMatrix[15] = 0;
-
- // Now that we have all the data for the projection matrix we can also setup the view frustum.
- if(computeFrustum)
- R_SetupFrustum(dest, xmin, xmax, ymax, zProj, stereoSep);
-}
-
-/*
-===============
-R_SetupProjectionZ
-
-Sets the z-component transformation part in the projection matrix
-===============
-*/
-void R_SetupProjectionZ(viewParms_t *dest)
-{
- float zNear, zFar, depth;
-
- zNear = r_znear->value;
- zFar = dest->zFar;
- depth = zFar - zNear;
-
- dest->projectionMatrix[2] = 0;
- dest->projectionMatrix[6] = 0;
- dest->projectionMatrix[10] = -( zFar + zNear ) / depth;
- dest->projectionMatrix[14] = -2 * zFar * zNear / depth;
-}
-
-/*
-=================
-R_MirrorPoint
-=================
-*/
-void R_MirrorPoint (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {
- int i;
- vec3_t local;
- vec3_t transformed;
- float d;
-
- VectorSubtract( in, surface->origin, local );
-
- VectorClear( transformed );
- for ( i = 0 ; i < 3 ; i++ ) {
- d = DotProduct(local, surface->axis[i]);
- VectorMA( transformed, d, camera->axis[i], transformed );
- }
-
- VectorAdd( transformed, camera->origin, out );
-}
-
-void R_MirrorVector (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {
- int i;
- float d;
-
- VectorClear( out );
- for ( i = 0 ; i < 3 ; i++ ) {
- d = DotProduct(in, surface->axis[i]);
- VectorMA( out, d, camera->axis[i], out );
- }
-}
-
-
-/*
-=============
-R_PlaneForSurface
-=============
-*/
-void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) {
- srfTriangles_t *tri;
- srfPoly_t *poly;
- drawVert_t *v1, *v2, *v3;
- vec4_t plane4;
-
- if (!surfType) {
- Com_Memset (plane, 0, sizeof(*plane));
- plane->normal[0] = 1;
- return;
- }
- switch (*surfType) {
- case SF_FACE:
- *plane = ((srfSurfaceFace_t *)surfType)->plane;
- return;
- case SF_TRIANGLES:
- tri = (srfTriangles_t *)surfType;
- v1 = tri->verts + tri->indexes[0];
- v2 = tri->verts + tri->indexes[1];
- v3 = tri->verts + tri->indexes[2];
- PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz );
- VectorCopy( plane4, plane->normal );
- plane->dist = plane4[3];
- return;
- case SF_POLY:
- poly = (srfPoly_t *)surfType;
- PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz );
- VectorCopy( plane4, plane->normal );
- plane->dist = plane4[3];
- return;
- default:
- Com_Memset (plane, 0, sizeof(*plane));
- plane->normal[0] = 1;
- return;
- }
-}
-
-/*
-=================
-R_GetPortalOrientation
-
-entityNum is the entity that the portal surface is a part of, which may
-be moving and rotating.
-
-Returns qtrue if it should be mirrored
-=================
-*/
-qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum,
- orientation_t *surface, orientation_t *camera,
- vec3_t pvsOrigin, qboolean *mirror ) {
- int i;
- cplane_t originalPlane, plane;
- trRefEntity_t *e;
- float d;
- vec3_t transformed;
-
- // create plane axis for the portal we are seeing
- R_PlaneForSurface( drawSurf->surface, &originalPlane );
-
- // rotate the plane if necessary
- if ( entityNum != ENTITYNUM_WORLD ) {
- tr.currentEntityNum = entityNum;
- tr.currentEntity = &tr.refdef.entities[entityNum];
-
- // get the orientation of the entity
- R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or );
-
- // rotate the plane, but keep the non-rotated version for matching
- // against the portalSurface entities
- R_LocalNormalToWorld( originalPlane.normal, plane.normal );
- plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin );
-
- // translate the original plane
- originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin );
- } else {
- plane = originalPlane;
- }
-
- VectorCopy( plane.normal, surface->axis[0] );
- PerpendicularVector( surface->axis[1], surface->axis[0] );
- CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] );
-
- // locate the portal entity closest to this plane.
- // origin will be the origin of the portal, origin2 will be
- // the origin of the camera
- for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) {
- e = &tr.refdef.entities[i];
- if ( e->e.reType != RT_PORTALSURFACE ) {
- continue;
- }
-
- d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
- if ( d > 64 || d < -64) {
- continue;
- }
-
- // get the pvsOrigin from the entity
- VectorCopy( e->e.oldorigin, pvsOrigin );
-
- // if the entity is just a mirror, don't use as a camera point
- if ( e->e.oldorigin[0] == e->e.origin[0] &&
- e->e.oldorigin[1] == e->e.origin[1] &&
- e->e.oldorigin[2] == e->e.origin[2] ) {
- VectorScale( plane.normal, plane.dist, surface->origin );
- VectorCopy( surface->origin, camera->origin );
- VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] );
- VectorCopy( surface->axis[1], camera->axis[1] );
- VectorCopy( surface->axis[2], camera->axis[2] );
-
- *mirror = qtrue;
- return qtrue;
- }
-
- // project the origin onto the surface plane to get
- // an origin point we can rotate around
- d = DotProduct( e->e.origin, plane.normal ) - plane.dist;
- VectorMA( e->e.origin, -d, surface->axis[0], surface->origin );
-
- // now get the camera origin and orientation
- VectorCopy( e->e.oldorigin, camera->origin );
- AxisCopy( e->e.axis, camera->axis );
- VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] );
- VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] );
-
- // optionally rotate
- if ( e->e.oldframe ) {
- // if a speed is specified
- if ( e->e.frame ) {
- // continuous rotate
- d = (tr.refdef.time/1000.0f) * e->e.frame;
- VectorCopy( camera->axis[1], transformed );
- RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
- CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
- } else {
- // bobbing rotate, with skinNum being the rotation offset
- d = sin( tr.refdef.time * 0.003f );
- d = e->e.skinNum + d * 4;
- VectorCopy( camera->axis[1], transformed );
- RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
- CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
- }
- }
- else if ( e->e.skinNum ) {
- d = e->e.skinNum;
- VectorCopy( camera->axis[1], transformed );
- RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
- CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
- }
- *mirror = qfalse;
- return qtrue;
- }
-
- // if we didn't locate a portal entity, don't render anything.
- // We don't want to just treat it as a mirror, because without a
- // portal entity the server won't have communicated a proper entity set
- // in the snapshot
-
- // unfortunately, with local movement prediction it is easily possible
- // to see a surface before the server has communicated the matching
- // portal surface entity, so we don't want to print anything here...
-
- //ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" );
-
- return qfalse;
-}
-
-static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum )
-{
- int i;
- cplane_t originalPlane, plane;
- trRefEntity_t *e;
- float d;
-
- // create plane axis for the portal we are seeing
- R_PlaneForSurface( drawSurf->surface, &originalPlane );
-
- // rotate the plane if necessary
- if ( entityNum != ENTITYNUM_WORLD )
- {
- tr.currentEntityNum = entityNum;
- tr.currentEntity = &tr.refdef.entities[entityNum];
-
- // get the orientation of the entity
- R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or );
-
- // rotate the plane, but keep the non-rotated version for matching
- // against the portalSurface entities
- R_LocalNormalToWorld( originalPlane.normal, plane.normal );
- plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin );
-
- // translate the original plane
- originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin );
- }
- else
- {
- plane = originalPlane;
- }
-
- // locate the portal entity closest to this plane.
- // origin will be the origin of the portal, origin2 will be
- // the origin of the camera
- for ( i = 0 ; i < tr.refdef.num_entities ; i++ )
- {
- e = &tr.refdef.entities[i];
- if ( e->e.reType != RT_PORTALSURFACE ) {
- continue;
- }
-
- d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
- if ( d > 64 || d < -64) {
- continue;
- }
-
- // if the entity is just a mirror, don't use as a camera point
- if ( e->e.oldorigin[0] == e->e.origin[0] &&
- e->e.oldorigin[1] == e->e.origin[1] &&
- e->e.oldorigin[2] == e->e.origin[2] )
- {
- return qtrue;
- }
-
- return qfalse;
- }
- return qfalse;
-}
-
-/*
-** SurfIsOffscreen
-**
-** Determines if a surface is completely offscreen.
-*/
-static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) {
- float shortest = 100000000;
- int entityNum;
- int numTriangles;
- shader_t *shader;
- int fogNum;
- int dlighted;
- vec4_t clip, eye;
- int i;
- unsigned int pointOr = 0;
- unsigned int pointAnd = (unsigned int)~0;
-
- if ( glConfig.smpActive ) { // FIXME! we can't do RB_BeginSurface/RB_EndSurface stuff with smp!
- return qfalse;
- }
-
- R_RotateForViewer();
-
- R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );
- RB_BeginSurface( shader, fogNum );
- rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
-
- assert( tess.numVertexes < 128 );
-
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- int j;
- unsigned int pointFlags = 0;
-
- R_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip );
-
- for ( j = 0; j < 3; j++ )
- {
- if ( clip[j] >= clip[3] )
- {
- pointFlags |= (1 << (j*2));
- }
- else if ( clip[j] <= -clip[3] )
- {
- pointFlags |= ( 1 << (j*2+1));
- }
- }
- pointAnd &= pointFlags;
- pointOr |= pointFlags;
- }
-
- // trivially reject
- if ( pointAnd )
- {
- return qtrue;
- }
-
- // determine if this surface is backfaced and also determine the distance
- // to the nearest vertex so we can cull based on portal range. Culling
- // based on vertex distance isn't 100% correct (we should be checking for
- // range to the surface), but it's good enough for the types of portals
- // we have in the game right now.
- numTriangles = tess.numIndexes / 3;
-
- for ( i = 0; i < tess.numIndexes; i += 3 )
- {
- vec3_t normal;
- float dot;
- float len;
-
- VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal );
-
- len = VectorLengthSquared( normal ); // lose the sqrt
- if ( len < shortest )
- {
- shortest = len;
- }
-
- if ( ( dot = DotProduct( normal, tess.normal[tess.indexes[i]] ) ) >= 0 )
- {
- numTriangles--;
- }
- }
- if ( !numTriangles )
- {
- return qtrue;
- }
-
- // mirrors can early out at this point, since we don't do a fade over distance
- // with them (although we could)
- if ( IsMirror( drawSurf, entityNum ) )
- {
- return qfalse;
- }
-
- if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) )
- {
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-========================
-R_MirrorViewBySurface
-
-Returns qtrue if another view has been rendered
-========================
-*/
-qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) {
- vec4_t clipDest[128];
- viewParms_t newParms;
- viewParms_t oldParms;
- orientation_t surface, camera;
-
- // don't recursively mirror
- if (tr.viewParms.isPortal) {
- ri.Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" );
- return qfalse;
- }
-
- if ( r_noportals->integer || (r_fastsky->integer == 1) ) {
- return qfalse;
- }
-
- // trivially reject portal/mirror
- if ( SurfIsOffscreen( drawSurf, clipDest ) ) {
- return qfalse;
- }
-
- // save old viewParms so we can return to it after the mirror view
- oldParms = tr.viewParms;
-
- newParms = tr.viewParms;
- newParms.isPortal = qtrue;
- if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera,
- newParms.pvsOrigin, &newParms.isMirror ) ) {
- return qfalse; // bad portal, no portalentity
- }
-
- R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin );
-
- VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal );
- newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal );
-
- R_MirrorVector (oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0]);
- R_MirrorVector (oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1]);
- R_MirrorVector (oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2]);
-
- // OPTIMIZE: restrict the viewport on the mirrored view
-
- // render the mirror view
- R_RenderView (&newParms);
-
- tr.viewParms = oldParms;
-
- return qtrue;
-}
-
-/*
-=================
-R_SpriteFogNum
-
-See if a sprite is inside a fog volume
-=================
-*/
-int R_SpriteFogNum( trRefEntity_t *ent ) {
- int i, j;
- fog_t *fog;
-
- if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
- return 0;
- }
-
- for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
- fog = &tr.world->fogs[i];
- for ( j = 0 ; j < 3 ; j++ ) {
- if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) {
- break;
- }
- if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) {
- break;
- }
- }
- if ( j == 3 ) {
- return i;
- }
- }
-
- return 0;
-}
-
-/*
-==========================================================================================
-
-DRAWSURF SORTING
-
-==========================================================================================
-*/
-
-/*
-===============
-R_Radix
-===============
-*/
-static ID_INLINE void R_Radix( int byte, int size, drawSurf_t *source, drawSurf_t *dest )
-{
- int count[ 256 ] = { 0 };
- int index[ 256 ];
- int i;
- unsigned char *sortKey = NULL;
- unsigned char *end = NULL;
-
- sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
- end = sortKey + ( size * sizeof( drawSurf_t ) );
- for( ; sortKey < end; sortKey += sizeof( drawSurf_t ) )
- ++count[ *sortKey ];
-
- index[ 0 ] = 0;
-
- for( i = 1; i < 256; ++i )
- index[ i ] = index[ i - 1 ] + count[ i - 1 ];
-
- sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
- for( i = 0; i < size; ++i, sortKey += sizeof( drawSurf_t ) )
- dest[ index[ *sortKey ]++ ] = source[ i ];
-}
-
-/*
-===============
-R_RadixSort
-
-Radix sort with 4 byte size buckets
-===============
-*/
-static void R_RadixSort( drawSurf_t *source, int size )
-{
- static drawSurf_t scratch[ MAX_DRAWSURFS ];
-#ifdef Q3_LITTLE_ENDIAN
- R_Radix( 0, size, source, scratch );
- R_Radix( 1, size, scratch, source );
- R_Radix( 2, size, source, scratch );
- R_Radix( 3, size, scratch, source );
-#else
- R_Radix( 3, size, source, scratch );
- R_Radix( 2, size, scratch, source );
- R_Radix( 1, size, source, scratch );
- R_Radix( 0, size, scratch, source );
-#endif //Q3_LITTLE_ENDIAN
-}
-
-//==========================================================================================
-
-/*
-=================
-R_AddDrawSurf
-=================
-*/
-void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
- int fogIndex, int dlightMap ) {
- int index;
-
- // instead of checking for overflow, we just mask the index
- // so it wraps around
- index = tr.refdef.numDrawSurfs & DRAWSURF_MASK;
- // the sort data is packed into a single 32 bit value so it can be
- // compared quickly during the qsorting process
- tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT)
- | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;
- tr.refdef.drawSurfs[index].surface = surface;
- tr.refdef.numDrawSurfs++;
-}
-
-/*
-=================
-R_DecomposeSort
-=================
-*/
-void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
- int *fogNum, int *dlightMap ) {
- *fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31;
- *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ];
- *entityNum = ( sort >> QSORT_ENTITYNUM_SHIFT ) & 1023;
- *dlightMap = sort & 3;
-}
-
-/*
-=================
-R_SortDrawSurfs
-=================
-*/
-void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
- shader_t *shader;
- int fogNum;
- int entityNum;
- int dlighted;
- int i;
-
- // it is possible for some views to not have any surfaces
- if ( numDrawSurfs < 1 ) {
- // we still need to add it for hyperspace cases
- R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
- return;
- }
-
- // if we overflowed MAX_DRAWSURFS, the drawsurfs
- // wrapped around in the buffer and we will be missing
- // the first surfaces, not the last ones
- if ( numDrawSurfs > MAX_DRAWSURFS ) {
- numDrawSurfs = MAX_DRAWSURFS;
- }
-
- // sort the drawsurfs by sort type, then orientation, then shader
- R_RadixSort( drawSurfs, numDrawSurfs );
-
- // check for any pass through drawing, which
- // may cause another view to be rendered first
- for ( i = 0 ; i < numDrawSurfs ; i++ ) {
- R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted );
-
- if ( shader->sort > SS_PORTAL ) {
- break;
- }
-
- // no shader should ever have this sort type
- if ( shader->sort == SS_BAD ) {
- ri.Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name );
- }
-
- // if the mirror was completely clipped away, we may need to check another surface
- if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) {
- // this is a debug option to see exactly what is being mirrored
- if ( r_portalOnly->integer ) {
- return;
- }
- break; // only one mirror view at a time
- }
- }
-
- R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
-}
-
-/*
-=============
-R_AddEntitySurfaces
-=============
-*/
-void R_AddEntitySurfaces (void) {
- trRefEntity_t *ent;
- shader_t *shader;
-
- if ( !r_drawentities->integer ) {
- return;
- }
-
- for ( tr.currentEntityNum = 0;
- tr.currentEntityNum < tr.refdef.num_entities;
- tr.currentEntityNum++ ) {
- ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum];
-
- ent->needDlights = qfalse;
-
- // preshift the value we are going to OR into the drawsurf sort
- tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT;
-
- //
- // the weapon model must be handled special --
- // we don't want the hacked weapon position showing in
- // mirrors, because the true body position will already be drawn
- //
- if ( (ent->e.renderfx & RF_FIRST_PERSON) && tr.viewParms.isPortal) {
- continue;
- }
-
- // simple generated models, like sprites and beams, are not culled
- switch ( ent->e.reType ) {
- case RT_PORTALSURFACE:
- break; // don't draw anything
- case RT_SPRITE:
- case RT_BEAM:
- case RT_LIGHTNING:
- case RT_RAIL_CORE:
- case RT_RAIL_RINGS:
- // self blood sprites, talk balloons, etc should not be drawn in the primary
- // view. We can't just do this check for all entities, because md3
- // entities may still want to cast shadows from them
- if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) {
- continue;
- }
- shader = R_GetShaderByHandle( ent->e.customShader );
- R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0 );
- break;
-
- case RT_MODEL:
- // we must set up parts of tr.or for model culling
- R_RotateForEntity( ent, &tr.viewParms, &tr.or );
-
- tr.currentModel = R_GetModelByHandle( ent->e.hModel );
- if (!tr.currentModel) {
- R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 );
- } else {
- switch ( tr.currentModel->type ) {
- case MOD_MESH:
- R_AddMD3Surfaces( ent );
- break;
- case MOD_MD4:
- R_AddAnimSurfaces( ent );
- break;
-#ifdef RAVENMD4
- case MOD_MDR:
- R_MDRAddAnimSurfaces( ent );
- break;
-#endif
- case MOD_BRUSH:
- R_AddBrushModelSurfaces( ent );
- break;
- case MOD_BAD: // null model axis
- if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) {
- break;
- }
- shader = R_GetShaderByHandle( ent->e.customShader );
- R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 );
- break;
- default:
- ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" );
- break;
- }
- }
- break;
- default:
- ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" );
- }
- }
-
-}
-
-
-/*
-====================
-R_GenerateDrawSurfs
-====================
-*/
-void R_GenerateDrawSurfs( void ) {
- R_AddWorldSurfaces ();
-
- R_AddPolygonSurfaces();
-
- // set the projection matrix with the minimum zfar
- // now that we have the world bounded
- // this needs to be done before entities are
- // added, because they use the projection
- // matrix for lod calculation
-
- // dynamically compute far clip plane distance
- R_SetFarClip();
-
- // we know the size of the clipping volume. Now set the rest of the projection matrix.
- R_SetupProjectionZ (&tr.viewParms);
-
- R_AddEntitySurfaces ();
-}
-
-/*
-================
-R_DebugPolygon
-================
-*/
-void R_DebugPolygon( int color, int numPoints, float *points ) {
- int i;
-
- GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
-
- // draw solid shade
-
- qglColor3f( color&1, (color>>1)&1, (color>>2)&1 );
- qglBegin( GL_POLYGON );
- for ( i = 0 ; i < numPoints ; i++ ) {
- qglVertex3fv( points + i * 3 );
- }
- qglEnd();
-
- // draw wireframe outline
- GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
- qglDepthRange( 0, 0 );
- qglColor3f( 1, 1, 1 );
- qglBegin( GL_POLYGON );
- for ( i = 0 ; i < numPoints ; i++ ) {
- qglVertex3fv( points + i * 3 );
- }
- qglEnd();
- qglDepthRange( 0, 1 );
-}
-
-/*
-====================
-R_DebugGraphics
-
-Visualization aid for movement clipping debugging
-====================
-*/
-void R_DebugGraphics( void ) {
- if ( !r_debugSurface->integer ) {
- return;
- }
-
- // the render thread can't make callbacks to the main thread
- R_SyncRenderThread();
-
- GL_Bind( tr.whiteImage);
- GL_Cull( CT_FRONT_SIDED );
- ri.CM_DrawDebugSurface( R_DebugPolygon );
-}
-
-
-/*
-================
-R_RenderView
-
-A view may be either the actual camera view,
-or a mirror / remote location
-================
-*/
-void R_RenderView (viewParms_t *parms) {
- int firstDrawSurf;
-
- if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) {
- return;
- }
-
- tr.viewCount++;
-
- tr.viewParms = *parms;
- tr.viewParms.frameSceneNum = tr.frameSceneNum;
- tr.viewParms.frameCount = tr.frameCount;
-
- firstDrawSurf = tr.refdef.numDrawSurfs;
-
- tr.viewCount++;
-
- // set viewParms.world
- R_RotateForViewer ();
-
- R_SetupProjection(&tr.viewParms, r_zproj->value, qtrue);
-
- R_GenerateDrawSurfs();
-
- R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf );
-
- // draw main system development information (surface outlines, etc)
- R_DebugGraphics();
-}
-
-
-
diff --git a/engine/code/renderer/tr_marks.c b/engine/code/renderer/tr_marks.c
deleted file mode 100644
index b83c77b..0000000
--- a/engine/code/renderer/tr_marks.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_marks.c -- polygon projection on the world polygons
-
-#include "tr_local.h"
-//#include "assert.h"
-
-#define MAX_VERTS_ON_POLY 64
-
-#define MARKER_OFFSET 0 // 1
-
-/*
-=============
-R_ChopPolyBehindPlane
-
-Out must have space for two more vertexes than in
-=============
-*/
-#define SIDE_FRONT 0
-#define SIDE_BACK 1
-#define SIDE_ON 2
-static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY],
- int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY],
- vec3_t normal, vec_t dist, vec_t epsilon) {
- float dists[MAX_VERTS_ON_POLY+4];
- int sides[MAX_VERTS_ON_POLY+4];
- int counts[3];
- float dot;
- int i, j;
- float *p1, *p2, *clip;
- float d;
-
- // don't clip if it might overflow
- if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) {
- *numOutPoints = 0;
- return;
- }
-
- counts[0] = counts[1] = counts[2] = 0;
-
- // determine sides for each point
- for ( i = 0 ; i < numInPoints ; i++ ) {
- dot = DotProduct( inPoints[i], normal );
- dot -= dist;
- dists[i] = dot;
- if ( dot > epsilon ) {
- sides[i] = SIDE_FRONT;
- } else if ( dot < -epsilon ) {
- sides[i] = SIDE_BACK;
- } else {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- *numOutPoints = 0;
-
- if ( !counts[0] ) {
- return;
- }
- if ( !counts[1] ) {
- *numOutPoints = numInPoints;
- Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) );
- return;
- }
-
- for ( i = 0 ; i < numInPoints ; i++ ) {
- p1 = inPoints[i];
- clip = outPoints[ *numOutPoints ];
-
- if ( sides[i] == SIDE_ON ) {
- VectorCopy( p1, clip );
- (*numOutPoints)++;
- continue;
- }
-
- if ( sides[i] == SIDE_FRONT ) {
- VectorCopy( p1, clip );
- (*numOutPoints)++;
- clip = outPoints[ *numOutPoints ];
- }
-
- if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
- continue;
- }
-
- // generate a split point
- p2 = inPoints[ (i+1) % numInPoints ];
-
- d = dists[i] - dists[i+1];
- if ( d == 0 ) {
- dot = 0;
- } else {
- dot = dists[i] / d;
- }
-
- // clip xyz
-
- for (j=0 ; j<3 ; j++) {
- clip[j] = p1[j] + dot * ( p2[j] - p1[j] );
- }
-
- (*numOutPoints)++;
- }
-}
-
-/*
-=================
-R_BoxSurfaces_r
-
-=================
-*/
-void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) {
-
- int s, c;
- msurface_t *surf, **mark;
-
- // do the tail recursion in a loop
- while ( node->contents == -1 ) {
- s = BoxOnPlaneSide( mins, maxs, node->plane );
- if (s == 1) {
- node = node->children[0];
- } else if (s == 2) {
- node = node->children[1];
- } else {
- R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir);
- node = node->children[1];
- }
- }
-
- // add the individual surfaces
- mark = node->firstmarksurface;
- c = node->nummarksurfaces;
- while (c--) {
- //
- if (*listlength >= listsize) break;
- //
- surf = *mark;
- // check if the surface has NOIMPACT or NOMARKS set
- if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )
- || ( surf->shader->contentFlags & CONTENTS_FOG ) ) {
- surf->viewCount = tr.viewCount;
- }
- // extra check for surfaces to avoid list overflows
- else if (*(surf->data) == SF_FACE) {
- // the face plane should go through the box
- s = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane );
- if (s == 1 || s == 2) {
- surf->viewCount = tr.viewCount;
- } else if (DotProduct((( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5) {
- // don't add faces that make sharp angles with the projection direction
- surf->viewCount = tr.viewCount;
- }
- }
- else if (*(surfaceType_t *) (surf->data) != SF_GRID &&
- *(surfaceType_t *) (surf->data) != SF_TRIANGLES)
- surf->viewCount = tr.viewCount;
- // check the viewCount because the surface may have
- // already been added if it spans multiple leafs
- if (surf->viewCount != tr.viewCount) {
- surf->viewCount = tr.viewCount;
- list[*listlength] = (surfaceType_t *) surf->data;
- (*listlength)++;
- }
- mark++;
- }
-}
-
-/*
-=================
-R_AddMarkFragments
-
-=================
-*/
-void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY],
- int numPlanes, vec3_t *normals, float *dists,
- int maxPoints, vec3_t pointBuffer,
- int maxFragments, markFragment_t *fragmentBuffer,
- int *returnedPoints, int *returnedFragments,
- vec3_t mins, vec3_t maxs) {
- int pingPong, i;
- markFragment_t *mf;
-
- // chop the surface by all the bounding planes of the to be projected polygon
- pingPong = 0;
-
- for ( i = 0 ; i < numPlanes ; i++ ) {
-
- R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong],
- &numClipPoints, clipPoints[!pingPong],
- normals[i], dists[i], 0.5 );
- pingPong ^= 1;
- if ( numClipPoints == 0 ) {
- break;
- }
- }
- // completely clipped away?
- if ( numClipPoints == 0 ) {
- return;
- }
-
- // add this fragment to the returned list
- if ( numClipPoints + (*returnedPoints) > maxPoints ) {
- return; // not enough space for this polygon
- }
- /*
- // all the clip points should be within the bounding box
- for ( i = 0 ; i < numClipPoints ; i++ ) {
- int j;
- for ( j = 0 ; j < 3 ; j++ ) {
- if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break;
- if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break;
- }
- if (j < 3) break;
- }
- if (i < numClipPoints) return;
- */
-
- mf = fragmentBuffer + (*returnedFragments);
- mf->firstPoint = (*returnedPoints);
- mf->numPoints = numClipPoints;
- Com_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) );
-
- (*returnedPoints) += numClipPoints;
- (*returnedFragments)++;
-}
-
-/*
-=================
-R_MarkFragments
-
-=================
-*/
-int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
- int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
- int numsurfaces, numPlanes;
- int i, j, k, m, n;
- surfaceType_t *surfaces[64];
- vec3_t mins, maxs;
- int returnedFragments;
- int returnedPoints;
- vec3_t normals[MAX_VERTS_ON_POLY+2];
- float dists[MAX_VERTS_ON_POLY+2];
- vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
- int numClipPoints;
- float *v;
- srfGridMesh_t *cv;
- drawVert_t *dv;
- vec3_t normal;
- vec3_t projectionDir;
- vec3_t v1, v2;
- int *indexes;
-
- //increment view count for double check prevention
- tr.viewCount++;
-
- //
- VectorNormalize2( projection, projectionDir );
- // find all the brushes that are to be considered
- ClearBounds( mins, maxs );
- for ( i = 0 ; i < numPoints ; i++ ) {
- vec3_t temp;
-
- AddPointToBounds( points[i], mins, maxs );
- VectorAdd( points[i], projection, temp );
- AddPointToBounds( temp, mins, maxs );
- // make sure we get all the leafs (also the one(s) in front of the hit surface)
- VectorMA( points[i], -20, projectionDir, temp );
- AddPointToBounds( temp, mins, maxs );
- }
-
- if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY;
- // create the bounding planes for the to be projected polygon
- for ( i = 0 ; i < numPoints ; i++ ) {
- VectorSubtract(points[(i+1)%numPoints], points[i], v1);
- VectorAdd(points[i], projection, v2);
- VectorSubtract(points[i], v2, v2);
- CrossProduct(v1, v2, normals[i]);
- VectorNormalizeFast(normals[i]);
- dists[i] = DotProduct(normals[i], points[i]);
- }
- // add near and far clipping planes for projection
- VectorCopy(projectionDir, normals[numPoints]);
- dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;
- VectorCopy(projectionDir, normals[numPoints+1]);
- VectorInverse(normals[numPoints+1]);
- dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20;
- numPlanes = numPoints + 2;
-
- numsurfaces = 0;
- R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir);
- //assert(numsurfaces <= 64);
- //assert(numsurfaces != 64);
-
- returnedPoints = 0;
- returnedFragments = 0;
-
- for ( i = 0 ; i < numsurfaces ; i++ ) {
-
- if (*surfaces[i] == SF_GRID) {
-
- cv = (srfGridMesh_t *) surfaces[i];
- for ( m = 0 ; m < cv->height - 1 ; m++ ) {
- for ( n = 0 ; n < cv->width - 1 ; n++ ) {
- // We triangulate the grid and chop all triangles within
- // the bounding planes of the to be projected polygon.
- // LOD is not taken into account, not such a big deal though.
- //
- // It's probably much nicer to chop the grid itself and deal
- // with this grid as a normal SF_GRID surface so LOD will
- // be applied. However the LOD of that chopped grid must
- // be synced with the LOD of the original curve.
- // One way to do this; the chopped grid shares vertices with
- // the original curve. When LOD is applied to the original
- // curve the unused vertices are flagged. Now the chopped curve
- // should skip the flagged vertices. This still leaves the
- // problems with the vertices at the chopped grid edges.
- //
- // To avoid issues when LOD applied to "hollow curves" (like
- // the ones around many jump pads) we now just add a 2 unit
- // offset to the triangle vertices.
- // The offset is added in the vertex normal vector direction
- // so all triangles will still fit together.
- // The 2 unit offset should avoid pretty much all LOD problems.
-
- numClipPoints = 3;
-
- dv = cv->verts + m * cv->width + n;
-
- VectorCopy(dv[0].xyz, clipPoints[0][0]);
- VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]);
- VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
- VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
- VectorCopy(dv[1].xyz, clipPoints[0][2]);
- VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]);
- // check the normal of this triangle
- VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
- VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
- CrossProduct(v1, v2, normal);
- VectorNormalizeFast(normal);
- if (DotProduct(normal, projectionDir) < -0.1) {
- // add the fragments of this triangle
- R_AddMarkFragments(numClipPoints, clipPoints,
- numPlanes, normals, dists,
- maxPoints, pointBuffer,
- maxFragments, fragmentBuffer,
- &returnedPoints, &returnedFragments, mins, maxs);
-
- if ( returnedFragments == maxFragments ) {
- return returnedFragments; // not enough space for more fragments
- }
- }
-
- VectorCopy(dv[1].xyz, clipPoints[0][0]);
- VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]);
- VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
- VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
- VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]);
- VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]);
- // check the normal of this triangle
- VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
- VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
- CrossProduct(v1, v2, normal);
- VectorNormalizeFast(normal);
- if (DotProduct(normal, projectionDir) < -0.05) {
- // add the fragments of this triangle
- R_AddMarkFragments(numClipPoints, clipPoints,
- numPlanes, normals, dists,
- maxPoints, pointBuffer,
- maxFragments, fragmentBuffer,
- &returnedPoints, &returnedFragments, mins, maxs);
-
- if ( returnedFragments == maxFragments ) {
- return returnedFragments; // not enough space for more fragments
- }
- }
- }
- }
- }
- else if (*surfaces[i] == SF_FACE) {
-
- srfSurfaceFace_t *surf = ( srfSurfaceFace_t * ) surfaces[i];
-
- // check the normal of this face
- if (DotProduct(surf->plane.normal, projectionDir) > -0.5) {
- continue;
- }
-
- indexes = (int *)( (byte *)surf + surf->ofsIndices );
- for ( k = 0 ; k < surf->numIndices ; k += 3 ) {
- for ( j = 0 ; j < 3 ; j++ ) {
- v = surf->points[0] + VERTEXSIZE * indexes[k+j];;
- VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] );
- }
-
- // add the fragments of this face
- R_AddMarkFragments( 3 , clipPoints,
- numPlanes, normals, dists,
- maxPoints, pointBuffer,
- maxFragments, fragmentBuffer,
- &returnedPoints, &returnedFragments, mins, maxs);
- if ( returnedFragments == maxFragments ) {
- return returnedFragments; // not enough space for more fragments
- }
- }
- }
- else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) {
-
- srfTriangles_t *surf = (srfTriangles_t *) surfaces[i];
-
- for (k = 0; k < surf->numIndexes; k += 3)
- {
- for(j = 0; j < 3; j++)
- {
- v = surf->verts[surf->indexes[k + j]].xyz;
- VectorMA(v, MARKER_OFFSET, surf->verts[surf->indexes[k + j]].normal, clipPoints[0][j]);
- }
-
- // add the fragments of this face
- R_AddMarkFragments(3, clipPoints,
- numPlanes, normals, dists,
- maxPoints, pointBuffer,
- maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
- if(returnedFragments == maxFragments)
- {
- return returnedFragments; // not enough space for more fragments
- }
- }
- }
- }
- return returnedFragments;
-}
-
diff --git a/engine/code/renderer/tr_mesh.c b/engine/code/renderer/tr_mesh.c
deleted file mode 100644
index 9b60348..0000000
--- a/engine/code/renderer/tr_mesh.c
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_mesh.c: triangle model functions
-
-#include "tr_local.h"
-
-static float ProjectRadius( float r, vec3_t location )
-{
- float pr;
- float dist;
- float c;
- vec3_t p;
- float projected[4];
-
- c = DotProduct( tr.viewParms.or.axis[0], tr.viewParms.or.origin );
- dist = DotProduct( tr.viewParms.or.axis[0], location ) - c;
-
- if ( dist <= 0 )
- return 0;
-
- p[0] = 0;
- p[1] = fabs( r );
- p[2] = -dist;
-
- projected[0] = p[0] * tr.viewParms.projectionMatrix[0] +
- p[1] * tr.viewParms.projectionMatrix[4] +
- p[2] * tr.viewParms.projectionMatrix[8] +
- tr.viewParms.projectionMatrix[12];
-
- projected[1] = p[0] * tr.viewParms.projectionMatrix[1] +
- p[1] * tr.viewParms.projectionMatrix[5] +
- p[2] * tr.viewParms.projectionMatrix[9] +
- tr.viewParms.projectionMatrix[13];
-
- projected[2] = p[0] * tr.viewParms.projectionMatrix[2] +
- p[1] * tr.viewParms.projectionMatrix[6] +
- p[2] * tr.viewParms.projectionMatrix[10] +
- tr.viewParms.projectionMatrix[14];
-
- projected[3] = p[0] * tr.viewParms.projectionMatrix[3] +
- p[1] * tr.viewParms.projectionMatrix[7] +
- p[2] * tr.viewParms.projectionMatrix[11] +
- tr.viewParms.projectionMatrix[15];
-
-
- pr = projected[1] / projected[3];
-
- if ( pr > 1.0f )
- pr = 1.0f;
-
- return pr;
-}
-
-/*
-=============
-R_CullModel
-=============
-*/
-static int R_CullModel( md3Header_t *header, trRefEntity_t *ent ) {
- vec3_t bounds[2];
- md3Frame_t *oldFrame, *newFrame;
- int i;
-
- // compute frame pointers
- newFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
- oldFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.oldframe;
-
- // cull bounding sphere ONLY if this is not an upscaled entity
- if ( !ent->e.nonNormalizedAxes )
- {
- if ( ent->e.frame == ent->e.oldframe )
- {
- switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
- {
- case CULL_OUT:
- tr.pc.c_sphere_cull_md3_out++;
- return CULL_OUT;
-
- case CULL_IN:
- tr.pc.c_sphere_cull_md3_in++;
- return CULL_IN;
-
- case CULL_CLIP:
- tr.pc.c_sphere_cull_md3_clip++;
- break;
- }
- }
- else
- {
- int sphereCull, sphereCullB;
-
- sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
- if ( newFrame == oldFrame ) {
- sphereCullB = sphereCull;
- } else {
- sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
- }
-
- if ( sphereCull == sphereCullB )
- {
- if ( sphereCull == CULL_OUT )
- {
- tr.pc.c_sphere_cull_md3_out++;
- return CULL_OUT;
- }
- else if ( sphereCull == CULL_IN )
- {
- tr.pc.c_sphere_cull_md3_in++;
- return CULL_IN;
- }
- else
- {
- tr.pc.c_sphere_cull_md3_clip++;
- }
- }
- }
- }
-
- // calculate a bounding box in the current coordinate system
- for (i = 0 ; i < 3 ; i++) {
- bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
- bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
- }
-
- switch ( R_CullLocalBox( bounds ) )
- {
- case CULL_IN:
- tr.pc.c_box_cull_md3_in++;
- return CULL_IN;
- case CULL_CLIP:
- tr.pc.c_box_cull_md3_clip++;
- return CULL_CLIP;
- case CULL_OUT:
- default:
- tr.pc.c_box_cull_md3_out++;
- return CULL_OUT;
- }
-}
-
-
-/*
-=================
-R_ComputeLOD
-
-=================
-*/
-int R_ComputeLOD( trRefEntity_t *ent ) {
- float radius;
- float flod, lodscale;
- float projectedRadius;
- md3Frame_t *frame;
-#ifdef RAVENMD4
- mdrHeader_t *mdr;
- mdrFrame_t *mdrframe;
-#endif
- int lod;
-
- if ( tr.currentModel->numLods < 2 )
- {
- // model has only 1 LOD level, skip computations and bias
- lod = 0;
- }
- else
- {
- // multiple LODs exist, so compute projected bounding sphere
- // and use that as a criteria for selecting LOD
-
-#ifdef RAVENMD4
- // This is an MDR model.
-
- if(tr.currentModel->md4)
- {
- int frameSize;
- mdr = (mdrHeader_t *) tr.currentModel->md4;
- frameSize = (size_t) (&((mdrFrame_t *)0)->bones[mdr->numBones]);
-
- mdrframe = (mdrFrame_t *) ((byte *) mdr + mdr->ofsFrames + frameSize * ent->e.frame);
-
- radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]);
- }
- else
-#endif
- {
- frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames );
-
- frame += ent->e.frame;
-
- radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] );
- }
-
- if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 )
- {
- lodscale = r_lodscale->value;
- if (lodscale > 20) lodscale = 20;
- flod = 1.0f - projectedRadius * lodscale;
- }
- else
- {
- // object intersects near view plane, e.g. view weapon
- flod = 0;
- }
-
- flod *= tr.currentModel->numLods;
- lod = myftol( flod );
-
- if ( lod < 0 )
- {
- lod = 0;
- }
- else if ( lod >= tr.currentModel->numLods )
- {
- lod = tr.currentModel->numLods - 1;
- }
- }
-
- lod += r_lodbias->integer;
-
- if ( lod >= tr.currentModel->numLods )
- lod = tr.currentModel->numLods - 1;
- if ( lod < 0 )
- lod = 0;
-
- return lod;
-}
-
-/*
-=================
-R_ComputeFogNum
-
-=================
-*/
-int R_ComputeFogNum( md3Header_t *header, trRefEntity_t *ent ) {
- int i, j;
- fog_t *fog;
- md3Frame_t *md3Frame;
- vec3_t localOrigin;
-
- if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
- return 0;
- }
-
- // FIXME: non-normalized axis issues
- md3Frame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
- VectorAdd( ent->e.origin, md3Frame->localOrigin, localOrigin );
- for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
- fog = &tr.world->fogs[i];
- for ( j = 0 ; j < 3 ; j++ ) {
- if ( localOrigin[j] - md3Frame->radius >= fog->bounds[1][j] ) {
- break;
- }
- if ( localOrigin[j] + md3Frame->radius <= fog->bounds[0][j] ) {
- break;
- }
- }
- if ( j == 3 ) {
- return i;
- }
- }
-
- return 0;
-}
-
-/*
-=================
-R_AddMD3Surfaces
-
-=================
-*/
-void R_AddMD3Surfaces( trRefEntity_t *ent ) {
- int i;
- md3Header_t *header = NULL;
- md3Surface_t *surface = NULL;
- md3Shader_t *md3Shader = NULL;
- shader_t *shader = NULL;
- int cull;
- int lod;
- int fogNum;
- qboolean personalModel;
-
- // don't add third_person objects if not in a portal
- personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
-
- if ( ent->e.renderfx & RF_WRAP_FRAMES ) {
- ent->e.frame %= tr.currentModel->md3[0]->numFrames;
- ent->e.oldframe %= tr.currentModel->md3[0]->numFrames;
- }
-
- //
- // Validate the frames so there is no chance of a crash.
- // This will write directly into the entity structure, so
- // when the surfaces are rendered, they don't need to be
- // range checked again.
- //
- if ( (ent->e.frame >= tr.currentModel->md3[0]->numFrames)
- || (ent->e.frame < 0)
- || (ent->e.oldframe >= tr.currentModel->md3[0]->numFrames)
- || (ent->e.oldframe < 0) ) {
- ri.Printf( PRINT_DEVELOPER, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n",
- ent->e.oldframe, ent->e.frame,
- tr.currentModel->name );
- ent->e.frame = 0;
- ent->e.oldframe = 0;
- }
-
- //
- // compute LOD
- //
- lod = R_ComputeLOD( ent );
-
- header = tr.currentModel->md3[lod];
-
- //
- // cull the entire model if merged bounding box of both frames
- // is outside the view frustum.
- //
- cull = R_CullModel ( header, ent );
- if ( cull == CULL_OUT ) {
- return;
- }
-
- //
- // set up lighting now that we know we aren't culled
- //
- if ( !personalModel || r_shadows->integer > 1 ) {
- R_SetupEntityLighting( &tr.refdef, ent );
- }
-
- //
- // see if we are in a fog volume
- //
- fogNum = R_ComputeFogNum( header, ent );
-
- //
- // draw all surfaces
- //
- surface = (md3Surface_t *)( (byte *)header + header->ofsSurfaces );
- for ( i = 0 ; i < header->numSurfaces ; i++ ) {
-
- if ( ent->e.customShader ) {
- shader = R_GetShaderByHandle( ent->e.customShader );
- } else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) {
- skin_t *skin;
- int j;
-
- skin = R_GetSkinByHandle( ent->e.customSkin );
-
- // match the surface name to something in the skin file
- shader = tr.defaultShader;
- for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
- // the names have both been lowercased
- if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
- shader = skin->surfaces[j]->shader;
- break;
- }
- }
- if (shader == tr.defaultShader) {
- ri.Printf( PRINT_DEVELOPER, "WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name);
- }
- else if (shader->defaultShader) {
- ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
- }
- } else if ( surface->numShaders <= 0 ) {
- shader = tr.defaultShader;
- } else {
- md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders );
- md3Shader += ent->e.skinNum % surface->numShaders;
- shader = tr.shaders[ md3Shader->shaderIndex ];
- }
-
-
- // we will add shadows even if the main object isn't visible in the view
-
- // stencil shadows can't do personal models unless I polyhedron clip
- if ( !personalModel
- && r_shadows->integer == 2
- && fogNum == 0
- && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
- && shader->sort == SS_OPAQUE ) {
- R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse );
- }
-
- // projection shadows work fine with personal models
- if ( r_shadows->integer == 3
- && fogNum == 0
- && (ent->e.renderfx & RF_SHADOW_PLANE )
- && shader->sort == SS_OPAQUE ) {
- R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
- }
-
- // don't add third_person objects if not viewing through a portal
- if ( !personalModel ) {
- R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse );
- }
-
- surface = (md3Surface_t *)( (byte *)surface + surface->ofsEnd );
- }
-
-}
-
diff --git a/engine/code/renderer/tr_model.c b/engine/code/renderer/tr_model.c
deleted file mode 100644
index 5355580..0000000
--- a/engine/code/renderer/tr_model.c
+++ /dev/null
@@ -1,1148 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_models.c -- model loading and caching
-
-#include "tr_local.h"
-
-#define LL(x) x=LittleLong(x)
-
-static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *name );
-static qboolean R_LoadMD4 (model_t *mod, void *buffer, const char *name );
-#ifdef RAVENMD4
-static qboolean R_LoadMDR (model_t *mod, void *buffer, int filesize, const char *name );
-#endif
-
-model_t *loadmodel;
-
-/*
-** R_GetModelByHandle
-*/
-model_t *R_GetModelByHandle( qhandle_t index ) {
- model_t *mod;
-
- // out of range gets the defualt model
- if ( index < 1 || index >= tr.numModels ) {
- return tr.models[0];
- }
-
- mod = tr.models[index];
-
- return mod;
-}
-
-//===============================================================================
-
-/*
-** R_AllocModel
-*/
-model_t *R_AllocModel( void ) {
- model_t *mod;
-
- if ( tr.numModels == MAX_MOD_KNOWN ) {
- return NULL;
- }
-
- mod = ri.Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), h_low );
- mod->index = tr.numModels;
- tr.models[tr.numModels] = mod;
- tr.numModels++;
-
- return mod;
-}
-
-/*
-====================
-RE_RegisterModel
-
-Loads in a model for the given name
-
-Zero will be returned if the model fails to load.
-An entry will be retained for failed models as an
-optimization to prevent disk rescanning if they are
-asked for again.
-====================
-*/
-qhandle_t RE_RegisterModel( const char *name ) {
- model_t *mod;
- union {
- unsigned *u;
- void *v;
- } buf;
- int lod;
- int ident;
- qboolean loaded = qfalse;
- qhandle_t hModel;
- int numLoaded;
- char *fext, defex[] = "md3", filename[MAX_QPATH], namebuf[MAX_QPATH+20];
-
- if ( !name || !name[0] ) {
- ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" );
- return 0;
- }
-
- if ( strlen( name ) >= MAX_QPATH ) {
- Com_Printf( "Model name exceeds MAX_QPATH\n" );
- return 0;
- }
-
- //
- // search the currently loaded models
- //
- for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) {
- mod = tr.models[hModel];
- if ( !strcmp( mod->name, name ) ) {
- if( mod->type == MOD_BAD ) {
- return 0;
- }
- return hModel;
- }
- }
-
- // allocate a new model_t
-
- if ( ( mod = R_AllocModel() ) == NULL ) {
- ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name);
- return 0;
- }
-
- // only set the name after the model has been successfully loaded
- Q_strncpyz( mod->name, name, sizeof( mod->name ) );
-
-
- // make sure the render thread is stopped
- R_SyncRenderThread();
-
- mod->numLods = 0;
-
- //
- // load the files
- //
- numLoaded = 0;
-
- strcpy(filename, name);
-
- fext = strchr(filename, '.');
- if(!fext)
- fext = defex;
- else
- {
- *fext = '\0';
- fext++;
- }
-
-#ifdef RAVENMD4
- if(!Q_stricmp(fext, "mdr"))
- {
- int filesize;
-
- filesize = ri.FS_ReadFile(name, (void **) &buf.v);
- if(!buf.u)
- {
- ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name);
- mod->type = MOD_BAD;
- return 0;
- }
-
- ident = LittleLong(*(unsigned *)buf.u);
- if(ident == MDR_IDENT)
- loaded = R_LoadMDR(mod, buf.u, filesize, name);
-
- ri.FS_FreeFile (buf.v);
-
- if(!loaded)
- {
- ri.Printf(PRINT_WARNING,"RE_RegisterModel: couldn't load mdr file %s\n", name);
- mod->type = MOD_BAD;
- return 0;
- }
-
- return mod->index;
- }
-#endif
-
- fext = defex;
-
- for ( lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod-- ) {
- if ( lod )
- Com_sprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext);
- else
- Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext);
-
- ri.FS_ReadFile( namebuf, &buf.v );
- if ( !buf.u ) {
- continue;
- }
-
- loadmodel = mod;
-
- ident = LittleLong(*(unsigned *)buf.u);
- if ( ident == MD4_IDENT ) {
- loaded = R_LoadMD4( mod, buf.u, name );
- } else {
- if ( ident != MD3_IDENT ) {
- ri.Printf (PRINT_WARNING,"RE_RegisterModel: unknown fileid for %s\n", name);
- goto fail;
- }
-
- loaded = R_LoadMD3( mod, lod, buf.u, name );
- }
-
- ri.FS_FreeFile (buf.v);
-
- if ( !loaded ) {
- if ( lod == 0 ) {
- goto fail;
- } else {
- break;
- }
- } else {
- mod->numLods++;
- numLoaded++;
- // if we have a valid model and are biased
- // so that we won't see any higher detail ones,
- // stop loading them
-// if ( lod <= r_lodbias->integer ) {
-// break;
-// }
- }
- }
-
- if ( numLoaded ) {
- // duplicate into higher lod spots that weren't
- // loaded, in case the user changes r_lodbias on the fly
- for ( lod-- ; lod >= 0 ; lod-- ) {
- mod->numLods++;
- mod->md3[lod] = mod->md3[lod+1];
- }
-
- return mod->index;
- }
-#ifdef _DEBUG
- else {
- ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name);
- }
-#endif
-
-fail:
- // we still keep the model_t around, so if the model name is asked for
- // again, we won't bother scanning the filesystem
- mod->type = MOD_BAD;
- return 0;
-}
-
-
-/*
-=================
-R_LoadMD3
-=================
-*/
-static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name ) {
- int i, j;
- md3Header_t *pinmodel;
- md3Frame_t *frame;
- md3Surface_t *surf;
- md3Shader_t *shader;
- md3Triangle_t *tri;
- md3St_t *st;
- md3XyzNormal_t *xyz;
- md3Tag_t *tag;
- int version;
- int size;
-
- pinmodel = (md3Header_t *)buffer;
-
- version = LittleLong (pinmodel->version);
- if (version != MD3_VERSION) {
- ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n",
- mod_name, version, MD3_VERSION);
- return qfalse;
- }
-
- mod->type = MOD_MESH;
- size = LittleLong(pinmodel->ofsEnd);
- mod->dataSize += size;
- mod->md3[lod] = ri.Hunk_Alloc( size, h_low );
-
- Com_Memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) );
-
- LL(mod->md3[lod]->ident);
- LL(mod->md3[lod]->version);
- LL(mod->md3[lod]->numFrames);
- LL(mod->md3[lod]->numTags);
- LL(mod->md3[lod]->numSurfaces);
- LL(mod->md3[lod]->ofsFrames);
- LL(mod->md3[lod]->ofsTags);
- LL(mod->md3[lod]->ofsSurfaces);
- LL(mod->md3[lod]->ofsEnd);
-
- if ( mod->md3[lod]->numFrames < 1 ) {
- ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name );
- return qfalse;
- }
-
- // swap all the frames
- frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
- for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
- frame->radius = LittleFloat( frame->radius );
- for ( j = 0 ; j < 3 ; j++ ) {
- frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
- frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
- frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
- }
- }
-
- // swap all the tags
- tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
- for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
- for ( j = 0 ; j < 3 ; j++ ) {
- tag->origin[j] = LittleFloat( tag->origin[j] );
- tag->axis[0][j] = LittleFloat( tag->axis[0][j] );
- tag->axis[1][j] = LittleFloat( tag->axis[1][j] );
- tag->axis[2][j] = LittleFloat( tag->axis[2][j] );
- }
- }
-
- // swap all the surfaces
- surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
- for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {
-
- LL(surf->ident);
- LL(surf->flags);
- LL(surf->numFrames);
- LL(surf->numShaders);
- LL(surf->numTriangles);
- LL(surf->ofsTriangles);
- LL(surf->numVerts);
- LL(surf->ofsShaders);
- LL(surf->ofsSt);
- LL(surf->ofsXyzNormals);
- LL(surf->ofsEnd);
-
- if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
- ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
- mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
- }
- if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
- ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
- mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
- }
-
- // change to surface identifier
- surf->ident = SF_MD3;
-
- // lowercase the surface name so skin compares are faster
- Q_strlwr( surf->name );
-
- // strip off a trailing _1 or _2
- // this is a crutch for q3data being a mess
- j = strlen( surf->name );
- if ( j > 2 && surf->name[j-2] == '_' ) {
- surf->name[j-2] = 0;
- }
-
- // register the shaders
- shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
- for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
- shader_t *sh;
-
- sh = R_FindShader( shader->name, LIGHTMAP_NONE, qtrue );
- if ( sh->defaultShader ) {
- shader->shaderIndex = 0;
- } else {
- shader->shaderIndex = sh->index;
- }
- }
-
- // swap all the triangles
- tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
- for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
- LL(tri->indexes[0]);
- LL(tri->indexes[1]);
- LL(tri->indexes[2]);
- }
-
- // swap all the ST
- st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
- for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
- st->st[0] = LittleFloat( st->st[0] );
- st->st[1] = LittleFloat( st->st[1] );
- }
-
- // swap all the XyzNormals
- xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
- for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ )
- {
- xyz->xyz[0] = LittleShort( xyz->xyz[0] );
- xyz->xyz[1] = LittleShort( xyz->xyz[1] );
- xyz->xyz[2] = LittleShort( xyz->xyz[2] );
-
- xyz->normal = LittleShort( xyz->normal );
- }
-
-
- // find the next surface
- surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
- }
-
- return qtrue;
-}
-
-
-#ifdef RAVENMD4
-
-/*
-=================
-R_LoadMDR
-=================
-*/
-static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name )
-{
- int i, j, k, l;
- mdrHeader_t *pinmodel, *mdr;
- mdrFrame_t *frame;
- mdrLOD_t *lod, *curlod;
- mdrSurface_t *surf, *cursurf;
- mdrTriangle_t *tri, *curtri;
- mdrVertex_t *v, *curv;
- mdrWeight_t *weight, *curweight;
- mdrTag_t *tag, *curtag;
- int size;
- shader_t *sh;
-
- pinmodel = (mdrHeader_t *)buffer;
-
- pinmodel->version = LittleLong(pinmodel->version);
- if (pinmodel->version != MDR_VERSION)
- {
- ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has wrong version (%i should be %i)\n", mod_name, pinmodel->version, MDR_VERSION);
- return qfalse;
- }
-
- size = LittleLong(pinmodel->ofsEnd);
-
- if(size > filesize)
- {
- ri.Printf(PRINT_WARNING, "R_LoadMDR: Header of %s is broken. Wrong filesize declared!\n", mod_name);
- return qfalse;
- }
-
- mod->type = MOD_MDR;
-
- LL(pinmodel->numFrames);
- LL(pinmodel->numBones);
- LL(pinmodel->ofsFrames);
-
- // This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame
- // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target md4.
- if(pinmodel->ofsFrames < 0)
- {
- // mdrFrame_t is larger than mdrCompFrame_t:
- size += pinmodel->numFrames * sizeof(frame->name);
- // now add enough space for the uncompressed bones.
- size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t)));
- }
-
- // simple bounds check
- if(pinmodel->numBones < 0 ||
- sizeof(*mdr) + pinmodel->numFrames * (sizeof(*frame) + (pinmodel->numBones - 1) * sizeof(*frame->bones)) > size)
- {
- ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
- return qfalse;
- }
-
- mod->dataSize += size;
- mod->md4 = mdr = ri.Hunk_Alloc( size, h_low );
-
- // Copy all the values over from the file and fix endian issues in the process, if necessary.
-
- mdr->ident = LittleLong(pinmodel->ident);
- mdr->version = pinmodel->version; // Don't need to swap byte order on this one, we already did above.
- Q_strncpyz(mdr->name, pinmodel->name, sizeof(mdr->name));
- mdr->numFrames = pinmodel->numFrames;
- mdr->numBones = pinmodel->numBones;
- mdr->numLODs = LittleLong(pinmodel->numLODs);
- mdr->numTags = LittleLong(pinmodel->numTags);
- // We don't care about the other offset values, we'll generate them ourselves while loading.
-
- mod->numLods = mdr->numLODs;
-
- if ( mdr->numFrames < 1 )
- {
- ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has no frames\n", mod_name);
- return qfalse;
- }
-
- /* The first frame will be put into the first free space after the header */
- frame = (mdrFrame_t *)(mdr + 1);
- mdr->ofsFrames = (int)((byte *) frame - (byte *) mdr);
-
- if (pinmodel->ofsFrames < 0)
- {
- mdrCompFrame_t *cframe;
-
- // compressed model...
- cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames);
-
- for(i = 0; i < mdr->numFrames; i++)
- {
- for(j = 0; j < 3; j++)
- {
- frame->bounds[0][j] = LittleFloat(cframe->bounds[0][j]);
- frame->bounds[1][j] = LittleFloat(cframe->bounds[1][j]);
- frame->localOrigin[j] = LittleFloat(cframe->localOrigin[j]);
- }
-
- frame->radius = LittleFloat(cframe->radius);
- frame->name[0] = '\0'; // No name supplied in the compressed version.
-
- for(j = 0; j < mdr->numBones; j++)
- {
- for(k = 0; k < (sizeof(cframe->bones[j].Comp) / 2); k++)
- {
- // Do swapping for the uncompressing functions. They seem to use shorts
- // values only, so I assume this will work. Never tested it on other
- // platforms, though.
-
- ((unsigned short *)(cframe->bones[j].Comp))[k] =
- LittleShort( ((unsigned short *)(cframe->bones[j].Comp))[k] );
- }
-
- /* Now do the actual uncompressing */
- MC_UnCompress(frame->bones[j].matrix, cframe->bones[j].Comp);
- }
-
- // Next Frame...
- cframe = (mdrCompFrame_t *) &cframe->bones[j];
- frame = (mdrFrame_t *) &frame->bones[j];
- }
- }
- else
- {
- mdrFrame_t *curframe;
-
- // uncompressed model...
- //
-
- curframe = (mdrFrame_t *)((byte *) pinmodel + pinmodel->ofsFrames);
-
- // swap all the frames
- for ( i = 0 ; i < mdr->numFrames ; i++)
- {
- for(j = 0; j < 3; j++)
- {
- frame->bounds[0][j] = LittleFloat(curframe->bounds[0][j]);
- frame->bounds[1][j] = LittleFloat(curframe->bounds[1][j]);
- frame->localOrigin[j] = LittleFloat(curframe->localOrigin[j]);
- }
-
- frame->radius = LittleFloat(curframe->radius);
- Q_strncpyz(frame->name, curframe->name, sizeof(frame->name));
-
- for (j = 0; j < (int) (mdr->numBones * sizeof(mdrBone_t) / 4); j++)
- {
- ((float *)frame->bones)[j] = LittleFloat( ((float *)curframe->bones)[j] );
- }
-
- curframe++;
- frame++;
- }
- }
-
- // frame should now point to the first free address after all frames.
- lod = (mdrLOD_t *) frame;
- mdr->ofsLODs = (int) ((byte *) lod - (byte *)mdr);
-
- curlod = (mdrLOD_t *)((byte *) pinmodel + LittleLong(pinmodel->ofsLODs));
-
- // swap all the LOD's
- for ( l = 0 ; l < mdr->numLODs ; l++)
- {
- // simple bounds check
- if((byte *) (lod + 1) > (byte *) mdr + size)
- {
- ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
- return qfalse;
- }
-
- lod->numSurfaces = LittleLong(curlod->numSurfaces);
-
- // swap all the surfaces
- surf = (mdrSurface_t *) (lod + 1);
- lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod);
- cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces));
-
- for ( i = 0 ; i < lod->numSurfaces ; i++)
- {
- // simple bounds check
- if((byte *) (surf + 1) > (byte *) mdr + size)
- {
- ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
- return qfalse;
- }
-
- // first do some copying stuff
-
- surf->ident = SF_MDR;
- Q_strncpyz(surf->name, cursurf->name, sizeof(surf->name));
- Q_strncpyz(surf->shader, cursurf->shader, sizeof(surf->shader));
-
- surf->ofsHeader = (byte *) mdr - (byte *) surf;
-
- surf->numVerts = LittleLong(cursurf->numVerts);
- surf->numTriangles = LittleLong(cursurf->numTriangles);
- // numBoneReferences and BoneReferences generally seem to be unused
-
- // now do the checks that may fail.
- if ( surf->numVerts > SHADER_MAX_VERTEXES )
- {
- ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on a surface (%i)",
- mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
- return qfalse;
- }
- if ( surf->numTriangles*3 > SHADER_MAX_INDEXES )
- {
- ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on a surface (%i)",
- mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
- return qfalse;
- }
- // lowercase the surface name so skin compares are faster
- Q_strlwr( surf->name );
-
- // register the shaders
- sh = R_FindShader(surf->shader, LIGHTMAP_NONE, qtrue);
- if ( sh->defaultShader ) {
- surf->shaderIndex = 0;
- } else {
- surf->shaderIndex = sh->index;
- }
-
- // now copy the vertexes.
- v = (mdrVertex_t *) (surf + 1);
- surf->ofsVerts = (int)((byte *) v - (byte *) surf);
- curv = (mdrVertex_t *) ((byte *)cursurf + LittleLong(cursurf->ofsVerts));
-
- for(j = 0; j < surf->numVerts; j++)
- {
- LL(curv->numWeights);
-
- // simple bounds check
- if(curv->numWeights < 0 || (byte *) (v + 1) + (curv->numWeights - 1) * sizeof(*weight) > (byte *) mdr + size)
- {
- ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
- return qfalse;
- }
-
- v->normal[0] = LittleFloat(curv->normal[0]);
- v->normal[1] = LittleFloat(curv->normal[1]);
- v->normal[2] = LittleFloat(curv->normal[2]);
-
- v->texCoords[0] = LittleFloat(curv->texCoords[0]);
- v->texCoords[1] = LittleFloat(curv->texCoords[1]);
-
- v->numWeights = curv->numWeights;
- weight = &v->weights[0];
- curweight = &curv->weights[0];
-
- // Now copy all the weights
- for(k = 0; k < v->numWeights; k++)
- {
- weight->boneIndex = LittleLong(curweight->boneIndex);
- weight->boneWeight = LittleFloat(curweight->boneWeight);
-
- weight->offset[0] = LittleFloat(curweight->offset[0]);
- weight->offset[1] = LittleFloat(curweight->offset[1]);
- weight->offset[2] = LittleFloat(curweight->offset[2]);
-
- weight++;
- curweight++;
- }
-
- v = (mdrVertex_t *) weight;
- curv = (mdrVertex_t *) curweight;
- }
-
- // we know the offset to the triangles now:
- tri = (mdrTriangle_t *) v;
- surf->ofsTriangles = (int)((byte *) tri - (byte *) surf);
- curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles));
-
- // simple bounds check
- if(surf->numTriangles < 0 || (byte *) (tri + surf->numTriangles) > (byte *) mdr + size)
- {
- ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
- return qfalse;
- }
-
- for(j = 0; j < surf->numTriangles; j++)
- {
- tri->indexes[0] = LittleLong(curtri->indexes[0]);
- tri->indexes[1] = LittleLong(curtri->indexes[1]);
- tri->indexes[2] = LittleLong(curtri->indexes[2]);
-
- tri++;
- curtri++;
- }
-
- // tri now points to the end of the surface.
- surf->ofsEnd = (byte *) tri - (byte *) surf;
- surf = (mdrSurface_t *) tri;
-
- // find the next surface.
- cursurf = (mdrSurface_t *) ((byte *) cursurf + LittleLong(cursurf->ofsEnd));
- }
-
- // surf points to the next lod now.
- lod->ofsEnd = (int)((byte *) surf - (byte *) lod);
- lod = (mdrLOD_t *) surf;
-
- // find the next LOD.
- curlod = (mdrLOD_t *)((byte *) curlod + LittleLong(curlod->ofsEnd));
- }
-
- // lod points to the first tag now, so update the offset too.
- tag = (mdrTag_t *) lod;
- mdr->ofsTags = (int)((byte *) tag - (byte *) mdr);
- curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags));
-
- // simple bounds check
- if(mdr->numTags < 0 || (byte *) (tag + mdr->numTags) > (byte *) mdr + size)
- {
- ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
- return qfalse;
- }
-
- for (i = 0 ; i < mdr->numTags ; i++)
- {
- tag->boneIndex = LittleLong(curtag->boneIndex);
- Q_strncpyz(tag->name, curtag->name, sizeof(tag->name));
-
- tag++;
- curtag++;
- }
-
- // And finally we know the real offset to the end.
- mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr);
-
- // phew! we're done.
-
- return qtrue;
-}
-#endif
-
-/*
-=================
-R_LoadMD4
-=================
-*/
-
-static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) {
- int i, j, k, lodindex;
- md4Header_t *pinmodel, *md4;
- md4Frame_t *frame;
- md4LOD_t *lod;
- md4Surface_t *surf;
- md4Triangle_t *tri;
- md4Vertex_t *v;
- int version;
- int size;
- shader_t *sh;
- int frameSize;
-
- pinmodel = (md4Header_t *)buffer;
-
- version = LittleLong (pinmodel->version);
- if (version != MD4_VERSION) {
- ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has wrong version (%i should be %i)\n",
- mod_name, version, MD4_VERSION);
- return qfalse;
- }
-
- mod->type = MOD_MD4;
- size = LittleLong(pinmodel->ofsEnd);
- mod->dataSize += size;
- md4 = mod->md4 = ri.Hunk_Alloc( size, h_low );
-
- Com_Memcpy(md4, buffer, size);
-
- LL(md4->ident);
- LL(md4->version);
- LL(md4->numFrames);
- LL(md4->numBones);
- LL(md4->numLODs);
- LL(md4->ofsFrames);
- LL(md4->ofsLODs);
- md4->ofsEnd = size;
-
- if ( md4->numFrames < 1 ) {
- ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has no frames\n", mod_name );
- return qfalse;
- }
-
- // we don't need to swap tags in the renderer, they aren't used
-
- // swap all the frames
- frameSize = (size_t)( &((md4Frame_t *)0)->bones[ md4->numBones ] );
- for ( i = 0 ; i < md4->numFrames ; i++, frame++) {
- frame = (md4Frame_t *) ( (byte *)md4 + md4->ofsFrames + i * frameSize );
- frame->radius = LittleFloat( frame->radius );
- for ( j = 0 ; j < 3 ; j++ ) {
- frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
- frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
- frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
- }
- for ( j = 0 ; j < md4->numBones * sizeof( md4Bone_t ) / 4 ; j++ ) {
- ((float *)frame->bones)[j] = LittleFloat( ((float *)frame->bones)[j] );
- }
- }
-
- // swap all the LOD's
- lod = (md4LOD_t *) ( (byte *)md4 + md4->ofsLODs );
- for ( lodindex = 0 ; lodindex < md4->numLODs ; lodindex++ ) {
-
- // swap all the surfaces
- surf = (md4Surface_t *) ( (byte *)lod + lod->ofsSurfaces );
- for ( i = 0 ; i < lod->numSurfaces ; i++) {
- LL(surf->ident);
- LL(surf->numTriangles);
- LL(surf->ofsTriangles);
- LL(surf->numVerts);
- LL(surf->ofsVerts);
- LL(surf->ofsEnd);
-
- if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
- ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
- mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
- }
- if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
- ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
- mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
- }
-
- // change to surface identifier
- surf->ident = SF_MD4;
-
- // lowercase the surface name so skin compares are faster
- Q_strlwr( surf->name );
-
- // register the shaders
- sh = R_FindShader( surf->shader, LIGHTMAP_NONE, qtrue );
- if ( sh->defaultShader ) {
- surf->shaderIndex = 0;
- } else {
- surf->shaderIndex = sh->index;
- }
-
- // swap all the triangles
- tri = (md4Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
- for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
- LL(tri->indexes[0]);
- LL(tri->indexes[1]);
- LL(tri->indexes[2]);
- }
-
- // swap all the vertexes
- // FIXME
- // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left
- // in for reference.
- //v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts + 12);
- v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts);
- for ( j = 0 ; j < surf->numVerts ; j++ ) {
- v->normal[0] = LittleFloat( v->normal[0] );
- v->normal[1] = LittleFloat( v->normal[1] );
- v->normal[2] = LittleFloat( v->normal[2] );
-
- v->texCoords[0] = LittleFloat( v->texCoords[0] );
- v->texCoords[1] = LittleFloat( v->texCoords[1] );
-
- v->numWeights = LittleLong( v->numWeights );
-
- for ( k = 0 ; k < v->numWeights ; k++ ) {
- v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex );
- v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight );
- v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] );
- v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] );
- v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] );
- }
- // FIXME
- // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left
- // in for reference.
- //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 );
- v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights]);
- }
-
- // find the next surface
- surf = (md4Surface_t *)( (byte *)surf + surf->ofsEnd );
- }
-
- // find the next LOD
- lod = (md4LOD_t *)( (byte *)lod + lod->ofsEnd );
- }
-
- return qtrue;
-}
-
-
-
-//=============================================================================
-
-/*
-** RE_BeginRegistration
-*/
-void RE_BeginRegistration( glconfig_t *glconfigOut ) {
-
- R_Init();
-
- *glconfigOut = glConfig;
-
- R_SyncRenderThread();
-
- tr.viewCluster = -1; // force markleafs to regenerate
- R_ClearFlares();
- RE_ClearScene();
-
- tr.registered = qtrue;
-
- // NOTE: this sucks, for some reason the first stretch pic is never drawn
- // without this we'd see a white flash on a level load because the very
- // first time the level shot would not be drawn
-// RE_StretchPic(0, 0, 0, 0, 0, 0, 1, 1, 0);
-}
-
-//=============================================================================
-
-/*
-===============
-R_ModelInit
-===============
-*/
-void R_ModelInit( void ) {
- model_t *mod;
-
- // leave a space for NULL model
- tr.numModels = 0;
-
- mod = R_AllocModel();
- mod->type = MOD_BAD;
-}
-
-
-/*
-================
-R_Modellist_f
-================
-*/
-void R_Modellist_f( void ) {
- int i, j;
- model_t *mod;
- int total;
- int lods;
-
- total = 0;
- for ( i = 1 ; i < tr.numModels; i++ ) {
- mod = tr.models[i];
- lods = 1;
- for ( j = 1 ; j < MD3_MAX_LODS ; j++ ) {
- if ( mod->md3[j] && mod->md3[j] != mod->md3[j-1] ) {
- lods++;
- }
- }
- ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name );
- total += mod->dataSize;
- }
- ri.Printf( PRINT_ALL, "%8i : Total models\n", total );
-
-#if 0 // not working right with new hunk
- if ( tr.world ) {
- ri.Printf( PRINT_ALL, "\n%8i : %s\n", tr.world->dataSize, tr.world->name );
- }
-#endif
-}
-
-
-//=============================================================================
-
-
-/*
-================
-R_GetTag
-================
-*/
-static md3Tag_t *R_GetTag( md3Header_t *mod, int frame, const char *tagName ) {
- md3Tag_t *tag;
- int i;
-
- if ( frame >= mod->numFrames ) {
- // it is possible to have a bad frame while changing models, so don't error
- frame = mod->numFrames - 1;
- }
-
- tag = (md3Tag_t *)((byte *)mod + mod->ofsTags) + frame * mod->numTags;
- for ( i = 0 ; i < mod->numTags ; i++, tag++ ) {
- if ( !strcmp( tag->name, tagName ) ) {
- return tag; // found it
- }
- }
-
- return NULL;
-}
-
-#ifdef RAVENMD4
-void R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, md3Tag_t * dest)
-{
- int i, j, k;
- int frameSize;
- mdrFrame_t *frame;
- mdrTag_t *tag;
-
- if ( framenum >= mod->numFrames )
- {
- // it is possible to have a bad frame while changing models, so don't error
- framenum = mod->numFrames - 1;
- }
-
- tag = (mdrTag_t *)((byte *)mod + mod->ofsTags);
- for ( i = 0 ; i < mod->numTags ; i++, tag++ )
- {
- if ( !strcmp( tag->name, tagName ) )
- {
- Q_strncpyz(dest->name, tag->name, sizeof(dest->name));
-
- // uncompressed model...
- //
- frameSize = (long)( &((mdrFrame_t *)0)->bones[ mod->numBones ] );
- frame = (mdrFrame_t *)((byte *)mod + mod->ofsFrames + framenum * frameSize );
-
- for (j = 0; j < 3; j++)
- {
- for (k = 0; k < 3; k++)
- dest->axis[j][k]=frame->bones[tag->boneIndex].matrix[k][j];
- }
-
- dest->origin[0]=frame->bones[tag->boneIndex].matrix[0][3];
- dest->origin[1]=frame->bones[tag->boneIndex].matrix[1][3];
- dest->origin[2]=frame->bones[tag->boneIndex].matrix[2][3];
-
- return;
- }
- }
-
- AxisClear( dest->axis );
- VectorClear( dest->origin );
- strcpy(dest->name,"");
-}
-#endif
-
-/*
-================
-R_LerpTag
-================
-*/
-int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame,
- float frac, const char *tagName ) {
- md3Tag_t *start, *end;
-#ifdef RAVENMD4
- md3Tag_t start_space, end_space;
-#endif
- int i;
- float frontLerp, backLerp;
- model_t *model;
-
- model = R_GetModelByHandle( handle );
- if ( !model->md3[0] )
- {
-#ifdef RAVENMD4
- if(model->md4)
- {
- start = &start_space;
- end = &end_space;
- R_GetAnimTag((mdrHeader_t *) model->md4, startFrame, tagName, start);
- R_GetAnimTag((mdrHeader_t *) model->md4, endFrame, tagName, end);
- }
- else
-#endif
- {
-
- AxisClear( tag->axis );
- VectorClear( tag->origin );
- return qfalse;
-
- }
- }
- else
- {
- start = R_GetTag( model->md3[0], startFrame, tagName );
- end = R_GetTag( model->md3[0], endFrame, tagName );
- if ( !start || !end ) {
- AxisClear( tag->axis );
- VectorClear( tag->origin );
- return qfalse;
- }
- }
-
- frontLerp = frac;
- backLerp = 1.0f - frac;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- tag->origin[i] = start->origin[i] * backLerp + end->origin[i] * frontLerp;
- tag->axis[0][i] = start->axis[0][i] * backLerp + end->axis[0][i] * frontLerp;
- tag->axis[1][i] = start->axis[1][i] * backLerp + end->axis[1][i] * frontLerp;
- tag->axis[2][i] = start->axis[2][i] * backLerp + end->axis[2][i] * frontLerp;
- }
- VectorNormalize( tag->axis[0] );
- VectorNormalize( tag->axis[1] );
- VectorNormalize( tag->axis[2] );
- return qtrue;
-}
-
-
-/*
-====================
-R_ModelBounds
-====================
-*/
-void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) {
- model_t *model;
- md3Header_t *header;
- md3Frame_t *frame;
-
- model = R_GetModelByHandle( handle );
-
- if ( model->bmodel ) {
- VectorCopy( model->bmodel->bounds[0], mins );
- VectorCopy( model->bmodel->bounds[1], maxs );
- return;
- }
-
- if ( !model->md3[0] ) {
- VectorClear( mins );
- VectorClear( maxs );
- return;
- }
-
- header = model->md3[0];
-
- frame = (md3Frame_t *)( (byte *)header + header->ofsFrames );
-
- VectorCopy( frame->bounds[0], mins );
- VectorCopy( frame->bounds[1], maxs );
-}
-
diff --git a/engine/code/renderer/tr_noise.c b/engine/code/renderer/tr_noise.c
deleted file mode 100644
index af2f84e..0000000
--- a/engine/code/renderer/tr_noise.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_noise.c
-#include "tr_local.h"
-
-#define NOISE_SIZE 256
-#define NOISE_MASK ( NOISE_SIZE - 1 )
-
-#define VAL( a ) s_noise_perm[ ( a ) & ( NOISE_MASK )]
-#define INDEX( x, y, z, t ) VAL( x + VAL( y + VAL( z + VAL( t ) ) ) )
-
-static float s_noise_table[NOISE_SIZE];
-static int s_noise_perm[NOISE_SIZE];
-
-#define LERP( a, b, w ) ( a * ( 1.0f - w ) + b * w )
-
-static float GetNoiseValue( int x, int y, int z, int t )
-{
- int index = INDEX( ( int ) x, ( int ) y, ( int ) z, ( int ) t );
-
- return s_noise_table[index];
-}
-
-void R_NoiseInit( void )
-{
- int i;
-
- for ( i = 0; i < NOISE_SIZE; i++ )
- {
- s_noise_table[i] = ( float ) ( ( ( rand() / ( float ) RAND_MAX ) * 2.0 - 1.0 ) );
- s_noise_perm[i] = ( unsigned char ) ( rand() / ( float ) RAND_MAX * 255 );
- }
-}
-
-float R_NoiseGet4f( float x, float y, float z, float t )
-{
- int i;
- int ix, iy, iz, it;
- float fx, fy, fz, ft;
- float front[4];
- float back[4];
- float fvalue, bvalue, value[2], finalvalue;
-
- ix = ( int ) floor( x );
- fx = x - ix;
- iy = ( int ) floor( y );
- fy = y - iy;
- iz = ( int ) floor( z );
- fz = z - iz;
- it = ( int ) floor( t );
- ft = t - it;
-
- for ( i = 0; i < 2; i++ )
- {
- front[0] = GetNoiseValue( ix, iy, iz, it + i );
- front[1] = GetNoiseValue( ix+1, iy, iz, it + i );
- front[2] = GetNoiseValue( ix, iy+1, iz, it + i );
- front[3] = GetNoiseValue( ix+1, iy+1, iz, it + i );
-
- back[0] = GetNoiseValue( ix, iy, iz + 1, it + i );
- back[1] = GetNoiseValue( ix+1, iy, iz + 1, it + i );
- back[2] = GetNoiseValue( ix, iy+1, iz + 1, it + i );
- back[3] = GetNoiseValue( ix+1, iy+1, iz + 1, it + i );
-
- fvalue = LERP( LERP( front[0], front[1], fx ), LERP( front[2], front[3], fx ), fy );
- bvalue = LERP( LERP( back[0], back[1], fx ), LERP( back[2], back[3], fx ), fy );
-
- value[i] = LERP( fvalue, bvalue, fz );
- }
-
- finalvalue = LERP( value[0], value[1], ft );
-
- return finalvalue;
-}
diff --git a/engine/code/renderer/tr_public.h b/engine/code/renderer/tr_public.h
deleted file mode 100644
index c6846a9..0000000
--- a/engine/code/renderer/tr_public.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#ifndef __TR_PUBLIC_H
-#define __TR_PUBLIC_H
-
-#include "tr_types.h"
-
-#define REF_API_VERSION 8
-
-//
-// these are the functions exported by the refresh module
-//
-typedef struct {
- // called before the library is unloaded
- // if the system is just reconfiguring, pass destroyWindow = qfalse,
- // which will keep the screen from flashing to the desktop.
- void (*Shutdown)( qboolean destroyWindow );
-
- // All data that will be used in a level should be
- // registered before rendering any frames to prevent disk hits,
- // but they can still be registered at a later time
- // if necessary.
- //
- // BeginRegistration makes any existing media pointers invalid
- // and returns the current gl configuration, including screen width
- // and height, which can be used by the client to intelligently
- // size display elements
- void (*BeginRegistration)( glconfig_t *config );
- qhandle_t (*RegisterModel)( const char *name );
- qhandle_t (*RegisterSkin)( const char *name );
- qhandle_t (*RegisterShader)( const char *name );
- qhandle_t (*RegisterShaderNoMip)( const char *name );
- void (*LoadWorld)( const char *name );
-
- // the vis data is a large enough block of data that we go to the trouble
- // of sharing it with the clipmodel subsystem
- void (*SetWorldVisData)( const byte *vis );
-
- // EndRegistration will draw a tiny polygon with each texture, forcing
- // them to be loaded into card memory
- void (*EndRegistration)( void );
-
- // a scene is built up by calls to R_ClearScene and the various R_Add functions.
- // Nothing is drawn until R_RenderScene is called.
- void (*ClearScene)( void );
- void (*AddRefEntityToScene)( const refEntity_t *re );
- void (*AddPolyToScene)( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );
- int (*LightForPoint)( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
- void (*AddLightToScene)( const vec3_t org, float intensity, float r, float g, float b );
- void (*AddAdditiveLightToScene)( const vec3_t org, float intensity, float r, float g, float b );
- void (*RenderScene)( const refdef_t *fd );
-
- void (*SetColor)( const float *rgba ); // NULL = 1,1,1,1
- void (*DrawStretchPic) ( float x, float y, float w, float h,
- float s1, float t1, float s2, float t2, qhandle_t hShader ); // 0 = white
-
- // Draw images for cinematic rendering, pass as 32 bit rgba
- void (*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);
- void (*UploadCinematic) (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);
-
- void (*BeginFrame)( stereoFrame_t stereoFrame );
-
- // if the pointers are not NULL, timing info will be returned
- void (*EndFrame)( int *frontEndMsec, int *backEndMsec );
-
-
- int (*MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection,
- int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );
-
- int (*LerpTag)( orientation_t *tag, qhandle_t model, int startFrame, int endFrame,
- float frac, const char *tagName );
- void (*ModelBounds)( qhandle_t model, vec3_t mins, vec3_t maxs );
-
-#ifdef __USEA3D
- void (*A3D_RenderGeometry) (void *pVoidA3D, void *pVoidGeom, void *pVoidMat, void *pVoidGeomStatus);
-#endif
- void (*RegisterFont)(const char *fontName, int pointSize, fontInfo_t *font);
- void (*RemapShader)(const char *oldShader, const char *newShader, const char *offsetTime);
- qboolean (*GetEntityToken)( char *buffer, int size );
- qboolean (*inPVS)( const vec3_t p1, const vec3_t p2 );
-
- void (*TakeVideoFrame)( int h, int w, byte* captureBuffer, byte *encodeBuffer, qboolean motionJpeg );
-} refexport_t;
-
-//
-// these are the functions imported by the refresh module
-//
-typedef struct {
- // print message on the local console
- void (QDECL *Printf)( int printLevel, const char *fmt, ...);
-
- // abort the game
- void (QDECL *Error)( int errorLevel, const char *fmt, ...);
-
- // milliseconds should only be used for profiling, never
- // for anything game related. Get time from the refdef
- int (*Milliseconds)( void );
-
- // stack based memory allocation for per-level things that
- // won't be freed
-#ifdef HUNK_DEBUG
- void *(*Hunk_AllocDebug)( int size, ha_pref pref, char *label, char *file, int line );
-#else
- void *(*Hunk_Alloc)( int size, ha_pref pref );
-#endif
- void *(*Hunk_AllocateTempMemory)( int size );
- void (*Hunk_FreeTempMemory)( void *block );
-
- // dynamic memory allocator for things that need to be freed
- void *(*Malloc)( int bytes );
- void (*Free)( void *buf );
-
- cvar_t *(*Cvar_Get)( const char *name, const char *value, int flags );
- void (*Cvar_Set)( const char *name, const char *value );
- void (*Cvar_CheckRange)( cvar_t *cv, float minVal, float maxVal, qboolean shouldBeIntegral );
-
- void (*Cmd_AddCommand)( const char *name, void(*cmd)(void) );
- void (*Cmd_RemoveCommand)( const char *name );
-
- int (*Cmd_Argc) (void);
- char *(*Cmd_Argv) (int i);
-
- void (*Cmd_ExecuteText) (int exec_when, const char *text);
-
- // visualization for debugging collision detection
- void (*CM_DrawDebugSurface)( void (*drawPoly)(int color, int numPoints, float *points) );
-
- // a -1 return means the file does not exist
- // NULL can be passed for buf to just determine existance
- int (*FS_FileIsInPAK)( const char *name, int *pCheckSum );
- int (*FS_ReadFile)( const char *name, void **buf );
- void (*FS_FreeFile)( void *buf );
- char ** (*FS_ListFiles)( const char *name, const char *extension, int *numfilesfound );
- void (*FS_FreeFileList)( char **filelist );
- void (*FS_WriteFile)( const char *qpath, const void *buffer, int size );
- qboolean (*FS_FileExists)( const char *file );
-
- // cinematic stuff
- void (*CIN_UploadCinematic)(int handle);
- int (*CIN_PlayCinematic)( const char *arg0, int xpos, int ypos, int width, int height, int bits);
- e_status (*CIN_RunCinematic) (int handle);
-
- void (*CL_WriteAVIVideoFrame)( const byte *buffer, int size );
-} refimport_t;
-
-
-// this is the only function actually exported at the linker level
-// If the module can't init to a valid rendering state, NULL will be
-// returned.
-refexport_t*GetRefAPI( int apiVersion, refimport_t *rimp );
-
-#endif // __TR_PUBLIC_H
diff --git a/engine/code/renderer/tr_scene.c b/engine/code/renderer/tr_scene.c
deleted file mode 100644
index 970ac33..0000000
--- a/engine/code/renderer/tr_scene.c
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "tr_local.h"
-
-int r_firstSceneDrawSurf;
-
-int r_numdlights;
-int r_firstSceneDlight;
-
-int r_numentities;
-int r_firstSceneEntity;
-
-int r_numpolys;
-int r_firstScenePoly;
-
-int r_numpolyverts;
-
-
-/*
-====================
-R_ToggleSmpFrame
-
-====================
-*/
-void R_ToggleSmpFrame( void ) {
- if ( r_smp->integer ) {
- // use the other buffers next frame, because another CPU
- // may still be rendering into the current ones
- tr.smpFrame ^= 1;
- } else {
- tr.smpFrame = 0;
- }
-
- backEndData[tr.smpFrame]->commands.used = 0;
-
- r_firstSceneDrawSurf = 0;
-
- r_numdlights = 0;
- r_firstSceneDlight = 0;
-
- r_numentities = 0;
- r_firstSceneEntity = 0;
-
- r_numpolys = 0;
- r_firstScenePoly = 0;
-
- r_numpolyverts = 0;
-}
-
-
-/*
-====================
-RE_ClearScene
-
-====================
-*/
-void RE_ClearScene( void ) {
- r_firstSceneDlight = r_numdlights;
- r_firstSceneEntity = r_numentities;
- r_firstScenePoly = r_numpolys;
-}
-
-/*
-===========================================================================
-
-DISCRETE POLYS
-
-===========================================================================
-*/
-
-/*
-=====================
-R_AddPolygonSurfaces
-
-Adds all the scene's polys into this view's drawsurf list
-=====================
-*/
-void R_AddPolygonSurfaces( void ) {
- int i;
- shader_t *sh;
- srfPoly_t *poly;
-
- tr.currentEntityNum = ENTITYNUM_WORLD;
- tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT;
-
- for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) {
- sh = R_GetShaderByHandle( poly->hShader );
- R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse );
- }
-}
-
-/*
-=====================
-RE_AddPolyToScene
-
-=====================
-*/
-void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) {
- srfPoly_t *poly;
- int i, j;
- int fogIndex;
- fog_t *fog;
- vec3_t bounds[2];
-
- if ( !tr.registered ) {
- return;
- }
-
- if ( !hShader ) {
- ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n");
- return;
- }
-
- for ( j = 0; j < numPolys; j++ ) {
- if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) {
- /*
- NOTE TTimo this was initially a PRINT_WARNING
- but it happens a lot with high fighting scenes and particles
- since we don't plan on changing the const and making for room for those effects
- simply cut this message to developer only
- */
- ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n");
- return;
- }
-
- poly = &backEndData[tr.smpFrame]->polys[r_numpolys];
- poly->surfaceType = SF_POLY;
- poly->hShader = hShader;
- poly->numVerts = numVerts;
- poly->verts = &backEndData[tr.smpFrame]->polyVerts[r_numpolyverts];
-
- Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) );
-
- if ( glConfig.hardwareType == GLHW_RAGEPRO ) {
- poly->verts->modulate[0] = 255;
- poly->verts->modulate[1] = 255;
- poly->verts->modulate[2] = 255;
- poly->verts->modulate[3] = 255;
- }
- // done.
- r_numpolys++;
- r_numpolyverts += numVerts;
-
- // if no world is loaded
- if ( tr.world == NULL ) {
- fogIndex = 0;
- }
- // see if it is in a fog volume
- else if ( tr.world->numfogs == 1 ) {
- fogIndex = 0;
- } else {
- // find which fog volume the poly is in
- VectorCopy( poly->verts[0].xyz, bounds[0] );
- VectorCopy( poly->verts[0].xyz, bounds[1] );
- for ( i = 1 ; i < poly->numVerts ; i++ ) {
- AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
- }
- for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
- fog = &tr.world->fogs[fogIndex];
- if ( bounds[1][0] >= fog->bounds[0][0]
- && bounds[1][1] >= fog->bounds[0][1]
- && bounds[1][2] >= fog->bounds[0][2]
- && bounds[0][0] <= fog->bounds[1][0]
- && bounds[0][1] <= fog->bounds[1][1]
- && bounds[0][2] <= fog->bounds[1][2] ) {
- break;
- }
- }
- if ( fogIndex == tr.world->numfogs ) {
- fogIndex = 0;
- }
- }
- poly->fogIndex = fogIndex;
- }
-}
-
-
-//=================================================================================
-
-
-/*
-=====================
-RE_AddRefEntityToScene
-
-=====================
-*/
-void RE_AddRefEntityToScene( const refEntity_t *ent ) {
- if ( !tr.registered ) {
- return;
- }
- if ( r_numentities >= MAX_ENTITIES ) {
- return;
- }
- if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) {
- static qboolean firstTime = qtrue;
- if (firstTime) {
- firstTime = qfalse;
- Com_DPrintf(S_COLOR_YELLOW "WARNING: RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n");
- }
- return;
- }
- if ( ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) {
- ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType );
- }
-
- backEndData[tr.smpFrame]->entities[r_numentities].e = *ent;
- backEndData[tr.smpFrame]->entities[r_numentities].lightingCalculated = qfalse;
-
- r_numentities++;
-}
-
-
-/*
-=====================
-RE_AddDynamicLightToScene
-
-=====================
-*/
-void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) {
- dlight_t *dl;
-
- if ( !tr.registered ) {
- return;
- }
- if ( r_numdlights >= MAX_DLIGHTS ) {
- return;
- }
- if ( intensity <= 0 ) {
- return;
- }
- // these cards don't have the correct blend mode
- if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
- return;
- }
- dl = &backEndData[tr.smpFrame]->dlights[r_numdlights++];
- VectorCopy (org, dl->origin);
- dl->radius = intensity;
- dl->color[0] = r;
- dl->color[1] = g;
- dl->color[2] = b;
- dl->additive = additive;
-}
-
-/*
-=====================
-RE_AddLightToScene
-
-=====================
-*/
-void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
- RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse );
-}
-
-/*
-=====================
-RE_AddAdditiveLightToScene
-
-=====================
-*/
-void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
- RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue );
-}
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-RE_RenderScene
-
-Draw a 3D view into a part of the window, then return
-to 2D drawing.
-
-Rendering a scene may require multiple views to be rendered
-to handle mirrors,
-@@@@@@@@@@@@@@@@@@@@@
-*/
-void RE_RenderScene( const refdef_t *fd ) {
- viewParms_t parms;
- int startTime;
-
- if ( !tr.registered ) {
- return;
- }
- GLimp_LogComment( "====== RE_RenderScene =====\n" );
-
- if ( r_norefresh->integer ) {
- return;
- }
-
- startTime = ri.Milliseconds();
-
- if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
- ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
- }
-
- Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
-
- tr.refdef.x = fd->x;
- tr.refdef.y = fd->y;
- tr.refdef.width = fd->width;
- tr.refdef.height = fd->height;
- tr.refdef.fov_x = fd->fov_x;
- tr.refdef.fov_y = fd->fov_y;
-
- VectorCopy( fd->vieworg, tr.refdef.vieworg );
- VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] );
- VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] );
- VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] );
-
- tr.refdef.time = fd->time;
- tr.refdef.rdflags = fd->rdflags;
-
- // copy the areamask data over and note if it has changed, which
- // will force a reset of the visible leafs even if the view hasn't moved
- tr.refdef.areamaskModified = qfalse;
- if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) {
- int areaDiff;
- int i;
-
- // compare the area bits
- areaDiff = 0;
- for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) {
- areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i];
- ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i];
- }
-
- if ( areaDiff ) {
- // a door just opened or something
- tr.refdef.areamaskModified = qtrue;
- }
- }
-
-
- // derived info
-
- tr.refdef.floatTime = tr.refdef.time * 0.001f;
-
- tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
- tr.refdef.drawSurfs = backEndData[tr.smpFrame]->drawSurfs;
-
- tr.refdef.num_entities = r_numentities - r_firstSceneEntity;
- tr.refdef.entities = &backEndData[tr.smpFrame]->entities[r_firstSceneEntity];
-
- tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;
- tr.refdef.dlights = &backEndData[tr.smpFrame]->dlights[r_firstSceneDlight];
-
- tr.refdef.numPolys = r_numpolys - r_firstScenePoly;
- tr.refdef.polys = &backEndData[tr.smpFrame]->polys[r_firstScenePoly];
-
- // turn off dynamic lighting globally by clearing all the
- // dlights if it needs to be disabled or if vertex lighting is enabled
- if ( r_dynamiclight->integer == 0 ||
- r_vertexLight->integer == 1 ||
- glConfig.hardwareType == GLHW_PERMEDIA2 ) {
- tr.refdef.num_dlights = 0;
- }
-
- // a single frame may have multiple scenes draw inside it --
- // a 3D game view, 3D status bar renderings, 3D menus, etc.
- // They need to be distinguished by the light flare code, because
- // the visibility state for a given surface may be different in
- // each scene / view.
- tr.frameSceneNum++;
- tr.sceneCount++;
-
- // setup view parms for the initial view
- //
- // set up viewport
- // The refdef takes 0-at-the-top y coordinates, so
- // convert to GL's 0-at-the-bottom space
- //
- Com_Memset( &parms, 0, sizeof( parms ) );
- parms.viewportX = tr.refdef.x;
- parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );
- parms.viewportWidth = tr.refdef.width;
- parms.viewportHeight = tr.refdef.height;
- parms.isPortal = qfalse;
-
- parms.fovX = tr.refdef.fov_x;
- parms.fovY = tr.refdef.fov_y;
-
- parms.stereoFrame = tr.refdef.stereoFrame;
-
- VectorCopy( fd->vieworg, parms.or.origin );
- VectorCopy( fd->viewaxis[0], parms.or.axis[0] );
- VectorCopy( fd->viewaxis[1], parms.or.axis[1] );
- VectorCopy( fd->viewaxis[2], parms.or.axis[2] );
-
- VectorCopy( fd->vieworg, parms.pvsOrigin );
-
- R_RenderView( &parms );
-
- // the next scene rendered in this frame will tack on after this one
- r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
- r_firstSceneEntity = r_numentities;
- r_firstSceneDlight = r_numdlights;
- r_firstScenePoly = r_numpolys;
-
- tr.frontEndMsec += ri.Milliseconds() - startTime;
-}
diff --git a/engine/code/renderer/tr_shade.c b/engine/code/renderer/tr_shade.c
deleted file mode 100644
index 33a7f2b..0000000
--- a/engine/code/renderer/tr_shade.c
+++ /dev/null
@@ -1,1495 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_shade.c
-
-#include "tr_local.h"
-#if idppc_altivec && !defined(MACOS_X)
-#include <altivec.h>
-#endif
-
-/*
-
- THIS ENTIRE FILE IS BACK END
-
- This file deals with applying shaders to surface data in the tess struct.
-*/
-
-/*
-================
-R_ArrayElementDiscrete
-
-This is just for OpenGL conformance testing, it should never be the fastest
-================
-*/
-static void APIENTRY R_ArrayElementDiscrete( GLint index ) {
- qglColor4ubv( tess.svars.colors[ index ] );
- if ( glState.currenttmu ) {
- qglMultiTexCoord2fARB( 0, tess.svars.texcoords[ 0 ][ index ][0], tess.svars.texcoords[ 0 ][ index ][1] );
- qglMultiTexCoord2fARB( 1, tess.svars.texcoords[ 1 ][ index ][0], tess.svars.texcoords[ 1 ][ index ][1] );
- } else {
- qglTexCoord2fv( tess.svars.texcoords[ 0 ][ index ] );
- }
- qglVertex3fv( tess.xyz[ index ] );
-}
-
-/*
-===================
-R_DrawStripElements
-
-===================
-*/
-static int c_vertexes; // for seeing how long our average strips are
-static int c_begins;
-static void R_DrawStripElements( int numIndexes, const glIndex_t *indexes, void ( APIENTRY *element )(GLint) ) {
- int i;
- int last[3] = { -1, -1, -1 };
- qboolean even;
-
- c_begins++;
-
- if ( numIndexes <= 0 ) {
- return;
- }
-
- qglBegin( GL_TRIANGLE_STRIP );
-
- // prime the strip
- element( indexes[0] );
- element( indexes[1] );
- element( indexes[2] );
- c_vertexes += 3;
-
- last[0] = indexes[0];
- last[1] = indexes[1];
- last[2] = indexes[2];
-
- even = qfalse;
-
- for ( i = 3; i < numIndexes; i += 3 )
- {
- // odd numbered triangle in potential strip
- if ( !even )
- {
- // check previous triangle to see if we're continuing a strip
- if ( ( indexes[i+0] == last[2] ) && ( indexes[i+1] == last[1] ) )
- {
- element( indexes[i+2] );
- c_vertexes++;
- assert( indexes[i+2] < tess.numVertexes );
- even = qtrue;
- }
- // otherwise we're done with this strip so finish it and start
- // a new one
- else
- {
- qglEnd();
-
- qglBegin( GL_TRIANGLE_STRIP );
- c_begins++;
-
- element( indexes[i+0] );
- element( indexes[i+1] );
- element( indexes[i+2] );
-
- c_vertexes += 3;
-
- even = qfalse;
- }
- }
- else
- {
- // check previous triangle to see if we're continuing a strip
- if ( ( last[2] == indexes[i+1] ) && ( last[0] == indexes[i+0] ) )
- {
- element( indexes[i+2] );
- c_vertexes++;
-
- even = qfalse;
- }
- // otherwise we're done with this strip so finish it and start
- // a new one
- else
- {
- qglEnd();
-
- qglBegin( GL_TRIANGLE_STRIP );
- c_begins++;
-
- element( indexes[i+0] );
- element( indexes[i+1] );
- element( indexes[i+2] );
- c_vertexes += 3;
-
- even = qfalse;
- }
- }
-
- // cache the last three vertices
- last[0] = indexes[i+0];
- last[1] = indexes[i+1];
- last[2] = indexes[i+2];
- }
-
- qglEnd();
-}
-
-
-
-/*
-==================
-R_DrawElements
-
-Optionally performs our own glDrawElements that looks for strip conditions
-instead of using the single glDrawElements call that may be inefficient
-without compiled vertex arrays.
-==================
-*/
-static void R_DrawElements( int numIndexes, const glIndex_t *indexes ) {
- int primitives;
-
- primitives = r_primitives->integer;
-
- // default is to use triangles if compiled vertex arrays are present
- if ( primitives == 0 ) {
- if ( qglLockArraysEXT ) {
- primitives = 2;
- } else {
- primitives = 1;
- }
- }
-
-
- if ( primitives == 2 ) {
- qglDrawElements( GL_TRIANGLES,
- numIndexes,
- GL_INDEX_TYPE,
- indexes );
- return;
- }
-
- if ( primitives == 1 ) {
- R_DrawStripElements( numIndexes, indexes, qglArrayElement );
- return;
- }
-
- if ( primitives == 3 ) {
- R_DrawStripElements( numIndexes, indexes, R_ArrayElementDiscrete );
- return;
- }
-
- // anything else will cause no drawing
-}
-
-
-/*
-=============================================================
-
-SURFACE SHADERS
-
-=============================================================
-*/
-
-shaderCommands_t tess;
-static qboolean setArraysOnce;
-
-/*
-=================
-R_BindAnimatedImage
-
-=================
-*/
-static void R_BindAnimatedImage( textureBundle_t *bundle ) {
- int index;
-
- if ( bundle->isVideoMap ) {
- ri.CIN_RunCinematic(bundle->videoMapHandle);
- ri.CIN_UploadCinematic(bundle->videoMapHandle);
- return;
- }
-
- if ( bundle->numImageAnimations <= 1 ) {
- GL_Bind( bundle->image[0] );
- return;
- }
-
- // it is necessary to do this messy calc to make sure animations line up
- // exactly with waveforms of the same frequency
- index = myftol( tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE );
- index >>= FUNCTABLE_SIZE2;
-
- if ( index < 0 ) {
- index = 0; // may happen with shader time offsets
- }
- index %= bundle->numImageAnimations;
-
- GL_Bind( bundle->image[ index ] );
-}
-
-/*
-================
-DrawTris
-
-Draws triangle outlines for debugging
-================
-*/
-static void DrawTris (shaderCommands_t *input) {
- GL_Bind( tr.whiteImage );
- qglColor3f (1,1,1);
-
- GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
- qglDepthRange( 0, 0 );
-
- qglDisableClientState (GL_COLOR_ARRAY);
- qglDisableClientState (GL_TEXTURE_COORD_ARRAY);
-
- qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD
-
- if (qglLockArraysEXT) {
- qglLockArraysEXT(0, input->numVertexes);
- GLimp_LogComment( "glLockArraysEXT\n" );
- }
-
- R_DrawElements( input->numIndexes, input->indexes );
-
- if (qglUnlockArraysEXT) {
- qglUnlockArraysEXT();
- GLimp_LogComment( "glUnlockArraysEXT\n" );
- }
- qglDepthRange( 0, 1 );
-}
-
-
-/*
-================
-DrawNormals
-
-Draws vertex normals for debugging
-================
-*/
-static void DrawNormals (shaderCommands_t *input) {
- int i;
- vec3_t temp;
-
- GL_Bind( tr.whiteImage );
- qglColor3f (1,1,1);
- qglDepthRange( 0, 0 ); // never occluded
- GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
-
- qglBegin (GL_LINES);
- for (i = 0 ; i < input->numVertexes ; i++) {
- qglVertex3fv (input->xyz[i]);
- VectorMA (input->xyz[i], 2, input->normal[i], temp);
- qglVertex3fv (temp);
- }
- qglEnd ();
-
- qglDepthRange( 0, 1 );
-}
-
-/*
-==============
-RB_BeginSurface
-
-We must set some things up before beginning any tesselation,
-because a surface may be forced to perform a RB_End due
-to overflow.
-==============
-*/
-void RB_BeginSurface( shader_t *shader, int fogNum ) {
-
- shader_t *state = (shader->remappedShader) ? shader->remappedShader : shader;
-
- tess.numIndexes = 0;
- tess.numVertexes = 0;
- tess.shader = state;
- tess.fogNum = fogNum;
- tess.dlightBits = 0; // will be OR'd in by surface functions
- tess.xstages = state->stages;
- tess.numPasses = state->numUnfoggedPasses;
- tess.currentStageIteratorFunc = state->optimalStageIteratorFunc;
-
- tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
- if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) {
- tess.shaderTime = tess.shader->clampTime;
- }
-
-
-}
-
-/*
-===================
-DrawMultitextured
-
-output = t0 * t1 or t0 + t1
-
-t0 = most upstream according to spec
-t1 = most downstream according to spec
-===================
-*/
-static void DrawMultitextured( shaderCommands_t *input, int stage ) {
- shaderStage_t *pStage;
-
- pStage = tess.xstages[stage];
-
- GL_State( pStage->stateBits );
-
- // this is an ugly hack to work around a GeForce driver
- // bug with multitexture and clip planes
- if ( backEnd.viewParms.isPortal ) {
- qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
- }
-
- //
- // base
- //
- GL_SelectTexture( 0 );
- qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );
- R_BindAnimatedImage( &pStage->bundle[0] );
-
- //
- // lightmap/secondary pass
- //
- GL_SelectTexture( 1 );
- qglEnable( GL_TEXTURE_2D );
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
-
- if ( r_lightmap->integer ) {
- GL_TexEnv( GL_REPLACE );
- } else {
- GL_TexEnv( tess.shader->multitextureEnv );
- }
-
- qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[1] );
-
- R_BindAnimatedImage( &pStage->bundle[1] );
-
- R_DrawElements( input->numIndexes, input->indexes );
-
- //
- // disable texturing on TEXTURE1, then select TEXTURE0
- //
- //qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
- qglDisable( GL_TEXTURE_2D );
-
- GL_SelectTexture( 0 );
-}
-
-
-
-/*
-===================
-ProjectDlightTexture
-
-Perform dynamic lighting with another rendering pass
-===================
-*/
-#if idppc_altivec
-static void ProjectDlightTexture_altivec( void ) {
- int i, l;
- vec_t origin0, origin1, origin2;
- float texCoords0, texCoords1;
- vector float floatColorVec0, floatColorVec1;
- vector float modulateVec, colorVec, zero;
- vector short colorShort;
- vector signed int colorInt;
- vector unsigned char floatColorVecPerm, modulatePerm, colorChar;
- vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff);
- float *texCoords;
- byte *colors;
- byte clipBits[SHADER_MAX_VERTEXES];
- float texCoordsArray[SHADER_MAX_VERTEXES][2];
- byte colorArray[SHADER_MAX_VERTEXES][4];
- unsigned hitIndexes[SHADER_MAX_INDEXES];
- int numIndexes;
- float scale;
- float radius;
- vec3_t floatColor;
- float modulate = 0.0f;
-
- if ( !backEnd.refdef.num_dlights ) {
- return;
- }
-
- // There has to be a better way to do this so that floatColor
- // and/or modulate are already 16-byte aligned.
- floatColorVecPerm = vec_lvsl(0,(float *)floatColor);
- modulatePerm = vec_lvsl(0,(float *)&modulate);
- modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0);
- zero = (vector float)vec_splat_s8(0);
-
- for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
- dlight_t *dl;
-
- if ( !( tess.dlightBits & ( 1 << l ) ) ) {
- continue; // this surface definately doesn't have any of this light
- }
- texCoords = texCoordsArray[0];
- colors = colorArray[0];
-
- dl = &backEnd.refdef.dlights[l];
- origin0 = dl->transformed[0];
- origin1 = dl->transformed[1];
- origin2 = dl->transformed[2];
- radius = dl->radius;
- scale = 1.0f / radius;
-
- if(r_greyscale->integer)
- {
- float luminance;
-
- luminance = (dl->color[0] * 255.0f + dl->color[1] * 255.0f + dl->color[2] * 255.0f) / 3;
- floatColor[0] = floatColor[1] = floatColor[2] = luminance;
- }
- else
- {
- floatColor[0] = dl->color[0] * 255.0f;
- floatColor[1] = dl->color[1] * 255.0f;
- floatColor[2] = dl->color[2] * 255.0f;
- }
- floatColorVec0 = vec_ld(0, floatColor);
- floatColorVec1 = vec_ld(11, floatColor);
- floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm);
- for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
- int clip = 0;
- vec_t dist0, dist1, dist2;
-
- dist0 = origin0 - tess.xyz[i][0];
- dist1 = origin1 - tess.xyz[i][1];
- dist2 = origin2 - tess.xyz[i][2];
-
- backEnd.pc.c_dlightVertexes++;
-
- texCoords0 = 0.5f + dist0 * scale;
- texCoords1 = 0.5f + dist1 * scale;
-
- if( !r_dlightBacks->integer &&
- // dist . tess.normal[i]
- ( dist0 * tess.normal[i][0] +
- dist1 * tess.normal[i][1] +
- dist2 * tess.normal[i][2] ) < 0.0f ) {
- clip = 63;
- } else {
- if ( texCoords0 < 0.0f ) {
- clip |= 1;
- } else if ( texCoords0 > 1.0f ) {
- clip |= 2;
- }
- if ( texCoords1 < 0.0f ) {
- clip |= 4;
- } else if ( texCoords1 > 1.0f ) {
- clip |= 8;
- }
- texCoords[0] = texCoords0;
- texCoords[1] = texCoords1;
-
- // modulate the strength based on the height and color
- if ( dist2 > radius ) {
- clip |= 16;
- modulate = 0.0f;
- } else if ( dist2 < -radius ) {
- clip |= 32;
- modulate = 0.0f;
- } else {
- dist2 = Q_fabs(dist2);
- if ( dist2 < radius * 0.5f ) {
- modulate = 1.0f;
- } else {
- modulate = 2.0f * (radius - dist2) * scale;
- }
- }
- }
- clipBits[i] = clip;
-
- modulateVec = vec_ld(0,(float *)&modulate);
- modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm);
- colorVec = vec_madd(floatColorVec0,modulateVec,zero);
- colorInt = vec_cts(colorVec,0); // RGBx
- colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx
- colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx
- colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255
- vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color
- }
-
- // build a list of triangles that need light
- numIndexes = 0;
- for ( i = 0 ; i < tess.numIndexes ; i += 3 ) {
- int a, b, c;
-
- a = tess.indexes[i];
- b = tess.indexes[i+1];
- c = tess.indexes[i+2];
- if ( clipBits[a] & clipBits[b] & clipBits[c] ) {
- continue; // not lighted
- }
- hitIndexes[numIndexes] = a;
- hitIndexes[numIndexes+1] = b;
- hitIndexes[numIndexes+2] = c;
- numIndexes += 3;
- }
-
- if ( !numIndexes ) {
- continue;
- }
-
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );
-
- qglEnableClientState( GL_COLOR_ARRAY );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );
-
- GL_Bind( tr.dlightImage );
- // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
- // where they aren't rendered
- if ( dl->additive ) {
- GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
- }
- else {
- GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
- }
- R_DrawElements( numIndexes, hitIndexes );
- backEnd.pc.c_totalIndexes += numIndexes;
- backEnd.pc.c_dlightIndexes += numIndexes;
- }
-}
-#endif
-
-
-static void ProjectDlightTexture_scalar( void ) {
- int i, l;
- vec3_t origin;
- float *texCoords;
- byte *colors;
- byte clipBits[SHADER_MAX_VERTEXES];
- float texCoordsArray[SHADER_MAX_VERTEXES][2];
- byte colorArray[SHADER_MAX_VERTEXES][4];
- unsigned hitIndexes[SHADER_MAX_INDEXES];
- int numIndexes;
- float scale;
- float radius;
- vec3_t floatColor;
- float modulate = 0.0f;
-
- if ( !backEnd.refdef.num_dlights ) {
- return;
- }
-
- for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
- dlight_t *dl;
-
- if ( !( tess.dlightBits & ( 1 << l ) ) ) {
- continue; // this surface definately doesn't have any of this light
- }
- texCoords = texCoordsArray[0];
- colors = colorArray[0];
-
- dl = &backEnd.refdef.dlights[l];
- VectorCopy( dl->transformed, origin );
- radius = dl->radius;
- scale = 1.0f / radius;
-
- if(r_greyscale->integer)
- {
- float luminance;
-
- luminance = (dl->color[0] * 255.0f + dl->color[1] * 255.0f + dl->color[2] * 255.0f) / 3;
- floatColor[0] = floatColor[1] = floatColor[2] = luminance;
- }
- else
- {
- floatColor[0] = dl->color[0] * 255.0f;
- floatColor[1] = dl->color[1] * 255.0f;
- floatColor[2] = dl->color[2] * 255.0f;
- }
-
- for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
- int clip = 0;
- vec3_t dist;
-
- VectorSubtract( origin, tess.xyz[i], dist );
-
- backEnd.pc.c_dlightVertexes++;
-
- texCoords[0] = 0.5f + dist[0] * scale;
- texCoords[1] = 0.5f + dist[1] * scale;
-
- if( !r_dlightBacks->integer &&
- // dist . tess.normal[i]
- ( dist[0] * tess.normal[i][0] +
- dist[1] * tess.normal[i][1] +
- dist[2] * tess.normal[i][2] ) < 0.0f ) {
- clip = 63;
- } else {
- if ( texCoords[0] < 0.0f ) {
- clip |= 1;
- } else if ( texCoords[0] > 1.0f ) {
- clip |= 2;
- }
- if ( texCoords[1] < 0.0f ) {
- clip |= 4;
- } else if ( texCoords[1] > 1.0f ) {
- clip |= 8;
- }
- texCoords[0] = texCoords[0];
- texCoords[1] = texCoords[1];
-
- // modulate the strength based on the height and color
- if ( dist[2] > radius ) {
- clip |= 16;
- modulate = 0.0f;
- } else if ( dist[2] < -radius ) {
- clip |= 32;
- modulate = 0.0f;
- } else {
- dist[2] = Q_fabs(dist[2]);
- if ( dist[2] < radius * 0.5f ) {
- modulate = 1.0f;
- } else {
- modulate = 2.0f * (radius - dist[2]) * scale;
- }
- }
- }
- clipBits[i] = clip;
- colors[0] = myftol(floatColor[0] * modulate);
- colors[1] = myftol(floatColor[1] * modulate);
- colors[2] = myftol(floatColor[2] * modulate);
- colors[3] = 255;
- }
-
- // build a list of triangles that need light
- numIndexes = 0;
- for ( i = 0 ; i < tess.numIndexes ; i += 3 ) {
- int a, b, c;
-
- a = tess.indexes[i];
- b = tess.indexes[i+1];
- c = tess.indexes[i+2];
- if ( clipBits[a] & clipBits[b] & clipBits[c] ) {
- continue; // not lighted
- }
- hitIndexes[numIndexes] = a;
- hitIndexes[numIndexes+1] = b;
- hitIndexes[numIndexes+2] = c;
- numIndexes += 3;
- }
-
- if ( !numIndexes ) {
- continue;
- }
-
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );
-
- qglEnableClientState( GL_COLOR_ARRAY );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );
-
- GL_Bind( tr.dlightImage );
- // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
- // where they aren't rendered
- if ( dl->additive ) {
- GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
- }
- else {
- GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
- }
- R_DrawElements( numIndexes, hitIndexes );
- backEnd.pc.c_totalIndexes += numIndexes;
- backEnd.pc.c_dlightIndexes += numIndexes;
- }
-}
-
-static void ProjectDlightTexture( void ) {
-#if idppc_altivec
- if (com_altivec->integer) {
- // must be in a seperate function or G3 systems will crash.
- ProjectDlightTexture_altivec();
- return;
- }
-#endif
- ProjectDlightTexture_scalar();
-}
-
-
-/*
-===================
-RB_FogPass
-
-Blends a fog texture on top of everything else
-===================
-*/
-static void RB_FogPass( void ) {
- fog_t *fog;
- int i;
-
- qglEnableClientState( GL_COLOR_ARRAY );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
-
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
- qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );
-
- fog = tr.world->fogs + tess.fogNum;
-
- for ( i = 0; i < tess.numVertexes; i++ ) {
- * ( int * )&tess.svars.colors[i] = fog->colorInt;
- }
-
- RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[0] );
-
- GL_Bind( tr.fogImage );
-
- if ( tess.shader->fogPass == FP_EQUAL ) {
- GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );
- } else {
- GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
- }
-
- R_DrawElements( tess.numIndexes, tess.indexes );
-}
-
-/*
-===============
-ComputeColors
-===============
-*/
-static void ComputeColors( shaderStage_t *pStage )
-{
- int i;
-
- //
- // rgbGen
- //
- switch ( pStage->rgbGen )
- {
- case CGEN_IDENTITY:
- Com_Memset( tess.svars.colors, 0xff, tess.numVertexes * 4 );
- break;
- default:
- case CGEN_IDENTITY_LIGHTING:
- Com_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 );
- break;
- case CGEN_LIGHTING_DIFFUSE:
- RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors );
- break;
- case CGEN_EXACT_VERTEX:
- Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) );
- break;
- case CGEN_CONST:
- for ( i = 0; i < tess.numVertexes; i++ ) {
- *(int *)tess.svars.colors[i] = *(int *)pStage->constantColor;
- }
- break;
- case CGEN_VERTEX:
- if ( tr.identityLight == 1 )
- {
- Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) );
- }
- else
- {
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- tess.svars.colors[i][0] = tess.vertexColors[i][0] * tr.identityLight;
- tess.svars.colors[i][1] = tess.vertexColors[i][1] * tr.identityLight;
- tess.svars.colors[i][2] = tess.vertexColors[i][2] * tr.identityLight;
- tess.svars.colors[i][3] = tess.vertexColors[i][3];
- }
- }
- break;
- case CGEN_ONE_MINUS_VERTEX:
- if ( tr.identityLight == 1 )
- {
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- tess.svars.colors[i][0] = 255 - tess.vertexColors[i][0];
- tess.svars.colors[i][1] = 255 - tess.vertexColors[i][1];
- tess.svars.colors[i][2] = 255 - tess.vertexColors[i][2];
- }
- }
- else
- {
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- tess.svars.colors[i][0] = ( 255 - tess.vertexColors[i][0] ) * tr.identityLight;
- tess.svars.colors[i][1] = ( 255 - tess.vertexColors[i][1] ) * tr.identityLight;
- tess.svars.colors[i][2] = ( 255 - tess.vertexColors[i][2] ) * tr.identityLight;
- }
- }
- break;
- case CGEN_FOG:
- {
- fog_t *fog;
-
- fog = tr.world->fogs + tess.fogNum;
-
- for ( i = 0; i < tess.numVertexes; i++ ) {
- * ( int * )&tess.svars.colors[i] = fog->colorInt;
- }
- }
- break;
- case CGEN_WAVEFORM:
- RB_CalcWaveColor( &pStage->rgbWave, ( unsigned char * ) tess.svars.colors );
- break;
- case CGEN_ENTITY:
- RB_CalcColorFromEntity( ( unsigned char * ) tess.svars.colors );
- break;
- case CGEN_ONE_MINUS_ENTITY:
- RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors );
- break;
- }
-
- //
- // alphaGen
- //
- switch ( pStage->alphaGen )
- {
- case AGEN_SKIP:
- break;
- case AGEN_IDENTITY:
- if ( pStage->rgbGen != CGEN_IDENTITY ) {
- if ( ( pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1 ) ||
- pStage->rgbGen != CGEN_VERTEX ) {
- for ( i = 0; i < tess.numVertexes; i++ ) {
- tess.svars.colors[i][3] = 0xff;
- }
- }
- }
- break;
- case AGEN_CONST:
- if ( pStage->rgbGen != CGEN_CONST ) {
- for ( i = 0; i < tess.numVertexes; i++ ) {
- tess.svars.colors[i][3] = pStage->constantColor[3];
- }
- }
- break;
- case AGEN_WAVEFORM:
- RB_CalcWaveAlpha( &pStage->alphaWave, ( unsigned char * ) tess.svars.colors );
- break;
- case AGEN_LIGHTING_SPECULAR:
- RB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors );
- break;
- case AGEN_ENTITY:
- RB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors );
- break;
- case AGEN_ONE_MINUS_ENTITY:
- RB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors );
- break;
- case AGEN_VERTEX:
- if ( pStage->rgbGen != CGEN_VERTEX ) {
- for ( i = 0; i < tess.numVertexes; i++ ) {
- tess.svars.colors[i][3] = tess.vertexColors[i][3];
- }
- }
- break;
- case AGEN_ONE_MINUS_VERTEX:
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- tess.svars.colors[i][3] = 255 - tess.vertexColors[i][3];
- }
- break;
- case AGEN_PORTAL:
- {
- unsigned char alpha;
-
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- float len;
- vec3_t v;
-
- VectorSubtract( tess.xyz[i], backEnd.viewParms.or.origin, v );
- len = VectorLength( v );
-
- len /= tess.shader->portalRange;
-
- if ( len < 0 )
- {
- alpha = 0;
- }
- else if ( len > 1 )
- {
- alpha = 0xff;
- }
- else
- {
- alpha = len * 0xff;
- }
-
- tess.svars.colors[i][3] = alpha;
- }
- }
- break;
- }
-
- //
- // fog adjustment for colors to fade out as fog increases
- //
- if ( tess.fogNum )
- {
- switch ( pStage->adjustColorsForFog )
- {
- case ACFF_MODULATE_RGB:
- RB_CalcModulateColorsByFog( ( unsigned char * ) tess.svars.colors );
- break;
- case ACFF_MODULATE_ALPHA:
- RB_CalcModulateAlphasByFog( ( unsigned char * ) tess.svars.colors );
- break;
- case ACFF_MODULATE_RGBA:
- RB_CalcModulateRGBAsByFog( ( unsigned char * ) tess.svars.colors );
- break;
- case ACFF_NONE:
- break;
- }
- }
-
- // if in greyscale rendering mode turn all color values into greyscale.
- if(r_greyscale->integer)
- {
- int scale;
-
- for(i = 0; i < tess.numVertexes; i++)
- {
- scale = (tess.svars.colors[i][0] + tess.svars.colors[i][1] + tess.svars.colors[i][2]) / 3;
- tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale;
- }
- }
-}
-
-/*
-===============
-ComputeTexCoords
-===============
-*/
-static void ComputeTexCoords( shaderStage_t *pStage ) {
- int i;
- int b;
-
- for ( b = 0; b < NUM_TEXTURE_BUNDLES; b++ ) {
- int tm;
-
- //
- // generate the texture coordinates
- //
- switch ( pStage->bundle[b].tcGen )
- {
- case TCGEN_IDENTITY:
- Com_Memset( tess.svars.texcoords[b], 0, sizeof( float ) * 2 * tess.numVertexes );
- break;
- case TCGEN_TEXTURE:
- for ( i = 0 ; i < tess.numVertexes ; i++ ) {
- tess.svars.texcoords[b][i][0] = tess.texCoords[i][0][0];
- tess.svars.texcoords[b][i][1] = tess.texCoords[i][0][1];
- }
- break;
- case TCGEN_LIGHTMAP:
- for ( i = 0 ; i < tess.numVertexes ; i++ ) {
- tess.svars.texcoords[b][i][0] = tess.texCoords[i][1][0];
- tess.svars.texcoords[b][i][1] = tess.texCoords[i][1][1];
- }
- break;
- case TCGEN_VECTOR:
- for ( i = 0 ; i < tess.numVertexes ; i++ ) {
- tess.svars.texcoords[b][i][0] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[0] );
- tess.svars.texcoords[b][i][1] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[1] );
- }
- break;
- case TCGEN_FOG:
- RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[b] );
- break;
- case TCGEN_ENVIRONMENT_MAPPED:
- RB_CalcEnvironmentTexCoords( ( float * ) tess.svars.texcoords[b] );
- break;
- case TCGEN_BAD:
- return;
- }
-
- //
- // alter texture coordinates
- //
- for ( tm = 0; tm < pStage->bundle[b].numTexMods ; tm++ ) {
- switch ( pStage->bundle[b].texMods[tm].type )
- {
- case TMOD_NONE:
- tm = TR_MAX_TEXMODS; // break out of for loop
- break;
-
- case TMOD_TURBULENT:
- RB_CalcTurbulentTexCoords( &pStage->bundle[b].texMods[tm].wave,
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- case TMOD_ENTITY_TRANSLATE:
- RB_CalcScrollTexCoords( backEnd.currentEntity->e.shaderTexCoord,
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- case TMOD_SCROLL:
- RB_CalcScrollTexCoords( pStage->bundle[b].texMods[tm].scroll,
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- case TMOD_SCALE:
- RB_CalcScaleTexCoords( pStage->bundle[b].texMods[tm].scale,
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- case TMOD_STRETCH:
- RB_CalcStretchTexCoords( &pStage->bundle[b].texMods[tm].wave,
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- case TMOD_TRANSFORM:
- RB_CalcTransformTexCoords( &pStage->bundle[b].texMods[tm],
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- case TMOD_ROTATE:
- RB_CalcRotateTexCoords( pStage->bundle[b].texMods[tm].rotateSpeed,
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- default:
- ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'\n", pStage->bundle[b].texMods[tm].type, tess.shader->name );
- break;
- }
- }
- }
-}
-
-/*
-** RB_IterateStagesGeneric
-*/
-static void RB_IterateStagesGeneric( shaderCommands_t *input )
-{
- int stage;
-
- for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ )
- {
- shaderStage_t *pStage = tess.xstages[stage];
-
- if ( !pStage )
- {
- break;
- }
-
- ComputeColors( pStage );
- ComputeTexCoords( pStage );
-
- if ( !setArraysOnce )
- {
- qglEnableClientState( GL_COLOR_ARRAY );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors );
- }
-
- //
- // do multitexture
- //
- if ( pStage->bundle[1].image[0] != 0 )
- {
- DrawMultitextured( input, stage );
- }
- else
- {
- if ( !setArraysOnce )
- {
- qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );
- }
-
- //
- // set state
- //
- if ( pStage->bundle[0].vertexLightmap && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) && r_lightmap->integer )
- {
- GL_Bind( tr.whiteImage );
- }
- else
- R_BindAnimatedImage( &pStage->bundle[0] );
-
- GL_State( pStage->stateBits );
-
- //
- // draw
- //
- R_DrawElements( input->numIndexes, input->indexes );
- }
- // allow skipping out to show just lightmaps during development
- if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap ) )
- {
- break;
- }
- }
-}
-
-
-/*
-** RB_StageIteratorGeneric
-*/
-void RB_StageIteratorGeneric( void )
-{
- shaderCommands_t *input;
-
- input = &tess;
-
- RB_DeformTessGeometry();
-
- //
- // log this call
- //
- if ( r_logFile->integer )
- {
- // don't just call LogComment, or we will get
- // a call to va() every frame!
- GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) );
- }
-
- //
- // set face culling appropriately
- //
- GL_Cull( input->shader->cullType );
-
- // set polygon offset if necessary
- if ( input->shader->polygonOffset )
- {
- qglEnable( GL_POLYGON_OFFSET_FILL );
- qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value );
- }
-
- //
- // if there is only a single pass then we can enable color
- // and texture arrays before we compile, otherwise we need
- // to avoid compiling those arrays since they will change
- // during multipass rendering
- //
- if ( tess.numPasses > 1 || input->shader->multitextureEnv )
- {
- setArraysOnce = qfalse;
- qglDisableClientState (GL_COLOR_ARRAY);
- qglDisableClientState (GL_TEXTURE_COORD_ARRAY);
- }
- else
- {
- setArraysOnce = qtrue;
-
- qglEnableClientState( GL_COLOR_ARRAY);
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
-
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
- qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );
- }
-
- //
- // lock XYZ
- //
- qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD
- if (qglLockArraysEXT)
- {
- qglLockArraysEXT(0, input->numVertexes);
- GLimp_LogComment( "glLockArraysEXT\n" );
- }
-
- //
- // enable color and texcoord arrays after the lock if necessary
- //
- if ( !setArraysOnce )
- {
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- qglEnableClientState( GL_COLOR_ARRAY );
- }
-
- //
- // call shader function
- //
- RB_IterateStagesGeneric( input );
-
- //
- // now do any dynamic lighting needed
- //
- if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE
- && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) {
- ProjectDlightTexture();
- }
-
- //
- // now do fog
- //
- if ( tess.fogNum && tess.shader->fogPass ) {
- RB_FogPass();
- }
-
- //
- // unlock arrays
- //
- if (qglUnlockArraysEXT)
- {
- qglUnlockArraysEXT();
- GLimp_LogComment( "glUnlockArraysEXT\n" );
- }
-
- //
- // reset polygon offset
- //
- if ( input->shader->polygonOffset )
- {
- qglDisable( GL_POLYGON_OFFSET_FILL );
- }
-}
-
-
-/*
-** RB_StageIteratorVertexLitTexture
-*/
-void RB_StageIteratorVertexLitTexture( void )
-{
- shaderCommands_t *input;
- shader_t *shader;
-
- input = &tess;
-
- shader = input->shader;
-
- //
- // compute colors
- //
- RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors );
-
- //
- // log this call
- //
- if ( r_logFile->integer )
- {
- // don't just call LogComment, or we will get
- // a call to va() every frame!
- GLimp_LogComment( va("--- RB_StageIteratorVertexLitTexturedUnfogged( %s ) ---\n", tess.shader->name) );
- }
-
- //
- // set face culling appropriately
- //
- GL_Cull( input->shader->cullType );
-
- //
- // set arrays and lock
- //
- qglEnableClientState( GL_COLOR_ARRAY);
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
-
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
- qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] );
- qglVertexPointer (3, GL_FLOAT, 16, input->xyz);
-
- if ( qglLockArraysEXT )
- {
- qglLockArraysEXT(0, input->numVertexes);
- GLimp_LogComment( "glLockArraysEXT\n" );
- }
-
- //
- // call special shade routine
- //
- R_BindAnimatedImage( &tess.xstages[0]->bundle[0] );
- GL_State( tess.xstages[0]->stateBits );
- R_DrawElements( input->numIndexes, input->indexes );
-
- //
- // now do any dynamic lighting needed
- //
- if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) {
- ProjectDlightTexture();
- }
-
- //
- // now do fog
- //
- if ( tess.fogNum && tess.shader->fogPass ) {
- RB_FogPass();
- }
-
- //
- // unlock arrays
- //
- if (qglUnlockArraysEXT)
- {
- qglUnlockArraysEXT();
- GLimp_LogComment( "glUnlockArraysEXT\n" );
- }
-}
-
-//define REPLACE_MODE
-
-void RB_StageIteratorLightmappedMultitexture( void ) {
- shaderCommands_t *input;
-
- input = &tess;
-
- //
- // log this call
- //
- if ( r_logFile->integer ) {
- // don't just call LogComment, or we will get
- // a call to va() every frame!
- GLimp_LogComment( va("--- RB_StageIteratorLightmappedMultitexture( %s ) ---\n", tess.shader->name) );
- }
-
- //
- // set face culling appropriately
- //
- GL_Cull( input->shader->cullType );
-
- //
- // set color, pointers, and lock
- //
- GL_State( GLS_DEFAULT );
- qglVertexPointer( 3, GL_FLOAT, 16, input->xyz );
-
-#ifdef REPLACE_MODE
- qglDisableClientState( GL_COLOR_ARRAY );
- qglColor3f( 1, 1, 1 );
- qglShadeModel( GL_FLAT );
-#else
- qglEnableClientState( GL_COLOR_ARRAY );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.constantColor255 );
-#endif
-
- //
- // select base stage
- //
- GL_SelectTexture( 0 );
-
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- R_BindAnimatedImage( &tess.xstages[0]->bundle[0] );
- qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] );
-
- //
- // configure second stage
- //
- GL_SelectTexture( 1 );
- qglEnable( GL_TEXTURE_2D );
- if ( r_lightmap->integer ) {
- GL_TexEnv( GL_REPLACE );
- } else {
- GL_TexEnv( GL_MODULATE );
- }
- R_BindAnimatedImage( &tess.xstages[0]->bundle[1] );
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][1] );
-
- //
- // lock arrays
- //
- if ( qglLockArraysEXT ) {
- qglLockArraysEXT(0, input->numVertexes);
- GLimp_LogComment( "glLockArraysEXT\n" );
- }
-
- R_DrawElements( input->numIndexes, input->indexes );
-
- //
- // disable texturing on TEXTURE1, then select TEXTURE0
- //
- qglDisable( GL_TEXTURE_2D );
- qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
-
- GL_SelectTexture( 0 );
-#ifdef REPLACE_MODE
- GL_TexEnv( GL_MODULATE );
- qglShadeModel( GL_SMOOTH );
-#endif
-
- //
- // now do any dynamic lighting needed
- //
- if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) {
- ProjectDlightTexture();
- }
-
- //
- // now do fog
- //
- if ( tess.fogNum && tess.shader->fogPass ) {
- RB_FogPass();
- }
-
- //
- // unlock arrays
- //
- if ( qglUnlockArraysEXT ) {
- qglUnlockArraysEXT();
- GLimp_LogComment( "glUnlockArraysEXT\n" );
- }
-}
-
-/*
-** RB_EndSurface
-*/
-void RB_EndSurface( void ) {
- shaderCommands_t *input;
-
- input = &tess;
-
- if (input->numIndexes == 0) {
- return;
- }
-
- if (input->indexes[SHADER_MAX_INDEXES-1] != 0) {
- ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_INDEXES hit");
- }
- if (input->xyz[SHADER_MAX_VERTEXES-1][0] != 0) {
- ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_VERTEXES hit");
- }
-
- if ( tess.shader == tr.shadowShader ) {
- RB_ShadowTessEnd();
- return;
- }
-
- // for debugging of sort order issues, stop rendering after a given sort value
- if ( r_debugSort->integer && r_debugSort->integer < tess.shader->sort ) {
- return;
- }
-
- //
- // update performance counters
- //
- backEnd.pc.c_shaders++;
- backEnd.pc.c_vertexes += tess.numVertexes;
- backEnd.pc.c_indexes += tess.numIndexes;
- backEnd.pc.c_totalIndexes += tess.numIndexes * tess.numPasses;
-
- //
- // call off to shader specific tess end function
- //
- tess.currentStageIteratorFunc();
-
- //
- // draw debugging stuff
- //
- if ( r_showtris->integer ) {
- DrawTris (input);
- }
- if ( r_shownormals->integer ) {
- DrawNormals (input);
- }
- // clear shader so we can tell we don't have any unclosed surfaces
- tess.numIndexes = 0;
-
- GLimp_LogComment( "----------\n" );
-}
-
diff --git a/engine/code/renderer/tr_shade_calc.c b/engine/code/renderer/tr_shade_calc.c
deleted file mode 100644
index 6f9b0be..0000000
--- a/engine/code/renderer/tr_shade_calc.c
+++ /dev/null
@@ -1,1231 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_shade_calc.c
-
-#include "tr_local.h"
-#if idppc_altivec && !defined(MACOS_X)
-#include <altivec.h>
-#endif
-
-
-#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ myftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude))
-
-static float *TableForFunc( genFunc_t func )
-{
- switch ( func )
- {
- case GF_SIN:
- return tr.sinTable;
- case GF_TRIANGLE:
- return tr.triangleTable;
- case GF_SQUARE:
- return tr.squareTable;
- case GF_SAWTOOTH:
- return tr.sawToothTable;
- case GF_INVERSE_SAWTOOTH:
- return tr.inverseSawToothTable;
- case GF_NONE:
- default:
- break;
- }
-
- ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'\n", func, tess.shader->name );
- return NULL;
-}
-
-/*
-** EvalWaveForm
-**
-** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly
-*/
-static float EvalWaveForm( const waveForm_t *wf )
-{
- float *table;
-
- table = TableForFunc( wf->func );
-
- return WAVEVALUE( table, wf->base, wf->amplitude, wf->phase, wf->frequency );
-}
-
-static float EvalWaveFormClamped( const waveForm_t *wf )
-{
- float glow = EvalWaveForm( wf );
-
- if ( glow < 0 )
- {
- return 0;
- }
-
- if ( glow > 1 )
- {
- return 1;
- }
-
- return glow;
-}
-
-/*
-** RB_CalcStretchTexCoords
-*/
-void RB_CalcStretchTexCoords( const waveForm_t *wf, float *st )
-{
- float p;
- texModInfo_t tmi;
-
- p = 1.0f / EvalWaveForm( wf );
-
- tmi.matrix[0][0] = p;
- tmi.matrix[1][0] = 0;
- tmi.translate[0] = 0.5f - 0.5f * p;
-
- tmi.matrix[0][1] = 0;
- tmi.matrix[1][1] = p;
- tmi.translate[1] = 0.5f - 0.5f * p;
-
- RB_CalcTransformTexCoords( &tmi, st );
-}
-
-/*
-====================================================================
-
-DEFORMATIONS
-
-====================================================================
-*/
-
-/*
-========================
-RB_CalcDeformVertexes
-
-========================
-*/
-void RB_CalcDeformVertexes( deformStage_t *ds )
-{
- int i;
- vec3_t offset;
- float scale;
- float *xyz = ( float * ) tess.xyz;
- float *normal = ( float * ) tess.normal;
- float *table;
-
- if ( ds->deformationWave.frequency == 0 )
- {
- scale = EvalWaveForm( &ds->deformationWave );
-
- for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
- {
- VectorScale( normal, scale, offset );
-
- xyz[0] += offset[0];
- xyz[1] += offset[1];
- xyz[2] += offset[2];
- }
- }
- else
- {
- table = TableForFunc( ds->deformationWave.func );
-
- for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
- {
- float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;
-
- scale = WAVEVALUE( table, ds->deformationWave.base,
- ds->deformationWave.amplitude,
- ds->deformationWave.phase + off,
- ds->deformationWave.frequency );
-
- VectorScale( normal, scale, offset );
-
- xyz[0] += offset[0];
- xyz[1] += offset[1];
- xyz[2] += offset[2];
- }
- }
-}
-
-/*
-=========================
-RB_CalcDeformNormals
-
-Wiggle the normals for wavy environment mapping
-=========================
-*/
-void RB_CalcDeformNormals( deformStage_t *ds ) {
- int i;
- float scale;
- float *xyz = ( float * ) tess.xyz;
- float *normal = ( float * ) tess.normal;
-
- for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) {
- scale = 0.98f;
- scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
- tess.shaderTime * ds->deformationWave.frequency );
- normal[ 0 ] += ds->deformationWave.amplitude * scale;
-
- scale = 0.98f;
- scale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
- tess.shaderTime * ds->deformationWave.frequency );
- normal[ 1 ] += ds->deformationWave.amplitude * scale;
-
- scale = 0.98f;
- scale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
- tess.shaderTime * ds->deformationWave.frequency );
- normal[ 2 ] += ds->deformationWave.amplitude * scale;
-
- VectorNormalizeFast( normal );
- }
-}
-
-/*
-========================
-RB_CalcBulgeVertexes
-
-========================
-*/
-void RB_CalcBulgeVertexes( deformStage_t *ds ) {
- int i;
- const float *st = ( const float * ) tess.texCoords[0];
- float *xyz = ( float * ) tess.xyz;
- float *normal = ( float * ) tess.normal;
- float now;
-
- now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f;
-
- for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal += 4 ) {
- int off;
- float scale;
-
- off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now );
-
- scale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight;
-
- xyz[0] += normal[0] * scale;
- xyz[1] += normal[1] * scale;
- xyz[2] += normal[2] * scale;
- }
-}
-
-
-/*
-======================
-RB_CalcMoveVertexes
-
-A deformation that can move an entire surface along a wave path
-======================
-*/
-void RB_CalcMoveVertexes( deformStage_t *ds ) {
- int i;
- float *xyz;
- float *table;
- float scale;
- vec3_t offset;
-
- table = TableForFunc( ds->deformationWave.func );
-
- scale = WAVEVALUE( table, ds->deformationWave.base,
- ds->deformationWave.amplitude,
- ds->deformationWave.phase,
- ds->deformationWave.frequency );
-
- VectorScale( ds->moveVector, scale, offset );
-
- xyz = ( float * ) tess.xyz;
- for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
- VectorAdd( xyz, offset, xyz );
- }
-}
-
-
-/*
-=============
-DeformText
-
-Change a polygon into a bunch of text polygons
-=============
-*/
-void DeformText( const char *text ) {
- int i;
- vec3_t origin, width, height;
- int len;
- int ch;
- byte color[4];
- float bottom, top;
- vec3_t mid;
-
- height[0] = 0;
- height[1] = 0;
- height[2] = -1;
- CrossProduct( tess.normal[0], height, width );
-
- // find the midpoint of the box
- VectorClear( mid );
- bottom = 999999;
- top = -999999;
- for ( i = 0 ; i < 4 ; i++ ) {
- VectorAdd( tess.xyz[i], mid, mid );
- if ( tess.xyz[i][2] < bottom ) {
- bottom = tess.xyz[i][2];
- }
- if ( tess.xyz[i][2] > top ) {
- top = tess.xyz[i][2];
- }
- }
- VectorScale( mid, 0.25f, origin );
-
- // determine the individual character size
- height[0] = 0;
- height[1] = 0;
- height[2] = ( top - bottom ) * 0.5f;
-
- VectorScale( width, height[2] * -0.75f, width );
-
- // determine the starting position
- len = strlen( text );
- VectorMA( origin, (len-1), width, origin );
-
- // clear the shader indexes
- tess.numIndexes = 0;
- tess.numVertexes = 0;
-
- color[0] = color[1] = color[2] = color[3] = 255;
-
- // draw each character
- for ( i = 0 ; i < len ; i++ ) {
- ch = text[i];
- ch &= 255;
-
- if ( ch != ' ' ) {
- int row, col;
- float frow, fcol, size;
-
- row = ch>>4;
- col = ch&15;
-
- frow = row*0.0625f;
- fcol = col*0.0625f;
- size = 0.0625f;
-
- RB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size );
- }
- VectorMA( origin, -2, width, origin );
- }
-}
-
-/*
-==================
-GlobalVectorToLocal
-==================
-*/
-static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) {
- out[0] = DotProduct( in, backEnd.or.axis[0] );
- out[1] = DotProduct( in, backEnd.or.axis[1] );
- out[2] = DotProduct( in, backEnd.or.axis[2] );
-}
-
-/*
-=====================
-AutospriteDeform
-
-Assuming all the triangles for this shader are independant
-quads, rebuild them as forward facing sprites
-=====================
-*/
-static void AutospriteDeform( void ) {
- int i;
- int oldVerts;
- float *xyz;
- vec3_t mid, delta;
- float radius;
- vec3_t left, up;
- vec3_t leftDir, upDir;
-
- if ( tess.numVertexes & 3 ) {
- ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count", tess.shader->name );
- }
- if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
- ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count", tess.shader->name );
- }
-
- oldVerts = tess.numVertexes;
- tess.numVertexes = 0;
- tess.numIndexes = 0;
-
- if ( backEnd.currentEntity != &tr.worldEntity ) {
- GlobalVectorToLocal( backEnd.viewParms.or.axis[1], leftDir );
- GlobalVectorToLocal( backEnd.viewParms.or.axis[2], upDir );
- } else {
- VectorCopy( backEnd.viewParms.or.axis[1], leftDir );
- VectorCopy( backEnd.viewParms.or.axis[2], upDir );
- }
-
- for ( i = 0 ; i < oldVerts ; i+=4 ) {
- // find the midpoint
- xyz = tess.xyz[i];
-
- mid[0] = 0.25f * (xyz[0] + xyz[4] + xyz[8] + xyz[12]);
- mid[1] = 0.25f * (xyz[1] + xyz[5] + xyz[9] + xyz[13]);
- mid[2] = 0.25f * (xyz[2] + xyz[6] + xyz[10] + xyz[14]);
-
- VectorSubtract( xyz, mid, delta );
- radius = VectorLength( delta ) * 0.707f; // / sqrt(2)
-
- VectorScale( leftDir, radius, left );
- VectorScale( upDir, radius, up );
-
- if ( backEnd.viewParms.isMirror ) {
- VectorSubtract( vec3_origin, left, left );
- }
-
- // compensate for scale in the axes if necessary
- if ( backEnd.currentEntity->e.nonNormalizedAxes ) {
- float axisLength;
- axisLength = VectorLength( backEnd.currentEntity->e.axis[0] );
- if ( !axisLength ) {
- axisLength = 0;
- } else {
- axisLength = 1.0f / axisLength;
- }
- VectorScale(left, axisLength, left);
- VectorScale(up, axisLength, up);
- }
-
- RB_AddQuadStamp( mid, left, up, tess.vertexColors[i] );
- }
-}
-
-
-/*
-=====================
-Autosprite2Deform
-
-Autosprite2 will pivot a rectangular quad along the center of its long axis
-=====================
-*/
-int edgeVerts[6][2] = {
- { 0, 1 },
- { 0, 2 },
- { 0, 3 },
- { 1, 2 },
- { 1, 3 },
- { 2, 3 }
-};
-
-static void Autosprite2Deform( void ) {
- int i, j, k;
- int indexes;
- float *xyz;
- vec3_t forward;
-
- if ( tess.numVertexes & 3 ) {
- ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count", tess.shader->name );
- }
- if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
- ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count", tess.shader->name );
- }
-
- if ( backEnd.currentEntity != &tr.worldEntity ) {
- GlobalVectorToLocal( backEnd.viewParms.or.axis[0], forward );
- } else {
- VectorCopy( backEnd.viewParms.or.axis[0], forward );
- }
-
- // this is a lot of work for two triangles...
- // we could precalculate a lot of it is an issue, but it would mess up
- // the shader abstraction
- for ( i = 0, indexes = 0 ; i < tess.numVertexes ; i+=4, indexes+=6 ) {
- float lengths[2];
- int nums[2];
- vec3_t mid[2];
- vec3_t major, minor;
- float *v1, *v2;
-
- // find the midpoint
- xyz = tess.xyz[i];
-
- // identify the two shortest edges
- nums[0] = nums[1] = 0;
- lengths[0] = lengths[1] = 999999;
-
- for ( j = 0 ; j < 6 ; j++ ) {
- float l;
- vec3_t temp;
-
- v1 = xyz + 4 * edgeVerts[j][0];
- v2 = xyz + 4 * edgeVerts[j][1];
-
- VectorSubtract( v1, v2, temp );
-
- l = DotProduct( temp, temp );
- if ( l < lengths[0] ) {
- nums[1] = nums[0];
- lengths[1] = lengths[0];
- nums[0] = j;
- lengths[0] = l;
- } else if ( l < lengths[1] ) {
- nums[1] = j;
- lengths[1] = l;
- }
- }
-
- for ( j = 0 ; j < 2 ; j++ ) {
- v1 = xyz + 4 * edgeVerts[nums[j]][0];
- v2 = xyz + 4 * edgeVerts[nums[j]][1];
-
- mid[j][0] = 0.5f * (v1[0] + v2[0]);
- mid[j][1] = 0.5f * (v1[1] + v2[1]);
- mid[j][2] = 0.5f * (v1[2] + v2[2]);
- }
-
- // find the vector of the major axis
- VectorSubtract( mid[1], mid[0], major );
-
- // cross this with the view direction to get minor axis
- CrossProduct( major, forward, minor );
- VectorNormalize( minor );
-
- // re-project the points
- for ( j = 0 ; j < 2 ; j++ ) {
- float l;
-
- v1 = xyz + 4 * edgeVerts[nums[j]][0];
- v2 = xyz + 4 * edgeVerts[nums[j]][1];
-
- l = 0.5 * sqrt( lengths[j] );
-
- // we need to see which direction this edge
- // is used to determine direction of projection
- for ( k = 0 ; k < 5 ; k++ ) {
- if ( tess.indexes[ indexes + k ] == i + edgeVerts[nums[j]][0]
- && tess.indexes[ indexes + k + 1 ] == i + edgeVerts[nums[j]][1] ) {
- break;
- }
- }
-
- if ( k == 5 ) {
- VectorMA( mid[j], l, minor, v1 );
- VectorMA( mid[j], -l, minor, v2 );
- } else {
- VectorMA( mid[j], -l, minor, v1 );
- VectorMA( mid[j], l, minor, v2 );
- }
- }
- }
-}
-
-
-/*
-=====================
-RB_DeformTessGeometry
-
-=====================
-*/
-void RB_DeformTessGeometry( void ) {
- int i;
- deformStage_t *ds;
-
- for ( i = 0 ; i < tess.shader->numDeforms ; i++ ) {
- ds = &tess.shader->deforms[ i ];
-
- switch ( ds->deformation ) {
- case DEFORM_NONE:
- break;
- case DEFORM_NORMALS:
- RB_CalcDeformNormals( ds );
- break;
- case DEFORM_WAVE:
- RB_CalcDeformVertexes( ds );
- break;
- case DEFORM_BULGE:
- RB_CalcBulgeVertexes( ds );
- break;
- case DEFORM_MOVE:
- RB_CalcMoveVertexes( ds );
- break;
- case DEFORM_PROJECTION_SHADOW:
- RB_ProjectionShadowDeform();
- break;
- case DEFORM_AUTOSPRITE:
- AutospriteDeform();
- break;
- case DEFORM_AUTOSPRITE2:
- Autosprite2Deform();
- break;
- case DEFORM_TEXT0:
- case DEFORM_TEXT1:
- case DEFORM_TEXT2:
- case DEFORM_TEXT3:
- case DEFORM_TEXT4:
- case DEFORM_TEXT5:
- case DEFORM_TEXT6:
- case DEFORM_TEXT7:
- DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] );
- break;
- }
- }
-}
-
-/*
-====================================================================
-
-COLORS
-
-====================================================================
-*/
-
-
-/*
-** RB_CalcColorFromEntity
-*/
-void RB_CalcColorFromEntity( unsigned char *dstColors )
-{
- int i;
- int *pColors = ( int * ) dstColors;
- int c;
-
- if ( !backEnd.currentEntity )
- return;
-
- c = * ( int * ) backEnd.currentEntity->e.shaderRGBA;
-
- for ( i = 0; i < tess.numVertexes; i++, pColors++ )
- {
- *pColors = c;
- }
-}
-
-/*
-** RB_CalcColorFromOneMinusEntity
-*/
-void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors )
-{
- int i;
- int *pColors = ( int * ) dstColors;
- unsigned char invModulate[4];
- int c;
-
- if ( !backEnd.currentEntity )
- return;
-
- invModulate[0] = 255 - backEnd.currentEntity->e.shaderRGBA[0];
- invModulate[1] = 255 - backEnd.currentEntity->e.shaderRGBA[1];
- invModulate[2] = 255 - backEnd.currentEntity->e.shaderRGBA[2];
- invModulate[3] = 255 - backEnd.currentEntity->e.shaderRGBA[3]; // this trashes alpha, but the AGEN block fixes it
-
- c = * ( int * ) invModulate;
-
- for ( i = 0; i < tess.numVertexes; i++, pColors++ )
- {
- *pColors = * ( int * ) invModulate;
- }
-}
-
-/*
-** RB_CalcAlphaFromEntity
-*/
-void RB_CalcAlphaFromEntity( unsigned char *dstColors )
-{
- int i;
-
- if ( !backEnd.currentEntity )
- return;
-
- dstColors += 3;
-
- for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )
- {
- *dstColors = backEnd.currentEntity->e.shaderRGBA[3];
- }
-}
-
-/*
-** RB_CalcAlphaFromOneMinusEntity
-*/
-void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors )
-{
- int i;
-
- if ( !backEnd.currentEntity )
- return;
-
- dstColors += 3;
-
- for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )
- {
- *dstColors = 0xff - backEnd.currentEntity->e.shaderRGBA[3];
- }
-}
-
-/*
-** RB_CalcWaveColor
-*/
-void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors )
-{
- int i;
- int v;
- float glow;
- int *colors = ( int * ) dstColors;
- byte color[4];
-
-
- if ( wf->func == GF_NOISE ) {
- glow = wf->base + R_NoiseGet4f( 0, 0, 0, ( tess.shaderTime + wf->phase ) * wf->frequency ) * wf->amplitude;
- } else {
- glow = EvalWaveForm( wf ) * tr.identityLight;
- }
-
- if ( glow < 0 ) {
- glow = 0;
- }
- else if ( glow > 1 ) {
- glow = 1;
- }
-
- v = myftol( 255 * glow );
- color[0] = color[1] = color[2] = v;
- color[3] = 255;
- v = *(int *)color;
-
- for ( i = 0; i < tess.numVertexes; i++, colors++ ) {
- *colors = v;
- }
-}
-
-/*
-** RB_CalcWaveAlpha
-*/
-void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors )
-{
- int i;
- int v;
- float glow;
-
- glow = EvalWaveFormClamped( wf );
-
- v = 255 * glow;
-
- for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )
- {
- dstColors[3] = v;
- }
-}
-
-/*
-** RB_CalcModulateColorsByFog
-*/
-void RB_CalcModulateColorsByFog( unsigned char *colors ) {
- int i;
- float texCoords[SHADER_MAX_VERTEXES][2];
-
- // calculate texcoords so we can derive density
- // this is not wasted, because it would only have
- // been previously called if the surface was opaque
- RB_CalcFogTexCoords( texCoords[0] );
-
- for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
- float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
- colors[0] *= f;
- colors[1] *= f;
- colors[2] *= f;
- }
-}
-
-/*
-** RB_CalcModulateAlphasByFog
-*/
-void RB_CalcModulateAlphasByFog( unsigned char *colors ) {
- int i;
- float texCoords[SHADER_MAX_VERTEXES][2];
-
- // calculate texcoords so we can derive density
- // this is not wasted, because it would only have
- // been previously called if the surface was opaque
- RB_CalcFogTexCoords( texCoords[0] );
-
- for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
- float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
- colors[3] *= f;
- }
-}
-
-/*
-** RB_CalcModulateRGBAsByFog
-*/
-void RB_CalcModulateRGBAsByFog( unsigned char *colors ) {
- int i;
- float texCoords[SHADER_MAX_VERTEXES][2];
-
- // calculate texcoords so we can derive density
- // this is not wasted, because it would only have
- // been previously called if the surface was opaque
- RB_CalcFogTexCoords( texCoords[0] );
-
- for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
- float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
- colors[0] *= f;
- colors[1] *= f;
- colors[2] *= f;
- colors[3] *= f;
- }
-}
-
-
-/*
-====================================================================
-
-TEX COORDS
-
-====================================================================
-*/
-
-/*
-========================
-RB_CalcFogTexCoords
-
-To do the clipped fog plane really correctly, we should use
-projected textures, but I don't trust the drivers and it
-doesn't fit our shader data.
-========================
-*/
-void RB_CalcFogTexCoords( float *st ) {
- int i;
- float *v;
- float s, t;
- float eyeT;
- qboolean eyeOutside;
- fog_t *fog;
- vec3_t local;
- vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
-
- fog = tr.world->fogs + tess.fogNum;
-
- // all fogging distance is based on world Z units
- VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local );
- fogDistanceVector[0] = -backEnd.or.modelMatrix[2];
- fogDistanceVector[1] = -backEnd.or.modelMatrix[6];
- fogDistanceVector[2] = -backEnd.or.modelMatrix[10];
- fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] );
-
- // scale the fog vectors based on the fog's thickness
- fogDistanceVector[0] *= fog->tcScale;
- fogDistanceVector[1] *= fog->tcScale;
- fogDistanceVector[2] *= fog->tcScale;
- fogDistanceVector[3] *= fog->tcScale;
-
- // rotate the gradient vector for this orientation
- if ( fog->hasSurface ) {
- fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] +
- fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2];
- fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] +
- fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2];
- fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] +
- fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2];
- fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface );
-
- eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3];
- } else {
- eyeT = 1; // non-surface fog always has eye inside
- }
-
- // see if the viewpoint is outside
- // this is needed for clipping distance even for constant fog
-
- if ( eyeT < 0 ) {
- eyeOutside = qtrue;
- } else {
- eyeOutside = qfalse;
- }
-
- fogDistanceVector[3] += 1.0/512;
-
- // calculate density for each point
- for (i = 0, v = tess.xyz[0] ; i < tess.numVertexes ; i++, v += 4) {
- // calculate the length in fog
- s = DotProduct( v, fogDistanceVector ) + fogDistanceVector[3];
- t = DotProduct( v, fogDepthVector ) + fogDepthVector[3];
-
- // partially clipped fogs use the T axis
- if ( eyeOutside ) {
- if ( t < 1.0 ) {
- t = 1.0/32; // point is outside, so no fogging
- } else {
- t = 1.0/32 + 30.0/32 * t / ( t - eyeT ); // cut the distance at the fog plane
- }
- } else {
- if ( t < 0 ) {
- t = 1.0/32; // point is outside, so no fogging
- } else {
- t = 31.0/32;
- }
- }
-
- st[0] = s;
- st[1] = t;
- st += 2;
- }
-}
-
-
-
-/*
-** RB_CalcEnvironmentTexCoords
-*/
-void RB_CalcEnvironmentTexCoords( float *st )
-{
- int i;
- float *v, *normal;
- vec3_t viewer, reflected;
- float d;
-
- v = tess.xyz[0];
- normal = tess.normal[0];
-
- for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 )
- {
- VectorSubtract (backEnd.or.viewOrigin, v, viewer);
- VectorNormalizeFast (viewer);
-
- d = DotProduct (normal, viewer);
-
- reflected[0] = normal[0]*2*d - viewer[0];
- reflected[1] = normal[1]*2*d - viewer[1];
- reflected[2] = normal[2]*2*d - viewer[2];
-
- st[0] = 0.5 + reflected[1] * 0.5;
- st[1] = 0.5 - reflected[2] * 0.5;
- }
-}
-
-/*
-** RB_CalcTurbulentTexCoords
-*/
-void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st )
-{
- int i;
- float now;
-
- now = ( wf->phase + tess.shaderTime * wf->frequency );
-
- for ( i = 0; i < tess.numVertexes; i++, st += 2 )
- {
- float s = st[0];
- float t = st[1];
-
- st[0] = s + tr.sinTable[ ( ( int ) ( ( ( tess.xyz[i][0] + tess.xyz[i][2] )* 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude;
- st[1] = t + tr.sinTable[ ( ( int ) ( ( tess.xyz[i][1] * 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude;
- }
-}
-
-/*
-** RB_CalcScaleTexCoords
-*/
-void RB_CalcScaleTexCoords( const float scale[2], float *st )
-{
- int i;
-
- for ( i = 0; i < tess.numVertexes; i++, st += 2 )
- {
- st[0] *= scale[0];
- st[1] *= scale[1];
- }
-}
-
-/*
-** RB_CalcScrollTexCoords
-*/
-void RB_CalcScrollTexCoords( const float scrollSpeed[2], float *st )
-{
- int i;
- float timeScale = tess.shaderTime;
- float adjustedScrollS, adjustedScrollT;
-
- adjustedScrollS = scrollSpeed[0] * timeScale;
- adjustedScrollT = scrollSpeed[1] * timeScale;
-
- // clamp so coordinates don't continuously get larger, causing problems
- // with hardware limits
- adjustedScrollS = adjustedScrollS - floor( adjustedScrollS );
- adjustedScrollT = adjustedScrollT - floor( adjustedScrollT );
-
- for ( i = 0; i < tess.numVertexes; i++, st += 2 )
- {
- st[0] += adjustedScrollS;
- st[1] += adjustedScrollT;
- }
-}
-
-/*
-** RB_CalcTransformTexCoords
-*/
-void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *st )
-{
- int i;
-
- for ( i = 0; i < tess.numVertexes; i++, st += 2 )
- {
- float s = st[0];
- float t = st[1];
-
- st[0] = s * tmi->matrix[0][0] + t * tmi->matrix[1][0] + tmi->translate[0];
- st[1] = s * tmi->matrix[0][1] + t * tmi->matrix[1][1] + tmi->translate[1];
- }
-}
-
-/*
-** RB_CalcRotateTexCoords
-*/
-void RB_CalcRotateTexCoords( float degsPerSecond, float *st )
-{
- float timeScale = tess.shaderTime;
- float degs;
- int index;
- float sinValue, cosValue;
- texModInfo_t tmi;
-
- degs = -degsPerSecond * timeScale;
- index = degs * ( FUNCTABLE_SIZE / 360.0f );
-
- sinValue = tr.sinTable[ index & FUNCTABLE_MASK ];
- cosValue = tr.sinTable[ ( index + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ];
-
- tmi.matrix[0][0] = cosValue;
- tmi.matrix[1][0] = -sinValue;
- tmi.translate[0] = 0.5 - 0.5 * cosValue + 0.5 * sinValue;
-
- tmi.matrix[0][1] = sinValue;
- tmi.matrix[1][1] = cosValue;
- tmi.translate[1] = 0.5 - 0.5 * sinValue - 0.5 * cosValue;
-
- RB_CalcTransformTexCoords( &tmi, st );
-}
-
-
-
-
-
-
-#if id386 && !defined(__GNUC__)
-
-long myftol( float f ) {
- static int tmp;
- __asm fld f
- __asm fistp tmp
- __asm mov eax, tmp
-}
-
-#endif
-
-/*
-** RB_CalcSpecularAlpha
-**
-** Calculates specular coefficient and places it in the alpha channel
-*/
-vec3_t lightOrigin = { -960, 1980, 96 }; // FIXME: track dynamically
-
-void RB_CalcSpecularAlpha( unsigned char *alphas ) {
- int i;
- float *v, *normal;
- vec3_t viewer, reflected;
- float l, d;
- int b;
- vec3_t lightDir;
- int numVertexes;
-
- v = tess.xyz[0];
- normal = tess.normal[0];
-
- alphas += 3;
-
- numVertexes = tess.numVertexes;
- for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4, alphas += 4) {
- float ilength;
-
- VectorSubtract( lightOrigin, v, lightDir );
-// ilength = Q_rsqrt( DotProduct( lightDir, lightDir ) );
- VectorNormalizeFast( lightDir );
-
- // calculate the specular color
- d = DotProduct (normal, lightDir);
-// d *= ilength;
-
- // we don't optimize for the d < 0 case since this tends to
- // cause visual artifacts such as faceted "snapping"
- reflected[0] = normal[0]*2*d - lightDir[0];
- reflected[1] = normal[1]*2*d - lightDir[1];
- reflected[2] = normal[2]*2*d - lightDir[2];
-
- VectorSubtract (backEnd.or.viewOrigin, v, viewer);
- ilength = Q_rsqrt( DotProduct( viewer, viewer ) );
- l = DotProduct (reflected, viewer);
- l *= ilength;
-
- if (l < 0) {
- b = 0;
- } else {
- l = l*l;
- l = l*l;
- b = l * 255;
- if (b > 255) {
- b = 255;
- }
- }
-
- *alphas = b;
- }
-}
-
-/*
-** RB_CalcDiffuseColor
-**
-** The basic vertex lighting calc
-*/
-#if idppc_altivec
-static void RB_CalcDiffuseColor_altivec( unsigned char *colors )
-{
- int i;
- float *v, *normal;
- trRefEntity_t *ent;
- int ambientLightInt;
- vec3_t lightDir;
- int numVertexes;
- vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff);
- vector float ambientLightVec;
- vector float directedLightVec;
- vector float lightDirVec;
- vector float normalVec0, normalVec1;
- vector float incomingVec0, incomingVec1, incomingVec2;
- vector float zero, jVec;
- vector signed int jVecInt;
- vector signed short jVecShort;
- vector unsigned char jVecChar, normalPerm;
- ent = backEnd.currentEntity;
- ambientLightInt = ent->ambientLightInt;
- // A lot of this could be simplified if we made sure
- // entities light info was 16-byte aligned.
- jVecChar = vec_lvsl(0, ent->ambientLight);
- ambientLightVec = vec_ld(0, (vector float *)ent->ambientLight);
- jVec = vec_ld(11, (vector float *)ent->ambientLight);
- ambientLightVec = vec_perm(ambientLightVec,jVec,jVecChar);
-
- jVecChar = vec_lvsl(0, ent->directedLight);
- directedLightVec = vec_ld(0,(vector float *)ent->directedLight);
- jVec = vec_ld(11,(vector float *)ent->directedLight);
- directedLightVec = vec_perm(directedLightVec,jVec,jVecChar);
-
- jVecChar = vec_lvsl(0, ent->lightDir);
- lightDirVec = vec_ld(0,(vector float *)ent->lightDir);
- jVec = vec_ld(11,(vector float *)ent->lightDir);
- lightDirVec = vec_perm(lightDirVec,jVec,jVecChar);
-
- zero = (vector float)vec_splat_s8(0);
- VectorCopy( ent->lightDir, lightDir );
-
- v = tess.xyz[0];
- normal = tess.normal[0];
-
- normalPerm = vec_lvsl(0,normal);
- numVertexes = tess.numVertexes;
- for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) {
- normalVec0 = vec_ld(0,(vector float *)normal);
- normalVec1 = vec_ld(11,(vector float *)normal);
- normalVec0 = vec_perm(normalVec0,normalVec1,normalPerm);
- incomingVec0 = vec_madd(normalVec0, lightDirVec, zero);
- incomingVec1 = vec_sld(incomingVec0,incomingVec0,4);
- incomingVec2 = vec_add(incomingVec0,incomingVec1);
- incomingVec1 = vec_sld(incomingVec1,incomingVec1,4);
- incomingVec2 = vec_add(incomingVec2,incomingVec1);
- incomingVec0 = vec_splat(incomingVec2,0);
- incomingVec0 = vec_max(incomingVec0,zero);
- normalPerm = vec_lvsl(12,normal);
- jVec = vec_madd(incomingVec0, directedLightVec, ambientLightVec);
- jVecInt = vec_cts(jVec,0); // RGBx
- jVecShort = vec_pack(jVecInt,jVecInt); // RGBxRGBx
- jVecChar = vec_packsu(jVecShort,jVecShort); // RGBxRGBxRGBxRGBx
- jVecChar = vec_sel(jVecChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255
- vec_ste((vector unsigned int)jVecChar,0,(unsigned int *)&colors[i*4]); // store color
- }
-}
-#endif
-
-static void RB_CalcDiffuseColor_scalar( unsigned char *colors )
-{
- int i, j;
- float *v, *normal;
- float incoming;
- trRefEntity_t *ent;
- int ambientLightInt;
- vec3_t ambientLight;
- vec3_t lightDir;
- vec3_t directedLight;
- int numVertexes;
- ent = backEnd.currentEntity;
- ambientLightInt = ent->ambientLightInt;
- VectorCopy( ent->ambientLight, ambientLight );
- VectorCopy( ent->directedLight, directedLight );
- VectorCopy( ent->lightDir, lightDir );
-
- v = tess.xyz[0];
- normal = tess.normal[0];
-
- numVertexes = tess.numVertexes;
- for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) {
- incoming = DotProduct (normal, lightDir);
- if ( incoming <= 0 ) {
- *(int *)&colors[i*4] = ambientLightInt;
- continue;
- }
- j = myftol( ambientLight[0] + incoming * directedLight[0] );
- if ( j > 255 ) {
- j = 255;
- }
- colors[i*4+0] = j;
-
- j = myftol( ambientLight[1] + incoming * directedLight[1] );
- if ( j > 255 ) {
- j = 255;
- }
- colors[i*4+1] = j;
-
- j = myftol( ambientLight[2] + incoming * directedLight[2] );
- if ( j > 255 ) {
- j = 255;
- }
- colors[i*4+2] = j;
-
- colors[i*4+3] = 255;
- }
-}
-
-void RB_CalcDiffuseColor( unsigned char *colors )
-{
-#if idppc_altivec
- if (com_altivec->integer) {
- // must be in a seperate function or G3 systems will crash.
- RB_CalcDiffuseColor_altivec( colors );
- return;
- }
-#endif
- RB_CalcDiffuseColor_scalar( colors );
-}
-
diff --git a/engine/code/renderer/tr_shader.c b/engine/code/renderer/tr_shader.c
deleted file mode 100644
index 79b8aa0..0000000
--- a/engine/code/renderer/tr_shader.c
+++ /dev/null
@@ -1,3075 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "tr_local.h"
-
-// tr_shader.c -- this file deals with the parsing and definition of shaders
-
-static char *s_shaderText;
-
-// the shader is parsed into these global variables, then copied into
-// dynamically allocated memory if it is valid.
-static shaderStage_t stages[MAX_SHADER_STAGES];
-static shader_t shader;
-static texModInfo_t texMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS];
-static qboolean deferLoad;
-
-#define FILE_HASH_SIZE 1024
-static shader_t* hashTable[FILE_HASH_SIZE];
-
-#define MAX_SHADERTEXT_HASH 2048
-static char **shaderTextHashTable[MAX_SHADERTEXT_HASH];
-
-/*
-================
-return a hash value for the filename
-================
-*/
-#ifdef __GNUCC__
- #warning TODO: check if long is ok here
-#endif
-static long generateHashValue( const char *fname, const int size ) {
- int i;
- long hash;
- char letter;
-
- hash = 0;
- i = 0;
- while (fname[i] != '\0') {
- letter = tolower(fname[i]);
- if (letter =='.') break; // don't include extension
- if (letter =='\\') letter = '/'; // damn path names
- if (letter == PATH_SEP) letter = '/'; // damn path names
- hash+=(long)(letter)*(i+119);
- i++;
- }
- hash = (hash ^ (hash >> 10) ^ (hash >> 20));
- hash &= (size-1);
- return hash;
-}
-
-void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) {
- char strippedName[MAX_QPATH];
- int hash;
- shader_t *sh, *sh2;
- qhandle_t h;
-
- sh = R_FindShaderByName( shaderName );
- if (sh == NULL || sh == tr.defaultShader) {
- h = RE_RegisterShaderLightMap(shaderName, 0);
- sh = R_GetShaderByHandle(h);
- }
- if (sh == NULL || sh == tr.defaultShader) {
- ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", shaderName );
- return;
- }
-
- sh2 = R_FindShaderByName( newShaderName );
- if (sh2 == NULL || sh2 == tr.defaultShader) {
- h = RE_RegisterShaderLightMap(newShaderName, 0);
- sh2 = R_GetShaderByHandle(h);
- }
-
- if (sh2 == NULL || sh2 == tr.defaultShader) {
- ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: new shader %s not found\n", newShaderName );
- return;
- }
-
- // remap all the shaders with the given name
- // even tho they might have different lightmaps
- COM_StripExtension(shaderName, strippedName, sizeof(strippedName));
- hash = generateHashValue(strippedName, FILE_HASH_SIZE);
- for (sh = hashTable[hash]; sh; sh = sh->next) {
- if (Q_stricmp(sh->name, strippedName) == 0) {
- if (sh != sh2) {
- sh->remappedShader = sh2;
- } else {
- sh->remappedShader = NULL;
- }
- }
- }
- if (timeOffset) {
- sh2->timeOffset = atof(timeOffset);
- }
-}
-
-/*
-===============
-ParseVector
-===============
-*/
-static qboolean ParseVector( char **text, int count, float *v ) {
- char *token;
- int i;
-
- // FIXME: spaces are currently required after parens, should change parseext...
- token = COM_ParseExt( text, qfalse );
- if ( strcmp( token, "(" ) ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
- return qfalse;
- }
-
- for ( i = 0 ; i < count ; i++ ) {
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing vector element in shader '%s'\n", shader.name );
- return qfalse;
- }
- v[i] = atof( token );
- }
-
- token = COM_ParseExt( text, qfalse );
- if ( strcmp( token, ")" ) ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-===============
-NameToAFunc
-===============
-*/
-static unsigned NameToAFunc( const char *funcname )
-{
- if ( !Q_stricmp( funcname, "GT0" ) )
- {
- return GLS_ATEST_GT_0;
- }
- else if ( !Q_stricmp( funcname, "LT128" ) )
- {
- return GLS_ATEST_LT_80;
- }
- else if ( !Q_stricmp( funcname, "GE128" ) )
- {
- return GLS_ATEST_GE_80;
- }
-
- ri.Printf( PRINT_WARNING, "WARNING: invalid alphaFunc name '%s' in shader '%s'\n", funcname, shader.name );
- return 0;
-}
-
-
-/*
-===============
-NameToSrcBlendMode
-===============
-*/
-static int NameToSrcBlendMode( const char *name )
-{
- if ( !Q_stricmp( name, "GL_ONE" ) )
- {
- return GLS_SRCBLEND_ONE;
- }
- else if ( !Q_stricmp( name, "GL_ZERO" ) )
- {
- return GLS_SRCBLEND_ZERO;
- }
- else if ( !Q_stricmp( name, "GL_DST_COLOR" ) )
- {
- return GLS_SRCBLEND_DST_COLOR;
- }
- else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_COLOR" ) )
- {
- return GLS_SRCBLEND_ONE_MINUS_DST_COLOR;
- }
- else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) )
- {
- return GLS_SRCBLEND_SRC_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) )
- {
- return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) )
- {
- return GLS_SRCBLEND_DST_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) )
- {
- return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_SRC_ALPHA_SATURATE" ) )
- {
- return GLS_SRCBLEND_ALPHA_SATURATE;
- }
-
- ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
- return GLS_SRCBLEND_ONE;
-}
-
-/*
-===============
-NameToDstBlendMode
-===============
-*/
-static int NameToDstBlendMode( const char *name )
-{
- if ( !Q_stricmp( name, "GL_ONE" ) )
- {
- return GLS_DSTBLEND_ONE;
- }
- else if ( !Q_stricmp( name, "GL_ZERO" ) )
- {
- return GLS_DSTBLEND_ZERO;
- }
- else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) )
- {
- return GLS_DSTBLEND_SRC_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) )
- {
- return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) )
- {
- return GLS_DSTBLEND_DST_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) )
- {
- return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_SRC_COLOR" ) )
- {
- return GLS_DSTBLEND_SRC_COLOR;
- }
- else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_COLOR" ) )
- {
- return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR;
- }
-
- ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
- return GLS_DSTBLEND_ONE;
-}
-
-/*
-===============
-NameToGenFunc
-===============
-*/
-static genFunc_t NameToGenFunc( const char *funcname )
-{
- if ( !Q_stricmp( funcname, "sin" ) )
- {
- return GF_SIN;
- }
- else if ( !Q_stricmp( funcname, "square" ) )
- {
- return GF_SQUARE;
- }
- else if ( !Q_stricmp( funcname, "triangle" ) )
- {
- return GF_TRIANGLE;
- }
- else if ( !Q_stricmp( funcname, "sawtooth" ) )
- {
- return GF_SAWTOOTH;
- }
- else if ( !Q_stricmp( funcname, "inversesawtooth" ) )
- {
- return GF_INVERSE_SAWTOOTH;
- }
- else if ( !Q_stricmp( funcname, "noise" ) )
- {
- return GF_NOISE;
- }
-
- ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name );
- return GF_SIN;
-}
-
-
-/*
-===================
-ParseWaveForm
-===================
-*/
-static void ParseWaveForm( char **text, waveForm_t *wave )
-{
- char *token;
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
- return;
- }
- wave->func = NameToGenFunc( token );
-
- // BASE, AMP, PHASE, FREQ
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
- return;
- }
- wave->base = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
- return;
- }
- wave->amplitude = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
- return;
- }
- wave->phase = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
- return;
- }
- wave->frequency = atof( token );
-}
-
-
-/*
-===================
-ParseTexMod
-===================
-*/
-static void ParseTexMod( char *_text, shaderStage_t *stage )
-{
- const char *token;
- char **text = &_text;
- texModInfo_t *tmi;
-
- if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) {
- ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'\n", shader.name );
- return;
- }
-
- tmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods];
- stage->bundle[0].numTexMods++;
-
- token = COM_ParseExt( text, qfalse );
-
- //
- // turb
- //
- if ( !Q_stricmp( token, "turb" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.base = atof( token );
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.amplitude = atof( token );
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.phase = atof( token );
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.frequency = atof( token );
-
- tmi->type = TMOD_TURBULENT;
- }
- //
- // scale
- //
- else if ( !Q_stricmp( token, "scale" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->scale[0] = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->scale[1] = atof( token );
- tmi->type = TMOD_SCALE;
- }
- //
- // scroll
- //
- else if ( !Q_stricmp( token, "scroll" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->scroll[0] = atof( token );
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->scroll[1] = atof( token );
- tmi->type = TMOD_SCROLL;
- }
- //
- // stretch
- //
- else if ( !Q_stricmp( token, "stretch" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.func = NameToGenFunc( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.base = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.amplitude = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.phase = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.frequency = atof( token );
-
- tmi->type = TMOD_STRETCH;
- }
- //
- // transform
- //
- else if ( !Q_stricmp( token, "transform" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->matrix[0][0] = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->matrix[0][1] = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->matrix[1][0] = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->matrix[1][1] = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->translate[0] = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->translate[1] = atof( token );
-
- tmi->type = TMOD_TRANSFORM;
- }
- //
- // rotate
- //
- else if ( !Q_stricmp( token, "rotate" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->rotateSpeed = atof( token );
- tmi->type = TMOD_ROTATE;
- }
- //
- // entityTranslate
- //
- else if ( !Q_stricmp( token, "entityTranslate" ) )
- {
- tmi->type = TMOD_ENTITY_TRANSLATE;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name );
- }
-}
-
-
-/*
-===================
-ParseStage
-===================
-*/
-static qboolean ParseStage( shaderStage_t *stage, char **text )
-{
- char *token;
- int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0;
- qboolean depthMaskExplicit = qfalse;
-
- stage->active = qtrue;
-
- while ( 1 )
- {
- token = COM_ParseExt( text, qtrue );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" );
- return qfalse;
- }
-
- if ( token[0] == '}' )
- {
- break;
- }
- //
- // map <name>
- //
- else if ( !Q_stricmp( token, "map" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name );
- return qfalse;
- }
-
- if ( !Q_stricmp( token, "$whiteimage" ) )
- {
- stage->bundle[0].image[0] = tr.whiteImage;
- continue;
- }
- else if ( !Q_stricmp( token, "$lightmap" ) )
- {
- stage->bundle[0].isLightmap = qtrue;
- if ( shader.lightmapIndex < 0 ) {
- stage->bundle[0].image[0] = tr.whiteImage;
- } else {
- stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
- }
- continue;
- }
- else
- {
- stage->bundle[0].image[0] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_REPEAT );
- if ( !stage->bundle[0].image[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
- return qfalse;
- }
- }
- }
- //
- // clampmap <name>
- //
- else if ( !Q_stricmp( token, "clampmap" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name );
- return qfalse;
- }
-
- stage->bundle[0].image[0] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_CLAMP_TO_EDGE );
- if ( !stage->bundle[0].image[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
- return qfalse;
- }
- }
- //
- // animMap <frequency> <image1> .... <imageN>
- //
- else if ( !Q_stricmp( token, "animMap" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMmap' keyword in shader '%s'\n", shader.name );
- return qfalse;
- }
- stage->bundle[0].imageAnimationSpeed = atof( token );
-
- // parse up to MAX_IMAGE_ANIMATIONS animations
- while ( 1 ) {
- int num;
-
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] ) {
- break;
- }
- num = stage->bundle[0].numImageAnimations;
- if ( num < MAX_IMAGE_ANIMATIONS ) {
- stage->bundle[0].image[num] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_REPEAT );
- if ( !stage->bundle[0].image[num] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
- return qfalse;
- }
- stage->bundle[0].numImageAnimations++;
- }
- }
- }
- else if ( !Q_stricmp( token, "videoMap" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMmap' keyword in shader '%s'\n", shader.name );
- return qfalse;
- }
- stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader));
- if (stage->bundle[0].videoMapHandle != -1) {
- stage->bundle[0].isVideoMap = qtrue;
- stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle];
- }
- }
- //
- // alphafunc <func>
- //
- else if ( !Q_stricmp( token, "alphaFunc" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name );
- return qfalse;
- }
-
- atestBits = NameToAFunc( token );
- }
- //
- // depthFunc <func>
- //
- else if ( !Q_stricmp( token, "depthfunc" ) )
- {
- token = COM_ParseExt( text, qfalse );
-
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name );
- return qfalse;
- }
-
- if ( !Q_stricmp( token, "lequal" ) )
- {
- depthFuncBits = 0;
- }
- else if ( !Q_stricmp( token, "equal" ) )
- {
- depthFuncBits = GLS_DEPTHFUNC_EQUAL;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name );
- continue;
- }
- }
- //
- // detail
- //
- else if ( !Q_stricmp( token, "detail" ) )
- {
- stage->isDetail = qtrue;
- }
- //
- // blendfunc <srcFactor> <dstFactor>
- // or blendfunc <add|filter|blend>
- //
- else if ( !Q_stricmp( token, "blendfunc" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
- continue;
- }
- // check for "simple" blends first
- if ( !Q_stricmp( token, "add" ) ) {
- blendSrcBits = GLS_SRCBLEND_ONE;
- blendDstBits = GLS_DSTBLEND_ONE;
- } else if ( !Q_stricmp( token, "filter" ) ) {
- blendSrcBits = GLS_SRCBLEND_DST_COLOR;
- blendDstBits = GLS_DSTBLEND_ZERO;
- } else if ( !Q_stricmp( token, "blend" ) ) {
- blendSrcBits = GLS_SRCBLEND_SRC_ALPHA;
- blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
- } else {
- // complex double blends
- blendSrcBits = NameToSrcBlendMode( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
- continue;
- }
- blendDstBits = NameToDstBlendMode( token );
- }
-
- // clear depth mask for blended surfaces
- if ( !depthMaskExplicit )
- {
- depthMaskBits = 0;
- }
- }
- //
- // rgbGen
- //
- else if ( !Q_stricmp( token, "rgbGen" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name );
- continue;
- }
-
- if ( !Q_stricmp( token, "wave" ) )
- {
- ParseWaveForm( text, &stage->rgbWave );
- stage->rgbGen = CGEN_WAVEFORM;
- }
- else if ( !Q_stricmp( token, "const" ) )
- {
- vec3_t color;
-
- ParseVector( text, 3, color );
- stage->constantColor[0] = 255 * color[0];
- stage->constantColor[1] = 255 * color[1];
- stage->constantColor[2] = 255 * color[2];
-
- stage->rgbGen = CGEN_CONST;
- }
- else if ( !Q_stricmp( token, "identity" ) )
- {
- stage->rgbGen = CGEN_IDENTITY;
- }
- else if ( !Q_stricmp( token, "identityLighting" ) )
- {
- stage->rgbGen = CGEN_IDENTITY_LIGHTING;
- }
- else if ( !Q_stricmp( token, "entity" ) )
- {
- stage->rgbGen = CGEN_ENTITY;
- }
- else if ( !Q_stricmp( token, "oneMinusEntity" ) )
- {
- stage->rgbGen = CGEN_ONE_MINUS_ENTITY;
- }
- else if ( !Q_stricmp( token, "vertex" ) )
- {
- stage->rgbGen = CGEN_VERTEX;
- if ( stage->alphaGen == 0 ) {
- stage->alphaGen = AGEN_VERTEX;
- }
- }
- else if ( !Q_stricmp( token, "exactVertex" ) )
- {
- stage->rgbGen = CGEN_EXACT_VERTEX;
- }
- else if ( !Q_stricmp( token, "lightingDiffuse" ) )
- {
- stage->rgbGen = CGEN_LIGHTING_DIFFUSE;
- }
- else if ( !Q_stricmp( token, "oneMinusVertex" ) )
- {
- stage->rgbGen = CGEN_ONE_MINUS_VERTEX;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name );
- continue;
- }
- }
- //
- // alphaGen
- //
- else if ( !Q_stricmp( token, "alphaGen" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name );
- continue;
- }
-
- if ( !Q_stricmp( token, "wave" ) )
- {
- ParseWaveForm( text, &stage->alphaWave );
- stage->alphaGen = AGEN_WAVEFORM;
- }
- else if ( !Q_stricmp( token, "const" ) )
- {
- token = COM_ParseExt( text, qfalse );
- stage->constantColor[3] = 255 * atof( token );
- stage->alphaGen = AGEN_CONST;
- }
- else if ( !Q_stricmp( token, "identity" ) )
- {
- stage->alphaGen = AGEN_IDENTITY;
- }
- else if ( !Q_stricmp( token, "entity" ) )
- {
- stage->alphaGen = AGEN_ENTITY;
- }
- else if ( !Q_stricmp( token, "oneMinusEntity" ) )
- {
- stage->alphaGen = AGEN_ONE_MINUS_ENTITY;
- }
- else if ( !Q_stricmp( token, "vertex" ) )
- {
- stage->alphaGen = AGEN_VERTEX;
- }
- else if ( !Q_stricmp( token, "lightingSpecular" ) )
- {
- stage->alphaGen = AGEN_LIGHTING_SPECULAR;
- }
- else if ( !Q_stricmp( token, "oneMinusVertex" ) )
- {
- stage->alphaGen = AGEN_ONE_MINUS_VERTEX;
- }
- else if ( !Q_stricmp( token, "portal" ) )
- {
- stage->alphaGen = AGEN_PORTAL;
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- shader.portalRange = 256;
- ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name );
- }
- else
- {
- shader.portalRange = atof( token );
- }
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name );
- continue;
- }
- }
- //
- // tcGen <function>
- //
- else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name );
- continue;
- }
-
- if ( !Q_stricmp( token, "environment" ) )
- {
- stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED;
- }
- else if ( !Q_stricmp( token, "lightmap" ) )
- {
- stage->bundle[0].tcGen = TCGEN_LIGHTMAP;
- }
- else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) )
- {
- stage->bundle[0].tcGen = TCGEN_TEXTURE;
- }
- else if ( !Q_stricmp( token, "vector" ) )
- {
- ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] );
- ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] );
-
- stage->bundle[0].tcGen = TCGEN_VECTOR;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name );
- }
- }
- //
- // tcMod <type> <...>
- //
- else if ( !Q_stricmp( token, "tcMod" ) )
- {
- char buffer[1024] = "";
-
- while ( 1 )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- break;
- strcat( buffer, token );
- strcat( buffer, " " );
- }
-
- ParseTexMod( buffer, stage );
-
- continue;
- }
- //
- // depthmask
- //
- else if ( !Q_stricmp( token, "depthwrite" ) )
- {
- depthMaskBits = GLS_DEPTHMASK_TRUE;
- depthMaskExplicit = qtrue;
-
- continue;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name );
- return qfalse;
- }
- }
-
- //
- // if cgen isn't explicitly specified, use either identity or identitylighting
- //
- if ( stage->rgbGen == CGEN_BAD ) {
- if ( blendSrcBits == 0 ||
- blendSrcBits == GLS_SRCBLEND_ONE ||
- blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) {
- stage->rgbGen = CGEN_IDENTITY_LIGHTING;
- } else {
- stage->rgbGen = CGEN_IDENTITY;
- }
- }
-
-
- //
- // implicitly assume that a GL_ONE GL_ZERO blend mask disables blending
- //
- if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) &&
- ( blendDstBits == GLS_DSTBLEND_ZERO ) )
- {
- blendDstBits = blendSrcBits = 0;
- depthMaskBits = GLS_DEPTHMASK_TRUE;
- }
-
- // decide which agens we can skip
- if ( stage->alphaGen == CGEN_IDENTITY ) {
- if ( stage->rgbGen == CGEN_IDENTITY
- || stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) {
- stage->alphaGen = AGEN_SKIP;
- }
- }
-
- //
- // compute state bits
- //
- stage->stateBits = depthMaskBits |
- blendSrcBits | blendDstBits |
- atestBits |
- depthFuncBits;
-
- return qtrue;
-}
-
-/*
-===============
-ParseDeform
-
-deformVertexes wave <spread> <waveform> <base> <amplitude> <phase> <frequency>
-deformVertexes normal <frequency> <amplitude>
-deformVertexes move <vector> <waveform> <base> <amplitude> <phase> <frequency>
-deformVertexes bulge <bulgeWidth> <bulgeHeight> <bulgeSpeed>
-deformVertexes projectionShadow
-deformVertexes autoSprite
-deformVertexes autoSprite2
-deformVertexes text[0-7]
-===============
-*/
-static void ParseDeform( char **text ) {
- char *token;
- deformStage_t *ds;
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deform parm in shader '%s'\n", shader.name );
- return;
- }
-
- if ( shader.numDeforms == MAX_SHADER_DEFORMS ) {
- ri.Printf( PRINT_WARNING, "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name );
- return;
- }
-
- ds = &shader.deforms[ shader.numDeforms ];
- shader.numDeforms++;
-
- if ( !Q_stricmp( token, "projectionShadow" ) ) {
- ds->deformation = DEFORM_PROJECTION_SHADOW;
- return;
- }
-
- if ( !Q_stricmp( token, "autosprite" ) ) {
- ds->deformation = DEFORM_AUTOSPRITE;
- return;
- }
-
- if ( !Q_stricmp( token, "autosprite2" ) ) {
- ds->deformation = DEFORM_AUTOSPRITE2;
- return;
- }
-
- if ( !Q_stricmpn( token, "text", 4 ) ) {
- int n;
-
- n = token[4] - '0';
- if ( n < 0 || n > 7 ) {
- n = 0;
- }
- ds->deformation = DEFORM_TEXT0 + n;
- return;
- }
-
- if ( !Q_stricmp( token, "bulge" ) ) {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
- return;
- }
- ds->bulgeWidth = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
- return;
- }
- ds->bulgeHeight = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
- return;
- }
- ds->bulgeSpeed = atof( token );
-
- ds->deformation = DEFORM_BULGE;
- return;
- }
-
- if ( !Q_stricmp( token, "wave" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
- return;
- }
-
- if ( atof( token ) != 0 )
- {
- ds->deformationSpread = 1.0f / atof( token );
- }
- else
- {
- ds->deformationSpread = 100.0f;
- ri.Printf( PRINT_WARNING, "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name );
- }
-
- ParseWaveForm( text, &ds->deformationWave );
- ds->deformation = DEFORM_WAVE;
- return;
- }
-
- if ( !Q_stricmp( token, "normal" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
- return;
- }
- ds->deformationWave.amplitude = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
- return;
- }
- ds->deformationWave.frequency = atof( token );
-
- ds->deformation = DEFORM_NORMALS;
- return;
- }
-
- if ( !Q_stricmp( token, "move" ) ) {
- int i;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
- return;
- }
- ds->moveVector[i] = atof( token );
- }
-
- ParseWaveForm( text, &ds->deformationWave );
- ds->deformation = DEFORM_MOVE;
- return;
- }
-
- ri.Printf( PRINT_WARNING, "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name );
-}
-
-
-/*
-===============
-ParseSkyParms
-
-skyParms <outerbox> <cloudheight> <innerbox>
-===============
-*/
-static void ParseSkyParms( char **text ) {
- char *token;
- static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
- char pathname[MAX_QPATH];
- int i;
-
- // outerbox
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
- return;
- }
- if ( strcmp( token, "-" ) ) {
- for (i=0 ; i<6 ; i++) {
- Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga"
- , token, suf[i] );
- shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_CLAMP_TO_EDGE );
-
- if ( !shader.sky.outerbox[i] ) {
- shader.sky.outerbox[i] = tr.defaultImage;
- }
- }
- }
-
- // cloudheight
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
- return;
- }
- shader.sky.cloudHeight = atof( token );
- if ( !shader.sky.cloudHeight ) {
- shader.sky.cloudHeight = 512;
- }
- R_InitSkyTexCoords( shader.sky.cloudHeight );
-
-
- // innerbox
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
- return;
- }
- if ( strcmp( token, "-" ) ) {
- for (i=0 ; i<6 ; i++) {
- Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga"
- , token, suf[i] );
- shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_REPEAT );
- if ( !shader.sky.innerbox[i] ) {
- shader.sky.innerbox[i] = tr.defaultImage;
- }
- }
- }
-
- shader.isSky = qtrue;
-}
-
-
-/*
-=================
-ParseSort
-=================
-*/
-void ParseSort( char **text ) {
- char *token;
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing sort parameter in shader '%s'\n", shader.name );
- return;
- }
-
- if ( !Q_stricmp( token, "portal" ) ) {
- shader.sort = SS_PORTAL;
- } else if ( !Q_stricmp( token, "sky" ) ) {
- shader.sort = SS_ENVIRONMENT;
- } else if ( !Q_stricmp( token, "opaque" ) ) {
- shader.sort = SS_OPAQUE;
- }else if ( !Q_stricmp( token, "decal" ) ) {
- shader.sort = SS_DECAL;
- } else if ( !Q_stricmp( token, "seeThrough" ) ) {
- shader.sort = SS_SEE_THROUGH;
- } else if ( !Q_stricmp( token, "banner" ) ) {
- shader.sort = SS_BANNER;
- } else if ( !Q_stricmp( token, "additive" ) ) {
- shader.sort = SS_BLEND1;
- } else if ( !Q_stricmp( token, "nearest" ) ) {
- shader.sort = SS_NEAREST;
- } else if ( !Q_stricmp( token, "underwater" ) ) {
- shader.sort = SS_UNDERWATER;
- } else {
- shader.sort = atof( token );
- }
-}
-
-
-
-// this table is also present in q3map
-
-typedef struct {
- char *name;
- int clearSolid, surfaceFlags, contents;
-} infoParm_t;
-
-infoParm_t infoParms[] = {
- // server relevant contents
- {"water", 1, 0, CONTENTS_WATER },
- {"slime", 1, 0, CONTENTS_SLIME }, // mildly damaging
- {"lava", 1, 0, CONTENTS_LAVA }, // very damaging
- {"playerclip", 1, 0, CONTENTS_PLAYERCLIP },
- {"monsterclip", 1, 0, CONTENTS_MONSTERCLIP },
- {"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc)
- {"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag
-
- // utility relevant attributes
- {"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes
- {"trans", 0, 0, CONTENTS_TRANSLUCENT }, // don't eat contained surfaces
- {"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp
- {"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas
- {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas
- {"clusterportal", 1,0, CONTENTS_CLUSTERPORTAL }, // for bots
- {"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots
-
- {"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering
- {"sky", 0, SURF_SKY, 0 }, // emit light from an environment map
- {"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it
- {"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis
- {"hint", 0, SURF_HINT, 0 }, // use as a primary splitter
-
- // server attributes
- {"slick", 0, SURF_SLICK, 0 },
- {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks
- {"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode
- {"ladder", 0, SURF_LADDER, 0 },
- {"nodamage", 0, SURF_NODAMAGE, 0 },
- {"metalsteps", 0, SURF_METALSTEPS,0 },
- {"flesh", 0, SURF_FLESH, 0 },
- {"nosteps", 0, SURF_NOSTEPS, 0 },
-
- // drawsurf attributes
- {"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap)
- {"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes
- {"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap
- {"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights
- {"dust", 0, SURF_DUST, 0} // leave a dust trail when walking on this surface
-};
-
-
-/*
-===============
-ParseSurfaceParm
-
-surfaceparm <name>
-===============
-*/
-static void ParseSurfaceParm( char **text ) {
- char *token;
- int numInfoParms = sizeof(infoParms) / sizeof(infoParms[0]);
- int i;
-
- token = COM_ParseExt( text, qfalse );
- for ( i = 0 ; i < numInfoParms ; i++ ) {
- if ( !Q_stricmp( token, infoParms[i].name ) ) {
- shader.surfaceFlags |= infoParms[i].surfaceFlags;
- shader.contentFlags |= infoParms[i].contents;
-#if 0
- if ( infoParms[i].clearSolid ) {
- si->contents &= ~CONTENTS_SOLID;
- }
-#endif
- break;
- }
- }
-}
-
-/*
-=================
-ParseShader
-
-The current text pointer is at the explicit text definition of the
-shader. Parse it into the global shader variable. Later functions
-will optimize it.
-=================
-*/
-static qboolean ParseShader( char **text )
-{
- char *token;
- int s;
-
- s = 0;
-
- token = COM_ParseExt( text, qtrue );
- if ( token[0] != '{' )
- {
- ri.Printf( PRINT_WARNING, "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name );
- return qfalse;
- }
-
- while ( 1 )
- {
- token = COM_ParseExt( text, qtrue );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: no concluding '}' in shader %s\n", shader.name );
- return qfalse;
- }
-
- // end of shader definition
- if ( token[0] == '}' )
- {
- break;
- }
- // stage definition
- else if ( token[0] == '{' )
- {
- if ( s >= MAX_SHADER_STAGES ) {
- ri.Printf( PRINT_WARNING, "WARNING: too many stages in shader %s\n", shader.name );
- return qfalse;
- }
-
- if ( !ParseStage( &stages[s], text ) )
- {
- return qfalse;
- }
- stages[s].active = qtrue;
- s++;
-
- continue;
- }
- // skip stuff that only the QuakeEdRadient needs
- else if ( !Q_stricmpn( token, "qer", 3 ) ) {
- SkipRestOfLine( text );
- continue;
- }
- // sun parms
- else if ( !Q_stricmp( token, "q3map_sun" ) ) {
- float a, b;
-
- token = COM_ParseExt( text, qfalse );
- tr.sunLight[0] = atof( token );
- token = COM_ParseExt( text, qfalse );
- tr.sunLight[1] = atof( token );
- token = COM_ParseExt( text, qfalse );
- tr.sunLight[2] = atof( token );
-
- VectorNormalize( tr.sunLight );
-
- token = COM_ParseExt( text, qfalse );
- a = atof( token );
- VectorScale( tr.sunLight, a, tr.sunLight);
-
- token = COM_ParseExt( text, qfalse );
- a = atof( token );
- a = a / 180 * M_PI;
-
- token = COM_ParseExt( text, qfalse );
- b = atof( token );
- b = b / 180 * M_PI;
-
- tr.sunDirection[0] = cos( a ) * cos( b );
- tr.sunDirection[1] = sin( a ) * cos( b );
- tr.sunDirection[2] = sin( b );
- }
- else if ( !Q_stricmp( token, "deformVertexes" ) ) {
- ParseDeform( text );
- continue;
- }
- else if ( !Q_stricmp( token, "tesssize" ) ) {
- SkipRestOfLine( text );
- continue;
- }
- else if ( !Q_stricmp( token, "clampTime" ) ) {
- token = COM_ParseExt( text, qfalse );
- if (token[0]) {
- shader.clampTime = atof(token);
- }
- }
- // skip stuff that only the q3map needs
- else if ( !Q_stricmpn( token, "q3map", 5 ) ) {
- SkipRestOfLine( text );
- continue;
- }
- // skip stuff that only q3map or the server needs
- else if ( !Q_stricmp( token, "surfaceParm" ) ) {
- ParseSurfaceParm( text );
- continue;
- }
- // no mip maps
- else if ( !Q_stricmp( token, "nomipmaps" ) )
- {
- shader.noMipMaps = qtrue;
- shader.noPicMip = qtrue;
- continue;
- }
- // no picmip adjustment
- else if ( !Q_stricmp( token, "nopicmip" ) )
- {
- shader.noPicMip = qtrue;
- continue;
- }
- // polygonOffset
- else if ( !Q_stricmp( token, "polygonOffset" ) )
- {
- shader.polygonOffset = qtrue;
- continue;
- }
- // entityMergable, allowing sprite surfaces from multiple entities
- // to be merged into one batch. This is a savings for smoke
- // puffs and blood, but can't be used for anything where the
- // shader calcs (not the surface function) reference the entity color or scroll
- else if ( !Q_stricmp( token, "entityMergable" ) )
- {
- shader.entityMergable = qtrue;
- continue;
- }
- // fogParms
- else if ( !Q_stricmp( token, "fogParms" ) )
- {
- if ( !ParseVector( text, 3, shader.fogParms.color ) ) {
- return qfalse;
- }
-
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader.name );
- continue;
- }
- shader.fogParms.depthForOpaque = atof( token );
-
- // skip any old gradient directions
- SkipRestOfLine( text );
- continue;
- }
- // portal
- else if ( !Q_stricmp(token, "portal") )
- {
- shader.sort = SS_PORTAL;
- continue;
- }
- // skyparms <cloudheight> <outerbox> <innerbox>
- else if ( !Q_stricmp( token, "skyparms" ) )
- {
- ParseSkyParms( text );
- continue;
- }
- // light <value> determines flaring in q3map, not needed here
- else if ( !Q_stricmp(token, "light") )
- {
- token = COM_ParseExt( text, qfalse );
- continue;
- }
- // cull <face>
- else if ( !Q_stricmp( token, "cull") )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing cull parms in shader '%s'\n", shader.name );
- continue;
- }
-
- if ( !Q_stricmp( token, "none" ) || !Q_stricmp( token, "twosided" ) || !Q_stricmp( token, "disable" ) )
- {
- shader.cullType = CT_TWO_SIDED;
- }
- else if ( !Q_stricmp( token, "back" ) || !Q_stricmp( token, "backside" ) || !Q_stricmp( token, "backsided" ) )
- {
- shader.cullType = CT_BACK_SIDED;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name );
- }
- continue;
- }
- // sort
- else if ( !Q_stricmp( token, "sort" ) )
- {
- ParseSort( text );
- continue;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name );
- return qfalse;
- }
- }
-
- //
- // ignore shaders that don't have any stages, unless it is a sky or fog
- //
- if ( s == 0 && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG ) ) {
- return qfalse;
- }
-
- shader.explicitlyDefined = qtrue;
-
- return qtrue;
-}
-
-/*
-========================================================================================
-
-SHADER OPTIMIZATION AND FOGGING
-
-========================================================================================
-*/
-
-/*
-===================
-ComputeStageIteratorFunc
-
-See if we can use on of the simple fastpath stage functions,
-otherwise set to the generic stage function
-===================
-*/
-static void ComputeStageIteratorFunc( void )
-{
- shader.optimalStageIteratorFunc = RB_StageIteratorGeneric;
-
- //
- // see if this should go into the sky path
- //
- if ( shader.isSky )
- {
- shader.optimalStageIteratorFunc = RB_StageIteratorSky;
- goto done;
- }
-
- if ( r_ignoreFastPath->integer )
- {
- return;
- }
-
- //
- // see if this can go into the vertex lit fast path
- //
- if ( shader.numUnfoggedPasses == 1 )
- {
- if ( stages[0].rgbGen == CGEN_LIGHTING_DIFFUSE )
- {
- if ( stages[0].alphaGen == AGEN_IDENTITY )
- {
- if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE )
- {
- if ( !shader.polygonOffset )
- {
- if ( !shader.multitextureEnv )
- {
- if ( !shader.numDeforms )
- {
- shader.optimalStageIteratorFunc = RB_StageIteratorVertexLitTexture;
- goto done;
- }
- }
- }
- }
- }
- }
- }
-
- //
- // see if this can go into an optimized LM, multitextured path
- //
- if ( shader.numUnfoggedPasses == 1 )
- {
- if ( ( stages[0].rgbGen == CGEN_IDENTITY ) && ( stages[0].alphaGen == AGEN_IDENTITY ) )
- {
- if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE &&
- stages[0].bundle[1].tcGen == TCGEN_LIGHTMAP )
- {
- if ( !shader.polygonOffset )
- {
- if ( !shader.numDeforms )
- {
- if ( shader.multitextureEnv )
- {
- shader.optimalStageIteratorFunc = RB_StageIteratorLightmappedMultitexture;
- goto done;
- }
- }
- }
- }
- }
- }
-
-done:
- return;
-}
-
-typedef struct {
- int blendA;
- int blendB;
-
- int multitextureEnv;
- int multitextureBlend;
-} collapse_t;
-
-static collapse_t collapse[] = {
- { 0, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
- GL_MODULATE, 0 },
-
- { 0, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
- GL_MODULATE, 0 },
-
- { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
- GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
-
- { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
- GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
-
- { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
- GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
-
- { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
- GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
-
- { 0, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,
- GL_ADD, 0 },
-
- { GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,
- GL_ADD, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE },
-#if 0
- { 0, GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_SRCBLEND_SRC_ALPHA,
- GL_DECAL, 0 },
-#endif
- { -1 }
-};
-
-/*
-================
-CollapseMultitexture
-
-Attempt to combine two stages into a single multitexture stage
-FIXME: I think modulated add + modulated add collapses incorrectly
-=================
-*/
-static qboolean CollapseMultitexture( void ) {
- int abits, bbits;
- int i;
- textureBundle_t tmpBundle;
-
- if ( !qglActiveTextureARB ) {
- return qfalse;
- }
-
- // make sure both stages are active
- if ( !stages[0].active || !stages[1].active ) {
- return qfalse;
- }
-
- // on voodoo2, don't combine different tmus
- if ( glConfig.driverType == GLDRV_VOODOO ) {
- if ( stages[0].bundle[0].image[0]->TMU ==
- stages[1].bundle[0].image[0]->TMU ) {
- return qfalse;
- }
- }
-
- abits = stages[0].stateBits;
- bbits = stages[1].stateBits;
-
- // make sure that both stages have identical state other than blend modes
- if ( ( abits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) !=
- ( bbits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) ) {
- return qfalse;
- }
-
- abits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
- bbits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
-
- // search for a valid multitexture blend function
- for ( i = 0; collapse[i].blendA != -1 ; i++ ) {
- if ( abits == collapse[i].blendA
- && bbits == collapse[i].blendB ) {
- break;
- }
- }
-
- // nothing found
- if ( collapse[i].blendA == -1 ) {
- return qfalse;
- }
-
- // GL_ADD is a separate extension
- if ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) {
- return qfalse;
- }
-
- // make sure waveforms have identical parameters
- if ( ( stages[0].rgbGen != stages[1].rgbGen ) ||
- ( stages[0].alphaGen != stages[1].alphaGen ) ) {
- return qfalse;
- }
-
- // an add collapse can only have identity colors
- if ( collapse[i].multitextureEnv == GL_ADD && stages[0].rgbGen != CGEN_IDENTITY ) {
- return qfalse;
- }
-
- if ( stages[0].rgbGen == CGEN_WAVEFORM )
- {
- if ( memcmp( &stages[0].rgbWave,
- &stages[1].rgbWave,
- sizeof( stages[0].rgbWave ) ) )
- {
- return qfalse;
- }
- }
- if ( stages[0].alphaGen == CGEN_WAVEFORM )
- {
- if ( memcmp( &stages[0].alphaWave,
- &stages[1].alphaWave,
- sizeof( stages[0].alphaWave ) ) )
- {
- return qfalse;
- }
- }
-
-
- // make sure that lightmaps are in bundle 1 for 3dfx
- if ( stages[0].bundle[0].isLightmap )
- {
- tmpBundle = stages[0].bundle[0];
- stages[0].bundle[0] = stages[1].bundle[0];
- stages[0].bundle[1] = tmpBundle;
- }
- else
- {
- stages[0].bundle[1] = stages[1].bundle[0];
- }
-
- // set the new blend state bits
- shader.multitextureEnv = collapse[i].multitextureEnv;
- stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
- stages[0].stateBits |= collapse[i].multitextureBlend;
-
- //
- // move down subsequent shaders
- //
- memmove( &stages[1], &stages[2], sizeof( stages[0] ) * ( MAX_SHADER_STAGES - 2 ) );
- Com_Memset( &stages[MAX_SHADER_STAGES-1], 0, sizeof( stages[0] ) );
-
- return qtrue;
-}
-
-/*
-=============
-
-FixRenderCommandList
-https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
-Arnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated
-but before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces
-to be rendered with bad shaders. To fix this, need to go through all render commands and fix
-sortedIndex.
-==============
-*/
-static void FixRenderCommandList( int newShader ) {
- renderCommandList_t *cmdList = &backEndData[tr.smpFrame]->commands;
-
- if( cmdList ) {
- const void *curCmd = cmdList->cmds;
-
- while ( 1 ) {
- switch ( *(const int *)curCmd ) {
- case RC_SET_COLOR:
- {
- const setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd;
- curCmd = (const void *)(sc_cmd + 1);
- break;
- }
- case RC_STRETCH_PIC:
- {
- const stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd;
- curCmd = (const void *)(sp_cmd + 1);
- break;
- }
- case RC_DRAW_SURFS:
- {
- int i;
- drawSurf_t *drawSurf;
- shader_t *shader;
- int fogNum;
- int entityNum;
- int dlightMap;
- int sortedIndex;
- const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd;
-
- for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) {
- R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap );
- sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1));
- if( sortedIndex >= newShader ) {
- sortedIndex++;
- drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;
- }
- }
- curCmd = (const void *)(ds_cmd + 1);
- break;
- }
- case RC_DRAW_BUFFER:
- {
- const drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd;
- curCmd = (const void *)(db_cmd + 1);
- break;
- }
- case RC_SWAP_BUFFERS:
- {
- const swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd;
- curCmd = (const void *)(sb_cmd + 1);
- break;
- }
- case RC_END_OF_LIST:
- default:
- return;
- }
- }
- }
-}
-
-/*
-==============
-SortNewShader
-
-Positions the most recently created shader in the tr.sortedShaders[]
-array so that the shader->sort key is sorted reletive to the other
-shaders.
-
-Sets shader->sortedIndex
-==============
-*/
-static void SortNewShader( void ) {
- int i;
- float sort;
- shader_t *newShader;
-
- newShader = tr.shaders[ tr.numShaders - 1 ];
- sort = newShader->sort;
-
- for ( i = tr.numShaders - 2 ; i >= 0 ; i-- ) {
- if ( tr.sortedShaders[ i ]->sort <= sort ) {
- break;
- }
- tr.sortedShaders[i+1] = tr.sortedShaders[i];
- tr.sortedShaders[i+1]->sortedIndex++;
- }
-
- // Arnout: fix rendercommandlist
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
- FixRenderCommandList( i+1 );
-
- newShader->sortedIndex = i+1;
- tr.sortedShaders[i+1] = newShader;
-}
-
-
-/*
-====================
-GeneratePermanentShader
-====================
-*/
-static shader_t *GeneratePermanentShader( void ) {
- shader_t *newShader;
- int i, b;
- int size, hash;
-
- if ( tr.numShaders == MAX_SHADERS ) {
- ri.Printf( PRINT_WARNING, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n");
- return tr.defaultShader;
- }
-
- newShader = ri.Hunk_Alloc( sizeof( shader_t ), h_low );
-
- *newShader = shader;
-
- if ( shader.sort <= SS_OPAQUE ) {
- newShader->fogPass = FP_EQUAL;
- } else if ( shader.contentFlags & CONTENTS_FOG ) {
- newShader->fogPass = FP_LE;
- }
-
- tr.shaders[ tr.numShaders ] = newShader;
- newShader->index = tr.numShaders;
-
- tr.sortedShaders[ tr.numShaders ] = newShader;
- newShader->sortedIndex = tr.numShaders;
-
- tr.numShaders++;
-
- for ( i = 0 ; i < newShader->numUnfoggedPasses ; i++ ) {
- if ( !stages[i].active ) {
- break;
- }
- newShader->stages[i] = ri.Hunk_Alloc( sizeof( stages[i] ), h_low );
- *newShader->stages[i] = stages[i];
-
- for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) {
- size = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t );
- newShader->stages[i]->bundle[b].texMods = ri.Hunk_Alloc( size, h_low );
- Com_Memcpy( newShader->stages[i]->bundle[b].texMods, stages[i].bundle[b].texMods, size );
- }
- }
-
- SortNewShader();
-
- hash = generateHashValue(newShader->name, FILE_HASH_SIZE);
- newShader->next = hashTable[hash];
- hashTable[hash] = newShader;
-
- return newShader;
-}
-
-/*
-=================
-VertexLightingCollapse
-
-If vertex lighting is enabled, only render a single
-pass, trying to guess which is the correct one to best aproximate
-what it is supposed to look like.
-=================
-*/
-static void VertexLightingCollapse( void ) {
- int stage;
- shaderStage_t *bestStage;
- int bestImageRank;
- int rank;
-
- // if we aren't opaque, just use the first pass
- if ( shader.sort == SS_OPAQUE ) {
-
- // pick the best texture for the single pass
- bestStage = &stages[0];
- bestImageRank = -999999;
-
- for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) {
- shaderStage_t *pStage = &stages[stage];
-
- if ( !pStage->active ) {
- break;
- }
- rank = 0;
-
- if ( pStage->bundle[0].isLightmap ) {
- rank -= 100;
- }
- if ( pStage->bundle[0].tcGen != TCGEN_TEXTURE ) {
- rank -= 5;
- }
- if ( pStage->bundle[0].numTexMods ) {
- rank -= 5;
- }
- if ( pStage->rgbGen != CGEN_IDENTITY && pStage->rgbGen != CGEN_IDENTITY_LIGHTING ) {
- rank -= 3;
- }
-
- if ( rank > bestImageRank ) {
- bestImageRank = rank;
- bestStage = pStage;
- }
- }
-
- stages[0].bundle[0] = bestStage->bundle[0];
- stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
- stages[0].stateBits |= GLS_DEPTHMASK_TRUE;
- if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
- stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
- } else {
- stages[0].rgbGen = CGEN_EXACT_VERTEX;
- }
- stages[0].alphaGen = AGEN_SKIP;
- } else {
- // don't use a lightmap (tesla coils)
- if ( stages[0].bundle[0].isLightmap ) {
- stages[0] = stages[1];
- }
-
- // if we were in a cross-fade cgen, hack it to normal
- if ( stages[0].rgbGen == CGEN_ONE_MINUS_ENTITY || stages[1].rgbGen == CGEN_ONE_MINUS_ENTITY ) {
- stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
- }
- if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_SAWTOOTH )
- && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_INVERSE_SAWTOOTH ) ) {
- stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
- }
- if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_INVERSE_SAWTOOTH )
- && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_SAWTOOTH ) ) {
- stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
- }
- }
-
- for ( stage = 1; stage < MAX_SHADER_STAGES; stage++ ) {
- shaderStage_t *pStage = &stages[stage];
-
- if ( !pStage->active ) {
- break;
- }
-
- Com_Memset( pStage, 0, sizeof( *pStage ) );
- }
-}
-
-/*
-=========================
-FinishShader
-
-Returns a freshly allocated shader with all the needed info
-from the current global working shader
-=========================
-*/
-static shader_t *FinishShader( void ) {
- int stage;
- qboolean hasLightmapStage;
- qboolean vertexLightmap;
-
- hasLightmapStage = qfalse;
- vertexLightmap = qfalse;
-
- //
- // set sky stuff appropriate
- //
- if ( shader.isSky ) {
- shader.sort = SS_ENVIRONMENT;
- }
-
- //
- // set polygon offset
- //
- if ( shader.polygonOffset && !shader.sort ) {
- shader.sort = SS_DECAL;
- }
-
- //
- // set appropriate stage information
- //
- for ( stage = 0; stage < MAX_SHADER_STAGES; ) {
- shaderStage_t *pStage = &stages[stage];
-
- if ( !pStage->active ) {
- break;
- }
-
- // check for a missing texture
- if ( !pStage->bundle[0].image[0] ) {
- ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name );
- pStage->active = qfalse;
- stage++;
- continue;
- }
-
- //
- // ditch this stage if it's detail and detail textures are disabled
- //
- if ( pStage->isDetail && !r_detailTextures->integer )
- {
- int index;
-
- for(index = stage + 1; index < MAX_SHADER_STAGES; index++)
- {
- if(!stages[index].active)
- break;
- }
-
- if(index < MAX_SHADER_STAGES)
- memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage));
- else
- {
- if(stage + 1 < MAX_SHADER_STAGES)
- memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage - 1));
-
- Com_Memset(&stages[index - 1], 0, sizeof(*stages));
- }
-
- continue;
- }
-
- //
- // default texture coordinate generation
- //
- if ( pStage->bundle[0].isLightmap ) {
- if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
- pStage->bundle[0].tcGen = TCGEN_LIGHTMAP;
- }
- hasLightmapStage = qtrue;
- } else {
- if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
- pStage->bundle[0].tcGen = TCGEN_TEXTURE;
- }
- }
-
-
- // not a true lightmap but we want to leave existing
- // behaviour in place and not print out a warning
- //if (pStage->rgbGen == CGEN_VERTEX) {
- // vertexLightmap = qtrue;
- //}
-
-
-
- //
- // determine sort order and fog color adjustment
- //
- if ( ( pStage->stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) &&
- ( stages[0].stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) ) {
- int blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS;
- int blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS;
-
- // fog color adjustment only works for blend modes that have a contribution
- // that aproaches 0 as the modulate values aproach 0 --
- // GL_ONE, GL_ONE
- // GL_ZERO, GL_ONE_MINUS_SRC_COLOR
- // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
-
- // modulate, additive
- if ( ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ) ) ||
- ( ( blendSrcBits == GLS_SRCBLEND_ZERO ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ) ) ) {
- pStage->adjustColorsForFog = ACFF_MODULATE_RGB;
- }
- // strict blend
- else if ( ( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )
- {
- pStage->adjustColorsForFog = ACFF_MODULATE_ALPHA;
- }
- // premultiplied alpha
- else if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )
- {
- pStage->adjustColorsForFog = ACFF_MODULATE_RGBA;
- } else {
- // we can't adjust this one correctly, so it won't be exactly correct in fog
- }
-
- // don't screw with sort order if this is a portal or environment
- if ( !shader.sort ) {
- // see through item, like a grill or grate
- if ( pStage->stateBits & GLS_DEPTHMASK_TRUE ) {
- shader.sort = SS_SEE_THROUGH;
- } else {
- shader.sort = SS_BLEND0;
- }
- }
- }
-
- stage++;
- }
-
- // there are times when you will need to manually apply a sort to
- // opaque alpha tested shaders that have later blend passes
- if ( !shader.sort ) {
- shader.sort = SS_OPAQUE;
- }
-
- //
- // if we are in r_vertexLight mode, never use a lightmap texture
- //
- if ( stage > 1 && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) ) {
- VertexLightingCollapse();
- stage = 1;
- hasLightmapStage = qfalse;
- }
-
- //
- // look for multitexture potential
- //
- if ( stage > 1 && CollapseMultitexture() ) {
- stage--;
- }
-
- if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) {
- if (vertexLightmap) {
- ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has VERTEX forced lightmap!\n", shader.name );
- } else {
- ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has lightmap but no lightmap stage!\n", shader.name );
- shader.lightmapIndex = LIGHTMAP_NONE;
- }
- }
-
-
- //
- // compute number of passes
- //
- shader.numUnfoggedPasses = stage;
-
- // fogonly shaders don't have any normal passes
- if (stage == 0 && !shader.isSky)
- shader.sort = SS_FOG;
-
- // determine which stage iterator function is appropriate
- ComputeStageIteratorFunc();
-
- return GeneratePermanentShader();
-}
-
-//========================================================================================
-
-/*
-====================
-FindShaderInShaderText
-
-Scans the combined text description of all the shader files for
-the given shader name.
-
-return NULL if not found
-
-If found, it will return a valid shader
-=====================
-*/
-static char *FindShaderInShaderText( const char *shadername ) {
-
- char *token, *p;
-
- int i, hash;
-
- hash = generateHashValue(shadername, MAX_SHADERTEXT_HASH);
-
- for (i = 0; shaderTextHashTable[hash][i]; i++) {
- p = shaderTextHashTable[hash][i];
- token = COM_ParseExt(&p, qtrue);
- if ( !Q_stricmp( token, shadername ) ) {
- return p;
- }
- }
-
- p = s_shaderText;
-
- if ( !p ) {
- return NULL;
- }
-
- // look for label
- while ( 1 ) {
- token = COM_ParseExt( &p, qtrue );
- if ( token[0] == 0 ) {
- break;
- }
-
- if ( !Q_stricmp( token, shadername ) ) {
- return p;
- }
- else {
- // skip the definition
- SkipBracedSection( &p );
- }
- }
-
- return NULL;
-}
-
-
-/*
-==================
-R_FindShaderByName
-
-Will always return a valid shader, but it might be the
-default shader if the real one can't be found.
-==================
-*/
-shader_t *R_FindShaderByName( const char *name ) {
- char strippedName[MAX_QPATH];
- int hash;
- shader_t *sh;
-
- if ( (name==NULL) || (name[0] == 0) ) {
- return tr.defaultShader;
- }
-
- COM_StripExtension(name, strippedName, sizeof(strippedName));
-
- hash = generateHashValue(strippedName, FILE_HASH_SIZE);
-
- //
- // see if the shader is already loaded
- //
- for (sh=hashTable[hash]; sh; sh=sh->next) {
- // NOTE: if there was no shader or image available with the name strippedName
- // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
- // have to check all default shaders otherwise for every call to R_FindShader
- // with that same strippedName a new default shader is created.
- if (Q_stricmp(sh->name, strippedName) == 0) {
- // match found
- return sh;
- }
- }
-
- return tr.defaultShader;
-}
-
-
-/*
-===============
-R_FindShader
-
-Will always return a valid shader, but it might be the
-default shader if the real one can't be found.
-
-In the interest of not requiring an explicit shader text entry to
-be defined for every single image used in the game, three default
-shader behaviors can be auto-created for any image:
-
-If lightmapIndex == LIGHTMAP_NONE, then the image will have
-dynamic diffuse lighting applied to it, as apropriate for most
-entity skin surfaces.
-
-If lightmapIndex == LIGHTMAP_2D, then the image will be used
-for 2D rendering unless an explicit shader is found
-
-If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use
-the vertex rgba modulate values, as apropriate for misc_model
-pre-lit surfaces.
-
-Other lightmapIndex values will have a lightmap stage created
-and src*dest blending applied with the texture, as apropriate for
-most world construction surfaces.
-
-===============
-*/
-shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ) {
- char strippedName[MAX_QPATH];
- int i, hash;
- char *shaderText;
- image_t *image;
- shader_t *sh;
-
- if ( name[0] == 0 ) {
- return tr.defaultShader;
- }
-
- // use (fullbright) vertex lighting if the bsp file doesn't have
- // lightmaps
- if ( lightmapIndex >= 0 && lightmapIndex >= tr.numLightmaps ) {
- lightmapIndex = LIGHTMAP_BY_VERTEX;
- } else if ( lightmapIndex < LIGHTMAP_2D ) {
- // negative lightmap indexes cause stray pointers (think tr.lightmaps[lightmapIndex])
- ri.Printf( PRINT_WARNING, "WARNING: shader '%s' has invalid lightmap index of %d\n", name, lightmapIndex );
- lightmapIndex = LIGHTMAP_BY_VERTEX;
- }
-
- COM_StripExtension(name, strippedName, sizeof(strippedName));
-
- hash = generateHashValue(strippedName, FILE_HASH_SIZE);
-
- //
- // see if the shader is already loaded
- //
- for (sh = hashTable[hash]; sh; sh = sh->next) {
- // NOTE: if there was no shader or image available with the name strippedName
- // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
- // have to check all default shaders otherwise for every call to R_FindShader
- // with that same strippedName a new default shader is created.
- if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) &&
- !Q_stricmp(sh->name, strippedName)) {
- // match found
- return sh;
- }
- }
-
- // make sure the render thread is stopped, because we are probably
- // going to have to upload an image
- if (r_smp->integer) {
- R_SyncRenderThread();
- }
-
- // clear the global shader
- Com_Memset( &shader, 0, sizeof( shader ) );
- Com_Memset( &stages, 0, sizeof( stages ) );
- Q_strncpyz(shader.name, strippedName, sizeof(shader.name));
- shader.lightmapIndex = lightmapIndex;
- for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {
- stages[i].bundle[0].texMods = texMods[i];
- }
-
- // FIXME: set these "need" values apropriately
- shader.needsNormal = qtrue;
- shader.needsST1 = qtrue;
- shader.needsST2 = qtrue;
- shader.needsColor = qtrue;
-
- //
- // attempt to define shader from an explicit parameter file
- //
- shaderText = FindShaderInShaderText( strippedName );
- if ( shaderText ) {
- // enable this when building a pak file to get a global list
- // of all explicit shaders
- if ( r_printShaders->integer ) {
- ri.Printf( PRINT_ALL, "*SHADER* %s\n", name );
- }
-
- if ( !ParseShader( &shaderText ) ) {
- // had errors, so use default shader
- shader.defaultShader = qtrue;
- }
- sh = FinishShader();
- return sh;
- }
-
-
- //
- // if not defined in the in-memory shader descriptions,
- // look for a single supported image file
- //
- image = R_FindImageFile( name, mipRawImage, mipRawImage, mipRawImage ? GL_REPEAT : GL_CLAMP_TO_EDGE );
- if ( !image ) {
- ri.Printf( PRINT_DEVELOPER, "Couldn't find image file for shader %s\n", name );
- shader.defaultShader = qtrue;
- return FinishShader();
- }
-
- //
- // create the default shading commands
- //
- if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
- // dynamic colors at vertexes
- stages[0].bundle[0].image[0] = image;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
- stages[0].stateBits = GLS_DEFAULT;
- } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {
- // explicit colors at vertexes
- stages[0].bundle[0].image[0] = image;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_EXACT_VERTEX;
- stages[0].alphaGen = AGEN_SKIP;
- stages[0].stateBits = GLS_DEFAULT;
- } else if ( shader.lightmapIndex == LIGHTMAP_2D ) {
- // GUI elements
- stages[0].bundle[0].image[0] = image;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_VERTEX;
- stages[0].alphaGen = AGEN_VERTEX;
- stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
- GLS_SRCBLEND_SRC_ALPHA |
- GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
- } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {
- // fullbright level
- stages[0].bundle[0].image[0] = tr.whiteImage;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
- stages[0].stateBits = GLS_DEFAULT;
-
- stages[1].bundle[0].image[0] = image;
- stages[1].active = qtrue;
- stages[1].rgbGen = CGEN_IDENTITY;
- stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
- } else {
- // two pass lightmap
- stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
- stages[0].bundle[0].isLightmap = qtrue;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation
- // for identitylight
- stages[0].stateBits = GLS_DEFAULT;
-
- stages[1].bundle[0].image[0] = image;
- stages[1].active = qtrue;
- stages[1].rgbGen = CGEN_IDENTITY;
- stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
- }
-
- return FinishShader();
-}
-
-
-qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage) {
- int i, hash;
- shader_t *sh;
-
- hash = generateHashValue(name, FILE_HASH_SIZE);
-
- // probably not necessary since this function
- // only gets called from tr_font.c with lightmapIndex == LIGHTMAP_2D
- // but better safe than sorry.
- if ( lightmapIndex >= tr.numLightmaps ) {
- lightmapIndex = LIGHTMAP_WHITEIMAGE;
- }
-
- //
- // see if the shader is already loaded
- //
- for (sh=hashTable[hash]; sh; sh=sh->next) {
- // NOTE: if there was no shader or image available with the name strippedName
- // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
- // have to check all default shaders otherwise for every call to R_FindShader
- // with that same strippedName a new default shader is created.
- if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) &&
- // index by name
- !Q_stricmp(sh->name, name)) {
- // match found
- return sh->index;
- }
- }
-
- // make sure the render thread is stopped, because we are probably
- // going to have to upload an image
- if (r_smp->integer) {
- R_SyncRenderThread();
- }
-
- // clear the global shader
- Com_Memset( &shader, 0, sizeof( shader ) );
- Com_Memset( &stages, 0, sizeof( stages ) );
- Q_strncpyz(shader.name, name, sizeof(shader.name));
- shader.lightmapIndex = lightmapIndex;
- for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {
- stages[i].bundle[0].texMods = texMods[i];
- }
-
- // FIXME: set these "need" values apropriately
- shader.needsNormal = qtrue;
- shader.needsST1 = qtrue;
- shader.needsST2 = qtrue;
- shader.needsColor = qtrue;
-
- //
- // create the default shading commands
- //
- if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
- // dynamic colors at vertexes
- stages[0].bundle[0].image[0] = image;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
- stages[0].stateBits = GLS_DEFAULT;
- } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {
- // explicit colors at vertexes
- stages[0].bundle[0].image[0] = image;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_EXACT_VERTEX;
- stages[0].alphaGen = AGEN_SKIP;
- stages[0].stateBits = GLS_DEFAULT;
- } else if ( shader.lightmapIndex == LIGHTMAP_2D ) {
- // GUI elements
- stages[0].bundle[0].image[0] = image;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_VERTEX;
- stages[0].alphaGen = AGEN_VERTEX;
- stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
- GLS_SRCBLEND_SRC_ALPHA |
- GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
- } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {
- // fullbright level
- stages[0].bundle[0].image[0] = tr.whiteImage;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
- stages[0].stateBits = GLS_DEFAULT;
-
- stages[1].bundle[0].image[0] = image;
- stages[1].active = qtrue;
- stages[1].rgbGen = CGEN_IDENTITY;
- stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
- } else {
- // two pass lightmap
- stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
- stages[0].bundle[0].isLightmap = qtrue;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation
- // for identitylight
- stages[0].stateBits = GLS_DEFAULT;
-
- stages[1].bundle[0].image[0] = image;
- stages[1].active = qtrue;
- stages[1].rgbGen = CGEN_IDENTITY;
- stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
- }
-
- sh = FinishShader();
- return sh->index;
-}
-
-
-/*
-====================
-RE_RegisterShader
-
-This is the exported shader entry point for the rest of the system
-It will always return an index that will be valid.
-
-This should really only be used for explicit shaders, because there is no
-way to ask for different implicit lighting modes (vertex, lightmap, etc)
-====================
-*/
-qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ) {
- shader_t *sh;
-
- if ( strlen( name ) >= MAX_QPATH ) {
- Com_Printf( "Shader name exceeds MAX_QPATH\n" );
- return 0;
- }
-
- sh = R_FindShader( name, lightmapIndex, qtrue );
-
- // we want to return 0 if the shader failed to
- // load for some reason, but R_FindShader should
- // still keep a name allocated for it, so if
- // something calls RE_RegisterShader again with
- // the same name, we don't try looking for it again
- if ( sh->defaultShader ) {
- return 0;
- }
-
- return sh->index;
-}
-
-
-/*
-====================
-RE_RegisterShader
-
-This is the exported shader entry point for the rest of the system
-It will always return an index that will be valid.
-
-This should really only be used for explicit shaders, because there is no
-way to ask for different implicit lighting modes (vertex, lightmap, etc)
-====================
-*/
-qhandle_t RE_RegisterShader( const char *name ) {
- shader_t *sh;
-
- if ( strlen( name ) >= MAX_QPATH ) {
- Com_Printf( "Shader name exceeds MAX_QPATH\n" );
- return 0;
- }
-
- sh = R_FindShader( name, LIGHTMAP_2D, qtrue );
-
- // we want to return 0 if the shader failed to
- // load for some reason, but R_FindShader should
- // still keep a name allocated for it, so if
- // something calls RE_RegisterShader again with
- // the same name, we don't try looking for it again
- if ( sh->defaultShader ) {
- return 0;
- }
-
- return sh->index;
-}
-
-
-/*
-====================
-RE_RegisterShaderNoMip
-
-For menu graphics that should never be picmiped
-====================
-*/
-qhandle_t RE_RegisterShaderNoMip( const char *name ) {
- shader_t *sh;
-
- if ( strlen( name ) >= MAX_QPATH ) {
- Com_Printf( "Shader name exceeds MAX_QPATH\n" );
- return 0;
- }
-
- sh = R_FindShader( name, LIGHTMAP_2D, qfalse );
-
- // we want to return 0 if the shader failed to
- // load for some reason, but R_FindShader should
- // still keep a name allocated for it, so if
- // something calls RE_RegisterShader again with
- // the same name, we don't try looking for it again
- if ( sh->defaultShader ) {
- return 0;
- }
-
- return sh->index;
-}
-
-/*
-====================
-R_GetShaderByHandle
-
-When a handle is passed in by another module, this range checks
-it and returns a valid (possibly default) shader_t to be used internally.
-====================
-*/
-shader_t *R_GetShaderByHandle( qhandle_t hShader ) {
- if ( hShader < 0 ) {
- ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader );
- return tr.defaultShader;
- }
- if ( hShader >= tr.numShaders ) {
- ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader );
- return tr.defaultShader;
- }
- return tr.shaders[hShader];
-}
-
-/*
-===============
-R_ShaderList_f
-
-Dump information on all valid shaders to the console
-A second parameter will cause it to print in sorted order
-===============
-*/
-void R_ShaderList_f (void) {
- int i;
- int count;
- shader_t *shader;
-
- ri.Printf (PRINT_ALL, "-----------------------\n");
-
- count = 0;
- for ( i = 0 ; i < tr.numShaders ; i++ ) {
- if ( ri.Cmd_Argc() > 1 ) {
- shader = tr.sortedShaders[i];
- } else {
- shader = tr.shaders[i];
- }
-
- ri.Printf( PRINT_ALL, "%i ", shader->numUnfoggedPasses );
-
- if (shader->lightmapIndex >= 0 ) {
- ri.Printf (PRINT_ALL, "L ");
- } else {
- ri.Printf (PRINT_ALL, " ");
- }
- if ( shader->multitextureEnv == GL_ADD ) {
- ri.Printf( PRINT_ALL, "MT(a) " );
- } else if ( shader->multitextureEnv == GL_MODULATE ) {
- ri.Printf( PRINT_ALL, "MT(m) " );
- } else if ( shader->multitextureEnv == GL_DECAL ) {
- ri.Printf( PRINT_ALL, "MT(d) " );
- } else {
- ri.Printf( PRINT_ALL, " " );
- }
- if ( shader->explicitlyDefined ) {
- ri.Printf( PRINT_ALL, "E " );
- } else {
- ri.Printf( PRINT_ALL, " " );
- }
-
- if ( shader->optimalStageIteratorFunc == RB_StageIteratorGeneric ) {
- ri.Printf( PRINT_ALL, "gen " );
- } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorSky ) {
- ri.Printf( PRINT_ALL, "sky " );
- } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorLightmappedMultitexture ) {
- ri.Printf( PRINT_ALL, "lmmt" );
- } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorVertexLitTexture ) {
- ri.Printf( PRINT_ALL, "vlt " );
- } else {
- ri.Printf( PRINT_ALL, " " );
- }
-
- if ( shader->defaultShader ) {
- ri.Printf (PRINT_ALL, ": %s (DEFAULTED)\n", shader->name);
- } else {
- ri.Printf (PRINT_ALL, ": %s\n", shader->name);
- }
- count++;
- }
- ri.Printf (PRINT_ALL, "%i total shaders\n", count);
- ri.Printf (PRINT_ALL, "------------------\n");
-}
-
-
-/*
-====================
-ScanAndLoadShaderFiles
-
-Finds and loads all .shader files, combining them into
-a single large text block that can be scanned for shader names
-=====================
-*/
-#define MAX_SHADER_FILES 4096
-static void ScanAndLoadShaderFiles( void )
-{
- char **shaderFiles;
- char *buffers[MAX_SHADER_FILES];
- char *p;
- int numShaderFiles;
- int i;
- char *oldp, *token, *hashMem;
- int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size;
-
- long sum = 0, summand;
- // scan for shader files
- shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles );
-
- if ( !shaderFiles || !numShaderFiles )
- {
- ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" );
- return;
- }
-
- if ( numShaderFiles > MAX_SHADER_FILES ) {
- numShaderFiles = MAX_SHADER_FILES;
- }
-
- // load and parse shader files
- for ( i = 0; i < numShaderFiles; i++ )
- {
- char filename[MAX_QPATH];
-
- Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] );
- ri.Printf( PRINT_DEVELOPER, "...loading '%s'\n", filename );
- summand = ri.FS_ReadFile( filename, (void **)&buffers[i] );
-
- if ( !buffers[i] )
- ri.Error( ERR_DROP, "Couldn't load %s", filename );
-
- // Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders.
- p = buffers[i];
- while(1)
- {
- token = COM_ParseExt(&p, qtrue);
-
- if(!*token)
- break;
-
- oldp = p;
-
- token = COM_ParseExt(&p, qtrue);
- if(token[0] != '{' && token[1] != '\0')
- {
- ri.Printf(PRINT_WARNING, "WARNING: Bad shader file %s has incorrect syntax.\n", filename);
- ri.FS_FreeFile(buffers[i]);
- buffers[i] = NULL;
- break;
- }
-
- SkipBracedSection(&oldp);
- p = oldp;
- }
-
-
- if (buffers[i])
- sum += summand;
- }
-
- // build single large buffer
- s_shaderText = ri.Hunk_Alloc( sum + numShaderFiles*2, h_low );
- s_shaderText[ 0 ] = '\0';
-
- // free in reverse order, so the temp files are all dumped
- for ( i = numShaderFiles - 1; i >= 0 ; i-- )
- {
- if(buffers[i])
- {
- p = &s_shaderText[strlen(s_shaderText)];
- strcat( s_shaderText, buffers[i] );
- ri.FS_FreeFile( buffers[i] );
- COM_Compress(p);
- strcat( s_shaderText, "\n" );
- }
- }
-
- // free up memory
- ri.FS_FreeFileList( shaderFiles );
-
- Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
- size = 0;
-
- p = s_shaderText;
- // look for shader names
- while ( 1 ) {
- token = COM_ParseExt( &p, qtrue );
- if ( token[0] == 0 ) {
- break;
- }
-
- hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
- shaderTextHashTableSizes[hash]++;
- size++;
- SkipBracedSection(&p);
- }
-
- size += MAX_SHADERTEXT_HASH;
-
- hashMem = ri.Hunk_Alloc( size * sizeof(char *), h_low );
-
- for (i = 0; i < MAX_SHADERTEXT_HASH; i++) {
- shaderTextHashTable[i] = (char **) hashMem;
- hashMem = ((char *) hashMem) + ((shaderTextHashTableSizes[i] + 1) * sizeof(char *));
- }
-
- Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
-
- p = s_shaderText;
- // look for shader names
- while ( 1 ) {
- oldp = p;
- token = COM_ParseExt( &p, qtrue );
- if ( token[0] == 0 ) {
- break;
- }
-
- hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
- shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp;
-
- SkipBracedSection(&p);
- }
-
- return;
-
-}
-
-
-/*
-====================
-CreateInternalShaders
-====================
-*/
-static void CreateInternalShaders( void ) {
- tr.numShaders = 0;
-
- // init the default shader
- Com_Memset( &shader, 0, sizeof( shader ) );
- Com_Memset( &stages, 0, sizeof( stages ) );
-
- Q_strncpyz( shader.name, "<default>", sizeof( shader.name ) );
-
- shader.lightmapIndex = LIGHTMAP_NONE;
- stages[0].bundle[0].image[0] = tr.defaultImage;
- stages[0].active = qtrue;
- stages[0].stateBits = GLS_DEFAULT;
- tr.defaultShader = FinishShader();
-
- // shadow shader is just a marker
- Q_strncpyz( shader.name, "<stencil shadow>", sizeof( shader.name ) );
- shader.sort = SS_STENCIL_SHADOW;
- tr.shadowShader = FinishShader();
-}
-
-static void CreateExternalShaders( void ) {
- tr.projectionShadowShader = R_FindShader( "projectionShadow", LIGHTMAP_NONE, qtrue );
- tr.flareShader = R_FindShader( "flareShader", LIGHTMAP_NONE, qtrue );
-
- // Hack to make fogging work correctly on flares. Fog colors are calculated
- // in tr_flare.c already.
- if(!tr.flareShader->defaultShader)
- {
- int index;
-
- for(index = 0; index < tr.flareShader->numUnfoggedPasses; index++)
- {
- tr.flareShader->stages[index]->adjustColorsForFog = ACFF_NONE;
- tr.flareShader->stages[index]->stateBits |= GLS_DEPTHTEST_DISABLE;
- }
- }
-
- tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue );
-}
-
-/*
-==================
-R_InitShaders
-==================
-*/
-void R_InitShaders( void ) {
- ri.Printf( PRINT_ALL, "Initializing Shaders\n" );
-
- Com_Memset(hashTable, 0, sizeof(hashTable));
-
- deferLoad = qfalse;
-
- CreateInternalShaders();
-
- ScanAndLoadShaderFiles();
-
- CreateExternalShaders();
-}
diff --git a/engine/code/renderer/tr_shadows.c b/engine/code/renderer/tr_shadows.c
deleted file mode 100644
index f412b00..0000000
--- a/engine/code/renderer/tr_shadows.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "tr_local.h"
-
-
-/*
-
- for a projection shadow:
-
- point[x] += light vector * ( z - shadow plane )
- point[y] +=
- point[z] = shadow plane
-
- 1 0 light[x] / light[z]
-
-*/
-
-typedef struct {
- int i2;
- int facing;
-} edgeDef_t;
-
-#define MAX_EDGE_DEFS 32
-
-static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS];
-static int numEdgeDefs[SHADER_MAX_VERTEXES];
-static int facing[SHADER_MAX_INDEXES/3];
-
-void R_AddEdgeDef( int i1, int i2, int facing ) {
- int c;
-
- c = numEdgeDefs[ i1 ];
- if ( c == MAX_EDGE_DEFS ) {
- return; // overflow
- }
- edgeDefs[ i1 ][ c ].i2 = i2;
- edgeDefs[ i1 ][ c ].facing = facing;
-
- numEdgeDefs[ i1 ]++;
-}
-
-void R_RenderShadowEdges( void ) {
- int i;
-
-#if 0
- int numTris;
-
- // dumb way -- render every triangle's edges
- numTris = tess.numIndexes / 3;
-
- for ( i = 0 ; i < numTris ; i++ ) {
- int i1, i2, i3;
-
- if ( !facing[i] ) {
- continue;
- }
-
- i1 = tess.indexes[ i*3 + 0 ];
- i2 = tess.indexes[ i*3 + 1 ];
- i3 = tess.indexes[ i*3 + 2 ];
-
- qglBegin( GL_TRIANGLE_STRIP );
- qglVertex3fv( tess.xyz[ i1 ] );
- qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] );
- qglVertex3fv( tess.xyz[ i2 ] );
- qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] );
- qglVertex3fv( tess.xyz[ i3 ] );
- qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] );
- qglVertex3fv( tess.xyz[ i1 ] );
- qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] );
- qglEnd();
- }
-#else
- int c, c2;
- int j, k;
- int i2;
- int c_edges, c_rejected;
- int hit[2];
-
- // an edge is NOT a silhouette edge if its face doesn't face the light,
- // or if it has a reverse paired edge that also faces the light.
- // A well behaved polyhedron would have exactly two faces for each edge,
- // but lots of models have dangling edges or overfanned edges
- c_edges = 0;
- c_rejected = 0;
-
- for ( i = 0 ; i < tess.numVertexes ; i++ ) {
- c = numEdgeDefs[ i ];
- for ( j = 0 ; j < c ; j++ ) {
- if ( !edgeDefs[ i ][ j ].facing ) {
- continue;
- }
-
- hit[0] = 0;
- hit[1] = 0;
-
- i2 = edgeDefs[ i ][ j ].i2;
- c2 = numEdgeDefs[ i2 ];
- for ( k = 0 ; k < c2 ; k++ ) {
- if ( edgeDefs[ i2 ][ k ].i2 == i ) {
- hit[ edgeDefs[ i2 ][ k ].facing ]++;
- }
- }
-
- // if it doesn't share the edge with another front facing
- // triangle, it is a sil edge
- if ( hit[ 1 ] == 0 ) {
- qglBegin( GL_TRIANGLE_STRIP );
- qglVertex3fv( tess.xyz[ i ] );
- qglVertex3fv( tess.xyz[ i + tess.numVertexes ] );
- qglVertex3fv( tess.xyz[ i2 ] );
- qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] );
- qglEnd();
- c_edges++;
- } else {
- c_rejected++;
- }
- }
- }
-#endif
-}
-
-/*
-=================
-RB_ShadowTessEnd
-
-triangleFromEdge[ v1 ][ v2 ]
-
-
- set triangle from edge( v1, v2, tri )
- if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) {
- }
-=================
-*/
-void RB_ShadowTessEnd( void ) {
- int i;
- int numTris;
- vec3_t lightDir;
- GLboolean rgba[4];
-
- // we can only do this if we have enough space in the vertex buffers
- if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) {
- return;
- }
-
- if ( glConfig.stencilBits < 4 ) {
- return;
- }
-
- VectorCopy( backEnd.currentEntity->lightDir, lightDir );
-
- // project vertexes away from light direction
- for ( i = 0 ; i < tess.numVertexes ; i++ ) {
- VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] );
- }
-
- // decide which triangles face the light
- Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes );
-
- numTris = tess.numIndexes / 3;
- for ( i = 0 ; i < numTris ; i++ ) {
- int i1, i2, i3;
- vec3_t d1, d2, normal;
- float *v1, *v2, *v3;
- float d;
-
- i1 = tess.indexes[ i*3 + 0 ];
- i2 = tess.indexes[ i*3 + 1 ];
- i3 = tess.indexes[ i*3 + 2 ];
-
- v1 = tess.xyz[ i1 ];
- v2 = tess.xyz[ i2 ];
- v3 = tess.xyz[ i3 ];
-
- VectorSubtract( v2, v1, d1 );
- VectorSubtract( v3, v1, d2 );
- CrossProduct( d1, d2, normal );
-
- d = DotProduct( normal, lightDir );
- if ( d > 0 ) {
- facing[ i ] = 1;
- } else {
- facing[ i ] = 0;
- }
-
- // create the edges
- R_AddEdgeDef( i1, i2, facing[ i ] );
- R_AddEdgeDef( i2, i3, facing[ i ] );
- R_AddEdgeDef( i3, i1, facing[ i ] );
- }
-
- // draw the silhouette edges
-
- GL_Bind( tr.whiteImage );
- qglEnable( GL_CULL_FACE );
- GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
- qglColor3f( 0.2f, 0.2f, 0.2f );
-
- // don't write to the color buffer
- qglGetBooleanv(GL_COLOR_WRITEMASK, rgba);
- qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
-
- qglEnable( GL_STENCIL_TEST );
- qglStencilFunc( GL_ALWAYS, 1, 255 );
-
- // mirrors have the culling order reversed
- if ( backEnd.viewParms.isMirror ) {
- qglCullFace( GL_FRONT );
- qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
-
- R_RenderShadowEdges();
-
- qglCullFace( GL_BACK );
- qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
-
- R_RenderShadowEdges();
- } else {
- qglCullFace( GL_BACK );
- qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
-
- R_RenderShadowEdges();
-
- qglCullFace( GL_FRONT );
- qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
-
- R_RenderShadowEdges();
- }
-
-
- // reenable writing to the color buffer
- qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]);
-}
-
-
-/*
-=================
-RB_ShadowFinish
-
-Darken everything that is is a shadow volume.
-We have to delay this until everything has been shadowed,
-because otherwise shadows from different body parts would
-overlap and double darken.
-=================
-*/
-void RB_ShadowFinish( void ) {
- if ( r_shadows->integer != 2 ) {
- return;
- }
- if ( glConfig.stencilBits < 4 ) {
- return;
- }
- qglEnable( GL_STENCIL_TEST );
- qglStencilFunc( GL_NOTEQUAL, 0, 255 );
-
- qglDisable (GL_CLIP_PLANE0);
- qglDisable (GL_CULL_FACE);
-
- GL_Bind( tr.whiteImage );
-
- qglLoadIdentity ();
-
- qglColor3f( 0.6f, 0.6f, 0.6f );
- GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO );
-
-// qglColor3f( 1, 0, 0 );
-// GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
-
- qglBegin( GL_QUADS );
- qglVertex3f( -100, 100, -10 );
- qglVertex3f( 100, 100, -10 );
- qglVertex3f( 100, -100, -10 );
- qglVertex3f( -100, -100, -10 );
- qglEnd ();
-
- qglColor4f(1,1,1,1);
- qglDisable( GL_STENCIL_TEST );
-}
-
-
-/*
-=================
-RB_ProjectionShadowDeform
-
-=================
-*/
-void RB_ProjectionShadowDeform( void ) {
- float *xyz;
- int i;
- float h;
- vec3_t ground;
- vec3_t light;
- float groundDist;
- float d;
- vec3_t lightDir;
-
- xyz = ( float * ) tess.xyz;
-
- ground[0] = backEnd.or.axis[0][2];
- ground[1] = backEnd.or.axis[1][2];
- ground[2] = backEnd.or.axis[2][2];
-
- groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane;
-
- VectorCopy( backEnd.currentEntity->lightDir, lightDir );
- d = DotProduct( lightDir, ground );
- // don't let the shadows get too long or go negative
- if ( d < 0.5 ) {
- VectorMA( lightDir, (0.5 - d), ground, lightDir );
- d = DotProduct( lightDir, ground );
- }
- d = 1.0 / d;
-
- light[0] = lightDir[0] * d;
- light[1] = lightDir[1] * d;
- light[2] = lightDir[2] * d;
-
- for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
- h = DotProduct( xyz, ground ) + groundDist;
-
- xyz[0] -= light[0] * h;
- xyz[1] -= light[1] * h;
- xyz[2] -= light[2] * h;
- }
-}
diff --git a/engine/code/renderer/tr_sky.c b/engine/code/renderer/tr_sky.c
deleted file mode 100644
index 02624f3..0000000
--- a/engine/code/renderer/tr_sky.c
+++ /dev/null
@@ -1,845 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_sky.c
-#include "tr_local.h"
-
-#define SKY_SUBDIVISIONS 8
-#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2)
-
-static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
-static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
-
-/*
-===================================================================================
-
-POLYGON TO BOX SIDE PROJECTION
-
-===================================================================================
-*/
-
-static vec3_t sky_clip[6] =
-{
- {1,1,0},
- {1,-1,0},
- {0,-1,1},
- {0,1,1},
- {1,0,1},
- {-1,0,1}
-};
-
-static float sky_mins[2][6], sky_maxs[2][6];
-static float sky_min, sky_max;
-
-/*
-================
-AddSkyPolygon
-================
-*/
-static void AddSkyPolygon (int nump, vec3_t vecs)
-{
- int i,j;
- vec3_t v, av;
- float s, t, dv;
- int axis;
- float *vp;
- // s = [0]/[2], t = [1]/[2]
- static int vec_to_st[6][3] =
- {
- {-2,3,1},
- {2,3,-1},
-
- {1,3,2},
- {-1,3,-2},
-
- {-2,-1,3},
- {-2,1,-3}
-
- // {-1,2,3},
- // {1,2,-3}
- };
-
- // decide which face it maps to
- VectorCopy (vec3_origin, v);
- for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
- {
- VectorAdd (vp, v, v);
- }
- av[0] = fabs(v[0]);
- av[1] = fabs(v[1]);
- av[2] = fabs(v[2]);
- if (av[0] > av[1] && av[0] > av[2])
- {
- if (v[0] < 0)
- axis = 1;
- else
- axis = 0;
- }
- else if (av[1] > av[2] && av[1] > av[0])
- {
- if (v[1] < 0)
- axis = 3;
- else
- axis = 2;
- }
- else
- {
- if (v[2] < 0)
- axis = 5;
- else
- axis = 4;
- }
-
- // project new texture coords
- for (i=0 ; i<nump ; i++, vecs+=3)
- {
- j = vec_to_st[axis][2];
- if (j > 0)
- dv = vecs[j - 1];
- else
- dv = -vecs[-j - 1];
- if (dv < 0.001)
- continue; // don't divide by zero
- j = vec_to_st[axis][0];
- if (j < 0)
- s = -vecs[-j -1] / dv;
- else
- s = vecs[j-1] / dv;
- j = vec_to_st[axis][1];
- if (j < 0)
- t = -vecs[-j -1] / dv;
- else
- t = vecs[j-1] / dv;
-
- if (s < sky_mins[0][axis])
- sky_mins[0][axis] = s;
- if (t < sky_mins[1][axis])
- sky_mins[1][axis] = t;
- if (s > sky_maxs[0][axis])
- sky_maxs[0][axis] = s;
- if (t > sky_maxs[1][axis])
- sky_maxs[1][axis] = t;
- }
-}
-
-#define ON_EPSILON 0.1f // point on plane side epsilon
-#define MAX_CLIP_VERTS 64
-/*
-================
-ClipSkyPolygon
-================
-*/
-static void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
-{
- float *norm;
- float *v;
- qboolean front, back;
- float d, e;
- float dists[MAX_CLIP_VERTS];
- int sides[MAX_CLIP_VERTS];
- vec3_t newv[2][MAX_CLIP_VERTS];
- int newc[2];
- int i, j;
-
- if (nump > MAX_CLIP_VERTS-2)
- ri.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS");
- if (stage == 6)
- { // fully clipped, so draw it
- AddSkyPolygon (nump, vecs);
- return;
- }
-
- front = back = qfalse;
- norm = sky_clip[stage];
- for (i=0, v = vecs ; i<nump ; i++, v+=3)
- {
- d = DotProduct (v, norm);
- if (d > ON_EPSILON)
- {
- front = qtrue;
- sides[i] = SIDE_FRONT;
- }
- else if (d < -ON_EPSILON)
- {
- back = qtrue;
- sides[i] = SIDE_BACK;
- }
- else
- sides[i] = SIDE_ON;
- dists[i] = d;
- }
-
- if (!front || !back)
- { // not clipped
- ClipSkyPolygon (nump, vecs, stage+1);
- return;
- }
-
- // clip it
- sides[i] = sides[0];
- dists[i] = dists[0];
- VectorCopy (vecs, (vecs+(i*3)) );
- newc[0] = newc[1] = 0;
-
- for (i=0, v = vecs ; i<nump ; i++, v+=3)
- {
- switch (sides[i])
- {
- case SIDE_FRONT:
- VectorCopy (v, newv[0][newc[0]]);
- newc[0]++;
- break;
- case SIDE_BACK:
- VectorCopy (v, newv[1][newc[1]]);
- newc[1]++;
- break;
- case SIDE_ON:
- VectorCopy (v, newv[0][newc[0]]);
- newc[0]++;
- VectorCopy (v, newv[1][newc[1]]);
- newc[1]++;
- break;
- }
-
- if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- d = dists[i] / (dists[i] - dists[i+1]);
- for (j=0 ; j<3 ; j++)
- {
- e = v[j] + d*(v[j+3] - v[j]);
- newv[0][newc[0]][j] = e;
- newv[1][newc[1]][j] = e;
- }
- newc[0]++;
- newc[1]++;
- }
-
- // continue
- ClipSkyPolygon (newc[0], newv[0][0], stage+1);
- ClipSkyPolygon (newc[1], newv[1][0], stage+1);
-}
-
-/*
-==============
-ClearSkyBox
-==============
-*/
-static void ClearSkyBox (void) {
- int i;
-
- for (i=0 ; i<6 ; i++) {
- sky_mins[0][i] = sky_mins[1][i] = 9999;
- sky_maxs[0][i] = sky_maxs[1][i] = -9999;
- }
-}
-
-/*
-================
-RB_ClipSkyPolygons
-================
-*/
-void RB_ClipSkyPolygons( shaderCommands_t *input )
-{
- vec3_t p[5]; // need one extra point for clipping
- int i, j;
-
- ClearSkyBox();
-
- for ( i = 0; i < input->numIndexes; i += 3 )
- {
- for (j = 0 ; j < 3 ; j++)
- {
- VectorSubtract( input->xyz[input->indexes[i+j]],
- backEnd.viewParms.or.origin,
- p[j] );
- }
- ClipSkyPolygon( 3, p[0], 0 );
- }
-}
-
-/*
-===================================================================================
-
-CLOUD VERTEX GENERATION
-
-===================================================================================
-*/
-
-/*
-** MakeSkyVec
-**
-** Parms: s, t range from -1 to 1
-*/
-static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ )
-{
- // 1 = s, 2 = t, 3 = 2048
- static int st_to_vec[6][3] =
- {
- {3,-1,2},
- {-3,1,2},
-
- {1,3,2},
- {-1,-3,2},
-
- {-2,-1,3}, // 0 degrees yaw, look straight up
- {2,-1,-3} // look straight down
- };
-
- vec3_t b;
- int j, k;
- float boxSize;
-
- boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
- b[0] = s*boxSize;
- b[1] = t*boxSize;
- b[2] = boxSize;
-
- for (j=0 ; j<3 ; j++)
- {
- k = st_to_vec[axis][j];
- if (k < 0)
- {
- outXYZ[j] = -b[-k - 1];
- }
- else
- {
- outXYZ[j] = b[k - 1];
- }
- }
-
- // avoid bilerp seam
- s = (s+1)*0.5;
- t = (t+1)*0.5;
- if (s < sky_min)
- {
- s = sky_min;
- }
- else if (s > sky_max)
- {
- s = sky_max;
- }
-
- if (t < sky_min)
- {
- t = sky_min;
- }
- else if (t > sky_max)
- {
- t = sky_max;
- }
-
- t = 1.0 - t;
-
-
- if ( outSt )
- {
- outSt[0] = s;
- outSt[1] = t;
- }
-}
-
-static int sky_texorder[6] = {0,2,1,3,4,5};
-static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
-static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
-
-static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )
-{
- int s, t;
-
- GL_Bind( image );
-
- for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
- {
- qglBegin( GL_TRIANGLE_STRIP );
-
- for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
- {
- qglTexCoord2fv( s_skyTexCoords[t][s] );
- qglVertex3fv( s_skyPoints[t][s] );
-
- qglTexCoord2fv( s_skyTexCoords[t+1][s] );
- qglVertex3fv( s_skyPoints[t+1][s] );
- }
-
- qglEnd();
- }
-}
-
-static void DrawSkyBox( shader_t *shader )
-{
- int i;
-
- sky_min = 0;
- sky_max = 1;
-
- Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) );
-
- for (i=0 ; i<6 ; i++)
- {
- int sky_mins_subd[2], sky_maxs_subd[2];
- int s, t;
-
- sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
-
- if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
- ( sky_mins[1][i] >= sky_maxs[1][i] ) )
- {
- continue;
- }
-
- sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS;
- sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS;
- sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS;
- sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS;
-
- if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
- if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
-
- if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
- if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
-
- //
- // iterate through the subdivisions
- //
- for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
- {
- for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
- {
- MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- i,
- s_skyTexCoords[t][s],
- s_skyPoints[t][s] );
- }
- }
-
- DrawSkySide( shader->sky.outerbox[sky_texorder[i]],
- sky_mins_subd,
- sky_maxs_subd );
- }
-
-}
-
-static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes )
-{
- int s, t;
- int vertexStart = tess.numVertexes;
- int tHeight, sWidth;
-
- tHeight = maxs[1] - mins[1] + 1;
- sWidth = maxs[0] - mins[0] + 1;
-
- for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
- {
- for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
- {
- VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0];
- tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1];
-
- tess.numVertexes++;
-
- if ( tess.numVertexes >= SHADER_MAX_VERTEXES )
- {
- ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()\n" );
- }
- }
- }
-
- // only add indexes for one pass, otherwise it would draw multiple times for each pass
- if ( addIndexes ) {
- for ( t = 0; t < tHeight-1; t++ )
- {
- for ( s = 0; s < sWidth-1; s++ )
- {
- tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth );
- tess.numIndexes++;
- tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
- tess.numIndexes++;
- tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
- tess.numIndexes++;
-
- tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
- tess.numIndexes++;
- tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth );
- tess.numIndexes++;
- tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
- tess.numIndexes++;
- }
- }
- }
-}
-
-static void FillCloudBox( const shader_t *shader, int stage )
-{
- int i;
-
- for ( i =0; i < 6; i++ )
- {
- int sky_mins_subd[2], sky_maxs_subd[2];
- int s, t;
- float MIN_T;
-
- if ( 1 ) // FIXME? shader->sky.fullClouds )
- {
- MIN_T = -HALF_SKY_SUBDIVISIONS;
-
- // still don't want to draw the bottom, even if fullClouds
- if ( i == 5 )
- continue;
- }
- else
- {
- switch( i )
- {
- case 0:
- case 1:
- case 2:
- case 3:
- MIN_T = -1;
- break;
- case 5:
- // don't draw clouds beneath you
- continue;
- case 4: // top
- default:
- MIN_T = -HALF_SKY_SUBDIVISIONS;
- break;
- }
- }
-
- sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
-
- if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
- ( sky_mins[1][i] >= sky_maxs[1][i] ) )
- {
- continue;
- }
-
- sky_mins_subd[0] = myftol( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS );
- sky_mins_subd[1] = myftol( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS );
- sky_maxs_subd[0] = myftol( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS );
- sky_maxs_subd[1] = myftol( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS );
-
- if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
- if ( sky_mins_subd[1] < MIN_T )
- sky_mins_subd[1] = MIN_T;
- else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
-
- if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
- if ( sky_maxs_subd[1] < MIN_T )
- sky_maxs_subd[1] = MIN_T;
- else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
-
- //
- // iterate through the subdivisions
- //
- for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
- {
- for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
- {
- MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- i,
- NULL,
- s_skyPoints[t][s] );
-
- s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0];
- s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1];
- }
- }
-
- // only add indexes for first stage
- FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) );
- }
-}
-
-/*
-** R_BuildCloudData
-*/
-void R_BuildCloudData( shaderCommands_t *input )
-{
- int i;
- shader_t *shader;
-
- shader = input->shader;
-
- assert( shader->isSky );
-
- sky_min = 1.0 / 256.0f; // FIXME: not correct?
- sky_max = 255.0 / 256.0f;
-
- // set up for drawing
- tess.numIndexes = 0;
- tess.numVertexes = 0;
-
- if ( input->shader->sky.cloudHeight )
- {
- for ( i = 0; i < MAX_SHADER_STAGES; i++ )
- {
- if ( !tess.xstages[i] ) {
- break;
- }
- FillCloudBox( input->shader, i );
- }
- }
-}
-
-/*
-** R_InitSkyTexCoords
-** Called when a sky shader is parsed
-*/
-#define SQR( a ) ((a)*(a))
-void R_InitSkyTexCoords( float heightCloud )
-{
- int i, s, t;
- float radiusWorld = 4096;
- float p;
- float sRad, tRad;
- vec3_t skyVec;
- vec3_t v;
-
- // init zfar so MakeSkyVec works even though
- // a world hasn't been bounded
- backEnd.viewParms.zFar = 1024;
-
- for ( i = 0; i < 6; i++ )
- {
- for ( t = 0; t <= SKY_SUBDIVISIONS; t++ )
- {
- for ( s = 0; s <= SKY_SUBDIVISIONS; s++ )
- {
- // compute vector from view origin to sky side integral point
- MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- i,
- NULL,
- skyVec );
-
- // compute parametric value 'p' that intersects with cloud layer
- p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) *
- ( -2 * skyVec[2] * radiusWorld +
- 2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) +
- 2 * SQR( skyVec[0] ) * radiusWorld * heightCloud +
- SQR( skyVec[0] ) * SQR( heightCloud ) +
- 2 * SQR( skyVec[1] ) * radiusWorld * heightCloud +
- SQR( skyVec[1] ) * SQR( heightCloud ) +
- 2 * SQR( skyVec[2] ) * radiusWorld * heightCloud +
- SQR( skyVec[2] ) * SQR( heightCloud ) ) );
-
- s_cloudTexP[i][t][s] = p;
-
- // compute intersection point based on p
- VectorScale( skyVec, p, v );
- v[2] += radiusWorld;
-
- // compute vector from world origin to intersection point 'v'
- VectorNormalize( v );
-
- sRad = Q_acos( v[0] );
- tRad = Q_acos( v[1] );
-
- s_cloudTexCoords[i][t][s][0] = sRad;
- s_cloudTexCoords[i][t][s][1] = tRad;
- }
- }
- }
-}
-
-//======================================================================================
-
-/*
-** RB_DrawSun
-*/
-void RB_DrawSun( void ) {
- float size;
- float dist;
- vec3_t origin, vec1, vec2;
- vec3_t temp;
-
- if ( !backEnd.skyRenderedThisView ) {
- return;
- }
- if ( !r_drawSun->integer ) {
- return;
- }
- qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
- qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
-
- dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
- size = dist * 0.4;
-
- VectorScale( tr.sunDirection, dist, origin );
- PerpendicularVector( vec1, tr.sunDirection );
- CrossProduct( tr.sunDirection, vec1, vec2 );
-
- VectorScale( vec1, size, vec1 );
- VectorScale( vec2, size, vec2 );
-
- // farthest depth range
- qglDepthRange( 1.0, 1.0 );
-
- // FIXME: use quad stamp
- RB_BeginSurface( tr.sunShader, tess.fogNum );
- VectorCopy( origin, temp );
- VectorSubtract( temp, vec1, temp );
- VectorSubtract( temp, vec2, temp );
- VectorCopy( temp, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = 255;
- tess.vertexColors[tess.numVertexes][1] = 255;
- tess.vertexColors[tess.numVertexes][2] = 255;
- tess.numVertexes++;
-
- VectorCopy( origin, temp );
- VectorAdd( temp, vec1, temp );
- VectorSubtract( temp, vec2, temp );
- VectorCopy( temp, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = 255;
- tess.vertexColors[tess.numVertexes][1] = 255;
- tess.vertexColors[tess.numVertexes][2] = 255;
- tess.numVertexes++;
-
- VectorCopy( origin, temp );
- VectorAdd( temp, vec1, temp );
- VectorAdd( temp, vec2, temp );
- VectorCopy( temp, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 1;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = 255;
- tess.vertexColors[tess.numVertexes][1] = 255;
- tess.vertexColors[tess.numVertexes][2] = 255;
- tess.numVertexes++;
-
- VectorCopy( origin, temp );
- VectorSubtract( temp, vec1, temp );
- VectorAdd( temp, vec2, temp );
- VectorCopy( temp, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 1;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = 255;
- tess.vertexColors[tess.numVertexes][1] = 255;
- tess.vertexColors[tess.numVertexes][2] = 255;
- tess.numVertexes++;
-
- tess.indexes[tess.numIndexes++] = 0;
- tess.indexes[tess.numIndexes++] = 1;
- tess.indexes[tess.numIndexes++] = 2;
- tess.indexes[tess.numIndexes++] = 0;
- tess.indexes[tess.numIndexes++] = 2;
- tess.indexes[tess.numIndexes++] = 3;
-
- RB_EndSurface();
-
- // back to normal depth range
- qglDepthRange( 0.0, 1.0 );
-}
-
-
-
-
-/*
-================
-RB_StageIteratorSky
-
-All of the visible sky triangles are in tess
-
-Other things could be stuck in here, like birds in the sky, etc
-================
-*/
-void RB_StageIteratorSky( void ) {
- if ( r_fastsky->integer ) {
- return;
- }
-
- // go through all the polygons and project them onto
- // the sky box to see which blocks on each side need
- // to be drawn
- RB_ClipSkyPolygons( &tess );
-
- // r_showsky will let all the sky blocks be drawn in
- // front of everything to allow developers to see how
- // much sky is getting sucked in
- if ( r_showsky->integer ) {
- qglDepthRange( 0.0, 0.0 );
- } else {
- qglDepthRange( 1.0, 1.0 );
- }
-
- // draw the outer skybox
- if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {
- qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );
-
- qglPushMatrix ();
- GL_State( 0 );
- qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
-
- DrawSkyBox( tess.shader );
-
- qglPopMatrix();
- }
-
- // generate the vertexes for all the clouds, which will be drawn
- // by the generic shader routine
- R_BuildCloudData( &tess );
-
- RB_StageIteratorGeneric();
-
- // draw the inner skybox
-
-
- // back to normal depth range
- qglDepthRange( 0.0, 1.0 );
-
- // note that sky was drawn so we will draw a sun later
- backEnd.skyRenderedThisView = qtrue;
-}
-
diff --git a/engine/code/renderer/tr_surface.c b/engine/code/renderer/tr_surface.c
deleted file mode 100644
index 1365569..0000000
--- a/engine/code/renderer/tr_surface.c
+++ /dev/null
@@ -1,1248 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_surf.c
-#include "tr_local.h"
-#if idppc_altivec && !defined(MACOS_X)
-#include <altivec.h>
-#endif
-
-/*
-
- THIS ENTIRE FILE IS BACK END
-
-backEnd.currentEntity will be valid.
-
-Tess_Begin has already been called for the surface's shader.
-
-The modelview matrix will be set.
-
-It is safe to actually issue drawing commands here if you don't want to
-use the shader system.
-*/
-
-
-//============================================================================
-
-
-/*
-==============
-RB_CheckOverflow
-==============
-*/
-void RB_CheckOverflow( int verts, int indexes ) {
- if (tess.numVertexes + verts < SHADER_MAX_VERTEXES
- && tess.numIndexes + indexes < SHADER_MAX_INDEXES) {
- return;
- }
-
- RB_EndSurface();
-
- if ( verts >= SHADER_MAX_VERTEXES ) {
- ri.Error(ERR_DROP, "RB_CheckOverflow: verts > MAX (%d > %d)", verts, SHADER_MAX_VERTEXES );
- }
- if ( indexes >= SHADER_MAX_INDEXES ) {
- ri.Error(ERR_DROP, "RB_CheckOverflow: indices > MAX (%d > %d)", indexes, SHADER_MAX_INDEXES );
- }
-
- RB_BeginSurface(tess.shader, tess.fogNum );
-}
-
-
-/*
-==============
-RB_AddQuadStampExt
-==============
-*/
-void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 ) {
- vec3_t normal;
- int ndx;
-
- RB_CHECKOVERFLOW( 4, 6 );
-
- ndx = tess.numVertexes;
-
- // triangle indexes for a simple quad
- tess.indexes[ tess.numIndexes ] = ndx;
- tess.indexes[ tess.numIndexes + 1 ] = ndx + 1;
- tess.indexes[ tess.numIndexes + 2 ] = ndx + 3;
-
- tess.indexes[ tess.numIndexes + 3 ] = ndx + 3;
- tess.indexes[ tess.numIndexes + 4 ] = ndx + 1;
- tess.indexes[ tess.numIndexes + 5 ] = ndx + 2;
-
- tess.xyz[ndx][0] = origin[0] + left[0] + up[0];
- tess.xyz[ndx][1] = origin[1] + left[1] + up[1];
- tess.xyz[ndx][2] = origin[2] + left[2] + up[2];
-
- tess.xyz[ndx+1][0] = origin[0] - left[0] + up[0];
- tess.xyz[ndx+1][1] = origin[1] - left[1] + up[1];
- tess.xyz[ndx+1][2] = origin[2] - left[2] + up[2];
-
- tess.xyz[ndx+2][0] = origin[0] - left[0] - up[0];
- tess.xyz[ndx+2][1] = origin[1] - left[1] - up[1];
- tess.xyz[ndx+2][2] = origin[2] - left[2] - up[2];
-
- tess.xyz[ndx+3][0] = origin[0] + left[0] - up[0];
- tess.xyz[ndx+3][1] = origin[1] + left[1] - up[1];
- tess.xyz[ndx+3][2] = origin[2] + left[2] - up[2];
-
-
- // constant normal all the way around
- VectorSubtract( vec3_origin, backEnd.viewParms.or.axis[0], normal );
-
- tess.normal[ndx][0] = tess.normal[ndx+1][0] = tess.normal[ndx+2][0] = tess.normal[ndx+3][0] = normal[0];
- tess.normal[ndx][1] = tess.normal[ndx+1][1] = tess.normal[ndx+2][1] = tess.normal[ndx+3][1] = normal[1];
- tess.normal[ndx][2] = tess.normal[ndx+1][2] = tess.normal[ndx+2][2] = tess.normal[ndx+3][2] = normal[2];
-
- // standard square texture coordinates
- tess.texCoords[ndx][0][0] = tess.texCoords[ndx][1][0] = s1;
- tess.texCoords[ndx][0][1] = tess.texCoords[ndx][1][1] = t1;
-
- tess.texCoords[ndx+1][0][0] = tess.texCoords[ndx+1][1][0] = s2;
- tess.texCoords[ndx+1][0][1] = tess.texCoords[ndx+1][1][1] = t1;
-
- tess.texCoords[ndx+2][0][0] = tess.texCoords[ndx+2][1][0] = s2;
- tess.texCoords[ndx+2][0][1] = tess.texCoords[ndx+2][1][1] = t2;
-
- tess.texCoords[ndx+3][0][0] = tess.texCoords[ndx+3][1][0] = s1;
- tess.texCoords[ndx+3][0][1] = tess.texCoords[ndx+3][1][1] = t2;
-
- // constant color all the way around
- // should this be identity and let the shader specify from entity?
- * ( unsigned int * ) &tess.vertexColors[ndx] =
- * ( unsigned int * ) &tess.vertexColors[ndx+1] =
- * ( unsigned int * ) &tess.vertexColors[ndx+2] =
- * ( unsigned int * ) &tess.vertexColors[ndx+3] =
- * ( unsigned int * )color;
-
-
- tess.numVertexes += 4;
- tess.numIndexes += 6;
-}
-
-/*
-==============
-RB_AddQuadStamp
-==============
-*/
-void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color ) {
- RB_AddQuadStampExt( origin, left, up, color, 0, 0, 1, 1 );
-}
-
-/*
-==============
-RB_SurfaceSprite
-==============
-*/
-static void RB_SurfaceSprite( void ) {
- vec3_t left, up;
- float radius;
-
- // calculate the xyz locations for the four corners
- radius = backEnd.currentEntity->e.radius;
- if ( backEnd.currentEntity->e.rotation == 0 ) {
- VectorScale( backEnd.viewParms.or.axis[1], radius, left );
- VectorScale( backEnd.viewParms.or.axis[2], radius, up );
- } else {
- float s, c;
- float ang;
-
- ang = M_PI * backEnd.currentEntity->e.rotation / 180;
- s = sin( ang );
- c = cos( ang );
-
- VectorScale( backEnd.viewParms.or.axis[1], c * radius, left );
- VectorMA( left, -s * radius, backEnd.viewParms.or.axis[2], left );
-
- VectorScale( backEnd.viewParms.or.axis[2], c * radius, up );
- VectorMA( up, s * radius, backEnd.viewParms.or.axis[1], up );
- }
- if ( backEnd.viewParms.isMirror ) {
- VectorSubtract( vec3_origin, left, left );
- }
-
- RB_AddQuadStamp( backEnd.currentEntity->e.origin, left, up, backEnd.currentEntity->e.shaderRGBA );
-}
-
-
-/*
-=============
-RB_SurfacePolychain
-=============
-*/
-static void RB_SurfacePolychain( srfPoly_t *p ) {
- int i;
- int numv;
-
- RB_CHECKOVERFLOW( p->numVerts, 3*(p->numVerts - 2) );
-
- // fan triangles into the tess array
- numv = tess.numVertexes;
- for ( i = 0; i < p->numVerts; i++ ) {
- VectorCopy( p->verts[i].xyz, tess.xyz[numv] );
- tess.texCoords[numv][0][0] = p->verts[i].st[0];
- tess.texCoords[numv][0][1] = p->verts[i].st[1];
- *(int *)&tess.vertexColors[numv] = *(int *)p->verts[ i ].modulate;
-
- numv++;
- }
-
- // generate fan indexes into the tess array
- for ( i = 0; i < p->numVerts-2; i++ ) {
- tess.indexes[tess.numIndexes + 0] = tess.numVertexes;
- tess.indexes[tess.numIndexes + 1] = tess.numVertexes + i + 1;
- tess.indexes[tess.numIndexes + 2] = tess.numVertexes + i + 2;
- tess.numIndexes += 3;
- }
-
- tess.numVertexes = numv;
-}
-
-
-/*
-=============
-RB_SurfaceTriangles
-=============
-*/
-static void RB_SurfaceTriangles( srfTriangles_t *srf ) {
- int i;
- drawVert_t *dv;
- float *xyz, *normal, *texCoords;
- byte *color;
- int dlightBits;
- qboolean needsNormal;
-
- dlightBits = srf->dlightBits[backEnd.smpFrame];
- tess.dlightBits |= dlightBits;
-
- RB_CHECKOVERFLOW( srf->numVerts, srf->numIndexes );
-
- for ( i = 0 ; i < srf->numIndexes ; i += 3 ) {
- tess.indexes[ tess.numIndexes + i + 0 ] = tess.numVertexes + srf->indexes[ i + 0 ];
- tess.indexes[ tess.numIndexes + i + 1 ] = tess.numVertexes + srf->indexes[ i + 1 ];
- tess.indexes[ tess.numIndexes + i + 2 ] = tess.numVertexes + srf->indexes[ i + 2 ];
- }
- tess.numIndexes += srf->numIndexes;
-
- dv = srf->verts;
- xyz = tess.xyz[ tess.numVertexes ];
- normal = tess.normal[ tess.numVertexes ];
- texCoords = tess.texCoords[ tess.numVertexes ][0];
- color = tess.vertexColors[ tess.numVertexes ];
- needsNormal = tess.shader->needsNormal;
-
- for ( i = 0 ; i < srf->numVerts ; i++, dv++, xyz += 4, normal += 4, texCoords += 4, color += 4 ) {
- xyz[0] = dv->xyz[0];
- xyz[1] = dv->xyz[1];
- xyz[2] = dv->xyz[2];
-
- if ( needsNormal ) {
- normal[0] = dv->normal[0];
- normal[1] = dv->normal[1];
- normal[2] = dv->normal[2];
- }
-
- texCoords[0] = dv->st[0];
- texCoords[1] = dv->st[1];
-
- texCoords[2] = dv->lightmap[0];
- texCoords[3] = dv->lightmap[1];
-
- *(int *)color = *(int *)dv->color;
- }
-
- for ( i = 0 ; i < srf->numVerts ; i++ ) {
- tess.vertexDlightBits[ tess.numVertexes + i] = dlightBits;
- }
-
- tess.numVertexes += srf->numVerts;
-}
-
-
-
-/*
-==============
-RB_SurfaceBeam
-==============
-*/
-static void RB_SurfaceBeam( void )
-{
-#define NUM_BEAM_SEGS 6
- refEntity_t *e;
- int i;
- vec3_t perpvec;
- vec3_t direction, normalized_direction;
- vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
- vec3_t oldorigin, origin;
-
- e = &backEnd.currentEntity->e;
-
- oldorigin[0] = e->oldorigin[0];
- oldorigin[1] = e->oldorigin[1];
- oldorigin[2] = e->oldorigin[2];
-
- origin[0] = e->origin[0];
- origin[1] = e->origin[1];
- origin[2] = e->origin[2];
-
- normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
- normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
- normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
-
- if ( VectorNormalize( normalized_direction ) == 0 )
- return;
-
- PerpendicularVector( perpvec, normalized_direction );
-
- VectorScale( perpvec, 4, perpvec );
-
- for ( i = 0; i < NUM_BEAM_SEGS ; i++ )
- {
- RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
-// VectorAdd( start_points[i], origin, start_points[i] );
- VectorAdd( start_points[i], direction, end_points[i] );
- }
-
- GL_Bind( tr.whiteImage );
-
- GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
-
- qglColor3f( 1, 0, 0 );
-
- qglBegin( GL_TRIANGLE_STRIP );
- for ( i = 0; i <= NUM_BEAM_SEGS; i++ ) {
- qglVertex3fv( start_points[ i % NUM_BEAM_SEGS] );
- qglVertex3fv( end_points[ i % NUM_BEAM_SEGS] );
- }
- qglEnd();
-}
-
-//================================================================================
-
-static void DoRailCore( const vec3_t start, const vec3_t end, const vec3_t up, float len, float spanWidth )
-{
- float spanWidth2;
- int vbase;
- float t = len / 256.0f;
-
- vbase = tess.numVertexes;
-
- spanWidth2 = -spanWidth;
-
- // FIXME: use quad stamp?
- VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25;
- tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25;
- tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25;
- tess.numVertexes++;
-
- VectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
- tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
- tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
- tess.numVertexes++;
-
- VectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] );
-
- tess.texCoords[tess.numVertexes][0][0] = t;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
- tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
- tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
- tess.numVertexes++;
-
- VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = t;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
- tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
- tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
- tess.numVertexes++;
-
- tess.indexes[tess.numIndexes++] = vbase;
- tess.indexes[tess.numIndexes++] = vbase + 1;
- tess.indexes[tess.numIndexes++] = vbase + 2;
-
- tess.indexes[tess.numIndexes++] = vbase + 2;
- tess.indexes[tess.numIndexes++] = vbase + 1;
- tess.indexes[tess.numIndexes++] = vbase + 3;
-}
-
-static void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, const vec3_t right, const vec3_t up )
-{
- int i;
- vec3_t pos[4];
- vec3_t v;
- int spanWidth = r_railWidth->integer;
- float c, s;
- float scale;
-
- if ( numSegs > 1 )
- numSegs--;
- if ( !numSegs )
- return;
-
- scale = 0.25;
-
- for ( i = 0; i < 4; i++ )
- {
- c = cos( DEG2RAD( 45 + i * 90 ) );
- s = sin( DEG2RAD( 45 + i * 90 ) );
- v[0] = ( right[0] * c + up[0] * s ) * scale * spanWidth;
- v[1] = ( right[1] * c + up[1] * s ) * scale * spanWidth;
- v[2] = ( right[2] * c + up[2] * s ) * scale * spanWidth;
- VectorAdd( start, v, pos[i] );
-
- if ( numSegs > 1 )
- {
- // offset by 1 segment if we're doing a long distance shot
- VectorAdd( pos[i], dir, pos[i] );
- }
- }
-
- for ( i = 0; i < numSegs; i++ )
- {
- int j;
-
- RB_CHECKOVERFLOW( 4, 6 );
-
- for ( j = 0; j < 4; j++ )
- {
- VectorCopy( pos[j], tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = ( j < 2 );
- tess.texCoords[tess.numVertexes][0][1] = ( j && j != 3 );
- tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
- tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
- tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
- tess.numVertexes++;
-
- VectorAdd( pos[j], dir, pos[j] );
- }
-
- tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 0;
- tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1;
- tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3;
- tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3;
- tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1;
- tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 2;
- }
-}
-
-/*
-** RB_SurfaceRailRinges
-*/
-static void RB_SurfaceRailRings( void ) {
- refEntity_t *e;
- int numSegs;
- int len;
- vec3_t vec;
- vec3_t right, up;
- vec3_t start, end;
-
- e = &backEnd.currentEntity->e;
-
- VectorCopy( e->oldorigin, start );
- VectorCopy( e->origin, end );
-
- // compute variables
- VectorSubtract( end, start, vec );
- len = VectorNormalize( vec );
- MakeNormalVectors( vec, right, up );
- numSegs = ( len ) / r_railSegmentLength->value;
- if ( numSegs <= 0 ) {
- numSegs = 1;
- }
-
- VectorScale( vec, r_railSegmentLength->value, vec );
-
- DoRailDiscs( numSegs, start, vec, right, up );
-}
-
-/*
-** RB_SurfaceRailCore
-*/
-static void RB_SurfaceRailCore( void ) {
- refEntity_t *e;
- int len;
- vec3_t right;
- vec3_t vec;
- vec3_t start, end;
- vec3_t v1, v2;
-
- e = &backEnd.currentEntity->e;
-
- VectorCopy( e->oldorigin, start );
- VectorCopy( e->origin, end );
-
- VectorSubtract( end, start, vec );
- len = VectorNormalize( vec );
-
- // compute side vector
- VectorSubtract( start, backEnd.viewParms.or.origin, v1 );
- VectorNormalize( v1 );
- VectorSubtract( end, backEnd.viewParms.or.origin, v2 );
- VectorNormalize( v2 );
- CrossProduct( v1, v2, right );
- VectorNormalize( right );
-
- DoRailCore( start, end, right, len, r_railCoreWidth->integer );
-}
-
-/*
-** RB_SurfaceLightningBolt
-*/
-static void RB_SurfaceLightningBolt( void ) {
- refEntity_t *e;
- int len;
- vec3_t right;
- vec3_t vec;
- vec3_t start, end;
- vec3_t v1, v2;
- int i;
-
- e = &backEnd.currentEntity->e;
-
- VectorCopy( e->oldorigin, end );
- VectorCopy( e->origin, start );
-
- // compute variables
- VectorSubtract( end, start, vec );
- len = VectorNormalize( vec );
-
- // compute side vector
- VectorSubtract( start, backEnd.viewParms.or.origin, v1 );
- VectorNormalize( v1 );
- VectorSubtract( end, backEnd.viewParms.or.origin, v2 );
- VectorNormalize( v2 );
- CrossProduct( v1, v2, right );
- VectorNormalize( right );
-
- for ( i = 0 ; i < 4 ; i++ ) {
- vec3_t temp;
-
- DoRailCore( start, end, right, len, 8 );
- RotatePointAroundVector( temp, vec, right, 45 );
- VectorCopy( temp, right );
- }
-}
-
-/*
-** VectorArrayNormalize
-*
-* The inputs to this routing seem to always be close to length = 1.0 (about 0.6 to 2.0)
-* This means that we don't have to worry about zero length or enormously long vectors.
-*/
-static void VectorArrayNormalize(vec4_t *normals, unsigned int count)
-{
-// assert(count);
-
-#if idppc
- {
- register float half = 0.5;
- register float one = 1.0;
- float *components = (float *)normals;
-
- // Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction,
- // runs *much* faster than calling sqrt(). We'll use a single Newton-Raphson
- // refinement step to get a little more precision. This seems to yeild results
- // that are correct to 3 decimal places and usually correct to at least 4 (sometimes 5).
- // (That is, for the given input range of about 0.6 to 2.0).
- do {
- float x, y, z;
- float B, y0, y1;
-
- x = components[0];
- y = components[1];
- z = components[2];
- components += 4;
- B = x*x + y*y + z*z;
-
-#ifdef __GNUC__
- asm("frsqrte %0,%1" : "=f" (y0) : "f" (B));
-#else
- y0 = __frsqrte(B);
-#endif
- y1 = y0 + half*y0*(one - B*y0*y0);
-
- x = x * y1;
- y = y * y1;
- components[-4] = x;
- z = z * y1;
- components[-3] = y;
- components[-2] = z;
- } while(count--);
- }
-#else // No assembly version for this architecture, or C_ONLY defined
- // given the input, it's safe to call VectorNormalizeFast
- while (count--) {
- VectorNormalizeFast(normals[0]);
- normals++;
- }
-#endif
-
-}
-
-
-
-/*
-** LerpMeshVertexes
-*/
-#if idppc_altivec
-static void LerpMeshVertexes_altivec(md3Surface_t *surf, float backlerp)
-{
- short *oldXyz, *newXyz, *oldNormals, *newNormals;
- float *outXyz, *outNormal;
- float oldXyzScale ALIGN(16);
- float newXyzScale ALIGN(16);
- float oldNormalScale ALIGN(16);
- float newNormalScale ALIGN(16);
- int vertNum;
- unsigned lat, lng;
- int numVerts;
-
- outXyz = tess.xyz[tess.numVertexes];
- outNormal = tess.normal[tess.numVertexes];
-
- newXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
- + (backEnd.currentEntity->e.frame * surf->numVerts * 4);
- newNormals = newXyz + 3;
-
- newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp);
- newNormalScale = 1.0 - backlerp;
-
- numVerts = surf->numVerts;
-
- if ( backlerp == 0 ) {
- vector signed short newNormalsVec0;
- vector signed short newNormalsVec1;
- vector signed int newNormalsIntVec;
- vector float newNormalsFloatVec;
- vector float newXyzScaleVec;
- vector unsigned char newNormalsLoadPermute;
- vector unsigned char newNormalsStorePermute;
- vector float zero;
-
- newNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec);
- newXyzScaleVec = *(vector float *)&newXyzScale;
- newXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute);
- newXyzScaleVec = vec_splat(newXyzScaleVec,0);
- newNormalsLoadPermute = vec_lvsl(0,newXyz);
- newNormalsStorePermute = vec_lvsr(0,outXyz);
- zero = (vector float)vec_splat_s8(0);
- //
- // just copy the vertexes
- //
- for (vertNum=0 ; vertNum < numVerts ; vertNum++,
- newXyz += 4, newNormals += 4,
- outXyz += 4, outNormal += 4)
- {
- newNormalsLoadPermute = vec_lvsl(0,newXyz);
- newNormalsStorePermute = vec_lvsr(0,outXyz);
- newNormalsVec0 = vec_ld(0,newXyz);
- newNormalsVec1 = vec_ld(16,newXyz);
- newNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute);
- newNormalsIntVec = vec_unpackh(newNormalsVec0);
- newNormalsFloatVec = vec_ctf(newNormalsIntVec,0);
- newNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero);
- newNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute);
- //outXyz[0] = newXyz[0] * newXyzScale;
- //outXyz[1] = newXyz[1] * newXyzScale;
- //outXyz[2] = newXyz[2] * newXyzScale;
-
- lat = ( newNormals[0] >> 8 ) & 0xff;
- lng = ( newNormals[0] & 0xff );
- lat *= (FUNCTABLE_SIZE/256);
- lng *= (FUNCTABLE_SIZE/256);
-
- // decode X as cos( lat ) * sin( long )
- // decode Y as sin( lat ) * sin( long )
- // decode Z as cos( long )
-
- outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
- outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
- outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
- vec_ste(newNormalsFloatVec,0,outXyz);
- vec_ste(newNormalsFloatVec,4,outXyz);
- vec_ste(newNormalsFloatVec,8,outXyz);
- }
- } else {
- //
- // interpolate and copy the vertex and normal
- //
- oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
- + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4);
- oldNormals = oldXyz + 3;
-
- oldXyzScale = MD3_XYZ_SCALE * backlerp;
- oldNormalScale = backlerp;
-
- for (vertNum=0 ; vertNum < numVerts ; vertNum++,
- oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4,
- outXyz += 4, outNormal += 4)
- {
- vec3_t uncompressedOldNormal, uncompressedNewNormal;
-
- // interpolate the xyz
- outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale;
- outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale;
- outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale;
-
- // FIXME: interpolate lat/long instead?
- lat = ( newNormals[0] >> 8 ) & 0xff;
- lng = ( newNormals[0] & 0xff );
- lat *= 4;
- lng *= 4;
- uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
- uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
- uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
- lat = ( oldNormals[0] >> 8 ) & 0xff;
- lng = ( oldNormals[0] & 0xff );
- lat *= 4;
- lng *= 4;
-
- uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
- uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
- uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
- outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale;
- outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale;
- outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale;
-
-// VectorNormalize (outNormal);
- }
- VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts);
- }
-}
-#endif
-
-static void LerpMeshVertexes_scalar(md3Surface_t *surf, float backlerp)
-{
- short *oldXyz, *newXyz, *oldNormals, *newNormals;
- float *outXyz, *outNormal;
- float oldXyzScale, newXyzScale;
- float oldNormalScale, newNormalScale;
- int vertNum;
- unsigned lat, lng;
- int numVerts;
-
- outXyz = tess.xyz[tess.numVertexes];
- outNormal = tess.normal[tess.numVertexes];
-
- newXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
- + (backEnd.currentEntity->e.frame * surf->numVerts * 4);
- newNormals = newXyz + 3;
-
- newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp);
- newNormalScale = 1.0 - backlerp;
-
- numVerts = surf->numVerts;
-
- if ( backlerp == 0 ) {
- //
- // just copy the vertexes
- //
- for (vertNum=0 ; vertNum < numVerts ; vertNum++,
- newXyz += 4, newNormals += 4,
- outXyz += 4, outNormal += 4)
- {
-
- outXyz[0] = newXyz[0] * newXyzScale;
- outXyz[1] = newXyz[1] * newXyzScale;
- outXyz[2] = newXyz[2] * newXyzScale;
-
- lat = ( newNormals[0] >> 8 ) & 0xff;
- lng = ( newNormals[0] & 0xff );
- lat *= (FUNCTABLE_SIZE/256);
- lng *= (FUNCTABLE_SIZE/256);
-
- // decode X as cos( lat ) * sin( long )
- // decode Y as sin( lat ) * sin( long )
- // decode Z as cos( long )
-
- outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
- outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
- outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
- }
- } else {
- //
- // interpolate and copy the vertex and normal
- //
- oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
- + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4);
- oldNormals = oldXyz + 3;
-
- oldXyzScale = MD3_XYZ_SCALE * backlerp;
- oldNormalScale = backlerp;
-
- for (vertNum=0 ; vertNum < numVerts ; vertNum++,
- oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4,
- outXyz += 4, outNormal += 4)
- {
- vec3_t uncompressedOldNormal, uncompressedNewNormal;
-
- // interpolate the xyz
- outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale;
- outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale;
- outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale;
-
- // FIXME: interpolate lat/long instead?
- lat = ( newNormals[0] >> 8 ) & 0xff;
- lng = ( newNormals[0] & 0xff );
- lat *= 4;
- lng *= 4;
- uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
- uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
- uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
- lat = ( oldNormals[0] >> 8 ) & 0xff;
- lng = ( oldNormals[0] & 0xff );
- lat *= 4;
- lng *= 4;
-
- uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
- uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
- uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
- outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale;
- outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale;
- outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale;
-
-// VectorNormalize (outNormal);
- }
- VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts);
- }
-}
-
-static void LerpMeshVertexes(md3Surface_t *surf, float backlerp)
-{
-#if idppc_altivec
- if (com_altivec->integer) {
- // must be in a seperate function or G3 systems will crash.
- LerpMeshVertexes_altivec( surf, backlerp );
- return;
- }
-#endif // idppc_altivec
- LerpMeshVertexes_scalar( surf, backlerp );
-}
-
-
-/*
-=============
-RB_SurfaceMesh
-=============
-*/
-static void RB_SurfaceMesh(md3Surface_t *surface) {
- int j;
- float backlerp;
- int *triangles;
- float *texCoords;
- int indexes;
- int Bob, Doug;
- int numVerts;
-
- if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) {
- backlerp = 0;
- } else {
- backlerp = backEnd.currentEntity->e.backlerp;
- }
-
- RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles*3 );
-
- LerpMeshVertexes (surface, backlerp);
-
- triangles = (int *) ((byte *)surface + surface->ofsTriangles);
- indexes = surface->numTriangles * 3;
- Bob = tess.numIndexes;
- Doug = tess.numVertexes;
- for (j = 0 ; j < indexes ; j++) {
- tess.indexes[Bob + j] = Doug + triangles[j];
- }
- tess.numIndexes += indexes;
-
- texCoords = (float *) ((byte *)surface + surface->ofsSt);
-
- numVerts = surface->numVerts;
- for ( j = 0; j < numVerts; j++ ) {
- tess.texCoords[Doug + j][0][0] = texCoords[j*2+0];
- tess.texCoords[Doug + j][0][1] = texCoords[j*2+1];
- // FIXME: fill in lightmapST for completeness?
- }
-
- tess.numVertexes += surface->numVerts;
-
-}
-
-
-/*
-==============
-RB_SurfaceFace
-==============
-*/
-static void RB_SurfaceFace( srfSurfaceFace_t *surf ) {
- int i;
- unsigned *indices, *tessIndexes;
- float *v;
- float *normal;
- int ndx;
- int Bob;
- int numPoints;
- int dlightBits;
-
- RB_CHECKOVERFLOW( surf->numPoints, surf->numIndices );
-
- dlightBits = surf->dlightBits[backEnd.smpFrame];
- tess.dlightBits |= dlightBits;
-
- indices = ( unsigned * ) ( ( ( char * ) surf ) + surf->ofsIndices );
-
- Bob = tess.numVertexes;
- tessIndexes = tess.indexes + tess.numIndexes;
- for ( i = surf->numIndices-1 ; i >= 0 ; i-- ) {
- tessIndexes[i] = indices[i] + Bob;
- }
-
- tess.numIndexes += surf->numIndices;
-
- v = surf->points[0];
-
- ndx = tess.numVertexes;
-
- numPoints = surf->numPoints;
-
- if ( tess.shader->needsNormal ) {
- normal = surf->plane.normal;
- for ( i = 0, ndx = tess.numVertexes; i < numPoints; i++, ndx++ ) {
- VectorCopy( normal, tess.normal[ndx] );
- }
- }
-
- for ( i = 0, v = surf->points[0], ndx = tess.numVertexes; i < numPoints; i++, v += VERTEXSIZE, ndx++ ) {
- VectorCopy( v, tess.xyz[ndx]);
- tess.texCoords[ndx][0][0] = v[3];
- tess.texCoords[ndx][0][1] = v[4];
- tess.texCoords[ndx][1][0] = v[5];
- tess.texCoords[ndx][1][1] = v[6];
- * ( unsigned int * ) &tess.vertexColors[ndx] = * ( unsigned int * ) &v[7];
- tess.vertexDlightBits[ndx] = dlightBits;
- }
-
-
- tess.numVertexes += surf->numPoints;
-}
-
-
-static float LodErrorForVolume( vec3_t local, float radius ) {
- vec3_t world;
- float d;
-
- // never let it go negative
- if ( r_lodCurveError->value < 0 ) {
- return 0;
- }
-
- world[0] = local[0] * backEnd.or.axis[0][0] + local[1] * backEnd.or.axis[1][0] +
- local[2] * backEnd.or.axis[2][0] + backEnd.or.origin[0];
- world[1] = local[0] * backEnd.or.axis[0][1] + local[1] * backEnd.or.axis[1][1] +
- local[2] * backEnd.or.axis[2][1] + backEnd.or.origin[1];
- world[2] = local[0] * backEnd.or.axis[0][2] + local[1] * backEnd.or.axis[1][2] +
- local[2] * backEnd.or.axis[2][2] + backEnd.or.origin[2];
-
- VectorSubtract( world, backEnd.viewParms.or.origin, world );
- d = DotProduct( world, backEnd.viewParms.or.axis[0] );
-
- if ( d < 0 ) {
- d = -d;
- }
- d -= radius;
- if ( d < 1 ) {
- d = 1;
- }
-
- return r_lodCurveError->value / d;
-}
-
-/*
-=============
-RB_SurfaceGrid
-
-Just copy the grid of points and triangulate
-=============
-*/
-static void RB_SurfaceGrid( srfGridMesh_t *cv ) {
- int i, j;
- float *xyz;
- float *texCoords;
- float *normal;
- unsigned char *color;
- drawVert_t *dv;
- int rows, irows, vrows;
- int used;
- int widthTable[MAX_GRID_SIZE];
- int heightTable[MAX_GRID_SIZE];
- float lodError;
- int lodWidth, lodHeight;
- int numVertexes;
- int dlightBits;
- int *vDlightBits;
- qboolean needsNormal;
-
- dlightBits = cv->dlightBits[backEnd.smpFrame];
- tess.dlightBits |= dlightBits;
-
- // determine the allowable discrepance
- lodError = LodErrorForVolume( cv->lodOrigin, cv->lodRadius );
-
- // determine which rows and columns of the subdivision
- // we are actually going to use
- widthTable[0] = 0;
- lodWidth = 1;
- for ( i = 1 ; i < cv->width-1 ; i++ ) {
- if ( cv->widthLodError[i] <= lodError ) {
- widthTable[lodWidth] = i;
- lodWidth++;
- }
- }
- widthTable[lodWidth] = cv->width-1;
- lodWidth++;
-
- heightTable[0] = 0;
- lodHeight = 1;
- for ( i = 1 ; i < cv->height-1 ; i++ ) {
- if ( cv->heightLodError[i] <= lodError ) {
- heightTable[lodHeight] = i;
- lodHeight++;
- }
- }
- heightTable[lodHeight] = cv->height-1;
- lodHeight++;
-
-
- // very large grids may have more points or indexes than can be fit
- // in the tess structure, so we may have to issue it in multiple passes
-
- used = 0;
- rows = 0;
- while ( used < lodHeight - 1 ) {
- // see how many rows of both verts and indexes we can add without overflowing
- do {
- vrows = ( SHADER_MAX_VERTEXES - tess.numVertexes ) / lodWidth;
- irows = ( SHADER_MAX_INDEXES - tess.numIndexes ) / ( lodWidth * 6 );
-
- // if we don't have enough space for at least one strip, flush the buffer
- if ( vrows < 2 || irows < 1 ) {
- RB_EndSurface();
- RB_BeginSurface(tess.shader, tess.fogNum );
- } else {
- break;
- }
- } while ( 1 );
-
- rows = irows;
- if ( vrows < irows + 1 ) {
- rows = vrows - 1;
- }
- if ( used + rows > lodHeight ) {
- rows = lodHeight - used;
- }
-
- numVertexes = tess.numVertexes;
-
- xyz = tess.xyz[numVertexes];
- normal = tess.normal[numVertexes];
- texCoords = tess.texCoords[numVertexes][0];
- color = ( unsigned char * ) &tess.vertexColors[numVertexes];
- vDlightBits = &tess.vertexDlightBits[numVertexes];
- needsNormal = tess.shader->needsNormal;
-
- for ( i = 0 ; i < rows ; i++ ) {
- for ( j = 0 ; j < lodWidth ; j++ ) {
- dv = cv->verts + heightTable[ used + i ] * cv->width
- + widthTable[ j ];
-
- xyz[0] = dv->xyz[0];
- xyz[1] = dv->xyz[1];
- xyz[2] = dv->xyz[2];
- texCoords[0] = dv->st[0];
- texCoords[1] = dv->st[1];
- texCoords[2] = dv->lightmap[0];
- texCoords[3] = dv->lightmap[1];
- if ( needsNormal ) {
- normal[0] = dv->normal[0];
- normal[1] = dv->normal[1];
- normal[2] = dv->normal[2];
- }
- * ( unsigned int * ) color = * ( unsigned int * ) dv->color;
- *vDlightBits++ = dlightBits;
- xyz += 4;
- normal += 4;
- texCoords += 4;
- color += 4;
- }
- }
-
-
- // add the indexes
- {
- int numIndexes;
- int w, h;
-
- h = rows - 1;
- w = lodWidth - 1;
- numIndexes = tess.numIndexes;
- for (i = 0 ; i < h ; i++) {
- for (j = 0 ; j < w ; j++) {
- int v1, v2, v3, v4;
-
- // vertex order to be reckognized as tristrips
- v1 = numVertexes + i*lodWidth + j + 1;
- v2 = v1 - 1;
- v3 = v2 + lodWidth;
- v4 = v3 + 1;
-
- tess.indexes[numIndexes] = v2;
- tess.indexes[numIndexes+1] = v3;
- tess.indexes[numIndexes+2] = v1;
-
- tess.indexes[numIndexes+3] = v1;
- tess.indexes[numIndexes+4] = v3;
- tess.indexes[numIndexes+5] = v4;
- numIndexes += 6;
- }
- }
-
- tess.numIndexes = numIndexes;
- }
-
- tess.numVertexes += rows * lodWidth;
-
- used += rows - 1;
- }
-}
-
-
-/*
-===========================================================================
-
-NULL MODEL
-
-===========================================================================
-*/
-
-/*
-===================
-RB_SurfaceAxis
-
-Draws x/y/z lines from the origin for orientation debugging
-===================
-*/
-static void RB_SurfaceAxis( void ) {
- GL_Bind( tr.whiteImage );
- qglLineWidth( 3 );
- qglBegin( GL_LINES );
- qglColor3f( 1,0,0 );
- qglVertex3f( 0,0,0 );
- qglVertex3f( 16,0,0 );
- qglColor3f( 0,1,0 );
- qglVertex3f( 0,0,0 );
- qglVertex3f( 0,16,0 );
- qglColor3f( 0,0,1 );
- qglVertex3f( 0,0,0 );
- qglVertex3f( 0,0,16 );
- qglEnd();
- qglLineWidth( 1 );
-}
-
-//===========================================================================
-
-/*
-====================
-RB_SurfaceEntity
-
-Entities that have a single procedurally generated surface
-====================
-*/
-static void RB_SurfaceEntity( surfaceType_t *surfType ) {
- switch( backEnd.currentEntity->e.reType ) {
- case RT_SPRITE:
- RB_SurfaceSprite();
- break;
- case RT_BEAM:
- RB_SurfaceBeam();
- break;
- case RT_RAIL_CORE:
- RB_SurfaceRailCore();
- break;
- case RT_RAIL_RINGS:
- RB_SurfaceRailRings();
- break;
- case RT_LIGHTNING:
- RB_SurfaceLightningBolt();
- break;
- default:
- RB_SurfaceAxis();
- break;
- }
- return;
-}
-
-static void RB_SurfaceBad( surfaceType_t *surfType ) {
- ri.Printf( PRINT_ALL, "Bad surface tesselated.\n" );
-}
-
-static void RB_SurfaceFlare(srfFlare_t *surf)
-{
- if (r_flares->integer)
- RB_AddFlare(surf, tess.fogNum, surf->origin, surf->color, surf->normal);
-}
-
-static void RB_SurfaceDisplayList( srfDisplayList_t *surf ) {
- // all apropriate state must be set in RB_BeginSurface
- // this isn't implemented yet...
- qglCallList( surf->listNum );
-}
-
-static void RB_SurfaceSkip( void *surf ) {
-}
-
-
-void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = {
- (void(*)(void*))RB_SurfaceBad, // SF_BAD,
- (void(*)(void*))RB_SurfaceSkip, // SF_SKIP,
- (void(*)(void*))RB_SurfaceFace, // SF_FACE,
- (void(*)(void*))RB_SurfaceGrid, // SF_GRID,
- (void(*)(void*))RB_SurfaceTriangles, // SF_TRIANGLES,
- (void(*)(void*))RB_SurfacePolychain, // SF_POLY,
- (void(*)(void*))RB_SurfaceMesh, // SF_MD3,
- (void(*)(void*))RB_SurfaceAnim, // SF_MD4,
-#ifdef RAVENMD4
- (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR,
-#endif
- (void(*)(void*))RB_SurfaceFlare, // SF_FLARE,
- (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY
- (void(*)(void*))RB_SurfaceDisplayList // SF_DISPLAY_LIST
-};
diff --git a/engine/code/renderer/tr_world.c b/engine/code/renderer/tr_world.c
deleted file mode 100644
index d05373a..0000000
--- a/engine/code/renderer/tr_world.c
+++ /dev/null
@@ -1,668 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "tr_local.h"
-
-
-
-/*
-=================
-R_CullTriSurf
-
-Returns true if the grid is completely culled away.
-Also sets the clipped hint bit in tess
-=================
-*/
-static qboolean R_CullTriSurf( srfTriangles_t *cv ) {
- int boxCull;
-
- boxCull = R_CullLocalBox( cv->bounds );
-
- if ( boxCull == CULL_OUT ) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-=================
-R_CullGrid
-
-Returns true if the grid is completely culled away.
-Also sets the clipped hint bit in tess
-=================
-*/
-static qboolean R_CullGrid( srfGridMesh_t *cv ) {
- int boxCull;
- int sphereCull;
-
- if ( r_nocurves->integer ) {
- return qtrue;
- }
-
- if ( tr.currentEntityNum != ENTITYNUM_WORLD ) {
- sphereCull = R_CullLocalPointAndRadius( cv->localOrigin, cv->meshRadius );
- } else {
- sphereCull = R_CullPointAndRadius( cv->localOrigin, cv->meshRadius );
- }
- boxCull = CULL_OUT;
-
- // check for trivial reject
- if ( sphereCull == CULL_OUT )
- {
- tr.pc.c_sphere_cull_patch_out++;
- return qtrue;
- }
- // check bounding box if necessary
- else if ( sphereCull == CULL_CLIP )
- {
- tr.pc.c_sphere_cull_patch_clip++;
-
- boxCull = R_CullLocalBox( cv->meshBounds );
-
- if ( boxCull == CULL_OUT )
- {
- tr.pc.c_box_cull_patch_out++;
- return qtrue;
- }
- else if ( boxCull == CULL_IN )
- {
- tr.pc.c_box_cull_patch_in++;
- }
- else
- {
- tr.pc.c_box_cull_patch_clip++;
- }
- }
- else
- {
- tr.pc.c_sphere_cull_patch_in++;
- }
-
- return qfalse;
-}
-
-
-/*
-================
-R_CullSurface
-
-Tries to back face cull surfaces before they are lighted or
-added to the sorting list.
-
-This will also allow mirrors on both sides of a model without recursion.
-================
-*/
-static qboolean R_CullSurface( surfaceType_t *surface, shader_t *shader ) {
- srfSurfaceFace_t *sface;
- float d;
-
- if ( r_nocull->integer ) {
- return qfalse;
- }
-
- if ( *surface == SF_GRID ) {
- return R_CullGrid( (srfGridMesh_t *)surface );
- }
-
- if ( *surface == SF_TRIANGLES ) {
- return R_CullTriSurf( (srfTriangles_t *)surface );
- }
-
- if ( *surface != SF_FACE ) {
- return qfalse;
- }
-
- if ( shader->cullType == CT_TWO_SIDED ) {
- return qfalse;
- }
-
- // face culling
- if ( !r_facePlaneCull->integer ) {
- return qfalse;
- }
-
- sface = ( srfSurfaceFace_t * ) surface;
- d = DotProduct (tr.or.viewOrigin, sface->plane.normal);
-
- // don't cull exactly on the plane, because there are levels of rounding
- // through the BSP, ICD, and hardware that may cause pixel gaps if an
- // epsilon isn't allowed here
- if ( shader->cullType == CT_FRONT_SIDED ) {
- if ( d < sface->plane.dist - 8 ) {
- return qtrue;
- }
- } else {
- if ( d > sface->plane.dist + 8 ) {
- return qtrue;
- }
- }
-
- return qfalse;
-}
-
-
-static int R_DlightFace( srfSurfaceFace_t *face, int dlightBits ) {
- float d;
- int i;
- dlight_t *dl;
-
- for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
- if ( ! ( dlightBits & ( 1 << i ) ) ) {
- continue;
- }
- dl = &tr.refdef.dlights[i];
- d = DotProduct( dl->origin, face->plane.normal ) - face->plane.dist;
- if ( d < -dl->radius || d > dl->radius ) {
- // dlight doesn't reach the plane
- dlightBits &= ~( 1 << i );
- }
- }
-
- if ( !dlightBits ) {
- tr.pc.c_dlightSurfacesCulled++;
- }
-
- face->dlightBits[ tr.smpFrame ] = dlightBits;
- return dlightBits;
-}
-
-static int R_DlightGrid( srfGridMesh_t *grid, int dlightBits ) {
- int i;
- dlight_t *dl;
-
- for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
- if ( ! ( dlightBits & ( 1 << i ) ) ) {
- continue;
- }
- dl = &tr.refdef.dlights[i];
- if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0]
- || dl->origin[0] + dl->radius < grid->meshBounds[0][0]
- || dl->origin[1] - dl->radius > grid->meshBounds[1][1]
- || dl->origin[1] + dl->radius < grid->meshBounds[0][1]
- || dl->origin[2] - dl->radius > grid->meshBounds[1][2]
- || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) {
- // dlight doesn't reach the bounds
- dlightBits &= ~( 1 << i );
- }
- }
-
- if ( !dlightBits ) {
- tr.pc.c_dlightSurfacesCulled++;
- }
-
- grid->dlightBits[ tr.smpFrame ] = dlightBits;
- return dlightBits;
-}
-
-
-static int R_DlightTrisurf( srfTriangles_t *surf, int dlightBits ) {
- // FIXME: more dlight culling to trisurfs...
- surf->dlightBits[ tr.smpFrame ] = dlightBits;
- return dlightBits;
-#if 0
- int i;
- dlight_t *dl;
-
- for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
- if ( ! ( dlightBits & ( 1 << i ) ) ) {
- continue;
- }
- dl = &tr.refdef.dlights[i];
- if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0]
- || dl->origin[0] + dl->radius < grid->meshBounds[0][0]
- || dl->origin[1] - dl->radius > grid->meshBounds[1][1]
- || dl->origin[1] + dl->radius < grid->meshBounds[0][1]
- || dl->origin[2] - dl->radius > grid->meshBounds[1][2]
- || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) {
- // dlight doesn't reach the bounds
- dlightBits &= ~( 1 << i );
- }
- }
-
- if ( !dlightBits ) {
- tr.pc.c_dlightSurfacesCulled++;
- }
-
- grid->dlightBits[ tr.smpFrame ] = dlightBits;
- return dlightBits;
-#endif
-}
-
-/*
-====================
-R_DlightSurface
-
-The given surface is going to be drawn, and it touches a leaf
-that is touched by one or more dlights, so try to throw out
-more dlights if possible.
-====================
-*/
-static int R_DlightSurface( msurface_t *surf, int dlightBits ) {
- if ( *surf->data == SF_FACE ) {
- dlightBits = R_DlightFace( (srfSurfaceFace_t *)surf->data, dlightBits );
- } else if ( *surf->data == SF_GRID ) {
- dlightBits = R_DlightGrid( (srfGridMesh_t *)surf->data, dlightBits );
- } else if ( *surf->data == SF_TRIANGLES ) {
- dlightBits = R_DlightTrisurf( (srfTriangles_t *)surf->data, dlightBits );
- } else {
- dlightBits = 0;
- }
-
- if ( dlightBits ) {
- tr.pc.c_dlightSurfaces++;
- }
-
- return dlightBits;
-}
-
-
-
-/*
-======================
-R_AddWorldSurface
-======================
-*/
-static void R_AddWorldSurface( msurface_t *surf, int dlightBits ) {
- if ( surf->viewCount == tr.viewCount ) {
- return; // already in this view
- }
-
- surf->viewCount = tr.viewCount;
- // FIXME: bmodel fog?
-
- // try to cull before dlighting or adding
- if ( R_CullSurface( surf->data, surf->shader ) ) {
- return;
- }
-
- // check for dlighting
- if ( dlightBits ) {
- dlightBits = R_DlightSurface( surf, dlightBits );
- dlightBits = ( dlightBits != 0 );
- }
-
- R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits );
-}
-
-/*
-=============================================================
-
- BRUSH MODELS
-
-=============================================================
-*/
-
-/*
-=================
-R_AddBrushModelSurfaces
-=================
-*/
-void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) {
- bmodel_t *bmodel;
- int clip;
- model_t *pModel;
- int i;
-
- pModel = R_GetModelByHandle( ent->e.hModel );
-
- bmodel = pModel->bmodel;
-
- clip = R_CullLocalBox( bmodel->bounds );
- if ( clip == CULL_OUT ) {
- return;
- }
-
- R_DlightBmodel( bmodel );
-
- for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
- R_AddWorldSurface( bmodel->firstSurface + i, tr.currentEntity->needDlights );
- }
-}
-
-
-/*
-=============================================================
-
- WORLD MODEL
-
-=============================================================
-*/
-
-
-/*
-================
-R_RecursiveWorldNode
-================
-*/
-static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) {
-
- do {
- int newDlights[2];
-
- // if the node wasn't marked as potentially visible, exit
- if (node->visframe != tr.visCount) {
- return;
- }
-
- // if the bounding volume is outside the frustum, nothing
- // inside can be visible OPTIMIZE: don't do this all the way to leafs?
-
- if ( !r_nocull->integer ) {
- int r;
-
- if ( planeBits & 1 ) {
- r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]);
- if (r == 2) {
- return; // culled
- }
- if ( r == 1 ) {
- planeBits &= ~1; // all descendants will also be in front
- }
- }
-
- if ( planeBits & 2 ) {
- r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]);
- if (r == 2) {
- return; // culled
- }
- if ( r == 1 ) {
- planeBits &= ~2; // all descendants will also be in front
- }
- }
-
- if ( planeBits & 4 ) {
- r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]);
- if (r == 2) {
- return; // culled
- }
- if ( r == 1 ) {
- planeBits &= ~4; // all descendants will also be in front
- }
- }
-
- if ( planeBits & 8 ) {
- r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]);
- if (r == 2) {
- return; // culled
- }
- if ( r == 1 ) {
- planeBits &= ~8; // all descendants will also be in front
- }
- }
-
- }
-
- if ( node->contents != -1 ) {
- break;
- }
-
- // node is just a decision point, so go down both sides
- // since we don't care about sort orders, just go positive to negative
-
- // determine which dlights are needed
- newDlights[0] = 0;
- newDlights[1] = 0;
- if ( dlightBits ) {
- int i;
-
- for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
- dlight_t *dl;
- float dist;
-
- if ( dlightBits & ( 1 << i ) ) {
- dl = &tr.refdef.dlights[i];
- dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist;
-
- if ( dist > -dl->radius ) {
- newDlights[0] |= ( 1 << i );
- }
- if ( dist < dl->radius ) {
- newDlights[1] |= ( 1 << i );
- }
- }
- }
- }
-
- // recurse down the children, front side first
- R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0] );
-
- // tail recurse
- node = node->children[1];
- dlightBits = newDlights[1];
- } while ( 1 );
-
- {
- // leaf node, so add mark surfaces
- int c;
- msurface_t *surf, **mark;
-
- tr.pc.c_leafs++;
-
- // add to z buffer bounds
- if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) {
- tr.viewParms.visBounds[0][0] = node->mins[0];
- }
- if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) {
- tr.viewParms.visBounds[0][1] = node->mins[1];
- }
- if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) {
- tr.viewParms.visBounds[0][2] = node->mins[2];
- }
-
- if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) {
- tr.viewParms.visBounds[1][0] = node->maxs[0];
- }
- if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) {
- tr.viewParms.visBounds[1][1] = node->maxs[1];
- }
- if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) {
- tr.viewParms.visBounds[1][2] = node->maxs[2];
- }
-
- // add the individual surfaces
- mark = node->firstmarksurface;
- c = node->nummarksurfaces;
- while (c--) {
- // the surface may have already been added if it
- // spans multiple leafs
- surf = *mark;
- R_AddWorldSurface( surf, dlightBits );
- mark++;
- }
- }
-
-}
-
-
-/*
-===============
-R_PointInLeaf
-===============
-*/
-static mnode_t *R_PointInLeaf( const vec3_t p ) {
- mnode_t *node;
- float d;
- cplane_t *plane;
-
- if ( !tr.world ) {
- ri.Error (ERR_DROP, "R_PointInLeaf: bad model");
- }
-
- node = tr.world->nodes;
- while( 1 ) {
- if (node->contents != -1) {
- break;
- }
- plane = node->plane;
- d = DotProduct (p,plane->normal) - plane->dist;
- if (d > 0) {
- node = node->children[0];
- } else {
- node = node->children[1];
- }
- }
-
- return node;
-}
-
-/*
-==============
-R_ClusterPVS
-==============
-*/
-static const byte *R_ClusterPVS (int cluster) {
- if (!tr.world || !tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) {
- return tr.world->novis;
- }
-
- return tr.world->vis + cluster * tr.world->clusterBytes;
-}
-
-/*
-=================
-R_inPVS
-=================
-*/
-qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ) {
- mnode_t *leaf;
- byte *vis;
-
- leaf = R_PointInLeaf( p1 );
- vis = CM_ClusterPVS( leaf->cluster );
- leaf = R_PointInLeaf( p2 );
-
- if ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) {
- return qfalse;
- }
- return qtrue;
-}
-
-/*
-===============
-R_MarkLeaves
-
-Mark the leaves and nodes that are in the PVS for the current
-cluster
-===============
-*/
-static void R_MarkLeaves (void) {
- const byte *vis;
- mnode_t *leaf, *parent;
- int i;
- int cluster;
-
- // lockpvs lets designers walk around to determine the
- // extent of the current pvs
- if ( r_lockpvs->integer ) {
- return;
- }
-
- // current viewcluster
- leaf = R_PointInLeaf( tr.viewParms.pvsOrigin );
- cluster = leaf->cluster;
-
- // if the cluster is the same and the area visibility matrix
- // hasn't changed, we don't need to mark everything again
-
- // if r_showcluster was just turned on, remark everything
- if ( tr.viewCluster == cluster && !tr.refdef.areamaskModified
- && !r_showcluster->modified ) {
- return;
- }
-
- if ( r_showcluster->modified || r_showcluster->integer ) {
- r_showcluster->modified = qfalse;
- if ( r_showcluster->integer ) {
- ri.Printf( PRINT_ALL, "cluster:%i area:%i\n", cluster, leaf->area );
- }
- }
-
- tr.visCount++;
- tr.viewCluster = cluster;
-
- if ( r_novis->integer || tr.viewCluster == -1 ) {
- for (i=0 ; i<tr.world->numnodes ; i++) {
- if (tr.world->nodes[i].contents != CONTENTS_SOLID) {
- tr.world->nodes[i].visframe = tr.visCount;
- }
- }
- return;
- }
-
- vis = R_ClusterPVS (tr.viewCluster);
-
- for (i=0,leaf=tr.world->nodes ; i<tr.world->numnodes ; i++, leaf++) {
- cluster = leaf->cluster;
- if ( cluster < 0 || cluster >= tr.world->numClusters ) {
- continue;
- }
-
- // check general pvs
- if ( !(vis[cluster>>3] & (1<<(cluster&7))) ) {
- continue;
- }
-
- // check for door connection
- if ( (tr.refdef.areamask[leaf->area>>3] & (1<<(leaf->area&7)) ) ) {
- continue; // not visible
- }
-
- parent = leaf;
- do {
- if (parent->visframe == tr.visCount)
- break;
- parent->visframe = tr.visCount;
- parent = parent->parent;
- } while (parent);
- }
-}
-
-
-/*
-=============
-R_AddWorldSurfaces
-=============
-*/
-void R_AddWorldSurfaces (void) {
- if ( !r_drawworld->integer ) {
- return;
- }
-
- if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
- return;
- }
-
- tr.currentEntityNum = ENTITYNUM_WORLD;
- tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT;
-
- // determine which leaves are in the PVS / areamask
- R_MarkLeaves ();
-
- // clear out the visible min/max
- ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] );
-
- // perform frustum culling and add all the potentially visible surfaces
- if ( tr.refdef.num_dlights > 32 ) {
- tr.refdef.num_dlights = 32 ;
- }
- R_RecursiveWorldNode( tr.world->nodes, 15, ( 1 << tr.refdef.num_dlights ) - 1 );
-}
diff --git a/engine/code/sdl/sdl_gamma.c b/engine/code/sdl/sdl_gamma.c
deleted file mode 100644
index 71a42c8..0000000
--- a/engine/code/sdl/sdl_gamma.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#ifdef USE_LOCAL_HEADERS
-# include "SDL.h"
-#else
-# include <SDL.h>
-#endif
-
-#include "../renderer/tr_local.h"
-#include "../qcommon/qcommon.h"
-
-/*
-=================
-GLimp_SetGamma
-=================
-*/
-void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] )
-{
- Uint16 table[3][256];
- int i, j;
-
- if( !glConfig.deviceSupportsGamma || r_ignorehwgamma->integer )
- return;
-
- for (i = 0; i < 256; i++)
- {
- table[0][i] = ( ( ( Uint16 ) red[i] ) << 8 ) | red[i];
- table[1][i] = ( ( ( Uint16 ) green[i] ) << 8 ) | green[i];
- table[2][i] = ( ( ( Uint16 ) blue[i] ) << 8 ) | blue[i];
- }
-
-#ifdef _WIN32
-#include <windows.h>
-
- // Win2K and newer put this odd restriction on gamma ramps...
- {
- OSVERSIONINFO vinfo;
-
- vinfo.dwOSVersionInfoSize = sizeof( vinfo );
- GetVersionEx( &vinfo );
- if( vinfo.dwMajorVersion >= 5 && vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
- {
- Com_DPrintf( "performing gamma clamp.\n" );
- for( j = 0 ; j < 3 ; j++ )
- {
- for( i = 0 ; i < 128 ; i++ )
- {
- if( table[ j ] [ i] > ( ( 128 + i ) << 8 ) )
- table[ j ][ i ] = ( 128 + i ) << 8;
- }
-
- if( table[ j ] [127 ] > 254 << 8 )
- table[ j ][ 127 ] = 254 << 8;
- }
- }
- }
-#endif
-
- // enforce constantly increasing
- for (j = 0; j < 3; j++)
- {
- for (i = 1; i < 256; i++)
- {
- if (table[j][i] < table[j][i-1])
- table[j][i] = table[j][i-1];
- }
- }
-
- SDL_SetGammaRamp(table[0], table[1], table[2]);
-}
-
diff --git a/engine/code/sdl/sdl_glimp.c b/engine/code/sdl/sdl_glimp.c
deleted file mode 100644
index ea2268f..0000000
--- a/engine/code/sdl/sdl_glimp.c
+++ /dev/null
@@ -1,1027 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#ifdef USE_LOCAL_HEADERS
-# include "SDL.h"
-#else
-# include <SDL.h>
-#endif
-
-#ifdef SMP
-# ifdef USE_LOCAL_HEADERS
-# include "SDL_thread.h"
-# else
-# include <SDL_thread.h>
-# endif
-#endif
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include "../renderer/tr_local.h"
-#include "../client/client.h"
-#include "../sys/sys_local.h"
-#include "sdl_icon.h"
-
-/* Just hack it for now. */
-#ifdef MACOS_X
-#include <OpenGL/OpenGL.h>
-typedef CGLContextObj QGLContext;
-#define GLimp_GetCurrentContext() CGLGetCurrentContext()
-#define GLimp_SetCurrentContext(ctx) CGLSetCurrentContext(ctx)
-#else
-typedef void *QGLContext;
-#define GLimp_GetCurrentContext() (NULL)
-#define GLimp_SetCurrentContext(ctx)
-#endif
-
-static QGLContext opengl_context;
-
-typedef enum
-{
- RSERR_OK,
-
- RSERR_INVALID_FULLSCREEN,
- RSERR_INVALID_MODE,
-
- RSERR_UNKNOWN
-} rserr_t;
-
-static SDL_Surface *screen = NULL;
-static const SDL_VideoInfo *videoInfo = NULL;
-
-cvar_t *r_allowSoftwareGL; // Don't abort out if a hardware visual can't be obtained
-cvar_t *r_allowResize; // make window resizable
-cvar_t *r_centerWindow;
-cvar_t *r_sdlDriver;
-
-void (APIENTRYP qglActiveTextureARB) (GLenum texture);
-void (APIENTRYP qglClientActiveTextureARB) (GLenum texture);
-void (APIENTRYP qglMultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t);
-
-void (APIENTRYP qglLockArraysEXT) (GLint first, GLsizei count);
-void (APIENTRYP qglUnlockArraysEXT) (void);
-
-/*
-===============
-GLimp_Shutdown
-===============
-*/
-void GLimp_Shutdown( void )
-{
- IN_Shutdown();
-
- SDL_QuitSubSystem( SDL_INIT_VIDEO );
- screen = NULL;
-
- Com_Memset( &glConfig, 0, sizeof( glConfig ) );
- Com_Memset( &glState, 0, sizeof( glState ) );
-}
-
-/*
-===============
-GLimp_LogComment
-===============
-*/
-void GLimp_LogComment( char *comment )
-{
-}
-
-/*
-===============
-GLimp_CompareModes
-===============
-*/
-static int GLimp_CompareModes( const void *a, const void *b )
-{
- const float ASPECT_EPSILON = 0.001f;
- SDL_Rect *modeA = *(SDL_Rect **)a;
- SDL_Rect *modeB = *(SDL_Rect **)b;
- float aspectA = (float)modeA->w / (float)modeA->h;
- float aspectB = (float)modeB->w / (float)modeB->h;
- int areaA = modeA->w * modeA->h;
- int areaB = modeB->w * modeB->h;
- float aspectDiffA = fabs( aspectA - displayAspect );
- float aspectDiffB = fabs( aspectB - displayAspect );
- float aspectDiffsDiff = aspectDiffA - aspectDiffB;
-
- if( aspectDiffsDiff > ASPECT_EPSILON )
- return 1;
- else if( aspectDiffsDiff < -ASPECT_EPSILON )
- return -1;
- else
- return areaA - areaB;
-}
-
-
-/*
-===============
-GLimp_DetectAvailableModes
-===============
-*/
-static void GLimp_DetectAvailableModes(void)
-{
- char buf[ MAX_STRING_CHARS ] = { 0 };
- SDL_Rect **modes;
- int numModes;
- int i;
-
- modes = SDL_ListModes( videoInfo->vfmt, SDL_OPENGL | SDL_FULLSCREEN );
-
- if( !modes )
- {
- ri.Printf( PRINT_WARNING, "Can't get list of available modes\n" );
- return;
- }
-
- if( modes == (SDL_Rect **)-1 )
- {
- ri.Printf( PRINT_ALL, "Display supports any resolution\n" );
- return; // can set any resolution
- }
-
- for( numModes = 0; modes[ numModes ]; numModes++ );
-
- if( numModes > 1 )
- qsort( modes, numModes, sizeof( SDL_Rect* ), GLimp_CompareModes );
-
- for( i = 0; i < numModes; i++ )
- {
- const char *newModeString = va( "%ux%u ", modes[ i ]->w, modes[ i ]->h );
-
- if( strlen( newModeString ) < (int)sizeof( buf ) - strlen( buf ) )
- Q_strcat( buf, sizeof( buf ), newModeString );
- else
- ri.Printf( PRINT_WARNING, "Skipping mode %ux%x, buffer too small\n", modes[i]->w, modes[i]->h );
- }
-
- if( *buf )
- {
- buf[ strlen( buf ) - 1 ] = 0;
- ri.Printf( PRINT_ALL, "Available modes: '%s'\n", buf );
- ri.Cvar_Set( "r_availableModes", buf );
- }
-}
-
-/*
-===============
-GLimp_SetMode
-===============
-*/
-static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder)
-{
- const char* glstring;
- int sdlcolorbits;
- int colorbits, depthbits, stencilbits;
- int tcolorbits, tdepthbits, tstencilbits;
- int samples;
- int i = 0;
- SDL_Surface *vidscreen = NULL;
- Uint32 flags = SDL_OPENGL;
-
- ri.Printf( PRINT_ALL, "Initializing OpenGL display\n");
-
- if ( r_allowResize->integer )
- flags |= SDL_RESIZABLE;
-
- if( videoInfo == NULL )
- {
- static SDL_VideoInfo sVideoInfo;
- static SDL_PixelFormat sPixelFormat;
-
- videoInfo = SDL_GetVideoInfo( );
-
- // Take a copy of the videoInfo
- Com_Memcpy( &sPixelFormat, videoInfo->vfmt, sizeof( SDL_PixelFormat ) );
- sPixelFormat.palette = NULL; // Should already be the case
- Com_Memcpy( &sVideoInfo, videoInfo, sizeof( SDL_VideoInfo ) );
- sVideoInfo.vfmt = &sPixelFormat;
- videoInfo = &sVideoInfo;
-
- if( videoInfo->current_h > 0 )
- {
- // Guess the display aspect ratio through the desktop resolution
- // by assuming (relatively safely) that it is set at or close to
- // the display's native aspect ratio
- displayAspect = (float)videoInfo->current_w / (float)videoInfo->current_h;
-
- ri.Printf( PRINT_ALL, "Estimated display aspect: %.3f\n", displayAspect );
- }
- else
- {
- ri.Printf( PRINT_ALL,
- "Cannot estimate display aspect, assuming 1.333\n" );
- }
- }
-
- ri.Printf (PRINT_ALL, "...setting mode %d:", mode );
-
- if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) )
- {
- ri.Printf( PRINT_ALL, " invalid mode\n" );
- return RSERR_INVALID_MODE;
- }
- ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight);
-
- if (fullscreen)
- {
- flags |= SDL_FULLSCREEN;
- glConfig.isFullscreen = qtrue;
- }
- else
- {
- if (noborder)
- flags |= SDL_NOFRAME;
-
- glConfig.isFullscreen = qfalse;
- }
-
- colorbits = r_colorbits->value;
- if ((!colorbits) || (colorbits >= 32))
- colorbits = 24;
-
- if (!r_depthbits->value)
- depthbits = 24;
- else
- depthbits = r_depthbits->value;
- stencilbits = r_stencilbits->value;
- samples = r_ext_multisample->value;
-
- for (i = 0; i < 16; i++)
- {
- // 0 - default
- // 1 - minus colorbits
- // 2 - minus depthbits
- // 3 - minus stencil
- if ((i % 4) == 0 && i)
- {
- // one pass, reduce
- switch (i / 4)
- {
- case 2 :
- if (colorbits == 24)
- colorbits = 16;
- break;
- case 1 :
- if (depthbits == 24)
- depthbits = 16;
- else if (depthbits == 16)
- depthbits = 8;
- case 3 :
- if (stencilbits == 24)
- stencilbits = 16;
- else if (stencilbits == 16)
- stencilbits = 8;
- }
- }
-
- tcolorbits = colorbits;
- tdepthbits = depthbits;
- tstencilbits = stencilbits;
-
- if ((i % 4) == 3)
- { // reduce colorbits
- if (tcolorbits == 24)
- tcolorbits = 16;
- }
-
- if ((i % 4) == 2)
- { // reduce depthbits
- if (tdepthbits == 24)
- tdepthbits = 16;
- else if (tdepthbits == 16)
- tdepthbits = 8;
- }
-
- if ((i % 4) == 1)
- { // reduce stencilbits
- if (tstencilbits == 24)
- tstencilbits = 16;
- else if (tstencilbits == 16)
- tstencilbits = 8;
- else
- tstencilbits = 0;
- }
-
- sdlcolorbits = 4;
- if (tcolorbits == 24)
- sdlcolorbits = 8;
-
-#ifdef __sgi /* Fix for SGIs grabbing too many bits of color */
- if (sdlcolorbits == 4)
- sdlcolorbits = 0; /* Use minimum size for 16-bit color */
-
- /* Need alpha or else SGIs choose 36+ bit RGB mode */
- SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 1);
-#endif
-
- SDL_GL_SetAttribute( SDL_GL_RED_SIZE, sdlcolorbits );
- SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, sdlcolorbits );
- SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, sdlcolorbits );
- SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, tdepthbits );
- SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, tstencilbits );
-
- SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, samples ? 1 : 0 );
- SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, samples );
-
- if(r_stereoEnabled->integer)
- {
- glConfig.stereoEnabled = qtrue;
- SDL_GL_SetAttribute(SDL_GL_STEREO, 1);
- }
- else
- {
- glConfig.stereoEnabled = qfalse;
- SDL_GL_SetAttribute(SDL_GL_STEREO, 0);
- }
-
- SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
-
-#if 0 // See http://bugzilla.icculus.org/show_bug.cgi?id=3526
- // If not allowing software GL, demand accelerated
- if( !r_allowSoftwareGL->integer )
- {
- if( SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 ) < 0 )
- {
- ri.Printf( PRINT_ALL, "Unable to guarantee accelerated "
- "visual with libSDL < 1.2.10\n" );
- }
- }
-#endif
-
- if( SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, r_swapInterval->integer ) < 0 )
- ri.Printf( PRINT_ALL, "r_swapInterval requires libSDL >= 1.2.10\n" );
-
-#ifdef USE_ICON
- {
- SDL_Surface *icon = SDL_CreateRGBSurfaceFrom(
- (void *)CLIENT_WINDOW_ICON.pixel_data,
- CLIENT_WINDOW_ICON.width,
- CLIENT_WINDOW_ICON.height,
- CLIENT_WINDOW_ICON.bytes_per_pixel * 8,
- CLIENT_WINDOW_ICON.bytes_per_pixel * CLIENT_WINDOW_ICON.width,
-#ifdef Q3_LITTLE_ENDIAN
- 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
-#else
- 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF
-#endif
- );
-
- SDL_WM_SetIcon( icon, NULL );
- SDL_FreeSurface( icon );
- }
-#endif
-
- SDL_WM_SetCaption(CLIENT_WINDOW_TITLE, CLIENT_WINDOW_MIN_TITLE);
- SDL_ShowCursor(0);
-
- if (!(vidscreen = SDL_SetVideoMode(glConfig.vidWidth, glConfig.vidHeight, colorbits, flags)))
- {
- ri.Printf( PRINT_DEVELOPER, "SDL_SetVideoMode failed: %s\n", SDL_GetError( ) );
- continue;
- }
-
- opengl_context = GLimp_GetCurrentContext();
-
- ri.Printf( PRINT_ALL, "Using %d/%d/%d Color bits, %d depth, %d stencil display.\n",
- sdlcolorbits, sdlcolorbits, sdlcolorbits, tdepthbits, tstencilbits);
-
- glConfig.colorBits = tcolorbits;
- glConfig.depthBits = tdepthbits;
- glConfig.stencilBits = tstencilbits;
- break;
- }
-
- GLimp_DetectAvailableModes();
-
- if (!vidscreen)
- {
- ri.Printf( PRINT_ALL, "Couldn't get a visual\n" );
- return RSERR_INVALID_MODE;
- }
-
- screen = vidscreen;
-
- glstring = (char *) qglGetString (GL_RENDERER);
- ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glstring );
-
- return RSERR_OK;
-}
-
-/*
-===============
-GLimp_StartDriverAndSetMode
-===============
-*/
-static qboolean GLimp_StartDriverAndSetMode(int mode, qboolean fullscreen, qboolean noborder)
-{
- rserr_t err;
-
- if (!SDL_WasInit(SDL_INIT_VIDEO))
- {
- char driverName[ 64 ];
-
- if (SDL_Init(SDL_INIT_VIDEO) == -1)
- {
- ri.Printf( PRINT_ALL, "SDL_Init( SDL_INIT_VIDEO ) FAILED (%s)\n",
- SDL_GetError());
- return qfalse;
- }
-
- SDL_VideoDriverName( driverName, sizeof( driverName ) - 1 );
- ri.Printf( PRINT_ALL, "SDL using driver \"%s\"\n", driverName );
- Cvar_Set( "r_sdlDriver", driverName );
- }
-
- if (fullscreen && Cvar_VariableIntegerValue( "in_nograb" ) )
- {
- ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n");
- ri.Cvar_Set( "r_fullscreen", "0" );
- r_fullscreen->modified = qfalse;
- fullscreen = qfalse;
- }
-
- err = GLimp_SetMode(mode, fullscreen, noborder);
-
- switch ( err )
- {
- case RSERR_INVALID_FULLSCREEN:
- ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" );
- return qfalse;
- case RSERR_INVALID_MODE:
- ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode );
- return qfalse;
- default:
- break;
- }
-
- return qtrue;
-}
-
-static qboolean GLimp_HaveExtension(const char *ext)
-{
- const char *ptr = Q_stristr( glConfig.extensions_string, ext );
- if (ptr == NULL)
- return qfalse;
- ptr += strlen(ext);
- return ((*ptr == ' ') || (*ptr == '\0')); // verify it's complete string.
-}
-
-
-/*
-===============
-GLimp_InitExtensions
-===============
-*/
-static void GLimp_InitExtensions( void )
-{
- if ( !r_allowExtensions->integer )
- {
- ri.Printf( PRINT_ALL, "* IGNORING OPENGL EXTENSIONS *\n" );
- return;
- }
-
- ri.Printf( PRINT_ALL, "Initializing OpenGL extensions\n" );
-
- glConfig.textureCompression = TC_NONE;
-
- // GL_EXT_texture_compression_s3tc
- if ( GLimp_HaveExtension( "GL_ARB_texture_compression" ) &&
- GLimp_HaveExtension( "GL_EXT_texture_compression_s3tc" ) )
- {
- if ( r_ext_compressed_textures->value )
- {
- glConfig.textureCompression = TC_S3TC_ARB;
- ri.Printf( PRINT_ALL, "...using GL_EXT_texture_compression_s3tc\n" );
- }
- else
- {
- ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_compression_s3tc\n" );
- }
- }
- else
- {
- ri.Printf( PRINT_ALL, "...GL_EXT_texture_compression_s3tc not found\n" );
- }
-
- // GL_S3_s3tc ... legacy extension before GL_EXT_texture_compression_s3tc.
- if (glConfig.textureCompression == TC_NONE)
- {
- if ( GLimp_HaveExtension( "GL_S3_s3tc" ) )
- {
- if ( r_ext_compressed_textures->value )
- {
- glConfig.textureCompression = TC_S3TC;
- ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" );
- }
- else
- {
- ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" );
- }
- }
- else
- {
- ri.Printf( PRINT_ALL, "...GL_S3_s3tc not found\n" );
- }
- }
-
-
- // GL_EXT_texture_env_add
- glConfig.textureEnvAddAvailable = qfalse;
- if ( GLimp_HaveExtension( "EXT_texture_env_add" ) )
- {
- if ( r_ext_texture_env_add->integer )
- {
- glConfig.textureEnvAddAvailable = qtrue;
- ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" );
- }
- else
- {
- glConfig.textureEnvAddAvailable = qfalse;
- ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" );
- }
- }
- else
- {
- ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" );
- }
-
- // GL_ARB_multitexture
- qglMultiTexCoord2fARB = NULL;
- qglActiveTextureARB = NULL;
- qglClientActiveTextureARB = NULL;
- if ( GLimp_HaveExtension( "GL_ARB_multitexture" ) )
- {
- if ( r_ext_multitexture->value )
- {
- qglMultiTexCoord2fARB = SDL_GL_GetProcAddress( "glMultiTexCoord2fARB" );
- qglActiveTextureARB = SDL_GL_GetProcAddress( "glActiveTextureARB" );
- qglClientActiveTextureARB = SDL_GL_GetProcAddress( "glClientActiveTextureARB" );
-
- if ( qglActiveTextureARB )
- {
- GLint glint = 0;
- qglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &glint );
- glConfig.numTextureUnits = (int) glint;
- if ( glConfig.numTextureUnits > 1 )
- {
- ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" );
- }
- else
- {
- qglMultiTexCoord2fARB = NULL;
- qglActiveTextureARB = NULL;
- qglClientActiveTextureARB = NULL;
- ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" );
- }
- }
- }
- else
- {
- ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" );
- }
- }
- else
- {
- ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" );
- }
-
- // GL_EXT_compiled_vertex_array
- if ( GLimp_HaveExtension( "GL_EXT_compiled_vertex_array" ) )
- {
- if ( r_ext_compiled_vertex_array->value )
- {
- ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" );
- qglLockArraysEXT = ( void ( APIENTRY * )( GLint, GLint ) ) SDL_GL_GetProcAddress( "glLockArraysEXT" );
- qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) SDL_GL_GetProcAddress( "glUnlockArraysEXT" );
- if (!qglLockArraysEXT || !qglUnlockArraysEXT)
- {
- ri.Error (ERR_FATAL, "bad getprocaddress");
- }
- }
- else
- {
- ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" );
- }
- }
- else
- {
- ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" );
- }
-
- textureFilterAnisotropic = qfalse;
- if ( GLimp_HaveExtension( "GL_EXT_texture_filter_anisotropic" ) )
- {
- if ( r_ext_texture_filter_anisotropic->integer ) {
- qglGetIntegerv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, (GLint *)&maxAnisotropy );
- if ( maxAnisotropy <= 0 ) {
- ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not properly supported!\n" );
- maxAnisotropy = 0;
- }
- else
- {
- ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic (max: %i)\n", maxAnisotropy );
- textureFilterAnisotropic = qtrue;
- }
- }
- else
- {
- ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" );
- }
- }
- else
- {
- ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" );
- }
-}
-
-#define R_MODE_FALLBACK 3 // 640 * 480
-
-/*
-===============
-GLimp_Init
-
-This routine is responsible for initializing the OS specific portions
-of OpenGL
-===============
-*/
-void GLimp_Init( void )
-{
- r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH );
- r_sdlDriver = ri.Cvar_Get( "r_sdlDriver", "", CVAR_ROM );
- r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE );
- r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE );
-
- Sys_SetEnv( "SDL_VIDEO_CENTERED", r_centerWindow->integer ? "1" : "" );
-
- Sys_GLimpInit( );
-
- // Create the window and set up the context
- if(GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, r_noborder->integer))
- goto success;
-
- // Try again, this time in a platform specific "safe mode"
- Sys_GLimpSafeInit( );
-
- if(GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, qfalse))
- goto success;
-
- // Finally, try the default screen resolution
- if( r_mode->integer != R_MODE_FALLBACK )
- {
- ri.Printf( PRINT_ALL, "Setting r_mode %d failed, falling back on r_mode %d\n",
- r_mode->integer, R_MODE_FALLBACK );
-
- if(GLimp_StartDriverAndSetMode(R_MODE_FALLBACK, r_fullscreen->integer, qfalse))
- goto success;
- }
-
- // Nothing worked, give up
- ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" );
-
-success:
- // This values force the UI to disable driver selection
- glConfig.driverType = GLDRV_ICD;
- glConfig.hardwareType = GLHW_GENERIC;
- glConfig.deviceSupportsGamma = SDL_SetGamma( 1.0f, 1.0f, 1.0f ) >= 0;
-
- // Mysteriously, if you use an NVidia graphics card and multiple monitors,
- // SDL_SetGamma will incorrectly return false... the first time; ask
- // again and you get the correct answer. This is a suspected driver bug, see
- // http://bugzilla.icculus.org/show_bug.cgi?id=4316
- glConfig.deviceSupportsGamma = SDL_SetGamma( 1.0f, 1.0f, 1.0f ) >= 0;
-
- // get our config strings
- Q_strncpyz( glConfig.vendor_string, (char *) qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) );
- Q_strncpyz( glConfig.renderer_string, (char *) qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) );
- if (*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n')
- glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0;
- Q_strncpyz( glConfig.version_string, (char *) qglGetString (GL_VERSION), sizeof( glConfig.version_string ) );
- Q_strncpyz( glConfig.extensions_string, (char *) qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) );
-
- // initialize extensions
- GLimp_InitExtensions( );
-
- ri.Cvar_Get( "r_availableModes", "", CVAR_ROM );
-
- // This depends on SDL_INIT_VIDEO, hence having it here
- IN_Init( );
-}
-
-
-/*
-===============
-GLimp_EndFrame
-
-Responsible for doing a swapbuffers
-===============
-*/
-void GLimp_EndFrame( void )
-{
- // don't flip if drawing to front buffer
- if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 )
- {
- SDL_GL_SwapBuffers();
- }
-
- if( r_fullscreen->modified )
- {
- qboolean fullscreen;
- qboolean needToToggle = qtrue;
- qboolean sdlToggled = qfalse;
- SDL_Surface *s = SDL_GetVideoSurface( );
-
- if( s )
- {
- // Find out the current state
- fullscreen = !!( s->flags & SDL_FULLSCREEN );
-
- if( r_fullscreen->integer && Cvar_VariableIntegerValue( "in_nograb" ) )
- {
- ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n");
- ri.Cvar_Set( "r_fullscreen", "0" );
- r_fullscreen->modified = qfalse;
- }
-
- // Is the state we want different from the current state?
- needToToggle = !!r_fullscreen->integer != fullscreen;
-
- if( needToToggle )
- sdlToggled = SDL_WM_ToggleFullScreen( s );
- }
-
- if( needToToggle )
- {
- // SDL_WM_ToggleFullScreen didn't work, so do it the slow way
- if( !sdlToggled )
- Cbuf_AddText( "vid_restart" );
-
- IN_Restart( );
- }
-
- r_fullscreen->modified = qfalse;
- }
-}
-
-
-
-#ifdef SMP
-/*
-===========================================================
-
-SMP acceleration
-
-===========================================================
-*/
-
-/*
- * I have no idea if this will even work...most platforms don't offer
- * thread-safe OpenGL libraries, and it looks like the original Linux
- * code counted on each thread claiming the GL context with glXMakeCurrent(),
- * which you can't currently do in SDL. We'll just have to hope for the best.
- */
-
-static SDL_mutex *smpMutex = NULL;
-static SDL_cond *renderCommandsEvent = NULL;
-static SDL_cond *renderCompletedEvent = NULL;
-static void (*glimpRenderThread)( void ) = NULL;
-static SDL_Thread *renderThread = NULL;
-
-/*
-===============
-GLimp_ShutdownRenderThread
-===============
-*/
-static void GLimp_ShutdownRenderThread(void)
-{
- if (smpMutex != NULL)
- {
- SDL_DestroyMutex(smpMutex);
- smpMutex = NULL;
- }
-
- if (renderCommandsEvent != NULL)
- {
- SDL_DestroyCond(renderCommandsEvent);
- renderCommandsEvent = NULL;
- }
-
- if (renderCompletedEvent != NULL)
- {
- SDL_DestroyCond(renderCompletedEvent);
- renderCompletedEvent = NULL;
- }
-
- glimpRenderThread = NULL;
-}
-
-/*
-===============
-GLimp_RenderThreadWrapper
-===============
-*/
-static int GLimp_RenderThreadWrapper( void *arg )
-{
- Com_Printf( "Render thread starting\n" );
-
- glimpRenderThread();
-
- GLimp_SetCurrentContext(NULL);
-
- Com_Printf( "Render thread terminating\n" );
-
- return 0;
-}
-
-/*
-===============
-GLimp_SpawnRenderThread
-===============
-*/
-qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
-{
- static qboolean warned = qfalse;
- if (!warned)
- {
- Com_Printf("WARNING: You enable r_smp at your own risk!\n");
- warned = qtrue;
- }
-
-#ifndef MACOS_X
- return qfalse; /* better safe than sorry for now. */
-#endif
-
- if (renderThread != NULL) /* hopefully just a zombie at this point... */
- {
- Com_Printf("Already a render thread? Trying to clean it up...\n");
- SDL_WaitThread(renderThread, NULL);
- renderThread = NULL;
- GLimp_ShutdownRenderThread();
- }
-
- smpMutex = SDL_CreateMutex();
- if (smpMutex == NULL)
- {
- Com_Printf( "smpMutex creation failed: %s\n", SDL_GetError() );
- GLimp_ShutdownRenderThread();
- return qfalse;
- }
-
- renderCommandsEvent = SDL_CreateCond();
- if (renderCommandsEvent == NULL)
- {
- Com_Printf( "renderCommandsEvent creation failed: %s\n", SDL_GetError() );
- GLimp_ShutdownRenderThread();
- return qfalse;
- }
-
- renderCompletedEvent = SDL_CreateCond();
- if (renderCompletedEvent == NULL)
- {
- Com_Printf( "renderCompletedEvent creation failed: %s\n", SDL_GetError() );
- GLimp_ShutdownRenderThread();
- return qfalse;
- }
-
- glimpRenderThread = function;
- renderThread = SDL_CreateThread(GLimp_RenderThreadWrapper, NULL);
- if ( renderThread == NULL )
- {
- ri.Printf( PRINT_ALL, "SDL_CreateThread() returned %s", SDL_GetError() );
- GLimp_ShutdownRenderThread();
- return qfalse;
- }
- else
- {
- // tma 01/09/07: don't think this is necessary anyway?
- //
- // !!! FIXME: No detach API available in SDL!
- //ret = pthread_detach( renderThread );
- //if ( ret ) {
- //ri.Printf( PRINT_ALL, "pthread_detach returned %d: %s", ret, strerror( ret ) );
- //}
- }
-
- return qtrue;
-}
-
-static volatile void *smpData = NULL;
-static volatile qboolean smpDataReady;
-
-/*
-===============
-GLimp_RendererSleep
-===============
-*/
-void *GLimp_RendererSleep( void )
-{
- void *data = NULL;
-
- GLimp_SetCurrentContext(NULL);
-
- SDL_LockMutex(smpMutex);
- {
- smpData = NULL;
- smpDataReady = qfalse;
-
- // after this, the front end can exit GLimp_FrontEndSleep
- SDL_CondSignal(renderCompletedEvent);
-
- while ( !smpDataReady )
- SDL_CondWait(renderCommandsEvent, smpMutex);
-
- data = (void *)smpData;
- }
- SDL_UnlockMutex(smpMutex);
-
- GLimp_SetCurrentContext(opengl_context);
-
- return data;
-}
-
-/*
-===============
-GLimp_FrontEndSleep
-===============
-*/
-void GLimp_FrontEndSleep( void )
-{
- SDL_LockMutex(smpMutex);
- {
- while ( smpData )
- SDL_CondWait(renderCompletedEvent, smpMutex);
- }
- SDL_UnlockMutex(smpMutex);
-
- GLimp_SetCurrentContext(opengl_context);
-}
-
-/*
-===============
-GLimp_WakeRenderer
-===============
-*/
-void GLimp_WakeRenderer( void *data )
-{
- GLimp_SetCurrentContext(NULL);
-
- SDL_LockMutex(smpMutex);
- {
- assert( smpData == NULL );
- smpData = data;
- smpDataReady = qtrue;
-
- // after this, the renderer can continue through GLimp_RendererSleep
- SDL_CondSignal(renderCommandsEvent);
- }
- SDL_UnlockMutex(smpMutex);
-}
-
-#else
-
-// No SMP - stubs
-void GLimp_RenderThreadWrapper( void *arg )
-{
-}
-
-qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
-{
- ri.Printf( PRINT_WARNING, "ERROR: SMP support was disabled at compile time\n");
- return qfalse;
-}
-
-void *GLimp_RendererSleep( void )
-{
- return NULL;
-}
-
-void GLimp_FrontEndSleep( void )
-{
-}
-
-void GLimp_WakeRenderer( void *data )
-{
-}
-
-#endif
diff --git a/engine/code/sdl/sdl_icon.h b/engine/code/sdl/sdl_icon.h
deleted file mode 100644
index 866c549..0000000
--- a/engine/code/sdl/sdl_icon.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/* GIMP RGBA C-Source image dump (sdl_icon.h) */
-
-static const struct {
- unsigned int width;
- unsigned int height;
- unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */
- unsigned char pixel_data[32 * 32 * 4 + 1];
-} CLIENT_WINDOW_ICON = {
- 32, 32, 4,
- "\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\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\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\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\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\0\0\0w\0\0\377w\0\0\377\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\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\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\0\0\0\0\0\0\0\0\0w\0\0\377w\0\0"
- "\377\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\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\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\0\0\0\0\0\0\0\0\0w\0\0\377w\0\0\377\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\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\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\0\0\0\0\0\0\0\0\0w\0"
- "\0\377w\0\0\377\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\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\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\0\0\0\0\0\0\0\0\0w\0\0\377w\0\0\377\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\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\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\0\0\0\0\0"
- "\0\0\0\0w\0\0\377w\0\0\377\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\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\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\0\0\0\0\0\0\0\0\0\210\0\0\377\210\0\0\377"
- "\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\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\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\0\0\0\0\0\0\0\0\0\210\0\0\377\210\0\0\377\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\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\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\0\0\0\0\0\0\0\0\0"
- "\210\0\0\377\210\0\0\377\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\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\231\0\0\377\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\0\0\0\0\0\0\0\0\0\0\0\210\0\0\377\210\0\0"
- "\377\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\0\0\0\0\0\0\0\0\0\0\0\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\252\0\0"
- "\377\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\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\231\0\0\377\210\0\0\377\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\0\0\0\0\0"
- "\0\0\0\0\0\0\0\0\0\0\252\0\0\377\0\0\0\0\273\0\0\377\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\0\0\0\0\0\0\0\0\0"
- "\0\0\0\0\0\0\0\0\0\0\231\0\0\377\231\0\0\377\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\0\0\0\0\0\0\0\0\0\0\0\0\0"
- "\0\0\0\0\0\0\273\0\0\377\314\0\0\377\231\0\0\377\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\0\0\0\0\0\0\0\0\0\0\0"
- "\0\0\0\0\231\0\0\377\231\0\0\377\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\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\231\0\0"
- "\377\314\0\0\377\0\0\0\0\335\0\0\377\314\0\0\377\231\0\0\377\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\0\0\0\0\0"
- "\0\0\231\0\0\377\231\0\0\377\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\0\0\0\0\0\0\0\231\0\0\377\314\0\0\377\335"
- "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\231\0\0\377\314\0\0\377\335\0\0\377\335"
- "\0\0\377\273\0\0\377\231\0\0\377\210\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
- "\0\0\0\0\0\0\0\0\0\0\231\0\0\377\252\0\0\377\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\252\0\0\377\273\0\0\377\335\0\0\377\335\0\0"
- "\377\314\0\0\377\231\0\0\377\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\252\0\0\377\314\0\0\377\314\0\0\377\314\0\0\377\314\0\0\377"
- "\314\0\0\377\314\0\0\377\314\0\0\377\314\0\0\377\0\0\0\0\252\0\0\377\252"
- "\0\0\377\0\0\0\0\314\0\0\377\314\0\0\377\314\0\0\377\314\0\0\377\314\0\0"
- "\377\314\0\0\377\314\0\0\377\314\0\0\377\252\0\0\377\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\0\0\0\0\0\0\0\0\0"
- "\0\0\0\0\0\0\0\0\0\0\210\0\0\377\231\0\0\377\273\0\0\377\314\0\0\377\314"
- "\0\0\377\0\0\0\0\252\0\0\377\252\0\0\377\0\0\0\0\314\0\0\377\314\0\0\377"
- "\273\0\0\377\231\0\0\377\210\0\0\377\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\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\0\0\0\0\0\0\0\0\0\0\210\0\0\377"
- "\273\0\0\377\0\0\0\0\252\0\0\377\252\0\0\377\0\0\0\0\273\0\0\377\210\0\0"
- "\377\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\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\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0w\0\0\377\273\0\0\377"
- "\0\0\0\0\231\0\0\377\252\0\0\377\0\0\0\0\273\0\0\377w\0\0\377\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\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\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\252\0\0\377\0\0\0\0\231\0\0"
- "\377\231\0\0\377\0\0\0\0\252\0\0\377\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\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\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\252\0\0\377\0\0\0\0\210\0\0\377\231\0\0\377"
- "\0\0\0\0\252\0\0\377\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\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\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\231\0\0\377\0\0\0\0\210\0\0\377\210\0\0\377\0\0\0\0\231\0\0"
- "\377\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\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\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\231"
- "\0\0\377\0\0\0\0w\0\0\377\210\0\0\377\0\0\0\0\231\0\0\377\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\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\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\210\0\0\377\0\0\0\0\210"
- "\0\0\377\210\0\0\377\0\0\0\0\210\0\0\377\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\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\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\210\0\0\377\0\0\0\0w\0\0\377\210\0\0\377"
- "\0\0\0\0\210\0\0\377\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\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\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\0w\0\0\377\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0w\0\0\377\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\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\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\0w\0\0\377\0\0\0\0"
- "w\0\0\377w\0\0\377\0\0\0\0w\0\0\377\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\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\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\0w\0\0\377\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0w\0"
- "\0\377\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\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\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\0f\0\0\377f\0\0\377\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\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\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\0\0\0\0\0\0\0\0\0f\0\0\377f\0\0\377"
- "\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\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\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\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\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\0\0\0",
-};
-
diff --git a/engine/code/sdl/sdl_input.c b/engine/code/sdl/sdl_input.c
deleted file mode 100644
index 4949dc1..0000000
--- a/engine/code/sdl/sdl_input.c
+++ /dev/null
@@ -1,1038 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#ifdef USE_LOCAL_HEADERS
-# include "SDL.h"
-#else
-# include <SDL.h>
-#endif
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "../renderer/tr_local.h"
-#include "../client/client.h"
-#include "../sys/sys_local.h"
-
-#define ARRAYLEN(x) (sizeof(x)/sizeof(x[0]))
-
-#ifdef MACOS_X
-// Mouse acceleration needs to be disabled
-#define MACOS_X_ACCELERATION_HACK
-// Cursor needs hack to hide
-#define MACOS_X_CURSOR_HACK
-#endif
-
-#ifdef MACOS_X_ACCELERATION_HACK
-#include <IOKit/IOTypes.h>
-#include <IOKit/hidsystem/IOHIDLib.h>
-#include <IOKit/hidsystem/IOHIDParameter.h>
-#include <IOKit/hidsystem/event_status_driver.h>
-#endif
-
-static cvar_t *in_keyboardDebug = NULL;
-
-static SDL_Joystick *stick = NULL;
-
-static qboolean mouseAvailable = qfalse;
-static qboolean mouseActive = qfalse;
-static qboolean keyRepeatEnabled = qfalse;
-
-static cvar_t *in_mouse = NULL;
-#ifdef MACOS_X_ACCELERATION_HACK
-static cvar_t *in_disablemacosxmouseaccel = NULL;
-static double originalMouseSpeed = -1.0;
-#endif
-static cvar_t *in_nograb;
-
-static cvar_t *in_joystick = NULL;
-static cvar_t *in_joystickDebug = NULL;
-static cvar_t *in_joystickThreshold = NULL;
-static cvar_t *in_joystickNo = NULL;
-
-static int vidRestartTime = 0;
-
-#define CTRL(a) ((a)-'a'+1)
-
-/*
-===============
-IN_PrintKey
-===============
-*/
-static void IN_PrintKey( const SDL_keysym *keysym, keyNum_t key, qboolean down )
-{
- if( down )
- Com_Printf( "+ " );
- else
- Com_Printf( " " );
-
- Com_Printf( "0x%02x \"%s\"", keysym->scancode,
- SDL_GetKeyName( keysym->sym ) );
-
- if( keysym->mod & KMOD_LSHIFT ) Com_Printf( " KMOD_LSHIFT" );
- if( keysym->mod & KMOD_RSHIFT ) Com_Printf( " KMOD_RSHIFT" );
- if( keysym->mod & KMOD_LCTRL ) Com_Printf( " KMOD_LCTRL" );
- if( keysym->mod & KMOD_RCTRL ) Com_Printf( " KMOD_RCTRL" );
- if( keysym->mod & KMOD_LALT ) Com_Printf( " KMOD_LALT" );
- if( keysym->mod & KMOD_RALT ) Com_Printf( " KMOD_RALT" );
- if( keysym->mod & KMOD_LMETA ) Com_Printf( " KMOD_LMETA" );
- if( keysym->mod & KMOD_RMETA ) Com_Printf( " KMOD_RMETA" );
- if( keysym->mod & KMOD_NUM ) Com_Printf( " KMOD_NUM" );
- if( keysym->mod & KMOD_CAPS ) Com_Printf( " KMOD_CAPS" );
- if( keysym->mod & KMOD_MODE ) Com_Printf( " KMOD_MODE" );
- if( keysym->mod & KMOD_RESERVED ) Com_Printf( " KMOD_RESERVED" );
-
- Com_Printf( " Q:0x%02x(%s)", key, Key_KeynumToString( key ) );
-
- if( keysym->unicode )
- {
- Com_Printf( " U:0x%02x", keysym->unicode );
-
- if( keysym->unicode > ' ' && keysym->unicode < '~' )
- Com_Printf( "(%c)", (char)keysym->unicode );
- }
-
- Com_Printf( "\n" );
-}
-
-#define MAX_CONSOLE_KEYS 16
-
-/*
-===============
-IN_IsConsoleKey
-===============
-*/
-static qboolean IN_IsConsoleKey( keyNum_t key, const unsigned char character )
-{
- typedef struct consoleKey_s
- {
- enum
- {
- KEY,
- CHARACTER
- } type;
-
- union
- {
- keyNum_t key;
- unsigned char character;
- } u;
- } consoleKey_t;
-
- static consoleKey_t consoleKeys[ MAX_CONSOLE_KEYS ];
- static int numConsoleKeys = 0;
- int i;
-
- // Only parse the variable when it changes
- if( cl_consoleKeys->modified )
- {
- char *text_p, *token;
-
- cl_consoleKeys->modified = qfalse;
- text_p = cl_consoleKeys->string;
- numConsoleKeys = 0;
-
- while( numConsoleKeys < MAX_CONSOLE_KEYS )
- {
- consoleKey_t *c = &consoleKeys[ numConsoleKeys ];
- int charCode = 0;
-
- token = COM_Parse( &text_p );
- if( !token[ 0 ] )
- break;
-
- if( strlen( token ) == 4 )
- charCode = Com_HexStrToInt( token );
-
- if( charCode > 0 )
- {
- c->type = CHARACTER;
- c->u.character = (unsigned char)charCode;
- }
- else
- {
- c->type = KEY;
- c->u.key = Key_StringToKeynum( token );
-
- // 0 isn't a key
- if( c->u.key <= 0 )
- continue;
- }
-
- numConsoleKeys++;
- }
- }
-
- // If the character is the same as the key, prefer the character
- if( key == character )
- key = 0;
-
- for( i = 0; i < numConsoleKeys; i++ )
- {
- consoleKey_t *c = &consoleKeys[ i ];
-
- switch( c->type )
- {
- case KEY:
- if( key && c->u.key == key )
- return qtrue;
- break;
-
- case CHARACTER:
- if( c->u.character == character )
- return qtrue;
- break;
- }
- }
-
- return qfalse;
-}
-
-/*
-===============
-IN_TranslateSDLToQ3Key
-===============
-*/
-static const char *IN_TranslateSDLToQ3Key( SDL_keysym *keysym,
- keyNum_t *key, qboolean down )
-{
- static unsigned char buf[ 2 ] = { '\0', '\0' };
-
- *buf = '\0';
- *key = 0;
-
- if( keysym->sym >= SDLK_SPACE && keysym->sym < SDLK_DELETE )
- {
- // These happen to match the ASCII chars
- *key = (int)keysym->sym;
- }
- else
- {
- switch( keysym->sym )
- {
- case SDLK_PAGEUP: *key = K_PGUP; break;
- case SDLK_KP9: *key = K_KP_PGUP; break;
- case SDLK_PAGEDOWN: *key = K_PGDN; break;
- case SDLK_KP3: *key = K_KP_PGDN; break;
- case SDLK_KP7: *key = K_KP_HOME; break;
- case SDLK_HOME: *key = K_HOME; break;
- case SDLK_KP1: *key = K_KP_END; break;
- case SDLK_END: *key = K_END; break;
- case SDLK_KP4: *key = K_KP_LEFTARROW; break;
- case SDLK_LEFT: *key = K_LEFTARROW; break;
- case SDLK_KP6: *key = K_KP_RIGHTARROW; break;
- case SDLK_RIGHT: *key = K_RIGHTARROW; break;
- case SDLK_KP2: *key = K_KP_DOWNARROW; break;
- case SDLK_DOWN: *key = K_DOWNARROW; break;
- case SDLK_KP8: *key = K_KP_UPARROW; break;
- case SDLK_UP: *key = K_UPARROW; break;
- case SDLK_ESCAPE: *key = K_ESCAPE; break;
- case SDLK_KP_ENTER: *key = K_KP_ENTER; break;
- case SDLK_RETURN: *key = K_ENTER; break;
- case SDLK_TAB: *key = K_TAB; break;
- case SDLK_F1: *key = K_F1; break;
- case SDLK_F2: *key = K_F2; break;
- case SDLK_F3: *key = K_F3; break;
- case SDLK_F4: *key = K_F4; break;
- case SDLK_F5: *key = K_F5; break;
- case SDLK_F6: *key = K_F6; break;
- case SDLK_F7: *key = K_F7; break;
- case SDLK_F8: *key = K_F8; break;
- case SDLK_F9: *key = K_F9; break;
- case SDLK_F10: *key = K_F10; break;
- case SDLK_F11: *key = K_F11; break;
- case SDLK_F12: *key = K_F12; break;
- case SDLK_F13: *key = K_F13; break;
- case SDLK_F14: *key = K_F14; break;
- case SDLK_F15: *key = K_F15; break;
-
- case SDLK_BACKSPACE: *key = K_BACKSPACE; break;
- case SDLK_KP_PERIOD: *key = K_KP_DEL; break;
- case SDLK_DELETE: *key = K_DEL; break;
- case SDLK_PAUSE: *key = K_PAUSE; break;
-
- case SDLK_LSHIFT:
- case SDLK_RSHIFT: *key = K_SHIFT; break;
-
- case SDLK_LCTRL:
- case SDLK_RCTRL: *key = K_CTRL; break;
-
- case SDLK_RMETA:
- case SDLK_LMETA: *key = K_COMMAND; break;
-
- case SDLK_RALT:
- case SDLK_LALT: *key = K_ALT; break;
-
- case SDLK_LSUPER:
- case SDLK_RSUPER: *key = K_SUPER; break;
-
- case SDLK_KP5: *key = K_KP_5; break;
- case SDLK_INSERT: *key = K_INS; break;
- case SDLK_KP0: *key = K_KP_INS; break;
- case SDLK_KP_MULTIPLY: *key = K_KP_STAR; break;
- case SDLK_KP_PLUS: *key = K_KP_PLUS; break;
- case SDLK_KP_MINUS: *key = K_KP_MINUS; break;
- case SDLK_KP_DIVIDE: *key = K_KP_SLASH; break;
-
- case SDLK_MODE: *key = K_MODE; break;
- case SDLK_COMPOSE: *key = K_COMPOSE; break;
- case SDLK_HELP: *key = K_HELP; break;
- case SDLK_PRINT: *key = K_PRINT; break;
- case SDLK_SYSREQ: *key = K_SYSREQ; break;
- case SDLK_BREAK: *key = K_BREAK; break;
- case SDLK_MENU: *key = K_MENU; break;
- case SDLK_POWER: *key = K_POWER; break;
- case SDLK_EURO: *key = K_EURO; break;
- case SDLK_UNDO: *key = K_UNDO; break;
- case SDLK_SCROLLOCK: *key = K_SCROLLOCK; break;
- case SDLK_NUMLOCK: *key = K_KP_NUMLOCK; break;
- case SDLK_CAPSLOCK: *key = K_CAPSLOCK; break;
-
- default:
- if( keysym->sym >= SDLK_WORLD_0 && keysym->sym <= SDLK_WORLD_95 )
- *key = ( keysym->sym - SDLK_WORLD_0 ) + K_WORLD_0;
- break;
- }
- }
-
- if( down && keysym->unicode && !( keysym->unicode & 0xFF00 ) )
- {
- unsigned char ch = (unsigned char)keysym->unicode & 0xFF;
-
- switch( ch )
- {
- case 127: // ASCII delete
- if( *key != K_DEL )
- {
- // ctrl-h
- *buf = CTRL('h');
- break;
- }
- // fallthrough
-
- default: *buf = ch; break;
- }
- }
-
- if( in_keyboardDebug->integer )
- IN_PrintKey( keysym, *key, down );
-
- // Keys that have ASCII names but produce no character are probably
- // dead keys -- ignore them
- if( down && strlen( Key_KeynumToString( *key ) ) == 1 &&
- keysym->unicode == 0 )
- {
- if( in_keyboardDebug->integer )
- Com_Printf( " Ignored dead key '%c'\n", *key );
-
- *key = 0;
- }
-
- if( IN_IsConsoleKey( *key, *buf ) )
- {
- // Console keys can't be bound or generate characters
- *key = K_CONSOLE;
- *buf = '\0';
- }
-
- // Don't allow extended ASCII to generate characters
- if( *buf & 0x80 )
- *buf = '\0';
-
- return (char *)buf;
-}
-
-#ifdef MACOS_X_ACCELERATION_HACK
-/*
-===============
-IN_GetIOHandle
-===============
-*/
-static io_connect_t IN_GetIOHandle(void) // mac os x mouse accel hack
-{
- io_connect_t iohandle = MACH_PORT_NULL;
- kern_return_t status;
- io_service_t iohidsystem = MACH_PORT_NULL;
- mach_port_t masterport;
-
- status = IOMasterPort(MACH_PORT_NULL, &masterport);
- if(status != KERN_SUCCESS)
- return 0;
-
- iohidsystem = IORegistryEntryFromPath(masterport, kIOServicePlane ":/IOResources/IOHIDSystem");
- if(!iohidsystem)
- return 0;
-
- status = IOServiceOpen(iohidsystem, mach_task_self(), kIOHIDParamConnectType, &iohandle);
- IOObjectRelease(iohidsystem);
-
- return iohandle;
-}
-#endif
-
-/*
-===============
-IN_GobbleMotionEvents
-===============
-*/
-static void IN_GobbleMotionEvents( void )
-{
- SDL_Event dummy[ 1 ];
-
- // Gobble any mouse motion events
- SDL_PumpEvents( );
- while( SDL_PeepEvents( dummy, 1, SDL_GETEVENT,
- SDL_EVENTMASK( SDL_MOUSEMOTION ) ) ) { }
-}
-
-/*
-===============
-IN_ActivateMouse
-===============
-*/
-static void IN_ActivateMouse( void )
-{
- if (!mouseAvailable || !SDL_WasInit( SDL_INIT_VIDEO ) )
- return;
-
-#ifdef MACOS_X_ACCELERATION_HACK
- if (!mouseActive) // mac os x mouse accel hack
- {
- // Save the status of mouse acceleration
- originalMouseSpeed = -1.0; // in case of error
- if(in_disablemacosxmouseaccel->integer)
- {
- io_connect_t mouseDev = IN_GetIOHandle();
- if(mouseDev != 0)
- {
- if(IOHIDGetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), &originalMouseSpeed) == kIOReturnSuccess)
- {
- Com_Printf("previous mouse acceleration: %f\n", originalMouseSpeed);
- if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), -1.0) != kIOReturnSuccess)
- {
- Com_Printf("Could not disable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n");
- Cvar_Set ("in_disablemacosxmouseaccel", 0);
- }
- }
- else
- {
- Com_Printf("Could not disable mouse acceleration (failed at IOHIDGetAccelerationWithKey).\n");
- Cvar_Set ("in_disablemacosxmouseaccel", 0);
- }
- IOServiceClose(mouseDev);
- }
- else
- {
- Com_Printf("Could not disable mouse acceleration (failed at IO_GetIOHandle).\n");
- Cvar_Set ("in_disablemacosxmouseaccel", 0);
- }
- }
- }
-#endif
-
- if( !mouseActive )
- {
- SDL_ShowCursor( 0 );
-#ifdef MACOS_X_CURSOR_HACK
- // This is a bug in the current SDL/macosx...have to toggle it a few
- // times to get the cursor to hide.
- SDL_ShowCursor( 1 );
- SDL_ShowCursor( 0 );
-#endif
- SDL_WM_GrabInput( SDL_GRAB_ON );
-
- IN_GobbleMotionEvents( );
- }
-
- // in_nograb makes no sense in fullscreen mode
- if( !r_fullscreen->integer )
- {
- if( in_nograb->modified || !mouseActive )
- {
- if( in_nograb->integer )
- SDL_WM_GrabInput( SDL_GRAB_OFF );
- else
- SDL_WM_GrabInput( SDL_GRAB_ON );
-
- in_nograb->modified = qfalse;
- }
- }
-
- mouseActive = qtrue;
-}
-
-/*
-===============
-IN_DeactivateMouse
-===============
-*/
-static void IN_DeactivateMouse( void )
-{
- if( !SDL_WasInit( SDL_INIT_VIDEO ) )
- return;
-
- // Always show the cursor when the mouse is disabled,
- // but not when fullscreen
- if( !r_fullscreen->integer )
- SDL_ShowCursor( 1 );
-
- if( !mouseAvailable )
- return;
-
-#ifdef MACOS_X_ACCELERATION_HACK
- if (mouseActive) // mac os x mouse accel hack
- {
- if(originalMouseSpeed != -1.0)
- {
- io_connect_t mouseDev = IN_GetIOHandle();
- if(mouseDev != 0)
- {
- Com_Printf("restoring mouse acceleration to: %f\n", originalMouseSpeed);
- if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), originalMouseSpeed) != kIOReturnSuccess)
- Com_Printf("Could not re-enable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n");
- IOServiceClose(mouseDev);
- }
- else
- Com_Printf("Could not re-enable mouse acceleration (failed at IO_GetIOHandle).\n");
- }
- }
-#endif
-
- if( mouseActive )
- {
- IN_GobbleMotionEvents( );
-
- SDL_WM_GrabInput( SDL_GRAB_OFF );
-
- // Don't warp the mouse unless the cursor is within the window
- if( SDL_GetAppState( ) & SDL_APPMOUSEFOCUS )
- SDL_WarpMouse( glConfig.vidWidth / 2, glConfig.vidHeight / 2 );
-
- mouseActive = qfalse;
- }
-}
-
-// We translate axes movement into keypresses
-static int joy_keys[16] = {
- K_LEFTARROW, K_RIGHTARROW,
- K_UPARROW, K_DOWNARROW,
- K_JOY16, K_JOY17,
- K_JOY18, K_JOY19,
- K_JOY20, K_JOY21,
- K_JOY22, K_JOY23,
-
- K_JOY24, K_JOY25,
- K_JOY26, K_JOY27
-};
-
-// translate hat events into keypresses
-// the 4 highest buttons are used for the first hat ...
-static int hat_keys[16] = {
- K_JOY29, K_JOY30,
- K_JOY31, K_JOY32,
- K_JOY25, K_JOY26,
- K_JOY27, K_JOY28,
- K_JOY21, K_JOY22,
- K_JOY23, K_JOY24,
- K_JOY17, K_JOY18,
- K_JOY19, K_JOY20
-};
-
-
-struct
-{
- qboolean buttons[16]; // !!! FIXME: these might be too many.
- unsigned int oldaxes;
- unsigned int oldhats;
-} stick_state;
-
-
-/*
-===============
-IN_InitJoystick
-===============
-*/
-static void IN_InitJoystick( void )
-{
- int i = 0;
- int total = 0;
-
- if (stick != NULL)
- SDL_JoystickClose(stick);
-
- stick = NULL;
- memset(&stick_state, '\0', sizeof (stick_state));
-
- if( !in_joystick->integer ) {
- Com_DPrintf( "Joystick is not active.\n" );
- return;
- }
-
- if (!SDL_WasInit(SDL_INIT_JOYSTICK))
- {
- Com_DPrintf("Calling SDL_Init(SDL_INIT_JOYSTICK)...\n");
- if (SDL_Init(SDL_INIT_JOYSTICK) == -1)
- {
- Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) failed: %s\n", SDL_GetError());
- return;
- }
- Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) passed.\n");
- }
-
- total = SDL_NumJoysticks();
- Com_DPrintf("%d possible joysticks\n", total);
- for (i = 0; i < total; i++)
- Com_DPrintf("[%d] %s\n", i, SDL_JoystickName(i));
-
- in_joystickNo = Cvar_Get( "in_joystickNo", "0", CVAR_ARCHIVE );
- if( in_joystickNo->integer < 0 || in_joystickNo->integer >= total )
- Cvar_Set( "in_joystickNo", "0" );
-
- stick = SDL_JoystickOpen( in_joystickNo->integer );
-
- if (stick == NULL) {
- Com_DPrintf( "No joystick opened.\n" );
- return;
- }
-
- Com_DPrintf( "Joystick %d opened\n", in_joystickNo->integer );
- Com_DPrintf( "Name: %s\n", SDL_JoystickName(in_joystickNo->integer) );
- Com_DPrintf( "Axes: %d\n", SDL_JoystickNumAxes(stick) );
- Com_DPrintf( "Hats: %d\n", SDL_JoystickNumHats(stick) );
- Com_DPrintf( "Buttons: %d\n", SDL_JoystickNumButtons(stick) );
- Com_DPrintf( "Balls: %d\n", SDL_JoystickNumBalls(stick) );
-
- SDL_JoystickEventState(SDL_QUERY);
-}
-
-/*
-===============
-IN_ShutdownJoystick
-===============
-*/
-static void IN_ShutdownJoystick( void )
-{
- if (stick)
- {
- SDL_JoystickClose(stick);
- stick = NULL;
- }
-
- SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
-}
-
-/*
-===============
-IN_JoyMove
-===============
-*/
-static void IN_JoyMove( void )
-{
- qboolean joy_pressed[ARRAYLEN(joy_keys)];
- unsigned int axes = 0;
- unsigned int hats = 0;
- int total = 0;
- int i = 0;
-
- if (!stick)
- return;
-
- SDL_JoystickUpdate();
-
- memset(joy_pressed, '\0', sizeof (joy_pressed));
-
- // update the ball state.
- total = SDL_JoystickNumBalls(stick);
- if (total > 0)
- {
- int balldx = 0;
- int balldy = 0;
- for (i = 0; i < total; i++)
- {
- int dx = 0;
- int dy = 0;
- SDL_JoystickGetBall(stick, i, &dx, &dy);
- balldx += dx;
- balldy += dy;
- }
- if (balldx || balldy)
- {
- // !!! FIXME: is this good for stick balls, or just mice?
- // Scale like the mouse input...
- if (abs(balldx) > 1)
- balldx *= 2;
- if (abs(balldy) > 1)
- balldy *= 2;
- Com_QueueEvent( 0, SE_MOUSE, balldx, balldy, 0, NULL );
- }
- }
-
- // now query the stick buttons...
- total = SDL_JoystickNumButtons(stick);
- if (total > 0)
- {
- if (total > ARRAYLEN(stick_state.buttons))
- total = ARRAYLEN(stick_state.buttons);
- for (i = 0; i < total; i++)
- {
- qboolean pressed = (SDL_JoystickGetButton(stick, i) != 0);
- if (pressed != stick_state.buttons[i])
- {
- Com_QueueEvent( 0, SE_KEY, K_JOY1 + i, pressed, 0, NULL );
- stick_state.buttons[i] = pressed;
- }
- }
- }
-
- // look at the hats...
- total = SDL_JoystickNumHats(stick);
- if (total > 0)
- {
- if (total > 4) total = 4;
- for (i = 0; i < total; i++)
- {
- ((Uint8 *)&hats)[i] = SDL_JoystickGetHat(stick, i);
- }
- }
-
- // update hat state
- if (hats != stick_state.oldhats)
- {
- for( i = 0; i < 4; i++ ) {
- if( ((Uint8 *)&hats)[i] != ((Uint8 *)&stick_state.oldhats)[i] ) {
- // release event
- switch( ((Uint8 *)&stick_state.oldhats)[i] ) {
- case SDL_HAT_UP:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
- break;
- case SDL_HAT_RIGHT:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
- break;
- case SDL_HAT_DOWN:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
- break;
- case SDL_HAT_LEFT:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
- break;
- case SDL_HAT_RIGHTUP:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
- break;
- case SDL_HAT_RIGHTDOWN:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
- break;
- case SDL_HAT_LEFTUP:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
- break;
- case SDL_HAT_LEFTDOWN:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
- break;
- default:
- break;
- }
- // press event
- switch( ((Uint8 *)&hats)[i] ) {
- case SDL_HAT_UP:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
- break;
- case SDL_HAT_RIGHT:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
- break;
- case SDL_HAT_DOWN:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
- break;
- case SDL_HAT_LEFT:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
- break;
- case SDL_HAT_RIGHTUP:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
- break;
- case SDL_HAT_RIGHTDOWN:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
- break;
- case SDL_HAT_LEFTUP:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
- break;
- case SDL_HAT_LEFTDOWN:
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
- Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
- break;
- default:
- break;
- }
- }
- }
- }
-
- // save hat state
- stick_state.oldhats = hats;
-
- // finally, look at the axes...
- total = SDL_JoystickNumAxes(stick);
- if (total > 0)
- {
- if (total > 16) total = 16;
- for (i = 0; i < total; i++)
- {
- Sint16 axis = SDL_JoystickGetAxis(stick, i);
- float f = ( (float) axis ) / 32767.0f;
- if( f < -in_joystickThreshold->value ) {
- axes |= ( 1 << ( i * 2 ) );
- } else if( f > in_joystickThreshold->value ) {
- axes |= ( 1 << ( ( i * 2 ) + 1 ) );
- }
- }
- }
-
- /* Time to update axes state based on old vs. new. */
- if (axes != stick_state.oldaxes)
- {
- for( i = 0; i < 16; i++ ) {
- if( ( axes & ( 1 << i ) ) && !( stick_state.oldaxes & ( 1 << i ) ) ) {
- Com_QueueEvent( 0, SE_KEY, joy_keys[i], qtrue, 0, NULL );
- }
-
- if( !( axes & ( 1 << i ) ) && ( stick_state.oldaxes & ( 1 << i ) ) ) {
- Com_QueueEvent( 0, SE_KEY, joy_keys[i], qfalse, 0, NULL );
- }
- }
- }
-
- /* Save for future generations. */
- stick_state.oldaxes = axes;
-}
-
-/*
-===============
-IN_ProcessEvents
-===============
-*/
-static void IN_ProcessEvents( void )
-{
- SDL_Event e;
- const char *character = NULL;
- keyNum_t key = 0;
-
- if( !SDL_WasInit( SDL_INIT_VIDEO ) )
- return;
-
- if( Key_GetCatcher( ) == 0 && keyRepeatEnabled )
- {
- SDL_EnableKeyRepeat( 0, 0 );
- keyRepeatEnabled = qfalse;
- }
- else if( !keyRepeatEnabled )
- {
- SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY,
- SDL_DEFAULT_REPEAT_INTERVAL );
- keyRepeatEnabled = qtrue;
- }
-
- while( SDL_PollEvent( &e ) )
- {
- switch( e.type )
- {
- case SDL_KEYDOWN:
- character = IN_TranslateSDLToQ3Key( &e.key.keysym, &key, qtrue );
- if( key )
- Com_QueueEvent( 0, SE_KEY, key, qtrue, 0, NULL );
-
- if( character )
- Com_QueueEvent( 0, SE_CHAR, *character, 0, 0, NULL );
- break;
-
- case SDL_KEYUP:
- IN_TranslateSDLToQ3Key( &e.key.keysym, &key, qfalse );
-
- if( key )
- Com_QueueEvent( 0, SE_KEY, key, qfalse, 0, NULL );
- break;
-
- case SDL_MOUSEMOTION:
- if( mouseActive )
- Com_QueueEvent( 0, SE_MOUSE, e.motion.xrel, e.motion.yrel, 0, NULL );
- break;
-
- case SDL_MOUSEBUTTONDOWN:
- case SDL_MOUSEBUTTONUP:
- {
- unsigned char b;
- switch( e.button.button )
- {
- case 1: b = K_MOUSE1; break;
- case 2: b = K_MOUSE3; break;
- case 3: b = K_MOUSE2; break;
- case 4: b = K_MWHEELUP; break;
- case 5: b = K_MWHEELDOWN; break;
- case 6: b = K_MOUSE4; break;
- case 7: b = K_MOUSE5; break;
- default: b = K_AUX1 + ( e.button.button - 8 ) % 16; break;
- }
- Com_QueueEvent( 0, SE_KEY, b,
- ( e.type == SDL_MOUSEBUTTONDOWN ? qtrue : qfalse ), 0, NULL );
- }
- break;
-
- case SDL_QUIT:
- Sys_Quit( );
- break;
-
- case SDL_VIDEORESIZE:
- {
- char width[32], height[32];
- Com_sprintf( width, sizeof(width), "%d", e.resize.w );
- Com_sprintf( height, sizeof(height), "%d", e.resize.h );
- ri.Cvar_Set( "r_customwidth", width );
- ri.Cvar_Set( "r_customheight", height );
- ri.Cvar_Set( "r_mode", "-1" );
- /* wait until user stops dragging for 1 second, so
- we aren't constantly recreating the GL context while
- he tries to drag...*/
- vidRestartTime = Sys_Milliseconds() + 1000;
- }
- break;
-
- default:
- break;
- }
- }
-}
-
-/*
-===============
-IN_Frame
-===============
-*/
-void IN_Frame( void )
-{
- qboolean loading;
-
- IN_JoyMove( );
- IN_ProcessEvents( );
-
- // If not DISCONNECTED (main menu) or ACTIVE (in game), we're loading
- loading = !!( cls.state != CA_DISCONNECTED && cls.state != CA_ACTIVE );
-
- if( !r_fullscreen->integer && ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) )
- {
- // Console is down in windowed mode
- IN_DeactivateMouse( );
- }
- else if( !r_fullscreen->integer && loading )
- {
- // Loading in windowed mode
- IN_DeactivateMouse( );
- }
- else if( !( SDL_GetAppState() & SDL_APPINPUTFOCUS ) )
- {
- // Window not got focus
- IN_DeactivateMouse( );
- }
- else
- IN_ActivateMouse( );
-
- /* in case we had to delay actual restart of video system... */
- if ( (vidRestartTime != 0) && (vidRestartTime < Sys_Milliseconds()) )
- {
- vidRestartTime = 0;
- Cbuf_AddText( "vid_restart" );
- }
-}
-
-/*
-===============
-IN_Init
-===============
-*/
-void IN_Init( void )
-{
- if( !SDL_WasInit( SDL_INIT_VIDEO ) )
- {
- Com_Error( ERR_FATAL, "IN_Init called before SDL_Init( SDL_INIT_VIDEO )\n" );
- return;
- }
-
- Com_DPrintf( "\n------- Input Initialization -------\n" );
-
- in_keyboardDebug = Cvar_Get( "in_keyboardDebug", "0", CVAR_ARCHIVE );
-
- // mouse variables
- in_mouse = Cvar_Get( "in_mouse", "1", CVAR_ARCHIVE );
- in_nograb = Cvar_Get( "in_nograb", "0", CVAR_ARCHIVE );
-
- in_joystick = Cvar_Get( "in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH );
- in_joystickDebug = Cvar_Get( "in_joystickDebug", "0", CVAR_TEMP );
- in_joystickThreshold = Cvar_Get( "in_joystickThreshold", "0.15", CVAR_ARCHIVE );
-
-#ifdef MACOS_X_ACCELERATION_HACK
- in_disablemacosxmouseaccel = Cvar_Get( "in_disablemacosxmouseaccel", "1", CVAR_ARCHIVE );
-#endif
-
- SDL_EnableUNICODE( 1 );
- SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL );
- keyRepeatEnabled = qtrue;
-
- if( in_mouse->value )
- {
- mouseAvailable = qtrue;
- IN_ActivateMouse( );
- }
- else
- {
- IN_DeactivateMouse( );
- mouseAvailable = qfalse;
- }
-
- IN_InitJoystick( );
- Com_DPrintf( "------------------------------------\n" );
-}
-
-/*
-===============
-IN_Shutdown
-===============
-*/
-void IN_Shutdown( void )
-{
- IN_DeactivateMouse( );
- mouseAvailable = qfalse;
-
- IN_ShutdownJoystick( );
-}
-
-/*
-===============
-IN_Restart
-===============
-*/
-void IN_Restart( void )
-{
- IN_ShutdownJoystick( );
- IN_Init( );
-}
diff --git a/engine/code/sdl/sdl_snd.c b/engine/code/sdl/sdl_snd.c
deleted file mode 100644
index a131db7..0000000
--- a/engine/code/sdl/sdl_snd.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#ifdef USE_LOCAL_HEADERS
-# include "SDL.h"
-#else
-# include <SDL.h>
-#endif
-
-#include "../qcommon/q_shared.h"
-#include "../client/snd_local.h"
-
-qboolean snd_inited = qfalse;
-
-cvar_t *s_sdlBits;
-cvar_t *s_sdlSpeed;
-cvar_t *s_sdlChannels;
-cvar_t *s_sdlDevSamps;
-cvar_t *s_sdlMixSamps;
-
-/* The audio callback. All the magic happens here. */
-static int dmapos = 0;
-static int dmasize = 0;
-
-/*
-===============
-SNDDMA_AudioCallback
-===============
-*/
-static void SNDDMA_AudioCallback(void *userdata, Uint8 *stream, int len)
-{
- int pos = (dmapos * (dma.samplebits/8));
- if (pos >= dmasize)
- dmapos = pos = 0;
-
- if (!snd_inited) /* shouldn't happen, but just in case... */
- {
- memset(stream, '\0', len);
- return;
- }
- else
- {
- int tobufend = dmasize - pos; /* bytes to buffer's end. */
- int len1 = len;
- int len2 = 0;
-
- if (len1 > tobufend)
- {
- len1 = tobufend;
- len2 = len - len1;
- }
- memcpy(stream, dma.buffer + pos, len1);
- if (len2 <= 0)
- dmapos += (len1 / (dma.samplebits/8));
- else /* wraparound? */
- {
- memcpy(stream+len1, dma.buffer, len2);
- dmapos = (len2 / (dma.samplebits/8));
- }
- }
-
- if (dmapos >= dmasize)
- dmapos = 0;
-}
-
-static struct
-{
- Uint16 enumFormat;
- char *stringFormat;
-} formatToStringTable[ ] =
-{
- { AUDIO_U8, "AUDIO_U8" },
- { AUDIO_S8, "AUDIO_S8" },
- { AUDIO_U16LSB, "AUDIO_U16LSB" },
- { AUDIO_S16LSB, "AUDIO_S16LSB" },
- { AUDIO_U16MSB, "AUDIO_U16MSB" },
- { AUDIO_S16MSB, "AUDIO_S16MSB" }
-};
-
-static int formatToStringTableSize =
- sizeof( formatToStringTable ) / sizeof( formatToStringTable[ 0 ] );
-
-/*
-===============
-SNDDMA_PrintAudiospec
-===============
-*/
-static void SNDDMA_PrintAudiospec(const char *str, const SDL_AudioSpec *spec)
-{
- int i;
- char *fmt = NULL;
-
- Com_Printf("%s:\n", str);
-
- for( i = 0; i < formatToStringTableSize; i++ ) {
- if( spec->format == formatToStringTable[ i ].enumFormat ) {
- fmt = formatToStringTable[ i ].stringFormat;
- }
- }
-
- if( fmt ) {
- Com_Printf( " Format: %s\n", fmt );
- } else {
- Com_Printf( " Format: " S_COLOR_RED "UNKNOWN\n");
- }
-
- Com_Printf( " Freq: %d\n", (int) spec->freq );
- Com_Printf( " Samples: %d\n", (int) spec->samples );
- Com_Printf( " Channels: %d\n", (int) spec->channels );
-}
-
-/*
-===============
-SNDDMA_Init
-===============
-*/
-qboolean SNDDMA_Init(void)
-{
- char drivername[128];
- SDL_AudioSpec desired;
- SDL_AudioSpec obtained;
- int tmp;
-
- if (snd_inited)
- return qtrue;
-
- if (!s_sdlBits) {
- s_sdlBits = Cvar_Get("s_sdlBits", "16", CVAR_ARCHIVE);
- s_sdlSpeed = Cvar_Get("s_sdlSpeed", "0", CVAR_ARCHIVE);
- s_sdlChannels = Cvar_Get("s_sdlChannels", "2", CVAR_ARCHIVE);
- s_sdlDevSamps = Cvar_Get("s_sdlDevSamps", "0", CVAR_ARCHIVE);
- s_sdlMixSamps = Cvar_Get("s_sdlMixSamps", "0", CVAR_ARCHIVE);
- }
-
- Com_Printf( "SDL_Init( SDL_INIT_AUDIO )... " );
-
- if (!SDL_WasInit(SDL_INIT_AUDIO))
- {
- if (SDL_Init(SDL_INIT_AUDIO) == -1)
- {
- Com_Printf( "FAILED (%s)\n", SDL_GetError( ) );
- return qfalse;
- }
- }
-
- Com_Printf( "OK\n" );
-
- if (SDL_AudioDriverName(drivername, sizeof (drivername)) == NULL)
- strcpy(drivername, "(UNKNOWN)");
- Com_Printf("SDL audio driver is \"%s\".\n", drivername);
-
- memset(&desired, '\0', sizeof (desired));
- memset(&obtained, '\0', sizeof (obtained));
-
- tmp = ((int) s_sdlBits->value);
- if ((tmp != 16) && (tmp != 8))
- tmp = 16;
-
- desired.freq = (int) s_sdlSpeed->value;
- if(!desired.freq) desired.freq = 22050;
- desired.format = ((tmp == 16) ? AUDIO_S16SYS : AUDIO_U8);
-
- // I dunno if this is the best idea, but I'll give it a try...
- // should probably check a cvar for this...
- if (s_sdlDevSamps->value)
- desired.samples = s_sdlDevSamps->value;
- else
- {
- // just pick a sane default.
- if (desired.freq <= 11025)
- desired.samples = 256;
- else if (desired.freq <= 22050)
- desired.samples = 512;
- else if (desired.freq <= 44100)
- desired.samples = 1024;
- else
- desired.samples = 2048; // (*shrug*)
- }
-
- desired.channels = (int) s_sdlChannels->value;
- desired.callback = SNDDMA_AudioCallback;
-
- if (SDL_OpenAudio(&desired, &obtained) == -1)
- {
- Com_Printf("SDL_OpenAudio() failed: %s\n", SDL_GetError());
- SDL_QuitSubSystem(SDL_INIT_AUDIO);
- return qfalse;
- }
-
- SNDDMA_PrintAudiospec("SDL_AudioSpec", &obtained);
-
- // dma.samples needs to be big, or id's mixer will just refuse to
- // work at all; we need to keep it significantly bigger than the
- // amount of SDL callback samples, and just copy a little each time
- // the callback runs.
- // 32768 is what the OSS driver filled in here on my system. I don't
- // know if it's a good value overall, but at least we know it's
- // reasonable...this is why I let the user override.
- tmp = s_sdlMixSamps->value;
- if (!tmp)
- tmp = (obtained.samples * obtained.channels) * 10;
-
- if (tmp & (tmp - 1)) // not a power of two? Seems to confuse something.
- {
- int val = 1;
- while (val < tmp)
- val <<= 1;
-
- tmp = val;
- }
-
- dmapos = 0;
- dma.samplebits = obtained.format & 0xFF; // first byte of format is bits.
- dma.channels = obtained.channels;
- dma.samples = tmp;
- dma.submission_chunk = 1;
- dma.speed = obtained.freq;
- dmasize = (dma.samples * (dma.samplebits/8));
- dma.buffer = calloc(1, dmasize);
-
- Com_Printf("Starting SDL audio callback...\n");
- SDL_PauseAudio(0); // start callback.
-
- Com_Printf("SDL audio initialized.\n");
- snd_inited = qtrue;
- return qtrue;
-}
-
-/*
-===============
-SNDDMA_GetDMAPos
-===============
-*/
-int SNDDMA_GetDMAPos(void)
-{
- return dmapos;
-}
-
-/*
-===============
-SNDDMA_Shutdown
-===============
-*/
-void SNDDMA_Shutdown(void)
-{
- Com_Printf("Closing SDL audio device...\n");
- SDL_PauseAudio(1);
- SDL_CloseAudio();
- SDL_QuitSubSystem(SDL_INIT_AUDIO);
- free(dma.buffer);
- dma.buffer = NULL;
- dmapos = dmasize = 0;
- snd_inited = qfalse;
- Com_Printf("SDL audio device shut down.\n");
-}
-
-/*
-===============
-SNDDMA_Submit
-
-Send sound to device if buffer isn't really the dma buffer
-===============
-*/
-void SNDDMA_Submit(void)
-{
- SDL_UnlockAudio();
-}
-
-/*
-===============
-SNDDMA_BeginPainting
-===============
-*/
-void SNDDMA_BeginPainting (void)
-{
- SDL_LockAudio();
-}
diff --git a/engine/code/server/server.h b/engine/code/server/server.h
deleted file mode 100644
index bf85594..0000000
--- a/engine/code/server/server.h
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// server.h
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-#include "../game/g_public.h"
-#include "../game/bg_public.h"
-
-//=============================================================================
-
-#define PERS_SCORE 0 // !!! MUST NOT CHANGE, SERVER AND
- // GAME BOTH REFERENCE !!!
-
-#define MAX_ENT_CLUSTERS 16
-
-#ifdef USE_VOIP
-typedef struct voipServerPacket_s
-{
- int generation;
- int sequence;
- int frames;
- int len;
- int sender;
- byte data[1024];
-} voipServerPacket_t;
-#endif
-
-typedef struct svEntity_s {
- struct worldSector_s *worldSector;
- struct svEntity_s *nextEntityInWorldSector;
-
- entityState_t baseline; // for delta compression of initial sighting
- int numClusters; // if -1, use headnode instead
- int clusternums[MAX_ENT_CLUSTERS];
- int lastCluster; // if all the clusters don't fit in clusternums
- int areanum, areanum2;
- int snapshotCounter; // used to prevent double adding from portal views
-} svEntity_t;
-
-typedef enum {
- SS_DEAD, // no map loaded
- SS_LOADING, // spawning level entities
- SS_GAME // actively running
-} serverState_t;
-
-typedef struct {
- serverState_t state;
- qboolean restarting; // if true, send configstring changes during SS_LOADING
- int serverId; // changes each server start
- int restartedServerId; // serverId before a map_restart
- int checksumFeed; // the feed key that we use to compute the pure checksum strings
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
- // the serverId associated with the current checksumFeed (always <= serverId)
- int checksumFeedServerId;
- int snapshotCounter; // incremented for each snapshot built
- int timeResidual; // <= 1000 / sv_frame->value
- int nextFrameTime; // when time > nextFrameTime, process world
- struct cmodel_s *models[MAX_MODELS];
- char *configstrings[MAX_CONFIGSTRINGS];
- svEntity_t svEntities[MAX_GENTITIES];
-
- char *entityParsePoint; // used during game VM init
-
- // the game virtual machine will update these on init and changes
- sharedEntity_t *gentities;
- int gentitySize;
- int num_entities; // current number, <= MAX_GENTITIES
-
- playerState_t *gameClients;
- int gameClientSize; // will be > sizeof(playerState_t) due to game private data
-
- int restartTime;
- int time;
-} server_t;
-
-
-
-
-
-typedef struct {
- int areabytes;
- byte areabits[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
- playerState_t ps;
- int num_entities;
- int first_entity; // into the circular sv_packet_entities[]
- // the entities MUST be in increasing state number
- // order, otherwise the delta compression will fail
- int messageSent; // time the message was transmitted
- int messageAcked; // time the message was acked
- int messageSize; // used to rate drop packets
-} clientSnapshot_t;
-
-typedef enum {
- CS_FREE, // can be reused for a new connection
- CS_ZOMBIE, // client has been disconnected, but don't reuse
- // connection for a couple seconds
- CS_CONNECTED, // has been assigned to a client_t, but no gamestate yet
- CS_PRIMED, // gamestate has been sent, but client hasn't sent a usercmd
- CS_ACTIVE // client is fully in game
-} clientState_t;
-
-typedef struct netchan_buffer_s {
- msg_t msg;
- byte msgBuffer[MAX_MSGLEN];
- struct netchan_buffer_s *next;
-} netchan_buffer_t;
-
-typedef struct client_s {
- clientState_t state;
- char userinfo[MAX_INFO_STRING]; // name, etc
-
- char reliableCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS];
- int reliableSequence; // last added reliable message, not necesarily sent or acknowledged yet
- int reliableAcknowledge; // last acknowledged reliable message
- int reliableSent; // last sent reliable message, not necesarily acknowledged yet
- int messageAcknowledge;
-
- int gamestateMessageNum; // netchan->outgoingSequence of gamestate
- int challenge;
-
- usercmd_t lastUsercmd;
- int lastMessageNum; // for delta compression
- int lastClientCommand; // reliable client message sequence
- char lastClientCommandString[MAX_STRING_CHARS];
- sharedEntity_t *gentity; // SV_GentityNum(clientnum)
- char name[MAX_NAME_LENGTH]; // extracted from userinfo, high bits masked
-
- // downloading
- char downloadName[MAX_QPATH]; // if not empty string, we are downloading
- fileHandle_t download; // file being downloaded
- int downloadSize; // total bytes (can't use EOF because of paks)
- int downloadCount; // bytes sent
- int downloadClientBlock; // last block we sent to the client, awaiting ack
- int downloadCurrentBlock; // current block number
- int downloadXmitBlock; // last block we xmited
- unsigned char *downloadBlocks[MAX_DOWNLOAD_WINDOW]; // the buffers for the download blocks
- int downloadBlockSize[MAX_DOWNLOAD_WINDOW];
- qboolean downloadEOF; // We have sent the EOF block
- int downloadSendTime; // time we last got an ack from the client
-
- int deltaMessage; // frame last client usercmd message
- int nextReliableTime; // svs.time when another reliable command will be allowed
- int lastPacketTime; // svs.time when packet was last received
- int lastConnectTime; // svs.time when connection started
- int nextSnapshotTime; // send another snapshot when svs.time >= nextSnapshotTime
- qboolean rateDelayed; // true if nextSnapshotTime was set based on rate instead of snapshotMsec
- int timeoutCount; // must timeout a few frames in a row so debugging doesn't break
- clientSnapshot_t frames[PACKET_BACKUP]; // updates can be delta'd from here
- int ping;
- int rate; // bytes / second
- int snapshotMsec; // requests a snapshot every snapshotMsec unless rate choked
- int pureAuthentic;
- qboolean gotCP; // TTimo - additional flag to distinguish between a bad pure checksum, and no cp command at all
- netchan_t netchan;
- // TTimo
- // queuing outgoing fragmented messages to send them properly, without udp packet bursts
- // in case large fragmented messages are stacking up
- // buffer them into this queue, and hand them out to netchan as needed
- netchan_buffer_t *netchan_start_queue;
- netchan_buffer_t **netchan_end_queue;
-
-#ifdef USE_VOIP
- qboolean hasVoip;
- qboolean muteAllVoip;
- qboolean ignoreVoipFromClient[MAX_CLIENTS];
- voipServerPacket_t voipPacket[64]; // !!! FIXME: WAY too much memory!
- int queuedVoipPackets;
-#endif
-
- int oldServerTime;
- qboolean csUpdated[MAX_CONFIGSTRINGS+1];
-} client_t;
-
-//=============================================================================
-
-
-// MAX_CHALLENGES is made large to prevent a denial
-// of service attack that could cycle all of them
-// out before legitimate users connected
-#define MAX_CHALLENGES 1024
-
-#define AUTHORIZE_TIMEOUT 5000
-
-typedef struct {
- netadr_t adr;
- int challenge;
- int clientChallenge; // challenge number coming from the client
- int time; // time the last packet was sent to the autherize server
- int pingTime; // time the challenge response was sent to client
- int firstTime; // time the adr was first used, for authorize timeout checks
- qboolean wasrefused;
- qboolean connected;
-} challenge_t;
-
-
-#define MAX_MASTERS 8 // max recipients for heartbeat packets
-
-
-// this structure will be cleared only when the game dll changes
-typedef struct {
- qboolean initialized; // sv_init has completed
-
- int time; // will be strictly increasing across level changes
-
- int snapFlagServerBit; // ^= SNAPFLAG_SERVERCOUNT every SV_SpawnServer()
-
- client_t *clients; // [sv_maxclients->integer];
- int numSnapshotEntities; // sv_maxclients->integer*PACKET_BACKUP*MAX_PACKET_ENTITIES
- int nextSnapshotEntities; // next snapshotEntities to use
- entityState_t *snapshotEntities; // [numSnapshotEntities]
- int nextHeartbeatTime;
- challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting
- netadr_t redirectAddress; // for rcon return messages
-
- netadr_t authorizeAddress; // for rcon return messages
-} serverStatic_t;
-
-#define SERVER_MAXBANS 1024
-// Structure for managing bans
-typedef struct
-{
- netadr_t ip;
- // For a CIDR-Notation type suffix
- int subnet;
-
- qboolean isexception;
-} serverBan_t;
-
-//=============================================================================
-
-extern serverStatic_t svs; // persistant server info across maps
-extern server_t sv; // cleared each map
-extern vm_t *gvm; // game virtual machine
-
-#define MAX_MASTER_SERVERS 5
-
-extern cvar_t *sv_fps;
-extern cvar_t *sv_timeout;
-extern cvar_t *sv_zombietime;
-extern cvar_t *sv_rconPassword;
-extern cvar_t *sv_privatePassword;
-extern cvar_t *sv_allowDownload;
-extern cvar_t *sv_maxclients;
-
-extern cvar_t *sv_privateClients;
-extern cvar_t *sv_hostname;
-extern cvar_t *sv_master[MAX_MASTER_SERVERS];
-extern cvar_t *sv_reconnectlimit;
-extern cvar_t *sv_showloss;
-extern cvar_t *sv_padPackets;
-extern cvar_t *sv_killserver;
-extern cvar_t *sv_mapname;
-extern cvar_t *sv_mapChecksum;
-extern cvar_t *sv_serverid;
-extern cvar_t *sv_minRate;
-extern cvar_t *sv_maxRate;
-extern cvar_t *sv_minPing;
-extern cvar_t *sv_maxPing;
-extern cvar_t *sv_gametype;
-extern cvar_t *sv_pure;
-extern cvar_t *sv_floodProtect;
-extern cvar_t *sv_lanForceRate;
-extern cvar_t *sv_strictAuth;
-extern cvar_t *sv_banFile;
-
-extern serverBan_t serverBans[SERVER_MAXBANS];
-extern int serverBansCount;
-
-#ifdef USE_VOIP
-extern cvar_t *sv_voip;
-#endif
-
-
-//===========================================================
-
-//
-// sv_main.c
-//
-void SV_FinalMessage (char *message);
-void QDECL SV_SendServerCommand( client_t *cl, const char *fmt, ...);
-
-
-void SV_AddOperatorCommands (void);
-void SV_RemoveOperatorCommands (void);
-
-
-void SV_MasterHeartbeat (void);
-void SV_MasterShutdown (void);
-
-
-
-
-//
-// sv_init.c
-//
-void SV_SetConfigstring( int index, const char *val );
-void SV_GetConfigstring( int index, char *buffer, int bufferSize );
-void SV_UpdateConfigstrings( client_t *client );
-
-void SV_SetUserinfo( int index, const char *val );
-void SV_GetUserinfo( int index, char *buffer, int bufferSize );
-
-void SV_ChangeMaxClients( void );
-void SV_SpawnServer( char *server, qboolean killBots );
-
-
-
-//
-// sv_client.c
-//
-void SV_GetChallenge(netadr_t from);
-
-void SV_DirectConnect( netadr_t from );
-
-#ifndef STANDALONE
-void SV_AuthorizeIpPacket( netadr_t from );
-#endif
-
-void SV_ExecuteClientMessage( client_t *cl, msg_t *msg );
-void SV_UserinfoChanged( client_t *cl );
-
-void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd );
-void SV_DropClient( client_t *drop, const char *reason );
-
-void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK );
-void SV_ClientThink (client_t *cl, usercmd_t *cmd);
-
-void SV_WriteDownloadToClient( client_t *cl , msg_t *msg );
-
-#ifdef USE_VOIP
-void SV_WriteVoipToClient( client_t *cl, msg_t *msg );
-#endif
-
-
-//
-// sv_ccmds.c
-//
-void SV_Heartbeat_f( void );
-
-//
-// sv_snapshot.c
-//
-void SV_AddServerCommand( client_t *client, const char *cmd );
-void SV_UpdateServerCommandsToClient( client_t *client, msg_t *msg );
-void SV_WriteFrameToClient (client_t *client, msg_t *msg);
-void SV_SendMessageToClient( msg_t *msg, client_t *client );
-void SV_SendClientMessages( void );
-void SV_SendClientSnapshot( client_t *client );
-
-//
-// sv_game.c
-//
-int SV_NumForGentity( sharedEntity_t *ent );
-sharedEntity_t *SV_GentityNum( int num );
-playerState_t *SV_GameClientNum( int num );
-svEntity_t *SV_SvEntityForGentity( sharedEntity_t *gEnt );
-sharedEntity_t *SV_GEntityForSvEntity( svEntity_t *svEnt );
-void SV_InitGameProgs ( void );
-void SV_ShutdownGameProgs ( void );
-void SV_RestartGameProgs( void );
-qboolean SV_inPVS (const vec3_t p1, const vec3_t p2);
-
-//
-// sv_bot.c
-//
-void SV_BotFrame( int time );
-int SV_BotAllocateClient(void);
-void SV_BotFreeClient( int clientNum );
-
-void SV_BotInitCvars(void);
-int SV_BotLibSetup( void );
-int SV_BotLibShutdown( void );
-int SV_BotGetSnapshotEntity( int client, int ent );
-int SV_BotGetConsoleMessage( int client, char *buf, int size );
-
-int BotImport_DebugPolygonCreate(int color, int numPoints, vec3_t *points);
-void BotImport_DebugPolygonDelete(int id);
-
-void SV_BotInitBotLib(void);
-
-//============================================================
-//
-// high level object sorting to reduce interaction tests
-//
-
-void SV_ClearWorld (void);
-// called after the world model has been loaded, before linking any entities
-
-void SV_UnlinkEntity( sharedEntity_t *ent );
-// call before removing an entity, and before trying to move one,
-// so it doesn't clip against itself
-
-void SV_LinkEntity( sharedEntity_t *ent );
-// Needs to be called any time an entity changes origin, mins, maxs,
-// or solid. Automatically unlinks if needed.
-// sets ent->v.absmin and ent->v.absmax
-// sets ent->leafnums[] for pvs determination even if the entity
-// is not solid
-
-
-clipHandle_t SV_ClipHandleForEntity( const sharedEntity_t *ent );
-
-
-void SV_SectorList_f( void );
-
-
-int SV_AreaEntities( const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount );
-// fills in a table of entity numbers with entities that have bounding boxes
-// that intersect the given area. It is possible for a non-axial bmodel
-// to be returned that doesn't actually intersect the area on an exact
-// test.
-// returns the number of pointers filled in
-// The world entity is never returned in this list.
-
-
-int SV_PointContents( const vec3_t p, int passEntityNum );
-// returns the CONTENTS_* value from the world and all entities at the given point.
-
-
-void SV_Trace( trace_t *results, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask, int capsule );
-// mins and maxs are relative
-
-// if the entire move stays in a solid volume, trace.allsolid will be set,
-// trace.startsolid will be set, and trace.fraction will be 0
-
-// if the starting point is in a solid, it will be allowed to move out
-// to an open area
-
-// passEntityNum is explicitly excluded from clipping checks (normally ENTITYNUM_NONE)
-
-
-void SV_ClipToEntity( trace_t *trace, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int entityNum, int contentmask, int capsule );
-// clip to a specific entity
-
-//
-// sv_net_chan.c
-//
-void SV_Netchan_Transmit( client_t *client, msg_t *msg);
-void SV_Netchan_TransmitNextFragment( client_t *client );
-qboolean SV_Netchan_Process( client_t *client, msg_t *msg );
-
diff --git a/engine/code/server/sv_bot.c b/engine/code/server/sv_bot.c
deleted file mode 100644
index 8583f86..0000000
--- a/engine/code/server/sv_bot.c
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// sv_bot.c
-
-#include "server.h"
-#include "../botlib/botlib.h"
-
-typedef struct bot_debugpoly_s
-{
- int inuse;
- int color;
- int numPoints;
- vec3_t points[128];
-} bot_debugpoly_t;
-
-static bot_debugpoly_t *debugpolygons;
-int bot_maxdebugpolys;
-
-extern botlib_export_t *botlib_export;
-int bot_enable;
-
-
-/*
-==================
-SV_BotAllocateClient
-==================
-*/
-int SV_BotAllocateClient(void) {
- int i;
- client_t *cl;
-
- // find a client slot
- for ( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) {
- if ( cl->state == CS_FREE ) {
- break;
- }
- }
-
- if ( i == sv_maxclients->integer ) {
- return -1;
- }
-
- cl->gentity = SV_GentityNum( i );
- cl->gentity->s.number = i;
- cl->state = CS_ACTIVE;
- cl->lastPacketTime = svs.time;
- cl->netchan.remoteAddress.type = NA_BOT;
- cl->rate = 16384;
-
- return i;
-}
-
-/*
-==================
-SV_BotFreeClient
-==================
-*/
-void SV_BotFreeClient( int clientNum ) {
- client_t *cl;
-
- if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {
- Com_Error( ERR_DROP, "SV_BotFreeClient: bad clientNum: %i", clientNum );
- }
- cl = &svs.clients[clientNum];
- cl->state = CS_FREE;
- cl->name[0] = 0;
- if ( cl->gentity ) {
- cl->gentity->r.svFlags &= ~SVF_BOT;
- }
-}
-
-/*
-==================
-BotDrawDebugPolygons
-==================
-*/
-void BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *points), int value) {
- static cvar_t *bot_debug, *bot_groundonly, *bot_reachability, *bot_highlightarea;
- bot_debugpoly_t *poly;
- int i, parm0;
-
- if (!debugpolygons)
- return;
- //bot debugging
- if (!bot_debug) bot_debug = Cvar_Get("bot_debug", "0", 0);
- //
- if (bot_enable && bot_debug->integer) {
- //show reachabilities
- if (!bot_reachability) bot_reachability = Cvar_Get("bot_reachability", "0", 0);
- //show ground faces only
- if (!bot_groundonly) bot_groundonly = Cvar_Get("bot_groundonly", "1", 0);
- //get the hightlight area
- if (!bot_highlightarea) bot_highlightarea = Cvar_Get("bot_highlightarea", "0", 0);
- //
- parm0 = 0;
- if (svs.clients[0].lastUsercmd.buttons & BUTTON_ATTACK) parm0 |= 1;
- if (bot_reachability->integer) parm0 |= 2;
- if (bot_groundonly->integer) parm0 |= 4;
- botlib_export->BotLibVarSet("bot_highlightarea", bot_highlightarea->string);
- botlib_export->Test(parm0, NULL, svs.clients[0].gentity->r.currentOrigin,
- svs.clients[0].gentity->r.currentAngles);
- } //end if
- //draw all debug polys
- for (i = 0; i < bot_maxdebugpolys; i++) {
- poly = &debugpolygons[i];
- if (!poly->inuse) continue;
- drawPoly(poly->color, poly->numPoints, (float *) poly->points);
- //Com_Printf("poly %i, numpoints = %d\n", i, poly->numPoints);
- }
-}
-
-/*
-==================
-BotImport_Print
-==================
-*/
-static void QDECL BotImport_Print(int type, char *fmt, ...)
-{
- char str[2048];
- va_list ap;
-
- va_start(ap, fmt);
- Q_vsnprintf(str, sizeof(str), fmt, ap);
- va_end(ap);
-
- switch(type) {
- case PRT_MESSAGE: {
- Com_Printf("%s", str);
- break;
- }
- case PRT_WARNING: {
- Com_Printf(S_COLOR_YELLOW "Warning: %s", str);
- break;
- }
- case PRT_ERROR: {
- Com_Printf(S_COLOR_RED "Error: %s", str);
- break;
- }
- case PRT_FATAL: {
- Com_Printf(S_COLOR_RED "Fatal: %s", str);
- break;
- }
- case PRT_EXIT: {
- Com_Error(ERR_DROP, S_COLOR_RED "Exit: %s", str);
- break;
- }
- default: {
- Com_Printf("unknown print type\n");
- break;
- }
- }
-}
-
-/*
-==================
-BotImport_Trace
-==================
-*/
-static void BotImport_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) {
- trace_t trace;
-
- SV_Trace(&trace, start, mins, maxs, end, passent, contentmask, qfalse);
- //copy the trace information
- bsptrace->allsolid = trace.allsolid;
- bsptrace->startsolid = trace.startsolid;
- bsptrace->fraction = trace.fraction;
- VectorCopy(trace.endpos, bsptrace->endpos);
- bsptrace->plane.dist = trace.plane.dist;
- VectorCopy(trace.plane.normal, bsptrace->plane.normal);
- bsptrace->plane.signbits = trace.plane.signbits;
- bsptrace->plane.type = trace.plane.type;
- bsptrace->surface.value = trace.surfaceFlags;
- bsptrace->ent = trace.entityNum;
- bsptrace->exp_dist = 0;
- bsptrace->sidenum = 0;
- bsptrace->contents = 0;
-}
-
-/*
-==================
-BotImport_EntityTrace
-==================
-*/
-static void BotImport_EntityTrace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask) {
- trace_t trace;
-
- SV_ClipToEntity(&trace, start, mins, maxs, end, entnum, contentmask, qfalse);
- //copy the trace information
- bsptrace->allsolid = trace.allsolid;
- bsptrace->startsolid = trace.startsolid;
- bsptrace->fraction = trace.fraction;
- VectorCopy(trace.endpos, bsptrace->endpos);
- bsptrace->plane.dist = trace.plane.dist;
- VectorCopy(trace.plane.normal, bsptrace->plane.normal);
- bsptrace->plane.signbits = trace.plane.signbits;
- bsptrace->plane.type = trace.plane.type;
- bsptrace->surface.value = trace.surfaceFlags;
- bsptrace->ent = trace.entityNum;
- bsptrace->exp_dist = 0;
- bsptrace->sidenum = 0;
- bsptrace->contents = 0;
-}
-
-
-/*
-==================
-BotImport_PointContents
-==================
-*/
-static int BotImport_PointContents(vec3_t point) {
- return SV_PointContents(point, -1);
-}
-
-/*
-==================
-BotImport_inPVS
-==================
-*/
-static int BotImport_inPVS(vec3_t p1, vec3_t p2) {
- return SV_inPVS (p1, p2);
-}
-
-/*
-==================
-BotImport_BSPEntityData
-==================
-*/
-static char *BotImport_BSPEntityData(void) {
- return CM_EntityString();
-}
-
-/*
-==================
-BotImport_BSPModelMinsMaxsOrigin
-==================
-*/
-static void BotImport_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t outmins, vec3_t outmaxs, vec3_t origin) {
- clipHandle_t h;
- vec3_t mins, maxs;
- float max;
- int i;
-
- h = CM_InlineModel(modelnum);
- CM_ModelBounds(h, mins, maxs);
- //if the model is rotated
- if ((angles[0] || angles[1] || angles[2])) {
- // expand for rotation
-
- max = RadiusFromBounds(mins, maxs);
- for (i = 0; i < 3; i++) {
- mins[i] = -max;
- maxs[i] = max;
- }
- }
- if (outmins) VectorCopy(mins, outmins);
- if (outmaxs) VectorCopy(maxs, outmaxs);
- if (origin) VectorClear(origin);
-}
-
-/*
-==================
-BotImport_GetMemory
-==================
-*/
-static void *BotImport_GetMemory(int size) {
- void *ptr;
-
- ptr = Z_TagMalloc( size, TAG_BOTLIB );
- return ptr;
-}
-
-/*
-==================
-BotImport_FreeMemory
-==================
-*/
-static void BotImport_FreeMemory(void *ptr) {
- Z_Free(ptr);
-}
-
-/*
-=================
-BotImport_HunkAlloc
-=================
-*/
-static void *BotImport_HunkAlloc( int size ) {
- if( Hunk_CheckMark() ) {
- Com_Error( ERR_DROP, "SV_Bot_HunkAlloc: Alloc with marks already set\n" );
- }
- return Hunk_Alloc( size, h_high );
-}
-
-/*
-==================
-BotImport_DebugPolygonCreate
-==================
-*/
-int BotImport_DebugPolygonCreate(int color, int numPoints, vec3_t *points) {
- bot_debugpoly_t *poly;
- int i;
-
- if (!debugpolygons)
- return 0;
-
- for (i = 1; i < bot_maxdebugpolys; i++) {
- if (!debugpolygons[i].inuse)
- break;
- }
- if (i >= bot_maxdebugpolys)
- return 0;
- poly = &debugpolygons[i];
- poly->inuse = qtrue;
- poly->color = color;
- poly->numPoints = numPoints;
- Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t));
- //
- return i;
-}
-
-/*
-==================
-BotImport_DebugPolygonShow
-==================
-*/
-static void BotImport_DebugPolygonShow(int id, int color, int numPoints, vec3_t *points) {
- bot_debugpoly_t *poly;
-
- if (!debugpolygons) return;
- poly = &debugpolygons[id];
- poly->inuse = qtrue;
- poly->color = color;
- poly->numPoints = numPoints;
- Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t));
-}
-
-/*
-==================
-BotImport_DebugPolygonDelete
-==================
-*/
-void BotImport_DebugPolygonDelete(int id)
-{
- if (!debugpolygons) return;
- debugpolygons[id].inuse = qfalse;
-}
-
-/*
-==================
-BotImport_DebugLineCreate
-==================
-*/
-static int BotImport_DebugLineCreate(void) {
- vec3_t points[1];
- return BotImport_DebugPolygonCreate(0, 0, points);
-}
-
-/*
-==================
-BotImport_DebugLineDelete
-==================
-*/
-static void BotImport_DebugLineDelete(int line) {
- BotImport_DebugPolygonDelete(line);
-}
-
-/*
-==================
-BotImport_DebugLineShow
-==================
-*/
-static void BotImport_DebugLineShow(int line, vec3_t start, vec3_t end, int color) {
- vec3_t points[4], dir, cross, up = {0, 0, 1};
- float dot;
-
- VectorCopy(start, points[0]);
- VectorCopy(start, points[1]);
- //points[1][2] -= 2;
- VectorCopy(end, points[2]);
- //points[2][2] -= 2;
- VectorCopy(end, points[3]);
-
-
- VectorSubtract(end, start, dir);
- VectorNormalize(dir);
- dot = DotProduct(dir, up);
- if (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0);
- else CrossProduct(dir, up, cross);
-
- VectorNormalize(cross);
-
- VectorMA(points[0], 2, cross, points[0]);
- VectorMA(points[1], -2, cross, points[1]);
- VectorMA(points[2], -2, cross, points[2]);
- VectorMA(points[3], 2, cross, points[3]);
-
- BotImport_DebugPolygonShow(line, color, 4, points);
-}
-
-/*
-==================
-SV_BotClientCommand
-==================
-*/
-static void BotClientCommand( int client, char *command ) {
- SV_ExecuteClientCommand( &svs.clients[client], command, qtrue );
-}
-
-/*
-==================
-SV_BotFrame
-==================
-*/
-void SV_BotFrame( int time ) {
- if (!bot_enable) return;
- //NOTE: maybe the game is already shutdown
- if (!gvm) return;
- VM_Call( gvm, BOTAI_START_FRAME, time );
-}
-
-/*
-===============
-SV_BotLibSetup
-===============
-*/
-int SV_BotLibSetup( void ) {
- if (!bot_enable) {
- return 0;
- }
-
- if ( !botlib_export ) {
- Com_Printf( S_COLOR_RED "Error: SV_BotLibSetup without SV_BotInitBotLib\n" );
- return -1;
- }
-
- return botlib_export->BotLibSetup();
-}
-
-/*
-===============
-SV_ShutdownBotLib
-
-Called when either the entire server is being killed, or
-it is changing to a different game directory.
-===============
-*/
-int SV_BotLibShutdown( void ) {
-
- if ( !botlib_export ) {
- return -1;
- }
-
- return botlib_export->BotLibShutdown();
-}
-
-/*
-==================
-SV_BotInitCvars
-==================
-*/
-void SV_BotInitCvars(void) {
-
- Cvar_Get("bot_enable", "1", 0); //enable the bot
- Cvar_Get("bot_developer", "0", CVAR_CHEAT); //bot developer mode
- Cvar_Get("bot_debug", "0", CVAR_CHEAT); //enable bot debugging
- Cvar_Get("bot_maxdebugpolys", "2", 0); //maximum number of debug polys
- Cvar_Get("bot_groundonly", "1", 0); //only show ground faces of areas
- Cvar_Get("bot_reachability", "0", 0); //show all reachabilities to other areas
- Cvar_Get("bot_visualizejumppads", "0", CVAR_CHEAT); //show jumppads
- Cvar_Get("bot_forceclustering", "0", 0); //force cluster calculations
- Cvar_Get("bot_forcereachability", "0", 0); //force reachability calculations
- Cvar_Get("bot_forcewrite", "0", 0); //force writing aas file
- Cvar_Get("bot_aasoptimize", "0", 0); //no aas file optimisation
- Cvar_Get("bot_saveroutingcache", "0", 0); //save routing cache
- Cvar_Get("bot_thinktime", "100", CVAR_CHEAT); //msec the bots thinks
- Cvar_Get("bot_reloadcharacters", "0", 0); //reload the bot characters each time
- Cvar_Get("bot_testichat", "0", 0); //test ichats
- Cvar_Get("bot_testrchat", "0", 0); //test rchats
- Cvar_Get("bot_testsolid", "0", CVAR_CHEAT); //test for solid areas
- Cvar_Get("bot_testclusters", "0", CVAR_CHEAT); //test the AAS clusters
- Cvar_Get("bot_fastchat", "0", 0); //fast chatting bots
- Cvar_Get("bot_nochat", "0", 0); //disable chats
- Cvar_Get("bot_pause", "0", CVAR_CHEAT); //pause the bots thinking
- Cvar_Get("bot_report", "0", CVAR_CHEAT); //get a full report in ctf
- Cvar_Get("bot_grapple", "0", 0); //enable grapple
- Cvar_Get("bot_rocketjump", "1", 0); //enable rocket jumping
- Cvar_Get("bot_challenge", "0", 0); //challenging bot
- Cvar_Get("bot_minplayers", "0", 0); //minimum players in a team or the game
- Cvar_Get("bot_interbreedchar", "", CVAR_CHEAT); //bot character used for interbreeding
- Cvar_Get("bot_interbreedbots", "10", CVAR_CHEAT); //number of bots used for interbreeding
- Cvar_Get("bot_interbreedcycle", "20", CVAR_CHEAT); //bot interbreeding cycle
- Cvar_Get("bot_interbreedwrite", "", CVAR_CHEAT); //write interbreeded bots to this file
-}
-
-/*
-==================
-SV_BotInitBotLib
-==================
-*/
-void SV_BotInitBotLib(void) {
- botlib_import_t botlib_import;
-
- if (debugpolygons) Z_Free(debugpolygons);
- bot_maxdebugpolys = Cvar_VariableIntegerValue("bot_maxdebugpolys");
- debugpolygons = Z_Malloc(sizeof(bot_debugpoly_t) * bot_maxdebugpolys);
-
- botlib_import.Print = BotImport_Print;
- botlib_import.Trace = BotImport_Trace;
- botlib_import.EntityTrace = BotImport_EntityTrace;
- botlib_import.PointContents = BotImport_PointContents;
- botlib_import.inPVS = BotImport_inPVS;
- botlib_import.BSPEntityData = BotImport_BSPEntityData;
- botlib_import.BSPModelMinsMaxsOrigin = BotImport_BSPModelMinsMaxsOrigin;
- botlib_import.BotClientCommand = BotClientCommand;
-
- //memory management
- botlib_import.GetMemory = BotImport_GetMemory;
- botlib_import.FreeMemory = BotImport_FreeMemory;
- botlib_import.AvailableMemory = Z_AvailableMemory;
- botlib_import.HunkAlloc = BotImport_HunkAlloc;
-
- // file system access
- botlib_import.FS_FOpenFile = FS_FOpenFileByMode;
- botlib_import.FS_Read = FS_Read2;
- botlib_import.FS_Write = FS_Write;
- botlib_import.FS_FCloseFile = FS_FCloseFile;
- botlib_import.FS_Seek = FS_Seek;
-
- //debug lines
- botlib_import.DebugLineCreate = BotImport_DebugLineCreate;
- botlib_import.DebugLineDelete = BotImport_DebugLineDelete;
- botlib_import.DebugLineShow = BotImport_DebugLineShow;
-
- //debug polygons
- botlib_import.DebugPolygonCreate = BotImport_DebugPolygonCreate;
- botlib_import.DebugPolygonDelete = BotImport_DebugPolygonDelete;
-
- botlib_export = (botlib_export_t *)GetBotLibAPI( BOTLIB_API_VERSION, &botlib_import );
- assert(botlib_export); // somehow we end up with a zero import.
-}
-
-
-//
-// * * * BOT AI CODE IS BELOW THIS POINT * * *
-//
-
-/*
-==================
-SV_BotGetConsoleMessage
-==================
-*/
-int SV_BotGetConsoleMessage( int client, char *buf, int size )
-{
- client_t *cl;
- int index;
-
- cl = &svs.clients[client];
- cl->lastPacketTime = svs.time;
-
- if ( cl->reliableAcknowledge == cl->reliableSequence ) {
- return qfalse;
- }
-
- cl->reliableAcknowledge++;
- index = cl->reliableAcknowledge & ( MAX_RELIABLE_COMMANDS - 1 );
-
- if ( !cl->reliableCommands[index][0] ) {
- return qfalse;
- }
-
- Q_strncpyz( buf, cl->reliableCommands[index], size );
- return qtrue;
-}
-
-#if 0
-/*
-==================
-EntityInPVS
-==================
-*/
-int EntityInPVS( int client, int entityNum ) {
- client_t *cl;
- clientSnapshot_t *frame;
- int i;
-
- cl = &svs.clients[client];
- frame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK];
- for ( i = 0; i < frame->num_entities; i++ ) {
- if ( svs.snapshotEntities[(frame->first_entity + i) % svs.numSnapshotEntities].number == entityNum ) {
- return qtrue;
- }
- }
- return qfalse;
-}
-#endif
-
-/*
-==================
-SV_BotGetSnapshotEntity
-==================
-*/
-int SV_BotGetSnapshotEntity( int client, int sequence ) {
- client_t *cl;
- clientSnapshot_t *frame;
-
- cl = &svs.clients[client];
- frame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK];
- if (sequence < 0 || sequence >= frame->num_entities) {
- return -1;
- }
- return svs.snapshotEntities[(frame->first_entity + sequence) % svs.numSnapshotEntities].number;
-}
-
diff --git a/engine/code/server/sv_ccmds.c b/engine/code/server/sv_ccmds.c
deleted file mode 100644
index 0b9d578..0000000
--- a/engine/code/server/sv_ccmds.c
+++ /dev/null
@@ -1,1319 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "server.h"
-
-/*
-===============================================================================
-
-OPERATOR CONSOLE ONLY COMMANDS
-
-These commands can only be entered from stdin or by a remote operator datagram
-===============================================================================
-*/
-
-
-/*
-==================
-SV_GetPlayerByHandle
-
-Returns the player with player id or name from Cmd_Argv(1)
-==================
-*/
-static client_t *SV_GetPlayerByHandle( void ) {
- client_t *cl;
- int i;
- char *s;
- char cleanName[64];
-
- // make sure server is running
- if ( !com_sv_running->integer ) {
- return NULL;
- }
-
- if ( Cmd_Argc() < 2 ) {
- Com_Printf( "No player specified.\n" );
- return NULL;
- }
-
- s = Cmd_Argv(1);
-
- // Check whether this is a numeric player handle
- for(i = 0; s[i] >= '0' && s[i] <= '9'; i++);
-
- if(!s[i])
- {
- int plid = atoi(s);
-
- // Check for numeric playerid match
- if(plid >= 0 && plid < sv_maxclients->integer)
- {
- cl = &svs.clients[plid];
-
- if(cl->state)
- return cl;
- }
- }
-
- // check for a name match
- for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) {
- if ( !cl->state ) {
- continue;
- }
- if ( !Q_stricmp( cl->name, s ) ) {
- return cl;
- }
-
- Q_strncpyz( cleanName, cl->name, sizeof(cleanName) );
- Q_CleanStr( cleanName );
- if ( !Q_stricmp( cleanName, s ) ) {
- return cl;
- }
- }
-
- Com_Printf( "Player %s is not on the server\n", s );
-
- return NULL;
-}
-
-/*
-==================
-SV_GetPlayerByNum
-
-Returns the player with idnum from Cmd_Argv(1)
-==================
-*/
-static client_t *SV_GetPlayerByNum( void ) {
- client_t *cl;
- int i;
- int idnum;
- char *s;
-
- // make sure server is running
- if ( !com_sv_running->integer ) {
- return NULL;
- }
-
- if ( Cmd_Argc() < 2 ) {
- Com_Printf( "No player specified.\n" );
- return NULL;
- }
-
- s = Cmd_Argv(1);
-
- for (i = 0; s[i]; i++) {
- if (s[i] < '0' || s[i] > '9') {
- Com_Printf( "Bad slot number: %s\n", s);
- return NULL;
- }
- }
- idnum = atoi( s );
- if ( idnum < 0 || idnum >= sv_maxclients->integer ) {
- Com_Printf( "Bad client slot: %i\n", idnum );
- return NULL;
- }
-
- cl = &svs.clients[idnum];
- if ( !cl->state ) {
- Com_Printf( "Client %i is not active\n", idnum );
- return NULL;
- }
- return cl;
-}
-
-//=========================================================
-
-
-/*
-==================
-SV_Map_f
-
-Restart the server on a different map
-==================
-*/
-static void SV_Map_f( void ) {
- char *cmd;
- char *map;
- qboolean killBots, cheat;
- char expanded[MAX_QPATH];
- char mapname[MAX_QPATH];
-
- map = Cmd_Argv(1);
- if ( !map ) {
- return;
- }
-
- // make sure the level exists before trying to change, so that
- // a typo at the server console won't end the game
- Com_sprintf (expanded, sizeof(expanded), "maps/%s.bsp", map);
- if ( FS_ReadFile (expanded, NULL) == -1 ) {
- Com_Printf ("Can't find map %s\n", expanded);
- return;
- }
-
- // force latched values to get set
- Cvar_Get ("g_gametype", "0", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH );
-
- cmd = Cmd_Argv(0);
- if( Q_stricmpn( cmd, "sp", 2 ) == 0 ) {
- Cvar_SetValue( "g_gametype", GT_SINGLE_PLAYER );
- Cvar_SetValue( "g_doWarmup", 0 );
- // may not set sv_maxclients directly, always set latched
- Cvar_SetLatched( "sv_maxclients", "8" );
- cmd += 2;
- cheat = qfalse;
- killBots = qtrue;
- }
- else {
- if ( !Q_stricmp( cmd, "devmap" ) || !Q_stricmp( cmd, "spdevmap" ) ) {
- cheat = qtrue;
- killBots = qtrue;
- } else {
- cheat = qfalse;
- killBots = qfalse;
- }
- if( sv_gametype->integer == GT_SINGLE_PLAYER ) {
- Cvar_SetValue( "g_gametype", GT_FFA );
- }
- }
-
- // save the map name here cause on a map restart we reload the q3config.cfg
- // and thus nuke the arguments of the map command
- Q_strncpyz(mapname, map, sizeof(mapname));
-
- // start up the map
- SV_SpawnServer( mapname, killBots );
-
- // set the cheat value
- // if the level was started with "map <levelname>", then
- // cheats will not be allowed. If started with "devmap <levelname>"
- // then cheats will be allowed
- if ( cheat ) {
- Cvar_Set( "sv_cheats", "1" );
- } else {
- Cvar_Set( "sv_cheats", "0" );
- }
-}
-
-/*
-================
-SV_MapRestart_f
-
-Completely restarts a level, but doesn't send a new gamestate to the clients.
-This allows fair starts with variable load times.
-================
-*/
-static void SV_MapRestart_f( void ) {
- int i;
- client_t *client;
- char *denied;
- qboolean isBot;
- int delay;
-
- // make sure we aren't restarting twice in the same frame
- if ( com_frameTime == sv.serverId ) {
- return;
- }
-
- // make sure server is running
- if ( !com_sv_running->integer ) {
- Com_Printf( "Server is not running.\n" );
- return;
- }
-
- if ( sv.restartTime ) {
- return;
- }
-
- if (Cmd_Argc() > 1 ) {
- delay = atoi( Cmd_Argv(1) );
- }
- else {
- delay = 5;
- }
- if( delay && !Cvar_VariableValue("g_doWarmup") ) {
- sv.restartTime = sv.time + delay * 1000;
- SV_SetConfigstring( CS_WARMUP, va("%i", sv.restartTime) );
- return;
- }
-
- // check for changes in variables that can't just be restarted
- // check for maxclients change
- if ( sv_maxclients->modified || sv_gametype->modified ) {
- char mapname[MAX_QPATH];
-
- Com_Printf( "variable change -- restarting.\n" );
- // restart the map the slow way
- Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );
-
- SV_SpawnServer( mapname, qfalse );
- return;
- }
-
- // toggle the server bit so clients can detect that a
- // map_restart has happened
- svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;
-
- // generate a new serverid
- // TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
- sv.serverId = com_frameTime;
- Cvar_Set( "sv_serverid", va("%i", sv.serverId ) );
-
- // if a map_restart occurs while a client is changing maps, we need
- // to give them the correct time so that when they finish loading
- // they don't violate the backwards time check in cl_cgame.c
- for (i=0 ; i<sv_maxclients->integer ; i++) {
- if (svs.clients[i].state == CS_PRIMED) {
- svs.clients[i].oldServerTime = sv.restartTime;
- }
- }
-
- // reset all the vm data in place without changing memory allocation
- // note that we do NOT set sv.state = SS_LOADING, so configstrings that
- // had been changed from their default values will generate broadcast updates
- sv.state = SS_LOADING;
- sv.restarting = qtrue;
-
- SV_RestartGameProgs();
-
- // run a few frames to allow everything to settle
- for (i = 0; i < 3; i++)
- {
- VM_Call (gvm, GAME_RUN_FRAME, sv.time);
- sv.time += 100;
- svs.time += 100;
- }
-
- sv.state = SS_GAME;
- sv.restarting = qfalse;
-
- // connect and begin all the clients
- for (i=0 ; i<sv_maxclients->integer ; i++) {
- client = &svs.clients[i];
-
- // send the new gamestate to all connected clients
- if ( client->state < CS_CONNECTED) {
- continue;
- }
-
- if ( client->netchan.remoteAddress.type == NA_BOT ) {
- isBot = qtrue;
- } else {
- isBot = qfalse;
- }
-
- // add the map_restart command
- SV_AddServerCommand( client, "map_restart\n" );
-
- // connect the client again, without the firstTime flag
- denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) );
- if ( denied ) {
- // this generally shouldn't happen, because the client
- // was connected before the level change
- SV_DropClient( client, denied );
- Com_Printf( "SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i );
- continue;
- }
-
- client->state = CS_ACTIVE;
-
- SV_ClientEnterWorld( client, &client->lastUsercmd );
- }
-
- // run another frame to allow things to look at all the players
- VM_Call (gvm, GAME_RUN_FRAME, sv.time);
- sv.time += 100;
- svs.time += 100;
-}
-
-//===============================================================
-
-/*
-==================
-SV_Kick_f
-
-Kick a user off of the server FIXME: move to game
-==================
-*/
-static void SV_Kick_f( void ) {
- client_t *cl;
- int i;
-
- // make sure server is running
- if ( !com_sv_running->integer ) {
- Com_Printf( "Server is not running.\n" );
- return;
- }
-
- if ( Cmd_Argc() != 2 ) {
- Com_Printf ("Usage: kick <player name>\nkick all = kick everyone\nkick allbots = kick all bots\n");
- return;
- }
-
- cl = SV_GetPlayerByHandle();
- if ( !cl ) {
- if ( !Q_stricmp(Cmd_Argv(1), "all") ) {
- for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) {
- if ( !cl->state ) {
- continue;
- }
- if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
- continue;
- }
- SV_DropClient( cl, "was kicked" );
- cl->lastPacketTime = svs.time; // in case there is a funny zombie
- }
- }
- else if ( !Q_stricmp(Cmd_Argv(1), "allbots") ) {
- for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) {
- if ( !cl->state ) {
- continue;
- }
- if( cl->netchan.remoteAddress.type != NA_BOT ) {
- continue;
- }
- SV_DropClient( cl, "was kicked" );
- cl->lastPacketTime = svs.time; // in case there is a funny zombie
- }
- }
- return;
- }
- if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
- SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
- return;
- }
-
- SV_DropClient( cl, "was kicked" );
- cl->lastPacketTime = svs.time; // in case there is a funny zombie
-}
-
-#ifndef STANDALONE
-// these functions require the auth server which of course is not available anymore for stand-alone games.
-
-/*
-==================
-SV_Ban_f
-
-Ban a user from being able to play on this server through the auth
-server
-==================
-*/
-static void SV_Ban_f( void ) {
- client_t *cl;
-
- // make sure server is running
- if ( !com_sv_running->integer ) {
- Com_Printf( "Server is not running.\n" );
- return;
- }
-
- if ( Cmd_Argc() != 2 ) {
- Com_Printf ("Usage: banUser <player name>\n");
- return;
- }
-
- cl = SV_GetPlayerByHandle();
-
- if (!cl) {
- return;
- }
-
- if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
- SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
- return;
- }
-
- // look up the authorize server's IP
- if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
- Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
- if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress, NA_IP ) ) {
- Com_Printf( "Couldn't resolve address\n" );
- return;
- }
- svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );
- Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
- svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
- svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
- BigShort( svs.authorizeAddress.port ) );
- }
-
- // otherwise send their ip to the authorize server
- if ( svs.authorizeAddress.type != NA_BAD ) {
- NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
- "banUser %i.%i.%i.%i", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1],
- cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );
- Com_Printf("%s was banned from coming back\n", cl->name);
- }
-}
-
-/*
-==================
-SV_BanNum_f
-
-Ban a user from being able to play on this server through the auth
-server
-==================
-*/
-static void SV_BanNum_f( void ) {
- client_t *cl;
-
- // make sure server is running
- if ( !com_sv_running->integer ) {
- Com_Printf( "Server is not running.\n" );
- return;
- }
-
- if ( Cmd_Argc() != 2 ) {
- Com_Printf ("Usage: banClient <client number>\n");
- return;
- }
-
- cl = SV_GetPlayerByNum();
- if ( !cl ) {
- return;
- }
- if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
- SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
- return;
- }
-
- // look up the authorize server's IP
- if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
- Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
- if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress, NA_IP ) ) {
- Com_Printf( "Couldn't resolve address\n" );
- return;
- }
- svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );
- Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
- svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
- svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
- BigShort( svs.authorizeAddress.port ) );
- }
-
- // otherwise send their ip to the authorize server
- if ( svs.authorizeAddress.type != NA_BAD ) {
- NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
- "banUser %i.%i.%i.%i", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1],
- cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );
- Com_Printf("%s was banned from coming back\n", cl->name);
- }
-}
-#endif
-
-/*
-==================
-SV_RehashBans_f
-
-Load saved bans from file.
-==================
-*/
-static void SV_RehashBans_f(void)
-{
- int index, filelen;
- fileHandle_t readfrom;
- char *textbuf, *curpos, *maskpos, *newlinepos, *endpos;
- char filepath[MAX_QPATH];
-
- serverBansCount = 0;
-
- if(!sv_banFile->string || !*sv_banFile->string)
- return;
-
- if(!(curpos = Cvar_VariableString("fs_game")) || !*curpos)
- curpos = BASEGAME;
-
- Com_sprintf(filepath, sizeof(filepath), "%s/%s", curpos, sv_banFile->string);
-
- if((filelen = FS_SV_FOpenFileRead(filepath, &readfrom)) >= 0)
- {
- if(filelen < 2)
- {
- // Don't bother if file is too short.
- FS_FCloseFile(readfrom);
- return;
- }
-
- curpos = textbuf = Z_Malloc(filelen);
-
- filelen = FS_Read(textbuf, filelen, readfrom);
- FS_FCloseFile(readfrom);
-
- endpos = textbuf + filelen;
-
- for(index = 0; index < SERVER_MAXBANS && curpos + 2 < endpos; index++)
- {
- // find the end of the address string
- for(maskpos = curpos + 2; maskpos < endpos && *maskpos != ' '; maskpos++);
-
- if(maskpos + 1 >= endpos)
- break;
-
- *maskpos = '\0';
- maskpos++;
-
- // find the end of the subnet specifier
- for(newlinepos = maskpos; newlinepos < endpos && *newlinepos != '\n'; newlinepos++);
-
- if(newlinepos >= endpos)
- break;
-
- *newlinepos = '\0';
-
- if(NET_StringToAdr(curpos + 2, &serverBans[index].ip, NA_UNSPEC))
- {
- serverBans[index].isexception = (curpos[0] != '0');
- serverBans[index].subnet = atoi(maskpos);
-
- if(serverBans[index].ip.type == NA_IP &&
- (serverBans[index].subnet < 1 || serverBans[index].subnet > 32))
- {
- serverBans[index].subnet = 32;
- }
- else if(serverBans[index].ip.type == NA_IP6 &&
- (serverBans[index].subnet < 1 || serverBans[index].subnet > 128))
- {
- serverBans[index].subnet = 128;
- }
- }
-
- curpos = newlinepos + 1;
- }
-
- serverBansCount = index;
-
- Z_Free(textbuf);
- }
-}
-
-/*
-==================
-SV_WriteBans_f
-
-Save bans to file.
-==================
-*/
-static void SV_WriteBans(void)
-{
- int index;
- fileHandle_t writeto;
- char *curpos, filepath[MAX_QPATH];
-
- if(!sv_banFile->string || !*sv_banFile->string)
- return;
-
- if(!(curpos = Cvar_VariableString("fs_game")) || !*curpos)
- curpos = BASEGAME;
-
- Com_sprintf(filepath, sizeof(filepath), "%s/%s", curpos, sv_banFile->string);
-
- if((writeto = FS_SV_FOpenFileWrite(filepath)))
- {
- char writebuf[128];
- serverBan_t *curban;
-
- for(index = 0; index < serverBansCount; index++)
- {
- curban = &serverBans[index];
-
- Com_sprintf(writebuf, sizeof(writebuf), "%d %s %d\n",
- curban->isexception, NET_AdrToString(curban->ip), curban->subnet);
- FS_Write(writebuf, strlen(writebuf), writeto);
- }
-
- FS_FCloseFile(writeto);
- }
-}
-
-/*
-==================
-SV_DelBanEntryFromList
-
-Remove a ban or an exception from the list.
-==================
-*/
-
-static qboolean SV_DelBanEntryFromList(int index)
-{
- if(index == serverBansCount - 1)
- serverBansCount--;
- else if(index < sizeof(serverBans) / sizeof(*serverBans) - 1)
- {
- memmove(serverBans + index, serverBans + index + 1, (serverBansCount - index - 1) * sizeof(*serverBans));
- serverBansCount--;
- }
- else
- return qtrue;
-
- return qfalse;
-}
-
-/*
-==================
-SV_ParseCIDRNotation
-
-Parse a CIDR notation type string and return a netadr_t and suffix by reference
-==================
-*/
-
-static qboolean SV_ParseCIDRNotation(netadr_t *dest, int *mask, char *adrstr)
-{
- char *suffix;
-
- suffix = strchr(adrstr, '/');
- if(suffix)
- {
- *suffix = '\0';
- suffix++;
- }
-
- if(!NET_StringToAdr(adrstr, dest, NA_UNSPEC))
- return qtrue;
-
- if(suffix)
- {
- *mask = atoi(suffix);
-
- if(dest->type == NA_IP)
- {
- if(*mask < 1 || *mask > 32)
- *mask = 32;
- }
- else
- {
- if(*mask < 1 || *mask > 128)
- *mask = 128;
- }
- }
- else if(dest->type == NA_IP)
- *mask = 32;
- else
- *mask = 128;
-
- return qfalse;
-}
-
-/*
-==================
-SV_AddBanToList
-
-Ban a user from being able to play on this server based on his ip address.
-==================
-*/
-
-static void SV_AddBanToList(qboolean isexception)
-{
- char *banstring;
- char addy2[NET_ADDRSTRMAXLEN];
- netadr_t ip;
- int index, argc, mask;
- serverBan_t *curban;
-
- argc = Cmd_Argc();
-
- if(argc < 2 || argc > 3)
- {
- Com_Printf ("Usage: %s (ip[/subnet] | clientnum [subnet])\n", Cmd_Argv(0));
- return;
- }
-
- if(serverBansCount > sizeof(serverBans) / sizeof(*serverBans))
- {
- Com_Printf ("Error: Maximum number of bans/exceptions exceeded.\n");
- return;
- }
-
- banstring = Cmd_Argv(1);
-
- if(strchr(banstring, '.') || strchr(banstring, ':'))
- {
- // This is an ip address, not a client num.
-
- if(SV_ParseCIDRNotation(&ip, &mask, banstring))
- {
- Com_Printf("Error: Invalid address %s\n", banstring);
- return;
- }
- }
- else
- {
- client_t *cl;
-
- // client num.
- if(!com_sv_running->integer)
- {
- Com_Printf("Server is not running.\n");
- return;
- }
-
- cl = SV_GetPlayerByNum();
-
- if(!cl)
- {
- Com_Printf("Error: Playernum %s does not exist.\n", Cmd_Argv(1));
- return;
- }
-
- ip = cl->netchan.remoteAddress;
-
- if(argc == 3)
- {
- mask = atoi(Cmd_Argv(2));
-
- if(ip.type == NA_IP)
- {
- if(mask < 1 || mask > 32)
- mask = 32;
- }
- else
- {
- if(mask < 1 || mask > 128)
- mask = 128;
- }
- }
- else
- mask = (ip.type == NA_IP6) ? 128 : 32;
- }
-
- if(ip.type != NA_IP && ip.type != NA_IP6)
- {
- Com_Printf("Error: Can ban players connected via the internet only.\n");
- return;
- }
-
- // first check whether a conflicting ban exists that would supersede the new one.
- for(index = 0; index < serverBansCount; index++)
- {
- curban = &serverBans[index];
-
- if(curban->subnet <= mask)
- {
- if((curban->isexception || !isexception) && NET_CompareBaseAdrMask(curban->ip, ip, curban->subnet))
- {
- Q_strncpyz(addy2, NET_AdrToString(ip), sizeof(addy2));
-
- Com_Printf("Error: %s %s/%d supersedes %s %s/%d\n", curban->isexception ? "Exception" : "Ban",
- NET_AdrToString(curban->ip), curban->subnet,
- isexception ? "exception" : "ban", addy2, mask);
- return;
- }
- }
- if(curban->subnet >= mask)
- {
- if(!curban->isexception && isexception && NET_CompareBaseAdrMask(curban->ip, ip, mask))
- {
- Q_strncpyz(addy2, NET_AdrToString(curban->ip), sizeof(addy2));
-
- Com_Printf("Error: %s %s/%d supersedes already existing %s %s/%d\n", isexception ? "Exception" : "Ban",
- NET_AdrToString(ip), mask,
- curban->isexception ? "exception" : "ban", addy2, curban->subnet);
- return;
- }
- }
- }
-
- // now delete bans that are superseded by the new one
- index = 0;
- while(index < serverBansCount)
- {
- curban = &serverBans[index];
-
- if(curban->subnet > mask && (!curban->isexception || isexception) && NET_CompareBaseAdrMask(curban->ip, ip, mask))
- SV_DelBanEntryFromList(index);
- else
- index++;
- }
-
- serverBans[serverBansCount].ip = ip;
- serverBans[serverBansCount].subnet = mask;
- serverBans[serverBansCount].isexception = isexception;
-
- serverBansCount++;
-
- SV_WriteBans();
-
- Com_Printf("Added %s: %s/%d\n", isexception ? "ban exception" : "ban",
- NET_AdrToString(ip), mask);
-}
-
-/*
-==================
-SV_DelBanFromList
-
-Remove a ban or an exception from the list.
-==================
-*/
-
-static void SV_DelBanFromList(qboolean isexception)
-{
- int index, count = 0, todel, mask;
- netadr_t ip;
- char *banstring;
-
- if(Cmd_Argc() != 2)
- {
- Com_Printf ("Usage: %s (ip[/subnet] | num)\n", Cmd_Argv(0));
- return;
- }
-
- banstring = Cmd_Argv(1);
-
- if(strchr(banstring, '.') || strchr(banstring, ':'))
- {
- serverBan_t *curban;
-
- if(SV_ParseCIDRNotation(&ip, &mask, banstring))
- {
- Com_Printf("Error: Invalid address %s\n", banstring);
- return;
- }
-
- index = 0;
-
- while(index < serverBansCount)
- {
- curban = &serverBans[index];
-
- if(curban->isexception == isexception &&
- curban->subnet >= mask &&
- NET_CompareBaseAdrMask(curban->ip, ip, mask))
- {
- Com_Printf("Deleting %s %s/%d\n",
- isexception ? "exception" : "ban",
- NET_AdrToString(curban->ip), curban->subnet);
-
- SV_DelBanEntryFromList(index);
- }
- else
- index++;
- }
- }
- else
- {
- todel = atoi(Cmd_Argv(1));
-
- if(todel < 1 || todel > serverBansCount)
- {
- Com_Printf("Error: Invalid ban number given\n");
- return;
- }
-
- for(index = 0; index < serverBansCount; index++)
- {
- if(serverBans[index].isexception == isexception)
- {
- count++;
-
- if(count == todel)
- {
- Com_Printf("Deleting %s %s/%d\n",
- isexception ? "exception" : "ban",
- NET_AdrToString(serverBans[index].ip), serverBans[index].subnet);
-
- SV_DelBanEntryFromList(index);
-
- break;
- }
- }
- }
- }
-
- SV_WriteBans();
-}
-
-
-/*
-==================
-SV_ListBans_f
-
-List all bans and exceptions on console
-==================
-*/
-
-static void SV_ListBans_f(void)
-{
- int index, count;
- serverBan_t *ban;
-
- // List all bans
- for(index = count = 0; index < serverBansCount; index++)
- {
- ban = &serverBans[index];
- if(!ban->isexception)
- {
- count++;
-
- Com_Printf("Ban #%d: %s/%d\n", count,
- NET_AdrToString(ban->ip), ban->subnet);
- }
- }
- // List all exceptions
- for(index = count = 0; index < serverBansCount; index++)
- {
- ban = &serverBans[index];
- if(ban->isexception)
- {
- count++;
-
- Com_Printf("Except #%d: %s/%d\n", count,
- NET_AdrToString(ban->ip), ban->subnet);
- }
- }
-}
-
-/*
-==================
-SV_FlushBans_f
-
-Delete all bans and exceptions.
-==================
-*/
-
-static void SV_FlushBans_f(void)
-{
- serverBansCount = 0;
-
- // empty the ban file.
- SV_WriteBans();
-
- Com_Printf("All bans and exceptions have been deleted.\n");
-}
-
-static void SV_BanAddr_f(void)
-{
- SV_AddBanToList(qfalse);
-}
-
-static void SV_ExceptAddr_f(void)
-{
- SV_AddBanToList(qtrue);
-}
-
-static void SV_BanDel_f(void)
-{
- SV_DelBanFromList(qfalse);
-}
-
-static void SV_ExceptDel_f(void)
-{
- SV_DelBanFromList(qtrue);
-}
-
-/*
-==================
-SV_KickNum_f
-
-Kick a user off of the server FIXME: move to game
-==================
-*/
-static void SV_KickNum_f( void ) {
- client_t *cl;
-
- // make sure server is running
- if ( !com_sv_running->integer ) {
- Com_Printf( "Server is not running.\n" );
- return;
- }
-
- if ( Cmd_Argc() != 2 ) {
- Com_Printf ("Usage: kicknum <client number>\n");
- return;
- }
-
- cl = SV_GetPlayerByNum();
- if ( !cl ) {
- return;
- }
- if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
- SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
- return;
- }
-
- SV_DropClient( cl, "was kicked" );
- cl->lastPacketTime = svs.time; // in case there is a funny zombie
-}
-
-/*
-================
-SV_Status_f
-================
-*/
-static void SV_Status_f( void ) {
- int i, j, l;
- client_t *cl;
- playerState_t *ps;
- const char *s;
- int ping;
-
- // make sure server is running
- if ( !com_sv_running->integer ) {
- Com_Printf( "Server is not running.\n" );
- return;
- }
-
- Com_Printf ("map: %s\n", sv_mapname->string );
-
- Com_Printf ("num score ping name lastmsg address qport rate\n");
- Com_Printf ("--- ----- ---- --------------- ------- --------------------- ----- -----\n");
- for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++)
- {
- if (!cl->state)
- continue;
- Com_Printf ("%3i ", i);
- ps = SV_GameClientNum( i );
- Com_Printf ("%5i ", ps->persistant[PERS_SCORE]);
-
- if (cl->state == CS_CONNECTED)
- Com_Printf ("CNCT ");
- else if (cl->state == CS_ZOMBIE)
- Com_Printf ("ZMBI ");
- else
- {
- ping = cl->ping < 9999 ? cl->ping : 9999;
- Com_Printf ("%4i ", ping);
- }
-
- Com_Printf ("%s", cl->name);
- // TTimo adding a ^7 to reset the color
- // NOTE: colored names in status breaks the padding (WONTFIX)
- Com_Printf ("^7");
- l = 16 - strlen(cl->name);
- for (j=0 ; j<l ; j++)
- Com_Printf (" ");
-
- Com_Printf ("%7i ", svs.time - cl->lastPacketTime );
-
- s = NET_AdrToString( cl->netchan.remoteAddress );
- Com_Printf ("%s", s);
- l = 22 - strlen(s);
- for (j=0 ; j<l ; j++)
- Com_Printf (" ");
-
- Com_Printf ("%5i", cl->netchan.qport);
-
- Com_Printf (" %5i", cl->rate);
-
- Com_Printf ("\n");
- }
- Com_Printf ("\n");
-}
-
-/*
-==================
-SV_ConSay_f
-==================
-*/
-static void SV_ConSay_f(void) {
- char *p;
- char text[1024];
-
- // make sure server is running
- if ( !com_sv_running->integer ) {
- Com_Printf( "Server is not running.\n" );
- return;
- }
-
- if ( Cmd_Argc () < 2 ) {
- return;
- }
-
- strcpy (text, "console: ");
- p = Cmd_Args();
-
- if ( *p == '"' ) {
- p++;
- p[strlen(p)-1] = 0;
- }
-
- strcat(text, p);
-
- SV_SendServerCommand(NULL, "chat \"%s\"", text);
-}
-
-
-/*
-==================
-SV_Heartbeat_f
-
-Also called by SV_DropClient, SV_DirectConnect, and SV_SpawnServer
-==================
-*/
-void SV_Heartbeat_f( void ) {
- svs.nextHeartbeatTime = -9999999;
-}
-
-
-/*
-===========
-SV_Serverinfo_f
-
-Examine the serverinfo string
-===========
-*/
-static void SV_Serverinfo_f( void ) {
- Com_Printf ("Server info settings:\n");
- Info_Print ( Cvar_InfoString( CVAR_SERVERINFO ) );
-}
-
-
-/*
-===========
-SV_Systeminfo_f
-
-Examine or change the serverinfo string
-===========
-*/
-static void SV_Systeminfo_f( void ) {
- Com_Printf ("System info settings:\n");
- Info_Print ( Cvar_InfoString( CVAR_SYSTEMINFO ) );
-}
-
-
-/*
-===========
-SV_DumpUser_f
-
-Examine all a users info strings FIXME: move to game
-===========
-*/
-static void SV_DumpUser_f( void ) {
- client_t *cl;
-
- // make sure server is running
- if ( !com_sv_running->integer ) {
- Com_Printf( "Server is not running.\n" );
- return;
- }
-
- if ( Cmd_Argc() != 2 ) {
- Com_Printf ("Usage: info <userid>\n");
- return;
- }
-
- cl = SV_GetPlayerByHandle();
- if ( !cl ) {
- return;
- }
-
- Com_Printf( "userinfo\n" );
- Com_Printf( "--------\n" );
- Info_Print( cl->userinfo );
-}
-
-
-/*
-=================
-SV_KillServer
-=================
-*/
-static void SV_KillServer_f( void ) {
- SV_Shutdown( "killserver" );
-}
-
-//===========================================================
-
-/*
-==================
-SV_CompleteMapName
-==================
-*/
-static void SV_CompleteMapName( char *args, int argNum ) {
- if( argNum == 2 ) {
- Field_CompleteFilename( "maps", "bsp", qtrue );
- }
-}
-
-/*
-==================
-SV_AddOperatorCommands
-==================
-*/
-void SV_AddOperatorCommands( void ) {
- static qboolean initialized;
-
- if ( initialized ) {
- return;
- }
- initialized = qtrue;
-
- Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);
- Cmd_AddCommand ("kick", SV_Kick_f);
-#ifndef STANDALONE
- if(!Cvar_VariableIntegerValue("com_standalone"))
- {
- Cmd_AddCommand ("banUser", SV_Ban_f);
- Cmd_AddCommand ("banClient", SV_BanNum_f);
- }
-#endif
- Cmd_AddCommand ("clientkick", SV_KickNum_f);
- Cmd_AddCommand ("status", SV_Status_f);
- Cmd_AddCommand ("serverinfo", SV_Serverinfo_f);
- Cmd_AddCommand ("systeminfo", SV_Systeminfo_f);
- Cmd_AddCommand ("dumpuser", SV_DumpUser_f);
- Cmd_AddCommand ("map_restart", SV_MapRestart_f);
- Cmd_AddCommand ("sectorlist", SV_SectorList_f);
- Cmd_AddCommand ("map", SV_Map_f);
- Cmd_SetCommandCompletionFunc( "map", SV_CompleteMapName );
-#ifndef PRE_RELEASE_DEMO
- Cmd_AddCommand ("devmap", SV_Map_f);
- Cmd_SetCommandCompletionFunc( "devmap", SV_CompleteMapName );
- Cmd_AddCommand ("spmap", SV_Map_f);
- Cmd_SetCommandCompletionFunc( "spmap", SV_CompleteMapName );
- Cmd_AddCommand ("spdevmap", SV_Map_f);
- Cmd_SetCommandCompletionFunc( "spdevmap", SV_CompleteMapName );
-#endif
- Cmd_AddCommand ("killserver", SV_KillServer_f);
- if( com_dedicated->integer ) {
- Cmd_AddCommand ("say", SV_ConSay_f);
- }
-
- Cmd_AddCommand("rehashbans", SV_RehashBans_f);
- Cmd_AddCommand("listbans", SV_ListBans_f);
- Cmd_AddCommand("banaddr", SV_BanAddr_f);
- Cmd_AddCommand("exceptaddr", SV_ExceptAddr_f);
- Cmd_AddCommand("bandel", SV_BanDel_f);
- Cmd_AddCommand("exceptdel", SV_ExceptDel_f);
- Cmd_AddCommand("flushbans", SV_FlushBans_f);
-}
-
-/*
-==================
-SV_RemoveOperatorCommands
-==================
-*/
-void SV_RemoveOperatorCommands( void ) {
-#if 0
- // removing these won't let the server start again
- Cmd_RemoveCommand ("heartbeat");
- Cmd_RemoveCommand ("kick");
- Cmd_RemoveCommand ("banUser");
- Cmd_RemoveCommand ("banClient");
- Cmd_RemoveCommand ("status");
- Cmd_RemoveCommand ("serverinfo");
- Cmd_RemoveCommand ("systeminfo");
- Cmd_RemoveCommand ("dumpuser");
- Cmd_RemoveCommand ("map_restart");
- Cmd_RemoveCommand ("sectorlist");
- Cmd_RemoveCommand ("say");
-#endif
-}
-
diff --git a/engine/code/server/sv_client.c b/engine/code/server/sv_client.c
deleted file mode 100644
index 1195c88..0000000
--- a/engine/code/server/sv_client.c
+++ /dev/null
@@ -1,1914 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// sv_client.c -- server code for dealing with clients
-
-#include "server.h"
-
-static void SV_CloseDownload( client_t *cl );
-
-/*
-=================
-SV_GetChallenge
-
-A "getchallenge" OOB command has been received
-Returns a challenge number that can be used
-in a subsequent connectResponse command.
-We do this to prevent denial of service attacks that
-flood the server with invalid connection IPs. With a
-challenge, they must give a valid IP address.
-
-If we are authorizing, a challenge request will cause a packet
-to be sent to the authorize server.
-
-When an authorizeip is returned, a challenge response will be
-sent to that ip.
-
-ioquake3: we added a possibility for clients to add a challenge
-to their packets, to make it more difficult for malicious servers
-to hi-jack client connections.
-Also, the auth stuff is completely disabled for com_standalone games
-as well as IPv6 connections, since there is no way to use the
-v4-only auth server for these new types of connections.
-=================
-*/
-void SV_GetChallenge(netadr_t from)
-{
- int i;
- int oldest;
- int oldestTime;
- const char *clientChallenge = Cmd_Argv(1);
- challenge_t *challenge;
-
- // ignore if we are in single player
- if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) {
- return;
- }
-
- oldest = 0;
- oldestTime = 0x7fffffff;
-
- // see if we already have a challenge for this ip
- challenge = &svs.challenges[0];
- for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) {
- if (!challenge->connected && NET_CompareAdr( from, challenge->adr ) ) {
- break;
- }
- if ( challenge->time < oldestTime ) {
- oldestTime = challenge->time;
- oldest = i;
- }
- }
-
- if (i == MAX_CHALLENGES)
- {
- // this is the first time this client has asked for a challenge
- challenge = &svs.challenges[oldest];
- challenge->clientChallenge = 0;
- challenge->adr = from;
- challenge->firstTime = svs.time;
- challenge->time = svs.time;
- challenge->connected = qfalse;
- }
-
- // always generate a new challenge number, so the client cannot circumvent sv_maxping
- challenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time;
- challenge->wasrefused = qfalse;
-
-
-#ifndef STANDALONE
- // Drop the authorize stuff if this client is coming in via v6 as the auth server does not support ipv6.
- // Drop also for addresses coming in on local LAN and for stand-alone games independent from id's assets.
- if(challenge->adr.type == NA_IP && !Cvar_VariableIntegerValue("com_standalone") && !Sys_IsLANAddress(from))
- {
- // look up the authorize server's IP
- if (svs.authorizeAddress.type == NA_BAD)
- {
- Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
-
- if (NET_StringToAdr(AUTHORIZE_SERVER_NAME, &svs.authorizeAddress, NA_IP))
- {
- svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );
- Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
- svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
- svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
- BigShort( svs.authorizeAddress.port ) );
- }
- }
-
- // we couldn't contact the auth server, let them in.
- if(svs.authorizeAddress.type == NA_BAD)
- Com_Printf("Couldn't resolve auth server address\n");
-
- // if they have been challenging for a long time and we
- // haven't heard anything from the authorize server, go ahead and
- // let them in, assuming the id server is down
- else if(svs.time - challenge->firstTime > AUTHORIZE_TIMEOUT)
- Com_DPrintf( "authorize server timed out\n" );
- else
- {
- // otherwise send their ip to the authorize server
- cvar_t *fs;
- char game[1024];
-
- // If the client provided us with a client challenge, store it...
- if(*clientChallenge)
- challenge->clientChallenge = atoi(clientChallenge);
-
- Com_DPrintf( "sending getIpAuthorize for %s\n", NET_AdrToString( from ));
-
- strcpy(game, BASEGAME);
- fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
- if (fs && fs->string[0] != 0) {
- strcpy(game, fs->string);
- }
-
- // the 0 is for backwards compatibility with obsolete sv_allowanonymous flags
- // getIpAuthorize <challenge> <IP> <game> 0 <auth-flag>
- NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
- "getIpAuthorize %i %i.%i.%i.%i %s 0 %s", challenge->challenge,
- from.ip[0], from.ip[1], from.ip[2], from.ip[3], game, sv_strictAuth->string );
-
- return;
- }
- }
-#endif
-
- challenge->pingTime = svs.time;
- NET_OutOfBandPrint( NS_SERVER, challenge->adr, "challengeResponse %i %s", challenge->challenge, clientChallenge);
-}
-
-#ifndef STANDALONE
-/*
-====================
-SV_AuthorizeIpPacket
-
-A packet has been returned from the authorize server.
-If we have a challenge adr for that ip, send the
-challengeResponse to it
-====================
-*/
-void SV_AuthorizeIpPacket( netadr_t from ) {
- int challenge;
- int i;
- char *s;
- char *r;
- challenge_t *challengeptr;
-
- if ( !NET_CompareBaseAdr( from, svs.authorizeAddress ) ) {
- Com_Printf( "SV_AuthorizeIpPacket: not from authorize server\n" );
- return;
- }
-
- challenge = atoi( Cmd_Argv( 1 ) );
-
- for (i = 0 ; i < MAX_CHALLENGES ; i++) {
- if ( svs.challenges[i].challenge == challenge ) {
- break;
- }
- }
- if ( i == MAX_CHALLENGES ) {
- Com_Printf( "SV_AuthorizeIpPacket: challenge not found\n" );
- return;
- }
-
- challengeptr = &svs.challenges[i];
-
- // send a packet back to the original client
- challengeptr->pingTime = svs.time;
- s = Cmd_Argv( 2 );
- r = Cmd_Argv( 3 ); // reason
-
- if ( !Q_stricmp( s, "demo" ) ) {
- // they are a demo client trying to connect to a real server
- NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\nServer is not a demo server\n" );
- // clear the challenge record so it won't timeout and let them through
- Com_Memset( challengeptr, 0, sizeof( *challengeptr ) );
- return;
- }
- if ( !Q_stricmp( s, "accept" ) ) {
- NET_OutOfBandPrint(NS_SERVER, challengeptr->adr,
- "challengeResponse %d %d", challengeptr->challenge, challengeptr->clientChallenge);
- return;
- }
- if ( !Q_stricmp( s, "unknown" ) ) {
- if (!r) {
- NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\nAwaiting CD key authorization\n" );
- } else {
- NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\n%s\n", r);
- }
- // clear the challenge record so it won't timeout and let them through
- Com_Memset( challengeptr, 0, sizeof( *challengeptr ) );
- return;
- }
-
- // authorization failed
- if (!r) {
- NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\nSomeone is using this CD Key\n" );
- } else {
- NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\n%s\n", r );
- }
-
- // clear the challenge record so it won't timeout and let them through
- Com_Memset( challengeptr, 0, sizeof(*challengeptr) );
-}
-#endif
-
-/*
-==================
-SV_IsBanned
-
-Check whether a certain address is banned
-==================
-*/
-
-static qboolean SV_IsBanned(netadr_t *from, qboolean isexception)
-{
- int index;
- serverBan_t *curban;
-
- if(!isexception)
- {
- // If this is a query for a ban, first check whether the client is excepted
- if(SV_IsBanned(from, qtrue))
- return qfalse;
- }
-
- for(index = 0; index < serverBansCount; index++)
- {
- curban = &serverBans[index];
-
- if(curban->isexception == isexception)
- {
- if(NET_CompareBaseAdrMask(curban->ip, *from, curban->subnet))
- return qtrue;
- }
- }
-
- return qfalse;
-}
-
-/*
-==================
-SV_DirectConnect
-
-A "connect" OOB command has been received
-==================
-*/
-
-void SV_DirectConnect( netadr_t from ) {
- char userinfo[MAX_INFO_STRING];
- int i;
- client_t *cl, *newcl;
- client_t temp;
- sharedEntity_t *ent;
- int clientNum;
- int version;
- int qport;
- int challenge;
- char *password;
- int startIndex;
- intptr_t denied;
- int count;
- char *ip;
-
- Com_DPrintf ("SVC_DirectConnect ()\n");
-
- // Check whether this client is banned.
- if(SV_IsBanned(&from, qfalse))
- {
- NET_OutOfBandPrint(NS_SERVER, from, "print\nYou are banned from this server.\n");
- return;
- }
-
- Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) );
-
- version = atoi( Info_ValueForKey( userinfo, "protocol" ) );
- if ( version != PROTOCOL_VERSION ) {
- NET_OutOfBandPrint( NS_SERVER, from, "print\nServer uses protocol version %i.\n", PROTOCOL_VERSION );
- Com_DPrintf (" rejected connect from version %i\n", version);
- return;
- }
-
- challenge = atoi( Info_ValueForKey( userinfo, "challenge" ) );
- qport = atoi( Info_ValueForKey( userinfo, "qport" ) );
-
- // quick reject
- for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
- if ( cl->state == CS_FREE ) {
- continue;
- }
- if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress )
- && ( cl->netchan.qport == qport
- || from.port == cl->netchan.remoteAddress.port ) ) {
- if (( svs.time - cl->lastConnectTime)
- < (sv_reconnectlimit->integer * 1000)) {
- Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (from));
- return;
- }
- break;
- }
- }
-
- // don't let "ip" overflow userinfo string
- if ( NET_IsLocalAddress (from) )
- ip = "localhost";
- else
- ip = (char *)NET_AdrToString( from );
- if( ( strlen( ip ) + strlen( userinfo ) + 4 ) >= MAX_INFO_STRING ) {
- NET_OutOfBandPrint( NS_SERVER, from,
- "print\nUserinfo string length exceeded. "
- "Try removing setu cvars from your config.\n" );
- return;
- }
- Info_SetValueForKey( userinfo, "ip", ip );
-
- // see if the challenge is valid (LAN clients don't need to challenge)
- if (!NET_IsLocalAddress(from))
- {
- int ping;
- challenge_t *challengeptr;
-
- for (i=0; i<MAX_CHALLENGES; i++)
- {
- if (NET_CompareAdr(from, svs.challenges[i].adr))
- {
- if(challenge == svs.challenges[i].challenge)
- break;
- }
- }
-
- if (i == MAX_CHALLENGES)
- {
- NET_OutOfBandPrint( NS_SERVER, from, "print\nNo or bad challenge for your address.\n" );
- return;
- }
-
- challengeptr = &svs.challenges[i];
-
- if(challengeptr->wasrefused)
- {
- // Return silently, so that error messages written by the server keep being displayed.
- return;
- }
-
- ping = svs.time - challengeptr->pingTime;
-
- // never reject a LAN client based on ping
- if ( !Sys_IsLANAddress( from ) ) {
- if ( sv_minPing->value && ping < sv_minPing->value ) {
- NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for high pings only\n" );
- Com_DPrintf ("Client %i rejected on a too low ping\n", i);
- challengeptr->wasrefused = qtrue;
- return;
- }
- if ( sv_maxPing->value && ping > sv_maxPing->value ) {
- NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for low pings only\n" );
- Com_DPrintf ("Client %i rejected on a too high ping\n", i);
- challengeptr->wasrefused = qtrue;
- return;
- }
- }
-
- Com_Printf("Client %i connecting with %i challenge ping\n", i, ping);
- challengeptr->connected = qtrue;
- }
-
- newcl = &temp;
- Com_Memset (newcl, 0, sizeof(client_t));
-
- // if there is already a slot for this ip, reuse it
- for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
- if ( cl->state == CS_FREE ) {
- continue;
- }
- if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress )
- && ( cl->netchan.qport == qport
- || from.port == cl->netchan.remoteAddress.port ) ) {
- Com_Printf ("%s:reconnect\n", NET_AdrToString (from));
- newcl = cl;
-
- // this doesn't work because it nukes the players userinfo
-
-// // disconnect the client from the game first so any flags the
-// // player might have are dropped
-// VM_Call( gvm, GAME_CLIENT_DISCONNECT, newcl - svs.clients );
- //
- goto gotnewcl;
- }
- }
-
- // find a client slot
- // if "sv_privateClients" is set > 0, then that number
- // of client slots will be reserved for connections that
- // have "password" set to the value of "sv_privatePassword"
- // Info requests will report the maxclients as if the private
- // slots didn't exist, to prevent people from trying to connect
- // to a full server.
- // This is to allow us to reserve a couple slots here on our
- // servers so we can play without having to kick people.
-
- // check for privateClient password
- password = Info_ValueForKey( userinfo, "password" );
- if ( !strcmp( password, sv_privatePassword->string ) ) {
- startIndex = 0;
- } else {
- // skip past the reserved slots
- startIndex = sv_privateClients->integer;
- }
-
- newcl = NULL;
- for ( i = startIndex; i < sv_maxclients->integer ; i++ ) {
- cl = &svs.clients[i];
- if (cl->state == CS_FREE) {
- newcl = cl;
- break;
- }
- }
-
- if ( !newcl ) {
- if ( NET_IsLocalAddress( from ) ) {
- count = 0;
- for ( i = startIndex; i < sv_maxclients->integer ; i++ ) {
- cl = &svs.clients[i];
- if (cl->netchan.remoteAddress.type == NA_BOT) {
- count++;
- }
- }
- // if they're all bots
- if (count >= sv_maxclients->integer - startIndex) {
- SV_DropClient(&svs.clients[sv_maxclients->integer - 1], "only bots on server");
- newcl = &svs.clients[sv_maxclients->integer - 1];
- }
- else {
- Com_Error( ERR_FATAL, "server is full on local connect\n" );
- return;
- }
- }
- else {
- NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is full.\n" );
- Com_DPrintf ("Rejected a connection.\n");
- return;
- }
- }
-
- // we got a newcl, so reset the reliableSequence and reliableAcknowledge
- cl->reliableAcknowledge = 0;
- cl->reliableSequence = 0;
-
-gotnewcl:
- // build a new connection
- // accept the new client
- // this is the only place a client_t is ever initialized
- *newcl = temp;
- clientNum = newcl - svs.clients;
- ent = SV_GentityNum( clientNum );
- newcl->gentity = ent;
-
- // save the challenge
- newcl->challenge = challenge;
-
- // save the address
- Netchan_Setup (NS_SERVER, &newcl->netchan , from, qport);
- // init the netchan queue
- newcl->netchan_end_queue = &newcl->netchan_start_queue;
-
- // save the userinfo
- Q_strncpyz( newcl->userinfo, userinfo, sizeof(newcl->userinfo) );
-
- // get the game a chance to reject this connection or modify the userinfo
- denied = VM_Call( gvm, GAME_CLIENT_CONNECT, clientNum, qtrue, qfalse ); // firstTime = qtrue
- if ( denied ) {
- // we can't just use VM_ArgPtr, because that is only valid inside a VM_Call
- char *str = VM_ExplicitArgPtr( gvm, denied );
-
- NET_OutOfBandPrint( NS_SERVER, from, "print\n%s\n", str );
- Com_DPrintf ("Game rejected a connection: %s.\n", str);
- return;
- }
-
- SV_UserinfoChanged( newcl );
-
- // send the connect packet to the client
- NET_OutOfBandPrint( NS_SERVER, from, "connectResponse" );
-
- Com_DPrintf( "Going from CS_FREE to CS_CONNECTED for %s\n", newcl->name );
-
- newcl->state = CS_CONNECTED;
- newcl->nextSnapshotTime = svs.time;
- newcl->lastPacketTime = svs.time;
- newcl->lastConnectTime = svs.time;
-
- // when we receive the first packet from the client, we will
- // notice that it is from a different serverid and that the
- // gamestate message was not just sent, forcing a retransmit
- newcl->gamestateMessageNum = -1;
-
- // if this was the first client on the server, or the last client
- // the server can hold, send a heartbeat to the master.
- count = 0;
- for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
- if ( svs.clients[i].state >= CS_CONNECTED ) {
- count++;
- }
- }
- if ( count == 1 || count == sv_maxclients->integer ) {
- SV_Heartbeat_f();
- }
-}
-
-
-/*
-=====================
-SV_DropClient
-
-Called when the player is totally leaving the server, either willingly
-or unwillingly. This is NOT called if the entire server is quiting
-or crashing -- SV_FinalMessage() will handle that
-=====================
-*/
-void SV_DropClient( client_t *drop, const char *reason ) {
- int i;
- challenge_t *challenge;
- const qboolean isBot = drop->netchan.remoteAddress.type == NA_BOT;
-
- if ( drop->state == CS_ZOMBIE ) {
- return; // already dropped
- }
-
- if ( !isBot ) {
- // see if we already have a challenge for this ip
- challenge = &svs.challenges[0];
-
- for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++)
- {
- if(NET_CompareAdr(drop->netchan.remoteAddress, challenge->adr))
- {
- Com_Memset(challenge, 0, sizeof(*challenge));
- break;
- }
- }
- }
-
- // Kill any download
- SV_CloseDownload( drop );
-
- // tell everyone why they got dropped
- SV_SendServerCommand( NULL, "print \"%s" S_COLOR_WHITE " %s\n\"", drop->name, reason );
-
- if (drop->download) {
- FS_FCloseFile( drop->download );
- drop->download = 0;
- }
-
- // call the prog function for removing a client
- // this will remove the body, among other things
- VM_Call( gvm, GAME_CLIENT_DISCONNECT, drop - svs.clients );
-
- // add the disconnect command
- SV_SendServerCommand( drop, "disconnect \"%s\"", reason);
-
- if ( isBot ) {
- SV_BotFreeClient( drop - svs.clients );
- }
-
- // nuke user info
- SV_SetUserinfo( drop - svs.clients, "" );
-
- if ( isBot ) {
- // bots shouldn't go zombie, as there's no real net connection.
- drop->state = CS_FREE;
- } else {
- Com_DPrintf( "Going to CS_ZOMBIE for %s\n", drop->name );
- drop->state = CS_ZOMBIE; // become free in a few seconds
- }
-
- // if this was the last client on the server, send a heartbeat
- // to the master so it is known the server is empty
- // send a heartbeat now so the master will get up to date info
- // if there is already a slot for this ip, reuse it
- for (i=0 ; i < sv_maxclients->integer ; i++ ) {
- if ( svs.clients[i].state >= CS_CONNECTED ) {
- break;
- }
- }
- if ( i == sv_maxclients->integer ) {
- SV_Heartbeat_f();
- }
-}
-
-/*
-================
-SV_SendClientGameState
-
-Sends the first message from the server to a connected client.
-This will be sent on the initial connection and upon each new map load.
-
-It will be resent if the client acknowledges a later message but has
-the wrong gamestate.
-================
-*/
-static void SV_SendClientGameState( client_t *client ) {
- int start;
- entityState_t *base, nullstate;
- msg_t msg;
- byte msgBuffer[MAX_MSGLEN];
-
- Com_DPrintf ("SV_SendClientGameState() for %s\n", client->name);
- Com_DPrintf( "Going from CS_CONNECTED to CS_PRIMED for %s\n", client->name );
- client->state = CS_PRIMED;
- client->pureAuthentic = 0;
- client->gotCP = qfalse;
-
- // when we receive the first packet from the client, we will
- // notice that it is from a different serverid and that the
- // gamestate message was not just sent, forcing a retransmit
- client->gamestateMessageNum = client->netchan.outgoingSequence;
-
- MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) );
-
- // NOTE, MRE: all server->client messages now acknowledge
- // let the client know which reliable clientCommands we have received
- MSG_WriteLong( &msg, client->lastClientCommand );
-
- // send any server commands waiting to be sent first.
- // we have to do this cause we send the client->reliableSequence
- // with a gamestate and it sets the clc.serverCommandSequence at
- // the client side
- SV_UpdateServerCommandsToClient( client, &msg );
-
- // send the gamestate
- MSG_WriteByte( &msg, svc_gamestate );
- MSG_WriteLong( &msg, client->reliableSequence );
-
- // write the configstrings
- for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) {
- if (sv.configstrings[start][0]) {
- MSG_WriteByte( &msg, svc_configstring );
- MSG_WriteShort( &msg, start );
- MSG_WriteBigString( &msg, sv.configstrings[start] );
- }
- }
-
- // write the baselines
- Com_Memset( &nullstate, 0, sizeof( nullstate ) );
- for ( start = 0 ; start < MAX_GENTITIES; start++ ) {
- base = &sv.svEntities[start].baseline;
- if ( !base->number ) {
- continue;
- }
- MSG_WriteByte( &msg, svc_baseline );
- MSG_WriteDeltaEntity( &msg, &nullstate, base, qtrue );
- }
-
- MSG_WriteByte( &msg, svc_EOF );
-
- MSG_WriteLong( &msg, client - svs.clients);
-
- // write the checksum feed
- MSG_WriteLong( &msg, sv.checksumFeed);
-
- // deliver this to the client
- SV_SendMessageToClient( &msg, client );
-}
-
-
-/*
-==================
-SV_ClientEnterWorld
-==================
-*/
-void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) {
- int clientNum;
- sharedEntity_t *ent;
-
- Com_DPrintf( "Going from CS_PRIMED to CS_ACTIVE for %s\n", client->name );
- client->state = CS_ACTIVE;
-
- // resend all configstrings using the cs commands since these are
- // no longer sent when the client is CS_PRIMED
- SV_UpdateConfigstrings( client );
-
- // set up the entity for the client
- clientNum = client - svs.clients;
- ent = SV_GentityNum( clientNum );
- ent->s.number = clientNum;
- client->gentity = ent;
-
- client->deltaMessage = -1;
- client->nextSnapshotTime = svs.time; // generate a snapshot immediately
- client->lastUsercmd = *cmd;
-
- // call the game begin function
- VM_Call( gvm, GAME_CLIENT_BEGIN, client - svs.clients );
-}
-
-/*
-============================================================
-
-CLIENT COMMAND EXECUTION
-
-============================================================
-*/
-
-/*
-==================
-SV_CloseDownload
-
-clear/free any download vars
-==================
-*/
-static void SV_CloseDownload( client_t *cl ) {
- int i;
-
- // EOF
- if (cl->download) {
- FS_FCloseFile( cl->download );
- }
- cl->download = 0;
- *cl->downloadName = 0;
-
- // Free the temporary buffer space
- for (i = 0; i < MAX_DOWNLOAD_WINDOW; i++) {
- if (cl->downloadBlocks[i]) {
- Z_Free( cl->downloadBlocks[i] );
- cl->downloadBlocks[i] = NULL;
- }
- }
-
-}
-
-/*
-==================
-SV_StopDownload_f
-
-Abort a download if in progress
-==================
-*/
-static void SV_StopDownload_f( client_t *cl ) {
- if (*cl->downloadName)
- Com_DPrintf( "clientDownload: %d : file \"%s\" aborted\n", (int) (cl - svs.clients), cl->downloadName );
-
- SV_CloseDownload( cl );
-}
-
-/*
-==================
-SV_DoneDownload_f
-
-Downloads are finished
-==================
-*/
-static void SV_DoneDownload_f( client_t *cl ) {
- Com_DPrintf( "clientDownload: %s Done\n", cl->name);
- // resend the game state to update any clients that entered during the download
- SV_SendClientGameState(cl);
-}
-
-/*
-==================
-SV_NextDownload_f
-
-The argument will be the last acknowledged block from the client, it should be
-the same as cl->downloadClientBlock
-==================
-*/
-static void SV_NextDownload_f( client_t *cl )
-{
- int block = atoi( Cmd_Argv(1) );
-
- if (block == cl->downloadClientBlock) {
- Com_DPrintf( "clientDownload: %d : client acknowledge of block %d\n", (int) (cl - svs.clients), block );
-
- // Find out if we are done. A zero-length block indicates EOF
- if (cl->downloadBlockSize[cl->downloadClientBlock % MAX_DOWNLOAD_WINDOW] == 0) {
- Com_Printf( "clientDownload: %d : file \"%s\" completed\n", (int) (cl - svs.clients), cl->downloadName );
- SV_CloseDownload( cl );
- return;
- }
-
- cl->downloadSendTime = svs.time;
- cl->downloadClientBlock++;
- return;
- }
- // We aren't getting an acknowledge for the correct block, drop the client
- // FIXME: this is bad... the client will never parse the disconnect message
- // because the cgame isn't loaded yet
- SV_DropClient( cl, "broken download" );
-}
-
-/*
-==================
-SV_BeginDownload_f
-==================
-*/
-static void SV_BeginDownload_f( client_t *cl ) {
-
- // Kill any existing download
- SV_CloseDownload( cl );
-
- // cl->downloadName is non-zero now, SV_WriteDownloadToClient will see this and open
- // the file itself
- Q_strncpyz( cl->downloadName, Cmd_Argv(1), sizeof(cl->downloadName) );
-}
-
-/*
-==================
-SV_WriteDownloadToClient
-
-Check to see if the client wants a file, open it if needed and start pumping the client
-Fill up msg with data
-==================
-*/
-void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
-{
- int curindex;
- int rate;
- int blockspersnap;
- int idPack = 0, missionPack = 0, unreferenced = 1;
- char errorMessage[1024];
- char pakbuf[MAX_QPATH], *pakptr;
- int numRefPaks;
-
- if (!*cl->downloadName)
- return; // Nothing being downloaded
-
- if (!cl->download) {
- // Chop off filename extension.
- Com_sprintf(pakbuf, sizeof(pakbuf), "%s", cl->downloadName);
- pakptr = Q_strrchr(pakbuf, '.');
-
- if(pakptr)
- {
- *pakptr = '\0';
-
- // Check for pk3 filename extension
- if(!Q_stricmp(pakptr + 1, "pk3"))
- {
- const char *referencedPaks = FS_ReferencedPakNames();
-
- // Check whether the file appears in the list of referenced
- // paks to prevent downloading of arbitrary files.
- Cmd_TokenizeStringIgnoreQuotes(referencedPaks);
- numRefPaks = Cmd_Argc();
-
- for(curindex = 0; curindex < numRefPaks; curindex++)
- {
- if(!FS_FilenameCompare(Cmd_Argv(curindex), pakbuf))
- {
- unreferenced = 0;
-
- // now that we know the file is referenced,
- // check whether it's legal to download it.
- missionPack = FS_idPak(pakbuf, "missionpack");
- idPack = missionPack || FS_idPak(pakbuf, BASEGAME);
-
- break;
- }
- }
- }
- }
-
- cl->download = 0;
-
- // We open the file here
- if ( !(sv_allowDownload->integer & DLF_ENABLE) ||
- (sv_allowDownload->integer & DLF_NO_UDP) ||
- idPack || unreferenced ||
- ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) < 0 ) {
- // cannot auto-download file
- if(unreferenced)
- {
- Com_Printf("clientDownload: %d : \"%s\" is not referenced and cannot be downloaded.\n", (int) (cl - svs.clients), cl->downloadName);
- Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" is not referenced and cannot be downloaded.", cl->downloadName);
- }
- else if (idPack) {
- Com_Printf("clientDownload: %d : \"%s\" cannot download id pk3 files\n", (int) (cl - svs.clients), cl->downloadName);
- if (missionPack) {
- Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload Team Arena file \"%s\"\n"
- "The Team Arena mission pack can be found in your local game store.", cl->downloadName);
- }
- else {
- Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload id pk3 file \"%s\"", cl->downloadName);
- }
- }
- else if ( !(sv_allowDownload->integer & DLF_ENABLE) ||
- (sv_allowDownload->integer & DLF_NO_UDP) ) {
-
- Com_Printf("clientDownload: %d : \"%s\" download disabled", (int) (cl - svs.clients), cl->downloadName);
- if (sv_pure->integer) {
- Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n"
- "You will need to get this file elsewhere before you "
- "can connect to this pure server.\n", cl->downloadName);
- } else {
- Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n"
- "The server you are connecting to is not a pure server, "
- "set autodownload to No in your settings and you might be "
- "able to join the game anyway.\n", cl->downloadName);
- }
- } else {
- // NOTE TTimo this is NOT supposed to happen unless bug in our filesystem scheme?
- // if the pk3 is referenced, it must have been found somewhere in the filesystem
- Com_Printf("clientDownload: %d : \"%s\" file not found on server\n", (int) (cl - svs.clients), cl->downloadName);
- Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" not found on server for autodownloading.\n", cl->downloadName);
- }
- MSG_WriteByte( msg, svc_download );
- MSG_WriteShort( msg, 0 ); // client is expecting block zero
- MSG_WriteLong( msg, -1 ); // illegal file size
- MSG_WriteString( msg, errorMessage );
-
- *cl->downloadName = 0;
-
- if(cl->download)
- FS_FCloseFile(cl->download);
-
- return;
- }
-
- Com_Printf( "clientDownload: %d : beginning \"%s\"\n", (int) (cl - svs.clients), cl->downloadName );
-
- // Init
- cl->downloadCurrentBlock = cl->downloadClientBlock = cl->downloadXmitBlock = 0;
- cl->downloadCount = 0;
- cl->downloadEOF = qfalse;
- }
-
- // Perform any reads that we need to
- while (cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW &&
- cl->downloadSize != cl->downloadCount) {
-
- curindex = (cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW);
-
- if (!cl->downloadBlocks[curindex])
- cl->downloadBlocks[curindex] = Z_Malloc( MAX_DOWNLOAD_BLKSIZE );
-
- cl->downloadBlockSize[curindex] = FS_Read( cl->downloadBlocks[curindex], MAX_DOWNLOAD_BLKSIZE, cl->download );
-
- if (cl->downloadBlockSize[curindex] < 0) {
- // EOF right now
- cl->downloadCount = cl->downloadSize;
- break;
- }
-
- cl->downloadCount += cl->downloadBlockSize[curindex];
-
- // Load in next block
- cl->downloadCurrentBlock++;
- }
-
- // Check to see if we have eof condition and add the EOF block
- if (cl->downloadCount == cl->downloadSize &&
- !cl->downloadEOF &&
- cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW) {
-
- cl->downloadBlockSize[cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW] = 0;
- cl->downloadCurrentBlock++;
-
- cl->downloadEOF = qtrue; // We have added the EOF block
- }
-
- // Loop up to window size times based on how many blocks we can fit in the
- // client snapMsec and rate
-
- // based on the rate, how many bytes can we fit in the snapMsec time of the client
- // normal rate / snapshotMsec calculation
- rate = cl->rate;
- if ( sv_maxRate->integer ) {
- if ( sv_maxRate->integer < 1000 ) {
- Cvar_Set( "sv_MaxRate", "1000" );
- }
- if ( sv_maxRate->integer < rate ) {
- rate = sv_maxRate->integer;
- }
- }
- if ( sv_minRate->integer ) {
- if ( sv_minRate->integer < 1000 )
- Cvar_Set( "sv_minRate", "1000" );
- if ( sv_minRate->integer > rate )
- rate = sv_minRate->integer;
- }
-
- if (!rate) {
- blockspersnap = 1;
- } else {
- blockspersnap = ( (rate * cl->snapshotMsec) / 1000 + MAX_DOWNLOAD_BLKSIZE ) /
- MAX_DOWNLOAD_BLKSIZE;
- }
-
- if (blockspersnap < 0)
- blockspersnap = 1;
-
- while (blockspersnap--) {
-
- // Write out the next section of the file, if we have already reached our window,
- // automatically start retransmitting
-
- if (cl->downloadClientBlock == cl->downloadCurrentBlock)
- return; // Nothing to transmit
-
- if (cl->downloadXmitBlock == cl->downloadCurrentBlock) {
- // We have transmitted the complete window, should we start resending?
-
- //FIXME: This uses a hardcoded one second timeout for lost blocks
- //the timeout should be based on client rate somehow
- if (svs.time - cl->downloadSendTime > 1000)
- cl->downloadXmitBlock = cl->downloadClientBlock;
- else
- return;
- }
-
- // Send current block
- curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW);
-
- MSG_WriteByte( msg, svc_download );
- MSG_WriteShort( msg, cl->downloadXmitBlock );
-
- // block zero is special, contains file size
- if ( cl->downloadXmitBlock == 0 )
- MSG_WriteLong( msg, cl->downloadSize );
-
- MSG_WriteShort( msg, cl->downloadBlockSize[curindex] );
-
- // Write the block
- if ( cl->downloadBlockSize[curindex] ) {
- MSG_WriteData( msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex] );
- }
-
- Com_DPrintf( "clientDownload: %d : writing block %d\n", (int) (cl - svs.clients), cl->downloadXmitBlock );
-
- // Move on to the next block
- // It will get sent with next snap shot. The rate will keep us in line.
- cl->downloadXmitBlock++;
-
- cl->downloadSendTime = svs.time;
- }
-}
-
-#ifdef USE_VOIP
-/*
-==================
-SV_WriteVoipToClient
-
-Check to see if there is any VoIP queued for a client, and send if there is.
-==================
-*/
-void SV_WriteVoipToClient( client_t *cl, msg_t *msg )
-{
- voipServerPacket_t *packet = &cl->voipPacket[0];
- int totalbytes = 0;
- int i;
-
- if (*cl->downloadName) {
- cl->queuedVoipPackets = 0;
- return; // no VoIP allowed if download is going, to save bandwidth.
- }
-
- // Write as many VoIP packets as we reasonably can...
- for (i = 0; i < cl->queuedVoipPackets; i++, packet++) {
- totalbytes += packet->len;
- if (totalbytes > MAX_DOWNLOAD_BLKSIZE)
- break;
-
- // You have to start with a svc_EOF, so legacy clients drop the
- // rest of this packet. Otherwise, those without VoIP support will
- // see the svc_voip command, then panic and disconnect.
- // Generally we don't send VoIP packets to legacy clients, but this
- // serves as both a safety measure and a means to keep demo files
- // compatible.
- MSG_WriteByte( msg, svc_EOF );
- MSG_WriteByte( msg, svc_extension );
- MSG_WriteByte( msg, svc_voip );
- MSG_WriteShort( msg, packet->sender );
- MSG_WriteByte( msg, (byte) packet->generation );
- MSG_WriteLong( msg, packet->sequence );
- MSG_WriteByte( msg, packet->frames );
- MSG_WriteShort( msg, packet->len );
- MSG_WriteData( msg, packet->data, packet->len );
- }
-
- // !!! FIXME: I hate this queue system.
- cl->queuedVoipPackets -= i;
- if (cl->queuedVoipPackets > 0) {
- memmove( &cl->voipPacket[0], &cl->voipPacket[i],
- sizeof (voipServerPacket_t) * i);
- }
-}
-#endif
-
-
-/*
-=================
-SV_Disconnect_f
-
-The client is going to disconnect, so remove the connection immediately FIXME: move to game?
-=================
-*/
-static void SV_Disconnect_f( client_t *cl ) {
- SV_DropClient( cl, "disconnected" );
-}
-
-/*
-=================
-SV_VerifyPaks_f
-
-If we are pure, disconnect the client if they do no meet the following conditions:
-
-1. the first two checksums match our view of cgame and ui
-2. there are no any additional checksums that we do not have
-
-This routine would be a bit simpler with a goto but i abstained
-
-=================
-*/
-static void SV_VerifyPaks_f( client_t *cl ) {
- int nChkSum1, nChkSum2, nClientPaks, nServerPaks, i, j, nCurArg;
- int nClientChkSum[1024];
- int nServerChkSum[1024];
- const char *pPaks, *pArg;
- qboolean bGood = qtrue;
-
- // if we are pure, we "expect" the client to load certain things from
- // certain pk3 files, namely we want the client to have loaded the
- // ui and cgame that we think should be loaded based on the pure setting
- //
- if ( sv_pure->integer != 0 ) {
-
- bGood = qtrue;
- nChkSum1 = nChkSum2 = 0;
- // we run the game, so determine which cgame and ui the client "should" be running
- bGood = (FS_FileIsInPAK("vm/cgame.qvm", &nChkSum1) == 1);
- if (bGood)
- bGood = (FS_FileIsInPAK("vm/ui.qvm", &nChkSum2) == 1);
-
- nClientPaks = Cmd_Argc();
-
- // start at arg 2 ( skip serverId cl_paks )
- nCurArg = 1;
-
- pArg = Cmd_Argv(nCurArg++);
- if(!pArg) {
- bGood = qfalse;
- }
- else
- {
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
- // we may get incoming cp sequences from a previous checksumFeed, which we need to ignore
- // since serverId is a frame count, it always goes up
- if (atoi(pArg) < sv.checksumFeedServerId)
- {
- Com_DPrintf("ignoring outdated cp command from client %s\n", cl->name);
- return;
- }
- }
-
- // we basically use this while loop to avoid using 'goto' :)
- while (bGood) {
-
- // must be at least 6: "cl_paks cgame ui @ firstref ... numChecksums"
- // numChecksums is encoded
- if (nClientPaks < 6) {
- bGood = qfalse;
- break;
- }
- // verify first to be the cgame checksum
- pArg = Cmd_Argv(nCurArg++);
- if (!pArg || *pArg == '@' || atoi(pArg) != nChkSum1 ) {
- bGood = qfalse;
- break;
- }
- // verify the second to be the ui checksum
- pArg = Cmd_Argv(nCurArg++);
- if (!pArg || *pArg == '@' || atoi(pArg) != nChkSum2 ) {
- bGood = qfalse;
- break;
- }
- // should be sitting at the delimeter now
- pArg = Cmd_Argv(nCurArg++);
- if (*pArg != '@') {
- bGood = qfalse;
- break;
- }
- // store checksums since tokenization is not re-entrant
- for (i = 0; nCurArg < nClientPaks; i++) {
- nClientChkSum[i] = atoi(Cmd_Argv(nCurArg++));
- }
-
- // store number to compare against (minus one cause the last is the number of checksums)
- nClientPaks = i - 1;
-
- // make sure none of the client check sums are the same
- // so the client can't send 5 the same checksums
- for (i = 0; i < nClientPaks; i++) {
- for (j = 0; j < nClientPaks; j++) {
- if (i == j)
- continue;
- if (nClientChkSum[i] == nClientChkSum[j]) {
- bGood = qfalse;
- break;
- }
- }
- if (bGood == qfalse)
- break;
- }
- if (bGood == qfalse)
- break;
-
- // get the pure checksums of the pk3 files loaded by the server
- pPaks = FS_LoadedPakPureChecksums();
- Cmd_TokenizeString( pPaks );
- nServerPaks = Cmd_Argc();
- if (nServerPaks > 1024)
- nServerPaks = 1024;
-
- for (i = 0; i < nServerPaks; i++) {
- nServerChkSum[i] = atoi(Cmd_Argv(i));
- }
-
- // check if the client has provided any pure checksums of pk3 files not loaded by the server
- for (i = 0; i < nClientPaks; i++) {
- for (j = 0; j < nServerPaks; j++) {
- if (nClientChkSum[i] == nServerChkSum[j]) {
- break;
- }
- }
- if (j >= nServerPaks) {
- bGood = qfalse;
- break;
- }
- }
- if ( bGood == qfalse ) {
- break;
- }
-
- // check if the number of checksums was correct
- nChkSum1 = sv.checksumFeed;
- for (i = 0; i < nClientPaks; i++) {
- nChkSum1 ^= nClientChkSum[i];
- }
- nChkSum1 ^= nClientPaks;
- if (nChkSum1 != nClientChkSum[nClientPaks]) {
- bGood = qfalse;
- break;
- }
-
- // break out
- break;
- }
-
- cl->gotCP = qtrue;
-
- if (bGood) {
- cl->pureAuthentic = 1;
- }
- else {
- cl->pureAuthentic = 0;
- cl->nextSnapshotTime = -1;
- cl->state = CS_ACTIVE;
- SV_SendClientSnapshot( cl );
- SV_DropClient( cl, "Unpure client detected. Invalid .PK3 files referenced!" );
- }
- }
-}
-
-/*
-=================
-SV_ResetPureClient_f
-=================
-*/
-static void SV_ResetPureClient_f( client_t *cl ) {
- cl->pureAuthentic = 0;
- cl->gotCP = qfalse;
-}
-
-/*
-=================
-SV_UserinfoChanged
-
-Pull specific info from a newly changed userinfo string
-into a more C friendly form.
-=================
-*/
-void SV_UserinfoChanged( client_t *cl ) {
- char *val;
- char *ip;
- int i;
- int len;
-
- // name for C code
- Q_strncpyz( cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name) );
-
- // rate command
-
- // if the client is on the same subnet as the server and we aren't running an
- // internet public server, assume they don't need a rate choke
- if ( Sys_IsLANAddress( cl->netchan.remoteAddress ) && com_dedicated->integer != 2 && sv_lanForceRate->integer == 1) {
- cl->rate = 99999; // lans should not rate limit
- } else {
- val = Info_ValueForKey (cl->userinfo, "rate");
- if (strlen(val)) {
- i = atoi(val);
- cl->rate = i;
- if (cl->rate < 1000) {
- cl->rate = 1000;
- } else if (cl->rate > 90000) {
- cl->rate = 90000;
- }
- } else {
- cl->rate = 3000;
- }
- }
- val = Info_ValueForKey (cl->userinfo, "handicap");
- if (strlen(val)) {
- i = atoi(val);
- if (i<=0 || i>100 || strlen(val) > 4) {
- Info_SetValueForKey( cl->userinfo, "handicap", "100" );
- }
- }
-
- // snaps command
- val = Info_ValueForKey (cl->userinfo, "snaps");
- if (strlen(val)) {
- i = atoi(val);
- if ( i < 1 ) {
- i = 1;
- } else if ( i > sv_fps->integer ) {
- i = sv_fps->integer;
- }
- cl->snapshotMsec = 1000/i;
- } else {
- cl->snapshotMsec = 50;
- }
-
-#ifdef USE_VOIP
- // in the future, (val) will be a protocol version string, so only
- // accept explicitly 1, not generally non-zero.
- val = Info_ValueForKey (cl->userinfo, "cl_voip");
- cl->hasVoip = (atoi(val) == 1) ? qtrue : qfalse;
-#endif
-
- // TTimo
- // maintain the IP information
- // the banning code relies on this being consistently present
- if( NET_IsLocalAddress(cl->netchan.remoteAddress) )
- ip = "localhost";
- else
- ip = (char*)NET_AdrToString( cl->netchan.remoteAddress );
-
- val = Info_ValueForKey( cl->userinfo, "ip" );
- if( val[0] )
- len = strlen( ip ) - strlen( val ) + strlen( cl->userinfo );
- else
- len = strlen( ip ) + 4 + strlen( cl->userinfo );
-
- if( len >= MAX_INFO_STRING )
- SV_DropClient( cl, "userinfo string length exceeded" );
- else
- Info_SetValueForKey( cl->userinfo, "ip", ip );
-
-}
-
-
-/*
-==================
-SV_UpdateUserinfo_f
-==================
-*/
-static void SV_UpdateUserinfo_f( client_t *cl ) {
- Q_strncpyz( cl->userinfo, Cmd_Argv(1), sizeof(cl->userinfo) );
-
- SV_UserinfoChanged( cl );
- // call prog code to allow overrides
- VM_Call( gvm, GAME_CLIENT_USERINFO_CHANGED, cl - svs.clients );
-}
-
-
-#ifdef USE_VOIP
-static
-void SV_UpdateVoipIgnore(client_t *cl, const char *idstr, qboolean ignore)
-{
- if ((*idstr >= '0') && (*idstr <= '9')) {
- const int id = atoi(idstr);
- if ((id >= 0) && (id < MAX_CLIENTS)) {
- cl->ignoreVoipFromClient[id] = ignore;
- }
- }
-}
-
-/*
-==================
-SV_Voip_f
-==================
-*/
-static void SV_Voip_f( client_t *cl ) {
- const char *cmd = Cmd_Argv(1);
- if (strcmp(cmd, "ignore") == 0) {
- SV_UpdateVoipIgnore(cl, Cmd_Argv(2), qtrue);
- } else if (strcmp(cmd, "unignore") == 0) {
- SV_UpdateVoipIgnore(cl, Cmd_Argv(2), qfalse);
- } else if (strcmp(cmd, "muteall") == 0) {
- cl->muteAllVoip = qtrue;
- } else if (strcmp(cmd, "unmuteall") == 0) {
- cl->muteAllVoip = qfalse;
- }
-}
-#endif
-
-
-typedef struct {
- char *name;
- void (*func)( client_t *cl );
-} ucmd_t;
-
-static ucmd_t ucmds[] = {
- {"userinfo", SV_UpdateUserinfo_f},
- {"disconnect", SV_Disconnect_f},
- {"cp", SV_VerifyPaks_f},
- {"vdr", SV_ResetPureClient_f},
- {"download", SV_BeginDownload_f},
- {"nextdl", SV_NextDownload_f},
- {"stopdl", SV_StopDownload_f},
- {"donedl", SV_DoneDownload_f},
-
-#ifdef USE_VOIP
- {"voip", SV_Voip_f},
-#endif
-
- {NULL, NULL}
-};
-
-/*
-==================
-SV_ExecuteClientCommand
-
-Also called by bot code
-==================
-*/
-void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK ) {
- ucmd_t *u;
- qboolean bProcessed = qfalse;
-
- Cmd_TokenizeString( s );
-
- // see if it is a server level command
- for (u=ucmds ; u->name ; u++) {
- if (!strcmp (Cmd_Argv(0), u->name) ) {
- u->func( cl );
- bProcessed = qtrue;
- break;
- }
- }
-
- if (clientOK) {
- // pass unknown strings to the game
- if (!u->name && sv.state == SS_GAME) {
- Cmd_Args_Sanitize();
- VM_Call( gvm, GAME_CLIENT_COMMAND, cl - svs.clients );
- }
- }
- else if (!bProcessed)
- Com_DPrintf( "client text ignored for %s: %s\n", cl->name, Cmd_Argv(0) );
-}
-
-/*
-===============
-SV_ClientCommand
-===============
-*/
-static qboolean SV_ClientCommand( client_t *cl, msg_t *msg ) {
- int seq;
- const char *s;
- qboolean clientOk = qtrue;
-
- seq = MSG_ReadLong( msg );
- s = MSG_ReadString( msg );
-
- // see if we have already executed it
- if ( cl->lastClientCommand >= seq ) {
- return qtrue;
- }
-
- Com_DPrintf( "clientCommand: %s : %i : %s\n", cl->name, seq, s );
-
- // drop the connection if we have somehow lost commands
- if ( seq > cl->lastClientCommand + 1 ) {
- Com_Printf( "Client %s lost %i clientCommands\n", cl->name,
- seq - cl->lastClientCommand + 1 );
- SV_DropClient( cl, "Lost reliable commands" );
- return qfalse;
- }
-
- // malicious users may try using too many string commands
- // to lag other players. If we decide that we want to stall
- // the command, we will stop processing the rest of the packet,
- // including the usercmd. This causes flooders to lag themselves
- // but not other people
- // We don't do this when the client hasn't been active yet since its
- // normal to spam a lot of commands when downloading
- if ( !com_cl_running->integer &&
- cl->state >= CS_ACTIVE &&
- sv_floodProtect->integer &&
- svs.time < cl->nextReliableTime ) {
- // ignore any other text messages from this client but let them keep playing
- // TTimo - moved the ignored verbose to the actual processing in SV_ExecuteClientCommand, only printing if the core doesn't intercept
- clientOk = qfalse;
- }
-
- // don't allow another command for one second
- cl->nextReliableTime = svs.time + 1000;
-
- SV_ExecuteClientCommand( cl, s, clientOk );
-
- cl->lastClientCommand = seq;
- Com_sprintf(cl->lastClientCommandString, sizeof(cl->lastClientCommandString), "%s", s);
-
- return qtrue; // continue procesing
-}
-
-
-//==================================================================================
-
-
-/*
-==================
-SV_ClientThink
-
-Also called by bot code
-==================
-*/
-void SV_ClientThink (client_t *cl, usercmd_t *cmd) {
- cl->lastUsercmd = *cmd;
-
- if ( cl->state != CS_ACTIVE ) {
- return; // may have been kicked during the last usercmd
- }
-
- VM_Call( gvm, GAME_CLIENT_THINK, cl - svs.clients );
-}
-
-/*
-==================
-SV_UserMove
-
-The message usually contains all the movement commands
-that were in the last three packets, so that the information
-in dropped packets can be recovered.
-
-On very fast clients, there may be multiple usercmd packed into
-each of the backup packets.
-==================
-*/
-static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) {
- int i, key;
- int cmdCount;
- usercmd_t nullcmd;
- usercmd_t cmds[MAX_PACKET_USERCMDS];
- usercmd_t *cmd, *oldcmd;
-
- if ( delta ) {
- cl->deltaMessage = cl->messageAcknowledge;
- } else {
- cl->deltaMessage = -1;
- }
-
- cmdCount = MSG_ReadByte( msg );
-
- if ( cmdCount < 1 ) {
- Com_Printf( "cmdCount < 1\n" );
- return;
- }
-
- if ( cmdCount > MAX_PACKET_USERCMDS ) {
- Com_Printf( "cmdCount > MAX_PACKET_USERCMDS\n" );
- return;
- }
-
- // use the checksum feed in the key
- key = sv.checksumFeed;
- // also use the message acknowledge
- key ^= cl->messageAcknowledge;
- // also use the last acknowledged server command in the key
- key ^= MSG_HashKey(cl->reliableCommands[ cl->reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ], 32);
-
- Com_Memset( &nullcmd, 0, sizeof(nullcmd) );
- oldcmd = &nullcmd;
- for ( i = 0 ; i < cmdCount ; i++ ) {
- cmd = &cmds[i];
- MSG_ReadDeltaUsercmdKey( msg, key, oldcmd, cmd );
- oldcmd = cmd;
- }
-
- // save time for ping calculation
- cl->frames[ cl->messageAcknowledge & PACKET_MASK ].messageAcked = svs.time;
-
- // TTimo
- // catch the no-cp-yet situation before SV_ClientEnterWorld
- // if CS_ACTIVE, then it's time to trigger a new gamestate emission
- // if not, then we are getting remaining parasite usermove commands, which we should ignore
- if (sv_pure->integer != 0 && cl->pureAuthentic == 0 && !cl->gotCP) {
- if (cl->state == CS_ACTIVE)
- {
- // we didn't get a cp yet, don't assume anything and just send the gamestate all over again
- Com_DPrintf( "%s: didn't get cp command, resending gamestate\n", cl->name);
- SV_SendClientGameState( cl );
- }
- return;
- }
-
- // if this is the first usercmd we have received
- // this gamestate, put the client into the world
- if ( cl->state == CS_PRIMED ) {
- SV_ClientEnterWorld( cl, &cmds[0] );
- // the moves can be processed normaly
- }
-
- // a bad cp command was sent, drop the client
- if (sv_pure->integer != 0 && cl->pureAuthentic == 0) {
- SV_DropClient( cl, "Cannot validate pure client!");
- return;
- }
-
- if ( cl->state != CS_ACTIVE ) {
- cl->deltaMessage = -1;
- return;
- }
-
- // usually, the first couple commands will be duplicates
- // of ones we have previously received, but the servertimes
- // in the commands will cause them to be immediately discarded
- for ( i = 0 ; i < cmdCount ; i++ ) {
- // if this is a cmd from before a map_restart ignore it
- if ( cmds[i].serverTime > cmds[cmdCount-1].serverTime ) {
- continue;
- }
- // extremely lagged or cmd from before a map_restart
- //if ( cmds[i].serverTime > svs.time + 3000 ) {
- // continue;
- //}
- // don't execute if this is an old cmd which is already executed
- // these old cmds are included when cl_packetdup > 0
- if ( cmds[i].serverTime <= cl->lastUsercmd.serverTime ) {
- continue;
- }
- SV_ClientThink (cl, &cmds[ i ]);
- }
-}
-
-
-#ifdef USE_VOIP
-static
-qboolean SV_ShouldIgnoreVoipSender(const client_t *cl)
-{
- if (!sv_voip->integer)
- return qtrue; // VoIP disabled on this server.
- else if (!cl->hasVoip) // client doesn't have VoIP support?!
- return qtrue;
-
- // !!! FIXME: implement player blacklist.
-
- return qfalse; // don't ignore.
-}
-
-static
-void SV_UserVoip( client_t *cl, msg_t *msg ) {
- const int sender = (int) (cl - svs.clients);
- const int generation = MSG_ReadByte(msg);
- const int sequence = MSG_ReadLong(msg);
- const int frames = MSG_ReadByte(msg);
- const int recip1 = MSG_ReadLong(msg);
- const int recip2 = MSG_ReadLong(msg);
- const int recip3 = MSG_ReadLong(msg);
- const int packetsize = MSG_ReadShort(msg);
- byte encoded[sizeof (cl->voipPacket[0].data)];
- client_t *client = NULL;
- voipServerPacket_t *packet = NULL;
- int i;
-
- if (generation < 0)
- return; // short/invalid packet, bail.
- else if (sequence < 0)
- return; // short/invalid packet, bail.
- else if (frames < 0)
- return; // short/invalid packet, bail.
- else if (recip1 < 0)
- return; // short/invalid packet, bail.
- else if (recip2 < 0)
- return; // short/invalid packet, bail.
- else if (recip3 < 0)
- return; // short/invalid packet, bail.
- else if (packetsize < 0)
- return; // short/invalid packet, bail.
-
- if (packetsize > sizeof (encoded)) { // overlarge packet?
- int bytesleft = packetsize;
- while (bytesleft) {
- int br = bytesleft;
- if (br > sizeof (encoded))
- br = sizeof (encoded);
- MSG_ReadData(msg, encoded, br);
- bytesleft -= br;
- }
- return; // overlarge packet, bail.
- }
-
- MSG_ReadData(msg, encoded, packetsize);
-
- if (SV_ShouldIgnoreVoipSender(cl))
- return; // Blacklisted, disabled, etc.
-
- // !!! FIXME: see if we read past end of msg...
-
- // !!! FIXME: reject if not speex narrowband codec.
- // !!! FIXME: decide if this is bogus data?
-
- // (the three recip* values are 31 bits each (ignores sign bit so we can
- // get a -1 error from MSG_ReadLong() ... ), allowing for 93 clients.)
- assert( sv_maxclients->integer < 93 );
-
- // decide who needs this VoIP packet sent to them...
- for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) {
- if (client->state != CS_ACTIVE)
- continue; // not in the game yet, don't send to this guy.
- else if (i == sender)
- continue; // don't send voice packet back to original author.
- else if (!client->hasVoip)
- continue; // no VoIP support, or support disabled.
- else if (client->muteAllVoip)
- continue; // client is ignoring everyone.
- else if (client->ignoreVoipFromClient[sender])
- continue; // client is ignoring this talker.
- else if (*cl->downloadName) // !!! FIXME: possible to DoS?
- continue; // no VoIP allowed if downloading, to save bandwidth.
- else if ( ((i >= 0) && (i < 31)) && ((recip1 & (1 << (i-0))) == 0) )
- continue; // not addressed to this player.
- else if ( ((i >= 31) && (i < 62)) && ((recip2 & (1 << (i-31))) == 0) )
- continue; // not addressed to this player.
- else if ( ((i >= 62) && (i < 93)) && ((recip3 & (1 << (i-62))) == 0) )
- continue; // not addressed to this player.
-
- // Transmit this packet to the client.
- // !!! FIXME: I don't like this queueing system.
- if (client->queuedVoipPackets >= (sizeof (client->voipPacket) / sizeof (client->voipPacket[0]))) {
- Com_Printf("Too many VoIP packets queued for client #%d\n", i);
- continue; // no room for another packet right now.
- }
-
- packet = &client->voipPacket[client->queuedVoipPackets];
- packet->sender = sender;
- packet->frames = frames;
- packet->len = packetsize;
- packet->generation = generation;
- packet->sequence = sequence;
- memcpy(packet->data, encoded, packetsize);
- client->queuedVoipPackets++;
- }
-}
-#endif
-
-
-
-/*
-===========================================================================
-
-USER CMD EXECUTION
-
-===========================================================================
-*/
-
-/*
-===================
-SV_ExecuteClientMessage
-
-Parse a client packet
-===================
-*/
-void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
- int c;
- int serverId;
-
- MSG_Bitstream(msg);
-
- serverId = MSG_ReadLong( msg );
- cl->messageAcknowledge = MSG_ReadLong( msg );
-
- if (cl->messageAcknowledge < 0) {
- // usually only hackers create messages like this
- // it is more annoying for them to let them hanging
-#ifndef NDEBUG
- SV_DropClient( cl, "DEBUG: illegible client message" );
-#endif
- return;
- }
-
- cl->reliableAcknowledge = MSG_ReadLong( msg );
-
- // NOTE: when the client message is fux0red the acknowledgement numbers
- // can be out of range, this could cause the server to send thousands of server
- // commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient
- if (cl->reliableAcknowledge < cl->reliableSequence - MAX_RELIABLE_COMMANDS) {
- // usually only hackers create messages like this
- // it is more annoying for them to let them hanging
-#ifndef NDEBUG
- SV_DropClient( cl, "DEBUG: illegible client message" );
-#endif
- cl->reliableAcknowledge = cl->reliableSequence;
- return;
- }
- // if this is a usercmd from a previous gamestate,
- // ignore it or retransmit the current gamestate
- //
- // if the client was downloading, let it stay at whatever serverId and
- // gamestate it was at. This allows it to keep downloading even when
- // the gamestate changes. After the download is finished, we'll
- // notice and send it a new game state
- //
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=536
- // don't drop as long as previous command was a nextdl, after a dl is done, downloadName is set back to ""
- // but we still need to read the next message to move to next download or send gamestate
- // I don't like this hack though, it must have been working fine at some point, suspecting the fix is somewhere else
- if ( serverId != sv.serverId && !*cl->downloadName && !strstr(cl->lastClientCommandString, "nextdl") ) {
- if ( serverId >= sv.restartedServerId && serverId < sv.serverId ) { // TTimo - use a comparison here to catch multiple map_restart
- // they just haven't caught the map_restart yet
- Com_DPrintf("%s : ignoring pre map_restart / outdated client message\n", cl->name);
- return;
- }
- // if we can tell that the client has dropped the last
- // gamestate we sent them, resend it
- if ( cl->messageAcknowledge > cl->gamestateMessageNum ) {
- Com_DPrintf( "%s : dropped gamestate, resending\n", cl->name );
- SV_SendClientGameState( cl );
- }
- return;
- }
-
- // this client has acknowledged the new gamestate so it's
- // safe to start sending it the real time again
- if( cl->oldServerTime && serverId == sv.serverId ){
- Com_DPrintf( "%s acknowledged gamestate\n", cl->name );
- cl->oldServerTime = 0;
- }
-
- // read optional clientCommand strings
- do {
- c = MSG_ReadByte( msg );
-
- // See if this is an extension command after the EOF, which means we
- // got data that a legacy server should ignore.
- if ((c == clc_EOF) && (MSG_LookaheadByte( msg ) == clc_extension)) {
- MSG_ReadByte( msg ); // throw the clc_extension byte away.
- c = MSG_ReadByte( msg ); // something legacy servers can't do!
- // sometimes you get a clc_extension at end of stream...dangling
- // bits in the huffman decoder giving a bogus value?
- if (c == -1) {
- c = clc_EOF;
- }
- }
-
- if ( c == clc_EOF ) {
- break;
- }
-
- if ( c != clc_clientCommand ) {
- break;
- }
- if ( !SV_ClientCommand( cl, msg ) ) {
- return; // we couldn't execute it because of the flood protection
- }
- if (cl->state == CS_ZOMBIE) {
- return; // disconnect command
- }
- } while ( 1 );
-
- // read the usercmd_t
- if ( c == clc_move ) {
- SV_UserMove( cl, msg, qtrue );
- } else if ( c == clc_moveNoDelta ) {
- SV_UserMove( cl, msg, qfalse );
- } else if ( c == clc_voip ) {
-#ifdef USE_VOIP
- SV_UserVoip( cl, msg );
-#endif
- } else if ( c != clc_EOF ) {
- Com_Printf( "WARNING: bad command byte for client %i\n", (int) (cl - svs.clients) );
- }
-// if ( msg->readcount != msg->cursize ) {
-// Com_Printf( "WARNING: Junk at end of packet for client %i\n", cl - svs.clients );
-// }
-}
diff --git a/engine/code/server/sv_game.c b/engine/code/server/sv_game.c
deleted file mode 100644
index fe78650..0000000
--- a/engine/code/server/sv_game.c
+++ /dev/null
@@ -1,965 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// sv_game.c -- interface to the game dll
-
-#include "server.h"
-
-#include "../botlib/botlib.h"
-
-botlib_export_t *botlib_export;
-
-void SV_GameError( const char *string ) {
- Com_Error( ERR_DROP, "%s", string );
-}
-
-void SV_GamePrint( const char *string ) {
- Com_Printf( "%s", string );
-}
-
-// these functions must be used instead of pointer arithmetic, because
-// the game allocates gentities with private information after the server shared part
-int SV_NumForGentity( sharedEntity_t *ent ) {
- int num;
-
- num = ( (byte *)ent - (byte *)sv.gentities ) / sv.gentitySize;
-
- return num;
-}
-
-sharedEntity_t *SV_GentityNum( int num ) {
- sharedEntity_t *ent;
-
- ent = (sharedEntity_t *)((byte *)sv.gentities + sv.gentitySize*(num));
-
- return ent;
-}
-
-playerState_t *SV_GameClientNum( int num ) {
- playerState_t *ps;
-
- ps = (playerState_t *)((byte *)sv.gameClients + sv.gameClientSize*(num));
-
- return ps;
-}
-
-svEntity_t *SV_SvEntityForGentity( sharedEntity_t *gEnt ) {
- if ( !gEnt || gEnt->s.number < 0 || gEnt->s.number >= MAX_GENTITIES ) {
- Com_Error( ERR_DROP, "SV_SvEntityForGentity: bad gEnt" );
- }
- return &sv.svEntities[ gEnt->s.number ];
-}
-
-sharedEntity_t *SV_GEntityForSvEntity( svEntity_t *svEnt ) {
- int num;
-
- num = svEnt - sv.svEntities;
- return SV_GentityNum( num );
-}
-
-/*
-===============
-SV_GameSendServerCommand
-
-Sends a command string to a client
-===============
-*/
-void SV_GameSendServerCommand( int clientNum, const char *text ) {
- if ( clientNum == -1 ) {
- SV_SendServerCommand( NULL, "%s", text );
- } else {
- if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {
- return;
- }
- SV_SendServerCommand( svs.clients + clientNum, "%s", text );
- }
-}
-
-
-/*
-===============
-SV_GameDropClient
-
-Disconnects the client with a message
-===============
-*/
-void SV_GameDropClient( int clientNum, const char *reason ) {
- if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {
- return;
- }
- SV_DropClient( svs.clients + clientNum, reason );
-}
-
-
-/*
-=================
-SV_SetBrushModel
-
-sets mins and maxs for inline bmodels
-=================
-*/
-void SV_SetBrushModel( sharedEntity_t *ent, const char *name ) {
- clipHandle_t h;
- vec3_t mins, maxs;
-
- if (!name) {
- Com_Error( ERR_DROP, "SV_SetBrushModel: NULL" );
- }
-
- if (name[0] != '*') {
- Com_Error( ERR_DROP, "SV_SetBrushModel: %s isn't a brush model", name );
- }
-
-
- ent->s.modelindex = atoi( name + 1 );
-
- h = CM_InlineModel( ent->s.modelindex );
- CM_ModelBounds( h, mins, maxs );
- VectorCopy (mins, ent->r.mins);
- VectorCopy (maxs, ent->r.maxs);
- ent->r.bmodel = qtrue;
-
- ent->r.contents = -1; // we don't know exactly what is in the brushes
-
- SV_LinkEntity( ent ); // FIXME: remove
-}
-
-
-
-/*
-=================
-SV_inPVS
-
-Also checks portalareas so that doors block sight
-=================
-*/
-qboolean SV_inPVS (const vec3_t p1, const vec3_t p2)
-{
- int leafnum;
- int cluster;
- int area1, area2;
- byte *mask;
-
- leafnum = CM_PointLeafnum (p1);
- cluster = CM_LeafCluster (leafnum);
- area1 = CM_LeafArea (leafnum);
- mask = CM_ClusterPVS (cluster);
-
- leafnum = CM_PointLeafnum (p2);
- cluster = CM_LeafCluster (leafnum);
- area2 = CM_LeafArea (leafnum);
- if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
- return qfalse;
- if (!CM_AreasConnected (area1, area2))
- return qfalse; // a door blocks sight
- return qtrue;
-}
-
-
-/*
-=================
-SV_inPVSIgnorePortals
-
-Does NOT check portalareas
-=================
-*/
-qboolean SV_inPVSIgnorePortals( const vec3_t p1, const vec3_t p2)
-{
- int leafnum;
- int cluster;
- byte *mask;
-
- leafnum = CM_PointLeafnum (p1);
- cluster = CM_LeafCluster (leafnum);
- mask = CM_ClusterPVS (cluster);
-
- leafnum = CM_PointLeafnum (p2);
- cluster = CM_LeafCluster (leafnum);
-
- if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
- return qfalse;
-
- return qtrue;
-}
-
-
-/*
-========================
-SV_AdjustAreaPortalState
-========================
-*/
-void SV_AdjustAreaPortalState( sharedEntity_t *ent, qboolean open ) {
- svEntity_t *svEnt;
-
- svEnt = SV_SvEntityForGentity( ent );
- if ( svEnt->areanum2 == -1 ) {
- return;
- }
- CM_AdjustAreaPortalState( svEnt->areanum, svEnt->areanum2, open );
-}
-
-
-/*
-==================
-SV_GameAreaEntities
-==================
-*/
-qboolean SV_EntityContact( vec3_t mins, vec3_t maxs, const sharedEntity_t *gEnt, int capsule ) {
- const float *origin, *angles;
- clipHandle_t ch;
- trace_t trace;
-
- // check for exact collision
- origin = gEnt->r.currentOrigin;
- angles = gEnt->r.currentAngles;
-
- ch = SV_ClipHandleForEntity( gEnt );
- CM_TransformedBoxTrace ( &trace, vec3_origin, vec3_origin, mins, maxs,
- ch, -1, origin, angles, capsule );
-
- return trace.startsolid;
-}
-
-
-/*
-===============
-SV_GetServerinfo
-
-===============
-*/
-void SV_GetServerinfo( char *buffer, int bufferSize ) {
- if ( bufferSize < 1 ) {
- Com_Error( ERR_DROP, "SV_GetServerinfo: bufferSize == %i", bufferSize );
- }
- Q_strncpyz( buffer, Cvar_InfoString( CVAR_SERVERINFO ), bufferSize );
-}
-
-/*
-===============
-SV_LocateGameData
-
-===============
-*/
-void SV_LocateGameData( sharedEntity_t *gEnts, int numGEntities, int sizeofGEntity_t,
- playerState_t *clients, int sizeofGameClient ) {
- sv.gentities = gEnts;
- sv.gentitySize = sizeofGEntity_t;
- sv.num_entities = numGEntities;
-
- sv.gameClients = clients;
- sv.gameClientSize = sizeofGameClient;
-}
-
-
-/*
-===============
-SV_GetUsercmd
-
-===============
-*/
-void SV_GetUsercmd( int clientNum, usercmd_t *cmd ) {
- if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {
- Com_Error( ERR_DROP, "SV_GetUsercmd: bad clientNum:%i", clientNum );
- }
- *cmd = svs.clients[clientNum].lastUsercmd;
-}
-
-//==============================================
-
-static int FloatAsInt( float f ) {
- floatint_t fi;
- fi.f = f;
- return fi.i;
-}
-
-/*
-====================
-SV_GameSystemCalls
-
-The module is making a system call
-====================
-*/
-intptr_t SV_GameSystemCalls( intptr_t *args ) {
- switch( args[0] ) {
- case G_PRINT:
- Com_Printf( "%s", (const char*)VMA(1) );
- return 0;
- case G_ERROR:
- Com_Error( ERR_DROP, "%s", (const char*)VMA(1) );
- return 0;
- case G_MILLISECONDS:
- return Sys_Milliseconds();
- case G_CVAR_REGISTER:
- Cvar_Register( VMA(1), VMA(2), VMA(3), args[4] );
- return 0;
- case G_CVAR_UPDATE:
- Cvar_Update( VMA(1) );
- return 0;
- case G_CVAR_SET:
- Cvar_Set( (const char *)VMA(1), (const char *)VMA(2) );
- return 0;
- case G_CVAR_VARIABLE_INTEGER_VALUE:
- return Cvar_VariableIntegerValue( (const char *)VMA(1) );
- case G_CVAR_VARIABLE_STRING_BUFFER:
- Cvar_VariableStringBuffer( VMA(1), VMA(2), args[3] );
- return 0;
- case G_ARGC:
- return Cmd_Argc();
- case G_ARGV:
- Cmd_ArgvBuffer( args[1], VMA(2), args[3] );
- return 0;
- case G_SEND_CONSOLE_COMMAND:
- Cbuf_ExecuteText( args[1], VMA(2) );
- return 0;
-
- case G_FS_FOPEN_FILE:
- return FS_FOpenFileByMode( VMA(1), VMA(2), args[3] );
- case G_FS_READ:
- FS_Read2( VMA(1), args[2], args[3] );
- return 0;
- case G_FS_WRITE:
- FS_Write( VMA(1), args[2], args[3] );
- return 0;
- case G_FS_FCLOSE_FILE:
- FS_FCloseFile( args[1] );
- return 0;
- case G_FS_GETFILELIST:
- return FS_GetFileList( VMA(1), VMA(2), VMA(3), args[4] );
- case G_FS_SEEK:
- return FS_Seek( args[1], args[2], args[3] );
-
- case G_LOCATE_GAME_DATA:
- SV_LocateGameData( VMA(1), args[2], args[3], VMA(4), args[5] );
- return 0;
- case G_DROP_CLIENT:
- SV_GameDropClient( args[1], VMA(2) );
- return 0;
- case G_SEND_SERVER_COMMAND:
- SV_GameSendServerCommand( args[1], VMA(2) );
- return 0;
- case G_LINKENTITY:
- SV_LinkEntity( VMA(1) );
- return 0;
- case G_UNLINKENTITY:
- SV_UnlinkEntity( VMA(1) );
- return 0;
- case G_ENTITIES_IN_BOX:
- return SV_AreaEntities( VMA(1), VMA(2), VMA(3), args[4] );
- case G_ENTITY_CONTACT:
- return SV_EntityContact( VMA(1), VMA(2), VMA(3), /*int capsule*/ qfalse );
- case G_ENTITY_CONTACTCAPSULE:
- return SV_EntityContact( VMA(1), VMA(2), VMA(3), /*int capsule*/ qtrue );
- case G_TRACE:
- SV_Trace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], /*int capsule*/ qfalse );
- return 0;
- case G_TRACECAPSULE:
- SV_Trace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], /*int capsule*/ qtrue );
- return 0;
- case G_POINT_CONTENTS:
- return SV_PointContents( VMA(1), args[2] );
- case G_SET_BRUSH_MODEL:
- SV_SetBrushModel( VMA(1), VMA(2) );
- return 0;
- case G_IN_PVS:
- return SV_inPVS( VMA(1), VMA(2) );
- case G_IN_PVS_IGNORE_PORTALS:
- return SV_inPVSIgnorePortals( VMA(1), VMA(2) );
-
- case G_SET_CONFIGSTRING:
- SV_SetConfigstring( args[1], VMA(2) );
- return 0;
- case G_GET_CONFIGSTRING:
- SV_GetConfigstring( args[1], VMA(2), args[3] );
- return 0;
- case G_SET_USERINFO:
- SV_SetUserinfo( args[1], VMA(2) );
- return 0;
- case G_GET_USERINFO:
- SV_GetUserinfo( args[1], VMA(2), args[3] );
- return 0;
- case G_GET_SERVERINFO:
- SV_GetServerinfo( VMA(1), args[2] );
- return 0;
- case G_ADJUST_AREA_PORTAL_STATE:
- SV_AdjustAreaPortalState( VMA(1), args[2] );
- return 0;
- case G_AREAS_CONNECTED:
- return CM_AreasConnected( args[1], args[2] );
-
- case G_BOT_ALLOCATE_CLIENT:
- return SV_BotAllocateClient();
- case G_BOT_FREE_CLIENT:
- SV_BotFreeClient( args[1] );
- return 0;
-
- case G_GET_USERCMD:
- SV_GetUsercmd( args[1], VMA(2) );
- return 0;
- case G_GET_ENTITY_TOKEN:
- {
- const char *s;
-
- s = COM_Parse( &sv.entityParsePoint );
- Q_strncpyz( VMA(1), s, args[2] );
- if ( !sv.entityParsePoint && !s[0] ) {
- return qfalse;
- } else {
- return qtrue;
- }
- }
-
- case G_DEBUG_POLYGON_CREATE:
- return BotImport_DebugPolygonCreate( args[1], args[2], VMA(3) );
- case G_DEBUG_POLYGON_DELETE:
- BotImport_DebugPolygonDelete( args[1] );
- return 0;
- case G_REAL_TIME:
- return Com_RealTime( VMA(1) );
- case G_SNAPVECTOR:
- Sys_SnapVector( VMA(1) );
- return 0;
-
- //====================================
-
- case BOTLIB_SETUP:
- return SV_BotLibSetup();
- case BOTLIB_SHUTDOWN:
- return SV_BotLibShutdown();
- case BOTLIB_LIBVAR_SET:
- return botlib_export->BotLibVarSet( VMA(1), VMA(2) );
- case BOTLIB_LIBVAR_GET:
- return botlib_export->BotLibVarGet( VMA(1), VMA(2), args[3] );
-
- case BOTLIB_PC_ADD_GLOBAL_DEFINE:
- return botlib_export->PC_AddGlobalDefine( VMA(1) );
- case BOTLIB_PC_LOAD_SOURCE:
- return botlib_export->PC_LoadSourceHandle( VMA(1) );
- case BOTLIB_PC_FREE_SOURCE:
- return botlib_export->PC_FreeSourceHandle( args[1] );
- case BOTLIB_PC_READ_TOKEN:
- return botlib_export->PC_ReadTokenHandle( args[1], VMA(2) );
- case BOTLIB_PC_SOURCE_FILE_AND_LINE:
- return botlib_export->PC_SourceFileAndLine( args[1], VMA(2), VMA(3) );
-
- case BOTLIB_START_FRAME:
- return botlib_export->BotLibStartFrame( VMF(1) );
- case BOTLIB_LOAD_MAP:
- return botlib_export->BotLibLoadMap( VMA(1) );
- case BOTLIB_UPDATENTITY:
- return botlib_export->BotLibUpdateEntity( args[1], VMA(2) );
- case BOTLIB_TEST:
- return botlib_export->Test( args[1], VMA(2), VMA(3), VMA(4) );
-
- case BOTLIB_GET_SNAPSHOT_ENTITY:
- return SV_BotGetSnapshotEntity( args[1], args[2] );
- case BOTLIB_GET_CONSOLE_MESSAGE:
- return SV_BotGetConsoleMessage( args[1], VMA(2), args[3] );
- case BOTLIB_USER_COMMAND:
- SV_ClientThink( &svs.clients[args[1]], VMA(2) );
- return 0;
-
- case BOTLIB_AAS_BBOX_AREAS:
- return botlib_export->aas.AAS_BBoxAreas( VMA(1), VMA(2), VMA(3), args[4] );
- case BOTLIB_AAS_AREA_INFO:
- return botlib_export->aas.AAS_AreaInfo( args[1], VMA(2) );
- case BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL:
- return botlib_export->aas.AAS_AlternativeRouteGoals( VMA(1), args[2], VMA(3), args[4], args[5], VMA(6), args[7], args[8] );
- case BOTLIB_AAS_ENTITY_INFO:
- botlib_export->aas.AAS_EntityInfo( args[1], VMA(2) );
- return 0;
-
- case BOTLIB_AAS_INITIALIZED:
- return botlib_export->aas.AAS_Initialized();
- case BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX:
- botlib_export->aas.AAS_PresenceTypeBoundingBox( args[1], VMA(2), VMA(3) );
- return 0;
- case BOTLIB_AAS_TIME:
- return FloatAsInt( botlib_export->aas.AAS_Time() );
-
- case BOTLIB_AAS_POINT_AREA_NUM:
- return botlib_export->aas.AAS_PointAreaNum( VMA(1) );
- case BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX:
- return botlib_export->aas.AAS_PointReachabilityAreaIndex( VMA(1) );
- case BOTLIB_AAS_TRACE_AREAS:
- return botlib_export->aas.AAS_TraceAreas( VMA(1), VMA(2), VMA(3), VMA(4), args[5] );
-
- case BOTLIB_AAS_POINT_CONTENTS:
- return botlib_export->aas.AAS_PointContents( VMA(1) );
- case BOTLIB_AAS_NEXT_BSP_ENTITY:
- return botlib_export->aas.AAS_NextBSPEntity( args[1] );
- case BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY:
- return botlib_export->aas.AAS_ValueForBSPEpairKey( args[1], VMA(2), VMA(3), args[4] );
- case BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY:
- return botlib_export->aas.AAS_VectorForBSPEpairKey( args[1], VMA(2), VMA(3) );
- case BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY:
- return botlib_export->aas.AAS_FloatForBSPEpairKey( args[1], VMA(2), VMA(3) );
- case BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY:
- return botlib_export->aas.AAS_IntForBSPEpairKey( args[1], VMA(2), VMA(3) );
-
- case BOTLIB_AAS_AREA_REACHABILITY:
- return botlib_export->aas.AAS_AreaReachability( args[1] );
-
- case BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA:
- return botlib_export->aas.AAS_AreaTravelTimeToGoalArea( args[1], VMA(2), args[3], args[4] );
- case BOTLIB_AAS_ENABLE_ROUTING_AREA:
- return botlib_export->aas.AAS_EnableRoutingArea( args[1], args[2] );
- case BOTLIB_AAS_PREDICT_ROUTE:
- return botlib_export->aas.AAS_PredictRoute( VMA(1), args[2], VMA(3), args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11] );
-
- case BOTLIB_AAS_SWIMMING:
- return botlib_export->aas.AAS_Swimming( VMA(1) );
- case BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT:
- return botlib_export->aas.AAS_PredictClientMovement( VMA(1), args[2], VMA(3), args[4], args[5],
- VMA(6), VMA(7), args[8], args[9], VMF(10), args[11], args[12], args[13] );
-
- case BOTLIB_EA_SAY:
- botlib_export->ea.EA_Say( args[1], VMA(2) );
- return 0;
- case BOTLIB_EA_SAY_TEAM:
- botlib_export->ea.EA_SayTeam( args[1], VMA(2) );
- return 0;
- case BOTLIB_EA_COMMAND:
- botlib_export->ea.EA_Command( args[1], VMA(2) );
- return 0;
-
- case BOTLIB_EA_ACTION:
- botlib_export->ea.EA_Action( args[1], args[2] );
- break;
- case BOTLIB_EA_GESTURE:
- botlib_export->ea.EA_Gesture( args[1] );
- return 0;
- case BOTLIB_EA_TALK:
- botlib_export->ea.EA_Talk( args[1] );
- return 0;
- case BOTLIB_EA_ATTACK:
- botlib_export->ea.EA_Attack( args[1] );
- return 0;
- case BOTLIB_EA_USE:
- botlib_export->ea.EA_Use( args[1] );
- return 0;
- case BOTLIB_EA_RESPAWN:
- botlib_export->ea.EA_Respawn( args[1] );
- return 0;
- case BOTLIB_EA_CROUCH:
- botlib_export->ea.EA_Crouch( args[1] );
- return 0;
- case BOTLIB_EA_MOVE_UP:
- botlib_export->ea.EA_MoveUp( args[1] );
- return 0;
- case BOTLIB_EA_MOVE_DOWN:
- botlib_export->ea.EA_MoveDown( args[1] );
- return 0;
- case BOTLIB_EA_MOVE_FORWARD:
- botlib_export->ea.EA_MoveForward( args[1] );
- return 0;
- case BOTLIB_EA_MOVE_BACK:
- botlib_export->ea.EA_MoveBack( args[1] );
- return 0;
- case BOTLIB_EA_MOVE_LEFT:
- botlib_export->ea.EA_MoveLeft( args[1] );
- return 0;
- case BOTLIB_EA_MOVE_RIGHT:
- botlib_export->ea.EA_MoveRight( args[1] );
- return 0;
-
- case BOTLIB_EA_SELECT_WEAPON:
- botlib_export->ea.EA_SelectWeapon( args[1], args[2] );
- return 0;
- case BOTLIB_EA_JUMP:
- botlib_export->ea.EA_Jump( args[1] );
- return 0;
- case BOTLIB_EA_DELAYED_JUMP:
- botlib_export->ea.EA_DelayedJump( args[1] );
- return 0;
- case BOTLIB_EA_MOVE:
- botlib_export->ea.EA_Move( args[1], VMA(2), VMF(3) );
- return 0;
- case BOTLIB_EA_VIEW:
- botlib_export->ea.EA_View( args[1], VMA(2) );
- return 0;
-
- case BOTLIB_EA_END_REGULAR:
- botlib_export->ea.EA_EndRegular( args[1], VMF(2) );
- return 0;
- case BOTLIB_EA_GET_INPUT:
- botlib_export->ea.EA_GetInput( args[1], VMF(2), VMA(3) );
- return 0;
- case BOTLIB_EA_RESET_INPUT:
- botlib_export->ea.EA_ResetInput( args[1] );
- return 0;
-
- case BOTLIB_AI_LOAD_CHARACTER:
- return botlib_export->ai.BotLoadCharacter( VMA(1), VMF(2) );
- case BOTLIB_AI_FREE_CHARACTER:
- botlib_export->ai.BotFreeCharacter( args[1] );
- return 0;
- case BOTLIB_AI_CHARACTERISTIC_FLOAT:
- return FloatAsInt( botlib_export->ai.Characteristic_Float( args[1], args[2] ) );
- case BOTLIB_AI_CHARACTERISTIC_BFLOAT:
- return FloatAsInt( botlib_export->ai.Characteristic_BFloat( args[1], args[2], VMF(3), VMF(4) ) );
- case BOTLIB_AI_CHARACTERISTIC_INTEGER:
- return botlib_export->ai.Characteristic_Integer( args[1], args[2] );
- case BOTLIB_AI_CHARACTERISTIC_BINTEGER:
- return botlib_export->ai.Characteristic_BInteger( args[1], args[2], args[3], args[4] );
- case BOTLIB_AI_CHARACTERISTIC_STRING:
- botlib_export->ai.Characteristic_String( args[1], args[2], VMA(3), args[4] );
- return 0;
-
- case BOTLIB_AI_ALLOC_CHAT_STATE:
- return botlib_export->ai.BotAllocChatState();
- case BOTLIB_AI_FREE_CHAT_STATE:
- botlib_export->ai.BotFreeChatState( args[1] );
- return 0;
- case BOTLIB_AI_QUEUE_CONSOLE_MESSAGE:
- botlib_export->ai.BotQueueConsoleMessage( args[1], args[2], VMA(3) );
- return 0;
- case BOTLIB_AI_REMOVE_CONSOLE_MESSAGE:
- botlib_export->ai.BotRemoveConsoleMessage( args[1], args[2] );
- return 0;
- case BOTLIB_AI_NEXT_CONSOLE_MESSAGE:
- return botlib_export->ai.BotNextConsoleMessage( args[1], VMA(2) );
- case BOTLIB_AI_NUM_CONSOLE_MESSAGE:
- return botlib_export->ai.BotNumConsoleMessages( args[1] );
- case BOTLIB_AI_INITIAL_CHAT:
- botlib_export->ai.BotInitialChat( args[1], VMA(2), args[3], VMA(4), VMA(5), VMA(6), VMA(7), VMA(8), VMA(9), VMA(10), VMA(11) );
- return 0;
- case BOTLIB_AI_NUM_INITIAL_CHATS:
- return botlib_export->ai.BotNumInitialChats( args[1], VMA(2) );
- case BOTLIB_AI_REPLY_CHAT:
- return botlib_export->ai.BotReplyChat( args[1], VMA(2), args[3], args[4], VMA(5), VMA(6), VMA(7), VMA(8), VMA(9), VMA(10), VMA(11), VMA(12) );
- case BOTLIB_AI_CHAT_LENGTH:
- return botlib_export->ai.BotChatLength( args[1] );
- case BOTLIB_AI_ENTER_CHAT:
- botlib_export->ai.BotEnterChat( args[1], args[2], args[3] );
- return 0;
- case BOTLIB_AI_GET_CHAT_MESSAGE:
- botlib_export->ai.BotGetChatMessage( args[1], VMA(2), args[3] );
- return 0;
- case BOTLIB_AI_STRING_CONTAINS:
- return botlib_export->ai.StringContains( VMA(1), VMA(2), args[3] );
- case BOTLIB_AI_FIND_MATCH:
- return botlib_export->ai.BotFindMatch( VMA(1), VMA(2), args[3] );
- case BOTLIB_AI_MATCH_VARIABLE:
- botlib_export->ai.BotMatchVariable( VMA(1), args[2], VMA(3), args[4] );
- return 0;
- case BOTLIB_AI_UNIFY_WHITE_SPACES:
- botlib_export->ai.UnifyWhiteSpaces( VMA(1) );
- return 0;
- case BOTLIB_AI_REPLACE_SYNONYMS:
- botlib_export->ai.BotReplaceSynonyms( VMA(1), args[2] );
- return 0;
- case BOTLIB_AI_LOAD_CHAT_FILE:
- return botlib_export->ai.BotLoadChatFile( args[1], VMA(2), VMA(3) );
- case BOTLIB_AI_SET_CHAT_GENDER:
- botlib_export->ai.BotSetChatGender( args[1], args[2] );
- return 0;
- case BOTLIB_AI_SET_CHAT_NAME:
- botlib_export->ai.BotSetChatName( args[1], VMA(2), args[3] );
- return 0;
-
- case BOTLIB_AI_RESET_GOAL_STATE:
- botlib_export->ai.BotResetGoalState( args[1] );
- return 0;
- case BOTLIB_AI_RESET_AVOID_GOALS:
- botlib_export->ai.BotResetAvoidGoals( args[1] );
- return 0;
- case BOTLIB_AI_REMOVE_FROM_AVOID_GOALS:
- botlib_export->ai.BotRemoveFromAvoidGoals( args[1], args[2] );
- return 0;
- case BOTLIB_AI_PUSH_GOAL:
- botlib_export->ai.BotPushGoal( args[1], VMA(2) );
- return 0;
- case BOTLIB_AI_POP_GOAL:
- botlib_export->ai.BotPopGoal( args[1] );
- return 0;
- case BOTLIB_AI_EMPTY_GOAL_STACK:
- botlib_export->ai.BotEmptyGoalStack( args[1] );
- return 0;
- case BOTLIB_AI_DUMP_AVOID_GOALS:
- botlib_export->ai.BotDumpAvoidGoals( args[1] );
- return 0;
- case BOTLIB_AI_DUMP_GOAL_STACK:
- botlib_export->ai.BotDumpGoalStack( args[1] );
- return 0;
- case BOTLIB_AI_GOAL_NAME:
- botlib_export->ai.BotGoalName( args[1], VMA(2), args[3] );
- return 0;
- case BOTLIB_AI_GET_TOP_GOAL:
- return botlib_export->ai.BotGetTopGoal( args[1], VMA(2) );
- case BOTLIB_AI_GET_SECOND_GOAL:
- return botlib_export->ai.BotGetSecondGoal( args[1], VMA(2) );
- case BOTLIB_AI_CHOOSE_LTG_ITEM:
- return botlib_export->ai.BotChooseLTGItem( args[1], VMA(2), VMA(3), args[4] );
- case BOTLIB_AI_CHOOSE_NBG_ITEM:
- return botlib_export->ai.BotChooseNBGItem( args[1], VMA(2), VMA(3), args[4], VMA(5), VMF(6) );
- case BOTLIB_AI_TOUCHING_GOAL:
- return botlib_export->ai.BotTouchingGoal( VMA(1), VMA(2) );
- case BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE:
- return botlib_export->ai.BotItemGoalInVisButNotVisible( args[1], VMA(2), VMA(3), VMA(4) );
- case BOTLIB_AI_GET_LEVEL_ITEM_GOAL:
- return botlib_export->ai.BotGetLevelItemGoal( args[1], VMA(2), VMA(3) );
- case BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL:
- return botlib_export->ai.BotGetNextCampSpotGoal( args[1], VMA(2) );
- case BOTLIB_AI_GET_MAP_LOCATION_GOAL:
- return botlib_export->ai.BotGetMapLocationGoal( VMA(1), VMA(2) );
- case BOTLIB_AI_AVOID_GOAL_TIME:
- return FloatAsInt( botlib_export->ai.BotAvoidGoalTime( args[1], args[2] ) );
- case BOTLIB_AI_SET_AVOID_GOAL_TIME:
- botlib_export->ai.BotSetAvoidGoalTime( args[1], args[2], VMF(3));
- return 0;
- case BOTLIB_AI_INIT_LEVEL_ITEMS:
- botlib_export->ai.BotInitLevelItems();
- return 0;
- case BOTLIB_AI_UPDATE_ENTITY_ITEMS:
- botlib_export->ai.BotUpdateEntityItems();
- return 0;
- case BOTLIB_AI_LOAD_ITEM_WEIGHTS:
- return botlib_export->ai.BotLoadItemWeights( args[1], VMA(2) );
- case BOTLIB_AI_FREE_ITEM_WEIGHTS:
- botlib_export->ai.BotFreeItemWeights( args[1] );
- return 0;
- case BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC:
- botlib_export->ai.BotInterbreedGoalFuzzyLogic( args[1], args[2], args[3] );
- return 0;
- case BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC:
- botlib_export->ai.BotSaveGoalFuzzyLogic( args[1], VMA(2) );
- return 0;
- case BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC:
- botlib_export->ai.BotMutateGoalFuzzyLogic( args[1], VMF(2) );
- return 0;
- case BOTLIB_AI_ALLOC_GOAL_STATE:
- return botlib_export->ai.BotAllocGoalState( args[1] );
- case BOTLIB_AI_FREE_GOAL_STATE:
- botlib_export->ai.BotFreeGoalState( args[1] );
- return 0;
-
- case BOTLIB_AI_RESET_MOVE_STATE:
- botlib_export->ai.BotResetMoveState( args[1] );
- return 0;
- case BOTLIB_AI_ADD_AVOID_SPOT:
- botlib_export->ai.BotAddAvoidSpot( args[1], VMA(2), VMF(3), args[4] );
- return 0;
- case BOTLIB_AI_MOVE_TO_GOAL:
- botlib_export->ai.BotMoveToGoal( VMA(1), args[2], VMA(3), args[4] );
- return 0;
- case BOTLIB_AI_MOVE_IN_DIRECTION:
- return botlib_export->ai.BotMoveInDirection( args[1], VMA(2), VMF(3), args[4] );
- case BOTLIB_AI_RESET_AVOID_REACH:
- botlib_export->ai.BotResetAvoidReach( args[1] );
- return 0;
- case BOTLIB_AI_RESET_LAST_AVOID_REACH:
- botlib_export->ai.BotResetLastAvoidReach( args[1] );
- return 0;
- case BOTLIB_AI_REACHABILITY_AREA:
- return botlib_export->ai.BotReachabilityArea( VMA(1), args[2] );
- case BOTLIB_AI_MOVEMENT_VIEW_TARGET:
- return botlib_export->ai.BotMovementViewTarget( args[1], VMA(2), args[3], VMF(4), VMA(5) );
- case BOTLIB_AI_PREDICT_VISIBLE_POSITION:
- return botlib_export->ai.BotPredictVisiblePosition( VMA(1), args[2], VMA(3), args[4], VMA(5) );
- case BOTLIB_AI_ALLOC_MOVE_STATE:
- return botlib_export->ai.BotAllocMoveState();
- case BOTLIB_AI_FREE_MOVE_STATE:
- botlib_export->ai.BotFreeMoveState( args[1] );
- return 0;
- case BOTLIB_AI_INIT_MOVE_STATE:
- botlib_export->ai.BotInitMoveState( args[1], VMA(2) );
- return 0;
-
- case BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON:
- return botlib_export->ai.BotChooseBestFightWeapon( args[1], VMA(2) );
- case BOTLIB_AI_GET_WEAPON_INFO:
- botlib_export->ai.BotGetWeaponInfo( args[1], args[2], VMA(3) );
- return 0;
- case BOTLIB_AI_LOAD_WEAPON_WEIGHTS:
- return botlib_export->ai.BotLoadWeaponWeights( args[1], VMA(2) );
- case BOTLIB_AI_ALLOC_WEAPON_STATE:
- return botlib_export->ai.BotAllocWeaponState();
- case BOTLIB_AI_FREE_WEAPON_STATE:
- botlib_export->ai.BotFreeWeaponState( args[1] );
- return 0;
- case BOTLIB_AI_RESET_WEAPON_STATE:
- botlib_export->ai.BotResetWeaponState( args[1] );
- return 0;
-
- case BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION:
- return botlib_export->ai.GeneticParentsAndChildSelection(args[1], VMA(2), VMA(3), VMA(4), VMA(5));
-
- case TRAP_MEMSET:
- Com_Memset( VMA(1), args[2], args[3] );
- return 0;
-
- case TRAP_MEMCPY:
- Com_Memcpy( VMA(1), VMA(2), args[3] );
- return 0;
-
- case TRAP_STRNCPY:
- strncpy( VMA(1), VMA(2), args[3] );
- return args[1];
-
- case TRAP_SIN:
- return FloatAsInt( sin( VMF(1) ) );
-
- case TRAP_COS:
- return FloatAsInt( cos( VMF(1) ) );
-
- case TRAP_ATAN2:
- return FloatAsInt( atan2( VMF(1), VMF(2) ) );
-
- case TRAP_SQRT:
- return FloatAsInt( sqrt( VMF(1) ) );
-
- case TRAP_MATRIXMULTIPLY:
- MatrixMultiply( VMA(1), VMA(2), VMA(3) );
- return 0;
-
- case TRAP_ANGLEVECTORS:
- AngleVectors( VMA(1), VMA(2), VMA(3), VMA(4) );
- return 0;
-
- case TRAP_PERPENDICULARVECTOR:
- PerpendicularVector( VMA(1), VMA(2) );
- return 0;
-
- case TRAP_FLOOR:
- return FloatAsInt( floor( VMF(1) ) );
-
- case TRAP_CEIL:
- return FloatAsInt( ceil( VMF(1) ) );
-
-
- default:
- Com_Error( ERR_DROP, "Bad game system trap: %ld", (long int) args[0] );
- }
- return -1;
-}
-
-/*
-===============
-SV_ShutdownGameProgs
-
-Called every time a map changes
-===============
-*/
-void SV_ShutdownGameProgs( void ) {
- if ( !gvm ) {
- return;
- }
- VM_Call( gvm, GAME_SHUTDOWN, qfalse );
- VM_Free( gvm );
- gvm = NULL;
-}
-
-/*
-==================
-SV_InitGameVM
-
-Called for both a full init and a restart
-==================
-*/
-static void SV_InitGameVM( qboolean restart ) {
- int i;
-
- // start the entity parsing at the beginning
- sv.entityParsePoint = CM_EntityString();
-
- // clear all gentity pointers that might still be set from
- // a previous level
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=522
- // now done before GAME_INIT call
- for ( i = 0 ; i < sv_maxclients->integer ; i++ ) {
- svs.clients[i].gentity = NULL;
- }
-
- // use the current msec count for a random seed
- // init for this gamestate
- VM_Call (gvm, GAME_INIT, sv.time, Com_Milliseconds(), restart);
-}
-
-
-
-/*
-===================
-SV_RestartGameProgs
-
-Called on a map_restart, but not on a normal map change
-===================
-*/
-void SV_RestartGameProgs( void ) {
- if ( !gvm ) {
- return;
- }
- VM_Call( gvm, GAME_SHUTDOWN, qtrue );
-
- // do a restart instead of a free
- gvm = VM_Restart( gvm );
- if ( !gvm ) {
- Com_Error( ERR_FATAL, "VM_Restart on game failed" );
- }
-
- SV_InitGameVM( qtrue );
-}
-
-
-/*
-===============
-SV_InitGameProgs
-
-Called on a normal map change, not on a map_restart
-===============
-*/
-void SV_InitGameProgs( void ) {
- cvar_t *var;
- //FIXME these are temp while I make bots run in vm
- extern int bot_enable;
-
- var = Cvar_Get( "bot_enable", "1", CVAR_LATCH );
- if ( var ) {
- bot_enable = var->integer;
- }
- else {
- bot_enable = 0;
- }
-
- // load the dll or bytecode
- gvm = VM_Create( "qagame", SV_GameSystemCalls, Cvar_VariableValue( "vm_game" ) );
- if ( !gvm ) {
- Com_Error( ERR_FATAL, "VM_Create on game failed" );
- }
-
- SV_InitGameVM( qfalse );
-}
-
-
-/*
-====================
-SV_GameCommand
-
-See if the current console command is claimed by the game
-====================
-*/
-qboolean SV_GameCommand( void ) {
- if ( sv.state != SS_GAME ) {
- return qfalse;
- }
-
- return VM_Call( gvm, GAME_CONSOLE_COMMAND );
-}
-
diff --git a/engine/code/server/sv_init.c b/engine/code/server/sv_init.c
deleted file mode 100644
index bac7fa4..0000000
--- a/engine/code/server/sv_init.c
+++ /dev/null
@@ -1,771 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "server.h"
-
-
-/*
-===============
-SV_SendConfigstring
-
-Creates and sends the server command necessary to update the CS index for the
-given client
-===============
-*/
-static void SV_SendConfigstring(client_t *client, int index)
-{
- int maxChunkSize = MAX_STRING_CHARS - 24;
- int len;
-
- len = strlen(sv.configstrings[index]);
-
- if( len >= maxChunkSize ) {
- int sent = 0;
- int remaining = len;
- char *cmd;
- char buf[MAX_STRING_CHARS];
-
- while (remaining > 0 ) {
- if ( sent == 0 ) {
- cmd = "bcs0";
- }
- else if( remaining < maxChunkSize ) {
- cmd = "bcs2";
- }
- else {
- cmd = "bcs1";
- }
- Q_strncpyz( buf, &sv.configstrings[index][sent],
- maxChunkSize );
-
- SV_SendServerCommand( client, "%s %i \"%s\"\n", cmd,
- index, buf );
-
- sent += (maxChunkSize - 1);
- remaining -= (maxChunkSize - 1);
- }
- } else {
- // standard cs, just send it
- SV_SendServerCommand( client, "cs %i \"%s\"\n", index,
- sv.configstrings[index] );
- }
-}
-
-/*
-===============
-SV_UpdateConfigstrings
-
-Called when a client goes from CS_PRIMED to CS_ACTIVE. Updates all
-Configstring indexes that have changed while the client was in CS_PRIMED
-===============
-*/
-void SV_UpdateConfigstrings(client_t *client)
-{
- int index;
-
- for( index = 0; index <= MAX_CONFIGSTRINGS; index++ ) {
- // if the CS hasn't changed since we went to CS_PRIMED, ignore
- if(!client->csUpdated[index])
- continue;
-
- // do not always send server info to all clients
- if ( index == CS_SERVERINFO && client->gentity &&
- (client->gentity->r.svFlags & SVF_NOSERVERINFO) ) {
- continue;
- }
- SV_SendConfigstring(client, index);
- client->csUpdated[index] = qfalse;
- }
-}
-
-/*
-===============
-SV_SetConfigstring
-
-===============
-*/
-void SV_SetConfigstring (int index, const char *val) {
- int i;
- client_t *client;
-
- if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
- Com_Error (ERR_DROP, "SV_SetConfigstring: bad index %i\n", index);
- }
-
- if ( !val ) {
- val = "";
- }
-
- // don't bother broadcasting an update if no change
- if ( !strcmp( val, sv.configstrings[ index ] ) ) {
- return;
- }
-
- // change the string in sv
- Z_Free( sv.configstrings[index] );
- sv.configstrings[index] = CopyString( val );
-
- // send it to all the clients if we aren't
- // spawning a new server
- if ( sv.state == SS_GAME || sv.restarting ) {
-
- // send the data to all relevent clients
- for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) {
- if ( client->state < CS_ACTIVE ) {
- if ( client->state == CS_PRIMED )
- client->csUpdated[ index ] = qtrue;
- continue;
- }
- // do not always send server info to all clients
- if ( index == CS_SERVERINFO && client->gentity && (client->gentity->r.svFlags & SVF_NOSERVERINFO) ) {
- continue;
- }
-
- SV_SendConfigstring(client, index);
- }
- }
-}
-
-/*
-===============
-SV_GetConfigstring
-
-===============
-*/
-void SV_GetConfigstring( int index, char *buffer, int bufferSize ) {
- if ( bufferSize < 1 ) {
- Com_Error( ERR_DROP, "SV_GetConfigstring: bufferSize == %i", bufferSize );
- }
- if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
- Com_Error (ERR_DROP, "SV_GetConfigstring: bad index %i\n", index);
- }
- if ( !sv.configstrings[index] ) {
- buffer[0] = 0;
- return;
- }
-
- Q_strncpyz( buffer, sv.configstrings[index], bufferSize );
-}
-
-
-/*
-===============
-SV_SetUserinfo
-
-===============
-*/
-void SV_SetUserinfo( int index, const char *val ) {
- if ( index < 0 || index >= sv_maxclients->integer ) {
- Com_Error (ERR_DROP, "SV_SetUserinfo: bad index %i\n", index);
- }
-
- if ( !val ) {
- val = "";
- }
-
- Q_strncpyz( svs.clients[index].userinfo, val, sizeof( svs.clients[ index ].userinfo ) );
- Q_strncpyz( svs.clients[index].name, Info_ValueForKey( val, "name" ), sizeof(svs.clients[index].name) );
-}
-
-
-
-/*
-===============
-SV_GetUserinfo
-
-===============
-*/
-void SV_GetUserinfo( int index, char *buffer, int bufferSize ) {
- if ( bufferSize < 1 ) {
- Com_Error( ERR_DROP, "SV_GetUserinfo: bufferSize == %i", bufferSize );
- }
- if ( index < 0 || index >= sv_maxclients->integer ) {
- Com_Error (ERR_DROP, "SV_GetUserinfo: bad index %i\n", index);
- }
- Q_strncpyz( buffer, svs.clients[ index ].userinfo, bufferSize );
-}
-
-
-/*
-================
-SV_CreateBaseline
-
-Entity baselines are used to compress non-delta messages
-to the clients -- only the fields that differ from the
-baseline will be transmitted
-================
-*/
-static void SV_CreateBaseline( void ) {
- sharedEntity_t *svent;
- int entnum;
-
- for ( entnum = 1; entnum < sv.num_entities ; entnum++ ) {
- svent = SV_GentityNum(entnum);
- if (!svent->r.linked) {
- continue;
- }
- svent->s.number = entnum;
-
- //
- // take current state as baseline
- //
- sv.svEntities[entnum].baseline = svent->s;
- }
-}
-
-
-/*
-===============
-SV_BoundMaxClients
-
-===============
-*/
-static void SV_BoundMaxClients( int minimum ) {
- // get the current maxclients value
- Cvar_Get( "sv_maxclients", "8", 0 );
-
- sv_maxclients->modified = qfalse;
-
- if ( sv_maxclients->integer < minimum ) {
- Cvar_Set( "sv_maxclients", va("%i", minimum) );
- } else if ( sv_maxclients->integer > MAX_CLIENTS ) {
- Cvar_Set( "sv_maxclients", va("%i", MAX_CLIENTS) );
- }
-}
-
-
-/*
-===============
-SV_Startup
-
-Called when a host starts a map when it wasn't running
-one before. Successive map or map_restart commands will
-NOT cause this to be called, unless the game is exited to
-the menu system first.
-===============
-*/
-static void SV_Startup( void ) {
- if ( svs.initialized ) {
- Com_Error( ERR_FATAL, "SV_Startup: svs.initialized" );
- }
- SV_BoundMaxClients( 1 );
-
- svs.clients = Z_Malloc (sizeof(client_t) * sv_maxclients->integer );
- if ( com_dedicated->integer ) {
- svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64;
- } else {
- // we don't need nearly as many when playing locally
- svs.numSnapshotEntities = sv_maxclients->integer * 4 * 64;
- }
- svs.initialized = qtrue;
-
- // Don't respect sv_killserver unless a server is actually running
- if ( sv_killserver->integer ) {
- Cvar_Set( "sv_killserver", "0" );
- }
-
- Cvar_Set( "sv_running", "1" );
-
- // Join the ipv6 multicast group now that a map is running so clients can scan for us on the local network.
- NET_JoinMulticast6();
-}
-
-
-/*
-==================
-SV_ChangeMaxClients
-==================
-*/
-void SV_ChangeMaxClients( void ) {
- int oldMaxClients;
- int i;
- client_t *oldClients;
- int count;
-
- // get the highest client number in use
- count = 0;
- for ( i = 0 ; i < sv_maxclients->integer ; i++ ) {
- if ( svs.clients[i].state >= CS_CONNECTED ) {
- if (i > count)
- count = i;
- }
- }
- count++;
-
- oldMaxClients = sv_maxclients->integer;
- // never go below the highest client number in use
- SV_BoundMaxClients( count );
- // if still the same
- if ( sv_maxclients->integer == oldMaxClients ) {
- return;
- }
-
- oldClients = Hunk_AllocateTempMemory( count * sizeof(client_t) );
- // copy the clients to hunk memory
- for ( i = 0 ; i < count ; i++ ) {
- if ( svs.clients[i].state >= CS_CONNECTED ) {
- oldClients[i] = svs.clients[i];
- }
- else {
- Com_Memset(&oldClients[i], 0, sizeof(client_t));
- }
- }
-
- // free old clients arrays
- Z_Free( svs.clients );
-
- // allocate new clients
- svs.clients = Z_Malloc ( sv_maxclients->integer * sizeof(client_t) );
- Com_Memset( svs.clients, 0, sv_maxclients->integer * sizeof(client_t) );
-
- // copy the clients over
- for ( i = 0 ; i < count ; i++ ) {
- if ( oldClients[i].state >= CS_CONNECTED ) {
- svs.clients[i] = oldClients[i];
- }
- }
-
- // free the old clients on the hunk
- Hunk_FreeTempMemory( oldClients );
-
- // allocate new snapshot entities
- if ( com_dedicated->integer ) {
- svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64;
- } else {
- // we don't need nearly as many when playing locally
- svs.numSnapshotEntities = sv_maxclients->integer * 4 * 64;
- }
-}
-
-/*
-================
-SV_ClearServer
-================
-*/
-static void SV_ClearServer(void) {
- int i;
-
- for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
- if ( sv.configstrings[i] ) {
- Z_Free( sv.configstrings[i] );
- }
- }
- Com_Memset (&sv, 0, sizeof(sv));
-}
-
-/*
-================
-SV_TouchCGame
-
- touch the cgame.vm so that a pure client can load it if it's in a seperate pk3
-================
-*/
-static void SV_TouchCGame(void) {
- fileHandle_t f;
- char filename[MAX_QPATH];
-
- Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", "cgame" );
- FS_FOpenFileRead( filename, &f, qfalse );
- if ( f ) {
- FS_FCloseFile( f );
- }
-}
-
-/*
-================
-SV_SpawnServer
-
-Change the server to a new map, taking all connected
-clients along with it.
-This is NOT called for map_restart
-================
-*/
-void SV_SpawnServer( char *server, qboolean killBots ) {
- int i;
- int checksum;
- qboolean isBot;
- char systemInfo[16384];
- const char *p;
-
- // shut down the existing game if it is running
- SV_ShutdownGameProgs();
-
- Com_Printf ("------ Server Initialization ------\n");
- Com_Printf ("Server: %s\n",server);
-
- // if not running a dedicated server CL_MapLoading will connect the client to the server
- // also print some status stuff
- CL_MapLoading();
-
- // make sure all the client stuff is unloaded
- CL_ShutdownAll();
-
- // clear the whole hunk because we're (re)loading the server
- Hunk_Clear();
-
-#ifndef DEDICATED
- // Restart renderer
- CL_StartHunkUsers( qtrue );
-#endif
-
- // clear collision map data
- CM_ClearMap();
-
- // init client structures and svs.numSnapshotEntities
- if ( !Cvar_VariableValue("sv_running") ) {
- SV_Startup();
- } else {
- // check for maxclients change
- if ( sv_maxclients->modified ) {
- SV_ChangeMaxClients();
- }
- }
-
- // clear pak references
- FS_ClearPakReferences(0);
-
- // allocate the snapshot entities on the hunk
- svs.snapshotEntities = Hunk_Alloc( sizeof(entityState_t)*svs.numSnapshotEntities, h_high );
- svs.nextSnapshotEntities = 0;
-
- // toggle the server bit so clients can detect that a
- // server has changed
- svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;
-
- // set nextmap to the same map, but it may be overriden
- // by the game startup or another console command
- Cvar_Set( "nextmap", "map_restart 0");
-// Cvar_Set( "nextmap", va("map %s", server) );
-
- for (i=0 ; i<sv_maxclients->integer ; i++) {
- // save when the server started for each client already connected
- if (svs.clients[i].state >= CS_CONNECTED) {
- svs.clients[i].oldServerTime = sv.time;
- }
- }
-
- // wipe the entire per-level structure
- SV_ClearServer();
- for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
- sv.configstrings[i] = CopyString("");
- }
-
- // make sure we are not paused
- Cvar_Set("cl_paused", "0");
-
- // get a new checksum feed and restart the file system
- sv.checksumFeed = ( ((int) rand() << 16) ^ rand() ) ^ Com_Milliseconds();
- FS_Restart( sv.checksumFeed );
-
- CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum );
-
- // set serverinfo visible name
- Cvar_Set( "mapname", server );
-
- Cvar_Set( "sv_mapChecksum", va("%i",checksum) );
-
- // serverid should be different each time
- sv.serverId = com_frameTime;
- sv.restartedServerId = sv.serverId; // I suppose the init here is just to be safe
- sv.checksumFeedServerId = sv.serverId;
- Cvar_Set( "sv_serverid", va("%i", sv.serverId ) );
-
- // clear physics interaction links
- SV_ClearWorld ();
-
- // media configstring setting should be done during
- // the loading stage, so connected clients don't have
- // to load during actual gameplay
- sv.state = SS_LOADING;
-
- // load and spawn all other entities
- SV_InitGameProgs();
-
- // don't allow a map_restart if game is modified
- sv_gametype->modified = qfalse;
-
- // run a few frames to allow everything to settle
- for (i = 0;i < 3; i++)
- {
- VM_Call (gvm, GAME_RUN_FRAME, sv.time);
- SV_BotFrame (sv.time);
- sv.time += 100;
- svs.time += 100;
- }
-
- // create a baseline for more efficient communications
- SV_CreateBaseline ();
-
- for (i=0 ; i<sv_maxclients->integer ; i++) {
- // send the new gamestate to all connected clients
- if (svs.clients[i].state >= CS_CONNECTED) {
- char *denied;
-
- if ( svs.clients[i].netchan.remoteAddress.type == NA_BOT ) {
- if ( killBots ) {
- SV_DropClient( &svs.clients[i], "" );
- continue;
- }
- isBot = qtrue;
- }
- else {
- isBot = qfalse;
- }
-
- // connect the client again
- denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) ); // firstTime = qfalse
- if ( denied ) {
- // this generally shouldn't happen, because the client
- // was connected before the level change
- SV_DropClient( &svs.clients[i], denied );
- } else {
- if( !isBot ) {
- // when we get the next packet from a connected client,
- // the new gamestate will be sent
- svs.clients[i].state = CS_CONNECTED;
- }
- else {
- client_t *client;
- sharedEntity_t *ent;
-
- client = &svs.clients[i];
- client->state = CS_ACTIVE;
- ent = SV_GentityNum( i );
- ent->s.number = i;
- client->gentity = ent;
-
- client->deltaMessage = -1;
- client->nextSnapshotTime = svs.time; // generate a snapshot immediately
-
- VM_Call( gvm, GAME_CLIENT_BEGIN, i );
- }
- }
- }
- }
-
- // run another frame to allow things to look at all the players
- VM_Call (gvm, GAME_RUN_FRAME, sv.time);
- SV_BotFrame (sv.time);
- sv.time += 100;
- svs.time += 100;
-
- if ( sv_pure->integer ) {
- // the server sends these to the clients so they will only
- // load pk3s also loaded at the server
- p = FS_LoadedPakChecksums();
- Cvar_Set( "sv_paks", p );
- if (strlen(p) == 0) {
- Com_Printf( "WARNING: sv_pure set but no PK3 files loaded\n" );
- }
- p = FS_LoadedPakNames();
- Cvar_Set( "sv_pakNames", p );
-
- // if a dedicated pure server we need to touch the cgame because it could be in a
- // seperate pk3 file and the client will need to load the latest cgame.qvm
- if ( com_dedicated->integer ) {
- SV_TouchCGame();
- }
- }
- else {
- Cvar_Set( "sv_paks", "" );
- Cvar_Set( "sv_pakNames", "" );
- }
- // the server sends these to the clients so they can figure
- // out which pk3s should be auto-downloaded
- p = FS_ReferencedPakChecksums();
- Cvar_Set( "sv_referencedPaks", p );
- p = FS_ReferencedPakNames();
- Cvar_Set( "sv_referencedPakNames", p );
-
- // save systeminfo and serverinfo strings
- Q_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) );
- cvar_modifiedFlags &= ~CVAR_SYSTEMINFO;
- SV_SetConfigstring( CS_SYSTEMINFO, systemInfo );
-
- SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) );
- cvar_modifiedFlags &= ~CVAR_SERVERINFO;
-
- // any media configstring setting now should issue a warning
- // and any configstring changes should be reliably transmitted
- // to all clients
- sv.state = SS_GAME;
-
- // send a heartbeat now so the master will get up to date info
- SV_Heartbeat_f();
-
- Hunk_SetMark();
-
- Com_Printf ("-----------------------------------\n");
-}
-
-/*
-===============
-SV_Init
-
-Only called at main exe startup, not for each game
-===============
-*/
-void SV_Init (void) {
- SV_AddOperatorCommands ();
-
- // serverinfo vars
- Cvar_Get ("dmflags", "0", CVAR_SERVERINFO);
- Cvar_Get ("fraglimit", "20", CVAR_SERVERINFO);
- Cvar_Get ("timelimit", "0", CVAR_SERVERINFO);
- sv_gametype = Cvar_Get ("g_gametype", "0", CVAR_SERVERINFO | CVAR_LATCH );
- Cvar_Get ("sv_keywords", "", CVAR_SERVERINFO);
- Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO | CVAR_ROM);
- sv_mapname = Cvar_Get ("mapname", "nomap", CVAR_SERVERINFO | CVAR_ROM);
- sv_privateClients = Cvar_Get ("sv_privateClients", "0", CVAR_SERVERINFO);
- sv_hostname = Cvar_Get ("sv_hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE );
- sv_maxclients = Cvar_Get ("sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
-
- sv_minRate = Cvar_Get ("sv_minRate", "0", CVAR_ARCHIVE | CVAR_SERVERINFO );
- sv_maxRate = Cvar_Get ("sv_maxRate", "0", CVAR_ARCHIVE | CVAR_SERVERINFO );
- sv_minPing = Cvar_Get ("sv_minPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO );
- sv_maxPing = Cvar_Get ("sv_maxPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO );
- sv_floodProtect = Cvar_Get ("sv_floodProtect", "1", CVAR_ARCHIVE | CVAR_SERVERINFO );
-
- // systeminfo
- Cvar_Get ("sv_cheats", "1", CVAR_SYSTEMINFO | CVAR_ROM );
- sv_serverid = Cvar_Get ("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM );
- sv_pure = Cvar_Get ("sv_pure", "1", CVAR_SYSTEMINFO );
-#ifdef USE_VOIP
- sv_voip = Cvar_Get ("sv_voip", "1", CVAR_SYSTEMINFO | CVAR_LATCH);
- Cvar_CheckRange( sv_voip, 0, 1, qtrue );
-#endif
- Cvar_Get ("sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM );
- Cvar_Get ("sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM );
- Cvar_Get ("sv_referencedPaks", "", CVAR_SYSTEMINFO | CVAR_ROM );
- Cvar_Get ("sv_referencedPakNames", "", CVAR_SYSTEMINFO | CVAR_ROM );
-
- // server vars
- sv_rconPassword = Cvar_Get ("rconPassword", "", CVAR_TEMP );
- sv_privatePassword = Cvar_Get ("sv_privatePassword", "", CVAR_TEMP );
- sv_fps = Cvar_Get ("sv_fps", "20", CVAR_TEMP );
- sv_timeout = Cvar_Get ("sv_timeout", "200", CVAR_TEMP );
- sv_zombietime = Cvar_Get ("sv_zombietime", "2", CVAR_TEMP );
- Cvar_Get ("nextmap", "", CVAR_TEMP );
-
- sv_allowDownload = Cvar_Get ("sv_allowDownload", "0", CVAR_SERVERINFO);
- Cvar_Get ("sv_dlURL", "", CVAR_SERVERINFO | CVAR_ARCHIVE);
- sv_master[0] = Cvar_Get ("sv_master1", MASTER_SERVER_NAME, 0 );
- sv_master[1] = Cvar_Get ("sv_master2", "", CVAR_ARCHIVE );
- sv_master[2] = Cvar_Get ("sv_master3", "", CVAR_ARCHIVE );
- sv_master[3] = Cvar_Get ("sv_master4", "", CVAR_ARCHIVE );
- sv_master[4] = Cvar_Get ("sv_master5", "", CVAR_ARCHIVE );
- sv_reconnectlimit = Cvar_Get ("sv_reconnectlimit", "3", 0);
- sv_showloss = Cvar_Get ("sv_showloss", "0", 0);
- sv_padPackets = Cvar_Get ("sv_padPackets", "0", 0);
- sv_killserver = Cvar_Get ("sv_killserver", "0", 0);
- sv_mapChecksum = Cvar_Get ("sv_mapChecksum", "", CVAR_ROM);
- sv_lanForceRate = Cvar_Get ("sv_lanForceRate", "1", CVAR_ARCHIVE );
- sv_strictAuth = Cvar_Get ("sv_strictAuth", "1", CVAR_ARCHIVE );
- sv_banFile = Cvar_Get("sv_banFile", "serverbans.dat", CVAR_ARCHIVE);
-
- // initialize bot cvars so they are listed and can be set before loading the botlib
- SV_BotInitCvars();
-
- // init the botlib here because we need the pre-compiler in the UI
- SV_BotInitBotLib();
-
- // Load saved bans
- Cbuf_AddText("rehashbans\n");
-}
-
-
-/*
-==================
-SV_FinalMessage
-
-Used by SV_Shutdown to send a final message to all
-connected clients before the server goes down. The messages are sent immediately,
-not just stuck on the outgoing message list, because the server is going
-to totally exit after returning from this function.
-==================
-*/
-void SV_FinalMessage( char *message ) {
- int i, j;
- client_t *cl;
-
- // send it twice, ignoring rate
- for ( j = 0 ; j < 2 ; j++ ) {
- for (i=0, cl = svs.clients ; i < sv_maxclients->integer ; i++, cl++) {
- if (cl->state >= CS_CONNECTED) {
- // don't send a disconnect to a local client
- if ( cl->netchan.remoteAddress.type != NA_LOOPBACK ) {
- SV_SendServerCommand( cl, "print \"%s\n\"\n", message );
- SV_SendServerCommand( cl, "disconnect \"%s\"", message );
- }
- // force a snapshot to be sent
- cl->nextSnapshotTime = -1;
- SV_SendClientSnapshot( cl );
- }
- }
- }
-}
-
-
-/*
-================
-SV_Shutdown
-
-Called when each game quits,
-before Sys_Quit or Sys_Error
-================
-*/
-void SV_Shutdown( char *finalmsg ) {
- if ( !com_sv_running || !com_sv_running->integer ) {
- return;
- }
-
- Com_Printf( "----- Server Shutdown (%s) -----\n", finalmsg );
-
- NET_LeaveMulticast6();
-
- if ( svs.clients && !com_errorEntered ) {
- SV_FinalMessage( finalmsg );
- }
-
- SV_RemoveOperatorCommands();
- SV_MasterShutdown();
- SV_ShutdownGameProgs();
-
- // free current level
- SV_ClearServer();
-
- // free server static data
- if ( svs.clients ) {
- Z_Free( svs.clients );
- }
- Com_Memset( &svs, 0, sizeof( svs ) );
-
- Cvar_Set( "sv_running", "0" );
- Cvar_Set("ui_singlePlayerActive", "0");
-
- Com_Printf( "---------------------------\n" );
-
- // disconnect any local clients
- if( sv_killserver->integer != 2 )
- CL_Disconnect( qfalse );
-}
-
diff --git a/engine/code/server/sv_main.c b/engine/code/server/sv_main.c
deleted file mode 100644
index 6215791..0000000
--- a/engine/code/server/sv_main.c
+++ /dev/null
@@ -1,934 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "server.h"
-
-#ifdef USE_VOIP
-cvar_t *sv_voip;
-#endif
-
-serverStatic_t svs; // persistant server info
-server_t sv; // local server
-vm_t *gvm = NULL; // game virtual machine
-
-cvar_t *sv_fps; // time rate for running non-clients
-cvar_t *sv_timeout; // seconds without any message
-cvar_t *sv_zombietime; // seconds to sink messages after disconnect
-cvar_t *sv_rconPassword; // password for remote server commands
-cvar_t *sv_privatePassword; // password for the privateClient slots
-cvar_t *sv_allowDownload;
-cvar_t *sv_maxclients;
-
-cvar_t *sv_privateClients; // number of clients reserved for password
-cvar_t *sv_hostname;
-cvar_t *sv_master[MAX_MASTER_SERVERS]; // master server ip address
-cvar_t *sv_reconnectlimit; // minimum seconds between connect messages
-cvar_t *sv_showloss; // report when usercmds are lost
-cvar_t *sv_padPackets; // add nop bytes to messages
-cvar_t *sv_killserver; // menu system can set to 1 to shut server down
-cvar_t *sv_mapname;
-cvar_t *sv_mapChecksum;
-cvar_t *sv_serverid;
-cvar_t *sv_minRate;
-cvar_t *sv_maxRate;
-cvar_t *sv_minPing;
-cvar_t *sv_maxPing;
-cvar_t *sv_gametype;
-cvar_t *sv_pure;
-cvar_t *sv_floodProtect;
-cvar_t *sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491)
-cvar_t *sv_strictAuth;
-cvar_t *sv_banFile;
-
-serverBan_t serverBans[SERVER_MAXBANS];
-int serverBansCount = 0;
-
-/*
-=============================================================================
-
-EVENT MESSAGES
-
-=============================================================================
-*/
-
-/*
-===============
-SV_ExpandNewlines
-
-Converts newlines to "\n" so a line prints nicer
-===============
-*/
-static char *SV_ExpandNewlines( char *in ) {
- static char string[1024];
- int l;
-
- l = 0;
- while ( *in && l < sizeof(string) - 3 ) {
- if ( *in == '\n' ) {
- string[l++] = '\\';
- string[l++] = 'n';
- } else {
- string[l++] = *in;
- }
- in++;
- }
- string[l] = 0;
-
- return string;
-}
-
-/*
-======================
-SV_ReplacePendingServerCommands
-
-FIXME: This is ugly
-======================
-*/
-#if 0 // unused
-static int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) {
- int i, index, csnum1, csnum2;
-
- for ( i = client->reliableSent+1; i <= client->reliableSequence; i++ ) {
- index = i & ( MAX_RELIABLE_COMMANDS - 1 );
- //
- if ( !Q_strncmp(cmd, client->reliableCommands[ index ], strlen("cs")) ) {
- sscanf(cmd, "cs %i", &csnum1);
- sscanf(client->reliableCommands[ index ], "cs %i", &csnum2);
- if ( csnum1 == csnum2 ) {
- Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );
- /*
- if ( client->netchan.remoteAddress.type != NA_BOT ) {
- Com_Printf( "WARNING: client %i removed double pending config string %i: %s\n", client-svs.clients, csnum1, cmd );
- }
- */
- return qtrue;
- }
- }
- }
- return qfalse;
-}
-#endif
-
-/*
-======================
-SV_AddServerCommand
-
-The given command will be transmitted to the client, and is guaranteed to
-not have future snapshot_t executed before it is executed
-======================
-*/
-void SV_AddServerCommand( client_t *client, const char *cmd ) {
- int index, i;
-
- // this is very ugly but it's also a waste to for instance send multiple config string updates
- // for the same config string index in one snapshot
-// if ( SV_ReplacePendingServerCommands( client, cmd ) ) {
-// return;
-// }
-
- // do not send commands until the gamestate has been sent
- if( client->state < CS_PRIMED )
- return;
-
- client->reliableSequence++;
- // if we would be losing an old command that hasn't been acknowledged,
- // we must drop the connection
- // we check == instead of >= so a broadcast print added by SV_DropClient()
- // doesn't cause a recursive drop client
- if ( client->reliableSequence - client->reliableAcknowledge == MAX_RELIABLE_COMMANDS + 1 ) {
- Com_Printf( "===== pending server commands =====\n" );
- for ( i = client->reliableAcknowledge + 1 ; i <= client->reliableSequence ; i++ ) {
- Com_Printf( "cmd %5d: %s\n", i, client->reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
- }
- Com_Printf( "cmd %5d: %s\n", i, cmd );
- SV_DropClient( client, "Server command overflow" );
- return;
- }
- index = client->reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );
- Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );
-}
-
-
-/*
-=================
-SV_SendServerCommand
-
-Sends a reliable command string to be interpreted by
-the client game module: "cp", "print", "chat", etc
-A NULL client will broadcast to all clients
-=================
-*/
-void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) {
- va_list argptr;
- byte message[MAX_MSGLEN];
- client_t *client;
- int j;
-
- va_start (argptr,fmt);
- Q_vsnprintf ((char *)message, sizeof(message), fmt,argptr);
- va_end (argptr);
-
- // Fix to http://aluigi.altervista.org/adv/q3msgboom-adv.txt
- // The actual cause of the bug is probably further downstream
- // and should maybe be addressed later, but this certainly
- // fixes the problem for now
- if ( strlen ((char *)message) > 1022 ) {
- return;
- }
-
- if ( cl != NULL ) {
- SV_AddServerCommand( cl, (char *)message );
- return;
- }
-
- // hack to echo broadcast prints to console
- if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5) ) {
- Com_Printf ("broadcast: %s\n", SV_ExpandNewlines((char *)message) );
- }
-
- // send the data to all relevent clients
- for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) {
- SV_AddServerCommand( client, (char *)message );
- }
-}
-
-
-/*
-==============================================================================
-
-MASTER SERVER FUNCTIONS
-
-==============================================================================
-*/
-
-/*
-================
-SV_MasterHeartbeat
-
-Send a message to the masters every few minutes to
-let it know we are alive, and log information.
-We will also have a heartbeat sent when a server
-changes from empty to non-empty, and full to non-full,
-but not on every player enter or exit.
-================
-*/
-#define HEARTBEAT_MSEC 300*1000
-#define HEARTBEAT_GAME "QuakeArena-1"
-void SV_MasterHeartbeat( void ) {
- static netadr_t adr[MAX_MASTER_SERVERS][2]; // [2] for v4 and v6 address for the same address string.
- int i;
- int res;
- int netenabled;
-
- netenabled = Cvar_VariableIntegerValue("net_enabled");
-
- // "dedicated 1" is for lan play, "dedicated 2" is for inet public play
- if (!com_dedicated || com_dedicated->integer != 2 || !(netenabled & (NET_ENABLEV4 | NET_ENABLEV6)))
- return; // only dedicated servers send heartbeats
-
- // if not time yet, don't send anything
- if ( svs.time < svs.nextHeartbeatTime )
- return;
-
- svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC;
-
- // send to group masters
- for (i = 0; i < MAX_MASTER_SERVERS; i++)
- {
- if(!sv_master[i]->string[0])
- continue;
-
- // see if we haven't already resolved the name
- // resolving usually causes hitches on win95, so only
- // do it when needed
- if(sv_master[i]->modified || (adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD))
- {
- sv_master[i]->modified = qfalse;
-
- if(netenabled & NET_ENABLEV4)
- {
- Com_Printf("Resolving %s (IPv4)\n", sv_master[i]->string);
- res = NET_StringToAdr(sv_master[i]->string, &adr[i][0], NA_IP);
-
- if(res == 2)
- {
- // if no port was specified, use the default master port
- adr[i][0].port = BigShort(PORT_MASTER);
- }
-
- if(res)
- Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][0]));
- else
- Com_Printf( "%s has no IPv4 address.\n", sv_master[i]->string);
- }
-
- if(netenabled & NET_ENABLEV6)
- {
- Com_Printf("Resolving %s (IPv6)\n", sv_master[i]->string);
- res = NET_StringToAdr(sv_master[i]->string, &adr[i][1], NA_IP6);
-
- if(res == 2)
- {
- // if no port was specified, use the default master port
- adr[i][1].port = BigShort(PORT_MASTER);
- }
-
- if(res)
- Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][1]));
- else
- Com_Printf( "%s has no IPv6 address.\n", sv_master[i]->string);
- }
-
- if(adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD)
- {
- // if the address failed to resolve, clear it
- // so we don't take repeated dns hits
- Com_Printf("Couldn't resolve address: %s\n", sv_master[i]->string);
- Cvar_Set(sv_master[i]->name, "");
- sv_master[i]->modified = qfalse;
- continue;
- }
- }
-
-
- Com_Printf ("Sending heartbeat to %s\n", sv_master[i]->string );
-
- // this command should be changed if the server info / status format
- // ever incompatably changes
-
- if(adr[i][0].type != NA_BAD)
- NET_OutOfBandPrint( NS_SERVER, adr[i][0], "heartbeat %s\n", HEARTBEAT_GAME );
- if(adr[i][1].type != NA_BAD)
- NET_OutOfBandPrint( NS_SERVER, adr[i][1], "heartbeat %s\n", HEARTBEAT_GAME );
- }
-}
-
-/*
-=================
-SV_MasterShutdown
-
-Informs all masters that this server is going down
-=================
-*/
-void SV_MasterShutdown( void ) {
- // send a hearbeat right now
- svs.nextHeartbeatTime = -9999;
- SV_MasterHeartbeat();
-
- // send it again to minimize chance of drops
- svs.nextHeartbeatTime = -9999;
- SV_MasterHeartbeat();
-
- // when the master tries to poll the server, it won't respond, so
- // it will be removed from the list
-}
-
-
-/*
-==============================================================================
-
-CONNECTIONLESS COMMANDS
-
-==============================================================================
-*/
-
-/*
-================
-SVC_Status
-
-Responds with all the info that qplug or qspy can see about the server
-and all connected players. Used for getting detailed information after
-the simple info query.
-================
-*/
-static void SVC_Status( netadr_t from ) {
- char player[1024];
- char status[MAX_MSGLEN];
- int i;
- client_t *cl;
- playerState_t *ps;
- int statusLength;
- int playerLength;
- char infostring[MAX_INFO_STRING];
-
- // ignore if we are in single player
- if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER ) {
- return;
- }
-
- strcpy( infostring, Cvar_InfoString( CVAR_SERVERINFO ) );
-
- // echo back the parameter to status. so master servers can use it as a challenge
- // to prevent timed spoofed reply packets that add ghost servers
- Info_SetValueForKey( infostring, "challenge", Cmd_Argv(1) );
-
- status[0] = 0;
- statusLength = 0;
-
- for (i=0 ; i < sv_maxclients->integer ; i++) {
- cl = &svs.clients[i];
- if ( cl->state >= CS_CONNECTED ) {
- ps = SV_GameClientNum( i );
- Com_sprintf (player, sizeof(player), "%i %i \"%s\"\n",
- ps->persistant[PERS_SCORE], cl->ping, cl->name);
- playerLength = strlen(player);
- if (statusLength + playerLength >= sizeof(status) ) {
- break; // can't hold any more
- }
- strcpy (status + statusLength, player);
- statusLength += playerLength;
- }
- }
-
- NET_OutOfBandPrint( NS_SERVER, from, "statusResponse\n%s\n%s", infostring, status );
-}
-
-/*
-================
-SVC_Info
-
-Responds with a short info message that should be enough to determine
-if a user is interested in a server to do a full status
-================
-*/
-void SVC_Info( netadr_t from ) {
- int i, count;
- char *gamedir;
- char infostring[MAX_INFO_STRING];
-
- // ignore if we are in single player
- if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) {
- return;
- }
-
- /*
- * Check whether Cmd_Argv(1) has a sane length. This was not done in the original Quake3 version which led
- * to the Infostring bug discovered by Luigi Auriemma. See http://aluigi.altervista.org/ for the advisory.
- */
-
- // A maximum challenge length of 128 should be more than plenty.
- if(strlen(Cmd_Argv(1)) > 128)
- return;
-
- // don't count privateclients
- count = 0;
- for ( i = sv_privateClients->integer ; i < sv_maxclients->integer ; i++ ) {
- if ( svs.clients[i].state >= CS_CONNECTED ) {
- count++;
- }
- }
-
- infostring[0] = 0;
-
- // echo back the parameter to status. so servers can use it as a challenge
- // to prevent timed spoofed reply packets that add ghost servers
- Info_SetValueForKey( infostring, "challenge", Cmd_Argv(1) );
-
- Info_SetValueForKey( infostring, "protocol", va("%i", PROTOCOL_VERSION) );
- Info_SetValueForKey( infostring, "hostname", sv_hostname->string );
- Info_SetValueForKey( infostring, "mapname", sv_mapname->string );
- Info_SetValueForKey( infostring, "clients", va("%i", count) );
- Info_SetValueForKey( infostring, "sv_maxclients",
- va("%i", sv_maxclients->integer - sv_privateClients->integer ) );
- Info_SetValueForKey( infostring, "gametype", va("%i", sv_gametype->integer ) );
- Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) );
-
-#ifdef USE_VOIP
- if (sv_voip->integer) {
- Info_SetValueForKey( infostring, "voip", va("%i", sv_voip->integer ) );
- }
-#endif
-
- if( sv_minPing->integer ) {
- Info_SetValueForKey( infostring, "minPing", va("%i", sv_minPing->integer) );
- }
- if( sv_maxPing->integer ) {
- Info_SetValueForKey( infostring, "maxPing", va("%i", sv_maxPing->integer) );
- }
- gamedir = Cvar_VariableString( "fs_game" );
- if( *gamedir ) {
- Info_SetValueForKey( infostring, "game", gamedir );
- }
-
- NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring );
-}
-
-/*
-================
-SVC_FlushRedirect
-
-================
-*/
-static void SV_FlushRedirect( char *outputbuf ) {
- NET_OutOfBandPrint( NS_SERVER, svs.redirectAddress, "print\n%s", outputbuf );
-}
-
-/*
-===============
-SVC_RemoteCommand
-
-An rcon packet arrived from the network.
-Shift down the remaining args
-Redirect all printfs
-===============
-*/
-static void SVC_RemoteCommand( netadr_t from, msg_t *msg ) {
- qboolean valid;
- unsigned int time;
- char remaining[1024];
- // TTimo - scaled down to accumulate, but not overflow anything network wise, print wise etc.
- // (OOB messages are the bottleneck here)
-#define SV_OUTPUTBUF_LENGTH (1024 - 16)
- char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
- static unsigned int lasttime = 0;
- char *cmd_aux;
-
- // TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=534
- time = Com_Milliseconds();
- if ( (unsigned)( time - lasttime ) < 500u ) {
- return;
- }
- lasttime = time;
-
- if ( !strlen( sv_rconPassword->string ) ||
- strcmp (Cmd_Argv(1), sv_rconPassword->string) ) {
- valid = qfalse;
- Com_Printf ("Bad rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) );
- } else {
- valid = qtrue;
- Com_Printf ("Rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) );
- }
-
- // start redirecting all print outputs to the packet
- svs.redirectAddress = from;
- Com_BeginRedirect (sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
-
- if ( !strlen( sv_rconPassword->string ) ) {
- Com_Printf ("No rconpassword set on the server.\n");
- } else if ( !valid ) {
- Com_Printf ("Bad rconpassword.\n");
- } else {
- remaining[0] = 0;
-
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543
- // get the command directly, "rcon <pass> <command>" to avoid quoting issues
- // extract the command by walking
- // since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing
- cmd_aux = Cmd_Cmd();
- cmd_aux+=4;
- while(cmd_aux[0]==' ')
- cmd_aux++;
- while(cmd_aux[0] && cmd_aux[0]!=' ') // password
- cmd_aux++;
- while(cmd_aux[0]==' ')
- cmd_aux++;
-
- Q_strcat( remaining, sizeof(remaining), cmd_aux);
-
- Cmd_ExecuteString (remaining);
-
- }
-
- Com_EndRedirect ();
-}
-
-/*
-=================
-SV_ConnectionlessPacket
-
-A connectionless packet has four leading 0xff
-characters to distinguish it from a game channel.
-Clients that are in the game can still send
-connectionless packets.
-=================
-*/
-static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
- char *s;
- char *c;
-
- MSG_BeginReadingOOB( msg );
- MSG_ReadLong( msg ); // skip the -1 marker
-
- if (!Q_strncmp("connect", (char *) &msg->data[4], 7)) {
- Huff_Decompress(msg, 12);
- }
-
- s = MSG_ReadStringLine( msg );
- Cmd_TokenizeString( s );
-
- c = Cmd_Argv(0);
- Com_DPrintf ("SV packet %s : %s\n", NET_AdrToString(from), c);
-
- if (!Q_stricmp(c, "getstatus")) {
- SVC_Status( from );
- } else if (!Q_stricmp(c, "getinfo")) {
- SVC_Info( from );
- } else if (!Q_stricmp(c, "getchallenge")) {
- SV_GetChallenge(from);
- } else if (!Q_stricmp(c, "connect")) {
- SV_DirectConnect( from );
-#ifndef STANDALONE
- } else if (!Q_stricmp(c, "ipAuthorize")) {
- SV_AuthorizeIpPacket( from );
-#endif
- } else if (!Q_stricmp(c, "rcon")) {
- SVC_RemoteCommand( from, msg );
- } else if (!Q_stricmp(c, "disconnect")) {
- // if a client starts up a local server, we may see some spurious
- // server disconnect messages when their new server sees our final
- // sequenced messages to the old client
- } else {
- Com_DPrintf ("bad connectionless packet from %s:\n%s\n"
- , NET_AdrToString (from), s);
- }
-}
-
-//============================================================================
-
-/*
-=================
-SV_ReadPackets
-=================
-*/
-void SV_PacketEvent( netadr_t from, msg_t *msg ) {
- int i;
- client_t *cl;
- int qport;
-
- // check for connectionless packet (0xffffffff) first
- if ( msg->cursize >= 4 && *(int *)msg->data == -1) {
- SV_ConnectionlessPacket( from, msg );
- return;
- }
-
- // read the qport out of the message so we can fix up
- // stupid address translating routers
- MSG_BeginReadingOOB( msg );
- MSG_ReadLong( msg ); // sequence number
- qport = MSG_ReadShort( msg ) & 0xffff;
-
- // find which client the message is from
- for (i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
- if (cl->state == CS_FREE) {
- continue;
- }
- if ( !NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) ) {
- continue;
- }
- // it is possible to have multiple clients from a single IP
- // address, so they are differentiated by the qport variable
- if (cl->netchan.qport != qport) {
- continue;
- }
-
- // the IP port can't be used to differentiate them, because
- // some address translating routers periodically change UDP
- // port assignments
- if (cl->netchan.remoteAddress.port != from.port) {
- Com_Printf( "SV_PacketEvent: fixing up a translated port\n" );
- cl->netchan.remoteAddress.port = from.port;
- }
-
- // make sure it is a valid, in sequence packet
- if (SV_Netchan_Process(cl, msg)) {
- // zombie clients still need to do the Netchan_Process
- // to make sure they don't need to retransmit the final
- // reliable message, but they don't do any other processing
- if (cl->state != CS_ZOMBIE) {
- cl->lastPacketTime = svs.time; // don't timeout
- SV_ExecuteClientMessage( cl, msg );
- }
- }
- return;
- }
-
- // if we received a sequenced packet from an address we don't recognize,
- // send an out of band disconnect packet to it
- NET_OutOfBandPrint( NS_SERVER, from, "disconnect" );
-}
-
-
-/*
-===================
-SV_CalcPings
-
-Updates the cl->ping variables
-===================
-*/
-static void SV_CalcPings( void ) {
- int i, j;
- client_t *cl;
- int total, count;
- int delta;
- playerState_t *ps;
-
- for (i=0 ; i < sv_maxclients->integer ; i++) {
- cl = &svs.clients[i];
- if ( cl->state != CS_ACTIVE ) {
- cl->ping = 999;
- continue;
- }
- if ( !cl->gentity ) {
- cl->ping = 999;
- continue;
- }
- if ( cl->gentity->r.svFlags & SVF_BOT ) {
- cl->ping = 0;
- continue;
- }
-
- total = 0;
- count = 0;
- for ( j = 0 ; j < PACKET_BACKUP ; j++ ) {
- if ( cl->frames[j].messageAcked <= 0 ) {
- continue;
- }
- delta = cl->frames[j].messageAcked - cl->frames[j].messageSent;
- count++;
- total += delta;
- }
- if (!count) {
- cl->ping = 999;
- } else {
- cl->ping = total/count;
- if ( cl->ping > 999 ) {
- cl->ping = 999;
- }
- }
-
- // let the game dll know about the ping
- ps = SV_GameClientNum( i );
- ps->ping = cl->ping;
- }
-}
-
-/*
-==================
-SV_CheckTimeouts
-
-If a packet has not been received from a client for timeout->integer
-seconds, drop the conneciton. Server time is used instead of
-realtime to avoid dropping the local client while debugging.
-
-When a client is normally dropped, the client_t goes into a zombie state
-for a few seconds to make sure any final reliable message gets resent
-if necessary
-==================
-*/
-static void SV_CheckTimeouts( void ) {
- int i;
- client_t *cl;
- int droppoint;
- int zombiepoint;
-
- droppoint = svs.time - 1000 * sv_timeout->integer;
- zombiepoint = svs.time - 1000 * sv_zombietime->integer;
-
- for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
- // message times may be wrong across a changelevel
- if (cl->lastPacketTime > svs.time) {
- cl->lastPacketTime = svs.time;
- }
-
- if (cl->state == CS_ZOMBIE
- && cl->lastPacketTime < zombiepoint) {
- // using the client id cause the cl->name is empty at this point
- Com_DPrintf( "Going from CS_ZOMBIE to CS_FREE for client %d\n", i );
- cl->state = CS_FREE; // can now be reused
- continue;
- }
- if ( cl->state >= CS_CONNECTED && cl->lastPacketTime < droppoint) {
- // wait several frames so a debugger session doesn't
- // cause a timeout
- if ( ++cl->timeoutCount > 5 ) {
- SV_DropClient (cl, "timed out");
- cl->state = CS_FREE; // don't bother with zombie state
- }
- } else {
- cl->timeoutCount = 0;
- }
- }
-}
-
-
-/*
-==================
-SV_CheckPaused
-==================
-*/
-static qboolean SV_CheckPaused( void ) {
- int count;
- client_t *cl;
- int i;
-
- if ( !cl_paused->integer ) {
- return qfalse;
- }
-
- // only pause if there is just a single client connected
- count = 0;
- for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
- if ( cl->state >= CS_CONNECTED && cl->netchan.remoteAddress.type != NA_BOT ) {
- count++;
- }
- }
-
- if ( count > 1 ) {
- // don't pause
- if (sv_paused->integer)
- Cvar_Set("sv_paused", "0");
- return qfalse;
- }
-
- if (!sv_paused->integer)
- Cvar_Set("sv_paused", "1");
- return qtrue;
-}
-
-/*
-==================
-SV_Frame
-
-Player movement occurs as a result of packet events, which
-happen before SV_Frame is called
-==================
-*/
-void SV_Frame( int msec ) {
- int frameMsec;
- int startTime;
-
- // the menu kills the server with this cvar
- if ( sv_killserver->integer ) {
- SV_Shutdown ("Server was killed");
- Cvar_Set( "sv_killserver", "0" );
- return;
- }
-
- if (!com_sv_running->integer)
- {
- // Running as a server, but no map loaded
-#ifdef DEDICATED
- // Block until something interesting happens
- Sys_Sleep(-1);
-#endif
-
- return;
- }
-
- // allow pause if only the local client is connected
- if ( SV_CheckPaused() ) {
- return;
- }
-
- // if it isn't time for the next frame, do nothing
- if ( sv_fps->integer < 1 ) {
- Cvar_Set( "sv_fps", "10" );
- }
-
- frameMsec = 1000 / sv_fps->integer * com_timescale->value;
- // don't let it scale below 1ms
- if(frameMsec < 1)
- {
- Cvar_Set("timescale", va("%f", sv_fps->integer / 1000.0f));
- frameMsec = 1;
- }
-
- sv.timeResidual += msec;
-
- if (!com_dedicated->integer) SV_BotFrame (sv.time + sv.timeResidual);
-
- if ( com_dedicated->integer && sv.timeResidual < frameMsec ) {
- // NET_Sleep will give the OS time slices until either get a packet
- // or time enough for a server frame has gone by
- NET_Sleep(frameMsec - sv.timeResidual);
- return;
- }
-
- // if time is about to hit the 32nd bit, kick all clients
- // and clear sv.time, rather
- // than checking for negative time wraparound everywhere.
- // 2giga-milliseconds = 23 days, so it won't be too often
- if ( svs.time > 0x70000000 ) {
- SV_Shutdown( "Restarting server due to time wrapping" );
- Cbuf_AddText( va( "map %s\n", Cvar_VariableString( "mapname" ) ) );
- return;
- }
- // this can happen considerably earlier when lots of clients play and the map doesn't change
- if ( svs.nextSnapshotEntities >= 0x7FFFFFFE - svs.numSnapshotEntities ) {
- SV_Shutdown( "Restarting server due to numSnapshotEntities wrapping" );
- Cbuf_AddText( va( "map %s\n", Cvar_VariableString( "mapname" ) ) );
- return;
- }
-
- if( sv.restartTime && sv.time >= sv.restartTime ) {
- sv.restartTime = 0;
- Cbuf_AddText( "map_restart 0\n" );
- return;
- }
-
- // update infostrings if anything has been changed
- if ( cvar_modifiedFlags & CVAR_SERVERINFO ) {
- SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) );
- cvar_modifiedFlags &= ~CVAR_SERVERINFO;
- }
- if ( cvar_modifiedFlags & CVAR_SYSTEMINFO ) {
- SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString_Big( CVAR_SYSTEMINFO ) );
- cvar_modifiedFlags &= ~CVAR_SYSTEMINFO;
- }
-
- if ( com_speeds->integer ) {
- startTime = Sys_Milliseconds ();
- } else {
- startTime = 0; // quite a compiler warning
- }
-
- // update ping based on the all received frames
- SV_CalcPings();
-
- if (com_dedicated->integer) SV_BotFrame (sv.time);
-
- // run the game simulation in chunks
- while ( sv.timeResidual >= frameMsec ) {
- sv.timeResidual -= frameMsec;
- svs.time += frameMsec;
- sv.time += frameMsec;
-
- // let everything in the world think and move
- VM_Call (gvm, GAME_RUN_FRAME, sv.time);
- }
-
- if ( com_speeds->integer ) {
- time_game = Sys_Milliseconds () - startTime;
- }
-
- // check timeouts
- SV_CheckTimeouts();
-
- // send messages back to the clients
- SV_SendClientMessages();
-
- // send a heartbeat to the master if needed
- SV_MasterHeartbeat();
-}
-
-//============================================================================
-
diff --git a/engine/code/server/sv_net_chan.c b/engine/code/server/sv_net_chan.c
deleted file mode 100644
index 5b2f500..0000000
--- a/engine/code/server/sv_net_chan.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-#include "server.h"
-
-/*
-==============
-SV_Netchan_Encode
-
- // first four bytes of the data are always:
- long reliableAcknowledge;
-
-==============
-*/
-static void SV_Netchan_Encode( client_t *client, msg_t *msg ) {
- long i, index;
- byte key, *string;
- int srdc, sbit;
- qboolean soob;
-
- if ( msg->cursize < SV_ENCODE_START ) {
- return;
- }
-
- srdc = msg->readcount;
- sbit = msg->bit;
- soob = msg->oob;
-
- msg->bit = 0;
- msg->readcount = 0;
- msg->oob = qfalse;
-
- /* reliableAcknowledge = */ MSG_ReadLong(msg);
-
- msg->oob = soob;
- msg->bit = sbit;
- msg->readcount = srdc;
-
- string = (byte *)client->lastClientCommandString;
- index = 0;
- // xor the client challenge with the netchan sequence number
- key = client->challenge ^ client->netchan.outgoingSequence;
- for (i = SV_ENCODE_START; i < msg->cursize; i++) {
- // modify the key with the last received and with this message acknowledged client command
- if (!string[index])
- index = 0;
- if (string[index] > 127 || string[index] == '%') {
- key ^= '.' << (i & 1);
- }
- else {
- key ^= string[index] << (i & 1);
- }
- index++;
- // encode the data with this key
- *(msg->data + i) = *(msg->data + i) ^ key;
- }
-}
-
-/*
-==============
-SV_Netchan_Decode
-
- // first 12 bytes of the data are always:
- long serverId;
- long messageAcknowledge;
- long reliableAcknowledge;
-
-==============
-*/
-static void SV_Netchan_Decode( client_t *client, msg_t *msg ) {
- int serverId, messageAcknowledge, reliableAcknowledge;
- int i, index, srdc, sbit;
- qboolean soob;
- byte key, *string;
-
- srdc = msg->readcount;
- sbit = msg->bit;
- soob = msg->oob;
-
- msg->oob = qfalse;
-
- serverId = MSG_ReadLong(msg);
- messageAcknowledge = MSG_ReadLong(msg);
- reliableAcknowledge = MSG_ReadLong(msg);
-
- msg->oob = soob;
- msg->bit = sbit;
- msg->readcount = srdc;
-
- string = (byte *)client->reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ];
- index = 0;
- //
- key = client->challenge ^ serverId ^ messageAcknowledge;
- for (i = msg->readcount + SV_DECODE_START; i < msg->cursize; i++) {
- // modify the key with the last sent and acknowledged server command
- if (!string[index])
- index = 0;
- if (string[index] > 127 || string[index] == '%') {
- key ^= '.' << (i & 1);
- }
- else {
- key ^= string[index] << (i & 1);
- }
- index++;
- // decode the data with this key
- *(msg->data + i) = *(msg->data + i) ^ key;
- }
-}
-
-/*
-=================
-SV_Netchan_TransmitNextFragment
-=================
-*/
-void SV_Netchan_TransmitNextFragment( client_t *client ) {
- Netchan_TransmitNextFragment( &client->netchan );
- if (!client->netchan.unsentFragments)
- {
- // make sure the netchan queue has been properly initialized (you never know)
- if ((!client->netchan_end_queue) && (client->state >= CS_CONNECTED)) {
- Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment\n");
- }
- // the last fragment was transmitted, check wether we have queued messages
- if (client->netchan_start_queue) {
- netchan_buffer_t *netbuf;
- Com_DPrintf("#462 Netchan_TransmitNextFragment: popping a queued message for transmit\n");
- netbuf = client->netchan_start_queue;
- SV_Netchan_Encode( client, &netbuf->msg );
- Netchan_Transmit( &client->netchan, netbuf->msg.cursize, netbuf->msg.data );
- // pop from queue
- client->netchan_start_queue = netbuf->next;
- if (!client->netchan_start_queue) {
- Com_DPrintf("#462 Netchan_TransmitNextFragment: emptied queue\n");
- client->netchan_end_queue = &client->netchan_start_queue;
- }
- else
- Com_DPrintf("#462 Netchan_TransmitNextFragment: remaining queued message\n");
- Z_Free(netbuf);
- }
- }
-}
-
-
-/*
-===============
-SV_Netchan_Transmit
-TTimo
-https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=462
-if there are some unsent fragments (which may happen if the snapshots
-and the gamestate are fragmenting, and collide on send for instance)
-then buffer them and make sure they get sent in correct order
-================
-*/
-
-void SV_Netchan_Transmit( client_t *client, msg_t *msg) { //int length, const byte *data ) {
- MSG_WriteByte( msg, svc_EOF );
- if (client->netchan.unsentFragments) {
- netchan_buffer_t *netbuf;
- Com_DPrintf("#462 SV_Netchan_Transmit: unsent fragments, stacked\n");
- netbuf = (netchan_buffer_t *)Z_Malloc(sizeof(netchan_buffer_t));
- // store the msg, we can't store it encoded, as the encoding depends on stuff we still have to finish sending
- MSG_Copy(&netbuf->msg, netbuf->msgBuffer, sizeof( netbuf->msgBuffer ), msg);
- netbuf->next = NULL;
- // insert it in the queue, the message will be encoded and sent later
- *client->netchan_end_queue = netbuf;
- client->netchan_end_queue = &(*client->netchan_end_queue)->next;
- // emit the next fragment of the current message for now
- Netchan_TransmitNextFragment(&client->netchan);
- } else {
- SV_Netchan_Encode( client, msg );
- Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
- }
-}
-
-/*
-=================
-Netchan_SV_Process
-=================
-*/
-qboolean SV_Netchan_Process( client_t *client, msg_t *msg ) {
- int ret;
- ret = Netchan_Process( &client->netchan, msg );
- if (!ret)
- return qfalse;
- SV_Netchan_Decode( client, msg );
- return qtrue;
-}
-
diff --git a/engine/code/server/sv_rankings.c b/engine/code/server/sv_rankings.c
deleted file mode 100644
index 90a90aa..0000000
--- a/engine/code/server/sv_rankings.c
+++ /dev/null
@@ -1,1537 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// sv_rankings.c -- global rankings interface
-
-#include "server.h"
-#include "..\rankings\1.0\gr\grapi.h"
-#include "..\rankings\1.0\gr\grlog.h"
-
-typedef struct
-{
- GR_CONTEXT context;
- uint64_t game_id;
- uint64_t match;
- uint64_t player_id;
- GR_PLAYER_TOKEN token;
- grank_status_t grank_status;
- grank_status_t final_status; // status to set after cleanup
- uint32_t grank; // global rank
- char name[32];
-} ranked_player_t;
-
-static int s_rankings_contexts = 0;
-static qboolean s_rankings_active = qfalse;
-static GR_CONTEXT s_server_context = 0;
-static uint64_t s_server_match = 0;
-static char* s_rankings_game_key = NULL;
-static uint64_t s_rankings_game_id = 0;
-static ranked_player_t* s_ranked_players = NULL;
-static qboolean s_server_quitting = qfalse;
-static const char s_ascii_encoding[] =
- "0123456789abcdef"
- "ghijklmnopqrstuv"
- "wxyzABCDEFGHIJKL"
- "MNOPQRSTUVWXYZ[]";
-
-// private functions
-static void SV_RankNewGameCBF( GR_NEWGAME* gr_newgame, void* cbf_arg );
-static void SV_RankUserCBF( GR_LOGIN* gr_login, void* cbf_arg );
-static void SV_RankJoinGameCBF( GR_JOINGAME* gr_joingame, void* cbf_arg );
-static void SV_RankSendReportsCBF( GR_STATUS* gr_status, void* cbf_arg );
-static void SV_RankCleanupCBF( GR_STATUS* gr_status, void* cbf_arg );
-static void SV_RankCloseContext( ranked_player_t* ranked_player );
-static int SV_RankAsciiEncode( char* dest, const unsigned char* src,
- int src_len );
-static int SV_RankAsciiDecode( unsigned char* dest, const char* src,
- int src_len );
-static void SV_RankEncodeGameID( uint64_t game_id, char* result,
- int len );
-static uint64_t SV_RankDecodePlayerID( const char* string );
-static void SV_RankDecodePlayerKey( const char* string, GR_PLAYER_TOKEN key );
-static char* SV_RankStatusString( GR_STATUS status );
-static void SV_RankError( const char* fmt, ... );
-static char SV_RankGameKey[64];
-
-/*
-================
-SV_RankBegin
-================
-*/
-void SV_RankBegin( char *gamekey )
-{
- GR_INIT init;
- GR_STATUS status;
-
- assert( s_rankings_contexts == 0 );
- assert( !s_rankings_active );
- assert( s_ranked_players == NULL );
-
- if( sv_enableRankings->integer == 0 || Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER )
- {
- s_rankings_active = qfalse;
- if( sv_rankingsActive->integer == 1 )
- {
- Cvar_Set( "sv_rankingsActive", "0" );
- }
- return;
- }
-
- // only allow official game key on pure servers
- if( strcmp(gamekey, GR_GAMEKEY) == 0 )
- {
-/*
- if( Cvar_VariableValue("sv_pure") != 1 )
- {
- Cvar_Set( "sv_enableRankings", "0" );
- return;
- }
-*/
-
- // substitute game-specific game key
- switch( (int)Cvar_VariableValue("g_gametype") )
- {
- case GT_FFA:
- gamekey = "Q3 Free For All";
- break;
- case GT_TOURNAMENT:
- gamekey = "Q3 Tournament";
- break;
- case GT_TEAM:
- gamekey = "Q3 Team Deathmatch";
- break;
- case GT_CTF:
- gamekey = "Q3 Capture the Flag";
- break;
- case GT_1FCTF:
- gamekey = "Q3 One Flag CTF";
- break;
- case GT_OBELISK:
- gamekey = "Q3 Overload";
- break;
- case GT_HARVESTER:
- gamekey = "Q3 Harvester";
- break;
- default:
- break;
- }
- }
- s_rankings_game_key = gamekey;
-
- // initialize rankings
- GRankLogLevel( GRLOG_OFF );
- memset(SV_RankGameKey,0,sizeof(SV_RankGameKey));
- strncpy(SV_RankGameKey,gamekey,sizeof(SV_RankGameKey)-1);
- init = GRankInit( 1, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END );
- s_server_context = init.context;
- s_rankings_contexts++;
- Com_DPrintf( "SV_RankBegin(); GR_GAMEKEY is %s\n", gamekey );
- Com_DPrintf( "SV_RankBegin(); s_rankings_contexts=%d\n",s_rankings_contexts );
- Com_DPrintf( "SV_RankBegin(); s_server_context=%d\n",init.context );
-
- // new game
- if(!strlen(Cvar_VariableString( "sv_leagueName" )))
- {
- status = GRankNewGameAsync
- (
- s_server_context,
- SV_RankNewGameCBF,
- NULL,
- GR_OPT_LEAGUENAME,
- (void*)(Cvar_VariableString( "sv_leagueName" )),
- GR_OPT_END
- );
- }
- else
- {
- status = GRankNewGameAsync
- (
- s_server_context,
- SV_RankNewGameCBF,
- NULL,
- GR_OPT_END
- );
- }
-
- if( status != GR_STATUS_PENDING )
- {
- SV_RankError( "SV_RankBegin: Expected GR_STATUS_PENDING, got %s",
- SV_RankStatusString( status ) );
- return;
- }
-
- // logging
- if( com_developer->value )
- {
- GRankLogLevel( GRLOG_TRACE );
- }
-
- // allocate rankings info for each player
- s_ranked_players = Z_Malloc( sv_maxclients->value *
- sizeof(ranked_player_t) );
- memset( (void*)s_ranked_players, 0 ,sv_maxclients->value
- * sizeof(ranked_player_t));
-}
-
-/*
-================
-SV_RankEnd
-================
-*/
-void SV_RankEnd( void )
-{
- GR_STATUS status;
- int i;
-
- Com_DPrintf( "SV_RankEnd();\n" );
-
- if( !s_rankings_active )
- {
- // cleanup after error during game
- if( s_ranked_players != NULL )
- {
- for( i = 0; i < sv_maxclients->value; i++ )
- {
- if( s_ranked_players[i].context != 0 )
- {
- SV_RankCloseContext( &(s_ranked_players[i]) );
- }
- }
- }
- if( s_server_context != 0 )
- {
- SV_RankCloseContext( NULL );
- }
-
- return;
- }
-
- for( i = 0; i < sv_maxclients->value; i++ )
- {
- if( s_ranked_players[i].grank_status == QGR_STATUS_ACTIVE )
- {
- SV_RankUserLogout( i );
- Com_DPrintf( "SV_RankEnd: SV_RankUserLogout %d\n",i );
- }
- }
-
- assert( s_server_context != 0 );
-
- // send match reports, proceed to SV_RankSendReportsCBF
- status = GRankSendReportsAsync
- (
- s_server_context,
- 0,
- SV_RankSendReportsCBF,
- NULL,
- GR_OPT_END
- );
-
- if( status != GR_STATUS_PENDING )
- {
- SV_RankError( "SV_RankEnd: Expected GR_STATUS_PENDING, got %s",
- SV_RankStatusString( status ) );
- }
-
- s_rankings_active = qfalse;
- Cvar_Set( "sv_rankingsActive", "0" );
-}
-
-/*
-================
-SV_RankPoll
-================
-*/
-void SV_RankPoll( void )
-{
- GRankPoll();
-}
-
-/*
-================
-SV_RankCheckInit
-================
-*/
-qboolean SV_RankCheckInit( void )
-{
- return (s_rankings_contexts > 0);
-}
-
-/*
-================
-SV_RankActive
-================
-*/
-qboolean SV_RankActive( void )
-{
- return s_rankings_active;
-}
-
-/*
-=================
-SV_RankUserStatus
-=================
-*/
-grank_status_t SV_RankUserStatus( int index )
-{
- if( !s_rankings_active )
- {
- return GR_STATUS_ERROR;
- }
-
- assert( s_ranked_players != NULL );
- assert( index >= 0 );
- assert( index < sv_maxclients->value );
-
- return s_ranked_players[index].grank_status;
-}
-
-/*
-================
-SV_RankUserGRank
-================
-*/
-int SV_RankUserGrank( int index )
-{
- if( !s_rankings_active )
- {
- return 0;
- }
-
- assert( s_ranked_players != NULL );
- assert( index >= 0 );
- assert( index < sv_maxclients->value );
-
- return s_ranked_players[index].grank;
-}
-
-/*
-================
-SV_RankUserReset
-================
-*/
-void SV_RankUserReset( int index )
-{
- if( !s_rankings_active )
- {
- return;
- }
-
- assert( s_ranked_players != NULL );
- assert( index >= 0 );
- assert( index < sv_maxclients->value );
-
- switch( s_ranked_players[index].grank_status )
- {
- case QGR_STATUS_SPECTATOR:
- case QGR_STATUS_NO_USER:
- case QGR_STATUS_BAD_PASSWORD:
- case QGR_STATUS_USER_EXISTS:
- case QGR_STATUS_NO_MEMBERSHIP:
- case QGR_STATUS_TIMEOUT:
- case QGR_STATUS_ERROR:
- s_ranked_players[index].grank_status = QGR_STATUS_NEW;
- break;
- default:
- break;
- }
-}
-
-/*
-================
-SV_RankUserSpectate
-================
-*/
-void SV_RankUserSpectate( int index )
-{
- if( !s_rankings_active )
- {
- return;
- }
-
- assert( s_ranked_players != NULL );
- assert( index >= 0 );
- assert( index < sv_maxclients->value );
-
- // GRANK_FIXME - check current status?
- s_ranked_players[index].grank_status = QGR_STATUS_SPECTATOR;
-}
-
-/*
-================
-SV_RankUserCreate
-================
-*/
-void SV_RankUserCreate( int index, char* username, char* password,
- char* email )
-{
- GR_INIT init;
- GR_STATUS status;
-
- assert( index >= 0 );
- assert( index < sv_maxclients->value );
- assert( username != NULL );
- assert( password != NULL );
- assert( email != NULL );
- assert( s_ranked_players );
- assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE );
-
- Com_DPrintf( "SV_RankUserCreate( %d, %s, \"****\", %s );\n", index,
- username, email );
-
- if( !s_rankings_active )
- {
- Com_DPrintf( "SV_RankUserCreate: Not ready to create\n" );
- s_ranked_players[index].grank_status = QGR_STATUS_ERROR;
- return;
- }
-
- if( s_ranked_players[index].grank_status == QGR_STATUS_ACTIVE )
- {
- Com_DPrintf( "SV_RankUserCreate: Got Create from active player\n" );
- return;
- }
-
- // get a separate context for the new user
- init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END );
- s_ranked_players[index].context = init.context;
- s_rankings_contexts++;
- Com_DPrintf( "SV_RankUserCreate(); s_rankings_contexts=%d\n",s_rankings_contexts );
- Com_DPrintf( "SV_RankUserCreate(); s_ranked_players[%d].context=%d\n",index,init.context );
-
- // attempt to create a new account, proceed to SV_RankUserCBF
- status = GRankUserCreateAsync
- (
- s_ranked_players[index].context,
- username,
- password,
- email,
- SV_RankUserCBF,
- (void*)&s_ranked_players[index],
- GR_OPT_END
- );
-
- if( status == GR_STATUS_PENDING )
- {
- s_ranked_players[index].grank_status = QGR_STATUS_PENDING;
- s_ranked_players[index].final_status = QGR_STATUS_NEW;
- }
- else
- {
- SV_RankError( "SV_RankUserCreate: Expected GR_STATUS_PENDING, got %s",
- SV_RankStatusString( status ) );
- }
-}
-
-/*
-================
-SV_RankUserLogin
-================
-*/
-void SV_RankUserLogin( int index, char* username, char* password )
-{
- GR_INIT init;
- GR_STATUS status;
-
- assert( index >= 0 );
- assert( index < sv_maxclients->value );
- assert( username != NULL );
- assert( password != NULL );
- assert( s_ranked_players );
- assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE );
-
- Com_DPrintf( "SV_RankUserLogin( %d, %s, \"****\" );\n", index, username );
-
- if( !s_rankings_active )
- {
- Com_DPrintf( "SV_RankUserLogin: Not ready for login\n" );
- s_ranked_players[index].grank_status = QGR_STATUS_ERROR;
- return;
- }
-
- if( s_ranked_players[index].grank_status == QGR_STATUS_ACTIVE )
- {
- Com_DPrintf( "SV_RankUserLogin: Got Login from active player\n" );
- return;
- }
-
- // get a separate context for the new user
- init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END );
- s_ranked_players[index].context = init.context;
- s_rankings_contexts++;
- Com_DPrintf( "SV_RankUserLogin(); s_rankings_contexts=%d\n",s_rankings_contexts );
- Com_DPrintf( "SV_RankUserLogin(); s_ranked_players[%d].context=%d\n",index,init.context );
-
- // login user, proceed to SV_RankUserCBF
- status = GRankUserLoginAsync
- (
- s_ranked_players[index].context,
- username,
- password,
- SV_RankUserCBF,
- (void*)&s_ranked_players[index],
- GR_OPT_END
- );
-
- if( status == GR_STATUS_PENDING )
- {
- s_ranked_players[index].grank_status = QGR_STATUS_PENDING;
- s_ranked_players[index].final_status = QGR_STATUS_NEW;
- }
- else
- {
- SV_RankError( "SV_RankUserLogin: Expected GR_STATUS_PENDING, got %s",
- SV_RankStatusString( status ) );
- }
-}
-
-/*
-===================
-SV_RankUserValidate
-===================
-*/
-qboolean SV_RankUserValidate( int index, const char* player_id, const char* key, int token_len, int rank, char* name )
-{
- GR_INIT init;
- GR_STATUS status;
- qboolean rVal;
- ranked_player_t* ranked_player;
- int i;
-
- assert( s_ranked_players );
- assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE );
-
- rVal = qfalse;
-
- if( !s_rankings_active )
- {
- Com_DPrintf( "SV_RankUserValidate: Not ready to validate\n" );
- s_ranked_players[index].grank_status = QGR_STATUS_ERROR;
- return rVal;
- }
-
- ranked_player = &(s_ranked_players[index]);
-
- if ( (player_id != NULL) && (key != NULL))
- {
- // the real player_id and key is set when SV_RankJoinGameCBF
- // is called we do this so that SV_RankUserValidate
- // can be shared by both server side login and client side login
-
- // for client side logined in players
- // server is creating GR_OPT_PLAYERCONTEXT
- init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END );
- ranked_player->context = init.context;
- s_rankings_contexts++;
- Com_DPrintf( "SV_RankUserValidate(); s_rankings_contexts=%d\n",s_rankings_contexts );
- Com_DPrintf( "SV_RankUserValidate(); s_ranked_players[%d].context=%d\n",index,init.context );
-
- // uudecode player id and player token
- ranked_player->player_id = SV_RankDecodePlayerID(player_id);
- Com_DPrintf( "SV_RankUserValidate(); ranked_player->player_id =%u\n", (uint32_t)ranked_player->player_id );
- SV_RankDecodePlayerKey(key, ranked_player->token);
-
- // save name and check for duplicates
- Q_strncpyz( ranked_player->name, name, sizeof(ranked_player->name) );
- for( i = 0; i < sv_maxclients->value; i++ )
- {
- if( (i != index) && (s_ranked_players[i].grank_status == QGR_STATUS_ACTIVE) &&
- (strcmp( s_ranked_players[i].name, name ) == 0) )
- {
- Com_DPrintf( "SV_RankUserValidate: Duplicate login\n" );
- ranked_player->grank_status = QGR_STATUS_NO_USER;
- ranked_player->final_status = QGR_STATUS_NEW;
- ranked_player->grank = 0;
- return qfalse;
- }
- }
-
- // then validate
- status = GRankPlayerValidate(
- s_server_context,
- ranked_player->player_id,
- ranked_player->token,
- token_len,
- GR_OPT_PLAYERCONTEXT,
- ranked_player->context,
- GR_OPT_END);
- }
- else
- {
- // make server side login (bots) happy
- status = GR_STATUS_OK;
- }
-
- if (status == GR_STATUS_OK)
- {
- ranked_player->grank_status = QGR_STATUS_ACTIVE;
- ranked_player->final_status = QGR_STATUS_NEW;
- ranked_player->grank = rank;
- rVal = qtrue;
- }
- else if (status == GR_STATUS_INVALIDUSER)
- {
- ranked_player->grank_status = QGR_STATUS_INVALIDUSER;
- ranked_player->final_status = QGR_STATUS_NEW;
- ranked_player->grank = 0;
- rVal = qfalse;
- }
- else
- {
- SV_RankError( "SV_RankUserValidate: Unexpected status %s",
- SV_RankStatusString( status ) );
- s_ranked_players[index].grank_status = QGR_STATUS_ERROR;
- ranked_player->grank = 0;
- }
-
- return rVal;
-}
-
-/*
-================
-SV_RankUserLogout
-================
-*/
-void SV_RankUserLogout( int index )
-{
- GR_STATUS status;
- GR_STATUS cleanup_status;
-
- if( !s_rankings_active )
- {
- return;
- }
-
- assert( index >= 0 );
- assert( index < sv_maxclients->value );
- assert( s_ranked_players );
-
- if( s_ranked_players[index].context == 0 ) {
- return;
- }
-
- Com_DPrintf( "SV_RankUserLogout( %d );\n", index );
-
- // masqueraded player may not be active yet, if they fail validation,
- // but still they have a context needs to be cleaned
- // what matters is the s_ranked_players[index].context
-
- // send reports, proceed to SV_RankSendReportsCBF
- status = GRankSendReportsAsync
- (
- s_ranked_players[index].context,
- 0,
- SV_RankSendReportsCBF,
- (void*)&s_ranked_players[index],
- GR_OPT_END
- );
-
- if( status == GR_STATUS_PENDING )
- {
- s_ranked_players[index].grank_status = QGR_STATUS_PENDING;
- s_ranked_players[index].final_status = QGR_STATUS_NEW;
- }
- else
- {
- SV_RankError( "SV_RankUserLogout: Expected GR_STATUS_PENDING, got %s",
- SV_RankStatusString( status ) );
-
- cleanup_status = GRankCleanupAsync
- (
- s_ranked_players[index].context,
- 0,
- SV_RankCleanupCBF,
- (void*)&s_ranked_players[index],
- GR_OPT_END
- );
-
- if( cleanup_status != GR_STATUS_PENDING )
- {
- SV_RankError( "SV_RankUserLogout: Expected "
- "GR_STATUS_PENDING from GRankCleanupAsync, got %s",
- SV_RankStatusString( cleanup_status ) );
- SV_RankCloseContext( &(s_ranked_players[index]) );
- }
- }
-}
-
-/*
-================
-SV_RankReportInt
-================
-*/
-void SV_RankReportInt( int index1, int index2, int key, int value,
- qboolean accum )
-{
- GR_STATUS status;
- GR_CONTEXT context;
- uint64_t match;
- uint64_t user1;
- uint64_t user2;
- int opt_accum;
-
- if( !s_rankings_active )
- {
- return;
- }
-
- assert( index1 >= -1 );
- assert( index1 < sv_maxclients->value );
- assert( index2 >= -1 );
- assert( index2 < sv_maxclients->value );
- assert( s_ranked_players );
-
-// Com_DPrintf( "SV_RankReportInt( %d, %d, %d, %d, %d );\n", index1, index2,
-// key, value, accum );
-
- // get context, match, and player_id for player index1
- if( index1 == -1 )
- {
- context = s_server_context;
- match = s_server_match;
- user1 = 0;
- }
- else
- {
- if( s_ranked_players[index1].grank_status != QGR_STATUS_ACTIVE )
- {
- Com_DPrintf( "SV_RankReportInt: Expecting QGR_STATUS_ACTIVE"
- " Got Unexpected status %d for player %d\n",
- s_ranked_players[index1].grank_status, index1 );
- return;
- }
-
- context = s_ranked_players[index1].context;
- match = s_ranked_players[index1].match;
- user1 = s_ranked_players[index1].player_id;
- }
-
- // get player_id for player index2
- if( index2 == -1 )
- {
- user2 = 0;
- }
- else
- {
- if( s_ranked_players[index2].grank_status != QGR_STATUS_ACTIVE )
- {
- Com_DPrintf( "SV_RankReportInt: Expecting QGR_STATUS_ACTIVE"
- " Got Unexpected status %d for player %d\n",
- s_ranked_players[index2].grank_status, index2 );
- return;
- }
-
- user2 = s_ranked_players[index2].player_id;
- }
-
- opt_accum = accum ? GR_OPT_ACCUM : GR_OPT_END;
-
- status = GRankReportInt
- (
- context,
- match,
- user1,
- user2,
- key,
- value,
- opt_accum,
- GR_OPT_END
- );
-
- if( status != GR_STATUS_OK )
- {
- SV_RankError( "SV_RankReportInt: Unexpected status %s",
- SV_RankStatusString( status ) );
- }
-
- if( user2 != 0 )
- {
- context = s_ranked_players[index2].context;
- match = s_ranked_players[index2].match;
-
- status = GRankReportInt
- (
- context,
- match,
- user1,
- user2,
- key,
- value,
- opt_accum,
- GR_OPT_END
- );
-
- if( status != GR_STATUS_OK )
- {
- SV_RankError( "SV_RankReportInt: Unexpected status %s",
- SV_RankStatusString( status ) );
- }
- }
-}
-
-/*
-================
-SV_RankReportStr
-================
-*/
-void SV_RankReportStr( int index1, int index2, int key, char* value )
-{
- GR_STATUS status;
- GR_CONTEXT context;
- uint64_t match;
- uint64_t user1;
- uint64_t user2;
-
- if( !s_rankings_active )
- {
- return;
- }
-
- assert( index1 >= -1 );
- assert( index1 < sv_maxclients->value );
- assert( index2 >= -1 );
- assert( index2 < sv_maxclients->value );
- assert( s_ranked_players );
-
-// Com_DPrintf( "SV_RankReportStr( %d, %d, %d, \"%s\" );\n", index1, index2,
-// key, value );
-
- // get context, match, and player_id for player index1
- if( index1 == -1 )
- {
- context = s_server_context;
- match = s_server_match;
- user1 = 0;
- }
- else
- {
- if( s_ranked_players[index1].grank_status != QGR_STATUS_ACTIVE )
- {
- Com_DPrintf( "SV_RankReportStr: Unexpected status %d\n",
- s_ranked_players[index1].grank_status );
- return;
- }
-
- context = s_ranked_players[index1].context;
- match = s_ranked_players[index1].match;
- user1 = s_ranked_players[index1].player_id;
- }
-
- // get player_id for player index2
- if( index2 == -1 )
- {
- user2 = 0;
- }
- else
- {
- if( s_ranked_players[index2].grank_status != QGR_STATUS_ACTIVE )
- {
- Com_DPrintf( "SV_RankReportStr: Unexpected status %d\n",
- s_ranked_players[index2].grank_status );
- return;
- }
-
- user2 = s_ranked_players[index2].player_id;
- }
-
- status = GRankReportStr
- (
- context,
- match,
- user1,
- user2,
- key,
- value,
- GR_OPT_END
- );
-
- if( status != GR_STATUS_OK )
- {
- SV_RankError( "SV_RankReportStr: Unexpected status %s",
- SV_RankStatusString( status ) );
- }
-
- if( user2 != 0 )
- {
- context = s_ranked_players[index2].context;
- match = s_ranked_players[index2].match;
-
- status = GRankReportStr
- (
- context,
- match,
- user1,
- user2,
- key,
- value,
- GR_OPT_END
- );
-
- if( status != GR_STATUS_OK )
- {
- SV_RankError( "SV_RankReportInt: Unexpected status %s",
- SV_RankStatusString( status ) );
- }
- }
-}
-
-/*
-================
-SV_RankQuit
-================
-*/
-void SV_RankQuit( void )
-{
- int i;
- int j = 0;
- // yuck
-
- while( s_rankings_contexts > 1 )
- {
- assert(s_ranked_players);
- if( s_ranked_players != NULL )
- {
- for( i = 0; i < sv_maxclients->value; i++ )
- {
- // check for players that weren't yet active in SV_RankEnd
- if( s_ranked_players[i].grank_status == QGR_STATUS_ACTIVE )
- {
- SV_RankUserLogout( i );
- Com_DPrintf( "SV_RankQuit: SV_RankUserLogout %d\n",i );
- }
- else
- {
- if( s_ranked_players[i].context )
- {
- GR_STATUS cleanup_status;
- cleanup_status = GRankCleanupAsync
- (
- s_ranked_players[i].context,
- 0,
- SV_RankCleanupCBF,
- (void*)&(s_ranked_players[i]),
- GR_OPT_END
- );
-
- if( cleanup_status != GR_STATUS_PENDING )
- {
- SV_RankError( "SV_RankQuit: Expected "
- "GR_STATUS_PENDING from GRankCleanupAsync, got %s",
- SV_RankStatusString( cleanup_status ) );
- }
- }
- }
- }
- }
- SV_RankPoll();
-
- // should've finished by now
- assert( (j++) < 68 );
- }
-}
-
-/*
-==============================================================================
-
-Private Functions
-
-==============================================================================
-*/
-
-/*
-=================
-SV_RankNewGameCBF
-=================
-*/
-static void SV_RankNewGameCBF( GR_NEWGAME* gr_newgame, void* cbf_arg )
-{
- GR_MATCH match;
- int i;
-
- assert( gr_newgame != NULL );
- assert( cbf_arg == NULL );
-
- Com_DPrintf( "SV_RankNewGameCBF( %08X, %08X );\n", gr_newgame, cbf_arg );
-
- if( gr_newgame->status == GR_STATUS_OK )
- {
- char info[MAX_INFO_STRING];
- char gameid[sizeof(s_ranked_players[i].game_id) * 4 / 3 + 2];
-
- // save game id
- s_rankings_game_id = gr_newgame->game_id;
-
- // encode gameid
- memset(gameid,0,sizeof(gameid));
- SV_RankEncodeGameID(s_rankings_game_id,gameid,sizeof(gameid));
-
- // set CS_GRANK rankingsGameID to pass to client
- memset(info,0,sizeof(info));
- Info_SetValueForKey( info, "rankingsGameKey", s_rankings_game_key );
- Info_SetValueForKey( info, "rankingsGameID", gameid );
- SV_SetConfigstring( CS_GRANK, info );
-
- // initialize client status
- for( i = 0; i < sv_maxclients->value; i++ )
- s_ranked_players[i].grank_status = QGR_STATUS_NEW;
-
- // start new match
- match = GRankStartMatch( s_server_context );
- s_server_match = match.match;
-
- // ready to go
- s_rankings_active = qtrue;
- Cvar_Set( "sv_rankingsActive", "1" );
-
- }
- else if( gr_newgame->status == GR_STATUS_BADLEAGUE )
- {
- SV_RankError( "SV_RankNewGameCBF: Invalid League name\n" );
- }
- else
- {
- //GRank handle new game failure
- // force SV_RankEnd() to run
- //SV_RankEnd();
- SV_RankError( "SV_RankNewGameCBF: Unexpected status %s",
- SV_RankStatusString( gr_newgame->status ) );
- }
-}
-
-/*
-================
-SV_RankUserCBF
-================
-*/
-static void SV_RankUserCBF( GR_LOGIN* gr_login, void* cbf_arg )
-{
- ranked_player_t* ranked_player;
- GR_STATUS join_status;
- GR_STATUS cleanup_status;
-
- assert( gr_login != NULL );
- assert( cbf_arg != NULL );
-
- Com_DPrintf( "SV_RankUserCBF( %08X, %08X );\n", gr_login, cbf_arg );
-
- ranked_player = (ranked_player_t*)cbf_arg;
- assert(ranked_player);
- assert( ranked_player->context );
-
- switch( gr_login->status )
- {
- case GR_STATUS_OK:
- // attempt to join the game, proceed to SV_RankJoinGameCBF
- join_status = GRankJoinGameAsync
- (
- ranked_player->context,
- s_rankings_game_id,
- SV_RankJoinGameCBF,
- cbf_arg,
- GR_OPT_END
- );
-
- if( join_status != GR_STATUS_PENDING )
- {
- SV_RankError( "SV_RankUserCBF: Expected GR_STATUS_PENDING "
- "from GRankJoinGameAsync, got %s",
- SV_RankStatusString( join_status ) );
- }
- break;
- case GR_STATUS_NOUSER:
- Com_DPrintf( "SV_RankUserCBF: Got status %s\n",
- SV_RankStatusString( gr_login->status ) );
- ranked_player->final_status = QGR_STATUS_NO_USER;
- break;
- case GR_STATUS_BADPASSWORD:
- Com_DPrintf( "SV_RankUserCBF: Got status %s\n",
- SV_RankStatusString( gr_login->status ) );
- ranked_player->final_status = QGR_STATUS_BAD_PASSWORD;
- break;
- case GR_STATUS_TIMEOUT:
- Com_DPrintf( "SV_RankUserCBF: Got status %s\n",
- SV_RankStatusString( gr_login->status ) );
- ranked_player->final_status = QGR_STATUS_TIMEOUT;
- break;
- default:
- Com_DPrintf( "SV_RankUserCBF: Unexpected status %s\n",
- SV_RankStatusString( gr_login->status ) );
- ranked_player->final_status = QGR_STATUS_ERROR;
- break;
- }
-
- if( ranked_player->final_status != QGR_STATUS_NEW )
- {
- // login or create failed, so clean up before the next attempt
- cleanup_status = GRankCleanupAsync
- (
- ranked_player->context,
- 0,
- SV_RankCleanupCBF,
- (void*)ranked_player,
- GR_OPT_END
- );
-
- if( cleanup_status != GR_STATUS_PENDING )
- {
- SV_RankError( "SV_RankUserCBF: Expected GR_STATUS_PENDING "
- "from GRankCleanupAsync, got %s",
- SV_RankStatusString( cleanup_status ) );
- SV_RankCloseContext( ranked_player );
- }
- }
-}
-
-/*
-================
-SV_RankJoinGameCBF
-================
-*/
-static void SV_RankJoinGameCBF( GR_JOINGAME* gr_joingame, void* cbf_arg )
-{
- ranked_player_t* ranked_player;
- GR_MATCH match;
- GR_STATUS cleanup_status;
-
- assert( gr_joingame != NULL );
- assert( cbf_arg != NULL );
-
- Com_DPrintf( "SV_RankJoinGameCBF( %08X, %08X );\n", gr_joingame, cbf_arg );
-
- ranked_player = (ranked_player_t*)cbf_arg;
-
- assert( ranked_player );
- assert( ranked_player->context != 0 );
-
- if( gr_joingame->status == GR_STATUS_OK )
- {
- int i;
- // save user id
- ranked_player->player_id = gr_joingame->player_id;
- memcpy(ranked_player->token,gr_joingame->token,
- sizeof(GR_PLAYER_TOKEN)) ;
- match = GRankStartMatch( ranked_player->context );
- ranked_player->match = match.match;
- ranked_player->grank = gr_joingame->rank;
-
- // find the index and call SV_RankUserValidate
- for (i=0;i<sv_maxclients->value;i++)
- if ( ranked_player == &s_ranked_players[i] )
- SV_RankUserValidate(i,NULL,NULL,0, gr_joingame->rank,ranked_player->name);
- }
- else
- {
- //GRand handle join game failure
- SV_RankError( "SV_RankJoinGameCBF: Unexpected status %s",
- SV_RankStatusString( gr_joingame->status ) );
-
- cleanup_status = GRankCleanupAsync
- (
- ranked_player->context,
- 0,
- SV_RankCleanupCBF,
- cbf_arg,
- GR_OPT_END
- );
-
- if( cleanup_status != GR_STATUS_PENDING )
- {
- SV_RankError( "SV_RankJoinGameCBF: Expected "
- "GR_STATUS_PENDING from GRankCleanupAsync, got %s",
- SV_RankStatusString( cleanup_status ) );
- SV_RankCloseContext( ranked_player );
- }
- }
-}
-
-/*
-================
-SV_RankSendReportsCBF
-================
-*/
-static void SV_RankSendReportsCBF( GR_STATUS* status, void* cbf_arg )
-{
- ranked_player_t* ranked_player;
- GR_CONTEXT context;
- GR_STATUS cleanup_status;
-
- assert( status != NULL );
- // NULL cbf_arg means server is sending match reports
-
- Com_DPrintf( "SV_RankSendReportsCBF( %08X, %08X );\n", status, cbf_arg );
-
- ranked_player = (ranked_player_t*)cbf_arg;
- if( ranked_player == NULL )
- {
- Com_DPrintf( "SV_RankSendReportsCBF: server\n" );
- context = s_server_context;
- }
- else
- {
- Com_DPrintf( "SV_RankSendReportsCBF: player\n" );
- context = ranked_player->context;
- }
-
- //assert( context != 0 );
- if( *status != GR_STATUS_OK )
- {
- SV_RankError( "SV_RankSendReportsCBF: Unexpected status %s",
- SV_RankStatusString( *status ) );
- }
-
- if( context == 0 )
- {
- Com_DPrintf( "SV_RankSendReportsCBF: WARNING: context == 0" );
- SV_RankCloseContext( ranked_player );
- }
- else
- {
- cleanup_status = GRankCleanupAsync
- (
- context,
- 0,
- SV_RankCleanupCBF,
- cbf_arg,
- GR_OPT_END
- );
-
- if( cleanup_status != GR_STATUS_PENDING )
- {
- SV_RankError( "SV_RankSendReportsCBF: Expected "
- "GR_STATUS_PENDING from GRankCleanupAsync, got %s",
- SV_RankStatusString( cleanup_status ) );
- SV_RankCloseContext( ranked_player );
- }
- }
-}
-
-/*
-================
-SV_RankCleanupCBF
-================
-*/
-static void SV_RankCleanupCBF( GR_STATUS* status, void* cbf_arg )
-{
- ranked_player_t* ranked_player;
- ranked_player = (ranked_player_t*)cbf_arg;
-
- assert( status != NULL );
- // NULL cbf_arg means server is cleaning up
-
- Com_DPrintf( "SV_RankCleanupCBF( %08X, %08X );\n", status, cbf_arg );
-
- if( *status != GR_STATUS_OK )
- {
- SV_RankError( "SV_RankCleanupCBF: Unexpected status %s",
- SV_RankStatusString( *status ) );
- }
-
- SV_RankCloseContext( ranked_player );
-}
-
-/*
-================
-SV_RankCloseContext
-================
-*/
-static void SV_RankCloseContext( ranked_player_t* ranked_player )
-{
- if( ranked_player == NULL )
- {
- // server cleanup
- if( s_server_context == 0 )
- {
- return;
- }
- s_server_context = 0;
- s_server_match = 0;
- }
- else
- {
- // player cleanup
- if( s_ranked_players == NULL )
- {
- return;
- }
- if( ranked_player->context == 0 )
- {
- return;
- }
- ranked_player->context = 0;
- ranked_player->match = 0;
- ranked_player->player_id = 0;
- memset( ranked_player->token, 0, sizeof(GR_PLAYER_TOKEN) );
- ranked_player->grank_status = ranked_player->final_status;
- ranked_player->final_status = QGR_STATUS_NEW;
- ranked_player->name[0] = '\0';
- }
-
- assert( s_rankings_contexts > 0 );
- s_rankings_contexts--;
- Com_DPrintf( "SV_RankCloseContext: s_rankings_contexts = %d\n",
- s_rankings_contexts );
-
- if( s_rankings_contexts == 0 )
- {
- GRankLogLevel( GRLOG_OFF );
-
- if( s_ranked_players != NULL )
- {
- Z_Free( s_ranked_players );
- s_ranked_players = NULL;
- }
-
- s_rankings_active = qfalse;
- Cvar_Set( "sv_rankingsActive", "0" );
- }
-}
-
-/*
-================
-SV_RankAsciiEncode
-
-Encodes src_len bytes of binary data from the src buffer as ASCII text,
-using 6 bits per character. The result string is null-terminated and
-stored in the dest buffer.
-
-The dest buffer must be at least (src_len * 4) / 3 + 2 bytes in length.
-
-Returns the length of the result string, not including the null.
-================
-*/
-static int SV_RankAsciiEncode( char* dest, const unsigned char* src,
- int src_len )
-{
- unsigned char bin[3];
- unsigned char txt[4];
- int dest_len = 0;
- int i;
- int j;
- int num_chars;
-
- assert( dest != NULL );
- assert( src != NULL );
-
- for( i = 0; i < src_len; i += 3 )
- {
- // read three bytes of input
- for( j = 0; j < 3; j++ )
- {
- bin[j] = (i + j < src_len) ? src[i + j] : 0;
- }
-
- // get four 6-bit values from three bytes
- txt[0] = bin[0] >> 2;
- txt[1] = ((bin[0] << 4) | (bin[1] >> 4)) & 63;
- txt[2] = ((bin[1] << 2) | (bin[2] >> 6)) & 63;
- txt[3] = bin[2] & 63;
-
- // store ASCII encoding of 6-bit values
- num_chars = (i + 2 < src_len) ? 4 : ((src_len - i) * 4) / 3 + 1;
- for( j = 0; j < num_chars; j++ )
- {
- dest[dest_len++] = s_ascii_encoding[txt[j]];
- }
- }
-
- dest[dest_len] = '\0';
-
- return dest_len;
-}
-
-/*
-================
-SV_RankAsciiDecode
-
-Decodes src_len characters of ASCII text from the src buffer, stores
-the binary result in the dest buffer.
-
-The dest buffer must be at least (src_len * 3) / 4 bytes in length.
-
-Returns the length of the binary result, or zero for invalid input.
-================
-*/
-static int SV_RankAsciiDecode( unsigned char* dest, const char* src,
- int src_len )
-{
- static unsigned char s_inverse_encoding[256];
- static char s_init = 0;
-
- unsigned char bin[3];
- unsigned char txt[4];
- int dest_len = 0;
- int i;
- int j;
- int num_bytes;
-
- assert( dest != NULL );
- assert( src != NULL );
-
- if( !s_init )
- {
- // initialize lookup table for decoding
- memset( s_inverse_encoding, 255, sizeof(s_inverse_encoding) );
- for( i = 0; i < 64; i++ )
- {
- s_inverse_encoding[s_ascii_encoding[i]] = i;
- }
- s_init = 1;
- }
-
- for( i = 0; i < src_len; i += 4 )
- {
- // read four characters of input, decode them to 6-bit values
- for( j = 0; j < 4; j++ )
- {
- txt[j] = (i + j < src_len) ? s_inverse_encoding[src[i + j]] : 0;
- if (txt[j] == 255)
- {
- return 0; // invalid input character
- }
- }
-
- // get three bytes from four 6-bit values
- bin[0] = (txt[0] << 2) | (txt[1] >> 4);
- bin[1] = (txt[1] << 4) | (txt[2] >> 2);
- bin[2] = (txt[2] << 6) | txt[3];
-
- // store binary data
- num_bytes = (i + 3 < src_len) ? 3 : ((src_len - i) * 3) / 4;
- for( j = 0; j < num_bytes; j++ )
- {
- dest[dest_len++] = bin[j];
- }
- }
-
- return dest_len;
-}
-
-/*
-================
-SV_RankEncodeGameID
-================
-*/
-static void SV_RankEncodeGameID( uint64_t game_id, char* result,
- int len )
-{
- assert( result != NULL );
-
- if( len < ( ( sizeof(game_id) * 4) / 3 + 2) )
- {
- Com_DPrintf( "SV_RankEncodeGameID: result buffer too small\n" );
- result[0] = '\0';
- }
- else
- {
- qint64 gameid = LittleLong64(*(qint64*)&game_id);
- SV_RankAsciiEncode( result, (unsigned char*)&gameid,
- sizeof(qint64) );
- }
-}
-
-/*
-================
-SV_RankDecodePlayerID
-================
-*/
-static uint64_t SV_RankDecodePlayerID( const char* string )
-{
- unsigned char buffer[9];
- int len;
- qint64 player_id;
-
- assert( string != NULL );
-
- len = strlen (string) ;
- Com_DPrintf( "SV_RankDecodePlayerID: string length %d\n",len );
- SV_RankAsciiDecode( buffer, string, len );
- player_id = LittleLong64(*(qint64*)buffer);
- return *(uint64_t*)&player_id;
-}
-
-/*
-================
-SV_RankDecodePlayerKey
-================
-*/
-static void SV_RankDecodePlayerKey( const char* string, GR_PLAYER_TOKEN key )
-{
- unsigned char buffer[1400];
- int len;
- assert( string != NULL );
-
- len = strlen (string) ;
- Com_DPrintf( "SV_RankDecodePlayerKey: string length %d\n",len );
-
- memset(key,0,sizeof(GR_PLAYER_TOKEN));
- memset(buffer,0,sizeof(buffer));
- memcpy( key, buffer, SV_RankAsciiDecode( buffer, string, len ) );
-}
-
-/*
-================
-SV_RankStatusString
-================
-*/
-static char* SV_RankStatusString( GR_STATUS status )
-{
- switch( status )
- {
- case GR_STATUS_OK: return "GR_STATUS_OK";
- case GR_STATUS_ERROR: return "GR_STATUS_ERROR";
- case GR_STATUS_BADPARAMS: return "GR_STATUS_BADPARAMS";
- case GR_STATUS_NETWORK: return "GR_STATUS_NETWORK";
- case GR_STATUS_NOUSER: return "GR_STATUS_NOUSER";
- case GR_STATUS_BADPASSWORD: return "GR_STATUS_BADPASSWORD";
- case GR_STATUS_BADGAME: return "GR_STATUS_BADGAME";
- case GR_STATUS_PENDING: return "GR_STATUS_PENDING";
- case GR_STATUS_BADDOMAIN: return "GR_STATUS_BADDOMAIN";
- case GR_STATUS_DOMAINLOCK: return "GR_STATUS_DOMAINLOCK";
- case GR_STATUS_TIMEOUT: return "GR_STATUS_TIMEOUT";
- case GR_STATUS_INVALIDUSER: return "GR_STATUS_INVALIDUSER";
- case GR_STATUS_INVALIDCONTEXT: return "GR_STATUS_INVALIDCONTEXT";
- default: return "(UNKNOWN)";
- }
-}
-
-/*
-================
-SV_RankError
-================
-*/
-static void SV_RankError( const char* fmt, ... )
-{
- va_list arg_ptr;
- char text[1024];
-
- va_start( arg_ptr, fmt );
- Q_vsnprintf(text, sizeof(text), fmt, arg_ptr );
- va_end( arg_ptr );
-
- Com_DPrintf( "****************************************\n" );
- Com_DPrintf( "SV_RankError: %s\n", text );
- Com_DPrintf( "****************************************\n" );
-
- s_rankings_active = qfalse;
- Cvar_Set( "sv_rankingsActive", "0" );
- // FIXME - attempt clean shutdown?
-}
-
diff --git a/engine/code/server/sv_snapshot.c b/engine/code/server/sv_snapshot.c
deleted file mode 100644
index d84a189..0000000
--- a/engine/code/server/sv_snapshot.c
+++ /dev/null
@@ -1,699 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "server.h"
-
-
-/*
-=============================================================================
-
-Delta encode a client frame onto the network channel
-
-A normal server packet will look like:
-
-4 sequence number (high bit set if an oversize fragment)
-<optional reliable commands>
-1 svc_snapshot
-4 last client reliable command
-4 serverTime
-1 lastframe for delta compression
-1 snapFlags
-1 areaBytes
-<areabytes>
-<playerstate>
-<packetentities>
-
-=============================================================================
-*/
-
-/*
-=============
-SV_EmitPacketEntities
-
-Writes a delta update of an entityState_t list to the message.
-=============
-*/
-static void SV_EmitPacketEntities( clientSnapshot_t *from, clientSnapshot_t *to, msg_t *msg ) {
- entityState_t *oldent, *newent;
- int oldindex, newindex;
- int oldnum, newnum;
- int from_num_entities;
-
- // generate the delta update
- if ( !from ) {
- from_num_entities = 0;
- } else {
- from_num_entities = from->num_entities;
- }
-
- newent = NULL;
- oldent = NULL;
- newindex = 0;
- oldindex = 0;
- while ( newindex < to->num_entities || oldindex < from_num_entities ) {
- if ( newindex >= to->num_entities ) {
- newnum = 9999;
- } else {
- newent = &svs.snapshotEntities[(to->first_entity+newindex) % svs.numSnapshotEntities];
- newnum = newent->number;
- }
-
- if ( oldindex >= from_num_entities ) {
- oldnum = 9999;
- } else {
- oldent = &svs.snapshotEntities[(from->first_entity+oldindex) % svs.numSnapshotEntities];
- oldnum = oldent->number;
- }
-
- if ( newnum == oldnum ) {
- // delta update from old position
- // because the force parm is qfalse, this will not result
- // in any bytes being emited if the entity has not changed at all
- MSG_WriteDeltaEntity (msg, oldent, newent, qfalse );
- oldindex++;
- newindex++;
- continue;
- }
-
- if ( newnum < oldnum ) {
- // this is a new entity, send it from the baseline
- MSG_WriteDeltaEntity (msg, &sv.svEntities[newnum].baseline, newent, qtrue );
- newindex++;
- continue;
- }
-
- if ( newnum > oldnum ) {
- // the old entity isn't present in the new message
- MSG_WriteDeltaEntity (msg, oldent, NULL, qtrue );
- oldindex++;
- continue;
- }
- }
-
- MSG_WriteBits( msg, (MAX_GENTITIES-1), GENTITYNUM_BITS ); // end of packetentities
-}
-
-
-
-/*
-==================
-SV_WriteSnapshotToClient
-==================
-*/
-static void SV_WriteSnapshotToClient( client_t *client, msg_t *msg ) {
- clientSnapshot_t *frame, *oldframe;
- int lastframe;
- int i;
- int snapFlags;
-
- // this is the snapshot we are creating
- frame = &client->frames[ client->netchan.outgoingSequence & PACKET_MASK ];
-
- // try to use a previous frame as the source for delta compressing the snapshot
- if ( client->deltaMessage <= 0 || client->state != CS_ACTIVE ) {
- // client is asking for a retransmit
- oldframe = NULL;
- lastframe = 0;
- } else if ( client->netchan.outgoingSequence - client->deltaMessage
- >= (PACKET_BACKUP - 3) ) {
- // client hasn't gotten a good message through in a long time
- Com_DPrintf ("%s: Delta request from out of date packet.\n", client->name);
- oldframe = NULL;
- lastframe = 0;
- } else {
- // we have a valid snapshot to delta from
- oldframe = &client->frames[ client->deltaMessage & PACKET_MASK ];
- lastframe = client->netchan.outgoingSequence - client->deltaMessage;
-
- // the snapshot's entities may still have rolled off the buffer, though
- if ( oldframe->first_entity <= svs.nextSnapshotEntities - svs.numSnapshotEntities ) {
- Com_DPrintf ("%s: Delta request from out of date entities.\n", client->name);
- oldframe = NULL;
- lastframe = 0;
- }
- }
-
- MSG_WriteByte (msg, svc_snapshot);
-
- // NOTE, MRE: now sent at the start of every message from server to client
- // let the client know which reliable clientCommands we have received
- //MSG_WriteLong( msg, client->lastClientCommand );
-
- // send over the current server time so the client can drift
- // its view of time to try to match
- if( client->oldServerTime ) {
- // The server has not yet got an acknowledgement of the
- // new gamestate from this client, so continue to send it
- // a time as if the server has not restarted. Note from
- // the client's perspective this time is strictly speaking
- // incorrect, but since it'll be busy loading a map at
- // the time it doesn't really matter.
- MSG_WriteLong (msg, sv.time + client->oldServerTime);
- } else {
- MSG_WriteLong (msg, sv.time);
- }
-
- // what we are delta'ing from
- MSG_WriteByte (msg, lastframe);
-
- snapFlags = svs.snapFlagServerBit;
- if ( client->rateDelayed ) {
- snapFlags |= SNAPFLAG_RATE_DELAYED;
- }
- if ( client->state != CS_ACTIVE ) {
- snapFlags |= SNAPFLAG_NOT_ACTIVE;
- }
-
- MSG_WriteByte (msg, snapFlags);
-
- // send over the areabits
- MSG_WriteByte (msg, frame->areabytes);
- MSG_WriteData (msg, frame->areabits, frame->areabytes);
-
- // delta encode the playerstate
- if ( oldframe ) {
- MSG_WriteDeltaPlayerstate( msg, &oldframe->ps, &frame->ps );
- } else {
- MSG_WriteDeltaPlayerstate( msg, NULL, &frame->ps );
- }
-
- // delta encode the entities
- SV_EmitPacketEntities (oldframe, frame, msg);
-
- // padding for rate debugging
- if ( sv_padPackets->integer ) {
- for ( i = 0 ; i < sv_padPackets->integer ; i++ ) {
- MSG_WriteByte (msg, svc_nop);
- }
- }
-}
-
-
-/*
-==================
-SV_UpdateServerCommandsToClient
-
-(re)send all server commands the client hasn't acknowledged yet
-==================
-*/
-void SV_UpdateServerCommandsToClient( client_t *client, msg_t *msg ) {
- int i;
-
- // write any unacknowledged serverCommands
- for ( i = client->reliableAcknowledge + 1 ; i <= client->reliableSequence ; i++ ) {
- MSG_WriteByte( msg, svc_serverCommand );
- MSG_WriteLong( msg, i );
- MSG_WriteString( msg, client->reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
- }
- client->reliableSent = client->reliableSequence;
-}
-
-/*
-=============================================================================
-
-Build a client snapshot structure
-
-=============================================================================
-*/
-
-#define MAX_SNAPSHOT_ENTITIES 1024
-typedef struct {
- int numSnapshotEntities;
- int snapshotEntities[MAX_SNAPSHOT_ENTITIES];
-} snapshotEntityNumbers_t;
-
-/*
-=======================
-SV_QsortEntityNumbers
-=======================
-*/
-static int QDECL SV_QsortEntityNumbers( const void *a, const void *b ) {
- int *ea, *eb;
-
- ea = (int *)a;
- eb = (int *)b;
-
- if ( *ea == *eb ) {
- Com_Error( ERR_DROP, "SV_QsortEntityStates: duplicated entity" );
- }
-
- if ( *ea < *eb ) {
- return -1;
- }
-
- return 1;
-}
-
-
-/*
-===============
-SV_AddEntToSnapshot
-===============
-*/
-static void SV_AddEntToSnapshot( svEntity_t *svEnt, sharedEntity_t *gEnt, snapshotEntityNumbers_t *eNums ) {
- // if we have already added this entity to this snapshot, don't add again
- if ( svEnt->snapshotCounter == sv.snapshotCounter ) {
- return;
- }
- svEnt->snapshotCounter = sv.snapshotCounter;
-
- // if we are full, silently discard entities
- if ( eNums->numSnapshotEntities == MAX_SNAPSHOT_ENTITIES ) {
- return;
- }
-
- eNums->snapshotEntities[ eNums->numSnapshotEntities ] = gEnt->s.number;
- eNums->numSnapshotEntities++;
-}
-
-/*
-===============
-SV_AddEntitiesVisibleFromPoint
-===============
-*/
-static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame,
- snapshotEntityNumbers_t *eNums, qboolean portal ) {
- int e, i;
- sharedEntity_t *ent;
- svEntity_t *svEnt;
- int l;
- int clientarea, clientcluster;
- int leafnum;
- byte *clientpvs;
- byte *bitvector;
-
- // during an error shutdown message we may need to transmit
- // the shutdown message after the server has shutdown, so
- // specfically check for it
- if ( !sv.state ) {
- return;
- }
-
- leafnum = CM_PointLeafnum (origin);
- clientarea = CM_LeafArea (leafnum);
- clientcluster = CM_LeafCluster (leafnum);
-
- // calculate the visible areas
- frame->areabytes = CM_WriteAreaBits( frame->areabits, clientarea );
-
- clientpvs = CM_ClusterPVS (clientcluster);
-
- for ( e = 0 ; e < sv.num_entities ; e++ ) {
- ent = SV_GentityNum(e);
-
- // never send entities that aren't linked in
- if ( !ent->r.linked ) {
- continue;
- }
-
- if (ent->s.number != e) {
- Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n");
- ent->s.number = e;
- }
-
- // entities can be flagged to explicitly not be sent to the client
- if ( ent->r.svFlags & SVF_NOCLIENT ) {
- continue;
- }
-
- // entities can be flagged to be sent to only one client
- if ( ent->r.svFlags & SVF_SINGLECLIENT ) {
- if ( ent->r.singleClient != frame->ps.clientNum ) {
- continue;
- }
- }
- // entities can be flagged to be sent to everyone but one client
- if ( ent->r.svFlags & SVF_NOTSINGLECLIENT ) {
- if ( ent->r.singleClient == frame->ps.clientNum ) {
- continue;
- }
- }
- // entities can be flagged to be sent to a given mask of clients
- if ( ent->r.svFlags & SVF_CLIENTMASK ) {
- if (frame->ps.clientNum >= 32)
- Com_Error( ERR_DROP, "SVF_CLIENTMASK: cientNum > 32\n" );
- if (~ent->r.singleClient & (1 << frame->ps.clientNum))
- continue;
- }
-
- svEnt = SV_SvEntityForGentity( ent );
-
- // don't double add an entity through portals
- if ( svEnt->snapshotCounter == sv.snapshotCounter ) {
- continue;
- }
-
- // broadcast entities are always sent
- if ( ent->r.svFlags & SVF_BROADCAST ) {
- SV_AddEntToSnapshot( svEnt, ent, eNums );
- continue;
- }
-
- // ignore if not touching a PV leaf
- // check area
- if ( !CM_AreasConnected( clientarea, svEnt->areanum ) ) {
- // doors can legally straddle two areas, so
- // we may need to check another one
- if ( !CM_AreasConnected( clientarea, svEnt->areanum2 ) ) {
- continue; // blocked by a door
- }
- }
-
- bitvector = clientpvs;
-
- // check individual leafs
- if ( !svEnt->numClusters ) {
- continue;
- }
- l = 0;
- for ( i=0 ; i < svEnt->numClusters ; i++ ) {
- l = svEnt->clusternums[i];
- if ( bitvector[l >> 3] & (1 << (l&7) ) ) {
- break;
- }
- }
-
- // if we haven't found it to be visible,
- // check overflow clusters that coudln't be stored
- if ( i == svEnt->numClusters ) {
- if ( svEnt->lastCluster ) {
- for ( ; l <= svEnt->lastCluster ; l++ ) {
- if ( bitvector[l >> 3] & (1 << (l&7) ) ) {
- break;
- }
- }
- if ( l == svEnt->lastCluster ) {
- continue; // not visible
- }
- } else {
- continue;
- }
- }
-
- // add it
- SV_AddEntToSnapshot( svEnt, ent, eNums );
-
- // if its a portal entity, add everything visible from its camera position
- if ( ent->r.svFlags & SVF_PORTAL ) {
- if ( ent->s.generic1 ) {
- vec3_t dir;
- VectorSubtract(ent->s.origin, origin, dir);
- if ( VectorLengthSquared(dir) > (float) ent->s.generic1 * ent->s.generic1 ) {
- continue;
- }
- }
- SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue );
- }
-
- }
-}
-
-/*
-=============
-SV_BuildClientSnapshot
-
-Decides which entities are going to be visible to the client, and
-copies off the playerstate and areabits.
-
-This properly handles multiple recursive portals, but the render
-currently doesn't.
-
-For viewing through other player's eyes, clent can be something other than client->gentity
-=============
-*/
-static void SV_BuildClientSnapshot( client_t *client ) {
- vec3_t org;
- clientSnapshot_t *frame;
- snapshotEntityNumbers_t entityNumbers;
- int i;
- sharedEntity_t *ent;
- entityState_t *state;
- svEntity_t *svEnt;
- sharedEntity_t *clent;
- int clientNum;
- playerState_t *ps;
-
- // bump the counter used to prevent double adding
- sv.snapshotCounter++;
-
- // this is the frame we are creating
- frame = &client->frames[ client->netchan.outgoingSequence & PACKET_MASK ];
-
- // clear everything in this snapshot
- entityNumbers.numSnapshotEntities = 0;
- Com_Memset( frame->areabits, 0, sizeof( frame->areabits ) );
-
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=62
- frame->num_entities = 0;
-
- clent = client->gentity;
- if ( !clent || client->state == CS_ZOMBIE ) {
- return;
- }
-
- // grab the current playerState_t
- ps = SV_GameClientNum( client - svs.clients );
- frame->ps = *ps;
-
- // never send client's own entity, because it can
- // be regenerated from the playerstate
- clientNum = frame->ps.clientNum;
- if ( clientNum < 0 || clientNum >= MAX_GENTITIES ) {
- Com_Error( ERR_DROP, "SV_SvEntityForGentity: bad gEnt" );
- }
- svEnt = &sv.svEntities[ clientNum ];
-
- svEnt->snapshotCounter = sv.snapshotCounter;
-
- // find the client's viewpoint
- VectorCopy( ps->origin, org );
- org[2] += ps->viewheight;
-
- // add all the entities directly visible to the eye, which
- // may include portal entities that merge other viewpoints
- SV_AddEntitiesVisibleFromPoint( org, frame, &entityNumbers, qfalse );
-
- // if there were portals visible, there may be out of order entities
- // in the list which will need to be resorted for the delta compression
- // to work correctly. This also catches the error condition
- // of an entity being included twice.
- qsort( entityNumbers.snapshotEntities, entityNumbers.numSnapshotEntities,
- sizeof( entityNumbers.snapshotEntities[0] ), SV_QsortEntityNumbers );
-
- // now that all viewpoint's areabits have been OR'd together, invert
- // all of them to make it a mask vector, which is what the renderer wants
- for ( i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++ ) {
- ((int *)frame->areabits)[i] = ((int *)frame->areabits)[i] ^ -1;
- }
-
- // copy the entity states out
- frame->num_entities = 0;
- frame->first_entity = svs.nextSnapshotEntities;
- for ( i = 0 ; i < entityNumbers.numSnapshotEntities ; i++ ) {
- ent = SV_GentityNum(entityNumbers.snapshotEntities[i]);
- state = &svs.snapshotEntities[svs.nextSnapshotEntities % svs.numSnapshotEntities];
- *state = ent->s;
- svs.nextSnapshotEntities++;
- // this should never hit, map should always be restarted first in SV_Frame
- if ( svs.nextSnapshotEntities >= 0x7FFFFFFE ) {
- Com_Error(ERR_FATAL, "svs.nextSnapshotEntities wrapped");
- }
- frame->num_entities++;
- }
-}
-
-
-/*
-====================
-SV_RateMsec
-
-Return the number of msec a given size message is supposed
-to take to clear, based on the current rate
-====================
-*/
-#define HEADER_RATE_BYTES 48 // include our header, IP header, and some overhead
-static int SV_RateMsec( client_t *client, int messageSize ) {
- int rate;
- int rateMsec;
-
- // individual messages will never be larger than fragment size
- if ( messageSize > 1500 ) {
- messageSize = 1500;
- }
- rate = client->rate;
- if ( sv_maxRate->integer ) {
- if ( sv_maxRate->integer < 1000 ) {
- Cvar_Set( "sv_MaxRate", "1000" );
- }
- if ( sv_maxRate->integer < rate ) {
- rate = sv_maxRate->integer;
- }
- }
- if ( sv_minRate->integer ) {
- if ( sv_minRate->integer < 1000 )
- Cvar_Set( "sv_minRate", "1000" );
- if ( sv_minRate->integer > rate )
- rate = sv_minRate->integer;
- }
-
- rateMsec = ( messageSize + HEADER_RATE_BYTES ) * 1000 / rate * com_timescale->value;
-
- return rateMsec;
-}
-
-/*
-=======================
-SV_SendMessageToClient
-
-Called by SV_SendClientSnapshot and SV_SendClientGameState
-=======================
-*/
-void SV_SendMessageToClient( msg_t *msg, client_t *client ) {
- int rateMsec;
-
- // record information about the message
- client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSize = msg->cursize;
- client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSent = svs.time;
- client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageAcked = -1;
-
- // send the datagram
- SV_Netchan_Transmit( client, msg ); //msg->cursize, msg->data );
-
- // set nextSnapshotTime based on rate and requested number of updates
-
- // local clients get snapshots every server frame
- // TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491
- // added sv_lanForceRate check
- if ( client->netchan.remoteAddress.type == NA_LOOPBACK || (sv_lanForceRate->integer && Sys_IsLANAddress (client->netchan.remoteAddress)) ) {
- client->nextSnapshotTime = svs.time + (1000.0 / sv_fps->integer * com_timescale->value);
- return;
- }
-
- // normal rate / snapshotMsec calculation
- rateMsec = SV_RateMsec(client, msg->cursize);
-
- if ( rateMsec < client->snapshotMsec * com_timescale->value) {
- // never send more packets than this, no matter what the rate is at
- rateMsec = client->snapshotMsec * com_timescale->value;
- client->rateDelayed = qfalse;
- } else {
- client->rateDelayed = qtrue;
- }
-
- client->nextSnapshotTime = svs.time + rateMsec * com_timescale->value;
-
- // don't pile up empty snapshots while connecting
- if ( client->state != CS_ACTIVE ) {
- // a gigantic connection message may have already put the nextSnapshotTime
- // more than a second away, so don't shorten it
- // do shorten if client is downloading
- if (!*client->downloadName && client->nextSnapshotTime < svs.time + 1000 * com_timescale->value)
- client->nextSnapshotTime = svs.time + 1000 * com_timescale->value;
- }
-}
-
-
-/*
-=======================
-SV_SendClientSnapshot
-
-Also called by SV_FinalMessage
-
-=======================
-*/
-void SV_SendClientSnapshot( client_t *client ) {
- byte msg_buf[MAX_MSGLEN];
- msg_t msg;
-
- // build the snapshot
- SV_BuildClientSnapshot( client );
-
- // bots need to have their snapshots build, but
- // the query them directly without needing to be sent
- if ( client->gentity && client->gentity->r.svFlags & SVF_BOT ) {
- return;
- }
-
- MSG_Init (&msg, msg_buf, sizeof(msg_buf));
- msg.allowoverflow = qtrue;
-
- // NOTE, MRE: all server->client messages now acknowledge
- // let the client know which reliable clientCommands we have received
- MSG_WriteLong( &msg, client->lastClientCommand );
-
- // (re)send any reliable server commands
- SV_UpdateServerCommandsToClient( client, &msg );
-
- // send over all the relevant entityState_t
- // and the playerState_t
- SV_WriteSnapshotToClient( client, &msg );
-
- // Add any download data if the client is downloading
- SV_WriteDownloadToClient( client, &msg );
-
-#ifdef USE_VOIP
- SV_WriteVoipToClient( client, &msg );
-#endif
-
- // check for overflow
- if ( msg.overflowed ) {
- Com_Printf ("WARNING: msg overflowed for %s\n", client->name);
- MSG_Clear (&msg);
- }
-
- SV_SendMessageToClient( &msg, client );
-}
-
-
-/*
-=======================
-SV_SendClientMessages
-=======================
-*/
-void SV_SendClientMessages( void ) {
- int i;
- client_t *c;
-
- // send a message to each connected client
- for (i=0, c = svs.clients ; i < sv_maxclients->integer ; i++, c++) {
- if (!c->state) {
- continue; // not connected
- }
-
- if ( svs.time < c->nextSnapshotTime ) {
- continue; // not time yet
- }
-
- // send additional message fragments if the last message
- // was too large to send at once
- if ( c->netchan.unsentFragments ) {
- c->nextSnapshotTime = svs.time +
- SV_RateMsec( c, c->netchan.unsentLength - c->netchan.unsentFragmentStart );
- SV_Netchan_TransmitNextFragment( c );
- continue;
- }
-
- // generate and send a new message
- SV_SendClientSnapshot( c );
- }
-}
-
diff --git a/engine/code/server/sv_world.c b/engine/code/server/sv_world.c
deleted file mode 100644
index b2cec81..0000000
--- a/engine/code/server/sv_world.c
+++ /dev/null
@@ -1,691 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// world.c -- world query functions
-
-#include "server.h"
-
-/*
-================
-SV_ClipHandleForEntity
-
-Returns a headnode that can be used for testing or clipping to a
-given entity. If the entity is a bsp model, the headnode will
-be returned, otherwise a custom box tree will be constructed.
-================
-*/
-clipHandle_t SV_ClipHandleForEntity( const sharedEntity_t *ent ) {
- if ( ent->r.bmodel ) {
- // explicit hulls in the BSP model
- return CM_InlineModel( ent->s.modelindex );
- }
- if ( ent->r.svFlags & SVF_CAPSULE ) {
- // create a temp capsule from bounding box sizes
- return CM_TempBoxModel( ent->r.mins, ent->r.maxs, qtrue );
- }
-
- // create a temp tree from bounding box sizes
- return CM_TempBoxModel( ent->r.mins, ent->r.maxs, qfalse );
-}
-
-
-
-/*
-===============================================================================
-
-ENTITY CHECKING
-
-To avoid linearly searching through lists of entities during environment testing,
-the world is carved up with an evenly spaced, axially aligned bsp tree. Entities
-are kept in chains either at the final leafs, or at the first node that splits
-them, which prevents having to deal with multiple fragments of a single entity.
-
-===============================================================================
-*/
-
-typedef struct worldSector_s {
- int axis; // -1 = leaf node
- float dist;
- struct worldSector_s *children[2];
- svEntity_t *entities;
-} worldSector_t;
-
-#define AREA_DEPTH 4
-#define AREA_NODES 64
-
-worldSector_t sv_worldSectors[AREA_NODES];
-int sv_numworldSectors;
-
-
-/*
-===============
-SV_SectorList_f
-===============
-*/
-void SV_SectorList_f( void ) {
- int i, c;
- worldSector_t *sec;
- svEntity_t *ent;
-
- for ( i = 0 ; i < AREA_NODES ; i++ ) {
- sec = &sv_worldSectors[i];
-
- c = 0;
- for ( ent = sec->entities ; ent ; ent = ent->nextEntityInWorldSector ) {
- c++;
- }
- Com_Printf( "sector %i: %i entities\n", i, c );
- }
-}
-
-/*
-===============
-SV_CreateworldSector
-
-Builds a uniformly subdivided tree for the given world size
-===============
-*/
-static worldSector_t *SV_CreateworldSector( int depth, vec3_t mins, vec3_t maxs ) {
- worldSector_t *anode;
- vec3_t size;
- vec3_t mins1, maxs1, mins2, maxs2;
-
- anode = &sv_worldSectors[sv_numworldSectors];
- sv_numworldSectors++;
-
- if (depth == AREA_DEPTH) {
- anode->axis = -1;
- anode->children[0] = anode->children[1] = NULL;
- return anode;
- }
-
- VectorSubtract (maxs, mins, size);
- if (size[0] > size[1]) {
- anode->axis = 0;
- } else {
- anode->axis = 1;
- }
-
- anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
- VectorCopy (mins, mins1);
- VectorCopy (mins, mins2);
- VectorCopy (maxs, maxs1);
- VectorCopy (maxs, maxs2);
-
- maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
-
- anode->children[0] = SV_CreateworldSector (depth+1, mins2, maxs2);
- anode->children[1] = SV_CreateworldSector (depth+1, mins1, maxs1);
-
- return anode;
-}
-
-/*
-===============
-SV_ClearWorld
-
-===============
-*/
-void SV_ClearWorld( void ) {
- clipHandle_t h;
- vec3_t mins, maxs;
-
- Com_Memset( sv_worldSectors, 0, sizeof(sv_worldSectors) );
- sv_numworldSectors = 0;
-
- // get world map bounds
- h = CM_InlineModel( 0 );
- CM_ModelBounds( h, mins, maxs );
- SV_CreateworldSector( 0, mins, maxs );
-}
-
-
-/*
-===============
-SV_UnlinkEntity
-
-===============
-*/
-void SV_UnlinkEntity( sharedEntity_t *gEnt ) {
- svEntity_t *ent;
- svEntity_t *scan;
- worldSector_t *ws;
-
- ent = SV_SvEntityForGentity( gEnt );
-
- gEnt->r.linked = qfalse;
-
- ws = ent->worldSector;
- if ( !ws ) {
- return; // not linked in anywhere
- }
- ent->worldSector = NULL;
-
- if ( ws->entities == ent ) {
- ws->entities = ent->nextEntityInWorldSector;
- return;
- }
-
- for ( scan = ws->entities ; scan ; scan = scan->nextEntityInWorldSector ) {
- if ( scan->nextEntityInWorldSector == ent ) {
- scan->nextEntityInWorldSector = ent->nextEntityInWorldSector;
- return;
- }
- }
-
- Com_Printf( "WARNING: SV_UnlinkEntity: not found in worldSector\n" );
-}
-
-
-/*
-===============
-SV_LinkEntity
-
-===============
-*/
-#define MAX_TOTAL_ENT_LEAFS 128
-void SV_LinkEntity( sharedEntity_t *gEnt ) {
- worldSector_t *node;
- int leafs[MAX_TOTAL_ENT_LEAFS];
- int cluster;
- int num_leafs;
- int i, j, k;
- int area;
- int lastLeaf;
- float *origin, *angles;
- svEntity_t *ent;
-
- ent = SV_SvEntityForGentity( gEnt );
-
- if ( ent->worldSector ) {
- SV_UnlinkEntity( gEnt ); // unlink from old position
- }
-
- // encode the size into the entityState_t for client prediction
- if ( gEnt->r.bmodel ) {
- gEnt->s.solid = SOLID_BMODEL; // a solid_box will never create this value
- } else if ( gEnt->r.contents & ( CONTENTS_SOLID | CONTENTS_BODY ) ) {
- // assume that x/y are equal and symetric
- i = gEnt->r.maxs[0];
- if (i<1)
- i = 1;
- if (i>255)
- i = 255;
-
- // z is not symetric
- j = (-gEnt->r.mins[2]);
- if (j<1)
- j = 1;
- if (j>255)
- j = 255;
-
- // and z maxs can be negative...
- k = (gEnt->r.maxs[2]+32);
- if (k<1)
- k = 1;
- if (k>255)
- k = 255;
-
- gEnt->s.solid = (k<<16) | (j<<8) | i;
- } else {
- gEnt->s.solid = 0;
- }
-
- // get the position
- origin = gEnt->r.currentOrigin;
- angles = gEnt->r.currentAngles;
-
- // set the abs box
- if ( gEnt->r.bmodel && (angles[0] || angles[1] || angles[2]) ) {
- // expand for rotation
- float max;
- int i;
-
- max = RadiusFromBounds( gEnt->r.mins, gEnt->r.maxs );
- for (i=0 ; i<3 ; i++) {
- gEnt->r.absmin[i] = origin[i] - max;
- gEnt->r.absmax[i] = origin[i] + max;
- }
- } else {
- // normal
- VectorAdd (origin, gEnt->r.mins, gEnt->r.absmin);
- VectorAdd (origin, gEnt->r.maxs, gEnt->r.absmax);
- }
-
- // because movement is clipped an epsilon away from an actual edge,
- // we must fully check even when bounding boxes don't quite touch
- gEnt->r.absmin[0] -= 1;
- gEnt->r.absmin[1] -= 1;
- gEnt->r.absmin[2] -= 1;
- gEnt->r.absmax[0] += 1;
- gEnt->r.absmax[1] += 1;
- gEnt->r.absmax[2] += 1;
-
- // link to PVS leafs
- ent->numClusters = 0;
- ent->lastCluster = 0;
- ent->areanum = -1;
- ent->areanum2 = -1;
-
- //get all leafs, including solids
- num_leafs = CM_BoxLeafnums( gEnt->r.absmin, gEnt->r.absmax,
- leafs, MAX_TOTAL_ENT_LEAFS, &lastLeaf );
-
- // if none of the leafs were inside the map, the
- // entity is outside the world and can be considered unlinked
- if ( !num_leafs ) {
- return;
- }
-
- // set areas, even from clusters that don't fit in the entity array
- for (i=0 ; i<num_leafs ; i++) {
- area = CM_LeafArea (leafs[i]);
- if (area != -1) {
- // doors may legally straggle two areas,
- // but nothing should evern need more than that
- if (ent->areanum != -1 && ent->areanum != area) {
- if (ent->areanum2 != -1 && ent->areanum2 != area && sv.state == SS_LOADING) {
- Com_DPrintf ("Object %i touching 3 areas at %f %f %f\n",
- gEnt->s.number,
- gEnt->r.absmin[0], gEnt->r.absmin[1], gEnt->r.absmin[2]);
- }
- ent->areanum2 = area;
- } else {
- ent->areanum = area;
- }
- }
- }
-
- // store as many explicit clusters as we can
- ent->numClusters = 0;
- for (i=0 ; i < num_leafs ; i++) {
- cluster = CM_LeafCluster( leafs[i] );
- if ( cluster != -1 ) {
- ent->clusternums[ent->numClusters++] = cluster;
- if ( ent->numClusters == MAX_ENT_CLUSTERS ) {
- break;
- }
- }
- }
-
- // store off a last cluster if we need to
- if ( i != num_leafs ) {
- ent->lastCluster = CM_LeafCluster( lastLeaf );
- }
-
- gEnt->r.linkcount++;
-
- // find the first world sector node that the ent's box crosses
- node = sv_worldSectors;
- while (1)
- {
- if (node->axis == -1)
- break;
- if ( gEnt->r.absmin[node->axis] > node->dist)
- node = node->children[0];
- else if ( gEnt->r.absmax[node->axis] < node->dist)
- node = node->children[1];
- else
- break; // crosses the node
- }
-
- // link it in
- ent->worldSector = node;
- ent->nextEntityInWorldSector = node->entities;
- node->entities = ent;
-
- gEnt->r.linked = qtrue;
-}
-
-/*
-============================================================================
-
-AREA QUERY
-
-Fills in a list of all entities who's absmin / absmax intersects the given
-bounds. This does NOT mean that they actually touch in the case of bmodels.
-============================================================================
-*/
-
-typedef struct {
- const float *mins;
- const float *maxs;
- int *list;
- int count, maxcount;
-} areaParms_t;
-
-
-/*
-====================
-SV_AreaEntities_r
-
-====================
-*/
-static void SV_AreaEntities_r( worldSector_t *node, areaParms_t *ap ) {
- svEntity_t *check, *next;
- sharedEntity_t *gcheck;
- int count;
-
- count = 0;
-
- for ( check = node->entities ; check ; check = next ) {
- next = check->nextEntityInWorldSector;
-
- gcheck = SV_GEntityForSvEntity( check );
-
- if ( gcheck->r.absmin[0] > ap->maxs[0]
- || gcheck->r.absmin[1] > ap->maxs[1]
- || gcheck->r.absmin[2] > ap->maxs[2]
- || gcheck->r.absmax[0] < ap->mins[0]
- || gcheck->r.absmax[1] < ap->mins[1]
- || gcheck->r.absmax[2] < ap->mins[2]) {
- continue;
- }
-
- if ( ap->count == ap->maxcount ) {
- Com_Printf ("SV_AreaEntities: MAXCOUNT\n");
- return;
- }
-
- ap->list[ap->count] = check - sv.svEntities;
- ap->count++;
- }
-
- if (node->axis == -1) {
- return; // terminal node
- }
-
- // recurse down both sides
- if ( ap->maxs[node->axis] > node->dist ) {
- SV_AreaEntities_r ( node->children[0], ap );
- }
- if ( ap->mins[node->axis] < node->dist ) {
- SV_AreaEntities_r ( node->children[1], ap );
- }
-}
-
-/*
-================
-SV_AreaEntities
-================
-*/
-int SV_AreaEntities( const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount ) {
- areaParms_t ap;
-
- ap.mins = mins;
- ap.maxs = maxs;
- ap.list = entityList;
- ap.count = 0;
- ap.maxcount = maxcount;
-
- SV_AreaEntities_r( sv_worldSectors, &ap );
-
- return ap.count;
-}
-
-
-
-//===========================================================================
-
-
-typedef struct {
- vec3_t boxmins, boxmaxs;// enclose the test object along entire move
- const float *mins;
- const float *maxs; // size of the moving object
- const float *start;
- vec3_t end;
- trace_t trace;
- int passEntityNum;
- int contentmask;
- int capsule;
-} moveclip_t;
-
-
-/*
-====================
-SV_ClipToEntity
-
-====================
-*/
-void SV_ClipToEntity( trace_t *trace, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int entityNum, int contentmask, int capsule ) {
- sharedEntity_t *touch;
- clipHandle_t clipHandle;
- float *origin, *angles;
-
- touch = SV_GentityNum( entityNum );
-
- Com_Memset(trace, 0, sizeof(trace_t));
-
- // if it doesn't have any brushes of a type we
- // are looking for, ignore it
- if ( ! ( contentmask & touch->r.contents ) ) {
- trace->fraction = 1.0;
- return;
- }
-
- // might intersect, so do an exact clip
- clipHandle = SV_ClipHandleForEntity (touch);
-
- origin = touch->r.currentOrigin;
- angles = touch->r.currentAngles;
-
- if ( !touch->r.bmodel ) {
- angles = vec3_origin; // boxes don't rotate
- }
-
- CM_TransformedBoxTrace ( trace, (float *)start, (float *)end,
- (float *)mins, (float *)maxs, clipHandle, contentmask,
- origin, angles, capsule);
-
- if ( trace->fraction < 1 ) {
- trace->entityNum = touch->s.number;
- }
-}
-
-
-/*
-====================
-SV_ClipMoveToEntities
-
-====================
-*/
-static void SV_ClipMoveToEntities( moveclip_t *clip ) {
- int i, num;
- int touchlist[MAX_GENTITIES];
- sharedEntity_t *touch;
- int passOwnerNum;
- trace_t trace;
- clipHandle_t clipHandle;
- float *origin, *angles;
-
- num = SV_AreaEntities( clip->boxmins, clip->boxmaxs, touchlist, MAX_GENTITIES);
-
- if ( clip->passEntityNum != ENTITYNUM_NONE ) {
- passOwnerNum = ( SV_GentityNum( clip->passEntityNum ) )->r.ownerNum;
- if ( passOwnerNum == ENTITYNUM_NONE ) {
- passOwnerNum = -1;
- }
- } else {
- passOwnerNum = -1;
- }
-
- for ( i=0 ; i<num ; i++ ) {
- if ( clip->trace.allsolid ) {
- return;
- }
- touch = SV_GentityNum( touchlist[i] );
-
- // see if we should ignore this entity
- if ( clip->passEntityNum != ENTITYNUM_NONE ) {
- if ( touchlist[i] == clip->passEntityNum ) {
- continue; // don't clip against the pass entity
- }
- if ( touch->r.ownerNum == clip->passEntityNum ) {
- continue; // don't clip against own missiles
- }
- if ( touch->r.ownerNum == passOwnerNum ) {
- continue; // don't clip against other missiles from our owner
- }
- }
-
- // if it doesn't have any brushes of a type we
- // are looking for, ignore it
- if ( ! ( clip->contentmask & touch->r.contents ) ) {
- continue;
- }
-
- // might intersect, so do an exact clip
- clipHandle = SV_ClipHandleForEntity (touch);
-
- origin = touch->r.currentOrigin;
- angles = touch->r.currentAngles;
-
-
- if ( !touch->r.bmodel ) {
- angles = vec3_origin; // boxes don't rotate
- }
-
- CM_TransformedBoxTrace ( &trace, (float *)clip->start, (float *)clip->end,
- (float *)clip->mins, (float *)clip->maxs, clipHandle, clip->contentmask,
- origin, angles, clip->capsule);
-
- if ( trace.allsolid ) {
- clip->trace.allsolid = qtrue;
- trace.entityNum = touch->s.number;
- } else if ( trace.startsolid ) {
- clip->trace.startsolid = qtrue;
- trace.entityNum = touch->s.number;
- }
-
- if ( trace.fraction < clip->trace.fraction ) {
- qboolean oldStart;
-
- // make sure we keep a startsolid from a previous trace
- oldStart = clip->trace.startsolid;
-
- trace.entityNum = touch->s.number;
- clip->trace = trace;
- clip->trace.startsolid |= oldStart;
- }
- }
-}
-
-
-/*
-==================
-SV_Trace
-
-Moves the given mins/maxs volume through the world from start to end.
-passEntityNum and entities owned by passEntityNum are explicitly not checked.
-==================
-*/
-void SV_Trace( trace_t *results, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask, int capsule ) {
- moveclip_t clip;
- int i;
-
- if ( !mins ) {
- mins = vec3_origin;
- }
- if ( !maxs ) {
- maxs = vec3_origin;
- }
-
- Com_Memset ( &clip, 0, sizeof ( moveclip_t ) );
-
- // clip to world
- CM_BoxTrace( &clip.trace, start, end, mins, maxs, 0, contentmask, capsule );
- clip.trace.entityNum = clip.trace.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
- if ( clip.trace.fraction == 0 ) {
- *results = clip.trace;
- return; // blocked immediately by the world
- }
-
- clip.contentmask = contentmask;
- clip.start = start;
-// VectorCopy( clip.trace.endpos, clip.end );
- VectorCopy( end, clip.end );
- clip.mins = mins;
- clip.maxs = maxs;
- clip.passEntityNum = passEntityNum;
- clip.capsule = capsule;
-
- // create the bounding box of the entire move
- // we can limit it to the part of the move not
- // already clipped off by the world, which can be
- // a significant savings for line of sight and shot traces
- for ( i=0 ; i<3 ; i++ ) {
- if ( end[i] > start[i] ) {
- clip.boxmins[i] = clip.start[i] + clip.mins[i] - 1;
- clip.boxmaxs[i] = clip.end[i] + clip.maxs[i] + 1;
- } else {
- clip.boxmins[i] = clip.end[i] + clip.mins[i] - 1;
- clip.boxmaxs[i] = clip.start[i] + clip.maxs[i] + 1;
- }
- }
-
- // clip to other solid entities
- SV_ClipMoveToEntities ( &clip );
-
- *results = clip.trace;
-}
-
-
-
-/*
-=============
-SV_PointContents
-=============
-*/
-int SV_PointContents( const vec3_t p, int passEntityNum ) {
- int touch[MAX_GENTITIES];
- sharedEntity_t *hit;
- int i, num;
- int contents, c2;
- clipHandle_t clipHandle;
- float *angles;
-
- // get base contents from world
- contents = CM_PointContents( p, 0 );
-
- // or in contents from all the other entities
- num = SV_AreaEntities( p, p, touch, MAX_GENTITIES );
-
- for ( i=0 ; i<num ; i++ ) {
- if ( touch[i] == passEntityNum ) {
- continue;
- }
- hit = SV_GentityNum( touch[i] );
- // might intersect, so do an exact clip
- clipHandle = SV_ClipHandleForEntity( hit );
- angles = hit->s.angles;
- if ( !hit->r.bmodel ) {
- angles = vec3_origin; // boxes don't rotate
- }
-
- c2 = CM_TransformedPointContents (p, clipHandle, hit->s.origin, hit->s.angles);
-
- contents |= c2;
- }
-
- return contents;
-}
-
-
diff --git a/engine/code/sys/con_log.c b/engine/code/sys/con_log.c
deleted file mode 100644
index c3a4a5b..0000000
--- a/engine/code/sys/con_log.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-#include "sys_local.h"
-
-#define MAX_LOG 32768
-
-static char consoleLog[ MAX_LOG ];
-static unsigned int writePos = 0;
-static unsigned int readPos = 0;
-
-/*
-==================
-CON_LogSize
-==================
-*/
-unsigned int CON_LogSize( void )
-{
- if( readPos <= writePos )
- return writePos - readPos;
- else
- return writePos + MAX_LOG - readPos;
-}
-
-/*
-==================
-CON_LogFree
-==================
-*/
-static unsigned int CON_LogFree( void )
-{
- return MAX_LOG - CON_LogSize( ) - 1;
-}
-
-/*
-==================
-CON_LogWrite
-==================
-*/
-unsigned int CON_LogWrite( const char *in )
-{
- unsigned int length = strlen( in );
- unsigned int firstChunk;
- unsigned int secondChunk;
-
- while( CON_LogFree( ) < length && CON_LogSize( ) > 0 )
- {
- // Free enough space
- while( consoleLog[ readPos ] != '\n' && CON_LogSize( ) > 1 )
- readPos = ( readPos + 1 ) % MAX_LOG;
-
- // Skip past the '\n'
- readPos = ( readPos + 1 ) % MAX_LOG;
- }
-
- if( CON_LogFree( ) < length )
- return 0;
-
- if( writePos + length > MAX_LOG )
- {
- firstChunk = MAX_LOG - writePos;
- secondChunk = length - firstChunk;
- }
- else
- {
- firstChunk = length;
- secondChunk = 0;
- }
-
- Com_Memcpy( consoleLog + writePos, in, firstChunk );
- Com_Memcpy( consoleLog, in + firstChunk, secondChunk );
-
- writePos = ( writePos + length ) % MAX_LOG;
-
- return length;
-}
-
-/*
-==================
-CON_LogRead
-==================
-*/
-unsigned int CON_LogRead( char *out, unsigned int outSize )
-{
- unsigned int firstChunk;
- unsigned int secondChunk;
-
- if( CON_LogSize( ) < outSize )
- outSize = CON_LogSize( );
-
- if( readPos + outSize > MAX_LOG )
- {
- firstChunk = MAX_LOG - readPos;
- secondChunk = outSize - firstChunk;
- }
- else
- {
- firstChunk = outSize;
- secondChunk = 0;
- }
-
- Com_Memcpy( out, consoleLog + readPos, firstChunk );
- Com_Memcpy( out + firstChunk, out, secondChunk );
-
- readPos = ( readPos + outSize ) % MAX_LOG;
-
- return outSize;
-}
diff --git a/engine/code/sys/con_passive.c b/engine/code/sys/con_passive.c
deleted file mode 100644
index 794c895..0000000
--- a/engine/code/sys/con_passive.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-#include "sys_local.h"
-
-#include <stdio.h>
-
-/*
-==================
-CON_Shutdown
-==================
-*/
-void CON_Shutdown( void )
-{
-}
-
-/*
-==================
-CON_Init
-==================
-*/
-void CON_Init( void )
-{
-}
-
-/*
-==================
-CON_Input
-==================
-*/
-char *CON_Input( void )
-{
- return NULL;
-}
-
-/*
-==================
-CON_Print
-==================
-*/
-void CON_Print( const char *msg )
-{
- if( com_ansiColor && com_ansiColor->integer )
- Sys_AnsiColorPrint( msg );
- else
- fputs( msg, stderr );
-}
diff --git a/engine/code/sys/con_tty.c b/engine/code/sys/con_tty.c
deleted file mode 100644
index 7f5f631..0000000
--- a/engine/code/sys/con_tty.c
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-#include "sys_local.h"
-
-#include <unistd.h>
-#include <signal.h>
-#include <termios.h>
-#include <fcntl.h>
-#include <sys/time.h>
-
-/*
-=============================================================
-tty console routines
-
-NOTE: if the user is editing a line when something gets printed to the early
-console then it won't look good so we provide CON_Hide and CON_Show to be
-called before and after a stdout or stderr output
-=============================================================
-*/
-
-extern qboolean stdinIsATTY;
-static qboolean stdin_active;
-// general flag to tell about tty console mode
-static qboolean ttycon_on = qfalse;
-static int ttycon_hide = 0;
-
-// some key codes that the terminal may be using, initialised on start up
-static int TTY_erase;
-static int TTY_eof;
-
-static struct termios TTY_tc;
-
-static field_t TTY_con;
-
-// This is somewhat of aduplicate of the graphical console history
-// but it's safer more modular to have our own here
-#define CON_HISTORY 32
-static field_t ttyEditLines[ CON_HISTORY ];
-static int hist_current = -1, hist_count = 0;
-
-/*
-==================
-CON_FlushIn
-
-Flush stdin, I suspect some terminals are sending a LOT of shit
-FIXME relevant?
-==================
-*/
-static void CON_FlushIn( void )
-{
- char key;
- while (read(STDIN_FILENO, &key, 1)!=-1);
-}
-
-/*
-==================
-CON_Back
-
-Output a backspace
-
-NOTE: it seems on some terminals just sending '\b' is not enough so instead we
-send "\b \b"
-(FIXME there may be a way to find out if '\b' alone would work though)
-==================
-*/
-static void CON_Back( void )
-{
- char key;
- size_t size;
-
- key = '\b';
- size = write(STDOUT_FILENO, &key, 1);
- key = ' ';
- size = write(STDOUT_FILENO, &key, 1);
- key = '\b';
- size = write(STDOUT_FILENO, &key, 1);
-}
-
-/*
-==================
-CON_Hide
-
-Clear the display of the line currently edited
-bring cursor back to beginning of line
-==================
-*/
-static void CON_Hide( void )
-{
- if( ttycon_on )
- {
- int i;
- if (ttycon_hide)
- {
- ttycon_hide++;
- return;
- }
- if (TTY_con.cursor>0)
- {
- for (i=0; i<TTY_con.cursor; i++)
- {
- CON_Back();
- }
- }
- CON_Back(); // Delete "]"
- ttycon_hide++;
- }
-}
-
-/*
-==================
-CON_Show
-
-Show the current line
-FIXME need to position the cursor if needed?
-==================
-*/
-static void CON_Show( void )
-{
- if( ttycon_on )
- {
- int i;
-
- assert(ttycon_hide>0);
- ttycon_hide--;
- if (ttycon_hide == 0)
- {
- size_t size;
- size = write(STDOUT_FILENO, "]", 1);
- if (TTY_con.cursor)
- {
- for (i=0; i<TTY_con.cursor; i++)
- {
- size = write(STDOUT_FILENO, TTY_con.buffer+i, 1);
- }
- }
- }
- }
-}
-
-/*
-==================
-CON_Shutdown
-
-Never exit without calling this, or your terminal will be left in a pretty bad state
-==================
-*/
-void CON_Shutdown( void )
-{
- if (ttycon_on)
- {
- CON_Back(); // Delete "]"
- tcsetattr (STDIN_FILENO, TCSADRAIN, &TTY_tc);
- }
-
- // Restore blocking to stdin reads
- fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
-}
-
-/*
-==================
-Hist_Add
-==================
-*/
-void Hist_Add(field_t *field)
-{
- int i;
- assert(hist_count <= CON_HISTORY);
- assert(hist_count >= 0);
- assert(hist_current >= -1);
- assert(hist_current <= hist_count);
- // make some room
- for (i=CON_HISTORY-1; i>0; i--)
- {
- ttyEditLines[i] = ttyEditLines[i-1];
- }
- ttyEditLines[0] = *field;
- if (hist_count<CON_HISTORY)
- {
- hist_count++;
- }
- hist_current = -1; // re-init
-}
-
-/*
-==================
-Hist_Prev
-==================
-*/
-field_t *Hist_Prev( void )
-{
- int hist_prev;
- assert(hist_count <= CON_HISTORY);
- assert(hist_count >= 0);
- assert(hist_current >= -1);
- assert(hist_current <= hist_count);
- hist_prev = hist_current + 1;
- if (hist_prev >= hist_count)
- {
- return NULL;
- }
- hist_current++;
- return &(ttyEditLines[hist_current]);
-}
-
-/*
-==================
-Hist_Next
-==================
-*/
-field_t *Hist_Next( void )
-{
- assert(hist_count <= CON_HISTORY);
- assert(hist_count >= 0);
- assert(hist_current >= -1);
- assert(hist_current <= hist_count);
- if (hist_current >= 0)
- {
- hist_current--;
- }
- if (hist_current == -1)
- {
- return NULL;
- }
- return &(ttyEditLines[hist_current]);
-}
-
-/*
-==================
-CON_SigCont
-Reinitialize console input after receiving SIGCONT, as on Linux the terminal seems to lose all
-set attributes if user did CTRL+Z and then does fg again.
-==================
-*/
-
-void CON_SigCont(int signum)
-{
- CON_Init();
-}
-
-/*
-==================
-CON_Init
-
-Initialize the console input (tty mode if possible)
-==================
-*/
-void CON_Init( void )
-{
- struct termios tc;
-
- // If the process is backgrounded (running non interactively)
- // then SIGTTIN or SIGTOU is emitted, if not caught, turns into a SIGSTP
- signal(SIGTTIN, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
-
- // If SIGCONT is received, reinitialize console
- signal(SIGCONT, CON_SigCont);
-
- // Make stdin reads non-blocking
- fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK );
-
- if (!stdinIsATTY)
- {
- Com_Printf("tty console mode disabled\n");
- ttycon_on = qfalse;
- stdin_active = qtrue;
- return;
- }
-
- Field_Clear(&TTY_con);
- tcgetattr (STDIN_FILENO, &TTY_tc);
- TTY_erase = TTY_tc.c_cc[VERASE];
- TTY_eof = TTY_tc.c_cc[VEOF];
- tc = TTY_tc;
-
- /*
- ECHO: don't echo input characters
- ICANON: enable canonical mode. This enables the special
- characters EOF, EOL, EOL2, ERASE, KILL, REPRINT,
- STATUS, and WERASE, and buffers by lines.
- ISIG: when any of the characters INTR, QUIT, SUSP, or
- DSUSP are received, generate the corresponding sig
- nal
- */
- tc.c_lflag &= ~(ECHO | ICANON);
-
- /*
- ISTRIP strip off bit 8
- INPCK enable input parity checking
- */
- tc.c_iflag &= ~(ISTRIP | INPCK);
- tc.c_cc[VMIN] = 1;
- tc.c_cc[VTIME] = 0;
- tcsetattr (STDIN_FILENO, TCSADRAIN, &tc);
- ttycon_on = qtrue;
-}
-
-/*
-==================
-CON_Input
-==================
-*/
-char *CON_Input( void )
-{
- // we use this when sending back commands
- static char text[MAX_EDIT_LINE];
- int avail;
- char key;
- field_t *history;
- size_t size;
-
- if(ttycon_on)
- {
- avail = read(STDIN_FILENO, &key, 1);
- if (avail != -1)
- {
- // we have something
- // backspace?
- // NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere
- if ((key == TTY_erase) || (key == 127) || (key == 8))
- {
- if (TTY_con.cursor > 0)
- {
- TTY_con.cursor--;
- TTY_con.buffer[TTY_con.cursor] = '\0';
- CON_Back();
- }
- return NULL;
- }
- // check if this is a control char
- if ((key) && (key) < ' ')
- {
- if (key == '\n')
- {
- // push it in history
- Hist_Add(&TTY_con);
- Q_strncpyz(text, TTY_con.buffer, sizeof(text));
- Field_Clear(&TTY_con);
- key = '\n';
- size = write(1, &key, 1);
- size = write( 1, "]", 1 );
- return text;
- }
- if (key == '\t')
- {
- CON_Hide();
- Field_AutoComplete( &TTY_con );
- CON_Show();
- return NULL;
- }
- avail = read(STDIN_FILENO, &key, 1);
- if (avail != -1)
- {
- // VT 100 keys
- if (key == '[' || key == 'O')
- {
- avail = read(STDIN_FILENO, &key, 1);
- if (avail != -1)
- {
- switch (key)
- {
- case 'A':
- history = Hist_Prev();
- if (history)
- {
- CON_Hide();
- TTY_con = *history;
- CON_Show();
- }
- CON_FlushIn();
- return NULL;
- break;
- case 'B':
- history = Hist_Next();
- CON_Hide();
- if (history)
- {
- TTY_con = *history;
- } else
- {
- Field_Clear(&TTY_con);
- }
- CON_Show();
- CON_FlushIn();
- return NULL;
- break;
- case 'C':
- return NULL;
- case 'D':
- return NULL;
- }
- }
- }
- }
- Com_DPrintf("droping ISCTL sequence: %d, TTY_erase: %d\n", key, TTY_erase);
- CON_FlushIn();
- return NULL;
- }
- if (TTY_con.cursor >= sizeof(text) - 1)
- return NULL;
- // push regular character
- TTY_con.buffer[TTY_con.cursor] = key;
- TTY_con.cursor++;
- // print the current line (this is differential)
- size = write(STDOUT_FILENO, &key, 1);
- }
-
- return NULL;
- }
- else if (stdin_active)
- {
- int len;
- fd_set fdset;
- struct timeval timeout;
-
- 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 == 0)
- { // eof!
- stdin_active = qfalse;
- return NULL;
- }
-
- if (len < 1)
- return NULL;
- text[len-1] = 0; // rip off the /n and terminate
-
- return text;
- }
- return NULL;
-}
-
-/*
-==================
-CON_Print
-==================
-*/
-void CON_Print( const char *msg )
-{
- CON_Hide( );
-
- if( com_ansiColor && com_ansiColor->integer )
- Sys_AnsiColorPrint( msg );
- else
- fputs( msg, stderr );
-
- CON_Show( );
-}
diff --git a/engine/code/sys/con_win32.c b/engine/code/sys/con_win32.c
deleted file mode 100644
index 787c74f..0000000
--- a/engine/code/sys/con_win32.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-#include "sys_local.h"
-#include "windows.h"
-
-#define QCONSOLE_HISTORY 32
-
-static WORD qconsole_attrib;
-
-// saved console status
-static DWORD qconsole_orig_mode;
-static CONSOLE_CURSOR_INFO qconsole_orig_cursorinfo;
-
-// cmd history
-static char qconsole_history[ QCONSOLE_HISTORY ][ MAX_EDIT_LINE ];
-static int qconsole_history_pos = -1;
-static int qconsole_history_oldest = 0;
-
-// current edit buffer
-static char qconsole_line[ MAX_EDIT_LINE ];
-static int qconsole_linelen = 0;
-
-static HANDLE qconsole_hout;
-static HANDLE qconsole_hin;
-
-/*
-==================
-CON_CtrlHandler
-
-The Windows Console doesn't use signals for terminating the application
-with Ctrl-C, logging off, window closing, etc. Instead it uses a special
-handler routine. Fortunately, the values for Ctrl signals don't seem to
-overlap with true signal codes that Windows provides, so calling
-Sys_SigHandler() with those numbers should be safe for generating unique
-shutdown messages.
-==================
-*/
-static BOOL WINAPI CON_CtrlHandler( DWORD sig )
-{
- Sys_SigHandler( sig );
- return TRUE;
-}
-
-/*
-==================
-CON_HistAdd
-==================
-*/
-static void CON_HistAdd( void )
-{
- Q_strncpyz( qconsole_history[ qconsole_history_oldest ], qconsole_line,
- sizeof( qconsole_history[ qconsole_history_oldest ] ) );
-
- if( qconsole_history_oldest >= QCONSOLE_HISTORY - 1 )
- qconsole_history_oldest = 0;
- else
- qconsole_history_oldest++;
-
- qconsole_history_pos = qconsole_history_oldest;
-}
-
-/*
-==================
-CON_HistPrev
-==================
-*/
-static void CON_HistPrev( void )
-{
- int pos;
-
- pos = ( qconsole_history_pos < 1 ) ?
- ( QCONSOLE_HISTORY - 1 ) : ( qconsole_history_pos - 1 );
-
- // don' t allow looping through history
- if( pos == qconsole_history_oldest )
- return;
-
- qconsole_history_pos = pos;
- Q_strncpyz( qconsole_line, qconsole_history[ qconsole_history_pos ],
- sizeof( qconsole_line ) );
- qconsole_linelen = strlen( qconsole_line );
-}
-
-/*
-==================
-CON_HistNext
-==================
-*/
-static void CON_HistNext( void )
-{
- int pos;
-
- pos = ( qconsole_history_pos >= QCONSOLE_HISTORY - 1 ) ?
- 0 : ( qconsole_history_pos + 1 );
-
- // clear the edit buffer if they try to advance to a future command
- if( pos == qconsole_history_oldest )
- {
- qconsole_line[ 0 ] = '\0';
- qconsole_linelen = 0;
- return;
- }
-
- qconsole_history_pos = pos;
- Q_strncpyz( qconsole_line, qconsole_history[ qconsole_history_pos ],
- sizeof( qconsole_line ) );
- qconsole_linelen = strlen( qconsole_line );
-}
-
-
-/*
-==================
-CON_Show
-==================
-*/
-static void CON_Show( void )
-{
- CONSOLE_SCREEN_BUFFER_INFO binfo;
- COORD writeSize = { MAX_EDIT_LINE, 1 };
- COORD writePos = { 0, 0 };
- SMALL_RECT writeArea = { 0, 0, 0, 0 };
- int i;
- CHAR_INFO line[ MAX_EDIT_LINE ];
-
- GetConsoleScreenBufferInfo( qconsole_hout, &binfo );
-
- // if we're in the middle of printf, don't bother writing the buffer
- if( binfo.dwCursorPosition.X != 0 )
- return;
-
- writeArea.Left = 0;
- writeArea.Top = binfo.dwCursorPosition.Y;
- writeArea.Bottom = binfo.dwCursorPosition.Y;
- writeArea.Right = MAX_EDIT_LINE;
-
- // build a space-padded CHAR_INFO array
- for( i = 0; i < MAX_EDIT_LINE; i++ )
- {
- if( i < qconsole_linelen )
- line[ i ].Char.AsciiChar = qconsole_line[ i ];
- else
- line[ i ].Char.AsciiChar = ' ';
-
- line[ i ].Attributes = qconsole_attrib;
- }
-
- if( qconsole_linelen > binfo.srWindow.Right )
- {
- WriteConsoleOutput( qconsole_hout,
- line + (qconsole_linelen - binfo.srWindow.Right ),
- writeSize, writePos, &writeArea );
- }
- else
- {
- WriteConsoleOutput( qconsole_hout, line, writeSize,
- writePos, &writeArea );
- }
-}
-
-/*
-==================
-CON_Shutdown
-==================
-*/
-void CON_Shutdown( void )
-{
- SetConsoleMode( qconsole_hin, qconsole_orig_mode );
- SetConsoleCursorInfo( qconsole_hout, &qconsole_orig_cursorinfo );
- CloseHandle( qconsole_hout );
- CloseHandle( qconsole_hin );
-}
-
-/*
-==================
-CON_Init
-==================
-*/
-void CON_Init( void )
-{
- CONSOLE_CURSOR_INFO curs;
- CONSOLE_SCREEN_BUFFER_INFO info;
- int i;
-
- // handle Ctrl-C or other console termination
- SetConsoleCtrlHandler( CON_CtrlHandler, TRUE );
-
- qconsole_hin = GetStdHandle( STD_INPUT_HANDLE );
- if( qconsole_hin == INVALID_HANDLE_VALUE )
- return;
-
- qconsole_hout = GetStdHandle( STD_OUTPUT_HANDLE );
- if( qconsole_hout == INVALID_HANDLE_VALUE )
- return;
-
- GetConsoleMode( qconsole_hin, &qconsole_orig_mode );
-
- // allow mouse wheel scrolling
- SetConsoleMode( qconsole_hin,
- qconsole_orig_mode & ~ENABLE_MOUSE_INPUT );
-
- FlushConsoleInputBuffer( qconsole_hin );
-
- GetConsoleScreenBufferInfo( qconsole_hout, &info );
- qconsole_attrib = info.wAttributes;
-
- SetConsoleTitle("ioquake3 Dedicated Server Console");
-
- // make cursor invisible
- GetConsoleCursorInfo( qconsole_hout, &qconsole_orig_cursorinfo );
- curs.dwSize = 1;
- curs.bVisible = FALSE;
- SetConsoleCursorInfo( qconsole_hout, &curs );
-
- // initialize history
- for( i = 0; i < QCONSOLE_HISTORY; i++ )
- qconsole_history[ i ][ 0 ] = '\0';
-}
-
-/*
-==================
-CON_Input
-==================
-*/
-char *CON_Input( void )
-{
- INPUT_RECORD buff[ MAX_EDIT_LINE ];
- DWORD count = 0, events = 0;
- WORD key = 0;
- int i;
- int newlinepos = -1;
-
- if( !GetNumberOfConsoleInputEvents( qconsole_hin, &events ) )
- return NULL;
-
- if( events < 1 )
- return NULL;
-
- // if we have overflowed, start dropping oldest input events
- if( events >= MAX_EDIT_LINE )
- {
- ReadConsoleInput( qconsole_hin, buff, 1, &events );
- return NULL;
- }
-
- if( !ReadConsoleInput( qconsole_hin, buff, events, &count ) )
- return NULL;
-
- FlushConsoleInputBuffer( qconsole_hin );
-
- for( i = 0; i < count; i++ )
- {
- if( buff[ i ].EventType != KEY_EVENT )
- continue;
- if( !buff[ i ].Event.KeyEvent.bKeyDown )
- continue;
-
- key = buff[ i ].Event.KeyEvent.wVirtualKeyCode;
-
- if( key == VK_RETURN )
- {
- newlinepos = i;
- break;
- }
- else if( key == VK_UP )
- {
- CON_HistPrev();
- break;
- }
- else if( key == VK_DOWN )
- {
- CON_HistNext();
- break;
- }
- else if( key == VK_TAB )
- {
- field_t f;
-
- Q_strncpyz( f.buffer, qconsole_line,
- sizeof( f.buffer ) );
- Field_AutoComplete( &f );
- Q_strncpyz( qconsole_line, f.buffer,
- sizeof( qconsole_line ) );
- qconsole_linelen = strlen( qconsole_line );
- break;
- }
-
- if( qconsole_linelen < sizeof( qconsole_line ) - 1 )
- {
- char c = buff[ i ].Event.KeyEvent.uChar.AsciiChar;
-
- if( key == VK_BACK )
- {
- int pos = ( qconsole_linelen > 0 ) ?
- qconsole_linelen - 1 : 0;
-
- qconsole_line[ pos ] = '\0';
- qconsole_linelen = pos;
- }
- else if( c )
- {
- qconsole_line[ qconsole_linelen++ ] = c;
- qconsole_line[ qconsole_linelen ] = '\0';
- }
- }
- }
-
- CON_Show();
-
- if( newlinepos < 0)
- return NULL;
-
- if( !qconsole_linelen )
- {
- Com_Printf( "\n" );
- return NULL;
- }
-
- CON_HistAdd();
- Com_Printf( "%s\n", qconsole_line );
-
- qconsole_linelen = 0;
-
- return qconsole_line;
-}
-
-/*
-==================
-CON_Print
-==================
-*/
-void CON_Print( const char *msg )
-{
- fputs( msg, stderr );
-
- CON_Show( );
-}
diff --git a/engine/code/sys/sys_cocoa.m b/engine/code/sys/sys_cocoa.m
deleted file mode 100644
index cfc754d..0000000
--- a/engine/code/sys/sys_cocoa.m
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#ifndef MACOS_X
-#error This file is for Mac OS X only. You probably should not compile it.
-#endif
-
-// Please note that this file is just some Mac-specific bits. Most of the
-// Mac OS X code is shared with other Unix platforms in sys_unix.c ...
-
-#import <Cocoa/Cocoa.h>
-
-void Cocoa_MsgBox( const char *text )
-{
- NSRunInformationalAlertPanel(@"ioquake3",
- [NSString stringWithUTF8String:text],
- @"OK", nil, nil);
-}
-
-// end of sys_cocoa.m ...
-
diff --git a/engine/code/sys/sys_loadlib.h b/engine/code/sys/sys_loadlib.h
deleted file mode 100644
index 994c5d3..0000000
--- a/engine/code/sys/sys_loadlib.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#ifdef DEDICATED
-# ifdef _WIN32
-# include <windows.h>
-# define Sys_LoadLibrary(f) (void*)LoadLibrary(f)
-# define Sys_UnloadLibrary(h) FreeLibrary((HMODULE)h)
-# define Sys_LoadFunction(h,fn) (void*)GetProcAddress((HMODULE)h,fn)
-# define Sys_LibraryError() "unknown"
-# else
-# include <dlfcn.h>
-# define Sys_LoadLibrary(f) dlopen(f,RTLD_NOW)
-# define Sys_UnloadLibrary(h) dlclose(h)
-# define Sys_LoadFunction(h,fn) dlsym(h,fn)
-# define Sys_LibraryError() dlerror()
-# endif
-#else
-# ifdef USE_LOCAL_HEADERS
-# include "SDL.h"
-# include "SDL_loadso.h"
-# else
-# include <SDL.h>
-# include <SDL_loadso.h>
-# endif
-# define Sys_LoadLibrary(f) SDL_LoadObject(f)
-# define Sys_UnloadLibrary(h) SDL_UnloadObject(h)
-# define Sys_LoadFunction(h,fn) SDL_LoadFunction(h,fn)
-# define Sys_LibraryError() SDL_GetError()
-#endif
diff --git a/engine/code/sys/sys_local.h b/engine/code/sys/sys_local.h
deleted file mode 100644
index ee808d4..0000000
--- a/engine/code/sys/sys_local.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-
-// Require a minimum version of SDL
-#define MINSDL_MAJOR 1
-#define MINSDL_MINOR 2
-#define MINSDL_PATCH 10
-
-// Input subsystem
-void IN_Init( void );
-void IN_Frame( void );
-void IN_Shutdown( void );
-void IN_Restart( void );
-
-// Console
-void CON_Shutdown( void );
-void CON_Init( void );
-char *CON_Input( void );
-void CON_Print( const char *message );
-
-unsigned int CON_LogSize( void );
-unsigned int CON_LogWrite( const char *in );
-unsigned int CON_LogRead( char *out, unsigned int outSize );
-
-#ifdef MACOS_X
-char *Sys_StripAppBundle( char *pwd );
-#endif
-
-void Sys_GLimpSafeInit( void );
-void Sys_GLimpInit( void );
-void Sys_PlatformInit( void );
-void Sys_SigHandler( int signal );
-void Sys_ErrorDialog( const char *error );
-void Sys_AnsiColorPrint( const char *msg );
diff --git a/engine/code/sys/sys_main.c b/engine/code/sys/sys_main.c
deleted file mode 100644
index 1adfc93..0000000
--- a/engine/code/sys/sys_main.c
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include <signal.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-
-#ifndef DEDICATED
-#ifdef USE_LOCAL_HEADERS
-# include "SDL.h"
-# include "SDL_cpuinfo.h"
-#else
-# include <SDL.h>
-# include <SDL_cpuinfo.h>
-#endif
-#endif
-
-#include "sys_local.h"
-#include "sys_loadlib.h"
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-
-static char binaryPath[ MAX_OSPATH ] = { 0 };
-static char installPath[ MAX_OSPATH ] = { 0 };
-
-/*
-=================
-Sys_SetBinaryPath
-=================
-*/
-void Sys_SetBinaryPath(const char *path)
-{
- Q_strncpyz(binaryPath, path, sizeof(binaryPath));
-}
-
-/*
-=================
-Sys_BinaryPath
-=================
-*/
-char *Sys_BinaryPath(void)
-{
- return binaryPath;
-}
-
-/*
-=================
-Sys_SetDefaultInstallPath
-=================
-*/
-void Sys_SetDefaultInstallPath(const char *path)
-{
- Q_strncpyz(installPath, path, sizeof(installPath));
-}
-
-/*
-=================
-Sys_DefaultInstallPath
-=================
-*/
-char *Sys_DefaultInstallPath(void)
-{
- if (*installPath)
- return installPath;
- else
- return Sys_Cwd();
-}
-
-/*
-=================
-Sys_DefaultAppPath
-=================
-*/
-char *Sys_DefaultAppPath(void)
-{
- return Sys_BinaryPath();
-}
-
-/*
-=================
-Sys_In_Restart_f
-
-Restart the input subsystem
-=================
-*/
-void Sys_In_Restart_f( void )
-{
- IN_Restart( );
-}
-
-/*
-=================
-Sys_ConsoleInput
-
-Handle new console input
-=================
-*/
-char *Sys_ConsoleInput(void)
-{
- return CON_Input( );
-}
-
-/*
-=================
-Sys_Exit
-
-Single exit point (regular exit or in case of error)
-=================
-*/
-void Sys_Exit( int ex )
-{
- CON_Shutdown( );
-
-#ifndef DEDICATED
- SDL_Quit( );
-#endif
-
-#ifdef NDEBUG
- exit( ex );
-#else
- // Cause a backtrace on error exits
- assert( ex == 0 );
- exit( ex );
-#endif
-}
-
-/*
-=================
-Sys_Quit
-=================
-*/
-void Sys_Quit( void )
-{
- CL_Shutdown( );
- Sys_Exit( 0 );
-}
-
-/*
-=================
-Sys_GetProcessorFeatures
-=================
-*/
-cpuFeatures_t Sys_GetProcessorFeatures( void )
-{
- cpuFeatures_t features = 0;
-
-#ifndef DEDICATED
- if( SDL_HasRDTSC( ) ) features |= CF_RDTSC;
- if( SDL_HasMMX( ) ) features |= CF_MMX;
- if( SDL_HasMMXExt( ) ) features |= CF_MMX_EXT;
- if( SDL_Has3DNow( ) ) features |= CF_3DNOW;
- if( SDL_Has3DNowExt( ) ) features |= CF_3DNOW_EXT;
- if( SDL_HasSSE( ) ) features |= CF_SSE;
- if( SDL_HasSSE2( ) ) features |= CF_SSE2;
- if( SDL_HasAltiVec( ) ) features |= CF_ALTIVEC;
-#endif
-
- return features;
-}
-
-/*
-=================
-Sys_Init
-=================
-*/
-void Sys_Init(void)
-{
- Cmd_AddCommand( "in_restart", Sys_In_Restart_f );
- Cvar_Set( "arch", OS_STRING " " ARCH_STRING );
- Cvar_Set( "username", Sys_GetCurrentUser( ) );
-}
-
-/*
-=================
-Sys_AnsiColorPrint
-
-Transform Q3 colour codes to ANSI escape sequences
-=================
-*/
-void Sys_AnsiColorPrint( const char *msg )
-{
- static char buffer[ MAXPRINTMSG ];
- int length = 0;
- static int q3ToAnsi[ 8 ] =
- {
- 30, // COLOR_BLACK
- 31, // COLOR_RED
- 32, // COLOR_GREEN
- 33, // COLOR_YELLOW
- 34, // COLOR_BLUE
- 36, // COLOR_CYAN
- 35, // COLOR_MAGENTA
- 0 // COLOR_WHITE
- };
-
- while( *msg )
- {
- if( Q_IsColorString( msg ) || *msg == '\n' )
- {
- // First empty the buffer
- if( length > 0 )
- {
- buffer[ length ] = '\0';
- fputs( buffer, stderr );
- length = 0;
- }
-
- if( *msg == '\n' )
- {
- // Issue a reset and then the newline
- fputs( "\033[0m\n", stderr );
- msg++;
- }
- else
- {
- // Print the color code
- Com_sprintf( buffer, sizeof( buffer ), "\033[%dm",
- q3ToAnsi[ ColorIndex( *( msg + 1 ) ) ] );
- fputs( buffer, stderr );
- msg += 2;
- }
- }
- else
- {
- if( length >= MAXPRINTMSG - 1 )
- break;
-
- buffer[ length ] = *msg;
- length++;
- msg++;
- }
- }
-
- // Empty anything still left in the buffer
- if( length > 0 )
- {
- buffer[ length ] = '\0';
- fputs( buffer, stderr );
- }
-}
-
-/*
-=================
-Sys_Print
-=================
-*/
-void Sys_Print( const char *msg )
-{
- CON_LogWrite( msg );
- CON_Print( msg );
-}
-
-/*
-=================
-Sys_Error
-=================
-*/
-void Sys_Error( const char *error, ... )
-{
- va_list argptr;
- char string[1024];
-
- CL_Shutdown ();
-
- va_start (argptr,error);
- Q_vsnprintf (string, sizeof(string), error, argptr);
- va_end (argptr);
-
- Sys_ErrorDialog( string );
-
- Sys_Exit( 1 );
-}
-
-/*
-=================
-Sys_Warn
-=================
-*/
-void Sys_Warn( char *warning, ... )
-{
- va_list argptr;
- char string[1024];
-
- va_start (argptr,warning);
- Q_vsnprintf (string, sizeof(string), warning, argptr);
- va_end (argptr);
-
- CON_Print( va( "Warning: %s", string ) );
-}
-
-/*
-============
-Sys_FileTime
-
-returns -1 if not present
-============
-*/
-int Sys_FileTime( char *path )
-{
- struct stat buf;
-
- if (stat (path,&buf) == -1)
- return -1;
-
- return buf.st_mtime;
-}
-
-/*
-=================
-Sys_UnloadDll
-=================
-*/
-void Sys_UnloadDll( void *dllHandle )
-{
- if( !dllHandle )
- {
- Com_Printf("Sys_UnloadDll(NULL)\n");
- return;
- }
-
- Sys_UnloadLibrary(dllHandle);
-}
-
-/*
-=================
-Sys_TryLibraryLoad
-=================
-*/
-static void* Sys_TryLibraryLoad(const char* base, const char* gamedir, const char* fname, char* fqpath )
-{
- void* libHandle;
- char* fn;
-
- *fqpath = 0;
-
- fn = FS_BuildOSPath( base, gamedir, fname );
- Com_Printf( "Sys_LoadDll(%s)... \n", fn );
-
- libHandle = Sys_LoadLibrary(fn);
-
- if(!libHandle) {
- Com_Printf( "Sys_LoadDll(%s) failed:\n\"%s\"\n", fn, Sys_LibraryError() );
- return NULL;
- }
-
- Com_Printf ( "Sys_LoadDll(%s): succeeded ...\n", fn );
- Q_strncpyz ( fqpath , fn , MAX_QPATH ) ;
-
- return libHandle;
-}
-
-/*
-=================
-Sys_LoadDll
-
-Used to load a development dll instead of a virtual machine
-#1 look in fs_homepath
-#2 look in fs_basepath
-=================
-*/
-void *Sys_LoadDll( const char *name, char *fqpath ,
- intptr_t (**entryPoint)(int, ...),
- intptr_t (*systemcalls)(intptr_t, ...) )
-{
- void *libHandle;
- void (*dllEntry)( intptr_t (*syscallptr)(intptr_t, ...) );
- char fname[MAX_OSPATH];
- char *basepath;
- char *homepath;
- char *gamedir;
-
- assert( name );
-
- Q_snprintf (fname, sizeof(fname), "%s" ARCH_STRING DLL_EXT, name);
-
- // TODO: use fs_searchpaths from files.c
- basepath = Cvar_VariableString( "fs_basepath" );
- homepath = Cvar_VariableString( "fs_homepath" );
- gamedir = Cvar_VariableString( "fs_game" );
-
- libHandle = Sys_TryLibraryLoad(homepath, gamedir, fname, fqpath);
-
- if(!libHandle && basepath)
- libHandle = Sys_TryLibraryLoad(basepath, gamedir, fname, fqpath);
-
- if(!libHandle) {
- Com_Printf ( "Sys_LoadDll(%s) failed to load library\n", name );
- return NULL;
- }
-
- dllEntry = Sys_LoadFunction( libHandle, "dllEntry" );
- *entryPoint = Sys_LoadFunction( libHandle, "vmMain" );
-
- if ( !*entryPoint || !dllEntry )
- {
- Com_Printf ( "Sys_LoadDll(%s) failed to find vmMain function:\n\"%s\" !\n", name, Sys_LibraryError( ) );
- Sys_UnloadLibrary(libHandle);
-
- return NULL;
- }
-
- Com_Printf ( "Sys_LoadDll(%s) found vmMain function at %p\n", name, *entryPoint );
- dllEntry( systemcalls );
-
- return libHandle;
-}
-
-/*
-=================
-Sys_ParseArgs
-=================
-*/
-void Sys_ParseArgs( int argc, char **argv )
-{
- if( argc == 2 )
- {
- if( !strcmp( argv[1], "--version" ) ||
- !strcmp( argv[1], "-v" ) )
- {
- const char* date = __DATE__;
-#ifdef DEDICATED
- fprintf( stdout, Q3_VERSION " dedicated server (%s)\n", date );
-#else
- fprintf( stdout, Q3_VERSION " client (%s)\n", date );
-#endif
- Sys_Exit(0);
- }
- }
-}
-
-#ifndef DEFAULT_BASEDIR
-# ifdef MACOS_X
-# define DEFAULT_BASEDIR Sys_StripAppBundle(Sys_BinaryPath())
-# else
-# define DEFAULT_BASEDIR Sys_BinaryPath()
-# endif
-#endif
-
-/*
-=================
-Sys_SigHandler
-=================
-*/
-void Sys_SigHandler( int signal )
-{
- static qboolean signalcaught = qfalse;
-
- if( signalcaught )
- {
- fprintf( stderr, "DOUBLE SIGNAL FAULT: Received signal %d, exiting...\n",
- signal );
- }
- else
- {
- signalcaught = qtrue;
- fprintf( stderr, "Received signal %d, exiting...\n", signal );
-#ifndef DEDICATED
- CL_Shutdown();
-#endif
- SV_Shutdown( "Signal caught" );
- }
-
- Sys_Exit( 0 ); // Exit with 0 to avoid recursive signals
-}
-
-/*
-=================
-main
-=================
-*/
-int main( int argc, char **argv )
-{
- int i;
- char commandLine[ MAX_STRING_CHARS ] = { 0 };
-
-#ifndef DEDICATED
- // SDL version check
-
- // Compile time
-# if !SDL_VERSION_ATLEAST(MINSDL_MAJOR,MINSDL_MINOR,MINSDL_PATCH)
-# error A more recent version of SDL is required
-# endif
-
- // Run time
- const SDL_version *ver = SDL_Linked_Version( );
-
-#define MINSDL_VERSION \
- XSTRING(MINSDL_MAJOR) "." \
- XSTRING(MINSDL_MINOR) "." \
- XSTRING(MINSDL_PATCH)
-
- if( SDL_VERSIONNUM( ver->major, ver->minor, ver->patch ) <
- SDL_VERSIONNUM( MINSDL_MAJOR, MINSDL_MINOR, MINSDL_PATCH ) )
- {
- Sys_Print( "SDL version " MINSDL_VERSION " or greater required\n" );
- Sys_Exit( 1 );
- }
-#endif
-
- Sys_PlatformInit( );
-
- // Set the initial time base
- Sys_Milliseconds( );
-
- Sys_ParseArgs( argc, argv );
- Sys_SetBinaryPath( Sys_Dirname( argv[ 0 ] ) );
- Sys_SetDefaultInstallPath( DEFAULT_BASEDIR );
-
- // Concatenate the command line for passing to Com_Init
- for( i = 1; i < argc; i++ )
- {
- const qboolean containsSpaces = strchr(argv[i], ' ') != NULL;
- if (containsSpaces)
- Q_strcat( commandLine, sizeof( commandLine ), "\"" );
-
- Q_strcat( commandLine, sizeof( commandLine ), argv[ i ] );
-
- if (containsSpaces)
- Q_strcat( commandLine, sizeof( commandLine ), "\"" );
-
- Q_strcat( commandLine, sizeof( commandLine ), " " );
- }
-
- Com_Init( commandLine );
- NET_Init( );
-
- CON_Init( );
-
- signal( SIGILL, Sys_SigHandler );
- signal( SIGFPE, Sys_SigHandler );
- signal( SIGSEGV, Sys_SigHandler );
- signal( SIGTERM, Sys_SigHandler );
- signal( SIGINT, Sys_SigHandler );
-
- while( 1 )
- {
-#ifndef DEDICATED
- int appState = SDL_GetAppState( );
-
- Cvar_SetValue( "com_unfocused", !( appState & SDL_APPINPUTFOCUS ) );
- Cvar_SetValue( "com_minimized", !( appState & SDL_APPACTIVE ) );
-#endif
-
- IN_Frame( );
- Com_Frame( );
- }
-
- return 0;
-}
-
diff --git a/engine/code/sys/sys_unix.c b/engine/code/sys/sys_unix.c
deleted file mode 100644
index c0b4ecb..0000000
--- a/engine/code/sys/sys_unix.c
+++ /dev/null
@@ -1,613 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-#include "sys_local.h"
-
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <stdio.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <pwd.h>
-#include <libgen.h>
-#include <fcntl.h>
-
-qboolean stdinIsATTY;
-
-// Used to determine where to store user-specific files
-static char homePath[ MAX_OSPATH ] = { 0 };
-
-/*
-==================
-Sys_DefaultHomePath
-==================
-*/
-char *Sys_DefaultHomePath(void)
-{
- char *p;
-
- if( !*homePath )
- {
- if( ( p = getenv( "HOME" ) ) != NULL )
- {
- Q_strncpyz( homePath, p, sizeof( homePath ) );
-#ifdef MACOS_X
- Q_strcat( homePath, sizeof( homePath ),
- "/Library/Application Support/Quake3" );
-#else
- Q_strcat( homePath, sizeof( homePath ), "/.q3a" );
-#endif
- }
- }
-
- return homePath;
-}
-
-/*
-================
-Sys_Milliseconds
-================
-*/
-/* base time in seconds, that's our origin
- timeval:tv_sec is an int:
- assuming this wraps every 0x7fffffff - ~68 years since the Epoch (1970) - we're safe till 2038
- using unsigned long data type to work right with Sys_XTimeToSysTime */
-unsigned long sys_timeBase = 0;
-/* current time in ms, using sys_timeBase as origin
- NOTE: sys_timeBase*1000 + curtime -> ms since the Epoch
- 0x7fffffff ms - ~24 days
- although timeval:tv_usec is an int, I'm not sure wether it is actually used as an unsigned int
- (which would affect the wrap period) */
-int curtime;
-int Sys_Milliseconds (void)
-{
- struct timeval tp;
-
- gettimeofday(&tp, NULL);
-
- if (!sys_timeBase)
- {
- sys_timeBase = tp.tv_sec;
- return tp.tv_usec/1000;
- }
-
- curtime = (tp.tv_sec - sys_timeBase)*1000 + tp.tv_usec/1000;
-
- return curtime;
-}
-
-#if !id386
-/*
-==================
-fastftol
-==================
-*/
-long fastftol( float f )
-{
- return (long)f;
-}
-
-/*
-==================
-Sys_SnapVector
-==================
-*/
-void Sys_SnapVector( float *v )
-{
- v[0] = rint(v[0]);
- v[1] = rint(v[1]);
- v[2] = rint(v[2]);
-}
-#endif
-
-
-/*
-==================
-Sys_RandomBytes
-==================
-*/
-qboolean Sys_RandomBytes( byte *string, int len )
-{
- FILE *fp;
-
- fp = fopen( "/dev/urandom", "r" );
- if( !fp )
- return qfalse;
-
- if( !fread( string, sizeof( byte ), len, fp ) )
- {
- fclose( fp );
- return qfalse;
- }
-
- fclose( fp );
- return qtrue;
-}
-
-/*
-==================
-Sys_GetCurrentUser
-==================
-*/
-char *Sys_GetCurrentUser( void )
-{
- struct passwd *p;
-
- if ( (p = getpwuid( getuid() )) == NULL ) {
- return "player";
- }
- return p->pw_name;
-}
-
-/*
-==================
-Sys_GetClipboardData
-==================
-*/
-char *Sys_GetClipboardData(void)
-{
- return NULL;
-}
-
-#define MEM_THRESHOLD 96*1024*1024
-
-/*
-==================
-Sys_LowPhysicalMemory
-
-TODO
-==================
-*/
-qboolean Sys_LowPhysicalMemory( void )
-{
- return qfalse;
-}
-
-/*
-==================
-Sys_Basename
-==================
-*/
-const char *Sys_Basename( char *path )
-{
- return basename( path );
-}
-
-/*
-==================
-Sys_Dirname
-==================
-*/
-const char *Sys_Dirname( char *path )
-{
- return dirname( path );
-}
-
-/*
-==================
-Sys_Mkdir
-==================
-*/
-qboolean Sys_Mkdir( const char *path )
-{
- int result = mkdir( path, 0750 );
-
- if( result != 0 )
- return errno == EEXIST;
-
- return qtrue;
-}
-
-/*
-==================
-Sys_Cwd
-==================
-*/
-char *Sys_Cwd( void )
-{
- static char cwd[MAX_OSPATH];
-
- char *result = getcwd( cwd, sizeof( cwd ) - 1 );
- if( result != cwd )
- return NULL;
-
- cwd[MAX_OSPATH-1] = 0;
-
- return cwd;
-}
-
-/*
-==============================================================
-
-DIRECTORY SCANNING
-
-==============================================================
-*/
-
-#define MAX_FOUND_FILES 0x1000
-
-/*
-==================
-Sys_ListFilteredFiles
-==================
-*/
-void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles )
-{
- char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
- char filename[MAX_OSPATH];
- DIR *fdir;
- struct dirent *d;
- struct stat st;
-
- if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
- return;
- }
-
- if (strlen(subdirs)) {
- Com_sprintf( search, sizeof(search), "%s/%s", basedir, subdirs );
- }
- else {
- Com_sprintf( search, sizeof(search), "%s", basedir );
- }
-
- if ((fdir = opendir(search)) == NULL) {
- return;
- }
-
- while ((d = readdir(fdir)) != NULL) {
- Com_sprintf(filename, sizeof(filename), "%s/%s", search, d->d_name);
- if (stat(filename, &st) == -1)
- continue;
-
- if (st.st_mode & S_IFDIR) {
- if (Q_stricmp(d->d_name, ".") && Q_stricmp(d->d_name, "..")) {
- if (strlen(subdirs)) {
- Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s/%s", subdirs, d->d_name);
- }
- else {
- Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", d->d_name);
- }
- Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
- }
- }
- if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
- break;
- }
- Com_sprintf( filename, sizeof(filename), "%s/%s", subdirs, d->d_name );
- if (!Com_FilterPath( filter, filename, qfalse ))
- continue;
- list[ *numfiles ] = CopyString( filename );
- (*numfiles)++;
- }
-
- closedir(fdir);
-}
-
-/*
-==================
-Sys_ListFiles
-==================
-*/
-char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs )
-{
- struct dirent *d;
- DIR *fdir;
- qboolean dironly = wantsubs;
- char search[MAX_OSPATH];
- int nfiles;
- char **listCopy;
- char *list[MAX_FOUND_FILES];
- int i;
- struct stat st;
-
- int extLen;
-
- if (filter) {
-
- nfiles = 0;
- Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
-
- list[ nfiles ] = NULL;
- *numfiles = nfiles;
-
- if (!nfiles)
- return NULL;
-
- listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
- for ( i = 0 ; i < nfiles ; i++ ) {
- listCopy[i] = list[i];
- }
- listCopy[i] = NULL;
-
- return listCopy;
- }
-
- if ( !extension)
- extension = "";
-
- if ( extension[0] == '/' && extension[1] == 0 ) {
- extension = "";
- dironly = qtrue;
- }
-
- extLen = strlen( extension );
-
- // search
- nfiles = 0;
-
- if ((fdir = opendir(directory)) == NULL) {
- *numfiles = 0;
- return NULL;
- }
-
- while ((d = readdir(fdir)) != NULL) {
- Com_sprintf(search, sizeof(search), "%s/%s", directory, d->d_name);
- if (stat(search, &st) == -1)
- continue;
- if ((dironly && !(st.st_mode & S_IFDIR)) ||
- (!dironly && (st.st_mode & S_IFDIR)))
- continue;
-
- if (*extension) {
- if ( strlen( d->d_name ) < strlen( extension ) ||
- Q_stricmp(
- d->d_name + strlen( d->d_name ) - strlen( extension ),
- extension ) ) {
- continue; // didn't match
- }
- }
-
- if ( nfiles == MAX_FOUND_FILES - 1 )
- break;
- list[ nfiles ] = CopyString( d->d_name );
- nfiles++;
- }
-
- list[ nfiles ] = NULL;
-
- closedir(fdir);
-
- // return a copy of the list
- *numfiles = nfiles;
-
- if ( !nfiles ) {
- return NULL;
- }
-
- listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
- for ( i = 0 ; i < nfiles ; i++ ) {
- listCopy[i] = list[i];
- }
- listCopy[i] = NULL;
-
- return listCopy;
-}
-
-/*
-==================
-Sys_FreeFileList
-==================
-*/
-void Sys_FreeFileList( char **list )
-{
- int i;
-
- if ( !list ) {
- return;
- }
-
- for ( i = 0 ; list[i] ; i++ ) {
- Z_Free( list[i] );
- }
-
- Z_Free( list );
-}
-
-#ifdef MACOS_X
-/*
-=================
-Sys_StripAppBundle
-
-Discovers if passed dir is suffixed with the directory structure of a Mac OS X
-.app bundle. If it is, the .app directory structure is stripped off the end and
-the result is returned. If not, dir is returned untouched.
-=================
-*/
-char *Sys_StripAppBundle( char *dir )
-{
- static char cwd[MAX_OSPATH];
-
- Q_strncpyz(cwd, dir, sizeof(cwd));
- if(strcmp(Sys_Basename(cwd), "MacOS"))
- return dir;
- Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
- if(strcmp(Sys_Basename(cwd), "Contents"))
- return dir;
- Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
- if(!strstr(Sys_Basename(cwd), ".app"))
- return dir;
- Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
- return cwd;
-}
-#endif // MACOS_X
-
-
-/*
-==================
-Sys_Sleep
-
-Block execution for msec or until input is recieved.
-==================
-*/
-void Sys_Sleep( int msec )
-{
- if( msec == 0 )
- return;
-
- if( stdinIsATTY )
- {
- fd_set fdset;
-
- FD_ZERO(&fdset);
- FD_SET(STDIN_FILENO, &fdset);
- if( msec < 0 )
- {
- select(STDIN_FILENO + 1, &fdset, NULL, NULL, NULL);
- }
- else
- {
- struct timeval timeout;
-
- timeout.tv_sec = msec/1000;
- timeout.tv_usec = (msec%1000)*1000;
- select(STDIN_FILENO + 1, &fdset, NULL, NULL, &timeout);
- }
- }
- else
- {
- // With nothing to select() on, we can't wait indefinitely
- if( msec < 0 )
- msec = 10;
-
- usleep( msec * 1000 );
- }
-}
-
-/*
-==============
-Sys_ErrorDialog
-
-Display an error message
-==============
-*/
-void Sys_ErrorDialog( const char *error )
-{
- char buffer[ 1024 ];
- unsigned int size;
- int f = -1;
- const char *homepath = Cvar_VariableString( "fs_homepath" );
- const char *gamedir = Cvar_VariableString( "fs_gamedir" );
- const char *fileName = "crashlog.txt";
- char *ospath = FS_BuildOSPath( homepath, gamedir, fileName );
-
- Sys_Print( va( "%s\n", error ) );
-
-#if defined(MACOS_X) && !DEDICATED
- /* This function has to be in a separate file, compiled as Objective-C. */
- extern void Cocoa_MsgBox( const char *text );
- if (!com_dedicated || !com_dedicated->integer)
- Cocoa_MsgBox(error);
-#endif
-
- /* make sure the write path for the crashlog exists... */
- if( FS_CreatePath( ospath ) ) {
- Com_Printf( "ERROR: couldn't create path '%s' for crash log.\n", ospath );
- return;
- }
-
- /* we might be crashing because we maxed out the Quake MAX_FILE_HANDLES,
- which will come through here, so we don't want to recurse forever by
- calling FS_FOpenFileWrite()...use the Unix system APIs instead. */
- f = open(ospath, O_CREAT | O_TRUNC | O_WRONLY, 0640);
- if( f == -1 )
- {
- Com_Printf( "ERROR: couldn't open %s\n", fileName );
- return;
- }
-
- /* We're crashing, so we don't care much if write() or close() fails. */
- while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 ) {
- if (write( f, buffer, size ) != size) {
- Com_Printf( "ERROR: couldn't fully write to %s\n", fileName );
- break;
- }
- }
-
- close(f);
-}
-
-/*
-==============
-Sys_GLimpSafeInit
-
-Unix specific "safe" GL implementation initialisation
-==============
-*/
-void Sys_GLimpSafeInit( void )
-{
- // NOP
-}
-
-/*
-==============
-Sys_GLimpInit
-
-Unix specific GL implementation initialisation
-==============
-*/
-void Sys_GLimpInit( void )
-{
- // NOP
-}
-
-/*
-==============
-Sys_PlatformInit
-
-Unix specific initialisation
-==============
-*/
-void Sys_PlatformInit( void )
-{
- const char* term = getenv( "TERM" );
-
- signal( SIGHUP, Sys_SigHandler );
- signal( SIGQUIT, Sys_SigHandler );
- signal( SIGTRAP, Sys_SigHandler );
- signal( SIGIOT, Sys_SigHandler );
- signal( SIGBUS, Sys_SigHandler );
-
- stdinIsATTY = isatty( STDIN_FILENO ) &&
- !( term && ( !strcmp( term, "raw" ) || !strcmp( term, "dumb" ) ) );
-}
-
-/*
-==============
-Sys_SetEnv
-
-set/unset environment variables (empty value removes it)
-==============
-*/
-
-void Sys_SetEnv(const char *name, const char *value)
-{
- if(value && *value)
- setenv(name, value, 1);
- else
- unsetenv(name);
-}
diff --git a/engine/code/sys/sys_win32.c b/engine/code/sys/sys_win32.c
deleted file mode 100644
index c428533..0000000
--- a/engine/code/sys/sys_win32.c
+++ /dev/null
@@ -1,665 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../qcommon/q_shared.h"
-#include "../qcommon/qcommon.h"
-#include "sys_local.h"
-
-#include <windows.h>
-#include <lmerr.h>
-#include <lmcons.h>
-#include <lmwksta.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <direct.h>
-#include <io.h>
-#include <conio.h>
-#include <wincrypt.h>
-#include <shlobj.h>
-
-// Used to determine where to store user-specific files
-static char homePath[ MAX_OSPATH ] = { 0 };
-
-/*
-================
-Sys_DefaultHomePath
-================
-*/
-char *Sys_DefaultHomePath( void )
-{
- TCHAR szPath[MAX_PATH];
- FARPROC qSHGetFolderPath;
- HMODULE shfolder = LoadLibrary("shfolder.dll");
-
- if( !*homePath )
- {
- if(shfolder == NULL)
- {
- Com_Printf("Unable to load SHFolder.dll\n");
- return NULL;
- }
-
- qSHGetFolderPath = GetProcAddress(shfolder, "SHGetFolderPathA");
- if(qSHGetFolderPath == NULL)
- {
- Com_Printf("Unable to find SHGetFolderPath in SHFolder.dll\n");
- FreeLibrary(shfolder);
- return NULL;
- }
-
- if( !SUCCEEDED( qSHGetFolderPath( NULL, CSIDL_APPDATA,
- NULL, 0, szPath ) ) )
- {
- Com_Printf("Unable to detect CSIDL_APPDATA\n");
- FreeLibrary(shfolder);
- return NULL;
- }
- Q_strncpyz( homePath, szPath, sizeof( homePath ) );
- Q_strcat( homePath, sizeof( homePath ), "\\Quake3" );
- FreeLibrary(shfolder);
- }
-
- return homePath;
-}
-
-/*
-================
-Sys_Milliseconds
-================
-*/
-int sys_timeBase;
-int Sys_Milliseconds (void)
-{
- int sys_curtime;
- static qboolean initialized = qfalse;
-
- if (!initialized) {
- sys_timeBase = timeGetTime();
- initialized = qtrue;
- }
- sys_curtime = timeGetTime() - sys_timeBase;
-
- return sys_curtime;
-}
-
-#ifndef __GNUC__ //see snapvectora.s
-/*
-================
-Sys_SnapVector
-================
-*/
-void Sys_SnapVector( float *v )
-{
- int i;
- float f;
-
- f = *v;
- __asm fld f;
- __asm fistp i;
- *v = i;
- v++;
- f = *v;
- __asm fld f;
- __asm fistp i;
- *v = i;
- v++;
- f = *v;
- __asm fld f;
- __asm fistp i;
- *v = i;
-}
-#endif
-
-/*
-================
-Sys_RandomBytes
-================
-*/
-qboolean Sys_RandomBytes( byte *string, int len )
-{
- HCRYPTPROV prov;
-
- if( !CryptAcquireContext( &prov, NULL, NULL,
- PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) ) {
-
- return qfalse;
- }
-
- if( !CryptGenRandom( prov, len, (BYTE *)string ) ) {
- CryptReleaseContext( prov, 0 );
- return qfalse;
- }
- CryptReleaseContext( prov, 0 );
- return qtrue;
-}
-
-/*
-================
-Sys_GetCurrentUser
-================
-*/
-char *Sys_GetCurrentUser( void )
-{
- static char s_userName[1024];
- unsigned long size = sizeof( s_userName );
-
- if( !GetUserName( s_userName, &size ) )
- strcpy( s_userName, "player" );
-
- if( !s_userName[0] )
- {
- strcpy( s_userName, "player" );
- }
-
- return s_userName;
-}
-
-/*
-================
-Sys_GetClipboardData
-================
-*/
-char *Sys_GetClipboardData( void )
-{
- char *data = NULL;
- char *cliptext;
-
- if ( OpenClipboard( NULL ) != 0 ) {
- HANDLE hClipboardData;
-
- if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 ) {
- if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 ) {
- data = Z_Malloc( GlobalSize( hClipboardData ) + 1 );
- Q_strncpyz( data, cliptext, GlobalSize( hClipboardData ) );
- GlobalUnlock( hClipboardData );
-
- strtok( data, "\n\r\b" );
- }
- }
- CloseClipboard();
- }
- return data;
-}
-
-#define MEM_THRESHOLD 96*1024*1024
-
-/*
-==================
-Sys_LowPhysicalMemory
-==================
-*/
-qboolean Sys_LowPhysicalMemory( void )
-{
- MEMORYSTATUS stat;
- GlobalMemoryStatus (&stat);
- return (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse;
-}
-
-/*
-==============
-Sys_Basename
-==============
-*/
-const char *Sys_Basename( char *path )
-{
- static char base[ MAX_OSPATH ] = { 0 };
- int length;
-
- length = strlen( path ) - 1;
-
- // Skip trailing slashes
- while( length > 0 && path[ length ] == '\\' )
- length--;
-
- while( length > 0 && path[ length - 1 ] != '\\' )
- length--;
-
- Q_strncpyz( base, &path[ length ], sizeof( base ) );
-
- length = strlen( base ) - 1;
-
- // Strip trailing slashes
- while( length > 0 && base[ length ] == '\\' )
- base[ length-- ] = '\0';
-
- return base;
-}
-
-/*
-==============
-Sys_Dirname
-==============
-*/
-const char *Sys_Dirname( char *path )
-{
- static char dir[ MAX_OSPATH ] = { 0 };
- int length;
-
- Q_strncpyz( dir, path, sizeof( dir ) );
- length = strlen( dir ) - 1;
-
- while( length > 0 && dir[ length ] != '\\' )
- length--;
-
- dir[ length ] = '\0';
-
- return dir;
-}
-
-/*
-==============
-Sys_Mkdir
-==============
-*/
-qboolean Sys_Mkdir( const char *path )
-{
- if( !CreateDirectory( path, NULL ) )
- {
- if( GetLastError( ) != ERROR_ALREADY_EXISTS )
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-==============
-Sys_Cwd
-==============
-*/
-char *Sys_Cwd( void ) {
- static char cwd[MAX_OSPATH];
-
- _getcwd( cwd, sizeof( cwd ) - 1 );
- cwd[MAX_OSPATH-1] = 0;
-
- return cwd;
-}
-
-/*
-==============================================================
-
-DIRECTORY SCANNING
-
-==============================================================
-*/
-
-#define MAX_FOUND_FILES 0x1000
-
-/*
-==============
-Sys_ListFilteredFiles
-==============
-*/
-void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles )
-{
- char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
- char filename[MAX_OSPATH];
- int findhandle;
- struct _finddata_t findinfo;
-
- if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
- return;
- }
-
- if (strlen(subdirs)) {
- Com_sprintf( search, sizeof(search), "%s\\%s\\*", basedir, subdirs );
- }
- else {
- Com_sprintf( search, sizeof(search), "%s\\*", basedir );
- }
-
- findhandle = _findfirst (search, &findinfo);
- if (findhandle == -1) {
- return;
- }
-
- do {
- if (findinfo.attrib & _A_SUBDIR) {
- if (Q_stricmp(findinfo.name, ".") && Q_stricmp(findinfo.name, "..")) {
- if (strlen(subdirs)) {
- Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s\\%s", subdirs, findinfo.name);
- }
- else {
- Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", findinfo.name);
- }
- Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
- }
- }
- if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
- break;
- }
- Com_sprintf( filename, sizeof(filename), "%s\\%s", subdirs, findinfo.name );
- if (!Com_FilterPath( filter, filename, qfalse ))
- continue;
- list[ *numfiles ] = CopyString( filename );
- (*numfiles)++;
- } while ( _findnext (findhandle, &findinfo) != -1 );
-
- _findclose (findhandle);
-}
-
-/*
-==============
-strgtr
-==============
-*/
-static qboolean strgtr(const char *s0, const char *s1)
-{
- int l0, l1, i;
-
- l0 = strlen(s0);
- l1 = strlen(s1);
-
- if (l1<l0) {
- l0 = l1;
- }
-
- for(i=0;i<l0;i++) {
- if (s1[i] > s0[i]) {
- return qtrue;
- }
- if (s1[i] < s0[i]) {
- return qfalse;
- }
- }
- return qfalse;
-}
-
-/*
-==============
-Sys_ListFiles
-==============
-*/
-char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs )
-{
- char search[MAX_OSPATH];
- int nfiles;
- char **listCopy;
- char *list[MAX_FOUND_FILES];
- struct _finddata_t findinfo;
- int findhandle;
- int flag;
- int i;
-
- if (filter) {
-
- nfiles = 0;
- Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
-
- list[ nfiles ] = 0;
- *numfiles = nfiles;
-
- if (!nfiles)
- return NULL;
-
- listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
- for ( i = 0 ; i < nfiles ; i++ ) {
- listCopy[i] = list[i];
- }
- listCopy[i] = NULL;
-
- return listCopy;
- }
-
- if ( !extension) {
- extension = "";
- }
-
- // passing a slash as extension will find directories
- if ( extension[0] == '/' && extension[1] == 0 ) {
- extension = "";
- flag = 0;
- } else {
- flag = _A_SUBDIR;
- }
-
- Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension );
-
- // search
- nfiles = 0;
-
- findhandle = _findfirst (search, &findinfo);
- if (findhandle == -1) {
- *numfiles = 0;
- return NULL;
- }
-
- do {
- if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) {
- if ( nfiles == MAX_FOUND_FILES - 1 ) {
- break;
- }
- list[ nfiles ] = CopyString( findinfo.name );
- nfiles++;
- }
- } while ( _findnext (findhandle, &findinfo) != -1 );
-
- list[ nfiles ] = 0;
-
- _findclose (findhandle);
-
- // return a copy of the list
- *numfiles = nfiles;
-
- if ( !nfiles ) {
- return NULL;
- }
-
- listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
- for ( i = 0 ; i < nfiles ; i++ ) {
- listCopy[i] = list[i];
- }
- listCopy[i] = NULL;
-
- do {
- flag = 0;
- for(i=1; i<nfiles; i++) {
- if (strgtr(listCopy[i-1], listCopy[i])) {
- char *temp = listCopy[i];
- listCopy[i] = listCopy[i-1];
- listCopy[i-1] = temp;
- flag = 1;
- }
- }
- } while(flag);
-
- return listCopy;
-}
-
-/*
-==============
-Sys_FreeFileList
-==============
-*/
-void Sys_FreeFileList( char **list )
-{
- int i;
-
- if ( !list ) {
- return;
- }
-
- for ( i = 0 ; list[i] ; i++ ) {
- Z_Free( list[i] );
- }
-
- Z_Free( list );
-}
-
-
-/*
-==============
-Sys_Sleep
-
-Block execution for msec or until input is received.
-==============
-*/
-void Sys_Sleep( int msec )
-{
- if( msec == 0 )
- return;
-
-#ifdef DEDICATED
- if( msec < 0 )
- WaitForSingleObject( GetStdHandle( STD_INPUT_HANDLE ), INFINITE );
- else
- WaitForSingleObject( GetStdHandle( STD_INPUT_HANDLE ), msec );
-#else
- // Client Sys_Sleep doesn't support waiting on stdin
- if( msec < 0 )
- return;
-
- Sleep( msec );
-#endif
-}
-
-/*
-==============
-Sys_ErrorDialog
-
-Display an error message
-==============
-*/
-void Sys_ErrorDialog( const char *error )
-{
- if( MessageBox( NULL, va( "%s. Copy console log to clipboard?", error ),
- NULL, MB_YESNO|MB_ICONERROR ) == IDYES )
- {
- HGLOBAL memoryHandle;
- char *clipMemory;
-
- memoryHandle = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, CON_LogSize( ) + 1 );
- clipMemory = (char *)GlobalLock( memoryHandle );
-
- if( clipMemory )
- {
- char *p = clipMemory;
- char buffer[ 1024 ];
- unsigned int size;
-
- while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 )
- {
- Com_Memcpy( p, buffer, size );
- p += size;
- }
-
- *p = '\0';
-
- if( OpenClipboard( NULL ) && EmptyClipboard( ) )
- SetClipboardData( CF_TEXT, memoryHandle );
-
- GlobalUnlock( clipMemory );
- CloseClipboard( );
- }
- }
-}
-
-#ifndef DEDICATED
-static qboolean SDL_VIDEODRIVER_externallySet = qfalse;
-#endif
-
-/*
-==============
-Sys_GLimpSafeInit
-
-Windows specific "safe" GL implementation initialisation
-==============
-*/
-void Sys_GLimpSafeInit( void )
-{
-#ifndef DEDICATED
- if( !SDL_VIDEODRIVER_externallySet )
- {
- // Here, we want to let SDL decide what do to unless
- // explicitly requested otherwise
- _putenv( "SDL_VIDEODRIVER=" );
- }
-#endif
-}
-
-/*
-==============
-Sys_GLimpInit
-
-Windows specific GL implementation initialisation
-==============
-*/
-void Sys_GLimpInit( void )
-{
-#ifndef DEDICATED
- if( !SDL_VIDEODRIVER_externallySet )
- {
- // It's a little bit weird having in_mouse control the
- // video driver, but from ioq3's point of view they're
- // virtually the same except for the mouse input anyway
- if( Cvar_VariableIntegerValue( "in_mouse" ) == -1 )
- {
- // Use the windib SDL backend, which is closest to
- // the behaviour of idq3 with in_mouse set to -1
- _putenv( "SDL_VIDEODRIVER=windib" );
- }
- else
- {
- // Use the DirectX SDL backend
- _putenv( "SDL_VIDEODRIVER=directx" );
- }
- }
-#endif
-}
-
-/*
-==============
-Sys_PlatformInit
-
-Windows specific initialisation
-==============
-*/
-void Sys_PlatformInit( void )
-{
-#ifndef DEDICATED
- const char *SDL_VIDEODRIVER = getenv( "SDL_VIDEODRIVER" );
-
- if( SDL_VIDEODRIVER )
- {
- Com_Printf( "SDL_VIDEODRIVER is externally set to \"%s\", "
- "in_mouse -1 will have no effect\n", SDL_VIDEODRIVER );
- SDL_VIDEODRIVER_externallySet = qtrue;
- }
- else
- SDL_VIDEODRIVER_externallySet = qfalse;
-#endif
-}
-
-/*
-==============
-Sys_SetEnv
-
-set/unset environment variables (empty value removes it)
-==============
-*/
-
-void Sys_SetEnv(const char *name, const char *value)
-{
- _putenv(va("%s=%s", name, value));
-}
diff --git a/engine/code/sys/win_resource.h b/engine/code/sys/win_resource.h
deleted file mode 100644
index 93c517e..0000000
--- a/engine/code/sys/win_resource.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//{{NO_DEPENDENCIES}}
-// Microsoft Developer Studio generated include file.
-// Used by winquake.rc
-//
-#define IDS_STRING1 1
-#define IDI_ICON1 1
-#define IDB_BITMAP1 1
-#define IDB_BITMAP2 128
-#define IDC_CURSOR1 129
-#define IDC_CURSOR2 130
-#define IDC_CURSOR3 131
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NO_MFC 1
-#define _APS_NEXT_RESOURCE_VALUE 132
-#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1005
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
diff --git a/engine/code/sys/win_resource.rc b/engine/code/sys/win_resource.rc
deleted file mode 100644
index b1c39d5..0000000
--- a/engine/code/sys/win_resource.rc
+++ /dev/null
@@ -1,76 +0,0 @@
-//Microsoft Developer Studio generated resource script.
-//
-#include "win_resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include <winresrc.h>
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE DISCARDABLE
-BEGIN
- "resource.h\0"
-END
-
-2 TEXTINCLUDE DISCARDABLE
-BEGIN
- "#include ""winres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE DISCARDABLE
-BEGIN
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-#ifndef __MINGW32__
-IDI_ICON1 ICON DISCARDABLE "../quake3.ico"
-#else
-IDI_ICON1 ICON DISCARDABLE "misc/quake3.ico"
-#endif
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE DISCARDABLE
-BEGIN
- IDS_STRING1 "Quake3"
-END
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
diff --git a/engine/code/tools/asm/cmdlib.c b/engine/code/tools/asm/cmdlib.c
deleted file mode 100644
index f7171ee..0000000
--- a/engine/code/tools/asm/cmdlib.c
+++ /dev/null
@@ -1,1140 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// cmdlib.c
-
-#include "cmdlib.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifdef WIN32
-#include <direct.h>
-#include <windows.h>
-#elif defined(NeXT)
-#include <libc.h>
-#else
-#include <unistd.h>
-#endif
-
-#define BASEDIRNAME "quake" // assumed to have a 2 or 3 following
-#define PATHSEPERATOR '/'
-
-// set these before calling CheckParm
-int myargc;
-char **myargv;
-
-char com_token[1024];
-qboolean com_eof;
-
-qboolean archive;
-char archivedir[1024];
-
-
-/*
-===================
-ExpandWildcards
-
-Mimic unix command line expansion
-===================
-*/
-#define MAX_EX_ARGC 1024
-int ex_argc;
-char *ex_argv[MAX_EX_ARGC];
-#ifdef _WIN32
-#include "io.h"
-void ExpandWildcards( int *argc, char ***argv )
-{
- struct _finddata_t fileinfo;
- int handle;
- int i;
- char filename[1024];
- char filebase[1024];
- char *path;
-
- ex_argc = 0;
- for (i=0 ; i<*argc ; i++)
- {
- path = (*argv)[i];
- if ( path[0] == '-'
- || ( !strstr(path, "*") && !strstr(path, "?") ) )
- {
- ex_argv[ex_argc++] = path;
- continue;
- }
-
- handle = _findfirst (path, &fileinfo);
- if (handle == -1)
- return;
-
- ExtractFilePath (path, filebase);
-
- do
- {
- sprintf (filename, "%s%s", filebase, fileinfo.name);
- ex_argv[ex_argc++] = copystring (filename);
- } while (_findnext( handle, &fileinfo ) != -1);
-
- _findclose (handle);
- }
-
- *argc = ex_argc;
- *argv = ex_argv;
-}
-#else
-void ExpandWildcards (int *argc, char ***argv)
-{
-}
-#endif
-
-#ifdef WIN_ERROR
-#include <windows.h>
-/*
-=================
-Error
-
-For abnormal program terminations in windowed apps
-=================
-*/
-void Error( const char *error, ... )
-{
- va_list argptr;
- char text[1024];
- char text2[1024];
- int err;
-
- err = GetLastError ();
-
- va_start (argptr,error);
- vsprintf (text, error,argptr);
- va_end (argptr);
-
- sprintf (text2, "%s\nGetLastError() = %i", text, err);
- MessageBox(NULL, text2, "Error", 0 /* MB_OK */ );
-
- exit (1);
-}
-
-#else
-/*
-=================
-Error
-
-For abnormal program terminations in console apps
-=================
-*/
-void Error( const char *error, ...)
-{
- va_list argptr;
-
- _printf ("\n************ ERROR ************\n");
-
- va_start (argptr,error);
- vprintf (error,argptr);
- va_end (argptr);
- _printf ("\r\n");
-
- exit (1);
-}
-#endif
-
-// only printf if in verbose mode
-qboolean verbose = qfalse;
-void qprintf( const char *format, ... ) {
- va_list argptr;
-
- if (!verbose)
- return;
-
- va_start (argptr,format);
- vprintf (format,argptr);
- va_end (argptr);
-
-}
-
-#ifdef WIN32
-HWND hwndOut = NULL;
-qboolean lookedForServer = qfalse;
-UINT wm_BroadcastCommand = -1;
-#endif
-
-void _printf( const char *format, ... ) {
- va_list argptr;
- char text[4096];
-#ifdef WIN32
- ATOM a;
-#endif
- va_start (argptr,format);
- vsprintf (text, format, argptr);
- va_end (argptr);
-
- printf("%s", text);
-
-#ifdef WIN32
- if (!lookedForServer) {
- lookedForServer = qtrue;
- hwndOut = FindWindow(NULL, "Q3Map Process Server");
- if (hwndOut) {
- wm_BroadcastCommand = RegisterWindowMessage( "Q3MPS_BroadcastCommand" );
- }
- }
- if (hwndOut) {
- a = GlobalAddAtom(text);
- PostMessage(hwndOut, wm_BroadcastCommand, 0, (LPARAM)a);
- }
-#endif
-}
-
-
-/*
-
-qdir will hold the path up to the quake directory, including the slash
-
- f:\quake\
- /raid/quake/
-
-gamedir will hold qdir + the game directory (id1, id2, etc)
-
- */
-
-char qdir[1024];
-char gamedir[1024];
-char writedir[1024];
-
-void SetQdirFromPath( const char *path )
-{
- char temp[1024];
- const char *c;
- const char *sep;
- int len, count;
-
- if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':'))
- { // path is partial
- Q_getwd (temp);
- strcat (temp, path);
- path = temp;
- }
-
- // search for "quake2" in path
-
- len = strlen(BASEDIRNAME);
- for (c=path+strlen(path)-1 ; c != path ; c--)
- {
- int i;
-
- if (!Q_strncasecmp (c, BASEDIRNAME, len))
- {
- //
- //strncpy (qdir, path, c+len+2-path);
- // the +2 assumes a 2 or 3 following quake which is not the
- // case with a retail install
- // so we need to add up how much to the next separator
- sep = c + len;
- count = 1;
- while (*sep && *sep != '/' && *sep != '\\')
- {
- sep++;
- count++;
- }
- strncpy (qdir, path, c+len+count-path);
- qprintf ("qdir: %s\n", qdir);
- for ( i = 0; i < strlen( qdir ); i++ )
- {
- if ( qdir[i] == '\\' )
- qdir[i] = '/';
- }
-
- c += len+count;
- while (*c)
- {
- if (*c == '/' || *c == '\\')
- {
- strncpy (gamedir, path, c+1-path);
-
- for ( i = 0; i < strlen( gamedir ); i++ )
- {
- if ( gamedir[i] == '\\' )
- gamedir[i] = '/';
- }
-
- qprintf ("gamedir: %s\n", gamedir);
-
- if ( !writedir[0] )
- strcpy( writedir, gamedir );
- else if ( writedir[strlen( writedir )-1] != '/' )
- {
- writedir[strlen( writedir )] = '/';
- writedir[strlen( writedir )+1] = 0;
- }
-
- return;
- }
- c++;
- }
- Error ("No gamedir in %s", path);
- return;
- }
- }
- Error ("SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path);
-}
-
-char *ExpandArg (const char *path)
-{
- static char full[1024];
-
- if (path[0] != '/' && path[0] != '\\' && path[1] != ':')
- {
- Q_getwd (full);
- strcat (full, path);
- }
- else
- strcpy (full, path);
- return full;
-}
-
-char *ExpandPath (const char *path)
-{
- static char full[1024];
- if (!qdir[0])
- Error ("ExpandPath called without qdir set");
- if (path[0] == '/' || path[0] == '\\' || path[1] == ':') {
- strcpy( full, path );
- return full;
- }
- sprintf (full, "%s%s", qdir, path);
- return full;
-}
-
-char *ExpandGamePath (const char *path)
-{
- static char full[1024];
- if (!qdir[0])
- Error ("ExpandGamePath called without qdir set");
- if (path[0] == '/' || path[0] == '\\' || path[1] == ':') {
- strcpy( full, path );
- return full;
- }
- sprintf (full, "%s%s", gamedir, path);
- return full;
-}
-
-char *ExpandPathAndArchive (const char *path)
-{
- char *expanded;
- char archivename[1024];
-
- expanded = ExpandPath (path);
-
- if (archive)
- {
- sprintf (archivename, "%s/%s", archivedir, path);
- QCopyFile (expanded, archivename);
- }
- return expanded;
-}
-
-
-char *copystring(const char *s)
-{
- char *b;
- b = malloc(strlen(s)+1);
- strcpy (b, s);
- return b;
-}
-
-
-
-/*
-================
-I_FloatTime
-================
-*/
-double I_FloatTime (void)
-{
- time_t t;
-
- time (&t);
-
- return t;
-#if 0
-// more precise, less portable
- 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;
-#endif
-}
-
-void Q_getwd (char *out)
-{
- int i = 0;
-
-#ifdef WIN32
- if (_getcwd (out, 256) == NULL)
- strcpy(out, "."); /* shrug */
- strcat (out, "\\");
-#else
- if (getcwd (out, 256) == NULL)
- strcpy(out, "."); /* shrug */
- strcat (out, "/");
-#endif
-
- while ( out[i] != 0 )
- {
- if ( out[i] == '\\' )
- out[i] = '/';
- i++;
- }
-}
-
-
-void Q_mkdir (const char *path)
-{
-#ifdef WIN32
- if (_mkdir (path) != -1)
- return;
-#else
- if (mkdir (path, 0777) != -1)
- return;
-#endif
- if (errno != EEXIST)
- Error ("mkdir %s: %s",path, strerror(errno));
-}
-
-/*
-============
-FileTime
-
-returns -1 if not present
-============
-*/
-int FileTime (const char *path)
-{
- struct stat buf;
-
- if (stat (path,&buf) == -1)
- return -1;
-
- return buf.st_mtime;
-}
-
-
-
-/*
-==============
-COM_Parse
-
-Parse a token out of a string
-==============
-*/
-char *COM_Parse (char *data)
-{
- int c;
- int len;
-
- len = 0;
- com_token[0] = 0;
-
- if (!data)
- return NULL;
-
-// skip whitespace
-skipwhite:
- while ( (c = *data) <= ' ')
- {
- if (c == 0)
- {
- com_eof = qtrue;
- return NULL; // end of file;
- }
- data++;
- }
-
-// skip // comments
- if (c=='/' && data[1] == '/')
- {
- while (*data && *data != '\n')
- data++;
- goto skipwhite;
- }
-
-
-// handle quoted strings specially
- if (c == '\"')
- {
- data++;
- do
- {
- c = *data++;
- if (c=='\"')
- {
- com_token[len] = 0;
- return data;
- }
- com_token[len] = c;
- len++;
- } while (1);
- }
-
-// parse single characters
- if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
- {
- com_token[len] = c;
- len++;
- com_token[len] = 0;
- return data+1;
- }
-
-// parse a regular word
- do
- {
- com_token[len] = c;
- data++;
- len++;
- c = *data;
- if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
- break;
- } while (c>32);
-
- com_token[len] = 0;
- return data;
-}
-
-
-int Q_strncasecmp (const char *s1, const char *s2, int n)
-{
- int c1, c2;
-
- do
- {
- c1 = *s1++;
- c2 = *s2++;
-
- if (!n--)
- return 0; // strings are equal until end point
-
- if (c1 != c2)
- {
- if (c1 >= 'a' && c1 <= 'z')
- c1 -= ('a' - 'A');
- if (c2 >= 'a' && c2 <= 'z')
- c2 -= ('a' - 'A');
- if (c1 != c2)
- return -1; // strings not equal
- }
- } while (c1);
-
- return 0; // strings are equal
-}
-
-int Q_stricmp (const char *s1, const char *s2)
-{
- return Q_strncasecmp (s1, s2, 99999);
-}
-
-
-char *strupr (char *start)
-{
- char *in;
- in = start;
- while (*in)
- {
- *in = toupper(*in);
- in++;
- }
- return start;
-}
-
-char *strlower (char *start)
-{
- char *in;
- in = start;
- while (*in)
- {
- *in = tolower(*in);
- in++;
- }
- return start;
-}
-
-
-/*
-=============================================================================
-
- MISC FUNCTIONS
-
-=============================================================================
-*/
-
-
-/*
-=================
-CheckParm
-
-Checks for the given parameter in the program's command line arguments
-Returns the argument number (1 to argc-1) or 0 if not present
-=================
-*/
-int CheckParm (const char *check)
-{
- int i;
-
- for (i = 1;i<myargc;i++)
- {
- if ( !Q_stricmp(check, myargv[i]) )
- return i;
- }
-
- return 0;
-}
-
-
-
-/*
-================
-Q_filelength
-================
-*/
-int Q_filelength (FILE *f)
-{
- int pos;
- int end;
-
- pos = ftell (f);
- fseek (f, 0, SEEK_END);
- end = ftell (f);
- fseek (f, pos, SEEK_SET);
-
- return end;
-}
-
-#ifdef MAX_PATH
-#undef MAX_PATH
-#endif
-#define MAX_PATH 4096
-static FILE* myfopen(const char* filename, const char* mode)
-{
- char* p;
- char fn[MAX_PATH];
-
- fn[0] = '\0';
- strncat(fn, filename, sizeof(fn)-1);
-
- for(p=fn;*p;++p) if(*p == '\\') *p = '/';
-
- return fopen(fn, mode);
-}
-
-
-FILE *SafeOpenWrite (const char *filename)
-{
- FILE *f;
-
- f = myfopen(filename, "wb");
-
- if (!f)
- Error ("Error opening %s: %s",filename,strerror(errno));
-
- return f;
-}
-
-FILE *SafeOpenRead (const char *filename)
-{
- FILE *f;
-
- f = myfopen(filename, "rb");
-
- if (!f)
- Error ("Error opening %s: %s",filename,strerror(errno));
-
- return f;
-}
-
-
-void SafeRead (FILE *f, void *buffer, int count)
-{
- if ( fread (buffer, 1, count, f) != (size_t)count)
- Error ("File read failure");
-}
-
-
-void SafeWrite (FILE *f, const void *buffer, int count)
-{
- if (fwrite (buffer, 1, count, f) != (size_t)count)
- Error ("File write failure");
-}
-
-
-/*
-==============
-FileExists
-==============
-*/
-qboolean FileExists (const char *filename)
-{
- FILE *f;
-
- f = myfopen (filename, "r");
- if (!f)
- return qfalse;
- fclose (f);
- return qtrue;
-}
-
-/*
-==============
-LoadFile
-==============
-*/
-int LoadFile( const char *filename, void **bufferptr )
-{
- FILE *f;
- int length;
- void *buffer;
-
- f = SafeOpenRead (filename);
- length = Q_filelength (f);
- buffer = malloc (length+1);
- ((char *)buffer)[length] = 0;
- SafeRead (f, buffer, length);
- fclose (f);
-
- *bufferptr = buffer;
- return length;
-}
-
-
-/*
-==============
-LoadFileBlock
--
-rounds up memory allocation to 4K boundry
--
-==============
-*/
-int LoadFileBlock( const char *filename, void **bufferptr )
-{
- FILE *f;
- int length, nBlock, nAllocSize;
- void *buffer;
-
- f = SafeOpenRead (filename);
- length = Q_filelength (f);
- nAllocSize = length;
- nBlock = nAllocSize % MEM_BLOCKSIZE;
- if ( nBlock > 0) {
- nAllocSize += MEM_BLOCKSIZE - nBlock;
- }
- buffer = malloc (nAllocSize+1);
- memset(buffer, 0, nAllocSize+1);
- SafeRead (f, buffer, length);
- fclose (f);
-
- *bufferptr = buffer;
- return length;
-}
-
-
-/*
-==============
-TryLoadFile
-
-Allows failure
-==============
-*/
-int TryLoadFile (const char *filename, void **bufferptr)
-{
- FILE *f;
- int length;
- void *buffer;
-
- *bufferptr = NULL;
-
- f = myfopen (filename, "rb");
- if (!f)
- return -1;
- length = Q_filelength (f);
- buffer = malloc (length+1);
- ((char *)buffer)[length] = 0;
- SafeRead (f, buffer, length);
- fclose (f);
-
- *bufferptr = buffer;
- return length;
-}
-
-
-/*
-==============
-SaveFile
-==============
-*/
-void SaveFile (const char *filename, const void *buffer, int count)
-{
- FILE *f;
-
- f = SafeOpenWrite (filename);
- SafeWrite (f, buffer, count);
- fclose (f);
-}
-
-
-
-void DefaultExtension (char *path, const char *extension)
-{
- char *src;
-//
-// if path doesnt have a .EXT, append extension
-// (extension should include the .)
-//
- src = path + strlen(path) - 1;
-
- while (*src != '/' && *src != '\\' && src != path)
- {
- if (*src == '.')
- return; // it has an extension
- src--;
- }
-
- strcat (path, extension);
-}
-
-
-void DefaultPath (char *path, const char *basepath)
-{
- char temp[128];
-
- if (path[0] == PATHSEPERATOR)
- return; // absolute path location
- strcpy (temp,path);
- strcpy (path,basepath);
- strcat (path,temp);
-}
-
-
-void StripFilename (char *path)
-{
- int length;
-
- length = strlen(path)-1;
- while (length > 0 && path[length] != PATHSEPERATOR)
- length--;
- path[length] = 0;
-}
-
-void StripExtension (char *path)
-{
- int length;
-
- length = strlen(path)-1;
- while (length > 0 && path[length] != '.')
- {
- length--;
- if (path[length] == '/')
- return; // no extension
- }
- if (length)
- path[length] = 0;
-}
-
-
-/*
-====================
-Extract file parts
-====================
-*/
-// FIXME: should include the slash, otherwise
-// backing to an empty path will be wrong when appending a slash
-void ExtractFilePath (const char *path, char *dest)
-{
- const char *src;
-
- src = path + strlen(path) - 1;
-
-//
-// back up until a \ or the start
-//
- while (src != path && *(src-1) != '\\' && *(src-1) != '/')
- src--;
-
- memcpy (dest, path, src-path);
- dest[src-path] = 0;
-}
-
-void ExtractFileBase (const char *path, char *dest)
-{
- const char *src;
-
- src = path + strlen(path) - 1;
-
-//
-// back up until a \ or the start
-//
- while (src != path && *(src-1) != PATHSEPERATOR)
- src--;
-
- while (*src && *src != '.')
- {
- *dest++ = *src++;
- }
- *dest = 0;
-}
-
-void ExtractFileExtension (const char *path, char *dest)
-{
- const char *src;
-
- src = path + strlen(path) - 1;
-
-//
-// back up until a . or the start
-//
- while (src != path && *(src-1) != '.')
- src--;
- if (src == path)
- {
- *dest = 0; // no extension
- return;
- }
-
- strcpy (dest,src);
-}
-
-
-/*
-==============
-ParseNum / ParseHex
-==============
-*/
-int ParseHex (const char *hex)
-{
- const char *str;
- int num;
-
- num = 0;
- str = hex;
-
- while (*str)
- {
- num <<= 4;
- if (*str >= '0' && *str <= '9')
- num += *str-'0';
- else if (*str >= 'a' && *str <= 'f')
- num += 10 + *str-'a';
- else if (*str >= 'A' && *str <= 'F')
- num += 10 + *str-'A';
- else
- Error ("Bad hex number: %s",hex);
- str++;
- }
-
- return num;
-}
-
-
-int ParseNum (const char *str)
-{
- if (str[0] == '$')
- return ParseHex (str+1);
- if (str[0] == '0' && str[1] == 'x')
- return ParseHex (str+2);
- return atol (str);
-}
-
-
-
-/*
-============================================================================
-
- BYTE ORDER FUNCTIONS
-
-============================================================================
-*/
-
-short ShortSwap (short l)
-{
- byte b1,b2;
-
- b1 = l&255;
- b2 = (l>>8)&255;
-
- return (b1<<8) + b2;
-}
-
-int LongSwap (int l)
-{
- byte b1,b2,b3,b4;
-
- b1 = l&255;
- b2 = (l>>8)&255;
- b3 = (l>>16)&255;
- b4 = (l>>24)&255;
-
- return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
-}
-
-typedef union {
- float f;
- unsigned int i;
-} _FloatByteUnion;
-
-float FloatSwap (const float *f) {
- _FloatByteUnion out;
-
- out.f = *f;
- out.i = LongSwap(out.i);
-
- return out.f;
-}
-
-//=======================================================
-
-
-// FIXME: byte swap?
-
-// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
-// and the initial and final xor values shown below... in other words, the
-// CCITT standard CRC used by XMODEM
-
-#define CRC_INIT_VALUE 0xffff
-#define CRC_XOR_VALUE 0x0000
-
-static unsigned short crctable[256] =
-{
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
- 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
- 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
- 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
- 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
- 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
- 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
- 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
- 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
- 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
- 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
- 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
- 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
- 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
- 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
- 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
- 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
- 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
- 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
- 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
- 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
- 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
- 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
- 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
- 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
- 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
- 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
- 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
- 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
- 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
- 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
- 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
-};
-
-void CRC_Init(unsigned short *crcvalue)
-{
- *crcvalue = CRC_INIT_VALUE;
-}
-
-void CRC_ProcessByte(unsigned short *crcvalue, byte data)
-{
- *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
-}
-
-unsigned short CRC_Value(unsigned short crcvalue)
-{
- return crcvalue ^ CRC_XOR_VALUE;
-}
-//=============================================================================
-
-/*
-============
-CreatePath
-============
-*/
-void CreatePath (const char *path)
-{
- const char *ofs;
- char c;
- char dir[1024];
-
-#ifdef _WIN32
- int olddrive = -1;
-
- if ( path[1] == ':' )
- {
- olddrive = _getdrive();
- _chdrive( toupper( path[0] ) - 'A' + 1 );
- }
-#endif
-
- if (path[1] == ':')
- path += 2;
-
- for (ofs = path+1 ; *ofs ; ofs++)
- {
- c = *ofs;
- if (c == '/' || c == '\\')
- { // create the directory
- memcpy( dir, path, ofs - path );
- dir[ ofs - path ] = 0;
- Q_mkdir( dir );
- }
- }
-
-#ifdef _WIN32
- if ( olddrive != -1 )
- {
- _chdrive( olddrive );
- }
-#endif
-}
-
-
-/*
-============
-QCopyFile
-
- Used to archive source files
-============
-*/
-void QCopyFile (const char *from, const char *to)
-{
- void *buffer;
- int length;
-
- length = LoadFile (from, &buffer);
- CreatePath (to);
- SaveFile (to, buffer, length);
- free (buffer);
-}
diff --git a/engine/code/tools/asm/cmdlib.h b/engine/code/tools/asm/cmdlib.h
deleted file mode 100644
index c2e6dd8..0000000
--- a/engine/code/tools/asm/cmdlib.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// cmdlib.h
-
-#ifndef __CMDLIB__
-#define __CMDLIB__
-
-#ifdef _MSC_VER
-#pragma warning(disable : 4244) // MIPS
-#pragma warning(disable : 4136) // X86
-#pragma warning(disable : 4051) // ALPHA
-
-#pragma warning(disable : 4018) // signed/unsigned mismatch
-#pragma warning(disable : 4305) // truncate from double to float
-
-#pragma check_stack(off)
-
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <ctype.h>
-#include <time.h>
-#include <stdarg.h>
-
-#ifdef _MSC_VER
-
-#pragma intrinsic( memset, memcpy )
-
-#endif
-
-#ifndef __BYTEBOOL__
-#define __BYTEBOOL__
-typedef enum { qfalse, qtrue } qboolean;
-typedef unsigned char byte;
-#endif
-
-#define MAX_OS_PATH 1024
-#define MEM_BLOCKSIZE 4096
-
-// the dec offsetof macro doesnt work very well...
-#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier)
-
-
-// set these before calling CheckParm
-extern int myargc;
-extern char **myargv;
-
-char *strupr (char *in);
-char *strlower (char *in);
-int Q_strncasecmp( const char *s1, const char *s2, int n );
-int Q_stricmp( const char *s1, const char *s2 );
-void Q_getwd( char *out );
-
-int Q_filelength (FILE *f);
-int FileTime( const char *path );
-
-void Q_mkdir( const char *path );
-
-extern char qdir[1024];
-extern char gamedir[1024];
-extern char writedir[1024];
-void SetQdirFromPath( const char *path );
-char *ExpandArg( const char *path ); // from cmd line
-char *ExpandPath( const char *path ); // from scripts
-char *ExpandGamePath (const char *path);
-char *ExpandPathAndArchive( const char *path );
-
-
-double I_FloatTime( void );
-
-void Error( const char *error, ... );
-int CheckParm( const char *check );
-
-FILE *SafeOpenWrite( const char *filename );
-FILE *SafeOpenRead( const char *filename );
-void SafeRead (FILE *f, void *buffer, int count);
-void SafeWrite (FILE *f, const void *buffer, int count);
-
-int LoadFile( const char *filename, void **bufferptr );
-int LoadFileBlock( const char *filename, void **bufferptr );
-int TryLoadFile( const char *filename, void **bufferptr );
-void SaveFile( const char *filename, const void *buffer, int count );
-qboolean FileExists( const char *filename );
-
-void DefaultExtension( char *path, const char *extension );
-void DefaultPath( char *path, const char *basepath );
-void StripFilename( char *path );
-void StripExtension( char *path );
-
-void ExtractFilePath( const char *path, char *dest );
-void ExtractFileBase( const char *path, char *dest );
-void ExtractFileExtension( const char *path, char *dest );
-
-int ParseNum (const char *str);
-
-char *COM_Parse (char *data);
-
-extern char com_token[1024];
-extern qboolean com_eof;
-
-char *copystring(const char *s);
-
-
-void CRC_Init(unsigned short *crcvalue);
-void CRC_ProcessByte(unsigned short *crcvalue, byte data);
-unsigned short CRC_Value(unsigned short crcvalue);
-
-void CreatePath( const char *path );
-void QCopyFile( const char *from, const char *to );
-
-extern qboolean archive;
-extern char archivedir[1024];
-
-
-extern qboolean verbose;
-void qprintf( const char *format, ... );
-void _printf( const char *format, ... );
-
-void ExpandWildcards( int *argc, char ***argv );
-
-
-// for compression routines
-typedef struct
-{
- void *data;
- int count, width, height;
-} cblock_t;
-
-
-#endif
diff --git a/engine/code/tools/asm/q3asm.c b/engine/code/tools/asm/q3asm.c
deleted file mode 100644
index c740c7f..0000000
--- a/engine/code/tools/asm/q3asm.c
+++ /dev/null
@@ -1,1646 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "../../qcommon/q_platform.h"
-#include "cmdlib.h"
-#include "mathlib.h"
-#include "../../qcommon/qfiles.h"
-
-/* 19079 total symbols in FI, 2002 Jan 23 */
-#define DEFAULT_HASHTABLE_SIZE 2048
-
-char outputFilename[MAX_OS_PATH];
-
-// the zero page size is just used for detecting run time faults
-#define ZERO_PAGE_SIZE 0 // 256
-
-typedef enum {
- OP_UNDEF,
-
- OP_IGNORE,
-
- OP_BREAK,
-
- OP_ENTER,
- OP_LEAVE,
- OP_CALL,
- OP_PUSH,
- OP_POP,
-
- OP_CONST,
- OP_LOCAL,
-
- OP_JUMP,
-
- //-------------------
-
- OP_EQ,
- OP_NE,
-
- OP_LTI,
- OP_LEI,
- OP_GTI,
- OP_GEI,
-
- OP_LTU,
- OP_LEU,
- OP_GTU,
- OP_GEU,
-
- OP_EQF,
- OP_NEF,
-
- OP_LTF,
- OP_LEF,
- OP_GTF,
- OP_GEF,
-
- //-------------------
-
- OP_LOAD1,
- OP_LOAD2,
- OP_LOAD4,
- OP_STORE1,
- OP_STORE2,
- OP_STORE4, // *(stack[top-1]) = stack[yop
- OP_ARG,
- OP_BLOCK_COPY,
-
- //-------------------
-
- OP_SEX8,
- OP_SEX16,
-
- OP_NEGI,
- OP_ADD,
- OP_SUB,
- OP_DIVI,
- OP_DIVU,
- OP_MODI,
- OP_MODU,
- OP_MULI,
- OP_MULU,
-
- OP_BAND,
- OP_BOR,
- OP_BXOR,
- OP_BCOM,
-
- OP_LSH,
- OP_RSHI,
- OP_RSHU,
-
- OP_NEGF,
- OP_ADDF,
- OP_SUBF,
- OP_DIVF,
- OP_MULF,
-
- OP_CVIF,
- OP_CVFI
-} opcode_t;
-
-typedef struct {
- int imageBytes; // after decompression
- int entryPoint;
- int stackBase;
- int stackSize;
-} executableHeader_t;
-
-typedef enum {
- CODESEG,
- DATASEG, // initialized 32 bit data, will be byte swapped
- LITSEG, // strings
- BSSSEG, // 0 filled
- JTRGSEG, // pseudo-segment that contains only jump table targets
- NUM_SEGMENTS
-} segmentName_t;
-
-#define MAX_IMAGE 0x400000
-
-typedef struct {
- byte image[MAX_IMAGE];
- int imageUsed;
- int segmentBase; // only valid on second pass
-} segment_t;
-
-typedef struct symbol_s {
- struct symbol_s *next;
- int hash;
- segment_t *segment;
- char *name;
- int value;
-} symbol_t;
-
-typedef struct hashchain_s {
- void *data;
- struct hashchain_s *next;
-} hashchain_t;
-
-typedef struct hashtable_s {
- int buckets;
- hashchain_t **table;
-} hashtable_t;
-
-int symtablelen = DEFAULT_HASHTABLE_SIZE;
-hashtable_t *symtable;
-hashtable_t *optable;
-
-segment_t segment[NUM_SEGMENTS];
-segment_t *currentSegment;
-
-int passNumber;
-
-int numSymbols;
-int errorCount;
-
-typedef struct options_s {
- qboolean verbose;
- qboolean writeMapFile;
- qboolean vanillaQ3Compatibility;
-} options_t;
-
-options_t options = { 0 };
-
-symbol_t *symbols;
-symbol_t *lastSymbol = 0; /* Most recent symbol defined. */
-
-
-#define MAX_ASM_FILES 256
-int numAsmFiles;
-char *asmFiles[MAX_ASM_FILES];
-char *asmFileNames[MAX_ASM_FILES];
-
-int currentFileIndex;
-char *currentFileName;
-int currentFileLine;
-
-//int stackSize = 16384;
-int stackSize = 0x10000;
-
-// we need to convert arg and ret instructions to
-// stores to the local stack frame, so we need to track the
-// characteristics of the current functions stack frame
-int currentLocals; // bytes of locals needed by this function
-int currentArgs; // bytes of largest argument list called from this function
-int currentArgOffset; // byte offset in currentArgs to store next arg, reset each call
-
-#define MAX_LINE_LENGTH 1024
-char lineBuffer[MAX_LINE_LENGTH];
-int lineParseOffset;
-char token[MAX_LINE_LENGTH];
-
-int instructionCount;
-
-typedef struct {
- char *name;
- int opcode;
-} sourceOps_t;
-
-sourceOps_t sourceOps[] = {
-#include "opstrings.h"
-};
-
-#define NUM_SOURCE_OPS ( sizeof( sourceOps ) / sizeof( sourceOps[0] ) )
-
-int opcodesHash[ NUM_SOURCE_OPS ];
-
-
-
-static int vreport (const char* fmt, va_list vp)
-{
- if (options.verbose != qtrue)
- return 0;
- return vprintf(fmt, vp);
-}
-
-static int report (const char *fmt, ...)
-{
- va_list va;
- int retval;
-
- va_start(va, fmt);
- retval = vreport(fmt, va);
- va_end(va);
- return retval;
-}
-
-/* The chain-and-bucket hash table. -PH */
-
-static void hashtable_init (hashtable_t *H, int buckets)
-{
- H->buckets = buckets;
- H->table = calloc(H->buckets, sizeof(*(H->table)));
- return;
-}
-
-static hashtable_t *hashtable_new (int buckets)
-{
- hashtable_t *H;
-
- H = malloc(sizeof(hashtable_t));
- hashtable_init(H, buckets);
- return H;
-}
-
-/* No destroy/destructor. No need. */
-
-static void hashtable_add (hashtable_t *H, int hashvalue, void *datum)
-{
- hashchain_t *hc, **hb;
-
- hashvalue = (abs(hashvalue) % H->buckets);
- hb = &(H->table[hashvalue]);
- if (*hb == 0)
- {
- /* Empty bucket. Create new one. */
- *hb = calloc(1, sizeof(**hb));
- hc = *hb;
- }
- else
- {
- /* Get hc to point to last node in chain. */
- for (hc = *hb; hc && hc->next; hc = hc->next);
- hc->next = calloc(1, sizeof(*hc));
- hc = hc->next;
- }
- hc->data = datum;
- hc->next = 0;
- return;
-}
-
-static hashchain_t *hashtable_get (hashtable_t *H, int hashvalue)
-{
- hashvalue = (abs(hashvalue) % H->buckets);
- return (H->table[hashvalue]);
-}
-
-static void hashtable_stats (hashtable_t *H)
-{
- int len, empties, longest, nodes;
- int i;
- float meanlen;
- hashchain_t *hc;
-
- report("Stats for hashtable %08X", H);
- empties = 0;
- longest = 0;
- nodes = 0;
- for (i = 0; i < H->buckets; i++)
- {
- if (H->table[i] == 0)
- { empties++; continue; }
- for (hc = H->table[i], len = 0; hc; hc = hc->next, len++);
- if (len > longest) { longest = len; }
- nodes += len;
- }
- meanlen = (float)(nodes) / (H->buckets - empties);
-#if 0
-/* Long stats display */
- report(" Total buckets: %d\n", H->buckets);
- report(" Total stored nodes: %d\n", nodes);
- report(" Longest chain: %d\n", longest);
- report(" Empty chains: %d\n", empties);
- report(" Mean non-empty chain length: %f\n", meanlen);
-#else //0
-/* Short stats display */
- report(", %d buckets, %d nodes", H->buckets, nodes);
- report("\n");
- report(" Longest chain: %d, empty chains: %d, mean non-empty: %f", longest, empties, meanlen);
-#endif //0
- report("\n");
-}
-
-
-/* Kludge. */
-/* Check if symbol already exists. */
-/* Returns 0 if symbol does NOT already exist, non-zero otherwise. */
-static int hashtable_symbol_exists (hashtable_t *H, int hash, char *sym)
-{
- hashchain_t *hc;
- symbol_t *s;
-
- hash = (abs(hash) % H->buckets);
- hc = H->table[hash];
- if (hc == 0)
- {
- /* Empty chain means this symbol has not yet been defined. */
- return 0;
- }
- for (; hc; hc = hc->next)
- {
- s = (symbol_t*)hc->data;
-// if ((hash == s->hash) && (strcmp(sym, s->name) == 0))
-/* We _already_ know the hash is the same. That's why we're probing! */
- if (strcmp(sym, s->name) == 0)
- {
- /* Symbol collisions -- symbol already exists. */
- return 1;
- }
- }
- return 0; /* Can't find collision. */
-}
-
-
-
-
-/* Comparator function for quicksorting. */
-static int symlist_cmp (const void *e1, const void *e2)
-{
- const symbol_t *a, *b;
-
- a = *(const symbol_t **)e1;
- b = *(const symbol_t **)e2;
-//crumb("Symbol comparison (1) %d to (2) %d\n", a->value, b->value);
- return ( a->value - b->value);
-}
-
-/*
- Sort the symbols list by using QuickSort (qsort()).
- This may take a LOT of memory (a few megabytes?), but memory is cheap these days.
- However, qsort(3) already exists, and I'm really lazy.
- -PH
-*/
-static void sort_symbols ()
-{
- int i, elems;
- symbol_t *s;
- symbol_t **symlist;
-
-//crumb("sort_symbols: Constructing symlist array\n");
- for (elems = 0, s = symbols; s; s = s->next, elems++) /* nop */ ;
- symlist = malloc(elems * sizeof(symbol_t*));
- for (i = 0, s = symbols; s; s = s->next, i++)
- {
- symlist[i] = s;
- }
-//crumbf("sort_symbols: Quick-sorting %d symbols\n", elems);
- qsort(symlist, elems, sizeof(symbol_t*), symlist_cmp);
-//crumbf("sort_symbols: Reconstructing symbols list\n");
- s = symbols = symlist[0];
- for (i = 1; i < elems; i++)
- {
- s->next = symlist[i];
- s = s->next;
- }
- lastSymbol = s;
- s->next = 0;
-//crumbf("sort_symbols: verifying..."); fflush(stdout);
- for (i = 0, s = symbols; s; s = s->next, i++) /*nop*/ ;
-//crumbf(" %d elements\n", i);
- free(symlist); /* d'oh. no gc. */
-}
-
-
-#ifdef _MSC_VER
-#define INT64 __int64
-#define atoi64 _atoi64
-#else
-#define INT64 long long int
-#define atoi64 atoll
-#endif
-
-/*
- Problem:
- BYTE values are specified as signed decimal string. A properly functional
- atoip() will cap large signed values at 0x7FFFFFFF. Negative word values are
- often specified as very large decimal values by lcc. Therefore, values that
- should be between 0x7FFFFFFF and 0xFFFFFFFF come out as 0x7FFFFFFF when using
- atoi(). Bad.
-
- This function is one big evil hack to work around this problem.
-*/
-static int atoiNoCap (const char *s)
-{
- INT64 l;
- union {
- unsigned int u;
- signed int i;
- } retval;
-
- l = atoi64(s);
- /* Now smash to signed 32 bits accordingly. */
- if (l < 0) {
- retval.i = (int)l;
- } else {
- retval.u = (unsigned int)l;
- }
- return retval.i; /* <- union hackage. I feel dirty with this. -PH */
-}
-
-
-
-/*
-=============
-HashString
-=============
-*/
-/* Default hash function of Kazlib 1.19, slightly modified. */
-static unsigned int HashString (const char *key)
-{
- static unsigned long randbox[] = {
- 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
- 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
- 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
- 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
- };
-
- const char *str = key;
- unsigned int acc = 0;
-
- while (*str) {
- acc ^= randbox[(*str + acc) & 0xf];
- acc = (acc << 1) | (acc >> 31);
- acc &= 0xffffffffU;
- acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
- acc = (acc << 2) | (acc >> 30);
- acc &= 0xffffffffU;
- }
- return abs(acc);
-}
-
-
-/*
-============
-CodeError
-============
-*/
-static void CodeError( char *fmt, ... ) {
- va_list argptr;
-
- errorCount++;
-
- fprintf( stderr, "%s:%i ", currentFileName, currentFileLine );
-
- va_start( argptr,fmt );
- vfprintf( stderr, fmt, argptr );
- va_end( argptr );
-}
-
-/*
-============
-EmitByte
-============
-*/
-static void EmitByte( segment_t *seg, int v ) {
- if ( seg->imageUsed >= MAX_IMAGE ) {
- Error( "MAX_IMAGE" );
- }
- seg->image[ seg->imageUsed ] = v;
- seg->imageUsed++;
-}
-
-/*
-============
-EmitInt
-============
-*/
-static void EmitInt( segment_t *seg, int v ) {
- if ( seg->imageUsed >= MAX_IMAGE - 4) {
- Error( "MAX_IMAGE" );
- }
- seg->image[ seg->imageUsed ] = v & 255;
- seg->image[ seg->imageUsed + 1 ] = ( v >> 8 ) & 255;
- seg->image[ seg->imageUsed + 2 ] = ( v >> 16 ) & 255;
- seg->image[ seg->imageUsed + 3 ] = ( v >> 24 ) & 255;
- seg->imageUsed += 4;
-}
-
-/*
-============
-DefineSymbol
-
-Symbols can only be defined on pass 0
-============
-*/
-static void DefineSymbol( char *sym, int value ) {
- /* Hand optimization by PhaethonH */
- symbol_t *s;
- char expanded[MAX_LINE_LENGTH];
- int hash;
-
- if ( passNumber == 1 ) {
- return;
- }
-
- // add the file prefix to local symbols to guarantee unique
- if ( sym[0] == '$' ) {
- sprintf( expanded, "%s_%i", sym, currentFileIndex );
- sym = expanded;
- }
-
- hash = HashString( sym );
-
- if (hashtable_symbol_exists(symtable, hash, sym)) {
- CodeError( "Multiple definitions for %s\n", sym );
- return;
- }
-
- s = malloc( sizeof( *s ) );
- s->next = NULL;
- s->name = copystring( sym );
- s->hash = hash;
- s->value = value;
- s->segment = currentSegment;
-
- hashtable_add(symtable, hash, s);
-
-/*
- Hash table lookup already speeds up symbol lookup enormously.
- We postpone sorting until end of pass 0.
- Since we're not doing the insertion sort, lastSymbol should always
- wind up pointing to the end of list.
- This allows constant time for adding to the list.
- -PH
-*/
- if (symbols == 0) {
- lastSymbol = symbols = s;
- } else {
- lastSymbol->next = s;
- lastSymbol = s;
- }
-}
-
-
-/*
-============
-LookupSymbol
-
-Symbols can only be evaluated on pass 1
-============
-*/
-static int LookupSymbol( char *sym ) {
- symbol_t *s;
- char expanded[MAX_LINE_LENGTH];
- int hash;
- hashchain_t *hc;
-
- if ( passNumber == 0 ) {
- return 0;
- }
-
- // add the file prefix to local symbols to guarantee unique
- if ( sym[0] == '$' ) {
- sprintf( expanded, "%s_%i", sym, currentFileIndex );
- sym = expanded;
- }
-
- hash = HashString( sym );
-
-/*
- Hand optimization by PhaethonH
-
- Using a hash table with chain/bucket for lookups alone sped up q3asm by almost 3x for me.
- -PH
-*/
- for (hc = hashtable_get(symtable, hash); hc; hc = hc->next) {
- s = (symbol_t*)hc->data; /* ugly typecasting, but it's fast! */
- if ( (hash == s->hash) && !strcmp(sym, s->name) ) {
- return s->segment->segmentBase + s->value;
- }
- }
-
- CodeError( "error: symbol %s undefined\n", sym );
- passNumber = 0;
- DefineSymbol( sym, 0 ); // so more errors aren't printed
- passNumber = 1;
- return 0;
-}
-
-
-/*
-==============
-ExtractLine
-
-Extracts the next line from the given text block.
-If a full line isn't parsed, returns NULL
-Otherwise returns the updated parse pointer
-===============
-*/
-static char *ExtractLine( char *data ) {
-/* Goal:
- Given a string `data', extract one text line into buffer `lineBuffer' that
- is no longer than MAX_LINE_LENGTH characters long. Return value is
- remainder of `data' that isn't part of `lineBuffer'.
- -PH
-*/
- /* Hand-optimized by PhaethonH */
- char *p, *q;
-
- currentFileLine++;
-
- lineParseOffset = 0;
- token[0] = 0;
- *lineBuffer = 0;
-
- p = q = data;
- if (!*q) {
- return NULL;
- }
-
- for ( ; !((*p == 0) || (*p == '\n')); p++) /* nop */ ;
-
- if ((p - q) >= MAX_LINE_LENGTH) {
- CodeError( "MAX_LINE_LENGTH" );
- return data;
- }
-
- memcpy( lineBuffer, data, (p - data) );
- lineBuffer[(p - data)] = 0;
- p += (*p == '\n') ? 1 : 0; /* Skip over final newline. */
- return p;
-}
-
-
-/*
-==============
-Parse
-
-Parse a token out of linebuffer
-==============
-*/
-static qboolean Parse( void ) {
- /* Hand-optimized by PhaethonH */
- const char *p, *q;
-
- /* Because lineParseOffset is only updated just before exit, this makes this code version somewhat harder to debug under a symbolic debugger. */
-
- *token = 0; /* Clear token. */
-
- // skip whitespace
- for (p = lineBuffer + lineParseOffset; *p && (*p <= ' '); p++) /* nop */ ;
-
- // skip ; comments
- /* die on end-of-string */
- if ((*p == ';') || (*p == 0)) {
- lineParseOffset = p - lineBuffer;
- return qfalse;
- }
-
- q = p; /* Mark the start of token. */
- /* Find separator first. */
- for ( ; *p > 32; p++) /* nop */ ; /* XXX: unsafe assumptions. */
- /* *p now sits on separator. Mangle other values accordingly. */
- strncpy(token, q, p - q);
- token[p - q] = 0;
-
- lineParseOffset = p - lineBuffer;
-
- return qtrue;
-}
-
-
-/*
-==============
-ParseValue
-==============
-*/
-static int ParseValue( void ) {
- Parse();
- return atoiNoCap( token );
-}
-
-
-/*
-==============
-ParseExpression
-==============
-*/
-static int ParseExpression(void) {
- /* Hand optimization, PhaethonH */
- int i, j;
- char sym[MAX_LINE_LENGTH];
- int v;
-
- /* Skip over a leading minus. */
- for ( i = ((token[0] == '-') ? 1 : 0) ; i < MAX_LINE_LENGTH ; i++ ) {
- if ( token[i] == '+' || token[i] == '-' || token[i] == 0 ) {
- break;
- }
- }
-
- memcpy( sym, token, i );
- sym[i] = 0;
-
- switch (*sym) { /* Resolve depending on first character. */
-/* Optimizing compilers can convert cases into "calculated jumps". I think these are faster. -PH */
- case '-':
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- v = atoiNoCap(sym);
- break;
- default:
- v = LookupSymbol(sym);
- break;
- }
-
- // parse add / subtract offsets
- while ( token[i] != 0 ) {
- for ( j = i + 1 ; j < MAX_LINE_LENGTH ; j++ ) {
- if ( token[j] == '+' || token[j] == '-' || token[j] == 0 ) {
- break;
- }
- }
-
- memcpy( sym, token+i+1, j-i-1 );
- sym[j-i-1] = 0;
-
- switch (token[i]) {
- case '+':
- v += atoiNoCap(sym);
- break;
- case '-':
- v -= atoiNoCap(sym);
- break;
- }
-
- i = j;
- }
-
- return v;
-}
-
-
-/*
-==============
-HackToSegment
-
-BIG HACK: I want to put all 32 bit values in the data
-segment so they can be byte swapped, and all char data in the lit
-segment, but switch jump tables are emited in the lit segment and
-initialized strng variables are put in the data segment.
-
-I can change segments here, but I also need to fixup the
-label that was just defined
-
-Note that the lit segment is read-write in the VM, so strings
-aren't read only as in some architectures.
-==============
-*/
-static void HackToSegment( segmentName_t seg ) {
- if ( currentSegment == &segment[seg] ) {
- return;
- }
-
- currentSegment = &segment[seg];
- if ( passNumber == 0 ) {
- lastSymbol->segment = currentSegment;
- lastSymbol->value = currentSegment->imageUsed;
- }
-}
-
-
-
-
-
-
-
-//#define STAT(L) report("STAT " L "\n");
-#define STAT(L)
-#define ASM(O) int TryAssemble##O ()
-
-
-/*
- These clauses were moved out from AssembleLine() to allow reordering of if's.
- An optimizing compiler should reconstruct these back into inline code.
- -PH
-*/
-
- // call instructions reset currentArgOffset
-ASM(CALL)
-{
- if ( !strncmp( token, "CALL", 4 ) ) {
-STAT("CALL");
- EmitByte( &segment[CODESEG], OP_CALL );
- instructionCount++;
- currentArgOffset = 0;
- return 1;
- }
- return 0;
-}
-
- // arg is converted to a reversed store
-ASM(ARG)
-{
- if ( !strncmp( token, "ARG", 3 ) ) {
-STAT("ARG");
- EmitByte( &segment[CODESEG], OP_ARG );
- instructionCount++;
- if ( 8 + currentArgOffset >= 256 ) {
- CodeError( "currentArgOffset >= 256" );
- return 1;
- }
- EmitByte( &segment[CODESEG], 8 + currentArgOffset );
- currentArgOffset += 4;
- return 1;
- }
- return 0;
-}
-
- // ret just leaves something on the op stack
-ASM(RET)
-{
- if ( !strncmp( token, "RET", 3 ) ) {
-STAT("RET");
- EmitByte( &segment[CODESEG], OP_LEAVE );
- instructionCount++;
- EmitInt( &segment[CODESEG], 8 + currentLocals + currentArgs );
- return 1;
- }
- return 0;
-}
-
- // pop is needed to discard the return value of
- // a function
-ASM(POP)
-{
- if ( !strncmp( token, "pop", 3 ) ) {
-STAT("POP");
- EmitByte( &segment[CODESEG], OP_POP );
- instructionCount++;
- return 1;
- }
- return 0;
-}
-
- // address of a parameter is converted to OP_LOCAL
-ASM(ADDRF)
-{
- int v;
- if ( !strncmp( token, "ADDRF", 5 ) ) {
-STAT("ADDRF");
- instructionCount++;
- Parse();
- v = ParseExpression();
- v = 16 + currentArgs + currentLocals + v;
- EmitByte( &segment[CODESEG], OP_LOCAL );
- EmitInt( &segment[CODESEG], v );
- return 1;
- }
- return 0;
-}
-
- // address of a local is converted to OP_LOCAL
-ASM(ADDRL)
-{
- int v;
- if ( !strncmp( token, "ADDRL", 5 ) ) {
-STAT("ADDRL");
- instructionCount++;
- Parse();
- v = ParseExpression();
- v = 8 + currentArgs + v;
- EmitByte( &segment[CODESEG], OP_LOCAL );
- EmitInt( &segment[CODESEG], v );
- return 1;
- }
- return 0;
-}
-
-ASM(PROC)
-{
- char name[1024];
- if ( !strcmp( token, "proc" ) ) {
-STAT("PROC");
- Parse(); // function name
- strcpy( name, token );
-
- DefineSymbol( token, instructionCount ); // segment[CODESEG].imageUsed );
-
- currentLocals = ParseValue(); // locals
- currentLocals = ( currentLocals + 3 ) & ~3;
- currentArgs = ParseValue(); // arg marshalling
- currentArgs = ( currentArgs + 3 ) & ~3;
-
- if ( 8 + currentLocals + currentArgs >= 32767 ) {
- CodeError( "Locals > 32k in %s\n", name );
- }
-
- instructionCount++;
- EmitByte( &segment[CODESEG], OP_ENTER );
- EmitInt( &segment[CODESEG], 8 + currentLocals + currentArgs );
- return 1;
- }
- return 0;
-}
-
-
-ASM(ENDPROC)
-{
- int v, v2;
- if ( !strcmp( token, "endproc" ) ) {
-STAT("ENDPROC");
- Parse(); // skip the function name
- v = ParseValue(); // locals
- v2 = ParseValue(); // arg marshalling
-
- // all functions must leave something on the opstack
- instructionCount++;
- EmitByte( &segment[CODESEG], OP_PUSH );
-
- instructionCount++;
- EmitByte( &segment[CODESEG], OP_LEAVE );
- EmitInt( &segment[CODESEG], 8 + currentLocals + currentArgs );
-
- return 1;
- }
- return 0;
-}
-
-
-ASM(ADDRESS)
-{
- int v;
- if ( !strcmp( token, "address" ) ) {
-STAT("ADDRESS");
- Parse();
- v = ParseExpression();
-
-/* Addresses are 32 bits wide, and therefore go into data segment. */
- HackToSegment( DATASEG );
- EmitInt( currentSegment, v );
- if( passNumber == 1 && token[ 0 ] == '$' ) // crude test for labels
- EmitInt( &segment[ JTRGSEG ], v );
- return 1;
- }
- return 0;
-}
-
-ASM(EXPORT)
-{
- if ( !strcmp( token, "export" ) ) {
-STAT("EXPORT");
- return 1;
- }
- return 0;
-}
-
-ASM(IMPORT)
-{
- if ( !strcmp( token, "import" ) ) {
-STAT("IMPORT");
- return 1;
- }
- return 0;
-}
-
-ASM(CODE)
-{
- if ( !strcmp( token, "code" ) ) {
-STAT("CODE");
- currentSegment = &segment[CODESEG];
- return 1;
- }
- return 0;
-}
-
-ASM(BSS)
-{
- if ( !strcmp( token, "bss" ) ) {
-STAT("BSS");
- currentSegment = &segment[BSSSEG];
- return 1;
- }
- return 0;
-}
-
-ASM(DATA)
-{
- if ( !strcmp( token, "data" ) ) {
-STAT("DATA");
- currentSegment = &segment[DATASEG];
- return 1;
- }
- return 0;
-}
-
-ASM(LIT)
-{
- if ( !strcmp( token, "lit" ) ) {
-STAT("LIT");
- currentSegment = &segment[LITSEG];
- return 1;
- }
- return 0;
-}
-
-ASM(LINE)
-{
- if ( !strcmp( token, "line" ) ) {
-STAT("LINE");
- return 1;
- }
- return 0;
-}
-
-ASM(FILE)
-{
- if ( !strcmp( token, "file" ) ) {
-STAT("FILE");
- return 1;
- }
- return 0;
-}
-
-ASM(EQU)
-{
- char name[1024];
- if ( !strcmp( token, "equ" ) ) {
-STAT("EQU");
- Parse();
- strcpy( name, token );
- Parse();
- DefineSymbol( name, atoiNoCap(token) );
- return 1;
- }
- return 0;
-}
-
-ASM(ALIGN)
-{
- int v;
- if ( !strcmp( token, "align" ) ) {
-STAT("ALIGN");
- v = ParseValue();
- currentSegment->imageUsed = (currentSegment->imageUsed + v - 1 ) & ~( v - 1 );
- return 1;
- }
- return 0;
-}
-
-ASM(SKIP)
-{
- int v;
- if ( !strcmp( token, "skip" ) ) {
-STAT("SKIP");
- v = ParseValue();
- currentSegment->imageUsed += v;
- return 1;
- }
- return 0;
-}
-
-ASM(BYTE)
-{
- int i, v, v2;
- if ( !strcmp( token, "byte" ) ) {
-STAT("BYTE");
- v = ParseValue();
- v2 = ParseValue();
-
- if ( v == 1 ) {
-/* Character (1-byte) values go into lit(eral) segment. */
- HackToSegment( LITSEG );
- } else if ( v == 4 ) {
-/* 32-bit (4-byte) values go into data segment. */
- HackToSegment( DATASEG );
- } else if ( v == 2 ) {
-/* and 16-bit (2-byte) values will cause q3asm to barf. */
- CodeError( "16 bit initialized data not supported" );
- }
-
- // emit little endien
- for ( i = 0 ; i < v ; i++ ) {
- EmitByte( currentSegment, (v2 & 0xFF) ); /* paranoid ANDing -PH */
- v2 >>= 8;
- }
- return 1;
- }
- return 0;
-}
-
- // code labels are emited as instruction counts, not byte offsets,
- // because the physical size of the code will change with
- // different run time compilers and we want to minimize the
- // size of the required translation table
-ASM(LABEL)
-{
- if ( !strncmp( token, "LABEL", 5 ) ) {
-STAT("LABEL");
- Parse();
- if ( currentSegment == &segment[CODESEG] ) {
- DefineSymbol( token, instructionCount );
- } else {
- DefineSymbol( token, currentSegment->imageUsed );
- }
- return 1;
- }
- return 0;
-}
-
-
-
-/*
-==============
-AssembleLine
-
-==============
-*/
-static void AssembleLine( void ) {
- hashchain_t *hc;
- sourceOps_t *op;
- int i;
- int hash;
-
- Parse();
- if ( !token[0] ) {
- return;
- }
-
- hash = HashString( token );
-
-/*
- Opcode search using hash table.
- Since the opcodes stays mostly fixed, this may benefit even more from a tree.
- Always with the tree :)
- -PH
-*/
- for (hc = hashtable_get(optable, hash); hc; hc = hc->next) {
- op = (sourceOps_t*)(hc->data);
- i = op - sourceOps;
- if ((hash == opcodesHash[i]) && (!strcmp(token, op->name))) {
- int opcode;
- int expression;
-
- if ( op->opcode == OP_UNDEF ) {
- CodeError( "Undefined opcode: %s\n", token );
- }
- if ( op->opcode == OP_IGNORE ) {
- return; // we ignore most conversions
- }
-
- // sign extensions need to check next parm
- opcode = op->opcode;
- if ( opcode == OP_SEX8 ) {
- Parse();
- if ( token[0] == '1' ) {
- opcode = OP_SEX8;
- } else if ( token[0] == '2' ) {
- opcode = OP_SEX16;
- } else {
- CodeError( "Bad sign extension: %s\n", token );
- return;
- }
- }
-
- // check for expression
- Parse();
- if ( token[0] && op->opcode != OP_CVIF
- && op->opcode != OP_CVFI ) {
- expression = ParseExpression();
-
- // code like this can generate non-dword block copies:
- // auto char buf[2] = " ";
- // we are just going to round up. This might conceivably
- // be incorrect if other initialized chars follow.
- if ( opcode == OP_BLOCK_COPY ) {
- expression = ( expression + 3 ) & ~3;
- }
-
- EmitByte( &segment[CODESEG], opcode );
- EmitInt( &segment[CODESEG], expression );
- } else {
- EmitByte( &segment[CODESEG], opcode );
- }
-
- instructionCount++;
- return;
- }
- }
-
-/* This falls through if an assembly opcode is not found. -PH */
-
-/* The following should be sorted in sequence of statistical frequency, most frequent first. -PH */
-/*
-Empirical frequency statistics from FI 2001.01.23:
- 109892 STAT ADDRL
- 72188 STAT BYTE
- 51150 STAT LINE
- 50906 STAT ARG
- 43704 STAT IMPORT
- 34902 STAT LABEL
- 32066 STAT ADDRF
- 23704 STAT CALL
- 7720 STAT POP
- 7256 STAT RET
- 5198 STAT ALIGN
- 3292 STAT EXPORT
- 2878 STAT PROC
- 2878 STAT ENDPROC
- 2812 STAT ADDRESS
- 738 STAT SKIP
- 374 STAT EQU
- 280 STAT CODE
- 176 STAT LIT
- 102 STAT FILE
- 100 STAT BSS
- 68 STAT DATA
-
- -PH
-*/
-
-#undef ASM
-#define ASM(O) if (TryAssemble##O ()) return;
-
- ASM(ADDRL)
- ASM(BYTE)
- ASM(LINE)
- ASM(ARG)
- ASM(IMPORT)
- ASM(LABEL)
- ASM(ADDRF)
- ASM(CALL)
- ASM(POP)
- ASM(RET)
- ASM(ALIGN)
- ASM(EXPORT)
- ASM(PROC)
- ASM(ENDPROC)
- ASM(ADDRESS)
- ASM(SKIP)
- ASM(EQU)
- ASM(CODE)
- ASM(LIT)
- ASM(FILE)
- ASM(BSS)
- ASM(DATA)
-
- CodeError( "Unknown token: %s\n", token );
-}
-
-/*
-==============
-InitTables
-==============
-*/
-void InitTables( void ) {
- int i;
-
- symtable = hashtable_new(symtablelen);
- optable = hashtable_new(100); /* There's hardly 100 opcodes anyway. */
-
- for ( i = 0 ; i < NUM_SOURCE_OPS ; i++ ) {
- opcodesHash[i] = HashString( sourceOps[i].name );
- hashtable_add(optable, opcodesHash[i], sourceOps + i);
- }
-}
-
-
-/*
-==============
-WriteMapFile
-==============
-*/
-static void WriteMapFile( void ) {
- FILE *f;
- symbol_t *s;
- char imageName[MAX_OS_PATH];
- int seg;
-
- strcpy( imageName, outputFilename );
- StripExtension( imageName );
- strcat( imageName, ".map" );
-
- report( "Writing %s...\n", imageName );
-
- f = SafeOpenWrite( imageName );
- for ( seg = CODESEG ; seg <= BSSSEG ; seg++ ) {
- for ( s = symbols ; s ; s = s->next ) {
- if ( s->name[0] == '$' ) {
- continue; // skip locals
- }
- if ( &segment[seg] != s->segment ) {
- continue;
- }
- fprintf( f, "%i %8x %s\n", seg, s->value, s->name );
- }
- }
- fclose( f );
-}
-
-/*
-===============
-WriteVmFile
-===============
-*/
-static void WriteVmFile( void ) {
- char imageName[MAX_OS_PATH];
- vmHeader_t header;
- FILE *f;
- int headerSize;
-
- report( "%i total errors\n", errorCount );
-
- strcpy( imageName, outputFilename );
- StripExtension( imageName );
- strcat( imageName, ".qvm" );
-
- remove( imageName );
-
- report( "code segment: %7i\n", segment[CODESEG].imageUsed );
- report( "data segment: %7i\n", segment[DATASEG].imageUsed );
- report( "lit segment: %7i\n", segment[LITSEG].imageUsed );
- report( "bss segment: %7i\n", segment[BSSSEG].imageUsed );
- report( "instruction count: %i\n", instructionCount );
-
- if ( errorCount != 0 ) {
- report( "Not writing a file due to errors\n" );
- return;
- }
-
- if( !options.vanillaQ3Compatibility ) {
- header.vmMagic = VM_MAGIC_VER2;
- headerSize = sizeof( header );
- } else {
- header.vmMagic = VM_MAGIC;
-
- // Don't write the VM_MAGIC_VER2 bits when maintaining 1.32b compatibility.
- // (I know this isn't strictly correct due to padding, but then platforms
- // that pad wouldn't be able to write a correct header anyway). Note: if
- // vmHeader_t changes, this needs to be adjusted too.
- headerSize = sizeof( header ) - sizeof( header.jtrgLength );
- }
-
- header.instructionCount = instructionCount;
- header.codeOffset = headerSize;
- header.codeLength = segment[CODESEG].imageUsed;
- header.dataOffset = header.codeOffset + segment[CODESEG].imageUsed;
- header.dataLength = segment[DATASEG].imageUsed;
- header.litLength = segment[LITSEG].imageUsed;
- header.bssLength = segment[BSSSEG].imageUsed;
- header.jtrgLength = segment[JTRGSEG].imageUsed;
-
- report( "Writing to %s\n", imageName );
-
-#ifdef Q3_BIG_ENDIAN
- {
- int i;
-
- // byte swap the header
- for ( i = 0 ; i < sizeof( vmHeader_t ) / 4 ; i++ ) {
- ((int *)&header)[i] = LittleLong( ((int *)&header)[i] );
- }
- }
-#endif
-
- CreatePath( imageName );
- f = SafeOpenWrite( imageName );
- SafeWrite( f, &header, headerSize );
- SafeWrite( f, &segment[CODESEG].image, segment[CODESEG].imageUsed );
- SafeWrite( f, &segment[DATASEG].image, segment[DATASEG].imageUsed );
- SafeWrite( f, &segment[LITSEG].image, segment[LITSEG].imageUsed );
-
- if( !options.vanillaQ3Compatibility ) {
- SafeWrite( f, &segment[JTRGSEG].image, segment[JTRGSEG].imageUsed );
- }
-
- fclose( f );
-}
-
-/*
-===============
-Assemble
-===============
-*/
-static void Assemble( void ) {
- int i;
- char filename[MAX_OS_PATH];
- char *ptr;
-
- report( "outputFilename: %s\n", outputFilename );
-
- for ( i = 0 ; i < numAsmFiles ; i++ ) {
- strcpy( filename, asmFileNames[ i ] );
- DefaultExtension( filename, ".asm" );
- LoadFile( filename, (void **)&asmFiles[i] );
- }
-
- // assemble
- for ( passNumber = 0 ; passNumber < 2 ; passNumber++ ) {
- segment[LITSEG].segmentBase = segment[DATASEG].imageUsed;
- segment[BSSSEG].segmentBase = segment[LITSEG].segmentBase + segment[LITSEG].imageUsed;
- segment[JTRGSEG].segmentBase = segment[BSSSEG].segmentBase + segment[BSSSEG].imageUsed;
- for ( i = 0 ; i < NUM_SEGMENTS ; i++ ) {
- segment[i].imageUsed = 0;
- }
- segment[DATASEG].imageUsed = 4; // skip the 0 byte, so NULL pointers are fixed up properly
- instructionCount = 0;
-
- for ( i = 0 ; i < numAsmFiles ; i++ ) {
- currentFileIndex = i;
- currentFileName = asmFileNames[ i ];
- currentFileLine = 0;
- report("pass %i: %s\n", passNumber, currentFileName );
- fflush( NULL );
- ptr = asmFiles[i];
- while ( ptr ) {
- ptr = ExtractLine( ptr );
- AssembleLine();
- }
- }
-
- // align all segment
- for ( i = 0 ; i < NUM_SEGMENTS ; i++ ) {
- segment[i].imageUsed = (segment[i].imageUsed + 3) & ~3;
- }
- if (passNumber == 0) {
- sort_symbols();
- }
- }
-
- // reserve the stack in bss
- DefineSymbol( "_stackStart", segment[BSSSEG].imageUsed );
- segment[BSSSEG].imageUsed += stackSize;
- DefineSymbol( "_stackEnd", segment[BSSSEG].imageUsed );
-
- // write the image
- WriteVmFile();
-
- // write the map file even if there were errors
- if( options.writeMapFile ) {
- WriteMapFile();
- }
-}
-
-
-/*
-=============
-ParseOptionFile
-
-=============
-*/
-static void ParseOptionFile( const char *filename ) {
- char expanded[MAX_OS_PATH];
- char *text, *text_p;
-
- strcpy( expanded, filename );
- DefaultExtension( expanded, ".q3asm" );
- LoadFile( expanded, (void **)&text );
- if ( !text ) {
- return;
- }
-
- text_p = text;
-
- while( ( text_p = COM_Parse( text_p ) ) != 0 ) {
- if ( !strcmp( com_token, "-o" ) ) {
- // allow output override in option file
- text_p = COM_Parse( text_p );
- if ( text_p ) {
- strcpy( outputFilename, com_token );
- }
- continue;
- }
-
- asmFileNames[ numAsmFiles ] = copystring( com_token );
- numAsmFiles++;
- }
-}
-
-static void ShowHelp( char *argv0 ) {
- Error("Usage: %s [OPTION]... [FILES]...\n\
-Assemble LCC bytecode assembly to Q3VM bytecode.\n\
-\n\
- -o OUTPUT Write assembled output to file OUTPUT.qvm\n\
- -f LISTFILE Read options and list of files to assemble from LISTFILE.q3asm\n\
- -b BUCKETS Set symbol hash table to BUCKETS buckets\n\
- -m Generate a mapfile for each OUTPUT.qvm\n\
- -v Verbose compilation report\n\
- -vq3 Produce a qvm file compatible with Q3 1.32b\n\
- -h --help -? Show this help\n\
-", argv0);
-}
-
-/*
-==============
-main
-==============
-*/
-int main( int argc, char **argv ) {
- int i;
- double start, end;
-
-// _chdir( "/quake3/jccode/cgame/lccout" ); // hack for vc profiler
-
- if ( argc < 2 ) {
- ShowHelp( argv[0] );
- }
-
- start = I_FloatTime ();
-
- // default filename is "q3asm"
- strcpy( outputFilename, "q3asm" );
- numAsmFiles = 0;
-
- for ( i = 1 ; i < argc ; i++ ) {
- if ( argv[i][0] != '-' ) {
- break;
- }
- if( !strcmp( argv[ i ], "-h" ) ||
- !strcmp( argv[ i ], "--help" ) ||
- !strcmp( argv[ i ], "-?") ) {
- ShowHelp( argv[0] );
- }
-
- if ( !strcmp( argv[i], "-o" ) ) {
- if ( i == argc - 1 ) {
- Error( "-o must preceed a filename" );
- }
-/* Timbo of Tremulous pointed out -o not working; stock ID q3asm folded in the change. Yay. */
- strcpy( outputFilename, argv[ i+1 ] );
- i++;
- continue;
- }
-
- if ( !strcmp( argv[i], "-f" ) ) {
- if ( i == argc - 1 ) {
- Error( "-f must preceed a filename" );
- }
- ParseOptionFile( argv[ i+1 ] );
- i++;
- continue;
- }
-
- if (!strcmp(argv[i], "-b")) {
- if (i == argc - 1) {
- Error("-b requires an argument");
- }
- i++;
- symtablelen = atoiNoCap(argv[i]);
- continue;
- }
-
- if( !strcmp( argv[ i ], "-v" ) ) {
-/* Verbosity option added by Timbo, 2002.09.14.
-By default (no -v option), q3asm remains silent except for critical errors.
-Verbosity turns on all messages, error or not.
-Motivation: not wanting to scrollback for pages to find asm error.
-*/
- options.verbose = qtrue;
- continue;
- }
-
- if( !strcmp( argv[ i ], "-m" ) ) {
- options.writeMapFile = qtrue;
- continue;
- }
-
- if( !strcmp( argv[ i ], "-vq3" ) ) {
- options.vanillaQ3Compatibility = qtrue;
- continue;
- }
-
- Error( "Unknown option: %s", argv[i] );
- }
-
- // the rest of the command line args are asm files
- for ( ; i < argc ; i++ ) {
- asmFileNames[ numAsmFiles ] = copystring( argv[ i ] );
- numAsmFiles++;
- }
- // In some case it Segfault without this check
- if ( numAsmFiles == 0 ) {
- Error( "No file to assemble\n" );
- }
-
- InitTables();
- Assemble();
-
- {
- symbol_t *s;
-
- for ( i = 0, s = symbols ; s ; s = s->next, i++ ) /* nop */ ;
-
- if (options.verbose)
- {
- report("%d symbols defined\n", i);
- hashtable_stats(symtable);
- hashtable_stats(optable);
- }
- }
-
- end = I_FloatTime ();
- report ("%5.0f seconds elapsed\n", end-start);
-
- return errorCount;
-}
-
diff --git a/engine/code/ui/ui_atoms.c b/engine/code/ui/ui_atoms.c
deleted file mode 100644
index 50c4ed6..0000000
--- a/engine/code/ui/ui_atoms.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/**********************************************************************
- UI_ATOMS.C
-
- User interface building blocks and support functions.
-**********************************************************************/
-#include "ui_local.h"
-
-qboolean m_entersound; // after a frame, so caching won't disrupt the sound
-
-void QDECL Com_Error( int level, const char *error, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, error);
- Q_vsnprintf (text, sizeof(text), error, argptr);
- va_end (argptr);
-
- trap_Error( va("%s", text) );
-}
-
-void QDECL Com_Printf( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- Q_vsnprintf (text, sizeof(text), msg, argptr);
- va_end (argptr);
-
- trap_Print( va("%s", text) );
-}
-
-qboolean newUI = qfalse;
-
-
-/*
-=================
-UI_ClampCvar
-=================
-*/
-float UI_ClampCvar( float min, float max, float value )
-{
- if ( value < min ) return min;
- if ( value > max ) return max;
- return value;
-}
-
-/*
-=================
-UI_StartDemoLoop
-=================
-*/
-void UI_StartDemoLoop( void ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "d1\n" );
-}
-
-
-#ifndef MISSIONPACK
-static void NeedCDAction( qboolean result ) {
- if ( !result ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
- }
-}
-#endif // MISSIONPACK
-
-#ifndef MISSIONPACK
-static void NeedCDKeyAction( qboolean result ) {
- if ( !result ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
- }
-}
-#endif // MISSIONPACK
-
-char *UI_Argv( int arg ) {
- static char buffer[MAX_STRING_CHARS];
-
- trap_Argv( arg, buffer, sizeof( buffer ) );
-
- return buffer;
-}
-
-
-char *UI_Cvar_VariableString( const char *var_name ) {
- static char buffer[MAX_STRING_CHARS];
-
- trap_Cvar_VariableStringBuffer( var_name, buffer, sizeof( buffer ) );
-
- return buffer;
-}
-
-
-
-void UI_SetBestScores(postGameInfo_t *newInfo, qboolean postGame) {
- trap_Cvar_Set("ui_scoreAccuracy", va("%i%%", newInfo->accuracy));
- trap_Cvar_Set("ui_scoreImpressives", va("%i", newInfo->impressives));
- trap_Cvar_Set("ui_scoreExcellents", va("%i", newInfo->excellents));
- trap_Cvar_Set("ui_scoreDefends", va("%i", newInfo->defends));
- trap_Cvar_Set("ui_scoreAssists", va("%i", newInfo->assists));
- trap_Cvar_Set("ui_scoreGauntlets", va("%i", newInfo->gauntlets));
- trap_Cvar_Set("ui_scoreScore", va("%i", newInfo->score));
- trap_Cvar_Set("ui_scorePerfect", va("%i", newInfo->perfects));
- trap_Cvar_Set("ui_scoreTeam", va("%i to %i", newInfo->redScore, newInfo->blueScore));
- trap_Cvar_Set("ui_scoreBase", va("%i", newInfo->baseScore));
- trap_Cvar_Set("ui_scoreTimeBonus", va("%i", newInfo->timeBonus));
- trap_Cvar_Set("ui_scoreSkillBonus", va("%i", newInfo->skillBonus));
- trap_Cvar_Set("ui_scoreShutoutBonus", va("%i", newInfo->shutoutBonus));
- trap_Cvar_Set("ui_scoreTime", va("%02i:%02i", newInfo->time / 60, newInfo->time % 60));
- trap_Cvar_Set("ui_scoreCaptures", va("%i", newInfo->captures));
- if (postGame) {
- trap_Cvar_Set("ui_scoreAccuracy2", va("%i%%", newInfo->accuracy));
- trap_Cvar_Set("ui_scoreImpressives2", va("%i", newInfo->impressives));
- trap_Cvar_Set("ui_scoreExcellents2", va("%i", newInfo->excellents));
- trap_Cvar_Set("ui_scoreDefends2", va("%i", newInfo->defends));
- trap_Cvar_Set("ui_scoreAssists2", va("%i", newInfo->assists));
- trap_Cvar_Set("ui_scoreGauntlets2", va("%i", newInfo->gauntlets));
- trap_Cvar_Set("ui_scoreScore2", va("%i", newInfo->score));
- trap_Cvar_Set("ui_scorePerfect2", va("%i", newInfo->perfects));
- trap_Cvar_Set("ui_scoreTeam2", va("%i to %i", newInfo->redScore, newInfo->blueScore));
- trap_Cvar_Set("ui_scoreBase2", va("%i", newInfo->baseScore));
- trap_Cvar_Set("ui_scoreTimeBonus2", va("%i", newInfo->timeBonus));
- trap_Cvar_Set("ui_scoreSkillBonus2", va("%i", newInfo->skillBonus));
- trap_Cvar_Set("ui_scoreShutoutBonus2", va("%i", newInfo->shutoutBonus));
- trap_Cvar_Set("ui_scoreTime2", va("%02i:%02i", newInfo->time / 60, newInfo->time % 60));
- trap_Cvar_Set("ui_scoreCaptures2", va("%i", newInfo->captures));
- }
-}
-
-void UI_LoadBestScores(const char *map, int game) {
- char fileName[MAX_QPATH];
- fileHandle_t f;
- postGameInfo_t newInfo;
- memset(&newInfo, 0, sizeof(postGameInfo_t));
- Com_sprintf(fileName, MAX_QPATH, "games/%s_%i.game", map, game);
- if (trap_FS_FOpenFile(fileName, &f, FS_READ) >= 0) {
- int size = 0;
- trap_FS_Read(&size, sizeof(int), f);
- if (size == sizeof(postGameInfo_t)) {
- trap_FS_Read(&newInfo, sizeof(postGameInfo_t), f);
- }
- trap_FS_FCloseFile(f);
- }
- UI_SetBestScores(&newInfo, qfalse);
-
- Com_sprintf(fileName, MAX_QPATH, "demos/%s_%d.dm_%d", map, game, (int)trap_Cvar_VariableValue("protocol"));
- uiInfo.demoAvailable = qfalse;
- if (trap_FS_FOpenFile(fileName, &f, FS_READ) >= 0) {
- uiInfo.demoAvailable = qtrue;
- trap_FS_FCloseFile(f);
- }
-}
-
-/*
-===============
-UI_ClearScores
-===============
-*/
-void UI_ClearScores(void) {
- char gameList[4096];
- char *gameFile;
- int i, len, count, size;
- fileHandle_t f;
- postGameInfo_t newInfo;
-
- count = trap_FS_GetFileList( "games", "game", gameList, sizeof(gameList) );
-
- size = sizeof(postGameInfo_t);
- memset(&newInfo, 0, size);
-
- if (count > 0) {
- gameFile = gameList;
- for ( i = 0; i < count; i++ ) {
- len = strlen(gameFile);
- if (trap_FS_FOpenFile(va("games/%s",gameFile), &f, FS_WRITE) >= 0) {
- trap_FS_Write(&size, sizeof(int), f);
- trap_FS_Write(&newInfo, size, f);
- trap_FS_FCloseFile(f);
- }
- gameFile += len + 1;
- }
- }
-
- UI_SetBestScores(&newInfo, qfalse);
-
-}
-
-
-
-static void UI_Cache_f( void ) {
- Display_CacheAll();
-}
-
-/*
-=======================
-UI_CalcPostGameStats
-=======================
-*/
-static void UI_CalcPostGameStats( void ) {
- char map[MAX_QPATH];
- char fileName[MAX_QPATH];
- char info[MAX_INFO_STRING];
- fileHandle_t f;
- int size, game, time, adjustedTime;
- postGameInfo_t oldInfo;
- postGameInfo_t newInfo;
- qboolean newHigh = qfalse;
-
- trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
- Q_strncpyz( map, Info_ValueForKey( info, "mapname" ), sizeof(map) );
- game = atoi(Info_ValueForKey(info, "g_gametype"));
-
- // compose file name
- Com_sprintf(fileName, MAX_QPATH, "games/%s_%i.game", map, game);
- // see if we have one already
- memset(&oldInfo, 0, sizeof(postGameInfo_t));
- if (trap_FS_FOpenFile(fileName, &f, FS_READ) >= 0) {
- // if so load it
- size = 0;
- trap_FS_Read(&size, sizeof(int), f);
- if (size == sizeof(postGameInfo_t)) {
- trap_FS_Read(&oldInfo, sizeof(postGameInfo_t), f);
- }
- trap_FS_FCloseFile(f);
- }
-
- newInfo.accuracy = atoi(UI_Argv(3));
- newInfo.impressives = atoi(UI_Argv(4));
- newInfo.excellents = atoi(UI_Argv(5));
- newInfo.defends = atoi(UI_Argv(6));
- newInfo.assists = atoi(UI_Argv(7));
- newInfo.gauntlets = atoi(UI_Argv(8));
- newInfo.baseScore = atoi(UI_Argv(9));
- newInfo.perfects = atoi(UI_Argv(10));
- newInfo.redScore = atoi(UI_Argv(11));
- newInfo.blueScore = atoi(UI_Argv(12));
- time = atoi(UI_Argv(13));
- newInfo.captures = atoi(UI_Argv(14));
-
- newInfo.time = (time - trap_Cvar_VariableValue("ui_matchStartTime")) / 1000;
- adjustedTime = uiInfo.mapList[ui_currentMap.integer].timeToBeat[game];
- if (newInfo.time < adjustedTime) {
- newInfo.timeBonus = (adjustedTime - newInfo.time) * 10;
- } else {
- newInfo.timeBonus = 0;
- }
-
- if (newInfo.redScore > newInfo.blueScore && newInfo.blueScore <= 0) {
- newInfo.shutoutBonus = 100;
- } else {
- newInfo.shutoutBonus = 0;
- }
-
- newInfo.skillBonus = trap_Cvar_VariableValue("g_spSkill");
- if (newInfo.skillBonus <= 0) {
- newInfo.skillBonus = 1;
- }
- newInfo.score = newInfo.baseScore + newInfo.shutoutBonus + newInfo.timeBonus;
- newInfo.score *= newInfo.skillBonus;
-
- // see if the score is higher for this one
- newHigh = (newInfo.redScore > newInfo.blueScore && newInfo.score > oldInfo.score);
-
- if (newHigh) {
- // if so write out the new one
- uiInfo.newHighScoreTime = uiInfo.uiDC.realTime + 20000;
- if (trap_FS_FOpenFile(fileName, &f, FS_WRITE) >= 0) {
- size = sizeof(postGameInfo_t);
- trap_FS_Write(&size, sizeof(int), f);
- trap_FS_Write(&newInfo, sizeof(postGameInfo_t), f);
- trap_FS_FCloseFile(f);
- }
- }
-
- if (newInfo.time < oldInfo.time) {
- uiInfo.newBestTime = uiInfo.uiDC.realTime + 20000;
- }
-
- // put back all the ui overrides
- trap_Cvar_Set("capturelimit", UI_Cvar_VariableString("ui_saveCaptureLimit"));
- trap_Cvar_Set("fraglimit", UI_Cvar_VariableString("ui_saveFragLimit"));
- trap_Cvar_Set("cg_drawTimer", UI_Cvar_VariableString("ui_drawTimer"));
- trap_Cvar_Set("g_doWarmup", UI_Cvar_VariableString("ui_doWarmup"));
- trap_Cvar_Set("g_Warmup", UI_Cvar_VariableString("ui_Warmup"));
- trap_Cvar_Set("sv_pure", UI_Cvar_VariableString("ui_pure"));
- trap_Cvar_Set("g_friendlyFire", UI_Cvar_VariableString("ui_friendlyFire"));
-
- UI_SetBestScores(&newInfo, qtrue);
- UI_ShowPostGame(newHigh);
-
-
-}
-
-
-/*
-=================
-UI_ConsoleCommand
-=================
-*/
-qboolean UI_ConsoleCommand( int realTime ) {
- char *cmd;
-
- uiInfo.uiDC.frameTime = realTime - uiInfo.uiDC.realTime;
- uiInfo.uiDC.realTime = realTime;
-
- cmd = UI_Argv( 0 );
-
- // ensure minimum menu data is available
- //Menu_Cache();
-
- if ( Q_stricmp (cmd, "ui_test") == 0 ) {
- UI_ShowPostGame(qtrue);
- }
-
- if ( Q_stricmp (cmd, "ui_report") == 0 ) {
- UI_Report();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "ui_load") == 0 ) {
- UI_Load();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "remapShader") == 0 ) {
- if (trap_Argc() == 4) {
- char shader1[MAX_QPATH];
- char shader2[MAX_QPATH];
- char shader3[MAX_QPATH];
-
- Q_strncpyz(shader1, UI_Argv(1), sizeof(shader1));
- Q_strncpyz(shader2, UI_Argv(2), sizeof(shader2));
- Q_strncpyz(shader3, UI_Argv(3), sizeof(shader3));
-
- trap_R_RemapShader(shader1, shader2, shader3);
- return qtrue;
- }
- }
-
- if ( Q_stricmp (cmd, "postgame") == 0 ) {
- UI_CalcPostGameStats();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "ui_cache") == 0 ) {
- UI_Cache_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "ui_teamOrders") == 0 ) {
- //UI_TeamOrdersMenu_f();
- return qtrue;
- }
-
-
- if ( Q_stricmp (cmd, "ui_cdkey") == 0 ) {
- //UI_CDKeyMenu_f();
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-=================
-UI_Shutdown
-=================
-*/
-void UI_Shutdown( void ) {
-}
-
-/*
-================
-UI_AdjustFrom640
-
-Adjusted for resolution and screen aspect ratio
-================
-*/
-void UI_AdjustFrom640( float *x, float *y, float *w, float *h ) {
- // expect valid pointers
-#if 0
- *x = *x * uiInfo.uiDC.scale + uiInfo.uiDC.bias;
- *y *= uiInfo.uiDC.scale;
- *w *= uiInfo.uiDC.scale;
- *h *= uiInfo.uiDC.scale;
-#endif
-
- *x *= uiInfo.uiDC.xscale;
- *y *= uiInfo.uiDC.yscale;
- *w *= uiInfo.uiDC.xscale;
- *h *= uiInfo.uiDC.yscale;
-
-}
-
-void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {
- qhandle_t hShader;
-
- hShader = trap_R_RegisterShaderNoMip( picname );
- UI_AdjustFrom640( &x, &y, &width, &height );
- trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
-}
-
-void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader ) {
- float s0;
- float s1;
- float t0;
- float t1;
-
- if( w < 0 ) { // flip about vertical
- w = -w;
- s0 = 1;
- s1 = 0;
- }
- else {
- s0 = 0;
- s1 = 1;
- }
-
- if( h < 0 ) { // flip about horizontal
- h = -h;
- t0 = 1;
- t1 = 0;
- }
- else {
- t0 = 0;
- t1 = 1;
- }
-
- UI_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, w, h, s0, t0, s1, t1, hShader );
-}
-
-/*
-================
-UI_FillRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void UI_FillRect( float x, float y, float width, float height, const float *color ) {
- trap_R_SetColor( color );
-
- UI_AdjustFrom640( &x, &y, &width, &height );
- trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
-
- trap_R_SetColor( NULL );
-}
-
-void UI_DrawSides(float x, float y, float w, float h) {
- UI_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, 1, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
- trap_R_DrawStretchPic( x + w - 1, y, 1, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
-}
-
-void UI_DrawTopBottom(float x, float y, float w, float h) {
- UI_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, w, 1, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
- trap_R_DrawStretchPic( x, y + h - 1, w, 1, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
-}
-/*
-================
-UI_DrawRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void UI_DrawRect( float x, float y, float width, float height, const float *color ) {
- trap_R_SetColor( color );
-
- UI_DrawTopBottom(x, y, width, height);
- UI_DrawSides(x, y, width, height);
-
- trap_R_SetColor( NULL );
-}
-
-void UI_SetColor( const float *rgba ) {
- trap_R_SetColor( rgba );
-}
-
-void UI_UpdateScreen( void ) {
- trap_UpdateScreen();
-}
-
-
-void UI_DrawTextBox (int x, int y, int width, int lines)
-{
- UI_FillRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorBlack );
- UI_DrawRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorWhite );
-}
-
-qboolean UI_CursorInRect (int x, int y, int width, int height)
-{
- if (uiInfo.uiDC.cursorx < x ||
- uiInfo.uiDC.cursory < y ||
- uiInfo.uiDC.cursorx > x+width ||
- uiInfo.uiDC.cursory > y+height)
- return qfalse;
-
- return qtrue;
-}
diff --git a/engine/code/ui/ui_gameinfo.c b/engine/code/ui/ui_gameinfo.c
deleted file mode 100644
index bcb2622..0000000
--- a/engine/code/ui/ui_gameinfo.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-//
-// gameinfo.c
-//
-
-#include "ui_local.h"
-
-
-//
-// arena and bot info
-//
-
-
-int ui_numBots;
-static char *ui_botInfos[MAX_BOTS];
-
-static int ui_numArenas;
-static char *ui_arenaInfos[MAX_ARENAS];
-
-#ifndef MISSIONPACK
-static int ui_numSinglePlayerArenas;
-static int ui_numSpecialSinglePlayerArenas;
-#endif
-
-/*
-===============
-UI_ParseInfos
-===============
-*/
-int UI_ParseInfos( char *buf, int max, char *infos[] ) {
- char *token;
- int count;
- char key[MAX_TOKEN_CHARS];
- char info[MAX_INFO_STRING];
-
- count = 0;
-
- while ( 1 ) {
- token = COM_Parse( &buf );
- if ( !token[0] ) {
- break;
- }
- if ( strcmp( token, "{" ) ) {
- Com_Printf( "Missing { in info file\n" );
- break;
- }
-
- if ( count == max ) {
- Com_Printf( "Max infos exceeded\n" );
- break;
- }
-
- info[0] = '\0';
- while ( 1 ) {
- token = COM_ParseExt( &buf, qtrue );
- if ( !token[0] ) {
- Com_Printf( "Unexpected end of info file\n" );
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- Q_strncpyz( key, token, sizeof( key ) );
-
- token = COM_ParseExt( &buf, qfalse );
- if ( !token[0] ) {
- strcpy( token, "<NULL>" );
- }
- Info_SetValueForKey( info, key, token );
- }
- //NOTE: extra space for arena number
- infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
- if (infos[count]) {
- strcpy(infos[count], info);
- count++;
- }
- }
- return count;
-}
-
-/*
-===============
-UI_LoadArenasFromFile
-===============
-*/
-static void UI_LoadArenasFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_ARENAS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_ARENAS_TEXT ) {
- trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_ARENAS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] );
-}
-
-/*
-===============
-UI_LoadArenas
-===============
-*/
-void UI_LoadArenas( void ) {
- int numdirs;
- vmCvar_t arenasFile;
- char filename[128];
- char dirlist[1024];
- char* dirptr;
- int i, n;
- int dirlen;
- char *type;
-
- ui_numArenas = 0;
- uiInfo.mapCount = 0;
-
- trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
- if( *arenasFile.string ) {
- UI_LoadArenasFromFile(arenasFile.string);
- }
- else {
- UI_LoadArenasFromFile("scripts/arenas.txt");
- }
-
- // get all arenas from .arena files
- numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- UI_LoadArenasFromFile(filename);
- }
- trap_Print( va( "%i arenas parsed\n", ui_numArenas ) );
- if (UI_OutOfMemory()) {
- trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all arenas\n");
- }
-
- for( n = 0; n < ui_numArenas; n++ ) {
- // determine type
-
- uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
- uiInfo.mapList[uiInfo.mapCount].mapLoadName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "map"));
- uiInfo.mapList[uiInfo.mapCount].mapName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "longname"));
- uiInfo.mapList[uiInfo.mapCount].levelShot = -1;
- uiInfo.mapList[uiInfo.mapCount].imageName = String_Alloc(va("levelshots/%s", uiInfo.mapList[uiInfo.mapCount].mapLoadName));
- uiInfo.mapList[uiInfo.mapCount].typeBits = 0;
-
- type = Info_ValueForKey( ui_arenaInfos[n], "type" );
- // if no type specified, it will be treated as "ffa"
- if( *type ) {
- if( strstr( type, "ffa" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_FFA);
- }
- if( strstr( type, "tourney" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_TOURNAMENT);
- }
- if( strstr( type, "ctf" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_CTF);
- }
- if( strstr( type, "oneflag" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_1FCTF);
- }
- if( strstr( type, "overload" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_OBELISK);
- }
- if( strstr( type, "harvester" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_HARVESTER);
- }
- } else {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_FFA);
- }
-
- uiInfo.mapCount++;
- if (uiInfo.mapCount >= MAX_MAPS) {
- break;
- }
- }
-}
-
-
-/*
-===============
-UI_LoadBotsFromFile
-===============
-*/
-static void UI_LoadBotsFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_BOTS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_BOTS_TEXT ) {
- trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- COM_Compress(buf);
-
- ui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] );
-}
-
-/*
-===============
-UI_LoadBots
-===============
-*/
-void UI_LoadBots( void ) {
- vmCvar_t botsFile;
- int numdirs;
- char filename[128];
- char dirlist[1024];
- char* dirptr;
- int i;
- int dirlen;
-
- ui_numBots = 0;
-
- trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
- if( *botsFile.string ) {
- UI_LoadBotsFromFile(botsFile.string);
- }
- else {
- UI_LoadBotsFromFile("scripts/bots.txt");
- }
-
- // get all bots from .bot files
- numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- UI_LoadBotsFromFile(filename);
- }
- trap_Print( va( "%i bots parsed\n", ui_numBots ) );
-}
-
-
-/*
-===============
-UI_GetBotInfoByNumber
-===============
-*/
-char *UI_GetBotInfoByNumber( int num ) {
- if( num < 0 || num >= ui_numBots ) {
- trap_Print( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
- return NULL;
- }
- return ui_botInfos[num];
-}
-
-
-/*
-===============
-UI_GetBotInfoByName
-===============
-*/
-char *UI_GetBotInfoByName( const char *name ) {
- int n;
- char *value;
-
- for ( n = 0; n < ui_numBots ; n++ ) {
- value = Info_ValueForKey( ui_botInfos[n], "name" );
- if ( !Q_stricmp( value, name ) ) {
- return ui_botInfos[n];
- }
- }
-
- return NULL;
-}
-
-int UI_GetNumBots( void ) {
- return ui_numBots;
-}
-
-
-char *UI_GetBotNameByNumber( int num ) {
- char *info = UI_GetBotInfoByNumber(num);
- if (info) {
- return Info_ValueForKey( info, "name" );
- }
- return "Sarge";
-}
diff --git a/engine/code/ui/ui_local.h b/engine/code/ui/ui_local.h
deleted file mode 100644
index 2b69cf2..0000000
--- a/engine/code/ui/ui_local.h
+++ /dev/null
@@ -1,1136 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#ifndef __UI_LOCAL_H__
-#define __UI_LOCAL_H__
-
-#include "../qcommon/q_shared.h"
-#include "../renderer/tr_types.h"
-#include "ui_public.h"
-#include "../client/keycodes.h"
-#include "../game/bg_public.h"
-#include "ui_shared.h"
-
-// global display context
-
-extern vmCvar_t ui_ffa_fraglimit;
-extern vmCvar_t ui_ffa_timelimit;
-
-extern vmCvar_t ui_tourney_fraglimit;
-extern vmCvar_t ui_tourney_timelimit;
-
-extern vmCvar_t ui_team_fraglimit;
-extern vmCvar_t ui_team_timelimit;
-extern vmCvar_t ui_team_friendly;
-
-extern vmCvar_t ui_ctf_capturelimit;
-extern vmCvar_t ui_ctf_timelimit;
-extern vmCvar_t ui_ctf_friendly;
-
-extern vmCvar_t ui_arenasFile;
-extern vmCvar_t ui_botsFile;
-extern vmCvar_t ui_spScores1;
-extern vmCvar_t ui_spScores2;
-extern vmCvar_t ui_spScores3;
-extern vmCvar_t ui_spScores4;
-extern vmCvar_t ui_spScores5;
-extern vmCvar_t ui_spAwards;
-extern vmCvar_t ui_spVideos;
-extern vmCvar_t ui_spSkill;
-
-extern vmCvar_t ui_spSelection;
-
-extern vmCvar_t ui_browserMaster;
-extern vmCvar_t ui_browserGameType;
-extern vmCvar_t ui_browserSortKey;
-extern vmCvar_t ui_browserShowFull;
-extern vmCvar_t ui_browserShowEmpty;
-
-extern vmCvar_t ui_brassTime;
-extern vmCvar_t ui_drawCrosshair;
-extern vmCvar_t ui_drawCrosshairNames;
-extern vmCvar_t ui_marks;
-
-extern vmCvar_t ui_server1;
-extern vmCvar_t ui_server2;
-extern vmCvar_t ui_server3;
-extern vmCvar_t ui_server4;
-extern vmCvar_t ui_server5;
-extern vmCvar_t ui_server6;
-extern vmCvar_t ui_server7;
-extern vmCvar_t ui_server8;
-extern vmCvar_t ui_server9;
-extern vmCvar_t ui_server10;
-extern vmCvar_t ui_server11;
-extern vmCvar_t ui_server12;
-extern vmCvar_t ui_server13;
-extern vmCvar_t ui_server14;
-extern vmCvar_t ui_server15;
-extern vmCvar_t ui_server16;
-
-extern vmCvar_t ui_cdkey;
-extern vmCvar_t ui_cdkeychecked;
-
-extern vmCvar_t ui_captureLimit;
-extern vmCvar_t ui_fragLimit;
-extern vmCvar_t ui_gameType;
-extern vmCvar_t ui_netGameType;
-extern vmCvar_t ui_actualNetGameType;
-extern vmCvar_t ui_joinGameType;
-extern vmCvar_t ui_netSource;
-extern vmCvar_t ui_serverFilterType;
-extern vmCvar_t ui_dedicated;
-extern vmCvar_t ui_opponentName;
-extern vmCvar_t ui_menuFiles;
-extern vmCvar_t ui_currentTier;
-extern vmCvar_t ui_currentMap;
-extern vmCvar_t ui_currentNetMap;
-extern vmCvar_t ui_mapIndex;
-extern vmCvar_t ui_currentOpponent;
-extern vmCvar_t ui_selectedPlayer;
-extern vmCvar_t ui_selectedPlayerName;
-extern vmCvar_t ui_lastServerRefresh_0;
-extern vmCvar_t ui_lastServerRefresh_1;
-extern vmCvar_t ui_lastServerRefresh_2;
-extern vmCvar_t ui_lastServerRefresh_3;
-extern vmCvar_t ui_singlePlayerActive;
-extern vmCvar_t ui_scoreAccuracy;
-extern vmCvar_t ui_scoreImpressives;
-extern vmCvar_t ui_scoreExcellents;
-extern vmCvar_t ui_scoreDefends;
-extern vmCvar_t ui_scoreAssists;
-extern vmCvar_t ui_scoreGauntlets;
-extern vmCvar_t ui_scoreScore;
-extern vmCvar_t ui_scorePerfect;
-extern vmCvar_t ui_scoreTeam;
-extern vmCvar_t ui_scoreBase;
-extern vmCvar_t ui_scoreTimeBonus;
-extern vmCvar_t ui_scoreSkillBonus;
-extern vmCvar_t ui_scoreShutoutBonus;
-extern vmCvar_t ui_scoreTime;
-extern vmCvar_t ui_smallFont;
-extern vmCvar_t ui_bigFont;
-extern vmCvar_t ui_serverStatusTimeOut;
-
-
-
-//
-// ui_qmenu.c
-//
-
-#define RCOLUMN_OFFSET ( BIGCHAR_WIDTH )
-#define LCOLUMN_OFFSET (-BIGCHAR_WIDTH )
-
-#define SLIDER_RANGE 10
-#define MAX_EDIT_LINE 256
-
-#define MAX_MENUDEPTH 8
-#define MAX_MENUITEMS 96
-
-#define MTYPE_NULL 0
-#define MTYPE_SLIDER 1
-#define MTYPE_ACTION 2
-#define MTYPE_SPINCONTROL 3
-#define MTYPE_FIELD 4
-#define MTYPE_RADIOBUTTON 5
-#define MTYPE_BITMAP 6
-#define MTYPE_TEXT 7
-#define MTYPE_SCROLLLIST 8
-#define MTYPE_PTEXT 9
-#define MTYPE_BTEXT 10
-
-#define QMF_BLINK 0x00000001
-#define QMF_SMALLFONT 0x00000002
-#define QMF_LEFT_JUSTIFY 0x00000004
-#define QMF_CENTER_JUSTIFY 0x00000008
-#define QMF_RIGHT_JUSTIFY 0x00000010
-#define QMF_NUMBERSONLY 0x00000020 // edit field is only numbers
-#define QMF_HIGHLIGHT 0x00000040
-#define QMF_HIGHLIGHT_IF_FOCUS 0x00000080 // steady focus
-#define QMF_PULSEIFFOCUS 0x00000100 // pulse if focus
-#define QMF_HASMOUSEFOCUS 0x00000200
-#define QMF_NOONOFFTEXT 0x00000400
-#define QMF_MOUSEONLY 0x00000800 // only mouse input allowed
-#define QMF_HIDDEN 0x00001000 // skips drawing
-#define QMF_GRAYED 0x00002000 // grays and disables
-#define QMF_INACTIVE 0x00004000 // disables any input
-#define QMF_NODEFAULTINIT 0x00008000 // skip default initialization
-#define QMF_OWNERDRAW 0x00010000
-#define QMF_PULSE 0x00020000
-#define QMF_LOWERCASE 0x00040000 // edit field is all lower case
-#define QMF_UPPERCASE 0x00080000 // edit field is all upper case
-#define QMF_SILENT 0x00100000
-
-// callback notifications
-#define QM_GOTFOCUS 1
-#define QM_LOSTFOCUS 2
-#define QM_ACTIVATED 3
-
-typedef struct _tag_menuframework
-{
- int cursor;
- int cursor_prev;
-
- int nitems;
- void *items[MAX_MENUITEMS];
-
- void (*draw) (void);
- sfxHandle_t (*key) (int key);
-
- qboolean wrapAround;
- qboolean fullscreen;
- qboolean showlogo;
-} menuframework_s;
-
-typedef struct
-{
- int type;
- const char *name;
- int id;
- int x, y;
- int left;
- int top;
- int right;
- int bottom;
- menuframework_s *parent;
- int menuPosition;
- unsigned flags;
-
- void (*callback)( void *self, int event );
- void (*statusbar)( void *self );
- void (*ownerdraw)( void *self );
-} menucommon_s;
-
-typedef struct {
- int cursor;
- int scroll;
- int widthInChars;
- char buffer[MAX_EDIT_LINE];
- int maxchars;
-} mfield_t;
-
-typedef struct
-{
- menucommon_s generic;
- mfield_t field;
-} menufield_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- float minvalue;
- float maxvalue;
- float curvalue;
-
- float range;
-} menuslider_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- int oldvalue;
- int curvalue;
- int numitems;
- int top;
-
- const char **itemnames;
-
- int width;
- int height;
- int columns;
- int seperation;
-} menulist_s;
-
-typedef struct
-{
- menucommon_s generic;
-} menuaction_s;
-
-typedef struct
-{
- menucommon_s generic;
- int curvalue;
-} menuradiobutton_s;
-
-typedef struct
-{
- menucommon_s generic;
- char* focuspic;
- char* errorpic;
- qhandle_t shader;
- qhandle_t focusshader;
- int width;
- int height;
- float* focuscolor;
-} menubitmap_s;
-
-typedef struct
-{
- menucommon_s generic;
- char* string;
- int style;
- float* color;
-} menutext_s;
-
-extern void Menu_Cache( void );
-extern void Menu_Focus( menucommon_s *m );
-extern void Menu_AddItem( menuframework_s *menu, void *item );
-extern void Menu_AdjustCursor( menuframework_s *menu, int dir );
-extern void Menu_Draw( menuframework_s *menu );
-extern void *Menu_ItemAtCursor( menuframework_s *m );
-extern sfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item );
-extern void Menu_SetCursor( menuframework_s *s, int cursor );
-extern void Menu_SetCursorToItem( menuframework_s *m, void* ptr );
-extern sfxHandle_t Menu_DefaultKey( menuframework_s *s, int key );
-extern void Bitmap_Init( menubitmap_s *b );
-extern void Bitmap_Draw( menubitmap_s *b );
-extern void ScrollList_Draw( menulist_s *l );
-extern sfxHandle_t ScrollList_Key( menulist_s *l, int key );
-extern sfxHandle_t menu_in_sound;
-extern sfxHandle_t menu_move_sound;
-extern sfxHandle_t menu_out_sound;
-extern sfxHandle_t menu_buzz_sound;
-extern sfxHandle_t menu_null_sound;
-extern sfxHandle_t weaponChangeSound;
-extern vec4_t menu_text_color;
-extern vec4_t menu_grayed_color;
-extern vec4_t menu_dark_color;
-extern vec4_t menu_highlight_color;
-extern vec4_t menu_red_color;
-extern vec4_t menu_black_color;
-extern vec4_t menu_dim_color;
-extern vec4_t color_black;
-extern vec4_t color_white;
-extern vec4_t color_yellow;
-extern vec4_t color_blue;
-extern vec4_t color_orange;
-extern vec4_t color_red;
-extern vec4_t color_dim;
-extern vec4_t name_color;
-extern vec4_t list_color;
-extern vec4_t listbar_color;
-extern vec4_t text_color_disabled;
-extern vec4_t text_color_normal;
-extern vec4_t text_color_highlight;
-
-extern char *ui_medalNames[];
-extern char *ui_medalPicNames[];
-extern char *ui_medalSounds[];
-
-//
-// ui_mfield.c
-//
-extern void MField_Clear( mfield_t *edit );
-extern void MField_KeyDownEvent( mfield_t *edit, int key );
-extern void MField_CharEvent( mfield_t *edit, int ch );
-extern void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color );
-extern void MenuField_Init( menufield_s* m );
-extern void MenuField_Draw( menufield_s *f );
-extern sfxHandle_t MenuField_Key( menufield_s* m, int* key );
-
-//
-// ui_main.c
-//
-void UI_Report( void );
-void UI_Load( void );
-void UI_LoadMenus(const char *menuFile, qboolean reset);
-void _UI_SetActiveMenu( uiMenuCommand_t menu );
-int UI_AdjustTimeByGame(int time);
-void UI_ShowPostGame(qboolean newHigh);
-void UI_ClearScores( void );
-void UI_LoadArenas(void);
-
-//
-// ui_menu.c
-//
-extern void MainMenu_Cache( void );
-extern void UI_MainMenu(void);
-extern void UI_RegisterCvars( void );
-extern void UI_UpdateCvars( void );
-
-//
-// ui_credits.c
-//
-extern void UI_CreditMenu( void );
-
-//
-// ui_ingame.c
-//
-extern void InGame_Cache( void );
-extern void UI_InGameMenu(void);
-
-//
-// ui_confirm.c
-//
-extern void ConfirmMenu_Cache( void );
-extern void UI_ConfirmMenu( const char *question, void (*draw)( void ), void (*action)( qboolean result ) );
-
-//
-// ui_setup.c
-//
-extern void UI_SetupMenu_Cache( void );
-extern void UI_SetupMenu(void);
-
-//
-// ui_team.c
-//
-extern void UI_TeamMainMenu( void );
-extern void TeamMain_Cache( void );
-
-//
-// ui_connect.c
-//
-extern void UI_DrawConnectScreen( qboolean overlay );
-
-//
-// ui_controls2.c
-//
-extern void UI_ControlsMenu( void );
-extern void Controls_Cache( void );
-
-//
-// ui_demo2.c
-//
-extern void UI_DemosMenu( void );
-extern void Demos_Cache( void );
-
-//
-// ui_cinematics.c
-//
-extern void UI_CinematicsMenu( void );
-extern void UI_CinematicsMenu_f( void );
-extern void UI_CinematicsMenu_Cache( void );
-
-//
-// ui_mods.c
-//
-extern void UI_ModsMenu( void );
-extern void UI_ModsMenu_Cache( void );
-
-//
-// ui_cdkey.c
-//
-extern void UI_CDKeyMenu( void );
-extern void UI_CDKeyMenu_Cache( void );
-extern void UI_CDKeyMenu_f( void );
-
-//
-// ui_playermodel.c
-//
-extern void UI_PlayerModelMenu( void );
-extern void PlayerModel_Cache( void );
-
-//
-// ui_playersettings.c
-//
-extern void UI_PlayerSettingsMenu( void );
-extern void PlayerSettings_Cache( void );
-
-//
-// ui_preferences.c
-//
-extern void UI_PreferencesMenu( void );
-extern void Preferences_Cache( void );
-
-//
-// ui_specifyleague.c
-//
-extern void UI_SpecifyLeagueMenu( void );
-extern void SpecifyLeague_Cache( void );
-
-//
-// ui_specifyserver.c
-//
-extern void UI_SpecifyServerMenu( void );
-extern void SpecifyServer_Cache( void );
-
-//
-// ui_servers2.c
-//
-#define MAX_FAVORITESERVERS 16
-
-extern void UI_ArenaServersMenu( void );
-extern void ArenaServers_Cache( void );
-
-//
-// ui_startserver.c
-//
-extern void UI_StartServerMenu( qboolean multiplayer );
-extern void StartServer_Cache( void );
-extern void ServerOptions_Cache( void );
-extern void UI_BotSelectMenu( char *bot );
-extern void UI_BotSelectMenu_Cache( void );
-
-//
-// ui_serverinfo.c
-//
-extern void UI_ServerInfoMenu( void );
-extern void ServerInfo_Cache( void );
-
-//
-// ui_video.c
-//
-extern void UI_GraphicsOptionsMenu( void );
-extern void GraphicsOptions_Cache( void );
-extern void DriverInfo_Cache( void );
-
-//
-// ui_players.c
-//
-
-//FIXME ripped from cg_local.h
-typedef struct {
- int oldFrame;
- int oldFrameTime; // time when ->oldFrame was exactly on
-
- int frame;
- int frameTime; // time when ->frame will be exactly on
-
- float backlerp;
-
- float yawAngle;
- qboolean yawing;
- float pitchAngle;
- qboolean pitching;
-
- int animationNumber; // may include ANIM_TOGGLEBIT
- animation_t *animation;
- int animationTime; // time when the first frame of the animation will be exact
-} lerpFrame_t;
-
-typedef struct {
- // model info
- qhandle_t legsModel;
- qhandle_t legsSkin;
- lerpFrame_t legs;
-
- qhandle_t torsoModel;
- qhandle_t torsoSkin;
- lerpFrame_t torso;
-
- qhandle_t headModel;
- qhandle_t headSkin;
-
- animation_t animations[MAX_TOTALANIMATIONS];
-
- qhandle_t weaponModel;
- qhandle_t barrelModel;
- qhandle_t flashModel;
- vec3_t flashDlightColor;
- int muzzleFlashTime;
-
- // currently in use drawing parms
- vec3_t viewAngles;
- vec3_t moveAngles;
- weapon_t currentWeapon;
- int legsAnim;
- int torsoAnim;
-
- // animation vars
- weapon_t weapon;
- weapon_t lastWeapon;
- weapon_t pendingWeapon;
- int weaponTimer;
- int pendingLegsAnim;
- int torsoAnimationTimer;
-
- int pendingTorsoAnim;
- int legsAnimationTimer;
-
- qboolean chat;
- qboolean newModel;
-
- qboolean barrelSpinning;
- float barrelAngle;
- int barrelTime;
-
- int realWeapon;
-} playerInfo_t;
-
-void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time );
-void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model, const char *headmodel, char *teamName );
-void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNum, qboolean chat );
-qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName , const char *headName, const char *teamName);
-
-//
-// ui_atoms.c
-//
-// this is only used in the old ui, the new ui has it's own version
-typedef struct {
- int frametime;
- int realtime;
- int cursorx;
- int cursory;
- glconfig_t glconfig;
- qboolean debug;
- qhandle_t whiteShader;
- qhandle_t menuBackShader;
- qhandle_t menuBackShader2;
- qhandle_t menuBackNoLogoShader;
- qhandle_t charset;
- qhandle_t charsetProp;
- qhandle_t charsetPropGlow;
- qhandle_t charsetPropB;
- qhandle_t cursor;
- qhandle_t rb_on;
- qhandle_t rb_off;
- float scale;
- float bias;
- qboolean demoversion;
- qboolean firstdraw;
-} uiStatic_t;
-
-
-// new ui stuff
-#define UI_NUMFX 7
-#define MAX_HEADS 64
-#define MAX_ALIASES 64
-#define MAX_HEADNAME 32
-#define MAX_TEAMS 64
-#define MAX_GAMETYPES 16
-#define MAX_MAPS 128
-#define MAX_SPMAPS 16
-#define PLAYERS_PER_TEAM 5
-#define MAX_PINGREQUESTS 32
-#define MAX_ADDRESSLENGTH 64
-#define MAX_HOSTNAMELENGTH 22
-#define MAX_MAPNAMELENGTH 16
-#define MAX_STATUSLENGTH 64
-#define MAX_LISTBOXWIDTH 59
-#define UI_FONT_THRESHOLD 0.1
-#define MAX_DISPLAY_SERVERS 2048
-#define MAX_SERVERSTATUS_LINES 128
-#define MAX_SERVERSTATUS_TEXT 1024
-#define MAX_FOUNDPLAYER_SERVERS 16
-#define TEAM_MEMBERS 5
-#define GAMES_ALL 0
-#define GAMES_FFA 1
-#define GAMES_TEAMPLAY 2
-#define GAMES_TOURNEY 3
-#define GAMES_CTF 4
-#define MAPS_PER_TIER 3
-#define MAX_TIERS 16
-#define MAX_MODS 64
-#define MAX_DEMOS 256
-#define MAX_MOVIES 256
-#define MAX_PLAYERMODELS 256
-
-
-typedef struct {
- const char *name;
- const char *imageName;
- qhandle_t headImage;
- const char *base;
- qboolean active;
- int reference;
-} characterInfo;
-
-typedef struct {
- const char *name;
- const char *ai;
- const char *action;
-} aliasInfo;
-
-typedef struct {
- const char *teamName;
- const char *imageName;
- const char *teamMembers[TEAM_MEMBERS];
- qhandle_t teamIcon;
- qhandle_t teamIcon_Metal;
- qhandle_t teamIcon_Name;
- int cinematic;
-} teamInfo;
-
-typedef struct {
- const char *gameType;
- int gtEnum;
-} gameTypeInfo;
-
-typedef struct {
- const char *mapName;
- const char *mapLoadName;
- const char *imageName;
- const char *opponentName;
- int teamMembers;
- int typeBits;
- int cinematic;
- int timeToBeat[MAX_GAMETYPES];
- qhandle_t levelShot;
- qboolean active;
-} mapInfo;
-
-typedef struct {
- const char *tierName;
- const char *maps[MAPS_PER_TIER];
- int gameTypes[MAPS_PER_TIER];
- qhandle_t mapHandles[MAPS_PER_TIER];
-} tierInfo;
-
-typedef struct serverFilter_s {
- const char *description;
- const char *basedir;
-} serverFilter_t;
-
-typedef struct {
- char adrstr[MAX_ADDRESSLENGTH];
- int start;
-} pinglist_t;
-
-
-typedef struct serverStatus_s {
- pinglist_t pingList[MAX_PINGREQUESTS];
- int numqueriedservers;
- int currentping;
- int nextpingtime;
- int maxservers;
- int refreshtime;
- int numServers;
- int sortKey;
- int sortDir;
- int lastCount;
- qboolean refreshActive;
- int currentServer;
- int displayServers[MAX_DISPLAY_SERVERS];
- int numDisplayServers;
- int numPlayersOnServers;
- int nextDisplayRefresh;
- int nextSortTime;
- qhandle_t currentServerPreview;
- int currentServerCinematic;
- int motdLen;
- int motdWidth;
- int motdPaintX;
- int motdPaintX2;
- int motdOffset;
- int motdTime;
- char motd[MAX_STRING_CHARS];
-} serverStatus_t;
-
-
-typedef struct {
- char adrstr[MAX_ADDRESSLENGTH];
- char name[MAX_ADDRESSLENGTH];
- int startTime;
- int serverNum;
- qboolean valid;
-} pendingServer_t;
-
-typedef struct {
- int num;
- pendingServer_t server[MAX_SERVERSTATUSREQUESTS];
-} pendingServerStatus_t;
-
-typedef struct {
- char address[MAX_ADDRESSLENGTH];
- char *lines[MAX_SERVERSTATUS_LINES][4];
- char text[MAX_SERVERSTATUS_TEXT];
- char pings[MAX_CLIENTS * 3];
- int numLines;
-} serverStatusInfo_t;
-
-typedef struct {
- const char *modName;
- const char *modDescr;
-} modInfo_t;
-
-
-typedef struct {
- displayContextDef_t uiDC;
- int newHighScoreTime;
- int newBestTime;
- int showPostGameTime;
- qboolean newHighScore;
- qboolean demoAvailable;
- qboolean soundHighScore;
-
- int characterCount;
- int botIndex;
- characterInfo characterList[MAX_HEADS];
-
- int aliasCount;
- aliasInfo aliasList[MAX_ALIASES];
-
- int teamCount;
- teamInfo teamList[MAX_TEAMS];
-
- int numGameTypes;
- gameTypeInfo gameTypes[MAX_GAMETYPES];
-
- int numJoinGameTypes;
- gameTypeInfo joinGameTypes[MAX_GAMETYPES];
-
- int redBlue;
- int playerCount;
- int myTeamCount;
- int teamIndex;
- int playerRefresh;
- int playerIndex;
- int playerNumber;
- qboolean teamLeader;
- char playerNames[MAX_CLIENTS][MAX_NAME_LENGTH];
- char teamNames[MAX_CLIENTS][MAX_NAME_LENGTH];
- int teamClientNums[MAX_CLIENTS];
-
- int mapCount;
- mapInfo mapList[MAX_MAPS];
-
-
- int tierCount;
- tierInfo tierList[MAX_TIERS];
-
- int skillIndex;
-
- modInfo_t modList[MAX_MODS];
- int modCount;
- int modIndex;
-
- const char *demoList[MAX_DEMOS];
- int demoCount;
- int demoIndex;
-
- const char *movieList[MAX_MOVIES];
- int movieCount;
- int movieIndex;
- int previewMovie;
-
- serverStatus_t serverStatus;
-
- // for the showing the status of a server
- char serverStatusAddress[MAX_ADDRESSLENGTH];
- serverStatusInfo_t serverStatusInfo;
- int nextServerStatusRefresh;
-
- // to retrieve the status of server to find a player
- pendingServerStatus_t pendingServerStatus;
- char findPlayerName[MAX_STRING_CHARS];
- char foundPlayerServerAddresses[MAX_FOUNDPLAYER_SERVERS][MAX_ADDRESSLENGTH];
- char foundPlayerServerNames[MAX_FOUNDPLAYER_SERVERS][MAX_ADDRESSLENGTH];
- int currentFoundPlayerServer;
- int numFoundPlayerServers;
- int nextFindPlayerRefresh;
-
- int currentCrosshair;
- int startPostGameTime;
- sfxHandle_t newHighScoreSound;
-
- int q3HeadCount;
- char q3HeadNames[MAX_PLAYERMODELS][64];
- qhandle_t q3HeadIcons[MAX_PLAYERMODELS];
- int q3SelectedHead;
-
- int effectsColor;
-
- qboolean inGameLoad;
-
-} uiInfo_t;
-
-extern uiInfo_t uiInfo;
-
-
-extern void UI_Init( void );
-extern void UI_Shutdown( void );
-extern void UI_KeyEvent( int key );
-extern void UI_MouseEvent( int dx, int dy );
-extern void UI_Refresh( int realtime );
-extern qboolean UI_ConsoleCommand( int realTime );
-extern float UI_ClampCvar( float min, float max, float value );
-extern void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname );
-extern void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader );
-extern void UI_FillRect( float x, float y, float width, float height, const float *color );
-extern void UI_DrawRect( float x, float y, float width, float height, const float *color );
-extern void UI_DrawTopBottom(float x, float y, float w, float h);
-extern void UI_DrawSides(float x, float y, float w, float h);
-extern void UI_UpdateScreen( void );
-extern void UI_SetColor( const float *rgba );
-extern void UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t);
-extern void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color );
-extern float UI_ProportionalSizeScale( int style );
-extern void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );
-extern int UI_ProportionalStringWidth( const char* str );
-extern void UI_DrawString( int x, int y, const char* str, int style, vec4_t color );
-extern void UI_DrawChar( int x, int y, int ch, int style, vec4_t color );
-extern qboolean UI_CursorInRect (int x, int y, int width, int height);
-extern void UI_AdjustFrom640( float *x, float *y, float *w, float *h );
-extern void UI_DrawTextBox (int x, int y, int width, int lines);
-extern qboolean UI_IsFullscreen( void );
-extern void UI_SetActiveMenu( uiMenuCommand_t menu );
-extern void UI_PushMenu ( menuframework_s *menu );
-extern void UI_PopMenu (void);
-extern void UI_ForceMenuOff (void);
-extern char *UI_Argv( int arg );
-extern char *UI_Cvar_VariableString( const char *var_name );
-extern void UI_Refresh( int time );
-extern void UI_KeyEvent( int key );
-extern void UI_StartDemoLoop( void );
-extern qboolean m_entersound;
-void UI_LoadBestScores(const char *map, int game);
-extern uiStatic_t uis;
-
-//
-// ui_spLevel.c
-//
-void UI_SPLevelMenu_Cache( void );
-void UI_SPLevelMenu( void );
-void UI_SPLevelMenu_f( void );
-void UI_SPLevelMenu_ReInit( void );
-
-//
-// ui_spArena.c
-//
-void UI_SPArena_Start( const char *arenaInfo );
-
-//
-// ui_spPostgame.c
-//
-void UI_SPPostgameMenu_Cache( void );
-void UI_SPPostgameMenu_f( void );
-
-//
-// ui_spSkill.c
-//
-void UI_SPSkillMenu( const char *arenaInfo );
-void UI_SPSkillMenu_Cache( void );
-
-//
-// ui_syscalls.c
-//
-void trap_Print( const char *string );
-void trap_Error( const char *string );
-int trap_Milliseconds( void );
-void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
-void trap_Cvar_Update( vmCvar_t *vmCvar );
-void trap_Cvar_Set( const char *var_name, const char *value );
-float trap_Cvar_VariableValue( const char *var_name );
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-void trap_Cvar_SetValue( const char *var_name, float value );
-void trap_Cvar_Reset( const char *name );
-void trap_Cvar_Create( const char *var_name, const char *var_value, int flags );
-void trap_Cvar_InfoStringBuffer( int bit, char *buffer, int bufsize );
-int trap_Argc( void );
-void trap_Argv( int n, char *buffer, int bufferLength );
-void trap_Cmd_ExecuteText( int exec_when, const char *text ); // don't use EXEC_NOW!
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
-void trap_FS_Read( void *buffer, int len, fileHandle_t f );
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
-void trap_FS_FCloseFile( fileHandle_t f );
-int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
-qhandle_t trap_R_RegisterModel( const char *name );
-qhandle_t trap_R_RegisterSkin( const char *name );
-qhandle_t trap_R_RegisterShaderNoMip( const char *name );
-void trap_R_ClearScene( void );
-void trap_R_AddRefEntityToScene( const refEntity_t *re );
-void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );
-void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
-void trap_R_RenderScene( const refdef_t *fd );
-void trap_R_SetColor( const float *rgba );
-void trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
-void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );
-void trap_UpdateScreen( void );
-int trap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName );
-void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );
-sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed );
-void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen );
-void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen );
-void trap_Key_SetBinding( int keynum, const char *binding );
-qboolean trap_Key_IsDown( int keynum );
-qboolean trap_Key_GetOverstrikeMode( void );
-void trap_Key_SetOverstrikeMode( qboolean state );
-void trap_Key_ClearStates( void );
-int trap_Key_GetCatcher( void );
-void trap_Key_SetCatcher( int catcher );
-void trap_GetClipboardData( char *buf, int bufsize );
-void trap_GetClientState( uiClientState_t *state );
-void trap_GetGlconfig( glconfig_t *glconfig );
-int trap_GetConfigString( int index, char* buff, int buffsize );
-int trap_LAN_GetServerCount( int source );
-void trap_LAN_GetServerAddressString( int source, int n, char *buf, int buflen );
-void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen );
-int trap_LAN_GetServerPing( int source, int n );
-int trap_LAN_GetPingQueueCount( void );
-void trap_LAN_ClearPing( int n );
-void trap_LAN_GetPing( int n, char *buf, int buflen, int *pingtime );
-void trap_LAN_GetPingInfo( int n, char *buf, int buflen );
-void trap_LAN_LoadCachedServers( void );
-void trap_LAN_SaveCachedServers( void );
-void trap_LAN_MarkServerVisible(int source, int n, qboolean visible);
-int trap_LAN_ServerIsVisible( int source, int n);
-qboolean trap_LAN_UpdateVisiblePings( int source );
-int trap_LAN_AddServer(int source, const char *name, const char *addr);
-void trap_LAN_RemoveServer(int source, const char *addr);
-void trap_LAN_ResetPings(int n);
-int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen );
-int trap_LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 );
-int trap_MemoryRemaining( void );
-void trap_GetCDKey( char *buf, int buflen );
-void trap_SetCDKey( char *buf );
-void trap_R_RegisterFont(const char *pFontname, int pointSize, fontInfo_t *font);
-void trap_S_StopBackgroundTrack( void );
-void trap_S_StartBackgroundTrack( const char *intro, const char *loop);
-int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits);
-e_status trap_CIN_StopCinematic(int handle);
-e_status trap_CIN_RunCinematic (int handle);
-void trap_CIN_DrawCinematic (int handle);
-void trap_CIN_SetExtents (int handle, int x, int y, int w, int h);
-int trap_RealTime(qtime_t *qtime);
-void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset );
-qboolean trap_VerifyCDKey( const char *key, const char *chksum);
-
-void trap_SetPbClStatus( int status );
-
-//
-// ui_addbots.c
-//
-void UI_AddBots_Cache( void );
-void UI_AddBotsMenu( void );
-
-//
-// ui_removebots.c
-//
-void UI_RemoveBots_Cache( void );
-void UI_RemoveBotsMenu( void );
-
-//
-// ui_teamorders.c
-//
-extern void UI_TeamOrdersMenu( void );
-extern void UI_TeamOrdersMenu_f( void );
-extern void UI_TeamOrdersMenu_Cache( void );
-
-//
-// ui_loadconfig.c
-//
-void UI_LoadConfig_Cache( void );
-void UI_LoadConfigMenu( void );
-
-//
-// ui_saveconfig.c
-//
-void UI_SaveConfigMenu_Cache( void );
-void UI_SaveConfigMenu( void );
-
-//
-// ui_display.c
-//
-void UI_DisplayOptionsMenu_Cache( void );
-void UI_DisplayOptionsMenu( void );
-
-//
-// ui_sound.c
-//
-void UI_SoundOptionsMenu_Cache( void );
-void UI_SoundOptionsMenu( void );
-
-//
-// ui_network.c
-//
-void UI_NetworkOptionsMenu_Cache( void );
-void UI_NetworkOptionsMenu( void );
-
-//
-// ui_gameinfo.c
-//
-typedef enum {
- AWARD_ACCURACY,
- AWARD_IMPRESSIVE,
- AWARD_EXCELLENT,
- AWARD_GAUNTLET,
- AWARD_FRAGS,
- AWARD_PERFECT
-} awardType_t;
-
-const char *UI_GetArenaInfoByNumber( int num );
-const char *UI_GetArenaInfoByMap( const char *map );
-const char *UI_GetSpecialArenaInfo( const char *tag );
-int UI_GetNumArenas( void );
-int UI_GetNumSPArenas( void );
-int UI_GetNumSPTiers( void );
-
-char *UI_GetBotInfoByNumber( int num );
-char *UI_GetBotInfoByName( const char *name );
-int UI_GetNumBots( void );
-void UI_LoadBots( void );
-char *UI_GetBotNameByNumber( int num );
-
-void UI_GetBestScore( int level, int *score, int *skill );
-void UI_SetBestScore( int level, int score );
-int UI_TierCompleted( int levelWon );
-qboolean UI_ShowTierVideo( int tier );
-qboolean UI_CanShowTierVideo( int tier );
-int UI_GetCurrentGame( void );
-void UI_NewGame( void );
-void UI_LogAwardData( int award, int data );
-int UI_GetAwardLevel( int award );
-
-void UI_SPUnlock_f( void );
-void UI_SPUnlockMedals_f( void );
-
-void UI_InitGameinfo( void );
-
-//
-// ui_login.c
-//
-void Login_Cache( void );
-void UI_LoginMenu( void );
-
-//
-// ui_signup.c
-//
-void Signup_Cache( void );
-void UI_SignupMenu( void );
-
-//
-// ui_rankstatus.c
-//
-void RankStatus_Cache( void );
-void UI_RankStatusMenu( void );
-
-
-// new ui
-
-#define ASSET_BACKGROUND "uiBackground"
-
-// for tracking sp game info in Team Arena
-typedef struct postGameInfo_s {
- int score;
- int redScore;
- int blueScore;
- int perfects;
- int accuracy;
- int impressives;
- int excellents;
- int defends;
- int assists;
- int gauntlets;
- int captures;
- int time;
- int timeBonus;
- int shutoutBonus;
- int skillBonus;
- int baseScore;
-} postGameInfo_t;
-
-
-
-#endif
diff --git a/engine/code/ui/ui_main.c b/engine/code/ui/ui_main.c
deleted file mode 100644
index 6c9fb6e..0000000
--- a/engine/code/ui/ui_main.c
+++ /dev/null
@@ -1,5981 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-USER INTERFACE MAIN
-
-=======================================================================
-*/
-
-// use this to get a demo build without an explicit demo build, i.e. to get the demo ui files to build
-//#define PRE_RELEASE_TADEMO
-
-#include "ui_local.h"
-
-uiInfo_t uiInfo;
-
-static const char *MonthAbbrev[] = {
- "Jan","Feb","Mar",
- "Apr","May","Jun",
- "Jul","Aug","Sep",
- "Oct","Nov","Dec"
-};
-
-
-static const char *skillLevels[] = {
- "I Can Win",
- "Bring It On",
- "Hurt Me Plenty",
- "Hardcore",
- "Nightmare"
-};
-
-static const int numSkillLevels = sizeof(skillLevels) / sizeof(const char*);
-
-
-static const char *netSources[] = {
- "Local",
- "Mplayer",
- "Internet",
- "Favorites"
-};
-static const int numNetSources = sizeof(netSources) / sizeof(const char*);
-
-static const serverFilter_t serverFilters[] = {
- {"All", "" },
- {"Quake 3 Arena", "" },
- {"Team Arena", "missionpack" },
- {"Rocket Arena", "arena" },
- {"Alliance", "alliance20" },
- {"Weapons Factory Arena", "wfa" },
- {"OSP", "osp" },
-};
-
-static const char *teamArenaGameTypes[] = {
- "FFA",
- "TOURNAMENT",
- "SP",
- "TEAM DM",
- "CTF",
- "1FCTF",
- "OVERLOAD",
- "HARVESTER",
- "TEAMTOURNAMENT"
-};
-
-static int const numTeamArenaGameTypes = sizeof(teamArenaGameTypes) / sizeof(const char*);
-
-
-static const char *teamArenaGameNames[] = {
- "Free For All",
- "Tournament",
- "Single Player",
- "Team Deathmatch",
- "Capture the Flag",
- "One Flag CTF",
- "Overload",
- "Harvester",
- "Team Tournament",
-};
-
-static int const numTeamArenaGameNames = sizeof(teamArenaGameNames) / sizeof(const char*);
-
-
-static const int numServerFilters = sizeof(serverFilters) / sizeof(serverFilter_t);
-
-static const char *sortKeys[] = {
- "Server Name",
- "Map Name",
- "Open Player Spots",
- "Game Type",
- "Ping Time"
-};
-static const int numSortKeys = sizeof(sortKeys) / sizeof(const char*);
-
-static char* netnames[] = {
- "???",
- "UDP",
- NULL
-};
-
-#ifndef MISSIONPACK
-static char quake3worldMessage[] = "Visit www.quake3world.com - News, Community, Events, Files";
-#endif
-
-static int gamecodetoui[] = {4,2,3,0,5,1,6};
-static int uitogamecode[] = {4,6,2,3,1,5,7};
-
-
-static void UI_StartServerRefresh(qboolean full);
-static void UI_StopServerRefresh( void );
-static void UI_DoServerRefresh( void );
-static void UI_FeederSelection(float feederID, int index);
-static void UI_BuildServerDisplayList(qboolean force);
-static void UI_BuildServerStatus(qboolean force);
-static void UI_BuildFindPlayerList(qboolean force);
-static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 );
-static int UI_MapCountByGameType(qboolean singlePlayer);
-static int UI_HeadCountByTeam( void );
-static void UI_ParseGameInfo(const char *teamFile);
-static void UI_ParseTeamInfo(const char *teamFile);
-static const char *UI_SelectedMap(int index, int *actual);
-static const char *UI_SelectedHead(int index, int *actual);
-static int UI_GetIndexFromSelection(int actual);
-
-int ProcessNewUI( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 );
-
-/*
-================
-vmMain
-
-This is the only way control passes into the module.
-This must be the very first function compiled into the .qvm file
-================
-*/
-vmCvar_t ui_new;
-vmCvar_t ui_debug;
-vmCvar_t ui_initialized;
-vmCvar_t ui_teamArenaFirstRun;
-
-void _UI_Init( qboolean );
-void _UI_Shutdown( void );
-void _UI_KeyEvent( int key, qboolean down );
-void _UI_MouseEvent( int dx, int dy );
-void _UI_Refresh( int realtime );
-qboolean _UI_IsFullscreen( void );
-Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
- switch ( command ) {
- case UI_GETAPIVERSION:
- return UI_API_VERSION;
-
- case UI_INIT:
- _UI_Init(arg0);
- return 0;
-
- case UI_SHUTDOWN:
- _UI_Shutdown();
- return 0;
-
- case UI_KEY_EVENT:
- _UI_KeyEvent( arg0, arg1 );
- return 0;
-
- case UI_MOUSE_EVENT:
- _UI_MouseEvent( arg0, arg1 );
- return 0;
-
- case UI_REFRESH:
- _UI_Refresh( arg0 );
- return 0;
-
- case UI_IS_FULLSCREEN:
- return _UI_IsFullscreen();
-
- case UI_SET_ACTIVE_MENU:
- _UI_SetActiveMenu( arg0 );
- return 0;
-
- case UI_CONSOLE_COMMAND:
- return UI_ConsoleCommand(arg0);
-
- case UI_DRAW_CONNECT_SCREEN:
- UI_DrawConnectScreen( arg0 );
- return 0;
- case UI_HASUNIQUECDKEY: // mod authors need to observe this
- return qtrue; // change this to qfalse for mods!
-
- }
-
- return -1;
-}
-
-
-
-void AssetCache( void ) {
- int n;
- //if (Assets.textFont == NULL) {
- //}
- //Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND );
- //Com_Printf("Menu Size: %i bytes\n", sizeof(Menus));
- uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
- uiInfo.uiDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
- uiInfo.uiDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
- uiInfo.uiDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
- uiInfo.uiDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
- uiInfo.uiDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
- uiInfo.uiDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
- uiInfo.uiDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
- uiInfo.uiDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
- uiInfo.uiDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
- uiInfo.uiDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
- uiInfo.uiDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
- uiInfo.uiDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
- uiInfo.uiDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
- uiInfo.uiDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
- uiInfo.uiDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
- uiInfo.uiDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
-
- for( n = 0; n < NUM_CROSSHAIRS; n++ ) {
- uiInfo.uiDC.Assets.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a' + n ) );
- }
-
- uiInfo.newHighScoreSound = trap_S_RegisterSound("sound/feedback/voc_newhighscore.wav", qfalse);
-}
-
-void _UI_DrawSides(float x, float y, float w, float h, float size) {
- UI_AdjustFrom640( &x, &y, &w, &h );
- size *= uiInfo.uiDC.xscale;
- trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
- trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
-}
-
-void _UI_DrawTopBottom(float x, float y, float w, float h, float size) {
- UI_AdjustFrom640( &x, &y, &w, &h );
- size *= uiInfo.uiDC.yscale;
- trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
- trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
-}
-/*
-================
-UI_DrawRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void _UI_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
- trap_R_SetColor( color );
-
- _UI_DrawTopBottom(x, y, width, height, size);
- _UI_DrawSides(x, y, width, height, size);
-
- trap_R_SetColor( NULL );
-}
-
-int Text_Width(const char *text, float scale, int limit) {
- int count,len;
- float out;
- glyphInfo_t *glyph;
- float useScale;
- const char *s = text;
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale >= ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- out = 0;
- if (text) {
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- if ( Q_IsColorString(s) ) {
- s += 2;
- continue;
- } else {
- glyph = &font->glyphs[(int)*s];
- out += glyph->xSkip;
- s++;
- count++;
- }
- }
- }
- return out * useScale;
-}
-
-int Text_Height(const char *text, float scale, int limit) {
- int len, count;
- float max;
- glyphInfo_t *glyph;
- float useScale;
- const char *s = text;
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale >= ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- max = 0;
- if (text) {
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- if ( Q_IsColorString(s) ) {
- s += 2;
- continue;
- } else {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- if (max < glyph->height) {
- max = glyph->height;
- }
- s++;
- count++;
- }
- }
- }
- return max * useScale;
-}
-
-void Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
- float w, h;
- w = width * scale;
- h = height * scale;
- UI_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
-}
-
-void Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph;
- float useScale;
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale >= ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- if (text) {
- const char *s = text;
- trap_R_SetColor( color );
- memcpy(&newColor[0], &color[0], sizeof(vec4_t));
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
- //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- float yadj = useScale * glyph->top;
- if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
- int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
- colorBlack[3] = newColor[3];
- trap_R_SetColor( colorBlack );
- Text_PaintChar(x + ofs, y - yadj + ofs,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- trap_R_SetColor( newColor );
- colorBlack[3] = 1.0;
- }
- Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
-
- x += (glyph->xSkip * useScale) + adjust;
- s++;
- count++;
- }
- }
- trap_R_SetColor( NULL );
- }
-}
-
-void Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph, *glyph2;
- float yadj;
- float useScale;
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale >= ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- if (text) {
- const char *s = text;
- trap_R_SetColor( color );
- memcpy(&newColor[0], &color[0], sizeof(vec4_t));
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- glyph2 = &font->glyphs[ (int) cursor];
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
- //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- yadj = useScale * glyph->top;
- if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
- int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
- colorBlack[3] = newColor[3];
- trap_R_SetColor( colorBlack );
- Text_PaintChar(x + ofs, y - yadj + ofs,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- colorBlack[3] = 1.0;
- trap_R_SetColor( newColor );
- }
- Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
-
- yadj = useScale * glyph2->top;
- if (count == cursorPos && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
- Text_PaintChar(x, y - yadj,
- glyph2->imageWidth,
- glyph2->imageHeight,
- useScale,
- glyph2->s,
- glyph2->t,
- glyph2->s2,
- glyph2->t2,
- glyph2->glyph);
- }
-
- x += (glyph->xSkip * useScale);
- s++;
- count++;
- }
- }
- // need to paint cursor at end of text
- if (cursorPos == len && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
- yadj = useScale * glyph2->top;
- Text_PaintChar(x, y - yadj,
- glyph2->imageWidth,
- glyph2->imageHeight,
- useScale,
- glyph2->s,
- glyph2->t,
- glyph2->s2,
- glyph2->t2,
- glyph2->glyph);
-
- }
-
- trap_R_SetColor( NULL );
- }
-}
-
-
-static void Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph;
- if (text) {
- const char *s = text;
- float max = *maxX;
- float useScale;
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale > ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- trap_R_SetColor( color );
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- float yadj = useScale * glyph->top;
- if (Text_Width(s, useScale, 1) + x > max) {
- *maxX = 0;
- break;
- }
- Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- x += (glyph->xSkip * useScale) + adjust;
- *maxX = x;
- count++;
- s++;
- }
- }
- trap_R_SetColor( NULL );
- }
-
-}
-
-
-void UI_ShowPostGame(qboolean newHigh) {
- trap_Cvar_Set ("cg_cameraOrbit", "0");
- trap_Cvar_Set("cg_thirdPerson", "0");
- uiInfo.soundHighScore = newHigh;
- _UI_SetActiveMenu(UIMENU_POSTGAME);
-}
-/*
-=================
-_UI_Refresh
-=================
-*/
-
-void UI_DrawCenteredPic(qhandle_t image, int w, int h) {
- int x, y;
- x = (SCREEN_WIDTH - w) / 2;
- y = (SCREEN_HEIGHT - h) / 2;
- UI_DrawHandlePic(x, y, w, h, image);
-}
-
-int frameCount = 0;
-int startTime;
-
-#define UI_FPS_FRAMES 4
-void _UI_Refresh( int realtime )
-{
- static int index;
- static int previousTimes[UI_FPS_FRAMES];
-
- //if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
- // return;
- //}
-
- uiInfo.uiDC.frameTime = realtime - uiInfo.uiDC.realTime;
- uiInfo.uiDC.realTime = realtime;
-
- previousTimes[index % UI_FPS_FRAMES] = uiInfo.uiDC.frameTime;
- index++;
- if ( index > UI_FPS_FRAMES ) {
- int i, total;
- // average multiple frames together to smooth changes out a bit
- total = 0;
- for ( i = 0 ; i < UI_FPS_FRAMES ; i++ ) {
- total += previousTimes[i];
- }
- if ( !total ) {
- total = 1;
- }
- uiInfo.uiDC.FPS = 1000 * UI_FPS_FRAMES / total;
- }
-
-
-
- UI_UpdateCvars();
-
- if (Menu_Count() > 0) {
- // paint all the menus
- Menu_PaintAll();
- // refresh server browser list
- UI_DoServerRefresh();
- // refresh server status
- UI_BuildServerStatus(qfalse);
- // refresh find player list
- UI_BuildFindPlayerList(qfalse);
- }
-
- // draw cursor
- UI_SetColor( NULL );
- if (Menu_Count() > 0) {
- UI_DrawHandlePic( uiInfo.uiDC.cursorx-16, uiInfo.uiDC.cursory-16, 32, 32, uiInfo.uiDC.Assets.cursor);
- }
-
-#ifndef NDEBUG
- if (uiInfo.uiDC.debug)
- {
- // cursor coordinates
- //FIXME
- //UI_DrawString( 0, 0, va("(%d,%d)",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed );
- }
-#endif
-
-}
-
-/*
-=================
-_UI_Shutdown
-=================
-*/
-void _UI_Shutdown( void ) {
- trap_LAN_SaveCachedServers();
-}
-
-char *defaultMenu = NULL;
-
-char *GetMenuBuffer(const char *filename) {
- int len;
- fileHandle_t f;
- static char buf[MAX_MENUFILE];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
- return defaultMenu;
- }
- if ( len >= MAX_MENUFILE ) {
- trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", filename, len, MAX_MENUFILE ) );
- trap_FS_FCloseFile( f );
- return defaultMenu;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
- //COM_Compress(buf);
- return buf;
-
-}
-
-qboolean Asset_Parse(int handle) {
- pc_token_t token;
- const char *tempStr;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (Q_stricmp(token.string, "{") != 0) {
- return qfalse;
- }
-
- while ( 1 ) {
-
- memset(&token, 0, sizeof(pc_token_t));
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
-
- if (Q_stricmp(token.string, "}") == 0) {
- return qtrue;
- }
-
- // font
- if (Q_stricmp(token.string, "font") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
- return qfalse;
- }
- trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.textFont);
- uiInfo.uiDC.Assets.fontRegistered = qtrue;
- continue;
- }
-
- if (Q_stricmp(token.string, "smallFont") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
- return qfalse;
- }
- trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.smallFont);
- continue;
- }
-
- if (Q_stricmp(token.string, "bigFont") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
- return qfalse;
- }
- trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.bigFont);
- continue;
- }
-
-
- // gradientbar
- if (Q_stricmp(token.string, "gradientbar") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
- continue;
- }
-
- // enterMenuSound
- if (Q_stricmp(token.string, "menuEnterSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // exitMenuSound
- if (Q_stricmp(token.string, "menuExitSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // itemFocusSound
- if (Q_stricmp(token.string, "itemFocusSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // menuBuzzSound
- if (Q_stricmp(token.string, "menuBuzzSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- if (Q_stricmp(token.string, "cursor") == 0) {
- if (!PC_String_Parse(handle, &uiInfo.uiDC.Assets.cursorStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.cursor = trap_R_RegisterShaderNoMip( uiInfo.uiDC.Assets.cursorStr);
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeClamp") == 0) {
- if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeClamp)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeCycle") == 0) {
- if (!PC_Int_Parse(handle, &uiInfo.uiDC.Assets.fadeCycle)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeAmount") == 0) {
- if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeAmount)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowX") == 0) {
- if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowX)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowY") == 0) {
- if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowY)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowColor") == 0) {
- if (!PC_Color_Parse(handle, &uiInfo.uiDC.Assets.shadowColor)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.shadowFadeClamp = uiInfo.uiDC.Assets.shadowColor[3];
- continue;
- }
-
- }
- return qfalse;
-}
-
-void Font_Report( void ) {
- int i;
- Com_Printf("Font Info\n");
- Com_Printf("=========\n");
- for ( i = 32; i < 96; i++) {
- Com_Printf("Glyph handle %i: %i\n", i, uiInfo.uiDC.Assets.textFont.glyphs[i].glyph);
- }
-}
-
-void UI_Report( void ) {
- String_Report();
- //Font_Report();
-
-}
-
-void UI_ParseMenu(const char *menuFile) {
- int handle;
- pc_token_t token;
-
- Com_Printf("Parsing menu file:%s\n", menuFile);
-
- handle = trap_PC_LoadSource(menuFile);
- if (!handle) {
- return;
- }
-
- while ( 1 ) {
- memset(&token, 0, sizeof(pc_token_t));
- if (!trap_PC_ReadToken( handle, &token )) {
- break;
- }
-
- //if ( Q_stricmp( token, "{" ) ) {
- // Com_Printf( "Missing { in menu file\n" );
- // break;
- //}
-
- //if ( menuCount == MAX_MENUS ) {
- // Com_Printf( "Too many menus!\n" );
- // break;
- //}
-
- if ( token.string[0] == '}' ) {
- break;
- }
-
- if (Q_stricmp(token.string, "assetGlobalDef") == 0) {
- if (Asset_Parse(handle)) {
- continue;
- } else {
- break;
- }
- }
-
- if (Q_stricmp(token.string, "menudef") == 0) {
- // start a new menu
- Menu_New(handle);
- }
- }
- trap_PC_FreeSource(handle);
-}
-
-qboolean Load_Menu(int handle) {
- pc_token_t token;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (token.string[0] != '{') {
- return qfalse;
- }
-
- while ( 1 ) {
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
-
- if ( token.string[0] == 0 ) {
- return qfalse;
- }
-
- if ( token.string[0] == '}' ) {
- return qtrue;
- }
-
- UI_ParseMenu(token.string);
- }
- return qfalse;
-}
-
-void UI_LoadMenus(const char *menuFile, qboolean reset) {
- pc_token_t token;
- int handle;
- int start;
-
- start = trap_Milliseconds();
-
- handle = trap_PC_LoadSource( menuFile );
- if (!handle) {
- trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );
- handle = trap_PC_LoadSource( "ui/menus.txt" );
- if (!handle) {
- trap_Error( va( S_COLOR_RED "default menu file not found: ui/menus.txt, unable to continue!\n") );
- }
- }
-
- ui_new.integer = 1;
-
- if (reset) {
- Menu_Reset();
- }
-
- while ( 1 ) {
- if (!trap_PC_ReadToken(handle, &token))
- break;
- if( token.string[0] == 0 || token.string[0] == '}') {
- break;
- }
-
- if ( token.string[0] == '}' ) {
- break;
- }
-
- if (Q_stricmp(token.string, "loadmenu") == 0) {
- if (Load_Menu(handle)) {
- continue;
- } else {
- break;
- }
- }
- }
-
- Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start);
-
- trap_PC_FreeSource( handle );
-}
-
-void UI_Load(void) {
- char lastName[1024];
- menuDef_t *menu = Menu_GetFocused();
- char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
- if (menu && menu->window.name) {
- strcpy(lastName, menu->window.name);
- }
- if (menuSet == NULL || menuSet[0] == '\0') {
- menuSet = "ui/menus.txt";
- }
-
- String_Init();
-
-#ifdef PRE_RELEASE_TADEMO
- UI_ParseGameInfo("demogameinfo.txt");
-#else
- UI_ParseGameInfo("gameinfo.txt");
- UI_LoadArenas();
-#endif
-
- UI_LoadMenus(menuSet, qtrue);
- Menus_CloseAll();
- Menus_ActivateByName(lastName);
-
-}
-
-static const char *handicapValues[] = {"None","95","90","85","80","75","70","65","60","55","50","45","40","35","30","25","20","15","10","5",NULL};
-#ifndef MISSIONPACK
-static int numHandicaps = sizeof(handicapValues) / sizeof(const char*);
-#endif
-
-static void UI_DrawHandicap(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i, h;
-
- h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
- i = 20 - h / 5;
-
- Text_Paint(rect->x, rect->y, scale, color, handicapValues[i], 0, 0, textStyle);
-}
-
-static void UI_DrawClanName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_teamName"), 0, 0, textStyle);
-}
-
-
-static void UI_SetCapFragLimits(qboolean uiVars) {
- int cap = 5;
- int frag = 10;
- if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_OBELISK) {
- cap = 4;
- } else if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_HARVESTER) {
- cap = 15;
- }
- if (uiVars) {
- trap_Cvar_Set("ui_captureLimit", va("%d", cap));
- trap_Cvar_Set("ui_fragLimit", va("%d", frag));
- } else {
- trap_Cvar_Set("capturelimit", va("%d", cap));
- trap_Cvar_Set("fraglimit", va("%d", frag));
- }
-}
-// ui_gameType assumes gametype 0 is -1 ALL and will not show
-static void UI_DrawGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_gameType.integer].gameType, 0, 0, textStyle);
-}
-
-static void UI_DrawNetGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (ui_netGameType.integer < 0 || ui_netGameType.integer > uiInfo.numGameTypes) {
- trap_Cvar_Set("ui_netGameType", "0");
- trap_Cvar_Set("ui_actualNetGameType", "0");
- }
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_netGameType.integer].gameType , 0, 0, textStyle);
-}
-
-static void UI_DrawJoinGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (ui_joinGameType.integer < 0 || ui_joinGameType.integer > uiInfo.numJoinGameTypes) {
- trap_Cvar_Set("ui_joinGameType", "0");
- }
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.joinGameTypes[ui_joinGameType.integer].gameType , 0, 0, textStyle);
-}
-
-
-
-static int UI_TeamIndexFromName(const char *name) {
- int i;
-
- if (name && *name) {
- for (i = 0; i < uiInfo.teamCount; i++) {
- if (Q_stricmp(name, uiInfo.teamList[i].teamName) == 0) {
- return i;
- }
- }
- }
-
- return 0;
-
-}
-
-static void UI_DrawClanLogo(rectDef_t *rect, float scale, vec4_t color) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (i >= 0 && i < uiInfo.teamCount) {
- trap_R_SetColor( color );
-
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
- trap_R_SetColor(NULL);
- }
-}
-
-static void UI_DrawClanCinematic(rectDef_t *rect, float scale, vec4_t color) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (i >= 0 && i < uiInfo.teamCount) {
-
- if (uiInfo.teamList[i].cinematic >= -2) {
- if (uiInfo.teamList[i].cinematic == -1) {
- uiInfo.teamList[i].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.teamList[i].imageName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- }
- if (uiInfo.teamList[i].cinematic >= 0) {
- trap_CIN_RunCinematic(uiInfo.teamList[i].cinematic);
- trap_CIN_SetExtents(uiInfo.teamList[i].cinematic, rect->x, rect->y, rect->w, rect->h);
- trap_CIN_DrawCinematic(uiInfo.teamList[i].cinematic);
- } else {
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal);
- trap_R_SetColor(NULL);
- uiInfo.teamList[i].cinematic = -2;
- }
- } else {
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
- trap_R_SetColor(NULL);
- }
- }
-
-}
-
-static void UI_DrawPreviewCinematic(rectDef_t *rect, float scale, vec4_t color) {
- if (uiInfo.previewMovie > -2) {
- uiInfo.previewMovie = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.movieList[uiInfo.movieIndex]), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- if (uiInfo.previewMovie >= 0) {
- trap_CIN_RunCinematic(uiInfo.previewMovie);
- trap_CIN_SetExtents(uiInfo.previewMovie, rect->x, rect->y, rect->w, rect->h);
- trap_CIN_DrawCinematic(uiInfo.previewMovie);
- } else {
- uiInfo.previewMovie = -2;
- }
- }
-
-}
-
-
-
-static void UI_DrawSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i;
- i = trap_Cvar_VariableValue( "g_spSkill" );
- if (i < 1 || i > numSkillLevels) {
- i = 1;
- }
- Text_Paint(rect->x, rect->y, scale, color, skillLevels[i-1],0, 0, textStyle);
-}
-
-
-static void UI_DrawTeamName(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int textStyle) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
- if (i >= 0 && i < uiInfo.teamCount) {
- Text_Paint(rect->x, rect->y, scale, color, va("%s: %s", (blue) ? "Blue" : "Red", uiInfo.teamList[i].teamName),0, 0, textStyle);
- }
-}
-
-static void UI_DrawTeamMember(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int num, int textStyle) {
- // 0 - None
- // 1 - Human
- // 2..NumCharacters - Bot
- int value = trap_Cvar_VariableValue(va(blue ? "ui_blueteam%i" : "ui_redteam%i", num));
- const char *text;
- if (value <= 0) {
- text = "Closed";
- } else if (value == 1) {
- text = "Human";
- } else {
- value -= 2;
-
- if (ui_actualNetGameType.integer >= GT_TEAM) {
- if (value >= uiInfo.characterCount) {
- value = 0;
- }
- text = uiInfo.characterList[value].name;
- } else {
- if (value >= UI_GetNumBots()) {
- value = 0;
- }
- text = UI_GetBotNameByNumber(value);
- }
- }
- Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
-}
-
-static void UI_DrawEffects(rectDef_t *rect, float scale, vec4_t color) {
- UI_DrawHandlePic( rect->x, rect->y - 14, 128, 8, uiInfo.uiDC.Assets.fxBasePic );
- UI_DrawHandlePic( rect->x + uiInfo.effectsColor * 16 + 8, rect->y - 16, 16, 12, uiInfo.uiDC.Assets.fxPic[uiInfo.effectsColor] );
-}
-
-static void UI_DrawMapPreview(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
- int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
- if (map < 0 || map > uiInfo.mapCount) {
- if (net) {
- ui_currentNetMap.integer = 0;
- trap_Cvar_Set("ui_currentNetMap", "0");
- } else {
- ui_currentMap.integer = 0;
- trap_Cvar_Set("ui_currentMap", "0");
- }
- map = 0;
- }
-
- if (uiInfo.mapList[map].levelShot == -1) {
- uiInfo.mapList[map].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[map].imageName);
- }
-
- if (uiInfo.mapList[map].levelShot > 0) {
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.mapList[map].levelShot);
- } else {
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("menu/art/unknownmap"));
- }
-}
-
-
-static void UI_DrawMapTimeToBeat(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int minutes, seconds, time;
- if (ui_currentMap.integer < 0 || ui_currentMap.integer > uiInfo.mapCount) {
- ui_currentMap.integer = 0;
- trap_Cvar_Set("ui_currentMap", "0");
- }
-
- time = uiInfo.mapList[ui_currentMap.integer].timeToBeat[uiInfo.gameTypes[ui_gameType.integer].gtEnum];
-
- minutes = time / 60;
- seconds = time % 60;
-
- Text_Paint(rect->x, rect->y, scale, color, va("%02i:%02i", minutes, seconds), 0, 0, textStyle);
-}
-
-
-
-static void UI_DrawMapCinematic(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
-
- int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
- if (map < 0 || map > uiInfo.mapCount) {
- if (net) {
- ui_currentNetMap.integer = 0;
- trap_Cvar_Set("ui_currentNetMap", "0");
- } else {
- ui_currentMap.integer = 0;
- trap_Cvar_Set("ui_currentMap", "0");
- }
- map = 0;
- }
-
- if (uiInfo.mapList[map].cinematic >= -1) {
- if (uiInfo.mapList[map].cinematic == -1) {
- uiInfo.mapList[map].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[map].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- }
- if (uiInfo.mapList[map].cinematic >= 0) {
- trap_CIN_RunCinematic(uiInfo.mapList[map].cinematic);
- trap_CIN_SetExtents(uiInfo.mapList[map].cinematic, rect->x, rect->y, rect->w, rect->h);
- trap_CIN_DrawCinematic(uiInfo.mapList[map].cinematic);
- } else {
- uiInfo.mapList[map].cinematic = -2;
- }
- } else {
- UI_DrawMapPreview(rect, scale, color, net);
- }
-}
-
-
-
-static qboolean updateModel = qtrue;
-static qboolean q3Model = qfalse;
-
-static void UI_DrawPlayerModel(rectDef_t *rect) {
- static playerInfo_t info;
- char model[MAX_QPATH];
- char team[256];
- char head[256];
- vec3_t viewangles;
- vec3_t moveangles;
-
- if (trap_Cvar_VariableValue("ui_Q3Model")) {
- strcpy(model, UI_Cvar_VariableString("model"));
- strcpy(head, UI_Cvar_VariableString("headmodel"));
- if (!q3Model) {
- q3Model = qtrue;
- updateModel = qtrue;
- }
- team[0] = '\0';
- } else {
-
- strcpy(team, UI_Cvar_VariableString("ui_teamName"));
- strcpy(model, UI_Cvar_VariableString("team_model"));
- strcpy(head, UI_Cvar_VariableString("team_headmodel"));
- if (q3Model) {
- q3Model = qfalse;
- updateModel = qtrue;
- }
- }
- if (updateModel) {
- memset( &info, 0, sizeof(playerInfo_t) );
- viewangles[YAW] = 180 - 10;
- viewangles[PITCH] = 0;
- viewangles[ROLL] = 0;
- VectorClear( moveangles );
- UI_PlayerInfo_SetModel( &info, model, head, team);
- UI_PlayerInfo_SetInfo( &info, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
-// UI_RegisterClientModelname( &info, model, head, team);
- updateModel = qfalse;
- }
-
- UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info, uiInfo.uiDC.realTime / 2);
-
-}
-
-static void UI_DrawNetSource(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (ui_netSource.integer < 0 || ui_netSource.integer > numNetSources) {
- ui_netSource.integer = 0;
- }
- Text_Paint(rect->x, rect->y, scale, color, va("Source: %s", netSources[ui_netSource.integer]), 0, 0, textStyle);
-}
-
-static void UI_DrawNetMapPreview(rectDef_t *rect, float scale, vec4_t color) {
-
- if (uiInfo.serverStatus.currentServerPreview > 0) {
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.serverStatus.currentServerPreview);
- } else {
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("menu/art/unknownmap"));
- }
-}
-
-static void UI_DrawNetMapCinematic(rectDef_t *rect, float scale, vec4_t color) {
- if (ui_currentNetMap.integer < 0 || ui_currentNetMap.integer > uiInfo.mapCount) {
- ui_currentNetMap.integer = 0;
- trap_Cvar_Set("ui_currentNetMap", "0");
- }
-
- if (uiInfo.serverStatus.currentServerCinematic >= 0) {
- trap_CIN_RunCinematic(uiInfo.serverStatus.currentServerCinematic);
- trap_CIN_SetExtents(uiInfo.serverStatus.currentServerCinematic, rect->x, rect->y, rect->w, rect->h);
- trap_CIN_DrawCinematic(uiInfo.serverStatus.currentServerCinematic);
- } else {
- UI_DrawNetMapPreview(rect, scale, color);
- }
-}
-
-
-
-static void UI_DrawNetFilter(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
- ui_serverFilterType.integer = 0;
- }
- Text_Paint(rect->x, rect->y, scale, color, va("Filter: %s", serverFilters[ui_serverFilterType.integer].description), 0, 0, textStyle);
-}
-
-
-static void UI_DrawTier(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i;
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= uiInfo.tierCount) {
- i = 0;
- }
- Text_Paint(rect->x, rect->y, scale, color, va("Tier: %s", uiInfo.tierList[i].tierName),0, 0, textStyle);
-}
-
-static void UI_DrawTierMap(rectDef_t *rect, int index) {
- int i;
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= uiInfo.tierCount) {
- i = 0;
- }
-
- if (uiInfo.tierList[i].mapHandles[index] == -1) {
- uiInfo.tierList[i].mapHandles[index] = trap_R_RegisterShaderNoMip(va("levelshots/%s", uiInfo.tierList[i].maps[index]));
- }
-
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.tierList[i].mapHandles[index]);
-}
-
-static const char *UI_EnglishMapName(const char *map) {
- int i;
- for (i = 0; i < uiInfo.mapCount; i++) {
- if (Q_stricmp(map, uiInfo.mapList[i].mapLoadName) == 0) {
- return uiInfo.mapList[i].mapName;
- }
- }
- return "";
-}
-
-static void UI_DrawTierMapName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i, j;
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= uiInfo.tierCount) {
- i = 0;
- }
- j = trap_Cvar_VariableValue("ui_currentMap");
- if (j < 0 || j > MAPS_PER_TIER) {
- j = 0;
- }
-
- Text_Paint(rect->x, rect->y, scale, color, UI_EnglishMapName(uiInfo.tierList[i].maps[j]), 0, 0, textStyle);
-}
-
-static void UI_DrawTierGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i, j;
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= uiInfo.tierCount) {
- i = 0;
- }
- j = trap_Cvar_VariableValue("ui_currentMap");
- if (j < 0 || j > MAPS_PER_TIER) {
- j = 0;
- }
-
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[uiInfo.tierList[i].gameTypes[j]].gameType , 0, 0, textStyle);
-}
-
-
-#ifndef MISSIONPACK
-static const char *UI_OpponentLeaderName(void) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- return uiInfo.teamList[i].teamMembers[0];
-}
-#endif
-
-static const char *UI_AIFromName(const char *name) {
- int j;
- for (j = 0; j < uiInfo.aliasCount; j++) {
- if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
- return uiInfo.aliasList[j].ai;
- }
- }
- return "James";
-}
-
-#ifndef MISSIONPACK
-static const int UI_AIIndex(const char *name) {
- int j;
- for (j = 0; j < uiInfo.characterCount; j++) {
- if (Q_stricmp(name, uiInfo.characterList[j].name) == 0) {
- return j;
- }
- }
- return 0;
-}
-#endif
-
-#ifndef MISSIONPACK
-static const int UI_AIIndexFromName(const char *name) {
- int j;
- for (j = 0; j < uiInfo.aliasCount; j++) {
- if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
- return UI_AIIndex(uiInfo.aliasList[j].ai);
- }
- }
- return 0;
-}
-#endif
-
-
-#ifndef MISSIONPACK
-static const char *UI_OpponentLeaderHead(void) {
- const char *leader = UI_OpponentLeaderName();
- return UI_AIFromName(leader);
-}
-#endif
-
-#ifndef MISSIONPACK
-static const char *UI_OpponentLeaderModel(void) {
- int i;
- const char *head = UI_OpponentLeaderHead();
- for (i = 0; i < uiInfo.characterCount; i++) {
- if (Q_stricmp(head, uiInfo.characterList[i].name) == 0) {
- return uiInfo.characterList[i].base;
- }
- }
- return "James";
-}
-#endif
-
-
-static qboolean updateOpponentModel = qtrue;
-static void UI_DrawOpponent(rectDef_t *rect) {
- static playerInfo_t info2;
- char model[MAX_QPATH];
- char headmodel[MAX_QPATH];
- char team[256];
- vec3_t viewangles;
- vec3_t moveangles;
-
- if (updateOpponentModel) {
-
- strcpy(model, UI_Cvar_VariableString("ui_opponentModel"));
- strcpy(headmodel, UI_Cvar_VariableString("ui_opponentModel"));
- team[0] = '\0';
-
- memset( &info2, 0, sizeof(playerInfo_t) );
- viewangles[YAW] = 180 - 10;
- viewangles[PITCH] = 0;
- viewangles[ROLL] = 0;
- VectorClear( moveangles );
- UI_PlayerInfo_SetModel( &info2, model, headmodel, "");
- UI_PlayerInfo_SetInfo( &info2, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
- UI_RegisterClientModelname( &info2, model, headmodel, team);
- updateOpponentModel = qfalse;
- }
-
- UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info2, uiInfo.uiDC.realTime / 2);
-
-}
-
-static void UI_NextOpponent( void ) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- i++;
- if (i >= uiInfo.teamCount) {
- i = 0;
- }
- if (i == j) {
- i++;
- if ( i >= uiInfo.teamCount) {
- i = 0;
- }
- }
- trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
-}
-
-static void UI_PriorOpponent( void ) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- i--;
- if (i < 0) {
- i = uiInfo.teamCount - 1;
- }
- if (i == j) {
- i--;
- if ( i < 0) {
- i = uiInfo.teamCount - 1;
- }
- }
- trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
-}
-
-static void UI_DrawPlayerLogo(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
-
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
- trap_R_SetColor( NULL );
-}
-
-static void UI_DrawPlayerLogoMetal(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
- trap_R_SetColor( NULL );
-}
-
-static void UI_DrawPlayerLogoName(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
- trap_R_SetColor( NULL );
-}
-
-static void UI_DrawOpponentLogo(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
- trap_R_SetColor( NULL );
-}
-
-static void UI_DrawOpponentLogoMetal(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
- trap_R_SetColor( NULL );
-}
-
-static void UI_DrawOpponentLogoName(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
- trap_R_SetColor( NULL );
-}
-
-static void UI_DrawAllMapsSelection(rectDef_t *rect, float scale, vec4_t color, int textStyle, qboolean net) {
- int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
- if (map >= 0 && map < uiInfo.mapCount) {
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.mapList[map].mapName, 0, 0, textStyle);
- }
-}
-
-static void UI_DrawOpponentName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_opponentName"), 0, 0, textStyle);
-}
-
-
-static int UI_OwnerDrawWidth(int ownerDraw, float scale) {
- int i, h, value;
- const char *text;
- const char *s = NULL;
-
- switch (ownerDraw) {
- case UI_HANDICAP:
- h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
- i = 20 - h / 5;
- s = handicapValues[i];
- break;
- case UI_CLANNAME:
- s = UI_Cvar_VariableString("ui_teamName");
- break;
- case UI_GAMETYPE:
- s = uiInfo.gameTypes[ui_gameType.integer].gameType;
- break;
- case UI_SKILL:
- i = trap_Cvar_VariableValue( "g_spSkill" );
- if (i < 1 || i > numSkillLevels) {
- i = 1;
- }
- s = skillLevels[i-1];
- break;
- case UI_BLUETEAMNAME:
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_blueTeam"));
- if (i >= 0 && i < uiInfo.teamCount) {
- s = va("%s: %s", "Blue", uiInfo.teamList[i].teamName);
- }
- break;
- case UI_REDTEAMNAME:
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_redTeam"));
- if (i >= 0 && i < uiInfo.teamCount) {
- s = va("%s: %s", "Red", uiInfo.teamList[i].teamName);
- }
- break;
- case UI_BLUETEAM1:
- case UI_BLUETEAM2:
- case UI_BLUETEAM3:
- case UI_BLUETEAM4:
- case UI_BLUETEAM5:
- value = trap_Cvar_VariableValue(va("ui_blueteam%i", ownerDraw-UI_BLUETEAM1 + 1));
- if (value <= 0) {
- text = "Closed";
- } else if (value == 1) {
- text = "Human";
- } else {
- value -= 2;
- if (value >= uiInfo.aliasCount) {
- value = 0;
- }
- text = uiInfo.aliasList[value].name;
- }
- s = va("%i. %s", ownerDraw-UI_BLUETEAM1 + 1, text);
- break;
- case UI_REDTEAM1:
- case UI_REDTEAM2:
- case UI_REDTEAM3:
- case UI_REDTEAM4:
- case UI_REDTEAM5:
- value = trap_Cvar_VariableValue(va("ui_redteam%i", ownerDraw-UI_REDTEAM1 + 1));
- if (value <= 0) {
- text = "Closed";
- } else if (value == 1) {
- text = "Human";
- } else {
- value -= 2;
- if (value >= uiInfo.aliasCount) {
- value = 0;
- }
- text = uiInfo.aliasList[value].name;
- }
- s = va("%i. %s", ownerDraw-UI_REDTEAM1 + 1, text);
- break;
- case UI_NETSOURCE:
- if (ui_netSource.integer < 0 || ui_netSource.integer > uiInfo.numJoinGameTypes) {
- ui_netSource.integer = 0;
- }
- s = va("Source: %s", netSources[ui_netSource.integer]);
- break;
- case UI_NETFILTER:
- if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
- ui_serverFilterType.integer = 0;
- }
- s = va("Filter: %s", serverFilters[ui_serverFilterType.integer].description );
- break;
- case UI_TIER:
- break;
- case UI_TIER_MAPNAME:
- break;
- case UI_TIER_GAMETYPE:
- break;
- case UI_ALLMAPS_SELECTION:
- break;
- case UI_OPPONENT_NAME:
- break;
- case UI_KEYBINDSTATUS:
- if (Display_KeyBindPending()) {
- s = "Waiting for new key... Press ESCAPE to cancel";
- } else {
- s = "Press ENTER or CLICK to change, Press BACKSPACE to clear";
- }
- break;
- case UI_SERVERREFRESHDATE:
- s = UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer));
- break;
- default:
- break;
- }
-
- if (s) {
- return Text_Width(s, scale, 0);
- }
- return 0;
-}
-
-static void UI_DrawBotName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int value = uiInfo.botIndex;
- int game = trap_Cvar_VariableValue("g_gametype");
- const char *text = "";
- if (game >= GT_TEAM) {
- if (value >= uiInfo.characterCount) {
- value = 0;
- }
- text = uiInfo.characterList[value].name;
- } else {
- if (value >= UI_GetNumBots()) {
- value = 0;
- }
- text = UI_GetBotNameByNumber(value);
- }
- Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
-}
-
-static void UI_DrawBotSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (uiInfo.skillIndex >= 0 && uiInfo.skillIndex < numSkillLevels) {
- Text_Paint(rect->x, rect->y, scale, color, skillLevels[uiInfo.skillIndex], 0, 0, textStyle);
- }
-}
-
-static void UI_DrawRedBlue(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- Text_Paint(rect->x, rect->y, scale, color, (uiInfo.redBlue == 0) ? "Red" : "Blue", 0, 0, textStyle);
-}
-
-static void UI_DrawCrosshair(rectDef_t *rect, float scale, vec4_t color) {
- trap_R_SetColor( color );
- if (uiInfo.currentCrosshair < 0 || uiInfo.currentCrosshair >= NUM_CROSSHAIRS) {
- uiInfo.currentCrosshair = 0;
- }
- UI_DrawHandlePic( rect->x, rect->y - rect->h, rect->w, rect->h, uiInfo.uiDC.Assets.crosshairShader[uiInfo.currentCrosshair]);
- trap_R_SetColor( NULL );
-}
-
-/*
-===============
-UI_BuildPlayerList
-===============
-*/
-static void UI_BuildPlayerList( void ) {
- uiClientState_t cs;
- int n, count, team, team2, playerTeamNumber;
- char info[MAX_INFO_STRING];
-
- trap_GetClientState( &cs );
- trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );
- uiInfo.playerNumber = cs.clientNum;
- uiInfo.teamLeader = atoi(Info_ValueForKey(info, "tl"));
- team = atoi(Info_ValueForKey(info, "t"));
- trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
- count = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
- uiInfo.playerCount = 0;
- uiInfo.myTeamCount = 0;
- playerTeamNumber = 0;
- for( n = 0; n < count; n++ ) {
- trap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING );
-
- if (info[0]) {
- Q_strncpyz( uiInfo.playerNames[uiInfo.playerCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
- Q_CleanStr( uiInfo.playerNames[uiInfo.playerCount] );
- uiInfo.playerCount++;
- team2 = atoi(Info_ValueForKey(info, "t"));
- if (team2 == team) {
- Q_strncpyz( uiInfo.teamNames[uiInfo.myTeamCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
- Q_CleanStr( uiInfo.teamNames[uiInfo.myTeamCount] );
- uiInfo.teamClientNums[uiInfo.myTeamCount] = n;
- if (uiInfo.playerNumber == n) {
- playerTeamNumber = uiInfo.myTeamCount;
- }
- uiInfo.myTeamCount++;
- }
- }
- }
-
- if (!uiInfo.teamLeader) {
- trap_Cvar_Set("cg_selectedPlayer", va("%d", playerTeamNumber));
- }
-
- n = trap_Cvar_VariableValue("cg_selectedPlayer");
- if (n < 0 || n > uiInfo.myTeamCount) {
- n = 0;
- }
- if (n < uiInfo.myTeamCount) {
- trap_Cvar_Set("cg_selectedPlayerName", uiInfo.teamNames[n]);
- }
-}
-
-
-static void UI_DrawSelectedPlayer(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
- uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
- UI_BuildPlayerList();
- }
- Text_Paint(rect->x, rect->y, scale, color, (uiInfo.teamLeader) ? UI_Cvar_VariableString("cg_selectedPlayerName") : UI_Cvar_VariableString("name") , 0, 0, textStyle);
-}
-
-static void UI_DrawServerRefreshDate(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (uiInfo.serverStatus.refreshActive) {
- vec4_t lowLight, newColor;
- lowLight[0] = 0.8 * color[0];
- lowLight[1] = 0.8 * color[1];
- lowLight[2] = 0.8 * color[2];
- lowLight[3] = 0.8 * color[3];
- LerpColor(color,lowLight,newColor,0.5+0.5*sin(uiInfo.uiDC.realTime / PULSE_DIVISOR));
- Text_Paint(rect->x, rect->y, scale, newColor, va("Getting info for %d servers (ESC to cancel)", trap_LAN_GetServerCount(ui_netSource.integer)), 0, 0, textStyle);
- } else {
- char buff[64];
- Q_strncpyz(buff, UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer)), 64);
- Text_Paint(rect->x, rect->y, scale, color, va("Refresh Time: %s", buff), 0, 0, textStyle);
- }
-}
-
-static void UI_DrawServerMOTD(rectDef_t *rect, float scale, vec4_t color) {
- if (uiInfo.serverStatus.motdLen) {
- float maxX;
-
- if (uiInfo.serverStatus.motdWidth == -1) {
- uiInfo.serverStatus.motdWidth = 0;
- uiInfo.serverStatus.motdPaintX = rect->x + 1;
- uiInfo.serverStatus.motdPaintX2 = -1;
- }
-
- if (uiInfo.serverStatus.motdOffset > uiInfo.serverStatus.motdLen) {
- uiInfo.serverStatus.motdOffset = 0;
- uiInfo.serverStatus.motdPaintX = rect->x + 1;
- uiInfo.serverStatus.motdPaintX2 = -1;
- }
-
- if (uiInfo.uiDC.realTime > uiInfo.serverStatus.motdTime) {
- uiInfo.serverStatus.motdTime = uiInfo.uiDC.realTime + 10;
- if (uiInfo.serverStatus.motdPaintX <= rect->x + 2) {
- if (uiInfo.serverStatus.motdOffset < uiInfo.serverStatus.motdLen) {
- uiInfo.serverStatus.motdPaintX += Text_Width(&uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], scale, 1) - 1;
- uiInfo.serverStatus.motdOffset++;
- } else {
- uiInfo.serverStatus.motdOffset = 0;
- if (uiInfo.serverStatus.motdPaintX2 >= 0) {
- uiInfo.serverStatus.motdPaintX = uiInfo.serverStatus.motdPaintX2;
- } else {
- uiInfo.serverStatus.motdPaintX = rect->x + rect->w - 2;
- }
- uiInfo.serverStatus.motdPaintX2 = -1;
- }
- } else {
- //serverStatus.motdPaintX--;
- uiInfo.serverStatus.motdPaintX -= 2;
- if (uiInfo.serverStatus.motdPaintX2 >= 0) {
- //serverStatus.motdPaintX2--;
- uiInfo.serverStatus.motdPaintX2 -= 2;
- }
- }
- }
-
- maxX = rect->x + rect->w - 2;
- Text_Paint_Limit(&maxX, uiInfo.serverStatus.motdPaintX, rect->y + rect->h - 3, scale, color, &uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], 0, 0);
- if (uiInfo.serverStatus.motdPaintX2 >= 0) {
- float maxX2 = rect->x + rect->w - 2;
- Text_Paint_Limit(&maxX2, uiInfo.serverStatus.motdPaintX2, rect->y + rect->h - 3, scale, color, uiInfo.serverStatus.motd, 0, uiInfo.serverStatus.motdOffset);
- }
- if (uiInfo.serverStatus.motdOffset && maxX > 0) {
- // if we have an offset ( we are skipping the first part of the string ) and we fit the string
- if (uiInfo.serverStatus.motdPaintX2 == -1) {
- uiInfo.serverStatus.motdPaintX2 = rect->x + rect->w - 2;
- }
- } else {
- uiInfo.serverStatus.motdPaintX2 = -1;
- }
-
- }
-}
-
-static void UI_DrawKeyBindStatus(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
-// int ofs = 0; TTimo: unused
- if (Display_KeyBindPending()) {
- Text_Paint(rect->x, rect->y, scale, color, "Waiting for new key... Press ESCAPE to cancel", 0, 0, textStyle);
- } else {
- Text_Paint(rect->x, rect->y, scale, color, "Press ENTER or CLICK to change, Press BACKSPACE to clear", 0, 0, textStyle);
- }
-}
-
-static void UI_DrawGLInfo(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- char * eptr;
- char buff[1024];
- const char *lines[64];
- int y, numLines, i;
-
- Text_Paint(rect->x + 2, rect->y, scale, color, va("VENDOR: %s", uiInfo.uiDC.glconfig.vendor_string), 0, 30, textStyle);
- Text_Paint(rect->x + 2, rect->y + 15, scale, color, va("VERSION: %s: %s", uiInfo.uiDC.glconfig.version_string,uiInfo.uiDC.glconfig.renderer_string), 0, 30, textStyle);
- Text_Paint(rect->x + 2, rect->y + 30, scale, color, va ("PIXELFORMAT: color(%d-bits) Z(%d-bits) stencil(%d-bits)", uiInfo.uiDC.glconfig.colorBits, uiInfo.uiDC.glconfig.depthBits, uiInfo.uiDC.glconfig.stencilBits), 0, 30, textStyle);
-
- // build null terminated extension strings
- // TTimo: https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=399
- // in TA this was not directly crashing, but displaying a nasty broken shader right in the middle
- // brought down the string size to 1024, there's not much that can be shown on the screen anyway
- Q_strncpyz(buff, uiInfo.uiDC.glconfig.extensions_string, 1024);
- eptr = buff;
- y = rect->y + 45;
- numLines = 0;
- while ( y < rect->y + rect->h && *eptr )
- {
- while ( *eptr && *eptr == ' ' )
- *eptr++ = '\0';
-
- // track start of valid string
- if (*eptr && *eptr != ' ') {
- lines[numLines++] = eptr;
- }
-
- while ( *eptr && *eptr != ' ' )
- eptr++;
- }
-
- i = 0;
- while (i < numLines) {
- Text_Paint(rect->x + 2, y, scale, color, lines[i++], 0, 20, textStyle);
- if (i < numLines) {
- Text_Paint(rect->x + rect->w / 2, y, scale, color, lines[i++], 0, 20, textStyle);
- }
- y += 10;
- if (y > rect->y + rect->h - 11) {
- break;
- }
- }
-
-
-}
-
-// FIXME: table drive
-//
-static void UI_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- rectDef_t rect;
-
- rect.x = x + text_x;
- rect.y = y + text_y;
- rect.w = w;
- rect.h = h;
-
- switch (ownerDraw) {
- case UI_HANDICAP:
- UI_DrawHandicap(&rect, scale, color, textStyle);
- break;
- case UI_EFFECTS:
- UI_DrawEffects(&rect, scale, color);
- break;
- case UI_PLAYERMODEL:
- UI_DrawPlayerModel(&rect);
- break;
- case UI_CLANNAME:
- UI_DrawClanName(&rect, scale, color, textStyle);
- break;
- case UI_CLANLOGO:
- UI_DrawClanLogo(&rect, scale, color);
- break;
- case UI_CLANCINEMATIC:
- UI_DrawClanCinematic(&rect, scale, color);
- break;
- case UI_PREVIEWCINEMATIC:
- UI_DrawPreviewCinematic(&rect, scale, color);
- break;
- case UI_GAMETYPE:
- UI_DrawGameType(&rect, scale, color, textStyle);
- break;
- case UI_NETGAMETYPE:
- UI_DrawNetGameType(&rect, scale, color, textStyle);
- break;
- case UI_JOINGAMETYPE:
- UI_DrawJoinGameType(&rect, scale, color, textStyle);
- break;
- case UI_MAPPREVIEW:
- UI_DrawMapPreview(&rect, scale, color, qtrue);
- break;
- case UI_MAP_TIMETOBEAT:
- UI_DrawMapTimeToBeat(&rect, scale, color, textStyle);
- break;
- case UI_MAPCINEMATIC:
- UI_DrawMapCinematic(&rect, scale, color, qfalse);
- break;
- case UI_STARTMAPCINEMATIC:
- UI_DrawMapCinematic(&rect, scale, color, qtrue);
- break;
- case UI_SKILL:
- UI_DrawSkill(&rect, scale, color, textStyle);
- break;
- case UI_BLUETEAMNAME:
- UI_DrawTeamName(&rect, scale, color, qtrue, textStyle);
- break;
- case UI_REDTEAMNAME:
- UI_DrawTeamName(&rect, scale, color, qfalse, textStyle);
- break;
- case UI_BLUETEAM1:
- case UI_BLUETEAM2:
- case UI_BLUETEAM3:
- case UI_BLUETEAM4:
- case UI_BLUETEAM5:
- UI_DrawTeamMember(&rect, scale, color, qtrue, ownerDraw - UI_BLUETEAM1 + 1, textStyle);
- break;
- case UI_REDTEAM1:
- case UI_REDTEAM2:
- case UI_REDTEAM3:
- case UI_REDTEAM4:
- case UI_REDTEAM5:
- UI_DrawTeamMember(&rect, scale, color, qfalse, ownerDraw - UI_REDTEAM1 + 1, textStyle);
- break;
- case UI_NETSOURCE:
- UI_DrawNetSource(&rect, scale, color, textStyle);
- break;
- case UI_NETMAPPREVIEW:
- UI_DrawNetMapPreview(&rect, scale, color);
- break;
- case UI_NETMAPCINEMATIC:
- UI_DrawNetMapCinematic(&rect, scale, color);
- break;
- case UI_NETFILTER:
- UI_DrawNetFilter(&rect, scale, color, textStyle);
- break;
- case UI_TIER:
- UI_DrawTier(&rect, scale, color, textStyle);
- break;
- case UI_OPPONENTMODEL:
- UI_DrawOpponent(&rect);
- break;
- case UI_TIERMAP1:
- UI_DrawTierMap(&rect, 0);
- break;
- case UI_TIERMAP2:
- UI_DrawTierMap(&rect, 1);
- break;
- case UI_TIERMAP3:
- UI_DrawTierMap(&rect, 2);
- break;
- case UI_PLAYERLOGO:
- UI_DrawPlayerLogo(&rect, color);
- break;
- case UI_PLAYERLOGO_METAL:
- UI_DrawPlayerLogoMetal(&rect, color);
- break;
- case UI_PLAYERLOGO_NAME:
- UI_DrawPlayerLogoName(&rect, color);
- break;
- case UI_OPPONENTLOGO:
- UI_DrawOpponentLogo(&rect, color);
- break;
- case UI_OPPONENTLOGO_METAL:
- UI_DrawOpponentLogoMetal(&rect, color);
- break;
- case UI_OPPONENTLOGO_NAME:
- UI_DrawOpponentLogoName(&rect, color);
- break;
- case UI_TIER_MAPNAME:
- UI_DrawTierMapName(&rect, scale, color, textStyle);
- break;
- case UI_TIER_GAMETYPE:
- UI_DrawTierGameType(&rect, scale, color, textStyle);
- break;
- case UI_ALLMAPS_SELECTION:
- UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qtrue);
- break;
- case UI_MAPS_SELECTION:
- UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qfalse);
- break;
- case UI_OPPONENT_NAME:
- UI_DrawOpponentName(&rect, scale, color, textStyle);
- break;
- case UI_BOTNAME:
- UI_DrawBotName(&rect, scale, color, textStyle);
- break;
- case UI_BOTSKILL:
- UI_DrawBotSkill(&rect, scale, color, textStyle);
- break;
- case UI_REDBLUE:
- UI_DrawRedBlue(&rect, scale, color, textStyle);
- break;
- case UI_CROSSHAIR:
- UI_DrawCrosshair(&rect, scale, color);
- break;
- case UI_SELECTEDPLAYER:
- UI_DrawSelectedPlayer(&rect, scale, color, textStyle);
- break;
- case UI_SERVERREFRESHDATE:
- UI_DrawServerRefreshDate(&rect, scale, color, textStyle);
- break;
- case UI_SERVERMOTD:
- UI_DrawServerMOTD(&rect, scale, color);
- break;
- case UI_GLINFO:
- UI_DrawGLInfo(&rect,scale, color, textStyle);
- break;
- case UI_KEYBINDSTATUS:
- UI_DrawKeyBindStatus(&rect,scale, color, textStyle);
- break;
- default:
- break;
- }
-
-}
-
-static qboolean UI_OwnerDrawVisible(int flags) {
- qboolean vis = qtrue;
-
- while (flags) {
-
- if (flags & UI_SHOW_FFA) {
- if (trap_Cvar_VariableValue("g_gametype") != GT_FFA) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_FFA;
- }
-
- if (flags & UI_SHOW_NOTFFA) {
- if (trap_Cvar_VariableValue("g_gametype") == GT_FFA) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_NOTFFA;
- }
-
- if (flags & UI_SHOW_LEADER) {
- // these need to show when this client can give orders to a player or a group
- if (!uiInfo.teamLeader) {
- vis = qfalse;
- } else {
- // if showing yourself
- if (ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber) {
- vis = qfalse;
- }
- }
- flags &= ~UI_SHOW_LEADER;
- }
- if (flags & UI_SHOW_NOTLEADER) {
- // these need to show when this client is assigning their own status or they are NOT the leader
- if (uiInfo.teamLeader) {
- // if not showing yourself
- if (!(ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber)) {
- vis = qfalse;
- }
- // these need to show when this client can give orders to a player or a group
- }
- flags &= ~UI_SHOW_NOTLEADER;
- }
- if (flags & UI_SHOW_FAVORITESERVERS) {
- // this assumes you only put this type of display flag on something showing in the proper context
- if (ui_netSource.integer != AS_FAVORITES) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_FAVORITESERVERS;
- }
- if (flags & UI_SHOW_NOTFAVORITESERVERS) {
- // this assumes you only put this type of display flag on something showing in the proper context
- if (ui_netSource.integer == AS_FAVORITES) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_NOTFAVORITESERVERS;
- }
- if (flags & UI_SHOW_ANYTEAMGAME) {
- if (uiInfo.gameTypes[ui_gameType.integer].gtEnum <= GT_TEAM ) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_ANYTEAMGAME;
- }
- if (flags & UI_SHOW_ANYNONTEAMGAME) {
- if (uiInfo.gameTypes[ui_gameType.integer].gtEnum > GT_TEAM ) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_ANYNONTEAMGAME;
- }
- if (flags & UI_SHOW_NETANYTEAMGAME) {
- if (uiInfo.gameTypes[ui_netGameType.integer].gtEnum <= GT_TEAM ) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_NETANYTEAMGAME;
- }
- if (flags & UI_SHOW_NETANYNONTEAMGAME) {
- if (uiInfo.gameTypes[ui_netGameType.integer].gtEnum > GT_TEAM ) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_NETANYNONTEAMGAME;
- }
- if (flags & UI_SHOW_NEWHIGHSCORE) {
- if (uiInfo.newHighScoreTime < uiInfo.uiDC.realTime) {
- vis = qfalse;
- } else {
- if (uiInfo.soundHighScore) {
- if (trap_Cvar_VariableValue("sv_killserver") == 0) {
- // wait on server to go down before playing sound
- trap_S_StartLocalSound(uiInfo.newHighScoreSound, CHAN_ANNOUNCER);
- uiInfo.soundHighScore = qfalse;
- }
- }
- }
- flags &= ~UI_SHOW_NEWHIGHSCORE;
- }
- if (flags & UI_SHOW_NEWBESTTIME) {
- if (uiInfo.newBestTime < uiInfo.uiDC.realTime) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_NEWBESTTIME;
- }
- if (flags & UI_SHOW_DEMOAVAILABLE) {
- if (!uiInfo.demoAvailable) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_DEMOAVAILABLE;
- } else {
- flags = 0;
- }
- }
- return vis;
-}
-
-static qboolean UI_Handicap_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int h;
- h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
- if (key == K_MOUSE2) {
- h -= 5;
- } else {
- h += 5;
- }
- if (h > 100) {
- h = 5;
- } else if (h < 0) {
- h = 100;
- }
- trap_Cvar_Set( "handicap", va( "%i", h) );
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_Effects_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
-
- if (key == K_MOUSE2) {
- uiInfo.effectsColor--;
- } else {
- uiInfo.effectsColor++;
- }
-
- if( uiInfo.effectsColor > 6 ) {
- uiInfo.effectsColor = 0;
- } else if (uiInfo.effectsColor < 0) {
- uiInfo.effectsColor = 6;
- }
-
- trap_Cvar_SetValue( "color1", uitogamecode[uiInfo.effectsColor] );
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_ClanName_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (uiInfo.teamList[i].cinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
- uiInfo.teamList[i].cinematic = -1;
- }
- if (key == K_MOUSE2) {
- i--;
- } else {
- i++;
- }
- if (i >= uiInfo.teamCount) {
- i = 0;
- } else if (i < 0) {
- i = uiInfo.teamCount - 1;
- }
- trap_Cvar_Set( "ui_teamName", uiInfo.teamList[i].teamName);
- UI_HeadCountByTeam();
- UI_FeederSelection(FEEDER_HEADS, 0);
- updateModel = qtrue;
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_GameType_HandleKey(int flags, float *special, int key, qboolean resetMap) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int oldCount = UI_MapCountByGameType(qtrue);
-
- // hard coded mess here
- if (key == K_MOUSE2) {
- ui_gameType.integer--;
- if (ui_gameType.integer == 2) {
- ui_gameType.integer = 1;
- } else if (ui_gameType.integer < 2) {
- ui_gameType.integer = uiInfo.numGameTypes - 1;
- }
- } else {
- ui_gameType.integer++;
- if (ui_gameType.integer >= uiInfo.numGameTypes) {
- ui_gameType.integer = 1;
- } else if (ui_gameType.integer == 2) {
- ui_gameType.integer = 3;
- }
- }
-
- if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_TOURNAMENT) {
- trap_Cvar_Set("ui_Q3Model", "1");
- } else {
- trap_Cvar_Set("ui_Q3Model", "0");
- }
-
- trap_Cvar_Set("ui_gameType", va("%d", ui_gameType.integer));
- UI_SetCapFragLimits(qtrue);
- UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
- if (resetMap && oldCount != UI_MapCountByGameType(qtrue)) {
- trap_Cvar_Set( "ui_currentMap", "0");
- Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, NULL);
- }
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_NetGameType_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
-
- if (key == K_MOUSE2) {
- ui_netGameType.integer--;
- } else {
- ui_netGameType.integer++;
- }
-
- if (ui_netGameType.integer < 0) {
- ui_netGameType.integer = uiInfo.numGameTypes - 1;
- } else if (ui_netGameType.integer >= uiInfo.numGameTypes) {
- ui_netGameType.integer = 0;
- }
-
- trap_Cvar_Set( "ui_netGameType", va("%d", ui_netGameType.integer));
- trap_Cvar_Set( "ui_actualnetGameType", va("%d", uiInfo.gameTypes[ui_netGameType.integer].gtEnum));
- trap_Cvar_Set( "ui_currentNetMap", "0");
- UI_MapCountByGameType(qfalse);
- Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, NULL);
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_JoinGameType_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
-
- if (key == K_MOUSE2) {
- ui_joinGameType.integer--;
- } else {
- ui_joinGameType.integer++;
- }
-
- if (ui_joinGameType.integer < 0) {
- ui_joinGameType.integer = uiInfo.numJoinGameTypes - 1;
- } else if (ui_joinGameType.integer >= uiInfo.numJoinGameTypes) {
- ui_joinGameType.integer = 0;
- }
-
- trap_Cvar_Set( "ui_joinGameType", va("%d", ui_joinGameType.integer));
- UI_BuildServerDisplayList(qtrue);
- return qtrue;
- }
- return qfalse;
-}
-
-
-
-static qboolean UI_Skill_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int i = trap_Cvar_VariableValue( "g_spSkill" );
-
- if (key == K_MOUSE2) {
- i--;
- } else {
- i++;
- }
-
- if (i < 1) {
- i = numSkillLevels;
- } else if (i > numSkillLevels) {
- i = 1;
- }
-
- trap_Cvar_Set("g_spSkill", va("%i", i));
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_TeamName_HandleKey(int flags, float *special, int key, qboolean blue) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
-
- if (key == K_MOUSE2) {
- i--;
- } else {
- i++;
- }
-
- if (i >= uiInfo.teamCount) {
- i = 0;
- } else if (i < 0) {
- i = uiInfo.teamCount - 1;
- }
-
- trap_Cvar_Set( (blue) ? "ui_blueTeam" : "ui_redTeam", uiInfo.teamList[i].teamName);
-
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_TeamMember_HandleKey(int flags, float *special, int key, qboolean blue, int num) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- // 0 - None
- // 1 - Human
- // 2..NumCharacters - Bot
- char *cvar = va(blue ? "ui_blueteam%i" : "ui_redteam%i", num);
- int value = trap_Cvar_VariableValue(cvar);
-
- if (key == K_MOUSE2) {
- value--;
- } else {
- value++;
- }
-
- if (ui_actualNetGameType.integer >= GT_TEAM) {
- if (value >= uiInfo.characterCount + 2) {
- value = 0;
- } else if (value < 0) {
- value = uiInfo.characterCount + 2 - 1;
- }
- } else {
- if (value >= UI_GetNumBots() + 2) {
- value = 0;
- } else if (value < 0) {
- value = UI_GetNumBots() + 2 - 1;
- }
- }
-
- trap_Cvar_Set(cvar, va("%i", value));
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_NetSource_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
-
- if (key == K_MOUSE2) {
- ui_netSource.integer--;
- } else {
- ui_netSource.integer++;
- }
-
- if (ui_netSource.integer >= numNetSources) {
- ui_netSource.integer = 0;
- } else if (ui_netSource.integer < 0) {
- ui_netSource.integer = numNetSources - 1;
- }
-
- UI_BuildServerDisplayList(qtrue);
- if (ui_netSource.integer != AS_GLOBAL) {
- UI_StartServerRefresh(qtrue);
- }
- trap_Cvar_Set( "ui_netSource", va("%d", ui_netSource.integer));
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_NetFilter_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
-
- if (key == K_MOUSE2) {
- ui_serverFilterType.integer--;
- } else {
- ui_serverFilterType.integer++;
- }
-
- if (ui_serverFilterType.integer >= numServerFilters) {
- ui_serverFilterType.integer = 0;
- } else if (ui_serverFilterType.integer < 0) {
- ui_serverFilterType.integer = numServerFilters - 1;
- }
- UI_BuildServerDisplayList(qtrue);
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_OpponentName_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- if (key == K_MOUSE2) {
- UI_PriorOpponent();
- } else {
- UI_NextOpponent();
- }
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_BotName_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int game = trap_Cvar_VariableValue("g_gametype");
- int value = uiInfo.botIndex;
-
- if (key == K_MOUSE2) {
- value--;
- } else {
- value++;
- }
-
- if (game >= GT_TEAM) {
- if (value >= uiInfo.characterCount + 2) {
- value = 0;
- } else if (value < 0) {
- value = uiInfo.characterCount + 2 - 1;
- }
- } else {
- if (value >= UI_GetNumBots() + 2) {
- value = 0;
- } else if (value < 0) {
- value = UI_GetNumBots() + 2 - 1;
- }
- }
- uiInfo.botIndex = value;
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_BotSkill_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- if (key == K_MOUSE2) {
- uiInfo.skillIndex--;
- } else {
- uiInfo.skillIndex++;
- }
- if (uiInfo.skillIndex >= numSkillLevels) {
- uiInfo.skillIndex = 0;
- } else if (uiInfo.skillIndex < 0) {
- uiInfo.skillIndex = numSkillLevels-1;
- }
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_RedBlue_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- uiInfo.redBlue ^= 1;
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_Crosshair_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- if (key == K_MOUSE2) {
- uiInfo.currentCrosshair--;
- } else {
- uiInfo.currentCrosshair++;
- }
-
- if (uiInfo.currentCrosshair >= NUM_CROSSHAIRS) {
- uiInfo.currentCrosshair = 0;
- } else if (uiInfo.currentCrosshair < 0) {
- uiInfo.currentCrosshair = NUM_CROSSHAIRS - 1;
- }
- trap_Cvar_Set("cg_drawCrosshair", va("%d", uiInfo.currentCrosshair));
- return qtrue;
- }
- return qfalse;
-}
-
-
-
-static qboolean UI_SelectedPlayer_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int selected;
-
- UI_BuildPlayerList();
- if (!uiInfo.teamLeader) {
- return qfalse;
- }
- selected = trap_Cvar_VariableValue("cg_selectedPlayer");
-
- if (key == K_MOUSE2) {
- selected--;
- } else {
- selected++;
- }
-
- if (selected > uiInfo.myTeamCount) {
- selected = 0;
- } else if (selected < 0) {
- selected = uiInfo.myTeamCount;
- }
-
- if (selected == uiInfo.myTeamCount) {
- trap_Cvar_Set( "cg_selectedPlayerName", "Everyone");
- } else {
- trap_Cvar_Set( "cg_selectedPlayerName", uiInfo.teamNames[selected]);
- }
- trap_Cvar_Set( "cg_selectedPlayer", va("%d", selected));
- }
- return qfalse;
-}
-
-
-static qboolean UI_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) {
- switch (ownerDraw) {
- case UI_HANDICAP:
- return UI_Handicap_HandleKey(flags, special, key);
- break;
- case UI_EFFECTS:
- return UI_Effects_HandleKey(flags, special, key);
- break;
- case UI_CLANNAME:
- return UI_ClanName_HandleKey(flags, special, key);
- break;
- case UI_GAMETYPE:
- return UI_GameType_HandleKey(flags, special, key, qtrue);
- break;
- case UI_NETGAMETYPE:
- return UI_NetGameType_HandleKey(flags, special, key);
- break;
- case UI_JOINGAMETYPE:
- return UI_JoinGameType_HandleKey(flags, special, key);
- break;
- case UI_SKILL:
- return UI_Skill_HandleKey(flags, special, key);
- break;
- case UI_BLUETEAMNAME:
- return UI_TeamName_HandleKey(flags, special, key, qtrue);
- break;
- case UI_REDTEAMNAME:
- return UI_TeamName_HandleKey(flags, special, key, qfalse);
- break;
- case UI_BLUETEAM1:
- case UI_BLUETEAM2:
- case UI_BLUETEAM3:
- case UI_BLUETEAM4:
- case UI_BLUETEAM5:
- UI_TeamMember_HandleKey(flags, special, key, qtrue, ownerDraw - UI_BLUETEAM1 + 1);
- break;
- case UI_REDTEAM1:
- case UI_REDTEAM2:
- case UI_REDTEAM3:
- case UI_REDTEAM4:
- case UI_REDTEAM5:
- UI_TeamMember_HandleKey(flags, special, key, qfalse, ownerDraw - UI_REDTEAM1 + 1);
- break;
- case UI_NETSOURCE:
- UI_NetSource_HandleKey(flags, special, key);
- break;
- case UI_NETFILTER:
- UI_NetFilter_HandleKey(flags, special, key);
- break;
- case UI_OPPONENT_NAME:
- UI_OpponentName_HandleKey(flags, special, key);
- break;
- case UI_BOTNAME:
- return UI_BotName_HandleKey(flags, special, key);
- break;
- case UI_BOTSKILL:
- return UI_BotSkill_HandleKey(flags, special, key);
- break;
- case UI_REDBLUE:
- UI_RedBlue_HandleKey(flags, special, key);
- break;
- case UI_CROSSHAIR:
- UI_Crosshair_HandleKey(flags, special, key);
- break;
- case UI_SELECTEDPLAYER:
- UI_SelectedPlayer_HandleKey(flags, special, key);
- break;
- default:
- break;
- }
-
- return qfalse;
-}
-
-
-static float UI_GetValue(int ownerDraw) {
- return 0;
-}
-
-/*
-=================
-UI_ServersQsortCompare
-=================
-*/
-static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 ) {
- return trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey, uiInfo.serverStatus.sortDir, *(int*)arg1, *(int*)arg2);
-}
-
-
-/*
-=================
-UI_ServersSort
-=================
-*/
-void UI_ServersSort(int column, qboolean force) {
-
- if ( !force ) {
- if ( uiInfo.serverStatus.sortKey == column ) {
- return;
- }
- }
-
- uiInfo.serverStatus.sortKey = column;
- qsort( &uiInfo.serverStatus.displayServers[0], uiInfo.serverStatus.numDisplayServers, sizeof(int), UI_ServersQsortCompare);
-}
-
-/*
-static void UI_StartSinglePlayer(void) {
- int i,j, k, skill;
- char buff[1024];
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= tierCount) {
- i = 0;
- }
- j = trap_Cvar_VariableValue("ui_currentMap");
- if (j < 0 || j > MAPS_PER_TIER) {
- j = 0;
- }
-
- trap_Cvar_SetValue( "singleplayer", 1 );
- trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, 7, tierList[i].gameTypes[j] ) );
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", tierList[i].maps[j] ) );
- skill = trap_Cvar_VariableValue( "g_spSkill" );
-
- if (j == MAPS_PER_TIER-1) {
- k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[0]), skill, "", teamList[k].teamMembers[0]);
- } else {
- k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- for (i = 0; i < PLAYERS_PER_TEAM; i++) {
- Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[i]), skill, "Blue", teamList[k].teamMembers[i]);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- }
-
- k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- for (i = 1; i < PLAYERS_PER_TEAM; i++) {
- Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[i]), skill, "Red", teamList[k].teamMembers[i]);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- }
- trap_Cmd_ExecuteText( EXEC_APPEND, "wait 5; team Red\n" );
- }
-
-
-}
-*/
-
-/*
-===============
-UI_LoadMods
-===============
-*/
-static void UI_LoadMods( void ) {
- int numdirs;
- char dirlist[2048];
- char *dirptr;
- char *descptr;
- int i;
- int dirlen;
-
- uiInfo.modCount = 0;
- numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) );
- dirptr = dirlist;
- for( i = 0; i < numdirs; i++ ) {
- dirlen = strlen( dirptr ) + 1;
- descptr = dirptr + dirlen;
- uiInfo.modList[uiInfo.modCount].modName = String_Alloc(dirptr);
- uiInfo.modList[uiInfo.modCount].modDescr = String_Alloc(descptr);
- dirptr += dirlen + strlen(descptr) + 1;
- uiInfo.modCount++;
- if (uiInfo.modCount >= MAX_MODS) {
- break;
- }
- }
-
-}
-
-
-/*
-===============
-UI_LoadTeams
-===============
-*/
-static void UI_LoadTeams( void ) {
- char teamList[4096];
- char *teamName;
- int i, len, count;
-
- count = trap_FS_GetFileList( "", "team", teamList, 4096 );
-
- if (count) {
- teamName = teamList;
- for ( i = 0; i < count; i++ ) {
- len = strlen( teamName );
- UI_ParseTeamInfo(teamName);
- teamName += len + 1;
- }
- }
-
-}
-
-
-/*
-===============
-UI_LoadMovies
-===============
-*/
-static void UI_LoadMovies( void ) {
- char movielist[4096];
- char *moviename;
- int i, len;
-
- uiInfo.movieCount = trap_FS_GetFileList( "video", "roq", movielist, 4096 );
-
- if (uiInfo.movieCount) {
- if (uiInfo.movieCount > MAX_MOVIES) {
- uiInfo.movieCount = MAX_MOVIES;
- }
- moviename = movielist;
- for ( i = 0; i < uiInfo.movieCount; i++ ) {
- len = strlen( moviename );
- if (!Q_stricmp(moviename + len - 4,".roq")) {
- moviename[len-4] = '\0';
- }
- Q_strupr(moviename);
- uiInfo.movieList[i] = String_Alloc(moviename);
- moviename += len + 1;
- }
- }
-
-}
-
-
-
-/*
-===============
-UI_LoadDemos
-===============
-*/
-static void UI_LoadDemos( void ) {
- char demolist[4096];
- char demoExt[32];
- char *demoname;
- int i, len;
-
- Com_sprintf(demoExt, sizeof(demoExt), "dm_%d", (int)trap_Cvar_VariableValue("protocol"));
-
- uiInfo.demoCount = trap_FS_GetFileList( "demos", demoExt, demolist, 4096 );
-
- Com_sprintf(demoExt, sizeof(demoExt), ".dm_%d", (int)trap_Cvar_VariableValue("protocol"));
-
- if (uiInfo.demoCount) {
- if (uiInfo.demoCount > MAX_DEMOS) {
- uiInfo.demoCount = MAX_DEMOS;
- }
- demoname = demolist;
- for ( i = 0; i < uiInfo.demoCount; i++ ) {
- len = strlen( demoname );
- if (!Q_stricmp(demoname + len - strlen(demoExt), demoExt)) {
- demoname[len-strlen(demoExt)] = '\0';
- }
- Q_strupr(demoname);
- uiInfo.demoList[i] = String_Alloc(demoname);
- demoname += len + 1;
- }
- }
-
-}
-
-
-static qboolean UI_SetNextMap(int actual, int index) {
- int i;
- for (i = actual + 1; i < uiInfo.mapCount; i++) {
- if (uiInfo.mapList[i].active) {
- Menu_SetFeederSelection(NULL, FEEDER_MAPS, index + 1, "skirmish");
- return qtrue;
- }
- }
- return qfalse;
-}
-
-
-static void UI_StartSkirmish(qboolean next) {
- int i, k, g, delay, temp;
- float skill;
- char buff[MAX_STRING_CHARS];
-
- if (next) {
- int actual;
- int index = trap_Cvar_VariableValue("ui_mapIndex");
- UI_MapCountByGameType(qtrue);
- UI_SelectedMap(index, &actual);
- if (UI_SetNextMap(actual, index)) {
- } else {
- UI_GameType_HandleKey(0, NULL, K_MOUSE1, qfalse);
- UI_MapCountByGameType(qtrue);
- Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, "skirmish");
- }
- }
-
- g = uiInfo.gameTypes[ui_gameType.integer].gtEnum;
- trap_Cvar_SetValue( "g_gametype", g );
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName) );
- skill = trap_Cvar_VariableValue( "g_spSkill" );
- trap_Cvar_Set("ui_scoreMap", uiInfo.mapList[ui_currentMap.integer].mapName);
-
- k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
-
- trap_Cvar_Set("ui_singlePlayerActive", "1");
-
- // set up sp overrides, will be replaced on postgame
- temp = trap_Cvar_VariableValue( "capturelimit" );
- trap_Cvar_Set("ui_saveCaptureLimit", va("%i", temp));
- temp = trap_Cvar_VariableValue( "fraglimit" );
- trap_Cvar_Set("ui_saveFragLimit", va("%i", temp));
-
- UI_SetCapFragLimits(qfalse);
-
- temp = trap_Cvar_VariableValue( "cg_drawTimer" );
- trap_Cvar_Set("ui_drawTimer", va("%i", temp));
- temp = trap_Cvar_VariableValue( "g_doWarmup" );
- trap_Cvar_Set("ui_doWarmup", va("%i", temp));
- temp = trap_Cvar_VariableValue( "g_friendlyFire" );
- trap_Cvar_Set("ui_friendlyFire", va("%i", temp));
- temp = trap_Cvar_VariableValue( "sv_maxClients" );
- trap_Cvar_Set("ui_maxClients", va("%i", temp));
- temp = trap_Cvar_VariableValue( "g_warmup" );
- trap_Cvar_Set("ui_Warmup", va("%i", temp));
- temp = trap_Cvar_VariableValue( "sv_pure" );
- trap_Cvar_Set("ui_pure", va("%i", temp));
-
- trap_Cvar_Set("cg_cameraOrbit", "0");
- trap_Cvar_Set("cg_thirdPerson", "0");
- trap_Cvar_Set("cg_drawTimer", "1");
- trap_Cvar_Set("g_doWarmup", "1");
- trap_Cvar_Set("g_warmup", "15");
- trap_Cvar_Set("sv_pure", "0");
- trap_Cvar_Set("g_friendlyFire", "0");
- trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
- trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
-
- if (trap_Cvar_VariableValue("ui_recordSPDemo")) {
- Com_sprintf(buff, MAX_STRING_CHARS, "%s_%i", uiInfo.mapList[ui_currentMap.integer].mapLoadName, g);
- trap_Cvar_Set("ui_recordSPDemoName", buff);
- }
-
- delay = 500;
-
- if (g == GT_TOURNAMENT) {
- trap_Cvar_Set("sv_maxClients", "2");
- Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %f "", %i \n", uiInfo.mapList[ui_currentMap.integer].opponentName, skill, delay);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- } else {
- temp = uiInfo.mapList[ui_currentMap.integer].teamMembers * 2;
- trap_Cvar_Set("sv_maxClients", va("%d", temp));
- for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers; i++) {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f %s %i %s\n", UI_AIFromName(uiInfo.teamList[k].teamMembers[i]), skill, (g == GT_FFA) ? "" : "Blue", delay, uiInfo.teamList[k].teamMembers[i]);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- delay += 500;
- }
- k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers-1; i++) {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f %s %i %s\n", UI_AIFromName(uiInfo.teamList[k].teamMembers[i]), skill, (g == GT_FFA) ? "" : "Red", delay, uiInfo.teamList[k].teamMembers[i]);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- delay += 500;
- }
- }
- if (g >= GT_TEAM ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "wait 5; team Red\n" );
- }
-}
-
-static void UI_Update(const char *name) {
- int val = trap_Cvar_VariableValue(name);
-
- if (Q_stricmp(name, "ui_SetName") == 0) {
- trap_Cvar_Set( "name", UI_Cvar_VariableString("ui_Name"));
- } else if (Q_stricmp(name, "ui_setRate") == 0) {
- float rate = trap_Cvar_VariableValue("rate");
- if (rate >= 5000) {
- trap_Cvar_Set("cl_maxpackets", "30");
- trap_Cvar_Set("cl_packetdup", "1");
- } else if (rate >= 4000) {
- trap_Cvar_Set("cl_maxpackets", "15");
- trap_Cvar_Set("cl_packetdup", "2"); // favor less prediction errors when there's packet loss
- } else {
- trap_Cvar_Set("cl_maxpackets", "15");
- trap_Cvar_Set("cl_packetdup", "1"); // favor lower bandwidth
- }
- } else if (Q_stricmp(name, "ui_GetName") == 0) {
- trap_Cvar_Set( "ui_Name", UI_Cvar_VariableString("name"));
- } else if (Q_stricmp(name, "r_colorbits") == 0) {
- switch (val) {
- case 0:
- trap_Cvar_SetValue( "r_depthbits", 0 );
- trap_Cvar_SetValue( "r_stencilbits", 0 );
- break;
- case 16:
- trap_Cvar_SetValue( "r_depthbits", 16 );
- trap_Cvar_SetValue( "r_stencilbits", 0 );
- break;
- case 32:
- trap_Cvar_SetValue( "r_depthbits", 24 );
- break;
- }
- } else if (Q_stricmp(name, "r_lodbias") == 0) {
- switch (val) {
- case 0:
- trap_Cvar_SetValue( "r_subdivisions", 4 );
- break;
- case 1:
- trap_Cvar_SetValue( "r_subdivisions", 12 );
- break;
- case 2:
- trap_Cvar_SetValue( "r_subdivisions", 20 );
- break;
- }
- } else if (Q_stricmp(name, "ui_glCustom") == 0) {
- switch (val) {
- case 0: // high quality
- trap_Cvar_SetValue( "r_fullScreen", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 4 );
- trap_Cvar_SetValue( "r_vertexlight", 0 );
- trap_Cvar_SetValue( "r_lodbias", 0 );
- trap_Cvar_SetValue( "r_colorbits", 32 );
- trap_Cvar_SetValue( "r_depthbits", 24 );
- trap_Cvar_SetValue( "r_picmip", 0 );
- trap_Cvar_SetValue( "r_mode", 4 );
- trap_Cvar_SetValue( "r_texturebits", 32 );
- trap_Cvar_SetValue( "r_fastSky", 0 );
- trap_Cvar_SetValue( "r_inGameVideo", 1 );
- trap_Cvar_SetValue( "cg_shadows", 1 );
- trap_Cvar_SetValue( "cg_brassTime", 2500 );
- trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
- break;
- case 1: // normal
- trap_Cvar_SetValue( "r_fullScreen", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 12 );
- trap_Cvar_SetValue( "r_vertexlight", 0 );
- trap_Cvar_SetValue( "r_lodbias", 0 );
- trap_Cvar_SetValue( "r_colorbits", 0 );
- trap_Cvar_SetValue( "r_depthbits", 24 );
- trap_Cvar_SetValue( "r_picmip", 1 );
- trap_Cvar_SetValue( "r_mode", 3 );
- trap_Cvar_SetValue( "r_texturebits", 0 );
- trap_Cvar_SetValue( "r_fastSky", 0 );
- trap_Cvar_SetValue( "r_inGameVideo", 1 );
- trap_Cvar_SetValue( "cg_brassTime", 2500 );
- trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
- trap_Cvar_SetValue( "cg_shadows", 0 );
- break;
- case 2: // fast
- trap_Cvar_SetValue( "r_fullScreen", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 8 );
- trap_Cvar_SetValue( "r_vertexlight", 0 );
- trap_Cvar_SetValue( "r_lodbias", 1 );
- trap_Cvar_SetValue( "r_colorbits", 0 );
- trap_Cvar_SetValue( "r_depthbits", 0 );
- trap_Cvar_SetValue( "r_picmip", 1 );
- trap_Cvar_SetValue( "r_mode", 3 );
- trap_Cvar_SetValue( "r_texturebits", 0 );
- trap_Cvar_SetValue( "cg_shadows", 0 );
- trap_Cvar_SetValue( "r_fastSky", 1 );
- trap_Cvar_SetValue( "r_inGameVideo", 0 );
- trap_Cvar_SetValue( "cg_brassTime", 0 );
- trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
- break;
- case 3: // fastest
- trap_Cvar_SetValue( "r_fullScreen", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 20 );
- trap_Cvar_SetValue( "r_vertexlight", 1 );
- trap_Cvar_SetValue( "r_lodbias", 2 );
- trap_Cvar_SetValue( "r_colorbits", 16 );
- trap_Cvar_SetValue( "r_depthbits", 16 );
- trap_Cvar_SetValue( "r_mode", 3 );
- trap_Cvar_SetValue( "r_picmip", 2 );
- trap_Cvar_SetValue( "r_texturebits", 16 );
- trap_Cvar_SetValue( "cg_shadows", 0 );
- trap_Cvar_SetValue( "cg_brassTime", 0 );
- trap_Cvar_SetValue( "r_fastSky", 1 );
- trap_Cvar_SetValue( "r_inGameVideo", 0 );
- trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
- break;
- }
- } else if (Q_stricmp(name, "ui_mousePitch") == 0) {
- if (val == 0) {
- trap_Cvar_SetValue( "m_pitch", 0.022f );
- } else {
- trap_Cvar_SetValue( "m_pitch", -0.022f );
- }
- }
-}
-
-static void UI_RunMenuScript(char **args) {
- const char *name, *name2;
- char buff[1024];
-
- if (String_Parse(args, &name)) {
- if (Q_stricmp(name, "StartServer") == 0) {
- int i, clients, oldclients;
- float skill;
- trap_Cvar_Set("cg_thirdPerson", "0");
- trap_Cvar_Set("cg_cameraOrbit", "0");
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, ui_dedicated.integer ) );
- trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, 8, uiInfo.gameTypes[ui_netGameType.integer].gtEnum ) );
- trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
- trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName ) );
- skill = trap_Cvar_VariableValue( "g_spSkill" );
- // set max clients based on spots
- oldclients = trap_Cvar_VariableValue( "sv_maxClients" );
- clients = 0;
- for (i = 0; i < PLAYERS_PER_TEAM; i++) {
- int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
- if (bot >= 0) {
- clients++;
- }
- bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
- if (bot >= 0) {
- clients++;
- }
- }
- if (clients == 0) {
- clients = 8;
- }
-
- if (oldclients > clients) {
- clients = oldclients;
- }
-
- trap_Cvar_Set("sv_maxClients", va("%d",clients));
-
- for (i = 0; i < PLAYERS_PER_TEAM; i++) {
- int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
- if (bot > 1) {
- if (ui_actualNetGameType.integer >= GT_TEAM) {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Blue");
- } else {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
- }
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- }
- bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
- if (bot > 1) {
- if (ui_actualNetGameType.integer >= GT_TEAM) {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Red");
- } else {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
- }
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- }
- }
- } else if (Q_stricmp(name, "updateSPMenu") == 0) {
- UI_SetCapFragLimits(qtrue);
- UI_MapCountByGameType(qtrue);
- ui_mapIndex.integer = UI_GetIndexFromSelection(ui_currentMap.integer);
- trap_Cvar_Set("ui_mapIndex", va("%d", ui_mapIndex.integer));
- Menu_SetFeederSelection(NULL, FEEDER_MAPS, ui_mapIndex.integer, "skirmish");
- UI_GameType_HandleKey(0, NULL, K_MOUSE1, qfalse);
- UI_GameType_HandleKey(0, NULL, K_MOUSE2, qfalse);
- } else if (Q_stricmp(name, "resetDefaults") == 0) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n");
- trap_Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n");
- Controls_SetDefaults();
- trap_Cvar_Set("com_introPlayed", "1" );
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" );
- } else if (Q_stricmp(name, "getCDKey") == 0) {
- char out[17];
- trap_GetCDKey(buff, 17);
- trap_Cvar_Set("cdkey1", "");
- trap_Cvar_Set("cdkey2", "");
- trap_Cvar_Set("cdkey3", "");
- trap_Cvar_Set("cdkey4", "");
- if (strlen(buff) == CDKEY_LEN) {
- Q_strncpyz(out, buff, 5);
- trap_Cvar_Set("cdkey1", out);
- Q_strncpyz(out, buff + 4, 5);
- trap_Cvar_Set("cdkey2", out);
- Q_strncpyz(out, buff + 8, 5);
- trap_Cvar_Set("cdkey3", out);
- Q_strncpyz(out, buff + 12, 5);
- trap_Cvar_Set("cdkey4", out);
- }
-
- } else if (Q_stricmp(name, "verifyCDKey") == 0) {
- buff[0] = '\0';
- Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey1"));
- Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey2"));
- Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey3"));
- Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey4"));
- trap_Cvar_Set("cdkey", buff);
- if (trap_VerifyCDKey(buff, UI_Cvar_VariableString("cdkeychecksum"))) {
- trap_Cvar_Set("ui_cdkeyvalid", "CD Key Appears to be valid.");
- trap_SetCDKey(buff);
- } else {
- trap_Cvar_Set("ui_cdkeyvalid", "CD Key does not appear to be valid.");
- }
- } else if (Q_stricmp(name, "loadArenas") == 0) {
- UI_LoadArenas();
- UI_MapCountByGameType(qfalse);
- Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, "createserver");
- } else if (Q_stricmp(name, "saveControls") == 0) {
- Controls_SetConfig(qtrue);
- } else if (Q_stricmp(name, "loadControls") == 0) {
- Controls_GetConfig();
- } else if (Q_stricmp(name, "clearError") == 0) {
- trap_Cvar_Set("com_errorMessage", "");
- } else if (Q_stricmp(name, "loadGameInfo") == 0) {
-#ifdef PRE_RELEASE_TADEMO
- UI_ParseGameInfo("demogameinfo.txt");
-#else
- UI_ParseGameInfo("gameinfo.txt");
-#endif
- UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
- } else if (Q_stricmp(name, "resetScores") == 0) {
- UI_ClearScores();
- } else if (Q_stricmp(name, "RefreshServers") == 0) {
- UI_StartServerRefresh(qtrue);
- UI_BuildServerDisplayList(qtrue);
- } else if (Q_stricmp(name, "RefreshFilter") == 0) {
- UI_StartServerRefresh(qfalse);
- UI_BuildServerDisplayList(qtrue);
- } else if (Q_stricmp(name, "RunSPDemo") == 0) {
- if (uiInfo.demoAvailable) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s_%i\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum));
- }
- } else if (Q_stricmp(name, "LoadDemos") == 0) {
- UI_LoadDemos();
- } else if (Q_stricmp(name, "LoadMovies") == 0) {
- UI_LoadMovies();
- } else if (Q_stricmp(name, "LoadMods") == 0) {
- UI_LoadMods();
- } else if (Q_stricmp(name, "playMovie") == 0) {
- if (uiInfo.previewMovie >= 0) {
- trap_CIN_StopCinematic(uiInfo.previewMovie);
- }
- trap_Cmd_ExecuteText( EXEC_APPEND, va("cinematic %s.roq 2\n", uiInfo.movieList[uiInfo.movieIndex]));
- } else if (Q_stricmp(name, "RunMod") == 0) {
- trap_Cvar_Set( "fs_game", uiInfo.modList[uiInfo.modIndex].modName);
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
- } else if (Q_stricmp(name, "RunDemo") == 0) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s\n", uiInfo.demoList[uiInfo.demoIndex]));
- } else if (Q_stricmp(name, "Quake3") == 0) {
- trap_Cvar_Set( "fs_game", "");
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
- } else if (Q_stricmp(name, "closeJoin") == 0) {
- if (uiInfo.serverStatus.refreshActive) {
- UI_StopServerRefresh();
- uiInfo.serverStatus.nextDisplayRefresh = 0;
- uiInfo.nextServerStatusRefresh = 0;
- uiInfo.nextFindPlayerRefresh = 0;
- UI_BuildServerDisplayList(qtrue);
- } else {
- Menus_CloseByName("joinserver");
- Menus_OpenByName("main");
- }
- } else if (Q_stricmp(name, "StopRefresh") == 0) {
- UI_StopServerRefresh();
- uiInfo.serverStatus.nextDisplayRefresh = 0;
- uiInfo.nextServerStatusRefresh = 0;
- uiInfo.nextFindPlayerRefresh = 0;
- } else if (Q_stricmp(name, "UpdateFilter") == 0) {
- if (ui_netSource.integer == AS_LOCAL) {
- UI_StartServerRefresh(qtrue);
- }
- UI_BuildServerDisplayList(qtrue);
- UI_FeederSelection(FEEDER_SERVERS, 0);
- } else if (Q_stricmp(name, "ServerStatus") == 0) {
- trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], uiInfo.serverStatusAddress, sizeof(uiInfo.serverStatusAddress));
- UI_BuildServerStatus(qtrue);
- } else if (Q_stricmp(name, "FoundPlayerServerStatus") == 0) {
- Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
- UI_BuildServerStatus(qtrue);
- Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
- } else if (Q_stricmp(name, "FindPlayer") == 0) {
- UI_BuildFindPlayerList(qtrue);
- // clear the displayed server status info
- uiInfo.serverStatusInfo.numLines = 0;
- Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
- } else if (Q_stricmp(name, "JoinServer") == 0) {
- trap_Cvar_Set("cg_thirdPerson", "0");
- trap_Cvar_Set("cg_cameraOrbit", "0");
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- if (uiInfo.serverStatus.currentServer >= 0 && uiInfo.serverStatus.currentServer < uiInfo.serverStatus.numDisplayServers) {
- trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, 1024);
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", buff ) );
- }
- } else if (Q_stricmp(name, "FoundPlayerJoinServer") == 0) {
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- if (uiInfo.currentFoundPlayerServer >= 0 && uiInfo.currentFoundPlayerServer < uiInfo.numFoundPlayerServers) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer] ) );
- }
- } else if (Q_stricmp(name, "Quit") == 0) {
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- trap_Cmd_ExecuteText( EXEC_NOW, "quit");
- } else if (Q_stricmp(name, "Controls") == 0) {
- trap_Cvar_Set( "cl_paused", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- Menus_CloseAll();
- Menus_ActivateByName("setup_menu2");
- } else if (Q_stricmp(name, "Leave") == 0) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- Menus_CloseAll();
- Menus_ActivateByName("main");
- } else if (Q_stricmp(name, "ServerSort") == 0) {
- int sortColumn;
- if (Int_Parse(args, &sortColumn)) {
- // if same column we're already sorting on then flip the direction
- if (sortColumn == uiInfo.serverStatus.sortKey) {
- uiInfo.serverStatus.sortDir = !uiInfo.serverStatus.sortDir;
- }
- // make sure we sort again
- UI_ServersSort(sortColumn, qtrue);
- }
- } else if (Q_stricmp(name, "nextSkirmish") == 0) {
- UI_StartSkirmish(qtrue);
- } else if (Q_stricmp(name, "SkirmishStart") == 0) {
- UI_StartSkirmish(qfalse);
- } else if (Q_stricmp(name, "closeingame") == 0) {
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
- } else if (Q_stricmp(name, "voteMap") == 0) {
- if (ui_currentNetMap.integer >=0 && ui_currentNetMap.integer < uiInfo.mapCount) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote map %s\n",uiInfo.mapList[ui_currentNetMap.integer].mapLoadName) );
- }
- } else if (Q_stricmp(name, "voteKick") == 0) {
- if (uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote kick %s\n",uiInfo.playerNames[uiInfo.playerIndex]) );
- }
- } else if (Q_stricmp(name, "voteGame") == 0) {
- if (ui_netGameType.integer >= 0 && ui_netGameType.integer < uiInfo.numGameTypes) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote g_gametype %i\n",uiInfo.gameTypes[ui_netGameType.integer].gtEnum) );
- }
- } else if (Q_stricmp(name, "voteLeader") == 0) {
- if (uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("callteamvote leader %s\n",uiInfo.teamNames[uiInfo.teamIndex]) );
- }
- } else if (Q_stricmp(name, "addBot") == 0) {
- if (trap_Cvar_VariableValue("g_gametype") >= GT_TEAM) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", uiInfo.characterList[uiInfo.botIndex].name, uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") );
- } else {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", UI_GetBotNameByNumber(uiInfo.botIndex), uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") );
- }
- } else if (Q_stricmp(name, "addFavorite") == 0) {
- if (ui_netSource.integer != AS_FAVORITES) {
- char name[MAX_NAME_LENGTH];
- char addr[MAX_NAME_LENGTH];
- int res;
-
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
- name[0] = addr[0] = '\0';
- Q_strncpyz(name, Info_ValueForKey(buff, "hostname"), MAX_NAME_LENGTH);
- Q_strncpyz(addr, Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
- if (strlen(name) > 0 && strlen(addr) > 0) {
- res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
- if (res == 0) {
- // server already in the list
- Com_Printf("Favorite already in list\n");
- }
- else if (res == -1) {
- // list full
- Com_Printf("Favorite list full\n");
- }
- else {
- // successfully added
- Com_Printf("Added favorite server %s\n", addr);
- }
- }
- }
- } else if (Q_stricmp(name, "deleteFavorite") == 0) {
- if (ui_netSource.integer == AS_FAVORITES) {
- char addr[MAX_NAME_LENGTH];
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
- addr[0] = '\0';
- Q_strncpyz(addr, Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
- if (strlen(addr) > 0) {
- trap_LAN_RemoveServer(AS_FAVORITES, addr);
- }
- }
- } else if (Q_stricmp(name, "createFavorite") == 0) {
- if (ui_netSource.integer == AS_FAVORITES) {
- char name[MAX_NAME_LENGTH];
- char addr[MAX_NAME_LENGTH];
- int res;
-
- name[0] = addr[0] = '\0';
- Q_strncpyz(name, UI_Cvar_VariableString("ui_favoriteName"), MAX_NAME_LENGTH);
- Q_strncpyz(addr, UI_Cvar_VariableString("ui_favoriteAddress"), MAX_NAME_LENGTH);
- if (strlen(name) > 0 && strlen(addr) > 0) {
- res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
- if (res == 0) {
- // server already in the list
- Com_Printf("Favorite already in list\n");
- }
- else if (res == -1) {
- // list full
- Com_Printf("Favorite list full\n");
- }
- else {
- // successfully added
- Com_Printf("Added favorite server %s\n", addr);
- }
- }
- }
- } else if (Q_stricmp(name, "orders") == 0) {
- const char *orders;
- if (String_Parse(args, &orders)) {
- int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
- if (selectedPlayer < uiInfo.myTeamCount) {
- strcpy(buff, orders);
- trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
- trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
- } else {
- int i;
- for (i = 0; i < uiInfo.myTeamCount; i++) {
- if (Q_stricmp(UI_Cvar_VariableString("name"), uiInfo.teamNames[i]) == 0) {
- continue;
- }
- strcpy(buff, orders);
- trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamNames[i]) );
- trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
- }
- }
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
- }
- } else if (Q_stricmp(name, "voiceOrdersTeam") == 0) {
- const char *orders;
- if (String_Parse(args, &orders)) {
- int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
- if (selectedPlayer == uiInfo.myTeamCount) {
- trap_Cmd_ExecuteText( EXEC_APPEND, orders );
- trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
- }
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
- }
- } else if (Q_stricmp(name, "voiceOrders") == 0) {
- const char *orders;
- if (String_Parse(args, &orders)) {
- int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
- if (selectedPlayer < uiInfo.myTeamCount) {
- strcpy(buff, orders);
- trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
- trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
- }
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
- }
- } else if (Q_stricmp(name, "glCustom") == 0) {
- trap_Cvar_Set("ui_glCustom", "4");
- } else if (Q_stricmp(name, "update") == 0) {
- if (String_Parse(args, &name2)) {
- UI_Update(name2);
- }
- } else if (Q_stricmp(name, "setPbClStatus") == 0) {
- int stat;
- if ( Int_Parse( args, &stat ) )
- trap_SetPbClStatus( stat );
- }
- else {
- Com_Printf("unknown UI script %s\n", name);
- }
- }
-}
-
-static void UI_GetTeamColor(vec4_t *color) {
-}
-
-/*
-==================
-UI_MapCountByGameType
-==================
-*/
-static int UI_MapCountByGameType(qboolean singlePlayer) {
- int i, c, game;
- c = 0;
- game = singlePlayer ? uiInfo.gameTypes[ui_gameType.integer].gtEnum : uiInfo.gameTypes[ui_netGameType.integer].gtEnum;
- if (game == GT_SINGLE_PLAYER) {
- game++;
- }
- if (game == GT_TEAM) {
- game = GT_FFA;
- }
-
- for (i = 0; i < uiInfo.mapCount; i++) {
- uiInfo.mapList[i].active = qfalse;
- if ( uiInfo.mapList[i].typeBits & (1 << game)) {
- if (singlePlayer) {
- if (!(uiInfo.mapList[i].typeBits & (1 << GT_SINGLE_PLAYER))) {
- continue;
- }
- }
- c++;
- uiInfo.mapList[i].active = qtrue;
- }
- }
- return c;
-}
-
-qboolean UI_hasSkinForBase(const char *base, const char *team) {
- char test[1024];
-
- Com_sprintf( test, sizeof( test ), "models/players/%s/%s/lower_default.skin", base, team );
-
- if (trap_FS_FOpenFile(test, NULL, FS_READ)) {
- return qtrue;
- }
- Com_sprintf( test, sizeof( test ), "models/players/characters/%s/%s/lower_default.skin", base, team );
-
- if (trap_FS_FOpenFile(test, NULL, FS_READ)) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-UI_MapCountByTeam
-==================
-*/
-static int UI_HeadCountByTeam(void) {
- static int init = 0;
- int i, j, k, c, tIndex;
-
- c = 0;
- if (!init) {
- for (i = 0; i < uiInfo.characterCount; i++) {
- uiInfo.characterList[i].reference = 0;
- for (j = 0; j < uiInfo.teamCount; j++) {
- if (UI_hasSkinForBase(uiInfo.characterList[i].base, uiInfo.teamList[j].teamName)) {
- uiInfo.characterList[i].reference |= (1<<j);
- }
- }
- }
- init = 1;
- }
-
- tIndex = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
-
- // do names
- for (i = 0; i < uiInfo.characterCount; i++) {
- uiInfo.characterList[i].active = qfalse;
- for(j = 0; j < TEAM_MEMBERS; j++) {
- if (uiInfo.teamList[tIndex].teamMembers[j] != NULL) {
- if (uiInfo.characterList[i].reference&(1<<tIndex)) {// && Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.characterList[i].name)==0) {
- uiInfo.characterList[i].active = qtrue;
- c++;
- break;
- }
- }
- }
- }
-
- // and then aliases
- for(j = 0; j < TEAM_MEMBERS; j++) {
- for(k = 0; k < uiInfo.aliasCount; k++) {
- if (uiInfo.aliasList[k].name != NULL) {
- if (Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.aliasList[k].name)==0) {
- for (i = 0; i < uiInfo.characterCount; i++) {
- if (uiInfo.characterList[i].headImage != -1 && uiInfo.characterList[i].reference&(1<<tIndex) && Q_stricmp(uiInfo.aliasList[k].ai, uiInfo.characterList[i].name)==0) {
- if (uiInfo.characterList[i].active == qfalse) {
- uiInfo.characterList[i].active = qtrue;
- c++;
- }
- break;
- }
- }
- }
- }
- }
- }
- return c;
-}
-
-/*
-==================
-UI_InsertServerIntoDisplayList
-==================
-*/
-static void UI_InsertServerIntoDisplayList(int num, int position) {
- int i;
-
- if (position < 0 || position > uiInfo.serverStatus.numDisplayServers ) {
- return;
- }
- //
- uiInfo.serverStatus.numDisplayServers++;
- for (i = uiInfo.serverStatus.numDisplayServers; i > position; i--) {
- uiInfo.serverStatus.displayServers[i] = uiInfo.serverStatus.displayServers[i-1];
- }
- uiInfo.serverStatus.displayServers[position] = num;
-}
-
-/*
-==================
-UI_RemoveServerFromDisplayList
-==================
-*/
-static void UI_RemoveServerFromDisplayList(int num) {
- int i, j;
-
- for (i = 0; i < uiInfo.serverStatus.numDisplayServers; i++) {
- if (uiInfo.serverStatus.displayServers[i] == num) {
- uiInfo.serverStatus.numDisplayServers--;
- for (j = i; j < uiInfo.serverStatus.numDisplayServers; j++) {
- uiInfo.serverStatus.displayServers[j] = uiInfo.serverStatus.displayServers[j+1];
- }
- return;
- }
- }
-}
-
-/*
-==================
-UI_BinaryServerInsertion
-==================
-*/
-static void UI_BinaryServerInsertion(int num) {
- int mid, offset, res, len;
-
- // use binary search to insert server
- len = uiInfo.serverStatus.numDisplayServers;
- mid = len;
- offset = 0;
- res = 0;
- while(mid > 0) {
- mid = len >> 1;
- //
- res = trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey,
- uiInfo.serverStatus.sortDir, num, uiInfo.serverStatus.displayServers[offset+mid]);
- // if equal
- if (res == 0) {
- UI_InsertServerIntoDisplayList(num, offset+mid);
- return;
- }
- // if larger
- else if (res == 1) {
- offset += mid;
- len -= mid;
- }
- // if smaller
- else {
- len -= mid;
- }
- }
- if (res == 1) {
- offset++;
- }
- UI_InsertServerIntoDisplayList(num, offset);
-}
-
-/*
-==================
-UI_BuildServerDisplayList
-==================
-*/
-static void UI_BuildServerDisplayList(qboolean force) {
- int i, count, clients, maxClients, ping, game, len, visible;
- char info[MAX_STRING_CHARS];
-// qboolean startRefresh = qtrue; TTimo: unused
- static int numinvisible;
-
- if (!(force || uiInfo.uiDC.realTime > uiInfo.serverStatus.nextDisplayRefresh)) {
- return;
- }
- // if we shouldn't reset
- if ( force == 2 ) {
- force = 0;
- }
-
- // do motd updates here too
- trap_Cvar_VariableStringBuffer( "cl_motdString", uiInfo.serverStatus.motd, sizeof(uiInfo.serverStatus.motd) );
- len = strlen(uiInfo.serverStatus.motd);
- if (len == 0) {
- strcpy(uiInfo.serverStatus.motd, "Welcome to Team Arena!");
- len = strlen(uiInfo.serverStatus.motd);
- }
- if (len != uiInfo.serverStatus.motdLen) {
- uiInfo.serverStatus.motdLen = len;
- uiInfo.serverStatus.motdWidth = -1;
- }
-
- if (force) {
- numinvisible = 0;
- // clear number of displayed servers
- uiInfo.serverStatus.numDisplayServers = 0;
- uiInfo.serverStatus.numPlayersOnServers = 0;
- // set list box index to zero
- Menu_SetFeederSelection(NULL, FEEDER_SERVERS, 0, NULL);
- // mark all servers as visible so we store ping updates for them
- trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
- }
-
- // get the server count (comes from the master)
- count = trap_LAN_GetServerCount(ui_netSource.integer);
- if (count == -1 || (ui_netSource.integer == AS_LOCAL && count == 0) ) {
- // still waiting on a response from the master
- uiInfo.serverStatus.numDisplayServers = 0;
- uiInfo.serverStatus.numPlayersOnServers = 0;
- uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 500;
- return;
- }
-
- visible = qfalse;
- for (i = 0; i < count; i++) {
- // if we already got info for this server
- if (!trap_LAN_ServerIsVisible(ui_netSource.integer, i)) {
- continue;
- }
- visible = qtrue;
- // get the ping for this server
- ping = trap_LAN_GetServerPing(ui_netSource.integer, i);
- if (ping > 0 || ui_netSource.integer == AS_FAVORITES) {
-
- trap_LAN_GetServerInfo(ui_netSource.integer, i, info, MAX_STRING_CHARS);
-
- clients = atoi(Info_ValueForKey(info, "clients"));
- uiInfo.serverStatus.numPlayersOnServers += clients;
-
- if (ui_browserShowEmpty.integer == 0) {
- if (clients == 0) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- continue;
- }
- }
-
- if (ui_browserShowFull.integer == 0) {
- maxClients = atoi(Info_ValueForKey(info, "sv_maxclients"));
- if (clients == maxClients) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- continue;
- }
- }
-
- if (uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum != -1) {
- game = atoi(Info_ValueForKey(info, "gametype"));
- if (game != uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- continue;
- }
- }
-
- if (ui_serverFilterType.integer > 0) {
- if (Q_stricmp(Info_ValueForKey(info, "game"), serverFilters[ui_serverFilterType.integer].basedir) != 0) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- continue;
- }
- }
- // make sure we never add a favorite server twice
- if (ui_netSource.integer == AS_FAVORITES) {
- UI_RemoveServerFromDisplayList(i);
- }
- // insert the server into the list
- UI_BinaryServerInsertion(i);
- // done with this server
- if (ping > 0) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- numinvisible++;
- }
- }
- }
-
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime;
-
- // if there were no servers visible for ping updates
- if (!visible) {
-// UI_StopServerRefresh();
-// uiInfo.serverStatus.nextDisplayRefresh = 0;
- }
-}
-
-typedef struct
-{
- char *name, *altName;
-} serverStatusCvar_t;
-
-serverStatusCvar_t serverStatusCvars[] = {
- {"sv_hostname", "Name"},
- {"Address", ""},
- {"gamename", "Game name"},
- {"g_gametype", "Game type"},
- {"mapname", "Map"},
- {"version", ""},
- {"protocol", ""},
- {"timelimit", ""},
- {"fraglimit", ""},
- {NULL, NULL}
-};
-
-/*
-==================
-UI_SortServerStatusInfo
-==================
-*/
-static void UI_SortServerStatusInfo( serverStatusInfo_t *info ) {
- int i, j, index;
- char *tmp1, *tmp2;
-
- // FIXME: if "gamename" == "baseq3" or "missionpack" then
- // replace the gametype number by FFA, CTF etc.
- //
- index = 0;
- for (i = 0; serverStatusCvars[i].name; i++) {
- for (j = 0; j < info->numLines; j++) {
- if ( !info->lines[j][1] || info->lines[j][1][0] ) {
- continue;
- }
- if ( !Q_stricmp(serverStatusCvars[i].name, info->lines[j][0]) ) {
- // swap lines
- tmp1 = info->lines[index][0];
- tmp2 = info->lines[index][3];
- info->lines[index][0] = info->lines[j][0];
- info->lines[index][3] = info->lines[j][3];
- info->lines[j][0] = tmp1;
- info->lines[j][3] = tmp2;
- //
- if ( strlen(serverStatusCvars[i].altName) ) {
- info->lines[index][0] = serverStatusCvars[i].altName;
- }
- index++;
- }
- }
- }
-}
-
-/*
-==================
-UI_GetServerStatusInfo
-==================
-*/
-static int UI_GetServerStatusInfo( const char *serverAddress, serverStatusInfo_t *info ) {
- char *p, *score, *ping, *name;
- int i, len;
-
- if (!info) {
- trap_LAN_ServerStatus( serverAddress, NULL, 0);
- return qfalse;
- }
- memset(info, 0, sizeof(*info));
- if ( trap_LAN_ServerStatus( serverAddress, info->text, sizeof(info->text)) ) {
- Q_strncpyz(info->address, serverAddress, sizeof(info->address));
- p = info->text;
- info->numLines = 0;
- info->lines[info->numLines][0] = "Address";
- info->lines[info->numLines][1] = "";
- info->lines[info->numLines][2] = "";
- info->lines[info->numLines][3] = info->address;
- info->numLines++;
- // get the cvars
- while (p && *p) {
- p = strchr(p, '\\');
- if (!p) break;
- *p++ = '\0';
- if (*p == '\\')
- break;
- info->lines[info->numLines][0] = p;
- info->lines[info->numLines][1] = "";
- info->lines[info->numLines][2] = "";
- p = strchr(p, '\\');
- if (!p) break;
- *p++ = '\0';
- info->lines[info->numLines][3] = p;
-
- info->numLines++;
- if (info->numLines >= MAX_SERVERSTATUS_LINES)
- break;
- }
- // get the player list
- if (info->numLines < MAX_SERVERSTATUS_LINES-3) {
- // empty line
- info->lines[info->numLines][0] = "";
- info->lines[info->numLines][1] = "";
- info->lines[info->numLines][2] = "";
- info->lines[info->numLines][3] = "";
- info->numLines++;
- // header
- info->lines[info->numLines][0] = "num";
- info->lines[info->numLines][1] = "score";
- info->lines[info->numLines][2] = "ping";
- info->lines[info->numLines][3] = "name";
- info->numLines++;
- // parse players
- i = 0;
- len = 0;
- while (p && *p) {
- if (*p == '\\')
- *p++ = '\0';
- if (!p)
- break;
- score = p;
- p = strchr(p, ' ');
- if (!p)
- break;
- *p++ = '\0';
- ping = p;
- p = strchr(p, ' ');
- if (!p)
- break;
- *p++ = '\0';
- name = p;
- Com_sprintf(&info->pings[len], sizeof(info->pings)-len, "%d", i);
- info->lines[info->numLines][0] = &info->pings[len];
- len += strlen(&info->pings[len]) + 1;
- info->lines[info->numLines][1] = score;
- info->lines[info->numLines][2] = ping;
- info->lines[info->numLines][3] = name;
- info->numLines++;
- if (info->numLines >= MAX_SERVERSTATUS_LINES)
- break;
- p = strchr(p, '\\');
- if (!p)
- break;
- *p++ = '\0';
- //
- i++;
- }
- }
- UI_SortServerStatusInfo( info );
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-stristr
-==================
-*/
-static char *stristr(char *str, char *charset) {
- int i;
-
- while(*str) {
- for (i = 0; charset[i] && str[i]; i++) {
- if (toupper(charset[i]) != toupper(str[i])) break;
- }
- if (!charset[i]) return str;
- str++;
- }
- return NULL;
-}
-
-/*
-==================
-UI_BuildFindPlayerList
-==================
-*/
-static void UI_BuildFindPlayerList(qboolean force) {
- static int numFound, numTimeOuts;
- int i, j, resend;
- serverStatusInfo_t info;
- char name[MAX_NAME_LENGTH+2];
- char infoString[MAX_STRING_CHARS];
-
- if (!force) {
- if (!uiInfo.nextFindPlayerRefresh || uiInfo.nextFindPlayerRefresh > uiInfo.uiDC.realTime) {
- return;
- }
- }
- else {
- memset(&uiInfo.pendingServerStatus, 0, sizeof(uiInfo.pendingServerStatus));
- uiInfo.numFoundPlayerServers = 0;
- uiInfo.currentFoundPlayerServer = 0;
- trap_Cvar_VariableStringBuffer( "ui_findPlayer", uiInfo.findPlayerName, sizeof(uiInfo.findPlayerName));
- Q_CleanStr(uiInfo.findPlayerName);
- // should have a string of some length
- if (!strlen(uiInfo.findPlayerName)) {
- uiInfo.nextFindPlayerRefresh = 0;
- return;
- }
- // set resend time
- resend = ui_serverStatusTimeOut.integer / 2 - 10;
- if (resend < 50) {
- resend = 50;
- }
- trap_Cvar_Set("cl_serverStatusResendTime", va("%d", resend));
- // reset all server status requests
- trap_LAN_ServerStatus( NULL, NULL, 0);
- //
- uiInfo.numFoundPlayerServers = 1;
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
- sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
- "searching %d...", uiInfo.pendingServerStatus.num);
- numFound = 0;
- numTimeOuts++;
- }
- for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
- // if this pending server is valid
- if (uiInfo.pendingServerStatus.server[i].valid) {
- // try to get the server status for this server
- if (UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, &info ) ) {
- //
- numFound++;
- // parse through the server status lines
- for (j = 0; j < info.numLines; j++) {
- // should have ping info
- if ( !info.lines[j][2] || !info.lines[j][2][0] ) {
- continue;
- }
- // clean string first
- Q_strncpyz(name, info.lines[j][3], sizeof(name));
- Q_CleanStr(name);
- // if the player name is a substring
- if (stristr(name, uiInfo.findPlayerName)) {
- // add to found server list if we have space (always leave space for a line with the number found)
- if (uiInfo.numFoundPlayerServers < MAX_FOUNDPLAYER_SERVERS-1) {
- //
- Q_strncpyz(uiInfo.foundPlayerServerAddresses[uiInfo.numFoundPlayerServers-1],
- uiInfo.pendingServerStatus.server[i].adrstr,
- sizeof(uiInfo.foundPlayerServerAddresses[0]));
- Q_strncpyz(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
- uiInfo.pendingServerStatus.server[i].name,
- sizeof(uiInfo.foundPlayerServerNames[0]));
- uiInfo.numFoundPlayerServers++;
- }
- else {
- // can't add any more so we're done
- uiInfo.pendingServerStatus.num = uiInfo.serverStatus.numDisplayServers;
- }
- }
- }
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
- sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
- "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
- // retrieved the server status so reuse this spot
- uiInfo.pendingServerStatus.server[i].valid = qfalse;
- }
- }
- // if empty pending slot or timed out
- if (!uiInfo.pendingServerStatus.server[i].valid ||
- uiInfo.pendingServerStatus.server[i].startTime < uiInfo.uiDC.realTime - ui_serverStatusTimeOut.integer) {
- if (uiInfo.pendingServerStatus.server[i].valid) {
- numTimeOuts++;
- }
- // reset server status request for this address
- UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, NULL );
- // reuse pending slot
- uiInfo.pendingServerStatus.server[i].valid = qfalse;
- // if we didn't try to get the status of all servers in the main browser yet
- if (uiInfo.pendingServerStatus.num < uiInfo.serverStatus.numDisplayServers) {
- uiInfo.pendingServerStatus.server[i].startTime = uiInfo.uiDC.realTime;
- trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num],
- uiInfo.pendingServerStatus.server[i].adrstr, sizeof(uiInfo.pendingServerStatus.server[i].adrstr));
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num], infoString, sizeof(infoString));
- Q_strncpyz(uiInfo.pendingServerStatus.server[i].name, Info_ValueForKey(infoString, "hostname"), sizeof(uiInfo.pendingServerStatus.server[0].name));
- uiInfo.pendingServerStatus.server[i].valid = qtrue;
- uiInfo.pendingServerStatus.num++;
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
- sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
- "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
- }
- }
- }
- for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
- if (uiInfo.pendingServerStatus.server[i].valid) {
- break;
- }
- }
- // if still trying to retrieve server status info
- if (i < MAX_SERVERSTATUSREQUESTS) {
- uiInfo.nextFindPlayerRefresh = uiInfo.uiDC.realTime + 25;
- }
- else {
- // add a line that shows the number of servers found
- if (!uiInfo.numFoundPlayerServers) {
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]), "no servers found");
- }
- else {
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]),
- "%d server%s found with player %s", uiInfo.numFoundPlayerServers-1,
- uiInfo.numFoundPlayerServers == 2 ? "":"s", uiInfo.findPlayerName);
- }
- uiInfo.nextFindPlayerRefresh = 0;
- // show the server status info for the selected server
- UI_FeederSelection(FEEDER_FINDPLAYER, uiInfo.currentFoundPlayerServer);
- }
-}
-
-/*
-==================
-UI_BuildServerStatus
-==================
-*/
-static void UI_BuildServerStatus(qboolean force) {
-
- if (uiInfo.nextFindPlayerRefresh) {
- return;
- }
- if (!force) {
- if (!uiInfo.nextServerStatusRefresh || uiInfo.nextServerStatusRefresh > uiInfo.uiDC.realTime) {
- return;
- }
- }
- else {
- Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
- uiInfo.serverStatusInfo.numLines = 0;
- // reset all server status requests
- trap_LAN_ServerStatus( NULL, NULL, 0);
- }
- if (uiInfo.serverStatus.currentServer < 0 || uiInfo.serverStatus.currentServer > uiInfo.serverStatus.numDisplayServers || uiInfo.serverStatus.numDisplayServers == 0) {
- return;
- }
- if (UI_GetServerStatusInfo( uiInfo.serverStatusAddress, &uiInfo.serverStatusInfo ) ) {
- uiInfo.nextServerStatusRefresh = 0;
- UI_GetServerStatusInfo( uiInfo.serverStatusAddress, NULL );
- }
- else {
- uiInfo.nextServerStatusRefresh = uiInfo.uiDC.realTime + 500;
- }
-}
-
-/*
-==================
-UI_FeederCount
-==================
-*/
-static int UI_FeederCount(float feederID) {
- if (feederID == FEEDER_HEADS) {
- return UI_HeadCountByTeam();
- } else if (feederID == FEEDER_Q3HEADS) {
- return uiInfo.q3HeadCount;
- } else if (feederID == FEEDER_CINEMATICS) {
- return uiInfo.movieCount;
- } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
- return UI_MapCountByGameType(feederID == FEEDER_MAPS ? qtrue : qfalse);
- } else if (feederID == FEEDER_SERVERS) {
- return uiInfo.serverStatus.numDisplayServers;
- } else if (feederID == FEEDER_SERVERSTATUS) {
- return uiInfo.serverStatusInfo.numLines;
- } else if (feederID == FEEDER_FINDPLAYER) {
- return uiInfo.numFoundPlayerServers;
- } else if (feederID == FEEDER_PLAYER_LIST) {
- if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
- uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
- UI_BuildPlayerList();
- }
- return uiInfo.playerCount;
- } else if (feederID == FEEDER_TEAM_LIST) {
- if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
- uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
- UI_BuildPlayerList();
- }
- return uiInfo.myTeamCount;
- } else if (feederID == FEEDER_MODS) {
- return uiInfo.modCount;
- } else if (feederID == FEEDER_DEMOS) {
- return uiInfo.demoCount;
- }
- return 0;
-}
-
-static const char *UI_SelectedMap(int index, int *actual) {
- int i, c;
- c = 0;
- *actual = 0;
- for (i = 0; i < uiInfo.mapCount; i++) {
- if (uiInfo.mapList[i].active) {
- if (c == index) {
- *actual = i;
- return uiInfo.mapList[i].mapName;
- } else {
- c++;
- }
- }
- }
- return "";
-}
-
-static const char *UI_SelectedHead(int index, int *actual) {
- int i, c;
- c = 0;
- *actual = 0;
- for (i = 0; i < uiInfo.characterCount; i++) {
- if (uiInfo.characterList[i].active) {
- if (c == index) {
- *actual = i;
- return uiInfo.characterList[i].name;
- } else {
- c++;
- }
- }
- }
- return "";
-}
-
-static int UI_GetIndexFromSelection(int actual) {
- int i, c;
- c = 0;
- for (i = 0; i < uiInfo.mapCount; i++) {
- if (uiInfo.mapList[i].active) {
- if (i == actual) {
- return c;
- }
- c++;
- }
- }
- return 0;
-}
-
-static void UI_UpdatePendingPings( void ) {
- trap_LAN_ResetPings(ui_netSource.integer);
- uiInfo.serverStatus.refreshActive = qtrue;
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
-
-}
-
-static const char *UI_FeederItemText(float feederID, int index, int column, qhandle_t *handle) {
- static char info[MAX_STRING_CHARS];
- static char hostname[1024];
- static char clientBuff[32];
- static int lastColumn = -1;
- static int lastTime = 0;
- *handle = -1;
- if (feederID == FEEDER_HEADS) {
- int actual;
- return UI_SelectedHead(index, &actual);
- } else if (feederID == FEEDER_Q3HEADS) {
- if (index >= 0 && index < uiInfo.q3HeadCount) {
- return uiInfo.q3HeadNames[index];
- }
- } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
- int actual;
- return UI_SelectedMap(index, &actual);
- } else if (feederID == FEEDER_SERVERS) {
- if (index >= 0 && index < uiInfo.serverStatus.numDisplayServers) {
- int ping, game, punkbuster;
- if (lastColumn != column || lastTime > uiInfo.uiDC.realTime + 5000) {
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
- lastColumn = column;
- lastTime = uiInfo.uiDC.realTime;
- }
- ping = atoi(Info_ValueForKey(info, "ping"));
- if (ping == -1) {
- // if we ever see a ping that is out of date, do a server refresh
- // UI_UpdatePendingPings();
- }
- switch (column) {
- case SORT_HOST :
- if (ping <= 0) {
- return Info_ValueForKey(info, "addr");
- } else {
- if ( ui_netSource.integer == AS_LOCAL ) {
- Com_sprintf( hostname, sizeof(hostname), "%s [%s]",
- Info_ValueForKey(info, "hostname"),
- netnames[atoi(Info_ValueForKey(info, "nettype"))] );
- return hostname;
- }
- else {
- Com_sprintf( hostname, sizeof(hostname), "%s", Info_ValueForKey(info, "hostname"));
- return hostname;
- }
- }
- case SORT_MAP : return Info_ValueForKey(info, "mapname");
- case SORT_CLIENTS :
- Com_sprintf( clientBuff, sizeof(clientBuff), "%s (%s)", Info_ValueForKey(info, "clients"), Info_ValueForKey(info, "sv_maxclients"));
- return clientBuff;
- case SORT_GAME :
- game = atoi(Info_ValueForKey(info, "gametype"));
- if (game >= 0 && game < numTeamArenaGameTypes) {
- return teamArenaGameTypes[game];
- } else {
- return "Unknown";
- }
- case SORT_PING :
- if (ping <= 0) {
- return "...";
- } else {
- return Info_ValueForKey(info, "ping");
- }
- case SORT_PUNKBUSTER:
- punkbuster = atoi(Info_ValueForKey(info, "punkbuster"));
- if ( punkbuster ) {
- return "Yes";
- } else {
- return "No";
- }
- }
- }
- } else if (feederID == FEEDER_SERVERSTATUS) {
- if ( index >= 0 && index < uiInfo.serverStatusInfo.numLines ) {
- if ( column >= 0 && column < 4 ) {
- return uiInfo.serverStatusInfo.lines[index][column];
- }
- }
- } else if (feederID == FEEDER_FINDPLAYER) {
- if ( index >= 0 && index < uiInfo.numFoundPlayerServers ) {
- //return uiInfo.foundPlayerServerAddresses[index];
- return uiInfo.foundPlayerServerNames[index];
- }
- } else if (feederID == FEEDER_PLAYER_LIST) {
- if (index >= 0 && index < uiInfo.playerCount) {
- return uiInfo.playerNames[index];
- }
- } else if (feederID == FEEDER_TEAM_LIST) {
- if (index >= 0 && index < uiInfo.myTeamCount) {
- return uiInfo.teamNames[index];
- }
- } else if (feederID == FEEDER_MODS) {
- if (index >= 0 && index < uiInfo.modCount) {
- if (uiInfo.modList[index].modDescr && *uiInfo.modList[index].modDescr) {
- return uiInfo.modList[index].modDescr;
- } else {
- return uiInfo.modList[index].modName;
- }
- }
- } else if (feederID == FEEDER_CINEMATICS) {
- if (index >= 0 && index < uiInfo.movieCount) {
- return uiInfo.movieList[index];
- }
- } else if (feederID == FEEDER_DEMOS) {
- if (index >= 0 && index < uiInfo.demoCount) {
- return uiInfo.demoList[index];
- }
- }
- return "";
-}
-
-
-static qhandle_t UI_FeederItemImage(float feederID, int index) {
- if (feederID == FEEDER_HEADS) {
- int actual;
- UI_SelectedHead(index, &actual);
- index = actual;
- if (index >= 0 && index < uiInfo.characterCount) {
- if (uiInfo.characterList[index].headImage == -1) {
- uiInfo.characterList[index].headImage = trap_R_RegisterShaderNoMip(uiInfo.characterList[index].imageName);
- }
- return uiInfo.characterList[index].headImage;
- }
- } else if (feederID == FEEDER_Q3HEADS) {
- if (index >= 0 && index < uiInfo.q3HeadCount) {
- return uiInfo.q3HeadIcons[index];
- }
- } else if (feederID == FEEDER_ALLMAPS || feederID == FEEDER_MAPS) {
- int actual;
- UI_SelectedMap(index, &actual);
- index = actual;
- if (index >= 0 && index < uiInfo.mapCount) {
- if (uiInfo.mapList[index].levelShot == -1) {
- uiInfo.mapList[index].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[index].imageName);
- }
- return uiInfo.mapList[index].levelShot;
- }
- }
- return 0;
-}
-
-static void UI_FeederSelection(float feederID, int index) {
- static char info[MAX_STRING_CHARS];
- if (feederID == FEEDER_HEADS) {
- int actual;
- UI_SelectedHead(index, &actual);
- index = actual;
- if (index >= 0 && index < uiInfo.characterCount) {
- trap_Cvar_Set( "team_model", va("%s", uiInfo.characterList[index].base));
- trap_Cvar_Set( "team_headmodel", va("*%s", uiInfo.characterList[index].name));
- updateModel = qtrue;
- }
- } else if (feederID == FEEDER_Q3HEADS) {
- if (index >= 0 && index < uiInfo.q3HeadCount) {
- trap_Cvar_Set( "model", uiInfo.q3HeadNames[index]);
- trap_Cvar_Set( "headmodel", uiInfo.q3HeadNames[index]);
- updateModel = qtrue;
- }
- } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
- int actual, map;
- map = (feederID == FEEDER_ALLMAPS) ? ui_currentNetMap.integer : ui_currentMap.integer;
- if (uiInfo.mapList[map].cinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.mapList[map].cinematic);
- uiInfo.mapList[map].cinematic = -1;
- }
- UI_SelectedMap(index, &actual);
- trap_Cvar_Set("ui_mapIndex", va("%d", index));
- ui_mapIndex.integer = index;
-
- if (feederID == FEEDER_MAPS) {
- ui_currentMap.integer = actual;
- trap_Cvar_Set("ui_currentMap", va("%d", actual));
- uiInfo.mapList[ui_currentMap.integer].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[ui_currentMap.integer].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
- trap_Cvar_Set("ui_opponentModel", uiInfo.mapList[ui_currentMap.integer].opponentName);
- updateOpponentModel = qtrue;
- } else {
- ui_currentNetMap.integer = actual;
- trap_Cvar_Set("ui_currentNetMap", va("%d", actual));
- uiInfo.mapList[ui_currentNetMap.integer].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- }
-
- } else if (feederID == FEEDER_SERVERS) {
- const char *mapName = NULL;
- uiInfo.serverStatus.currentServer = index;
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
- uiInfo.serverStatus.currentServerPreview = trap_R_RegisterShaderNoMip(va("levelshots/%s", Info_ValueForKey(info, "mapname")));
- if (uiInfo.serverStatus.currentServerCinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
- uiInfo.serverStatus.currentServerCinematic = -1;
- }
- mapName = Info_ValueForKey(info, "mapname");
- if (mapName && *mapName) {
- uiInfo.serverStatus.currentServerCinematic = trap_CIN_PlayCinematic(va("%s.roq", mapName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- }
- } else if (feederID == FEEDER_SERVERSTATUS) {
- //
- } else if (feederID == FEEDER_FINDPLAYER) {
- uiInfo.currentFoundPlayerServer = index;
- //
- if ( index < uiInfo.numFoundPlayerServers-1) {
- // build a new server status for this server
- Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
- Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
- UI_BuildServerStatus(qtrue);
- }
- } else if (feederID == FEEDER_PLAYER_LIST) {
- uiInfo.playerIndex = index;
- } else if (feederID == FEEDER_TEAM_LIST) {
- uiInfo.teamIndex = index;
- } else if (feederID == FEEDER_MODS) {
- uiInfo.modIndex = index;
- } else if (feederID == FEEDER_CINEMATICS) {
- uiInfo.movieIndex = index;
- if (uiInfo.previewMovie >= 0) {
- trap_CIN_StopCinematic(uiInfo.previewMovie);
- }
- uiInfo.previewMovie = -1;
- } else if (feederID == FEEDER_DEMOS) {
- uiInfo.demoIndex = index;
- }
-}
-
-static qboolean Team_Parse(char **p) {
- char *token;
- const char *tempStr;
- int i;
-
- token = COM_ParseExt(p, qtrue);
-
- if (token[0] != '{') {
- return qfalse;
- }
-
- while ( 1 ) {
-
- token = COM_ParseExt(p, qtrue);
-
- if (Q_stricmp(token, "}") == 0) {
- return qtrue;
- }
-
- if ( !token || token[0] == 0 ) {
- return qfalse;
- }
-
- if (token[0] == '{') {
- // seven tokens per line, team name and icon, and 5 team member names
- if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamName) || !String_Parse(p, &tempStr)) {
- return qfalse;
- }
-
-
- uiInfo.teamList[uiInfo.teamCount].imageName = tempStr;
- uiInfo.teamList[uiInfo.teamCount].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[uiInfo.teamCount].imageName);
- uiInfo.teamList[uiInfo.teamCount].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[uiInfo.teamCount].imageName));
- uiInfo.teamList[uiInfo.teamCount].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[uiInfo.teamCount].imageName));
-
- uiInfo.teamList[uiInfo.teamCount].cinematic = -1;
-
- for (i = 0; i < TEAM_MEMBERS; i++) {
- uiInfo.teamList[uiInfo.teamCount].teamMembers[i] = NULL;
- if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamMembers[i])) {
- return qfalse;
- }
- }
-
- Com_Printf("Loaded team %s with team icon %s.\n", uiInfo.teamList[uiInfo.teamCount].teamName, tempStr);
- if (uiInfo.teamCount < MAX_TEAMS) {
- uiInfo.teamCount++;
- } else {
- Com_Printf("Too many teams, last team replaced!\n");
- }
- token = COM_ParseExt(p, qtrue);
- if (token[0] != '}') {
- return qfalse;
- }
- }
- }
-
- return qfalse;
-}
-
-static qboolean Character_Parse(char **p) {
- char *token;
- const char *tempStr;
-
- token = COM_ParseExt(p, qtrue);
-
- if (token[0] != '{') {
- return qfalse;
- }
-
-
- while ( 1 ) {
- token = COM_ParseExt(p, qtrue);
-
- if (Q_stricmp(token, "}") == 0) {
- return qtrue;
- }
-
- if ( !token || token[0] == 0 ) {
- return qfalse;
- }
-
- if (token[0] == '{') {
- // two tokens per line, character name and sex
- if (!String_Parse(p, &uiInfo.characterList[uiInfo.characterCount].name) || !String_Parse(p, &tempStr)) {
- return qfalse;
- }
-
- uiInfo.characterList[uiInfo.characterCount].headImage = -1;
- uiInfo.characterList[uiInfo.characterCount].imageName = String_Alloc(va("models/players/heads/%s/icon_default.tga", uiInfo.characterList[uiInfo.characterCount].name));
-
- if (tempStr && (!Q_stricmp(tempStr, "female"))) {
- uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("Janet"));
- } else if (tempStr && (!Q_stricmp(tempStr, "male"))) {
- uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("James"));
- } else {
- uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("%s",tempStr));
- }
-
- Com_Printf("Loaded %s character %s.\n", uiInfo.characterList[uiInfo.characterCount].base, uiInfo.characterList[uiInfo.characterCount].name);
- if (uiInfo.characterCount < MAX_HEADS) {
- uiInfo.characterCount++;
- } else {
- Com_Printf("Too many characters, last character replaced!\n");
- }
-
- token = COM_ParseExt(p, qtrue);
- if (token[0] != '}') {
- return qfalse;
- }
- }
- }
-
- return qfalse;
-}
-
-
-static qboolean Alias_Parse(char **p) {
- char *token;
-
- token = COM_ParseExt(p, qtrue);
-
- if (token[0] != '{') {
- return qfalse;
- }
-
- while ( 1 ) {
- token = COM_ParseExt(p, qtrue);
-
- if (Q_stricmp(token, "}") == 0) {
- return qtrue;
- }
-
- if ( !token || token[0] == 0 ) {
- return qfalse;
- }
-
- if (token[0] == '{') {
- // three tokens per line, character name, bot alias, and preferred action a - all purpose, d - defense, o - offense
- if (!String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].name) || !String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].ai) || !String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].action)) {
- return qfalse;
- }
-
- Com_Printf("Loaded character alias %s using character ai %s.\n", uiInfo.aliasList[uiInfo.aliasCount].name, uiInfo.aliasList[uiInfo.aliasCount].ai);
- if (uiInfo.aliasCount < MAX_ALIASES) {
- uiInfo.aliasCount++;
- } else {
- Com_Printf("Too many aliases, last alias replaced!\n");
- }
-
- token = COM_ParseExt(p, qtrue);
- if (token[0] != '}') {
- return qfalse;
- }
- }
- }
-
- return qfalse;
-}
-
-
-
-// mode
-// 0 - high level parsing
-// 1 - team parsing
-// 2 - character parsing
-static void UI_ParseTeamInfo(const char *teamFile) {
- char *token;
- char *p;
- char *buff = NULL;
- //static int mode = 0; TTimo: unused
-
- buff = GetMenuBuffer(teamFile);
- if (!buff) {
- return;
- }
-
- p = buff;
-
- while ( 1 ) {
- token = COM_ParseExt( &p, qtrue );
- if( !token || token[0] == 0 || token[0] == '}') {
- break;
- }
-
- if ( Q_stricmp( token, "}" ) == 0 ) {
- break;
- }
-
- if (Q_stricmp(token, "teams") == 0) {
-
- if (Team_Parse(&p)) {
- continue;
- } else {
- break;
- }
- }
-
- if (Q_stricmp(token, "characters") == 0) {
- Character_Parse(&p);
- }
-
- if (Q_stricmp(token, "aliases") == 0) {
- Alias_Parse(&p);
- }
-
- }
-
-}
-
-
-static qboolean GameType_Parse(char **p, qboolean join) {
- char *token;
-
- token = COM_ParseExt(p, qtrue);
-
- if (token[0] != '{') {
- return qfalse;
- }
-
- if (join) {
- uiInfo.numJoinGameTypes = 0;
- } else {
- uiInfo.numGameTypes = 0;
- }
-
- while ( 1 ) {
- token = COM_ParseExt(p, qtrue);
-
- if (Q_stricmp(token, "}") == 0) {
- return qtrue;
- }
-
- if ( !token || token[0] == 0 ) {
- return qfalse;
- }
-
- if (token[0] == '{') {
- // two tokens per line, character name and sex
- if (join) {
- if (!String_Parse(p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gameType) || !Int_Parse(p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gtEnum)) {
- return qfalse;
- }
- } else {
- if (!String_Parse(p, &uiInfo.gameTypes[uiInfo.numGameTypes].gameType) || !Int_Parse(p, &uiInfo.gameTypes[uiInfo.numGameTypes].gtEnum)) {
- return qfalse;
- }
- }
-
- if (join) {
- if (uiInfo.numJoinGameTypes < MAX_GAMETYPES) {
- uiInfo.numJoinGameTypes++;
- } else {
- Com_Printf("Too many net game types, last one replace!\n");
- }
- } else {
- if (uiInfo.numGameTypes < MAX_GAMETYPES) {
- uiInfo.numGameTypes++;
- } else {
- Com_Printf("Too many game types, last one replace!\n");
- }
- }
-
- token = COM_ParseExt(p, qtrue);
- if (token[0] != '}') {
- return qfalse;
- }
- }
- }
- return qfalse;
-}
-
-static qboolean MapList_Parse(char **p) {
- char *token;
-
- token = COM_ParseExt(p, qtrue);
-
- if (token[0] != '{') {
- return qfalse;
- }
-
- uiInfo.mapCount = 0;
-
- while ( 1 ) {
- token = COM_ParseExt(p, qtrue);
-
- if (Q_stricmp(token, "}") == 0) {
- return qtrue;
- }
-
- if ( !token || token[0] == 0 ) {
- return qfalse;
- }
-
- if (token[0] == '{') {
- if (!String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].mapName) || !String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].mapLoadName)
- ||!Int_Parse(p, &uiInfo.mapList[uiInfo.mapCount].teamMembers) ) {
- return qfalse;
- }
-
- if (!String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].opponentName)) {
- return qfalse;
- }
-
- uiInfo.mapList[uiInfo.mapCount].typeBits = 0;
-
- while (1) {
- token = COM_ParseExt(p, qtrue);
- if (token[0] >= '0' && token[0] <= '9') {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << (token[0] - 0x030));
- if (!Int_Parse(p, &uiInfo.mapList[uiInfo.mapCount].timeToBeat[token[0] - 0x30])) {
- return qfalse;
- }
- } else {
- break;
- }
- }
-
- //mapList[mapCount].imageName = String_Alloc(va("levelshots/%s", mapList[mapCount].mapLoadName));
- //if (uiInfo.mapCount == 0) {
- // only load the first cinematic, selection loads the others
- // uiInfo.mapList[uiInfo.mapCount].cinematic = trap_CIN_PlayCinematic(va("%s.roq",uiInfo.mapList[uiInfo.mapCount].mapLoadName), qfalse, qfalse, qtrue, 0, 0, 0, 0);
- //}
- uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
- uiInfo.mapList[uiInfo.mapCount].levelShot = trap_R_RegisterShaderNoMip(va("levelshots/%s_small", uiInfo.mapList[uiInfo.mapCount].mapLoadName));
-
- if (uiInfo.mapCount < MAX_MAPS) {
- uiInfo.mapCount++;
- } else {
- Com_Printf("Too many maps, last one replaced!\n");
- }
- }
- }
- return qfalse;
-}
-
-static void UI_ParseGameInfo(const char *teamFile) {
- char *token;
- char *p;
- char *buff = NULL;
- //int mode = 0; TTimo: unused
-
- buff = GetMenuBuffer(teamFile);
- if (!buff) {
- return;
- }
-
- p = buff;
-
- while ( 1 ) {
- token = COM_ParseExt( &p, qtrue );
- if( !token || token[0] == 0 || token[0] == '}') {
- break;
- }
-
- if ( Q_stricmp( token, "}" ) == 0 ) {
- break;
- }
-
- if (Q_stricmp(token, "gametypes") == 0) {
-
- if (GameType_Parse(&p, qfalse)) {
- continue;
- } else {
- break;
- }
- }
-
- if (Q_stricmp(token, "joingametypes") == 0) {
-
- if (GameType_Parse(&p, qtrue)) {
- continue;
- } else {
- break;
- }
- }
-
- if (Q_stricmp(token, "maps") == 0) {
- // start a new menu
- MapList_Parse(&p);
- }
-
- }
-}
-
-static void UI_Pause(qboolean b) {
- if (b) {
- // pause the game and set the ui keycatcher
- trap_Cvar_Set( "cl_paused", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- } else {
- // unpause the game and clear the ui keycatcher
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- }
-}
-
-#ifndef MISSIONPACK
-static int UI_OwnerDraw_Width(int ownerDraw) {
- return 0;
-}
-#endif
-
-static int UI_PlayCinematic(const char *name, float x, float y, float w, float h) {
- return trap_CIN_PlayCinematic(name, x, y, w, h, (CIN_loop | CIN_silent));
-}
-
-static void UI_StopCinematic(int handle) {
- if (handle >= 0) {
- trap_CIN_StopCinematic(handle);
- } else {
- handle = abs(handle);
- if (handle == UI_MAPCINEMATIC) {
- if (uiInfo.mapList[ui_currentMap.integer].cinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.mapList[ui_currentMap.integer].cinematic);
- uiInfo.mapList[ui_currentMap.integer].cinematic = -1;
- }
- } else if (handle == UI_NETMAPCINEMATIC) {
- if (uiInfo.serverStatus.currentServerCinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
- uiInfo.serverStatus.currentServerCinematic = -1;
- }
- } else if (handle == UI_CLANCINEMATIC) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (i >= 0 && i < uiInfo.teamCount) {
- if (uiInfo.teamList[i].cinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
- uiInfo.teamList[i].cinematic = -1;
- }
- }
- }
- }
-}
-
-static void UI_DrawCinematic(int handle, float x, float y, float w, float h) {
- trap_CIN_SetExtents(handle, x, y, w, h);
- trap_CIN_DrawCinematic(handle);
-}
-
-static void UI_RunCinematicFrame(int handle) {
- trap_CIN_RunCinematic(handle);
-}
-
-
-
-/*
-=================
-PlayerModel_BuildList
-=================
-*/
-static void UI_BuildQ3Model_List( void )
-{
- int numdirs;
- int numfiles;
- char dirlist[2048];
- char filelist[2048];
- char skinname[MAX_QPATH];
- char scratch[256];
- char* dirptr;
- char* fileptr;
- int i;
- int j, k, dirty;
- int dirlen;
- int filelen;
-
- uiInfo.q3HeadCount = 0;
-
- // iterate directory of all player models
- numdirs = trap_FS_GetFileList("models/players", "/", dirlist, 2048 );
- dirptr = dirlist;
- for (i=0; i<numdirs && uiInfo.q3HeadCount < MAX_PLAYERMODELS; i++,dirptr+=dirlen+1)
- {
- dirlen = strlen(dirptr);
-
- if (dirlen && dirptr[dirlen-1]=='/') dirptr[dirlen-1]='\0';
-
- if (!strcmp(dirptr,".") || !strcmp(dirptr,".."))
- continue;
-
- // iterate all skin files in directory
- numfiles = trap_FS_GetFileList( va("models/players/%s",dirptr), "tga", filelist, 2048 );
- fileptr = filelist;
- for (j=0; j<numfiles && uiInfo.q3HeadCount < MAX_PLAYERMODELS;j++,fileptr+=filelen+1)
- {
- filelen = strlen(fileptr);
-
- COM_StripExtension(fileptr, skinname, sizeof(skinname));
-
- // look for icon_????
- if (Q_stricmpn(skinname, "icon_", 5) == 0 && !(Q_stricmp(skinname,"icon_blue") == 0 || Q_stricmp(skinname,"icon_red") == 0))
- {
- if (Q_stricmp(skinname, "icon_default") == 0) {
- Com_sprintf( scratch, sizeof(scratch), "%s", dirptr);
- } else {
- Com_sprintf( scratch, sizeof(scratch), "%s/%s",dirptr, skinname + 5);
- }
- dirty = 0;
- for(k=0;k<uiInfo.q3HeadCount;k++) {
- if (!Q_stricmp(scratch, uiInfo.q3HeadNames[uiInfo.q3HeadCount])) {
- dirty = 1;
- break;
- }
- }
- if (!dirty) {
- Com_sprintf( uiInfo.q3HeadNames[uiInfo.q3HeadCount], sizeof(uiInfo.q3HeadNames[uiInfo.q3HeadCount]), "%s", scratch);
- uiInfo.q3HeadIcons[uiInfo.q3HeadCount++] = trap_R_RegisterShaderNoMip(va("models/players/%s/%s",dirptr,skinname));
- }
- }
-
- }
- }
-
-}
-
-
-
-/*
-=================
-UI_Init
-=================
-*/
-void _UI_Init( qboolean inGameLoad ) {
- const char *menuSet;
- int start;
-
- //uiInfo.inGameLoad = inGameLoad;
-
- UI_RegisterCvars();
- UI_InitMemory();
-
- // cache redundant calulations
- trap_GetGlconfig( &uiInfo.uiDC.glconfig );
-
- // for 640x480 virtualized screen
- uiInfo.uiDC.yscale = uiInfo.uiDC.glconfig.vidHeight * (1.0/480.0);
- uiInfo.uiDC.xscale = uiInfo.uiDC.glconfig.vidWidth * (1.0/640.0);
- if ( uiInfo.uiDC.glconfig.vidWidth * 480 > uiInfo.uiDC.glconfig.vidHeight * 640 ) {
- // wide screen
- uiInfo.uiDC.bias = 0.5 * ( uiInfo.uiDC.glconfig.vidWidth - ( uiInfo.uiDC.glconfig.vidHeight * (640.0/480.0) ) );
- }
- else {
- // no wide screen
- uiInfo.uiDC.bias = 0;
- }
-
-
- //UI_Load();
- uiInfo.uiDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
- uiInfo.uiDC.setColor = &UI_SetColor;
- uiInfo.uiDC.drawHandlePic = &UI_DrawHandlePic;
- uiInfo.uiDC.drawStretchPic = &trap_R_DrawStretchPic;
- uiInfo.uiDC.drawText = &Text_Paint;
- uiInfo.uiDC.textWidth = &Text_Width;
- uiInfo.uiDC.textHeight = &Text_Height;
- uiInfo.uiDC.registerModel = &trap_R_RegisterModel;
- uiInfo.uiDC.modelBounds = &trap_R_ModelBounds;
- uiInfo.uiDC.fillRect = &UI_FillRect;
- uiInfo.uiDC.drawRect = &_UI_DrawRect;
- uiInfo.uiDC.drawSides = &_UI_DrawSides;
- uiInfo.uiDC.drawTopBottom = &_UI_DrawTopBottom;
- uiInfo.uiDC.clearScene = &trap_R_ClearScene;
- uiInfo.uiDC.drawSides = &_UI_DrawSides;
- uiInfo.uiDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
- uiInfo.uiDC.renderScene = &trap_R_RenderScene;
- uiInfo.uiDC.registerFont = &trap_R_RegisterFont;
- uiInfo.uiDC.ownerDrawItem = &UI_OwnerDraw;
- uiInfo.uiDC.getValue = &UI_GetValue;
- uiInfo.uiDC.ownerDrawVisible = &UI_OwnerDrawVisible;
- uiInfo.uiDC.runScript = &UI_RunMenuScript;
- uiInfo.uiDC.getTeamColor = &UI_GetTeamColor;
- uiInfo.uiDC.setCVar = trap_Cvar_Set;
- uiInfo.uiDC.getCVarString = trap_Cvar_VariableStringBuffer;
- uiInfo.uiDC.getCVarValue = trap_Cvar_VariableValue;
- uiInfo.uiDC.drawTextWithCursor = &Text_PaintWithCursor;
- uiInfo.uiDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
- uiInfo.uiDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
- uiInfo.uiDC.startLocalSound = &trap_S_StartLocalSound;
- uiInfo.uiDC.ownerDrawHandleKey = &UI_OwnerDrawHandleKey;
- uiInfo.uiDC.feederCount = &UI_FeederCount;
- uiInfo.uiDC.feederItemImage = &UI_FeederItemImage;
- uiInfo.uiDC.feederItemText = &UI_FeederItemText;
- uiInfo.uiDC.feederSelection = &UI_FeederSelection;
- uiInfo.uiDC.setBinding = &trap_Key_SetBinding;
- uiInfo.uiDC.getBindingBuf = &trap_Key_GetBindingBuf;
- uiInfo.uiDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
- uiInfo.uiDC.executeText = &trap_Cmd_ExecuteText;
- uiInfo.uiDC.Error = &Com_Error;
- uiInfo.uiDC.Print = &Com_Printf;
- uiInfo.uiDC.Pause = &UI_Pause;
- uiInfo.uiDC.ownerDrawWidth = &UI_OwnerDrawWidth;
- uiInfo.uiDC.registerSound = &trap_S_RegisterSound;
- uiInfo.uiDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
- uiInfo.uiDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
- uiInfo.uiDC.playCinematic = &UI_PlayCinematic;
- uiInfo.uiDC.stopCinematic = &UI_StopCinematic;
- uiInfo.uiDC.drawCinematic = &UI_DrawCinematic;
- uiInfo.uiDC.runCinematicFrame = &UI_RunCinematicFrame;
-
- Init_Display(&uiInfo.uiDC);
-
- String_Init();
-
- uiInfo.uiDC.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
- uiInfo.uiDC.whiteShader = trap_R_RegisterShaderNoMip( "white" );
-
- AssetCache();
-
- start = trap_Milliseconds();
-
- uiInfo.teamCount = 0;
- uiInfo.characterCount = 0;
- uiInfo.aliasCount = 0;
-
-#ifdef PRE_RELEASE_TADEMO
- UI_ParseTeamInfo("demoteaminfo.txt");
- UI_ParseGameInfo("demogameinfo.txt");
-#else
- UI_ParseTeamInfo("teaminfo.txt");
- UI_LoadTeams();
- UI_ParseGameInfo("gameinfo.txt");
-#endif
-
- menuSet = UI_Cvar_VariableString("ui_menuFiles");
- if (menuSet == NULL || menuSet[0] == '\0') {
- menuSet = "ui/menus.txt";
- }
-
-#if 0
- if (uiInfo.inGameLoad) {
- UI_LoadMenus("ui/ingame.txt", qtrue);
- } else {
- }
-#else
- UI_LoadMenus(menuSet, qtrue);
- UI_LoadMenus("ui/ingame.txt", qfalse);
-#endif
-
- Menus_CloseAll();
-
- trap_LAN_LoadCachedServers();
- UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
-
- UI_BuildQ3Model_List();
- UI_LoadBots();
-
- // sets defaults for ui temp cvars
- uiInfo.effectsColor = gamecodetoui[(int)trap_Cvar_VariableValue("color1")-1];
- uiInfo.currentCrosshair = (int)trap_Cvar_VariableValue("cg_drawCrosshair");
- trap_Cvar_Set("ui_mousePitch", (trap_Cvar_VariableValue("m_pitch") >= 0) ? "0" : "1");
-
- uiInfo.serverStatus.currentServerCinematic = -1;
- uiInfo.previewMovie = -1;
-
- if (trap_Cvar_VariableValue("ui_TeamArenaFirstRun") == 0) {
- trap_Cvar_Set("s_volume", "0.8");
- trap_Cvar_Set("s_musicvolume", "0.5");
- trap_Cvar_Set("ui_TeamArenaFirstRun", "1");
- }
-
- trap_Cvar_Register(NULL, "debug_protocol", "", 0 );
-
- trap_Cvar_Set("ui_actualNetGameType", va("%d", ui_netGameType.integer));
-}
-
-
-/*
-=================
-UI_KeyEvent
-=================
-*/
-void _UI_KeyEvent( int key, qboolean down ) {
-
- if (Menu_Count() > 0) {
- menuDef_t *menu = Menu_GetFocused();
- if (menu) {
- if (key == K_ESCAPE && down && !Menus_AnyFullScreenVisible()) {
- Menus_CloseAll();
- } else {
- Menu_HandleKey(menu, key, down );
- }
- } else {
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- }
- }
-
- //if ((s > 0) && (s != menu_null_sound)) {
- // trap_S_StartLocalSound( s, CHAN_LOCAL_SOUND );
- //}
-}
-
-/*
-=================
-UI_MouseEvent
-=================
-*/
-void _UI_MouseEvent( int dx, int dy )
-{
- // update mouse screen position
- uiInfo.uiDC.cursorx += dx;
- if (uiInfo.uiDC.cursorx < 0)
- uiInfo.uiDC.cursorx = 0;
- else if (uiInfo.uiDC.cursorx > SCREEN_WIDTH)
- uiInfo.uiDC.cursorx = SCREEN_WIDTH;
-
- uiInfo.uiDC.cursory += dy;
- if (uiInfo.uiDC.cursory < 0)
- uiInfo.uiDC.cursory = 0;
- else if (uiInfo.uiDC.cursory > SCREEN_HEIGHT)
- uiInfo.uiDC.cursory = SCREEN_HEIGHT;
-
- if (Menu_Count() > 0) {
- //menuDef_t *menu = Menu_GetFocused();
- //Menu_HandleMouseMove(menu, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
- Display_MouseMove(NULL, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
- }
-
-}
-
-void UI_LoadNonIngame( void ) {
- const char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
- if (menuSet == NULL || menuSet[0] == '\0') {
- menuSet = "ui/menus.txt";
- }
- UI_LoadMenus(menuSet, qfalse);
- uiInfo.inGameLoad = qfalse;
-}
-
-void _UI_SetActiveMenu( uiMenuCommand_t menu ) {
- char buf[256];
-
- // this should be the ONLY way the menu system is brought up
- // enusure minumum menu data is cached
- if (Menu_Count() > 0) {
- vec3_t v;
- v[0] = v[1] = v[2] = 0;
- switch ( menu ) {
- case UIMENU_NONE:
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
-
- return;
- case UIMENU_MAIN:
- trap_Cvar_Set( "sv_killserver", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- //trap_S_StartLocalSound( trap_S_RegisterSound("sound/misc/menu_background.wav", qfalse) , CHAN_LOCAL_SOUND );
- //trap_S_StartBackgroundTrack("sound/misc/menu_background.wav", NULL);
- if (uiInfo.inGameLoad) {
- UI_LoadNonIngame();
- }
- Menus_CloseAll();
- Menus_ActivateByName("main");
- trap_Cvar_VariableStringBuffer("com_errorMessage", buf, sizeof(buf));
- if (strlen(buf)) {
- if (!ui_singlePlayerActive.integer) {
- Menus_ActivateByName("error_popmenu");
- } else {
- trap_Cvar_Set("com_errorMessage", "");
- }
- }
- return;
- case UIMENU_TEAM:
- trap_Key_SetCatcher( KEYCATCH_UI );
- Menus_ActivateByName("team");
- return;
- case UIMENU_NEED_CD:
- // no cd check in TA
- //trap_Key_SetCatcher( KEYCATCH_UI );
- //Menus_ActivateByName("needcd");
- //UI_ConfirmMenu( "Insert the CD", NULL, NeedCDAction );
- return;
- case UIMENU_BAD_CD_KEY:
- // no cd check in TA
- //trap_Key_SetCatcher( KEYCATCH_UI );
- //Menus_ActivateByName("badcd");
- //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
- return;
- case UIMENU_POSTGAME:
- trap_Cvar_Set( "sv_killserver", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- if (uiInfo.inGameLoad) {
- UI_LoadNonIngame();
- }
- Menus_CloseAll();
- Menus_ActivateByName("endofgame");
- //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
- return;
- case UIMENU_INGAME:
- trap_Cvar_Set( "cl_paused", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- UI_BuildPlayerList();
- Menus_CloseAll();
- Menus_ActivateByName("ingame");
- return;
- }
- }
-}
-
-qboolean _UI_IsFullscreen( void ) {
- return Menus_AnyFullScreenVisible();
-}
-
-
-
-static connstate_t lastConnState;
-static char lastLoadingText[MAX_INFO_VALUE];
-
-static void UI_ReadableSize ( char *buf, int bufsize, int value )
-{
- if (value > 1024*1024*1024 ) { // gigs
- Com_sprintf( buf, bufsize, "%d", value / (1024*1024*1024) );
- Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d GB",
- (value % (1024*1024*1024))*100 / (1024*1024*1024) );
- } else if (value > 1024*1024 ) { // megs
- Com_sprintf( buf, bufsize, "%d", value / (1024*1024) );
- Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d MB",
- (value % (1024*1024))*100 / (1024*1024) );
- } else if (value > 1024 ) { // kilos
- Com_sprintf( buf, bufsize, "%d KB", value / 1024 );
- } else { // bytes
- Com_sprintf( buf, bufsize, "%d bytes", value );
- }
-}
-
-// Assumes time is in msec
-static void UI_PrintTime ( char *buf, int bufsize, int time ) {
- time /= 1000; // change to seconds
-
- if (time > 3600) { // in the hours range
- Com_sprintf( buf, bufsize, "%d hr %d min", time / 3600, (time % 3600) / 60 );
- } else if (time > 60) { // mins
- Com_sprintf( buf, bufsize, "%d min %d sec", time / 60, time % 60 );
- } else { // secs
- Com_sprintf( buf, bufsize, "%d sec", time );
- }
-}
-
-void Text_PaintCenter(float x, float y, float scale, vec4_t color, const char *text, float adjust) {
- int len = Text_Width(text, scale, 0);
- Text_Paint(x - len / 2, y, scale, color, text, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
-}
-
-void Text_PaintCenter_AutoWrapped(float x, float y, float xmax, float ystep, float scale, vec4_t color, const char *str, float adjust) {
- int width;
- char *s1,*s2,*s3;
- char c_bcp;
- char buf[1024];
-
- if (!str || str[0]=='\0')
- return;
-
- Q_strncpyz(buf, str, sizeof(buf));
- s1 = s2 = s3 = buf;
-
- while (1) {
- do {
- s3++;
- } while (*s3!=' ' && *s3!='\0');
- c_bcp = *s3;
- *s3 = '\0';
- width = Text_Width(s1, scale, 0);
- *s3 = c_bcp;
- if (width > xmax) {
- if (s1==s2)
- {
- // fuck, don't have a clean cut, we'll overflow
- s2 = s3;
- }
- *s2 = '\0';
- Text_PaintCenter(x, y, scale, color, s1, adjust);
- y += ystep;
- if (c_bcp == '\0')
- {
- // that was the last word
- // we could start a new loop, but that wouldn't be much use
- // even if the word is too long, we would overflow it (see above)
- // so just print it now if needed
- s2++;
- if (*s2 != '\0') // if we are printing an overflowing line we have s2 == s3
- Text_PaintCenter(x, y, scale, color, s2, adjust);
- break;
- }
- s2++;
- s1 = s2;
- s3 = s2;
- }
- else
- {
- s2 = s3;
- if (c_bcp == '\0') // we reached the end
- {
- Text_PaintCenter(x, y, scale, color, s1, adjust);
- break;
- }
- }
- }
-}
-
-static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, float yStart, float scale ) {
- static char dlText[] = "Downloading:";
- static char etaText[] = "Estimated time left:";
- static char xferText[] = "Transfer rate:";
-
- int downloadSize, downloadCount, downloadTime;
- char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64];
- int xferRate;
- int leftWidth;
- const char *s;
-
- downloadSize = trap_Cvar_VariableValue( "cl_downloadSize" );
- downloadCount = trap_Cvar_VariableValue( "cl_downloadCount" );
- downloadTime = trap_Cvar_VariableValue( "cl_downloadTime" );
-
- leftWidth = 320;
-
- UI_SetColor(colorWhite);
- Text_PaintCenter(centerPoint, yStart + 112, scale, colorWhite, dlText, 0);
- Text_PaintCenter(centerPoint, yStart + 192, scale, colorWhite, etaText, 0);
- Text_PaintCenter(centerPoint, yStart + 248, scale, colorWhite, xferText, 0);
-
- if (downloadSize > 0) {
- s = va( "%s (%d%%)", downloadName,
- (int)( (float)downloadCount * 100.0f / downloadSize ) );
- } else {
- s = downloadName;
- }
-
- Text_PaintCenter(centerPoint, yStart+136, scale, colorWhite, s, 0);
-
- UI_ReadableSize( dlSizeBuf, sizeof dlSizeBuf, downloadCount );
- UI_ReadableSize( totalSizeBuf, sizeof totalSizeBuf, downloadSize );
-
- if (downloadCount < 4096 || !downloadTime) {
- Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
- Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
- } else {
- if ((uiInfo.uiDC.realTime - downloadTime) / 1000) {
- xferRate = downloadCount / ((uiInfo.uiDC.realTime - downloadTime) / 1000);
- } else {
- xferRate = 0;
- }
- UI_ReadableSize( xferRateBuf, sizeof xferRateBuf, xferRate );
-
- // Extrapolate estimated completion time
- if (downloadSize && xferRate) {
- int n = downloadSize / xferRate; // estimated time for entire d/l in secs
-
- // We do it in K (/1024) because we'd overflow around 4MB
- UI_PrintTime ( dlTimeBuf, sizeof dlTimeBuf,
- (n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000);
-
- Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, dlTimeBuf, 0);
- Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
- } else {
- Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
- if (downloadSize) {
- Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
- } else {
- Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s copied)", dlSizeBuf), 0);
- }
- }
-
- if (xferRate) {
- Text_PaintCenter(leftWidth, yStart+272, scale, colorWhite, va("%s/Sec", xferRateBuf), 0);
- }
- }
-}
-
-/*
-========================
-UI_DrawConnectScreen
-
-This will also be overlaid on the cgame info screen during loading
-to prevent it from blinking away too rapidly on local or lan games.
-========================
-*/
-void UI_DrawConnectScreen( qboolean overlay ) {
- char *s;
- uiClientState_t cstate;
- char info[MAX_INFO_VALUE];
- char text[256];
- float centerPoint, yStart, scale;
-
- menuDef_t *menu = Menus_FindByName("Connect");
-
-
- if ( !overlay && menu ) {
- Menu_Paint(menu, qtrue);
- }
-
- if (!overlay) {
- centerPoint = 320;
- yStart = 130;
- scale = 0.5f;
- } else {
- centerPoint = 320;
- yStart = 32;
- scale = 0.6f;
- return;
- }
-
- // see what information we should display
- trap_GetClientState( &cstate );
-
- info[0] = '\0';
- if( trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ) ) {
- Text_PaintCenter(centerPoint, yStart, scale, colorWhite, va( "Loading %s", Info_ValueForKey( info, "mapname" )), 0);
- }
-
- if (!Q_stricmp(cstate.servername,"localhost")) {
- Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite, va("Starting up..."), ITEM_TEXTSTYLE_SHADOWEDMORE);
- } else {
- strcpy(text, va("Connecting to %s", cstate.servername));
- Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite,text , ITEM_TEXTSTYLE_SHADOWEDMORE);
- }
-
- // display global MOTD at bottom
- Text_PaintCenter(centerPoint, 600, scale, colorWhite, Info_ValueForKey( cstate.updateInfoString, "motd" ), 0);
- // print any server info (server full, bad version, etc)
- if ( cstate.connState < CA_CONNECTED ) {
- Text_PaintCenter_AutoWrapped(centerPoint, yStart + 176, 630, 20, scale, colorWhite, cstate.messageString, 0);
- }
-
- if ( lastConnState > cstate.connState ) {
- lastLoadingText[0] = '\0';
- }
- lastConnState = cstate.connState;
-
- switch ( cstate.connState ) {
- case CA_CONNECTING:
- s = va("Awaiting connection...%i", cstate.connectPacketCount);
- break;
- case CA_CHALLENGING:
- s = va("Awaiting challenge...%i", cstate.connectPacketCount);
- break;
- case CA_CONNECTED: {
- char downloadName[MAX_INFO_VALUE];
-
- trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof(downloadName) );
- if (*downloadName) {
- UI_DisplayDownloadInfo( downloadName, centerPoint, yStart, scale );
- return;
- }
- }
- s = "Awaiting gamestate...";
- break;
- case CA_LOADING:
- return;
- case CA_PRIMED:
- return;
- default:
- return;
- }
-
-
- if (Q_stricmp(cstate.servername,"localhost")) {
- Text_PaintCenter(centerPoint, yStart + 80, scale, colorWhite, s, 0);
- }
-
- // password required / connection rejected information goes here
-}
-
-
-/*
-================
-cvars
-================
-*/
-
-typedef struct {
- vmCvar_t *vmCvar;
- char *cvarName;
- char *defaultString;
- int cvarFlags;
-} cvarTable_t;
-
-vmCvar_t ui_ffa_fraglimit;
-vmCvar_t ui_ffa_timelimit;
-
-vmCvar_t ui_tourney_fraglimit;
-vmCvar_t ui_tourney_timelimit;
-
-vmCvar_t ui_team_fraglimit;
-vmCvar_t ui_team_timelimit;
-vmCvar_t ui_team_friendly;
-
-vmCvar_t ui_ctf_capturelimit;
-vmCvar_t ui_ctf_timelimit;
-vmCvar_t ui_ctf_friendly;
-
-vmCvar_t ui_arenasFile;
-vmCvar_t ui_botsFile;
-vmCvar_t ui_spScores1;
-vmCvar_t ui_spScores2;
-vmCvar_t ui_spScores3;
-vmCvar_t ui_spScores4;
-vmCvar_t ui_spScores5;
-vmCvar_t ui_spAwards;
-vmCvar_t ui_spVideos;
-vmCvar_t ui_spSkill;
-
-vmCvar_t ui_spSelection;
-
-vmCvar_t ui_browserMaster;
-vmCvar_t ui_browserGameType;
-vmCvar_t ui_browserSortKey;
-vmCvar_t ui_browserShowFull;
-vmCvar_t ui_browserShowEmpty;
-
-vmCvar_t ui_brassTime;
-vmCvar_t ui_drawCrosshair;
-vmCvar_t ui_drawCrosshairNames;
-vmCvar_t ui_marks;
-
-vmCvar_t ui_server1;
-vmCvar_t ui_server2;
-vmCvar_t ui_server3;
-vmCvar_t ui_server4;
-vmCvar_t ui_server5;
-vmCvar_t ui_server6;
-vmCvar_t ui_server7;
-vmCvar_t ui_server8;
-vmCvar_t ui_server9;
-vmCvar_t ui_server10;
-vmCvar_t ui_server11;
-vmCvar_t ui_server12;
-vmCvar_t ui_server13;
-vmCvar_t ui_server14;
-vmCvar_t ui_server15;
-vmCvar_t ui_server16;
-
-vmCvar_t ui_cdkeychecked;
-
-vmCvar_t ui_redteam;
-vmCvar_t ui_redteam1;
-vmCvar_t ui_redteam2;
-vmCvar_t ui_redteam3;
-vmCvar_t ui_redteam4;
-vmCvar_t ui_redteam5;
-vmCvar_t ui_blueteam;
-vmCvar_t ui_blueteam1;
-vmCvar_t ui_blueteam2;
-vmCvar_t ui_blueteam3;
-vmCvar_t ui_blueteam4;
-vmCvar_t ui_blueteam5;
-vmCvar_t ui_teamName;
-vmCvar_t ui_dedicated;
-vmCvar_t ui_gameType;
-vmCvar_t ui_netGameType;
-vmCvar_t ui_actualNetGameType;
-vmCvar_t ui_joinGameType;
-vmCvar_t ui_netSource;
-vmCvar_t ui_serverFilterType;
-vmCvar_t ui_opponentName;
-vmCvar_t ui_menuFiles;
-vmCvar_t ui_currentTier;
-vmCvar_t ui_currentMap;
-vmCvar_t ui_currentNetMap;
-vmCvar_t ui_mapIndex;
-vmCvar_t ui_currentOpponent;
-vmCvar_t ui_selectedPlayer;
-vmCvar_t ui_selectedPlayerName;
-vmCvar_t ui_lastServerRefresh_0;
-vmCvar_t ui_lastServerRefresh_1;
-vmCvar_t ui_lastServerRefresh_2;
-vmCvar_t ui_lastServerRefresh_3;
-vmCvar_t ui_singlePlayerActive;
-vmCvar_t ui_scoreAccuracy;
-vmCvar_t ui_scoreImpressives;
-vmCvar_t ui_scoreExcellents;
-vmCvar_t ui_scoreCaptures;
-vmCvar_t ui_scoreDefends;
-vmCvar_t ui_scoreAssists;
-vmCvar_t ui_scoreGauntlets;
-vmCvar_t ui_scoreScore;
-vmCvar_t ui_scorePerfect;
-vmCvar_t ui_scoreTeam;
-vmCvar_t ui_scoreBase;
-vmCvar_t ui_scoreTimeBonus;
-vmCvar_t ui_scoreSkillBonus;
-vmCvar_t ui_scoreShutoutBonus;
-vmCvar_t ui_scoreTime;
-vmCvar_t ui_captureLimit;
-vmCvar_t ui_fragLimit;
-vmCvar_t ui_smallFont;
-vmCvar_t ui_bigFont;
-vmCvar_t ui_findPlayer;
-vmCvar_t ui_Q3Model;
-vmCvar_t ui_hudFiles;
-vmCvar_t ui_recordSPDemo;
-vmCvar_t ui_realCaptureLimit;
-vmCvar_t ui_realWarmUp;
-vmCvar_t ui_serverStatusTimeOut;
-
-static cvarTable_t cvarTable[] = {
- { &ui_ffa_fraglimit, "ui_ffa_fraglimit", "20", CVAR_ARCHIVE },
- { &ui_ffa_timelimit, "ui_ffa_timelimit", "0", CVAR_ARCHIVE },
-
- { &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE },
- { &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE },
-
- { &ui_team_fraglimit, "ui_team_fraglimit", "0", CVAR_ARCHIVE },
- { &ui_team_timelimit, "ui_team_timelimit", "20", CVAR_ARCHIVE },
- { &ui_team_friendly, "ui_team_friendly", "1", CVAR_ARCHIVE },
-
- { &ui_ctf_capturelimit, "ui_ctf_capturelimit", "8", CVAR_ARCHIVE },
- { &ui_ctf_timelimit, "ui_ctf_timelimit", "30", CVAR_ARCHIVE },
- { &ui_ctf_friendly, "ui_ctf_friendly", "0", CVAR_ARCHIVE },
-
- { &ui_arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM },
- { &ui_botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM },
- { &ui_spScores1, "g_spScores1", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores2, "g_spScores2", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores3, "g_spScores3", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores4, "g_spScores4", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores5, "g_spScores5", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spAwards, "g_spAwards", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spVideos, "g_spVideos", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spSkill, "g_spSkill", "2", CVAR_ARCHIVE },
-
- { &ui_spSelection, "ui_spSelection", "", CVAR_ROM },
-
- { &ui_browserMaster, "ui_browserMaster", "0", CVAR_ARCHIVE },
- { &ui_browserGameType, "ui_browserGameType", "0", CVAR_ARCHIVE },
- { &ui_browserSortKey, "ui_browserSortKey", "4", CVAR_ARCHIVE },
- { &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE },
- { &ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE },
-
- { &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
- { &ui_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
- { &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
- { &ui_marks, "cg_marks", "1", CVAR_ARCHIVE },
-
- { &ui_server1, "server1", "", CVAR_ARCHIVE },
- { &ui_server2, "server2", "", CVAR_ARCHIVE },
- { &ui_server3, "server3", "", CVAR_ARCHIVE },
- { &ui_server4, "server4", "", CVAR_ARCHIVE },
- { &ui_server5, "server5", "", CVAR_ARCHIVE },
- { &ui_server6, "server6", "", CVAR_ARCHIVE },
- { &ui_server7, "server7", "", CVAR_ARCHIVE },
- { &ui_server8, "server8", "", CVAR_ARCHIVE },
- { &ui_server9, "server9", "", CVAR_ARCHIVE },
- { &ui_server10, "server10", "", CVAR_ARCHIVE },
- { &ui_server11, "server11", "", CVAR_ARCHIVE },
- { &ui_server12, "server12", "", CVAR_ARCHIVE },
- { &ui_server13, "server13", "", CVAR_ARCHIVE },
- { &ui_server14, "server14", "", CVAR_ARCHIVE },
- { &ui_server15, "server15", "", CVAR_ARCHIVE },
- { &ui_server16, "server16", "", CVAR_ARCHIVE },
- { &ui_cdkeychecked, "ui_cdkeychecked", "0", CVAR_ROM },
- { &ui_new, "ui_new", "0", CVAR_TEMP },
- { &ui_debug, "ui_debug", "0", CVAR_TEMP },
- { &ui_initialized, "ui_initialized", "0", CVAR_TEMP },
- { &ui_teamName, "ui_teamName", "Pagans", CVAR_ARCHIVE },
- { &ui_opponentName, "ui_opponentName", "Stroggs", CVAR_ARCHIVE },
- { &ui_redteam, "ui_redteam", "Pagans", CVAR_ARCHIVE },
- { &ui_blueteam, "ui_blueteam", "Stroggs", CVAR_ARCHIVE },
- { &ui_dedicated, "ui_dedicated", "0", CVAR_ARCHIVE },
- { &ui_gameType, "ui_gametype", "3", CVAR_ARCHIVE },
- { &ui_joinGameType, "ui_joinGametype", "0", CVAR_ARCHIVE },
- { &ui_netGameType, "ui_netGametype", "3", CVAR_ARCHIVE },
- { &ui_actualNetGameType, "ui_actualNetGametype", "3", CVAR_ARCHIVE },
- { &ui_redteam1, "ui_redteam1", "0", CVAR_ARCHIVE },
- { &ui_redteam2, "ui_redteam2", "0", CVAR_ARCHIVE },
- { &ui_redteam3, "ui_redteam3", "0", CVAR_ARCHIVE },
- { &ui_redteam4, "ui_redteam4", "0", CVAR_ARCHIVE },
- { &ui_redteam5, "ui_redteam5", "0", CVAR_ARCHIVE },
- { &ui_blueteam1, "ui_blueteam1", "0", CVAR_ARCHIVE },
- { &ui_blueteam2, "ui_blueteam2", "0", CVAR_ARCHIVE },
- { &ui_blueteam3, "ui_blueteam3", "0", CVAR_ARCHIVE },
- { &ui_blueteam4, "ui_blueteam4", "0", CVAR_ARCHIVE },
- { &ui_blueteam5, "ui_blueteam5", "0", CVAR_ARCHIVE },
- { &ui_netSource, "ui_netSource", "0", CVAR_ARCHIVE },
- { &ui_menuFiles, "ui_menuFiles", "ui/menus.txt", CVAR_ARCHIVE },
- { &ui_currentTier, "ui_currentTier", "0", CVAR_ARCHIVE },
- { &ui_currentMap, "ui_currentMap", "0", CVAR_ARCHIVE },
- { &ui_currentNetMap, "ui_currentNetMap", "0", CVAR_ARCHIVE },
- { &ui_mapIndex, "ui_mapIndex", "0", CVAR_ARCHIVE },
- { &ui_currentOpponent, "ui_currentOpponent", "0", CVAR_ARCHIVE },
- { &ui_selectedPlayer, "cg_selectedPlayer", "0", CVAR_ARCHIVE},
- { &ui_selectedPlayerName, "cg_selectedPlayerName", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_0, "ui_lastServerRefresh_0", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_1, "ui_lastServerRefresh_1", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_2, "ui_lastServerRefresh_2", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_3, "ui_lastServerRefresh_3", "", CVAR_ARCHIVE},
- { &ui_singlePlayerActive, "ui_singlePlayerActive", "0", 0},
- { &ui_scoreAccuracy, "ui_scoreAccuracy", "0", CVAR_ARCHIVE},
- { &ui_scoreImpressives, "ui_scoreImpressives", "0", CVAR_ARCHIVE},
- { &ui_scoreExcellents, "ui_scoreExcellents", "0", CVAR_ARCHIVE},
- { &ui_scoreCaptures, "ui_scoreCaptures", "0", CVAR_ARCHIVE},
- { &ui_scoreDefends, "ui_scoreDefends", "0", CVAR_ARCHIVE},
- { &ui_scoreAssists, "ui_scoreAssists", "0", CVAR_ARCHIVE},
- { &ui_scoreGauntlets, "ui_scoreGauntlets", "0",CVAR_ARCHIVE},
- { &ui_scoreScore, "ui_scoreScore", "0", CVAR_ARCHIVE},
- { &ui_scorePerfect, "ui_scorePerfect", "0", CVAR_ARCHIVE},
- { &ui_scoreTeam, "ui_scoreTeam", "0 to 0", CVAR_ARCHIVE},
- { &ui_scoreBase, "ui_scoreBase", "0", CVAR_ARCHIVE},
- { &ui_scoreTime, "ui_scoreTime", "00:00", CVAR_ARCHIVE},
- { &ui_scoreTimeBonus, "ui_scoreTimeBonus", "0", CVAR_ARCHIVE},
- { &ui_scoreSkillBonus, "ui_scoreSkillBonus", "0", CVAR_ARCHIVE},
- { &ui_scoreShutoutBonus, "ui_scoreShutoutBonus", "0", CVAR_ARCHIVE},
- { &ui_fragLimit, "ui_fragLimit", "10", 0},
- { &ui_captureLimit, "ui_captureLimit", "5", 0},
- { &ui_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE},
- { &ui_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE},
- { &ui_findPlayer, "ui_findPlayer", "Sarge", CVAR_ARCHIVE},
- { &ui_Q3Model, "ui_q3model", "0", CVAR_ARCHIVE},
- { &ui_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
- { &ui_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE},
- { &ui_teamArenaFirstRun, "ui_teamArenaFirstRun", "0", CVAR_ARCHIVE},
- { &ui_realWarmUp, "g_warmup", "20", CVAR_ARCHIVE},
- { &ui_realCaptureLimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART},
- { &ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE},
-
-};
-
-static int cvarTableSize = sizeof(cvarTable) / sizeof(cvarTable[0]);
-
-
-/*
-=================
-UI_RegisterCvars
-=================
-*/
-void UI_RegisterCvars( void ) {
- int i;
- cvarTable_t *cv;
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );
- }
-}
-
-/*
-=================
-UI_UpdateCvars
-=================
-*/
-void UI_UpdateCvars( void ) {
- int i;
- cvarTable_t *cv;
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Update( cv->vmCvar );
- }
-}
-
-
-/*
-=================
-ArenaServers_StopRefresh
-=================
-*/
-static void UI_StopServerRefresh( void )
-{
- int count;
-
- if (!uiInfo.serverStatus.refreshActive) {
- // not currently refreshing
- return;
- }
- uiInfo.serverStatus.refreshActive = qfalse;
- Com_Printf("%d servers listed in browser with %d players.\n",
- uiInfo.serverStatus.numDisplayServers,
- uiInfo.serverStatus.numPlayersOnServers);
- count = trap_LAN_GetServerCount(ui_netSource.integer);
- if (count - uiInfo.serverStatus.numDisplayServers > 0) {
- Com_Printf("%d servers not listed due to packet loss or pings higher than %d\n",
- count - uiInfo.serverStatus.numDisplayServers,
- (int) trap_Cvar_VariableValue("cl_maxPing"));
- }
-
-}
-
-/*
-=================
-ArenaServers_MaxPing
-=================
-*/
-#ifndef MISSIONPACK
-static int ArenaServers_MaxPing( void ) {
- int maxPing;
-
- maxPing = (int)trap_Cvar_VariableValue( "cl_maxPing" );
- if( maxPing < 100 ) {
- maxPing = 100;
- }
- return maxPing;
-}
-#endif
-
-/*
-=================
-UI_DoServerRefresh
-=================
-*/
-static void UI_DoServerRefresh( void )
-{
- qboolean wait = qfalse;
-
- if (!uiInfo.serverStatus.refreshActive) {
- return;
- }
- if (ui_netSource.integer != AS_FAVORITES) {
- if (ui_netSource.integer == AS_LOCAL) {
- if (!trap_LAN_GetServerCount(ui_netSource.integer)) {
- wait = qtrue;
- }
- } else {
- if (trap_LAN_GetServerCount(ui_netSource.integer) < 0) {
- wait = qtrue;
- }
- }
- }
-
- if (uiInfo.uiDC.realTime < uiInfo.serverStatus.refreshtime) {
- if (wait) {
- return;
- }
- }
-
- // if still trying to retrieve pings
- if (trap_LAN_UpdateVisiblePings(ui_netSource.integer)) {
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
- } else if (!wait) {
- // get the last servers in the list
- UI_BuildServerDisplayList(2);
- // stop the refresh
- UI_StopServerRefresh();
- }
- //
- UI_BuildServerDisplayList(qfalse);
-}
-
-/*
-=================
-UI_StartServerRefresh
-=================
-*/
-static void UI_StartServerRefresh(qboolean full)
-{
- char *ptr;
-
- qtime_t q;
- trap_RealTime(&q);
- trap_Cvar_Set( va("ui_lastServerRefresh_%i", ui_netSource.integer), va("%s-%i, %i at %i:%i", MonthAbbrev[q.tm_mon],q.tm_mday, 1900+q.tm_year,q.tm_hour,q.tm_min));
-
- if (!full) {
- UI_UpdatePendingPings();
- return;
- }
-
- uiInfo.serverStatus.refreshActive = qtrue;
- uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 1000;
- // clear number of displayed servers
- uiInfo.serverStatus.numDisplayServers = 0;
- uiInfo.serverStatus.numPlayersOnServers = 0;
- // mark all servers as visible so we store ping updates for them
- trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
- // reset all the pings
- trap_LAN_ResetPings(ui_netSource.integer);
- //
- if( ui_netSource.integer == AS_LOCAL ) {
- trap_Cmd_ExecuteText( EXEC_NOW, "localservers\n" );
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
- return;
- }
-
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 5000;
- if( ui_netSource.integer == AS_GLOBAL ) {
-
- ptr = UI_Cvar_VariableString("debug_protocol");
- if (strlen(ptr)) {
- trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers 0 %s full empty\n", ptr));
- }
- else {
- trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers 0 %d full empty\n", (int)trap_Cvar_VariableValue( "protocol" ) ) );
- }
- }
-}
-
diff --git a/engine/code/ui/ui_players.c b/engine/code/ui/ui_players.c
deleted file mode 100644
index 59a339c..0000000
--- a/engine/code/ui/ui_players.c
+++ /dev/null
@@ -1,1379 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// ui_players.c
-
-#include "ui_local.h"
-
-
-#define UI_TIMER_GESTURE 2300
-#define UI_TIMER_JUMP 1000
-#define UI_TIMER_LAND 130
-#define UI_TIMER_WEAPON_SWITCH 300
-#define UI_TIMER_ATTACK 500
-#define UI_TIMER_MUZZLE_FLASH 20
-#define UI_TIMER_WEAPON_DELAY 250
-
-#define JUMP_HEIGHT 56
-
-#define SWINGSPEED 0.3f
-
-#define SPIN_SPEED 0.9f
-#define COAST_TIME 1000
-
-
-static int dp_realtime;
-static float jumpHeight;
-sfxHandle_t weaponChangeSound;
-
-
-/*
-===============
-UI_PlayerInfo_SetWeapon
-===============
-*/
-static void UI_PlayerInfo_SetWeapon( playerInfo_t *pi, weapon_t weaponNum ) {
- gitem_t * item;
- char path[MAX_QPATH];
-
- pi->currentWeapon = weaponNum;
-tryagain:
- pi->realWeapon = weaponNum;
- pi->weaponModel = 0;
- pi->barrelModel = 0;
- pi->flashModel = 0;
-
- if ( weaponNum == WP_NONE ) {
- return;
- }
-
- for ( item = bg_itemlist + 1; item->classname ; item++ ) {
- if ( item->giType != IT_WEAPON ) {
- continue;
- }
- if ( item->giTag == weaponNum ) {
- break;
- }
- }
-
- if ( item->classname ) {
- pi->weaponModel = trap_R_RegisterModel( item->world_model[0] );
- }
-
- if( pi->weaponModel == 0 ) {
- if( weaponNum == WP_MACHINEGUN ) {
- weaponNum = WP_NONE;
- goto tryagain;
- }
- weaponNum = WP_MACHINEGUN;
- goto tryagain;
- }
-
- if ( weaponNum == WP_MACHINEGUN || weaponNum == WP_GAUNTLET || weaponNum == WP_BFG ) {
- strcpy( path, item->world_model[0] );
- COM_StripExtension(path, path, sizeof(path));
- strcat( path, "_barrel.md3" );
- pi->barrelModel = trap_R_RegisterModel( path );
- }
-
- strcpy( path, item->world_model[0] );
- COM_StripExtension(path, path, sizeof(path));
- strcat( path, "_flash.md3" );
- pi->flashModel = trap_R_RegisterModel( path );
-
- switch( weaponNum ) {
- case WP_GAUNTLET:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_MACHINEGUN:
- MAKERGB( pi->flashDlightColor, 1, 1, 0 );
- break;
-
- case WP_SHOTGUN:
- MAKERGB( pi->flashDlightColor, 1, 1, 0 );
- break;
-
- case WP_GRENADE_LAUNCHER:
- MAKERGB( pi->flashDlightColor, 1, 0.7f, 0.5f );
- break;
-
- case WP_ROCKET_LAUNCHER:
- MAKERGB( pi->flashDlightColor, 1, 0.75f, 0 );
- break;
-
- case WP_LIGHTNING:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_RAILGUN:
- MAKERGB( pi->flashDlightColor, 1, 0.5f, 0 );
- break;
-
- case WP_PLASMAGUN:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_BFG:
- MAKERGB( pi->flashDlightColor, 1, 0.7f, 1 );
- break;
-
- case WP_GRAPPLING_HOOK:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- default:
- MAKERGB( pi->flashDlightColor, 1, 1, 1 );
- break;
- }
-}
-
-
-/*
-===============
-UI_ForceLegsAnim
-===============
-*/
-static void UI_ForceLegsAnim( playerInfo_t *pi, int anim ) {
- pi->legsAnim = ( ( pi->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-
- if ( anim == LEGS_JUMP ) {
- pi->legsAnimationTimer = UI_TIMER_JUMP;
- }
-}
-
-
-/*
-===============
-UI_SetLegsAnim
-===============
-*/
-static void UI_SetLegsAnim( playerInfo_t *pi, int anim ) {
- if ( pi->pendingLegsAnim ) {
- anim = pi->pendingLegsAnim;
- pi->pendingLegsAnim = 0;
- }
- UI_ForceLegsAnim( pi, anim );
-}
-
-
-/*
-===============
-UI_ForceTorsoAnim
-===============
-*/
-static void UI_ForceTorsoAnim( playerInfo_t *pi, int anim ) {
- pi->torsoAnim = ( ( pi->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-
- if ( anim == TORSO_GESTURE ) {
- pi->torsoAnimationTimer = UI_TIMER_GESTURE;
- }
-
- if ( anim == TORSO_ATTACK || anim == TORSO_ATTACK2 ) {
- pi->torsoAnimationTimer = UI_TIMER_ATTACK;
- }
-}
-
-
-/*
-===============
-UI_SetTorsoAnim
-===============
-*/
-static void UI_SetTorsoAnim( playerInfo_t *pi, int anim ) {
- if ( pi->pendingTorsoAnim ) {
- anim = pi->pendingTorsoAnim;
- pi->pendingTorsoAnim = 0;
- }
-
- UI_ForceTorsoAnim( pi, anim );
-}
-
-
-/*
-===============
-UI_TorsoSequencing
-===============
-*/
-static void UI_TorsoSequencing( playerInfo_t *pi ) {
- int currentAnim;
-
- currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
-
- if ( pi->weapon != pi->currentWeapon ) {
- if ( currentAnim != TORSO_DROP ) {
- pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
- UI_ForceTorsoAnim( pi, TORSO_DROP );
- }
- }
-
- if ( pi->torsoAnimationTimer > 0 ) {
- return;
- }
-
- if( currentAnim == TORSO_GESTURE ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-
- if( currentAnim == TORSO_ATTACK || currentAnim == TORSO_ATTACK2 ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-
- if ( currentAnim == TORSO_DROP ) {
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
- pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
- UI_ForceTorsoAnim( pi, TORSO_RAISE );
- return;
- }
-
- if ( currentAnim == TORSO_RAISE ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-}
-
-
-/*
-===============
-UI_LegsSequencing
-===============
-*/
-static void UI_LegsSequencing( playerInfo_t *pi ) {
- int currentAnim;
-
- currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
-
- if ( pi->legsAnimationTimer > 0 ) {
- if ( currentAnim == LEGS_JUMP ) {
- jumpHeight = JUMP_HEIGHT * sin( M_PI * ( UI_TIMER_JUMP - pi->legsAnimationTimer ) / UI_TIMER_JUMP );
- }
- return;
- }
-
- if ( currentAnim == LEGS_JUMP ) {
- UI_ForceLegsAnim( pi, LEGS_LAND );
- pi->legsAnimationTimer = UI_TIMER_LAND;
- jumpHeight = 0;
- return;
- }
-
- if ( currentAnim == LEGS_LAND ) {
- UI_SetLegsAnim( pi, LEGS_IDLE );
- return;
- }
-}
-
-
-/*
-======================
-UI_PositionEntityOnTag
-======================
-*/
-static void UI_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- clipHandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
-
- // lerp the tag
- trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // cast away const because of compiler problems
- MatrixMultiply( lerped.axis, ((refEntity_t*)parent)->axis, entity->axis );
- entity->backlerp = parent->backlerp;
-}
-
-
-/*
-======================
-UI_PositionRotatedEntityOnTag
-======================
-*/
-static void UI_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- clipHandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
- vec3_t tempAxis[3];
-
- // lerp the tag
- trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // cast away const because of compiler problems
- MatrixMultiply( entity->axis, ((refEntity_t *)parent)->axis, tempAxis );
- MatrixMultiply( lerped.axis, tempAxis, entity->axis );
-}
-
-
-/*
-===============
-UI_SetLerpFrameAnimation
-===============
-*/
-static void UI_SetLerpFrameAnimation( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
- animation_t *anim;
-
- lf->animationNumber = newAnimation;
- newAnimation &= ~ANIM_TOGGLEBIT;
-
- if ( newAnimation < 0 || newAnimation >= MAX_ANIMATIONS ) {
- trap_Error( va("Bad animation number: %i", newAnimation) );
- }
-
- anim = &ci->animations[ newAnimation ];
-
- lf->animation = anim;
- lf->animationTime = lf->frameTime + anim->initialLerp;
-}
-
-
-/*
-===============
-UI_RunLerpFrame
-===============
-*/
-static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
- int f;
- animation_t *anim;
-
- // see if the animation sequence is switching
- if ( newAnimation != lf->animationNumber || !lf->animation ) {
- UI_SetLerpFrameAnimation( ci, lf, newAnimation );
- }
-
- // if we have passed the current frame, move it to
- // oldFrame and calculate a new frame
- if ( dp_realtime >= lf->frameTime ) {
- lf->oldFrame = lf->frame;
- lf->oldFrameTime = lf->frameTime;
-
- // get the next frame based on the animation
- anim = lf->animation;
- if ( dp_realtime < lf->animationTime ) {
- lf->frameTime = lf->animationTime; // initial lerp
- } else {
- lf->frameTime = lf->oldFrameTime + anim->frameLerp;
- }
- f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
- if ( f >= anim->numFrames ) {
- f -= anim->numFrames;
- if ( anim->loopFrames ) {
- f %= anim->loopFrames;
- f += anim->numFrames - anim->loopFrames;
- } else {
- f = anim->numFrames - 1;
- // the animation is stuck at the end, so it
- // can immediately transition to another sequence
- lf->frameTime = dp_realtime;
- }
- }
- lf->frame = anim->firstFrame + f;
- if ( dp_realtime > lf->frameTime ) {
- lf->frameTime = dp_realtime;
- }
- }
-
- if ( lf->frameTime > dp_realtime + 200 ) {
- lf->frameTime = dp_realtime;
- }
-
- if ( lf->oldFrameTime > dp_realtime ) {
- lf->oldFrameTime = dp_realtime;
- }
- // calculate current lerp value
- if ( lf->frameTime == lf->oldFrameTime ) {
- lf->backlerp = 0;
- } else {
- lf->backlerp = 1.0 - (float)( dp_realtime - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
- }
-}
-
-
-/*
-===============
-UI_PlayerAnimation
-===============
-*/
-static void UI_PlayerAnimation( playerInfo_t *pi, int *legsOld, int *legs, float *legsBackLerp,
- int *torsoOld, int *torso, float *torsoBackLerp ) {
-
- // legs animation
- pi->legsAnimationTimer -= uiInfo.uiDC.frameTime;
- if ( pi->legsAnimationTimer < 0 ) {
- pi->legsAnimationTimer = 0;
- }
-
- UI_LegsSequencing( pi );
-
- if ( pi->legs.yawing && ( pi->legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {
- UI_RunLerpFrame( pi, &pi->legs, LEGS_TURN );
- } else {
- UI_RunLerpFrame( pi, &pi->legs, pi->legsAnim );
- }
- *legsOld = pi->legs.oldFrame;
- *legs = pi->legs.frame;
- *legsBackLerp = pi->legs.backlerp;
-
- // torso animation
- pi->torsoAnimationTimer -= uiInfo.uiDC.frameTime;
- if ( pi->torsoAnimationTimer < 0 ) {
- pi->torsoAnimationTimer = 0;
- }
-
- UI_TorsoSequencing( pi );
-
- UI_RunLerpFrame( pi, &pi->torso, pi->torsoAnim );
- *torsoOld = pi->torso.oldFrame;
- *torso = pi->torso.frame;
- *torsoBackLerp = pi->torso.backlerp;
-}
-
-
-/*
-==================
-UI_SwingAngles
-==================
-*/
-static void UI_SwingAngles( float destination, float swingTolerance, float clampTolerance,
- float speed, float *angle, qboolean *swinging ) {
- float swing;
- float move;
- float scale;
-
- if ( !*swinging ) {
- // see if a swing should be started
- swing = AngleSubtract( *angle, destination );
- if ( swing > swingTolerance || swing < -swingTolerance ) {
- *swinging = qtrue;
- }
- }
-
- if ( !*swinging ) {
- return;
- }
-
- // modify the speed depending on the delta
- // so it doesn't seem so linear
- swing = AngleSubtract( destination, *angle );
- scale = fabs( swing );
- if ( scale < swingTolerance * 0.5 ) {
- scale = 0.5;
- } else if ( scale < swingTolerance ) {
- scale = 1.0;
- } else {
- scale = 2.0;
- }
-
- // swing towards the destination angle
- if ( swing >= 0 ) {
- move = uiInfo.uiDC.frameTime * scale * speed;
- if ( move >= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- } else if ( swing < 0 ) {
- move = uiInfo.uiDC.frameTime * scale * -speed;
- if ( move <= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- }
-
- // clamp to no more than tolerance
- swing = AngleSubtract( destination, *angle );
- if ( swing > clampTolerance ) {
- *angle = AngleMod( destination - (clampTolerance - 1) );
- } else if ( swing < -clampTolerance ) {
- *angle = AngleMod( destination + (clampTolerance - 1) );
- }
-}
-
-
-/*
-======================
-UI_MovedirAdjustment
-======================
-*/
-static float UI_MovedirAdjustment( playerInfo_t *pi ) {
- vec3_t relativeAngles;
- vec3_t moveVector;
-
- VectorSubtract( pi->viewAngles, pi->moveAngles, relativeAngles );
- AngleVectors( relativeAngles, moveVector, NULL, NULL );
- if ( Q_fabs( moveVector[0] ) < 0.01 ) {
- moveVector[0] = 0.0;
- }
- if ( Q_fabs( moveVector[1] ) < 0.01 ) {
- moveVector[1] = 0.0;
- }
-
- if ( moveVector[1] == 0 && moveVector[0] > 0 ) {
- return 0;
- }
- if ( moveVector[1] < 0 && moveVector[0] > 0 ) {
- return 22;
- }
- if ( moveVector[1] < 0 && moveVector[0] == 0 ) {
- return 45;
- }
- if ( moveVector[1] < 0 && moveVector[0] < 0 ) {
- return -22;
- }
- if ( moveVector[1] == 0 && moveVector[0] < 0 ) {
- return 0;
- }
- if ( moveVector[1] > 0 && moveVector[0] < 0 ) {
- return 22;
- }
- if ( moveVector[1] > 0 && moveVector[0] == 0 ) {
- return -45;
- }
-
- return -22;
-}
-
-
-/*
-===============
-UI_PlayerAngles
-===============
-*/
-static void UI_PlayerAngles( playerInfo_t *pi, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {
- vec3_t legsAngles, torsoAngles, headAngles;
- float dest;
- float adjust;
-
- VectorCopy( pi->viewAngles, headAngles );
- headAngles[YAW] = AngleMod( headAngles[YAW] );
- VectorClear( legsAngles );
- VectorClear( torsoAngles );
-
- // --------- yaw -------------
-
- // allow yaw to drift a bit
- if ( ( pi->legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE
- || ( pi->torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) {
- // if not standing still, always point all in the same direction
- pi->torso.yawing = qtrue; // always center
- pi->torso.pitching = qtrue; // always center
- pi->legs.yawing = qtrue; // always center
- }
-
- // adjust legs for movement dir
- adjust = UI_MovedirAdjustment( pi );
- legsAngles[YAW] = headAngles[YAW] + adjust;
- torsoAngles[YAW] = headAngles[YAW] + 0.25 * adjust;
-
-
- // torso
- UI_SwingAngles( torsoAngles[YAW], 25, 90, SWINGSPEED, &pi->torso.yawAngle, &pi->torso.yawing );
- UI_SwingAngles( legsAngles[YAW], 40, 90, SWINGSPEED, &pi->legs.yawAngle, &pi->legs.yawing );
-
- torsoAngles[YAW] = pi->torso.yawAngle;
- legsAngles[YAW] = pi->legs.yawAngle;
-
- // --------- pitch -------------
-
- // only show a fraction of the pitch angle in the torso
- if ( headAngles[PITCH] > 180 ) {
- dest = (-360 + headAngles[PITCH]) * 0.75;
- } else {
- dest = headAngles[PITCH] * 0.75;
- }
- UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching );
- torsoAngles[PITCH] = pi->torso.pitchAngle;
-
- // pull the angles back out of the hierarchial chain
- AnglesSubtract( headAngles, torsoAngles, headAngles );
- AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
- AnglesToAxis( legsAngles, legs );
- AnglesToAxis( torsoAngles, torso );
- AnglesToAxis( headAngles, head );
-}
-
-
-/*
-===============
-UI_PlayerFloatSprite
-===============
-*/
-static void UI_PlayerFloatSprite( playerInfo_t *pi, vec3_t origin, qhandle_t shader ) {
- refEntity_t ent;
-
- memset( &ent, 0, sizeof( ent ) );
- VectorCopy( origin, ent.origin );
- ent.origin[2] += 48;
- ent.reType = RT_SPRITE;
- ent.customShader = shader;
- ent.radius = 10;
- ent.renderfx = 0;
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-/*
-======================
-UI_MachinegunSpinAngle
-======================
-*/
-float UI_MachinegunSpinAngle( playerInfo_t *pi ) {
- int delta;
- float angle;
- float speed;
- int torsoAnim;
-
- delta = dp_realtime - pi->barrelTime;
- if ( pi->barrelSpinning ) {
- angle = pi->barrelAngle + delta * SPIN_SPEED;
- } else {
- if ( delta > COAST_TIME ) {
- delta = COAST_TIME;
- }
-
- speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
- angle = pi->barrelAngle + delta * speed;
- }
-
- torsoAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
- if( torsoAnim == TORSO_ATTACK2 ) {
- torsoAnim = TORSO_ATTACK;
- }
- if ( pi->barrelSpinning == !(torsoAnim == TORSO_ATTACK) ) {
- pi->barrelTime = dp_realtime;
- pi->barrelAngle = AngleMod( angle );
- pi->barrelSpinning = !!(torsoAnim == TORSO_ATTACK);
- }
-
- return angle;
-}
-
-
-/*
-===============
-UI_DrawPlayer
-===============
-*/
-void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ) {
- refdef_t refdef;
- refEntity_t legs;
- refEntity_t torso;
- refEntity_t head;
- refEntity_t gun;
- refEntity_t barrel;
- refEntity_t flash;
- vec3_t origin;
- int renderfx;
- vec3_t mins = {-16, -16, -24};
- vec3_t maxs = {16, 16, 32};
- float len;
- float xx;
-
- if ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) {
- return;
- }
-
- // this allows the ui to cache the player model on the main menu
- if (w == 0 || h == 0) {
- return;
- }
-
- dp_realtime = time;
-
- if ( pi->pendingWeapon != -1 && dp_realtime > pi->weaponTimer ) {
- pi->weapon = pi->pendingWeapon;
- pi->lastWeapon = pi->pendingWeapon;
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- if( pi->currentWeapon != pi->weapon ) {
- trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL );
- }
- }
-
- UI_AdjustFrom640( &x, &y, &w, &h );
-
- y -= jumpHeight;
-
- memset( &refdef, 0, sizeof( refdef ) );
- memset( &legs, 0, sizeof(legs) );
- memset( &torso, 0, sizeof(torso) );
- memset( &head, 0, sizeof(head) );
-
- refdef.rdflags = RDF_NOWORLDMODEL;
-
- AxisClear( refdef.viewaxis );
-
- refdef.x = x;
- refdef.y = y;
- refdef.width = w;
- refdef.height = h;
-
- refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
- xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
- refdef.fov_y = atan2( refdef.height, xx );
- refdef.fov_y *= ( 360 / (float)M_PI );
-
- // calculate distance so the player nearly fills the box
- len = 0.7 * ( maxs[2] - mins[2] );
- origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
-
- refdef.time = dp_realtime;
-
- trap_R_ClearScene();
-
- // get the rotation information
- UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis );
-
- // get the animation state (after rotation, to allow feet shuffle)
- UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp,
- &torso.oldframe, &torso.frame, &torso.backlerp );
-
- renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
-
- //
- // add the legs
- //
- legs.hModel = pi->legsModel;
- legs.customSkin = pi->legsSkin;
-
- VectorCopy( origin, legs.origin );
-
- VectorCopy( origin, legs.lightingOrigin );
- legs.renderfx = renderfx;
- VectorCopy (legs.origin, legs.oldorigin);
-
- trap_R_AddRefEntityToScene( &legs );
-
- if (!legs.hModel) {
- return;
- }
-
- //
- // add the torso
- //
- torso.hModel = pi->torsoModel;
- if (!torso.hModel) {
- return;
- }
-
- torso.customSkin = pi->torsoSkin;
-
- VectorCopy( origin, torso.lightingOrigin );
-
- UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, "tag_torso");
-
- torso.renderfx = renderfx;
-
- trap_R_AddRefEntityToScene( &torso );
-
- //
- // add the head
- //
- head.hModel = pi->headModel;
- if (!head.hModel) {
- return;
- }
- head.customSkin = pi->headSkin;
-
- VectorCopy( origin, head.lightingOrigin );
-
- UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, "tag_head");
-
- head.renderfx = renderfx;
-
- trap_R_AddRefEntityToScene( &head );
-
- //
- // add the gun
- //
- if ( pi->currentWeapon != WP_NONE ) {
- memset( &gun, 0, sizeof(gun) );
- gun.hModel = pi->weaponModel;
- VectorCopy( origin, gun.lightingOrigin );
- UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, "tag_weapon");
- gun.renderfx = renderfx;
- trap_R_AddRefEntityToScene( &gun );
- }
-
- //
- // add the spinning barrel
- //
- if ( pi->realWeapon == WP_MACHINEGUN || pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
- vec3_t angles;
-
- memset( &barrel, 0, sizeof(barrel) );
- VectorCopy( origin, barrel.lightingOrigin );
- barrel.renderfx = renderfx;
-
- barrel.hModel = pi->barrelModel;
- angles[YAW] = 0;
- angles[PITCH] = 0;
- angles[ROLL] = UI_MachinegunSpinAngle( pi );
- if( pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
- angles[PITCH] = angles[ROLL];
- angles[ROLL] = 0;
- }
- AnglesToAxis( angles, barrel.axis );
-
- UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel");
-
- trap_R_AddRefEntityToScene( &barrel );
- }
-
- //
- // add muzzle flash
- //
- if ( dp_realtime <= pi->muzzleFlashTime ) {
- if ( pi->flashModel ) {
- memset( &flash, 0, sizeof(flash) );
- flash.hModel = pi->flashModel;
- VectorCopy( origin, flash.lightingOrigin );
- UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash");
- flash.renderfx = renderfx;
- trap_R_AddRefEntityToScene( &flash );
- }
-
- // make a dlight for the flash
- if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) {
- trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), pi->flashDlightColor[0],
- pi->flashDlightColor[1], pi->flashDlightColor[2] );
- }
- }
-
- //
- // add the chat icon
- //
- if ( pi->chat ) {
- UI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) );
- }
-
- //
- // add an accent light
- //
- origin[0] -= 100; // + = behind, - = in front
- origin[1] += 100; // + = left, - = right
- origin[2] += 100; // + = above, - = below
- trap_R_AddLightToScene( origin, 500, 1.0, 1.0, 1.0 );
-
- origin[0] -= 100;
- origin[1] -= 100;
- origin[2] -= 100;
- trap_R_AddLightToScene( origin, 500, 1.0, 0.0, 0.0 );
-
- trap_R_RenderScene( &refdef );
-}
-
-/*
-==========================
-UI_FileExists
-==========================
-*/
-static qboolean UI_FileExists(const char *filename) {
- int len;
-
- len = trap_FS_FOpenFile( filename, NULL, FS_READ );
- if (len>0) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==========================
-UI_FindClientHeadFile
-==========================
-*/
-static qboolean UI_FindClientHeadFile( char *filename, int length, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) {
- char *team, *headsFolder;
- int i;
-
- team = "default";
-
- if ( headModelName[0] == '*' ) {
- headsFolder = "heads/";
- headModelName++;
- }
- else {
- headsFolder = "";
- }
- while(1) {
- for ( i = 0; i < 2; i++ ) {
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s/%s%s_%s.%s", headsFolder, headModelName, headSkinName, teamName, base, team, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s/%s_%s.%s", headsFolder, headModelName, headSkinName, base, team, ext );
- }
- if ( UI_FileExists( filename ) ) {
- return qtrue;
- }
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, headSkinName, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, headSkinName, ext );
- }
- if ( UI_FileExists( filename ) ) {
- return qtrue;
- }
- if ( !teamName || !*teamName ) {
- break;
- }
- }
- // if tried the heads folder first
- if ( headsFolder[0] ) {
- break;
- }
- headsFolder = "heads/";
- }
-
- return qfalse;
-}
-
-/*
-==========================
-UI_RegisterClientSkin
-==========================
-*/
-static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName , const char *teamName) {
- char filename[MAX_QPATH*2];
-
- if (teamName && *teamName) {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/%s/lower_%s.skin", modelName, teamName, skinName );
- } else {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName );
- }
- pi->legsSkin = trap_R_RegisterSkin( filename );
- if (!pi->legsSkin) {
- if (teamName && *teamName) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%s/lower_%s.skin", modelName, teamName, skinName );
- } else {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower_%s.skin", modelName, skinName );
- }
- pi->legsSkin = trap_R_RegisterSkin( filename );
- }
-
- if (teamName && *teamName) {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/%s/upper_%s.skin", modelName, teamName, skinName );
- } else {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName );
- }
- pi->torsoSkin = trap_R_RegisterSkin( filename );
- if (!pi->torsoSkin) {
- if (teamName && *teamName) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%s/upper_%s.skin", modelName, teamName, skinName );
- } else {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper_%s.skin", modelName, skinName );
- }
- pi->torsoSkin = trap_R_RegisterSkin( filename );
- }
-
- if ( UI_FindClientHeadFile( filename, sizeof(filename), teamName, headModelName, headSkinName, "head", "skin" ) ) {
- pi->headSkin = trap_R_RegisterSkin( filename );
- }
-
- if ( !pi->legsSkin || !pi->torsoSkin || !pi->headSkin ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-======================
-UI_ParseAnimationFile
-======================
-*/
-static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) {
- char *text_p, *prev;
- int len;
- int i;
- char *token;
- float fps;
- int skip;
- char text[20000];
- fileHandle_t f;
-
- memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS );
-
- // load the file
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( len <= 0 ) {
- return qfalse;
- }
- if ( len >= ( sizeof( text ) - 1 ) ) {
- Com_Printf( "File %s too long\n", filename );
- trap_FS_FCloseFile( f );
- return qfalse;
- }
- trap_FS_Read( text, len, f );
- text[len] = 0;
- trap_FS_FCloseFile( f );
-
- COM_Compress(text);
-
- // parse the text
- text_p = text;
- skip = 0; // quite the compiler warning
-
- // read optional parameters
- while ( 1 ) {
- prev = text_p; // so we can unget
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( !Q_stricmp( token, "footsteps" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- continue;
- } else if ( !Q_stricmp( token, "headoffset" ) ) {
- for ( i = 0 ; i < 3 ; i++ ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- }
- continue;
- } else if ( !Q_stricmp( token, "sex" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- continue;
- }
-
- // if it is a number, start parsing animations
- if ( token[0] >= '0' && token[0] <= '9' ) {
- text_p = prev; // unget the token
- break;
- }
-
- Com_Printf( "unknown token '%s' is %s\n", token, filename );
- }
-
- // read information for each frame
- for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].firstFrame = atoi( token );
- // leg only frames are adjusted to not count the upper body only frames
- if ( i == LEGS_WALKCR ) {
- skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
- }
- if ( i >= LEGS_WALKCR ) {
- animations[i].firstFrame -= skip;
- }
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].numFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].loopFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- fps = atof( token );
- if ( fps == 0 ) {
- fps = 1;
- }
- animations[i].frameLerp = 1000 / fps;
- animations[i].initialLerp = 1000 / fps;
- }
-
- if ( i != MAX_ANIMATIONS ) {
- Com_Printf( "Error parsing animation file: %s", filename );
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-==========================
-UI_RegisterClientModelname
-==========================
-*/
-qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName, const char *headModelSkinName, const char *teamName ) {
- char modelName[MAX_QPATH];
- char skinName[MAX_QPATH];
- char headModelName[MAX_QPATH];
- char headSkinName[MAX_QPATH];
- char filename[MAX_QPATH];
- char *slash;
-
- pi->torsoModel = 0;
- pi->headModel = 0;
-
- if ( !modelSkinName[0] ) {
- return qfalse;
- }
-
- Q_strncpyz( modelName, modelSkinName, sizeof( modelName ) );
-
- slash = strchr( modelName, '/' );
- if ( !slash ) {
- // modelName did not include a skin name
- Q_strncpyz( skinName, "default", sizeof( skinName ) );
- } else {
- Q_strncpyz( skinName, slash + 1, sizeof( skinName ) );
- *slash = '\0';
- }
-
- Q_strncpyz( headModelName, headModelSkinName, sizeof( headModelName ) );
- slash = strchr( headModelName, '/' );
- if ( !slash ) {
- // modelName did not include a skin name
- Q_strncpyz( headSkinName, "default", sizeof( skinName ) );
- } else {
- Q_strncpyz( headSkinName, slash + 1, sizeof( skinName ) );
- *slash = '\0';
- }
-
- // load cmodels before models so filecache works
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
- pi->legsModel = trap_R_RegisterModel( filename );
- if ( !pi->legsModel ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower.md3", modelName );
- pi->legsModel = trap_R_RegisterModel( filename );
- if ( !pi->legsModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
- }
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
- pi->torsoModel = trap_R_RegisterModel( filename );
- if ( !pi->torsoModel ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper.md3", modelName );
- pi->torsoModel = trap_R_RegisterModel( filename );
- if ( !pi->torsoModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
- }
-
- if (headModelName[0] == '*' ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", &headModelName[1], &headModelName[1] );
- }
- else {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headModelName );
- }
- pi->headModel = trap_R_RegisterModel( filename );
- if ( !pi->headModel && headModelName[0] != '*') {
- Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", headModelName, headModelName );
- pi->headModel = trap_R_RegisterModel( filename );
- }
-
- if (!pi->headModel) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
-
- // if any skins failed to load, fall back to default
- if ( !UI_RegisterClientSkin( pi, modelName, skinName, headModelName, headSkinName, teamName) ) {
- if ( !UI_RegisterClientSkin( pi, modelName, "default", headModelName, "default", teamName ) ) {
- Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName );
- return qfalse;
- }
- }
-
- // load the animations
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
- if ( !UI_ParseAnimationFile( filename, pi->animations ) ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName );
- if ( !UI_ParseAnimationFile( filename, pi->animations ) ) {
- Com_Printf( "Failed to load animation file %s\n", filename );
- return qfalse;
- }
- }
-
- return qtrue;
-}
-
-
-/*
-===============
-UI_PlayerInfo_SetModel
-===============
-*/
-void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model, const char *headmodel, char *teamName ) {
- memset( pi, 0, sizeof(*pi) );
- UI_RegisterClientModelname( pi, model, headmodel, teamName );
- pi->weapon = WP_MACHINEGUN;
- pi->currentWeapon = pi->weapon;
- pi->lastWeapon = pi->weapon;
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- pi->chat = qfalse;
- pi->newModel = qtrue;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
-}
-
-
-/*
-===============
-UI_PlayerInfo_SetInfo
-===============
-*/
-void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) {
- int currentAnim;
- weapon_t weaponNum;
-
- pi->chat = chat;
-
- // view angles
- VectorCopy( viewAngles, pi->viewAngles );
-
- // move angles
- VectorCopy( moveAngles, pi->moveAngles );
-
- if ( pi->newModel ) {
- pi->newModel = qfalse;
-
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
- pi->legs.yawAngle = viewAngles[YAW];
- pi->legs.yawing = qfalse;
-
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
- pi->torso.yawAngle = viewAngles[YAW];
- pi->torso.yawing = qfalse;
-
- if ( weaponNumber != -1 ) {
- pi->weapon = weaponNumber;
- pi->currentWeapon = weaponNumber;
- pi->lastWeapon = weaponNumber;
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
- }
-
- return;
- }
-
- // weapon
- if ( weaponNumber == -1 ) {
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- }
- else if ( weaponNumber != WP_NONE ) {
- pi->pendingWeapon = weaponNumber;
- pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY;
- }
- weaponNum = pi->lastWeapon;
- pi->weapon = weaponNum;
-
- if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) {
- torsoAnim = legsAnim = BOTH_DEATH1;
- pi->weapon = pi->currentWeapon = WP_NONE;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
-
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
-
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
-
- return;
- }
-
- // leg animation
- currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
- if ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) {
- pi->pendingLegsAnim = legsAnim;
- }
- else if ( legsAnim != currentAnim ) {
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
- }
-
- // torso animation
- if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) {
- if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
- torsoAnim = TORSO_STAND2;
- }
- else {
- torsoAnim = TORSO_STAND;
- }
- }
-
- if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) {
- if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
- torsoAnim = TORSO_ATTACK2;
- }
- else {
- torsoAnim = TORSO_ATTACK;
- }
- pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH;
- //FIXME play firing sound here
- }
-
- currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
-
- if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) {
- pi->pendingTorsoAnim = torsoAnim;
- }
- else if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) {
- pi->pendingTorsoAnim = torsoAnim;
- }
- else if ( torsoAnim != currentAnim ) {
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
- }
-}
diff --git a/engine/code/ui/ui_public.h b/engine/code/ui/ui_public.h
deleted file mode 100644
index bcc7235..0000000
--- a/engine/code/ui/ui_public.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#ifndef __UI_PUBLIC_H__
-#define __UI_PUBLIC_H__
-
-#define UI_API_VERSION 6
-
-typedef struct {
- connstate_t connState;
- int connectPacketCount;
- int clientNum;
- char servername[MAX_STRING_CHARS];
- char updateInfoString[MAX_STRING_CHARS];
- char messageString[MAX_STRING_CHARS];
-} uiClientState_t;
-
-typedef enum {
- UI_ERROR,
- UI_PRINT,
- UI_MILLISECONDS,
- UI_CVAR_SET,
- UI_CVAR_VARIABLEVALUE,
- UI_CVAR_VARIABLESTRINGBUFFER,
- UI_CVAR_SETVALUE,
- UI_CVAR_RESET,
- UI_CVAR_CREATE,
- UI_CVAR_INFOSTRINGBUFFER,
- UI_ARGC,
- UI_ARGV,
- UI_CMD_EXECUTETEXT,
- UI_FS_FOPENFILE,
- UI_FS_READ,
- UI_FS_WRITE,
- UI_FS_FCLOSEFILE,
- UI_FS_GETFILELIST,
- UI_R_REGISTERMODEL,
- UI_R_REGISTERSKIN,
- UI_R_REGISTERSHADERNOMIP,
- UI_R_CLEARSCENE,
- UI_R_ADDREFENTITYTOSCENE,
- UI_R_ADDPOLYTOSCENE,
- UI_R_ADDLIGHTTOSCENE,
- UI_R_RENDERSCENE,
- UI_R_SETCOLOR,
- UI_R_DRAWSTRETCHPIC,
- UI_UPDATESCREEN,
- UI_CM_LERPTAG,
- UI_CM_LOADMODEL,
- UI_S_REGISTERSOUND,
- UI_S_STARTLOCALSOUND,
- UI_KEY_KEYNUMTOSTRINGBUF,
- UI_KEY_GETBINDINGBUF,
- UI_KEY_SETBINDING,
- UI_KEY_ISDOWN,
- UI_KEY_GETOVERSTRIKEMODE,
- UI_KEY_SETOVERSTRIKEMODE,
- UI_KEY_CLEARSTATES,
- UI_KEY_GETCATCHER,
- UI_KEY_SETCATCHER,
- UI_GETCLIPBOARDDATA,
- UI_GETGLCONFIG,
- UI_GETCLIENTSTATE,
- UI_GETCONFIGSTRING,
- UI_LAN_GETPINGQUEUECOUNT,
- UI_LAN_CLEARPING,
- UI_LAN_GETPING,
- UI_LAN_GETPINGINFO,
- UI_CVAR_REGISTER,
- UI_CVAR_UPDATE,
- UI_MEMORY_REMAINING,
- UI_GET_CDKEY,
- UI_SET_CDKEY,
- UI_R_REGISTERFONT,
- UI_R_MODELBOUNDS,
- UI_PC_ADD_GLOBAL_DEFINE,
- UI_PC_LOAD_SOURCE,
- UI_PC_FREE_SOURCE,
- UI_PC_READ_TOKEN,
- UI_PC_SOURCE_FILE_AND_LINE,
- UI_S_STOPBACKGROUNDTRACK,
- UI_S_STARTBACKGROUNDTRACK,
- UI_REAL_TIME,
- UI_LAN_GETSERVERCOUNT,
- UI_LAN_GETSERVERADDRESSSTRING,
- UI_LAN_GETSERVERINFO,
- UI_LAN_MARKSERVERVISIBLE,
- UI_LAN_UPDATEVISIBLEPINGS,
- UI_LAN_RESETPINGS,
- UI_LAN_LOADCACHEDSERVERS,
- UI_LAN_SAVECACHEDSERVERS,
- UI_LAN_ADDSERVER,
- UI_LAN_REMOVESERVER,
- UI_CIN_PLAYCINEMATIC,
- UI_CIN_STOPCINEMATIC,
- UI_CIN_RUNCINEMATIC,
- UI_CIN_DRAWCINEMATIC,
- UI_CIN_SETEXTENTS,
- UI_R_REMAP_SHADER,
- UI_VERIFY_CDKEY,
- UI_LAN_SERVERSTATUS,
- UI_LAN_GETSERVERPING,
- UI_LAN_SERVERISVISIBLE,
- UI_LAN_COMPARESERVERS,
- // 1.32
- UI_FS_SEEK,
- UI_SET_PBCLSTATUS,
-
- UI_MEMSET = 100,
- UI_MEMCPY,
- UI_STRNCPY,
- UI_SIN,
- UI_COS,
- UI_ATAN2,
- UI_SQRT,
- UI_FLOOR,
- UI_CEIL
-} uiImport_t;
-
-typedef enum {
- UIMENU_NONE,
- UIMENU_MAIN,
- UIMENU_INGAME,
- UIMENU_NEED_CD,
- UIMENU_BAD_CD_KEY,
- UIMENU_TEAM,
- UIMENU_POSTGAME
-} uiMenuCommand_t;
-
-#define SORT_HOST 0
-#define SORT_MAP 1
-#define SORT_CLIENTS 2
-#define SORT_GAME 3
-#define SORT_PING 4
-#define SORT_PUNKBUSTER 5
-
-typedef enum {
- UI_GETAPIVERSION = 0, // system reserved
-
- UI_INIT,
-// void UI_Init( void );
-
- UI_SHUTDOWN,
-// void UI_Shutdown( void );
-
- UI_KEY_EVENT,
-// void UI_KeyEvent( int key );
-
- UI_MOUSE_EVENT,
-// void UI_MouseEvent( int dx, int dy );
-
- UI_REFRESH,
-// void UI_Refresh( int time );
-
- UI_IS_FULLSCREEN,
-// qboolean UI_IsFullscreen( void );
-
- UI_SET_ACTIVE_MENU,
-// void UI_SetActiveMenu( uiMenuCommand_t menu );
-
- UI_CONSOLE_COMMAND,
-// qboolean UI_ConsoleCommand( int realTime );
-
- UI_DRAW_CONNECT_SCREEN,
-// void UI_DrawConnectScreen( qboolean overlay );
- UI_HASUNIQUECDKEY
-// if !overlay, the background will be drawn, otherwise it will be
-// overlayed over whatever the cgame has drawn.
-// a GetClientState syscall will be made to get the current strings
-} uiExport_t;
-
-#endif
diff --git a/engine/code/ui/ui_shared.c b/engine/code/ui/ui_shared.c
deleted file mode 100644
index e6e460c..0000000
--- a/engine/code/ui/ui_shared.c
+++ /dev/null
@@ -1,5789 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// string allocation/managment
-
-#include "ui_shared.h"
-
-#define SCROLL_TIME_START 500
-#define SCROLL_TIME_ADJUST 150
-#define SCROLL_TIME_ADJUSTOFFSET 40
-#define SCROLL_TIME_FLOOR 20
-
-typedef struct scrollInfo_s {
- int nextScrollTime;
- int nextAdjustTime;
- int adjustValue;
- int scrollKey;
- float xStart;
- float yStart;
- itemDef_t *item;
- qboolean scrollDir;
-} scrollInfo_t;
-
-static scrollInfo_t scrollInfo;
-
-static void (*captureFunc) (void *p) = 0;
-static void *captureData = NULL;
-static itemDef_t *itemCapture = NULL; // item that has the mouse captured ( if any )
-
-displayContextDef_t *DC = NULL;
-
-static qboolean g_waitingForKey = qfalse;
-static qboolean g_editingField = qfalse;
-
-static itemDef_t *g_bindItem = NULL;
-static itemDef_t *g_editItem = NULL;
-
-menuDef_t Menus[MAX_MENUS]; // defined menus
-int menuCount = 0; // how many
-
-menuDef_t *menuStack[MAX_OPEN_MENUS];
-int openMenuCount = 0;
-
-static qboolean debugMode = qfalse;
-
-#define DOUBLE_CLICK_DELAY 300
-static int lastListBoxClickTime = 0;
-
-void Item_RunScript(itemDef_t *item, const char *s);
-void Item_SetupKeywordHash(void);
-void Menu_SetupKeywordHash(void);
-int BindingIDFromName(const char *name);
-qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down);
-itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu);
-itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu);
-static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y);
-
-#ifdef CGAME
-#define MEM_POOL_SIZE 128 * 1024
-#else
-#define MEM_POOL_SIZE 1024 * 1024
-#endif
-
-static char memoryPool[MEM_POOL_SIZE];
-static int allocPoint, outOfMemory;
-
-
-/*
-===============
-UI_Alloc
-===============
-*/
-void *UI_Alloc( int size ) {
- char *p;
-
- if ( allocPoint + size > MEM_POOL_SIZE ) {
- outOfMemory = qtrue;
- if (DC->Print) {
- DC->Print("UI_Alloc: Failure. Out of memory!\n");
- }
- //DC->trap_Print(S_COLOR_YELLOW"WARNING: UI Out of Memory!\n");
- return NULL;
- }
-
- p = &memoryPool[allocPoint];
-
- allocPoint += ( size + 15 ) & ~15;
-
- return p;
-}
-
-/*
-===============
-UI_InitMemory
-===============
-*/
-void UI_InitMemory( void ) {
- allocPoint = 0;
- outOfMemory = qfalse;
-}
-
-qboolean UI_OutOfMemory( void ) {
- return outOfMemory;
-}
-
-
-
-
-
-#define HASH_TABLE_SIZE 2048
-/*
-================
-return a hash value for the string
-================
-*/
-static unsigned hashForString(const char *str) {
- int i;
- unsigned hash;
- char letter;
-
- hash = 0;
- i = 0;
- while (str[i] != '\0') {
- letter = tolower(str[i]);
- hash+=(unsigned)(letter)*(i+119);
- i++;
- }
- hash &= (HASH_TABLE_SIZE-1);
- return hash;
-}
-
-typedef struct stringDef_s {
- struct stringDef_s *next;
- const char *str;
-} stringDef_t;
-
-static int strPoolIndex = 0;
-static char strPool[STRING_POOL_SIZE];
-
-static int strHandleCount = 0;
-static stringDef_t *strHandle[HASH_TABLE_SIZE];
-
-
-const char *String_Alloc(const char *p) {
- int len;
- unsigned hash;
- stringDef_t *str, *last;
- static const char *staticNULL = "";
-
- if (p == NULL) {
- return NULL;
- }
-
- if (*p == 0) {
- return staticNULL;
- }
-
- hash = hashForString(p);
-
- str = strHandle[hash];
- while (str) {
- if (strcmp(p, str->str) == 0) {
- return str->str;
- }
- str = str->next;
- }
-
- len = strlen(p);
- if (len + strPoolIndex + 1 < STRING_POOL_SIZE) {
- int ph = strPoolIndex;
- strcpy(&strPool[strPoolIndex], p);
- strPoolIndex += len + 1;
-
- str = strHandle[hash];
- last = str;
- while (str && str->next) {
- last = str;
- str = str->next;
- }
-
- str = UI_Alloc(sizeof(stringDef_t));
- str->next = NULL;
- str->str = &strPool[ph];
- if (last) {
- last->next = str;
- } else {
- strHandle[hash] = str;
- }
- return &strPool[ph];
- }
- return NULL;
-}
-
-void String_Report(void) {
- float f;
- Com_Printf("Memory/String Pool Info\n");
- Com_Printf("----------------\n");
- f = strPoolIndex;
- f /= STRING_POOL_SIZE;
- f *= 100;
- Com_Printf("String Pool is %.1f%% full, %i bytes out of %i used.\n", f, strPoolIndex, STRING_POOL_SIZE);
- f = allocPoint;
- f /= MEM_POOL_SIZE;
- f *= 100;
- Com_Printf("Memory Pool is %.1f%% full, %i bytes out of %i used.\n", f, allocPoint, MEM_POOL_SIZE);
-}
-
-/*
-=================
-String_Init
-=================
-*/
-void String_Init(void) {
- int i;
- for (i = 0; i < HASH_TABLE_SIZE; i++) {
- strHandle[i] = NULL;
- }
- strHandleCount = 0;
- strPoolIndex = 0;
- menuCount = 0;
- openMenuCount = 0;
- UI_InitMemory();
- Item_SetupKeywordHash();
- Menu_SetupKeywordHash();
- if (DC && DC->getBindingBuf) {
- Controls_GetConfig();
- }
-}
-
-/*
-=================
-PC_SourceWarning
-=================
-*/
-void PC_SourceWarning(int handle, char *format, ...) {
- int line;
- char filename[128];
- va_list argptr;
- static char string[4096];
-
- va_start (argptr, format);
- Q_vsnprintf (string, sizeof(string), format, argptr);
- va_end (argptr);
-
- filename[0] = '\0';
- line = 0;
- trap_PC_SourceFileAndLine(handle, filename, &line);
-
- Com_Printf(S_COLOR_YELLOW "WARNING: %s, line %d: %s\n", filename, line, string);
-}
-
-/*
-=================
-PC_SourceError
-=================
-*/
-void PC_SourceError(int handle, char *format, ...) {
- int line;
- char filename[128];
- va_list argptr;
- static char string[4096];
-
- va_start (argptr, format);
- Q_vsnprintf (string, sizeof(string), format, argptr);
- va_end (argptr);
-
- filename[0] = '\0';
- line = 0;
- trap_PC_SourceFileAndLine(handle, filename, &line);
-
- Com_Printf(S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string);
-}
-
-/*
-=================
-LerpColor
-=================
-*/
-void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)
-{
- int i;
-
- // lerp and clamp each component
- for (i=0; i<4; i++)
- {
- c[i] = a[i] + t*(b[i]-a[i]);
- if (c[i] < 0)
- c[i] = 0;
- else if (c[i] > 1.0)
- c[i] = 1.0;
- }
-}
-
-/*
-=================
-Float_Parse
-=================
-*/
-qboolean Float_Parse(char **p, float *f) {
- char *token;
- token = COM_ParseExt(p, qfalse);
- if (token && token[0] != 0) {
- *f = atof(token);
- return qtrue;
- } else {
- return qfalse;
- }
-}
-
-/*
-=================
-PC_Float_Parse
-=================
-*/
-qboolean PC_Float_Parse(int handle, float *f) {
- pc_token_t token;
- int negative = qfalse;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (token.string[0] == '-') {
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- negative = qtrue;
- }
- if (token.type != TT_NUMBER) {
- PC_SourceError(handle, "expected float but found %s\n", token.string);
- return qfalse;
- }
- if (negative)
- *f = -token.floatvalue;
- else
- *f = token.floatvalue;
- return qtrue;
-}
-
-/*
-=================
-Color_Parse
-=================
-*/
-qboolean Color_Parse(char **p, vec4_t *c) {
- int i;
- float f;
-
- for (i = 0; i < 4; i++) {
- if (!Float_Parse(p, &f)) {
- return qfalse;
- }
- (*c)[i] = f;
- }
- return qtrue;
-}
-
-/*
-=================
-PC_Color_Parse
-=================
-*/
-qboolean PC_Color_Parse(int handle, vec4_t *c) {
- int i;
- float f;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- (*c)[i] = f;
- }
- return qtrue;
-}
-
-/*
-=================
-Int_Parse
-=================
-*/
-qboolean Int_Parse(char **p, int *i) {
- char *token;
- token = COM_ParseExt(p, qfalse);
-
- if (token && token[0] != 0) {
- *i = atoi(token);
- return qtrue;
- } else {
- return qfalse;
- }
-}
-
-/*
-=================
-PC_Int_Parse
-=================
-*/
-qboolean PC_Int_Parse(int handle, int *i) {
- pc_token_t token;
- int negative = qfalse;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (token.string[0] == '-') {
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- negative = qtrue;
- }
- if (token.type != TT_NUMBER) {
- PC_SourceError(handle, "expected integer but found %s\n", token.string);
- return qfalse;
- }
- *i = token.intvalue;
- if (negative)
- *i = - *i;
- return qtrue;
-}
-
-/*
-=================
-Rect_Parse
-=================
-*/
-qboolean Rect_Parse(char **p, rectDef_t *r) {
- if (Float_Parse(p, &r->x)) {
- if (Float_Parse(p, &r->y)) {
- if (Float_Parse(p, &r->w)) {
- if (Float_Parse(p, &r->h)) {
- return qtrue;
- }
- }
- }
- }
- return qfalse;
-}
-
-/*
-=================
-PC_Rect_Parse
-=================
-*/
-qboolean PC_Rect_Parse(int handle, rectDef_t *r) {
- if (PC_Float_Parse(handle, &r->x)) {
- if (PC_Float_Parse(handle, &r->y)) {
- if (PC_Float_Parse(handle, &r->w)) {
- if (PC_Float_Parse(handle, &r->h)) {
- return qtrue;
- }
- }
- }
- }
- return qfalse;
-}
-
-/*
-=================
-String_Parse
-=================
-*/
-qboolean String_Parse(char **p, const char **out) {
- char *token;
-
- token = COM_ParseExt(p, qfalse);
- if (token && token[0] != 0) {
- *(out) = String_Alloc(token);
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-=================
-PC_String_Parse
-=================
-*/
-qboolean PC_String_Parse(int handle, const char **out) {
- pc_token_t token;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
-
- *(out) = String_Alloc(token.string);
- return qtrue;
-}
-
-/*
-=================
-PC_Script_Parse
-=================
-*/
-qboolean PC_Script_Parse(int handle, const char **out) {
- char script[1024];
- pc_token_t token;
-
- memset(script, 0, sizeof(script));
- // scripts start with { and have ; separated command lists.. commands are command, arg..
- // basically we want everything between the { } as it will be interpreted at run time
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (Q_stricmp(token.string, "{") != 0) {
- return qfalse;
- }
-
- while ( 1 ) {
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
-
- if (Q_stricmp(token.string, "}") == 0) {
- *out = String_Alloc(script);
- return qtrue;
- }
-
- if (token.string[1] != '\0') {
- Q_strcat(script, 1024, va("\"%s\"", token.string));
- } else {
- Q_strcat(script, 1024, token.string);
- }
- Q_strcat(script, 1024, " ");
- }
- return qfalse;
-}
-
-// display, window, menu, item code
-//
-
-/*
-==================
-Init_Display
-
-Initializes the display with a structure to all the drawing routines
- ==================
-*/
-void Init_Display(displayContextDef_t *dc) {
- DC = dc;
-}
-
-
-
-// type and style painting
-
-void GradientBar_Paint(rectDef_t *rect, vec4_t color) {
- // gradient bar takes two paints
- DC->setColor( color );
- DC->drawHandlePic(rect->x, rect->y, rect->w, rect->h, DC->Assets.gradientBar);
- DC->setColor( NULL );
-}
-
-
-/*
-==================
-Window_Init
-
-Initializes a window structure ( windowDef_t ) with defaults
-
-==================
-*/
-void Window_Init(Window *w) {
- memset(w, 0, sizeof(windowDef_t));
- w->borderSize = 1;
- w->foreColor[0] = w->foreColor[1] = w->foreColor[2] = w->foreColor[3] = 1.0;
- w->cinematic = -1;
-}
-
-void Fade(int *flags, float *f, float clamp, int *nextTime, int offsetTime, qboolean bFlags, float fadeAmount) {
- if (*flags & (WINDOW_FADINGOUT | WINDOW_FADINGIN)) {
- if (DC->realTime > *nextTime) {
- *nextTime = DC->realTime + offsetTime;
- if (*flags & WINDOW_FADINGOUT) {
- *f -= fadeAmount;
- if (bFlags && *f <= 0.0) {
- *flags &= ~(WINDOW_FADINGOUT | WINDOW_VISIBLE);
- }
- } else {
- *f += fadeAmount;
- if (*f >= clamp) {
- *f = clamp;
- if (bFlags) {
- *flags &= ~WINDOW_FADINGIN;
- }
- }
- }
- }
- }
-}
-
-
-
-void Window_Paint(Window *w, float fadeAmount, float fadeClamp, float fadeCycle) {
- //float bordersize = 0;
- vec4_t color;
- rectDef_t fillRect = w->rect;
-
-
- if (debugMode) {
- color[0] = color[1] = color[2] = color[3] = 1;
- DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, 1, color);
- }
-
- if (w == NULL || (w->style == 0 && w->border == 0)) {
- return;
- }
-
- if (w->border != 0) {
- fillRect.x += w->borderSize;
- fillRect.y += w->borderSize;
- fillRect.w -= w->borderSize + 1;
- fillRect.h -= w->borderSize + 1;
- }
-
- if (w->style == WINDOW_STYLE_FILLED) {
- // box, but possible a shader that needs filled
- if (w->background) {
- Fade(&w->flags, &w->backColor[3], fadeClamp, &w->nextTime, fadeCycle, qtrue, fadeAmount);
- DC->setColor(w->backColor);
- DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
- DC->setColor(NULL);
- } else {
- DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->backColor);
- }
- } else if (w->style == WINDOW_STYLE_GRADIENT) {
- GradientBar_Paint(&fillRect, w->backColor);
- // gradient bar
- } else if (w->style == WINDOW_STYLE_SHADER) {
- if (w->flags & WINDOW_FORECOLORSET) {
- DC->setColor(w->foreColor);
- }
- DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
- DC->setColor(NULL);
- } else if (w->style == WINDOW_STYLE_TEAMCOLOR) {
- if (DC->getTeamColor) {
- DC->getTeamColor(&color);
- DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, color);
- }
- } else if (w->style == WINDOW_STYLE_CINEMATIC) {
- if (w->cinematic == -1) {
- w->cinematic = DC->playCinematic(w->cinematicName, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
- if (w->cinematic == -1) {
- w->cinematic = -2;
- }
- }
- if (w->cinematic >= 0) {
- DC->runCinematicFrame(w->cinematic);
- DC->drawCinematic(w->cinematic, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
- }
- }
-
- if (w->border == WINDOW_BORDER_FULL) {
- // full
- // HACK HACK HACK
- if (w->style == WINDOW_STYLE_TEAMCOLOR) {
- if (color[0] > 0) {
- // red
- color[0] = 1;
- color[1] = color[2] = .5;
-
- } else {
- color[2] = 1;
- color[0] = color[1] = .5;
- }
- color[3] = 1;
- DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, color);
- } else {
- DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, w->borderColor);
- }
- } else if (w->border == WINDOW_BORDER_HORZ) {
- // top/bottom
- DC->setColor(w->borderColor);
- DC->drawTopBottom(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
- DC->setColor( NULL );
- } else if (w->border == WINDOW_BORDER_VERT) {
- // left right
- DC->setColor(w->borderColor);
- DC->drawSides(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
- DC->setColor( NULL );
- } else if (w->border == WINDOW_BORDER_KCGRADIENT) {
- // this is just two gradient bars along each horz edge
- rectDef_t r = w->rect;
- r.h = w->borderSize;
- GradientBar_Paint(&r, w->borderColor);
- r.y = w->rect.y + w->rect.h - 1;
- GradientBar_Paint(&r, w->borderColor);
- }
-
-}
-
-
-void Item_SetScreenCoords(itemDef_t *item, float x, float y) {
-
- if (item == NULL) {
- return;
- }
-
- if (item->window.border != 0) {
- x += item->window.borderSize;
- y += item->window.borderSize;
- }
-
- item->window.rect.x = x + item->window.rectClient.x;
- item->window.rect.y = y + item->window.rectClient.y;
- item->window.rect.w = item->window.rectClient.w;
- item->window.rect.h = item->window.rectClient.h;
-
- // force the text rects to recompute
- item->textRect.w = 0;
- item->textRect.h = 0;
-}
-
-// FIXME: consolidate this with nearby stuff
-void Item_UpdatePosition(itemDef_t *item) {
- float x, y;
- menuDef_t *menu;
-
- if (item == NULL || item->parent == NULL) {
- return;
- }
-
- menu = item->parent;
-
- x = menu->window.rect.x;
- y = menu->window.rect.y;
-
- if (menu->window.border != 0) {
- x += menu->window.borderSize;
- y += menu->window.borderSize;
- }
-
- Item_SetScreenCoords(item, x, y);
-
-}
-
-// menus
-void Menu_UpdatePosition(menuDef_t *menu) {
- int i;
- float x, y;
-
- if (menu == NULL) {
- return;
- }
-
- x = menu->window.rect.x;
- y = menu->window.rect.y;
- if (menu->window.border != 0) {
- x += menu->window.borderSize;
- y += menu->window.borderSize;
- }
-
- for (i = 0; i < menu->itemCount; i++) {
- Item_SetScreenCoords(menu->items[i], x, y);
- }
-}
-
-void Menu_PostParse(menuDef_t *menu) {
- if (menu == NULL) {
- return;
- }
- if (menu->fullScreen) {
- menu->window.rect.x = 0;
- menu->window.rect.y = 0;
- menu->window.rect.w = 640;
- menu->window.rect.h = 480;
- }
- Menu_UpdatePosition(menu);
-}
-
-itemDef_t *Menu_ClearFocus(menuDef_t *menu) {
- int i;
- itemDef_t *ret = NULL;
-
- if (menu == NULL) {
- return NULL;
- }
-
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
- ret = menu->items[i];
- }
- menu->items[i]->window.flags &= ~WINDOW_HASFOCUS;
- if (menu->items[i]->leaveFocus) {
- Item_RunScript(menu->items[i], menu->items[i]->leaveFocus);
- }
- }
-
- return ret;
-}
-
-qboolean IsVisible(int flags) {
- return (flags & WINDOW_VISIBLE && !(flags & WINDOW_FADINGOUT));
-}
-
-qboolean Rect_ContainsPoint(rectDef_t *rect, float x, float y) {
- if (rect) {
- if (x > rect->x && x < rect->x + rect->w && y > rect->y && y < rect->y + rect->h) {
- return qtrue;
- }
- }
- return qfalse;
-}
-
-int Menu_ItemsMatchingGroup(menuDef_t *menu, const char *name) {
- int i;
- int count = 0;
- for (i = 0; i < menu->itemCount; i++) {
- if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
- count++;
- }
- }
- return count;
-}
-
-itemDef_t *Menu_GetMatchingItemByNumber(menuDef_t *menu, int index, const char *name) {
- int i;
- int count = 0;
- for (i = 0; i < menu->itemCount; i++) {
- if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
- if (count == index) {
- return menu->items[i];
- }
- count++;
- }
- }
- return NULL;
-}
-
-
-
-void Script_SetColor(itemDef_t *item, char **args) {
- const char *name;
- int i;
- float f;
- vec4_t *out;
- // expecting type of color to set and 4 args for the color
- if (String_Parse(args, &name)) {
- out = NULL;
- if (Q_stricmp(name, "backcolor") == 0) {
- out = &item->window.backColor;
- item->window.flags |= WINDOW_BACKCOLORSET;
- } else if (Q_stricmp(name, "forecolor") == 0) {
- out = &item->window.foreColor;
- item->window.flags |= WINDOW_FORECOLORSET;
- } else if (Q_stricmp(name, "bordercolor") == 0) {
- out = &item->window.borderColor;
- }
-
- if (out) {
- for (i = 0; i < 4; i++) {
- if (!Float_Parse(args, &f)) {
- return;
- }
- (*out)[i] = f;
- }
- }
- }
-}
-
-void Script_SetAsset(itemDef_t *item, char **args) {
- const char *name;
- // expecting name to set asset to
- if (String_Parse(args, &name)) {
- // check for a model
- if (item->type == ITEM_TYPE_MODEL) {
- }
- }
-}
-
-void Script_SetBackground(itemDef_t *item, char **args) {
- const char *name;
- // expecting name to set asset to
- if (String_Parse(args, &name)) {
- item->window.background = DC->registerShaderNoMip(name);
- }
-}
-
-
-
-
-itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p) {
- int i;
- if (menu == NULL || p == NULL) {
- return NULL;
- }
-
- for (i = 0; i < menu->itemCount; i++) {
- if (Q_stricmp(p, menu->items[i]->window.name) == 0) {
- return menu->items[i];
- }
- }
-
- return NULL;
-}
-
-void Script_SetTeamColor(itemDef_t *item, char **args) {
- if (DC->getTeamColor) {
- int i;
- vec4_t color;
- DC->getTeamColor(&color);
- for (i = 0; i < 4; i++) {
- item->window.backColor[i] = color[i];
- }
- }
-}
-
-void Script_SetItemColor(itemDef_t *item, char **args) {
- const char *itemname;
- const char *name;
- vec4_t color;
- int i;
- vec4_t *out;
- // expecting type of color to set and 4 args for the color
- if (String_Parse(args, &itemname) && String_Parse(args, &name)) {
- itemDef_t *item2;
- int j;
- int count = Menu_ItemsMatchingGroup(item->parent, itemname);
-
- if (!Color_Parse(args, &color)) {
- return;
- }
-
- for (j = 0; j < count; j++) {
- item2 = Menu_GetMatchingItemByNumber(item->parent, j, itemname);
- if (item2 != NULL) {
- out = NULL;
- if (Q_stricmp(name, "backcolor") == 0) {
- out = &item2->window.backColor;
- } else if (Q_stricmp(name, "forecolor") == 0) {
- out = &item2->window.foreColor;
- item2->window.flags |= WINDOW_FORECOLORSET;
- } else if (Q_stricmp(name, "bordercolor") == 0) {
- out = &item2->window.borderColor;
- }
-
- if (out) {
- for (i = 0; i < 4; i++) {
- (*out)[i] = color[i];
- }
- }
- }
- }
- }
-}
-
-
-void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow) {
- itemDef_t *item;
- int i;
- int count = Menu_ItemsMatchingGroup(menu, p);
- for (i = 0; i < count; i++) {
- item = Menu_GetMatchingItemByNumber(menu, i, p);
- if (item != NULL) {
- if (bShow) {
- item->window.flags |= WINDOW_VISIBLE;
- } else {
- item->window.flags &= ~WINDOW_VISIBLE;
- // stop cinematics playing in the window
- if (item->window.cinematic >= 0) {
- DC->stopCinematic(item->window.cinematic);
- item->window.cinematic = -1;
- }
- }
- }
- }
-}
-
-void Menu_FadeItemByName(menuDef_t *menu, const char *p, qboolean fadeOut) {
- itemDef_t *item;
- int i;
- int count = Menu_ItemsMatchingGroup(menu, p);
- for (i = 0; i < count; i++) {
- item = Menu_GetMatchingItemByNumber(menu, i, p);
- if (item != NULL) {
- if (fadeOut) {
- item->window.flags |= (WINDOW_FADINGOUT | WINDOW_VISIBLE);
- item->window.flags &= ~WINDOW_FADINGIN;
- } else {
- item->window.flags |= (WINDOW_VISIBLE | WINDOW_FADINGIN);
- item->window.flags &= ~WINDOW_FADINGOUT;
- }
- }
- }
-}
-
-menuDef_t *Menus_FindByName(const char *p) {
- int i;
- for (i = 0; i < menuCount; i++) {
- if (Q_stricmp(Menus[i].window.name, p) == 0) {
- return &Menus[i];
- }
- }
- return NULL;
-}
-
-void Menus_ShowByName(const char *p) {
- menuDef_t *menu = Menus_FindByName(p);
- if (menu) {
- Menus_Activate(menu);
- }
-}
-
-void Menus_OpenByName(const char *p) {
- Menus_ActivateByName(p);
-}
-
-static void Menu_RunCloseScript(menuDef_t *menu) {
- if (menu && menu->window.flags & WINDOW_VISIBLE && menu->onClose) {
- itemDef_t item;
- item.parent = menu;
- Item_RunScript(&item, menu->onClose);
- }
-}
-
-void Menus_CloseByName(const char *p) {
- menuDef_t *menu = Menus_FindByName(p);
- if (menu != NULL) {
- Menu_RunCloseScript(menu);
- menu->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS);
- }
-}
-
-void Menus_CloseAll(void) {
- int i;
- for (i = 0; i < menuCount; i++) {
- Menu_RunCloseScript(&Menus[i]);
- Menus[i].window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
- }
-}
-
-
-void Script_Show(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menu_ShowItemByName(item->parent, name, qtrue);
- }
-}
-
-void Script_Hide(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menu_ShowItemByName(item->parent, name, qfalse);
- }
-}
-
-void Script_FadeIn(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menu_FadeItemByName(item->parent, name, qfalse);
- }
-}
-
-void Script_FadeOut(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menu_FadeItemByName(item->parent, name, qtrue);
- }
-}
-
-
-
-void Script_Open(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menus_OpenByName(name);
- }
-}
-
-void Script_ConditionalOpen(itemDef_t *item, char **args) {
- const char *cvar;
- const char *name1;
- const char *name2;
- float val;
-
- if ( String_Parse(args, &cvar) && String_Parse(args, &name1) && String_Parse(args, &name2) ) {
- val = DC->getCVarValue( cvar );
- if ( val == 0.f ) {
- Menus_OpenByName(name2);
- } else {
- Menus_OpenByName(name1);
- }
- }
-}
-
-void Script_Close(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menus_CloseByName(name);
- }
-}
-
-void Menu_TransitionItemByName(menuDef_t *menu, const char *p, rectDef_t rectFrom, rectDef_t rectTo, int time, float amt) {
- itemDef_t *item;
- int i;
- int count = Menu_ItemsMatchingGroup(menu, p);
- for (i = 0; i < count; i++) {
- item = Menu_GetMatchingItemByNumber(menu, i, p);
- if (item != NULL) {
- item->window.flags |= (WINDOW_INTRANSITION | WINDOW_VISIBLE);
- item->window.offsetTime = time;
- memcpy(&item->window.rectClient, &rectFrom, sizeof(rectDef_t));
- memcpy(&item->window.rectEffects, &rectTo, sizeof(rectDef_t));
- item->window.rectEffects2.x = abs(rectTo.x - rectFrom.x) / amt;
- item->window.rectEffects2.y = abs(rectTo.y - rectFrom.y) / amt;
- item->window.rectEffects2.w = abs(rectTo.w - rectFrom.w) / amt;
- item->window.rectEffects2.h = abs(rectTo.h - rectFrom.h) / amt;
- Item_UpdatePosition(item);
- }
- }
-}
-
-
-void Script_Transition(itemDef_t *item, char **args) {
- const char *name;
- rectDef_t rectFrom, rectTo;
- int time;
- float amt;
-
- if (String_Parse(args, &name)) {
- if ( Rect_Parse(args, &rectFrom) && Rect_Parse(args, &rectTo) && Int_Parse(args, &time) && Float_Parse(args, &amt)) {
- Menu_TransitionItemByName(item->parent, name, rectFrom, rectTo, time, amt);
- }
- }
-}
-
-
-void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, float cx, float cy, int time) {
- itemDef_t *item;
- int i;
- int count = Menu_ItemsMatchingGroup(menu, p);
- for (i = 0; i < count; i++) {
- item = Menu_GetMatchingItemByNumber(menu, i, p);
- if (item != NULL) {
- item->window.flags |= (WINDOW_ORBITING | WINDOW_VISIBLE);
- item->window.offsetTime = time;
- item->window.rectEffects.x = cx;
- item->window.rectEffects.y = cy;
- item->window.rectClient.x = x;
- item->window.rectClient.y = y;
- Item_UpdatePosition(item);
- }
- }
-}
-
-
-void Script_Orbit(itemDef_t *item, char **args) {
- const char *name;
- float cx, cy, x, y;
- int time;
-
- if (String_Parse(args, &name)) {
- if ( Float_Parse(args, &x) && Float_Parse(args, &y) && Float_Parse(args, &cx) && Float_Parse(args, &cy) && Int_Parse(args, &time) ) {
- Menu_OrbitItemByName(item->parent, name, x, y, cx, cy, time);
- }
- }
-}
-
-
-
-void Script_SetFocus(itemDef_t *item, char **args) {
- const char *name;
- itemDef_t *focusItem;
-
- if (String_Parse(args, &name)) {
- focusItem = Menu_FindItemByName(item->parent, name);
- if (focusItem && !(focusItem->window.flags & WINDOW_DECORATION) && !(focusItem->window.flags & WINDOW_HASFOCUS)) {
- Menu_ClearFocus(item->parent);
- focusItem->window.flags |= WINDOW_HASFOCUS;
- if (focusItem->onFocus) {
- Item_RunScript(focusItem, focusItem->onFocus);
- }
- if (DC->Assets.itemFocusSound) {
- DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND );
- }
- }
- }
-}
-
-void Script_SetPlayerModel(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- DC->setCVar("team_model", name);
- }
-}
-
-void Script_SetPlayerHead(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- DC->setCVar("team_headmodel", name);
- }
-}
-
-void Script_SetCvar(itemDef_t *item, char **args) {
- const char *cvar, *val;
- if (String_Parse(args, &cvar) && String_Parse(args, &val)) {
- DC->setCVar(cvar, val);
- }
-
-}
-
-void Script_Exec(itemDef_t *item, char **args) {
- const char *val;
- if (String_Parse(args, &val)) {
- DC->executeText(EXEC_APPEND, va("%s ; ", val));
- }
-}
-
-void Script_Play(itemDef_t *item, char **args) {
- const char *val;
- if (String_Parse(args, &val)) {
- DC->startLocalSound(DC->registerSound(val, qfalse), CHAN_LOCAL_SOUND);
- }
-}
-
-void Script_playLooped(itemDef_t *item, char **args) {
- const char *val;
- if (String_Parse(args, &val)) {
- DC->stopBackgroundTrack();
- DC->startBackgroundTrack(val, val);
- }
-}
-
-
-commandDef_t commandList[] =
-{
- {"fadein", &Script_FadeIn}, // group/name
- {"fadeout", &Script_FadeOut}, // group/name
- {"show", &Script_Show}, // group/name
- {"hide", &Script_Hide}, // group/name
- {"setcolor", &Script_SetColor}, // works on this
- {"open", &Script_Open}, // menu
- {"conditionalopen", &Script_ConditionalOpen}, // menu
- {"close", &Script_Close}, // menu
- {"setasset", &Script_SetAsset}, // works on this
- {"setbackground", &Script_SetBackground}, // works on this
- {"setitemcolor", &Script_SetItemColor}, // group/name
- {"setteamcolor", &Script_SetTeamColor}, // sets this background color to team color
- {"setfocus", &Script_SetFocus}, // sets this background color to team color
- {"setplayermodel", &Script_SetPlayerModel}, // sets this background color to team color
- {"setplayerhead", &Script_SetPlayerHead}, // sets this background color to team color
- {"transition", &Script_Transition}, // group/name
- {"setcvar", &Script_SetCvar}, // group/name
- {"exec", &Script_Exec}, // group/name
- {"play", &Script_Play}, // group/name
- {"playlooped", &Script_playLooped}, // group/name
- {"orbit", &Script_Orbit} // group/name
-};
-
-int scriptCommandCount = sizeof(commandList) / sizeof(commandDef_t);
-
-
-void Item_RunScript(itemDef_t *item, const char *s) {
- char script[1024], *p;
- int i;
- qboolean bRan;
- memset(script, 0, sizeof(script));
- if (item && s && s[0]) {
- Q_strcat(script, 1024, s);
- p = script;
- while (1) {
- const char *command;
- // expect command then arguments, ; ends command, NULL ends script
- if (!String_Parse(&p, &command)) {
- return;
- }
-
- if (command[0] == ';' && command[1] == '\0') {
- continue;
- }
-
- bRan = qfalse;
- for (i = 0; i < scriptCommandCount; i++) {
- if (Q_stricmp(command, commandList[i].name) == 0) {
- (commandList[i].handler(item, &p));
- bRan = qtrue;
- break;
- }
- }
- // not in our auto list, pass to handler
- if (!bRan) {
- DC->runScript(&p);
- }
- }
- }
-}
-
-
-qboolean Item_EnableShowViaCvar(itemDef_t *item, int flag) {
- char script[1024], *p;
- memset(script, 0, sizeof(script));
- if (item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
- char buff[1024];
- DC->getCVarString(item->cvarTest, buff, sizeof(buff));
-
- Q_strcat(script, 1024, item->enableCvar);
- p = script;
- while (1) {
- const char *val;
- // expect value then ; or NULL, NULL ends list
- if (!String_Parse(&p, &val)) {
- return (item->cvarFlags & flag) ? qfalse : qtrue;
- }
-
- if (val[0] == ';' && val[1] == '\0') {
- continue;
- }
-
- // enable it if any of the values are true
- if (item->cvarFlags & flag) {
- if (Q_stricmp(buff, val) == 0) {
- return qtrue;
- }
- } else {
- // disable it if any of the values are true
- if (Q_stricmp(buff, val) == 0) {
- return qfalse;
- }
- }
-
- }
- return (item->cvarFlags & flag) ? qfalse : qtrue;
- }
- return qtrue;
-}
-
-
-// will optionaly set focus to this item
-qboolean Item_SetFocus(itemDef_t *item, float x, float y) {
- int i;
- itemDef_t *oldFocus;
- sfxHandle_t *sfx = &DC->Assets.itemFocusSound;
- qboolean playSound = qfalse;
- menuDef_t *parent;
- // sanity check, non-null, not a decoration and does not already have the focus
- if (item == NULL || item->window.flags & WINDOW_DECORATION || item->window.flags & WINDOW_HASFOCUS || !(item->window.flags & WINDOW_VISIBLE)) {
- return qfalse;
- }
-
- // this can be NULL
- parent = (menuDef_t*)item->parent;
-
- // items can be enabled and disabled based on cvars
- if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
- return qfalse;
- }
-
- if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
- return qfalse;
- }
-
- oldFocus = Menu_ClearFocus(item->parent);
-
- if (item->type == ITEM_TYPE_TEXT) {
- rectDef_t r;
- r = item->textRect;
- r.y -= r.h;
- if (Rect_ContainsPoint(&r, x, y)) {
- item->window.flags |= WINDOW_HASFOCUS;
- if (item->focusSound) {
- sfx = &item->focusSound;
- }
- playSound = qtrue;
- } else {
- if (oldFocus) {
- oldFocus->window.flags |= WINDOW_HASFOCUS;
- if (oldFocus->onFocus) {
- Item_RunScript(oldFocus, oldFocus->onFocus);
- }
- }
- }
- } else {
- item->window.flags |= WINDOW_HASFOCUS;
- if (item->onFocus) {
- Item_RunScript(item, item->onFocus);
- }
- if (item->focusSound) {
- sfx = &item->focusSound;
- }
- playSound = qtrue;
- }
-
- if (playSound && sfx) {
- DC->startLocalSound( *sfx, CHAN_LOCAL_SOUND );
- }
-
- for (i = 0; i < parent->itemCount; i++) {
- if (parent->items[i] == item) {
- parent->cursorItem = i;
- break;
- }
- }
-
- return qtrue;
-}
-
-int Item_ListBox_MaxScroll(itemDef_t *item) {
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
- int count = DC->feederCount(item->special);
- int max;
-
- if (item->window.flags & WINDOW_HORIZONTAL) {
- max = count - (item->window.rect.w / listPtr->elementWidth) + 1;
- }
- else {
- max = count - (item->window.rect.h / listPtr->elementHeight) + 1;
- }
- if (max < 0) {
- return 0;
- }
- return max;
-}
-
-int Item_ListBox_ThumbPosition(itemDef_t *item) {
- float max, pos, size;
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
-
- max = Item_ListBox_MaxScroll(item);
- if (item->window.flags & WINDOW_HORIZONTAL) {
- size = item->window.rect.w - (SCROLLBAR_SIZE * 2) - 2;
- if (max > 0) {
- pos = (size-SCROLLBAR_SIZE) / (float) max;
- } else {
- pos = 0;
- }
- pos *= listPtr->startPos;
- return item->window.rect.x + 1 + SCROLLBAR_SIZE + pos;
- }
- else {
- size = item->window.rect.h - (SCROLLBAR_SIZE * 2) - 2;
- if (max > 0) {
- pos = (size-SCROLLBAR_SIZE) / (float) max;
- } else {
- pos = 0;
- }
- pos *= listPtr->startPos;
- return item->window.rect.y + 1 + SCROLLBAR_SIZE + pos;
- }
-}
-
-int Item_ListBox_ThumbDrawPosition(itemDef_t *item) {
- int min, max;
-
- if (itemCapture == item) {
- if (item->window.flags & WINDOW_HORIZONTAL) {
- min = item->window.rect.x + SCROLLBAR_SIZE + 1;
- max = item->window.rect.x + item->window.rect.w - 2*SCROLLBAR_SIZE - 1;
- if (DC->cursorx >= min + SCROLLBAR_SIZE/2 && DC->cursorx <= max + SCROLLBAR_SIZE/2) {
- return DC->cursorx - SCROLLBAR_SIZE/2;
- }
- else {
- return Item_ListBox_ThumbPosition(item);
- }
- }
- else {
- min = item->window.rect.y + SCROLLBAR_SIZE + 1;
- max = item->window.rect.y + item->window.rect.h - 2*SCROLLBAR_SIZE - 1;
- if (DC->cursory >= min + SCROLLBAR_SIZE/2 && DC->cursory <= max + SCROLLBAR_SIZE/2) {
- return DC->cursory - SCROLLBAR_SIZE/2;
- }
- else {
- return Item_ListBox_ThumbPosition(item);
- }
- }
- }
- else {
- return Item_ListBox_ThumbPosition(item);
- }
-}
-
-float Item_Slider_ThumbPosition(itemDef_t *item) {
- float value, range, x;
- editFieldDef_t *editDef = item->typeData;
-
- if (item->text) {
- x = item->textRect.x + item->textRect.w + 8;
- } else {
- x = item->window.rect.x;
- }
-
- if (editDef == NULL && item->cvar) {
- return x;
- }
-
- value = DC->getCVarValue(item->cvar);
-
- if (value < editDef->minVal) {
- value = editDef->minVal;
- } else if (value > editDef->maxVal) {
- value = editDef->maxVal;
- }
-
- range = editDef->maxVal - editDef->minVal;
- value -= editDef->minVal;
- value /= range;
- //value /= (editDef->maxVal - editDef->minVal);
- value *= SLIDER_WIDTH;
- x += value;
- // vm fuckage
- //x = x + (((float)value / editDef->maxVal) * SLIDER_WIDTH);
- return x;
-}
-
-int Item_Slider_OverSlider(itemDef_t *item, float x, float y) {
- rectDef_t r;
-
- r.x = Item_Slider_ThumbPosition(item) - (SLIDER_THUMB_WIDTH / 2);
- r.y = item->window.rect.y - 2;
- r.w = SLIDER_THUMB_WIDTH;
- r.h = SLIDER_THUMB_HEIGHT;
-
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_THUMB;
- }
- return 0;
-}
-
-int Item_ListBox_OverLB(itemDef_t *item, float x, float y) {
- rectDef_t r;
- listBoxDef_t *listPtr;
- int thumbstart;
- int count;
-
- count = DC->feederCount(item->special);
- listPtr = (listBoxDef_t*)item->typeData;
- if (item->window.flags & WINDOW_HORIZONTAL) {
- // check if on left arrow
- r.x = item->window.rect.x;
- r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
- r.h = r.w = SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_LEFTARROW;
- }
- // check if on right arrow
- r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_RIGHTARROW;
- }
- // check if on thumb
- thumbstart = Item_ListBox_ThumbPosition(item);
- r.x = thumbstart;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_THUMB;
- }
- r.x = item->window.rect.x + SCROLLBAR_SIZE;
- r.w = thumbstart - r.x;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_PGUP;
- }
- r.x = thumbstart + SCROLLBAR_SIZE;
- r.w = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_PGDN;
- }
- } else {
- r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
- r.y = item->window.rect.y;
- r.h = r.w = SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_LEFTARROW;
- }
- r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_RIGHTARROW;
- }
- thumbstart = Item_ListBox_ThumbPosition(item);
- r.y = thumbstart;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_THUMB;
- }
- r.y = item->window.rect.y + SCROLLBAR_SIZE;
- r.h = thumbstart - r.y;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_PGUP;
- }
- r.y = thumbstart + SCROLLBAR_SIZE;
- r.h = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_PGDN;
- }
- }
- return 0;
-}
-
-
-void Item_ListBox_MouseEnter(itemDef_t *item, float x, float y)
-{
- rectDef_t r;
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
-
- item->window.flags &= ~(WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN);
- item->window.flags |= Item_ListBox_OverLB(item, x, y);
-
- if (item->window.flags & WINDOW_HORIZONTAL) {
- if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
- // check for selection hit as we have exausted buttons and thumb
- if (listPtr->elementStyle == LISTBOX_IMAGE) {
- r.x = item->window.rect.x;
- r.y = item->window.rect.y;
- r.h = item->window.rect.h - SCROLLBAR_SIZE;
- r.w = item->window.rect.w - listPtr->drawPadding;
- if (Rect_ContainsPoint(&r, x, y)) {
- listPtr->cursorPos = (int)((x - r.x) / listPtr->elementWidth) + listPtr->startPos;
- if (listPtr->cursorPos >= listPtr->endPos) {
- listPtr->cursorPos = listPtr->endPos;
- }
- }
- } else {
- // text hit..
- }
- }
- } else if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
- r.x = item->window.rect.x;
- r.y = item->window.rect.y;
- r.w = item->window.rect.w - SCROLLBAR_SIZE;
- r.h = item->window.rect.h - listPtr->drawPadding;
- if (Rect_ContainsPoint(&r, x, y)) {
- listPtr->cursorPos = (int)((y - 2 - r.y) / listPtr->elementHeight) + listPtr->startPos;
- if (listPtr->cursorPos > listPtr->endPos) {
- listPtr->cursorPos = listPtr->endPos;
- }
- }
- }
-}
-
-void Item_MouseEnter(itemDef_t *item, float x, float y) {
- rectDef_t r;
- if (item) {
- r = item->textRect;
- r.y -= r.h;
- // in the text rect?
-
- // items can be enabled and disabled based on cvars
- if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
- return;
- }
-
- if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
- return;
- }
-
- if (Rect_ContainsPoint(&r, x, y)) {
- if (!(item->window.flags & WINDOW_MOUSEOVERTEXT)) {
- Item_RunScript(item, item->mouseEnterText);
- item->window.flags |= WINDOW_MOUSEOVERTEXT;
- }
- if (!(item->window.flags & WINDOW_MOUSEOVER)) {
- Item_RunScript(item, item->mouseEnter);
- item->window.flags |= WINDOW_MOUSEOVER;
- }
-
- } else {
- // not in the text rect
- if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
- // if we were
- Item_RunScript(item, item->mouseExitText);
- item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
- }
- if (!(item->window.flags & WINDOW_MOUSEOVER)) {
- Item_RunScript(item, item->mouseEnter);
- item->window.flags |= WINDOW_MOUSEOVER;
- }
-
- if (item->type == ITEM_TYPE_LISTBOX) {
- Item_ListBox_MouseEnter(item, x, y);
- }
- }
- }
-}
-
-void Item_MouseLeave(itemDef_t *item) {
- if (item) {
- if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
- Item_RunScript(item, item->mouseExitText);
- item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
- }
- Item_RunScript(item, item->mouseExit);
- item->window.flags &= ~(WINDOW_LB_RIGHTARROW | WINDOW_LB_LEFTARROW);
- }
-}
-
-itemDef_t *Menu_HitTest(menuDef_t *menu, float x, float y) {
- int i;
- for (i = 0; i < menu->itemCount; i++) {
- if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
- return menu->items[i];
- }
- }
- return NULL;
-}
-
-void Item_SetMouseOver(itemDef_t *item, qboolean focus) {
- if (item) {
- if (focus) {
- item->window.flags |= WINDOW_MOUSEOVER;
- } else {
- item->window.flags &= ~WINDOW_MOUSEOVER;
- }
- }
-}
-
-
-qboolean Item_OwnerDraw_HandleKey(itemDef_t *item, int key) {
- if (item && DC->ownerDrawHandleKey) {
- return DC->ownerDrawHandleKey(item->window.ownerDraw, item->window.ownerDrawFlags, &item->special, key);
- }
- return qfalse;
-}
-
-qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolean force) {
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
- int count = DC->feederCount(item->special);
- int max, viewmax;
-
- if (force || (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS)) {
- max = Item_ListBox_MaxScroll(item);
- if (item->window.flags & WINDOW_HORIZONTAL) {
- viewmax = (item->window.rect.w / listPtr->elementWidth);
- if ( key == K_LEFTARROW || key == K_KP_LEFTARROW )
- {
- if (!listPtr->notselectable) {
- listPtr->cursorPos--;
- if (listPtr->cursorPos < 0) {
- listPtr->cursorPos = 0;
- }
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos--;
- if (listPtr->startPos < 0)
- listPtr->startPos = 0;
- }
- return qtrue;
- }
- if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW )
- {
- if (!listPtr->notselectable) {
- listPtr->cursorPos++;
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= count) {
- listPtr->cursorPos = count-1;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos++;
- if (listPtr->startPos >= count)
- listPtr->startPos = count-1;
- }
- return qtrue;
- }
- }
- else {
- viewmax = (item->window.rect.h / listPtr->elementHeight);
- if ( key == K_UPARROW || key == K_KP_UPARROW )
- {
- if (!listPtr->notselectable) {
- listPtr->cursorPos--;
- if (listPtr->cursorPos < 0) {
- listPtr->cursorPos = 0;
- }
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos--;
- if (listPtr->startPos < 0)
- listPtr->startPos = 0;
- }
- return qtrue;
- }
- if ( key == K_DOWNARROW || key == K_KP_DOWNARROW )
- {
- if (!listPtr->notselectable) {
- listPtr->cursorPos++;
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= count) {
- listPtr->cursorPos = count-1;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos++;
- if (listPtr->startPos > max)
- listPtr->startPos = max;
- }
- return qtrue;
- }
- }
- // mouse hit
- if (key == K_MOUSE1 || key == K_MOUSE2) {
- if (item->window.flags & WINDOW_LB_LEFTARROW) {
- listPtr->startPos--;
- if (listPtr->startPos < 0) {
- listPtr->startPos = 0;
- }
- } else if (item->window.flags & WINDOW_LB_RIGHTARROW) {
- // one down
- listPtr->startPos++;
- if (listPtr->startPos > max) {
- listPtr->startPos = max;
- }
- } else if (item->window.flags & WINDOW_LB_PGUP) {
- // page up
- listPtr->startPos -= viewmax;
- if (listPtr->startPos < 0) {
- listPtr->startPos = 0;
- }
- } else if (item->window.flags & WINDOW_LB_PGDN) {
- // page down
- listPtr->startPos += viewmax;
- if (listPtr->startPos > max) {
- listPtr->startPos = max;
- }
- } else if (item->window.flags & WINDOW_LB_THUMB) {
- // Display_SetCaptureItem(item);
- } else {
- // select an item
- if (DC->realTime < lastListBoxClickTime && listPtr->doubleClick) {
- Item_RunScript(item, listPtr->doubleClick);
- }
- lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY;
- if (item->cursorPos != listPtr->cursorPos) {
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- }
- return qtrue;
- }
- if ( key == K_HOME || key == K_KP_HOME) {
- // home
- listPtr->startPos = 0;
- return qtrue;
- }
- if ( key == K_END || key == K_KP_END) {
- // end
- listPtr->startPos = max;
- return qtrue;
- }
- if (key == K_PGUP || key == K_KP_PGUP ) {
- // page up
- if (!listPtr->notselectable) {
- listPtr->cursorPos -= viewmax;
- if (listPtr->cursorPos < 0) {
- listPtr->cursorPos = 0;
- }
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos -= viewmax;
- if (listPtr->startPos < 0) {
- listPtr->startPos = 0;
- }
- }
- return qtrue;
- }
- if ( key == K_PGDN || key == K_KP_PGDN ) {
- // page down
- if (!listPtr->notselectable) {
- listPtr->cursorPos += viewmax;
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= count) {
- listPtr->cursorPos = count-1;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos += viewmax;
- if (listPtr->startPos > max) {
- listPtr->startPos = max;
- }
- }
- return qtrue;
- }
- }
- return qfalse;
-}
-
-qboolean Item_YesNo_HandleKey(itemDef_t *item, int key) {
-
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
- if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
- DC->setCVar(item->cvar, va("%i", !DC->getCVarValue(item->cvar)));
- return qtrue;
- }
- }
-
- return qfalse;
-
-}
-
-int Item_Multi_CountSettings(itemDef_t *item) {
- multiDef_t *multiPtr = (multiDef_t*)item->typeData;
- if (multiPtr == NULL) {
- return 0;
- }
- return multiPtr->count;
-}
-
-int Item_Multi_FindCvarByValue(itemDef_t *item) {
- char buff[1024];
- float value = 0;
- int i;
- multiDef_t *multiPtr = (multiDef_t*)item->typeData;
- if (multiPtr) {
- if (multiPtr->strDef) {
- DC->getCVarString(item->cvar, buff, sizeof(buff));
- } else {
- value = DC->getCVarValue(item->cvar);
- }
- for (i = 0; i < multiPtr->count; i++) {
- if (multiPtr->strDef) {
- if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
- return i;
- }
- } else {
- if (multiPtr->cvarValue[i] == value) {
- return i;
- }
- }
- }
- }
- return 0;
-}
-
-const char *Item_Multi_Setting(itemDef_t *item) {
- char buff[1024];
- float value = 0;
- int i;
- multiDef_t *multiPtr = (multiDef_t*)item->typeData;
- if (multiPtr) {
- if (multiPtr->strDef) {
- DC->getCVarString(item->cvar, buff, sizeof(buff));
- } else {
- value = DC->getCVarValue(item->cvar);
- }
- for (i = 0; i < multiPtr->count; i++) {
- if (multiPtr->strDef) {
- if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
- return multiPtr->cvarList[i];
- }
- } else {
- if (multiPtr->cvarValue[i] == value) {
- return multiPtr->cvarList[i];
- }
- }
- }
- }
- return "";
-}
-
-qboolean Item_Multi_HandleKey(itemDef_t *item, int key) {
- multiDef_t *multiPtr = (multiDef_t*)item->typeData;
- if (multiPtr) {
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
- if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
- int current = Item_Multi_FindCvarByValue(item) + 1;
- int max = Item_Multi_CountSettings(item);
- if ( current < 0 || current >= max ) {
- current = 0;
- }
- if (multiPtr->strDef) {
- DC->setCVar(item->cvar, multiPtr->cvarStr[current]);
- } else {
- float value = multiPtr->cvarValue[current];
- if (((float)((int) value)) == value) {
- DC->setCVar(item->cvar, va("%i", (int) value ));
- }
- else {
- DC->setCVar(item->cvar, va("%f", value ));
- }
- }
- return qtrue;
- }
- }
- }
- return qfalse;
-}
-
-qboolean Item_TextField_HandleKey(itemDef_t *item, int key) {
- char buff[1024];
- int len;
- itemDef_t *newItem = NULL;
- editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
-
- if (item->cvar) {
-
- memset(buff, 0, sizeof(buff));
- DC->getCVarString(item->cvar, buff, sizeof(buff));
- len = strlen(buff);
- if (editPtr->maxChars && len > editPtr->maxChars) {
- len = editPtr->maxChars;
- }
- if ( key & K_CHAR_FLAG ) {
- key &= ~K_CHAR_FLAG;
-
-
- if (key == 'h' - 'a' + 1 ) { // ctrl-h is backspace
- if ( item->cursorPos > 0 ) {
- memmove( &buff[item->cursorPos - 1], &buff[item->cursorPos], len + 1 - item->cursorPos);
- item->cursorPos--;
- if (item->cursorPos < editPtr->paintOffset) {
- editPtr->paintOffset--;
- }
- }
- DC->setCVar(item->cvar, buff);
- return qtrue;
- }
-
-
- //
- // ignore any non printable chars
- //
- if ( key < 32 || !item->cvar) {
- return qtrue;
- }
-
- if (item->type == ITEM_TYPE_NUMERICFIELD) {
- if (key < '0' || key > '9') {
- return qfalse;
- }
- }
-
- if (!DC->getOverstrikeMode()) {
- if (( len == MAX_EDITFIELD - 1 ) || (editPtr->maxChars && len >= editPtr->maxChars)) {
- return qtrue;
- }
- memmove( &buff[item->cursorPos + 1], &buff[item->cursorPos], len + 1 - item->cursorPos );
- } else {
- if (editPtr->maxChars && item->cursorPos >= editPtr->maxChars) {
- return qtrue;
- }
- }
-
- buff[item->cursorPos] = key;
-
- DC->setCVar(item->cvar, buff);
-
- if (item->cursorPos < len + 1) {
- item->cursorPos++;
- if (editPtr->maxPaintChars && item->cursorPos > editPtr->maxPaintChars) {
- editPtr->paintOffset++;
- }
- }
-
- } else {
-
- if ( key == K_DEL || key == K_KP_DEL ) {
- if ( item->cursorPos < len ) {
- memmove( buff + item->cursorPos, buff + item->cursorPos + 1, len - item->cursorPos);
- DC->setCVar(item->cvar, buff);
- }
- return qtrue;
- }
-
- if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW )
- {
- if (editPtr->maxPaintChars && item->cursorPos >= editPtr->maxPaintChars && item->cursorPos < len) {
- item->cursorPos++;
- editPtr->paintOffset++;
- return qtrue;
- }
- if (item->cursorPos < len) {
- item->cursorPos++;
- }
- return qtrue;
- }
-
- if ( key == K_LEFTARROW || key == K_KP_LEFTARROW )
- {
- if ( item->cursorPos > 0 ) {
- item->cursorPos--;
- }
- if (item->cursorPos < editPtr->paintOffset) {
- editPtr->paintOffset--;
- }
- return qtrue;
- }
-
- if ( key == K_HOME || key == K_KP_HOME) {// || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {
- item->cursorPos = 0;
- editPtr->paintOffset = 0;
- return qtrue;
- }
-
- if ( key == K_END || key == K_KP_END) {// ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {
- item->cursorPos = len;
- if(item->cursorPos > editPtr->maxPaintChars) {
- editPtr->paintOffset = len - editPtr->maxPaintChars;
- }
- return qtrue;
- }
-
- if ( key == K_INS || key == K_KP_INS ) {
- DC->setOverstrikeMode(!DC->getOverstrikeMode());
- return qtrue;
- }
- }
-
- if (key == K_TAB || key == K_DOWNARROW || key == K_KP_DOWNARROW) {
- newItem = Menu_SetNextCursorItem(item->parent);
- if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
- g_editItem = newItem;
- }
- }
-
- if (key == K_UPARROW || key == K_KP_UPARROW) {
- newItem = Menu_SetPrevCursorItem(item->parent);
- if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
- g_editItem = newItem;
- }
- }
-
- if ( key == K_ENTER || key == K_KP_ENTER || key == K_ESCAPE) {
- return qfalse;
- }
-
- return qtrue;
- }
- return qfalse;
-
-}
-
-static void Scroll_ListBox_AutoFunc(void *p) {
- scrollInfo_t *si = (scrollInfo_t*)p;
- if (DC->realTime > si->nextScrollTime) {
- // need to scroll which is done by simulating a click to the item
- // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
- // so it calls it directly
- Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
- si->nextScrollTime = DC->realTime + si->adjustValue;
- }
-
- if (DC->realTime > si->nextAdjustTime) {
- si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
- if (si->adjustValue > SCROLL_TIME_FLOOR) {
- si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
- }
- }
-}
-
-static void Scroll_ListBox_ThumbFunc(void *p) {
- scrollInfo_t *si = (scrollInfo_t*)p;
- rectDef_t r;
- int pos, max;
-
- listBoxDef_t *listPtr = (listBoxDef_t*)si->item->typeData;
- if (si->item->window.flags & WINDOW_HORIZONTAL) {
- if (DC->cursorx == si->xStart) {
- return;
- }
- r.x = si->item->window.rect.x + SCROLLBAR_SIZE + 1;
- r.y = si->item->window.rect.y + si->item->window.rect.h - SCROLLBAR_SIZE - 1;
- r.h = SCROLLBAR_SIZE;
- r.w = si->item->window.rect.w - (SCROLLBAR_SIZE*2) - 2;
- max = Item_ListBox_MaxScroll(si->item);
- //
- pos = (DC->cursorx - r.x - SCROLLBAR_SIZE/2) * max / (r.w - SCROLLBAR_SIZE);
- if (pos < 0) {
- pos = 0;
- }
- else if (pos > max) {
- pos = max;
- }
- listPtr->startPos = pos;
- si->xStart = DC->cursorx;
- }
- else if (DC->cursory != si->yStart) {
-
- r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_SIZE - 1;
- r.y = si->item->window.rect.y + SCROLLBAR_SIZE + 1;
- r.h = si->item->window.rect.h - (SCROLLBAR_SIZE*2) - 2;
- r.w = SCROLLBAR_SIZE;
- max = Item_ListBox_MaxScroll(si->item);
- //
- pos = (DC->cursory - r.y - SCROLLBAR_SIZE/2) * max / (r.h - SCROLLBAR_SIZE);
- if (pos < 0) {
- pos = 0;
- }
- else if (pos > max) {
- pos = max;
- }
- listPtr->startPos = pos;
- si->yStart = DC->cursory;
- }
-
- if (DC->realTime > si->nextScrollTime) {
- // need to scroll which is done by simulating a click to the item
- // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
- // so it calls it directly
- Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
- si->nextScrollTime = DC->realTime + si->adjustValue;
- }
-
- if (DC->realTime > si->nextAdjustTime) {
- si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
- if (si->adjustValue > SCROLL_TIME_FLOOR) {
- si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
- }
- }
-}
-
-static void Scroll_Slider_ThumbFunc(void *p) {
- float x, value, cursorx;
- scrollInfo_t *si = (scrollInfo_t*)p;
- editFieldDef_t *editDef = si->item->typeData;
-
- if (si->item->text) {
- x = si->item->textRect.x + si->item->textRect.w + 8;
- } else {
- x = si->item->window.rect.x;
- }
-
- cursorx = DC->cursorx;
-
- if (cursorx < x) {
- cursorx = x;
- } else if (cursorx > x + SLIDER_WIDTH) {
- cursorx = x + SLIDER_WIDTH;
- }
- value = cursorx - x;
- value /= SLIDER_WIDTH;
- value *= (editDef->maxVal - editDef->minVal);
- value += editDef->minVal;
- DC->setCVar(si->item->cvar, va("%f", value));
-}
-
-void Item_StartCapture(itemDef_t *item, int key) {
- int flags;
- switch (item->type) {
- case ITEM_TYPE_EDITFIELD:
- case ITEM_TYPE_NUMERICFIELD:
-
- case ITEM_TYPE_LISTBOX:
- {
- flags = Item_ListBox_OverLB(item, DC->cursorx, DC->cursory);
- if (flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW)) {
- scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START;
- scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
- scrollInfo.adjustValue = SCROLL_TIME_START;
- scrollInfo.scrollKey = key;
- scrollInfo.scrollDir = (flags & WINDOW_LB_LEFTARROW) ? qtrue : qfalse;
- scrollInfo.item = item;
- captureData = &scrollInfo;
- captureFunc = &Scroll_ListBox_AutoFunc;
- itemCapture = item;
- } else if (flags & WINDOW_LB_THUMB) {
- scrollInfo.scrollKey = key;
- scrollInfo.item = item;
- scrollInfo.xStart = DC->cursorx;
- scrollInfo.yStart = DC->cursory;
- captureData = &scrollInfo;
- captureFunc = &Scroll_ListBox_ThumbFunc;
- itemCapture = item;
- }
- break;
- }
- case ITEM_TYPE_SLIDER:
- {
- flags = Item_Slider_OverSlider(item, DC->cursorx, DC->cursory);
- if (flags & WINDOW_LB_THUMB) {
- scrollInfo.scrollKey = key;
- scrollInfo.item = item;
- scrollInfo.xStart = DC->cursorx;
- scrollInfo.yStart = DC->cursory;
- captureData = &scrollInfo;
- captureFunc = &Scroll_Slider_ThumbFunc;
- itemCapture = item;
- }
- break;
- }
- }
-}
-
-void Item_StopCapture(itemDef_t *item) {
-
-}
-
-qboolean Item_Slider_HandleKey(itemDef_t *item, int key, qboolean down) {
- float x, value, width, work;
-
- //DC->Print("slider handle key\n");
- if (item->window.flags & WINDOW_HASFOCUS && item->cvar && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
- if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
- editFieldDef_t *editDef = item->typeData;
- if (editDef) {
- rectDef_t testRect;
- width = SLIDER_WIDTH;
- if (item->text) {
- x = item->textRect.x + item->textRect.w + 8;
- } else {
- x = item->window.rect.x;
- }
-
- testRect = item->window.rect;
- testRect.x = x;
- value = (float)SLIDER_THUMB_WIDTH / 2;
- testRect.x -= value;
- //DC->Print("slider x: %f\n", testRect.x);
- testRect.w = (SLIDER_WIDTH + (float)SLIDER_THUMB_WIDTH / 2);
- //DC->Print("slider w: %f\n", testRect.w);
- if (Rect_ContainsPoint(&testRect, DC->cursorx, DC->cursory)) {
- work = DC->cursorx - x;
- value = work / width;
- value *= (editDef->maxVal - editDef->minVal);
- // vm fuckage
- // value = (((float)(DC->cursorx - x)/ SLIDER_WIDTH) * (editDef->maxVal - editDef->minVal));
- value += editDef->minVal;
- DC->setCVar(item->cvar, va("%f", value));
- return qtrue;
- }
- }
- }
- }
- DC->Print("slider handle key exit\n");
- return qfalse;
-}
-
-
-qboolean Item_HandleKey(itemDef_t *item, int key, qboolean down) {
-
- if (itemCapture) {
- Item_StopCapture(itemCapture);
- itemCapture = NULL;
- captureFunc = 0;
- captureData = NULL;
- } else {
- if ( down && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
- Item_StartCapture(item, key);
- }
- }
-
- if (!down) {
- return qfalse;
- }
-
- switch (item->type) {
- case ITEM_TYPE_BUTTON:
- return qfalse;
- break;
- case ITEM_TYPE_RADIOBUTTON:
- return qfalse;
- break;
- case ITEM_TYPE_CHECKBOX:
- return qfalse;
- break;
- case ITEM_TYPE_EDITFIELD:
- case ITEM_TYPE_NUMERICFIELD:
- //return Item_TextField_HandleKey(item, key);
- return qfalse;
- break;
- case ITEM_TYPE_COMBO:
- return qfalse;
- break;
- case ITEM_TYPE_LISTBOX:
- return Item_ListBox_HandleKey(item, key, down, qfalse);
- break;
- case ITEM_TYPE_YESNO:
- return Item_YesNo_HandleKey(item, key);
- break;
- case ITEM_TYPE_MULTI:
- return Item_Multi_HandleKey(item, key);
- break;
- case ITEM_TYPE_OWNERDRAW:
- return Item_OwnerDraw_HandleKey(item, key);
- break;
- case ITEM_TYPE_BIND:
- return Item_Bind_HandleKey(item, key, down);
- break;
- case ITEM_TYPE_SLIDER:
- return Item_Slider_HandleKey(item, key, down);
- break;
- //case ITEM_TYPE_IMAGE:
- // Item_Image_Paint(item);
- // break;
- default:
- return qfalse;
- break;
- }
-
- //return qfalse;
-}
-
-void Item_Action(itemDef_t *item) {
- if (item) {
- Item_RunScript(item, item->action);
- }
-}
-
-itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu) {
- qboolean wrapped = qfalse;
- int oldCursor = menu->cursorItem;
-
- if (menu->cursorItem < 0) {
- menu->cursorItem = menu->itemCount-1;
- wrapped = qtrue;
- }
-
- while (menu->cursorItem > -1) {
-
- menu->cursorItem--;
- if (menu->cursorItem < 0 && !wrapped) {
- wrapped = qtrue;
- menu->cursorItem = menu->itemCount -1;
- }
-
- if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
- Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
- return menu->items[menu->cursorItem];
- }
- }
- menu->cursorItem = oldCursor;
- return NULL;
-
-}
-
-itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu) {
-
- qboolean wrapped = qfalse;
- int oldCursor = menu->cursorItem;
-
-
- if (menu->cursorItem == -1) {
- menu->cursorItem = 0;
- wrapped = qtrue;
- }
-
- while (menu->cursorItem < menu->itemCount) {
-
- menu->cursorItem++;
- if (menu->cursorItem >= menu->itemCount && !wrapped) {
- wrapped = qtrue;
- menu->cursorItem = 0;
- }
- if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
- Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
- return menu->items[menu->cursorItem];
- }
-
- }
-
- menu->cursorItem = oldCursor;
- return NULL;
-}
-
-static void Window_CloseCinematic(windowDef_t *window) {
- if (window->style == WINDOW_STYLE_CINEMATIC && window->cinematic >= 0) {
- DC->stopCinematic(window->cinematic);
- window->cinematic = -1;
- }
-}
-
-static void Menu_CloseCinematics(menuDef_t *menu) {
- if (menu) {
- int i;
- Window_CloseCinematic(&menu->window);
- for (i = 0; i < menu->itemCount; i++) {
- Window_CloseCinematic(&menu->items[i]->window);
- if (menu->items[i]->type == ITEM_TYPE_OWNERDRAW) {
- DC->stopCinematic(0-menu->items[i]->window.ownerDraw);
- }
- }
- }
-}
-
-static void Display_CloseCinematics( void ) {
- int i;
- for (i = 0; i < menuCount; i++) {
- Menu_CloseCinematics(&Menus[i]);
- }
-}
-
-void Menus_Activate(menuDef_t *menu) {
- menu->window.flags |= (WINDOW_HASFOCUS | WINDOW_VISIBLE);
- if (menu->onOpen) {
- itemDef_t item;
- item.parent = menu;
- Item_RunScript(&item, menu->onOpen);
- }
-
- if (menu->soundName && *menu->soundName) {
-// DC->stopBackgroundTrack(); // you don't want to do this since it will reset s_rawend
- DC->startBackgroundTrack(menu->soundName, menu->soundName);
- }
-
- Display_CloseCinematics();
-
-}
-
-int Display_VisibleMenuCount( void ) {
- int i, count;
- count = 0;
- for (i = 0; i < menuCount; i++) {
- if (Menus[i].window.flags & (WINDOW_FORCED | WINDOW_VISIBLE)) {
- count++;
- }
- }
- return count;
-}
-
-void Menus_HandleOOBClick(menuDef_t *menu, int key, qboolean down) {
- if (menu) {
- int i;
- // basically the behaviour we are looking for is if there are windows in the stack.. see if
- // the cursor is within any of them.. if not close them otherwise activate them and pass the
- // key on.. force a mouse move to activate focus and script stuff
- if (down && menu->window.flags & WINDOW_OOB_CLICK) {
- Menu_RunCloseScript(menu);
- menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
- }
-
- for (i = 0; i < menuCount; i++) {
- if (Menu_OverActiveItem(&Menus[i], DC->cursorx, DC->cursory)) {
- Menu_RunCloseScript(menu);
- menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
- Menus_Activate(&Menus[i]);
- Menu_HandleMouseMove(&Menus[i], DC->cursorx, DC->cursory);
- Menu_HandleKey(&Menus[i], key, down);
- }
- }
-
- if (Display_VisibleMenuCount() == 0) {
- if (DC->Pause) {
- DC->Pause(qfalse);
- }
- }
- Display_CloseCinematics();
- }
-}
-
-static rectDef_t *Item_CorrectedTextRect(itemDef_t *item) {
- static rectDef_t rect;
- memset(&rect, 0, sizeof(rectDef_t));
- if (item) {
- rect = item->textRect;
- if (rect.w) {
- rect.y -= rect.h;
- }
- }
- return ▭
-}
-
-void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) {
- int i;
- itemDef_t *item = NULL;
- qboolean inHandler = qfalse;
-
- if (inHandler) {
- return;
- }
-
- inHandler = qtrue;
- if (g_waitingForKey && down) {
- Item_Bind_HandleKey(g_bindItem, key, down);
- inHandler = qfalse;
- return;
- }
-
- if (g_editingField && down) {
- if (!Item_TextField_HandleKey(g_editItem, key)) {
- g_editingField = qfalse;
- g_editItem = NULL;
- inHandler = qfalse;
- return;
- } else if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) {
- g_editingField = qfalse;
- g_editItem = NULL;
- Display_MouseMove(NULL, DC->cursorx, DC->cursory);
- } else if (key == K_TAB || key == K_UPARROW || key == K_DOWNARROW) {
- return;
- }
- }
-
- if (menu == NULL) {
- inHandler = qfalse;
- return;
- }
-
- // see if the mouse is within the window bounds and if so is this a mouse click
- if (down && !(menu->window.flags & WINDOW_POPUP) && !Rect_ContainsPoint(&menu->window.rect, DC->cursorx, DC->cursory)) {
- static qboolean inHandleKey = qfalse;
- if (!inHandleKey && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
- inHandleKey = qtrue;
- Menus_HandleOOBClick(menu, key, down);
- inHandleKey = qfalse;
- inHandler = qfalse;
- return;
- }
- }
-
- // get the item with focus
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
- item = menu->items[i];
- }
- }
-
- if (item != NULL) {
- if (Item_HandleKey(item, key, down)) {
- Item_Action(item);
- inHandler = qfalse;
- return;
- }
- }
-
- if (!down) {
- inHandler = qfalse;
- return;
- }
-
- // default handling
- switch ( key ) {
-
- case K_F11:
- if (DC->getCVarValue("developer")) {
- debugMode ^= 1;
- }
- break;
-
- case K_F12:
- if (DC->getCVarValue("developer")) {
- DC->executeText(EXEC_APPEND, "screenshot\n");
- }
- break;
- case K_KP_UPARROW:
- case K_UPARROW:
- Menu_SetPrevCursorItem(menu);
- break;
-
- case K_ESCAPE:
- if (!g_waitingForKey && menu->onESC) {
- itemDef_t it;
- it.parent = menu;
- Item_RunScript(&it, menu->onESC);
- }
- break;
- case K_TAB:
- case K_KP_DOWNARROW:
- case K_DOWNARROW:
- Menu_SetNextCursorItem(menu);
- break;
-
- case K_MOUSE1:
- case K_MOUSE2:
- if (item) {
- if (item->type == ITEM_TYPE_TEXT) {
- if (Rect_ContainsPoint(Item_CorrectedTextRect(item), DC->cursorx, DC->cursory)) {
- Item_Action(item);
- }
- } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
- item->cursorPos = 0;
- g_editingField = qtrue;
- g_editItem = item;
- DC->setOverstrikeMode(qtrue);
- }
- } else {
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
- Item_Action(item);
- }
- }
- }
- break;
-
- case K_JOY1:
- case K_JOY2:
- case K_JOY3:
- case K_JOY4:
- case K_AUX1:
- case K_AUX2:
- case K_AUX3:
- case K_AUX4:
- case K_AUX5:
- case K_AUX6:
- case K_AUX7:
- case K_AUX8:
- case K_AUX9:
- case K_AUX10:
- case K_AUX11:
- case K_AUX12:
- case K_AUX13:
- case K_AUX14:
- case K_AUX15:
- case K_AUX16:
- break;
- case K_KP_ENTER:
- case K_ENTER:
- if (item) {
- if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
- item->cursorPos = 0;
- g_editingField = qtrue;
- g_editItem = item;
- DC->setOverstrikeMode(qtrue);
- } else {
- Item_Action(item);
- }
- }
- break;
- }
- inHandler = qfalse;
-}
-
-void ToWindowCoords(float *x, float *y, windowDef_t *window) {
- if (window->border != 0) {
- *x += window->borderSize;
- *y += window->borderSize;
- }
- *x += window->rect.x;
- *y += window->rect.y;
-}
-
-void Rect_ToWindowCoords(rectDef_t *rect, windowDef_t *window) {
- ToWindowCoords(&rect->x, &rect->y, window);
-}
-
-void Item_SetTextExtents(itemDef_t *item, int *width, int *height, const char *text) {
- const char *textPtr = (text) ? text : item->text;
-
- if (textPtr == NULL ) {
- return;
- }
-
- *width = item->textRect.w;
- *height = item->textRect.h;
-
- // keeps us from computing the widths and heights more than once
- if (*width == 0 || (item->type == ITEM_TYPE_OWNERDRAW && item->textalignment == ITEM_ALIGN_CENTER)) {
- int originalWidth = DC->textWidth(item->text, item->textscale, 0);
-
- if (item->type == ITEM_TYPE_OWNERDRAW && (item->textalignment == ITEM_ALIGN_CENTER || item->textalignment == ITEM_ALIGN_RIGHT)) {
- originalWidth += DC->ownerDrawWidth(item->window.ownerDraw, item->textscale);
- } else if (item->type == ITEM_TYPE_EDITFIELD && item->textalignment == ITEM_ALIGN_CENTER && item->cvar) {
- char buff[256];
- DC->getCVarString(item->cvar, buff, 256);
- originalWidth += DC->textWidth(buff, item->textscale, 0);
- }
-
- *width = DC->textWidth(textPtr, item->textscale, 0);
- *height = DC->textHeight(textPtr, item->textscale, 0);
- item->textRect.w = *width;
- item->textRect.h = *height;
- item->textRect.x = item->textalignx;
- item->textRect.y = item->textaligny;
- if (item->textalignment == ITEM_ALIGN_RIGHT) {
- item->textRect.x = item->textalignx - originalWidth;
- } else if (item->textalignment == ITEM_ALIGN_CENTER) {
- item->textRect.x = item->textalignx - originalWidth / 2;
- }
-
- ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
- }
-}
-
-void Item_TextColor(itemDef_t *item, vec4_t *newColor) {
- vec4_t lowLight;
- menuDef_t *parent = (menuDef_t*)item->parent;
-
- Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
- lowLight[0] = 0.8 * item->window.foreColor[0];
- lowLight[1] = 0.8 * item->window.foreColor[1];
- lowLight[2] = 0.8 * item->window.foreColor[2];
- lowLight[3] = 0.8 * item->window.foreColor[3];
- LerpColor(item->window.foreColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else {
- memcpy(newColor, &item->window.foreColor, sizeof(vec4_t));
- // items can be enabled and disabled based on cvars
- }
-
- if (item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
- if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
- memcpy(newColor, &parent->disableColor, sizeof(vec4_t));
- }
- }
-}
-
-void Item_Text_AutoWrapped_Paint(itemDef_t *item) {
- char text[1024];
- const char *p, *textPtr, *newLinePtr;
- char buff[1024];
- int width, height, len, textWidth, newLine, newLineWidth;
- float y;
- vec4_t color;
-
- textWidth = 0;
- newLinePtr = NULL;
-
- if (item->text == NULL) {
- if (item->cvar == NULL) {
- return;
- }
- else {
- DC->getCVarString(item->cvar, text, sizeof(text));
- textPtr = text;
- }
- }
- else {
- textPtr = item->text;
- }
- if (*textPtr == '\0') {
- return;
- }
- Item_TextColor(item, &color);
- Item_SetTextExtents(item, &width, &height, textPtr);
-
- y = item->textaligny;
- len = 0;
- buff[0] = '\0';
- newLine = 0;
- newLineWidth = 0;
- p = textPtr;
- while (p) {
- if (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\0') {
- newLine = len;
- newLinePtr = p+1;
- newLineWidth = textWidth;
- }
- textWidth = DC->textWidth(buff, item->textscale, 0);
- if ( (newLine && textWidth > item->window.rect.w) || *p == '\n' || *p == '\0') {
- if (len) {
- if (item->textalignment == ITEM_ALIGN_LEFT) {
- item->textRect.x = item->textalignx;
- } else if (item->textalignment == ITEM_ALIGN_RIGHT) {
- item->textRect.x = item->textalignx - newLineWidth;
- } else if (item->textalignment == ITEM_ALIGN_CENTER) {
- item->textRect.x = item->textalignx - newLineWidth / 2;
- }
- item->textRect.y = y;
- ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
- //
- buff[newLine] = '\0';
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, buff, 0, 0, item->textStyle);
- }
- if (*p == '\0') {
- break;
- }
- //
- y += height + 5;
- p = newLinePtr;
- len = 0;
- newLine = 0;
- newLineWidth = 0;
- continue;
- }
- buff[len++] = *p++;
- buff[len] = '\0';
- }
-}
-
-void Item_Text_Wrapped_Paint(itemDef_t *item) {
- char text[1024];
- const char *p, *start, *textPtr;
- char buff[1024];
- int width, height;
- float x, y;
- vec4_t color;
-
- // now paint the text and/or any optional images
- // default to left
-
- if (item->text == NULL) {
- if (item->cvar == NULL) {
- return;
- }
- else {
- DC->getCVarString(item->cvar, text, sizeof(text));
- textPtr = text;
- }
- }
- else {
- textPtr = item->text;
- }
- if (*textPtr == '\0') {
- return;
- }
-
- Item_TextColor(item, &color);
- Item_SetTextExtents(item, &width, &height, textPtr);
-
- x = item->textRect.x;
- y = item->textRect.y;
- start = textPtr;
- p = strchr(textPtr, '\r');
- while (p && *p) {
- strncpy(buff, start, p-start+1);
- buff[p-start] = '\0';
- DC->drawText(x, y, item->textscale, color, buff, 0, 0, item->textStyle);
- y += height + 5;
- start += p - start + 1;
- p = strchr(p+1, '\r');
- }
- DC->drawText(x, y, item->textscale, color, start, 0, 0, item->textStyle);
-}
-
-void Item_Text_Paint(itemDef_t *item) {
- char text[1024];
- const char *textPtr;
- int height, width;
- vec4_t color;
-
- if (item->window.flags & WINDOW_WRAPPED) {
- Item_Text_Wrapped_Paint(item);
- return;
- }
- if (item->window.flags & WINDOW_AUTOWRAPPED) {
- Item_Text_AutoWrapped_Paint(item);
- return;
- }
-
- if (item->text == NULL) {
- if (item->cvar == NULL) {
- return;
- }
- else {
- DC->getCVarString(item->cvar, text, sizeof(text));
- textPtr = text;
- }
- }
- else {
- textPtr = item->text;
- }
-
- // this needs to go here as it sets extents for cvar types as well
- Item_SetTextExtents(item, &width, &height, textPtr);
-
- if (*textPtr == '\0') {
- return;
- }
-
-
- Item_TextColor(item, &color);
-
- //FIXME: this is a fucking mess
-/*
- adjust = 0;
- if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
- adjust = 0.5;
- }
-
- if (item->textStyle == ITEM_TEXTSTYLE_SHADOWED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
- Fade(&item->window.flags, &DC->Assets.shadowColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
- DC->drawText(item->textRect.x + DC->Assets.shadowX, item->textRect.y + DC->Assets.shadowY, item->textscale, DC->Assets.shadowColor, textPtr, adjust);
- }
-*/
-
-
-// if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
-// Fade(&item->window.flags, &item->window.outlineColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
-// /*
-// Text_Paint(item->textRect.x-1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x+1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x-1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x+1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x-1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x+1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
-// */
-// DC->drawText(item->textRect.x - 1, item->textRect.y + 1, item->textscale * 1.02, item->window.outlineColor, textPtr, adjust);
-// }
-
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, textPtr, 0, 0, item->textStyle);
-}
-
-
-
-//float trap_Cvar_VariableValue( const char *var_name );
-//void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-
-void Item_TextField_Paint(itemDef_t *item) {
- char buff[1024];
- vec4_t newColor, lowLight;
- int offset;
- menuDef_t *parent = (menuDef_t*)item->parent;
- editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
-
- Item_Text_Paint(item);
-
- buff[0] = '\0';
-
- if (item->cvar) {
- DC->getCVarString(item->cvar, buff, sizeof(buff));
- }
-
- parent = (menuDef_t*)item->parent;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- offset = (item->text && *item->text) ? 8 : 0;
- if (item->window.flags & WINDOW_HASFOCUS && g_editingField) {
- char cursor = DC->getOverstrikeMode() ? '_' : '|';
- DC->drawTextWithCursor(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, item->cursorPos - editPtr->paintOffset , cursor, editPtr->maxPaintChars, item->textStyle);
- } else {
- DC->drawText(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, 0, editPtr->maxPaintChars, item->textStyle);
- }
-
-}
-
-void Item_YesNo_Paint(itemDef_t *item) {
- vec4_t newColor, lowLight;
- float value;
- menuDef_t *parent = (menuDef_t*)item->parent;
-
- value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- if (item->text) {
- Item_Text_Paint(item);
- DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
- } else {
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
- }
-}
-
-void Item_Multi_Paint(itemDef_t *item) {
- vec4_t newColor, lowLight;
- const char *text = "";
- menuDef_t *parent = (menuDef_t*)item->parent;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- text = Item_Multi_Setting(item);
-
- if (item->text) {
- Item_Text_Paint(item);
- DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
- } else {
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
- }
-}
-
-
-typedef struct {
- char *command;
- int id;
- int defaultbind1;
- int defaultbind2;
- int bind1;
- int bind2;
-} bind_t;
-
-typedef struct
-{
- char* name;
- float defaultvalue;
- float value;
-} configcvar_t;
-
-
-static bind_t g_bindings[] =
-{
- {"+scores", K_TAB, -1, -1, -1},
- {"+button2", K_ENTER, -1, -1, -1},
- {"+speed", K_SHIFT, -1, -1, -1},
- {"+forward", K_UPARROW, -1, -1, -1},
- {"+back", K_DOWNARROW, -1, -1, -1},
- {"+moveleft", ',', -1, -1, -1},
- {"+moveright", '.', -1, -1, -1},
- {"+moveup", K_SPACE, -1, -1, -1},
- {"+movedown", 'c', -1, -1, -1},
- {"+left", K_LEFTARROW, -1, -1, -1},
- {"+right", K_RIGHTARROW, -1, -1, -1},
- {"+strafe", K_ALT, -1, -1, -1},
- {"+lookup", K_PGDN, -1, -1, -1},
- {"+lookdown", K_DEL, -1, -1, -1},
- {"+mlook", '/', -1, -1, -1},
- {"centerview", K_END, -1, -1, -1},
- {"+zoom", -1, -1, -1, -1},
- {"weapon 1", '1', -1, -1, -1},
- {"weapon 2", '2', -1, -1, -1},
- {"weapon 3", '3', -1, -1, -1},
- {"weapon 4", '4', -1, -1, -1},
- {"weapon 5", '5', -1, -1, -1},
- {"weapon 6", '6', -1, -1, -1},
- {"weapon 7", '7', -1, -1, -1},
- {"weapon 8", '8', -1, -1, -1},
- {"weapon 9", '9', -1, -1, -1},
- {"weapon 10", '0', -1, -1, -1},
- {"weapon 11", -1, -1, -1, -1},
- {"weapon 12", -1, -1, -1, -1},
- {"weapon 13", -1, -1, -1, -1},
- {"+attack", K_CTRL, -1, -1, -1},
- {"weapprev", '[', -1, -1, -1},
- {"weapnext", ']', -1, -1, -1},
- {"+button3", K_MOUSE3, -1, -1, -1},
- {"+button4", K_MOUSE4, -1, -1, -1},
- {"prevTeamMember", 'w', -1, -1, -1},
- {"nextTeamMember", 'r', -1, -1, -1},
- {"nextOrder", 't', -1, -1, -1},
- {"confirmOrder", 'y', -1, -1, -1},
- {"denyOrder", 'n', -1, -1, -1},
- {"taskOffense", 'o', -1, -1, -1},
- {"taskDefense", 'd', -1, -1, -1},
- {"taskPatrol", 'p', -1, -1, -1},
- {"taskCamp", 'c', -1, -1, -1},
- {"taskFollow", 'f', -1, -1, -1},
- {"taskRetrieve", 'v', -1, -1, -1},
- {"taskEscort", 'e', -1, -1, -1},
- {"taskOwnFlag", 'i', -1, -1, -1},
- {"taskSuicide", 'k', -1, -1, -1},
- {"tauntKillInsult", K_F1, -1, -1, -1},
- {"tauntPraise", K_F2, -1, -1, -1},
- {"tauntTaunt", K_F3, -1, -1, -1},
- {"tauntDeathInsult", K_F4, -1, -1, -1},
- {"tauntGauntlet", K_F5, -1, -1, -1},
- {"scoresUp", K_KP_PGUP, -1, -1, -1},
- {"scoresDown", K_KP_PGDN, -1, -1, -1},
- {"messagemode", -1, -1, -1, -1},
- {"messagemode2", -1, -1, -1, -1},
- {"messagemode3", -1, -1, -1, -1},
- {"messagemode4", -1, -1, -1, -1}
-};
-
-
-static const int g_bindCount = sizeof(g_bindings) / sizeof(bind_t);
-
-#ifndef MISSIONPACK
-static configcvar_t g_configcvars[] =
-{
- {"cl_run", 0, 0},
- {"m_pitch", 0, 0},
- {"cg_autoswitch", 0, 0},
- {"sensitivity", 0, 0},
- {"in_joystick", 0, 0},
- {"joy_threshold", 0, 0},
- {"m_filter", 0, 0},
- {"cl_freelook", 0, 0},
- {NULL, 0, 0}
-};
-#endif
-
-/*
-=================
-Controls_GetKeyAssignment
-=================
-*/
-static void Controls_GetKeyAssignment (char *command, int *twokeys)
-{
- int count;
- int j;
- char b[256];
-
- twokeys[0] = twokeys[1] = -1;
- count = 0;
-
- for ( j = 0; j < 256; j++ )
- {
- DC->getBindingBuf( j, b, 256 );
- if ( *b == 0 ) {
- continue;
- }
- if ( !Q_stricmp( b, command ) ) {
- twokeys[count] = j;
- count++;
- if (count == 2) {
- break;
- }
- }
- }
-}
-
-/*
-=================
-Controls_GetConfig
-=================
-*/
-void Controls_GetConfig( void )
-{
- int i;
- int twokeys[2];
-
- // iterate each command, get its numeric binding
- for (i=0; i < g_bindCount; i++)
- {
-
- Controls_GetKeyAssignment(g_bindings[i].command, twokeys);
-
- g_bindings[i].bind1 = twokeys[0];
- g_bindings[i].bind2 = twokeys[1];
- }
-
- //s_controls.invertmouse.curvalue = DC->getCVarValue( "m_pitch" ) < 0;
- //s_controls.smoothmouse.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "m_filter" ) );
- //s_controls.alwaysrun.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_run" ) );
- //s_controls.autoswitch.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_autoswitch" ) );
- //s_controls.sensitivity.curvalue = UI_ClampCvar( 2, 30, Controls_GetCvarValue( "sensitivity" ) );
- //s_controls.joyenable.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "in_joystick" ) );
- //s_controls.joythreshold.curvalue = UI_ClampCvar( 0.05, 0.75, Controls_GetCvarValue( "joy_threshold" ) );
- //s_controls.freelook.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_freelook" ) );
-}
-
-/*
-=================
-Controls_SetConfig
-=================
-*/
-void Controls_SetConfig(qboolean restart)
-{
- int i;
-
- // iterate each command, get its numeric binding
- for (i=0; i < g_bindCount; i++)
- {
-
- if (g_bindings[i].bind1 != -1)
- {
- DC->setBinding( g_bindings[i].bind1, g_bindings[i].command );
-
- if (g_bindings[i].bind2 != -1)
- DC->setBinding( g_bindings[i].bind2, g_bindings[i].command );
- }
- }
-
- //if ( s_controls.invertmouse.curvalue )
- // DC->setCVar("m_pitch", va("%f),-fabs( DC->getCVarValue( "m_pitch" ) ) );
- //else
- // trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
-
- //trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue );
- //trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue );
- //trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue );
- //trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue );
- //trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue );
- //trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue );
- //trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue );
- DC->executeText(EXEC_APPEND, "in_restart\n");
- //trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" );
-}
-
-/*
-=================
-Controls_SetDefaults
-=================
-*/
-void Controls_SetDefaults( void )
-{
- int i;
-
- // iterate each command, set its default binding
- for (i=0; i < g_bindCount; i++)
- {
- g_bindings[i].bind1 = g_bindings[i].defaultbind1;
- g_bindings[i].bind2 = g_bindings[i].defaultbind2;
- }
-
- //s_controls.invertmouse.curvalue = Controls_GetCvarDefault( "m_pitch" ) < 0;
- //s_controls.smoothmouse.curvalue = Controls_GetCvarDefault( "m_filter" );
- //s_controls.alwaysrun.curvalue = Controls_GetCvarDefault( "cl_run" );
- //s_controls.autoswitch.curvalue = Controls_GetCvarDefault( "cg_autoswitch" );
- //s_controls.sensitivity.curvalue = Controls_GetCvarDefault( "sensitivity" );
- //s_controls.joyenable.curvalue = Controls_GetCvarDefault( "in_joystick" );
- //s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" );
- //s_controls.freelook.curvalue = Controls_GetCvarDefault( "cl_freelook" );
-}
-
-int BindingIDFromName(const char *name) {
- int i;
- for (i=0; i < g_bindCount; i++)
- {
- if (Q_stricmp(name, g_bindings[i].command) == 0) {
- return i;
- }
- }
- return -1;
-}
-
-char g_nameBind1[32];
-char g_nameBind2[32];
-
-void BindingFromName(const char *cvar) {
- int i, b1, b2;
-
- // iterate each command, set its default binding
- for (i=0; i < g_bindCount; i++)
- {
- if (Q_stricmp(cvar, g_bindings[i].command) == 0) {
- b1 = g_bindings[i].bind1;
- if (b1 == -1) {
- break;
- }
- DC->keynumToStringBuf( b1, g_nameBind1, 32 );
- Q_strupr(g_nameBind1);
-
- b2 = g_bindings[i].bind2;
- if (b2 != -1)
- {
- DC->keynumToStringBuf( b2, g_nameBind2, 32 );
- Q_strupr(g_nameBind2);
- strcat( g_nameBind1, " or " );
- strcat( g_nameBind1, g_nameBind2 );
- }
- return;
- }
- }
- strcpy(g_nameBind1, "???");
-}
-
-void Item_Slider_Paint(itemDef_t *item) {
- vec4_t newColor, lowLight;
- float x, y, value;
- menuDef_t *parent = (menuDef_t*)item->parent;
-
- value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- y = item->window.rect.y;
- if (item->text) {
- Item_Text_Paint(item);
- x = item->textRect.x + item->textRect.w + 8;
- } else {
- x = item->window.rect.x;
- }
- DC->setColor(newColor);
- DC->drawHandlePic( x, y, SLIDER_WIDTH, SLIDER_HEIGHT, DC->Assets.sliderBar );
-
- x = Item_Slider_ThumbPosition(item);
- DC->drawHandlePic( x - (SLIDER_THUMB_WIDTH / 2), y - 2, SLIDER_THUMB_WIDTH, SLIDER_THUMB_HEIGHT, DC->Assets.sliderThumb );
-
-}
-
-void Item_Bind_Paint(itemDef_t *item) {
- vec4_t newColor, lowLight;
- float value;
- int maxChars = 0;
- menuDef_t *parent = (menuDef_t*)item->parent;
- editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
- if (editPtr) {
- maxChars = editPtr->maxPaintChars;
- }
-
- value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- if (g_bindItem == item) {
- lowLight[0] = 0.8f * 1.0f;
- lowLight[1] = 0.8f * 0.0f;
- lowLight[2] = 0.8f * 0.0f;
- lowLight[3] = 0.8f * 1.0f;
- } else {
- lowLight[0] = 0.8f * parent->focusColor[0];
- lowLight[1] = 0.8f * parent->focusColor[1];
- lowLight[2] = 0.8f * parent->focusColor[2];
- lowLight[3] = 0.8f * parent->focusColor[3];
- }
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- if (item->text) {
- Item_Text_Paint(item);
- BindingFromName(item->cvar);
- DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, g_nameBind1, 0, maxChars, item->textStyle);
- } else {
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "FIXME" : "FIXME", 0, maxChars, item->textStyle);
- }
-}
-
-qboolean Display_KeyBindPending(void) {
- return g_waitingForKey;
-}
-
-qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) {
- int id;
- int i;
-
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey)
- {
- if (down && (key == K_MOUSE1 || key == K_ENTER)) {
- g_waitingForKey = qtrue;
- g_bindItem = item;
- }
- return qtrue;
- }
- else
- {
- if (!g_waitingForKey || g_bindItem == NULL) {
- return qtrue;
- }
-
- if (key & K_CHAR_FLAG) {
- return qtrue;
- }
-
- switch (key)
- {
- case K_ESCAPE:
- g_waitingForKey = qfalse;
- return qtrue;
-
- case K_BACKSPACE:
- id = BindingIDFromName(item->cvar);
- if (id != -1) {
- g_bindings[id].bind1 = -1;
- g_bindings[id].bind2 = -1;
- }
- Controls_SetConfig(qtrue);
- g_waitingForKey = qfalse;
- g_bindItem = NULL;
- return qtrue;
-
- case '`':
- return qtrue;
- }
- }
-
- if (key != -1)
- {
-
- for (i=0; i < g_bindCount; i++)
- {
-
- if (g_bindings[i].bind2 == key) {
- g_bindings[i].bind2 = -1;
- }
-
- if (g_bindings[i].bind1 == key)
- {
- g_bindings[i].bind1 = g_bindings[i].bind2;
- g_bindings[i].bind2 = -1;
- }
- }
- }
-
-
- id = BindingIDFromName(item->cvar);
-
- if (id != -1) {
- if (key == -1) {
- if( g_bindings[id].bind1 != -1 ) {
- DC->setBinding( g_bindings[id].bind1, "" );
- g_bindings[id].bind1 = -1;
- }
- if( g_bindings[id].bind2 != -1 ) {
- DC->setBinding( g_bindings[id].bind2, "" );
- g_bindings[id].bind2 = -1;
- }
- }
- else if (g_bindings[id].bind1 == -1) {
- g_bindings[id].bind1 = key;
- }
- else if (g_bindings[id].bind1 != key && g_bindings[id].bind2 == -1) {
- g_bindings[id].bind2 = key;
- }
- else {
- DC->setBinding( g_bindings[id].bind1, "" );
- DC->setBinding( g_bindings[id].bind2, "" );
- g_bindings[id].bind1 = key;
- g_bindings[id].bind2 = -1;
- }
- }
-
- Controls_SetConfig(qtrue);
- g_waitingForKey = qfalse;
-
- return qtrue;
-}
-
-
-
-void AdjustFrom640(float *x, float *y, float *w, float *h) {
- //*x = *x * DC->scale + DC->bias;
- *x *= DC->xscale;
- *y *= DC->yscale;
- *w *= DC->xscale;
- *h *= DC->yscale;
-}
-
-void Item_Model_Paint(itemDef_t *item) {
- float x, y, w, h;
- refdef_t refdef;
- refEntity_t ent;
- vec3_t mins, maxs, origin;
- vec3_t angles;
- modelDef_t *modelPtr = (modelDef_t*)item->typeData;
-
- if (modelPtr == NULL) {
- return;
- }
-
- // setup the refdef
- memset( &refdef, 0, sizeof( refdef ) );
- refdef.rdflags = RDF_NOWORLDMODEL;
- AxisClear( refdef.viewaxis );
- x = item->window.rect.x+1;
- y = item->window.rect.y+1;
- w = item->window.rect.w-2;
- h = item->window.rect.h-2;
-
- AdjustFrom640( &x, &y, &w, &h );
-
- refdef.x = x;
- refdef.y = y;
- refdef.width = w;
- refdef.height = h;
-
- DC->modelBounds( item->asset, mins, maxs );
-
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
-
- // calculate distance so the model nearly fills the box
- if (qtrue) {
- float len = 0.5 * ( maxs[2] - mins[2] );
- origin[0] = len / 0.268; // len / tan( fov/2 )
- //origin[0] = len / tan(w/2);
- } else {
- origin[0] = item->textscale;
- }
- refdef.fov_x = (modelPtr->fov_x) ? modelPtr->fov_x : w;
- refdef.fov_y = (modelPtr->fov_y) ? modelPtr->fov_y : h;
-
- //refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
- //xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
- //refdef.fov_y = atan2( refdef.height, xx );
- //refdef.fov_y *= ( 360 / M_PI );
-
- DC->clearScene();
-
- refdef.time = DC->realTime;
-
- // add the model
-
- memset( &ent, 0, sizeof(ent) );
-
- //adjust = 5.0 * sin( (float)uis.realtime / 500 );
- //adjust = 360 % (int)((float)uis.realtime / 1000);
- //VectorSet( angles, 0, 0, 1 );
-
- // use item storage to track
- if (modelPtr->rotationSpeed) {
- if (DC->realTime > item->window.nextTime) {
- item->window.nextTime = DC->realTime + modelPtr->rotationSpeed;
- modelPtr->angle = (int)(modelPtr->angle + 1) % 360;
- }
- }
- VectorSet( angles, 0, modelPtr->angle, 0 );
- AnglesToAxis( angles, ent.axis );
-
- ent.hModel = item->asset;
- VectorCopy( origin, ent.origin );
- VectorCopy( origin, ent.lightingOrigin );
- ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
- VectorCopy( ent.origin, ent.oldorigin );
-
- DC->addRefEntityToScene( &ent );
- DC->renderScene( &refdef );
-
-}
-
-
-void Item_Image_Paint(itemDef_t *item) {
- if (item == NULL) {
- return;
- }
- DC->drawHandlePic(item->window.rect.x+1, item->window.rect.y+1, item->window.rect.w-2, item->window.rect.h-2, item->asset);
-}
-
-void Item_ListBox_Paint(itemDef_t *item) {
- float x, y, size, count, i, thumb;
- qhandle_t image;
- qhandle_t optionalImage;
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
-
- // the listbox is horizontal or vertical and has a fixed size scroll bar going either direction
- // elements are enumerated from the DC and either text or image handles are acquired from the DC as well
- // textscale is used to size the text, textalignx and textaligny are used to size image elements
- // there is no clipping available so only the last completely visible item is painted
- count = DC->feederCount(item->special);
- // default is vertical if horizontal flag is not here
- if (item->window.flags & WINDOW_HORIZONTAL) {
- // draw scrollbar in bottom of the window
- // bar
- x = item->window.rect.x + 1;
- y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE - 1;
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowLeft);
- x += SCROLLBAR_SIZE - 1;
- size = item->window.rect.w - (SCROLLBAR_SIZE * 2);
- DC->drawHandlePic(x, y, size+1, SCROLLBAR_SIZE, DC->Assets.scrollBar);
- x += size - 1;
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowRight);
- // thumb
- thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
- if (thumb > x - SCROLLBAR_SIZE - 1) {
- thumb = x - SCROLLBAR_SIZE - 1;
- }
- DC->drawHandlePic(thumb, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
- //
- listPtr->endPos = listPtr->startPos;
- size = item->window.rect.w - 2;
- // items
- // size contains max available space
- if (listPtr->elementStyle == LISTBOX_IMAGE) {
- // fit = 0;
- x = item->window.rect.x + 1;
- y = item->window.rect.y + 1;
- for (i = listPtr->startPos; i < count; i++) {
- // always draw at least one
- // which may overdraw the box if it is too small for the element
- image = DC->feederItemImage(item->special, i);
- if (image) {
- DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
- }
-
- if (i == item->cursorPos) {
- DC->drawRect(x, y, listPtr->elementWidth-1, listPtr->elementHeight-1, item->window.borderSize, item->window.borderColor);
- }
-
- size -= listPtr->elementWidth;
- if (size < listPtr->elementWidth) {
- listPtr->drawPadding = size; //listPtr->elementWidth - size;
- break;
- }
- x += listPtr->elementWidth;
- listPtr->endPos++;
- // fit++;
- }
- } else {
- //
- }
- } else {
- // draw scrollbar to right side of the window
- x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE - 1;
- y = item->window.rect.y + 1;
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowUp);
- y += SCROLLBAR_SIZE - 1;
-
- listPtr->endPos = listPtr->startPos;
- size = item->window.rect.h - (SCROLLBAR_SIZE * 2);
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, size+1, DC->Assets.scrollBar);
- y += size - 1;
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowDown);
- // thumb
- thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
- if (thumb > y - SCROLLBAR_SIZE - 1) {
- thumb = y - SCROLLBAR_SIZE - 1;
- }
- DC->drawHandlePic(x, thumb, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
-
- // adjust size for item painting
- size = item->window.rect.h - 2;
- if (listPtr->elementStyle == LISTBOX_IMAGE) {
- // fit = 0;
- x = item->window.rect.x + 1;
- y = item->window.rect.y + 1;
- for (i = listPtr->startPos; i < count; i++) {
- // always draw at least one
- // which may overdraw the box if it is too small for the element
- image = DC->feederItemImage(item->special, i);
- if (image) {
- DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
- }
-
- if (i == item->cursorPos) {
- DC->drawRect(x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, item->window.borderSize, item->window.borderColor);
- }
-
- listPtr->endPos++;
- size -= listPtr->elementWidth;
- if (size < listPtr->elementHeight) {
- listPtr->drawPadding = listPtr->elementHeight - size;
- break;
- }
- y += listPtr->elementHeight;
- // fit++;
- }
- } else {
- x = item->window.rect.x + 1;
- y = item->window.rect.y + 1;
- for (i = listPtr->startPos; i < count; i++) {
- const char *text;
- // always draw at least one
- // which may overdraw the box if it is too small for the element
-
- if (listPtr->numColumns > 0) {
- int j;
- for (j = 0; j < listPtr->numColumns; j++) {
- text = DC->feederItemText(item->special, i, j, &optionalImage);
- if (optionalImage >= 0) {
- DC->drawHandlePic(x + 4 + listPtr->columnInfo[j].pos, y - 1 + listPtr->elementHeight / 2, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
- } else if (text) {
- DC->drawText(x + 4 + listPtr->columnInfo[j].pos, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, listPtr->columnInfo[j].maxChars, item->textStyle);
- }
- }
- } else {
- text = DC->feederItemText(item->special, i, 0, &optionalImage);
- if (optionalImage >= 0) {
- //DC->drawHandlePic(x + 4 + listPtr->elementHeight, y, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
- } else if (text) {
- DC->drawText(x + 4, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, 0, item->textStyle);
- }
- }
-
- if (i == item->cursorPos) {
- DC->fillRect(x + 2, y + 2, item->window.rect.w - SCROLLBAR_SIZE - 4, listPtr->elementHeight, item->window.outlineColor);
- }
-
- size -= listPtr->elementHeight;
- if (size < listPtr->elementHeight) {
- listPtr->drawPadding = listPtr->elementHeight - size;
- break;
- }
- listPtr->endPos++;
- y += listPtr->elementHeight;
- // fit++;
- }
- }
- }
-}
-
-
-void Item_OwnerDraw_Paint(itemDef_t *item) {
- menuDef_t *parent;
-
- if (item == NULL) {
- return;
- }
- parent = (menuDef_t*)item->parent;
-
- if (DC->ownerDrawItem) {
- vec4_t color, lowLight;
- menuDef_t *parent = (menuDef_t*)item->parent;
- Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
- memcpy(&color, &item->window.foreColor, sizeof(color));
- if (item->numColors > 0 && DC->getValue) {
- // if the value is within one of the ranges then set color to that, otherwise leave at default
- int i;
- float f = DC->getValue(item->window.ownerDraw);
- for (i = 0; i < item->numColors; i++) {
- if (f >= item->colorRanges[i].low && f <= item->colorRanges[i].high) {
- memcpy(&color, &item->colorRanges[i].color, sizeof(color));
- break;
- }
- }
- }
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
- lowLight[0] = 0.8 * item->window.foreColor[0];
- lowLight[1] = 0.8 * item->window.foreColor[1];
- lowLight[2] = 0.8 * item->window.foreColor[2];
- lowLight[3] = 0.8 * item->window.foreColor[3];
- LerpColor(item->window.foreColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- }
-
- if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
- Com_Memcpy(color, parent->disableColor, sizeof(vec4_t));
- }
-
- if (item->text) {
- Item_Text_Paint(item);
- if (item->text[0]) {
- // +8 is an offset kludge to properly align owner draw items that have text combined with them
- DC->ownerDrawItem(item->textRect.x + item->textRect.w + 8, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
- } else {
- DC->ownerDrawItem(item->textRect.x + item->textRect.w, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
- }
- } else {
- DC->ownerDrawItem(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, item->textalignx, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
- }
- }
-}
-
-
-void Item_Paint(itemDef_t *item) {
- vec4_t red;
- menuDef_t *parent = (menuDef_t*)item->parent;
- red[0] = red[3] = 1;
- red[1] = red[2] = 0;
-
- if (item == NULL) {
- return;
- }
-
- if (item->window.flags & WINDOW_ORBITING) {
- if (DC->realTime > item->window.nextTime) {
- float rx, ry, a, c, s, w, h;
-
- item->window.nextTime = DC->realTime + item->window.offsetTime;
- // translate
- w = item->window.rectClient.w / 2;
- h = item->window.rectClient.h / 2;
- rx = item->window.rectClient.x + w - item->window.rectEffects.x;
- ry = item->window.rectClient.y + h - item->window.rectEffects.y;
- a = 3 * M_PI / 180;
- c = cos(a);
- s = sin(a);
- item->window.rectClient.x = (rx * c - ry * s) + item->window.rectEffects.x - w;
- item->window.rectClient.y = (rx * s + ry * c) + item->window.rectEffects.y - h;
- Item_UpdatePosition(item);
-
- }
- }
-
-
- if (item->window.flags & WINDOW_INTRANSITION) {
- if (DC->realTime > item->window.nextTime) {
- int done = 0;
- item->window.nextTime = DC->realTime + item->window.offsetTime;
- // transition the x,y
- if (item->window.rectClient.x == item->window.rectEffects.x) {
- done++;
- } else {
- if (item->window.rectClient.x < item->window.rectEffects.x) {
- item->window.rectClient.x += item->window.rectEffects2.x;
- if (item->window.rectClient.x > item->window.rectEffects.x) {
- item->window.rectClient.x = item->window.rectEffects.x;
- done++;
- }
- } else {
- item->window.rectClient.x -= item->window.rectEffects2.x;
- if (item->window.rectClient.x < item->window.rectEffects.x) {
- item->window.rectClient.x = item->window.rectEffects.x;
- done++;
- }
- }
- }
- if (item->window.rectClient.y == item->window.rectEffects.y) {
- done++;
- } else {
- if (item->window.rectClient.y < item->window.rectEffects.y) {
- item->window.rectClient.y += item->window.rectEffects2.y;
- if (item->window.rectClient.y > item->window.rectEffects.y) {
- item->window.rectClient.y = item->window.rectEffects.y;
- done++;
- }
- } else {
- item->window.rectClient.y -= item->window.rectEffects2.y;
- if (item->window.rectClient.y < item->window.rectEffects.y) {
- item->window.rectClient.y = item->window.rectEffects.y;
- done++;
- }
- }
- }
- if (item->window.rectClient.w == item->window.rectEffects.w) {
- done++;
- } else {
- if (item->window.rectClient.w < item->window.rectEffects.w) {
- item->window.rectClient.w += item->window.rectEffects2.w;
- if (item->window.rectClient.w > item->window.rectEffects.w) {
- item->window.rectClient.w = item->window.rectEffects.w;
- done++;
- }
- } else {
- item->window.rectClient.w -= item->window.rectEffects2.w;
- if (item->window.rectClient.w < item->window.rectEffects.w) {
- item->window.rectClient.w = item->window.rectEffects.w;
- done++;
- }
- }
- }
- if (item->window.rectClient.h == item->window.rectEffects.h) {
- done++;
- } else {
- if (item->window.rectClient.h < item->window.rectEffects.h) {
- item->window.rectClient.h += item->window.rectEffects2.h;
- if (item->window.rectClient.h > item->window.rectEffects.h) {
- item->window.rectClient.h = item->window.rectEffects.h;
- done++;
- }
- } else {
- item->window.rectClient.h -= item->window.rectEffects2.h;
- if (item->window.rectClient.h < item->window.rectEffects.h) {
- item->window.rectClient.h = item->window.rectEffects.h;
- done++;
- }
- }
- }
-
- Item_UpdatePosition(item);
-
- if (done == 4) {
- item->window.flags &= ~WINDOW_INTRANSITION;
- }
-
- }
- }
-
- if (item->window.ownerDrawFlags && DC->ownerDrawVisible) {
- if (!DC->ownerDrawVisible(item->window.ownerDrawFlags)) {
- item->window.flags &= ~WINDOW_VISIBLE;
- } else {
- item->window.flags |= WINDOW_VISIBLE;
- }
- }
-
- if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE)) {
- if (!Item_EnableShowViaCvar(item, CVAR_SHOW)) {
- return;
- }
- }
-
- if (item->window.flags & WINDOW_TIMEDVISIBLE) {
-
- }
-
- if (!(item->window.flags & WINDOW_VISIBLE)) {
- return;
- }
-
- // paint the rect first..
- Window_Paint(&item->window, parent->fadeAmount , parent->fadeClamp, parent->fadeCycle);
-
- if (debugMode) {
- vec4_t color;
- rectDef_t *r = Item_CorrectedTextRect(item);
- color[1] = color[3] = 1;
- color[0] = color[2] = 0;
- DC->drawRect(r->x, r->y, r->w, r->h, 1, color);
- }
-
- //DC->drawRect(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, 1, red);
-
- switch (item->type) {
- case ITEM_TYPE_OWNERDRAW:
- Item_OwnerDraw_Paint(item);
- break;
- case ITEM_TYPE_TEXT:
- case ITEM_TYPE_BUTTON:
- Item_Text_Paint(item);
- break;
- case ITEM_TYPE_RADIOBUTTON:
- break;
- case ITEM_TYPE_CHECKBOX:
- break;
- case ITEM_TYPE_EDITFIELD:
- case ITEM_TYPE_NUMERICFIELD:
- Item_TextField_Paint(item);
- break;
- case ITEM_TYPE_COMBO:
- break;
- case ITEM_TYPE_LISTBOX:
- Item_ListBox_Paint(item);
- break;
- //case ITEM_TYPE_IMAGE:
- // Item_Image_Paint(item);
- // break;
- case ITEM_TYPE_MODEL:
- Item_Model_Paint(item);
- break;
- case ITEM_TYPE_YESNO:
- Item_YesNo_Paint(item);
- break;
- case ITEM_TYPE_MULTI:
- Item_Multi_Paint(item);
- break;
- case ITEM_TYPE_BIND:
- Item_Bind_Paint(item);
- break;
- case ITEM_TYPE_SLIDER:
- Item_Slider_Paint(item);
- break;
- default:
- break;
- }
-
-}
-
-void Menu_Init(menuDef_t *menu) {
- memset(menu, 0, sizeof(menuDef_t));
- menu->cursorItem = -1;
- menu->fadeAmount = DC->Assets.fadeAmount;
- menu->fadeClamp = DC->Assets.fadeClamp;
- menu->fadeCycle = DC->Assets.fadeCycle;
- Window_Init(&menu->window);
-}
-
-itemDef_t *Menu_GetFocusedItem(menuDef_t *menu) {
- int i;
- if (menu) {
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
- return menu->items[i];
- }
- }
- }
- return NULL;
-}
-
-menuDef_t *Menu_GetFocused(void) {
- int i;
- for (i = 0; i < menuCount; i++) {
- if (Menus[i].window.flags & WINDOW_HASFOCUS && Menus[i].window.flags & WINDOW_VISIBLE) {
- return &Menus[i];
- }
- }
- return NULL;
-}
-
-void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down) {
- if (menu) {
- int i;
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->special == feeder) {
- Item_ListBox_HandleKey(menu->items[i], (down) ? K_DOWNARROW : K_UPARROW, qtrue, qtrue);
- return;
- }
- }
- }
-}
-
-
-
-void Menu_SetFeederSelection(menuDef_t *menu, int feeder, int index, const char *name) {
- if (menu == NULL) {
- if (name == NULL) {
- menu = Menu_GetFocused();
- } else {
- menu = Menus_FindByName(name);
- }
- }
-
- if (menu) {
- int i;
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->special == feeder) {
- if (index == 0) {
- listBoxDef_t *listPtr = (listBoxDef_t*)menu->items[i]->typeData;
- listPtr->cursorPos = 0;
- listPtr->startPos = 0;
- }
- menu->items[i]->cursorPos = index;
- DC->feederSelection(menu->items[i]->special, menu->items[i]->cursorPos);
- return;
- }
- }
- }
-}
-
-qboolean Menus_AnyFullScreenVisible(void) {
- int i;
- for (i = 0; i < menuCount; i++) {
- if (Menus[i].window.flags & WINDOW_VISIBLE && Menus[i].fullScreen) {
- return qtrue;
- }
- }
- return qfalse;
-}
-
-menuDef_t *Menus_ActivateByName(const char *p) {
- int i;
- menuDef_t *m = NULL;
- menuDef_t *focus = Menu_GetFocused();
- for (i = 0; i < menuCount; i++) {
- if (Q_stricmp(Menus[i].window.name, p) == 0) {
- m = &Menus[i];
- Menus_Activate(m);
- if (openMenuCount < MAX_OPEN_MENUS && focus != NULL) {
- menuStack[openMenuCount++] = focus;
- }
- } else {
- Menus[i].window.flags &= ~WINDOW_HASFOCUS;
- }
- }
- Display_CloseCinematics();
- return m;
-}
-
-
-void Item_Init(itemDef_t *item) {
- memset(item, 0, sizeof(itemDef_t));
- item->textscale = 0.55f;
- Window_Init(&item->window);
-}
-
-void Menu_HandleMouseMove(menuDef_t *menu, float x, float y) {
- int i, pass;
- qboolean focusSet = qfalse;
-
- itemDef_t *overItem;
- if (menu == NULL) {
- return;
- }
-
- if (!(menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
- return;
- }
-
- if (itemCapture) {
- //Item_MouseMove(itemCapture, x, y);
- return;
- }
-
- if (g_waitingForKey || g_editingField) {
- return;
- }
-
- // FIXME: this is the whole issue of focus vs. mouse over..
- // need a better overall solution as i don't like going through everything twice
- for (pass = 0; pass < 2; pass++) {
- for (i = 0; i < menu->itemCount; i++) {
- // turn off focus each item
- // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
-
- if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
- continue;
- }
-
- // items can be enabled and disabled based on cvars
- if (menu->items[i]->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_ENABLE)) {
- continue;
- }
-
- if (menu->items[i]->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_SHOW)) {
- continue;
- }
-
-
-
- if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
- if (pass == 1) {
- overItem = menu->items[i];
- if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
- if (!Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
- continue;
- }
- }
- // if we are over an item
- if (IsVisible(overItem->window.flags)) {
- // different one
- Item_MouseEnter(overItem, x, y);
- // Item_SetMouseOver(overItem, qtrue);
-
- // if item is not a decoration see if it can take focus
- if (!focusSet) {
- focusSet = Item_SetFocus(overItem, x, y);
- }
- }
- }
- } else if (menu->items[i]->window.flags & WINDOW_MOUSEOVER) {
- Item_MouseLeave(menu->items[i]);
- Item_SetMouseOver(menu->items[i], qfalse);
- }
- }
- }
-
-}
-
-void Menu_Paint(menuDef_t *menu, qboolean forcePaint) {
- int i;
-
- if (menu == NULL) {
- return;
- }
-
- if (!(menu->window.flags & WINDOW_VISIBLE) && !forcePaint) {
- return;
- }
-
- if (menu->window.ownerDrawFlags && DC->ownerDrawVisible && !DC->ownerDrawVisible(menu->window.ownerDrawFlags)) {
- return;
- }
-
- if (forcePaint) {
- menu->window.flags |= WINDOW_FORCED;
- }
-
- // draw the background if necessary
- if (menu->fullScreen) {
- // implies a background shader
- // FIXME: make sure we have a default shader if fullscreen is set with no background
- DC->drawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, menu->window.background );
- } else if (menu->window.background) {
- // this allows a background shader without being full screen
- //UI_DrawHandlePic(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, menu->backgroundShader);
- }
-
- // paint the background and or border
- Window_Paint(&menu->window, menu->fadeAmount, menu->fadeClamp, menu->fadeCycle );
-
- for (i = 0; i < menu->itemCount; i++) {
- Item_Paint(menu->items[i]);
- }
-
- if (debugMode) {
- vec4_t color;
- color[0] = color[2] = color[3] = 1;
- color[1] = 0;
- DC->drawRect(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, 1, color);
- }
-}
-
-/*
-===============
-Item_ValidateTypeData
-===============
-*/
-void Item_ValidateTypeData(itemDef_t *item) {
- if (item->typeData) {
- return;
- }
-
- if (item->type == ITEM_TYPE_LISTBOX) {
- item->typeData = UI_Alloc(sizeof(listBoxDef_t));
- memset(item->typeData, 0, sizeof(listBoxDef_t));
- } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD || item->type == ITEM_TYPE_YESNO || item->type == ITEM_TYPE_BIND || item->type == ITEM_TYPE_SLIDER || item->type == ITEM_TYPE_TEXT) {
- item->typeData = UI_Alloc(sizeof(editFieldDef_t));
- memset(item->typeData, 0, sizeof(editFieldDef_t));
- if (item->type == ITEM_TYPE_EDITFIELD) {
- if (!((editFieldDef_t *) item->typeData)->maxPaintChars) {
- ((editFieldDef_t *) item->typeData)->maxPaintChars = MAX_EDITFIELD;
- }
- }
- } else if (item->type == ITEM_TYPE_MULTI) {
- item->typeData = UI_Alloc(sizeof(multiDef_t));
- } else if (item->type == ITEM_TYPE_MODEL) {
- item->typeData = UI_Alloc(sizeof(modelDef_t));
- }
-}
-
-/*
-===============
-Keyword Hash
-===============
-*/
-
-#define KEYWORDHASH_SIZE 512
-
-typedef struct keywordHash_s
-{
- char *keyword;
- qboolean (*func)(itemDef_t *item, int handle);
- struct keywordHash_s *next;
-} keywordHash_t;
-
-int KeywordHash_Key(char *keyword) {
- int register hash, i;
-
- hash = 0;
- for (i = 0; keyword[i] != '\0'; i++) {
- if (keyword[i] >= 'A' && keyword[i] <= 'Z')
- hash += (keyword[i] + ('a' - 'A')) * (119 + i);
- else
- hash += keyword[i] * (119 + i);
- }
- hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (KEYWORDHASH_SIZE-1);
- return hash;
-}
-
-void KeywordHash_Add(keywordHash_t *table[], keywordHash_t *key) {
- int hash;
-
- hash = KeywordHash_Key(key->keyword);
-/*
- if (table[hash]) {
- int collision = qtrue;
- }
-*/
- key->next = table[hash];
- table[hash] = key;
-}
-
-keywordHash_t *KeywordHash_Find(keywordHash_t *table[], char *keyword)
-{
- keywordHash_t *key;
- int hash;
-
- hash = KeywordHash_Key(keyword);
- for (key = table[hash]; key; key = key->next) {
- if (!Q_stricmp(key->keyword, keyword))
- return key;
- }
- return NULL;
-}
-
-/*
-===============
-Item Keyword Parse functions
-===============
-*/
-
-// name <string>
-qboolean ItemParse_name( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->window.name)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// name <string>
-qboolean ItemParse_focusSound( itemDef_t *item, int handle ) {
- const char *temp;
- if (!PC_String_Parse(handle, &temp)) {
- return qfalse;
- }
- item->focusSound = DC->registerSound(temp, qfalse);
- return qtrue;
-}
-
-
-// text <string>
-qboolean ItemParse_text( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->text)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// group <string>
-qboolean ItemParse_group( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->window.group)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// asset_model <string>
-qboolean ItemParse_asset_model( itemDef_t *item, int handle ) {
- const char *temp;
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_String_Parse(handle, &temp)) {
- return qfalse;
- }
- item->asset = DC->registerModel(temp);
- modelPtr->angle = rand() % 360;
- return qtrue;
-}
-
-// asset_shader <string>
-qboolean ItemParse_asset_shader( itemDef_t *item, int handle ) {
- const char *temp;
-
- if (!PC_String_Parse(handle, &temp)) {
- return qfalse;
- }
- item->asset = DC->registerShaderNoMip(temp);
- return qtrue;
-}
-
-// model_origin <number> <number> <number>
-qboolean ItemParse_model_origin( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (PC_Float_Parse(handle, &modelPtr->origin[0])) {
- if (PC_Float_Parse(handle, &modelPtr->origin[1])) {
- if (PC_Float_Parse(handle, &modelPtr->origin[2])) {
- return qtrue;
- }
- }
- }
- return qfalse;
-}
-
-// model_fovx <number>
-qboolean ItemParse_model_fovx( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_Float_Parse(handle, &modelPtr->fov_x)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// model_fovy <number>
-qboolean ItemParse_model_fovy( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_Float_Parse(handle, &modelPtr->fov_y)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// model_rotation <integer>
-qboolean ItemParse_model_rotation( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_Int_Parse(handle, &modelPtr->rotationSpeed)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// model_angle <integer>
-qboolean ItemParse_model_angle( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_Int_Parse(handle, &modelPtr->angle)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// rect <rectangle>
-qboolean ItemParse_rect( itemDef_t *item, int handle ) {
- if (!PC_Rect_Parse(handle, &item->window.rectClient)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// style <integer>
-qboolean ItemParse_style( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->window.style)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// decoration
-qboolean ItemParse_decoration( itemDef_t *item, int handle ) {
- item->window.flags |= WINDOW_DECORATION;
- return qtrue;
-}
-
-// notselectable
-qboolean ItemParse_notselectable( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
- Item_ValidateTypeData(item);
- listPtr = (listBoxDef_t*)item->typeData;
- if (item->type == ITEM_TYPE_LISTBOX && listPtr) {
- listPtr->notselectable = qtrue;
- }
- return qtrue;
-}
-
-// manually wrapped
-qboolean ItemParse_wrapped( itemDef_t *item, int handle ) {
- item->window.flags |= WINDOW_WRAPPED;
- return qtrue;
-}
-
-// auto wrapped
-qboolean ItemParse_autowrapped( itemDef_t *item, int handle ) {
- item->window.flags |= WINDOW_AUTOWRAPPED;
- return qtrue;
-}
-
-
-// horizontalscroll
-qboolean ItemParse_horizontalscroll( itemDef_t *item, int handle ) {
- item->window.flags |= WINDOW_HORIZONTAL;
- return qtrue;
-}
-
-// type <integer>
-qboolean ItemParse_type( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->type)) {
- return qfalse;
- }
- Item_ValidateTypeData(item);
- return qtrue;
-}
-
-// elementwidth, used for listbox image elements
-// uses textalignx for storage
-qboolean ItemParse_elementwidth( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
-
- Item_ValidateTypeData(item);
- listPtr = (listBoxDef_t*)item->typeData;
- if (!PC_Float_Parse(handle, &listPtr->elementWidth)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// elementheight, used for listbox image elements
-// uses textaligny for storage
-qboolean ItemParse_elementheight( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
-
- Item_ValidateTypeData(item);
- listPtr = (listBoxDef_t*)item->typeData;
- if (!PC_Float_Parse(handle, &listPtr->elementHeight)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// feeder <float>
-qboolean ItemParse_feeder( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->special)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// elementtype, used to specify what type of elements a listbox contains
-// uses textstyle for storage
-qboolean ItemParse_elementtype( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- listPtr = (listBoxDef_t*)item->typeData;
- if (!PC_Int_Parse(handle, &listPtr->elementStyle)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// columns sets a number of columns and an x pos and width per..
-qboolean ItemParse_columns( itemDef_t *item, int handle ) {
- int num, i;
- listBoxDef_t *listPtr;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- listPtr = (listBoxDef_t*)item->typeData;
- if (PC_Int_Parse(handle, &num)) {
- if (num > MAX_LB_COLUMNS) {
- num = MAX_LB_COLUMNS;
- }
- listPtr->numColumns = num;
- for (i = 0; i < num; i++) {
- int pos, width, maxChars;
-
- if (PC_Int_Parse(handle, &pos) && PC_Int_Parse(handle, &width) && PC_Int_Parse(handle, &maxChars)) {
- listPtr->columnInfo[i].pos = pos;
- listPtr->columnInfo[i].width = width;
- listPtr->columnInfo[i].maxChars = maxChars;
- } else {
- return qfalse;
- }
- }
- } else {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_border( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->window.border)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_bordersize( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->window.borderSize)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_visible( itemDef_t *item, int handle ) {
- int i;
-
- if (!PC_Int_Parse(handle, &i)) {
- return qfalse;
- }
- if (i) {
- item->window.flags |= WINDOW_VISIBLE;
- }
- return qtrue;
-}
-
-qboolean ItemParse_ownerdraw( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->window.ownerDraw)) {
- return qfalse;
- }
- item->type = ITEM_TYPE_OWNERDRAW;
- return qtrue;
-}
-
-qboolean ItemParse_align( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->alignment)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_textalign( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->textalignment)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_textalignx( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->textalignx)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_textaligny( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->textaligny)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_textscale( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->textscale)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_textstyle( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->textStyle)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_backcolor( itemDef_t *item, int handle ) {
- int i;
- float f;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- item->window.backColor[i] = f;
- }
- return qtrue;
-}
-
-qboolean ItemParse_forecolor( itemDef_t *item, int handle ) {
- int i;
- float f;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- item->window.foreColor[i] = f;
- item->window.flags |= WINDOW_FORECOLORSET;
- }
- return qtrue;
-}
-
-qboolean ItemParse_bordercolor( itemDef_t *item, int handle ) {
- int i;
- float f;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- item->window.borderColor[i] = f;
- }
- return qtrue;
-}
-
-qboolean ItemParse_outlinecolor( itemDef_t *item, int handle ) {
- if (!PC_Color_Parse(handle, &item->window.outlineColor)){
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_background( itemDef_t *item, int handle ) {
- const char *temp;
-
- if (!PC_String_Parse(handle, &temp)) {
- return qfalse;
- }
- item->window.background = DC->registerShaderNoMip(temp);
- return qtrue;
-}
-
-qboolean ItemParse_cinematic( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->window.cinematicName)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_doubleClick( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
-
- Item_ValidateTypeData(item);
- if (!item->typeData) {
- return qfalse;
- }
-
- listPtr = (listBoxDef_t*)item->typeData;
-
- if (!PC_Script_Parse(handle, &listPtr->doubleClick)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_onFocus( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->onFocus)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_leaveFocus( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->leaveFocus)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_mouseEnter( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->mouseEnter)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_mouseExit( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->mouseExit)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_mouseEnterText( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->mouseEnterText)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_mouseExitText( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->mouseExitText)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_action( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->action)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_special( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->special)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_cvarTest( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->cvarTest)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_cvar( itemDef_t *item, int handle ) {
- editFieldDef_t *editPtr;
-
- Item_ValidateTypeData(item);
- if (!PC_String_Parse(handle, &item->cvar)) {
- return qfalse;
- }
- if (item->typeData) {
- editPtr = (editFieldDef_t*)item->typeData;
- editPtr->minVal = -1;
- editPtr->maxVal = -1;
- editPtr->defVal = -1;
- }
- return qtrue;
-}
-
-qboolean ItemParse_maxChars( itemDef_t *item, int handle ) {
- editFieldDef_t *editPtr;
- int maxChars;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
-
- if (!PC_Int_Parse(handle, &maxChars)) {
- return qfalse;
- }
- editPtr = (editFieldDef_t*)item->typeData;
- editPtr->maxChars = maxChars;
- return qtrue;
-}
-
-qboolean ItemParse_maxPaintChars( itemDef_t *item, int handle ) {
- editFieldDef_t *editPtr;
- int maxChars;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
-
- if (!PC_Int_Parse(handle, &maxChars)) {
- return qfalse;
- }
- editPtr = (editFieldDef_t*)item->typeData;
- editPtr->maxPaintChars = maxChars;
- return qtrue;
-}
-
-
-
-qboolean ItemParse_cvarFloat( itemDef_t *item, int handle ) {
- editFieldDef_t *editPtr;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- editPtr = (editFieldDef_t*)item->typeData;
- if (PC_String_Parse(handle, &item->cvar) &&
- PC_Float_Parse(handle, &editPtr->defVal) &&
- PC_Float_Parse(handle, &editPtr->minVal) &&
- PC_Float_Parse(handle, &editPtr->maxVal)) {
- return qtrue;
- }
- return qfalse;
-}
-
-qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) {
- pc_token_t token;
- multiDef_t *multiPtr;
- int pass;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- multiPtr = (multiDef_t*)item->typeData;
- multiPtr->count = 0;
- multiPtr->strDef = qtrue;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (*token.string != '{') {
- return qfalse;
- }
-
- pass = 0;
- while ( 1 ) {
- if (!trap_PC_ReadToken(handle, &token)) {
- PC_SourceError(handle, "end of file inside menu item\n");
- return qfalse;
- }
-
- if (*token.string == '}') {
- return qtrue;
- }
-
- if (*token.string == ',' || *token.string == ';') {
- continue;
- }
-
- if (pass == 0) {
- multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
- pass = 1;
- } else {
- multiPtr->cvarStr[multiPtr->count] = String_Alloc(token.string);
- pass = 0;
- multiPtr->count++;
- if (multiPtr->count >= MAX_MULTI_CVARS) {
- return qfalse;
- }
- }
-
- }
- return qfalse;
-}
-
-qboolean ItemParse_cvarFloatList( itemDef_t *item, int handle ) {
- pc_token_t token;
- multiDef_t *multiPtr;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- multiPtr = (multiDef_t*)item->typeData;
- multiPtr->count = 0;
- multiPtr->strDef = qfalse;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (*token.string != '{') {
- return qfalse;
- }
-
- while ( 1 ) {
- if (!trap_PC_ReadToken(handle, &token)) {
- PC_SourceError(handle, "end of file inside menu item\n");
- return qfalse;
- }
-
- if (*token.string == '}') {
- return qtrue;
- }
-
- if (*token.string == ',' || *token.string == ';') {
- continue;
- }
-
- multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
- if (!PC_Float_Parse(handle, &multiPtr->cvarValue[multiPtr->count])) {
- return qfalse;
- }
-
- multiPtr->count++;
- if (multiPtr->count >= MAX_MULTI_CVARS) {
- return qfalse;
- }
-
- }
- return qfalse;
-}
-
-
-
-qboolean ItemParse_addColorRange( itemDef_t *item, int handle ) {
- colorRangeDef_t color;
-
- if (PC_Float_Parse(handle, &color.low) &&
- PC_Float_Parse(handle, &color.high) &&
- PC_Color_Parse(handle, &color.color) ) {
- if (item->numColors < MAX_COLOR_RANGES) {
- memcpy(&item->colorRanges[item->numColors], &color, sizeof(color));
- item->numColors++;
- }
- return qtrue;
- }
- return qfalse;
-}
-
-qboolean ItemParse_ownerdrawFlag( itemDef_t *item, int handle ) {
- int i;
- if (!PC_Int_Parse(handle, &i)) {
- return qfalse;
- }
- item->window.ownerDrawFlags |= i;
- return qtrue;
-}
-
-qboolean ItemParse_enableCvar( itemDef_t *item, int handle ) {
- if (PC_Script_Parse(handle, &item->enableCvar)) {
- item->cvarFlags = CVAR_ENABLE;
- return qtrue;
- }
- return qfalse;
-}
-
-qboolean ItemParse_disableCvar( itemDef_t *item, int handle ) {
- if (PC_Script_Parse(handle, &item->enableCvar)) {
- item->cvarFlags = CVAR_DISABLE;
- return qtrue;
- }
- return qfalse;
-}
-
-qboolean ItemParse_showCvar( itemDef_t *item, int handle ) {
- if (PC_Script_Parse(handle, &item->enableCvar)) {
- item->cvarFlags = CVAR_SHOW;
- return qtrue;
- }
- return qfalse;
-}
-
-qboolean ItemParse_hideCvar( itemDef_t *item, int handle ) {
- if (PC_Script_Parse(handle, &item->enableCvar)) {
- item->cvarFlags = CVAR_HIDE;
- return qtrue;
- }
- return qfalse;
-}
-
-
-keywordHash_t itemParseKeywords[] = {
- {"name", ItemParse_name, NULL},
- {"text", ItemParse_text, NULL},
- {"group", ItemParse_group, NULL},
- {"asset_model", ItemParse_asset_model, NULL},
- {"asset_shader", ItemParse_asset_shader, NULL},
- {"model_origin", ItemParse_model_origin, NULL},
- {"model_fovx", ItemParse_model_fovx, NULL},
- {"model_fovy", ItemParse_model_fovy, NULL},
- {"model_rotation", ItemParse_model_rotation, NULL},
- {"model_angle", ItemParse_model_angle, NULL},
- {"rect", ItemParse_rect, NULL},
- {"style", ItemParse_style, NULL},
- {"decoration", ItemParse_decoration, NULL},
- {"notselectable", ItemParse_notselectable, NULL},
- {"wrapped", ItemParse_wrapped, NULL},
- {"autowrapped", ItemParse_autowrapped, NULL},
- {"horizontalscroll", ItemParse_horizontalscroll, NULL},
- {"type", ItemParse_type, NULL},
- {"elementwidth", ItemParse_elementwidth, NULL},
- {"elementheight", ItemParse_elementheight, NULL},
- {"feeder", ItemParse_feeder, NULL},
- {"elementtype", ItemParse_elementtype, NULL},
- {"columns", ItemParse_columns, NULL},
- {"border", ItemParse_border, NULL},
- {"bordersize", ItemParse_bordersize, NULL},
- {"visible", ItemParse_visible, NULL},
- {"ownerdraw", ItemParse_ownerdraw, NULL},
- {"align", ItemParse_align, NULL},
- {"textalign", ItemParse_textalign, NULL},
- {"textalignx", ItemParse_textalignx, NULL},
- {"textaligny", ItemParse_textaligny, NULL},
- {"textscale", ItemParse_textscale, NULL},
- {"textstyle", ItemParse_textstyle, NULL},
- {"backcolor", ItemParse_backcolor, NULL},
- {"forecolor", ItemParse_forecolor, NULL},
- {"bordercolor", ItemParse_bordercolor, NULL},
- {"outlinecolor", ItemParse_outlinecolor, NULL},
- {"background", ItemParse_background, NULL},
- {"onFocus", ItemParse_onFocus, NULL},
- {"leaveFocus", ItemParse_leaveFocus, NULL},
- {"mouseEnter", ItemParse_mouseEnter, NULL},
- {"mouseExit", ItemParse_mouseExit, NULL},
- {"mouseEnterText", ItemParse_mouseEnterText, NULL},
- {"mouseExitText", ItemParse_mouseExitText, NULL},
- {"action", ItemParse_action, NULL},
- {"special", ItemParse_special, NULL},
- {"cvar", ItemParse_cvar, NULL},
- {"maxChars", ItemParse_maxChars, NULL},
- {"maxPaintChars", ItemParse_maxPaintChars, NULL},
- {"focusSound", ItemParse_focusSound, NULL},
- {"cvarFloat", ItemParse_cvarFloat, NULL},
- {"cvarStrList", ItemParse_cvarStrList, NULL},
- {"cvarFloatList", ItemParse_cvarFloatList, NULL},
- {"addColorRange", ItemParse_addColorRange, NULL},
- {"ownerdrawFlag", ItemParse_ownerdrawFlag, NULL},
- {"enableCvar", ItemParse_enableCvar, NULL},
- {"cvarTest", ItemParse_cvarTest, NULL},
- {"disableCvar", ItemParse_disableCvar, NULL},
- {"showCvar", ItemParse_showCvar, NULL},
- {"hideCvar", ItemParse_hideCvar, NULL},
- {"cinematic", ItemParse_cinematic, NULL},
- {"doubleclick", ItemParse_doubleClick, NULL},
- {NULL, 0, NULL}
-};
-
-keywordHash_t *itemParseKeywordHash[KEYWORDHASH_SIZE];
-
-/*
-===============
-Item_SetupKeywordHash
-===============
-*/
-void Item_SetupKeywordHash(void) {
- int i;
-
- memset(itemParseKeywordHash, 0, sizeof(itemParseKeywordHash));
- for (i = 0; itemParseKeywords[i].keyword; i++) {
- KeywordHash_Add(itemParseKeywordHash, &itemParseKeywords[i]);
- }
-}
-
-/*
-===============
-Item_Parse
-===============
-*/
-qboolean Item_Parse(int handle, itemDef_t *item) {
- pc_token_t token;
- keywordHash_t *key;
-
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (*token.string != '{') {
- return qfalse;
- }
- while ( 1 ) {
- if (!trap_PC_ReadToken(handle, &token)) {
- PC_SourceError(handle, "end of file inside menu item\n");
- return qfalse;
- }
-
- if (*token.string == '}') {
- return qtrue;
- }
-
- key = KeywordHash_Find(itemParseKeywordHash, token.string);
- if (!key) {
- PC_SourceError(handle, "unknown menu item keyword %s", token.string);
- continue;
- }
- if ( !key->func(item, handle) ) {
- PC_SourceError(handle, "couldn't parse menu item keyword %s", token.string);
- return qfalse;
- }
- }
- return qfalse;
-}
-
-
-// Item_InitControls
-// init's special control types
-void Item_InitControls(itemDef_t *item) {
- if (item == NULL) {
- return;
- }
- if (item->type == ITEM_TYPE_LISTBOX) {
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
- item->cursorPos = 0;
- if (listPtr) {
- listPtr->cursorPos = 0;
- listPtr->startPos = 0;
- listPtr->endPos = 0;
- listPtr->cursorPos = 0;
- }
- }
-}
-
-/*
-===============
-Menu Keyword Parse functions
-===============
-*/
-
-qboolean MenuParse_font( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_String_Parse(handle, &menu->font)) {
- return qfalse;
- }
- if (!DC->Assets.fontRegistered) {
- DC->registerFont(menu->font, 48, &DC->Assets.textFont);
- DC->Assets.fontRegistered = qtrue;
- }
- return qtrue;
-}
-
-qboolean MenuParse_name( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_String_Parse(handle, &menu->window.name)) {
- return qfalse;
- }
- if (Q_stricmp(menu->window.name, "main") == 0) {
- // default main as having focus
- //menu->window.flags |= WINDOW_HASFOCUS;
- }
- return qtrue;
-}
-
-qboolean MenuParse_fullscreen( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- union
- {
- qboolean b;
- int i;
- } fullScreen;
-
- if (!PC_Int_Parse(handle, &fullScreen.i)) {
- return qfalse;
- }
- menu->fullScreen = fullScreen.b;
- return qtrue;
-}
-
-qboolean MenuParse_rect( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Rect_Parse(handle, &menu->window.rect)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_style( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Int_Parse(handle, &menu->window.style)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_visible( itemDef_t *item, int handle ) {
- int i;
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_Int_Parse(handle, &i)) {
- return qfalse;
- }
- if (i) {
- menu->window.flags |= WINDOW_VISIBLE;
- }
- return qtrue;
-}
-
-qboolean MenuParse_onOpen( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Script_Parse(handle, &menu->onOpen)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_onClose( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Script_Parse(handle, &menu->onClose)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_onESC( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Script_Parse(handle, &menu->onESC)) {
- return qfalse;
- }
- return qtrue;
-}
-
-
-
-qboolean MenuParse_border( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Int_Parse(handle, &menu->window.border)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_borderSize( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Float_Parse(handle, &menu->window.borderSize)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_backcolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- menu->window.backColor[i] = f;
- }
- return qtrue;
-}
-
-qboolean MenuParse_forecolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- menu->window.foreColor[i] = f;
- menu->window.flags |= WINDOW_FORECOLORSET;
- }
- return qtrue;
-}
-
-qboolean MenuParse_bordercolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- menu->window.borderColor[i] = f;
- }
- return qtrue;
-}
-
-qboolean MenuParse_focuscolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- menu->focusColor[i] = f;
- }
- return qtrue;
-}
-
-qboolean MenuParse_disablecolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- menu->disableColor[i] = f;
- }
- return qtrue;
-}
-
-
-qboolean MenuParse_outlinecolor( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Color_Parse(handle, &menu->window.outlineColor)){
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_background( itemDef_t *item, int handle ) {
- const char *buff;
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_String_Parse(handle, &buff)) {
- return qfalse;
- }
- menu->window.background = DC->registerShaderNoMip(buff);
- return qtrue;
-}
-
-qboolean MenuParse_cinematic( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_String_Parse(handle, &menu->window.cinematicName)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_ownerdrawFlag( itemDef_t *item, int handle ) {
- int i;
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_Int_Parse(handle, &i)) {
- return qfalse;
- }
- menu->window.ownerDrawFlags |= i;
- return qtrue;
-}
-
-qboolean MenuParse_ownerdraw( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_Int_Parse(handle, &menu->window.ownerDraw)) {
- return qfalse;
- }
- return qtrue;
-}
-
-
-// decoration
-qboolean MenuParse_popup( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- menu->window.flags |= WINDOW_POPUP;
- return qtrue;
-}
-
-
-qboolean MenuParse_outOfBounds( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- menu->window.flags |= WINDOW_OOB_CLICK;
- return qtrue;
-}
-
-qboolean MenuParse_soundLoop( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_String_Parse(handle, &menu->soundName)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_fadeClamp( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_Float_Parse(handle, &menu->fadeClamp)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_fadeAmount( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_Float_Parse(handle, &menu->fadeAmount)) {
- return qfalse;
- }
- return qtrue;
-}
-
-
-qboolean MenuParse_fadeCycle( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_Int_Parse(handle, &menu->fadeCycle)) {
- return qfalse;
- }
- return qtrue;
-}
-
-
-qboolean MenuParse_itemDef( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (menu->itemCount < MAX_MENUITEMS) {
- menu->items[menu->itemCount] = UI_Alloc(sizeof(itemDef_t));
- Item_Init(menu->items[menu->itemCount]);
- if (!Item_Parse(handle, menu->items[menu->itemCount])) {
- return qfalse;
- }
- Item_InitControls(menu->items[menu->itemCount]);
- menu->items[menu->itemCount++]->parent = menu;
- }
- return qtrue;
-}
-
-keywordHash_t menuParseKeywords[] = {
- {"font", MenuParse_font, NULL},
- {"name", MenuParse_name, NULL},
- {"fullscreen", MenuParse_fullscreen, NULL},
- {"rect", MenuParse_rect, NULL},
- {"style", MenuParse_style, NULL},
- {"visible", MenuParse_visible, NULL},
- {"onOpen", MenuParse_onOpen, NULL},
- {"onClose", MenuParse_onClose, NULL},
- {"onESC", MenuParse_onESC, NULL},
- {"border", MenuParse_border, NULL},
- {"borderSize", MenuParse_borderSize, NULL},
- {"backcolor", MenuParse_backcolor, NULL},
- {"forecolor", MenuParse_forecolor, NULL},
- {"bordercolor", MenuParse_bordercolor, NULL},
- {"focuscolor", MenuParse_focuscolor, NULL},
- {"disablecolor", MenuParse_disablecolor, NULL},
- {"outlinecolor", MenuParse_outlinecolor, NULL},
- {"background", MenuParse_background, NULL},
- {"ownerdraw", MenuParse_ownerdraw, NULL},
- {"ownerdrawFlag", MenuParse_ownerdrawFlag, NULL},
- {"outOfBoundsClick", MenuParse_outOfBounds, NULL},
- {"soundLoop", MenuParse_soundLoop, NULL},
- {"itemDef", MenuParse_itemDef, NULL},
- {"cinematic", MenuParse_cinematic, NULL},
- {"popup", MenuParse_popup, NULL},
- {"fadeClamp", MenuParse_fadeClamp, NULL},
- {"fadeCycle", MenuParse_fadeCycle, NULL},
- {"fadeAmount", MenuParse_fadeAmount, NULL},
- {NULL, 0, NULL}
-};
-
-keywordHash_t *menuParseKeywordHash[KEYWORDHASH_SIZE];
-
-/*
-===============
-Menu_SetupKeywordHash
-===============
-*/
-void Menu_SetupKeywordHash(void) {
- int i;
-
- memset(menuParseKeywordHash, 0, sizeof(menuParseKeywordHash));
- for (i = 0; menuParseKeywords[i].keyword; i++) {
- KeywordHash_Add(menuParseKeywordHash, &menuParseKeywords[i]);
- }
-}
-
-/*
-===============
-Menu_Parse
-===============
-*/
-qboolean Menu_Parse(int handle, menuDef_t *menu) {
- pc_token_t token;
- keywordHash_t *key;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (*token.string != '{') {
- return qfalse;
- }
-
- while ( 1 ) {
-
- memset(&token, 0, sizeof(pc_token_t));
- if (!trap_PC_ReadToken(handle, &token)) {
- PC_SourceError(handle, "end of file inside menu\n");
- return qfalse;
- }
-
- if (*token.string == '}') {
- return qtrue;
- }
-
- key = KeywordHash_Find(menuParseKeywordHash, token.string);
- if (!key) {
- PC_SourceError(handle, "unknown menu keyword %s", token.string);
- continue;
- }
- if ( !key->func((itemDef_t*)menu, handle) ) {
- PC_SourceError(handle, "couldn't parse menu keyword %s", token.string);
- return qfalse;
- }
- }
- return qfalse;
-}
-
-/*
-===============
-Menu_New
-===============
-*/
-void Menu_New(int handle) {
- menuDef_t *menu = &Menus[menuCount];
-
- if (menuCount < MAX_MENUS) {
- Menu_Init(menu);
- if (Menu_Parse(handle, menu)) {
- Menu_PostParse(menu);
- menuCount++;
- }
- }
-}
-
-int Menu_Count(void) {
- return menuCount;
-}
-
-void Menu_PaintAll(void) {
- int i;
- if (captureFunc) {
- captureFunc(captureData);
- }
-
- for (i = 0; i < Menu_Count(); i++) {
- Menu_Paint(&Menus[i], qfalse);
- }
-
- if (debugMode) {
- vec4_t v = {1, 1, 1, 1};
- DC->drawText(5, 25, .5, v, va("fps: %f", DC->FPS), 0, 0, 0);
- }
-}
-
-void Menu_Reset(void) {
- menuCount = 0;
-}
-
-displayContextDef_t *Display_GetContext(void) {
- return DC;
-}
-
-#ifndef MISSIONPACK
-static float captureX;
-static float captureY;
-#endif
-
-void *Display_CaptureItem(int x, int y) {
- int i;
-
- for (i = 0; i < menuCount; i++) {
- // turn off focus each item
- // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
- if (Rect_ContainsPoint(&Menus[i].window.rect, x, y)) {
- return &Menus[i];
- }
- }
- return NULL;
-}
-
-
-// FIXME:
-qboolean Display_MouseMove(void *p, int x, int y) {
- int i;
- menuDef_t *menu = p;
-
- if (menu == NULL) {
- menu = Menu_GetFocused();
- if (menu) {
- if (menu->window.flags & WINDOW_POPUP) {
- Menu_HandleMouseMove(menu, x, y);
- return qtrue;
- }
- }
- for (i = 0; i < menuCount; i++) {
- Menu_HandleMouseMove(&Menus[i], x, y);
- }
- } else {
- menu->window.rect.x += x;
- menu->window.rect.y += y;
- Menu_UpdatePosition(menu);
- }
- return qtrue;
-
-}
-
-int Display_CursorType(int x, int y) {
- int i;
- for (i = 0; i < menuCount; i++) {
- rectDef_t r2;
- r2.x = Menus[i].window.rect.x - 3;
- r2.y = Menus[i].window.rect.y - 3;
- r2.w = r2.h = 7;
- if (Rect_ContainsPoint(&r2, x, y)) {
- return CURSOR_SIZER;
- }
- }
- return CURSOR_ARROW;
-}
-
-
-void Display_HandleKey(int key, qboolean down, int x, int y) {
- menuDef_t *menu = Display_CaptureItem(x, y);
- if (menu == NULL) {
- menu = Menu_GetFocused();
- }
- if (menu) {
- Menu_HandleKey(menu, key, down );
- }
-}
-
-static void Window_CacheContents(windowDef_t *window) {
- if (window) {
- if (window->cinematicName) {
- int cin = DC->playCinematic(window->cinematicName, 0, 0, 0, 0);
- DC->stopCinematic(cin);
- }
- }
-}
-
-
-static void Item_CacheContents(itemDef_t *item) {
- if (item) {
- Window_CacheContents(&item->window);
- }
-
-}
-
-static void Menu_CacheContents(menuDef_t *menu) {
- if (menu) {
- int i;
- Window_CacheContents(&menu->window);
- for (i = 0; i < menu->itemCount; i++) {
- Item_CacheContents(menu->items[i]);
- }
-
- if (menu->soundName && *menu->soundName) {
- DC->registerSound(menu->soundName, qfalse);
- }
- }
-
-}
-
-void Display_CacheAll(void) {
- int i;
- for (i = 0; i < menuCount; i++) {
- Menu_CacheContents(&Menus[i]);
- }
-}
-
-
-static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y) {
- if (menu && menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED)) {
- if (Rect_ContainsPoint(&menu->window.rect, x, y)) {
- int i;
- for (i = 0; i < menu->itemCount; i++) {
- // turn off focus each item
- // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
-
- if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
- continue;
- }
-
- if (menu->items[i]->window.flags & WINDOW_DECORATION) {
- continue;
- }
-
- if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
- itemDef_t *overItem = menu->items[i];
- if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
- if (Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
- return qtrue;
- } else {
- continue;
- }
- } else {
- return qtrue;
- }
- }
- }
-
- }
- }
- return qfalse;
-}
-
diff --git a/engine/code/ui/ui_shared.h b/engine/code/ui/ui_shared.h
deleted file mode 100644
index 5ab438b..0000000
--- a/engine/code/ui/ui_shared.h
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#ifndef __UI_SHARED_H
-#define __UI_SHARED_H
-
-
-#include "../qcommon/q_shared.h"
-#include "../renderer/tr_types.h"
-#include "../client/keycodes.h"
-
-#include "../../ui/menudef.h"
-
-#define MAX_MENUNAME 32
-#define MAX_ITEMTEXT 64
-#define MAX_ITEMACTION 64
-#define MAX_MENUDEFFILE 4096
-#define MAX_MENUFILE 32768
-#define MAX_MENUS 64
-#define MAX_MENUITEMS 96
-#define MAX_COLOR_RANGES 10
-#define MAX_OPEN_MENUS 16
-
-#define WINDOW_MOUSEOVER 0x00000001 // mouse is over it, non exclusive
-#define WINDOW_HASFOCUS 0x00000002 // has cursor focus, exclusive
-#define WINDOW_VISIBLE 0x00000004 // is visible
-#define WINDOW_GREY 0x00000008 // is visible but grey ( non-active )
-#define WINDOW_DECORATION 0x00000010 // for decoration only, no mouse, keyboard, etc..
-#define WINDOW_FADINGOUT 0x00000020 // fading out, non-active
-#define WINDOW_FADINGIN 0x00000040 // fading in
-#define WINDOW_MOUSEOVERTEXT 0x00000080 // mouse is over it, non exclusive
-#define WINDOW_INTRANSITION 0x00000100 // window is in transition
-#define WINDOW_FORECOLORSET 0x00000200 // forecolor was explicitly set ( used to color alpha images or not )
-#define WINDOW_HORIZONTAL 0x00000400 // for list boxes and sliders, vertical is default this is set of horizontal
-#define WINDOW_LB_LEFTARROW 0x00000800 // mouse is over left/up arrow
-#define WINDOW_LB_RIGHTARROW 0x00001000 // mouse is over right/down arrow
-#define WINDOW_LB_THUMB 0x00002000 // mouse is over thumb
-#define WINDOW_LB_PGUP 0x00004000 // mouse is over page up
-#define WINDOW_LB_PGDN 0x00008000 // mouse is over page down
-#define WINDOW_ORBITING 0x00010000 // item is in orbit
-#define WINDOW_OOB_CLICK 0x00020000 // close on out of bounds click
-#define WINDOW_WRAPPED 0x00040000 // manually wrap text
-#define WINDOW_AUTOWRAPPED 0x00080000 // auto wrap text
-#define WINDOW_FORCED 0x00100000 // forced open
-#define WINDOW_POPUP 0x00200000 // popup
-#define WINDOW_BACKCOLORSET 0x00400000 // backcolor was explicitly set
-#define WINDOW_TIMEDVISIBLE 0x00800000 // visibility timing ( NOT implemented )
-
-
-// CGAME cursor type bits
-#define CURSOR_NONE 0x00000001
-#define CURSOR_ARROW 0x00000002
-#define CURSOR_SIZER 0x00000004
-
-#ifdef CGAME
-#define STRING_POOL_SIZE 128*1024
-#else
-#define STRING_POOL_SIZE 384*1024
-#endif
-#define MAX_STRING_HANDLES 4096
-
-#define MAX_SCRIPT_ARGS 12
-#define MAX_EDITFIELD 256
-
-#define ART_FX_BASE "menu/art/fx_base"
-#define ART_FX_BLUE "menu/art/fx_blue"
-#define ART_FX_CYAN "menu/art/fx_cyan"
-#define ART_FX_GREEN "menu/art/fx_grn"
-#define ART_FX_RED "menu/art/fx_red"
-#define ART_FX_TEAL "menu/art/fx_teal"
-#define ART_FX_WHITE "menu/art/fx_white"
-#define ART_FX_YELLOW "menu/art/fx_yel"
-
-#define ASSET_GRADIENTBAR "ui/assets/gradientbar2.tga"
-#define ASSET_SCROLLBAR "ui/assets/scrollbar.tga"
-#define ASSET_SCROLLBAR_ARROWDOWN "ui/assets/scrollbar_arrow_dwn_a.tga"
-#define ASSET_SCROLLBAR_ARROWUP "ui/assets/scrollbar_arrow_up_a.tga"
-#define ASSET_SCROLLBAR_ARROWLEFT "ui/assets/scrollbar_arrow_left.tga"
-#define ASSET_SCROLLBAR_ARROWRIGHT "ui/assets/scrollbar_arrow_right.tga"
-#define ASSET_SCROLL_THUMB "ui/assets/scrollbar_thumb.tga"
-#define ASSET_SLIDER_BAR "ui/assets/slider2.tga"
-#define ASSET_SLIDER_THUMB "ui/assets/sliderbutt_1.tga"
-#define SCROLLBAR_SIZE 16.0
-#define SLIDER_WIDTH 96.0
-#define SLIDER_HEIGHT 16.0
-#define SLIDER_THUMB_WIDTH 12.0
-#define SLIDER_THUMB_HEIGHT 20.0
-#define NUM_CROSSHAIRS 10
-
-typedef struct {
- const char *command;
- const char *args[MAX_SCRIPT_ARGS];
-} scriptDef_t;
-
-
-typedef struct {
- float x; // horiz position
- float y; // vert position
- float w; // width
- float h; // height;
-} rectDef_t;
-
-typedef rectDef_t Rectangle;
-
-// FIXME: do something to separate text vs window stuff
-typedef struct {
- Rectangle rect; // client coord rectangle
- Rectangle rectClient; // screen coord rectangle
- const char *name; //
- const char *group; // if it belongs to a group
- const char *cinematicName; // cinematic name
- int cinematic; // cinematic handle
- int style; //
- int border; //
- int ownerDraw; // ownerDraw style
- int ownerDrawFlags; // show flags for ownerdraw items
- float borderSize; //
- int flags; // visible, focus, mouseover, cursor
- Rectangle rectEffects; // for various effects
- Rectangle rectEffects2; // for various effects
- int offsetTime; // time based value for various effects
- int nextTime; // time next effect should cycle
- vec4_t foreColor; // text color
- vec4_t backColor; // border color
- vec4_t borderColor; // border color
- vec4_t outlineColor; // border color
- qhandle_t background; // background asset
-} windowDef_t;
-
-typedef windowDef_t Window;
-
-typedef struct {
- vec4_t color;
- float low;
- float high;
-} colorRangeDef_t;
-
-// FIXME: combine flags into bitfields to save space
-// FIXME: consolidate all of the common stuff in one structure for menus and items
-// THINKABOUTME: is there any compelling reason not to have items contain items
-// and do away with a menu per say.. major issue is not being able to dynamically allocate
-// and destroy stuff.. Another point to consider is adding an alloc free call for vm's and have
-// the engine just allocate the pool for it based on a cvar
-// many of the vars are re-used for different item types, as such they are not always named appropriately
-// the benefits of c++ in DOOM will greatly help crap like this
-// FIXME: need to put a type ptr that points to specific type info per type
-//
-#define MAX_LB_COLUMNS 16
-
-typedef struct columnInfo_s {
- int pos;
- int width;
- int maxChars;
-} columnInfo_t;
-
-typedef struct listBoxDef_s {
- int startPos;
- int endPos;
- int drawPadding;
- int cursorPos;
- float elementWidth;
- float elementHeight;
- int elementStyle;
- int numColumns;
- columnInfo_t columnInfo[MAX_LB_COLUMNS];
- const char *doubleClick;
- qboolean notselectable;
-} listBoxDef_t;
-
-typedef struct editFieldDef_s {
- float minVal; // edit field limits
- float maxVal; //
- float defVal; //
- float range; //
- int maxChars; // for edit fields
- int maxPaintChars; // for edit fields
- int paintOffset; //
-} editFieldDef_t;
-
-#define MAX_MULTI_CVARS 32
-
-typedef struct multiDef_s {
- const char *cvarList[MAX_MULTI_CVARS];
- const char *cvarStr[MAX_MULTI_CVARS];
- float cvarValue[MAX_MULTI_CVARS];
- int count;
- qboolean strDef;
-} multiDef_t;
-
-typedef struct modelDef_s {
- int angle;
- vec3_t origin;
- float fov_x;
- float fov_y;
- int rotationSpeed;
-} modelDef_t;
-
-#define CVAR_ENABLE 0x00000001
-#define CVAR_DISABLE 0x00000002
-#define CVAR_SHOW 0x00000004
-#define CVAR_HIDE 0x00000008
-
-typedef struct itemDef_s {
- Window window; // common positional, border, style, layout info
- Rectangle textRect; // rectangle the text ( if any ) consumes
- int type; // text, button, radiobutton, checkbox, textfield, listbox, combo
- int alignment; // left center right
- int textalignment; // ( optional ) alignment for text within rect based on text width
- float textalignx; // ( optional ) text alignment x coord
- float textaligny; // ( optional ) text alignment x coord
- float textscale; // scale percentage from 72pts
- int textStyle; // ( optional ) style, normal and shadowed are it for now
- const char *text; // display text
- void *parent; // menu owner
- qhandle_t asset; // handle to asset
- const char *mouseEnterText; // mouse enter script
- const char *mouseExitText; // mouse exit script
- const char *mouseEnter; // mouse enter script
- const char *mouseExit; // mouse exit script
- const char *action; // select script
- const char *onFocus; // select script
- const char *leaveFocus; // select script
- const char *cvar; // associated cvar
- const char *cvarTest; // associated cvar for enable actions
- const char *enableCvar; // enable, disable, show, or hide based on value, this can contain a list
- int cvarFlags; // what type of action to take on cvarenables
- sfxHandle_t focusSound;
- int numColors; // number of color ranges
- colorRangeDef_t colorRanges[MAX_COLOR_RANGES];
- float special; // used for feeder id's etc.. diff per type
- int cursorPos; // cursor position in characters
- void *typeData; // type specific data ptr's
-} itemDef_t;
-
-typedef struct {
- Window window;
- const char *font; // font
- qboolean fullScreen; // covers entire screen
- int itemCount; // number of items;
- int fontIndex; //
- int cursorItem; // which item as the cursor
- int fadeCycle; //
- float fadeClamp; //
- float fadeAmount; //
- const char *onOpen; // run when the menu is first opened
- const char *onClose; // run when the menu is closed
- const char *onESC; // run when the menu is closed
- const char *soundName; // background loop sound for menu
-
- vec4_t focusColor; // focus color for items
- vec4_t disableColor; // focus color for items
- itemDef_t *items[MAX_MENUITEMS]; // items this menu contains
-} menuDef_t;
-
-typedef struct {
- const char *fontStr;
- const char *cursorStr;
- const char *gradientStr;
- fontInfo_t textFont;
- fontInfo_t smallFont;
- fontInfo_t bigFont;
- qhandle_t cursor;
- qhandle_t gradientBar;
- qhandle_t scrollBarArrowUp;
- qhandle_t scrollBarArrowDown;
- qhandle_t scrollBarArrowLeft;
- qhandle_t scrollBarArrowRight;
- qhandle_t scrollBar;
- qhandle_t scrollBarThumb;
- qhandle_t buttonMiddle;
- qhandle_t buttonInside;
- qhandle_t solidBox;
- qhandle_t sliderBar;
- qhandle_t sliderThumb;
- sfxHandle_t menuEnterSound;
- sfxHandle_t menuExitSound;
- sfxHandle_t menuBuzzSound;
- sfxHandle_t itemFocusSound;
- float fadeClamp;
- int fadeCycle;
- float fadeAmount;
- float shadowX;
- float shadowY;
- vec4_t shadowColor;
- float shadowFadeClamp;
- qboolean fontRegistered;
-
- // player settings
- qhandle_t fxBasePic;
- qhandle_t fxPic[7];
- qhandle_t crosshairShader[NUM_CROSSHAIRS];
-
-} cachedAssets_t;
-
-typedef struct {
- const char *name;
- void (*handler) (itemDef_t *item, char** args);
-} commandDef_t;
-
-typedef struct {
- qhandle_t (*registerShaderNoMip) (const char *p);
- void (*setColor) (const vec4_t v);
- void (*drawHandlePic) (float x, float y, float w, float h, qhandle_t asset);
- void (*drawStretchPic) (float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
- void (*drawText) (float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style );
- int (*textWidth) (const char *text, float scale, int limit);
- int (*textHeight) (const char *text, float scale, int limit);
- qhandle_t (*registerModel) (const char *p);
- void (*modelBounds) (qhandle_t model, vec3_t min, vec3_t max);
- void (*fillRect) ( float x, float y, float w, float h, const vec4_t color);
- void (*drawRect) ( float x, float y, float w, float h, float size, const vec4_t color);
- void (*drawSides) (float x, float y, float w, float h, float size);
- void (*drawTopBottom) (float x, float y, float w, float h, float size);
- void (*clearScene) ( void );
- void (*addRefEntityToScene) (const refEntity_t *re );
- void (*renderScene) ( const refdef_t *fd );
- void (*registerFont) (const char *pFontname, int pointSize, fontInfo_t *font);
- void (*ownerDrawItem) (float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle);
- float (*getValue) (int ownerDraw);
- qboolean (*ownerDrawVisible) (int flags);
- void (*runScript)(char **p);
- void (*getTeamColor)(vec4_t *color);
- void (*getCVarString)(const char *cvar, char *buffer, int bufsize);
- float (*getCVarValue)(const char *cvar);
- void (*setCVar)(const char *cvar, const char *value);
- void (*drawTextWithCursor)(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style);
- void (*setOverstrikeMode)(qboolean b);
- qboolean (*getOverstrikeMode)( void );
- void (*startLocalSound)( sfxHandle_t sfx, int channelNum );
- qboolean (*ownerDrawHandleKey)(int ownerDraw, int flags, float *special, int key);
- int (*feederCount)(float feederID);
- const char *(*feederItemText)(float feederID, int index, int column, qhandle_t *handle);
- qhandle_t (*feederItemImage)(float feederID, int index);
- void (*feederSelection)(float feederID, int index);
- void (*keynumToStringBuf)( int keynum, char *buf, int buflen );
- void (*getBindingBuf)( int keynum, char *buf, int buflen );
- void (*setBinding)( int keynum, const char *binding );
- void (*executeText)(int exec_when, const char *text );
- void (*Error)(int level, const char *error, ...);
- void (*Print)(const char *msg, ...);
- void (*Pause)(qboolean b);
- int (*ownerDrawWidth)(int ownerDraw, float scale);
- sfxHandle_t (*registerSound)(const char *name, qboolean compressed);
- void (*startBackgroundTrack)( const char *intro, const char *loop);
- void (*stopBackgroundTrack)( void );
- int (*playCinematic)(const char *name, float x, float y, float w, float h);
- void (*stopCinematic)(int handle);
- void (*drawCinematic)(int handle, float x, float y, float w, float h);
- void (*runCinematicFrame)(int handle);
-
- float yscale;
- float xscale;
- float bias;
- int realTime;
- int frameTime;
- int cursorx;
- int cursory;
- qboolean debug;
-
- cachedAssets_t Assets;
-
- glconfig_t glconfig;
- qhandle_t whiteShader;
- qhandle_t gradientImage;
- qhandle_t cursor;
- float FPS;
-
-} displayContextDef_t;
-
-const char *String_Alloc(const char *p);
-void String_Init( void );
-void String_Report( void );
-void Init_Display(displayContextDef_t *dc);
-void Display_ExpandMacros(char * buff);
-void Menu_Init(menuDef_t *menu);
-void Item_Init(itemDef_t *item);
-void Menu_PostParse(menuDef_t *menu);
-menuDef_t *Menu_GetFocused( void );
-void Menu_HandleKey(menuDef_t *menu, int key, qboolean down);
-void Menu_HandleMouseMove(menuDef_t *menu, float x, float y);
-void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down);
-qboolean Float_Parse(char **p, float *f);
-qboolean Color_Parse(char **p, vec4_t *c);
-qboolean Int_Parse(char **p, int *i);
-qboolean Rect_Parse(char **p, rectDef_t *r);
-qboolean String_Parse(char **p, const char **out);
-qboolean Script_Parse(char **p, const char **out);
-qboolean PC_Float_Parse(int handle, float *f);
-qboolean PC_Color_Parse(int handle, vec4_t *c);
-qboolean PC_Int_Parse(int handle, int *i);
-qboolean PC_Rect_Parse(int handle, rectDef_t *r);
-qboolean PC_String_Parse(int handle, const char **out);
-qboolean PC_Script_Parse(int handle, const char **out);
-int Menu_Count( void );
-void Menu_New(int handle);
-void Menu_PaintAll( void );
-menuDef_t *Menus_ActivateByName(const char *p);
-void Menu_Reset( void );
-qboolean Menus_AnyFullScreenVisible( void );
-void Menus_Activate(menuDef_t *menu);
-
-displayContextDef_t *Display_GetContext( void );
-void *Display_CaptureItem(int x, int y);
-qboolean Display_MouseMove(void *p, int x, int y);
-int Display_CursorType(int x, int y);
-qboolean Display_KeyBindPending( void );
-void Menus_OpenByName(const char *p);
-menuDef_t *Menus_FindByName(const char *p);
-void Menus_ShowByName(const char *p);
-void Menus_CloseByName(const char *p);
-void Display_HandleKey(int key, qboolean down, int x, int y);
-void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t);
-void Menus_CloseAll( void );
-void Menu_Paint(menuDef_t *menu, qboolean forcePaint);
-void Menu_SetFeederSelection(menuDef_t *menu, int feeder, int index, const char *name);
-void Display_CacheAll( void );
-
-void *UI_Alloc( int size );
-void UI_InitMemory( void );
-qboolean UI_OutOfMemory( void );
-
-void Controls_GetConfig( void );
-void Controls_SetConfig(qboolean restart);
-void Controls_SetDefaults( void );
-
-int trap_PC_AddGlobalDefine( char *define );
-int trap_PC_LoadSource( const char *filename );
-int trap_PC_FreeSource( int handle );
-int trap_PC_ReadToken( int handle, pc_token_t *pc_token );
-int trap_PC_SourceFileAndLine( int handle, char *filename, int *line );
-
-#endif
diff --git a/engine/code/ui/ui_syscalls.c b/engine/code/ui/ui_syscalls.c
deleted file mode 100644
index 5b3ab45..0000000
--- a/engine/code/ui/ui_syscalls.c
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-// this file is only included when building a dll
-// syscalls.asm is included instead when building a qvm
-#ifdef Q3_VM
-#error "Do not use in VM build"
-#endif
-
-static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;
-
-Q_EXPORT void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) {
- syscall = syscallptr;
-}
-
-int PASSFLOAT( float x ) {
- floatint_t fi;
- fi.f = x;
- return fi.i;
-}
-
-void trap_Print( const char *string ) {
- syscall( UI_PRINT, string );
-}
-
-void trap_Error( const char *string ) {
- syscall( UI_ERROR, string );
-}
-
-int trap_Milliseconds( void ) {
- return syscall( UI_MILLISECONDS );
-}
-
-void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags ) {
- syscall( UI_CVAR_REGISTER, cvar, var_name, value, flags );
-}
-
-void trap_Cvar_Update( vmCvar_t *cvar ) {
- syscall( UI_CVAR_UPDATE, cvar );
-}
-
-void trap_Cvar_Set( const char *var_name, const char *value ) {
- syscall( UI_CVAR_SET, var_name, value );
-}
-
-float trap_Cvar_VariableValue( const char *var_name ) {
- floatint_t fi;
- fi.i = syscall( UI_CVAR_VARIABLEVALUE, var_name );
- return fi.f;
-}
-
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
- syscall( UI_CVAR_VARIABLESTRINGBUFFER, var_name, buffer, bufsize );
-}
-
-void trap_Cvar_SetValue( const char *var_name, float value ) {
- syscall( UI_CVAR_SETVALUE, var_name, PASSFLOAT( value ) );
-}
-
-void trap_Cvar_Reset( const char *name ) {
- syscall( UI_CVAR_RESET, name );
-}
-
-void trap_Cvar_Create( const char *var_name, const char *var_value, int flags ) {
- syscall( UI_CVAR_CREATE, var_name, var_value, flags );
-}
-
-void trap_Cvar_InfoStringBuffer( int bit, char *buffer, int bufsize ) {
- syscall( UI_CVAR_INFOSTRINGBUFFER, bit, buffer, bufsize );
-}
-
-int trap_Argc( void ) {
- return syscall( UI_ARGC );
-}
-
-void trap_Argv( int n, char *buffer, int bufferLength ) {
- syscall( UI_ARGV, n, buffer, bufferLength );
-}
-
-void trap_Cmd_ExecuteText( int exec_when, const char *text ) {
- syscall( UI_CMD_EXECUTETEXT, exec_when, text );
-}
-
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
- return syscall( UI_FS_FOPENFILE, qpath, f, mode );
-}
-
-void trap_FS_Read( void *buffer, int len, fileHandle_t f ) {
- syscall( UI_FS_READ, buffer, len, f );
-}
-
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f ) {
- syscall( UI_FS_WRITE, buffer, len, f );
-}
-
-void trap_FS_FCloseFile( fileHandle_t f ) {
- syscall( UI_FS_FCLOSEFILE, f );
-}
-
-int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ) {
- return syscall( UI_FS_GETFILELIST, path, extension, listbuf, bufsize );
-}
-
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ) {
- return syscall( UI_FS_SEEK, f, offset, origin );
-}
-
-qhandle_t trap_R_RegisterModel( const char *name ) {
- return syscall( UI_R_REGISTERMODEL, name );
-}
-
-qhandle_t trap_R_RegisterSkin( const char *name ) {
- return syscall( UI_R_REGISTERSKIN, name );
-}
-
-void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {
- syscall( UI_R_REGISTERFONT, fontName, pointSize, font );
-}
-
-qhandle_t trap_R_RegisterShaderNoMip( const char *name ) {
- return syscall( UI_R_REGISTERSHADERNOMIP, name );
-}
-
-void trap_R_ClearScene( void ) {
- syscall( UI_R_CLEARSCENE );
-}
-
-void trap_R_AddRefEntityToScene( const refEntity_t *re ) {
- syscall( UI_R_ADDREFENTITYTOSCENE, re );
-}
-
-void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ) {
- syscall( UI_R_ADDPOLYTOSCENE, hShader, numVerts, verts );
-}
-
-void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
- syscall( UI_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );
-}
-
-void trap_R_RenderScene( const refdef_t *fd ) {
- syscall( UI_R_RENDERSCENE, fd );
-}
-
-void trap_R_SetColor( const float *rgba ) {
- syscall( UI_R_SETCOLOR, rgba );
-}
-
-void trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader ) {
- syscall( UI_R_DRAWSTRETCHPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), hShader );
-}
-
-void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {
- syscall( UI_R_MODELBOUNDS, model, mins, maxs );
-}
-
-void trap_UpdateScreen( void ) {
- syscall( UI_UPDATESCREEN );
-}
-
-int trap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName ) {
- return syscall( UI_CM_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName );
-}
-
-void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ) {
- syscall( UI_S_STARTLOCALSOUND, sfx, channelNum );
-}
-
-sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ) {
- return syscall( UI_S_REGISTERSOUND, sample, compressed );
-}
-
-void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) {
- syscall( UI_KEY_KEYNUMTOSTRINGBUF, keynum, buf, buflen );
-}
-
-void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen ) {
- syscall( UI_KEY_GETBINDINGBUF, keynum, buf, buflen );
-}
-
-void trap_Key_SetBinding( int keynum, const char *binding ) {
- syscall( UI_KEY_SETBINDING, keynum, binding );
-}
-
-qboolean trap_Key_IsDown( int keynum ) {
- return syscall( UI_KEY_ISDOWN, keynum );
-}
-
-qboolean trap_Key_GetOverstrikeMode( void ) {
- return syscall( UI_KEY_GETOVERSTRIKEMODE );
-}
-
-void trap_Key_SetOverstrikeMode( qboolean state ) {
- syscall( UI_KEY_SETOVERSTRIKEMODE, state );
-}
-
-void trap_Key_ClearStates( void ) {
- syscall( UI_KEY_CLEARSTATES );
-}
-
-int trap_Key_GetCatcher( void ) {
- return syscall( UI_KEY_GETCATCHER );
-}
-
-void trap_Key_SetCatcher( int catcher ) {
- syscall( UI_KEY_SETCATCHER, catcher );
-}
-
-void trap_GetClipboardData( char *buf, int bufsize ) {
- syscall( UI_GETCLIPBOARDDATA, buf, bufsize );
-}
-
-void trap_GetClientState( uiClientState_t *state ) {
- syscall( UI_GETCLIENTSTATE, state );
-}
-
-void trap_GetGlconfig( glconfig_t *glconfig ) {
- syscall( UI_GETGLCONFIG, glconfig );
-}
-
-int trap_GetConfigString( int index, char* buff, int buffsize ) {
- return syscall( UI_GETCONFIGSTRING, index, buff, buffsize );
-}
-
-int trap_LAN_GetServerCount( int source ) {
- return syscall( UI_LAN_GETSERVERCOUNT, source );
-}
-
-void trap_LAN_GetServerAddressString( int source, int n, char *buf, int buflen ) {
- syscall( UI_LAN_GETSERVERADDRESSSTRING, source, n, buf, buflen );
-}
-
-void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen ) {
- syscall( UI_LAN_GETSERVERINFO, source, n, buf, buflen );
-}
-
-int trap_LAN_GetServerPing( int source, int n ) {
- return syscall( UI_LAN_GETSERVERPING, source, n );
-}
-
-int trap_LAN_GetPingQueueCount( void ) {
- return syscall( UI_LAN_GETPINGQUEUECOUNT );
-}
-
-int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen ) {
- return syscall( UI_LAN_SERVERSTATUS, serverAddress, serverStatus, maxLen );
-}
-
-void trap_LAN_SaveCachedServers( void ) {
- syscall( UI_LAN_SAVECACHEDSERVERS );
-}
-
-void trap_LAN_LoadCachedServers( void ) {
- syscall( UI_LAN_LOADCACHEDSERVERS );
-}
-
-void trap_LAN_ResetPings(int n) {
- syscall( UI_LAN_RESETPINGS, n );
-}
-
-void trap_LAN_ClearPing( int n ) {
- syscall( UI_LAN_CLEARPING, n );
-}
-
-void trap_LAN_GetPing( int n, char *buf, int buflen, int *pingtime ) {
- syscall( UI_LAN_GETPING, n, buf, buflen, pingtime );
-}
-
-void trap_LAN_GetPingInfo( int n, char *buf, int buflen ) {
- syscall( UI_LAN_GETPINGINFO, n, buf, buflen );
-}
-
-void trap_LAN_MarkServerVisible( int source, int n, qboolean visible ) {
- syscall( UI_LAN_MARKSERVERVISIBLE, source, n, visible );
-}
-
-int trap_LAN_ServerIsVisible( int source, int n) {
- return syscall( UI_LAN_SERVERISVISIBLE, source, n );
-}
-
-qboolean trap_LAN_UpdateVisiblePings( int source ) {
- return syscall( UI_LAN_UPDATEVISIBLEPINGS, source );
-}
-
-int trap_LAN_AddServer(int source, const char *name, const char *addr) {
- return syscall( UI_LAN_ADDSERVER, source, name, addr );
-}
-
-void trap_LAN_RemoveServer(int source, const char *addr) {
- syscall( UI_LAN_REMOVESERVER, source, addr );
-}
-
-int trap_LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 ) {
- return syscall( UI_LAN_COMPARESERVERS, source, sortKey, sortDir, s1, s2 );
-}
-
-int trap_MemoryRemaining( void ) {
- return syscall( UI_MEMORY_REMAINING );
-}
-
-void trap_GetCDKey( char *buf, int buflen ) {
- syscall( UI_GET_CDKEY, buf, buflen );
-}
-
-void trap_SetCDKey( char *buf ) {
- syscall( UI_SET_CDKEY, buf );
-}
-
-int trap_PC_AddGlobalDefine( char *define ) {
- return syscall( UI_PC_ADD_GLOBAL_DEFINE, define );
-}
-
-int trap_PC_LoadSource( const char *filename ) {
- return syscall( UI_PC_LOAD_SOURCE, filename );
-}
-
-int trap_PC_FreeSource( int handle ) {
- return syscall( UI_PC_FREE_SOURCE, handle );
-}
-
-int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) {
- return syscall( UI_PC_READ_TOKEN, handle, pc_token );
-}
-
-int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) {
- return syscall( UI_PC_SOURCE_FILE_AND_LINE, handle, filename, line );
-}
-
-void trap_S_StopBackgroundTrack( void ) {
- syscall( UI_S_STOPBACKGROUNDTRACK );
-}
-
-void trap_S_StartBackgroundTrack( const char *intro, const char *loop) {
- syscall( UI_S_STARTBACKGROUNDTRACK, intro, loop );
-}
-
-int trap_RealTime(qtime_t *qtime) {
- return syscall( UI_REAL_TIME, qtime );
-}
-
-// this returns a handle. arg0 is the name in the format "idlogo.roq", set arg1 to NULL, alteredstates to qfalse (do not alter gamestate)
-int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits) {
- return syscall(UI_CIN_PLAYCINEMATIC, arg0, xpos, ypos, width, height, bits);
-}
-
-// stops playing the cinematic and ends it. should always return FMV_EOF
-// cinematics must be stopped in reverse order of when they are started
-e_status trap_CIN_StopCinematic(int handle) {
- return syscall(UI_CIN_STOPCINEMATIC, handle);
-}
-
-
-// will run a frame of the cinematic but will not draw it. Will return FMV_EOF if the end of the cinematic has been reached.
-e_status trap_CIN_RunCinematic (int handle) {
- return syscall(UI_CIN_RUNCINEMATIC, handle);
-}
-
-
-// draws the current frame
-void trap_CIN_DrawCinematic (int handle) {
- syscall(UI_CIN_DRAWCINEMATIC, handle);
-}
-
-
-// allows you to resize the animation dynamically
-void trap_CIN_SetExtents (int handle, int x, int y, int w, int h) {
- syscall(UI_CIN_SETEXTENTS, handle, x, y, w, h);
-}
-
-
-void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) {
- syscall( UI_R_REMAP_SHADER, oldShader, newShader, timeOffset );
-}
-
-qboolean trap_VerifyCDKey( const char *key, const char *chksum) {
- return syscall( UI_VERIFY_CDKEY, key, chksum);
-}
-
-void trap_SetPbClStatus( int status ) {
- syscall( UI_SET_PBCLSTATUS, status );
-}
diff --git a/engine/cross-make-mingw.sh b/engine/cross-make-mingw.sh
deleted file mode 100755
index c6dbe37..0000000
--- a/engine/cross-make-mingw.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/sh
-
-export CC=i586-mingw32msvc-gcc
-export WINDRES=i586-mingw32msvc-windres
-export PLATFORM=mingw32
-exec make $*
diff --git a/engine/make-macosx-ub.sh b/engine/make-macosx-ub.sh
deleted file mode 100755
index 0066682..0000000
--- a/engine/make-macosx-ub.sh
+++ /dev/null
@@ -1,180 +0,0 @@
-#!/bin/sh
-APPBUNDLE=ioquake3.app
-BINARY=ioquake3.ub
-DEDBIN=ioq3ded.ub
-PKGINFO=APPLIOQ3
-ICNS=misc/quake3.icns
-DESTDIR=build/release-darwin-ub
-BASEDIR=baseq3
-MPACKDIR=missionpack
-
-BIN_OBJ="
- build/release-darwin-ppc/ioquake3-smp.ppc
- build/release-darwin-i386/ioquake3-smp.i386
-"
-BIN_DEDOBJ="
- build/release-darwin-ppc/ioq3ded.ppc
- build/release-darwin-i386/ioq3ded.i386
-"
-BASE_OBJ="
- build/release-darwin-ppc/$BASEDIR/cgameppc.dylib
- build/release-darwin-i386/$BASEDIR/cgamei386.dylib
- build/release-darwin-ppc/$BASEDIR/uippc.dylib
- build/release-darwin-i386/$BASEDIR/uii386.dylib
- build/release-darwin-ppc/$BASEDIR/qagameppc.dylib
- build/release-darwin-i386/$BASEDIR/qagamei386.dylib
-"
-MPACK_OBJ="
- build/release-darwin-ppc/$MPACKDIR/cgameppc.dylib
- build/release-darwin-i386/$MPACKDIR/cgamei386.dylib
- build/release-darwin-ppc/$MPACKDIR/uippc.dylib
- build/release-darwin-i386/$MPACKDIR/uii386.dylib
- build/release-darwin-ppc/$MPACKDIR/qagameppc.dylib
- build/release-darwin-i386/$MPACKDIR/qagamei386.dylib
-"
-
-cd `dirname $0`
-if [ ! -f Makefile ]; then
- echo "This script must be run from the ioquake3 build directory"
- exit 1
-fi
-
-Q3_VERSION=`grep '^VERSION=' Makefile | sed -e 's/.*=\(.*\)/\1/'`
-
-# We only care if we're >= 10.4, not if we're specifically Tiger.
-# "8" is the Darwin major kernel version.
-TIGERHOST=`uname -r |perl -w -p -e 's/\A(\d+)\..*\Z/$1/; $_ = (($_ >= 8) ? "1" : "0");'`
-
-# we want to use the oldest available SDK for max compatiblity
-unset PPC_SDK
-unset PPC_CFLAGS
-unset PPC_LDFLAGS
-unset X86_SDK
-unset X86_CFLAGS
-unset X86_LDFLAGS
-if [ -d /Developer/SDKs/MacOSX10.5.sdk ]; then
- PPC_SDK=/Developer/SDKs/MacOSX10.5.sdk
- PPC_CFLAGS="-arch ppc -isysroot /Developer/SDKs/MacOSX10.5.sdk \
- -DMAC_OS_X_VERSION_MIN_REQUIRED=1050"
- PPC_LDFLAGS=" -mmacosx-version-min=10.5"
-
- X86_SDK=/Developer/SDKs/MacOSX10.5.sdk
- X86_CFLAGS="-arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk \
- -DMAC_OS_X_VERSION_MIN_REQUIRED=1050"
- X86_LDFLAGS=" -mmacosx-version-min=10.5"
-fi
-
-if [ -d /Developer/SDKs/MacOSX10.4u.sdk ]; then
- PPC_SDK=/Developer/SDKs/MacOSX10.4u.sdk
- PPC_CFLAGS="-arch ppc -isysroot /Developer/SDKs/MacOSX10.4u.sdk \
- -DMAC_OS_X_VERSION_MIN_REQUIRED=1040"
- PPC_LDFLAGS=" -mmacosx-version-min=10.4"
-
- X86_SDK=/Developer/SDKs/MacOSX10.4u.sdk
- X86_CFLAGS="-arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk \
- -DMAC_OS_X_VERSION_MIN_REQUIRED=1040"
- X86_LDFLAGS=" -mmacosx-version-min=10.4"
-fi
-
-if [ -d /Developer/SDKs/MacOSX10.3.9.sdk ] && [ $TIGERHOST ]; then
- PPC_SDK=/Developer/SDKs/MacOSX10.3.9.sdk
- PPC_CFLAGS="-arch ppc -isysroot /Developer/SDKs/MacOSX10.3.9.sdk \
- -DMAC_OS_X_VERSION_MIN_REQUIRED=1030"
- PPC_LDFLAGS=" -mmacosx-version-min=10.3"
-fi
-
-if [ -z $PPC_SDK ] || [ -z $X86_SDK ]; then
- echo "\
-ERROR: This script is for building a Universal Binary. You cannot build
- for a different architecture unless you have the proper Mac OS X SDKs
- installed. If you just want to to compile for your own system run
- 'make' instead of this script."
- exit 1
-fi
-
-echo "Building PPC Client/Dedicated Server against \"$PPC_SDK\""
-echo "Building X86 Client/Dedicated Server against \"$X86_SDK\""
-if [ "$PPC_SDK" != "/Developer/SDKs/MacOSX10.3.9.sdk" ] || \
- [ "$X86_SDK" != "/Developer/SDKs/MacOSX10.4u.sdk" ]; then
- echo "\
-WARNING: in order to build a binary with maximum compatibility you must
- build on Mac OS X 10.4 using Xcode 2.3 or 2.5 and have the
- MacOSX10.3.9, and MacOSX10.4u SDKs installed from the Xcode
- install disk Packages folder."
-fi
-sleep 3
-
-if [ ! -d $DESTDIR ]; then
- mkdir -p $DESTDIR
-fi
-
-# For parallel make on multicore boxes...
-NCPU=`sysctl -n hw.ncpu`
-
-# ppc client and server
-if [ -d build/release-release-ppc ]; then
- rm -r build/release-darwin-ppc
-fi
-(ARCH=ppc CFLAGS=$PPC_CFLAGS LDFLAGS=$PPC_LDFLAGS make -j$NCPU) || exit 1;
-
-# intel client and server
-if [ -d build/release-darwin-i386 ]; then
- rm -r build/release-darwin-i386
-fi
-(ARCH=i386 CFLAGS=$X86_CFLAGS LDFLAGS=$X86_LDFLAGS make -j$NCPU) || exit 1;
-
-echo "Creating .app bundle $DESTDIR/$APPBUNDLE"
-if [ ! -d $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR ]; then
- mkdir -p $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR || exit 1;
-fi
-if [ ! -d $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR ]; then
- mkdir -p $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR || exit 1;
-fi
-if [ ! -d $DESTDIR/$APPBUNDLE/Contents/Resources ]; then
- mkdir -p $DESTDIR/$APPBUNDLE/Contents/Resources
-fi
-cp $ICNS $DESTDIR/$APPBUNDLE/Contents/Resources/ioquake3.icns || exit 1;
-echo $PKGINFO > $DESTDIR/$APPBUNDLE/Contents/PkgInfo
-echo "
- <?xml version=\"1.0\" encoding=\"UTF-8\"?>
- <!DOCTYPE plist
- PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\"
- \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
- <plist version=\"1.0\">
- <dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>English</string>
- <key>CFBundleExecutable</key>
- <string>$BINARY</string>
- <key>CFBundleGetInfoString</key>
- <string>ioquake3 $Q3_VERSION</string>
- <key>CFBundleIconFile</key>
- <string>ioquake3.icns</string>
- <key>CFBundleIdentifier</key>
- <string>org.ioquake.ioquake3</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>ioquake3</string>
- <key>CFBundlePackageType</key>
- <string>APPL</string>
- <key>CFBundleShortVersionString</key>
- <string>$Q3_VERSION</string>
- <key>CFBundleSignature</key>
- <string>$PKGINFO</string>
- <key>CFBundleVersion</key>
- <string>$Q3_VERSION</string>
- <key>NSExtensions</key>
- <dict/>
- <key>NSPrincipalClass</key>
- <string>NSApplication</string>
- </dict>
- </plist>
- " > $DESTDIR/$APPBUNDLE/Contents/Info.plist
-
-lipo -create -o $DESTDIR/$APPBUNDLE/Contents/MacOS/$BINARY $BIN_OBJ
-lipo -create -o $DESTDIR/$APPBUNDLE/Contents/MacOS/$DEDBIN $BIN_DEDOBJ
-cp $BASE_OBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR/
-cp $MPACK_OBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR/
-cp code/libs/macosx/*.dylib $DESTDIR/$APPBUNDLE/Contents/MacOS/
-
diff --git a/engine/md4-readme.txt b/engine/md4-readme.txt
deleted file mode 100644
index 315fad0..0000000
--- a/engine/md4-readme.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-##########################################################
-# Info about the MD4 format supported by the ioQ3 engine #
-##########################################################
-
-All models included with the original version of Quake3 from id soft are in
-the MD3 format. Animations in this format are realized by saving the position
-of every vertex in each frame which can make these files pretty large.
-
-ID started work on a newer format, the MD4 format which they never finished.
-This format uses a skeleton with all vertices "attached" to their bones.
-Because only the position of the bones must be stored for each frame and the
-number of bones is not very high this format is more efficient when
-doing animations.
-
-Raven software "finished" this format originally started by ID and included
-it in their game EliteForce. They called their model format "MDR" which is
-the name I have used throughout the sourcecode and I will continue using in
-this readme. Since the code on how to handle those MDR files was released
-under a GPL licence a long time ago, I was able to implement this format for
-Quake3 and do some efficiency improvements.
-To enable the support for this model format, go to qcommon/qfiles.h,
-remove the comment slashes for #define RAVENMDR and then compile the engine.
-
-Including finished MDR models in your projects is easy: just load the model
-files in your cgame code as you would normally load an MD3 model. The engine
-will expect the models to have a ".mdr" suffix.
-The rest is pretty much the same: Selecting the current animation frame,
-adding a skin to the model, etc..
-You can check out the original eliteforce game sourcecode if you want to
-have examples on using the md4s. The source can be got at:
-http://eliteforce2.filefront.com/
-You can also get reference MDR files there, just go to the model/skin
-section there and pick something to download.
-
-Now here comes the tricky part:
-Creating files with this format. There are tools to create these kinds of
-MDR files, like a plugin for Milkshape.
-
-A pretty good overview about MDR file creation is available at
-http://synapse.vgfort.com/
-You can find some tools for creating MDR files there.
-
-On a sidenote:
-There is an independent implementation of the MD4 file format available
-here:
-http://gongo.quakedev.com/
-At this time, ioquake3 has no support for these models though that may
-change in the future. Nevertheless, he has got a tool for skeletal
-animations that can possibly be hooked into the MDR format with some
-modifications.
-
-
-Good luck!
- - Thilo Schulz
diff --git a/engine/misc/ReadMe-OSX.rtf b/engine/misc/ReadMe-OSX.rtf
deleted file mode 100644
index c673741..0000000
--- a/engine/misc/ReadMe-OSX.rtf
+++ /dev/null
@@ -1,29 +0,0 @@
-{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf430
-{\fonttbl\f0\fswiss\fcharset0 ArialMT;}
-{\colortbl;\red255\green255\blue255;}
-\paperw11905\paperh16837\margl1440\margr1440\vieww11380\viewh12260\viewkind0
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
-
-\f0\b\fs24 \cf0 Welcome to ioquake3.\
-\
-You can find us on the web at:\
-http://www.ioquake3.org/\
-This is the 1.36 release for Mac OS X.\
-If you run into any issues, please check out our website's discussion page for a place to talk about them and get help.\
-http://ioquake3.org/discussion/\
-\
-To install, simply copy the ioquake3 folder to your applications directory, then copy the pak0.pk3 file\
-from your legal Quake 3 Arena CDROM into the baseq3 sub-folder.\
-You can also copy it over from a boot camp'd steam install or whatever. \
-Just make sure to get your cd key as well.\
-\
-If you don't have Quake 3, check out some of the excellent games made with ioquake3:\
-http://ioquake3.org/extras/derivative-games/\
-\
-On ioquake3.org you can also find links to the latest source for this release, packages for other platforms, and more.\
-I hope to see you on server.ioquake3.org soon!\
--\
-Thanks,\
-Zachary Slater\
-zachary at ioquake.org\
-}
\ No newline at end of file
diff --git a/engine/misc/ioquake3-folder.icns b/engine/misc/ioquake3-folder.icns
deleted file mode 100644
index 618d31a..0000000
Binary files a/engine/misc/ioquake3-folder.icns and /dev/null differ
diff --git a/engine/misc/msvc/cgame.def b/engine/misc/msvc/cgame.def
deleted file mode 100644
index 48b7743..0000000
--- a/engine/misc/msvc/cgame.def
+++ /dev/null
@@ -1,3 +0,0 @@
-EXPORTS
- vmMain
- dllEntry
\ No newline at end of file
diff --git a/engine/misc/msvc/cgame.vcproj b/engine/misc/msvc/cgame.vcproj
deleted file mode 100644
index 2c76c9d..0000000
--- a/engine/misc/msvc/cgame.vcproj
+++ /dev/null
@@ -1,1514 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="8.00"
- Name="cgame"
- ProjectGUID="{C878E295-CB82-4B40-8ECF-5CE5525466FA}"
- RootNamespace="cgame"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Release TA|Win32"
- OutputDirectory="..\..\build\cgame_release_ta"
- IntermediateDirectory="..\..\build\cgame_release_ta"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\$(IntDir)\cgame.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;MISSIONPACK"
- StringPooling="true"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="true"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\cgame.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- WarningLevel="4"
- SuppressStartupBanner="true"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="$(OutDir)\cgamex86.dll"
- LinkIncremental="1"
- SuppressStartupBanner="true"
- ModuleDefinitionFile=".\cgame.def"
- ProgramDatabaseFile="$(IntDir)\cgamex86.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\cgamex86.map"
- SubSystem="2"
- BaseAddress="0x30000000"
- ImportLibrary="$(IntDir)\cgamex86.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="..\..\build\cgame_debug"
- IntermediateDirectory="..\..\build\cgame_debug"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Debug/cgame.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE"
- RuntimeLibrary="1"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\cgame.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="true"
- DebugInformationFormat="4"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="$(OutDir)\cgamex86.dll"
- LinkIncremental="2"
- SuppressStartupBanner="true"
- ModuleDefinitionFile=".\cgame.def"
- GenerateDebugInformation="true"
- ProgramDatabaseFile="$(IntDir)\cgamex86.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\cgamex86.map"
- SubSystem="2"
- BaseAddress="0x30000000"
- ImportLibrary="$(IntDir)\cgamex86.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="..\..\build\cgame_release"
- IntermediateDirectory="..\..\build\cgame_release"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Release/cgame.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE"
- StringPooling="true"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="true"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\cgame.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- WarningLevel="4"
- SuppressStartupBanner="true"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="$(OutDir)\cgamex86.dll"
- LinkIncremental="1"
- SuppressStartupBanner="true"
- ModuleDefinitionFile=".\cgame.def"
- ProgramDatabaseFile="$(IntDir)\cgamex86.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\cgamex86.map"
- SubSystem="2"
- BaseAddress="0x30000000"
- ImportLibrary="$(IntDir)\cgamex86.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Debug TA|Win32"
- OutputDirectory="..\..\build\cgame_debug_ta"
- IntermediateDirectory="..\..\build\cgame_debug_ta"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Debug_TA/cgame.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;_CRT_SECURE_NO_DEPRECATE"
- RuntimeLibrary="1"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\cgame.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="true"
- DebugInformationFormat="4"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="$(OutDir)\cgamex86.dll"
- LinkIncremental="2"
- SuppressStartupBanner="true"
- ModuleDefinitionFile=".\cgame.def"
- GenerateDebugInformation="true"
- ProgramDatabaseFile="$(IntDir)\cgamex86.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\cgamex86.map"
- SubSystem="2"
- BaseAddress="0x30000000"
- ImportLibrary="$(IntDir)\cgamex86.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="c"
- >
- <File
- RelativePath="..\..\code\game\bg_lib.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\bg_misc.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\bg_pmove.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\bg_slidemove.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_consolecmds.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_draw.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_drawtools.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_effects.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_ents.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_event.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_info.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_localents.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_main.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_marks.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_newDraw.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_players.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_playerstate.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_predict.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_scoreboard.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_servercmds.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_snapshot.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_syscalls.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_view.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_weapons.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\q_math.c"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\q_shared.c"
- >
- </File>
- <File
- RelativePath="..\..\code\ui\ui_shared.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h"
- >
- <File
- RelativePath="..\..\code\game\bg_public.h"
- >
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_local.h"
- >
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_public.h"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\q_shared.h"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\surfaceflags.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Resource Files"
- >
- <File
- RelativePath=".\cgame.def"
- >
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/engine/misc/msvc/game.def b/engine/misc/msvc/game.def
deleted file mode 100644
index 6563196..0000000
--- a/engine/misc/msvc/game.def
+++ /dev/null
@@ -1,3 +0,0 @@
-EXPORTS
- dllEntry
- vmMain
\ No newline at end of file
diff --git a/engine/misc/msvc/game.vcproj b/engine/misc/msvc/game.vcproj
deleted file mode 100644
index 902fc0b..0000000
--- a/engine/misc/msvc/game.vcproj
+++ /dev/null
@@ -1,1893 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="8.00"
- Name="game"
- ProjectGUID="{F9EE10DA-2404-4154-B904-F93C936C040A}"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Debug TA|Win32"
- OutputDirectory="..\..\build\game_debug_ta"
- IntermediateDirectory="..\..\build\game_debug_ta"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Debug_TA/game.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;_CRT_SECURE_NO_DEPRECATE"
- RuntimeLibrary="1"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\game.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="true"
- DebugInformationFormat="4"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="winmm.lib"
- OutputFile="$(OutDir)\qagamex86.dll"
- LinkIncremental="2"
- SuppressStartupBanner="true"
- ModuleDefinitionFile=".\game.def"
- GenerateDebugInformation="true"
- ProgramDatabaseFile="$(IntDir)\qagamex86.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\qagamex86.map"
- SubSystem="2"
- BaseAddress="0x20000000"
- ImportLibrary="$(IntDir)\qagamex86.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="..\..\build\game_debug"
- IntermediateDirectory="..\..\build\game_debug"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Debug/game.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;_CRT_SECURE_NO_DEPRECATE"
- RuntimeLibrary="1"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\game.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="true"
- DebugInformationFormat="4"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="winmm.lib"
- OutputFile="$(OutDir)\qagamex86.dll"
- LinkIncremental="2"
- SuppressStartupBanner="true"
- ModuleDefinitionFile=".\game.def"
- GenerateDebugInformation="true"
- ProgramDatabaseFile="$(IntDir)\qagamex86.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\qagamex86.map"
- SubSystem="2"
- BaseAddress="0x20000000"
- ImportLibrary="$(IntDir)\qagamex86.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="..\..\build\game_release"
- IntermediateDirectory="..\..\build\game_release"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Release/game.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;_CRT_SECURE_NO_DEPRECATE"
- StringPooling="true"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="true"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\game.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- WarningLevel="4"
- SuppressStartupBanner="true"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="winmm.lib"
- OutputFile="$(OutDir)\qagamex86.dll"
- LinkIncremental="1"
- SuppressStartupBanner="true"
- ModuleDefinitionFile=".\game.def"
- ProgramDatabaseFile="$(IntDir)\qagamex86.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\qagamex86.map"
- SubSystem="2"
- BaseAddress="0x20000000"
- ImportLibrary="$(IntDir)\qagamex86.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release TA|Win32"
- OutputDirectory="..\..\build\game_release_ta"
- IntermediateDirectory="..\..\build\game_release_ta"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Release_TA/game.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;_CRT_SECURE_NO_DEPRECATE"
- StringPooling="true"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="true"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\game.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- WarningLevel="4"
- SuppressStartupBanner="true"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="winmm.lib"
- OutputFile="$(IntDir)\qagamex86.dll"
- LinkIncremental="1"
- SuppressStartupBanner="true"
- ModuleDefinitionFile=".\game.def"
- ProgramDatabaseFile="$(IntDir)\qagamex86.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\qagamex86.map"
- SubSystem="2"
- BaseAddress="0x20000000"
- ImportLibrary="$(IntDir)\qagamex86.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
- >
- <File
- RelativePath="..\..\code\game\ai_chat.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\ai_cmd.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\ai_dmnet.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\ai_dmq3.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\ai_main.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\ai_team.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\ai_vcmd.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\bg_lib.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\bg_misc.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\bg_pmove.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\bg_slidemove.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_active.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_arenas.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_bot.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_client.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_cmds.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_combat.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_items.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_main.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_mem.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_misc.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_missile.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_mover.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_session.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_spawn.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_svcmds.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_syscalls.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_target.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_team.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_trigger.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_utils.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\g_weapon.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;MISSIONPACK;QAGAME;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BUILDING_REF_GL;DEBUG;GLOBALRANK;"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;GLOBALRANK;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\q_math.c"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\q_shared.c"
- >
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl;fi;fd"
- >
- <File
- RelativePath="..\..\code\game\ai_chat.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\ai_cmd.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\ai_dmnet.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\ai_dmq3.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\ai_main.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\ai_team.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\ai_vcmd.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\be_aas.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\be_ai_char.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\be_ai_chat.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\be_ai_gen.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\be_ai_goal.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\be_ai_move.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\be_ai_weap.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\be_ea.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\bg_local.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\bg_public.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\botlib.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\chars.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\g_local.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\g_public.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\g_team.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\inv.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\match.h"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\q_shared.h"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\surfaceflags.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\syn.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Resource Files"
- >
- <File
- RelativePath=".\game.def"
- >
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/engine/misc/msvc/ioq3.sln b/engine/misc/msvc/ioq3.sln
deleted file mode 100755
index 13b1bb3..0000000
--- a/engine/misc/msvc/ioq3.sln
+++ /dev/null
@@ -1,61 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual C++ Express 2005
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cgame", "cgame.vcproj", "{C878E295-CB82-4B40-8ECF-5CE5525466FA}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "game", "game.vcproj", "{F9EE10DA-2404-4154-B904-F93C936C040A}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "q3_ui", "q3_ui.vcproj", "{D454C4C7-7765-4149-ABAD-05FDEB9D94F8}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "quake3", "quake3.vcproj", "{81CB51C4-B434-4E12-B69B-BAEE102F2852}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ui", "ui.vcproj", "{A8EAC38E-C7DA-42F8-811D-77FD092B9D19}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug TA|Win32 = Debug TA|Win32
- Debug|Win32 = Debug|Win32
- Release TA|Win32 = Release TA|Win32
- Release|Win32 = Release|Win32
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {C878E295-CB82-4B40-8ECF-5CE5525466FA}.Debug TA|Win32.ActiveCfg = Debug TA|Win32
- {C878E295-CB82-4B40-8ECF-5CE5525466FA}.Debug TA|Win32.Build.0 = Debug TA|Win32
- {C878E295-CB82-4B40-8ECF-5CE5525466FA}.Debug|Win32.ActiveCfg = Debug|Win32
- {C878E295-CB82-4B40-8ECF-5CE5525466FA}.Debug|Win32.Build.0 = Debug|Win32
- {C878E295-CB82-4B40-8ECF-5CE5525466FA}.Release TA|Win32.ActiveCfg = Release TA|Win32
- {C878E295-CB82-4B40-8ECF-5CE5525466FA}.Release TA|Win32.Build.0 = Release TA|Win32
- {C878E295-CB82-4B40-8ECF-5CE5525466FA}.Release|Win32.ActiveCfg = Release|Win32
- {C878E295-CB82-4B40-8ECF-5CE5525466FA}.Release|Win32.Build.0 = Release|Win32
- {F9EE10DA-2404-4154-B904-F93C936C040A}.Debug TA|Win32.ActiveCfg = Debug TA|Win32
- {F9EE10DA-2404-4154-B904-F93C936C040A}.Debug TA|Win32.Build.0 = Debug TA|Win32
- {F9EE10DA-2404-4154-B904-F93C936C040A}.Debug|Win32.ActiveCfg = Debug|Win32
- {F9EE10DA-2404-4154-B904-F93C936C040A}.Debug|Win32.Build.0 = Debug|Win32
- {F9EE10DA-2404-4154-B904-F93C936C040A}.Release TA|Win32.ActiveCfg = Release TA|Win32
- {F9EE10DA-2404-4154-B904-F93C936C040A}.Release TA|Win32.Build.0 = Release TA|Win32
- {F9EE10DA-2404-4154-B904-F93C936C040A}.Release|Win32.ActiveCfg = Release|Win32
- {F9EE10DA-2404-4154-B904-F93C936C040A}.Release|Win32.Build.0 = Release|Win32
- {D454C4C7-7765-4149-ABAD-05FDEB9D94F8}.Debug TA|Win32.ActiveCfg = Debug TA|Win32
- {D454C4C7-7765-4149-ABAD-05FDEB9D94F8}.Debug|Win32.ActiveCfg = Debug|Win32
- {D454C4C7-7765-4149-ABAD-05FDEB9D94F8}.Debug|Win32.Build.0 = Debug|Win32
- {D454C4C7-7765-4149-ABAD-05FDEB9D94F8}.Release TA|Win32.ActiveCfg = Release TA|Win32
- {D454C4C7-7765-4149-ABAD-05FDEB9D94F8}.Release|Win32.ActiveCfg = Release|Win32
- {D454C4C7-7765-4149-ABAD-05FDEB9D94F8}.Release|Win32.Build.0 = Release|Win32
- {81CB51C4-B434-4E12-B69B-BAEE102F2852}.Debug TA|Win32.ActiveCfg = Debug TA|Win32
- {81CB51C4-B434-4E12-B69B-BAEE102F2852}.Debug TA|Win32.Build.0 = Debug TA|Win32
- {81CB51C4-B434-4E12-B69B-BAEE102F2852}.Debug|Win32.ActiveCfg = Debug|Win32
- {81CB51C4-B434-4E12-B69B-BAEE102F2852}.Debug|Win32.Build.0 = Debug|Win32
- {81CB51C4-B434-4E12-B69B-BAEE102F2852}.Release TA|Win32.ActiveCfg = Release TA|Win32
- {81CB51C4-B434-4E12-B69B-BAEE102F2852}.Release TA|Win32.Build.0 = Release TA|Win32
- {81CB51C4-B434-4E12-B69B-BAEE102F2852}.Release|Win32.ActiveCfg = Release|Win32
- {81CB51C4-B434-4E12-B69B-BAEE102F2852}.Release|Win32.Build.0 = Release|Win32
- {A8EAC38E-C7DA-42F8-811D-77FD092B9D19}.Debug TA|Win32.ActiveCfg = Debug TA|Win32
- {A8EAC38E-C7DA-42F8-811D-77FD092B9D19}.Debug TA|Win32.Build.0 = Debug TA|Win32
- {A8EAC38E-C7DA-42F8-811D-77FD092B9D19}.Debug|Win32.ActiveCfg = Debug|Win32
- {A8EAC38E-C7DA-42F8-811D-77FD092B9D19}.Release TA|Win32.ActiveCfg = Release TA|Win32
- {A8EAC38E-C7DA-42F8-811D-77FD092B9D19}.Release TA|Win32.Build.0 = Release TA|Win32
- {A8EAC38E-C7DA-42F8-811D-77FD092B9D19}.Release|Win32.ActiveCfg = Release|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/engine/misc/msvc/q3_ui.def b/engine/misc/msvc/q3_ui.def
deleted file mode 100644
index 48b7743..0000000
--- a/engine/misc/msvc/q3_ui.def
+++ /dev/null
@@ -1,3 +0,0 @@
-EXPORTS
- vmMain
- dllEntry
\ No newline at end of file
diff --git a/engine/misc/msvc/q3_ui.vcproj b/engine/misc/msvc/q3_ui.vcproj
deleted file mode 100644
index 812c90a..0000000
--- a/engine/misc/msvc/q3_ui.vcproj
+++ /dev/null
@@ -1,2465 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="8.00"
- Name="q3_ui"
- ProjectGUID="{D454C4C7-7765-4149-ABAD-05FDEB9D94F8}"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Debug TA|Win32"
- OutputDirectory="..\..\build\q3_ui_debug_ta"
- IntermediateDirectory="..\..\build\q3_ui_debug_ta"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Debug_TA/q3_ui.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;UI_EXPORTS;_CRT_SECURE_NO_DEPRECATE;MISSIONPACK"
- BasicRuntimeChecks="3"
- RuntimeLibrary="1"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\q3_ui.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="true"
- DebugInformationFormat="4"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="$(OutDir)\uix86_old.dll"
- LinkIncremental="2"
- SuppressStartupBanner="true"
- ModuleDefinitionFile="q3_ui.def"
- GenerateDebugInformation="true"
- ProgramDatabaseFile="$(IntDir)\ui.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\uix86.map"
- BaseAddress="0x40000000"
- ImportLibrary="$(IntDir)\uix86.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release TA|Win32"
- OutputDirectory="..\..\build\q3_ui_release_ta"
- IntermediateDirectory="..\..\build\q3_ui_release_ta"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Release_TA/q3_ui.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;Q3_UI_EXPORTS;_CRT_SECURE_NO_DEPRECATE;MISSIONPACK"
- StringPooling="true"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="true"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\q3_ui.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- WarningLevel="3"
- SuppressStartupBanner="true"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="$(OutDir)\uix86_old.dll"
- LinkIncremental="1"
- SuppressStartupBanner="true"
- ModuleDefinitionFile="q3_ui.def"
- ProgramDatabaseFile="$(IntDir)\uix86_old.pdb"
- ImportLibrary="$(IntDir)\q3_ui.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="..\..\build\q3_ui_release"
- IntermediateDirectory="..\..\build\q3_ui_release"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Release/q3_ui.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;Q3_UI_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
- StringPooling="true"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="true"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\q3_ui.pch"
- AssemblerOutput="0"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- WarningLevel="3"
- SuppressStartupBanner="true"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- OutputFile="$(OutDir)\uix86.dll"
- LinkIncremental="1"
- SuppressStartupBanner="true"
- ModuleDefinitionFile=".\q3_ui.def"
- ProgramDatabaseFile="$(IntDir)\uix86.pdb"
- ImportLibrary="$(IntDir)\uix86.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="..\..\build\q3_ui_debug"
- IntermediateDirectory="..\..\build\q3_ui_debug"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\q3_ui___Win32_Debug/q3_ui.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;UI_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
- BasicRuntimeChecks="3"
- RuntimeLibrary="1"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\q3_ui.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="true"
- DebugInformationFormat="4"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="$(OutDir)\uix86.dll"
- LinkIncremental="2"
- SuppressStartupBanner="true"
- ModuleDefinitionFile="q3_ui.def"
- GenerateDebugInformation="true"
- ProgramDatabaseFile="$(IntDir)\ui.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\uix86.map"
- BaseAddress="0x40000000"
- ImportLibrary="$(IntDir)\uix86.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
- >
- <File
- RelativePath="..\..\code\game\bg_misc.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\q_math.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\q_shared.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_addbots.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_atoms.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_cdkey.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_cinematics.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_confirm.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_connect.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_controls2.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_credits.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_demo2.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_display.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_gameinfo.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_ingame.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_loadconfig.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_main.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_menu.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_mfield.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_mods.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_network.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_options.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_playermodel.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_players.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_playersettings.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_preferences.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_qmenu.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_removebots.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_saveconfig.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_serverinfo.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_servers2.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_setup.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_sound.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_sparena.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_specifyserver.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_splevel.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_sppostgame.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_spreset.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_spskill.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_startserver.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\ui\ui_syscalls.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_team.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_teamorders.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_video.c"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;Q3_UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl"
- >
- <File
- RelativePath="..\..\code\q3_ui\keycodes.h"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\q_shared.h"
- >
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_local.h"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\q3_ui\ui_public.h"
- >
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="Resource Files"
- >
- <File
- RelativePath=".\q3_ui.def"
- >
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/engine/misc/msvc/quake3.vcproj b/engine/misc/msvc/quake3.vcproj
deleted file mode 100644
index 3a398b0..0000000
--- a/engine/misc/msvc/quake3.vcproj
+++ /dev/null
@@ -1,3224 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="8.00"
- Name="quake3"
- ProjectGUID="{81CB51C4-B434-4E12-B69B-BAEE102F2852}"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Release TA|Win32"
- OutputDirectory="..\..\build\quake3_release_ta"
- IntermediateDirectory="..\..\build\quake3_release_ta"
- ConfigurationType="1"
- UseOfMFC="1"
- ATLMinimizesCRunTimeLibraryUsage="false"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName="$(IntDir)\quake3.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="2"
- AdditionalIncludeDirectories="..\..\code\libcurl; ..\..\code\AL; ..\..\code\libspeex\include; ..\..\code\SDL12\include; ..\..\code\zlib"
- PreprocessorDefinitions="_WIN32; WIN32; NDEBUG; _WINDOWS; _CRT_SECURE_NO_DEPRECATE; BOTLIB; USE_ICON; USE_CURL; USE_CURL_DLOPEN; USE_OPENAL; USE_OPENAL_DLOPEN; USE_VOIP; HAVE_CONFIG_H; MISSIONPACK"
- StringPooling="true"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="true"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\quake3.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- WarningLevel="4"
- SuppressStartupBanner="true"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="user32.lib advapi32.lib winmm.lib wsock32.lib ws2_32.lib SDLmain.lib SDL.lib OpenGL32.lib msvcrt.lib"
- OutputFile="$(OutDir)\ioquake3.exe"
- LinkIncremental="1"
- SuppressStartupBanner="true"
- GenerateDebugInformation="false"
- ProgramDatabaseFile="$(IntDir)\quake3.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\quake3.map"
- SubSystem="2"
- StackReserveSize="8388608"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- Description="Post build processing.."
- CommandLine="rem bash -c "perl ./unix/cons -- release-TA""
- />
- </Configuration>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="..\..\build\quake3_debug"
- IntermediateDirectory="..\..\build\quake3_debug"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName="$(IntDir)\quake3.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="..\..\code\libcurl; ..\..\code\AL; ..\..\code\libspeex\include; ..\..\code\SDL12\include; ..\..\code\zlib"
- PreprocessorDefinitions="_WIN32; WIN32; _DEBUG; _WINDOWS; _CRT_SECURE_NO_DEPRECATE; BOTLIB; USE_ICON; USE_CURL; USE_CURL_DLOPEN; USE_OPENAL; USE_OPENAL_DLOPEN; USE_VOIP; HAVE_CONFIG_H"
- RuntimeLibrary="3"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\quake3.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- BrowseInformation="1"
- BrowseInformationFile="$(IntDir)\"
- WarningLevel="3"
- SuppressStartupBanner="true"
- DebugInformationFormat="4"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"
- ResourceOutputFileName="..\winquake.res"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="user32.lib advapi32.lib winmm.lib wsock32.lib ws2_32.lib SDLmain.lib SDL.lib OpenGL32.lib msvcrt.lib"
- OutputFile="$(OutDir)\ioquake3.exe"
- LinkIncremental="2"
- SuppressStartupBanner="true"
- IgnoreDefaultLibraryNames=""
- GenerateDebugInformation="true"
- ProgramDatabaseFile="$(IntDir)\quake3.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\quake3.map"
- SubSystem="2"
- StackReserveSize="8388608"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- Description="Post build processing.."
- CommandLine="rem bash -c "perl ./unix/cons -- debug""
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="..\..\build\quake3_release"
- IntermediateDirectory="..\..\build\quake3_release"
- ConfigurationType="1"
- UseOfMFC="1"
- ATLMinimizesCRunTimeLibraryUsage="false"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName="$(IntDir)\quake3.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="2"
- AdditionalIncludeDirectories="..\..\code\SDL12\include; ..\..\code\libcurl; ..\..\code\AL; ..\..\code\libspeex\include; ..\..\code\zlib"
- PreprocessorDefinitions="_WIN32; WIN32; NDEBUG; _WINDOWS; _CRT_SECURE_NO_DEPRECATE; BOTLIB; USE_ICON; USE_CURL; USE_CURL_DLOPEN; USE_OPENAL; USE_OPENAL_DLOPEN; USE_VOIP; HAVE_CONFIG_H"
- StringPooling="true"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="true"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\quake3.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- WarningLevel="4"
- SuppressStartupBanner="true"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="user32.lib advapi32.lib winmm.lib wsock32.lib ws2_32.lib SDLmain.lib SDL.lib OpenGL32.lib msvcrt.lib"
- OutputFile="$(OutDir)\ioquake3.exe"
- LinkIncremental="1"
- SuppressStartupBanner="true"
- GenerateDebugInformation="false"
- ProgramDatabaseFile="$(IntDir)\quake3.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\quake3.map"
- SubSystem="2"
- StackReserveSize="8388608"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Debug TA|Win32"
- OutputDirectory="..\..\build\quake3_debug_ta"
- IntermediateDirectory="..\..\build\quake3_debug_ta"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName="$(IntDir)\quake3.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="..\..\code\libcurl; ..\..\code\AL; ..\..\code\libspeex\include; ..\..\code\SDL12\include; ..\..\code\zlib"
- PreprocessorDefinitions="_WIN32; WIN32; _DEBUG; _WINDOWS; _CRT_SECURE_NO_DEPRECATE; BOTLIB; USE_ICON; USE_CURL; USE_CURL_DLOPEN; USE_OPENAL; USE_OPENAL_DLOPEN; USE_VOIP; HAVE_CONFIG_H; MISSIONPACK"
- RuntimeLibrary="3"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\quake3.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- BrowseInformation="1"
- BrowseInformationFile="$(IntDir)\"
- WarningLevel="3"
- SuppressStartupBanner="true"
- DebugInformationFormat="4"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"
- ResourceOutputFileName="..\winquake.res"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="user32.lib advapi32.lib winmm.lib wsock32.lib ws2_32.lib SDLmain.lib SDL.lib OpenGL32.lib msvcrt.lib"
- OutputFile="$(OutDir)\ioquake3.exe"
- LinkIncremental="2"
- SuppressStartupBanner="true"
- GenerateDebugInformation="true"
- ProgramDatabaseFile="$(IntDir)\quake3.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\quake3.map"
- SubSystem="2"
- StackReserveSize="8388608"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- Description="Post build processing.."
- CommandLine="rem bash -c "perl ./unix/cons -- debug-TA""
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
- >
- <File
- RelativePath="..\..\code\client\cl_avi.c"
- >
- </File>
- <File
- RelativePath="..\..\code\client\cl_cgame.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\client\cl_cin.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\client\cl_console.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\client\cl_curl.c"
- >
- </File>
- <File
- RelativePath="..\..\code\client\cl_input.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\client\cl_keys.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\client\cl_main.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\client\cl_net_chan.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\client\cl_parse.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\client\cl_scrn.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\client\cl_ui.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\cm_load.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\cm_patch.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\cm_polylib.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\cm_test.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\cm_trace.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\cmd.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\common.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\sys\con_log.c"
- >
- </File>
- <File
- RelativePath="..\..\code\sys\con_passive.c"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\cvar.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\files.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\huffman.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\md4.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\md5.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\msg.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\net_chan.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\net_ip.c"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\puff.c"
- >
- </File>
- <File
- RelativePath="..\..\code\.\qcommon\q_math.c"
- >
- </File>
- <File
- RelativePath="..\..\code\.\qcommon\q_shared.c"
- >
- </File>
- <File
- RelativePath="..\..\code\client\qal.c"
- >
- </File>
- <File
- RelativePath="..\..\code\sdl\sdl_gamma.c"
- >
- </File>
- <File
- RelativePath="..\..\code\sdl\sdl_glimp.c"
- >
- </File>
- <File
- RelativePath="..\..\code\sdl\sdl_input.c"
- >
- </File>
- <File
- RelativePath="..\..\code\sdl\sdl_snd.c"
- >
- </File>
- <File
- RelativePath="..\..\code\client\snd_adpcm.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\client\snd_codec.c"
- >
- </File>
- <File
- RelativePath="..\..\code\client\snd_codec_ogg.c"
- >
- </File>
- <File
- RelativePath="..\..\code\client\snd_codec_wav.c"
- >
- </File>
- <File
- RelativePath="..\..\code\client\snd_dma.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\client\snd_main.c"
- >
- </File>
- <File
- RelativePath="..\..\code\client\snd_mem.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\client\snd_mix.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\client\snd_openal.c"
- >
- </File>
- <File
- RelativePath="..\..\code\client\snd_wavelet.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\server\sv_bot.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\server\sv_ccmds.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\server\sv_client.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\server\sv_game.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\server\sv_init.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\server\sv_main.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\server\sv_net_chan.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\server\sv_snapshot.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\server\sv_world.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\sys\sys_main.c"
- >
- </File>
- <File
- RelativePath="..\..\code\sys\sys_win32.c"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\unzip.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\ioapi.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\vm.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\vm_interpreted.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\vm_x86.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl;fi;fd"
- >
- <File
- RelativePath="..\..\code\game\bg_public.h"
- >
- </File>
- <File
- RelativePath="..\..\code\cgame\cg_public.h"
- >
- </File>
- <File
- RelativePath="..\..\code\client\cl_curl.h"
- >
- </File>
- <File
- RelativePath="..\..\code\client\client.h"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\cm_local.h"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\cm_patch.h"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\cm_polylib.h"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\cm_public.h"
- >
- </File>
- <File
- RelativePath="..\..\code\game\g_public.h"
- >
- </File>
- <File
- RelativePath="..\..\code\ui\keycodes.h"
- >
- </File>
- <File
- RelativePath="..\..\code\client\keys.h"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\puff.h"
- >
- </File>
- <File
- RelativePath="..\..\code\.\qcommon\q_shared.h"
- >
- </File>
- <File
- RelativePath="..\..\code\client\qal.h"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\qcommon.h"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\qfiles.h"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\qgl.h"
- >
- </File>
- <File
- RelativePath="..\..\code\win32\resource.h"
- >
- </File>
- <File
- RelativePath="..\..\code\server\server.h"
- >
- </File>
- <File
- RelativePath="..\..\code\client\snd_local.h"
- >
- </File>
- <File
- RelativePath="..\..\code\client\snd_public.h"
- >
- </File>
- <File
- RelativePath="..\..\code\.\qcommon\surfaceflags.h"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_local.h"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_public.h"
- >
- </File>
- <File
- RelativePath="..\..\code\cgame\tr_types.h"
- >
- </File>
- <File
- RelativePath="..\..\code\ui\ui_public.h"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\unzip.h"
- >
- </File>
- <File
- RelativePath="..\..\code\qcommon\vm_local.h"
- >
- </File>
- <File
- RelativePath="..\..\code\win32\win_local.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
- >
- <File
- RelativePath="..\..\code\sys\win_resource.h"
- >
- </File>
- <File
- RelativePath="..\..\code\sys\win_resource.rc"
- >
- </File>
- </Filter>
- <Filter
- Name="jpeg"
- >
- <Filter
- Name="Source Files"
- >
- <File
- RelativePath="..\..\code\jpeg-6b\jcapimin.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jcapistd.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jccoefct.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jccolor.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jcdctmgr.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jchuff.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jcinit.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jcmainct.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jcmarker.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jcmaster.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jcomapi.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jcparam.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jcphuff.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jcprepct.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jcsample.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdapimin.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdapistd.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdatasrc.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdcoefct.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdcolor.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jddctmgr.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdhuff.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdinput.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdmainct.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdmarker.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdmaster.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdpostct.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdsample.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdtrans.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jerror.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jfdctflt.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jidctflt.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jmemmgr.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jmemnobs.c"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jutils.c"
- >
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- >
- <File
- RelativePath="..\..\code\jpeg-6b\jchuff.h"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jconfig.h"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdct.h"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jdhuff.h"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jerror.h"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jinclude.h"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jmemsys.h"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jmorecfg.h"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jpegint.h"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jpeglib.h"
- >
- </File>
- <File
- RelativePath="..\..\code\jpeg-6b\jversion.h"
- >
- </File>
- </Filter>
- </Filter>
- <Filter
- Name="botlib"
- >
- <Filter
- Name="Source Files"
- >
- <File
- RelativePath="..\..\code\botlib\be_aas_bspq3.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_cluster.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_debug.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_entity.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_file.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_main.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_move.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_optimize.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_reach.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_route.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_routealt.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_sample.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_ai_char.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_ai_chat.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_ai_gen.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_ai_goal.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_ai_move.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_ai_weap.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_ai_weight.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_ea.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_interface.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_crc.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_libvar.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_log.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_memory.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_precomp.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_script.c"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_struct.c"
- >
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- >
- <File
- RelativePath="..\..\code\botlib\aasfile.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_bsp.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_cluster.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_debug.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_def.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_entity.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_file.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_funcs.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_main.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_move.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_optimize.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_reach.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_route.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_routealt.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_aas_sample.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_ai_weight.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\be_interface.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_crc.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_libvar.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_log.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_memory.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_precomp.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_script.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_struct.h"
- >
- </File>
- <File
- RelativePath="..\..\code\botlib\l_utils.h"
- >
- </File>
- </Filter>
- </Filter>
- <Filter
- Name="renderer"
- >
- <Filter
- Name="Source Files"
- >
- <File
- RelativePath="..\..\code\renderer\tr_animation.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_backend.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_bsp.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_cmds.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_curve.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_flares.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_font.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_image.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_image_bmp.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_image_jpg.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_image_pcx.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_image_png.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_image_tga.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_init.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_light.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_main.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_marks.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_mesh.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_model.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_noise.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_scene.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_shade.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_shade_calc.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_shader.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_shadows.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_sky.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_surface.c"
- >
- </File>
- <File
- RelativePath="..\..\code\renderer\tr_world.c"
- >
- </File>
- </Filter>
- </Filter>
- <Filter
- Name="speex"
- >
- <File
- RelativePath="..\..\code\libspeex\bits.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\buffer.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\cb_search.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\config.h"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\exc_10_16_table.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\exc_10_32_table.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\exc_20_32_table.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\exc_5_256_table.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\exc_5_64_table.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\exc_8_128_table.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\fftwrap.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\filterbank.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\filters.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\gain_table.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\gain_table_lbr.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\hexc_10_32_table.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\hexc_table.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\high_lsp_tables.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\jitter.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\kiss_fft.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\kiss_fftr.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\lpc.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\lsp.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\lsp_tables_nb.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\ltp.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\mdf.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\modes.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\modes_wb.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\nb_celp.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\preprocess.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\quant_lsp.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\resample.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\sb_celp.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\smallft.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\speex.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\speex_callbacks.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\speex_header.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\stereo.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\vbr.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\vq.c"
- >
- </File>
- <File
- RelativePath="..\..\code\libspeex\window.c"
- >
- </File>
- </Filter>
- <Filter
- Name="zlib"
- >
- <File
- RelativePath="..\..\code\zlib\adler32.c"
- >
- </File>
- <File
- RelativePath="..\..\code\zlib\crc32.c"
- >
- </File>
- <File
- RelativePath="..\..\code\zlib\inffast.c"
- >
- </File>
- <File
- RelativePath="..\..\code\zlib\inflate.c"
- >
- </File>
- <File
- RelativePath="..\..\code\zlib\inftrees.c"
- >
- </File>
- <File
- RelativePath="..\..\code\zlib\zutil.c"
- >
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/engine/misc/msvc/ui.def b/engine/misc/msvc/ui.def
deleted file mode 100644
index 48b7743..0000000
--- a/engine/misc/msvc/ui.def
+++ /dev/null
@@ -1,3 +0,0 @@
-EXPORTS
- vmMain
- dllEntry
\ No newline at end of file
diff --git a/engine/misc/msvc/ui.vcproj b/engine/misc/msvc/ui.vcproj
deleted file mode 100644
index 79e0821..0000000
--- a/engine/misc/msvc/ui.vcproj
+++ /dev/null
@@ -1,1018 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="8.00"
- Name="ui"
- ProjectGUID="{A8EAC38E-C7DA-42F8-811D-77FD092B9D19}"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Release TA|Win32"
- OutputDirectory="..\..\build\ui_release_ta"
- IntermediateDirectory="..\..\build\ui_release_ta"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Release_TA/ui.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;UI_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
- StringPooling="true"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="true"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\ui.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- WarningLevel="3"
- SuppressStartupBanner="true"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="$(OutDir)\uix86.dll"
- LinkIncremental="1"
- SuppressStartupBanner="true"
- ModuleDefinitionFile=".\ui.def"
- ProgramDatabaseFile="$(IntDir)\uix86.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\uix86.map"
- BaseAddress="0x40000000"
- ImportLibrary="$(IntDir)\uix86.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="..\..\build\ui_debug"
- IntermediateDirectory="..\..\build\ui_debug"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Debug/ui.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;UI_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
- BasicRuntimeChecks="3"
- RuntimeLibrary="1"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\ui.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="true"
- DebugInformationFormat="4"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="$(OutDir)\uix86_new.dll"
- LinkIncremental="2"
- SuppressStartupBanner="true"
- GenerateDebugInformation="true"
- ProgramDatabaseFile="$(IntDir)\ui.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\uix86_new.map"
- BaseAddress="0x40000000"
- ImportLibrary="$(IntDir)\uix86_new.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="..\..\build\ui_release"
- IntermediateDirectory="..\..\build\ui_release"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Release/ui.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;UI_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
- StringPooling="true"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="true"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\ui.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- WarningLevel="3"
- SuppressStartupBanner="true"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="$(OutDir)\uix86_new.dll"
- LinkIncremental="1"
- SuppressStartupBanner="true"
- ProgramDatabaseFile="$(IntDir)\uix86_new.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\uix86_new.map"
- BaseAddress="0x40000000"
- ImportLibrary="$(IntDir)\uix86_new.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Debug TA|Win32"
- OutputDirectory="..\..\build\ui_debug_ta"
- IntermediateDirectory="..\..\build\ui_debug_ta"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="true"
- SuppressStartupBanner="true"
- TargetEnvironment="1"
- TypeLibraryName=".\Debug_TA/ui.tlb"
- HeaderFileName=""
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;UI_EXPORTS;MISSIONPACK;_CRT_SECURE_NO_DEPRECATE"
- BasicRuntimeChecks="3"
- RuntimeLibrary="1"
- UsePrecompiledHeader="0"
- PrecompiledHeaderFile="$(IntDir)\ui.pch"
- AssemblerListingLocation="$(IntDir)\"
- ObjectFile="$(IntDir)\"
- ProgramDataBaseFileName="$(IntDir)\"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="true"
- DebugInformationFormat="4"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="$(OutDir)\uix86.dll"
- LinkIncremental="2"
- SuppressStartupBanner="true"
- ModuleDefinitionFile=".\ui.def"
- GenerateDebugInformation="true"
- ProgramDatabaseFile="$(IntDir)\ui.pdb"
- GenerateMapFile="true"
- MapFileName="$(IntDir)\uix86.map"
- BaseAddress="0x40000000"
- ImportLibrary="$(IntDir)\uix86.lib"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
- >
- <File
- RelativePath="..\..\code\game\bg_lib.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;MISSIONPACK;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\bg_misc.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;MISSIONPACK;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\q_math.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\qcommon\q_shared.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\ui\ui_atoms.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;MISSIONPACK;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\ui\ui_gameinfo.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;MISSIONPACK;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\ui\ui_main.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;MISSIONPACK;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\ui\ui_players.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;MISSIONPACK;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\ui\ui_shared.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;MISSIONPACK;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\ui\ui_syscalls.c"
- >
- <FileConfiguration
- Name="Release TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;UI_EXPORTS;MISSIONPACK;"
- BasicRuntimeChecks="3"
- BrowseInformation="1"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl"
- >
- <File
- RelativePath="..\..\code\game\bg_public.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\ui\keycodes.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\..\ui\menudef.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\q_shared.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\game\surfaceflags.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\cgame\tr_types.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\ui\ui_local.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\ui\ui_public.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\code\ui\ui_shared.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="Resource Files"
- >
- <File
- RelativePath=".\ui.def"
- >
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/engine/misc/nsis/Makefile b/engine/misc/nsis/Makefile
deleted file mode 100644
index 4405f0f..0000000
--- a/engine/misc/nsis/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-VERSION=1.35_SVN
-RELEASE=0
-
-all: ioquake3-$(VERSION)-$(RELEASE).x86.exe
-
-ioquake3.nsi: ioquake3.nsi.in
- sed 's/XXXVERSIONXXX/$(VERSION)/;s/XXXRELEASEXXX/$(RELEASE)/' < $< > $@
-
-ioquake3-$(VERSION)-$(RELEASE).x86.exe: ioquake3.nsi
- makensis ioquake3.nsi
-
-clean:
- rm -rf *.exe ioquake3.nsi
-
-.PHONY: all clean
diff --git a/engine/misc/nsis/ioquake3-q3a.nsi b/engine/misc/nsis/ioquake3-q3a.nsi
deleted file mode 100644
index 9975609..0000000
--- a/engine/misc/nsis/ioquake3-q3a.nsi
+++ /dev/null
@@ -1,248 +0,0 @@
-; NSIS description file for quake3 data file installer
-
-SetCompressor lzma
-
-!define NAME "Quake III Arena"
-!define FSNAME "ioquake3-q3a"
-!define VERSION "1.32"
-!define RELEASE "1"
-
-!define MULTIUSER_MUI
-!define MULTIUSER_EXECUTIONLEVEL Highest
-!define MULTIUSER_INSTALLMODE_COMMANDLINE
-!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY "Software\ioquake3"
-!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME "Install_Mode"
-!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY "Software\ioquake3"
-!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME "Install_Dir"
-!define MULTIUSER_INSTALLMODE_INSTDIR "ioquake3"
-!include MultiUser.nsh
-
-!include "FileFunc.nsh"
-Var q3a_pak0
-Var q3ta_pak0
-
-!include "MUI2.nsh"
-!define MUI_ICON "../quake3.ico"
-
-; The name of the installer
-Name "${NAME}-${VERSION} for ioquake3"
-
-; The file to write
-OutFile "${FSNAME}-${VERSION}-${RELEASE}.x86.exe"
-
-;Interface Settings
-
-!define MUI_ABORTWARNING
-
-;--------------------------------
-;Pages
-
-!insertmacro MULTIUSER_PAGE_INSTALLMODE
-!insertmacro MUI_PAGE_LICENSE "id_patch_pk3s_Q3A_EULA.txt"
-!insertmacro MUI_PAGE_COMPONENTS
-!insertmacro MUI_PAGE_DIRECTORY
-!insertmacro MUI_PAGE_INSTFILES
-
-!insertmacro MUI_UNPAGE_CONFIRM
-!insertmacro MUI_UNPAGE_COMPONENTS
-!insertmacro MUI_UNPAGE_INSTFILES
-
-;--------------------------------
-;Languages
-
-!insertmacro MUI_LANGUAGE "English"
-
-;--------------------------------
-
-;--------------------------------
-;Multiuser stuff
-Function .onInit
- !insertmacro MULTIUSER_INIT
- StrCpy $q3a_pak0 "notfound"
- ReadRegStr $0 SHCTX "Software\ioquake3" ${MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME}
- IfErrors 0 oninitdone
- MessageBox MB_OK "You need to install the ioquake3 engine first"
- Abort
- oninitdone:
-FunctionEnd
-
-Function un.onInit
- !insertmacro MULTIUSER_UNINIT
-FunctionEnd
-
-; The stuff to install
-Section "${NAME}" sec_q3a
-
- SectionIn RO
-
- SetOutPath $INSTDIR
- File "id_patch_pk3s_Q3A_EULA.txt"
-
- SetOutPath "$INSTDIR\baseq3"
- File "baseq3/pak1.pk3"
- File "baseq3/pak2.pk3"
- File "baseq3/pak3.pk3"
- File "baseq3/pak4.pk3"
- File "baseq3/pak5.pk3"
- File "baseq3/pak6.pk3"
- File "baseq3/pak7.pk3"
- File "baseq3/pak8.pk3"
-
- ; Write the uninstall keys for Windows
- WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${FSNAME}" "DisplayName" "${NAME}"
- WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${FSNAME}" "UninstallString" '"$INSTDIR\uninstall-${FSNAME}.exe"'
- WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${FSNAME}" "NoModify" 1
- WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${FSNAME}" "NoRepair" 1
- WriteUninstaller "uninstall-${FSNAME}.exe"
-
-SectionEnd
-
-Section /o "${NAME} CDROM" sec_q3acd
- AddSize 468992
- q3apak0retry:
- ClearErrors
- StrCmp $q3a_pak0 "notfound" 0 q3apak0copy
- call findq3acd
- q3apak0copy:
- CopyFiles $q3a_pak0 "$INSTDIR\baseq3"
- IfErrors 0 q3apak0done
- MessageBox MB_RETRYCANCEL "Copying the Quake III Arena pak0.pk3 file failed. Make sure the correct CD is in the drive" IDRETRY q3apak0retry IDCANCEL q3apak0cancel
- goto q3apak0done
- q3apak0cancel:
- Abort
- q3apak0done:
-SectionEnd
-
-Function findq3acd
- StrCpy $q3a_pak0 "notfound"
- ${GetDrives} "CDROM" "findq3acd_cb"
-FunctionEnd
-
-Function findq3acd_cb
- StrCpy $R1 "$9baseq3\pak0.pk3"
- IfFileExists $R1 q3acd_cb_found 0
- StrCpy $R1 "$9quake3\baseq3\pak0.pk3"
- IfFileExists $R1 0 q3acd_cb_done
-q3acd_cb_found:
- StrCpy $q3a_pak0 $R1
- StrCpy $0 StopGetDrives
-
-q3acd_cb_done:
- Push $0
-FunctionEnd
-
-Section "Quake III Team Arena" sec_q3ta
-
- SetOutPath "$INSTDIR\missionpack"
-
- File "missionpack/pak1.pk3"
- File "missionpack/pak2.pk3"
- File "missionpack/pak3.pk3"
-
- CreateShortCut "$SMPROGRAMS\ioquake3\Team Arena.lnk" "$INSTDIR\ioquake3.x86.exe" "+set fs_game missionpack" "$INSTDIR\ioquake3.x86.exe" 0 "" "" "Team Arena"
-
-SectionEnd
-
-Section /o "Quake III Team Arena CDROM" sec_q3tacd
- AddSize 344064
- q3tapak0retry:
- ClearErrors
- StrCmp $q3ta_pak0 "notfound" 0 q3tapak0copy
- call findq3tacd
- q3tapak0copy:
- CopyFiles $q3ta_pak0 "$INSTDIR\missionpack"
- IfErrors 0 q3tapak0done
- MessageBox MB_RETRYCANCEL "Copying the Quake III TeamArena pak0.pk3 file failed. Make sure the correct CD is in the drive" IDRETRY q3tapak0retry IDCANCEL q3tapak0cancel
- goto q3tapak0done
- q3tapak0cancel:
- Abort
- q3tapak0done:
-SectionEnd
-
-Function findq3tacd
- StrCpy $q3ta_pak0 "notfound"
- ${GetDrives} "CDROM" "findq3tacd_cb"
-FunctionEnd
-
-Function findq3tacd_cb
- StrCpy $R1 "$9Setup\missionpack\pak0.pk3"
- IfFileExists $R1 0 q3tacd_cb_done
- StrCpy $q3ta_pak0 $R1
- StrCpy $0 StopGetDrives
-q3tacd_cb_done:
- Push $0
-FunctionEnd
-
-;--------------------------------
-
-; Uninstaller
-
-Section "un.Quake III Arena and Team Arena" sec_un_q3a
-
- SectionIn RO
-
- ; Remove registry keys
- DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${FSNAME}"
-
- ; Remove files and uninstaller
- Delete $INSTDIR\baseq3\pak1.pk3
- Delete $INSTDIR\baseq3\pak2.pk3
- Delete $INSTDIR\baseq3\pak3.pk3
- Delete $INSTDIR\baseq3\pak4.pk3
- Delete $INSTDIR\baseq3\pak5.pk3
- Delete $INSTDIR\baseq3\pak6.pk3
- Delete $INSTDIR\baseq3\pak7.pk3
- Delete $INSTDIR\baseq3\pak8.pk3
-
- Delete $INSTDIR\missionpack\pak1.pk3
- Delete $INSTDIR\missionpack\pak2.pk3
- Delete $INSTDIR\missionpack\pak3.pk3
-
- Delete $INSTDIR\uninstall-${FSNAME}.exe
-
- Delete "$INSTDIR\id_patch_pk3s_Q3A_EULA.txt"
-
- ; Remove shortcuts, if any
- Delete "$SMPROGRAMS\ioquake3\Team Arena.lnk"
-
- ; Remove directories used
- RMDir "$SMPROGRAMS\ioquake3"
- RMDir "$INSTDIR\baseq3"
- RMDir "$INSTDIR\missionpack"
- RMDir "$INSTDIR"
-
-SectionEnd
-
-Section "un.CDROM Data" sec_un_q3a_cd
- Delete $INSTDIR\baseq3\pak0.pk3
- Delete $INSTDIR\missionpack\pak0.pk3
- RMDir "$INSTDIR\baseq3"
- RMDir "$INSTDIR\missionpack"
- RMDir "$INSTDIR"
-SectionEnd
-
-Function .onSelChange
- ${If} ${SectionIsSelected} ${sec_q3acd}
- Call findq3acd
- StrCmp $q3a_pak0 "notfound" 0 +2
- MessageBox MB_OK "Quake III Arena CD not found. Make sure it is in the drive otherwise installation will fail"
- ${EndIf}
- ${If} ${SectionIsSelected} ${sec_q3tacd}
- Call findq3tacd
- StrCmp $q3ta_pak0 "notfound" 0 +2
- MessageBox MB_OK "Quake III TeamArena CD not found. Make sure it is in the drive otherwise installation will fail"
- ${EndIf}
-FunctionEnd
-
-
-LangString DESC_q3a ${LANG_ENGLISH} "Install official Quake III Arena Point Release 1.32 data files. Note that the data files alone are useless. You need to also install the Quake III Arena base assets (pak0.pk3) from the game's CD-ROM."
-LangString DESC_q3acd ${LANG_ENGLISH} "Install the Quake III Arena base assets (pak0.pk3) from the game's CD-ROM."
-LangString DESC_q3ta ${LANG_ENGLISH} "Install official Quake III Team Arena Point Release 1.32 data files. Note that the data files alone are useless. You need to also install the Quake III Team Arena base assets (pak0.pk3) from the game's CD-ROM."
-LangString DESC_q3tacd ${LANG_ENGLISH} "Install the Quake III Team Arena base assets (pak0.pk3) from the game's CD-ROM."
-
-!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
- !insertmacro MUI_DESCRIPTION_TEXT ${sec_q3a} $(DESC_q3a)
- !insertmacro MUI_DESCRIPTION_TEXT ${sec_q3acd} $(DESC_q3acd)
- !insertmacro MUI_DESCRIPTION_TEXT ${sec_q3ta} $(DESC_q3ta)
- !insertmacro MUI_DESCRIPTION_TEXT ${sec_q3tacd} $(DESC_q3tacd)
-!insertmacro MUI_FUNCTION_DESCRIPTION_END
diff --git a/engine/misc/nsis/ioquake3-q3ctc.nsi b/engine/misc/nsis/ioquake3-q3ctc.nsi
deleted file mode 100644
index e4f27e3..0000000
--- a/engine/misc/nsis/ioquake3-q3ctc.nsi
+++ /dev/null
@@ -1,140 +0,0 @@
-; sample NSIS description file for a ioquake3 mod installer
-
-!define NAME "Catch the Chicken"
-!define FSNAME "ioquake3-q3ctc"
-!define VERSION "1.4"
-!define RELEASE "1"
-!define MODDIR "q3ctc"
-!define PUBLISHER "The ioquake3 Team"
-!define URL "http://ioquake3.org/"
-; uncomment if the mod works without baseq3
-;!define STANDALONE
-
-!define MUI_ICON "../quake3.ico"
-
-!macro FILES
- File ctc0.pk3
- File ctc1.pk3
- File description.txt
- File gfx/chicken.jpg
- File gfx/egggun.jpg
- File gfx/q3ctc.gif
- File q3ctc.config
- File q3ctcteam.config
- File readme.html
- File readmeFirst.txt
-!macroend
-
-; no need to edit below in theory
-
-SetCompressor lzma
-
-!define MULTIUSER_MUI
-!define MULTIUSER_EXECUTIONLEVEL Highest
-!define MULTIUSER_INSTALLMODE_COMMANDLINE
-!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY "Software\ioquake3"
-!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME "Install_Mode"
-!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY "Software\ioquake3"
-!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME "Install_Dir"
-!define MULTIUSER_INSTALLMODE_INSTDIR "ioquake3"
-!include MultiUser.nsh
-
-!include "FileFunc.nsh"
-
-!include "MUI2.nsh"
-
-; The name of the installer
-Name "${NAME}-${VERSION} for ioquake3"
-
-; The file to write
-OutFile "${FSNAME}-${VERSION}-${RELEASE}.x86.exe"
-
-;Interface Settings
-
-!define MUI_ABORTWARNING
-
-;--------------------------------
-;Pages
-
-!insertmacro MULTIUSER_PAGE_INSTALLMODE
-;!insertmacro MUI_PAGE_LICENSE "id_patch_pk3s_Q3A_EULA.txt"
-!define MUI_COMPONENTSPAGE_NODESC
-!insertmacro MUI_PAGE_COMPONENTS
-!insertmacro MUI_PAGE_DIRECTORY
-!insertmacro MUI_PAGE_INSTFILES
-
-!insertmacro MUI_UNPAGE_CONFIRM
-!insertmacro MUI_UNPAGE_INSTFILES
-
-;--------------------------------
-;Languages
-
-!insertmacro MUI_LANGUAGE "English"
-
-;--------------------------------
-
-;--------------------------------
-;Multiuser stuff
-Function .onInit
- !insertmacro MULTIUSER_INIT
- ReadRegStr $0 SHCTX "Software\ioquake3" ${MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME}
- IfErrors 0 oninitdone
- MessageBox MB_OK "You need to install the ioquake3 engine first"
- Abort
- oninitdone:
-FunctionEnd
-
-Function un.onInit
- !insertmacro MULTIUSER_UNINIT
-FunctionEnd
-
-; The stuff to install
-Section "${NAME}" sec_base
-
- SectionIn RO
-
- SetOutPath $INSTDIR
-
- SetOutPath "$INSTDIR\${MODDIR}"
-
- !insertmacro FILES
-
- ; Write the uninstall keys for Windows
- WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${FSNAME}" "DisplayName" "${NAME}"
- WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${FSNAME}" "DisplayVersion" "${VERSION}-${RELEASE}"
- WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${FSNAME}" "Publisher" "${PUBLISHER}"
- WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${FSNAME}" "URLInfoAbout" "${URL}"
- WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${FSNAME}" "UninstallString" '"$INSTDIR\uninstall-${FSNAME}.exe"'
- WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${FSNAME}" "NoModify" 1
- WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${FSNAME}" "NoRepair" 1
-
- WriteUninstaller "uninstall-${FSNAME}.exe"
-
-!ifdef STANDALONE
-!define ARGS "+set com_standalone 1 "
-!else
-!define ARGS ""
-!endif
- CreateShortCut "$SMPROGRAMS\ioquake3\${NAME}.lnk" "$INSTDIR\ioquake3.x86.exe" "${ARGS}+set fs_game ${MODDIR}" "$INSTDIR\ioquake3.x86.exe" 0 "" "" "${NAME}"
-
-SectionEnd
-
-Section "Uninstall"
-
- ; Remove registry keys
- DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${FSNAME}"
-
- ; Remove files and uninstaller
- Delete $INSTDIR\${MODDIR}\*
-
- Delete $INSTDIR\uninstall-${FSNAME}.exe
-
- ; Remove shortcuts, if any
- Delete "$SMPROGRAMS\ioquake3\${NAME}.lnk"
-
- ; Remove directories used
- RMDir "$SMPROGRAMS\ioquake3"
- RMDir "$INSTDIR\${MODDIR}"
- RMDir "$INSTDIR"
-
-SectionEnd
diff --git a/engine/misc/nsis/ioquake3.nsi.in b/engine/misc/nsis/ioquake3.nsi.in
deleted file mode 100644
index ddf2090..0000000
--- a/engine/misc/nsis/ioquake3.nsi.in
+++ /dev/null
@@ -1,186 +0,0 @@
-; NSIS description file for ioquake3 installer
-;
-; EDIT WITH CARE!
-;
-; This file is used to automatically build the installers in the
-; openSUSE build service, don't break this!
-;
-; you have to copy SDL.dll and libcurl-4.dll here manually
-
-!define MULTIUSER_MUI
-!define MULTIUSER_EXECUTIONLEVEL Highest
-!define MULTIUSER_INSTALLMODE_COMMANDLINE
-!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY "Software\ioquake3"
-!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME "Install_Mode"
-!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY "Software\ioquake3"
-!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME "Install_Dir"
-!define MULTIUSER_INSTALLMODE_INSTDIR "ioquake3"
-!include MultiUser.nsh
-
-!include "MUI2.nsh"
-!define MUI_ICON "../quake3.ico"
-
-; The name of the installer
-Name "ioquake3"
-
-; The file to write
-OutFile "ioquake3-XXXVERSIONXXX-XXXRELEASEXXX.x86.exe"
-
-; The default installation directory
-; set by Multiuser.nsh
-;InstallDir $PROGRAMFILES\ioquake3
-
-; Registry key to check for directory (so if you install again, it will
-; overwrite the old one automatically)
-; handled by Multiuser.nsh
-;InstallDirRegKey HKLM "Software\ioquake3" "Install_Dir"
-
-;--------------------------------
-;Interface Settings
-
-!define MUI_ABORTWARNING
-
-;--------------------------------
-;Pages
-
-!insertmacro MULTIUSER_PAGE_INSTALLMODE
-#!insertmacro MUI_PAGE_LICENSE "${NSISDIR}\Docs\Modern UI\License.txt"
-!insertmacro MUI_PAGE_COMPONENTS
-!insertmacro MUI_PAGE_DIRECTORY
-!insertmacro MUI_PAGE_INSTFILES
-
-!insertmacro MUI_UNPAGE_CONFIRM
-!insertmacro MUI_UNPAGE_INSTFILES
-
-;--------------------------------
-;Languages
-
-!insertmacro MUI_LANGUAGE "English"
-
-;--------------------------------
-
-;--------------------------------
-;Multiuser stuff
-Function .onInit
- !insertmacro MULTIUSER_INIT
-FunctionEnd
-
-Function un.onInit
- !insertmacro MULTIUSER_UNINIT
-FunctionEnd
-
-; The stuff to install
-Section "ioquake3 (required)"
-
- SectionIn RO
-
- ; Set output path to the installation directory.
- SetOutPath $INSTDIR
-
- ; Put file there
- File "../../build/release-mingw32-x86/ioq3ded.x86.exe"
- File "../../build/release-mingw32-x86/ioquake3.x86.exe"
- File "../../COPYING.txt"
- File "../../README.txt"
- File "../../id-readme.txt"
- File "../../voip-readme.txt"
-
- SetOutPath "$INSTDIR\baseq3"
- File "../../build/release-mingw32-x86/baseq3/cgamex86.dll"
- File "../../build/release-mingw32-x86/baseq3/qagamex86.dll"
- File "../../build/release-mingw32-x86/baseq3/uix86.dll"
- SetOutPath "$INSTDIR\missionpack"
- File "../../build/release-mingw32-x86/missionpack/cgamex86.dll"
- File "../../build/release-mingw32-x86/missionpack/qagamex86.dll"
- File "../../build/release-mingw32-x86/missionpack/uix86.dll"
-
- ; Write the installation path into the registry
- WriteRegStr SHCTX "Software\ioquake3" ${MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME} "$INSTDIR"
- WriteRegStr SHCTX "Software\ioquake3" ${MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME} "$MultiUser.InstallMode"
-
- ; Write the uninstall keys for Windows
- WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\ioquake3" "DisplayName" "ioquake3"
- WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\ioquake3" "UninstallString" '"$INSTDIR\uninstall.exe"'
- WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\ioquake3" "NoModify" 1
- WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\ioquake3" "NoRepair" 1
- WriteUninstaller "uninstall.exe"
-
-SectionEnd
-
-; Optional section (can be disabled by the user)
-Section "Start Menu Shortcuts"
-
- CreateDirectory "$SMPROGRAMS\ioquake3"
- CreateShortCut "$SMPROGRAMS\ioquake3\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0
- CreateShortCut "$SMPROGRAMS\ioquake3\ioquake3.lnk" "$INSTDIR\ioquake3.x86.exe" "" "$INSTDIR\ioquake3.x86.exe" 0
-
-SectionEnd
-
-Section "SDL.dll"
-
- SetOutPath $INSTDIR
-
- File "SDL.dll"
-
-SectionEnd
-
-Section "libcurl"
-
- SetOutPath $INSTDIR
-
- File "libcurl-4.dll"
-
-SectionEnd
-
-Section "OpenAL-Soft library"
-
- SetOutPath $INSTDIR
-
- File "OpenAL32.dll"
-
-SectionEnd
-
-;--------------------------------
-
-; Uninstaller
-
-Section "Uninstall"
-
- ; Remove registry keys
- DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\ioquake3"
- DeleteRegKey SHCTX "Software\ioquake3"
-
- ; Remove files and uninstaller
- Delete $INSTDIR\baseq3\cgamex86.dll
- Delete $INSTDIR\baseq3\qagamex86.dll
- Delete $INSTDIR\baseq3\uix86.dll
- Delete $INSTDIR\missionpack\cgamex86.dll
- Delete $INSTDIR\missionpack\qagamex86.dll
- Delete $INSTDIR\missionpack\uix86.dll
- Delete $INSTDIR\ioquake3.x86.exe
- Delete $INSTDIR\ioq3ded.x86.exe
-
- Delete $INSTDIR\COPYING.txt
- Delete $INSTDIR\README.txt
- Delete $INSTDIR\id-readme.txt
- Delete $INSTDIR\voip-readme.txt
-
- Delete $INSTDIR\SDL.dll
-
- Delete $INSTDIR\libcurl-4.dll
-
- Delete $INSTDIR\OpenAL32.dll
-
- Delete $INSTDIR\uninstall.exe
-
- ; Remove shortcuts, if any
- Delete "$SMPROGRAMS\ioquake3\Uninstall.lnk"
- Delete "$SMPROGRAMS\ioquake3\ioquake3.lnk"
-
- ; Remove directories used
- RMDir "$SMPROGRAMS\ioquake3"
- RMDir "$INSTDIR\baseq3"
- RMDir "$INSTDIR\missionpack"
- RMDir "$INSTDIR"
-
-SectionEnd
diff --git a/engine/misc/quake3-tango.png b/engine/misc/quake3-tango.png
deleted file mode 100644
index ccd3fdd..0000000
Binary files a/engine/misc/quake3-tango.png and /dev/null differ
diff --git a/engine/misc/quake3-tango.xcf b/engine/misc/quake3-tango.xcf
deleted file mode 100644
index 6d9844c..0000000
Binary files a/engine/misc/quake3-tango.xcf and /dev/null differ
diff --git a/engine/misc/quake3.icns b/engine/misc/quake3.icns
deleted file mode 100644
index 30e3b67..0000000
Binary files a/engine/misc/quake3.icns and /dev/null differ
diff --git a/engine/misc/quake3.ico b/engine/misc/quake3.ico
deleted file mode 100644
index 6106c27..0000000
Binary files a/engine/misc/quake3.ico and /dev/null differ
diff --git a/engine/misc/quake3.png b/engine/misc/quake3.png
deleted file mode 100644
index 94010a7..0000000
Binary files a/engine/misc/quake3.png and /dev/null differ
diff --git a/engine/misc/quake3.svg b/engine/misc/quake3.svg
deleted file mode 100644
index 24c4b9f..0000000
--- a/engine/misc/quake3.svg
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.0"
- width="64"
- height="64"
- id="svg1306">
- <defs
- id="defs1308">
- <linearGradient
- id="linearGradient2180">
- <stop
- style="stop-color:#ff0000;stop-opacity:1"
- offset="0"
- id="stop2182" />
- <stop
- style="stop-color:#590000;stop-opacity:1"
- offset="1"
- id="stop2184" />
- </linearGradient>
- <linearGradient
- x1="14.860399"
- y1="19.054131"
- x2="15.042735"
- y2="59"
- id="linearGradient2190"
- xlink:href="#linearGradient2180"
- gradientUnits="userSpaceOnUse" />
- <linearGradient
- x1="14.860399"
- y1="19.054131"
- x2="15.042735"
- y2="59"
- id="linearGradient2194"
- xlink:href="#linearGradient2180"
- gradientUnits="userSpaceOnUse" />
- <linearGradient
- x1="32"
- y1="64.091171"
- x2="32"
- y2="0"
- id="linearGradient3077"
- xlink:href="#linearGradient2180"
- gradientUnits="userSpaceOnUse" />
- </defs>
- <g
- id="layer1">
- <g
- id="g1327">
- <path
- d="M 34.538626,32.090265 L 32.538627,64 L 30.538626,32 L 32.538627,0 L 34.538626,32.090265 z "
- style="opacity:1;fill:url(#linearGradient3077);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5261631;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="path1329" />
- <path
- d="M 28.059562,59 L 25.612281,34.036677 C 25.612281,34.036677 2.1281775,31.218199 2.0010765,25.064561 C 1.9155925,21.016997 6.9421265,19.095215 9.6946005,19.095215 C 12.000721,19.095215 4.2082195,19.143464 4.1713675,24.287073 C 4.1405475,28.679913 29.3599,30.346963 29.3599,30.346963 L 28.059562,59 z "
- style="fill:url(#linearGradient2190);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="path1307" />
- <path
- d="M 36.940438,59 L 39.387719,34.036677 C 39.387719,34.036677 62.871823,31.218199 62.998924,25.064561 C 63.084408,21.016997 58.057873,19.095215 55.305399,19.095215 C 52.999279,19.095215 60.79178,19.143464 60.828632,24.287073 C 60.859452,28.679913 35.6401,30.346963 35.6401,30.346963 L 36.940438,59 z "
- style="fill:url(#linearGradient2194);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="path2192" />
- </g>
- </g>
-</svg>
diff --git a/engine/misc/setup/MacOSX/SLA-dmg.sh b/engine/misc/setup/MacOSX/SLA-dmg.sh
deleted file mode 100755
index af268f3..0000000
--- a/engine/misc/setup/MacOSX/SLA-dmg.sh
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/bin/bash
-#
-# This script appends the text from Q3A_EULA.txt to a .dmg as a SLA resource
-#
-# usage is './SLA-dmg.sh /path/to/Q3A_EULA.txt /path/to/ioquake3.dmg'
-#
-
-if [ "x$1" = "x" ] || [ "x$2" = "x" ]; then
- echo "usage: ./SLA-dmg.sh /path/to/Q3A_EULA.txt /path/to/ioquake3.dmg"
- exit 1;
-fi
-
-if [ ! -r $1 ]; then
- echo "$1 is not a readable Q3A_EULA.txt file"
- exit 1;
-fi
-if [ ! -w $2 ]; then
- echo "$2 is not writable .dmg file"
- exit 1;
-fi
-touch tmp.r
-if [ ! -w tmp.r ]; then
- echo "Could not create temporary file tmp.r for writing"
- exit 1;
-fi
-
-echo "
-data 'LPic' (5000) {
- \$\"0002 0011 0003 0001 0000 0000 0002 0000\"
- \$\"0008 0003 0000 0001 0004 0000 0004 0005\"
- \$\"0000 000E 0006 0001 0005 0007 0000 0007\"
- \$\"0008 0000 0047 0009 0000 0034 000A 0001\"
- \$\"0035 000B 0001 0020 000C 0000 0011 000D\"
- \$\"0000 005B 0004 0000 0033 000F 0001 000C\"
- \$\"0010 0000 000B 000E 0000\"
-};
-
-data 'TEXT' (5002, \"English\") {
-" > tmp.r
-
-sed -e 's/"/\\"/g' -e 's/\(.*\)$/"\1\\n"/g' $1 >> tmp.r
-
-echo "
-};
-
-resource 'STR#' (5002, \"English\") {
- {
- \"English\",
- \"Agree\",
- \"Disagree\",
- \"Print\",
- \"Save...\",
- \"IMPORTANT - Read this License Agreement carefully before clicking on \"
- \"the \\\"Agree\\\" button. By clicking on the \\\"Agree\\\" button, you agree \"
- \"to be bound by the terms of the License Agreement.\",
- \"Software License Agreement\",
- \"This text cannot be saved. This disk may be full or locked, or the \"
- \"file may be locked.\",
- \"Unable to print. Make sure you have selected a printer.\"
- }
-};
-" >> tmp.r
-
-hdiutil convert -format UDCO -o tmp.dmg $2 || exit 1
-hdiutil unflatten tmp.dmg || exit 1
-/Developer/Tools/Rez /Developer/Headers/FlatCarbon/*.r tmp.r -a -o tmp.dmg \
- || exit 1
-hdiutil flatten tmp.dmg || exit 1
-hdiutil internet-enable -yes tmp.dmg || exit 1
-mv tmp.dmg $2 || (echo "Could not copy tmp.dmg to $2" && exit 1)
-rm tmp.dmg
-rm tmp.r
-echo "SLA $1 successfully added to $2"
diff --git a/engine/misc/setup/Makefile b/engine/misc/setup/Makefile
deleted file mode 100644
index 286831c..0000000
--- a/engine/misc/setup/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-VERSION=1.34
-RELEASE=svn
-
-all:
- VERSION=$(VERSION) RELEASE=$(RELEASE) ./doit
-
-sign:
- for i in *.run; do \
- gpg -bao $$i.asc $$i; \
- done
-
-clean:
- rm -rf *.run image
-
-.PHONY: all sign clean
diff --git a/engine/misc/setup/Solaris_pkg.sh b/engine/misc/setup/Solaris_pkg.sh
deleted file mode 100644
index 650d285..0000000
--- a/engine/misc/setup/Solaris_pkg.sh
+++ /dev/null
@@ -1,180 +0,0 @@
-#!/bin/bash
-
-# Source directory
-MOUNT_DIR="../.."
-
-# Solaris stuff
-PLATFORM=`uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]'`
-if [ "X${PLATFORM}" != "Xsunos" ]; then
- echo "Unsupported platform! Must run this script on Solaris host!" ; exit 127
-fi
-
-
-if [ "X`uname -m`" = "Xi86pc" ]; then
- ARCH=i386
-else
- ARCH=sparc
-fi
-
-# Packages
-PKG_SOLARIS_NAME=ioquake3
-PKG_DATA_NAME=ioquake3d
-PKG_DEMO_NAME=ioquake3m
-BUILD_DATE="`/usr/bin/date '+%Y%m%d%H%M%S'`"
-SVNVERSION=/usr/local/bin/svnversion
-BUILD_VERSION="1.36_SVN"
-if [ -x "$SVNVERSION" ]; then
- SVN_BANNER=`$SVNVERSION ${MOUNT_DIR}|sed -e 's/S$//' -e 's/M$//' `
- BUILD_VERSION="${BUILD_VERSION}${SVN_BANNER}"
-fi
-PKG_VERSION="`date '+%Y%m%d%H%M'`"
-PKG_MAINT_ID="quake at cojot.name"
-SOLARIS_PKGFILE="${PKG_SOLARIS_NAME}-${BUILD_VERSION}-${PKG_VERSION}-${ARCH}.pkg"
-DATA_PKGFILE="${PKG_DATA_NAME}-${BUILD_VERSION}-${PKG_VERSION}.pkg"
-DEMO_PKGFILE="${PKG_DEMO_NAME}-${BUILD_VERSION}-${PKG_VERSION}.pkg"
-
-# build directories
-BUILD_DIR="${MOUNT_DIR}/build/release-${PLATFORM}-${ARCH}"
-PKG_SRC_DIR="${MOUNT_DIR}/misc/setup/pkg/${PKG_SOLARIS_NAME}"
-PKG_BUILD_DIR="/tmp/ioquake3-build/${PKG_SOLARIS_NAME}-${BUILD_VERSION}"
-PKG_EXTRA_BUILD_DIR="/usr/local/src/quake3-data/ioquake3/quake3"
-PKG_DATA_SRC_DIR="${MOUNT_DIR}/misc/setup/pkg/${PKG_DATA_NAME}"
-PKG_DATA_BUILD_DIR="/usr/local/src/quake3-data/ioquake3d/quake3"
-PKG_DEMO_SRC_DIR="${MOUNT_DIR}/misc/setup/pkg/${PKG_DEMO_NAME}"
-PKG_DEMO_BUILD_DIR="/usr/local/src/quake3-data/ioquake3m/quake3"
-
-# Tools
-RM="/usr/bin/rm"
-TOUCH="/usr/bin/touch"
-SED="/usr/bin/sed"
-CAT="/usr/bin/cat"
-NAWK="/usr/bin/nawk"
-MKDIR="gmkdir -v -p"
-INSTALL_BIN="ginstall -D -m 755"
-INSTALL_DATA="ginstall -D -m 644"
-PKGPROTO="/usr/bin/pkgproto"
-PKGMK="/usr/bin/pkgmk"
-PKGTRANS="/usr/bin/pkgtrans"
-
-#############################################################################
-# SOLARIS PACKAGE
-#############################################################################
-
-if [ -d ${BUILD_DIR} ]; then
- if [ ! -d ${BUILD_DIR}/pkg ]; then
- ${MKDIR} ${BUILD_DIR}/pkg
- fi
- echo "Building ${BUILD_DIR}/pkg/${SOLARIS_PKGFILE}"
- ${RM} -f ${BUILD_DIR}/pkg/${SOLARIS_PKGFILE}
- ${TOUCH} ${BUILD_DIR}/pkg/${SOLARIS_PKGFILE}
- ${SED} -e "/VERSION=/s/.*/VERSION=${BUILD_VERSION}-${PKG_VERSION}/" \
- < ${PKG_SRC_DIR}/pkginfo.template \
- > ${PKG_SRC_DIR}/pkginfo
- ${CAT} ${PKG_SRC_DIR}/prototype.template > ${PKG_SRC_DIR}/prototype
-
- ${INSTALL_DATA} ${MOUNT_DIR}/COPYING.txt ${PKG_SRC_DIR}/copyright
- for EXEC_READ in README id-readme.txt
- do
- if [ -f ${MOUNT_DIR}/${EXEC_READ} ]; then
- ${INSTALL_DATA} ${MOUNT_DIR}/${EXEC_READ} ${PKG_BUILD_DIR}/${EXEC_READ}
- fi
- done
-
- for EXEC_BIN in ioq3ded ioquake3-smp ioquake3
- do
- if [ -f ${BUILD_DIR}/${EXEC_BIN}.${ARCH} ]; then
- ${INSTALL_BIN} ${BUILD_DIR}/${EXEC_BIN}.${ARCH} ${PKG_BUILD_DIR}/${EXEC_BIN}.${ARCH}
- fi
- done
-
- for EXEC_SH in ioq3ded.sh ioquake3.sh
- do
- if [ -f ${MOUNT_DIR}/misc/setup/pkg/${EXEC_SH} ]; then
- ${INSTALL_BIN} ${MOUNT_DIR}/misc/setup/pkg/${EXEC_SH} ${PKG_BUILD_DIR}/${EXEC_SH}
- fi
- done
-
- for EXEC_SO in cgamesparc.so qagamesparc.so uisparc.so cgamei386.so qagamei386.so uii386.so
- do
- if [ -f ${BUILD_DIR}/baseq3/${EXEC_SO} ]; then
- ${INSTALL_BIN} ${BUILD_DIR}/baseq3/${EXEC_SO} ${PKG_BUILD_DIR}/baseq3/${EXEC_SO}
- fi
- if [ -f ${BUILD_DIR}/missionpack/${EXEC_SO} ]; then
- ${INSTALL_BIN} ${BUILD_DIR}/missionpack/${EXEC_SO} ${PKG_BUILD_DIR}/missionpack/${EXEC_SO}
- fi
- done
-
- for EXEC_VM in cgame.qvm qagame.qvm ui.qvm
- do
- if [ -f ${BUILD_DIR}/baseq3/vm/${EXEC_VM} ]; then
- ${INSTALL_BIN} ${BUILD_DIR}/baseq3/vm/${EXEC_VM} ${PKG_BUILD_DIR}/baseq3/vm/${EXEC_VM}
- fi
- if [ -f ${BUILD_DIR}/missionpack/vm/${EXEC_VM} ]; then
- ${INSTALL_BIN} ${BUILD_DIR}/missionpack/vm/${EXEC_VM} ${PKG_BUILD_DIR}/missionpack/vm/${EXEC_VM}
- fi
- done
-
- ${PKGPROTO} ${PKG_BUILD_DIR}=quake3 ${PKG_EXTRA_BUILD_DIR}=quake3 | \
- ${NAWK} '{ print $1,$2,$3,$4 }' >> ${PKG_SRC_DIR}/prototype
- ${PKGMK} -o -p "${PKG_MAINT_ID}${BUILD_DATE}" \
- -b ${PKG_SRC_DIR} -f ${PKG_SRC_DIR}/prototype \
- -d /tmp -a ${ARCH} owner=root group=bin mode=0755
- ${PKGTRANS} -s /tmp ${BUILD_DIR}/pkg/${SOLARIS_PKGFILE} ${PKG_SOLARIS_NAME}
-
- echo "Building ${BUILD_DIR}/pkg/${DATA_PKGFILE}"
- ${RM} -f ${BUILD_DIR}/pkg/${DATA_PKGFILE}
- ${TOUCH} ${BUILD_DIR}/pkg/${DATA_PKGFILE}
- ${SED} -e "/VERSION=/s/.*/VERSION=${BUILD_VERSION}.${PKG_VERSION}/" \
- < ${PKG_DATA_SRC_DIR}/pkginfo.template \
- > ${PKG_DATA_SRC_DIR}/pkginfo
- ${CAT} ${PKG_DATA_SRC_DIR}/prototype.template > ${PKG_DATA_SRC_DIR}/prototype
-
- if [ -d ${MOUNT_DIR}/../webspace/include ]; then
- EULA_DIR=${MOUNT_DIR}/../webspace/include
- else
- if [ -d ${MOUNT_DIR}/../../webspace/include ]; then
- EULA_DIR=${MOUNT_DIR}/../../webspace/include
- fi
- fi
- if [ -f ${EULA_DIR}/id_patch_pk3s_Q3A_EULA.txt ]; then
- ${INSTALL_DATA} ${EULA_DIR}/id_patch_pk3s_Q3A_EULA.txt ${PKG_DATA_SRC_DIR}/copyright
- fi
-
- ${PKGPROTO} ${PKG_DATA_BUILD_DIR}=quake3 | \
- ${NAWK} '{ print $1,$2,$3,$4 }' >> ${PKG_DATA_SRC_DIR}/prototype
- ${PKGMK} -o -p "${PKG_MAINT_ID}${BUILD_DATE}" \
- -b ${PKG_DATA_SRC_DIR} -f ${PKG_DATA_SRC_DIR}/prototype \
- -d /tmp -a ${ARCH} owner=root group=bin mode=0755
- ${PKGTRANS} -s /tmp ${BUILD_DIR}/pkg/${DATA_PKGFILE} ${PKG_DATA_NAME}
-
- echo "Building ${BUILD_DIR}/pkg/${DEMO_PKGFILE}"
- ${RM} -f ${BUILD_DIR}/pkg/${DEMO_PKGFILE}
- ${TOUCH} ${BUILD_DIR}/pkg/${DEMO_PKGFILE}
- ${SED} -e "/VERSION=/s/.*/VERSION=${BUILD_VERSION}.${PKG_VERSION}/" \
- < ${PKG_DEMO_SRC_DIR}/pkginfo.template \
- > ${PKG_DEMO_SRC_DIR}/pkginfo
- ${CAT} ${PKG_DEMO_SRC_DIR}/prototype.template > ${PKG_DEMO_SRC_DIR}/prototype
-
- if [ -d ${MOUNT_DIR}/../webspace/include ]; then
- EULA_DIR=${MOUNT_DIR}/../webspace/include
- else
- if [ -d ${MOUNT_DIR}/../../webspace/include ]; then
- EULA_DIR=${MOUNT_DIR}/../../webspace/include
- fi
- fi
- if [ -f ${EULA_DIR}/id_patch_pk3s_Q3A_EULA.txt ]; then
- ${INSTALL_DEMO} ${EULA_DIR}/id_patch_pk3s_Q3A_EULA.txt ${PKG_DEMO_SRC_DIR}/copyright
- fi
-
- ${PKGPROTO} ${PKG_DEMO_BUILD_DIR}=quake3 | \
- ${NAWK} '{ print $1,$2,$3,$4 }' >> ${PKG_DEMO_SRC_DIR}/prototype
- ${PKGMK} -o -p "${PKG_MAINT_ID}${BUILD_DATE}" \
- -b ${PKG_DEMO_SRC_DIR} -f ${PKG_DEMO_SRC_DIR}/prototype \
- -d /tmp -a ${ARCH} owner=root group=bin mode=0755
- ${PKGTRANS} -s /tmp ${BUILD_DIR}/pkg/${DEMO_PKGFILE} ${PKG_DEMO_NAME}
-else
- echo "Directory ${BUILD_DIR} not found!"
- exit 1
-fi
-
-
diff --git a/engine/misc/setup/doit b/engine/misc/setup/doit
deleted file mode 100755
index 033d88c..0000000
--- a/engine/misc/setup/doit
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/bin/bash
-
-: ${MAKESELF:=/usr/share/loki-setup/makeself}
-: ${SETUPIMAGE:=/usr/share/loki-setup/image}
-
-: ${VERSION:=0.0_`date +%Y%m%d%H%M`}
-: ${RELEASE:=0}
-
-set -e
-set -x
-
-shopt -s nullglob
-
-rm -rf image
-mkdir image
-
-### loki-setup files
-cp -a $SETUPIMAGE/{setup.data,setup.sh} image/
-
-### splash
-rm -f image/setup.data/splash.xpm
-[ -e splash.xpm ] && cp splash.xpm image/setup.data/splash.xpm
-rm -f image/quake3.png
-cp ../quake3.png image/quake3.png
-
-### binaries
-topdir="../.."
-
-echo "changequote(\`[', \`]')dnl" > defines.m4
-echo "define(VERSION,$VERSION)dnl" >> defines.m4
-
-copystartscript()
-{
- local arch="$1"
- mkdir -p image/bin/Linux/$arch
- if [ "$arch" = x86_64 ]; then
- ln -s x86_64 image/bin/Linux/amd64
- elif [ "$arch" = ppc ]; then
- ln -s ppc image/bin/Linux/ppc64
- fi
- install -m 755 ioquake3.sh image/bin/Linux/$arch/ioquake3
- install -m 755 ioq3demo.sh image/bin/Linux/$arch/ioq3demo
-}
-
-archs=()
-for arch in $topdir/build/release-*; do
- arch=${arch##*-}
- case "$arch" in
- i386) echo "define(HAVE_I386,yes)dnl" >> defines.m4
- copystartscript x86
- ;;
- x86_64) echo "define(HAVE_X86_64,yes)dnl" >> defines.m4
- copystartscript $arch
- ;;
- ppc) echo "define(HAVE_PPC,yes)dnl" >> defines.m4
- copystartscript $arch
- ;;
- ppc64) echo "define(HAVE_PPC64,yes)dnl" >> defines.m4
- copystartscript $arch
- ;;
- *)
- echo "architecture $arch unsupported"
- continue;
- ;;
- esac
- archs[${#archs[@]}]=$arch
-done
-
-for arch in "${archs[@]}"; do
- dst=image/tmp
- mkdir $dst
- mkdir $dst/baseq3 $dst/demoq3 $dst/missionpack
- install -m 755 $topdir/build/release-linux-$arch/ioquake3.$arch $dst/ioquake3.$arch
- install -m 755 $topdir/build/release-linux-$arch/ioq3ded.$arch $dst/ioq3ded.$arch
- install -m 644 $topdir/build/release-linux-$arch/baseq3/*.so $dst/baseq3
- install -m 644 $topdir/build/release-linux-$arch/missionpack/*.so $dst/missionpack
- for i in cgame qagame ui; do
- ln -s ../baseq3/$i$arch.so $dst/demoq3
- done
-
- tar --owner=root --group=root -C $dst -cf ./image/ioquake3.$arch.tar .
- rm -rf ./image/tmp
-done
-
-# patch pk3 files
-if [ -e ./idpatchpk3s.tar -a -e ./idtapatchpk3s.tar ]; then
- install -m 644 ./idpatchpk3s.tar image/idpatchpk3s.tar
- install -m 644 ./idtapatchpk3s.tar image/idtapatchpk3s.tar
- install -m 644 ./id_patch_pk3s_Q3A_EULA.txt image/id_patch_pk3s_Q3A_EULA.txt
- echo "define(HAVE_PATCHPK3,yes)dnl" >> defines.m4
-elif [ -e quake3-latest-pk3s.zip ]; then
- unzip quake3-latest-pk3s.zip
- chmod 644 quake3-latest-pk3s/*/*.pk3
- tar -C quake3-latest-pk3s/baseq3 -cf image/idpatchpk3s.tar .
- tar -C quake3-latest-pk3s/missionpack -cf image/idtapatchpk3s.tar .
- rm -r quake3-latest-pk3s
- install -m 644 id_patch_pk3s_Q3A_EULA.txt image/id_patch_pk3s_Q3A_EULA.txt
- echo "define(HAVE_PATCHPK3,yes)dnl" >> defines.m4
-fi
-
-### uninstall script
-install -m 755 ./preuninstall.sh image/preuninstall.sh
-
-# desktop file handling
-install -m 755 ./install-desktop-files.sh image/install-desktop-files.sh
-install -m 755 /usr/bin/xdg-desktop-menu image/xdg-desktop-menu
-install -m 644 ioquake3.desktop image/ioquake3.desktop.in
-
-### README, COPYING and EULA
-install -m 644 $topdir/voip-readme.txt image/voip-readme.txt
-install -m 644 $topdir/README image/README
-install -m 644 $topdir/COPYING.txt image/COPYING
-
-# create setup.xml
-m4 defines.m4 setup.xml.in > image/setup.data/setup.xml
-
-### makeself installer
-ARCH=
-if [ "${#archs[@]}" -eq 1 ]; then
- ARCH=.$arch
-fi
-$MAKESELF/makeself.sh image ioquake3-$VERSION-$RELEASE$ARCH.run "ioquake3 $VERSION-$RELEASE" ./setup.sh
diff --git a/engine/misc/setup/install-desktop-files.sh b/engine/misc/setup/install-desktop-files.sh
deleted file mode 100755
index 5bcb411..0000000
--- a/engine/misc/setup/install-desktop-files.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-set -e
-if ! test -e "$SETUP_INSTALLPATH"/ioquake3.desktop.in; then
- exit 0
-fi
-xdg_desktop_menu=`which xdg-desktop-menu 2>/dev/null`
-if test "x$xdg_desktop_menu" = x; then
- xdg_desktop_menu=./xdg-desktop-menu
-fi
-sed -e "s#^Exec=.*#Exec=$SETUP_INSTALLPATH/ioquake3#" \
- -e "s#^Icon=.*#Icon=$SETUP_INSTALLPATH/quake3.png#" \
- < $SETUP_INSTALLPATH/ioquake3.desktop.in \
- > $SETUP_INSTALLPATH/ioquake3.desktop
-$xdg_desktop_menu install --novendor $SETUP_INSTALLPATH/ioquake3.desktop
diff --git a/engine/misc/setup/ioq3demo.sh b/engine/misc/setup/ioq3demo.sh
deleted file mode 100644
index 05df7ff..0000000
--- a/engine/misc/setup/ioq3demo.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/sh
-
-readlink() {
- local path=$1 ll
-
- if [ -L "$path" ]; then
- ll="$(LC_ALL=C ls -l "$path" 2> /dev/null)" &&
- echo "${ll/* -> }"
- else
- return 1
- fi
-}
-
-script=$0
-count=0
-while [ -L "$script" ]
-do
- script=$(readlink "$script")
- count=`expr $count + 1`
- if [ $count -gt 100 ]
- then
- echo "Too many symbolic links"
- exit 1
- fi
-done
-cd "`dirname $script`"
-
-
-lib=lib
-test -e lib64 && lib=lib64
-
-if test "x$LD_LIBRARY_PATH" = x; then
- LD_LIBRARY_PATH="`pwd`/$lib"
-else
- LD_LIBRARY_PATH="`pwd`/$lib:$LD_LIBRARY_PATH"
-fi
-export LD_LIBRARY_PATH
-
-archs=`uname -m`
-case "$archs" in
- i?86) archs=i386 ;;
- x86_64) archs="x86_64 i386" ;;
- ppc64) archs="ppc64 ppc" ;;
-esac
-
-for arch in $archs; do
- test -x ./ioquake3.$arch || continue
- exec ./ioquake3.$arch +set sv_pure 0 +set vm_cgame 0 +set vm_game 0 +set vm_ui 0 +set fs_game demoq3 "$@"
-done
-echo "could not execute ioquake3" >&2
diff --git a/engine/misc/setup/ioquake3.SlackBuild b/engine/misc/setup/ioquake3.SlackBuild
deleted file mode 100644
index af261b7..0000000
--- a/engine/misc/setup/ioquake3.SlackBuild
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/bin/sh
-
-CWD=`pwd`
-BASE=$CWD/../..
-if [ "$TMP" = "" ]; then
- TMP=/tmp
-fi
-
-# clean, update
-make -C $BASE clean || exit 1
-svn up $BASE || exit 1
-
-# extract version info
-VERSION=`grep "\#define *PRODUCT_VERSION" $BASE/code/qcommon/q_shared.h | \
- sed -e 's/[^"]*"\(.*\)"/\1/'`
-
-SVN_REV=`LANG=C svnversion $BASE`
-if [ ! "$SVN_REV" = "" ]; then
- VERSION=${VERSION}_SVN${SVN_REV}
-fi
-
-PKG_VERSION=$VERSION
-
-ARCH=${ARCH:-i586}
-
-BUILD=${BUILD:-1_io}
-
-APP=ioquake3
-
-PKG=$TMP/package-$APP
-
-rm -rf $PKG
-mkdir -p $PKG
-
-# build
-make -C $BASE release copyfiles COPYDIR="$PKG"/usr/games/$APP|| exit 1
-
-# copy additional files
-cp $BASE/BUGS $BASE/COPYING.txt $BASE/ChangeLog $BASE/README $PKG/usr/games/$APP/
-cat $CWD/$APP.SlackBuild > $PKG/usr/games/$APP/$APP.SlackBuild
-
-mkdir -p $PKG/usr/share/$APP/icons
-cp $BASE/misc/quake3.png $PKG/usr/share/$APP/icons/ioquake3.png
-
-mkdir -p $PKG/usr/bin
-cat >> $PKG/usr/bin/ioquake3 << EOF
-#!/bin/sh
-cd /usr/games/$APP/
-./ioquake3.i386 \$*
-exit \$?
-EOF
-chmod 754 $PKG/usr/bin/ioquake3
-
-mkdir -p $PKG/usr/bin
-cat >> $PKG/usr/bin/ioq3ded << EOF
-#!/bin/sh
-cd /usr/games/$APP/
-./ioq3ded.i386 \$*
-exit \$?
-EOF
-chmod 754 $PKG/usr/bin/ioq3ded
-
-mkdir -p $PKG/install
-cat $CWD/slack-desc > $PKG/install/slack-desc
-
-cat >> $PKG/install/doinst.sh << EOF
-chmod 754 /usr/games/$APP/*.i386
-chmod 754 /usr/bin/ioquake3 /usr/bin/ioq3ded
-EOF
-chmod +x $PKG/install/doinst.sh
-
-pushd $PKG
-chown -R root:root install/ || exit 1
-chown -R root:games usr/ || exit 1
-/sbin/makepkg -l y -c n $TMP/$APP-$VERSION-$ARCH-$BUILD.tgz
-popd
-
diff --git a/engine/misc/setup/ioquake3.desktop b/engine/misc/setup/ioquake3.desktop
deleted file mode 100644
index 0ccff3a..0000000
--- a/engine/misc/setup/ioquake3.desktop
+++ /dev/null
@@ -1,9 +0,0 @@
-[Desktop Entry]
-Name=ioquake3
-Exec=ioquake3
-Icon=quake3
-Type=Application
-Terminal=false
-Encoding=UTF-8
-Categories=Game;ActionGame;
-X-SuSE-translate=false
diff --git a/engine/misc/setup/ioquake3.sh b/engine/misc/setup/ioquake3.sh
deleted file mode 100644
index fbef567..0000000
--- a/engine/misc/setup/ioquake3.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/sh
-
-readlink() {
- local path=$1 ll
-
- if [ -L "$path" ]; then
- ll="$(LC_ALL=C ls -l "$path" 2> /dev/null)" &&
- echo "${ll##* -> }"
- else
- return 1
- fi
-}
-
-script=$0
-count=0
-while [ -L "$script" ]
-do
- script=$(readlink "$script")
- count=`expr $count + 1`
- if [ $count -gt 100 ]
- then
- echo "Too many symbolic links"
- exit 1
- fi
-done
-cd "`dirname $script`"
-
-
-lib=lib
-test -e lib64 && lib=lib64
-
-if test "x$LD_LIBRARY_PATH" = x; then
- LD_LIBRARY_PATH="`pwd`/$lib"
-else
- LD_LIBRARY_PATH="`pwd`/$lib:$LD_LIBRARY_PATH"
-fi
-export LD_LIBRARY_PATH
-
-archs=`uname -m`
-case "$archs" in
- i?86) archs=i386 ;;
- x86_64) archs="x86_64 i386" ;;
- ppc64) archs="ppc64 ppc" ;;
-esac
-
-for arch in $archs; do
- test -x ./ioquake3.$arch || continue
- exec ./ioquake3.$arch "$@"
-done
-echo "could not execute ioquake3" >&2
diff --git a/engine/misc/setup/pkg/ioq3ded.sh b/engine/misc/setup/pkg/ioq3ded.sh
deleted file mode 100644
index 511f4fb..0000000
--- a/engine/misc/setup/pkg/ioq3ded.sh
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/bash
-# Rev: $Id: ioq3ded.sh,v 1.9 2006/01/18 13:47:42 raistlin Exp raistlin $
-# Needed to make symlinks/shortcuts work.
-# the binaries must run with correct working directory
-
-IOQ3_DIR=/usr/local/share/games/quake3
-
-if [ "x${LD_LIBRARY_PATH}" = "x" ]; then
- LD_LIBRARY_PATH="${IOQ3_DIR}/lib"
-else
- LD_LIBRARY_PATH="${IOQ3_DIR}/lib:${LD_LIBRARY_PATH}"
-fi
-export LD_LIBRARY_PATH
-
-COMPILE_PLATFORM=`uname|sed -e 's/_.*//'|tr '[:upper:]' '[:lower:]'`
-COMPILE_ARCH=`uname -p | sed -e 's/i.86/i386/'`
-
-EXEC_REL=release
-
-# EXEC_BIN=ioquake3.${COMPILE_ARCH}
-# EXEC_BIN=ioquake3-smp.${COMPILE_ARCH}
-EXEC_BIN=ioq3ded.${COMPILE_ARCH}
-
-EXEC_FLAGS="+set fs_basepath ${IOQ3_DIR} +set vm_game 1 +set vm_cgame 1 +set vm_ui 1 +set sv_pure 1 +set ttycon 0 +set com_ansiColor 0"
-
-EXEC_DIR_LIST="${IOQ3_DIR}"
-
-for d in ${EXEC_DIR_LIST}
-do
- if [ -d $d ]; then
- EXEC_DIR=${d}
- break
- fi
-done
-
-if [ "X${EXEC_DIR}" != "X" ]; then
- if [ ! -x ${EXEC_DIR}/${EXEC_BIN} ]; then
- echo "Executable ${EXEC_DIR}/${EXEC_BIN} not found!" ; exit 1
- fi
- cd ${IOQ3_DIR} && \
- ${EXEC_DIR}/${EXEC_BIN} ${EXEC_FLAGS} $*
- exit $?
-else
- echo "No ioq3 binaries found!"
- exit 1
-fi
-
-
diff --git a/engine/misc/setup/pkg/ioquake3.sh b/engine/misc/setup/pkg/ioquake3.sh
deleted file mode 100644
index 29a050b..0000000
--- a/engine/misc/setup/pkg/ioquake3.sh
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/bash
-# Rev: $Id: ioquake3.sh,v 1.11 2006/01/18 13:47:42 raistlin Exp raistlin $
-# Needed to make symlinks/shortcuts work.
-# the binaries must run with correct working directory
-
-IOQ3_DIR=/usr/local/share/games/quake3
-
-if [ "x${LD_LIBRARY_PATH}" = "x" ]; then
- LD_LIBRARY_PATH="${IOQ3_DIR}/lib"
-else
- LD_LIBRARY_PATH="${IOQ3_DIR}/lib:${LD_LIBRARY_PATH}"
-fi
-export LD_LIBRARY_PATH
-
-COMPILE_PLATFORM=`uname|sed -e 's/_.*//'|tr '[:upper:]' '[:lower:]'`
-COMPILE_ARCH=`uname -p | sed -e 's/i.86/i386/'`
-
-EXEC_REL=release
-
-EXEC_BIN=ioquake3.${COMPILE_ARCH}
-# EXEC_BIN=ioquake3-smp.${COMPILE_ARCH}
-# EXEC_BIN=ioq3ded.${COMPILE_ARCH}
-
-EXEC_FLAGS="+set fs_basepath ${IOQ3_DIR} +set vm_game 1 +set vm_cgame 1 +set vm_ui 1 +set sv_pure 1 +set ttycon 0 +set com_ansiColor 0"
-
-EXEC_DIR_LIST="${IOQ3_DIR}"
-
-for d in ${EXEC_DIR_LIST}
-do
- if [ -d $d ]; then
- EXEC_DIR=${d}
- break
- fi
-done
-
-if [ "X${EXEC_DIR}" != "X" ]; then
- if [ ! -x ${EXEC_DIR}/${EXEC_BIN} ]; then
- echo "Executable ${EXEC_DIR}/${EXEC_BIN} not found!" ; exit 1
- fi
- cd ${IOQ3_DIR} && \
- ${EXEC_DIR}/${EXEC_BIN} ${EXEC_FLAGS} $*
- exit $?
-else
- echo "No ioq3 binaries found!"
- exit 1
-fi
-
-
diff --git a/engine/misc/setup/pkg/ioquake3/depend b/engine/misc/setup/pkg/ioquake3/depend
deleted file mode 100644
index ad9a1d9..0000000
--- a/engine/misc/setup/pkg/ioquake3/depend
+++ /dev/null
@@ -1,2 +0,0 @@
-P SUNWxwplt X Window System platform software
-P ioquake3d Icculus.Org Quake3 patch data files for Solaris 10 (X11,GLX,SDL)
diff --git a/engine/misc/setup/pkg/ioquake3/pkginfo.template b/engine/misc/setup/pkg/ioquake3/pkginfo.template
deleted file mode 100644
index 18f81c3..0000000
--- a/engine/misc/setup/pkg/ioquake3/pkginfo.template
+++ /dev/null
@@ -1,12 +0,0 @@
-CLASSES=none
-BASEDIR=/usr/local/share/games
-TZ=PST
-PATH=/sbin:/usr/sbin:/usr/bin:/usr/sadm/install/bin
-PKG=ioquake3
-NAME=ioquake3 for Solaris 10 (X11,GLX,SDL)
-VERSION=
-CATEGORY=application,graphics,opengl
-DESC=Icculus.Org Quake3 for Solaris 10 (http://www.ioquake3.org/)
-VENDOR=http://www.ioquake3.org/
-EMAIL=quake at cojot.name
-PKGSAV=/var/sadm/pkg/ioquake3/save
diff --git a/engine/misc/setup/pkg/ioquake3/postinstall b/engine/misc/setup/pkg/ioquake3/postinstall
deleted file mode 100644
index 2775d5e..0000000
--- a/engine/misc/setup/pkg/ioquake3/postinstall
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/sh
-#
-# @(#)postinstall $Id: postinstall,v 1.3 2006/01/21 12:54:52 coyote Exp $
-#
-# postinstall script for quake3
-
-quake3_dir=$BASEDIR/quake3
-dest_dir=${PKG_INSTALL_ROOT}/usr/local/bin
-
-if [ -d ${dest_dir} ]; then
- for inst_script in ioq3ded.sh ioquake3.sh
- do
- dest_script=${dest_dir}/${inst_script}
- if [ ! -h ${dest_script} ]; then
- ln -s ${quake3_dir}/${inst_script} ${dest_script}
- fi
- done
-fi
-
-exit 0
-
diff --git a/engine/misc/setup/pkg/ioquake3/postremove b/engine/misc/setup/pkg/ioquake3/postremove
deleted file mode 100644
index 37690f6..0000000
--- a/engine/misc/setup/pkg/ioquake3/postremove
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/sh
-#
-# @(#)postremove $Id: postremove,v 1.3 2006/01/21 12:54:52 coyote Exp $
-#
-# postremove script for quake3
-
-quake3_dir=$BASEDIR
-dest_dir=${PKG_INSTALL_ROOT}/usr/local/bin
-
-if [ -d ${dest_dir} ]; then
- for inst_script in ioq3ded.sh ioquake3.sh
- do
- dest_script=${dest_dir}/${inst_script}
- if [ -h ${dest_script} ]; then
- rm -f ${dest_script}
- fi
- done
-fi
-
-exit 0
-
diff --git a/engine/misc/setup/pkg/ioquake3/preinstall b/engine/misc/setup/pkg/ioquake3/preinstall
deleted file mode 100644
index ad126a1..0000000
--- a/engine/misc/setup/pkg/ioquake3/preinstall
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-#
-# @(#)postinstall $Id: preinstall,v 1.2 2006/01/25 13:22:56 coyote Exp $
-#
-# postinstall script for quake3
-
-quake3_dir=$BASEDIR
-
-exit 0
-
diff --git a/engine/misc/setup/pkg/ioquake3/preremove b/engine/misc/setup/pkg/ioquake3/preremove
deleted file mode 100644
index 3f316f3..0000000
--- a/engine/misc/setup/pkg/ioquake3/preremove
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-#
-# @(#)postinstall $Id: preremove,v 1.2 2006/01/25 13:22:56 coyote Exp $
-#
-# postinstall script for quake3
-
-quake3_dir=$BASEDIR
-
-exit 0
-
diff --git a/engine/misc/setup/pkg/ioquake3/prototype.template b/engine/misc/setup/pkg/ioquake3/prototype.template
deleted file mode 100644
index f23af77..0000000
--- a/engine/misc/setup/pkg/ioquake3/prototype.template
+++ /dev/null
@@ -1,8 +0,0 @@
-!default 0755 root bin
-i pkginfo
-i copyright
-i depend
-i postinstall
-i postremove
-i preinstall
-i preremove
diff --git a/engine/misc/setup/pkg/ioquake3/space b/engine/misc/setup/pkg/ioquake3/space
deleted file mode 100644
index 95b7294..0000000
--- a/engine/misc/setup/pkg/ioquake3/space
+++ /dev/null
@@ -1 +0,0 @@
-/usr/local/share 20000 15
diff --git a/engine/misc/setup/pkg/ioquake3d/depend b/engine/misc/setup/pkg/ioquake3d/depend
deleted file mode 100644
index 101bfab..0000000
--- a/engine/misc/setup/pkg/ioquake3d/depend
+++ /dev/null
@@ -1 +0,0 @@
-P SUNWxwplt X Window System platform software
diff --git a/engine/misc/setup/pkg/ioquake3d/pkginfo.template b/engine/misc/setup/pkg/ioquake3d/pkginfo.template
deleted file mode 100644
index 46b2dc5..0000000
--- a/engine/misc/setup/pkg/ioquake3d/pkginfo.template
+++ /dev/null
@@ -1,12 +0,0 @@
-CLASSES=none
-BASEDIR=/usr/local/share/games
-TZ=PST
-PATH=/sbin:/usr/sbin:/usr/bin:/usr/sadm/install/bin
-PKG=ioquake3d
-NAME=ioquake3 patch data files for Solaris 10 (X11,GLX,SDL)
-VERSION=
-CATEGORY=application,graphics,opengl
-DESC=ioquake3 patch data files for Solaris 10 (http://www.ioquake3.org/)
-VENDOR=http://www.ioquake3.org/
-EMAIL=quake at cojot.name
-PKGSAV=/var/sadm/pkg/ioquake3d/save
diff --git a/engine/misc/setup/pkg/ioquake3d/postinstall b/engine/misc/setup/pkg/ioquake3d/postinstall
deleted file mode 100644
index f116fc3..0000000
--- a/engine/misc/setup/pkg/ioquake3d/postinstall
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-#
-# @(#)postinstall $Id: postinstall,v 1.2 2006/01/25 13:22:56 coyote Exp $
-#
-# postinstall script for quake3
-
-quake3_dir=$BASEDIR
-
-exit 0
-
diff --git a/engine/misc/setup/pkg/ioquake3d/postremove b/engine/misc/setup/pkg/ioquake3d/postremove
deleted file mode 100644
index 7614348..0000000
--- a/engine/misc/setup/pkg/ioquake3d/postremove
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-#
-# @(#)postinstall $Id: postremove,v 1.2 2006/01/25 13:22:56 coyote Exp $
-#
-# postinstall script for quake3
-
-quake3_dir=$BASEDIR
-
-exit 0
-
diff --git a/engine/misc/setup/pkg/ioquake3d/preinstall b/engine/misc/setup/pkg/ioquake3d/preinstall
deleted file mode 100644
index ad126a1..0000000
--- a/engine/misc/setup/pkg/ioquake3d/preinstall
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-#
-# @(#)postinstall $Id: preinstall,v 1.2 2006/01/25 13:22:56 coyote Exp $
-#
-# postinstall script for quake3
-
-quake3_dir=$BASEDIR
-
-exit 0
-
diff --git a/engine/misc/setup/pkg/ioquake3d/preremove b/engine/misc/setup/pkg/ioquake3d/preremove
deleted file mode 100644
index 3f316f3..0000000
--- a/engine/misc/setup/pkg/ioquake3d/preremove
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-#
-# @(#)postinstall $Id: preremove,v 1.2 2006/01/25 13:22:56 coyote Exp $
-#
-# postinstall script for quake3
-
-quake3_dir=$BASEDIR
-
-exit 0
-
diff --git a/engine/misc/setup/pkg/ioquake3d/prototype.template b/engine/misc/setup/pkg/ioquake3d/prototype.template
deleted file mode 100644
index 26bd06a..0000000
--- a/engine/misc/setup/pkg/ioquake3d/prototype.template
+++ /dev/null
@@ -1,7 +0,0 @@
-!default 0755 root bin
-i pkginfo
-i depend
-i postinstall
-i postremove
-i preinstall
-i preremove
diff --git a/engine/misc/setup/pkg/ioquake3d/space b/engine/misc/setup/pkg/ioquake3d/space
deleted file mode 100644
index a8d224c..0000000
--- a/engine/misc/setup/pkg/ioquake3d/space
+++ /dev/null
@@ -1 +0,0 @@
-/usr/local/share 50000 100
diff --git a/engine/misc/setup/pkg/ioquake3m/depend b/engine/misc/setup/pkg/ioquake3m/depend
deleted file mode 100644
index 101bfab..0000000
--- a/engine/misc/setup/pkg/ioquake3m/depend
+++ /dev/null
@@ -1 +0,0 @@
-P SUNWxwplt X Window System platform software
diff --git a/engine/misc/setup/pkg/ioquake3m/pkginfo.template b/engine/misc/setup/pkg/ioquake3m/pkginfo.template
deleted file mode 100644
index 3e10450..0000000
--- a/engine/misc/setup/pkg/ioquake3m/pkginfo.template
+++ /dev/null
@@ -1,12 +0,0 @@
-CLASSES=none
-BASEDIR=/usr/local/share/games
-TZ=PST
-PATH=/sbin:/usr/sbin:/usr/bin:/usr/sadm/install/bin
-PKG=ioquake3m
-NAME=ioquake3 demo data files for Solaris 10 (X11,GLX,SDL)
-VERSION=
-CATEGORY=application,graphics,opengl
-DESC=ioquake3 demo data files for Solaris 10 (http://www.ioquake3.org/)
-VENDOR=http://www.ioquake3.org/
-EMAIL=quake at cojot.name
-PKGSAV=/var/sadm/pkg/ioquake3m/save
diff --git a/engine/misc/setup/pkg/ioquake3m/postinstall b/engine/misc/setup/pkg/ioquake3m/postinstall
deleted file mode 100644
index f116fc3..0000000
--- a/engine/misc/setup/pkg/ioquake3m/postinstall
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-#
-# @(#)postinstall $Id: postinstall,v 1.2 2006/01/25 13:22:56 coyote Exp $
-#
-# postinstall script for quake3
-
-quake3_dir=$BASEDIR
-
-exit 0
-
diff --git a/engine/misc/setup/pkg/ioquake3m/postremove b/engine/misc/setup/pkg/ioquake3m/postremove
deleted file mode 100644
index 7614348..0000000
--- a/engine/misc/setup/pkg/ioquake3m/postremove
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-#
-# @(#)postinstall $Id: postremove,v 1.2 2006/01/25 13:22:56 coyote Exp $
-#
-# postinstall script for quake3
-
-quake3_dir=$BASEDIR
-
-exit 0
-
diff --git a/engine/misc/setup/pkg/ioquake3m/preinstall b/engine/misc/setup/pkg/ioquake3m/preinstall
deleted file mode 100644
index ad126a1..0000000
--- a/engine/misc/setup/pkg/ioquake3m/preinstall
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-#
-# @(#)postinstall $Id: preinstall,v 1.2 2006/01/25 13:22:56 coyote Exp $
-#
-# postinstall script for quake3
-
-quake3_dir=$BASEDIR
-
-exit 0
-
diff --git a/engine/misc/setup/pkg/ioquake3m/preremove b/engine/misc/setup/pkg/ioquake3m/preremove
deleted file mode 100644
index 3f316f3..0000000
--- a/engine/misc/setup/pkg/ioquake3m/preremove
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-#
-# @(#)postinstall $Id: preremove,v 1.2 2006/01/25 13:22:56 coyote Exp $
-#
-# postinstall script for quake3
-
-quake3_dir=$BASEDIR
-
-exit 0
-
diff --git a/engine/misc/setup/pkg/ioquake3m/prototype.template b/engine/misc/setup/pkg/ioquake3m/prototype.template
deleted file mode 100644
index 26bd06a..0000000
--- a/engine/misc/setup/pkg/ioquake3m/prototype.template
+++ /dev/null
@@ -1,7 +0,0 @@
-!default 0755 root bin
-i pkginfo
-i depend
-i postinstall
-i postremove
-i preinstall
-i preremove
diff --git a/engine/misc/setup/pkg/ioquake3m/space b/engine/misc/setup/pkg/ioquake3m/space
deleted file mode 100644
index a8d224c..0000000
--- a/engine/misc/setup/pkg/ioquake3m/space
+++ /dev/null
@@ -1 +0,0 @@
-/usr/local/share 50000 100
diff --git a/engine/misc/setup/preuninstall.sh b/engine/misc/setup/preuninstall.sh
deleted file mode 100755
index e6a413d..0000000
--- a/engine/misc/setup/preuninstall.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-rmdir --ignore-fail-on-non-empty demoq3 missionpack >& /dev/null
-if test -e "$SETUP_INSTALLPATH"/ioquake3.desktop.in; then
- xdg_desktop_menu=`which xdg-desktop-menu 2>/dev/null`
- if test "x$xdg_desktop_menu" = x; then
- xdg_desktop_menu=./xdg-desktop-menu
- fi
- $xdg_desktop_menu uninstall --novendor ioquake3.desktop
- rm ioquake3.desktop
-fi
diff --git a/engine/misc/setup/setup.xml.in b/engine/misc/setup/setup.xml.in
deleted file mode 100644
index b820101..0000000
--- a/engine/misc/setup/setup.xml.in
+++ /dev/null
@@ -1,134 +0,0 @@
-<?xml version="1.0" standalone="yes"?>
-<install product="ioquake3"
- desc="ioquake3"
- version="VERSION"
- update_url="http://www.ioquake3.org/updates.txt"
- promptbinaries="yes"
- reinstall="yes"
- nopromptoverwrite="yes"
- nomenuitems="yes"
- postinstall="install-desktop-files.sh"
- preuninstall="preuninstall.sh">
- <readme>
- README
- </readme>
-
- <component name="Default" version="VERSION" default="yes">
-ifelse(HAVE_X86_64,yes,dnl
- <option install="true" arch="x86_64">
- ioq3 x86_64 binaries
- <binary libc="any" symlink="ioquake3" icon="quake3.png" name="ioquake3">ioquake3</binary>
- <files>
- ioquake3.x86_64.tar
- </files>
- <help>you need the binaries to play the game</help>
- </option>
-)dnl
-ifelse(HAVE_I386,yes,dnl
- <option install="true" if="|(x86,x86_64)">
- ioq3 x86 (32 bit) binaries
- <binary libc="any" symlink="ioquake3" icon="quake3.png" name="ioquake3">ioquake3</binary>
- <files>
- ioquake3.i386.tar
- </files>
- <help>you need the binaries to play the game</help>
- </option>
-)dnl
-ifelse(HAVE_PPC,yes,dnl
- <option install="true" if="|(ppc,ppc64)">
- <binary libc="any" symlink="ioquake3" icon="quake3.png" name="ioquake3">ioquake3</binary>
- ioq3 ppc binaries
- <files>
- ioquake3.ppc.tar
- </files>
- <help>you need the binaries to play the game</help>
- </option>
-)dnl
-ifelse(HAVE_PPC64,yes,dnl
- <option install="true" arch="ppc64">
- <binary libc="any" symlink="ioquake3" icon="quake3.png" name="ioquake3">ioquake3</binary>
- ioq3 ppc64 binaries
- <files>
- ioquake3.ppc64.tar
- </files>
- <help>you need the binaries to play the game</help>
- </option>
-)dnl
- <option install="true">
- Desktop menu entries
- <files mode="0755">
- xdg-desktop-menu
- </files>
- <files>
- ioquake3.desktop.in
- </files>
- </option>
-
- <option install="true" show="false">
- shared data
- <files>
- quake3.png
- COPYING
- voip-readme.txt
- </files>
- </option>
- </component>
-ifelse(HAVE_PATCHPK3,yes,dnl
-
- <component name="Quake III Arena" version="VERSION">
- <eula>
- id_patch_pk3s_Q3A_EULA.txt
- </eula>
-
- <option install="true">
- Quake III Arena Point Release 1.32 data files
- <files path="baseq3">
- idpatchpk3s.tar
- </files>
- </option>
-
- <option>
- <help>
- If you don't select this you need to copy pak0.pk3 to the baseq3 directory manually.
- </help>
- Quake III Arena CDROM data
- <files cdromid="CD 1" path="baseq3"
- md5sum="1197ca3df1e65f3c380f8abc10ca43bf"
- size="458M" mode="0664">
- Quake3/baseq3/pak0.pk3
- </files>
- </option>
- </component>
-
- <component name="Quake III Team Arena" version="VERSION">
- <eula>
- id_patch_pk3s_Q3A_EULA.txt
- </eula>
-
- <option install="true">
- Quake III Team Arena Point Release 1.32 data files
- <files path="missionpack">
- idtapatchpk3s.tar
- </files>
- </option>
- <option>
- <help>
- If you don't select this you need to copy the TA pak0.pk3 to the missionpack directory manually.
- </help>
- Quake III Team Arena CDROM data
- <files cdromid="CD 2" path="missionpack" size="336M"
- md5sum="e8ba9e3bf06210930bc0e7fdbcdd01c2" mode="0644">
- Setup/missionpack/pak0.pk3
- </files>
- </option>
- </component>
-
- <cdrom id="CD 1" name="Quake 3 Arena installation CD">
- Quake3/baseq3/pak0.pk3
- </cdrom>
- <cdrom id="CD 2" name="Quake 3 Team Arena installation CD">
- Setup/missionpack/pak0.pk3
- </cdrom>
-)dnl
-
-</install>
diff --git a/engine/misc/setup/setup.xml.mod b/engine/misc/setup/setup.xml.mod
deleted file mode 100644
index ec6707f..0000000
--- a/engine/misc/setup/setup.xml.mod
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" standalone="yes"?>
-<!-- ioquake3 is the name of the base product -->
-<install product="ioquake3"
- desc="ioquake3"
- component="Foo Mod"
- version="1.1"
- >
-
- <option install="true">
- Foo
- <!--
- install symlink 'foo' into $PATH, pointing to a script
- called startfoo that gets installed into ioquake3's
- directory
- The script could look like this:
- #!/bin/sh
- exec ioquake3 +set fs_game foo "$@"
- exit 1
- -->
- <binary arch="any" libc="any"
- symlink="foo"
- binpath="startfoo">
- startfoo
- </binary>
- <!--
- extract archive in ioquake3's directory.
- the archive must contain a subdirectory of course
- -->
- <files>
- foo-1.1.zip
- </files>
- </option>
-</install>
diff --git a/engine/misc/setup/slack-desc b/engine/misc/setup/slack-desc
deleted file mode 100644
index c88b4bc..0000000
--- a/engine/misc/setup/slack-desc
+++ /dev/null
@@ -1,12 +0,0 @@
- |-----handy-ruler------------------------------------------------------|
-ioquake3: ioquake 3 - An open source Quake 3 distribution
-ioquake3:
-ioquake3: ioquake3 aims to build upon id Software's Quake 3 source code release.
-ioquake3: The source code was released on August 20, 2005 under the GPL. Since
-ioquake3: then code has been cleaned up, bugs have been fixed and features been
-ioquake3: added.
-ioquake3: The permanent goal is to create THE open source Quake 3 distribution
-ioquake3: upon which people base their games and projects.
-ioquake3:
-ioquake3: http://ioquake3.org/
-ioquake3:
diff --git a/engine/misc/setup/splash.xpm b/engine/misc/setup/splash.xpm
deleted file mode 100644
index 2767767..0000000
--- a/engine/misc/setup/splash.xpm
+++ /dev/null
@@ -1,2289 +0,0 @@
-/* XPM */
-static char * splash_xpm[] = {
-"296 296 1990 2",
-" c #999999",
-". c #989797",
-"+ c #999898",
-"@ c #938B8B",
-"# c #979494",
-"$ c #8D7D7D",
-"% c #958F8F",
-"& c #887070",
-"* c #928989",
-"= c #846666",
-"- c #8F7F7F",
-"; c #815C5C",
-"> c #8B7676",
-", c #7D5353",
-"' c #876C6C",
-") c #7A4949",
-"! c #846262",
-"~ c #764040",
-"{ c #805959",
-"] c #733636",
-"^ c #7D4F4F",
-"/ c #702C2C",
-"( c #794646",
-"_ c #6C2323",
-": c #763C3C",
-"< c #691919",
-"[ c #733232",
-"} c #979595",
-"| c #671313",
-"1 c #6F2929",
-"2 c #969090",
-"3 c #660E0E",
-"4 c #6C1F1F",
-"5 c #948B8B",
-"6 c #650A0A",
-"7 c #691616",
-"8 c #928686",
-"9 c #640505",
-"0 c #660C0C",
-"a c #918181",
-"b c #630101",
-"c c #640303",
-"d c #8D7878",
-"e c #630000",
-"f c #969292",
-"g c #8A6E6E",
-"h c #640000",
-"i c #938888",
-"j c #876565",
-"k c #907F7F",
-"l c #845B5B",
-"m c #650000",
-"n c #8D7575",
-"o c #815252",
-"p c #8A6B6B",
-"q c #7E4848",
-"r c #660000",
-"s c #876262",
-"t c #7B3E3E",
-"u c #670000",
-"v c #845858",
-"w c #783535",
-"x c #814F4F",
-"y c #762B2B",
-"z c #680000",
-"A c #7E4545",
-"B c #732222",
-"C c #7B3B3B",
-"D c #989696",
-"E c #711A1A",
-"F c #690000",
-"G c #793232",
-"H c #701313",
-"I c #6A0000",
-"J c #762828",
-"K c #979191",
-"L c #6E0C0C",
-"M c #731F1F",
-"N c #968F8F",
-"O c #6C0505",
-"P c #6B0000",
-"Q c #711515",
-"R c #948A8A",
-"S c #6F0D0D",
-"T c #928080",
-"U c #6C0000",
-"V c #6F0909",
-"W c #8F7777",
-"X c #6E0707",
-"Y c #958A8A",
-"Z c #8C6D6D",
-"` c #6D0000",
-" . c #6E0404",
-".. c #938383",
-"+. c #8A6464",
-"@. c #6E0202",
-"#. c #917C7C",
-"$. c #875A5A",
-"%. c #6E0000",
-"&. c #8F7474",
-"*. c #855050",
-"=. c #6F0000",
-"-. c #8C6B6B",
-";. c #824646",
-">. c #8A6161",
-",. c #803D3D",
-"'. c #700000",
-"). c #875757",
-"!. c #7E3333",
-"~. c #854D4D",
-"{. c #7C2929",
-"]. c #710000",
-"^. c #834444",
-"/. c #792020",
-"(. c #803A3A",
-"_. c #781616",
-":. c #720000",
-"<. c #7E3131",
-"[. c #760D0D",
-"}. c #730000",
-"|. c #7D2727",
-"1. c #740303",
-"2. c #7A1D1D",
-"3. c #979292",
-"4. c #740000",
-"5. c #791616",
-"6. c #999797",
-"7. c #958989",
-"8. c #781111",
-"9. c #937F7F",
-"0. c #750000",
-"a. c #780C0C",
-"b. c #968E8E",
-"c. c #917676",
-"d. c #770707",
-"e. c #8F6B6B",
-"f. c #760000",
-"g. c #770202",
-"h. c #948484",
-"i. c #8D6262",
-"j. c #770000",
-"k. c #937D7D",
-"l. c #8B5858",
-"m. c #917373",
-"n. c #894F4F",
-"o. c #780000",
-"p. c #8F6A6A",
-"q. c #874545",
-"r. c #8D6060",
-"s. c #853B3B",
-"t. c #790000",
-"u. c #8B5656",
-"v. c #843232",
-"w. c #7A0000",
-"x. c #8A4D4D",
-"y. c #822828",
-"z. c #884343",
-"A. c #811F1F",
-"B. c #7B0000",
-"C. c #863A3A",
-"D. c #7F1515",
-"E. c #843030",
-"F. c #7E0D0D",
-"G. c #7C0000",
-"H. c #832626",
-"I. c #989191",
-"J. c #7E0909",
-"K. c #821F1F",
-"L. c #968A8A",
-"M. c #7E0707",
-"N. c #7D0000",
-"O. c #811717",
-"P. c #989595",
-"Q. c #958383",
-"R. c #7E0404",
-"S. c #801010",
-"T. c #989292",
-"U. c #947C7C",
-"V. c #7E0202",
-"W. c #7E0000",
-"X. c #7F0808",
-"Y. c #979090",
-"Z. c #937474",
-"`. c #7F0000",
-" + c #7F0202",
-".+ c #978E8E",
-"++ c #916A6A",
-"@+ c #968585",
-"#+ c #906161",
-"$+ c #800000",
-"%+ c #8E5757",
-"&+ c #937373",
-"*+ c #8D4D4D",
-"=+ c #810000",
-"-+ c #916969",
-";+ c #8C4444",
-">+ c #905F5F",
-",+ c #8B3A3A",
-"'+ c #820000",
-")+ c #8F5555",
-"!+ c #8A3131",
-"~+ c #830000",
-"{+ c #8E4C4C",
-"]+ c #892727",
-"^+ c #8D4343",
-"/+ c #881D1D",
-"(+ c #840000",
-"_+ c #8C3838",
-":+ c #871616",
-"<+ c #8A2F2F",
-"[+ c #871111",
-"}+ c #850000",
-"|+ c #8A2525",
-"1+ c #988E8E",
-"2+ c #870C0C",
-"3+ c #891C1C",
-"4+ c #978989",
-"5+ c #870707",
-"6+ c #860000",
-"7+ c #881212",
-"8+ c #968383",
-"9+ c #870202",
-"0+ c #870000",
-"a+ c #880808",
-"b+ c #967C7C",
-"c+ c #870101",
-"d+ c #957373",
-"e+ c #880000",
-"f+ c #946969",
-"g+ c #978585",
-"h+ c #935F5F",
-"i+ c #890000",
-"j+ c #967B7B",
-"k+ c #925656",
-"l+ c #8A0000",
-"m+ c #957171",
-"n+ c #914C4C",
-"o+ c #946868",
-"p+ c #9F9191",
-"q+ c #AB7E7E",
-"r+ c #BD6262",
-"s+ c #CF4848",
-"t+ c #DB3636",
-"u+ c #E72525",
-"v+ c #EB1F1F",
-"w+ c #E12C2C",
-"x+ c #CD4B4B",
-"y+ c #B76C6C",
-"z+ c #9E9191",
-"A+ c #914343",
-"B+ c #8B0000",
-"C+ c #945E5E",
-"D+ c #AA7F7F",
-"E+ c #C15C5C",
-"F+ c #D83A3A",
-"G+ c #E82222",
-"H+ c #E91F1F",
-"I+ c #E02D2D",
-"J+ c #D43F3F",
-"K+ c #C55555",
-"L+ c #B47070",
-"M+ c #A38989",
-"N+ c #9B9595",
-"O+ c #9D9292",
-"P+ c #B17474",
-"Q+ c #CB4D4D",
-"R+ c #E32828",
-"S+ c #F70B0B",
-"T+ c #FE0000",
-"U+ c #FC0202",
-"V+ c #EE1919",
-"W+ c #D34141",
-"X+ c #B76B6B",
-"Y+ c #903939",
-"Z+ c #935555",
-"`+ c #9D9494",
-" @ c #AD7B7B",
-".@ c #C45757",
-"+@ c #E12B2B",
-"@@ c #F60A0A",
-"#@ c #FD0000",
-"$@ c #FB0202",
-"%@ c #ED1919",
-"&@ c #D63B3B",
-"*@ c #BD6161",
-"=@ c #A58686",
-"-@ c #B46F6F",
-";@ c #D63C3C",
-">@ c #F11313",
-",@ c #FD0101",
-"'@ c #EE1717",
-")@ c #CE4949",
-"!@ c #AC7C7C",
-"~@ c #902F2F",
-"{@ c #8C0000",
-"]@ c #924B4B",
-"^@ c #A28B8B",
-"/@ c #BC6363",
-"(@ c #DE2E2E",
-"_@ c #F80707",
-":@ c #FC0000",
-"<@ c #F70707",
-"[@ c #E32525",
-"}@ c #C45656",
-"|@ c #A58787",
-"1@ c #CB4C4C",
-"2@ c #EE1515",
-"3@ c #FB0101",
-"4@ c #DD2F2F",
-"5@ c #B37070",
-"6@ c #9C9494",
-"7@ c #8F2626",
-"8@ c #924141",
-"9@ c #C94E4E",
-"0@ c #F11010",
-"a@ c #FB0000",
-"b@ c #B86969",
-"c@ c #9A9898",
-"d@ c #AB7D7D",
-"e@ c #D73838",
-"f@ c #F90404",
-"g@ c #F80505",
-"h@ c #D53B3B",
-"i@ c #A78383",
-"j@ c #8F1E1E",
-"k@ c #8D0000",
-"l@ c #913838",
-"m@ c #9C9595",
-"n@ c #BC6161",
-"o@ c #EB1717",
-"p@ c #FA0000",
-"q@ c #EB1818",
-"r@ c #BE5E5E",
-"s@ c #A88181",
-"t@ c #D83636",
-"u@ c #F80303",
-"v@ c #F90101",
-"w@ c #DB3131",
-"x@ c #999595",
-"y@ c #8F1717",
-"z@ c #912E2E",
-"A@ c #9D9393",
-"B@ c #C35656",
-"C@ c #EF1010",
-"D@ c #F90000",
-"E@ c #ED1414",
-"F@ c #BD5F5F",
-"G@ c #9F9090",
-"H@ c #CD4646",
-"I@ c #F40808",
-"J@ c #EE1111",
-"K@ c #B96666",
-"L@ c #999292",
-"M@ c #8F1010",
-"N@ c #8E0000",
-"O@ c #912525",
-"P@ c #D73535",
-"Q@ c #F70101",
-"R@ c #F80000",
-"S@ c #E32222",
-"T@ c #B17272",
-"U@ c #EA1717",
-"V@ c #D93232",
-"W@ c #989090",
-"X@ c #900808",
-"Y@ c #8F0000",
-"Z@ c #911B1B",
-"`@ c #9A9797",
-" # c #BA6464",
-".# c #F10A0A",
-"+# c #F70000",
-"@# c #F40404",
-"## c #CE4343",
-"$# c #CD4444",
-"%# c #F70202",
-"&# c #C55252",
-"*# c #988D8D",
-"=# c #8F0101",
-"-# c #901111",
-";# c #A78282",
-"># c #E61A1A",
-",# c #F60000",
-"'# c #E91616",
-")# c #AC7A7A",
-"!# c #A18B8B",
-"~# c #DD2929",
-"{# c #F40505",
-"]# c #BD5E5E",
-"^# c #988585",
-"/# c #900000",
-"(# c #910B0B",
-"_# c #999696",
-":# c #A28A8A",
-"<# c #E02222",
-"[# c #F50000",
-"}# c #F00909",
-"|# c #B96363",
-"1# c #A88080",
-"2# c #E71818",
-"3# c #F40303",
-"4# c #BD5D5D",
-"5# c #977B7B",
-"6# c #988F8F",
-"7# c #A18C8C",
-"8# c #E31D1D",
-"9# c #F40000",
-"0# c #F20303",
-"a# c #C74C4C",
-"b# c #E91414",
-"c# c #F50101",
-"d# c #C84B4B",
-"e# c #977171",
-"f# c #910000",
-"g# c #910606",
-"h# c #988888",
-"i# c #A48787",
-"j# c #EC0D0D",
-"k# c #F30101",
-"l# c #A68383",
-"m# c #E91313",
-"n# c #DB2B2B",
-"o# c #9B9696",
-"p# c #966868",
-"q# c #910404",
-"r# c #988080",
-"s# c #B26F6F",
-"t# c #F10303",
-"u# c #F30000",
-"v# c #C44F4F",
-"w# c #E11F1F",
-"x# c #EF0707",
-"y# c #A58585",
-"z# c #965E5E",
-"A# c #920000",
-"B# c #920101",
-"C# c #987979",
-"D# c #CE3E3E",
-"E# c #F20000",
-"F# c #F10202",
-"G# c #B76565",
-"H# c #CE3D3D",
-"I# c #C64C4C",
-"J# c #965555",
-"K# c #930000",
-"L# c #A28989",
-"M# c #EA0D0D",
-"N# c #F10000",
-"O# c #A87F7F",
-"P# c #B66767",
-"Q# c #F00202",
-"R# c #EA0C0C",
-"S# c #A08C8C",
-"T# c #964B4B",
-"U# c #976767",
-"V# c #C74949",
-"W# c #F00000",
-"X# c #DC2323",
-"Y# c #E31717",
-"Z# c #CB4141",
-"`# c #964141",
-" $ c #940000",
-".$ c #975D5D",
-"+$ c #A48585",
-"@$ c #EC0606",
-"#$ c #EF0000",
-"$$ c #BA5E5E",
-"%$ c #C25050",
-"&$ c #EE0202",
-"*$ c #AC7777",
-"=$ c #963838",
-"-$ c #975353",
-";$ c #D72929",
-">$ c #EE0000",
-",$ c #E51010",
-"'$ c #9E8F8F",
-")$ c #E41212",
-"!$ c #962E2E",
-"~$ c #950000",
-"{$ c #974A4A",
-"]$ c #BE5555",
-"^$ c #ED0000",
-"/$ c #B86060",
-"($ c #D23131",
-"_$ c #962424",
-":$ c #974040",
-"<$ c #A97B7B",
-"[$ c #EC0000",
-"}$ c #DF1919",
-"|$ c #D62929",
-"1$ c #C34C4C",
-"2$ c #971A1A",
-"3$ c #960000",
-"4$ c #973737",
-"5$ c #EA0202",
-"6$ c #EB0000",
-"7$ c #AB7777",
-"8$ c #E90404",
-"9$ c #B76161",
-"0$ c #971111",
-"a$ c #970000",
-"b$ c #982D2D",
-"c$ c #E11111",
-"d$ c #EA0000",
-"e$ c #C14D4D",
-"f$ c #AD7373",
-"g$ c #B16B6B",
-"h$ c #970707",
-"i$ c #972323",
-"j$ c #DA1C1C",
-"k$ c #E90000",
-"l$ c #D42929",
-"m$ c #BC5656",
-"n$ c #AE7272",
-"o$ c #980101",
-"p$ c #980000",
-"q$ c #981A1A",
-"r$ c #D72323",
-"s$ c #DF1313",
-"t$ c #C64343",
-"u$ c #B46666",
-"v$ c #998D8D",
-"w$ c #981414",
-"x$ c #DC1717",
-"y$ c #E80000",
-"z$ c #E40808",
-"A$ c #A18A8A",
-"B$ c #CC3636",
-"C$ c #C93D3D",
-"D$ c #998383",
-"E$ c #990000",
-"F$ c #990F0F",
-"G$ c #999191",
-"H$ c #A38585",
-"I$ c #E70101",
-"J$ c #E70000",
-"K$ c #E60202",
-"L$ c #A48383",
-"M$ c #CE3232",
-"N$ c #E20A0A",
-"O$ c #997A7A",
-"P$ c #9A0000",
-"Q$ c #9A0A0A",
-"R$ c #998C8C",
-"S$ c #C73E3E",
-"T$ c #E60000",
-"U$ c #A58181",
-"V$ c #CB3535",
-"W$ c #D12929",
-"X$ c #997070",
-"Y$ c #9A0505",
-"Z$ c #998787",
-"`$ c #AF6B6B",
-" % c #E30404",
-".% c #E50000",
-"+% c #E40202",
-"@% c #C34444",
-"#% c #E30000",
-"$% c #B23434",
-"%% c #6A6A6A",
-"&% c #626262",
-"*% c #717171",
-"=% c #8F8F8F",
-"-% c #9A6767",
-";% c #9B0000",
-">% c #9B0101",
-",% c #998282",
-"'% c #AC7171",
-")% c #DF0A0A",
-"!% c #E40000",
-"~% c #E00909",
-"{% c #A08B8B",
-"]% c #B46262",
-"^% c #BF0000",
-"/% c #450000",
-"(% c #050000",
-"_% c #000000",
-":% c #0A0A0A",
-"<% c #494949",
-"[% c #929292",
-"}% c #9A5D5D",
-"|% c #997979",
-"1% c #B75A5A",
-"2% c #E00707",
-"3% c #D61B1B",
-"4% c #9F8C8C",
-"5% c #E20303",
-"6% c #AF0000",
-"7% c #120000",
-"8% c #272727",
-"9% c #9A5353",
-"0% c #9C0000",
-"a% c #9A7070",
-"b% c #C73A3A",
-"c% c #E10101",
-"d% c #E20000",
-"e% c #C14545",
-"f% c #CB3131",
-"g% c #D90000",
-"h% c #1B0000",
-"i% c #3D3D3D",
-"j% c #989898",
-"k% c #9B4A4A",
-"l% c #9A6666",
-"m% c #919191",
-"n% c #868686",
-"o% c #8E8E8E",
-"p% c #878585",
-"q% c #9F5858",
-"r% c #D40E0E",
-"s% c #E10000",
-"t% c #DF0404",
-"u% c #A77C7C",
-"v% c #A87979",
-"w% c #E10303",
-"x% c #040404",
-"y% c #858585",
-"z% c #9B4040",
-"A% c #9D0000",
-"B% c #9B5C5C",
-"C% c #575757",
-"D% c #434343",
-"E% c #7A7A7A",
-"F% c #373737",
-"G% c #0B0B0B",
-"H% c #010000",
-"I% c #250000",
-"J% c #CE0000",
-"K% c #E00000",
-"L% c #C93232",
-"M% c #C43D3D",
-"N% c #480000",
-"O% c #742F2F",
-"P% c #A77A7A",
-"Q% c #9C3636",
-"R% c #9B5353",
-"S% c #949494",
-"T% c #454545",
-"U% c #030303",
-"V% c #170000",
-"W% c #DF0000",
-"X% c #DB0808",
-"Y% c #A38383",
-"Z% c #D51919",
-"`% c #360000",
-" & c #DF0303",
-".& c #D02323",
-"+& c #B45E5E",
-"@& c #9D9191",
-"#& c #9D2C2C",
-"$& c #9E0000",
-"%& c #9C4949",
-"&& c #979797",
-"*& c #3A3A3A",
-"=& c #080000",
-"-& c #DE0000",
-";& c #DD0101",
-">& c #B55B5B",
-",& c #A57F7F",
-"'& c #D90D0D",
-")& c #4A0000",
-"!& c #DA0C0C",
-"~& c #C53838",
-"{& c #AD6D6D",
-"]& c #9E2323",
-"^& c #9F0000",
-"/& c #9D4040",
-"(& c #5E5E5E",
-"_& c #010101",
-":& c #0F0000",
-"<& c #C90000",
-"[& c #BF4444",
-"}& c #AA7474",
-"|& c #DB0606",
-"1& c #090000",
-"2& c #C60000",
-"3& c #D80D0D",
-"4& c #C33C3C",
-"5& c #AE6B6B",
-"6& c #9D8F8F",
-"7& c #9E1919",
-"8& c #9D3636",
-"9& c #959595",
-"0& c #0F0F0F",
-"a& c #5E0000",
-"b& c #DD0000",
-"c& c #C63434",
-"d& c #AB7070",
-"e& c #D70D0D",
-"f& c #D70000",
-"g& c #DC0000",
-"h& c #D80B0B",
-"i& c #C83030",
-"j& c #B35D5D",
-"k& c #9A9696",
-"l& c #9F1010",
-"m& c #A00000",
-"n& c #9E2C2C",
-"o& c #040000",
-"p& c #1C0000",
-"q& c #130000",
-"r& c #180000",
-"s& c #D50000",
-"t& c #C33838",
-"u& c #9C9393",
-"v& c #D41313",
-"w& c #B70000",
-"x& c #1D0000",
-"y& c #D30000",
-"z& c #DA0404",
-"A& c #D01A1A",
-"B& c #C04040",
-"C& c #AE6969",
-"D& c #A08989",
-"E& c #A00A0A",
-"F& c #9B9494",
-"G& c #A67A7A",
-"H& c #B65555",
-"I& c #681E1E",
-"J& c #A80000",
-"K& c #D00000",
-"L& c #D60000",
-"M& c #CC0000",
-"N& c #B80000",
-"O& c #DA0101",
-"P& c #BD4444",
-"Q& c #A18686",
-"R& c #CB2626",
-"S& c #DB0000",
-"T& c #580000",
-"U& c #1A0000",
-"V& c #D80707",
-"W& c #C13D3D",
-"X& c #B16161",
-"Y& c #A28484",
-"Z& c #9A8E8E",
-"`& c #A10808",
-" * c #A10000",
-".* c #A01C1C",
-"+* c #9C9292",
-"@* c #AA7171",
-"#* c #B94F4F",
-"$* c #C82B2B",
-"%* c #D50D0D",
-"&* c #D90202",
-"** c #DA0000",
-"=* c #610000",
-"-* c #A40707",
-";* c #B35C5C",
-">* c #BB4B4B",
-",* c #D80404",
-"'* c #D40000",
-")* c #AD0000",
-"!* c #D40F0F",
-"~* c #C53232",
-"{* c #A77979",
-"]* c #9A8686",
-"^* c #A10505",
-"/* c #A01414",
-"(* c #999494",
-"_* c #A08787",
-":* c #AE6666",
-"<* c #BD4343",
-"[* c #CC2020",
-"}* c #D80202",
-"|* c #5C0000",
-"1* c #786969",
-"2* c #A97272",
-"3* c #CD1C1C",
-"4* c #D40B0B",
-"5* c #CB2222",
-"6* c #BF3E3E",
-"7* c #9B7F7F",
-"8* c #A20303",
-"9* c #A20000",
-"0* c #A10D0D",
-"a* c #9B9393",
-"b* c #AD6A6A",
-"c* c #B94C4C",
-"d* c #C42F2F",
-"e* c #CF1616",
-"f* c #D70202",
-"g* c #D80000",
-"h* c #5F0000",
-"i* c #060000",
-"j* c #260000",
-"k* c #737373",
-"l* c #747474",
-"m* c #5D5D5D",
-"n* c #605656",
-"o* c #791A1A",
-"p* c #B60000",
-"q* c #D80101",
-"r* c #D40A0A",
-"s* c #C13838",
-"t* c #B55656",
-"u* c #9F8989",
-"v* c #9B7878",
-"w* c #A30101",
-"x* c #A30000",
-"y* c #A30606",
-"z* c #9A8F8F",
-"A* c #A47E7E",
-"B* c #AE6464",
-"C* c #BB4646",
-"D* c #C62929",
-"E* c #D01212",
-"F* c #D60404",
-"G* c #C70000",
-"H* c #BC0000",
-"I* c #3B3B3B",
-"J* c #C00000",
-"K* c #3C0000",
-"L* c #200000",
-"M* c #100000",
-"N* c #240000",
-"O* c #4C0000",
-"P* c #D10000",
-"Q* c #D70101",
-"R* c #D40707",
-"S* c #CF1313",
-"T* c #C52C2C",
-"U* c #BB4545",
-"V* c #B15E5E",
-"W* c #A77777",
-"X* c #9C6F6F",
-"Y* c #9A8B8B",
-"Z* c #A28383",
-"`* c #AC6A6A",
-" = c #B65151",
-".= c #C03838",
-"+= c #CA1F1F",
-"@= c #D20B0B",
-"#= c #D50303",
-"$= c #CB0000",
-"%= c #620000",
-"&= c #070000",
-"*= c #D01010",
-"== c #BB4343",
-"-= c #B25B5B",
-";= c #A87474",
-">= c #9F8A8A",
-",= c #7C7C7C",
-"'= c #6E6E6E",
-")= c #6D6D6D",
-"!= c #767676",
-"~= c #888888",
-"{= c #969696",
-"]= c #707070",
-"^= c #757575",
-"/= c #9D6565",
-"(= c #A40000",
-"_= c #6D5D5D",
-":= c #909090",
-"<= c #A37F7F",
-"[= c #AD6767",
-"}= c #B54E4E",
-"|= c #B13535",
-"1= c #970505",
-"2= c #A70000",
-"3= c #C10000",
-"4= c #D00D0D",
-"5= c #1D1717",
-"6= c #BB0000",
-"7= c #2F0000",
-"8= c #020000",
-"9= c #560000",
-"0= c #CD0000",
-"a= c #D50101",
-"b= c #CF0E0E",
-"c= c #9F1F1F",
-"d= c #3A2525",
-"e= c #020202",
-"f= c #1F1F1F",
-"g= c #5F5F5F",
-"h= c #8D8D8D",
-"i= c #727272",
-"j= c #1C1C1C",
-"k= c #9D5B5B",
-"l= c #090909",
-"m= c #313131",
-"n= c #797979",
-"o= c #323232",
-"p= c #9A9595",
-"q= c #9E8B8B",
-"r= c #A37E7E",
-"s= c #AC6969",
-"t= c #B45353",
-"u= c #BC3E3E",
-"v= c #C42828",
-"w= c #CB1616",
-"x= c #D10707",
-"y= c #3F0000",
-"z= c #0B0000",
-"A= c #350000",
-"B= c #B74C4C",
-"C= c #1B1B1B",
-"D= c #3C3C3C",
-"E= c #673D3D",
-"F= c #C32F2F",
-"G= c #D40202",
-"H= c #2B0000",
-"I= c #4E0000",
-"J= c #2B2B2B",
-"K= c #8B8B8B",
-"L= c #9F5252",
-"M= c #A50000",
-"N= c #515151",
-"O= c #444444",
-"P= c #020101",
-"Q= c #8B4C4C",
-"R= c #B64F4F",
-"S= c #BD3B3B",
-"T= c #C52626",
-"U= c #CC1414",
-"V= c #D00A0A",
-"W= c #D40101",
-"X= c #CF0000",
-"Y= c #CC1313",
-"Z= c #B45252",
-"`= c #9E8C8C",
-" - c #5B5B5B",
-".- c #A47C7C",
-"+- c #BC3D3D",
-"@- c #500000",
-"#- c #222121",
-"$- c #948686",
-"%- c #9F4848",
-"&- c #A18383",
-"*- c #5B4F4F",
-"=- c #2C0000",
-"-- c #C80000",
-";- c #D20000",
-">- c #420000",
-",- c #C71E1E",
-"'- c #AF5F5F",
-")- c #9C9191",
-"!- c #9D8E8E",
-"~- c #B35555",
-"{- c #CA1717",
-"]- c #D30101",
-"^- c #B50000",
-"/- c #5B0000",
-"(- c #D00505",
-"_- c #CB1515",
-":- c #C42626",
-"<- c #BE3737",
-"[- c #B74848",
-"}- c #B15959",
-"|- c #AB6A6A",
-"1- c #A57979",
-"2- c #9F8888",
-"3- c #9C9090",
-"4- c #8F8888",
-"5- c #A13E3E",
-"6- c #A60000",
-"7- c #777777",
-"8- c #493030",
-"9- c #AE6161",
-"0- c #B45050",
-"a- c #BB3F3F",
-"b- c #C12E2E",
-"c- c #C71D1D",
-"d- c #CE0C0C",
-"e- c #D20101",
-"f- c #030000",
-"g- c #BE0000",
-"h- c #CF0808",
-"i- c #BE3535",
-"j- c #A67676",
-"k- c #A87070",
-"l- c #BD3737",
-"m- c #550505",
-"n- c #BA0000",
-"o- c #BB1111",
-"p- c #0F0202",
-"q- c #A67474",
-"r- c #A28181",
-"s- c #A23535",
-"t- c #0D0000",
-"u- c #2F2F2F",
-"v- c #A08585",
-"w- c #A47A7A",
-"x- c #A96D6D",
-"y- c #AD6161",
-"z- c #B25353",
-"A- c #B84343",
-"B- c #6B1F1F",
-"C- c #0E0000",
-"D- c #AB0000",
-"E- c #D00202",
-"F- c #C61D1D",
-"G- c #B25555",
-"H- c #141414",
-"I- c #161414",
-"J- c #440000",
-"K- c #CA0000",
-"L- c #1E0000",
-"M- c #340000",
-"N- c #470000",
-"O- c #380000",
-"P- c #D10101",
-"Q- c #CF0707",
-"R- c #CC0D0D",
-"S- c #CA1414",
-"T- c #C12B2B",
-"U- c #BD3838",
-"V- c #B74545",
-"W- c #B35252",
-"X- c #AE5F5F",
-"Y- c #A96C6C",
-"Z- c #A57878",
-"`- c #795F5F",
-" ; c #A32B2B",
-".; c #390000",
-"+; c #371818",
-"@; c #353535",
-"#; c #363131",
-"$; c #392828",
-"%; c #311515",
-"&; c #080202",
-"*; c #090505",
-"=; c #B32222",
-"-; c #C81717",
-";; c #CA1010",
-">; c #CC0A0A",
-",; c #CF0303",
-"'; c #5A0000",
-"); c #0A0000",
-"!; c #C40000",
-"~; c #2A0000",
-"{; c #BA3E3E",
-"]; c #A57777",
-"^; c #7D7D7D",
-"/; c #050505",
-"(; c #7B7B7B",
-"_; c #3E3E3E",
-":; c #570000",
-"<; c #D00101",
-"[; c #9A0202",
-"}; c #A52222",
-"|; c #A23E3E",
-"1; c #C41F1F",
-"2; c #CC0808",
-"3; c #CD0505",
-"4; c #9C0101",
-"5; c #C30000",
-"6; c #B90000",
-"7; c #160000",
-"8; c #BC3737",
-"9; c #505050",
-"0; c #404040",
-"a; c #0E0E0E",
-"b; c #070707",
-"c; c #4D0000",
-"d; c #B10000",
-"e; c #5D0000",
-"f; c #A61919",
-"g; c #A33535",
-"h; c #C41C1C",
-"i; c #210000",
-"j; c #CE0101",
-"k; c #CA0D0D",
-"l; c #BC3535",
-"m; c #AB6565",
-"n; c #8A8A8A",
-"o; c #0B0707",
-"p; c #AC4F4F",
-"q; c #C22323",
-"r; c #CC0707",
-"s; c #1F0000",
-"t; c #430000",
-"u; c #9A9494",
-"v; c #A71313",
-"w; c #A90000",
-"x; c #A42B2B",
-"y; c #C22020",
-"z; c #590000",
-"A; c #540000",
-"B; c #3A0000",
-"C; c #600000",
-"D; c #CD0101",
-"E; c #C71313",
-"F; c #B93B3B",
-"G; c #A86C6C",
-"H; c #9F8787",
-"I; c #AD5F5F",
-"J; c #BC3333",
-"K; c #C90D0D",
-"L; c #AE0000",
-"M; c #BD0000",
-"N; c #A80E0E",
-"O; c #AA0000",
-"P; c #A62222",
-"Q; c #BF2626",
-"R; c #C50000",
-"S; c #3B0000",
-"T; c #CB0303",
-"U; c #C21F1F",
-"V; c #B34A4A",
-"W; c #A57676",
-"X; c #9B9292",
-"Y; c #282828",
-"Z; c #3F3F3F",
-"`; c #A67272",
-" > c #B54848",
-".> c #C12020",
-"+> c #9D0202",
-"@> c #9B8B8B",
-"#> c #A90A0A",
-"$> c #A71818",
-"%> c #BC2E2E",
-"&> c #4F3232",
-"*> c #9F8686",
-"=> c #777171",
-"-> c #9B8686",
-";> c #AB0404",
-">> c #A90E0E",
-",> c #BA3535",
-"'> c #CA0101",
-")> c #5C0303",
-"!> c #484848",
-"~> c #AC0000",
-"{> c #9C8080",
-"]> c #AB0101",
-"^> c #510000",
-"/> c #510404",
-"(> c #571C1C",
-"_> c #150000",
-":> c #C60A0A",
-"<> c #BE2323",
-"[> c #B24A4A",
-"}> c #A57272",
-"|> c #494040",
-"1> c #101010",
-"2> c #1A0606",
-"3> c #C21A1A",
-"4> c #C90303",
-"5> c #9D7979",
-"6> c #4B0000",
-"7> c #0C0000",
-"8> c #C50D0D",
-"9> c #BC2A2A",
-"0> c #B14D4D",
-"a> c #A67171",
-"b> c #464646",
-"c> c #151515",
-"d> c #9E8989",
-"e> c #A86969",
-"f> c #B44444",
-"g> c #BF2121",
-"h> c #C70404",
-"i> c #9C7F7F",
-"j> c #BF0E0E",
-"k> c #590101",
-"l> c #2D0101",
-"m> c #260D0D",
-"n> c #231919",
-"o> c #212020",
-"p> c #202020",
-"q> c #414141",
-"r> c #A47474",
-"s> c #AF5252",
-"t> c #9C2E2E",
-"u> c #410000",
-"v> c #9C8585",
-"w> c #AC0404",
-"x> c #302020",
-"y> c #9F8585",
-"z> c #5C5B5B",
-"A> c #828282",
-"B> c #1D0202",
-"C> c #C60404",
-"D> c #9B8A8A",
-"E> c #AC0808",
-"F> c #190000",
-"G> c #C60101",
-"H> c #C30B0B",
-"I> c #BD1F1F",
-"J> c #812828",
-"K> c #2C2C2C",
-"L> c #171616",
-"M> c #9F8383",
-"N> c #A76868",
-"O> c #B04B4B",
-"P> c #B82E2E",
-"Q> c #C01616",
-"R> c #C50303",
-"S> c #AC0D0D",
-"T> c #C20C0C",
-"U> c #BB2222",
-"V> c #B43D3D",
-"W> c #AB5959",
-"X> c #A27878",
-"Y> c #9D8C8C",
-"Z> c #363636",
-"`> c #424242",
-" , c #171717",
-"., c #9D8B8B",
-"+, c #A47171",
-"@, c #AC5555",
-"#, c #B53838",
-"$, c #BD1C1C",
-"%, c #C40404",
-"&, c #AC1313",
-"*, c #2E0000",
-"=, c #631515",
-"-, c #595959",
-";, c #613C3C",
-">, c #140000",
-",, c #C00E0E",
-"', c #B82B2B",
-"), c #B04747",
-"!, c #A86464",
-"~, c #A08080",
-"{, c #9B9191",
-"], c #4A4A4A",
-"^, c #A07F7F",
-"/, c #683030",
-"(, c #400000",
-"_, c #B40000",
-":, c #AC1717",
-"<, c #A92C2C",
-"[, c #A56D6D",
-"}, c #550000",
-"|, c #9C0707",
-"1, c #B92323",
-"2, c #B23D3D",
-"3, c #AB5858",
-"4, c #A47272",
-"5, c #121212",
-"6, c #5C5C5C",
-"7, c #3A1616",
-"8, c #B53333",
-"9, c #BB1D1D",
-"0, c #C20404",
-"a, c #AB2020",
-"b, c #B00000",
-"c, c #A83636",
-"d, c #A37474",
-"e, c #C20000",
-"f, c #230000",
-"g, c #700101",
-"h, c #050101",
-"i, c #7F7F7F",
-"j, c #7E7E7E",
-"k, c #9B9090",
-"l, c #9F8484",
-"m, c #A47070",
-"n, c #AA5959",
-"o, c #B04343",
-"p, c #B62C2C",
-"q, c #BC1818",
-"r, c #B10707",
-"s, c #AA2A2A",
-"t, c #A64040",
-"u, c #A17B7B",
-"v, c #4B2525",
-"w, c #A76565",
-"x, c #A07C7C",
-"y, c #5A5757",
-"z, c #8F8585",
-"A, c #0C0B0B",
-"B, c #A93434",
-"C, c #A64949",
-"D, c #9F8181",
-"E, c #C00101",
-"F, c #B81F1F",
-"G, c #B23838",
-"H, c #AD4D4D",
-"I, c #603535",
-"J, c #0C0C0C",
-"K, c #898989",
-"L, c #585858",
-"M, c #656565",
-"N, c #A73D3D",
-"O, c #A45353",
-"P, c #9E8585",
-"Q, c #BF0404",
-"R, c #9F8080",
-"S, c #838383",
-"T, c #A64747",
-"U, c #B20000",
-"V, c #A35D5D",
-"W, c #9D8989",
-"X, c #BD0707",
-"Y, c #939393",
-"Z, c #161616",
-"`, c #A55050",
-" ' c #B30000",
-".' c #A26666",
-"+' c #9C8C8C",
-"@' c #BB0B0B",
-"#' c #BA0F0F",
-"$' c #2D2D2D",
-"%' c #212121",
-"&' c #555555",
-"*' c #A45A5A",
-"=' c #A07070",
-"-' c #9B8F8F",
-";' c #BA0E0E",
-">' c #B81717",
-",' c #606060",
-"'' c #262626",
-")' c #343434",
-"!' c #292929",
-"~' c #A26464",
-"{' c #320000",
-"]' c #9F7A7A",
-"^' c #9A9393",
-"/' c #B81111",
-"(' c #B42525",
-"_' c #616161",
-":' c #080808",
-"<' c #1D1D1D",
-"[' c #686868",
-"}' c #333333",
-"|' c #A16E6E",
-"1' c #715D5D",
-"2' c #6E6B6B",
-"3' c #820F0F",
-"4' c #B03434",
-"5' c #6F6F6F",
-"6' c #878787",
-"7' c #676767",
-"8' c #131313",
-"9' c #111111",
-"0' c #9F7777",
-"a' c #B50101",
-"b' c #220000",
-"c' c #AC4343",
-"d' c #222222",
-"e' c #808080",
-"f' c #9E7E7E",
-"g' c #B40303",
-"h' c #3D0000",
-"i' c #A85252",
-"j' c #646464",
-"k' c #565656",
-"l' c #666666",
-"m' c #4C4C4C",
-"n' c #9D8585",
-"o' c #B50505",
-"p' c #300000",
-"q' c #A46161",
-"r' c #8C8C8C",
-"s' c #0D0D0D",
-"t' c #787878",
-"u' c #9B8C8C",
-"v' c #B50808",
-"w' c #280000",
-"x' c #A17070",
-"y' c #1A1A1A",
-"z' c #4D4D4D",
-"A' c #4F4F4F",
-"B' c #B50A0A",
-"C' c #330000",
-"D' c #520000",
-"E' c #B60202",
-"F' c #9E7D7D",
-"G' c #060606",
-"H' c #818181",
-"I' c #2E2E2E",
-"J' c #181818",
-"K' c #232323",
-"L' c #636363",
-"M' c #2A2A2A",
-"N' c #6B6B6B",
-"O' c #4D2020",
-"P' c #3E0000",
-"Q' c #353030",
-"R' c #B50E0E",
-"S' c #3B0D0D",
-"T' c #B40606",
-"U' c #9C8888",
-"V' c #696969",
-"W' c #525252",
-"X' c #A74E4E",
-"Y' c #B40404",
-"Z' c #B31818",
-"`' c #AF2E2E",
-" ) c #A94444",
-".) c #B30A0A",
-"+) c #A35E5E",
-"@) c #B20A0A",
-"#) c #9A9191",
-"$) c #B22222",
-"%) c #AD3838",
-"&) c #A74B4B",
-"*) c #B11414",
-"=) c #A16C6C",
-"-) c #B00F0F",
-";) c #9A9292",
-">) c #B12B2B",
-",) c #AC4141",
-"') c #A55252",
-")) c #AD2323",
-"!) c #9E7C7C",
-"~) c #AF1414",
-"{) c #AF3535",
-"]) c #AA4B4B",
-"^) c #A35959",
-"/) c #AA3232",
-"() c #B20101",
-"_) c #AE1919",
-":) c #AD3F3F",
-"<) c #A85555",
-"[) c #A26060",
-"}) c #A74141",
-"|) c #AF0A0A",
-"1) c #AC1F1F",
-"2) c #AB4949",
-"3) c #A65E5E",
-"4) c #A16767",
-"5) c #A45050",
-"6) c #AD1414",
-"7) c #AB2424",
-"8) c #A95252",
-"9) c #A46868",
-"0) c #9F6E6E",
-"a) c #A15F5F",
-"b) c #AA2020",
-"c) c #A92B2B",
-"d) c #A75C5C",
-"e) c #A27171",
-"f) c #9E7474",
-"g) c #A82E2E",
-"h) c #A73232",
-"i) c #A56565",
-"j) c #9D7A7A",
-"k) c #AD0202",
-"l) c #9D7D7D",
-"m) c #A53D3D",
-"n) c #A63939",
-"o) c #A36F6F",
-"p) c #BD0202",
-"q) c #9E8383",
-"r) c #AC0303",
-"s) c #A34C4C",
-"t) c #A44040",
-"u) c #A17979",
-"v) c #BC0707",
-"w) c #9D8888",
-"x) c #9B8585",
-"y) c #AA0505",
-"z) c #A05B5B",
-"A) c #A34747",
-"B) c #9F8282",
-"C) c #BC0B0B",
-"D) c #9C8D8D",
-"E) c #A90707",
-"F) c #A81212",
-"G) c #9E6B6B",
-"H) c #A14E4E",
-"I) c #BB1010",
-"J) c #A90808",
-"K) c #A62121",
-"L) c #9C7A7A",
-"M) c #A05555",
-"N) c #BB1515",
-"O) c #A80A0A",
-"P) c #A43030",
-"Q) c #A80404",
-"R) c #9F5C5C",
-"S) c #BE0606",
-"T) c #B91C1C",
-"U) c #A70D0D",
-"V) c #A23F3F",
-"W) c #9A8C8C",
-"X) c #A60B0B",
-"Y) c #9E6363",
-"Z) c #BD1010",
-"`) c #B72626",
-" ! c #A51414",
-".! c #A04E4E",
-"+! c #A51313",
-"@! c #9D6A6A",
-"#! c #BA1A1A",
-"$! c #B43030",
-"%! c #A41B1B",
-"&! c #9E5E5E",
-"*! c #A41D1D",
-"=! c #9C7171",
-"-! c #B33A3A",
-";! c #A22222",
-">! c #9C6D6D",
-",! c #A22C2C",
-"'! c #9C7878",
-")! c #B72C2C",
-"!! c #B14343",
-"~! c #A12929",
-"{! c #9B7C7C",
-"]! c #A03B3B",
-"^! c #B43737",
-"/! c #AE4D4D",
-"(! c #A03030",
-"_! c #9A8A8A",
-":! c #9E4B4B",
-"<! c #A30202",
-"[! c #9A8484",
-"}! c #B24040",
-"|! c #AC5656",
-"1! c #9F3737",
-"2! c #A10A0A",
-"3! c #9D5A5A",
-"4! c #A20606",
-"5! c #9A8888",
-"6! c #AF4A4A",
-"7! c #A96060",
-"8! c #9E3E3E",
-"9! c #A01515",
-"0! c #9C6969",
-"a! c #AD5353",
-"b! c #A76A6A",
-"c! c #9D4545",
-"d! c #9F2020",
-"e! c #9B7777",
-"f! c #A00101",
-"g! c #9F0D0D",
-"h! c #998E8E",
-"i! c #AA5D5D",
-"j! c #A47373",
-"k! c #9C4C4C",
-"l! c #9D2E2E",
-"m! c #9A8383",
-"n! c #9F0404",
-"o! c #9E1010",
-"p! c #A86767",
-"q! c #C50202",
-"r! c #A27C7C",
-"s! c #9C5353",
-"t! c #9D3E3E",
-"u! c #9E0808",
-"v! c #9D1414",
-"w! c #A57070",
-"x! c #A08383",
-"y! c #9B5A5A",
-"z! c #9B4D4D",
-"A! c #9D0E0E",
-"B! c #9C1818",
-"C! c #A27A7A",
-"D! c #C50707",
-"E! c #9E8A8A",
-"F! c #9A6161",
-"G! c #9B1C1C",
-"H! c #9B1E1E",
-"I! c #C50909",
-"J! c #9A6868",
-"K! c #9A6B6B",
-"L! c #9B2B2B",
-"M! c #9B2525",
-"N! c #C80101",
-"O! c #C40C0C",
-"P! c #9A6F6F",
-"Q! c #9A3A3A",
-"R! c #9A2C2C",
-"S! c #9C8F8F",
-"T! c #C70707",
-"U! c #C31414",
-"V! c #997676",
-"W! c #9A0404",
-"X! c #998585",
-"Y! c #9A4949",
-"Z! c #9A3333",
-"`! c #C50E0E",
-" ~ c #C01E1E",
-".~ c #997D7D",
-"+~ c #990B0B",
-"@~ c #995858",
-"#~ c #993A3A",
-"$~ c #C31616",
-"%~ c #BD2828",
-"&~ c #998484",
-"*~ c #981313",
-"=~ c #996767",
-"-~ c #984141",
-";~ c #C21D1D",
-">~ c #BB3232",
-",~ c #998B8B",
-"'~ c #971E1E",
-")~ c #984848",
-"!~ c #BF2525",
-"~~ c #B83B3B",
-"{~ c #972D2D",
-"]~ c #984F4F",
-"^~ c #BD2E2E",
-"/~ c #B54545",
-"(~ c #950101",
-"_~ c #973C3C",
-":~ c #975656",
-"<~ c #B93838",
-"[~ c #B24F4F",
-"}~ c #940707",
-"|~ c #940B0B",
-"1~ c #B74141",
-"2~ c #AF5858",
-"3~ c #940E0E",
-"4~ c #975A5A",
-"5~ c #941A1A",
-"6~ c #976464",
-"7~ c #B44B4B",
-"8~ c #AC6262",
-"9~ c #941515",
-"0~ c #976969",
-"a~ c #942929",
-"b~ c #976B6B",
-"c~ c #B15555",
-"d~ c #A96B6B",
-"e~ c #931C1C",
-"f~ c #977777",
-"g~ c #943838",
-"h~ c #977272",
-"i~ c #AD5E5E",
-"j~ c #A67575",
-"k~ c #932323",
-"l~ c #988383",
-"m~ c #954747",
-"n~ c #910101",
-"o~ c #977979",
-"p~ c #AA6868",
-"q~ c #A27F7F",
-"r~ c #922A2A",
-"s~ c #955656",
-"t~ c #900202",
-"u~ c #977D7D",
-"v~ c #A77171",
-"w~ c #923131",
-"x~ c #900E0E",
-"y~ c #966565",
-"z~ c #8F0404",
-"A~ c #A47B7B",
-"B~ c #923838",
-"C~ c #901C1C",
-"D~ c #967474",
-"E~ c #8E0606",
-"F~ c #D00303",
-"G~ c #923F3F",
-"H~ c #902B2B",
-"I~ c #978484",
-"J~ c #8E0808",
-"K~ c #924646",
-"L~ c #913A3A",
-"M~ c #8C0404",
-"N~ c #8D0A0A",
-"O~ c #9D8D8D",
-"P~ c #CE0B0B",
-"Q~ c #CA1616",
-"R~ c #924D4D",
-"S~ c #924949",
-"T~ c #8C1010",
-"U~ c #8C0B0B",
-"V~ c #CD1010",
-"W~ c #C72020",
-"X~ c #925454",
-"Y~ c #935858",
-"Z~ c #8D1B1B",
-"`~ c #8C1111",
-" { c #C32929",
-".{ c #925B5B",
-"+{ c #946767",
-"@{ c #8D2828",
-"#{ c #8C1919",
-"${ c #C91C1C",
-"%{ c #C03434",
-"&{ c #936262",
-"*{ c #957777",
-"={ c #8E3737",
-"-{ c #8B1F1F",
-";{ c #978686",
-">{ c #8F4646",
-",{ c #8C2626",
-"'{ c #C22F2F",
-"){ c #B94747",
-"!{ c #947070",
-"~{ c #989494",
-"{{ c #915555",
-"]{ c #8C2D2D",
-"^{ c #BF3939",
-"/{ c #B55050",
-"({ c #870B0B",
-"_{ c #926464",
-":{ c #8C3434",
-"<{ c #B25A5A",
-"[{ c #957E7E",
-"}{ c #881A1A",
-"|{ c #947373",
-"1{ c #8D3B3B",
-"2{ c #B84C4C",
-"3{ c #AF6464",
-"4{ c #8A2929",
-"5{ c #968181",
-"6{ c #840101",
-"7{ c #8D4242",
-"8{ c #B45656",
-"9{ c #AB6D6D",
-"0{ c #978C8C",
-"a{ c #8B3838",
-"b{ c #840808",
-"c{ c #8E4949",
-"d{ c #B15F5F",
-"e{ c #978F8F",
-"f{ c #830404",
-"g{ c #8D4747",
-"h{ c #841010",
-"i{ c #8E5050",
-"j{ c #A38181",
-"k{ c #830A0A",
-"l{ c #8F5757",
-"m{ c #851818",
-"n{ c #8F5858",
-"o{ c #A97373",
-"p{ c #916666",
-"q{ c #862626",
-"r{ c #8F5E5E",
-"s{ c #A67B7B",
-"t{ c #D70505",
-"u{ c #821414",
-"v{ c #937575",
-"w{ c #883535",
-"x{ c #906565",
-"y{ c #A38282",
-"z{ c #D50C0C",
-"A{ c #821919",
-"B{ c #958484",
-"C{ c #8A4444",
-"D{ c #916C6C",
-"E{ c #D21414",
-"F{ c #831F1F",
-"G{ c #7F0505",
-"H{ c #8C5353",
-"I{ c #927373",
-"J{ c #D70909",
-"K{ c #CF1B1B",
-"L{ c #842424",
-"M{ c #8F6262",
-"N{ c #937A7A",
-"O{ c #D70C0C",
-"P{ c #CD2222",
-"Q{ c #842B2B",
-"R{ c #811B1B",
-"S{ c #917171",
-"T{ c #948181",
-"U{ c #D31414",
-"V{ c #C92B2B",
-"W{ c #853232",
-"X{ c #832828",
-"Y{ c #947E7E",
-"Z{ c #7C0303",
-"`{ c #968888",
-" ] c #D01D1D",
-".] c #C53535",
-"+] c #863939",
-"@] c #853737",
-"#] c #968989",
-"$] c #7B0707",
-"%] c #CC2727",
-"&] c #C13F3F",
-"*] c #864040",
-"=] c #884646",
-"-] c #7B0A0A",
-";] c #C83131",
-">] c #BD4949",
-",] c #874747",
-"'] c #8A5555",
-")] c #7C1414",
-"!] c #790404",
-"~] c #C43A3A",
-"{] c #B95252",
-"]] c #884E4E",
-"^] c #8D6464",
-"/] c #7F2424",
-"(] c #7A0B0B",
-"_] c #C04444",
-":] c #B55C5C",
-"<] c #895555",
-"[] c #907373",
-"}] c #823333",
-"|] c #7A1313",
-"1] c #BC4E4E",
-"2] c #B16565",
-"3] c #8B5C5C",
-"4] c #750101",
-"5] c #938181",
-"6] c #854242",
-"7] c #7B1919",
-"8] c #B85757",
-"9] c #AC6F6F",
-"0] c #8C6363",
-"a] c #760808",
-"b] c #885151",
-"c] c #7C2020",
-"d] c #B46161",
-"e] c #8D6A6A",
-"f] c #771010",
-"g] c #8B6161",
-"h] c #7D2828",
-"i] c #E00101",
-"j] c #A48282",
-"k] c #8F7171",
-"l] c #791818",
-"m] c #8E7070",
-"n] c #7E2E2E",
-"o] c #DF0505",
-"p] c #A28787",
-"q] c #917878",
-"r] c #7C2626",
-"s] c #927F7F",
-"t] c #7F3535",
-"u] c #A67E7E",
-"v] c #DE0A0A",
-"w] c #803C3C",
-"x] c #A18888",
-"y] c #DC0F0F",
-"z] c #938484",
-"A] c #710202",
-"B] c #824444",
-"C] c #710505",
-"D] c #824343",
-"E] c #DA1414",
-"F] c #948787",
-"G] c #710606",
-"H] c #865353",
-"I] c #741313",
-"J] c #834A4A",
-"K] c #E30202",
-"L] c #D71A1A",
-"M] c #958B8B",
-"N] c #710A0A",
-"O] c #8A6262",
-"P] c #782222",
-"Q] c #855252",
-"R] c #DF0B0B",
-"S] c #D32323",
-"T] c #710D0D",
-"U] c #8E7171",
-"V] c #7B3131",
-"W] c #865858",
-"X] c #DB1515",
-"Y] c #CF2D2D",
-"Z] c #711010",
-"`] c #6D0303",
-" ^ c #917E7E",
-".^ c #7F4141",
-"+^ c #885F5F",
-"@^ c #D71F1F",
-"#^ c #CA3737",
-"$^ c #711414",
-"%^ c #6D0707",
-"&^ c #948989",
-"*^ c #835050",
-"=^ c #8A6767",
-"-^ c #D32828",
-";^ c #C64141",
-">^ c #711717",
-",^ c #6D0B0B",
-"'^ c #875F5F",
-")^ c #C14A4A",
-"!^ c #721E1E",
-"~^ c #701515",
-"{^ c #8B6E6E",
-"]^ c #8E7474",
-"^^ c #C93B3B",
-"/^ c #BD5454",
-"(^ c #742525",
-"_^ c #742424",
-":^ c #907D7D",
-"<^ c #907C7C",
-"[^ c #C44646",
-"}^ c #B85E5E",
-"|^ c #762C2C",
-"1^ c #793434",
-"2^ c #670101",
-"3^ c #928282",
-"4^ c #C04F4F",
-"5^ c #B36767",
-"6^ c #783333",
-"7^ c #7D4343",
-"8^ c #969191",
-"9^ c #690A0A",
-"0^ c #BB5959",
-"a^ c #AE7171",
-"b^ c #793A3A",
-"c^ c #6C1616",
-"d^ c #660202",
-"e^ c #958E8E",
-"f^ c #B66262",
-"g^ c #E90101",
-"h^ c #AA7979",
-"i^ c #7B4141",
-"j^ c #866161",
-"k^ c #702222",
-"l^ c #680808",
-"m^ c #B16C6C",
-"n^ c #A68080",
-"o^ c #7D4848",
-"p^ c #8B7070",
-"q^ c #680D0D",
-"r^ c #AC7676",
-"s^ c #E80606",
-"t^ c #A28888",
-"u^ c #7F4F4F",
-"v^ c #793F3F",
-"w^ c #691212",
-"x^ c #979393",
-"y^ c #A77F7F",
-"z^ c #E70808",
-"A^ c #9F8F8F",
-"B^ c #815656",
-"C^ c #7E4E4E",
-"D^ c #6A1717",
-"E^ c #E60B0B",
-"F^ c #835D5D",
-"G^ c #630505",
-"H^ c #6C1D1D",
-"I^ c #EB0404",
-"J^ c #E31212",
-"K^ c #856464",
-"L^ c #886C6C",
-"M^ c #6D2222",
-"N^ c #E70B0B",
-"O^ c #DE1C1C",
-"P^ c #886B6B",
-"Q^ c #6C2222",
-"R^ c #8E7B7B",
-"S^ c #6E2828",
-"T^ c #E41313",
-"U^ c #D92525",
-"V^ c #8A7272",
-"W^ c #713232",
-"X^ c #723434",
-"Y^ c #E01A1A",
-"Z^ c #D52F2F",
-"`^ c #8C7878",
-" / c #774141",
-"./ c #774343",
-"+/ c #DC2121",
-"@/ c #CF3939",
-"#/ c #8E7D7D",
-"$/ c #7C5151",
-"%/ c #D82A2A",
-"&/ c #CA4242",
-"*/ c #908383",
-"=/ c #846464",
-"-/ c #836363",
-";/ c #D33434",
-">/ c #C54C4C",
-",/ c #928888",
-"'/ c #8A7474",
-")/ c #8C7979",
-"!/ c #C05656",
-"~/ c #948D8D",
-"{/ c #918585",
-"]/ c #C84747",
-"^/ c #BA5F5F",
-"// c #C35050",
-"(/ c #B56969",
-"_/ c #BE5A5A",
-":/ c #B07373",
-"</ c #B86464",
-"[/ c #AA7C7C",
-"}/ c #B36D6D",
-"|/ c #A48686",
-"1/ c #AD7777",
-"2/ c #F40101",
-"3/ c #F30404",
-"4/ c #F00A0A",
-"5/ c #F10909",
-"6/ c #EA1414",
-"7/ c #EF0E0E",
-"8/ c #E51D1D",
-"9/ c #EC1313",
-"0/ c #DF2727",
-"a/ c #E91818",
-"b/ c #DA3131",
-"c/ c #D43A3A",
-"d/ c #DE2B2B",
-"e/ c #CE4444",
-"f/ c #D93535",
-"g/ c #C94D4D",
-"h/ c #D23E3E",
-"i/ c #C35757",
-"j/ c #CD4848",
-"k/ c #C75252",
-"l/ c #C15B5B",
-"m/ c #B07474",
-"n/ c #BB6565",
-"o/ c #AA7E7E",
-"p/ c #B56E6E",
-"q/ c #A48888",
-"r/ c #A08F8F",
-"s/ c #9B9797",
-" ",
-" ",
-" ",
-" ",
-" ",
-" . + ",
-" @ # ",
-" $ % ",
-" & * ",
-" = - ",
-" ; > ",
-" , ' ",
-" ) ! ",
-" ~ { ",
-" ] ^ ",
-" / ( ",
-" _ : ",
-" + < [ ",
-" } | 1 ",
-" 2 3 4 ",
-" 5 6 7 ",
-" 8 9 0 ",
-" a b c + ",
-" d e e f ",
-" g h h i ",
-" j h h k ",
-" l m m n ",
-" o m m p ",
-" q r r s ",
-" t u u v ",
-" w u u x ",
-" y z z A ",
-" + B z z C ",
-" D E F F G ",
-" # H I I J ",
-" K L I I M ",
-" N O P P Q ",
-" R P P P S + ",
-" T U U U V K ",
-" W U U U X Y ",
-" Z ` ` ` ... ",
-" +.` ` ` @.#. ",
-" $.%.%.%.%.&. ",
-" *.=.=.=.=.-. ",
-" ;.=.=.=.=.>. ",
-" ,.'.'.'.'.). ",
-" !.'.'.'.'.~. ",
-" {.].].].].^. ",
-" /.].].].].(. ",
-" _.:.:.:.:.<. ",
-" [.}.}.}.}.|. ",
-" 1.}.}.}.}.2. ",
-" 3.4.4.4.4.4.5.6. ",
-" 7.4.4.4.4.4.8.3. ",
-" 9.0.0.0.0.0.a.b. ",
-" c.0.0.0.0.0.d.7. ",
-" e.f.f.f.f.f.g.h. ",
-" i.j.j.j.j.j.j.k. ",
-" l.j.j.j.j.j.j.m. ",
-" n.o.o.o.o.o.o.p. ",
-" q.o.o.o.o.o.o.r. ",
-" s.t.t.t.t.t.t.u. ",
-" v.w.w.w.w.w.w.x. ",
-" y.w.w.w.w.w.w.z. ",
-" A.B.B.B.B.B.B.C. ",
-" D.B.B.B.B.B.B.E. ",
-" + F.G.G.G.G.G.G.H. ",
-" I.J.G.G.G.G.G.G.K.6. ",
-" L.M.N.N.N.N.N.N.O.P. ",
-" Q.R.N.N.N.N.N.N.S.T. ",
-" U.V.W.W.W.W.W.W.X.Y. ",
-" Z.`.`.`.`.`.`.`. +.+ ",
-" ++`.`.`.`.`.`.`.`. at + ",
-" #+$+$+$+$+$+$+$+$+U. ",
-" %+$+$+$+$+$+$+$+$+&+ ",
-" *+=+=+=+=+=+=+=+=+-+ ",
-" ;+=+=+=+=+=+=+=+=+>+ ",
-" ,+'+'+'+'+'+'+'+'+)+ ",
-" !+~+~+~+~+~+~+~+~+{+ ",
-" ]+~+~+~+~+~+~+~+~+^+ ",
-" /+(+(+(+(+(+(+(+(+_+ ",
-" 6.:+(+(+(+(+(+(+(+(+<+ ",
-" T.[+}+}+}+}+}+}+}+}+|+ ",
-" 1+2+}+}+}+}+}+}+}+}+3+ ",
-" 4+5+6+6+6+6+6+6+6+6+7+ ",
-" 8+9+0+0+0+0+0+0+0+0+a+ ",
-" b+0+0+0+0+0+0+0+0+0+c+6. ",
-" d+e+e+e+e+e+e+e+e+e+e+1+ ",
-" f+e+e+e+e+e+e+e+e+e+e+g+ ",
-" h+i+i+i+i+i+i+i+i+i+i+j+ ",
-" k+l+l+l+l+l+l+l+l+l+l+m+ ",
-" n+l+l+l+l+l+l+l+l+l+l+o+ ",
-" + p+q+r+s+t+u+v+w+x+y+z+ A+B+B+B+B+B+B+B+B+B+B+C+ + D+E+F+G+H+I+J+K+L+M+N+ ",
-" O+P+Q+R+S+T+U+V+W+X+M+ Y+B+B+B+B+B+B+B+B+B+B+Z+ `+ @. at +@@@#@$@%@&@*@=@+ ",
-" N+-@;@>@,@#@,@'@)@!@N+ ~@{@{@{@{@{@{@{@{@{@{@]@ ^@/@(@_@:@:@<@[@}@|@ ",
-" |@1 at 2@3@:@:@3 at 4@5 at 6@ 7@{@{@{@{@{@{@{@{@{@{@8@ + M+9 at 0@a at a@a@<@4 at b@+ ",
-" c at d@e at f@a at a@a at g@h at i@ 6.j at k@k at k@k at k@k at k@k at k@k at l@ m at n@o at p@p at p@p at q@r at z+ ",
-" s at t@u at p@p at p@v at w@d@ x at y@k at k@k at k@k at k@k at k@k at k@z@ A at B@C at D@D at D@D at E@F at m@ ",
-" G at H@I at D@D at D@D at J@K at + L at M@N at N@N at N@N at N@N at N@N at N@O@ M+P at Q@R at R@R at R@S at T@ ",
-" T at U@R at R@R at R@R at V@M+ W at X@Y at Y@Y at Y@Y at Y@Y at Y@Y at Y@Z@ `@ #.#+#+#+#+#@###O+ ",
-" 6@$#%#R at R@R at R@%#&#c@ *#=#Y at Y@Y at Y@Y at Y@Y at Y@Y at Y@-# ;#>#,#,#,#,#,#'#)# ",
-" !#~#+#+#+#+#+#{#]# ^#/#/#/#/#/#/#/#/#/#/#/#(#_# :#<#[#[#[#[#[#}#|#c@ ",
-" 1#2#,#,#,#,#,#3#4#+ 5#/#/#/#/#/#/#/#/#/#/#/#X at 6# 7#8#9#9#9#9#9#0#a#c@ ",
-" ;#b#[#[#[#[#[#c#d#+ e#f#f#f#f#f#f#f#f#f#f#f#g#h# i#j#9#9#9#9#9#k#a# ",
-" l#m#9#9#9#9#9#9#n#o# p#f#f#f#f#f#f#f#f#f#f#f#q#r# s#t#u#u#u#u#u#u#v#+ ",
-" O+w#u#u#u#u#u#u#x#y# z#A#A#A#A#A#A#A#A#A#A#A#B#C# + D#E#E#E#E#E#E#F#G# ",
-" c at H#E#E#E#E#E#E#E#I# J#K#K#K#K#K#K#K#K#K#K#K#K#e# L#M#N#N#N#N#N#N#M#O# ",
-" P#Q#N#N#N#N#N#N#R#S# T#K#K#K#K#K#K#K#K#K#K#K#K#U# V#W#W#W#W#W#W#W#X#N+ ",
-" z+Y#W#W#W#W#W#W#W#Z# `# $ $ $ $ $ $ $ $ $ $ $ $.$ +$@$#$#$#$#$#$#$#$$$ ",
-" %$#$#$#$#$#$#$#$&$*$ =$ $ $ $ $ $ $ $ $ $ $ $ $-$ ;$>$>$>$>$>$>$>$,$z+ ",
-" '$,$>$>$>$>$>$>$>$)$O+ !$~$~$~$~$~$~$~$~$~$~$~$~${$ ]$^$^$^$^$^$^$^$^$]$ ",
-" /$^$^$^$^$^$^$^$^$($ _$~$~$~$~$~$~$~$~$~$~$~$~$:$ <$[$[$[$[$[$[$[$[$}$`@ ",
-" |$^$^$^$^$^$^$^$^$1$ 2$3$3$3$3$3$3$3$3$3$3$3$3$4$ 6 at 5$6$6$6$6$6$6$6$5$7$ ",
-" O+8$[$[$[$[$[$[$[$[$9$ 0$a$a$a$a$a$a$a$a$a$a$a$a$b$ c$d$d$d$d$d$d$d$d$e$ ",
-" f$6$6$6$6$6$6$6$6$6$g$ h$a$a$a$a$a$a$a$a$a$a$a$a$i$ j$k$k$k$k$k$k$k$k$l$ ",
-" m$d$d$d$d$d$d$d$d$d$n$ 6.o$p$p$p$p$p$p$p$p$p$p$p$p$q$ r$k$k$k$k$k$k$k$k$s$6@ ",
-" t$k$k$k$k$k$k$k$k$k$u$ v$p$p$p$p$p$p$p$p$p$p$p$p$p$w$x@ x$y$y$y$y$y$y$y$y$z$A$ ",
-" B$y$y$y$y$y$y$y$y$y$C$ D$E$E$E$E$E$E$E$E$E$E$E$E$E$F$G$ H$I$J$J$J$J$J$J$J$J$K$L$ ",
-" M$J$J$J$J$J$J$J$J$J$N$L$ O$P$P$P$P$P$P$P$P$P$P$P$P$P$Q$R$ S$T$T$T$T$T$T$T$T$T$T$U$ ",
-" V$T$T$T$T$T$T$T$T$T$T$W$N+ X$P$P$P$P$P$P$P$P$P$P$P$P$P$Y$Z$ `$ %.%.%.%.%.%.%.%.%.%+%L$ ",
-" @%.%.%.%.%.%.%.%.%.%.%#%$%%%&%*%=% -%;%;%;%;%;%;%;%;%;%;%;%;%;%>%,% '%)%!%!%!%!%!%!%!%!%!%!%~%{% ",
-" ]%!%!%!%!%!%!%!%!%!%^%/%(%_%_%_%:%<%[% }%;%;%;%;%;%;%;%;%;%;%;%;%;%;%|% c at 1%2%#%#%#%#%#%#%#%#%#%#%#%3%`@ ",
-" 4%5%#%#%#%#%#%#%#%6%7%_%_%_%_%_%_%_%8%=% 9%0%0%0%0%0%0%0%0%0%0%0%0%0%0%a% {%b%c%d%d%d%d%d%d%d%d%d%d%d%d%e% ",
-" f%d%d%d%d%d%d%g%h%_%_%_%_%_%_%_%_%_%i%j% k%0%0%0%0%0%0%0%0%0%0%0%0%0%0%l% m%n%n%n%n%n%o% =%n%n%n%n%n%n%n%n%n%p%q%r%s%s%s%s%s%s%s%s%s%s%s%s%s%t%u% ",
-" v%w%d%d%d%d%d%~+_%_%_%_%_%_%_%_%_%_%x%y% z%A%A%A%A%A%A%A%A%A%A%A%A%A%A%B% C%_%_%_%_%_%D% j%E%F%G%_%_%_%_%_%_%_%_%_%_%_%_%H%I%}.J%K%K%K%K%K%K%K%K%K%K%L% ",
-" + M%s%s%s%s%s%N%_%_%_%_%_%_%_%_%_%_%_%O%P%`@ Q%A%A%A%A%A%A%A%A%A%A%A%A%A%A%R% C%_%_%_%_%_%D% S%T%U%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%V%A%W%W%W%W%W%W%W%W%X%Y% ",
-" 4%Z%K%K%K%K%`%_%_%_%_%_%_%_%_%_%_%_%f. &.&+&@& #&$&$&$&$&$&$&$&$&$&$&$&$&$&$&%& C%_%_%_%_%_%D% &&*&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%=&P$-&-&-&-&-&-&;&>& ",
-" ,&'&W%W%W%)&_%_%_%_%_%_%_%_%_%_%_%B+W%W%W%!&~&{&N+ ]&^&^&^&^&^&^&^&^&^&^&^&^&^&^&/& C%_%_%_%_%_%D% (&_&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%:&<&-&-&-&-&-&[&`@ ",
-" }&|&-&-&l+_%_%_%_%_%_%_%_%_%_%1&2&-&-&-&-&-&-&3&4&5&6&+ 7&^&^&^&^&^&^&^&^&^&^&^&^&^&^&8& C%_%_%_%_%_%D% 9&0&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%a&b&b&b&b&c&N+ ",
-" d&e&b&f&I%_%_%_%_%_%_%_%_%_%r g&b&b&b&b&b&b&b&b&b&h&i&j&Y%k& l&m&m&m&m&m&m&m&m&m&m&m&m&m&m&n& C%_%_%_%_%_%D% *%_%_%_%_%_%_%o&V%p&p&p&p&p&p&p&p&p&q&H%_%_%_%_%_%r&s&g&g&t&u& ",
-" P%v&g&w&x&_%_%_%_%_%_%H%)&y&g&g&g&g&g&g&g&g&g&g&g&g&g&z&A&B&C&D& x at E&m&m&m&m&m&m&m&m&m&m&m&m&m&m&]&+ C%_%_%_%_%_%D% F&G&H&I&_%_%_%_%_%r&J&K&L&L&L&L&L&L&L&L&s&M&}.H%_%_%_%_%(%N&O&P&k& ",
-" Q&R&S&2&T&1&_%_%_%U&'+f&S&S&S&S&S&S&S&S&S&S&S&S&S&S&S&S&S&S&V&A&W&X&Y&+ Z&`& * * * * * * * * * * * * * *.*6. C%_%_%_%_%_%D% +*@*#*$*%*&***=*_%_%_%_%_%z ************************s&q&_%_%_%_%H%-*;*`@ ",
-" `@>*,***'*)* *N&g%**************************************************!*~*H&{*@&c@ ]*^* * * * * * * * * * * * * * */*(* C%_%_%_%_%_%D% N+_*:*<*[*}*g%g%g%g%g%g%|*_%_%_%_%_%N.g%g%g%g%g%g%g%g%g%g%g%g%g%I%_%_%_%_%_%1* ",
-" 2*3*g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%4*5*6*;*{*4%c@ 7*8*9*9*9*9*9*9*9*9*9*9*9*9*9*9*0*L@ C%_%_%_%_%_%D% a*Y&b*c*d*e*f*g*g*g*g*g*g*g*g*g*g*h*i*i*i*i*i*`.g*g*g*g*g*g*g*g*g*g*g*g*g*j*_%_%_%_%_%k* ",
-" l*m*n*o*(+(+(+(+(+(+p*g*g*g*g*g*g*g*g*g*g*g*g*g*g*g*g*g*L&y&y&y&y&y&y&y&y&y&y&f&g*q*r*3*s*t*2*u*+ v*w*x*x*x*x*x*x*x*x*x*x*x*x*x*x*y*z* C%_%_%_%_%_%D% a*A*B*C*D*E*F*f&f&f&f&f&f&f&f&f&f&f&f&f&f&f&G*H*H*H*H*H*M&f&f&f&f&f&f&f&f&f&f&f&f&f&j*_%_%_%_%_%k* ",
-" I*_%_%_%_%_%_%_%_%_%=+f&f&f&f&f&f&f&f&f&f&f&f&f&J*j.K*L*M*:&:&:&:&:&:&:&:&:&:&q&N*O*B+P*f&f&Q*R*S*T*U*V*W*6& X*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*w*Y* C%_%_%_%_%_%D% `@Z*`* =.=+=@=#=L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&I%_%_%_%_%_%k* ",
-" I*_%_%_%_%_%_%_%_%_%$+f&f&f&f&f&f&f&f&f&f&f&$=%=&=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%r&i+'*f&f&f&f&f&f&f&Q**=D*==-=;=>=+*`@j%=%,='=)=)=)=)=)=)=)=)=)=)=!=~={= 9&]=)=)=)=)=)= o%)=)=)=)=)=^= /=(=(=(=(=(=(=(=(=(=(=(=;%w.0.0.0._=)=)=)=)=)=)=)='=,=o%j% C%_%_%_%_%_%D% m%'=)=)=)=)=)=:= N+6&<=[=}=|=.*1=p$p$p$p$p$p$p$p$p$p$2=3=y&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&4= =5=_%_%_%_%_%k* ",
-" I*_%_%_%_%_%_%_%_%_%$+L&L&L&L&L&L&L&L&L&L&6=7=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%8=9=0=L&L&L&L&L&L&L&s&s&s&s&s&a=b=c=d=:%_%_%_%_%_%_%_%_%_%_%_%_%_%e=f=g=9& h=G%_%_%_%_%_& i=_%_%_%_%_%j= k=(=(=(=(=(=(=(=(=(=(=$&I%_%_%_%_%_%_%_%_%_%_%_%_%_%_%l=m=n= C%_%_%_%_%_%D% S%o=_%_%_%_%_%_&E% p=q=r=s=t=u=v=w=x='*x*y=z=_%_%_%_%_%_%_%_%_%_%_%_%_%(%A=A#K&'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*b=B=q= C=_%_%_%_%_%k* ",
-" D=_%_%_%_%_%_%_%_%_%E=F=G=s&s&s&s&s&s&s&2&H=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%I=K&s&s&s&s&s&s&s&'*'*'*'*'*j.&=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%J=K= h=G%_%_%_%_%_& i=_%_%_%_%_%j= L=M=M=M=M=M=M=M=M=M=M==+H%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%x%N=&& C%_%_%_%_%_%D% j%O=_&_%_%_%_%_%P=Q=R=S=T=U=V=W='*'*'*'*'*X=u (%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%8=O*<&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&Y=Z=`= C=_%_%_%_%_%k* ",
-" D=_%_%_%_%_%_%_%_%_% -+ .-+-x='*'*'*'*'*@-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%H%4.'*'*'*'*'*'*y&y&y&y&y&`.8=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%#-$-+ h=G%_%_%_%_%_& i=_%_%_%_%_%j= %-M=M=M=M=M=M=M=M=M=M='._%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_&N= C%_%_%_%_%_%D% F&&-*-_&_%_%_%_%_%_%=---y&y&y&y&y&y&y&y&y&y&;-u H%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%>-P*;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-,-'-)- C=_%_%_%_%_%k* ",
-" i%_%_%_%_%_%_%_%_%_% - !-~-{-]-y&2=H%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%z=3=y&y&y&y&y&y&y&y&y&^-1&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%/-(-_-:-<-[-}-|-1-2-3-4-G%_%_%_%_%_& i=_%_%_%_%_%j= 5-6-6-6-6-6-6-6-6-6-6-t._%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%x%7- C%_%_%_%_%_%8-9-0-a-b-c-d-e-A#f-_%_%_%_%_%_%p&g-;-;-;-;-;-;-;-;-;-;-;-m&8=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%o.;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-h-i-j-+ C=_%_%_%_%_%k* ",
-" i%_%_%_%_%_%_%_%_%_% - p=k-l-m-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%G.;-;-;-;-;-;-;-;-;-T&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%=&n-;-;-;-;-;-;-;-;-h-o-p-_%_%_%_%_&q-r-2-6&p= i=_%_%_%_%_%j= s-2=2=2=2=2=2=2=2=2=2=a$t-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%u-j%+ +*q=v-w-x-y-z-A-B-_%_%_%_%_%/-P*P*P*P*P*P*M=C-_%_%_%_%_%_%7%D-P*P*P*P*P*P*P*P*P*P*P*P*K*_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%r&--P*P*P*P*P*P*P*P*P*P*P*P*P*P*P*E-F-G-u* H-_%_%_%_%_%l* ",
-" i%_%_%_%_%_%_%_%_%_% - I-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%J-P*P*P*P*P*P*P*P*K-L-_%_%_%_%_%(%M-N-N%N%N%N%N%N%N%N%O-1&_%_%_%_%_%_%N.P*P*P*P*P*P*P*P*P*J*M*_%_%_%_%H%P*P-Q-R-S-F-T-U-V-W-X-Y-Z-`-_%_%_%_%_%j= ;2=2=2=2=2=2=2=2=2=2=2=B.y=.;.;.;+;@;@;@;@;@;#;$;%;&;_%_%_%_%_%*;=;-;;;>;,;K&K&K&K&K&f._%_%_%_%_%';K&K&K&K&K&^-h%_%_%_%_%_%_%);p$K&K&K&K&K&K&K&K&K&K&K&K&!;(%_%_%_%_%_%H%~;N-N-N-N-N-N-N-N-N-y=q&_%_%_%_%_%H%E$K&K&K&K&K&K&K&K&K&K&K&K&K&;;{;];k& ^;/;_%_%_%_%e=(; ",
-" _;_%_%_%_%_%_%_%_%_% - [%:%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%=-K&K&K&K&K&K&K&K&n-);_%_%_%_%_%N at X=K&K&K&K&K&K&K&K&K&X=x*t-_%_%_%_%_%:;K&K&K&K&K&K&K&K&K&J*M*_%_%_%_%H%K&K&K&K&K&K&K&K&K&K&K&K&<;[;_%_%_%_%_%j= };J&J&J&J&J&J&J&J&J&J&J&J&J&J&J&J&|; p=1;2;3;4;o&_%_%_%_%_%(=X=X=X=X=X=X=X=X=X=f._%_%_%_%_%';X=X=X=X=5;H=_%_%_%_%_%_%f-~+X=X=X=X=X=X=X=X=X=X=X=X=X=6-_%_%_%_%_%H%].M&X=X=X=X=X=X=X=X=X=X=6;7;_%_%_%_%_%4.X=X=X=X=X=X=X=X=X=X=2;8;Y-+* n%9;9;9;9;9;9;9;0;a;_%_%_%_%_%l==% ",
-" _;_%_%_%_%_%_%_%_%_% - K=b;_%_%_%_%_%_%_%_%i*m %.%.%.%.%.%.%.%.c;_%_%_%_%_%_%_%_%_%x&X=X=X=X=X=X=X=X=d;H%_%_%_%_%M*X=X=X=X=X=X=X=X=X=X=X=X=X=e;_%_%_%_%_%/%X=X=X=X=X=X=X=X=X=^%M*_%_%_%_%H%X=X=X=X=X=X=X=X=X=X=X=X=X=P$_%_%_%_%_%j= + f;J&J&J&J&J&J&J&J&J&J&J&J&J&J&J&J&g; `@h;J%J%$=N*_%_%_%_%_%A#J%J%J%J%J%J%J%J%J%0._%_%_%_%_%';J%J%J%K-K*_%_%_%_%_%_%H%` J%J%J%J%J%J%J%J%J%J%J%J%J%J% $_%_%_%_%_%i;K-J%J%J%J%J%J%J%J%J%J%J%J%@-_%_%_%_%_%%=J%J%J%J%J%J%j;k;l;m;a* *%_%_%_%_%_%_%_%_%_%_%_%_%_%_%m= ",
-" _;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%o;p;q;r;J%J%J%J%J%J%^&_%_%_%_%_%_%_%_%_%p&J%J%J%J%J%J%J%J%6%H%_%_%_%_%s;J%J%J%J%J%J%J%J%J%J%J%J%J%B._%_%_%_%_%t;J%J%J%J%J%J%J%J%J%g-:&_%_%_%_%H%J%J%J%J%J%J%J%J%J%J%J%J%J%E$_%_%_%_%_%j= u;v;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;x; + y;0=0=0=7=_%_%_%_%_%/#0=0=0=0=0=0=0=0=0=0._%_%_%_%_%z;0=0=$=T&_%_%_%_%_%_%_%A;M&0=0=0=0=0=0=0=0=0=0=0=0=0=0=A#_%_%_%_%_%B;0=0=0=0=0=0=0=0=0=0=0=0=0=a&_%_%_%_%_%C;0=0=0=D;E;F;G;)- *%_%_%_%_%_%_%_%_%_%_%_%_%_%e=n= ",
-" _;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S%+ H;I;J;K;0=0=0=$&_%_%_%_%_%_%_%_%_%p&0=0=0=0=0=0=0=0=L;H%_%_%_%_%s;0=0=0=0=0=0=0=0=0=0=0=0=0=B._%_%_%_%_%t;0=0=0=0=0=0=0=0=0=M;:&_%_%_%_%H%0=0=0=0=0=0=0=0=0=0=0=0=0=E$_%_%_%_%_%j= z*N;O;O;O;O;O;O;O;O;O;O;O;O;O;O;O;O;P; Q;M&M&M&7=_%_%_%_%_%Y at M&M&M&M&M&M&M&M&M&4._%_%_%_%_%z;M&M&].8=_%_%_%_%_%_%y=R;M&M&M&M&M&M&M&M&M&M&M&M&M&M&M&A#_%_%_%_%_%S;M&M&M&M&M&M&M&M&M&M&M&M&M&a&_%_%_%_%_%C;T;U;V;W;X; *%_%_%_%_%_%_%_%_%_%_%_%_%_%Y; ",
-" Z;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% )-`; >.>+>_%_%_%_%_%_%_%_%_%p&M&M&M&M&M&M&M&M&)*H%_%_%_%_%L-M&M&M&M&M&M&M&M&M&M&M&M&M&B._%_%_%_%_%t;M&M&M&M&M&M&M&M&M&H*:&_%_%_%_%H%M&M&M&M&M&M&M&M&M&M&M&M&M&p$_%_%_%_%_%j= @>#>O;O;O;O;O;O;O;O;O;O;O;O;O;O;O;O;$> %>$=$=$=7=_%_%_%_%_%N@$=$=$=$=$=$=$=$=$=4._%_%_%_%_%T&$=l+i*_%_%_%_%_%_%H=M;$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=f#_%_%_%_%_%S;$=$=$=$=$=$=$=$=$=$=$=$=$=e;_%_%_%_%_%&>*>`@ *%_%_%_%_%_%_%_%_%_%_%_%_%_%e=n= ",
-" 0;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% =>_%_%_%_%_%_%_%_%_%p&M&M&M&M&M&$=$=$=)*H%_%_%_%_%L-$=$=$=$=$=$=$=$=$=$=$=$=$=w._%_%_%_%_%t;$=$=$=$=$=$=$=$=$=6=:&_%_%_%_%H%$=$=$=$=$=$=$=$=$=$=$=$=$=a$_%_%_%_%_%j= ->;>D-D-D-D-D-D-D-D-D-D-D-D-D-D-D-D->> ,>$=$=$=7=_%_%_%_%_%N@$=$=$=$=$=$=$=$=$=}._%_%_%_%_%T&$&z=_%_%_%_%_%_%p&^-$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=/#_%_%_%_%_%S;K-K-K-K-K-K-K-K-K-K-K-K-'>)>_%_%_%_%_%!> *%_%_%_%_%_%_%_%_%_%_%_%_%_%_%u- ",
-" 0;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%p&$=$=$=$=$=K-K-K-~>H%_%_%_%_%L-K-K-K-K-K-K-K-K-K-K-K-K-K-w._%_%_%_%_%>-K-K-K-K-K-K-K-K-K-n-:&_%_%_%_%H%K-K-K-K-K-K-K-K-K-K-K-K-K-a$_%_%_%_%_%j= {>]>D-D-D-D-D-D-D-D-D-D-D-0%4.|*^>^>/>!>!>!>!>!>(>C;=*'.p&_%_%_%_%_%k at K-K-K-K-K-K-K-K-K-:._%_%_%_%_%y=_>_%_%_%_%_%_%:&6-K-K-K-K-K-K-K-K-K-K-K-K-K-K-K-K-K-K-Y at _%_%_%_%_%S;<&<&<&<&<&<&<&<&<&:><>[>}>|>_%_%_%_%_%!> n%N=N=N=N=N=N=9;0;1>_%_%_%_%_%l=o% ",
-" 0;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%2>3>4>K-K-K-K-<&<&D-H%_%_%_%_%L-<&<&<&<&<&<&<&<&<&<&<&<&<&t._%_%_%_%_%>-<&<&<&<&<&<&<&<&<&n-:&_%_%_%_%H%<&<&<&<&<&<&<&<&<&<&<&<&<&3$_%_%_%_%_%j= 5>~>~>~>~>~>~>~>~>~>~>$&6>7>_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%{@<&<&<&<&<&<&<&<&<&:._%_%_%_%_%H%_%_%_%_%_%_%=&A#<&<&<&<&<&<&<&<&<&<&<&<&<&<&<&<&<&<&<&Y at _%_%_%_%_%B;----------8>9>0>a>q= b>_%_%_%_%_%!> ,=/;_%_%_%_%e=,= ",
-" 0;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c>p=d>e>f>g>h>----O;H%_%_%_%_%L---------------------------t._%_%_%_%_%>-------------------6;:&_%_%_%_%H%--------------------------~$_%_%_%_%_%j= i>~>~>~>~>~>~>~>~>~> $h%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%{@------------------]._%_%_%_%_%_%_%_%_%_%_%f-N.G*--------------------------------------N at _%_%_%_%_%B;G*j>k>l>m>n>o>p>p>p>p>p>p>0&_%_%_%_%_%!> H-_%_%_%_%_%l* ",
-" q>_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> a*r>s>t>_%_%_%_%_%L---------------------------o._%_%_%_%_%u>------------------N&:&_%_%_%_%H%--------------------------~$_%_%_%_%_%j= v>w>)*)*)*)*)*)*)*^&h%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%B+G*G*G*G*G*G*G*G*G*]._%_%_%_%_%_%_%_%_%_%_%z;G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*k at _%_%_%_%_%x>y>z>_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%!> C=_%_%_%_%_%k* ",
-" q>_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_%B>C>G*G*G*G*G*G*G*G*G*G*G*G*o._%_%_%_%_%u>G*G*G*G*G*G*G*G*G*w&:&_%_%_%_%H%G*G*G*G*G*G*G*G*G*G*G*G*G* $_%_%_%_%_%j= D>E>)*)*)*)*)*)*)*6>_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%l+2&2&2&2&2&2&2&2&2&'._%_%_%_%_%_%_%_%_%_%_%F>x*2&2&2&2&2&2&2&2&2&2&2&2&2&2&2&2&2&G>H>I>J>_%_%_%_%_%K> I*_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%!> C=_%_%_%_%_%k* ",
-" q>_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_%L>M>N>O>P>Q>R>2&2&2&2&2&2&2&j._%_%_%_%_%u>2&2&2&2&2&2&2&2&2&p*:&_%_%_%_%H%2&2&2&2&2&2&2&2&2&2&2&2&2&K#_%_%_%_%_%j= z*S>L;L;L;L;L;L;$&7>_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%l+R;R;R;R;R;R;R;R;R;'._%_%_%_%_%_%_%_%_%_%_%_%V%9*R;R;R;R;R;R;R;R;R;R;R;R;T>U>V>W>X>Y>+ )=_%_%_%_%_%K> Z>_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%!> C=_%_%_%_%_%k* ",
-" `>_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , u;.,+,@,#,$,%,R;R;f._%_%_%_%_%u>R;R;R;R;R;R;R;R;R;^-:&_%_%_%_%H%R;R;R;R;R;R;R;R;R;R;R;R;R;K#_%_%_%_%_%j= u;&,6%6%6%6%6%6%o._%_%_%_%_%_%*,|*r =,-,-,-,-,-,;,:.|*7>_%_%_%_%_%_%i+!;!;!;!;!;!;!;!;!;=._%_%_%_%_%_%_%_%_%_%_%_%_%>,x*!;!;!;!;!;!;,,',),!,~,{,+ )=_%_%_%_%_%K> ],_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%!> C=_%_%_%_%_%k* ",
-" `>_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , p=^,!,/,_%_%_%_%_%(,!;!;!;!;!;!;!;!;!;_,:&_%_%_%_%H%!;!;!;!;!;!;!;!;!;!;!;!;!;A#_%_%_%_%_%j= + :,6%6%6%6%6%6%C;_%_%_%_%_%~;6%6%6%<, [,5;5;p$o&_%_%_%_%_%i+5;5;5;5;5;5;5;5;5;=._%_%_%_%_%},'.f-_%_%_%_%_%_%q&|,1,2,3,4,Y> )=_%_%_%_%_%K> n%5,U%U%U%U%U%U%U%U%U%U%U%U%U%U%U%U%<% C=_%_%_%_%_%k* ",
-" D%_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , 6,_%_%_%_%_%7,8,9,j>0,5;5;5;5;5;_,:&_%_%_%_%H%5;5;5;5;5;5;5;5;5;5;5;5;5;f#_%_%_%_%_%j= a,b,b,b,b,b,b,},_%_%_%_%_%9=b,b,b,c, d,e,e,^%f,_%_%_%_%_%e+e,e,e,e,e,e,e,e,e,%._%_%_%_%_%A;3=g,h,_%_%_%_%_%_%1>n= )=_%_%_%_%_%K> m%i,j,j,j,j,j,j,j,j,j,j,j,j,j,j,j,K= C=_%_%_%_%_%k* ",
-" D%_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , 6,_%_%_%_%_%o= + k,l,m,n,o,p,q,r,C-_%_%_%_%H%e,e,e,e,e,e,e,e,e,e,e,e,e,f#_%_%_%_%_%j= s,b,b,b,b,b,b,},_%_%_%_%_%|*b,b,b,t, u,3=3=3==-_%_%_%_%_%0+3=3=3=3=3=3=3=3=3=%._%_%_%_%_%v,w,x,y,U%_%_%_%_%_%_%a;n= )=_%_%_%_%_%K> C=_%_%_%_%_%k* ",
-" D%_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , 6,_%_%_%_%_%o= p=z,A,_%_%_%_%H%3=3=3=3=3=3=3=3=3=3=3=3=3=/#_%_%_%_%_%j= B,d;d;d;d;d;d;},_%_%_%_%_%|*d;d;d;C, D,E,J*J*=-_%_%_%_%_%0+J*J*J*J*J*J*F,G,H,I,_%_%_%_%_%D% j% -_&_%_%_%_%_%_%J,E% )=_%_%_%_%_%K> K,&%L,M,=% C=_%_%_%_%_%k* ",
-" O=_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , 6,_%_%_%_%_%o= h=G%_%_%_%_%H%J*J*J*J*J*J*J*J*J*J*J*J*J*Y at _%_%_%_%_%j= N,d;d;d;d;d;d;},_%_%_%_%_%e;d;d;d;O, P,Q,J*J*=-_%_%_%_%_%6+J*J*J*J*J*E,R, C%_%_%_%_%_%D% 6,x%_%_%_%_%_%_%G%!= )=_%_%_%_%_%K> l*x%_%_%_%G%S, C=_%_%_%_%_%k* ",
-" O=_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , 6,_%_%_%_%_%o= h=G%_%_%_%_%H%^%^%^%^%^%^%^%^%^%^%^%^%^%N at _%_%_%_%_%j= T,U,U,U,U,U,U,9=_%_%_%_%_%e;U,U,U,V, W,X,^%g-=-_%_%_%_%_%}+^%^%^%^%^%X,W, C%_%_%_%_%_%D% j%6,x%_%_%_%_%_%_%J,l* )=_%_%_%_%_%K> T%_%_%_%_%_%6, C=_%_%_%_%_%k* ",
-" O=_%_%_%_%_%_%_%_%_%m=Y, K=b;_%_%_%_%_%_%_%_%e=D=b>b>b>b>b>b>b>b>m=_%_%_%_%_%_%_%_%_%Z, A>_&_%_%_%_% , 6,_%_%_%_%_%o= h=G%_%_%_%_%H%g-g-g-g-g-g-g-g-g-g-g-g-g-N at _%_%_%_%_%j= `, ' ' ' ' ' '9=_%_%_%_%_%e; ' ' '.' +'@'g-g-=-_%_%_%_%_%}+g-g-g-g-g-#'k, C%_%_%_%_%_%D% j%(&x%_%_%_%_%_%_%G%k* )=_%_%_%_%_%K> q>_%_%_%_%_%L, C=_%_%_%_%_%k* ",
-" T%_%_%_%_%_%_%_%_%_%_%$'Y, S%:%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%%' A>_&_%_%_%_%H- &'_%_%_%_%_%o= h=G%_%_%_%_%H%n-M;M;M;M;M;M;M;M;M;M;M;M;k at _%_%_%_%_%j= *' ' ' ' ' ' '9=_%_%_%_%_%T& ' ' '=' -';'M;6;L*_%_%_%_%_%(+M;M;M;M;M;>'6. C%_%_%_%_%_%D% j%,'e=_%_%_%_%_%_%l=l* )=_%_%_%_%_%Y; q>_%_%_%_%_%&' H-_%_%_%_%_%k* ",
-" T%_%_%_%_%_%_%_%_%_%_%_%''=% ,_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%)' n%/;_%_%_%_%e=n; 9&!'_%_%_%_%_%o= m%1>_%_%_%_%_%A#M;M;M;M;M;M;M;M;M;M;M;M;k at _%_%_%_%_%j= ~'_,_,_,_,_,_,C;_%_%_%_%_%{' '_,_,]' ^'/'H*l+8=_%_%_%_%_%N at H*H*H*H*H*(' C%_%_%_%_%_%D% _'x%_%_%_%_%_%_%:']= ^=_%_%_%_%_%1>=% <%_%_%_%_%_%@;j% n=x%_%_%_%_%e=E% ",
-" b>_%_%_%_%_%_%_%_%_%_%_%_%_; `>_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%g= =%a;_%_%_%_%_%<'6,)='='='='='='='='=['}'_&_%_%_%_%_%o= j%j=_%_%_%_%_%F>P }+6+6+6+6+6+6+6+6+6+6+h _%_%_%_%_%j= |'_,_,_,_,_,_,f._%_%_%_%_%_%N%t.=+1''='='='='=2'3'm t-_%_%_%_%_%8=x*6=6=6=6=6=4' C%_%_%_%_%_%D% j%_'/;_%_%_%_%_%_%:%5' 6'_%_%_%_%_%_%!'&%'='='='='='='='='='='='='='='='=5'S% 6,_%_%_%_%_%U%_;7''='='='='='='='=)=-,8'_%_%_%_%_%b;K, ",
-" k*:'_%_%_%_%_%_%_%_%_%_%_%9'[% n=_&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%G%o% u-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%o= T%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%j= 0'a'^-^-^-^-^-^&=&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%b'p*n-n-n-n-n-c' C%_%_%_%_%_%D% j%&%/;_%_%_%_%_%_%J= ,_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%/;n% n%_&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%d'j% ",
-" %%/;_%_%_%_%_%_%_%_%_%_%9'Y, @;_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%L, '=e=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%o= e'/;_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%j= f'g'^-^-^-^-^-_,h'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%%.6;6;6;6;6;6;i' C%_%_%_%_%_%D% j'e=_%_%_%_%_%!' k'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%/;n% u-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%j' ",
-" l'/;_%_%_%_%_%_%_%_%_%m= o%C=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_&I*&& j%F%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%o= m'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%j= n'o'p*p*p*p*p*p*0%M*_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%p'U,N&N&N&N&N&N&q' C%_%_%_%_%_%D% M,/;_%_%_%_%!' Y,%'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%:'r' A>s'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%$'j% ",
-" ,'U%_%_%_%_%_%_%_%b;t' y%d'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%e=0;S% [%J=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%o= &&I*_&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%j= u'v'w&w&w&w&w&w&w&6+t-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%w'M=w&w&w&w&w&w&w&x' C%_%_%_%_%_%D% M,b;_%_%_%!' y%y'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%<'j% 5's'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%''o% ",
-" M,:%_%_%_%_%_%x%,' m%z'G%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%y'7'j% S%A'G%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%o= && -9'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%j= u;B'w&w&w&w&w&w&w&w&3$C'8=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%1&D')*p*p*p*p*p*p*p*E'F' C%_%_%_%_%_%D% M,G'_%_%!' r'i%x%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%:%k* i,K>_&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%l=<%m% ",
-" H'I'_&_%_%J'*% K=,'F%K'Z,8'8'8'8'8'8'8'8'8'8'J'''`>'=S% r'L'O=@;)')')')')')')')')')'I*M'_%_%_%_%_%o= :=N'O'>-P'P'P'P'P'P'P'P'P'P'P'P'h'Q')')')'b> R'N&N&N&N&N&N&N&N&N&^-3$e )&P'S')')')')')')')'7,y=I=].x*^-^-^-^-^-^-^-^-^-T'U' )=)')')')')',' V')')'A' j%n%-,q>@;)')')')')')')')')')'F%I*0;m'_'K, &&^;W'i%)')')')')')')')')')'Z>D%g=K= ",
-" ~='=,=j% 6,_%_%_%_%_%o= X'^-^-^-^-^-^-^-^-^-^-^-^-^-Y'-' Z'N&N&N&N&N&N&N&N&N&N&N&N&N&N&`' )^-^-^-^-^-^-^-^-^-^-^-^-^-.)u; ",
-" 6,_%_%_%_%_%o= +)_,_,_,_,_,_,_,_,_,_,_,_,_,@)#) $)6;6;6;6;6;6;6;6;6;6;6;6;6;6;%) &)_,_,_,_,_,_,_,_,_,_,_,_,_,*) ",
-" 6,_%_%_%_%_%o= =) ' ' ' ' ' ' ' ' ' ' ' ' '-);) >)n-n-n-n-n-n-n-n-n-n-n-n-n-n-,) ') ' ' ' ' ' ' ' ' ' ' ' ' ')) ",
-" 6,_%_%_%_%_%o= !)U,U,U,U,U,U,U,U,U,U,U,U,U,~)u; {)n-n-n-n-n-n-n-n-n-n-n-n-n-n-]) ^)U,U,U,U,U,U,U,U,U,U,U,U,U,/) ",
-" 6,_%_%_%_%_%o= D>()U,U,U,U,U,U,U,U,U,U,U,U,_)_# :)6=6=6=6=6=6=6=6=6=6=6=6=6=6=<) [)d;d;d;d;d;d;d;d;d;d;d;d;d;}) ",
-" 6,_%_%_%_%_%o= #)|)d;d;d;d;d;d;d;d;d;d;d;d;1)6. 2)6=6=6=6=6=6=6=6=6=6=6=6=6=6=3) 4)b,b,b,b,b,b,b,b,b,b,b,b,b,5) ",
-" 6,_%_%_%_%_%o= u;6)b,b,b,b,b,b,b,b,b,b,b,b,7) 8)H*H*H*H*H*H*H*H*H*H*H*H*H*H*9) 0)6%6%6%6%6%6%6%6%6%6%6%6%6%a) ",
-" 6,_%_%_%_%_%o= + b)6%6%6%6%6%6%6%6%6%6%6%6%c) d)H*H*H*H*H*H*H*H*H*H*H*H*H*H*e) f)L;L;L;L;L;L;L;L;L;L;L;L;L;0) ",
-" 6,_%_%_%_%_%o= g)L;L;L;L;L;L;L;L;L;L;L;L;h) i)M;M;M;M;M;M;M;M;M;M;M;M;M;M;x, j)k))*)*)*)*)*)*)*)*)*)*)*)*l) ",
-" 6,_%_%_%_%_%o= m))*)*)*)*)*)*)*)*)*)*)*)*n) o)M;M;M;M;M;M;M;M;M;M;M;M;M;p)q) {>r)~>~>~>~>~>~>~>~>~>~>~>~>u' ",
-" 6,_%_%_%_%_%o= s)~>~>~>~>~>~>~>~>~>~>~>~>t) u)g-g-g-g-g-g-g-g-g-g-g-g-g-v)w) x)y)D-D-D-D-D-D-D-D-D-D-D-;>+ ",
-" 6,_%_%_%_%_%o= z)D-D-D-D-D-D-D-D-D-D-D-D-A) B)^%^%^%^%^%^%^%^%^%^%^%^%^%C)D) D>E)O;O;O;O;O;O;O;O;O;O;O;F) ",
-" i,L,L,L,L,L,)= G)O;O;O;O;O;O;O;O;O;O;O;O;H) +'^%^%^%^%^%^%^%^%^%^%^%^%^%I)X; z*J)O;O;O;O;O;O;O;O;O;O;O;K) ",
-" L)w;w;w;w;w;w;w;w;w;w;w;w;M) p=J*J*J*J*J*J*J*J*J*J*J*J*J*N)`@ x at O)w;w;w;w;w;w;w;w;w;w;w;P) ",
-" x)Q)J&J&J&J&J&J&J&J&J&J&J&R) S)J*J*J*J*J*J*J*J*J*J*J*J*T) + U)J&J&J&J&J&J&J&J&J&J&J&V) ",
-" W)X)2=2=2=2=2=2=2=2=2=2=2=Y) Z)3=3=3=3=3=3=3=3=3=3=3=3=`) !2=2=2=2=2=2=2=2=2=2=2=.! ",
-" (*+!2=2=2=2=2=2=2=2=2=2=2=@! #!3=3=3=3=3=3=3=3=3=3=3=3=$! %!6-6-6-6-6-6-6-6-6-6-6-&! ",
-" *!6-6-6-6-6-6-6-6-6-6-6-=! 1,e,e,e,e,e,e,e,e,e,e,e,e,-! ;!M=M=M=M=M=M=M=M=M=M=M=>! ",
-" ,!M=M=M=M=M=M=M=M=M=M=M='! )!5;5;5;5;5;5;5;5;5;5;5;5;!! ~!(=(=(=(=(=(=(=(=(=(=(={! ",
-" ]!(=(=(=(=(=(=(=(=(=(=(=7* ^!5;5;5;5;5;5;5;5;5;5;5;5;/! (!x*x*x*x*x*x*x*x*x*x*w*_! ",
-" :!x*x*x*x*x*x*x*x*x*x*<![! }!!;!;!;!;!;!;!;!;!;!;!;!;|! 1!9*9*9*9*9*9*9*9*9*9*2!G$ ",
-" 3!9*9*9*9*9*9*9*9*9*9*4!5! 6!!;!;!;!;!;!;!;!;!;!;!;!;7! 8! * * * * * * * * * *9!(* ",
-" 0! * * * * * * * * * *E&Y* a!R;R;R;R;R;R;R;R;R;R;R;R;b! c!m&m&m&m&m&m&m&m&m&m&d!+ ",
-" e!f!m&m&m&m&m&m&m&m&m&g!h! i!R;R;R;R;R;R;R;R;R;R;R;R;j! k!^&^&^&^&^&^&^&^&^&^&l! ",
-" m!n!^&^&^&^&^&^&^&^&^&o!L@ p!2&2&2&2&2&2&2&2&2&2&2&q!r! s!^&^&^&^&^&^&^&^&^&^&t! ",
-" h!u!$&$&$&$&$&$&$&$&$&v!x@ w!G*G*G*G*G*G*G*G*G*G*G*C>x! y!$&$&$&$&$&$&$&$&$&$&z! ",
-" + A!A%A%A%A%A%A%A%A%A%B!+ C!G*G*G*G*G*G*G*G*G*G*G*D!E! F!A%A%A%A%A%A%A%A%A%A%B% ",
-" G!0%0%0%0%0%0%0%0%0%H! x!----------------------I!{, J!0%0%0%0%0%0%0%0%0%0%K! ",
-" L!0%0%0%0%0%0%0%0%0%M! Y>N!--------------------O!+ P!;%;%;%;%;%;%;%;%;%;%O$ ",
-" Q!;%;%;%;%;%;%;%;%;%R! S!T!<&<&<&<&<&<&<&<&<&<&U! V!P$P$P$P$P$P$P$P$P$W!X! ",
-" Y!P$P$P$P$P$P$P$P$P$Z! X;`!K-K-K-K-K-K-K-K-K-K- ~ .~E$E$E$E$E$E$E$E$E$+~v$ ",
-" @~E$E$E$E$E$E$E$E$E$#~ F&$~K-K-K-K-K-K-K-K-K-K-%~ &~p$p$p$p$p$p$p$p$p$*~(* ",
-" =~p$p$p$p$p$p$p$p$p$-~ `@;~$=$=$=$=$=$=$=$=$=$=>~ ,~a$a$a$a$a$a$a$a$a$'~ ",
-" V!a$a$a$a$a$a$a$a$a$)~ !~$=$=$=$=$=$=$=$=$=$=~~ L at 3$3$3$3$3$3$3$3$3${~ ",
-" X!3$3$3$3$3$3$3$3$3$]~ ^~M&M&M&M&M&M&M&M&M&M&/~ + (~~$~$~$~$~$~$~$~$_~ ",
-" (*(~~$~$~$~$~$~$~$~$:~ <~M&M&M&M&M&M&M&M&M&M&[~ }~ $ $ $ $ $ $ $ $T# ",
-" |~ $ $ $ $ $ $ $ $.$ 1~0=0=0=0=0=0=0=0=0=0=2~ 3~ $ $ $ $ $ $ $ $4~ ",
-" 5~K#K#K#K#K#K#K#K#6~ 7~0=0=0=0=0=0=0=0=0=0=8~ 9~K#K#K#K#K#K#K#K#0~ ",
-" a~A#A#A#A#A#A#A#A#b~ c~J%J%J%J%J%J%J%J%J%J%d~ e~A#A#A#A#A#A#A#B#f~ ",
-" g~f#f#f#f#f#f#f#f#h~ i~X=X=X=X=X=X=X=X=X=X=j~ k~f#f#f#f#f#f#f#q#l~ ",
-" m~f#f#f#f#f#f#f#n~o~ p~X=X=X=X=X=X=X=X=X=X=q~ r~/#/#/#/#/#/#/#X at 1+ ",
-" s~/#/#/#/#/#/#/#t~u~ v~K&K&K&K&K&K&K&K&K&K&u* w~Y at Y@Y at Y@Y at Y@Y at x~+ ",
-" y~Y at Y@Y at Y@Y at Y@Y at z~l~ A~K&K&K&K&K&K&K&K&K&K&X; B~N at N@N at N@N at N@N at C~ ",
-" D~N at N@N at N@N at N@N at E~h# &-E-P*P*P*P*P*P*P*P*F~ G~k at k@k at k@k at k@k at H~ ",
-" I~k at k@k at k@k at k@k at J~1+ 2-Q-P*P*P*P*P*P*P*P*R- K~{@{@{@{@{@{@{@L~ ",
-" 6#M~{@{@{@{@{@{@N~T. O~P~;-;-;-;-;-;-;-;-Q~ R~B+B+B+B+B+B+B+S~ ",
-" T.T~B+B+B+B+B+B+U~+ +*V~y&y&y&y&y&y&y&y&W~ X~l+l+l+l+l+l+l+Y~ ",
-" _#Z~l+l+l+l+l+l+`~ `@_-y&y&y&y&y&y&y&y& { .{i+i+i+i+i+i+i++{ ",
-" @{i+i+i+i+i+i+#{ ${'*'*'*'*'*'*'*'*%{ &{i+i+i+i+i+i+i+*{ ",
-" ={e+e+e+e+e+e+-{ T='*'*'*'*'*'*'*'*+- f+e+e+e+e+e+e+e+;{ ",
-" >{0+0+0+0+0+0+,{ '{s&s&s&s&s&s&s&s&){ !{0+0+0+0+0+0+c+~{ ",
-" {{6+6+6+6+6+6+]{ ^{s&s&s&s&s&s&s&s&/{ *{6+6+6+6+6+6+({ ",
-" _{6+6+6+6+6+6+:{ ==L&L&L&L&L&L&L&L&<{ [{}+}+}+}+}+}+}{ ",
-" |{}+}+}+}+}+}+1{ 2{f&f&f&f&f&f&f&f&3{ @+(+(+(+(+(+(+4{ ",
-" 5{6{(+(+(+(+(+7{ 8{f&f&f&f&f&f&f&f&9{ 0{~+~+~+~+~+~+a{ ",
-" 4+b{~+~+~+~+~+c{ d{g*g*g*g*g*g*g*g*W* e{f{'+'+'+'+'+g{ ",
-" I.h{'+'+'+'+'+i{ b*g*g*g*g*g*g*g*g*j{ I.k{=+=+=+=+=+l{ ",
-" + m{=+=+=+=+=+n{ o{g%g%g%g%g%g%g%g%>= T.3'$+$+$+$+$+p{ ",
-" q{$+$+$+$+$+r{ s{&*************t{6& ~{u{`.`.`.`.`.v{ ",
-" w{`.`.`.`.`.x{ y{,*************z{)- P.A{W.W.W.W.W.B{ ",
-" C{W.W.W.W.W.D{ D&V&S&S&S&S&S&S&E{F& 6.F{W.W.W.W.G{e{ ",
-" H{N.N.N.N.N.I{ @&J{S&S&S&S&S&S&K{k& L{N.N.N.N.S.T. ",
-" M{G.G.G.G.G.N{ `@O{g&g&g&g&g&g&P{+ Q{G.G.G.G.R{D ",
-" S{B.B.B.B.B.T{ U{g&g&g&g&g&g&V{ W{B.B.B.B.X{ ",
-" Y{Z{B.B.B.B.`{ ]b&b&b&b&b&b&.] +]w.w.w.w.@] ",
-" #]$]w.w.w.w.e{ %]b&b&b&b&b&b&&] *]t.t.t.t.=] ",
-" ~{-]t.t.t.t.D ;]-&-&-&-&-&-&>] ,]o.o.o.o.'] ",
-" )]o.o.o.!] ~]W%W%W%W%W%W%{] ]]j.j.j.j.^] ",
-" /]j.j.j.(] _]W%W%W%W%W%W%:] <]f.f.f.f.[] ",
-" }]f.f.f.|] 1]K%K%K%K%K%K%2] 3]0.0.0.4]5] ",
-" 6]0.0.0.7] 8]K%K%K%K%K%K%9] 0]4.4.4.a]7. ",
-" b]4.4.4.c] d]s%s%s%s%s%s%v% e]}.}.}.f]K ",
-" g]}.}.}.h] `$s%s%s%s%s%i]j] k]}.}.}.l]+ ",
-" m]:.:.:.n] }&d%d%d%d%d%o]p] q]:.:.:.r] ",
-" s]].].].t] u]#%#%#%#%#%v]4% s]].].].t] ",
-" b.'.'.'.w] x]#%#%#%#%#%y]@& z]A]'.'.B] ",
-" + C]'.'.D] @&!%!%!%!%!%E]N+ F]G]=.=.H] ",
-" I]=.=.J] + K]!%!%!%!%L] M]N]%.%.O] ",
-" P]%.%.Q] R].%.%.%.%S] b.T]` ` U] ",
-" V]` ` W] X]T$T$T$T$Y] 3.Z]U `] ^ ",
-" .^U U +^ @^T$T$T$T$#^ P.$^P %^&^ ",
-" *^P P =^ -^J$J$J$J$;^ + >^I ,^~{ ",
-" '^I I Z M$J$J$J$J$)^ !^F ~^ ",
-" {^F F ]^ ^^y$y$y$y$/^ (^z _^ ",
-" :^z z <^ [^y$y$y$y$}^ |^z 1^ ",
-" 5 2^u 3^ 4^k$k$k$k$5^ 6^u 7^ ",
-" 8^9^r &^ 0^d$d$d$d$a^ b^r o ",
-" # c^d^e^ f^d$d$d$g^h^ i^m j^ ",
-" + k^l^2 m^6$6$6$8$n^ o^h p^ ",
-" O%q^3. r^6$6$6$s^t^ u^e k ",
-" v^w^x^ y^[$[$[$z^A^ B^%=e^ ",
-" C^D^} L#[$[$[$E^o# F^G^+ ",
-" F^H^. A^I^^$^$J^ K^| ",
-" L^M^+ @&N^^$^$O^ P^Q^ ",
-" R^S^ 6 at T^>$>$U^ V^W^ ",
-" 8 X^ o#Y^#$#$Z^ `^ / ",
-" e^./ + +/#$#$@/ #/, ",
-" } $/ %/W#W#&/ */=/ ",
-" -/ ;/W#W#>/ ,/'/ ",
-" )/ H#N#N#!/ ~/{/ ",
-" % ]/N#N#^/ # } ",
-" //E#E#(/ ",
-" _/u#u#:/ ",
-" </u#u#[/ ",
-" }/9#9#|/ ",
-" 1/9#9#A^ ",
-" 1#c#2/c@ ",
-" =@3/4/ ",
-" ^@5/6/ ",
-" A^7/8/ ",
-" 6 at 9/0/ ",
-" + a/b/ ",
-" S at c/ ",
-" d/e/ ",
-" f/g/ ",
-" h/i/ ",
-" j/n@ ",
-" k/X+ ",
-" l/m/ ",
-" n/o/ ",
-" p/q/ ",
-" @r/ ",
-" M+`+ ",
-" s/+ "};
diff --git a/engine/ui/menudef.h b/engine/ui/menudef.h
deleted file mode 100644
index 7bb7b0a..0000000
--- a/engine/ui/menudef.h
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#define ITEM_TYPE_TEXT 0 // simple text
-#define ITEM_TYPE_BUTTON 1 // button, basically text with a border
-#define ITEM_TYPE_RADIOBUTTON 2 // toggle button, may be grouped
-#define ITEM_TYPE_CHECKBOX 3 // check box
-#define ITEM_TYPE_EDITFIELD 4 // editable text, associated with a cvar
-#define ITEM_TYPE_COMBO 5 // drop down list
-#define ITEM_TYPE_LISTBOX 6 // scrollable list
-#define ITEM_TYPE_MODEL 7 // model
-#define ITEM_TYPE_OWNERDRAW 8 // owner draw, name specs what it is
-#define ITEM_TYPE_NUMERICFIELD 9 // editable text, associated with a cvar
-#define ITEM_TYPE_SLIDER 10 // mouse speed, volume, etc.
-#define ITEM_TYPE_YESNO 11 // yes no cvar setting
-#define ITEM_TYPE_MULTI 12 // multiple list setting, enumerated
-#define ITEM_TYPE_BIND 13 // multiple list setting, enumerated
-
-#define ITEM_ALIGN_LEFT 0 // left alignment
-#define ITEM_ALIGN_CENTER 1 // center alignment
-#define ITEM_ALIGN_RIGHT 2 // right alignment
-
-#define ITEM_TEXTSTYLE_NORMAL 0 // normal text
-#define ITEM_TEXTSTYLE_BLINK 1 // fast blinking
-#define ITEM_TEXTSTYLE_PULSE 2 // slow pulsing
-#define ITEM_TEXTSTYLE_SHADOWED 3 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_OUTLINED 4 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_OUTLINESHADOWED 5 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_SHADOWEDMORE 6 // drop shadow ( need a color for this )
-
-#define WINDOW_BORDER_NONE 0 // no border
-#define WINDOW_BORDER_FULL 1 // full border based on border color ( single pixel )
-#define WINDOW_BORDER_HORZ 2 // horizontal borders only
-#define WINDOW_BORDER_VERT 3 // vertical borders only
-#define WINDOW_BORDER_KCGRADIENT 4 // horizontal border using the gradient bars
-
-#define WINDOW_STYLE_EMPTY 0 // no background
-#define WINDOW_STYLE_FILLED 1 // filled with background color
-#define WINDOW_STYLE_GRADIENT 2 // gradient bar based on background color
-#define WINDOW_STYLE_SHADER 3 // gradient bar based on background color
-#define WINDOW_STYLE_TEAMCOLOR 4 // team color
-#define WINDOW_STYLE_CINEMATIC 5 // cinematic
-
-#define MENU_TRUE 1 // uh.. true
-#define MENU_FALSE 0 // and false
-
-#define HUD_VERTICAL 0x00
-#define HUD_HORIZONTAL 0x01
-
-// list box element types
-#define LISTBOX_TEXT 0x00
-#define LISTBOX_IMAGE 0x01
-
-// list feeders
-#define FEEDER_HEADS 0x00 // model heads
-#define FEEDER_MAPS 0x01 // text maps based on game type
-#define FEEDER_SERVERS 0x02 // servers
-#define FEEDER_CLANS 0x03 // clan names
-#define FEEDER_ALLMAPS 0x04 // all maps available, in graphic format
-#define FEEDER_REDTEAM_LIST 0x05 // red team members
-#define FEEDER_BLUETEAM_LIST 0x06 // blue team members
-#define FEEDER_PLAYER_LIST 0x07 // players
-#define FEEDER_TEAM_LIST 0x08 // team members for team voting
-#define FEEDER_MODS 0x09 // team members for team voting
-#define FEEDER_DEMOS 0x0a // team members for team voting
-#define FEEDER_SCOREBOARD 0x0b // team members for team voting
-#define FEEDER_Q3HEADS 0x0c // model heads
-#define FEEDER_SERVERSTATUS 0x0d // server status
-#define FEEDER_FINDPLAYER 0x0e // find player
-#define FEEDER_CINEMATICS 0x0f // cinematics
-
-// display flags
-#define CG_SHOW_BLUE_TEAM_HAS_REDFLAG 0x00000001
-#define CG_SHOW_RED_TEAM_HAS_BLUEFLAG 0x00000002
-#define CG_SHOW_ANYTEAMGAME 0x00000004
-#define CG_SHOW_HARVESTER 0x00000008
-#define CG_SHOW_ONEFLAG 0x00000010
-#define CG_SHOW_CTF 0x00000020
-#define CG_SHOW_OBELISK 0x00000040
-#define CG_SHOW_HEALTHCRITICAL 0x00000080
-#define CG_SHOW_SINGLEPLAYER 0x00000100
-#define CG_SHOW_TOURNAMENT 0x00000200
-#define CG_SHOW_DURINGINCOMINGVOICE 0x00000400
-#define CG_SHOW_IF_PLAYER_HAS_FLAG 0x00000800
-#define CG_SHOW_LANPLAYONLY 0x00001000
-#define CG_SHOW_MINED 0x00002000
-#define CG_SHOW_HEALTHOK 0x00004000
-#define CG_SHOW_TEAMINFO 0x00008000
-#define CG_SHOW_NOTEAMINFO 0x00010000
-#define CG_SHOW_OTHERTEAMHASFLAG 0x00020000
-#define CG_SHOW_YOURTEAMHASENEMYFLAG 0x00040000
-#define CG_SHOW_ANYNONTEAMGAME 0x00080000
-#define CG_SHOW_2DONLY 0x10000000
-
-
-#define UI_SHOW_LEADER 0x00000001
-#define UI_SHOW_NOTLEADER 0x00000002
-#define UI_SHOW_FAVORITESERVERS 0x00000004
-#define UI_SHOW_ANYNONTEAMGAME 0x00000008
-#define UI_SHOW_ANYTEAMGAME 0x00000010
-#define UI_SHOW_NEWHIGHSCORE 0x00000020
-#define UI_SHOW_DEMOAVAILABLE 0x00000040
-#define UI_SHOW_NEWBESTTIME 0x00000080
-#define UI_SHOW_FFA 0x00000100
-#define UI_SHOW_NOTFFA 0x00000200
-#define UI_SHOW_NETANYNONTEAMGAME 0x00000400
-#define UI_SHOW_NETANYTEAMGAME 0x00000800
-#define UI_SHOW_NOTFAVORITESERVERS 0x00001000
-
-
-
-
-// owner draw types
-// ideally these should be done outside of this file but
-// this makes it much easier for the macro expansion to
-// convert them for the designers ( from the .menu files )
-#define CG_OWNERDRAW_BASE 1
-#define CG_PLAYER_ARMOR_ICON 1
-#define CG_PLAYER_ARMOR_VALUE 2
-#define CG_PLAYER_HEAD 3
-#define CG_PLAYER_HEALTH 4
-#define CG_PLAYER_AMMO_ICON 5
-#define CG_PLAYER_AMMO_VALUE 6
-#define CG_SELECTEDPLAYER_HEAD 7
-#define CG_SELECTEDPLAYER_NAME 8
-#define CG_SELECTEDPLAYER_LOCATION 9
-#define CG_SELECTEDPLAYER_STATUS 10
-#define CG_SELECTEDPLAYER_WEAPON 11
-#define CG_SELECTEDPLAYER_POWERUP 12
-
-#define CG_FLAGCARRIER_HEAD 13
-#define CG_FLAGCARRIER_NAME 14
-#define CG_FLAGCARRIER_LOCATION 15
-#define CG_FLAGCARRIER_STATUS 16
-#define CG_FLAGCARRIER_WEAPON 17
-#define CG_FLAGCARRIER_POWERUP 18
-
-#define CG_PLAYER_ITEM 19
-#define CG_PLAYER_SCORE 20
-
-#define CG_BLUE_FLAGHEAD 21
-#define CG_BLUE_FLAGSTATUS 22
-#define CG_BLUE_FLAGNAME 23
-#define CG_RED_FLAGHEAD 24
-#define CG_RED_FLAGSTATUS 25
-#define CG_RED_FLAGNAME 26
-
-#define CG_BLUE_SCORE 27
-#define CG_RED_SCORE 28
-#define CG_RED_NAME 29
-#define CG_BLUE_NAME 30
-#define CG_HARVESTER_SKULLS 31 // only shows in harvester
-#define CG_ONEFLAG_STATUS 32 // only shows in one flag
-#define CG_PLAYER_LOCATION 33
-#define CG_TEAM_COLOR 34
-#define CG_CTF_POWERUP 35
-
-#define CG_AREA_POWERUP 36
-#define CG_AREA_LAGOMETER 37 // painted with old system
-#define CG_PLAYER_HASFLAG 38
-#define CG_GAME_TYPE 39 // not done
-
-#define CG_SELECTEDPLAYER_ARMOR 40
-#define CG_SELECTEDPLAYER_HEALTH 41
-#define CG_PLAYER_STATUS 42
-#define CG_FRAGGED_MSG 43 // painted with old system
-#define CG_PROXMINED_MSG 44 // painted with old system
-#define CG_AREA_FPSINFO 45 // painted with old system
-#define CG_AREA_SYSTEMCHAT 46 // painted with old system
-#define CG_AREA_TEAMCHAT 47 // painted with old system
-#define CG_AREA_CHAT 48 // painted with old system
-#define CG_GAME_STATUS 49
-#define CG_KILLER 50
-#define CG_PLAYER_ARMOR_ICON2D 51
-#define CG_PLAYER_AMMO_ICON2D 52
-#define CG_ACCURACY 53
-#define CG_ASSISTS 54
-#define CG_DEFEND 55
-#define CG_EXCELLENT 56
-#define CG_IMPRESSIVE 57
-#define CG_PERFECT 58
-#define CG_GAUNTLET 59
-#define CG_SPECTATORS 60
-#define CG_TEAMINFO 61
-#define CG_VOICE_HEAD 62
-#define CG_VOICE_NAME 63
-#define CG_PLAYER_HASFLAG2D 64
-#define CG_HARVESTER_SKULLS2D 65 // only shows in harvester
-#define CG_CAPFRAGLIMIT 66
-#define CG_1STPLACE 67
-#define CG_2NDPLACE 68
-#define CG_CAPTURES 69
-
-
-
-
-#define UI_OWNERDRAW_BASE 200
-#define UI_HANDICAP 200
-#define UI_EFFECTS 201
-#define UI_PLAYERMODEL 202
-#define UI_CLANNAME 203
-#define UI_CLANLOGO 204
-#define UI_GAMETYPE 205
-#define UI_MAPPREVIEW 206
-#define UI_SKILL 207
-#define UI_BLUETEAMNAME 208
-#define UI_REDTEAMNAME 209
-#define UI_BLUETEAM1 210
-#define UI_BLUETEAM2 211
-#define UI_BLUETEAM3 212
-#define UI_BLUETEAM4 213
-#define UI_BLUETEAM5 214
-#define UI_REDTEAM1 215
-#define UI_REDTEAM2 216
-#define UI_REDTEAM3 217
-#define UI_REDTEAM4 218
-#define UI_REDTEAM5 219
-#define UI_NETSOURCE 220
-#define UI_NETMAPPREVIEW 221
-#define UI_NETFILTER 222
-#define UI_TIER 223
-#define UI_OPPONENTMODEL 224
-#define UI_TIERMAP1 225
-#define UI_TIERMAP2 226
-#define UI_TIERMAP3 227
-#define UI_PLAYERLOGO 228
-#define UI_OPPONENTLOGO 229
-#define UI_PLAYERLOGO_METAL 230
-#define UI_OPPONENTLOGO_METAL 231
-#define UI_PLAYERLOGO_NAME 232
-#define UI_OPPONENTLOGO_NAME 233
-#define UI_TIER_MAPNAME 234
-#define UI_TIER_GAMETYPE 235
-#define UI_ALLMAPS_SELECTION 236
-#define UI_OPPONENT_NAME 237
-#define UI_VOTE_KICK 238
-#define UI_BOTNAME 239
-#define UI_BOTSKILL 240
-#define UI_REDBLUE 241
-#define UI_CROSSHAIR 242
-#define UI_SELECTEDPLAYER 243
-#define UI_MAPCINEMATIC 244
-#define UI_NETGAMETYPE 245
-#define UI_NETMAPCINEMATIC 246
-#define UI_SERVERREFRESHDATE 247
-#define UI_SERVERMOTD 248
-#define UI_GLINFO 249
-#define UI_KEYBINDSTATUS 250
-#define UI_CLANCINEMATIC 251
-#define UI_MAP_TIMETOBEAT 252
-#define UI_JOINGAMETYPE 253
-#define UI_PREVIEWCINEMATIC 254
-#define UI_STARTMAPCINEMATIC 255
-#define UI_MAPS_SELECTION 256
-
-#define VOICECHAT_GETFLAG "getflag" // command someone to get the flag
-#define VOICECHAT_OFFENSE "offense" // command someone to go on offense
-#define VOICECHAT_DEFEND "defend" // command someone to go on defense
-#define VOICECHAT_DEFENDFLAG "defendflag" // command someone to defend the flag
-#define VOICECHAT_PATROL "patrol" // command someone to go on patrol (roam)
-#define VOICECHAT_CAMP "camp" // command someone to camp (we don't have sounds for this one)
-#define VOICECHAT_FOLLOWME "followme" // command someone to follow you
-#define VOICECHAT_RETURNFLAG "returnflag" // command someone to return our flag
-#define VOICECHAT_FOLLOWFLAGCARRIER "followflagcarrier" // command someone to follow the flag carrier
-#define VOICECHAT_YES "yes" // yes, affirmative, etc.
-#define VOICECHAT_NO "no" // no, negative, etc.
-#define VOICECHAT_ONGETFLAG "ongetflag" // I'm getting the flag
-#define VOICECHAT_ONOFFENSE "onoffense" // I'm on offense
-#define VOICECHAT_ONDEFENSE "ondefense" // I'm on defense
-#define VOICECHAT_ONPATROL "onpatrol" // I'm on patrol (roaming)
-#define VOICECHAT_ONCAMPING "oncamp" // I'm camping somewhere
-#define VOICECHAT_ONFOLLOW "onfollow" // I'm following
-#define VOICECHAT_ONFOLLOWCARRIER "onfollowcarrier" // I'm following the flag carrier
-#define VOICECHAT_ONRETURNFLAG "onreturnflag" // I'm returning our flag
-#define VOICECHAT_INPOSITION "inposition" // I'm in position
-#define VOICECHAT_IHAVEFLAG "ihaveflag" // I have the flag
-#define VOICECHAT_BASEATTACK "baseattack" // the base is under attack
-#define VOICECHAT_ENEMYHASFLAG "enemyhasflag" // the enemy has our flag (CTF)
-#define VOICECHAT_STARTLEADER "startleader" // I'm the leader
-#define VOICECHAT_STOPLEADER "stopleader" // I resign leadership
-#define VOICECHAT_TRASH "trash" // lots of trash talk
-#define VOICECHAT_WHOISLEADER "whoisleader" // who is the team leader
-#define VOICECHAT_WANTONDEFENSE "wantondefense" // I want to be on defense
-#define VOICECHAT_WANTONOFFENSE "wantonoffense" // I want to be on offense
-#define VOICECHAT_KILLINSULT "kill_insult" // I just killed you
-#define VOICECHAT_TAUNT "taunt" // I want to taunt you
-#define VOICECHAT_DEATHINSULT "death_insult" // you just killed me
-#define VOICECHAT_KILLGAUNTLET "kill_gauntlet" // I just killed you with the gauntlet
-#define VOICECHAT_PRAISE "praise" // you did something good
diff --git a/engine/voip-readme.txt b/engine/voip-readme.txt
deleted file mode 100644
index 832379f..0000000
--- a/engine/voip-readme.txt
+++ /dev/null
@@ -1,199 +0,0 @@
-ioquake3 VoIP support documentation.
-Last updated 6/25/2008 by Ryan C. Gordon.
-
-There are two ways to use VoIP in ioquake3. You can either use Mumble as an
- external program, for which ioq3 now supplies some basic hooks, or you can
- use the new built-in VoIP support.
-
-Mumble is here: http://mumble.sourceforge.net/ ... ioquake3 can supply it
- with your in-game position, but everything else is whatever features Mumble
- offers outside of the game. To use it, start Mumble before you start ioq3,
- and run the game with +set cl_useMumble 1. This should work on at least
- Linux, Mac OS X, and Windows, and probably other platforms Mumble supports
- in the future.
-
-The built-in stuff offers tighter in-game integration, works on any platform
- that ioquake3 supports, and doesn't require anything more than a recent build
- of the game. The rest of this document is concerned with the built-in VoIP
- support.
-
-
-Quick start for servers:
- - run a recent build of ioquake3.
- - Make sure your network settings are set to broadband.
-
-Quick start for clients:
- - run a recent build of ioquake3.
- - Make sure your network settings are set to broadband.
- - +set s_useOpenAL 1
- - \bind q "+voiprecord"
- - Hook up a microphone, connect to a VoIP-supporting server.
- - hold down 'q' key and talk.
-
-
-Cvars you can set:
-
-sv_voip: set to "1" (the default) to enable server-side VoIP support. Set to
- "0" to disable. Without this, all VoIP packets are refused by the
- server, which means no one gets to use in-game VoIP.
-
-cl_voip: set to "1" (the default) to enable client-side VoIP support. Set to "0"
- to disable. Without this, you will neither be able to transmit voice nor
- hear other people.
-
-s_alCapture: set to "1" (the default) to have the audio layer open an OpenAL
- capture device. Without this set on sound startup, you'll never
- get bits from the microphone. This means you won't transmit, but
- you can still hear other people.
-
-cl_voipSendTarget: a string: "all" to broadcast to everyone, "none" to send
- to no one, "attacker" to send to the last person that hit
- you, "crosshair" to send to the people currently in your
- crosshair, or a comma-separated list of client numbers, like
- "0,7,2,23" ... an empty string is treated like "all". This
- is reset to "all" when connecting to a new server.
- Presumably mods will manage this cvar, not people, but
- keybind could be useful for the general cases. To send to
- just your team, or the opposing team, or a buddy list, you
- have to set a list of numbers.
-
-cl_voipUseVAD: set to "1" to automatically send audio when the game thinks you
- are talking, "0" (the default) to require the user to manually
- start transmitting, presumably with a keybind.
-
-cl_voipVADThreshold: only used if cl_voipUseVAD is "1" ... a value between
- 0.0 and 1.0 that signifies the volume of recorded audio
- that the game considers to be speech. You can use this
- to trim out breathing or perhaps the sound of your
- fingers tapping the keyboard and only transmit audio
- louder than that. You will have to experiment to find the
- value that works best for your hardware and play style.
- The default is "0.25", with "0.0" being silence and "1.0"
- being pretty-darn-loud.
-
-cl_voipSend: when set to "1", the game will capture audio from the microphone
- and transmit it, when "0", the game will not. The game can
- optimize for the "0" case (perhaps turning off audio recording).
- Lots of things set this on and off, including cl_voipUseVAD, so
- you probably should not touch this directly without knowing what
- you're doing, but perhaps mods can make use of it.
-
-cl_voipGainDuringCapture: This is the volume ("gain") of audio coming out of
- your speakers while you are recording sound for
- transmission. This is a value between 0.0 and 1.0,
- zero being silence and one being no reduction in
- volume. This prevents audio feedback and echo and
- such, but if you're listening in headphones that
- your mic won't pick up, you don't need to turn down
- the gain. Default is 0.2 (20% of normal volume). You
- ABSOLUTELY want to make your speakers quiet when you
- record, if the microphone might pick it up!
-
-cl_voipShowMeter: Set to "1" (the default) to show a volume meter as you are
- recording from the microphone, so you can see how well the
- game can "hear" you. Set to "0" to disable the display of
- the meter.
-
-cl_voipCaptureMult: Multiply recorded audio by this value after denoising.
- Defaults to 2.0 to _double_ the volume of your voice.
- This is to make you more audible if denoising eats away
- too much data. Set this to 1.0 to get no change, less to
- be quieter.
-
-
-
-Console commands:
-
-voip ignore <clientnum>
- Turn off incoming voice from player number <clientnum>. This will refuse to
- play any incoming audio from that player, and instruct the server to stop
- sending it, to save bandwidth. Use unignore to reenable. This is reset to
- unignored when (re)connecting to a server.
-
-voip unignore <clientnum>
- Turn on incoming voice from player number <clientnum>. This will start
- playing audio from this player again if you've previously done a "voip
- ignore", and instruct the server to start sending her voice packets to
- you again.
-
-voip muteall
- Turn off all incoming voice. This will refuse to play any incoming audio,
- and instruct the server to stop sending it, to save bandwidth. Use
- unmuteall to reenable. This is reset to unmuted when (re)connecting to
- a server.
-
-voip unmuteall
- Turn on incoming voice. This will start playing audio again if you've
- previously done a "voip muteall", and instruct the server to start
- sending voice packets to you again.
-
-voip gain <clientnum> <gain>
- Sets the volume ("gain") for player number <clientnum> to <gain> ...
- A gain of 0.0 is silence, and 2.0 doubles the volume. Use this if someone
- is too quiet or too loud.
-
-
-
-
-Actions:
-
-+voiprecord: The action you should bind to a key to record. This basically
- toggles cl_voipSend on and off. You don't need this if you're
- using cl_voipUseVAD, since that'll just record all the time and
- decide what parts of the recording are worth sending.
-
-
-
-More detailed/technical info:
-
-By default, all of this is enabled. You can build with or without VoIP
- support explicitly with USE_VOIP=[1|0] on the make command line.
-
-You currently must use OpenAL to speak, as we have ALC_EXT_capture support
- in place to pull data from the microphone. If you are using the SDL backend,
- you can still hear people, but not speak.
-
-There is no in-game UI to speak of: we encourage mods to add some. Largely
- they will just need to set cvars and run console commands for choosing
- voice targets and ignoring people, etc.
-
-This requires patched builds to be useful, but remains network compatible with
- legacy quake3 clients and servers. Clients and servers both report in their
- info strings whether they support VoIP, and won't send VoIP data to those not
- reporting support. If a stray VoIP packet makes it to a legacy build, it will
- be ignored without incident.
-
-VoIP packets are saved in demo files! You will be able to playback what you
- heard and what you said on VoIP-compatible clients. Legacy clients can also
- play demo files with VoIP packets in them, but just won't play the voice
- track. For VoIP-supported builds, it's nice to have a record of the
- trash-talk.
-
-Data is processed using the Speex narrowband codec, and is cross-platform.
- Bigendian and littleendian systems can speak to each other, as can 32 and
- 64-bit platforms.
-
-Bandwidth: VoIP data is broken up into 20 millisecond frames (this is a Speex
- requirement), and we try to push up to 12 Speex frames in one UDP packet
- (about a quarter of a second of audio)...we're using the narrowband codec:
- 8000Hz sample rate. In practice, a client should send about 2 kilobytes per
- second more when speaking, spread over about four bursts per second, plus a
- few bytes of state information. For comparison, this is less than the server
- sends when downloading files to the client without an http redirect. The
- server needs to rebroadcast the packet to all clients that should receive it
- (which may be less than the total connected players), so servers should
- assume they'll need to push (number of players speaking at once times number
- of people that should hear it) * 2 kilobytes per second. It shouldn't be a
- problem for any client or server on a broadband connection, although it may
- be painful for dialup users (but then again, everything is. They can just
- disable the cvar). The game will refuse to enable VoIP support if your have
- your network settings lower than "Cable/xDSL/LAN", just in case.
-
-The initial VoIP work was done by Ryan C. Gordon <icculus at icculus.org>, and
- he can be contacted with technical questions, if the ioq3 mailing list or
- forums aren't helpful.
-
-// end of voip-README.txt ...
-
-
-
diff --git a/game/Makefile b/game/Makefile
deleted file mode 100644
index 1520a96..0000000
--- a/game/Makefile
+++ /dev/null
@@ -1,2194 +0,0 @@
-#
-# ioq3 Makefile
-#
-# GNU Make required
-#
-
-COMPILE_PLATFORM=$(shell uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]')
-
-COMPILE_ARCH=$(shell uname -m | sed -e s/i.86/i386/)
-
-ifeq ($(COMPILE_PLATFORM),sunos)
- # Solaris uname and GNU uname differ
- COMPILE_ARCH=$(shell uname -p | sed -e s/i.86/i386/)
-endif
-ifeq ($(COMPILE_PLATFORM),darwin)
- # Apple does some things a little differently...
- COMPILE_ARCH=$(shell uname -p | sed -e s/i.86/i386/)
-endif
-
-ifeq ($(COMPILE_PLATFORM),mingw32)
- ifeq ($(COMPILE_ARCH),i386)
- COMPILE_ARCH=x86
- endif
-endif
-
- BUILD_STANDALONE = 1
- BUILD_CLIENT = 0
- BUILD_CLIENT_SMP = 0
- BUILD_SERVER = 0
- BUILD_GAME_SO = 1
- BUILD_GAME_QVM = 1
-ifndef BUILD_MISSIONPACK
- BUILD_MISSIONPACK=
-endif
-
-ifneq ($(PLATFORM),darwin)
- BUILD_CLIENT_SMP = 0
-endif
-
-#############################################################################
-#
-# If you require a different configuration from the defaults below, create a
-# new file named "Makefile.local" in the same directory as this file and define
-# your parameters there. This allows you to change configuration without
-# causing problems with keeping up to date with the repository.
-#
-#############################################################################
--include Makefile.local
-
-ifndef PLATFORM
-PLATFORM=$(COMPILE_PLATFORM)
-endif
-export PLATFORM
-
-ifeq ($(COMPILE_ARCH),powerpc)
- COMPILE_ARCH=ppc
-endif
-ifeq ($(COMPILE_ARCH),powerpc64)
- COMPILE_ARCH=ppc64
-endif
-
-ifndef ARCH
-ARCH=$(COMPILE_ARCH)
-endif
-export ARCH
-
-ifneq ($(PLATFORM),$(COMPILE_PLATFORM))
- CROSS_COMPILING=1
-else
- CROSS_COMPILING=0
-
- ifneq ($(ARCH),$(COMPILE_ARCH))
- CROSS_COMPILING=1
- endif
-endif
-export CROSS_COMPILING
-
-ifndef COPYDIR
-COPYDIR="/usr/local/games/quake3"
-endif
-
-ifndef MOUNT_DIR
-MOUNT_DIR=code
-endif
-
-ifndef BUILD_DIR
-BUILD_DIR=build
-endif
-
-ifndef GENERATE_DEPENDENCIES
-GENERATE_DEPENDENCIES=1
-endif
-
-ifndef USE_OPENAL
-USE_OPENAL=1
-endif
-
-ifndef USE_OPENAL_DLOPEN
- ifeq ($(PLATFORM),mingw32)
- USE_OPENAL_DLOPEN=1
- else
- USE_OPENAL_DLOPEN=0
- endif
-endif
-
-ifndef USE_CURL
-USE_CURL=1
-endif
-
-ifndef USE_CURL_DLOPEN
- ifeq ($(PLATFORM),mingw32)
- USE_CURL_DLOPEN=0
- else
- USE_CURL_DLOPEN=1
- endif
-endif
-
-ifndef USE_CODEC_VORBIS
-USE_CODEC_VORBIS=0
-endif
-
-ifndef USE_MUMBLE
-USE_MUMBLE=1
-endif
-
-ifndef USE_VOIP
-USE_VOIP=1
-endif
-
-ifndef USE_INTERNAL_SPEEX
-USE_INTERNAL_SPEEX=1
-endif
-
-ifndef USE_LOCAL_HEADERS
-USE_LOCAL_HEADERS=1
-endif
-
-#############################################################################
-
-BD=$(BUILD_DIR)/debug-$(PLATFORM)-$(ARCH)
-BR=$(BUILD_DIR)/release-$(PLATFORM)-$(ARCH)
-CDIR=$(MOUNT_DIR)/client
-SDIR=$(MOUNT_DIR)/server
-RDIR=$(MOUNT_DIR)/renderer
-CMDIR=$(MOUNT_DIR)/qcommon
-SDLDIR=$(MOUNT_DIR)/sdl
-ASMDIR=$(MOUNT_DIR)/asm
-SYSDIR=$(MOUNT_DIR)/sys
-GDIR=$(MOUNT_DIR)/game
-CGDIR=$(MOUNT_DIR)/cgame
-BLIBDIR=$(MOUNT_DIR)/botlib
-NDIR=$(MOUNT_DIR)/null
-UIDIR=$(MOUNT_DIR)/ui
-Q3UIDIR=$(MOUNT_DIR)/q3_ui
-JPDIR=$(MOUNT_DIR)/jpeg-6b
-SPEEXDIR=$(MOUNT_DIR)/libspeex
-Q3ASMDIR=$(MOUNT_DIR)/tools/asm
-LBURGDIR=$(MOUNT_DIR)/tools/lcc/lburg
-Q3CPPDIR=$(MOUNT_DIR)/tools/lcc/cpp
-Q3LCCETCDIR=$(MOUNT_DIR)/tools/lcc/etc
-Q3LCCSRCDIR=$(MOUNT_DIR)/tools/lcc/src
-LOKISETUPDIR=misc/setup
-NSISDIR=misc/nsis
-SDLHDIR=$(MOUNT_DIR)/SDL12
-LIBSDIR=$(MOUNT_DIR)/libs
-TEMPDIR=/tmp
-
-# set PKG_CONFIG_PATH to influence this, e.g.
-# PKG_CONFIG_PATH=/opt/cross/i386-mingw32msvc/lib/pkgconfig
-ifeq ($(shell which pkg-config > /dev/null; echo $$?),0)
- CURL_CFLAGS=$(shell pkg-config --cflags libcurl)
- CURL_LIBS=$(shell pkg-config --libs libcurl)
- OPENAL_CFLAGS=$(shell pkg-config --cflags openal)
- OPENAL_LIBS=$(shell pkg-config --libs openal)
- # FIXME: introduce CLIENT_CFLAGS
- SDL_CFLAGS=$(shell pkg-config --cflags sdl|sed 's/-Dmain=SDL_main//')
- SDL_LIBS=$(shell pkg-config --libs sdl)
-endif
-# Use sdl-config if all else fails
-ifeq ($(SDL_CFLAGS),)
- ifeq ($(shell which sdl-config > /dev/null; echo $$?),0)
- SDL_CFLAGS=$(shell sdl-config --cflags)
- SDL_LIBS=$(shell sdl-config --libs)
- endif
-endif
-
-# version info
-VERSION=1.36
-
-USE_SVN=
-ifeq ($(wildcard .svn),.svn)
- SVN_REV=$(shell LANG=C svnversion .)
- ifneq ($(SVN_REV),)
- VERSION:=$(VERSION)_SVN$(SVN_REV)
- USE_SVN=1
- endif
-else
-ifeq ($(wildcard .git/svn/.metadata),.git/svn/.metadata)
- SVN_REV=$(shell LANG=C git svn info | awk '$$1 == "Revision:" {print $$2; exit 0}')
- ifneq ($(SVN_REV),)
- VERSION:=$(VERSION)_SVN$(SVN_REV)
- endif
-endif
-endif
-
-
-#############################################################################
-# SETUP AND BUILD -- LINUX
-#############################################################################
-
-## Defaults
-LIB=lib
-
-INSTALL=install
-MKDIR=mkdir
-
-ifeq ($(PLATFORM),linux)
-
- ifeq ($(ARCH),alpha)
- ARCH=axp
- else
- ifeq ($(ARCH),x86_64)
- LIB=lib64
- else
- ifeq ($(ARCH),ppc64)
- LIB=lib64
- else
- ifeq ($(ARCH),s390x)
- LIB=lib64
- endif
- endif
- endif
- endif
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -pipe -DUSE_ICON $(SDL_CFLAGS)
-
- ifeq ($(USE_OPENAL),1)
- BASE_CFLAGS += -DUSE_OPENAL
- ifeq ($(USE_OPENAL_DLOPEN),1)
- BASE_CFLAGS += -DUSE_OPENAL_DLOPEN
- endif
- endif
-
- ifeq ($(USE_CURL),1)
- BASE_CFLAGS += -DUSE_CURL
- ifeq ($(USE_CURL_DLOPEN),1)
- BASE_CFLAGS += -DUSE_CURL_DLOPEN
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- BASE_CFLAGS += -DUSE_CODEC_VORBIS
- endif
-
- OPTIMIZE = -O3 -ffast-math -funroll-loops -fomit-frame-pointer
-
- ifeq ($(ARCH),x86_64)
- OPTIMIZE = -O3 -fomit-frame-pointer -ffast-math -funroll-loops \
- -falign-loops=2 -falign-jumps=2 -falign-functions=2 \
- -fstrength-reduce
- # experimental x86_64 jit compiler! you need GNU as
- HAVE_VM_COMPILED = true
- else
- ifeq ($(ARCH),i386)
- OPTIMIZE = -O3 -march=i586 -fomit-frame-pointer -ffast-math \
- -funroll-loops -falign-loops=2 -falign-jumps=2 \
- -falign-functions=2 -fstrength-reduce
- HAVE_VM_COMPILED=true
- else
- ifeq ($(ARCH),ppc)
- BASE_CFLAGS += -maltivec
- HAVE_VM_COMPILED=true
- endif
- ifeq ($(ARCH),ppc64)
- BASE_CFLAGS += -maltivec
- HAVE_VM_COMPILED=true
- endif
- ifeq ($(ARCH),sparc)
- OPTIMIZE += -mtune=ultrasparc3 -mv8plus
- HAVE_VM_COMPILED=true
- endif
- endif
- endif
-
- ifneq ($(HAVE_VM_COMPILED),true)
- BASE_CFLAGS += -DNO_VM_COMPILED
- endif
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- THREAD_LIBS=-lpthread
- LIBS=-ldl -lm
-
- CLIENT_LIBS=$(SDL_LIBS) -lGL
-
- ifeq ($(USE_OPENAL),1)
- ifneq ($(USE_OPENAL_DLOPEN),1)
- CLIENT_LIBS += -lopenal
- endif
- endif
-
- ifeq ($(USE_CURL),1)
- ifneq ($(USE_CURL_DLOPEN),1)
- CLIENT_LIBS += -lcurl
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- CLIENT_LIBS += -lvorbisfile -lvorbis -logg
- endif
-
- ifeq ($(USE_MUMBLE),1)
- CLIENT_LIBS += -lrt
- endif
-
-ifeq ($(USE_LOCAL_HEADERS),1)
- BASE_CFLAGS += -I$(SDLHDIR)/include
- endif
-
- ifeq ($(ARCH),i386)
- # linux32 make ...
- BASE_CFLAGS += -m32
- else
- ifeq ($(ARCH),ppc64)
- BASE_CFLAGS += -m64
- endif
- endif
-
- DEBUG_CFLAGS = $(BASE_CFLAGS) -g -O0
- RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG $(OPTIMIZE)
-
-else # ifeq Linux
-
-#############################################################################
-# SETUP AND BUILD -- MAC OS X
-#############################################################################
-
-ifeq ($(PLATFORM),darwin)
- HAVE_VM_COMPILED=true
- CLIENT_LIBS=
- OPTIMIZE=
-
- BASE_CFLAGS = -Wall -Wimplicit -Wstrict-prototypes
-
- ifeq ($(ARCH),ppc)
- BASE_CFLAGS += -faltivec
- OPTIMIZE += -O3
- endif
- ifeq ($(ARCH),ppc64)
- BASE_CFLAGS += -faltivec
- endif
- ifeq ($(ARCH),i386)
- OPTIMIZE += -march=prescott -mfpmath=sse
- # x86 vm will crash without -mstackrealign since MMX instructions will be
- # used no matter what and they corrupt the frame pointer in VM calls
- BASE_CFLAGS += -mstackrealign
- endif
-
- BASE_CFLAGS += -fno-strict-aliasing -DMACOS_X -fno-common -pipe
-
- ifeq ($(USE_OPENAL),1)
- BASE_CFLAGS += -DUSE_OPENAL
- ifneq ($(USE_OPENAL_DLOPEN),1)
- CLIENT_LIBS += -framework OpenAL
- else
- BASE_CFLAGS += -DUSE_OPENAL_DLOPEN
- endif
- endif
-
- ifeq ($(USE_CURL),1)
- BASE_CFLAGS += -DUSE_CURL
- ifneq ($(USE_CURL_DLOPEN),1)
- CLIENT_LIBS += -lcurl
- else
- BASE_CFLAGS += -DUSE_CURL_DLOPEN
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- BASE_CFLAGS += -DUSE_CODEC_VORBIS
- CLIENT_LIBS += -lvorbisfile -lvorbis -logg
- endif
-
- BASE_CFLAGS += -D_THREAD_SAFE=1
-
- ifeq ($(USE_LOCAL_HEADERS),1)
- BASE_CFLAGS += -I$(SDLHDIR)/include
- endif
-
- # We copy sdlmain before ranlib'ing it so that subversion doesn't think
- # the file has been modified by each build.
- LIBSDLMAIN=$(B)/libSDLmain.a
- LIBSDLMAINSRC=$(LIBSDIR)/macosx/libSDLmain.a
- CLIENT_LIBS += -framework Cocoa -framework IOKit -framework OpenGL \
- $(LIBSDIR)/macosx/libSDL-1.2.0.dylib
-
- OPTIMIZE += -ffast-math -falign-loops=16
-
- ifneq ($(HAVE_VM_COMPILED),true)
- BASE_CFLAGS += -DNO_VM_COMPILED
- endif
-
- DEBUG_CFLAGS = $(BASE_CFLAGS) -g -O0
-
- RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG $(OPTIMIZE)
-
- SHLIBEXT=dylib
- SHLIBCFLAGS=-fPIC -fno-common
- SHLIBLDFLAGS=-dynamiclib $(LDFLAGS)
-
- NOTSHLIBCFLAGS=-mdynamic-no-pic
-
- TOOLS_CFLAGS += -DMACOS_X
-
-else # ifeq darwin
-
-
-#############################################################################
-# SETUP AND BUILD -- MINGW32
-#############################################################################
-
-ifeq ($(PLATFORM),mingw32)
-
- ifndef WINDRES
- WINDRES=windres
- endif
-
- ARCH=x86
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -DUSE_ICON
-
- # In the absence of wspiapi.h, require Windows XP or later
- ifeq ($(shell test -e $(CMDIR)/wspiapi.h; echo $$?),1)
- BASE_CFLAGS += -DWINVER=0x501
- endif
-
- ifeq ($(USE_OPENAL),1)
- BASE_CFLAGS += -DUSE_OPENAL
- BASE_CFLAGS += $(OPENAL_CFLAGS)
- ifeq ($(USE_OPENAL_DLOPEN),1)
- BASE_CFLAGS += -DUSE_OPENAL_DLOPEN
- else
- CLIENT_LDFLAGS += $(OPENAL_LDFLAGS)
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- BASE_CFLAGS += -DUSE_CODEC_VORBIS
- endif
-
- OPTIMIZE = -O3 -march=i586 -fno-omit-frame-pointer -ffast-math \
- -falign-loops=2 -funroll-loops -falign-jumps=2 -falign-functions=2 \
- -fstrength-reduce
-
- HAVE_VM_COMPILED = true
-
- SHLIBEXT=dll
- SHLIBCFLAGS=
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- BINEXT=.exe
-
- LIBS= -lws2_32 -lwinmm
- CLIENT_LDFLAGS = -mwindows
- CLIENT_LIBS = -lgdi32 -lole32 -lopengl32
-
- ifeq ($(USE_CURL),1)
- BASE_CFLAGS += -DUSE_CURL
- BASE_CFLAGS += $(CURL_CFLAGS)
- ifneq ($(USE_CURL_DLOPEN),1)
- ifeq ($(USE_LOCAL_HEADERS),1)
- BASE_CFLAGS += -DCURL_STATICLIB
- CLIENT_LIBS += $(LIBSDIR)/win32/libcurl.a
- else
- CLIENT_LIBS += $(CURL_LIBS)
- endif
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- CLIENT_LIBS += -lvorbisfile -lvorbis -logg
- endif
-
- ifeq ($(ARCH),x86)
- # build 32bit
- BASE_CFLAGS += -m32
- endif
-
- DEBUG_CFLAGS=$(BASE_CFLAGS) -g -O0
- RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG $(OPTIMIZE)
-
- # libmingw32 must be linked before libSDLmain
- CLIENT_LIBS += -lmingw32
- ifeq ($(USE_LOCAL_HEADERS),1)
- BASE_CFLAGS += -I$(SDLHDIR)/include
- CLIENT_LIBS += $(LIBSDIR)/win32/libSDLmain.a \
- $(LIBSDIR)/win32/libSDL.dll.a
- else
- BASE_CFLAGS += $(SDL_CFLAGS)
- CLIENT_LIBS += $(SDL_LIBS)
- endif
-
-
-
- BUILD_CLIENT_SMP = 0
-
-else # ifeq mingw32
-
-#############################################################################
-# SETUP AND BUILD -- FREEBSD
-#############################################################################
-
-ifeq ($(PLATFORM),freebsd)
-
- ifneq (,$(findstring alpha,$(shell uname -m)))
- ARCH=axp
- else #default to i386
- ARCH=i386
- endif #alpha test
-
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -DUSE_ICON $(SDL_CFLAGS)
-
- ifeq ($(USE_OPENAL),1)
- BASE_CFLAGS += -DUSE_OPENAL
- ifeq ($(USE_OPENAL_DLOPEN),1)
- BASE_CFLAGS += -DUSE_OPENAL_DLOPEN
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- BASE_CFLAGS += -DUSE_CODEC_VORBIS
- endif
-
- ifeq ($(ARCH),axp)
- BASE_CFLAGS += -DNO_VM_COMPILED
- RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O3 -ffast-math -funroll-loops \
- -fomit-frame-pointer -fexpensive-optimizations
- else
- ifeq ($(ARCH),i386)
- RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O3 -mtune=pentiumpro \
- -march=pentium -fomit-frame-pointer -pipe -ffast-math \
- -falign-loops=2 -falign-jumps=2 -falign-functions=2 \
- -funroll-loops -fstrength-reduce
- HAVE_VM_COMPILED=true
- else
- BASE_CFLAGS += -DNO_VM_COMPILED
- endif
- endif
-
- DEBUG_CFLAGS=$(BASE_CFLAGS) -g
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- THREAD_LIBS=-lpthread
- # don't need -ldl (FreeBSD)
- LIBS=-lm
-
- CLIENT_LIBS =
-
- CLIENT_LIBS += $(SDL_LIBS) -lGL
-
- ifeq ($(USE_OPENAL),1)
- ifneq ($(USE_OPENAL_DLOPEN),1)
- CLIENT_LIBS += $(THREAD_LIBS) -lopenal
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- CLIENT_LIBS += -lvorbisfile -lvorbis -logg
- endif
-
-else # ifeq freebsd
-
-#############################################################################
-# SETUP AND BUILD -- OPENBSD
-#############################################################################
-
-ifeq ($(PLATFORM),openbsd)
-
- #default to i386, no tests done on anything else
- ARCH=i386
-
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -DUSE_ICON $(SDL_CFLAGS)
-
- ifeq ($(USE_OPENAL),1)
- BASE_CFLAGS += -DUSE_OPENAL
- ifeq ($(USE_OPENAL_DLOPEN),1)
- BASE_CFLAGS += -DUSE_OPENAL_DLOPEN
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- BASE_CFLAGS += -DUSE_CODEC_VORBIS
- endif
-
- BASE_CFLAGS += -DNO_VM_COMPILED -I/usr/X11R6/include -I/usr/local/include
- RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O3 \
- -march=pentium -fomit-frame-pointer -pipe -ffast-math \
- -falign-loops=2 -falign-jumps=2 -falign-functions=2 \
- -funroll-loops -fstrength-reduce
- HAVE_VM_COMPILED=false
-
- DEBUG_CFLAGS=$(BASE_CFLAGS) -g
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- THREAD_LIBS=-lpthread
- LIBS=-lm
-
- CLIENT_LIBS =
-
- CLIENT_LIBS += $(SDL_LIBS) -lGL
-
- ifeq ($(USE_OPENAL),1)
- ifneq ($(USE_OPENAL_DLOPEN),1)
- CLIENT_LIBS += $(THREAD_LIBS) -lossaudio -lopenal
- endif
- endif
-
- ifeq ($(USE_CODEC_VORBIS),1)
- CLIENT_LIBS += -lvorbisfile -lvorbis -logg
- endif
-
-else # ifeq openbsd
-
-#############################################################################
-# SETUP AND BUILD -- NETBSD
-#############################################################################
-
-ifeq ($(PLATFORM),netbsd)
-
- ifeq ($(shell uname -m),i386)
- ARCH=i386
- endif
-
- LIBS=-lm
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared $(LDFLAGS)
- THREAD_LIBS=-lpthread
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes
-
- ifneq ($(ARCH),i386)
- BASE_CFLAGS += -DNO_VM_COMPILED
- endif
-
- DEBUG_CFLAGS=$(BASE_CFLAGS) -g
-
- BUILD_CLIENT = 0
- BUILD_GAME_QVM = 0
-
-else # ifeq netbsd
-
-#############################################################################
-# SETUP AND BUILD -- IRIX
-#############################################################################
-
-ifeq ($(PLATFORM),irix64)
-
- ARCH=mips #default to MIPS
-
- CC = c99
- MKDIR = mkdir -p
-
- BASE_CFLAGS=-Dstricmp=strcasecmp -Xcpluscomm -woff 1185 \
- -I. $(SDL_CFLAGS) -I$(ROOT)/usr/include -DNO_VM_COMPILED
- RELEASE_CFLAGS=$(BASE_CFLAGS) -O3
- DEBUG_CFLAGS=$(BASE_CFLAGS) -g
-
- SHLIBEXT=so
- SHLIBCFLAGS=
- SHLIBLDFLAGS=-shared
-
- LIBS=-ldl -lm -lgen
- # FIXME: The X libraries probably aren't necessary?
- CLIENT_LIBS=-L/usr/X11/$(LIB) $(SDL_LIBS) -lGL \
- -lX11 -lXext -lm
-
-else # ifeq IRIX
-
-#############################################################################
-# SETUP AND BUILD -- SunOS
-#############################################################################
-
-ifeq ($(PLATFORM),sunos)
-
- CC=gcc
- INSTALL=ginstall
- MKDIR=gmkdir
- COPYDIR="/usr/local/share/games/quake3"
-
- ifneq (,$(findstring i86pc,$(shell uname -m)))
- ARCH=i386
- else #default to sparc
- ARCH=sparc
- endif
-
- ifneq ($(ARCH),i386)
- ifneq ($(ARCH),sparc)
- $(error arch $(ARCH) is currently not supported)
- endif
- endif
-
- BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -pipe -DUSE_ICON $(SDL_CFLAGS)
-
- OPTIMIZE = -O3 -ffast-math -funroll-loops
-
- ifeq ($(ARCH),sparc)
- OPTIMIZE = -O3 -ffast-math \
- -fstrength-reduce -falign-functions=2 \
- -mtune=ultrasparc3 -mv8plus -mno-faster-structs \
- -funroll-loops #-mv8plus
- HAVE_VM_COMPILED=true
- else
- ifeq ($(ARCH),i386)
- OPTIMIZE = -O3 -march=i586 -fomit-frame-pointer -ffast-math \
- -funroll-loops -falign-loops=2 -falign-jumps=2 \
- -falign-functions=2 -fstrength-reduce
- HAVE_VM_COMPILED=true
- BASE_CFLAGS += -m32
- BASE_CFLAGS += -I/usr/X11/include/NVIDIA
- CLIENT_LDFLAGS += -L/usr/X11/lib/NVIDIA -R/usr/X11/lib/NVIDIA
- endif
- endif
-
- ifneq ($(HAVE_VM_COMPILED),true)
- BASE_CFLAGS += -DNO_VM_COMPILED
- endif
-
- DEBUG_CFLAGS = $(BASE_CFLAGS) -ggdb -O0
-
- RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG $(OPTIMIZE)
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared $(LDFLAGS)
-
- THREAD_LIBS=-lpthread
- LIBS=-lsocket -lnsl -ldl -lm
-
- BOTCFLAGS=-O0
-
- CLIENT_LIBS +=$(SDL_LIBS) -lGL -lX11 -lXext -liconv -lm
-
-else # ifeq sunos
-
-#############################################################################
-# SETUP AND BUILD -- GENERIC
-#############################################################################
- BASE_CFLAGS=-DNO_VM_COMPILED
- DEBUG_CFLAGS=$(BASE_CFLAGS) -g
- RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O3
-
- SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
- SHLIBLDFLAGS=-shared
-
-endif #Linux
-endif #darwin
-endif #mingw32
-endif #FreeBSD
-endif #OpenBSD
-endif #NetBSD
-endif #IRIX
-endif #SunOS
-
-TARGETS =
-
-ifneq ($(BUILD_SERVER),0)
- TARGETS += $(B)/ioq3ded.$(ARCH)$(BINEXT)
-endif
-
-ifneq ($(BUILD_CLIENT),0)
- TARGETS += $(B)/ioquake3.$(ARCH)$(BINEXT)
- ifneq ($(BUILD_CLIENT_SMP),0)
- TARGETS += $(B)/ioquake3-smp.$(ARCH)$(BINEXT)
- endif
-endif
-
-ifneq ($(BUILD_GAME_SO),0)
- TARGETS += \
- $(B)/baseq3/cgame$(ARCH).$(SHLIBEXT) \
- $(B)/baseq3/qagame$(ARCH).$(SHLIBEXT) \
- $(B)/baseq3/ui$(ARCH).$(SHLIBEXT)
- ifneq ($(BUILD_MISSIONPACK),0)
- TARGETS += \
- $(B)/missionpack/cgame$(ARCH).$(SHLIBEXT) \
- $(B)/missionpack/qagame$(ARCH).$(SHLIBEXT) \
- $(B)/missionpack/ui$(ARCH).$(SHLIBEXT)
- endif
-endif
-
-ifneq ($(BUILD_GAME_QVM),0)
- ifneq ($(CROSS_COMPILING),1)
- TARGETS += \
- $(B)/baseq3/vm/cgame.qvm \
- $(B)/baseq3/vm/qagame.qvm \
- $(B)/baseq3/vm/ui.qvm
- ifneq ($(BUILD_MISSIONPACK),0)
- TARGETS += \
- $(B)/missionpack/vm/qagame.qvm \
- $(B)/missionpack/vm/cgame.qvm \
- $(B)/missionpack/vm/ui.qvm
- endif
- endif
-endif
-
-ifeq ($(USE_MUMBLE),1)
- BASE_CFLAGS += -DUSE_MUMBLE
-endif
-
-ifeq ($(USE_VOIP),1)
- BASE_CFLAGS += -DUSE_VOIP
- ifeq ($(USE_INTERNAL_SPEEX),1)
- BASE_CFLAGS += -DFLOATING_POINT -DUSE_ALLOCA -I$(SPEEXDIR)/include
- else
- CLIENT_LIBS += -lspeex
- endif
-endif
-
-ifdef DEFAULT_BASEDIR
- BASE_CFLAGS += -DDEFAULT_BASEDIR=\\\"$(DEFAULT_BASEDIR)\\\"
-endif
-
-ifeq ($(USE_LOCAL_HEADERS),1)
- BASE_CFLAGS += -DUSE_LOCAL_HEADERS
-endif
-
-ifeq ($(BUILD_STANDALONE),1)
- BASE_CFLAGS += -DSTANDALONE
-endif
-
-ifeq ($(GENERATE_DEPENDENCIES),1)
- DEPEND_CFLAGS = -MMD
-else
- DEPEND_CFLAGS =
-endif
-
-BASE_CFLAGS += -DPRODUCT_VERSION=\\\"$(VERSION)\\\"
-
-ifeq ($(V),1)
-echo_cmd=@:
-Q=
-else
-echo_cmd=@echo
-Q=@
-endif
-
-define DO_CC
-$(echo_cmd) "CC $<"
-$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) -o $@ -c $<
-endef
-
-define DO_SMP_CC
-$(echo_cmd) "SMP_CC $<"
-$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) -DSMP -o $@ -c $<
-endef
-
-define DO_BOT_CC
-$(echo_cmd) "BOT_CC $<"
-$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) $(BOTCFLAGS) -DBOTLIB -o $@ -c $<
-endef
-
-ifeq ($(GENERATE_DEPENDENCIES),1)
- DO_QVM_DEP=cat $(@:%.o=%.d) | sed -e 's/\.o/\.asm/g' >> $(@:%.o=%.d)
-endif
-
-define DO_SHLIB_CC
-$(echo_cmd) "SHLIB_CC $<"
-$(Q)$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_GAME_CC
-$(echo_cmd) "GAME_CC $<"
-$(Q)$(CC) -DQAGAME $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_CGAME_CC
-$(echo_cmd) "CGAME_CC $<"
-$(Q)$(CC) -DCGAME $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_UI_CC
-$(echo_cmd) "UI_CC $<"
-$(Q)$(CC) -DUI $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_SHLIB_CC_MISSIONPACK
-$(echo_cmd) "SHLIB_CC_MISSIONPACK $<"
-$(Q)$(CC) -DMISSIONPACK $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_GAME_CC_MISSIONPACK
-$(echo_cmd) "GAME_CC_MISSIONPACK $<"
-$(Q)$(CC) -DMISSIONPACK -DQAGAME $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_CGAME_CC_MISSIONPACK
-$(echo_cmd) "CGAME_CC_MISSIONPACK $<"
-$(Q)$(CC) -DMISSIONPACK -DCGAME $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_UI_CC_MISSIONPACK
-$(echo_cmd) "UI_CC_MISSIONPACK $<"
-$(Q)$(CC) -DMISSIONPACK -DUI $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
-$(Q)$(DO_QVM_DEP)
-endef
-
-define DO_AS
-$(echo_cmd) "AS $<"
-$(Q)$(CC) $(CFLAGS) -x assembler-with-cpp -o $@ -c $<
-endef
-
-define DO_DED_CC
-$(echo_cmd) "DED_CC $<"
-$(Q)$(CC) $(NOTSHLIBCFLAGS) -DDEDICATED $(CFLAGS) -o $@ -c $<
-endef
-
-define DO_WINDRES
-$(echo_cmd) "WINDRES $<"
-$(Q)$(WINDRES) -i $< -o $@
-endef
-
-
-#############################################################################
-# MAIN TARGETS
-#############################################################################
-
-default: release
-all: debug release
-
-debug:
- @$(MAKE) targets B=$(BD) CFLAGS="$(CFLAGS) $(DEPEND_CFLAGS) \
- $(DEBUG_CFLAGS)" V=$(V)
-
-release:
- @$(MAKE) targets B=$(BR) CFLAGS="$(CFLAGS) $(DEPEND_CFLAGS) \
- $(RELEASE_CFLAGS)" V=$(V)
-
-# Create the build directories, check libraries and print out
-# an informational message, then start building
-targets: makedirs
- @echo ""
- @echo "Building ioquake3 in $(B):"
- @echo " PLATFORM: $(PLATFORM)"
- @echo " ARCH: $(ARCH)"
- @echo " VERSION: $(VERSION)"
- @echo " COMPILE_PLATFORM: $(COMPILE_PLATFORM)"
- @echo " COMPILE_ARCH: $(COMPILE_ARCH)"
- @echo " CC: $(CC)"
- @echo ""
- @echo " CFLAGS:"
- - at for i in $(CFLAGS); \
- do \
- echo " $$i"; \
- done
- @echo ""
- @echo " LDFLAGS:"
- - at for i in $(LDFLAGS); \
- do \
- echo " $$i"; \
- done
- @echo ""
- @echo " LIBS:"
- - at for i in $(LIBS); \
- do \
- echo " $$i"; \
- done
- @echo ""
- @echo " CLIENT_LIBS:"
- - at for i in $(CLIENT_LIBS); \
- do \
- echo " $$i"; \
- done
- @echo ""
- @echo " Output:"
- - at for i in $(TARGETS); \
- do \
- echo " $$i"; \
- done
- @echo ""
-ifneq ($(TARGETS),)
- @$(MAKE) $(TARGETS) V=$(V)
-endif
-
-makedirs:
- @if [ ! -d $(BUILD_DIR) ];then $(MKDIR) $(BUILD_DIR);fi
- @if [ ! -d $(B) ];then $(MKDIR) $(B);fi
- @if [ ! -d $(B)/client ];then $(MKDIR) $(B)/client;fi
- @if [ ! -d $(B)/clientsmp ];then $(MKDIR) $(B)/clientsmp;fi
- @if [ ! -d $(B)/ded ];then $(MKDIR) $(B)/ded;fi
- @if [ ! -d $(B)/baseq3 ];then $(MKDIR) $(B)/baseq3;fi
- @if [ ! -d $(B)/baseq3/cgame ];then $(MKDIR) $(B)/baseq3/cgame;fi
- @if [ ! -d $(B)/baseq3/game ];then $(MKDIR) $(B)/baseq3/game;fi
- @if [ ! -d $(B)/baseq3/ui ];then $(MKDIR) $(B)/baseq3/ui;fi
- @if [ ! -d $(B)/baseq3/qcommon ];then $(MKDIR) $(B)/baseq3/qcommon;fi
- @if [ ! -d $(B)/baseq3/vm ];then $(MKDIR) $(B)/baseq3/vm;fi
- @if [ ! -d $(B)/missionpack ];then $(MKDIR) $(B)/missionpack;fi
- @if [ ! -d $(B)/missionpack/cgame ];then $(MKDIR) $(B)/missionpack/cgame;fi
- @if [ ! -d $(B)/missionpack/game ];then $(MKDIR) $(B)/missionpack/game;fi
- @if [ ! -d $(B)/missionpack/ui ];then $(MKDIR) $(B)/missionpack/ui;fi
- @if [ ! -d $(B)/missionpack/qcommon ];then $(MKDIR) $(B)/missionpack/qcommon;fi
- @if [ ! -d $(B)/missionpack/vm ];then $(MKDIR) $(B)/missionpack/vm;fi
- @if [ ! -d $(B)/tools ];then $(MKDIR) $(B)/tools;fi
- @if [ ! -d $(B)/tools/asm ];then $(MKDIR) $(B)/tools/asm;fi
- @if [ ! -d $(B)/tools/etc ];then $(MKDIR) $(B)/tools/etc;fi
- @if [ ! -d $(B)/tools/rcc ];then $(MKDIR) $(B)/tools/rcc;fi
- @if [ ! -d $(B)/tools/cpp ];then $(MKDIR) $(B)/tools/cpp;fi
- @if [ ! -d $(B)/tools/lburg ];then $(MKDIR) $(B)/tools/lburg;fi
-
-#############################################################################
-# QVM BUILD TOOLS
-#############################################################################
-
-TOOLS_OPTIMIZE = -g -O2 -Wall -fno-strict-aliasing
-TOOLS_CFLAGS = $(TOOLS_OPTIMIZE) \
- -DTEMPDIR=\"$(TEMPDIR)\" -DSYSTEM=\"\" \
- -I$(Q3LCCSRCDIR) \
- -I$(LBURGDIR)
-TOOLS_LIBS =
-TOOLS_LDFLAGS =
-
-ifeq ($(GENERATE_DEPENDENCIES),1)
- TOOLS_CFLAGS += -MMD
-endif
-
-define DO_TOOLS_CC
-$(echo_cmd) "TOOLS_CC $<"
-$(Q)$(CC) $(TOOLS_CFLAGS) -o $@ -c $<
-endef
-
-define DO_TOOLS_CC_DAGCHECK
-$(echo_cmd) "TOOLS_CC_DAGCHECK $<"
-$(Q)$(CC) $(TOOLS_CFLAGS) -Wno-unused -o $@ -c $<
-endef
-
-LBURG = $(B)/tools/lburg/lburg$(BINEXT)
-DAGCHECK_C = $(B)/tools/rcc/dagcheck.c
-Q3RCC = $(B)/tools/q3rcc$(BINEXT)
-Q3CPP = $(B)/tools/q3cpp$(BINEXT)
-Q3LCC = $(B)/tools/q3lcc$(BINEXT)
-Q3ASM = $(B)/tools/q3asm$(BINEXT)
-
-LBURGOBJ= \
- $(B)/tools/lburg/lburg.o \
- $(B)/tools/lburg/gram.o
-
-$(B)/tools/lburg/%.o: $(LBURGDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(LBURG): $(LBURGOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
-
-Q3RCCOBJ = \
- $(B)/tools/rcc/alloc.o \
- $(B)/tools/rcc/bind.o \
- $(B)/tools/rcc/bytecode.o \
- $(B)/tools/rcc/dag.o \
- $(B)/tools/rcc/dagcheck.o \
- $(B)/tools/rcc/decl.o \
- $(B)/tools/rcc/enode.o \
- $(B)/tools/rcc/error.o \
- $(B)/tools/rcc/event.o \
- $(B)/tools/rcc/expr.o \
- $(B)/tools/rcc/gen.o \
- $(B)/tools/rcc/init.o \
- $(B)/tools/rcc/inits.o \
- $(B)/tools/rcc/input.o \
- $(B)/tools/rcc/lex.o \
- $(B)/tools/rcc/list.o \
- $(B)/tools/rcc/main.o \
- $(B)/tools/rcc/null.o \
- $(B)/tools/rcc/output.o \
- $(B)/tools/rcc/prof.o \
- $(B)/tools/rcc/profio.o \
- $(B)/tools/rcc/simp.o \
- $(B)/tools/rcc/stmt.o \
- $(B)/tools/rcc/string.o \
- $(B)/tools/rcc/sym.o \
- $(B)/tools/rcc/symbolic.o \
- $(B)/tools/rcc/trace.o \
- $(B)/tools/rcc/tree.o \
- $(B)/tools/rcc/types.o
-
-$(DAGCHECK_C): $(LBURG) $(Q3LCCSRCDIR)/dagcheck.md
- $(echo_cmd) "LBURG $(Q3LCCSRCDIR)/dagcheck.md"
- $(Q)$(LBURG) $(Q3LCCSRCDIR)/dagcheck.md $@
-
-$(B)/tools/rcc/dagcheck.o: $(DAGCHECK_C)
- $(DO_TOOLS_CC_DAGCHECK)
-
-$(B)/tools/rcc/%.o: $(Q3LCCSRCDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(Q3RCC): $(Q3RCCOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
-
-Q3CPPOBJ = \
- $(B)/tools/cpp/cpp.o \
- $(B)/tools/cpp/lex.o \
- $(B)/tools/cpp/nlist.o \
- $(B)/tools/cpp/tokens.o \
- $(B)/tools/cpp/macro.o \
- $(B)/tools/cpp/eval.o \
- $(B)/tools/cpp/include.o \
- $(B)/tools/cpp/hideset.o \
- $(B)/tools/cpp/getopt.o \
- $(B)/tools/cpp/unix.o
-
-$(B)/tools/cpp/%.o: $(Q3CPPDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(Q3CPP): $(Q3CPPOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
-
-Q3LCCOBJ = \
- $(B)/tools/etc/lcc.o \
- $(B)/tools/etc/bytecode.o
-
-$(B)/tools/etc/%.o: $(Q3LCCETCDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(Q3LCC): $(Q3LCCOBJ) $(Q3RCC) $(Q3CPP)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $(Q3LCCOBJ) $(TOOLS_LIBS)
-
-define DO_Q3LCC
-$(echo_cmd) "Q3LCC $<"
-$(Q)$(Q3LCC) -o $@ $<
-endef
-
-define DO_CGAME_Q3LCC
-$(echo_cmd) "CGAME_Q3LCC $<"
-$(Q)$(Q3LCC) -DCGAME -o $@ $<
-endef
-
-define DO_GAME_Q3LCC
-$(echo_cmd) "GAME_Q3LCC $<"
-$(Q)$(Q3LCC) -DQAGAME -o $@ $<
-endef
-
-define DO_UI_Q3LCC
-$(echo_cmd) "UI_Q3LCC $<"
-$(Q)$(Q3LCC) -DUI -o $@ $<
-endef
-
-define DO_Q3LCC_MISSIONPACK
-$(echo_cmd) "Q3LCC_MISSIONPACK $<"
-$(Q)$(Q3LCC) -DMISSIONPACK -o $@ $<
-endef
-
-define DO_CGAME_Q3LCC_MISSIONPACK
-$(echo_cmd) "CGAME_Q3LCC_MISSIONPACK $<"
-$(Q)$(Q3LCC) -DMISSIONPACK -DCGAME -o $@ $<
-endef
-
-define DO_GAME_Q3LCC_MISSIONPACK
-$(echo_cmd) "GAME_Q3LCC_MISSIONPACK $<"
-$(Q)$(Q3LCC) -DMISSIONPACK -DQAGAME -o $@ $<
-endef
-
-define DO_UI_Q3LCC_MISSIONPACK
-$(echo_cmd) "UI_Q3LCC_MISSIONPACK $<"
-$(Q)$(Q3LCC) -DMISSIONPACK -DUI -o $@ $<
-endef
-
-
-Q3ASMOBJ = \
- $(B)/tools/asm/q3asm.o \
- $(B)/tools/asm/cmdlib.o
-
-$(B)/tools/asm/%.o: $(Q3ASMDIR)/%.c
- $(DO_TOOLS_CC)
-
-$(Q3ASM): $(Q3ASMOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
-
-
-#############################################################################
-# CLIENT/SERVER
-#############################################################################
-
-Q3OBJ = \
- $(B)/client/cl_cgame.o \
- $(B)/client/cl_cin.o \
- $(B)/client/cl_console.o \
- $(B)/client/cl_input.o \
- $(B)/client/cl_keys.o \
- $(B)/client/cl_main.o \
- $(B)/client/cl_net_chan.o \
- $(B)/client/cl_parse.o \
- $(B)/client/cl_scrn.o \
- $(B)/client/cl_ui.o \
- $(B)/client/cl_avi.o \
- \
- $(B)/client/cm_load.o \
- $(B)/client/cm_patch.o \
- $(B)/client/cm_polylib.o \
- $(B)/client/cm_test.o \
- $(B)/client/cm_trace.o \
- \
- $(B)/client/cmd.o \
- $(B)/client/common.o \
- $(B)/client/cvar.o \
- $(B)/client/files.o \
- $(B)/client/md4.o \
- $(B)/client/md5.o \
- $(B)/client/msg.o \
- $(B)/client/net_chan.o \
- $(B)/client/net_ip.o \
- $(B)/client/huffman.o \
- \
- $(B)/client/snd_adpcm.o \
- $(B)/client/snd_dma.o \
- $(B)/client/snd_mem.o \
- $(B)/client/snd_mix.o \
- $(B)/client/snd_wavelet.o \
- \
- $(B)/client/snd_main.o \
- $(B)/client/snd_codec.o \
- $(B)/client/snd_codec_wav.o \
- $(B)/client/snd_codec_ogg.o \
- \
- $(B)/client/qal.o \
- $(B)/client/snd_openal.o \
- \
- $(B)/client/cl_curl.o \
- \
- $(B)/client/sv_bot.o \
- $(B)/client/sv_ccmds.o \
- $(B)/client/sv_client.o \
- $(B)/client/sv_game.o \
- $(B)/client/sv_init.o \
- $(B)/client/sv_main.o \
- $(B)/client/sv_net_chan.o \
- $(B)/client/sv_snapshot.o \
- $(B)/client/sv_world.o \
- \
- $(B)/client/q_math.o \
- $(B)/client/q_shared.o \
- \
- $(B)/client/unzip.o \
- $(B)/client/puff.o \
- $(B)/client/vm.o \
- $(B)/client/vm_interpreted.o \
- \
- $(B)/client/be_aas_bspq3.o \
- $(B)/client/be_aas_cluster.o \
- $(B)/client/be_aas_debug.o \
- $(B)/client/be_aas_entity.o \
- $(B)/client/be_aas_file.o \
- $(B)/client/be_aas_main.o \
- $(B)/client/be_aas_move.o \
- $(B)/client/be_aas_optimize.o \
- $(B)/client/be_aas_reach.o \
- $(B)/client/be_aas_route.o \
- $(B)/client/be_aas_routealt.o \
- $(B)/client/be_aas_sample.o \
- $(B)/client/be_ai_char.o \
- $(B)/client/be_ai_chat.o \
- $(B)/client/be_ai_gen.o \
- $(B)/client/be_ai_goal.o \
- $(B)/client/be_ai_move.o \
- $(B)/client/be_ai_weap.o \
- $(B)/client/be_ai_weight.o \
- $(B)/client/be_ea.o \
- $(B)/client/be_interface.o \
- $(B)/client/l_crc.o \
- $(B)/client/l_libvar.o \
- $(B)/client/l_log.o \
- $(B)/client/l_memory.o \
- $(B)/client/l_precomp.o \
- $(B)/client/l_script.o \
- $(B)/client/l_struct.o \
- \
- $(B)/client/jcapimin.o \
- $(B)/client/jcapistd.o \
- $(B)/client/jccoefct.o \
- $(B)/client/jccolor.o \
- $(B)/client/jcdctmgr.o \
- $(B)/client/jchuff.o \
- $(B)/client/jcinit.o \
- $(B)/client/jcmainct.o \
- $(B)/client/jcmarker.o \
- $(B)/client/jcmaster.o \
- $(B)/client/jcomapi.o \
- $(B)/client/jcparam.o \
- $(B)/client/jcphuff.o \
- $(B)/client/jcprepct.o \
- $(B)/client/jcsample.o \
- $(B)/client/jdapimin.o \
- $(B)/client/jdapistd.o \
- $(B)/client/jdatasrc.o \
- $(B)/client/jdcoefct.o \
- $(B)/client/jdcolor.o \
- $(B)/client/jddctmgr.o \
- $(B)/client/jdhuff.o \
- $(B)/client/jdinput.o \
- $(B)/client/jdmainct.o \
- $(B)/client/jdmarker.o \
- $(B)/client/jdmaster.o \
- $(B)/client/jdpostct.o \
- $(B)/client/jdsample.o \
- $(B)/client/jdtrans.o \
- $(B)/client/jerror.o \
- $(B)/client/jfdctflt.o \
- $(B)/client/jidctflt.o \
- $(B)/client/jmemmgr.o \
- $(B)/client/jmemnobs.o \
- $(B)/client/jutils.o \
- \
- $(B)/client/tr_animation.o \
- $(B)/client/tr_backend.o \
- $(B)/client/tr_bsp.o \
- $(B)/client/tr_cmds.o \
- $(B)/client/tr_curve.o \
- $(B)/client/tr_flares.o \
- $(B)/client/tr_font.o \
- $(B)/client/tr_image.o \
- $(B)/client/tr_image_png.o \
- $(B)/client/tr_image_jpg.o \
- $(B)/client/tr_image_bmp.o \
- $(B)/client/tr_image_tga.o \
- $(B)/client/tr_image_pcx.o \
- $(B)/client/tr_init.o \
- $(B)/client/tr_light.o \
- $(B)/client/tr_main.o \
- $(B)/client/tr_marks.o \
- $(B)/client/tr_mesh.o \
- $(B)/client/tr_model.o \
- $(B)/client/tr_noise.o \
- $(B)/client/tr_scene.o \
- $(B)/client/tr_shade.o \
- $(B)/client/tr_shade_calc.o \
- $(B)/client/tr_shader.o \
- $(B)/client/tr_shadows.o \
- $(B)/client/tr_sky.o \
- $(B)/client/tr_surface.o \
- $(B)/client/tr_world.o \
- \
- $(B)/client/sdl_gamma.o \
- $(B)/client/sdl_input.o \
- $(B)/client/sdl_snd.o \
- \
- $(B)/client/con_passive.o \
- $(B)/client/con_log.o \
- $(B)/client/sys_main.o
-
-ifeq ($(ARCH),i386)
- Q3OBJ += \
- $(B)/client/snd_mixa.o \
- $(B)/client/matha.o \
- $(B)/client/ftola.o \
- $(B)/client/snapvectora.o
-endif
-ifeq ($(ARCH),x86)
- Q3OBJ += \
- $(B)/client/snd_mixa.o \
- $(B)/client/matha.o \
- $(B)/client/ftola.o \
- $(B)/client/snapvectora.o
-endif
-
-ifeq ($(USE_VOIP),1)
-ifeq ($(USE_INTERNAL_SPEEX),1)
-Q3OBJ += \
- $(B)/client/bits.o \
- $(B)/client/buffer.o \
- $(B)/client/cb_search.o \
- $(B)/client/exc_10_16_table.o \
- $(B)/client/exc_10_32_table.o \
- $(B)/client/exc_20_32_table.o \
- $(B)/client/exc_5_256_table.o \
- $(B)/client/exc_5_64_table.o \
- $(B)/client/exc_8_128_table.o \
- $(B)/client/fftwrap.o \
- $(B)/client/filterbank.o \
- $(B)/client/filters.o \
- $(B)/client/gain_table.o \
- $(B)/client/gain_table_lbr.o \
- $(B)/client/hexc_10_32_table.o \
- $(B)/client/hexc_table.o \
- $(B)/client/high_lsp_tables.o \
- $(B)/client/jitter.o \
- $(B)/client/kiss_fft.o \
- $(B)/client/kiss_fftr.o \
- $(B)/client/lpc.o \
- $(B)/client/lsp.o \
- $(B)/client/lsp_tables_nb.o \
- $(B)/client/ltp.o \
- $(B)/client/mdf.o \
- $(B)/client/modes.o \
- $(B)/client/modes_wb.o \
- $(B)/client/nb_celp.o \
- $(B)/client/preprocess.o \
- $(B)/client/quant_lsp.o \
- $(B)/client/resample.o \
- $(B)/client/sb_celp.o \
- $(B)/client/smallft.o \
- $(B)/client/speex.o \
- $(B)/client/speex_callbacks.o \
- $(B)/client/speex_header.o \
- $(B)/client/stereo.o \
- $(B)/client/vbr.o \
- $(B)/client/vq.o \
- $(B)/client/window.o
-endif
-endif
-
-
-ifeq ($(HAVE_VM_COMPILED),true)
- ifeq ($(ARCH),i386)
- Q3OBJ += $(B)/client/vm_x86.o
- endif
- ifeq ($(ARCH),x86)
- Q3OBJ += $(B)/client/vm_x86.o
- endif
- ifeq ($(ARCH),x86_64)
- Q3OBJ += $(B)/client/vm_x86_64.o $(B)/client/vm_x86_64_assembler.o
- endif
- ifeq ($(ARCH),ppc)
- Q3OBJ += $(B)/client/vm_powerpc.o $(B)/client/vm_powerpc_asm.o
- endif
- ifeq ($(ARCH),ppc64)
- Q3OBJ += $(B)/client/vm_powerpc.o $(B)/client/vm_powerpc_asm.o
- endif
- ifeq ($(ARCH),sparc)
- Q3OBJ += $(B)/client/vm_sparc.o
- endif
-endif
-
-ifeq ($(PLATFORM),mingw32)
- Q3OBJ += \
- $(B)/client/win_resource.o \
- $(B)/client/sys_win32.o
-else
- Q3OBJ += \
- $(B)/client/sys_unix.o
-endif
-
-ifeq ($(USE_MUMBLE),1)
- Q3OBJ += \
- $(B)/client/libmumblelink.o
-endif
-
-Q3POBJ += \
- $(B)/client/sdl_glimp.o
-
-Q3POBJ_SMP += \
- $(B)/clientsmp/sdl_glimp.o
-
-$(B)/ioquake3.$(ARCH)$(BINEXT): $(Q3OBJ) $(Q3POBJ) $(LIBSDLMAIN)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \
- -o $@ $(Q3OBJ) $(Q3POBJ) \
- $(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS)
-
-$(B)/ioquake3-smp.$(ARCH)$(BINEXT): $(Q3OBJ) $(Q3POBJ_SMP) $(LIBSDLMAIN)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(THREAD_LDFLAGS) \
- -o $@ $(Q3OBJ) $(Q3POBJ_SMP) \
- $(THREAD_LIBS) $(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS)
-
-ifneq ($(strip $(LIBSDLMAIN)),)
-ifneq ($(strip $(LIBSDLMAINSRC)),)
-$(LIBSDLMAIN) : $(LIBSDLMAINSRC)
- cp $< $@
- ranlib $@
-endif
-endif
-
-
-
-#############################################################################
-# DEDICATED SERVER
-#############################################################################
-
-Q3DOBJ = \
- $(B)/ded/sv_bot.o \
- $(B)/ded/sv_client.o \
- $(B)/ded/sv_ccmds.o \
- $(B)/ded/sv_game.o \
- $(B)/ded/sv_init.o \
- $(B)/ded/sv_main.o \
- $(B)/ded/sv_net_chan.o \
- $(B)/ded/sv_snapshot.o \
- $(B)/ded/sv_world.o \
- \
- $(B)/ded/cm_load.o \
- $(B)/ded/cm_patch.o \
- $(B)/ded/cm_polylib.o \
- $(B)/ded/cm_test.o \
- $(B)/ded/cm_trace.o \
- $(B)/ded/cmd.o \
- $(B)/ded/common.o \
- $(B)/ded/cvar.o \
- $(B)/ded/files.o \
- $(B)/ded/md4.o \
- $(B)/ded/msg.o \
- $(B)/ded/net_chan.o \
- $(B)/ded/net_ip.o \
- $(B)/ded/huffman.o \
- \
- $(B)/ded/q_math.o \
- $(B)/ded/q_shared.o \
- \
- $(B)/ded/unzip.o \
- $(B)/ded/vm.o \
- $(B)/ded/vm_interpreted.o \
- \
- $(B)/ded/be_aas_bspq3.o \
- $(B)/ded/be_aas_cluster.o \
- $(B)/ded/be_aas_debug.o \
- $(B)/ded/be_aas_entity.o \
- $(B)/ded/be_aas_file.o \
- $(B)/ded/be_aas_main.o \
- $(B)/ded/be_aas_move.o \
- $(B)/ded/be_aas_optimize.o \
- $(B)/ded/be_aas_reach.o \
- $(B)/ded/be_aas_route.o \
- $(B)/ded/be_aas_routealt.o \
- $(B)/ded/be_aas_sample.o \
- $(B)/ded/be_ai_char.o \
- $(B)/ded/be_ai_chat.o \
- $(B)/ded/be_ai_gen.o \
- $(B)/ded/be_ai_goal.o \
- $(B)/ded/be_ai_move.o \
- $(B)/ded/be_ai_weap.o \
- $(B)/ded/be_ai_weight.o \
- $(B)/ded/be_ea.o \
- $(B)/ded/be_interface.o \
- $(B)/ded/l_crc.o \
- $(B)/ded/l_libvar.o \
- $(B)/ded/l_log.o \
- $(B)/ded/l_memory.o \
- $(B)/ded/l_precomp.o \
- $(B)/ded/l_script.o \
- $(B)/ded/l_struct.o \
- \
- $(B)/ded/null_client.o \
- $(B)/ded/null_input.o \
- $(B)/ded/null_snddma.o \
- \
- $(B)/ded/con_log.o \
- $(B)/ded/sys_main.o
-
-ifeq ($(ARCH),i386)
- Q3DOBJ += \
- $(B)/ded/ftola.o \
- $(B)/ded/snapvectora.o \
- $(B)/ded/matha.o
-endif
-ifeq ($(ARCH),x86)
- Q3DOBJ += \
- $(B)/ded/ftola.o \
- $(B)/ded/snapvectora.o \
- $(B)/ded/matha.o
-endif
-
-ifeq ($(HAVE_VM_COMPILED),true)
- ifeq ($(ARCH),i386)
- Q3DOBJ += $(B)/ded/vm_x86.o
- endif
- ifeq ($(ARCH),x86)
- Q3DOBJ += $(B)/ded/vm_x86.o
- endif
- ifeq ($(ARCH),x86_64)
- Q3DOBJ += $(B)/ded/vm_x86_64.o $(B)/ded/vm_x86_64_assembler.o
- endif
- ifeq ($(ARCH),ppc)
- Q3DOBJ += $(B)/ded/vm_powerpc.o $(B)/ded/vm_powerpc_asm.o
- endif
- ifeq ($(ARCH),ppc64)
- Q3DOBJ += $(B)/ded/vm_powerpc.o $(B)/ded/vm_powerpc_asm.o
- endif
- ifeq ($(ARCH),sparc)
- Q3DOBJ += $(B)/ded/vm_sparc.o
- endif
-endif
-
-ifeq ($(PLATFORM),mingw32)
- Q3DOBJ += \
- $(B)/ded/win_resource.o \
- $(B)/ded/sys_win32.o \
- $(B)/ded/con_win32.o
-else
- Q3DOBJ += \
- $(B)/ded/sys_unix.o \
- $(B)/ded/con_tty.o
-endif
-
-$(B)/ioq3ded.$(ARCH)$(BINEXT): $(Q3DOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(Q3DOBJ) $(LIBS)
-
-
-
-#############################################################################
-## BASEQ3 CGAME
-#############################################################################
-
-Q3CGOBJ_ = \
- $(B)/baseq3/cgame/cg_main.o \
- $(B)/baseq3/game/bg_misc.o \
- $(B)/baseq3/game/bg_lib.o \
- $(B)/baseq3/game/bg_pmove.o \
- $(B)/baseq3/game/bg_slidemove.o \
- $(B)/baseq3/cgame/cg_challenges.o \
- $(B)/baseq3/cgame/cg_consolecmds.o \
- $(B)/baseq3/cgame/cg_draw.o \
- $(B)/baseq3/cgame/cg_drawtools.o \
- $(B)/baseq3/cgame/cg_effects.o \
- $(B)/baseq3/cgame/cg_ents.o \
- $(B)/baseq3/cgame/cg_event.o \
- $(B)/baseq3/cgame/cg_info.o \
- $(B)/baseq3/cgame/cg_localents.o \
- $(B)/baseq3/cgame/cg_marks.o \
- $(B)/baseq3/cgame/cg_players.o \
- $(B)/baseq3/cgame/cg_playerstate.o \
- $(B)/baseq3/cgame/cg_predict.o \
- $(B)/baseq3/cgame/cg_scoreboard.o \
- $(B)/baseq3/cgame/cg_servercmds.o \
- $(B)/baseq3/cgame/cg_snapshot.o \
- $(B)/baseq3/cgame/cg_unlagged.o \
- $(B)/baseq3/cgame/cg_view.o \
- $(B)/baseq3/cgame/cg_weapons.o \
- \
- $(B)/baseq3/qcommon/q_math.o \
- $(B)/baseq3/qcommon/q_shared.o
-
-Q3CGOBJ = $(Q3CGOBJ_) $(B)/baseq3/cgame/cg_syscalls.o
-Q3CGVMOBJ = $(Q3CGOBJ_:%.o=%.asm)
-
-$(B)/baseq3/cgame$(ARCH).$(SHLIBEXT): $(Q3CGOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3CGOBJ)
-
-$(B)/baseq3/vm/cgame.qvm: $(Q3CGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(Q3CGVMOBJ) $(CGDIR)/cg_syscalls.asm
-
-#############################################################################
-## MISSIONPACK CGAME
-#############################################################################
-
-MPCGOBJ_ = \
- $(B)/missionpack/cgame/cg_main.o \
- $(B)/missionpack/game/bg_misc.o \
- $(B)/missionpack/game/bg_lib.o \
- $(B)/missionpack/game/bg_pmove.o \
- $(B)/missionpack/game/bg_slidemove.o \
- $(B)/missionpack/cgame/cg_challenges.o \
- $(B)/missionpack/cgame/cg_consolecmds.o \
- $(B)/missionpack/cgame/cg_newdraw.o \
- $(B)/missionpack/cgame/cg_draw.o \
- $(B)/missionpack/cgame/cg_drawtools.o \
- $(B)/missionpack/cgame/cg_effects.o \
- $(B)/missionpack/cgame/cg_ents.o \
- $(B)/missionpack/cgame/cg_event.o \
- $(B)/missionpack/cgame/cg_info.o \
- $(B)/missionpack/cgame/cg_localents.o \
- $(B)/missionpack/cgame/cg_marks.o \
- $(B)/missionpack/cgame/cg_players.o \
- $(B)/missionpack/cgame/cg_playerstate.o \
- $(B)/missionpack/cgame/cg_predict.o \
- $(B)/missionpack/cgame/cg_scoreboard.o \
- $(B)/missionpack/cgame/cg_servercmds.o \
- $(B)/missionpack/cgame/cg_snapshot.o \
- $(B)/missionpack/cgame/cg_unlagged.o \
- $(B)/missionpack/cgame/cg_view.o \
- $(B)/missionpack/cgame/cg_weapons.o \
- $(B)/missionpack/ui/ui_shared.o \
- \
- $(B)/missionpack/qcommon/q_math.o \
- $(B)/missionpack/qcommon/q_shared.o
-
-MPCGOBJ = $(MPCGOBJ_) $(B)/missionpack/cgame/cg_syscalls.o
-MPCGVMOBJ = $(MPCGOBJ_:%.o=%.asm)
-
-$(B)/missionpack/cgame$(ARCH).$(SHLIBEXT): $(MPCGOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPCGOBJ)
-
-$(B)/missionpack/vm/cgame.qvm: $(MPCGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(MPCGVMOBJ) $(CGDIR)/cg_syscalls.asm
-
-
-
-#############################################################################
-## BASEQ3 GAME
-#############################################################################
-
-Q3GOBJ_ = \
- $(B)/baseq3/game/g_main.o \
- $(B)/baseq3/game/ai_chat.o \
- $(B)/baseq3/game/ai_cmd.o \
- $(B)/baseq3/game/ai_dmnet.o \
- $(B)/baseq3/game/ai_dmq3.o \
- $(B)/baseq3/game/ai_main.o \
- $(B)/baseq3/game/ai_team.o \
- $(B)/baseq3/game/ai_vcmd.o \
- $(B)/baseq3/game/bg_misc.o \
- $(B)/baseq3/game/bg_lib.o \
- $(B)/baseq3/game/bg_pmove.o \
- $(B)/baseq3/game/bg_slidemove.o \
- $(B)/baseq3/game/g_active.o \
- $(B)/baseq3/game/g_arenas.o \
- $(B)/baseq3/game/g_admin.o \
- $(B)/baseq3/game/g_bot.o \
- $(B)/baseq3/game/g_client.o \
- $(B)/baseq3/game/g_cmds.o \
- $(B)/baseq3/game/g_cmds_ext.o \
- $(B)/baseq3/game/g_combat.o \
- $(B)/baseq3/game/g_items.o \
- $(B)/baseq3/game/bg_alloc.o \
- $(B)/baseq3/game/g_fileops.o \
- $(B)/baseq3/game/g_killspree.o \
- $(B)/baseq3/game/g_misc.o \
- $(B)/baseq3/game/g_missile.o \
- $(B)/baseq3/game/g_mover.o \
- $(B)/baseq3/game/g_playerstore.o \
- $(B)/baseq3/game/g_session.o \
- $(B)/baseq3/game/g_spawn.o \
- $(B)/baseq3/game/g_svcmds.o \
- $(B)/baseq3/game/g_svcmds_ext.o \
- $(B)/baseq3/game/g_target.o \
- $(B)/baseq3/game/g_team.o \
- $(B)/baseq3/game/g_trigger.o \
- $(B)/baseq3/game/g_unlagged.o \
- $(B)/baseq3/game/g_utils.o \
- $(B)/baseq3/game/g_vote.o \
- $(B)/baseq3/game/g_weapon.o \
- \
- $(B)/baseq3/qcommon/q_math.o \
- $(B)/baseq3/qcommon/q_shared.o
-
-Q3GOBJ = $(Q3GOBJ_) $(B)/baseq3/game/g_syscalls.o
-Q3GVMOBJ = $(Q3GOBJ_:%.o=%.asm)
-
-$(B)/baseq3/qagame$(ARCH).$(SHLIBEXT): $(Q3GOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3GOBJ)
-
-$(B)/baseq3/vm/qagame.qvm: $(Q3GVMOBJ) $(GDIR)/g_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(Q3GVMOBJ) $(GDIR)/g_syscalls.asm
-
-#############################################################################
-## MISSIONPACK GAME
-#############################################################################
-
-MPGOBJ_ = \
- $(B)/missionpack/game/g_main.o \
- $(B)/missionpack/game/ai_chat.o \
- $(B)/missionpack/game/ai_cmd.o \
- $(B)/missionpack/game/ai_dmnet.o \
- $(B)/missionpack/game/ai_dmq3.o \
- $(B)/missionpack/game/ai_main.o \
- $(B)/missionpack/game/ai_team.o \
- $(B)/missionpack/game/ai_vcmd.o \
- $(B)/missionpack/game/bg_misc.o \
- $(B)/missionpack/game/bg_lib.o \
- $(B)/missionpack/game/bg_pmove.o \
- $(B)/missionpack/game/bg_slidemove.o \
- $(B)/missionpack/game/g_active.o \
- $(B)/missionpack/game/g_admin.o \
- $(B)/missionpack/game/g_arenas.o \
- $(B)/missionpack/game/g_bot.o \
- $(B)/missionpack/game/g_client.o \
- $(B)/missionpack/game/g_cmds.o \
- $(B)/missionpack/game/g_cmds_ext.o \
- $(B)/missionpack/game/g_combat.o \
- $(B)/missionpack/game/g_items.o \
- $(B)/missionpack/game/bg_alloc.o \
- $(B)/missionpack/game/g_fileops.o \
- $(B)/missionpack/game/g_killspree.o \
- $(B)/missionpack/game/g_misc.o \
- $(B)/missionpack/game/g_missile.o \
- $(B)/missionpack/game/g_mover.o \
- $(B)/missionpack/game/g_playerstore.o \
- $(B)/missionpack/game/g_session.o \
- $(B)/missionpack/game/g_spawn.o \
- $(B)/missionpack/game/g_svcmds.o \
- $(B)/missionpack/game/g_svcmds_ext.o \
- $(B)/missionpack/game/g_target.o \
- $(B)/missionpack/game/g_team.o \
- $(B)/missionpack/game/g_trigger.o \
- $(B)/missionpack/game/g_unlagged.o \
- $(B)/missionpack/game/g_utils.o \
- $(B)/missionpack/game/g_vote.o \
- $(B)/missionpack/game/g_weapon.o \
- \
- $(B)/missionpack/qcommon/q_math.o \
- $(B)/missionpack/qcommon/q_shared.o
-
-MPGOBJ = $(MPGOBJ_) $(B)/missionpack/game/g_syscalls.o
-MPGVMOBJ = $(MPGOBJ_:%.o=%.asm)
-
-$(B)/missionpack/qagame$(ARCH).$(SHLIBEXT): $(MPGOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPGOBJ)
-
-$(B)/missionpack/vm/qagame.qvm: $(MPGVMOBJ) $(GDIR)/g_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(MPGVMOBJ) $(GDIR)/g_syscalls.asm
-
-
-
-#############################################################################
-## BASEQ3 UI
-#############################################################################
-
-Q3UIOBJ_ = \
- $(B)/baseq3/ui/ui_main.o \
- $(B)/baseq3/game/bg_misc.o \
- $(B)/baseq3/game/bg_lib.o \
- $(B)/baseq3/ui/ui_addbots.o \
- $(B)/baseq3/ui/ui_atoms.o \
- $(B)/baseq3/ui/ui_cdkey.o \
- $(B)/baseq3/ui/ui_challenges.o \
- $(B)/baseq3/ui/ui_cinematics.o \
- $(B)/baseq3/ui/ui_confirm.o \
- $(B)/baseq3/ui/ui_connect.o \
- $(B)/baseq3/ui/ui_controls2.o \
- $(B)/baseq3/ui/ui_credits.o \
- $(B)/baseq3/ui/ui_demo2.o \
- $(B)/baseq3/ui/ui_display.o \
- $(B)/baseq3/ui/ui_firstconnect.o \
- $(B)/baseq3/ui/ui_gameinfo.o \
- $(B)/baseq3/ui/ui_ingame.o \
- $(B)/baseq3/ui/ui_loadconfig.o \
- $(B)/baseq3/ui/ui_menu.o \
- $(B)/baseq3/ui/ui_mfield.o \
- $(B)/baseq3/ui/ui_mods.o \
- $(B)/baseq3/ui/ui_network.o \
- $(B)/baseq3/ui/ui_options.o \
- $(B)/baseq3/ui/ui_password.o \
- $(B)/baseq3/ui/ui_playermodel.o \
- $(B)/baseq3/ui/ui_players.o \
- $(B)/baseq3/ui/ui_playersettings.o \
- $(B)/baseq3/ui/ui_preferences.o \
- $(B)/baseq3/ui/ui_qmenu.o \
- $(B)/baseq3/ui/ui_removebots.o \
- $(B)/baseq3/ui/ui_saveconfig.o \
- $(B)/baseq3/ui/ui_serverinfo.o \
- $(B)/baseq3/ui/ui_servers2.o \
- $(B)/baseq3/ui/ui_setup.o \
- $(B)/baseq3/ui/ui_sound.o \
- $(B)/baseq3/ui/ui_sparena.o \
- $(B)/baseq3/ui/ui_specifyserver.o \
- $(B)/baseq3/ui/ui_splevel.o \
- $(B)/baseq3/ui/ui_sppostgame.o \
- $(B)/baseq3/ui/ui_spskill.o \
- $(B)/baseq3/ui/ui_startserver.o \
- $(B)/baseq3/ui/ui_team.o \
- $(B)/baseq3/ui/ui_teamorders.o \
- $(B)/baseq3/ui/ui_video.o \
- $(B)/baseq3/ui/ui_votemenu.o \
- $(B)/baseq3/ui/ui_votemenu_fraglimit.o \
- $(B)/baseq3/ui/ui_votemenu_timelimit.o \
- $(B)/baseq3/ui/ui_votemenu_gametype.o \
- $(B)/baseq3/ui/ui_votemenu_kick.o \
- $(B)/baseq3/ui/ui_votemenu_map.o \
- $(B)/baseq3/ui/ui_votemenu_custom.o \
- \
- $(B)/baseq3/qcommon/q_math.o \
- $(B)/baseq3/qcommon/q_shared.o
-
-Q3UIOBJ = $(Q3UIOBJ_) $(B)/missionpack/ui/ui_syscalls.o
-Q3UIVMOBJ = $(Q3UIOBJ_:%.o=%.asm)
-
-$(B)/baseq3/ui$(ARCH).$(SHLIBEXT): $(Q3UIOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3UIOBJ)
-
-$(B)/baseq3/vm/ui.qvm: $(Q3UIVMOBJ) $(UIDIR)/ui_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(Q3UIVMOBJ) $(UIDIR)/ui_syscalls.asm
-
-#############################################################################
-## MISSIONPACK UI
-#############################################################################
-
-MPUIOBJ_ = \
- $(B)/missionpack/ui/ui_main.o \
- $(B)/missionpack/ui/ui_atoms.o \
- $(B)/missionpack/ui/ui_gameinfo.o \
- $(B)/missionpack/ui/ui_players.o \
- $(B)/missionpack/ui/ui_shared.o \
- \
- $(B)/missionpack/ui/bg_misc.o \
- $(B)/missionpack/ui/bg_lib.o \
- \
- $(B)/missionpack/qcommon/q_math.o \
- $(B)/missionpack/qcommon/q_shared.o
-
-MPUIOBJ = $(MPUIOBJ_) $(B)/missionpack/ui/ui_syscalls.o
-MPUIVMOBJ = $(MPUIOBJ_:%.o=%.asm)
-
-$(B)/missionpack/ui$(ARCH).$(SHLIBEXT): $(MPUIOBJ)
- $(echo_cmd) "LD $@"
- $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPUIOBJ)
-
-$(B)/missionpack/vm/ui.qvm: $(MPUIVMOBJ) $(UIDIR)/ui_syscalls.asm $(Q3ASM)
- $(echo_cmd) "Q3ASM $@"
- $(Q)$(Q3ASM) -o $@ $(MPUIVMOBJ) $(UIDIR)/ui_syscalls.asm
-
-
-
-#############################################################################
-## CLIENT/SERVER RULES
-#############################################################################
-
-$(B)/client/%.o: $(ASMDIR)/%.s
- $(DO_AS)
-
-$(B)/client/%.o: $(CDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(SDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(CMDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(BLIBDIR)/%.c
- $(DO_BOT_CC)
-
-$(B)/client/%.o: $(JPDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(SPEEXDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(RDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(SDLDIR)/%.c
- $(DO_CC)
-
-$(B)/clientsmp/%.o: $(SDLDIR)/%.c
- $(DO_SMP_CC)
-
-$(B)/client/%.o: $(SYSDIR)/%.c
- $(DO_CC)
-
-$(B)/client/%.o: $(SYSDIR)/%.rc
- $(DO_WINDRES)
-
-
-$(B)/ded/%.o: $(ASMDIR)/%.s
- $(DO_AS)
-
-$(B)/ded/%.o: $(SDIR)/%.c
- $(DO_DED_CC)
-
-$(B)/ded/%.o: $(CMDIR)/%.c
- $(DO_DED_CC)
-
-$(B)/ded/%.o: $(BLIBDIR)/%.c
- $(DO_BOT_CC)
-
-$(B)/ded/%.o: $(SYSDIR)/%.c
- $(DO_DED_CC)
-
-$(B)/ded/%.o: $(SYSDIR)/%.rc
- $(DO_WINDRES)
-
-$(B)/ded/%.o: $(NDIR)/%.c
- $(DO_DED_CC)
-
-# Extra dependencies to ensure the SVN version is incorporated
-ifeq ($(USE_SVN),1)
- $(B)/client/cl_console.o : .svn/entries
- $(B)/client/common.o : .svn/entries
- $(B)/ded/common.o : .svn/entries
-endif
-
-
-#############################################################################
-## GAME MODULE RULES
-#############################################################################
-
-$(B)/baseq3/cgame/bg_%.o: $(GDIR)/bg_%.c
- $(DO_CGAME_CC)
-
-$(B)/baseq3/cgame/%.o: $(CGDIR)/%.c
- $(DO_CGAME_CC)
-
-$(B)/baseq3/cgame/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
- $(DO_CGAME_Q3LCC)
-
-$(B)/baseq3/cgame/%.asm: $(CGDIR)/%.c $(Q3LCC)
- $(DO_CGAME_Q3LCC)
-
-$(B)/missionpack/cgame/bg_%.o: $(GDIR)/bg_%.c
- $(DO_CGAME_CC_MISSIONPACK)
-
-$(B)/missionpack/cgame/%.o: $(CGDIR)/%.c
- $(DO_CGAME_CC_MISSIONPACK)
-
-$(B)/missionpack/cgame/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
- $(DO_CGAME_Q3LCC_MISSIONPACK)
-
-$(B)/missionpack/cgame/%.asm: $(CGDIR)/%.c $(Q3LCC)
- $(DO_CGAME_Q3LCC_MISSIONPACK)
-
-
-$(B)/baseq3/game/%.o: $(GDIR)/%.c
- $(DO_GAME_CC)
-
-$(B)/baseq3/game/%.asm: $(GDIR)/%.c $(Q3LCC)
- $(DO_GAME_Q3LCC)
-
-$(B)/missionpack/game/%.o: $(GDIR)/%.c
- $(DO_GAME_CC_MISSIONPACK)
-
-$(B)/missionpack/game/%.asm: $(GDIR)/%.c $(Q3LCC)
- $(DO_GAME_Q3LCC_MISSIONPACK)
-
-
-$(B)/baseq3/ui/bg_%.o: $(GDIR)/bg_%.c
- $(DO_UI_CC)
-
-$(B)/baseq3/ui/%.o: $(Q3UIDIR)/%.c
- $(DO_UI_CC)
-
-$(B)/baseq3/ui/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
- $(DO_UI_Q3LCC)
-
-$(B)/baseq3/ui/%.asm: $(Q3UIDIR)/%.c $(Q3LCC)
- $(DO_UI_Q3LCC)
-
-$(B)/missionpack/ui/bg_%.o: $(GDIR)/bg_%.c
- $(DO_UI_CC_MISSIONPACK)
-
-$(B)/missionpack/ui/%.o: $(UIDIR)/%.c
- $(DO_UI_CC_MISSIONPACK)
-
-$(B)/missionpack/ui/bg_%.asm: $(GDIR)/bg_%.c $(Q3LCC)
- $(DO_UI_Q3LCC_MISSIONPACK)
-
-$(B)/missionpack/ui/%.asm: $(UIDIR)/%.c $(Q3LCC)
- $(DO_UI_Q3LCC_MISSIONPACK)
-
-
-$(B)/baseq3/qcommon/%.o: $(CMDIR)/%.c
- $(DO_SHLIB_CC)
-
-$(B)/baseq3/qcommon/%.asm: $(CMDIR)/%.c $(Q3LCC)
- $(DO_Q3LCC)
-
-$(B)/missionpack/qcommon/%.o: $(CMDIR)/%.c
- $(DO_SHLIB_CC_MISSIONPACK)
-
-$(B)/missionpack/qcommon/%.asm: $(CMDIR)/%.c $(Q3LCC)
- $(DO_Q3LCC_MISSIONPACK)
-
-
-#############################################################################
-# MISC
-#############################################################################
-
-OBJ = $(Q3OBJ) $(Q3POBJ) $(Q3POBJ_SMP) $(Q3DOBJ) \
- $(MPGOBJ) $(Q3GOBJ) $(Q3CGOBJ) $(MPCGOBJ) $(Q3UIOBJ) $(MPUIOBJ) \
- $(MPGVMOBJ) $(Q3GVMOBJ) $(Q3CGVMOBJ) $(MPCGVMOBJ) $(Q3UIVMOBJ) $(MPUIVMOBJ)
-TOOLSOBJ = $(LBURGOBJ) $(Q3CPPOBJ) $(Q3RCCOBJ) $(Q3LCCOBJ) $(Q3ASMOBJ)
-
-
-copyfiles: release
- @if [ ! -d $(COPYDIR)/baseq3 ]; then echo "You need to set COPYDIR to where your Quake3 data is!"; fi
- -$(MKDIR) -p -m 0755 $(COPYDIR)/baseq3
- -$(MKDIR) -p -m 0755 $(COPYDIR)/missionpack
-
-ifneq ($(BUILD_CLIENT),0)
- $(INSTALL) -s -m 0755 $(BR)/ioquake3.$(ARCH)$(BINEXT) $(COPYDIR)/ioquake3.$(ARCH)$(BINEXT)
-endif
-
-# Don't copy the SMP until it's working together with SDL.
-#ifneq ($(BUILD_CLIENT_SMP),0)
-# $(INSTALL) -s -m 0755 $(BR)/ioquake3-smp.$(ARCH)$(BINEXT) $(COPYDIR)/ioquake3-smp.$(ARCH)$(BINEXT)
-#endif
-
-ifneq ($(BUILD_SERVER),0)
- @if [ -f $(BR)/ioq3ded.$(ARCH)$(BINEXT) ]; then \
- $(INSTALL) -s -m 0755 $(BR)/ioq3ded.$(ARCH)$(BINEXT) $(COPYDIR)/ioq3ded.$(ARCH)$(BINEXT); \
- fi
-endif
-
-ifneq ($(BUILD_GAME_SO),0)
- $(INSTALL) -s -m 0755 $(BR)/baseq3/cgame$(ARCH).$(SHLIBEXT) \
- $(COPYDIR)/baseq3/.
- $(INSTALL) -s -m 0755 $(BR)/baseq3/qagame$(ARCH).$(SHLIBEXT) \
- $(COPYDIR)/baseq3/.
- $(INSTALL) -s -m 0755 $(BR)/baseq3/ui$(ARCH).$(SHLIBEXT) \
- $(COPYDIR)/baseq3/.
- ifneq ($(BUILD_MISSIONPACK),0)
- -$(MKDIR) -p -m 0755 $(COPYDIR)/missionpack
- $(INSTALL) -s -m 0755 $(BR)/missionpack/cgame$(ARCH).$(SHLIBEXT) \
- $(COPYDIR)/missionpack/.
- $(INSTALL) -s -m 0755 $(BR)/missionpack/qagame$(ARCH).$(SHLIBEXT) \
- $(COPYDIR)/missionpack/.
- $(INSTALL) -s -m 0755 $(BR)/missionpack/ui$(ARCH).$(SHLIBEXT) \
- $(COPYDIR)/missionpack/.
- endif
-endif
-
-clean: clean-debug clean-release
-ifeq ($(PLATFORM),mingw32)
- @$(MAKE) -C $(NSISDIR) clean
-else
- @$(MAKE) -C $(LOKISETUPDIR) clean
-endif
-
-clean-debug:
- @$(MAKE) clean2 B=$(BD)
-
-clean-release:
- @$(MAKE) clean2 B=$(BR)
-
-clean2:
- @echo "CLEAN $(B)"
- @rm -f $(OBJ)
- @rm -f $(OBJ_D_FILES)
- @rm -f $(TARGETS)
-
-toolsclean: toolsclean-debug toolsclean-release
-
-toolsclean-debug:
- @$(MAKE) toolsclean2 B=$(BD)
-
-toolsclean-release:
- @$(MAKE) toolsclean2 B=$(BR)
-
-toolsclean2:
- @echo "TOOLS_CLEAN $(B)"
- @rm -f $(TOOLSOBJ)
- @rm -f $(TOOLSOBJ_D_FILES)
- @rm -f $(LBURG) $(DAGCHECK_C) $(Q3RCC) $(Q3CPP) $(Q3LCC) $(Q3ASM)
-
-distclean: clean toolsclean
- @rm -rf $(BUILD_DIR)
-
-installer: release
-ifeq ($(PLATFORM),mingw32)
- @$(MAKE) VERSION=$(VERSION) -C $(NSISDIR) V=$(V)
-else
- @$(MAKE) VERSION=$(VERSION) -C $(LOKISETUPDIR) V=$(V)
-endif
-
-dist:
- rm -rf ioquake3-$(VERSION)
- svn export . ioquake3-$(VERSION)
- tar --owner=root --group=root --force-local -cjf ioquake3-$(VERSION).tar.bz2 ioquake3-$(VERSION)
- rm -rf ioquake3-$(VERSION)
-
-#############################################################################
-# DEPENDENCIES
-#############################################################################
-
-OBJ_D_FILES=$(filter %.d,$(OBJ:%.o=%.d))
-TOOLSOBJ_D_FILES=$(filter %.d,$(TOOLSOBJ:%.o=%.d))
--include $(OBJ_D_FILES) $(TOOLSOBJ_D_FILES)
-
-.PHONY: all clean clean2 clean-debug clean-release copyfiles \
- debug default dist distclean installer makedirs \
- release targets \
- toolsclean toolsclean2 toolsclean-debug toolsclean-release
diff --git a/game/admin.log b/game/admin.log
deleted file mode 100644
index e69de29..0000000
diff --git a/game/code/botlib/aasfile.h b/game/code/botlib/aasfile.h
deleted file mode 100644
index 8f2fbf6..0000000
--- a/game/code/botlib/aasfile.h
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-
-//NOTE: int = default signed
-// default long
-
-#define AASID (('S'<<24)+('A'<<16)+('A'<<8)+'E')
-#define AASVERSION_OLD 4
-#define AASVERSION 5
-
-//presence types
-#define PRESENCE_NONE 1
-#define PRESENCE_NORMAL 2
-#define PRESENCE_CROUCH 4
-
-//travel types
-#define MAX_TRAVELTYPES 32
-#define TRAVEL_INVALID 1 //temporary not possible
-#define TRAVEL_WALK 2 //walking
-#define TRAVEL_CROUCH 3 //crouching
-#define TRAVEL_BARRIERJUMP 4 //jumping onto a barrier
-#define TRAVEL_JUMP 5 //jumping
-#define TRAVEL_LADDER 6 //climbing a ladder
-#define TRAVEL_WALKOFFLEDGE 7 //walking of a ledge
-#define TRAVEL_SWIM 8 //swimming
-#define TRAVEL_WATERJUMP 9 //jump out of the water
-#define TRAVEL_TELEPORT 10 //teleportation
-#define TRAVEL_ELEVATOR 11 //travel by elevator
-#define TRAVEL_ROCKETJUMP 12 //rocket jumping required for travel
-#define TRAVEL_BFGJUMP 13 //bfg jumping required for travel
-#define TRAVEL_GRAPPLEHOOK 14 //grappling hook required for travel
-#define TRAVEL_DOUBLEJUMP 15 //double jump
-#define TRAVEL_RAMPJUMP 16 //ramp jump
-#define TRAVEL_STRAFEJUMP 17 //strafe jump
-#define TRAVEL_JUMPPAD 18 //jump pad
-#define TRAVEL_FUNCBOB 19 //func bob
-
-//additional travel flags
-#define TRAVELTYPE_MASK 0xFFFFFF
-#define TRAVELFLAG_NOTTEAM1 (1 << 24)
-#define TRAVELFLAG_NOTTEAM2 (2 << 24)
-
-//face flags
-#define FACE_SOLID 1 //just solid at the other side
-#define FACE_LADDER 2 //ladder
-#define FACE_GROUND 4 //standing on ground when in this face
-#define FACE_GAP 8 //gap in the ground
-#define FACE_LIQUID 16 //face seperating two areas with liquid
-#define FACE_LIQUIDSURFACE 32 //face seperating liquid and air
-#define FACE_BRIDGE 64 //can walk over this face if bridge is closed
-
-//area contents
-#define AREACONTENTS_WATER 1
-#define AREACONTENTS_LAVA 2
-#define AREACONTENTS_SLIME 4
-#define AREACONTENTS_CLUSTERPORTAL 8
-#define AREACONTENTS_TELEPORTAL 16
-#define AREACONTENTS_ROUTEPORTAL 32
-#define AREACONTENTS_TELEPORTER 64
-#define AREACONTENTS_JUMPPAD 128
-#define AREACONTENTS_DONOTENTER 256
-#define AREACONTENTS_VIEWPORTAL 512
-#define AREACONTENTS_MOVER 1024
-#define AREACONTENTS_NOTTEAM1 2048
-#define AREACONTENTS_NOTTEAM2 4096
-//number of model of the mover inside this area
-#define AREACONTENTS_MODELNUMSHIFT 24
-#define AREACONTENTS_MAXMODELNUM 0xFF
-#define AREACONTENTS_MODELNUM (AREACONTENTS_MAXMODELNUM << AREACONTENTS_MODELNUMSHIFT)
-
-//area flags
-#define AREA_GROUNDED 1 //bot can stand on the ground
-#define AREA_LADDER 2 //area contains one or more ladder faces
-#define AREA_LIQUID 4 //area contains a liquid
-#define AREA_DISABLED 8 //area is disabled for routing when set
-#define AREA_BRIDGE 16 //area ontop of a bridge
-
-//aas file header lumps
-#define AAS_LUMPS 14
-#define AASLUMP_BBOXES 0
-#define AASLUMP_VERTEXES 1
-#define AASLUMP_PLANES 2
-#define AASLUMP_EDGES 3
-#define AASLUMP_EDGEINDEX 4
-#define AASLUMP_FACES 5
-#define AASLUMP_FACEINDEX 6
-#define AASLUMP_AREAS 7
-#define AASLUMP_AREASETTINGS 8
-#define AASLUMP_REACHABILITY 9
-#define AASLUMP_NODES 10
-#define AASLUMP_PORTALS 11
-#define AASLUMP_PORTALINDEX 12
-#define AASLUMP_CLUSTERS 13
-
-//========== bounding box =========
-
-//bounding box
-typedef struct aas_bbox_s
-{
- int presencetype;
- int flags;
- vec3_t mins, maxs;
-} aas_bbox_t;
-
-//============ settings ===========
-
-//reachability to another area
-typedef struct aas_reachability_s
-{
- int areanum; //number of the reachable area
- int facenum; //number of the face towards the other area
- int edgenum; //number of the edge towards the other area
- vec3_t start; //start point of inter area movement
- vec3_t end; //end point of inter area movement
- int traveltype; //type of travel required to get to the area
- unsigned short int traveltime;//travel time of the inter area movement
-} aas_reachability_t;
-
-//area settings
-typedef struct aas_areasettings_s
-{
- //could also add all kind of statistic fields
- int contents; //contents of the area
- int areaflags; //several area flags
- int presencetype; //how a bot can be present in this area
- int cluster; //cluster the area belongs to, if negative it's a portal
- int clusterareanum; //number of the area in the cluster
- int numreachableareas; //number of reachable areas from this one
- int firstreachablearea; //first reachable area in the reachable area index
-} aas_areasettings_t;
-
-//cluster portal
-typedef struct aas_portal_s
-{
- int areanum; //area that is the actual portal
- int frontcluster; //cluster at front of portal
- int backcluster; //cluster at back of portal
- int clusterareanum[2]; //number of the area in the front and back cluster
-} aas_portal_t;
-
-//cluster portal index
-typedef int aas_portalindex_t;
-
-//cluster
-typedef struct aas_cluster_s
-{
- int numareas; //number of areas in the cluster
- int numreachabilityareas; //number of areas with reachabilities
- int numportals; //number of cluster portals
- int firstportal; //first cluster portal in the index
-} aas_cluster_t;
-
-//============ 3d definition ============
-
-typedef vec3_t aas_vertex_t;
-
-//just a plane in the third dimension
-typedef struct aas_plane_s
-{
- vec3_t normal; //normal vector of the plane
- float dist; //distance of the plane (normal vector * distance = point in plane)
- int type;
-} aas_plane_t;
-
-//edge
-typedef struct aas_edge_s
-{
- int v[2]; //numbers of the vertexes of this edge
-} aas_edge_t;
-
-//edge index, negative if vertexes are reversed
-typedef int aas_edgeindex_t;
-
-//a face bounds an area, often it will also seperate two areas
-typedef struct aas_face_s
-{
- int planenum; //number of the plane this face is in
- int faceflags; //face flags (no use to create face settings for just this field)
- int numedges; //number of edges in the boundary of the face
- int firstedge; //first edge in the edge index
- int frontarea; //area at the front of this face
- int backarea; //area at the back of this face
-} aas_face_t;
-
-//face index, stores a negative index if backside of face
-typedef int aas_faceindex_t;
-
-//area with a boundary of faces
-typedef struct aas_area_s
-{
- int areanum; //number of this area
- //3d definition
- int numfaces; //number of faces used for the boundary of the area
- int firstface; //first face in the face index used for the boundary of the area
- vec3_t mins; //mins of the area
- vec3_t maxs; //maxs of the area
- vec3_t center; //'center' of the area
-} aas_area_t;
-
-//nodes of the bsp tree
-typedef struct aas_node_s
-{
- int planenum;
- int children[2]; //child nodes of this node, or areas as leaves when negative
- //when a child is zero it's a solid leaf
-} aas_node_t;
-
-//=========== aas file ===============
-
-//header lump
-typedef struct
-{
- int fileofs;
- int filelen;
-} aas_lump_t;
-
-//aas file header
-typedef struct aas_header_s
-{
- int ident;
- int version;
- int bspchecksum;
- //data entries
- aas_lump_t lumps[AAS_LUMPS];
-} aas_header_t;
-
-
-//====== additional information ======
-/*
-
-- when a node child is a solid leaf the node child number is zero
-- two adjacent areas (sharing a plane at opposite sides) share a face
- this face is a portal between the areas
-- when an area uses a face from the faceindex with a positive index
- then the face plane normal points into the area
-- the face edges are stored counter clockwise using the edgeindex
-- two adjacent convex areas (sharing a face) only share One face
- this is a simple result of the areas being convex
-- the areas can't have a mixture of ground and gap faces
- other mixtures of faces in one area are allowed
-- areas with the AREACONTENTS_CLUSTERPORTAL in the settings have
- the cluster number set to the negative portal number
-- edge zero is a dummy
-- face zero is a dummy
-- area zero is a dummy
-- node zero is a dummy
-*/
diff --git a/game/code/botlib/be_aas.h b/game/code/botlib/be_aas.h
deleted file mode 100644
index dbf24bc..0000000
--- a/game/code/botlib/be_aas.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: be_aas.h
- *
- * desc: Area Awareness System, stuff exported to the AI
- *
- * $Archive: /source/code/botlib/be_aas.h $
- *
- *****************************************************************************/
-
-#ifndef MAX_STRINGFIELD
-#define MAX_STRINGFIELD 80
-#endif
-
-//travel flags
-#define TFL_INVALID 0x00000001 //traveling temporary not possible
-#define TFL_WALK 0x00000002 //walking
-#define TFL_CROUCH 0x00000004 //crouching
-#define TFL_BARRIERJUMP 0x00000008 //jumping onto a barrier
-#define TFL_JUMP 0x00000010 //jumping
-#define TFL_LADDER 0x00000020 //climbing a ladder
-#define TFL_WALKOFFLEDGE 0x00000080 //walking of a ledge
-#define TFL_SWIM 0x00000100 //swimming
-#define TFL_WATERJUMP 0x00000200 //jumping out of the water
-#define TFL_TELEPORT 0x00000400 //teleporting
-#define TFL_ELEVATOR 0x00000800 //elevator
-#define TFL_ROCKETJUMP 0x00001000 //rocket jumping
-#define TFL_BFGJUMP 0x00002000 //bfg jumping
-#define TFL_GRAPPLEHOOK 0x00004000 //grappling hook
-#define TFL_DOUBLEJUMP 0x00008000 //double jump
-#define TFL_RAMPJUMP 0x00010000 //ramp jump
-#define TFL_STRAFEJUMP 0x00020000 //strafe jump
-#define TFL_JUMPPAD 0x00040000 //jump pad
-#define TFL_AIR 0x00080000 //travel through air
-#define TFL_WATER 0x00100000 //travel through water
-#define TFL_SLIME 0x00200000 //travel through slime
-#define TFL_LAVA 0x00400000 //travel through lava
-#define TFL_DONOTENTER 0x00800000 //travel through donotenter area
-#define TFL_FUNCBOB 0x01000000 //func bobbing
-#define TFL_FLIGHT 0x02000000 //flight
-#define TFL_BRIDGE 0x04000000 //move over a bridge
-//
-#define TFL_NOTTEAM1 0x08000000 //not team 1
-#define TFL_NOTTEAM2 0x10000000 //not team 2
-
-//default travel flags
-#define TFL_DEFAULT TFL_WALK|TFL_CROUCH|TFL_BARRIERJUMP|\
- TFL_JUMP|TFL_LADDER|\
- TFL_WALKOFFLEDGE|TFL_SWIM|TFL_WATERJUMP|\
- TFL_TELEPORT|TFL_ELEVATOR|\
- TFL_AIR|TFL_WATER|TFL_JUMPPAD|TFL_FUNCBOB
-
-typedef enum
-{
- SOLID_NOT, // no interaction with other objects
- SOLID_TRIGGER, // only touch when inside, after moving
- SOLID_BBOX, // touch on edge
- SOLID_BSP // bsp clip, touch on edge
-} solid_t;
-
-//a trace is returned when a box is swept through the AAS world
-typedef struct aas_trace_s
-{
- qboolean startsolid; // if true, the initial point was in a solid area
- float fraction; // time completed, 1.0 = didn't hit anything
- vec3_t endpos; // final position
- int ent; // entity blocking the trace
- int lastarea; // last area the trace was in (zero if none)
- int area; // area blocking the trace (zero if none)
- int planenum; // number of the plane that was hit
-} aas_trace_t;
-
-/* Defined in botlib.h
-
-//bsp_trace_t hit surface
-typedef struct bsp_surface_s
-{
- char name[16];
- int flags;
- int value;
-} bsp_surface_t;
-
-//a trace is returned when a box is swept through the BSP world
-typedef struct bsp_trace_s
-{
- qboolean allsolid; // if true, plane is not valid
- qboolean startsolid; // if true, the initial point was in a solid area
- float fraction; // time completed, 1.0 = didn't hit anything
- vec3_t endpos; // final position
- cplane_t plane; // surface normal at impact
- float exp_dist; // expanded plane distance
- int sidenum; // number of the brush side hit
- bsp_surface_t surface; // hit surface
- int contents; // contents on other side of surface hit
- int ent; // number of entity hit
-} bsp_trace_t;
-//
-*/
-
-//entity info
-typedef struct aas_entityinfo_s
-{
- int valid; // true if updated this frame
- int type; // entity type
- int flags; // entity flags
- float ltime; // local time
- float update_time; // time between last and current update
- int number; // number of the entity
- vec3_t origin; // origin of the entity
- vec3_t angles; // angles of the model
- vec3_t old_origin; // for lerping
- vec3_t lastvisorigin; // last visible origin
- vec3_t mins; // bounding box minimums
- vec3_t maxs; // bounding box maximums
- int groundent; // ground entity
- int solid; // solid type
- int modelindex; // model used
- int modelindex2; // weapons, CTF flags, etc
- int frame; // model frame number
- int event; // impulse events -- muzzle flashes, footsteps, etc
- int eventParm; // even parameter
- int powerups; // bit flags
- int weapon; // determines weapon and flash model, etc
- int legsAnim; // mask off ANIM_TOGGLEBIT
- int torsoAnim; // mask off ANIM_TOGGLEBIT
-} aas_entityinfo_t;
-
-// area info
-typedef struct aas_areainfo_s
-{
- int contents;
- int flags;
- int presencetype;
- int cluster;
- vec3_t mins;
- vec3_t maxs;
- vec3_t center;
-} aas_areainfo_t;
-
-// client movement prediction stop events, stop as soon as:
-#define SE_NONE 0
-#define SE_HITGROUND 1 // the ground is hit
-#define SE_LEAVEGROUND 2 // there's no ground
-#define SE_ENTERWATER 4 // water is entered
-#define SE_ENTERSLIME 8 // slime is entered
-#define SE_ENTERLAVA 16 // lava is entered
-#define SE_HITGROUNDDAMAGE 32 // the ground is hit with damage
-#define SE_GAP 64 // there's a gap
-#define SE_TOUCHJUMPPAD 128 // touching a jump pad area
-#define SE_TOUCHTELEPORTER 256 // touching teleporter
-#define SE_ENTERAREA 512 // the given stoparea is entered
-#define SE_HITGROUNDAREA 1024 // a ground face in the area is hit
-#define SE_HITBOUNDINGBOX 2048 // hit the specified bounding box
-#define SE_TOUCHCLUSTERPORTAL 4096 // touching a cluster portal
-
-typedef struct aas_clientmove_s
-{
- vec3_t endpos; //position at the end of movement prediction
- int endarea; //area at end of movement prediction
- vec3_t velocity; //velocity at the end of movement prediction
- aas_trace_t trace; //last trace
- int presencetype; //presence type at end of movement prediction
- int stopevent; //event that made the prediction stop
- int endcontents; //contents at the end of movement prediction
- float time; //time predicted ahead
- int frames; //number of frames predicted ahead
-} aas_clientmove_t;
-
-// alternate route goals
-#define ALTROUTEGOAL_ALL 1
-#define ALTROUTEGOAL_CLUSTERPORTALS 2
-#define ALTROUTEGOAL_VIEWPORTALS 4
-
-typedef struct aas_altroutegoal_s
-{
- vec3_t origin;
- int areanum;
- unsigned short starttraveltime;
- unsigned short goaltraveltime;
- unsigned short extratraveltime;
-} aas_altroutegoal_t;
-
-// route prediction stop events
-#define RSE_NONE 0
-#define RSE_NOROUTE 1 //no route to goal
-#define RSE_USETRAVELTYPE 2 //stop as soon as on of the given travel types is used
-#define RSE_ENTERCONTENTS 4 //stop when entering the given contents
-#define RSE_ENTERAREA 8 //stop when entering the given area
-
-typedef struct aas_predictroute_s
-{
- vec3_t endpos; //position at the end of movement prediction
- int endarea; //area at end of movement prediction
- int stopevent; //event that made the prediction stop
- int endcontents; //contents at the end of movement prediction
- int endtravelflags; //end travel flags
- int numareas; //number of areas predicted ahead
- int time; //time predicted ahead (in hundreth of a sec)
-} aas_predictroute_t;
diff --git a/game/code/botlib/be_aas_bsp.h b/game/code/botlib/be_aas_bsp.h
deleted file mode 100644
index 932874a..0000000
--- a/game/code/botlib/be_aas_bsp.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_bsp.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_bsp.h $
- *
- *****************************************************************************/
-
-#ifdef AASINTERN
-//loads the given BSP file
-int AAS_LoadBSPFile(void);
-//dump the loaded BSP data
-void AAS_DumpBSPData(void);
-//unlink the given entity from the bsp tree leaves
-void AAS_UnlinkFromBSPLeaves(bsp_link_t *leaves);
-//link the given entity to the bsp tree leaves of the given model
-bsp_link_t *AAS_BSPLinkEntity(vec3_t absmins,
- vec3_t absmaxs,
- int entnum,
- int modelnum);
-
-//calculates collision with given entity
-qboolean AAS_EntityCollision(int entnum,
- vec3_t start,
- vec3_t boxmins,
- vec3_t boxmaxs,
- vec3_t end,
- int contentmask,
- bsp_trace_t *trace);
-//for debugging
-void AAS_PrintFreeBSPLinks(char *str);
-//
-#endif //AASINTERN
-
-#define MAX_EPAIRKEY 128
-
-//trace through the world
-bsp_trace_t AAS_Trace( vec3_t start,
- vec3_t mins,
- vec3_t maxs,
- vec3_t end,
- int passent,
- int contentmask);
-//returns the contents at the given point
-int AAS_PointContents(vec3_t point);
-//returns true when p2 is in the PVS of p1
-qboolean AAS_inPVS(vec3_t p1, vec3_t p2);
-//returns true when p2 is in the PHS of p1
-qboolean AAS_inPHS(vec3_t p1, vec3_t p2);
-//returns true if the given areas are connected
-qboolean AAS_AreasConnected(int area1, int area2);
-//creates a list with entities totally or partly within the given box
-int AAS_BoxEntities(vec3_t absmins, vec3_t absmaxs, int *list, int maxcount);
-//gets the mins, maxs and origin of a BSP model
-void AAS_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin);
-//handle to the next bsp entity
-int AAS_NextBSPEntity(int ent);
-//return the value of the BSP epair key
-int AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size);
-//get a vector for the BSP epair key
-int AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v);
-//get a float for the BSP epair key
-int AAS_FloatForBSPEpairKey(int ent, char *key, float *value);
-//get an integer for the BSP epair key
-int AAS_IntForBSPEpairKey(int ent, char *key, int *value);
-
diff --git a/game/code/botlib/be_aas_cluster.h b/game/code/botlib/be_aas_cluster.h
deleted file mode 100644
index e36697d..0000000
--- a/game/code/botlib/be_aas_cluster.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_cluster.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_cluster.h $
- *
- *****************************************************************************/
-
-#ifdef AASINTERN
-//initialize the AAS clustering
-void AAS_InitClustering(void);
-//
-void AAS_SetViewPortalsAsClusterPortals(void);
-#endif //AASINTERN
-
diff --git a/game/code/botlib/be_aas_debug.h b/game/code/botlib/be_aas_debug.h
deleted file mode 100644
index 008eeba..0000000
--- a/game/code/botlib/be_aas_debug.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_debug.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_debug.h $
- *
- *****************************************************************************/
-
-//clear the shown debug lines
-void AAS_ClearShownDebugLines(void);
-//
-void AAS_ClearShownPolygons(void);
-//show a debug line
-void AAS_DebugLine(vec3_t start, vec3_t end, int color);
-//show a permenent line
-void AAS_PermanentLine(vec3_t start, vec3_t end, int color);
-//show a permanent cross
-void AAS_DrawPermanentCross(vec3_t origin, float size, int color);
-//draw a cross in the plane
-void AAS_DrawPlaneCross(vec3_t point, vec3_t normal, float dist, int type, int color);
-//show a bounding box
-void AAS_ShowBoundingBox(vec3_t origin, vec3_t mins, vec3_t maxs);
-//show a face
-void AAS_ShowFace(int facenum);
-//show an area
-void AAS_ShowArea(int areanum, int groundfacesonly);
-//
-void AAS_ShowAreaPolygons(int areanum, int color, int groundfacesonly);
-//draw a cros
-void AAS_DrawCross(vec3_t origin, float size, int color);
-//print the travel type
-void AAS_PrintTravelType(int traveltype);
-//draw an arrow
-void AAS_DrawArrow(vec3_t start, vec3_t end, int linecolor, int arrowcolor);
-//visualize the given reachability
-void AAS_ShowReachability(struct aas_reachability_s *reach);
-//show the reachable areas from the given area
-void AAS_ShowReachableAreas(int areanum);
-
diff --git a/game/code/botlib/be_aas_def.h b/game/code/botlib/be_aas_def.h
deleted file mode 100644
index eb995d6..0000000
--- a/game/code/botlib/be_aas_def.h
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_def.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_def.h $
- *
- *****************************************************************************/
-
-//debugging on
-#define AAS_DEBUG
-
-#define MAX_CLIENTS 64
-#define MAX_MODELS 256 // these are sent over the net as 8 bits
-#define MAX_SOUNDS 256 // so they cannot be blindly increased
-#define MAX_CONFIGSTRINGS 1024
-
-#define CS_SCORES 32
-#define CS_MODELS (CS_SCORES+MAX_CLIENTS)
-#define CS_SOUNDS (CS_MODELS+MAX_MODELS)
-
-#define DF_AASENTNUMBER(x) (x - aasworld.entities)
-#define DF_NUMBERAASENT(x) (&aasworld.entities[x])
-#define DF_AASENTCLIENT(x) (x - aasworld.entities - 1)
-#define DF_CLIENTAASENT(x) (&aasworld.entities[x + 1])
-
-#ifndef MAX_PATH
- #define MAX_PATH MAX_QPATH
-#endif
-
-//string index (for model, sound and image index)
-typedef struct aas_stringindex_s
-{
- int numindexes;
- char **index;
-} aas_stringindex_t;
-
-//structure to link entities to areas and areas to entities
-typedef struct aas_link_s
-{
- int entnum;
- int areanum;
- struct aas_link_s *next_ent, *prev_ent;
- struct aas_link_s *next_area, *prev_area;
-} aas_link_t;
-
-//structure to link entities to leaves and leaves to entities
-typedef struct bsp_link_s
-{
- int entnum;
- int leafnum;
- struct bsp_link_s *next_ent, *prev_ent;
- struct bsp_link_s *next_leaf, *prev_leaf;
-} bsp_link_t;
-
-typedef struct bsp_entdata_s
-{
- vec3_t origin;
- vec3_t angles;
- vec3_t absmins;
- vec3_t absmaxs;
- int solid;
- int modelnum;
-} bsp_entdata_t;
-
-//entity
-typedef struct aas_entity_s
-{
- //entity info
- aas_entityinfo_t i;
- //links into the AAS areas
- aas_link_t *areas;
- //links into the BSP leaves
- bsp_link_t *leaves;
-} aas_entity_t;
-
-typedef struct aas_settings_s
-{
- vec3_t phys_gravitydirection;
- float phys_friction;
- float phys_stopspeed;
- float phys_gravity;
- float phys_waterfriction;
- float phys_watergravity;
- float phys_maxvelocity;
- float phys_maxwalkvelocity;
- float phys_maxcrouchvelocity;
- float phys_maxswimvelocity;
- float phys_walkaccelerate;
- float phys_airaccelerate;
- float phys_swimaccelerate;
- float phys_maxstep;
- float phys_maxsteepness;
- float phys_maxwaterjump;
- float phys_maxbarrier;
- float phys_jumpvel;
- float phys_falldelta5;
- float phys_falldelta10;
- float rs_waterjump;
- float rs_teleport;
- float rs_barrierjump;
- float rs_startcrouch;
- float rs_startgrapple;
- float rs_startwalkoffledge;
- float rs_startjump;
- float rs_rocketjump;
- float rs_bfgjump;
- float rs_jumppad;
- float rs_aircontrolledjumppad;
- float rs_funcbob;
- float rs_startelevator;
- float rs_falldamage5;
- float rs_falldamage10;
- float rs_maxfallheight;
- float rs_maxjumpfallheight;
-} aas_settings_t;
-
-#define CACHETYPE_PORTAL 0
-#define CACHETYPE_AREA 1
-
-//routing cache
-typedef struct aas_routingcache_s
-{
- byte type; //portal or area cache
- float time; //last time accessed or updated
- int size; //size of the routing cache
- int cluster; //cluster the cache is for
- int areanum; //area the cache is created for
- vec3_t origin; //origin within the area
- float starttraveltime; //travel time to start with
- int travelflags; //combinations of the travel flags
- struct aas_routingcache_s *prev, *next;
- struct aas_routingcache_s *time_prev, *time_next;
- unsigned char *reachabilities; //reachabilities used for routing
- unsigned short int traveltimes[1]; //travel time for every area (variable sized)
-} aas_routingcache_t;
-
-//fields for the routing algorithm
-typedef struct aas_routingupdate_s
-{
- int cluster;
- int areanum; //area number of the update
- vec3_t start; //start point the area was entered
- unsigned short int tmptraveltime; //temporary travel time
- unsigned short int *areatraveltimes; //travel times within the area
- qboolean inlist; //true if the update is in the list
- struct aas_routingupdate_s *next;
- struct aas_routingupdate_s *prev;
-} aas_routingupdate_t;
-
-//reversed reachability link
-typedef struct aas_reversedlink_s
-{
- int linknum; //the aas_areareachability_t
- int areanum; //reachable from this area
- struct aas_reversedlink_s *next; //next link
-} aas_reversedlink_t;
-
-//reversed area reachability
-typedef struct aas_reversedreachability_s
-{
- int numlinks;
- aas_reversedlink_t *first;
-} aas_reversedreachability_t;
-
-//areas a reachability goes through
-typedef struct aas_reachabilityareas_s
-{
- int firstarea, numareas;
-} aas_reachabilityareas_t;
-
-typedef struct aas_s
-{
- int loaded; //true when an AAS file is loaded
- int initialized; //true when AAS has been initialized
- int savefile; //set true when file should be saved
- int bspchecksum;
- //current time
- float time;
- int numframes;
- //name of the aas file
- char filename[MAX_PATH];
- char mapname[MAX_PATH];
- //bounding boxes
- int numbboxes;
- aas_bbox_t *bboxes;
- //vertexes
- int numvertexes;
- aas_vertex_t *vertexes;
- //planes
- int numplanes;
- aas_plane_t *planes;
- //edges
- int numedges;
- aas_edge_t *edges;
- //edge index
- int edgeindexsize;
- aas_edgeindex_t *edgeindex;
- //faces
- int numfaces;
- aas_face_t *faces;
- //face index
- int faceindexsize;
- aas_faceindex_t *faceindex;
- //convex areas
- int numareas;
- aas_area_t *areas;
- //convex area settings
- int numareasettings;
- aas_areasettings_t *areasettings;
- //reachablity list
- int reachabilitysize;
- aas_reachability_t *reachability;
- //nodes of the bsp tree
- int numnodes;
- aas_node_t *nodes;
- //cluster portals
- int numportals;
- aas_portal_t *portals;
- //cluster portal index
- int portalindexsize;
- aas_portalindex_t *portalindex;
- //clusters
- int numclusters;
- aas_cluster_t *clusters;
- //
- int numreachabilityareas;
- float reachabilitytime;
- //enities linked in the areas
- aas_link_t *linkheap; //heap with link structures
- int linkheapsize; //size of the link heap
- aas_link_t *freelinks; //first free link
- aas_link_t **arealinkedentities; //entities linked into areas
- //entities
- int maxentities;
- int maxclients;
- aas_entity_t *entities;
- //string indexes
- char *configstrings[MAX_CONFIGSTRINGS];
- int indexessetup;
- //index to retrieve travel flag for a travel type
- int travelflagfortype[MAX_TRAVELTYPES];
- //travel flags for each area based on contents
- int *areacontentstravelflags;
- //routing update
- aas_routingupdate_t *areaupdate;
- aas_routingupdate_t *portalupdate;
- //number of routing updates during a frame (reset every frame)
- int frameroutingupdates;
- //reversed reachability links
- aas_reversedreachability_t *reversedreachability;
- //travel times within the areas
- unsigned short ***areatraveltimes;
- //array of size numclusters with cluster cache
- aas_routingcache_t ***clusterareacache;
- aas_routingcache_t **portalcache;
- //cache list sorted on time
- aas_routingcache_t *oldestcache; // start of cache list sorted on time
- aas_routingcache_t *newestcache; // end of cache list sorted on time
- //maximum travel time through portal areas
- int *portalmaxtraveltimes;
- //areas the reachabilities go through
- int *reachabilityareaindex;
- aas_reachabilityareas_t *reachabilityareas;
-} aas_t;
-
-#define AASINTERN
-
-#ifndef BSPCINCLUDE
-
-#include "be_aas_main.h"
-#include "be_aas_entity.h"
-#include "be_aas_sample.h"
-#include "be_aas_cluster.h"
-#include "be_aas_reach.h"
-#include "be_aas_route.h"
-#include "be_aas_routealt.h"
-#include "be_aas_debug.h"
-#include "be_aas_file.h"
-#include "be_aas_optimize.h"
-#include "be_aas_bsp.h"
-#include "be_aas_move.h"
-
-#endif //BSPCINCLUDE
diff --git a/game/code/botlib/be_aas_entity.h b/game/code/botlib/be_aas_entity.h
deleted file mode 100644
index 01ec54c..0000000
--- a/game/code/botlib/be_aas_entity.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_entity.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_entity.h $
- *
- *****************************************************************************/
-
-#ifdef AASINTERN
-//invalidates all entity infos
-void AAS_InvalidateEntities(void);
-//unlink not updated entities
-void AAS_UnlinkInvalidEntities(void);
-//resets the entity AAS and BSP links (sets areas and leaves pointers to NULL)
-void AAS_ResetEntityLinks(void);
-//updates an entity
-int AAS_UpdateEntity(int ent, bot_entitystate_t *state);
-//gives the entity data used for collision detection
-void AAS_EntityBSPData(int entnum, bsp_entdata_t *entdata);
-#endif //AASINTERN
-
-//returns the size of the entity bounding box in mins and maxs
-void AAS_EntitySize(int entnum, vec3_t mins, vec3_t maxs);
-//returns the BSP model number of the entity
-int AAS_EntityModelNum(int entnum);
-//returns the origin of an entity with the given model number
-int AAS_OriginOfMoverWithModelNum(int modelnum, vec3_t origin);
-//returns the best reachable area the entity is situated in
-int AAS_BestReachableEntityArea(int entnum);
-//returns the info of the given entity
-void AAS_EntityInfo(int entnum, aas_entityinfo_t *info);
-//returns the next entity
-int AAS_NextEntity(int entnum);
-//returns the origin of the entity
-void AAS_EntityOrigin(int entnum, vec3_t origin);
-//returns the entity type
-int AAS_EntityType(int entnum);
-//returns the model index of the entity
-int AAS_EntityModelindex(int entnum);
-
diff --git a/game/code/botlib/be_aas_file.h b/game/code/botlib/be_aas_file.h
deleted file mode 100644
index c2271fc..0000000
--- a/game/code/botlib/be_aas_file.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_file.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_file.h $
- *
- *****************************************************************************/
-
-#ifdef AASINTERN
-//loads the AAS file with the given name
-int AAS_LoadAASFile(char *filename);
-//writes an AAS file with the given name
-qboolean AAS_WriteAASFile(char *filename);
-//dumps the loaded AAS data
-void AAS_DumpAASData(void);
-//print AAS file information
-void AAS_FileInfo(void);
-#endif //AASINTERN
-
diff --git a/game/code/botlib/be_aas_funcs.h b/game/code/botlib/be_aas_funcs.h
deleted file mode 100644
index 87c7636..0000000
--- a/game/code/botlib/be_aas_funcs.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_funcs.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_funcs.h $
- *
- *****************************************************************************/
-
-#ifndef BSPCINCLUDE
-
-#include "be_aas_main.h"
-#include "be_aas_entity.h"
-#include "be_aas_sample.h"
-#include "be_aas_cluster.h"
-#include "be_aas_reach.h"
-#include "be_aas_route.h"
-#include "be_aas_routealt.h"
-#include "be_aas_debug.h"
-#include "be_aas_file.h"
-#include "be_aas_optimize.h"
-#include "be_aas_bsp.h"
-#include "be_aas_move.h"
-
-#endif //BSPCINCLUDE
diff --git a/game/code/botlib/be_aas_main.h b/game/code/botlib/be_aas_main.h
deleted file mode 100644
index 1d0bef1..0000000
--- a/game/code/botlib/be_aas_main.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_main.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_main.h $
- *
- *****************************************************************************/
-
-#ifdef AASINTERN
-
-extern aas_t aasworld;
-
-//AAS error message
-void QDECL AAS_Error(char *fmt, ...);
-//set AAS initialized
-void AAS_SetInitialized(void);
-//setup AAS with the given number of entities and clients
-int AAS_Setup(void);
-//shutdown AAS
-void AAS_Shutdown(void);
-//start a new map
-int AAS_LoadMap(const char *mapname);
-//start a new time frame
-int AAS_StartFrame(float time);
-#endif //AASINTERN
-
-//returns true if AAS is initialized
-int AAS_Initialized(void);
-//returns true if the AAS file is loaded
-int AAS_Loaded(void);
-//returns the model name from the given index
-char *AAS_ModelFromIndex(int index);
-//returns the index from the given model name
-int AAS_IndexFromModel(char *modelname);
-//returns the current time
-float AAS_Time(void);
-//
-void AAS_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj );
diff --git a/game/code/botlib/be_aas_move.h b/game/code/botlib/be_aas_move.h
deleted file mode 100644
index b00e41a..0000000
--- a/game/code/botlib/be_aas_move.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_move.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_move.h $
- *
- *****************************************************************************/
-
-#ifdef AASINTERN
-extern aas_settings_t aassettings;
-#endif //AASINTERN
-
-//movement prediction
-int AAS_PredictClientMovement(struct aas_clientmove_s *move,
- int entnum, vec3_t origin,
- int presencetype, int onground,
- vec3_t velocity, vec3_t cmdmove,
- int cmdframes,
- int maxframes, float frametime,
- int stopevent, int stopareanum, int visualize);
-//predict movement until bounding box is hit
-int AAS_ClientMovementHitBBox(struct aas_clientmove_s *move,
- int entnum, vec3_t origin,
- int presencetype, int onground,
- vec3_t velocity, vec3_t cmdmove,
- int cmdframes,
- int maxframes, float frametime,
- vec3_t mins, vec3_t maxs, int visualize);
-//returns true if on the ground at the given origin
-int AAS_OnGround(vec3_t origin, int presencetype, int passent);
-//returns true if swimming at the given origin
-int AAS_Swimming(vec3_t origin);
-//returns the jump reachability run start point
-void AAS_JumpReachRunStart(struct aas_reachability_s *reach, vec3_t runstart);
-//returns true if against a ladder at the given origin
-int AAS_AgainstLadder(vec3_t origin);
-//rocket jump Z velocity when rocket-jumping at origin
-float AAS_RocketJumpZVelocity(vec3_t origin);
-//bfg jump Z velocity when bfg-jumping at origin
-float AAS_BFGJumpZVelocity(vec3_t origin);
-//calculates the horizontal velocity needed for a jump and returns true this velocity could be calculated
-int AAS_HorizontalVelocityForJump(float zvel, vec3_t start, vec3_t end, float *velocity);
-//
-void AAS_SetMovedir(vec3_t angles, vec3_t movedir);
-//
-int AAS_DropToFloor(vec3_t origin, vec3_t mins, vec3_t maxs);
-//
-void AAS_InitSettings(void);
diff --git a/game/code/botlib/be_aas_optimize.h b/game/code/botlib/be_aas_optimize.h
deleted file mode 100644
index 799c28a..0000000
--- a/game/code/botlib/be_aas_optimize.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_optimize.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_optimize.h $
- *
- *****************************************************************************/
-
-void AAS_Optimize(void);
-
diff --git a/game/code/botlib/be_aas_reach.h b/game/code/botlib/be_aas_reach.h
deleted file mode 100644
index 0ab8740..0000000
--- a/game/code/botlib/be_aas_reach.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_reach.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_reach.h $
- *
- *****************************************************************************/
-
-#ifdef AASINTERN
-//initialize calculating the reachabilities
-void AAS_InitReachability(void);
-//continue calculating the reachabilities
-int AAS_ContinueInitReachability(float time);
-//
-int AAS_BestReachableLinkArea(aas_link_t *areas);
-#endif //AASINTERN
-
-//returns true if the are has reachabilities to other areas
-int AAS_AreaReachability(int areanum);
-//returns the best reachable area and goal origin for a bounding box at the given origin
-int AAS_BestReachableArea(vec3_t origin, vec3_t mins, vec3_t maxs, vec3_t goalorigin);
-//returns the best jumppad area from which the bbox at origin is reachable
-int AAS_BestReachableFromJumpPadArea(vec3_t origin, vec3_t mins, vec3_t maxs);
-//returns the next reachability using the given model
-int AAS_NextModelReachability(int num, int modelnum);
-//returns the total area of the ground faces of the given area
-float AAS_AreaGroundFaceArea(int areanum);
-//returns true if the area is crouch only
-int AAS_AreaCrouch(int areanum);
-//returns true if a player can swim in this area
-int AAS_AreaSwim(int areanum);
-//returns true if the area is filled with a liquid
-int AAS_AreaLiquid(int areanum);
-//returns true if the area contains lava
-int AAS_AreaLava(int areanum);
-//returns true if the area contains slime
-int AAS_AreaSlime(int areanum);
-//returns true if the area has one or more ground faces
-int AAS_AreaGrounded(int areanum);
-//returns true if the area has one or more ladder faces
-int AAS_AreaLadder(int areanum);
-//returns true if the area is a jump pad
-int AAS_AreaJumpPad(int areanum);
-//returns true if the area is donotenter
-int AAS_AreaDoNotEnter(int areanum);
diff --git a/game/code/botlib/be_aas_route.h b/game/code/botlib/be_aas_route.h
deleted file mode 100644
index 8805c66..0000000
--- a/game/code/botlib/be_aas_route.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_route.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_route.h $
- *
- *****************************************************************************/
-
-#ifdef AASINTERN
-//initialize the AAS routing
-void AAS_InitRouting(void);
-//free the AAS routing caches
-void AAS_FreeRoutingCaches(void);
-//returns the travel time from start to end in the given area
-unsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end);
-//
-void AAS_CreateAllRoutingCache(void);
-void AAS_WriteRouteCache(void);
-//
-void AAS_RoutingInfo(void);
-#endif //AASINTERN
-
-//returns the travel flag for the given travel type
-int AAS_TravelFlagForType(int traveltype);
-//return the travel flag(s) for traveling through this area
-int AAS_AreaContentsTravelFlags(int areanum);
-//returns the index of the next reachability for the given area
-int AAS_NextAreaReachability(int areanum, int reachnum);
-//returns the reachability with the given index
-void AAS_ReachabilityFromNum(int num, struct aas_reachability_s *reach);
-//returns a random goal area and goal origin
-int AAS_RandomGoalArea(int areanum, int travelflags, int *goalareanum, vec3_t goalorigin);
-//enable or disable an area for routing
-int AAS_EnableRoutingArea(int areanum, int enable);
-//returns the travel time within the given area from start to end
-unsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end);
-//returns the travel time from the area to the goal area using the given travel flags
-int AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags);
-//predict a route up to a stop event
-int AAS_PredictRoute(struct aas_predictroute_s *route, int areanum, vec3_t origin,
- int goalareanum, int travelflags, int maxareas, int maxtime,
- int stopevent, int stopcontents, int stoptfl, int stopareanum);
-
-
diff --git a/game/code/botlib/be_aas_routealt.h b/game/code/botlib/be_aas_routealt.h
deleted file mode 100644
index 160966a..0000000
--- a/game/code/botlib/be_aas_routealt.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_routealt.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_routealt.h $
- *
- *****************************************************************************/
-
-#ifdef AASINTERN
-void AAS_InitAlternativeRouting(void);
-void AAS_ShutdownAlternativeRouting(void);
-#endif //AASINTERN
-
-
-int AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,
- aas_altroutegoal_t *altroutegoals, int maxaltroutegoals,
- int type);
diff --git a/game/code/botlib/be_aas_sample.h b/game/code/botlib/be_aas_sample.h
deleted file mode 100644
index ed6c237..0000000
--- a/game/code/botlib/be_aas_sample.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_aas_sample.h
- *
- * desc: AAS
- *
- * $Archive: /source/code/botlib/be_aas_sample.h $
- *
- *****************************************************************************/
-
-#ifdef AASINTERN
-void AAS_InitAASLinkHeap(void);
-void AAS_InitAASLinkedEntities(void);
-void AAS_FreeAASLinkHeap(void);
-void AAS_FreeAASLinkedEntities(void);
-aas_face_t *AAS_AreaGroundFace(int areanum, vec3_t point);
-aas_face_t *AAS_TraceEndFace(aas_trace_t *trace);
-aas_plane_t *AAS_PlaneFromNum(int planenum);
-aas_link_t *AAS_AASLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum);
-aas_link_t *AAS_LinkEntityClientBBox(vec3_t absmins, vec3_t absmaxs, int entnum, int presencetype);
-qboolean AAS_PointInsideFace(int facenum, vec3_t point, float epsilon);
-qboolean AAS_InsideFace(aas_face_t *face, vec3_t pnormal, vec3_t point, float epsilon);
-void AAS_UnlinkFromAreas(aas_link_t *areas);
-#endif //AASINTERN
-
-//returns the mins and maxs of the bounding box for the given presence type
-void AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs);
-//returns the cluster the area is in (negative portal number if the area is a portal)
-int AAS_AreaCluster(int areanum);
-//returns the presence type(s) of the area
-int AAS_AreaPresenceType(int areanum);
-//returns the presence type(s) at the given point
-int AAS_PointPresenceType(vec3_t point);
-//returns the result of the trace of a client bbox
-aas_trace_t AAS_TraceClientBBox(vec3_t start, vec3_t end, int presencetype, int passent);
-//stores the areas the trace went through and returns the number of passed areas
-int AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas);
-//returns the areas the bounding box is in
-int AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas);
-//return area information
-int AAS_AreaInfo( int areanum, aas_areainfo_t *info );
-//returns the area the point is in
-int AAS_PointAreaNum(vec3_t point);
-//
-int AAS_PointReachabilityAreaIndex( vec3_t point );
-//returns the plane the given face is in
-void AAS_FacePlane(int facenum, vec3_t normal, float *dist);
-
diff --git a/game/code/botlib/be_ai_char.h b/game/code/botlib/be_ai_char.h
deleted file mode 100644
index 719d68f..0000000
--- a/game/code/botlib/be_ai_char.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: be_ai_char.h
- *
- * desc: bot characters
- *
- * $Archive: /source/code/botlib/be_ai_char.h $
- *
- *****************************************************************************/
-
-//loads a bot character from a file
-int BotLoadCharacter(char *charfile, float skill);
-//frees a bot character
-void BotFreeCharacter(int character);
-//returns a float characteristic
-float Characteristic_Float(int character, int index);
-//returns a bounded float characteristic
-float Characteristic_BFloat(int character, int index, float min, float max);
-//returns an integer characteristic
-int Characteristic_Integer(int character, int index);
-//returns a bounded integer characteristic
-int Characteristic_BInteger(int character, int index, int min, int max);
-//returns a string characteristic
-void Characteristic_String(int character, int index, char *buf, int size);
-//free cached bot characters
-void BotShutdownCharacters(void);
diff --git a/game/code/botlib/be_ai_chat.h b/game/code/botlib/be_ai_chat.h
deleted file mode 100644
index 53a56d7..0000000
--- a/game/code/botlib/be_ai_chat.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*****************************************************************************
- * name: be_ai_chat.h
- *
- * desc: char AI
- *
- * $Archive: /source/code/botlib/be_ai_chat.h $
- *
- *****************************************************************************/
-
-#define MAX_MESSAGE_SIZE 256
-#define MAX_CHATTYPE_NAME 32
-#define MAX_MATCHVARIABLES 8
-
-#define CHAT_GENDERLESS 0
-#define CHAT_GENDERFEMALE 1
-#define CHAT_GENDERMALE 2
-
-#define CHAT_ALL 0
-#define CHAT_TEAM 1
-#define CHAT_TELL 2
-
-//a console message
-typedef struct bot_consolemessage_s
-{
- int handle;
- float time; //message time
- int type; //message type
- char message[MAX_MESSAGE_SIZE]; //message
- struct bot_consolemessage_s *prev, *next; //prev and next in list
-} bot_consolemessage_t;
-
-//match variable
-typedef struct bot_matchvariable_s
-{
- char offset;
- int length;
-} bot_matchvariable_t;
-//returned to AI when a match is found
-typedef struct bot_match_s
-{
- char string[MAX_MESSAGE_SIZE];
- int type;
- int subtype;
- bot_matchvariable_t variables[MAX_MATCHVARIABLES];
-} bot_match_t;
-
-//setup the chat AI
-int BotSetupChatAI(void);
-//shutdown the chat AI
-void BotShutdownChatAI(void);
-//returns the handle to a newly allocated chat state
-int BotAllocChatState(void);
-//frees the chatstate
-void BotFreeChatState(int handle);
-//adds a console message to the chat state
-void BotQueueConsoleMessage(int chatstate, int type, char *message);
-//removes the console message from the chat state
-void BotRemoveConsoleMessage(int chatstate, int handle);
-//returns the next console message from the state
-int BotNextConsoleMessage(int chatstate, bot_consolemessage_t *cm);
-//returns the number of console messages currently stored in the state
-int BotNumConsoleMessages(int chatstate);
-//selects a chat message of the given type
-void BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7);
-//returns the number of initial chat messages of the given type
-int BotNumInitialChats(int chatstate, char *type);
-//find and select a reply for the given message
-int BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7);
-//returns the length of the currently selected chat message
-int BotChatLength(int chatstate);
-//enters the selected chat message
-void BotEnterChat(int chatstate, int clientto, int sendto);
-//get the chat message ready to be output
-void BotGetChatMessage(int chatstate, char *buf, int size);
-//checks if the first string contains the second one, returns index into first string or -1 if not found
-int StringContains(char *str1, char *str2, int casesensitive);
-//finds a match for the given string using the match templates
-int BotFindMatch(char *str, bot_match_t *match, unsigned long int context);
-//returns a variable from a match
-void BotMatchVariable(bot_match_t *match, int variable, char *buf, int size);
-//unify all the white spaces in the string
-void UnifyWhiteSpaces(char *string);
-//replace all the context related synonyms in the string
-void BotReplaceSynonyms(char *string, unsigned long int context);
-//loads a chat file for the chat state
-int BotLoadChatFile(int chatstate, char *chatfile, char *chatname);
-//store the gender of the bot in the chat state
-void BotSetChatGender(int chatstate, int gender);
-//store the bot name in the chat state
-void BotSetChatName(int chatstate, char *name, int client);
-
diff --git a/game/code/botlib/be_ai_gen.h b/game/code/botlib/be_ai_gen.h
deleted file mode 100644
index ce9ba92..0000000
--- a/game/code/botlib/be_ai_gen.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: be_ai_gen.h
- *
- * desc: genetic selection
- *
- * $Archive: /source/code/botlib/be_ai_gen.h $
- *
- *****************************************************************************/
-
-int GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child);
diff --git a/game/code/botlib/be_ai_goal.h b/game/code/botlib/be_ai_goal.h
deleted file mode 100644
index 80dad08..0000000
--- a/game/code/botlib/be_ai_goal.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*****************************************************************************
- * name: be_ai_goal.h
- *
- * desc: goal AI
- *
- * $Archive: /source/code/botlib/be_ai_goal.h $
- *
- *****************************************************************************/
-
-#define MAX_AVOIDGOALS 256
-#define MAX_GOALSTACK 8
-
-#define GFL_NONE 0
-#define GFL_ITEM 1
-#define GFL_ROAM 2
-#define GFL_DROPPED 4
-
-//a bot goal
-typedef struct bot_goal_s
-{
- vec3_t origin; //origin of the goal
- int areanum; //area number of the goal
- vec3_t mins, maxs; //mins and maxs of the goal
- int entitynum; //number of the goal entity
- int number; //goal number
- int flags; //goal flags
- int iteminfo; //item information
-} bot_goal_t;
-
-//reset the whole goal state, but keep the item weights
-void BotResetGoalState(int goalstate);
-//reset avoid goals
-void BotResetAvoidGoals(int goalstate);
-//remove the goal with the given number from the avoid goals
-void BotRemoveFromAvoidGoals(int goalstate, int number);
-//push a goal onto the goal stack
-void BotPushGoal(int goalstate, bot_goal_t *goal);
-//pop a goal from the goal stack
-void BotPopGoal(int goalstate);
-//empty the bot's goal stack
-void BotEmptyGoalStack(int goalstate);
-//dump the avoid goals
-void BotDumpAvoidGoals(int goalstate);
-//dump the goal stack
-void BotDumpGoalStack(int goalstate);
-//get the name name of the goal with the given number
-void BotGoalName(int number, char *name, int size);
-//get the top goal from the stack
-int BotGetTopGoal(int goalstate, bot_goal_t *goal);
-//get the second goal on the stack
-int BotGetSecondGoal(int goalstate, bot_goal_t *goal);
-//choose the best long term goal item for the bot
-int BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags);
-//choose the best nearby goal item for the bot
-//the item may not be further away from the current bot position than maxtime
-//also the travel time from the nearby goal towards the long term goal may not
-//be larger than the travel time towards the long term goal from the current bot position
-int BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags,
- bot_goal_t *ltg, float maxtime);
-//returns true if the bot touches the goal
-int BotTouchingGoal(vec3_t origin, bot_goal_t *goal);
-//returns true if the goal should be visible but isn't
-int BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, bot_goal_t *goal);
-//search for a goal for the given classname, the index can be used
-//as a start point for the search when multiple goals are available with that same classname
-int BotGetLevelItemGoal(int index, char *classname, bot_goal_t *goal);
-//get the next camp spot in the map
-int BotGetNextCampSpotGoal(int num, bot_goal_t *goal);
-//get the map location with the given name
-int BotGetMapLocationGoal(char *name, bot_goal_t *goal);
-//returns the avoid goal time
-float BotAvoidGoalTime(int goalstate, int number);
-//set the avoid goal time
-void BotSetAvoidGoalTime(int goalstate, int number, float avoidtime);
-//initializes the items in the level
-void BotInitLevelItems(void);
-//regularly update dynamic entity items (dropped weapons, flags etc.)
-void BotUpdateEntityItems(void);
-//interbreed the goal fuzzy logic
-void BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child);
-//save the goal fuzzy logic to disk
-void BotSaveGoalFuzzyLogic(int goalstate, char *filename);
-//mutate the goal fuzzy logic
-void BotMutateGoalFuzzyLogic(int goalstate, float range);
-//loads item weights for the bot
-int BotLoadItemWeights(int goalstate, char *filename);
-//frees the item weights of the bot
-void BotFreeItemWeights(int goalstate);
-//returns the handle of a newly allocated goal state
-int BotAllocGoalState(int client);
-//free the given goal state
-void BotFreeGoalState(int handle);
-//setup the goal AI
-int BotSetupGoalAI(void);
-//shut down the goal AI
-void BotShutdownGoalAI(void);
diff --git a/game/code/botlib/be_ai_move.h b/game/code/botlib/be_ai_move.h
deleted file mode 100644
index a32d939..0000000
--- a/game/code/botlib/be_ai_move.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: be_ai_move.h
- *
- * desc: movement AI
- *
- * $Archive: /source/code/botlib/be_ai_move.h $
- *
- *****************************************************************************/
-
-//movement types
-#define MOVE_WALK 1
-#define MOVE_CROUCH 2
-#define MOVE_JUMP 4
-#define MOVE_GRAPPLE 8
-#define MOVE_ROCKETJUMP 16
-#define MOVE_BFGJUMP 32
-//move flags
-#define MFL_BARRIERJUMP 1 //bot is performing a barrier jump
-#define MFL_ONGROUND 2 //bot is in the ground
-#define MFL_SWIMMING 4 //bot is swimming
-#define MFL_AGAINSTLADDER 8 //bot is against a ladder
-#define MFL_WATERJUMP 16 //bot is waterjumping
-#define MFL_TELEPORTED 32 //bot is being teleported
-#define MFL_GRAPPLEPULL 64 //bot is being pulled by the grapple
-#define MFL_ACTIVEGRAPPLE 128 //bot is using the grapple hook
-#define MFL_GRAPPLERESET 256 //bot has reset the grapple
-#define MFL_WALK 512 //bot should walk slowly
-// move result flags
-#define MOVERESULT_MOVEMENTVIEW 1 //bot uses view for movement
-#define MOVERESULT_SWIMVIEW 2 //bot uses view for swimming
-#define MOVERESULT_WAITING 4 //bot is waiting for something
-#define MOVERESULT_MOVEMENTVIEWSET 8 //bot has set the view in movement code
-#define MOVERESULT_MOVEMENTWEAPON 16 //bot uses weapon for movement
-#define MOVERESULT_ONTOPOFOBSTACLE 32 //bot is ontop of obstacle
-#define MOVERESULT_ONTOPOF_FUNCBOB 64 //bot is ontop of a func_bobbing
-#define MOVERESULT_ONTOPOF_ELEVATOR 128 //bot is ontop of an elevator (func_plat)
-#define MOVERESULT_BLOCKEDBYAVOIDSPOT 256 //bot is blocked by an avoid spot
-//
-#define MAX_AVOIDREACH 1
-#define MAX_AVOIDSPOTS 32
-// avoid spot types
-#define AVOID_CLEAR 0 //clear all avoid spots
-#define AVOID_ALWAYS 1 //avoid always
-#define AVOID_DONTBLOCK 2 //never totally block
-// restult types
-#define RESULTTYPE_ELEVATORUP 1 //elevator is up
-#define RESULTTYPE_WAITFORFUNCBOBBING 2 //waiting for func bobbing to arrive
-#define RESULTTYPE_BADGRAPPLEPATH 4 //grapple path is obstructed
-#define RESULTTYPE_INSOLIDAREA 8 //stuck in solid area, this is bad
-
-//structure used to initialize the movement state
-//the or_moveflags MFL_ONGROUND, MFL_TELEPORTED and MFL_WATERJUMP come from the playerstate
-typedef struct bot_initmove_s
-{
- vec3_t origin; //origin of the bot
- vec3_t velocity; //velocity of the bot
- vec3_t viewoffset; //view offset
- int entitynum; //entity number of the bot
- int client; //client number of the bot
- float thinktime; //time the bot thinks
- int presencetype; //presencetype of the bot
- vec3_t viewangles; //view angles of the bot
- int or_moveflags; //values ored to the movement flags
-} bot_initmove_t;
-
-//NOTE: the ideal_viewangles are only valid if MFL_MOVEMENTVIEW is set
-typedef struct bot_moveresult_s
-{
- int failure; //true if movement failed all together
- int type; //failure or blocked type
- int blocked; //true if blocked by an entity
- int blockentity; //entity blocking the bot
- int traveltype; //last executed travel type
- int flags; //result flags
- int weapon; //weapon used for movement
- vec3_t movedir; //movement direction
- vec3_t ideal_viewangles; //ideal viewangles for the movement
-} bot_moveresult_t;
-
-#define bot_moveresult_t_cleared(x) bot_moveresult_t (x) = {0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0}}
-
-typedef struct bot_avoidspot_s
-{
- vec3_t origin;
- float radius;
- int type;
-} bot_avoidspot_t;
-
-//resets the whole move state
-void BotResetMoveState(int movestate);
-//moves the bot to the given goal
-void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags);
-//moves the bot in the specified direction using the specified type of movement
-int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type);
-//reset avoid reachability
-void BotResetAvoidReach(int movestate);
-//resets the last avoid reachability
-void BotResetLastAvoidReach(int movestate);
-//returns a reachability area if the origin is in one
-int BotReachabilityArea(vec3_t origin, int client);
-//view target based on movement
-int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target);
-//predict the position of a player based on movement towards a goal
-int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target);
-//returns the handle of a newly allocated movestate
-int BotAllocMoveState(void);
-//frees the movestate with the given handle
-void BotFreeMoveState(int handle);
-//initialize movement state before performing any movement
-void BotInitMoveState(int handle, bot_initmove_t *initmove);
-//add a spot to avoid (if type == AVOID_CLEAR all spots are removed)
-void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type);
-//must be called every map change
-void BotSetBrushModelTypes(void);
-//setup movement AI
-int BotSetupMoveAI(void);
-//shutdown movement AI
-void BotShutdownMoveAI(void);
-
diff --git a/game/code/botlib/be_ai_weap.h b/game/code/botlib/be_ai_weap.h
deleted file mode 100644
index 59067fb..0000000
--- a/game/code/botlib/be_ai_weap.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: be_ai_weap.h
- *
- * desc: weapon AI
- *
- * $Archive: /source/code/botlib/be_ai_weap.h $
- *
- *****************************************************************************/
-
-//projectile flags
-#define PFL_WINDOWDAMAGE 1 //projectile damages through window
-#define PFL_RETURN 2 //set when projectile returns to owner
-//weapon flags
-#define WFL_FIRERELEASED 1 //set when projectile is fired with key-up event
-//damage types
-#define DAMAGETYPE_IMPACT 1 //damage on impact
-#define DAMAGETYPE_RADIAL 2 //radial damage
-#define DAMAGETYPE_VISIBLE 4 //damage to all entities visible to the projectile
-
-typedef struct projectileinfo_s
-{
- char name[MAX_STRINGFIELD];
- char model[MAX_STRINGFIELD];
- int flags;
- float gravity;
- int damage;
- float radius;
- int visdamage;
- int damagetype;
- int healthinc;
- float push;
- float detonation;
- float bounce;
- float bouncefric;
- float bouncestop;
-} projectileinfo_t;
-
-typedef struct weaponinfo_s
-{
- int valid; //true if the weapon info is valid
- int number; //number of the weapon
- char name[MAX_STRINGFIELD];
- char model[MAX_STRINGFIELD];
- int level;
- int weaponindex;
- int flags;
- char projectile[MAX_STRINGFIELD];
- int numprojectiles;
- float hspread;
- float vspread;
- float speed;
- float acceleration;
- vec3_t recoil;
- vec3_t offset;
- vec3_t angleoffset;
- float extrazvelocity;
- int ammoamount;
- int ammoindex;
- float activate;
- float reload;
- float spinup;
- float spindown;
- projectileinfo_t proj; //pointer to the used projectile
-} weaponinfo_t;
-
-//setup the weapon AI
-int BotSetupWeaponAI(void);
-//shut down the weapon AI
-void BotShutdownWeaponAI(void);
-//returns the best weapon to fight with
-int BotChooseBestFightWeapon(int weaponstate, int *inventory);
-//returns the information of the current weapon
-void BotGetWeaponInfo(int weaponstate, int weapon, weaponinfo_t *weaponinfo);
-//loads the weapon weights
-int BotLoadWeaponWeights(int weaponstate, char *filename);
-//returns a handle to a newly allocated weapon state
-int BotAllocWeaponState(void);
-//frees the weapon state
-void BotFreeWeaponState(int weaponstate);
-//resets the whole weapon state
-void BotResetWeaponState(int weaponstate);
diff --git a/game/code/botlib/be_ai_weight.h b/game/code/botlib/be_ai_weight.h
deleted file mode 100644
index fb1c885..0000000
--- a/game/code/botlib/be_ai_weight.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_ai_weight.h
- *
- * desc: fuzzy weights
- *
- * $Archive: /source/code/botlib/be_ai_weight.h $
- *
- *****************************************************************************/
-
-#define WT_BALANCE 1
-#define MAX_WEIGHTS 128
-
-//fuzzy seperator
-typedef struct fuzzyseperator_s
-{
- int index;
- int value;
- int type;
- float weight;
- float minweight;
- float maxweight;
- struct fuzzyseperator_s *child;
- struct fuzzyseperator_s *next;
-} fuzzyseperator_t;
-
-//fuzzy weight
-typedef struct weight_s
-{
- char *name;
- struct fuzzyseperator_s *firstseperator;
-} weight_t;
-
-//weight configuration
-typedef struct weightconfig_s
-{
- int numweights;
- weight_t weights[MAX_WEIGHTS];
- char filename[MAX_QPATH];
-} weightconfig_t;
-
-//reads a weight configuration
-weightconfig_t *ReadWeightConfig(char *filename);
-//free a weight configuration
-void FreeWeightConfig(weightconfig_t *config);
-//writes a weight configuration, returns true if successfull
-qboolean WriteWeightConfig(char *filename, weightconfig_t *config);
-//find the fuzzy weight with the given name
-int FindFuzzyWeight(weightconfig_t *wc, char *name);
-//returns the fuzzy weight for the given inventory and weight
-float FuzzyWeight(int *inventory, weightconfig_t *wc, int weightnum);
-float FuzzyWeightUndecided(int *inventory, weightconfig_t *wc, int weightnum);
-//scales the weight with the given name
-void ScaleWeight(weightconfig_t *config, char *name, float scale);
-//scale the balance range
-void ScaleBalanceRange(weightconfig_t *config, float scale);
-//evolves the weight configuration
-void EvolveWeightConfig(weightconfig_t *config);
-//interbreed the weight configurations and stores the interbreeded one in configout
-void InterbreedWeightConfigs(weightconfig_t *config1, weightconfig_t *config2, weightconfig_t *configout);
-//frees cached weight configurations
-void BotShutdownWeights(void);
diff --git a/game/code/botlib/be_ea.h b/game/code/botlib/be_ea.h
deleted file mode 100644
index 4fb3704..0000000
--- a/game/code/botlib/be_ea.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: be_ea.h
- *
- * desc: elementary actions
- *
- * $Archive: /source/code/botlib/be_ea.h $
- *
- *****************************************************************************/
-
-//ClientCommand elementary actions
-void EA_Say(int client, char *str);
-void EA_SayTeam(int client, char *str);
-void EA_Command(int client, char *command );
-
-void EA_Action(int client, int action);
-void EA_Crouch(int client);
-void EA_Walk(int client);
-void EA_MoveUp(int client);
-void EA_MoveDown(int client);
-void EA_MoveForward(int client);
-void EA_MoveBack(int client);
-void EA_MoveLeft(int client);
-void EA_MoveRight(int client);
-void EA_Attack(int client);
-void EA_Respawn(int client);
-void EA_Talk(int client);
-void EA_Gesture(int client);
-void EA_Use(int client);
-
-//regular elementary actions
-void EA_SelectWeapon(int client, int weapon);
-void EA_Jump(int client);
-void EA_DelayedJump(int client);
-void EA_Move(int client, vec3_t dir, float speed);
-void EA_View(int client, vec3_t viewangles);
-
-//send regular input to the server
-void EA_EndRegular(int client, float thinktime);
-void EA_GetInput(int client, float thinktime, bot_input_t *input);
-void EA_ResetInput(int client);
-//setup and shutdown routines
-int EA_Setup(void);
-void EA_Shutdown(void);
diff --git a/game/code/botlib/l_crc.h b/game/code/botlib/l_crc.h
deleted file mode 100644
index f9c7e37..0000000
--- a/game/code/botlib/l_crc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-typedef unsigned short crc_t;
-
-void CRC_Init(unsigned short *crcvalue);
-void CRC_ProcessByte(unsigned short *crcvalue, byte data);
-unsigned short CRC_Value(unsigned short crcvalue);
-unsigned short CRC_ProcessString(unsigned char *data, int length);
-void CRC_ContinueProcessString(unsigned short *crc, char *data, int length);
diff --git a/game/code/botlib/l_libvar.h b/game/code/botlib/l_libvar.h
deleted file mode 100644
index d96685f..0000000
--- a/game/code/botlib/l_libvar.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: l_libvar.h
- *
- * desc: botlib vars
- *
- * $Archive: /source/code/botlib/l_libvar.h $
- *
- *****************************************************************************/
-
-//library variable
-typedef struct libvar_s
-{
- char *name;
- char *string;
- int flags;
- qboolean modified; // set each time the cvar is changed
- float value;
- struct libvar_s *next;
-} libvar_t;
-
-//removes all library variables
-void LibVarDeAllocAll(void);
-//gets the library variable with the given name
-libvar_t *LibVarGet(char *var_name);
-//gets the string of the library variable with the given name
-char *LibVarGetString(char *var_name);
-//gets the value of the library variable with the given name
-float LibVarGetValue(char *var_name);
-//creates the library variable if not existing already and returns it
-libvar_t *LibVar(char *var_name, char *value);
-//creates the library variable if not existing already and returns the value
-float LibVarValue(char *var_name, char *value);
-//creates the library variable if not existing already and returns the value string
-char *LibVarString(char *var_name, char *value);
-//sets the library variable
-void LibVarSet(char *var_name, char *value);
-//returns true if the library variable has been modified
-qboolean LibVarChanged(char *var_name);
-//sets the library variable to unmodified
-void LibVarSetNotModified(char *var_name);
-
diff --git a/game/code/botlib/l_log.h b/game/code/botlib/l_log.h
deleted file mode 100644
index 3ddb464..0000000
--- a/game/code/botlib/l_log.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: l_log.h
- *
- * desc: log file
- *
- * $Archive: /source/code/botlib/l_log.h $
- *
- *****************************************************************************/
-
-//open a log file
-void Log_Open(char *filename);
-//close the current log file
-void Log_Close(void);
-//close log file if present
-void Log_Shutdown(void);
-//write to the current opened log file
-void QDECL Log_Write(char *fmt, ...);
-//write to the current opened log file with a time stamp
-void QDECL Log_WriteTimeStamped(char *fmt, ...);
-//returns a pointer to the log file
-FILE *Log_FilePointer(void);
-//flush log file
-void Log_Flush(void);
-
diff --git a/game/code/botlib/l_memory.h b/game/code/botlib/l_memory.h
deleted file mode 100644
index 17c89d5..0000000
--- a/game/code/botlib/l_memory.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: l_memory.h
- *
- * desc: memory management
- *
- * $Archive: /source/code/botlib/l_memory.h $
- *
- *****************************************************************************/
-
-//#define MEMDEBUG
-
-#ifdef MEMDEBUG
-#define GetMemory(size) GetMemoryDebug(size, #size, __FILE__, __LINE__);
-#define GetClearedMemory(size) GetClearedMemoryDebug(size, #size, __FILE__, __LINE__);
-//allocate a memory block of the given size
-void *GetMemoryDebug(unsigned long size, char *label, char *file, int line);
-//allocate a memory block of the given size and clear it
-void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line);
-//
-#define GetHunkMemory(size) GetHunkMemoryDebug(size, #size, __FILE__, __LINE__);
-#define GetClearedHunkMemory(size) GetClearedHunkMemoryDebug(size, #size, __FILE__, __LINE__);
-//allocate a memory block of the given size
-void *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line);
-//allocate a memory block of the given size and clear it
-void *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line);
-#else
-//allocate a memory block of the given size
-void *GetMemory(unsigned long size);
-//allocate a memory block of the given size and clear it
-void *GetClearedMemory(unsigned long size);
-//
-#ifdef BSPC
-#define GetHunkMemory GetMemory
-#define GetClearedHunkMemory GetClearedMemory
-#else
-//allocate a memory block of the given size
-void *GetHunkMemory(unsigned long size);
-//allocate a memory block of the given size and clear it
-void *GetClearedHunkMemory(unsigned long size);
-#endif
-#endif
-
-//free the given memory block
-void FreeMemory(void *ptr);
-//returns the amount available memory
-int AvailableMemory(void);
-//prints the total used memory size
-void PrintUsedMemorySize(void);
-//print all memory blocks with label
-void PrintMemoryLabels(void);
-//returns the size of the memory block in bytes
-int MemoryByteSize(void *ptr);
-//free all allocated memory
-void DumpMemory(void);
diff --git a/game/code/botlib/l_precomp.h b/game/code/botlib/l_precomp.h
deleted file mode 100644
index fcc0e8a..0000000
--- a/game/code/botlib/l_precomp.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: l_precomp.h
- *
- * desc: pre compiler
- *
- * $Archive: /source/code/botlib/l_precomp.h $
- *
- *****************************************************************************/
-
-#ifndef MAX_PATH
- #define MAX_PATH MAX_QPATH
-#endif
-
-#ifndef PATH_SEPERATORSTR
- #if defined(WIN32)|defined(_WIN32)|defined(__NT__)|defined(__WINDOWS__)|defined(__WINDOWS_386__)
- #define PATHSEPERATOR_STR "\\"
- #else
- #define PATHSEPERATOR_STR "/"
- #endif
-#endif
-#ifndef PATH_SEPERATORCHAR
- #if defined(WIN32)|defined(_WIN32)|defined(__NT__)|defined(__WINDOWS__)|defined(__WINDOWS_386__)
- #define PATHSEPERATOR_CHAR '\\'
- #else
- #define PATHSEPERATOR_CHAR '/'
- #endif
-#endif
-
-#if defined(BSPC) && !defined(QDECL)
-#define QDECL
-#endif
-
-
-#define DEFINE_FIXED 0x0001
-
-#define BUILTIN_LINE 1
-#define BUILTIN_FILE 2
-#define BUILTIN_DATE 3
-#define BUILTIN_TIME 4
-#define BUILTIN_STDC 5
-
-#define INDENT_IF 0x0001
-#define INDENT_ELSE 0x0002
-#define INDENT_ELIF 0x0004
-#define INDENT_IFDEF 0x0008
-#define INDENT_IFNDEF 0x0010
-
-//macro definitions
-typedef struct define_s
-{
- char *name; //define name
- int flags; //define flags
- int builtin; // > 0 if builtin define
- int numparms; //number of define parameters
- token_t *parms; //define parameters
- token_t *tokens; //macro tokens (possibly containing parm tokens)
- struct define_s *next; //next defined macro in a list
- struct define_s *hashnext; //next define in the hash chain
-} define_t;
-
-//indents
-//used for conditional compilation directives:
-//#if, #else, #elif, #ifdef, #ifndef
-typedef struct indent_s
-{
- int type; //indent type
- int skip; //true if skipping current indent
- script_t *script; //script the indent was in
- struct indent_s *next; //next indent on the indent stack
-} indent_t;
-
-//source file
-typedef struct source_s
-{
- char filename[1024]; //file name of the script
- char includepath[1024]; //path to include files
- punctuation_t *punctuations; //punctuations to use
- script_t *scriptstack; //stack with scripts of the source
- token_t *tokens; //tokens to read first
- define_t *defines; //list with macro definitions
- define_t **definehash; //hash chain with defines
- indent_t *indentstack; //stack with indents
- int skip; // > 0 if skipping conditional code
- token_t token; //last read token
-} source_t;
-
-
-//read a token from the source
-int PC_ReadToken(source_t *source, token_t *token);
-//expect a certain token
-int PC_ExpectTokenString(source_t *source, char *string);
-//expect a certain token type
-int PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token);
-//expect a token
-int PC_ExpectAnyToken(source_t *source, token_t *token);
-//returns true when the token is available
-int PC_CheckTokenString(source_t *source, char *string);
-//returns true an reads the token when a token with the given type is available
-int PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token);
-//skip tokens until the given token string is read
-int PC_SkipUntilString(source_t *source, char *string);
-//unread the last token read from the script
-void PC_UnreadLastToken(source_t *source);
-//unread the given token
-void PC_UnreadToken(source_t *source, token_t *token);
-//read a token only if on the same line, lines are concatenated with a slash
-int PC_ReadLine(source_t *source, token_t *token);
-//returns true if there was a white space in front of the token
-int PC_WhiteSpaceBeforeToken(token_t *token);
-//add a define to the source
-int PC_AddDefine(source_t *source, char *string);
-//add a globals define that will be added to all opened sources
-int PC_AddGlobalDefine(char *string);
-//remove the given global define
-int PC_RemoveGlobalDefine(char *name);
-//remove all globals defines
-void PC_RemoveAllGlobalDefines(void);
-//add builtin defines
-void PC_AddBuiltinDefines(source_t *source);
-//set the source include path
-void PC_SetIncludePath(source_t *source, char *path);
-//set the punction set
-void PC_SetPunctuations(source_t *source, punctuation_t *p);
-//set the base folder to load files from
-void PC_SetBaseFolder(char *path);
-//load a source file
-source_t *LoadSourceFile(const char *filename);
-//load a source from memory
-source_t *LoadSourceMemory(char *ptr, int length, char *name);
-//free the given source
-void FreeSource(source_t *source);
-//print a source error
-void QDECL SourceError(source_t *source, char *str, ...);
-//print a source warning
-void QDECL SourceWarning(source_t *source, char *str, ...);
-
-#ifdef BSPC
-// some of BSPC source does include game/q_shared.h and some does not
-// we define pc_token_s pc_token_t if needed (yes, it's ugly)
-#ifndef __Q_SHARED_H
-#define MAX_TOKENLENGTH 1024
-typedef struct pc_token_s
-{
- int type;
- int subtype;
- int intvalue;
- float floatvalue;
- char string[MAX_TOKENLENGTH];
-} pc_token_t;
-#endif //!_Q_SHARED_H
-#endif //BSPC
-
-//
-int PC_LoadSourceHandle(const char *filename);
-int PC_FreeSourceHandle(int handle);
-int PC_ReadTokenHandle(int handle, pc_token_t *pc_token);
-int PC_SourceFileAndLine(int handle, char *filename, int *line);
-void PC_CheckOpenSourceHandles(void);
diff --git a/game/code/botlib/l_script.h b/game/code/botlib/l_script.h
deleted file mode 100644
index ceb0469..0000000
--- a/game/code/botlib/l_script.h
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: l_script.h
- *
- * desc: lexicographical parser
- *
- * $Archive: /source/code/botlib/l_script.h $
- *
- *****************************************************************************/
-
-//undef if binary numbers of the form 0b... or 0B... are not allowed
-#define BINARYNUMBERS
-//undef if not using the token.intvalue and token.floatvalue
-#define NUMBERVALUE
-//use dollar sign also as punctuation
-#define DOLLAR
-
-//maximum token length
-#define MAX_TOKEN 1024
-
-#if defined(BSPC) && !defined(QDECL)
-#define QDECL
-#endif
-
-
-//script flags
-#define SCFL_NOERRORS 0x0001
-#define SCFL_NOWARNINGS 0x0002
-#define SCFL_NOSTRINGWHITESPACES 0x0004
-#define SCFL_NOSTRINGESCAPECHARS 0x0008
-#define SCFL_PRIMITIVE 0x0010
-#define SCFL_NOBINARYNUMBERS 0x0020
-#define SCFL_NONUMBERVALUES 0x0040
-
-//token types
-#define TT_STRING 1 // string
-#define TT_LITERAL 2 // literal
-#define TT_NUMBER 3 // number
-#define TT_NAME 4 // name
-#define TT_PUNCTUATION 5 // punctuation
-
-//string sub type
-//---------------
-// the length of the string
-//literal sub type
-//----------------
-// the ASCII code of the literal
-//number sub type
-//---------------
-#define TT_DECIMAL 0x0008 // decimal number
-#define TT_HEX 0x0100 // hexadecimal number
-#define TT_OCTAL 0x0200 // octal number
-#ifdef BINARYNUMBERS
-#define TT_BINARY 0x0400 // binary number
-#endif //BINARYNUMBERS
-#define TT_FLOAT 0x0800 // floating point number
-#define TT_INTEGER 0x1000 // integer number
-#define TT_LONG 0x2000 // long number
-#define TT_UNSIGNED 0x4000 // unsigned number
-//punctuation sub type
-//--------------------
-#define P_RSHIFT_ASSIGN 1
-#define P_LSHIFT_ASSIGN 2
-#define P_PARMS 3
-#define P_PRECOMPMERGE 4
-
-#define P_LOGIC_AND 5
-#define P_LOGIC_OR 6
-#define P_LOGIC_GEQ 7
-#define P_LOGIC_LEQ 8
-#define P_LOGIC_EQ 9
-#define P_LOGIC_UNEQ 10
-
-#define P_MUL_ASSIGN 11
-#define P_DIV_ASSIGN 12
-#define P_MOD_ASSIGN 13
-#define P_ADD_ASSIGN 14
-#define P_SUB_ASSIGN 15
-#define P_INC 16
-#define P_DEC 17
-
-#define P_BIN_AND_ASSIGN 18
-#define P_BIN_OR_ASSIGN 19
-#define P_BIN_XOR_ASSIGN 20
-#define P_RSHIFT 21
-#define P_LSHIFT 22
-
-#define P_POINTERREF 23
-#define P_CPP1 24
-#define P_CPP2 25
-#define P_MUL 26
-#define P_DIV 27
-#define P_MOD 28
-#define P_ADD 29
-#define P_SUB 30
-#define P_ASSIGN 31
-
-#define P_BIN_AND 32
-#define P_BIN_OR 33
-#define P_BIN_XOR 34
-#define P_BIN_NOT 35
-
-#define P_LOGIC_NOT 36
-#define P_LOGIC_GREATER 37
-#define P_LOGIC_LESS 38
-
-#define P_REF 39
-#define P_COMMA 40
-#define P_SEMICOLON 41
-#define P_COLON 42
-#define P_QUESTIONMARK 43
-
-#define P_PARENTHESESOPEN 44
-#define P_PARENTHESESCLOSE 45
-#define P_BRACEOPEN 46
-#define P_BRACECLOSE 47
-#define P_SQBRACKETOPEN 48
-#define P_SQBRACKETCLOSE 49
-#define P_BACKSLASH 50
-
-#define P_PRECOMP 51
-#define P_DOLLAR 52
-//name sub type
-//-------------
-// the length of the name
-
-//punctuation
-typedef struct punctuation_s
-{
- char *p; //punctuation character(s)
- int n; //punctuation indication
- struct punctuation_s *next; //next punctuation
-} punctuation_t;
-
-//token
-typedef struct token_s
-{
- char string[MAX_TOKEN]; //available token
- int type; //last read token type
- int subtype; //last read token sub type
-#ifdef NUMBERVALUE
- unsigned long int intvalue; //integer value
- float floatvalue; //floating point value
-#endif //NUMBERVALUE
- char *whitespace_p; //start of white space before token
- char *endwhitespace_p; //start of white space before token
- int line; //line the token was on
- int linescrossed; //lines crossed in white space
- struct token_s *next; //next token in chain
-} token_t;
-
-//script file
-typedef struct script_s
-{
- char filename[1024]; //file name of the script
- char *buffer; //buffer containing the script
- char *script_p; //current pointer in the script
- char *end_p; //pointer to the end of the script
- char *lastscript_p; //script pointer before reading token
- char *whitespace_p; //begin of the white space
- char *endwhitespace_p; //end of the white space
- int length; //length of the script in bytes
- int line; //current line in script
- int lastline; //line before reading token
- int tokenavailable; //set by UnreadLastToken
- int flags; //several script flags
- punctuation_t *punctuations; //the punctuations used in the script
- punctuation_t **punctuationtable;
- token_t token; //available token
- struct script_s *next; //next script in a chain
-} script_t;
-
-//read a token from the script
-int PS_ReadToken(script_t *script, token_t *token);
-//expect a certain token
-int PS_ExpectTokenString(script_t *script, char *string);
-//expect a certain token type
-int PS_ExpectTokenType(script_t *script, int type, int subtype, token_t *token);
-//expect a token
-int PS_ExpectAnyToken(script_t *script, token_t *token);
-//returns true when the token is available
-int PS_CheckTokenString(script_t *script, char *string);
-//returns true an reads the token when a token with the given type is available
-int PS_CheckTokenType(script_t *script, int type, int subtype, token_t *token);
-//skip tokens until the given token string is read
-int PS_SkipUntilString(script_t *script, char *string);
-//unread the last token read from the script
-void PS_UnreadLastToken(script_t *script);
-//unread the given token
-void PS_UnreadToken(script_t *script, token_t *token);
-//returns the next character of the read white space, returns NULL if none
-char PS_NextWhiteSpaceChar(script_t *script);
-//remove any leading and trailing double quotes from the token
-void StripDoubleQuotes(char *string);
-//remove any leading and trailing single quotes from the token
-void StripSingleQuotes(char *string);
-//read a possible signed integer
-signed long int ReadSignedInt(script_t *script);
-//read a possible signed floating point number
-float ReadSignedFloat(script_t *script);
-//set an array with punctuations, NULL restores default C/C++ set
-void SetScriptPunctuations(script_t *script, punctuation_t *p);
-//set script flags
-void SetScriptFlags(script_t *script, int flags);
-//get script flags
-int GetScriptFlags(script_t *script);
-//reset a script
-void ResetScript(script_t *script);
-//returns true if at the end of the script
-int EndOfScript(script_t *script);
-//returns a pointer to the punctuation with the given number
-char *PunctuationFromNum(script_t *script, int num);
-//load a script from the given file at the given offset with the given length
-script_t *LoadScriptFile(const char *filename);
-//load a script from the given memory with the given length
-script_t *LoadScriptMemory(char *ptr, int length, char *name);
-//free a script
-void FreeScript(script_t *script);
-//set the base folder to load files from
-void PS_SetBaseFolder(char *path);
-//print a script error with filename and line number
-void QDECL ScriptError(script_t *script, char *str, ...);
-//print a script warning with filename and line number
-void QDECL ScriptWarning(script_t *script, char *str, ...);
-
-
diff --git a/game/code/botlib/l_struct.h b/game/code/botlib/l_struct.h
deleted file mode 100644
index e2c6b03..0000000
--- a/game/code/botlib/l_struct.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: l_struct.h
- *
- * desc: structure reading/writing
- *
- * $Archive: /source/code/botlib/l_struct.h $
- *
- *****************************************************************************/
-
-
-#define MAX_STRINGFIELD 80
-//field types
-#define FT_CHAR 1 // char
-#define FT_INT 2 // int
-#define FT_FLOAT 3 // float
-#define FT_STRING 4 // char [MAX_STRINGFIELD]
-#define FT_STRUCT 6 // struct (sub structure)
-//type only mask
-#define FT_TYPE 0x00FF // only type, clear subtype
-//sub types
-#define FT_ARRAY 0x0100 // array of type
-#define FT_BOUNDED 0x0200 // bounded value
-#define FT_UNSIGNED 0x0400
-
-//structure field definition
-typedef struct fielddef_s
-{
- char *name; //name of the field
- int offset; //offset in the structure
- int type; //type of the field
- //type specific fields
- int maxarray; //maximum array size
- float floatmin, floatmax; //float min and max
- struct structdef_s *substruct; //sub structure
-} fielddef_t;
-
-//structure definition
-typedef struct structdef_s
-{
- int size;
- fielddef_t *fields;
-} structdef_t;
-
-//read a structure from a script
-int ReadStructure(source_t *source, structdef_t *def, char *structure);
-//write a structure to a file
-int WriteStructure(FILE *fp, structdef_t *def, char *structure);
-//writes indents
-int WriteIndent(FILE *fp, int indent);
-//writes a float without traling zeros
-int WriteFloat(FILE *fp, float value);
-
-
diff --git a/game/code/botlib/l_utils.h b/game/code/botlib/l_utils.h
deleted file mode 100644
index 6944d06..0000000
--- a/game/code/botlib/l_utils.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: l_util.h
- *
- * desc: utils
- *
- * $Archive: /source/code/botlib/l_util.h $
- *
- *****************************************************************************/
-
-#define Vector2Angles(v,a) vectoangles(v,a)
-#ifndef MAX_PATH
-#define MAX_PATH MAX_QPATH
-#endif
-#define Maximum(x,y) (x > y ? x : y)
-#define Minimum(x,y) (x < y ? x : y)
diff --git a/game/code/botlib/lcc.mak b/game/code/botlib/lcc.mak
deleted file mode 100644
index f5567c3..0000000
--- a/game/code/botlib/lcc.mak
+++ /dev/null
@@ -1,55 +0,0 @@
-#
-# Makefile for Gladiator Bot library: gladiator.dll
-# Intended for LCC-Win32
-#
-
-CC=lcc
-CFLAGS=-DC_ONLY -o
-OBJS= be_aas_bspq2.obj \
- be_aas_bsphl.obj \
- be_aas_cluster.obj \
- be_aas_debug.obj \
- be_aas_entity.obj \
- be_aas_file.obj \
- be_aas_light.obj \
- be_aas_main.obj \
- be_aas_move.obj \
- be_aas_optimize.obj \
- be_aas_reach.obj \
- be_aas_route.obj \
- be_aas_routealt.obj \
- be_aas_sample.obj \
- be_aas_sound.obj \
- be_ai2_dm.obj \
- be_ai2_dmnet.obj \
- be_ai2_main.obj \
- be_ai_char.obj \
- be_ai_chat.obj \
- be_ai_goal.obj \
- be_ai_load.obj \
- be_ai_move.obj \
- be_ai_weap.obj \
- be_ai_weight.obj \
- be_ea.obj \
- be_interface.obj \
- l_crc.obj \
- l_libvar.obj \
- l_log.obj \
- l_memory.obj \
- l_precomp.obj \
- l_script.obj \
- l_struct.obj \
- l_utils.obj \
- q_shared.obj
-
-all: gladiator.dll
-
-gladiator.dll: $(OBJS)
- lcclnk -dll -entry GetBotAPI *.obj botlib.def -o gladiator.dll
-
-clean:
- del *.obj gladiator.dll
-
-%.obj: %.c
- $(CC) $(CFLAGS) $<
-
diff --git a/game/code/botlib/linux-i386.mak b/game/code/botlib/linux-i386.mak
deleted file mode 100644
index c9607a7..0000000
--- a/game/code/botlib/linux-i386.mak
+++ /dev/null
@@ -1,92 +0,0 @@
-#
-# Makefile for Gladiator Bot library: gladiator.so
-# Intended for gcc/Linux
-#
-
-ARCH=i386
-CC=gcc
-BASE_CFLAGS=-Dstricmp=strcasecmp
-
-#use these cflags to optimize it
-CFLAGS=$(BASE_CFLAGS) -m486 -O6 -ffast-math -funroll-loops \
- -fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \
- -malign-jumps=2 -malign-functions=2
-#use these when debugging
-#CFLAGS=$(BASE_CFLAGS) -g
-
-LDFLAGS=-ldl -lm
-SHLIBEXT=so
-SHLIBCFLAGS=-fPIC
-SHLIBLDFLAGS=-shared
-
-DO_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
-
-#############################################################################
-# SETUP AND BUILD
-# GLADIATOR BOT
-#############################################################################
-
-.c.o:
- $(DO_CC)
-
-GAME_OBJS = \
- be_aas_bsphl.o\
- be_aas_bspq2.o\
- be_aas_cluster.o\
- be_aas_debug.o\
- be_aas_entity.o\
- be_aas_file.o\
- be_aas_light.o\
- be_aas_main.o\
- be_aas_move.o\
- be_aas_optimize.o\
- be_aas_reach.o\
- be_aas_route.o\
- be_aas_routealt.o\
- be_aas_sample.o\
- be_aas_sound.o\
- be_ai2_dmq2.o\
- be_ai2_dmhl.o\
- be_ai2_dmnet.o\
- be_ai2_main.o\
- be_ai_char.o\
- be_ai_chat.o\
- be_ai_goal.o\
- be_ai_load.o\
- be_ai_move.o\
- be_ai_weap.o\
- be_ai_weight.o\
- be_ea.o\
- be_interface.o\
- l_crc.o\
- l_libvar.o\
- l_log.o\
- l_memory.o\
- l_precomp.o\
- l_script.o\
- l_struct.o\
- l_utils.o\
- q_shared.o
-
-glad$(ARCH).$(SHLIBEXT) : $(GAME_OBJS)
- $(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(GAME_OBJS)
-
-
-#############################################################################
-# MISC
-#############################################################################
-
-clean:
- -rm -f $(GAME_OBJS)
-
-depend:
- gcc -MM $(GAME_OBJS:.o=.c)
-
-
-install:
- cp gladiator.so ..
-
-#
-# From "make depend"
-#
-
diff --git a/game/code/cgame/cg_consolecmds.c b/game/code/cgame/cg_consolecmds.c
deleted file mode 100644
index e966422..0000000
--- a/game/code/cgame/cg_consolecmds.c
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_consolecmds.c -- text commands typed in at the local console, or
-// executed by a key binding
-
-#include "cg_local.h"
-#include "../ui/ui_shared.h"
-#ifdef MISSIONPACK
-extern menuDef_t *menuScoreboard;
-#endif
-
-void CG_PrintClientNumbers( void ) {
- int i;
-
- CG_Printf( "slot score ping name\n" );
- CG_Printf( "---- ----- ---- ----\n" );
-
- for(i=0;i<cg.numScores;i++) {
- CG_Printf("%-4d",cg.scores[i].client);
-
- CG_Printf(" %-5d",cg.scores[i].score);
-
- CG_Printf(" %-4d",cg.scores[i].ping);
-
- CG_Printf(" %s\n",cgs.clientinfo[cg.scores[i].client].name);
- }
-}
-
-void CG_TargetCommand_f( void ) {
- int targetNum;
- char test[4];
-
- targetNum = CG_CrosshairPlayer();
- if (!targetNum ) {
- return;
- }
-
- trap_Argv( 1, test, 4 );
- trap_SendConsoleCommand( va( "gc %i %i", targetNum, atoi( test ) ) );
-}
-
-
-
-/*
-=================
-CG_SizeUp_f
-
-Keybinding command
-=================
-*/
-static void CG_SizeUp_f (void) {
- trap_Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize.integer+10)));
-}
-
-
-/*
-=================
-CG_SizeDown_f
-
-Keybinding command
-=================
-*/
-static void CG_SizeDown_f (void) {
- trap_Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize.integer-10)));
-}
-
-
-/*
-=============
-CG_Viewpos_f
-
-Debugging command to print the current position
-=============
-*/
-static void CG_Viewpos_f (void) {
- CG_Printf ("(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0],
- (int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2],
- (int)cg.refdefViewAngles[YAW]);
-}
-
-
-static void CG_ScoresDown_f( void ) {
-
-#ifdef MISSIONPACK
- CG_BuildSpectatorString();
-#endif
- if ( cg.scoresRequestTime + 2000 < cg.time ) {
- // the scores are more than two seconds out of data,
- // so request new ones
- cg.scoresRequestTime = cg.time;
- trap_SendClientCommand( "score" );
-
- // leave the current scores up if they were already
- // displayed, but if this is the first hit, clear them out
- if ( !cg.showScores ) {
- cg.showScores = qtrue;
- cg.numScores = 0;
- }
- } else {
- // show the cached contents even if they just pressed if it
- // is within two seconds
- cg.showScores = qtrue;
- }
-}
-
-static void CG_ScoresUp_f( void ) {
- if ( cg.showScores ) {
- cg.showScores = qfalse;
- cg.scoreFadeTime = cg.time;
- }
-}
-
-#ifdef MISSIONPACK
-extern menuDef_t *menuScoreboard;
-void Menu_Reset( void ); // FIXME: add to right include file
-
-static void CG_LoadHud_f( void) {
- char buff[1024];
- const char *hudSet;
- memset(buff, 0, sizeof(buff));
-
- String_Init();
- Menu_Reset();
-
- trap_Cvar_VariableStringBuffer("cg_hudFiles", buff, sizeof(buff));
- hudSet = buff;
- if (hudSet[0] == '\0') {
- hudSet = "ui/hud.txt";
- }
-
- CG_LoadMenus(hudSet);
- menuScoreboard = NULL;
-}
-
-
-static void CG_scrollScoresDown_f( void) {
- if (menuScoreboard && cg.scoreBoardShowing) {
- Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qtrue);
- Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qtrue);
- Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qtrue);
- }
-}
-
-
-static void CG_scrollScoresUp_f( void) {
- if (menuScoreboard && cg.scoreBoardShowing) {
- Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qfalse);
- Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qfalse);
- Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qfalse);
- }
-}
-
-
-static void CG_spWin_f( void) {
- trap_Cvar_Set("cg_cameraOrbit", "2");
- trap_Cvar_Set("cg_cameraOrbitDelay", "35");
- trap_Cvar_Set("cg_thirdPerson", "1");
- trap_Cvar_Set("cg_thirdPersonAngle", "0");
- trap_Cvar_Set("cg_thirdPersonRange", "100");
- CG_AddBufferedSound(cgs.media.winnerSound);
- //trap_S_StartLocalSound(cgs.media.winnerSound, CHAN_ANNOUNCER);
- CG_CenterPrint("YOU WIN!", SCREEN_HEIGHT * .30, 0);
-}
-
-static void CG_spLose_f( void) {
- trap_Cvar_Set("cg_cameraOrbit", "2");
- trap_Cvar_Set("cg_cameraOrbitDelay", "35");
- trap_Cvar_Set("cg_thirdPerson", "1");
- trap_Cvar_Set("cg_thirdPersonAngle", "0");
- trap_Cvar_Set("cg_thirdPersonRange", "100");
- CG_AddBufferedSound(cgs.media.loserSound);
- //trap_S_StartLocalSound(cgs.media.loserSound, CHAN_ANNOUNCER);
- CG_CenterPrint("YOU LOSE...", SCREEN_HEIGHT * .30, 0);
-}
-
-#endif
-
-static void CG_TellTarget_f( void ) {
- int clientNum;
- char command[128];
- char message[128];
-
- clientNum = CG_CrosshairPlayer();
- if ( clientNum == -1 ) {
- return;
- }
-
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "tell %i %s", clientNum, message );
- trap_SendClientCommand( command );
-}
-
-static void CG_TellAttacker_f( void ) {
- int clientNum;
- char command[128];
- char message[128];
-
- clientNum = CG_LastAttacker();
- if ( clientNum == -1 ) {
- return;
- }
-
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "tell %i %s", clientNum, message );
- trap_SendClientCommand( command );
-}
-
-static void CG_VoiceTellTarget_f( void ) {
- int clientNum;
- char command[128];
- char message[128];
-
- clientNum = CG_CrosshairPlayer();
- if ( clientNum == -1 ) {
- return;
- }
-
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "vtell %i %s", clientNum, message );
- trap_SendClientCommand( command );
-}
-
-static void CG_VoiceTellAttacker_f( void ) {
- int clientNum;
- char command[128];
- char message[128];
-
- clientNum = CG_LastAttacker();
- if ( clientNum == -1 ) {
- return;
- }
-
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "vtell %i %s", clientNum, message );
- trap_SendClientCommand( command );
-}
-
-#ifdef MISSIONPACK
-static void CG_NextTeamMember_f( void ) {
- CG_SelectNextPlayer();
-}
-
-static void CG_PrevTeamMember_f( void ) {
- CG_SelectPrevPlayer();
-}
-
-// ASS U ME's enumeration order as far as task specific orders, OFFENSE is zero, CAMP is last
-//
-static void CG_NextOrder_f( void ) {
- clientInfo_t *ci = cgs.clientinfo + cg.snap->ps.clientNum;
- if (ci) {
- if (!ci->teamLeader && sortedTeamPlayers[cg_currentSelectedPlayer.integer] != cg.snap->ps.clientNum) {
- return;
- }
- }
- if (cgs.currentOrder < TEAMTASK_CAMP) {
- cgs.currentOrder++;
-
- if (cgs.currentOrder == TEAMTASK_RETRIEVE) {
- if (!CG_OtherTeamHasFlag()) {
- cgs.currentOrder++;
- }
- }
-
- if (cgs.currentOrder == TEAMTASK_ESCORT) {
- if (!CG_YourTeamHasFlag()) {
- cgs.currentOrder++;
- }
- }
-
- } else {
- cgs.currentOrder = TEAMTASK_OFFENSE;
- }
- cgs.orderPending = qtrue;
- cgs.orderTime = cg.time + 3000;
-}
-
-
-static void CG_ConfirmOrder_f (void ) {
- trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_YES));
- trap_SendConsoleCommand("+button5; wait; -button5");
- if (cg.time < cgs.acceptOrderTime) {
- trap_SendClientCommand(va("teamtask %d\n", cgs.acceptTask));
- cgs.acceptOrderTime = 0;
- }
-}
-
-static void CG_DenyOrder_f (void ) {
- trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_NO));
- trap_SendConsoleCommand("+button6; wait; -button6");
- if (cg.time < cgs.acceptOrderTime) {
- cgs.acceptOrderTime = 0;
- }
-}
-
-static void CG_TaskOffense_f (void ) {
- if (cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION || cgs.gametype == GT_1FCTF) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONGETFLAG));
- } else {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONOFFENSE));
- }
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_OFFENSE));
-}
-
-static void CG_TaskDefense_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONDEFENSE));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_DEFENSE));
-}
-
-static void CG_TaskPatrol_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONPATROL));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_PATROL));
-}
-
-static void CG_TaskCamp_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONCAMPING));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_CAMP));
-}
-
-static void CG_TaskFollow_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOW));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_FOLLOW));
-}
-
-static void CG_TaskRetrieve_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONRETURNFLAG));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_RETRIEVE));
-}
-
-static void CG_TaskEscort_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOWCARRIER));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_ESCORT));
-}
-
-static void CG_TaskOwnFlag_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_IHAVEFLAG));
-}
-
-static void CG_TauntKillInsult_f (void ) {
- trap_SendConsoleCommand("cmd vsay kill_insult\n");
-}
-
-static void CG_TauntPraise_f (void ) {
- trap_SendConsoleCommand("cmd vsay praise\n");
-}
-
-static void CG_TauntTaunt_f (void ) {
- trap_SendConsoleCommand("cmd vtaunt\n");
-}
-
-static void CG_TauntDeathInsult_f (void ) {
- trap_SendConsoleCommand("cmd vsay death_insult\n");
-}
-
-static void CG_TauntGauntlet_f (void ) {
- trap_SendConsoleCommand("cmd vsay kill_guantlet\n");
-}
-
-static void CG_TaskSuicide_f (void ) {
- int clientNum;
- char command[128];
-
- clientNum = CG_CrosshairPlayer();
- if ( clientNum == -1 ) {
- return;
- }
-
- Com_sprintf( command, 128, "tell %i suicide", clientNum );
- trap_SendClientCommand( command );
-}
-
-
-
-/*
-==================
-CG_TeamMenu_f
-==================
-*/
-/*
-static void CG_TeamMenu_f( void ) {
- if (trap_Key_GetCatcher() & KEYCATCH_CGAME) {
- CG_EventHandling(CGAME_EVENT_NONE);
- trap_Key_SetCatcher(0);
- } else {
- CG_EventHandling(CGAME_EVENT_TEAMMENU);
- //trap_Key_SetCatcher(KEYCATCH_CGAME);
- }
-}
-*/
-
-/*
-==================
-CG_EditHud_f
-==================
-*/
-/*
-static void CG_EditHud_f( void ) {
- //cls.keyCatchers ^= KEYCATCH_CGAME;
- //VM_Call (cgvm, CG_EVENT_HANDLING, (cls.keyCatchers & KEYCATCH_CGAME) ? CGAME_EVENT_EDITHUD : CGAME_EVENT_NONE);
-}
-*/
-
-#endif
-
-/*
-==================
-CG_StartOrbit_f
-==================
-*/
-
-static void CG_StartOrbit_f( void ) {
- char var[MAX_TOKEN_CHARS];
-
- trap_Cvar_VariableStringBuffer( "developer", var, sizeof( var ) );
- if ( !atoi(var) ) {
- return;
- }
- if (cg_cameraOrbit.value != 0) {
- trap_Cvar_Set ("cg_cameraOrbit", "0");
- trap_Cvar_Set("cg_thirdPerson", "0");
- } else {
- trap_Cvar_Set("cg_cameraOrbit", "5");
- trap_Cvar_Set("cg_thirdPerson", "1");
- trap_Cvar_Set("cg_thirdPersonAngle", "0");
- trap_Cvar_Set("cg_thirdPersonRange", "100");
- }
-}
-
-/*
-static void CG_Camera_f( void ) {
- char name[1024];
- trap_Argv( 1, name, sizeof(name));
- if (trap_loadCamera(name)) {
- cg.cameraMode = qtrue;
- trap_startCamera(cg.time);
- } else {
- CG_Printf ("Unable to load camera %s\n",name);
- }
-}
-*/
-
-
-typedef struct {
- char *cmd;
- void (*function)(void);
-} consoleCommand_t;
-
-static consoleCommand_t commands[] = {
- { "testgun", CG_TestGun_f },
- { "testmodel", CG_TestModel_f },
- { "nextframe", CG_TestModelNextFrame_f },
- { "prevframe", CG_TestModelPrevFrame_f },
- { "nextskin", CG_TestModelNextSkin_f },
- { "prevskin", CG_TestModelPrevSkin_f },
- { "viewpos", CG_Viewpos_f },
- { "+scores", CG_ScoresDown_f },
- { "-scores", CG_ScoresUp_f },
- { "+zoom", CG_ZoomDown_f },
- { "-zoom", CG_ZoomUp_f },
- { "sizeup", CG_SizeUp_f },
- { "sizedown", CG_SizeDown_f },
- { "weapnext", CG_NextWeapon_f },
- { "weapprev", CG_PrevWeapon_f },
- { "weapon", CG_Weapon_f },
- { "tell_target", CG_TellTarget_f },
- { "tell_attacker", CG_TellAttacker_f },
- { "vtell_target", CG_VoiceTellTarget_f },
- { "vtell_attacker", CG_VoiceTellAttacker_f },
- { "tcmd", CG_TargetCommand_f },
-#ifdef MISSIONPACK
- { "loadhud", CG_LoadHud_f },
- { "nextTeamMember", CG_NextTeamMember_f },
- { "prevTeamMember", CG_PrevTeamMember_f },
- { "nextOrder", CG_NextOrder_f },
- { "confirmOrder", CG_ConfirmOrder_f },
- { "denyOrder", CG_DenyOrder_f },
- { "taskOffense", CG_TaskOffense_f },
- { "taskDefense", CG_TaskDefense_f },
- { "taskPatrol", CG_TaskPatrol_f },
- { "taskCamp", CG_TaskCamp_f },
- { "taskFollow", CG_TaskFollow_f },
- { "taskRetrieve", CG_TaskRetrieve_f },
- { "taskEscort", CG_TaskEscort_f },
- { "taskSuicide", CG_TaskSuicide_f },
- { "taskOwnFlag", CG_TaskOwnFlag_f },
- { "tauntKillInsult", CG_TauntKillInsult_f },
- { "tauntPraise", CG_TauntPraise_f },
- { "tauntTaunt", CG_TauntTaunt_f },
- { "tauntDeathInsult", CG_TauntDeathInsult_f },
- { "tauntGauntlet", CG_TauntGauntlet_f },
- { "spWin", CG_spWin_f },
- { "spLose", CG_spLose_f },
- { "scoresDown", CG_scrollScoresDown_f },
- { "scoresUp", CG_scrollScoresUp_f },
-#endif
- { "startOrbit", CG_StartOrbit_f },
- //{ "camera", CG_Camera_f },
- { "loaddeferred", CG_LoadDeferredPlayers },
- { "clients", CG_PrintClientNumbers }
-};
-
-
-/*
-=================
-CG_ConsoleCommand
-
-The string has been tokenized and can be retrieved with
-Cmd_Argc() / Cmd_Argv()
-=================
-*/
-qboolean CG_ConsoleCommand( void ) {
- const char *cmd;
- int i;
-
- cmd = CG_Argv(0);
-
- for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
- if ( !Q_stricmp( cmd, commands[i].cmd ) ) {
- commands[i].function();
- return qtrue;
- }
- }
-
- return qfalse;
-}
-
-
-/*
-=================
-CG_InitConsoleCommands
-
-Let the client system know about all of our commands
-so it can perform tab completion
-=================
-*/
-void CG_InitConsoleCommands( void ) {
- int i;
-
- for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
- trap_AddCommand( commands[i].cmd );
- }
-
- //
- // the game server will interpret these commands, which will be automatically
- // forwarded to the server after they are not recognized locally
- //
- trap_AddCommand ("kill");
- trap_AddCommand ("say");
- trap_AddCommand ("say_team");
- trap_AddCommand ("tell");
- trap_AddCommand ("vsay");
- trap_AddCommand ("vsay_team");
- trap_AddCommand ("vtell");
- trap_AddCommand ("vtaunt");
- trap_AddCommand ("vosay");
- trap_AddCommand ("vosay_team");
- trap_AddCommand ("votell");
- trap_AddCommand ("give");
- trap_AddCommand ("god");
- trap_AddCommand ("notarget");
- trap_AddCommand ("noclip");
- trap_AddCommand ("team");
- trap_AddCommand ("follow");
- trap_AddCommand ("levelshot");
- trap_AddCommand ("addbot");
- trap_AddCommand ("setviewpos");
- trap_AddCommand ("callvote");
- trap_AddCommand ("getmappage");
- trap_AddCommand ("vote");
- trap_AddCommand ("callteamvote");
- trap_AddCommand ("teamvote");
- trap_AddCommand ("stats");
- trap_AddCommand ("teamtask");
- trap_AddCommand ("loaddefered"); // spelled wrong, but not changing for demo
-}
diff --git a/game/code/cgame/cg_draw.c b/game/code/cgame/cg_draw.c
deleted file mode 100644
index e4d2b2a..0000000
--- a/game/code/cgame/cg_draw.c
+++ /dev/null
@@ -1,3333 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_draw.c -- draw all of the graphical elements during
-// active (after loading) gameplay
-
-#include "cg_local.h"
-
-#ifdef MISSIONPACK
-#include "../ui/ui_shared.h"
-
-// used for scoreboard
-extern displayContextDef_t cgDC;
-menuDef_t *menuScoreboard = NULL;
-#else
-int drawTeamOverlayModificationCount = -1;
-#endif
-
-int sortedTeamPlayers[TEAM_MAXOVERLAY];
-int numSortedTeamPlayers;
-
-char systemChat[256];
-char teamChat1[256];
-char teamChat2[256];
-
-#ifdef MISSIONPACK
-
-int CG_Text_Width(const char *text, float scale, int limit) {
- int count,len;
- float out;
- glyphInfo_t *glyph;
- float useScale;
-// FIXME: see ui_main.c, same problem
-// const unsigned char *s = text;
- const char *s = text;
- fontInfo_t *font = &cgDC.Assets.textFont;
- if (scale <= cg_smallFont.value) {
- font = &cgDC.Assets.smallFont;
- } else if (scale > cg_bigFont.value) {
- font = &cgDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- out = 0;
- if (text) {
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- if ( Q_IsColorString(s) ) {
- s += 2;
- continue;
- } else {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- out += glyph->xSkip;
- s++;
- count++;
- }
- }
- }
- return out * useScale;
-}
-
-int CG_Text_Height(const char *text, float scale, int limit) {
- int len, count;
- float max;
- glyphInfo_t *glyph;
- float useScale;
-// TTimo: FIXME
-// const unsigned char *s = text;
- const char *s = text;
- fontInfo_t *font = &cgDC.Assets.textFont;
- if (scale <= cg_smallFont.value) {
- font = &cgDC.Assets.smallFont;
- } else if (scale > cg_bigFont.value) {
- font = &cgDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- max = 0;
- if (text) {
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- if ( Q_IsColorString(s) ) {
- s += 2;
- continue;
- } else {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- if (max < glyph->height) {
- max = glyph->height;
- }
- s++;
- count++;
- }
- }
- }
- return max * useScale;
-}
-
-void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
- float w, h;
- w = width * scale;
- h = height * scale;
- CG_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
-}
-
-void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph;
- float useScale;
- fontInfo_t *font = &cgDC.Assets.textFont;
- if (scale <= cg_smallFont.value) {
- font = &cgDC.Assets.smallFont;
- } else if (scale > cg_bigFont.value) {
- font = &cgDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- if (text) {
-// TTimo: FIXME
-// const unsigned char *s = text;
- const char *s = text;
- trap_R_SetColor( color );
- memcpy(&newColor[0], &color[0], sizeof(vec4_t));
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
- //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- float yadj = useScale * glyph->top;
- if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
- int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
- colorBlack[3] = newColor[3];
- trap_R_SetColor( colorBlack );
- CG_Text_PaintChar(x + ofs, y - yadj + ofs,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- colorBlack[3] = 1.0;
- trap_R_SetColor( newColor );
- }
- CG_Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- // CG_DrawPic(x, y - yadj, scale * cgDC.Assets.textFont.glyphs[text[i]].imageWidth, scale * cgDC.Assets.textFont.glyphs[text[i]].imageHeight, cgDC.Assets.textFont.glyphs[text[i]].glyph);
- x += (glyph->xSkip * useScale) + adjust;
- s++;
- count++;
- }
- }
- trap_R_SetColor( NULL );
- }
-}
-
-
-#endif
-
-/*
-==============
-CG_DrawField
-
-Draws large numbers for status bar and powerups
-==============
-*/
-#ifndef MISSIONPACK
-static void CG_DrawField (int x, int y, int width, int value) {
- char num[16], *ptr;
- int l;
- int frame;
-
- if ( width < 1 ) {
- return;
- }
-
- // draw number string
- if ( width > 5 ) {
- width = 5;
- }
-
- switch ( width ) {
- case 1:
- value = value > 9 ? 9 : value;
- value = value < 0 ? 0 : value;
- break;
- case 2:
- value = value > 99 ? 99 : value;
- value = value < -9 ? -9 : value;
- break;
- case 3:
- value = value > 999 ? 999 : value;
- value = value < -99 ? -99 : value;
- break;
- case 4:
- value = value > 9999 ? 9999 : value;
- value = value < -999 ? -999 : value;
- break;
- }
-
- Com_sprintf (num, sizeof(num), "%i", value);
- l = strlen(num);
- if (l > width)
- l = width;
- x += 2 + CHAR_WIDTH*(width - l);
-
- ptr = num;
- while (*ptr && l)
- {
- if (*ptr == '-')
- frame = STAT_MINUS;
- else
- frame = *ptr -'0';
-
- CG_DrawPic( x,y, CHAR_WIDTH, CHAR_HEIGHT, cgs.media.numberShaders[frame] );
- x += CHAR_WIDTH;
- ptr++;
- l--;
- }
-}
-#endif // MISSIONPACK
-
-/*
-================
-CG_Draw3DModel
-
-================
-*/
-void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles ) {
- refdef_t refdef;
- refEntity_t ent;
-
- if ( !cg_draw3dIcons.integer || !cg_drawIcons.integer ) {
- return;
- }
-
- CG_AdjustFrom640( &x, &y, &w, &h );
-
- memset( &refdef, 0, sizeof( refdef ) );
-
- memset( &ent, 0, sizeof( ent ) );
- AnglesToAxis( angles, ent.axis );
- VectorCopy( origin, ent.origin );
- ent.hModel = model;
- ent.customSkin = skin;
- ent.renderfx = RF_NOSHADOW; // no stencil shadows
-
- refdef.rdflags = RDF_NOWORLDMODEL;
-
- AxisClear( refdef.viewaxis );
-
- refdef.fov_x = 30;
- refdef.fov_y = 30;
-
- refdef.x = x;
- refdef.y = y;
- refdef.width = w;
- refdef.height = h;
-
- refdef.time = cg.time;
-
- trap_R_ClearScene();
- trap_R_AddRefEntityToScene( &ent );
- trap_R_RenderScene( &refdef );
-}
-
-/*
-================
-CG_DrawHead
-
-Used for both the status bar and the scoreboard
-================
-*/
-void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles ) {
- clipHandle_t cm;
- clientInfo_t *ci;
- float len;
- vec3_t origin;
- vec3_t mins, maxs;
-
- ci = &cgs.clientinfo[ clientNum ];
-
- if ( cg_draw3dIcons.integer ) {
- cm = ci->headModel;
- if ( !cm ) {
- return;
- }
-
- // offset the origin y and z to center the head
- trap_R_ModelBounds( cm, mins, maxs );
-
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
-
- // calculate distance so the head nearly fills the box
- // assume heads are taller than wide
- len = 0.7 * ( maxs[2] - mins[2] );
- origin[0] = len / 0.268; // len / tan( fov/2 )
-
- // allow per-model tweaking
- VectorAdd( origin, ci->headOffset, origin );
-
- CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, origin, headAngles );
- } else if ( cg_drawIcons.integer ) {
- CG_DrawPic( x, y, w, h, ci->modelIcon );
- }
-
- // if they are deferred, draw a cross out
- if ( ci->deferred ) {
- CG_DrawPic( x, y, w, h, cgs.media.deferShader );
- }
-}
-
-/*
-================
-CG_DrawFlagModel
-
-Used for both the status bar and the scoreboard
-================
-*/
-void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D ) {
- qhandle_t cm;
- float len;
- vec3_t origin, angles;
- vec3_t mins, maxs;
- qhandle_t handle;
-
- if ( !force2D && cg_draw3dIcons.integer ) {
-
- VectorClear( angles );
-
- cm = cgs.media.redFlagModel;
-
- // offset the origin y and z to center the flag
- trap_R_ModelBounds( cm, mins, maxs );
-
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
-
- // calculate distance so the flag nearly fills the box
- // assume heads are taller than wide
- len = 0.5 * ( maxs[2] - mins[2] );
- origin[0] = len / 0.268; // len / tan( fov/2 )
-
- angles[YAW] = 60 * sin( cg.time / 2000.0 );;
-
- if( team == TEAM_RED ) {
- handle = cgs.media.redFlagModel;
- if(cgs.gametype == GT_DOUBLE_D){
- if(cgs.redflag == TEAM_BLUE)
- handle = cgs.media.blueFlagModel;
- if(cgs.redflag == TEAM_FREE)
- handle = cgs.media.neutralFlagModel;
- if(cgs.redflag == TEAM_NONE)
- handle = cgs.media.neutralFlagModel;
- }
- } else if( team == TEAM_BLUE ) {
- handle = cgs.media.blueFlagModel;
- if(cgs.gametype == GT_DOUBLE_D){
- if(cgs.redflag == TEAM_BLUE)
- handle = cgs.media.blueFlagModel;
- if(cgs.redflag == TEAM_FREE)
- handle = cgs.media.neutralFlagModel;
- if(cgs.redflag == TEAM_NONE)
- handle = cgs.media.neutralFlagModel;
- }
- } else if( team == TEAM_FREE ) {
- handle = cgs.media.neutralFlagModel;
- } else {
- return;
- }
- CG_Draw3DModel( x, y, w, h, handle, 0, origin, angles );
- } else if ( cg_drawIcons.integer ) {
- gitem_t *item;
-
- if( team == TEAM_RED ) {
- item = BG_FindItemForPowerup( PW_REDFLAG );
- } else if( team == TEAM_BLUE ) {
- item = BG_FindItemForPowerup( PW_BLUEFLAG );
- } else if( team == TEAM_FREE ) {
- item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
- } else {
- return;
- }
- if (item) {
- CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon );
- }
- }
-}
-
-/*
-================
-CG_DrawStatusBarHead
-
-================
-*/
-#ifndef MISSIONPACK
-
-static void CG_DrawStatusBarHead( float x ) {
- vec3_t angles;
- float size, stretch;
- float frac;
-
- VectorClear( angles );
-
- if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) {
- frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME;
- size = ICON_SIZE * 1.25 * ( 1.5 - frac * 0.5 );
-
- stretch = size - ICON_SIZE * 1.25;
- // kick in the direction of damage
- x -= stretch * 0.5 + cg.damageX * stretch * 0.5;
-
- cg.headStartYaw = 180 + cg.damageX * 45;
-
- cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
- cg.headEndPitch = 5 * cos( crandom()*M_PI );
-
- cg.headStartTime = cg.time;
- cg.headEndTime = cg.time + 100 + random() * 2000;
- } else {
- if ( cg.time >= cg.headEndTime ) {
- // select a new head angle
- cg.headStartYaw = cg.headEndYaw;
- cg.headStartPitch = cg.headEndPitch;
- cg.headStartTime = cg.headEndTime;
- cg.headEndTime = cg.time + 100 + random() * 2000;
-
- cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
- cg.headEndPitch = 5 * cos( crandom()*M_PI );
- }
-
- size = ICON_SIZE * 1.25;
- }
-
- // if the server was frozen for a while we may have a bad head start time
- if ( cg.headStartTime > cg.time ) {
- cg.headStartTime = cg.time;
- }
-
- frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime );
- frac = frac * frac * ( 3 - 2 * frac );
- angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac;
- angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac;
-
- CG_DrawHead( x, 480 - size, size, size,
- cg.snap->ps.clientNum, angles );
-}
-#endif // MISSIONPACK
-
-/*
-================
-CG_DrawStatusBarFlag
-
-================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawStatusBarFlag( float x, int team ) {
- CG_DrawFlagModel( x, 480 - ICON_SIZE, ICON_SIZE, ICON_SIZE, team, qfalse );
-}
-#endif // MISSIONPACK
-
-/*
-================
-CG_DrawTeamBackground
-
-================
-*/
-void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team )
-{
- vec4_t hcolor;
-
- hcolor[3] = alpha;
- if ( team == TEAM_RED ) {
- hcolor[0] = 1;
- hcolor[1] = 0;
- hcolor[2] = 0;
- } else if ( team == TEAM_BLUE ) {
- hcolor[0] = 0;
- hcolor[1] = 0;
- hcolor[2] = 1;
- } else {
- return;
- }
- trap_R_SetColor( hcolor );
- CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
- trap_R_SetColor( NULL );
-}
-
-/*
-================
-CG_DrawStatusBar
-
-================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawStatusBar( void ) {
- int color;
- centity_t *cent;
- playerState_t *ps;
- int value;
- vec4_t hcolor;
- vec3_t angles;
- vec3_t origin;
- qhandle_t handle;
-
- static float colors[4][4] = {
-// { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} };
- { 1.0f, 0.69f, 0.0f, 1.0f }, // normal
- { 1.0f, 0.2f, 0.2f, 1.0f }, // low health
- { 0.5f, 0.5f, 0.5f, 1.0f }, // weapon firing
- { 1.0f, 1.0f, 1.0f, 1.0f } }; // health > 100
-
- if ( cg_drawStatus.integer == 0 ) {
- return;
- }
-
- // draw the team background
- if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) //If not following anybody:
- CG_DrawTeamBackground( 0, 420, 640, 60, 0.33f, cg.snap->ps.persistant[PERS_TEAM] );
- else //Sago: If we follow find the teamcolor of the guy we follow. It might not be our own team!
- CG_DrawTeamBackground( 0, 420, 640, 60, 0.33f, cgs.clientinfo[ cg.snap->ps.clientNum ].team );
-
- cent = &cg_entities[cg.snap->ps.clientNum];
- ps = &cg.snap->ps;
-
- VectorClear( angles );
-
- // draw any 3D icons first, so the changes back to 2D are minimized
- if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) {
- origin[0] = 70;
- origin[1] = 0;
- origin[2] = 0;
- angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 );
- CG_Draw3DModel( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
- cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles );
- }
-
- CG_DrawStatusBarHead( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE );
-
- if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) {
- CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_RED );
- } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) {
- CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_BLUE );
- } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) {
- CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_FREE );
- }
-
- if ( ps->stats[ STAT_ARMOR ] ) {
- origin[0] = 90;
- origin[1] = 0;
- origin[2] = -10;
- angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
- CG_Draw3DModel( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
- cgs.media.armorModel, 0, origin, angles );
- }
-
- if( cgs.gametype == GT_HARVESTER ) {
- origin[0] = 90;
- origin[1] = 0;
- origin[2] = -10;
- angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
- if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- handle = cgs.media.redCubeModel;
- } else {
- handle = cgs.media.blueCubeModel;
- }
- CG_Draw3DModel( 470 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, handle, 0, origin, angles );
- }
-
-
- //
- // ammo
- //
- if ( cent->currentState.weapon ) {
- value = ps->ammo[cent->currentState.weapon];
- if ( value > -1 ) {
- if ( cg.predictedPlayerState.weaponstate == WEAPON_FIRING
- && cg.predictedPlayerState.weaponTime > 100 ) {
- // draw as dark grey when reloading
- color = 2; // dark grey
- } else {
- if ( value >= 0 ) {
- color = 0; // green
- } else {
- color = 1; // red
- }
- }
- trap_R_SetColor( colors[color] );
-
- CG_DrawField (0, 432, 3, value);
- trap_R_SetColor( NULL );
-
- // if we didn't draw a 3D icon, draw a 2D icon for ammo
- if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
- qhandle_t icon;
-
- icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon;
- if ( icon ) {
- CG_DrawPic( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, icon );
- }
- }
- }
- }
-
- //
- // health
- //
- value = ps->stats[STAT_HEALTH];
- if ( value > 100 ) {
- trap_R_SetColor( colors[3] ); // white
- } else if (value > 25) {
- trap_R_SetColor( colors[0] ); // green
- } else if (value > 0) {
- color = (cg.time >> 8) & 1; // flash
- trap_R_SetColor( colors[color] );
- } else {
- trap_R_SetColor( colors[1] ); // red
- }
-
- // stretch the health up when taking damage
- CG_DrawField ( 185, 432, 3, value);
- CG_ColorForHealth( hcolor );
- trap_R_SetColor( hcolor );
-
-
- //
- // armor
- //
- value = ps->stats[STAT_ARMOR];
- if (value > 0 ) {
- trap_R_SetColor( colors[0] );
- CG_DrawField (370, 432, 3, value);
- trap_R_SetColor( NULL );
- // if we didn't draw a 3D icon, draw a 2D icon for armor
- if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
- CG_DrawPic( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, cgs.media.armorIcon );
- }
-
- }
-
- //Skulls!
- if(cgs.gametype == GT_HARVESTER)
- {
- value = ps->generic1;
- if (value > 0 ) {
- trap_R_SetColor( colors[0] );
- CG_DrawField (470, 432, 3, value);
- trap_R_SetColor( NULL );
- // if we didn't draw a 3D icon, draw a 2D icon for skull
- if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
- if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- handle = cgs.media.redCubeIcon;
- } else {
- handle = cgs.media.blueCubeIcon;
- }
- CG_DrawPic( 470 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, handle );
- }
-
- }
- }
-}
-#endif
-
-/*
-===========================================================================================
-
- UPPER RIGHT CORNER
-
-===========================================================================================
-*/
-
-/*
-================
-CG_DrawAttacker
-
-================
-*/
-static float CG_DrawAttacker( float y ) {
- int t;
- float size;
- vec3_t angles;
- const char *info;
- const char *name;
- int clientNum;
-
- if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
- return y;
- }
-
- if ( !cg.attackerTime ) {
- return y;
- }
-
- clientNum = cg.predictedPlayerState.persistant[PERS_ATTACKER];
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS || clientNum == cg.snap->ps.clientNum ) {
- return y;
- }
-
- t = cg.time - cg.attackerTime;
- if ( t > ATTACKER_HEAD_TIME ) {
- cg.attackerTime = 0;
- return y;
- }
-
- size = ICON_SIZE * 1.25;
-
- angles[PITCH] = 0;
- angles[YAW] = 180;
- angles[ROLL] = 0;
- CG_DrawHead( 640 - size, y, size, size, clientNum, angles );
-
- info = CG_ConfigString( CS_PLAYERS + clientNum );
- name = Info_ValueForKey( info, "n" );
- y += size;
- CG_DrawBigString( 640 - ( Q_PrintStrlen( name ) * BIGCHAR_WIDTH), y, name, 0.5 );
-
- return y + BIGCHAR_HEIGHT + 2;
-}
-
-/*
-================
-CG_DrawSpeedMeter
-
-================
-*/
-static float CG_DrawSpeedMeter( float y ) {
- char *s;
- int w;
- vec_t *vel;
- int speed;
-
- /* speed meter can get in the way of the scoreboard */
- if ( cg.scoreBoardShowing ) {
- return y;
- }
-
- vel = cg.snap->ps.velocity;
- /* ignore vertical component of velocity */
- speed = sqrt(vel[0] * vel[0] + vel[1] * vel[1]);
-
- s = va( "%iu/s", speed );
-
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
-
- if (cg_drawSpeed.integer == 1) {
- /* top left-hand corner of screen */
- CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
- return y + BIGCHAR_HEIGHT + 4;
- } else {
- /* center of screen */
- CG_DrawBigString( 320 - w / 2, 300, s, 1.0F);
- return y;
- }
-}
-
-/*
-==================
-CG_DrawSnapshot
-==================
-*/
-static float CG_DrawSnapshot( float y ) {
- char *s;
- int w;
-
- s = va( "time:%i snap:%i cmd:%i", cg.snap->serverTime,
- cg.latestSnapshotNum, cgs.serverCommandSequence );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
-
- CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
-
- return y + BIGCHAR_HEIGHT + 4;
-}
-
-/*
-==================
-CG_DrawFPS
-==================
-*/
-#define FPS_FRAMES 4
-static float CG_DrawFPS( float y ) {
- char *s;
- int w;
- static int previousTimes[FPS_FRAMES];
- static int index;
- int i, total;
- int fps;
- static int previous;
- int t, frameTime;
-
- // don't use serverTime, because that will be drifting to
- // correct for internet lag changes, timescales, timedemos, etc
- t = trap_Milliseconds();
- frameTime = t - previous;
- previous = t;
-
- previousTimes[index % FPS_FRAMES] = frameTime;
- index++;
- if ( index > FPS_FRAMES ) {
- // average multiple frames together to smooth changes out a bit
- total = 0;
- for ( i = 0 ; i < FPS_FRAMES ; i++ ) {
- total += previousTimes[i];
- }
- if ( !total ) {
- total = 1;
- }
- fps = 1000 * FPS_FRAMES / total;
-
- s = va( "%ifps", fps );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
-
- CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
- }
-
- return y + BIGCHAR_HEIGHT + 4;
-}
-
-/*
-=================
-CG_DrawTimer
-=================
-*/
-static float CG_DrawTimer( float y ) {
- char *s;
- int w;
- int mins, seconds, tens;
- int msec;
-
- msec = cg.time - cgs.levelStartTime;
-
- seconds = msec / 1000;
- mins = seconds / 60;
- seconds -= mins * 60;
- tens = seconds / 10;
- seconds -= tens * 10;
-
- s = va( "%i:%i%i", mins, tens, seconds );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
-
- CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
-
- return y + BIGCHAR_HEIGHT + 4;
-}
-
-/*
-CG_DrawDoubleDominationThings
- *
- *Sago: Might be relevant for debugging missionpack.
-*/
-
-/*static float CG_DrawDoubleDominationThings( float y ) {
- char *s;
- int w;
- int statusA, statusB;
- statusA = cgs.redflag;
- statusB = cgs.blueflag;
-
- if(statusA == TEAM_NONE) {
- s = va("Point A not spawned");
- } else
- if(statusA == TEAM_FREE) {
- s = va("Point A is not controlled");
- } else
- if(statusA == TEAM_RED) {
- s = va("Point A is controlled by RED");
- } else
- if(statusA == TEAM_BLUE) {
- s = va("Point A is controlled by BLUE");
- } else
- s = va("Point A has an error");
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- CG_DrawSmallString( 635 - w, y + 2, s, 1.0F);
- y+=SMALLCHAR_HEIGHT+4;
-
- if(statusB == TEAM_NONE) {
- s = va("Point B not spawned");
- } else
- if(statusB == TEAM_FREE) {
- s = va("Point B is not controlled");
- } else
- if(statusB == TEAM_RED) {
- s = va("Point B is controlled by RED");
- } else
- if(statusB == TEAM_BLUE) {
- s = va("Point B is controlled by BLUE");
- } else
- s = va("Point B has an error");
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- CG_DrawSmallString( 635 - w, y + 2, s, 1.0F);
-
- if( ( ( statusB == statusA ) && ( statusA == TEAM_RED ) ) ||
- ( ( statusB == statusA ) && ( statusA == TEAM_BLUE ) ) ) {
- s = va("Capture in: %i",(cgs.timetaken+10*1000-cg.time)/1000+1);
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- y+=SMALLCHAR_HEIGHT+4;
- CG_DrawSmallString( 635 - w, y + 2, s, 1.0F);
- }
-
- return y + SMALLCHAR_HEIGHT+4;
-}*/
-
-/*
-=================
-CG_DrawLMSmode
-=================
-*/
-
-static float CG_DrawLMSmode( float y ) {
- char *s;
- int w;
-
- if(cgs.lms_mode == 0) {
- s = va("LMS: Point/round + OT");
- } else
- if(cgs.lms_mode == 1) {
- s = va("LMS: Point/round - OT");
- } else
- if(cgs.lms_mode == 2) {
- s = va("LMS: Point/kill + OT");
- } else
- if(cgs.lms_mode == 3) {
- s = va("LMS: Point/kill - OT");
- } else
- s = va("LMS: Unknown mode");
-
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- CG_DrawSmallString( 635 - w, y + 2, s, 1.0F);
-
- return y + SMALLCHAR_HEIGHT+4;
-}
-
-/*
-=================
-CG_DrawCTFoneway
-=================
-*/
-
-static float CG_DrawCTFoneway( float y ) {
- char *s;
- int w;
- vec4_t color;
-
- if(cgs.gametype != GT_CTF_ELIMINATION)
- return y;
-
- memcpy(color,g_color_table[ColorIndex(COLOR_WHITE)],sizeof(color));
-
- if( (cgs.elimflags&EF_ONEWAY)==0) {
- return y; //nothing to draw
- } else
- if(cgs.attackingTeam == TEAM_BLUE) {
- memcpy(color,g_color_table[ColorIndex(COLOR_BLUE)],sizeof(color));
- s = va("Blue team on offence");
- } else
- if(cgs.attackingTeam == TEAM_RED) {
- memcpy(color,g_color_table[ColorIndex(COLOR_RED)],sizeof(color));
- s = va("Red team on offence");
- } else
- s = va("Unknown team on offence");
-
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- CG_DrawSmallStringColor( 635 - w, y + 2, s, color);
-
- return y + SMALLCHAR_HEIGHT+4;
-}
-
-/*
-=================
-CG_DrawEliminationDeathMessage
-=================
-*/
-
-/*static float CG_DrawEliminationDeathMessage( float y ) {
- char *s;
- int w;
-
- s = va("You are waiting for a new round");
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- CG_DrawSmallString( 635 - w, y + 2, s, 1.0F);
-
- return y + SMALLCHAR_HEIGHT+4;
-}*/
-
-/*
-=================
-CG_DrawDomStatus
-=================
-*/
-
-static float CG_DrawDomStatus( float y ) {
- int i,w;
- char *s;
- vec4_t color;
-
- for(i = 0;i < cgs.domination_points_count;i++) {
- switch(cgs.domination_points_status[i]) {
- case TEAM_RED:
- memcpy(color,g_color_table[ColorIndex(COLOR_RED)],sizeof(color));
- break;
- case TEAM_BLUE:
- memcpy(color,g_color_table[ColorIndex(COLOR_BLUE)],sizeof(color));
- break;
- default:
- memcpy(color,g_color_table[ColorIndex(COLOR_WHITE)],sizeof(color));
- break;
- }
-
- s = va("%s",cgs.domination_points_names[i]);
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- CG_DrawSmallStringColor( 635 - w, y + 2, s, color);
- y += SMALLCHAR_HEIGHT+4;
-
- }
-
- return y;
-}
-
-
-/*
-=================
-CG_DrawEliminationTimer
-=================
-*/
-static float CG_DrawEliminationTimer( float y ) {
- char *s;
- int w;
- int mins, seconds, tens, sec;
- int msec;
- vec4_t color;
- const char *st;
- float scale;
- int cw;
- int rst;
-
- rst = cgs.roundStartTime;
-
- //default color is white
- memcpy(color,g_color_table[ColorIndex(COLOR_WHITE)],sizeof(color));
-
- //msec = cg.time - cgs.levelStartTime;
- if(cg.time>rst) //We are started
- {
- msec = cgs.roundtime*1000 - (cg.time -rst);
- if(msec<=30*1000-1) //<= 30 seconds
- memcpy(color,g_color_table[ColorIndex(COLOR_YELLOW)],sizeof(color));
- if(msec<=10*1000-1) //<= 10 seconds
- memcpy(color,g_color_table[ColorIndex(COLOR_RED)],sizeof(color));
- msec += 1000; //120-1 instead of 119-0
- }
- else
- {
- //Warmup
- msec = -cg.time +rst;
- memcpy(color,g_color_table[ColorIndex(COLOR_GREEN)],sizeof(color));
- sec = msec/1000;
- msec += 1000; //5-1 instead of 4-0
-/***
-Lots of stuff
-****/
- if(cg.warmup == 0)
- {
- st = va( "Round in: %i", sec + 1 );
- if ( sec != cg.warmupCount ) {
- cg.warmupCount = sec;
- switch ( sec ) {
- case 0:
- trap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER );
- break;
- case 1:
- trap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER );
- break;
- case 2:
- trap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER );
- break;
- default:
- break;
- }
- }
- scale = 0.45f;
- switch ( cg.warmupCount ) {
- case 0:
- cw = 28;
- scale = 0.54f;
- break;
- case 1:
- cw = 24;
- scale = 0.51f;
- break;
- case 2:
- cw = 20;
- scale = 0.48f;
- break;
- default:
- cw = 16;
- scale = 0.45f;
- break;
- }
-
- #ifdef MISSIONPACK
- //w = CG_Text_Width(s, scale, 0);
- //CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, st, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
- #else
- w = CG_DrawStrlen( st );
- CG_DrawStringExt( 320 - w * cw/2, 70, st, colorWhite,
- qfalse, qtrue, cw, (int)(cw * 1.5), 0 );
- #endif
- }
-/*
-Lots of stuff
-*/
- }
-
- seconds = msec / 1000;
- mins = seconds / 60;
- seconds -= mins * 60;
- tens = seconds / 10;
- seconds -= tens * 10;
-
- if(msec>=0)
- s = va( " %i:%i%i", mins, tens, seconds );
- else
- s = va( " Overtime");
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
-
- CG_DrawBigStringColor( 635 - w, y + 2, s, color);
-
- return y + BIGCHAR_HEIGHT + 4;
-}
-
-
-/*
-=================
-CG_DrawTeamOverlay
-=================
-*/
-
-static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) {
- int x, w, h, xx;
- int i, j, len;
- const char *p;
- vec4_t hcolor;
- int pwidth, lwidth;
- int plyrs;
- char st[16];
- clientInfo_t *ci;
- gitem_t *item;
- int ret_y, count;
-
- if ( !cg_drawTeamOverlay.integer ) {
- return y;
- }
-
- if ( cg.snap->ps.persistant[PERS_TEAM] != TEAM_RED && cg.snap->ps.persistant[PERS_TEAM] != TEAM_BLUE ) {
- return y; // Not on any team
- }
-
- plyrs = 0;
-
- // max player name width
- pwidth = 0;
- count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers;
- for (i = 0; i < count; i++) {
- ci = cgs.clientinfo + sortedTeamPlayers[i];
- if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
- plyrs++;
- len = CG_DrawStrlen(ci->name);
- if (len > pwidth)
- pwidth = len;
- }
- }
-
- if (!plyrs)
- return y;
-
- if (pwidth > TEAM_OVERLAY_MAXNAME_WIDTH)
- pwidth = TEAM_OVERLAY_MAXNAME_WIDTH;
-
- // max location name width
- lwidth = 0;
- for (i = 1; i < MAX_LOCATIONS; i++) {
- p = CG_ConfigString(CS_LOCATIONS + i);
- if (p && *p) {
- len = CG_DrawStrlen(p);
- if (len > lwidth)
- lwidth = len;
- }
- }
-
- if (lwidth > TEAM_OVERLAY_MAXLOCATION_WIDTH)
- lwidth = TEAM_OVERLAY_MAXLOCATION_WIDTH;
-
- w = (pwidth + lwidth + 4 + 7) * TINYCHAR_WIDTH;
-
- if ( right )
- x = 640 - w;
- else
- x = 0;
-
- h = plyrs * TINYCHAR_HEIGHT;
-
- if ( upper ) {
- ret_y = y + h;
- } else {
- y -= h;
- ret_y = y;
- }
-
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
- hcolor[0] = 1.0f;
- hcolor[1] = 0.0f;
- hcolor[2] = 0.0f;
- hcolor[3] = 0.33f;
- } else { // if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE )
- hcolor[0] = 0.0f;
- hcolor[1] = 0.0f;
- hcolor[2] = 1.0f;
- hcolor[3] = 0.33f;
- }
- trap_R_SetColor( hcolor );
- CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
- trap_R_SetColor( NULL );
-
- for (i = 0; i < count; i++) {
- ci = cgs.clientinfo + sortedTeamPlayers[i];
- if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
-
- hcolor[0] = hcolor[1] = hcolor[2] = hcolor[3] = 1.0;
-
- xx = x + TINYCHAR_WIDTH;
-
- CG_DrawStringExt( xx, y,
- ci->name, hcolor, qfalse, qfalse,
- TINYCHAR_WIDTH, TINYCHAR_HEIGHT, TEAM_OVERLAY_MAXNAME_WIDTH);
-
- if (lwidth) {
- p = CG_ConfigString(CS_LOCATIONS + ci->location);
- if (!p || !*p)
- p = "unknown";
- len = CG_DrawStrlen(p);
- if (len > lwidth)
- len = lwidth;
-
-// xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth +
-// ((lwidth/2 - len/2) * TINYCHAR_WIDTH);
- xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth;
- CG_DrawStringExt( xx, y,
- p, hcolor, qfalse, qfalse, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
- TEAM_OVERLAY_MAXLOCATION_WIDTH);
- }
-
- CG_GetColorForHealth( ci->health, ci->armor, hcolor );
-
- Com_sprintf (st, sizeof(st), "%3i %3i", ci->health, ci->armor);
-
- xx = x + TINYCHAR_WIDTH * 3 +
- TINYCHAR_WIDTH * pwidth + TINYCHAR_WIDTH * lwidth;
-
- CG_DrawStringExt( xx, y,
- st, hcolor, qfalse, qfalse,
- TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
-
- // draw weapon icon
- xx += TINYCHAR_WIDTH * 3;
-
- if ( cg_weapons[ci->curWeapon].weaponIcon ) {
- CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
- cg_weapons[ci->curWeapon].weaponIcon );
- } else {
- CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
- cgs.media.deferShader );
- }
-
- // Draw powerup icons
- if (right) {
- xx = x;
- } else {
- xx = x + w - TINYCHAR_WIDTH;
- }
- for (j = 0; j <= PW_NUM_POWERUPS; j++) {
- if (ci->powerups & (1 << j)) {
-
- item = BG_FindItemForPowerup( j );
-
- if (item) {
- CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
- trap_R_RegisterShader( item->icon ) );
- if (right) {
- xx -= TINYCHAR_WIDTH;
- } else {
- xx += TINYCHAR_WIDTH;
- }
- }
- }
- }
-
- y += TINYCHAR_HEIGHT;
- }
- }
-
- return ret_y;
-//#endif
-}
-
-static float CG_DrawFollowMessage( float y ) {
- char *s;
- int w;
-
- if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) || ( ( cgs.elimflags & EF_NO_FREESPEC ) && (cgs.gametype == GT_ELIMINATION || cgs.gametype == GT_CTF_ELIMINATION ) ) ) {
- return y;
- }
-
- s = va("USE_ITEM to stop following");
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- CG_DrawSmallString( 635 - w, y + 2, s, 1.0F);
-
- return y + SMALLCHAR_HEIGHT+4;
-}
-
-
-/*
-=====================
-CG_DrawUpperRight
-
-=====================
-*/
-static void CG_DrawUpperRight(stereoFrame_t stereoFrame)
-{
- float y;
-
- y = 0;
-
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1 && cg_drawTeamOverlay.integer == 1 ) {
- y = CG_DrawTeamOverlay( y, qtrue, qtrue );
- }
- /*if ( cgs.gametype == GT_DOUBLE_D ) {
- y = CG_DrawDoubleDominationThings(y);
- }
- else*/
- if ( cgs.gametype == GT_LMS && cg.showScores ) {
- y = CG_DrawLMSmode(y);
- }
- else
- if ( cgs.gametype == GT_CTF_ELIMINATION ) {
- y = CG_DrawCTFoneway(y);
- }
- else
- if ( cgs.gametype == GT_DOMINATION ) {
- y = CG_DrawDomStatus(y);
- }
-
- if ( cg_drawSnapshot.integer ) {
- y = CG_DrawSnapshot( y );
- }
- if (cg_drawFPS.integer && (stereoFrame == STEREO_CENTER || stereoFrame == STEREO_RIGHT)) {
- y = CG_DrawFPS( y );
- }
- if (cgs.gametype==GT_ELIMINATION || cgs.gametype == GT_CTF_ELIMINATION || cgs.gametype==GT_LMS) {
- y = CG_DrawEliminationTimer( y );
- /*if (cgs.clientinfo[ cg.clientNum ].isDead)
- y = CG_DrawEliminationDeathMessage( y);*/
- }
-
- y = CG_DrawFollowMessage( y );
-
- if ( cg_drawTimer.integer) {
- y = CG_DrawTimer( y );
- }
- if ( cg_drawAttacker.integer ) {
- y = CG_DrawAttacker( y );
- }
- if ( cg_drawSpeed.integer ) {
- y = CG_DrawSpeedMeter( y );
- }
-
-}
-
-/*
-===========================================================================================
-
- LOWER RIGHT CORNER
-
-===========================================================================================
-*/
-
-/*
-=================
-CG_DrawScores
-
-Draw the small two score display
-=================
-*/
-#ifndef MISSIONPACK
-static float CG_DrawScores( float y ) {
- const char *s;
- int s1, s2, score;
- int x, w;
- int v;
- vec4_t color;
- float y1;
- gitem_t *item;
- int statusA,statusB;
-
- statusA = cgs.redflag;
- statusB = cgs.blueflag;
-
- s1 = cgs.scores1;
- s2 = cgs.scores2;
-
- y -= BIGCHAR_HEIGHT + 8;
-
- y1 = y;
-
- // draw from the right side to left
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- x = 640;
- color[0] = 0.0f;
- color[1] = 0.0f;
- color[2] = 1.0f;
- color[3] = 0.33f;
- s = va( "%2i", s2 );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
- }
- CG_DrawBigString( x + 4, y, s, 1.0F);
-
- if ( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION) {
- // Display flag status
- item = BG_FindItemForPowerup( PW_BLUEFLAG );
-
- if (item) {
- y1 = y - BIGCHAR_HEIGHT - 8;
- if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) {
- CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.blueFlagShader[cgs.blueflag] );
- }
- }
- }
-
- if ( cgs.gametype == GT_DOUBLE_D ) {
- // Display Domination point status
-
- y1 = y - 32;//BIGCHAR_HEIGHT - 8;
- if( cgs.redflag >= 0 && cgs.redflag <= 3 ) {
- CG_DrawPic( x, y1-4, w, 32, cgs.media.ddPointSkinB[cgs.blueflag] );
- }
- }
-
- color[0] = 1.0f;
- color[1] = 0.0f;
- color[2] = 0.0f;
- color[3] = 0.33f;
- s = va( "%2i", s1 );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
- CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
- }
- CG_DrawBigString( x + 4, y, s, 1.0F);
-
- if ( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION ) {
- // Display flag status
- item = BG_FindItemForPowerup( PW_REDFLAG );
-
- if (item) {
- y1 = y - BIGCHAR_HEIGHT - 8;
- if( cgs.redflag >= 0 && cgs.redflag <= 2 ) {
- CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.redFlagShader[cgs.redflag] );
- }
- }
- }
-
- if ( cgs.gametype == GT_DOUBLE_D ) {
- // Display Domination point status
-
- y1 = y - 32;//BIGCHAR_HEIGHT - 8;
- if( cgs.redflag >= 0 && cgs.redflag <= 3 ) {
- CG_DrawPic( x, y1-4, w, 32, cgs.media.ddPointSkinA[cgs.redflag] );
- }
-
-
-
- //Time till capture:
- if( ( ( statusB == statusA ) && ( statusA == TEAM_RED ) ) ||
- ( ( statusB == statusA ) && ( statusA == TEAM_BLUE ) ) ) {
- s = va("%i",(cgs.timetaken+10*1000-cg.time)/1000+1);
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- CG_DrawBigString( x + 32+8-w/2, y-28, s, 1.0F);
- }
- }
-
-
-
- if ( cgs.gametype >= GT_CTF && cgs.ffa_gt==0) {
- v = cgs.capturelimit;
- } else {
- v = cgs.fraglimit;
- }
- if ( v ) {
- s = va( "%2i", v );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- CG_DrawBigString( x + 4, y, s, 1.0F);
- }
-
- } else {
- qboolean spectator;
-
- x = 640;
- score = cg.snap->ps.persistant[PERS_SCORE];
- spectator = ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR );
-
- // always show your score in the second box if not in first place
- if ( s1 != score ) {
- s2 = score;
- }
- if ( s2 != SCORE_NOT_PRESENT ) {
- s = va( "%2i", s2 );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- if ( !spectator && score == s2 && score != s1 ) {
- color[0] = 1.0f;
- color[1] = 0.0f;
- color[2] = 0.0f;
- color[3] = 0.33f;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
- } else {
- color[0] = 0.5f;
- color[1] = 0.5f;
- color[2] = 0.5f;
- color[3] = 0.33f;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- }
- CG_DrawBigString( x + 4, y, s, 1.0F);
- }
-
- // first place
- if ( s1 != SCORE_NOT_PRESENT ) {
- s = va( "%2i", s1 );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- if ( !spectator && score == s1 ) {
- color[0] = 0.0f;
- color[1] = 0.0f;
- color[2] = 1.0f;
- color[3] = 0.33f;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
- } else {
- color[0] = 0.5f;
- color[1] = 0.5f;
- color[2] = 0.5f;
- color[3] = 0.33f;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- }
- CG_DrawBigString( x + 4, y, s, 1.0F);
- }
-
- if ( cgs.fraglimit ) {
- s = va( "%2i", cgs.fraglimit );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- CG_DrawBigString( x + 4, y, s, 1.0F);
- }
-
- }
-
- return y1 - 8;
-}
-#endif // MISSIONPACK
-
-/*
-================
-CG_DrawPowerups
-================
-*/
-#ifndef MISSIONPACK
-static float CG_DrawPowerups( float y ) {
- int sorted[MAX_POWERUPS];
- int sortedTime[MAX_POWERUPS];
- int i, j, k;
- int active;
- playerState_t *ps;
- int t;
- gitem_t *item;
- int x;
- int color;
- float size;
- float f;
- static float colors[2][4] = {
- { 0.2f, 1.0f, 0.2f, 1.0f } ,
- { 1.0f, 0.2f, 0.2f, 1.0f }
- };
-
- ps = &cg.snap->ps;
-
- if ( ps->stats[STAT_HEALTH] <= 0 ) {
- return y;
- }
-
- // sort the list by time remaining
- active = 0;
- for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
- if ( !ps->powerups[ i ] ) {
- continue;
- }
- t = ps->powerups[ i ] - cg.time;
- // ZOID--don't draw if the power up has unlimited time (999 seconds)
- // This is true of the CTF flags
- if ( t < 0 || t > 999000) {
- continue;
- }
-
- item = BG_FindItemForPowerup( i );
- if ( item && item->giType == IT_PERSISTANT_POWERUP)
- continue; //Don't draw persistant powerups here!
-
- // insert into the list
- for ( j = 0 ; j < active ; j++ ) {
- if ( sortedTime[j] >= t ) {
- for ( k = active - 1 ; k >= j ; k-- ) {
- sorted[k+1] = sorted[k];
- sortedTime[k+1] = sortedTime[k];
- }
- break;
- }
- }
- sorted[j] = i;
- sortedTime[j] = t;
- active++;
- }
-
- // draw the icons and timers
- x = 640 - ICON_SIZE - CHAR_WIDTH * 2;
- for ( i = 0 ; i < active ; i++ ) {
- item = BG_FindItemForPowerup( sorted[i] );
-
- if (item) {
-
- color = 1;
-
- y -= ICON_SIZE;
-
- trap_R_SetColor( colors[color] );
- CG_DrawField( x, y, 2, sortedTime[ i ] / 1000 );
-
- t = ps->powerups[ sorted[i] ];
- if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
- trap_R_SetColor( NULL );
- } else {
- vec4_t modulate;
-
- f = (float)( t - cg.time ) / POWERUP_BLINK_TIME;
- f -= (int)f;
- modulate[0] = modulate[1] = modulate[2] = modulate[3] = f;
- trap_R_SetColor( modulate );
- }
-
- if ( cg.powerupActive == sorted[i] &&
- cg.time - cg.powerupTime < PULSE_TIME ) {
- f = 1.0 - ( ( (float)cg.time - cg.powerupTime ) / PULSE_TIME );
- size = ICON_SIZE * ( 1.0 + ( PULSE_SCALE - 1.0 ) * f );
- } else {
- size = ICON_SIZE;
- }
-
- CG_DrawPic( 640 - size, y + ICON_SIZE / 2 - size / 2,
- size, size, trap_R_RegisterShader( item->icon ) );
- }
- }
- trap_R_SetColor( NULL );
-
- return y;
-}
-#endif // MISSIONPACK
-
-/*
-=====================
-CG_DrawLowerRight
-
-=====================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawLowerRight( void ) {
- float y;
-
- y = 480 - ICON_SIZE;
-
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1 && cg_drawTeamOverlay.integer == 2 ) {
- y = CG_DrawTeamOverlay( y, qtrue, qfalse );
- }
-
- y = CG_DrawScores( y );
- y = CG_DrawPowerups( y );
-}
-#endif // MISSIONPACK
-
-/*
-===================
-CG_DrawPickupItem
-===================
-*/
-#ifndef MISSIONPACK
-static int CG_DrawPickupItem( int y ) {
- int value;
- float *fadeColor;
-
- if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
- return y;
- }
-
- y -= ICON_SIZE;
-
- value = cg.itemPickup;
- if ( value ) {
- fadeColor = CG_FadeColor( cg.itemPickupTime, 3000 );
- if ( fadeColor ) {
- CG_RegisterItemVisuals( value );
- trap_R_SetColor( fadeColor );
- CG_DrawPic( 8, y, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
- CG_DrawBigString( ICON_SIZE + 16, y + (ICON_SIZE/2 - BIGCHAR_HEIGHT/2), bg_itemlist[ value ].pickup_name, fadeColor[0] );
- trap_R_SetColor( NULL );
- }
- }
-
- return y;
-}
-#endif // MISSIONPACK
-
-/*
-=====================
-CG_DrawLowerLeft
-
-=====================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawLowerLeft( void ) {
- float y;
-
- y = 480 - ICON_SIZE;
-
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1 && cg_drawTeamOverlay.integer == 3 ) {
- y = CG_DrawTeamOverlay( y, qfalse, qfalse );
- }
-
-
- y = CG_DrawPickupItem( y );
-}
-#endif // MISSIONPACK
-
-
-//===========================================================================================
-
-/*
-=================
-CG_DrawTeamInfo
-=================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawTeamInfo( void ) {
- int w, h;
- int i, len;
- vec4_t hcolor;
- int chatHeight;
-
-#define CHATLOC_Y 420 // bottom end
-#define CHATLOC_X 0
-
- if (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT)
- chatHeight = cg_teamChatHeight.integer;
- else
- chatHeight = TEAMCHAT_HEIGHT;
- if (chatHeight <= 0)
- return; // disabled
-
- if (cgs.teamLastChatPos != cgs.teamChatPos) {
- if (cg.time - cgs.teamChatMsgTimes[cgs.teamLastChatPos % chatHeight] > cg_teamChatTime.integer) {
- cgs.teamLastChatPos++;
- }
-
- h = (cgs.teamChatPos - cgs.teamLastChatPos) * TINYCHAR_HEIGHT;
-
- w = 0;
-
- for (i = cgs.teamLastChatPos; i < cgs.teamChatPos; i++) {
- len = CG_DrawStrlen(cgs.teamChatMsgs[i % chatHeight]);
- if (len > w)
- w = len;
- }
- w *= TINYCHAR_WIDTH;
- w += TINYCHAR_WIDTH * 2;
-
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
- hcolor[0] = 1.0f;
- hcolor[1] = 0.0f;
- hcolor[2] = 0.0f;
- hcolor[3] = 0.33f;
- } else if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- hcolor[0] = 0.0f;
- hcolor[1] = 0.0f;
- hcolor[2] = 1.0f;
- hcolor[3] = 0.33f;
- } else {
- hcolor[0] = 0.0f;
- hcolor[1] = 1.0f;
- hcolor[2] = 0.0f;
- hcolor[3] = 0.33f;
- }
-
- trap_R_SetColor( hcolor );
- CG_DrawPic( CHATLOC_X, CHATLOC_Y - h, 640, h, cgs.media.teamStatusBar );
- trap_R_SetColor( NULL );
-
- hcolor[0] = hcolor[1] = hcolor[2] = 1.0f;
- hcolor[3] = 1.0f;
-
- for (i = cgs.teamChatPos - 1; i >= cgs.teamLastChatPos; i--) {
- CG_DrawStringExt( CHATLOC_X + TINYCHAR_WIDTH,
- CHATLOC_Y - (cgs.teamChatPos - i)*TINYCHAR_HEIGHT,
- cgs.teamChatMsgs[i % chatHeight], hcolor, qfalse, qfalse,
- TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
- }
- }
-}
-#endif // MISSIONPACK
-
-/*
-===================
-CG_DrawHoldableItem
-===================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawHoldableItem( void ) {
- int value;
-
- value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM];
- if ( value ) {
- CG_RegisterItemVisuals( value );
- CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
- }
-
-}
-#endif // MISSIONPACK
-
-#ifndef MISSIONPACK
-/*
-===================
-CG_DrawPersistantPowerup
-===================
-*/
-#if 1 // sos001208 - DEAD // sago - ALIVE
-static void CG_DrawPersistantPowerup( void ) {
- int value;
-
- value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP];
- if ( value ) {
- CG_RegisterItemVisuals( value );
- CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2 - ICON_SIZE, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
- }
-}
-#endif
-#endif // MISSIONPACK
-
-
-/*
-===================
-CG_DrawReward
-===================
-*/
-static void CG_DrawReward( void ) {
- float *color;
- int i, count;
- float x, y;
- char buf[32];
-
- if ( !cg_drawRewards.integer ) {
- return;
- }
-
- color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
- if ( !color ) {
- if (cg.rewardStack > 0) {
- for(i = 0; i < cg.rewardStack; i++) {
- cg.rewardSound[i] = cg.rewardSound[i+1];
-
- cg.rewardShader[i] = cg.rewardShader[i+1];
- cg.rewardCount[i] = cg.rewardCount[i+1];
- }
- cg.rewardTime = cg.time;
- cg.rewardStack--;
- color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
-
- trap_S_StartLocalSound(cg.rewardSound[0], CHAN_ANNOUNCER);
-
- } else {
- return;
- }
- }
-
- trap_R_SetColor( color );
-
- /*
- count = cg.rewardCount[0]/10; // number of big rewards to draw
-
- if (count) {
- y = 4;
- x = 320 - count * ICON_SIZE;
- for ( i = 0 ; i < count ; i++ ) {
- CG_DrawPic( x, y, (ICON_SIZE*2)-4, (ICON_SIZE*2)-4, cg.rewardShader[0] );
- x += (ICON_SIZE*2);
- }
- }
-
- count = cg.rewardCount[0] - count*10; // number of small rewards to draw
- */
-
- if ( cg.rewardCount[0] >= 10 ) {
- y = 56;
- x = 320 - ICON_SIZE/2;
- CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
- Com_sprintf(buf, sizeof(buf), "%d", cg.rewardCount[0]);
- x = ( SCREEN_WIDTH - SMALLCHAR_WIDTH * CG_DrawStrlen( buf ) ) / 2;
- CG_DrawStringExt( x, y+ICON_SIZE, buf, color, qfalse, qtrue,
- SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
- }
- else {
-
- count = cg.rewardCount[0];
-
- y = 56;
- x = 320 - count * ICON_SIZE/2;
- for ( i = 0 ; i < count ; i++ ) {
- CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
- x += ICON_SIZE;
- }
- }
- trap_R_SetColor( NULL );
-}
-
-
-/*
-===============================================================================
-
-LAGOMETER
-
-===============================================================================
-*/
-
-#define LAG_SAMPLES 128
-
-
-typedef struct {
- int frameSamples[LAG_SAMPLES];
- int frameCount;
- int snapshotFlags[LAG_SAMPLES];
- int snapshotSamples[LAG_SAMPLES];
- int snapshotCount;
-} lagometer_t;
-
-lagometer_t lagometer;
-
-/*
-==============
-CG_AddLagometerFrameInfo
-
-Adds the current interpolate / extrapolate bar for this frame
-==============
-*/
-void CG_AddLagometerFrameInfo( void ) {
- int offset;
-
- offset = cg.time - cg.latestSnapshotTime;
- lagometer.frameSamples[ lagometer.frameCount & ( LAG_SAMPLES - 1) ] = offset;
- lagometer.frameCount++;
-}
-
-/*
-==============
-CG_AddLagometerSnapshotInfo
-
-Each time a snapshot is received, log its ping time and
-the number of snapshots that were dropped before it.
-
-Pass NULL for a dropped packet.
-==============
-*/
-void CG_AddLagometerSnapshotInfo( snapshot_t *snap ) {
- // dropped packet
- if ( !snap ) {
- lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = -1;
- lagometer.snapshotCount++;
- return;
- }
-
- // add this snapshot's info
- lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->ping;
- lagometer.snapshotFlags[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->snapFlags;
- lagometer.snapshotCount++;
-}
-
-/*
-==============
-CG_DrawDisconnect
-
-Should we draw something differnet for long lag vs no packets?
-==============
-*/
-static void CG_DrawDisconnect( void ) {
- float x, y;
- int cmdNum;
- usercmd_t cmd;
- const char *s;
- int w; // bk010215 - FIXME char message[1024];
-
- // draw the phone jack if we are completely past our buffers
- cmdNum = trap_GetCurrentCmdNumber() - CMD_BACKUP + 1;
- trap_GetUserCmd( cmdNum, &cmd );
- if ( cmd.serverTime <= cg.snap->ps.commandTime
- || cmd.serverTime > cg.time ) { // special check for map_restart // bk 0102165 - FIXME
- return;
- }
-
- // also add text in center of screen
- s = "Connection Interrupted"; // bk 010215 - FIXME
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- CG_DrawBigString( 320 - w/2, 100, s, 1.0F);
-
- // blink the icon
- if ( ( cg.time >> 9 ) & 1 ) {
- return;
- }
-
- x = 640 - 48;
- y = 480 - 48;
-
- CG_DrawPic( x, y, 48, 48, trap_R_RegisterShader("gfx/2d/net.tga" ) );
-}
-
-
-#define MAX_LAGOMETER_PING 900
-#define MAX_LAGOMETER_RANGE 300
-
-/*
-==============
-CG_DrawLagometer
-==============
-*/
-static void CG_DrawLagometer( void ) {
- int a, x, y, i;
- float v;
- float ax, ay, aw, ah, mid, range;
- int color;
- float vscale;
-
- if ( !cg_lagometer.integer || cgs.localServer ) {
- CG_DrawDisconnect();
- return;
- }
-
- //
- // draw the graph
- //
-#ifdef MISSIONPACK
- x = 640 - 48;
- y = 480 - 144;
-#else
- x = 640 - 48;
- y = 480 - 48;
-#endif
-
- trap_R_SetColor( NULL );
- CG_DrawPic( x, y, 48, 48, cgs.media.lagometerShader );
-
- ax = x;
- ay = y;
- aw = 48;
- ah = 48;
- CG_AdjustFrom640( &ax, &ay, &aw, &ah );
-
- color = -1;
- range = ah / 3;
- mid = ay + range;
-
- vscale = range / MAX_LAGOMETER_RANGE;
-
- // draw the frame interpoalte / extrapolate graph
- for ( a = 0 ; a < aw ; a++ ) {
- i = ( lagometer.frameCount - 1 - a ) & (LAG_SAMPLES - 1);
- v = lagometer.frameSamples[i];
- v *= vscale;
- if ( v > 0 ) {
- if ( color != 1 ) {
- color = 1;
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
- }
- if ( v > range ) {
- v = range;
- }
- trap_R_DrawStretchPic ( ax + aw - a, mid - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
- } else if ( v < 0 ) {
- if ( color != 2 ) {
- color = 2;
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_BLUE)] );
- }
- v = -v;
- if ( v > range ) {
- v = range;
- }
- trap_R_DrawStretchPic( ax + aw - a, mid, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
- }
- }
-
- // draw the snapshot latency / drop graph
- range = ah / 2;
- vscale = range / MAX_LAGOMETER_PING;
-
- for ( a = 0 ; a < aw ; a++ ) {
- i = ( lagometer.snapshotCount - 1 - a ) & (LAG_SAMPLES - 1);
- v = lagometer.snapshotSamples[i];
- if ( v > 0 ) {
- if ( lagometer.snapshotFlags[i] & SNAPFLAG_RATE_DELAYED ) {
- if ( color != 5 ) {
- color = 5; // YELLOW for rate delay
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
- }
- } else {
- if ( color != 3 ) {
- color = 3;
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_GREEN)] );
- }
- }
- v = v * vscale;
- if ( v > range ) {
- v = range;
- }
- trap_R_DrawStretchPic( ax + aw - a, ay + ah - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
- } else if ( v < 0 ) {
- if ( color != 4 ) {
- color = 4; // RED for dropped snapshots
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_RED)] );
- }
- trap_R_DrawStretchPic( ax + aw - a, ay + ah - range, 1, range, 0, 0, 0, 0, cgs.media.whiteShader );
- }
- }
-
- trap_R_SetColor( NULL );
-
- if ( cg_nopredict.integer || cg_synchronousClients.integer ) {
- CG_DrawBigString( ax, ay, "snc", 1.0 );
- }
-
- CG_DrawDisconnect();
-}
-
-
-
-/*
-===============================================================================
-
-CENTER PRINTING
-
-===============================================================================
-*/
-
-
-/*
-==============
-CG_CenterPrint
-
-Called for important messages that should stay in the center of the screen
-for a few moments
-==============
-*/
-void CG_CenterPrint( const char *str, int y, int charWidth ) {
- char *s;
-
- Q_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) );
-
- cg.centerPrintTime = cg.time;
- cg.centerPrintY = y;
- cg.centerPrintCharWidth = charWidth;
-
- // count the number of lines for centering
- cg.centerPrintLines = 1;
- s = cg.centerPrint;
- while( *s ) {
- if (*s == '\n')
- cg.centerPrintLines++;
- s++;
- }
-}
-
-
-/*
-===================
-CG_DrawCenterString
-===================
-*/
-static void CG_DrawCenterString( void ) {
- char *start;
- int l;
- int x, y, w;
-#ifdef MISSIONPACK // bk010221 - unused else
- int h;
-#endif
- float *color;
-
- if ( !cg.centerPrintTime ) {
- return;
- }
-
- color = CG_FadeColor( cg.centerPrintTime, 1000 * cg_centertime.value );
- if ( !color ) {
- return;
- }
-
- trap_R_SetColor( color );
-
- start = cg.centerPrint;
-
- y = cg.centerPrintY - cg.centerPrintLines * BIGCHAR_HEIGHT / 2;
-
- while ( 1 ) {
- char linebuffer[1024];
-
- for ( l = 0; l < 50; l++ ) {
- if ( !start[l] || start[l] == '\n' ) {
- break;
- }
- linebuffer[l] = start[l];
- }
- linebuffer[l] = 0;
-
-#ifdef MISSIONPACK
- w = CG_Text_Width(linebuffer, 0.5, 0);
- h = CG_Text_Height(linebuffer, 0.5, 0);
- x = (SCREEN_WIDTH - w) / 2;
- CG_Text_Paint(x, y + h, 0.5, color, linebuffer, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
- y += h + 6;
-#else
- w = cg.centerPrintCharWidth * CG_DrawStrlen( linebuffer );
-
- x = ( SCREEN_WIDTH - w ) / 2;
-
- CG_DrawStringExt( x, y, linebuffer, color, qfalse, qtrue,
- cg.centerPrintCharWidth, (int)(cg.centerPrintCharWidth * 1.5), 0 );
-
- y += cg.centerPrintCharWidth * 1.5;
-#endif
- while ( *start && ( *start != '\n' ) ) {
- start++;
- }
- if ( !*start ) {
- break;
- }
- start++;
- }
-
- trap_R_SetColor( NULL );
-}
-
-/*
-=====================
-CG_DrawCenter1FctfString
-=====================
-*/
-static void CG_DrawCenter1FctfString( void ) {
- #ifndef MISSIONPACK
- int x, y, w;
- float *color;
- char *line;
- int status;
-
- if(cgs.gametype != GT_1FCTF)
- return;
-
- status = cgs.flagStatus;
-
- //Sago: TODO: Find the proper defines instead of hardcoded values.
- switch(status)
- {
- case 2:
- line = va("Red has the flag!");
- color = colorRed;
- break;
- case 3:
- line = va("Blue has the flag!");
- color = colorBlue;
- break;
- case 4:
- line = va("Flag dropped!");
- color = colorWhite;
- break;
- default:
- return;
-
- };
- y = 100;
-
-
- w = cg.centerPrintCharWidth * CG_DrawStrlen( line );
-
- x = ( SCREEN_WIDTH - w ) / 2;
-
- CG_DrawStringExt( x, y, line, color, qfalse, qtrue,
- cg.centerPrintCharWidth, (int)(cg.centerPrintCharWidth * 1.5), 0 );
-
-
- #endif
-}
-
-static int lastDDSec = -100;
-
-/*
-=====================
-CG_DrawCenterDDString
-=====================
-*/
-static void CG_DrawCenterDDString( void ) {
- #ifndef MISSIONPACK
- int x, y, w;
- float *color;
- char *line;
- int statusA, statusB;
- int sec;
-
-
- if(cgs.gametype != GT_DOUBLE_D)
- return;
-
- statusA = cgs.redflag;
- statusB = cgs.blueflag;
-
- if( ( ( statusB == statusA ) && ( statusA == TEAM_RED ) ) ||
- ( ( statusB == statusA ) && ( statusA == TEAM_BLUE ) ) ) {
- }
- else
- return; //No team is dominating
-
- if(statusA == TEAM_BLUE) {
- line = va("Blue scores in %i",(cgs.timetaken+10*1000-cg.time)/1000+1);
- color = colorBlue;
- } else if(statusA == TEAM_RED) {
- line = va("Red scores in %i",(cgs.timetaken+10*1000-cg.time)/1000+1);
- color = colorRed;
- } else {
- lastDDSec = -100;
- return;
- }
-
- sec = (cgs.timetaken+10*1000-cg.time)/1000+1;
- if(sec!=lastDDSec) {
- //A new number is being displayed... play the sound!
- switch ( sec ) {
- case 1:
- trap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER );
- break;
- case 2:
- trap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER );
- break;
- case 3:
- trap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER );
- break;
- case 10:
- trap_S_StartLocalSound( cgs.media.doublerSound , CHAN_ANNOUNCER );
- break;
- default:
- break;
- }
- }
- lastDDSec = sec;
-
- y = 100;
-
-
- w = cg.centerPrintCharWidth * CG_DrawStrlen( line );
-
- x = ( SCREEN_WIDTH - w ) / 2;
-
- CG_DrawStringExt( x, y, line, color, qfalse, qtrue,
- cg.centerPrintCharWidth, (int)(cg.centerPrintCharWidth * 1.5), 0 );
-
- #endif
-}
-
-
-/*
-================================================================================
-
-CROSSHAIR
-
-================================================================================
-*/
-
-
-/*
-=================
-CG_DrawCrosshair
-=================
-*/
-static void CG_DrawCrosshair(void)
-{
- float w, h;
- qhandle_t hShader;
- float f;
- float x, y;
- int ca = 0; //only to get rid of the warning(not useful)
- int currentWeapon;
-
- currentWeapon = cg.predictedPlayerState.weapon;
-
- if ( !cg_drawCrosshair.integer ) {
- return;
- }
-
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) {
- return;
- }
-
- if ( cg.renderingThirdPerson ) {
- return;
- }
-
- // set color based on health
- if ( cg_crosshairHealth.integer ) {
- vec4_t hcolor;
-
- CG_ColorForHealth( hcolor );
- trap_R_SetColor( hcolor );
- } else {
- vec4_t color;
- color[0]=cg_crosshairColorRed.value;
- color[1]=cg_crosshairColorGreen.value;
- color[2]=cg_crosshairColorBlue.value;
- color[3]=1.0f;
- trap_R_SetColor( color );
- }
-
- if( cg_differentCrosshairs.integer == 1 ){
- switch( currentWeapon ){
- case 1:
- w = h = cg_ch1size.value;
- ca = cg_ch1.integer;
- break;
- case 2:
- w = h = cg_ch2size.value;
- ca = cg_ch2.integer;
- break;
- case 3:
- w = h = cg_ch3size.value;
- ca = cg_ch3.integer;
- break;
- case 4:
- w = h = cg_ch4size.value;
- ca = cg_ch4.integer;
- break;
- case 5:
- w = h = cg_ch5size.value;
- ca = cg_ch5.integer;
- break;
- case 6:
- w = h = cg_ch6size.value;
- ca = cg_ch6.integer;
- break;
- case 7:
- w = h = cg_ch7size.value;
- ca = cg_ch7.integer;
- break;
- case 8:
- w = h = cg_ch8size.value;
- ca = cg_ch8.integer;
- break;
- case 9:
- w = h = cg_ch9size.value;
- ca = cg_ch9.integer;
- break;
- case 10:
- w = h = cg_ch10size.value;
- ca = cg_ch10.integer;
- break;
- case 11:
- w = h = cg_ch11size.value;
- ca = cg_ch11.integer;
- break;
- case 12:
- w = h = cg_ch12size.value;
- ca = cg_ch12.integer;
- break;
- case 13:
- w = h = cg_ch13size.value;
- ca = cg_ch13.integer;
- break;
- }
- }
- else{
- w = h = cg_crosshairSize.value;
- ca = cg_drawCrosshair.integer;
- }
-
- if( cg_crosshairPulse.integer ){
- // pulse the size of the crosshair when picking up items
- f = cg.time - cg.itemPickupBlendTime;
- if ( f > 0 && f < ITEM_BLOB_TIME ) {
- f /= ITEM_BLOB_TIME;
- w *= ( 1 + f );
- h *= ( 1 + f );
- }
- }
-
- x = cg_crosshairX.integer;
- y = cg_crosshairY.integer;
- CG_AdjustFrom640( &x, &y, &w, &h );
-
- if (ca < 0) {
- ca = 0;
- }
- hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ];
-
- if(!hShader)
- hShader = cgs.media.crosshairShader[ ca % 10 ];
-
- trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (cg.refdef.width - w),
- y + cg.refdef.y + 0.5 * (cg.refdef.height - h),
- w, h, 0, 0, 1, 1, hShader );
-}
-
-/*
-=================
-CG_DrawCrosshair3D
-=================
-*/
-static void CG_DrawCrosshair3D(void)
-{
- float w, h;
- qhandle_t hShader;
- float f;
- int ca;
-
- trace_t trace;
- vec3_t endpos;
- float stereoSep, zProj, maxdist, xmax;
- char rendererinfos[128];
- refEntity_t ent;
-
- if ( !cg_drawCrosshair.integer ) {
- return;
- }
-
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) {
- return;
- }
-
- if ( cg.renderingThirdPerson ) {
- return;
- }
-
- w = h = cg_crosshairSize.value;
-
- // pulse the size of the crosshair when picking up items
- f = cg.time - cg.itemPickupBlendTime;
- if ( f > 0 && f < ITEM_BLOB_TIME ) {
- f /= ITEM_BLOB_TIME;
- w *= ( 1 + f );
- h *= ( 1 + f );
- }
-
- ca = cg_drawCrosshair.integer;
- if (ca < 0) {
- ca = 0;
- }
- hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ];
-
- if(!hShader)
- hShader = cgs.media.crosshairShader[ ca % 10 ];
-
- // Use a different method rendering the crosshair so players don't see two of them when
- // focusing their eyes at distant objects with high stereo separation
- // We are going to trace to the next shootable object and place the crosshair in front of it.
-
- // first get all the important renderer information
- trap_Cvar_VariableStringBuffer("r_zProj", rendererinfos, sizeof(rendererinfos));
- zProj = atof(rendererinfos);
- trap_Cvar_VariableStringBuffer("r_stereoSeparation", rendererinfos, sizeof(rendererinfos));
- stereoSep = zProj / atof(rendererinfos);
-
- xmax = zProj * tan(cg.refdef.fov_x * M_PI / 360.0f);
-
- // let the trace run through until a change in stereo separation of the crosshair becomes less than one pixel.
- maxdist = cgs.glconfig.vidWidth * stereoSep * zProj / (2 * xmax);
- VectorMA(cg.refdef.vieworg, maxdist, cg.refdef.viewaxis[0], endpos);
- CG_Trace(&trace, cg.refdef.vieworg, NULL, NULL, endpos, 0, MASK_SHOT);
-
- memset(&ent, 0, sizeof(ent));
- ent.reType = RT_SPRITE;
- ent.renderfx = RF_DEPTHHACK | RF_CROSSHAIR;
-
- VectorCopy(trace.endpos, ent.origin);
-
- // scale the crosshair so it appears the same size for all distances
- ent.radius = w / 640 * xmax * trace.fraction * maxdist / zProj;
- ent.customShader = hShader;
-
- trap_R_AddRefEntityToScene(&ent);
-}
-
-
-
-/*
-=================
-CG_ScanForCrosshairEntity
-=================
-*/
-static void CG_ScanForCrosshairEntity( void ) {
- trace_t trace;
- vec3_t start, end;
- int content;
-
- VectorCopy( cg.refdef.vieworg, start );
- VectorMA( start, 131072, cg.refdef.viewaxis[0], end );
-
- CG_Trace( &trace, start, vec3_origin, vec3_origin, end,
- cg.snap->ps.clientNum, CONTENTS_SOLID|CONTENTS_BODY );
- if ( trace.entityNum >= MAX_CLIENTS ) {
- return;
- }
-
- // if the player is in fog, don't show it
- content = trap_CM_PointContents( trace.endpos, 0 );
- if ( content & CONTENTS_FOG ) {
- return;
- }
-
- // if the player is invisible, don't show it
- if ( cg_entities[ trace.entityNum ].currentState.powerups & ( 1 << PW_INVIS ) ) {
- return;
- }
-
- // update the fade timer
- cg.crosshairClientNum = trace.entityNum;
- cg.crosshairClientTime = cg.time;
-}
-
-
-/*
-=====================
-CG_DrawCrosshairNames
-=====================
-*/
-static void CG_DrawCrosshairNames( void ) {
- float *color;
- char *name;
- float w;
-
- if ( !cg_drawCrosshair.integer ) {
- return;
- }
- if ( !cg_drawCrosshairNames.integer ) {
- return;
- }
- if ( cg.renderingThirdPerson ) {
- return;
- }
-
- // scan the known entities to see if the crosshair is sighted on one
- CG_ScanForCrosshairEntity();
-
- // draw the name of the player being looked at
- color = CG_FadeColor( cg.crosshairClientTime, 1000 );
- if ( !color ) {
- trap_R_SetColor( NULL );
- return;
- }
-
- name = cgs.clientinfo[ cg.crosshairClientNum ].name;
-#ifdef MISSIONPACK
- color[3] *= 0.5f;
- w = CG_Text_Width(name, 0.3f, 0);
- CG_Text_Paint( 320 - w / 2, 190, 0.3f, color, name, 0, 0, ITEM_TEXTSTYLE_SHADOWED);
-#else
- w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH;
- CG_DrawBigString( 320 - w / 2, 170, name, color[3] * 0.5f );
-#endif
- trap_R_SetColor( NULL );
-}
-
-
-//==============================================================================
-
-/*
-=================
-CG_DrawSpectator
-=================
-*/
-static void CG_DrawSpectator(void) {
- CG_DrawBigString(320 - 9 * 8, 440, "SPECTATOR", 1.0F);
- if ( cgs.gametype == GT_TOURNAMENT ) {
- CG_DrawBigString(320 - 15 * 8, 460, "waiting to play", 1.0F);
- }
- else if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- CG_DrawBigString(320 - 39 * 8, 460, "press ESC and use the JOIN menu to play", 1.0F);
- }
-}
-
-/*
-=================
-CG_DrawVote
-=================
-*/
-static void CG_DrawVote(void) {
- char *s;
- int sec;
-
- if ( !cgs.voteTime ) {
- return;
- }
-
- // play a talk beep whenever it is modified
- if ( cgs.voteModified ) {
- cgs.voteModified = qfalse;
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- }
-
- sec = ( VOTE_TIME - ( cg.time - cgs.voteTime ) ) / 1000;
- if ( sec < 0 ) {
- sec = 0;
- }
-#ifdef MISSIONPACK
- s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo);
- CG_DrawSmallString( 0, 58, s, 1.0F );
- s = "or press ESC then click Vote";
- CG_DrawSmallString( 0, 58 + SMALLCHAR_HEIGHT + 2, s, 1.0F );
-#else
- s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo );
- CG_DrawSmallString( 0, 58, s, 1.0F );
-#endif
-}
-
-/*
-=================
-CG_DrawTeamVote
-=================
-*/
-static void CG_DrawTeamVote(void) {
- char *s;
- int sec, cs_offset;
-
- if ( cgs.clientinfo->team == TEAM_RED )
- cs_offset = 0;
- else if ( cgs.clientinfo->team == TEAM_BLUE )
- cs_offset = 1;
- else
- return;
-
- if ( !cgs.teamVoteTime[cs_offset] ) {
- return;
- }
-
- // play a talk beep whenever it is modified
- if ( cgs.teamVoteModified[cs_offset] ) {
- cgs.teamVoteModified[cs_offset] = qfalse;
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- }
-
- sec = ( VOTE_TIME - ( cg.time - cgs.teamVoteTime[cs_offset] ) ) / 1000;
- if ( sec < 0 ) {
- sec = 0;
- }
- s = va("TEAMVOTE(%i):%s yes:%i no:%i", sec, cgs.teamVoteString[cs_offset],
- cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] );
- CG_DrawSmallString( 0, 90, s, 1.0F );
-}
-
-
-static qboolean CG_DrawScoreboard( void ) {
-#ifdef MISSIONPACK
- static qboolean firstTime = qtrue;
- float fade, *fadeColor;
-
- if (menuScoreboard) {
- menuScoreboard->window.flags &= ~WINDOW_FORCED;
- }
- if (cg_paused.integer) {
- cg.deferredPlayerLoading = 0;
- firstTime = qtrue;
- return qfalse;
- }
-
- // should never happen in Team Arena
- if (cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- cg.deferredPlayerLoading = 0;
- firstTime = qtrue;
- return qfalse;
- }
-
- // don't draw scoreboard during death while warmup up
- if ( cg.warmup && !cg.showScores ) {
- return qfalse;
- }
-
- if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD || cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- fade = 1.0;
- fadeColor = colorWhite;
- } else {
- fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
- if ( !fadeColor ) {
- // next time scoreboard comes up, don't print killer
- cg.deferredPlayerLoading = 0;
- cg.killerName[0] = 0;
- firstTime = qtrue;
- return qfalse;
- }
- fade = *fadeColor;
- }
-
-
- if (menuScoreboard == NULL) {
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- menuScoreboard = Menus_FindByName("teamscore_menu");
- } else {
- menuScoreboard = Menus_FindByName("score_menu");
- }
- }
-
- if (menuScoreboard) {
- if (firstTime) {
- CG_SetScoreSelection(menuScoreboard);
- firstTime = qfalse;
- }
- Menu_Paint(menuScoreboard, qtrue);
- }
-
- // load any models that have been deferred
- if ( ++cg.deferredPlayerLoading > 10 ) {
- CG_LoadDeferredPlayers();
- }
-
- return qtrue;
-#else
- return CG_DrawOldScoreboard();
-#endif
-}
-
-/*
-=================
-CG_DrawIntermission
-=================
-*/
-static void CG_DrawIntermission( void ) {
-// int key;
-#ifdef MISSIONPACK
- //if (cg_singlePlayer.integer) {
- // CG_DrawCenterString();
- // return;
- //}
-#else
- if ( cgs.gametype == GT_SINGLE_PLAYER ) {
- CG_DrawCenterString();
- return;
- }
-#endif
- cg.scoreFadeTime = cg.time;
- cg.scoreBoardShowing = CG_DrawScoreboard();
-}
-
-/*
-=================
-CG_DrawFollow
-=================
-*/
-static qboolean CG_DrawFollow( void ) {
- float x;
- vec4_t color;
- const char *name;
-
- if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
- return qfalse;
- }
- color[0] = 1;
- color[1] = 1;
- color[2] = 1;
- color[3] = 1;
-
-
- CG_DrawBigString( 320 - 9 * 8, 24, "following", 1.0F );
-
- name = cgs.clientinfo[ cg.snap->ps.clientNum ].name;
-
- x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( name ) );
-
- CG_DrawStringExt( x, 40, name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
-
- return qtrue;
-}
-
-
-
-/*
-=================
-CG_DrawAmmoWarning
-=================
-*/
-static void CG_DrawAmmoWarning( void ) {
- const char *s;
- int w;
-
- //Don't report in instant gib same with RA
- if(cgs.nopickup)
- return;
-
- if ( cg_drawAmmoWarning.integer == 0 ) {
- return;
- }
-
- if ( !cg.lowAmmoWarning ) {
- return;
- }
-
- if ( cg.lowAmmoWarning == 2 ) {
- s = "OUT OF AMMO";
- } else {
- s = "LOW AMMO WARNING";
- }
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- CG_DrawBigString(320 - w / 2, 64, s, 1.0F);
-}
-
-
-//#ifdef MISSIONPACK
-/*
-=================
-CG_DrawProxWarning
-=================
-*/
-static void CG_DrawProxWarning( void ) {
- char s [32];
- int w;
- static int proxTime;
- static int proxCounter;
- static int proxTick;
-
- if( !(cg.snap->ps.eFlags & EF_TICKING ) ) {
- proxTime = 0;
- return;
- }
-
- if (proxTime == 0) {
- proxTime = cg.time + 5000;
- proxCounter = 5;
- proxTick = 0;
- }
-
- if (cg.time > proxTime) {
- proxTick = proxCounter--;
- proxTime = cg.time + 1000;
- }
-
- if (proxTick != 0) {
- Com_sprintf(s, sizeof(s), "INTERNAL COMBUSTION IN: %i", proxTick);
- } else {
- Com_sprintf(s, sizeof(s), "YOU HAVE BEEN MINED");
- }
-
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- CG_DrawBigStringColor( 320 - w / 2, 64 + BIGCHAR_HEIGHT, s, g_color_table[ColorIndex(COLOR_RED)] );
-}
-//#endif
-
-
-/*
-=================
-CG_DrawWarmup
-=================
-*/
-static void CG_DrawWarmup( void ) {
- int w;
- int sec;
- int i;
- float scale;
- clientInfo_t *ci1, *ci2;
- int cw;
- const char *s;
-
- sec = cg.warmup;
- if ( !sec ) {
- return;
- }
-
- if ( sec < 0 ) {
- s = "Waiting for players";
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- CG_DrawBigString(320 - w / 2, 24, s, 1.0F);
- cg.warmupCount = 0;
- return;
- }
-
- if (cgs.gametype == GT_TOURNAMENT) {
- // find the two active players
- ci1 = NULL;
- ci2 = NULL;
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_FREE ) {
- if ( !ci1 ) {
- ci1 = &cgs.clientinfo[i];
- } else {
- ci2 = &cgs.clientinfo[i];
- }
- }
- }
-
- if ( ci1 && ci2 ) {
- s = va( "%s vs %s", ci1->name, ci2->name );
-#ifdef MISSIONPACK
- w = CG_Text_Width(s, 0.6f, 0);
- CG_Text_Paint(320 - w / 2, 60, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
-#else
- w = CG_DrawStrlen( s );
- if ( w > 640 / GIANT_WIDTH ) {
- cw = 640 / w;
- } else {
- cw = GIANT_WIDTH;
- }
- CG_DrawStringExt( 320 - w * cw/2, 20,s, colorWhite,
- qfalse, qtrue, cw, (int)(cw * 1.5f), 0 );
-#endif
- }
- } else {
- if ( cgs.gametype == GT_FFA ) {
- s = "Free For All";
- } else if ( cgs.gametype == GT_TEAM ) {
- s = "Team Deathmatch";
- } else if ( cgs.gametype == GT_CTF ) {
- s = "Capture the Flag";
- } else if ( cgs.gametype == GT_ELIMINATION ) {
- s = "Elimination";
- } else if ( cgs.gametype == GT_CTF_ELIMINATION ) {
- s = "CTF Elimination";
- } else if ( cgs.gametype == GT_LMS ) {
- s = "Last Man Standing";
- } else if ( cgs.gametype == GT_DOUBLE_D ) {
- s = "Double Domination";
- } else if ( cgs.gametype == GT_1FCTF ) {
- s = "One Flag CTF";
- } else if ( cgs.gametype == GT_OBELISK ) {
- s = "Overload";
- } else if ( cgs.gametype == GT_HARVESTER ) {
- s = "Harvester";
- } else if ( cgs.gametype == GT_DOMINATION ) {
- s = "Domination";
- } else {
- s = "";
- }
-#ifdef MISSIONPACK
- w = CG_Text_Width(s, 0.6f, 0);
- CG_Text_Paint(320 - w / 2, 90, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
-#else
- w = CG_DrawStrlen( s );
- if ( w > 640 / GIANT_WIDTH ) {
- cw = 640 / w;
- } else {
- cw = GIANT_WIDTH;
- }
- CG_DrawStringExt( 320 - w * cw/2, 25,s, colorWhite,
- qfalse, qtrue, cw, (int)(cw * 1.1f), 0 );
-#endif
- }
-
- sec = ( sec - cg.time ) / 1000;
- if ( sec < 0 ) {
- cg.warmup = 0;
- sec = 0;
- }
- s = va( "Starts in: %i", sec + 1 );
- if ( sec != cg.warmupCount ) {
- cg.warmupCount = sec;
- switch ( sec ) {
- case 0:
- trap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER );
- break;
- case 1:
- trap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER );
- break;
- case 2:
- trap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER );
- break;
- default:
- break;
- }
- }
- scale = 0.45f;
- switch ( cg.warmupCount ) {
- case 0:
- cw = 28;
- scale = 0.54f;
- break;
- case 1:
- cw = 24;
- scale = 0.51f;
- break;
- case 2:
- cw = 20;
- scale = 0.48f;
- break;
- default:
- cw = 16;
- scale = 0.45f;
- break;
- }
-
-#ifdef MISSIONPACK
- w = CG_Text_Width(s, scale, 0);
- CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
-#else
- w = CG_DrawStrlen( s );
- CG_DrawStringExt( 320 - w * cw/2, 70, s, colorWhite,
- qfalse, qtrue, cw, (int)(cw * 1.5), 0 );
-#endif
-}
-
-//==================================================================================
-#ifdef MISSIONPACK
-/*
-=================
-CG_DrawTimedMenus
-=================
-*/
-void CG_DrawTimedMenus( void ) {
- if (cg.voiceTime) {
- int t = cg.time - cg.voiceTime;
- if ( t > 2500 ) {
- Menus_CloseByName("voiceMenu");
- trap_Cvar_Set("cl_conXOffset", "0");
- cg.voiceTime = 0;
- }
- }
-}
-#endif
-/*
-=================
-CG_Draw2D
-=================
-*/
-static void CG_Draw2D(stereoFrame_t stereoFrame)
-{
-#ifdef MISSIONPACK
- if (cgs.orderPending && cg.time > cgs.orderTime) {
- CG_CheckOrderPending();
- }
-#endif
- // if we are taking a levelshot for the menu, don't draw anything
- if ( cg.levelShot ) {
- return;
- }
-
- if ( cg_draw2D.integer == 0 ) {
- return;
- }
-
- if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
- CG_DrawIntermission();
- return;
- }
-
-/*
- if (cg.cameraMode) {
- return;
- }
-*/
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR /*|| cg.snap->ps.pm_type == PM_SPECTATOR*/ ) {
- CG_DrawSpectator();
-
- if(stereoFrame == STEREO_CENTER)
- CG_DrawCrosshair();
-
- CG_DrawCrosshairNames();
- } else {
- // don't draw any status if dead or the scoreboard is being explicitly shown
- if ( !cg.showScores && cg.snap->ps.stats[STAT_HEALTH] > 0 ) {
-
-#ifdef MISSIONPACK
- if ( cg_drawStatus.integer ) {
- Menu_PaintAll();
- CG_DrawTimedMenus();
- }
-#else
- CG_DrawStatusBar();
-#endif
-
- CG_DrawAmmoWarning();
-
- CG_DrawProxWarning();
- if(stereoFrame == STEREO_CENTER)
- CG_DrawCrosshair();
- CG_DrawCrosshairNames();
- CG_DrawWeaponSelect();
-
- #ifndef MISSIONPACK
- CG_DrawHoldableItem();
- CG_DrawPersistantPowerup();
- #endif
-
- CG_DrawReward();
- }
-
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
-#ifndef MISSIONPACK
- CG_DrawTeamInfo();
-#endif
- }
- }
-
- CG_DrawVote();
- CG_DrawTeamVote();
-
- CG_DrawLagometer();
-
-#ifdef MISSIONPACK
- if (!cg_paused.integer) {
- CG_DrawUpperRight(stereoFrame);
- }
-#else
- CG_DrawUpperRight(stereoFrame);
-#endif
-
-#ifndef MISSIONPACK
- CG_DrawLowerRight();
- CG_DrawLowerLeft();
-#endif
-
- if ( !CG_DrawFollow() ) {
- CG_DrawWarmup();
- }
-
- // don't draw center string if scoreboard is up
- cg.scoreBoardShowing = CG_DrawScoreboard();
- if ( !cg.scoreBoardShowing) {
- CG_DrawCenterDDString();
- CG_DrawCenter1FctfString();
- CG_DrawCenterString();
- }
-}
-
-
-static void CG_DrawTourneyScoreboard( void ) {
-#ifdef MISSIONPACK
-#else
- CG_DrawOldTourneyScoreboard();
-#endif
-}
-
-/*
-=====================
-CG_DrawActive
-
-Perform all drawing needed to completely fill the screen
-=====================
-*/
-void CG_DrawActive( stereoFrame_t stereoView ) {
- // optionally draw the info screen instead
- if ( !cg.snap ) {
- CG_DrawInformation();
- return;
- }
-
- // optionally draw the tournement scoreboard instead
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR &&
- ( cg.snap->ps.pm_flags & PMF_SCOREBOARD ) ) {
- CG_DrawTourneyScoreboard();
- return;
- }
-
- // clear around the rendered view if sized down
- CG_TileClear();
-
- if(stereoView != STEREO_CENTER)
- CG_DrawCrosshair3D();
-
- // draw 3D view
- trap_R_RenderScene( &cg.refdef );
-
- // draw status bar and other floating elements
- CG_Draw2D(stereoView);
-}
-
-
-
diff --git a/game/code/cgame/cg_effects.c b/game/code/cgame/cg_effects.c
deleted file mode 100644
index 8a5e7a8..0000000
--- a/game/code/cgame/cg_effects.c
+++ /dev/null
@@ -1,764 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_effects.c -- these functions generate localentities, usually as a result
-// of event processing
-
-#include "cg_local.h"
-
-
-/*
-==================
-CG_BubbleTrail
-
-Bullets shot underwater
-==================
-*/
-void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ) {
- vec3_t move;
- vec3_t vec;
- float len;
- int i;
-
- if ( cg_noProjectileTrail.integer ) {
- return;
- }
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- // advance a random amount first
- i = rand() % (int)spacing;
- VectorMA( move, i, vec, move );
-
- VectorScale (vec, spacing, vec);
-
- for ( ; i < len; i += spacing ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- le->leFlags = LEF_PUFF_DONT_SCALE;
- le->leType = LE_MOVE_SCALE_FADE;
- le->startTime = cg.time;
- le->endTime = cg.time + 1000 + random() * 250;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- re = &le->refEntity;
- re->shaderTime = cg.time / 1000.0f;
-
- re->reType = RT_SPRITE;
- re->rotation = 0;
- re->radius = 3;
- re->customShader = cgs.media.waterBubbleShader;
- re->shaderRGBA[0] = 0xff;
- re->shaderRGBA[1] = 0xff;
- re->shaderRGBA[2] = 0xff;
- re->shaderRGBA[3] = 0xff;
-
- le->color[3] = 1.0;
-
- le->pos.trType = TR_LINEAR;
- le->pos.trTime = cg.time;
- VectorCopy( move, le->pos.trBase );
- le->pos.trDelta[0] = crandom()*5;
- le->pos.trDelta[1] = crandom()*5;
- le->pos.trDelta[2] = crandom()*5 + 6;
-
- VectorAdd (move, vec, move);
- }
-}
-
-/*
-=====================
-CG_SmokePuff
-
-Adds a smoke puff or blood trail localEntity.
-=====================
-*/
-localEntity_t *CG_SmokePuff( const vec3_t p, const vec3_t vel,
- float radius,
- float r, float g, float b, float a,
- float duration,
- int startTime,
- int fadeInTime,
- int leFlags,
- qhandle_t hShader ) {
- static int seed = 0x92;
- localEntity_t *le;
- refEntity_t *re;
-// int fadeInTime = startTime + duration / 2;
-
- le = CG_AllocLocalEntity();
- le->leFlags = leFlags;
- le->radius = radius;
-
- re = &le->refEntity;
- re->rotation = Q_random( &seed ) * 360;
- re->radius = radius;
- re->shaderTime = startTime / 1000.0f;
-
- le->leType = LE_MOVE_SCALE_FADE;
- le->startTime = startTime;
- le->fadeInTime = fadeInTime;
- le->endTime = startTime + duration;
- if ( fadeInTime > startTime ) {
- le->lifeRate = 1.0 / ( le->endTime - le->fadeInTime );
- }
- else {
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
- }
- le->color[0] = r;
- le->color[1] = g;
- le->color[2] = b;
- le->color[3] = a;
-
-
- le->pos.trType = TR_LINEAR;
- le->pos.trTime = startTime;
- VectorCopy( vel, le->pos.trDelta );
- VectorCopy( p, le->pos.trBase );
-
- VectorCopy( p, re->origin );
- re->customShader = hShader;
-
- // rage pro can't alpha fade, so use a different shader
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
- re->customShader = cgs.media.smokePuffRageProShader;
- re->shaderRGBA[0] = 0xff;
- re->shaderRGBA[1] = 0xff;
- re->shaderRGBA[2] = 0xff;
- re->shaderRGBA[3] = 0xff;
- } else {
- re->shaderRGBA[0] = le->color[0] * 0xff;
- re->shaderRGBA[1] = le->color[1] * 0xff;
- re->shaderRGBA[2] = le->color[2] * 0xff;
- re->shaderRGBA[3] = 0xff;
- }
-
- re->reType = RT_SPRITE;
- re->radius = le->radius;
-
- return le;
-}
-
-/*
-==================
-CG_SpawnEffect
-
-Player teleporting in or out
-==================
-*/
-void CG_SpawnEffect( vec3_t org ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_FADE_RGB;
- le->startTime = cg.time;
- le->endTime = cg.time + 500;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
-
- re = &le->refEntity;
-
- re->reType = RT_MODEL;
- re->shaderTime = cg.time / 1000.0f;
-
-#ifndef MISSIONPACK
- re->customShader = cgs.media.teleportEffectShader;
-#endif
- re->hModel = cgs.media.teleportEffectModel;
- AxisClear( re->axis );
-
- VectorCopy( org, re->origin );
-#ifdef MISSIONPACK
- re->origin[2] += 16;
-#else
- re->origin[2] -= 24;
-#endif
-}
-
-/*
-===============
-CG_LightningBoltBeam
-===============
-*/
-void CG_LightningBoltBeam( vec3_t start, vec3_t end ) {
- localEntity_t *le;
- refEntity_t *beam;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_SHOWREFENTITY;
- le->startTime = cg.time;
- le->endTime = cg.time + 50;
-
- beam = &le->refEntity;
-
- VectorCopy( start, beam->origin );
- // this is the end point
- VectorCopy( end, beam->oldorigin );
-
- beam->reType = RT_LIGHTNING;
- beam->customShader = cgs.media.lightningShader;
-}
-
-/*
-==================
-CG_KamikazeEffect
-==================
-*/
-void CG_KamikazeEffect( vec3_t org ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_KAMIKAZE;
- le->startTime = cg.time;
- le->endTime = cg.time + 3000;//2250;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
-
- VectorClear(le->angles.trBase);
-
- re = &le->refEntity;
-
- re->reType = RT_MODEL;
- re->shaderTime = cg.time / 1000.0f;
-
- re->hModel = cgs.media.kamikazeEffectModel;
-
- VectorCopy( org, re->origin );
-
-}
-
-/*
-==================
-CG_ObeliskExplode
-==================
-*/
-void CG_ObeliskExplode( vec3_t org, int entityNum ) {
- localEntity_t *le;
- vec3_t origin;
-
- // create an explosion
- VectorCopy( org, origin );
- origin[2] += 64;
- le = CG_MakeExplosion( origin, vec3_origin,
- cgs.media.dishFlashModel,
- cgs.media.rocketExplosionShader,
- 600, qtrue );
- le->light = 300;
- le->lightColor[0] = 1;
- le->lightColor[1] = 0.75;
- le->lightColor[2] = 0.0;
-}
-
-/*
-==================
-CG_ObeliskPain
-==================
-*/
-void CG_ObeliskPain( vec3_t org ) {
- float r;
- sfxHandle_t sfx;
-
- // hit sound
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.obeliskHitSound1;
- } else if ( r == 2 ) {
- sfx = cgs.media.obeliskHitSound2;
- } else {
- sfx = cgs.media.obeliskHitSound3;
- }
- trap_S_StartSound ( org, ENTITYNUM_NONE, CHAN_BODY, sfx );
-}
-
-
-/*
-==================
-CG_InvulnerabilityImpact
-==================
-*/
-void CG_InvulnerabilityImpact( vec3_t org, vec3_t angles ) {
- localEntity_t *le;
- refEntity_t *re;
- int r;
- sfxHandle_t sfx;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_INVULIMPACT;
- le->startTime = cg.time;
- le->endTime = cg.time + 1000;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
-
- re = &le->refEntity;
-
- re->reType = RT_MODEL;
- re->shaderTime = cg.time / 1000.0f;
-
- re->hModel = cgs.media.invulnerabilityImpactModel;
-
- VectorCopy( org, re->origin );
- AnglesToAxis( angles, re->axis );
-
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.invulnerabilityImpactSound1;
- } else if ( r == 2 ) {
- sfx = cgs.media.invulnerabilityImpactSound2;
- } else {
- sfx = cgs.media.invulnerabilityImpactSound3;
- }
- trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, sfx );
-}
-
-/*
-==================
-CG_InvulnerabilityJuiced
-==================
-*/
-void CG_InvulnerabilityJuiced( vec3_t org ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t angles;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_INVULJUICED;
- le->startTime = cg.time;
- le->endTime = cg.time + 10000;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
-
- re = &le->refEntity;
-
- re->reType = RT_MODEL;
- re->shaderTime = cg.time / 1000.0f;
-
- re->hModel = cgs.media.invulnerabilityJuicedModel;
-
- VectorCopy( org, re->origin );
- VectorClear(angles);
- AnglesToAxis( angles, re->axis );
-
- trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, cgs.media.invulnerabilityJuicedSound );
-}
-
-/*
-==================
-CG_ScorePlum
-==================
-*/
-void CG_ScorePlum( int client, vec3_t org, int score ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t angles;
- static vec3_t lastPos;
-
- // only visualize for the client that scored
- if (client != cg.predictedPlayerState.clientNum || cg_scorePlum.integer == 0) {
- return;
- }
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_SCOREPLUM;
- le->startTime = cg.time;
- le->endTime = cg.time + 4000;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
- le->radius = score;
-
- VectorCopy( org, le->pos.trBase );
- if (org[2] >= lastPos[2] - 20 && org[2] <= lastPos[2] + 20) {
- le->pos.trBase[2] -= 20;
- }
-
- //CG_Printf( "Plum origin %i %i %i -- %i\n", (int)org[0], (int)org[1], (int)org[2], (int)Distance(org, lastPos));
- VectorCopy(org, lastPos);
-
-
- re = &le->refEntity;
-
- re->reType = RT_SPRITE;
- re->radius = 16;
-
- VectorClear(angles);
- AnglesToAxis( angles, re->axis );
-}
-
-
-/*
-====================
-CG_MakeExplosion
-====================
-*/
-localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
- qhandle_t hModel, qhandle_t shader,
- int msec, qboolean isSprite ) {
- float ang;
- localEntity_t *ex;
- int offset;
- vec3_t tmpVec, newOrigin;
-
- if ( msec <= 0 ) {
- CG_Error( "CG_MakeExplosion: msec = %i", msec );
- }
-
- // skew the time a bit so they aren't all in sync
- offset = rand() & 63;
-
- ex = CG_AllocLocalEntity();
- if ( isSprite ) {
- ex->leType = LE_SPRITE_EXPLOSION;
-
- // randomly rotate sprite orientation
- ex->refEntity.rotation = rand() % 360;
- VectorScale( dir, 16, tmpVec );
- VectorAdd( tmpVec, origin, newOrigin );
- } else {
- ex->leType = LE_EXPLOSION;
- VectorCopy( origin, newOrigin );
-
- // set axis with random rotate
- if ( !dir ) {
- AxisClear( ex->refEntity.axis );
- } else {
- ang = rand() % 360;
- VectorCopy( dir, ex->refEntity.axis[0] );
- RotateAroundDirection( ex->refEntity.axis, ang );
- }
- }
-
- ex->startTime = cg.time - offset;
- ex->endTime = ex->startTime + msec;
-
- // bias the time so all shader effects start correctly
- ex->refEntity.shaderTime = ex->startTime / 1000.0f;
-
- ex->refEntity.hModel = hModel;
- ex->refEntity.customShader = shader;
-
- // set origin
- VectorCopy( newOrigin, ex->refEntity.origin );
- VectorCopy( newOrigin, ex->refEntity.oldorigin );
-
- ex->color[0] = ex->color[1] = ex->color[2] = 1.0;
-
- return ex;
-}
-
-
-/*
-=================
-CG_Bleed
-
-This is the spurt of blood when a character gets hit
-=================
-*/
-void CG_Bleed( vec3_t origin, int entityNum ) {
- localEntity_t *ex;
-
- if ( !cg_blood.integer ) {
- return;
- }
-
- ex = CG_AllocLocalEntity();
- ex->leType = LE_EXPLOSION;
-
- ex->startTime = cg.time;
- ex->endTime = ex->startTime + 500;
-
- VectorCopy ( origin, ex->refEntity.origin);
- ex->refEntity.reType = RT_SPRITE;
- ex->refEntity.rotation = rand() % 360;
- ex->refEntity.radius = 24;
-
- ex->refEntity.customShader = cgs.media.bloodExplosionShader;
-
- // don't show player's own blood in view
- if ( entityNum == cg.snap->ps.clientNum ) {
- ex->refEntity.renderfx |= RF_THIRD_PERSON;
- }
-}
-
-
-
-/*
-==================
-CG_SpurtBlood (LEILEI)
-==================
-*/
-void CG_SpurtBlood( vec3_t origin, vec3_t velocity, int hard ) {
- localEntity_t *le;
- refEntity_t *re;
- localEntity_t *blood;
-// if ( !cg_blood.integer ) { return; }
-
-
- velocity[0] = velocity[0] * hard * crandom()*460;
- velocity[1] = velocity[1] * hard * crandom()*460;
- velocity[2] = velocity[2] * hard * crandom()*566 + 65;
- blood = CG_SmokePuff( origin, velocity,
- 21, // radius
- 1, 1, 1, 1, // color
- 2450, // trailTime
- cg.time, // startTime
- 0, // fadeInTime
- 0, // flags
- cgs.media.lbldShader1 );
- // use the optimized version
- blood->leType = LE_FALL_SCALE_FADE;
- blood->leType = LE_GORE;
- blood->pos.trType = TR_GRAVITY;
- VectorCopy( velocity, blood->pos.trDelta );
- blood->pos.trDelta[2] = 55;
- if (crandom() < 0.5){
- blood->leMarkType = LEMT_BURN;
- blood->leBounceSoundType = LEBS_BLOOD;
- }
- // VectorCopy( velocity, blood->pos.trDelta );
-
-}
-/*
-==================
-CG_LaunchGib
-==================
-*/
-void CG_LaunchGib( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + 5000 + random() * 3000;
-
- VectorCopy( origin, re->origin );
- AxisCopy( axisDefault, re->axis );
- re->hModel = hModel;
-
- le->pos.trType = TR_GRAVITY;
- VectorCopy( origin, le->pos.trBase );
- VectorCopy( velocity, le->pos.trDelta );
- le->pos.trTime = cg.time;
-
- le->bounceFactor = 0.6f;
-
- le->leBounceSoundType = LEBS_BLOOD;
- le->leMarkType = LEMT_BLOOD;
- if ( cg_leiSuperGoreyAwesome.integer ) {
- CG_SpurtBlood( origin, velocity, 7); // LEILEI toss some extra juice
- CG_SpurtBlood( origin, velocity, 22);
- CG_SpurtBlood( origin, velocity, 11);
- }
-
-}
-
-
-
-
-
-/*
-===================
-CG_GibPlayer
-
-Generated a bunch of gibs launching out from the bodies location
-===================
-*/
-#define GIB_VELOCITY 250
-#define GIB_JUMP 250
-void CG_GibPlayer( vec3_t playerOrigin ) {
- vec3_t origin, velocity;
-
- if ( !cg_blood.integer ) {
- return;
- }
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- if ( rand() & 1 ) {
- CG_LaunchGib( origin, velocity, cgs.media.gibSkull );
- } else {
- CG_LaunchGib( origin, velocity, cgs.media.gibBrain );
- }
-
- // allow gibs to be turned off for speed
- if ( !cg_gibs.integer ) {
- return;
- }
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibAbdomen );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibArm );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibChest );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibFist );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibFoot );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibForearm );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibIntestine );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
-}
-
-/*
-==================
-CG_LaunchGib
-==================
-*/
-void CG_LaunchExplode( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + 10000 + random() * 6000;
-
- VectorCopy( origin, re->origin );
- AxisCopy( axisDefault, re->axis );
- re->hModel = hModel;
-
- le->pos.trType = TR_GRAVITY;
- VectorCopy( origin, le->pos.trBase );
- VectorCopy( velocity, le->pos.trDelta );
- le->pos.trTime = cg.time;
-
- le->bounceFactor = 0.1f;
-
- le->leBounceSoundType = LEBS_BRASS;
- le->leMarkType = LEMT_NONE;
-}
-
-#define EXP_VELOCITY 100
-#define EXP_JUMP 150
-/*
-===================
-CG_GibPlayer
-
-Generated a bunch of gibs launching out from the bodies location
-===================
-*/
-void CG_BigExplosion( vec3_t playerOrigin ) {
- vec3_t origin, velocity;
-
- if ( !cg_blood.integer ) {
- return;
- }
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY;
- velocity[1] = crandom()*EXP_VELOCITY;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY;
- velocity[1] = crandom()*EXP_VELOCITY;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY*1.5;
- velocity[1] = crandom()*EXP_VELOCITY*1.5;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY*2.0;
- velocity[1] = crandom()*EXP_VELOCITY*2.0;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY*2.5;
- velocity[1] = crandom()*EXP_VELOCITY*2.5;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-}
-
-
-
-
-
diff --git a/game/code/cgame/cg_ents.c b/game/code/cgame/cg_ents.c
deleted file mode 100644
index 538053e..0000000
--- a/game/code/cgame/cg_ents.c
+++ /dev/null
@@ -1,1111 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_ents.c -- present snapshot entities, happens every single frame
-
-#include "cg_local.h"
-
-
-/*
-======================
-CG_PositionEntityOnTag
-
-Modifies the entities position and axis by the given
-tag location
-======================
-*/
-void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- qhandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
-
- // lerp the tag
- trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // had to cast away the const to avoid compiler problems...
- MatrixMultiply( lerped.axis, ((refEntity_t *)parent)->axis, entity->axis );
- entity->backlerp = parent->backlerp;
-}
-
-
-/*
-======================
-CG_PositionRotatedEntityOnTag
-
-Modifies the entities position and axis by the given
-tag location
-======================
-*/
-void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- qhandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
- vec3_t tempAxis[3];
-
-//AxisClear( entity->axis );
- // lerp the tag
- trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // had to cast away the const to avoid compiler problems...
- MatrixMultiply( entity->axis, lerped.axis, tempAxis );
- MatrixMultiply( tempAxis, ((refEntity_t *)parent)->axis, entity->axis );
-}
-
-
-
-/*
-==========================================================================
-
-FUNCTIONS CALLED EACH FRAME
-
-==========================================================================
-*/
-
-/*
-======================
-CG_SetEntitySoundPosition
-
-Also called by event processing code
-======================
-*/
-void CG_SetEntitySoundPosition( centity_t *cent ) {
- if ( cent->currentState.solid == SOLID_BMODEL ) {
- vec3_t origin;
- float *v;
-
- v = cgs.inlineModelMidpoints[ cent->currentState.modelindex ];
- VectorAdd( cent->lerpOrigin, v, origin );
- trap_S_UpdateEntityPosition( cent->currentState.number, origin );
- } else {
- trap_S_UpdateEntityPosition( cent->currentState.number, cent->lerpOrigin );
- }
-}
-
-/*
-==================
-CG_EntityEffects
-
-Add continuous entity effects, like local entity emission and lighting
-==================
-*/
-static void CG_EntityEffects( centity_t *cent ) {
-
- // update sound origins
- CG_SetEntitySoundPosition( cent );
-
- // add loop sound
- if ( cent->currentState.loopSound ) {
- if (cent->currentState.eType != ET_SPEAKER) {
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin,
- cgs.gameSounds[ cent->currentState.loopSound ] );
- } else {
- trap_S_AddRealLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin,
- cgs.gameSounds[ cent->currentState.loopSound ] );
- }
- }
-
-
- // constant light glow
- if ( cent->currentState.constantLight ) {
- int cl;
- int i, r, g, b;
-
- cl = cent->currentState.constantLight;
- r = cl & 255;
- g = ( cl >> 8 ) & 255;
- b = ( cl >> 16 ) & 255;
- i = ( ( cl >> 24 ) & 255 ) * 4;
- trap_R_AddLightToScene( cent->lerpOrigin, i, r, g, b );
- }
-
-}
-
-
-/*
-==================
-CG_General
-==================
-*/
-static void CG_General( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
-
- s1 = ¢->currentState;
-
- // if set to invisible, skip
- if (!s1->modelindex) {
- return;
- }
-
- memset (&ent, 0, sizeof(ent));
-
- // set frame
-
- ent.frame = s1->frame;
- ent.oldframe = ent.frame;
- ent.backlerp = 0;
-
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
-
- ent.hModel = cgs.gameModels[s1->modelindex];
-
- // player model
- if (s1->number == cg.snap->ps.clientNum) {
- ent.renderfx |= RF_THIRD_PERSON; // only draw from mirrors
- }
-
- // convert angles to axis
- AnglesToAxis( cent->lerpAngles, ent.axis );
-
- // add to refresh list
- trap_R_AddRefEntityToScene (&ent);
-}
-
-/*
-==================
-CG_Speaker
-
-Speaker entities can automatically play sounds
-==================
-*/
-static void CG_Speaker( centity_t *cent ) {
- if ( ! cent->currentState.clientNum ) { // FIXME: use something other than clientNum...
- return; // not auto triggering
- }
-
- if ( cg.time < cent->miscTime ) {
- return;
- }
-
- trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.gameSounds[cent->currentState.eventParm] );
-
- // ent->s.frame = ent->wait * 10;
- // ent->s.clientNum = ent->random * 10;
- cent->miscTime = cg.time + cent->currentState.frame * 100 + cent->currentState.clientNum * 100 * crandom();
-}
-
-/*
-==================
-CG_Item
-==================
-*/
-static void CG_Item( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *es;
- gitem_t *item;
- int msec;
- float frac;
- float scale;
- weaponInfo_t *wi;
-
- es = ¢->currentState;
- if ( es->modelindex >= bg_numItems ) {
- CG_Error( "Bad item index %i on entity", es->modelindex );
- }
-
- // if set to invisible, skip
- if ( !es->modelindex || ( es->eFlags & EF_NODRAW ) ) {
- return;
- }
-
- item = &bg_itemlist[ es->modelindex ];
- if ( cg_simpleItems.integer && item->giType != IT_TEAM ) {
- memset( &ent, 0, sizeof( ent ) );
- ent.reType = RT_SPRITE;
- VectorCopy( cent->lerpOrigin, ent.origin );
- ent.radius = 14;
- ent.customShader = cg_items[es->modelindex].icon;
- ent.shaderRGBA[0] = 255;
- ent.shaderRGBA[1] = 255;
- ent.shaderRGBA[2] = 255;
- ent.shaderRGBA[3] = 255;
- trap_R_AddRefEntityToScene(&ent);
- return;
- }
-
- // items bob up and down continuously
- scale = 0.005 + cent->currentState.number * 0.00001;
- cent->lerpOrigin[2] += 4 + cos( ( cg.time + 1000 ) * scale ) * 4;
-
- memset (&ent, 0, sizeof(ent));
-
- // autorotate at one of two speeds
- if ( item->giType == IT_HEALTH ) {
- VectorCopy( cg.autoAnglesFast, cent->lerpAngles );
- AxisCopy( cg.autoAxisFast, ent.axis );
- } else {
- VectorCopy( cg.autoAngles, cent->lerpAngles );
- AxisCopy( cg.autoAxis, ent.axis );
- }
-
- wi = NULL;
- // the weapons have their origin where they attatch to player
- // models, so we need to offset them or they will rotate
- // eccentricly
- if ( item->giType == IT_WEAPON ) {
- wi = &cg_weapons[item->giTag];
- cent->lerpOrigin[0] -=
- wi->weaponMidpoint[0] * ent.axis[0][0] +
- wi->weaponMidpoint[1] * ent.axis[1][0] +
- wi->weaponMidpoint[2] * ent.axis[2][0];
- cent->lerpOrigin[1] -=
- wi->weaponMidpoint[0] * ent.axis[0][1] +
- wi->weaponMidpoint[1] * ent.axis[1][1] +
- wi->weaponMidpoint[2] * ent.axis[2][1];
- cent->lerpOrigin[2] -=
- wi->weaponMidpoint[0] * ent.axis[0][2] +
- wi->weaponMidpoint[1] * ent.axis[1][2] +
- wi->weaponMidpoint[2] * ent.axis[2][2];
-
- cent->lerpOrigin[2] += 8; // an extra height boost
- }
-
- ent.hModel = cg_items[es->modelindex].models[0];
-
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
-
- ent.nonNormalizedAxes = qfalse;
-
- // if just respawned, slowly scale up
- msec = cg.time - cent->miscTime;
- if ( msec >= 0 && msec < ITEM_SCALEUP_TIME ) {
- frac = (float)msec / ITEM_SCALEUP_TIME;
- VectorScale( ent.axis[0], frac, ent.axis[0] );
- VectorScale( ent.axis[1], frac, ent.axis[1] );
- VectorScale( ent.axis[2], frac, ent.axis[2] );
- ent.nonNormalizedAxes = qtrue;
- } else {
- frac = 1.0;
- }
-
- // items without glow textures need to keep a minimum light value
- // so they are always visible
- if ( ( item->giType == IT_WEAPON ) ||
- ( item->giType == IT_ARMOR ) ) {
- ent.renderfx |= RF_MINLIGHT;
- }
-
- // increase the size of the weapons when they are presented as items
- if ( item->giType == IT_WEAPON ) {
- VectorScale( ent.axis[0], 1.5, ent.axis[0] );
- VectorScale( ent.axis[1], 1.5, ent.axis[1] );
- VectorScale( ent.axis[2], 1.5, ent.axis[2] );
- ent.nonNormalizedAxes = qtrue;
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.weaponHoverSound );
- }
-
- if ( item->giType == IT_HOLDABLE && item->giTag == HI_KAMIKAZE ) {
- VectorScale( ent.axis[0], 2, ent.axis[0] );
- VectorScale( ent.axis[1], 2, ent.axis[1] );
- VectorScale( ent.axis[2], 2, ent.axis[2] );
- ent.nonNormalizedAxes = qtrue;
- }
-
- // add to refresh list
- trap_R_AddRefEntityToScene(&ent);
-
- if ( item->giType == IT_WEAPON && wi->barrelModel ) {
- refEntity_t barrel;
-
- memset( &barrel, 0, sizeof( barrel ) );
-
- barrel.hModel = wi->barrelModel;
-
- VectorCopy( ent.lightingOrigin, barrel.lightingOrigin );
- barrel.shadowPlane = ent.shadowPlane;
- barrel.renderfx = ent.renderfx;
-
- CG_PositionRotatedEntityOnTag( &barrel, &ent, wi->weaponModel, "tag_barrel" );
-
- AxisCopy( ent.axis, barrel.axis );
- barrel.nonNormalizedAxes = ent.nonNormalizedAxes;
-
- trap_R_AddRefEntityToScene( &barrel );
- }
-
- // accompanying rings / spheres for powerups
- if ( !cg_simpleItems.integer )
- {
- vec3_t spinAngles;
-
- VectorClear( spinAngles );
-
- if ( item->giType == IT_HEALTH || item->giType == IT_POWERUP )
- {
- if ( ( ent.hModel = cg_items[es->modelindex].models[1] ) != 0 )
- {
- if ( item->giType == IT_POWERUP )
- {
- ent.origin[2] += 12;
- spinAngles[1] = ( cg.time & 1023 ) * 360 / -1024.0f;
- }
- AnglesToAxis( spinAngles, ent.axis );
-
- // scale up if respawning
- if ( frac != 1.0 ) {
- VectorScale( ent.axis[0], frac, ent.axis[0] );
- VectorScale( ent.axis[1], frac, ent.axis[1] );
- VectorScale( ent.axis[2], frac, ent.axis[2] );
- ent.nonNormalizedAxes = qtrue;
- }
- trap_R_AddRefEntityToScene( &ent );
- }
- }
- }
-}
-
-//============================================================================
-
-/*
-===============
-CG_Missile
-===============
-*/
-static void CG_Missile( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
- const weaponInfo_t *weapon;
-// int col;
-
- s1 = ¢->currentState;
- if ( s1->weapon > WP_NUM_WEAPONS ) {
- s1->weapon = 0;
- }
- weapon = &cg_weapons[s1->weapon];
-
- // calculate the axis
- VectorCopy( s1->angles, cent->lerpAngles);
-
- // add trails
- if ( weapon->missileTrailFunc )
- {
- weapon->missileTrailFunc( cent, weapon );
- }
-/*
- if ( cent->currentState.modelindex == TEAM_RED ) {
- col = 1;
- }
- else if ( cent->currentState.modelindex == TEAM_BLUE ) {
- col = 2;
- }
- else {
- col = 0;
- }
-
- // add dynamic light
- if ( weapon->missileDlight ) {
- trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight,
- weapon->missileDlightColor[col][0], weapon->missileDlightColor[col][1], weapon->missileDlightColor[col][2] );
- }
-*/
- // add dynamic light
- if ( weapon->missileDlight ) {
- trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight,
- weapon->missileDlightColor[0], weapon->missileDlightColor[1], weapon->missileDlightColor[2] );
- }
-
- // add missile sound
- if ( weapon->missileSound ) {
- vec3_t velocity;
-
- BG_EvaluateTrajectoryDelta( ¢->currentState.pos, cg.time, velocity );
-
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, weapon->missileSound );
- }
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
-
- if ( cent->currentState.weapon == WP_PLASMAGUN ) {
- ent.reType = RT_SPRITE;
- ent.radius = 16;
- ent.rotation = 0;
- ent.customShader = cgs.media.plasmaBallShader;
- trap_R_AddRefEntityToScene( &ent );
- return;
- }
-
- // flicker between two skins
- ent.skinNum = cg.clientFrame & 1;
- ent.hModel = weapon->missileModel;
- ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
-
-//#ifdef MISSIONPACK
- if ( cent->currentState.weapon == WP_PROX_LAUNCHER ) {
- if (s1->generic1 == TEAM_BLUE) {
- ent.hModel = cgs.media.blueProxMine;
- }
- }
-//#endif
-
- // convert direction of travel into axis
- if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {
- ent.axis[0][2] = 1;
- }
-
- // spin as it moves
- if ( s1->pos.trType != TR_STATIONARY ) {
- RotateAroundDirection( ent.axis, cg.time / 4 );
- } else {
-//#ifdef MISSIONPACK
- if ( s1->weapon == WP_PROX_LAUNCHER ) {
- AnglesToAxis( cent->lerpAngles, ent.axis );
- }
- else
-//#endif
- {
- RotateAroundDirection( ent.axis, s1->time );
- }
- }
-
- // add to refresh list, possibly with quad glow
- CG_AddRefEntityWithPowerups( &ent, s1, TEAM_FREE );
-}
-
-/*
-===============
-CG_Grapple
-
-This is called when the grapple is sitting up against the wall
-===============
-*/
-static void CG_Grapple( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
- const weaponInfo_t *weapon;
-
- s1 = ¢->currentState;
- if ( s1->weapon > WP_NUM_WEAPONS ) {
- s1->weapon = 0;
- }
- weapon = &cg_weapons[s1->weapon];
-
- // calculate the axis
- VectorCopy( s1->angles, cent->lerpAngles);
-
-#if 0 // FIXME add grapple pull sound here..?
- // add missile sound
- if ( weapon->missileSound ) {
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->missileSound );
- }
-#endif
-
- // Will draw cable if needed
- CG_GrappleTrail ( cent, weapon );
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
-
- // flicker between two skins
- ent.skinNum = cg.clientFrame & 1;
- ent.hModel = weapon->missileModel;
- ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
-
- // convert direction of travel into axis
- if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {
- ent.axis[0][2] = 1;
- }
-
- trap_R_AddRefEntityToScene( &ent );
-}
-
-/*
-===============
-CG_Mover
-===============
-*/
-static void CG_Mover( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
-
- s1 = ¢->currentState;
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
- AnglesToAxis( cent->lerpAngles, ent.axis );
-
- ent.renderfx = RF_NOSHADOW;
-
- // flicker between two skins (FIXME?)
- ent.skinNum = ( cg.time >> 6 ) & 1;
-
- // get the model, either as a bmodel or a modelindex
- if ( s1->solid == SOLID_BMODEL ) {
- ent.hModel = cgs.inlineDrawModel[s1->modelindex];
- } else {
- ent.hModel = cgs.gameModels[s1->modelindex];
- }
-
- // add to refresh list
- trap_R_AddRefEntityToScene(&ent);
-
- // add the secondary model
- if ( s1->modelindex2 ) {
- ent.skinNum = 0;
- ent.hModel = cgs.gameModels[s1->modelindex2];
- trap_R_AddRefEntityToScene(&ent);
- }
-
-}
-
-/*
-===============
-CG_Beam
-
-Also called as an event
-===============
-*/
-void CG_Beam( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
-
- s1 = ¢->currentState;
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( s1->pos.trBase, ent.origin );
- VectorCopy( s1->origin2, ent.oldorigin );
- AxisClear( ent.axis );
- ent.reType = RT_BEAM;
-
- ent.renderfx = RF_NOSHADOW;
-
- // add to refresh list
- trap_R_AddRefEntityToScene(&ent);
-}
-
-
-/*
-===============
-CG_Portal
-===============
-*/
-static void CG_Portal( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
-
- s1 = ¢->currentState;
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( cent->lerpOrigin, ent.origin );
- VectorCopy( s1->origin2, ent.oldorigin );
- ByteToDir( s1->eventParm, ent.axis[0] );
- PerpendicularVector( ent.axis[1], ent.axis[0] );
-
- // negating this tends to get the directions like they want
- // we really should have a camera roll value
- VectorSubtract( vec3_origin, ent.axis[1], ent.axis[1] );
-
- CrossProduct( ent.axis[0], ent.axis[1], ent.axis[2] );
- ent.reType = RT_PORTALSURFACE;
- ent.oldframe = s1->powerups;
- ent.frame = s1->frame; // rotation speed
- ent.skinNum = s1->clientNum/256.0 * 360; // roll offset
-
- // add to refresh list
- trap_R_AddRefEntityToScene(&ent);
-}
-
-
-/*
-=========================
-CG_AdjustPositionForMover
-
-Also called by client movement prediction code
-=========================
-*/
-void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out ) {
- centity_t *cent;
- vec3_t oldOrigin, origin, deltaOrigin;
- vec3_t oldAngles, angles, deltaAngles;
-
- if ( moverNum <= 0 || moverNum >= ENTITYNUM_MAX_NORMAL ) {
- VectorCopy( in, out );
- return;
- }
-
- cent = &cg_entities[ moverNum ];
- if ( cent->currentState.eType != ET_MOVER ) {
- VectorCopy( in, out );
- return;
- }
-
- BG_EvaluateTrajectory( ¢->currentState.pos, fromTime, oldOrigin );
- BG_EvaluateTrajectory( ¢->currentState.apos, fromTime, oldAngles );
-
- BG_EvaluateTrajectory( ¢->currentState.pos, toTime, origin );
- BG_EvaluateTrajectory( ¢->currentState.apos, toTime, angles );
-
- VectorSubtract( origin, oldOrigin, deltaOrigin );
- VectorSubtract( angles, oldAngles, deltaAngles );
-
- VectorAdd( in, deltaOrigin, out );
-
- // FIXME: origin change when on a rotating object
-}
-
-
-/*
-=============================
-CG_InterpolateEntityPosition
-=============================
-*/
-static void CG_InterpolateEntityPosition( centity_t *cent ) {
- vec3_t current, next;
- float f;
-
- // it would be an internal error to find an entity that interpolates without
- // a snapshot ahead of the current one
- if ( cg.nextSnap == NULL ) {
- CG_Error( "CG_InterpoateEntityPosition: cg.nextSnap == NULL" );
- }
-
- f = cg.frameInterpolation;
-
- // this will linearize a sine or parabolic curve, but it is important
- // to not extrapolate player positions if more recent data is available
- BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, current );
- BG_EvaluateTrajectory( ¢->nextState.pos, cg.nextSnap->serverTime, next );
-
- cent->lerpOrigin[0] = current[0] + f * ( next[0] - current[0] );
- cent->lerpOrigin[1] = current[1] + f * ( next[1] - current[1] );
- cent->lerpOrigin[2] = current[2] + f * ( next[2] - current[2] );
-
- BG_EvaluateTrajectory( ¢->currentState.apos, cg.snap->serverTime, current );
- BG_EvaluateTrajectory( ¢->nextState.apos, cg.nextSnap->serverTime, next );
-
- cent->lerpAngles[0] = LerpAngle( current[0], next[0], f );
- cent->lerpAngles[1] = LerpAngle( current[1], next[1], f );
- cent->lerpAngles[2] = LerpAngle( current[2], next[2], f );
-
-}
-
-/*
-===============
-CG_CalcEntityLerpPositions
-
-===============
-*/
-static void CG_CalcEntityLerpPositions( centity_t *cent ) {
-
-//unlagged - projectile nudge
- // this will be set to how far forward projectiles will be extrapolated
- int timeshift = 0;
-//unlagged - projectile nudge
-
-//unlagged - smooth clients #2
- // this is done server-side now - cg_smoothClients is undefined
- // players will always be TR_INTERPOLATE
-/*
- // if this player does not want to see extrapolated players
- if ( !cg_smoothClients.integer ) {
- // make sure the clients use TR_INTERPOLATE
- if ( cent->currentState.number < MAX_CLIENTS ) {
- cent->currentState.pos.trType = TR_INTERPOLATE;
- cent->nextState.pos.trType = TR_INTERPOLATE;
- }
- }
-*/
-//unlagged - smooth clients #2
-
- if ( cent->interpolate && cent->currentState.pos.trType == TR_INTERPOLATE ) {
- CG_InterpolateEntityPosition( cent );
- return;
- }
-
- // first see if we can interpolate between two snaps for
- // linear extrapolated clients
- if ( cent->interpolate && cent->currentState.pos.trType == TR_LINEAR_STOP &&
- cent->currentState.number < MAX_CLIENTS) {
- CG_InterpolateEntityPosition( cent );
- return;
- }
-
-//unlagged - timenudge extrapolation
- // interpolating failed (probably no nextSnap), so extrapolate
- // this can also happen if the teleport bit is flipped, but that
- // won't be noticeable
- if ( cent->currentState.number < MAX_CLIENTS &&
- cent->currentState.clientNum != cg.predictedPlayerState.clientNum ) {
- cent->currentState.pos.trType = TR_LINEAR_STOP;
- cent->currentState.pos.trTime = cg.snap->serverTime;
- cent->currentState.pos.trDuration = 1000 / sv_fps.integer;
- }
-//unlagged - timenudge extrapolation
-
-//unlagged - projectile nudge
- // if it's a missile but not a grappling hook
- if ( cent->currentState.eType == ET_MISSILE && cent->currentState.weapon != WP_GRAPPLING_HOOK ) {
- // if it's one of ours
- if ( cent->currentState.otherEntityNum == cg.clientNum ) {
- // extrapolate one server frame's worth - this will correct for tiny
- // visual inconsistencies introduced by backward-reconciling all players
- // one server frame before running projectiles
- timeshift = 1000 / sv_fps.integer;
- }
- // if it's not, and it's not a grenade launcher
- else if ( cent->currentState.weapon != WP_GRENADE_LAUNCHER ) {
- // extrapolate based on cg_projectileNudge
- timeshift = cg_projectileNudge.integer + 1000 / sv_fps.integer;
- }
- }
-
- // just use the current frame and evaluate as best we can
-// BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin );
-// BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles );
- BG_EvaluateTrajectory( ¢->currentState.pos, cg.time + timeshift, cent->lerpOrigin );
- BG_EvaluateTrajectory( ¢->currentState.apos, cg.time + timeshift, cent->lerpAngles );
-
- // if there's a time shift
- if ( timeshift != 0 ) {
- trace_t tr;
- vec3_t lastOrigin;
-
- BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, lastOrigin );
-
- CG_Trace( &tr, lastOrigin, vec3_origin, vec3_origin, cent->lerpOrigin, cent->currentState.number, MASK_SHOT );
-
- // don't let the projectile go through the floor
- if ( tr.fraction < 1.0f ) {
- cent->lerpOrigin[0] = lastOrigin[0] + tr.fraction * ( cent->lerpOrigin[0] - lastOrigin[0] );
- cent->lerpOrigin[1] = lastOrigin[1] + tr.fraction * ( cent->lerpOrigin[1] - lastOrigin[1] );
- cent->lerpOrigin[2] = lastOrigin[2] + tr.fraction * ( cent->lerpOrigin[2] - lastOrigin[2] );
- }
- }
-//unlagged - projectile nudge
-
- // adjust for riding a mover if it wasn't rolled into the predicted
- // player state
- if ( cent != &cg.predictedPlayerEntity ) {
- CG_AdjustPositionForMover( cent->lerpOrigin, cent->currentState.groundEntityNum,
- cg.snap->serverTime, cg.time, cent->lerpOrigin );
- }
-}
-
-/*
-===============
-CG_TeamBase
-===============
-*/
-static void CG_TeamBase( centity_t *cent ) {
- refEntity_t model;
-//#ifdef MISSIONPACK
- vec3_t angles;
- int t, h;
- float c;
-
- if ( cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF ) {
-//#else
-// if ( cgs.gametype == GT_CTF) {
-//#endif
- // show the flag base
- memset(&model, 0, sizeof(model));
- model.reType = RT_MODEL;
- VectorCopy( cent->lerpOrigin, model.lightingOrigin );
- VectorCopy( cent->lerpOrigin, model.origin );
- AnglesToAxis( cent->currentState.angles, model.axis );
- if ( cent->currentState.modelindex == TEAM_RED ) {
- model.hModel = cgs.media.redFlagBaseModel;
- }
- else if ( cent->currentState.modelindex == TEAM_BLUE ) {
- model.hModel = cgs.media.blueFlagBaseModel;
- }
- else {
- model.hModel = cgs.media.neutralFlagBaseModel;
- }
- trap_R_AddRefEntityToScene( &model );
- }
-//#ifdef MISSIONPACK
- else if ( cgs.gametype == GT_OBELISK ) {
- // show the obelisk
- memset(&model, 0, sizeof(model));
- model.reType = RT_MODEL;
- VectorCopy( cent->lerpOrigin, model.lightingOrigin );
- VectorCopy( cent->lerpOrigin, model.origin );
- AnglesToAxis( cent->currentState.angles, model.axis );
-
- model.hModel = cgs.media.overloadBaseModel;
- trap_R_AddRefEntityToScene( &model );
- // if hit
- if ( cent->currentState.frame == 1) {
- // show hit model
- // modelindex2 is the health value of the obelisk
- c = cent->currentState.modelindex2;
- model.shaderRGBA[0] = 0xff;
- model.shaderRGBA[1] = c;
- model.shaderRGBA[2] = c;
- model.shaderRGBA[3] = 0xff;
- //
- model.hModel = cgs.media.overloadEnergyModel;
- trap_R_AddRefEntityToScene( &model );
- }
- // if respawning
- if ( cent->currentState.frame == 2) {
- if ( !cent->miscTime ) {
- cent->miscTime = cg.time;
- }
- t = cg.time - cent->miscTime;
- h = (cg_obeliskRespawnDelay.integer - 5) * 1000;
- //
- if (t > h) {
- c = (float) (t - h) / h;
- if (c > 1)
- c = 1;
- }
- else {
- c = 0;
- }
- // show the lights
- AnglesToAxis( cent->currentState.angles, model.axis );
- //
- model.shaderRGBA[0] = c * 0xff;
- model.shaderRGBA[1] = c * 0xff;
- model.shaderRGBA[2] = c * 0xff;
- model.shaderRGBA[3] = c * 0xff;
-
- model.hModel = cgs.media.overloadLightsModel;
- trap_R_AddRefEntityToScene( &model );
- // show the target
- if (t > h) {
- if ( !cent->muzzleFlashTime ) {
- trap_S_StartSound (cent->lerpOrigin, ENTITYNUM_NONE, CHAN_BODY, cgs.media.obeliskRespawnSound);
- cent->muzzleFlashTime = 1;
- }
- VectorCopy(cent->currentState.angles, angles);
- angles[YAW] += (float) 16 * acos(1-c) * 180 / M_PI;
- AnglesToAxis( angles, model.axis );
-
- VectorScale( model.axis[0], c, model.axis[0]);
- VectorScale( model.axis[1], c, model.axis[1]);
- VectorScale( model.axis[2], c, model.axis[2]);
-
- model.shaderRGBA[0] = 0xff;
- model.shaderRGBA[1] = 0xff;
- model.shaderRGBA[2] = 0xff;
- model.shaderRGBA[3] = 0xff;
- //
- model.origin[2] += 56;
- model.hModel = cgs.media.overloadTargetModel;
- trap_R_AddRefEntityToScene( &model );
- }
- else {
- //FIXME: show animated smoke
- }
- }
- else {
- cent->miscTime = 0;
- cent->muzzleFlashTime = 0;
- // modelindex2 is the health value of the obelisk
- c = cent->currentState.modelindex2;
- model.shaderRGBA[0] = 0xff;
- model.shaderRGBA[1] = c;
- model.shaderRGBA[2] = c;
- model.shaderRGBA[3] = 0xff;
- // show the lights
- model.hModel = cgs.media.overloadLightsModel;
- trap_R_AddRefEntityToScene( &model );
- // show the target
- model.origin[2] += 56;
- model.hModel = cgs.media.overloadTargetModel;
- trap_R_AddRefEntityToScene( &model );
- }
- }
- else if ( cgs.gametype == GT_HARVESTER ) {
- // show harvester model
- memset(&model, 0, sizeof(model));
- model.reType = RT_MODEL;
- VectorCopy( cent->lerpOrigin, model.lightingOrigin );
- VectorCopy( cent->lerpOrigin, model.origin );
- AnglesToAxis( cent->currentState.angles, model.axis );
-
- if ( cent->currentState.modelindex == TEAM_RED ) {
- model.hModel = cgs.media.harvesterModel;
- model.customSkin = cgs.media.harvesterRedSkin;
- }
- else if ( cent->currentState.modelindex == TEAM_BLUE ) {
- model.hModel = cgs.media.harvesterModel;
- model.customSkin = cgs.media.harvesterBlueSkin;
- }
- else {
- model.hModel = cgs.media.harvesterNeutralModel;
- model.customSkin = 0;
- }
- trap_R_AddRefEntityToScene( &model );
- }
-//#endif
-}
-
-/*
-===============
-CG_AddCEntity
-
-===============
-*/
-static void CG_AddCEntity( centity_t *cent ) {
- // event-only entities will have been dealt with already
- if ( cent->currentState.eType >= ET_EVENTS ) {
- return;
- }
-
- // calculate the current origin
- CG_CalcEntityLerpPositions( cent );
-
- // add automatic effects
- CG_EntityEffects( cent );
-
- switch ( cent->currentState.eType ) {
- default:
- CG_Error( "Bad entity type: %i\n", cent->currentState.eType );
- break;
- case ET_INVISIBLE:
- case ET_PUSH_TRIGGER:
- case ET_TELEPORT_TRIGGER:
- break;
- case ET_GENERAL:
- CG_General( cent );
- break;
- case ET_PLAYER:
- CG_Player( cent );
- break;
- case ET_ITEM:
- CG_Item( cent );
- break;
- case ET_MISSILE:
- CG_Missile( cent );
- break;
- case ET_MOVER:
- CG_Mover( cent );
- break;
- case ET_BEAM:
- CG_Beam( cent );
- break;
- case ET_PORTAL:
- CG_Portal( cent );
- break;
- case ET_SPEAKER:
- CG_Speaker( cent );
- break;
- case ET_GRAPPLE:
- CG_Grapple( cent );
- break;
- case ET_TEAM:
- CG_TeamBase( cent );
- break;
- }
-}
-
-/*
-===============
-CG_AddPacketEntities
-
-===============
-*/
-void CG_AddPacketEntities( void ) {
- int num;
- centity_t *cent;
- playerState_t *ps;
-
- // set cg.frameInterpolation
- if ( cg.nextSnap ) {
- int delta;
-
- delta = (cg.nextSnap->serverTime - cg.snap->serverTime);
- if ( delta == 0 ) {
- cg.frameInterpolation = 0;
- } else {
- cg.frameInterpolation = (float)( cg.time - cg.snap->serverTime ) / delta;
- }
- } else {
- cg.frameInterpolation = 0; // actually, it should never be used, because
- // no entities should be marked as interpolating
- }
-
- // the auto-rotating items will all have the same axis
- cg.autoAngles[0] = 0;
- cg.autoAngles[1] = ( cg.time & 2047 ) * 360 / 2048.0;
- cg.autoAngles[2] = 0;
-
- cg.autoAnglesFast[0] = 0;
- cg.autoAnglesFast[1] = ( cg.time & 1023 ) * 360 / 1024.0f;
- cg.autoAnglesFast[2] = 0;
-
- AnglesToAxis( cg.autoAngles, cg.autoAxis );
- AnglesToAxis( cg.autoAnglesFast, cg.autoAxisFast );
-
- // generate and add the entity from the playerstate
- ps = &cg.predictedPlayerState;
- BG_PlayerStateToEntityState( ps, &cg.predictedPlayerEntity.currentState, qfalse );
- CG_AddCEntity( &cg.predictedPlayerEntity );
-
- // lerp the non-predicted value for lightning gun origins
- CG_CalcEntityLerpPositions( &cg_entities[ cg.snap->ps.clientNum ] );
-
-//unlagged - early transitioning
- if ( cg.nextSnap ) {
- // pre-add some of the entities sent over by the server
- // we have data for them and they don't need to interpolate
- for ( num = 0 ; num < cg.nextSnap->numEntities ; num++ ) {
- cent = &cg_entities[ cg.nextSnap->entities[ num ].number ];
- if ( cent->nextState.eType == ET_MISSILE || cent->nextState.eType == ET_GENERAL ) {
- // transition it immediately and add it
- CG_TransitionEntity( cent );
- cent->interpolate = qtrue;
- CG_AddCEntity( cent );
- }
- }
- }
-//unlagged - early transitioning
-
- // add each entity sent over by the server
- for ( num = 0 ; num < cg.snap->numEntities ; num++ ) {
- cent = &cg_entities[ cg.snap->entities[ num ].number ];
-//unlagged - early transitioning
- if ( !cg.nextSnap || (cent->nextState.eType != ET_MISSILE && cent->nextState.eType != ET_GENERAL) ) {
-//unlagged - early transitioning
- CG_AddCEntity( cent );
- } //Also unlagged
- }
-}
-
diff --git a/game/code/cgame/cg_event.c b/game/code/cgame/cg_event.c
deleted file mode 100644
index fc87265..0000000
--- a/game/code/cgame/cg_event.c
+++ /dev/null
@@ -1,1283 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_event.c -- handle entity events at snapshot or playerstate transitions
-
-#include "cg_local.h"
-
-// for the voice chats
-#ifdef MISSIONPACK // bk001205
-#include "../../ui/menudef.h"
-#endif
-//==========================================================================
-
-/*
-===================
-CG_PlaceString
-
-Also called by scoreboard drawing
-===================
-*/
-const char *CG_PlaceString( int rank ) {
- static char str[64];
- char *s, *t;
-
- if ( rank & RANK_TIED_FLAG ) {
- rank &= ~RANK_TIED_FLAG;
- t = "Tied for ";
- } else {
- t = "";
- }
-
- if ( rank == 1 ) {
- s = S_COLOR_BLUE "1st" S_COLOR_WHITE; // draw in blue
- } else if ( rank == 2 ) {
- s = S_COLOR_RED "2nd" S_COLOR_WHITE; // draw in red
- } else if ( rank == 3 ) {
- s = S_COLOR_YELLOW "3rd" S_COLOR_WHITE; // draw in yellow
- } else if ( rank == 11 ) {
- s = "11th";
- } else if ( rank == 12 ) {
- s = "12th";
- } else if ( rank == 13 ) {
- s = "13th";
- } else if ( rank % 10 == 1 ) {
- s = va("%ist", rank);
- } else if ( rank % 10 == 2 ) {
- s = va("%ind", rank);
- } else if ( rank % 10 == 3 ) {
- s = va("%ird", rank);
- } else {
- s = va("%ith", rank);
- }
-
- Com_sprintf( str, sizeof( str ), "%s%s", t, s );
- return str;
-}
-
-/*
-=============
-CG_Obituary
-=============
-*/
-static void CG_Obituary( entityState_t *ent ) {
- int mod;
- int target, attacker;
- char *message;
- char *message2;
- const char *targetInfo;
- const char *attackerInfo;
- char targetName[32];
- char attackerName[32];
- gender_t gender;
- clientInfo_t *ci;
-
- target = ent->otherEntityNum;
- attacker = ent->otherEntityNum2;
- mod = ent->eventParm;
-
- if ( target < 0 || target >= MAX_CLIENTS ) {
- CG_Error( "CG_Obituary: target out of range" );
- }
- ci = &cgs.clientinfo[target];
-
- if ( attacker < 0 || attacker >= MAX_CLIENTS ) {
- attacker = ENTITYNUM_WORLD;
- attackerInfo = NULL;
- } else {
- attackerInfo = CG_ConfigString( CS_PLAYERS + attacker );
- }
-
- targetInfo = CG_ConfigString( CS_PLAYERS + target );
- if ( !targetInfo ) {
- return;
- }
- Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof(targetName) - 2);
- strcat( targetName, S_COLOR_WHITE );
-
- message2 = "";
-
- // check for single client messages
-
- if(attacker != ENTITYNUM_WORLD)
- message = NULL;
- else
- switch( mod ) {
- case MOD_SUICIDE:
- message = "suicides";
- break;
- case MOD_FALLING:
- message = "cratered";
- break;
- case MOD_CRUSH:
- message = "was squished";
- break;
- case MOD_WATER:
- message = "sank like a rock";
- break;
- case MOD_SLIME:
- message = "melted";
- break;
- case MOD_LAVA:
- message = "does a back flip into the lava";
- break;
- case MOD_TARGET_LASER:
- message = "saw the light";
- break;
- case MOD_TRIGGER_HURT:
- message = "was in the wrong place";
- break;
- default:
- message = NULL;
- break;
- }
-
- if (attacker == target) {
- gender = ci->gender;
- switch (mod) {
- case MOD_KAMIKAZE:
- message = "goes out with a bang";
- break;
- case MOD_GRENADE_SPLASH:
- if ( gender == GENDER_FEMALE )
- message = "tripped on her own grenade";
- else if ( gender == GENDER_NEUTER )
- message = "tripped on its own grenade";
- else
- message = "tripped on his own grenade";
- break;
- case MOD_ROCKET_SPLASH:
- if ( gender == GENDER_FEMALE )
- message = "blew herself up";
- else if ( gender == GENDER_NEUTER )
- message = "blew itself up";
- else
- message = "blew himself up";
- break;
- case MOD_PLASMA_SPLASH:
- if ( gender == GENDER_FEMALE )
- message = "melted herself";
- else if ( gender == GENDER_NEUTER )
- message = "melted itself";
- else
- message = "melted himself";
- break;
- case MOD_BFG_SPLASH:
- message = "should have used a smaller gun";
- break;
- case MOD_PROXIMITY_MINE:
- if( gender == GENDER_FEMALE ) {
- message = "found her prox mine";
- } else if ( gender == GENDER_NEUTER ) {
- message = "found it's prox mine";
- } else {
- message = "found his prox mine";
- }
- break;
- default:
- if ( gender == GENDER_FEMALE )
- message = "killed herself";
- else if ( gender == GENDER_NEUTER )
- message = "killed itself";
- else
- message = "killed himself";
- break;
- }
- }
-
- //If a suicide happens while disconnecting then we might not have a targetName
- if (message && strlen(targetName)) {
- CG_Printf( "%s %s.\n", targetName, message);
- return;
- }
-
-
- // check for kill messages from the current clientNum
- if ( attacker == cg.snap->ps.clientNum ) {
- char *s;
-
- if ( cgs.gametype < GT_TEAM ) {
- s = va("You fragged %s\n%s place with %i", targetName,
- CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
- cg.snap->ps.persistant[PERS_SCORE] );
- } else {
- if(ent->generic1)
- s = va("You fragged your ^1TEAMMATE^7 %s", targetName );
- else
- s = va("You fragged %s", targetName );
- }
-#ifdef MISSIONPACK
- if (!(cg_singlePlayerActive.integer && cg_cameraOrbit.integer)) {
- CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, (int)(BIGCHAR_WIDTH * cg_fragmsgsize.value) );
- }
-#else
- CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, (int)(BIGCHAR_WIDTH * cg_fragmsgsize.value) );
-#endif
-
- // print the text message as well
- }
-
- // check for double client messages
- if ( !attackerInfo ) {
- attacker = ENTITYNUM_WORLD;
- strcpy( attackerName, "noname" );
- } else {
- Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof(attackerName) - 2);
- strcat( attackerName, S_COLOR_WHITE );
- // check for kill messages about the current clientNum
- if ( target == cg.snap->ps.clientNum ) {
- Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) );
- }
- }
-
- if ( attacker != ENTITYNUM_WORLD ) {
-
- if(ent->generic1) {
- message = "was killed by ^1TEAMMATE^7";
- }
- else
- switch (mod) {
- case MOD_GRAPPLE:
- message = "was caught by";
- break;
- case MOD_GAUNTLET:
- message = "was pummeled by";
- break;
- case MOD_MACHINEGUN:
- message = "was machinegunned by";
- break;
- case MOD_SHOTGUN:
- message = "was gunned down by";
- break;
- case MOD_GRENADE:
- message = "ate";
- message2 = "'s grenade";
- break;
- case MOD_GRENADE_SPLASH:
- message = "was shredded by";
- message2 = "'s shrapnel";
- break;
- case MOD_ROCKET:
- message = "ate";
- message2 = "'s rocket";
- break;
- case MOD_ROCKET_SPLASH:
- message = "almost dodged";
- message2 = "'s rocket";
- break;
- case MOD_PLASMA:
- message = "was melted by";
- message2 = "'s plasmagun";
- break;
- case MOD_PLASMA_SPLASH:
- message = "was melted by";
- message2 = "'s plasmagun";
- break;
- case MOD_RAILGUN:
- message = "was railed by";
- break;
- case MOD_LIGHTNING:
- message = "was electrocuted by";
- break;
- case MOD_BFG:
- case MOD_BFG_SPLASH:
- message = "was blasted by";
- message2 = "'s BFG";
- break;
- case MOD_NAIL:
- message = "was nailed by";
- break;
- case MOD_CHAINGUN:
- message = "got lead poisoning from";
- message2 = "'s Chaingun";
- break;
- case MOD_PROXIMITY_MINE:
- message = "was too close to";
- message2 = "'s Prox Mine";
- break;
- case MOD_KAMIKAZE:
- message = "falls to";
- message2 = "'s Kamikaze blast";
- break;
- case MOD_JUICED:
- message = "was juiced by";
- break;
- case MOD_TELEFRAG:
- message = "tried to invade";
- message2 = "'s personal space";
- break;
- case MOD_LAVA:
- message = "was given a hot bath by";
- break;
- case MOD_SLIME:
- message = "was given a acid bath by";
- break;
- case MOD_FALLING:
- message = "was given a small push by";
- break;
- case MOD_TRIGGER_HURT:
- message = "was helped on the way by";
- break;
- case MOD_CRUSH:
- message = "was crushed in";
- message2 = "'s trap";
- break;
- default:
- message = "was killed by";
- break;
- }
-
- if (message) {
- CG_Printf( "%s %s %s%s\n",
- targetName, message, attackerName, message2);
- return;
- }
- }
-
- // we don't know what it was
- CG_Printf( "%s died.\n", targetName );
-}
-
-//==========================================================================
-
-/*
-===============
-CG_UseItem
-===============
-*/
-static void CG_UseItem( centity_t *cent ) {
- clientInfo_t *ci;
- int itemNum, clientNum;
- gitem_t *item;
- entityState_t *es;
-
- es = ¢->currentState;
-
- itemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0;
- if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) {
- itemNum = 0;
- }
-
- // print a message if the local player
- if ( es->number == cg.snap->ps.clientNum ) {
- if ( !itemNum ) {
- CG_CenterPrint( "No item to use", SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
- } else {
- item = BG_FindItemForHoldable( itemNum );
- CG_CenterPrint( va("Use %s", item->pickup_name), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
- }
- }
-
- switch ( itemNum ) {
- default:
- case HI_NONE:
- trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound );
- break;
-
- case HI_TELEPORTER:
- break;
-
- case HI_MEDKIT:
- clientNum = cent->currentState.clientNum;
- if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
- ci = &cgs.clientinfo[ clientNum ];
- ci->medkitUsageTime = cg.time;
- }
- trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.medkitSound );
- break;
-
-//#ifdef MISSIONPACK
- case HI_KAMIKAZE:
- break;
-
- case HI_PORTAL:
- break;
- case HI_INVULNERABILITY:
- trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useInvulnerabilitySound );
- break;
-//#endif
- }
-
-}
-
-/*
-================
-CG_ItemPickup
-
-A new item was picked up this frame
-================
-*/
-static void CG_ItemPickup( int itemNum ) {
- cg.itemPickup = itemNum;
- cg.itemPickupTime = cg.time;
- cg.itemPickupBlendTime = cg.time;
- // see if it should be the grabbed weapon
- if ( bg_itemlist[itemNum].giType == IT_WEAPON ) {
- // select it immediately
- if ( cg_autoswitch.integer && bg_itemlist[itemNum].giTag != WP_MACHINEGUN ) {
- cg.weaponSelectTime = cg.time;
- cg.weaponSelect = bg_itemlist[itemNum].giTag;
- }
- }
-
-}
-
-
-/*
-================
-CG_PainEvent
-
-Also called by playerstate transition
-================
-*/
-void CG_PainEvent( centity_t *cent, int health ) {
- char *snd;
-
- // don't do more than two pain sounds a second
- if ( cg.time - cent->pe.painTime < 500 ) {
- return;
- }
-
- if ( health < 25 ) {
- snd = "*pain25_1.wav";
- } else if ( health < 50 ) {
- snd = "*pain50_1.wav";
- } else if ( health < 75 ) {
- snd = "*pain75_1.wav";
- } else {
- snd = "*pain100_1.wav";
- }
- trap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE,
- CG_CustomSound( cent->currentState.number, snd ) );
-
- // save pain time for programitic twitch animation
- cent->pe.painTime = cg.time;
- cent->pe.painDirection ^= 1;
-}
-
-
-
-/*
-==============
-CG_EntityEvent
-
-An entity has an event value
-also called by CG_CheckPlayerstateEvents
-==============
-*/
-#define DEBUGNAME(x) if(cg_debugEvents.integer){CG_Printf(x"\n");}
-void CG_EntityEvent( centity_t *cent, vec3_t position ) {
- entityState_t *es;
- int event;
- vec3_t dir;
- const char *s;
- int clientNum;
- clientInfo_t *ci;
-
- es = ¢->currentState;
- event = es->event & ~EV_EVENT_BITS;
-
- if ( cg_debugEvents.integer ) {
- CG_Printf( "ent:%3i event:%3i ", es->number, event );
- }
-
- if ( !event ) {
- DEBUGNAME("ZEROEVENT");
- return;
- }
-
- clientNum = es->clientNum;
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- clientNum = 0;
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- switch ( event ) {
- //
- // movement generated events
- //
- case EV_FOOTSTEP:
- DEBUGNAME("EV_FOOTSTEP");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ ci->footsteps ][rand()&3] );
- }
- break;
- case EV_FOOTSTEP_METAL:
- DEBUGNAME("EV_FOOTSTEP_METAL");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] );
- }
- break;
- case EV_FOOTSPLASH:
- DEBUGNAME("EV_FOOTSPLASH");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
- }
- break;
- case EV_FOOTWADE:
- DEBUGNAME("EV_FOOTWADE");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
- }
- break;
- case EV_SWIM:
- DEBUGNAME("EV_SWIM");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
- }
- break;
-
-
- case EV_FALL_SHORT:
- DEBUGNAME("EV_FALL_SHORT");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound );
- if ( clientNum == cg.predictedPlayerState.clientNum ) {
- // smooth landing z changes
- cg.landChange = -8;
- cg.landTime = cg.time;
- }
- break;
- case EV_FALL_MEDIUM:
- DEBUGNAME("EV_FALL_MEDIUM");
- // use normal pain sound
- trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) );
- if ( clientNum == cg.predictedPlayerState.clientNum ) {
- // smooth landing z changes
- cg.landChange = -16;
- cg.landTime = cg.time;
- }
- break;
- case EV_FALL_FAR:
- DEBUGNAME("EV_FALL_FAR");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) );
- cent->pe.painTime = cg.time; // don't play a pain sound right after this
- if ( clientNum == cg.predictedPlayerState.clientNum ) {
- // smooth landing z changes
- cg.landChange = -24;
- cg.landTime = cg.time;
- }
- break;
-
- case EV_STEP_4:
- case EV_STEP_8:
- case EV_STEP_12:
- case EV_STEP_16: // smooth out step up transitions
- DEBUGNAME("EV_STEP");
- {
- float oldStep;
- int delta;
- int step;
-
- if ( clientNum != cg.predictedPlayerState.clientNum ) {
- break;
- }
- // if we are interpolating, we don't need to smooth steps
- if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ||
- cg_nopredict.integer || cg_synchronousClients.integer ) {
- break;
- }
- // check for stepping up before a previous step is completed
- delta = cg.time - cg.stepTime;
- if (delta < STEP_TIME) {
- oldStep = cg.stepChange * (STEP_TIME - delta) / STEP_TIME;
- } else {
- oldStep = 0;
- }
-
- // add this amount
- step = 4 * (event - EV_STEP_4 + 1 );
- cg.stepChange = oldStep + step;
- if ( cg.stepChange > MAX_STEP_CHANGE ) {
- cg.stepChange = MAX_STEP_CHANGE;
- }
- cg.stepTime = cg.time;
- break;
- }
-
- case EV_JUMP_PAD:
- DEBUGNAME("EV_JUMP_PAD");
-// CG_Printf( "EV_JUMP_PAD w/effect #%i\n", es->eventParm );
- {
- localEntity_t *smoke;
- vec3_t up = {0, 0, 1};
-
-
- smoke = CG_SmokePuff( cent->lerpOrigin, up,
- 32,
- 1, 1, 1, 0.33f,
- 1000,
- cg.time, 0,
- LEF_PUFF_DONT_SCALE,
- cgs.media.smokePuffShader );
- }
-
- // boing sound at origin, jump sound on player
- trap_S_StartSound ( cent->lerpOrigin, -1, CHAN_VOICE, cgs.media.jumpPadSound );
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
- break;
-
- case EV_JUMP:
- DEBUGNAME("EV_JUMP");
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
- break;
- case EV_TAUNT:
- DEBUGNAME("EV_TAUNT");
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) );
- break;
-#ifdef MISSIONPACK
- case EV_TAUNT_YES:
- DEBUGNAME("EV_TAUNT_YES");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_YES);
- break;
- case EV_TAUNT_NO:
- DEBUGNAME("EV_TAUNT_NO");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_NO);
- break;
- case EV_TAUNT_FOLLOWME:
- DEBUGNAME("EV_TAUNT_FOLLOWME");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_FOLLOWME);
- break;
- case EV_TAUNT_GETFLAG:
- DEBUGNAME("EV_TAUNT_GETFLAG");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONGETFLAG);
- break;
- case EV_TAUNT_GUARDBASE:
- DEBUGNAME("EV_TAUNT_GUARDBASE");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONDEFENSE);
- break;
- case EV_TAUNT_PATROL:
- DEBUGNAME("EV_TAUNT_PATROL");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONPATROL);
- break;
-#endif
- case EV_WATER_TOUCH:
- DEBUGNAME("EV_WATER_TOUCH");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound );
- break;
- case EV_WATER_LEAVE:
- DEBUGNAME("EV_WATER_LEAVE");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );
- break;
- case EV_WATER_UNDER:
- DEBUGNAME("EV_WATER_UNDER");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound );
- break;
- case EV_WATER_CLEAR:
- DEBUGNAME("EV_WATER_CLEAR");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) );
- break;
-
- case EV_ITEM_PICKUP:
- DEBUGNAME("EV_ITEM_PICKUP");
- {
- gitem_t *item;
- int index;
-
- index = es->eventParm; // player predicted
-
- if ( index < 1 || index >= bg_numItems ) {
- break;
- }
- item = &bg_itemlist[ index ];
-
- // powerups and team items will have a separate global sound, this one
- // will be played at prediction time
- if ( item->giType == IT_POWERUP || item->giType == IT_TEAM) {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.n_healthSound );
- } else if (item->giType == IT_PERSISTANT_POWERUP) {
-#ifdef MISSIONPACK
- switch (item->giTag ) {
- case PW_SCOUT:
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.scoutSound );
- break;
- case PW_GUARD:
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.guardSound );
- break;
- case PW_DOUBLER:
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.doublerSound );
- break;
- case PW_AMMOREGEN:
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.ammoregenSound );
- break;
- }
-#endif
- } else {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );
- }
-
- // show icon and name on status bar
- if ( es->number == cg.snap->ps.clientNum ) {
- CG_ItemPickup( index );
- }
- }
- break;
-
- case EV_GLOBAL_ITEM_PICKUP:
- DEBUGNAME("EV_GLOBAL_ITEM_PICKUP");
- {
- gitem_t *item;
- int index;
-
- index = es->eventParm; // player predicted
-
- if ( index < 1 || index >= bg_numItems ) {
- break;
- }
- item = &bg_itemlist[ index ];
- // powerup pickups are global
- if( item->pickup_sound ) {
- trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );
- }
-
- // show icon and name on status bar
- if ( es->number == cg.snap->ps.clientNum ) {
- CG_ItemPickup( index );
- }
- }
- break;
-
- //
- // weapon events
- //
- case EV_NOAMMO:
- DEBUGNAME("EV_NOAMMO");
-// trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound );
- if ( es->number == cg.snap->ps.clientNum ) {
- CG_OutOfAmmoChange();
- }
- break;
- case EV_CHANGE_WEAPON:
- DEBUGNAME("EV_CHANGE_WEAPON");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
- break;
- case EV_FIRE_WEAPON:
- DEBUGNAME("EV_FIRE_WEAPON");
- CG_FireWeapon( cent );
- break;
-
- case EV_USE_ITEM0:
- DEBUGNAME("EV_USE_ITEM0");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM1:
- DEBUGNAME("EV_USE_ITEM1");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM2:
- DEBUGNAME("EV_USE_ITEM2");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM3:
- DEBUGNAME("EV_USE_ITEM3");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM4:
- DEBUGNAME("EV_USE_ITEM4");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM5:
- DEBUGNAME("EV_USE_ITEM5");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM6:
- DEBUGNAME("EV_USE_ITEM6");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM7:
- DEBUGNAME("EV_USE_ITEM7");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM8:
- DEBUGNAME("EV_USE_ITEM8");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM9:
- DEBUGNAME("EV_USE_ITEM9");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM10:
- DEBUGNAME("EV_USE_ITEM10");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM11:
- DEBUGNAME("EV_USE_ITEM11");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM12:
- DEBUGNAME("EV_USE_ITEM12");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM13:
- DEBUGNAME("EV_USE_ITEM13");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM14:
- DEBUGNAME("EV_USE_ITEM14");
- CG_UseItem( cent );
- break;
-
- //=================================================================
-
- //
- // other events
- //
- case EV_PLAYER_TELEPORT_IN:
- DEBUGNAME("EV_PLAYER_TELEPORT_IN");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleInSound );
- CG_SpawnEffect( position);
- break;
-
- case EV_PLAYER_TELEPORT_OUT:
- DEBUGNAME("EV_PLAYER_TELEPORT_OUT");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleOutSound );
- CG_SpawnEffect( position);
- break;
-
- case EV_ITEM_POP:
- DEBUGNAME("EV_ITEM_POP");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
- break;
- case EV_ITEM_RESPAWN:
- DEBUGNAME("EV_ITEM_RESPAWN");
- cent->miscTime = cg.time; // scale up from this
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
- break;
-
- case EV_GRENADE_BOUNCE:
- DEBUGNAME("EV_GRENADE_BOUNCE");
- if ( rand() & 1 ) {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb1aSound );
- } else {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb2aSound );
- }
- break;
-
-
- case EV_PROXIMITY_MINE_STICK:
- DEBUGNAME("EV_PROXIMITY_MINE_STICK");
- if( es->eventParm & SURF_FLESH ) {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimplSound );
- } else if( es->eventParm & SURF_METALSTEPS ) {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpmSound );
- } else {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpdSound );
- }
- break;
-
- case EV_PROXIMITY_MINE_TRIGGER:
- DEBUGNAME("EV_PROXIMITY_MINE_TRIGGER");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbactvSound );
- break;
- case EV_KAMIKAZE:
- DEBUGNAME("EV_KAMIKAZE");
- CG_KamikazeEffect( cent->lerpOrigin );
- break;
- case EV_OBELISKEXPLODE:
- DEBUGNAME("EV_OBELISKEXPLODE");
- CG_ObeliskExplode( cent->lerpOrigin, es->eventParm );
- break;
- case EV_OBELISKPAIN:
- DEBUGNAME("EV_OBELISKPAIN");
- CG_ObeliskPain( cent->lerpOrigin );
- break;
- case EV_INVUL_IMPACT:
- DEBUGNAME("EV_INVUL_IMPACT");
- CG_InvulnerabilityImpact( cent->lerpOrigin, cent->currentState.angles );
- break;
- case EV_JUICED:
- DEBUGNAME("EV_JUICED");
- CG_InvulnerabilityJuiced( cent->lerpOrigin );
- break;
- case EV_LIGHTNINGBOLT:
- DEBUGNAME("EV_LIGHTNINGBOLT");
- CG_LightningBoltBeam(es->origin2, es->pos.trBase);
- break;
- case EV_SCOREPLUM:
- DEBUGNAME("EV_SCOREPLUM");
- CG_ScorePlum( cent->currentState.otherEntityNum, cent->lerpOrigin, cent->currentState.time );
- break;
-
- //
- // missile impacts
- //
- case EV_MISSILE_HIT:
- DEBUGNAME("EV_MISSILE_HIT");
- ByteToDir( es->eventParm, dir );
- CG_MissileHitPlayer( es->weapon, position, dir, es->otherEntityNum );
- break;
-
- case EV_MISSILE_MISS:
- DEBUGNAME("EV_MISSILE_MISS");
- ByteToDir( es->eventParm, dir );
- CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_DEFAULT );
- break;
-
- case EV_MISSILE_MISS_METAL:
- DEBUGNAME("EV_MISSILE_MISS_METAL");
- ByteToDir( es->eventParm, dir );
- CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_METAL );
- break;
-
- case EV_RAILTRAIL:
- DEBUGNAME("EV_RAILTRAIL");
- cent->currentState.weapon = WP_RAILGUN;
-//unlagged - attack prediction #2
- // if the client is us, unlagged is on server-side, and we've got it client-side
- if ( es->clientNum == cg.predictedPlayerState.clientNum &&
- cgs.delagHitscan && (cg_delag.integer & 1 || cg_delag.integer & 16) ) {
- // do nothing, because it was already predicted
- //Com_Printf("Ignoring rail trail event\n");
- }
- else {
- if(es->clientNum == cg.snap->ps.clientNum && !cg.renderingThirdPerson)
- {
- if(cg_drawGun.integer == 2)
- VectorMA(es->origin2, 8, cg.refdef.viewaxis[1], es->origin2);
- else if(cg_drawGun.integer == 3)
- VectorMA(es->origin2, 4, cg.refdef.viewaxis[1], es->origin2);
- }
-
-
- // draw a rail trail, because it wasn't predicted
- CG_RailTrail( ci, es->origin2, es->pos.trBase );
-
- // if the end was on a nomark surface, don't make an explosion
- if ( es->eventParm != 255 ) {
- ByteToDir( es->eventParm, dir );
- CG_MissileHitWall( es->weapon, es->clientNum, position, dir, IMPACTSOUND_DEFAULT );
- }
- //Com_Printf("Non-predicted rail trail\n");
- }
-//unlagged - attack prediction #2
- break;
-
- case EV_BULLET_HIT_WALL:
- DEBUGNAME("EV_BULLET_HIT_WALL");
-//unlagged - attack prediction #2
- // if the client is us, unlagged is on server-side, and we've got it client-side
- if ( es->clientNum == cg.predictedPlayerState.clientNum &&
- cgs.delagHitscan && (cg_delag.integer & 1 || cg_delag.integer & 2) ) {
- // do nothing, because it was already predicted
- //Com_Printf("Ignoring bullet event\n");
- }
- else {
- // do the bullet, because it wasn't predicted
- ByteToDir( es->eventParm, dir );
- CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD );
- //Com_Printf("Non-predicted bullet\n");
- }
-//unlagged - attack prediction #2
- break;
-
- case EV_BULLET_HIT_FLESH:
- DEBUGNAME("EV_BULLET_HIT_FLESH");
-//unlagged - attack prediction #2
- // if the client is us, unlagged is on server-side, and we've got it client-side
- if ( es->clientNum == cg.predictedPlayerState.clientNum &&
- cgs.delagHitscan && (cg_delag.integer & 1 || cg_delag.integer & 2) ) {
- // do nothing, because it was already predicted
- //Com_Printf("Ignoring bullet event\n");
- }
- else {
- // do the bullet, because it wasn't predicted
- CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );
- //Com_Printf("Non-predicted bullet\n");
- }
-//unlagged - attack prediction #2
- break;
-
- case EV_SHOTGUN:
- DEBUGNAME("EV_SHOTGUN");
-//unlagged - attack prediction #2
- // if the client is us, unlagged is on server-side, and we've got it client-side
- if ( es->otherEntityNum == cg.predictedPlayerState.clientNum &&
- cgs.delagHitscan && (cg_delag.integer & 1 || cg_delag.integer & 4) ) {
- // do nothing, because it was already predicted
- //Com_Printf("Ignoring shotgun event\n");
- }
- else {
- // do the shotgun pattern, because it wasn't predicted
- CG_ShotgunFire( es );
- //Com_Printf("Non-predicted shotgun pattern\n");
- }
-//unlagged - attack prediction #2
- break;
-
- case EV_GENERAL_SOUND:
- DEBUGNAME("EV_GENERAL_SOUND");
- if ( cgs.gameSounds[ es->eventParm ] ) {
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] );
- } else {
- s = CG_ConfigString( CS_SOUNDS + es->eventParm );
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) );
- }
- break;
-
- case EV_GLOBAL_SOUND: // play from the player's head so it never diminishes
- DEBUGNAME("EV_GLOBAL_SOUND");
- if ( cgs.gameSounds[ es->eventParm ] ) {
- trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
- } else {
- s = CG_ConfigString( CS_SOUNDS + es->eventParm );
- trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
- }
- break;
-
- case EV_GLOBAL_TEAM_SOUND: // play from the player's head so it never diminishes
- {
- DEBUGNAME("EV_GLOBAL_TEAM_SOUND");
- switch( es->eventParm ) {
- case GTS_RED_CAPTURE: // CTF: red team captured the blue flag, 1FCTF: red team captured the neutral flag
- if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
- CG_AddBufferedSound( cgs.media.captureYourTeamSound );
- else
- CG_AddBufferedSound( cgs.media.captureOpponentSound );
- break;
- case GTS_BLUE_CAPTURE: // CTF: blue team captured the red flag, 1FCTF: blue team captured the neutral flag
- if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )
- CG_AddBufferedSound( cgs.media.captureYourTeamSound );
- else
- CG_AddBufferedSound( cgs.media.captureOpponentSound );
- break;
- case GTS_RED_RETURN: // CTF: blue flag returned, 1FCTF: never used
- if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
- CG_AddBufferedSound( cgs.media.returnYourTeamSound );
- else
- CG_AddBufferedSound( cgs.media.returnOpponentSound );
- //
- CG_AddBufferedSound( cgs.media.blueFlagReturnedSound );
- break;
- case GTS_BLUE_RETURN: // CTF red flag returned, 1FCTF: neutral flag returned
- if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )
- CG_AddBufferedSound( cgs.media.returnYourTeamSound );
- else
- CG_AddBufferedSound( cgs.media.returnOpponentSound );
- //
- CG_AddBufferedSound( cgs.media.redFlagReturnedSound );
- break;
-
- case GTS_RED_TAKEN: // CTF: red team took blue flag, 1FCTF: blue team took the neutral flag
- // if this player picked up the flag then a sound is played in CG_CheckLocalSounds
- if (cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
- }
- else {
- if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
-//#ifdef MISSIONPACK
- if (cgs.gametype == GT_1FCTF)
- CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
- else
-//#endif
- CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
- }
- else if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
-//#ifdef MISSIONPACK
- if (cgs.gametype == GT_1FCTF)
- CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
- else
-//#endif
- CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
- }
- }
- break;
- case GTS_BLUE_TAKEN: // CTF: blue team took the red flag, 1FCTF red team took the neutral flag
- // if this player picked up the flag then a sound is played in CG_CheckLocalSounds
- if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
- }
- else {
- if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
-//#ifdef MISSIONPACK
- if (cgs.gametype == GT_1FCTF)
- CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
- else
-//#endif
- CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
- }
- else if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
-//#ifdef MISSIONPACK
- if (cgs.gametype == GT_1FCTF)
- CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
- else
-//#endif
- CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
- }
- }
- break;
- case GTS_REDOBELISK_ATTACKED: // Overload: red obelisk is being attacked
- if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
- CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );
- }
- break;
- case GTS_BLUEOBELISK_ATTACKED: // Overload: blue obelisk is being attacked
- if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
- CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );
- }
- break;
-
- case GTS_REDTEAM_SCORED:
- CG_AddBufferedSound(cgs.media.redScoredSound);
- break;
- case GTS_BLUETEAM_SCORED:
- CG_AddBufferedSound(cgs.media.blueScoredSound);
- break;
- case GTS_REDTEAM_TOOK_LEAD:
- CG_AddBufferedSound(cgs.media.redLeadsSound);
- break;
- case GTS_BLUETEAM_TOOK_LEAD:
- CG_AddBufferedSound(cgs.media.blueLeadsSound);
- break;
- case GTS_TEAMS_ARE_TIED:
- CG_AddBufferedSound( cgs.media.teamsTiedSound );
- break;
- case GTS_KAMIKAZE:
- trap_S_StartLocalSound(cgs.media.kamikazeFarSound, CHAN_ANNOUNCER);
- break;
- default:
- break;
- }
- break;
- }
-
- case EV_PAIN:
- // local player sounds are triggered in CG_CheckLocalSounds,
- // so ignore events on the player
- DEBUGNAME("EV_PAIN");
- if ( cent->currentState.number != cg.snap->ps.clientNum ) {
- CG_PainEvent( cent, es->eventParm );
- }
- break;
-
- case EV_DEATH1:
- case EV_DEATH2:
- case EV_DEATH3:
- DEBUGNAME("EV_DEATHx");
- trap_S_StartSound( NULL, es->number, CHAN_VOICE,
- CG_CustomSound( es->number, va("*death%i.wav", event - EV_DEATH1 + 1) ) );
- break;
-
-
- case EV_OBITUARY:
- DEBUGNAME("EV_OBITUARY");
- CG_Obituary( es );
- break;
-
- //
- // powerup events
- //
- case EV_POWERUP_QUAD:
- DEBUGNAME("EV_POWERUP_QUAD");
- if ( es->number == cg.snap->ps.clientNum ) {
- cg.powerupActive = PW_QUAD;
- cg.powerupTime = cg.time;
- }
- trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.quadSound );
- break;
- case EV_POWERUP_BATTLESUIT:
- DEBUGNAME("EV_POWERUP_BATTLESUIT");
- if ( es->number == cg.snap->ps.clientNum ) {
- cg.powerupActive = PW_BATTLESUIT;
- cg.powerupTime = cg.time;
- }
- trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.protectSound );
- break;
- case EV_POWERUP_REGEN:
- DEBUGNAME("EV_POWERUP_REGEN");
- if ( es->number == cg.snap->ps.clientNum ) {
- cg.powerupActive = PW_REGEN;
- cg.powerupTime = cg.time;
- }
- trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.regenSound );
- break;
-
- case EV_GIB_PLAYER:
- DEBUGNAME("EV_GIB_PLAYER");
- // don't play gib sound when using the kamikaze because it interferes
- // with the kamikaze sound, downside is that the gib sound will also
- // not be played when someone is gibbed while just carrying the kamikaze
- if ( !(es->eFlags & EF_KAMIKAZE) ) {
- trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound );
- }
- CG_GibPlayer( cent->lerpOrigin );
- break;
-
- case EV_STOPLOOPINGSOUND:
- DEBUGNAME("EV_STOPLOOPINGSOUND");
- trap_S_StopLoopingSound( es->number );
- es->loopSound = 0;
- break;
-
- case EV_DEBUG_LINE:
- DEBUGNAME("EV_DEBUG_LINE");
- CG_Beam( cent );
- break;
-
- default:
- DEBUGNAME("UNKNOWN");
- CG_Error( "Unknown event: %i", event );
- break;
- }
-
-}
-
-
-/*
-==============
-CG_CheckEvents
-
-==============
-*/
-void CG_CheckEvents( centity_t *cent ) {
- // check for event-only entities
- if ( cent->currentState.eType > ET_EVENTS ) {
- if ( cent->previousEvent ) {
- return; // already fired
- }
- // if this is a player event set the entity number of the client entity number
- if ( cent->currentState.eFlags & EF_PLAYER_EVENT ) {
- cent->currentState.number = cent->currentState.otherEntityNum;
- }
-
- cent->previousEvent = 1;
-
- cent->currentState.event = cent->currentState.eType - ET_EVENTS;
- } else {
- // check for events riding with another entity
- if ( cent->currentState.event == cent->previousEvent ) {
- return;
- }
- cent->previousEvent = cent->currentState.event;
- if ( ( cent->currentState.event & ~EV_EVENT_BITS ) == 0 ) {
- return;
- }
- }
-
- // calculate the position at exactly the frame time
- BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, cent->lerpOrigin );
- CG_SetEntitySoundPosition( cent );
-
- CG_EntityEvent( cent, cent->lerpOrigin );
-}
-
diff --git a/game/code/cgame/cg_info.c b/game/code/cgame/cg_info.c
deleted file mode 100644
index 24f62be..0000000
--- a/game/code/cgame/cg_info.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_info.c -- display information while data is being loading
-
-#include "cg_local.h"
-
-#define MAX_LOADING_PLAYER_ICONS 16
-#define MAX_LOADING_ITEM_ICONS 26
-
-static int loadingPlayerIconCount;
-static int loadingItemIconCount;
-static qhandle_t loadingPlayerIcons[MAX_LOADING_PLAYER_ICONS];
-static qhandle_t loadingItemIcons[MAX_LOADING_ITEM_ICONS];
-
-
-/*
-===================
-CG_DrawLoadingIcons
-===================
-*/
-static void CG_DrawLoadingIcons( void ) {
- int n;
- int x, y;
-
- for( n = 0; n < loadingPlayerIconCount; n++ ) {
- x = 16 + n * 78;
- y = 324-40;
- CG_DrawPic( x, y, 64, 64, loadingPlayerIcons[n] );
- }
-
- for( n = 0; n < loadingItemIconCount; n++ ) {
- y = 400-40;
- if( n >= 13 ) {
- y += 40;
- }
- x = 16 + n % 13 * 48;
- CG_DrawPic( x, y, 32, 32, loadingItemIcons[n] );
- }
-}
-
-
-/*
-======================
-CG_LoadingString
-
-======================
-*/
-void CG_LoadingString( const char *s ) {
- Q_strncpyz( cg.infoScreenText, s, sizeof( cg.infoScreenText ) );
-
- trap_UpdateScreen();
-}
-
-/*
-===================
-CG_LoadingItem
-===================
-*/
-void CG_LoadingItem( int itemNum ) {
- gitem_t *item;
-
- item = &bg_itemlist[itemNum];
-
- if ( item->icon && loadingItemIconCount < MAX_LOADING_ITEM_ICONS ) {
- loadingItemIcons[loadingItemIconCount++] = trap_R_RegisterShaderNoMip( item->icon );
- }
-
- CG_LoadingString( item->pickup_name );
-}
-
-/*
-===================
-CG_LoadingClient
-===================
-*/
-void CG_LoadingClient( int clientNum ) {
- const char *info;
- char *skin;
- char personality[MAX_QPATH];
- char model[MAX_QPATH];
- char iconName[MAX_QPATH];
-
- info = CG_ConfigString( CS_PLAYERS + clientNum );
-
- if ( loadingPlayerIconCount < MAX_LOADING_PLAYER_ICONS ) {
- Q_strncpyz( model, Info_ValueForKey( info, "model" ), sizeof( model ) );
- skin = Q_strrchr( model, '/' );
- if ( skin ) {
- *skin++ = '\0';
- } else {
- skin = "default";
- }
-
- Com_sprintf( iconName, MAX_QPATH, "models/players/%s/icon_%s.tga", model, skin );
-
- loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
- if ( !loadingPlayerIcons[loadingPlayerIconCount] ) {
- Com_sprintf( iconName, MAX_QPATH, "models/players/characters/%s/icon_%s.tga", model, skin );
- loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
- }
- if ( !loadingPlayerIcons[loadingPlayerIconCount] ) {
- Com_sprintf( iconName, MAX_QPATH, "models/players/%s/icon_%s.tga", DEFAULT_MODEL, "default" );
- loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
- }
- if ( loadingPlayerIcons[loadingPlayerIconCount] ) {
- loadingPlayerIconCount++;
- }
- }
-
- Q_strncpyz( personality, Info_ValueForKey( info, "n" ), sizeof(personality) );
- Q_CleanStr( personality );
-
- if( cgs.gametype == GT_SINGLE_PLAYER ) {
- trap_S_RegisterSound( va( "sound/player/announce/%s.wav", personality ), qtrue );
- }
-
- CG_LoadingString( personality );
-}
-
-
-/*
-====================
-CG_DrawInformation
-
-Draw all the status / pacifier stuff during level loading
-====================
-*/
-void CG_DrawInformation( void ) {
- const char *s;
- const char *info;
- const char *sysInfo;
- int y;
- int value;
- qhandle_t levelshot;
- qhandle_t detail;
- char buf[1024];
-
- info = CG_ConfigString( CS_SERVERINFO );
- sysInfo = CG_ConfigString( CS_SYSTEMINFO );
-
- s = Info_ValueForKey( info, "mapname" );
- levelshot = trap_R_RegisterShaderNoMip( va( "levelshots/%s.tga", s ) );
- if ( !levelshot ) {
- levelshot = trap_R_RegisterShaderNoMip( "menu/art/unknownmap" );
- }
- trap_R_SetColor( NULL );
- CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, levelshot );
-
- // blend a detail texture over it
- detail = trap_R_RegisterShader( "levelShotDetail" );
- trap_R_DrawStretchPic( 0, 0, cgs.glconfig.vidWidth, cgs.glconfig.vidHeight, 0, 0, 2.5, 2, detail );
-
- // draw the icons of things as they are loaded
- CG_DrawLoadingIcons();
-
- // the first 150 rows are reserved for the client connection
- // screen to write into
- if ( cg.infoScreenText[0] ) {
- UI_DrawProportionalString( 320, 128-32, va("Loading... %s", cg.infoScreenText),
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- } else {
- UI_DrawProportionalString( 320, 128-32, "Awaiting snapshot...",
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- }
-
- // draw info string information
-
- y = 180-32;
-
- // don't print server lines if playing a local game
- trap_Cvar_VariableStringBuffer( "sv_running", buf, sizeof( buf ) );
- if ( !atoi( buf ) ) {
- // server hostname
- Q_strncpyz(buf, Info_ValueForKey( info, "sv_hostname" ), 1024);
- Q_CleanStr(buf);
- UI_DrawProportionalString( 320, y, buf,
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
-
- // pure server
- s = Info_ValueForKey( sysInfo, "sv_pure" );
- if ( s[0] == '1' ) {
- UI_DrawProportionalString( 320, y, "Pure Server",
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- // server-specific message of the day
- s = CG_ConfigString( CS_MOTD );
- if ( s[0] ) {
- UI_DrawProportionalString( 320, y, s,
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- // some extra space after hostname and motd
- y += 10;
- }
-
- // map-specific message (long map name)
- s = CG_ConfigString( CS_MESSAGE );
- if ( s[0] ) {
- UI_DrawProportionalString( 320, y, s,
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- // cheats warning
- s = Info_ValueForKey( sysInfo, "sv_cheats" );
- if ( s[0] == '1' ) {
- UI_DrawProportionalString( 320, y, "CHEATS ARE ENABLED",
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- // game type
- switch ( cgs.gametype ) {
- case GT_FFA:
- s = "Free For All";
- break;
- case GT_SINGLE_PLAYER:
- s = "Single Player";
- break;
- case GT_TOURNAMENT:
- s = "Tournament";
- break;
- case GT_TEAM:
- s = "Team Deathmatch";
- break;
- case GT_CTF:
- s = "Capture The Flag";
- break;
-//#ifdef MISSIONPACK
- case GT_1FCTF:
- s = "One Flag CTF";
- break;
- case GT_OBELISK:
- s = "Overload";
- break;
- case GT_HARVESTER:
- s = "Harvester";
- break;
-//#endif
- case GT_ELIMINATION:
- s = "Elimination";
- break;
- case GT_CTF_ELIMINATION:
- s = " CTF Elimination";
- break;
- case GT_LMS:
- s = "Last Man Standing";
- break;
- case GT_DOUBLE_D:
- s = "Double Domination";
- break;
- case GT_DOMINATION:
- s = "Domination";
- break;
- default:
- s = "Unknown Gametype";
- break;
- }
- UI_DrawProportionalString( 320, y, s,
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
-
- value = atoi( Info_ValueForKey( info, "timelimit" ) );
- if ( value ) {
- UI_DrawProportionalString( 320, y, va( "timelimit %i", value ),
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- if (cgs.gametype < GT_CTF || cgs.ffa_gt>0) {
- value = atoi( Info_ValueForKey( info, "fraglimit" ) );
- if ( value ) {
- UI_DrawProportionalString( 320, y, va( "fraglimit %i", value ),
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
- }
-
- if (cgs.gametype >= GT_CTF && cgs.ffa_gt == 0) {
- value = atoi( Info_ValueForKey( info, "capturelimit" ) );
- if ( value ) {
- UI_DrawProportionalString( 320, y, va( "capturelimit %i", value ),
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
- }
-}
-
diff --git a/game/code/cgame/cg_local.h b/game/code/cgame/cg_local.h
deleted file mode 100644
index a25027b..0000000
--- a/game/code/cgame/cg_local.h
+++ /dev/null
@@ -1,1862 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "../qcommon/q_shared.h"
-#include "../renderer/tr_types.h"
-#include "../game/bg_public.h"
-#include "cg_public.h"
-
-#include "../game/challenges.h"
-
-
-// The entire cgame module is unloaded and reloaded on each level change,
-// so there is NO persistant data between levels on the client side.
-// If you absolutely need something stored, it can either be kept
-// by the server in the server stored userinfos, or stashed in a cvar.
-
-#ifdef MISSIONPACK
-#define CG_FONT_THRESHOLD 0.1
-#endif
-
-#define POWERUP_BLINKS 5
-
-#define POWERUP_BLINK_TIME 1000
-#define FADE_TIME 200
-#define PULSE_TIME 200
-#define DAMAGE_DEFLECT_TIME 100
-#define DAMAGE_RETURN_TIME 400
-#define DAMAGE_TIME 500
-#define LAND_DEFLECT_TIME 150
-#define LAND_RETURN_TIME 300
-#define STEP_TIME 200
-#define DUCK_TIME 100
-#define PAIN_TWITCH_TIME 200
-#define WEAPON_SELECT_TIME 1400
-#define ITEM_SCALEUP_TIME 1000
-#define ZOOM_TIME 150
-#define ITEM_BLOB_TIME 200
-#define MUZZLE_FLASH_TIME 20
-#define SINK_TIME 1000 // time for fragments to sink into ground before going away
-#define ATTACKER_HEAD_TIME 10000
-#define REWARD_TIME 3000
-
-#define PULSE_SCALE 1.5 // amount to scale up the icons when activating
-
-#define MAX_STEP_CHANGE 32
-
-#define MAX_VERTS_ON_POLY 10
-#define MAX_MARK_POLYS 256
-
-#define STAT_MINUS 10 // num frame for '-' stats digit
-
-#define ICON_SIZE 48
-#define CHAR_WIDTH 32
-#define CHAR_HEIGHT 48
-#define TEXT_ICON_SPACE 4
-
-#define TEAMCHAT_WIDTH 80
-#define TEAMCHAT_HEIGHT 8
-
-// very large characters.pk
-#define GIANT_WIDTH 32
-#define GIANT_HEIGHT 48
-
-#define NUM_CROSSHAIRS 99
-
-#define TEAM_OVERLAY_MAXNAME_WIDTH 12
-#define TEAM_OVERLAY_MAXLOCATION_WIDTH 16
-
-#define DEFAULT_MODEL "sarge"
-#ifdef MISSIONPACK
-#define DEFAULT_TEAM_MODEL "sergei"
-#define DEFAULT_TEAM_HEAD "*sergei"
-#else
-#define DEFAULT_TEAM_MODEL "sarge"
-#define DEFAULT_TEAM_HEAD "sarge"
-#endif
-
-#define DEFAULT_REDTEAM_NAME "Vim supporters"
-#define DEFAULT_BLUETEAM_NAME "Emacs supporters"
-
-typedef enum {
- FOOTSTEP_NORMAL,
- FOOTSTEP_BOOT,
- FOOTSTEP_FLESH,
- FOOTSTEP_MECH,
- FOOTSTEP_ENERGY,
- FOOTSTEP_METAL,
- FOOTSTEP_SPLASH,
-
- FOOTSTEP_TOTAL
-} footstep_t;
-
-typedef enum {
- IMPACTSOUND_DEFAULT,
- IMPACTSOUND_METAL,
- IMPACTSOUND_FLESH
-} impactSound_t;
-
-//=================================================
-
-// player entities need to track more information
-// than any other type of entity.
-
-// note that not every player entity is a client entity,
-// because corpses after respawn are outside the normal
-// client numbering range
-
-// when changing animation, set animationTime to frameTime + lerping time
-// The current lerp will finish out, then it will lerp to the new animation
-typedef struct {
- int oldFrame;
- int oldFrameTime; // time when ->oldFrame was exactly on
-
- int frame;
- int frameTime; // time when ->frame will be exactly on
-
- float backlerp;
-
- float yawAngle;
- qboolean yawing;
- float pitchAngle;
- qboolean pitching;
-
- int animationNumber; // may include ANIM_TOGGLEBIT
- animation_t *animation;
- int animationTime; // time when the first frame of the animation will be exact
-} lerpFrame_t;
-
-
-typedef struct {
- lerpFrame_t legs, torso, flag;
- int painTime;
- int painDirection; // flip from 0 to 1
- int lightningFiring;
-
- // railgun trail spawning
- vec3_t railgunImpact;
- qboolean railgunFlash;
-
- // machinegun spinning
- float barrelAngle;
- int barrelTime;
- qboolean barrelSpinning;
-} playerEntity_t;
-
-//=================================================
-
-
-
-// centity_t have a direct corespondence with gentity_t in the game, but
-// only the entityState_t is directly communicated to the cgame
-typedef struct centity_s {
- entityState_t currentState; // from cg.frame
- entityState_t nextState; // from cg.nextFrame, if available
- qboolean interpolate; // true if next is valid to interpolate to
- qboolean currentValid; // true if cg.frame holds this entity
-
- int muzzleFlashTime; // move to playerEntity?
- int previousEvent;
- int teleportFlag;
-
- int trailTime; // so missile trails can handle dropped initial packets
- int dustTrailTime;
- int miscTime;
-
- int snapShotTime; // last time this entity was found in a snapshot
-
- playerEntity_t pe;
-
- int errorTime; // decay the error from this time
- vec3_t errorOrigin;
- vec3_t errorAngles;
-
- qboolean extrapolated; // false if origin / angles is an interpolation
- vec3_t rawOrigin;
- vec3_t rawAngles;
-
- vec3_t beamEnd;
-
- // exact interpolated position of entity on this frame
- vec3_t lerpOrigin;
- vec3_t lerpAngles;
-} centity_t;
-
-
-//======================================================================
-
-// local entities are created as a result of events or predicted actions,
-// and live independantly from all server transmitted entities
-
-typedef struct markPoly_s {
- struct markPoly_s *prevMark, *nextMark;
- int time;
- qhandle_t markShader;
- qboolean alphaFade; // fade alpha instead of rgb
- float color[4];
- poly_t poly;
- polyVert_t verts[MAX_VERTS_ON_POLY];
-} markPoly_t;
-
-
-typedef enum {
- LE_MARK,
- LE_EXPLOSION,
- LE_SPRITE_EXPLOSION,
- LE_FRAGMENT,
- LE_MOVE_SCALE_FADE,
- LE_FALL_SCALE_FADE,
- LE_FADE_RGB,
- LE_SCALE_FADE,
- LE_SCOREPLUM,
- LE_KAMIKAZE,
- LE_INVULIMPACT,
- LE_INVULJUICED,
- LE_SHOWREFENTITY,
- LE_GORE
-} leType_t;
-
-typedef enum {
- LEF_PUFF_DONT_SCALE = 0x0001, // do not scale size over time
- LEF_TUMBLE = 0x0002, // tumble over time, used for ejecting shells
- LEF_SOUND1 = 0x0004, // sound 1 for kamikaze
- LEF_SOUND2 = 0x0008 // sound 2 for kamikaze
-} leFlag_t;
-
-typedef enum {
- LEMT_NONE,
- LEMT_BURN,
- LEMT_BLOOD
-} leMarkType_t; // fragment local entities can leave marks on walls
-
-typedef enum {
- LEBS_NONE,
- LEBS_BLOOD,
- LEBS_BRASS,
- LEBS_SHELL
-} leBounceSoundType_t; // fragment local entities can make sounds on impacts
-
-typedef struct localEntity_s {
- struct localEntity_s *prev, *next;
- leType_t leType;
- int leFlags;
-
- int startTime;
- int endTime;
- int fadeInTime;
-
- float lifeRate; // 1.0 / (endTime - startTime)
-
- trajectory_t pos;
- trajectory_t angles;
-
- float bounceFactor; // 0.0 = no bounce, 1.0 = perfect
-
- float color[4];
-
- float radius;
-
- float light;
- vec3_t lightColor;
-
- leMarkType_t leMarkType; // mark to leave on fragment impact
- leBounceSoundType_t leBounceSoundType;
-
- refEntity_t refEntity;
-} localEntity_t;
-
-//======================================================================
-
-
-typedef struct {
- int client;
- int score;
- int ping;
- int time;
- int scoreFlags;
- int powerUps;
- int accuracy;
- int impressiveCount;
- int excellentCount;
- int guantletCount;
- int defendCount;
- int assistCount;
- int captures;
- qboolean perfect;
- int team;
- int isDead;
-} score_t;
-
-// each client has an associated clientInfo_t
-// that contains media references necessary to present the
-// client model and other color coded effects
-// this is regenerated each time a client's configstring changes,
-// usually as a result of a userinfo (name, model, etc) change
-#define MAX_CUSTOM_SOUNDS 32
-
-typedef struct {
- qboolean infoValid;
-
- char name[MAX_QPATH];
- team_t team;
-
- int botSkill; // 0 = not bot, 1-5 = bot
-
- vec3_t color1;
- vec3_t color2;
-
- int score; // updated by score servercmds
- int location; // location index for team mode
- int health; // you only get this info about your teammates
- int armor;
- int curWeapon;
-
- int handicap;
- int wins, losses; // in tourney mode
-
- int teamTask; // task in teamplay (offence/defence)
- qboolean teamLeader; // true when this is a team leader
-
- int powerups; // so can display quad/flag status
-
- int medkitUsageTime;
- int invulnerabilityStartTime;
- int invulnerabilityStopTime;
-
- int breathPuffTime;
-
- // when clientinfo is changed, the loading of models/skins/sounds
- // can be deferred until you are dead, to prevent hitches in
- // gameplay
- char modelName[MAX_QPATH];
- char skinName[MAX_QPATH];
- char headModelName[MAX_QPATH];
- char headSkinName[MAX_QPATH];
- char redTeam[MAX_TEAMNAME];
- char blueTeam[MAX_TEAMNAME];
- qboolean deferred;
-
- qboolean newAnims; // true if using the new mission pack animations
- qboolean fixedlegs; // true if legs yaw is always the same as torso yaw
- qboolean fixedtorso; // true if torso never changes yaw
-
- vec3_t headOffset; // move head in icon views
- footstep_t footsteps;
- gender_t gender; // from model
-
- qhandle_t legsModel;
- qhandle_t legsSkin;
-
- qhandle_t torsoModel;
- qhandle_t torsoSkin;
-
- qhandle_t headModel;
- qhandle_t headSkin;
-
- qhandle_t modelIcon;
-
- animation_t animations[MAX_TOTALANIMATIONS];
-
- sfxHandle_t sounds[MAX_CUSTOM_SOUNDS];
-
- int isDead;
-} clientInfo_t;
-
-
-// each WP_* weapon enum has an associated weaponInfo_t
-// that contains media references necessary to present the
-// weapon and its effects
-typedef struct weaponInfo_s {
- qboolean registered;
- gitem_t *item;
-
- qhandle_t handsModel; // the hands don't actually draw, they just position the weapon
- qhandle_t weaponModel;
- qhandle_t barrelModel;
- qhandle_t flashModel;
-
- vec3_t weaponMidpoint; // so it will rotate centered instead of by tag
-
- float flashDlight;
- vec3_t flashDlightColor;
- sfxHandle_t flashSound[4]; // fast firing weapons randomly choose
-
- qhandle_t weaponIcon;
- qhandle_t ammoIcon;
-
- qhandle_t ammoModel;
-
- qhandle_t missileModel;
- sfxHandle_t missileSound;
- void (*missileTrailFunc)( centity_t *, const struct weaponInfo_s *wi );
- float missileDlight;
- vec3_t missileDlightColor;
- int missileRenderfx;
-
- void (*ejectBrassFunc)( centity_t * );
-
- float trailRadius;
- float wiTrailTime;
-
- sfxHandle_t readySound;
- sfxHandle_t firingSound;
- qboolean loopFireSound;
-} weaponInfo_t;
-
-
-// each IT_* item has an associated itemInfo_t
-// that constains media references necessary to present the
-// item and its effects
-typedef struct {
- qboolean registered;
- qhandle_t models[MAX_ITEM_MODELS];
- qhandle_t icon;
-} itemInfo_t;
-
-
-typedef struct {
- int itemNum;
-} powerupInfo_t;
-
-
-#define MAX_SKULLTRAIL 10
-
-typedef struct {
- vec3_t positions[MAX_SKULLTRAIL];
- int numpositions;
-} skulltrail_t;
-
-
-#define MAX_REWARDSTACK 10
-#define MAX_SOUNDBUFFER 20
-
-//======================================================================
-
-// all cg.stepTime, cg.duckTime, cg.landTime, etc are set to cg.time when the action
-// occurs, and they will have visible effects for #define STEP_TIME or whatever msec after
-
-#define MAX_PREDICTED_EVENTS 16
-
-//unlagged - optimized prediction
-#define NUM_SAVED_STATES (CMD_BACKUP + 2)
-//unlagged - optimized prediction
-
-typedef struct {
- int clientFrame; // incremented each frame
-
- int clientNum;
-
- qboolean demoPlayback;
- qboolean levelShot; // taking a level menu screenshot
- int deferredPlayerLoading;
- qboolean loading; // don't defer players at initial startup
- qboolean intermissionStarted; // don't play voice rewards, because game will end shortly
-
- // there are only one or two snapshot_t that are relevent at a time
- int latestSnapshotNum; // the number of snapshots the client system has received
- int latestSnapshotTime; // the time from latestSnapshotNum, so we don't need to read the snapshot yet
-
- snapshot_t *snap; // cg.snap->serverTime <= cg.time
- snapshot_t *nextSnap; // cg.nextSnap->serverTime > cg.time, or NULL
- snapshot_t activeSnapshots[2];
-
- float frameInterpolation; // (float)( cg.time - cg.frame->serverTime ) / (cg.nextFrame->serverTime - cg.frame->serverTime)
-
- qboolean thisFrameTeleport;
- qboolean nextFrameTeleport;
-
- int frametime; // cg.time - cg.oldTime
-
- int time; // this is the time value that the client
- // is rendering at.
- int oldTime; // time at last frame, used for missile trails and prediction checking
-
- int physicsTime; // either cg.snap->time or cg.nextSnap->time
-
- int timelimitWarnings; // 5 min, 1 min, overtime
- int fraglimitWarnings;
-
- qboolean mapRestart; // set on a map restart to set back the weapon
-
- qboolean renderingThirdPerson; // during deaths, chasecams, etc
-
- // prediction state
- qboolean hyperspace; // true if prediction has hit a trigger_teleport
- playerState_t predictedPlayerState;
- centity_t predictedPlayerEntity;
- qboolean validPPS; // clear until the first call to CG_PredictPlayerState
- int predictedErrorTime;
- vec3_t predictedError;
-
- int eventSequence;
- int predictableEvents[MAX_PREDICTED_EVENTS];
-
- float stepChange; // for stair up smoothing
- int stepTime;
-
- float duckChange; // for duck viewheight smoothing
- int duckTime;
-
- float landChange; // for landing hard
- int landTime;
-
- // input state sent to server
- int weaponSelect;
-
- // auto rotating items
- vec3_t autoAngles;
- vec3_t autoAxis[3];
- vec3_t autoAnglesFast;
- vec3_t autoAxisFast[3];
-
- // view rendering
- refdef_t refdef;
- vec3_t refdefViewAngles; // will be converted to refdef.viewaxis
-
- // zoom key
- qboolean zoomed;
- int zoomTime;
- float zoomSensitivity;
-
- // information screen text during loading
- char infoScreenText[MAX_STRING_CHARS];
-
- // scoreboard
- int scoresRequestTime;
- int numScores;
- int selectedScore;
- int teamScores[2];
- score_t scores[MAX_CLIENTS];
- qboolean showScores;
- qboolean scoreBoardShowing;
- int scoreFadeTime;
- char killerName[MAX_NAME_LENGTH];
- char spectatorList[MAX_STRING_CHARS]; // list of names
- int spectatorLen; // length of list
- float spectatorWidth; // width in device units
- int spectatorTime; // next time to offset
- int spectatorPaintX; // current paint x
- int spectatorPaintX2; // current paint x
- int spectatorOffset; // current offset from start
- int spectatorPaintLen; // current offset from start
-
- // skull trails
- skulltrail_t skulltrails[MAX_CLIENTS];
-
- // centerprinting
- int centerPrintTime;
- int centerPrintCharWidth;
- int centerPrintY;
- char centerPrint[1024];
- int centerPrintLines;
-
- // low ammo warning state
- int lowAmmoWarning; // 1 = low, 2 = empty
-
- // kill timers for carnage reward
- int lastKillTime;
-
- // crosshair client ID
- int crosshairClientNum;
- int crosshairClientTime;
-
- // powerup active flashing
- int powerupActive;
- int powerupTime;
-
- // attacking player
- int attackerTime;
- int voiceTime;
-
- // reward medals
- int rewardStack;
- int rewardTime;
- int rewardCount[MAX_REWARDSTACK];
- qhandle_t rewardShader[MAX_REWARDSTACK];
- qhandle_t rewardSound[MAX_REWARDSTACK];
-
- // sound buffer mainly for announcer sounds
- int soundBufferIn;
- int soundBufferOut;
- int soundTime;
- qhandle_t soundBuffer[MAX_SOUNDBUFFER];
-
- // for voice chat buffer
- int voiceChatTime;
- int voiceChatBufferIn;
- int voiceChatBufferOut;
-
- // warmup countdown
- int warmup;
- int warmupCount;
-
- //==========================
-
- int itemPickup;
- int itemPickupTime;
- int itemPickupBlendTime; // the pulse around the crosshair is timed seperately
-
- int weaponSelectTime;
- int weaponAnimation;
- int weaponAnimationTime;
-
- // blend blobs
- float damageTime;
- float damageX, damageY, damageValue;
-
- // status bar head
- float headYaw;
- float headEndPitch;
- float headEndYaw;
- int headEndTime;
- float headStartPitch;
- float headStartYaw;
- int headStartTime;
-
- // view movement
- float v_dmg_time;
- float v_dmg_pitch;
- float v_dmg_roll;
-
- vec3_t kick_angles; // weapon kicks
- vec3_t kick_origin;
-
- // temp working variables for player view
- float bobfracsin;
- int bobcycle;
- float xyspeed;
- int nextOrbitTime;
-
- //qboolean cameraMode; // if rendering from a loaded camera
-
-
- // development tool
- refEntity_t testModelEntity;
- char testModelName[MAX_QPATH];
- qboolean testGun;
-
-//unlagged - optimized prediction
- int lastPredictedCommand;
- int lastServerTime;
- playerState_t savedPmoveStates[NUM_SAVED_STATES];
- int stateHead, stateTail;
-//unlagged - optimized prediction
-
-} cg_t;
-
-
-// all of the model, shader, and sound references that are
-// loaded at gamestate time are stored in cgMedia_t
-// Other media that can be tied to clients, weapons, or items are
-// stored in the clientInfo_t, itemInfo_t, weaponInfo_t, and powerupInfo_t
-typedef struct {
- qhandle_t charsetShader;
- qhandle_t charsetProp;
- qhandle_t charsetPropGlow;
- qhandle_t charsetPropB;
- qhandle_t whiteShader;
-
- qhandle_t redCubeModel;
- qhandle_t blueCubeModel;
- qhandle_t redCubeIcon;
- qhandle_t blueCubeIcon;
- qhandle_t redFlagModel;
- qhandle_t blueFlagModel;
- qhandle_t neutralFlagModel;
- qhandle_t redFlagShader[3];
- qhandle_t blueFlagShader[3];
- qhandle_t flagShader[4];
-
-//For Double Domination:
- //qhandle_t ddPointA;
- //qhandle_t ddPointB;
- qhandle_t ddPointSkinA[4]; //white,red,blue,none
- qhandle_t ddPointSkinB[4]; //white,red,blue,none
-
- qhandle_t flagPoleModel;
- qhandle_t flagFlapModel;
-
- qhandle_t redFlagFlapSkin;
- qhandle_t blueFlagFlapSkin;
- qhandle_t neutralFlagFlapSkin;
-
- qhandle_t redFlagBaseModel;
- qhandle_t blueFlagBaseModel;
- qhandle_t neutralFlagBaseModel;
-
- qhandle_t overloadBaseModel;
- qhandle_t overloadTargetModel;
- qhandle_t overloadLightsModel;
- qhandle_t overloadEnergyModel;
-
- qhandle_t harvesterModel;
- qhandle_t harvesterRedSkin;
- qhandle_t harvesterBlueSkin;
- qhandle_t harvesterNeutralModel;
-
- qhandle_t armorModel;
- qhandle_t armorIcon;
-
- qhandle_t teamStatusBar;
-
- qhandle_t deferShader;
-
- // gib explosions
- qhandle_t gibAbdomen;
- qhandle_t gibArm;
- qhandle_t gibChest;
- qhandle_t gibFist;
- qhandle_t gibFoot;
- qhandle_t gibForearm;
- qhandle_t gibIntestine;
- qhandle_t gibLeg;
- qhandle_t gibSkull;
- qhandle_t gibBrain;
-
- qhandle_t smoke2;
-
- qhandle_t machinegunBrassModel;
- qhandle_t shotgunBrassModel;
-
- qhandle_t railRingsShader;
- qhandle_t railCoreShader;
-
- qhandle_t lightningShader;
-
- qhandle_t friendShader;
-
- qhandle_t balloonShader;
- qhandle_t connectionShader;
-
- qhandle_t selectShader;
- qhandle_t viewBloodShader;
- qhandle_t tracerShader;
- qhandle_t crosshairShader[NUM_CROSSHAIRS];
- qhandle_t lagometerShader;
- qhandle_t backTileShader;
- qhandle_t noammoShader;
-
- qhandle_t smokePuffShader;
- qhandle_t smokePuffRageProShader;
- qhandle_t shotgunSmokePuffShader;
- qhandle_t plasmaBallShader;
- qhandle_t waterBubbleShader;
- qhandle_t bloodTrailShader;
-
-
-
- // LEILEI shaders
-
- qhandle_t lsmkShader1;
- qhandle_t lsmkShader2;
- qhandle_t lsmkShader3;
- qhandle_t lsmkShader4;
- qhandle_t lbumShader1;
- qhandle_t lfblShader1;
- qhandle_t lsplShader;
- qhandle_t lspkShader1;
- qhandle_t lspkShader2;
- qhandle_t lbldShader1;
- qhandle_t lbldShader2;
-
-
-//#ifdef MISSIONPACK
- qhandle_t nailPuffShader;
- qhandle_t blueProxMine;
-//#endif
-
- qhandle_t numberShaders[11];
-
- qhandle_t shadowMarkShader;
-
- qhandle_t botSkillShaders[5];
-
- // wall mark shaders
- qhandle_t wakeMarkShader;
- qhandle_t bloodMarkShader;
- qhandle_t bulletMarkShader;
- qhandle_t burnMarkShader;
- qhandle_t holeMarkShader;
- qhandle_t energyMarkShader;
-
- // powerup shaders
- qhandle_t quadShader;
- qhandle_t redQuadShader;
- qhandle_t quadWeaponShader;
- qhandle_t invisShader;
- qhandle_t regenShader;
- qhandle_t battleSuitShader;
- qhandle_t battleWeaponShader;
- qhandle_t hastePuffShader;
- qhandle_t redKamikazeShader;
- qhandle_t blueKamikazeShader;
-
- // weapon effect models
- qhandle_t bulletFlashModel;
- qhandle_t ringFlashModel;
- qhandle_t dishFlashModel;
- qhandle_t lightningExplosionModel;
-
- // weapon effect shaders
- qhandle_t railExplosionShader;
- qhandle_t plasmaExplosionShader;
- qhandle_t bulletExplosionShader;
- qhandle_t rocketExplosionShader;
- qhandle_t grenadeExplosionShader;
- qhandle_t bfgExplosionShader;
- qhandle_t bloodExplosionShader;
-
- // special effects models
- qhandle_t teleportEffectModel;
- qhandle_t teleportEffectShader;
-//#ifdef MISSIONPACK
- qhandle_t kamikazeEffectModel;
- qhandle_t kamikazeShockWave;
- qhandle_t kamikazeHeadModel;
- qhandle_t kamikazeHeadTrail;
- qhandle_t guardPowerupModel;
- qhandle_t scoutPowerupModel;
- qhandle_t doublerPowerupModel;
- qhandle_t ammoRegenPowerupModel;
- qhandle_t invulnerabilityImpactModel;
- qhandle_t invulnerabilityJuicedModel;
- qhandle_t medkitUsageModel;
- qhandle_t dustPuffShader;
- qhandle_t heartShader;
-//#endif
- qhandle_t invulnerabilityPowerupModel;
-
- // scoreboard headers
- qhandle_t scoreboardName;
- qhandle_t scoreboardPing;
- qhandle_t scoreboardScore;
- qhandle_t scoreboardTime;
-
- // medals shown during gameplay
- qhandle_t medalImpressive;
- qhandle_t medalExcellent;
- qhandle_t medalGauntlet;
- qhandle_t medalDefend;
- qhandle_t medalAssist;
- qhandle_t medalCapture;
-
- // sounds
- sfxHandle_t quadSound;
- sfxHandle_t tracerSound;
- sfxHandle_t selectSound;
- sfxHandle_t useNothingSound;
- sfxHandle_t wearOffSound;
- sfxHandle_t footsteps[FOOTSTEP_TOTAL][4];
- sfxHandle_t sfx_lghit1;
- sfxHandle_t sfx_lghit2;
- sfxHandle_t sfx_lghit3;
- sfxHandle_t sfx_ric1;
- sfxHandle_t sfx_ric2;
- sfxHandle_t sfx_ric3;
- sfxHandle_t sfx_railg;
- sfxHandle_t sfx_rockexp;
- sfxHandle_t sfx_plasmaexp;
-//#ifdef MISSIONPACK
- sfxHandle_t sfx_proxexp;
- sfxHandle_t sfx_nghit;
- sfxHandle_t sfx_nghitflesh;
- sfxHandle_t sfx_nghitmetal;
- sfxHandle_t sfx_chghit;
- sfxHandle_t sfx_chghitflesh;
- sfxHandle_t sfx_chghitmetal;
- sfxHandle_t kamikazeExplodeSound;
- sfxHandle_t kamikazeImplodeSound;
- sfxHandle_t kamikazeFarSound;
- sfxHandle_t useInvulnerabilitySound;
- sfxHandle_t invulnerabilityImpactSound1;
- sfxHandle_t invulnerabilityImpactSound2;
- sfxHandle_t invulnerabilityImpactSound3;
- sfxHandle_t invulnerabilityJuicedSound;
- sfxHandle_t obeliskHitSound1;
- sfxHandle_t obeliskHitSound2;
- sfxHandle_t obeliskHitSound3;
- sfxHandle_t obeliskRespawnSound;
- sfxHandle_t winnerSound;
- sfxHandle_t loserSound;
- sfxHandle_t youSuckSound;
-//#endif
- sfxHandle_t gibSound;
- sfxHandle_t gibBounce1Sound;
- sfxHandle_t gibBounce2Sound;
- sfxHandle_t gibBounce3Sound;
- sfxHandle_t teleInSound;
- sfxHandle_t teleOutSound;
- sfxHandle_t noAmmoSound;
- sfxHandle_t respawnSound;
- sfxHandle_t talkSound;
- sfxHandle_t landSound;
- sfxHandle_t fallSound;
- sfxHandle_t jumpPadSound;
-
-// LEILEI
- sfxHandle_t lspl1Sound;
- sfxHandle_t lspl2Sound; // Blood Splat Noises
- sfxHandle_t lspl3Sound;
-
- sfxHandle_t lbul1Sound;
- sfxHandle_t lbul2Sound; // Bullet Drop Noises
- sfxHandle_t lbul3Sound;
-
- sfxHandle_t lshl1Sound;
- sfxHandle_t lshl2Sound; // Shell Drop Noises
- sfxHandle_t lshl3Sound;
-
-// LEILEI END
-
- sfxHandle_t oneMinuteSound;
- sfxHandle_t fiveMinuteSound;
- sfxHandle_t suddenDeathSound;
-
- sfxHandle_t threeFragSound;
- sfxHandle_t twoFragSound;
- sfxHandle_t oneFragSound;
-
- sfxHandle_t hitSound;
- sfxHandle_t hitSoundHighArmor;
- sfxHandle_t hitSoundLowArmor;
- sfxHandle_t hitTeamSound;
- sfxHandle_t impressiveSound;
- sfxHandle_t excellentSound;
- sfxHandle_t deniedSound;
- sfxHandle_t humiliationSound;
- sfxHandle_t assistSound;
- sfxHandle_t defendSound;
- sfxHandle_t firstImpressiveSound;
- sfxHandle_t firstExcellentSound;
- sfxHandle_t firstHumiliationSound;
-
- sfxHandle_t takenLeadSound;
- sfxHandle_t tiedLeadSound;
- sfxHandle_t lostLeadSound;
-
- sfxHandle_t voteNow;
- sfxHandle_t votePassed;
- sfxHandle_t voteFailed;
-
- sfxHandle_t watrInSound;
- sfxHandle_t watrOutSound;
- sfxHandle_t watrUnSound;
-
- sfxHandle_t flightSound;
- sfxHandle_t medkitSound;
-
- sfxHandle_t weaponHoverSound;
-
- // teamplay sounds
- sfxHandle_t captureAwardSound;
- sfxHandle_t redScoredSound;
- sfxHandle_t blueScoredSound;
- sfxHandle_t redLeadsSound;
- sfxHandle_t blueLeadsSound;
- sfxHandle_t teamsTiedSound;
-
- sfxHandle_t captureYourTeamSound;
- sfxHandle_t captureOpponentSound;
- sfxHandle_t returnYourTeamSound;
- sfxHandle_t returnOpponentSound;
- sfxHandle_t takenYourTeamSound;
- sfxHandle_t takenOpponentSound;
-
- sfxHandle_t redFlagReturnedSound;
- sfxHandle_t blueFlagReturnedSound;
- sfxHandle_t neutralFlagReturnedSound;
- sfxHandle_t enemyTookYourFlagSound;
- sfxHandle_t enemyTookTheFlagSound;
- sfxHandle_t yourTeamTookEnemyFlagSound;
- sfxHandle_t yourTeamTookTheFlagSound;
- sfxHandle_t youHaveFlagSound;
- sfxHandle_t yourBaseIsUnderAttackSound;
- sfxHandle_t holyShitSound;
-
- // tournament sounds
- sfxHandle_t count3Sound;
- sfxHandle_t count2Sound;
- sfxHandle_t count1Sound;
- sfxHandle_t countFightSound;
- sfxHandle_t countPrepareSound;
-
-#ifdef MISSIONPACK
- // new stuff
- qhandle_t patrolShader;
- qhandle_t assaultShader;
- qhandle_t campShader;
- qhandle_t followShader;
- qhandle_t defendShader;
- qhandle_t teamLeaderShader;
- qhandle_t retrieveShader;
- qhandle_t escortShader;
- qhandle_t deathShader;
- qhandle_t flagShaders[3];
- sfxHandle_t countPrepareTeamSound;
-#endif
-
- sfxHandle_t ammoregenSound;
- sfxHandle_t doublerSound;
- sfxHandle_t guardSound;
- sfxHandle_t scoutSound;
-
- qhandle_t cursor;
- qhandle_t selectCursor;
- qhandle_t sizeCursor;
-
- sfxHandle_t regenSound;
- sfxHandle_t protectSound;
- sfxHandle_t n_healthSound;
- sfxHandle_t hgrenb1aSound;
- sfxHandle_t hgrenb2aSound;
- sfxHandle_t wstbimplSound;
- sfxHandle_t wstbimpmSound;
- sfxHandle_t wstbimpdSound;
- sfxHandle_t wstbactvSound;
-
-} cgMedia_t;
-
-
-// The client game static (cgs) structure hold everything
-// loaded or calculated from the gamestate. It will NOT
-// be cleared when a tournement restart is done, allowing
-// all clients to begin playing instantly
-typedef struct {
- gameState_t gameState; // gamestate from server
- glconfig_t glconfig; // rendering configuration
- float screenXScale; // derived from glconfig
- float screenYScale;
- float screenXBias;
-
- int serverCommandSequence; // reliable command stream counter
- int processedSnapshotNum;// the number of snapshots cgame has requested
-
- qboolean localServer; // detected on startup by checking sv_running
-
- // parsed from serverinfo
- gametype_t gametype;
- int dmflags;
- int videoflags;
- int elimflags;
- int teamflags;
- int fraglimit;
- int capturelimit;
- int timelimit;
- int maxclients;
- char mapname[MAX_QPATH];
- char redTeam[MAX_QPATH];
- char blueTeam[MAX_QPATH];
-
- int voteTime;
- int voteYes;
- int voteNo;
- qboolean voteModified; // beep whenever changed
- char voteString[MAX_STRING_TOKENS];
-
- int teamVoteTime[2];
- int teamVoteYes[2];
- int teamVoteNo[2];
- qboolean teamVoteModified[2]; // beep whenever changed
- char teamVoteString[2][MAX_STRING_TOKENS];
-
- int levelStartTime;
-
-//Forced FFA
- int ffa_gt;
-
-//Elimination
- int roundStartTime;
- int roundtime;
-
-//CTF Elimination
- int attackingTeam;
-
-//Last Man Standing
- int lms_mode;
-
-//instantgib + nexuiz style rocket arena:
- int nopickup;
-
-//Double Domination DD
- int timetaken;
-
-//Domination
- int domination_points_count;
- char domination_points_names[MAX_DOMINATION_POINTS][MAX_DOMINATION_POINTS_NAMES];
- int domination_points_status[MAX_DOMINATION_POINTS];
-
-
- int scores1, scores2; // from configstrings
- int redflag, blueflag; // flag status from configstrings
- int flagStatus;
-
- qboolean newHud;
-
- //
- // locally derived information from gamestate
- //
- qhandle_t gameModels[MAX_MODELS];
- sfxHandle_t gameSounds[MAX_SOUNDS];
-
- int numInlineModels;
- qhandle_t inlineDrawModel[MAX_MODELS];
- vec3_t inlineModelMidpoints[MAX_MODELS];
-
- clientInfo_t clientinfo[MAX_CLIENTS];
-
- // teamchat width is *3 because of embedded color codes
- char teamChatMsgs[TEAMCHAT_HEIGHT][TEAMCHAT_WIDTH*3+1];
- int teamChatMsgTimes[TEAMCHAT_HEIGHT];
- int teamChatPos;
- int teamLastChatPos;
-
- int cursorX;
- int cursorY;
- qboolean eventHandling;
- qboolean mouseCaptured;
- qboolean sizingHud;
- void *capturedItem;
- qhandle_t activeCursor;
-
- // orders
- int currentOrder;
- qboolean orderPending;
- int orderTime;
- int currentVoiceClient;
- int acceptOrderTime;
- int acceptTask;
- int acceptLeader;
- char acceptVoice[MAX_NAME_LENGTH];
-
- // media
- cgMedia_t media;
-
-//unlagged - client options
- // this will be set to the server's g_delagHitscan
- int delagHitscan;
-//unlagged - client options
-//KK-OAX For storing whether or not the server has multikills enabled.
- int altExcellent;
-} cgs_t;
-
-//==============================================================================
-
-extern cgs_t cgs;
-extern cg_t cg;
-extern centity_t cg_entities[MAX_GENTITIES];
-extern weaponInfo_t cg_weapons[MAX_WEAPONS];
-extern itemInfo_t cg_items[MAX_ITEMS];
-extern markPoly_t cg_markPolys[MAX_MARK_POLYS];
-
-extern vmCvar_t cg_centertime;
-extern vmCvar_t cg_runpitch;
-extern vmCvar_t cg_runroll;
-extern vmCvar_t cg_bobup;
-extern vmCvar_t cg_bobpitch;
-extern vmCvar_t cg_bobroll;
-extern vmCvar_t cg_swingSpeed;
-extern vmCvar_t cg_shadows;
-extern vmCvar_t cg_gibs;
-extern vmCvar_t cg_drawTimer;
-extern vmCvar_t cg_drawFPS;
-extern vmCvar_t cg_drawSnapshot;
-extern vmCvar_t cg_draw3dIcons;
-extern vmCvar_t cg_drawIcons;
-extern vmCvar_t cg_drawAmmoWarning;
-extern vmCvar_t cg_drawCrosshair;
-extern vmCvar_t cg_drawCrosshairNames;
-extern vmCvar_t cg_drawRewards;
-extern vmCvar_t cg_drawTeamOverlay;
-extern vmCvar_t cg_teamOverlayUserinfo;
-extern vmCvar_t cg_crosshairX;
-extern vmCvar_t cg_crosshairY;
-extern vmCvar_t cg_crosshairSize;
-extern vmCvar_t cg_crosshairHealth;
-extern vmCvar_t cg_drawStatus;
-extern vmCvar_t cg_draw2D;
-extern vmCvar_t cg_animSpeed;
-extern vmCvar_t cg_debugAnim;
-extern vmCvar_t cg_debugPosition;
-extern vmCvar_t cg_debugEvents;
-extern vmCvar_t cg_railTrailTime;
-extern vmCvar_t cg_errorDecay;
-extern vmCvar_t cg_nopredict;
-extern vmCvar_t cg_noPlayerAnims;
-extern vmCvar_t cg_showmiss;
-extern vmCvar_t cg_footsteps;
-extern vmCvar_t cg_addMarks;
-extern vmCvar_t cg_brassTime;
-extern vmCvar_t cg_gun_frame;
-extern vmCvar_t cg_gun_x;
-extern vmCvar_t cg_gun_y;
-extern vmCvar_t cg_gun_z;
-extern vmCvar_t cg_drawGun;
-extern vmCvar_t cg_viewsize;
-extern vmCvar_t cg_tracerChance;
-extern vmCvar_t cg_tracerWidth;
-extern vmCvar_t cg_tracerLength;
-extern vmCvar_t cg_autoswitch;
-extern vmCvar_t cg_ignore;
-extern vmCvar_t cg_simpleItems;
-extern vmCvar_t cg_fov;
-extern vmCvar_t cg_zoomFov;
-extern vmCvar_t cg_thirdPersonRange;
-extern vmCvar_t cg_thirdPersonAngle;
-extern vmCvar_t cg_thirdPerson;
-extern vmCvar_t cg_lagometer;
-extern vmCvar_t cg_drawAttacker;
-extern vmCvar_t cg_drawSpeed;
-extern vmCvar_t cg_synchronousClients;
-extern vmCvar_t cg_teamChatTime;
-extern vmCvar_t cg_teamChatHeight;
-extern vmCvar_t cg_stats;
-extern vmCvar_t cg_forceModel;
-extern vmCvar_t cg_buildScript;
-extern vmCvar_t cg_paused;
-extern vmCvar_t cg_blood;
-extern vmCvar_t cg_predictItems;
-extern vmCvar_t cg_deferPlayers;
-extern vmCvar_t cg_drawFriend;
-extern vmCvar_t cg_teamChatsOnly;
-extern vmCvar_t cg_noVoiceChats;
-extern vmCvar_t cg_noVoiceText;
-extern vmCvar_t cg_scorePlum;
-//unlagged - smooth clients #2
-// this is done server-side now
-//extern vmCvar_t cg_smoothClients;
-//unlagged - smooth clients #2
-extern vmCvar_t pmove_fixed;
-extern vmCvar_t pmove_msec;
-extern vmCvar_t pmove_float;
-//extern vmCvar_t cg_pmove_fixed;
-extern vmCvar_t cg_cameraOrbit;
-extern vmCvar_t cg_cameraOrbitDelay;
-extern vmCvar_t cg_timescaleFadeEnd;
-extern vmCvar_t cg_timescaleFadeSpeed;
-extern vmCvar_t cg_timescale;
-extern vmCvar_t cg_cameraMode;
-extern vmCvar_t cg_smallFont;
-extern vmCvar_t cg_bigFont;
-extern vmCvar_t cg_noTaunt;
-extern vmCvar_t cg_noProjectileTrail;
-extern vmCvar_t cg_oldRail;
-extern vmCvar_t cg_oldRocket;
-
-extern vmCvar_t cg_leiEnhancement; // LEILEI'S LINE!
-extern vmCvar_t cg_leiGoreNoise; // LEILEI'S LINE!
-extern vmCvar_t cg_leiBrassNoise; // LEILEI'S LINE!
-extern vmCvar_t cg_leiSuperGoreyAwesome; // LEILEI'S LINE!
-extern vmCvar_t cg_oldPlasma;
-extern vmCvar_t cg_trueLightning;
-extern vmCvar_t cg_music;
-#ifdef MISSIONPACK
-extern vmCvar_t cg_redTeamName;
-extern vmCvar_t cg_blueTeamName;
-extern vmCvar_t cg_currentSelectedPlayer;
-extern vmCvar_t cg_currentSelectedPlayerName;
-extern vmCvar_t cg_singlePlayer;
-extern vmCvar_t cg_singlePlayerActive;
-extern vmCvar_t cg_recordSPDemo;
-extern vmCvar_t cg_recordSPDemoName;
-#endif
-//Sago: Moved outside
-extern vmCvar_t cg_obeliskRespawnDelay;
-extern vmCvar_t cg_enableDust;
-extern vmCvar_t cg_enableBreath;
-
-//unlagged - client options
-extern vmCvar_t cg_delag;
-//extern vmCvar_t cg_debugDelag;
-//extern vmCvar_t cg_drawBBox;
-extern vmCvar_t cg_cmdTimeNudge;
-extern vmCvar_t sv_fps;
-extern vmCvar_t cg_projectileNudge;
-extern vmCvar_t cg_optimizePrediction;
-extern vmCvar_t cl_timeNudge;
-//extern vmCvar_t cg_latentSnaps;
-//extern vmCvar_t cg_latentCmds;
-//extern vmCvar_t cg_plOut;
-//unlagged - client options
-
-//extra CVARS elimination
-extern vmCvar_t cg_alwaysWeaponBar;
-extern vmCvar_t cg_hitsound;
-extern vmCvar_t cg_voip_teamonly;
-extern vmCvar_t cg_voteflags;
-extern vmCvar_t cg_cyclegrapple;
-extern vmCvar_t cg_vote_custom_commands;
-
-extern vmCvar_t cg_autovertex;
-
-//Cvar to adjust the size of the fragmessage
-extern vmCvar_t cg_fragmsgsize;
-
-extern vmCvar_t cg_crosshairPulse;
-extern vmCvar_t cg_differentCrosshairs;
-extern vmCvar_t cg_ch1;
-extern vmCvar_t cg_ch1size;
-extern vmCvar_t cg_ch2;
-extern vmCvar_t cg_ch2size;
-extern vmCvar_t cg_ch3;
-extern vmCvar_t cg_ch3size;
-extern vmCvar_t cg_ch4;
-extern vmCvar_t cg_ch4size;
-extern vmCvar_t cg_ch5;
-extern vmCvar_t cg_ch5size;
-extern vmCvar_t cg_ch6;
-extern vmCvar_t cg_ch6size;
-extern vmCvar_t cg_ch7;
-extern vmCvar_t cg_ch7size;
-extern vmCvar_t cg_ch8;
-extern vmCvar_t cg_ch8size;
-extern vmCvar_t cg_ch9;
-extern vmCvar_t cg_ch9size;
-extern vmCvar_t cg_ch10;
-extern vmCvar_t cg_ch10size;
-extern vmCvar_t cg_ch11;
-extern vmCvar_t cg_ch11size;
-extern vmCvar_t cg_ch12;
-extern vmCvar_t cg_ch12size;
-extern vmCvar_t cg_ch13;
-extern vmCvar_t cg_ch13size;
-
-extern vmCvar_t cg_crosshairColorRed;
-extern vmCvar_t cg_crosshairColorGreen;
-extern vmCvar_t cg_crosshairColorBlue;
-
-extern vmCvar_t cg_weaponBarStyle;
-
-//unlagged - cg_unlagged.c
-void CG_PredictWeaponEffects( centity_t *cent );
-//void CG_AddBoundingBox( centity_t *cent );
-qboolean CG_Cvar_ClampInt( const char *name, vmCvar_t *vmCvar, int min, int max );
-//unlagged - cg_unlagged.c
-
-//
-// cg_main.c
-//
-const char *CG_ConfigString( int index );
-const char *CG_Argv( int arg );
-
-void QDECL CG_Printf( const char *msg, ... );
-void QDECL CG_Error( const char *msg, ... );
-
-void CG_StartMusic( void );
-
-void CG_UpdateCvars( void );
-
-int CG_CrosshairPlayer( void );
-int CG_LastAttacker( void );
-void CG_LoadMenus(const char *menuFile);
-void CG_KeyEvent(int key, qboolean down);
-void CG_MouseEvent(int x, int y);
-void CG_EventHandling(int type);
-void CG_RankRunFrame( void );
-void CG_SetScoreSelection(void *menu);
-score_t *CG_GetSelectedScore( void );
-void CG_BuildSpectatorString( void );
-
-//unlagged, sagos modfication
-void SnapVectorTowards( vec3_t v, vec3_t to );
-
-void CG_FairCvars();
-
-//
-// cg_view.c
-//
-void CG_TestModel_f (void);
-void CG_TestGun_f (void);
-void CG_TestModelNextFrame_f (void);
-void CG_TestModelPrevFrame_f (void);
-void CG_TestModelNextSkin_f (void);
-void CG_TestModelPrevSkin_f (void);
-void CG_ZoomDown_f( void );
-void CG_ZoomUp_f( void );
-void CG_AddBufferedSound( sfxHandle_t sfx);
-
-void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
-
-
-//
-// cg_drawtools.c
-//
-void CG_AdjustFrom640( float *x, float *y, float *w, float *h );
-void CG_FillRect( float x, float y, float width, float height, const float *color );
-void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader );
-void CG_DrawString( float x, float y, const char *string,
- float charWidth, float charHeight, const float *modulate );
-
-
-void CG_DrawStringExt( int x, int y, const char *string, const float *setColor,
- qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars );
-void CG_DrawBigString( int x, int y, const char *s, float alpha );
-void CG_DrawBigStringColor( int x, int y, const char *s, vec4_t color );
-void CG_DrawSmallString( int x, int y, const char *s, float alpha );
-void CG_DrawSmallStringColor( int x, int y, const char *s, vec4_t color );
-
-int CG_DrawStrlen( const char *str );
-
-float *CG_FadeColor( int startMsec, int totalMsec );
-float *CG_TeamColor( int team );
-void CG_TileClear( void );
-void CG_ColorForHealth( vec4_t hcolor );
-void CG_GetColorForHealth( int health, int armor, vec4_t hcolor );
-
-void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );
-void CG_DrawRect( float x, float y, float width, float height, float size, const float *color );
-void CG_DrawSides(float x, float y, float w, float h, float size);
-void CG_DrawTopBottom(float x, float y, float w, float h, float size);
-
-
-//
-// cg_draw.c, cg_newDraw.c
-//
-extern int sortedTeamPlayers[TEAM_MAXOVERLAY];
-extern int numSortedTeamPlayers;
-extern int drawTeamOverlayModificationCount;
-extern char systemChat[256];
-extern char teamChat1[256];
-extern char teamChat2[256];
-
-void CG_AddLagometerFrameInfo( void );
-void CG_AddLagometerSnapshotInfo( snapshot_t *snap );
-void CG_CenterPrint( const char *str, int y, int charWidth );
-void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles );
-void CG_DrawActive( stereoFrame_t stereoView );
-void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D );
-void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team );
-void CG_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle);
-void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style);
-int CG_Text_Width(const char *text, float scale, int limit);
-int CG_Text_Height(const char *text, float scale, int limit);
-void CG_SelectPrevPlayer( void );
-void CG_SelectNextPlayer( void );
-float CG_GetValue(int ownerDraw);
-qboolean CG_OwnerDrawVisible(int flags);
-void CG_RunMenuScript(char **args);
-void CG_ShowResponseHead( void );
-void CG_SetPrintString(int type, const char *p);
-void CG_InitTeamChat( void );
-void CG_GetTeamColor(vec4_t *color);
-const char *CG_GetGameStatusText( void );
-const char *CG_GetKillerText( void );
-void CG_Draw3DModel(float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles);
-void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader);
-void CG_CheckOrderPending( void );
-const char *CG_GameTypeString( void );
-qboolean CG_YourTeamHasFlag( void );
-qboolean CG_OtherTeamHasFlag( void );
-qhandle_t CG_StatusHandle(int task);
-
-
-
-//
-// cg_player.c
-//
-void CG_Player( centity_t *cent );
-void CG_ResetPlayerEntity( centity_t *cent );
-void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team );
-void CG_NewClientInfo( int clientNum );
-sfxHandle_t CG_CustomSound( int clientNum, const char *soundName );
-
-//
-// cg_predict.c
-//
-void CG_BuildSolidList( void );
-int CG_PointContents( const vec3_t point, int passEntityNum );
-void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
- int skipNumber, int mask );
-void CG_PredictPlayerState( void );
-void CG_LoadDeferredPlayers( void );
-
-
-//
-// cg_events.c
-//
-void CG_CheckEvents( centity_t *cent );
-const char *CG_PlaceString( int rank );
-void CG_EntityEvent( centity_t *cent, vec3_t position );
-void CG_PainEvent( centity_t *cent, int health );
-
-
-//
-// cg_ents.c
-//
-void CG_SetEntitySoundPosition( centity_t *cent );
-void CG_AddPacketEntities( void );
-void CG_Beam( centity_t *cent );
-void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out );
-
-void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- qhandle_t parentModel, char *tagName );
-void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- qhandle_t parentModel, char *tagName );
-
-
-
-//
-// cg_weapons.c
-//
-void CG_NextWeapon_f( void );
-void CG_PrevWeapon_f( void );
-void CG_Weapon_f( void );
-
-void CG_RegisterWeapon( int weaponNum );
-void CG_RegisterItemVisuals( int itemNum );
-
-void CG_FireWeapon( centity_t *cent );
-void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType );
-void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum );
-void CG_ShotgunFire( entityState_t *es );
-void CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum );
-
-void CG_RailTrail( clientInfo_t *ci, vec3_t start, vec3_t end );
-void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi );
-void CG_AddViewWeapon (playerState_t *ps);
-void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team );
-void CG_DrawWeaponSelect( void );
-
-void CG_DrawWeaponBar0(int count, int bits);
-void CG_DrawWeaponBar1(int count, int bits);
-void CG_DrawWeaponBar2(int count, int bits, float *color);
-void CG_DrawWeaponBar3(int count, int bits, float *color);
-void CG_DrawWeaponBar4(int count, int bits, float *color);
-void CG_DrawWeaponBar5(int count, int bits, float *color);
-void CG_DrawWeaponBar6(int count, int bits, float *color);
-void CG_DrawWeaponBar7(int count, int bits, float *color);
-
-void CG_OutOfAmmoChange( void ); // should this be in pmove?
-
-//
-// cg_marks.c
-//
-void CG_InitMarkPolys( void );
-void CG_AddMarks( void );
-void CG_ImpactMark( qhandle_t markShader,
- const vec3_t origin, const vec3_t dir,
- float orientation,
- float r, float g, float b, float a,
- qboolean alphaFade,
- float radius, qboolean temporary );
-
-//
-// cg_localents.c
-//
-void CG_InitLocalEntities( void );
-localEntity_t *CG_AllocLocalEntity( void );
-void CG_AddLocalEntities( void );
-
-//
-// cg_effects.c
-//
-localEntity_t *CG_SmokePuff( const vec3_t p,
- const vec3_t vel,
- float radius,
- float r, float g, float b, float a,
- float duration,
- int startTime,
- int fadeInTime,
- int leFlags,
- qhandle_t hShader );
-void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing );
-void CG_SpawnEffect( vec3_t org );
-//#ifdef MISSIONPACK
-void CG_KamikazeEffect( vec3_t org );
-void CG_ObeliskExplode( vec3_t org, int entityNum );
-void CG_ObeliskPain( vec3_t org );
-void CG_InvulnerabilityImpact( vec3_t org, vec3_t angles );
-void CG_InvulnerabilityJuiced( vec3_t org );
-void CG_LightningBoltBeam( vec3_t start, vec3_t end );
-//#endif
-void CG_ScorePlum( int client, vec3_t org, int score );
-
-void CG_GibPlayer( vec3_t playerOrigin );
-void CG_BigExplode( vec3_t playerOrigin );
-
-void CG_Bleed( vec3_t origin, int entityNum );
-
-localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
- qhandle_t hModel, qhandle_t shader, int msec,
- qboolean isSprite );
-
-//
-// cg_snapshot.c
-//
-void CG_ProcessSnapshots( void );
-//unlagged - early transitioning
-void CG_TransitionEntity( centity_t *cent );
-//unlagged - early transitioning
-
-//
-// cg_info.c
-//
-void CG_LoadingString( const char *s );
-void CG_LoadingItem( int itemNum );
-void CG_LoadingClient( int clientNum );
-void CG_DrawInformation( void );
-
-//
-// cg_scoreboard.c
-//
-qboolean CG_DrawOldScoreboard( void );
-void CG_DrawOldTourneyScoreboard( void );
-
-//
-// cg_challenges.c
-//
-void challenges_init(void);
-void challenges_save(void);
-unsigned int getChallenge(int challenge);
-void addChallenge(int challenge);
-
-//
-// cg_consolecmds.c
-//
-qboolean CG_ConsoleCommand( void );
-void CG_InitConsoleCommands( void );
-
-//
-// cg_servercmds.c
-//
-void CG_ExecuteNewServerCommands( int latestSequence );
-void CG_ParseServerinfo( void );
-void CG_SetConfigValues( void );
-void CG_LoadVoiceChats( void );
-void CG_ShaderStateChanged(void);
-void CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd );
-void CG_PlayBufferedVoiceChats( void );
-
-//
-// cg_playerstate.c
-//
-void CG_Respawn( void );
-void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops );
-void CG_CheckChangedPredictableEvents( playerState_t *ps );
-
-
-//===============================================
-
-//
-// system traps
-// These functions are how the cgame communicates with the main game system
-//
-
-// print message on the local console
-void trap_Print( const char *fmt );
-
-// abort the game
-void trap_Error( const char *fmt );
-
-// milliseconds should only be used for performance tuning, never
-// for anything game related. Get time from the CG_DrawActiveFrame parameter
-int trap_Milliseconds( void );
-
-// console variable interaction
-void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
-void trap_Cvar_Update( vmCvar_t *vmCvar );
-void trap_Cvar_Set( const char *var_name, const char *value );
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-
-// ServerCommand and ConsoleCommand parameter access
-int trap_Argc( void );
-void trap_Argv( int n, char *buffer, int bufferLength );
-void trap_Args( char *buffer, int bufferLength );
-
-// filesystem access
-// returns length of file
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
-void trap_FS_Read( void *buffer, int len, fileHandle_t f );
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
-void trap_FS_FCloseFile( fileHandle_t f );
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
-
-// add commands to the local console as if they were typed in
-// for map changing, etc. The command is not executed immediately,
-// but will be executed in order the next time console commands
-// are processed
-void trap_SendConsoleCommand( const char *text );
-
-// register a command name so the console can perform command completion.
-// FIXME: replace this with a normal console command "defineCommand"?
-void trap_AddCommand( const char *cmdName );
-
-// send a string to the server over the network
-void trap_SendClientCommand( const char *s );
-
-// force a screen update, only used during gamestate load
-void trap_UpdateScreen( void );
-
-// model collision
-void trap_CM_LoadMap( const char *mapname );
-int trap_CM_NumInlineModels( void );
-clipHandle_t trap_CM_InlineModel( int index ); // 0 = world, 1+ = bmodels
-clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs );
-int trap_CM_PointContents( const vec3_t p, clipHandle_t model );
-int trap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles );
-void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask );
-void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask,
- const vec3_t origin, const vec3_t angles );
-
-// Returns the projection of a polygon onto the solid brushes in the world
-int trap_CM_MarkFragments( int numPoints, const vec3_t *points,
- const vec3_t projection,
- int maxPoints, vec3_t pointBuffer,
- int maxFragments, markFragment_t *fragmentBuffer );
-
-// normal sounds will have their volume dynamically changed as their entity
-// moves and the listener moves
-void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx );
-void trap_S_StopLoopingSound(int entnum);
-
-// a local sound is always played full volume
-void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );
-void trap_S_ClearLoopingSounds( qboolean killall );
-void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
-void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
-void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin );
-
-// respatialize recalculates the volumes of sound as they should be heard by the
-// given entityNum and position
-void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
-sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ); // returns buzz if not found
-void trap_S_StartBackgroundTrack( const char *intro, const char *loop ); // empty name stops music
-void trap_S_StopBackgroundTrack( void );
-
-
-void trap_R_LoadWorldMap( const char *mapname );
-
-// all media should be registered during level startup to prevent
-// hitches during gameplay
-qhandle_t trap_R_RegisterModel( const char *name ); // returns rgb axis if not found
-qhandle_t trap_R_RegisterSkin( const char *name ); // returns all white if not found
-qhandle_t trap_R_RegisterShader( const char *name ); // returns all white if not found
-qhandle_t trap_R_RegisterShaderNoMip( const char *name ); // returns all white if not found
-
-// a scene is built up by calls to R_ClearScene and the various R_Add functions.
-// Nothing is drawn until R_RenderScene is called.
-void trap_R_ClearScene( void );
-void trap_R_AddRefEntityToScene( const refEntity_t *re );
-
-// polys are intended for simple wall marks, not really for doing
-// significant construction
-void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );
-void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int numPolys );
-void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
-int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
-void trap_R_RenderScene( const refdef_t *fd );
-void trap_R_SetColor( const float *rgba ); // NULL = 1,1,1,1
-void trap_R_DrawStretchPic( float x, float y, float w, float h,
- float s1, float t1, float s2, float t2, qhandle_t hShader );
-void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );
-int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame,
- float frac, const char *tagName );
-void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset );
-
-// The glconfig_t will not change during the life of a cgame.
-// If it needs to change, the entire cgame will be restarted, because
-// all the qhandle_t are then invalid.
-void trap_GetGlconfig( glconfig_t *glconfig );
-
-// the gamestate should be grabbed at startup, and whenever a
-// configstring changes
-void trap_GetGameState( gameState_t *gamestate );
-
-// cgame will poll each frame to see if a newer snapshot has arrived
-// that it is interested in. The time is returned seperately so that
-// snapshot latency can be calculated.
-void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime );
-
-// a snapshot get can fail if the snapshot (or the entties it holds) is so
-// old that it has fallen out of the client system queue
-qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot );
-
-// retrieve a text command from the server stream
-// the current snapshot will hold the number of the most recent command
-// qfalse can be returned if the client system handled the command
-// argc() / argv() can be used to examine the parameters of the command
-qboolean trap_GetServerCommand( int serverCommandNumber );
-
-// returns the most recent command number that can be passed to GetUserCmd
-// this will always be at least one higher than the number in the current
-// snapshot, and it may be quite a few higher if it is a fast computer on
-// a lagged connection
-int trap_GetCurrentCmdNumber( void );
-
-qboolean trap_GetUserCmd( int cmdNumber, usercmd_t *ucmd );
-
-// used for the weapon select and zoom
-void trap_SetUserCmdValue( int stateValue, float sensitivityScale );
-
-// aids for VM testing
-void testPrintInt( char *string, int i );
-void testPrintFloat( char *string, float f );
-
-int trap_MemoryRemaining( void );
-void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font);
-qboolean trap_Key_IsDown( int keynum );
-int trap_Key_GetCatcher( void );
-void trap_Key_SetCatcher( int catcher );
-int trap_Key_GetKey( const char *binding );
-
-
-typedef enum {
- SYSTEM_PRINT,
- CHAT_PRINT,
- TEAMCHAT_PRINT
-} q3print_t; // bk001201 - warning: useless keyword or type name in empty declaration
-
-
-int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits);
-e_status trap_CIN_StopCinematic(int handle);
-e_status trap_CIN_RunCinematic (int handle);
-void trap_CIN_DrawCinematic (int handle);
-void trap_CIN_SetExtents (int handle, int x, int y, int w, int h);
-
-void trap_SnapVector( float *v );
-
-qboolean trap_loadCamera(const char *name);
-void trap_startCamera(int time);
-qboolean trap_getCameraInfo(int time, vec3_t *origin, vec3_t *angles);
-
-qboolean trap_GetEntityToken( char *buffer, int bufferSize );
-
-void CG_ClearParticles (void);
-void CG_AddParticles (void);
-void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum);
-void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent);
-void CG_AddParticleShrapnel (localEntity_t *le);
-void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent);
-void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration);
-void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed);
-void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir);
-void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha);
-void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd);
-extern qboolean initparticles;
-int CG_NewParticleArea ( int num );
-
-
-// LEILEI ENHANCEMENT
-
diff --git a/game/code/cgame/cg_localents.c b/game/code/cgame/cg_localents.c
deleted file mode 100644
index 5c526b2..0000000
--- a/game/code/cgame/cg_localents.c
+++ /dev/null
@@ -1,1101 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-// cg_localents.c -- every frame, generate renderer commands for locally
-// processed entities, like smoke puffs, gibs, shells, etc.
-
-#include "cg_local.h"
-
-#define MAX_LOCAL_ENTITIES 512
-localEntity_t cg_localEntities[MAX_LOCAL_ENTITIES];
-localEntity_t cg_activeLocalEntities; // double linked list
-localEntity_t *cg_freeLocalEntities; // single linked list
-
-/*
-===================
-CG_InitLocalEntities
-
-This is called at startup and for tournement restarts
-===================
-*/
-void CG_InitLocalEntities( void ) {
- int i;
-
- memset( cg_localEntities, 0, sizeof( cg_localEntities ) );
- cg_activeLocalEntities.next = &cg_activeLocalEntities;
- cg_activeLocalEntities.prev = &cg_activeLocalEntities;
- cg_freeLocalEntities = cg_localEntities;
- for ( i = 0 ; i < MAX_LOCAL_ENTITIES - 1 ; i++ ) {
- cg_localEntities[i].next = &cg_localEntities[i+1];
- }
-}
-
-
-/*
-==================
-CG_FreeLocalEntity
-==================
-*/
-void CG_FreeLocalEntity( localEntity_t *le ) {
- if ( !le->prev ) {
- CG_Error( "CG_FreeLocalEntity: not active" );
- }
-
- // remove from the doubly linked active list
- le->prev->next = le->next;
- le->next->prev = le->prev;
-
- // the free list is only singly linked
- le->next = cg_freeLocalEntities;
- cg_freeLocalEntities = le;
-}
-
-/*
-===================
-CG_AllocLocalEntity
-
-Will allways succeed, even if it requires freeing an old active entity
-===================
-*/
-localEntity_t *CG_AllocLocalEntity( void ) {
- localEntity_t *le;
-
- if ( !cg_freeLocalEntities ) {
- // no free entities, so free the one at the end of the chain
- // remove the oldest active entity
- CG_FreeLocalEntity( cg_activeLocalEntities.prev );
- }
-
- le = cg_freeLocalEntities;
- cg_freeLocalEntities = cg_freeLocalEntities->next;
-
- memset( le, 0, sizeof( *le ) );
-
- // link into the active list
- le->next = cg_activeLocalEntities.next;
- le->prev = &cg_activeLocalEntities;
- cg_activeLocalEntities.next->prev = le;
- cg_activeLocalEntities.next = le;
- return le;
-}
-
-
-/*
-====================================================================================
-
-FRAGMENT PROCESSING
-
-A fragment localentity interacts with the environment in some way (hitting walls),
-or generates more localentities along a trail.
-
-====================================================================================
-*/
-
-/*
-================
-CG_BloodTrail
-
-Leave expanding blood puffs behind gibs
-================
-*/
-void CG_BloodTrail( localEntity_t *le ) {
- int t;
- int t2;
- int step;
- vec3_t newOrigin;
- localEntity_t *blood;
-
- step = 150;
- t = step * ( (cg.time - cg.frametime + step ) / step );
- t2 = step * ( cg.time / step );
-
- for ( ; t <= t2; t += step ) {
- BG_EvaluateTrajectory( &le->pos, t, newOrigin );
-
- blood = CG_SmokePuff( newOrigin, vec3_origin,
- 20, // radius
- 1, 1, 1, 1, // color
- 2000, // trailTime
- t, // startTime
- 0, // fadeInTime
- 0, // flags
- cgs.media.bloodTrailShader );
- // use the optimized version
- blood->leType = LE_FALL_SCALE_FADE;
- // drop a total of 40 units over its lifetime
- blood->pos.trDelta[2] = 40;
- if ( cg_leiSuperGoreyAwesome.integer ) {
-// blood = CG_SpurtBlood( newOrigin, vec3_origin, 3); // LEILEI more gore plz
- }
- }
-}
-
-
-// LEILEI
-void CG_SmallBloodTrail( localEntity_t *le ) {
- int t;
- int t2;
- int step;
- vec3_t newOrigin;
- localEntity_t *blood;
-
- step = 61;
- t = step * ( (cg.time - cg.frametime + step ) / step );
- t2 = step * ( cg.time / step );
-
- for ( ; t <= t2; t += step ) {
- BG_EvaluateTrajectory( &le->pos, t, newOrigin );
-
- blood = CG_SmokePuff( newOrigin, vec3_origin,
- 3, // radius
- 1, 1, 1, 1, // color
- 770, // trailTime
- t, // startTime
- 0, // fadeInTime
- 0, // flags
- cgs.media.lbldShader1 );
- // use the optimized version
- blood->leType = LE_FALL_SCALE_FADE;
- // drop a total of 40 units over its lifetime
- blood->pos.trDelta[2] = 120;
- }
-}
-
-
-
-/*
-================
-CG_FragmentBounceMark
-================
-*/
-void CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) {
- int radius;
-
- if ( le->leMarkType == LEMT_BLOOD ) {
-
- radius = 16 + (rand()&31);
- CG_ImpactMark( cgs.media.bloodMarkShader, trace->endpos, trace->plane.normal, random()*360,
- 1,1,1,1, qtrue, radius, qfalse );
- } else if ( le->leMarkType == LEMT_BURN ) {
-
- radius = 8 + (rand()&15);
- CG_ImpactMark( cgs.media.burnMarkShader, trace->endpos, trace->plane.normal, random()*360,
- 1,1,1,1, qtrue, radius, qfalse );
- }
-
-
- // don't allow a fragment to make multiple marks, or they
- // pile up while settling
- le->leMarkType = LEMT_NONE;
-}
-
-/*
-================
-CG_FragmentBounceSound
-================
-*/
-void CG_FragmentBounceSound( localEntity_t *le, trace_t *trace ) {
- if ( le->leBounceSoundType == LEBS_BLOOD ) {
- // half the gibs will make splat sounds
- if ( rand() & 1 ) {
- int r = rand()&3;
- sfxHandle_t s;
-
- if ( r == 0 ) {
- s = cgs.media.gibBounce1Sound;
- } else if ( r == 1 ) {
- s = cgs.media.gibBounce2Sound;
- } else {
- s = cgs.media.gibBounce3Sound;
- }
- trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );
- }
- } else if ( le->leBounceSoundType == LEBS_BRASS ) {
- if ( cg_leiBrassNoise.integer ) {
- // half the casings will make casing sounds
- if ( rand() & 1 ) {
- int r = rand()&3;
- sfxHandle_t s;
-
- if ( r == 0 ) {
- s = cgs.media.lbul1Sound;
- } else if ( r == 1 ) {
- s = cgs.media.lbul2Sound;
- } else {
- s = cgs.media.lbul3Sound;
- }
- trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );
- }
- }
-
- } else if ( le->leBounceSoundType == LEBS_SHELL ) {
-
- if ( cg_leiBrassNoise.integer ) {
-
- // half the casings will make casing sounds
- if ( rand() & 1 ) {
- int r = rand()&3;
- sfxHandle_t s;
-
- if ( r == 0 ) {
- s = cgs.media.lshl1Sound;
- } else if ( r == 1 ) {
- s = cgs.media.lshl2Sound;
- } else {
- s = cgs.media.lshl3Sound;
- }
- trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );
- }
- }
-
- }
-
- // don't allow a fragment to make multiple bounce sounds,
- // or it gets too noisy as they settle
- le->leBounceSoundType = LEBS_NONE;
-}
-
-
-// LEILEI
-void CG_GoreMark( localEntity_t *le, trace_t *trace ) {
- int radius;
-
- if ( le->leMarkType == LEMT_BURN ) {
-
- radius = 6 + (rand()&16);
- CG_ImpactMark( cgs.media.lbldShader2, trace->endpos, trace->plane.normal, random()*360,
- 1,1,1,1, qtrue, radius, qfalse );
-
- }
-
- le->leMarkType = LEMT_NONE;
-}
-
-
-/*
-================
-CG_SplatSound LEILEI
-================
-*/
-void CG_SplatSound( localEntity_t *le, trace_t *trace ) {
- if ( le->leBounceSoundType == LEBS_BLOOD ) {
- // half the splats will make splat sounds
- if ( cg_leiGoreNoise.integer ) {
- if ( rand() & 1 ) {
- int r = rand()&3;
- sfxHandle_t s;
-
- if ( r == 0 ) {
- s = cgs.media.lspl1Sound;
- } else if ( r == 1 ) {
- s = cgs.media.lspl2Sound;
- } else {
- s = cgs.media.lspl3Sound;
- }
- trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );
- }
- }
- } else if ( le->leBounceSoundType == LEBS_BRASS ) {
- // no GERMAN EURO CENSOR ROBOTS mode yet.
- }
-
- // don't allow a fragment to make multiple bounce sounds,
- // or it gets too noisy as they settle
- le->leBounceSoundType = LEBS_NONE;
-}
-
-
-
-/*
-================
-CG_ReflectVelocity
-================
-*/
-void CG_ReflectVelocity( localEntity_t *le, trace_t *trace ) {
- vec3_t velocity;
- float dot;
- int hitTime;
-
- // reflect the velocity on the trace plane
- hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction;
- BG_EvaluateTrajectoryDelta( &le->pos, hitTime, velocity );
- dot = DotProduct( velocity, trace->plane.normal );
- VectorMA( velocity, -2*dot, trace->plane.normal, le->pos.trDelta );
-
- VectorScale( le->pos.trDelta, le->bounceFactor, le->pos.trDelta );
-
- VectorCopy( trace->endpos, le->pos.trBase );
- le->pos.trTime = cg.time;
-
-
- // check for stop, making sure that even on low FPS systems it doesn't bobble
- if ( trace->allsolid ||
- ( trace->plane.normal[2] > 0 &&
- ( le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2] ) ) ) {
- le->pos.trType = TR_STATIONARY;
- } else {
-
- }
-}
-
-/*
-================
-CG_AddFragment
-================
-*/
-void CG_AddFragment( localEntity_t *le ) {
- vec3_t newOrigin;
- trace_t trace;
-
- if ( le->pos.trType == TR_STATIONARY ) {
- // sink into the ground if near the removal time
- int t;
- float oldZ;
-
- t = le->endTime - cg.time;
- if ( t < SINK_TIME ) {
- // we must use an explicit lighting origin, otherwise the
- // lighting would be lost as soon as the origin went
- // into the ground
- VectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin );
- le->refEntity.renderfx |= RF_LIGHTING_ORIGIN;
- oldZ = le->refEntity.origin[2];
- le->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME );
- trap_R_AddRefEntityToScene( &le->refEntity );
- le->refEntity.origin[2] = oldZ;
- } else {
- trap_R_AddRefEntityToScene( &le->refEntity );
- }
-
- return;
- }
-
- // calculate new position
- BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );
-
- // trace a line from previous position to new position
- CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
- if ( trace.fraction == 1.0 ) {
- // still in free fall
- VectorCopy( newOrigin, le->refEntity.origin );
-
- if ( le->leFlags & LEF_TUMBLE ) {
- vec3_t angles;
-
- BG_EvaluateTrajectory( &le->angles, cg.time, angles );
- AnglesToAxis( angles, le->refEntity.axis );
- }
-
- trap_R_AddRefEntityToScene( &le->refEntity );
-
- // add a blood trail
- if ( le->leBounceSoundType == LEBS_BLOOD ) {
- CG_BloodTrail( le );
- }
-
- return;
- }
-
- // if it is in a nodrop zone, remove it
- // this keeps gibs from waiting at the bottom of pits of death
- // and floating levels
- if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- // leave a mark
- CG_FragmentBounceMark( le, &trace );
-
- // do a bouncy sound
- CG_FragmentBounceSound( le, &trace );
-
- // reflect the velocity on the trace plane
- CG_ReflectVelocity( le, &trace );
-
- trap_R_AddRefEntityToScene( &le->refEntity );
-}
-
-// LEILEI
-
-void CG_JustSplat( localEntity_t *le, trace_t *trace ) {
- vec3_t velocity;
- float dot;
- int hitTime;
-
- // reflect the velocity on the trace plane
- hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction;
- BG_EvaluateTrajectoryDelta( &le->pos, hitTime, velocity );
- dot = DotProduct( velocity, trace->plane.normal );
- VectorMA( velocity, -2*dot, trace->plane.normal, le->pos.trDelta );
-
- VectorScale( le->pos.trDelta, le->bounceFactor, le->pos.trDelta );
-
- VectorCopy( trace->endpos, le->pos.trBase );
- le->pos.trTime = cg.time;
-
-
- // check for stop, making sure that even on low FPS systems it doesn't bobble
- if ( trace->allsolid ||
- ( trace->plane.normal[2] > 0 &&
- ( le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2] ) ) ) {
- le->pos.trType = TR_STATIONARY;
- } else {
-
- }
-}
-
-void CG_AddGore( localEntity_t *le ) {
- vec3_t newOrigin;
- trace_t trace;
-
- if ( le->pos.trType == TR_STATIONARY ) {
- // sink into the ground if near the removal time
- int t;
- float oldZ;
-
- CG_FreeLocalEntity( le ); // kill it
-
- return;
- }
-
- // calculate new position
- BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );
-
- // trace a line from previous position to new position
- CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
- if ( trace.fraction == 1.0 ) {
- // still in free fall
- VectorCopy( newOrigin, le->refEntity.origin );
-
- if ( le->leFlags & LEF_TUMBLE ) {
- vec3_t angles;
-
- BG_EvaluateTrajectory( &le->angles, cg.time, angles );
- AnglesToAxis( angles, le->refEntity.axis );
- }
-
- trap_R_AddRefEntityToScene( &le->refEntity );
-
- CG_SmallBloodTrail( le );
-
- return;
- }
-
- // if it is in a nodrop zone, remove it
- // this keeps gibs from waiting at the bottom of pits of death
- // and floating levels
- if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- // leave a mark
- CG_GoreMark( le, &trace );
-
- // do a juicy sound
- CG_SplatSound( le, &trace );
-
- CG_JustSplat( le, &trace );
-
- trap_R_AddRefEntityToScene( &le->refEntity );
-}
-
-/*
-=====================================================================
-
-TRIVIAL LOCAL ENTITIES
-
-These only do simple scaling or modulation before passing to the renderer
-=====================================================================
-*/
-
-/*
-====================
-CG_AddFadeRGB
-====================
-*/
-void CG_AddFadeRGB( localEntity_t *le ) {
- refEntity_t *re;
- float c;
-
- re = &le->refEntity;
-
- c = ( le->endTime - cg.time ) * le->lifeRate;
- c *= 0xff;
-
- re->shaderRGBA[0] = le->color[0] * c;
- re->shaderRGBA[1] = le->color[1] * c;
- re->shaderRGBA[2] = le->color[2] * c;
- re->shaderRGBA[3] = le->color[3] * c;
-
- trap_R_AddRefEntityToScene( re );
-}
-
-/*
-==================
-CG_AddMoveScaleFade
-==================
-*/
-static void CG_AddMoveScaleFade( localEntity_t *le ) {
- refEntity_t *re;
- float c;
- vec3_t delta;
- float len;
-
- re = &le->refEntity;
-
- if ( le->fadeInTime > le->startTime && cg.time < le->fadeInTime ) {
- // fade / grow time
- c = 1.0 - (float) ( le->fadeInTime - cg.time ) / ( le->fadeInTime - le->startTime );
- }
- else {
- // fade / grow time
- c = ( le->endTime - cg.time ) * le->lifeRate;
- }
-
- re->shaderRGBA[3] = 0xff * c * le->color[3];
-
- if ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) {
- re->radius = le->radius * ( 1.0 - c ) + 8;
- }
-
- BG_EvaluateTrajectory( &le->pos, cg.time, re->origin );
-
- // if the view would be "inside" the sprite, kill the sprite
- // so it doesn't add too much overdraw
- VectorSubtract( re->origin, cg.refdef.vieworg, delta );
- len = VectorLength( delta );
- if ( len < le->radius ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- trap_R_AddRefEntityToScene( re );
-}
-
-
-/*
-===================
-CG_AddScaleFade
-
-For rocket smokes that hang in place, fade out, and are
-removed if the view passes through them.
-There are often many of these, so it needs to be simple.
-===================
-*/
-static void CG_AddScaleFade( localEntity_t *le ) {
- refEntity_t *re;
- float c;
- vec3_t delta;
- float len;
-
- re = &le->refEntity;
-
- // fade / grow time
- c = ( le->endTime - cg.time ) * le->lifeRate;
-
- re->shaderRGBA[3] = 0xff * c * le->color[3];
- re->radius = le->radius * ( 1.0 - c ) + 8;
-
- // if the view would be "inside" the sprite, kill the sprite
- // so it doesn't add too much overdraw
- VectorSubtract( re->origin, cg.refdef.vieworg, delta );
- len = VectorLength( delta );
- // LEILEI
- if (!cg_leiEnhancement.integer) {
- if ( len < le->radius ) {
- CG_FreeLocalEntity( le );
- return;
- }
- }
- trap_R_AddRefEntityToScene( re );
-}
-
-
-/*
-=================
-CG_AddFallScaleFade
-
-This is just an optimized CG_AddMoveScaleFade
-For blood mists that drift down, fade out, and are
-removed if the view passes through them.
-There are often 100+ of these, so it needs to be simple.
-=================
-*/
-static void CG_AddFallScaleFade( localEntity_t *le ) {
- refEntity_t *re;
- float c;
- vec3_t delta;
- float len;
-
- re = &le->refEntity;
-
- // fade time
- c = ( le->endTime - cg.time ) * le->lifeRate;
-
- re->shaderRGBA[3] = 0xff * c * le->color[3];
-
- re->origin[2] = le->pos.trBase[2] - ( 1.0 - c ) * le->pos.trDelta[2];
-
- re->radius = le->radius * ( 1.0 - c ) + 16;
-
- // if the view would be "inside" the sprite, kill the sprite
- // so it doesn't add too much overdraw
- VectorSubtract( re->origin, cg.refdef.vieworg, delta );
- len = VectorLength( delta );
-
- // LEILEI
-if (!cg_leiEnhancement.integer) {
- if ( len < le->radius ) {
- CG_FreeLocalEntity( le );
- return;
- }
- }
- trap_R_AddRefEntityToScene( re );
-}
-
-
-
-/*
-================
-CG_AddExplosion
-================
-*/
-static void CG_AddExplosion( localEntity_t *ex ) {
- refEntity_t *ent;
-
- ent = &ex->refEntity;
-
- // add the entity
- trap_R_AddRefEntityToScene(ent);
-
- // add the dlight
- if ( ex->light ) {
- float light;
-
- light = (float)( cg.time - ex->startTime ) / ( ex->endTime - ex->startTime );
- if ( light < 0.5 ) {
- light = 1.0;
- } else {
- light = 1.0 - ( light - 0.5 ) * 2;
- }
- light = ex->light * light;
- trap_R_AddLightToScene(ent->origin, light, ex->lightColor[0], ex->lightColor[1], ex->lightColor[2] );
- }
-}
-
-/*
-================
-CG_AddSpriteExplosion
-================
-*/
-static void CG_AddSpriteExplosion( localEntity_t *le ) {
- refEntity_t re;
- float c;
-
- re = le->refEntity;
-
- c = ( le->endTime - cg.time ) / ( float ) ( le->endTime - le->startTime );
- if ( c > 1 ) {
- c = 1.0; // can happen during connection problems
- }
-
- re.shaderRGBA[0] = 0xff;
- re.shaderRGBA[1] = 0xff;
- re.shaderRGBA[2] = 0xff;
- re.shaderRGBA[3] = 0xff * c * 0.33;
-
- re.reType = RT_SPRITE;
- re.radius = 42 * ( 1.0 - c ) + 30;
-
- trap_R_AddRefEntityToScene( &re );
-
- // add the dlight
- if ( le->light ) {
- float light;
-
- light = (float)( cg.time - le->startTime ) / ( le->endTime - le->startTime );
- if ( light < 0.5 ) {
- light = 1.0;
- } else {
- light = 1.0 - ( light - 0.5 ) * 2;
- }
- light = le->light * light;
- trap_R_AddLightToScene(re.origin, light, le->lightColor[0], le->lightColor[1], le->lightColor[2] );
- }
-}
-
-
-//#ifdef MISSIONPACK
-/*
-====================
-CG_AddKamikaze
-====================
-*/
-void CG_AddKamikaze( localEntity_t *le ) {
- refEntity_t *re;
- refEntity_t shockwave;
- float c;
- vec3_t test, axis[3];
- int t;
-
- re = &le->refEntity;
-
- t = cg.time - le->startTime;
- VectorClear( test );
- AnglesToAxis( test, axis );
-
- if (t > KAMI_SHOCKWAVE_STARTTIME && t < KAMI_SHOCKWAVE_ENDTIME) {
-
- if (!(le->leFlags & LEF_SOUND1)) {
-// trap_S_StartSound (re->origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.kamikazeExplodeSound );
- trap_S_StartLocalSound(cgs.media.kamikazeExplodeSound, CHAN_AUTO);
- le->leFlags |= LEF_SOUND1;
- }
- // 1st kamikaze shockwave
- memset(&shockwave, 0, sizeof(shockwave));
- shockwave.hModel = cgs.media.kamikazeShockWave;
- shockwave.reType = RT_MODEL;
- shockwave.shaderTime = re->shaderTime;
- VectorCopy(re->origin, shockwave.origin);
-
- c = (float)(t - KAMI_SHOCKWAVE_STARTTIME) / (float)(KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVE_STARTTIME);
- VectorScale( axis[0], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[0] );
- VectorScale( axis[1], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[1] );
- VectorScale( axis[2], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[2] );
- shockwave.nonNormalizedAxes = qtrue;
-
- if (t > KAMI_SHOCKWAVEFADE_STARTTIME) {
- c = (float)(t - KAMI_SHOCKWAVEFADE_STARTTIME) / (float)(KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVEFADE_STARTTIME);
- }
- else {
- c = 0;
- }
- c *= 0xff;
- shockwave.shaderRGBA[0] = 0xff - c;
- shockwave.shaderRGBA[1] = 0xff - c;
- shockwave.shaderRGBA[2] = 0xff - c;
- shockwave.shaderRGBA[3] = 0xff - c;
-
- trap_R_AddRefEntityToScene( &shockwave );
- }
-
- if (t > KAMI_EXPLODE_STARTTIME && t < KAMI_IMPLODE_ENDTIME) {
- // explosion and implosion
- c = ( le->endTime - cg.time ) * le->lifeRate;
- c *= 0xff;
- re->shaderRGBA[0] = le->color[0] * c;
- re->shaderRGBA[1] = le->color[1] * c;
- re->shaderRGBA[2] = le->color[2] * c;
- re->shaderRGBA[3] = le->color[3] * c;
-
- if( t < KAMI_IMPLODE_STARTTIME ) {
- c = (float)(t - KAMI_EXPLODE_STARTTIME) / (float)(KAMI_IMPLODE_STARTTIME - KAMI_EXPLODE_STARTTIME);
- }
- else {
- if (!(le->leFlags & LEF_SOUND2)) {
-// trap_S_StartSound (re->origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.kamikazeImplodeSound );
- trap_S_StartLocalSound(cgs.media.kamikazeImplodeSound, CHAN_AUTO);
- le->leFlags |= LEF_SOUND2;
- }
- c = (float)(KAMI_IMPLODE_ENDTIME - t) / (float) (KAMI_IMPLODE_ENDTIME - KAMI_IMPLODE_STARTTIME);
- }
- VectorScale( axis[0], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[0] );
- VectorScale( axis[1], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[1] );
- VectorScale( axis[2], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[2] );
- re->nonNormalizedAxes = qtrue;
-
- trap_R_AddRefEntityToScene( re );
- // add the dlight
- trap_R_AddLightToScene( re->origin, c * 1000.0, 1.0, 1.0, c );
- }
-
- if (t > KAMI_SHOCKWAVE2_STARTTIME && t < KAMI_SHOCKWAVE2_ENDTIME) {
- // 2nd kamikaze shockwave
- if (le->angles.trBase[0] == 0 &&
- le->angles.trBase[1] == 0 &&
- le->angles.trBase[2] == 0) {
- le->angles.trBase[0] = random() * 360;
- le->angles.trBase[1] = random() * 360;
- le->angles.trBase[2] = random() * 360;
- }
- else {
- c = 0;
- }
- memset(&shockwave, 0, sizeof(shockwave));
- shockwave.hModel = cgs.media.kamikazeShockWave;
- shockwave.reType = RT_MODEL;
- shockwave.shaderTime = re->shaderTime;
- VectorCopy(re->origin, shockwave.origin);
-
- test[0] = le->angles.trBase[0];
- test[1] = le->angles.trBase[1];
- test[2] = le->angles.trBase[2];
- AnglesToAxis( test, axis );
-
- c = (float)(t - KAMI_SHOCKWAVE2_STARTTIME) / (float)(KAMI_SHOCKWAVE2_ENDTIME - KAMI_SHOCKWAVE2_STARTTIME);
- VectorScale( axis[0], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[0] );
- VectorScale( axis[1], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[1] );
- VectorScale( axis[2], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[2] );
- shockwave.nonNormalizedAxes = qtrue;
-
- if (t > KAMI_SHOCKWAVE2FADE_STARTTIME) {
- c = (float)(t - KAMI_SHOCKWAVE2FADE_STARTTIME) / (float)(KAMI_SHOCKWAVE2_ENDTIME - KAMI_SHOCKWAVE2FADE_STARTTIME);
- }
- else {
- c = 0;
- }
- c *= 0xff;
- shockwave.shaderRGBA[0] = 0xff - c;
- shockwave.shaderRGBA[1] = 0xff - c;
- shockwave.shaderRGBA[2] = 0xff - c;
- shockwave.shaderRGBA[3] = 0xff - c;
-
- trap_R_AddRefEntityToScene( &shockwave );
- }
-}
-
-/*
-===================
-CG_AddInvulnerabilityImpact
-===================
-*/
-void CG_AddInvulnerabilityImpact( localEntity_t *le ) {
- trap_R_AddRefEntityToScene( &le->refEntity );
-}
-
-/*
-===================
-CG_AddInvulnerabilityJuiced
-===================
-*/
-void CG_AddInvulnerabilityJuiced( localEntity_t *le ) {
- int t;
-
- t = cg.time - le->startTime;
- if ( t > 3000 ) {
- le->refEntity.axis[0][0] = (float) 1.0 + 0.3 * (t - 3000) / 2000;
- le->refEntity.axis[1][1] = (float) 1.0 + 0.3 * (t - 3000) / 2000;
- le->refEntity.axis[2][2] = (float) 0.7 + 0.3 * (2000 - (t - 3000)) / 2000;
- }
- if ( t > 5000 ) {
- le->endTime = 0;
- CG_GibPlayer( le->refEntity.origin );
- }
- else {
- trap_R_AddRefEntityToScene( &le->refEntity );
- }
-}
-
-/*
-===================
-CG_AddRefEntity
-===================
-*/
-void CG_AddRefEntity( localEntity_t *le ) {
- if (le->endTime < cg.time) {
- CG_FreeLocalEntity( le );
- return;
- }
- trap_R_AddRefEntityToScene( &le->refEntity );
-}
-
-//#endif
-/*
-===================
-CG_AddScorePlum
-===================
-*/
-#define NUMBER_SIZE 8
-
-void CG_AddScorePlum( localEntity_t *le ) {
- refEntity_t *re;
- vec3_t origin, delta, dir, vec, up = {0, 0, 1};
- float c, len;
- int i, score, digits[10], numdigits, negative;
-
- re = &le->refEntity;
-
- c = ( le->endTime - cg.time ) * le->lifeRate;
-
- score = le->radius;
- if (score < 0) {
- re->shaderRGBA[0] = 0xff;
- re->shaderRGBA[1] = 0x11;
- re->shaderRGBA[2] = 0x11;
- }
- else {
- re->shaderRGBA[0] = 0xff;
- re->shaderRGBA[1] = 0xff;
- re->shaderRGBA[2] = 0xff;
- if (score >= 50) {
- re->shaderRGBA[1] = 0;
- } else if (score >= 20) {
- re->shaderRGBA[0] = re->shaderRGBA[1] = 0;
- } else if (score >= 10) {
- re->shaderRGBA[2] = 0;
- } else if (score >= 2) {
- re->shaderRGBA[0] = re->shaderRGBA[2] = 0;
- }
-
- }
- if (c < 0.25)
- re->shaderRGBA[3] = 0xff * 4 * c;
- else
- re->shaderRGBA[3] = 0xff;
-
- re->radius = NUMBER_SIZE / 2;
-
- VectorCopy(le->pos.trBase, origin);
- origin[2] += 110 - c * 100;
-
- VectorSubtract(cg.refdef.vieworg, origin, dir);
- CrossProduct(dir, up, vec);
- VectorNormalize(vec);
-
- VectorMA(origin, -10 + 20 * sin(c * 2 * M_PI), vec, origin);
-
- // if the view would be "inside" the sprite, kill the sprite
- // so it doesn't add too much overdraw
- VectorSubtract( origin, cg.refdef.vieworg, delta );
- len = VectorLength( delta );
- if ( len < 20 ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- negative = qfalse;
- if (score < 0) {
- negative = qtrue;
- score = -score;
- }
-
- for (numdigits = 0; !(numdigits && !score); numdigits++) {
- digits[numdigits] = score % 10;
- score = score / 10;
- }
-
- if (negative) {
- digits[numdigits] = 10;
- numdigits++;
- }
-
- for (i = 0; i < numdigits; i++) {
- VectorMA(origin, (float) (((float) numdigits / 2) - i) * NUMBER_SIZE, vec, re->origin);
- re->customShader = cgs.media.numberShaders[digits[numdigits-1-i]];
- trap_R_AddRefEntityToScene( re );
- }
-}
-
-
-
-
-//==============================================================================
-
-/*
-===================
-CG_AddLocalEntities
-
-===================
-*/
-void CG_AddLocalEntities( void ) {
- localEntity_t *le, *next;
-
- // walk the list backwards, so any new local entities generated
- // (trails, marks, etc) will be present this frame
- le = cg_activeLocalEntities.prev;
- for ( ; le != &cg_activeLocalEntities ; le = next ) {
- // grab next now, so if the local entity is freed we
- // still have it
- next = le->prev;
-
- if ( cg.time >= le->endTime ) {
- CG_FreeLocalEntity( le );
- continue;
- }
- switch ( le->leType ) {
- default:
- CG_Error( "Bad leType: %i", le->leType );
- break;
-
- case LE_MARK:
- break;
-
- case LE_SPRITE_EXPLOSION:
- CG_AddSpriteExplosion( le );
- break;
-
- case LE_EXPLOSION:
- CG_AddExplosion( le );
- break;
-
- case LE_FRAGMENT: // gibs and brass
- CG_AddFragment( le );
- break;
-
- case LE_MOVE_SCALE_FADE: // water bubbles
- CG_AddMoveScaleFade( le );
- break;
-
- case LE_FADE_RGB: // teleporters, railtrails
- CG_AddFadeRGB( le );
- break;
-
- case LE_FALL_SCALE_FADE: // gib blood trails
- CG_AddFallScaleFade( le );
- break;
-
- case LE_SCALE_FADE: // rocket trails
- CG_AddScaleFade( le );
- break;
-
- case LE_SCOREPLUM:
- CG_AddScorePlum( le );
- break;
-
-//#ifdef MISSIONPACK
- case LE_KAMIKAZE:
- CG_AddKamikaze( le );
- break;
- case LE_INVULIMPACT:
- CG_AddInvulnerabilityImpact( le );
- break;
- case LE_INVULJUICED:
- CG_AddInvulnerabilityJuiced( le );
- break;
- case LE_SHOWREFENTITY:
- CG_AddRefEntity( le );
- break;
-//#endif
-
- case LE_GORE: // blood
- CG_AddGore( le );
- break;
- }
- }
-}
-
-
-
-
diff --git a/game/code/cgame/cg_main.c b/game/code/cgame/cg_main.c
deleted file mode 100644
index 5525e47..0000000
--- a/game/code/cgame/cg_main.c
+++ /dev/null
@@ -1,2323 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_main.c -- initialization and primary entry point for cgame
-#include "cg_local.h"
-
-#ifdef MISSIONPACK
-#include "../ui/ui_shared.h"
-// display context for new ui stuff
-displayContextDef_t cgDC;
-#endif
-
-int forceModelModificationCount = -1;
-
-void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum );
-void CG_Shutdown( void );
-
-
-/*
-================
-vmMain
-
-This is the only way control passes into the module.
-This must be the very first function compiled into the .q3vm file
-================
-*/
-intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
-
- switch ( command ) {
- case CG_INIT:
- CG_Init( arg0, arg1, arg2 );
- return 0;
- case CG_SHUTDOWN:
- CG_Shutdown();
- return 0;
- case CG_CONSOLE_COMMAND:
- return CG_ConsoleCommand();
- case CG_DRAW_ACTIVE_FRAME:
- CG_DrawActiveFrame( arg0, arg1, arg2 );
- CG_FairCvars();
- return 0;
- case CG_CROSSHAIR_PLAYER:
- return CG_CrosshairPlayer();
- case CG_LAST_ATTACKER:
- return CG_LastAttacker();
- case CG_KEY_EVENT:
- CG_KeyEvent(arg0, arg1);
- return 0;
- case CG_MOUSE_EVENT:
-#ifdef MISSIONPACK
- cgDC.cursorx = cgs.cursorX;
- cgDC.cursory = cgs.cursorY;
-#endif
- CG_MouseEvent(arg0, arg1);
- return 0;
- case CG_EVENT_HANDLING:
- CG_EventHandling(arg0);
- return 0;
- default:
- CG_Error( "vmMain: unknown command %i", command );
- break;
- }
- return -1;
-}
-
-
-cg_t cg;
-cgs_t cgs;
-centity_t cg_entities[MAX_GENTITIES];
-weaponInfo_t cg_weapons[MAX_WEAPONS];
-itemInfo_t cg_items[MAX_ITEMS];
-
-
-vmCvar_t cg_railTrailTime;
-vmCvar_t cg_centertime;
-vmCvar_t cg_runpitch;
-vmCvar_t cg_runroll;
-vmCvar_t cg_bobup;
-vmCvar_t cg_bobpitch;
-vmCvar_t cg_bobroll;
-vmCvar_t cg_swingSpeed;
-vmCvar_t cg_shadows;
-vmCvar_t cg_gibs;
-vmCvar_t cg_drawTimer;
-vmCvar_t cg_drawFPS;
-vmCvar_t cg_drawSnapshot;
-vmCvar_t cg_draw3dIcons;
-vmCvar_t cg_drawIcons;
-vmCvar_t cg_drawAmmoWarning;
-vmCvar_t cg_drawCrosshair;
-vmCvar_t cg_drawCrosshairNames;
-vmCvar_t cg_drawRewards;
-vmCvar_t cg_crosshairSize;
-vmCvar_t cg_crosshairX;
-vmCvar_t cg_crosshairY;
-vmCvar_t cg_crosshairHealth;
-vmCvar_t cg_draw2D;
-vmCvar_t cg_drawStatus;
-vmCvar_t cg_animSpeed;
-vmCvar_t cg_debugAnim;
-vmCvar_t cg_debugPosition;
-vmCvar_t cg_debugEvents;
-vmCvar_t cg_errorDecay;
-vmCvar_t cg_nopredict;
-vmCvar_t cg_noPlayerAnims;
-vmCvar_t cg_showmiss;
-vmCvar_t cg_footsteps;
-vmCvar_t cg_addMarks;
-vmCvar_t cg_brassTime;
-vmCvar_t cg_viewsize;
-vmCvar_t cg_drawGun;
-vmCvar_t cg_gun_frame;
-vmCvar_t cg_gun_x;
-vmCvar_t cg_gun_y;
-vmCvar_t cg_gun_z;
-vmCvar_t cg_tracerChance;
-vmCvar_t cg_tracerWidth;
-vmCvar_t cg_tracerLength;
-vmCvar_t cg_autoswitch;
-vmCvar_t cg_ignore;
-vmCvar_t cg_simpleItems;
-vmCvar_t cg_fov;
-vmCvar_t cg_zoomFov;
-vmCvar_t cg_thirdPerson;
-vmCvar_t cg_thirdPersonRange;
-vmCvar_t cg_thirdPersonAngle;
-vmCvar_t cg_lagometer;
-vmCvar_t cg_drawAttacker;
-vmCvar_t cg_drawSpeed;
-vmCvar_t cg_synchronousClients;
-vmCvar_t cg_teamChatTime;
-vmCvar_t cg_teamChatHeight;
-vmCvar_t cg_stats;
-vmCvar_t cg_buildScript;
-vmCvar_t cg_forceModel;
-vmCvar_t cg_paused;
-vmCvar_t cg_blood;
-vmCvar_t cg_predictItems;
-vmCvar_t cg_deferPlayers;
-vmCvar_t cg_drawTeamOverlay;
-vmCvar_t cg_teamOverlayUserinfo;
-vmCvar_t cg_drawFriend;
-vmCvar_t cg_teamChatsOnly;
-vmCvar_t cg_noVoiceChats;
-vmCvar_t cg_noVoiceText;
-vmCvar_t cg_hudFiles;
-vmCvar_t cg_scorePlum;
-//unlagged - smooth clients #2
-// this is done server-side now
-//vmCvar_t cg_smoothClients;
-//unlagged - smooth clients #2
-vmCvar_t pmove_fixed;
-//vmCvar_t cg_pmove_fixed;
-vmCvar_t pmove_msec;
-vmCvar_t pmove_float;
-vmCvar_t cg_pmove_msec;
-vmCvar_t cg_cameraMode;
-vmCvar_t cg_cameraOrbit;
-vmCvar_t cg_cameraOrbitDelay;
-vmCvar_t cg_timescaleFadeEnd;
-vmCvar_t cg_timescaleFadeSpeed;
-vmCvar_t cg_timescale;
-vmCvar_t cg_smallFont;
-vmCvar_t cg_bigFont;
-vmCvar_t cg_noTaunt;
-vmCvar_t cg_noProjectileTrail;
-vmCvar_t cg_oldRail;
-vmCvar_t cg_oldRocket;
-vmCvar_t cg_leiEnhancement; // ANOTHER LEILEI LINE!!!
-vmCvar_t cg_leiBrassNoise; // ANOTHER LEILEI LINE!!!
-vmCvar_t cg_leiGoreNoise; // ANOTHER LEILEI LINE!!!
-vmCvar_t cg_leiSuperGoreyAwesome; // ANOTHER LEILEI LINE!!!
-vmCvar_t cg_oldPlasma;
-vmCvar_t cg_trueLightning;
-vmCvar_t cg_music;
-
-
-#ifdef MISSIONPACK
-vmCvar_t cg_redTeamName;
-vmCvar_t cg_blueTeamName;
-vmCvar_t cg_currentSelectedPlayer;
-vmCvar_t cg_currentSelectedPlayerName;
-vmCvar_t cg_singlePlayer;
-vmCvar_t cg_singlePlayerActive;
-vmCvar_t cg_recordSPDemo;
-vmCvar_t cg_recordSPDemoName;
-#endif
-vmCvar_t cg_obeliskRespawnDelay;
-vmCvar_t cg_enableDust;
-vmCvar_t cg_enableBreath;
-
-//unlagged - client options
-vmCvar_t cg_delag;
-//vmCvar_t cg_debugDelag;
-//vmCvar_t cg_drawBBox;
-vmCvar_t cg_cmdTimeNudge;
-vmCvar_t sv_fps;
-vmCvar_t cg_projectileNudge;
-vmCvar_t cg_optimizePrediction;
-vmCvar_t cl_timeNudge;
-//vmCvar_t cg_latentSnaps;
-//vmCvar_t cg_latentCmds;
-//vmCvar_t cg_plOut;
-//unlagged - client options
-
-//elimination addition
-vmCvar_t cg_alwaysWeaponBar;
-vmCvar_t cg_hitsound;
-vmCvar_t cg_voip_teamonly;
-vmCvar_t cg_voteflags;
-vmCvar_t cg_cyclegrapple;
-vmCvar_t cg_vote_custom_commands;
-
-vmCvar_t cg_autovertex;
-
-vmCvar_t cg_fragmsgsize;
-
-vmCvar_t cg_crosshairPulse;
-vmCvar_t cg_differentCrosshairs;
-vmCvar_t cg_ch1;
-vmCvar_t cg_ch1size;
-vmCvar_t cg_ch2;
-vmCvar_t cg_ch2size;
-vmCvar_t cg_ch3;
-vmCvar_t cg_ch3size;
-vmCvar_t cg_ch4;
-vmCvar_t cg_ch4size;
-vmCvar_t cg_ch5;
-vmCvar_t cg_ch5size;
-vmCvar_t cg_ch6;
-vmCvar_t cg_ch6size;
-vmCvar_t cg_ch7;
-vmCvar_t cg_ch7size;
-vmCvar_t cg_ch8;
-vmCvar_t cg_ch8size;
-vmCvar_t cg_ch9;
-vmCvar_t cg_ch9size;
-vmCvar_t cg_ch10;
-vmCvar_t cg_ch10size;
-vmCvar_t cg_ch11;
-vmCvar_t cg_ch11size;
-vmCvar_t cg_ch12;
-vmCvar_t cg_ch12size;
-vmCvar_t cg_ch13;
-vmCvar_t cg_ch13size;
-
-vmCvar_t cg_crosshairColorRed;
-vmCvar_t cg_crosshairColorGreen;
-vmCvar_t cg_crosshairColorBlue;
-
-vmCvar_t cg_weaponBarStyle;
-
-typedef struct {
- vmCvar_t *vmCvar;
- char *cvarName;
- char *defaultString;
- int cvarFlags;
-} cvarTable_t;
-
-static cvarTable_t cvarTable[] = { // bk001129
- { &cg_ignore, "cg_ignore", "0", 0 }, // used for debugging
- { &cg_autoswitch, "cg_autoswitch", "1", CVAR_ARCHIVE },
- { &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE },
- { &cg_zoomFov, "cg_zoomfov", "22.5", CVAR_ARCHIVE },
- { &cg_fov, "cg_fov", "90", CVAR_ARCHIVE },
- { &cg_viewsize, "cg_viewsize", "100", CVAR_ARCHIVE },
- { &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE },
- { &cg_gibs, "cg_gibs", "1", CVAR_ARCHIVE },
- { &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE },
- { &cg_drawStatus, "cg_drawStatus", "1", CVAR_ARCHIVE },
- { &cg_drawTimer, "cg_drawTimer", "0", CVAR_ARCHIVE },
- { &cg_drawFPS, "cg_drawFPS", "0", CVAR_ARCHIVE },
- { &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE },
- { &cg_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE },
- { &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE },
- { &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE },
- { &cg_drawAttacker, "cg_drawAttacker", "1", CVAR_ARCHIVE },
- { &cg_drawSpeed, "cg_drawSpeed", "0", CVAR_ARCHIVE },
- { &cg_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
- { &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
- { &cg_drawRewards, "cg_drawRewards", "1", CVAR_ARCHIVE },
- { &cg_crosshairSize, "cg_crosshairSize", "24", CVAR_ARCHIVE },
- { &cg_crosshairHealth, "cg_crosshairHealth", "1", CVAR_ARCHIVE },
- { &cg_crosshairX, "cg_crosshairX", "0", CVAR_ARCHIVE },
- { &cg_crosshairY, "cg_crosshairY", "0", CVAR_ARCHIVE },
- { &cg_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
- { &cg_simpleItems, "cg_simpleItems", "0", CVAR_ARCHIVE },
- { &cg_addMarks, "cg_marks", "1", CVAR_ARCHIVE },
- { &cg_lagometer, "cg_lagometer", "1", CVAR_ARCHIVE },
- { &cg_railTrailTime, "cg_railTrailTime", "600", CVAR_ARCHIVE },
- { &cg_gun_x, "cg_gunX", "0", CVAR_CHEAT },
- { &cg_gun_y, "cg_gunY", "0", CVAR_CHEAT },
- { &cg_gun_z, "cg_gunZ", "0", CVAR_CHEAT },
- { &cg_centertime, "cg_centertime", "3", CVAR_CHEAT },
- { &cg_runpitch, "cg_runpitch", "0.002", CVAR_ARCHIVE},
- { &cg_runroll, "cg_runroll", "0.005", CVAR_ARCHIVE },
- { &cg_bobup , "cg_bobup", "0.005", CVAR_CHEAT },
- { &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE },
- { &cg_bobroll, "cg_bobroll", "0.002", CVAR_ARCHIVE },
- { &cg_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT },
- { &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT },
- { &cg_debugAnim, "cg_debuganim", "0", CVAR_CHEAT },
- { &cg_debugPosition, "cg_debugposition", "0", CVAR_CHEAT },
- { &cg_debugEvents, "cg_debugevents", "0", CVAR_CHEAT },
- { &cg_errorDecay, "cg_errordecay", "100", 0 },
- { &cg_nopredict, "cg_nopredict", "0", 0 },
- { &cg_noPlayerAnims, "cg_noplayeranims", "0", CVAR_CHEAT },
- { &cg_showmiss, "cg_showmiss", "0", 0 },
- { &cg_footsteps, "cg_footsteps", "1", CVAR_CHEAT },
- { &cg_tracerChance, "cg_tracerchance", "0.4", CVAR_CHEAT },
- { &cg_tracerWidth, "cg_tracerwidth", "1", CVAR_CHEAT },
- { &cg_tracerLength, "cg_tracerlength", "100", CVAR_CHEAT },
- { &cg_thirdPersonRange, "cg_thirdPersonRange", "40", CVAR_CHEAT },
- { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", CVAR_CHEAT },
- { &cg_thirdPerson, "cg_thirdPerson", "0", 0 },
- { &cg_teamChatTime, "cg_teamChatTime", "3000", CVAR_ARCHIVE },
- { &cg_teamChatHeight, "cg_teamChatHeight", "0", CVAR_ARCHIVE },
- { &cg_forceModel, "cg_forceModel", "0", CVAR_ARCHIVE },
- { &cg_predictItems, "cg_predictItems", "1", CVAR_ARCHIVE },
-#ifdef MISSIONPACK
- { &cg_deferPlayers, "cg_deferPlayers", "0", CVAR_ARCHIVE },
-#else
- { &cg_deferPlayers, "cg_deferPlayers", "1", CVAR_ARCHIVE },
-#endif
- { &cg_drawTeamOverlay, "cg_drawTeamOverlay", "0", CVAR_ARCHIVE },
- { &cg_teamOverlayUserinfo, "teamoverlay", "0", CVAR_ROM | CVAR_USERINFO },
- { &cg_stats, "cg_stats", "0", 0 },
- { &cg_drawFriend, "cg_drawFriend", "1", CVAR_ARCHIVE },
- { &cg_teamChatsOnly, "cg_teamChatsOnly", "0", CVAR_ARCHIVE },
- { &cg_noVoiceChats, "cg_noVoiceChats", "0", CVAR_ARCHIVE },
- { &cg_noVoiceText, "cg_noVoiceText", "0", CVAR_ARCHIVE },
- // the following variables are created in other parts of the system,
- // but we also reference them here
- { &cg_buildScript, "com_buildScript", "0", 0 }, // force loading of all possible data amd error on failures
- { &cg_paused, "cl_paused", "0", CVAR_ROM },
- { &cg_blood, "com_blood", "1", CVAR_ARCHIVE },
- { &cg_alwaysWeaponBar, "cg_alwaysWeaponBar", "0", CVAR_ARCHIVE}, //Elimination
- { &cg_hitsound, "cg_hitsound", "0", CVAR_ARCHIVE},
- { &cg_voip_teamonly, "cg_voipTeamOnly", "1", CVAR_ARCHIVE},
- { &cg_voteflags, "cg_voteflags", "*", CVAR_ROM},
- { &cg_cyclegrapple, "cg_cyclegrapple", "1", CVAR_ARCHIVE},
- { &cg_vote_custom_commands, "cg_vote_custom_commands", "", CVAR_ROM },
- { &cg_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO }, // communicated by systeminfo
-
- { &cg_autovertex, "cg_autovertex", "0", CVAR_ARCHIVE },
-#ifdef MISSIONPACK
- { &cg_redTeamName, "g_redteam", DEFAULT_REDTEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO },
- { &cg_blueTeamName, "g_blueteam", DEFAULT_BLUETEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO },
- { &cg_currentSelectedPlayer, "cg_currentSelectedPlayer", "0", CVAR_ARCHIVE},
- { &cg_currentSelectedPlayerName, "cg_currentSelectedPlayerName", "", CVAR_ARCHIVE},
- { &cg_singlePlayer, "ui_singlePlayerActive", "0", CVAR_USERINFO},
- { &cg_singlePlayerActive, "ui_singlePlayerActive", "0", CVAR_USERINFO},
- { &cg_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE},
- { &cg_recordSPDemoName, "ui_recordSPDemoName", "", CVAR_ARCHIVE},
- { &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
-#endif
- { &cg_enableDust, "g_enableDust", "0", CVAR_SERVERINFO},
- { &cg_enableBreath, "g_enableBreath", "0", CVAR_SERVERINFO},
- { &cg_obeliskRespawnDelay, "g_obeliskRespawnDelay", "10", CVAR_SERVERINFO},
-
- { &cg_cameraOrbit, "cg_cameraOrbit", "0", CVAR_CHEAT},
- { &cg_cameraOrbitDelay, "cg_cameraOrbitDelay", "50", CVAR_ARCHIVE},
- { &cg_timescaleFadeEnd, "cg_timescaleFadeEnd", "1", 0},
- { &cg_timescaleFadeSpeed, "cg_timescaleFadeSpeed", "0", 0},
- { &cg_timescale, "timescale", "1", 0},
- { &cg_scorePlum, "cg_scorePlums", "1", CVAR_USERINFO | CVAR_ARCHIVE},
-//unlagged - smooth clients #2
-// this is done server-side now
-// { &cg_smoothClients, "cg_smoothClients", "0", CVAR_USERINFO | CVAR_ARCHIVE},
-//unlagged - smooth clients #2
- { &cg_cameraMode, "com_cameraMode", "0", CVAR_CHEAT},
-
- { &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO},
- { &pmove_msec, "pmove_msec", "11", CVAR_SYSTEMINFO},
- { &pmove_float, "pmove_float", "1", CVAR_SYSTEMINFO},
- { &cg_noTaunt, "cg_noTaunt", "0", CVAR_ARCHIVE},
- { &cg_noProjectileTrail, "cg_noProjectileTrail", "0", CVAR_ARCHIVE},
- { &cg_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE},
- { &cg_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE},
- { &cg_oldRail, "cg_oldRail", "0", CVAR_ARCHIVE},
- { &cg_oldRocket, "cg_oldRocket", "1", CVAR_ARCHIVE},
- { &cg_leiEnhancement, "cg_leiEnhancement", "0", CVAR_ARCHIVE}, // LEILEI default off (in case of whiner)
- { &cg_leiGoreNoise, "cg_leiGoreNoise", "0", CVAR_ARCHIVE}, // LEILEI
- { &cg_leiBrassNoise, "cg_leiBrassNoise", "0", CVAR_ARCHIVE}, // LEILEI
- { &cg_leiSuperGoreyAwesome, "cg_leiSuperGoreyAwesome", "0", CVAR_ARCHIVE}, // LEILEI
- { &cg_oldPlasma, "cg_oldPlasma", "1", CVAR_ARCHIVE},
-//unlagged - client options
- { &cg_delag, "cg_delag", "0", CVAR_ARCHIVE | CVAR_USERINFO },
-// { &cg_debugDelag, "cg_debugDelag", "0", CVAR_USERINFO | CVAR_CHEAT },
-// { &cg_drawBBox, "cg_drawBBox", "0", CVAR_CHEAT },
- { &cg_cmdTimeNudge, "cg_cmdTimeNudge", "0", CVAR_ARCHIVE | CVAR_USERINFO },
- // this will be automagically copied from the server
- { &sv_fps, "sv_fps", "20", CVAR_SYSTEMINFO },
- { &cg_projectileNudge, "cg_projectileNudge", "0", CVAR_ARCHIVE },
- { &cg_optimizePrediction, "cg_optimizePrediction", "1", CVAR_ARCHIVE },
- { &cl_timeNudge, "cl_timeNudge", "0", CVAR_ARCHIVE },
-// { &cg_latentSnaps, "cg_latentSnaps", "0", CVAR_USERINFO | CVAR_CHEAT },
-// { &cg_latentCmds, "cg_latentCmds", "0", CVAR_USERINFO | CVAR_CHEAT },
-// { &cg_plOut, "cg_plOut", "0", CVAR_USERINFO | CVAR_CHEAT },
-//unlagged - client options
- { &cg_trueLightning, "cg_trueLightning", "0.0", CVAR_ARCHIVE},
- { &cg_music, "cg_music", "", CVAR_ARCHIVE},
-// { &cg_pmove_fixed, "cg_pmove_fixed", "0", CVAR_USERINFO | CVAR_ARCHIVE }
-
- { &cg_fragmsgsize, "cg_fragmsgsize", "1.0", CVAR_ARCHIVE},
- { &cg_crosshairPulse, "cg_crosshairPulse", "1", CVAR_ARCHIVE},
-
- { &cg_differentCrosshairs, "cg_differentCrosshairs", "0", CVAR_ARCHIVE},
- { &cg_ch1, "cg_ch1", "1", CVAR_ARCHIVE},
- { &cg_ch1size, "cg_ch1size", "24", CVAR_ARCHIVE},
- { &cg_ch2, "cg_ch2", "1", CVAR_ARCHIVE},
- { &cg_ch2size, "cg_ch2size", "24", CVAR_ARCHIVE},
- { &cg_ch3, "cg_ch3", "1", CVAR_ARCHIVE},
- { &cg_ch3size, "cg_ch3size", "24", CVAR_ARCHIVE},
- { &cg_ch4, "cg_ch4", "1", CVAR_ARCHIVE},
- { &cg_ch4size, "cg_ch4size", "24", CVAR_ARCHIVE},
- { &cg_ch5, "cg_ch5", "1", CVAR_ARCHIVE},
- { &cg_ch5size, "cg_ch5size", "24", CVAR_ARCHIVE},
- { &cg_ch6, "cg_ch6", "1", CVAR_ARCHIVE},
- { &cg_ch6size, "cg_ch6size", "24", CVAR_ARCHIVE},
- { &cg_ch7, "cg_ch7", "1", CVAR_ARCHIVE},
- { &cg_ch7size, "cg_ch7size", "24", CVAR_ARCHIVE},
- { &cg_ch8, "cg_ch8", "1", CVAR_ARCHIVE},
- { &cg_ch8size, "cg_ch8size", "24", CVAR_ARCHIVE},
- { &cg_ch9, "cg_ch9", "1", CVAR_ARCHIVE},
- { &cg_ch9size, "cg_ch9size", "24", CVAR_ARCHIVE},
- { &cg_ch10, "cg_ch10", "1", CVAR_ARCHIVE},
- { &cg_ch10size, "cg_ch10size", "24", CVAR_ARCHIVE},
- { &cg_ch11, "cg_ch11", "1", CVAR_ARCHIVE},
- { &cg_ch11size, "cg_ch11size", "24", CVAR_ARCHIVE},
- { &cg_ch12, "cg_ch12", "1", CVAR_ARCHIVE},
- { &cg_ch12size, "cg_ch12size", "24", CVAR_ARCHIVE},
- { &cg_ch13, "cg_ch13", "1", CVAR_ARCHIVE},
- { &cg_ch13size, "cg_ch13size", "24", CVAR_ARCHIVE},
-
- { &cg_crosshairColorRed, "cg_crosshairColorRed", "1.0", CVAR_ARCHIVE},
- { &cg_crosshairColorGreen, "cg_crosshairColorGreen", "1.0", CVAR_ARCHIVE},
- { &cg_crosshairColorBlue, "cg_crosshairColorBlue", "1.0", CVAR_ARCHIVE},
-
- { &cg_weaponBarStyle, "cg_weaponBarStyle", "0", CVAR_ARCHIVE},
-};
-
-static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] );
-
-/*
-=================
-CG_RegisterCvars
-=================
-*/
-void CG_RegisterCvars( void ) {
- int i;
- cvarTable_t *cv;
- char var[MAX_TOKEN_CHARS];
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Register( cv->vmCvar, cv->cvarName,
- cv->defaultString, cv->cvarFlags );
- }
-
- // see if we are also running the server on this machine
- trap_Cvar_VariableStringBuffer( "sv_running", var, sizeof( var ) );
- cgs.localServer = atoi( var );
-
- forceModelModificationCount = cg_forceModel.modificationCount;
-
- trap_Cvar_Register(NULL, "model", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
- trap_Cvar_Register(NULL, "headmodel", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
- trap_Cvar_Register(NULL, "team_model", DEFAULT_TEAM_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
- trap_Cvar_Register(NULL, "team_headmodel", DEFAULT_TEAM_HEAD, CVAR_USERINFO | CVAR_ARCHIVE );
-}
-
-/*
-===================
-CG_ForceModelChange
-===================
-*/
-static void CG_ForceModelChange( void ) {
- int i;
-
- for (i=0 ; i<MAX_CLIENTS ; i++) {
- const char *clientInfo;
-
- clientInfo = CG_ConfigString( CS_PLAYERS+i );
- if ( !clientInfo[0] ) {
- continue;
- }
- CG_NewClientInfo( i );
- }
-}
-
-/*
-=================
-CG_UpdateCvars
-=================
-*/
-void CG_UpdateCvars( void ) {
- int i;
- cvarTable_t *cv;
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
-//unlagged - client options
- // clamp the value between 0 and 999
- // negative values would suck - people could conceivably shoot other
- // players *long* after they had left the area, on purpose
- if ( cv->vmCvar == &cg_cmdTimeNudge ) {
- CG_Cvar_ClampInt( cv->cvarName, cv->vmCvar, 0, 999 );
- }
- // cl_timenudge less than -50 or greater than 50 doesn't actually
- // do anything more than -50 or 50 (actually the numbers are probably
- // closer to -30 and 30, but 50 is nice and round-ish)
- // might as well not feed the myth, eh?
- else if ( cv->vmCvar == &cl_timeNudge ) {
- CG_Cvar_ClampInt( cv->cvarName, cv->vmCvar, -50, 50 );
- }
- // don't let this go too high - no point
- /*else if ( cv->vmCvar == &cg_latentSnaps ) {
- CG_Cvar_ClampInt( cv->cvarName, cv->vmCvar, 0, 10 );
- }*/
- // don't let this get too large
- /*else if ( cv->vmCvar == &cg_latentCmds ) {
- CG_Cvar_ClampInt( cv->cvarName, cv->vmCvar, 0, MAX_LATENT_CMDS - 1 );
- }*/
- // no more than 100% packet loss
- /*else if ( cv->vmCvar == &cg_plOut ) {
- CG_Cvar_ClampInt( cv->cvarName, cv->vmCvar, 0, 100 );
- }*/
-//unlagged - client options
- else if ( cv->vmCvar == &cg_errorDecay ) {
- CG_Cvar_ClampInt( cv->cvarName, cv->vmCvar, 0, 250 );
- }
- trap_Cvar_Update( cv->vmCvar );
- }
-
- // check for modications here
-
- // If team overlay is on, ask for updates from the server. If its off,
- // let the server know so we don't receive it
- if ( drawTeamOverlayModificationCount != cg_drawTeamOverlay.modificationCount ) {
- drawTeamOverlayModificationCount = cg_drawTeamOverlay.modificationCount;
-
- if ( cg_drawTeamOverlay.integer > 0 ) {
- trap_Cvar_Set( "teamoverlay", "1" );
- } else {
- trap_Cvar_Set( "teamoverlay", "0" );
- }
- }
-
- // if force model changed
- if ( forceModelModificationCount != cg_forceModel.modificationCount ) {
- forceModelModificationCount = cg_forceModel.modificationCount;
- CG_ForceModelChange();
- }
-}
-
-int CG_CrosshairPlayer( void ) {
- if ( cg.time > ( cg.crosshairClientTime + 1000 ) ) {
- return -1;
- }
- return cg.crosshairClientNum;
-}
-
-int CG_LastAttacker( void ) {
- if ( !cg.attackerTime ) {
- return -1;
- }
- return cg.snap->ps.persistant[PERS_ATTACKER];
-}
-
-void QDECL CG_Printf( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- Q_vsnprintf (text, sizeof(text), msg, argptr);
- va_end (argptr);
-
- trap_Print( text );
-}
-
-void QDECL CG_Error( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- Q_vsnprintf (text, sizeof(text), msg, argptr);
- va_end (argptr);
-
- trap_Error( text );
-}
-
-void QDECL Com_Error( int level, const char *error, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, error);
- Q_vsnprintf (text, sizeof(text), error, argptr);
- va_end (argptr);
-
- CG_Error( "%s", text);
-}
-
-void QDECL Com_Printf( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- Q_vsnprintf (text, sizeof(text), msg, argptr);
- va_end (argptr);
-
- CG_Printf ("%s", text);
-}
-
-/*
-================
-CG_Argv
-================
-*/
-const char *CG_Argv( int arg ) {
- static char buffer[MAX_STRING_CHARS];
-
- trap_Argv( arg, buffer, sizeof( buffer ) );
-
- return buffer;
-}
-
-
-//========================================================================
-
-/*
-=================
-CG_RegisterItemSounds
-
-The server says this item is used on this level
-=================
-*/
-static void CG_RegisterItemSounds( int itemNum ) {
- gitem_t *item;
- char data[MAX_QPATH];
- char *s, *start;
- int len;
-
- item = &bg_itemlist[ itemNum ];
-
- if( item->pickup_sound ) {
- trap_S_RegisterSound( item->pickup_sound, qfalse );
- }
-
- // parse the space seperated precache string for other media
- s = item->sounds;
- if (!s || !s[0])
- return;
-
- while (*s) {
- start = s;
- while (*s && *s != ' ') {
- s++;
- }
-
- len = s-start;
- if (len >= MAX_QPATH || len < 5) {
- CG_Error( "PrecacheItem: %s has bad precache string",
- item->classname);
- return;
- }
- memcpy (data, start, len);
- data[len] = 0;
- if ( *s ) {
- s++;
- }
-
- if ( !strcmp(data+len-3, "wav" )) {
- trap_S_RegisterSound( data, qfalse );
- }
- }
-}
-
-
-/*
-=================
-CG_RegisterSounds
-
-called during a precache command
-=================
-*/
-static void CG_RegisterSounds( void ) {
- int i;
- char items[MAX_ITEMS+1];
- char name[MAX_QPATH];
- const char *soundName;
-
- // voice commands
-#ifdef MISSIONPACK
- CG_LoadVoiceChats();
-#endif
-
- cgs.media.oneMinuteSound = trap_S_RegisterSound( "sound/feedback/1_minute.wav", qtrue );
- cgs.media.fiveMinuteSound = trap_S_RegisterSound( "sound/feedback/5_minute.wav", qtrue );
- cgs.media.suddenDeathSound = trap_S_RegisterSound( "sound/feedback/sudden_death.wav", qtrue );
- cgs.media.oneFragSound = trap_S_RegisterSound( "sound/feedback/1_frag.wav", qtrue );
- cgs.media.twoFragSound = trap_S_RegisterSound( "sound/feedback/2_frags.wav", qtrue );
- cgs.media.threeFragSound = trap_S_RegisterSound( "sound/feedback/3_frags.wav", qtrue );
- cgs.media.count3Sound = trap_S_RegisterSound( "sound/feedback/three.wav", qtrue );
- cgs.media.count2Sound = trap_S_RegisterSound( "sound/feedback/two.wav", qtrue );
- cgs.media.count1Sound = trap_S_RegisterSound( "sound/feedback/one.wav", qtrue );
- cgs.media.countFightSound = trap_S_RegisterSound( "sound/feedback/fight.wav", qtrue );
- cgs.media.countPrepareSound = trap_S_RegisterSound( "sound/feedback/prepare.wav", qtrue );
-#ifdef MISSIONPACK
- cgs.media.countPrepareTeamSound = trap_S_RegisterSound( "sound/feedback/prepare_team.wav", qtrue );
-#endif
-
- // N_G: Another condition that makes no sense to me, see for
- // yourself if you really meant this
- // Sago: Makes perfect sense: Load team game stuff if the gametype is a teamgame and not an exception (like GT_LMS)
- if ( ( ( cgs.gametype >= GT_TEAM ) && ( cgs.ffa_gt != 1 ) ) ||
- cg_buildScript.integer ) {
-
- cgs.media.captureAwardSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qtrue );
- cgs.media.redLeadsSound = trap_S_RegisterSound( "sound/feedback/redleads.wav", qtrue );
- cgs.media.blueLeadsSound = trap_S_RegisterSound( "sound/feedback/blueleads.wav", qtrue );
- cgs.media.teamsTiedSound = trap_S_RegisterSound( "sound/feedback/teamstied.wav", qtrue );
- cgs.media.hitTeamSound = trap_S_RegisterSound( "sound/feedback/hit_teammate.wav", qtrue );
-
- cgs.media.redScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_red_scores.wav", qtrue );
- cgs.media.blueScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_scores.wav", qtrue );
-
- cgs.media.captureYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qtrue );
- cgs.media.captureOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_opponent.wav", qtrue );
-
- cgs.media.returnYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_yourteam.wav", qtrue );
- cgs.media.returnOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue );
-
- cgs.media.takenYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_yourteam.wav", qtrue );
- cgs.media.takenOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_opponent.wav", qtrue );
-
- if ( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION|| cg_buildScript.integer ) {
- cgs.media.redFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_red_returned.wav", qtrue );
- cgs.media.blueFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_returned.wav", qtrue );
- cgs.media.enemyTookYourFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_flag.wav", qtrue );
- cgs.media.yourTeamTookEnemyFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_flag.wav", qtrue );
- }
-
- if ( cgs.gametype == GT_1FCTF || cg_buildScript.integer ) {
- // FIXME: get a replacement for this sound ?
- cgs.media.neutralFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue );
- cgs.media.yourTeamTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_1flag.wav", qtrue );
- cgs.media.enemyTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_1flag.wav", qtrue );
- }
-
- if ( cgs.gametype == GT_1FCTF || cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION ||cg_buildScript.integer ) {
- cgs.media.youHaveFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_you_flag.wav", qtrue );
- cgs.media.holyShitSound = trap_S_RegisterSound("sound/feedback/voc_holyshit.wav", qtrue);
- }
-
- if ( cgs.gametype == GT_OBELISK || cg_buildScript.integer ) {
- cgs.media.yourBaseIsUnderAttackSound = trap_S_RegisterSound( "sound/teamplay/voc_base_attack.wav", qtrue );
- }
- }
-
- cgs.media.tracerSound = trap_S_RegisterSound( "sound/weapons/machinegun/buletby1.wav", qfalse );
- cgs.media.selectSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse );
- cgs.media.wearOffSound = trap_S_RegisterSound( "sound/items/wearoff.wav", qfalse );
- cgs.media.useNothingSound = trap_S_RegisterSound( "sound/items/use_nothing.wav", qfalse );
- cgs.media.gibSound = trap_S_RegisterSound( "sound/player/gibsplt1.wav", qfalse );
- cgs.media.gibBounce1Sound = trap_S_RegisterSound( "sound/player/gibimp1.wav", qfalse );
- cgs.media.gibBounce2Sound = trap_S_RegisterSound( "sound/player/gibimp2.wav", qfalse );
- cgs.media.gibBounce3Sound = trap_S_RegisterSound( "sound/player/gibimp3.wav", qfalse );
-
-
- // LEILEI
-
- cgs.media.lspl1Sound = trap_S_RegisterSound( "sound/le/splat1.wav", qfalse );
- cgs.media.lspl2Sound = trap_S_RegisterSound( "sound/le/splat2.wav", qfalse );
- cgs.media.lspl3Sound = trap_S_RegisterSound( "sound/le/splat3.wav", qfalse );
-
- cgs.media.lbul1Sound = trap_S_RegisterSound( "sound/le/bullet1.wav", qfalse );
- cgs.media.lbul2Sound = trap_S_RegisterSound( "sound/le/bullet2.wav", qfalse );
- cgs.media.lbul3Sound = trap_S_RegisterSound( "sound/le/bullet3.wav", qfalse );
-
- cgs.media.lshl1Sound = trap_S_RegisterSound( "sound/le/shell1.wav", qfalse );
- cgs.media.lshl2Sound = trap_S_RegisterSound( "sound/le/shell2.wav", qfalse );
- cgs.media.lshl3Sound = trap_S_RegisterSound( "sound/le/shell3.wav", qfalse );
-
- cgs.media.useInvulnerabilitySound = trap_S_RegisterSound( "sound/items/invul_activate.wav", qfalse );
- cgs.media.invulnerabilityImpactSound1 = trap_S_RegisterSound( "sound/items/invul_impact_01.wav", qfalse );
- cgs.media.invulnerabilityImpactSound2 = trap_S_RegisterSound( "sound/items/invul_impact_02.wav", qfalse );
- cgs.media.invulnerabilityImpactSound3 = trap_S_RegisterSound( "sound/items/invul_impact_03.wav", qfalse );
- cgs.media.invulnerabilityJuicedSound = trap_S_RegisterSound( "sound/items/invul_juiced.wav", qfalse );
-
- cgs.media.ammoregenSound = trap_S_RegisterSound("sound/items/cl_ammoregen.wav", qfalse);
- cgs.media.doublerSound = trap_S_RegisterSound("sound/items/cl_doubler.wav", qfalse);
- cgs.media.guardSound = trap_S_RegisterSound("sound/items/cl_guard.wav", qfalse);
- cgs.media.scoutSound = trap_S_RegisterSound("sound/items/cl_scout.wav", qfalse);
- cgs.media.obeliskHitSound1 = trap_S_RegisterSound( "sound/items/obelisk_hit_01.wav", qfalse );
- cgs.media.obeliskHitSound2 = trap_S_RegisterSound( "sound/items/obelisk_hit_02.wav", qfalse );
- cgs.media.obeliskHitSound3 = trap_S_RegisterSound( "sound/items/obelisk_hit_03.wav", qfalse );
- cgs.media.obeliskRespawnSound = trap_S_RegisterSound( "sound/items/obelisk_respawn.wav", qfalse );
-
- cgs.media.teleInSound = trap_S_RegisterSound( "sound/world/telein.wav", qfalse );
- cgs.media.teleOutSound = trap_S_RegisterSound( "sound/world/teleout.wav", qfalse );
- cgs.media.respawnSound = trap_S_RegisterSound( "sound/items/respawn1.wav", qfalse );
-
- cgs.media.noAmmoSound = trap_S_RegisterSound( "sound/weapons/noammo.wav", qfalse );
-
- cgs.media.talkSound = trap_S_RegisterSound( "sound/player/talk.wav", qfalse );
- cgs.media.landSound = trap_S_RegisterSound( "sound/player/land1.wav", qfalse);
-
- switch(cg_hitsound.integer) {
-
- case 0:
- default:
- cgs.media.hitSound = trap_S_RegisterSound( "sound/feedback/hit.wav", qfalse );
- };
-
-#ifdef MISSIONPACK
- cgs.media.hitSoundHighArmor = trap_S_RegisterSound( "sound/feedback/hithi.wav", qfalse );
- cgs.media.hitSoundLowArmor = trap_S_RegisterSound( "sound/feedback/hitlo.wav", qfalse );
-#endif
-
- cgs.media.impressiveSound = trap_S_RegisterSound( "sound/feedback/impressive.wav", qtrue );
- cgs.media.excellentSound = trap_S_RegisterSound( "sound/feedback/excellent.wav", qtrue );
- cgs.media.deniedSound = trap_S_RegisterSound( "sound/feedback/denied.wav", qtrue );
- cgs.media.humiliationSound = trap_S_RegisterSound( "sound/feedback/humiliation.wav", qtrue );
- cgs.media.assistSound = trap_S_RegisterSound( "sound/feedback/assist.wav", qtrue );
- cgs.media.defendSound = trap_S_RegisterSound( "sound/feedback/defense.wav", qtrue );
-#ifdef MISSIONPACK
- cgs.media.firstImpressiveSound = trap_S_RegisterSound( "sound/feedback/first_impressive.wav", qtrue );
- cgs.media.firstExcellentSound = trap_S_RegisterSound( "sound/feedback/first_excellent.wav", qtrue );
- cgs.media.firstHumiliationSound = trap_S_RegisterSound( "sound/feedback/first_gauntlet.wav", qtrue );
-#endif
-
- cgs.media.takenLeadSound = trap_S_RegisterSound( "sound/feedback/takenlead.wav", qtrue);
- cgs.media.tiedLeadSound = trap_S_RegisterSound( "sound/feedback/tiedlead.wav", qtrue);
- cgs.media.lostLeadSound = trap_S_RegisterSound( "sound/feedback/lostlead.wav", qtrue);
-
-#ifdef MISSIONPACK
- cgs.media.voteNow = trap_S_RegisterSound( "sound/feedback/vote_now.wav", qtrue);
- cgs.media.votePassed = trap_S_RegisterSound( "sound/feedback/vote_passed.wav", qtrue);
- cgs.media.voteFailed = trap_S_RegisterSound( "sound/feedback/vote_failed.wav", qtrue);
-#endif
-
- cgs.media.watrInSound = trap_S_RegisterSound( "sound/player/watr_in.wav", qfalse);
- cgs.media.watrOutSound = trap_S_RegisterSound( "sound/player/watr_out.wav", qfalse);
- cgs.media.watrUnSound = trap_S_RegisterSound( "sound/player/watr_un.wav", qfalse);
-
- cgs.media.jumpPadSound = trap_S_RegisterSound ("sound/world/jumppad.wav", qfalse );
-
- for (i=0 ; i<4 ; i++) {
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/step%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_NORMAL][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/boot%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_BOOT][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/flesh%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_FLESH][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/mech%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_MECH][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/energy%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_ENERGY][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/splash%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_SPLASH][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/clank%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_METAL][i] = trap_S_RegisterSound (name, qfalse);
- }
-
- // only register the items that the server says we need
- Q_strncpyz(items, CG_ConfigString(CS_ITEMS), sizeof(items));
-
- for ( i = 1 ; i < bg_numItems ; i++ ) {
-// if ( items[ i ] == '1' || cg_buildScript.integer ) {
- CG_RegisterItemSounds( i );
-// }
- }
-
- for ( i = 1 ; i < MAX_SOUNDS ; i++ ) {
- soundName = CG_ConfigString( CS_SOUNDS+i );
- if ( !soundName[0] ) {
- break;
- }
- if ( soundName[0] == '*' ) {
- continue; // custom sound
- }
- cgs.gameSounds[i] = trap_S_RegisterSound( soundName, qfalse );
- }
-
- // FIXME: only needed with item
- cgs.media.flightSound = trap_S_RegisterSound( "sound/items/flight.wav", qfalse );
- cgs.media.medkitSound = trap_S_RegisterSound ("sound/items/use_medkit.wav", qfalse);
- cgs.media.quadSound = trap_S_RegisterSound("sound/items/damage3.wav", qfalse);
- cgs.media.sfx_ric1 = trap_S_RegisterSound ("sound/weapons/machinegun/ric1.wav", qfalse);
- cgs.media.sfx_ric2 = trap_S_RegisterSound ("sound/weapons/machinegun/ric2.wav", qfalse);
- cgs.media.sfx_ric3 = trap_S_RegisterSound ("sound/weapons/machinegun/ric3.wav", qfalse);
- cgs.media.sfx_railg = trap_S_RegisterSound ("sound/weapons/railgun/railgf1a.wav", qfalse);
- cgs.media.sfx_rockexp = trap_S_RegisterSound ("sound/weapons/rocket/rocklx1a.wav", qfalse);
- cgs.media.sfx_plasmaexp = trap_S_RegisterSound ("sound/weapons/plasma/plasmx1a.wav", qfalse);
- cgs.media.sfx_proxexp = trap_S_RegisterSound( "sound/weapons/proxmine/wstbexpl.wav" , qfalse);
- cgs.media.sfx_nghit = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpd.wav" , qfalse);
- cgs.media.sfx_nghitflesh = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpl.wav" , qfalse);
- cgs.media.sfx_nghitmetal = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpm.wav", qfalse );
- cgs.media.sfx_chghit = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpd.wav", qfalse );
- cgs.media.sfx_chghitflesh = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpl.wav", qfalse );
- cgs.media.sfx_chghitmetal = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpm.wav", qfalse );
- cgs.media.weaponHoverSound = trap_S_RegisterSound( "sound/weapons/weapon_hover.wav", qfalse );
- cgs.media.kamikazeExplodeSound = trap_S_RegisterSound( "sound/items/kam_explode.wav", qfalse );
- cgs.media.kamikazeImplodeSound = trap_S_RegisterSound( "sound/items/kam_implode.wav", qfalse );
- cgs.media.kamikazeFarSound = trap_S_RegisterSound( "sound/items/kam_explode_far.wav", qfalse );
- cgs.media.winnerSound = trap_S_RegisterSound( "sound/feedback/voc_youwin.wav", qfalse );
- cgs.media.loserSound = trap_S_RegisterSound( "sound/feedback/voc_youlose.wav", qfalse );
- cgs.media.youSuckSound = trap_S_RegisterSound( "sound/misc/yousuck.wav", qfalse );
-
- cgs.media.wstbimplSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpl.wav", qfalse);
- cgs.media.wstbimpmSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpm.wav", qfalse);
- cgs.media.wstbimpdSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpd.wav", qfalse);
- cgs.media.wstbactvSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbactv.wav", qfalse);
-
- cgs.media.regenSound = trap_S_RegisterSound("sound/items/regen.wav", qfalse);
- cgs.media.protectSound = trap_S_RegisterSound("sound/items/protect3.wav", qfalse);
- cgs.media.n_healthSound = trap_S_RegisterSound("sound/items/n_health.wav", qfalse );
- cgs.media.hgrenb1aSound = trap_S_RegisterSound("sound/weapons/grenade/hgrenb1a.wav", qfalse);
- cgs.media.hgrenb2aSound = trap_S_RegisterSound("sound/weapons/grenade/hgrenb2a.wav", qfalse);
-
-#ifdef MISSIONPACK
- trap_S_RegisterSound("sound/player/sergei/death1.wav", qfalse );
- trap_S_RegisterSound("sound/player/sergei/death2.wav", qfalse );
- trap_S_RegisterSound("sound/player/sergei/death3.wav", qfalse );
- trap_S_RegisterSound("sound/player/sergei/jump1.wav", qfalse );
- trap_S_RegisterSound("sound/player/sergei/pain25_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/sergei/pain75_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/sergei/pain100_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/sergei/falling1.wav", qfalse );
- trap_S_RegisterSound("sound/player/sergei/gasp.wav", qfalse );
- trap_S_RegisterSound("sound/player/sergei/drown.wav", qfalse );
- trap_S_RegisterSound("sound/player/sergei/fall1.wav", qfalse );
- trap_S_RegisterSound("sound/player/sergei/taunt.wav", qfalse );
-
- trap_S_RegisterSound("sound/player/kyonshi/death1.wav", qfalse );
- trap_S_RegisterSound("sound/player/kyonshi/death2.wav", qfalse );
- trap_S_RegisterSound("sound/player/kyonshi/death3.wav", qfalse );
- trap_S_RegisterSound("sound/player/kyonshi/jump1.wav", qfalse );
- trap_S_RegisterSound("sound/player/kyonshi/pain25_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/kyonshi/pain75_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/kyonshi/pain100_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/kyonshi/falling1.wav", qfalse );
- trap_S_RegisterSound("sound/player/kyonshi/gasp.wav", qfalse );
- trap_S_RegisterSound("sound/player/kyonshi/drown.wav", qfalse );
- trap_S_RegisterSound("sound/player/kyonshi/fall1.wav", qfalse );
- trap_S_RegisterSound("sound/player/kyonshi/taunt.wav", qfalse );
-#endif
-
-}
-
-
-//===================================================================================
-
-
-/*
-=================
-CG_RegisterGraphics
-
-This function may execute for a couple of minutes with a slow disk.
-=================
-*/
-static void CG_RegisterGraphics( void ) {
- int i;
- char items[MAX_ITEMS+1];
- static char *sb_nums[11] = {
- "gfx/2d/numbers/zero_32b",
- "gfx/2d/numbers/one_32b",
- "gfx/2d/numbers/two_32b",
- "gfx/2d/numbers/three_32b",
- "gfx/2d/numbers/four_32b",
- "gfx/2d/numbers/five_32b",
- "gfx/2d/numbers/six_32b",
- "gfx/2d/numbers/seven_32b",
- "gfx/2d/numbers/eight_32b",
- "gfx/2d/numbers/nine_32b",
- "gfx/2d/numbers/minus_32b",
- };
-
- // clear any references to old media
- memset( &cg.refdef, 0, sizeof( cg.refdef ) );
- trap_R_ClearScene();
-
- CG_LoadingString( cgs.mapname );
-
- trap_R_LoadWorldMap( cgs.mapname );
-
- // precache status bar pics
- CG_LoadingString( "game media" );
-
- for ( i=0 ; i<11 ; i++) {
- cgs.media.numberShaders[i] = trap_R_RegisterShader( sb_nums[i] );
- }
-
- cgs.media.botSkillShaders[0] = trap_R_RegisterShader( "menu/art/skill1.tga" );
- cgs.media.botSkillShaders[1] = trap_R_RegisterShader( "menu/art/skill2.tga" );
- cgs.media.botSkillShaders[2] = trap_R_RegisterShader( "menu/art/skill3.tga" );
- cgs.media.botSkillShaders[3] = trap_R_RegisterShader( "menu/art/skill4.tga" );
- cgs.media.botSkillShaders[4] = trap_R_RegisterShader( "menu/art/skill5.tga" );
-
- cgs.media.viewBloodShader = trap_R_RegisterShader( "viewBloodBlend" );
-
- cgs.media.deferShader = trap_R_RegisterShaderNoMip( "gfx/2d/defer.tga" );
-
- cgs.media.scoreboardName = trap_R_RegisterShaderNoMip( "menu/tab/name.tga" );
- cgs.media.scoreboardPing = trap_R_RegisterShaderNoMip( "menu/tab/ping.tga" );
- cgs.media.scoreboardScore = trap_R_RegisterShaderNoMip( "menu/tab/score.tga" );
- cgs.media.scoreboardTime = trap_R_RegisterShaderNoMip( "menu/tab/time.tga" );
-
- cgs.media.smokePuffShader = trap_R_RegisterShader( "smokePuff" );
- cgs.media.smokePuffRageProShader = trap_R_RegisterShader( "smokePuffRagePro" );
- cgs.media.shotgunSmokePuffShader = trap_R_RegisterShader( "shotgunSmokePuff" );
- cgs.media.nailPuffShader = trap_R_RegisterShader( "nailtrail" );
- cgs.media.blueProxMine = trap_R_RegisterModel( "models/weaphits/proxmineb.md3" );
- cgs.media.plasmaBallShader = trap_R_RegisterShader( "sprites/plasma1" );
- cgs.media.bloodTrailShader = trap_R_RegisterShader( "bloodTrail" );
- cgs.media.lagometerShader = trap_R_RegisterShader("lagometer" );
- cgs.media.connectionShader = trap_R_RegisterShader( "disconnected" );
-
- cgs.media.waterBubbleShader = trap_R_RegisterShader( "waterBubble" );
-
- cgs.media.tracerShader = trap_R_RegisterShader( "gfx/misc/tracer" );
- cgs.media.selectShader = trap_R_RegisterShader( "gfx/2d/select" );
-
- for (i = 0; i < NUM_CROSSHAIRS; i++ ) {
- if (i < 10)
- cgs.media.crosshairShader[i] = trap_R_RegisterShader( va("gfx/2d/crosshair%c", 'a'+i) );
- else
- cgs.media.crosshairShader[i] = trap_R_RegisterShader( va("gfx/2d/crosshair%02d", i - 10) );
- }
-
- cgs.media.backTileShader = trap_R_RegisterShader( "gfx/2d/backtile" );
- cgs.media.noammoShader = trap_R_RegisterShader( "icons/noammo" );
-
- // powerup shaders
- cgs.media.quadShader = trap_R_RegisterShader("powerups/quad" );
- cgs.media.quadWeaponShader = trap_R_RegisterShader("powerups/quadWeapon" );
- cgs.media.battleSuitShader = trap_R_RegisterShader("powerups/battleSuit" );
- cgs.media.battleWeaponShader = trap_R_RegisterShader("powerups/battleWeapon" );
- cgs.media.invisShader = trap_R_RegisterShader("powerups/invisibility" );
- cgs.media.regenShader = trap_R_RegisterShader("powerups/regen" );
- cgs.media.hastePuffShader = trap_R_RegisterShader("hasteSmokePuff" );
-
- if ( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION|| cgs.gametype == GT_1FCTF || cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
- cgs.media.redCubeModel = trap_R_RegisterModel( "models/powerups/orb/r_orb.md3" );
- cgs.media.blueCubeModel = trap_R_RegisterModel( "models/powerups/orb/b_orb.md3" );
- cgs.media.redCubeIcon = trap_R_RegisterShader( "icons/skull_red" );
- cgs.media.blueCubeIcon = trap_R_RegisterShader( "icons/skull_blue" );
- }
-
-//For Double Domination:
- if ( cgs.gametype == GT_DOUBLE_D ) {
- cgs.media.ddPointSkinA[TEAM_RED] = trap_R_RegisterShaderNoMip( "icons/icona_red" );
- cgs.media.ddPointSkinA[TEAM_BLUE] = trap_R_RegisterShaderNoMip( "icons/icona_blue" );
- cgs.media.ddPointSkinA[TEAM_FREE] = trap_R_RegisterShaderNoMip( "icons/icona_white" );
- cgs.media.ddPointSkinA[TEAM_NONE] = trap_R_RegisterShaderNoMip( "icons/noammo" );
-
- cgs.media.ddPointSkinB[TEAM_RED] = trap_R_RegisterShaderNoMip( "icons/iconb_red" );
- cgs.media.ddPointSkinB[TEAM_BLUE] = trap_R_RegisterShaderNoMip( "icons/iconb_blue" );
- cgs.media.ddPointSkinB[TEAM_FREE] = trap_R_RegisterShaderNoMip( "icons/iconb_white" );
- cgs.media.ddPointSkinB[TEAM_NONE] = trap_R_RegisterShaderNoMip( "icons/noammo" );
- }
-
- if ( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION || cgs.gametype == GT_1FCTF || cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
- cgs.media.redFlagModel = trap_R_RegisterModel( "models/flags/r_flag.md3" );
- cgs.media.blueFlagModel = trap_R_RegisterModel( "models/flags/b_flag.md3" );
- cgs.media.neutralFlagModel = trap_R_RegisterModel( "models/flags/n_flag.md3" );
- cgs.media.redFlagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_red1" );
- cgs.media.redFlagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_red2" );
- cgs.media.redFlagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_red3" );
- cgs.media.blueFlagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_blu1" );
- cgs.media.blueFlagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_blu2" );
- cgs.media.blueFlagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_blu3" );
- cgs.media.flagPoleModel = trap_R_RegisterModel( "models/flag2/flagpole.md3" );
- cgs.media.flagFlapModel = trap_R_RegisterModel( "models/flag2/flagflap3.md3" );
-
- cgs.media.redFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/red.skin" );
- cgs.media.blueFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/blue.skin" );
- cgs.media.neutralFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/white.skin" );
-
- cgs.media.redFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/red_base.md3" );
- cgs.media.blueFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/blue_base.md3" );
- cgs.media.neutralFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/ntrl_base.md3" );
- }
-
- if ( cgs.gametype == GT_1FCTF || cg_buildScript.integer ) {
- cgs.media.neutralFlagModel = trap_R_RegisterModel( "models/flags/n_flag.md3" );
- cgs.media.flagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_neutral1" );
- cgs.media.flagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_red2" );
- cgs.media.flagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_blu2" );
- cgs.media.flagShader[3] = trap_R_RegisterShaderNoMip( "icons/iconf_neutral3" );
- }
-
- if ( cgs.gametype == GT_OBELISK || cg_buildScript.integer ) {
- cgs.media.overloadBaseModel = trap_R_RegisterModel( "models/powerups/overload_base.md3" );
- cgs.media.overloadTargetModel = trap_R_RegisterModel( "models/powerups/overload_target.md3" );
- cgs.media.overloadLightsModel = trap_R_RegisterModel( "models/powerups/overload_lights.md3" );
- cgs.media.overloadEnergyModel = trap_R_RegisterModel( "models/powerups/overload_energy.md3" );
- }
-
- if ( cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
- cgs.media.harvesterModel = trap_R_RegisterModel( "models/powerups/harvester/harvester.md3" );
- cgs.media.harvesterRedSkin = trap_R_RegisterSkin( "models/powerups/harvester/red.skin" );
- cgs.media.harvesterBlueSkin = trap_R_RegisterSkin( "models/powerups/harvester/blue.skin" );
- cgs.media.harvesterNeutralModel = trap_R_RegisterModel( "models/powerups/obelisk/obelisk.md3" );
- }
-
- cgs.media.redKamikazeShader = trap_R_RegisterShader( "models/weaphits/kamikred" );
- cgs.media.dustPuffShader = trap_R_RegisterShader("hasteSmokePuff" );
-
- if ( ( ( cgs.gametype >= GT_TEAM ) && ( cgs.ffa_gt != 1 ) ) ||
- cg_buildScript.integer ) {
-
- cgs.media.friendShader = trap_R_RegisterShader( "sprites/foe" );
- cgs.media.redQuadShader = trap_R_RegisterShader("powerups/blueflag" );
- cgs.media.teamStatusBar = trap_R_RegisterShader( "gfx/2d/colorbar.tga" );
- cgs.media.blueKamikazeShader = trap_R_RegisterShader( "models/weaphits/kamikblu" );
- }
-
- cgs.media.armorModel = trap_R_RegisterModel( "models/powerups/armor/armor_yel.md3" );
- cgs.media.armorIcon = trap_R_RegisterShaderNoMip( "icons/iconr_yellow" );
-
- cgs.media.machinegunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/m_shell.md3" );
- cgs.media.shotgunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/s_shell.md3" );
-
- cgs.media.gibAbdomen = trap_R_RegisterModel( "models/gibs/abdomen.md3" );
- cgs.media.gibArm = trap_R_RegisterModel( "models/gibs/arm.md3" );
- cgs.media.gibChest = trap_R_RegisterModel( "models/gibs/chest.md3" );
- cgs.media.gibFist = trap_R_RegisterModel( "models/gibs/fist.md3" );
- cgs.media.gibFoot = trap_R_RegisterModel( "models/gibs/foot.md3" );
- cgs.media.gibForearm = trap_R_RegisterModel( "models/gibs/forearm.md3" );
- cgs.media.gibIntestine = trap_R_RegisterModel( "models/gibs/intestine.md3" );
- cgs.media.gibLeg = trap_R_RegisterModel( "models/gibs/leg.md3" );
- cgs.media.gibSkull = trap_R_RegisterModel( "models/gibs/skull.md3" );
- cgs.media.gibBrain = trap_R_RegisterModel( "models/gibs/brain.md3" );
-
- cgs.media.smoke2 = trap_R_RegisterModel( "models/weapons2/shells/s_shell.md3" );
-
- cgs.media.balloonShader = trap_R_RegisterShader( "sprites/balloon3" );
-
- cgs.media.bloodExplosionShader = trap_R_RegisterShader( "bloodExplosion" );
-
- cgs.media.bulletFlashModel = trap_R_RegisterModel("models/weaphits/bullet.md3");
- cgs.media.ringFlashModel = trap_R_RegisterModel("models/weaphits/ring02.md3");
- cgs.media.dishFlashModel = trap_R_RegisterModel("models/weaphits/boom01.md3");
-#ifdef MISSIONPACK
- cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/powerups/pop.md3" );
-#else
- cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/misc/telep.md3" );
- cgs.media.teleportEffectShader = trap_R_RegisterShader( "teleportEffect" );
-#endif
- cgs.media.kamikazeEffectModel = trap_R_RegisterModel( "models/weaphits/kamboom2.md3" );
- cgs.media.kamikazeShockWave = trap_R_RegisterModel( "models/weaphits/kamwave.md3" );
- cgs.media.kamikazeHeadModel = trap_R_RegisterModel( "models/powerups/kamikazi.md3" );
- cgs.media.kamikazeHeadTrail = trap_R_RegisterModel( "models/powerups/trailtest.md3" );
- cgs.media.guardPowerupModel = trap_R_RegisterModel( "models/powerups/guard_player.md3" );
- cgs.media.scoutPowerupModel = trap_R_RegisterModel( "models/powerups/scout_player.md3" );
- cgs.media.doublerPowerupModel = trap_R_RegisterModel( "models/powerups/doubler_player.md3" );
- cgs.media.ammoRegenPowerupModel = trap_R_RegisterModel( "models/powerups/ammo_player.md3" );
- cgs.media.invulnerabilityImpactModel = trap_R_RegisterModel( "models/powerups/shield/impact.md3" );
- cgs.media.invulnerabilityJuicedModel = trap_R_RegisterModel( "models/powerups/shield/juicer.md3" );
- cgs.media.medkitUsageModel = trap_R_RegisterModel( "models/powerups/regen.md3" );
- cgs.media.heartShader = trap_R_RegisterShaderNoMip( "ui/assets/statusbar/selectedhealth.tga" );
-
-
- cgs.media.invulnerabilityPowerupModel = trap_R_RegisterModel( "models/powerups/shield/shield.md3" );
- cgs.media.medalImpressive = trap_R_RegisterShaderNoMip( "medal_impressive" );
- cgs.media.medalExcellent = trap_R_RegisterShaderNoMip( "medal_excellent" );
- cgs.media.medalGauntlet = trap_R_RegisterShaderNoMip( "medal_gauntlet" );
- cgs.media.medalDefend = trap_R_RegisterShaderNoMip( "medal_defend" );
- cgs.media.medalAssist = trap_R_RegisterShaderNoMip( "medal_assist" );
- cgs.media.medalCapture = trap_R_RegisterShaderNoMip( "medal_capture" );
-
- // LEILEI SHADERS
- cgs.media.lsmkShader1 = trap_R_RegisterShader("leismoke1" );
- cgs.media.lsmkShader2 = trap_R_RegisterShader("leismoke2" );
- cgs.media.lsmkShader3 = trap_R_RegisterShader("leismoke3" );
- cgs.media.lsmkShader4 = trap_R_RegisterShader("leismoke4" );
-
- cgs.media.lsplShader = trap_R_RegisterShader("leisplash" );
- cgs.media.lspkShader1 = trap_R_RegisterShader("leispark" );
- cgs.media.lspkShader2 = trap_R_RegisterShader("leispark2" );
- cgs.media.lbumShader1 = trap_R_RegisterShader("leiboom1" );
- cgs.media.lfblShader1 = trap_R_RegisterShader("leifball" );
-
- cgs.media.lbldShader1 = trap_R_RegisterShader("leiblood1" );
- cgs.media.lbldShader2 = trap_R_RegisterShader("leiblood2" ); // this is a mark, by the way
-
-
- memset( cg_items, 0, sizeof( cg_items ) );
- memset( cg_weapons, 0, sizeof( cg_weapons ) );
-
- // only register the items that the server says we need
- Q_strncpyz(items, CG_ConfigString(CS_ITEMS), sizeof(items));
-
- for ( i = 1 ; i < bg_numItems ; i++ ) {
- if ( items[ i ] == '1' || cg_buildScript.integer ) {
- CG_LoadingItem( i );
- CG_RegisterItemVisuals( i );
- }
- }
-
- // wall marks
- cgs.media.bulletMarkShader = trap_R_RegisterShader( "gfx/damage/bullet_mrk" );
- cgs.media.burnMarkShader = trap_R_RegisterShader( "gfx/damage/burn_med_mrk" );
- cgs.media.holeMarkShader = trap_R_RegisterShader( "gfx/damage/hole_lg_mrk" );
- cgs.media.energyMarkShader = trap_R_RegisterShader( "gfx/damage/plasma_mrk" );
- cgs.media.shadowMarkShader = trap_R_RegisterShader( "markShadow" );
- cgs.media.wakeMarkShader = trap_R_RegisterShader( "wake" );
- cgs.media.bloodMarkShader = trap_R_RegisterShader( "bloodMark" );
-
- // register the inline models
- cgs.numInlineModels = trap_CM_NumInlineModels();
- for ( i = 1 ; i < cgs.numInlineModels ; i++ ) {
- char name[10];
- vec3_t mins, maxs;
- int j;
-
- Com_sprintf( name, sizeof(name), "*%i", i );
- cgs.inlineDrawModel[i] = trap_R_RegisterModel( name );
- trap_R_ModelBounds( cgs.inlineDrawModel[i], mins, maxs );
- for ( j = 0 ; j < 3 ; j++ ) {
- cgs.inlineModelMidpoints[i][j] = mins[j] + 0.5 * ( maxs[j] - mins[j] );
- }
- }
-
- // register all the server specified models
- for (i=1 ; i<MAX_MODELS ; i++) {
- const char *modelName;
-
- modelName = CG_ConfigString( CS_MODELS+i );
- if ( !modelName[0] ) {
- break;
- }
- cgs.gameModels[i] = trap_R_RegisterModel( modelName );
- }
-
-#ifdef MISSIONPACK
- // new stuff
- cgs.media.patrolShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/patrol.tga");
- cgs.media.assaultShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/assault.tga");
- cgs.media.campShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/camp.tga");
- cgs.media.followShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/follow.tga");
- cgs.media.defendShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/defend.tga");
- cgs.media.teamLeaderShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/team_leader.tga");
- cgs.media.retrieveShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/retrieve.tga");
- cgs.media.escortShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/escort.tga");
- cgs.media.deathShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/death.tga");
-
- cgs.media.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
- cgs.media.sizeCursor = trap_R_RegisterShaderNoMip( "ui/assets/sizecursor.tga" );
- cgs.media.selectCursor = trap_R_RegisterShaderNoMip( "ui/assets/selectcursor.tga" );
- cgs.media.flagShaders[0] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_in_base.tga");
- cgs.media.flagShaders[1] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_capture.tga");
- cgs.media.flagShaders[2] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_missing.tga");
-
- trap_R_RegisterModel( "models/players/sergei/lower.md3" );
- trap_R_RegisterModel( "models/players/sergei/upper.md3" );
- trap_R_RegisterModel( "models/players/sergei/head.md3" );
-
- trap_R_RegisterModel( "models/players/kyonshi/lower.md3" );
- trap_R_RegisterModel( "models/players/kyonshi/upper.md3" );
- trap_R_RegisterModel( "models/players/kyonshi/head.md3" );
-
-#endif
- CG_ClearParticles ();
-/*
- for (i=1; i<MAX_PARTICLES_AREAS; i++)
- {
- {
- int rval;
-
- rval = CG_NewParticleArea ( CS_PARTICLES + i);
- if (!rval)
- break;
- }
- }
-*/
-}
-
-
-
-/*
-=======================
-CG_BuildSpectatorString
-
-=======================
-*/
-void CG_BuildSpectatorString(void) {
- int i;
- cg.spectatorList[0] = 0;
- for (i = 0; i < MAX_CLIENTS; i++) {
- if (cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_SPECTATOR ) {
- Q_strcat(cg.spectatorList, sizeof(cg.spectatorList), va("%s ", cgs.clientinfo[i].name));
- }
- }
- i = strlen(cg.spectatorList);
- if (i != cg.spectatorLen) {
- cg.spectatorLen = i;
- cg.spectatorWidth = -1;
- }
-}
-
-
-/*
-===================
-CG_RegisterClients
-===================
-*/
-static void CG_RegisterClients( void ) {
- int i;
-
- CG_LoadingClient(cg.clientNum);
- CG_NewClientInfo(cg.clientNum);
-
- for (i=0 ; i<MAX_CLIENTS ; i++) {
- const char *clientInfo;
-
- if (cg.clientNum == i) {
- continue;
- }
-
- clientInfo = CG_ConfigString( CS_PLAYERS+i );
- if ( !clientInfo[0]) {
- continue;
- }
- CG_LoadingClient( i );
- CG_NewClientInfo( i );
- }
- CG_BuildSpectatorString();
-}
-
-//===========================================================================
-
-/*
-=================
-CG_ConfigString
-=================
-*/
-const char *CG_ConfigString( int index ) {
- if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
- CG_Error( "CG_ConfigString: bad index: %i", index );
- }
- return cgs.gameState.stringData + cgs.gameState.stringOffsets[ index ];
-}
-
-//==================================================================
-
-/*
-======================
-CG_StartMusic
-
-======================
-*/
-void CG_StartMusic( void ) {
- char *s;
- char parm1[MAX_QPATH], parm2[MAX_QPATH];
-
- // start the background music
- if ( *cg_music.string && Q_stricmp( cg_music.string, "none" ) ) {
- s = (char *)cg_music.string;
- } else {
- s = (char *)CG_ConfigString( CS_MUSIC );
- Q_strncpyz( parm1, COM_Parse( &s ), sizeof( parm1 ) );
- Q_strncpyz( parm2, COM_Parse( &s ), sizeof( parm2 ) );
-
- trap_S_StartBackgroundTrack( parm1, parm2 );
- }
-}
-#ifdef MISSIONPACK
-char *CG_GetMenuBuffer(const char *filename) {
- int len;
- fileHandle_t f;
- static char buf[MAX_MENUFILE];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
- return NULL;
- }
- if ( len >= MAX_MENUFILE ) {
- trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", filename, len, MAX_MENUFILE ) );
- trap_FS_FCloseFile( f );
- return NULL;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- return buf;
-}
-
-//
-// ==============================
-// new hud stuff ( mission pack )
-// ==============================
-//
-qboolean CG_Asset_Parse(int handle) {
- pc_token_t token;
- const char *tempStr;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (Q_stricmp(token.string, "{") != 0) {
- return qfalse;
- }
-
- while ( 1 ) {
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
-
- if (Q_stricmp(token.string, "}") == 0) {
- return qtrue;
- }
-
- // font
- if (Q_stricmp(token.string, "font") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
- return qfalse;
- }
- cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.textFont);
- continue;
- }
-
- // smallFont
- if (Q_stricmp(token.string, "smallFont") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
- return qfalse;
- }
- cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.smallFont);
- continue;
- }
-
- // font
- if (Q_stricmp(token.string, "bigfont") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
- return qfalse;
- }
- cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.bigFont);
- continue;
- }
-
- // gradientbar
- if (Q_stricmp(token.string, "gradientbar") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
- continue;
- }
-
- // enterMenuSound
- if (Q_stricmp(token.string, "menuEnterSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // exitMenuSound
- if (Q_stricmp(token.string, "menuExitSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // itemFocusSound
- if (Q_stricmp(token.string, "itemFocusSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // menuBuzzSound
- if (Q_stricmp(token.string, "menuBuzzSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- if (Q_stricmp(token.string, "cursor") == 0) {
- if (!PC_String_Parse(handle, &cgDC.Assets.cursorStr)) {
- return qfalse;
- }
- cgDC.Assets.cursor = trap_R_RegisterShaderNoMip( cgDC.Assets.cursorStr);
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeClamp") == 0) {
- if (!PC_Float_Parse(handle, &cgDC.Assets.fadeClamp)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeCycle") == 0) {
- if (!PC_Int_Parse(handle, &cgDC.Assets.fadeCycle)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeAmount") == 0) {
- if (!PC_Float_Parse(handle, &cgDC.Assets.fadeAmount)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowX") == 0) {
- if (!PC_Float_Parse(handle, &cgDC.Assets.shadowX)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowY") == 0) {
- if (!PC_Float_Parse(handle, &cgDC.Assets.shadowY)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowColor") == 0) {
- if (!PC_Color_Parse(handle, &cgDC.Assets.shadowColor)) {
- return qfalse;
- }
- cgDC.Assets.shadowFadeClamp = cgDC.Assets.shadowColor[3];
- continue;
- }
- }
- return qfalse; // bk001204 - why not?
-}
-
-void CG_ParseMenu(const char *menuFile) {
- pc_token_t token;
- int handle;
-
- handle = trap_PC_LoadSource(menuFile);
- if (!handle)
- handle = trap_PC_LoadSource("ui/testhud.menu");
- if (!handle)
- return;
-
- while ( 1 ) {
- if (!trap_PC_ReadToken( handle, &token )) {
- break;
- }
-
- //if ( Q_stricmp( token, "{" ) ) {
- // Com_Printf( "Missing { in menu file\n" );
- // break;
- //}
-
- //if ( menuCount == MAX_MENUS ) {
- // Com_Printf( "Too many menus!\n" );
- // break;
- //}
-
- if ( token.string[0] == '}' ) {
- break;
- }
-
- if (Q_stricmp(token.string, "assetGlobalDef") == 0) {
- if (CG_Asset_Parse(handle)) {
- continue;
- } else {
- break;
- }
- }
-
-
- if (Q_stricmp(token.string, "menudef") == 0) {
- // start a new menu
- Menu_New(handle);
- }
- }
- trap_PC_FreeSource(handle);
-}
-
-qboolean CG_Load_Menu(char **p) {
- char *token;
-
- token = COM_ParseExt(p, qtrue);
-
- if (token[0] != '{') {
- return qfalse;
- }
-
- while ( 1 ) {
-
- token = COM_ParseExt(p, qtrue);
-
- if (Q_stricmp(token, "}") == 0) {
- return qtrue;
- }
-
- if ( !token || token[0] == 0 ) {
- return qfalse;
- }
-
- CG_ParseMenu(token);
- }
- return qfalse;
-}
-
-
-
-void CG_LoadMenus(const char *menuFile) {
- char *token;
- char *p;
- int len, start;
- fileHandle_t f;
- static char buf[MAX_MENUDEFFILE];
-
- start = trap_Milliseconds();
-
- len = trap_FS_FOpenFile( menuFile, &f, FS_READ );
- if ( !f ) {
- trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );
- len = trap_FS_FOpenFile( "ui/hud.txt", &f, FS_READ );
- if (!f) {
- trap_Error( va( S_COLOR_RED "default menu file not found: ui/hud.txt, unable to continue!\n") );
- }
- }
-
- if ( len >= MAX_MENUDEFFILE ) {
- trap_Error( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", menuFile, len, MAX_MENUDEFFILE ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- COM_Compress(buf);
-
- Menu_Reset();
-
- p = buf;
-
- while ( 1 ) {
- token = COM_ParseExt( &p, qtrue );
- if( !token || token[0] == 0 || token[0] == '}') {
- break;
- }
-
- //if ( Q_stricmp( token, "{" ) ) {
- // Com_Printf( "Missing { in menu file\n" );
- // break;
- //}
-
- //if ( menuCount == MAX_MENUS ) {
- // Com_Printf( "Too many menus!\n" );
- // break;
- //}
-
- if ( Q_stricmp( token, "}" ) == 0 ) {
- break;
- }
-
- if (Q_stricmp(token, "loadmenu") == 0) {
- if (CG_Load_Menu(&p)) {
- continue;
- } else {
- break;
- }
- }
- }
-
- Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start);
-
-}
-
-
-
-static qboolean CG_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) {
- return qfalse;
-}
-
-
-static int CG_FeederCount(float feederID) {
- int i, count;
- count = 0;
- if (feederID == FEEDER_REDTEAM_LIST) {
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == TEAM_RED) {
- count++;
- }
- }
- } else if (feederID == FEEDER_BLUETEAM_LIST) {
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == TEAM_BLUE) {
- count++;
- }
- }
- } else if (feederID == FEEDER_SCOREBOARD) {
- return cg.numScores;
- }
- return count;
-}
-
-
-void CG_SetScoreSelection(void *p) {
- menuDef_t *menu = (menuDef_t*)p;
- playerState_t *ps = &cg.snap->ps;
- int i, red, blue;
- red = blue = 0;
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == TEAM_RED) {
- red++;
- } else if (cg.scores[i].team == TEAM_BLUE) {
- blue++;
- }
- if (ps->clientNum == cg.scores[i].client) {
- cg.selectedScore = i;
- }
- }
-
- if (menu == NULL) {
- // just interested in setting the selected score
- return;
- }
-
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- int feeder = FEEDER_REDTEAM_LIST;
- i = red;
- if (cg.scores[cg.selectedScore].team == TEAM_BLUE) {
- feeder = FEEDER_BLUETEAM_LIST;
- i = blue;
- }
- Menu_SetFeederSelection(menu, feeder, i, NULL);
- } else {
- Menu_SetFeederSelection(menu, FEEDER_SCOREBOARD, cg.selectedScore, NULL);
- }
-}
-
-// FIXME: might need to cache this info
-static clientInfo_t * CG_InfoFromScoreIndex(int index, int team, int *scoreIndex) {
- int i, count;
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- count = 0;
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == team) {
- if (count == index) {
- *scoreIndex = i;
- return &cgs.clientinfo[cg.scores[i].client];
- }
- count++;
- }
- }
- }
- *scoreIndex = index;
- return &cgs.clientinfo[ cg.scores[index].client ];
-}
-
-static const char *CG_FeederItemText(float feederID, int index, int column, qhandle_t *handle) {
- gitem_t *item;
- int scoreIndex = 0;
- clientInfo_t *info = NULL;
- int team = -1;
- score_t *sp = NULL;
-
- *handle = -1;
-
- if (feederID == FEEDER_REDTEAM_LIST) {
- team = TEAM_RED;
- } else if (feederID == FEEDER_BLUETEAM_LIST) {
- team = TEAM_BLUE;
- }
-
- info = CG_InfoFromScoreIndex(index, team, &scoreIndex);
- sp = &cg.scores[scoreIndex];
-
- if (info && info->infoValid) {
- switch (column) {
- case 0:
- if ( info->powerups & ( 1 << PW_NEUTRALFLAG ) ) {
- item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
- *handle = cg_items[ ITEM_INDEX(item) ].icon;
- } else if ( info->powerups & ( 1 << PW_REDFLAG ) ) {
- item = BG_FindItemForPowerup( PW_REDFLAG );
- *handle = cg_items[ ITEM_INDEX(item) ].icon;
- } else if ( info->powerups & ( 1 << PW_BLUEFLAG ) ) {
- item = BG_FindItemForPowerup( PW_BLUEFLAG );
- *handle = cg_items[ ITEM_INDEX(item) ].icon;
- } else {
- if ( info->botSkill > 0 && info->botSkill <= 5 ) {
- *handle = cgs.media.botSkillShaders[ info->botSkill - 1 ];
- } else if ( info->handicap < 100 ) {
- return va("%i", info->handicap );
- }
- }
- break;
- case 1:
- if (team == -1) {
- return "";
- } else if (info->isDead) {
- *handle = cgs.media.deathShader;
- } else {
- *handle = CG_StatusHandle(info->teamTask);
- }
- break;
- case 2:
- if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << sp->client ) ) {
- return "Ready";
- }
- if (team == -1) {
- if (cgs.gametype == GT_TOURNAMENT) {
- return va("%i/%i", info->wins, info->losses);
- } else if (info->infoValid && info->team == TEAM_SPECTATOR ) {
- return "Spectator";
- } else {
- return "";
- }
- } else {
- if (info->teamLeader) {
- return "Leader";
- }
- }
- break;
- case 3:
- return info->name;
- break;
- case 4:
- return va("%i", info->score);
- break;
- case 5:
- return va("%4i", sp->time);
- break;
- case 6:
- if ( sp->ping == -1 ) {
- return "connecting";
- }
- return va("%4i", sp->ping);
- break;
- }
- }
-
- return "";
-}
-
-static qhandle_t CG_FeederItemImage(float feederID, int index) {
- return 0;
-}
-
-static void CG_FeederSelection(float feederID, int index) {
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- int i, count;
- int team = (feederID == FEEDER_REDTEAM_LIST) ? TEAM_RED : TEAM_BLUE;
- count = 0;
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == team) {
- if (index == count) {
- cg.selectedScore = i;
- }
- count++;
- }
- }
- } else {
- cg.selectedScore = index;
- }
-}
-#endif
-
-#ifdef MISSIONPACK // bk001204 - only needed there
-static float CG_Cvar_Get(const char *cvar) {
- char buff[128];
- memset(buff, 0, sizeof(buff));
- trap_Cvar_VariableStringBuffer(cvar, buff, sizeof(buff));
- return atof(buff);
-}
-#endif
-
-#ifdef MISSIONPACK
-void CG_Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) {
- CG_Text_Paint(x, y, scale, color, text, 0, limit, style);
-}
-
-static int CG_OwnerDrawWidth(int ownerDraw, float scale) {
- switch (ownerDraw) {
- case CG_GAME_TYPE:
- return CG_Text_Width(CG_GameTypeString(), scale, 0);
- case CG_GAME_STATUS:
- return CG_Text_Width(CG_GetGameStatusText(), scale, 0);
- break;
- case CG_KILLER:
- return CG_Text_Width(CG_GetKillerText(), scale, 0);
- break;
- case CG_RED_NAME:
- return CG_Text_Width(cg_redTeamName.string, scale, 0);
- break;
- case CG_BLUE_NAME:
- return CG_Text_Width(cg_blueTeamName.string, scale, 0);
- break;
-
-
- }
- return 0;
-}
-
-static int CG_PlayCinematic(const char *name, float x, float y, float w, float h) {
- return trap_CIN_PlayCinematic(name, x, y, w, h, CIN_loop);
-}
-
-static void CG_StopCinematic(int handle) {
- trap_CIN_StopCinematic(handle);
-}
-
-static void CG_DrawCinematic(int handle, float x, float y, float w, float h) {
- trap_CIN_SetExtents(handle, x, y, w, h);
- trap_CIN_DrawCinematic(handle);
-}
-
-static void CG_RunCinematicFrame(int handle) {
- trap_CIN_RunCinematic(handle);
-}
-
-/*
-=================
-CG_LoadHudMenu();
-
-=================
-*/
-void CG_LoadHudMenu( void ) {
- char buff[1024];
- const char *hudSet;
-
- cgDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
- cgDC.setColor = &trap_R_SetColor;
- cgDC.drawHandlePic = &CG_DrawPic;
- cgDC.drawStretchPic = &trap_R_DrawStretchPic;
- cgDC.drawText = &CG_Text_Paint;
- cgDC.textWidth = &CG_Text_Width;
- cgDC.textHeight = &CG_Text_Height;
- cgDC.registerModel = &trap_R_RegisterModel;
- cgDC.modelBounds = &trap_R_ModelBounds;
- cgDC.fillRect = &CG_FillRect;
- cgDC.drawRect = &CG_DrawRect;
- cgDC.drawSides = &CG_DrawSides;
- cgDC.drawTopBottom = &CG_DrawTopBottom;
- cgDC.clearScene = &trap_R_ClearScene;
- cgDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
- cgDC.renderScene = &trap_R_RenderScene;
- cgDC.registerFont = &trap_R_RegisterFont;
- cgDC.ownerDrawItem = &CG_OwnerDraw;
- cgDC.getValue = &CG_GetValue;
- cgDC.ownerDrawVisible = &CG_OwnerDrawVisible;
- cgDC.runScript = &CG_RunMenuScript;
- cgDC.getTeamColor = &CG_GetTeamColor;
- cgDC.setCVar = trap_Cvar_Set;
- cgDC.getCVarString = trap_Cvar_VariableStringBuffer;
- cgDC.getCVarValue = CG_Cvar_Get;
- cgDC.drawTextWithCursor = &CG_Text_PaintWithCursor;
- //cgDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
- //cgDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
- cgDC.startLocalSound = &trap_S_StartLocalSound;
- cgDC.ownerDrawHandleKey = &CG_OwnerDrawHandleKey;
- cgDC.feederCount = &CG_FeederCount;
- cgDC.feederItemImage = &CG_FeederItemImage;
- cgDC.feederItemText = &CG_FeederItemText;
- cgDC.feederSelection = &CG_FeederSelection;
- //cgDC.setBinding = &trap_Key_SetBinding;
- //cgDC.getBindingBuf = &trap_Key_GetBindingBuf;
- //cgDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
- //cgDC.executeText = &trap_Cmd_ExecuteText;
- cgDC.Error = &Com_Error;
- cgDC.Print = &Com_Printf;
- cgDC.ownerDrawWidth = &CG_OwnerDrawWidth;
- //cgDC.Pause = &CG_Pause;
- cgDC.registerSound = &trap_S_RegisterSound;
- cgDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
- cgDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
- cgDC.playCinematic = &CG_PlayCinematic;
- cgDC.stopCinematic = &CG_StopCinematic;
- cgDC.drawCinematic = &CG_DrawCinematic;
- cgDC.runCinematicFrame = &CG_RunCinematicFrame;
-
- Init_Display(&cgDC);
-
- Menu_Reset();
-
- trap_Cvar_VariableStringBuffer("cg_hudFiles", buff, sizeof(buff));
- hudSet = buff;
- if (hudSet[0] == '\0') {
- hudSet = "ui/hud.txt";
- }
-
- CG_LoadMenus(hudSet);
-}
-
-void CG_AssetCache( void ) {
- //if (Assets.textFont == NULL) {
- // trap_R_RegisterFont("fonts/arial.ttf", 72, &Assets.textFont);
- //}
- //Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND );
- //Com_Printf("Menu Size: %i bytes\n", sizeof(Menus));
- cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
- cgDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
- cgDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
- cgDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
- cgDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
- cgDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
- cgDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
- cgDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
- cgDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
- cgDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
- cgDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
- cgDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
- cgDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
- cgDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
- cgDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
- cgDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
- cgDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
-}
-#endif
-/*
-=================
-CG_Init
-
-Called after every level change or subsystem restart
-Will perform callbacks to make the loading info screen update.
-=================
-*/
-void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) {
- const char *s;
-
- // clear everything
- memset( &cgs, 0, sizeof( cgs ) );
- memset( &cg, 0, sizeof( cg ) );
- memset( cg_entities, 0, sizeof(cg_entities) );
- memset( cg_weapons, 0, sizeof(cg_weapons) );
- memset( cg_items, 0, sizeof(cg_items) );
-
- cg.clientNum = clientNum;
-
- cgs.processedSnapshotNum = serverMessageNum;
- cgs.serverCommandSequence = serverCommandSequence;
-
- // load a few needed things before we do any screen updates
- cgs.media.charsetShader = trap_R_RegisterShader( "gfx/2d/bigchars" );
- cgs.media.whiteShader = trap_R_RegisterShader( "white" );
- cgs.media.charsetProp = trap_R_RegisterShaderNoMip( "menu/art/font1_prop.tga" );
- cgs.media.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" );
- cgs.media.charsetPropB = trap_R_RegisterShaderNoMip( "menu/art/font2_prop.tga" );
-
- CG_RegisterCvars();
-
- CG_InitConsoleCommands();
-
- cg.weaponSelect = WP_MACHINEGUN;
-
- cgs.redflag = cgs.blueflag = -1; // For compatibily, default to unset for
- cgs.flagStatus = -1;
- // old servers
-
- // get the rendering configuration from the client system
- trap_GetGlconfig( &cgs.glconfig );
- cgs.screenXScale = cgs.glconfig.vidWidth / 640.0;
- cgs.screenYScale = cgs.glconfig.vidHeight / 480.0;
-
- // get the gamestate from the client system
- trap_GetGameState( &cgs.gameState );
-
- // check version
- s = CG_ConfigString( CS_GAME_VERSION );
- if ( strcmp( s, GAME_VERSION ) ) {
- CG_Error( "Client/Server game mismatch: %s/%s", GAME_VERSION, s );
- }
-
- s = CG_ConfigString( CS_LEVEL_START_TIME );
- cgs.levelStartTime = atoi( s );
-
- CG_ParseServerinfo();
-
- // load the new map
- CG_LoadingString( "collision map" );
-
- trap_CM_LoadMap( cgs.mapname );
-
-#ifdef MISSIONPACK
- String_Init();
-#endif
-
- cg.loading = qtrue; // force players to load instead of defer
-
- CG_LoadingString( "sounds" );
-
- CG_RegisterSounds();
-
- CG_LoadingString( "graphics" );
-
- CG_RegisterGraphics();
-
- CG_LoadingString( "clients" );
-
- CG_RegisterClients(); // if low on memory, some clients will be deferred
-
-#ifdef MISSIONPACK
- CG_AssetCache();
- CG_LoadHudMenu(); // load new hud stuff
-#endif
-
- cg.loading = qfalse; // future players will be deferred
-
- CG_InitLocalEntities();
-
- CG_InitMarkPolys();
-
- // remove the last loading update
- cg.infoScreenText[0] = 0;
-
- // Make sure we have update values (scores)
- CG_SetConfigValues();
-
- CG_StartMusic();
-
- CG_LoadingString( "" );
-
-#ifdef MISSIONPACK
- CG_InitTeamChat();
-#endif
-
- CG_ShaderStateChanged();
-
- //Init challenge system
- challenges_init();
-
- addChallenge(GENERAL_TEST);
-
- trap_S_ClearLoopingSounds( qtrue );
-}
-
-/*
-=================
-CG_Shutdown
-
-Called before every level change or subsystem restart
-=================
-*/
-void CG_Shutdown( void ) {
- // some mods may need to do cleanup work here,
- // like closing files or archiving session data
- challenges_save();
-}
-
-
-/*
-==================
-CG_EventHandling
-==================
- type 0 - no event handling
- 1 - team menu
- 2 - hud editor
-
-*/
-#ifndef MISSIONPACK
-void CG_EventHandling(int type) {
-}
-
-
-
-void CG_KeyEvent(int key, qboolean down) {
-}
-
-void CG_MouseEvent(int x, int y) {
-}
-#endif
-
-//unlagged - attack prediction #3
-// moved from g_weapon.c
-/*
-======================
-SnapVectorTowards
-
-Round a vector to integers for more efficient network
-transmission, but make sure that it rounds towards a given point
-rather than blindly truncating. This prevents it from truncating
-into a wall.
-======================
-*/
-void SnapVectorTowards( vec3_t v, vec3_t to ) {
- int i;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( to[i] <= v[i] ) {
- v[i] = (int)v[i];
- } else {
- v[i] = (int)v[i] + 1;
- }
- }
-}
-//unlagged - attack prediction #3
-
-static qboolean do_vid_restart = qfalse;
-
-void CG_FairCvars() {
- qboolean vid_restart_required = qfalse;
- char rendererinfos[128];
-
- if(cgs.gametype == GT_SINGLE_PLAYER) {
- trap_Cvar_VariableStringBuffer("r_vertexlight",rendererinfos,sizeof(rendererinfos) );
- if(cg_autovertex.integer && atoi( rendererinfos ) == 0 ) {
- trap_Cvar_Set("r_vertexlight","1");
- vid_restart_required = qtrue;
- }
- return; //Don't do anything in single player
- }
-
- if(cgs.videoflags & VF_LOCK_CVARS_BASIC) {
- //Lock basic cvars.
- trap_Cvar_VariableStringBuffer("r_subdivisions",rendererinfos,sizeof(rendererinfos) );
- if(atoi( rendererinfos ) > 80 ) {
- trap_Cvar_Set("r_subdivisions","80");
- vid_restart_required = qtrue;
- }
-
- trap_Cvar_VariableStringBuffer("cg_shadows",rendererinfos,sizeof(rendererinfos) );
- if (atoi( rendererinfos )!=0 && atoi( rendererinfos )!=1 ) {
- trap_Cvar_Set("cg_shadows","1");
- }
- }
-
- if(cgs.videoflags & VF_LOCK_CVARS_EXTENDED) {
- //Lock extended cvars.
- trap_Cvar_VariableStringBuffer("r_subdivisions",rendererinfos,sizeof(rendererinfos) );
- if(atoi( rendererinfos ) > 20 ) {
- trap_Cvar_Set("r_subdivisions","20");
- vid_restart_required = qtrue;
- }
-
- trap_Cvar_VariableStringBuffer("r_picmip",rendererinfos,sizeof(rendererinfos) );
- if(atoi( rendererinfos ) > 3 ) {
- trap_Cvar_Set("r_picmip","3");
- vid_restart_required = qtrue;
- } else if(atoi( rendererinfos ) < 0 ) {
- trap_Cvar_Set("r_picmip","0");
- vid_restart_required = qtrue;
- }
-
- trap_Cvar_VariableStringBuffer("r_intensity",rendererinfos,sizeof(rendererinfos) );
- if(atoi( rendererinfos ) > 2 ) {
- trap_Cvar_Set("r_intensity","2");
- vid_restart_required = qtrue;
- } else if(atoi( rendererinfos ) < 0 ) {
- trap_Cvar_Set("r_intensity","0");
- vid_restart_required = qtrue;
- }
-
- trap_Cvar_VariableStringBuffer("r_mapoverbrightbits",rendererinfos,sizeof(rendererinfos) );
- if(atoi( rendererinfos ) > 2 ) {
- trap_Cvar_Set("r_mapoverbrightbits","2");
- vid_restart_required = qtrue;
- } else if(atoi( rendererinfos ) < 0 ) {
- trap_Cvar_Set("r_mapoverbrightbits","0");
- vid_restart_required = qtrue;
- }
-
- trap_Cvar_VariableStringBuffer("r_overbrightbits",rendererinfos,sizeof(rendererinfos) );
- if(atoi( rendererinfos ) > 2 ) {
- trap_Cvar_Set("r_overbrightbits","2");
- vid_restart_required = qtrue;
- } else if(atoi( rendererinfos ) < 0 ) {
- trap_Cvar_Set("r_overbrightbits","0");
- vid_restart_required = qtrue;
- }
- }
-
- if(cgs.videoflags & VF_LOCK_VERTEX) {
- trap_Cvar_VariableStringBuffer("r_vertexlight",rendererinfos,sizeof(rendererinfos) );
- if(atoi( rendererinfos ) != 0 ) {
- trap_Cvar_Set("r_vertexlight","0");
- vid_restart_required = qtrue;
- }
- } else if(cg_autovertex.integer){
- trap_Cvar_VariableStringBuffer("r_vertexlight",rendererinfos,sizeof(rendererinfos) );
- if(atoi( rendererinfos ) == 0 ) {
- trap_Cvar_Set("r_vertexlight","1");
- vid_restart_required = qtrue;
- }
- }
-
- if(vid_restart_required && do_vid_restart)
- trap_SendConsoleCommand("vid_restart");
-
- do_vid_restart = qtrue;
-}
-
diff --git a/game/code/cgame/cg_marks.c b/game/code/cgame/cg_marks.c
deleted file mode 100644
index 2a9d082..0000000
--- a/game/code/cgame/cg_marks.c
+++ /dev/null
@@ -1,2439 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_marks.c -- wall marks
-
-#include "cg_local.h"
-
-/*
-===================================================================
-
-MARK POLYS
-
-===================================================================
-*/
-
-
-markPoly_t cg_activeMarkPolys; // double linked list
-markPoly_t *cg_freeMarkPolys; // single linked list
-markPoly_t cg_markPolys[MAX_MARK_POLYS];
-static int markTotal;
-
-/*
-===================
-CG_InitMarkPolys
-
-This is called at startup and for tournement restarts
-===================
-*/
-void CG_InitMarkPolys( void ) {
- int i;
-
- memset( cg_markPolys, 0, sizeof(cg_markPolys) );
-
- cg_activeMarkPolys.nextMark = &cg_activeMarkPolys;
- cg_activeMarkPolys.prevMark = &cg_activeMarkPolys;
- cg_freeMarkPolys = cg_markPolys;
- for ( i = 0 ; i < MAX_MARK_POLYS - 1 ; i++ ) {
- cg_markPolys[i].nextMark = &cg_markPolys[i+1];
- }
-}
-
-
-/*
-==================
-CG_FreeMarkPoly
-==================
-*/
-void CG_FreeMarkPoly( markPoly_t *le ) {
- if ( !le->prevMark ) {
- CG_Error( "CG_FreeLocalEntity: not active" );
- }
-
- // remove from the doubly linked active list
- le->prevMark->nextMark = le->nextMark;
- le->nextMark->prevMark = le->prevMark;
-
- // the free list is only singly linked
- le->nextMark = cg_freeMarkPolys;
- cg_freeMarkPolys = le;
-}
-
-/*
-===================
-CG_AllocMark
-
-Will allways succeed, even if it requires freeing an old active mark
-===================
-*/
-markPoly_t *CG_AllocMark( void ) {
- markPoly_t *le;
- int time;
-
- if ( !cg_freeMarkPolys ) {
- // no free entities, so free the one at the end of the chain
- // remove the oldest active entity
- time = cg_activeMarkPolys.prevMark->time;
- while (cg_activeMarkPolys.prevMark && time == cg_activeMarkPolys.prevMark->time) {
- CG_FreeMarkPoly( cg_activeMarkPolys.prevMark );
- }
- }
-
- le = cg_freeMarkPolys;
- cg_freeMarkPolys = cg_freeMarkPolys->nextMark;
-
- memset( le, 0, sizeof( *le ) );
-
- // link into the active list
- le->nextMark = cg_activeMarkPolys.nextMark;
- le->prevMark = &cg_activeMarkPolys;
- cg_activeMarkPolys.nextMark->prevMark = le;
- cg_activeMarkPolys.nextMark = le;
- return le;
-}
-
-
-
-/*
-=================
-CG_ImpactMark
-
-origin should be a point within a unit of the plane
-dir should be the plane normal
-
-temporary marks will not be stored or randomly oriented, but immediately
-passed to the renderer.
-=================
-*/
-#define MAX_MARK_FRAGMENTS 128
-#define MAX_MARK_POINTS 384
-
-void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir,
- float orientation, float red, float green, float blue, float alpha,
- qboolean alphaFade, float radius, qboolean temporary ) {
- vec3_t axis[3];
- float texCoordScale;
- vec3_t originalPoints[4];
- byte colors[4];
- int i, j;
- int numFragments;
- markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf;
- vec3_t markPoints[MAX_MARK_POINTS];
- vec3_t projection;
-
- if ( !cg_addMarks.integer ) {
- return;
- }
-
- if ( radius <= 0 ) {
- CG_Error( "CG_ImpactMark called with <= 0 radius" );
- }
-
- //if ( markTotal >= MAX_MARK_POLYS ) {
- // return;
- //}
-
- // create the texture axis
- VectorNormalize2( dir, axis[0] );
- PerpendicularVector( axis[1], axis[0] );
- RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
- CrossProduct( axis[0], axis[2], axis[1] );
-
- texCoordScale = 0.5 * 1.0 / radius;
-
- // create the full polygon
- for ( i = 0 ; i < 3 ; i++ ) {
- originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
- originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
- originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
- originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
- }
-
- // get the fragments
- VectorScale( dir, -20, projection );
- numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints,
- projection, MAX_MARK_POINTS, markPoints[0],
- MAX_MARK_FRAGMENTS, markFragments );
-
- colors[0] = red * 255;
- colors[1] = green * 255;
- colors[2] = blue * 255;
- colors[3] = alpha * 255;
-
- for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
- polyVert_t *v;
- polyVert_t verts[MAX_VERTS_ON_POLY];
- markPoly_t *mark;
-
- // we have an upper limit on the complexity of polygons
- // that we store persistantly
- if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
- mf->numPoints = MAX_VERTS_ON_POLY;
- }
- for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
- vec3_t delta;
-
- VectorCopy( markPoints[mf->firstPoint + j], v->xyz );
-
- VectorSubtract( v->xyz, origin, delta );
- v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
- v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
- *(int *)v->modulate = *(int *)colors;
- }
-
- // if it is a temporary (shadow) mark, add it immediately and forget about it
- if ( temporary ) {
- trap_R_AddPolyToScene( markShader, mf->numPoints, verts );
- continue;
- }
-
- // otherwise save it persistantly
- mark = CG_AllocMark();
- mark->time = cg.time;
- mark->alphaFade = alphaFade;
- mark->markShader = markShader;
- mark->poly.numVerts = mf->numPoints;
- mark->color[0] = red;
- mark->color[1] = green;
- mark->color[2] = blue;
- mark->color[3] = alpha;
- memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
- markTotal++;
- }
-}
-
-
-/*
-===============
-CG_AddMarks
-===============
-*/
-#define MARK_TOTAL_TIME 10000
-#define MARK_FADE_TIME 1000
-
-void CG_AddMarks( void ) {
- int j;
- markPoly_t *mp, *next;
- int t;
- int fade;
-
- if ( !cg_addMarks.integer ) {
- return;
- }
-
- mp = cg_activeMarkPolys.nextMark;
- for ( ; mp != &cg_activeMarkPolys ; mp = next ) {
- // grab next now, so if the local entity is freed we
- // still have it
- next = mp->nextMark;
-
- // see if it is time to completely remove it
- if ( cg.time > mp->time + MARK_TOTAL_TIME ) {
- CG_FreeMarkPoly( mp );
- continue;
- }
-
- // fade out the energy bursts
- if ( mp->markShader == cgs.media.energyMarkShader ) {
-
- fade = 450 - 450 * ( (cg.time - mp->time ) / 3000.0 );
- if ( fade < 255 ) {
- if ( fade < 0 ) {
- fade = 0;
- }
- if ( mp->verts[0].modulate[0] != 0 ) {
- for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
- mp->verts[j].modulate[0] = mp->color[0] * fade;
- mp->verts[j].modulate[1] = mp->color[1] * fade;
- mp->verts[j].modulate[2] = mp->color[2] * fade;
- }
- }
- }
- }
-
- // fade all marks out with time
- t = mp->time + MARK_TOTAL_TIME - cg.time;
- if ( t < MARK_FADE_TIME ) {
- fade = 255 * t / MARK_FADE_TIME;
- if ( mp->alphaFade ) {
- for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
- mp->verts[j].modulate[3] = fade;
- }
- } else {
- for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
- mp->verts[j].modulate[0] = mp->color[0] * fade;
- mp->verts[j].modulate[1] = mp->color[1] * fade;
- mp->verts[j].modulate[2] = mp->color[2] * fade;
- }
- }
- }
-
-
- trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts );
- }
-}
-
-// cg_particles.c
-
-#define BLOODRED 2
-#define EMISIVEFADE 3
-#define GREY75 4
-
-typedef struct particle_s
-{
- struct particle_s *next;
-
- float time;
- float endtime;
-
- vec3_t org;
- vec3_t vel;
- vec3_t accel;
- int color;
- float colorvel;
- float alpha;
- float alphavel;
- int type;
- qhandle_t pshader;
-
- float height;
- float width;
-
- float endheight;
- float endwidth;
-
- float start;
- float end;
-
- float startfade;
- qboolean rotate;
- int snum;
-
- qboolean link;
-
- // Ridah
- int shaderAnim;
- int roll;
-
- int accumroll;
-
-} cparticle_t;
-
-typedef enum
-{
- P_NONE,
- P_WEATHER,
- P_FLAT,
- P_SMOKE,
- P_ROTATE,
- P_WEATHER_TURBULENT,
- P_ANIM, // Ridah
- P_BAT,
- P_BLEED,
- P_FLAT_SCALEUP,
- P_FLAT_SCALEUP_FADE,
- P_WEATHER_FLURRY,
- P_SMOKE_IMPACT,
- P_BUBBLE,
- P_BUBBLE_TURBULENT,
- P_SPRITE
-} particle_type_t;
-
-#define MAX_SHADER_ANIMS 32
-#define MAX_SHADER_ANIM_FRAMES 64
-
-static char *shaderAnimNames[MAX_SHADER_ANIMS] = {
- "explode1",
- NULL
-};
-static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];
-static int shaderAnimCounts[MAX_SHADER_ANIMS] = {
- 23
-};
-static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = {
- 1.0f
-};
-static int numShaderAnims;
-// done.
-
-#define PARTICLE_GRAVITY 40
-#define MAX_PARTICLES 1024
-
-cparticle_t *active_particles, *free_particles;
-cparticle_t particles[MAX_PARTICLES];
-int cl_numparticles = MAX_PARTICLES;
-
-qboolean initparticles = qfalse;
-vec3_t pvforward, pvright, pvup;
-vec3_t rforward, rright, rup;
-
-float oldtime;
-
-/*
-===============
-CL_ClearParticles
-===============
-*/
-void CG_ClearParticles (void)
-{
- int i;
-
- memset( particles, 0, sizeof(particles) );
-
- free_particles = &particles[0];
- active_particles = NULL;
-
- for (i=0 ;i<cl_numparticles ; i++)
- {
- particles[i].next = &particles[i+1];
- particles[i].type = 0;
- }
- particles[cl_numparticles-1].next = NULL;
-
- oldtime = cg.time;
-
- // Ridah, init the shaderAnims
- for (i=0; shaderAnimNames[i]; i++) {
- int j;
-
- for (j=0; j<shaderAnimCounts[i]; j++) {
- shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) );
- }
- }
- numShaderAnims = i;
- // done.
-
- initparticles = qtrue;
-}
-
-
-/*
-=====================
-CG_AddParticleToScene
-=====================
-*/
-void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)
-{
-
- vec3_t point;
- polyVert_t verts[4];
- float width;
- float height;
- float time, time2;
- float ratio;
- float invratio;
- vec3_t color;
- polyVert_t TRIverts[3];
- vec3_t rright2, rup2;
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY
- || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {// create a front facing polygon
-
- if (p->type != P_WEATHER_FLURRY)
- {
- if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {
- if (org[2] > p->end)
- {
- p->time = cg.time;
- VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
-
- p->org[2] = ( p->start + crandom () * 4 );
-
-
- if (p->type == P_BUBBLE_TURBULENT)
- {
- p->vel[0] = crandom() * 4;
- p->vel[1] = crandom() * 4;
- }
-
- }
- }
- else
- {
- if (org[2] < p->end)
- {
- p->time = cg.time;
- VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
-
- while (p->org[2] < p->end)
- {
- p->org[2] += (p->start - p->end);
- }
-
-
- if (p->type == P_WEATHER_TURBULENT)
- {
- p->vel[0] = crandom() * 16;
- p->vel[1] = crandom() * 16;
- }
-
- }
- }
-
-
- // Rafael snow pvs check
- if (!p->link)
- return;
-
- p->alpha = 1;
- }
-
- // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp
- if (Distance( cg.snap->ps.origin, org ) > 1024) {
- return;
- }
- // done.
-
- if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255 * p->alpha;
- }
- else
- {
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- VectorCopy( point, TRIverts[0].xyz );
- TRIverts[0].st[0] = 1;
- TRIverts[0].st[1] = 0;
- TRIverts[0].modulate[0] = 255;
- TRIverts[0].modulate[1] = 255;
- TRIverts[0].modulate[2] = 255;
- TRIverts[0].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- VectorCopy (point, TRIverts[1].xyz);
- TRIverts[1].st[0] = 0;
- TRIverts[1].st[1] = 0;
- TRIverts[1].modulate[0] = 255;
- TRIverts[1].modulate[1] = 255;
- TRIverts[1].modulate[2] = 255;
- TRIverts[1].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- VectorCopy (point, TRIverts[2].xyz);
- TRIverts[2].st[0] = 0;
- TRIverts[2].st[1] = 1;
- TRIverts[2].modulate[0] = 255;
- TRIverts[2].modulate[1] = 255;
- TRIverts[2].modulate[2] = 255;
- TRIverts[2].modulate[3] = 255 * p->alpha;
- }
-
- }
- else if (p->type == P_SPRITE)
- {
- vec3_t rr, ru;
- vec3_t rotate_ang;
-
- VectorSet (color, 1.0, 1.0, 0.5);
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (p->roll) {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
-
- if (p->roll) {
- VectorMA (org, -height, ru, point);
- VectorMA (point, -width, rr, point);
- } else {
- VectorMA (org, -height, pvup, point);
- VectorMA (point, -width, pvright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*height, ru, point);
- } else {
- VectorMA (point, 2*height, pvup, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*width, rr, point);
- } else {
- VectorMA (point, 2*width, pvright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, -2*height, ru, point);
- } else {
- VectorMA (point, -2*height, pvup, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
- }
- else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)
- {// create a front rotating facing polygon
-
- if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {
- return;
- }
-
- if (p->color == BLOODRED)
- VectorSet (color, 0.22f, 0.0f, 0.0f);
- else if (p->color == GREY75)
- {
- float len;
- float greyit;
- float val;
- len = Distance (cg.snap->ps.origin, org);
- if (!len)
- len = 1;
-
- val = 4096/len;
- greyit = 0.25 * val;
- if (greyit > 0.5)
- greyit = 0.5;
-
- VectorSet (color, greyit, greyit, greyit);
- }
- else
- VectorSet (color, 1.0, 1.0, 1.0);
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- if (cg.time > p->startfade)
- {
- invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );
-
- if (p->color == EMISIVEFADE)
- {
- float fval;
- fval = (invratio * invratio);
- if (fval < 0)
- fval = 0;
- VectorSet (color, fval , fval , fval );
- }
- invratio *= p->alpha;
- }
- else
- invratio = 1 * p->alpha;
-
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
- invratio = 1;
-
- if (invratio > 1)
- invratio = 1;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (p->type != P_SMOKE_IMPACT)
- {
- vec3_t temp;
-
- vectoangles (rforward, temp);
- p->accumroll += p->roll;
- temp[ROLL] += p->accumroll * 0.1;
- AngleVectors ( temp, NULL, rright2, rup2);
- }
- else
- {
- VectorCopy (rright, rright2);
- VectorCopy (rup, rup2);
- }
-
- if (p->rotate)
- {
- VectorMA (org, -height, rup2, point);
- VectorMA (point, -width, rright2, point);
- }
- else
- {
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255 * color[0];
- verts[0].modulate[1] = 255 * color[1];
- verts[0].modulate[2] = 255 * color[2];
- verts[0].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, -height, rup2, point);
- VectorMA (point, width, rright2, point);
- }
- else
- {
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255 * color[0];
- verts[1].modulate[1] = 255 * color[1];
- verts[1].modulate[2] = 255 * color[2];
- verts[1].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, height, rup2, point);
- VectorMA (point, width, rright2, point);
- }
- else
- {
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255 * color[0];
- verts[2].modulate[1] = 255 * color[1];
- verts[2].modulate[2] = 255 * color[2];
- verts[2].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, height, rup2, point);
- VectorMA (point, -width, rright2, point);
- }
- else
- {
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255 * color[0];
- verts[3].modulate[1] = 255 * color[1];
- verts[3].modulate[2] = 255 * color[2];
- verts[3].modulate[3] = 255 * invratio;
-
- }
- else if (p->type == P_BLEED)
- {
- vec3_t rr, ru;
- vec3_t rotate_ang;
- float alpha;
-
- alpha = p->alpha;
-
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
- alpha = 1;
-
- if (p->roll)
- {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
- else
- {
- VectorCopy (pvup, ru);
- VectorCopy (pvright, rr);
- }
-
- VectorMA (org, -p->height, ru, point);
- VectorMA (point, -p->width, rr, point);
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 111;
- verts[0].modulate[1] = 19;
- verts[0].modulate[2] = 9;
- verts[0].modulate[3] = 255 * alpha;
-
- VectorMA (org, -p->height, ru, point);
- VectorMA (point, p->width, rr, point);
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 111;
- verts[1].modulate[1] = 19;
- verts[1].modulate[2] = 9;
- verts[1].modulate[3] = 255 * alpha;
-
- VectorMA (org, p->height, ru, point);
- VectorMA (point, p->width, rr, point);
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 111;
- verts[2].modulate[1] = 19;
- verts[2].modulate[2] = 9;
- verts[2].modulate[3] = 255 * alpha;
-
- VectorMA (org, p->height, ru, point);
- VectorMA (point, -p->width, rr, point);
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 111;
- verts[3].modulate[1] = 19;
- verts[3].modulate[2] = 9;
- verts[3].modulate[3] = 255 * alpha;
-
- }
- else if (p->type == P_FLAT_SCALEUP)
- {
- float width, height;
- float sinR, cosR;
-
- if (p->color == BLOODRED)
- VectorSet (color, 1, 1, 1);
- else
- VectorSet (color, 0.5, 0.5, 0.5);
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (width > p->endwidth)
- width = p->endwidth;
-
- if (height > p->endheight)
- height = p->endheight;
-
- sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);
- cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);
-
- VectorCopy (org, verts[0].xyz);
- verts[0].xyz[0] -= sinR;
- verts[0].xyz[1] -= cosR;
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255 * color[0];
- verts[0].modulate[1] = 255 * color[1];
- verts[0].modulate[2] = 255 * color[2];
- verts[0].modulate[3] = 255;
-
- VectorCopy (org, verts[1].xyz);
- verts[1].xyz[0] -= cosR;
- verts[1].xyz[1] += sinR;
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255 * color[0];
- verts[1].modulate[1] = 255 * color[1];
- verts[1].modulate[2] = 255 * color[2];
- verts[1].modulate[3] = 255;
-
- VectorCopy (org, verts[2].xyz);
- verts[2].xyz[0] += sinR;
- verts[2].xyz[1] += cosR;
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255 * color[0];
- verts[2].modulate[1] = 255 * color[1];
- verts[2].modulate[2] = 255 * color[2];
- verts[2].modulate[3] = 255;
-
- VectorCopy (org, verts[3].xyz);
- verts[3].xyz[0] += cosR;
- verts[3].xyz[1] -= sinR;
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255 * color[0];
- verts[3].modulate[1] = 255 * color[1];
- verts[3].modulate[2] = 255 * color[2];
- verts[3].modulate[3] = 255;
- }
- else if (p->type == P_FLAT)
- {
-
- VectorCopy (org, verts[0].xyz);
- verts[0].xyz[0] -= p->height;
- verts[0].xyz[1] -= p->width;
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- VectorCopy (org, verts[1].xyz);
- verts[1].xyz[0] -= p->height;
- verts[1].xyz[1] += p->width;
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- VectorCopy (org, verts[2].xyz);
- verts[2].xyz[0] += p->height;
- verts[2].xyz[1] += p->width;
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- VectorCopy (org, verts[3].xyz);
- verts[3].xyz[0] += p->height;
- verts[3].xyz[1] -= p->width;
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
-
- }
- // Ridah
- else if (p->type == P_ANIM) {
- vec3_t rr, ru;
- vec3_t rotate_ang;
- int i, j;
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
- if (ratio >= 1.0f) {
- ratio = 0.9999f;
- }
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- // if we are "inside" this sprite, don't draw
- if (Distance( cg.snap->ps.origin, org ) < width/1.5) {
- return;
- }
-
- i = p->shaderAnim;
- j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);
- p->pshader = shaderAnims[i][j];
-
- if (p->roll) {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
-
- if (p->roll) {
- VectorMA (org, -height, ru, point);
- VectorMA (point, -width, rr, point);
- } else {
- VectorMA (org, -height, pvup, point);
- VectorMA (point, -width, pvright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*height, ru, point);
- } else {
- VectorMA (point, 2*height, pvup, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*width, rr, point);
- } else {
- VectorMA (point, 2*width, pvright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, -2*height, ru, point);
- } else {
- VectorMA (point, -2*height, pvup, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
- }
- // done.
-
- if (!p->pshader) {
-// (SA) temp commented out for DM
-// CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type);
- return;
- }
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)
- trap_R_AddPolyToScene( p->pshader, 3, TRIverts );
- else
- trap_R_AddPolyToScene( p->pshader, 4, verts );
-
-}
-
-// Ridah, made this static so it doesn't interfere with other files
-static float roll = 0.0;
-
-/*
-===============
-CG_AddParticles
-===============
-*/
-void CG_AddParticles (void)
-{
- cparticle_t *p, *next;
- float alpha;
- float time, time2;
- vec3_t org;
- int color;
- cparticle_t *active, *tail;
- int type;
- vec3_t rotate_ang;
-
- if (!initparticles)
- CG_ClearParticles ();
-
- VectorCopy( cg.refdef.viewaxis[0], pvforward );
- VectorCopy( cg.refdef.viewaxis[1], pvright );
- VectorCopy( cg.refdef.viewaxis[2], pvup );
-
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- roll += ((cg.time - oldtime) * 0.1) ;
- rotate_ang[ROLL] += (roll*0.9);
- AngleVectors ( rotate_ang, rforward, rright, rup);
-
- oldtime = cg.time;
-
- active = NULL;
- tail = NULL;
-
- for (p=active_particles ; p ; p=next)
- {
-
- next = p->next;
-
- time = (cg.time - p->time)*0.001;
-
- alpha = p->alpha + time*p->alphavel;
- if (alpha <= 0)
- { // faded out
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
-
- continue;
- }
-
- }
-
- if (p->type == P_WEATHER_FLURRY)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
-
- continue;
- }
- }
-
-
- if (p->type == P_FLAT_SCALEUP_FADE)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- }
-
- if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {
- // temporary sprite
- CG_AddParticleToScene (p, p->org, alpha);
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- p->next = NULL;
- if (!tail)
- active = tail = p;
- else
- {
- tail->next = p;
- tail = p;
- }
-
- if (alpha > 1.0)
- alpha = 1;
-
- color = p->color;
-
- time2 = time*time;
-
- org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
- org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
- org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
-
- type = p->type;
-
- CG_AddParticleToScene (p, org, alpha);
- }
-
- active_particles = active;
-}
-
-/*
-======================
-CG_AddParticles
-======================
-*/
-void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
- qboolean turb = qtrue;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.90f;
- p->alphavel = 0;
-
- p->start = cent->currentState.origin2[0];
- p->end = cent->currentState.origin2[1];
-
- p->endtime = cg.time + cent->currentState.time;
- p->startfade = cg.time + cent->currentState.time2;
-
- p->pshader = pshader;
-
- if (rand()%100 > 90)
- {
- p->height = 32;
- p->width = 32;
- p->alpha = 0.10f;
- }
- else
- {
- p->height = 1;
- p->width = 1;
- }
-
- p->vel[2] = -20;
-
- p->type = P_WEATHER_FLURRY;
-
- if (turb)
- p->vel[2] = -10;
-
- VectorCopy(cent->currentState.origin, p->org);
-
- p->org[0] = p->org[0];
- p->org[1] = p->org[1];
- p->org[2] = p->org[2];
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16);
- p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16);
- p->vel[2] += cent->currentState.angles[2];
-
- if (turb)
- {
- p->accel[0] = crandom () * 16;
- p->accel[1] = crandom () * 16;
- }
-
-}
-
-void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.40f;
- p->alphavel = 0;
- p->start = origin[2];
- p->end = origin2[2];
- p->pshader = pshader;
- p->height = 1;
- p->width = 1;
-
- p->vel[2] = -50;
-
- if (turb)
- {
- p->type = P_WEATHER_TURBULENT;
- p->vel[2] = -50 * 1.3;
- }
- else
- {
- p->type = P_WEATHER;
- }
-
- VectorCopy(origin, p->org);
-
- p->org[0] = p->org[0] + ( crandom() * range);
- p->org[1] = p->org[1] + ( crandom() * range);
- p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- if (turb)
- {
- p->vel[0] = crandom() * 16;
- p->vel[1] = crandom() * 16;
- }
-
- // Rafael snow pvs check
- p->snum = snum;
- p->link = qtrue;
-
-}
-
-void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
-{
- cparticle_t *p;
- float randsize;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.40f;
- p->alphavel = 0;
- p->start = origin[2];
- p->end = origin2[2];
- p->pshader = pshader;
-
- randsize = 1 + (crandom() * 0.5);
-
- p->height = randsize;
- p->width = randsize;
-
- p->vel[2] = 50 + ( crandom() * 10 );
-
- if (turb)
- {
- p->type = P_BUBBLE_TURBULENT;
- p->vel[2] = 50 * 1.3;
- }
- else
- {
- p->type = P_BUBBLE;
- }
-
- VectorCopy(origin, p->org);
-
- p->org[0] = p->org[0] + ( crandom() * range);
- p->org[1] = p->org[1] + ( crandom() * range);
- p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- if (turb)
- {
- p->vel[0] = crandom() * 4;
- p->vel[1] = crandom() * 4;
- }
-
- // Rafael snow pvs check
- p->snum = snum;
- p->link = qtrue;
-
-}
-
-void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent)
-{
-
- // using cent->density = enttime
- // cent->frame = startfade
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSmoke == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + cent->currentState.time;
- p->startfade = cg.time + cent->currentState.time2;
-
- p->color = 0;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->start = cent->currentState.origin[2];
- p->end = cent->currentState.origin2[2];
- p->pshader = pshader;
- p->rotate = qfalse;
- p->height = 8;
- p->width = 8;
- p->endheight = 32;
- p->endwidth = 32;
- p->type = P_SMOKE;
-
- VectorCopy(cent->currentState.origin, p->org);
-
- p->vel[0] = p->vel[1] = 0;
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[2] = 5;
-
- if (cent->currentState.frame == 1)// reverse gravity
- p->vel[2] *= -1;
-
- p->roll = 8 + (crandom() * 4);
-}
-
-
-void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration)
-{
-
- cparticle_t *p;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + duration;
- p->startfade = cg.time + duration/2;
-
- p->color = EMISIVEFADE;
- p->alpha = 1.0;
- p->alphavel = 0;
-
- p->height = 0.5;
- p->width = 0.5;
- p->endheight = 0.5;
- p->endwidth = 0.5;
-
- p->pshader = cgs.media.tracerShader;
-
- p->type = P_SMOKE;
-
- VectorCopy(org, p->org);
-
- p->vel[0] = vel[0];
- p->vel[1] = vel[1];
- p->vel[2] = vel[2];
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->accel[2] = -60;
- p->vel[2] += -20;
-
-}
-
-/*
-======================
-CG_ParticleExplosion
-======================
-*/
-
-void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd)
-{
- cparticle_t *p;
- int anim;
-
- if (animStr < (char *)10)
- CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" );
-
- // find the animation string
- for (anim=0; shaderAnimNames[anim]; anim++) {
- if (!Q_stricmp( animStr, shaderAnimNames[anim] ))
- break;
- }
- if (!shaderAnimNames[anim]) {
- CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr);
- return;
- }
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 0.5;
- p->alphavel = 0;
-
- if (duration < 0) {
- duration *= -1;
- p->roll = 0;
- } else {
- p->roll = crandom()*179;
- }
-
- p->shaderAnim = anim;
-
- p->width = sizeStart;
- p->height = sizeStart*shaderAnimSTRatio[anim]; // for sprites that are stretch in either direction
-
- p->endheight = sizeEnd;
- p->endwidth = sizeEnd*shaderAnimSTRatio[anim];
-
- p->endtime = cg.time + duration;
-
- p->type = P_ANIM;
-
- VectorCopy( origin, p->org );
- VectorCopy( vel, p->vel );
- VectorClear( p->accel );
-
-}
-
-// Rafael Shrapnel
-void CG_AddParticleShrapnel (localEntity_t *le)
-{
- return;
-}
-// done.
-
-int CG_NewParticleArea (int num)
-{
- // const char *str;
- char *str;
- char *token;
- int type;
- vec3_t origin, origin2;
- int i;
- float range = 0;
- int turb;
- int numparticles;
- int snum;
-
- str = (char *) CG_ConfigString (num);
- if (!str[0])
- return (0);
-
- // returns type 128 64 or 32
- token = COM_Parse (&str);
- type = atoi (token);
-
- if (type == 1)
- range = 128;
- else if (type == 2)
- range = 64;
- else if (type == 3)
- range = 32;
- else if (type == 0)
- range = 256;
- else if (type == 4)
- range = 8;
- else if (type == 5)
- range = 16;
- else if (type == 6)
- range = 32;
- else if (type == 7)
- range = 64;
-
-
- for (i=0; i<3; i++)
- {
- token = COM_Parse (&str);
- origin[i] = atof (token);
- }
-
- for (i=0; i<3; i++)
- {
- token = COM_Parse (&str);
- origin2[i] = atof (token);
- }
-
- token = COM_Parse (&str);
- numparticles = atoi (token);
-
- token = COM_Parse (&str);
- turb = atoi (token);
-
- token = COM_Parse (&str);
- snum = atoi (token);
-
- for (i=0; i<numparticles; i++)
- {
- if (type >= 4)
- CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
- else
- CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
- }
-
- return (1);
-}
-
-void CG_SnowLink (centity_t *cent, qboolean particleOn)
-{
- cparticle_t *p, *next;
- int id;
-
- id = cent->currentState.frame;
-
- for (p=active_particles ; p ; p=next)
- {
- next = p->next;
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT)
- {
- if (p->snum == id)
- {
- if (particleOn)
- p->link = qtrue;
- else
- p->link = qfalse;
- }
- }
-
- }
-}
-
-void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 0.25;
- p->alphavel = 0;
- p->roll = crandom()*179;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + 1000;
- p->startfade = cg.time + 100;
-
- p->width = rand()%4 + 8;
- p->height = rand()%4 + 8;
-
- p->endheight = p->height *2;
- p->endwidth = p->width * 2;
-
- p->endtime = cg.time + 500;
-
- p->type = P_SMOKE_IMPACT;
-
- VectorCopy( origin, p->org );
- VectorSet(p->vel, 0, 0, 20);
- VectorSet(p->accel, 0, 0, 20);
-
- p->rotate = qtrue;
-}
-
-void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + duration;
-
- if (fleshEntityNum)
- p->startfade = cg.time;
- else
- p->startfade = cg.time + 100;
-
- p->width = 4;
- p->height = 4;
-
- p->endheight = 4+rand()%3;
- p->endwidth = p->endheight;
-
- p->type = P_SMOKE;
-
- VectorCopy( start, p->org );
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = -20;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->color = BLOODRED;
- p->alpha = 0.75;
-
-}
-
-void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
-
- int time;
- int time2;
- float ratio;
-
- float duration = 1500;
-
- time = cg.time;
- time2 = cg.time + cent->currentState.time;
-
- ratio =(float)1 - ((float)time / (float)time2);
-
- if (!pshader)
- CG_Printf ("CG_Particle_OilParticle == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + duration;
-
- p->startfade = p->endtime;
-
- p->width = 1;
- p->height = 3;
-
- p->endheight = 3;
- p->endwidth = 1;
-
- p->type = P_SMOKE;
-
- VectorCopy(cent->currentState.origin, p->org );
-
- p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio));
- p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio));
- p->vel[2] = (cent->currentState.origin2[2]);
-
- p->snum = 1.0f;
-
- VectorClear( p->accel );
-
- p->accel[2] = -20;
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
-}
-
-
-void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_Particle_OilSlick == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- if (cent->currentState.angles2[2])
- p->endtime = cg.time + cent->currentState.angles2[2];
- else
- p->endtime = cg.time + 60000;
-
- p->startfade = p->endtime;
-
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- if (cent->currentState.angles2[0] || cent->currentState.angles2[1])
- {
- p->width = cent->currentState.angles2[0];
- p->height = cent->currentState.angles2[0];
-
- p->endheight = cent->currentState.angles2[1];
- p->endwidth = cent->currentState.angles2[1];
- }
- else
- {
- p->width = 8;
- p->height = 8;
-
- p->endheight = 16;
- p->endwidth = 16;
- }
-
- p->type = P_FLAT_SCALEUP;
-
- p->snum = 1.0;
-
- VectorCopy(cent->currentState.origin, p->org );
-
- p->org[2]+= 0.55 + (crandom() * 0.5);
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = 0;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
-}
-
-void CG_OilSlickRemove (centity_t *cent)
-{
- cparticle_t *p, *next;
- int id;
-
- id = 1.0f;
-
- if (!id)
- CG_Printf ("CG_OilSlickRevove NULL id\n");
-
- for (p=active_particles ; p ; p=next)
- {
- next = p->next;
-
- if (p->type == P_FLAT_SCALEUP)
- {
- if (p->snum == id)
- {
- p->endtime = cg.time + 100;
- p->startfade = p->endtime;
- p->type = P_FLAT_SCALEUP_FADE;
-
- }
- }
-
- }
-}
-
-qboolean ValidBloodPool (vec3_t start)
-{
-#define EXTRUDE_DIST 0.5
-
- vec3_t angles;
- vec3_t right, up;
- vec3_t this_pos, x_pos, center_pos, end_pos;
- float x, y;
- float fwidth, fheight;
- trace_t trace;
- vec3_t normal;
-
- fwidth = 16;
- fheight = 16;
-
- VectorSet (normal, 0, 0, 1);
-
- vectoangles (normal, angles);
- AngleVectors (angles, NULL, right, up);
-
- VectorMA (start, EXTRUDE_DIST, normal, center_pos);
-
- for (x= -fwidth/2; x<fwidth; x+= fwidth)
- {
- VectorMA (center_pos, x, right, x_pos);
-
- for (y= -fheight/2; y<fheight; y+= fheight)
- {
- VectorMA (x_pos, y, up, this_pos);
- VectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos);
-
- CG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID);
-
-
- if (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world
- return qfalse;
-
- if (!(!trace.startsolid && trace.fraction < 1))
- return qfalse;
-
- }
- }
-
- return qtrue;
-}
-
-void CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr)
-{
- cparticle_t *p;
- qboolean legit;
- vec3_t start;
- float rndSize;
-
- if (!pshader)
- CG_Printf ("CG_BloodPool pshader == ZERO!\n");
-
- if (!free_particles)
- return;
-
- VectorCopy (tr->endpos, start);
- legit = ValidBloodPool (start);
-
- if (!legit)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + 3000;
- p->startfade = p->endtime;
-
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- rndSize = 0.4 + random()*0.6;
-
- p->width = 8*rndSize;
- p->height = 8*rndSize;
-
- p->endheight = 16*rndSize;
- p->endwidth = 16*rndSize;
-
- p->type = P_FLAT_SCALEUP;
-
- VectorCopy(start, p->org );
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = 0;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
- p->color = BLOODRED;
-}
-
-#define NORMALSIZE 16
-#define LARGESIZE 32
-
-void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir)
-{
- float length;
- float dist;
- float crittersize;
- vec3_t angles, forward;
- vec3_t point;
- cparticle_t *p;
- int i;
-
- dist = 0;
-
- length = VectorLength (dir);
- vectoangles (dir, angles);
- AngleVectors (angles, forward, NULL, NULL);
-
- crittersize = LARGESIZE;
-
- if (length)
- dist = length / crittersize;
-
- if (dist < 1)
- dist = 1;
-
- VectorCopy (origin, point);
-
- for (i=0; i<dist; i++)
- {
- VectorMA (point, crittersize, forward, point);
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = cgs.media.smokePuffShader;
-
- p->endtime = cg.time + 350 + (crandom() * 100);
-
- p->startfade = cg.time;
-
- p->width = LARGESIZE;
- p->height = LARGESIZE;
- p->endheight = LARGESIZE;
- p->endwidth = LARGESIZE;
-
- p->type = P_SMOKE;
-
- VectorCopy( origin, p->org );
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = -1;
-
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->color = BLOODRED;
-
- p->alpha = 0.75;
-
- }
-
-
-}
-
-void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
-{
- cparticle_t *p;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + duration;
- p->startfade = cg.time + duration/2;
-
- p->color = EMISIVEFADE;
- p->alpha = 0.4f;
- p->alphavel = 0;
-
- p->height = 0.5;
- p->width = 0.5;
- p->endheight = 0.5;
- p->endwidth = 0.5;
-
- p->pshader = cgs.media.tracerShader;
-
- p->type = P_SMOKE;
-
- VectorCopy(org, p->org);
-
- p->org[0] += (crandom() * x);
- p->org[1] += (crandom() * y);
-
- p->vel[0] = vel[0];
- p->vel[1] = vel[1];
- p->vel[2] = vel[2];
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[0] += (crandom() * 4);
- p->vel[1] += (crandom() * 4);
- p->vel[2] += (20 + (crandom() * 10)) * speed;
-
- p->accel[0] = crandom () * 4;
- p->accel[1] = crandom () * 4;
-
-}
-
-void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir)
-{
- float length;
- float dist;
- float crittersize;
- vec3_t angles, forward;
- vec3_t point;
- cparticle_t *p;
- int i;
-
- dist = 0;
-
- VectorNegate (dir, dir);
- length = VectorLength (dir);
- vectoangles (dir, angles);
- AngleVectors (angles, forward, NULL, NULL);
-
- crittersize = LARGESIZE;
-
- if (length)
- dist = length / crittersize;
-
- if (dist < 1)
- dist = 1;
-
- VectorCopy (origin, point);
-
- for (i=0; i<dist; i++)
- {
- VectorMA (point, crittersize, forward, point);
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cg.time;
- p->alpha = 5.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = cgs.media.smokePuffShader;
-
- // RF, stay around for long enough to expand and dissipate naturally
- if (length)
- p->endtime = cg.time + 4500 + (crandom() * 3500);
- else
- p->endtime = cg.time + 750 + (crandom() * 500);
-
- p->startfade = cg.time;
-
- p->width = LARGESIZE;
- p->height = LARGESIZE;
-
- // RF, expand while falling
- p->endheight = LARGESIZE*3.0;
- p->endwidth = LARGESIZE*3.0;
-
- if (!length)
- {
- p->width *= 0.2f;
- p->height *= 0.2f;
-
- p->endheight = NORMALSIZE;
- p->endwidth = NORMALSIZE;
- }
-
- p->type = P_SMOKE;
-
- VectorCopy( point, p->org );
-
- p->vel[0] = crandom()*6;
- p->vel[1] = crandom()*6;
- p->vel[2] = random()*20;
-
- // RF, add some gravity/randomness
- p->accel[0] = crandom()*3;
- p->accel[1] = crandom()*3;
- p->accel[2] = -PARTICLE_GRAVITY*0.4;
-
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
- }
-
-
-}
-
-void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = rand()%179;
-
- p->pshader = pshader;
-
- if (duration > 0)
- p->endtime = cg.time + duration;
- else
- p->endtime = duration;
-
- p->startfade = cg.time;
-
- p->width = size;
- p->height = size;
-
- p->endheight = size;
- p->endwidth = size;
-
- p->type = P_SPRITE;
-
- VectorCopy( origin, p->org );
-
- p->rotate = qfalse;
-}
-
-
-
-
-
-// LEILEI ENHANCEMENT PARTICLE EFFECTS
-
-
-// sparks!
-// for small arms
-
-void CG_LeiSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
-{
- cparticle_t *p;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + duration;
- p->startfade = cg.time + duration/2;
-
- p->color = EMISIVEFADE;
- p->alpha = 0.8f;
- p->alphavel = 0.8f;
-
- p->height = 4;
- p->width = 4;
- p->endheight = 4;
- p->endwidth = 4;
-
- p->pshader = cgs.media.lspkShader1;
-
- p->type = P_SMOKE;
-
- VectorCopy(org, p->org);
-
- p->org[0] += (crandom() * x);
- p->org[1] += (crandom() * y);
-
- p->vel[0] = vel[0] * 35;
- p->vel[1] = vel[1] * 35;
- p->vel[2] = vel[2] * 85;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[0] += (crandom() * 44);
- p->vel[1] += (crandom() * 44);
- p->vel[2] += (75 + (crandom() * 190)) * speed;
-
- // p->vel[0] += (crandom() * 24);
- //p->vel[1] += (crandom() * 24);
- //p->vel[2] += (20 + (crandom() * 180)) * speed;
-
- p->accel[0] = crandom()*6;
- p->accel[1] = crandom()*6;
- p->accel[2] = -PARTICLE_GRAVITY*7.2;
-
-}
-
-// for explosions
-
-void CG_LeiSparks2 (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
-{
- cparticle_t *p;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + duration;
- p->startfade = cg.time + duration/2;
-
- p->color = EMISIVEFADE;
- p->alpha = 0.8f;
- p->alphavel = 0;
-
- p->height = 9;
- p->width = 9;
- p->endheight = 16;
- p->endwidth = 16;
-
- p->pshader = cgs.media.lspkShader1;
-
- p->type = P_SMOKE;
-
- VectorCopy(org, p->org);
-
- p->org[0] += (crandom() * x);
- p->org[1] += (crandom() * y);
-
- p->vel[0] = vel[0] * 35;
- p->vel[1] = vel[1] * 35;
- p->vel[2] = vel[2] * 85;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[0] += (crandom() * 524);
- p->vel[1] += (crandom() * 524);
- p->vel[2] += (120 + (crandom() * 780)) * speed;
-
- p->accel[0] = crandom()*76;
- p->accel[1] = crandom()*76;
- p->accel[2] = crandom()*76;
-
-
-}
-
-// not so friendly water splash
-void CG_LeiSplash2 (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
-{
- cparticle_t *p;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + duration;
- p->startfade = cg.time + duration/2;
-
- p->color = EMISIVEFADE;
- p->alpha = 0.9f;
- p->alphavel = 0;
-
- p->height = 4;
- p->width = 4;
- p->endheight = 2;
- p->endwidth = 2;
-
- p->pshader = cgs.media.lsplShader;
-
- p->type = P_SMOKE;
-
- VectorCopy(org, p->org);
-
- p->org[0] += (crandom() * x);
- p->org[1] += (crandom() * y);
-
- p->vel[0] = vel[0] * 44;
- p->vel[1] = vel[1] * 44;
- p->vel[2] = vel[2] * 872;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[0] += (crandom() * 4);
- p->vel[1] += (crandom() * 4);
- p->vel[2] += (20 + (crandom() * 10)) * speed;
-
- p->accel[0] = crandom()*3;
- p->accel[1] = crandom()*3;
- p->accel[2] = -PARTICLE_GRAVITY*4.2;
-
-}
-
diff --git a/game/code/cgame/cg_players.c b/game/code/cgame/cg_players.c
deleted file mode 100644
index 3a99a76..0000000
--- a/game/code/cgame/cg_players.c
+++ /dev/null
@@ -1,2604 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_players.c -- handle the media and animation for player entities
-#include "cg_local.h"
-
-char *cg_customSoundNames[MAX_CUSTOM_SOUNDS] = {
- "*death1.wav",
- "*death2.wav",
- "*death3.wav",
- "*jump1.wav",
- "*pain25_1.wav",
- "*pain50_1.wav",
- "*pain75_1.wav",
- "*pain100_1.wav",
- "*falling1.wav",
- "*gasp.wav",
- "*drown.wav",
- "*fall1.wav",
- "*taunt.wav"
-};
-
-
-/*
-================
-CG_CustomSound
-
-================
-*/
-sfxHandle_t CG_CustomSound( int clientNum, const char *soundName ) {
- clientInfo_t *ci;
- int i;
-
- if ( soundName[0] != '*' ) {
- return trap_S_RegisterSound( soundName, qfalse );
- }
-
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- clientNum = 0;
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- for ( i = 0 ; i < MAX_CUSTOM_SOUNDS && cg_customSoundNames[i] ; i++ ) {
- if ( !strcmp( soundName, cg_customSoundNames[i] ) ) {
- return ci->sounds[i];
- }
- }
-
- CG_Error( "Unknown custom sound: %s", soundName );
- return 0;
-}
-
-
-
-/*
-=============================================================================
-
-CLIENT INFO
-
-=============================================================================
-*/
-
-/*
-======================
-CG_ParseAnimationFile
-
-Read a configuration file containing animation coutns and rates
-models/players/visor/animation.cfg, etc
-======================
-*/
-static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) {
- char *text_p, *prev;
- int len;
- int i;
- char *token;
- float fps;
- int skip;
- char text[20000];
- fileHandle_t f;
- animation_t *animations;
-
- animations = ci->animations;
-
- // load the file
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( len <= 0 ) {
- return qfalse;
- }
- if ( len >= sizeof( text ) - 1 ) {
- CG_Printf( "File %s too long\n", filename );
- trap_FS_FCloseFile( f );
- return qfalse;
- }
- trap_FS_Read( text, len, f );
- text[len] = 0;
- trap_FS_FCloseFile( f );
-
- // parse the text
- text_p = text;
- skip = 0; // quite the compiler warning
-
- ci->footsteps = FOOTSTEP_NORMAL;
- VectorClear( ci->headOffset );
- ci->gender = GENDER_MALE;
- ci->fixedlegs = qfalse;
- ci->fixedtorso = qfalse;
-
- // read optional parameters
- while ( 1 ) {
- prev = text_p; // so we can unget
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( !Q_stricmp( token, "footsteps" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( !Q_stricmp( token, "default" ) || !Q_stricmp( token, "normal" ) ) {
- ci->footsteps = FOOTSTEP_NORMAL;
- } else if ( !Q_stricmp( token, "boot" ) ) {
- ci->footsteps = FOOTSTEP_BOOT;
- } else if ( !Q_stricmp( token, "flesh" ) ) {
- ci->footsteps = FOOTSTEP_FLESH;
- } else if ( !Q_stricmp( token, "mech" ) ) {
- ci->footsteps = FOOTSTEP_MECH;
- } else if ( !Q_stricmp( token, "energy" ) ) {
- ci->footsteps = FOOTSTEP_ENERGY;
- } else {
- CG_Printf( "Bad footsteps parm in %s: %s\n", filename, token );
- }
- continue;
- } else if ( !Q_stricmp( token, "headoffset" ) ) {
- for ( i = 0 ; i < 3 ; i++ ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- ci->headOffset[i] = atof( token );
- }
- continue;
- } else if ( !Q_stricmp( token, "sex" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( token[0] == 'f' || token[0] == 'F' ) {
- ci->gender = GENDER_FEMALE;
- } else if ( token[0] == 'n' || token[0] == 'N' ) {
- ci->gender = GENDER_NEUTER;
- } else {
- ci->gender = GENDER_MALE;
- }
- continue;
- } else if ( !Q_stricmp( token, "fixedlegs" ) ) {
- ci->fixedlegs = qtrue;
- continue;
- } else if ( !Q_stricmp( token, "fixedtorso" ) ) {
- ci->fixedtorso = qtrue;
- continue;
- }
-
- // if it is a number, start parsing animations
- if ( token[0] >= '0' && token[0] <= '9' ) {
- text_p = prev; // unget the token
- break;
- }
- Com_Printf( "unknown token '%s' is %s\n", token, filename );
- }
-
- // read information for each frame
- for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
-
- token = COM_Parse( &text_p );
- if ( !*token ) {
- if( i >= TORSO_GETFLAG && i <= TORSO_NEGATIVE ) {
- animations[i].firstFrame = animations[TORSO_GESTURE].firstFrame;
- animations[i].frameLerp = animations[TORSO_GESTURE].frameLerp;
- animations[i].initialLerp = animations[TORSO_GESTURE].initialLerp;
- animations[i].loopFrames = animations[TORSO_GESTURE].loopFrames;
- animations[i].numFrames = animations[TORSO_GESTURE].numFrames;
- animations[i].reversed = qfalse;
- animations[i].flipflop = qfalse;
- continue;
- }
- break;
- }
- animations[i].firstFrame = atoi( token );
- // leg only frames are adjusted to not count the upper body only frames
- if ( i == LEGS_WALKCR ) {
- skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
- }
- if ( i >= LEGS_WALKCR && i<TORSO_GETFLAG) {
- animations[i].firstFrame -= skip;
- }
-
- token = COM_Parse( &text_p );
- if ( !*token ) {
- break;
- }
- animations[i].numFrames = atoi( token );
-
- animations[i].reversed = qfalse;
- animations[i].flipflop = qfalse;
- // if numFrames is negative the animation is reversed
- if (animations[i].numFrames < 0) {
- animations[i].numFrames = -animations[i].numFrames;
- animations[i].reversed = qtrue;
- }
-
- token = COM_Parse( &text_p );
- if ( !*token ) {
- break;
- }
- animations[i].loopFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !*token ) {
- break;
- }
- fps = atof( token );
- if ( fps == 0 ) {
- fps = 1;
- }
- animations[i].frameLerp = 1000 / fps;
- animations[i].initialLerp = 1000 / fps;
- }
-
- if ( i != MAX_ANIMATIONS ) {
- CG_Printf( "Error parsing animation file: %s", filename );
- return qfalse;
- }
-
- // crouch backward animation
- memcpy(&animations[LEGS_BACKCR], &animations[LEGS_WALKCR], sizeof(animation_t));
- animations[LEGS_BACKCR].reversed = qtrue;
- // walk backward animation
- memcpy(&animations[LEGS_BACKWALK], &animations[LEGS_WALK], sizeof(animation_t));
- animations[LEGS_BACKWALK].reversed = qtrue;
- // flag moving fast
- animations[FLAG_RUN].firstFrame = 0;
- animations[FLAG_RUN].numFrames = 16;
- animations[FLAG_RUN].loopFrames = 16;
- animations[FLAG_RUN].frameLerp = 1000 / 15;
- animations[FLAG_RUN].initialLerp = 1000 / 15;
- animations[FLAG_RUN].reversed = qfalse;
- // flag not moving or moving slowly
- animations[FLAG_STAND].firstFrame = 16;
- animations[FLAG_STAND].numFrames = 5;
- animations[FLAG_STAND].loopFrames = 0;
- animations[FLAG_STAND].frameLerp = 1000 / 20;
- animations[FLAG_STAND].initialLerp = 1000 / 20;
- animations[FLAG_STAND].reversed = qfalse;
- // flag speeding up
- animations[FLAG_STAND2RUN].firstFrame = 16;
- animations[FLAG_STAND2RUN].numFrames = 5;
- animations[FLAG_STAND2RUN].loopFrames = 1;
- animations[FLAG_STAND2RUN].frameLerp = 1000 / 15;
- animations[FLAG_STAND2RUN].initialLerp = 1000 / 15;
- animations[FLAG_STAND2RUN].reversed = qtrue;
- //
- // new anims changes
- //
-// animations[TORSO_GETFLAG].flipflop = qtrue;
-// animations[TORSO_GUARDBASE].flipflop = qtrue;
-// animations[TORSO_PATROL].flipflop = qtrue;
-// animations[TORSO_AFFIRMATIVE].flipflop = qtrue;
-// animations[TORSO_NEGATIVE].flipflop = qtrue;
- //
- return qtrue;
-}
-
-/*
-==========================
-CG_FileExists
-==========================
-*/
-static qboolean CG_FileExists(const char *filename) {
- int len;
-
- len = trap_FS_FOpenFile( filename, NULL, FS_READ );
- if (len>0) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==========================
-CG_FindClientModelFile
-==========================
-*/
-static qboolean CG_FindClientModelFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *base, const char *ext ) {
- char *team, *charactersFolder;
- int i;
-
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- switch ( ci->team ) {
- case TEAM_BLUE: {
- team = "blue";
- break;
- }
- default: {
- team = "red";
- break;
- }
- }
- }
- else {
- team = "default";
- }
- charactersFolder = "";
- while(1) {
- for ( i = 0; i < 2; i++ ) {
- if ( i == 0 && teamName && *teamName ) {
- // "models/players/characters/sergei/stroggs/lower_lily_red.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, team, ext );
- }
- else {
- // "models/players/characters/sergei/lower_lily_red.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s_%s.%s", charactersFolder, modelName, base, skinName, team, ext );
- }
- if ( CG_FileExists( filename ) ) {
- return qtrue;
- }
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- if ( i == 0 && teamName && *teamName ) {
- // "models/players/characters/sergei/stroggs/lower_red.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, team, ext );
- }
- else {
- // "models/players/characters/sergei/lower_red.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, team, ext );
- }
- }
- else {
- if ( i == 0 && teamName && *teamName ) {
- // "models/players/characters/sergei/stroggs/lower_lily.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, ext );
- }
- else {
- // "models/players/characters/sergei/lower_lily.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, skinName, ext );
- }
- }
- if ( CG_FileExists( filename ) ) {
- return qtrue;
- }
- if ( !teamName || !*teamName ) {
- break;
- }
- }
- // if tried the heads folder first
- if ( charactersFolder[0] ) {
- break;
- }
- charactersFolder = "characters/";
- }
-
- return qfalse;
-}
-
-/*
-==========================
-CG_FindClientHeadFile
-==========================
-*/
-static qboolean CG_FindClientHeadFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) {
- char *team, *headsFolder;
- int i;
-
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- switch ( ci->team ) {
- case TEAM_BLUE: {
- team = "blue";
- break;
- }
- default: {
- team = "red";
- break;
- }
- }
- }
- else {
- team = "default";
- }
-
- if ( headModelName[0] == '*' ) {
- headsFolder = "heads/";
- headModelName++;
- }
- else {
- headsFolder = "";
- }
- while(1) {
- for ( i = 0; i < 2; i++ ) {
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s/%s%s_%s.%s", headsFolder, headModelName, headSkinName, teamName, base, team, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s/%s_%s.%s", headsFolder, headModelName, headSkinName, base, team, ext );
- }
- if ( CG_FileExists( filename ) ) {
- return qtrue;
- }
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, team, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, team, ext );
- }
- }
- else {
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, headSkinName, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, headSkinName, ext );
- }
- }
- if ( CG_FileExists( filename ) ) {
- return qtrue;
- }
- if ( !teamName || !*teamName ) {
- break;
- }
- }
- // if tried the heads folder first
- if ( headsFolder[0] ) {
- break;
- }
- headsFolder = "heads/";
- }
-
- return qfalse;
-}
-
-/*
-==========================
-CG_RegisterClientSkin
-==========================
-*/
-static qboolean CG_RegisterClientSkin( clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName ) {
- char filename[MAX_QPATH];
-
- /*
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/%slower_%s.skin", modelName, teamName, skinName );
- ci->legsSkin = trap_R_RegisterSkin( filename );
- if (!ci->legsSkin) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%slower_%s.skin", modelName, teamName, skinName );
- ci->legsSkin = trap_R_RegisterSkin( filename );
- if (!ci->legsSkin) {
- Com_Printf( "Leg skin load failure: %s\n", filename );
- }
- }
-
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/%supper_%s.skin", modelName, teamName, skinName );
- ci->torsoSkin = trap_R_RegisterSkin( filename );
- if (!ci->torsoSkin) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%supper_%s.skin", modelName, teamName, skinName );
- ci->torsoSkin = trap_R_RegisterSkin( filename );
- if (!ci->torsoSkin) {
- Com_Printf( "Torso skin load failure: %s\n", filename );
- }
- }
- */
- if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "lower", "skin" ) ) {
- ci->legsSkin = trap_R_RegisterSkin( filename );
- }
- if (!ci->legsSkin) {
- Com_Printf( "Leg skin load failure: %s\n", filename );
- }
-
- if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "upper", "skin" ) ) {
- ci->torsoSkin = trap_R_RegisterSkin( filename );
- }
- if (!ci->torsoSkin) {
- Com_Printf( "Torso skin load failure: %s\n", filename );
- }
-
- if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headModelName, headSkinName, "head", "skin" ) ) {
- ci->headSkin = trap_R_RegisterSkin( filename );
- }
- if (!ci->headSkin) {
- Com_Printf( "Head skin load failure: %s\n", filename );
- }
-
- // if any skins failed to load
- if ( !ci->legsSkin || !ci->torsoSkin || !ci->headSkin ) {
- return qfalse;
- }
- return qtrue;
-}
-
-/*
-==========================
-CG_RegisterClientModelname
-==========================
-*/
-static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName, const char *teamName ) {
- char filename[MAX_QPATH*2];
- const char *headName;
- char newTeamName[MAX_QPATH*2];
-
- if ( headModelName[0] == '\0' ) {
- headName = modelName;
- }
- else {
- headName = headModelName;
- }
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
- ci->legsModel = trap_R_RegisterModel( filename );
- if ( !ci->legsModel ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower.md3", modelName );
- ci->legsModel = trap_R_RegisterModel( filename );
- if ( !ci->legsModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
- }
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
- ci->torsoModel = trap_R_RegisterModel( filename );
- if ( !ci->torsoModel ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper.md3", modelName );
- ci->torsoModel = trap_R_RegisterModel( filename );
- if ( !ci->torsoModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
- }
-
- if( headName[0] == '*' ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", &headModelName[1], &headModelName[1] );
- }
- else {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headName );
- }
- ci->headModel = trap_R_RegisterModel( filename );
- // if the head model could not be found and we didn't load from the heads folder try to load from there
- if ( !ci->headModel && headName[0] != '*' ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", headModelName, headModelName );
- ci->headModel = trap_R_RegisterModel( filename );
- }
- if ( !ci->headModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
-
- // if any skins failed to load, return failure
- if ( !CG_RegisterClientSkin( ci, teamName, modelName, skinName, headName, headSkinName ) ) {
- if ( teamName && *teamName) {
- Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", teamName, modelName, skinName, headName, headSkinName );
- if( ci->team == TEAM_BLUE ) {
- Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_BLUETEAM_NAME);
- }
- else {
- Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_REDTEAM_NAME);
- }
- if ( !CG_RegisterClientSkin( ci, newTeamName, modelName, skinName, headName, headSkinName ) ) {
- Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", newTeamName, modelName, skinName, headName, headSkinName );
- return qfalse;
- }
- } else {
- Com_Printf( "Failed to load skin file: %s : %s, %s : %s\n", modelName, skinName, headName, headSkinName );
- return qfalse;
- }
- }
-
- // load the animations
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
- if ( !CG_ParseAnimationFile( filename, ci ) ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName );
- if ( !CG_ParseAnimationFile( filename, ci ) ) {
- Com_Printf( "Failed to load animation file %s\n", filename );
- return qfalse;
- }
- }
-
- if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "skin" ) ) {
- ci->modelIcon = trap_R_RegisterShaderNoMip( filename );
- }
- else if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "tga" ) ) {
- ci->modelIcon = trap_R_RegisterShaderNoMip( filename );
- }
-
- if ( !ci->modelIcon ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-====================
-CG_ColorFromString
-====================
-*/
-static void CG_ColorFromString( const char *v, vec3_t color ) {
- int val;
-
- VectorClear( color );
-
- val = atoi( v );
-
- if ( val < 1 || val > 7 ) {
- VectorSet( color, 1, 1, 1 );
- return;
- }
-
- if ( val & 1 ) {
- color[2] = 1.0f;
- }
- if ( val & 2 ) {
- color[1] = 1.0f;
- }
- if ( val & 4 ) {
- color[0] = 1.0f;
- }
-}
-
-/*
-===================
-CG_LoadClientInfo
-
-Load it now, taking the disk hits.
-This will usually be deferred to a safe time
-===================
-*/
-static void CG_LoadClientInfo( int clientNum, clientInfo_t *ci ) {
- const char *dir, *fallback;
- int i, modelloaded;
- const char *s;
- char teamname[MAX_QPATH];
-
- teamname[0] = 0;
-#ifdef MISSIONPACK
- if( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- if( ci->team == TEAM_BLUE ) {
- Q_strncpyz(teamname, cg_blueTeamName.string, sizeof(teamname) );
- } else {
- Q_strncpyz(teamname, cg_redTeamName.string, sizeof(teamname) );
- }
- }
- if( teamname[0] ) {
- strcat( teamname, "/" );
- }
-#endif
- modelloaded = qtrue;
- if ( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname ) ) {
- if ( cg_buildScript.integer ) {
- CG_Error( "CG_RegisterClientModelname( %s, %s, %s, %s %s ) failed", ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname );
- }
-
- // fall back to default team name
- if( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- // keep skin name
- if( ci->team == TEAM_BLUE ) {
- Q_strncpyz(teamname, DEFAULT_BLUETEAM_NAME, sizeof(teamname) );
- } else {
- Q_strncpyz(teamname, DEFAULT_REDTEAM_NAME, sizeof(teamname) );
- }
- if ( !CG_RegisterClientModelname( ci, DEFAULT_TEAM_MODEL, ci->skinName, DEFAULT_TEAM_HEAD, ci->skinName, teamname ) ) {
- CG_Error( "DEFAULT_TEAM_MODEL / skin (%s/%s) failed to register", DEFAULT_TEAM_MODEL, ci->skinName );
- }
- } else {
- if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default", DEFAULT_MODEL, "default", teamname ) ) {
- CG_Error( "DEFAULT_MODEL (%s) failed to register", DEFAULT_MODEL );
- }
- }
- modelloaded = qfalse;
- }
-
- ci->newAnims = qfalse;
- if ( ci->torsoModel ) {
- orientation_t tag;
- // if the torso model has the "tag_flag"
- if ( trap_R_LerpTag( &tag, ci->torsoModel, 0, 0, 1, "tag_flag" ) ) {
- ci->newAnims = qtrue;
- }
- }
-
- // sounds
- dir = ci->modelName;
- fallback = (cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) ? DEFAULT_TEAM_MODEL : DEFAULT_MODEL;
-
- for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i++ ) {
- s = cg_customSoundNames[i];
- if ( !s ) {
- break;
- }
- ci->sounds[i] = 0;
- // if the model didn't load use the sounds of the default model
- if (modelloaded) {
- ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", dir, s + 1), qfalse );
- }
- if ( !ci->sounds[i] ) {
- ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", fallback, s + 1), qfalse );
- }
- }
-
- ci->deferred = qfalse;
-
- // reset any existing players and bodies, because they might be in bad
- // frames for this new model
- for ( i = 0 ; i < MAX_GENTITIES ; i++ ) {
- if ( cg_entities[i].currentState.clientNum == clientNum
- && cg_entities[i].currentState.eType == ET_PLAYER ) {
- CG_ResetPlayerEntity( &cg_entities[i] );
- }
- }
-}
-
-/*
-======================
-CG_CopyClientInfoModel
-======================
-*/
-static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to ) {
- VectorCopy( from->headOffset, to->headOffset );
- to->footsteps = from->footsteps;
- to->gender = from->gender;
-
- to->legsModel = from->legsModel;
- to->legsSkin = from->legsSkin;
- to->torsoModel = from->torsoModel;
- to->torsoSkin = from->torsoSkin;
- to->headModel = from->headModel;
- to->headSkin = from->headSkin;
- to->modelIcon = from->modelIcon;
-
- to->newAnims = from->newAnims;
-
- memcpy( to->animations, from->animations, sizeof( to->animations ) );
- memcpy( to->sounds, from->sounds, sizeof( to->sounds ) );
-}
-
-/*
-======================
-CG_ScanForExistingClientInfo
-======================
-*/
-static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci ) {
- int i;
- clientInfo_t *match;
-
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- match = &cgs.clientinfo[ i ];
- if ( !match->infoValid ) {
- continue;
- }
- if ( match->deferred ) {
- continue;
- }
- if ( !Q_stricmp( ci->modelName, match->modelName )
- && !Q_stricmp( ci->skinName, match->skinName )
- && !Q_stricmp( ci->headModelName, match->headModelName )
- && !Q_stricmp( ci->headSkinName, match->headSkinName )
- && !Q_stricmp( ci->blueTeam, match->blueTeam )
- && !Q_stricmp( ci->redTeam, match->redTeam )
- && (cgs.gametype < GT_TEAM || cgs.ffa_gt==1 || ci->team == match->team) ) {
- // this clientinfo is identical, so use it's handles
-
- ci->deferred = qfalse;
-
- CG_CopyClientInfoModel( match, ci );
-
- return qtrue;
- }
- }
-
- // nothing matches, so defer the load
- return qfalse;
-}
-
-/*
-======================
-CG_SetDeferredClientInfo
-
-We aren't going to load it now, so grab some other
-client's info to use until we have some spare time.
-======================
-*/
-static void CG_SetDeferredClientInfo( int clientNum, clientInfo_t *ci ) {
- int i;
- clientInfo_t *match;
-
- // if someone else is already the same models and skins we
- // can just load the client info
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- match = &cgs.clientinfo[ i ];
- if ( !match->infoValid || match->deferred ) {
- continue;
- }
- if ( Q_stricmp( ci->skinName, match->skinName ) ||
- Q_stricmp( ci->modelName, match->modelName ) ||
-// Q_stricmp( ci->headModelName, match->headModelName ) ||
-// Q_stricmp( ci->headSkinName, match->headSkinName ) ||
- (cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1 && ci->team != match->team) ) {
- continue;
- }
- // just load the real info cause it uses the same models and skins
- CG_LoadClientInfo( clientNum, ci );
- return;
- }
-
- // if we are in teamplay, only grab a model if the skin is correct
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- match = &cgs.clientinfo[ i ];
- if ( !match->infoValid || match->deferred ) {
- continue;
- }
- if ( Q_stricmp( ci->skinName, match->skinName ) ||
- (cgs.gametype >= GT_TEAM && cgs.ffa_gt != 1 && ci->team != match->team) ) {
- continue;
- }
- ci->deferred = qtrue;
- CG_CopyClientInfoModel( match, ci );
- return;
- }
- // load the full model, because we don't ever want to show
- // an improper team skin. This will cause a hitch for the first
- // player, when the second enters. Combat shouldn't be going on
- // yet, so it shouldn't matter
- CG_LoadClientInfo( clientNum, ci );
- return;
- }
-
- // find the first valid clientinfo and grab its stuff
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- match = &cgs.clientinfo[ i ];
- if ( !match->infoValid ) {
- continue;
- }
-
- ci->deferred = qtrue;
- CG_CopyClientInfoModel( match, ci );
- return;
- }
-
- // we should never get here...
- CG_Printf( "CG_SetDeferredClientInfo: no valid clients!\n" );
-
- CG_LoadClientInfo( clientNum, ci );
-}
-
-
-/*
-======================
-CG_NewClientInfo
-======================
-*/
-void CG_NewClientInfo( int clientNum ) {
- clientInfo_t *ci;
- clientInfo_t newInfo;
- const char *configstring;
- const char *v;
- char *slash;
-
- ci = &cgs.clientinfo[clientNum];
-
- configstring = CG_ConfigString( clientNum + CS_PLAYERS );
- if ( !configstring[0] ) {
- memset( ci, 0, sizeof( *ci ) );
- return; // player just left
- }
-
- // build into a temp buffer so the defer checks can use
- // the old value
- memset( &newInfo, 0, sizeof( newInfo ) );
-
- // isolate the player's name
- v = Info_ValueForKey(configstring, "n");
- Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) );
-
- // colors
- v = Info_ValueForKey( configstring, "c1" );
- CG_ColorFromString( v, newInfo.color1 );
-
- v = Info_ValueForKey( configstring, "c2" );
- CG_ColorFromString( v, newInfo.color2 );
-
- // bot skill
- v = Info_ValueForKey( configstring, "skill" );
- newInfo.botSkill = atoi( v );
-
- // handicap
- v = Info_ValueForKey( configstring, "hc" );
- newInfo.handicap = atoi( v );
-
- // wins
- v = Info_ValueForKey( configstring, "w" );
- newInfo.wins = atoi( v );
-
- // losses
- v = Info_ValueForKey( configstring, "l" );
- newInfo.losses = atoi( v );
-
- // team
- v = Info_ValueForKey( configstring, "t" );
- newInfo.team = atoi( v );
-
- // team task
- v = Info_ValueForKey( configstring, "tt" );
- newInfo.teamTask = atoi(v);
-
- // team leader
- v = Info_ValueForKey( configstring, "tl" );
- newInfo.teamLeader = atoi(v);
-
- v = Info_ValueForKey( configstring, "g_redteam" );
- Q_strncpyz(newInfo.redTeam, v, MAX_TEAMNAME);
-
- v = Info_ValueForKey( configstring, "g_blueteam" );
- Q_strncpyz(newInfo.blueTeam, v, MAX_TEAMNAME);
-
- // model
- v = Info_ValueForKey( configstring, "model" );
- if ( cg_forceModel.integer ) {
- // forcemodel makes everyone use a single model
- // to prevent load hitches
- char modelStr[MAX_QPATH];
- char *skin;
-
- if( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- Q_strncpyz( newInfo.modelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.modelName ) );
- Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
- } else {
- trap_Cvar_VariableStringBuffer( "model", modelStr, sizeof( modelStr ) );
- if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
- skin = "default";
- } else {
- *skin++ = 0;
- }
-
- Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) );
- Q_strncpyz( newInfo.modelName, modelStr, sizeof( newInfo.modelName ) );
- }
-
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1 ) {
- // keep skin name
- slash = strchr( v, '/' );
- if ( slash ) {
- Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
- }
- }
- } else {
- Q_strncpyz( newInfo.modelName, v, sizeof( newInfo.modelName ) );
-
- slash = strchr( newInfo.modelName, '/' );
- if ( !slash ) {
- // modelName didn not include a skin name
- Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
- } else {
- Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
- // truncate modelName
- *slash = 0;
- }
- }
-
- // head model
- v = Info_ValueForKey( configstring, "hmodel" );
- if ( cg_forceModel.integer ) {
- // forcemodel makes everyone use a single model
- // to prevent load hitches
- char modelStr[MAX_QPATH];
- char *skin;
-
- if( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- Q_strncpyz( newInfo.headModelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.headModelName ) );
- Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) );
- } else {
- trap_Cvar_VariableStringBuffer( "headmodel", modelStr, sizeof( modelStr ) );
- if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
- skin = "default";
- } else {
- *skin++ = 0;
- }
-
- Q_strncpyz( newInfo.headSkinName, skin, sizeof( newInfo.headSkinName ) );
- Q_strncpyz( newInfo.headModelName, modelStr, sizeof( newInfo.headModelName ) );
- }
-
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- // keep skin name
- slash = strchr( v, '/' );
- if ( slash ) {
- Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) );
- }
- }
- } else {
- Q_strncpyz( newInfo.headModelName, v, sizeof( newInfo.headModelName ) );
-
- slash = strchr( newInfo.headModelName, '/' );
- if ( !slash ) {
- // modelName didn not include a skin name
- Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) );
- } else {
- Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) );
- // truncate modelName
- *slash = 0;
- }
- }
-
- // scan for an existing clientinfo that matches this modelname
- // so we can avoid loading checks if possible
- if ( !CG_ScanForExistingClientInfo( &newInfo ) ) {
- qboolean forceDefer;
-
- forceDefer = trap_MemoryRemaining() < 4000000;
-
- // if we are defering loads, just have it pick the first valid
- if ( forceDefer || (cg_deferPlayers.integer && !cg_buildScript.integer && !cg.loading ) ) {
- // keep whatever they had if it won't violate team skins
- CG_SetDeferredClientInfo( clientNum, &newInfo );
- // if we are low on memory, leave them with this model
- if ( forceDefer ) {
- CG_Printf( "Memory is low. Using deferred model.\n" );
- newInfo.deferred = qfalse;
- }
- } else {
- CG_LoadClientInfo( clientNum, &newInfo );
- }
- }
-
- // replace whatever was there with the new one
- newInfo.infoValid = qtrue;
- *ci = newInfo;
-}
-
-
-
-/*
-======================
-CG_LoadDeferredPlayers
-
-Called each frame when a player is dead
-and the scoreboard is up
-so deferred players can be loaded
-======================
-*/
-void CG_LoadDeferredPlayers( void ) {
- int i;
- clientInfo_t *ci;
-
- // scan for a deferred player to load
- for ( i = 0, ci = cgs.clientinfo ; i < cgs.maxclients ; i++, ci++ ) {
- if ( ci->infoValid && ci->deferred ) {
- // if we are low on memory, leave it deferred
- if ( trap_MemoryRemaining() < 4000000 ) {
- CG_Printf( "Memory is low. Using deferred model.\n" );
- ci->deferred = qfalse;
- continue;
- }
- CG_LoadClientInfo( i, ci );
-// break;
- }
- }
-}
-
-/*
-=============================================================================
-
-PLAYER ANIMATION
-
-=============================================================================
-*/
-
-
-/*
-===============
-CG_SetLerpFrameAnimation
-
-may include ANIM_TOGGLEBIT
-===============
-*/
-static void CG_SetLerpFrameAnimation( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
- animation_t *anim;
-
- lf->animationNumber = newAnimation;
- newAnimation &= ~ANIM_TOGGLEBIT;
-
- if ( newAnimation < 0 || newAnimation >= MAX_TOTALANIMATIONS ) {
- CG_Error( "Bad animation number: %i", newAnimation );
- }
-
- anim = &ci->animations[ newAnimation ];
-
- lf->animation = anim;
- lf->animationTime = lf->frameTime + anim->initialLerp;
-
- if ( cg_debugAnim.integer ) {
- CG_Printf( "Anim: %i\n", newAnimation );
- }
-}
-
-/*
-===============
-CG_RunLerpFrame
-
-Sets cg.snap, cg.oldFrame, and cg.backlerp
-cg.time should be between oldFrameTime and frameTime after exit
-===============
-*/
-static void CG_RunLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation, float speedScale ) {
- int f, numFrames;
- animation_t *anim;
-
- // debugging tool to get no animations
- if ( cg_animSpeed.integer == 0 ) {
- lf->oldFrame = lf->frame = lf->backlerp = 0;
- return;
- }
-
- // see if the animation sequence is switching
- if ( newAnimation != lf->animationNumber || !lf->animation ) {
- CG_SetLerpFrameAnimation( ci, lf, newAnimation );
- }
-
- // if we have passed the current frame, move it to
- // oldFrame and calculate a new frame
- if ( cg.time >= lf->frameTime ) {
- lf->oldFrame = lf->frame;
- lf->oldFrameTime = lf->frameTime;
-
- // get the next frame based on the animation
- anim = lf->animation;
- if ( !anim->frameLerp ) {
- return; // shouldn't happen
- }
- if ( cg.time < lf->animationTime ) {
- lf->frameTime = lf->animationTime; // initial lerp
- } else {
- lf->frameTime = lf->oldFrameTime + anim->frameLerp;
- }
- f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
- f *= speedScale; // adjust for haste, etc
-
- numFrames = anim->numFrames;
- if (anim->flipflop) {
- numFrames *= 2;
- }
- if ( f >= numFrames ) {
- f -= numFrames;
- if ( anim->loopFrames ) {
- f %= anim->loopFrames;
- f += anim->numFrames - anim->loopFrames;
- } else {
- f = numFrames - 1;
- // the animation is stuck at the end, so it
- // can immediately transition to another sequence
- lf->frameTime = cg.time;
- }
- }
- if ( anim->reversed ) {
- lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
- }
- else if (anim->flipflop && f>=anim->numFrames) {
- lf->frame = anim->firstFrame + anim->numFrames - 1 - (f%anim->numFrames);
- }
- else {
- lf->frame = anim->firstFrame + f;
- }
- if ( cg.time > lf->frameTime ) {
- lf->frameTime = cg.time;
- if ( cg_debugAnim.integer ) {
- CG_Printf( "Clamp lf->frameTime\n");
- }
- }
- }
-
- if ( lf->frameTime > cg.time + 200 ) {
- lf->frameTime = cg.time;
- }
-
- if ( lf->oldFrameTime > cg.time ) {
- lf->oldFrameTime = cg.time;
- }
- // calculate current lerp value
- if ( lf->frameTime == lf->oldFrameTime ) {
- lf->backlerp = 0;
- } else {
- lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
- }
-}
-
-
-/*
-===============
-CG_ClearLerpFrame
-===============
-*/
-static void CG_ClearLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int animationNumber ) {
- lf->frameTime = lf->oldFrameTime = cg.time;
- CG_SetLerpFrameAnimation( ci, lf, animationNumber );
- lf->oldFrame = lf->frame = lf->animation->firstFrame;
-}
-
-
-/*
-===============
-CG_PlayerAnimation
-===============
-*/
-static void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float *legsBackLerp,
- int *torsoOld, int *torso, float *torsoBackLerp ) {
- clientInfo_t *ci;
- int clientNum;
- float speedScale;
-
- clientNum = cent->currentState.clientNum;
-
- if ( cg_noPlayerAnims.integer ) {
- *legsOld = *legs = *torsoOld = *torso = 0;
- return;
- }
-
- if ( cent->currentState.powerups & ( 1 << PW_HASTE ) ) {
- speedScale = 1.5;
- } else {
- speedScale = 1;
- }
-
- ci = &cgs.clientinfo[ clientNum ];
-
- // do the shuffle turn frames locally
- if ( cent->pe.legs.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {
- CG_RunLerpFrame( ci, ¢->pe.legs, LEGS_TURN, speedScale );
- } else {
- CG_RunLerpFrame( ci, ¢->pe.legs, cent->currentState.legsAnim, speedScale );
- }
-
- *legsOld = cent->pe.legs.oldFrame;
- *legs = cent->pe.legs.frame;
- *legsBackLerp = cent->pe.legs.backlerp;
-
- CG_RunLerpFrame( ci, ¢->pe.torso, cent->currentState.torsoAnim, speedScale );
-
- *torsoOld = cent->pe.torso.oldFrame;
- *torso = cent->pe.torso.frame;
- *torsoBackLerp = cent->pe.torso.backlerp;
-}
-
-/*
-=============================================================================
-
-PLAYER ANGLES
-
-=============================================================================
-*/
-
-/*
-==================
-CG_SwingAngles
-==================
-*/
-static void CG_SwingAngles( float destination, float swingTolerance, float clampTolerance,
- float speed, float *angle, qboolean *swinging ) {
- float swing;
- float move;
- float scale;
-
- if ( !*swinging ) {
- // see if a swing should be started
- swing = AngleSubtract( *angle, destination );
- if ( swing > swingTolerance || swing < -swingTolerance ) {
- *swinging = qtrue;
- }
- }
-
- if ( !*swinging ) {
- return;
- }
-
- // modify the speed depending on the delta
- // so it doesn't seem so linear
- swing = AngleSubtract( destination, *angle );
- scale = fabs( swing );
- if ( scale < swingTolerance * 0.5 ) {
- scale = 0.5;
- } else if ( scale < swingTolerance ) {
- scale = 1.0;
- } else {
- scale = 2.0;
- }
-
- // swing towards the destination angle
- if ( swing >= 0 ) {
- move = cg.frametime * scale * speed;
- if ( move >= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- } else if ( swing < 0 ) {
- move = cg.frametime * scale * -speed;
- if ( move <= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- }
-
- // clamp to no more than tolerance
- swing = AngleSubtract( destination, *angle );
- if ( swing > clampTolerance ) {
- *angle = AngleMod( destination - (clampTolerance - 1) );
- } else if ( swing < -clampTolerance ) {
- *angle = AngleMod( destination + (clampTolerance - 1) );
- }
-}
-
-/*
-=================
-CG_AddPainTwitch
-=================
-*/
-static void CG_AddPainTwitch( centity_t *cent, vec3_t torsoAngles ) {
- int t;
- float f;
-
- t = cg.time - cent->pe.painTime;
- if ( t >= PAIN_TWITCH_TIME ) {
- return;
- }
-
- f = 1.0 - (float)t / PAIN_TWITCH_TIME;
-
- if ( cent->pe.painDirection ) {
- torsoAngles[ROLL] += 20 * f;
- } else {
- torsoAngles[ROLL] -= 20 * f;
- }
-}
-
-
-/*
-===============
-CG_PlayerAngles
-
-Handles seperate torso motion
-
- legs pivot based on direction of movement
-
- head always looks exactly at cent->lerpAngles
-
- if motion < 20 degrees, show in head only
- if < 45 degrees, also show in torso
-===============
-*/
-static void CG_PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {
- vec3_t legsAngles, torsoAngles, headAngles;
- float dest;
- static int movementOffsets[8] = { 0, 22, 45, -22, 0, 22, -45, -22 };
- vec3_t velocity;
- float speed;
- int dir, clientNum;
- clientInfo_t *ci;
-
- VectorCopy( cent->lerpAngles, headAngles );
- headAngles[YAW] = AngleMod( headAngles[YAW] );
- VectorClear( legsAngles );
- VectorClear( torsoAngles );
-
- // --------- yaw -------------
-
- // allow yaw to drift a bit
- if ( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE
- || ( cent->currentState.torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) {
- // if not standing still, always point all in the same direction
- cent->pe.torso.yawing = qtrue; // always center
- cent->pe.torso.pitching = qtrue; // always center
- cent->pe.legs.yawing = qtrue; // always center
- }
-
- // adjust legs for movement dir
- if ( cent->currentState.eFlags & EF_DEAD ) {
- // don't let dead bodies twitch
- dir = 0;
- } else {
- dir = cent->currentState.angles2[YAW];
- if ( dir < 0 || dir > 7 ) {
- CG_Error( "Bad player movement angle" );
- }
- }
- legsAngles[YAW] = headAngles[YAW] + movementOffsets[ dir ];
- torsoAngles[YAW] = headAngles[YAW] + 0.25 * movementOffsets[ dir ];
-
- // torso
- CG_SwingAngles( torsoAngles[YAW], 25, 90, cg_swingSpeed.value, ¢->pe.torso.yawAngle, ¢->pe.torso.yawing );
- CG_SwingAngles( legsAngles[YAW], 40, 90, cg_swingSpeed.value, ¢->pe.legs.yawAngle, ¢->pe.legs.yawing );
-
- torsoAngles[YAW] = cent->pe.torso.yawAngle;
- legsAngles[YAW] = cent->pe.legs.yawAngle;
-
-
- // --------- pitch -------------
-
- // only show a fraction of the pitch angle in the torso
- if ( headAngles[PITCH] > 180 ) {
- dest = (-360 + headAngles[PITCH]) * 0.75f;
- } else {
- dest = headAngles[PITCH] * 0.75f;
- }
- CG_SwingAngles( dest, 15, 30, 0.1f, ¢->pe.torso.pitchAngle, ¢->pe.torso.pitching );
- torsoAngles[PITCH] = cent->pe.torso.pitchAngle;
-
- //
- clientNum = cent->currentState.clientNum;
- if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
- ci = &cgs.clientinfo[ clientNum ];
- if ( ci->fixedtorso ) {
- torsoAngles[PITCH] = 0.0f;
- }
- }
-
- // --------- roll -------------
-
-
- // lean towards the direction of travel
- VectorCopy( cent->currentState.pos.trDelta, velocity );
- speed = VectorNormalize( velocity );
- if ( speed ) {
- vec3_t axis[3];
- float side;
-
- speed *= 0.05f;
-
- AnglesToAxis( legsAngles, axis );
- side = speed * DotProduct( velocity, axis[1] );
- legsAngles[ROLL] -= side;
-
- side = speed * DotProduct( velocity, axis[0] );
- legsAngles[PITCH] += side;
- }
-
- //
- clientNum = cent->currentState.clientNum;
- if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
- ci = &cgs.clientinfo[ clientNum ];
- if ( ci->fixedlegs ) {
- legsAngles[YAW] = torsoAngles[YAW];
- legsAngles[PITCH] = 0.0f;
- legsAngles[ROLL] = 0.0f;
- }
- }
-
- // pain twitch
- CG_AddPainTwitch( cent, torsoAngles );
-
- // pull the angles back out of the hierarchial chain
- AnglesSubtract( headAngles, torsoAngles, headAngles );
- AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
- AnglesToAxis( legsAngles, legs );
- AnglesToAxis( torsoAngles, torso );
- AnglesToAxis( headAngles, head );
-}
-
-
-//==========================================================================
-
-/*
-===============
-CG_HasteTrail
-===============
-*/
-static void CG_HasteTrail( centity_t *cent ) {
- localEntity_t *smoke;
- vec3_t origin;
- int anim;
-
- if ( cent->trailTime > cg.time ) {
- return;
- }
- anim = cent->pe.legs.animationNumber & ~ANIM_TOGGLEBIT;
- if ( anim != LEGS_RUN && anim != LEGS_BACK ) {
- return;
- }
-
- cent->trailTime += 100;
- if ( cent->trailTime < cg.time ) {
- cent->trailTime = cg.time;
- }
-
- VectorCopy( cent->lerpOrigin, origin );
- origin[2] -= 16;
-
- smoke = CG_SmokePuff( origin, vec3_origin,
- 8,
- 1, 1, 1, 1,
- 500,
- cg.time,
- 0,
- 0,
- cgs.media.hastePuffShader );
-
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
-}
-
-/*
-===============
-CG_BreathPuffs
-===============
-*/
-static void CG_BreathPuffs( centity_t *cent, refEntity_t *head) {
- clientInfo_t *ci;
- vec3_t up, origin;
- int contents;
-
- ci = &cgs.clientinfo[ cent->currentState.number ];
-
- if (!cg_enableBreath.integer) {
- return;
- }
- if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson) {
- return;
- }
- if ( cent->currentState.eFlags & EF_DEAD ) {
- return;
- }
- contents = trap_CM_PointContents( head->origin, 0 );
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- return;
- }
- if ( ci->breathPuffTime > cg.time ) {
- return;
- }
-
- VectorSet( up, 0, 0, 8 );
- VectorMA(head->origin, 8, head->axis[0], origin);
- VectorMA(origin, -4, head->axis[2], origin);
- CG_SmokePuff( origin, up, 16, 1, 1, 1, 0.66f, 1500, cg.time, cg.time + 400, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
- ci->breathPuffTime = cg.time + 2000;
-}
-
-/*
-===============
-CG_DustTrail
-===============
-*/
-static void CG_DustTrail( centity_t *cent ) {
- int anim;
- localEntity_t *dust;
- vec3_t end, vel;
- trace_t tr;
-
- if (!cg_enableDust.integer)
- return;
-
- if ( cent->dustTrailTime > cg.time ) {
- return;
- }
-
- anim = cent->pe.legs.animationNumber & ~ANIM_TOGGLEBIT;
- if ( anim != LEGS_LANDB && anim != LEGS_LAND ) {
- return;
- }
-
- cent->dustTrailTime += 40;
- if ( cent->dustTrailTime < cg.time ) {
- cent->dustTrailTime = cg.time;
- }
-
- VectorCopy(cent->currentState.pos.trBase, end);
- end[2] -= 64;
- CG_Trace( &tr, cent->currentState.pos.trBase, NULL, NULL, end, cent->currentState.number, MASK_PLAYERSOLID );
-
- if ( !(tr.surfaceFlags & SURF_DUST) )
- return;
-
- VectorCopy( cent->currentState.pos.trBase, end );
- end[2] -= 16;
-
- VectorSet(vel, 0, 0, -30);
- dust = CG_SmokePuff( end, vel,
- 24,
- .8f, .8f, 0.7f, 0.33f,
- 500,
- cg.time,
- 0,
- 0,
- cgs.media.dustPuffShader );
-}
-
-/*
-===============
-CG_TrailItem
-===============
-*/
-static void CG_TrailItem( centity_t *cent, qhandle_t hModel ) {
- refEntity_t ent;
- vec3_t angles;
- vec3_t axis[3];
-
- VectorCopy( cent->lerpAngles, angles );
- angles[PITCH] = 0;
- angles[ROLL] = 0;
- AnglesToAxis( angles, axis );
-
- memset( &ent, 0, sizeof( ent ) );
- VectorMA( cent->lerpOrigin, -16, axis[0], ent.origin );
- ent.origin[2] += 16;
- angles[YAW] += 90;
- AnglesToAxis( angles, ent.axis );
-
- ent.hModel = hModel;
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-/*
-===============
-CG_PlayerFlag
-===============
-*/
-static void CG_PlayerFlag( centity_t *cent, qhandle_t hSkin, refEntity_t *torso ) {
- clientInfo_t *ci;
- refEntity_t pole;
- refEntity_t flag;
- vec3_t angles, dir;
- int legsAnim, flagAnim, updateangles;
- float angle, d;
-
- // show the flag pole model
- memset( &pole, 0, sizeof(pole) );
- pole.hModel = cgs.media.flagPoleModel;
- VectorCopy( torso->lightingOrigin, pole.lightingOrigin );
- pole.shadowPlane = torso->shadowPlane;
- pole.renderfx = torso->renderfx;
- CG_PositionEntityOnTag( &pole, torso, torso->hModel, "tag_flag" );
- trap_R_AddRefEntityToScene( &pole );
-
- // show the flag model
- memset( &flag, 0, sizeof(flag) );
- flag.hModel = cgs.media.flagFlapModel;
- flag.customSkin = hSkin;
- VectorCopy( torso->lightingOrigin, flag.lightingOrigin );
- flag.shadowPlane = torso->shadowPlane;
- flag.renderfx = torso->renderfx;
-
- VectorClear(angles);
-
- updateangles = qfalse;
- legsAnim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
- if( legsAnim == LEGS_IDLE || legsAnim == LEGS_IDLECR ) {
- flagAnim = FLAG_STAND;
- } else if ( legsAnim == LEGS_WALK || legsAnim == LEGS_WALKCR ) {
- flagAnim = FLAG_STAND;
- updateangles = qtrue;
- } else {
- flagAnim = FLAG_RUN;
- updateangles = qtrue;
- }
-
- if ( updateangles ) {
-
- VectorCopy( cent->currentState.pos.trDelta, dir );
- // add gravity
- dir[2] += 100;
- VectorNormalize( dir );
- d = DotProduct(pole.axis[2], dir);
- // if there is anough movement orthogonal to the flag pole
- if (fabs(d) < 0.9) {
- //
- d = DotProduct(pole.axis[0], dir);
- if (d > 1.0f) {
- d = 1.0f;
- }
- else if (d < -1.0f) {
- d = -1.0f;
- }
- angle = acos(d);
-
- d = DotProduct(pole.axis[1], dir);
- if (d < 0) {
- angles[YAW] = 360 - angle * 180 / M_PI;
- }
- else {
- angles[YAW] = angle * 180 / M_PI;
- }
- if (angles[YAW] < 0)
- angles[YAW] += 360;
- if (angles[YAW] > 360)
- angles[YAW] -= 360;
-
- //vectoangles( cent->currentState.pos.trDelta, tmpangles );
- //angles[YAW] = tmpangles[YAW] + 45 - cent->pe.torso.yawAngle;
- // change the yaw angle
- CG_SwingAngles( angles[YAW], 25, 90, 0.15f, ¢->pe.flag.yawAngle, ¢->pe.flag.yawing );
- }
-
- /*
- d = DotProduct(pole.axis[2], dir);
- angle = Q_acos(d);
-
- d = DotProduct(pole.axis[1], dir);
- if (d < 0) {
- angle = 360 - angle * 180 / M_PI;
- }
- else {
- angle = angle * 180 / M_PI;
- }
- if (angle > 340 && angle < 20) {
- flagAnim = FLAG_RUNUP;
- }
- if (angle > 160 && angle < 200) {
- flagAnim = FLAG_RUNDOWN;
- }
- */
- }
-
- // set the yaw angle
- angles[YAW] = cent->pe.flag.yawAngle;
- // lerp the flag animation frames
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- CG_RunLerpFrame( ci, ¢->pe.flag, flagAnim, 1 );
- flag.oldframe = cent->pe.flag.oldFrame;
- flag.frame = cent->pe.flag.frame;
- flag.backlerp = cent->pe.flag.backlerp;
-
- AnglesToAxis( angles, flag.axis );
- CG_PositionRotatedEntityOnTag( &flag, &pole, pole.hModel, "tag_flag" );
-
- trap_R_AddRefEntityToScene( &flag );
-}
-
-/*
-===============
-CG_PlayerTokens
-===============
-*/
-static void CG_PlayerTokens( centity_t *cent, int renderfx ) {
- int tokens, i, j;
- float angle;
- refEntity_t ent;
- vec3_t dir, origin;
- skulltrail_t *trail;
- trail = &cg.skulltrails[cent->currentState.number];
- tokens = cent->currentState.generic1;
- if ( !tokens ) {
- trail->numpositions = 0;
- return;
- }
-
- if ( tokens > MAX_SKULLTRAIL ) {
- tokens = MAX_SKULLTRAIL;
- }
-
- // add skulls if there are more than last time
- for (i = 0; i < tokens - trail->numpositions; i++) {
- for (j = trail->numpositions; j > 0; j--) {
- VectorCopy(trail->positions[j-1], trail->positions[j]);
- }
- VectorCopy(cent->lerpOrigin, trail->positions[0]);
- }
- trail->numpositions = tokens;
-
- // move all the skulls along the trail
- VectorCopy(cent->lerpOrigin, origin);
- for (i = 0; i < trail->numpositions; i++) {
- VectorSubtract(trail->positions[i], origin, dir);
- if (VectorNormalize(dir) > 30) {
- VectorMA(origin, 30, dir, trail->positions[i]);
- }
- VectorCopy(trail->positions[i], origin);
- }
-
- memset( &ent, 0, sizeof( ent ) );
- if( cgs.clientinfo[ cent->currentState.clientNum ].team == TEAM_BLUE ) {
- ent.hModel = cgs.media.redCubeModel;
- } else {
- ent.hModel = cgs.media.blueCubeModel;
- }
- ent.renderfx = renderfx;
-
- VectorCopy(cent->lerpOrigin, origin);
- for (i = 0; i < trail->numpositions; i++) {
- VectorSubtract(origin, trail->positions[i], ent.axis[0]);
- ent.axis[0][2] = 0;
- VectorNormalize(ent.axis[0]);
- VectorSet(ent.axis[2], 0, 0, 1);
- CrossProduct(ent.axis[0], ent.axis[2], ent.axis[1]);
-
- VectorCopy(trail->positions[i], ent.origin);
- angle = (((cg.time + 500 * MAX_SKULLTRAIL - 500 * i) / 16) & 255) * (M_PI * 2) / 255;
- ent.origin[2] += sin(angle) * 10;
- trap_R_AddRefEntityToScene( &ent );
- VectorCopy(trail->positions[i], origin);
- }
-}
-
-
-/*
-===============
-CG_PlayerPowerups
-===============
-*/
-static void CG_PlayerPowerups( centity_t *cent, refEntity_t *torso ) {
- int powerups;
- clientInfo_t *ci;
-
- powerups = cent->currentState.powerups;
- if ( !powerups ) {
- return;
- }
-
- // quad gives a dlight
- if ( powerups & ( 1 << PW_QUAD ) ) {
- trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1 );
- }
-
- // flight plays a looped sound
- if ( powerups & ( 1 << PW_FLIGHT ) ) {
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.flightSound );
- }
-
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- // redflag
- if ( powerups & ( 1 << PW_REDFLAG ) ) {
- if (ci->newAnims) {
- CG_PlayerFlag( cent, cgs.media.redFlagFlapSkin, torso );
- }
- else {
- CG_TrailItem( cent, cgs.media.redFlagModel );
- }
- trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 0.2f, 0.2f );
- }
-
- // blueflag
- if ( powerups & ( 1 << PW_BLUEFLAG ) ) {
- if (ci->newAnims){
- CG_PlayerFlag( cent, cgs.media.blueFlagFlapSkin, torso );
- }
- else {
- CG_TrailItem( cent, cgs.media.blueFlagModel );
- }
- trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1.0 );
- }
-
- // neutralflag
- if ( powerups & ( 1 << PW_NEUTRALFLAG ) ) {
- if (ci->newAnims) {
- CG_PlayerFlag( cent, cgs.media.neutralFlagFlapSkin, torso );
- }
- else {
- CG_TrailItem( cent, cgs.media.neutralFlagModel );
- }
- trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 1.0, 1.0 );
- }
-
- // haste leaves smoke trails
- if ( powerups & ( 1 << PW_HASTE ) ) {
- CG_HasteTrail( cent );
- }
-}
-
-
-/*
-===============
-CG_PlayerFloatSprite
-
-Float a sprite over the player's head
-===============
-*/
-static void CG_PlayerFloatSprite( centity_t *cent, qhandle_t shader ) {
- int rf;
- refEntity_t ent;
-
- if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) {
- rf = RF_THIRD_PERSON; // only show in mirrors
- } else {
- rf = 0;
- }
-
- memset( &ent, 0, sizeof( ent ) );
- VectorCopy( cent->lerpOrigin, ent.origin );
- ent.origin[2] += 48;
- ent.reType = RT_SPRITE;
- ent.customShader = shader;
- ent.radius = 10;
- ent.renderfx = rf;
- ent.shaderRGBA[0] = 255;
- ent.shaderRGBA[1] = 255;
- ent.shaderRGBA[2] = 255;
- ent.shaderRGBA[3] = 255;
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-
-/*
-===============
-CG_PlayerSprites
-
-Float sprites over the player's head
-===============
-*/
-static void CG_PlayerSprites( centity_t *cent ) {
- int team;
-
- if ( cent->currentState.eFlags & EF_CONNECTION ) {
- CG_PlayerFloatSprite( cent, cgs.media.connectionShader );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_TALK ) {
- CG_PlayerFloatSprite( cent, cgs.media.balloonShader );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_IMPRESSIVE ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalImpressive );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_EXCELLENT ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalExcellent );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_GAUNTLET ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalGauntlet );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_DEFEND ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalDefend );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_ASSIST ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalAssist );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_CAP ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalCapture );
- return;
- }
-
- team = cgs.clientinfo[ cent->currentState.clientNum ].team;
- if ( !(cent->currentState.eFlags & EF_DEAD) &&
- cg.snap->ps.persistant[PERS_TEAM] == team &&
- cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- if (cg_drawFriend.integer) {
- CG_PlayerFloatSprite( cent, cgs.media.friendShader );
- }
- return;
- }
-}
-
-/*
-===============
-CG_PlayerShadow
-
-Returns the Z component of the surface being shadowed
-
- should it return a full plane instead of a Z?
-===============
-*/
-#define SHADOW_DISTANCE 128
-static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane ) {
- vec3_t end, mins = {-15, -15, 0}, maxs = {15, 15, 2};
- trace_t trace;
- float alpha;
-
- *shadowPlane = 0;
-
- if ( cg_shadows.integer == 0 ) {
- return qfalse;
- }
-
- // no shadows when invisible
- if ( cent->currentState.powerups & ( 1 << PW_INVIS ) ) {
- return qfalse;
- }
-
- // send a trace down from the player to the ground
- VectorCopy( cent->lerpOrigin, end );
- end[2] -= SHADOW_DISTANCE;
-
- trap_CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID );
-
- // no shadow if too high
- if ( trace.fraction == 1.0 || trace.startsolid || trace.allsolid ) {
- return qfalse;
- }
-
- *shadowPlane = trace.endpos[2] + 1;
-
- if ( cg_shadows.integer != 1 ) { // no mark for stencil or projection shadows
- return qtrue;
- }
-
- // fade the shadow out with height
- alpha = 1.0 - trace.fraction;
-
- // bk0101022 - hack / FPE - bogus planes?
- //assert( DotProduct( trace.plane.normal, trace.plane.normal ) != 0.0f )
-
- // add the mark as a temporary, so it goes directly to the renderer
- // without taking a spot in the cg_marks array
- CG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal,
- cent->pe.legs.yawAngle, alpha,alpha,alpha,1, qfalse, 24, qtrue );
-
- return qtrue;
-}
-
-
-/*
-===============
-CG_PlayerSplash
-
-Draw a mark at the water surface
-===============
-*/
-static void CG_PlayerSplash( centity_t *cent ) {
- vec3_t start, end;
- trace_t trace;
- int contents;
- polyVert_t verts[4];
-
- if ( !cg_shadows.integer ) {
- return;
- }
-
- VectorCopy( cent->lerpOrigin, end );
- end[2] -= 24;
-
- // if the feet aren't in liquid, don't make a mark
- // this won't handle moving water brushes, but they wouldn't draw right anyway...
- contents = trap_CM_PointContents( end, 0 );
- if ( !( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) ) {
- return;
- }
-
- VectorCopy( cent->lerpOrigin, start );
- start[2] += 32;
-
- // if the head isn't out of liquid, don't make a mark
- contents = trap_CM_PointContents( start, 0 );
- if ( contents & ( CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- return;
- }
-
- // trace down to find the surface
- trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) );
-
- if ( trace.fraction == 1.0 ) {
- return;
- }
-
- // create a mark polygon
- VectorCopy( trace.endpos, verts[0].xyz );
- verts[0].xyz[0] -= 32;
- verts[0].xyz[1] -= 32;
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- VectorCopy( trace.endpos, verts[1].xyz );
- verts[1].xyz[0] -= 32;
- verts[1].xyz[1] += 32;
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- VectorCopy( trace.endpos, verts[2].xyz );
- verts[2].xyz[0] += 32;
- verts[2].xyz[1] += 32;
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- VectorCopy( trace.endpos, verts[3].xyz );
- verts[3].xyz[0] += 32;
- verts[3].xyz[1] -= 32;
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
-
- trap_R_AddPolyToScene( cgs.media.wakeMarkShader, 4, verts );
-}
-
-
-
-/*
-===============
-CG_AddRefEntityWithPowerups
-
-Adds a piece with modifications or duplications for powerups
-Also called by CG_Missile for quad rockets, but nobody can tell...
-===============
-*/
-void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team ) {
-
- if ( state->powerups & ( 1 << PW_INVIS ) ) {
- ent->customShader = cgs.media.invisShader;
- trap_R_AddRefEntityToScene( ent );
- } else {
- /*
- if ( state->eFlags & EF_KAMIKAZE ) {
- if (team == TEAM_BLUE)
- ent->customShader = cgs.media.blueKamikazeShader;
- else
- ent->customShader = cgs.media.redKamikazeShader;
- trap_R_AddRefEntityToScene( ent );
- }
- else {*/
- trap_R_AddRefEntityToScene( ent );
- //}
-
- if ( state->powerups & ( 1 << PW_QUAD ) )
- {
- if (team == TEAM_RED)
- ent->customShader = cgs.media.redQuadShader;
- else
- ent->customShader = cgs.media.quadShader;
- trap_R_AddRefEntityToScene( ent );
- }
- if ( state->powerups & ( 1 << PW_REGEN ) ) {
- if ( ( ( cg.time / 100 ) % 10 ) == 1 ) {
- ent->customShader = cgs.media.regenShader;
- trap_R_AddRefEntityToScene( ent );
- }
- }
- if ( state->powerups & ( 1 << PW_BATTLESUIT ) ) {
- ent->customShader = cgs.media.battleSuitShader;
- trap_R_AddRefEntityToScene( ent );
- }
- }
-}
-
-/*
-=================
-CG_LightVerts
-=================
-*/
-int CG_LightVerts( vec3_t normal, int numVerts, polyVert_t *verts )
-{
- int i, j;
- float incoming;
- vec3_t ambientLight;
- vec3_t lightDir;
- vec3_t directedLight;
-
- trap_R_LightForPoint( verts[0].xyz, ambientLight, directedLight, lightDir );
-
- for (i = 0; i < numVerts; i++) {
- incoming = DotProduct (normal, lightDir);
- if ( incoming <= 0 ) {
- verts[i].modulate[0] = ambientLight[0];
- verts[i].modulate[1] = ambientLight[1];
- verts[i].modulate[2] = ambientLight[2];
- verts[i].modulate[3] = 255;
- continue;
- }
- j = ( ambientLight[0] + incoming * directedLight[0] );
- if ( j > 255 ) {
- j = 255;
- }
- verts[i].modulate[0] = j;
-
- j = ( ambientLight[1] + incoming * directedLight[1] );
- if ( j > 255 ) {
- j = 255;
- }
- verts[i].modulate[1] = j;
-
- j = ( ambientLight[2] + incoming * directedLight[2] );
- if ( j > 255 ) {
- j = 255;
- }
- verts[i].modulate[2] = j;
-
- verts[i].modulate[3] = 255;
- }
- return qtrue;
-}
-
-/*
-===============
-CG_Player
-===============
-*/
-void CG_Player( centity_t *cent ) {
- clientInfo_t *ci;
- refEntity_t legs;
- refEntity_t torso;
- refEntity_t head;
- int clientNum;
- int renderfx;
- qboolean shadow;
- float shadowPlane;
- refEntity_t skull;
- refEntity_t powerup;
- int t;
- float c;
- float angle;
- vec3_t dir, angles;
-
- // the client number is stored in clientNum. It can't be derived
- // from the entity number, because a single client may have
- // multiple corpses on the level using the same clientinfo
- clientNum = cent->currentState.clientNum;
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- CG_Error( "Bad clientNum on player entity");
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- // it is possible to see corpses from disconnected players that may
- // not have valid clientinfo
- if ( !ci->infoValid ) {
- return;
- }
-
- // get the player model information
- renderfx = 0;
- if ( cent->currentState.number == cg.snap->ps.clientNum) {
- if (!cg.renderingThirdPerson) {
- renderfx = RF_THIRD_PERSON; // only draw in mirrors
- } else {
- if (cg_cameraMode.integer) {
- return;
- }
- }
- }
-
-
- memset( &legs, 0, sizeof(legs) );
- memset( &torso, 0, sizeof(torso) );
- memset( &head, 0, sizeof(head) );
-
- // get the rotation information
- CG_PlayerAngles( cent, legs.axis, torso.axis, head.axis );
-
- // get the animation state (after rotation, to allow feet shuffle)
- CG_PlayerAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp,
- &torso.oldframe, &torso.frame, &torso.backlerp );
-
- // add the talk baloon or disconnect icon
- CG_PlayerSprites( cent );
-
- // add the shadow
- shadow = CG_PlayerShadow( cent, &shadowPlane );
-
- // add a water splash if partially in and out of water
- CG_PlayerSplash( cent );
-
- if ( cg_shadows.integer == 3 && shadow ) {
- renderfx |= RF_SHADOW_PLANE;
- }
- renderfx |= RF_LIGHTING_ORIGIN; // use the same origin for all
- if( cgs.gametype == GT_HARVESTER ) {
- CG_PlayerTokens( cent, renderfx );
- }
- //
- // add the legs
- //
- legs.hModel = ci->legsModel;
- legs.customSkin = ci->legsSkin;
-
- VectorCopy( cent->lerpOrigin, legs.origin );
-
- VectorCopy( cent->lerpOrigin, legs.lightingOrigin );
- legs.shadowPlane = shadowPlane;
- legs.renderfx = renderfx;
- VectorCopy (legs.origin, legs.oldorigin); // don't positionally lerp at all
-
- CG_AddRefEntityWithPowerups( &legs, ¢->currentState, ci->team );
-
- // if the model failed, allow the default nullmodel to be displayed
- if (!legs.hModel) {
- return;
- }
-
- //
- // add the torso
- //
- torso.hModel = ci->torsoModel;
- if (!torso.hModel) {
- return;
- }
-
- torso.customSkin = ci->torsoSkin;
-
- VectorCopy( cent->lerpOrigin, torso.lightingOrigin );
-
- CG_PositionRotatedEntityOnTag( &torso, &legs, ci->legsModel, "tag_torso");
-
- torso.shadowPlane = shadowPlane;
- torso.renderfx = renderfx;
-
- CG_AddRefEntityWithPowerups( &torso, ¢->currentState, ci->team );
-
- if ( cent->currentState.eFlags & EF_KAMIKAZE ) {
-
- memset( &skull, 0, sizeof(skull) );
-
- VectorCopy( cent->lerpOrigin, skull.lightingOrigin );
- skull.shadowPlane = shadowPlane;
- skull.renderfx = renderfx;
-
- if ( cent->currentState.eFlags & EF_DEAD ) {
- // one skull bobbing above the dead body
- angle = ((cg.time / 7) & 255) * (M_PI * 2) / 255;
- if (angle > M_PI * 2)
- angle -= (float)M_PI * 2;
- dir[0] = sin(angle) * 20;
- dir[1] = cos(angle) * 20;
- angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255;
- dir[2] = 15 + sin(angle) * 8;
- VectorAdd(torso.origin, dir, skull.origin);
-
- dir[2] = 0;
- VectorCopy(dir, skull.axis[1]);
- VectorNormalize(skull.axis[1]);
- VectorSet(skull.axis[2], 0, 0, 1);
- CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
-
- skull.hModel = cgs.media.kamikazeHeadModel;
- trap_R_AddRefEntityToScene( &skull );
- skull.hModel = cgs.media.kamikazeHeadTrail;
- trap_R_AddRefEntityToScene( &skull );
- }
- else {
- // three skulls spinning around the player
- angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255;
- dir[0] = cos(angle) * 20;
- dir[1] = sin(angle) * 20;
- dir[2] = cos(angle) * 20;
- VectorAdd(torso.origin, dir, skull.origin);
-
- angles[0] = sin(angle) * 30;
- angles[1] = (angle * 180 / M_PI) + 90;
- if (angles[1] > 360)
- angles[1] -= 360;
- angles[2] = 0;
- AnglesToAxis( angles, skull.axis );
-
- /*
- dir[2] = 0;
- VectorInverse(dir);
- VectorCopy(dir, skull.axis[1]);
- VectorNormalize(skull.axis[1]);
- VectorSet(skull.axis[2], 0, 0, 1);
- CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
- */
-
- skull.hModel = cgs.media.kamikazeHeadModel;
- trap_R_AddRefEntityToScene( &skull );
- // flip the trail because this skull is spinning in the other direction
- VectorInverse(skull.axis[1]);
- skull.hModel = cgs.media.kamikazeHeadTrail;
- trap_R_AddRefEntityToScene( &skull );
-
- angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255 + M_PI;
- if (angle > M_PI * 2)
- angle -= (float)M_PI * 2;
- dir[0] = sin(angle) * 20;
- dir[1] = cos(angle) * 20;
- dir[2] = cos(angle) * 20;
- VectorAdd(torso.origin, dir, skull.origin);
-
- angles[0] = cos(angle - 0.5 * M_PI) * 30;
- angles[1] = 360 - (angle * 180 / M_PI);
- if (angles[1] > 360)
- angles[1] -= 360;
- angles[2] = 0;
- AnglesToAxis( angles, skull.axis );
-
- /*
- dir[2] = 0;
- VectorCopy(dir, skull.axis[1]);
- VectorNormalize(skull.axis[1]);
- VectorSet(skull.axis[2], 0, 0, 1);
- CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
- */
-
- skull.hModel = cgs.media.kamikazeHeadModel;
- trap_R_AddRefEntityToScene( &skull );
- skull.hModel = cgs.media.kamikazeHeadTrail;
- trap_R_AddRefEntityToScene( &skull );
-
- angle = ((cg.time / 3) & 255) * (M_PI * 2) / 255 + 0.5 * M_PI;
- if (angle > M_PI * 2)
- angle -= (float)M_PI * 2;
- dir[0] = sin(angle) * 20;
- dir[1] = cos(angle) * 20;
- dir[2] = 0;
- VectorAdd(torso.origin, dir, skull.origin);
-
- VectorCopy(dir, skull.axis[1]);
- VectorNormalize(skull.axis[1]);
- VectorSet(skull.axis[2], 0, 0, 1);
- CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
-
- skull.hModel = cgs.media.kamikazeHeadModel;
- trap_R_AddRefEntityToScene( &skull );
- skull.hModel = cgs.media.kamikazeHeadTrail;
- trap_R_AddRefEntityToScene( &skull );
- }
- }
-
- if ( cent->currentState.powerups & ( 1 << PW_GUARD ) ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.guardPowerupModel;
- powerup.frame = 0;
- powerup.oldframe = 0;
- powerup.customSkin = 0;
- trap_R_AddRefEntityToScene( &powerup );
- }
- if ( cent->currentState.powerups & ( 1 << PW_SCOUT ) ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.scoutPowerupModel;
- powerup.frame = 0;
- powerup.oldframe = 0;
- powerup.customSkin = 0;
- trap_R_AddRefEntityToScene( &powerup );
- }
- if ( cent->currentState.powerups & ( 1 << PW_DOUBLER ) ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.doublerPowerupModel;
- powerup.frame = 0;
- powerup.oldframe = 0;
- powerup.customSkin = 0;
- trap_R_AddRefEntityToScene( &powerup );
- }
- if ( cent->currentState.powerups & ( 1 << PW_AMMOREGEN ) ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.ammoRegenPowerupModel;
- powerup.frame = 0;
- powerup.oldframe = 0;
- powerup.customSkin = 0;
- trap_R_AddRefEntityToScene( &powerup );
- }
- if ( cent->currentState.powerups & ( 1 << PW_INVULNERABILITY ) ) {
- if ( !ci->invulnerabilityStartTime ) {
- ci->invulnerabilityStartTime = cg.time;
- }
- ci->invulnerabilityStopTime = cg.time;
- }
- else {
- ci->invulnerabilityStartTime = 0;
- }
- if ( (cent->currentState.powerups & ( 1 << PW_INVULNERABILITY ) ) ||
- cg.time - ci->invulnerabilityStopTime < 250 ) {
-
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.invulnerabilityPowerupModel;
- powerup.customSkin = 0;
- // always draw
- powerup.renderfx &= ~RF_THIRD_PERSON;
- VectorCopy(cent->lerpOrigin, powerup.origin);
-
- if ( cg.time - ci->invulnerabilityStartTime < 250 ) {
- c = (float) (cg.time - ci->invulnerabilityStartTime) / 250;
- }
- else if (cg.time - ci->invulnerabilityStopTime < 250 ) {
- c = (float) (250 - (cg.time - ci->invulnerabilityStopTime)) / 250;
- }
- else {
- c = 1;
- }
- VectorSet( powerup.axis[0], c, 0, 0 );
- VectorSet( powerup.axis[1], 0, c, 0 );
- VectorSet( powerup.axis[2], 0, 0, c );
- trap_R_AddRefEntityToScene( &powerup );
- }
-
- t = cg.time - ci->medkitUsageTime;
- if ( ci->medkitUsageTime && t < 500 ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.medkitUsageModel;
- powerup.customSkin = 0;
- // always draw
- powerup.renderfx &= ~RF_THIRD_PERSON;
- VectorClear(angles);
- AnglesToAxis(angles, powerup.axis);
- VectorCopy(cent->lerpOrigin, powerup.origin);
- powerup.origin[2] += -24 + (float) t * 80 / 500;
- if ( t > 400 ) {
- c = (float) (t - 1000) * 0xff / 100;
- powerup.shaderRGBA[0] = 0xff - c;
- powerup.shaderRGBA[1] = 0xff - c;
- powerup.shaderRGBA[2] = 0xff - c;
- powerup.shaderRGBA[3] = 0xff - c;
- }
- else {
- powerup.shaderRGBA[0] = 0xff;
- powerup.shaderRGBA[1] = 0xff;
- powerup.shaderRGBA[2] = 0xff;
- powerup.shaderRGBA[3] = 0xff;
- }
- trap_R_AddRefEntityToScene( &powerup );
- }
-
- //
- // add the head
- //
- head.hModel = ci->headModel;
- if (!head.hModel) {
- return;
- }
- head.customSkin = ci->headSkin;
-
- VectorCopy( cent->lerpOrigin, head.lightingOrigin );
-
- CG_PositionRotatedEntityOnTag( &head, &torso, ci->torsoModel, "tag_head");
-
- head.shadowPlane = shadowPlane;
- head.renderfx = renderfx;
-
- CG_AddRefEntityWithPowerups( &head, ¢->currentState, ci->team );
-
- CG_BreathPuffs(cent, &head);
-
- CG_DustTrail(cent);
-
- //
- // add the gun / barrel / flash
- //
- CG_AddPlayerWeapon( &torso, NULL, cent, ci->team );
-
- // add powerups floating behind the player
- CG_PlayerPowerups( cent, &torso );
-}
-
-
-//=====================================================================
-
-/*
-===============
-CG_ResetPlayerEntity
-
-A player just came into view or teleported, so reset all animation info
-===============
-*/
-void CG_ResetPlayerEntity( centity_t *cent ) {
- cent->errorTime = -99999; // guarantee no error decay added
- cent->extrapolated = qfalse;
-
- CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.legs, cent->currentState.legsAnim );
- CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.torso, cent->currentState.torsoAnim );
-
- BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin );
- BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles );
-
- VectorCopy( cent->lerpOrigin, cent->rawOrigin );
- VectorCopy( cent->lerpAngles, cent->rawAngles );
-
- memset( ¢->pe.legs, 0, sizeof( cent->pe.legs ) );
- cent->pe.legs.yawAngle = cent->rawAngles[YAW];
- cent->pe.legs.yawing = qfalse;
- cent->pe.legs.pitchAngle = 0;
- cent->pe.legs.pitching = qfalse;
-
- memset( ¢->pe.torso, 0, sizeof( cent->pe.legs ) );
- cent->pe.torso.yawAngle = cent->rawAngles[YAW];
- cent->pe.torso.yawing = qfalse;
- cent->pe.torso.pitchAngle = cent->rawAngles[PITCH];
- cent->pe.torso.pitching = qfalse;
-
- if ( cg_debugPosition.integer ) {
- CG_Printf("%i ResetPlayerEntity yaw=%i\n", cent->currentState.number, cent->pe.torso.yawAngle );
- }
-}
-
diff --git a/game/code/cgame/cg_playerstate.c b/game/code/cgame/cg_playerstate.c
deleted file mode 100644
index 71c83de..0000000
--- a/game/code/cgame/cg_playerstate.c
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_playerstate.c -- this file acts on changes in a new playerState_t
-// With normal play, this will be done after local prediction, but when
-// following another player or playing back a demo, it will be checked
-// when the snapshot transitions like all the other entities
-
-#include "cg_local.h"
-
-/*
-==============
-CG_CheckAmmo
-
-If the ammo has gone low enough to generate the warning, play a sound
-==============
-*/
-void CG_CheckAmmo( void ) {
- int i;
- int total;
- int previous;
- int weapons;
-
- // see about how many seconds of ammo we have remaining
- weapons = cg.snap->ps.stats[ STAT_WEAPONS ];
- total = 0;
- for ( i = WP_MACHINEGUN ; i < WP_NUM_WEAPONS ; i++ ) {
- if ( ! ( weapons & ( 1 << i ) ) || i == WP_GRAPPLING_HOOK ) {
- continue;
- }
- switch ( i ) {
- case WP_ROCKET_LAUNCHER:
- case WP_GRENADE_LAUNCHER:
- case WP_RAILGUN:
- case WP_SHOTGUN:
-//#ifdef MISSIONPACK
- case WP_PROX_LAUNCHER:
-//#endif
- total += cg.snap->ps.ammo[i] * 1000;
- break;
- default:
- total += cg.snap->ps.ammo[i] * 200;
- break;
- }
- if ( total >= 5000 ) {
- cg.lowAmmoWarning = 0;
- return;
- }
- }
-
- previous = cg.lowAmmoWarning;
-
- if ( total == 0 ) {
- cg.lowAmmoWarning = 2;
- } else {
- cg.lowAmmoWarning = 1;
- }
-
- // play a sound on transitions
- if ( cg.lowAmmoWarning != previous ) {
- trap_S_StartLocalSound( cgs.media.noAmmoSound, CHAN_LOCAL_SOUND );
- }
-}
-
-/*
-==============
-CG_DamageFeedback
-==============
-*/
-void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) {
- float left, front, up;
- float kick;
- int health;
- float scale;
- vec3_t dir;
- vec3_t angles;
- float dist;
- float yaw, pitch;
-
- // show the attacking player's head and name in corner
- cg.attackerTime = cg.time;
-
- // the lower on health you are, the greater the view kick will be
- health = cg.snap->ps.stats[STAT_HEALTH];
- if ( health < 40 ) {
- scale = 1;
- } else {
- scale = 40.0 / health;
- }
- kick = damage * scale;
-
- if (kick < 5)
- kick = 5;
- if (kick > 10)
- kick = 10;
-
- // if yaw and pitch are both 255, make the damage always centered (falling, etc)
- if ( yawByte == 255 && pitchByte == 255 ) {
- cg.damageX = 0;
- cg.damageY = 0;
- cg.v_dmg_roll = 0;
- cg.v_dmg_pitch = -kick;
- } else {
- // positional
- pitch = pitchByte / 255.0 * 360;
- yaw = yawByte / 255.0 * 360;
-
- angles[PITCH] = pitch;
- angles[YAW] = yaw;
- angles[ROLL] = 0;
-
- AngleVectors( angles, dir, NULL, NULL );
- VectorSubtract( vec3_origin, dir, dir );
-
- front = DotProduct (dir, cg.refdef.viewaxis[0] );
- left = DotProduct (dir, cg.refdef.viewaxis[1] );
- up = DotProduct (dir, cg.refdef.viewaxis[2] );
-
- dir[0] = front;
- dir[1] = left;
- dir[2] = 0;
- dist = VectorLength( dir );
- if ( dist < 0.1 ) {
- dist = 0.1f;
- }
-
- cg.v_dmg_roll = kick * left;
-
- cg.v_dmg_pitch = -kick * front;
-
- if ( front <= 0.1 ) {
- front = 0.1f;
- }
- cg.damageX = -left / front;
- cg.damageY = up / dist;
- }
-
- // clamp the position
- if ( cg.damageX > 1.0 ) {
- cg.damageX = 1.0;
- }
- if ( cg.damageX < - 1.0 ) {
- cg.damageX = -1.0;
- }
-
- if ( cg.damageY > 1.0 ) {
- cg.damageY = 1.0;
- }
- if ( cg.damageY < - 1.0 ) {
- cg.damageY = -1.0;
- }
-
- // don't let the screen flashes vary as much
- if ( kick > 10 ) {
- kick = 10;
- }
- cg.damageValue = kick;
- cg.v_dmg_time = cg.time + DAMAGE_TIME;
- cg.damageTime = cg.snap->serverTime;
-}
-
-
-
-
-/*
-================
-CG_Respawn
-
-A respawn happened this snapshot
-================
-*/
-void CG_Respawn( void ) {
- // no error decay on player movement
- cg.thisFrameTeleport = qtrue;
-
- // display weapons available
- cg.weaponSelectTime = cg.time;
-
- // select the weapon the server says we are using
- cg.weaponSelect = cg.snap->ps.weapon;
-}
-
-extern char *eventnames[];
-
-/*
-==============
-CG_CheckPlayerstateEvents
-==============
-*/
-void CG_CheckPlayerstateEvents( playerState_t *ps, playerState_t *ops ) {
- int i;
- int event;
- centity_t *cent;
-
- if ( ps->externalEvent && ps->externalEvent != ops->externalEvent ) {
- cent = &cg_entities[ ps->clientNum ];
- cent->currentState.event = ps->externalEvent;
- cent->currentState.eventParm = ps->externalEventParm;
- CG_EntityEvent( cent, cent->lerpOrigin );
- }
-
- cent = &cg.predictedPlayerEntity; // cg_entities[ ps->clientNum ];
- // go through the predictable events buffer
- for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {
- // if we have a new predictable event
- if ( i >= ops->eventSequence
- // or the server told us to play another event instead of a predicted event we already issued
- // or something the server told us changed our prediction causing a different event
- || (i > ops->eventSequence - MAX_PS_EVENTS && ps->events[i & (MAX_PS_EVENTS-1)] != ops->events[i & (MAX_PS_EVENTS-1)]) ) {
-
- event = ps->events[ i & (MAX_PS_EVENTS-1) ];
- cent->currentState.event = event;
- cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];
- CG_EntityEvent( cent, cent->lerpOrigin );
-
- cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event;
-
- cg.eventSequence++;
- }
- }
-}
-
-/*
-==================
-CG_CheckChangedPredictableEvents
-==================
-*/
-void CG_CheckChangedPredictableEvents( playerState_t *ps ) {
- int i;
- int event;
- centity_t *cent;
-
- cent = &cg.predictedPlayerEntity;
- for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {
- //
- if (i >= cg.eventSequence) {
- continue;
- }
- // if this event is not further back in than the maximum predictable events we remember
- if (i > cg.eventSequence - MAX_PREDICTED_EVENTS) {
- // if the new playerstate event is different from a previously predicted one
- if ( ps->events[i & (MAX_PS_EVENTS-1)] != cg.predictableEvents[i & (MAX_PREDICTED_EVENTS-1) ] ) {
-
- event = ps->events[ i & (MAX_PS_EVENTS-1) ];
- cent->currentState.event = event;
- cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];
- CG_EntityEvent( cent, cent->lerpOrigin );
-
- cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event;
-
- if ( cg_showmiss.integer ) {
- CG_Printf("WARNING: changed predicted event\n");
- }
- }
- }
- }
-}
-
-/*
-==================
-pushReward
-==================
-*/
-static void pushReward(sfxHandle_t sfx, qhandle_t shader, int rewardCount) {
- if (cg.rewardStack < (MAX_REWARDSTACK-1)) {
- cg.rewardStack++;
- cg.rewardSound[cg.rewardStack] = sfx;
- cg.rewardShader[cg.rewardStack] = shader;
- cg.rewardCount[cg.rewardStack] = rewardCount;
- }
-}
-
-
-/*
-==================
-CG_CheckLocalSounds
-==================
-*/
-void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) {
- int highScore, health, armor, reward;
- sfxHandle_t sfx;
-
- // don't play the sounds if the player just changed teams
- if ( ps->persistant[PERS_TEAM] != ops->persistant[PERS_TEAM] ) {
- return;
- }
-
- // hit changes
- if ( ps->persistant[PERS_HITS] > ops->persistant[PERS_HITS] ) {
- armor = ps->persistant[PERS_ATTACKEE_ARMOR] & 0xff;
- health = ps->persistant[PERS_ATTACKEE_ARMOR] >> 8;
-#ifdef MISSIONPACK
- if (armor > 50 ) {
- trap_S_StartLocalSound( cgs.media.hitSoundHighArmor, CHAN_LOCAL_SOUND );
- } else if (armor || health > 100) {
- trap_S_StartLocalSound( cgs.media.hitSoundLowArmor, CHAN_LOCAL_SOUND );
- } else {
- trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND );
- }
-#else
- trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND );
-#endif
- } else if ( ps->persistant[PERS_HITS] < ops->persistant[PERS_HITS] ) {
- trap_S_StartLocalSound( cgs.media.hitTeamSound, CHAN_LOCAL_SOUND );
- }
-
- // health changes of more than -1 should make pain sounds
- if ( ps->stats[STAT_HEALTH] < ops->stats[STAT_HEALTH] - 1 ) {
- if ( ps->stats[STAT_HEALTH] > 0 ) {
- CG_PainEvent( &cg.predictedPlayerEntity, ps->stats[STAT_HEALTH] );
- }
- }
-
-
- // if we are going into the intermission, don't start any voices
- if ( cg.intermissionStarted ) {
- return;
- }
-
- // reward sounds
- reward = qfalse;
- if (ps->persistant[PERS_CAPTURES] != ops->persistant[PERS_CAPTURES]) {
- pushReward(cgs.media.captureAwardSound, cgs.media.medalCapture, ps->persistant[PERS_CAPTURES]);
- reward = qtrue;
- //Com_Printf("capture\n");
- }
- if (ps->persistant[PERS_IMPRESSIVE_COUNT] != ops->persistant[PERS_IMPRESSIVE_COUNT]) {
-#ifdef MISSIONPACK
- if (ps->persistant[PERS_IMPRESSIVE_COUNT] == 1) {
- sfx = cgs.media.firstImpressiveSound;
- } else {
- sfx = cgs.media.impressiveSound;
- }
-#else
- sfx = cgs.media.impressiveSound;
-#endif
- pushReward(sfx, cgs.media.medalImpressive, ps->persistant[PERS_IMPRESSIVE_COUNT]);
- reward = qtrue;
- //Com_Printf("impressive\n");
- }
- //KK-OAX We Just Won't Draw The Excellent Stuff if Multikills are Enabled!!!
- if( !cgs.altExcellent ) {
- if (ps->persistant[PERS_EXCELLENT_COUNT] != ops->persistant[PERS_EXCELLENT_COUNT]) {
-#ifdef MISSIONPACK
- if (ps->persistant[PERS_EXCELLENT_COUNT] == 1) {
- sfx = cgs.media.firstExcellentSound;
- } else {
- sfx = cgs.media.excellentSound;
- }
-#else
- sfx = cgs.media.excellentSound;
-#endif
-
- pushReward(sfx, cgs.media.medalExcellent, ps->persistant[PERS_EXCELLENT_COUNT]);
- reward = qtrue;
- //Com_Printf("excellent\n");
- }
- }
- if (ps->persistant[PERS_GAUNTLET_FRAG_COUNT] != ops->persistant[PERS_GAUNTLET_FRAG_COUNT]) {
-#ifdef MISSIONPACK
- if (ops->persistant[PERS_GAUNTLET_FRAG_COUNT] == 1) {
- sfx = cgs.media.firstHumiliationSound;
- } else {
- sfx = cgs.media.humiliationSound;
- }
-#else
- sfx = cgs.media.humiliationSound;
-#endif
- pushReward(sfx, cgs.media.medalGauntlet, ps->persistant[PERS_GAUNTLET_FRAG_COUNT]);
- reward = qtrue;
- //Com_Printf("guantlet frag\n");
- }
- if (ps->persistant[PERS_DEFEND_COUNT] != ops->persistant[PERS_DEFEND_COUNT]) {
- pushReward(cgs.media.defendSound, cgs.media.medalDefend, ps->persistant[PERS_DEFEND_COUNT]);
- reward = qtrue;
- //Com_Printf("defend\n");
- }
- if (ps->persistant[PERS_ASSIST_COUNT] != ops->persistant[PERS_ASSIST_COUNT]) {
- pushReward(cgs.media.assistSound, cgs.media.medalAssist, ps->persistant[PERS_ASSIST_COUNT]);
- reward = qtrue;
- //Com_Printf("assist\n");
- }
- // if any of the player event bits changed
- if (ps->persistant[PERS_PLAYEREVENTS] != ops->persistant[PERS_PLAYEREVENTS]) {
- if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD) !=
- (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD)) {
- trap_S_StartLocalSound( cgs.media.deniedSound, CHAN_ANNOUNCER );
- }
- else if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD) !=
- (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD)) {
- trap_S_StartLocalSound( cgs.media.humiliationSound, CHAN_ANNOUNCER );
- }
- else if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT) !=
- (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT)) {
- trap_S_StartLocalSound( cgs.media.holyShitSound, CHAN_ANNOUNCER );
- }
- reward = qtrue;
- }
-
- // check for flag pickup
- if ( cgs.gametype >= GT_TEAM ) {
- if ((ps->powerups[PW_REDFLAG] != ops->powerups[PW_REDFLAG] && ps->powerups[PW_REDFLAG]) ||
- (ps->powerups[PW_BLUEFLAG] != ops->powerups[PW_BLUEFLAG] && ps->powerups[PW_BLUEFLAG]) ||
- (ps->powerups[PW_NEUTRALFLAG] != ops->powerups[PW_NEUTRALFLAG] && ps->powerups[PW_NEUTRALFLAG]) )
- {
- trap_S_StartLocalSound( cgs.media.youHaveFlagSound, CHAN_ANNOUNCER );
- }
- }
-
- // lead changes
- if (!reward) {
- //
- if ( !cg.warmup ) {
- // never play lead changes during warmup
- if ( ps->persistant[PERS_RANK] != ops->persistant[PERS_RANK] ) {
- if ( cgs.gametype < GT_TEAM || cgs.ffa_gt==1) {
- if ( ps->persistant[PERS_RANK] == 0 ) {
- CG_AddBufferedSound(cgs.media.takenLeadSound);
- } else if ( ps->persistant[PERS_RANK] == RANK_TIED_FLAG ) {
- CG_AddBufferedSound(cgs.media.tiedLeadSound);
- } else if ( ( ops->persistant[PERS_RANK] & ~RANK_TIED_FLAG ) == 0 ) {
- CG_AddBufferedSound(cgs.media.lostLeadSound);
- }
- }
- }
- }
- }
-
- // timelimit warnings
- if ( cgs.timelimit > 0 ) {
- int msec;
-
- msec = cg.time - cgs.levelStartTime;
- if ( !( cg.timelimitWarnings & 4 ) && msec > ( cgs.timelimit * 60 + 2 ) * 1000 ) {
- cg.timelimitWarnings |= 1 | 2 | 4;
- trap_S_StartLocalSound( cgs.media.suddenDeathSound, CHAN_ANNOUNCER );
- }
- else if ( !( cg.timelimitWarnings & 2 ) && msec > (cgs.timelimit - 1) * 60 * 1000 ) {
- cg.timelimitWarnings |= 1 | 2;
- trap_S_StartLocalSound( cgs.media.oneMinuteSound, CHAN_ANNOUNCER );
- }
- else if ( cgs.timelimit > 5 && !( cg.timelimitWarnings & 1 ) && msec > (cgs.timelimit - 5) * 60 * 1000 ) {
- cg.timelimitWarnings |= 1;
- trap_S_StartLocalSound( cgs.media.fiveMinuteSound, CHAN_ANNOUNCER );
- }
- }
-
- // fraglimit warnings
- if ( cgs.fraglimit > 0 && cgs.gametype < GT_CTF) {
- highScore = cgs.scores1;
- if ( !( cg.fraglimitWarnings & 4 ) && highScore == (cgs.fraglimit - 1) ) {
- cg.fraglimitWarnings |= 1 | 2 | 4;
- CG_AddBufferedSound(cgs.media.oneFragSound);
- }
- else if ( cgs.fraglimit > 2 && !( cg.fraglimitWarnings & 2 ) && highScore == (cgs.fraglimit - 2) ) {
- cg.fraglimitWarnings |= 1 | 2;
- CG_AddBufferedSound(cgs.media.twoFragSound);
- }
- else if ( cgs.fraglimit > 3 && !( cg.fraglimitWarnings & 1 ) && highScore == (cgs.fraglimit - 3) ) {
- cg.fraglimitWarnings |= 1;
- CG_AddBufferedSound(cgs.media.threeFragSound);
- }
- }
-}
-
-/*
-===============
-CG_TransitionPlayerState
-
-===============
-*/
-void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) {
- // check for changing follow mode
- if ( ps->clientNum != ops->clientNum ) {
- cg.thisFrameTeleport = qtrue;
- // make sure we don't get any unwanted transition effects
- *ops = *ps;
- }
-
- // damage events (player is getting wounded)
- if ( ps->damageEvent != ops->damageEvent && ps->damageCount ) {
- CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount );
- }
-
- // respawning
- if ( ps->persistant[PERS_SPAWN_COUNT] != ops->persistant[PERS_SPAWN_COUNT] ) {
- CG_Respawn();
- }
-
- if ( cg.mapRestart ) {
- CG_Respawn();
- cg.mapRestart = qfalse;
- }
-
- if ( cg.snap->ps.pm_type != PM_INTERMISSION
- && ps->persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
- CG_CheckLocalSounds( ps, ops );
- }
-
- // check for going low on ammo
- CG_CheckAmmo();
-
- // run events
- CG_CheckPlayerstateEvents( ps, ops );
-
- // smooth the ducking viewheight change
- if ( ps->viewheight != ops->viewheight ) {
- cg.duckChange = ps->viewheight - ops->viewheight;
- cg.duckTime = cg.time;
- }
-}
-
diff --git a/game/code/cgame/cg_predict.c b/game/code/cgame/cg_predict.c
deleted file mode 100644
index d3a88f9..0000000
--- a/game/code/cgame/cg_predict.c
+++ /dev/null
@@ -1,941 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_predict.c -- this file generates cg.predictedPlayerState by either
-// interpolating between snapshots from the server or locally predicting
-// ahead the client's movement.
-// It also handles local physics interaction, like fragments bouncing off walls
-
-#include "cg_local.h"
-
-static pmove_t cg_pmove;
-
-static int cg_numSolidEntities;
-static centity_t *cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT];
-static int cg_numTriggerEntities;
-static centity_t *cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT];
-
-/*
-====================
-CG_BuildSolidList
-
-When a new cg.snap has been set, this function builds a sublist
-of the entities that are actually solid, to make for more
-efficient collision detection
-====================
-*/
-void CG_BuildSolidList( void ) {
- int i;
- centity_t *cent;
- snapshot_t *snap;
- entityState_t *ent;
-
- cg_numSolidEntities = 0;
- cg_numTriggerEntities = 0;
-
- if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
- snap = cg.nextSnap;
- } else {
- snap = cg.snap;
- }
-
- for ( i = 0 ; i < snap->numEntities ; i++ ) {
- cent = &cg_entities[ snap->entities[ i ].number ];
- ent = ¢->currentState;
-
- if ( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) {
- cg_triggerEntities[cg_numTriggerEntities] = cent;
- cg_numTriggerEntities++;
- continue;
- }
-
- if ( cent->nextState.solid ) {
- cg_solidEntities[cg_numSolidEntities] = cent;
- cg_numSolidEntities++;
- continue;
- }
- }
-}
-
-/*
-====================
-CG_ClipMoveToEntities
-
-====================
-*/
-static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
- int skipNumber, int mask, trace_t *tr ) {
- int i, x, zd, zu;
- trace_t trace;
- entityState_t *ent;
- clipHandle_t cmodel;
- vec3_t bmins, bmaxs;
- vec3_t origin, angles;
- centity_t *cent;
-
- for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
- cent = cg_solidEntities[ i ];
- ent = ¢->currentState;
-
- if ( ent->number == skipNumber ) {
- continue;
- }
-
- if ( ent->solid == SOLID_BMODEL ) {
- // special value for bmodel
- cmodel = trap_CM_InlineModel( ent->modelindex );
- VectorCopy( cent->lerpAngles, angles );
- BG_EvaluateTrajectory( ¢->currentState.pos, cg.physicsTime, origin );
- } else {
- // encoded bbox
- x = (ent->solid & 255);
- zd = ((ent->solid>>8) & 255);
- zu = ((ent->solid>>16) & 255) - 32;
-
- bmins[0] = bmins[1] = -x;
- bmaxs[0] = bmaxs[1] = x;
- bmins[2] = -zd;
- bmaxs[2] = zu;
-
- cmodel = trap_CM_TempBoxModel( bmins, bmaxs );
- VectorCopy( vec3_origin, angles );
- VectorCopy( cent->lerpOrigin, origin );
- }
-
-
- trap_CM_TransformedBoxTrace ( &trace, start, end,
- mins, maxs, cmodel, mask, origin, angles);
-
- if (trace.allsolid || trace.fraction < tr->fraction) {
- trace.entityNum = ent->number;
- *tr = trace;
- } else if (trace.startsolid) {
- tr->startsolid = qtrue;
- }
- if ( tr->allsolid ) {
- return;
- }
- }
-}
-
-/*
-================
-CG_Trace
-================
-*/
-void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
- int skipNumber, int mask ) {
- trace_t t;
-
- trap_CM_BoxTrace ( &t, start, end, mins, maxs, 0, mask);
- t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
- // check all other solid models
- CG_ClipMoveToEntities (start, mins, maxs, end, skipNumber, mask, &t);
-
- *result = t;
-}
-
-/*
-================
-CG_PointContents
-================
-*/
-int CG_PointContents( const vec3_t point, int passEntityNum ) {
- int i;
- entityState_t *ent;
- centity_t *cent;
- clipHandle_t cmodel;
- int contents;
-
- contents = trap_CM_PointContents (point, 0);
-
- for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
- cent = cg_solidEntities[ i ];
-
- ent = ¢->currentState;
-
- if ( ent->number == passEntityNum ) {
- continue;
- }
-
- if (ent->solid != SOLID_BMODEL) { // special value for bmodel
- continue;
- }
-
- cmodel = trap_CM_InlineModel( ent->modelindex );
- if ( !cmodel ) {
- continue;
- }
-
- contents |= trap_CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles );
- }
-
- return contents;
-}
-
-
-/*
-========================
-CG_InterpolatePlayerState
-
-Generates cg.predictedPlayerState by interpolating between
-cg.snap->player_state and cg.nextFrame->player_state
-========================
-*/
-static void CG_InterpolatePlayerState( qboolean grabAngles ) {
- float f;
- int i;
- playerState_t *out;
- snapshot_t *prev, *next;
-
- out = &cg.predictedPlayerState;
- prev = cg.snap;
- next = cg.nextSnap;
-
- *out = cg.snap->ps;
-
- // if we are still allowing local input, short circuit the view angles
- if ( grabAngles ) {
- usercmd_t cmd;
- int cmdNum;
-
- cmdNum = trap_GetCurrentCmdNumber();
- trap_GetUserCmd( cmdNum, &cmd );
-
- PM_UpdateViewAngles( out, &cmd );
- }
-
- // if the next frame is a teleport, we can't lerp to it
- if ( cg.nextFrameTeleport ) {
- return;
- }
-
- if ( !next || next->serverTime <= prev->serverTime ) {
- return;
- }
-
- f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime );
-
- i = next->ps.bobCycle;
- if ( i < prev->ps.bobCycle ) {
- i += 256; // handle wraparound
- }
- out->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle );
-
- for ( i = 0 ; i < 3 ; i++ ) {
- out->origin[i] = prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i] );
- if ( !grabAngles ) {
- out->viewangles[i] = LerpAngle(
- prev->ps.viewangles[i], next->ps.viewangles[i], f );
- }
- out->velocity[i] = prev->ps.velocity[i] +
- f * (next->ps.velocity[i] - prev->ps.velocity[i] );
- }
-
-}
-
-/*
-===================
-CG_TouchItem
-===================
-*/
-static void CG_TouchItem( centity_t *cent ) {
- gitem_t *item;
- //For instantgib
- qboolean canBePicked;
-
- if(cgs.gametype == GT_ELIMINATION || cgs.gametype == GT_LMS)
- return; //No weapon pickup in elimination
-
- //normally we can
- canBePicked = qtrue;
-
- //But in instantgib, rocket arena, and CTF_ELIMINATION we normally can't:
- if(cgs.nopickup || cgs.gametype == GT_CTF_ELIMINATION)
- canBePicked = qfalse;
-
- if ( !cg_predictItems.integer ) {
- return;
- }
- if ( !BG_PlayerTouchesItem( &cg.predictedPlayerState, ¢->currentState, cg.time ) ) {
- return;
- }
-
- // never pick an item up twice in a prediction
- if ( cent->miscTime == cg.time ) {
- return;
- }
-
- if ( !BG_CanItemBeGrabbed( cgs.gametype, ¢->currentState, &cg.predictedPlayerState ) ) {
- return; // can't hold it
- }
-
- item = &bg_itemlist[ cent->currentState.modelindex ];
-
- // Special case for flags.
- // We don't predict touching our own flag
-#if 1 //MISSIONPACK
- if( cgs.gametype == GT_1FCTF ) {
- if( item->giTag != PW_NEUTRALFLAG ) {
- return;
- }
- }
- if( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION || cgs.gametype == GT_HARVESTER ) {
-#else
- if( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION ) {
-#endif
- if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_RED &&
- item->giTag == PW_REDFLAG)
- return;
- if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_BLUE &&
- item->giTag == PW_BLUEFLAG)
- return;
- //Even in instantgib, we can predict our enemy flag
- if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_RED &&
- item->giTag == PW_BLUEFLAG && (!(cgs.elimflags&EF_ONEWAY) || cgs.attackingTeam == TEAM_RED))
- canBePicked = qtrue;
- if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_BLUE &&
- item->giTag == PW_REDFLAG && (!(cgs.elimflags&EF_ONEWAY) || cgs.attackingTeam == TEAM_BLUE))
- canBePicked = qtrue;
- if (item->giTag == WP_RAILGUN)
- canBePicked = qfalse;
- if (item->giTag == WP_PLASMAGUN)
- canBePicked = qfalse;
- }
-
- //Currently we don't predict anything in Double Domination because it looks like we take a flag
- if( cgs.gametype == GT_DOUBLE_D ) {
- if(cgs.redflag == TEAM_NONE)
- return; //Can never pick if just one flag is NONE (because then the other is too)
- if(item->giTag == PW_REDFLAG){ //at point A
- if(cgs.redflag != cg.predictedPlayerState.persistant[PERS_TEAM]) //not already taken
- trap_S_StartLocalSound( cgs.media.hitSound , CHAN_ANNOUNCER );
- return;
- }
- if(item->giTag == PW_BLUEFLAG){ //at point B
- if(cgs.blueflag != cg.predictedPlayerState.persistant[PERS_TEAM]) //already taken
- trap_S_StartLocalSound( cgs.media.hitSound , CHAN_ANNOUNCER );
- return;
- }
- }
-
- // grab it
- if(canBePicked)
- {
- BG_AddPredictableEventToPlayerstate( EV_ITEM_PICKUP, cent->currentState.modelindex , &cg.predictedPlayerState);
-
- // remove it from the frame so it won't be drawn
- cent->currentState.eFlags |= EF_NODRAW;
-
- // don't touch it again this prediction
- cent->miscTime = cg.time;
-
- // if its a weapon, give them some predicted ammo so the autoswitch will work
- if ( item->giType == IT_WEAPON ) {
- cg.predictedPlayerState.stats[ STAT_WEAPONS ] |= 1 << item->giTag;
- if ( !cg.predictedPlayerState.ammo[ item->giTag ] ) {
- cg.predictedPlayerState.ammo[ item->giTag ] = 1;
- }
- }
- }
-}
-
-
-/*
-=========================
-CG_TouchTriggerPrediction
-
-Predict push triggers and items
-=========================
-*/
-static void CG_TouchTriggerPrediction( void ) {
- int i;
- trace_t trace;
- entityState_t *ent;
- clipHandle_t cmodel;
- centity_t *cent;
- qboolean spectator;
-
- // dead clients don't activate triggers
- if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
- return;
- }
-
- spectator = ( cg.predictedPlayerState.pm_type == PM_SPECTATOR );
-
- if ( cg.predictedPlayerState.pm_type != PM_NORMAL && !spectator ) {
- return;
- }
-
- for ( i = 0 ; i < cg_numTriggerEntities ; i++ ) {
- cent = cg_triggerEntities[ i ];
- ent = ¢->currentState;
-
- if ( ent->eType == ET_ITEM && !spectator ) {
- CG_TouchItem( cent );
- continue;
- }
-
- if ( ent->solid != SOLID_BMODEL ) {
- continue;
- }
-
- cmodel = trap_CM_InlineModel( ent->modelindex );
- if ( !cmodel ) {
- continue;
- }
-
- trap_CM_BoxTrace( &trace, cg.predictedPlayerState.origin, cg.predictedPlayerState.origin,
- cg_pmove.mins, cg_pmove.maxs, cmodel, -1 );
-
- if ( !trace.startsolid ) {
- continue;
- }
-
- if ( ent->eType == ET_TELEPORT_TRIGGER ) {
- cg.hyperspace = qtrue;
- } else if ( ent->eType == ET_PUSH_TRIGGER ) {
- BG_TouchJumpPad( &cg.predictedPlayerState, ent );
- }
- }
-
- // if we didn't touch a jump pad this pmove frame
- if ( cg.predictedPlayerState.jumppad_frame != cg.predictedPlayerState.pmove_framecount ) {
- cg.predictedPlayerState.jumppad_frame = 0;
- cg.predictedPlayerState.jumppad_ent = 0;
- }
-}
-
-//unlagged - optimized prediction
-#define ABS(x) ((x) < 0 ? (-(x)) : (x))
-
-static int IsUnacceptableError( playerState_t *ps, playerState_t *pps ) {
- vec3_t delta;
- int i;
-
- if ( pps->pm_type != ps->pm_type ||
- pps->pm_flags != ps->pm_flags ||
- pps->pm_time != ps->pm_time ) {
- return 1;
- }
-
- VectorSubtract( pps->origin, ps->origin, delta );
- if ( VectorLengthSquared( delta ) > 0.1f * 0.1f ) {
- if ( cg_showmiss.integer ) {
- CG_Printf("delta: %.2f ", VectorLength(delta) );
- }
- return 2;
- }
-
- VectorSubtract( pps->velocity, ps->velocity, delta );
- if ( VectorLengthSquared( delta ) > 0.1f * 0.1f ) {
- if ( cg_showmiss.integer ) {
- CG_Printf("delta: %.2f ", VectorLength(delta) );
- }
- return 3;
- }
-
- if ( pps->weaponTime != ps->weaponTime ||
- pps->gravity != ps->gravity ||
- pps->speed != ps->speed ||
- pps->delta_angles[0] != ps->delta_angles[0] ||
- pps->delta_angles[1] != ps->delta_angles[1] ||
- pps->delta_angles[2] != ps->delta_angles[2] ||
- pps->groundEntityNum != ps->groundEntityNum ) {
- return 4;
- }
-
- if ( pps->legsTimer != ps->legsTimer ||
- pps->legsAnim != ps->legsAnim ||
- pps->torsoTimer != ps->torsoTimer ||
- pps->torsoAnim != ps->torsoAnim ||
- pps->movementDir != ps->movementDir ) {
- return 5;
- }
-
- VectorSubtract( pps->grapplePoint, ps->grapplePoint, delta );
- if ( VectorLengthSquared( delta ) > 0.1f * 0.1f ) {
- return 6;
- }
-
- if ( pps->eFlags != ps->eFlags ) {
- return 7;
- }
-
- if ( pps->eventSequence != ps->eventSequence ) {
- return 8;
- }
-
- for ( i = 0; i < MAX_PS_EVENTS; i++ ) {
- if ( pps->events[i] != ps->events[i] ||
- pps->eventParms[i] != ps->eventParms[i] ) {
- return 9;
- }
- }
-
- if ( pps->externalEvent != ps->externalEvent ||
- pps->externalEventParm != ps->externalEventParm ||
- pps->externalEventTime != ps->externalEventTime ) {
- return 10;
- }
-
- if ( pps->clientNum != ps->clientNum ||
- pps->weapon != ps->weapon ||
- pps->weaponstate != ps->weaponstate ) {
- return 11;
- }
-
- if ( ABS(pps->viewangles[0] - ps->viewangles[0]) > 1.0f ||
- ABS(pps->viewangles[1] - ps->viewangles[1]) > 1.0f ||
- ABS(pps->viewangles[2] - ps->viewangles[2]) > 1.0f ) {
- return 12;
- }
-
- if ( pps->viewheight != ps->viewheight ) {
- return 13;
- }
-
- if ( pps->damageEvent != ps->damageEvent ||
- pps->damageYaw != ps->damageYaw ||
- pps->damagePitch != ps->damagePitch ||
- pps->damageCount != ps->damageCount ) {
- return 14;
- }
-
- for ( i = 0; i < MAX_STATS; i++ ) {
- if ( pps->stats[i] != ps->stats[i] ) {
- return 15;
- }
- }
-
- for ( i = 0; i < MAX_PERSISTANT; i++ ) {
- if ( pps->persistant[i] != ps->persistant[i] ) {
- return 16;
- }
- }
-
- for ( i = 0; i < MAX_POWERUPS; i++ ) {
- if ( pps->powerups[i] != ps->powerups[i] ) {
- return 17;
- }
- }
-
- for ( i = 0; i < MAX_WEAPONS; i++ ) {
- if ( pps->ammo[i] != ps->ammo[i] ) {
- return 18;
- }
- }
-
- if ( pps->generic1 != ps->generic1 ||
- pps->loopSound != ps->loopSound ||
- pps->jumppad_ent != ps->jumppad_ent ) {
- return 19;
- }
-
- return 0;
-}
-//unlagged - optimized prediction
-
-/*
-=================
-CG_PredictPlayerState
-
-Generates cg.predictedPlayerState for the current cg.time
-cg.predictedPlayerState is guaranteed to be valid after exiting.
-
-For demo playback, this will be an interpolation between two valid
-playerState_t.
-
-For normal gameplay, it will be the result of predicted usercmd_t on
-top of the most recent playerState_t received from the server.
-
-Each new snapshot will usually have one or more new usercmd over the last,
-but we simulate all unacknowledged commands each time, not just the new ones.
-This means that on an internet connection, quite a few pmoves may be issued
-each frame.
-
-OPTIMIZE: don't re-simulate unless the newly arrived snapshot playerState_t
-differs from the predicted one. Would require saving all intermediate
-playerState_t during prediction.
-
-We detect prediction errors and allow them to be decayed off over several frames
-to ease the jerk.
-=================
-*/
-void CG_PredictPlayerState( void ) {
- int cmdNum, current;
- playerState_t oldPlayerState;
- qboolean moved;
- usercmd_t oldestCmd;
- usercmd_t latestCmd;
-//unlagged - optimized prediction
- int stateIndex = 0, predictCmd = 0; //Sago: added initializing
- int numPredicted = 0, numPlayedBack = 0; // debug code
-//unlagged - optimized prediction
-
- cg.hyperspace = qfalse; // will be set if touching a trigger_teleport
-
- // if this is the first frame we must guarantee
- // predictedPlayerState is valid even if there is some
- // other error condition
- if ( !cg.validPPS ) {
- cg.validPPS = qtrue;
- cg.predictedPlayerState = cg.snap->ps;
- }
-
-
- // demo playback just copies the moves
- if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
- CG_InterpolatePlayerState( qfalse );
- return;
- }
-
- // non-predicting local movement will grab the latest angles
- if ( cg_nopredict.integer || cg_synchronousClients.integer ) {
- CG_InterpolatePlayerState( qtrue );
- return;
- }
-
- // prepare for pmove
- cg_pmove.ps = &cg.predictedPlayerState;
- cg_pmove.trace = CG_Trace;
- cg_pmove.pointcontents = CG_PointContents;
- if ( cg_pmove.ps->pm_type == PM_DEAD ) {
- cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
- }
- else {
- cg_pmove.tracemask = MASK_PLAYERSOLID;
- }
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
- cg_pmove.tracemask &= ~CONTENTS_BODY; // spectators can fly through bodies
- }
- cg_pmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0;
-
- // save the state before the pmove so we can detect transitions
- oldPlayerState = cg.predictedPlayerState;
-
- current = trap_GetCurrentCmdNumber();
-
- // if we don't have the commands right after the snapshot, we
- // can't accurately predict a current position, so just freeze at
- // the last good position we had
- cmdNum = current - CMD_BACKUP + 1;
- trap_GetUserCmd( cmdNum, &oldestCmd );
- if ( oldestCmd.serverTime > cg.snap->ps.commandTime
- && oldestCmd.serverTime < cg.time ) { // special check for map_restart
- if ( cg_showmiss.integer ) {
- CG_Printf ("exceeded PACKET_BACKUP on commands\n");
- }
- return;
- }
-
- // get the latest command so we can know which commands are from previous map_restarts
- trap_GetUserCmd( current, &latestCmd );
-
- // get the most recent information we have, even if
- // the server time is beyond our current cg.time,
- // because predicted player positions are going to
- // be ahead of everything else anyway
- if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
- cg.predictedPlayerState = cg.nextSnap->ps;
- cg.physicsTime = cg.nextSnap->serverTime;
- } else {
- cg.predictedPlayerState = cg.snap->ps;
- cg.physicsTime = cg.snap->serverTime;
- }
-
- if ( pmove_msec.integer < 8 ) {
- trap_Cvar_Set("pmove_msec", "8");
- }
- else if (pmove_msec.integer > 33) {
- trap_Cvar_Set("pmove_msec", "33");
- }
-
- cg_pmove.pmove_fixed = pmove_fixed.integer;// | cg_pmove_fixed.integer;
- cg_pmove.pmove_msec = pmove_msec.integer;
- cg_pmove.pmove_float = pmove_float.integer;
-
-
-//unlagged - optimized prediction
- // Like the comments described above, a player's state is entirely
- // re-predicted from the last valid snapshot every client frame, which
- // can be really, really, really slow. Every old command has to be
- // run again. For every client frame that is *not* directly after a
- // snapshot, this is unnecessary, since we have no new information.
- // For those, we'll play back the predictions from the last frame and
- // predict only the newest commands. Essentially, we'll be doing
- // an incremental predict instead of a full predict.
- //
- // If we have a new snapshot, we can compare its player state's command
- // time to the command times in the queue to find a match. If we find
- // a matching state, and the predicted version has not deviated, we can
- // use the predicted state as a base - and also do an incremental predict.
- //
- // With this method, we get incremental predicts on every client frame
- // except a frame following a new snapshot in which there was a prediction
- // error. This yeilds anywhere from a 15% to 40% performance increase,
- // depending on how much of a bottleneck the CPU is.
-
- if ( cg_optimizePrediction.integer ) {
- if ( cg.nextFrameTeleport || cg.thisFrameTeleport ) {
- // do a full predict
- cg.lastPredictedCommand = 0;
- cg.stateTail = cg.stateHead;
- predictCmd = current - CMD_BACKUP + 1;
- }
- // cg.physicsTime is the current snapshot's serverTime
- // if it's the same as the last one
- else if ( cg.physicsTime == cg.lastServerTime ) {
- // we have no new information, so do an incremental predict
- predictCmd = cg.lastPredictedCommand + 1;
- }
- else {
- // we have a new snapshot
-
- int i;
- qboolean error = qtrue;
-
- // loop through the saved states queue
- for ( i = cg.stateHead; i != cg.stateTail; i = (i + 1) % NUM_SAVED_STATES ) {
- // if we find a predicted state whose commandTime matches the snapshot player state's commandTime
- if ( cg.savedPmoveStates[i].commandTime == cg.predictedPlayerState.commandTime ) {
- // make sure the state differences are acceptable
- int errorcode = IsUnacceptableError( &cg.predictedPlayerState, &cg.savedPmoveStates[i] );
-
- // too much change?
- if ( errorcode ) {
- if ( cg_showmiss.integer ) {
- CG_Printf("errorcode %d at %d\n", errorcode, cg.time);
- }
- // yeah, so do a full predict
- break;
- }
-
- // this one is almost exact, so we'll copy it in as the starting point
- *cg_pmove.ps = cg.savedPmoveStates[i];
- // advance the head
- cg.stateHead = (i + 1) % NUM_SAVED_STATES;
-
- // set the next command to predict
- predictCmd = cg.lastPredictedCommand + 1;
-
- // a saved state matched, so flag it
- error = qfalse;
- break;
- }
- }
-
- // if no saved states matched
- if ( error ) {
- // do a full predict
- cg.lastPredictedCommand = 0;
- cg.stateTail = cg.stateHead;
- predictCmd = current - CMD_BACKUP + 1;
- }
- }
-
- // keep track of the server time of the last snapshot so we
- // know when we're starting from a new one in future calls
- cg.lastServerTime = cg.physicsTime;
- stateIndex = cg.stateHead;
- }
-//unlagged - optimized prediction
-
- // run cmds
- moved = qfalse;
- for ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) {
- // get the command
- trap_GetUserCmd( cmdNum, &cg_pmove.cmd );
-
- if ( cg_pmove.pmove_fixed ) {
- PM_UpdateViewAngles( cg_pmove.ps, &cg_pmove.cmd );
- }
-
- // don't do anything if the time is before the snapshot player time
- if ( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime ) {
- continue;
- }
-
- // don't do anything if the command was from a previous map_restart
- if ( cg_pmove.cmd.serverTime > latestCmd.serverTime ) {
- continue;
- }
-
- // check for a prediction error from last frame
- // on a lan, this will often be the exact value
- // from the snapshot, but on a wan we will have
- // to predict several commands to get to the point
- // we want to compare
- if ( cg.predictedPlayerState.commandTime == oldPlayerState.commandTime ) {
- vec3_t delta;
- float len;
-
- if ( cg.thisFrameTeleport ) {
- // a teleport will not cause an error decay
- VectorClear( cg.predictedError );
- if ( cg_showmiss.integer ) {
- CG_Printf( "PredictionTeleport\n" );
- }
- cg.thisFrameTeleport = qfalse;
- } else {
- vec3_t adjusted;
- CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
- cg.predictedPlayerState.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted );
-
- if ( cg_showmiss.integer ) {
- if (!VectorCompare( oldPlayerState.origin, adjusted )) {
- CG_Printf("prediction error\n");
- }
- }
- VectorSubtract( oldPlayerState.origin, adjusted, delta );
- len = VectorLength( delta );
- if ( len > 0.1 ) {
- if ( cg_showmiss.integer ) {
- CG_Printf("Prediction miss: %f\n", len);
- }
- if ( cg_errorDecay.integer ) {
- int t;
- float f;
-
- t = cg.time - cg.predictedErrorTime;
- f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
- if ( f < 0 ) {
- f = 0;
- }
- if ( f > 0 && cg_showmiss.integer ) {
- CG_Printf("Double prediction decay: %f\n", f);
- }
- VectorScale( cg.predictedError, f, cg.predictedError );
- } else {
- VectorClear( cg.predictedError );
- }
- VectorAdd( delta, cg.predictedError, cg.predictedError );
- cg.predictedErrorTime = cg.oldTime;
- }
- }
- }
-
- // don't predict gauntlet firing, which is only supposed to happen
- // when it actually inflicts damage
- cg_pmove.gauntletHit = qfalse;
-
- if ( cg_pmove.pmove_fixed ) {
- cg_pmove.cmd.serverTime = ((cg_pmove.cmd.serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;
- }
-
-//unlagged - optimized prediction
- if ( cg_optimizePrediction.integer ) {
- // if we need to predict this command, or we've run out of space in the saved states queue
- if ( cmdNum >= predictCmd || (stateIndex + 1) % NUM_SAVED_STATES == cg.stateHead ) {
- // run the Pmove
- Pmove (&cg_pmove);
-
- numPredicted++; // debug code
-
- // record the last predicted command
- cg.lastPredictedCommand = cmdNum;
-
- // if we haven't run out of space in the saved states queue
- if ( (stateIndex + 1) % NUM_SAVED_STATES != cg.stateHead ) {
- // save the state for the false case (of cmdNum >= predictCmd)
- // in later calls to this function
- cg.savedPmoveStates[stateIndex] = *cg_pmove.ps;
- stateIndex = (stateIndex + 1) % NUM_SAVED_STATES;
- cg.stateTail = stateIndex;
- }
- }
- else {
- numPlayedBack++; // debug code
-
- if ( cg_showmiss.integer &&
- cg.savedPmoveStates[stateIndex].commandTime != cg_pmove.cmd.serverTime) {
- // this should ONLY happen just after changing the value of pmove_fixed
- CG_Printf( "saved state miss\n" );
- }
-
- // play back the command from the saved states
- *cg_pmove.ps = cg.savedPmoveStates[stateIndex];
-
- // go to the next element in the saved states array
- stateIndex = (stateIndex + 1) % NUM_SAVED_STATES;
- }
- }
- else {
- // run the Pmove
- Pmove (&cg_pmove);
-
- numPredicted++; // debug code
- }
-//unlagged - optimized prediction
-
- moved = qtrue;
-
- // add push trigger movement effects
- CG_TouchTriggerPrediction();
-
- // check for predictable events that changed from previous predictions
- //CG_CheckChangedPredictableEvents(&cg.predictedPlayerState);
- }
-
-//unlagged - optimized prediction
- // do a /condump after a few seconds of this
- //CG_Printf("cg.time: %d, numPredicted: %d, numPlayedBack: %d\n", cg.time, numPredicted, numPlayedBack); // debug code
- // if everything is working right, numPredicted should be 1 more than 98%
- // of the time, meaning only ONE predicted move was done in the frame
- // you should see other values for numPredicted after IsUnacceptableError
- // returns nonzero, and that's it
-//unlagged - optimized prediction
-
- if ( cg_showmiss.integer > 1 ) {
- CG_Printf( "[%i : %i] ", cg_pmove.cmd.serverTime, cg.time );
- }
-
- if ( !moved ) {
- if ( cg_showmiss.integer ) {
- CG_Printf( "not moved\n" );
- }
- return;
- }
-
- // adjust for the movement of the groundentity
- CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
- cg.predictedPlayerState.groundEntityNum,
- cg.physicsTime, cg.time, cg.predictedPlayerState.origin );
-
- if ( cg_showmiss.integer ) {
- if (cg.predictedPlayerState.eventSequence > oldPlayerState.eventSequence + MAX_PS_EVENTS) {
- CG_Printf("WARNING: dropped event\n");
- }
- }
-
- // fire events and other transition triggered things
- CG_TransitionPlayerState( &cg.predictedPlayerState, &oldPlayerState );
-
- if ( cg_showmiss.integer ) {
- if (cg.eventSequence > cg.predictedPlayerState.eventSequence) {
- CG_Printf("WARNING: double event\n");
- cg.eventSequence = cg.predictedPlayerState.eventSequence;
- }
- }
-}
-
-
diff --git a/game/code/cgame/cg_public.h b/game/code/cgame/cg_public.h
deleted file mode 100644
index 7449d38..0000000
--- a/game/code/cgame/cg_public.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-
-#define CMD_BACKUP 64
-#define CMD_MASK (CMD_BACKUP - 1)
-// allow a lot of command backups for very fast systems
-// multiple commands may be combined into a single packet, so this
-// needs to be larger than PACKET_BACKUP
-
-
-#define MAX_ENTITIES_IN_SNAPSHOT 256
-
-// snapshots are a view of the server at a given time
-
-// Snapshots are generated at regular time intervals by the server,
-// but they may not be sent if a client's rate level is exceeded, or
-// they may be dropped by the network.
-typedef struct {
- int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
- int ping;
-
- int serverTime; // server time the message is valid for (in msec)
-
- byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
-
- playerState_t ps; // complete information about the current player at this time
-
- int numEntities; // all of the entities that need to be presented
- entityState_t entities[MAX_ENTITIES_IN_SNAPSHOT]; // at the time of this snapshot
-
- int numServerCommands; // text based server commands to execute when this
- int serverCommandSequence; // snapshot becomes current
-} snapshot_t;
-
-enum {
- CGAME_EVENT_NONE,
- CGAME_EVENT_TEAMMENU,
- CGAME_EVENT_SCOREBOARD,
- CGAME_EVENT_EDITHUD
-};
-
-
-/*
-==================================================================
-
-functions imported from the main executable
-
-==================================================================
-*/
-
-#define CGAME_IMPORT_API_VERSION 4
-
-typedef enum {
- CG_PRINT,
- CG_ERROR,
- CG_MILLISECONDS,
- CG_CVAR_REGISTER,
- CG_CVAR_UPDATE,
- CG_CVAR_SET,
- CG_CVAR_VARIABLESTRINGBUFFER,
- CG_ARGC,
- CG_ARGV,
- CG_ARGS,
- CG_FS_FOPENFILE,
- CG_FS_READ,
- CG_FS_WRITE,
- CG_FS_FCLOSEFILE,
- CG_SENDCONSOLECOMMAND,
- CG_ADDCOMMAND,
- CG_SENDCLIENTCOMMAND,
- CG_UPDATESCREEN,
- CG_CM_LOADMAP,
- CG_CM_NUMINLINEMODELS,
- CG_CM_INLINEMODEL,
- CG_CM_LOADMODEL,
- CG_CM_TEMPBOXMODEL,
- CG_CM_POINTCONTENTS,
- CG_CM_TRANSFORMEDPOINTCONTENTS,
- CG_CM_BOXTRACE,
- CG_CM_TRANSFORMEDBOXTRACE,
- CG_CM_MARKFRAGMENTS,
- CG_S_STARTSOUND,
- CG_S_STARTLOCALSOUND,
- CG_S_CLEARLOOPINGSOUNDS,
- CG_S_ADDLOOPINGSOUND,
- CG_S_UPDATEENTITYPOSITION,
- CG_S_RESPATIALIZE,
- CG_S_REGISTERSOUND,
- CG_S_STARTBACKGROUNDTRACK,
- CG_R_LOADWORLDMAP,
- CG_R_REGISTERMODEL,
- CG_R_REGISTERSKIN,
- CG_R_REGISTERSHADER,
- CG_R_CLEARSCENE,
- CG_R_ADDREFENTITYTOSCENE,
- CG_R_ADDPOLYTOSCENE,
- CG_R_ADDLIGHTTOSCENE,
- CG_R_RENDERSCENE,
- CG_R_SETCOLOR,
- CG_R_DRAWSTRETCHPIC,
- CG_R_MODELBOUNDS,
- CG_R_LERPTAG,
- CG_GETGLCONFIG,
- CG_GETGAMESTATE,
- CG_GETCURRENTSNAPSHOTNUMBER,
- CG_GETSNAPSHOT,
- CG_GETSERVERCOMMAND,
- CG_GETCURRENTCMDNUMBER,
- CG_GETUSERCMD,
- CG_SETUSERCMDVALUE,
- CG_R_REGISTERSHADERNOMIP,
- CG_MEMORY_REMAINING,
- CG_R_REGISTERFONT,
- CG_KEY_ISDOWN,
- CG_KEY_GETCATCHER,
- CG_KEY_SETCATCHER,
- CG_KEY_GETKEY,
- CG_PC_ADD_GLOBAL_DEFINE,
- CG_PC_LOAD_SOURCE,
- CG_PC_FREE_SOURCE,
- CG_PC_READ_TOKEN,
- CG_PC_SOURCE_FILE_AND_LINE,
- CG_S_STOPBACKGROUNDTRACK,
- CG_REAL_TIME,
- CG_SNAPVECTOR,
- CG_REMOVECOMMAND,
- CG_R_LIGHTFORPOINT,
- CG_CIN_PLAYCINEMATIC,
- CG_CIN_STOPCINEMATIC,
- CG_CIN_RUNCINEMATIC,
- CG_CIN_DRAWCINEMATIC,
- CG_CIN_SETEXTENTS,
- CG_R_REMAP_SHADER,
- CG_S_ADDREALLOOPINGSOUND,
- CG_S_STOPLOOPINGSOUND,
-
- CG_CM_TEMPCAPSULEMODEL,
- CG_CM_CAPSULETRACE,
- CG_CM_TRANSFORMEDCAPSULETRACE,
- CG_R_ADDADDITIVELIGHTTOSCENE,
- CG_GET_ENTITY_TOKEN,
- CG_R_ADDPOLYSTOSCENE,
- CG_R_INPVS,
- // 1.32
- CG_FS_SEEK,
-
-/*
- CG_LOADCAMERA,
- CG_STARTCAMERA,
- CG_GETCAMERAINFO,
-*/
-
- CG_MEMSET = 100,
- CG_MEMCPY,
- CG_STRNCPY,
- CG_SIN,
- CG_COS,
- CG_ATAN2,
- CG_SQRT,
- CG_FLOOR,
- CG_CEIL,
- CG_TESTPRINTINT,
- CG_TESTPRINTFLOAT,
- CG_ACOS
-} cgameImport_t;
-
-
-/*
-==================================================================
-
-functions exported to the main executable
-
-==================================================================
-*/
-
-typedef enum {
- CG_INIT,
-// void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
- // called when the level loads or when the renderer is restarted
- // all media should be registered at this time
- // cgame will display loading status by calling SCR_Update, which
- // will call CG_DrawInformation during the loading process
- // reliableCommandSequence will be 0 on fresh loads, but higher for
- // demos, tourney restarts, or vid_restarts
-
- CG_SHUTDOWN,
-// void (*CG_Shutdown)( void );
- // oportunity to flush and close any open files
-
- CG_CONSOLE_COMMAND,
-// qboolean (*CG_ConsoleCommand)( void );
- // a console command has been issued locally that is not recognized by the
- // main game system.
- // use Cmd_Argc() / Cmd_Argv() to read the command, return qfalse if the
- // command is not known to the game
-
- CG_DRAW_ACTIVE_FRAME,
-// void (*CG_DrawActiveFrame)( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
- // Generates and draws a game scene and status information at the given time.
- // If demoPlayback is set, local movement prediction will not be enabled
-
- CG_CROSSHAIR_PLAYER,
-// int (*CG_CrosshairPlayer)( void );
-
- CG_LAST_ATTACKER,
-// int (*CG_LastAttacker)( void );
-
- CG_KEY_EVENT,
-// void (*CG_KeyEvent)( int key, qboolean down );
-
- CG_MOUSE_EVENT,
-// void (*CG_MouseEvent)( int dx, int dy );
- CG_EVENT_HANDLING
-// void (*CG_EventHandling)(int type);
-} cgameExport_t;
-
-//----------------------------------------------
diff --git a/game/code/cgame/cg_scoreboard.c b/game/code/cgame/cg_scoreboard.c
deleted file mode 100644
index 0d527a5..0000000
--- a/game/code/cgame/cg_scoreboard.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_scoreboard -- draw the scoreboard on top of the game screen
-#include "cg_local.h"
-
-
-#define SCOREBOARD_X (0)
-
-#define SB_HEADER 86
-#define SB_TOP (SB_HEADER+32)
-
-// Where the status bar starts, so we don't overwrite it
-#define SB_STATUSBAR 420
-
-#define SB_NORMAL_HEIGHT 40
-#define SB_INTER_HEIGHT 16 // interleaved height
-
-#define SB_MAXCLIENTS_NORMAL ((SB_STATUSBAR - SB_TOP) / SB_NORMAL_HEIGHT)
-#define SB_MAXCLIENTS_INTER ((SB_STATUSBAR - SB_TOP) / SB_INTER_HEIGHT - 1)
-
-// Used when interleaved
-
-
-
-#define SB_LEFT_BOTICON_X (SCOREBOARD_X+0)
-#define SB_LEFT_HEAD_X (SCOREBOARD_X+32)
-#define SB_RIGHT_BOTICON_X (SCOREBOARD_X+64)
-#define SB_RIGHT_HEAD_X (SCOREBOARD_X+96)
-// Normal
-#define SB_BOTICON_X (SCOREBOARD_X+32)
-#define SB_HEAD_X (SCOREBOARD_X+64)
-
-#define SB_SCORELINE_X 112
-
-#define SB_RATING_WIDTH (6 * BIGCHAR_WIDTH) // width 6
-#define SB_SCORE_X (SB_SCORELINE_X + BIGCHAR_WIDTH) // width 6
-#define SB_RATING_X (SB_SCORELINE_X + 6 * BIGCHAR_WIDTH) // width 6
-#define SB_PING_X (SB_SCORELINE_X + 12 * BIGCHAR_WIDTH + 8) // width 5
-#define SB_TIME_X (SB_SCORELINE_X + 17 * BIGCHAR_WIDTH + 8) // width 5
-#define SB_NAME_X (SB_SCORELINE_X + 22 * BIGCHAR_WIDTH) // width 15
-
-// The new and improved score board
-//
-// In cases where the number of clients is high, the score board heads are interleaved
-// here's the layout
-
-//
-// 0 32 80 112 144 240 320 400 <-- pixel position
-// bot head bot head score ping time name
-//
-// wins/losses are drawn on bot icon now
-
-static qboolean localClient; // true if local client has been displayed
-
-
- /*
-=================
-CG_DrawScoreboard
-=================
-*/
-static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) {
- char string[1024];
- vec3_t headAngles;
- clientInfo_t *ci;
- int iconx, headx;
-
- if ( score->client < 0 || score->client >= cgs.maxclients ) {
- Com_Printf( "Bad score->client: %i\n", score->client );
- return;
- }
-
- ci = &cgs.clientinfo[score->client];
-
- iconx = SB_BOTICON_X + (SB_RATING_WIDTH / 2);
- headx = SB_HEAD_X + (SB_RATING_WIDTH / 2);
-
- // draw the handicap or bot skill marker (unless player has flag)
- if ( ci->powerups & ( 1 << PW_NEUTRALFLAG ) ) {
- if( largeFormat ) {
- CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_FREE, qfalse );
- }
- else {
- CG_DrawFlagModel( iconx, y, 16, 16, TEAM_FREE, qfalse );
- }
- } else if ( ci->powerups & ( 1 << PW_REDFLAG ) ) {
- if( largeFormat ) {
- CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_RED, qfalse );
- }
- else {
- CG_DrawFlagModel( iconx, y, 16, 16, TEAM_RED, qfalse );
- }
- } else if ( ci->powerups & ( 1 << PW_BLUEFLAG ) ) {
- if( largeFormat ) {
- CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_BLUE, qfalse );
- }
- else {
- CG_DrawFlagModel( iconx, y, 16, 16, TEAM_BLUE, qfalse );
- }
- } else {
- if ( ci->botSkill > 0 && ci->botSkill <= 5 ) {
- if ( cg_drawIcons.integer ) {
- if( largeFormat ) {
- CG_DrawPic( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
- }
- else {
- CG_DrawPic( iconx, y, 16, 16, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
- }
- }
- } else if ( ci->handicap < 100 ) {
- Com_sprintf( string, sizeof( string ), "%i", ci->handicap );
- if ( cgs.gametype == GT_TOURNAMENT )
- CG_DrawSmallStringColor( iconx, y - SMALLCHAR_HEIGHT/2, string, color );
- else
- CG_DrawSmallStringColor( iconx, y, string, color );
- }
-
- // draw the wins / losses
- if ( cgs.gametype == GT_TOURNAMENT ) {
- Com_sprintf( string, sizeof( string ), "%i/%i", ci->wins, ci->losses );
- if( ci->handicap < 100 && !ci->botSkill ) {
- CG_DrawSmallStringColor( iconx, y + SMALLCHAR_HEIGHT/2, string, color );
- }
- else {
- CG_DrawSmallStringColor( iconx, y, string, color );
- }
- }
- }
-
- // draw the face
- VectorClear( headAngles );
- headAngles[YAW] = 180;
- if( largeFormat ) {
- CG_DrawHead( headx, y - ( ICON_SIZE - BIGCHAR_HEIGHT ) / 2, ICON_SIZE, ICON_SIZE,
- score->client, headAngles );
- }
- else {
- CG_DrawHead( headx, y, 16, 16, score->client, headAngles );
- }
-
-#ifdef MISSIONPACK
- // draw the team task
- if ( ci->teamTask != TEAMTASK_NONE ) {
- if (ci->isDead) {
- CG_DrawPic( headx + 48, y, 16, 16, cgs.media.deathShader );
- }
- else if ( ci->teamTask == TEAMTASK_OFFENSE ) {
- CG_DrawPic( headx + 48, y, 16, 16, cgs.media.assaultShader );
- }
- else if ( ci->teamTask == TEAMTASK_DEFENSE ) {
- CG_DrawPic( headx + 48, y, 16, 16, cgs.media.defendShader );
- }
- }
-#endif
- // draw the score line
- if ( score->ping == -1 ) {
- Com_sprintf(string, sizeof(string),
- " connecting %s", ci->name);
- } else if ( ci->team == TEAM_SPECTATOR ) {
- Com_sprintf(string, sizeof(string),
- " SPECT %3i %4i %s", score->ping, score->time, ci->name);
- } else {
- /*if(cgs.gametype == GT_LMS)
- Com_sprintf(string, sizeof(string),
- "%5i %4i %4i %s *%i*", score->score, score->ping, score->time, ci->name, ci->isDead);
- else*/
- /*if(ci->isDead)
- Com_sprintf(string, sizeof(string),
- "%5i %4i %4i %s *DEAD*", score->score, score->ping, score->time, ci->name);
- else*/
- Com_sprintf(string, sizeof(string),
- "%5i %4i %4i %s", score->score, score->ping, score->time, ci->name);
- }
-
- // highlight your position
- if ( score->client == cg.snap->ps.clientNum ) {
- float hcolor[4];
- int rank;
-
- localClient = qtrue;
-
- if ( ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) ||
- ( ( cgs.gametype >= GT_TEAM ) &&
- ( cgs.ffa_gt != 1 ) ) ) {
- // Sago: I think this means that it doesn't matter if two players are tied in team game - only team score counts
- rank = -1;
- } else {
- rank = cg.snap->ps.persistant[PERS_RANK] & ~RANK_TIED_FLAG;
- }
- if ( rank == 0 ) {
- hcolor[0] = 0;
- hcolor[1] = 0;
- hcolor[2] = 0.7f;
- } else if ( rank == 1 ) {
- hcolor[0] = 0.7f;
- hcolor[1] = 0;
- hcolor[2] = 0;
- } else if ( rank == 2 ) {
- hcolor[0] = 0.7f;
- hcolor[1] = 0.7f;
- hcolor[2] = 0;
- } else {
- hcolor[0] = 0.7f;
- hcolor[1] = 0.7f;
- hcolor[2] = 0.7f;
- }
-
- hcolor[3] = fade * 0.7;
- CG_FillRect( SB_SCORELINE_X + BIGCHAR_WIDTH + (SB_RATING_WIDTH / 2), y,
- 640 - SB_SCORELINE_X - BIGCHAR_WIDTH, BIGCHAR_HEIGHT+1, hcolor );
- }
-
- CG_DrawBigString( SB_SCORELINE_X + (SB_RATING_WIDTH / 2), y, string, fade );
-
- // add the "ready" marker for intermission exiting
- if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) ) {
- CG_DrawBigStringColor( iconx, y, "READY", color );
- } else
- if(cgs.gametype == GT_LMS) {
- CG_DrawBigStringColor( iconx-50, y, va("*%i*",ci->isDead), color );
- } else
- if(ci->isDead) {
- CG_DrawBigStringColor( iconx-60, y, "DEAD", color );
- }
-}
-
-/*
-=================
-CG_TeamScoreboard
-=================
-*/
-static int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, int lineHeight ) {
- int i;
- score_t *score;
- float color[4];
- int count;
- clientInfo_t *ci;
-
- color[0] = color[1] = color[2] = 1.0;
- color[3] = fade;
-
- count = 0;
- for ( i = 0 ; i < cg.numScores && count < maxClients ; i++ ) {
- score = &cg.scores[i];
- ci = &cgs.clientinfo[ score->client ];
-
- if ( team != ci->team ) {
- continue;
- }
-
- CG_DrawClientScore( y + lineHeight * count, score, color, fade, lineHeight == SB_NORMAL_HEIGHT );
-
- count++;
- }
-
- return count;
-}
-
-/*
-=================
-CG_DrawScoreboard
-
-Draw the normal in-game scoreboard
-=================
-*/
-qboolean CG_DrawOldScoreboard( void ) {
- int x, y, w, i, n1, n2;
- float fade;
- float *fadeColor;
- char *s;
- int maxClients;
- int lineHeight;
- int topBorderSize, bottomBorderSize;
-
- // don't draw amuthing if the menu or console is up
- if ( cg_paused.integer ) {
- cg.deferredPlayerLoading = 0;
- return qfalse;
- }
-
- if ( cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- cg.deferredPlayerLoading = 0;
- return qfalse;
- }
-
- // don't draw scoreboard during death while warmup up
- if ( cg.warmup && !cg.showScores ) {
- return qfalse;
- }
-
- if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD ||
- cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- fade = 1.0;
- fadeColor = colorWhite;
- } else {
- fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
-
- if ( !fadeColor ) {
- // next time scoreboard comes up, don't print killer
- cg.deferredPlayerLoading = 0;
- cg.killerName[0] = 0;
- return qfalse;
- }
- fade = *fadeColor;
- }
-
-
- // fragged by ... line
- if ( cg.killerName[0] ) {
- s = va("Fragged by %s", cg.killerName );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- x = ( SCREEN_WIDTH - w ) / 2;
- y = 40;
- CG_DrawBigString( x, y, s, fade );
- }
-
- // current rank
- if ( cgs.gametype < GT_TEAM || cgs.ffa_gt == 1) {
- if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
- s = va("%s place with %i",
- CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
- cg.snap->ps.persistant[PERS_SCORE] );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- x = ( SCREEN_WIDTH - w ) / 2;
- y = 60;
- CG_DrawBigString( x, y, s, fade );
- }
- } else {
- if ( cg.teamScores[0] == cg.teamScores[1] ) {
- s = va("Teams are tied at %i", cg.teamScores[0] );
- } else if ( cg.teamScores[0] >= cg.teamScores[1] ) {
- s = va("Red leads %i to %i",cg.teamScores[0], cg.teamScores[1] );
- } else {
- s = va("Blue leads %i to %i",cg.teamScores[1], cg.teamScores[0] );
- }
-
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- x = ( SCREEN_WIDTH - w ) / 2;
- y = 60;
- CG_DrawBigString( x, y, s, fade );
- }
-
- // scoreboard
- y = SB_HEADER;
-
- CG_DrawPic( SB_SCORE_X + (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardScore );
- CG_DrawPic( SB_PING_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardPing );
- CG_DrawPic( SB_TIME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardTime );
- CG_DrawPic( SB_NAME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardName );
-
- y = SB_TOP;
-
- // If there are more than SB_MAXCLIENTS_NORMAL, use the interleaved scores
- if ( cg.numScores > SB_MAXCLIENTS_NORMAL ) {
- maxClients = SB_MAXCLIENTS_INTER;
- lineHeight = SB_INTER_HEIGHT;
- topBorderSize = 8;
- bottomBorderSize = 16;
- } else {
- maxClients = SB_MAXCLIENTS_NORMAL;
- lineHeight = SB_NORMAL_HEIGHT;
- topBorderSize = 16;
- bottomBorderSize = 16;
- }
-
- localClient = qfalse;
-
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- //
- // teamplay scoreboard
- //
- y += lineHeight/2;
-
- if ( cg.teamScores[0] >= cg.teamScores[1] ) {
- n1 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
- CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );
- y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
- maxClients -= n1;
- n2 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
- CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );
- y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
- maxClients -= n2;
- } else {
- n1 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
- CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );
- y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
- maxClients -= n1;
- n2 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
- CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );
- y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
- maxClients -= n2;
- }
- n1 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients, lineHeight );
- y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
-
- } else {
- //
- // free for all scoreboard
- //
- n1 = CG_TeamScoreboard( y, TEAM_FREE, fade, maxClients, lineHeight );
- y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
- n2 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients - n1, lineHeight );
- y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
- }
-
- if (!localClient) {
- // draw local client at the bottom
- for ( i = 0 ; i < cg.numScores ; i++ ) {
- if ( cg.scores[i].client == cg.snap->ps.clientNum ) {
- CG_DrawClientScore( y, &cg.scores[i], fadeColor, fade, lineHeight == SB_NORMAL_HEIGHT );
- break;
- }
- }
- }
-
- // load any models that have been deferred
- if ( ++cg.deferredPlayerLoading > 10 ) {
- CG_LoadDeferredPlayers();
- }
-
- return qtrue;
-}
-
-//================================================================================
-
-/*
-================
-CG_CenterGiantLine
-================
-*/
-static void CG_CenterGiantLine( float y, const char *string ) {
- float x;
- vec4_t color;
-
- color[0] = 1;
- color[1] = 1;
- color[2] = 1;
- color[3] = 1;
-
- x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( string ) );
-
- CG_DrawStringExt( x, y, string, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
-}
-
-/*
-=================
-CG_DrawTourneyScoreboard
-
-Draw the oversize scoreboard for tournements
-=================
-*/
-void CG_DrawOldTourneyScoreboard( void ) {
- const char *s;
- vec4_t color;
- int min, tens, ones;
- clientInfo_t *ci;
- int y;
- int i;
-
- // request more scores regularly
- if ( cg.scoresRequestTime + 2000 < cg.time ) {
- cg.scoresRequestTime = cg.time;
- trap_SendClientCommand( "score" );
- }
-
- color[0] = 1;
- color[1] = 1;
- color[2] = 1;
- color[3] = 1;
-
- // draw the dialog background
- color[0] = color[1] = color[2] = 0;
- color[3] = 1;
- CG_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, color );
-
- // print the mesage of the day
- s = CG_ConfigString( CS_MOTD );
- if ( !s[0] ) {
- s = "Scoreboard";
- }
-
- // print optional title
- CG_CenterGiantLine( 8, s );
-
- // print server time
- ones = cg.time / 1000;
- min = ones / 60;
- ones %= 60;
- tens = ones / 10;
- ones %= 10;
- s = va("%i:%i%i", min, tens, ones );
-
- CG_CenterGiantLine( 64, s );
-
-
- // print the two scores
-
- y = 160;
- if ( cgs.gametype >= GT_TEAM && cgs.ffa_gt!=1) {
- //
- // teamplay scoreboard
- //
- CG_DrawStringExt( 8, y, "Red Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- s = va("%i", cg.teamScores[0] );
- CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
-
- y += 64;
-
- CG_DrawStringExt( 8, y, "Blue Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- s = va("%i", cg.teamScores[1] );
- CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- } else {
- //
- // free for all scoreboard
- //
- for ( i = 0 ; i < MAX_CLIENTS ; i++ ) {
- ci = &cgs.clientinfo[i];
- if ( !ci->infoValid ) {
- continue;
- }
- if ( ci->team != TEAM_FREE ) {
- continue;
- }
-
- CG_DrawStringExt( 8, y, ci->name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- s = va("%i", ci->score );
- CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- y += 64;
- }
- }
-
-
-}
-
diff --git a/game/code/cgame/cg_servercmds.c b/game/code/cgame/cg_servercmds.c
deleted file mode 100644
index dcdf4e0..0000000
--- a/game/code/cgame/cg_servercmds.c
+++ /dev/null
@@ -1,1357 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_servercmds.c -- reliably sequenced text commands sent by the server
-// these are processed at snapshot transition time, so there will definately
-// be a valid snapshot this frame
-
-#include "cg_local.h"
-#include "../../ui/menudef.h" // bk001205 - for Q3_ui as well
-
-typedef struct {
- const char *order;
- int taskNum;
-} orderTask_t;
-
-static const orderTask_t validOrders[] = {
- { VOICECHAT_GETFLAG, TEAMTASK_OFFENSE },
- { VOICECHAT_OFFENSE, TEAMTASK_OFFENSE },
- { VOICECHAT_DEFEND, TEAMTASK_DEFENSE },
- { VOICECHAT_DEFENDFLAG, TEAMTASK_DEFENSE },
- { VOICECHAT_PATROL, TEAMTASK_PATROL },
- { VOICECHAT_CAMP, TEAMTASK_CAMP },
- { VOICECHAT_FOLLOWME, TEAMTASK_FOLLOW },
- { VOICECHAT_RETURNFLAG, TEAMTASK_RETRIEVE },
- { VOICECHAT_FOLLOWFLAGCARRIER, TEAMTASK_ESCORT }
-};
-
-static const int numValidOrders = sizeof(validOrders) / sizeof(orderTask_t);
-
-#ifdef MISSIONPACK // bk001204
-static int CG_ValidOrder(const char *p) {
- int i;
- for (i = 0; i < numValidOrders; i++) {
- if (Q_stricmp(p, validOrders[i].order) == 0) {
- return validOrders[i].taskNum;
- }
- }
- return -1;
-}
-#endif
-
-/*
-=================
-CG_ParseScores
-
-=================
-*/
-static void CG_ParseScores( void ) {
- int i, powerups;
-
- cg.numScores = atoi( CG_Argv( 1 ) );
- if ( cg.numScores > MAX_CLIENTS ) {
- cg.numScores = MAX_CLIENTS;
- }
-
- cg.teamScores[0] = atoi( CG_Argv( 2 ) );
- cg.teamScores[1] = atoi( CG_Argv( 3 ) );
-
- cgs.roundStartTime = atoi( CG_Argv( 4 ) );
-
- //Update thing in lower-right corner
- if(cgs.gametype == GT_ELIMINATION || cgs.gametype == GT_CTF_ELIMINATION)
- {
- cgs.scores1 = cg.teamScores[0];
- cgs.scores2 = cg.teamScores[1];
- }
-
- memset( cg.scores, 0, sizeof( cg.scores ) );
-
-#define NUM_DATA 15
-#define FIRST_DATA 4
-
- for ( i = 0 ; i < cg.numScores ; i++ ) {
- //
- cg.scores[i].client = atoi( CG_Argv( i * NUM_DATA + FIRST_DATA + 1 ) );
- cg.scores[i].score = atoi( CG_Argv( i * NUM_DATA + FIRST_DATA + 2 ) );
- cg.scores[i].ping = atoi( CG_Argv( i * NUM_DATA + FIRST_DATA + 3 ) );
- cg.scores[i].time = atoi( CG_Argv( i * NUM_DATA + FIRST_DATA + 4 ) );
- cg.scores[i].scoreFlags = atoi( CG_Argv( i * NUM_DATA + FIRST_DATA + 5 ) );
- powerups = atoi( CG_Argv( i * NUM_DATA + FIRST_DATA + 6 ) );
- cg.scores[i].accuracy = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 7));
- cg.scores[i].impressiveCount = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 8));
- cg.scores[i].excellentCount = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 9));
- cg.scores[i].guantletCount = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 10));
- cg.scores[i].defendCount = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 11));
- cg.scores[i].assistCount = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 12));
- cg.scores[i].perfect = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 13));
- cg.scores[i].captures = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 14));
- cg.scores[i].isDead = atoi(CG_Argv(i * NUM_DATA + FIRST_DATA + 15));
- //cgs.roundStartTime =
-
- if ( cg.scores[i].client < 0 || cg.scores[i].client >= MAX_CLIENTS ) {
- cg.scores[i].client = 0;
- }
- cgs.clientinfo[ cg.scores[i].client ].score = cg.scores[i].score;
- cgs.clientinfo[ cg.scores[i].client ].powerups = powerups;
- cgs.clientinfo[ cg.scores[i].client ].isDead = cg.scores[i].isDead;
-
- cg.scores[i].team = cgs.clientinfo[cg.scores[i].client].team;
- }
-#ifdef MISSIONPACK
- CG_SetScoreSelection(NULL);
-#endif
-
-}
-
-/*
-=================
-CG_ParseElimination
-
-=================
-*/
-static void CG_ParseElimination( void ) {
- if(cgs.gametype == GT_ELIMINATION || cgs.gametype == GT_CTF_ELIMINATION)
- {
- cgs.scores1 = atoi( CG_Argv( 1 ) );
- cgs.scores2 = atoi( CG_Argv( 2 ) );
- }
- cgs.roundStartTime = atoi( CG_Argv( 3 ) );
-}
-
-/*
-=================
-CG_ParseMappage
-Sago: This parses values from the server rather directly. Some checks are performed, but beware if you change it or new
-security holes are found
-=================
-*/
-static void CG_ParseMappage( void ) {
- char command[1024];
- const char *temp;
- const char* c;
- int i;
-
- temp = CG_Argv( 1 );
- for( c = temp; *c; ++c) {
- switch(*c) {
- case '\n':
- case '\r':
- case ';':
- //The server tried something bad!
- return;
- break;
- }
- }
- Q_strncpyz(command,va("ui_mappage %s",temp),1024);
- for(i=2;i<12;i++) {
- temp = CG_Argv( i );
- for( c = temp; *c; ++c) {
- switch(*c) {
- case '\n':
- case '\r':
- case ';':
- //The server tried something bad!
- return;
- break;
- }
- }
- if(strlen(temp)<1)
- temp = "---";
- Q_strcat(command,1024,va(" %s ",temp));
- }
- trap_SendConsoleCommand(command);
-
-}
-
-/*
-=================
-CG_ParseDDtimetaken
-
-=================
-*/
-static void CG_ParseDDtimetaken( void ) {
- cgs.timetaken = atoi( CG_Argv( 1 ) );
-}
-
-/*
-=================
-CG_ParseDomPointNames
-=================
-*/
-
-static void CG_ParseDomPointNames( void ) {
- int i,j;
- cgs.domination_points_count = atoi( CG_Argv( 1 ) );
- if(cgs.domination_points_count>=MAX_DOMINATION_POINTS)
- cgs.domination_points_count = MAX_DOMINATION_POINTS;
- for(i = 0;i<cgs.domination_points_count;i++) {
- Q_strncpyz(cgs.domination_points_names[i],CG_Argv(2)+i*MAX_DOMINATION_POINTS_NAMES,MAX_DOMINATION_POINTS_NAMES-1);
- for(j=MAX_DOMINATION_POINTS_NAMES-1; cgs.domination_points_names[i][j] < '0' && j>0; j--) {
- cgs.domination_points_names[i][j] = 0;
- }
- }
-}
-
-/*
-=================
-CG_ParseDomScores
-=================
-*/
-
-static void CG_ParseDomStatus( void ) {
- int i;
- if( cgs.domination_points_count!=atoi( CG_Argv(1) ) ) {
- cgs.domination_points_count = 0;
- return;
- }
- for(i = 0;i<cgs.domination_points_count;i++) {
- cgs.domination_points_status[i] = atoi( CG_Argv(2+i) );
- }
-}
-
-/*
-=================
-CG_ParseChallenge
-=================
-*/
-
-static void CG_ParseChallenge( void ) {
- addChallenge(atoi( CG_Argv(1) ) );
-}
-
-/*
-=================
-CG_ParseTeam
-=================
-*/
-
-static void CG_ParseTeam( void ) {
- //TODO: Add code here
- if(cg_voip_teamonly.integer)
- trap_Cvar_Set("cl_voipSendTarget",CG_Argv(1));
-}
-
-/*
-=================
-CG_ParseAttackingTeam
-
-=================
-*/
-static void CG_ParseAttackingTeam( void ) {
- int temp;
- temp = atoi( CG_Argv( 1 ) );
- if(temp==TEAM_RED)
- cgs.attackingTeam = TEAM_RED;
- else if (temp==TEAM_BLUE)
- cgs.attackingTeam = TEAM_BLUE;
- else
- cgs.attackingTeam = TEAM_NONE; //Should never happen.
-}
-
-/*
-=================
-CG_ParseTeamInfo
-
-=================
-*/
-static void CG_ParseTeamInfo( void ) {
- int i;
- int client;
-
- numSortedTeamPlayers = atoi( CG_Argv( 1 ) );
- if( numSortedTeamPlayers < 0 || numSortedTeamPlayers > TEAM_MAXOVERLAY )
- {
- CG_Error( "CG_ParseTeamInfo: numSortedTeamPlayers out of range (%d)",
- numSortedTeamPlayers );
- return;
- }
-
- for ( i = 0 ; i < numSortedTeamPlayers ; i++ ) {
- client = atoi( CG_Argv( i * 6 + 2 ) );
- if( client < 0 || client >= MAX_CLIENTS )
- {
- CG_Error( "CG_ParseTeamInfo: bad client number: %d", client );
- return;
- }
-
-
- sortedTeamPlayers[i] = client;
-
- cgs.clientinfo[ client ].location = atoi( CG_Argv( i * 6 + 3 ) );
- cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 6 + 4 ) );
- cgs.clientinfo[ client ].armor = atoi( CG_Argv( i * 6 + 5 ) );
- cgs.clientinfo[ client ].curWeapon = atoi( CG_Argv( i * 6 + 6 ) );
- cgs.clientinfo[ client ].powerups = atoi( CG_Argv( i * 6 + 7 ) );
- }
-}
-
-
-/*
-================
-CG_ParseServerinfo
-
-This is called explicitly when the gamestate is first received,
-and whenever the server updates any serverinfo flagged cvars
-================
-*/
-void CG_ParseServerinfo( void ) {
- const char *info;
- char *mapname;
-
- info = CG_ConfigString( CS_SERVERINFO );
- cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
- //By default do as normal:
- cgs.ffa_gt = 0;
- //See if ffa gametype
- if(cgs.gametype == GT_LMS)
- cgs.ffa_gt = 1;
- trap_Cvar_Set("g_gametype", va("%i", cgs.gametype));
- cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) );
- cgs.videoflags = atoi( Info_ValueForKey( info, "videoflags" ) );
- cgs.elimflags = atoi( Info_ValueForKey( info, "elimflags" ) );
- cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) );
- cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) );
- cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) );
- cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) );
- cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
- cgs.roundtime = atoi( Info_ValueForKey( info, "elimination_roundtime" ) );
- cgs.nopickup = atoi( Info_ValueForKey( info, "g_rockets" ) ) + atoi( Info_ValueForKey( info, "g_instantgib" ) ) + atoi( Info_ValueForKey( info, "g_elimination" ) );
- cgs.lms_mode = atoi( Info_ValueForKey( info, "g_lms_mode" ) );
- cgs.altExcellent = atoi( Info_ValueForKey( info, "g_altExcellent" ) );
- mapname = Info_ValueForKey( info, "mapname" );
- Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname );
- Q_strncpyz( cgs.redTeam, Info_ValueForKey( info, "g_redTeam" ), sizeof(cgs.redTeam) );
- trap_Cvar_Set("g_redTeam", cgs.redTeam);
- Q_strncpyz( cgs.blueTeam, Info_ValueForKey( info, "g_blueTeam" ), sizeof(cgs.blueTeam) );
- trap_Cvar_Set("g_blueTeam", cgs.blueTeam);
-
-//unlagged - server options
- // we'll need this for deciding whether or not to predict weapon effects
- cgs.delagHitscan = atoi( Info_ValueForKey( info, "g_delagHitscan" ) );
- trap_Cvar_Set("g_delagHitscan", va("%i", cgs.delagHitscan));
-//unlagged - server options
-
- //Copy allowed votes directly to the client:
- trap_Cvar_Set("cg_voteflags",Info_ValueForKey( info, "voteflags" ) );
-}
-
-/*
-==================
-CG_ParseWarmup
-==================
-*/
-static void CG_ParseWarmup( void ) {
- const char *info;
- int warmup;
-
- info = CG_ConfigString( CS_WARMUP );
-
- warmup = atoi( info );
- cg.warmupCount = -1;
-
- if ( warmup == 0 && cg.warmup ) {
-
- } else if ( warmup > 0 && cg.warmup <= 0 ) {
-#ifdef MISSIONPACK
- if (cgs.gametype >= GT_CTF && cgs.gametype < GT_MAX_GAME_TYPE && !cgs.ffa_gt) {
- trap_S_StartLocalSound( cgs.media.countPrepareTeamSound, CHAN_ANNOUNCER );
- } else
-#endif
- {
- trap_S_StartLocalSound( cgs.media.countPrepareSound, CHAN_ANNOUNCER );
- }
- }
-
- cg.warmup = warmup;
-}
-
-/*
-================
-CG_SetConfigValues
-
-Called on load to set the initial values from configure strings
-================
-*/
-void CG_SetConfigValues( void ) {
- const char *s;
-
- cgs.scores1 = atoi( CG_ConfigString( CS_SCORES1 ) );
- cgs.scores2 = atoi( CG_ConfigString( CS_SCORES2 ) );
- cgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) );
- if( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION || cgs.gametype == GT_DOUBLE_D) {
- s = CG_ConfigString( CS_FLAGSTATUS );
- cgs.redflag = s[0] - '0';
- cgs.blueflag = s[1] - '0';
- }
-//#ifdef MISSIONPACK
- else if( cgs.gametype == GT_1FCTF ) {
- s = CG_ConfigString( CS_FLAGSTATUS );
- cgs.flagStatus = s[0] - '0';
- }
-//#endif
- cg.warmup = atoi( CG_ConfigString( CS_WARMUP ) );
-}
-
-/*
-=====================
-CG_ShaderStateChanged
-=====================
-*/
-void CG_ShaderStateChanged(void) {
- char originalShader[MAX_QPATH];
- char newShader[MAX_QPATH];
- char timeOffset[16];
- const char *o;
- char *n,*t;
-
- o = CG_ConfigString( CS_SHADERSTATE );
- while (o && *o) {
- n = strstr(o, "=");
- if (n && *n) {
- strncpy(originalShader, o, n-o);
- originalShader[n-o] = 0;
- n++;
- t = strstr(n, ":");
- if (t && *t) {
- strncpy(newShader, n, t-n);
- newShader[t-n] = 0;
- } else {
- break;
- }
- t++;
- o = strstr(t, "@");
- if (o) {
- strncpy(timeOffset, t, o-t);
- timeOffset[o-t] = 0;
- o++;
- trap_R_RemapShader( originalShader, newShader, timeOffset );
- }
- } else {
- break;
- }
- }
-}
-
-/*
-================
-CG_ConfigStringModified
-
-================
-*/
-static void CG_ConfigStringModified( void ) {
- const char *str;
- int num;
-
- num = atoi( CG_Argv( 1 ) );
-
- // get the gamestate from the client system, which will have the
- // new configstring already integrated
- trap_GetGameState( &cgs.gameState );
-
- // look up the individual string that was modified
- str = CG_ConfigString( num );
-
- // do something with it if necessary
- if ( num == CS_MUSIC ) {
- CG_StartMusic();
- } else if ( num == CS_SERVERINFO ) {
- CG_ParseServerinfo();
- } else if ( num == CS_WARMUP ) {
- CG_ParseWarmup();
- } else if ( num == CS_SCORES1 ) {
- cgs.scores1 = atoi( str );
- } else if ( num == CS_SCORES2 ) {
- cgs.scores2 = atoi( str );
- } else if ( num == CS_LEVEL_START_TIME ) {
- cgs.levelStartTime = atoi( str );
- } else if ( num == CS_VOTE_TIME ) {
- cgs.voteTime = atoi( str );
- cgs.voteModified = qtrue;
- } else if ( num == CS_VOTE_YES ) {
- cgs.voteYes = atoi( str );
- cgs.voteModified = qtrue;
- } else if ( num == CS_VOTE_NO ) {
- cgs.voteNo = atoi( str );
- cgs.voteModified = qtrue;
- } else if ( num == CS_VOTE_STRING ) {
- Q_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) );
-#ifdef MISSIONPACK
- trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER );
-#endif //MISSIONPACK
- } else if ( num >= CS_TEAMVOTE_TIME && num <= CS_TEAMVOTE_TIME + 1) {
- cgs.teamVoteTime[num-CS_TEAMVOTE_TIME] = atoi( str );
- cgs.teamVoteModified[num-CS_TEAMVOTE_TIME] = qtrue;
- } else if ( num >= CS_TEAMVOTE_YES && num <= CS_TEAMVOTE_YES + 1) {
- cgs.teamVoteYes[num-CS_TEAMVOTE_YES] = atoi( str );
- cgs.teamVoteModified[num-CS_TEAMVOTE_YES] = qtrue;
- } else if ( num >= CS_TEAMVOTE_NO && num <= CS_TEAMVOTE_NO + 1) {
- cgs.teamVoteNo[num-CS_TEAMVOTE_NO] = atoi( str );
- cgs.teamVoteModified[num-CS_TEAMVOTE_NO] = qtrue;
- } else if ( num >= CS_TEAMVOTE_STRING && num <= CS_TEAMVOTE_STRING + 1) {
- Q_strncpyz( cgs.teamVoteString[num-CS_TEAMVOTE_STRING], str, sizeof( cgs.teamVoteString ) );
-#ifdef MISSIONPACK
- trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER );
-#endif
- } else if ( num == CS_INTERMISSION ) {
- cg.intermissionStarted = atoi( str );
- } else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) {
- cgs.gameModels[ num-CS_MODELS ] = trap_R_RegisterModel( str );
- } else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_SOUNDS ) {
- if ( str[0] != '*' ) { // player specific sounds don't register here
- cgs.gameSounds[ num-CS_SOUNDS] = trap_S_RegisterSound( str, qfalse );
- }
- } else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) {
- CG_NewClientInfo( num - CS_PLAYERS );
- CG_BuildSpectatorString();
- } else if ( num == CS_FLAGSTATUS ) {
- if( cgs.gametype == GT_CTF || cgs.gametype == GT_CTF_ELIMINATION || cgs.gametype == GT_DOUBLE_D) {
- // format is rb where its red/blue, 0 is at base, 1 is taken, 2 is dropped
- cgs.redflag = str[0] - '0';
- cgs.blueflag = str[1] - '0';
- }
-//#ifdef MISSIONPACK
- else if( cgs.gametype == GT_1FCTF ) {
- cgs.flagStatus = str[0] - '0';
- }
-//#endif
- }
- else if ( num == CS_SHADERSTATE ) {
- CG_ShaderStateChanged();
- }
-
-}
-
-
-/*
-=======================
-CG_AddToTeamChat
-
-=======================
-*/
-static void CG_AddToTeamChat( const char *str ) {
- int len;
- char *p, *ls;
- int lastcolor;
- int chatHeight;
-
- if (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT) {
- chatHeight = cg_teamChatHeight.integer;
- } else {
- chatHeight = TEAMCHAT_HEIGHT;
- }
-
- if (chatHeight <= 0 || cg_teamChatTime.integer <= 0) {
- // team chat disabled, dump into normal chat
- cgs.teamChatPos = cgs.teamLastChatPos = 0;
- return;
- }
-
- len = 0;
-
- p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
- *p = 0;
-
- lastcolor = '7';
-
- ls = NULL;
- while (*str) {
- if (len > TEAMCHAT_WIDTH - 1) {
- if (ls) {
- str -= (p - ls);
- str++;
- p -= (p - ls);
- }
- *p = 0;
-
- cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
-
- cgs.teamChatPos++;
- p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
- *p = 0;
- *p++ = Q_COLOR_ESCAPE;
- *p++ = lastcolor;
- len = 0;
- ls = NULL;
- }
-
- if ( Q_IsColorString( str ) ) {
- *p++ = *str++;
- lastcolor = *str;
- *p++ = *str++;
- continue;
- }
- if (*str == ' ') {
- ls = p;
- }
- *p++ = *str++;
- len++;
- }
- *p = 0;
-
- cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
- cgs.teamChatPos++;
-
- if (cgs.teamChatPos - cgs.teamLastChatPos > chatHeight)
- cgs.teamLastChatPos = cgs.teamChatPos - chatHeight;
-}
-
-/*
-===============
-CG_MapRestart
-
-The server has issued a map_restart, so the next snapshot
-is completely new and should not be interpolated to.
-
-A tournement restart will clear everything, but doesn't
-require a reload of all the media
-===============
-*/
-static void CG_MapRestart( void ) {
- if ( cg_showmiss.integer ) {
- CG_Printf( "CG_MapRestart\n" );
- }
-
- CG_InitLocalEntities();
- CG_InitMarkPolys();
- CG_ClearParticles ();
-
- // make sure the "3 frags left" warnings play again
- cg.fraglimitWarnings = 0;
-
- cg.timelimitWarnings = 0;
-
- cg.intermissionStarted = qfalse;
-
- cgs.voteTime = 0;
-
- cg.mapRestart = qtrue;
-
- CG_StartMusic();
-
- trap_S_ClearLoopingSounds(qtrue);
-
- // we really should clear more parts of cg here and stop sounds
-
- // play the "fight" sound if this is a restart without warmup
- if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) {
- trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER );
- CG_CenterPrint( "FIGHT!", 120, GIANTCHAR_WIDTH*2 );
- }
-#ifdef MISSIONPACK
- if (cg_singlePlayerActive.integer) {
- trap_Cvar_Set("ui_matchStartTime", va("%i", cg.time));
- if (cg_recordSPDemo.integer && cg_recordSPDemoName.string && *cg_recordSPDemoName.string) {
- trap_SendConsoleCommand(va("set g_synchronousclients 1 ; record %s \n", cg_recordSPDemoName.string));
- }
- }
-#endif
- trap_Cvar_Set("cg_thirdPerson", "0");
-}
-
-#define MAX_VOICEFILESIZE 16384
-#define MAX_VOICEFILES 8
-#define MAX_VOICECHATS 64
-#define MAX_VOICESOUNDS 64
-#define MAX_CHATSIZE 64
-#define MAX_HEADMODELS 64
-
-typedef struct voiceChat_s
-{
- char id[64];
- int numSounds;
- sfxHandle_t sounds[MAX_VOICESOUNDS];
- char chats[MAX_VOICESOUNDS][MAX_CHATSIZE];
-} voiceChat_t;
-
-typedef struct voiceChatList_s
-{
- char name[64];
- int gender;
- int numVoiceChats;
- voiceChat_t voiceChats[MAX_VOICECHATS];
-} voiceChatList_t;
-
-typedef struct headModelVoiceChat_s
-{
- char headmodel[64];
- int voiceChatNum;
-} headModelVoiceChat_t;
-
-voiceChatList_t voiceChatLists[MAX_VOICEFILES];
-headModelVoiceChat_t headModelVoiceChat[MAX_HEADMODELS];
-
-/*
-=================
-CG_ParseVoiceChats
-=================
-*/
-int CG_ParseVoiceChats( const char *filename, voiceChatList_t *voiceChatList, int maxVoiceChats ) {
- int len, i;
- fileHandle_t f;
- char buf[MAX_VOICEFILESIZE];
- char **p, *ptr;
- char *token;
- voiceChat_t *voiceChats;
- qboolean compress;
- sfxHandle_t sound;
-
- compress = qtrue;
- if (cg_buildScript.integer) {
- compress = qfalse;
- }
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "voice chat file not found: %s\n", filename ) );
- return qfalse;
- }
- if ( len >= MAX_VOICEFILESIZE ) {
- trap_Print( va( S_COLOR_RED "voice chat file too large: %s is %i, max allowed is %i", filename, len, MAX_VOICEFILESIZE ) );
- trap_FS_FCloseFile( f );
- return qfalse;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- ptr = buf;
- p = &ptr;
-
- Com_sprintf(voiceChatList->name, sizeof(voiceChatList->name), "%s", filename);
- voiceChats = voiceChatList->voiceChats;
- for ( i = 0; i < maxVoiceChats; i++ ) {
- voiceChats[i].id[0] = 0;
- }
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return qtrue;
- }
- if (!Q_stricmp(token, "female")) {
- voiceChatList->gender = GENDER_FEMALE;
- }
- else if (!Q_stricmp(token, "male")) {
- voiceChatList->gender = GENDER_MALE;
- }
- else if (!Q_stricmp(token, "neuter")) {
- voiceChatList->gender = GENDER_NEUTER;
- }
- else {
- trap_Print( va( S_COLOR_RED "expected gender not found in voice chat file: %s\n", filename ) );
- return qfalse;
- }
-
- voiceChatList->numVoiceChats = 0;
- while ( 1 ) {
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return qtrue;
- }
- Com_sprintf(voiceChats[voiceChatList->numVoiceChats].id, sizeof( voiceChats[voiceChatList->numVoiceChats].id ), "%s", token);
- token = COM_ParseExt(p, qtrue);
- if (Q_stricmp(token, "{")) {
- trap_Print( va( S_COLOR_RED "expected { found %s in voice chat file: %s\n", token, filename ) );
- return qfalse;
- }
- voiceChats[voiceChatList->numVoiceChats].numSounds = 0;
- while(1) {
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return qtrue;
- }
- if (!Q_stricmp(token, "}"))
- break;
- sound = trap_S_RegisterSound( token, compress );
- voiceChats[voiceChatList->numVoiceChats].sounds[voiceChats[voiceChatList->numVoiceChats].numSounds] = sound;
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return qtrue;
- }
- Com_sprintf(voiceChats[voiceChatList->numVoiceChats].chats[
- voiceChats[voiceChatList->numVoiceChats].numSounds], MAX_CHATSIZE, "%s", token);
- if (sound)
- voiceChats[voiceChatList->numVoiceChats].numSounds++;
- if (voiceChats[voiceChatList->numVoiceChats].numSounds >= MAX_VOICESOUNDS)
- break;
- }
- voiceChatList->numVoiceChats++;
- if (voiceChatList->numVoiceChats >= maxVoiceChats)
- return qtrue;
- }
- return qtrue;
-}
-
-/*
-=================
-CG_LoadVoiceChats
-=================
-*/
-void CG_LoadVoiceChats( void ) {
- int size;
-
- size = trap_MemoryRemaining();
- CG_ParseVoiceChats( "scripts/female1.voice", &voiceChatLists[0], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/female2.voice", &voiceChatLists[1], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/female3.voice", &voiceChatLists[2], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male1.voice", &voiceChatLists[3], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male2.voice", &voiceChatLists[4], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male3.voice", &voiceChatLists[5], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male4.voice", &voiceChatLists[6], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male5.voice", &voiceChatLists[7], MAX_VOICECHATS );
- CG_Printf("voice chat memory size = %d\n", size - trap_MemoryRemaining());
-}
-
-/*
-=================
-CG_HeadModelVoiceChats
-=================
-*/
-int CG_HeadModelVoiceChats( char *filename ) {
- int len, i;
- fileHandle_t f;
- char buf[MAX_VOICEFILESIZE];
- char **p, *ptr;
- char *token;
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- //trap_Print( va( "voice chat file not found: %s\n", filename ) );
- return -1;
- }
- if ( len >= MAX_VOICEFILESIZE ) {
- trap_Print( va( S_COLOR_RED "voice chat file too large: %s is %i, max allowed is %i", filename, len, MAX_VOICEFILESIZE ) );
- trap_FS_FCloseFile( f );
- return -1;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- ptr = buf;
- p = &ptr;
-
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return -1;
- }
-
- for ( i = 0; i < MAX_VOICEFILES; i++ ) {
- if ( !Q_stricmp(token, voiceChatLists[i].name) ) {
- return i;
- }
- }
-
- //FIXME: maybe try to load the .voice file which name is stored in token?
-
- return -1;
-}
-
-
-/*
-=================
-CG_GetVoiceChat
-=================
-*/
-int CG_GetVoiceChat( voiceChatList_t *voiceChatList, const char *id, sfxHandle_t *snd, char **chat) {
- int i, rnd;
-
- for ( i = 0; i < voiceChatList->numVoiceChats; i++ ) {
- if ( !Q_stricmp( id, voiceChatList->voiceChats[i].id ) ) {
- rnd = random() * voiceChatList->voiceChats[i].numSounds;
- *snd = voiceChatList->voiceChats[i].sounds[rnd];
- *chat = voiceChatList->voiceChats[i].chats[rnd];
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-=================
-CG_VoiceChatListForClient
-=================
-*/
-voiceChatList_t *CG_VoiceChatListForClient( int clientNum ) {
- clientInfo_t *ci;
- int voiceChatNum, i, j, k, gender;
- char filename[MAX_QPATH], headModelName[MAX_QPATH];
-
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- clientNum = 0;
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- for ( k = 0; k < 2; k++ ) {
- if ( k == 0 ) {
- if (ci->headModelName[0] == '*') {
- Com_sprintf( headModelName, sizeof(headModelName), "%s/%s", ci->headModelName+1, ci->headSkinName );
- }
- else {
- Com_sprintf( headModelName, sizeof(headModelName), "%s/%s", ci->headModelName, ci->headSkinName );
- }
- }
- else {
- if (ci->headModelName[0] == '*') {
- Com_sprintf( headModelName, sizeof(headModelName), "%s", ci->headModelName+1 );
- }
- else {
- Com_sprintf( headModelName, sizeof(headModelName), "%s", ci->headModelName );
- }
- }
- // find the voice file for the head model the client uses
- for ( i = 0; i < MAX_HEADMODELS; i++ ) {
- if (!Q_stricmp(headModelVoiceChat[i].headmodel, headModelName)) {
- break;
- }
- }
- if (i < MAX_HEADMODELS) {
- return &voiceChatLists[headModelVoiceChat[i].voiceChatNum];
- }
- // find a <headmodelname>.vc file
- for ( i = 0; i < MAX_HEADMODELS; i++ ) {
- if (!strlen(headModelVoiceChat[i].headmodel)) {
- Com_sprintf(filename, sizeof(filename), "scripts/%s.vc", headModelName);
- voiceChatNum = CG_HeadModelVoiceChats(filename);
- if (voiceChatNum == -1)
- break;
- Com_sprintf(headModelVoiceChat[i].headmodel, sizeof ( headModelVoiceChat[i].headmodel ),
- "%s", headModelName);
- headModelVoiceChat[i].voiceChatNum = voiceChatNum;
- return &voiceChatLists[headModelVoiceChat[i].voiceChatNum];
- }
- }
- }
- gender = ci->gender;
- for (k = 0; k < 2; k++) {
- // just pick the first with the right gender
- for ( i = 0; i < MAX_VOICEFILES; i++ ) {
- if (strlen(voiceChatLists[i].name)) {
- if (voiceChatLists[i].gender == gender) {
- // store this head model with voice chat for future reference
- for ( j = 0; j < MAX_HEADMODELS; j++ ) {
- if (!strlen(headModelVoiceChat[j].headmodel)) {
- Com_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ),
- "%s", headModelName);
- headModelVoiceChat[j].voiceChatNum = i;
- break;
- }
- }
- return &voiceChatLists[i];
- }
- }
- }
- // fall back to male gender because we don't have neuter in the mission pack
- if (gender == GENDER_MALE)
- break;
- gender = GENDER_MALE;
- }
- // store this head model with voice chat for future reference
- for ( j = 0; j < MAX_HEADMODELS; j++ ) {
- if (!strlen(headModelVoiceChat[j].headmodel)) {
- Com_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ),
- "%s", headModelName);
- headModelVoiceChat[j].voiceChatNum = 0;
- break;
- }
- }
- // just return the first voice chat list
- return &voiceChatLists[0];
-}
-
-#define MAX_VOICECHATBUFFER 32
-
-typedef struct bufferedVoiceChat_s
-{
- int clientNum;
- sfxHandle_t snd;
- int voiceOnly;
- char cmd[MAX_SAY_TEXT];
- char message[MAX_SAY_TEXT];
-} bufferedVoiceChat_t;
-
-bufferedVoiceChat_t voiceChatBuffer[MAX_VOICECHATBUFFER];
-
-/*
-=================
-CG_PlayVoiceChat
-=================
-*/
-void CG_PlayVoiceChat( bufferedVoiceChat_t *vchat ) {
-#ifdef MISSIONPACK
- // if we are going into the intermission, don't start any voices
- if ( cg.intermissionStarted ) {
- return;
- }
-
- if ( !cg_noVoiceChats.integer ) {
- trap_S_StartLocalSound( vchat->snd, CHAN_VOICE);
- if (vchat->clientNum != cg.snap->ps.clientNum) {
- int orderTask = CG_ValidOrder(vchat->cmd);
- if (orderTask > 0) {
- cgs.acceptOrderTime = cg.time + 5000;
- Q_strncpyz(cgs.acceptVoice, vchat->cmd, sizeof(cgs.acceptVoice));
- cgs.acceptTask = orderTask;
- cgs.acceptLeader = vchat->clientNum;
- }
- // see if this was an order
- CG_ShowResponseHead();
- }
- }
- if (!vchat->voiceOnly && !cg_noVoiceText.integer) {
- CG_AddToTeamChat( vchat->message );
- CG_Printf( "%s\n", vchat->message );
- }
- voiceChatBuffer[cg.voiceChatBufferOut].snd = 0;
-#endif
-}
-
-/*
-=====================
-CG_PlayBufferedVoieChats
-=====================
-*/
-void CG_PlayBufferedVoiceChats( void ) {
-#ifdef MISSIONPACK
- if ( cg.voiceChatTime < cg.time ) {
- if (cg.voiceChatBufferOut != cg.voiceChatBufferIn && voiceChatBuffer[cg.voiceChatBufferOut].snd) {
- //
- CG_PlayVoiceChat(&voiceChatBuffer[cg.voiceChatBufferOut]);
- //
- cg.voiceChatBufferOut = (cg.voiceChatBufferOut + 1) % MAX_VOICECHATBUFFER;
- cg.voiceChatTime = cg.time + 1000;
- }
- }
-#endif
-}
-
-/*
-=====================
-CG_AddBufferedVoiceChat
-=====================
-*/
-void CG_AddBufferedVoiceChat( bufferedVoiceChat_t *vchat ) {
-#ifdef MISSIONPACK
- // if we are going into the intermission, don't start any voices
- if ( cg.intermissionStarted ) {
- return;
- }
-
- memcpy(&voiceChatBuffer[cg.voiceChatBufferIn], vchat, sizeof(bufferedVoiceChat_t));
- cg.voiceChatBufferIn = (cg.voiceChatBufferIn + 1) % MAX_VOICECHATBUFFER;
- if (cg.voiceChatBufferIn == cg.voiceChatBufferOut) {
- CG_PlayVoiceChat( &voiceChatBuffer[cg.voiceChatBufferOut] );
- cg.voiceChatBufferOut++;
- }
-#endif
-}
-
-/*
-=================
-CG_VoiceChatLocal
-=================
-*/
-void CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd ) {
-#ifdef MISSIONPACK
- char *chat;
- voiceChatList_t *voiceChatList;
- clientInfo_t *ci;
- sfxHandle_t snd;
- bufferedVoiceChat_t vchat;
-
- // if we are going into the intermission, don't start any voices
- if ( cg.intermissionStarted ) {
- return;
- }
-
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- clientNum = 0;
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- cgs.currentVoiceClient = clientNum;
-
- voiceChatList = CG_VoiceChatListForClient( clientNum );
-
- if ( CG_GetVoiceChat( voiceChatList, cmd, &snd, &chat ) ) {
- //
- if ( mode == SAY_TEAM || !cg_teamChatsOnly.integer ) {
- vchat.clientNum = clientNum;
- vchat.snd = snd;
- vchat.voiceOnly = voiceOnly;
- Q_strncpyz(vchat.cmd, cmd, sizeof(vchat.cmd));
- if ( mode == SAY_TELL ) {
- Com_sprintf(vchat.message, sizeof(vchat.message), "[%s]: %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
- }
- else if ( mode == SAY_TEAM ) {
- Com_sprintf(vchat.message, sizeof(vchat.message), "(%s): %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
- }
- else {
- Com_sprintf(vchat.message, sizeof(vchat.message), "%s: %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
- }
- CG_AddBufferedVoiceChat(&vchat);
- }
- }
-#endif
-}
-
-/*
-=================
-CG_VoiceChat
-=================
-*/
-void CG_VoiceChat( int mode ) {
-#ifdef MISSIONPACK
- const char *cmd;
- int clientNum, color;
- qboolean voiceOnly;
-
- voiceOnly = atoi(CG_Argv(1));
- clientNum = atoi(CG_Argv(2));
- color = atoi(CG_Argv(3));
- cmd = CG_Argv(4);
-
- if (cg_noTaunt.integer != 0) {
- if (!strcmp(cmd, VOICECHAT_KILLINSULT) || !strcmp(cmd, VOICECHAT_TAUNT) || \
- !strcmp(cmd, VOICECHAT_DEATHINSULT) || !strcmp(cmd, VOICECHAT_KILLGAUNTLET) || \
- !strcmp(cmd, VOICECHAT_PRAISE)) {
- return;
- }
- }
-
- CG_VoiceChatLocal( mode, voiceOnly, clientNum, color, cmd );
-#endif
-}
-
-/*
-=================
-CG_RemoveChatEscapeChar
-=================
-*/
-static void CG_RemoveChatEscapeChar( char *text ) {
- int i, l;
-
- l = 0;
- for ( i = 0; text[i]; i++ ) {
- if (text[i] == '\x19')
- continue;
- text[l++] = text[i];
- }
- text[l] = '\0';
-}
-
-/*
-=================
-CG_ServerCommand
-
-The string has been tokenized and can be retrieved with
-Cmd_Argc() / Cmd_Argv()
-=================
-*/
-static void CG_ServerCommand( void ) {
- const char *cmd;
- char text[MAX_SAY_TEXT];
-
- cmd = CG_Argv(0);
-
- if ( !cmd[0] ) {
- // server claimed the command
- return;
- }
-
- if ( !strcmp( cmd, "cp" ) ) {
- CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
- return;
- }
-
- if ( !strcmp( cmd, "cs" ) ) {
- CG_ConfigStringModified();
- return;
- }
-
- if ( !strcmp( cmd, "print" ) ) {
- CG_Printf( "%s", CG_Argv(1) );
-#ifdef MISSIONPACK
- cmd = CG_Argv(1); // yes, this is obviously a hack, but so is the way we hear about
- // votes passing or failing
- if ( !Q_stricmpn( cmd, "vote failed", 11 ) || !Q_stricmpn( cmd, "team vote failed", 16 )) {
- trap_S_StartLocalSound( cgs.media.voteFailed, CHAN_ANNOUNCER );
- } else if ( !Q_stricmpn( cmd, "vote passed", 11 ) || !Q_stricmpn( cmd, "team vote passed", 16 ) ) {
- trap_S_StartLocalSound( cgs.media.votePassed, CHAN_ANNOUNCER );
- }
-#endif
- return;
- }
-
- if ( !strcmp( cmd, "chat" ) ) {
- if ( !cg_teamChatsOnly.integer ) {
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
- CG_RemoveChatEscapeChar( text );
- CG_Printf( "%s\n", text );
- }
- return;
- }
-
- if ( !strcmp( cmd, "tchat" ) ) {
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
- CG_RemoveChatEscapeChar( text );
- CG_AddToTeamChat( text );
- CG_Printf( "%s\n", text );
- return;
- }
- if ( !strcmp( cmd, "vchat" ) ) {
- CG_VoiceChat( SAY_ALL );
- return;
- }
-
- if ( !strcmp( cmd, "vtchat" ) ) {
- CG_VoiceChat( SAY_TEAM );
- return;
- }
-
- if ( !strcmp( cmd, "vtell" ) ) {
- CG_VoiceChat( SAY_TELL );
- return;
- }
-
- if ( !strcmp( cmd, "scores" ) ) {
- CG_ParseScores();
- return;
- }
-
- if ( !strcmp( cmd, "ddtaken" ) ) {
- CG_ParseDDtimetaken();
- return;
- }
-
- if ( !strcmp( cmd, "dompointnames" ) ) {
- CG_ParseDomPointNames();
- return;
- }
-
- if ( !strcmp( cmd, "domStatus" ) ) {
- CG_ParseDomStatus();
- return;
- }
-
- if ( !strcmp( cmd, "elimination" ) ) {
- CG_ParseElimination();
- return;
- }
-
- if ( !strcmp( cmd, "mappage" ) ) {
- CG_ParseMappage();
- return;
- }
-
- if ( !strcmp( cmd, "attackingteam" ) ) {
- CG_ParseAttackingTeam();
- return;
- }
-
- if ( !strcmp( cmd, "tinfo" ) ) {
- CG_ParseTeamInfo();
- return;
- }
-
- if ( !strcmp( cmd, "map_restart" ) ) {
- CG_MapRestart();
- return;
- }
-
- if ( Q_stricmp (cmd, "remapShader") == 0 )
- {
- if (trap_Argc() == 4)
- {
- char shader1[MAX_QPATH];
- char shader2[MAX_QPATH];
- char shader3[MAX_QPATH];
-
- Q_strncpyz(shader1, CG_Argv(1), sizeof(shader1));
- Q_strncpyz(shader2, CG_Argv(2), sizeof(shader2));
- Q_strncpyz(shader3, CG_Argv(3), sizeof(shader3));
-
- trap_R_RemapShader(shader1, shader2, shader3);
- }
-
- return;
- }
-
- // loaddeferred can be both a servercmd and a consolecmd
- if ( !strcmp( cmd, "loaddefered" ) ) { // FIXME: spelled wrong, but not changing for demo
- CG_LoadDeferredPlayers();
- return;
- }
-
- // clientLevelShot is sent before taking a special screenshot for
- // the menu system during development
- if ( !strcmp( cmd, "clientLevelShot" ) ) {
- cg.levelShot = qtrue;
- return;
- }
-
- // challenge completed is determened by the server. A client should consider this message valid:
- if ( !strcmp( cmd, "ch" ) ) {
- CG_ParseChallenge();
- return;
- }
-
- if ( !strcmp( cmd, "team" ) ) {
- CG_ParseTeam();
- return;
- }
-
- if ( !strcmp( cmd, "customvotes" ) ) {
- char infoString[1024];
- int i;
- //TODO: Create a ParseCustomvotes function
- memset(&infoString,0,sizeof(infoString));
- for(i=1;i<=12;i++) {
- Q_strcat(infoString,sizeof(infoString),CG_Argv( i ));
- Q_strcat(infoString,sizeof(infoString)," ");
- }
- trap_Cvar_Set("cg_vote_custom_commands",infoString);
- return;
- }
-
- CG_Printf( "Unknown client game command: %s\n", cmd );
-}
-
-
-/*
-====================
-CG_ExecuteNewServerCommands
-
-Execute all of the server commands that were received along
-with this this snapshot.
-====================
-*/
-void CG_ExecuteNewServerCommands( int latestSequence ) {
- while ( cgs.serverCommandSequence < latestSequence ) {
- if ( trap_GetServerCommand( ++cgs.serverCommandSequence ) ) {
- CG_ServerCommand();
- }
- }
-}
diff --git a/game/code/cgame/cg_syscalls.asm b/game/code/cgame/cg_syscalls.asm
deleted file mode 100644
index 0874b47..0000000
--- a/game/code/cgame/cg_syscalls.asm
+++ /dev/null
@@ -1,106 +0,0 @@
-code
-
-equ trap_Print -1
-equ trap_Error -2
-equ trap_Milliseconds -3
-equ trap_Cvar_Register -4
-equ trap_Cvar_Update -5
-equ trap_Cvar_Set -6
-equ trap_Cvar_VariableStringBuffer -7
-equ trap_Argc -8
-equ trap_Argv -9
-equ trap_Args -10
-equ trap_FS_FOpenFile -11
-equ trap_FS_Read -12
-equ trap_FS_Write -13
-equ trap_FS_FCloseFile -14
-equ trap_SendConsoleCommand -15
-equ trap_AddCommand -16
-equ trap_SendClientCommand -17
-equ trap_UpdateScreen -18
-equ trap_CM_LoadMap -19
-equ trap_CM_NumInlineModels -20
-equ trap_CM_InlineModel -21
-equ trap_CM_LoadModel -22
-equ trap_CM_TempBoxModel -23
-equ trap_CM_PointContents -24
-equ trap_CM_TransformedPointContents -25
-equ trap_CM_BoxTrace -26
-equ trap_CM_TransformedBoxTrace -27
-equ trap_CM_MarkFragments -28
-equ trap_S_StartSound -29
-equ trap_S_StartLocalSound -30
-equ trap_S_ClearLoopingSounds -31
-equ trap_S_AddLoopingSound -32
-equ trap_S_UpdateEntityPosition -33
-equ trap_S_Respatialize -34
-equ trap_S_RegisterSound -35
-equ trap_S_StartBackgroundTrack -36
-equ trap_R_LoadWorldMap -37
-equ trap_R_RegisterModel -38
-equ trap_R_RegisterSkin -39
-equ trap_R_RegisterShader -40
-equ trap_R_ClearScene -41
-equ trap_R_AddRefEntityToScene -42
-equ trap_R_AddPolyToScene -43
-equ trap_R_AddLightToScene -44
-equ trap_R_RenderScene -45
-equ trap_R_SetColor -46
-equ trap_R_DrawStretchPic -47
-equ trap_R_ModelBounds -48
-equ trap_R_LerpTag -49
-equ trap_GetGlconfig -50
-equ trap_GetGameState -51
-equ trap_GetCurrentSnapshotNumber -52
-equ trap_GetSnapshot -53
-equ trap_GetServerCommand -54
-equ trap_GetCurrentCmdNumber -55
-equ trap_GetUserCmd -56
-equ trap_SetUserCmdValue -57
-equ trap_R_RegisterShaderNoMip -58
-equ trap_MemoryRemaining -59
-equ trap_R_RegisterFont -60
-equ trap_Key_IsDown -61
-equ trap_Key_GetCatcher -62
-equ trap_Key_SetCatcher -63
-equ trap_Key_GetKey -64
-equ trap_PC_AddGlobalDefine -65
-equ trap_PC_LoadSource -66
-equ trap_PC_FreeSource -67
-equ trap_PC_ReadToken -68
-equ trap_PC_SourceFileAndLine -69
-equ trap_S_StopBackgroundTrack -70
-equ trap_RealTime -71
-equ trap_SnapVector -72
-equ trap_RemoveCommand -73
-equ trap_R_LightForPoint -74
-equ trap_CIN_PlayCinematic -75
-equ trap_CIN_StopCinematic -76
-equ trap_CIN_RunCinematic -77
-equ trap_CIN_DrawCinematic -78
-equ trap_CIN_SetExtents -79
-equ trap_R_RemapShader -80
-equ trap_S_AddRealLoopingSound -81
-equ trap_S_StopLoopingSound -82
-equ trap_CM_TempCapsuleModel -83
-equ trap_CM_CapsuleTrace -84
-equ trap_CM_TransformedCapsuleTrace -85
-equ trap_R_AddAdditiveLightToScene -86
-equ trap_GetEntityToken -87
-equ trap_R_AddPolysToScene -88
-equ trap_R_inPVS -89
-equ trap_FS_Seek -90
-
-equ memset -101
-equ memcpy -102
-equ strncpy -103
-equ sin -104
-equ cos -105
-equ atan2 -106
-equ sqrt -107
-equ floor -108
-equ ceil -109
-equ testPrintInt -110
-equ testPrintFloat -111
-equ acos -112
-
diff --git a/game/code/cgame/cg_syscalls.c b/game/code/cgame/cg_syscalls.c
deleted file mode 100644
index 758d1b4..0000000
--- a/game/code/cgame/cg_syscalls.c
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_syscalls.c -- this file is only included when building a dll
-// cg_syscalls.asm is included instead when building a qvm
-#ifdef Q3_VM
-#error "Do not use in VM build"
-#endif
-
-#include "cg_local.h"
-
-static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;
-
-
-void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) {
- syscall = syscallptr;
-}
-
-
-int PASSFLOAT( float x ) {
- float floatTemp;
- floatTemp = x;
- return *(int *)&floatTemp;
-}
-
-void trap_Print( const char *fmt ) {
- syscall( CG_PRINT, fmt );
-}
-
-void trap_Error( const char *fmt ) {
- syscall( CG_ERROR, fmt );
-}
-
-int trap_Milliseconds( void ) {
- return syscall( CG_MILLISECONDS );
-}
-
-void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) {
- syscall( CG_CVAR_REGISTER, vmCvar, varName, defaultValue, flags );
-}
-
-void trap_Cvar_Update( vmCvar_t *vmCvar ) {
- syscall( CG_CVAR_UPDATE, vmCvar );
-}
-
-void trap_Cvar_Set( const char *var_name, const char *value ) {
- syscall( CG_CVAR_SET, var_name, value );
-}
-
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
- syscall( CG_CVAR_VARIABLESTRINGBUFFER, var_name, buffer, bufsize );
-}
-
-int trap_Argc( void ) {
- return syscall( CG_ARGC );
-}
-
-void trap_Argv( int n, char *buffer, int bufferLength ) {
- syscall( CG_ARGV, n, buffer, bufferLength );
-}
-
-void trap_Args( char *buffer, int bufferLength ) {
- syscall( CG_ARGS, buffer, bufferLength );
-}
-
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
- return syscall( CG_FS_FOPENFILE, qpath, f, mode );
-}
-
-void trap_FS_Read( void *buffer, int len, fileHandle_t f ) {
- syscall( CG_FS_READ, buffer, len, f );
-}
-
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f ) {
- syscall( CG_FS_WRITE, buffer, len, f );
-}
-
-void trap_FS_FCloseFile( fileHandle_t f ) {
- syscall( CG_FS_FCLOSEFILE, f );
-}
-
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ) {
- return syscall( CG_FS_SEEK, f, offset, origin );
-}
-
-void trap_SendConsoleCommand( const char *text ) {
- syscall( CG_SENDCONSOLECOMMAND, text );
-}
-
-void trap_AddCommand( const char *cmdName ) {
- syscall( CG_ADDCOMMAND, cmdName );
-}
-
-void trap_RemoveCommand( const char *cmdName ) {
- syscall( CG_REMOVECOMMAND, cmdName );
-}
-
-void trap_SendClientCommand( const char *s ) {
- syscall( CG_SENDCLIENTCOMMAND, s );
-}
-
-void trap_UpdateScreen( void ) {
- syscall( CG_UPDATESCREEN );
-}
-
-void trap_CM_LoadMap( const char *mapname ) {
- syscall( CG_CM_LOADMAP, mapname );
-}
-
-int trap_CM_NumInlineModels( void ) {
- return syscall( CG_CM_NUMINLINEMODELS );
-}
-
-clipHandle_t trap_CM_InlineModel( int index ) {
- return syscall( CG_CM_INLINEMODEL, index );
-}
-
-clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) {
- return syscall( CG_CM_TEMPBOXMODEL, mins, maxs );
-}
-
-clipHandle_t trap_CM_TempCapsuleModel( const vec3_t mins, const vec3_t maxs ) {
- return syscall( CG_CM_TEMPCAPSULEMODEL, mins, maxs );
-}
-
-int trap_CM_PointContents( const vec3_t p, clipHandle_t model ) {
- return syscall( CG_CM_POINTCONTENTS, p, model );
-}
-
-int trap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles ) {
- return syscall( CG_CM_TRANSFORMEDPOINTCONTENTS, p, model, origin, angles );
-}
-
-void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask ) {
- syscall( CG_CM_BOXTRACE, results, start, end, mins, maxs, model, brushmask );
-}
-
-void trap_CM_CapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask ) {
- syscall( CG_CM_CAPSULETRACE, results, start, end, mins, maxs, model, brushmask );
-}
-
-void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask,
- const vec3_t origin, const vec3_t angles ) {
- syscall( CG_CM_TRANSFORMEDBOXTRACE, results, start, end, mins, maxs, model, brushmask, origin, angles );
-}
-
-void trap_CM_TransformedCapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask,
- const vec3_t origin, const vec3_t angles ) {
- syscall( CG_CM_TRANSFORMEDCAPSULETRACE, results, start, end, mins, maxs, model, brushmask, origin, angles );
-}
-
-int trap_CM_MarkFragments( int numPoints, const vec3_t *points,
- const vec3_t projection,
- int maxPoints, vec3_t pointBuffer,
- int maxFragments, markFragment_t *fragmentBuffer ) {
- return syscall( CG_CM_MARKFRAGMENTS, numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer );
-}
-
-void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ) {
- syscall( CG_S_STARTSOUND, origin, entityNum, entchannel, sfx );
-}
-
-void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ) {
- syscall( CG_S_STARTLOCALSOUND, sfx, channelNum );
-}
-
-void trap_S_ClearLoopingSounds( qboolean killall ) {
- syscall( CG_S_CLEARLOOPINGSOUNDS, killall );
-}
-
-void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) {
- syscall( CG_S_ADDLOOPINGSOUND, entityNum, origin, velocity, sfx );
-}
-
-void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) {
- syscall( CG_S_ADDREALLOOPINGSOUND, entityNum, origin, velocity, sfx );
-}
-
-void trap_S_StopLoopingSound( int entityNum ) {
- syscall( CG_S_STOPLOOPINGSOUND, entityNum );
-}
-
-void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin ) {
- syscall( CG_S_UPDATEENTITYPOSITION, entityNum, origin );
-}
-
-void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater ) {
- syscall( CG_S_RESPATIALIZE, entityNum, origin, axis, inwater );
-}
-
-sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ) {
- return syscall( CG_S_REGISTERSOUND, sample, compressed );
-}
-
-void trap_S_StartBackgroundTrack( const char *intro, const char *loop ) {
- syscall( CG_S_STARTBACKGROUNDTRACK, intro, loop );
-}
-
-void trap_R_LoadWorldMap( const char *mapname ) {
- syscall( CG_R_LOADWORLDMAP, mapname );
-}
-
-qhandle_t trap_R_RegisterModel( const char *name ) {
- return syscall( CG_R_REGISTERMODEL, name );
-}
-
-qhandle_t trap_R_RegisterSkin( const char *name ) {
- return syscall( CG_R_REGISTERSKIN, name );
-}
-
-qhandle_t trap_R_RegisterShader( const char *name ) {
- return syscall( CG_R_REGISTERSHADER, name );
-}
-
-qhandle_t trap_R_RegisterShaderNoMip( const char *name ) {
- return syscall( CG_R_REGISTERSHADERNOMIP, name );
-}
-
-void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {
- syscall(CG_R_REGISTERFONT, fontName, pointSize, font );
-}
-
-void trap_R_ClearScene( void ) {
- syscall( CG_R_CLEARSCENE );
-}
-
-void trap_R_AddRefEntityToScene( const refEntity_t *re ) {
- syscall( CG_R_ADDREFENTITYTOSCENE, re );
-}
-
-void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ) {
- syscall( CG_R_ADDPOLYTOSCENE, hShader, numVerts, verts );
-}
-
-void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ) {
- syscall( CG_R_ADDPOLYSTOSCENE, hShader, numVerts, verts, num );
-}
-
-int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) {
- return syscall( CG_R_LIGHTFORPOINT, point, ambientLight, directedLight, lightDir );
-}
-
-void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
- syscall( CG_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );
-}
-
-void trap_R_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
- syscall( CG_R_ADDADDITIVELIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );
-}
-
-void trap_R_RenderScene( const refdef_t *fd ) {
- syscall( CG_R_RENDERSCENE, fd );
-}
-
-void trap_R_SetColor( const float *rgba ) {
- syscall( CG_R_SETCOLOR, rgba );
-}
-
-void trap_R_DrawStretchPic( float x, float y, float w, float h,
- float s1, float t1, float s2, float t2, qhandle_t hShader ) {
- syscall( CG_R_DRAWSTRETCHPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), hShader );
-}
-
-void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {
- syscall( CG_R_MODELBOUNDS, model, mins, maxs );
-}
-
-int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame,
- float frac, const char *tagName ) {
- return syscall( CG_R_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName );
-}
-
-void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) {
- syscall( CG_R_REMAP_SHADER, oldShader, newShader, timeOffset );
-}
-
-void trap_GetGlconfig( glconfig_t *glconfig ) {
- syscall( CG_GETGLCONFIG, glconfig );
-}
-
-void trap_GetGameState( gameState_t *gamestate ) {
- syscall( CG_GETGAMESTATE, gamestate );
-}
-
-void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) {
- syscall( CG_GETCURRENTSNAPSHOTNUMBER, snapshotNumber, serverTime );
-}
-
-qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {
- return syscall( CG_GETSNAPSHOT, snapshotNumber, snapshot );
-}
-
-qboolean trap_GetServerCommand( int serverCommandNumber ) {
- return syscall( CG_GETSERVERCOMMAND, serverCommandNumber );
-}
-
-int trap_GetCurrentCmdNumber( void ) {
- return syscall( CG_GETCURRENTCMDNUMBER );
-}
-
-qboolean trap_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) {
- return syscall( CG_GETUSERCMD, cmdNumber, ucmd );
-}
-
-void trap_SetUserCmdValue( int stateValue, float sensitivityScale ) {
- syscall( CG_SETUSERCMDVALUE, stateValue, PASSFLOAT(sensitivityScale) );
-}
-
-void testPrintInt( char *string, int i ) {
- syscall( CG_TESTPRINTINT, string, i );
-}
-
-void testPrintFloat( char *string, float f ) {
- syscall( CG_TESTPRINTFLOAT, string, PASSFLOAT(f) );
-}
-
-int trap_MemoryRemaining( void ) {
- return syscall( CG_MEMORY_REMAINING );
-}
-
-qboolean trap_Key_IsDown( int keynum ) {
- return syscall( CG_KEY_ISDOWN, keynum );
-}
-
-int trap_Key_GetCatcher( void ) {
- return syscall( CG_KEY_GETCATCHER );
-}
-
-void trap_Key_SetCatcher( int catcher ) {
- syscall( CG_KEY_SETCATCHER, catcher );
-}
-
-int trap_Key_GetKey( const char *binding ) {
- return syscall( CG_KEY_GETKEY, binding );
-}
-
-int trap_PC_AddGlobalDefine( char *define ) {
- return syscall( CG_PC_ADD_GLOBAL_DEFINE, define );
-}
-
-int trap_PC_LoadSource( const char *filename ) {
- return syscall( CG_PC_LOAD_SOURCE, filename );
-}
-
-int trap_PC_FreeSource( int handle ) {
- return syscall( CG_PC_FREE_SOURCE, handle );
-}
-
-int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) {
- return syscall( CG_PC_READ_TOKEN, handle, pc_token );
-}
-
-int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) {
- return syscall( CG_PC_SOURCE_FILE_AND_LINE, handle, filename, line );
-}
-
-void trap_S_StopBackgroundTrack( void ) {
- syscall( CG_S_STOPBACKGROUNDTRACK );
-}
-
-int trap_RealTime(qtime_t *qtime) {
- return syscall( CG_REAL_TIME, qtime );
-}
-
-void trap_SnapVector( float *v ) {
- syscall( CG_SNAPVECTOR, v );
-}
-
-// this returns a handle. arg0 is the name in the format "idlogo.roq", set arg1 to NULL, alteredstates to qfalse (do not alter gamestate)
-int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits) {
- return syscall(CG_CIN_PLAYCINEMATIC, arg0, xpos, ypos, width, height, bits);
-}
-
-// stops playing the cinematic and ends it. should always return FMV_EOF
-// cinematics must be stopped in reverse order of when they are started
-e_status trap_CIN_StopCinematic(int handle) {
- return syscall(CG_CIN_STOPCINEMATIC, handle);
-}
-
-
-// will run a frame of the cinematic but will not draw it. Will return FMV_EOF if the end of the cinematic has been reached.
-e_status trap_CIN_RunCinematic (int handle) {
- return syscall(CG_CIN_RUNCINEMATIC, handle);
-}
-
-
-// draws the current frame
-void trap_CIN_DrawCinematic (int handle) {
- syscall(CG_CIN_DRAWCINEMATIC, handle);
-}
-
-
-// allows you to resize the animation dynamically
-void trap_CIN_SetExtents (int handle, int x, int y, int w, int h) {
- syscall(CG_CIN_SETEXTENTS, handle, x, y, w, h);
-}
-
-/*
-qboolean trap_loadCamera( const char *name ) {
- return syscall( CG_LOADCAMERA, name );
-}
-
-void trap_startCamera(int time) {
- syscall(CG_STARTCAMERA, time);
-}
-
-qboolean trap_getCameraInfo( int time, vec3_t *origin, vec3_t *angles) {
- return syscall( CG_GETCAMERAINFO, time, origin, angles );
-}
-*/
-
-qboolean trap_GetEntityToken( char *buffer, int bufferSize ) {
- return syscall( CG_GET_ENTITY_TOKEN, buffer, bufferSize );
-}
-
-qboolean trap_R_inPVS( const vec3_t p1, const vec3_t p2 ) {
- return syscall( CG_R_INPVS, p1, p2 );
-}
diff --git a/game/code/cgame/cg_view.c b/game/code/cgame/cg_view.c
deleted file mode 100644
index 3194536..0000000
--- a/game/code/cgame/cg_view.c
+++ /dev/null
@@ -1,888 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_view.c -- setup all the parameters (position, angle, etc)
-// for a 3D rendering
-#include "cg_local.h"
-
-
-/*
-=============================================================================
-
- MODEL TESTING
-
-The viewthing and gun positioning tools from Q2 have been integrated and
-enhanced into a single model testing facility.
-
-Model viewing can begin with either "testmodel <modelname>" or "testgun <modelname>".
-
-The names must be the full pathname after the basedir, like
-"models/weapons/v_launch/tris.md3" or "players/male/tris.md3"
-
-Testmodel will create a fake entity 100 units in front of the current view
-position, directly facing the viewer. It will remain immobile, so you can
-move around it to view it from different angles.
-
-Testgun will cause the model to follow the player around and supress the real
-view weapon model. The default frame 0 of most guns is completely off screen,
-so you will probably have to cycle a couple frames to see it.
-
-"nextframe", "prevframe", "nextskin", and "prevskin" commands will change the
-frame or skin of the testmodel. These are bound to F5, F6, F7, and F8 in
-q3default.cfg.
-
-If a gun is being tested, the "gun_x", "gun_y", and "gun_z" variables will let
-you adjust the positioning.
-
-Note that none of the model testing features update while the game is paused, so
-it may be convenient to test with deathmatch set to 1 so that bringing down the
-console doesn't pause the game.
-
-=============================================================================
-*/
-
-/*
-=================
-CG_TestModel_f
-
-Creates an entity in front of the current position, which
-can then be moved around
-=================
-*/
-void CG_TestModel_f (void) {
- vec3_t angles;
-
- memset( &cg.testModelEntity, 0, sizeof(cg.testModelEntity) );
- if ( trap_Argc() < 2 ) {
- return;
- }
-
- Q_strncpyz (cg.testModelName, CG_Argv( 1 ), MAX_QPATH );
- cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
-
- if ( trap_Argc() == 3 ) {
- cg.testModelEntity.backlerp = atof( CG_Argv( 2 ) );
- cg.testModelEntity.frame = 1;
- cg.testModelEntity.oldframe = 0;
- }
- if (! cg.testModelEntity.hModel ) {
- CG_Printf( "Can't register model\n" );
- return;
- }
-
- VectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[0], cg.testModelEntity.origin );
-
- angles[PITCH] = 0;
- angles[YAW] = 180 + cg.refdefViewAngles[1];
- angles[ROLL] = 0;
-
- AnglesToAxis( angles, cg.testModelEntity.axis );
- cg.testGun = qfalse;
-}
-
-/*
-=================
-CG_TestGun_f
-
-Replaces the current view weapon with the given model
-=================
-*/
-void CG_TestGun_f (void) {
- CG_TestModel_f();
- cg.testGun = qtrue;
- cg.testModelEntity.renderfx = RF_MINLIGHT | RF_DEPTHHACK | RF_FIRST_PERSON;
-}
-
-
-void CG_TestModelNextFrame_f (void) {
- cg.testModelEntity.frame++;
- CG_Printf( "frame %i\n", cg.testModelEntity.frame );
-}
-
-void CG_TestModelPrevFrame_f (void) {
- cg.testModelEntity.frame--;
- if ( cg.testModelEntity.frame < 0 ) {
- cg.testModelEntity.frame = 0;
- }
- CG_Printf( "frame %i\n", cg.testModelEntity.frame );
-}
-
-void CG_TestModelNextSkin_f (void) {
- cg.testModelEntity.skinNum++;
- CG_Printf( "skin %i\n", cg.testModelEntity.skinNum );
-}
-
-void CG_TestModelPrevSkin_f (void) {
- cg.testModelEntity.skinNum--;
- if ( cg.testModelEntity.skinNum < 0 ) {
- cg.testModelEntity.skinNum = 0;
- }
- CG_Printf( "skin %i\n", cg.testModelEntity.skinNum );
-}
-
-static void CG_AddTestModel (void) {
- int i;
-
- // re-register the model, because the level may have changed
- cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
- if (! cg.testModelEntity.hModel ) {
- CG_Printf ("Can't register model\n");
- return;
- }
-
- // if testing a gun, set the origin reletive to the view origin
- if ( cg.testGun ) {
- VectorCopy( cg.refdef.vieworg, cg.testModelEntity.origin );
- VectorCopy( cg.refdef.viewaxis[0], cg.testModelEntity.axis[0] );
- VectorCopy( cg.refdef.viewaxis[1], cg.testModelEntity.axis[1] );
- VectorCopy( cg.refdef.viewaxis[2], cg.testModelEntity.axis[2] );
-
- // allow the position to be adjusted
- for (i=0 ; i<3 ; i++) {
- cg.testModelEntity.origin[i] += cg.refdef.viewaxis[0][i] * cg_gun_x.value;
- cg.testModelEntity.origin[i] += cg.refdef.viewaxis[1][i] * cg_gun_y.value;
- cg.testModelEntity.origin[i] += cg.refdef.viewaxis[2][i] * cg_gun_z.value;
- }
- }
-
- trap_R_AddRefEntityToScene( &cg.testModelEntity );
-}
-
-
-
-//============================================================================
-
-
-/*
-=================
-CG_CalcVrect
-
-Sets the coordinates of the rendered window
-=================
-*/
-static void CG_CalcVrect (void) {
- int size;
-
- // the intermission should allways be full screen
- if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
- size = 100;
- } else {
- // bound normal viewsize
- if (cg_viewsize.integer < 30) {
- trap_Cvar_Set ("cg_viewsize","30");
- size = 30;
- } else if (cg_viewsize.integer > 100) {
- trap_Cvar_Set ("cg_viewsize","100");
- size = 100;
- } else {
- size = cg_viewsize.integer;
- }
-
- }
- cg.refdef.width = cgs.glconfig.vidWidth*size/100;
- cg.refdef.width &= ~1;
-
- cg.refdef.height = cgs.glconfig.vidHeight*size/100;
- cg.refdef.height &= ~1;
-
- cg.refdef.x = (cgs.glconfig.vidWidth - cg.refdef.width)/2;
- cg.refdef.y = (cgs.glconfig.vidHeight - cg.refdef.height)/2;
-}
-
-//==============================================================================
-
-
-/*
-===============
-CG_OffsetThirdPersonView
-
-===============
-*/
-#define FOCUS_DISTANCE 512
-static void CG_OffsetThirdPersonView( void ) {
- vec3_t forward, right, up;
- vec3_t view;
- vec3_t focusAngles;
- trace_t trace;
- static vec3_t mins = { -4, -4, -4 };
- static vec3_t maxs = { 4, 4, 4 };
- vec3_t focusPoint;
- float focusDist;
- float forwardScale, sideScale;
-
- cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight;
-
- VectorCopy( cg.refdefViewAngles, focusAngles );
-
- // if dead, look at killer
- if ( (cg.predictedPlayerState.stats[STAT_HEALTH] <= 0) &&
- (cgs.gametype !=GT_ELIMINATION && cgs.gametype !=GT_CTF_ELIMINATION && cgs.gametype !=GT_LMS) ) {
- focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
- cg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
- }
-
- if ( focusAngles[PITCH] > 45 ) {
- focusAngles[PITCH] = 45; // don't go too far overhead
- }
- AngleVectors( focusAngles, forward, NULL, NULL );
-
- VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint );
-
- VectorCopy( cg.refdef.vieworg, view );
-
- view[2] += 8;
-
- cg.refdefViewAngles[PITCH] *= 0.5;
-
- AngleVectors( cg.refdefViewAngles, forward, right, up );
-
- forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI );
- sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI );
- VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view );
- VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view );
-
- // trace a ray from the origin to the viewpoint to make sure the view isn't
- // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything
-
- if (!cg_cameraMode.integer) {
- CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
-
- if ( trace.fraction != 1.0 ) {
- VectorCopy( trace.endpos, view );
- view[2] += (1.0 - trace.fraction) * 32;
- // try another trace to this position, because a tunnel may have the ceiling
- // close enogh that this is poking out
-
- CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
- VectorCopy( trace.endpos, view );
- }
- }
-
-
- VectorCopy( view, cg.refdef.vieworg );
-
- // select pitch to look at focus point from vieword
- VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
- focusDist = sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] );
- if ( focusDist < 1 ) {
- focusDist = 1; // should never happen
- }
- cg.refdefViewAngles[PITCH] = -180 / M_PI * atan2( focusPoint[2], focusDist );
- cg.refdefViewAngles[YAW] -= cg_thirdPersonAngle.value;
-}
-
-
-// this causes a compiler bug on mac MrC compiler
-static void CG_StepOffset( void ) {
- int timeDelta;
-
- // smooth out stair climbing
- timeDelta = cg.time - cg.stepTime;
- if ( timeDelta < STEP_TIME ) {
- cg.refdef.vieworg[2] -= cg.stepChange
- * (STEP_TIME - timeDelta) / STEP_TIME;
- }
-}
-
-/*
-===============
-CG_OffsetFirstPersonView
-
-===============
-*/
-static void CG_OffsetFirstPersonView( void ) {
- float *origin;
- float *angles;
- float bob;
- float ratio;
- float delta;
- float speed;
- float f;
- vec3_t predictedVelocity;
- int timeDelta;
-
- if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
- return;
- }
-
- origin = cg.refdef.vieworg;
- angles = cg.refdefViewAngles;
-
- // if dead, fix the angle and don't add any kick
- if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
- angles[ROLL] = 40;
- angles[PITCH] = -15;
- angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW];
- origin[2] += cg.predictedPlayerState.viewheight;
- return;
- }
-
- // add angles based on weapon kick
- VectorAdd (angles, cg.kick_angles, angles);
-
- // add angles based on damage kick
- if ( cg.damageTime && cgs.gametype!=GT_ELIMINATION && cgs.gametype!=GT_CTF_ELIMINATION && cgs.gametype!=GT_LMS) {
- ratio = cg.time - cg.damageTime;
- if ( ratio < DAMAGE_DEFLECT_TIME ) {
- ratio /= DAMAGE_DEFLECT_TIME;
- angles[PITCH] += ratio * cg.v_dmg_pitch;
- angles[ROLL] += ratio * cg.v_dmg_roll;
- } else {
- ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME;
- if ( ratio > 0 ) {
- angles[PITCH] += ratio * cg.v_dmg_pitch;
- angles[ROLL] += ratio * cg.v_dmg_roll;
- }
- }
- }
-
- // add pitch based on fall kick
-#if 0
- ratio = ( cg.time - cg.landTime) / FALL_TIME;
- if (ratio < 0)
- ratio = 0;
- angles[PITCH] += ratio * cg.fall_value;
-#endif
-
- // add angles based on velocity
- VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity );
-
- delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[0]);
- angles[PITCH] += delta * cg_runpitch.value;
-
- delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[1]);
- angles[ROLL] -= delta * cg_runroll.value;
-
- // add angles based on bob
-
- // make sure the bob is visible even at low speeds
- speed = cg.xyspeed > 200 ? cg.xyspeed : 200;
-
- delta = cg.bobfracsin * cg_bobpitch.value * speed;
- if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
- delta *= 3; // crouching
- angles[PITCH] += delta;
- delta = cg.bobfracsin * cg_bobroll.value * speed;
- if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
- delta *= 3; // crouching accentuates roll
- if (cg.bobcycle & 1)
- delta = -delta;
- angles[ROLL] += delta;
-
-//===================================
-
- // add view height
- origin[2] += cg.predictedPlayerState.viewheight;
-
- // smooth out duck height changes
- timeDelta = cg.time - cg.duckTime;
- if ( timeDelta < DUCK_TIME) {
- cg.refdef.vieworg[2] -= cg.duckChange
- * (DUCK_TIME - timeDelta) / DUCK_TIME;
- }
-
- // add bob height
- bob = cg.bobfracsin * cg.xyspeed * cg_bobup.value;
- if (bob > 6) {
- bob = 6;
- }
-
- origin[2] += bob;
-
-
- // add fall height
- delta = cg.time - cg.landTime;
- if ( delta < LAND_DEFLECT_TIME ) {
- f = delta / LAND_DEFLECT_TIME;
- cg.refdef.vieworg[2] += cg.landChange * f;
- } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
- delta -= LAND_DEFLECT_TIME;
- f = 1.0 - ( delta / LAND_RETURN_TIME );
- cg.refdef.vieworg[2] += cg.landChange * f;
- }
-
- // add step offset
- CG_StepOffset();
-
- // add kick offset
-
- VectorAdd (origin, cg.kick_origin, origin);
-
- // pivot the eye based on a neck length
-#if 0
- {
-#define NECK_LENGTH 8
- vec3_t forward, up;
-
- cg.refdef.vieworg[2] -= NECK_LENGTH;
- AngleVectors( cg.refdefViewAngles, forward, NULL, up );
- VectorMA( cg.refdef.vieworg, 3, forward, cg.refdef.vieworg );
- VectorMA( cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg );
- }
-#endif
-}
-
-//======================================================================
-
-void CG_ZoomDown_f( void ) {
- if ( cg.zoomed ) {
- return;
- }
- cg.zoomed = qtrue;
- cg.zoomTime = cg.time;
-}
-
-void CG_ZoomUp_f( void ) {
- if ( !cg.zoomed ) {
- return;
- }
- cg.zoomed = qfalse;
- cg.zoomTime = cg.time;
-}
-
-
-/*
-====================
-CG_CalcFov
-
-Fixed fov at intermissions, otherwise account for fov variable and zooms.
-====================
-*/
-#define WAVE_AMPLITUDE 1
-#define WAVE_FREQUENCY 0.4
-
-static int CG_CalcFov( void ) {
- float x;
- float phase;
- float v;
- int contents;
- float fov_x, fov_y;
- float zoomFov;
- float f;
- int inwater;
-
- if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- // if in intermission, use a fixed value
- fov_x = 90;
- } else {
- // user selectable
- if ( cgs.dmflags & DF_FIXED_FOV ) {
- // dmflag to prevent wide fov for all clients
- fov_x = 90;
- } else {
- fov_x = cg_fov.value;
- if ( fov_x < 1 ) {
- fov_x = 1;
- } else if ( fov_x > 160 ) {
- fov_x = 160;
- }
- if( (cgs.videoflags & VF_LOCK_CVARS_BASIC) && fov_x>140 )
- fov_x = 140;
-
- }
-
- if ( cgs.dmflags & DF_FIXED_FOV ) {
- // dmflag to prevent wide fov for all clients
- zoomFov = 22.5;
- } else {
- // account for zooms
- zoomFov = cg_zoomFov.value;
- if ( zoomFov < 1 ) {
- zoomFov = 1;
- } else if ( zoomFov > 160 ) {
- zoomFov = 160;
- }
-
- if( (cgs.videoflags & VF_LOCK_CVARS_BASIC) && zoomFov>140 )
- zoomFov = 140;
- }
-
- if ( cg.zoomed ) {
- f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
- if ( f > 1.0 ) {
- fov_x = zoomFov;
- } else {
- fov_x = fov_x + f * ( zoomFov - fov_x );
- }
- } else {
- f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
- if ( f > 1.0 ) {
- fov_x = fov_x;
- } else {
- fov_x = zoomFov + f * ( fov_x - zoomFov );
- }
- }
- }
-
- x = cg.refdef.width / tan( fov_x / 360 * M_PI );
- fov_y = atan2( cg.refdef.height, x );
- fov_y = fov_y * 360 / M_PI;
-
- // warp if underwater
- contents = CG_PointContents( cg.refdef.vieworg, -1 );
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ){
- phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
- v = WAVE_AMPLITUDE * sin( phase );
- fov_x += v;
- fov_y -= v;
- inwater = qtrue;
- }
- else {
- inwater = qfalse;
- }
-
-
- // set it
- cg.refdef.fov_x = fov_x;
- cg.refdef.fov_y = fov_y;
-
- if ( !cg.zoomed ) {
- cg.zoomSensitivity = 1;
- } else {
- cg.zoomSensitivity = cg.refdef.fov_y / 75.0;
- }
-
- return inwater;
-}
-
-
-
-/*
-===============
-CG_DamageBlendBlob
-
-===============
-*/
-static void CG_DamageBlendBlob( void ) {
- int t;
- int maxTime;
- refEntity_t ent;
-
- if ( !cg.damageValue ) {
- return;
- }
-
- //if (cg.cameraMode) {
- // return;
- //}
-
- // ragePro systems can't fade blends, so don't obscure the screen
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
- return;
- }
-
- maxTime = DAMAGE_TIME;
- t = cg.time - cg.damageTime;
- if ( t <= 0 || t >= maxTime ) {
- return;
- }
-
-
- memset( &ent, 0, sizeof( ent ) );
- ent.reType = RT_SPRITE;
- ent.renderfx = RF_FIRST_PERSON;
-
- VectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], ent.origin );
- VectorMA( ent.origin, cg.damageX * -8, cg.refdef.viewaxis[1], ent.origin );
- VectorMA( ent.origin, cg.damageY * 8, cg.refdef.viewaxis[2], ent.origin );
-
- ent.radius = cg.damageValue * 3;
- ent.customShader = cgs.media.viewBloodShader;
- ent.shaderRGBA[0] = 255;
- ent.shaderRGBA[1] = 255;
- ent.shaderRGBA[2] = 255;
- ent.shaderRGBA[3] = 200 * ( 1.0 - ((float)t / maxTime) );
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-/*
-===============
-CG_CalcViewValues
-
-Sets cg.refdef view values
-===============
-*/
-static int CG_CalcViewValues( void ) {
- playerState_t *ps;
-
- memset( &cg.refdef, 0, sizeof( cg.refdef ) );
-
- // strings for in game rendering
- // Q_strncpyz( cg.refdef.text[0], "Park Ranger", sizeof(cg.refdef.text[0]) );
- // Q_strncpyz( cg.refdef.text[1], "19", sizeof(cg.refdef.text[1]) );
-
- // calculate size of 3D view
- CG_CalcVrect();
-
- ps = &cg.predictedPlayerState;
-/*
- if (cg.cameraMode) {
- vec3_t origin, angles;
- if (trap_getCameraInfo(cg.time, &origin, &angles)) {
- VectorCopy(origin, cg.refdef.vieworg);
- angles[ROLL] = 0;
- VectorCopy(angles, cg.refdefViewAngles);
- AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
- return CG_CalcFov();
- } else {
- cg.cameraMode = qfalse;
- }
- }
-*/
- // intermission view
- if ( ps->pm_type == PM_INTERMISSION ) {
- VectorCopy( ps->origin, cg.refdef.vieworg );
- VectorCopy( ps->viewangles, cg.refdefViewAngles );
- AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
- return CG_CalcFov();
- }
-
- cg.bobcycle = ( ps->bobCycle & 128 ) >> 7;
- cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) );
- cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] +
- ps->velocity[1] * ps->velocity[1] );
-
-
- VectorCopy( ps->origin, cg.refdef.vieworg );
- VectorCopy( ps->viewangles, cg.refdefViewAngles );
-
- if (cg_cameraOrbit.integer) {
- if (cg.time > cg.nextOrbitTime) {
- cg.nextOrbitTime = cg.time + cg_cameraOrbitDelay.integer;
- cg_thirdPersonAngle.value += cg_cameraOrbit.value;
- }
- }
- // add error decay
- if ( cg_errorDecay.value > 0 ) {
- int t;
- float f;
-
- t = cg.time - cg.predictedErrorTime;
- f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
- if ( f > 0 && f < 1 ) {
- VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg );
- } else {
- cg.predictedErrorTime = 0;
- }
- }
-
- if ( cg.renderingThirdPerson ) {
- // back away from character
- CG_OffsetThirdPersonView();
- } else {
- // offset for local bobbing and kicks
- CG_OffsetFirstPersonView();
- }
-
- // position eye reletive to origin
- AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
-
- if ( cg.hyperspace ) {
- cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE;
- }
-
- // field of view
- return CG_CalcFov();
-}
-
-
-/*
-=====================
-CG_PowerupTimerSounds
-=====================
-*/
-static void CG_PowerupTimerSounds( void ) {
- int i;
- int t;
-
- // powerup timers going away
- for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
- t = cg.snap->ps.powerups[i];
- if ( t <= cg.time ) {
- continue;
- }
- if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
- continue;
- }
- if ( ( t - cg.time ) / POWERUP_BLINK_TIME != ( t - cg.oldTime ) / POWERUP_BLINK_TIME ) {
- trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_ITEM, cgs.media.wearOffSound );
- }
- }
-}
-
-/*
-=====================
-CG_AddBufferedSound
-=====================
-*/
-void CG_AddBufferedSound( sfxHandle_t sfx ) {
- if ( !sfx )
- return;
- cg.soundBuffer[cg.soundBufferIn] = sfx;
- cg.soundBufferIn = (cg.soundBufferIn + 1) % MAX_SOUNDBUFFER;
- if (cg.soundBufferIn == cg.soundBufferOut) {
- cg.soundBufferOut++;
- }
-}
-
-/*
-=====================
-CG_PlayBufferedSounds
-=====================
-*/
-static void CG_PlayBufferedSounds( void ) {
- if ( cg.soundTime < cg.time ) {
- if (cg.soundBufferOut != cg.soundBufferIn && cg.soundBuffer[cg.soundBufferOut]) {
- trap_S_StartLocalSound(cg.soundBuffer[cg.soundBufferOut], CHAN_ANNOUNCER);
- cg.soundBuffer[cg.soundBufferOut] = 0;
- cg.soundBufferOut = (cg.soundBufferOut + 1) % MAX_SOUNDBUFFER;
- cg.soundTime = cg.time + 750;
- }
- }
-}
-
-//=========================================================================
-
-/*
-=================
-CG_DrawActiveFrame
-
-Generates and draws a game scene and status information at the given time.
-=================
-*/
-void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) {
- int inwater;
-
- cg.time = serverTime;
- cg.demoPlayback = demoPlayback;
-
- // update cvars
- CG_UpdateCvars();
-
- // if we are only updating the screen as a loading
- // pacifier, don't even try to read snapshots
- if ( cg.infoScreenText[0] != 0 ) {
- CG_DrawInformation();
- return;
- }
-
- // any looped sounds will be respecified as entities
- // are added to the render list
- trap_S_ClearLoopingSounds(qfalse);
-
- // clear all the render lists
- trap_R_ClearScene();
-
- // set up cg.snap and possibly cg.nextSnap
- CG_ProcessSnapshots();
-
- // if we haven't received any snapshots yet, all
- // we can draw is the information screen
- if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
- CG_DrawInformation();
- return;
- }
-
- // let the client system know what our weapon and zoom settings are
- trap_SetUserCmdValue( cg.weaponSelect, cg.zoomSensitivity );
-
- // this counter will be bumped for every valid scene we generate
- cg.clientFrame++;
-
- // update cg.predictedPlayerState
- CG_PredictPlayerState();
-
- // decide on third person view
- cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0);
-
- // build cg.refdef
- inwater = CG_CalcViewValues();
-
- // first person blend blobs, done after AnglesToAxis
- if ( !cg.renderingThirdPerson ) {
- CG_DamageBlendBlob();
- }
-
- // build the render lists
- if ( !cg.hyperspace ) {
- CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct
- CG_AddMarks();
- CG_AddParticles ();
- CG_AddLocalEntities();
- }
- CG_AddViewWeapon( &cg.predictedPlayerState );
-
- // add buffered sounds
- CG_PlayBufferedSounds();
-
- // play buffered voice chats
- CG_PlayBufferedVoiceChats();
-
- // finish up the rest of the refdef
- if ( cg.testModelEntity.hModel ) {
- CG_AddTestModel();
- }
- cg.refdef.time = cg.time;
- memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) );
-
- // warning sounds when powerup is wearing off
- CG_PowerupTimerSounds();
-
- // update audio positions
- trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater );
-
- // make sure the lagometerSample and frame timing isn't done twice when in stereo
- if ( stereoView != STEREO_RIGHT ) {
- cg.frametime = cg.time - cg.oldTime;
- if ( cg.frametime < 0 ) {
- cg.frametime = 0;
- }
- cg.oldTime = cg.time;
- CG_AddLagometerFrameInfo();
- }
- if (cg_timescale.value != cg_timescaleFadeEnd.value) {
- if (cg_timescale.value < cg_timescaleFadeEnd.value) {
- cg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;
- if (cg_timescale.value > cg_timescaleFadeEnd.value)
- cg_timescale.value = cg_timescaleFadeEnd.value;
- }
- else {
- cg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;
- if (cg_timescale.value < cg_timescaleFadeEnd.value)
- cg_timescale.value = cg_timescaleFadeEnd.value;
- }
- if (cg_timescaleFadeSpeed.value) {
- trap_Cvar_Set("timescale", va("%f", cg_timescale.value));
- }
- }
-
- // actually issue the rendering calls
- CG_DrawActive( stereoView );
-
- if ( cg_stats.integer ) {
- CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame );
- }
-
-
-}
-
diff --git a/game/code/cgame/cg_weapons.c b/game/code/cgame/cg_weapons.c
deleted file mode 100644
index 72dda3b..0000000
--- a/game/code/cgame/cg_weapons.c
+++ /dev/null
@@ -1,3513 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_weapons.c -- events and effects dealing with weapons
-#include "cg_local.h"
-
-/*
-==========================
-CG_MachineGunEjectBrass
-==========================
-*/
-static void CG_MachineGunEjectBrass( centity_t *cent ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t velocity, xvelocity;
- vec3_t offset, xoffset;
- float waterScale = 1.0f;
- vec3_t v[3];
-
- if ( cg_brassTime.integer <= 0 ) {
- return;
- }
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- velocity[0] = 0;
- velocity[1] = -50 + 40 * crandom();
- velocity[2] = 100 + 50 * crandom();
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random();
-
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time - (rand()&15);
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[0] = 8;
- offset[1] = -4;
- offset[2] = 24;
-
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( cent->lerpOrigin, xoffset, re->origin );
-
- VectorCopy( re->origin, le->pos.trBase );
-
- if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
- waterScale = 0.10f;
- }
-
- xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
- xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
- xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
-
- AxisCopy( axisDefault, re->axis );
- re->hModel = cgs.media.machinegunBrassModel;
-
- le->bounceFactor = 0.4 * waterScale;
-
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[0] = rand()&31;
- le->angles.trBase[1] = rand()&31;
- le->angles.trBase[2] = rand()&31;
- le->angles.trDelta[0] = 2;
- le->angles.trDelta[1] = 1;
- le->angles.trDelta[2] = 0;
-
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_BRASS;
- le->leMarkType = LEMT_NONE;
-}
-
-
-
-/*
-==========================
-CG_ShotgunEjectBrass
-==========================
-*/
-static void CG_ShotgunEjectBrass( centity_t *cent ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t velocity, xvelocity;
- vec3_t offset, xoffset;
- vec3_t v[3];
- int i;
-
- if ( cg_brassTime.integer <= 0 ) {
- return;
- }
-
- for ( i = 0; i < 2; i++ ) {
- float waterScale = 1.0f;
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- velocity[0] = 60 + 60 * crandom();
- if ( i == 0 ) {
- velocity[1] = 40 + 10 * crandom();
- } else {
- velocity[1] = -40 + 10 * crandom();
- }
- velocity[2] = 100 + 50 * crandom();
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + cg_brassTime.integer*3 + cg_brassTime.integer * random();
-
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time;
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[0] = 8;
- offset[1] = 0;
- offset[2] = 24;
-
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( cent->lerpOrigin, xoffset, re->origin );
- VectorCopy( re->origin, le->pos.trBase );
- if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
- waterScale = 0.10f;
- }
-
- xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
- xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
- xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
-
- AxisCopy( axisDefault, re->axis );
- re->hModel = cgs.media.shotgunBrassModel;
- le->bounceFactor = 0.3f;
-
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[0] = rand()&31;
- le->angles.trBase[1] = rand()&31;
- le->angles.trBase[2] = rand()&31;
- le->angles.trDelta[0] = 1;
- le->angles.trDelta[1] = 0.5;
- le->angles.trDelta[2] = 0;
-
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_SHELL; // LEILEI shell noises
- le->leMarkType = LEMT_NONE;
- }
-}
-
-
-//#ifdef MISSIONPACK
-/*
-==========================
-CG_NailgunEjectBrass
-==========================
-*/
-static void CG_NailgunEjectBrass( centity_t *cent ) {
- localEntity_t *smoke;
- vec3_t origin;
- vec3_t v[3];
- vec3_t offset;
- vec3_t xoffset;
- vec3_t up;
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[0] = 0;
- offset[1] = -12;
- offset[2] = 24;
-
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( cent->lerpOrigin, xoffset, origin );
-
- VectorSet( up, 0, 0, 64 );
-
- smoke = CG_SmokePuff( origin, up, 32, 1, 1, 1, 0.33f, 700, cg.time, 0, 0, cgs.media.smokePuffShader );
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
-}
-//#endif
-
-
-/*
-==========================
-CG_RailTrail
-==========================
-*/
-void CG_RailTrail (clientInfo_t *ci, vec3_t start, vec3_t end) {
- vec3_t axis[36], move, move2, next_move, vec, temp;
- float len;
- int i, j, skip;
-
- localEntity_t *le;
- refEntity_t *re;
-
-#define RADIUS 4
-#define ROTATION 1
-#define SPACING 5
-
- start[2] -= 4;
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- le->leType = LE_FADE_RGB;
- le->startTime = cg.time;
- le->endTime = cg.time + cg_railTrailTime.value;
- le->lifeRate = 1.0 / (le->endTime - le->startTime);
-
- re->shaderTime = cg.time / 1000.0f;
- re->reType = RT_RAIL_CORE;
- re->customShader = cgs.media.railCoreShader;
-
- VectorCopy(start, re->origin);
- VectorCopy(end, re->oldorigin);
-
- re->shaderRGBA[0] = ci->color1[0] * 255;
- re->shaderRGBA[1] = ci->color1[1] * 255;
- re->shaderRGBA[2] = ci->color1[2] * 255;
- re->shaderRGBA[3] = 255;
-
- le->color[0] = ci->color1[0] * 0.75;
- le->color[1] = ci->color1[1] * 0.75;
- le->color[2] = ci->color1[2] * 0.75;
- le->color[3] = 1.0f;
-
- AxisClear( re->axis );
-
- if (cg_oldRail.integer)
- {
- // nudge down a bit so it isn't exactly in center
- re->origin[2] -= 8;
- re->oldorigin[2] -= 8;
- return;
- }
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
- PerpendicularVector(temp, vec);
- for (i = 0 ; i < 36; i++)
- {
- RotatePointAroundVector(axis[i], vec, temp, i * 10);//banshee 2.4 was 10
- }
-
- VectorMA(move, 20, vec, move);
- VectorCopy(move, next_move);
- VectorScale (vec, SPACING, vec);
-
- skip = -1;
-
- j = 18;
- for (i = 0; i < len; i += SPACING)
- {
- if (i != skip)
- {
- skip = i + SPACING;
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
- le->leFlags = LEF_PUFF_DONT_SCALE;
- le->leType = LE_MOVE_SCALE_FADE;
- le->startTime = cg.time;
- le->endTime = cg.time + (i>>1) + 600;
- le->lifeRate = 1.0 / (le->endTime - le->startTime);
-
- re->shaderTime = cg.time / 1000.0f;
- re->reType = RT_SPRITE;
- re->radius = 1.1f;
- re->customShader = cgs.media.railRingsShader;
-
- re->shaderRGBA[0] = ci->color2[0] * 255;
- re->shaderRGBA[1] = ci->color2[1] * 255;
- re->shaderRGBA[2] = ci->color2[2] * 255;
- re->shaderRGBA[3] = 255;
-
- le->color[0] = ci->color2[0] * 0.75;
- le->color[1] = ci->color2[1] * 0.75;
- le->color[2] = ci->color2[2] * 0.75;
- le->color[3] = 1.0f;
-
- le->pos.trType = TR_LINEAR;
- le->pos.trTime = cg.time;
-
- VectorCopy( move, move2);
- VectorMA(move2, RADIUS , axis[j], move2);
- VectorCopy(move2, le->pos.trBase);
-
- le->pos.trDelta[0] = axis[j][0]*6;
- le->pos.trDelta[1] = axis[j][1]*6;
- le->pos.trDelta[2] = axis[j][2]*6;
- }
-
- VectorAdd (move, vec, move);
-
- j = (j + ROTATION) % 36;
- }
-}
-
-/*
-==========================
-CG_OldRocketTrail (for the crappy old rocket trail.)
-==========================
-*/
-static void CG_OldRocketTrail( centity_t *ent, const weaponInfo_t *wi ) {
- int step;
- vec3_t origin, lastPos;
- int t;
- int startTime, contents;
- int lastContents;
- entityState_t *es;
- vec3_t up;
- localEntity_t *smoke;
-
- if ( cg_noProjectileTrail.integer ) {
- return;
- }
-
- up[0] = 0;
- up[1] = 0;
- up[2] = 0;
-
- step = 50;
-
- es = &ent->currentState;
- startTime = ent->trailTime;
- t = step * ( (startTime + step) / step );
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- contents = CG_PointContents( origin, -1 );
-
- // if object (e.g. grenade) is stationary, don't toss up smoke
- if ( es->pos.trType == TR_STATIONARY ) {
- ent->trailTime = cg.time;
- return;
- }
-
- BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
- lastContents = CG_PointContents( lastPos, -1 );
-
- ent->trailTime = cg.time;
-
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- if ( contents & lastContents & CONTENTS_WATER ) {
- CG_BubbleTrail( lastPos, origin, 8 );
- }
- return;
- }
-
- for ( ; t <= ent->trailTime ; t += step ) {
- BG_EvaluateTrajectory( &es->pos, t, lastPos );
-
- smoke = CG_SmokePuff( lastPos, up,
- wi->trailRadius,
- 1, 1, 1, 0.33f,
- wi->wiTrailTime,
- t,
- 0,
- 0,
- cgs.media.smokePuffShader );
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
- }
-
-}
-
-/*
-==========================
-CG_LeiSmokeTrail
-==========================
-*/
-
-static void CG_LeiSmokeTrail( centity_t *ent, const weaponInfo_t *wi ) {
- int step;
- vec3_t origin, lastPos;
- int t;
- int startTime, contents;
- int lastContents;
- entityState_t *es;
- vec3_t up;
- localEntity_t *smoke;
- int therando;
- int theradio;
-
- if ( cg_noProjectileTrail.integer ) {
- return;
- }
-
- up[0] = 5 - 10 * crandom();
- up[1] = 5 - 10 * crandom();
- up[2] = 8 - 5 * crandom();
-
- step = 18;
-
- es = &ent->currentState;
- startTime = ent->trailTime;
- t = step * ( (startTime + step) / step );
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- contents = CG_PointContents( origin, -1 );
-
- // if object (e.g. grenade) is stationary, don't toss up smoke
- if ( es->pos.trType == TR_STATIONARY ) {
- ent->trailTime = cg.time;
- return;
- }
-
- BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
- lastContents = CG_PointContents( lastPos, -1 );
-
- ent->trailTime = cg.time;
-
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- if ( contents & lastContents & CONTENTS_WATER ) {
- CG_BubbleTrail( lastPos, origin, 8 );
- }
- return;
- }
-
- for ( ; t <= ent->trailTime ; t += step ) {
- BG_EvaluateTrajectory( &es->pos, t, lastPos );
- therando = crandom() * 4;
-
- theradio = wi->trailRadius * (rand() * 0.7); // what is this doing here
- if (therando == 3) smoke = CG_SmokePuff( lastPos, up, 27, 1, 1, 1, 0.9f, wi->wiTrailTime, t, 0, 0, cgs.media.lsmkShader1 );
- else if (therando == 1) smoke = CG_SmokePuff( lastPos, up, 27, 1, 1, 1, 0.9f, wi->wiTrailTime, t, 0, 0, cgs.media.lsmkShader2 );
- else if (therando == 2) smoke = CG_SmokePuff( lastPos, up, 27, 1, 1, 1, 0.9f, wi->wiTrailTime, t, 0, 0, cgs.media.lsmkShader3 );
- else smoke = CG_SmokePuff( lastPos, up, 27, 1, 1, 1, 0.9f, wi->wiTrailTime, t, 0, 0, cgs.media.lsmkShader4 );
- // use the optimized local entity add
- smoke->leType = LE_MOVE_SCALE_FADE;
- //smoke->trType = TR_GRAVITY;
- }
-
-}
-
-
-static void CG_LeiPlasmaTrail( centity_t *ent, const weaponInfo_t *wi ) {
- int step;
- vec3_t origin, lastPos;
- int t;
- int startTime, contents;
- int lastContents;
- entityState_t *es;
- vec3_t up;
- localEntity_t *smoke;
- int therando;
- int theradio;
-
- if ( cg_noProjectileTrail.integer ) {
- return;
- }
-
- up[0] = 0;
- up[1] = 0;
- up[2] = 0;
-
- step = 16;
-
- es = &ent->currentState;
- startTime = ent->trailTime;
- t = step * ( (startTime + step) / step );
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- contents = CG_PointContents( origin, -1 );
-
- // if object (e.g. grenade) is stationary, don't toss up smoke
- if ( es->pos.trType == TR_STATIONARY ) {
- ent->trailTime = cg.time;
- return;
- }
-
- BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
- lastContents = CG_PointContents( lastPos, -1 );
-
- ent->trailTime = cg.time;
-
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- return;
- }
-
- for ( ; t <= ent->trailTime ; t += step ) {
- BG_EvaluateTrajectory( &es->pos, t, lastPos );
-
- smoke = CG_SmokePuff( lastPos, up, 27, 1, 1, 1, 0.9f, wi->wiTrailTime, t, 0, 0, cgs.media.lsmkShader1 );
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
- //smoke->trType = TR_GRAVITY;
- }
-
-}
-
-
-//#ifdef MISSIONPACK
-/*
-==========================
-CG_NailTrail
-==========================
-*/
-static void CG_NailTrail( centity_t *ent, const weaponInfo_t *wi ) {
- int step;
- vec3_t origin, lastPos;
- int t;
- int startTime, contents;
- int lastContents;
- entityState_t *es;
- vec3_t up;
- localEntity_t *smoke;
-
- if ( cg_noProjectileTrail.integer ) {
- return;
- }
-
- up[0] = 0;
- up[1] = 0;
- up[2] = 0;
-
- step = 50;
-
- es = &ent->currentState;
- startTime = ent->trailTime;
- t = step * ( (startTime + step) / step );
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- contents = CG_PointContents( origin, -1 );
-
- // if object (e.g. grenade) is stationary, don't toss up smoke
- if ( es->pos.trType == TR_STATIONARY ) {
- ent->trailTime = cg.time;
- return;
- }
-
- BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
- lastContents = CG_PointContents( lastPos, -1 );
-
- ent->trailTime = cg.time;
-
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- if ( contents & lastContents & CONTENTS_WATER ) {
- CG_BubbleTrail( lastPos, origin, 8 );
- }
- return;
- }
-
- for ( ; t <= ent->trailTime ; t += step ) {
- BG_EvaluateTrajectory( &es->pos, t, lastPos );
-
- smoke = CG_SmokePuff( lastPos, up,
- wi->trailRadius,
- 1, 1, 1, 0.33f,
- wi->wiTrailTime,
- t,
- 0,
- 0,
- cgs.media.nailPuffShader );
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
- }
-
-}
-//#endif
-
-/*
-==========================
-CG_NailTrail
-==========================
-*/
-static void CG_OldPlasmaTrail( centity_t *cent, const weaponInfo_t *wi ) {
- localEntity_t *le;
- refEntity_t *re;
- entityState_t *es;
- vec3_t velocity, xvelocity, origin;
- vec3_t offset, xoffset;
- vec3_t v[3];
- int t, startTime, step;
-
- float waterScale = 1.0f;
-
- if ( cg_noProjectileTrail.integer || cg_oldPlasma.integer ) {
- return;
- }
-
- step = 50;
-
- es = ¢->currentState;
- startTime = cent->trailTime;
- t = step * ( (startTime + step) / step );
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- velocity[0] = 60 - 120 * crandom();
- velocity[1] = 40 - 80 * crandom();
- velocity[2] = 100 - 200 * crandom();
-
- le->leType = LE_MOVE_SCALE_FADE;
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_NONE;
- le->leMarkType = LEMT_NONE;
-
- le->startTime = cg.time;
- le->endTime = le->startTime + 600;
-
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time;
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[0] = 2;
- offset[1] = 2;
- offset[2] = 2;
-
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
-
- VectorAdd( origin, xoffset, re->origin );
- VectorCopy( re->origin, le->pos.trBase );
-
- if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
- waterScale = 0.10f;
- }
-
- xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
- xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
- xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
-
- AxisCopy( axisDefault, re->axis );
- re->shaderTime = cg.time / 1000.0f;
- re->reType = RT_SPRITE;
- re->radius = 0.25f;
- re->customShader = cgs.media.railRingsShader;
- le->bounceFactor = 0.3f;
-
-
- re->shaderRGBA[0] = wi->flashDlightColor[0] * 63;
- re->shaderRGBA[1] = wi->flashDlightColor[1] * 63;
- re->shaderRGBA[2] = wi->flashDlightColor[2] * 63;
- re->shaderRGBA[3] = 63;
-
- le->color[0] = wi->flashDlightColor[0] * 0.2;
- le->color[1] = wi->flashDlightColor[1] * 0.2;
- le->color[2] = wi->flashDlightColor[2] * 0.2;
- le->color[3] = 0.25f;
-
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[0] = rand()&31;
- le->angles.trBase[1] = rand()&31;
- le->angles.trBase[2] = rand()&31;
- le->angles.trDelta[0] = 1;
- le->angles.trDelta[1] = 0.5;
- le->angles.trDelta[2] = 0;
-
-}
-/*
-==========================
-CG_GrappleTrail
-==========================
-*/
-void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi ) {
- vec3_t origin;
- entityState_t *es;
- vec3_t forward, up;
- refEntity_t beam;
-
- es = &ent->currentState;
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- ent->trailTime = cg.time;
-
- memset( &beam, 0, sizeof( beam ) );
- //FIXME adjust for muzzle position
- VectorCopy ( cg_entities[ ent->currentState.otherEntityNum ].lerpOrigin, beam.origin );
- beam.origin[2] += 26;
- AngleVectors( cg_entities[ ent->currentState.otherEntityNum ].lerpAngles, forward, NULL, up );
- VectorMA( beam.origin, -6, up, beam.origin );
- VectorCopy( origin, beam.oldorigin );
-
- if (Distance( beam.origin, beam.oldorigin ) < 64 )
- return; // Don't draw if close
-
- beam.reType = RT_LIGHTNING;
- beam.customShader = cgs.media.lightningShader;
-
- AxisClear( beam.axis );
- beam.shaderRGBA[0] = 0xff;
- beam.shaderRGBA[1] = 0xff;
- beam.shaderRGBA[2] = 0xff;
- beam.shaderRGBA[3] = 0xff;
- trap_R_AddRefEntityToScene( &beam );
-}
-
-/*
-==========================
-CG_GrenadeTrail
-==========================
-*/
-// LEILEI enhancment
-static void CG_RocketTrail( centity_t *ent, const weaponInfo_t *wi ) {
-
- if (cg_leiEnhancement.integer) {
- CG_LeiSmokeTrail( ent, wi );
- }
- else
- {
- CG_OldRocketTrail( ent, wi );
- }
-}
-
-static void CG_PlasmaTrail( centity_t *ent, const weaponInfo_t *wi ) {
-
- if (cg_leiEnhancement.integer) {
- CG_LeiPlasmaTrail( ent, wi );
- }
- else
- {
- CG_OldPlasmaTrail( ent, wi );
- }
-}
-
-
-static void CG_GrenadeTrail( centity_t *ent, const weaponInfo_t *wi ) {
- CG_RocketTrail( ent, wi );
-}
-
-
-
-
-
-
-/*
-=================
-CG_RegisterWeapon
-
-The server says this item is used on this level
-=================
-*/
-void CG_RegisterWeapon( int weaponNum ) {
- weaponInfo_t *weaponInfo;
- gitem_t *item, *ammo;
- char path[MAX_QPATH];
- vec3_t mins, maxs;
- int i;
-
- weaponInfo = &cg_weapons[weaponNum];
-
- if ( weaponNum == 0 ) {
- return;
- }
-
- if ( weaponInfo->registered ) {
- return;
- }
-
- memset( weaponInfo, 0, sizeof( *weaponInfo ) );
- weaponInfo->registered = qtrue;
-
- for ( item = bg_itemlist + 1 ; item->classname ; item++ ) {
- if ( item->giType == IT_WEAPON && item->giTag == weaponNum ) {
- weaponInfo->item = item;
- break;
- }
- }
- if ( !item->classname ) {
- CG_Error( "Couldn't find weapon %i", weaponNum );
- }
- CG_RegisterItemVisuals( item - bg_itemlist );
-
- // load cmodel before model so filecache works
- weaponInfo->weaponModel = trap_R_RegisterModel( item->world_model[0] );
-
- // calc midpoint for rotation
- trap_R_ModelBounds( weaponInfo->weaponModel, mins, maxs );
- for ( i = 0 ; i < 3 ; i++ ) {
- weaponInfo->weaponMidpoint[i] = mins[i] + 0.5 * ( maxs[i] - mins[i] );
- }
-
- weaponInfo->weaponIcon = trap_R_RegisterShader( item->icon );
- weaponInfo->ammoIcon = trap_R_RegisterShader( item->icon );
-
- for ( ammo = bg_itemlist + 1 ; ammo->classname ; ammo++ ) {
- if ( ammo->giType == IT_AMMO && ammo->giTag == weaponNum ) {
- break;
- }
- }
- if ( ammo->classname && ammo->world_model[0] ) {
- weaponInfo->ammoModel = trap_R_RegisterModel( ammo->world_model[0] );
- }
-
- Q_strncpyz( path, item->world_model[0], MAX_QPATH );
- COM_StripExtension(path, path, sizeof(path));
- strcat( path, "_flash.md3" );
- weaponInfo->flashModel = trap_R_RegisterModel( path );
-
- Q_strncpyz( path, item->world_model[0], MAX_QPATH );
- COM_StripExtension(path, path, sizeof(path));
- strcat( path, "_barrel.md3" );
- weaponInfo->barrelModel = trap_R_RegisterModel( path );
-
- Q_strncpyz( path, item->world_model[0], MAX_QPATH );
- COM_StripExtension(path, path, sizeof(path));
- strcat( path, "_hand.md3" );
- weaponInfo->handsModel = trap_R_RegisterModel( path );
-
- if ( !weaponInfo->handsModel ) {
- weaponInfo->handsModel = trap_R_RegisterModel( "models/weapons2/shotgun/shotgun_hand.md3" );
- }
-
- weaponInfo->loopFireSound = qfalse;
-
- switch ( weaponNum ) {
- case WP_GAUNTLET:
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/melee/fstatck.wav", qfalse );
- break;
-
- case WP_LIGHTNING:
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse );
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/lightning/lg_hum.wav", qfalse );
-
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/lightning/lg_fire.wav", qfalse );
- cgs.media.lightningShader = trap_R_RegisterShader( "lightningBoltNew");
- cgs.media.lightningExplosionModel = trap_R_RegisterModel( "models/weaphits/crackle.md3" );
- cgs.media.sfx_lghit1 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit.wav", qfalse );
- cgs.media.sfx_lghit2 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit2.wav", qfalse );
- cgs.media.sfx_lghit3 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit3.wav", qfalse );
-
- break;
-
- case WP_GRAPPLING_HOOK:
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" );
- weaponInfo->missileTrailFunc = CG_GrappleTrail;
- weaponInfo->missileDlight = 200;
- weaponInfo->wiTrailTime = 2000;
- weaponInfo->trailRadius = 64;
- MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse );
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse );
- break;
-
-//#ifdef MISSIONPACK
- case WP_CHAINGUN:
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/vulcan/wvulfire.wav", qfalse );
- weaponInfo->loopFireSound = qtrue;
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf1b.wav", qfalse );
- weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf2b.wav", qfalse );
- weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf3b.wav", qfalse );
- weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf4b.wav", qfalse );
- weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;
- cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
- break;
-//#endif
-
- case WP_MACHINEGUN:
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf1b.wav", qfalse );
- weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf2b.wav", qfalse );
- weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf3b.wav", qfalse );
- weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf4b.wav", qfalse );
- weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;
- cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
- break;
-
- case WP_SHOTGUN:
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/shotgun/sshotf1b.wav", qfalse );
- weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass;
- break;
-
- case WP_ROCKET_LAUNCHER:
- weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" );
- weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse );
- weaponInfo->missileTrailFunc = CG_RocketTrail;
- weaponInfo->missileDlight = 200;
- weaponInfo->wiTrailTime = 2000;
- weaponInfo->trailRadius = 64;
-
- MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 );
-
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse );
- cgs.media.rocketExplosionShader = trap_R_RegisterShader( "rocketExplosion" );
- break;
-
-//#ifdef MISSIONPACK
- case WP_PROX_LAUNCHER:
- weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/proxmine.md3" );
- weaponInfo->missileTrailFunc = CG_GrenadeTrail;
- weaponInfo->wiTrailTime = 700;
- weaponInfo->trailRadius = 32;
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/proxmine/wstbfire.wav", qfalse );
- cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" );
- break;
-//#endif
-
- case WP_GRENADE_LAUNCHER:
- weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/grenade1.md3" );
- weaponInfo->missileTrailFunc = CG_GrenadeTrail;
- weaponInfo->wiTrailTime = 700;
- weaponInfo->trailRadius = 32;
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/grenade/grenlf1a.wav", qfalse );
- cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" );
- break;
-
-//#ifdef MISSIONPACK
- case WP_NAILGUN:
- weaponInfo->ejectBrassFunc = CG_NailgunEjectBrass;
- weaponInfo->missileTrailFunc = CG_NailTrail;
-// weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/nailgun/wnalflit.wav", qfalse );
- weaponInfo->trailRadius = 16;
- weaponInfo->wiTrailTime = 250;
- weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/nail.md3" );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/nailgun/wnalfire.wav", qfalse );
- break;
-//#endif
-
- case WP_PLASMAGUN:
-// weaponInfo->missileModel = cgs.media.invulnerabilityPowerupModel;
- weaponInfo->missileTrailFunc = CG_PlasmaTrail;
- weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/plasma/lasfly.wav", qfalse );
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/plasma/hyprbf1a.wav", qfalse );
- cgs.media.plasmaExplosionShader = trap_R_RegisterShader( "plasmaExplosion" );
- cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" );
- break;
-
- case WP_RAILGUN:
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/railgun/rg_hum.wav", qfalse );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.5f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/railgun/railgf1a.wav", qfalse );
- cgs.media.railExplosionShader = trap_R_RegisterShader( "railExplosion" );
- cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" );
- cgs.media.railCoreShader = trap_R_RegisterShader( "railCore" );
- break;
-
- case WP_BFG:
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/bfg/bfg_hum.wav", qfalse );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.7f, 1 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/bfg/bfg_fire.wav", qfalse );
- cgs.media.bfgExplosionShader = trap_R_RegisterShader( "bfgExplosion" );
- weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/bfg.md3" );
- weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse );
- break;
-
- default:
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 1 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse );
- break;
- }
-}
-
-/*
-=================
-CG_RegisterItemVisuals
-
-The server says this item is used on this level
-=================
-*/
-void CG_RegisterItemVisuals( int itemNum ) {
- itemInfo_t *itemInfo;
- gitem_t *item;
-
- if ( itemNum < 0 || itemNum >= bg_numItems ) {
- CG_Error( "CG_RegisterItemVisuals: itemNum %d out of range [0-%d]", itemNum, bg_numItems-1 );
- }
-
- itemInfo = &cg_items[ itemNum ];
- if ( itemInfo->registered ) {
- return;
- }
-
- item = &bg_itemlist[ itemNum ];
-
- memset( itemInfo, 0, sizeof( &itemInfo ) );
- itemInfo->registered = qtrue;
-
- itemInfo->models[0] = trap_R_RegisterModel( item->world_model[0] );
-
- itemInfo->icon = trap_R_RegisterShader( item->icon );
-
- if ( item->giType == IT_WEAPON ) {
- CG_RegisterWeapon( item->giTag );
- }
-
- //
- // powerups have an accompanying ring or sphere
- //
- if ( item->giType == IT_POWERUP || item->giType == IT_HEALTH ||
- item->giType == IT_ARMOR || item->giType == IT_HOLDABLE ) {
- if ( item->world_model[1] ) {
- itemInfo->models[1] = trap_R_RegisterModel( item->world_model[1] );
- }
- }
-}
-
-
-/*
-========================================================================================
-
-VIEW WEAPON
-
-========================================================================================
-*/
-
-/*
-=================
-CG_MapTorsoToWeaponFrame
-
-=================
-*/
-static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame ) {
-
- // change weapon
- if ( frame >= ci->animations[TORSO_DROP].firstFrame
- && frame < ci->animations[TORSO_DROP].firstFrame + 9 ) {
- return frame - ci->animations[TORSO_DROP].firstFrame + 6;
- }
-
- // stand attack
- if ( frame >= ci->animations[TORSO_ATTACK].firstFrame
- && frame < ci->animations[TORSO_ATTACK].firstFrame + 6 ) {
- return 1 + frame - ci->animations[TORSO_ATTACK].firstFrame;
- }
-
- // stand attack 2
- if ( frame >= ci->animations[TORSO_ATTACK2].firstFrame
- && frame < ci->animations[TORSO_ATTACK2].firstFrame + 6 ) {
- return 1 + frame - ci->animations[TORSO_ATTACK2].firstFrame;
- }
-
- return 0;
-}
-
-
-/*
-==============
-CG_CalculateWeaponPosition
-==============
-*/
-static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) {
- float scale;
- int delta;
- float fracsin;
-
- VectorCopy( cg.refdef.vieworg, origin );
- VectorCopy( cg.refdefViewAngles, angles );
-
- // on odd legs, invert some angles
- if ( cg.bobcycle & 1 ) {
- scale = -cg.xyspeed;
- } else {
- scale = cg.xyspeed;
- }
-
- // gun angles from bobbing
- angles[ROLL] += scale * cg.bobfracsin * 0.005;
- angles[YAW] += scale * cg.bobfracsin * 0.01;
- angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005;
-
- // drop the weapon when landing
- delta = cg.time - cg.landTime;
- if ( delta < LAND_DEFLECT_TIME ) {
- origin[2] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME;
- } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
- origin[2] += cg.landChange*0.25 *
- (LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME;
- }
-
-#if 0
- // drop the weapon when stair climbing
- delta = cg.time - cg.stepTime;
- if ( delta < STEP_TIME/2 ) {
- origin[2] -= cg.stepChange*0.25 * delta / (STEP_TIME/2);
- } else if ( delta < STEP_TIME ) {
- origin[2] -= cg.stepChange*0.25 * (STEP_TIME - delta) / (STEP_TIME/2);
- }
-#endif
-
- // idle drift
- scale = cg.xyspeed + 40;
- fracsin = sin( cg.time * 0.001 );
- angles[ROLL] += scale * fracsin * 0.01;
- angles[YAW] += scale * fracsin * 0.01;
- angles[PITCH] += scale * fracsin * 0.01;
-}
-
-
-/*
-===============
-CG_LightningBolt
-
-Origin will be the exact tag point, which is slightly
-different than the muzzle point used for determining hits.
-The cent should be the non-predicted cent if it is from the player,
-so the endpoint will reflect the simulated strike (lagging the predicted
-angle)
-===============
-*/
-static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
- trace_t trace;
- refEntity_t beam;
- vec3_t forward;
- vec3_t muzzlePoint, endPoint;
-
- if (cent->currentState.weapon != WP_LIGHTNING) {
- return;
- }
-
- memset( &beam, 0, sizeof( beam ) );
-
-//unlagged - attack prediction #1
- // if the entity is us, unlagged is on server-side, and we've got it on for the lightning gun
- if ( (cent->currentState.number == cg.predictedPlayerState.clientNum) && cgs.delagHitscan &&
- ( cg_delag.integer & 1 || cg_delag.integer & 8 ) ) {
- // always shoot straight forward from our current position
- AngleVectors( cg.predictedPlayerState.viewangles, forward, NULL, NULL );
- VectorCopy( cg.predictedPlayerState.origin, muzzlePoint );
- }
- else
-//unlagged - attack prediction #1
-
- // CPMA "true" lightning
- if ((cent->currentState.number == cg.predictedPlayerState.clientNum) && (cg_trueLightning.value != 0)) {
- vec3_t angle;
- int i;
-
-//unlagged - true lightning
- // might as well fix up true lightning while we're at it
- vec3_t viewangles;
- VectorCopy( cg.predictedPlayerState.viewangles, viewangles );
-//unlagged - true lightning
-
- for (i = 0; i < 3; i++) {
- float a = cent->lerpAngles[i] - cg.refdefViewAngles[i];
- if (a > 180) {
- a -= 360;
- }
- if (a < -180) {
- a += 360;
- }
-
- angle[i] = cg.refdefViewAngles[i] + a * (1.0 - cg_trueLightning.value);
- if (angle[i] < 0) {
- angle[i] += 360;
- }
- if (angle[i] > 360) {
- angle[i] -= 360;
- }
- }
-
- AngleVectors(angle, forward, NULL, NULL );
-//unlagged - true lightning
-// VectorCopy(cent->lerpOrigin, muzzlePoint );
-// VectorCopy(cg.refdef.vieworg, muzzlePoint );
- // *this* is the correct origin for true lightning
- VectorCopy(cg.predictedPlayerState.origin, muzzlePoint );
-//unlagged - true lightning
- } else {
- // !CPMA
- AngleVectors( cent->lerpAngles, forward, NULL, NULL );
- VectorCopy(cent->lerpOrigin, muzzlePoint );
- }
-
- // FIXME: crouch
- muzzlePoint[2] += DEFAULT_VIEWHEIGHT;
-
- VectorMA( muzzlePoint, 14, forward, muzzlePoint );
-
- // project forward by the lightning range
- VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );
-
- // see if it hit a wall
- CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint,
- cent->currentState.number, MASK_SHOT );
-
- // this is the endpoint
- VectorCopy( trace.endpos, beam.oldorigin );
-
- // use the provided origin, even though it may be slightly
- // different than the muzzle origin
- VectorCopy( origin, beam.origin );
-
- beam.reType = RT_LIGHTNING;
- beam.customShader = cgs.media.lightningShader;
- trap_R_AddRefEntityToScene( &beam );
-
- // add the impact flare if it hit something
- if ( trace.fraction < 1.0 ) {
- vec3_t angles;
- vec3_t dir;
-
- VectorSubtract( beam.oldorigin, beam.origin, dir );
- VectorNormalize( dir );
-
- memset( &beam, 0, sizeof( beam ) );
- beam.hModel = cgs.media.lightningExplosionModel;
-
- VectorMA( trace.endpos, -16, dir, beam.origin );
-
- // make a random orientation
- angles[0] = rand() % 360;
- angles[1] = rand() % 360;
- angles[2] = rand() % 360;
- AnglesToAxis( angles, beam.axis );
- trap_R_AddRefEntityToScene( &beam );
- }
-}
-/*
-
-static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
- trace_t trace;
- refEntity_t beam;
- vec3_t forward;
- vec3_t muzzlePoint, endPoint;
-
- if ( cent->currentState.weapon != WP_LIGHTNING ) {
- return;
- }
-
- memset( &beam, 0, sizeof( beam ) );
-
- // find muzzle point for this frame
- VectorCopy( cent->lerpOrigin, muzzlePoint );
- AngleVectors( cent->lerpAngles, forward, NULL, NULL );
-
- // FIXME: crouch
- muzzlePoint[2] += DEFAULT_VIEWHEIGHT;
-
- VectorMA( muzzlePoint, 14, forward, muzzlePoint );
-
- // project forward by the lightning range
- VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );
-
- // see if it hit a wall
- CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint,
- cent->currentState.number, MASK_SHOT );
-
- // this is the endpoint
- VectorCopy( trace.endpos, beam.oldorigin );
-
- // use the provided origin, even though it may be slightly
- // different than the muzzle origin
- VectorCopy( origin, beam.origin );
-
- beam.reType = RT_LIGHTNING;
- beam.customShader = cgs.media.lightningShader;
- trap_R_AddRefEntityToScene( &beam );
-
- // add the impact flare if it hit something
- if ( trace.fraction < 1.0 ) {
- vec3_t angles;
- vec3_t dir;
-
- VectorSubtract( beam.oldorigin, beam.origin, dir );
- VectorNormalize( dir );
-
- memset( &beam, 0, sizeof( beam ) );
- beam.hModel = cgs.media.lightningExplosionModel;
-
- VectorMA( trace.endpos, -16, dir, beam.origin );
-
- // make a random orientation
- angles[0] = rand() % 360;
- angles[1] = rand() % 360;
- angles[2] = rand() % 360;
- AnglesToAxis( angles, beam.axis );
- trap_R_AddRefEntityToScene( &beam );
- }
-}
-*/
-
-/*
-===============
-CG_SpawnRailTrail
-
-Origin will be the exact tag point, which is slightly
-different than the muzzle point used for determining hits.
-===============
-*/
-static void CG_SpawnRailTrail( centity_t *cent, vec3_t origin ) {
- clientInfo_t *ci;
-
- if ( cent->currentState.weapon != WP_RAILGUN ) {
- return;
- }
- if ( !cent->pe.railgunFlash ) {
- return;
- }
- cent->pe.railgunFlash = qtrue;
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- CG_RailTrail( ci, origin, cent->pe.railgunImpact );
-}
-
-
-/*
-======================
-CG_MachinegunSpinAngle
-======================
-*/
-#define SPIN_SPEED 0.9
-#define COAST_TIME 1000
-static float CG_MachinegunSpinAngle( centity_t *cent ) {
- int delta;
- float angle;
- float speed;
-
- delta = cg.time - cent->pe.barrelTime;
- if ( cent->pe.barrelSpinning ) {
- angle = cent->pe.barrelAngle + delta * SPIN_SPEED;
- } else {
- if ( delta > COAST_TIME ) {
- delta = COAST_TIME;
- }
-
- speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
- angle = cent->pe.barrelAngle + delta * speed;
- }
-
- if ( cent->pe.barrelSpinning == !(cent->currentState.eFlags & EF_FIRING) ) {
- cent->pe.barrelTime = cg.time;
- cent->pe.barrelAngle = AngleMod( angle );
- cent->pe.barrelSpinning = !!(cent->currentState.eFlags & EF_FIRING);
-//#ifdef MISSIONPACK
- if ( cent->currentState.weapon == WP_CHAINGUN && !cent->pe.barrelSpinning ) {
- trap_S_StartSound( NULL, cent->currentState.number, CHAN_WEAPON, trap_S_RegisterSound( "sound/weapons/vulcan/wvulwind.wav", qfalse ) );
- }
-//#endif
- }
-
- return angle;
-}
-
-
-/*
-========================
-CG_AddWeaponWithPowerups
-========================
-*/
-static void CG_AddWeaponWithPowerups( refEntity_t *gun, int powerups ) {
- // add powerup effects
- if ( powerups & ( 1 << PW_INVIS ) ) {
- gun->customShader = cgs.media.invisShader;
- trap_R_AddRefEntityToScene( gun );
- } else {
- trap_R_AddRefEntityToScene( gun );
-
- if ( powerups & ( 1 << PW_BATTLESUIT ) ) {
- gun->customShader = cgs.media.battleWeaponShader;
- trap_R_AddRefEntityToScene( gun );
- }
- if ( powerups & ( 1 << PW_QUAD ) ) {
- gun->customShader = cgs.media.quadWeaponShader;
- trap_R_AddRefEntityToScene( gun );
- }
- }
-}
-
-
-/*
-=============
-CG_AddPlayerWeapon
-
-Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL)
-The main player will have this called for BOTH cases, so effects like light and
-sound should only be done on the world model case.
-=============
-*/
-void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team ) {
- refEntity_t gun;
- refEntity_t barrel;
- refEntity_t flash;
- vec3_t angles;
- weapon_t weaponNum;
- weaponInfo_t *weapon;
- centity_t *nonPredictedCent;
- orientation_t lerped;
-
- weaponNum = cent->currentState.weapon;
-
- CG_RegisterWeapon( weaponNum );
- weapon = &cg_weapons[weaponNum];
-
- // add the weapon
- memset( &gun, 0, sizeof( gun ) );
- VectorCopy( parent->lightingOrigin, gun.lightingOrigin );
- gun.shadowPlane = parent->shadowPlane;
- gun.renderfx = parent->renderfx;
-
- // set custom shading for railgun refire rate
- if ( ps ) {
- if ( cg.predictedPlayerState.weapon == WP_RAILGUN
- && cg.predictedPlayerState.weaponstate == WEAPON_FIRING ) {
- float f;
-
- f = (float)cg.predictedPlayerState.weaponTime / 1500;
- gun.shaderRGBA[1] = 0;
- gun.shaderRGBA[0] =
- gun.shaderRGBA[2] = 255 * ( 1.0 - f );
- } else {
- gun.shaderRGBA[0] = 255;
- gun.shaderRGBA[1] = 255;
- gun.shaderRGBA[2] = 255;
- gun.shaderRGBA[3] = 255;
- }
- }
-
- gun.hModel = weapon->weaponModel;
- if (!gun.hModel) {
- return;
- }
-
- if ( !ps ) {
- // add weapon ready sound
- cent->pe.lightningFiring = qfalse;
- if ( ( cent->currentState.eFlags & EF_FIRING ) && weapon->firingSound ) {
- // lightning gun and guantlet make a different sound when fire is held down
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound );
- cent->pe.lightningFiring = qtrue;
- } else if ( weapon->readySound ) {
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound );
- }
- }
-
- trap_R_LerpTag(&lerped, parent->hModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, "tag_weapon");
- VectorCopy(parent->origin, gun.origin);
-
- VectorMA(gun.origin, lerped.origin[0], parent->axis[0], gun.origin);
-
- // Make weapon appear left-handed for 2 and centered for 3
- if(ps && cg_drawGun.integer == 2)
- VectorMA(gun.origin, -lerped.origin[1], parent->axis[1], gun.origin);
- else if(!ps || cg_drawGun.integer != 3)
- VectorMA(gun.origin, lerped.origin[1], parent->axis[1], gun.origin);
-
- VectorMA(gun.origin, lerped.origin[2], parent->axis[2], gun.origin);
-
- MatrixMultiply(lerped.axis, ((refEntity_t *)parent)->axis, gun.axis);
- gun.backlerp = parent->backlerp;
-
- CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups );
-
- // add the spinning barrel
- if ( weapon->barrelModel ) {
- memset( &barrel, 0, sizeof( barrel ) );
- VectorCopy( parent->lightingOrigin, barrel.lightingOrigin );
- barrel.shadowPlane = parent->shadowPlane;
- barrel.renderfx = parent->renderfx;
-
- barrel.hModel = weapon->barrelModel;
- angles[YAW] = 0;
- angles[PITCH] = 0;
- angles[ROLL] = CG_MachinegunSpinAngle( cent );
- AnglesToAxis( angles, barrel.axis );
-
- CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" );
-
- CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups );
- }
-
- // make sure we aren't looking at cg.predictedPlayerEntity for LG
- nonPredictedCent = &cg_entities[cent->currentState.clientNum];
-
- // if the index of the nonPredictedCent is not the same as the clientNum
- // then this is a fake player (like on teh single player podiums), so
- // go ahead and use the cent
- if( ( nonPredictedCent - cg_entities ) != cent->currentState.clientNum ) {
- nonPredictedCent = cent;
- }
-
- // add the flash
- if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK )
- && ( nonPredictedCent->currentState.eFlags & EF_FIRING ) )
- {
- // continuous flash
- } else {
- // impulse flash
- if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash ) {
- return;
- }
- }
-
- memset( &flash, 0, sizeof( flash ) );
- VectorCopy( parent->lightingOrigin, flash.lightingOrigin );
- flash.shadowPlane = parent->shadowPlane;
- flash.renderfx = parent->renderfx;
-
- flash.hModel = weapon->flashModel;
- if (!flash.hModel) {
- return;
- }
- angles[YAW] = 0;
- angles[PITCH] = 0;
- angles[ROLL] = crandom() * 10;
- AnglesToAxis( angles, flash.axis );
-
- // colorize the railgun blast
- if ( weaponNum == WP_RAILGUN ) {
- clientInfo_t *ci;
-
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- flash.shaderRGBA[0] = 255 * ci->color1[0];
- flash.shaderRGBA[1] = 255 * ci->color1[1];
- flash.shaderRGBA[2] = 255 * ci->color1[2];
- }
-
- CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash");
- trap_R_AddRefEntityToScene( &flash );
-
- if ( ps || cg.renderingThirdPerson ||
- cent->currentState.number != cg.predictedPlayerState.clientNum ) {
- // add lightning bolt
- CG_LightningBolt( nonPredictedCent, flash.origin );
-
- // add rail trail
- CG_SpawnRailTrail( cent, flash.origin );
-
- if ( weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2] ) {
- trap_R_AddLightToScene( flash.origin, 300 + (rand()&31), weapon->flashDlightColor[0],
- weapon->flashDlightColor[1], weapon->flashDlightColor[2] );
- }
- }
-}
-
-/*
-==============
-CG_AddViewWeapon
-
-Add the weapon, and flash for the player's view
-==============
-*/
-void CG_AddViewWeapon( playerState_t *ps ) {
- refEntity_t hand;
- centity_t *cent;
- clientInfo_t *ci;
- float fovOffset;
- vec3_t angles;
- weaponInfo_t *weapon;
-
- if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
- return;
- }
-
- if ( ps->pm_type == PM_INTERMISSION ) {
- return;
- }
-
- // no gun if in third person view or a camera is active
- //if ( cg.renderingThirdPerson || cg.cameraMode) {
- if ( cg.renderingThirdPerson ) {
- return;
- }
-
-
- // allow the gun to be completely removed
- if ( !cg_drawGun.integer ) {
- vec3_t origin;
-
- if ( cg.predictedPlayerState.eFlags & EF_FIRING ) {
- // special hack for lightning gun...
- VectorCopy( cg.refdef.vieworg, origin );
- VectorMA( origin, -8, cg.refdef.viewaxis[2], origin );
- CG_LightningBolt( &cg_entities[ps->clientNum], origin );
- }
- return;
- }
-
- // don't draw if testing a gun model
- if ( cg.testGun ) {
- return;
- }
-
- // drop gun lower at higher fov
- if ( cg_fov.integer > 90 ) {
- fovOffset = -0.2 * ( cg_fov.integer - 90 );
- } else {
- fovOffset = 0;
- }
-
- cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum];
- CG_RegisterWeapon( ps->weapon );
- weapon = &cg_weapons[ ps->weapon ];
-
- memset (&hand, 0, sizeof(hand));
-
- // set up gun position
- CG_CalculateWeaponPosition( hand.origin, angles );
-
- VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin );
- VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin );
- VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin );
-
- AnglesToAxis( angles, hand.axis );
-
- // map torso animations to weapon animations
- if ( cg_gun_frame.integer ) {
- // development tool
- hand.frame = hand.oldframe = cg_gun_frame.integer;
- hand.backlerp = 0;
- } else {
- // get clientinfo for animation map
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame );
- hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame );
- hand.backlerp = cent->pe.torso.backlerp;
- }
-
- hand.hModel = weapon->handsModel;
- hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT;
-
- // add everything onto the hand
- CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->persistant[PERS_TEAM] );
-}
-
-/*
-==============================================================================
-
-WEAPON SELECTION
-
-==============================================================================
-*/
-
-/*
-===================
-CG_DrawWeaponSelect
-===================
-*/
-void CG_DrawWeaponSelect( void ) {
- int i;
- int bits;
- int count;
- float *color;
- vec4_t realColor;
-
-
-
- // don't display if dead
- if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
- return;
- }
-
- color = CG_FadeColor( cg.weaponSelectTime, WEAPON_SELECT_TIME );
-
- //Elimination: Always show weapon bar
- if(cg_alwaysWeaponBar.integer) {
- realColor[0] = 1.0;
- realColor[1] = 1.0;
- realColor[2] = 1.0;
- realColor[3] = 1.0;
- color = realColor;
- }
-
- if ( !color ) {
- return;
- }
- trap_R_SetColor( color );
-
- // showing weapon select clears pickup item display, but not the blend blob
- cg.itemPickupTime = 0;
-
- // count the number of weapons owned
- bits = cg.snap->ps.stats[ STAT_WEAPONS ];
- count = 0;
- for ( i = 1 ; i < MAX_WEAPONS ; i++ ) {
- if ( bits & ( 1 << i ) ) {
- count++;
- }
- }
-
- switch(cg_weaponBarStyle.integer){
- case 0:
- CG_DrawWeaponBar0(count,bits);
- break;
- case 1:
- CG_DrawWeaponBar1(count,bits);
- break;
- case 2:
- CG_DrawWeaponBar2(count,bits, color);
- break;
- case 3:
- CG_DrawWeaponBar3(count,bits, color);
- break;
- case 4:
- CG_DrawWeaponBar4(count,bits, color);
- break;
- case 5:
- CG_DrawWeaponBar5(count,bits, color);
- break;
- case 6:
- CG_DrawWeaponBar6(count,bits, color);
- break;
- case 7:
- CG_DrawWeaponBar7(count,bits, color);
- break;
- }
- trap_R_SetColor(NULL);
- return;
-}
-
-/*
-===============
-CG_DrawWeaponBar0
-===============
-*/
-
-void CG_DrawWeaponBar0(int count, int bits){
-
- int y = 380;
- int x = 320 - count * 20;
- int i;
-
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- //Sago: Do mad change of grapple placement:
- if(i==10)
- continue;
- if(i==0)
- i=10;
- if ( !( bits & ( 1 << i ) ) ) {
- if(i==10)
- i=0;
- continue;
- }
-
- CG_RegisterWeapon( i );
- // draw weapon icon
- CG_DrawPic( x, y, 32, 32, cg_weapons[i].weaponIcon );
-
- // draw selection marker
- if ( i == cg.weaponSelect ) {
- CG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader );
- }
-
- // no ammo cross on top
- if ( !cg.snap->ps.ammo[ i ] ) {
- CG_DrawPic( x, y, 32, 32, cgs.media.noammoShader );
- }
-
- x += 40;
- //Sago: Undo mad change of weapons
- if(i==10)
- i=0;
- }
-}
-
-/*
-===============
-CG_DrawWeaponBar1
-===============
-*/
-
-void CG_DrawWeaponBar1(int count, int bits){
-
- int y = 380;
- int x = 320 - count * 20;
- int i;
- int ammo;
- int br;
- int max;
- float red[4];
- float yellow[4];
- float green[4];
-
- red[0] = 1.0f;
- red[1] = 0;
- red[2] = 0;
- red[3] = 1.0f;
-
- yellow[0] = 1.0f;
- yellow[1] = 0.6f;
- yellow[2] = 0;
- yellow[3] = 1.0f;
-
- green[0] = 0;
- green[1] = 1.0f;
- green[2] = 0;
- green[3] = 1.0f;
-
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- //Sago: Do mad change of grapple placement:
- if(i==10)
- continue;
- if(i==0)
- i=10;
- if ( !( bits & ( 1 << i ) ) ) {
- if(i==10)
- i=0;
- continue;
- }
-
- ammo=cg.snap->ps.ammo[i];
-
- switch(i) {
- case WP_MACHINEGUN: max = 100; break;
- case WP_SHOTGUN: max = 10; break;
- case WP_GRENADE_LAUNCHER: max = 10; break;
- case WP_ROCKET_LAUNCHER: max = 10; break;
- case WP_LIGHTNING: max = 100; break;
- case WP_RAILGUN: max = 10; break;
- case WP_PLASMAGUN: max = 50; break;
- case WP_BFG: max = 10; break;
- case WP_NAILGUN: max = 10; break;
- case WP_PROX_LAUNCHER: max = 5; break;
- case WP_CHAINGUN: max = 100; break;
- default: max = 1; break;
- }
-
- ammo = (ammo*100)/max;
- if(ammo >=100)
- ammo=100;
-
- br=ammo*32/100;
-
- if(i!=1){
- if(ammo <= 20)
- CG_FillRect( x, y+38, br,4, red);
- if(ammo > 20 && ammo <= 50)
- CG_FillRect( x, y+38, br, 4, yellow);
- if(ammo > 50)
- CG_FillRect( x, y+38, br, 4, green);
- }
-
- CG_RegisterWeapon( i );
- // draw weapon icon
- CG_DrawPic( x, y, 32, 32, cg_weapons[i].weaponIcon );
-
- // draw selection marker
- if ( i == cg.weaponSelect ) {
- CG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader );
- }
-
- // no ammo cross on top
- if ( !cg.snap->ps.ammo[ i ] ) {
- CG_DrawPic( x, y, 32, 32, cgs.media.noammoShader );
- }
-
- x += 40;
- //Sago: Undo mad change of weapons
- if(i==10)
- i=0;
- }
-}
-
-/*
-===============
-CG_DrawWeaponBar2
-===============
-*/
-
-void CG_DrawWeaponBar2(int count, int bits, float *color){
-
- int y = 200 + count * 12;
- int x = 0;
- int i;
- int w;
- char *s;
- float red[4];
- float yellow[4];
- float blue[4];
-
- red[0] = 1.0f;
- red[1] = 0;
- red[2] = 0;
- red[3] = 0.4f;
-
- yellow[0] = 1.0f;
- yellow[1] = 1.0f;
- yellow[2] = 0;
- yellow[3] = 1.0f;
-
- blue[0] = 0;
- blue[1] = 0;
- blue[2] = 1.0f;
- blue[3] = 0.4f;
-
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- //Sago: Do mad change of grapple placement:
- if(i==10)
- continue;
- if(i==0)
- i=10;
- if ( !( bits & ( 1 << i ) ) ) {
- if(i==10)
- i=0;
- continue;
- }
-
- if(cg.snap->ps.ammo[i]){
- if ( i == cg.weaponSelect) {
- CG_FillRect( x, y, 50, 24, blue );
- CG_DrawRect( x, y, 50, 24, 2, yellow);
- }
- else{
- CG_FillRect( x, y,50, 24, blue );
- }
- }
- else{
- if ( i == cg.weaponSelect) {
- CG_FillRect( x, y, 50, 24, red );
- CG_DrawRect( x, y, 50, 24, 2, yellow);
- }
- else{
- CG_FillRect( x, y,50, 24, red );
- }
- }
-
- // draw weapon icon
- CG_DrawPic( x+2, y+4, 16, 16, cg_weapons[i].weaponIcon );
-
- /** Draw Weapon Ammo **/
- if(cg.snap->ps.ammo[ i ]!=-1){
- s = va("%i", cg.snap->ps.ammo[ i ] );
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- CG_DrawSmallStringColor(x - w/2 + 32, y+4, s, color);
- }
-
- y -= 24;
- //Sago: Undo mad change of weapons
- if(i==10)
- i=0;
- }
-}
-
-/*
-===============
-CG_DrawWeaponBar3
-===============
-*/
-
-void CG_DrawWeaponBar3(int count, int bits, float *color){
-
- int y = 200 + count * 12;
- int x = 0;
- int i;
- int ammo;
- int max;
- int br;
- int w;
- char *s;
- float red[4];
- float yellow[4];
- float green[4];
- float blue[4];
-
- red[0] = 1.0f;
- red[1] = 0;
- red[2] = 0;
- red[3] = 0.4f;
-
- yellow[0] = 1.0f;
- yellow[1] = 1.0f;
- yellow[2] = 0;
- yellow[3] = 1.0f;
-
- green[0] = 0;
- green[1] = 1.0f;
- green[2] = 0;
- green[3] = 1.0f;
-
- blue[0] = 0;
- blue[1] = 0;
- blue[2] = 1.0f;
- blue[3] = 0.4f;
-
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- //Sago: Do mad change of grapple placement:
- if(i==10)
- continue;
- if(i==0)
- i=10;
- if ( !( bits & ( 1 << i ) ) ) {
- if(i==10)
- i=0;
- continue;
- }
-
- ammo=cg.snap->ps.ammo[i];
-
- switch(i) {
- case WP_MACHINEGUN: max = 100; break;
- case WP_SHOTGUN: max = 10; break;
- case WP_GRENADE_LAUNCHER: max = 10; break;
- case WP_ROCKET_LAUNCHER: max = 10; break;
- case WP_LIGHTNING: max = 100; break;
- case WP_RAILGUN: max = 10; break;
- case WP_PLASMAGUN: max = 50; break;
- case WP_BFG: max = 10; break;
- case WP_NAILGUN: max = 10; break;
- case WP_PROX_LAUNCHER: max = 5; break;
- case WP_CHAINGUN: max = 100; break;
- default: max = 1; break;
- }
-
- ammo = (ammo*100)/max;
- if(ammo >=100)
- ammo=100;
-
- br=ammo*20/100;
-
- if(i!=1){
- if(ammo <= 20)
- CG_FillRect( 51, y+2+20-br, 4,br, red);
- if(ammo > 20 && ammo <= 50)
- CG_FillRect( 51, y+2+20-br, 4,br, yellow);
- if(ammo > 50)
- CG_FillRect( 51, y+2+20-br, 4,br, green);
- }
-
- if(cg.snap->ps.ammo[i]){
- if ( i == cg.weaponSelect) {
- CG_FillRect( x, y, 50, 24, blue );
- CG_DrawRect( x, y, 50, 24, 2, yellow);
- }
- else{
- CG_FillRect( x, y,50, 24, blue );
- }
- }
- else{
- if ( i == cg.weaponSelect) {
- CG_FillRect( x, y, 50, 24, red );
- CG_DrawRect( x, y, 50, 24, 2, yellow);
- }
- else{
- CG_FillRect( x, y,50, 24, red );
- }
- }
-
- // draw weapon icon
- CG_DrawPic( x+2, y+4, 16, 16, cg_weapons[i].weaponIcon );
-
- /** Draw Weapon Ammo **/
- if(cg.snap->ps.ammo[ i ]!=-1){
- s = va("%i", cg.snap->ps.ammo[ i ] );
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- CG_DrawSmallStringColor(x - w/2 + 32, y+4, s, color);
- }
-
- y -= 24;
- //Sago: Undo mad change of weapons
- if(i==10)
- i=0;
- }
-}
-
-/*
-===============
-CG_DrawWeaponBar4
-===============
-*/
-
-void CG_DrawWeaponBar4(int count, int bits, float *color){
-
- int y = 200 + count * 12;
- int x = 0;
- int i;
- float ammo;
- int max;
- int w;
- char *s;
- float boxColor[4];
- float yellow[4];
-
- boxColor[1]=0;
- boxColor[3]=0.4f;
-
- yellow[0] = 1.0f;
- yellow[1] = 1.0f;
- yellow[2] = 0;
- yellow[3] = 1.0f;
-
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- //Sago: Do mad change of grapple placement:
- if(i==10)
- continue;
- if(i==0)
- i=10;
- if ( !( bits & ( 1 << i ) ) ) {
- if(i==10)
- i=0;
- continue;
- }
-
- ammo=cg.snap->ps.ammo[i];
-
- switch(i) {
- case WP_MACHINEGUN: max = 100; break;
- case WP_SHOTGUN: max = 10; break;
- case WP_GRENADE_LAUNCHER: max = 10; break;
- case WP_ROCKET_LAUNCHER: max = 10; break;
- case WP_LIGHTNING: max = 100; break;
- case WP_RAILGUN: max = 10; break;
- case WP_PLASMAGUN: max = 50; break;
- case WP_BFG: max = 10; break;
- case WP_NAILGUN: max = 10; break;
- case WP_PROX_LAUNCHER: max = 5; break;
- case WP_CHAINGUN: max = 100; break;
- default: max = 1; break;
- }
-
- ammo = (ammo*100)/max;
-
- if((ammo >=100) || (ammo < 0))
- ammo=100;
-
- boxColor[2]=(ammo/100.0f)*1.0f;
- boxColor[0]=1.0f-(ammo/100.0f)*1.0f;
-
- if ( i == cg.weaponSelect) {
- CG_FillRect( x, y, 50, 24, boxColor );
- CG_DrawRect( x, y, 50, 24, 2, yellow);
- }
- else{
- CG_FillRect( x, y,50, 24, boxColor );
- }
-
- // draw weapon icon
- CG_DrawPic( x+2, y+4, 16, 16, cg_weapons[i].weaponIcon );
-
- /** Draw Weapon Ammo **/
- if(cg.snap->ps.ammo[ i ]!=-1){
- s = va("%i", cg.snap->ps.ammo[ i ] );
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- CG_DrawSmallStringColor(x - w/2 + 32, y+4, s, color);
- }
-
- y -= 24;
- //Sago: Undo mad change of weapons
- if(i==10)
- i=0;
- }
-}
-
-/*
-===============
-CG_DrawWeaponBar5
-===============
-*/
-
-void CG_DrawWeaponBar5(int count, int bits, float *color){
-
- int y = 380;
- int x = 320 - count * 15;
- int i;
- int w;
- char *s;
- float red[4];
- float yellow[4];
- float blue[4];
-
- red[0] = 1.0f;
- red[1] = 0;
- red[2] = 0;
- red[3] = 0.4f;
-
- yellow[0] = 1.0f;
- yellow[1] = 1.0f;
- yellow[2] = 0;
- yellow[3] = 1.0f;
-
- blue[0] = 0;
- blue[1] = 0;
- blue[2] = 1.0f;
- blue[3] = 0.4f;
-
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- //Sago: Do mad change of grapple placement:
- if(i==10)
- continue;
- if(i==0)
- i=10;
- if ( !( bits & ( 1 << i ) ) ) {
- if(i==10)
- i=0;
- continue;
- }
-
- if(cg.snap->ps.ammo[i]){
- if ( i == cg.weaponSelect) {
- CG_FillRect( x, y , 30 , 38, blue );
- CG_DrawRect( x, y, 30 ,38 ,2, yellow);
- }
- else{
- CG_FillRect( x, y,30, 38, blue );
- }
- }
- else{
- if ( i == cg.weaponSelect) {
- CG_FillRect( x, y , 30 , 38, red );
- CG_DrawRect( x , y, 30,38,2, yellow);
- }
- else{
- CG_FillRect( x, y,30, 38, red );
- }
- }
-
- CG_DrawPic( x+7, y+2, 16, 16, cg_weapons[i].weaponIcon );
-
- if(cg.snap->ps.ammo[ i ]!=-1){
- s = va("%i", cg.snap->ps.ammo[ i ] );
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- CG_DrawSmallStringColor(x - w/2 + 15, y+20, s, color);
- }
-
- x += 30;
- //Sago: Undo mad change of weapons
- if(i==10)
- i=0;
- }
-}
-
-/*
-===============
-CG_DrawWeaponBar6
-===============
-*/
-
-void CG_DrawWeaponBar6(int count, int bits, float *color){
-
- int y = 380;
- int x = 320 - count * 15;
- int i;
- int ammo;
- int max;
- int br;
- int w;
- char *s;
- float red[4];
- float yellow[4];
- float green[4];
- float blue[4];
-
- red[0] = 1.0f;
- red[1] = 0;
- red[2] = 0;
- red[3] = 0.4f;
-
- yellow[0] = 1.0f;
- yellow[1] = 1.0f;
- yellow[2] = 0;
- yellow[3] = 1.0f;
-
- green[0] = 0;
- green[1] = 1.0f;
- green[2] = 0;
- green[3] = 1.0f;
-
- blue[0] = 0;
- blue[1] = 0;
- blue[2] = 1.0f;
- blue[3] = 0.4f;
-
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- //Sago: Do mad change of grapple placement:
- if(i==10)
- continue;
- if(i==0)
- i=10;
- if ( !( bits & ( 1 << i ) ) ) {
- if(i==10)
- i=0;
- continue;
- }
-
- ammo=cg.snap->ps.ammo[i];
-
- switch(i) {
- case WP_MACHINEGUN: max = 100; break;
- case WP_SHOTGUN: max = 10; break;
- case WP_GRENADE_LAUNCHER: max = 10; break;
- case WP_ROCKET_LAUNCHER: max = 10; break;
- case WP_LIGHTNING: max = 100; break;
- case WP_RAILGUN: max = 10; break;
- case WP_PLASMAGUN: max = 50; break;
- case WP_BFG: max = 10; break;
- case WP_NAILGUN: max = 10; break;
- case WP_PROX_LAUNCHER: max = 5; break;
- case WP_CHAINGUN: max = 100; break;
- default: max = 1; break;
- }
-
- ammo = (ammo*100)/max;
-
- if(ammo >=100)
- ammo=100;
-
- br=ammo*26/100;
-
- if(i!=1){
- if(ammo <= 20)
- CG_FillRect( x+2, y +40, br, 4, red);
- if(ammo > 20 && ammo <= 50)
- CG_FillRect( x+2, y+40, br, 4, yellow);
- if(ammo > 50)
- CG_FillRect( x+2, y+40, br, 4, green);
- }
-
- if(cg.snap->ps.ammo[i]){
- if ( i == cg.weaponSelect) {
- CG_FillRect( x, y , 30 , 38, blue );
- CG_DrawRect( x, y, 30 ,38 ,2, yellow);
- }
- else{
- CG_FillRect( x, y,30, 38, blue );
- }
- }
- else{
- if ( i == cg.weaponSelect) {
- CG_FillRect( x, y , 30 , 38, red );
- CG_DrawRect( x , y, 30,38,2, yellow);
- }
- else{
- CG_FillRect( x, y,30, 38, red );
- }
- }
-
- CG_DrawPic( x+7, y+2, 16, 16, cg_weapons[i].weaponIcon );
-
- if(cg.snap->ps.ammo[ i ]!=-1){
- s = va("%i", cg.snap->ps.ammo[ i ] );
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- CG_DrawSmallStringColor(x - w/2 + 15, y+20, s, color);
- }
-
- x += 30;
- //Sago: Undo mad change of weapons
- if(i==10)
- i=0;
- }
-}
-
-/*
-===============
-CG_DrawWeaponBar7
-===============
-*/
-
-void CG_DrawWeaponBar7(int count, int bits, float *color){
-
- int y = 380;
- int x = 320 - count * 15;
- int i;
- float ammo;
- float max;
- int w;
- char *s;
- float yellow[4];
- float boxColor[4];
-
- boxColor[1]=0;
- boxColor[3]=0.4f;
-
- yellow[0] = 1.0f;
- yellow[1] = 1.0f;
- yellow[2] = 0;
- yellow[3] = 1.0f;
-
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- //Sago: Do mad change of grapple placement:
- if(i==10)
- continue;
- if(i==0)
- i=10;
- if ( !( bits & ( 1 << i ) ) ) {
- if(i==10)
- i=0;
- continue;
- }
-
- ammo=cg.snap->ps.ammo[i];
-
- switch(i) {
- case WP_MACHINEGUN: max = 100; break;
- case WP_SHOTGUN: max = 10; break;
- case WP_GRENADE_LAUNCHER: max = 10; break;
- case WP_ROCKET_LAUNCHER: max = 10; break;
- case WP_LIGHTNING: max = 100; break;
- case WP_RAILGUN: max = 10; break;
- case WP_PLASMAGUN: max = 50; break;
- case WP_BFG: max = 10; break;
- case WP_NAILGUN: max = 10; break;
- case WP_PROX_LAUNCHER: max = 5; break;
- case WP_CHAINGUN: max = 100; break;
- default: max = 1; break;
- }
-
- ammo = (ammo*100)/max;
-
- if((ammo >=100) || (ammo < 0))
- ammo=100;
-
- boxColor[2]=(ammo/100.0f)*1.0f;
- boxColor[0]=1.0f-(ammo/100.0f)*1.0f;
-
- if ( i == cg.weaponSelect) {
- CG_FillRect( x, y , 30 , 38, boxColor );
- CG_DrawRect( x, y, 30 ,38 ,2, yellow);
- }
- else{
- CG_FillRect( x, y,30, 38, boxColor );
- }
-
- CG_DrawPic( x+7, y+2, 16, 16, cg_weapons[i].weaponIcon );
-
- if(cg.snap->ps.ammo[ i ]!=-1){
- s = va("%i", cg.snap->ps.ammo[ i ] );
- w = CG_DrawStrlen( s ) * SMALLCHAR_WIDTH;
- CG_DrawSmallStringColor(x - w/2 + 15, y+20, s, color);
- }
-
- x += 30;
- //Sago: Undo mad change of weapons
- if(i==10)
- i=0;
- }
-}
-
-
-/*
-===============
-CG_WeaponSelectable
-===============
-*/
-static qboolean CG_WeaponSelectable( int i ) {
- if ( !cg.snap->ps.ammo[i] ) {
- return qfalse;
- }
- if ( ! (cg.snap->ps.stats[ STAT_WEAPONS ] & ( 1 << i ) ) ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-===============
-CG_NextWeapon_f
-===============
-*/
-void CG_NextWeapon_f( void ) {
- int i;
- int original;
-
- if ( !cg.snap ) {
- return;
- }
- if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
- return;
- }
-
- cg.weaponSelectTime = cg.time;
- original = cg.weaponSelect;
- //Part of mad hook select code:
- if(cg.weaponSelect == WP_GRAPPLING_HOOK)
- cg.weaponSelect = 0;
-
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- cg.weaponSelect++;
- if ( cg.weaponSelect == MAX_WEAPONS ) {
- cg.weaponSelect = 0;
- }
- if ( cg.weaponSelect == WP_GAUNTLET ) {
- continue; // never cycle to gauntlet
- }
- //Sago: Mad change of grapple order
- if( cg.weaponSelect == WP_GRAPPLING_HOOK) {
- continue;
- }
- if( cg.weaponSelect == 0)
- cg.weaponSelect = WP_GRAPPLING_HOOK;
- if ( cg.weaponSelect == WP_GRAPPLING_HOOK && !cg_cyclegrapple.integer ) {
- cg.weaponSelect = 0;
- continue; // never cycle to grapple unless the client wants it
- }
- if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
- break;
- }
- if( cg.weaponSelect == WP_GRAPPLING_HOOK)
- cg.weaponSelect = 0;
- }
- if ( i == MAX_WEAPONS ) {
- cg.weaponSelect = original;
- }
-}
-
-/*
-===============
-CG_PrevWeapon_f
-===============
-*/
-void CG_PrevWeapon_f( void ) {
- int i;
- int original;
-
- if ( !cg.snap ) {
- return;
- }
- if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
- return;
- }
-
- cg.weaponSelectTime = cg.time;
- original = cg.weaponSelect;
- //Part of mad hook select code:
- if(cg.weaponSelect == WP_GRAPPLING_HOOK)
- cg.weaponSelect = 0;
-
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- cg.weaponSelect--;
- if ( cg.weaponSelect == -1 ) {
- cg.weaponSelect = MAX_WEAPONS - 1;
- }
- if ( cg.weaponSelect == WP_GAUNTLET ) {
- continue; // never cycle to gauntlet
- }
- //Sago: Mad change of grapple order
- if( cg.weaponSelect == WP_GRAPPLING_HOOK) {
- continue;
- }
- if( cg.weaponSelect == 0)
- cg.weaponSelect = WP_GRAPPLING_HOOK;
- if ( cg.weaponSelect == WP_GRAPPLING_HOOK && !cg_cyclegrapple.integer ) {
- cg.weaponSelect = 0;
- continue; // never cycle to grapple unless the client wants it
- }
- if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
- break;
- }
- if( cg.weaponSelect == WP_GRAPPLING_HOOK)
- cg.weaponSelect = 0;
- }
- if ( i == MAX_WEAPONS ) {
- cg.weaponSelect = original;
- }
-}
-
-/*
-===============
-CG_Weapon_f
-===============
-*/
-void CG_Weapon_f( void ) {
- int num;
-
- if ( !cg.snap ) {
- return;
- }
- if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
- return;
- }
-
- num = atoi( CG_Argv( 1 ) );
-
- if ( num < 1 || num > MAX_WEAPONS-1 ) {
- return;
- }
-
- cg.weaponSelectTime = cg.time;
-
- if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) ) {
- return; // don't have the weapon
- }
-
- cg.weaponSelect = num;
-}
-
-/*
-===================
-CG_OutOfAmmoChange
-
-The current weapon has just run out of ammo
-===================
-*/
-void CG_OutOfAmmoChange( void ) {
- int i;
-
- cg.weaponSelectTime = cg.time;
-
- for ( i = MAX_WEAPONS-1 ; i > 0 ; i-- ) {
- if ( CG_WeaponSelectable( i ) && i != WP_GRAPPLING_HOOK ) {
- cg.weaponSelect = i;
- break;
- }
- }
-}
-
-
-
-/*
-===================================================================================================
-
-WEAPON EVENTS
-
-===================================================================================================
-*/
-
-/*
-================
-CG_FireWeapon
-
-Caused by an EV_FIRE_WEAPON event
-================
-*/
-void CG_FireWeapon( centity_t *cent ) {
- entityState_t *ent;
- int c;
- weaponInfo_t *weap;
-
- if((cgs.gametype == GT_ELIMINATION || cgs.gametype == GT_CTF_ELIMINATION) && cgs.roundStartTime>=cg.time)
- return; //if we havn't started in ELIMINATION then do not fire
-
- ent = ¢->currentState;
- if ( ent->weapon == WP_NONE ) {
- return;
- }
- if ( ent->weapon >= WP_NUM_WEAPONS ) {
- CG_Error( "CG_FireWeapon: ent->weapon >= WP_NUM_WEAPONS" );
- return;
- }
- weap = &cg_weapons[ ent->weapon ];
-
- // mark the entity as muzzle flashing, so when it is added it will
- // append the flash to the weapon model
- cent->muzzleFlashTime = cg.time;
-
- // lightning gun only does this this on initial press
- if ( ent->weapon == WP_LIGHTNING ) {
- if ( cent->pe.lightningFiring ) {
- return;
- }
- }
-
- // play quad sound if needed
- if ( cent->currentState.powerups & ( 1 << PW_QUAD ) ) {
- trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.media.quadSound );
- }
-
- // play a sound
- for ( c = 0 ; c < 4 ; c++ ) {
- if ( !weap->flashSound[c] ) {
- break;
- }
- }
- if ( c > 0 ) {
- c = rand() % c;
- if ( weap->flashSound[c] )
- {
- trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound[c] );
- }
- }
-
- // do brass ejection
- if ( weap->ejectBrassFunc && cg_brassTime.integer > 0 ) {
- weap->ejectBrassFunc( cent );
- }
-
-//unlagged - attack prediction #1
- CG_PredictWeaponEffects( cent );
-//unlagged - attack prediction #1
-}
-
-
-/*
-==========================
-CG_Explosionia LEILEI
-==========================
-
-static void CG_Explosionia ( centity_t *cent ) {
- localEntity_t *le;
- ec3_t velocity, xvelocity;
- vec3_t offset, xoffset;
- float waterScale = 1.0f;
- vec3_t v[3];
-
- if ( cg_brassTime.integer <= 0 ) {
- return;
- }
-
- le = CG_AllocLocalEntity();
-
-
- velocity[0] = -50 + 100 * crandom();
- velocity[1] = -50 + 100 * crandom();
- velocity[2] = -50 + 100 * crandom();
-
- le->leType = LE_FALL_SCALE_FADE;
- le->startTime = cg.time;
- le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random();
-
- //le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time - (rand()&15);
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[0] = 8;
- offset[1] = -4;
- offset[2] = 24;
-
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( cent->lerpOrigin, xoffset, re->origin );
-
- VectorCopy( re->origin, le->pos.trBase );
-
- if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
- waterScale = 0.10f;
- }
-
- xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
- xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
- xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
-
- le->bounceFactor = 0.4 * waterScale;
-
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[0] = rand()&31;
- le->angles.trBase[1] = rand()&31;
- le->angles.trBase[2] = rand()&31;
- le->angles.trDelta[0] = 2;
- le->angles.trDelta[1] = 1;
- le->angles.trDelta[2] = 0;
- le = CG_SmokePuff( le->origin, le->velocity,
- 30, // radius
- 1, 1, 1, 1, // color
- 2000, // trailTime
- cg.time, // startTime
- 0, // fadeInTime
- 0, // flags
- cgs.media.lbumShader1 );
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_NONE;
- le->leMarkType = LEMT_NONE;
-}
-
-*/
-
-/*
-=================
-CG_MissileHitWall
-
-Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing
-=================
-*/
-void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType ) {
- qhandle_t mod;
- qhandle_t mark;
- qhandle_t shader;
- sfxHandle_t sfx;
- float radius;
- float light;
- vec3_t lightColor;
- localEntity_t *le;
- int r;
- qboolean alphaFade;
- qboolean isSprite;
- int duration;
- vec3_t sprOrg;
- vec3_t sprVel;
-
- mark = 0;
- radius = 32;
- sfx = 0;
- mod = 0;
- shader = 0;
- light = 0;
- lightColor[0] = 1;
- lightColor[1] = 1;
- lightColor[2] = 0;
-
- // set defaults
- isSprite = qfalse;
- duration = 600;
-
- switch ( weapon ) {
- default:
-//#ifdef MISSIONPACK
- case WP_NAILGUN:
- if( soundType == IMPACTSOUND_FLESH ) {
- sfx = cgs.media.sfx_nghitflesh;
- } else if( soundType == IMPACTSOUND_METAL ) {
- sfx = cgs.media.sfx_nghitmetal;
- } else {
- sfx = cgs.media.sfx_nghit;
- }
- mark = cgs.media.holeMarkShader;
- radius = 12;
- break;
-//#endif
- case WP_LIGHTNING:
- // no explosion at LG impact, it is added with the beam
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.sfx_lghit2;
- } else if ( r == 2 ) {
- sfx = cgs.media.sfx_lghit1;
- } else {
- sfx = cgs.media.sfx_lghit3;
- }
- mark = cgs.media.holeMarkShader;
- radius = 12;
- break;
-//#ifdef MISSIONPACK
- case WP_PROX_LAUNCHER:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.grenadeExplosionShader;
- sfx = cgs.media.sfx_proxexp;
- mark = cgs.media.burnMarkShader;
- radius = 64;
- light = 300;
- isSprite = qtrue;
- break;
-//#endif
- case WP_GRENADE_LAUNCHER:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.grenadeExplosionShader;
- sfx = cgs.media.sfx_rockexp;
- mark = cgs.media.burnMarkShader;
- radius = 64;
- light = 300;
- isSprite = qtrue;
- break;
- case WP_ROCKET_LAUNCHER:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.rocketExplosionShader;
- sfx = cgs.media.sfx_rockexp;
- mark = cgs.media.burnMarkShader;
- radius = 64;
- light = 300;
- isSprite = qtrue;
- duration = 1000;
- lightColor[0] = 1;
- lightColor[1] = 0.75;
- lightColor[2] = 0.0;
- if (!cg_oldRocket.integer) {
- // explosion sprite animation
- VectorMA( origin, 24, dir, sprOrg );
- VectorScale( dir, 64, sprVel );
-
- CG_ParticleExplosion( "explode1", sprOrg, sprVel, 1400, 20, 30 );
- }
- // LEILEI START enhancement
- if (cg_leiEnhancement.integer) {
- // some more fireball, fireball, fireball, fire fire!
- VectorMA( origin, 2, dir, sprOrg );
- VectorScale( dir, 0, sprVel );
- lightColor[0] = 0.7; // subtler explosion colors
- lightColor[1] = 0.6;
- lightColor[2] = 0.4;
- //CG_Explosionia(self);
- /*
- CG_LeiSparks(sprOrg, sprVel, 1400, 0, 0, 177);
- CG_LeiSparks(sprOrg, sprVel, 1400, 0, 0, 13);
- CG_LeiSparks(sprOrg, sprVel, 1400, 0, 0, 111);
- CG_LeiSparks(sprOrg, sprVel, 1400, 0, 0, 74);
- CG_LeiSparks(sprOrg, sprVel, 1400, 0, 0, 15);
- CG_LeiSparks(sprOrg, sprVel, 1400, 0, 0, 19);
- CG_LeiSparks(sprOrg, sprVel, 1400, 0, 0, 11);
- CG_LeiSparks(sprOrg, sprVel, 1400, 0, 0, 13);
- */
- }
- // LEILEI END enhancement
- break;
- case WP_RAILGUN:
- mod = cgs.media.ringFlashModel;
- shader = cgs.media.railExplosionShader;
- sfx = cgs.media.sfx_plasmaexp;
- mark = cgs.media.energyMarkShader;
- radius = 24;
- break;
- case WP_PLASMAGUN:
- mod = cgs.media.ringFlashModel;
- shader = cgs.media.plasmaExplosionShader;
- sfx = cgs.media.sfx_plasmaexp;
- mark = cgs.media.energyMarkShader;
- radius = 16;
- break;
- case WP_BFG:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.bfgExplosionShader;
- sfx = cgs.media.sfx_rockexp;
- mark = cgs.media.burnMarkShader;
- radius = 32;
- isSprite = qtrue;
- break;
- case WP_SHOTGUN:
- mod = cgs.media.bulletFlashModel;
- shader = cgs.media.bulletExplosionShader;
- mark = cgs.media.bulletMarkShader;
- sfx = 0;
- radius = 4;
- break;
-
-//#ifdef MISSIONPACK
- case WP_CHAINGUN:
- mod = cgs.media.bulletFlashModel;
- if( soundType == IMPACTSOUND_FLESH ) {
- sfx = cgs.media.sfx_chghitflesh;
- } else if( soundType == IMPACTSOUND_METAL ) {
- sfx = cgs.media.sfx_chghitmetal;
- } else {
- sfx = cgs.media.sfx_chghit;
- }
- mark = cgs.media.bulletMarkShader;
-
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.sfx_ric1;
- } else if ( r == 2 ) {
- sfx = cgs.media.sfx_ric2;
- } else {
- sfx = cgs.media.sfx_ric3;
- }
-
- radius = 8;
- break;
-//#endif
-
- case WP_MACHINEGUN:
- mod = cgs.media.bulletFlashModel;
- shader = cgs.media.bulletExplosionShader;
- mark = cgs.media.bulletMarkShader;
-
- r = rand() & 3;
- if ( r == 0 ) {
- sfx = cgs.media.sfx_ric1;
- } else if ( r == 1 ) {
- sfx = cgs.media.sfx_ric2;
- } else {
- sfx = cgs.media.sfx_ric3;
- }
-
- radius = 8;
- break;
- }
-
- if ( sfx ) {
- trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, sfx );
- }
-
- //
- // create the explosion
- //
- if ( mod ) {
- le = CG_MakeExplosion( origin, dir,
- mod, shader,
- duration, isSprite );
- le->light = light;
- VectorCopy( lightColor, le->lightColor );
- if ( weapon == WP_RAILGUN ) {
- // colorize with client color
- VectorCopy( cgs.clientinfo[clientNum].color1, le->color );
- }
- }
-
- //
- // impact mark
- //
- alphaFade = (mark == cgs.media.energyMarkShader); // plasma fades alpha, all others fade color
- if ( weapon == WP_RAILGUN ) {
- float *color;
-
- // colorize with client color
- color = cgs.clientinfo[clientNum].color1;
- CG_ImpactMark( mark, origin, dir, random()*360, color[0],color[1], color[2],1, alphaFade, radius, qfalse );
- } else {
- CG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse );
- }
-}
-
-
-/*
-=================
-CG_MissileHitPlayer
-=================
-*/
-void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum ) {
-// LEILEI ENHANCEMENT
- if (cg_leiEnhancement.integer) {
- CG_SmokePuff( origin, dir, 22, 1, 1, 1, 1.0f, 900, cg.time, 0, 0, cgs.media.lbldShader1 );
- CG_SpurtBlood( origin, dir, 1);
- CG_SpurtBlood( origin, dir, 4);
- CG_SpurtBlood( origin, dir, -12);
- }
-
- else
- CG_Bleed( origin, entityNum );
-
- // some weapons will make an explosion with the blood, while
- // others will just make the blood
- switch ( weapon ) {
- case WP_GRENADE_LAUNCHER:
- case WP_ROCKET_LAUNCHER:
-//#ifdef MISSIONPACK
- case WP_NAILGUN:
- case WP_CHAINGUN:
- case WP_PROX_LAUNCHER:
-//#endif
- CG_MissileHitWall( weapon, 0, origin, dir, IMPACTSOUND_FLESH );
- break;
- default:
- break;
- }
-}
-
-
-
-/*
-============================================================================
-
-SHOTGUN TRACING
-
-============================================================================
-*/
-
-/*
-================
-CG_ShotgunPellet
-================
-*/
-static void CG_ShotgunPellet( vec3_t start, vec3_t end, int skipNum ) {
- trace_t tr;
- int sourceContentType, destContentType;
-
-// LEILEI ENHACNEMENT
- localEntity_t *smoke;
- vec3_t kapew;
- vec3_t kapow;
- int therando;
-
-
-
- CG_Trace( &tr, start, NULL, NULL, end, skipNum, MASK_SHOT );
-
- sourceContentType = trap_CM_PointContents( start, 0 );
- destContentType = trap_CM_PointContents( tr.endpos, 0 );
-
- // FIXME: should probably move this cruft into CG_BubbleTrail
- if ( sourceContentType == destContentType ) {
- if ( sourceContentType & CONTENTS_WATER ) {
- CG_BubbleTrail( start, tr.endpos, 32 );
- }
- } else if ( sourceContentType & CONTENTS_WATER ) {
- trace_t trace;
-
- trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( start, trace.endpos, 32 );
-
-// LEILEI ENHANCEMENT
- if (cg_leiEnhancement.integer) {
- // Water Splash
- VectorCopy( trace.plane.normal, kapow );
-
- kapow[0] = kapow[0] * (crandom() * 22);
- kapow[1] = kapow[1] * (crandom() * 22);
- kapow[2] = kapow[2] * (crandom() * 65 + 37);
- smoke = CG_SmokePuff( trace.endpos, kapow, 14, 1, 1, 1, 1.0f, 400, cg.time, 0, 0, cgs.media.lsplShader );
- smoke = CG_SmokePuff( trace.endpos, kapow, 6, 1, 1, 1, 1.0f, 200, cg.time, 0, 0, cgs.media.lsplShader );
- smoke = CG_SmokePuff( trace.endpos, kapow, 10, 1, 1, 1, 1.0f, 300, cg.time, 0, 0, cgs.media.lsplShader );
- }
-// END LEIHANCMENET
- } else if ( destContentType & CONTENTS_WATER ) {
- trace_t trace;
-
- trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( tr.endpos, trace.endpos, 32 );
-
-// LEILEI ENHANCEMENT
- if (cg_leiEnhancement.integer) {
- // Water Splash
- VectorCopy( trace.plane.normal, kapow );
-
- kapow[0] = kapow[0] * (crandom() * 22);
- kapow[1] = kapow[1] * (crandom() * 22);
- kapow[2] = kapow[2] * (crandom() * 65 + 37);
- smoke = CG_SmokePuff( trace.endpos, kapow, 14, 1, 1, 1, 1.0f, 400, cg.time, 0, 0, cgs.media.lsplShader );
- smoke = CG_SmokePuff( trace.endpos, kapow, 6, 1, 1, 1, 1.0f, 200, cg.time, 0, 0, cgs.media.lsplShader );
- smoke = CG_SmokePuff( trace.endpos, kapow, 10, 1, 1, 1, 1.0f, 300, cg.time, 0, 0, cgs.media.lsplShader );
- }
-// END LEIHANCMENET
- }
-
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- return;
- }
-
- if ( cg_entities[tr.entityNum].currentState.eType == ET_PLAYER ) {
- CG_MissileHitPlayer( WP_SHOTGUN, tr.endpos, tr.plane.normal, tr.entityNum );
- } else {
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- // SURF_NOIMPACT will not make a flame puff or a mark
- return;
- }
- if ( tr.surfaceFlags & SURF_METALSTEPS ) {
- CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL );
-// LEILEI ENHANCEMENT
- if (cg_leiEnhancement.integer) {
- VectorCopy( tr.plane.normal, kapow );
-
- kapow[0] = kapow[0] * (crandom() * 65 + 37);
- kapow[1] = kapow[1] * (crandom() * 65 + 37);
- kapow[2] = kapow[2] * (crandom() * 65 + 37);
- CG_LeiSparks(tr.endpos, tr.plane.normal, 800, 0, 0, 7);
- CG_LeiSparks(tr.endpos, tr.plane.normal, 800, 0, 0, 3);
- CG_LeiSparks(tr.endpos, tr.plane.normal, 800, 0, 0, 1);
-
- }
-// END LEIHANCMENET
- } else {
- CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT );
-
-// LEILEI ENHANCEMENT
- if (cg_leiEnhancement.integer) {
- VectorCopy( tr.plane.normal, kapow );
-
- kapow[0] = kapow[0] * (crandom() * 65 + 37);
- kapow[1] = kapow[1] * (crandom() * 65 + 37);
- kapow[2] = kapow[2] * (crandom() * 65 + 37);
- CG_LeiSparks(tr.endpos, tr.plane.normal, 800, 0, 0, 7);
- CG_LeiSparks(tr.endpos, tr.plane.normal, 800, 0, 0, 2);
-
- smoke = CG_SmokePuff( tr.endpos, kapow, 21, 1, 1, 1, 0.9f, 1200, cg.time, 0, 0, cgs.media.lsmkShader2 );
- //smoke = CG_SmokePuff( tr.endpos, kapow, 21, 1, 1, 1, 0.9f, 1200, cg.time, 0, 0, cgs.media.lbumShader1 );
- }
-// END LEIHANCMENET
- }
- }
-}
-
-/*
-================
-CG_ShotgunPattern
-
-Perform the same traces the server did to locate the
-hit splashes
-================
-*/
-//unlagged - attack prediction
-// made this non-static for access from cg_unlagged.c
-void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) {
- int i;
- float r, u;
- vec3_t end;
- vec3_t forward, right, up;
-
- // derive the right and up vectors from the forward vector, because
- // the client won't have any other information
- VectorNormalize2( origin2, forward );
- PerpendicularVector( right, forward );
- CrossProduct( forward, right, up );
-
- // generate the "random" spread pattern
- for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {
- r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
- u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
- VectorMA( origin, 8192 * 16, forward, end);
- VectorMA (end, r, right, end);
- VectorMA (end, u, up, end);
-
- CG_ShotgunPellet( origin, end, otherEntNum );
- }
-}
-
-/*
-==============
-CG_ShotgunFire
-==============
-*/
-void CG_ShotgunFire( entityState_t *es ) {
- vec3_t v;
- int contents;
-
- VectorSubtract( es->origin2, es->pos.trBase, v );
- VectorNormalize( v );
- VectorScale( v, 32, v );
- VectorAdd( es->pos.trBase, v, v );
- if ( cgs.glconfig.hardwareType != GLHW_RAGEPRO ) {
- // ragepro can't alpha fade, so don't even bother with smoke
- vec3_t up;
-
- contents = trap_CM_PointContents( es->pos.trBase, 0 );
- if ( !( contents & CONTENTS_WATER ) ) {
- VectorSet( up, 0, 0, 8 );
-// LEILEI ENHANCEMENT
- if (cg_leiEnhancement.integer) {
- // Shotgun puffy
- VectorSet( up, 4, 4, 4 );
- up[0] = up[0] * (crandom() * 22 + 44); up[1] = up[1] * (crandom() * 22 + 44); up[2] = up[2] * (crandom() * 22 + 44);
- CG_SmokePuff( v, up, 14, 1, 1, 1, 0.4f, 900, cg.time, 0, 0, cgs.media.lsmkShader1 );
- up[0] = up[0] * (crandom() * 22 + 44); up[1] = up[1] * (crandom() * 22 + 44); up[2] = up[2] * (crandom() * 22 + 44);
- CG_SmokePuff( v, up, 14, 1, 1, 1, 0.4f, 900, cg.time, 0, 0, cgs.media.lsmkShader2 );
- up[0] = up[0] * (crandom() * 22 + 44); up[1] = up[1] * (crandom() * 22 + 44); up[2] = up[2] * (crandom() * 22 + 44);
- CG_SmokePuff( v, up, 14, 1, 1, 1, 0.4f, 900, cg.time, 0, 0, cgs.media.lsmkShader3 );
- up[0] = up[0] * (crandom() * 22 + 44); up[1] = up[1] * (crandom() * 22 + 44); up[2] = up[2] * (crandom() * 22 + 44);
- CG_SmokePuff( v, up, 14, 1, 1, 1, 0.4f, 900, cg.time, 0, 0, cgs.media.lsmkShader4 );
- }
- else
-
-// END LEIHANCMENET
-
-CG_SmokePuff( v, up, 32, 1, 1, 1, 0.33f, 900, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
-
- }
- }
- CG_ShotgunPattern( es->pos.trBase, es->origin2, es->eventParm, es->otherEntityNum );
-}
-
-/*
-============================================================================
-
-BULLETS
-
-============================================================================
-*/
-
-
-/*
-===============
-CG_Tracer
-===============
-*/
-void CG_Tracer( vec3_t source, vec3_t dest ) {
- vec3_t forward, right;
- polyVert_t verts[4];
- vec3_t line;
- float len, begin, end;
- vec3_t start, finish;
- vec3_t midpoint;
-
- // tracer
- VectorSubtract( dest, source, forward );
- len = VectorNormalize( forward );
-
- // start at least a little ways from the muzzle
- if ( len < 100 ) {
- return;
- }
- begin = 50 + random() * (len - 60);
- end = begin + cg_tracerLength.value;
- if ( end > len ) {
- end = len;
- }
- VectorMA( source, begin, forward, start );
- VectorMA( source, end, forward, finish );
-
- line[0] = DotProduct( forward, cg.refdef.viewaxis[1] );
- line[1] = DotProduct( forward, cg.refdef.viewaxis[2] );
-
- VectorScale( cg.refdef.viewaxis[1], line[1], right );
- VectorMA( right, -line[0], cg.refdef.viewaxis[2], right );
- VectorNormalize( right );
-
- VectorMA( finish, cg_tracerWidth.value, right, verts[0].xyz );
- verts[0].st[0] = 0;
- verts[0].st[1] = 1;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- VectorMA( finish, -cg_tracerWidth.value, right, verts[1].xyz );
- verts[1].st[0] = 1;
- verts[1].st[1] = 0;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- VectorMA( start, -cg_tracerWidth.value, right, verts[2].xyz );
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- VectorMA( start, cg_tracerWidth.value, right, verts[3].xyz );
- verts[3].st[0] = 0;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
-
- trap_R_AddPolyToScene( cgs.media.tracerShader, 4, verts );
-
- midpoint[0] = ( start[0] + finish[0] ) * 0.5;
- midpoint[1] = ( start[1] + finish[1] ) * 0.5;
- midpoint[2] = ( start[2] + finish[2] ) * 0.5;
-
- // add the tracer sound
- trap_S_StartSound( midpoint, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.tracerSound );
-
-}
-
-
-/*
-======================
-CG_CalcMuzzlePoint
-======================
-*/
-static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) {
- vec3_t forward;
- centity_t *cent;
- int anim;
-
- if ( entityNum == cg.snap->ps.clientNum ) {
- VectorCopy( cg.snap->ps.origin, muzzle );
- muzzle[2] += cg.snap->ps.viewheight;
- AngleVectors( cg.snap->ps.viewangles, forward, NULL, NULL );
- VectorMA( muzzle, 14, forward, muzzle );
- return qtrue;
- }
-
- cent = &cg_entities[entityNum];
- if ( !cent->currentValid ) {
- return qfalse;
- }
-
- VectorCopy( cent->currentState.pos.trBase, muzzle );
-
- AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL );
- anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
- if ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) {
- muzzle[2] += CROUCH_VIEWHEIGHT;
- } else {
- muzzle[2] += DEFAULT_VIEWHEIGHT;
- }
-
- VectorMA( muzzle, 14, forward, muzzle );
-
- return qtrue;
-
-}
-
-/*
-======================
-CG_Bullet
-
-Renders bullet effects.
-======================
-*/
-void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ) {
- trace_t trace;
- int sourceContentType, destContentType;
- vec3_t start;
-// LEILEI ENHACNEMENT
- localEntity_t *smoke;
- localEntity_t *spark;
- vec3_t kapew;
- vec3_t kapow;
- int therando;
-
-
-
-
- // if the shooter is currently valid, calc a source point and possibly
- // do trail effects
- if ( sourceEntityNum >= 0 && cg_tracerChance.value > 0 ) {
- if ( CG_CalcMuzzlePoint( sourceEntityNum, start ) ) {
- sourceContentType = trap_CM_PointContents( start, 0 );
- destContentType = trap_CM_PointContents( end, 0 );
-
- // do a complete bubble trail if necessary
- if ( ( sourceContentType == destContentType ) && ( sourceContentType & CONTENTS_WATER ) ) {
- CG_BubbleTrail( start, end, 32 );
- }
- // bubble trail from water into air
- else if ( ( sourceContentType & CONTENTS_WATER ) ) {
- trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( start, trace.endpos, 32 );
-
-
-// LEILEI ENHANCEMENT
- if (cg_leiEnhancement.integer) {
- // Water Splash
- VectorCopy( trace.plane.normal, kapow );
- kapow[0] = kapow[0] * (crandom() * 22);
- kapow[1] = kapow[1] * (crandom() * 22);
- kapow[2] = kapow[2] * (crandom() * 65 + 37);
- smoke = CG_SmokePuff( trace.endpos, kapow, 14, 1, 1, 1, 1.0f, 400, cg.time, 0, 0, cgs.media.lsplShader );
- smoke = CG_SmokePuff( trace.endpos, kapow, 6, 1, 1, 1, 1.0f, 200, cg.time, 0, 0, cgs.media.lsplShader );
- smoke = CG_SmokePuff( trace.endpos, kapow, 10, 1, 1, 1, 1.0f, 300, cg.time, 0, 0, cgs.media.lsplShader );
- // CG_LeiSplash2(trace.endpos, kapow, 900, 0, 0, 444);
-
- }
-// END LEIHANCMENET
-
-
- }
- // bubble trail from air into water
- else if ( ( destContentType & CONTENTS_WATER ) ) {
- trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( trace.endpos, end, 32 );
-
-// LEILEI ENHANCEMENT
- if (cg_leiEnhancement.integer) {
- // Water Splash
- VectorCopy( trace.plane.normal, kapow );
-
- kapow[0] = kapow[0] * (crandom() * 22);
- kapow[1] = kapow[1] * (crandom() * 22);
- kapow[2] = kapow[2] * (crandom() * 65 + 37);
- smoke = CG_SmokePuff( trace.endpos, kapow, 14, 1, 1, 1, 1.0f, 400, cg.time, 0, 0, cgs.media.lsplShader );
- smoke = CG_SmokePuff( trace.endpos, kapow, 6, 1, 1, 1, 1.0f, 200, cg.time, 0, 0, cgs.media.lsplShader );
- smoke = CG_SmokePuff( trace.endpos, kapow, 10, 1, 1, 1, 1.0f, 300, cg.time, 0, 0, cgs.media.lsplShader );
- //CG_LeiSplash2(trace.endpos, kapow, 500, 0, 0, 1);
- }
-// END LEIHANCMENET
- }
-
- // draw a tracer
- if ( random() < cg_tracerChance.value ) {
- CG_Tracer( start, end );
- }
- }
- }
-
- // impact splash and mark
- if ( flesh ) {
-// LEILEI ENHANCEMENT
- if (cg_leiEnhancement.integer) {
-
-
- // Blood Hack
- VectorCopy( normal, kapow );
-
- kapow[0] = kapow[0] * (crandom() * 65 + 37);
- kapow[1] = kapow[1] * (crandom() * 65 + 37);
- kapow[2] = kapow[2] * (crandom() * 65 + 37);
- VectorCopy( kapow, kapew );
-
- kapew[0] = kapew[0] * (crandom() * 2 + 37);
- kapew[1] = kapew[1] * (crandom() * 2 + 37);
- kapew[2] = kapew[2] * (crandom() * 2 + 37);
-
- CG_SmokePuff( end, kapow, 6, 1, 1, 1, 1.0f, 600, cg.time, 0, 0, cgs.media.lbldShader1 );
- CG_SpurtBlood( end, kapow, 2);
- CG_SpurtBlood( end, kapew, 1);
-if (cg_leiSuperGoreyAwesome.integer) {
- CG_SpurtBlood( end, kapow, -2);
- }
- }
-
- else
- CG_Bleed( end, fleshEntityNum );
- } else {
- CG_MissileHitWall( WP_MACHINEGUN, 0, end, normal, IMPACTSOUND_DEFAULT );
-
-// LEILEI ENHANCEMENT
- if (cg_leiEnhancement.integer) {
-
- // Smoke puff
- VectorCopy( normal, kapow );
-
- kapow[0] = kapow[0] * (crandom() * 65 + 37);
- kapow[1] = kapow[1] * (crandom() * 65 + 37);
- kapow[2] = kapow[2] * (crandom() * 65 + 37);
- VectorCopy( kapow, kapew );
-
- kapew[0] = kapew[0] * (crandom() * 65 + 37);
- kapew[1] = kapew[1] * (crandom() * 65 + 37);
- kapew[2] = kapew[2] * (crandom() * 65 + 37);
-
-
- smoke = CG_SmokePuff( end, kapow, 14, 1, 1, 1, 1.0f, 600, cg.time, 0, 0, cgs.media.lsmkShader1 );
- // CG_LeiSparks(end, normal, 600, 0, 0, 177);
- // CG_LeiSparks(end, normal, 600, 0, 0, 155);
- CG_LeiSparks(end, normal, 600, 0, 0, 444);
-
- }
-// END LEIHANCMENET
- }
-
-}
diff --git a/game/code/game/ai_chat.c b/game/code/game/ai_chat.c
deleted file mode 100644
index 87c4726..0000000
--- a/game/code/game/ai_chat.c
+++ /dev/null
@@ -1,1217 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_chat.c
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /MissionPack/code/game/ai_chat.c $
- *
- *****************************************************************************/
-
-#include "g_local.h"
-#include "../botlib/botlib.h"
-#include "../botlib/be_aas.h"
-#include "../botlib/be_ea.h"
-#include "../botlib/be_ai_char.h"
-#include "../botlib/be_ai_chat.h"
-#include "../botlib/be_ai_gen.h"
-#include "../botlib/be_ai_goal.h"
-#include "../botlib/be_ai_move.h"
-#include "../botlib/be_ai_weap.h"
-//
-#include "ai_main.h"
-#include "ai_dmq3.h"
-#include "ai_chat.h"
-#include "ai_cmd.h"
-#include "ai_dmnet.h"
-//
-#include "chars.h" //characteristics
-#include "inv.h" //indexes into the inventory
-#include "syn.h" //synonyms
-#include "match.h" //string matching types and vars
-
-// for the voice chats
-#ifdef MISSIONPACK // bk001205
-#include "../../ui/menudef.h"
-#endif
-
-#define TIME_BETWEENCHATTING 25
-
-
-/*
-==================
-BotNumActivePlayers
-==================
-*/
-int BotNumActivePlayers(void) {
- int i, num;
- char buf[MAX_INFO_STRING];
- static int maxclients;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- num = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- num++;
- }
- return num;
-}
-
-/*
-==================
-BotIsFirstInRankings
-==================
-*/
-int BotIsFirstInRankings(bot_state_t *bs) {
- int i, score;
- char buf[MAX_INFO_STRING];
- static int maxclients;
- playerState_t ps;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- score = bs->cur_ps.persistant[PERS_SCORE];
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- BotAI_GetClientState(i, &ps);
- if (score < ps.persistant[PERS_SCORE]) return qfalse;
- }
- return qtrue;
-}
-
-/*
-==================
-BotIsLastInRankings
-==================
-*/
-int BotIsLastInRankings(bot_state_t *bs) {
- int i, score;
- char buf[MAX_INFO_STRING];
- static int maxclients;
- playerState_t ps;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- score = bs->cur_ps.persistant[PERS_SCORE];
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- BotAI_GetClientState(i, &ps);
- if (score > ps.persistant[PERS_SCORE]) return qfalse;
- }
- return qtrue;
-}
-
-/*
-==================
-BotFirstClientInRankings
-==================
-*/
-char *BotFirstClientInRankings(void) {
- int i, bestscore, bestclient;
- char buf[MAX_INFO_STRING];
- static char name[32];
- static int maxclients;
- playerState_t ps;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- bestscore = -999999;
- bestclient = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- BotAI_GetClientState(i, &ps);
- if (ps.persistant[PERS_SCORE] > bestscore) {
- bestscore = ps.persistant[PERS_SCORE];
- bestclient = i;
- }
- }
- EasyClientName(bestclient, name, 32);
- return name;
-}
-
-/*
-==================
-BotLastClientInRankings
-==================
-*/
-char *BotLastClientInRankings(void) {
- int i, worstscore, bestclient;
- char buf[MAX_INFO_STRING];
- static char name[32];
- static int maxclients;
- playerState_t ps;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- worstscore = 999999;
- bestclient = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- BotAI_GetClientState(i, &ps);
- if (ps.persistant[PERS_SCORE] < worstscore) {
- worstscore = ps.persistant[PERS_SCORE];
- bestclient = i;
- }
- }
- EasyClientName(bestclient, name, 32);
- return name;
-}
-
-/*
-==================
-BotRandomOpponentName
-==================
-*/
-char *BotRandomOpponentName(bot_state_t *bs) {
- int i, count;
- char buf[MAX_INFO_STRING];
- int opponents[MAX_CLIENTS], numopponents;
- static int maxclients;
- static char name[32];
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- numopponents = 0;
- opponents[0] = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client) continue;
- //
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //skip team mates
- if (BotSameTeam(bs, i)) continue;
- //
- opponents[numopponents] = i;
- numopponents++;
- }
- count = random() * numopponents;
- for (i = 0; i < numopponents; i++) {
- count--;
- if (count <= 0) {
- EasyClientName(opponents[i], name, sizeof(name));
- return name;
- }
- }
- EasyClientName(opponents[0], name, sizeof(name));
- return name;
-}
-
-/*
-==================
-BotMapTitle
-==================
-*/
-
-char *BotMapTitle(void) {
- char info[1024];
- static char mapname[128];
-
- trap_GetServerinfo(info, sizeof(info));
-
- strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1);
- mapname[sizeof(mapname)-1] = '\0';
-
- return mapname;
-}
-
-
-/*
-==================
-BotWeaponNameForMeansOfDeath
-==================
-*/
-
-char *BotWeaponNameForMeansOfDeath(int mod) {
- switch(mod) {
- case MOD_SHOTGUN: return "Shotgun";
- case MOD_GAUNTLET: return "Gauntlet";
- case MOD_MACHINEGUN: return "Machinegun";
- case MOD_GRENADE:
- case MOD_GRENADE_SPLASH: return "Grenade Launcher";
- case MOD_ROCKET:
- case MOD_ROCKET_SPLASH: return "Rocket Launcher";
- case MOD_PLASMA:
- case MOD_PLASMA_SPLASH: return "Plasmagun";
- case MOD_RAILGUN: return "Railgun";
- case MOD_LIGHTNING: return "Lightning Gun";
- case MOD_BFG:
- case MOD_BFG_SPLASH: return "BFG10K";
- case MOD_NAIL: return "Nailgun";
- case MOD_CHAINGUN: return "Chaingun";
- case MOD_PROXIMITY_MINE: return "Proximity Launcher";
- case MOD_KAMIKAZE: return "Kamikaze";
- case MOD_JUICED: return "Prox mine";
- case MOD_GRAPPLE: return "Grapple";
- default: return "[unknown weapon]";
- }
-}
-
-/*
-==================
-BotRandomWeaponName
-==================
-*/
-char *BotRandomWeaponName(void) {
- int rnd;
-
- rnd = random() * 11.9;
- switch(rnd) {
- case 0: return "Gauntlet";
- case 1: return "Shotgun";
- case 2: return "Machinegun";
- case 3: return "Grenade Launcher";
- case 4: return "Rocket Launcher";
- case 5: return "Plasmagun";
- case 6: return "Railgun";
- case 7: return "Lightning Gun";
- case 8: return "Nailgun";
- case 9: return "Chaingun";
- case 10: return "Proximity Launcher";
- default: return "BFG10K";
- }
-}
-
-/*
-==================
-BotVisibleEnemies
-==================
-*/
-int BotVisibleEnemies(bot_state_t *bs) {
- float vis;
- int i;
- aas_entityinfo_t entinfo;
-
- for (i = 0; i < MAX_CLIENTS; i++) {
-
- if (i == bs->client) continue;
- //
- BotEntityInfo(i, &entinfo);
- //
- if (!entinfo.valid) continue;
- //if the enemy isn't dead and the enemy isn't the bot self
- if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;
- //if the enemy is invisible and not shooting
- if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
- continue;
- }
- //if on the same team
- if (BotSameTeam(bs, i)) continue;
- //check if the enemy is visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
- if (vis > 0) return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-BotValidChatPosition
-==================
-*/
-int BotValidChatPosition(bot_state_t *bs) {
- vec3_t point, start, end, mins, maxs;
- bsp_trace_t trace;
-
- //if the bot is dead all positions are valid
- if (BotIsDead(bs)) return qtrue;
- if (BotIsObserver(bs)) return qtrue;
- //never start chatting with a powerup
- if (bs->inventory[INVENTORY_QUAD] ||
- bs->inventory[INVENTORY_HASTE] ||
- bs->inventory[INVENTORY_INVISIBILITY] ||
- bs->inventory[INVENTORY_REGEN] ||
- bs->inventory[INVENTORY_FLIGHT]) return qfalse;
- //must be on the ground
- //if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) return qfalse;
- //do not chat if in lava or slime
- VectorCopy(bs->origin, point);
- point[2] -= 24;
- if (trap_PointContents(point,bs->entitynum) & (CONTENTS_LAVA|CONTENTS_SLIME)) return qfalse;
- //do not chat if under water
- VectorCopy(bs->origin, point);
- point[2] += 32;
- if (trap_PointContents(point,bs->entitynum) & MASK_WATER) return qfalse;
- //must be standing on the world entity
- VectorCopy(bs->origin, start);
- VectorCopy(bs->origin, end);
- start[2] += 1;
- end[2] -= 10;
- trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs);
- BotAI_Trace(&trace, start, mins, maxs, end, bs->client, MASK_SOLID);
- if (trace.ent != ENTITYNUM_WORLD) return qfalse;
- //the bot is in a position where it can chat
- return qtrue;
-}
-
-/*
-==================
-BotChat_EnterGame
-==================
-*/
-int BotChat_EnterGame(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- //don't chat in teamplay
- if (TeamPlayIsOn()) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (BotNumActivePlayers() <= 1) return qfalse;
- if (!BotValidChatPosition(bs)) return qfalse;
- BotAI_BotInitialChat(bs, "game_enter",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_ExitGame
-==================
-*/
-int BotChat_ExitGame(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- //don't chat in teamplay
- if (TeamPlayIsOn()) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (BotNumActivePlayers() <= 1) return qfalse;
- //
- BotAI_BotInitialChat(bs, "game_exit",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_StartLevel
-==================
-*/
-int BotChat_StartLevel(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (BotIsObserver(bs)) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- //don't chat in teamplay
- if (TeamPlayIsOn()) {
- trap_EA_Command(bs->client, "vtaunt");
- return qfalse;
- }
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (BotNumActivePlayers() <= 1) return qfalse;
- BotAI_BotInitialChat(bs, "level_start",
- EasyClientName(bs->client, name, 32), // 0
- NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_EndLevel
-==================
-*/
-int BotChat_EndLevel(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (BotIsObserver(bs)) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- // teamplay
- if (TeamPlayIsOn())
- {
- if (BotIsFirstInRankings(bs)) {
- trap_EA_Command(bs->client, "vtaunt");
- }
- return qtrue;
- }
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (BotNumActivePlayers() <= 1) return qfalse;
- //
- if (BotIsFirstInRankings(bs)) {
- BotAI_BotInitialChat(bs, "level_end_victory",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- "[invalid var]", // 2
- BotLastClientInRankings(), // 3
- BotMapTitle(), // 4
- NULL);
- }
- else if (BotIsLastInRankings(bs)) {
- BotAI_BotInitialChat(bs, "level_end_lose",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- BotFirstClientInRankings(), // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- NULL);
- }
- else {
- BotAI_BotInitialChat(bs, "level_end",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- BotFirstClientInRankings(), // 2
- BotLastClientInRankings(), // 3
- BotMapTitle(), // 4
- NULL);
- }
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_Death
-==================
-*/
-int BotChat_Death(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_DEATH, 0, 1);
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //if fast chatting is off
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (BotNumActivePlayers() <= 1) return qfalse;
- //
- if (bs->lastkilledby >= 0 && bs->lastkilledby < MAX_CLIENTS)
- EasyClientName(bs->lastkilledby, name, 32);
- else
- strcpy(name, "[world]");
- //
- if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledby)) {
- if (bs->lastkilledby == bs->client) return qfalse;
- BotAI_BotInitialChat(bs, "death_teammate", name, NULL);
- bs->chatto = CHAT_TEAM;
- }
- else
- {
- //teamplay
- if (TeamPlayIsOn()) {
- trap_EA_Command(bs->client, "vtaunt");
- return qtrue;
- }
- //
- if (bs->botdeathtype == MOD_WATER)
- BotAI_BotInitialChat(bs, "death_drown", BotRandomOpponentName(bs), NULL);
- else if (bs->botdeathtype == MOD_SLIME)
- BotAI_BotInitialChat(bs, "death_slime", BotRandomOpponentName(bs), NULL);
- else if (bs->botdeathtype == MOD_LAVA)
- BotAI_BotInitialChat(bs, "death_lava", BotRandomOpponentName(bs), NULL);
- else if (bs->botdeathtype == MOD_FALLING)
- BotAI_BotInitialChat(bs, "death_cratered", BotRandomOpponentName(bs), NULL);
- else if (bs->botsuicide || //all other suicides by own weapon
- bs->botdeathtype == MOD_CRUSH ||
- bs->botdeathtype == MOD_SUICIDE ||
- bs->botdeathtype == MOD_TARGET_LASER ||
- bs->botdeathtype == MOD_TRIGGER_HURT ||
- bs->botdeathtype == MOD_UNKNOWN)
- BotAI_BotInitialChat(bs, "death_suicide", BotRandomOpponentName(bs), NULL);
- else if (bs->botdeathtype == MOD_TELEFRAG)
- BotAI_BotInitialChat(bs, "death_telefrag", name, NULL);
- else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "death_kamikaze"))
- BotAI_BotInitialChat(bs, "death_kamikaze", name, NULL);
- else {
- if ((bs->botdeathtype == MOD_GAUNTLET ||
- bs->botdeathtype == MOD_RAILGUN ||
- bs->botdeathtype == MOD_BFG ||
- bs->botdeathtype == MOD_BFG_SPLASH) && random() < 0.5) {
-
- if (bs->botdeathtype == MOD_GAUNTLET)
- BotAI_BotInitialChat(bs, "death_gauntlet",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- else if (bs->botdeathtype == MOD_RAILGUN)
- BotAI_BotInitialChat(bs, "death_rail",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- else
- BotAI_BotInitialChat(bs, "death_bfg",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- }
- //choose between insult and praise
- else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {
- BotAI_BotInitialChat(bs, "death_insult",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- }
- else {
- BotAI_BotInitialChat(bs, "death_praise",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- }
- }
- bs->chatto = CHAT_ALL;
- }
- bs->lastchat_time = FloatTime();
- return qtrue;
-}
-
-/*
-==================
-BotChat_Kill
-==================
-*/
-int BotChat_Kill(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1);
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //if fast chat is off
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (bs->lastkilledplayer == bs->client) return qfalse;
- if (BotNumActivePlayers() <= 1) return qfalse;
- if (!BotValidChatPosition(bs)) return qfalse;
- //
- if (BotVisibleEnemies(bs)) return qfalse;
- //
- EasyClientName(bs->lastkilledplayer, name, 32);
- //
- bs->chatto = CHAT_ALL;
- if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledplayer)) {
- BotAI_BotInitialChat(bs, "kill_teammate", name, NULL);
- bs->chatto = CHAT_TEAM;
- }
- else
- {
- //don't chat in teamplay
- if (TeamPlayIsOn()) {
- trap_EA_Command(bs->client, "vtaunt");
- return qfalse; // don't wait
- }
- //
- if (bs->enemydeathtype == MOD_GAUNTLET) {
- BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL);
- }
- else if (bs->enemydeathtype == MOD_RAILGUN) {
- BotAI_BotInitialChat(bs, "kill_rail", name, NULL);
- }
- else if (bs->enemydeathtype == MOD_TELEFRAG) {
- BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL);
- }
- else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "kill_kamikaze"))
- BotAI_BotInitialChat(bs, "kill_kamikaze", name, NULL);
- //choose between insult and praise
- else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {
- BotAI_BotInitialChat(bs, "kill_insult", name, NULL);
- }
- else {
- BotAI_BotInitialChat(bs, "kill_praise", name, NULL);
- }
- }
- bs->lastchat_time = FloatTime();
- return qtrue;
-}
-
-/*
-==================
-BotChat_EnemySuicide
-==================
-*/
-int BotChat_EnemySuicide(bot_state_t *bs) {
- char name[32];
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- if (BotNumActivePlayers() <= 1) return qfalse;
- //
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1);
- //don't chat in teamplay
- if (TeamPlayIsOn()) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //if fast chat is off
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- }
- if (!BotValidChatPosition(bs)) return qfalse;
- //
- if (BotVisibleEnemies(bs)) return qfalse;
- //
- if (bs->enemy >= 0) EasyClientName(bs->enemy, name, 32);
- else strcpy(name, "");
- BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_HitTalking
-==================
-*/
-int BotChat_HitTalking(bot_state_t *bs) {
- char name[32], *weap;
- int lasthurt_client;
- float rnd;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- if (BotNumActivePlayers() <= 1) return qfalse;
- lasthurt_client = g_entities[bs->client].client->lasthurt_client;
- if (!lasthurt_client) return qfalse;
- if (lasthurt_client == bs->client) return qfalse;
- //
- if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;
- //
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITTALKING, 0, 1);
- //don't chat in teamplay
- if (TeamPlayIsOn()) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //if fast chat is off
- if (!bot_fastchat.integer) {
- if (random() > rnd * 0.5) return qfalse;
- }
- if (!BotValidChatPosition(bs)) return qfalse;
- //
- ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name));
- weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client);
- //
- BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_HitNoDeath
-==================
-*/
-int BotChat_HitNoDeath(bot_state_t *bs) {
- char name[32], *weap;
- float rnd;
- int lasthurt_client;
- aas_entityinfo_t entinfo;
-
- lasthurt_client = g_entities[bs->client].client->lasthurt_client;
- if (!lasthurt_client) return qfalse;
- if (lasthurt_client == bs->client) return qfalse;
- //
- if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;
- //
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- if (BotNumActivePlayers() <= 1) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNODEATH, 0, 1);
- //don't chat in teamplay
- if (TeamPlayIsOn()) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //if fast chat is off
- if (!bot_fastchat.integer) {
- if (random() > rnd * 0.5) return qfalse;
- }
- if (!BotValidChatPosition(bs)) return qfalse;
- //
- if (BotVisibleEnemies(bs)) return qfalse;
- //
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityIsShooting(&entinfo)) return qfalse;
- //
- ClientName(lasthurt_client, name, sizeof(name));
- weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_mod);
- //
- BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_HitNoKill
-==================
-*/
-int BotChat_HitNoKill(bot_state_t *bs) {
- char name[32], *weap;
- float rnd;
- aas_entityinfo_t entinfo;
-
- if (bot_nochat.integer) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- if (BotNumActivePlayers() <= 1) return qfalse;
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNOKILL, 0, 1);
- //don't chat in teamplay
- if (TeamPlayIsOn()) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //if fast chat is off
- if (!bot_fastchat.integer) {
- if (random() > rnd * 0.5) return qfalse;
- }
- if (!BotValidChatPosition(bs)) return qfalse;
- //
- if (BotVisibleEnemies(bs)) return qfalse;
- //
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityIsShooting(&entinfo)) return qfalse;
- //
- ClientName(bs->enemy, name, sizeof(name));
- weap = BotWeaponNameForMeansOfDeath(g_entities[bs->enemy].client->lasthurt_mod);
- //
- BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL);
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChat_Random
-==================
-*/
-int BotChat_Random(bot_state_t *bs) {
- float rnd;
- char name[32];
-
- if (bot_nochat.integer) return qfalse;
- if (BotIsObserver(bs)) return qfalse;
- if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
- // don't chat in tournament mode
- if (gametype == GT_TOURNAMENT) return qfalse;
- //don't chat when doing something important :)
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_RUSHBASE) return qfalse;
- //
- rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_RANDOM, 0, 1);
- if (random() > bs->thinktime * 0.1) return qfalse;
- if (!bot_fastchat.integer) {
- if (random() > rnd) return qfalse;
- if (random() > 0.25) return qfalse;
- }
- if (BotNumActivePlayers() <= 1) return qfalse;
- //
- if (!BotValidChatPosition(bs)) return qfalse;
- //
- if (BotVisibleEnemies(bs)) return qfalse;
- //
- if (bs->lastkilledplayer == bs->client) {
- Q_strncpyz(name, BotRandomOpponentName(bs),sizeof(name));
- }
- else {
- EasyClientName(bs->lastkilledplayer, name, sizeof(name));
- }
- if (TeamPlayIsOn()) {
- trap_EA_Command(bs->client, "vtaunt");
- return qfalse; // don't wait
- }
- //
- if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_MISC, 0, 1)) {
- BotAI_BotInitialChat(bs, "random_misc",
- BotRandomOpponentName(bs), // 0
- name, // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- BotRandomWeaponName(), // 5
- NULL);
- }
- else {
- BotAI_BotInitialChat(bs, "random_insult",
- BotRandomOpponentName(bs), // 0
- name, // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- BotRandomWeaponName(), // 5
- NULL);
- }
- bs->lastchat_time = FloatTime();
- bs->chatto = CHAT_ALL;
- return qtrue;
-}
-
-/*
-==================
-BotChatTime
-==================
-*/
-float BotChatTime(bot_state_t *bs) {
- int cpm;
-
- cpm = trap_Characteristic_BInteger(bs->character, CHARACTERISTIC_CHAT_CPM, 1, 4000);
-
- return 2.0; //(float) trap_BotChatLength(bs->cs) * 30 / cpm;
-}
-
-/*
-==================
-BotChatTest
-==================
-*/
-void BotChatTest(bot_state_t *bs) {
-
- char name[32];
- char *weap;
- int num, i;
-
- if (bot_nochat.integer) return;
-
- num = trap_BotNumInitialChats(bs->cs, "game_enter");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "game_enter",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "game_exit");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "game_exit",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "level_start");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "level_start",
- EasyClientName(bs->client, name, 32), // 0
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "level_end_victory");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "level_end_victory",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- BotFirstClientInRankings(), // 2
- BotLastClientInRankings(), // 3
- BotMapTitle(), // 4
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "level_end_lose");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "level_end_lose",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- BotFirstClientInRankings(), // 2
- BotLastClientInRankings(), // 3
- BotMapTitle(), // 4
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "level_end");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "level_end",
- EasyClientName(bs->client, name, 32), // 0
- BotRandomOpponentName(bs), // 1
- BotFirstClientInRankings(), // 2
- BotLastClientInRankings(), // 3
- BotMapTitle(), // 4
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- EasyClientName(bs->lastkilledby, name, sizeof(name));
- num = trap_BotNumInitialChats(bs->cs, "death_drown");
- for (i = 0; i < num; i++)
- {
- //
- BotAI_BotInitialChat(bs, "death_drown", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_slime");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_slime", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_lava");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_lava", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_cratered");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_cratered", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_suicide");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_suicide", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_telefrag");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_telefrag", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_gauntlet");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_gauntlet",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_rail");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_rail",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_bfg");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_bfg",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_insult");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_insult",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "death_praise");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "death_praise",
- name, // 0
- BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- //
- EasyClientName(bs->lastkilledplayer, name, 32);
- //
- num = trap_BotNumInitialChats(bs->cs, "kill_gauntlet");
- for (i = 0; i < num; i++)
- {
- //
- BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "kill_rail");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "kill_rail", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "kill_telefrag");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "kill_insult");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "kill_insult", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "kill_praise");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "kill_praise", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "enemy_suicide");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name));
- weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client);
- num = trap_BotNumInitialChats(bs->cs, "hit_talking");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "hit_nodeath");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "hit_nokill");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- //
- if (bs->lastkilledplayer == bs->client) {
- Q_strncpyz(name, BotRandomOpponentName(bs), sizeof(name));
- }
- else {
- EasyClientName(bs->lastkilledplayer, name, sizeof(name));
- }
- //
- num = trap_BotNumInitialChats(bs->cs, "random_misc");
- for (i = 0; i < num; i++)
- {
- //
- BotAI_BotInitialChat(bs, "random_misc",
- BotRandomOpponentName(bs), // 0
- name, // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- BotRandomWeaponName(), // 5
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
- num = trap_BotNumInitialChats(bs->cs, "random_insult");
- for (i = 0; i < num; i++)
- {
- BotAI_BotInitialChat(bs, "random_insult",
- BotRandomOpponentName(bs), // 0
- name, // 1
- "[invalid var]", // 2
- "[invalid var]", // 3
- BotMapTitle(), // 4
- BotRandomWeaponName(), // 5
- NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
- }
-}
diff --git a/game/code/game/ai_chat.h b/game/code/game/ai_chat.h
deleted file mode 100644
index e458554..0000000
--- a/game/code/game/ai_chat.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_chat.h
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /source/code/botai/ai_chat.c $
- *
- *****************************************************************************/
-
-//
-int BotChat_EnterGame(bot_state_t *bs);
-//
-int BotChat_ExitGame(bot_state_t *bs);
-//
-int BotChat_StartLevel(bot_state_t *bs);
-//
-int BotChat_EndLevel(bot_state_t *bs);
-//
-int BotChat_HitTalking(bot_state_t *bs);
-//
-int BotChat_HitNoDeath(bot_state_t *bs);
-//
-int BotChat_HitNoKill(bot_state_t *bs);
-//
-int BotChat_Death(bot_state_t *bs);
-//
-int BotChat_Kill(bot_state_t *bs);
-//
-int BotChat_EnemySuicide(bot_state_t *bs);
-//
-int BotChat_Random(bot_state_t *bs);
-// time the selected chat takes to type in
-float BotChatTime(bot_state_t *bs);
-// returns true if the bot can chat at the current position
-int BotValidChatPosition(bot_state_t *bs);
-// test the initial bot chats
-void BotChatTest(bot_state_t *bs);
-
diff --git a/game/code/game/ai_cmd.h b/game/code/game/ai_cmd.h
deleted file mode 100644
index dd10bc1..0000000
--- a/game/code/game/ai_cmd.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_cmd.h
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /source/code/botai/ai_chat.c $
- *
- *****************************************************************************/
-
-extern int notleader[MAX_CLIENTS];
-
-int BotMatchMessage(bot_state_t *bs, char *message);
-void BotPrintTeamGoal(bot_state_t *bs);
-
diff --git a/game/code/game/ai_dmnet.c b/game/code/game/ai_dmnet.c
deleted file mode 100644
index b3eda48..0000000
--- a/game/code/game/ai_dmnet.c
+++ /dev/null
@@ -1,2683 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_dmnet.c
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /MissionPack/code/game/ai_dmnet.c $
- *
- *****************************************************************************/
-
-#include "g_local.h"
-#include "../botlib/botlib.h"
-#include "../botlib/be_aas.h"
-#include "../botlib/be_ea.h"
-#include "../botlib/be_ai_char.h"
-#include "../botlib/be_ai_chat.h"
-#include "../botlib/be_ai_gen.h"
-#include "../botlib/be_ai_goal.h"
-#include "../botlib/be_ai_move.h"
-#include "../botlib/be_ai_weap.h"
-//
-#include "ai_main.h"
-#include "ai_dmq3.h"
-#include "ai_chat.h"
-#include "ai_cmd.h"
-#include "ai_dmnet.h"
-#include "ai_team.h"
-//data file headers
-#include "chars.h" //characteristics
-#include "inv.h" //indexes into the inventory
-#include "syn.h" //synonyms
-#include "match.h" //string matching types and vars
-
-// for the voice chats
-#include "../../ui/menudef.h"
-
-//goal flag, see ../botlib/be_ai_goal.h for the other GFL_*
-#define GFL_AIR 128
-
-int numnodeswitches;
-char nodeswitch[MAX_NODESWITCHES+1][144];
-
-#define LOOKAHEAD_DISTANCE 300
-
-extern bot_goal_t dom_points_bot[MAX_DOMINATION_POINTS];
-
-/*
-==================
-BotResetNodeSwitches
-==================
-*/
-void BotResetNodeSwitches(void) {
- numnodeswitches = 0;
-}
-
-/*
-==================
-BotDumpNodeSwitches
-==================
-*/
-void BotDumpNodeSwitches(bot_state_t *bs) {
- int i;
- char netname[MAX_NETNAME];
-
- ClientName(bs->client, netname, sizeof(netname));
- BotAI_Print(PRT_MESSAGE, "%s at %1.1f switched more than %d AI nodes\n", netname, FloatTime(), MAX_NODESWITCHES);
- for (i = 0; i < numnodeswitches; i++) {
- BotAI_Print(PRT_MESSAGE, "%s", nodeswitch[i]);
- }
- BotAI_Print(PRT_FATAL, "");
-}
-
-/*
-==================
-BotRecordNodeSwitch
-==================
-*/
-void BotRecordNodeSwitch(bot_state_t *bs, char *node, char *str, char *s) {
- char netname[MAX_NETNAME];
-
- ClientName(bs->client, netname, sizeof(netname));
- Com_sprintf(nodeswitch[numnodeswitches], 144, "%s at %2.1f entered %s: %s from %s\n", netname, FloatTime(), node, str, s);
-#ifdef DEBUG
- if (0) {
- BotAI_Print(PRT_MESSAGE, "%s", nodeswitch[numnodeswitches]);
- }
-#endif //DEBUG
- numnodeswitches++;
-}
-
-/*
-==================
-BotGetAirGoal
-==================
-*/
-int BotGetAirGoal(bot_state_t *bs, bot_goal_t *goal) {
- bsp_trace_t bsptrace;
- vec3_t end, mins = {-15, -15, -2}, maxs = {15, 15, 2};
- int areanum;
-
- //trace up until we hit solid
- VectorCopy(bs->origin, end);
- end[2] += 1000;
- BotAI_Trace(&bsptrace, bs->origin, mins, maxs, end, bs->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- //trace down until we hit water
- VectorCopy(bsptrace.endpos, end);
- BotAI_Trace(&bsptrace, end, mins, maxs, bs->origin, bs->entitynum, CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA);
- //if we found the water surface
- if (bsptrace.fraction > 0) {
- areanum = BotPointAreaNum(bsptrace.endpos);
- if (areanum) {
- VectorCopy(bsptrace.endpos, goal->origin);
- goal->origin[2] -= 2;
- goal->areanum = areanum;
- goal->mins[0] = -15;
- goal->mins[1] = -15;
- goal->mins[2] = -1;
- goal->maxs[0] = 15;
- goal->maxs[1] = 15;
- goal->maxs[2] = 1;
- goal->flags = GFL_AIR;
- goal->number = 0;
- goal->iteminfo = 0;
- goal->entitynum = 0;
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-==================
-BotGoForAir
-==================
-*/
-int BotGoForAir(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) {
- bot_goal_t goal;
-
- //if the bot needs air
- if (bs->lastair_time < FloatTime() - 6) {
- //
-#ifdef DEBUG
- //BotAI_Print(PRT_MESSAGE, "going for air\n");
-#endif //DEBUG
- //if we can find an air goal
- if (BotGetAirGoal(bs, &goal)) {
- trap_BotPushGoal(bs->gs, &goal);
- return qtrue;
- }
- else {
- //get a nearby goal outside the water
- while(trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range)) {
- trap_BotGetTopGoal(bs->gs, &goal);
- //if the goal is not in water
- if (!(trap_AAS_PointContents(goal.origin) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))) {
- return qtrue;
- }
- trap_BotPopGoal(bs->gs);
- }
- trap_BotResetAvoidGoals(bs->gs);
- }
- }
- return qfalse;
-}
-
-/*
-==================
-BotNearbyGoal
-==================
-*/
-int BotNearbyGoal(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) {
- int ret;
-
- //check if the bot should go for air
- if (BotGoForAir(bs, tfl, ltg, range)) return qtrue;
- //if the bot is carrying the enemy flag
- if (BotCTFCarryingFlag(bs)) {
- //if the bot is just a few secs away from the base
- if (trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin,
- bs->teamgoal.areanum, TFL_DEFAULT) < 300) {
- //make the range really small
- range = 50;
- }
- }
- //
- ret = trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range);
- /*
- if (ret)
- {
- char buf[128];
- //get the goal at the top of the stack
- trap_BotGetTopGoal(bs->gs, &goal);
- trap_BotGoalName(goal.number, buf, sizeof(buf));
- BotAI_Print(PRT_MESSAGE, "%1.1f: new nearby goal %s\n", FloatTime(), buf);
- }
- */
- return ret;
-}
-
-/*
-==================
-BotReachedGoal
-==================
-*/
-int BotReachedGoal(bot_state_t *bs, bot_goal_t *goal) {
- if (goal->flags & GFL_ITEM) {
- //if touching the goal
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- if (!(goal->flags & GFL_DROPPED)) {
- trap_BotSetAvoidGoalTime(bs->gs, goal->number, -1);
- }
- return qtrue;
- }
- //if the goal isn't there
- if (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) {
- /*
- float avoidtime;
- int t;
-
- avoidtime = trap_BotAvoidGoalTime(bs->gs, goal->number);
- if (avoidtime > 0) {
- t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, goal->areanum, bs->tfl);
- if ((float) t * 0.009 < avoidtime)
- return qtrue;
- }
- */
- return qtrue;
- }
- //if in the goal area and below or above the goal and not swimming
- if (bs->areanum == goal->areanum) {
- if (bs->origin[0] > goal->origin[0] + goal->mins[0] && bs->origin[0] < goal->origin[0] + goal->maxs[0]) {
- if (bs->origin[1] > goal->origin[1] + goal->mins[1] && bs->origin[1] < goal->origin[1] + goal->maxs[1]) {
- if (!trap_AAS_Swimming(bs->origin)) {
- return qtrue;
- }
- }
- }
- }
- }
- else if (goal->flags & GFL_AIR) {
- //if touching the goal
- if (trap_BotTouchingGoal(bs->origin, goal)) return qtrue;
- //if the bot got air
- if (bs->lastair_time > FloatTime() - 1) return qtrue;
- }
- else {
- //if touching the goal
- if (trap_BotTouchingGoal(bs->origin, goal)) return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-BotGetItemLongTermGoal
-==================
-*/
-int BotGetItemLongTermGoal(bot_state_t *bs, int tfl, bot_goal_t *goal) {
- //if the bot has no goal
- if (!trap_BotGetTopGoal(bs->gs, goal)) {
- //BotAI_Print(PRT_MESSAGE, "no ltg on stack\n");
- bs->ltg_time = 0;
- }
- //if the bot touches the current goal
- else if (BotReachedGoal(bs, goal)) {
- BotChooseWeapon(bs);
- bs->ltg_time = 0;
- }
- //if it is time to find a new long term goal
- if (bs->ltg_time < FloatTime()) {
- //pop the current goal from the stack
- trap_BotPopGoal(bs->gs);
- //BotAI_Print(PRT_MESSAGE, "%s: choosing new ltg\n", ClientName(bs->client, netname, sizeof(netname)));
- //choose a new goal
- //BotAI_Print(PRT_MESSAGE, "%6.1f client %d: BotChooseLTGItem\n", FloatTime(), bs->client);
- if (trap_BotChooseLTGItem(bs->gs, bs->origin, bs->inventory, tfl)) {
- /*
- char buf[128];
- //get the goal at the top of the stack
- trap_BotGetTopGoal(bs->gs, goal);
- trap_BotGoalName(goal->number, buf, sizeof(buf));
- BotAI_Print(PRT_MESSAGE, "%1.1f: new long term goal %s\n", FloatTime(), buf);
- */
- bs->ltg_time = FloatTime() + 20;
- }
- else {//the bot gets sorta stuck with all the avoid timings, shouldn't happen though
- //
-#ifdef DEBUG
- char netname[128];
-
- BotAI_Print(PRT_MESSAGE, "%s: no valid ltg (probably stuck)\n", ClientName(bs->client, netname, sizeof(netname)));
-#endif
- //trap_BotDumpAvoidGoals(bs->gs);
- //reset the avoid goals and the avoid reach
- trap_BotResetAvoidGoals(bs->gs);
- trap_BotResetAvoidReach(bs->ms);
- }
- //get the goal at the top of the stack
- return trap_BotGetTopGoal(bs->gs, goal);
- }
- return qtrue;
-}
-
-/*
-==================
-BotGetLongTermGoal
-
-we could also create a seperate AI node for every long term goal type
-however this saves us a lot of code
-==================
-*/
-int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) {
- vec3_t target, dir, dir2;
- char netname[MAX_NETNAME];
- char buf[MAX_MESSAGE_SIZE];
- int areanum;
- float croucher;
- aas_entityinfo_t entinfo, botinfo;
- bot_waypoint_t *wp;
-
- if (bs->ltgtype == LTG_TEAMHELP && !retreat) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "help_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
- bs->teammessage_time = 0;
- }
- //if trying to help the team mate for more than a minute
- if (bs->teamgoal_time < FloatTime())
- bs->ltgtype = 0;
- //if the team mate IS visible for quite some time
- if (bs->teammatevisible_time < FloatTime() - 10) bs->ltgtype = 0;
- //get entity information of the companion
- BotEntityInfo(bs->teammate, &entinfo);
- //if the team mate is visible
- if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) {
- //if close just stand still there
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(100)) {
- trap_BotResetAvoidReach(bs->ms);
- return qfalse;
- }
- }
- else {
- //last time the bot was NOT visible
- bs->teammatevisible_time = FloatTime();
- }
- //if the entity information is valid (entity in PVS)
- if (entinfo.valid) {
- areanum = BotPointAreaNum(entinfo.origin);
- if (areanum && trap_AAS_AreaReachability(areanum)) {
- //update team goal
- bs->teamgoal.entitynum = bs->teammate;
- bs->teamgoal.areanum = areanum;
- VectorCopy(entinfo.origin, bs->teamgoal.origin);
- VectorSet(bs->teamgoal.mins, -8, -8, -8);
- VectorSet(bs->teamgoal.maxs, 8, 8, 8);
- }
- }
- memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
- return qtrue;
- }
- //if the bot accompanies someone
- if (bs->ltgtype == LTG_TEAMACCOMPANY && !retreat) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "accompany_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
- bs->teammessage_time = 0;
- }
- //if accompanying the companion for 3 minutes
- if (bs->teamgoal_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "accompany_stop", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->ltgtype = 0;
- }
- //get entity information of the companion
- BotEntityInfo(bs->teammate, &entinfo);
- //if the companion is visible
- if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) {
- //update visible time
- bs->teammatevisible_time = FloatTime();
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(bs->formation_dist)) {
- //
- // if the client being followed bumps into this bot then
- // the bot should back up
- BotEntityInfo(bs->entitynum, &botinfo);
- // if the followed client is not standing ontop of the bot
- if (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2]) {
- // if the bounding boxes touch each other
- if (botinfo.origin[0] + botinfo.maxs[0] > entinfo.origin[0] + entinfo.mins[0] - 4&&
- botinfo.origin[0] + botinfo.mins[0] < entinfo.origin[0] + entinfo.maxs[0] + 4) {
- if (botinfo.origin[1] + botinfo.maxs[1] > entinfo.origin[1] + entinfo.mins[1] - 4 &&
- botinfo.origin[1] + botinfo.mins[1] < entinfo.origin[1] + entinfo.maxs[1] + 4) {
- if (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2] - 4 &&
- botinfo.origin[2] + botinfo.mins[2] < entinfo.origin[2] + entinfo.maxs[2] + 4) {
- // if the followed client looks in the direction of this bot
- AngleVectors(entinfo.angles, dir, NULL, NULL);
- dir[2] = 0;
- VectorNormalize(dir);
- //VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir);
- VectorSubtract(bs->origin, entinfo.origin, dir2);
- VectorNormalize(dir2);
- if (DotProduct(dir, dir2) > 0.7) {
- // back up
- BotSetupForMovement(bs);
- trap_BotMoveInDirection(bs->ms, dir2, 400, MOVE_WALK);
- }
- }
- }
- }
- }
- //check if the bot wants to crouch
- //don't crouch if crouched less than 5 seconds ago
- if (bs->attackcrouch_time < FloatTime() - 5) {
- croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);
- if (random() < bs->thinktime * croucher) {
- bs->attackcrouch_time = FloatTime() + 5 + croucher * 15;
- }
- }
- //don't crouch when swimming
- if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1;
- //if not arrived yet or arived some time ago
- if (bs->arrive_time < FloatTime() - 2) {
- //if not arrived yet
- if (!bs->arrive_time) {
- trap_EA_Gesture(bs->client);
- BotAI_BotInitialChat(bs, "accompany_arrive", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->arrive_time = FloatTime();
- }
- //if the bot wants to crouch
- else if (bs->attackcrouch_time > FloatTime()) {
- trap_EA_Crouch(bs->client);
- }
- //else do some model taunts
- else if (random() < bs->thinktime * 0.05) {
- //do a gesture :)
- trap_EA_Gesture(bs->client);
- }
- }
- //if just arrived look at the companion
- if (bs->arrive_time > FloatTime() - 2) {
- VectorSubtract(entinfo.origin, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- //else look strategically around for enemies
- else if (random() < bs->thinktime * 0.8) {
- BotRoamGoal(bs, target);
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- //check if the bot wants to go for air
- if (BotGoForAir(bs, bs->tfl, &bs->teamgoal, 400)) {
- trap_BotResetLastAvoidReach(bs->ms);
- //get the goal at the top of the stack
- //trap_BotGetTopGoal(bs->gs, &tmpgoal);
- //trap_BotGoalName(tmpgoal.number, buf, 144);
- //BotAI_Print(PRT_MESSAGE, "new nearby goal %s\n", buf);
- //time the bot gets to pick up the nearby goal item
- bs->nbg_time = FloatTime() + 8;
- AIEnter_Seek_NBG(bs, "BotLongTermGoal: go for air");
- return qfalse;
- }
- //
- trap_BotResetAvoidReach(bs->ms);
- return qfalse;
- }
- }
- //if the entity information is valid (entity in PVS)
- if (entinfo.valid) {
- areanum = BotPointAreaNum(entinfo.origin);
- if (areanum && trap_AAS_AreaReachability(areanum)) {
- //update team goal
- bs->teamgoal.entitynum = bs->teammate;
- bs->teamgoal.areanum = areanum;
- VectorCopy(entinfo.origin, bs->teamgoal.origin);
- VectorSet(bs->teamgoal.mins, -8, -8, -8);
- VectorSet(bs->teamgoal.maxs, 8, 8, 8);
- }
- }
- //the goal the bot should go for
- memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
- //if the companion is NOT visible for too long
- if (bs->teammatevisible_time < FloatTime() - 60) {
- BotAI_BotInitialChat(bs, "accompany_cannotfind", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->ltgtype = 0;
- // just to make sure the bot won't spam this message
- bs->teammatevisible_time = FloatTime();
- }
- return qtrue;
- }
- //
- if (bs->ltgtype == LTG_DEFENDKEYAREA) {
- if (trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin,
- bs->teamgoal.areanum, TFL_DEFAULT) > bs->defendaway_range) {
- bs->defendaway_time = 0;
- }
- }
- //For double domination
- if (bs->ltgtype == LTG_POINTA &&
- bs->defendaway_time < FloatTime()) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "dd_start_pointa", buf, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- //BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE);
- bs->teammessage_time = 0;
- }
- //set the bot goal
- memcpy(goal, &ctf_redflag, sizeof(bot_goal_t));
- //if very close... go away for some time
- VectorSubtract(goal->origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(70)) {
- trap_BotResetAvoidReach(bs->ms);
- bs->defendaway_time = FloatTime() + 3 + 3 * random();
- if (BotHasPersistantPowerupAndWeapon(bs)) {
- bs->defendaway_range = 100;
- }
- else {
- bs->defendaway_range = 350;
- }
- }
- return qtrue;
- }
- if (bs->ltgtype == LTG_POINTB &&
- bs->defendaway_time < FloatTime()) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "dd_start_pointb", buf, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- //BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE);
- bs->teammessage_time = 0;
- }
- //set the bot goal
- memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t));
- //if very close... go away for some time
- VectorSubtract(goal->origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(70)) {
- trap_BotResetAvoidReach(bs->ms);
- bs->defendaway_time = FloatTime() + 3 + 3 * random();
- if (BotHasPersistantPowerupAndWeapon(bs)) {
- bs->defendaway_range = 100;
- }
- else {
- bs->defendaway_range = 350;
- }
- }
- return qtrue;
- }
- //if (bs->ltgtype == LTG_DOMHOLD &&
- // bs->defendaway_time < FloatTime()) {
- //check for bot typing status message
- /*if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "dd_start_pointb", buf, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- //BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE);
- bs->teammessage_time = 0;
- }*/
- //set the bot goal
- // memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
- //if very close... go away for some time
- // VectorSubtract(goal->origin, bs->origin, dir);
- // if (VectorLengthSquared(dir) < Square(30)) {
- /*trap_BotResetAvoidReach(bs->ms);
- bs->defendaway_time = FloatTime() + 3 + 3 * random();
- if (BotHasPersistantPowerupAndWeapon(bs)) {
- bs->defendaway_range = 100;
- }
- else {
- bs->defendaway_range = 350;
- }*/
- // memcpy(&bs->teamgoal, &dom_points_bot[((rand()) % (level.domination_points_count))], sizeof(bot_goal_t));
- // BotAlternateRoute(bs, &bs->teamgoal);
- // BotSetTeamStatus(bs);
-
- //}
- //return qtrue;
-
- // }
- //if defending a key area
- if (bs->ltgtype == LTG_DEFENDKEYAREA && !retreat &&
- bs->defendaway_time < FloatTime()) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "defend_start", buf, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE);
- bs->teammessage_time = 0;
- }
- //set the bot goal
- memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
- //stop after 2 minutes
- if (bs->teamgoal_time < FloatTime()) {
- trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "defend_stop", buf, NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- bs->ltgtype = 0;
- }
- //if very close... go away for some time
- VectorSubtract(goal->origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(70)) {
- trap_BotResetAvoidReach(bs->ms);
- bs->defendaway_time = FloatTime() + 3 + 3 * random();
- if (BotHasPersistantPowerupAndWeapon(bs)) {
- bs->defendaway_range = 100;
- }
- else {
- bs->defendaway_range = 350;
- }
- }
- return qtrue;
- }
- //going to kill someone
- if (bs->ltgtype == LTG_KILL && !retreat) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "kill_start", buf, NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- bs->teammessage_time = 0;
- }
- //
- if (bs->lastkilledplayer == bs->teamgoal.entitynum) {
- EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "kill_done", buf, NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- bs->lastkilledplayer = -1;
- bs->ltgtype = 0;
- }
- //
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //just roam around
- return BotGetItemLongTermGoal(bs, tfl, goal);
- }
- //get an item
- if (bs->ltgtype == LTG_GETITEM && !retreat) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "getitem_start", buf, NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
- bs->teammessage_time = 0;
- }
- //set the bot goal
- memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
- //stop after some time
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //
- if (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) {
- trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "getitem_notthere", buf, NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- bs->ltgtype = 0;
- }
- else if (BotReachedGoal(bs, goal)) {
- trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
- BotAI_BotInitialChat(bs, "getitem_gotit", buf, NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- bs->ltgtype = 0;
- }
- return qtrue;
- }
- //if camping somewhere
- if ((bs->ltgtype == LTG_CAMP || bs->ltgtype == LTG_CAMPORDER) && !retreat) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- if (bs->ltgtype == LTG_CAMPORDER) {
- BotAI_BotInitialChat(bs, "camp_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
- }
- bs->teammessage_time = 0;
- }
- //set the bot goal
- memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
- //
- if (bs->teamgoal_time < FloatTime()) {
- if (bs->ltgtype == LTG_CAMPORDER) {
- BotAI_BotInitialChat(bs, "camp_stop", NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- }
- bs->ltgtype = 0;
- }
- //if really near the camp spot
- VectorSubtract(goal->origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(60))
- {
- //if not arrived yet
- if (!bs->arrive_time) {
- if (bs->ltgtype == LTG_CAMPORDER) {
- BotAI_BotInitialChat(bs, "camp_arrive", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_INPOSITION);
- }
- bs->arrive_time = FloatTime();
- }
- //look strategically around for enemies
- if (random() < bs->thinktime * 0.8) {
- BotRoamGoal(bs, target);
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- //check if the bot wants to crouch
- //don't crouch if crouched less than 5 seconds ago
- if (bs->attackcrouch_time < FloatTime() - 5) {
- croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);
- if (random() < bs->thinktime * croucher) {
- bs->attackcrouch_time = FloatTime() + 5 + croucher * 15;
- }
- }
- //if the bot wants to crouch
- if (bs->attackcrouch_time > FloatTime()) {
- trap_EA_Crouch(bs->client);
- }
- //don't crouch when swimming
- if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1;
- //make sure the bot is not gonna drown
- if (trap_PointContents(bs->eye,bs->entitynum) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) {
- if (bs->ltgtype == LTG_CAMPORDER) {
- BotAI_BotInitialChat(bs, "camp_stop", NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- //
- if (bs->lastgoal_ltgtype == LTG_CAMPORDER) {
- bs->lastgoal_ltgtype = 0;
- }
- }
- bs->ltgtype = 0;
- }
- //
- if (bs->camp_range > 0) {
- //FIXME: move around a bit
- }
- //
- trap_BotResetAvoidReach(bs->ms);
- return qfalse;
- }
- return qtrue;
- }
- //patrolling along several waypoints
- if (bs->ltgtype == LTG_PATROL && !retreat) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- strcpy(buf, "");
- for (wp = bs->patrolpoints; wp; wp = wp->next) {
- strcat(buf, wp->name);
- if (wp->next) strcat(buf, " to ");
- }
- BotAI_BotInitialChat(bs, "patrol_start", buf, NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
- trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
- bs->teammessage_time = 0;
- }
- //
- if (!bs->curpatrolpoint) {
- bs->ltgtype = 0;
- return qfalse;
- }
- //if the bot touches the current goal
- if (trap_BotTouchingGoal(bs->origin, &bs->curpatrolpoint->goal)) {
- if (bs->patrolflags & PATROL_BACK) {
- if (bs->curpatrolpoint->prev) {
- bs->curpatrolpoint = bs->curpatrolpoint->prev;
- }
- else {
- bs->curpatrolpoint = bs->curpatrolpoint->next;
- bs->patrolflags &= ~PATROL_BACK;
- }
- }
- else {
- if (bs->curpatrolpoint->next) {
- bs->curpatrolpoint = bs->curpatrolpoint->next;
- }
- else {
- bs->curpatrolpoint = bs->curpatrolpoint->prev;
- bs->patrolflags |= PATROL_BACK;
- }
- }
- }
- //stop after 5 minutes
- if (bs->teamgoal_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "patrol_stop", NULL);
- trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
- bs->ltgtype = 0;
- }
- if (!bs->curpatrolpoint) {
- bs->ltgtype = 0;
- return qfalse;
- }
- memcpy(goal, &bs->curpatrolpoint->goal, sizeof(bot_goal_t));
- return qtrue;
- }
-#ifdef CTF
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- //if going for enemy flag
- if (bs->ltgtype == LTG_GETFLAG) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "captureflag_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONGETFLAG);
- bs->teammessage_time = 0;
- }
- //
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //if touching the flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- // make sure the bot knows the flag isn't there anymore
- switch(BotTeam(bs)) {
- case TEAM_RED: bs->blueflagstatus = 1; break;
- case TEAM_BLUE: bs->redflagstatus = 1; break;
- }
- bs->ltgtype = 0;
- }
- //stop after 3 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- BotAlternateRoute(bs, goal);
- return qtrue;
- }
- //if rushing to the base
- if (bs->ltgtype == LTG_RUSHBASE && bs->rushbaseaway_time < FloatTime()) {
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //if not carrying the flag anymore
- if (!BotCTFCarryingFlag(bs)) bs->ltgtype = 0;
- //quit rushing after 2 minutes
- if (bs->teamgoal_time < FloatTime()) bs->ltgtype = 0;
- //if touching the base flag the bot should loose the enemy flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- //if the bot is still carrying the enemy flag then the
- //base flag is gone, now just walk near the base a bit
- if (BotCTFCarryingFlag(bs)) {
- trap_BotResetAvoidReach(bs->ms);
- bs->rushbaseaway_time = FloatTime() + 5 + 10 * random();
- //FIXME: add chat to tell the others to get back the flag
- }
- else {
- bs->ltgtype = 0;
- }
- }
- BotAlternateRoute(bs, goal);
- return qtrue;
- }
- //returning flag
- if (bs->ltgtype == LTG_RETURNFLAG) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "returnflag_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONRETURNFLAG);
- bs->teammessage_time = 0;
- }
- //
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //if touching the flag
- if (trap_BotTouchingGoal(bs->origin, goal)) bs->ltgtype = 0;
- //stop after 3 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- BotAlternateRoute(bs, goal);
- return qtrue;
- }
- }
-#endif //CTF
- else if (gametype == GT_1FCTF) {
- if (bs->ltgtype == LTG_GETFLAG) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "captureflag_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONGETFLAG);
- bs->teammessage_time = 0;
- }
- memcpy(goal, &ctf_neutralflag, sizeof(bot_goal_t));
- //if touching the flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- bs->ltgtype = 0;
- }
- //stop after 3 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- return qtrue;
- }
- //if rushing to the base
- if (bs->ltgtype == LTG_RUSHBASE) {
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //if not carrying the flag anymore
- if (!Bot1FCTFCarryingFlag(bs)) {
- bs->ltgtype = 0;
- }
- //quit rushing after 2 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //if touching the base flag the bot should loose the enemy flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- bs->ltgtype = 0;
- }
- BotAlternateRoute(bs, goal);
- return qtrue;
- }
- //attack the enemy base
- if (bs->ltgtype == LTG_ATTACKENEMYBASE &&
- bs->attackaway_time < FloatTime()) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "attackenemybase_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
- bs->teammessage_time = 0;
- }
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //quit rushing after 2 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //if touching the base flag the bot should loose the enemy flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- bs->attackaway_time = FloatTime() + 2 + 5 * random();
- }
- return qtrue;
- }
- //returning flag
- if (bs->ltgtype == LTG_RETURNFLAG) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "returnflag_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONRETURNFLAG);
- bs->teammessage_time = 0;
- }
- //
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //just roam around
- return BotGetItemLongTermGoal(bs, tfl, goal);
- }
- }
- else if (gametype == GT_OBELISK) {
- if (bs->ltgtype == LTG_ATTACKENEMYBASE &&
- bs->attackaway_time < FloatTime()) {
-
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "attackenemybase_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
- bs->teammessage_time = 0;
- }
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //if the bot no longer wants to attack the obelisk
- if (BotFeelingBad(bs) > 50) {
- return BotGetItemLongTermGoal(bs, tfl, goal);
- }
- //if touching the obelisk
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- bs->attackaway_time = FloatTime() + 3 + 5 * random();
- }
- // or very close to the obelisk
- VectorSubtract(bs->origin, goal->origin, dir);
- if (VectorLengthSquared(dir) < Square(60)) {
- bs->attackaway_time = FloatTime() + 3 + 5 * random();
- }
- //quit rushing after 2 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- BotAlternateRoute(bs, goal);
- //just move towards the obelisk
- return qtrue;
- }
- }
- else if (gametype == GT_HARVESTER) {
- //if rushing to the base
- if (bs->ltgtype == LTG_RUSHBASE) {
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break;
- default: BotGoHarvest(bs); return qfalse;
- }
- //if not carrying any cubes
- if (!BotHarvesterCarryingCubes(bs)) {
- BotGoHarvest(bs);
- return qfalse;
- }
- //quit rushing after 2 minutes
- if (bs->teamgoal_time < FloatTime()) {
- BotGoHarvest(bs);
- return qfalse;
- }
- //if touching the base flag the bot should loose the enemy flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- BotGoHarvest(bs);
- return qfalse;
- }
- BotAlternateRoute(bs, goal);
- return qtrue;
- }
- //attack the enemy base
- if (bs->ltgtype == LTG_ATTACKENEMYBASE &&
- bs->attackaway_time < FloatTime()) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "attackenemybase_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
- bs->teammessage_time = 0;
- }
- switch(BotTeam(bs)) {
- case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break;
- case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break;
- default: bs->ltgtype = 0; return qfalse;
- }
- //quit rushing after 2 minutes
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //if touching the base flag the bot should loose the enemy flag
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- bs->attackaway_time = FloatTime() + 2 + 5 * random();
- }
- return qtrue;
- }
- //harvest cubes
- if (bs->ltgtype == LTG_HARVEST &&
- bs->harvestaway_time < FloatTime()) {
- //check for bot typing status message
- if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "harvest_start", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
- bs->teammessage_time = 0;
- }
- memcpy(goal, &neutralobelisk, sizeof(bot_goal_t));
- //
- if (bs->teamgoal_time < FloatTime()) {
- bs->ltgtype = 0;
- }
- //
- if (trap_BotTouchingGoal(bs->origin, goal)) {
- bs->harvestaway_time = FloatTime() + 4 + 3 * random();
- }
- return qtrue;
- }
- }
-//#endif
- //normal goal stuff
- return BotGetItemLongTermGoal(bs, tfl, goal);
-}
-
-/*
-==================
-BotLongTermGoal
-==================
-*/
-int BotLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) {
- aas_entityinfo_t entinfo;
- char teammate[MAX_MESSAGE_SIZE];
- float squaredist;
- int areanum;
- vec3_t dir;
-
- //FIXME: also have air long term goals?
- //
- //if the bot is leading someone and not retreating
- if (bs->lead_time > 0 && !retreat) {
- if (bs->lead_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "lead_stop", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->lead_time = 0;
- return BotGetLongTermGoal(bs, tfl, retreat, goal);
- }
- //
- if (bs->leadmessage_time < 0 && -bs->leadmessage_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->leadmessage_time = FloatTime();
- }
- //get entity information of the companion
- BotEntityInfo(bs->lead_teammate, &entinfo);
- //
- if (entinfo.valid) {
- areanum = BotPointAreaNum(entinfo.origin);
- if (areanum && trap_AAS_AreaReachability(areanum)) {
- //update team goal
- bs->lead_teamgoal.entitynum = bs->lead_teammate;
- bs->lead_teamgoal.areanum = areanum;
- VectorCopy(entinfo.origin, bs->lead_teamgoal.origin);
- VectorSet(bs->lead_teamgoal.mins, -8, -8, -8);
- VectorSet(bs->lead_teamgoal.maxs, 8, 8, 8);
- }
- }
- //if the team mate is visible
- if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->lead_teammate)) {
- bs->leadvisible_time = FloatTime();
- }
- //if the team mate is not visible for 1 seconds
- if (bs->leadvisible_time < FloatTime() - 1) {
- bs->leadbackup_time = FloatTime() + 2;
- }
- //distance towards the team mate
- VectorSubtract(bs->origin, bs->lead_teamgoal.origin, dir);
- squaredist = VectorLengthSquared(dir);
- //if backing up towards the team mate
- if (bs->leadbackup_time > FloatTime()) {
- if (bs->leadmessage_time < FloatTime() - 20) {
- BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->leadmessage_time = FloatTime();
- }
- //if very close to the team mate
- if (squaredist < Square(100)) {
- bs->leadbackup_time = 0;
- }
- //the bot should go back to the team mate
- memcpy(goal, &bs->lead_teamgoal, sizeof(bot_goal_t));
- return qtrue;
- }
- else {
- //if quite distant from the team mate
- if (squaredist > Square(500)) {
- if (bs->leadmessage_time < FloatTime() - 20) {
- BotAI_BotInitialChat(bs, "followme", EasyClientName(bs->lead_teammate, teammate, sizeof(teammate)), NULL);
- trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
- bs->leadmessage_time = FloatTime();
- }
- //look at the team mate
- VectorSubtract(entinfo.origin, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- //just wait for the team mate
- return qfalse;
- }
- }
- }
- return BotGetLongTermGoal(bs, tfl, retreat, goal);
-}
-
-/*
-==================
-AIEnter_Intermission
-==================
-*/
-void AIEnter_Intermission(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "intermission", "", s);
- //reset the bot state
- BotResetState(bs);
- //check for end level chat
- if (BotChat_EndLevel(bs)) {
- trap_BotEnterChat(bs->cs, 0, bs->chatto);
- }
- bs->ainode = AINode_Intermission;
-}
-
-/*
-==================
-AINode_Intermission
-==================
-*/
-int AINode_Intermission(bot_state_t *bs) {
- //if the intermission ended
- if (!BotIntermission(bs)) {
- if (BotChat_StartLevel(bs)) {
- bs->stand_time = FloatTime() + BotChatTime(bs);
- }
- else {
- bs->stand_time = FloatTime() + 2;
- }
- AIEnter_Stand(bs, "intermission: chat");
- }
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Observer
-==================
-*/
-void AIEnter_Observer(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "observer", "", s);
- //reset the bot state
- BotResetState(bs);
- bs->ainode = AINode_Observer;
-}
-
-/*
-==================
-AINode_Observer
-==================
-*/
-int AINode_Observer(bot_state_t *bs) {
- //if the bot left observer mode
- if (!BotIsObserver(bs)) {
- AIEnter_Stand(bs, "observer: left observer");
- }
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Stand
-==================
-*/
-void AIEnter_Stand(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "stand", "", s);
- bs->standfindenemy_time = FloatTime() + 1;
- bs->ainode = AINode_Stand;
-}
-
-/*
-==================
-AINode_Stand
-==================
-*/
-int AINode_Stand(bot_state_t *bs) {
-
- //if the bot's health decreased
- if (bs->lastframe_health > bs->inventory[INVENTORY_HEALTH]) {
- if (BotChat_HitTalking(bs)) {
- bs->standfindenemy_time = FloatTime() + BotChatTime(bs) + 0.1;
- bs->stand_time = FloatTime() + BotChatTime(bs) + 0.1;
- }
- }
- if (bs->standfindenemy_time < FloatTime()) {
- if (BotFindEnemy(bs, -1)) {
- AIEnter_Battle_Fight(bs, "stand: found enemy");
- return qfalse;
- }
- bs->standfindenemy_time = FloatTime() + 1;
- }
- // put up chat icon
- trap_EA_Talk(bs->client);
- // when done standing
- if (bs->stand_time < FloatTime()) {
- trap_BotEnterChat(bs->cs, 0, bs->chatto);
- AIEnter_Seek_LTG(bs, "stand: time out");
- return qfalse;
- }
- //
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Respawn
-==================
-*/
-void AIEnter_Respawn(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "respawn", "", s);
- //reset some states
- trap_BotResetMoveState(bs->ms);
- trap_BotResetGoalState(bs->gs);
- trap_BotResetAvoidGoals(bs->gs);
- trap_BotResetAvoidReach(bs->ms);
- //if the bot wants to chat
- if (BotChat_Death(bs)) {
- bs->respawn_time = FloatTime() + BotChatTime(bs);
- bs->respawnchat_time = FloatTime();
- }
- else {
- bs->respawn_time = FloatTime() + 1 + random();
- bs->respawnchat_time = 0;
- }
- //set respawn state
- bs->respawn_wait = qfalse;
- bs->ainode = AINode_Respawn;
-}
-
-/*
-==================
-AINode_Respawn
-==================
-*/
-int AINode_Respawn(bot_state_t *bs) {
- // if waiting for the actual respawn
- if (bs->respawn_wait) {
- if (!BotIsDead(bs)) {
- AIEnter_Seek_LTG(bs, "respawn: respawned");
- }
- else {
- trap_EA_Respawn(bs->client);
- }
- }
- else if (bs->respawn_time < FloatTime()) {
- // wait until respawned
- bs->respawn_wait = qtrue;
- // elementary action respawn
- trap_EA_Respawn(bs->client);
- //
- if (bs->respawnchat_time) {
- trap_BotEnterChat(bs->cs, 0, bs->chatto);
- bs->enemy = -1;
- }
- }
- if (bs->respawnchat_time && bs->respawnchat_time < FloatTime() - 0.5) {
- trap_EA_Talk(bs->client);
- }
- //
- return qtrue;
-}
-
-/*
-==================
-BotSelectActivateWeapon
-==================
-*/
-int BotSelectActivateWeapon(bot_state_t *bs) {
- //
- if (bs->inventory[INVENTORY_MACHINEGUN] > 0 && bs->inventory[INVENTORY_BULLETS] > 0)
- return WEAPONINDEX_MACHINEGUN;
- else if (bs->inventory[INVENTORY_SHOTGUN] > 0 && bs->inventory[INVENTORY_SHELLS] > 0)
- return WEAPONINDEX_SHOTGUN;
- else if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0)
- return WEAPONINDEX_PLASMAGUN;
- else if (bs->inventory[INVENTORY_LIGHTNING] > 0 && bs->inventory[INVENTORY_LIGHTNINGAMMO] > 0)
- return WEAPONINDEX_LIGHTNING;
- else if (bs->inventory[INVENTORY_CHAINGUN] > 0 && bs->inventory[INVENTORY_BELT] > 0)
- return WEAPONINDEX_CHAINGUN;
- else if (bs->inventory[INVENTORY_NAILGUN] > 0 && bs->inventory[INVENTORY_NAILS] > 0)
- return WEAPONINDEX_NAILGUN;
- else if (bs->inventory[INVENTORY_RAILGUN] > 0 && bs->inventory[INVENTORY_SLUGS] > 0)
- return WEAPONINDEX_RAILGUN;
- else if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0)
- return WEAPONINDEX_ROCKET_LAUNCHER;
- else if (bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0)
- return WEAPONINDEX_BFG;
- else {
- return -1;
- }
-}
-
-/*
-==================
-BotClearPath
-
- try to deactivate obstacles like proximity mines on the bot's path
-==================
-*/
-void BotClearPath(bot_state_t *bs, bot_moveresult_t *moveresult) {
- int i, bestmine;
- float dist, bestdist;
- vec3_t target, dir;
- bsp_trace_t bsptrace;
- entityState_t state;
-
- // if there is a dead body wearing kamikze nearby
- if (bs->kamikazebody) {
- // if the bot's view angles and weapon are not used for movement
- if ( !(moveresult->flags & (MOVERESULT_MOVEMENTVIEW | MOVERESULT_MOVEMENTWEAPON)) ) {
- //
- BotAI_GetEntityState(bs->kamikazebody, &state);
- VectorCopy(state.pos.trBase, target);
- target[2] += 8;
- VectorSubtract(target, bs->eye, dir);
- vectoangles(dir, moveresult->ideal_viewangles);
- //
- moveresult->weapon = BotSelectActivateWeapon(bs);
- if (moveresult->weapon == -1) {
- // FIXME: run away!
- moveresult->weapon = 0;
- }
- if (moveresult->weapon) {
- //
- moveresult->flags |= MOVERESULT_MOVEMENTWEAPON | MOVERESULT_MOVEMENTVIEW;
- // if holding the right weapon
- if (bs->cur_ps.weapon == moveresult->weapon) {
- // if the bot is pretty close with it's aim
- if (InFieldOfVision(bs->viewangles, 20, moveresult->ideal_viewangles)) {
- //
- BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, target, bs->entitynum, MASK_SHOT);
- // if the mine is visible from the current position
- if (bsptrace.fraction >= 1.0 || bsptrace.ent == state.number) {
- // shoot at the mine
- trap_EA_Attack(bs->client);
- }
- }
- }
- }
- }
- }
- if (moveresult->flags & MOVERESULT_BLOCKEDBYAVOIDSPOT) {
- bs->blockedbyavoidspot_time = FloatTime() + 5;
- }
- // if blocked by an avoid spot and the view angles and weapon are used for movement
- if (bs->blockedbyavoidspot_time > FloatTime() &&
- !(moveresult->flags & (MOVERESULT_MOVEMENTVIEW | MOVERESULT_MOVEMENTWEAPON)) ) {
- bestdist = 300;
- bestmine = -1;
- for (i = 0; i < bs->numproxmines; i++) {
- BotAI_GetEntityState(bs->proxmines[i], &state);
- VectorSubtract(state.pos.trBase, bs->origin, dir);
- dist = VectorLength(dir);
- if (dist < bestdist) {
- bestdist = dist;
- bestmine = i;
- }
- }
- if (bestmine != -1) {
- //
- // state->generic1 == TEAM_RED || state->generic1 == TEAM_BLUE
- //
- // deactivate prox mines in the bot's path by shooting
- // rockets or plasma cells etc. at them
- BotAI_GetEntityState(bs->proxmines[bestmine], &state);
- VectorCopy(state.pos.trBase, target);
- target[2] += 2;
- VectorSubtract(target, bs->eye, dir);
- vectoangles(dir, moveresult->ideal_viewangles);
- // if the bot has a weapon that does splash damage
- if (bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0)
- moveresult->weapon = WEAPONINDEX_PLASMAGUN;
- else if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0)
- moveresult->weapon = WEAPONINDEX_ROCKET_LAUNCHER;
- else if (bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0)
- moveresult->weapon = WEAPONINDEX_BFG;
- else {
- moveresult->weapon = 0;
- }
- if (moveresult->weapon) {
- //
- moveresult->flags |= MOVERESULT_MOVEMENTWEAPON | MOVERESULT_MOVEMENTVIEW;
- // if holding the right weapon
- if (bs->cur_ps.weapon == moveresult->weapon) {
- // if the bot is pretty close with it's aim
- if (InFieldOfVision(bs->viewangles, 20, moveresult->ideal_viewangles)) {
- //
- BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, target, bs->entitynum, MASK_SHOT);
- // if the mine is visible from the current position
- if (bsptrace.fraction >= 1.0 || bsptrace.ent == state.number) {
- // shoot at the mine
- trap_EA_Attack(bs->client);
- }
- }
- }
- }
- }
- }
-}
-
-/*
-==================
-AIEnter_Seek_ActivateEntity
-==================
-*/
-void AIEnter_Seek_ActivateEntity(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "activate entity", "", s);
- bs->ainode = AINode_Seek_ActivateEntity;
-}
-
-/*
-==================
-AINode_Seek_Activate_Entity
-==================
-*/
-int AINode_Seek_ActivateEntity(bot_state_t *bs) {
- bot_goal_t *goal;
- vec3_t target, dir, ideal_viewangles;
- bot_moveresult_t moveresult;
- int targetvisible;
- bsp_trace_t bsptrace;
- aas_entityinfo_t entinfo;
-
- if (BotIsObserver(bs)) {
- BotClearActivateGoalStack(bs);
- AIEnter_Observer(bs, "active entity: observer");
- return qfalse;
- }
- //if in the intermission
- if (BotIntermission(bs)) {
- BotClearActivateGoalStack(bs);
- AIEnter_Intermission(bs, "activate entity: intermission");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- BotClearActivateGoalStack(bs);
- AIEnter_Respawn(bs, "activate entity: bot dead");
- return qfalse;
- }
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- // if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- // map specific code
- BotMapScripts(bs);
- // no enemy
- bs->enemy = -1;
- // if the bot has no activate goal
- if (!bs->activatestack) {
- BotClearActivateGoalStack(bs);
- AIEnter_Seek_NBG(bs, "activate entity: no goal");
- return qfalse;
- }
- //
- goal = &bs->activatestack->goal;
- // initialize target being visible to false
- targetvisible = qfalse;
- // if the bot has to shoot at a target to activate something
- if (bs->activatestack->shoot) {
- //
- BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, bs->activatestack->target, bs->entitynum, MASK_SHOT);
- // if the shootable entity is visible from the current position
- if (bsptrace.fraction >= 1.0 || bsptrace.ent == goal->entitynum) {
- targetvisible = qtrue;
- // if holding the right weapon
- if (bs->cur_ps.weapon == bs->activatestack->weapon) {
- VectorSubtract(bs->activatestack->target, bs->eye, dir);
- vectoangles(dir, ideal_viewangles);
- // if the bot is pretty close with it's aim
- if (InFieldOfVision(bs->viewangles, 20, ideal_viewangles)) {
- trap_EA_Attack(bs->client);
- }
- }
- }
- }
- // if the shoot target is visible
- if (targetvisible) {
- // get the entity info of the entity the bot is shooting at
- BotEntityInfo(goal->entitynum, &entinfo);
- // if the entity the bot shoots at moved
- if (!VectorCompare(bs->activatestack->origin, entinfo.origin)) {
-#ifdef DEBUG
- BotAI_Print(PRT_MESSAGE, "hit shootable button or trigger\n");
-#endif //DEBUG
- bs->activatestack->time = 0;
- }
- // if the activate goal has been activated or the bot takes too long
- if (bs->activatestack->time < FloatTime()) {
- BotPopFromActivateGoalStack(bs);
- // if there are more activate goals on the stack
- if (bs->activatestack) {
- bs->activatestack->time = FloatTime() + 10;
- return qfalse;
- }
- AIEnter_Seek_NBG(bs, "activate entity: time out");
- return qfalse;
- }
- memset(&moveresult, 0, sizeof(bot_moveresult_t));
- }
- else {
- // if the bot has no goal
- if (!goal) {
- bs->activatestack->time = 0;
- }
- // if the bot does not have a shoot goal
- else if (!bs->activatestack->shoot) {
- //if the bot touches the current goal
- if (trap_BotTouchingGoal(bs->origin, goal)) {
-#ifdef DEBUG
- BotAI_Print(PRT_MESSAGE, "touched button or trigger\n");
-#endif //DEBUG
- bs->activatestack->time = 0;
- }
- }
- // if the activate goal has been activated or the bot takes too long
- if (bs->activatestack->time < FloatTime()) {
- BotPopFromActivateGoalStack(bs);
- // if there are more activate goals on the stack
- if (bs->activatestack) {
- bs->activatestack->time = FloatTime() + 10;
- return qfalse;
- }
- AIEnter_Seek_NBG(bs, "activate entity: activated");
- return qfalse;
- }
- //predict obstacles
- if (BotAIPredictObstacles(bs, goal))
- return qfalse;
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, goal, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- //
- bs->activatestack->time = 0;
- }
- //check if the bot is blocked
- BotAIBlocked(bs, &moveresult, qtrue);
- }
- //
- BotClearPath(bs, &moveresult);
- // if the bot has to shoot to activate
- if (bs->activatestack->shoot) {
- // if the view angles aren't yet used for the movement
- if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEW)) {
- VectorSubtract(bs->activatestack->target, bs->eye, dir);
- vectoangles(dir, moveresult.ideal_viewangles);
- moveresult.flags |= MOVERESULT_MOVEMENTVIEW;
- }
- // if there's no weapon yet used for the movement
- if (!(moveresult.flags & MOVERESULT_MOVEMENTWEAPON)) {
- moveresult.flags |= MOVERESULT_MOVEMENTWEAPON;
- //
- bs->activatestack->weapon = BotSelectActivateWeapon(bs);
- if (bs->activatestack->weapon == -1) {
- //FIXME: find a decent weapon first
- bs->activatestack->weapon = 0;
- }
- moveresult.weapon = bs->activatestack->weapon;
- }
- }
- // if the ideal view angles are set for movement
- if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
- VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
- }
- // if waiting for something
- else if (moveresult.flags & MOVERESULT_WAITING) {
- if (random() < bs->thinktime * 0.8) {
- BotRoamGoal(bs, target);
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- }
- else if (!(bs->flags & BFL_IDEALVIEWSET)) {
- if (trap_BotMovementViewTarget(bs->ms, goal, bs->tfl, 300, target)) {
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- }
- else {
- vectoangles(moveresult.movedir, bs->ideal_viewangles);
- }
- bs->ideal_viewangles[2] *= 0.5;
- }
- // if the weapon is used for the bot movement
- if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON)
- bs->weaponnum = moveresult.weapon;
- // if there is an enemy
- if (BotFindEnemy(bs, -1)) {
- if (BotWantsToRetreat(bs)) {
- //keep the current long term goal and retreat
- AIEnter_Battle_NBG(bs, "activate entity: found enemy");
- }
- else {
- trap_BotResetLastAvoidReach(bs->ms);
- //empty the goal stack
- trap_BotEmptyGoalStack(bs->gs);
- //go fight
- AIEnter_Battle_Fight(bs, "activate entity: found enemy");
- }
- BotClearActivateGoalStack(bs);
- }
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Seek_NBG
-==================
-*/
-void AIEnter_Seek_NBG(bot_state_t *bs, char *s) {
- bot_goal_t goal;
- char buf[144];
-
- if (trap_BotGetTopGoal(bs->gs, &goal)) {
- trap_BotGoalName(goal.number, buf, 144);
- BotRecordNodeSwitch(bs, "seek NBG", buf, s);
- }
- else {
- BotRecordNodeSwitch(bs, "seek NBG", "no goal", s);
- }
- bs->ainode = AINode_Seek_NBG;
-}
-
-/*
-==================
-AINode_Seek_NBG
-==================
-*/
-int AINode_Seek_NBG(bot_state_t *bs) {
- bot_goal_t goal;
- vec3_t target, dir;
- bot_moveresult_t moveresult;
-
- if (BotIsObserver(bs)) {
- AIEnter_Observer(bs, "seek nbg: observer");
- return qfalse;
- }
- //if in the intermission
- if (BotIntermission(bs)) {
- AIEnter_Intermission(bs, "seek nbg: intermision");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- AIEnter_Respawn(bs, "seek nbg: bot dead");
- return qfalse;
- }
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- //if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- //
- if (BotCanAndWantsToRocketJump(bs)) {
- bs->tfl |= TFL_ROCKETJUMP;
- }
- //map specific code
- BotMapScripts(bs);
- //no enemy
- bs->enemy = -1;
- //if the bot has no goal
- if (!trap_BotGetTopGoal(bs->gs, &goal)) bs->nbg_time = 0;
- //if the bot touches the current goal
- else if (BotReachedGoal(bs, &goal)) {
- BotChooseWeapon(bs);
- bs->nbg_time = 0;
- }
- //
- if (bs->nbg_time < FloatTime()) {
- //pop the current goal from the stack
- trap_BotPopGoal(bs->gs);
- //check for new nearby items right away
- //NOTE: we canNOT reset the check_time to zero because it would create an endless loop of node switches
- bs->check_time = FloatTime() + 0.05;
- //go back to seek ltg
- AIEnter_Seek_LTG(bs, "seek nbg: time out");
- return qfalse;
- }
- //predict obstacles
- if (BotAIPredictObstacles(bs, &goal))
- return qfalse;
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- bs->nbg_time = 0;
- }
- //check if the bot is blocked
- BotAIBlocked(bs, &moveresult, qtrue);
- //
- BotClearPath(bs, &moveresult);
- //if the viewangles are used for the movement
- if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
- VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
- }
- //if waiting for something
- else if (moveresult.flags & MOVERESULT_WAITING) {
- if (random() < bs->thinktime * 0.8) {
- BotRoamGoal(bs, target);
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- }
- else if (!(bs->flags & BFL_IDEALVIEWSET)) {
- if (!trap_BotGetSecondGoal(bs->gs, &goal)) trap_BotGetTopGoal(bs->gs, &goal);
- if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- }
- //FIXME: look at cluster portals?
- else vectoangles(moveresult.movedir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- //if the weapon is used for the bot movement
- if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
- //if there is an enemy
- if (BotFindEnemy(bs, -1)) {
- if (BotWantsToRetreat(bs)) {
- //keep the current long term goal and retreat
- AIEnter_Battle_NBG(bs, "seek nbg: found enemy");
- }
- else {
- trap_BotResetLastAvoidReach(bs->ms);
- //empty the goal stack
- trap_BotEmptyGoalStack(bs->gs);
- //go fight
- AIEnter_Battle_Fight(bs, "seek nbg: found enemy");
- }
- }
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Seek_LTG
-==================
-*/
-void AIEnter_Seek_LTG(bot_state_t *bs, char *s) {
- bot_goal_t goal;
- char buf[144];
-
- if (trap_BotGetTopGoal(bs->gs, &goal)) {
- trap_BotGoalName(goal.number, buf, 144);
- BotRecordNodeSwitch(bs, "seek LTG", buf, s);
- }
- else {
- BotRecordNodeSwitch(bs, "seek LTG", "no goal", s);
- }
- bs->ainode = AINode_Seek_LTG;
-}
-
-/*
-==================
-AINode_Seek_LTG
-==================
-*/
-int AINode_Seek_LTG(bot_state_t *bs)
-{
- bot_goal_t goal;
- vec3_t target, dir;
- bot_moveresult_t moveresult;
- int range;
- //char buf[128];
- //bot_goal_t tmpgoal;
-
- if (BotIsObserver(bs)) {
- AIEnter_Observer(bs, "seek ltg: observer");
- return qfalse;
- }
- //if in the intermission
- if (BotIntermission(bs)) {
- AIEnter_Intermission(bs, "seek ltg: intermission");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- AIEnter_Respawn(bs, "seek ltg: bot dead");
- return qfalse;
- }
- //
- if (BotChat_Random(bs)) {
- bs->stand_time = FloatTime() + BotChatTime(bs);
- AIEnter_Stand(bs, "seek ltg: random chat");
- return qfalse;
- }
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- //if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- //
- if (BotCanAndWantsToRocketJump(bs)) {
- bs->tfl |= TFL_ROCKETJUMP;
- }
- //map specific code
- BotMapScripts(bs);
- //no enemy
- bs->enemy = -1;
- //
- if (bs->killedenemy_time > FloatTime() - 2) {
- if (random() < bs->thinktime * 1) {
- trap_EA_Gesture(bs->client);
- }
- }
- //if there is an enemy
- if (BotFindEnemy(bs, -1)) {
- if (BotWantsToRetreat(bs)) {
- //keep the current long term goal and retreat
- AIEnter_Battle_Retreat(bs, "seek ltg: found enemy");
- return qfalse;
- }
- else {
- trap_BotResetLastAvoidReach(bs->ms);
- //empty the goal stack
- trap_BotEmptyGoalStack(bs->gs);
- //go fight
- AIEnter_Battle_Fight(bs, "seek ltg: found enemy");
- return qfalse;
- }
- }
- //
- BotTeamGoals(bs, qfalse);
- //get the current long term goal
- if (!BotLongTermGoal(bs, bs->tfl, qfalse, &goal)) {
- return qtrue;
- }
- //check for nearby goals periodicly
- if (bs->check_time < FloatTime()) {
- bs->check_time = FloatTime() + 0.5;
- //check if the bot wants to camp
- BotWantsToCamp(bs);
- //
- if (bs->ltgtype == LTG_DEFENDKEYAREA) range = 400;
- else range = 150;
- //
-#ifdef CTF
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- //if carrying a flag the bot shouldn't be distracted too much
- if (BotCTFCarryingFlag(bs))
- range = 50;
- }
-#endif //CTF
- else if (gametype == GT_1FCTF) {
- if (Bot1FCTFCarryingFlag(bs))
- range = 50;
- }
- else if (gametype == GT_HARVESTER) {
- if (BotHarvesterCarryingCubes(bs))
- range = 80;
- }
- //
- if (BotNearbyGoal(bs, bs->tfl, &goal, range)) {
- trap_BotResetLastAvoidReach(bs->ms);
- //get the goal at the top of the stack
- //trap_BotGetTopGoal(bs->gs, &tmpgoal);
- //trap_BotGoalName(tmpgoal.number, buf, 144);
- //BotAI_Print(PRT_MESSAGE, "new nearby goal %s\n", buf);
- //time the bot gets to pick up the nearby goal item
- bs->nbg_time = FloatTime() + 4 + range * 0.01;
- AIEnter_Seek_NBG(bs, "ltg seek: nbg");
- return qfalse;
- }
- }
- //predict obstacles
- if (BotAIPredictObstacles(bs, &goal))
- return qfalse;
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
- bs->ltg_time = 0;
- }
- //
- BotAIBlocked(bs, &moveresult, qtrue);
- //
- BotClearPath(bs, &moveresult);
- //if the viewangles are used for the movement
- if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
- VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
- }
- //if waiting for something
- else if (moveresult.flags & MOVERESULT_WAITING) {
- if (random() < bs->thinktime * 0.8) {
- BotRoamGoal(bs, target);
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- }
- else if (!(bs->flags & BFL_IDEALVIEWSET)) {
- if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- }
- //FIXME: look at cluster portals?
- else if (VectorLengthSquared(moveresult.movedir)) {
- vectoangles(moveresult.movedir, bs->ideal_viewangles);
- }
- else if (random() < bs->thinktime * 0.8) {
- BotRoamGoal(bs, target);
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- bs->ideal_viewangles[2] *= 0.5;
- }
- bs->ideal_viewangles[2] *= 0.5;
- }
- //if the weapon is used for the bot movement
- if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
- //
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Battle_Fight
-==================
-*/
-void AIEnter_Battle_Fight(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "battle fight", "", s);
- trap_BotResetLastAvoidReach(bs->ms);
- bs->ainode = AINode_Battle_Fight;
-}
-
-/*
-==================
-AIEnter_Battle_Fight
-==================
-*/
-void AIEnter_Battle_SuicidalFight(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "battle fight", "", s);
- trap_BotResetLastAvoidReach(bs->ms);
- bs->ainode = AINode_Battle_Fight;
- bs->flags |= BFL_FIGHTSUICIDAL;
-}
-
-/*
-==================
-AINode_Battle_Fight
-==================
-*/
-int AINode_Battle_Fight(bot_state_t *bs) {
- int areanum;
- vec3_t target;
- aas_entityinfo_t entinfo;
- bot_moveresult_t moveresult;
-
- if (BotIsObserver(bs)) {
- AIEnter_Observer(bs, "battle fight: observer");
- return qfalse;
- }
-
- //if in the intermission
- if (BotIntermission(bs)) {
- AIEnter_Intermission(bs, "battle fight: intermission");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- AIEnter_Respawn(bs, "battle fight: bot dead");
- return qfalse;
- }
- //if there is another better enemy
- if (BotFindEnemy(bs, bs->enemy)) {
-#ifdef DEBUG
- BotAI_Print(PRT_MESSAGE, "found new better enemy\n");
-#endif
- }
- //if no enemy
- if (bs->enemy < 0) {
- AIEnter_Seek_LTG(bs, "battle fight: no enemy");
- return qfalse;
- }
- //
- BotEntityInfo(bs->enemy, &entinfo);
- //if the enemy is dead
- if (bs->enemydeath_time) {
- if (bs->enemydeath_time < FloatTime() - 1.0) {
- bs->enemydeath_time = 0;
- if (bs->enemysuicide) {
- BotChat_EnemySuicide(bs);
- }
- if (bs->lastkilledplayer == bs->enemy && BotChat_Kill(bs)) {
- bs->stand_time = FloatTime() + BotChatTime(bs);
- AIEnter_Stand(bs, "battle fight: enemy dead");
- }
- else {
- bs->ltg_time = 0;
- AIEnter_Seek_LTG(bs, "battle fight: enemy dead");
- }
- return qfalse;
- }
- }
- else {
- if (EntityIsDead(&entinfo)) {
- bs->enemydeath_time = FloatTime();
- }
- }
- //if the enemy is invisible and not shooting the bot looses track easily
- if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
- if (random() < 0.2) {
- AIEnter_Seek_LTG(bs, "battle fight: invisible");
- return qfalse;
- }
- }
- //
- VectorCopy(entinfo.origin, target);
- // if not a player enemy
- if (bs->enemy >= MAX_CLIENTS) {
- // if attacking an obelisk
- if ( bs->enemy == redobelisk.entitynum ||
- bs->enemy == blueobelisk.entitynum ) {
- target[2] += 16;
- }
- }
- //update the reachability area and origin if possible
- areanum = BotPointAreaNum(target);
- if (areanum && trap_AAS_AreaReachability(areanum)) {
- VectorCopy(target, bs->lastenemyorigin);
- bs->lastenemyareanum = areanum;
- }
- //update the attack inventory values
- BotUpdateBattleInventory(bs, bs->enemy);
- //if the bot's health decreased
- if (bs->lastframe_health > bs->inventory[INVENTORY_HEALTH]) {
- if (BotChat_HitNoDeath(bs)) {
- bs->stand_time = FloatTime() + BotChatTime(bs);
- AIEnter_Stand(bs, "battle fight: chat health decreased");
- return qfalse;
- }
- }
- //if the bot hit someone
- if (bs->cur_ps.persistant[PERS_HITS] > bs->lasthitcount) {
- if (BotChat_HitNoKill(bs)) {
- bs->stand_time = FloatTime() + BotChatTime(bs);
- AIEnter_Stand(bs, "battle fight: chat hit someone");
- return qfalse;
- }
- }
- //if the enemy is not visible
- if (!BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
- if (BotWantsToChase(bs)) {
- AIEnter_Battle_Chase(bs, "battle fight: enemy out of sight");
- return qfalse;
- }
- else {
- AIEnter_Seek_LTG(bs, "battle fight: enemy out of sight");
- return qfalse;
- }
- }
- //use holdable items
- BotBattleUseItems(bs);
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- //if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- //
- if (BotCanAndWantsToRocketJump(bs)) {
- bs->tfl |= TFL_ROCKETJUMP;
- }
- //choose the best weapon to fight with
- BotChooseWeapon(bs);
- //do attack movements
- moveresult = BotAttackMove(bs, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
- bs->ltg_time = 0;
- }
- //
- BotAIBlocked(bs, &moveresult, qfalse);
- //aim at the enemy
- BotAimAtEnemy(bs);
- //attack the enemy if possible
- BotCheckAttack(bs);
- //if the bot wants to retreat
- if (!(bs->flags & BFL_FIGHTSUICIDAL)) {
- if (BotWantsToRetreat(bs)) {
- AIEnter_Battle_Retreat(bs, "battle fight: wants to retreat");
- return qtrue;
- }
- }
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Battle_Chase
-==================
-*/
-void AIEnter_Battle_Chase(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "battle chase", "", s);
- bs->chase_time = FloatTime();
- bs->ainode = AINode_Battle_Chase;
-}
-
-/*
-==================
-AINode_Battle_Chase
-==================
-*/
-int AINode_Battle_Chase(bot_state_t *bs)
-{
- bot_goal_t goal;
- vec3_t target, dir;
- bot_moveresult_t moveresult;
- float range;
-
- if (BotIsObserver(bs)) {
- AIEnter_Observer(bs, "battle chase: observer");
- return qfalse;
- }
- //if in the intermission
- if (BotIntermission(bs)) {
- AIEnter_Intermission(bs, "battle chase: intermission");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- AIEnter_Respawn(bs, "battle chase: bot dead");
- return qfalse;
- }
- //if no enemy
- if (bs->enemy < 0) {
- AIEnter_Seek_LTG(bs, "battle chase: no enemy");
- return qfalse;
- }
- //if the enemy is visible
- if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
- AIEnter_Battle_Fight(bs, "battle chase");
- return qfalse;
- }
- //if there is another enemy
- if (BotFindEnemy(bs, -1)) {
- AIEnter_Battle_Fight(bs, "battle chase: better enemy");
- return qfalse;
- }
- //there is no last enemy area
- if (!bs->lastenemyareanum) {
- AIEnter_Seek_LTG(bs, "battle chase: no enemy area");
- return qfalse;
- }
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- //if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- //
- if (BotCanAndWantsToRocketJump(bs)) {
- bs->tfl |= TFL_ROCKETJUMP;
- }
- //map specific code
- BotMapScripts(bs);
- //create the chase goal
- goal.entitynum = bs->enemy;
- goal.areanum = bs->lastenemyareanum;
- VectorCopy(bs->lastenemyorigin, goal.origin);
- VectorSet(goal.mins, -8, -8, -8);
- VectorSet(goal.maxs, 8, 8, 8);
- //if the last seen enemy spot is reached the enemy could not be found
- if (trap_BotTouchingGoal(bs->origin, &goal)) bs->chase_time = 0;
- //if there's no chase time left
- if (!bs->chase_time || bs->chase_time < FloatTime() - 10) {
- AIEnter_Seek_LTG(bs, "battle chase: time out");
- return qfalse;
- }
- //check for nearby goals periodicly
- if (bs->check_time < FloatTime()) {
- bs->check_time = FloatTime() + 1;
- range = 150;
- //
- if (BotNearbyGoal(bs, bs->tfl, &goal, range)) {
- //the bot gets 5 seconds to pick up the nearby goal item
- bs->nbg_time = FloatTime() + 0.1 * range + 1;
- trap_BotResetLastAvoidReach(bs->ms);
- AIEnter_Battle_NBG(bs, "battle chase: nbg");
- return qfalse;
- }
- }
- //
- BotUpdateBattleInventory(bs, bs->enemy);
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
- bs->ltg_time = 0;
- }
- //
- BotAIBlocked(bs, &moveresult, qfalse);
- //
- if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
- VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
- }
- else if (!(bs->flags & BFL_IDEALVIEWSET)) {
- if (bs->chase_time > FloatTime() - 2) {
- BotAimAtEnemy(bs);
- }
- else {
- if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- }
- else {
- vectoangles(moveresult.movedir, bs->ideal_viewangles);
- }
- }
- bs->ideal_viewangles[2] *= 0.5;
- }
- //if the weapon is used for the bot movement
- if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
- //if the bot is in the area the enemy was last seen in
- if (bs->areanum == bs->lastenemyareanum) bs->chase_time = 0;
- //if the bot wants to retreat (the bot could have been damage during the chase)
- if (BotWantsToRetreat(bs)) {
- AIEnter_Battle_Retreat(bs, "battle chase: wants to retreat");
- return qtrue;
- }
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Battle_Retreat
-==================
-*/
-void AIEnter_Battle_Retreat(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "battle retreat", "", s);
- bs->ainode = AINode_Battle_Retreat;
-}
-
-/*
-==================
-AINode_Battle_Retreat
-==================
-*/
-int AINode_Battle_Retreat(bot_state_t *bs) {
- bot_goal_t goal;
- aas_entityinfo_t entinfo;
- bot_moveresult_t moveresult;
- vec3_t target, dir;
- float attack_skill, range;
- int areanum;
-
- if (BotIsObserver(bs)) {
- AIEnter_Observer(bs, "battle retreat: observer");
- return qfalse;
- }
- //if in the intermission
- if (BotIntermission(bs)) {
- AIEnter_Intermission(bs, "battle retreat: intermission");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- AIEnter_Respawn(bs, "battle retreat: bot dead");
- return qfalse;
- }
- //if no enemy
- if (bs->enemy < 0) {
- AIEnter_Seek_LTG(bs, "battle retreat: no enemy");
- return qfalse;
- }
- //
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityIsDead(&entinfo)) {
- AIEnter_Seek_LTG(bs, "battle retreat: enemy dead");
- return qfalse;
- }
- //if there is another better enemy
- if (BotFindEnemy(bs, bs->enemy)) {
-#ifdef DEBUG
- BotAI_Print(PRT_MESSAGE, "found new better enemy\n");
-#endif
- }
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- //if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- //map specific code
- BotMapScripts(bs);
- //update the attack inventory values
- BotUpdateBattleInventory(bs, bs->enemy);
- //if the bot doesn't want to retreat anymore... probably picked up some nice items
- if (BotWantsToChase(bs)) {
- //empty the goal stack, when chasing, only the enemy is the goal
- trap_BotEmptyGoalStack(bs->gs);
- //go chase the enemy
- AIEnter_Battle_Chase(bs, "battle retreat: wants to chase");
- return qfalse;
- }
- //update the last time the enemy was visible
- if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
- bs->enemyvisible_time = FloatTime();
- VectorCopy(entinfo.origin, target);
- // if not a player enemy
- if (bs->enemy >= MAX_CLIENTS) {
- // if attacking an obelisk
- if ( bs->enemy == redobelisk.entitynum ||
- bs->enemy == blueobelisk.entitynum ) {
- target[2] += 16;
- }
- }
- //update the reachability area and origin if possible
- areanum = BotPointAreaNum(target);
- if (areanum && trap_AAS_AreaReachability(areanum)) {
- VectorCopy(target, bs->lastenemyorigin);
- bs->lastenemyareanum = areanum;
- }
- }
- //if the enemy is NOT visible for 4 seconds
- if (bs->enemyvisible_time < FloatTime() - 4) {
- AIEnter_Seek_LTG(bs, "battle retreat: lost enemy");
- return qfalse;
- }
- //else if the enemy is NOT visible
- else if (bs->enemyvisible_time < FloatTime()) {
- //if there is another enemy
- if (BotFindEnemy(bs, -1)) {
- AIEnter_Battle_Fight(bs, "battle retreat: another enemy");
- return qfalse;
- }
- }
- //
- BotTeamGoals(bs, qtrue);
- //use holdable items
- BotBattleUseItems(bs);
- //get the current long term goal while retreating
- if (!BotLongTermGoal(bs, bs->tfl, qtrue, &goal)) {
- AIEnter_Battle_SuicidalFight(bs, "battle retreat: no way out");
- return qfalse;
- }
- //check for nearby goals periodicly
- if (bs->check_time < FloatTime()) {
- bs->check_time = FloatTime() + 1;
- range = 150;
-#ifdef CTF
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- //if carrying a flag the bot shouldn't be distracted too much
- if (BotCTFCarryingFlag(bs))
- range = 50;
- }
-#endif //CTF
- else if (gametype == GT_1FCTF) {
- if (Bot1FCTFCarryingFlag(bs))
- range = 50;
- }
- else if (gametype == GT_HARVESTER) {
- if (BotHarvesterCarryingCubes(bs))
- range = 80;
- }
- //
- if (BotNearbyGoal(bs, bs->tfl, &goal, range)) {
- trap_BotResetLastAvoidReach(bs->ms);
- //time the bot gets to pick up the nearby goal item
- bs->nbg_time = FloatTime() + range / 100 + 1;
- AIEnter_Battle_NBG(bs, "battle retreat: nbg");
- return qfalse;
- }
- }
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
- bs->ltg_time = 0;
- }
- //
- BotAIBlocked(bs, &moveresult, qfalse);
- //choose the best weapon to fight with
- BotChooseWeapon(bs);
- //if the view is fixed for the movement
- if (moveresult.flags & (MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
- VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
- }
- else if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET)
- && !(bs->flags & BFL_IDEALVIEWSET) ) {
- attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1);
- //if the bot is skilled anough
- if (attack_skill > 0.3) {
- BotAimAtEnemy(bs);
- }
- else {
- if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- }
- else {
- vectoangles(moveresult.movedir, bs->ideal_viewangles);
- }
- bs->ideal_viewangles[2] *= 0.5;
- }
- }
- //if the weapon is used for the bot movement
- if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
- //attack the enemy if possible
- BotCheckAttack(bs);
- //
- return qtrue;
-}
-
-/*
-==================
-AIEnter_Battle_NBG
-==================
-*/
-void AIEnter_Battle_NBG(bot_state_t *bs, char *s) {
- BotRecordNodeSwitch(bs, "battle NBG", "", s);
- bs->ainode = AINode_Battle_NBG;
-}
-
-/*
-==================
-AINode_Battle_NBG
-==================
-*/
-int AINode_Battle_NBG(bot_state_t *bs) {
- int areanum;
- bot_goal_t goal;
- aas_entityinfo_t entinfo;
- bot_moveresult_t moveresult;
- float attack_skill;
- vec3_t target, dir;
-
- if (BotIsObserver(bs)) {
- AIEnter_Observer(bs, "battle nbg: observer");
- return qfalse;
- }
- //if in the intermission
- if (BotIntermission(bs)) {
- AIEnter_Intermission(bs, "battle nbg: intermission");
- return qfalse;
- }
- //respawn if dead
- if (BotIsDead(bs)) {
- AIEnter_Respawn(bs, "battle nbg: bot dead");
- return qfalse;
- }
- //if no enemy
- if (bs->enemy < 0) {
- AIEnter_Seek_NBG(bs, "battle nbg: no enemy");
- return qfalse;
- }
- //
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityIsDead(&entinfo)) {
- AIEnter_Seek_NBG(bs, "battle nbg: enemy dead");
- return qfalse;
- }
- //
- bs->tfl = TFL_DEFAULT;
- if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
- //if in lava or slime the bot should be able to get out
- if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
- //
- if (BotCanAndWantsToRocketJump(bs)) {
- bs->tfl |= TFL_ROCKETJUMP;
- }
- //map specific code
- BotMapScripts(bs);
- //update the last time the enemy was visible
- if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
- bs->enemyvisible_time = FloatTime();
- VectorCopy(entinfo.origin, target);
- // if not a player enemy
- if (bs->enemy >= MAX_CLIENTS) {
- // if attacking an obelisk
- if ( bs->enemy == redobelisk.entitynum ||
- bs->enemy == blueobelisk.entitynum ) {
- target[2] += 16;
- }
- }
- //update the reachability area and origin if possible
- areanum = BotPointAreaNum(target);
- if (areanum && trap_AAS_AreaReachability(areanum)) {
- VectorCopy(target, bs->lastenemyorigin);
- bs->lastenemyareanum = areanum;
- }
- }
- //if the bot has no goal or touches the current goal
- if (!trap_BotGetTopGoal(bs->gs, &goal)) {
- bs->nbg_time = 0;
- }
- else if (BotReachedGoal(bs, &goal)) {
- bs->nbg_time = 0;
- }
- //
- if (bs->nbg_time < FloatTime()) {
- //pop the current goal from the stack
- trap_BotPopGoal(bs->gs);
- //if the bot still has a goal
- if (trap_BotGetTopGoal(bs->gs, &goal))
- AIEnter_Battle_Retreat(bs, "battle nbg: time out");
- else
- AIEnter_Battle_Fight(bs, "battle nbg: time out");
- //
- return qfalse;
- }
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
- //if the movement failed
- if (moveresult.failure) {
- //reset the avoid reach, otherwise bot is stuck in current area
- trap_BotResetAvoidReach(bs->ms);
- //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
- bs->nbg_time = 0;
- }
- //
- BotAIBlocked(bs, &moveresult, qfalse);
- //update the attack inventory values
- BotUpdateBattleInventory(bs, bs->enemy);
- //choose the best weapon to fight with
- BotChooseWeapon(bs);
- //if the view is fixed for the movement
- if (moveresult.flags & (MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
- VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
- }
- else if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET)
- && !(bs->flags & BFL_IDEALVIEWSET)) {
- attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1);
- //if the bot is skilled anough and the enemy is visible
- if (attack_skill > 0.3) {
- //&& BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)
- BotAimAtEnemy(bs);
- }
- else {
- if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
- VectorSubtract(target, bs->origin, dir);
- vectoangles(dir, bs->ideal_viewangles);
- }
- else {
- vectoangles(moveresult.movedir, bs->ideal_viewangles);
- }
- bs->ideal_viewangles[2] *= 0.5;
- }
- }
- //if the weapon is used for the bot movement
- if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
- //attack the enemy if possible
- BotCheckAttack(bs);
- //
- return qtrue;
-}
-
diff --git a/game/code/game/ai_dmnet.h b/game/code/game/ai_dmnet.h
deleted file mode 100644
index 05ed2ed..0000000
--- a/game/code/game/ai_dmnet.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_dmnet.h
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /source/code/botai/ai_chat.c $
- *
- *****************************************************************************/
-
-#define MAX_NODESWITCHES 50
-
-void AIEnter_Intermission(bot_state_t *bs, char *s);
-void AIEnter_Observer(bot_state_t *bs, char *s);
-void AIEnter_Respawn(bot_state_t *bs, char *s);
-void AIEnter_Stand(bot_state_t *bs, char *s);
-void AIEnter_Seek_ActivateEntity(bot_state_t *bs, char *s);
-void AIEnter_Seek_NBG(bot_state_t *bs, char *s);
-void AIEnter_Seek_LTG(bot_state_t *bs, char *s);
-void AIEnter_Seek_Camp(bot_state_t *bs, char *s);
-void AIEnter_Battle_Fight(bot_state_t *bs, char *s);
-void AIEnter_Battle_Chase(bot_state_t *bs, char *s);
-void AIEnter_Battle_Retreat(bot_state_t *bs, char *s);
-void AIEnter_Battle_NBG(bot_state_t *bs, char *s);
-int AINode_Intermission(bot_state_t *bs);
-int AINode_Observer(bot_state_t *bs);
-int AINode_Respawn(bot_state_t *bs);
-int AINode_Stand(bot_state_t *bs);
-int AINode_Seek_ActivateEntity(bot_state_t *bs);
-int AINode_Seek_NBG(bot_state_t *bs);
-int AINode_Seek_LTG(bot_state_t *bs);
-int AINode_Battle_Fight(bot_state_t *bs);
-int AINode_Battle_Chase(bot_state_t *bs);
-int AINode_Battle_Retreat(bot_state_t *bs);
-int AINode_Battle_NBG(bot_state_t *bs);
-
-void BotResetNodeSwitches(void);
-void BotDumpNodeSwitches(bot_state_t *bs);
-
diff --git a/game/code/game/ai_dmq3.c b/game/code/game/ai_dmq3.c
deleted file mode 100644
index 9037445..0000000
--- a/game/code/game/ai_dmq3.c
+++ /dev/null
@@ -1,5575 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_dmq3.c
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /MissionPack/code/game/ai_dmq3.c $
- *
- *****************************************************************************/
-
-
-#include "g_local.h"
-#include "../botlib/botlib.h"
-#include "../botlib/be_aas.h"
-#include "../botlib/be_ea.h"
-#include "../botlib/be_ai_char.h"
-#include "../botlib/be_ai_chat.h"
-#include "../botlib/be_ai_gen.h"
-#include "../botlib/be_ai_goal.h"
-#include "../botlib/be_ai_move.h"
-#include "../botlib/be_ai_weap.h"
-//
-#include "ai_main.h"
-#include "ai_dmq3.h"
-#include "ai_chat.h"
-#include "ai_cmd.h"
-#include "ai_dmnet.h"
-#include "ai_team.h"
-//
-#include "chars.h" //characteristics
-#include "inv.h" //indexes into the inventory
-#include "syn.h" //synonyms
-#include "match.h" //string matching types and vars
-
-// for the voice chats
-#include "../../ui/menudef.h" // sos001205 - for q3_ui also
-
-// from aasfile.h
-#define AREACONTENTS_MOVER 1024
-#define AREACONTENTS_MODELNUMSHIFT 24
-#define AREACONTENTS_MAXMODELNUM 0xFF
-#define AREACONTENTS_MODELNUM (AREACONTENTS_MAXMODELNUM << AREACONTENTS_MODELNUMSHIFT)
-
-#define IDEAL_ATTACKDIST 140
-
-#define MAX_WAYPOINTS 128
-
-#define MAX_EPAIRKEY 128
-//
-bot_waypoint_t botai_waypoints[MAX_WAYPOINTS];
-bot_waypoint_t *botai_freewaypoints;
-
-//NOTE: not using a cvars which can be updated because the game should be reloaded anyway
-int gametype; //game type
-int maxclients; //maximum number of clients
-
-vmCvar_t bot_grapple;
-vmCvar_t bot_rocketjump;
-vmCvar_t bot_fastchat;
-vmCvar_t bot_nochat;
-vmCvar_t bot_testrchat;
-vmCvar_t bot_challenge;
-vmCvar_t bot_predictobstacles;
-vmCvar_t g_spSkill;
-
-extern vmCvar_t bot_developer;
-
-vec3_t lastteleport_origin; //last teleport event origin
-float lastteleport_time; //last teleport event time
-int max_bspmodelindex; //maximum BSP model index
-
-//CTF flag goals
-bot_goal_t ctf_redflag;
-bot_goal_t ctf_blueflag;
-//Domination goals:
-bot_goal_t dom_points_bot[MAX_DOMINATION_POINTS];
-bot_goal_t ctf_neutralflag;
-bot_goal_t redobelisk;
-bot_goal_t blueobelisk;
-bot_goal_t neutralobelisk;
-
-#define MAX_ALTROUTEGOALS 32
-
-int altroutegoals_setup;
-aas_altroutegoal_t red_altroutegoals[MAX_ALTROUTEGOALS];
-int red_numaltroutegoals;
-aas_altroutegoal_t blue_altroutegoals[MAX_ALTROUTEGOALS];
-int blue_numaltroutegoals;
-
-/*
-==================
-untrap_BotGetLevelItemGoal
- *same as trap_BotGetLevelItemGoal, but respects the gametype flag!
-==================
- */
-int untrap_BotGetLevelItemGoal(int start, char *classname, void /* struct bot_goal_s */ *goal) {
- static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester", "elimination", "ctf", "lms", "dd", "dom"};
- char allowedGametypes[MAX_EPAIRKEY];
- char *gametypeName;
-
- start = trap_BotGetLevelItemGoal(start,classname,goal);
- while(start>-1) {
- if(!trap_AAS_ValueForBSPEpairKey(start,"gametype",allowedGametypes,MAX_EPAIRKEY))
- return start; //No gametype flag
- if( gametype >= GT_FFA && gametype < GT_MAX_GAME_TYPE ) {
- gametypeName = gametypeNames[gametype];
- if(strstr( allowedGametypes, gametypeName ))
- {
- //In gametype strig
- return start;
- }
- }
- else
- return start;
- start = trap_BotGetLevelItemGoal(start,classname,goal);
- }
- return -1;
-}
-
-/*
-==================
-BotSetUserInfo
-==================
-*/
-void BotSetUserInfo(bot_state_t *bs, char *key, char *value) {
- char userinfo[MAX_INFO_STRING];
-
- trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo));
- Info_SetValueForKey(userinfo, key, value);
- trap_SetUserinfo(bs->client, userinfo);
- ClientUserinfoChanged( bs->client );
-}
-
-/*
-==================
-BotCTFCarryingFlag
-==================
-*/
-int BotCTFCarryingFlag(bot_state_t *bs) {
- if (gametype != GT_CTF && gametype!=GT_CTF_ELIMINATION) return CTF_FLAG_NONE;
-
- if (bs->inventory[INVENTORY_REDFLAG] > 0) return CTF_FLAG_RED;
- else if (bs->inventory[INVENTORY_BLUEFLAG] > 0) return CTF_FLAG_BLUE;
- return CTF_FLAG_NONE;
-}
-
-/*
-==================
-BotTeam
-==================
-*/
-int BotTeam(bot_state_t *bs) {
- char info[1024];
-
- if (bs->client < 0 || bs->client >= MAX_CLIENTS) {
- //BotAI_Print(PRT_ERROR, "BotCTFTeam: client out of range\n");
- return qfalse;
- }
- trap_GetConfigstring(CS_PLAYERS+bs->client, info, sizeof(info));
- //
- /*if (atoi(Info_ValueForKey(info, "t")) == TEAM_RED) return TEAM_RED;
- else if (atoi(Info_ValueForKey(info, "t")) == TEAM_BLUE) return TEAM_BLUE;
- return TEAM_FREE;*/
- if (level.clients[bs->client].sess.sessionTeam == TEAM_RED) return TEAM_RED;
- else if (level.clients[bs->client].sess.sessionTeam == TEAM_BLUE) return TEAM_BLUE;
- return TEAM_FREE;
-}
-
-/*
-==================
-BotOppositeTeam
-==================
-*/
-int BotOppositeTeam(bot_state_t *bs) {
- switch(BotTeam(bs)) {
- case TEAM_RED: return TEAM_BLUE;
- case TEAM_BLUE: return TEAM_RED;
- default: return TEAM_FREE;
- }
-}
-
-/*
-==================
-BotEnemyFlag
-==================
-*/
-bot_goal_t *BotEnemyFlag(bot_state_t *bs) {
- if (BotTeam(bs) == TEAM_RED) {
- return &ctf_blueflag;
- }
- else {
- return &ctf_redflag;
- }
-}
-
-/*
-==================
-BotTeamFlag
-==================
-*/
-bot_goal_t *BotTeamFlag(bot_state_t *bs) {
- if (BotTeam(bs) == TEAM_RED) {
- return &ctf_redflag;
- }
- else {
- return &ctf_blueflag;
- }
-}
-
-
-/*
-==================
-EntityIsDead
-==================
-*/
-qboolean EntityIsDead(aas_entityinfo_t *entinfo) {
- playerState_t ps;
-
- if (entinfo->number >= 0 && entinfo->number < MAX_CLIENTS) {
- //retrieve the current client state
- BotAI_GetClientState( entinfo->number, &ps );
- if (ps.pm_type != PM_NORMAL) return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-EntityCarriesFlag
-==================
-*/
-qboolean EntityCarriesFlag(aas_entityinfo_t *entinfo) {
- if ( entinfo->powerups & ( 1 << PW_REDFLAG ) )
- return qtrue;
- if ( entinfo->powerups & ( 1 << PW_BLUEFLAG ) )
- return qtrue;
- if ( entinfo->powerups & ( 1 << PW_NEUTRALFLAG ) )
- return qtrue;
- return qfalse;
-}
-
-/*
-==================
-EntityIsInvisible
-==================
-*/
-qboolean EntityIsInvisible(aas_entityinfo_t *entinfo) {
- // the flag is always visible
- if (EntityCarriesFlag(entinfo)) {
- return qfalse;
- }
- if (entinfo->powerups & (1 << PW_INVIS)) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-EntityIsShooting
-==================
-*/
-qboolean EntityIsShooting(aas_entityinfo_t *entinfo) {
- if (entinfo->flags & EF_FIRING) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-EntityIsChatting
-==================
-*/
-qboolean EntityIsChatting(aas_entityinfo_t *entinfo) {
- if (entinfo->flags & EF_TALK) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-EntityHasQuad
-==================
-*/
-qboolean EntityHasQuad(aas_entityinfo_t *entinfo) {
- if (entinfo->powerups & (1 << PW_QUAD)) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-EntityHasKamikze
-==================
-*/
-qboolean EntityHasKamikaze(aas_entityinfo_t *entinfo) {
- if (entinfo->flags & EF_KAMIKAZE) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-EntityCarriesCubes
-==================
-*/
-qboolean EntityCarriesCubes(aas_entityinfo_t *entinfo) {
- entityState_t state;
-
- if (gametype != GT_HARVESTER)
- return qfalse;
- //FIXME: get this info from the aas_entityinfo_t ?
- BotAI_GetEntityState(entinfo->number, &state);
- if (state.generic1 > 0)
- return qtrue;
- return qfalse;
-}
-
-/*
-==================
-Bot1FCTFCarryingFlag
-==================
-*/
-int Bot1FCTFCarryingFlag(bot_state_t *bs) {
- if (gametype != GT_1FCTF) return qfalse;
-
- if (bs->inventory[INVENTORY_NEUTRALFLAG] > 0) return qtrue;
- return qfalse;
-}
-
-/*
-==================
-BotHarvesterCarryingCubes
-==================
-*/
-int BotHarvesterCarryingCubes(bot_state_t *bs) {
- if (gametype != GT_HARVESTER) return qfalse;
-
- if (bs->inventory[INVENTORY_REDCUBE] > 0) return qtrue;
- if (bs->inventory[INVENTORY_BLUECUBE] > 0) return qtrue;
- return qfalse;
-}
-//#endif
-
-/*
-==================
-BotRememberLastOrderedTask
-==================
-*/
-void BotRememberLastOrderedTask(bot_state_t *bs) {
- if (!bs->ordered) {
- return;
- }
- bs->lastgoal_decisionmaker = bs->decisionmaker;
- bs->lastgoal_ltgtype = bs->ltgtype;
- memcpy(&bs->lastgoal_teamgoal, &bs->teamgoal, sizeof(bot_goal_t));
- bs->lastgoal_teammate = bs->teammate;
-}
-
-/*
-==================
-BotSetTeamStatus
-==================
-*/
-void BotSetTeamStatus(bot_state_t *bs) {
- int teamtask;
- aas_entityinfo_t entinfo;
-
- teamtask = TEAMTASK_PATROL;
-
- switch(bs->ltgtype) {
- case LTG_TEAMHELP:
- break;
- case LTG_TEAMACCOMPANY:
- BotEntityInfo(bs->teammate, &entinfo);
- if ( ( (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION || gametype == GT_1FCTF) && EntityCarriesFlag(&entinfo))
- || ( gametype == GT_HARVESTER && EntityCarriesCubes(&entinfo)) ) {
- teamtask = TEAMTASK_ESCORT;
- }
- else {
- teamtask = TEAMTASK_FOLLOW;
- }
- break;
- case LTG_DEFENDKEYAREA:
- teamtask = TEAMTASK_DEFENSE;
- break;
- case LTG_GETFLAG:
- teamtask = TEAMTASK_OFFENSE;
- break;
- case LTG_RUSHBASE:
- teamtask = TEAMTASK_DEFENSE;
- break;
- case LTG_RETURNFLAG:
- teamtask = TEAMTASK_RETRIEVE;
- break;
- case LTG_CAMP:
- case LTG_CAMPORDER:
- teamtask = TEAMTASK_CAMP;
- break;
- case LTG_PATROL:
- teamtask = TEAMTASK_PATROL;
- break;
- case LTG_GETITEM:
- teamtask = TEAMTASK_PATROL;
- break;
- case LTG_KILL:
- teamtask = TEAMTASK_PATROL;
- break;
- case LTG_HARVEST:
- teamtask = TEAMTASK_OFFENSE;
- break;
- case LTG_ATTACKENEMYBASE:
- teamtask = TEAMTASK_OFFENSE;
- break;
- case LTG_POINTA:
- if(BotTeam(bs) == TEAM_BLUE)
- teamtask = TEAMTASK_OFFENSE;
- else
- teamtask = TEAMTASK_DEFENSE;
- case LTG_POINTB:
- if(BotTeam(bs) == TEAM_RED)
- teamtask = TEAMTASK_OFFENSE;
- else
- teamtask = TEAMTASK_DEFENSE;
- default:
- teamtask = TEAMTASK_PATROL;
- break;
- }
- BotSetUserInfo(bs, "teamtask", va("%d", teamtask));
-}
-
-/*
-==================
-BotSetLastOrderedTask
-==================
-*/
-int BotSetLastOrderedTask(bot_state_t *bs) {
-
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- // don't go back to returning the flag if it's at the base
- if ( bs->lastgoal_ltgtype == LTG_RETURNFLAG ) {
- if ( BotTeam(bs) == TEAM_RED ) {
- if ( bs->redflagstatus == 0 ) {
- bs->lastgoal_ltgtype = 0;
- }
- }
- else {
- if ( bs->blueflagstatus == 0 ) {
- bs->lastgoal_ltgtype = 0;
- }
- }
- }
- }
-
- if ( bs->lastgoal_ltgtype ) {
- bs->decisionmaker = bs->lastgoal_decisionmaker;
- bs->ordered = qtrue;
- bs->ltgtype = bs->lastgoal_ltgtype;
- memcpy(&bs->teamgoal, &bs->lastgoal_teamgoal, sizeof(bot_goal_t));
- bs->teammate = bs->lastgoal_teammate;
- bs->teamgoal_time = FloatTime() + 300;
- BotSetTeamStatus(bs);
- //
- if ( gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- if ( bs->ltgtype == LTG_GETFLAG ) {
- bot_goal_t *tb, *eb;
- int tt, et;
-
- tb = BotTeamFlag(bs);
- eb = BotEnemyFlag(bs);
- tt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, tb->areanum, TFL_DEFAULT);
- et = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, eb->areanum, TFL_DEFAULT);
- // if the travel time towards the enemy base is larger than towards our base
- if (et > tt) {
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- }
- }
- }
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-BotRefuseOrder
-==================
-*/
-void BotRefuseOrder(bot_state_t *bs) {
- if (!bs->ordered)
- return;
- // if the bot was ordered to do something
- if ( bs->order_time && bs->order_time > FloatTime() - 10 ) {
- trap_EA_Action(bs->client, ACTION_NEGATIVE);
- BotVoiceChat(bs, bs->decisionmaker, VOICECHAT_NO);
- bs->order_time = 0;
- }
-}
-
-/*
-==================
-BotCTFSeekGoals
-==================
-*/
-void BotCTFSeekGoals(bot_state_t *bs) {
- float rnd, l1, l2;
- int flagstatus, c;
- vec3_t dir;
- aas_entityinfo_t entinfo;
-
- //when carrying a flag in ctf the bot should rush to the base
- if (BotCTFCarryingFlag(bs)) {
- //if not already rushing to the base
- if (bs->ltgtype != LTG_RUSHBASE) {
- BotRefuseOrder(bs);
- bs->ltgtype = LTG_RUSHBASE;
- bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
- bs->rushbaseaway_time = 0;
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- switch(BotTeam(bs)) {
- case TEAM_RED: VectorSubtract(bs->origin, ctf_blueflag.origin, dir); break;
- case TEAM_BLUE: VectorSubtract(bs->origin, ctf_redflag.origin, dir); break;
- default: VectorSet(dir, 999, 999, 999); break;
- }
- // if the bot picked up the flag very close to the enemy base
- if ( VectorLength(dir) < 128 ) {
- // get an alternative route goal through the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- } else {
- // don't use any alt route goal, just get the hell out of the base
- bs->altroutegoal.areanum = 0;
- }
- BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_OFFENSE));
- BotVoiceChat(bs, -1, VOICECHAT_IHAVEFLAG);
- }
- else if (bs->rushbaseaway_time > FloatTime()) {
- if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus;
- else flagstatus = bs->blueflagstatus;
- //if the flag is back
- if (flagstatus == 0) {
- bs->rushbaseaway_time = 0;
- }
- }
- return;
- }
- // if the bot decided to follow someone
- if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) {
- // if the team mate being accompanied no longer carries the flag
- BotEntityInfo(bs->teammate, &entinfo);
- if (!EntityCarriesFlag(&entinfo)) {
- bs->ltgtype = 0;
- }
- }
- //
- if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus;
- else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus;
- //if our team has the enemy flag and our flag is at the base
- if (flagstatus == 1) {
- //
- if (bs->owndecision_time < FloatTime()) {
- //if Not defending the base already
- if (!(bs->ltgtype == LTG_DEFENDKEYAREA &&
- (bs->teamgoal.number == ctf_redflag.number ||
- bs->teamgoal.number == ctf_blueflag.number))) {
- //if there is a visible team mate flag carrier
- c = BotTeamFlagCarrierVisible(bs);
- if (c >= 0 &&
- // and not already following the team mate flag carrier
- (bs->ltgtype != LTG_TEAMACCOMPANY || bs->teammate != c)) {
- //
- BotRefuseOrder(bs);
- //follow the flag carrier
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //the team mate
- bs->teammate = c;
- //last time the team mate was visible
- bs->teammatevisible_time = FloatTime();
- //no message
- bs->teammessage_time = 0;
- //no arrive message
- bs->arrive_time = 1;
- //
- BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
- //get the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
- bs->ltgtype = LTG_TEAMACCOMPANY;
- bs->formation_dist = 3.5 * 32; //3.5 meter
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- }
- }
- }
- return;
- }
- //if the enemy has our flag
- else if (flagstatus == 2) {
- //
- if (bs->owndecision_time < FloatTime()) {
- //if enemy flag carrier is visible
- c = BotEnemyFlagCarrierVisible(bs);
- if (c >= 0) {
- //FIXME: fight enemy flag carrier
- }
- //if not already doing something important
- if (bs->ltgtype != LTG_GETFLAG &&
- bs->ltgtype != LTG_RETURNFLAG &&
- bs->ltgtype != LTG_TEAMHELP &&
- bs->ltgtype != LTG_TEAMACCOMPANY &&
- bs->ltgtype != LTG_CAMPORDER &&
- bs->ltgtype != LTG_PATROL &&
- bs->ltgtype != LTG_GETITEM) {
-
- BotRefuseOrder(bs);
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (random() < 0.5) {
- //go for the enemy flag
- bs->ltgtype = LTG_GETFLAG;
- }
- else {
- bs->ltgtype = LTG_RETURNFLAG;
- }
- //no team message
- bs->teammessage_time = 0;
- //set the time the bot will stop getting the flag
- bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- //
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- }
- }
- return;
- }
- //if both flags Not at their bases
- else if (flagstatus == 3) {
- //
- if (bs->owndecision_time < FloatTime()) {
- // if not trying to return the flag and not following the team flag carrier
- if ( bs->ltgtype != LTG_RETURNFLAG && bs->ltgtype != LTG_TEAMACCOMPANY ) {
- //
- c = BotTeamFlagCarrierVisible(bs);
- // if there is a visible team mate flag carrier
- if (c >= 0) {
- BotRefuseOrder(bs);
- //follow the flag carrier
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //the team mate
- bs->teammate = c;
- //last time the team mate was visible
- bs->teammatevisible_time = FloatTime();
- //no message
- bs->teammessage_time = 0;
- //no arrive message
- bs->arrive_time = 1;
- //
- BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
- //get the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
- bs->ltgtype = LTG_TEAMACCOMPANY;
- bs->formation_dist = 3.5 * 32; //3.5 meter
- //
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- }
- else {
- BotRefuseOrder(bs);
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //get the enemy flag
- bs->teammessage_time = FloatTime() + 2 * random();
- //get the flag
- bs->ltgtype = LTG_RETURNFLAG;
- //set the time the bot will stop getting the flag
- bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME;
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- //
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- }
- }
- }
- return;
- }
- // don't just do something wait for the bot team leader to give orders
- if (BotTeamLeader(bs)) {
- return;
- }
- // if the bot is ordered to do something
- if ( bs->lastgoal_ltgtype ) {
- bs->teamgoal_time += 60;
- }
- // if the bot decided to do something on it's own and has a last ordered goal
- if ( !bs->ordered && bs->lastgoal_ltgtype ) {
- bs->ltgtype = 0;
- }
- //if already a CTF or team goal
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_DEFENDKEYAREA ||
- bs->ltgtype == LTG_GETFLAG ||
- bs->ltgtype == LTG_RUSHBASE ||
- bs->ltgtype == LTG_RETURNFLAG ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL ||
- bs->ltgtype == LTG_GETITEM ||
- bs->ltgtype == LTG_MAKELOVE_UNDER ||
- bs->ltgtype == LTG_MAKELOVE_ONTOP) {
- return;
- }
- //
- if (BotSetLastOrderedTask(bs))
- return;
- //
- if (bs->owndecision_time > FloatTime())
- return;;
- //if the bot is roaming
- if (bs->ctfroam_time > FloatTime())
- return;
- //if the bot has anough aggression to decide what to do
- if (BotAggression(bs) < 50)
- return;
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //
- if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
- if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
- l1 = 0.7f;
- }
- else {
- l1 = 0.2f;
- }
- l2 = 0.9f;
- }
- else {
- l1 = 0.4f;
- l2 = 0.7f;
- }
- //get the flag or defend the base
- rnd = random();
- if (rnd < l1 && ctf_redflag.areanum && ctf_blueflag.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- bs->ltgtype = LTG_GETFLAG;
- //set the time the bot will stop getting the flag
- bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- BotSetTeamStatus(bs);
- }
- else if (rnd < l2 && ctf_redflag.areanum && ctf_blueflag.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_DEFENDKEYAREA;
- //set the time the bot stops defending the base
- bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
- bs->defendaway_time = 0;
- BotSetTeamStatus(bs);
- }
- else {
- bs->ltgtype = 0;
- //set the time the bot will stop roaming
- bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
- BotSetTeamStatus(bs);
- }
- bs->owndecision_time = FloatTime() + 5;
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-BotCTFRetreatGoals
-==================
-*/
-void BotCTFRetreatGoals(bot_state_t *bs) {
- //when carrying a flag in ctf the bot should rush to the base
- if (BotCTFCarryingFlag(bs)) {
- //if not already rushing to the base
- if (bs->ltgtype != LTG_RUSHBASE) {
- BotRefuseOrder(bs);
- bs->ltgtype = LTG_RUSHBASE;
- bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
- bs->rushbaseaway_time = 0;
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- BotSetTeamStatus(bs);
- }
- }
-}
-
-/*
-==================
-BotDomSeekGoals
-==================
- */
-
-/*void BotDomSeekGoals(bot_state_t *bs) {
- int index;
- bs->ltgtype = LTG_DOMHOLD; //For debugging we are forcing roam
-
- index=0;
- //dom_points_bot[i]
-
- if(bs->ltgtype == LTG_DOMHOLD) {
- //index = 0;
- index = ((rand()) % (level.domination_points_count));
- }
-
- //if(bs->ltgtype == LTG_DOMROAM) {
-
- //}
-
- memcpy(&bs->teamgoal, &dom_points_bot[index], sizeof(bot_goal_t));
-
- BotAlternateRoute(bs, &bs->teamgoal);
-
- BotSetTeamStatus(bs);
-}*/
-
-/*
-==================
-BotDDSeekGoals
-==================
-*/
-
-void BotDDSeekGoals(bot_state_t *bs) {
-
- /*if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL ||
- bs->ltgtype == LTG_GETITEM) {
- return;
- }*/
-
- if(bs->ltgtype == LTG_POINTA)
- memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
- if(bs->ltgtype == LTG_POINTB)
- memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
-
- if(bs->ltgtype == LTG_POINTA || bs->ltgtype == LTG_POINTB)
- return;
-
- if(rand()%2==0)
- bs->ltgtype = LTG_POINTA;
- else
- bs->ltgtype = LTG_POINTB;
-
- if(bs->ltgtype == LTG_POINTA) {
- memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
- if(BotTeam(bs) == TEAM_BLUE)
- BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_OFFENSE));
- else
- BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_DEFENSE));
- } else
- if(bs->ltgtype == LTG_POINTB) {
- memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
- if(BotTeam(bs) == TEAM_RED)
- BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_OFFENSE));
- else
- BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_DEFENSE));
- }
-
-
-}
-
-/*
-==================
-Bot1FCTFSeekGoals
-==================
-*/
-void Bot1FCTFSeekGoals(bot_state_t *bs) {
- aas_entityinfo_t entinfo;
- float rnd, l1, l2;
- int c;
-
- //when carrying a flag in ctf the bot should rush to the base
- if (Bot1FCTFCarryingFlag(bs)) {
- //if not already rushing to the base
- if (bs->ltgtype != LTG_RUSHBASE) {
- BotRefuseOrder(bs);
- bs->ltgtype = LTG_RUSHBASE;
- bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
- bs->rushbaseaway_time = 0;
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- //
- BotSetTeamStatus(bs);
- BotVoiceChat(bs, -1, VOICECHAT_IHAVEFLAG);
- }
- return;
- }
- // if the bot decided to follow someone
- if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) {
- // if the team mate being accompanied no longer carries the flag
- BotEntityInfo(bs->teammate, &entinfo);
- if (!EntityCarriesFlag(&entinfo)) {
- bs->ltgtype = 0;
- }
- }
- //our team has the flag
- if (bs->neutralflagstatus == 1) {
- if (bs->owndecision_time < FloatTime()) {
- // if not already following someone
- if (bs->ltgtype != LTG_TEAMACCOMPANY) {
- //if there is a visible team mate flag carrier
- c = BotTeamFlagCarrierVisible(bs);
- if (c >= 0) {
- BotRefuseOrder(bs);
- //follow the flag carrier
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //the team mate
- bs->teammate = c;
- //last time the team mate was visible
- bs->teammatevisible_time = FloatTime();
- //no message
- bs->teammessage_time = 0;
- //no arrive message
- bs->arrive_time = 1;
- //
- BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
- //get the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
- bs->ltgtype = LTG_TEAMACCOMPANY;
- bs->formation_dist = 3.5 * 32; //3.5 meter
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- return;
- }
- }
- //if already a CTF or team goal
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_DEFENDKEYAREA ||
- bs->ltgtype == LTG_GETFLAG ||
- bs->ltgtype == LTG_RUSHBASE ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL ||
- bs->ltgtype == LTG_ATTACKENEMYBASE ||
- bs->ltgtype == LTG_GETITEM ||
- bs->ltgtype == LTG_MAKELOVE_UNDER ||
- bs->ltgtype == LTG_MAKELOVE_ONTOP) {
- return;
- }
- //if not already attacking the enemy base
- if (bs->ltgtype != LTG_ATTACKENEMYBASE) {
- BotRefuseOrder(bs);
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_ATTACKENEMYBASE;
- //set the time the bot will stop getting the flag
- bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- }
- }
- return;
- }
- //enemy team has the flag
- else if (bs->neutralflagstatus == 2) {
- if (bs->owndecision_time < FloatTime()) {
- c = BotEnemyFlagCarrierVisible(bs);
- if (c >= 0) {
- //FIXME: attack enemy flag carrier
- }
- //if already a CTF or team goal
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL ||
- bs->ltgtype == LTG_GETITEM) {
- return;
- }
- // if not already defending the base
- if (bs->ltgtype != LTG_DEFENDKEYAREA) {
- BotRefuseOrder(bs);
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_DEFENDKEYAREA;
- //set the time the bot stops defending the base
- bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
- bs->defendaway_time = 0;
- BotSetTeamStatus(bs);
- bs->owndecision_time = FloatTime() + 5;
- }
- }
- return;
- }
- // don't just do something wait for the bot team leader to give orders
- if (BotTeamLeader(bs)) {
- return;
- }
- // if the bot is ordered to do something
- if ( bs->lastgoal_ltgtype ) {
- bs->teamgoal_time += 60;
- }
- // if the bot decided to do something on it's own and has a last ordered goal
- if ( !bs->ordered && bs->lastgoal_ltgtype ) {
- bs->ltgtype = 0;
- }
- //if already a CTF or team goal
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_DEFENDKEYAREA ||
- bs->ltgtype == LTG_GETFLAG ||
- bs->ltgtype == LTG_RUSHBASE ||
- bs->ltgtype == LTG_RETURNFLAG ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL ||
- bs->ltgtype == LTG_ATTACKENEMYBASE ||
- bs->ltgtype == LTG_GETITEM ||
- bs->ltgtype == LTG_MAKELOVE_UNDER ||
- bs->ltgtype == LTG_MAKELOVE_ONTOP) {
- return;
- }
- //
- if (BotSetLastOrderedTask(bs))
- return;
- //
- if (bs->owndecision_time > FloatTime())
- return;;
- //if the bot is roaming
- if (bs->ctfroam_time > FloatTime())
- return;
- //if the bot has anough aggression to decide what to do
- if (BotAggression(bs) < 50)
- return;
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //
- if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
- if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
- l1 = 0.7f;
- }
- else {
- l1 = 0.2f;
- }
- l2 = 0.9f;
- }
- else {
- l1 = 0.4f;
- l2 = 0.7f;
- }
- //get the flag or defend the base
- rnd = random();
- if (rnd < l1 && ctf_neutralflag.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- bs->ltgtype = LTG_GETFLAG;
- //set the time the bot will stop getting the flag
- bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
- BotSetTeamStatus(bs);
- }
- else if (rnd < l2 && ctf_redflag.areanum && ctf_blueflag.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_DEFENDKEYAREA;
- //set the time the bot stops defending the base
- bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
- bs->defendaway_time = 0;
- BotSetTeamStatus(bs);
- }
- else {
- bs->ltgtype = 0;
- //set the time the bot will stop roaming
- bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
- BotSetTeamStatus(bs);
- }
- bs->owndecision_time = FloatTime() + 5;
-#ifdef DEBUG
- BotPrintTeamGoal(bs);
-#endif //DEBUG
-}
-
-/*
-==================
-Bot1FCTFRetreatGoals
-==================
-*/
-void Bot1FCTFRetreatGoals(bot_state_t *bs) {
- //when carrying a flag in ctf the bot should rush to the enemy base
- if (Bot1FCTFCarryingFlag(bs)) {
- //if not already rushing to the base
- if (bs->ltgtype != LTG_RUSHBASE) {
- BotRefuseOrder(bs);
- bs->ltgtype = LTG_RUSHBASE;
- bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
- bs->rushbaseaway_time = 0;
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- BotSetTeamStatus(bs);
- }
- }
-}
-
-/*
-==================
-BotObeliskSeekGoals
-==================
-*/
-void BotObeliskSeekGoals(bot_state_t *bs) {
- float rnd, l1, l2;
-
- // don't just do something wait for the bot team leader to give orders
- if (BotTeamLeader(bs)) {
- return;
- }
- // if the bot is ordered to do something
- if ( bs->lastgoal_ltgtype ) {
- bs->teamgoal_time += 60;
- }
- //if already a team goal
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_DEFENDKEYAREA ||
- bs->ltgtype == LTG_GETFLAG ||
- bs->ltgtype == LTG_RUSHBASE ||
- bs->ltgtype == LTG_RETURNFLAG ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL ||
- bs->ltgtype == LTG_ATTACKENEMYBASE ||
- bs->ltgtype == LTG_GETITEM ||
- bs->ltgtype == LTG_MAKELOVE_UNDER ||
- bs->ltgtype == LTG_MAKELOVE_ONTOP) {
- return;
- }
- //
- if (BotSetLastOrderedTask(bs))
- return;
- //if the bot is roaming
- if (bs->ctfroam_time > FloatTime())
- return;
- //if the bot has anough aggression to decide what to do
- if (BotAggression(bs) < 50)
- return;
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //
- if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
- if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
- l1 = 0.7f;
- }
- else {
- l1 = 0.2f;
- }
- l2 = 0.9f;
- }
- else {
- l1 = 0.4f;
- l2 = 0.7f;
- }
- //get the flag or defend the base
- rnd = random();
- if (rnd < l1 && redobelisk.areanum && blueobelisk.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_ATTACKENEMYBASE;
- //set the time the bot will stop attacking the enemy base
- bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
- //get an alternate route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- BotSetTeamStatus(bs);
- }
- else if (rnd < l2 && redobelisk.areanum && blueobelisk.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_DEFENDKEYAREA;
- //set the time the bot stops defending the base
- bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
- bs->defendaway_time = 0;
- BotSetTeamStatus(bs);
- }
- else {
- bs->ltgtype = 0;
- //set the time the bot will stop roaming
- bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
- BotSetTeamStatus(bs);
- }
-}
-
-/*
-==================
-BotGoHarvest
-==================
-*/
-void BotGoHarvest(bot_state_t *bs) {
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_HARVEST;
- //set the time the bot will stop harvesting
- bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME;
- bs->harvestaway_time = 0;
- BotSetTeamStatus(bs);
-}
-
-/*
-==================
-BotObeliskRetreatGoals
-==================
-*/
-void BotObeliskRetreatGoals(bot_state_t *bs) {
- //nothing special
-}
-
-/*
-==================
-BotHarvesterSeekGoals
-==================
-*/
-void BotHarvesterSeekGoals(bot_state_t *bs) {
- aas_entityinfo_t entinfo;
- float rnd, l1, l2;
- int c;
-
- //when carrying cubes in harvester the bot should rush to the base
- if (BotHarvesterCarryingCubes(bs)) {
- //if not already rushing to the base
- if (bs->ltgtype != LTG_RUSHBASE) {
- BotRefuseOrder(bs);
- bs->ltgtype = LTG_RUSHBASE;
- bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
- bs->rushbaseaway_time = 0;
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //get an alternative route goal towards the enemy base
- BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
- //
- BotSetTeamStatus(bs);
- }
- return;
- }
- // don't just do something wait for the bot team leader to give orders
- if (BotTeamLeader(bs)) {
- return;
- }
- // if the bot decided to follow someone
- if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) {
- // if the team mate being accompanied no longer carries the flag
- BotEntityInfo(bs->teammate, &entinfo);
- if (!EntityCarriesCubes(&entinfo)) {
- bs->ltgtype = 0;
- }
- }
- // if the bot is ordered to do something
- if ( bs->lastgoal_ltgtype ) {
- bs->teamgoal_time += 60;
- }
- //if not yet doing something
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_DEFENDKEYAREA ||
- bs->ltgtype == LTG_GETFLAG ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL ||
- bs->ltgtype == LTG_ATTACKENEMYBASE ||
- bs->ltgtype == LTG_HARVEST ||
- bs->ltgtype == LTG_GETITEM ||
- bs->ltgtype == LTG_MAKELOVE_UNDER ||
- bs->ltgtype == LTG_MAKELOVE_ONTOP) {
- return;
- }
- //
- if (BotSetLastOrderedTask(bs))
- return;
- //if the bot is roaming
- if (bs->ctfroam_time > FloatTime())
- return;
- //if the bot has anough aggression to decide what to do
- if (BotAggression(bs) < 50)
- return;
- //set the time to send a message to the team mates
- bs->teammessage_time = FloatTime() + 2 * random();
- //
- c = BotEnemyCubeCarrierVisible(bs);
- if (c >= 0) {
- //FIXME: attack enemy cube carrier
- }
- if (bs->ltgtype != LTG_TEAMACCOMPANY) {
- //if there is a visible team mate carrying cubes
- c = BotTeamCubeCarrierVisible(bs);
- if (c >= 0) {
- //follow the team mate carrying cubes
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //the team mate
- bs->teammate = c;
- //last time the team mate was visible
- bs->teammatevisible_time = FloatTime();
- //no message
- bs->teammessage_time = 0;
- //no arrive message
- bs->arrive_time = 1;
- //
- BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
- //get the team goal time
- bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
- bs->ltgtype = LTG_TEAMACCOMPANY;
- bs->formation_dist = 3.5 * 32; //3.5 meter
- BotSetTeamStatus(bs);
- return;
- }
- }
- //
- if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
- if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
- l1 = 0.7f;
- }
- else {
- l1 = 0.2f;
- }
- l2 = 0.9f;
- }
- else {
- l1 = 0.4f;
- l2 = 0.7f;
- }
- //
- rnd = random();
- if (rnd < l1 && redobelisk.areanum && blueobelisk.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- BotGoHarvest(bs);
- }
- else if (rnd < l2 && redobelisk.areanum && blueobelisk.areanum) {
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- //
- if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
- else memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
- //set the ltg type
- bs->ltgtype = LTG_DEFENDKEYAREA;
- //set the time the bot stops defending the base
- bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
- bs->defendaway_time = 0;
- BotSetTeamStatus(bs);
- }
- else {
- bs->ltgtype = 0;
- //set the time the bot will stop roaming
- bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
- BotSetTeamStatus(bs);
- }
-}
-
-/*
-==================
-BotHarvesterRetreatGoals
-==================
-*/
-void BotHarvesterRetreatGoals(bot_state_t *bs) {
- //when carrying cubes in harvester the bot should rush to the base
- if (BotHarvesterCarryingCubes(bs)) {
- //if not already rushing to the base
- if (bs->ltgtype != LTG_RUSHBASE) {
- BotRefuseOrder(bs);
- bs->ltgtype = LTG_RUSHBASE;
- bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
- bs->rushbaseaway_time = 0;
- bs->decisionmaker = bs->client;
- bs->ordered = qfalse;
- BotSetTeamStatus(bs);
- }
- return;
- }
-}
-//#endif
-
-/*
-==================
-BotTeamGoals
-==================
-*/
-void BotTeamGoals(bot_state_t *bs, int retreat) {
-
- if ( retreat ) {
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION ) {
- BotCTFRetreatGoals(bs);
- }
- else if (gametype == GT_1FCTF) {
- Bot1FCTFRetreatGoals(bs);
- }
- else if (gametype == GT_OBELISK) {
- BotObeliskRetreatGoals(bs);
- }
- else if (gametype == GT_HARVESTER) {
- BotHarvesterRetreatGoals(bs);
- }
- }
- else {
- if (gametype == GT_CTF|| gametype == GT_CTF_ELIMINATION) {
- //decide what to do in CTF mode
- BotCTFSeekGoals(bs);
- }
- else if (gametype == GT_1FCTF) {
- Bot1FCTFSeekGoals(bs);
- }
- else if (gametype == GT_OBELISK) {
- BotObeliskSeekGoals(bs);
- }
- else if (gametype == GT_HARVESTER) {
- BotHarvesterSeekGoals(bs);
- }
- }
-
- if(gametype == GT_DOUBLE_D) //Don't care about retreat
- BotDDSeekGoals(bs);
-
- //if(gametype == GT_DOMINATION) //Don't care about retreat
- // BotDomSeekGoals(bs);
-
- // reset the order time which is used to see if
- // we decided to refuse an order
- bs->order_time = 0;
-}
-
-/*
-==================
-BotPointAreaNum
-==================
-*/
-int BotPointAreaNum(vec3_t origin) {
- int areanum, numareas, areas[10];
- vec3_t end;
-
- areanum = trap_AAS_PointAreaNum(origin);
- if (areanum) return areanum;
- VectorCopy(origin, end);
- end[2] += 10;
- numareas = trap_AAS_TraceAreas(origin, end, areas, NULL, 10);
- if (numareas > 0) return areas[0];
- return 0;
-}
-
-/*
-==================
-ClientName
-==================
-*/
-char *ClientName(int client, char *name, int size) {
- char buf[MAX_INFO_STRING];
-
- if (client < 0 || client >= MAX_CLIENTS) {
- BotAI_Print(PRT_ERROR, "ClientName: client out of range\n");
- return "[client out of range]";
- }
- trap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf));
- strncpy(name, Info_ValueForKey(buf, "n"), size-1);
- name[size-1] = '\0';
- Q_CleanStr( name );
- return name;
-}
-
-/*
-==================
-ClientSkin
-==================
-*/
-char *ClientSkin(int client, char *skin, int size) {
- char buf[MAX_INFO_STRING];
-
- if (client < 0 || client >= MAX_CLIENTS) {
- BotAI_Print(PRT_ERROR, "ClientSkin: client out of range\n");
- return "[client out of range]";
- }
- trap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf));
- strncpy(skin, Info_ValueForKey(buf, "model"), size-1);
- skin[size-1] = '\0';
- return skin;
-}
-
-/*
-==================
-ClientFromName
-==================
-*/
-int ClientFromName(char *name) {
- int i;
- char buf[MAX_INFO_STRING];
- static int maxclients;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- Q_CleanStr( buf );
- if (!Q_stricmp(Info_ValueForKey(buf, "n"), name)) return i;
- }
- return -1;
-}
-
-/*
-==================
-ClientOnSameTeamFromName
-==================
-*/
-int ClientOnSameTeamFromName(bot_state_t *bs, char *name) {
- int i;
- char buf[MAX_INFO_STRING];
- static int maxclients;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (!BotSameTeam(bs, i))
- continue;
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- Q_CleanStr( buf );
- if (!Q_stricmp(Info_ValueForKey(buf, "n"), name)) return i;
- }
- return -1;
-}
-
-/*
-==================
-stristr
-==================
-*/
-char *stristr(char *str, char *charset) {
- int i;
-
- while(*str) {
- for (i = 0; charset[i] && str[i]; i++) {
- if (toupper(charset[i]) != toupper(str[i])) break;
- }
- if (!charset[i]) return str;
- str++;
- }
- return NULL;
-}
-
-/*
-==================
-EasyClientName
-==================
-*/
-char *EasyClientName(int client, char *buf, int size) {
- int i;
- char *str1, *str2, *ptr, c;
- char name[128];
-
- strcpy(name, ClientName(client, name, sizeof(name)));
- for (i = 0; name[i]; i++) name[i] &= 127;
- //remove all spaces
- for (ptr = strstr(name, " "); ptr; ptr = strstr(name, " ")) {
- memmove(ptr, ptr+1, strlen(ptr+1)+1);
- }
- //check for [x] and ]x[ clan names
- str1 = strstr(name, "[");
- str2 = strstr(name, "]");
- if (str1 && str2) {
- if (str2 > str1) memmove(str1, str2+1, strlen(str2+1)+1);
- else memmove(str2, str1+1, strlen(str1+1)+1);
- }
- //remove Mr prefix
- if ((name[0] == 'm' || name[0] == 'M') &&
- (name[1] == 'r' || name[1] == 'R')) {
- memmove(name, name+2, strlen(name+2)+1);
- }
- //only allow lower case alphabet characters
- ptr = name;
- while(*ptr) {
- c = *ptr;
- if ((c >= 'a' && c <= 'z') ||
- (c >= '0' && c <= '9') || c == '_') {
- ptr++;
- }
- else if (c >= 'A' && c <= 'Z') {
- *ptr += 'a' - 'A';
- ptr++;
- }
- else {
- memmove(ptr, ptr+1, strlen(ptr + 1)+1);
- }
- }
- strncpy(buf, name, size-1);
- buf[size-1] = '\0';
- return buf;
-}
-
-/*
-==================
-BotSynonymContext
-==================
-*/
-int BotSynonymContext(bot_state_t *bs) {
- int context;
-
- context = CONTEXT_NORMAL|CONTEXT_NEARBYITEM|CONTEXT_NAMES;
- //
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION
- || gametype == GT_1FCTF
- ) {
- if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_CTFREDTEAM;
- else context |= CONTEXT_CTFBLUETEAM;
- }
- else if (gametype == GT_OBELISK) {
- if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_OBELISKREDTEAM;
- else context |= CONTEXT_OBELISKBLUETEAM;
- }
- else if (gametype == GT_HARVESTER) {
- if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_HARVESTERREDTEAM;
- else context |= CONTEXT_HARVESTERBLUETEAM;
- }
- return context;
-}
-
-/*
-==================
-BotChooseWeapon
-==================
-*/
-void BotChooseWeapon(bot_state_t *bs) {
- int newweaponnum;
-
- if (bs->cur_ps.weaponstate == WEAPON_RAISING ||
- bs->cur_ps.weaponstate == WEAPON_DROPPING) {
- trap_EA_SelectWeapon(bs->client, bs->weaponnum);
- }
- else {
- if(g_instantgib.integer)
- newweaponnum = WP_RAILGUN;
- else if(g_rockets.integer)
- newweaponnum = WP_ROCKET_LAUNCHER;
- else
- newweaponnum = trap_BotChooseBestFightWeapon(bs->ws, bs->inventory);
- if (bs->weaponnum != newweaponnum) bs->weaponchange_time = FloatTime();
- bs->weaponnum = newweaponnum;
- //BotAI_Print(PRT_MESSAGE, "bs->weaponnum = %d\n", bs->weaponnum);
- trap_EA_SelectWeapon(bs->client, bs->weaponnum);
- }
-}
-
-/*
-==================
-BotSetupForMovement
-==================
-*/
-void BotSetupForMovement(bot_state_t *bs) {
- bot_initmove_t initmove;
-
- memset(&initmove, 0, sizeof(bot_initmove_t));
- VectorCopy(bs->cur_ps.origin, initmove.origin);
- VectorCopy(bs->cur_ps.velocity, initmove.velocity);
- VectorClear(initmove.viewoffset);
- initmove.viewoffset[2] += bs->cur_ps.viewheight;
- initmove.entitynum = bs->entitynum;
- initmove.client = bs->client;
- initmove.thinktime = bs->thinktime;
- //set the onground flag
- if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) initmove.or_moveflags |= MFL_ONGROUND;
- //set the teleported flag
- if ((bs->cur_ps.pm_flags & PMF_TIME_KNOCKBACK) && (bs->cur_ps.pm_time > 0)) {
- initmove.or_moveflags |= MFL_TELEPORTED;
- }
- //set the waterjump flag
- if ((bs->cur_ps.pm_flags & PMF_TIME_WATERJUMP) && (bs->cur_ps.pm_time > 0)) {
- initmove.or_moveflags |= MFL_WATERJUMP;
- }
- //set presence type
- if (bs->cur_ps.pm_flags & PMF_DUCKED) initmove.presencetype = PRESENCE_CROUCH;
- else initmove.presencetype = PRESENCE_NORMAL;
- //
- if (bs->walker > 0.5) initmove.or_moveflags |= MFL_WALK;
- //
- VectorCopy(bs->viewangles, initmove.viewangles);
- //
- trap_BotInitMoveState(bs->ms, &initmove);
-}
-
-/*
-==================
-BotCheckItemPickup
-==================
-*/
-void BotCheckItemPickup(bot_state_t *bs, int *oldinventory) {
- int offence, leader;
-
- if (gametype <= GT_TEAM && g_ffa_gt==0)
- return;
-
- offence = -1;
- // go into offence if picked up the kamikaze or invulnerability
- if (!oldinventory[INVENTORY_KAMIKAZE] && bs->inventory[INVENTORY_KAMIKAZE] >= 1) {
- offence = qtrue;
- }
- if (!oldinventory[INVENTORY_INVULNERABILITY] && bs->inventory[INVENTORY_INVULNERABILITY] >= 1) {
- offence = qtrue;
- }
- // if not already wearing the kamikaze or invulnerability
- if (!bs->inventory[INVENTORY_KAMIKAZE] && !bs->inventory[INVENTORY_INVULNERABILITY]) {
- if (!oldinventory[INVENTORY_SCOUT] && bs->inventory[INVENTORY_SCOUT] >= 1) {
- offence = qtrue;
- }
- if (!oldinventory[INVENTORY_GUARD] && bs->inventory[INVENTORY_GUARD] >= 1) {
- offence = qtrue;
- }
- if (!oldinventory[INVENTORY_DOUBLER] && bs->inventory[INVENTORY_DOUBLER] >= 1) {
- offence = qfalse;
- }
- if (!oldinventory[INVENTORY_AMMOREGEN] && bs->inventory[INVENTORY_AMMOREGEN] >= 1) {
- offence = qfalse;
- }
- }
-
- if (offence >= 0) {
- leader = ClientFromName(bs->teamleader);
- if (offence) {
- if (!(bs->teamtaskpreference & TEAMTP_ATTACKER)) {
- // if we have a bot team leader
- if (BotTeamLeader(bs)) {
- // tell the leader we want to be on offence
- BotVoiceChat(bs, leader, VOICECHAT_WANTONOFFENSE);
- //BotAI_BotInitialChat(bs, "wantoffence", NULL);
- //trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
- }
- else if (g_spSkill.integer <= 3) {
- if ( ( bs->ltgtype != LTG_GETFLAG ) &&
- ( bs->ltgtype != LTG_ATTACKENEMYBASE ) &&
- ( bs->ltgtype != LTG_HARVEST ) &&
- ( ( ( gametype != GT_CTF ) &&
- ( gametype != GT_CTF_ELIMINATION ) ) ||
- ( ( bs->redflagstatus == 0 ) &&
- ( bs->blueflagstatus == 0 ) ) ) &&
- ( ( gametype != GT_1FCTF ) ||
- ( bs->neutralflagstatus == 0 ) ) ) {
- // tell the leader we want to be on offence
- BotVoiceChat(bs, leader, VOICECHAT_WANTONOFFENSE);
- //BotAI_BotInitialChat(bs, "wantoffence", NULL);
- //trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
- }
- bs->teamtaskpreference |= TEAMTP_ATTACKER;
- }
- }
- bs->teamtaskpreference &= ~TEAMTP_DEFENDER;
- }
- else {
- if (!(bs->teamtaskpreference & TEAMTP_DEFENDER)) {
- // if we have a bot team leader
- if (BotTeamLeader(bs)) {
- // tell the leader we want to be on defense
- BotVoiceChat(bs, -1, VOICECHAT_WANTONDEFENSE);
- //BotAI_BotInitialChat(bs, "wantdefence", NULL);
- //trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
- }
- else if ( (g_spSkill.integer <= 3) &&
- ( bs->ltgtype != LTG_DEFENDKEYAREA ) &&
- ( ( ( gametype != GT_CTF ) &&
- ( gametype != GT_CTF_ELIMINATION ) ) ||
- ( ( bs->redflagstatus == 0 ) &&
- ( bs->blueflagstatus == 0 ) ) ) &&
- ( ( gametype != GT_1FCTF ) ||
- ( bs->neutralflagstatus == 0 ) ) ) {
-
- // tell the leader we want to be on defense
- BotVoiceChat(bs, -1, VOICECHAT_WANTONDEFENSE);
- //BotAI_BotInitialChat(bs, "wantdefence", NULL);
- //trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
- }
- bs->teamtaskpreference |= TEAMTP_DEFENDER;
- }
- bs->teamtaskpreference &= ~TEAMTP_ATTACKER;
- }
- }
-//#endif
-}
-
-/*
-==================
-BotUpdateInventory
-==================
-*/
-void BotUpdateInventory(bot_state_t *bs) {
- int oldinventory[MAX_ITEMS];
-
- memcpy(oldinventory, bs->inventory, sizeof(oldinventory));
- //armor
- bs->inventory[INVENTORY_ARMOR] = bs->cur_ps.stats[STAT_ARMOR];
- //weapons
- bs->inventory[INVENTORY_GAUNTLET] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GAUNTLET)) != 0;
- bs->inventory[INVENTORY_SHOTGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_SHOTGUN)) != 0;
- bs->inventory[INVENTORY_MACHINEGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_MACHINEGUN)) != 0;
- bs->inventory[INVENTORY_GRENADELAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRENADE_LAUNCHER)) != 0;
- bs->inventory[INVENTORY_ROCKETLAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_ROCKET_LAUNCHER)) != 0;
- bs->inventory[INVENTORY_LIGHTNING] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_LIGHTNING)) != 0;
- bs->inventory[INVENTORY_RAILGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_RAILGUN)) != 0;
- bs->inventory[INVENTORY_PLASMAGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_PLASMAGUN)) != 0;
- bs->inventory[INVENTORY_BFG10K] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_BFG)) != 0;
- bs->inventory[INVENTORY_GRAPPLINGHOOK] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRAPPLING_HOOK)) != 0;
- bs->inventory[INVENTORY_NAILGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_NAILGUN)) != 0;;
- bs->inventory[INVENTORY_PROXLAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_PROX_LAUNCHER)) != 0;;
- bs->inventory[INVENTORY_CHAINGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_CHAINGUN)) != 0;;
- //ammo
- bs->inventory[INVENTORY_SHELLS] = bs->cur_ps.ammo[WP_SHOTGUN];
- bs->inventory[INVENTORY_BULLETS] = bs->cur_ps.ammo[WP_MACHINEGUN];
- bs->inventory[INVENTORY_GRENADES] = bs->cur_ps.ammo[WP_GRENADE_LAUNCHER];
- bs->inventory[INVENTORY_CELLS] = bs->cur_ps.ammo[WP_PLASMAGUN];
- bs->inventory[INVENTORY_LIGHTNINGAMMO] = bs->cur_ps.ammo[WP_LIGHTNING];
- bs->inventory[INVENTORY_ROCKETS] = bs->cur_ps.ammo[WP_ROCKET_LAUNCHER];
- bs->inventory[INVENTORY_SLUGS] = bs->cur_ps.ammo[WP_RAILGUN];
- bs->inventory[INVENTORY_BFGAMMO] = bs->cur_ps.ammo[WP_BFG];
- bs->inventory[INVENTORY_NAILS] = bs->cur_ps.ammo[WP_NAILGUN];
- bs->inventory[INVENTORY_MINES] = bs->cur_ps.ammo[WP_PROX_LAUNCHER];
- bs->inventory[INVENTORY_BELT] = bs->cur_ps.ammo[WP_CHAINGUN];
- //powerups
- bs->inventory[INVENTORY_HEALTH] = bs->cur_ps.stats[STAT_HEALTH];
- bs->inventory[INVENTORY_TELEPORTER] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_TELEPORTER;
- bs->inventory[INVENTORY_MEDKIT] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_MEDKIT;
- bs->inventory[INVENTORY_KAMIKAZE] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_KAMIKAZE;
- bs->inventory[INVENTORY_PORTAL] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_PORTAL;
- bs->inventory[INVENTORY_INVULNERABILITY] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_INVULNERABILITY;
- bs->inventory[INVENTORY_QUAD] = bs->cur_ps.powerups[PW_QUAD] != 0;
- bs->inventory[INVENTORY_ENVIRONMENTSUIT] = bs->cur_ps.powerups[PW_BATTLESUIT] != 0;
- bs->inventory[INVENTORY_HASTE] = bs->cur_ps.powerups[PW_HASTE] != 0;
- bs->inventory[INVENTORY_INVISIBILITY] = bs->cur_ps.powerups[PW_INVIS] != 0;
- bs->inventory[INVENTORY_REGEN] = bs->cur_ps.powerups[PW_REGEN] != 0;
- bs->inventory[INVENTORY_FLIGHT] = bs->cur_ps.powerups[PW_FLIGHT] != 0;
- bs->inventory[INVENTORY_SCOUT] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_SCOUT;
- bs->inventory[INVENTORY_GUARD] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_GUARD;
- bs->inventory[INVENTORY_DOUBLER] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_DOUBLER;
- bs->inventory[INVENTORY_AMMOREGEN] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_AMMOREGEN;
- bs->inventory[INVENTORY_REDFLAG] = bs->cur_ps.powerups[PW_REDFLAG] != 0;
- bs->inventory[INVENTORY_BLUEFLAG] = bs->cur_ps.powerups[PW_BLUEFLAG] != 0;
- bs->inventory[INVENTORY_NEUTRALFLAG] = bs->cur_ps.powerups[PW_NEUTRALFLAG] != 0;
- if (BotTeam(bs) == TEAM_RED) {
- bs->inventory[INVENTORY_REDCUBE] = bs->cur_ps.generic1;
- bs->inventory[INVENTORY_BLUECUBE] = 0;
- }
- else {
- bs->inventory[INVENTORY_REDCUBE] = 0;
- bs->inventory[INVENTORY_BLUECUBE] = bs->cur_ps.generic1;
- }
- BotCheckItemPickup(bs, oldinventory);
-}
-
-/*
-==================
-BotUpdateBattleInventory
-==================
-*/
-void BotUpdateBattleInventory(bot_state_t *bs, int enemy) {
- vec3_t dir;
- aas_entityinfo_t entinfo;
-
- BotEntityInfo(enemy, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- bs->inventory[ENEMY_HEIGHT] = (int) dir[2];
- dir[2] = 0;
- bs->inventory[ENEMY_HORIZONTAL_DIST] = (int) VectorLength(dir);
- //FIXME: add num visible enemies and num visible team mates to the inventory
-}
-
-/*
-==================
-BotUseKamikaze
-==================
-*/
-#define KAMIKAZE_DIST 1024
-
-void BotUseKamikaze(bot_state_t *bs) {
- int c, teammates, enemies;
- aas_entityinfo_t entinfo;
- vec3_t dir, target;
- bot_goal_t *goal;
- bsp_trace_t trace;
-
- //if the bot has no kamikaze
- if (bs->inventory[INVENTORY_KAMIKAZE] <= 0)
- return;
- if (bs->kamikaze_time > FloatTime())
- return;
- bs->kamikaze_time = FloatTime() + 0.2;
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- //never use kamikaze if the team flag carrier is visible
- if (BotCTFCarryingFlag(bs))
- return;
- c = BotTeamFlagCarrierVisible(bs);
- if (c >= 0) {
- BotEntityInfo(c, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST))
- return;
- }
- c = BotEnemyFlagCarrierVisible(bs);
- if (c >= 0) {
- BotEntityInfo(c, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- else if (gametype == GT_1FCTF) {
- //never use kamikaze if the team flag carrier is visible
- if (Bot1FCTFCarryingFlag(bs))
- return;
- c = BotTeamFlagCarrierVisible(bs);
- if (c >= 0) {
- BotEntityInfo(c, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST))
- return;
- }
- c = BotEnemyFlagCarrierVisible(bs);
- if (c >= 0) {
- BotEntityInfo(c, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- else if (gametype == GT_OBELISK) {
- switch(BotTeam(bs)) {
- case TEAM_RED: goal = &blueobelisk; break;
- default: goal = &redobelisk; break;
- }
- //if the obelisk is visible
- VectorCopy(goal->origin, target);
- target[2] += 1;
- VectorSubtract(bs->origin, target, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST * 0.9)) {
- BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
- if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- else if (gametype == GT_HARVESTER) {
- //
- if (BotHarvesterCarryingCubes(bs))
- return;
- //never use kamikaze if a team mate carrying cubes is visible
- c = BotTeamCubeCarrierVisible(bs);
- if (c >= 0) {
- BotEntityInfo(c, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST))
- return;
- }
- c = BotEnemyCubeCarrierVisible(bs);
- if (c >= 0) {
- BotEntityInfo(c, &entinfo);
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- //
- BotVisibleTeamMatesAndEnemies(bs, &teammates, &enemies, KAMIKAZE_DIST);
- //
- if (enemies > 2 && enemies > teammates+1) {
- trap_EA_Use(bs->client);
- return;
- }
-}
-
-/*
-==================
-BotUseInvulnerability
-==================
-*/
-void BotUseInvulnerability(bot_state_t *bs) {
- int c;
- vec3_t dir, target;
- bot_goal_t *goal;
- bsp_trace_t trace;
-
- //if the bot has no invulnerability
- if (bs->inventory[INVENTORY_INVULNERABILITY] <= 0)
- return;
- if (bs->invulnerability_time > FloatTime())
- return;
- bs->invulnerability_time = FloatTime() + 0.2;
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- //never use kamikaze if the team flag carrier is visible
- if (BotCTFCarryingFlag(bs))
- return;
- c = BotEnemyFlagCarrierVisible(bs);
- if (c >= 0)
- return;
- //if near enemy flag and the flag is visible
- switch(BotTeam(bs)) {
- case TEAM_RED: goal = &ctf_blueflag; break;
- default: goal = &ctf_redflag; break;
- }
- //if the obelisk is visible
- VectorCopy(goal->origin, target);
- target[2] += 1;
- VectorSubtract(bs->origin, target, dir);
- if (VectorLengthSquared(dir) < Square(200)) {
- BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
- if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- else if (gametype == GT_1FCTF) {
- //never use kamikaze if the team flag carrier is visible
- if (Bot1FCTFCarryingFlag(bs))
- return;
- c = BotEnemyFlagCarrierVisible(bs);
- if (c >= 0)
- return;
- //if near enemy flag and the flag is visible
- switch(BotTeam(bs)) {
- case TEAM_RED: goal = &ctf_blueflag; break;
- default: goal = &ctf_redflag; break;
- }
- //if the obelisk is visible
- VectorCopy(goal->origin, target);
- target[2] += 1;
- VectorSubtract(bs->origin, target, dir);
- if (VectorLengthSquared(dir) < Square(200)) {
- BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
- if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- else if (gametype == GT_OBELISK) {
- switch(BotTeam(bs)) {
- case TEAM_RED: goal = &blueobelisk; break;
- default: goal = &redobelisk; break;
- }
- //if the obelisk is visible
- VectorCopy(goal->origin, target);
- target[2] += 1;
- VectorSubtract(bs->origin, target, dir);
- if (VectorLengthSquared(dir) < Square(300)) {
- BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
- if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
- else if (gametype == GT_HARVESTER) {
- //
- if (BotHarvesterCarryingCubes(bs))
- return;
- c = BotEnemyCubeCarrierVisible(bs);
- if (c >= 0)
- return;
- //if near enemy base and enemy base is visible
- switch(BotTeam(bs)) {
- case TEAM_RED: goal = &blueobelisk; break;
- default: goal = &redobelisk; break;
- }
- //if the obelisk is visible
- VectorCopy(goal->origin, target);
- target[2] += 1;
- VectorSubtract(bs->origin, target, dir);
- if (VectorLengthSquared(dir) < Square(200)) {
- BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
- if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
- trap_EA_Use(bs->client);
- return;
- }
- }
- }
-}
-
-/*
-==================
-BotBattleUseItems
-==================
-*/
-void BotBattleUseItems(bot_state_t *bs) {
- if (bs->inventory[INVENTORY_HEALTH] < 40) {
- if (bs->inventory[INVENTORY_TELEPORTER] > 0) {
- if (!BotCTFCarryingFlag(bs)
- && !Bot1FCTFCarryingFlag(bs)
- && !BotHarvesterCarryingCubes(bs)
- ) {
- trap_EA_Use(bs->client);
- }
- }
- }
- if (bs->inventory[INVENTORY_HEALTH] < 60) {
- if (bs->inventory[INVENTORY_MEDKIT] > 0) {
- trap_EA_Use(bs->client);
- }
- }
- BotUseKamikaze(bs);
- BotUseInvulnerability(bs);
-}
-
-/*
-==================
-BotSetTeleportTime
-==================
-*/
-void BotSetTeleportTime(bot_state_t *bs) {
- if ((bs->cur_ps.eFlags ^ bs->last_eFlags) & EF_TELEPORT_BIT) {
- bs->teleport_time = FloatTime();
- }
- bs->last_eFlags = bs->cur_ps.eFlags;
-}
-
-/*
-==================
-BotIsDead
-==================
-*/
-qboolean BotIsDead(bot_state_t *bs) {
- return (bs->cur_ps.pm_type == PM_DEAD);
-}
-
-/*
-==================
-BotIsObserver
-==================
-*/
-qboolean BotIsObserver(bot_state_t *bs) {
- char buf[MAX_INFO_STRING];
- if (bs->cur_ps.pm_type == PM_SPECTATOR) return qtrue;
- trap_GetConfigstring(CS_PLAYERS+bs->client, buf, sizeof(buf));
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) return qtrue;
- return qfalse;
-}
-
-/*
-==================
-BotIntermission
-==================
-*/
-qboolean BotIntermission(bot_state_t *bs) {
- //NOTE: we shouldn't be looking at the game code...
- if (level.intermissiontime) return qtrue;
- return (bs->cur_ps.pm_type == PM_FREEZE || bs->cur_ps.pm_type == PM_INTERMISSION);
-}
-
-/*
-==================
-BotInLavaOrSlime
-==================
-*/
-qboolean BotInLavaOrSlime(bot_state_t *bs) {
- vec3_t feet;
-
- VectorCopy(bs->origin, feet);
- feet[2] -= 23;
- return (trap_AAS_PointContents(feet) & (CONTENTS_LAVA|CONTENTS_SLIME));
-}
-
-/*
-==================
-BotCreateWayPoint
-==================
-*/
-bot_waypoint_t *BotCreateWayPoint(char *name, vec3_t origin, int areanum) {
- bot_waypoint_t *wp;
- vec3_t waypointmins = {-8, -8, -8}, waypointmaxs = {8, 8, 8};
-
- wp = botai_freewaypoints;
- if ( !wp ) {
- BotAI_Print( PRT_WARNING, "BotCreateWayPoint: Out of waypoints\n" );
- return NULL;
- }
- botai_freewaypoints = botai_freewaypoints->next;
-
- Q_strncpyz( wp->name, name, sizeof(wp->name) );
- VectorCopy(origin, wp->goal.origin);
- VectorCopy(waypointmins, wp->goal.mins);
- VectorCopy(waypointmaxs, wp->goal.maxs);
- wp->goal.areanum = areanum;
- wp->next = NULL;
- wp->prev = NULL;
- return wp;
-}
-
-/*
-==================
-BotFindWayPoint
-==================
-*/
-bot_waypoint_t *BotFindWayPoint(bot_waypoint_t *waypoints, char *name) {
- bot_waypoint_t *wp;
-
- for (wp = waypoints; wp; wp = wp->next) {
- if (!Q_stricmp(wp->name, name)) return wp;
- }
- return NULL;
-}
-
-/*
-==================
-BotFreeWaypoints
-==================
-*/
-void BotFreeWaypoints(bot_waypoint_t *wp) {
- bot_waypoint_t *nextwp;
-
- for (; wp; wp = nextwp) {
- nextwp = wp->next;
- wp->next = botai_freewaypoints;
- botai_freewaypoints = wp;
- }
-}
-
-/*
-==================
-BotInitWaypoints
-==================
-*/
-void BotInitWaypoints(void) {
- int i;
-
- botai_freewaypoints = NULL;
- for (i = 0; i < MAX_WAYPOINTS; i++) {
- botai_waypoints[i].next = botai_freewaypoints;
- botai_freewaypoints = &botai_waypoints[i];
- }
-}
-
-/*
-==================
-TeamPlayIsOn
-==================
-*/
-int TeamPlayIsOn(void) {
- return ( gametype >= GT_TEAM && g_ffa_gt!=1);
-}
-
-/*
-==================
-BotAggression
-==================
-*/
-float BotAggression(bot_state_t *bs) {
- //if the bot has quad
- if (bs->inventory[INVENTORY_QUAD]) {
- //if the bot is not holding the gauntlet or the enemy is really nearby
- if (bs->weaponnum != WP_GAUNTLET ||
- bs->inventory[ENEMY_HORIZONTAL_DIST] < 80) {
- return 70;
- }
- }
- //if the enemy is located way higher than the bot
- if (bs->inventory[ENEMY_HEIGHT] > 200) return 0;
- //if the bot is very low on health
- if (bs->inventory[INVENTORY_HEALTH] < 60) return 0;
- //if the bot is low on health
- if (bs->inventory[INVENTORY_HEALTH] < 80) {
- //if the bot has insufficient armor
- if (bs->inventory[INVENTORY_ARMOR] < 40) return 0;
- }
- //if the bot can use the bfg
- if (bs->inventory[INVENTORY_BFG10K] > 0 &&
- bs->inventory[INVENTORY_BFGAMMO] > 7) return 100;
- //if the bot can use the railgun
- if (bs->inventory[INVENTORY_RAILGUN] > 0 &&
- bs->inventory[INVENTORY_SLUGS] > 5) return 95;
- //if the bot can use the lightning gun
- if (bs->inventory[INVENTORY_LIGHTNING] > 0 &&
- bs->inventory[INVENTORY_LIGHTNINGAMMO] > 50) return 90;
- //if the bot can use the rocketlauncher
- if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 &&
- bs->inventory[INVENTORY_ROCKETS] > 5) return 90;
- //if the bot can use the plasmagun
- if (bs->inventory[INVENTORY_PLASMAGUN] > 0 &&
- bs->inventory[INVENTORY_CELLS] > 40) return 85;
- //if the bot can use the grenade launcher
- if (bs->inventory[INVENTORY_GRENADELAUNCHER] > 0 &&
- bs->inventory[INVENTORY_GRENADES] > 10) return 80;
- //if the bot can use the shotgun
- if (bs->inventory[INVENTORY_SHOTGUN] > 0 &&
- bs->inventory[INVENTORY_SHELLS] > 10) return 50;
- //otherwise the bot is not feeling too good
- return 0;
-}
-
-/*
-==================
-BotFeelingBad
-==================
-*/
-float BotFeelingBad(bot_state_t *bs) {
- if (bs->weaponnum == WP_GAUNTLET) {
- return 100;
- }
- if (bs->inventory[INVENTORY_HEALTH] < 40) {
- return 100;
- }
- if (bs->weaponnum == WP_MACHINEGUN) {
- return 90;
- }
- if (bs->inventory[INVENTORY_HEALTH] < 60) {
- return 80;
- }
- return 0;
-}
-
-/*
-==================
-BotWantsToRetreat
-==================
-*/
-int BotWantsToRetreat(bot_state_t *bs) {
- aas_entityinfo_t entinfo;
-
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- //always retreat when carrying a CTF flag
- if (BotCTFCarryingFlag(bs))
- return qtrue;
- }
- else if (gametype == GT_1FCTF) {
- //if carrying the flag then always retreat
- if (Bot1FCTFCarryingFlag(bs))
- return qtrue;
- }
- else if (gametype == GT_OBELISK) {
- //the bots should be dedicated to attacking the enemy obelisk
- if (bs->ltgtype == LTG_ATTACKENEMYBASE) {
- if (bs->enemy != redobelisk.entitynum ||
- bs->enemy != blueobelisk.entitynum) {
- return qtrue;
- }
- }
- if (BotFeelingBad(bs) > 50) {
- return qtrue;
- }
- return qfalse;
- }
- else if (gametype == GT_HARVESTER) {
- //if carrying cubes then always retreat
- if (BotHarvesterCarryingCubes(bs)) return qtrue;
- }
- //
- if (bs->enemy >= 0) {
- //if the enemy is carrying a flag
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityCarriesFlag(&entinfo))
- return qfalse;
- }
- //if the bot is getting the flag
- if (bs->ltgtype == LTG_GETFLAG)
- return qtrue;
- //
- if (BotAggression(bs) < 50)
- return qtrue;
- return qfalse;
-}
-
-/*
-==================
-BotWantsToChase
-==================
-*/
-int BotWantsToChase(bot_state_t *bs) {
- aas_entityinfo_t entinfo;
-
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- //never chase when carrying a CTF flag
- if (BotCTFCarryingFlag(bs))
- return qfalse;
- //always chase if the enemy is carrying a flag
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityCarriesFlag(&entinfo))
- return qtrue;
- }
- else if (gametype == GT_1FCTF) {
- //never chase if carrying the flag
- if (Bot1FCTFCarryingFlag(bs))
- return qfalse;
- //always chase if the enemy is carrying a flag
- BotEntityInfo(bs->enemy, &entinfo);
- if (EntityCarriesFlag(&entinfo))
- return qtrue;
- }
- else if (gametype == GT_OBELISK) {
- //the bots should be dedicated to attacking the enemy obelisk
- if (bs->ltgtype == LTG_ATTACKENEMYBASE) {
- if (bs->enemy != redobelisk.entitynum ||
- bs->enemy != blueobelisk.entitynum) {
- return qfalse;
- }
- }
- }
- else if (gametype == GT_HARVESTER) {
- //never chase if carrying cubes
- if (BotHarvesterCarryingCubes(bs))
- return qfalse;
- }
- //if the bot is getting the flag
- if (bs->ltgtype == LTG_GETFLAG)
- return qfalse;
- //
- if (BotAggression(bs) > 50)
- return qtrue;
- return qfalse;
-}
-
-/*
-==================
-BotWantsToHelp
-==================
-*/
-int BotWantsToHelp(bot_state_t *bs) {
- return qtrue;
-}
-
-/*
-==================
-BotCanAndWantsToRocketJump
-==================
-*/
-int BotCanAndWantsToRocketJump(bot_state_t *bs) {
- float rocketjumper;
-
- //if rocket jumping is disabled
- if (!bot_rocketjump.integer) return qfalse;
- //if no rocket launcher
- if (bs->inventory[INVENTORY_ROCKETLAUNCHER] <= 0) return qfalse;
- //if low on rockets
- if (bs->inventory[INVENTORY_ROCKETS] < 3) return qfalse;
- //Sago: Special rule - always happy to rocket jump in elimination, eCTF end LMS if
- if ( (g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION || g_gametype.integer==GT_LMS )
- && g_elimination_selfdamage.integer==0) {
- return qtrue;
- }
- //never rocket jump with the Quad
- if (bs->inventory[INVENTORY_QUAD]) return qfalse;
- //if low on health
- if (bs->inventory[INVENTORY_HEALTH] < 60) return qfalse;
- //if not full health
- if (bs->inventory[INVENTORY_HEALTH] < 90) {
- //if the bot has insufficient armor
- if (bs->inventory[INVENTORY_ARMOR] < 40) return qfalse;
- }
- rocketjumper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WEAPONJUMPING, 0, 1);
- if (rocketjumper < 0.5) return qfalse;
- return qtrue;
-}
-
-/*
-==================
-BotHasPersistantPowerupAndWeapon
-==================
-*/
-int BotHasPersistantPowerupAndWeapon(bot_state_t *bs) {
- // if the bot does not have a persistant powerup
- //Sago - FIXME - This causes problems if there are no persistant powerups
-/* if (!bs->inventory[INVENTORY_SCOUT] &&
- !bs->inventory[INVENTORY_GUARD] &&
- !bs->inventory[INVENTORY_DOUBLER] &&
- !bs->inventory[INVENTORY_AMMOREGEN] ) {
- return qfalse;
- }*/
- //if the bot is very low on health
- if (bs->inventory[INVENTORY_HEALTH] < 60) return qfalse;
- //if the bot is low on health
- if (bs->inventory[INVENTORY_HEALTH] < 80) {
- //if the bot has insufficient armor
- if (bs->inventory[INVENTORY_ARMOR] < 40) return qfalse;
- }
- //if the bot can use the bfg
- if (bs->inventory[INVENTORY_BFG10K] > 0 &&
- bs->inventory[INVENTORY_BFGAMMO] > 7) return qtrue;
- //if the bot can use the railgun
- if (bs->inventory[INVENTORY_RAILGUN] > 0 &&
- bs->inventory[INVENTORY_SLUGS] > 5) return qtrue;
- //if the bot can use the lightning gun
- if (bs->inventory[INVENTORY_LIGHTNING] > 0 &&
- bs->inventory[INVENTORY_LIGHTNINGAMMO] > 50) return qtrue;
- //if the bot can use the rocketlauncher
- if (bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 &&
- bs->inventory[INVENTORY_ROCKETS] > 5) return qtrue;
- //
- if (bs->inventory[INVENTORY_NAILGUN] > 0 &&
- bs->inventory[INVENTORY_NAILS] > 5) return qtrue;
- //
- if (bs->inventory[INVENTORY_PROXLAUNCHER] > 0 &&
- bs->inventory[INVENTORY_MINES] > 5) return qtrue;
- //
- if (bs->inventory[INVENTORY_CHAINGUN] > 0 &&
- bs->inventory[INVENTORY_BELT] > 40) return qtrue;
- //if the bot can use the plasmagun
- if (bs->inventory[INVENTORY_PLASMAGUN] > 0 &&
- bs->inventory[INVENTORY_CELLS] > 20) return qtrue;
- return qfalse;
-}
-
-/*
-==================
-BotGoCamp
-==================
-*/
-void BotGoCamp(bot_state_t *bs, bot_goal_t *goal) {
- float camper;
-
- bs->decisionmaker = bs->client;
- //set message time to zero so bot will NOT show any message
- bs->teammessage_time = 0;
- //set the ltg type
- bs->ltgtype = LTG_CAMP;
- //set the team goal
- memcpy(&bs->teamgoal, goal, sizeof(bot_goal_t));
- //get the team goal time
- camper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CAMPER, 0, 1);
- if (camper > 0.99) bs->teamgoal_time = FloatTime() + 99999;
- else bs->teamgoal_time = FloatTime() + 120 + 180 * camper + random() * 15;
- //set the last time the bot started camping
- bs->camp_time = FloatTime();
- //the teammate that requested the camping
- bs->teammate = 0;
- //do NOT type arrive message
- bs->arrive_time = 1;
-}
-
-/*
-==================
-BotWantsToCamp
-==================
-*/
-int BotWantsToCamp(bot_state_t *bs) {
- float camper;
- int cs, traveltime, besttraveltime;
- bot_goal_t goal, bestgoal;
-
- camper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CAMPER, 0, 1);
- if (camper < 0.1) return qfalse;
- //if the bot has a team goal
- if (bs->ltgtype == LTG_TEAMHELP ||
- bs->ltgtype == LTG_TEAMACCOMPANY ||
- bs->ltgtype == LTG_DEFENDKEYAREA ||
- bs->ltgtype == LTG_GETFLAG ||
- bs->ltgtype == LTG_RUSHBASE ||
- bs->ltgtype == LTG_CAMP ||
- bs->ltgtype == LTG_CAMPORDER ||
- bs->ltgtype == LTG_PATROL) {
- return qfalse;
- }
- //if camped recently
- if (bs->camp_time > FloatTime() - 60 + 300 * (1-camper)) return qfalse;
- //
- if (random() > camper) {
- bs->camp_time = FloatTime();
- return qfalse;
- }
- //if the bot isn't healthy anough
- if (BotAggression(bs) < 50) return qfalse;
- //the bot should have at least have the rocket launcher, the railgun or the bfg10k with some ammo
- if ((bs->inventory[INVENTORY_ROCKETLAUNCHER] <= 0 || bs->inventory[INVENTORY_ROCKETS < 10]) &&
- (bs->inventory[INVENTORY_RAILGUN] <= 0 || bs->inventory[INVENTORY_SLUGS] < 10) &&
- (bs->inventory[INVENTORY_BFG10K] <= 0 || bs->inventory[INVENTORY_BFGAMMO] < 10)) {
- return qfalse;
- }
- //find the closest camp spot
- besttraveltime = 99999;
- for (cs = trap_BotGetNextCampSpotGoal(0, &goal); cs; cs = trap_BotGetNextCampSpotGoal(cs, &goal)) {
- traveltime = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, goal.areanum, TFL_DEFAULT);
- if (traveltime && traveltime < besttraveltime) {
- besttraveltime = traveltime;
- memcpy(&bestgoal, &goal, sizeof(bot_goal_t));
- }
- }
- if (besttraveltime > 150) return qfalse;
- //ok found a camp spot, go camp there
- BotGoCamp(bs, &bestgoal);
- bs->ordered = qfalse;
- //
- return qtrue;
-}
-
-/*
-==================
-BotDontAvoid
-==================
-*/
-void BotDontAvoid(bot_state_t *bs, char *itemname) {
- bot_goal_t goal;
- int num;
-
- num = trap_BotGetLevelItemGoal(-1, itemname, &goal);
- while(num >= 0) {
- trap_BotRemoveFromAvoidGoals(bs->gs, goal.number);
- num = trap_BotGetLevelItemGoal(num, itemname, &goal);
- }
-}
-
-/*
-==================
-BotGoForPowerups
-==================
-*/
-void BotGoForPowerups(bot_state_t *bs) {
-
- //don't avoid any of the powerups anymore
- BotDontAvoid(bs, "Quad Damage");
- BotDontAvoid(bs, "Regeneration");
- BotDontAvoid(bs, "Battle Suit");
- BotDontAvoid(bs, "Speed");
- BotDontAvoid(bs, "Invisibility");
- //BotDontAvoid(bs, "Flight");
- //reset the long term goal time so the bot will go for the powerup
- //NOTE: the long term goal type doesn't change
- bs->ltg_time = 0;
-}
-
-/*
-==================
-BotRoamGoal
-==================
-*/
-void BotRoamGoal(bot_state_t *bs, vec3_t goal) {
- int pc, i;
- float len, rnd;
- vec3_t dir, bestorg, belowbestorg;
- bsp_trace_t trace;
-
- for (i = 0; i < 10; i++) {
- //start at the bot origin
- VectorCopy(bs->origin, bestorg);
- rnd = random();
- if (rnd > 0.25) {
- //add a random value to the x-coordinate
- if (random() < 0.5) bestorg[0] -= 800 * random() + 100;
- else bestorg[0] += 800 * random() + 100;
- }
- if (rnd < 0.75) {
- //add a random value to the y-coordinate
- if (random() < 0.5) bestorg[1] -= 800 * random() + 100;
- else bestorg[1] += 800 * random() + 100;
- }
- //add a random value to the z-coordinate (NOTE: 48 = maxjump?)
- bestorg[2] += 2 * 48 * crandom();
- //trace a line from the origin to the roam target
- BotAI_Trace(&trace, bs->origin, NULL, NULL, bestorg, bs->entitynum, MASK_SOLID);
- //direction and length towards the roam target
- VectorSubtract(trace.endpos, bs->origin, dir);
- len = VectorNormalize(dir);
- //if the roam target is far away anough
- if (len > 200) {
- //the roam target is in the given direction before walls
- VectorScale(dir, len * trace.fraction - 40, dir);
- VectorAdd(bs->origin, dir, bestorg);
- //get the coordinates of the floor below the roam target
- belowbestorg[0] = bestorg[0];
- belowbestorg[1] = bestorg[1];
- belowbestorg[2] = bestorg[2] - 800;
- BotAI_Trace(&trace, bestorg, NULL, NULL, belowbestorg, bs->entitynum, MASK_SOLID);
- //
- if (!trace.startsolid) {
- trace.endpos[2]++;
- pc = trap_PointContents(trace.endpos, bs->entitynum);
- if (!(pc & (CONTENTS_LAVA | CONTENTS_SLIME))) {
- VectorCopy(bestorg, goal);
- return;
- }
- }
- }
- }
- VectorCopy(bestorg, goal);
-}
-
-/*
-==================
-BotAttackMove
-==================
-*/
-bot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl) {
- int movetype, i, attackentity;
- float attack_skill, jumper, croucher, dist, strafechange_time;
- float attack_dist, attack_range;
- vec3_t forward, backward, sideward, hordir, up = {0, 0, 1};
- aas_entityinfo_t entinfo;
- bot_moveresult_t moveresult;
- bot_goal_t goal;
-
- attackentity = bs->enemy;
- //
- if (bs->attackchase_time > FloatTime()) {
- //create the chase goal
- goal.entitynum = attackentity;
- goal.areanum = bs->lastenemyareanum;
- VectorCopy(bs->lastenemyorigin, goal.origin);
- VectorSet(goal.mins, -8, -8, -8);
- VectorSet(goal.maxs, 8, 8, 8);
- //initialize the movement state
- BotSetupForMovement(bs);
- //move towards the goal
- trap_BotMoveToGoal(&moveresult, bs->ms, &goal, tfl);
- return moveresult;
- }
- //
- memset(&moveresult, 0, sizeof(bot_moveresult_t));
- //
- attack_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ATTACK_SKILL, 0, 1);
- jumper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_JUMPER, 0, 1);
- croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);
- //if the bot is really stupid
- if (attack_skill < 0.2) return moveresult;
- //initialize the movement state
- BotSetupForMovement(bs);
- //get the enemy entity info
- BotEntityInfo(attackentity, &entinfo);
- //direction towards the enemy
- VectorSubtract(entinfo.origin, bs->origin, forward);
- //the distance towards the enemy
- dist = VectorNormalize(forward);
- VectorNegate(forward, backward);
- //walk, crouch or jump
- movetype = MOVE_WALK;
- //
- if (bs->attackcrouch_time < FloatTime() - 1) {
- if (random() < jumper) {
- movetype = MOVE_JUMP;
- }
- //wait at least one second before crouching again
- else if (bs->attackcrouch_time < FloatTime() - 1 && random() < croucher) {
- bs->attackcrouch_time = FloatTime() + croucher * 5;
- }
- }
- if (bs->attackcrouch_time > FloatTime()) movetype = MOVE_CROUCH;
- //if the bot should jump
- if (movetype == MOVE_JUMP) {
- //if jumped last frame
- if (bs->attackjump_time > FloatTime()) {
- movetype = MOVE_WALK;
- }
- else {
- bs->attackjump_time = FloatTime() + 1;
- }
- }
- if (bs->cur_ps.weapon == WP_GAUNTLET) {
- attack_dist = 0;
- attack_range = 0;
- }
- else {
- attack_dist = IDEAL_ATTACKDIST;
- attack_range = 40;
- }
- //if the bot is stupid
- if (attack_skill <= 0.4) {
- //just walk to or away from the enemy
- if (dist > attack_dist + attack_range) {
- if (trap_BotMoveInDirection(bs->ms, forward, 400, movetype)) return moveresult;
- }
- if (dist < attack_dist - attack_range) {
- if (trap_BotMoveInDirection(bs->ms, backward, 400, movetype)) return moveresult;
- }
- return moveresult;
- }
- //increase the strafe time
- bs->attackstrafe_time += bs->thinktime;
- //get the strafe change time
- strafechange_time = 0.4 + (1 - attack_skill) * 0.2;
- if (attack_skill > 0.7) strafechange_time += crandom() * 0.2;
- //if the strafe direction should be changed
- if (bs->attackstrafe_time > strafechange_time) {
- //some magic number :)
- if (random() > 0.935) {
- //flip the strafe direction
- bs->flags ^= BFL_STRAFERIGHT;
- bs->attackstrafe_time = 0;
- }
- }
- //
- for (i = 0; i < 2; i++) {
- hordir[0] = forward[0];
- hordir[1] = forward[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //get the sideward vector
- CrossProduct(hordir, up, sideward);
- //reverse the vector depending on the strafe direction
- if (bs->flags & BFL_STRAFERIGHT) VectorNegate(sideward, sideward);
- //randomly go back a little
- if (random() > 0.9) {
- VectorAdd(sideward, backward, sideward);
- }
- else {
- //walk forward or backward to get at the ideal attack distance
- if (dist > attack_dist + attack_range) {
- VectorAdd(sideward, forward, sideward);
- }
- else if (dist < attack_dist - attack_range) {
- VectorAdd(sideward, backward, sideward);
- }
- }
- //perform the movement
- if (trap_BotMoveInDirection(bs->ms, sideward, 400, movetype))
- return moveresult;
- //movement failed, flip the strafe direction
- bs->flags ^= BFL_STRAFERIGHT;
- bs->attackstrafe_time = 0;
- }
- //bot couldn't do any usefull movement
-// bs->attackchase_time = AAS_Time() + 6;
- return moveresult;
-}
-
-/*
-==================
-BotSameTeam
-==================
-*/
-int BotSameTeam(bot_state_t *bs, int entnum) {
- if (bs->client < 0 || bs->client >= MAX_CLIENTS) {
- //BotAI_Print(PRT_ERROR, "BotSameTeam: client out of range\n");
- return qfalse;
- }
- if (entnum < 0 || entnum >= MAX_CLIENTS) {
- //BotAI_Print(PRT_ERROR, "BotSameTeam: client out of range\n");
- return qfalse;
- }
- if ( gametype >= GT_TEAM && g_ffa_gt!=1) {
- /*Sago: I don't know why they decided to check the configstring instead of the real value.
- For some reason bots sometimes gets a wrong config string when chaning gametypes.
- Now we check the real value: */
- if(level.clients[bs->client].sess.sessionTeam==level.clients[entnum].sess.sessionTeam) return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-InFieldOfVision
-==================
-*/
-qboolean InFieldOfVision(vec3_t viewangles, float fov, vec3_t angles)
-{
- int i;
- float diff, angle;
-
- for (i = 0; i < 2; i++) {
- angle = AngleMod(viewangles[i]);
- angles[i] = AngleMod(angles[i]);
- diff = angles[i] - angle;
- if (angles[i] > angle) {
- if (diff > 180.0) diff -= 360.0;
- }
- else {
- if (diff < -180.0) diff += 360.0;
- }
- if (diff > 0) {
- if (diff > fov * 0.5) return qfalse;
- }
- else {
- if (diff < -fov * 0.5) return qfalse;
- }
- }
- return qtrue;
-}
-
-/*
-==================
-BotEntityVisible
-
-returns visibility in the range [0, 1] taking fog and water surfaces into account
-==================
-*/
-float BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int ent) {
- int i, contents_mask, passent, hitent, infog, inwater, otherinfog, pc;
- float squaredfogdist, waterfactor, vis, bestvis;
- bsp_trace_t trace;
- aas_entityinfo_t entinfo;
- vec3_t dir, entangles, start, end, middle;
-
- //calculate middle of bounding box
- BotEntityInfo(ent, &entinfo);
- VectorAdd(entinfo.mins, entinfo.maxs, middle);
- VectorScale(middle, 0.5, middle);
- VectorAdd(entinfo.origin, middle, middle);
- //check if entity is within field of vision
- VectorSubtract(middle, eye, dir);
- vectoangles(dir, entangles);
- if (!InFieldOfVision(viewangles, fov, entangles)) return 0;
- //
- pc = trap_AAS_PointContents(eye);
- infog = (pc & CONTENTS_FOG);
- inwater = (pc & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER));
- //
- bestvis = 0;
- for (i = 0; i < 3; i++) {
- //if the point is not in potential visible sight
- //if (!AAS_inPVS(eye, middle)) continue;
- //
- contents_mask = CONTENTS_SOLID|CONTENTS_PLAYERCLIP;
- passent = viewer;
- hitent = ent;
- VectorCopy(eye, start);
- VectorCopy(middle, end);
- //if the entity is in water, lava or slime
- if (trap_AAS_PointContents(middle) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) {
- contents_mask |= (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER);
- }
- //if eye is in water, lava or slime
- if (inwater) {
- if (!(contents_mask & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) {
- passent = ent;
- hitent = viewer;
- VectorCopy(middle, start);
- VectorCopy(eye, end);
- }
- contents_mask ^= (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER);
- }
- //trace from start to end
- BotAI_Trace(&trace, start, NULL, NULL, end, passent, contents_mask);
- //if water was hit
- waterfactor = 1.0;
- if (trace.contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) {
- //if the water surface is translucent
- if (1) {
- //trace through the water
- contents_mask &= ~(CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER);
- BotAI_Trace(&trace, trace.endpos, NULL, NULL, end, passent, contents_mask);
- waterfactor = 0.5;
- }
- }
- //if a full trace or the hitent was hit
- if (trace.fraction >= 1 || trace.ent == hitent) {
- //check for fog, assuming there's only one fog brush where
- //either the viewer or the entity is in or both are in
- otherinfog = (trap_AAS_PointContents(middle) & CONTENTS_FOG);
- if (infog && otherinfog) {
- VectorSubtract(trace.endpos, eye, dir);
- squaredfogdist = VectorLengthSquared(dir);
- }
- else if (infog) {
- VectorCopy(trace.endpos, start);
- BotAI_Trace(&trace, start, NULL, NULL, eye, viewer, CONTENTS_FOG);
- VectorSubtract(eye, trace.endpos, dir);
- squaredfogdist = VectorLengthSquared(dir);
- }
- else if (otherinfog) {
- VectorCopy(trace.endpos, end);
- BotAI_Trace(&trace, eye, NULL, NULL, end, viewer, CONTENTS_FOG);
- VectorSubtract(end, trace.endpos, dir);
- squaredfogdist = VectorLengthSquared(dir);
- }
- else {
- //if the entity and the viewer are not in fog assume there's no fog in between
- squaredfogdist = 0;
- }
- //decrease visibility with the view distance through fog
- vis = 1 / ((squaredfogdist * 0.001) < 1 ? 1 : (squaredfogdist * 0.001));
- //if entering water visibility is reduced
- vis *= waterfactor;
- //
- if (vis > bestvis) bestvis = vis;
- //if pretty much no fog
- if (bestvis >= 0.95) return bestvis;
- }
- //check bottom and top of bounding box as well
- if (i == 0) middle[2] += entinfo.mins[2];
- else if (i == 1) middle[2] += entinfo.maxs[2] - entinfo.mins[2];
- }
- return bestvis;
-}
-
-/*
-==================
-BotFindEnemy
-==================
-*/
-int BotFindEnemy(bot_state_t *bs, int curenemy) {
- int i, healthdecrease;
- float f, alertness, easyfragger, vis;
- float squaredist, cursquaredist;
- aas_entityinfo_t entinfo, curenemyinfo;
- vec3_t dir, angles;
-
- alertness = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_ALERTNESS, 0, 1);
- easyfragger = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_EASY_FRAGGER, 0, 1);
- //check if the health decreased
- healthdecrease = bs->lasthealth > bs->inventory[INVENTORY_HEALTH];
- //remember the current health value
- bs->lasthealth = bs->inventory[INVENTORY_HEALTH];
- //
- if (curenemy >= 0) {
- BotEntityInfo(curenemy, &curenemyinfo);
- if (EntityCarriesFlag(&curenemyinfo)) return qfalse;
- VectorSubtract(curenemyinfo.origin, bs->origin, dir);
- cursquaredist = VectorLengthSquared(dir);
- }
- else {
- cursquaredist = 0;
- }
- if (gametype == GT_OBELISK) {
- vec3_t target;
- bot_goal_t *goal;
- bsp_trace_t trace;
-
- if (BotTeam(bs) == TEAM_RED)
- goal = &blueobelisk;
- else
- goal = &redobelisk;
- //if the obelisk is visible
- VectorCopy(goal->origin, target);
- target[2] += 1;
- BotAI_Trace(&trace, bs->eye, NULL, NULL, target, bs->client, CONTENTS_SOLID);
- if (trace.fraction >= 1 || trace.ent == goal->entitynum) {
- if (goal->entitynum == bs->enemy) {
- return qfalse;
- }
- bs->enemy = goal->entitynum;
- bs->enemysight_time = FloatTime();
- bs->enemysuicide = qfalse;
- bs->enemydeath_time = 0;
- bs->enemyvisible_time = FloatTime();
- return qtrue;
- }
- }
- //
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
-
- if (i == bs->client) continue;
- //if it's the current enemy
- if (i == curenemy) continue;
- //
- BotEntityInfo(i, &entinfo);
- //
- if (!entinfo.valid) continue;
- //if the enemy isn't dead and the enemy isn't the bot self
- if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;
- //if the enemy is invisible and not shooting
- if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
- continue;
- }
-//Neil Torontos unlagged
-//unlagged - misc
- // this has nothing to do with lag compensation, but it's great for testing
- if ( g_entities[i].flags & FL_NOTARGET ) continue;
-//unlagged - misc
- //if not an easy fragger don't shoot at chatting players
- if (easyfragger < 0.5 && EntityIsChatting(&entinfo)) continue;
- //
- if (lastteleport_time > FloatTime() - 3) {
- VectorSubtract(entinfo.origin, lastteleport_origin, dir);
- if (VectorLengthSquared(dir) < Square(70)) continue;
- }
- //calculate the distance towards the enemy
- VectorSubtract(entinfo.origin, bs->origin, dir);
- squaredist = VectorLengthSquared(dir);
- //if this entity is not carrying a flag
- if (!EntityCarriesFlag(&entinfo))
- {
- //if this enemy is further away than the current one
- if (curenemy >= 0 && squaredist > cursquaredist) continue;
- } //end if
- //if the bot has no
- if (squaredist > Square(900.0 + alertness * 4000.0)) continue;
- //if on the same team
- if (BotSameTeam(bs, i)) continue;
- //if the bot's health decreased or the enemy is shooting
- if (curenemy < 0 && (healthdecrease || EntityIsShooting(&entinfo)))
- f = 360;
- else
- f = 90 + 90 - (90 - (squaredist > Square(810) ? Square(810) : squaredist) / (810 * 9));
- //check if the enemy is visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, f, i);
- if (vis <= 0) continue;
- //if the enemy is quite far away, not shooting and the bot is not damaged
- if (curenemy < 0 && squaredist > Square(100) && !healthdecrease && !EntityIsShooting(&entinfo))
- {
- //check if we can avoid this enemy
- VectorSubtract(bs->origin, entinfo.origin, dir);
- vectoangles(dir, angles);
- //if the bot isn't in the fov of the enemy
- if (!InFieldOfVision(entinfo.angles, 90, angles)) {
- //update some stuff for this enemy
- BotUpdateBattleInventory(bs, i);
- //if the bot doesn't really want to fight
- if (BotWantsToRetreat(bs)) continue;
- }
- }
- //found an enemy
- bs->enemy = entinfo.number;
- if (curenemy >= 0) bs->enemysight_time = FloatTime() - 2;
- else bs->enemysight_time = FloatTime();
- bs->enemysuicide = qfalse;
- bs->enemydeath_time = 0;
- bs->enemyvisible_time = FloatTime();
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-BotTeamFlagCarrierVisible
-==================
-*/
-int BotTeamFlagCarrierVisible(bot_state_t *bs) {
- int i;
- float vis;
- aas_entityinfo_t entinfo;
-
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client)
- continue;
- //
- BotEntityInfo(i, &entinfo);
- //if this player is active
- if (!entinfo.valid)
- continue;
- //if this player is carrying a flag
- if (!EntityCarriesFlag(&entinfo))
- continue;
- //if the flag carrier is not on the same team
- if (!BotSameTeam(bs, i))
- continue;
- //if the flag carrier is not visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
- if (vis <= 0)
- continue;
- //
- return i;
- }
- return -1;
-}
-
-/*
-==================
-BotTeamFlagCarrier
-==================
-*/
-int BotTeamFlagCarrier(bot_state_t *bs) {
- int i;
- aas_entityinfo_t entinfo;
-
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client)
- continue;
- //
- BotEntityInfo(i, &entinfo);
- //if this player is active
- if (!entinfo.valid)
- continue;
- //if this player is carrying a flag
- if (!EntityCarriesFlag(&entinfo))
- continue;
- //if the flag carrier is not on the same team
- if (!BotSameTeam(bs, i))
- continue;
- //
- return i;
- }
- return -1;
-}
-
-/*
-==================
-BotEnemyFlagCarrierVisible
-==================
-*/
-int BotEnemyFlagCarrierVisible(bot_state_t *bs) {
- int i;
- float vis;
- aas_entityinfo_t entinfo;
-
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client)
- continue;
- //
- BotEntityInfo(i, &entinfo);
- //if this player is active
- if (!entinfo.valid)
- continue;
- //if this player is carrying a flag
- if (!EntityCarriesFlag(&entinfo))
- continue;
- //if the flag carrier is on the same team
- if (BotSameTeam(bs, i))
- continue;
- //if the flag carrier is not visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
- if (vis <= 0)
- continue;
- //
- return i;
- }
- return -1;
-}
-
-/*
-==================
-BotVisibleTeamMatesAndEnemies
-==================
-*/
-void BotVisibleTeamMatesAndEnemies(bot_state_t *bs, int *teammates, int *enemies, float range) {
- int i;
- float vis;
- aas_entityinfo_t entinfo;
- vec3_t dir;
-
- if (teammates)
- *teammates = 0;
- if (enemies)
- *enemies = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client)
- continue;
- //
- BotEntityInfo(i, &entinfo);
- //if this player is active
- if (!entinfo.valid)
- continue;
- //if this player is carrying a flag
- if (!EntityCarriesFlag(&entinfo))
- continue;
- //if not within range
- VectorSubtract(entinfo.origin, bs->origin, dir);
- if (VectorLengthSquared(dir) > Square(range))
- continue;
- //if the flag carrier is not visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
- if (vis <= 0)
- continue;
- //if the flag carrier is on the same team
- if (BotSameTeam(bs, i)) {
- if (teammates)
- (*teammates)++;
- }
- else {
- if (enemies)
- (*enemies)++;
- }
- }
-}
-
-/*
-==================
-BotTeamCubeCarrierVisible
-==================
-*/
-int BotTeamCubeCarrierVisible(bot_state_t *bs) {
- int i;
- float vis;
- aas_entityinfo_t entinfo;
-
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client) continue;
- //
- BotEntityInfo(i, &entinfo);
- //if this player is active
- if (!entinfo.valid) continue;
- //if this player is carrying a flag
- if (!EntityCarriesCubes(&entinfo)) continue;
- //if the flag carrier is not on the same team
- if (!BotSameTeam(bs, i)) continue;
- //if the flag carrier is not visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
- if (vis <= 0) continue;
- //
- return i;
- }
- return -1;
-}
-
-/*
-==================
-BotEnemyCubeCarrierVisible
-==================
-*/
-int BotEnemyCubeCarrierVisible(bot_state_t *bs) {
- int i;
- float vis;
- aas_entityinfo_t entinfo;
-
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- if (i == bs->client)
- continue;
- //
- BotEntityInfo(i, &entinfo);
- //if this player is active
- if (!entinfo.valid)
- continue;
- //if this player is carrying a flag
- if (!EntityCarriesCubes(&entinfo)) continue;
- //if the flag carrier is on the same team
- if (BotSameTeam(bs, i))
- continue;
- //if the flag carrier is not visible
- vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
- if (vis <= 0)
- continue;
- //
- return i;
- }
- return -1;
-}
-//#endif
-
-/*
-==================
-BotAimAtEnemy
-==================
-*/
-void BotAimAtEnemy(bot_state_t *bs) {
- int i, enemyvisible;
- float dist, f, aim_skill, aim_accuracy, speed, reactiontime;
- vec3_t dir, bestorigin, end, start, groundtarget, cmdmove, enemyvelocity;
- vec3_t mins = {-4,-4,-4}, maxs = {4, 4, 4};
- weaponinfo_t wi;
- aas_entityinfo_t entinfo;
- bot_goal_t goal;
- bsp_trace_t trace;
- vec3_t target;
-
- //if the bot has no enemy
- if (bs->enemy < 0) {
- return;
- }
- //get the enemy entity information
- BotEntityInfo(bs->enemy, &entinfo);
- //if this is not a player (should be an obelisk)
- if (bs->enemy >= MAX_CLIENTS) {
- //if the obelisk is visible
- VectorCopy(entinfo.origin, target);
- // if attacking an obelisk
- if ( bs->enemy == redobelisk.entitynum ||
- bs->enemy == blueobelisk.entitynum ) {
- target[2] += 32;
- }
- //aim at the obelisk
- VectorSubtract(target, bs->eye, dir);
- vectoangles(dir, bs->ideal_viewangles);
- //set the aim target before trying to attack
- VectorCopy(target, bs->aimtarget);
- return;
- }
- //
- //BotAI_Print(PRT_MESSAGE, "client %d: aiming at client %d\n", bs->entitynum, bs->enemy);
- //
- aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL, 0, 1);
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY, 0, 1);
- //
- if (aim_skill > 0.95) {
- //don't aim too early
- reactiontime = 0.5 * trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_REACTIONTIME, 0, 1);
- if (bs->enemysight_time > FloatTime() - reactiontime) return;
- if (bs->teleport_time > FloatTime() - reactiontime) return;
- }
-
- //get the weapon information
- trap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi);
- //get the weapon specific aim accuracy and or aim skill
- if (wi.number == WP_MACHINEGUN) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN, 0, 1);
- }
- else if (wi.number == WP_SHOTGUN) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_SHOTGUN, 0, 1);
- }
- else if (wi.number == WP_GRENADE_LAUNCHER) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_GRENADELAUNCHER, 0, 1);
- aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_GRENADELAUNCHER, 0, 1);
- }
- else if (wi.number == WP_ROCKET_LAUNCHER) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_ROCKETLAUNCHER, 0, 1);
- aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_ROCKETLAUNCHER, 0, 1);
- }
- else if (wi.number == WP_LIGHTNING) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_LIGHTNING, 0, 1);
- }
- else if (wi.number == WP_RAILGUN) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_RAILGUN, 0, 1);
- }
- else if (wi.number == WP_PLASMAGUN) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_PLASMAGUN, 0, 1);
- aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_PLASMAGUN, 0, 1);
- }
- else if (wi.number == WP_BFG) {
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY_BFG10K, 0, 1);
- aim_skill = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_SKILL_BFG10K, 0, 1);
- }
- //
- if (aim_accuracy <= 0) aim_accuracy = 0.0001f;
- //get the enemy entity information
- BotEntityInfo(bs->enemy, &entinfo);
- //if the enemy is invisible then shoot crappy most of the time
- if (EntityIsInvisible(&entinfo)) {
- if (random() > 0.1) aim_accuracy *= 0.4f;
- }
- //
- VectorSubtract(entinfo.origin, entinfo.lastvisorigin, enemyvelocity);
- VectorScale(enemyvelocity, 1 / entinfo.update_time, enemyvelocity);
- //enemy origin and velocity is remembered every 0.5 seconds
- if (bs->enemyposition_time < FloatTime()) {
- //
- bs->enemyposition_time = FloatTime() + 0.5;
- VectorCopy(enemyvelocity, bs->enemyvelocity);
- VectorCopy(entinfo.origin, bs->enemyorigin);
- }
- //if not extremely skilled
- if (aim_skill < 0.9) {
- VectorSubtract(entinfo.origin, bs->enemyorigin, dir);
- //if the enemy moved a bit
- if (VectorLengthSquared(dir) > Square(48)) {
- //if the enemy changed direction
- if (DotProduct(bs->enemyvelocity, enemyvelocity) < 0) {
- //aim accuracy should be worse now
- aim_accuracy *= 0.7f;
- }
- }
- }
- //check visibility of enemy
- enemyvisible = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy);
- //if the enemy is visible
- if (enemyvisible) {
- //
- VectorCopy(entinfo.origin, bestorigin);
- bestorigin[2] += 8;
- //get the start point shooting from
- //NOTE: the x and y projectile start offsets are ignored
- VectorCopy(bs->origin, start);
- start[2] += bs->cur_ps.viewheight;
- start[2] += wi.offset[2];
- //
- BotAI_Trace(&trace, start, mins, maxs, bestorigin, bs->entitynum, MASK_SHOT);
- //if the enemy is NOT hit
- if (trace.fraction <= 1 && trace.ent != entinfo.number) {
- bestorigin[2] += 16;
- }
- //if it is not an instant hit weapon the bot might want to predict the enemy
- if (wi.speed) {
- //
- VectorSubtract(bestorigin, bs->origin, dir);
- dist = VectorLength(dir);
- VectorSubtract(entinfo.origin, bs->enemyorigin, dir);
- //if the enemy is NOT pretty far away and strafing just small steps left and right
- if (!(dist > 100 && VectorLengthSquared(dir) < Square(32))) {
- //if skilled anough do exact prediction
- if (aim_skill > 0.8 &&
- //if the weapon is ready to fire
- bs->cur_ps.weaponstate == WEAPON_READY) {
- aas_clientmove_t move;
- vec3_t origin;
-
- VectorSubtract(entinfo.origin, bs->origin, dir);
- //distance towards the enemy
- dist = VectorLength(dir);
- //direction the enemy is moving in
- VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir);
- //
- VectorScale(dir, 1 / entinfo.update_time, dir);
- //
- VectorCopy(entinfo.origin, origin);
- origin[2] += 1;
- //
- VectorClear(cmdmove);
- //AAS_ClearShownDebugLines();
- trap_AAS_PredictClientMovement(&move, bs->enemy, origin,
- PRESENCE_CROUCH, qfalse,
- dir, cmdmove, 0,
- dist * 10 / wi.speed, 0.1f, 0, 0, qfalse);
- VectorCopy(move.endpos, bestorigin);
- //BotAI_Print(PRT_MESSAGE, "%1.1f predicted speed = %f, frames = %f\n", FloatTime(), VectorLength(dir), dist * 10 / wi.speed);
- }
- //if not that skilled do linear prediction
- else if (aim_skill > 0.4) {
- VectorSubtract(entinfo.origin, bs->origin, dir);
- //distance towards the enemy
- dist = VectorLength(dir);
- //direction the enemy is moving in
- VectorSubtract(entinfo.origin, entinfo.lastvisorigin, dir);
- dir[2] = 0;
- //
- speed = VectorNormalize(dir) / entinfo.update_time;
- //botimport.Print(PRT_MESSAGE, "speed = %f, wi->speed = %f\n", speed, wi->speed);
- //best spot to aim at
- VectorMA(entinfo.origin, (dist / wi.speed) * speed, dir, bestorigin);
- }
- }
- }
- //if the projectile does radial damage
- if (aim_skill > 0.6 && wi.proj.damagetype & DAMAGETYPE_RADIAL) {
- //if the enemy isn't standing significantly higher than the bot
- if (entinfo.origin[2] < bs->origin[2] + 16) {
- //try to aim at the ground in front of the enemy
- VectorCopy(entinfo.origin, end);
- end[2] -= 64;
- BotAI_Trace(&trace, entinfo.origin, NULL, NULL, end, entinfo.number, MASK_SHOT);
- //
- VectorCopy(bestorigin, groundtarget);
- if (trace.startsolid) groundtarget[2] = entinfo.origin[2] - 16;
- else groundtarget[2] = trace.endpos[2] - 8;
- //trace a line from projectile start to ground target
- BotAI_Trace(&trace, start, NULL, NULL, groundtarget, bs->entitynum, MASK_SHOT);
- //if hitpoint is not vertically too far from the ground target
- if (fabs(trace.endpos[2] - groundtarget[2]) < 50) {
- VectorSubtract(trace.endpos, groundtarget, dir);
- //if the hitpoint is near anough the ground target
- if (VectorLengthSquared(dir) < Square(60)) {
- VectorSubtract(trace.endpos, start, dir);
- //if the hitpoint is far anough from the bot
- if (VectorLengthSquared(dir) > Square(100)) {
- //check if the bot is visible from the ground target
- trace.endpos[2] += 1;
- BotAI_Trace(&trace, trace.endpos, NULL, NULL, entinfo.origin, entinfo.number, MASK_SHOT);
- if (trace.fraction >= 1) {
- //botimport.Print(PRT_MESSAGE, "%1.1f aiming at ground\n", AAS_Time());
- VectorCopy(groundtarget, bestorigin);
- }
- }
- }
- }
- }
- }
- bestorigin[0] += 20 * crandom() * (1 - aim_accuracy);
- bestorigin[1] += 20 * crandom() * (1 - aim_accuracy);
- bestorigin[2] += 10 * crandom() * (1 - aim_accuracy);
- }
- else {
- //
- VectorCopy(bs->lastenemyorigin, bestorigin);
- bestorigin[2] += 8;
- //if the bot is skilled anough
- if (aim_skill > 0.5) {
- //do prediction shots around corners
- if (wi.number == WP_BFG ||
- wi.number == WP_ROCKET_LAUNCHER ||
- wi.number == WP_GRENADE_LAUNCHER) {
- //create the chase goal
- goal.entitynum = bs->client;
- goal.areanum = bs->areanum;
- VectorCopy(bs->eye, goal.origin);
- VectorSet(goal.mins, -8, -8, -8);
- VectorSet(goal.maxs, 8, 8, 8);
- //
- if (trap_BotPredictVisiblePosition(bs->lastenemyorigin, bs->lastenemyareanum, &goal, TFL_DEFAULT, target)) {
- VectorSubtract(target, bs->eye, dir);
- if (VectorLengthSquared(dir) > Square(80)) {
- VectorCopy(target, bestorigin);
- bestorigin[2] -= 20;
- }
- }
- aim_accuracy = 1;
- }
- }
- }
- //
- if (enemyvisible) {
- BotAI_Trace(&trace, bs->eye, NULL, NULL, bestorigin, bs->entitynum, MASK_SHOT);
- VectorCopy(trace.endpos, bs->aimtarget);
- }
- else {
- VectorCopy(bestorigin, bs->aimtarget);
- }
- //get aim direction
- VectorSubtract(bestorigin, bs->eye, dir);
- //
- if (wi.number == WP_MACHINEGUN ||
- wi.number == WP_SHOTGUN ||
- wi.number == WP_LIGHTNING ||
- wi.number == WP_RAILGUN) {
- //distance towards the enemy
- dist = VectorLength(dir);
- if (dist > 150) dist = 150;
- f = 0.6 + dist / 150 * 0.4;
- aim_accuracy *= f;
- }
- //add some random stuff to the aim direction depending on the aim accuracy
- if (aim_accuracy < 0.8) {
- VectorNormalize(dir);
- for (i = 0; i < 3; i++) dir[i] += 0.3 * crandom() * (1 - aim_accuracy);
- }
- //set the ideal view angles
- vectoangles(dir, bs->ideal_viewangles);
- //take the weapon spread into account for lower skilled bots
- bs->ideal_viewangles[PITCH] += 6 * wi.vspread * crandom() * (1 - aim_accuracy);
- bs->ideal_viewangles[PITCH] = AngleMod(bs->ideal_viewangles[PITCH]);
- bs->ideal_viewangles[YAW] += 6 * wi.hspread * crandom() * (1 - aim_accuracy);
- bs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]);
- //if the bots should be really challenging
- if (bot_challenge.integer) {
- //if the bot is really accurate and has the enemy in view for some time
- if (aim_accuracy > 0.9 && bs->enemysight_time < FloatTime() - 1) {
- //set the view angles directly
- if (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360;
- VectorCopy(bs->ideal_viewangles, bs->viewangles);
- trap_EA_View(bs->client, bs->viewangles);
- }
- }
-}
-
-/*
-==================
-BotCheckAttack
-==================
-*/
-void BotCheckAttack(bot_state_t *bs) {
- float points, reactiontime, fov, firethrottle;
- int attackentity;
- bsp_trace_t bsptrace;
- //float selfpreservation;
- vec3_t forward, right, start, end, dir, angles;
- weaponinfo_t wi;
- bsp_trace_t trace;
- aas_entityinfo_t entinfo;
- vec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8};
-
- attackentity = bs->enemy;
- //
- BotEntityInfo(attackentity, &entinfo);
- // if not attacking a player
- if (attackentity >= MAX_CLIENTS) {
- // if attacking an obelisk
- if ( entinfo.number == redobelisk.entitynum ||
- entinfo.number == blueobelisk.entitynum ) {
- // if obelisk is respawning return
- if ( g_entities[entinfo.number].activator &&
- g_entities[entinfo.number].activator->s.frame == 2 ) {
- return;
- }
- }
- }
- //
- reactiontime = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_REACTIONTIME, 0, 1);
- if (bs->enemysight_time > FloatTime() - reactiontime) return;
- if (bs->teleport_time > FloatTime() - reactiontime) return;
- //if changing weapons
- if (bs->weaponchange_time > FloatTime() - 0.1) return;
- //check fire throttle characteristic
- if (bs->firethrottlewait_time > FloatTime()) return;
- firethrottle = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_FIRETHROTTLE, 0, 1);
- if (bs->firethrottleshoot_time < FloatTime()) {
- if (random() > firethrottle) {
- bs->firethrottlewait_time = FloatTime() + firethrottle;
- bs->firethrottleshoot_time = 0;
- }
- else {
- bs->firethrottleshoot_time = FloatTime() + 1 - firethrottle;
- bs->firethrottlewait_time = 0;
- }
- }
- //
- //
- VectorSubtract(bs->aimtarget, bs->eye, dir);
- //
- if (bs->weaponnum == WP_GAUNTLET) {
- if (VectorLengthSquared(dir) > Square(60)) {
- return;
- }
- }
- if (VectorLengthSquared(dir) < Square(100))
- fov = 120;
- else
- fov = 50;
- //
- vectoangles(dir, angles);
- if (!InFieldOfVision(bs->viewangles, fov, angles))
- return;
- BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, bs->aimtarget, bs->client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- if (bsptrace.fraction < 1 && bsptrace.ent != attackentity)
- return;
-
- //get the weapon info
- trap_BotGetWeaponInfo(bs->ws, bs->weaponnum, &wi);
- //get the start point shooting from
- VectorCopy(bs->origin, start);
- start[2] += bs->cur_ps.viewheight;
- AngleVectors(bs->viewangles, forward, right, NULL);
- start[0] += forward[0] * wi.offset[0] + right[0] * wi.offset[1];
- start[1] += forward[1] * wi.offset[0] + right[1] * wi.offset[1];
- start[2] += forward[2] * wi.offset[0] + right[2] * wi.offset[1] + wi.offset[2];
- //end point aiming at
- VectorMA(start, 1000, forward, end);
- //a little back to make sure not inside a very close enemy
- VectorMA(start, -12, forward, start);
- BotAI_Trace(&trace, start, mins, maxs, end, bs->entitynum, MASK_SHOT);
- //if the entity is a client
- if (trace.ent > 0 && trace.ent <= MAX_CLIENTS) {
- if (trace.ent != attackentity) {
- //if a teammate is hit
- if (BotSameTeam(bs, trace.ent))
- return;
- }
- }
- //if won't hit the enemy or not attacking a player (obelisk)
- if (trace.ent != attackentity || attackentity >= MAX_CLIENTS) {
- //if the projectile does radial damage
- if (wi.proj.damagetype & DAMAGETYPE_RADIAL) {
- if (trace.fraction * 1000 < wi.proj.radius) {
- points = (wi.proj.damage - 0.5 * trace.fraction * 1000) * 0.5;
- if (points > 0) {
- return;
- }
- }
- //FIXME: check if a teammate gets radial damage
- }
- }
- //if fire has to be release to activate weapon
- if (wi.flags & WFL_FIRERELEASED) {
- if (bs->flags & BFL_ATTACKED) {
- trap_EA_Attack(bs->client);
- }
- }
- else {
- trap_EA_Attack(bs->client);
- }
- bs->flags ^= BFL_ATTACKED;
-}
-
-/*
-==================
-BotMapScripts
-==================
-*/
-void BotMapScripts(bot_state_t *bs) {
- char info[1024];
- char mapname[128];
- int i, shootbutton;
- float aim_accuracy;
- aas_entityinfo_t entinfo;
- vec3_t dir;
-
- trap_GetServerinfo(info, sizeof(info));
-
- strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1);
- mapname[sizeof(mapname)-1] = '\0';
-
- if (!Q_stricmp(mapname, "q3tourney6")) {
- vec3_t mins = {700, 204, 672}, maxs = {964, 468, 680};
- vec3_t buttonorg = {304, 352, 920};
- //NOTE: NEVER use the func_bobbing in q3tourney6
- bs->tfl &= ~TFL_FUNCBOB;
- //if the bot is below the bounding box
- if (bs->origin[0] > mins[0] && bs->origin[0] < maxs[0]) {
- if (bs->origin[1] > mins[1] && bs->origin[1] < maxs[1]) {
- if (bs->origin[2] < mins[2]) {
- return;
- }
- }
- }
- shootbutton = qfalse;
- //if an enemy is below this bounding box then shoot the button
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
-
- if (i == bs->client) continue;
- //
- BotEntityInfo(i, &entinfo);
- //
- if (!entinfo.valid) continue;
- //if the enemy isn't dead and the enemy isn't the bot self
- if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;
- //
- if (entinfo.origin[0] > mins[0] && entinfo.origin[0] < maxs[0]) {
- if (entinfo.origin[1] > mins[1] && entinfo.origin[1] < maxs[1]) {
- if (entinfo.origin[2] < mins[2]) {
- //if there's a team mate below the crusher
- if (BotSameTeam(bs, i)) {
- shootbutton = qfalse;
- break;
- }
- else {
- shootbutton = qtrue;
- }
- }
- }
- }
- }
- if (shootbutton) {
- bs->flags |= BFL_IDEALVIEWSET;
- VectorSubtract(buttonorg, bs->eye, dir);
- vectoangles(dir, bs->ideal_viewangles);
- aim_accuracy = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_AIM_ACCURACY, 0, 1);
- bs->ideal_viewangles[PITCH] += 8 * crandom() * (1 - aim_accuracy);
- bs->ideal_viewangles[PITCH] = AngleMod(bs->ideal_viewangles[PITCH]);
- bs->ideal_viewangles[YAW] += 8 * crandom() * (1 - aim_accuracy);
- bs->ideal_viewangles[YAW] = AngleMod(bs->ideal_viewangles[YAW]);
- //
- if (InFieldOfVision(bs->viewangles, 20, bs->ideal_viewangles)) {
- trap_EA_Attack(bs->client);
- }
- }
- }
- else if (!Q_stricmp(mapname, "mpq3tourney6")) {
- //NOTE: NEVER use the func_bobbing in mpq3tourney6
- bs->tfl &= ~TFL_FUNCBOB;
- }
-}
-
-/*
-==================
-BotSetMovedir
-==================
-*/
-// bk001205 - made these static
-static vec3_t VEC_UP = {0, -1, 0};
-static vec3_t MOVEDIR_UP = {0, 0, 1};
-static vec3_t VEC_DOWN = {0, -2, 0};
-static vec3_t MOVEDIR_DOWN = {0, 0, -1};
-
-void BotSetMovedir(vec3_t angles, vec3_t movedir) {
- if (VectorCompare(angles, VEC_UP)) {
- VectorCopy(MOVEDIR_UP, movedir);
- }
- else if (VectorCompare(angles, VEC_DOWN)) {
- VectorCopy(MOVEDIR_DOWN, movedir);
- }
- else {
- AngleVectors(angles, movedir, NULL, NULL);
- }
-}
-
-/*
-==================
-BotModelMinsMaxs
-
-this is ugly
-==================
-*/
-int BotModelMinsMaxs(int modelindex, int eType, int contents, vec3_t mins, vec3_t maxs) {
- gentity_t *ent;
- int i;
-
- ent = &g_entities[0];
- for (i = 0; i < level.num_entities; i++, ent++) {
- if ( !ent->inuse ) {
- continue;
- }
- if ( eType && ent->s.eType != eType) {
- continue;
- }
- if ( contents && ent->r.contents != contents) {
- continue;
- }
- if (ent->s.modelindex == modelindex) {
- if (mins)
- VectorAdd(ent->r.currentOrigin, ent->r.mins, mins);
- if (maxs)
- VectorAdd(ent->r.currentOrigin, ent->r.maxs, maxs);
- return i;
- }
- }
- if (mins)
- VectorClear(mins);
- if (maxs)
- VectorClear(maxs);
- return 0;
-}
-
-/*
-==================
-BotFuncButtonGoal
-==================
-*/
-int BotFuncButtonActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) {
- int i, areas[10], numareas, modelindex, entitynum;
- char model[128];
- float lip, dist, health, angle;
- vec3_t size, start, end, mins, maxs, angles, points[10];
- vec3_t movedir, origin, goalorigin, bboxmins, bboxmaxs;
- vec3_t extramins = {1, 1, 1}, extramaxs = {-1, -1, -1};
- bsp_trace_t bsptrace;
-
- activategoal->shoot = qfalse;
- VectorClear(activategoal->target);
- //create a bot goal towards the button
- trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model));
- if (!*model)
- return qfalse;
- modelindex = atoi(model+1);
- if (!modelindex)
- return qfalse;
- VectorClear(angles);
- entitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs);
- //get the lip of the button
- trap_AAS_FloatForBSPEpairKey(bspent, "lip", &lip);
- if (!lip) lip = 4;
- //get the move direction from the angle
- trap_AAS_FloatForBSPEpairKey(bspent, "angle", &angle);
- VectorSet(angles, 0, angle, 0);
- BotSetMovedir(angles, movedir);
- //button size
- VectorSubtract(maxs, mins, size);
- //button origin
- VectorAdd(mins, maxs, origin);
- VectorScale(origin, 0.5, origin);
- //touch distance of the button
- dist = fabs(movedir[0]) * size[0] + fabs(movedir[1]) * size[1] + fabs(movedir[2]) * size[2];
- dist *= 0.5;
- //
- trap_AAS_FloatForBSPEpairKey(bspent, "health", &health);
- //if the button is shootable
- if (health) {
- //calculate the shoot target
- VectorMA(origin, -dist, movedir, goalorigin);
- //
- VectorCopy(goalorigin, activategoal->target);
- activategoal->shoot = qtrue;
- //
- BotAI_Trace(&bsptrace, bs->eye, NULL, NULL, goalorigin, bs->entitynum, MASK_SHOT);
- // if the button is visible from the current position
- if (bsptrace.fraction >= 1.0 || bsptrace.ent == entitynum) {
- //
- activategoal->goal.entitynum = entitynum; //NOTE: this is the entity number of the shootable button
- activategoal->goal.number = 0;
- activategoal->goal.flags = 0;
- VectorCopy(bs->origin, activategoal->goal.origin);
- activategoal->goal.areanum = bs->areanum;
- VectorSet(activategoal->goal.mins, -8, -8, -8);
- VectorSet(activategoal->goal.maxs, 8, 8, 8);
- //
- return qtrue;
- }
- else {
- //create a goal from where the button is visible and shoot at the button from there
- //add bounding box size to the dist
- trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs);
- for (i = 0; i < 3; i++) {
- if (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]);
- else dist += fabs(movedir[i]) * fabs(bboxmins[i]);
- }
- //calculate the goal origin
- VectorMA(origin, -dist, movedir, goalorigin);
- //
- VectorCopy(goalorigin, start);
- start[2] += 24;
- VectorCopy(start, end);
- end[2] -= 512;
- numareas = trap_AAS_TraceAreas(start, end, areas, points, 10);
- //
- for (i = numareas-1; i >= 0; i--) {
- if (trap_AAS_AreaReachability(areas[i])) {
- break;
- }
- }
- if (i < 0) {
- // FIXME: trace forward and maybe in other directions to find a valid area
- }
- if (i >= 0) {
- //
- VectorCopy(points[i], activategoal->goal.origin);
- activategoal->goal.areanum = areas[i];
- VectorSet(activategoal->goal.mins, 8, 8, 8);
- VectorSet(activategoal->goal.maxs, -8, -8, -8);
- //
- for (i = 0; i < 3; i++)
- {
- if (movedir[i] < 0) activategoal->goal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]);
- else activategoal->goal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]);
- } //end for
- //
- activategoal->goal.entitynum = entitynum;
- activategoal->goal.number = 0;
- activategoal->goal.flags = 0;
- return qtrue;
- }
- }
- return qfalse;
- }
- else {
- //add bounding box size to the dist
- trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bboxmins, bboxmaxs);
- for (i = 0; i < 3; i++) {
- if (movedir[i] < 0) dist += fabs(movedir[i]) * fabs(bboxmaxs[i]);
- else dist += fabs(movedir[i]) * fabs(bboxmins[i]);
- }
- //calculate the goal origin
- VectorMA(origin, -dist, movedir, goalorigin);
- //
- VectorCopy(goalorigin, start);
- start[2] += 24;
- VectorCopy(start, end);
- end[2] -= 100;
- numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10);
- //
- for (i = 0; i < numareas; i++) {
- if (trap_AAS_AreaReachability(areas[i])) {
- break;
- }
- }
- if (i < numareas) {
- //
- VectorCopy(origin, activategoal->goal.origin);
- activategoal->goal.areanum = areas[i];
- VectorSubtract(mins, origin, activategoal->goal.mins);
- VectorSubtract(maxs, origin, activategoal->goal.maxs);
- //
- for (i = 0; i < 3; i++)
- {
- if (movedir[i] < 0) activategoal->goal.maxs[i] += fabs(movedir[i]) * fabs(extramaxs[i]);
- else activategoal->goal.mins[i] += fabs(movedir[i]) * fabs(extramins[i]);
- } //end for
- //
- activategoal->goal.entitynum = entitynum;
- activategoal->goal.number = 0;
- activategoal->goal.flags = 0;
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-==================
-BotFuncDoorGoal
-==================
-*/
-int BotFuncDoorActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) {
- int modelindex, entitynum;
- char model[MAX_INFO_STRING];
- vec3_t mins, maxs, origin, angles;
-
- //shoot at the shootable door
- trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model));
- if (!*model)
- return qfalse;
- modelindex = atoi(model+1);
- if (!modelindex)
- return qfalse;
- VectorClear(angles);
- entitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs);
- //door origin
- VectorAdd(mins, maxs, origin);
- VectorScale(origin, 0.5, origin);
- VectorCopy(origin, activategoal->target);
- activategoal->shoot = qtrue;
- //
- activategoal->goal.entitynum = entitynum; //NOTE: this is the entity number of the shootable door
- activategoal->goal.number = 0;
- activategoal->goal.flags = 0;
- VectorCopy(bs->origin, activategoal->goal.origin);
- activategoal->goal.areanum = bs->areanum;
- VectorSet(activategoal->goal.mins, -8, -8, -8);
- VectorSet(activategoal->goal.maxs, 8, 8, 8);
- return qtrue;
-}
-
-/*
-==================
-BotTriggerMultipleGoal
-==================
-*/
-int BotTriggerMultipleActivateGoal(bot_state_t *bs, int bspent, bot_activategoal_t *activategoal) {
- int i, areas[10], numareas, modelindex, entitynum;
- char model[128];
- vec3_t start, end, mins, maxs, angles;
- vec3_t origin, goalorigin;
-
- activategoal->shoot = qfalse;
- VectorClear(activategoal->target);
- //create a bot goal towards the trigger
- trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model));
- if (!*model)
- return qfalse;
- modelindex = atoi(model+1);
- if (!modelindex)
- return qfalse;
- VectorClear(angles);
- entitynum = BotModelMinsMaxs(modelindex, 0, CONTENTS_TRIGGER, mins, maxs);
- //trigger origin
- VectorAdd(mins, maxs, origin);
- VectorScale(origin, 0.5, origin);
- VectorCopy(origin, goalorigin);
- //
- VectorCopy(goalorigin, start);
- start[2] += 24;
- VectorCopy(start, end);
- end[2] -= 100;
- numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10);
- //
- for (i = 0; i < numareas; i++) {
- if (trap_AAS_AreaReachability(areas[i])) {
- break;
- }
- }
- if (i < numareas) {
- VectorCopy(origin, activategoal->goal.origin);
- activategoal->goal.areanum = areas[i];
- VectorSubtract(mins, origin, activategoal->goal.mins);
- VectorSubtract(maxs, origin, activategoal->goal.maxs);
- //
- activategoal->goal.entitynum = entitynum;
- activategoal->goal.number = 0;
- activategoal->goal.flags = 0;
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-BotPopFromActivateGoalStack
-==================
-*/
-int BotPopFromActivateGoalStack(bot_state_t *bs) {
- if (!bs->activatestack)
- return qfalse;
- BotEnableActivateGoalAreas(bs->activatestack, qtrue);
- bs->activatestack->inuse = qfalse;
- bs->activatestack->justused_time = FloatTime();
- bs->activatestack = bs->activatestack->next;
- return qtrue;
-}
-
-/*
-==================
-BotPushOntoActivateGoalStack
-==================
-*/
-int BotPushOntoActivateGoalStack(bot_state_t *bs, bot_activategoal_t *activategoal) {
- int i, best;
- float besttime;
-
- best = -1;
- besttime = FloatTime() + 9999;
- //
- for (i = 0; i < MAX_ACTIVATESTACK; i++) {
- if (!bs->activategoalheap[i].inuse) {
- if (bs->activategoalheap[i].justused_time < besttime) {
- besttime = bs->activategoalheap[i].justused_time;
- best = i;
- }
- }
- }
- if (best != -1) {
- memcpy(&bs->activategoalheap[best], activategoal, sizeof(bot_activategoal_t));
- bs->activategoalheap[best].inuse = qtrue;
- bs->activategoalheap[best].next = bs->activatestack;
- bs->activatestack = &bs->activategoalheap[best];
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-BotClearActivateGoalStack
-==================
-*/
-void BotClearActivateGoalStack(bot_state_t *bs) {
- while(bs->activatestack)
- BotPopFromActivateGoalStack(bs);
-}
-
-/*
-==================
-BotEnableActivateGoalAreas
-==================
-*/
-void BotEnableActivateGoalAreas(bot_activategoal_t *activategoal, int enable) {
- int i;
-
- if (activategoal->areasdisabled == !enable)
- return;
- for (i = 0; i < activategoal->numareas; i++)
- trap_AAS_EnableRoutingArea( activategoal->areas[i], enable );
- activategoal->areasdisabled = !enable;
-}
-
-/*
-==================
-BotIsGoingToActivateEntity
-==================
-*/
-int BotIsGoingToActivateEntity(bot_state_t *bs, int entitynum) {
- bot_activategoal_t *a;
- int i;
-
- for (a = bs->activatestack; a; a = a->next) {
- if (a->time < FloatTime())
- continue;
- if (a->goal.entitynum == entitynum)
- return qtrue;
- }
- for (i = 0; i < MAX_ACTIVATESTACK; i++) {
- if (bs->activategoalheap[i].inuse)
- continue;
- //
- if (bs->activategoalheap[i].goal.entitynum == entitynum) {
- // if the bot went for this goal less than 2 seconds ago
- if (bs->activategoalheap[i].justused_time > FloatTime() - 2)
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-==================
-BotGetActivateGoal
-
- returns the number of the bsp entity to activate
- goal->entitynum will be set to the game entity to activate
-==================
-*/
-//#define OBSTACLEDEBUG
-
-int BotGetActivateGoal(bot_state_t *bs, int entitynum, bot_activategoal_t *activategoal) {
- int i, ent, cur_entities[10], spawnflags, modelindex, areas[MAX_ACTIVATEAREAS*2], numareas, t;
- char model[MAX_INFO_STRING], tmpmodel[128];
- char target[128], classname[128];
- float health;
- char targetname[10][128];
- aas_entityinfo_t entinfo;
- aas_areainfo_t areainfo;
- vec3_t origin, angles, absmins, absmaxs;
-
- memset(activategoal, 0, sizeof(bot_activategoal_t));
- BotEntityInfo(entitynum, &entinfo);
- Com_sprintf(model, sizeof( model ), "*%d", entinfo.modelindex);
- for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) {
- if (!trap_AAS_ValueForBSPEpairKey(ent, "model", tmpmodel, sizeof(tmpmodel))) continue;
- if (!strcmp(model, tmpmodel)) break;
- }
- if (!ent) {
- BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no entity found with model %s\n", model);
- return 0;
- }
- trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname));
- if (!*classname) {
- BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with model %s has no classname\n", model);
- return 0;
- }
- //if it is a door
- if (!strcmp(classname, "func_door")) {
- if (trap_AAS_FloatForBSPEpairKey(ent, "health", &health)) {
- //if the door has health then the door must be shot to open
- if (health) {
- BotFuncDoorActivateGoal(bs, ent, activategoal);
- return ent;
- }
- }
- //
- trap_AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags);
- // if the door starts open then just wait for the door to return
- if ( spawnflags & 1 )
- return 0;
- //get the door origin
- if (!trap_AAS_VectorForBSPEpairKey(ent, "origin", origin)) {
- VectorClear(origin);
- }
- //if the door is open or opening already
- if (!VectorCompare(origin, entinfo.origin))
- return 0;
- // store all the areas the door is in
- trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model));
- if (*model) {
- modelindex = atoi(model+1);
- if (modelindex) {
- VectorClear(angles);
- BotModelMinsMaxs(modelindex, ET_MOVER, 0, absmins, absmaxs);
- //
- numareas = trap_AAS_BBoxAreas(absmins, absmaxs, areas, MAX_ACTIVATEAREAS*2);
- // store the areas with reachabilities first
- for (i = 0; i < numareas; i++) {
- if (activategoal->numareas >= MAX_ACTIVATEAREAS)
- break;
- if ( !trap_AAS_AreaReachability(areas[i]) ) {
- continue;
- }
- trap_AAS_AreaInfo(areas[i], &areainfo);
- if (areainfo.contents & AREACONTENTS_MOVER) {
- activategoal->areas[activategoal->numareas++] = areas[i];
- }
- }
- // store any remaining areas
- for (i = 0; i < numareas; i++) {
- if (activategoal->numareas >= MAX_ACTIVATEAREAS)
- break;
- if ( trap_AAS_AreaReachability(areas[i]) ) {
- continue;
- }
- trap_AAS_AreaInfo(areas[i], &areainfo);
- if (areainfo.contents & AREACONTENTS_MOVER) {
- activategoal->areas[activategoal->numareas++] = areas[i];
- }
- }
- }
- }
- }
- // if the bot is blocked by or standing on top of a button
- if (!strcmp(classname, "func_button")) {
- return 0;
- }
- // get the targetname so we can find an entity with a matching target
- if (!trap_AAS_ValueForBSPEpairKey(ent, "targetname", targetname[0], sizeof(targetname[0]))) {
- if (bot_developer.integer) {
- BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with model \"%s\" has no targetname\n", model);
- }
- return 0;
- }
- // allow tree-like activation
- cur_entities[0] = trap_AAS_NextBSPEntity(0);
- for (i = 0; i >= 0 && i < 10;) {
- for (ent = cur_entities[i]; ent; ent = trap_AAS_NextBSPEntity(ent)) {
- if (!trap_AAS_ValueForBSPEpairKey(ent, "target", target, sizeof(target))) continue;
- if (!strcmp(targetname[i], target)) {
- cur_entities[i] = trap_AAS_NextBSPEntity(ent);
- break;
- }
- }
- if (!ent) {
- if (bot_developer.integer) {
- BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no entity with target \"%s\"\n", targetname[i]);
- }
- i--;
- continue;
- }
- if (!trap_AAS_ValueForBSPEpairKey(ent, "classname", classname, sizeof(classname))) {
- if (bot_developer.integer) {
- BotAI_Print(PRT_ERROR, "BotGetActivateGoal: entity with target \"%s\" has no classname\n", targetname[i]);
- }
- continue;
- }
- // BSP button model
- if (!strcmp(classname, "func_button")) {
- //
- if (!BotFuncButtonActivateGoal(bs, ent, activategoal))
- continue;
- // if the bot tries to activate this button already
- if ( bs->activatestack && bs->activatestack->inuse &&
- bs->activatestack->goal.entitynum == activategoal->goal.entitynum &&
- bs->activatestack->time > FloatTime() &&
- bs->activatestack->start_time < FloatTime() - 2)
- continue;
- // if the bot is in a reachability area
- if ( trap_AAS_AreaReachability(bs->areanum) ) {
- // disable all areas the blocking entity is in
- BotEnableActivateGoalAreas( activategoal, qfalse );
- //
- t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, activategoal->goal.areanum, bs->tfl);
- // if the button is not reachable
- if (!t) {
- continue;
- }
- activategoal->time = FloatTime() + t * 0.01 + 5;
- }
- return ent;
- }
- // invisible trigger multiple box
- else if (!strcmp(classname, "trigger_multiple")) {
- //
- if (!BotTriggerMultipleActivateGoal(bs, ent, activategoal))
- continue;
- // if the bot tries to activate this trigger already
- if ( bs->activatestack && bs->activatestack->inuse &&
- bs->activatestack->goal.entitynum == activategoal->goal.entitynum &&
- bs->activatestack->time > FloatTime() &&
- bs->activatestack->start_time < FloatTime() - 2)
- continue;
- // if the bot is in a reachability area
- if ( trap_AAS_AreaReachability(bs->areanum) ) {
- // disable all areas the blocking entity is in
- BotEnableActivateGoalAreas( activategoal, qfalse );
- //
- t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, activategoal->goal.areanum, bs->tfl);
- // if the trigger is not reachable
- if (!t) {
- continue;
- }
- activategoal->time = FloatTime() + t * 0.01 + 5;
- }
- return ent;
- }
- else if (!strcmp(classname, "func_timer")) {
- // just skip the func_timer
- continue;
- }
- // the actual button or trigger might be linked through a target_relay or target_delay
- else if (!strcmp(classname, "target_relay") || !strcmp(classname, "target_delay")) {
- if (trap_AAS_ValueForBSPEpairKey(ent, "targetname", targetname[i+1], sizeof(targetname[0]))) {
- i++;
- cur_entities[i] = trap_AAS_NextBSPEntity(0);
- }
- }
- }
-#ifdef OBSTACLEDEBUG
- BotAI_Print(PRT_ERROR, "BotGetActivateGoal: no valid activator for entity with target \"%s\"\n", targetname[0]);
-#endif
- return 0;
-}
-
-/*
-==================
-BotGoForActivateGoal
-==================
-*/
-int BotGoForActivateGoal(bot_state_t *bs, bot_activategoal_t *activategoal) {
- aas_entityinfo_t activateinfo;
-
- activategoal->inuse = qtrue;
- if (!activategoal->time)
- activategoal->time = FloatTime() + 10;
- activategoal->start_time = FloatTime();
- BotEntityInfo(activategoal->goal.entitynum, &activateinfo);
- VectorCopy(activateinfo.origin, activategoal->origin);
- //
- if (BotPushOntoActivateGoalStack(bs, activategoal)) {
- // enter the activate entity AI node
- AIEnter_Seek_ActivateEntity(bs, "BotGoForActivateGoal");
- return qtrue;
- }
- else {
- // enable any routing areas that were disabled
- BotEnableActivateGoalAreas(activategoal, qtrue);
- return qfalse;
- }
-}
-
-/*
-==================
-BotPrintActivateGoalInfo
-==================
-*/
-void BotPrintActivateGoalInfo(bot_state_t *bs, bot_activategoal_t *activategoal, int bspent) {
- char netname[MAX_NETNAME];
- char classname[128];
- char buf[128];
-
- ClientName(bs->client, netname, sizeof(netname));
- trap_AAS_ValueForBSPEpairKey(bspent, "classname", classname, sizeof(classname));
- if (activategoal->shoot) {
- Com_sprintf(buf, sizeof(buf), "%s: I have to shoot at a %s from %1.1f %1.1f %1.1f in area %d\n",
- netname, classname,
- activategoal->goal.origin[0],
- activategoal->goal.origin[1],
- activategoal->goal.origin[2],
- activategoal->goal.areanum);
- }
- else {
- Com_sprintf(buf, sizeof(buf), "%s: I have to activate a %s at %1.1f %1.1f %1.1f in area %d\n",
- netname, classname,
- activategoal->goal.origin[0],
- activategoal->goal.origin[1],
- activategoal->goal.origin[2],
- activategoal->goal.areanum);
- }
- trap_EA_Say(bs->client, buf);
-}
-
-/*
-==================
-BotRandomMove
-==================
-*/
-void BotRandomMove(bot_state_t *bs, bot_moveresult_t *moveresult) {
- vec3_t dir, angles;
-
- angles[0] = 0;
- angles[1] = random() * 360;
- angles[2] = 0;
- AngleVectors(angles, dir, NULL, NULL);
-
- trap_BotMoveInDirection(bs->ms, dir, 400, MOVE_WALK);
-
- moveresult->failure = qfalse;
- VectorCopy(dir, moveresult->movedir);
-}
-
-/*
-==================
-BotAIBlocked
-
-Very basic handling of bots being blocked by other entities.
-Check what kind of entity is blocking the bot and try to activate
-it. If that's not an option then try to walk around or over the entity.
-Before the bot ends in this part of the AI it should predict which doors to
-open, which buttons to activate etc.
-==================
-*/
-void BotAIBlocked(bot_state_t *bs, bot_moveresult_t *moveresult, int activate) {
- int movetype, bspent;
- vec3_t hordir, start, end, mins, maxs, sideward, angles, up = {0, 0, 1};
- aas_entityinfo_t entinfo;
- bot_activategoal_t activategoal;
-
- // if the bot is not blocked by anything
- if (!moveresult->blocked) {
- bs->notblocked_time = FloatTime();
- return;
- }
- // if stuck in a solid area
- if ( moveresult->type == RESULTTYPE_INSOLIDAREA ) {
- // move in a random direction in the hope to get out
- BotRandomMove(bs, moveresult);
- //
- return;
- }
- // get info for the entity that is blocking the bot
- BotEntityInfo(moveresult->blockentity, &entinfo);
-#ifdef OBSTACLEDEBUG
- ClientName(bs->client, netname, sizeof(netname));
- BotAI_Print(PRT_MESSAGE, "%s: I'm blocked by model %d\n", netname, entinfo.modelindex);
-#endif // OBSTACLEDEBUG
- // if blocked by a bsp model and the bot wants to activate it
- if (activate && entinfo.modelindex > 0 && entinfo.modelindex <= max_bspmodelindex) {
- // find the bsp entity which should be activated in order to get the blocking entity out of the way
- bspent = BotGetActivateGoal(bs, entinfo.number, &activategoal);
- if (bspent) {
- //
- if (bs->activatestack && !bs->activatestack->inuse)
- bs->activatestack = NULL;
- // if not already trying to activate this entity
- if (!BotIsGoingToActivateEntity(bs, activategoal.goal.entitynum)) {
- //
- BotGoForActivateGoal(bs, &activategoal);
- }
- // if ontop of an obstacle or
- // if the bot is not in a reachability area it'll still
- // need some dynamic obstacle avoidance, otherwise return
- if (!(moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE) &&
- trap_AAS_AreaReachability(bs->areanum))
- return;
- }
- else {
- // enable any routing areas that were disabled
- BotEnableActivateGoalAreas(&activategoal, qtrue);
- }
- }
- // just some basic dynamic obstacle avoidance code
- hordir[0] = moveresult->movedir[0];
- hordir[1] = moveresult->movedir[1];
- hordir[2] = 0;
- // if no direction just take a random direction
- if (VectorNormalize(hordir) < 0.1) {
- VectorSet(angles, 0, 360 * random(), 0);
- AngleVectors(angles, hordir, NULL, NULL);
- }
- //
- //if (moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE) movetype = MOVE_JUMP;
- //else
- movetype = MOVE_WALK;
- // if there's an obstacle at the bot's feet and head then
- // the bot might be able to crouch through
- VectorCopy(bs->origin, start);
- start[2] += 18;
- VectorMA(start, 5, hordir, end);
- VectorSet(mins, -16, -16, -24);
- VectorSet(maxs, 16, 16, 4);
- //
- //bsptrace = AAS_Trace(start, mins, maxs, end, bs->entitynum, MASK_PLAYERSOLID);
- //if (bsptrace.fraction >= 1) movetype = MOVE_CROUCH;
- // get the sideward vector
- CrossProduct(hordir, up, sideward);
- //
- if (bs->flags & BFL_AVOIDRIGHT) VectorNegate(sideward, sideward);
- // try to crouch straight forward?
- if (movetype != MOVE_CROUCH || !trap_BotMoveInDirection(bs->ms, hordir, 400, movetype)) {
- // perform the movement
- if (!trap_BotMoveInDirection(bs->ms, sideward, 400, movetype)) {
- // flip the avoid direction flag
- bs->flags ^= BFL_AVOIDRIGHT;
- // flip the direction
- // VectorNegate(sideward, sideward);
- VectorMA(sideward, -1, hordir, sideward);
- // move in the other direction
- trap_BotMoveInDirection(bs->ms, sideward, 400, movetype);
- }
- }
- //
- if (bs->notblocked_time < FloatTime() - 0.4) {
- // just reset goals and hope the bot will go into another direction?
- // is this still needed??
- if (bs->ainode == AINode_Seek_NBG) bs->nbg_time = 0;
- else if (bs->ainode == AINode_Seek_LTG) bs->ltg_time = 0;
- }
-}
-
-/*
-==================
-BotAIPredictObstacles
-
-Predict the route towards the goal and check if the bot
-will be blocked by certain obstacles. When the bot has obstacles
-on it's path the bot should figure out if they can be removed
-by activating certain entities.
-==================
-*/
-int BotAIPredictObstacles(bot_state_t *bs, bot_goal_t *goal) {
- int modelnum, entitynum, bspent;
- bot_activategoal_t activategoal;
- aas_predictroute_t route;
-
- if (!bot_predictobstacles.integer)
- return qfalse;
-
- // always predict when the goal change or at regular intervals
- if (bs->predictobstacles_goalareanum == goal->areanum &&
- bs->predictobstacles_time > FloatTime() - 6) {
- return qfalse;
- }
- bs->predictobstacles_goalareanum = goal->areanum;
- bs->predictobstacles_time = FloatTime();
-
- // predict at most 100 areas or 10 seconds ahead
- trap_AAS_PredictRoute(&route, bs->areanum, bs->origin,
- goal->areanum, bs->tfl, 100, 1000,
- RSE_USETRAVELTYPE|RSE_ENTERCONTENTS,
- AREACONTENTS_MOVER, TFL_BRIDGE, 0);
- // if bot has to travel through an area with a mover
- if (route.stopevent & RSE_ENTERCONTENTS) {
- // if the bot will run into a mover
- if (route.endcontents & AREACONTENTS_MOVER) {
- //NOTE: this only works with bspc 2.1 or higher
- modelnum = (route.endcontents & AREACONTENTS_MODELNUM) >> AREACONTENTS_MODELNUMSHIFT;
- if (modelnum) {
- //
- entitynum = BotModelMinsMaxs(modelnum, ET_MOVER, 0, NULL, NULL);
- if (entitynum) {
- //NOTE: BotGetActivateGoal already checks if the door is open or not
- bspent = BotGetActivateGoal(bs, entitynum, &activategoal);
- if (bspent) {
- //
- if (bs->activatestack && !bs->activatestack->inuse)
- bs->activatestack = NULL;
- // if not already trying to activate this entity
- if (!BotIsGoingToActivateEntity(bs, activategoal.goal.entitynum)) {
- //
- //BotAI_Print(PRT_MESSAGE, "blocked by mover model %d, entity %d ?\n", modelnum, entitynum);
- //
- BotGoForActivateGoal(bs, &activategoal);
- return qtrue;
- }
- else {
- // enable any routing areas that were disabled
- BotEnableActivateGoalAreas(&activategoal, qtrue);
- }
- }
- }
- }
- }
- }
- else if (route.stopevent & RSE_USETRAVELTYPE) {
- if (route.endtravelflags & TFL_BRIDGE) {
- //FIXME: check if the bridge is available to travel over
- }
- }
- return qfalse;
-}
-
-/*
-==================
-BotCheckConsoleMessages
-==================
-*/
-void BotCheckConsoleMessages(bot_state_t *bs) {
- char botname[MAX_NETNAME], message[MAX_MESSAGE_SIZE], netname[MAX_NETNAME], *ptr;
- float chat_reply;
- int context, handle;
- bot_consolemessage_t m;
- bot_match_t match;
-
- //the name of this bot
- ClientName(bs->client, botname, sizeof(botname));
- //
- while((handle = trap_BotNextConsoleMessage(bs->cs, &m)) != 0) {
- //if the chat state is flooded with messages the bot will read them quickly
- if (trap_BotNumConsoleMessages(bs->cs) < 10) {
- //if it is a chat message the bot needs some time to read it
- if (m.type == CMS_CHAT && m.time > FloatTime() - (1 + random())) break;
- }
- //
- ptr = m.message;
- //if it is a chat message then don't unify white spaces and don't
- //replace synonyms in the netname
- if (m.type == CMS_CHAT) {
- //
- if (trap_BotFindMatch(m.message, &match, MTCONTEXT_REPLYCHAT)) {
- ptr = m.message + match.variables[MESSAGE].offset;
- }
- }
- //unify the white spaces in the message
- trap_UnifyWhiteSpaces(ptr);
- //replace synonyms in the right context
- context = BotSynonymContext(bs);
- trap_BotReplaceSynonyms(ptr, context);
- //if there's no match
- if (!BotMatchMessage(bs, m.message)) {
- //if it is a chat message
- if (m.type == CMS_CHAT && !bot_nochat.integer) {
- //
- if (!trap_BotFindMatch(m.message, &match, MTCONTEXT_REPLYCHAT)) {
- trap_BotRemoveConsoleMessage(bs->cs, handle);
- continue;
- }
- //don't use eliza chats with team messages
- if (match.subtype & ST_TEAM) {
- trap_BotRemoveConsoleMessage(bs->cs, handle);
- continue;
- }
- //
- trap_BotMatchVariable(&match, NETNAME, netname, sizeof(netname));
- trap_BotMatchVariable(&match, MESSAGE, message, sizeof(message));
- //if this is a message from the bot self
- if (bs->client == ClientFromName(netname)) {
- trap_BotRemoveConsoleMessage(bs->cs, handle);
- continue;
- }
- //unify the message
- trap_UnifyWhiteSpaces(message);
- //
- trap_Cvar_Update(&bot_testrchat);
- if (bot_testrchat.integer) {
- //
- trap_BotLibVarSet("bot_testrchat", "1");
- //if bot replies with a chat message
- if (trap_BotReplyChat(bs->cs, message, context, CONTEXT_REPLY,
- NULL, NULL,
- NULL, NULL,
- NULL, NULL,
- botname, netname)) {
- BotAI_Print(PRT_MESSAGE, "------------------------\n");
- }
- else {
- BotAI_Print(PRT_MESSAGE, "**** no valid reply ****\n");
- }
- }
- //if at a valid chat position and not chatting already and not in teamplay
- else if (bs->ainode != AINode_Stand && BotValidChatPosition(bs) && !TeamPlayIsOn()) {
- chat_reply = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_REPLY, 0, 1);
- if (random() < 1.5 / (NumBots()+1) && random() < chat_reply) {
- //if bot replies with a chat message
- if (trap_BotReplyChat(bs->cs, message, context, CONTEXT_REPLY,
- NULL, NULL,
- NULL, NULL,
- NULL, NULL,
- botname, netname)) {
- //remove the console message
- trap_BotRemoveConsoleMessage(bs->cs, handle);
- bs->stand_time = FloatTime() + BotChatTime(bs);
- AIEnter_Stand(bs, "BotCheckConsoleMessages: reply chat");
- //EA_Say(bs->client, bs->cs.chatmessage);
- break;
- }
- }
- }
- }
- }
- //remove the console message
- trap_BotRemoveConsoleMessage(bs->cs, handle);
- }
-}
-
-/*
-==================
-BotCheckEvents
-==================
-*/
-void BotCheckForGrenades(bot_state_t *bs, entityState_t *state) {
- // if this is not a grenade
- if (state->eType != ET_MISSILE || state->weapon != WP_GRENADE_LAUNCHER)
- return;
- // try to avoid the grenade
- trap_BotAddAvoidSpot(bs->ms, state->pos.trBase, 160, AVOID_ALWAYS);
-}
-
-
-/*
-==================
-BotCheckForProxMines
-==================
-*/
-void BotCheckForProxMines(bot_state_t *bs, entityState_t *state) {
- // if this is not a prox mine
- if (state->eType != ET_MISSILE || state->weapon != WP_PROX_LAUNCHER)
- return;
- // if this prox mine is from someone on our own team
- if (state->generic1 == BotTeam(bs))
- return;
- // if the bot doesn't have a weapon to deactivate the mine
- if (!(bs->inventory[INVENTORY_PLASMAGUN] > 0 && bs->inventory[INVENTORY_CELLS] > 0) &&
- !(bs->inventory[INVENTORY_ROCKETLAUNCHER] > 0 && bs->inventory[INVENTORY_ROCKETS] > 0) &&
- !(bs->inventory[INVENTORY_BFG10K] > 0 && bs->inventory[INVENTORY_BFGAMMO] > 0) ) {
- return;
- }
- // try to avoid the prox mine
- trap_BotAddAvoidSpot(bs->ms, state->pos.trBase, 160, AVOID_ALWAYS);
- //
- if (bs->numproxmines >= MAX_PROXMINES)
- return;
- bs->proxmines[bs->numproxmines] = state->number;
- bs->numproxmines++;
-}
-
-/*
-==================
-BotCheckForKamikazeBody
-==================
-*/
-void BotCheckForKamikazeBody(bot_state_t *bs, entityState_t *state) {
- // if this entity is not wearing the kamikaze
- if (!(state->eFlags & EF_KAMIKAZE))
- return;
- // if this entity isn't dead
- if (!(state->eFlags & EF_DEAD))
- return;
- //remember this kamikaze body
- bs->kamikazebody = state->number;
-}
-
-/*
-==================
-BotCheckEvents
-==================
-*/
-void BotCheckEvents(bot_state_t *bs, entityState_t *state) {
- int event;
- char buf[128];
- aas_entityinfo_t entinfo;
-
- //NOTE: this sucks, we're accessing the gentity_t directly
- //but there's no other fast way to do it right now
- if (bs->entityeventTime[state->number] == g_entities[state->number].eventTime) {
- return;
- }
- bs->entityeventTime[state->number] = g_entities[state->number].eventTime;
- //if it's an event only entity
- if (state->eType > ET_EVENTS) {
- event = (state->eType - ET_EVENTS) & ~EV_EVENT_BITS;
- }
- else {
- event = state->event & ~EV_EVENT_BITS;
- }
- //
- switch(event) {
- //client obituary event
- case EV_OBITUARY:
- {
- int target, attacker, mod;
-
- target = state->otherEntityNum;
- attacker = state->otherEntityNum2;
- mod = state->eventParm;
- //
- if (target == bs->client) {
- bs->botdeathtype = mod;
- bs->lastkilledby = attacker;
- //
- if (target == attacker ||
- target == ENTITYNUM_NONE ||
- target == ENTITYNUM_WORLD) bs->botsuicide = qtrue;
- else bs->botsuicide = qfalse;
- //
- bs->num_deaths++;
- }
- //else if this client was killed by the bot
- else if (attacker == bs->client) {
- bs->enemydeathtype = mod;
- bs->lastkilledplayer = target;
- bs->killedenemy_time = FloatTime();
- //
- bs->num_kills++;
- }
- else if (attacker == bs->enemy && target == attacker) {
- bs->enemysuicide = qtrue;
- }
- //
- if (gametype == GT_1FCTF) {
- //
- BotEntityInfo(target, &entinfo);
- if ( entinfo.powerups & ( 1 << PW_NEUTRALFLAG ) ) {
- if (!BotSameTeam(bs, target)) {
- bs->neutralflagstatus = 3; //enemy dropped the flag
- bs->flagstatuschanged = qtrue;
- }
- }
- }
- break;
- }
- case EV_GLOBAL_SOUND:
- {
- if (state->eventParm < 0 || state->eventParm > MAX_SOUNDS) {
- BotAI_Print(PRT_ERROR, "EV_GLOBAL_SOUND: eventParm (%d) out of range\n", state->eventParm);
- break;
- }
- trap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf));
- /*
- if (!strcmp(buf, "sound/teamplay/flagret_red.wav")) {
- //red flag is returned
- bs->redflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- }
- else if (!strcmp(buf, "sound/teamplay/flagret_blu.wav")) {
- //blue flag is returned
- bs->blueflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- }
- else*/
- if (!strcmp(buf, "sound/items/kamikazerespawn.wav" )) {
- //the kamikaze respawned so dont avoid it
- BotDontAvoid(bs, "Kamikaze");
- }
- else
- if (!strcmp(buf, "sound/items/poweruprespawn.wav")) {
- //powerup respawned... go get it
- BotGoForPowerups(bs);
- }
- break;
- }
- case EV_GLOBAL_TEAM_SOUND:
- {
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- switch(state->eventParm) {
- case GTS_RED_CAPTURE:
- bs->blueflagstatus = 0;
- bs->redflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break; //see BotMatch_CTF
- case GTS_BLUE_CAPTURE:
- bs->blueflagstatus = 0;
- bs->redflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break; //see BotMatch_CTF
- case GTS_RED_RETURN:
- //blue flag is returned
- bs->blueflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_BLUE_RETURN:
- //red flag is returned
- bs->redflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_RED_TAKEN:
- //blue flag is taken
- bs->blueflagstatus = 1;
- bs->flagstatuschanged = qtrue;
- break; //see BotMatch_CTF
- case GTS_BLUE_TAKEN:
- //red flag is taken
- bs->redflagstatus = 1;
- bs->flagstatuschanged = qtrue;
- break; //see BotMatch_CTF
- }
- }
- else if (gametype == GT_1FCTF) {
- switch(state->eventParm) {
- case GTS_RED_CAPTURE:
- bs->neutralflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_BLUE_CAPTURE:
- bs->neutralflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_RED_RETURN:
- //flag has returned
- bs->neutralflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_BLUE_RETURN:
- //flag has returned
- bs->neutralflagstatus = 0;
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_RED_TAKEN:
- bs->neutralflagstatus = BotTeam(bs) == TEAM_RED ? 2 : 1; //FIXME: check Team_TakeFlagSound in g_team.c
- bs->flagstatuschanged = qtrue;
- break;
- case GTS_BLUE_TAKEN:
- bs->neutralflagstatus = BotTeam(bs) == TEAM_BLUE ? 2 : 1; //FIXME: check Team_TakeFlagSound in g_team.c
- bs->flagstatuschanged = qtrue;
- break;
- }
- }
- break;
- }
- case EV_PLAYER_TELEPORT_IN:
- {
- VectorCopy(state->origin, lastteleport_origin);
- lastteleport_time = FloatTime();
- break;
- }
- case EV_GENERAL_SOUND:
- {
- //if this sound is played on the bot
- if (state->number == bs->client) {
- if (state->eventParm < 0 || state->eventParm > MAX_SOUNDS) {
- BotAI_Print(PRT_ERROR, "EV_GENERAL_SOUND: eventParm (%d) out of range\n", state->eventParm);
- break;
- }
- //check out the sound
- trap_GetConfigstring(CS_SOUNDS + state->eventParm, buf, sizeof(buf));
- //if falling into a death pit
- if (!strcmp(buf, "*falling1.wav")) {
- //if the bot has a personal teleporter
- if (bs->inventory[INVENTORY_TELEPORTER] > 0) {
- //use the holdable item
- trap_EA_Use(bs->client);
- }
- }
- }
- break;
- }
- case EV_FOOTSTEP:
- case EV_FOOTSTEP_METAL:
- case EV_FOOTSPLASH:
- case EV_FOOTWADE:
- case EV_SWIM:
- case EV_FALL_SHORT:
- case EV_FALL_MEDIUM:
- case EV_FALL_FAR:
- case EV_STEP_4:
- case EV_STEP_8:
- case EV_STEP_12:
- case EV_STEP_16:
- case EV_JUMP_PAD:
- case EV_JUMP:
- case EV_TAUNT:
- case EV_WATER_TOUCH:
- case EV_WATER_LEAVE:
- case EV_WATER_UNDER:
- case EV_WATER_CLEAR:
- case EV_ITEM_PICKUP:
- case EV_GLOBAL_ITEM_PICKUP:
- case EV_NOAMMO:
- case EV_CHANGE_WEAPON:
- case EV_FIRE_WEAPON:
- //FIXME: either add to sound queue or mark player as someone making noise
- break;
- case EV_USE_ITEM0:
- case EV_USE_ITEM1:
- case EV_USE_ITEM2:
- case EV_USE_ITEM3:
- case EV_USE_ITEM4:
- case EV_USE_ITEM5:
- case EV_USE_ITEM6:
- case EV_USE_ITEM7:
- case EV_USE_ITEM8:
- case EV_USE_ITEM9:
- case EV_USE_ITEM10:
- case EV_USE_ITEM11:
- case EV_USE_ITEM12:
- case EV_USE_ITEM13:
- case EV_USE_ITEM14:
- break;
- }
-}
-
-/*
-==================
-BotCheckSnapshot
-==================
-*/
-void BotCheckSnapshot(bot_state_t *bs) {
- int ent;
- entityState_t state;
-
- //remove all avoid spots
- trap_BotAddAvoidSpot(bs->ms, vec3_origin, 0, AVOID_CLEAR);
- //reset kamikaze body
- bs->kamikazebody = 0;
- //reset number of proxmines
- bs->numproxmines = 0;
- //
- ent = 0;
- while( ( ent = BotAI_GetSnapshotEntity( bs->client, ent, &state ) ) != -1 ) {
- //check the entity state for events
- BotCheckEvents(bs, &state);
- //check for grenades the bot should avoid
- BotCheckForGrenades(bs, &state);
- //
-
- //check for proximity mines which the bot should deactivate
- BotCheckForProxMines(bs, &state);
- //check for dead bodies with the kamikaze effect which should be gibbed
- BotCheckForKamikazeBody(bs, &state);
- }
- //check the player state for events
- BotAI_GetEntityState(bs->client, &state);
- //copy the player state events to the entity state
- state.event = bs->cur_ps.externalEvent;
- state.eventParm = bs->cur_ps.externalEventParm;
- //
- BotCheckEvents(bs, &state);
-}
-
-/*
-==================
-BotCheckAir
-==================
-*/
-void BotCheckAir(bot_state_t *bs) {
- if (bs->inventory[INVENTORY_ENVIRONMENTSUIT] <= 0) {
- if (trap_AAS_PointContents(bs->eye) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) {
- return;
- }
- }
- bs->lastair_time = FloatTime();
-}
-
-/*
-==================
-BotAlternateRoute
-==================
-*/
-bot_goal_t *BotAlternateRoute(bot_state_t *bs, bot_goal_t *goal) {
- int t;
-
- // if the bot has an alternative route goal
- if (bs->altroutegoal.areanum) {
- //
- if (bs->reachedaltroutegoal_time)
- return goal;
- // travel time towards alternative route goal
- t = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, bs->altroutegoal.areanum, bs->tfl);
- if (t && t < 20) {
- //BotAI_Print(PRT_MESSAGE, "reached alternate route goal\n");
- bs->reachedaltroutegoal_time = FloatTime();
- }
- memcpy(goal, &bs->altroutegoal, sizeof(bot_goal_t));
- return &bs->altroutegoal;
- }
- return goal;
-}
-
-/*
-==================
-BotGetAlternateRouteGoal
-==================
-*/
-int BotGetAlternateRouteGoal(bot_state_t *bs, int base) {
- aas_altroutegoal_t *altroutegoals;
- bot_goal_t *goal;
- int numaltroutegoals, rnd;
-
- if (base == TEAM_RED) {
- altroutegoals = red_altroutegoals;
- numaltroutegoals = red_numaltroutegoals;
- }
- else {
- altroutegoals = blue_altroutegoals;
- numaltroutegoals = blue_numaltroutegoals;
- }
- if (!numaltroutegoals)
- return qfalse;
- rnd = (float) random() * numaltroutegoals;
- if (rnd >= numaltroutegoals)
- rnd = numaltroutegoals-1;
- goal = &bs->altroutegoal;
- goal->areanum = altroutegoals[rnd].areanum;
- VectorCopy(altroutegoals[rnd].origin, goal->origin);
- VectorSet(goal->mins, -8, -8, -8);
- VectorSet(goal->maxs, 8, 8, 8);
- goal->entitynum = 0;
- goal->iteminfo = 0;
- goal->number = 0;
- goal->flags = 0;
- //
- bs->reachedaltroutegoal_time = 0;
- return qtrue;
-}
-
-/*
-==================
-BotSetupAlternateRouteGoals
-==================
-*/
-void BotSetupAlternativeRouteGoals(void) {
-
- if (altroutegoals_setup)
- return;
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- if (trap_BotGetLevelItemGoal(-1, "Neutral Flag", &ctf_neutralflag) < 0)
- BotAI_Print(PRT_WARNING, "no alt routes without Neutral Flag\n");
- if (ctf_neutralflag.areanum) {
- //
- red_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- ctf_neutralflag.origin, ctf_neutralflag.areanum,
- ctf_redflag.origin, ctf_redflag.areanum, TFL_DEFAULT,
- red_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- ctf_neutralflag.origin, ctf_neutralflag.areanum,
- ctf_blueflag.origin, ctf_blueflag.areanum, TFL_DEFAULT,
- blue_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- }
- }
- else if (gametype == GT_1FCTF) {
- //
- red_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- ctf_neutralflag.origin, ctf_neutralflag.areanum,
- ctf_redflag.origin, ctf_redflag.areanum, TFL_DEFAULT,
- red_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- ctf_neutralflag.origin, ctf_neutralflag.areanum,
- ctf_blueflag.origin, ctf_blueflag.areanum, TFL_DEFAULT,
- blue_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- }
- else if (gametype == GT_OBELISK) {
- if (trap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0)
- BotAI_Print(PRT_WARNING, "Obelisk without neutral obelisk\n");
- //
- red_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- neutralobelisk.origin, neutralobelisk.areanum,
- redobelisk.origin, redobelisk.areanum, TFL_DEFAULT,
- red_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- neutralobelisk.origin, neutralobelisk.areanum,
- blueobelisk.origin, blueobelisk.areanum, TFL_DEFAULT,
- blue_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- }
- else if (gametype == GT_HARVESTER) {
- if (untrap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0)
- BotAI_Print(PRT_WARNING, "Harvester without neutral obelisk\n");
- //
- red_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- neutralobelisk.origin, neutralobelisk.areanum,
- redobelisk.origin, redobelisk.areanum, TFL_DEFAULT,
- red_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- blue_numaltroutegoals = trap_AAS_AlternativeRouteGoals(
- neutralobelisk.origin, neutralobelisk.areanum,
- blueobelisk.origin, blueobelisk.areanum, TFL_DEFAULT,
- blue_altroutegoals, MAX_ALTROUTEGOALS,
- ALTROUTEGOAL_CLUSTERPORTALS|
- ALTROUTEGOAL_VIEWPORTALS);
- }
- altroutegoals_setup = qtrue;
-}
-
-/*
-==================
-BotDeathmatchAI
-==================
-*/
-void BotDeathmatchAI(bot_state_t *bs, float thinktime) {
- char gender[144], name[144], buf[144];
- char userinfo[MAX_INFO_STRING];
- int i;
-
- //if the bot has just been setup
- if (bs->setupcount > 0) {
- bs->setupcount--;
- if (bs->setupcount > 0) return;
- //get the gender characteristic
- trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, sizeof(gender));
- //set the bot gender
- trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo));
- Info_SetValueForKey(userinfo, "sex", gender);
- trap_SetUserinfo(bs->client, userinfo);
- //set the team
- if ( !bs->map_restart && g_gametype.integer != GT_TOURNAMENT ) {
- Com_sprintf(buf, sizeof(buf), "team %s", bs->settings.team);
- trap_EA_Command(bs->client, buf);
- }
- //set the chat gender
- if (gender[0] == 'm') trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE);
- else if (gender[0] == 'f') trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE);
- else trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS);
- //set the chat name
- ClientName(bs->client, name, sizeof(name));
- trap_BotSetChatName(bs->cs, name, bs->client);
- //
- bs->lastframe_health = bs->inventory[INVENTORY_HEALTH];
- bs->lasthitcount = bs->cur_ps.persistant[PERS_HITS];
- //
- bs->setupcount = 0;
- //
- BotSetupAlternativeRouteGoals();
- }
- //no ideal view set
- bs->flags &= ~BFL_IDEALVIEWSET;
- //
- if (!BotIntermission(bs)) {
- //set the teleport time
- BotSetTeleportTime(bs);
- //update some inventory values
- BotUpdateInventory(bs);
- //check out the snapshot
- BotCheckSnapshot(bs);
- //check for air
- BotCheckAir(bs);
- }
- //check the console messages
- BotCheckConsoleMessages(bs);
- //if not in the intermission and not in observer mode
- if (!BotIntermission(bs) && !BotIsObserver(bs)) {
- //do team AI
- BotTeamAI(bs);
- }
- //if the bot has no ai node
- if (!bs->ainode) {
- AIEnter_Seek_LTG(bs, "BotDeathmatchAI: no ai node");
- }
- //if the bot entered the game less than 8 seconds ago
- if (!bs->entergamechat && bs->entergame_time > FloatTime() - 8) {
- if (BotChat_EnterGame(bs)) {
- bs->stand_time = FloatTime() + BotChatTime(bs);
- AIEnter_Stand(bs, "BotDeathmatchAI: chat enter game");
- }
- bs->entergamechat = qtrue;
- }
- //reset the node switches from the previous frame
- BotResetNodeSwitches();
- //execute AI nodes
- for (i = 0; i < MAX_NODESWITCHES; i++) {
- if (bs->ainode(bs)) break;
- }
- //if the bot removed itself :)
- if (!bs->inuse) return;
- //if the bot executed too many AI nodes
- //Sago: FIXME - Outcommented this test... this is wrong
- #ifdef DEBUG
- if (i >= MAX_NODESWITCHES) {
- trap_BotDumpGoalStack(bs->gs);
- trap_BotDumpAvoidGoals(bs->gs);
- BotDumpNodeSwitches(bs);
- ClientName(bs->client, name, sizeof(name));
- BotAI_Print(PRT_ERROR, "%s at %1.1f switched more than %d AI nodes\n", name, FloatTime(), MAX_NODESWITCHES);
- }
- #endif
- //
- bs->lastframe_health = bs->inventory[INVENTORY_HEALTH];
- bs->lasthitcount = bs->cur_ps.persistant[PERS_HITS];
-}
-
-/*
-==================
-BotSetEntityNumForGoalWithModel
-==================
-*/
-void BotSetEntityNumForGoalWithModel(bot_goal_t *goal, int eType, char *modelname) {
- gentity_t *ent;
- int i, modelindex;
- vec3_t dir;
-
- modelindex = G_ModelIndex( modelname );
- ent = &g_entities[0];
- for (i = 0; i < level.num_entities; i++, ent++) {
- if ( !ent->inuse ) {
- continue;
- }
- if ( eType && ent->s.eType != eType) {
- continue;
- }
- if (ent->s.modelindex != modelindex) {
- continue;
- }
- VectorSubtract(goal->origin, ent->s.origin, dir);
- if (VectorLengthSquared(dir) < Square(10)) {
- goal->entitynum = i;
- return;
- }
- }
-}
-
-/*
-==================
-BotSetEntityNumForGoal
-==================
-*/
-void BotSetEntityNumForGoal(bot_goal_t *goal, char *classname) {
- gentity_t *ent;
- int i;
- vec3_t dir;
-
- ent = &g_entities[0];
- for (i = 0; i < level.num_entities; i++, ent++) {
- if ( !ent->inuse ) {
- continue;
- }
- if ( !Q_stricmp(ent->classname, classname) ) {
- continue;
- }
- VectorSubtract(goal->origin, ent->s.origin, dir);
- if (VectorLengthSquared(dir) < Square(10)) {
- goal->entitynum = i;
- return;
- }
- }
-}
-
-/*
-==================
-BotGoalForBSPEntity
-==================
-*/
-int BotGoalForBSPEntity( char *classname, bot_goal_t *goal ) {
- char value[MAX_INFO_STRING];
- vec3_t origin, start, end;
- int ent, numareas, areas[10];
-
- memset(goal, 0, sizeof(bot_goal_t));
- for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) {
- if (!trap_AAS_ValueForBSPEpairKey(ent, "classname", value, sizeof(value)))
- continue;
- if (!strcmp(value, classname)) {
- if (!trap_AAS_VectorForBSPEpairKey(ent, "origin", origin))
- return qfalse;
- VectorCopy(origin, goal->origin);
- VectorCopy(origin, start);
- start[2] -= 32;
- VectorCopy(origin, end);
- end[2] += 32;
- numareas = trap_AAS_TraceAreas(start, end, areas, NULL, 10);
- if (!numareas)
- return qfalse;
- goal->areanum = areas[0];
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-==================
-BotSetupDeathmatchAI
-==================
-*/
-void BotSetupDeathmatchAI(void) {
- int ent, modelnum,i;
- char model[128];
-
- gametype = trap_Cvar_VariableIntegerValue("g_gametype");
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- trap_Cvar_Register(&bot_rocketjump, "bot_rocketjump", "1", 0);
- trap_Cvar_Register(&bot_grapple, "bot_grapple", "0", 0);
- trap_Cvar_Register(&bot_fastchat, "bot_fastchat", "0", 0);
- trap_Cvar_Register(&bot_nochat, "bot_nochat", "0", 0);
- trap_Cvar_Register(&bot_testrchat, "bot_testrchat", "0", 0);
- trap_Cvar_Register(&bot_challenge, "bot_challenge", "0", 0);
- trap_Cvar_Register(&bot_predictobstacles, "bot_predictobstacles", "1", 0);
- trap_Cvar_Register(&g_spSkill, "g_spSkill", "2", 0);
- //
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- if (untrap_BotGetLevelItemGoal(-1, "Red Flag", &ctf_redflag) < 0)
- BotAI_Print(PRT_WARNING, "CTF without Red Flag\n");
- if (untrap_BotGetLevelItemGoal(-1, "Blue Flag", &ctf_blueflag) < 0)
- BotAI_Print(PRT_WARNING, "CTF without Blue Flag\n");
- }
- else if (gametype == GT_DOUBLE_D) {
- if (untrap_BotGetLevelItemGoal(-1, "Red Flag", &ctf_redflag) < 0)
- BotAI_Print(PRT_WARNING, "DD without Point A\n");
- if (untrap_BotGetLevelItemGoal(-1, "Blue Flag", &ctf_blueflag) < 0)
- BotAI_Print(PRT_WARNING, "DD without Point B\n");
- }
- else if (gametype == GT_DOMINATION) {
- ent = untrap_BotGetLevelItemGoal(-1, "Domination point", &dom_points_bot[0]);
- if(ent < 0)
- BotAI_Print(PRT_WARNING, "Domination without a single domination point\n");
- else
- BotSetEntityNumForGoal(&dom_points_bot[0], va("domination_point%i",0) );
- for(i=1;i<level.domination_points_count;i++) {
- //Find next from the privius found entity
- ent = untrap_BotGetLevelItemGoal(ent, "Domination point", &dom_points_bot[i]);
- if(ent < 0)
- BotAI_Print(PRT_WARNING, "Domination point %i not found!\n",i);
- else
- BotSetEntityNumForGoal(&dom_points_bot[0], va("domination_point%i",i) );
- }
- //MAX_DOMINATION_POINTS
- }
- else if (gametype == GT_1FCTF) {
- if (untrap_BotGetLevelItemGoal(-1, "Neutral Flag", &ctf_neutralflag) < 0)
- BotAI_Print(PRT_WARNING, "One Flag CTF without Neutral Flag\n");
- if (untrap_BotGetLevelItemGoal(-1, "Red Flag", &ctf_redflag) < 0)
- BotAI_Print(PRT_WARNING, "CTF without Red Flag\n");
- if (untrap_BotGetLevelItemGoal(-1, "Blue Flag", &ctf_blueflag) < 0)
- BotAI_Print(PRT_WARNING, "CTF without Blue Flag\n");
- }
- else if (gametype == GT_OBELISK) {
- if (untrap_BotGetLevelItemGoal(-1, "Red Obelisk", &redobelisk) < 0)
- BotAI_Print(PRT_WARNING, "Obelisk without red obelisk\n");
- BotSetEntityNumForGoal(&redobelisk, "team_redobelisk");
- if (untrap_BotGetLevelItemGoal(-1, "Blue Obelisk", &blueobelisk) < 0)
- BotAI_Print(PRT_WARNING, "Obelisk without blue obelisk\n");
- BotSetEntityNumForGoal(&blueobelisk, "team_blueobelisk");
- }
- else if (gametype == GT_HARVESTER) {
- if (untrap_BotGetLevelItemGoal(-1, "Red Obelisk", &redobelisk) < 0)
- BotAI_Print(PRT_WARNING, "Harvester without red obelisk\n");
- BotSetEntityNumForGoal(&redobelisk, "team_redobelisk");
- if (untrap_BotGetLevelItemGoal(-1, "Blue Obelisk", &blueobelisk) < 0)
- BotAI_Print(PRT_WARNING, "Harvester without blue obelisk\n");
- BotSetEntityNumForGoal(&blueobelisk, "team_blueobelisk");
- if (untrap_BotGetLevelItemGoal(-1, "Neutral Obelisk", &neutralobelisk) < 0)
- BotAI_Print(PRT_WARNING, "Harvester without neutral obelisk\n");
- BotSetEntityNumForGoal(&neutralobelisk, "team_neutralobelisk");
- }
-
- max_bspmodelindex = 0;
- for (ent = trap_AAS_NextBSPEntity(0); ent; ent = trap_AAS_NextBSPEntity(ent)) {
- if (!trap_AAS_ValueForBSPEpairKey(ent, "model", model, sizeof(model))) continue;
- if (model[0] == '*') {
- modelnum = atoi(model+1);
- if (modelnum > max_bspmodelindex)
- max_bspmodelindex = modelnum;
- }
- }
- //initialize the waypoint heap
- BotInitWaypoints();
-}
-
-/*
-==================
-BotShutdownDeathmatchAI
-==================
-*/
-void BotShutdownDeathmatchAI(void) {
- altroutegoals_setup = qfalse;
-}
diff --git a/game/code/game/ai_main.c b/game/code/game/ai_main.c
deleted file mode 100644
index 7b88b30..0000000
--- a/game/code/game/ai_main.c
+++ /dev/null
@@ -1,1722 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_main.c
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /MissionPack/code/game/ai_main.c $
- *
- *****************************************************************************/
-
-
-#include "g_local.h"
-#include "../qcommon/q_shared.h"
-#include "../botlib/botlib.h" //bot lib interface
-#include "../botlib/be_aas.h"
-#include "../botlib/be_ea.h"
-#include "../botlib/be_ai_char.h"
-#include "../botlib/be_ai_chat.h"
-#include "../botlib/be_ai_gen.h"
-#include "../botlib/be_ai_goal.h"
-#include "../botlib/be_ai_move.h"
-#include "../botlib/be_ai_weap.h"
-//
-#include "ai_main.h"
-#include "ai_dmq3.h"
-#include "ai_chat.h"
-#include "ai_cmd.h"
-#include "ai_dmnet.h"
-#include "ai_vcmd.h"
-
-//
-#include "chars.h"
-#include "inv.h"
-#include "syn.h"
-
-#ifndef MAX_PATH
-#define MAX_PATH 144
-#endif
-
-
-//bot states
-bot_state_t *botstates[MAX_CLIENTS];
-//number of bots
-int numbots;
-//floating point time
-float floattime;
-//time to do a regular update
-float regularupdate_time;
-//
-int bot_interbreed;
-int bot_interbreedmatchcount;
-//
-vmCvar_t bot_thinktime;
-vmCvar_t bot_memorydump;
-vmCvar_t bot_saveroutingcache;
-vmCvar_t bot_pause;
-vmCvar_t bot_report;
-vmCvar_t bot_testsolid;
-vmCvar_t bot_testclusters;
-vmCvar_t bot_developer;
-vmCvar_t bot_interbreedchar;
-vmCvar_t bot_interbreedbots;
-vmCvar_t bot_interbreedcycle;
-vmCvar_t bot_interbreedwrite;
-
-
-void ExitLevel( void );
-
-
-/*
-==================
-BotAI_Print
-==================
-*/
-void QDECL BotAI_Print(int type, char *fmt, ...) {
- char str[2048];
- va_list ap;
-
- va_start(ap, fmt);
- Q_vsnprintf(str, sizeof(str), fmt, ap);
- va_end(ap);
-
- switch(type) {
- case PRT_MESSAGE: {
- G_Printf("%s", str);
- break;
- }
- case PRT_WARNING: {
- G_Printf( S_COLOR_YELLOW "Warning: %s", str );
- break;
- }
- case PRT_ERROR: {
- G_Printf( S_COLOR_RED "Error: %s", str );
- break;
- }
- case PRT_FATAL: {
- G_Printf( S_COLOR_RED "Fatal: %s", str );
- break;
- }
- case PRT_EXIT: {
- G_Error( S_COLOR_RED "Exit: %s", str );
- break;
- }
- default: {
- G_Printf( "unknown print type\n" );
- break;
- }
- }
-}
-
-
-/*
-==================
-BotAI_Trace
-==================
-*/
-void BotAI_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) {
- trace_t trace;
-
- trap_Trace(&trace, start, mins, maxs, end, passent, contentmask);
- //copy the trace information
- bsptrace->allsolid = trace.allsolid;
- bsptrace->startsolid = trace.startsolid;
- bsptrace->fraction = trace.fraction;
- VectorCopy(trace.endpos, bsptrace->endpos);
- bsptrace->plane.dist = trace.plane.dist;
- VectorCopy(trace.plane.normal, bsptrace->plane.normal);
- bsptrace->plane.signbits = trace.plane.signbits;
- bsptrace->plane.type = trace.plane.type;
- bsptrace->surface.value = trace.surfaceFlags;
- bsptrace->ent = trace.entityNum;
- bsptrace->exp_dist = 0;
- bsptrace->sidenum = 0;
- bsptrace->contents = 0;
-}
-
-/*
-==================
-BotAI_GetClientState
-==================
-*/
-int BotAI_GetClientState( int clientNum, playerState_t *state ) {
- gentity_t *ent;
-
- ent = &g_entities[clientNum];
- if ( !ent->inuse ) {
- return qfalse;
- }
- if ( !ent->client ) {
- return qfalse;
- }
-
- memcpy( state, &ent->client->ps, sizeof(playerState_t) );
- return qtrue;
-}
-
-/*
-==================
-BotAI_GetEntityState
-==================
-*/
-int BotAI_GetEntityState( int entityNum, entityState_t *state ) {
- gentity_t *ent;
-
- ent = &g_entities[entityNum];
- memset( state, 0, sizeof(entityState_t) );
- if (!ent->inuse) return qfalse;
- if (!ent->r.linked) return qfalse;
- if ( !(g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_LMS ||g_instantgib.integer || g_rockets.integer || g_elimination_allgametypes.integer || g_gametype.integer==GT_CTF_ELIMINATION)
- && (ent->r.svFlags & SVF_NOCLIENT) ) return qfalse;
- memcpy( state, &ent->s, sizeof(entityState_t) );
- return qtrue;
-}
-
-/*
-==================
-BotAI_GetSnapshotEntity
-==================
-*/
-int BotAI_GetSnapshotEntity( int clientNum, int sequence, entityState_t *state ) {
- int entNum;
-
- entNum = trap_BotGetSnapshotEntity( clientNum, sequence );
- if ( entNum == -1 ) {
- memset(state, 0, sizeof(entityState_t));
- return -1;
- }
-
- BotAI_GetEntityState( entNum, state );
-
- return sequence + 1;
-}
-
-/*
-==================
-BotAI_BotInitialChat
-==================
-*/
-void QDECL BotAI_BotInitialChat( bot_state_t *bs, char *type, ... ) {
- int i, mcontext;
- va_list ap;
- char *p;
- char *vars[MAX_MATCHVARIABLES];
-
- memset(vars, 0, sizeof(vars));
- va_start(ap, type);
- p = va_arg(ap, char *);
- for (i = 0; i < MAX_MATCHVARIABLES; i++) {
- if( !p ) {
- break;
- }
- vars[i] = p;
- p = va_arg(ap, char *);
- }
- va_end(ap);
-
- mcontext = BotSynonymContext(bs);
-
- trap_BotInitialChat( bs->cs, type, mcontext, vars[0], vars[1], vars[2], vars[3], vars[4], vars[5], vars[6], vars[7] );
-}
-
-
-/*
-==================
-BotTestAAS
-==================
-*/
-void BotTestAAS(vec3_t origin) {
- int areanum;
- aas_areainfo_t info;
-
- trap_Cvar_Update(&bot_testsolid);
- trap_Cvar_Update(&bot_testclusters);
- if (bot_testsolid.integer) {
- if (!trap_AAS_Initialized()) return;
- areanum = BotPointAreaNum(origin);
- if (areanum) BotAI_Print(PRT_MESSAGE, "\remtpy area");
- else BotAI_Print(PRT_MESSAGE, "\r^1SOLID area");
- }
- else if (bot_testclusters.integer) {
- if (!trap_AAS_Initialized()) return;
- areanum = BotPointAreaNum(origin);
- if (!areanum)
- BotAI_Print(PRT_MESSAGE, "\r^1Solid! ");
- else {
- trap_AAS_AreaInfo(areanum, &info);
- BotAI_Print(PRT_MESSAGE, "\rarea %d, cluster %d ", areanum, info.cluster);
- }
- }
-}
-
-/*
-==================
-BotReportStatus
-==================
-*/
-void BotReportStatus(bot_state_t *bs) {
- char goalname[MAX_MESSAGE_SIZE];
- char netname[MAX_MESSAGE_SIZE];
- char *leader, flagstatus[32];
- //
- ClientName(bs->client, netname, sizeof(netname));
- if (Q_stricmp(netname, bs->teamleader) == 0) leader = "L";
- else leader = " ";
-
- strcpy(flagstatus, " ");
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- if (BotCTFCarryingFlag(bs)) {
- if (BotTeam(bs) == TEAM_RED) strcpy(flagstatus, S_COLOR_RED"F ");
- else strcpy(flagstatus, S_COLOR_BLUE"F ");
- }
- }
- else if (gametype == GT_1FCTF) {
- if (Bot1FCTFCarryingFlag(bs)) {
- if (BotTeam(bs) == TEAM_RED) strcpy(flagstatus, S_COLOR_RED"F ");
- else strcpy(flagstatus, S_COLOR_BLUE"F ");
- }
- }
- else if (gametype == GT_HARVESTER) {
- if (BotHarvesterCarryingCubes(bs)) {
- if (BotTeam(bs) == TEAM_RED) Com_sprintf(flagstatus, sizeof(flagstatus), S_COLOR_RED"%2d", bs->inventory[INVENTORY_REDCUBE]);
- else Com_sprintf(flagstatus, sizeof(flagstatus), S_COLOR_BLUE"%2d", bs->inventory[INVENTORY_BLUECUBE]);
- }
- }
-
- switch(bs->ltgtype) {
- case LTG_TEAMHELP:
- {
- EasyClientName(bs->teammate, goalname, sizeof(goalname));
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: helping %s\n", netname, leader, flagstatus, goalname);
- break;
- }
- case LTG_TEAMACCOMPANY:
- {
- EasyClientName(bs->teammate, goalname, sizeof(goalname));
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: accompanying %s\n", netname, leader, flagstatus, goalname);
- break;
- }
- case LTG_DEFENDKEYAREA:
- {
- trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: defending %s\n", netname, leader, flagstatus, goalname);
- break;
- }
- case LTG_GETITEM:
- {
- trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: getting item %s\n", netname, leader, flagstatus, goalname);
- break;
- }
- case LTG_KILL:
- {
- ClientName(bs->teamgoal.entitynum, goalname, sizeof(goalname));
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: killing %s\n", netname, leader, flagstatus, goalname);
- break;
- }
- case LTG_CAMP:
- case LTG_CAMPORDER:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: camping\n", netname, leader, flagstatus);
- break;
- }
- case LTG_PATROL:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: patrolling\n", netname, leader, flagstatus);
- break;
- }
- case LTG_GETFLAG:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: capturing flag\n", netname, leader, flagstatus);
- break;
- }
- case LTG_RUSHBASE:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: rushing base\n", netname, leader, flagstatus);
- break;
- }
- case LTG_RETURNFLAG:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: returning flag\n", netname, leader, flagstatus);
- break;
- }
- case LTG_ATTACKENEMYBASE:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: attacking the enemy base\n", netname, leader, flagstatus);
- break;
- }
- case LTG_HARVEST:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: harvesting\n", netname, leader, flagstatus);
- break;
- }
- case LTG_POINTA:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: going for point A\n", netname, leader, flagstatus);
- break;
- }
- case LTG_POINTB:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: going for point B\n", netname, leader, flagstatus);
- break;
- }
- default:
- {
- BotAI_Print(PRT_MESSAGE, "%-20s%s%s: roaming\n", netname, leader, flagstatus);
- break;
- }
- }
-}
-
-/*
-==================
-BotTeamplayReport
-==================
-*/
-void BotTeamplayReport(void) {
- int i;
- char buf[MAX_INFO_STRING];
-
- BotAI_Print(PRT_MESSAGE, S_COLOR_RED"RED\n");
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- //
- if ( !botstates[i] || !botstates[i]->inuse ) continue;
- //
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_RED) {
- BotReportStatus(botstates[i]);
- }
- }
- BotAI_Print(PRT_MESSAGE, S_COLOR_BLUE"BLUE\n");
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- //
- if ( !botstates[i] || !botstates[i]->inuse ) continue;
- //
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_BLUE) {
- BotReportStatus(botstates[i]);
- }
- }
-}
-
-/*
-==================
-BotSetInfoConfigString
-==================
-*/
-void BotSetInfoConfigString(bot_state_t *bs) {
- char goalname[MAX_MESSAGE_SIZE];
- char netname[MAX_MESSAGE_SIZE];
- char action[MAX_MESSAGE_SIZE];
- char *leader, carrying[32], *cs;
- bot_goal_t goal;
- //
- ClientName(bs->client, netname, sizeof(netname));
- if (Q_stricmp(netname, bs->teamleader) == 0) leader = "L";
- else leader = " ";
-
- strcpy(carrying, " ");
- if (gametype == GT_CTF || gametype == GT_CTF_ELIMINATION) {
- if (BotCTFCarryingFlag(bs)) {
- strcpy(carrying, "F ");
- }
- }
- else if (gametype == GT_1FCTF) {
- if (Bot1FCTFCarryingFlag(bs)) {
- strcpy(carrying, "F ");
- }
- }
- else if (gametype == GT_HARVESTER) {
- if (BotHarvesterCarryingCubes(bs)) {
- if (BotTeam(bs) == TEAM_RED) Com_sprintf(carrying, sizeof(carrying), "%2d", bs->inventory[INVENTORY_REDCUBE]);
- else Com_sprintf(carrying, sizeof(carrying), "%2d", bs->inventory[INVENTORY_BLUECUBE]);
- }
- }
-
- switch(bs->ltgtype) {
- case LTG_TEAMHELP:
- {
- EasyClientName(bs->teammate, goalname, sizeof(goalname));
- Com_sprintf(action, sizeof(action), "helping %s", goalname);
- break;
- }
- case LTG_TEAMACCOMPANY:
- {
- EasyClientName(bs->teammate, goalname, sizeof(goalname));
- Com_sprintf(action, sizeof(action), "accompanying %s", goalname);
- break;
- }
- case LTG_DEFENDKEYAREA:
- {
- trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
- Com_sprintf(action, sizeof(action), "defending %s", goalname);
- break;
- }
- case LTG_GETITEM:
- {
- trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
- Com_sprintf(action, sizeof(action), "getting item %s", goalname);
- break;
- }
- case LTG_KILL:
- {
- ClientName(bs->teamgoal.entitynum, goalname, sizeof(goalname));
- Com_sprintf(action, sizeof(action), "killing %s", goalname);
- break;
- }
- case LTG_CAMP:
- case LTG_CAMPORDER:
- {
- Com_sprintf(action, sizeof(action), "camping");
- break;
- }
- case LTG_PATROL:
- {
- Com_sprintf(action, sizeof(action), "patrolling");
- break;
- }
- case LTG_GETFLAG:
- {
- Com_sprintf(action, sizeof(action), "capturing flag");
- break;
- }
- case LTG_RUSHBASE:
- {
- Com_sprintf(action, sizeof(action), "rushing base");
- break;
- }
- case LTG_RETURNFLAG:
- {
- Com_sprintf(action, sizeof(action), "returning flag");
- break;
- }
- case LTG_ATTACKENEMYBASE:
- {
- Com_sprintf(action, sizeof(action), "attacking the enemy base");
- break;
- }
- case LTG_HARVEST:
- {
- Com_sprintf(action, sizeof(action), "harvesting");
- break;
- }
- case LTG_POINTA:
- {
- Com_sprintf(action, sizeof(action), "going for point A");
- break;
- }
- case LTG_POINTB:
- {
- Com_sprintf(action, sizeof(action), "going for point B");
- break;
- }
- default:
- {
- trap_BotGetTopGoal(bs->gs, &goal);
- trap_BotGoalName(goal.number, goalname, sizeof(goalname));
- Com_sprintf(action, sizeof(action), "roaming %s", goalname);
- break;
- }
- }
- cs = va("l\\%s\\c\\%s\\a\\%s",
- leader,
- carrying,
- action);
- trap_SetConfigstring (CS_BOTINFO + bs->client, cs);
-}
-
-/*
-==============
-BotUpdateInfoConfigStrings
-==============
-*/
-void BotUpdateInfoConfigStrings(void) {
- int i;
- char buf[MAX_INFO_STRING];
-
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- //
- if ( !botstates[i] || !botstates[i]->inuse )
- continue;
- //
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n")))
- continue;
- BotSetInfoConfigString(botstates[i]);
- }
-}
-
-/*
-==============
-BotInterbreedBots
-==============
-*/
-void BotInterbreedBots(void) {
- float ranks[MAX_CLIENTS];
- int parent1, parent2, child;
- int i;
-
- // get rankings for all the bots
- for (i = 0; i < MAX_CLIENTS; i++) {
- if ( botstates[i] && botstates[i]->inuse ) {
- ranks[i] = botstates[i]->num_kills * 2 - botstates[i]->num_deaths;
- }
- else {
- ranks[i] = -1;
- }
- }
-
- if (trap_GeneticParentsAndChildSelection(MAX_CLIENTS, ranks, &parent1, &parent2, &child)) {
- trap_BotInterbreedGoalFuzzyLogic(botstates[parent1]->gs, botstates[parent2]->gs, botstates[child]->gs);
- trap_BotMutateGoalFuzzyLogic(botstates[child]->gs, 1);
- }
- // reset the kills and deaths
- for (i = 0; i < MAX_CLIENTS; i++) {
- if (botstates[i] && botstates[i]->inuse) {
- botstates[i]->num_kills = 0;
- botstates[i]->num_deaths = 0;
- }
- }
-}
-
-/*
-==============
-BotWriteInterbreeded
-==============
-*/
-void BotWriteInterbreeded(char *filename) {
- float rank, bestrank;
- int i, bestbot;
-
- bestrank = 0;
- bestbot = -1;
- // get the best bot
- for (i = 0; i < MAX_CLIENTS; i++) {
- if ( botstates[i] && botstates[i]->inuse ) {
- rank = botstates[i]->num_kills * 2 - botstates[i]->num_deaths;
- }
- else {
- rank = -1;
- }
- if (rank > bestrank) {
- bestrank = rank;
- bestbot = i;
- }
- }
- if (bestbot >= 0) {
- //write out the new goal fuzzy logic
- trap_BotSaveGoalFuzzyLogic(botstates[bestbot]->gs, filename);
- }
-}
-
-/*
-==============
-BotInterbreedEndMatch
-
-add link back into ExitLevel?
-==============
-*/
-void BotInterbreedEndMatch(void) {
-
- if (!bot_interbreed) return;
- bot_interbreedmatchcount++;
- if (bot_interbreedmatchcount >= bot_interbreedcycle.integer) {
- bot_interbreedmatchcount = 0;
- //
- trap_Cvar_Update(&bot_interbreedwrite);
- if (strlen(bot_interbreedwrite.string)) {
- BotWriteInterbreeded(bot_interbreedwrite.string);
- trap_Cvar_Set("bot_interbreedwrite", "");
- }
- BotInterbreedBots();
- }
-}
-
-/*
-==============
-BotInterbreeding
-==============
-*/
-void BotInterbreeding(void) {
- int i;
-
- trap_Cvar_Update(&bot_interbreedchar);
- if (!strlen(bot_interbreedchar.string)) return;
- //make sure we are in tournament mode
- if (gametype != GT_TOURNAMENT) {
- trap_Cvar_Set("g_gametype", va("%d", GT_TOURNAMENT));
- ExitLevel();
- return;
- }
- //shutdown all the bots
- for (i = 0; i < MAX_CLIENTS; i++) {
- if (botstates[i] && botstates[i]->inuse) {
- BotAIShutdownClient(botstates[i]->client, qfalse);
- }
- }
- //make sure all item weight configs are reloaded and Not shared
- trap_BotLibVarSet("bot_reloadcharacters", "1");
- //add a number of bots using the desired bot character
- for (i = 0; i < bot_interbreedbots.integer; i++) {
- trap_SendConsoleCommand( EXEC_INSERT, va("addbot %s 4 free %i %s%d\n",
- bot_interbreedchar.string, i * 50, bot_interbreedchar.string, i) );
- }
- //
- trap_Cvar_Set("bot_interbreedchar", "");
- bot_interbreed = qtrue;
-}
-
-/*
-==============
-BotEntityInfo
-==============
-*/
-void BotEntityInfo(int entnum, aas_entityinfo_t *info) {
- trap_AAS_EntityInfo(entnum, info);
-}
-
-/*
-==============
-NumBots
-==============
-*/
-int NumBots(void) {
- return numbots;
-}
-
-/*
-==============
-BotTeamLeader
-==============
-*/
-int BotTeamLeader(bot_state_t *bs) {
- int leader;
-
- leader = ClientFromName(bs->teamleader);
- if (leader < 0) return qfalse;
- if (!botstates[leader] || !botstates[leader]->inuse) return qfalse;
- return qtrue;
-}
-
-/*
-==============
-AngleDifference
-==============
-*/
-float AngleDifference(float ang1, float ang2) {
- float diff;
-
- diff = ang1 - ang2;
- if (ang1 > ang2) {
- if (diff > 180.0) diff -= 360.0;
- }
- else {
- if (diff < -180.0) diff += 360.0;
- }
- return diff;
-}
-
-/*
-==============
-BotChangeViewAngle
-==============
-*/
-float BotChangeViewAngle(float angle, float ideal_angle, float speed) {
- float move;
-
- angle = AngleMod(angle);
- ideal_angle = AngleMod(ideal_angle);
- if (angle == ideal_angle) return angle;
- move = ideal_angle - angle;
- if (ideal_angle > angle) {
- if (move > 180.0) move -= 360.0;
- }
- else {
- if (move < -180.0) move += 360.0;
- }
- if (move > 0) {
- if (move > speed) move = speed;
- }
- else {
- if (move < -speed) move = -speed;
- }
- return AngleMod(angle + move);
-}
-
-/*
-==============
-BotChangeViewAngles
-==============
-*/
-void BotChangeViewAngles(bot_state_t *bs, float thinktime) {
- float diff, factor, maxchange, anglespeed, disired_speed;
- int i;
-
- if (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360;
- //
- if (bs->enemy >= 0) {
- factor = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_FACTOR, 0.01f, 1);
- maxchange = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_MAXCHANGE, 1, 1800);
- }
- else {
- factor = 0.05f;
- maxchange = 360;
- }
- if (maxchange < 240) maxchange = 240;
- maxchange *= thinktime;
- for (i = 0; i < 2; i++) {
- //
- if (bot_challenge.integer) {
- //smooth slowdown view model
- diff = abs(AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]));
- anglespeed = diff * factor;
- if (anglespeed > maxchange) anglespeed = maxchange;
- bs->viewangles[i] = BotChangeViewAngle(bs->viewangles[i],
- bs->ideal_viewangles[i], anglespeed);
- }
- else {
- //over reaction view model
- bs->viewangles[i] = AngleMod(bs->viewangles[i]);
- bs->ideal_viewangles[i] = AngleMod(bs->ideal_viewangles[i]);
- diff = AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]);
- disired_speed = diff * factor;
- bs->viewanglespeed[i] += (bs->viewanglespeed[i] - disired_speed);
- if (bs->viewanglespeed[i] > 180) bs->viewanglespeed[i] = maxchange;
- if (bs->viewanglespeed[i] < -180) bs->viewanglespeed[i] = -maxchange;
- anglespeed = bs->viewanglespeed[i];
- if (anglespeed > maxchange) anglespeed = maxchange;
- if (anglespeed < -maxchange) anglespeed = -maxchange;
- bs->viewangles[i] += anglespeed;
- bs->viewangles[i] = AngleMod(bs->viewangles[i]);
- //demping
- bs->viewanglespeed[i] *= 0.45 * (1 - factor);
- }
- //BotAI_Print(PRT_MESSAGE, "ideal_angles %f %f\n", bs->ideal_viewangles[0], bs->ideal_viewangles[1], bs->ideal_viewangles[2]);`
- //bs->viewangles[i] = bs->ideal_viewangles[i];
- }
- //bs->viewangles[PITCH] = 0;
- if (bs->viewangles[PITCH] > 180) bs->viewangles[PITCH] -= 360;
- //elementary action: view
- trap_EA_View(bs->client, bs->viewangles);
-}
-
-/*
-==============
-BotInputToUserCommand
-==============
-*/
-void BotInputToUserCommand(bot_input_t *bi, usercmd_t *ucmd, int delta_angles[3], int time) {
- vec3_t angles, forward, right;
- short temp;
- int j;
-
- //clear the whole structure
- memset(ucmd, 0, sizeof(usercmd_t));
- //
- //Com_Printf("dir = %f %f %f speed = %f\n", bi->dir[0], bi->dir[1], bi->dir[2], bi->speed);
- //the duration for the user command in milli seconds
- ucmd->serverTime = time;
- //
- if (bi->actionflags & ACTION_DELAYEDJUMP) {
- bi->actionflags |= ACTION_JUMP;
- bi->actionflags &= ~ACTION_DELAYEDJUMP;
- }
- //set the buttons
- if (bi->actionflags & ACTION_RESPAWN) ucmd->buttons = BUTTON_ATTACK;
- if (bi->actionflags & ACTION_ATTACK) ucmd->buttons |= BUTTON_ATTACK;
- if (bi->actionflags & ACTION_TALK) ucmd->buttons |= BUTTON_TALK;
- if (bi->actionflags & ACTION_GESTURE) ucmd->buttons |= BUTTON_GESTURE;
- if (bi->actionflags & ACTION_USE) ucmd->buttons |= BUTTON_USE_HOLDABLE;
- if (bi->actionflags & ACTION_WALK) ucmd->buttons |= BUTTON_WALKING;
- if (bi->actionflags & ACTION_AFFIRMATIVE) ucmd->buttons |= BUTTON_AFFIRMATIVE;
- if (bi->actionflags & ACTION_NEGATIVE) ucmd->buttons |= BUTTON_NEGATIVE;
- if (bi->actionflags & ACTION_GETFLAG) ucmd->buttons |= BUTTON_GETFLAG;
- if (bi->actionflags & ACTION_GUARDBASE) ucmd->buttons |= BUTTON_GUARDBASE;
- if (bi->actionflags & ACTION_PATROL) ucmd->buttons |= BUTTON_PATROL;
- if (bi->actionflags & ACTION_FOLLOWME) ucmd->buttons |= BUTTON_FOLLOWME;
- //
- ucmd->weapon = bi->weapon;
- //set the view angles
- //NOTE: the ucmd->angles are the angles WITHOUT the delta angles
- ucmd->angles[PITCH] = ANGLE2SHORT(bi->viewangles[PITCH]);
- ucmd->angles[YAW] = ANGLE2SHORT(bi->viewangles[YAW]);
- ucmd->angles[ROLL] = ANGLE2SHORT(bi->viewangles[ROLL]);
- //subtract the delta angles
- for (j = 0; j < 3; j++) {
- temp = ucmd->angles[j] - delta_angles[j];
- /*NOTE: disabled because temp should be mod first
- if ( j == PITCH ) {
- // don't let the player look up or down more than 90 degrees
- if ( temp > 16000 ) temp = 16000;
- else if ( temp < -16000 ) temp = -16000;
- }
- */
- ucmd->angles[j] = temp;
- }
- //NOTE: movement is relative to the REAL view angles
- //get the horizontal forward and right vector
- //get the pitch in the range [-180, 180]
- if (bi->dir[2]) angles[PITCH] = bi->viewangles[PITCH];
- else angles[PITCH] = 0;
- angles[YAW] = bi->viewangles[YAW];
- angles[ROLL] = 0;
- AngleVectors(angles, forward, right, NULL);
- //bot input speed is in the range [0, 400]
- bi->speed = bi->speed * 127 / 400;
- //set the view independent movement
- ucmd->forwardmove = DotProduct(forward, bi->dir) * bi->speed;
- ucmd->rightmove = DotProduct(right, bi->dir) * bi->speed;
- ucmd->upmove = abs(forward[2]) * bi->dir[2] * bi->speed;
- //normal keyboard movement
- if (bi->actionflags & ACTION_MOVEFORWARD) ucmd->forwardmove += 127;
- if (bi->actionflags & ACTION_MOVEBACK) ucmd->forwardmove -= 127;
- if (bi->actionflags & ACTION_MOVELEFT) ucmd->rightmove -= 127;
- if (bi->actionflags & ACTION_MOVERIGHT) ucmd->rightmove += 127;
- //jump/moveup
- if (bi->actionflags & ACTION_JUMP) ucmd->upmove += 127;
- //crouch/movedown
- if (bi->actionflags & ACTION_CROUCH) ucmd->upmove -= 127;
- //
- //Com_Printf("forward = %d right = %d up = %d\n", ucmd.forwardmove, ucmd.rightmove, ucmd.upmove);
- //Com_Printf("ucmd->serverTime = %d\n", ucmd->serverTime);
-}
-
-/*
-==============
-BotUpdateInput
-==============
-*/
-void BotUpdateInput(bot_state_t *bs, int time, int elapsed_time) {
- bot_input_t bi;
- int j;
-
- //add the delta angles to the bot's current view angles
- for (j = 0; j < 3; j++) {
- bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
- }
- //change the bot view angles
- BotChangeViewAngles(bs, (float) elapsed_time / 1000);
- //retrieve the bot input
- trap_EA_GetInput(bs->client, (float) time / 1000, &bi);
- //respawn hack
- if (bi.actionflags & ACTION_RESPAWN) {
- if (bs->lastucmd.buttons & BUTTON_ATTACK) bi.actionflags &= ~(ACTION_RESPAWN|ACTION_ATTACK);
- }
- //convert the bot input to a usercmd
- BotInputToUserCommand(&bi, &bs->lastucmd, bs->cur_ps.delta_angles, time);
- //subtract the delta angles
- for (j = 0; j < 3; j++) {
- bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
- }
-}
-
-/*
-==============
-BotAIRegularUpdate
-==============
-*/
-void BotAIRegularUpdate(void) {
- if (regularupdate_time < FloatTime()) {
- trap_BotUpdateEntityItems();
- regularupdate_time = FloatTime() + 0.3;
- }
-}
-
-/*
-==============
-RemoveColorEscapeSequences
-==============
-*/
-void RemoveColorEscapeSequences( char *text ) {
- int i, l;
-
- l = 0;
- for ( i = 0; text[i]; i++ ) {
- if (Q_IsColorString(&text[i])) {
- i++;
- continue;
- }
- if (text[i] > 0x7E)
- continue;
- text[l++] = text[i];
- }
- text[l] = '\0';
-}
-
-/*
-==============
-BotAI
-==============
-*/
-int BotAI(int client, float thinktime) {
- bot_state_t *bs;
- char buf[1024], *args;
- int j;
-
- trap_EA_ResetInput(client);
- //
- bs = botstates[client];
- if (!bs || !bs->inuse) {
- BotAI_Print(PRT_FATAL, "BotAI: client %d is not setup\n", client);
- return qfalse;
- }
-
- //retrieve the current client state
- BotAI_GetClientState( client, &bs->cur_ps );
-
- //retrieve any waiting server commands
- while( trap_BotGetServerCommand(client, buf, sizeof(buf)) ) {
- //have buf point to the command and args to the command arguments
- args = strchr( buf, ' ');
- if (!args) continue;
- *args++ = '\0';
-
- //remove color espace sequences from the arguments
- RemoveColorEscapeSequences( args );
-
- if (!Q_stricmp(buf, "cp "))
- { /*CenterPrintf*/ }
- else if (!Q_stricmp(buf, "cs"))
- { /*ConfigStringModified*/ }
- else if (!Q_stricmp(buf, "print")) {
- //remove first and last quote from the chat message
- memmove(args, args+1, strlen(args));
- args[strlen(args)-1] = '\0';
- trap_BotQueueConsoleMessage(bs->cs, CMS_NORMAL, args);
- }
- else if (!Q_stricmp(buf, "chat")) {
- //remove first and last quote from the chat message
- memmove(args, args+1, strlen(args));
- args[strlen(args)-1] = '\0';
- trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, args);
- }
- else if (!Q_stricmp(buf, "tchat")) {
- //remove first and last quote from the chat message
- memmove(args, args+1, strlen(args));
- args[strlen(args)-1] = '\0';
- trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, args);
- }
-#ifdef MISSIONPACK
- else if (!Q_stricmp(buf, "vchat")) {
- BotVoiceChatCommand(bs, SAY_ALL, args);
- }
- else if (!Q_stricmp(buf, "vtchat")) {
- BotVoiceChatCommand(bs, SAY_TEAM, args);
- }
- else if (!Q_stricmp(buf, "vtell")) {
- BotVoiceChatCommand(bs, SAY_TELL, args);
- }
-#endif
- else if (!Q_stricmp(buf, "scores"))
- { /*FIXME: parse scores?*/ }
- else if (!Q_stricmp(buf, "clientLevelShot"))
- { /*ignore*/ }
- }
- //add the delta angles to the bot's current view angles
- for (j = 0; j < 3; j++) {
- bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
- }
- //increase the local time of the bot
- bs->ltime += thinktime;
- //
- bs->thinktime = thinktime;
- //origin of the bot
- VectorCopy(bs->cur_ps.origin, bs->origin);
- //eye coordinates of the bot
- VectorCopy(bs->cur_ps.origin, bs->eye);
- bs->eye[2] += bs->cur_ps.viewheight;
- //get the area the bot is in
- bs->areanum = BotPointAreaNum(bs->origin);
- //the real AI
- BotDeathmatchAI(bs, thinktime);
- //set the weapon selection every AI frame
- trap_EA_SelectWeapon(bs->client, bs->weaponnum);
- //subtract the delta angles
- for (j = 0; j < 3; j++) {
- bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
- }
- //everything was ok
- return qtrue;
-}
-
-/*
-==================
-BotScheduleBotThink
-==================
-*/
-void BotScheduleBotThink(void) {
- int i, botnum;
-
- botnum = 0;
-
- for( i = 0; i < MAX_CLIENTS; i++ ) {
- if( !botstates[i] || !botstates[i]->inuse ) {
- continue;
- }
- //initialize the bot think residual time
- botstates[i]->botthink_residual = bot_thinktime.integer * botnum / numbots;
- botnum++;
- }
-}
-
-/*
-==============
-BotWriteSessionData
-==============
-*/
-void BotWriteSessionData(bot_state_t *bs) {
- const char *s;
- const char *var;
-
- s = va(
- "%i %i %i %i %i %i %i %i"
- " %f %f %f"
- " %f %f %f"
- " %f %f %f",
- bs->lastgoal_decisionmaker,
- bs->lastgoal_ltgtype,
- bs->lastgoal_teammate,
- bs->lastgoal_teamgoal.areanum,
- bs->lastgoal_teamgoal.entitynum,
- bs->lastgoal_teamgoal.flags,
- bs->lastgoal_teamgoal.iteminfo,
- bs->lastgoal_teamgoal.number,
- bs->lastgoal_teamgoal.origin[0],
- bs->lastgoal_teamgoal.origin[1],
- bs->lastgoal_teamgoal.origin[2],
- bs->lastgoal_teamgoal.mins[0],
- bs->lastgoal_teamgoal.mins[1],
- bs->lastgoal_teamgoal.mins[2],
- bs->lastgoal_teamgoal.maxs[0],
- bs->lastgoal_teamgoal.maxs[1],
- bs->lastgoal_teamgoal.maxs[2]
- );
-
- var = va( "botsession%i", bs->client );
-
- trap_Cvar_Set( var, s );
-}
-
-/*
-==============
-BotReadSessionData
-==============
-*/
-void BotReadSessionData(bot_state_t *bs) {
- char s[MAX_STRING_CHARS];
- const char *var;
-
- var = va( "botsession%i", bs->client );
- trap_Cvar_VariableStringBuffer( var, s, sizeof(s) );
-
- sscanf(s,
- "%i %i %i %i %i %i %i %i"
- " %f %f %f"
- " %f %f %f"
- " %f %f %f",
- &bs->lastgoal_decisionmaker,
- &bs->lastgoal_ltgtype,
- &bs->lastgoal_teammate,
- &bs->lastgoal_teamgoal.areanum,
- &bs->lastgoal_teamgoal.entitynum,
- &bs->lastgoal_teamgoal.flags,
- &bs->lastgoal_teamgoal.iteminfo,
- &bs->lastgoal_teamgoal.number,
- &bs->lastgoal_teamgoal.origin[0],
- &bs->lastgoal_teamgoal.origin[1],
- &bs->lastgoal_teamgoal.origin[2],
- &bs->lastgoal_teamgoal.mins[0],
- &bs->lastgoal_teamgoal.mins[1],
- &bs->lastgoal_teamgoal.mins[2],
- &bs->lastgoal_teamgoal.maxs[0],
- &bs->lastgoal_teamgoal.maxs[1],
- &bs->lastgoal_teamgoal.maxs[2]
- );
-}
-
-/*
-==============
-BotAISetupClient
-==============
-*/
-int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean restart) {
- char filename[MAX_PATH], name[MAX_PATH], gender[MAX_PATH];
- bot_state_t *bs;
- int errnum;
- //KK-OAX Changed to Tremulous's BG_Alloc
- if (!botstates[client]) {
- if(!BG_CanAlloc(sizeof(bot_state_t))) {
- //We cannot run BG_Alloc, fail nicely
- BotAI_Print(PRT_FATAL, "BotAISetupClient: Not enough heap memory\n", client);
- return qfalse;
- }
- botstates[client] = BG_Alloc(sizeof(bot_state_t));
- }
- bs = botstates[client];
-
- if (bs && bs->inuse) {
- BotAI_Print(PRT_FATAL, "BotAISetupClient: client %d already setup\n", client);
- return qfalse;
- }
-
- if (!trap_AAS_Initialized()) {
- BotAI_Print(PRT_FATAL, "AAS not initialized\n");
- return qfalse;
- }
-
- //load the bot character
- bs->character = trap_BotLoadCharacter(settings->characterfile, settings->skill);
- if (!bs->character) {
- BotAI_Print(PRT_FATAL, "couldn't load skill %f from %s\n", settings->skill, settings->characterfile);
- return qfalse;
- }
- //copy the settings
- memcpy(&bs->settings, settings, sizeof(bot_settings_t));
- //allocate a goal state
- bs->gs = trap_BotAllocGoalState(client);
- //load the item weights
- trap_Characteristic_String(bs->character, CHARACTERISTIC_ITEMWEIGHTS, filename, MAX_PATH);
- errnum = trap_BotLoadItemWeights(bs->gs, filename);
- if (errnum != BLERR_NOERROR) {
- trap_BotFreeGoalState(bs->gs);
- return qfalse;
- }
- //allocate a weapon state
- bs->ws = trap_BotAllocWeaponState();
- //load the weapon weights
- trap_Characteristic_String(bs->character, CHARACTERISTIC_WEAPONWEIGHTS, filename, MAX_PATH);
- errnum = trap_BotLoadWeaponWeights(bs->ws, filename);
- if (errnum != BLERR_NOERROR) {
- trap_BotFreeGoalState(bs->gs);
- trap_BotFreeWeaponState(bs->ws);
- return qfalse;
- }
- //allocate a chat state
- bs->cs = trap_BotAllocChatState();
- //load the chat file
- trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_FILE, filename, MAX_PATH);
- trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_NAME, name, MAX_PATH);
- errnum = trap_BotLoadChatFile(bs->cs, filename, name);
- if (errnum != BLERR_NOERROR) {
- trap_BotFreeChatState(bs->cs);
- trap_BotFreeGoalState(bs->gs);
- trap_BotFreeWeaponState(bs->ws);
- return qfalse;
- }
- //get the gender characteristic
- trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, MAX_PATH);
- //set the chat gender
- if (*gender == 'f' || *gender == 'F') trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE);
- else if (*gender == 'm' || *gender == 'M') trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE);
- else trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS);
-
- bs->inuse = qtrue;
- bs->client = client;
- bs->entitynum = client;
- bs->setupcount = 4;
- bs->entergame_time = FloatTime();
- bs->ms = trap_BotAllocMoveState();
- bs->walker = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WALKER, 0, 1);
- numbots++;
-
- if (trap_Cvar_VariableIntegerValue("bot_testichat")) {
- trap_BotLibVarSet("bot_testichat", "1");
- BotChatTest(bs);
- }
- //NOTE: reschedule the bot thinking
- BotScheduleBotThink();
- //if interbreeding start with a mutation
- if (bot_interbreed) {
- trap_BotMutateGoalFuzzyLogic(bs->gs, 1);
- }
- // if we kept the bot client
- if (restart) {
- BotReadSessionData(bs);
- }
- //bot has been setup succesfully
- return qtrue;
-}
-
-/*
-==============
-BotAIShutdownClient
-==============
-*/
-int BotAIShutdownClient(int client, qboolean restart) {
- bot_state_t *bs;
-
- bs = botstates[client];
- if (!bs || !bs->inuse) {
- //BotAI_Print(PRT_ERROR, "BotAIShutdownClient: client %d already shutdown\n", client);
- return qfalse;
- }
-
- if (restart) {
- BotWriteSessionData(bs);
- }
-
- if (BotChat_ExitGame(bs)) {
- trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
- }
-
- trap_BotFreeMoveState(bs->ms);
- //free the goal state`
- trap_BotFreeGoalState(bs->gs);
- //free the chat file
- trap_BotFreeChatState(bs->cs);
- //free the weapon weights
- trap_BotFreeWeaponState(bs->ws);
- //free the bot character
- trap_BotFreeCharacter(bs->character);
- //
- BotFreeWaypoints(bs->checkpoints);
- BotFreeWaypoints(bs->patrolpoints);
- //clear activate goal stack
- BotClearActivateGoalStack(bs);
- //clear the bot state
- memset(bs, 0, sizeof(bot_state_t));
- //set the inuse flag to qfalse
- bs->inuse = qfalse;
-
- //there's one bot less
- numbots--;
- //everything went ok
- return qtrue;
-}
-
-/*
-==============
-BotResetState
-
-called when a bot enters the intermission or observer mode and
-when the level is changed
-==============
-*/
-void BotResetState(bot_state_t *bs) {
- int client, entitynum, inuse;
- int movestate, goalstate, chatstate, weaponstate;
- bot_settings_t settings;
- int character;
- playerState_t ps; //current player state
- float entergame_time;
-
- //save some things that should not be reset here
- memcpy(&settings, &bs->settings, sizeof(bot_settings_t));
- memcpy(&ps, &bs->cur_ps, sizeof(playerState_t));
- inuse = bs->inuse;
- client = bs->client;
- entitynum = bs->entitynum;
- character = bs->character;
- movestate = bs->ms;
- goalstate = bs->gs;
- chatstate = bs->cs;
- weaponstate = bs->ws;
- entergame_time = bs->entergame_time;
- //free checkpoints and patrol points
- BotFreeWaypoints(bs->checkpoints);
- BotFreeWaypoints(bs->patrolpoints);
- //reset the whole state
- memset(bs, 0, sizeof(bot_state_t));
- //copy back some state stuff that should not be reset
- bs->ms = movestate;
- bs->gs = goalstate;
- bs->cs = chatstate;
- bs->ws = weaponstate;
- memcpy(&bs->cur_ps, &ps, sizeof(playerState_t));
- memcpy(&bs->settings, &settings, sizeof(bot_settings_t));
- bs->inuse = inuse;
- bs->client = client;
- bs->entitynum = entitynum;
- bs->character = character;
- bs->entergame_time = entergame_time;
- //reset several states
- if (bs->ms) trap_BotResetMoveState(bs->ms);
- if (bs->gs) trap_BotResetGoalState(bs->gs);
- if (bs->ws) trap_BotResetWeaponState(bs->ws);
- if (bs->gs) trap_BotResetAvoidGoals(bs->gs);
- if (bs->ms) trap_BotResetAvoidReach(bs->ms);
-}
-
-/*
-==============
-BotAILoadMap
-==============
-*/
-int BotAILoadMap( int restart ) {
- int i;
- vmCvar_t mapname;
-
- if (!restart) {
- trap_Cvar_Register( &mapname, "mapname", "", CVAR_SERVERINFO | CVAR_ROM );
- trap_BotLibLoadMap( mapname.string );
- }
-
- for (i = 0; i < MAX_CLIENTS; i++) {
- if (botstates[i] && botstates[i]->inuse) {
- BotResetState( botstates[i] );
- botstates[i]->setupcount = 4;
- }
- }
-
- BotSetupDeathmatchAI();
-
- return qtrue;
-}
-
-void ProximityMine_Trigger( gentity_t *trigger, gentity_t *other, trace_t *trace );
-
-/*
-==================
-BotAIStartFrame
-==================
-*/
-int BotAIStartFrame(int time) {
- int i;
- gentity_t *ent;
- bot_entitystate_t state;
- int elapsed_time, thinktime;
- static int local_time;
- static int botlib_residual;
- static int lastbotthink_time;
-
- G_CheckBotSpawn();
-
- trap_Cvar_Update(&bot_rocketjump);
- trap_Cvar_Update(&bot_grapple);
- trap_Cvar_Update(&bot_fastchat);
- trap_Cvar_Update(&bot_nochat);
- trap_Cvar_Update(&bot_testrchat);
- trap_Cvar_Update(&bot_thinktime);
- trap_Cvar_Update(&bot_memorydump);
- trap_Cvar_Update(&bot_saveroutingcache);
- trap_Cvar_Update(&bot_pause);
- trap_Cvar_Update(&bot_report);
-
- if (bot_report.integer) {
-// BotTeamplayReport();
-// trap_Cvar_Set("bot_report", "0");
- BotUpdateInfoConfigStrings();
- }
-
- if (bot_pause.integer) {
- // execute bot user commands every frame
- for( i = 0; i < MAX_CLIENTS; i++ ) {
- if( !botstates[i] || !botstates[i]->inuse ) {
- continue;
- }
- if( g_entities[i].client->pers.connected != CON_CONNECTED ) {
- continue;
- }
- botstates[i]->lastucmd.forwardmove = 0;
- botstates[i]->lastucmd.rightmove = 0;
- botstates[i]->lastucmd.upmove = 0;
- botstates[i]->lastucmd.buttons = 0;
- botstates[i]->lastucmd.serverTime = time;
- trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd);
- }
- return qtrue;
- }
-
- if (bot_memorydump.integer) {
- trap_BotLibVarSet("memorydump", "1");
- trap_Cvar_Set("bot_memorydump", "0");
- }
- if (bot_saveroutingcache.integer) {
- trap_BotLibVarSet("saveroutingcache", "1");
- trap_Cvar_Set("bot_saveroutingcache", "0");
- }
- //check if bot interbreeding is activated
- BotInterbreeding();
- //cap the bot think time
- if (bot_thinktime.integer > 200) {
- trap_Cvar_Set("bot_thinktime", "200");
- }
- //if the bot think time changed we should reschedule the bots
- if (bot_thinktime.integer != lastbotthink_time) {
- lastbotthink_time = bot_thinktime.integer;
- BotScheduleBotThink();
- }
-
- elapsed_time = time - local_time;
- local_time = time;
-
- botlib_residual += elapsed_time;
-
- if (elapsed_time > bot_thinktime.integer) thinktime = elapsed_time;
- else thinktime = bot_thinktime.integer;
-
- // update the bot library
- if ( botlib_residual >= thinktime ) {
- botlib_residual -= thinktime;
-
- trap_BotLibStartFrame((float) time / 1000);
-
- if (!trap_AAS_Initialized()) return qfalse;
-
- //update entities in the botlib
- for (i = 0; i < MAX_GENTITIES; i++) {
- ent = &g_entities[i];
- if (!ent->inuse) {
- trap_BotLibUpdateEntity(i, NULL);
- continue;
- }
- if (!ent->r.linked) {
- trap_BotLibUpdateEntity(i, NULL);
- continue;
- }
- if ( !(g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_LMS ||g_instantgib.integer || g_rockets.integer || g_elimination_allgametypes.integer || g_gametype.integer==GT_CTF_ELIMINATION)
- && ent->r.svFlags & SVF_NOCLIENT) {
- trap_BotLibUpdateEntity(i, NULL);
- continue;
- }
- // do not update missiles
- if (ent->s.eType == ET_MISSILE && ent->s.weapon != WP_GRAPPLING_HOOK) {
- trap_BotLibUpdateEntity(i, NULL);
- continue;
- }
- // do not update event only entities
- if (ent->s.eType > ET_EVENTS) {
- trap_BotLibUpdateEntity(i, NULL);
- continue;
- }
-
- // never link prox mine triggers
- if (ent->r.contents == CONTENTS_TRIGGER) {
- if (ent->touch == ProximityMine_Trigger) {
- trap_BotLibUpdateEntity(i, NULL);
- continue;
- }
- }
-
- //
- memset(&state, 0, sizeof(bot_entitystate_t));
- //
- VectorCopy(ent->r.currentOrigin, state.origin);
- if (i < MAX_CLIENTS) {
- VectorCopy(ent->s.apos.trBase, state.angles);
- } else {
- VectorCopy(ent->r.currentAngles, state.angles);
- }
- VectorCopy(ent->s.origin2, state.old_origin);
- VectorCopy(ent->r.mins, state.mins);
- VectorCopy(ent->r.maxs, state.maxs);
- state.type = ent->s.eType;
- state.flags = ent->s.eFlags;
- if (ent->r.bmodel) state.solid = SOLID_BSP;
- else state.solid = SOLID_BBOX;
- state.groundent = ent->s.groundEntityNum;
- state.modelindex = ent->s.modelindex;
- state.modelindex2 = ent->s.modelindex2;
- state.frame = ent->s.frame;
- state.event = ent->s.event;
- state.eventParm = ent->s.eventParm;
- state.powerups = ent->s.powerups;
- state.legsAnim = ent->s.legsAnim;
- state.torsoAnim = ent->s.torsoAnim;
- state.weapon = ent->s.weapon;
- //
- trap_BotLibUpdateEntity(i, &state);
- }
-
- BotAIRegularUpdate();
- }
-
- floattime = trap_AAS_Time();
-
- // execute scheduled bot AI
- for( i = 0; i < MAX_CLIENTS; i++ ) {
- if( !botstates[i] || !botstates[i]->inuse ) {
- continue;
- }
- //
- botstates[i]->botthink_residual += elapsed_time;
- //
- if ( botstates[i]->botthink_residual >= thinktime ) {
- botstates[i]->botthink_residual -= thinktime;
-
- if (!trap_AAS_Initialized()) return qfalse;
-
- if (g_entities[i].client->pers.connected == CON_CONNECTED) {
- BotAI(i, (float) thinktime / 1000);
- }
- }
- }
-
-
- // execute bot user commands every frame
- for( i = 0; i < MAX_CLIENTS; i++ ) {
- if( !botstates[i] || !botstates[i]->inuse ) {
- continue;
- }
- if( g_entities[i].client->pers.connected != CON_CONNECTED ) {
- continue;
- }
-
- BotUpdateInput(botstates[i], time, elapsed_time);
- trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd);
- }
-
- return qtrue;
-}
-
-/*
-==============
-BotInitLibrary
-==============
-*/
-int BotInitLibrary(void) {
- char buf[144];
-
- //set the maxclients and maxentities library variables before calling BotSetupLibrary
- trap_Cvar_VariableStringBuffer("sv_maxclients", buf, sizeof(buf));
- if (!strlen(buf)) strcpy(buf, "8");
- trap_BotLibVarSet("maxclients", buf);
- Com_sprintf(buf, sizeof(buf), "%d", MAX_GENTITIES);
- trap_BotLibVarSet("maxentities", buf);
- //bsp checksum
- trap_Cvar_VariableStringBuffer("sv_mapChecksum", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("sv_mapChecksum", buf);
- //maximum number of aas links
- trap_Cvar_VariableStringBuffer("max_aaslinks", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("max_aaslinks", buf);
- //maximum number of items in a level
- trap_Cvar_VariableStringBuffer("max_levelitems", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("max_levelitems", buf);
- //game type
- trap_Cvar_VariableStringBuffer("g_gametype", buf, sizeof(buf));
- if (!strlen(buf)) strcpy(buf, "0");
- trap_BotLibVarSet("g_gametype", buf);
- //bot developer mode and log file
- trap_BotLibVarSet("bot_developer", bot_developer.string);
- trap_Cvar_VariableStringBuffer("logfile", buf, sizeof(buf));
- trap_BotLibVarSet("log", buf);
- //no chatting
- trap_Cvar_VariableStringBuffer("bot_nochat", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("nochat", buf);
- //visualize jump pads
- trap_Cvar_VariableStringBuffer("bot_visualizejumppads", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("bot_visualizejumppads", buf);
- //forced clustering calculations
- trap_Cvar_VariableStringBuffer("bot_forceclustering", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("forceclustering", buf);
- //forced reachability calculations
- trap_Cvar_VariableStringBuffer("bot_forcereachability", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("forcereachability", buf);
- //force writing of AAS to file
- trap_Cvar_VariableStringBuffer("bot_forcewrite", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("forcewrite", buf);
- //no AAS optimization
- trap_Cvar_VariableStringBuffer("bot_aasoptimize", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("aasoptimize", buf);
- //
- trap_Cvar_VariableStringBuffer("bot_saveroutingcache", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("saveroutingcache", buf);
- //reload instead of cache bot character files
- trap_Cvar_VariableStringBuffer("bot_reloadcharacters", buf, sizeof(buf));
- if (!strlen(buf)) strcpy(buf, "0");
- trap_BotLibVarSet("bot_reloadcharacters", buf);
- //base directory
- trap_Cvar_VariableStringBuffer("fs_basepath", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("basedir", buf);
- //game directory
- trap_Cvar_VariableStringBuffer("fs_game", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("gamedir", buf);
- //home directory
- trap_Cvar_VariableStringBuffer("fs_homepath", buf, sizeof(buf));
- if (strlen(buf)) trap_BotLibVarSet("homedir", buf);
- //
-#ifdef MISSIONPACK
- trap_BotLibDefine("MISSIONPACK");
-#endif
- //setup the bot library
- return trap_BotLibSetup();
-}
-
-/*
-==============
-BotAISetup
-==============
-*/
-int BotAISetup( int restart ) {
- int errnum;
-
- trap_Cvar_Register(&bot_thinktime, "bot_thinktime", "100", CVAR_CHEAT);
- trap_Cvar_Register(&bot_memorydump, "bot_memorydump", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_saveroutingcache, "bot_saveroutingcache", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_pause, "bot_pause", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_report, "bot_report", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_testsolid, "bot_testsolid", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_testclusters, "bot_testclusters", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_developer, "bot_developer", "0", CVAR_CHEAT);
- trap_Cvar_Register(&bot_interbreedchar, "bot_interbreedchar", "", 0);
- trap_Cvar_Register(&bot_interbreedbots, "bot_interbreedbots", "10", 0);
- trap_Cvar_Register(&bot_interbreedcycle, "bot_interbreedcycle", "20", 0);
- trap_Cvar_Register(&bot_interbreedwrite, "bot_interbreedwrite", "", 0);
-
- //if the game is restarted for a tournament
- if (restart) {
- return qtrue;
- }
-
- //initialize the bot states
- memset( botstates, 0, sizeof(botstates) );
-
- errnum = BotInitLibrary();
- if (errnum != BLERR_NOERROR) return qfalse;
- return qtrue;
-}
-
-/*
-==============
-BotAIShutdown
-==============
-*/
-int BotAIShutdown( int restart ) {
-
- int i;
-
- //if the game is restarted for a tournament
- if ( restart ) {
- //shutdown all the bots in the botlib
- for (i = 0; i < MAX_CLIENTS; i++) {
- if (botstates[i] && botstates[i]->inuse) {
- BotAIShutdownClient(botstates[i]->client, restart);
- }
- }
- //don't shutdown the bot library
- }
- else {
- trap_BotLibShutdown();
- }
- return qtrue;
-}
-
diff --git a/game/code/game/ai_team.c b/game/code/game/ai_team.c
deleted file mode 100644
index fa1c1f3..0000000
--- a/game/code/game/ai_team.c
+++ /dev/null
@@ -1,2277 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_team.c
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /MissionPack/code/game/ai_team.c $
- *
- *****************************************************************************/
-
-#include "g_local.h"
-#include "../botlib/botlib.h"
-#include "../botlib/be_aas.h"
-#include "../botlib/be_ea.h"
-#include "../botlib/be_ai_char.h"
-#include "../botlib/be_ai_chat.h"
-#include "../botlib/be_ai_gen.h"
-#include "../botlib/be_ai_goal.h"
-#include "../botlib/be_ai_move.h"
-#include "../botlib/be_ai_weap.h"
-//
-#include "ai_main.h"
-#include "ai_dmq3.h"
-#include "ai_chat.h"
-#include "ai_cmd.h"
-#include "ai_dmnet.h"
-#include "ai_team.h"
-#include "ai_vcmd.h"
-
-#include "match.h"
-
-// for the voice chats
-#include "../../ui/menudef.h"
-
-//ctf task preferences for a client
-typedef struct bot_ctftaskpreference_s
-{
- char name[36];
- int preference;
-} bot_ctftaskpreference_t;
-
-bot_ctftaskpreference_t ctftaskpreferences[MAX_CLIENTS];
-
-
-/*
-==================
-BotValidTeamLeader
-==================
-*/
-int BotValidTeamLeader(bot_state_t *bs) {
- if (!strlen(bs->teamleader)) return qfalse;
- if (ClientFromName(bs->teamleader) == -1) return qfalse;
- return qtrue;
-}
-
-/*
-==================
-BotNumTeamMates
-==================
-*/
-int BotNumTeamMates(bot_state_t *bs) {
- int i, numplayers;
- char buf[MAX_INFO_STRING];
- static int maxclients;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- numplayers = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- if (BotSameTeam(bs, i)) {
- numplayers++;
- }
- }
- return numplayers;
-}
-
-/*
-==================
-BotClientTravelTimeToGoal
-==================
-*/
-int BotClientTravelTimeToGoal(int client, bot_goal_t *goal) {
- playerState_t ps;
- int areanum;
-
- BotAI_GetClientState(client, &ps);
- areanum = BotPointAreaNum(ps.origin);
- if (!areanum) return 1;
- return trap_AAS_AreaTravelTimeToGoalArea(areanum, ps.origin, goal->areanum, TFL_DEFAULT);
-}
-
-/*
-==================
-BotSortTeamMatesByBaseTravelTime
-==================
-*/
-int BotSortTeamMatesByBaseTravelTime(bot_state_t *bs, int *teammates, int maxteammates) {
-
- int i, j, k, numteammates, traveltime;
- char buf[MAX_INFO_STRING];
- static int maxclients;
- int traveltimes[MAX_CLIENTS];
- bot_goal_t *goal = NULL;
-
- if (gametype == GT_CTF || gametype == GT_1FCTF || gametype == GT_CTF_ELIMINATION) {
- if (BotTeam(bs) == TEAM_RED)
- goal = &ctf_redflag;
- else
- goal = &ctf_blueflag;
- }
- else {
- if (BotTeam(bs) == TEAM_RED)
- goal = &redobelisk;
- else
- goal = &blueobelisk;
- }
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- numteammates = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- if (BotSameTeam(bs, i)) {
- //
- traveltime = BotClientTravelTimeToGoal(i, goal);
- //
- for (j = 0; j < numteammates; j++) {
- if (traveltime < traveltimes[j]) {
- for (k = numteammates; k > j; k--) {
- traveltimes[k] = traveltimes[k-1];
- teammates[k] = teammates[k-1];
- }
- break;
- }
- }
- traveltimes[j] = traveltime;
- teammates[j] = i;
- numteammates++;
- if (numteammates >= maxteammates) break;
- }
- }
- return numteammates;
-}
-
-/*
-==================
-BotSortTeamMatesByReletiveTravelTime2ddA
-For Double Domination
-==================
-*/
-int BotSortTeamMatesByRelativeTravelTime2ddA(bot_state_t *bs, int *teammates, int maxteammates) {
- int i, j, k, numteammates;
- double traveltime, traveltime2b;
- char buf[MAX_INFO_STRING];
- static int maxclients;
- double traveltimes[MAX_CLIENTS];
- //int traveltimes2b[MAX_CLIENTS];
- bot_goal_t *goalA = &ctf_redflag;
- bot_goal_t *goalB = &ctf_blueflag;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- numteammates = 0;
-
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- if (BotSameTeam(bs, i)) {
- traveltime = (double)BotClientTravelTimeToGoal(i, goalA);
- traveltime2b = (double)BotClientTravelTimeToGoal(i, goalB);
- traveltime = traveltime/traveltime2b;
-
- for (j = 0; j < numteammates; j++) {
- if (traveltime < traveltimes[j]) {
- for (k = numteammates; k > j; k--) {
- traveltimes[k] = traveltimes[k-1];
- teammates[k] = teammates[k-1];
- }
- break;
- }
- }
- traveltimes[j] = traveltime;
- teammates[j] = i;
- numteammates++;
- if (numteammates >= maxteammates) break;
- }
- }
-
- return numteammates;
-}
-
-/*
-==================
-BotSetTeamMateTaskPreference
-==================
-*/
-void BotSetTeamMateTaskPreference(bot_state_t *bs, int teammate, int preference) {
- char teammatename[MAX_NETNAME];
-
- ctftaskpreferences[teammate].preference = preference;
- ClientName(teammate, teammatename, sizeof(teammatename));
- strcpy(ctftaskpreferences[teammate].name, teammatename);
-}
-
-/*
-==================
-BotGetTeamMateTaskPreference
-==================
-*/
-int BotGetTeamMateTaskPreference(bot_state_t *bs, int teammate) {
- char teammatename[MAX_NETNAME];
-
- if (!ctftaskpreferences[teammate].preference) return 0;
- ClientName(teammate, teammatename, sizeof(teammatename));
- if (Q_stricmp(teammatename, ctftaskpreferences[teammate].name)) return 0;
- return ctftaskpreferences[teammate].preference;
-}
-
-/*
-==================
-BotSortTeamMatesByTaskPreference
-==================
-*/
-int BotSortTeamMatesByTaskPreference(bot_state_t *bs, int *teammates, int numteammates) {
- int defenders[MAX_CLIENTS], numdefenders;
- int attackers[MAX_CLIENTS], numattackers;
- int roamers[MAX_CLIENTS], numroamers;
- int i, preference;
-
- numdefenders = numattackers = numroamers = 0;
- for (i = 0; i < numteammates; i++) {
- preference = BotGetTeamMateTaskPreference(bs, teammates[i]);
- if (preference & TEAMTP_DEFENDER) {
- defenders[numdefenders++] = teammates[i];
- }
- else if (preference & TEAMTP_ATTACKER) {
- attackers[numattackers++] = teammates[i];
- }
- else {
- roamers[numroamers++] = teammates[i];
- }
- }
- numteammates = 0;
- //defenders at the front of the list
- memcpy(&teammates[numteammates], defenders, numdefenders * sizeof(int));
- numteammates += numdefenders;
- //roamers in the middle
- memcpy(&teammates[numteammates], roamers, numroamers * sizeof(int));
- numteammates += numroamers;
- //attacker in the back of the list
- memcpy(&teammates[numteammates], attackers, numattackers * sizeof(int));
- numteammates += numattackers;
-
- return numteammates;
-}
-
-/*
-==================
-BotSayTeamOrders
-==================
-*/
-void BotSayTeamOrderAlways(bot_state_t *bs, int toclient) {
- char teamchat[MAX_MESSAGE_SIZE];
- char buf[MAX_MESSAGE_SIZE];
- char name[MAX_NETNAME];
-
- if (bot_nochat.integer>2) return;
-
- //if the bot is talking to itself
- if (bs->client == toclient) {
- //don't show the message just put it in the console message queue
- trap_BotGetChatMessage(bs->cs, buf, sizeof(buf));
- ClientName(bs->client, name, sizeof(name));
- Com_sprintf(teamchat, sizeof(teamchat), EC"(%s"EC")"EC": %s", name, buf);
- trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, teamchat);
- }
- else {
- trap_BotEnterChat(bs->cs, toclient, CHAT_TELL);
- }
-}
-
-/*
-==================
-BotSayTeamOrders
-==================
-*/
-void BotSayTeamOrder(bot_state_t *bs, int toclient) {
-#ifdef MISSIONPACK
- // voice chats only
- char buf[MAX_MESSAGE_SIZE];
-
- trap_BotGetChatMessage(bs->cs, buf, sizeof(buf));
-#else
- BotSayTeamOrderAlways(bs, toclient);
-#endif
-}
-
-/*
-==================
-BotVoiceChat
-==================
-*/
-void BotVoiceChat(bot_state_t *bs, int toclient, char *voicechat) {
-#ifdef MISSIONPACK
- if (toclient == -1)
- // voice only say team
- trap_EA_Command(bs->client, va("vsay_team %s", voicechat));
- else
- // voice only tell single player
- trap_EA_Command(bs->client, va("vtell %d %s", toclient, voicechat));
-#endif
-}
-
-/*
-==================
-BotVoiceChatOnly
-==================
-*/
-void BotVoiceChatOnly(bot_state_t *bs, int toclient, char *voicechat) {
-
-#ifdef MISSIONPACK
- if (toclient == -1)
- // voice only say team
- trap_EA_Command(bs->client, va("vosay_team %s", voicechat));
- else
- // voice only tell single player
- trap_EA_Command(bs->client, va("votell %d %s", toclient, voicechat));
-#endif
-}
-
-/*
-==================
-BotSayVoiceTeamOrder
-==================
-*/
-void BotSayVoiceTeamOrder(bot_state_t *bs, int toclient, char *voicechat) {
-
-#ifdef MISSIONPACK
- BotVoiceChat(bs, toclient, voicechat);
-#endif
-}
-
-/*
-==================
-BotCTFOrders
-==================
-*/
-void BotCTFOrders_BothFlagsNotAtBase(bot_state_t *bs) {
- int numteammates, defenders, attackers, i, other;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME], carriername[MAX_NETNAME];
-
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //different orders based on the number of team mates
- switch(bs->numteammates) {
- case 1: break;
- case 2:
- {
- //tell the one not carrying the flag to attack the enemy base
- if (teammates[0] != bs->flagcarrier) other = teammates[0];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- if (bot_nochat.integer<3) BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //tell the one closest to the base not carrying the flag to accompany the flag carrier
- if (teammates[0] != bs->flagcarrier) other = teammates[0];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- if ( bs->flagcarrier != -1 ) {
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- if (bs->flagcarrier == bs->client) {
- if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
- }
- else {
- if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
- }
- }
- else {
- //
- if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
- }
- if (bot_nochat.integer<3)BotSayTeamOrder(bs, other);
- //tell the one furthest from the the base not carrying the flag to get the enemy flag
- if (teammates[2] != bs->flagcarrier) other = teammates[2];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- if (bot_nochat.integer<3)BotSayTeamOrder(bs, other);
- if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, other, VOICECHAT_RETURNFLAG);
- break;
- }
- default:
- {
- defenders = (int) (float) numteammates * 0.4 + 0.5;
- if (defenders > 4) defenders = 4;
- attackers = (int) (float) numteammates * 0.5 + 0.5;
- if (attackers > 5) attackers = 5;
- if (bs->flagcarrier != -1) {
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- for (i = 0; i < defenders; i++) {
- //
- if (teammates[i] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[i], name, sizeof(name));
- if (bs->flagcarrier == bs->client) {
- if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWME);
- }
- else {
- if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWFLAGCARRIER);
- }
- if (bot_nochat.integer<3)BotSayTeamOrder(bs, teammates[i]);
- }
- }
- else {
- for (i = 0; i < defenders; i++) {
- //
- if (teammates[i] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[i], name, sizeof(name));
- if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_GETFLAG);
- if (bot_nochat.integer<3)BotSayTeamOrder(bs, teammates[i]);
- }
- }
- for (i = 0; i < attackers; i++) {
- //
- if (teammates[numteammates - i - 1] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- if (bot_nochat.integer<3)BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- if (bot_nochat.integer<3)BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- if (bot_nochat.integer<3)BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_RETURNFLAG);
- }
- //
- break;
- }
- }
-}
-
-/*
-==================
-BotCTFOrders
-==================
-*/
-void BotCTFOrders_FlagNotAtBase(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
- qboolean weAreAttacking;
-
- if (bot_nochat.integer>2) return;
-
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
-
- weAreAttacking = qfalse;
-
- //In oneway ctf we must all move out of the base (only one strategi, maybe we can also send some to the enemy base to meet the flag carier?)
- //We must be defending
- if(g_elimination_ctf_oneway.integer > 0) {
- for (i = 0; i < numteammates; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_GETFLAG);
- }
- return;
- }
-
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(bs->numteammates) {
- case 1: break;
- case 2:
- {
- //both will go for the enemy flag
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //keep one near the base for when the flag is returned
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other two get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //keep some people near the base for when the flag is returned
- defenders = (int) (float) numteammates * 0.3 + 0.5;
- if (defenders > 3) defenders = 3;
- attackers = (int) (float) numteammates * 0.7 + 0.5;
- if (attackers > 6) attackers = 6;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
- else {
- //different orders based on the number of team mates
- switch(bs->numteammates) {
- case 1: break;
- case 2:
- {
- //both will go for the enemy flag
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //everyone go for the flag
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //keep some people near the base for when the flag is returned
- defenders = (int) (float) numteammates * 0.2 + 0.5;
- if (defenders > 2) defenders = 2;
- attackers = (int) (float) numteammates * 0.7 + 0.5;
- if (attackers > 7) attackers = 7;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-BotCTFOrders
-==================
-*/
-void BotCTFOrders_EnemyFlagNotAtBase(bot_state_t *bs) {
- int numteammates, defenders, attackers, i, other;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME], carriername[MAX_NETNAME];
-
- if (bot_nochat.integer>2) return;
-
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //tell the one not carrying the flag to defend the base
- if (teammates[0] == bs->flagcarrier) other = teammates[1];
- else other = teammates[0];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
- break;
- }
- case 3:
- {
- //tell the one closest to the base not carrying the flag to defend the base
- if (teammates[0] != bs->flagcarrier) other = teammates[0];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
- //tell the other also to defend the base
- if (teammates[2] != bs->flagcarrier) other = teammates[2];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
- break;
- }
- default:
- {
- //60% will defend the base
- defenders = (int) (float) numteammates * 0.6 + 0.5;
- if (defenders > 6) defenders = 6;
- //30% accompanies the flag carrier
- attackers = (int) (float) numteammates * 0.3 + 0.5;
- if (attackers > 3) attackers = 3;
- for (i = 0; i < defenders; i++) {
- //
- if (teammates[i] == bs->flagcarrier) {
- continue;
- }
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- // if we have a flag carrier
- if ( bs->flagcarrier != -1 ) {
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- for (i = 0; i < attackers; i++) {
- //
- if (teammates[numteammates - i - 1] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- if (bs->flagcarrier == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
- }
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- }
- }
- else {
- for (i = 0; i < attackers; i++) {
- //
- if (teammates[numteammates - i - 1] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- }
- }
- //
- break;
- }
- }
-}
-
-/*
-==================
-BotDDorders
-==================
-*/
-
-void BotDDorders_Standard(bot_state_t *bs) {
- int numteammates, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
-
- if (bot_nochat.integer>2) return;
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByRelativeTravelTime2ddA(bs, teammates, sizeof(teammates));
-
- switch(numteammates) {
- case 1: break;
- /*case 2:
- {
- //the one closest to point A will take that
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_takea", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- //BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_TAKEA);
- //the other goes for point B
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_takeb", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- //BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_TAKEB);
- break;
- }*/
- default:
- {
- for(i=0;i<numteammates/2;i++) { //Half take point A
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_takea", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- //BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_TAKEA);
- }
- for(i=numteammates/2+1;i<numteammates;i++) { //Rest takes point B
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_takeb", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- //BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_TAKEB);
- }
- break;
- }
- }
-}
-
-/*
-==================
-BotCTFOrders
-==================
-*/
-void BotCTFOrders_BothFlagsAtBase(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
- qboolean weAreAttacking;
-
- if (bot_nochat.integer>2) return;
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
-
- weAreAttacking = qfalse;
-
- if(g_elimination_ctf_oneway.integer > 0) {
- //See if we are attacking:
- if( ( (level.eliminationSides+level.roundNumber)%2 == 0 ) && (BotTeam(bs) == TEAM_RED))
- weAreAttacking = qtrue;
-
- if(weAreAttacking) {
- for (i = 0; i < numteammates; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_GETFLAG);
- }
- } else {
- for (i = 0; i < numteammates; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- }
- return; //Sago: Or the leader will make a counter order.
- }
-
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the second one closest to the base will defend the base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- defenders = (int) (float) numteammates * 0.5 + 0.5;
- if (defenders > 5) defenders = 5;
- attackers = (int) (float) numteammates * 0.4 + 0.5;
- if (attackers > 4) attackers = 4;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
- else {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the others should go for the enemy flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- defenders = (int) (float) numteammates * 0.4 + 0.5;
- if (defenders > 4) defenders = 4;
- attackers = (int) (float) numteammates * 0.5 + 0.5;
- if (attackers > 5) attackers = 5;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-BotCTFOrders
-==================
-*/
-void BotCTFOrders(bot_state_t *bs) {
- int flagstatus;
-
- //
- if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus;
- else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus;
- //
- switch(flagstatus) {
- case 0: BotCTFOrders_BothFlagsAtBase(bs); break;
- case 1: BotCTFOrders_EnemyFlagNotAtBase(bs); break;
- case 2: BotCTFOrders_FlagNotAtBase(bs); break;
- case 3: BotCTFOrders_BothFlagsNotAtBase(bs); break;
- }
-}
-
-/*
-==================
-BotDDorders
-==================
-*/
-void BotDDorders(bot_state_t *bs) {
- BotDDorders_Standard(bs);
-}
-
-
-/*
-==================
-BotCreateGroup
-==================
-*/
-void BotCreateGroup(bot_state_t *bs, int *teammates, int groupsize) {
- char name[MAX_NETNAME], leadername[MAX_NETNAME];
- int i;
-
- if (bot_nochat.integer>2) return;
-
- // the others in the group will follow the teammates[0]
- ClientName(teammates[0], leadername, sizeof(leadername));
- for (i = 1; i < groupsize; i++)
- {
- ClientName(teammates[i], name, sizeof(name));
- if (teammates[0] == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, leadername, NULL);
- }
- BotSayTeamOrderAlways(bs, teammates[i]);
- }
-}
-
-/*
-==================
-BotTeamOrders
-
- FIXME: defend key areas?
-==================
-*/
-void BotTeamOrders(bot_state_t *bs) {
- int teammates[MAX_CLIENTS];
- int numteammates, i;
- char buf[MAX_INFO_STRING];
- static int maxclients;
-
- if (!maxclients)
- maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
-
- numteammates = 0;
- for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
- trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
- //if no config string or no name
- if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
- //skip spectators
- if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
- //
- if (BotSameTeam(bs, i)) {
- teammates[numteammates] = i;
- numteammates++;
- }
- }
- //
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //nothing special
- break;
- }
- case 3:
- {
- //have one follow another and one free roaming
- BotCreateGroup(bs, teammates, 2);
- break;
- }
- case 4:
- {
- BotCreateGroup(bs, teammates, 2); //a group of 2
- BotCreateGroup(bs, &teammates[2], 2); //a group of 2
- break;
- }
- case 5:
- {
- BotCreateGroup(bs, teammates, 2); //a group of 2
- BotCreateGroup(bs, &teammates[2], 3); //a group of 3
- break;
- }
- default:
- {
- if (numteammates <= 10) {
- for (i = 0; i < numteammates / 2; i++) {
- BotCreateGroup(bs, &teammates[i*2], 2); //groups of 2
- }
- }
- break;
- }
- }
-}
-
-/*
-==================
-Bot1FCTFOrders_FlagAtCenter
-
- X% defend the base, Y% get the flag
-==================
-*/
-void Bot1FCTFOrders_FlagAtCenter(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
-
- if (bot_nochat.integer>2) return;
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the second one closest to the base will defend the base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //50% defend the base
- defenders = (int) (float) numteammates * 0.5 + 0.5;
- if (defenders > 5) defenders = 5;
- //40% get the flag
- attackers = (int) (float) numteammates * 0.4 + 0.5;
- if (attackers > 4) attackers = 4;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
- else { //agressive
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the others should go for the enemy flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //30% defend the base
- defenders = (int) (float) numteammates * 0.3 + 0.5;
- if (defenders > 3) defenders = 3;
- //60% get the flag
- attackers = (int) (float) numteammates * 0.6 + 0.5;
- if (attackers > 6) attackers = 6;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-Bot1FCTFOrders_TeamHasFlag
-
- X% towards neutral flag, Y% go towards enemy base and accompany flag carrier if visible
-==================
-*/
-void Bot1FCTFOrders_TeamHasFlag(bot_state_t *bs) {
- int numteammates, defenders, attackers, i, other;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME], carriername[MAX_NETNAME];
-
- if (bot_nochat.integer>2) return;
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //tell the one not carrying the flag to attack the enemy base
- if (teammates[0] == bs->flagcarrier) other = teammates[1];
- else other = teammates[0];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_OFFENSE);
- break;
- }
- case 3:
- {
- //tell the one closest to the base not carrying the flag to defend the base
- if (teammates[0] != bs->flagcarrier) other = teammates[0];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
- //tell the one furthest from the base not carrying the flag to accompany the flag carrier
- if (teammates[2] != bs->flagcarrier) other = teammates[2];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- if ( bs->flagcarrier != -1 ) {
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- if (bs->flagcarrier == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
- }
- }
- else {
- //
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
- }
- BotSayTeamOrder(bs, other);
- break;
- }
- default:
- {
- //30% will defend the base
- defenders = (int) (float) numteammates * 0.3 + 0.5;
- if (defenders > 3) defenders = 3;
- //70% accompanies the flag carrier
- attackers = (int) (float) numteammates * 0.7 + 0.5;
- if (attackers > 7) attackers = 7;
- for (i = 0; i < defenders; i++) {
- //
- if (teammates[i] == bs->flagcarrier) {
- continue;
- }
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- if (bs->flagcarrier != -1) {
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- for (i = 0; i < attackers; i++) {
- //
- if (teammates[numteammates - i - 1] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- if (bs->flagcarrier == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
- }
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- }
- }
- else {
- for (i = 0; i < attackers; i++) {
- //
- if (teammates[numteammates - i - 1] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- }
- //
- break;
- }
- }
- }
- else { //agressive
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //tell the one not carrying the flag to defend the base
- if (teammates[0] == bs->flagcarrier) other = teammates[1];
- else other = teammates[0];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
- break;
- }
- case 3:
- {
- //tell the one closest to the base not carrying the flag to defend the base
- if (teammates[0] != bs->flagcarrier) other = teammates[0];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, other);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
- //tell the one furthest from the base not carrying the flag to accompany the flag carrier
- if (teammates[2] != bs->flagcarrier) other = teammates[2];
- else other = teammates[1];
- ClientName(other, name, sizeof(name));
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- if (bs->flagcarrier == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
- }
- BotSayTeamOrder(bs, other);
- break;
- }
- default:
- {
- //20% will defend the base
- defenders = (int) (float) numteammates * 0.2 + 0.5;
- if (defenders > 2) defenders = 2;
- //80% accompanies the flag carrier
- attackers = (int) (float) numteammates * 0.8 + 0.5;
- if (attackers > 8) attackers = 8;
- for (i = 0; i < defenders; i++) {
- //
- if (teammates[i] == bs->flagcarrier) {
- continue;
- }
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- ClientName(bs->flagcarrier, carriername, sizeof(carriername));
- for (i = 0; i < attackers; i++) {
- //
- if (teammates[numteammates - i - 1] == bs->flagcarrier) {
- continue;
- }
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- if (bs->flagcarrier == bs->client) {
- BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
- }
- else {
- BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
- }
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-Bot1FCTFOrders_EnemyHasFlag
-
- X% defend the base, Y% towards neutral flag
-==================
-*/
-void Bot1FCTFOrders_EnemyHasFlag(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
-
- if (bot_nochat.integer>2) return;
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //both defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the second one closest to the base will defend the base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- //the other will also defend the base
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_DEFEND);
- break;
- }
- default:
- {
- //80% will defend the base
- defenders = (int) (float) numteammates * 0.8 + 0.5;
- if (defenders > 8) defenders = 8;
- //10% will try to return the flag
- attackers = (int) (float) numteammates * 0.1 + 0.5;
- if (attackers > 2) attackers = 2;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
- else { //agressive
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the others should go for the enemy flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //70% defend the base
- defenders = (int) (float) numteammates * 0.7 + 0.5;
- if (defenders > 8) defenders = 8;
- //20% try to return the flag
- attackers = (int) (float) numteammates * 0.2 + 0.5;
- if (attackers > 2) attackers = 2;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-Bot1FCTFOrders_EnemyDroppedFlag
-
- X% defend the base, Y% get the flag
-==================
-*/
-void Bot1FCTFOrders_EnemyDroppedFlag(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
-
- if (bot_nochat.integer>2) return;
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the second one closest to the base will defend the base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //50% defend the base
- defenders = (int) (float) numteammates * 0.5 + 0.5;
- if (defenders > 5) defenders = 5;
- //40% get the flag
- attackers = (int) (float) numteammates * 0.4 + 0.5;
- if (attackers > 4) attackers = 4;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
- }
- //
- break;
- }
- }
- }
- else { //agressive
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will get the flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the others should go for the enemy flag
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
- break;
- }
- default:
- {
- //30% defend the base
- defenders = (int) (float) numteammates * 0.3 + 0.5;
- if (defenders > 3) defenders = 3;
- //60% get the flag
- attackers = (int) (float) numteammates * 0.6 + 0.5;
- if (attackers > 6) attackers = 6;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_DEFEND);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-Bot1FCTFOrders
-==================
-*/
-void Bot1FCTFOrders(bot_state_t *bs) {
- switch(bs->neutralflagstatus) {
- case 0: Bot1FCTFOrders_FlagAtCenter(bs); break;
- case 1: Bot1FCTFOrders_TeamHasFlag(bs); break;
- case 2: Bot1FCTFOrders_EnemyHasFlag(bs); break;
- case 3: Bot1FCTFOrders_EnemyDroppedFlag(bs); break;
- }
-}
-
-/*
-==================
-BotObeliskOrders
-
- X% in defence Y% in offence
-==================
-*/
-void BotObeliskOrders(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
-
- if (bot_nochat.integer>2) return;
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will attack the enemy base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the one second closest to the base also defends the base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- //the other one attacks the enemy base
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
- break;
- }
- default:
- {
- //50% defend the base
- defenders = (int) (float) numteammates * 0.5 + 0.5;
- if (defenders > 5) defenders = 5;
- //40% attack the enemy base
- attackers = (int) (float) numteammates * 0.4 + 0.5;
- if (attackers > 4) attackers = 4;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
- }
- //
- break;
- }
- }
- }
- else {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will attack the enemy base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the others attack the enemy base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
- break;
- }
- default:
- {
- //30% defend the base
- defenders = (int) (float) numteammates * 0.3 + 0.5;
- if (defenders > 3) defenders = 3;
- //70% attack the enemy base
- attackers = (int) (float) numteammates * 0.7 + 0.5;
- if (attackers > 7) attackers = 7;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-BotHarvesterOrders
-
- X% defend the base, Y% harvest
-==================
-*/
-void BotHarvesterOrders(bot_state_t *bs) {
- int numteammates, defenders, attackers, i;
- int teammates[MAX_CLIENTS];
- char name[MAX_NETNAME];
-
- if (bot_nochat.integer>2) return;
-
- //sort team mates by travel time to base
- numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
- //sort team mates by CTF preference
- BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
- //passive strategy
- if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will harvest
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the one second closest to the base also defends the base
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
- //the other one goes harvesting
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
- break;
- }
- default:
- {
- //50% defend the base
- defenders = (int) (float) numteammates * 0.5 + 0.5;
- if (defenders > 5) defenders = 5;
- //40% goes harvesting
- attackers = (int) (float) numteammates * 0.4 + 0.5;
- if (attackers > 4) attackers = 4;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
- }
- //
- break;
- }
- }
- }
- else {
- //different orders based on the number of team mates
- switch(numteammates) {
- case 1: break;
- case 2:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the other will harvest
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
- break;
- }
- case 3:
- {
- //the one closest to the base will defend the base
- ClientName(teammates[0], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[0]);
- BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
- //the others go harvesting
- ClientName(teammates[1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[1]);
- BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
- //
- ClientName(teammates[2], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[2]);
- BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
- break;
- }
- default:
- {
- //30% defend the base
- defenders = (int) (float) numteammates * 0.3 + 0.5;
- if (defenders > 3) defenders = 3;
- //70% go harvesting
- attackers = (int) (float) numteammates * 0.7 + 0.5;
- if (attackers > 7) attackers = 7;
- for (i = 0; i < defenders; i++) {
- //
- ClientName(teammates[i], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
- BotSayTeamOrder(bs, teammates[i]);
- BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
- }
- for (i = 0; i < attackers; i++) {
- //
- ClientName(teammates[numteammates - i - 1], name, sizeof(name));
- BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
- BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
- BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
- }
- //
- break;
- }
- }
- }
-}
-
-/*
-==================
-FindHumanTeamLeader
-==================
-*/
-int FindHumanTeamLeader(bot_state_t *bs) {
- int i;
-
- for (i = 0; i < MAX_CLIENTS; i++) {
- if ( g_entities[i].inuse ) {
- // if this player is not a bot
- if ( !(g_entities[i].r.svFlags & SVF_BOT) ) {
- // if this player is ok with being the leader
- if (!notleader[i]) {
- // if this player is on the same team
- if ( BotSameTeam(bs, i) ) {
- ClientName(i, bs->teamleader, sizeof(bs->teamleader));
- // if not yet ordered to do anything
- if ( !BotSetLastOrderedTask(bs) ) {
- // go on defense by default
- if (bot_nochat.integer<3)BotVoiceChat_Defend(bs, i, SAY_TELL);
- }
- return qtrue;
- }
- }
- }
- }
- }
- return qfalse;
-}
-
-int lastRoundNumber; //used to give new orders every round
-
-/*
-==================
-BotTeamAI
-==================
-*/
-void BotTeamAI(bot_state_t *bs) {
- int numteammates;
- char netname[MAX_NETNAME];
-
- if (bot_nochat.integer>2) return;
-
- //
- if ( gametype < GT_TEAM || g_ffa_gt == 1 )
- return;
- // make sure we've got a valid team leader
- if (!BotValidTeamLeader(bs)) {
- //
- if (!FindHumanTeamLeader(bs)) {
- //
- if (!bs->askteamleader_time && !bs->becometeamleader_time) {
- if (bs->entergame_time + 10 > FloatTime()) {
- bs->askteamleader_time = FloatTime() + 5 + random() * 10;
- }
- else {
- bs->becometeamleader_time = FloatTime() + 5 + random() * 10;
- }
- }
- if (bs->askteamleader_time && bs->askteamleader_time < FloatTime()) {
- // if asked for a team leader and no response
- BotAI_BotInitialChat(bs, "whoisteamleader", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- bs->askteamleader_time = 0;
- bs->becometeamleader_time = FloatTime() + 8 + random() * 10;
- }
- if (bs->becometeamleader_time && bs->becometeamleader_time < FloatTime()) {
- BotAI_BotInitialChat(bs, "iamteamleader", NULL);
- trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
- BotSayVoiceTeamOrder(bs, -1, VOICECHAT_STARTLEADER);
- ClientName(bs->client, netname, sizeof(netname));
- strncpy(bs->teamleader, netname, sizeof(bs->teamleader));
- bs->teamleader[sizeof(bs->teamleader)-1] = '\0';
- bs->becometeamleader_time = 0;
- }
- return;
- }
- }
- bs->askteamleader_time = 0;
- bs->becometeamleader_time = 0;
-
- //return if this bot is NOT the team leader
- ClientName(bs->client, netname, sizeof(netname));
- if (Q_stricmp(netname, bs->teamleader) != 0) return;
- //
- numteammates = BotNumTeamMates(bs);
- //give orders
- switch(gametype) {
- case GT_TEAM:
- {
- if (bs->numteammates != numteammates || bs->forceorders) {
- bs->teamgiveorders_time = FloatTime();
- bs->numteammates = numteammates;
- bs->forceorders = qfalse;
- }
- //if it's time to give orders
- if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
- BotTeamOrders(bs);
- //give orders again after 120 seconds
- bs->teamgiveorders_time = FloatTime() + 120;
- }
- break;
- }
- case GT_CTF:
- case GT_CTF_ELIMINATION:
- {
- //if the number of team mates changed or the flag status changed
- //or someone wants to know what to do
- if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders || lastRoundNumber != level.roundNumber) {
- bs->teamgiveorders_time = FloatTime();
- bs->numteammates = numteammates;
- bs->flagstatuschanged = qfalse;
- bs->forceorders = qfalse;
- lastRoundNumber = level.roundNumber;
- }
- //if there were no flag captures the last 3 minutes
- if (bs->lastflagcapture_time < FloatTime() - 240) {
- bs->lastflagcapture_time = FloatTime();
- //randomly change the CTF strategy
- if (random() < 0.4) {
- bs->ctfstrategy ^= CTFS_AGRESSIVE;
- bs->teamgiveorders_time = FloatTime();
- }
- }
- //if it's time to give orders
- if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 3) {
- BotCTFOrders(bs);
- //
- bs->teamgiveorders_time = 0;
- }
- break;
- }
- case GT_DOUBLE_D:
- {
- //if the number of team mates changed or the domination point status changed
- //or someone wants to know what to do
- if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) {
- bs->teamgiveorders_time = FloatTime();
- bs->numteammates = numteammates;
- bs->flagstatuschanged = qfalse;
- bs->forceorders = qfalse;
- }
- //if it's time to give orders
- if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 3) {
- BotDDorders(bs);
- //
- bs->teamgiveorders_time = 0;
- }
- break;
- }
- case GT_1FCTF:
- {
- if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) {
- bs->teamgiveorders_time = FloatTime();
- bs->numteammates = numteammates;
- bs->flagstatuschanged = qfalse;
- bs->forceorders = qfalse;
- }
- //if there were no flag captures the last 4 minutes
- if (bs->lastflagcapture_time < FloatTime() - 240) {
- bs->lastflagcapture_time = FloatTime();
- //randomly change the CTF strategy
- if (random() < 0.4) {
- bs->ctfstrategy ^= CTFS_AGRESSIVE;
- bs->teamgiveorders_time = FloatTime();
- }
- }
- //if it's time to give orders
- if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 2) {
- Bot1FCTFOrders(bs);
- //
- bs->teamgiveorders_time = 0;
- }
- break;
- }
- case GT_OBELISK:
- {
- if (bs->numteammates != numteammates || bs->forceorders) {
- bs->teamgiveorders_time = FloatTime();
- bs->numteammates = numteammates;
- bs->forceorders = qfalse;
- }
- //if it's time to give orders
- if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
- BotObeliskOrders(bs);
- //give orders again after 30 seconds
- bs->teamgiveorders_time = FloatTime() + 30;
- }
- break;
- }
- case GT_HARVESTER:
- {
- if (bs->numteammates != numteammates || bs->forceorders) {
- bs->teamgiveorders_time = FloatTime();
- bs->numteammates = numteammates;
- bs->forceorders = qfalse;
- }
- //if it's time to give orders
- if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
- BotHarvesterOrders(bs);
- //give orders again after 30 seconds
- bs->teamgiveorders_time = FloatTime() + 30;
- }
- break;
- }
- }
-}
-
diff --git a/game/code/game/ai_team.h b/game/code/game/ai_team.h
deleted file mode 100644
index 252e9e1..0000000
--- a/game/code/game/ai_team.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_team.h
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /source/code/botai/ai_chat.c $
- *
- *****************************************************************************/
-
-void BotTeamAI(bot_state_t *bs);
-int BotGetTeamMateTaskPreference(bot_state_t *bs, int teammate);
-void BotSetTeamMateTaskPreference(bot_state_t *bs, int teammate, int preference);
-void BotVoiceChat(bot_state_t *bs, int toclient, char *voicechat);
-void BotVoiceChatOnly(bot_state_t *bs, int toclient, char *voicechat);
-
-
diff --git a/game/code/game/ai_vcmd.h b/game/code/game/ai_vcmd.h
deleted file mode 100644
index 9a50b14..0000000
--- a/game/code/game/ai_vcmd.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-/*****************************************************************************
- * name: ai_vcmd.h
- *
- * desc: Quake3 bot AI
- *
- * $Archive: /source/code/botai/ai_vcmd.c $
- *
- *****************************************************************************/
-
-int BotVoiceChatCommand(bot_state_t *bs, int mode, char *voicechat);
-void BotVoiceChat_Defend(bot_state_t *bs, int client, int mode);
-
-
diff --git a/game/code/game/bg_lib.c b/game/code/game/bg_lib.c
deleted file mode 100644
index e1e9e9e..0000000
--- a/game/code/game/bg_lib.c
+++ /dev/null
@@ -1,2133 +0,0 @@
-//
-//
-// bg_lib,c -- standard C library replacement routines used by code
-// compiled for the virtual machine
-
-#ifdef Q3_VM
-
-#include "../qcommon/q_shared.h"
-
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "bg_lib.h"
-
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
-#endif
-static const char rcsid[] =
-#endif /* LIBC_SCCS and not lint */
-
-static char* med3(char *, char *, char *, cmp_t *);
-static void swapfunc(char *, char *, int, int);
-
-#ifndef min
-#define min(a, b) ((a) < (b) ? (a) : (b))
-#endif
-
-/*
- * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
- */
-#define swapcode(TYPE, parmi, parmj, n) { \
- long i = (n) / sizeof (TYPE); \
- register TYPE *pi = (TYPE *) (parmi); \
- register TYPE *pj = (TYPE *) (parmj); \
- do { \
- register TYPE t = *pi; \
- *pi++ = *pj; \
- *pj++ = t; \
- } while (--i > 0); \
-}
-
-#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
- es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
-
-static void
-swapfunc(a, b, n, swaptype)
- char *a, *b;
- int n, swaptype;
-{
- if(swaptype <= 1)
- swapcode(long, a, b, n)
- else
- swapcode(char, a, b, n)
-}
-
-#define swap(a, b) \
- if (swaptype == 0) { \
- long t = *(long *)(a); \
- *(long *)(a) = *(long *)(b); \
- *(long *)(b) = t; \
- } else \
- swapfunc(a, b, es, swaptype)
-
-#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
-
-static char *
-med3(a, b, c, cmp)
- char *a, *b, *c;
- cmp_t *cmp;
-{
- return cmp(a, b) < 0 ?
- (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
- :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
-}
-
-void
-qsort(a, n, es, cmp)
- void *a;
- size_t n, es;
- cmp_t *cmp;
-{
- char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
- int d, r, swaptype, swap_cnt;
-
-loop: SWAPINIT(a, es);
- swap_cnt = 0;
- if (n < 7) {
- for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
- for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0;
- pl -= es)
- swap(pl, pl - es);
- return;
- }
- pm = (char *)a + (n / 2) * es;
- if (n > 7) {
- pl = a;
- pn = (char *)a + (n - 1) * es;
- if (n > 40) {
- d = (n / 8) * es;
- pl = med3(pl, pl + d, pl + 2 * d, cmp);
- pm = med3(pm - d, pm, pm + d, cmp);
- pn = med3(pn - 2 * d, pn - d, pn, cmp);
- }
- pm = med3(pl, pm, pn, cmp);
- }
- swap(a, pm);
- pa = pb = (char *)a + es;
-
- pc = pd = (char *)a + (n - 1) * es;
- for (;;) {
- while (pb <= pc && (r = cmp(pb, a)) <= 0) {
- if (r == 0) {
- swap_cnt = 1;
- swap(pa, pb);
- pa += es;
- }
- pb += es;
- }
- while (pb <= pc && (r = cmp(pc, a)) >= 0) {
- if (r == 0) {
- swap_cnt = 1;
- swap(pc, pd);
- pd -= es;
- }
- pc -= es;
- }
- if (pb > pc)
- break;
- swap(pb, pc);
- swap_cnt = 1;
- pb += es;
- pc -= es;
- }
- if (swap_cnt == 0) { /* Switch to insertion sort */
- for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
- for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0;
- pl -= es)
- swap(pl, pl - es);
- return;
- }
-
- pn = (char *)a + n * es;
- r = min(pa - (char *)a, pb - pa);
- vecswap(a, pb - r, r);
- r = min(pd - pc, pn - pd - es);
- vecswap(pb, pn - r, r);
- if ((r = pb - pa) > es)
- qsort(a, r / es, es, cmp);
- if ((r = pd - pc) > es) {
- /* Iterate rather than recurse to save stack space */
- a = pn - r;
- n = r / es;
- goto loop;
- }
-/* qsort(pn - r, r / es, es, cmp);*/
-}
-
-//==================================================================================
-
-size_t strlen( const char *string ) {
- const char *s;
-
- s = string;
- while ( *s ) {
- s++;
- }
- return s - string;
-}
-
-
-char *strcat( char *strDestination, const char *strSource ) {
- char *s;
-
- s = strDestination;
- while ( *s ) {
- s++;
- }
- while ( *strSource ) {
- *s++ = *strSource++;
- }
- *s = 0;
- return strDestination;
-}
-
-char *strcpy( char *strDestination, const char *strSource ) {
- char *s;
-
- s = strDestination;
- while ( *strSource ) {
- *s++ = *strSource++;
- }
- *s = 0;
- return strDestination;
-}
-
-
-int strcmp( const char *string1, const char *string2 ) {
- while ( *string1 == *string2 && *string1 && *string2 ) {
- string1++;
- string2++;
- }
- return *string1 - *string2;
-}
-
-
-char *strchr( const char *string, int c ) {
- while ( *string ) {
- if ( *string == c ) {
- return ( char * )string;
- }
- string++;
- }
- return (char *)0;
-}
-
-char *strstr( const char *string, const char *strCharSet ) {
- while ( *string ) {
- int i;
-
- for ( i = 0 ; strCharSet[i] ; i++ ) {
- if ( string[i] != strCharSet[i] ) {
- break;
- }
- }
- if ( !strCharSet[i] ) {
- return (char *)string;
- }
- string++;
- }
- return (char *)0;
-}
-
-int tolower( int c ) {
- if ( c >= 'A' && c <= 'Z' ) {
- c += 'a' - 'A';
- }
- return c;
-}
-
-
-int toupper( int c ) {
- if ( c >= 'a' && c <= 'z' ) {
- c += 'A' - 'a';
- }
- return c;
-}
-
-void *memmove( void *dest, const void *src, size_t count ) {
- int i;
-
- if ( dest > src ) {
- for ( i = count-1 ; i >= 0 ; i-- ) {
- ((char *)dest)[i] = ((char *)src)[i];
- }
- } else {
- for ( i = 0 ; i < count ; i++ ) {
- ((char *)dest)[i] = ((char *)src)[i];
- }
- }
- return dest;
-}
-
-
-#if 0
-
-double floor( double x ) {
- return (int)(x + 0x40000000) - 0x40000000;
-}
-
-void *memset( void *dest, int c, size_t count ) {
- while ( count-- ) {
- ((char *)dest)[count] = c;
- }
- return dest;
-}
-
-void *memcpy( void *dest, const void *src, size_t count ) {
- while ( count-- ) {
- ((char *)dest)[count] = ((char *)src)[count];
- }
- return dest;
-}
-
-char *strncpy( char *strDest, const char *strSource, size_t count ) {
- char *s;
-
- s = strDest;
- while ( *strSource && count ) {
- *s++ = *strSource++;
- count--;
- }
- while ( count-- ) {
- *s++ = 0;
- }
- return strDest;
-}
-
-double sqrt( double x ) {
- float y;
- float delta;
- float maxError;
-
- if ( x <= 0 ) {
- return 0;
- }
-
- // initial guess
- y = x / 2;
-
- // refine
- maxError = x * 0.001;
-
- do {
- delta = ( y * y ) - x;
- y -= delta / ( 2 * y );
- } while ( delta > maxError || delta < -maxError );
-
- return y;
-}
-
-
-float sintable[1024] = {
-0.000000,0.001534,0.003068,0.004602,0.006136,0.007670,0.009204,0.010738,
-0.012272,0.013805,0.015339,0.016873,0.018407,0.019940,0.021474,0.023008,
-0.024541,0.026075,0.027608,0.029142,0.030675,0.032208,0.033741,0.035274,
-0.036807,0.038340,0.039873,0.041406,0.042938,0.044471,0.046003,0.047535,
-0.049068,0.050600,0.052132,0.053664,0.055195,0.056727,0.058258,0.059790,
-0.061321,0.062852,0.064383,0.065913,0.067444,0.068974,0.070505,0.072035,
-0.073565,0.075094,0.076624,0.078153,0.079682,0.081211,0.082740,0.084269,
-0.085797,0.087326,0.088854,0.090381,0.091909,0.093436,0.094963,0.096490,
-0.098017,0.099544,0.101070,0.102596,0.104122,0.105647,0.107172,0.108697,
-0.110222,0.111747,0.113271,0.114795,0.116319,0.117842,0.119365,0.120888,
-0.122411,0.123933,0.125455,0.126977,0.128498,0.130019,0.131540,0.133061,
-0.134581,0.136101,0.137620,0.139139,0.140658,0.142177,0.143695,0.145213,
-0.146730,0.148248,0.149765,0.151281,0.152797,0.154313,0.155828,0.157343,
-0.158858,0.160372,0.161886,0.163400,0.164913,0.166426,0.167938,0.169450,
-0.170962,0.172473,0.173984,0.175494,0.177004,0.178514,0.180023,0.181532,
-0.183040,0.184548,0.186055,0.187562,0.189069,0.190575,0.192080,0.193586,
-0.195090,0.196595,0.198098,0.199602,0.201105,0.202607,0.204109,0.205610,
-0.207111,0.208612,0.210112,0.211611,0.213110,0.214609,0.216107,0.217604,
-0.219101,0.220598,0.222094,0.223589,0.225084,0.226578,0.228072,0.229565,
-0.231058,0.232550,0.234042,0.235533,0.237024,0.238514,0.240003,0.241492,
-0.242980,0.244468,0.245955,0.247442,0.248928,0.250413,0.251898,0.253382,
-0.254866,0.256349,0.257831,0.259313,0.260794,0.262275,0.263755,0.265234,
-0.266713,0.268191,0.269668,0.271145,0.272621,0.274097,0.275572,0.277046,
-0.278520,0.279993,0.281465,0.282937,0.284408,0.285878,0.287347,0.288816,
-0.290285,0.291752,0.293219,0.294685,0.296151,0.297616,0.299080,0.300543,
-0.302006,0.303468,0.304929,0.306390,0.307850,0.309309,0.310767,0.312225,
-0.313682,0.315138,0.316593,0.318048,0.319502,0.320955,0.322408,0.323859,
-0.325310,0.326760,0.328210,0.329658,0.331106,0.332553,0.334000,0.335445,
-0.336890,0.338334,0.339777,0.341219,0.342661,0.344101,0.345541,0.346980,
-0.348419,0.349856,0.351293,0.352729,0.354164,0.355598,0.357031,0.358463,
-0.359895,0.361326,0.362756,0.364185,0.365613,0.367040,0.368467,0.369892,
-0.371317,0.372741,0.374164,0.375586,0.377007,0.378428,0.379847,0.381266,
-0.382683,0.384100,0.385516,0.386931,0.388345,0.389758,0.391170,0.392582,
-0.393992,0.395401,0.396810,0.398218,0.399624,0.401030,0.402435,0.403838,
-0.405241,0.406643,0.408044,0.409444,0.410843,0.412241,0.413638,0.415034,
-0.416430,0.417824,0.419217,0.420609,0.422000,0.423390,0.424780,0.426168,
-0.427555,0.428941,0.430326,0.431711,0.433094,0.434476,0.435857,0.437237,
-0.438616,0.439994,0.441371,0.442747,0.444122,0.445496,0.446869,0.448241,
-0.449611,0.450981,0.452350,0.453717,0.455084,0.456449,0.457813,0.459177,
-0.460539,0.461900,0.463260,0.464619,0.465976,0.467333,0.468689,0.470043,
-0.471397,0.472749,0.474100,0.475450,0.476799,0.478147,0.479494,0.480839,
-0.482184,0.483527,0.484869,0.486210,0.487550,0.488889,0.490226,0.491563,
-0.492898,0.494232,0.495565,0.496897,0.498228,0.499557,0.500885,0.502212,
-0.503538,0.504863,0.506187,0.507509,0.508830,0.510150,0.511469,0.512786,
-0.514103,0.515418,0.516732,0.518045,0.519356,0.520666,0.521975,0.523283,
-0.524590,0.525895,0.527199,0.528502,0.529804,0.531104,0.532403,0.533701,
-0.534998,0.536293,0.537587,0.538880,0.540171,0.541462,0.542751,0.544039,
-0.545325,0.546610,0.547894,0.549177,0.550458,0.551738,0.553017,0.554294,
-0.555570,0.556845,0.558119,0.559391,0.560662,0.561931,0.563199,0.564466,
-0.565732,0.566996,0.568259,0.569521,0.570781,0.572040,0.573297,0.574553,
-0.575808,0.577062,0.578314,0.579565,0.580814,0.582062,0.583309,0.584554,
-0.585798,0.587040,0.588282,0.589521,0.590760,0.591997,0.593232,0.594466,
-0.595699,0.596931,0.598161,0.599389,0.600616,0.601842,0.603067,0.604290,
-0.605511,0.606731,0.607950,0.609167,0.610383,0.611597,0.612810,0.614022,
-0.615232,0.616440,0.617647,0.618853,0.620057,0.621260,0.622461,0.623661,
-0.624859,0.626056,0.627252,0.628446,0.629638,0.630829,0.632019,0.633207,
-0.634393,0.635578,0.636762,0.637944,0.639124,0.640303,0.641481,0.642657,
-0.643832,0.645005,0.646176,0.647346,0.648514,0.649681,0.650847,0.652011,
-0.653173,0.654334,0.655493,0.656651,0.657807,0.658961,0.660114,0.661266,
-0.662416,0.663564,0.664711,0.665856,0.667000,0.668142,0.669283,0.670422,
-0.671559,0.672695,0.673829,0.674962,0.676093,0.677222,0.678350,0.679476,
-0.680601,0.681724,0.682846,0.683965,0.685084,0.686200,0.687315,0.688429,
-0.689541,0.690651,0.691759,0.692866,0.693971,0.695075,0.696177,0.697278,
-0.698376,0.699473,0.700569,0.701663,0.702755,0.703845,0.704934,0.706021,
-0.707107,0.708191,0.709273,0.710353,0.711432,0.712509,0.713585,0.714659,
-0.715731,0.716801,0.717870,0.718937,0.720003,0.721066,0.722128,0.723188,
-0.724247,0.725304,0.726359,0.727413,0.728464,0.729514,0.730563,0.731609,
-0.732654,0.733697,0.734739,0.735779,0.736817,0.737853,0.738887,0.739920,
-0.740951,0.741980,0.743008,0.744034,0.745058,0.746080,0.747101,0.748119,
-0.749136,0.750152,0.751165,0.752177,0.753187,0.754195,0.755201,0.756206,
-0.757209,0.758210,0.759209,0.760207,0.761202,0.762196,0.763188,0.764179,
-0.765167,0.766154,0.767139,0.768122,0.769103,0.770083,0.771061,0.772036,
-0.773010,0.773983,0.774953,0.775922,0.776888,0.777853,0.778817,0.779778,
-0.780737,0.781695,0.782651,0.783605,0.784557,0.785507,0.786455,0.787402,
-0.788346,0.789289,0.790230,0.791169,0.792107,0.793042,0.793975,0.794907,
-0.795837,0.796765,0.797691,0.798615,0.799537,0.800458,0.801376,0.802293,
-0.803208,0.804120,0.805031,0.805940,0.806848,0.807753,0.808656,0.809558,
-0.810457,0.811355,0.812251,0.813144,0.814036,0.814926,0.815814,0.816701,
-0.817585,0.818467,0.819348,0.820226,0.821103,0.821977,0.822850,0.823721,
-0.824589,0.825456,0.826321,0.827184,0.828045,0.828904,0.829761,0.830616,
-0.831470,0.832321,0.833170,0.834018,0.834863,0.835706,0.836548,0.837387,
-0.838225,0.839060,0.839894,0.840725,0.841555,0.842383,0.843208,0.844032,
-0.844854,0.845673,0.846491,0.847307,0.848120,0.848932,0.849742,0.850549,
-0.851355,0.852159,0.852961,0.853760,0.854558,0.855354,0.856147,0.856939,
-0.857729,0.858516,0.859302,0.860085,0.860867,0.861646,0.862424,0.863199,
-0.863973,0.864744,0.865514,0.866281,0.867046,0.867809,0.868571,0.869330,
-0.870087,0.870842,0.871595,0.872346,0.873095,0.873842,0.874587,0.875329,
-0.876070,0.876809,0.877545,0.878280,0.879012,0.879743,0.880471,0.881197,
-0.881921,0.882643,0.883363,0.884081,0.884797,0.885511,0.886223,0.886932,
-0.887640,0.888345,0.889048,0.889750,0.890449,0.891146,0.891841,0.892534,
-0.893224,0.893913,0.894599,0.895284,0.895966,0.896646,0.897325,0.898001,
-0.898674,0.899346,0.900016,0.900683,0.901349,0.902012,0.902673,0.903332,
-0.903989,0.904644,0.905297,0.905947,0.906596,0.907242,0.907886,0.908528,
-0.909168,0.909806,0.910441,0.911075,0.911706,0.912335,0.912962,0.913587,
-0.914210,0.914830,0.915449,0.916065,0.916679,0.917291,0.917901,0.918508,
-0.919114,0.919717,0.920318,0.920917,0.921514,0.922109,0.922701,0.923291,
-0.923880,0.924465,0.925049,0.925631,0.926210,0.926787,0.927363,0.927935,
-0.928506,0.929075,0.929641,0.930205,0.930767,0.931327,0.931884,0.932440,
-0.932993,0.933544,0.934093,0.934639,0.935184,0.935726,0.936266,0.936803,
-0.937339,0.937872,0.938404,0.938932,0.939459,0.939984,0.940506,0.941026,
-0.941544,0.942060,0.942573,0.943084,0.943593,0.944100,0.944605,0.945107,
-0.945607,0.946105,0.946601,0.947094,0.947586,0.948075,0.948561,0.949046,
-0.949528,0.950008,0.950486,0.950962,0.951435,0.951906,0.952375,0.952842,
-0.953306,0.953768,0.954228,0.954686,0.955141,0.955594,0.956045,0.956494,
-0.956940,0.957385,0.957826,0.958266,0.958703,0.959139,0.959572,0.960002,
-0.960431,0.960857,0.961280,0.961702,0.962121,0.962538,0.962953,0.963366,
-0.963776,0.964184,0.964590,0.964993,0.965394,0.965793,0.966190,0.966584,
-0.966976,0.967366,0.967754,0.968139,0.968522,0.968903,0.969281,0.969657,
-0.970031,0.970403,0.970772,0.971139,0.971504,0.971866,0.972226,0.972584,
-0.972940,0.973293,0.973644,0.973993,0.974339,0.974684,0.975025,0.975365,
-0.975702,0.976037,0.976370,0.976700,0.977028,0.977354,0.977677,0.977999,
-0.978317,0.978634,0.978948,0.979260,0.979570,0.979877,0.980182,0.980485,
-0.980785,0.981083,0.981379,0.981673,0.981964,0.982253,0.982539,0.982824,
-0.983105,0.983385,0.983662,0.983937,0.984210,0.984480,0.984749,0.985014,
-0.985278,0.985539,0.985798,0.986054,0.986308,0.986560,0.986809,0.987057,
-0.987301,0.987544,0.987784,0.988022,0.988258,0.988491,0.988722,0.988950,
-0.989177,0.989400,0.989622,0.989841,0.990058,0.990273,0.990485,0.990695,
-0.990903,0.991108,0.991311,0.991511,0.991710,0.991906,0.992099,0.992291,
-0.992480,0.992666,0.992850,0.993032,0.993212,0.993389,0.993564,0.993737,
-0.993907,0.994075,0.994240,0.994404,0.994565,0.994723,0.994879,0.995033,
-0.995185,0.995334,0.995481,0.995625,0.995767,0.995907,0.996045,0.996180,
-0.996313,0.996443,0.996571,0.996697,0.996820,0.996941,0.997060,0.997176,
-0.997290,0.997402,0.997511,0.997618,0.997723,0.997825,0.997925,0.998023,
-0.998118,0.998211,0.998302,0.998390,0.998476,0.998559,0.998640,0.998719,
-0.998795,0.998870,0.998941,0.999011,0.999078,0.999142,0.999205,0.999265,
-0.999322,0.999378,0.999431,0.999481,0.999529,0.999575,0.999619,0.999660,
-0.999699,0.999735,0.999769,0.999801,0.999831,0.999858,0.999882,0.999905,
-0.999925,0.999942,0.999958,0.999971,0.999981,0.999989,0.999995,0.999999
-};
-
-double sin( double x ) {
- int index;
- int quad;
-
- index = 1024 * x / (M_PI * 0.5);
- quad = ( index >> 10 ) & 3;
- index &= 1023;
- switch ( quad ) {
- case 0:
- return sintable[index];
- case 1:
- return sintable[1023-index];
- case 2:
- return -sintable[index];
- case 3:
- return -sintable[1023-index];
- }
- return 0;
-}
-
-
-double cos( double x ) {
- int index;
- int quad;
-
- index = 1024 * x / (M_PI * 0.5);
- quad = ( index >> 10 ) & 3;
- index &= 1023;
- switch ( quad ) {
- case 3:
- return sintable[index];
- case 0:
- return sintable[1023-index];
- case 1:
- return -sintable[index];
- case 2:
- return -sintable[1023-index];
- }
- return 0;
-}
-
-
-/*
-void create_acostable( void ) {
- int i;
- FILE *fp;
- float a;
-
- fp = fopen("c:\\acostable.txt", "w");
- fprintf(fp, "float acostable[] = {");
- for (i = 0; i < 1024; i++) {
- if (!(i & 7))
- fprintf(fp, "\n");
- a = acos( (float) -1 + i / 512 );
- fprintf(fp, "%1.8f,", a);
- }
- fprintf(fp, "\n}\n");
- fclose(fp);
-}
-*/
-
-float acostable[] = {
-3.14159265,3.07908248,3.05317551,3.03328655,3.01651113,3.00172442,2.98834964,2.97604422,
-2.96458497,2.95381690,2.94362719,2.93393068,2.92466119,2.91576615,2.90720289,2.89893629,
-2.89093699,2.88318015,2.87564455,2.86831188,2.86116621,2.85419358,2.84738169,2.84071962,
-2.83419760,2.82780691,2.82153967,2.81538876,2.80934770,2.80341062,2.79757211,2.79182724,
-2.78617145,2.78060056,2.77511069,2.76969824,2.76435988,2.75909250,2.75389319,2.74875926,
-2.74368816,2.73867752,2.73372510,2.72882880,2.72398665,2.71919677,2.71445741,2.70976688,
-2.70512362,2.70052613,2.69597298,2.69146283,2.68699438,2.68256642,2.67817778,2.67382735,
-2.66951407,2.66523692,2.66099493,2.65678719,2.65261279,2.64847088,2.64436066,2.64028133,
-2.63623214,2.63221238,2.62822133,2.62425835,2.62032277,2.61641398,2.61253138,2.60867440,
-2.60484248,2.60103507,2.59725167,2.59349176,2.58975488,2.58604053,2.58234828,2.57867769,
-2.57502832,2.57139977,2.56779164,2.56420354,2.56063509,2.55708594,2.55355572,2.55004409,
-2.54655073,2.54307530,2.53961750,2.53617701,2.53275354,2.52934680,2.52595650,2.52258238,
-2.51922417,2.51588159,2.51255441,2.50924238,2.50594525,2.50266278,2.49939476,2.49614096,
-2.49290115,2.48967513,2.48646269,2.48326362,2.48007773,2.47690482,2.47374472,2.47059722,
-2.46746215,2.46433933,2.46122860,2.45812977,2.45504269,2.45196720,2.44890314,2.44585034,
-2.44280867,2.43977797,2.43675809,2.43374890,2.43075025,2.42776201,2.42478404,2.42181622,
-2.41885841,2.41591048,2.41297232,2.41004380,2.40712480,2.40421521,2.40131491,2.39842379,
-2.39554173,2.39266863,2.38980439,2.38694889,2.38410204,2.38126374,2.37843388,2.37561237,
-2.37279910,2.36999400,2.36719697,2.36440790,2.36162673,2.35885335,2.35608768,2.35332964,
-2.35057914,2.34783610,2.34510044,2.34237208,2.33965094,2.33693695,2.33423003,2.33153010,
-2.32883709,2.32615093,2.32347155,2.32079888,2.31813284,2.31547337,2.31282041,2.31017388,
-2.30753373,2.30489988,2.30227228,2.29965086,2.29703556,2.29442632,2.29182309,2.28922580,
-2.28663439,2.28404881,2.28146900,2.27889490,2.27632647,2.27376364,2.27120637,2.26865460,
-2.26610827,2.26356735,2.26103177,2.25850149,2.25597646,2.25345663,2.25094195,2.24843238,
-2.24592786,2.24342836,2.24093382,2.23844420,2.23595946,2.23347956,2.23100444,2.22853408,
-2.22606842,2.22360742,2.22115104,2.21869925,2.21625199,2.21380924,2.21137096,2.20893709,
-2.20650761,2.20408248,2.20166166,2.19924511,2.19683280,2.19442469,2.19202074,2.18962092,
-2.18722520,2.18483354,2.18244590,2.18006225,2.17768257,2.17530680,2.17293493,2.17056692,
-2.16820274,2.16584236,2.16348574,2.16113285,2.15878367,2.15643816,2.15409630,2.15175805,
-2.14942338,2.14709226,2.14476468,2.14244059,2.14011997,2.13780279,2.13548903,2.13317865,
-2.13087163,2.12856795,2.12626757,2.12397047,2.12167662,2.11938600,2.11709859,2.11481435,
-2.11253326,2.11025530,2.10798044,2.10570867,2.10343994,2.10117424,2.09891156,2.09665185,
-2.09439510,2.09214129,2.08989040,2.08764239,2.08539725,2.08315496,2.08091550,2.07867884,
-2.07644495,2.07421383,2.07198545,2.06975978,2.06753681,2.06531651,2.06309887,2.06088387,
-2.05867147,2.05646168,2.05425445,2.05204979,2.04984765,2.04764804,2.04545092,2.04325628,
-2.04106409,2.03887435,2.03668703,2.03450211,2.03231957,2.03013941,2.02796159,2.02578610,
-2.02361292,2.02144204,2.01927344,2.01710710,2.01494300,2.01278113,2.01062146,2.00846399,
-2.00630870,2.00415556,2.00200457,1.99985570,1.99770895,1.99556429,1.99342171,1.99128119,
-1.98914271,1.98700627,1.98487185,1.98273942,1.98060898,1.97848051,1.97635399,1.97422942,
-1.97210676,1.96998602,1.96786718,1.96575021,1.96363511,1.96152187,1.95941046,1.95730088,
-1.95519310,1.95308712,1.95098292,1.94888050,1.94677982,1.94468089,1.94258368,1.94048818,
-1.93839439,1.93630228,1.93421185,1.93212308,1.93003595,1.92795046,1.92586659,1.92378433,
-1.92170367,1.91962459,1.91754708,1.91547113,1.91339673,1.91132385,1.90925250,1.90718266,
-1.90511432,1.90304746,1.90098208,1.89891815,1.89685568,1.89479464,1.89273503,1.89067683,
-1.88862003,1.88656463,1.88451060,1.88245794,1.88040664,1.87835668,1.87630806,1.87426076,
-1.87221477,1.87017008,1.86812668,1.86608457,1.86404371,1.86200412,1.85996577,1.85792866,
-1.85589277,1.85385809,1.85182462,1.84979234,1.84776125,1.84573132,1.84370256,1.84167495,
-1.83964848,1.83762314,1.83559892,1.83357582,1.83155381,1.82953289,1.82751305,1.82549429,
-1.82347658,1.82145993,1.81944431,1.81742973,1.81541617,1.81340362,1.81139207,1.80938151,
-1.80737194,1.80536334,1.80335570,1.80134902,1.79934328,1.79733848,1.79533460,1.79333164,
-1.79132959,1.78932843,1.78732817,1.78532878,1.78333027,1.78133261,1.77933581,1.77733985,
-1.77534473,1.77335043,1.77135695,1.76936428,1.76737240,1.76538132,1.76339101,1.76140148,
-1.75941271,1.75742470,1.75543743,1.75345090,1.75146510,1.74948002,1.74749565,1.74551198,
-1.74352900,1.74154672,1.73956511,1.73758417,1.73560389,1.73362426,1.73164527,1.72966692,
-1.72768920,1.72571209,1.72373560,1.72175971,1.71978441,1.71780969,1.71583556,1.71386199,
-1.71188899,1.70991653,1.70794462,1.70597325,1.70400241,1.70203209,1.70006228,1.69809297,
-1.69612416,1.69415584,1.69218799,1.69022062,1.68825372,1.68628727,1.68432127,1.68235571,
-1.68039058,1.67842588,1.67646160,1.67449772,1.67253424,1.67057116,1.66860847,1.66664615,
-1.66468420,1.66272262,1.66076139,1.65880050,1.65683996,1.65487975,1.65291986,1.65096028,
-1.64900102,1.64704205,1.64508338,1.64312500,1.64116689,1.63920905,1.63725148,1.63529416,
-1.63333709,1.63138026,1.62942366,1.62746728,1.62551112,1.62355517,1.62159943,1.61964388,
-1.61768851,1.61573332,1.61377831,1.61182346,1.60986877,1.60791422,1.60595982,1.60400556,
-1.60205142,1.60009739,1.59814349,1.59618968,1.59423597,1.59228235,1.59032882,1.58837536,
-1.58642196,1.58446863,1.58251535,1.58056211,1.57860891,1.57665574,1.57470259,1.57274945,
-1.57079633,1.56884320,1.56689007,1.56493692,1.56298375,1.56103055,1.55907731,1.55712403,
-1.55517069,1.55321730,1.55126383,1.54931030,1.54735668,1.54540297,1.54344917,1.54149526,
-1.53954124,1.53758710,1.53563283,1.53367843,1.53172389,1.52976919,1.52781434,1.52585933,
-1.52390414,1.52194878,1.51999323,1.51803748,1.51608153,1.51412537,1.51216900,1.51021240,
-1.50825556,1.50629849,1.50434117,1.50238360,1.50042576,1.49846765,1.49650927,1.49455060,
-1.49259163,1.49063237,1.48867280,1.48671291,1.48475270,1.48279215,1.48083127,1.47887004,
-1.47690845,1.47494650,1.47298419,1.47102149,1.46905841,1.46709493,1.46513106,1.46316677,
-1.46120207,1.45923694,1.45727138,1.45530538,1.45333893,1.45137203,1.44940466,1.44743682,
-1.44546850,1.44349969,1.44153038,1.43956057,1.43759024,1.43561940,1.43364803,1.43167612,
-1.42970367,1.42773066,1.42575709,1.42378296,1.42180825,1.41983295,1.41785705,1.41588056,
-1.41390346,1.41192573,1.40994738,1.40796840,1.40598877,1.40400849,1.40202755,1.40004594,
-1.39806365,1.39608068,1.39409701,1.39211264,1.39012756,1.38814175,1.38615522,1.38416795,
-1.38217994,1.38019117,1.37820164,1.37621134,1.37422025,1.37222837,1.37023570,1.36824222,
-1.36624792,1.36425280,1.36225684,1.36026004,1.35826239,1.35626387,1.35426449,1.35226422,
-1.35026307,1.34826101,1.34625805,1.34425418,1.34224937,1.34024364,1.33823695,1.33622932,
-1.33422072,1.33221114,1.33020059,1.32818904,1.32617649,1.32416292,1.32214834,1.32013273,
-1.31811607,1.31609837,1.31407960,1.31205976,1.31003885,1.30801684,1.30599373,1.30396951,
-1.30194417,1.29991770,1.29789009,1.29586133,1.29383141,1.29180031,1.28976803,1.28773456,
-1.28569989,1.28366400,1.28162688,1.27958854,1.27754894,1.27550809,1.27346597,1.27142257,
-1.26937788,1.26733189,1.26528459,1.26323597,1.26118602,1.25913471,1.25708205,1.25502803,
-1.25297262,1.25091583,1.24885763,1.24679802,1.24473698,1.24267450,1.24061058,1.23854519,
-1.23647833,1.23440999,1.23234015,1.23026880,1.22819593,1.22612152,1.22404557,1.22196806,
-1.21988898,1.21780832,1.21572606,1.21364219,1.21155670,1.20946958,1.20738080,1.20529037,
-1.20319826,1.20110447,1.19900898,1.19691177,1.19481283,1.19271216,1.19060973,1.18850553,
-1.18639955,1.18429178,1.18218219,1.18007079,1.17795754,1.17584244,1.17372548,1.17160663,
-1.16948589,1.16736324,1.16523866,1.16311215,1.16098368,1.15885323,1.15672081,1.15458638,
-1.15244994,1.15031147,1.14817095,1.14602836,1.14388370,1.14173695,1.13958808,1.13743709,
-1.13528396,1.13312866,1.13097119,1.12881153,1.12664966,1.12448556,1.12231921,1.12015061,
-1.11797973,1.11580656,1.11363107,1.11145325,1.10927308,1.10709055,1.10490563,1.10271831,
-1.10052856,1.09833638,1.09614174,1.09394462,1.09174500,1.08954287,1.08733820,1.08513098,
-1.08292118,1.08070879,1.07849378,1.07627614,1.07405585,1.07183287,1.06960721,1.06737882,
-1.06514770,1.06291382,1.06067715,1.05843769,1.05619540,1.05395026,1.05170226,1.04945136,
-1.04719755,1.04494080,1.04268110,1.04041841,1.03815271,1.03588399,1.03361221,1.03133735,
-1.02905939,1.02677830,1.02449407,1.02220665,1.01991603,1.01762219,1.01532509,1.01302471,
-1.01072102,1.00841400,1.00610363,1.00378986,1.00147268,0.99915206,0.99682798,0.99450039,
-0.99216928,0.98983461,0.98749636,0.98515449,0.98280898,0.98045980,0.97810691,0.97575030,
-0.97338991,0.97102573,0.96865772,0.96628585,0.96391009,0.96153040,0.95914675,0.95675912,
-0.95436745,0.95197173,0.94957191,0.94716796,0.94475985,0.94234754,0.93993099,0.93751017,
-0.93508504,0.93265556,0.93022170,0.92778341,0.92534066,0.92289341,0.92044161,0.91798524,
-0.91552424,0.91305858,0.91058821,0.90811309,0.90563319,0.90314845,0.90065884,0.89816430,
-0.89566479,0.89316028,0.89065070,0.88813602,0.88561619,0.88309116,0.88056088,0.87802531,
-0.87548438,0.87293806,0.87038629,0.86782901,0.86526619,0.86269775,0.86012366,0.85754385,
-0.85495827,0.85236686,0.84976956,0.84716633,0.84455709,0.84194179,0.83932037,0.83669277,
-0.83405893,0.83141877,0.82877225,0.82611928,0.82345981,0.82079378,0.81812110,0.81544172,
-0.81275556,0.81006255,0.80736262,0.80465570,0.80194171,0.79922057,0.79649221,0.79375655,
-0.79101352,0.78826302,0.78550497,0.78273931,0.77996593,0.77718475,0.77439569,0.77159865,
-0.76879355,0.76598029,0.76315878,0.76032891,0.75749061,0.75464376,0.75178826,0.74892402,
-0.74605092,0.74316887,0.74027775,0.73737744,0.73446785,0.73154885,0.72862033,0.72568217,
-0.72273425,0.71977644,0.71680861,0.71383064,0.71084240,0.70784376,0.70483456,0.70181469,
-0.69878398,0.69574231,0.69268952,0.68962545,0.68654996,0.68346288,0.68036406,0.67725332,
-0.67413051,0.67099544,0.66784794,0.66468783,0.66151492,0.65832903,0.65512997,0.65191753,
-0.64869151,0.64545170,0.64219789,0.63892987,0.63564741,0.63235028,0.62903824,0.62571106,
-0.62236849,0.61901027,0.61563615,0.61224585,0.60883911,0.60541564,0.60197515,0.59851735,
-0.59504192,0.59154856,0.58803694,0.58450672,0.58095756,0.57738911,0.57380101,0.57019288,
-0.56656433,0.56291496,0.55924437,0.55555212,0.55183778,0.54810089,0.54434099,0.54055758,
-0.53675018,0.53291825,0.52906127,0.52517867,0.52126988,0.51733431,0.51337132,0.50938028,
-0.50536051,0.50131132,0.49723200,0.49312177,0.48897987,0.48480547,0.48059772,0.47635573,
-0.47207859,0.46776530,0.46341487,0.45902623,0.45459827,0.45012983,0.44561967,0.44106652,
-0.43646903,0.43182577,0.42713525,0.42239588,0.41760600,0.41276385,0.40786755,0.40291513,
-0.39790449,0.39283339,0.38769946,0.38250016,0.37723277,0.37189441,0.36648196,0.36099209,
-0.35542120,0.34976542,0.34402054,0.33818204,0.33224495,0.32620390,0.32005298,0.31378574,
-0.30739505,0.30087304,0.29421096,0.28739907,0.28042645,0.27328078,0.26594810,0.25841250,
-0.25065566,0.24265636,0.23438976,0.22582651,0.21693146,0.20766198,0.19796546,0.18777575,
-0.17700769,0.16554844,0.15324301,0.13986823,0.12508152,0.10830610,0.08841715,0.06251018,
-}
-
-double acos( double x ) {
- int index;
-
- if (x < -1)
- x = -1;
- if (x > 1)
- x = 1;
- index = (float) (1.0 + x) * 511.9;
- return acostable[index];
-}
-
-double atan2( double y, double x ) {
- float base;
- float temp;
- float dir;
- float test;
- int i;
-
- if ( x < 0 ) {
- if ( y >= 0 ) {
- // quad 1
- base = M_PI / 2;
- temp = x;
- x = y;
- y = -temp;
- } else {
- // quad 2
- base = M_PI;
- x = -x;
- y = -y;
- }
- } else {
- if ( y < 0 ) {
- // quad 3
- base = 3 * M_PI / 2;
- temp = x;
- x = -y;
- y = temp;
- }
- }
-
- if ( y > x ) {
- base += M_PI/2;
- temp = x;
- x = y;
- y = temp;
- dir = -1;
- } else {
- dir = 1;
- }
-
- // calcualte angle in octant 0
- if ( x == 0 ) {
- return base;
- }
- y /= x;
-
- for ( i = 0 ; i < 512 ; i++ ) {
- test = sintable[i] / sintable[1023-i];
- if ( test > y ) {
- break;
- }
- }
-
- return base + dir * i * ( M_PI/2048);
-}
-
-
-#endif
-
-double tan( double x ) {
- return sin(x) / cos(x);
-}
-
-
-static int randSeed = 0;
-
-void srand( unsigned seed ) {
- randSeed = seed;
-}
-
-int rand( void ) {
- randSeed = (69069 * randSeed + 1);
- return randSeed & 0x7fff;
-}
-
-double atof( const char *string ) {
- float sign;
- float value;
- int c;
-
-
- // skip whitespace
- while ( *string <= ' ' ) {
- if ( !*string ) {
- return 0;
- }
- string++;
- }
-
- // check sign
- switch ( *string ) {
- case '+':
- string++;
- sign = 1;
- break;
- case '-':
- string++;
- sign = -1;
- break;
- default:
- sign = 1;
- break;
- }
-
- // read digits
- value = 0;
- c = string[0];
- if ( c != '.' ) {
- do {
- c = *string++;
- if ( c < '0' || c > '9' ) {
- break;
- }
- c -= '0';
- value = value * 10 + c;
- } while ( 1 );
- } else {
- string++;
- }
-
- // check for decimal point
- if ( c == '.' ) {
- double fraction;
-
- fraction = 0.1;
- do {
- c = *string++;
- if ( c < '0' || c > '9' ) {
- break;
- }
- c -= '0';
- value += c * fraction;
- fraction *= 0.1;
- } while ( 1 );
-
- }
-
- // not handling 10e10 notation...
-
- return value * sign;
-}
-
-double _atof( const char **stringPtr ) {
- const char *string;
- float sign;
- float value;
- int c = '0';
-
- string = *stringPtr;
-
- // skip whitespace
- while ( *string <= ' ' ) {
- if ( !*string ) {
- *stringPtr = string;
- return 0;
- }
- string++;
- }
-
- // check sign
- switch ( *string ) {
- case '+':
- string++;
- sign = 1;
- break;
- case '-':
- string++;
- sign = -1;
- break;
- default:
- sign = 1;
- break;
- }
-
- // read digits
- value = 0;
- if ( string[0] != '.' ) {
- do {
- c = *string++;
- if ( c < '0' || c > '9' ) {
- break;
- }
- c -= '0';
- value = value * 10 + c;
- } while ( 1 );
- }
-
- // check for decimal point
- if ( c == '.' ) {
- double fraction;
-
- fraction = 0.1;
- do {
- c = *string++;
- if ( c < '0' || c > '9' ) {
- break;
- }
- c -= '0';
- value += c * fraction;
- fraction *= 0.1;
- } while ( 1 );
-
- }
-
- // not handling 10e10 notation...
- *stringPtr = string;
-
- return value * sign;
-}
-
-/*
-==============
-strtod
-
-Without an errno variable, this is a fair bit less useful than it is in libc
-but it's still a fair bit more capable than atof or _atof
-Handles inf[inity], nan (ignoring case), hexadecimals, and decimals
-Handles decimal exponents like 10e10 and hex exponents like 0x7f8p20
-10e10 == 10000000000 (power of ten)
-0x7f8p20 == 0x7f800000 (decimal power of two)
-The variable pointed to by endptr will hold the location of the first character
-in the nptr string that was not used in the conversion
-==============
-*/
-double strtod( const char *nptr, const char **endptr )
-{
- double res;
- qboolean neg = qfalse;
-
- // skip whitespace
- while( isspace( *nptr ) )
- nptr++;
-
- // special string parsing
- if( Q_stricmpn( nptr, "nan", 3 ) == 0 )
- {
- floatint_t nan;
- if( endptr == NULL )
- {
- nan.ui = 0x7fffffff;
- return nan.f;
- }
- *endptr = &nptr[3];
- // nan can be followed by a bracketed number (in hex, octal,
- // or decimal) which is then put in the mantissa
- // this can be used to generate signalling or quiet NaNs, for
- // example (though I doubt it'll ever be used)
- // note that nan(0) is infinity!
- if( nptr[3] == '(' )
- {
- const char *end;
- int mantissa = strtol( &nptr[4], &end, 0 );
- if( *end == ')' )
- {
- nan.ui = 0x7f800000 | ( mantissa & 0x7fffff );
- if( endptr )
- *endptr = &end[1];
- return nan.f;
- }
- }
- nan.ui = 0x7fffffff;
- return nan.f;
- }
- if( Q_stricmpn( nptr, "inf", 3 ) == 0 )
- {
- floatint_t inf;
- inf.ui = 0x7f800000;
- if( endptr == NULL )
- return inf.f;
- if( Q_stricmpn( &nptr[3], "inity", 5 ) == 0 )
- *endptr = &nptr[8];
- else
- *endptr = &nptr[3];
- return inf.f;
- }
-
- // normal numeric parsing
- // sign
- if( *nptr == '-' )
- {
- nptr++;
- neg = qtrue;
- }
- else if( *nptr == '+' )
- nptr++;
- // hex
- if( Q_stricmpn( nptr, "0x", 2 ) == 0 )
- {
- // track if we use any digits
- const char *s = &nptr[1], *end = s;
- nptr += 2;
- res = 0;
- while( qtrue )
- {
- if( isdigit( *nptr ) )
- res = 16 * res + ( *nptr++ - '0' );
- else if( *nptr >= 'A' && *nptr <= 'F' )
- res = 16 * res + 10 + *nptr++ - 'A';
- else if( *nptr >= 'a' && *nptr <= 'f' )
- res = 16 * res + 10 + *nptr++ - 'a';
- else
- break;
- }
- // if nptr moved, save it
- if( end + 1 < nptr )
- end = nptr;
- if( *nptr == '.' )
- {
- float place;
- nptr++;
- // 1.0 / 16.0 == 0.0625
- // I don't expect the float accuracy to hold out for
- // very long but since we need to know the length of
- // the string anyway we keep on going regardless
- for( place = 0.0625;; place /= 16.0 )
- {
- if( isdigit( *nptr ) )
- res += place * ( *nptr++ - '0' );
- else if( *nptr >= 'A' && *nptr <= 'F' )
- res += place * ( 10 + *nptr++ - 'A' );
- else if( *nptr >= 'a' && *nptr <= 'f' )
- res += place * ( 10 + *nptr++ - 'a' );
- else
- break;
- }
- if( end < nptr )
- end = nptr;
- }
- // parse an optional exponent, representing multiplication
- // by a power of two
- // exponents are only valid if we encountered at least one
- // digit already (and have therefore set end to something)
- if( end != s && tolower( *nptr ) == 'p' )
- {
- int exp;
- float res2;
- // apparently (confusingly) the exponent should be
- // decimal
- exp = strtol( &nptr[1], &end, 10 );
- if( &nptr[1] == end )
- {
- // no exponent
- if( endptr )
- *endptr = nptr;
- return res;
- }
- if( exp > 0 )
- {
- while( exp-- > 0 )
- {
- res2 = res * 2;
- // check for infinity
- if( res2 <= res )
- break;
- res = res2;
- }
- }
- else
- {
- while( exp++ < 0 )
- {
- res2 = res / 2;
- // check for underflow
- if( res2 >= res )
- break;
- res = res2;
- }
- }
- }
- if( endptr )
- *endptr = end;
- return res;
- }
- // decimal
- else
- {
- // track if we find any digits
- const char *end = nptr, *p = nptr;
- // this is most of the work
- for( res = 0; isdigit( *nptr );
- res = 10 * res + *nptr++ - '0' );
- // if nptr moved, we read something
- if( end < nptr )
- end = nptr;
- if( *nptr == '.' )
- {
- // fractional part
- float place;
- nptr++;
- for( place = 0.1; isdigit( *nptr ); place /= 10.0 )
- res += ( *nptr++ - '0' ) * place;
- // if nptr moved, we read something
- if( end + 1 < nptr )
- end = nptr;
- }
- // exponent
- // meaningless without having already read digits, so check
- // we've set end to something
- if( p != end && tolower( *nptr ) == 'e' )
- {
- int exp;
- float res10;
- exp = strtol( &nptr[1], &end, 10 );
- if( &nptr[1] == end )
- {
- // no exponent
- if( endptr )
- *endptr = nptr;
- return res;
- }
- if( exp > 0 )
- {
- while( exp-- > 0 )
- {
- res10 = res * 10;
- // check for infinity to save us time
- if( res10 <= res )
- break;
- res = res10;
- }
- }
- else if( exp < 0 )
- {
- while( exp++ < 0 )
- {
- res10 = res / 10;
- // check for underflow
- // (test for 0 would probably be just
- // as good)
- if( res10 >= res )
- break;
- res = res10;
- }
- }
- }
- if( endptr )
- *endptr = end;
- return res;
- }
-}
-
-int atoi( const char *string ) {
- int sign;
- int value;
- int c;
-
-
- // skip whitespace
- while ( *string <= ' ' ) {
- if ( !*string ) {
- return 0;
- }
- string++;
- }
-
- // check sign
- switch ( *string ) {
- case '+':
- string++;
- sign = 1;
- break;
- case '-':
- string++;
- sign = -1;
- break;
- default:
- sign = 1;
- break;
- }
-
- // read digits
- value = 0;
- do {
- c = *string++;
- if ( c < '0' || c > '9' ) {
- break;
- }
- c -= '0';
- value = value * 10 + c;
- } while ( 1 );
-
- // not handling 10e10 notation...
-
- return value * sign;
-}
-
-
-int _atoi( const char **stringPtr ) {
- int sign;
- int value;
- int c;
- const char *string;
-
- string = *stringPtr;
-
- // skip whitespace
- while ( *string <= ' ' ) {
- if ( !*string ) {
- return 0;
- }
- string++;
- }
-
- // check sign
- switch ( *string ) {
- case '+':
- string++;
- sign = 1;
- break;
- case '-':
- string++;
- sign = -1;
- break;
- default:
- sign = 1;
- break;
- }
-
- // read digits
- value = 0;
- do {
- c = *string++;
- if ( c < '0' || c > '9' ) {
- break;
- }
- c -= '0';
- value = value * 10 + c;
- } while ( 1 );
-
- // not handling 10e10 notation...
-
- *stringPtr = string;
-
- return value * sign;
-}
-
-/*
-==============
-strtol
-
-Handles any base from 2 to 36. If base is 0 then it guesses
-decimal, hex, or octal based on the format of the number (leading 0 or 0x)
-Will not overflow - returns LONG_MIN or LONG_MAX as appropriate
-*endptr is set to the location of the first character not used
-==============
-*/
-long strtol( const char *nptr, const char **endptr, int base )
-{
- long res;
- qboolean pos = qtrue;
-
- if( endptr )
- *endptr = nptr;
- // bases other than 0, 2, 8, 16 are very rarely used, but they're
- // not much extra effort to support
- if( base < 0 || base == 1 || base > 36 )
- return 0;
- // skip leading whitespace
- while( isspace( *nptr ) )
- nptr++;
- // sign
- if( *nptr == '-' )
- {
- nptr++;
- pos = qfalse;
- }
- else if( *nptr == '+' )
- nptr++;
- // look for base-identifying sequences e.g. 0x for hex, 0 for octal
- if( nptr[0] == '0' )
- {
- nptr++;
- // 0 is always a valid digit
- if( endptr )
- *endptr = nptr;
- if( *nptr == 'x' || *nptr == 'X' )
- {
- if( base != 0 && base != 16 )
- {
- // can't be hex, reject x (accept 0)
- if( endptr )
- *endptr = nptr;
- return 0;
- }
- nptr++;
- base = 16;
- }
- else if( base == 0 )
- base = 8;
- }
- else if( base == 0 )
- base = 10;
- res = 0;
- while( qtrue )
- {
- int val;
- if( isdigit( *nptr ) )
- val = *nptr - '0';
- else if( islower( *nptr ) )
- val = 10 + *nptr - 'a';
- else if( isupper( *nptr ) )
- val = 10 + *nptr - 'A';
- else
- break;
- if( val >= base )
- break;
- // we go negative because LONG_MIN is further from 0 than
- // LONG_MAX
- if( res < ( LONG_MIN + val ) / base )
- res = LONG_MIN; // overflow
- else
- res = res * base - val;
- nptr++;
- if( endptr )
- *endptr = nptr;
- }
- if( pos )
- {
- // can't represent LONG_MIN positive
- if( res == LONG_MIN )
- res = LONG_MAX;
- else
- res = -res;
- }
- return res;
-}
-
-int abs( int n ) {
- return n < 0 ? -n : n;
-}
-
-double fabs( double x ) {
- return x < 0 ? -x : x;
-}
-
-
-
-//=========================================================
-
-/*
- * New implementation by Patrick Powell and others for vsnprintf.
- * Supports length checking in strings.
-*/
-
-/*
- * Copyright Patrick Powell 1995
- * This code is based on code written by Patrick Powell (papowell at astart.com)
- * It may be used for any purpose as long as this notice remains intact
- * on all source code distributions
- */
-
-/**************************************************************
- * Original:
- * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
- * A bombproof version of doprnt (dopr) included.
- * Sigh. This sort of thing is always nasty do deal with. Note that
- * the version here does not include floating point...
- *
- * snprintf() is used instead of sprintf() as it does limit checks
- * for string length. This covers a nasty loophole.
- *
- * The other functions are there to prevent NULL pointers from
- * causing nast effects.
- *
- * More Recently:
- * Brandon Long <blong at fiction.net> 9/15/96 for mutt 0.43
- * This was ugly. It is still ugly. I opted out of floating point
- * numbers, but the formatter understands just about everything
- * from the normal C string format, at least as far as I can tell from
- * the Solaris 2.5 printf(3S) man page.
- *
- * Brandon Long <blong at fiction.net> 10/22/97 for mutt 0.87.1
- * Ok, added some minimal floating point support, which means this
- * probably requires libm on most operating systems. Don't yet
- * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
- * was pretty badly broken, it just wasn't being exercised in ways
- * which showed it, so that's been fixed. Also, formated the code
- * to mutt conventions, and removed dead code left over from the
- * original. Also, there is now a builtin-test, just compile with:
- * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
- * and run snprintf for results.
- *
- * Thomas Roessler <roessler at guug.de> 01/27/98 for mutt 0.89i
- * The PGP code was using unsigned hexadecimal formats.
- * Unfortunately, unsigned formats simply didn't work.
- *
- * Michael Elkins <me at cs.hmc.edu> 03/05/98 for mutt 0.90.8
- * The original code assumed that both snprintf() and vsnprintf() were
- * missing. Some systems only have snprintf() but not vsnprintf(), so
- * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
- *
- * Andrew Tridgell (tridge at samba.org) Oct 1998
- * fixed handling of %.0f
- * added test for HAVE_LONG_DOUBLE
- *
- * Russ Allbery <rra at stanford.edu> 2000-08-26
- * fixed return value to comply with C99
- * fixed handling of snprintf(NULL, ...)
- *
- * Hrvoje Niksic <hniksic at arsdigita.com> 2000-11-04
- * include <config.h> instead of "config.h".
- * moved TEST_SNPRINTF stuff out of HAVE_SNPRINTF ifdef.
- * include <stdio.h> for NULL.
- * added support and test cases for long long.
- * don't declare argument types to (v)snprintf if stdarg is not used.
- * use int instead of short int as 2nd arg to va_arg.
- *
- **************************************************************/
-
-/* BDR 2002-01-13 %e and %g were being ignored. Now do something,
- if not necessarily correctly */
-
-#if (SIZEOF_LONG_DOUBLE > 0)
-/* #ifdef HAVE_LONG_DOUBLE */
-#define LDOUBLE long double
-#else
-#define LDOUBLE double
-#endif
-
-#if (SIZEOF_LONG_LONG > 0)
-/* #ifdef HAVE_LONG_LONG */
-# define LLONG long long
-#else
-# define LLONG long
-#endif
-
-static int dopr (char *buffer, size_t maxlen, const char *format,
- va_list args);
-static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
- char *value, int flags, int min, int max);
-static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
- LLONG value, int base, int min, int max, int flags);
-static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
- LDOUBLE fvalue, int min, int max, int flags);
-static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
-
-/*
- * dopr(): poor man's version of doprintf
- */
-
-/* format read states */
-#define DP_S_DEFAULT 0
-#define DP_S_FLAGS 1
-#define DP_S_MIN 2
-#define DP_S_DOT 3
-#define DP_S_MAX 4
-#define DP_S_MOD 5
-#define DP_S_MOD_L 6
-#define DP_S_CONV 7
-#define DP_S_DONE 8
-
-/* format flags - Bits */
-#define DP_F_MINUS (1 << 0)
-#define DP_F_PLUS (1 << 1)
-#define DP_F_SPACE (1 << 2)
-#define DP_F_NUM (1 << 3)
-#define DP_F_ZERO (1 << 4)
-#define DP_F_UP (1 << 5)
-#define DP_F_UNSIGNED (1 << 6)
-
-/* Conversion Flags */
-#define DP_C_SHORT 1
-#define DP_C_LONG 2
-#define DP_C_LLONG 3
-#define DP_C_LDOUBLE 4
-
-#define char_to_int(p) (p - '0')
-#define MAX(p,q) ((p >= q) ? p : q)
-#define MIN(p,q) ((p <= q) ? p : q)
-
-static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
-{
- char ch;
- LLONG value;
- LDOUBLE fvalue;
- char *strvalue;
- int min;
- int max;
- int state;
- int flags;
- int cflags;
- int total;
- size_t currlen;
-
- state = DP_S_DEFAULT;
- currlen = flags = cflags = min = 0;
- max = -1;
- ch = *format++;
- total = 0;
-
- while (state != DP_S_DONE)
- {
- if (ch == '\0')
- state = DP_S_DONE;
-
- switch(state)
- {
- case DP_S_DEFAULT:
- if (ch == '%')
- state = DP_S_FLAGS;
- else
- total += dopr_outch (buffer, &currlen, maxlen, ch);
- ch = *format++;
- break;
- case DP_S_FLAGS:
- switch (ch)
- {
- case '-':
- flags |= DP_F_MINUS;
- ch = *format++;
- break;
- case '+':
- flags |= DP_F_PLUS;
- ch = *format++;
- break;
- case ' ':
- flags |= DP_F_SPACE;
- ch = *format++;
- break;
- case '#':
- flags |= DP_F_NUM;
- ch = *format++;
- break;
- case '0':
- flags |= DP_F_ZERO;
- ch = *format++;
- break;
- default:
- state = DP_S_MIN;
- break;
- }
- break;
- case DP_S_MIN:
- if ('0' <= ch && ch <= '9')
- {
- min = 10*min + char_to_int (ch);
- ch = *format++;
- }
- else if (ch == '*')
- {
- min = va_arg (args, int);
- ch = *format++;
- state = DP_S_DOT;
- }
- else
- state = DP_S_DOT;
- break;
- case DP_S_DOT:
- if (ch == '.')
- {
- state = DP_S_MAX;
- ch = *format++;
- }
- else
- state = DP_S_MOD;
- break;
- case DP_S_MAX:
- if ('0' <= ch && ch <= '9')
- {
- if (max < 0)
- max = 0;
- max = 10*max + char_to_int (ch);
- ch = *format++;
- }
- else if (ch == '*')
- {
- max = va_arg (args, int);
- ch = *format++;
- state = DP_S_MOD;
- }
- else
- state = DP_S_MOD;
- break;
- case DP_S_MOD:
- switch (ch)
- {
- case 'h':
- cflags = DP_C_SHORT;
- ch = *format++;
- break;
- case 'l':
- cflags = DP_C_LONG;
- ch = *format++;
- break;
- case 'L':
- cflags = DP_C_LDOUBLE;
- ch = *format++;
- break;
- default:
- break;
- }
- if (cflags != DP_C_LONG)
- state = DP_S_CONV;
- else
- state = DP_S_MOD_L;
- break;
- case DP_S_MOD_L:
- switch (ch)
- {
- case 'l':
- cflags = DP_C_LLONG;
- ch = *format++;
- break;
- default:
- break;
- }
- state = DP_S_CONV;
- break;
- case DP_S_CONV:
- switch (ch)
- {
- case 'd':
- case 'i':
- if (cflags == DP_C_SHORT)
- value = (short int)va_arg (args, int);
- else if (cflags == DP_C_LONG)
- value = va_arg (args, long int);
- else if (cflags == DP_C_LLONG)
- value = va_arg (args, LLONG);
- else
- value = va_arg (args, int);
- total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
- break;
- case 'o':
- flags |= DP_F_UNSIGNED;
- if (cflags == DP_C_SHORT)
-// value = (unsigned short int) va_arg (args, unsigned short int); // Thilo: This does not work because the rcc compiler cannot do that cast correctly.
- value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1); // Using this workaround instead.
- else if (cflags == DP_C_LONG)
- value = va_arg (args, unsigned long int);
- else if (cflags == DP_C_LLONG)
- value = va_arg (args, unsigned LLONG);
- else
- value = va_arg (args, unsigned int);
- total += fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
- break;
- case 'u':
- flags |= DP_F_UNSIGNED;
- if (cflags == DP_C_SHORT)
- value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1);
- else if (cflags == DP_C_LONG)
- value = va_arg (args, unsigned long int);
- else if (cflags == DP_C_LLONG)
- value = va_arg (args, unsigned LLONG);
- else
- value = va_arg (args, unsigned int);
- total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
- break;
- case 'X':
- flags |= DP_F_UP;
- case 'x':
- flags |= DP_F_UNSIGNED;
- if (cflags == DP_C_SHORT)
- value = va_arg (args, unsigned int) & ( (1 << sizeof(unsigned short int) * 8) - 1);
- else if (cflags == DP_C_LONG)
- value = va_arg (args, unsigned long int);
- else if (cflags == DP_C_LLONG)
- value = va_arg (args, unsigned LLONG);
- else
- value = va_arg (args, unsigned int);
- total += fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
- break;
- case 'f':
- if (cflags == DP_C_LDOUBLE)
- fvalue = va_arg (args, LDOUBLE);
- else
- fvalue = va_arg (args, double);
- /* um, floating point? */
- total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
- break;
- case 'E':
- flags |= DP_F_UP;
- case 'e':
- if (cflags == DP_C_LDOUBLE)
- fvalue = va_arg (args, LDOUBLE);
- else
- fvalue = va_arg (args, double);
- /* um, floating point? */
- total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
- break;
- case 'G':
- flags |= DP_F_UP;
- case 'g':
- if (cflags == DP_C_LDOUBLE)
- fvalue = va_arg (args, LDOUBLE);
- else
- fvalue = va_arg (args, double);
- /* um, floating point? */
- total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
- break;
- case 'c':
- total += dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
- break;
- case 's':
- strvalue = va_arg (args, char *);
- total += fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
- break;
- case 'p':
- strvalue = va_arg (args, void *);
- total += fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min,
- max, flags);
- break;
- case 'n':
- if (cflags == DP_C_SHORT)
- {
- short int *num;
- num = va_arg (args, short int *);
- *num = currlen;
- }
- else if (cflags == DP_C_LONG)
- {
- long int *num;
- num = va_arg (args, long int *);
- *num = currlen;
- }
- else if (cflags == DP_C_LLONG)
- {
- LLONG *num;
- num = va_arg (args, LLONG *);
- *num = currlen;
- }
- else
- {
- int *num;
- num = va_arg (args, int *);
- *num = currlen;
- }
- break;
- case '%':
- total += dopr_outch (buffer, &currlen, maxlen, ch);
- break;
- case 'w':
- /* not supported yet, treat as next char */
- ch = *format++;
- break;
- default:
- /* Unknown, skip */
- break;
- }
- ch = *format++;
- state = DP_S_DEFAULT;
- flags = cflags = min = 0;
- max = -1;
- break;
- case DP_S_DONE:
- break;
- default:
- /* hmm? */
- break; /* some picky compilers need this */
- }
- }
- if (buffer != NULL)
- {
- if (currlen < maxlen - 1)
- buffer[currlen] = '\0';
- else
- buffer[maxlen - 1] = '\0';
- }
- return total;
-}
-
-static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
- char *value, int flags, int min, int max)
-{
- int padlen, strln; /* amount to pad */
- int cnt = 0;
- int total = 0;
-
- if (value == 0)
- {
- value = "<NULL>";
- }
-
- for (strln = 0; value[strln]; ++strln); /* strlen */
- if (max >= 0 && max < strln)
- strln = max;
- padlen = min - strln;
- if (padlen < 0)
- padlen = 0;
- if (flags & DP_F_MINUS)
- padlen = -padlen; /* Left Justify */
-
- while (padlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- --padlen;
- }
- while (*value && ((max < 0) || (cnt < max)))
- {
- total += dopr_outch (buffer, currlen, maxlen, *value++);
- ++cnt;
- }
- while (padlen < 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- ++padlen;
- }
- return total;
-}
-
-/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
-
-static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
- LLONG value, int base, int min, int max, int flags)
-{
- int signvalue = 0;
- unsigned LLONG uvalue;
- char convert[24];
- int place = 0;
- int spadlen = 0; /* amount to space pad */
- int zpadlen = 0; /* amount to zero pad */
- const char *digits;
- int total = 0;
-
- if (max < 0)
- max = 0;
-
- uvalue = value;
-
- if(!(flags & DP_F_UNSIGNED))
- {
- if( value < 0 ) {
- signvalue = '-';
- uvalue = -value;
- }
- else
- if (flags & DP_F_PLUS) /* Do a sign (+/i) */
- signvalue = '+';
- else
- if (flags & DP_F_SPACE)
- signvalue = ' ';
- }
-
- if (flags & DP_F_UP)
- /* Should characters be upper case? */
- digits = "0123456789ABCDEF";
- else
- digits = "0123456789abcdef";
-
- do {
- convert[place++] = digits[uvalue % (unsigned)base];
- uvalue = (uvalue / (unsigned)base );
- } while(uvalue && (place < sizeof (convert)));
- if (place == sizeof (convert)) place--;
- convert[place] = 0;
-
- zpadlen = max - place;
- spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
- if (zpadlen < 0) zpadlen = 0;
- if (spadlen < 0) spadlen = 0;
- if (flags & DP_F_ZERO)
- {
- zpadlen = MAX(zpadlen, spadlen);
- spadlen = 0;
- }
- if (flags & DP_F_MINUS)
- spadlen = -spadlen; /* Left Justifty */
-
-#ifdef DEBUG_SNPRINTF
- dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
- zpadlen, spadlen, min, max, place));
-#endif
-
- /* Spaces */
- while (spadlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- --spadlen;
- }
-
- /* Sign */
- if (signvalue)
- total += dopr_outch (buffer, currlen, maxlen, signvalue);
-
- /* Zeros */
- if (zpadlen > 0)
- {
- while (zpadlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, '0');
- --zpadlen;
- }
- }
-
- /* Digits */
- while (place > 0)
- total += dopr_outch (buffer, currlen, maxlen, convert[--place]);
-
- /* Left Justified spaces */
- while (spadlen < 0) {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- ++spadlen;
- }
-
- return total;
-}
-
-static LDOUBLE abs_val (LDOUBLE value)
-{
- LDOUBLE result = value;
-
- if (value < 0)
- result = -value;
-
- return result;
-}
-
-static LDOUBLE pow10 (int exp)
-{
- LDOUBLE result = 1;
-
- while (exp)
- {
- result *= 10;
- exp--;
- }
-
- return result;
-}
-
-static long round (LDOUBLE value)
-{
- long intpart;
-
- intpart = value;
- value = value - intpart;
- if (value >= 0.5)
- intpart++;
-
- return intpart;
-}
-
-static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
- LDOUBLE fvalue, int min, int max, int flags)
-{
- int signvalue = 0;
- LDOUBLE ufvalue;
- char iconvert[20];
- char fconvert[20];
- int iplace = 0;
- int fplace = 0;
- int padlen = 0; /* amount to pad */
- int zpadlen = 0;
- int caps = 0;
- int total = 0;
- long intpart;
- long fracpart;
-
- /*
- * AIX manpage says the default is 0, but Solaris says the default
- * is 6, and sprintf on AIX defaults to 6
- */
- if (max < 0)
- max = 6;
-
- ufvalue = abs_val (fvalue);
-
- if (fvalue < 0)
- signvalue = '-';
- else
- if (flags & DP_F_PLUS) /* Do a sign (+/i) */
- signvalue = '+';
- else
- if (flags & DP_F_SPACE)
- signvalue = ' ';
-
-#if 0
- if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
-#endif
-
- intpart = ufvalue;
-
- /*
- * Sorry, we only support 9 digits past the decimal because of our
- * conversion method
- */
- if (max > 9)
- max = 9;
-
- /* We "cheat" by converting the fractional part to integer by
- * multiplying by a factor of 10
- */
- fracpart = round ((pow10 (max)) * (ufvalue - intpart));
-
- if (fracpart >= pow10 (max))
- {
- intpart++;
- fracpart -= pow10 (max);
- }
-
-#ifdef DEBUG_SNPRINTF
- dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
-#endif
-
- /* Convert integer part */
- do {
- iconvert[iplace++] =
- (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
- intpart = (intpart / 10);
- } while(intpart && (iplace < 20));
- if (iplace == 20) iplace--;
- iconvert[iplace] = 0;
-
- /* Convert fractional part */
- do {
- fconvert[fplace++] =
- (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
- fracpart = (fracpart / 10);
- } while(fracpart && (fplace < 20));
- if (fplace == 20) fplace--;
- fconvert[fplace] = 0;
-
- /* -1 for decimal point, another -1 if we are printing a sign */
- padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
- zpadlen = max - fplace;
- if (zpadlen < 0)
- zpadlen = 0;
- if (padlen < 0)
- padlen = 0;
- if (flags & DP_F_MINUS)
- padlen = -padlen; /* Left Justifty */
-
- if ((flags & DP_F_ZERO) && (padlen > 0))
- {
- if (signvalue)
- {
- total += dopr_outch (buffer, currlen, maxlen, signvalue);
- --padlen;
- signvalue = 0;
- }
- while (padlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, '0');
- --padlen;
- }
- }
- while (padlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- --padlen;
- }
- if (signvalue)
- total += dopr_outch (buffer, currlen, maxlen, signvalue);
-
- while (iplace > 0)
- total += dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
-
- /*
- * Decimal point. This should probably use locale to find the correct
- * char to print out.
- */
- if (max > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, '.');
-
- while (zpadlen-- > 0)
- total += dopr_outch (buffer, currlen, maxlen, '0');
-
- while (fplace > 0)
- total += dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
- }
-
- while (padlen < 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- ++padlen;
- }
-
- return total;
-}
-
-static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
-{
- if (*currlen + 1 < maxlen)
- buffer[(*currlen)++] = c;
- return 1;
-}
-
-int Q_vsnprintf(char *str, size_t length, const char *fmt, va_list args)
-{
- if (str != NULL)
- str[0] = 0;
- return dopr(str, length, fmt, args);
-}
-
-int Q_snprintf(char *str, size_t length, const char *fmt, ...)
-{
- va_list ap;
- int retval;
-
- va_start(ap, fmt);
- retval = Q_vsnprintf(str, length, fmt, ap);
- va_end(ap);
-
- return retval;
-}
-
-/* this is really crappy */
-int sscanf( const char *buffer, const char *fmt, ... ) {
- int cmd;
- va_list ap;
- int count;
- size_t len;
-
- va_start (ap, fmt);
- count = 0;
-
- while ( *fmt ) {
- if ( fmt[0] != '%' ) {
- fmt++;
- continue;
- }
-
- fmt++;
- cmd = *fmt;
-
- if (isdigit (cmd)) {
- len = (size_t)_atoi (&fmt);
- cmd = *(fmt - 1);
- } else {
- len = MAX_STRING_CHARS - 1;
- fmt++;
- }
-
- switch ( cmd ) {
- case 'i':
- case 'd':
- case 'u':
- *(va_arg (ap, int *)) = _atoi( &buffer );
- break;
- case 'f':
- *(va_arg (ap, float *)) = _atof( &buffer );
- break;
- case 's':
- {
- char *s = va_arg (ap, char *);
- while (isspace (*buffer))
- buffer++;
- while (*buffer && !isspace (*buffer) && len-- > 0 )
- *s++ = *buffer++;
- *s++ = '\0';
- break;
- }
- }
- }
-
- va_end (ap);
- return count;
-}
-
-#endif
diff --git a/game/code/game/bg_lib.h b/game/code/game/bg_lib.h
deleted file mode 100644
index 0090ddd..0000000
--- a/game/code/game/bg_lib.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// bg_lib.h -- standard C library replacement routines used by code
-// compiled for the virtual machine
-
-// This file is NOT included on native builds
-#if !defined( BG_LIB_H ) && defined( Q3_VM )
-#define BG_LIB_H
-
-//Ignore __attribute__ on non-gcc platforms
-#ifndef __GNUC__
-#ifndef __attribute__
-#define __attribute__(x)
-#endif
-#endif
-
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
-typedef int size_t;
-
-typedef char * va_list;
-#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
-#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
-#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
-#define va_end(ap) ( ap = (va_list)0 )
-
-#define CHAR_BIT 8 /* number of bits in a char */
-#define SCHAR_MAX 0x7f /* maximum signed char value */
-#define SCHAR_MIN (-SCHAR_MAX - 1) /* minimum signed char value */
-#define UCHAR_MAX 0xff /* maximum unsigned char value */
-
-#define SHRT_MAX 0x7fff /* maximum (signed) short value */
-#define SHRT_MIN (-SHRT_MAX - 1) /* minimum (signed) short value */
-#define USHRT_MAX 0xffff /* maximum unsigned short value */
-#define INT_MAX 0x7fffffff /* maximum (signed) int value */
-#define INT_MIN (-INT_MAX - 1) /* minimum (signed) int value */
-#define UINT_MAX 0xffffffff /* maximum unsigned int value */
-#define LONG_MAX 0x7fffffffL /* maximum (signed) long value */
-#define LONG_MIN (-LONG_MAX - 1) /* minimum (signed) long value */
-#define ULONG_MAX 0xffffffffUL /* maximum unsigned long value */
-
-#define isalnum(c) (isalpha(c) || isdigit(c))
-#define isalpha(c) (isupper(c) || islower(c))
-#define isascii(c) ((c) > 0 && (c) <= 0x7f)
-#define iscntrl(c) (((c) >= 0) && (((c) <= 0x1f) || ((c) == 0x7f)))
-#define isdigit(c) ((c) >= '0' && (c) <= '9')
-#define isgraph(c) ((c) != ' ' && isprint(c))
-#define islower(c) ((c) >= 'a' && (c) <= 'z')
-#define isprint(c) ((c) >= ' ' && (c) <= '~')
-#define ispunct(c) (((c) > ' ' && (c) <= '~') && !isalnum(c))
-#define isspace(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || (c) == '\r' || \
- (c) == '\t' || (c) == '\v')
-#define isupper(c) ((c) >= 'A' && (c) <= 'Z')
-#define isxdigit(c) (isxupper(c) || isxlower(c))
-#define isxlower(c) (isdigit(c) || (c >= 'a' && c <= 'f'))
-#define isxupper(c) (isdigit(c) || (c >= 'A' && c <= 'F'))
-
-// Misc functions
-typedef int cmp_t(const void *, const void *);
-void qsort(void *a, size_t n, size_t es, cmp_t *cmp);
-void srand( unsigned seed );
-int rand( void );
-
-// String functions
-size_t strlen( const char *string );
-char *strcat( char *strDestination, const char *strSource );
-char *strcpy( char *strDestination, const char *strSource );
-int strcmp( const char *string1, const char *string2 );
-char *strchr( const char *string, int c );
-char *strstr( const char *string, const char *strCharSet );
-char *strncpy( char *strDest, const char *strSource, size_t count );
-int tolower( int c );
-int toupper( int c );
-
-double atof( const char *string );
-double _atof( const char **stringPtr );
-double strtod( const char *nptr, const char **endptr );
-int atoi( const char *string );
-int _atoi( const char **stringPtr );
-long strtol( const char *nptr, const char **endptr, int base );
-
-int Q_vsnprintf( char *buffer, size_t length, const char *fmt, va_list argptr );
-int Q_snprintf( char *buffer, size_t length, const char *fmt, ... ) __attribute__ ((format (printf, 3, 4)));
-
-int sscanf( const char *buffer, const char *fmt, ... ) __attribute__ ((format (scanf, 2, 3)));
-
-// Memory functions
-void *memmove( void *dest, const void *src, size_t count );
-void *memset( void *dest, int c, size_t count );
-void *memcpy( void *dest, const void *src, size_t count );
-
-// Math functions
-double ceil( double x );
-double floor( double x );
-double sqrt( double x );
-double sin( double x );
-double cos( double x );
-double atan2( double y, double x );
-double tan( double x );
-int abs( int n );
-double fabs( double x );
-double acos( double x );
-
-#endif // BG_LIB_H
diff --git a/game/code/game/bg_local.h b/game/code/game/bg_local.h
deleted file mode 100644
index 246299c..0000000
--- a/game/code/game/bg_local.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// bg_local.h -- local definitions for the bg (both games) files
-
-#define MIN_WALK_NORMAL 0.7f // can't walk on very steep slopes
-
-#define STEPSIZE 18
-
-#define JUMP_VELOCITY 270
-
-#define TIMER_LAND 130
-#define TIMER_GESTURE (34*66+50)
-
-#define OVERCLIP 1.001f
-
-// all of the locals will be zeroed before each
-// pmove, just to make damn sure we don't have
-// any differences when running on client or server
-typedef struct {
- vec3_t forward, right, up;
- float frametime;
-
- int msec;
-
- qboolean walking;
- qboolean groundPlane;
- trace_t groundTrace;
-
- float impactSpeed;
-
- vec3_t previous_origin;
- vec3_t previous_velocity;
- int previous_waterlevel;
-} pml_t;
-
-extern pmove_t *pm;
-extern pml_t pml;
-
-// movement parameters
-extern float pm_stopspeed;
-extern float pm_duckScale;
-extern float pm_swimScale;
-extern float pm_wadeScale;
-
-extern float pm_accelerate;
-extern float pm_airaccelerate;
-extern float pm_wateraccelerate;
-extern float pm_flyaccelerate;
-
-extern float pm_friction;
-extern float pm_waterfriction;
-extern float pm_flightfriction;
-
-extern int c_pmove;
-
-void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce );
-void PM_AddTouchEnt( int entityNum );
-void PM_AddEvent( int newEvent );
-
-qboolean PM_SlideMove( qboolean gravity );
-void PM_StepSlideMove( qboolean gravity );
-
-
diff --git a/game/code/game/bg_pmove.c b/game/code/game/bg_pmove.c
deleted file mode 100644
index 8bb6a2c..0000000
--- a/game/code/game/bg_pmove.c
+++ /dev/null
@@ -1,2074 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// bg_pmove.c -- both games player movement code
-// takes a playerstate and a usercmd as input and returns a modifed playerstate
-
-#include "../qcommon/q_shared.h"
-#include "bg_public.h"
-#include "bg_local.h"
-
-pmove_t *pm;
-pml_t pml;
-
-// movement parameters
-float pm_stopspeed = 100.0f;
-float pm_duckScale = 0.25f;
-float pm_swimScale = 0.50f;
-float pm_wadeScale = 0.70f;
-
-float pm_accelerate = 10.0f;
-float pm_airaccelerate = 1.0f;
-float pm_wateraccelerate = 4.0f;
-float pm_flyaccelerate = 8.0f;
-
-float pm_friction = 6.0f;
-float pm_waterfriction = 1.0f;
-float pm_flightfriction = 3.0f;
-float pm_spectatorfriction = 5.0f;
-
-int c_pmove = 0;
-
-/*
-===============
-PM_AddEvent
-
-===============
-*/
-void PM_AddEvent( int newEvent ) {
- BG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps );
-}
-
-/*
-===============
-PM_AddTouchEnt
-===============
-*/
-void PM_AddTouchEnt( int entityNum ) {
- int i;
-
- if ( entityNum == ENTITYNUM_WORLD ) {
- return;
- }
- if ( pm->numtouch == MAXTOUCH ) {
- return;
- }
-
- // see if it is already added
- for ( i = 0 ; i < pm->numtouch ; i++ ) {
- if ( pm->touchents[ i ] == entityNum ) {
- return;
- }
- }
-
- // add it
- pm->touchents[pm->numtouch] = entityNum;
- pm->numtouch++;
-}
-
-/*
-===================
-PM_StartTorsoAnim
-===================
-*/
-static void PM_StartTorsoAnim( int anim ) {
- if ( pm->ps->pm_type >= PM_DEAD ) {
- return;
- }
- pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
- | anim;
-}
-static void PM_StartLegsAnim( int anim ) {
- if ( pm->ps->pm_type >= PM_DEAD ) {
- return;
- }
- if ( pm->ps->legsTimer > 0 ) {
- return; // a high priority animation is running
- }
- pm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
- | anim;
-}
-
-static void PM_ContinueLegsAnim( int anim ) {
- if ( ( pm->ps->legsAnim & ~ANIM_TOGGLEBIT ) == anim ) {
- return;
- }
- if ( pm->ps->legsTimer > 0 ) {
- return; // a high priority animation is running
- }
- PM_StartLegsAnim( anim );
-}
-
-static void PM_ContinueTorsoAnim( int anim ) {
- if ( ( pm->ps->torsoAnim & ~ANIM_TOGGLEBIT ) == anim ) {
- return;
- }
- if ( pm->ps->torsoTimer > 0 ) {
- return; // a high priority animation is running
- }
- PM_StartTorsoAnim( anim );
-}
-
-static void PM_ForceLegsAnim( int anim ) {
- pm->ps->legsTimer = 0;
- PM_StartLegsAnim( anim );
-}
-
-
-/*
-==================
-PM_ClipVelocity
-
-Slide off of the impacting surface
-==================
-*/
-void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) {
- float backoff;
- float change;
- int i;
-
- backoff = DotProduct (in, normal);
-
- if ( backoff < 0 ) {
- backoff *= overbounce;
- } else {
- backoff /= overbounce;
- }
-
- for ( i=0 ; i<3 ; i++ ) {
- change = normal[i]*backoff;
- out[i] = in[i] - change;
- }
-}
-
-
-/*
-==================
-PM_Friction
-
-Handles both ground friction and water friction
-==================
-*/
-static void PM_Friction( void ) {
- vec3_t vec;
- float *vel;
- float speed, newspeed, control;
- float drop;
-
- vel = pm->ps->velocity;
-
- VectorCopy( vel, vec );
- if ( pml.walking ) {
- vec[2] = 0; // ignore slope movement
- }
-
- speed = VectorLength(vec);
- if (speed < 1) {
- vel[0] = 0;
- vel[1] = 0; // allow sinking underwater
- // FIXME: still have z friction underwater?
- return;
- }
-
- drop = 0;
-
- // apply ground friction
- if ( pm->waterlevel <= 1 ) {
- if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) {
- // if getting knocked back, no friction
- if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) {
- control = speed < pm_stopspeed ? pm_stopspeed : speed;
- drop += control*pm_friction*pml.frametime;
- }
- }
- }
-
- // apply water friction even if just wading
- if ( pm->waterlevel ) {
- drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
- }
-
- // apply flying friction
- if ( pm->ps->powerups[PW_FLIGHT]) {
- drop += speed*pm_flightfriction*pml.frametime;
- }
-
- if ( pm->ps->pm_type == PM_SPECTATOR) {
- drop += speed*pm_spectatorfriction*pml.frametime;
- }
-
- // scale the velocity
- newspeed = speed - drop;
- if (newspeed < 0) {
- newspeed = 0;
- }
- newspeed /= speed;
-
- vel[0] = vel[0] * newspeed;
- vel[1] = vel[1] * newspeed;
- vel[2] = vel[2] * newspeed;
-}
-
-
-/*
-==============
-PM_Accelerate
-
-TODO: bunny hoping
-
-Handles user intended acceleration
-==============
-*/
-static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) {
-#if 1
-
- // q2 style
- int i;
- float addspeed, accelspeed, currentspeed;
-
- currentspeed = DotProduct (pm->ps->velocity, wishdir);
- addspeed = wishspeed - currentspeed;
- if (addspeed <= 0) {
- return;
- }
- accelspeed = accel*pml.frametime*wishspeed;
- if (accelspeed > addspeed) {
- accelspeed = addspeed;
- }
-
- for (i=0 ; i<3 ; i++) {
- pm->ps->velocity[i] += accelspeed*wishdir[i];
- }
-#else
- // proper way (avoids strafe jump maxspeed bug), but feels bad
- vec3_t wishVelocity;
- vec3_t pushDir;
- float pushLen;
- float canPush;
-
- VectorScale( wishdir, wishspeed, wishVelocity );
- VectorSubtract( wishVelocity, pm->ps->velocity, pushDir );
- pushLen = VectorNormalize( pushDir );
-
- canPush = accel*pml.frametime*wishspeed;
- if (canPush > pushLen) {
- canPush = pushLen;
- }
-
- VectorMA( pm->ps->velocity, canPush, pushDir, pm->ps->velocity );
-}
-#endif
-}
-
-
-
-/*
-============
-PM_CmdScale
-
-Returns the scale factor to apply to cmd movements
-This allows the clients to use axial -127 to 127 values for all directions
-without getting a sqrt(2) distortion in speed.
-============
-*/
-static float PM_CmdScale( usercmd_t *cmd ) {
- int max;
- float total;
- float scale;
-
- max = abs( cmd->forwardmove );
- if ( abs( cmd->rightmove ) > max ) {
- max = abs( cmd->rightmove );
- }
- if ( abs( cmd->upmove ) > max ) {
- max = abs( cmd->upmove );
- }
- if ( !max ) {
- return 0;
- }
-
- total = sqrt( cmd->forwardmove * cmd->forwardmove
- + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove );
- scale = (float)pm->ps->speed * max / ( 127.0 * total );
-
- return scale;
-}
-
-
-/*
-================
-PM_SetMovementDir
-
-Determine the rotation of the legs reletive
-to the facing dir
-================
-*/
-static void PM_SetMovementDir( void ) {
- if ( pm->cmd.forwardmove || pm->cmd.rightmove ) {
- if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove > 0 ) {
- pm->ps->movementDir = 0;
- } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove > 0 ) {
- pm->ps->movementDir = 1;
- } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove == 0 ) {
- pm->ps->movementDir = 2;
- } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove < 0 ) {
- pm->ps->movementDir = 3;
- } else if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove < 0 ) {
- pm->ps->movementDir = 4;
- } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove < 0 ) {
- pm->ps->movementDir = 5;
- } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove == 0 ) {
- pm->ps->movementDir = 6;
- } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove > 0 ) {
- pm->ps->movementDir = 7;
- }
- } else {
- // if they aren't actively going directly sideways,
- // change the animation to the diagonal so they
- // don't stop too crooked
- if ( pm->ps->movementDir == 2 ) {
- pm->ps->movementDir = 1;
- } else if ( pm->ps->movementDir == 6 ) {
- pm->ps->movementDir = 7;
- }
- }
-}
-
-
-/*
-=============
-PM_CheckJump
-=============
-*/
-static qboolean PM_CheckJump( void ) {
-
-
- if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
- return qfalse; // don't allow jump until all buttons are up
- }
-
- if ( pm->cmd.upmove < 10 ) {
- // not holding jump
- return qfalse;
- }
-
-
- // must wait for jump to be released
- if ( pm->ps->pm_flags & PMF_JUMP_HELD ) {
- // clear upmove so cmdscale doesn't lower running speed
- pm->cmd.upmove = 0;
- return qfalse;
- }
-
-
-
-
- pml.groundPlane = qfalse; // jumping away
- pml.walking = qfalse;
- pm->ps->pm_flags |= PMF_JUMP_HELD;
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pm->ps->velocity[2] = JUMP_VELOCITY;
- PM_AddEvent( EV_JUMP );
-
- if ( pm->cmd.forwardmove >= 0 ) {
- PM_ForceLegsAnim( LEGS_JUMP );
- pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
- } else {
- PM_ForceLegsAnim( LEGS_JUMPB );
- pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
- }
-
- return qtrue;
-}
-
-/*
-=============
-PM_CheckWaterJump
-=============
-*/
-static qboolean PM_CheckWaterJump( void ) {
- vec3_t spot;
- int cont;
- vec3_t flatforward;
-
- if (pm->ps->pm_time) {
- return qfalse;
- }
-
- // check for water jump
- if ( pm->waterlevel != 2 ) {
- return qfalse;
- }
-
- flatforward[0] = pml.forward[0];
- flatforward[1] = pml.forward[1];
- flatforward[2] = 0;
- VectorNormalize (flatforward);
-
- VectorMA (pm->ps->origin, 30, flatforward, spot);
- spot[2] += 4;
- cont = pm->pointcontents (spot, pm->ps->clientNum );
- if ( !(cont & CONTENTS_SOLID) ) {
- return qfalse;
- }
-
- spot[2] += 16;
- cont = pm->pointcontents (spot, pm->ps->clientNum );
- if ( cont ) {
- return qfalse;
- }
-
- // jump out of water
- VectorScale (pml.forward, 200, pm->ps->velocity);
- pm->ps->velocity[2] = 350;
-
- pm->ps->pm_flags |= PMF_TIME_WATERJUMP;
- pm->ps->pm_time = 2000;
-
- return qtrue;
-}
-
-//============================================================================
-
-
-/*
-===================
-PM_WaterJumpMove
-
-Flying out of the water
-===================
-*/
-static void PM_WaterJumpMove( void ) {
- // waterjump has no control, but falls
-
- PM_StepSlideMove( qtrue );
-
- pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
- if (pm->ps->velocity[2] < 0) {
- // cancel as soon as we are falling down again
- pm->ps->pm_flags &= ~PMF_ALL_TIMES;
- pm->ps->pm_time = 0;
- }
-}
-
-/*
-===================
-PM_WaterMove
-
-===================
-*/
-static void PM_WaterMove( void ) {
- int i;
- vec3_t wishvel;
- float wishspeed;
- vec3_t wishdir;
- float scale;
- float vel;
-
- if ( PM_CheckWaterJump() ) {
- PM_WaterJumpMove();
- return;
- }
-#if 0
- // jump = head for surface
- if ( pm->cmd.upmove >= 10 ) {
- if (pm->ps->velocity[2] > -300) {
- if ( pm->watertype == CONTENTS_WATER ) {
- pm->ps->velocity[2] = 100;
- } else if (pm->watertype == CONTENTS_SLIME) {
- pm->ps->velocity[2] = 80;
- } else {
- pm->ps->velocity[2] = 50;
- }
- }
- }
-#endif
- PM_Friction ();
-
- scale = PM_CmdScale( &pm->cmd );
- //
- // user intentions
- //
- if ( !scale ) {
- wishvel[0] = 0;
- wishvel[1] = 0;
- wishvel[2] = -60; // sink towards bottom
- } else {
- for (i=0 ; i<3 ; i++)
- wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;
-
- wishvel[2] += scale * pm->cmd.upmove;
- }
-
- VectorCopy (wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
-
- if ( wishspeed > pm->ps->speed * pm_swimScale ) {
- wishspeed = pm->ps->speed * pm_swimScale;
- }
-
- PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);
-
- // make sure we can go up slopes easily under water
- if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) {
- vel = VectorLength(pm->ps->velocity);
- // slide along the ground plane
- PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
-
- VectorNormalize(pm->ps->velocity);
- VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
- }
-
- PM_SlideMove( qfalse );
-}
-
-/*
-===================
-PM_InvulnerabilityMove
-
-Only with the invulnerability powerup
-===================
-*/
-static void PM_InvulnerabilityMove( void ) {
- pm->cmd.forwardmove = 0;
- pm->cmd.rightmove = 0;
- pm->cmd.upmove = 0;
- VectorClear(pm->ps->velocity);
-}
-
-/*
-===================
-PM_FlyMove
-
-Only with the flight powerup
-===================
-*/
-static void PM_FlyMove( void ) {
- int i;
- vec3_t wishvel;
- float wishspeed;
- vec3_t wishdir;
- float scale;
-
- // normal slowdown
- PM_Friction ();
-
- scale = PM_CmdScale( &pm->cmd );
- //
- // user intentions
- //
- if ( !scale ) {
- wishvel[0] = 0;
- wishvel[1] = 0;
- wishvel[2] = 0;
- } else {
- for (i=0 ; i<3 ; i++) {
- wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;
- }
-
- wishvel[2] += scale * pm->cmd.upmove;
- }
-
- VectorCopy (wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
-
- PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate);
-
- PM_StepSlideMove( qfalse );
-}
-
-
-/*
-===================
-PM_AirMove
-
-===================
-*/
-static void PM_AirMove( void ) {
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- float scale;
- usercmd_t cmd;
-
- PM_Friction();
-
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.rightmove;
-
- cmd = pm->cmd;
- scale = PM_CmdScale( &cmd );
-
- // set the movementDir so clients can rotate the legs for strafing
- PM_SetMovementDir();
-
- // project moves down to flat plane
- pml.forward[2] = 0;
- pml.right[2] = 0;
- VectorNormalize (pml.forward);
- VectorNormalize (pml.right);
-
- for ( i = 0 ; i < 2 ; i++ ) {
- wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
- }
- wishvel[2] = 0;
-
- VectorCopy (wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
- wishspeed *= scale;
-
- // not on ground, so little effect on velocity
- PM_Accelerate (wishdir, wishspeed, pm_airaccelerate);
-
- // we may have a ground plane that is very steep, even
- // though we don't have a groundentity
- // slide along the steep plane
- if ( pml.groundPlane ) {
- PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
- }
-
-#if 0
- //ZOID: If we are on the grapple, try stair-stepping
- //this allows a player to use the grapple to pull himself
- //over a ledge
- if (pm->ps->pm_flags & PMF_GRAPPLE_PULL)
- PM_StepSlideMove ( qtrue );
- else
- PM_SlideMove ( qtrue );
-#endif
-
- PM_StepSlideMove ( qtrue );
-}
-
-/*
-===================
-PM_GrappleMove
-
-===================
-*/
-static void PM_GrappleMove( void ) {
- vec3_t vel, v;
- float vlen;
-
- VectorScale(pml.forward, -16, v);
- VectorAdd(pm->ps->grapplePoint, v, v);
- VectorSubtract(v, pm->ps->origin, vel);
- vlen = VectorLength(vel);
- VectorNormalize( vel );
-
- if (vlen <= 100)
- VectorScale(vel, 10 * vlen, vel);
- else
- VectorScale(vel, 800, vel);
-
- VectorCopy(vel, pm->ps->velocity);
-
- pml.groundPlane = qfalse;
-}
-
-/*
-===================
-PM_WalkMove
-
-===================
-*/
-static void PM_WalkMove( void ) {
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- float scale;
- usercmd_t cmd;
- float accelerate;
- float vel;
-
- if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) {
- // begin swimming
- PM_WaterMove();
- return;
- }
-
-
- if ( PM_CheckJump () ) {
- // jumped away
- if ( pm->waterlevel > 1 ) {
- PM_WaterMove();
- } else {
- PM_AirMove();
- }
- return;
- }
-
- PM_Friction ();
-
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.rightmove;
-
- cmd = pm->cmd;
- scale = PM_CmdScale( &cmd );
-
- // set the movementDir so clients can rotate the legs for strafing
- PM_SetMovementDir();
-
- // project moves down to flat plane
- pml.forward[2] = 0;
- pml.right[2] = 0;
-
- // project the forward and right directions onto the ground plane
- PM_ClipVelocity (pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP );
- PM_ClipVelocity (pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP );
- //
- VectorNormalize (pml.forward);
- VectorNormalize (pml.right);
-
- for ( i = 0 ; i < 3 ; i++ ) {
- wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
- }
- // when going up or down slopes the wish velocity should Not be zero
-// wishvel[2] = 0;
-
- VectorCopy (wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
- wishspeed *= scale;
-
- // clamp the speed lower if ducking
- if ( pm->ps->pm_flags & PMF_DUCKED ) {
- if ( wishspeed > pm->ps->speed * pm_duckScale ) {
- wishspeed = pm->ps->speed * pm_duckScale;
- }
- }
-
- // clamp the speed lower if wading or walking on the bottom
- if ( pm->waterlevel ) {
- float waterScale;
-
- waterScale = pm->waterlevel / 3.0;
- waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale;
- if ( wishspeed > pm->ps->speed * waterScale ) {
- wishspeed = pm->ps->speed * waterScale;
- }
- }
-
- // when a player gets hit, they temporarily lose
- // full control, which allows them to be moved a bit
- if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
- accelerate = pm_airaccelerate;
- } else {
- accelerate = pm_accelerate;
- }
-
- PM_Accelerate (wishdir, wishspeed, accelerate);
-
- //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]);
- //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity));
-
- if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
- pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
- } else {
- // don't reset the z velocity for slopes
-// pm->ps->velocity[2] = 0;
- }
-
- vel = VectorLength(pm->ps->velocity);
-
- // slide along the ground plane
- PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
-
- // don't decrease velocity when going up or down a slope
- VectorNormalize(pm->ps->velocity);
- VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
-
- // don't do anything if standing still
- if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) {
- return;
- }
-
- PM_StepSlideMove( qfalse );
-
- //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity));
-
-}
-
-
-/*
-==============
-PM_DeadMove
-==============
-*/
-static void PM_DeadMove( void ) {
- float forward;
-
- if ( !pml.walking ) {
- return;
- }
-
- // extra friction
-
- forward = VectorLength (pm->ps->velocity);
- forward -= 20;
- if ( forward <= 0 ) {
- VectorClear (pm->ps->velocity);
- } else {
- VectorNormalize (pm->ps->velocity);
- VectorScale (pm->ps->velocity, forward, pm->ps->velocity);
- }
-}
-
-
-/*
-===============
-PM_NoclipMove
-===============
-*/
-static void PM_NoclipMove( void ) {
- float speed, drop, friction, control, newspeed;
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- float scale;
-
- pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
-
- // friction
-
- speed = VectorLength (pm->ps->velocity);
- if (speed < 1)
- {
- VectorCopy (vec3_origin, pm->ps->velocity);
- }
- else
- {
- drop = 0;
-
- friction = pm_friction*1.5; // extra friction
- control = speed < pm_stopspeed ? pm_stopspeed : speed;
- drop += control*friction*pml.frametime;
-
- // scale the velocity
- newspeed = speed - drop;
- if (newspeed < 0)
- newspeed = 0;
- newspeed /= speed;
-
- VectorScale (pm->ps->velocity, newspeed, pm->ps->velocity);
- }
-
- // accelerate
- scale = PM_CmdScale( &pm->cmd );
-
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.rightmove;
-
- for (i=0 ; i<3 ; i++)
- wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
- wishvel[2] += pm->cmd.upmove;
-
- VectorCopy (wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
- wishspeed *= scale;
-
- PM_Accelerate( wishdir, wishspeed, pm_accelerate );
-
- // move
- VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin);
-}
-
-//============================================================================
-
-/*
-================
-PM_FootstepForSurface
-
-Returns an event number apropriate for the groundsurface
-================
-*/
-static int PM_FootstepForSurface( void ) {
- if ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) {
- return 0;
- }
- if ( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) {
- return EV_FOOTSTEP_METAL;
- }
- return EV_FOOTSTEP;
-}
-
-
-/*
-=================
-PM_CrashLand
-
-Check for hard landings that generate sound events
-=================
-*/
-static void PM_CrashLand( void ) {
- float delta;
- float dist;
- float vel, acc;
- float t;
- float a, b, c, den;
-
- // decide which landing animation to use
- if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) {
- PM_ForceLegsAnim( LEGS_LANDB );
- } else {
- PM_ForceLegsAnim( LEGS_LAND );
- }
-
- pm->ps->legsTimer = TIMER_LAND;
-
- // calculate the exact velocity on landing
- dist = pm->ps->origin[2] - pml.previous_origin[2];
- vel = pml.previous_velocity[2];
- acc = -pm->ps->gravity;
-
- a = acc / 2;
- b = vel;
- c = -dist;
-
- den = b * b - 4 * a * c;
- if ( den < 0 ) {
- return;
- }
- t = (-b - sqrt( den ) ) / ( 2 * a );
-
- delta = vel + t * acc;
- delta = delta*delta * 0.0001;
-
- // ducking while falling doubles damage
- if ( pm->ps->pm_flags & PMF_DUCKED ) {
- delta *= 2;
- }
-
- // never take falling damage if completely underwater
- if ( pm->waterlevel == 3 ) {
- return;
- }
-
- // reduce falling damage if there is standing water
- if ( pm->waterlevel == 2 ) {
- delta *= 0.25;
- }
- if ( pm->waterlevel == 1 ) {
- delta *= 0.5;
- }
-
- if ( delta < 1 ) {
- return;
- }
-
- // create a local entity event to play the sound
-
- // SURF_NODAMAGE is used for bounce pads where you don't ever
- // want to take damage or play a crunch sound
- if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) {
- if ( delta > 60 ) {
- PM_AddEvent( EV_FALL_FAR );
- } else if ( delta > 40 ) {
- // this is a pain grunt, so don't play it if dead
- if ( pm->ps->stats[STAT_HEALTH] > 0 ) {
- PM_AddEvent( EV_FALL_MEDIUM );
- }
- } else if ( delta > 7 ) {
- PM_AddEvent( EV_FALL_SHORT );
- } else {
- PM_AddEvent( PM_FootstepForSurface() );
- }
- }
-
- // start footstep cycle over
- pm->ps->bobCycle = 0;
-}
-
-/*
-=============
-PM_CheckStuck
-=============
-*/
-/*
-void PM_CheckStuck(void) {
- trace_t trace;
-
- pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask);
- if (trace.allsolid) {
- //int shit = qtrue;
- }
-}
-*/
-
-/*
-=============
-PM_CorrectAllSolid
-=============
-*/
-static int PM_CorrectAllSolid( trace_t *trace ) {
- int i, j, k;
- vec3_t point;
-
- if ( pm->debugLevel ) {
- Com_Printf("%i:allsolid\n", c_pmove);
- }
-
- // jitter around
- for (i = -1; i <= 1; i++) {
- for (j = -1; j <= 1; j++) {
- for (k = -1; k <= 1; k++) {
- VectorCopy(pm->ps->origin, point);
- point[0] += (float) i;
- point[1] += (float) j;
- point[2] += (float) k;
- pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
- if ( !trace->allsolid ) {
- point[0] = pm->ps->origin[0];
- point[1] = pm->ps->origin[1];
- point[2] = pm->ps->origin[2] - 0.25;
-
- pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
- pml.groundTrace = *trace;
- return qtrue;
- }
- }
- }
- }
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
-
- return qfalse;
-}
-
-
-/*
-=============
-PM_GroundTraceMissed
-
-The ground trace didn't hit a surface, so we are in freefall
-=============
-*/
-static void PM_GroundTraceMissed( void ) {
- trace_t trace;
- vec3_t point;
-
- if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) {
- // we just transitioned into freefall
- if ( pm->debugLevel ) {
- Com_Printf("%i:lift\n", c_pmove);
- }
-
- // if they aren't in a jumping animation and the ground is a ways away, force into it
- // if we didn't do the trace, the player would be backflipping down staircases
- VectorCopy( pm->ps->origin, point );
- point[2] -= 64;
-
- pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
- if ( trace.fraction == 1.0 ) {
- if ( pm->cmd.forwardmove >= 0 ) {
- PM_ForceLegsAnim( LEGS_JUMP );
- pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
- } else {
- PM_ForceLegsAnim( LEGS_JUMPB );
- pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
- }
- }
- }
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
-}
-
-
-/*
-=============
-PM_GroundTrace
-=============
-*/
-static void PM_GroundTrace( void ) {
- vec3_t point;
- trace_t trace;
-
- point[0] = pm->ps->origin[0];
- point[1] = pm->ps->origin[1];
- point[2] = pm->ps->origin[2] - 0.25;
-
- pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
- pml.groundTrace = trace;
-
- // do something corrective if the trace starts in a solid...
- if ( trace.allsolid ) {
- if ( !PM_CorrectAllSolid(&trace) )
- return;
- }
-
- // if the trace didn't hit anything, we are in free fall
- if ( trace.fraction == 1.0 ) {
- PM_GroundTraceMissed();
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
- return;
- }
-
- // check if getting thrown off the ground
- if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) {
- if ( pm->debugLevel ) {
- Com_Printf("%i:kickoff\n", c_pmove);
- }
- // go into jump animation
- if ( pm->cmd.forwardmove >= 0 ) {
- PM_ForceLegsAnim( LEGS_JUMP );
- pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
- } else {
- PM_ForceLegsAnim( LEGS_JUMPB );
- pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
- }
-
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
- return;
- }
-
- // slopes that are too steep will not be considered onground
- if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) {
- if ( pm->debugLevel ) {
- Com_Printf("%i:steep\n", c_pmove);
- }
- // FIXME: if they can't slide down the slope, let them
- // walk (sharp crevices)
- pm->ps->groundEntityNum = ENTITYNUM_NONE;
- pml.groundPlane = qtrue;
- pml.walking = qfalse;
- return;
- }
-
- pml.groundPlane = qtrue;
- pml.walking = qtrue;
-
- // hitting solid ground will end a waterjump
- if (pm->ps->pm_flags & PMF_TIME_WATERJUMP)
- {
- pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND);
- pm->ps->pm_time = 0;
- }
-
- if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
- // just hit the ground
- if ( pm->debugLevel ) {
- Com_Printf("%i:Land\n", c_pmove);
- }
-
- PM_CrashLand();
-
- // don't do landing time if we were just going down a slope
- if ( pml.previous_velocity[2] < -200 ) {
- // don't allow another jump for a little while
- pm->ps->pm_flags |= PMF_TIME_LAND;
- pm->ps->pm_time = 250;
- }
- }
-
- pm->ps->groundEntityNum = trace.entityNum;
-
- // don't reset the z velocity for slopes
-// pm->ps->velocity[2] = 0;
-
- PM_AddTouchEnt( trace.entityNum );
-}
-
-
-/*
-=============
-PM_SetWaterLevel FIXME: avoid this twice? certainly if not moving
-=============
-*/
-static void PM_SetWaterLevel( void ) {
- vec3_t point;
- int cont;
- int sample1;
- int sample2;
-
- //
- // get waterlevel, accounting for ducking
- //
- pm->waterlevel = 0;
- pm->watertype = 0;
-
- point[0] = pm->ps->origin[0];
- point[1] = pm->ps->origin[1];
- point[2] = pm->ps->origin[2] + MINS_Z + 1;
- cont = pm->pointcontents( point, pm->ps->clientNum );
-
- if ( cont & MASK_WATER ) {
- sample2 = pm->ps->viewheight - MINS_Z;
- sample1 = sample2 / 2;
-
- pm->watertype = cont;
- pm->waterlevel = 1;
- point[2] = pm->ps->origin[2] + MINS_Z + sample1;
- cont = pm->pointcontents (point, pm->ps->clientNum );
- if ( cont & MASK_WATER ) {
- pm->waterlevel = 2;
- point[2] = pm->ps->origin[2] + MINS_Z + sample2;
- cont = pm->pointcontents (point, pm->ps->clientNum );
- if ( cont & MASK_WATER ){
- pm->waterlevel = 3;
- }
- }
- }
-
-}
-
-/*
-==============
-PM_CheckDuck
-
-Sets mins, maxs, and pm->ps->viewheight
-==============
-*/
-static void PM_CheckDuck (void)
-{
- trace_t trace;
-
- if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
- if ( pm->ps->pm_flags & PMF_INVULEXPAND ) {
- // invulnerability sphere has a 42 units radius
- VectorSet( pm->mins, -42, -42, -42 );
- VectorSet( pm->maxs, 42, 42, 42 );
- }
- else {
- VectorSet( pm->mins, -15, -15, MINS_Z );
- VectorSet( pm->maxs, 15, 15, 16 );
- }
- pm->ps->pm_flags |= PMF_DUCKED;
- pm->ps->viewheight = CROUCH_VIEWHEIGHT;
- return;
- }
- pm->ps->pm_flags &= ~PMF_INVULEXPAND;
-
- pm->mins[0] = -15;
- pm->mins[1] = -15;
-
- pm->maxs[0] = 15;
- pm->maxs[1] = 15;
-
- pm->mins[2] = MINS_Z;
-
- if (pm->ps->pm_type == PM_DEAD)
- {
- pm->maxs[2] = -8;
- pm->ps->viewheight = DEAD_VIEWHEIGHT;
- return;
- }
-
- if (pm->cmd.upmove < 0)
- { // duck
- pm->ps->pm_flags |= PMF_DUCKED;
- }
- else
- { // stand up if possible
- if (pm->ps->pm_flags & PMF_DUCKED)
- {
- // try to stand up
- pm->maxs[2] = 32;
- pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask );
- if (!trace.allsolid)
- pm->ps->pm_flags &= ~PMF_DUCKED;
- }
- }
-
- if (pm->ps->pm_flags & PMF_DUCKED)
- {
- pm->maxs[2] = 16;
- pm->ps->viewheight = CROUCH_VIEWHEIGHT;
- }
- else
- {
- pm->maxs[2] = 32;
- pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
- }
-}
-
-
-
-//===================================================================
-
-
-/*
-===============
-PM_Footsteps
-===============
-*/
-static void PM_Footsteps( void ) {
- float bobmove;
- int old;
- qboolean footstep;
-
- //
- // calculate speed and cycle to be used for
- // all cyclic walking effects
- //
- pm->xyspeed = sqrt( pm->ps->velocity[0] * pm->ps->velocity[0]
- + pm->ps->velocity[1] * pm->ps->velocity[1] );
-
- if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
-
- if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
- PM_ContinueLegsAnim( LEGS_IDLECR );
- }
- // airborne leaves position in cycle intact, but doesn't advance
- if ( pm->waterlevel > 1 ) {
- PM_ContinueLegsAnim( LEGS_SWIM );
- }
- return;
- }
-
- // if not trying to move
- if ( !pm->cmd.forwardmove && !pm->cmd.rightmove ) {
- if ( pm->xyspeed < 5 ) {
- pm->ps->bobCycle = 0; // start at beginning of cycle again
- if ( pm->ps->pm_flags & PMF_DUCKED ) {
- PM_ContinueLegsAnim( LEGS_IDLECR );
- } else {
- PM_ContinueLegsAnim( LEGS_IDLE );
- }
- }
- return;
- }
-
-
- footstep = qfalse;
-
- if ( pm->ps->pm_flags & PMF_DUCKED ) {
- bobmove = 0.5; // ducked characters bob much faster
- if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
- PM_ContinueLegsAnim( LEGS_BACKCR );
- }
- else {
- PM_ContinueLegsAnim( LEGS_WALKCR );
- }
- // ducked characters never play footsteps
- /*
- } else if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
- if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
- bobmove = 0.4; // faster speeds bob faster
- footstep = qtrue;
- } else {
- bobmove = 0.3;
- }
- PM_ContinueLegsAnim( LEGS_BACK );
- */
- } else {
- if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
- bobmove = 0.4f; // faster speeds bob faster
- if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
- PM_ContinueLegsAnim( LEGS_BACK );
- }
- else {
- PM_ContinueLegsAnim( LEGS_RUN );
- }
- footstep = qtrue;
- } else {
- bobmove = 0.3f; // walking bobs slow
- if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
- PM_ContinueLegsAnim( LEGS_BACKWALK );
- }
- else {
- PM_ContinueLegsAnim( LEGS_WALK );
- }
- }
- }
-
- // check for footstep / splash sounds
- old = pm->ps->bobCycle;
- pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255;
-
- // if we just crossed a cycle boundary, play an apropriate footstep event
- if ( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) {
- if ( pm->waterlevel == 0 ) {
- // on ground will only play sounds if running
- if ( footstep && !pm->noFootsteps ) {
- PM_AddEvent( PM_FootstepForSurface() );
- }
- } else if ( pm->waterlevel == 1 ) {
- // splashing
- PM_AddEvent( EV_FOOTSPLASH );
- } else if ( pm->waterlevel == 2 ) {
- // wading / swimming at surface
- PM_AddEvent( EV_SWIM );
- } else if ( pm->waterlevel == 3 ) {
- // no sound when completely underwater
-
- }
- }
-}
-
-/*
-==============
-PM_WaterEvents
-
-Generate sound events for entering and leaving water
-==============
-*/
-static void PM_WaterEvents( void ) { // FIXME?
- //
- // if just entered a water volume, play a sound
- //
- if (!pml.previous_waterlevel && pm->waterlevel) {
- PM_AddEvent( EV_WATER_TOUCH );
- }
-
- //
- // if just completely exited a water volume, play a sound
- //
- if (pml.previous_waterlevel && !pm->waterlevel) {
- PM_AddEvent( EV_WATER_LEAVE );
- }
-
- //
- // check for head just going under water
- //
- if (pml.previous_waterlevel != 3 && pm->waterlevel == 3) {
- PM_AddEvent( EV_WATER_UNDER );
- }
-
- //
- // check for head just coming out of water
- //
- if (pml.previous_waterlevel == 3 && pm->waterlevel != 3) {
- PM_AddEvent( EV_WATER_CLEAR );
- }
-}
-
-
-/*
-===============
-PM_BeginWeaponChange
-===============
-*/
-static void PM_BeginWeaponChange( int weapon ) {
- if ( weapon <= WP_NONE || weapon >= WP_NUM_WEAPONS ) {
- return;
- }
-
- if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
- return;
- }
-
- if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
- return;
- }
-
- PM_AddEvent( EV_CHANGE_WEAPON );
- pm->ps->weaponstate = WEAPON_DROPPING;
- pm->ps->weaponTime += 200;
- PM_StartTorsoAnim( TORSO_DROP );
-}
-
-
-/*
-===============
-PM_FinishWeaponChange
-===============
-*/
-static void PM_FinishWeaponChange( void ) {
- int weapon;
-
- weapon = pm->cmd.weapon;
- if ( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) {
- weapon = WP_NONE;
- }
-
- if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
- weapon = WP_NONE;
- }
-
- pm->ps->weapon = weapon;
- pm->ps->weaponstate = WEAPON_RAISING;
- pm->ps->weaponTime += 250;
- PM_StartTorsoAnim( TORSO_RAISE );
-}
-
-
-/*
-==============
-PM_TorsoAnimation
-
-==============
-*/
-static void PM_TorsoAnimation( void ) {
- if ( pm->ps->weaponstate == WEAPON_READY ) {
- if ( pm->ps->weapon == WP_GAUNTLET ) {
- PM_ContinueTorsoAnim( TORSO_STAND2 );
- } else {
- PM_ContinueTorsoAnim( TORSO_STAND );
- }
- return;
- }
-}
-
-
-/*
-==============
-PM_Weapon
-
-Generates weapon events and modifes the weapon counter
-
-Elimination TODO:
-Make this thing stop during warmup (done)
-==============
-*/
-static void PM_Weapon( void ) {
- int addTime;
-
- // don't allow attack until all buttons are up
- if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
- return;
- }
-
- // ignore if spectator
- if ( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR || pm->ps->pm_type == PM_SPECTATOR) {
- return;
- }
-
- // check for dead player
- if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
- pm->ps->weapon = WP_NONE;
- return;
- }
-
- // check for item using
- if ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) {
- if ( ! ( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) {
- if ( bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_MEDKIT
- && pm->ps->stats[STAT_HEALTH] >= (pm->ps->stats[STAT_MAX_HEALTH] + 25) ) {
- // don't use medkit if at max health
- } else {
- pm->ps->pm_flags |= PMF_USE_ITEM_HELD;
- PM_AddEvent( EV_USE_ITEM0 + bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag );
- pm->ps->stats[STAT_HOLDABLE_ITEM] = 0;
- }
- return;
- }
- } else {
- pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD;
- }
-
-
- // make weapon function
- if ( pm->ps->weaponTime > 0 ) {
- pm->ps->weaponTime -= pml.msec;
- }
-
- // check for weapon change
- // can't change if weapon is firing, but can change
- // again if lowering or raising
- if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) {
- if ( pm->ps->weapon != pm->cmd.weapon ) {
- PM_BeginWeaponChange( pm->cmd.weapon );
- }
- }
-
- if ( pm->ps->weaponTime > 0 ) {
- return;
- }
-
- // change weapon if time
- if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
- PM_FinishWeaponChange();
- return;
- }
-
- if ( pm->ps->weaponstate == WEAPON_RAISING ) {
- pm->ps->weaponstate = WEAPON_READY;
- if ( pm->ps->weapon == WP_GAUNTLET ) {
- PM_StartTorsoAnim( TORSO_STAND2 );
- } else {
- PM_StartTorsoAnim( TORSO_STAND );
- }
- return;
- }
-
- // check for fire
- if ( ! (pm->cmd.buttons & BUTTON_ATTACK) ) {
- pm->ps->weaponTime = 0;
- pm->ps->weaponstate = WEAPON_READY;
- return;
- }
-
- // start the animation even if out of ammo
- if ( pm->ps->weapon == WP_GAUNTLET ) {
- // the guantlet only "fires" when it actually hits something
- if ( !pm->gauntletHit ) {
- pm->ps->weaponTime = 0;
- pm->ps->weaponstate = WEAPON_READY;
- return;
- }
- PM_StartTorsoAnim( TORSO_ATTACK2 );
- } else {
- PM_StartTorsoAnim( TORSO_ATTACK );
- }
-
- pm->ps->weaponstate = WEAPON_FIRING;
-
- // check for out of ammo
- if ( ! pm->ps->ammo[ pm->ps->weapon ] ) {
- PM_AddEvent( EV_NOAMMO );
- pm->ps->weaponTime += 500;
- return;
- }
-
- // take an ammo away if not infinite, 999 or up
- if ( !(pm->ps->ammo[ pm->ps->weapon ] == -1 || pm->ps->ammo[ pm->ps->weapon ] >=999 )) {
- pm->ps->ammo[ pm->ps->weapon ]--;
- }
-
- // fire weapon
- PM_AddEvent( EV_FIRE_WEAPON );
-
- switch( pm->ps->weapon ) {
- default:
- case WP_GAUNTLET:
- addTime = 400;
- break;
- case WP_LIGHTNING:
- addTime = 50;
- break;
- case WP_SHOTGUN:
- addTime = 1000;
- break;
- case WP_MACHINEGUN:
- addTime = 100;
- break;
- case WP_GRENADE_LAUNCHER:
- addTime = 800;
- break;
- case WP_ROCKET_LAUNCHER:
- addTime = 800;
- break;
- case WP_PLASMAGUN:
- addTime = 100;
- break;
- case WP_RAILGUN:
- addTime = 1500;
- break;
- case WP_BFG:
- addTime = 200;
- break;
- case WP_GRAPPLING_HOOK:
- addTime = 400;
- break;
- case WP_NAILGUN:
- addTime = 1000;
- break;
- case WP_PROX_LAUNCHER:
- addTime = 800;
- break;
- case WP_CHAINGUN:
- addTime = 30;
- break;
- }
-
- if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
- addTime /= 1.5;
- }
- else
- if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
- addTime /= 1.3;
- }
- else
- if ( pm->ps->powerups[PW_HASTE] ) {
- addTime /= 1.3;
- }
-
- pm->ps->weaponTime += addTime;
-}
-
-/*
-================
-PM_Animate
-================
-*/
-
-static void PM_Animate( void ) {
- if ( pm->cmd.buttons & BUTTON_GESTURE ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_GESTURE );
- pm->ps->torsoTimer = TIMER_GESTURE;
- PM_AddEvent( EV_TAUNT );
- }
- } else if ( pm->cmd.buttons & BUTTON_GETFLAG ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_GETFLAG );
- pm->ps->torsoTimer = 600; //TIMER_GESTURE;
- }
- } else if ( pm->cmd.buttons & BUTTON_GUARDBASE ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_GUARDBASE );
- pm->ps->torsoTimer = 600; //TIMER_GESTURE;
- }
- } else if ( pm->cmd.buttons & BUTTON_PATROL ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_PATROL );
- pm->ps->torsoTimer = 600; //TIMER_GESTURE;
- }
- } else if ( pm->cmd.buttons & BUTTON_FOLLOWME ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_FOLLOWME );
- pm->ps->torsoTimer = 600; //TIMER_GESTURE;
- }
- } else if ( pm->cmd.buttons & BUTTON_AFFIRMATIVE ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_AFFIRMATIVE);
- pm->ps->torsoTimer = 600; //TIMER_GESTURE;
- }
- } else if ( pm->cmd.buttons & BUTTON_NEGATIVE ) {
- if ( pm->ps->torsoTimer == 0 ) {
- PM_StartTorsoAnim( TORSO_NEGATIVE );
- pm->ps->torsoTimer = 600; //TIMER_GESTURE;
- }
- }
-}
-
-
-/*
-================
-PM_DropTimers
-================
-*/
-static void PM_DropTimers( void ) {
- // drop misc timing counter
- if ( pm->ps->pm_time ) {
- if ( pml.msec >= pm->ps->pm_time ) {
- pm->ps->pm_flags &= ~PMF_ALL_TIMES;
- pm->ps->pm_time = 0;
- } else {
- pm->ps->pm_time -= pml.msec;
- }
- }
-
- // drop animation counter
- if ( pm->ps->legsTimer > 0 ) {
- pm->ps->legsTimer -= pml.msec;
- if ( pm->ps->legsTimer < 0 ) {
- pm->ps->legsTimer = 0;
- }
- }
-
- if ( pm->ps->torsoTimer > 0 ) {
- pm->ps->torsoTimer -= pml.msec;
- if ( pm->ps->torsoTimer < 0 ) {
- pm->ps->torsoTimer = 0;
- }
- }
-}
-
-/*
-================
-PM_UpdateViewAngles
-
-This can be used as another entry point when only the viewangles
-are being updated isntead of a full move
-================
-*/
-void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) {
- short temp;
- int i;
-
- if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) {
- return; // no view changes at all
- }
-
- if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) {
- return; // no view changes at all
- }
-
- // circularly clamp the angles with deltas
- for (i=0 ; i<3 ; i++) {
- temp = cmd->angles[i] + ps->delta_angles[i];
- if ( i == PITCH ) {
- // don't let the player look up or down more than 90 degrees
- if ( temp > 16000 ) {
- ps->delta_angles[i] = 16000 - cmd->angles[i];
- temp = 16000;
- } else if ( temp < -16000 ) {
- ps->delta_angles[i] = -16000 - cmd->angles[i];
- temp = -16000;
- }
- }
- ps->viewangles[i] = SHORT2ANGLE(temp);
- }
-
-}
-
-
-/*
-================
-PmoveSingle
-
-================
-*/
-void trap_SnapVector( float *v );
-
-void PmoveSingle (pmove_t *pmove) {
- pm = pmove;
-
- // this counter lets us debug movement problems with a journal
- // by setting a conditional breakpoint fot the previous frame
- c_pmove++;
-
- // clear results
- pm->numtouch = 0;
- pm->watertype = 0;
- pm->waterlevel = 0;
-
- if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
- pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies
- }
-
- // make sure walking button is clear if they are running, to avoid
- // proxy no-footsteps cheats
- if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) {
- pm->cmd.buttons &= ~BUTTON_WALKING;
- }
-
- // set the talk balloon flag
- if ( pm->cmd.buttons & BUTTON_TALK ) {
- pm->ps->eFlags |= EF_TALK;
- } else {
- pm->ps->eFlags &= ~EF_TALK;
- }
-
- // set the firing flag for continuous beam weapons
- if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION
- && ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) {
- pm->ps->eFlags |= EF_FIRING;
- } else {
- pm->ps->eFlags &= ~EF_FIRING;
- }
-
- // clear the respawned flag if attack and use are cleared
- if ( pm->ps->stats[STAT_HEALTH] > 0 &&
- !( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) {
- pm->ps->pm_flags &= ~PMF_RESPAWNED;
- }
-
- // if talk button is down, dissallow all other input
- // this is to prevent any possible intercept proxy from
- // adding fake talk balloons
- if ( pmove->cmd.buttons & BUTTON_TALK ) {
- // keep the talk button set tho for when the cmd.serverTime > 66 msec
- // and the same cmd is used multiple times in Pmove
- pmove->cmd.buttons = BUTTON_TALK;
- pmove->cmd.forwardmove = 0;
- pmove->cmd.rightmove = 0;
- pmove->cmd.upmove = 0;
- }
-
- // clear all pmove local vars
- memset (&pml, 0, sizeof(pml));
-
- // determine the time
- pml.msec = pmove->cmd.serverTime - pm->ps->commandTime;
- if ( pml.msec < 1 ) {
- pml.msec = 1;
- } else if ( pml.msec > 200 ) {
- pml.msec = 200;
- }
- pm->ps->commandTime = pmove->cmd.serverTime;
-
- // save old org in case we get stuck
- VectorCopy (pm->ps->origin, pml.previous_origin);
-
- // save old velocity for crashlanding
- VectorCopy (pm->ps->velocity, pml.previous_velocity);
-
- pml.frametime = pml.msec * 0.001;
-
- // update the viewangles
- PM_UpdateViewAngles( pm->ps, &pm->cmd );
-
- AngleVectors (pm->ps->viewangles, pml.forward, pml.right, pml.up);
-
- if ( pm->cmd.upmove < 10 ) {
- // not holding jump
- pm->ps->pm_flags &= ~PMF_JUMP_HELD;
- }
-
- // decide if backpedaling animations should be used
- if ( pm->cmd.forwardmove < 0 ) {
- pm->ps->pm_flags |= PMF_BACKWARDS_RUN;
- } else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) {
- pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;
- }
-
- if ( pm->ps->pm_type >= PM_DEAD ) {
- pm->cmd.forwardmove = 0;
- pm->cmd.rightmove = 0;
- pm->cmd.upmove = 0;
- }
-
- if ( pm->ps->pm_type == PM_SPECTATOR ) {
- PM_CheckDuck ();
- PM_FlyMove ();
- PM_DropTimers ();
- return;
- }
-
- if ( pm->ps->pm_type == PM_NOCLIP ) {
- PM_NoclipMove ();
- PM_DropTimers ();
- return;
- }
-
- if (pm->ps->pm_type == PM_FREEZE) {
- return; // no movement at all
- }
-
- if ( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION) {
- return; // no movement at all
- }
-
- // set watertype, and waterlevel
- PM_SetWaterLevel();
- pml.previous_waterlevel = pmove->waterlevel;
-
- // set mins, maxs, and viewheight
- PM_CheckDuck ();
-
- // set groundentity
- PM_GroundTrace();
-
- if ( pm->ps->pm_type == PM_DEAD ) {
- PM_DeadMove ();
- }
-
- PM_DropTimers();
-
- if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
- PM_InvulnerabilityMove();
- } else
- if ( pm->ps->powerups[PW_FLIGHT] ) {
- // flight powerup doesn't allow jump and has different friction
- PM_FlyMove();
- } else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) {
- PM_GrappleMove();
- // We can wiggle a bit
- PM_AirMove();
- } else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) {
- PM_WaterJumpMove();
- } else if ( pm->waterlevel > 1 ) {
- // swimming
- PM_WaterMove();
- } else if ( pml.walking ) {
- // walking on ground
- PM_WalkMove();
- } else {
- // airborne
- PM_AirMove();
- }
-
- PM_Animate();
-
- // set groundentity, watertype, and waterlevel
- PM_GroundTrace();
- PM_SetWaterLevel();
-
- // weapons
- if(!(pm->ps->pm_flags & PMF_ELIMWARMUP))
- PM_Weapon();
-
- // torso animation
- PM_TorsoAnimation();
-
- // footstep events / legs animations
- PM_Footsteps();
-
- // entering / leaving water splashes
- PM_WaterEvents();
-
- // snap some parts of playerstate to save network bandwidth
- //But only if pmove_float is not enabled
- if(!(pm->pmove_float))
- trap_SnapVector( pm->ps->velocity );
-}
-
-
-/*
-================
-Pmove
-
-Can be called by either the server or the client
-================
-*/
-void Pmove (pmove_t *pmove) {
- int finalTime;
-
- finalTime = pmove->cmd.serverTime;
-
- if ( finalTime < pmove->ps->commandTime ) {
- return; // should not happen
- }
-
- if ( finalTime > pmove->ps->commandTime + 1000 ) {
- pmove->ps->commandTime = finalTime - 1000;
- }
-
- pmove->ps->pmove_framecount = (pmove->ps->pmove_framecount+1) & ((1<<PS_PMOVEFRAMECOUNTBITS)-1);
-
- // chop the move up if it is too long, to prevent framerate
- // dependent behavior
- while ( pmove->ps->commandTime != finalTime ) {
- int msec;
-
- msec = finalTime - pmove->ps->commandTime;
-
- if ( pmove->pmove_fixed ) {
- if ( msec > pmove->pmove_msec ) {
- msec = pmove->pmove_msec;
- }
- }
- else {
- if ( msec > 66 ) {
- msec = 66;
- }
- }
- pmove->cmd.serverTime = pmove->ps->commandTime + msec;
- PmoveSingle( pmove );
-
- if ( pmove->ps->pm_flags & PMF_JUMP_HELD ) {
- pmove->cmd.upmove = 20;
- }
- }
-
- //PM_CheckStuck();
-
-}
-
diff --git a/game/code/game/bg_public.h b/game/code/game/bg_public.h
deleted file mode 100644
index b0efb3e..0000000
--- a/game/code/game/bg_public.h
+++ /dev/null
@@ -1,814 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// bg_public.h -- definitions shared by both the server game and client game modules
-
-// because games can change separately from the main system version, we need a
-// second version that must match between game and cgame
-
-#if defined(BG_PUBLIC_H)
-#else
-#define BG_PUBLIC_H 1
-
-#define GAME_VERSION BASEGAME "-1"
-
-#define DEFAULT_GRAVITY 800
-#define GIB_HEALTH -40
-#define ARMOR_PROTECTION 0.66
-
-#define MAX_ITEMS 256
-
-#define RANK_TIED_FLAG 0x4000
-
-#define DEFAULT_SHOTGUN_SPREAD 700
-#define DEFAULT_SHOTGUN_COUNT 11
-
-#define ITEM_RADIUS 15 // item sizes are needed for client side pickup detection
-
-#define LIGHTNING_RANGE 768
-
-#define SCORE_NOT_PRESENT -9999 // for the CS_SCORES[12] when only one player is present
-
-#define VOTE_TIME 30000 // 30 seconds before vote times out
-
-#define MINS_Z -24
-#define DEFAULT_VIEWHEIGHT 26
-#define CROUCH_VIEWHEIGHT 12
-#define DEAD_VIEWHEIGHT -16
-
-//Domination points
-#define MAX_DOMINATION_POINTS 6
-#define MAX_DOMINATION_POINTS_NAMES 20
-
-//
-// config strings are a general means of communicating variable length strings
-// from the server to all connected clients.
-//
-
-// CS_SERVERINFO and CS_SYSTEMINFO are defined in q_shared.h
-#define CS_MUSIC 2
-#define CS_MESSAGE 3 // from the map worldspawn's message field
-#define CS_MOTD 4 // g_motd string for server message of the day
-#define CS_WARMUP 5 // server time when the match will be restarted
-#define CS_SCORES1 6
-#define CS_SCORES2 7
-#define CS_VOTE_TIME 8
-#define CS_VOTE_STRING 9
-#define CS_VOTE_YES 10
-#define CS_VOTE_NO 11
-
-#define CS_TEAMVOTE_TIME 12
-#define CS_TEAMVOTE_STRING 14
-#define CS_TEAMVOTE_YES 16
-#define CS_TEAMVOTE_NO 18
-
-#define CS_GAME_VERSION 20
-#define CS_LEVEL_START_TIME 21 // so the timer only shows the current level
-#define CS_INTERMISSION 22 // when 1, fraglimit/timelimit has been hit and intermission will start in a second or two
-#define CS_FLAGSTATUS 23 // string indicating flag status in CTF
-#define CS_SHADERSTATE 24
-#define CS_BOTINFO 25
-
-#define CS_ITEMS 27 // string of 0's and 1's that tell which items are present
-
-#define CS_MODELS 32
-#define CS_SOUNDS (CS_MODELS+MAX_MODELS)
-#define CS_PLAYERS (CS_SOUNDS+MAX_SOUNDS)
-#define CS_LOCATIONS (CS_PLAYERS+MAX_CLIENTS)
-#define CS_PARTICLES (CS_LOCATIONS+MAX_LOCATIONS)
-
-#define CS_MAX (CS_PARTICLES+MAX_LOCATIONS)
-
-#if (CS_MAX) > MAX_CONFIGSTRINGS
-#error overflow: (CS_MAX) > MAX_CONFIGSTRINGS
-#endif
-
-typedef enum {
- GT_FFA, // free for all
- GT_TOURNAMENT, // one on one tournament
- GT_SINGLE_PLAYER, // single player ffa
-
- //-- team games go after this --
-
- GT_TEAM, // team deathmatch
-
- //-- team games that uses bases go after this
-
- GT_CTF, // capture the flag
- GT_1FCTF,
- GT_OBELISK,
- GT_HARVESTER,
-
- //-- custom game types, there will be a variable in
-
- GT_ELIMINATION, // team elimination (custom)
- GT_CTF_ELIMINATION, // ctf elimination
- GT_LMS, // Last man standing
- GT_DOUBLE_D, // Double Domination
- GT_DOMINATION, // Standard domination 12
- GT_MAX_GAME_TYPE
-
-} gametype_t;
-
-typedef enum { GENDER_MALE, GENDER_FEMALE, GENDER_NEUTER } gender_t;
-
-/*
-===================================================================================
-
-PMOVE MODULE
-
-The pmove code takes a player_state_t and a usercmd_t and generates a new player_state_t
-and some other output data. Used for local prediction on the client game and true
-movement on the server game.
-===================================================================================
-*/
-
-typedef enum {
- PM_NORMAL, // can accelerate and turn
- PM_NOCLIP, // noclip movement
- PM_SPECTATOR, // still run into walls
- PM_DEAD, // no acceleration or turning, but free falling
- PM_FREEZE, // stuck in place with no control
- PM_INTERMISSION, // no movement or status bar
- PM_SPINTERMISSION // no movement or status bar
-} pmtype_t;
-
-typedef enum {
- WEAPON_READY,
- WEAPON_RAISING,
- WEAPON_DROPPING,
- WEAPON_FIRING
-} weaponstate_t;
-
-// pmove->pm_flags
-#define PMF_DUCKED 1
-#define PMF_JUMP_HELD 2
-#define PMF_BACKWARDS_JUMP 8 // go into backwards land
-#define PMF_BACKWARDS_RUN 16 // coast down to backwards run
-#define PMF_TIME_LAND 32 // pm_time is time before rejump
-#define PMF_TIME_KNOCKBACK 64 // pm_time is an air-accelerate only time
-#define PMF_TIME_WATERJUMP 256 // pm_time is waterjump
-#define PMF_RESPAWNED 512 // clear after attack and jump buttons come up
-#define PMF_USE_ITEM_HELD 1024
-#define PMF_GRAPPLE_PULL 2048 // pull towards grapple location
-#define PMF_FOLLOW 4096 // spectate following another player
-#define PMF_SCOREBOARD 8192 // spectate as a scoreboard
-#define PMF_INVULEXPAND 16384 // invulnerability sphere set to full size
-//Elimination players cannot fire in warmup
-#define PMF_ELIMWARMUP 32768 //I hope this is more than 16 signed bits! (it's not but it just works anyway...)
-//Don't add anymore, I have already set the sign bit :-(
-
-#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK)
-
-#define MAXTOUCH 32
-typedef struct {
- // state (in / out)
- playerState_t *ps;
-
- // command (in)
- usercmd_t cmd;
- int tracemask; // collide against these types of surfaces
- int debugLevel; // if set, diagnostic output will be printed
- qboolean noFootsteps; // if the game is setup for no footsteps by the server
- qboolean gauntletHit; // true if a gauntlet attack would actually hit something
-
- int framecount;
-
- // results (out)
- int numtouch;
- int touchents[MAXTOUCH];
-
- vec3_t mins, maxs; // bounding box size
-
- int watertype;
- int waterlevel;
-
- float xyspeed;
-
- // for fixed msec Pmove
- int pmove_fixed;
- int pmove_msec;
-
- //Sago's pmove
- int pmove_float;
-
- // callbacks to test the world
- // these will be different functions during game and cgame
- void (*trace)( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask );
- int (*pointcontents)( const vec3_t point, int passEntityNum );
-} pmove_t;
-
-// if a full pmove isn't done on the client, you can just update the angles
-void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd );
-void Pmove (pmove_t *pmove);
-
-//===================================================================================
-
-
-// player_state->stats[] indexes
-// NOTE: may not have more than 16
-typedef enum {
- STAT_HEALTH,
- STAT_HOLDABLE_ITEM,
- STAT_PERSISTANT_POWERUP,
- STAT_WEAPONS, // 16 bit fields
- STAT_ARMOR,
- STAT_DEAD_YAW, // look this direction when dead (FIXME: get rid of?)
- STAT_CLIENTS_READY, // bit mask of clients wishing to exit the intermission (FIXME: configstring?)
- STAT_MAX_HEALTH // health / armor limit, changable by handicap
-} statIndex_t;
-
-
-// player_state->persistant[] indexes
-// these fields are the only part of player_state that isn't
-// cleared on respawn
-// NOTE: may not have more than 16
-typedef enum {
- PERS_SCORE, // !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!!
- PERS_HITS, // total points damage inflicted so damage beeps can sound on change
- PERS_RANK, // player rank or team rank
- PERS_TEAM, // player team
- PERS_SPAWN_COUNT, // incremented every respawn
- PERS_PLAYEREVENTS, // 16 bits that can be flipped for events
- PERS_ATTACKER, // clientnum of last damage inflicter
- PERS_ATTACKEE_ARMOR, // health/armor of last person we attacked
- PERS_KILLED, // count of the number of times you died
- // player awards tracking
- PERS_IMPRESSIVE_COUNT, // two railgun hits in a row
- PERS_EXCELLENT_COUNT, // two successive kills in a short amount of time
- PERS_DEFEND_COUNT, // defend awards
- PERS_ASSIST_COUNT, // assist awards
- PERS_GAUNTLET_FRAG_COUNT, // kills with the guantlet
- PERS_CAPTURES // captures
-} persEnum_t;
-
-
-// entityState_t->eFlags
-#define EF_DEAD 0x00000001 // don't draw a foe marker over players with EF_DEAD
-#define EF_TICKING 0x00000002 // used to make players play the prox mine ticking sound
-#define EF_TELEPORT_BIT 0x00000004 // toggled every time the origin abruptly changes
-#define EF_AWARD_EXCELLENT 0x00000008 // draw an excellent sprite
-#define EF_PLAYER_EVENT 0x00000010
-#define EF_BOUNCE 0x00000010 // for missiles
-#define EF_BOUNCE_HALF 0x00000020 // for missiles
-#define EF_AWARD_GAUNTLET 0x00000040 // draw a gauntlet sprite
-#define EF_NODRAW 0x00000080 // may have an event, but no model (unspawned items)
-#define EF_FIRING 0x00000100 // for lightning gun
-#define EF_KAMIKAZE 0x00000200
-#define EF_MOVER_STOP 0x00000400 // will push otherwise
-#define EF_AWARD_CAP 0x00000800 // draw the capture sprite
-#define EF_TALK 0x00001000 // draw a talk balloon
-#define EF_CONNECTION 0x00002000 // draw a connection trouble sprite
-#define EF_VOTED 0x00004000 // already cast a vote
-#define EF_AWARD_IMPRESSIVE 0x00008000 // draw an impressive sprite
-#define EF_AWARD_DEFEND 0x00010000 // draw a defend sprite
-#define EF_AWARD_ASSIST 0x00020000 // draw a assist sprite
-#define EF_AWARD_DENIED 0x00040000 // denied
-#define EF_TEAMVOTED 0x00080000 // already cast a team vote
-
-// NOTE: may not have more than 16
-typedef enum {
- PW_NONE,
-
- PW_QUAD,
- PW_BATTLESUIT,
- PW_HASTE,
- PW_INVIS,
- PW_REGEN,
- PW_FLIGHT,
-
- PW_REDFLAG,
- PW_BLUEFLAG,
- PW_NEUTRALFLAG,
-
- PW_SCOUT,
- PW_GUARD,
- PW_DOUBLER,
- PW_AMMOREGEN,
- PW_INVULNERABILITY,
-
- PW_NUM_POWERUPS
-
-} powerup_t;
-
-typedef enum {
- HI_NONE,
-
- HI_TELEPORTER,
- HI_MEDKIT,
- HI_KAMIKAZE,
- HI_PORTAL,
- HI_INVULNERABILITY,
-
- HI_NUM_HOLDABLE
-} holdable_t;
-
-typedef enum {
- DD_NONE,
-
- DD_POINTARED,
- DD_POINTABLUE,
- DD_POINTAWHITE,
- DD_POINTBRED,
- DD_POINTBBLUE,
- DD_POINTBWHITE
-} doubled_t;
-
-typedef enum {
- DOM_NONE,
-
- DOM_POINTRED,
- DOM_POINTBLUE,
- DOM_POINTWHITE,
-} domination_t;
-
-
-typedef enum {
- WP_NONE,
-
- WP_GAUNTLET,
- WP_MACHINEGUN,
- WP_SHOTGUN,
- WP_GRENADE_LAUNCHER,
- WP_ROCKET_LAUNCHER,
- WP_LIGHTNING,
- WP_RAILGUN,
- WP_PLASMAGUN,
- WP_BFG,
- WP_GRAPPLING_HOOK,
- WP_NAILGUN,
- WP_PROX_LAUNCHER,
- WP_CHAINGUN,
-
- WP_NUM_WEAPONS
-} weapon_t;
-
-
-// reward sounds (stored in ps->persistant[PERS_PLAYEREVENTS])
-#define PLAYEREVENT_DENIEDREWARD 0x0001
-#define PLAYEREVENT_GAUNTLETREWARD 0x0002
-#define PLAYEREVENT_HOLYSHIT 0x0004
-
-// entityState_t->event values
-// entity events are for effects that take place reletive
-// to an existing entities origin. Very network efficient.
-
-// two bits at the top of the entityState->event field
-// will be incremented with each change in the event so
-// that an identical event started twice in a row can
-// be distinguished. And off the value with ~EV_EVENT_BITS
-// to retrieve the actual event number
-#define EV_EVENT_BIT1 0x00000100
-#define EV_EVENT_BIT2 0x00000200
-#define EV_EVENT_BITS (EV_EVENT_BIT1|EV_EVENT_BIT2)
-
-#define EVENT_VALID_MSEC 300
-
-typedef enum {
- EV_NONE,
-
- EV_FOOTSTEP,
- EV_FOOTSTEP_METAL,
- EV_FOOTSPLASH,
- EV_FOOTWADE,
- EV_SWIM,
-
- EV_STEP_4,
- EV_STEP_8,
- EV_STEP_12,
- EV_STEP_16,
-
- EV_FALL_SHORT,
- EV_FALL_MEDIUM,
- EV_FALL_FAR,
-
- EV_JUMP_PAD, // boing sound at origin, jump sound on player
-
- EV_JUMP, //Event 14
- EV_WATER_TOUCH, // foot touches
- EV_WATER_LEAVE, // foot leaves
- EV_WATER_UNDER, // head touches
- EV_WATER_CLEAR, // head leaves
-
- EV_ITEM_PICKUP, // normal item pickups are predictable
- EV_GLOBAL_ITEM_PICKUP, // powerup / team sounds are broadcast to everyone
-
- EV_NOAMMO,
- EV_CHANGE_WEAPON,
- EV_FIRE_WEAPON,
-
- EV_USE_ITEM0, //Event 24
- EV_USE_ITEM1,
- EV_USE_ITEM2,
- EV_USE_ITEM3,
- EV_USE_ITEM4,
- EV_USE_ITEM5,
- EV_USE_ITEM6,
- EV_USE_ITEM7,
- EV_USE_ITEM8,
- EV_USE_ITEM9,
- EV_USE_ITEM10,
- EV_USE_ITEM11,
- EV_USE_ITEM12,
- EV_USE_ITEM13,
- EV_USE_ITEM14,
- EV_USE_ITEM15,
-
- EV_ITEM_RESPAWN, //Event 40
- EV_ITEM_POP,
- EV_PLAYER_TELEPORT_IN,
- EV_PLAYER_TELEPORT_OUT,
-
- EV_GRENADE_BOUNCE, // eventParm will be the soundindex
-
- EV_GENERAL_SOUND,
- EV_GLOBAL_SOUND, // no attenuation
- EV_GLOBAL_TEAM_SOUND,
-
- EV_BULLET_HIT_FLESH,
- EV_BULLET_HIT_WALL,
-
- EV_MISSILE_HIT, //Event 50
- EV_MISSILE_MISS,
- EV_MISSILE_MISS_METAL,
- EV_RAILTRAIL,
- EV_SHOTGUN,
- EV_BULLET, // otherEntity is the shooter
-
- EV_PAIN,
- EV_DEATH1,
- EV_DEATH2,
- EV_DEATH3,
- EV_OBITUARY, //Event 60
-
- EV_POWERUP_QUAD,
- EV_POWERUP_BATTLESUIT,
- EV_POWERUP_REGEN,
-
- EV_GIB_PLAYER, // gib a previously living player
- EV_SCOREPLUM, // score plum
-
- EV_PROXIMITY_MINE_STICK,
- EV_PROXIMITY_MINE_TRIGGER,
- EV_KAMIKAZE, // kamikaze explodes
- EV_OBELISKEXPLODE, // obelisk explodes
- EV_OBELISKPAIN, // obelisk is in pain
- EV_INVUL_IMPACT, // invulnerability sphere impact
- EV_JUICED, // invulnerability juiced effect
- EV_LIGHTNINGBOLT, // lightning bolt bounced of invulnerability sphere
-
- EV_DEBUG_LINE,
- EV_STOPLOOPINGSOUND,
- EV_TAUNT,
- EV_TAUNT_YES,
- EV_TAUNT_NO,
- EV_TAUNT_FOLLOWME,
- EV_TAUNT_GETFLAG,
- EV_TAUNT_GUARDBASE,
- EV_TAUNT_PATROL
-
-} entity_event_t;
-
-
-typedef enum {
- GTS_RED_CAPTURE,
- GTS_BLUE_CAPTURE,
- GTS_RED_RETURN,
- GTS_BLUE_RETURN,
- GTS_RED_TAKEN,
- GTS_BLUE_TAKEN,
- GTS_REDOBELISK_ATTACKED,
- GTS_BLUEOBELISK_ATTACKED,
- GTS_REDTEAM_SCORED,
- GTS_BLUETEAM_SCORED,
- GTS_REDTEAM_TOOK_LEAD,
- GTS_BLUETEAM_TOOK_LEAD,
- GTS_TEAMS_ARE_TIED,
- GTS_KAMIKAZE
-} global_team_sound_t;
-
-// animations
-typedef enum {
- BOTH_DEATH1,
- BOTH_DEAD1,
- BOTH_DEATH2,
- BOTH_DEAD2,
- BOTH_DEATH3,
- BOTH_DEAD3,
-
- TORSO_GESTURE,
-
- TORSO_ATTACK,
- TORSO_ATTACK2,
-
- TORSO_DROP,
- TORSO_RAISE,
-
- TORSO_STAND,
- TORSO_STAND2,
-
- LEGS_WALKCR,
- LEGS_WALK,
- LEGS_RUN,
- LEGS_BACK,
- LEGS_SWIM,
-
- LEGS_JUMP,
- LEGS_LAND,
-
- LEGS_JUMPB,
- LEGS_LANDB,
-
- LEGS_IDLE,
- LEGS_IDLECR,
-
- LEGS_TURN,
-
- TORSO_GETFLAG,
- TORSO_GUARDBASE,
- TORSO_PATROL,
- TORSO_FOLLOWME,
- TORSO_AFFIRMATIVE,
- TORSO_NEGATIVE,
-
- MAX_ANIMATIONS,
-
- LEGS_BACKCR,
- LEGS_BACKWALK,
- FLAG_RUN,
- FLAG_STAND,
- FLAG_STAND2RUN,
-
- MAX_TOTALANIMATIONS
-} animNumber_t;
-
-
-typedef struct animation_s {
- int firstFrame;
- int numFrames;
- int loopFrames; // 0 to numFrames
- int frameLerp; // msec between frames
- int initialLerp; // msec to get to first frame
- int reversed; // true if animation is reversed
- int flipflop; // true if animation should flipflop back to base
-} animation_t;
-
-
-// flip the togglebit every time an animation
-// changes so a restart of the same anim can be detected
-#define ANIM_TOGGLEBIT 128
-
-
-typedef enum {
- TEAM_FREE,
- TEAM_RED,
- TEAM_BLUE,
- TEAM_SPECTATOR,
-
- TEAM_NUM_TEAMS
-} team_t;
-
-// This is a fair assumption for Double Domination:
-#define TEAM_NONE TEAM_SPECTATOR
-
-// Time between location updates
-#define TEAM_LOCATION_UPDATE_TIME 1000
-
-// How many players on the overlay
-#define TEAM_MAXOVERLAY 32
-
-//team task
-typedef enum {
- TEAMTASK_NONE,
- TEAMTASK_OFFENSE,
- TEAMTASK_DEFENSE,
- TEAMTASK_PATROL,
- TEAMTASK_FOLLOW,
- TEAMTASK_RETRIEVE,
- TEAMTASK_ESCORT,
- TEAMTASK_CAMP
-} teamtask_t;
-
-// means of death
-typedef enum {
- MOD_UNKNOWN,
- MOD_SHOTGUN,
- MOD_GAUNTLET,
- MOD_MACHINEGUN,
- MOD_GRENADE,
- MOD_GRENADE_SPLASH,
- MOD_ROCKET,
- MOD_ROCKET_SPLASH,
- MOD_PLASMA,
- MOD_PLASMA_SPLASH,
- MOD_RAILGUN,
- MOD_LIGHTNING,
- MOD_BFG,
- MOD_BFG_SPLASH,
- MOD_WATER,
- MOD_SLIME,
- MOD_LAVA,
- MOD_CRUSH,
- MOD_TELEFRAG,
- MOD_FALLING,
- MOD_SUICIDE,
- MOD_TARGET_LASER,
- MOD_TRIGGER_HURT,
- MOD_NAIL,
- MOD_CHAINGUN,
- MOD_PROXIMITY_MINE,
- MOD_KAMIKAZE,
- MOD_JUICED,
- MOD_GRAPPLE
-} meansOfDeath_t;
-
-
-//---------------------------------------------------------
-
-// gitem_t->type
-typedef enum {
- IT_BAD,
- IT_WEAPON, // EFX: rotate + upscale + minlight
- IT_AMMO, // EFX: rotate
- IT_ARMOR, // EFX: rotate + minlight
- IT_HEALTH, // EFX: static external sphere + rotating internal
- IT_POWERUP, // instant on, timer based
- // EFX: rotate + external ring that rotates
- IT_HOLDABLE, // single use, holdable item
- // EFX: rotate + bob
- IT_PERSISTANT_POWERUP,
- IT_TEAM
-} itemType_t;
-
-#define MAX_ITEM_MODELS 4
-
-typedef struct gitem_s {
- char *classname; // spawning name
- char *pickup_sound;
- char *world_model[MAX_ITEM_MODELS];
-
- char *icon;
- char *pickup_name; // for printing on pickup
-
- int quantity; // for ammo how much, or duration of powerup
- itemType_t giType; // IT_* flags
-
- int giTag;
-
- char *precaches; // string of all models and images this item will use
- char *sounds; // string of all sounds this item will use
-} gitem_t;
-
-// included in both the game dll and the client
-extern gitem_t bg_itemlist[];
-extern int bg_numItems;
-
-gitem_t *BG_FindItem( const char *pickupName );
-gitem_t *BG_FindItemForWeapon( weapon_t weapon );
-gitem_t *BG_FindItemForPowerup( powerup_t pw );
-gitem_t *BG_FindItemForHoldable( holdable_t pw );
-#define ITEM_INDEX(x) ((x)-bg_itemlist)
-
-qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps );
-
-
-// g_dmflags->integer flags
-#define DF_NO_FALLING 8
-#define DF_FIXED_FOV 16
-#define DF_NO_FOOTSTEPS 32
-
-//g_videoflags->integer
-#define VF_LOCK_CVARS_BASIC 1
-#define VF_LOCK_CVARS_EXTENDED 2
-#define VF_LOCK_VERTEX 4
-
-// g_elimflags->integer
-//This is used to signal the client that it cannot go to free spectator:
-#define EF_ONEWAY 1
-#define EF_NO_FREESPEC 2
-
-//g_voteflags->integer
-//Autoparsed from allowedvote
-//List: "/map_restart/nextmap/map/g_gametype/kick/clientkick/g_doWarmup/timelimit/fraglimit/custom/shuffle/"
-#define VF_map_restart 1
-#define VF_nextmap 2
-#define VF_map 4
-#define VF_g_gametype 8
-//Note that we skipped kick... not needed
-#define VF_clientkick 16
-#define VF_g_doWarmup 32
-#define VF_timelimit 64
-#define VF_fraglimit 128
-#define VF_custom 256
-#define VF_shuffle 512
-
-// content masks
-#define MASK_ALL (-1)
-#define MASK_SOLID (CONTENTS_SOLID)
-#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY)
-#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP)
-#define MASK_WATER (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME)
-#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA)
-#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE)
-
-
-//
-// entityState_t->eType
-//
-typedef enum {
- ET_GENERAL,
- ET_PLAYER,
- ET_ITEM,
- ET_MISSILE,
- ET_MOVER,
- ET_BEAM,
- ET_PORTAL,
- ET_SPEAKER,
- ET_PUSH_TRIGGER,
- ET_TELEPORT_TRIGGER,
- ET_INVISIBLE,
- ET_GRAPPLE, // grapple hooked on wall
- ET_TEAM,
-
- ET_EVENTS // any of the EV_* events can be added freestanding
- // by setting eType to ET_EVENTS + eventNum
- // this avoids having to set eFlags and eventNum
-} entityType_t;
-
-//KK-OAX Using this now instead of g_mem.c
-// bg_alloc.c
-//
-qboolean BG_CanAlloc( unsigned int size );
-void *BG_Alloc( unsigned int size );
-void BG_InitMemory( void );
-void BG_Free( void *ptr );
-void BG_DefragmentMemory( void );
-
-
-void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result );
-void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result );
-
-void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps );
-
-void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad );
-
-void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap );
-void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap );
-
-qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime );
-
-
-#define ARENAS_PER_TIER 4
-#define MAX_ARENAS 1024
-#define MAX_ARENAS_TEXT 8192
-
-#define MAX_BOTS 1024
-#define MAX_BOTS_TEXT 8192
-
-
-// Kamikaze
-
-// 1st shockwave times
-#define KAMI_SHOCKWAVE_STARTTIME 0
-#define KAMI_SHOCKWAVEFADE_STARTTIME 1500
-#define KAMI_SHOCKWAVE_ENDTIME 2000
-// explosion/implosion times
-#define KAMI_EXPLODE_STARTTIME 250
-#define KAMI_IMPLODE_STARTTIME 2000
-#define KAMI_IMPLODE_ENDTIME 2250
-// 2nd shockwave times
-#define KAMI_SHOCKWAVE2_STARTTIME 2000
-#define KAMI_SHOCKWAVE2FADE_STARTTIME 2500
-#define KAMI_SHOCKWAVE2_ENDTIME 3000
-// radius of the models without scaling
-#define KAMI_SHOCKWAVEMODEL_RADIUS 88
-#define KAMI_BOOMSPHEREMODEL_RADIUS 72
-// maximum radius of the models during the effect
-#define KAMI_SHOCKWAVE_MAXRADIUS 1320
-#define KAMI_BOOMSPHERE_MAXRADIUS 720
-#define KAMI_SHOCKWAVE2_MAXRADIUS 704
-
-//KK-OAX
-//bg_misc.c
-char *BG_TeamName( team_t team );
-
-#endif
diff --git a/game/code/game/bg_slidemove.c b/game/code/game/bg_slidemove.c
deleted file mode 100644
index 14b4834..0000000
--- a/game/code/game/bg_slidemove.c
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// bg_slidemove.c -- part of bg_pmove functionality
-
-#include "../qcommon/q_shared.h"
-#include "bg_public.h"
-#include "bg_local.h"
-
-/*
-
-input: origin, velocity, bounds, groundPlane, trace function
-
-output: origin, velocity, impacts, stairup boolean
-
-*/
-
-/*
-==================
-PM_SlideMove
-
-Returns qtrue if the velocity was clipped in some way
-==================
-*/
-#define MAX_CLIP_PLANES 5
-qboolean PM_SlideMove( qboolean gravity ) {
- int bumpcount, numbumps;
- vec3_t dir;
- float d;
- int numplanes;
- vec3_t planes[MAX_CLIP_PLANES];
- vec3_t primal_velocity;
- vec3_t clipVelocity;
- int i, j, k;
- trace_t trace;
- vec3_t end;
- float time_left;
- float into;
- vec3_t endVelocity;
- vec3_t endClipVelocity;
-
- numbumps = 4;
-
- VectorCopy (pm->ps->velocity, primal_velocity);
-
- if ( gravity ) {
- VectorCopy( pm->ps->velocity, endVelocity );
- endVelocity[2] -= pm->ps->gravity * pml.frametime;
- pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
- primal_velocity[2] = endVelocity[2];
- if ( pml.groundPlane ) {
- // slide along the ground plane
- PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
- pm->ps->velocity, OVERCLIP );
- }
- }
-
- time_left = pml.frametime;
-
- // never turn against the ground plane
- if ( pml.groundPlane ) {
- numplanes = 1;
- VectorCopy( pml.groundTrace.plane.normal, planes[0] );
- } else {
- numplanes = 0;
- }
-
- // never turn against original velocity
- VectorNormalize2( pm->ps->velocity, planes[numplanes] );
- numplanes++;
-
- for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {
-
- // calculate position we are trying to move to
- VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );
-
- // see if we can make it there
- pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask);
-
- if (trace.allsolid) {
- // entity is completely trapped in another solid
- pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration
- return qtrue;
- }
-
- if (trace.fraction > 0) {
- // actually covered some distance
- VectorCopy (trace.endpos, pm->ps->origin);
- }
-
- if (trace.fraction == 1) {
- break; // moved the entire distance
- }
-
- // save entity for contact
- PM_AddTouchEnt( trace.entityNum );
-
- time_left -= time_left * trace.fraction;
-
- if (numplanes >= MAX_CLIP_PLANES) {
- // this shouldn't really happen
- VectorClear( pm->ps->velocity );
- return qtrue;
- }
-
- //
- // if this is the same plane we hit before, nudge velocity
- // out along it, which fixes some epsilon issues with
- // non-axial planes
- //
- for ( i = 0 ; i < numplanes ; i++ ) {
- if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) {
- VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );
- break;
- }
- }
- if ( i < numplanes ) {
- continue;
- }
- VectorCopy (trace.plane.normal, planes[numplanes]);
- numplanes++;
-
- //
- // modify velocity so it parallels all of the clip planes
- //
-
- // find a plane that it enters
- for ( i = 0 ; i < numplanes ; i++ ) {
- into = DotProduct( pm->ps->velocity, planes[i] );
- if ( into >= 0.1 ) {
- continue; // move doesn't interact with the plane
- }
-
- // see how hard we are hitting things
- if ( -into > pml.impactSpeed ) {
- pml.impactSpeed = -into;
- }
-
- // slide along the plane
- PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );
-
- // slide along the plane
- PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );
-
- // see if there is a second plane that the new move enters
- for ( j = 0 ; j < numplanes ; j++ ) {
- if ( j == i ) {
- continue;
- }
- if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
- continue; // move doesn't interact with the plane
- }
-
- // try clipping the move to the plane
- PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
- PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );
-
- // see if it goes back into the first clip plane
- if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
- continue;
- }
-
- // slide the original velocity along the crease
- CrossProduct (planes[i], planes[j], dir);
- VectorNormalize( dir );
- d = DotProduct( dir, pm->ps->velocity );
- VectorScale( dir, d, clipVelocity );
-
- CrossProduct (planes[i], planes[j], dir);
- VectorNormalize( dir );
- d = DotProduct( dir, endVelocity );
- VectorScale( dir, d, endClipVelocity );
-
- // see if there is a third plane the the new move enters
- for ( k = 0 ; k < numplanes ; k++ ) {
- if ( k == i || k == j ) {
- continue;
- }
- if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
- continue; // move doesn't interact with the plane
- }
-
- // stop dead at a tripple plane interaction
- VectorClear( pm->ps->velocity );
- return qtrue;
- }
- }
-
- // if we have fixed all interactions, try another move
- VectorCopy( clipVelocity, pm->ps->velocity );
- VectorCopy( endClipVelocity, endVelocity );
- break;
- }
- }
-
- if ( gravity ) {
- VectorCopy( endVelocity, pm->ps->velocity );
- }
-
- // don't change velocity if in a timer (FIXME: is this correct?)
- if ( pm->ps->pm_time ) {
- VectorCopy( primal_velocity, pm->ps->velocity );
- }
-
- return ( bumpcount != 0 );
-}
-
-/*
-==================
-PM_StepSlideMove
-
-==================
-*/
-void PM_StepSlideMove( qboolean gravity ) {
- vec3_t start_o, start_v;
- vec3_t down_o, down_v;
- trace_t trace;
-// float down_dist, up_dist;
-// vec3_t delta, delta2;
- vec3_t up, down;
- float stepSize;
-
- VectorCopy (pm->ps->origin, start_o);
- VectorCopy (pm->ps->velocity, start_v);
-
- if ( PM_SlideMove( gravity ) == 0 ) {
- return; // we got exactly where we wanted to go first try
- }
-
- VectorCopy(start_o, down);
- down[2] -= STEPSIZE;
- pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
- VectorSet(up, 0, 0, 1);
- // never step up when you still have up velocity
- if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 ||
- DotProduct(trace.plane.normal, up) < 0.7)) {
- return;
- }
-
- VectorCopy (pm->ps->origin, down_o);
- VectorCopy (pm->ps->velocity, down_v);
-
- VectorCopy (start_o, up);
- up[2] += STEPSIZE;
-
- // test the player position if they were a stepheight higher
- pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);
- if ( trace.allsolid ) {
- if ( pm->debugLevel ) {
- Com_Printf("%i:bend can't step\n", c_pmove);
- }
- return; // can't step up
- }
-
- stepSize = trace.endpos[2] - start_o[2];
- // try slidemove from this position
- VectorCopy (trace.endpos, pm->ps->origin);
- VectorCopy (start_v, pm->ps->velocity);
-
- PM_SlideMove( gravity );
-
- // push down the final amount
- VectorCopy (pm->ps->origin, down);
- down[2] -= stepSize;
- pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
- if ( !trace.allsolid ) {
- VectorCopy (trace.endpos, pm->ps->origin);
- }
- if ( trace.fraction < 1.0 ) {
- PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
- }
-
-#if 0
- // if the down trace can trace back to the original position directly, don't step
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask);
- if ( trace.fraction == 1.0 ) {
- // use the original move
- VectorCopy (down_o, pm->ps->origin);
- VectorCopy (down_v, pm->ps->velocity);
- if ( pm->debugLevel ) {
- Com_Printf("%i:bend\n", c_pmove);
- }
- } else
-#endif
- {
- // use the step move
- float delta;
-
- delta = pm->ps->origin[2] - start_o[2];
- if ( delta > 2 ) {
- if ( delta < 7 ) {
- PM_AddEvent( EV_STEP_4 );
- } else if ( delta < 11 ) {
- PM_AddEvent( EV_STEP_8 );
- } else if ( delta < 15 ) {
- PM_AddEvent( EV_STEP_12 );
- } else {
- PM_AddEvent( EV_STEP_16 );
- }
- }
- if ( pm->debugLevel ) {
- Com_Printf("%i:stepped\n", c_pmove);
- }
- }
-}
-
diff --git a/game/code/game/chars.h b/game/code/game/chars.h
deleted file mode 100644
index 4b570df..0000000
--- a/game/code/game/chars.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-//========================================================
-//========================================================
-//name
-#define CHARACTERISTIC_NAME 0 //string
-//gender of the bot
-#define CHARACTERISTIC_GENDER 1 //string ("male", "female", "it")
-//attack skill
-// > 0.0 && < 0.2 = don't move
-// > 0.3 && < 1.0 = aim at enemy during retreat
-// > 0.0 && < 0.4 = only move forward/backward
-// >= 0.4 && < 1.0 = circle strafing
-// > 0.7 && < 1.0 = random strafe direction change
-#define CHARACTERISTIC_ATTACK_SKILL 2 //float [0, 1]
-//weapon weight file
-#define CHARACTERISTIC_WEAPONWEIGHTS 3 //string
-//view angle difference to angle change factor
-#define CHARACTERISTIC_VIEW_FACTOR 4 //float <0, 1]
-//maximum view angle change
-#define CHARACTERISTIC_VIEW_MAXCHANGE 5 //float [1, 360]
-//reaction time in seconds
-#define CHARACTERISTIC_REACTIONTIME 6 //float [0, 5]
-//accuracy when aiming
-#define CHARACTERISTIC_AIM_ACCURACY 7 //float [0, 1]
-//weapon specific aim accuracy
-#define CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN 8 //float [0, 1]
-#define CHARACTERISTIC_AIM_ACCURACY_SHOTGUN 9 //float [0, 1]
-#define CHARACTERISTIC_AIM_ACCURACY_ROCKETLAUNCHER 10 //float [0, 1]
-#define CHARACTERISTIC_AIM_ACCURACY_GRENADELAUNCHER 11 //float [0, 1]
-#define CHARACTERISTIC_AIM_ACCURACY_LIGHTNING 12
-#define CHARACTERISTIC_AIM_ACCURACY_PLASMAGUN 13 //float [0, 1]
-#define CHARACTERISTIC_AIM_ACCURACY_RAILGUN 14
-#define CHARACTERISTIC_AIM_ACCURACY_BFG10K 15 //float [0, 1]
-//skill when aiming
-// > 0.0 && < 0.9 = aim is affected by enemy movement
-// > 0.4 && <= 0.8 = enemy linear leading
-// > 0.8 && <= 1.0 = enemy exact movement leading
-// > 0.5 && <= 1.0 = prediction shots when enemy is not visible
-// > 0.6 && <= 1.0 = splash damage by shooting nearby geometry
-#define CHARACTERISTIC_AIM_SKILL 16 //float [0, 1]
-//weapon specific aim skill
-#define CHARACTERISTIC_AIM_SKILL_ROCKETLAUNCHER 17 //float [0, 1]
-#define CHARACTERISTIC_AIM_SKILL_GRENADELAUNCHER 18 //float [0, 1]
-#define CHARACTERISTIC_AIM_SKILL_PLASMAGUN 19 //float [0, 1]
-#define CHARACTERISTIC_AIM_SKILL_BFG10K 20 //float [0, 1]
-//========================================================
-//chat
-//========================================================
-//file with chats
-#define CHARACTERISTIC_CHAT_FILE 21 //string
-//name of the chat character
-#define CHARACTERISTIC_CHAT_NAME 22 //string
-//characters per minute type speed
-#define CHARACTERISTIC_CHAT_CPM 23 //integer [1, 4000]
-//tendency to insult/praise
-#define CHARACTERISTIC_CHAT_INSULT 24 //float [0, 1]
-//tendency to chat misc
-#define CHARACTERISTIC_CHAT_MISC 25 //float [0, 1]
-//tendency to chat at start or end of level
-#define CHARACTERISTIC_CHAT_STARTENDLEVEL 26 //float [0, 1]
-//tendency to chat entering or exiting the game
-#define CHARACTERISTIC_CHAT_ENTEREXITGAME 27 //float [0, 1]
-//tendency to chat when killed someone
-#define CHARACTERISTIC_CHAT_KILL 28 //float [0, 1]
-//tendency to chat when died
-#define CHARACTERISTIC_CHAT_DEATH 29 //float [0, 1]
-//tendency to chat when enemy suicides
-#define CHARACTERISTIC_CHAT_ENEMYSUICIDE 30 //float [0, 1]
-//tendency to chat when hit while talking
-#define CHARACTERISTIC_CHAT_HITTALKING 31 //float [0, 1]
-//tendency to chat when bot was hit but didn't dye
-#define CHARACTERISTIC_CHAT_HITNODEATH 32 //float [0, 1]
-//tendency to chat when bot hit the enemy but enemy didn't dye
-#define CHARACTERISTIC_CHAT_HITNOKILL 33 //float [0, 1]
-//tendency to randomly chat
-#define CHARACTERISTIC_CHAT_RANDOM 34 //float [0, 1]
-//tendency to reply
-#define CHARACTERISTIC_CHAT_REPLY 35 //float [0, 1]
-//========================================================
-//movement
-//========================================================
-//tendency to crouch
-#define CHARACTERISTIC_CROUCHER 36 //float [0, 1]
-//tendency to jump
-#define CHARACTERISTIC_JUMPER 37 //float [0, 1]
-//tendency to walk
-#define CHARACTERISTIC_WALKER 48 //float [0, 1]
-//tendency to jump using a weapon
-#define CHARACTERISTIC_WEAPONJUMPING 38 //float [0, 1]
-//tendency to use the grapple hook when available
-#define CHARACTERISTIC_GRAPPLE_USER 39 //float [0, 1] //use this!!
-//========================================================
-//goal
-//========================================================
-//item weight file
-#define CHARACTERISTIC_ITEMWEIGHTS 40 //string
-//the aggression of the bot
-#define CHARACTERISTIC_AGGRESSION 41 //float [0, 1]
-//the self preservation of the bot (rockets near walls etc.)
-#define CHARACTERISTIC_SELFPRESERVATION 42 //float [0, 1]
-//how likely the bot is to take revenge
-#define CHARACTERISTIC_VENGEFULNESS 43 //float [0, 1] //use this!!
-//tendency to camp
-#define CHARACTERISTIC_CAMPER 44 //float [0, 1]
-//========================================================
-//========================================================
-//tendency to get easy frags
-#define CHARACTERISTIC_EASY_FRAGGER 45 //float [0, 1]
-//how alert the bot is (view distance)
-#define CHARACTERISTIC_ALERTNESS 46 //float [0, 1]
-//how much the bot fires it's weapon
-#define CHARACTERISTIC_FIRETHROTTLE 47 //float [0, 1]
-
diff --git a/game/code/game/g_active.c b/game/code/game/g_active.c
deleted file mode 100644
index c905261..0000000
--- a/game/code/game/g_active.c
+++ /dev/null
@@ -1,1376 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-#include "g_local.h"
-
-
-/*
-===============
-G_DamageFeedback
-
-Called just before a snapshot is sent to the given player.
-Totals up all damage and generates both the player_state_t
-damage values to that client for pain blends and kicks, and
-global pain sound events for all clients.
-===============
-*/
-void P_DamageFeedback( gentity_t *player ) {
- gclient_t *client;
- float count;
- vec3_t angles;
-
- client = player->client;
- if ( client->ps.pm_type == PM_DEAD ) {
- return;
- }
-
- // total points of damage shot at the player this frame
- count = client->damage_blood + client->damage_armor;
- if ( count == 0 ) {
- return; // didn't take any damage
- }
-
- if ( count > 255 ) {
- count = 255;
- }
-
- // send the information to the client
-
- // world damage (falling, slime, etc) uses a special code
- // to make the blend blob centered instead of positional
- if ( client->damage_fromWorld ) {
- client->ps.damagePitch = 255;
- client->ps.damageYaw = 255;
-
- client->damage_fromWorld = qfalse;
- } else {
- vectoangles( client->damage_from, angles );
- client->ps.damagePitch = angles[PITCH]/360.0 * 256;
- client->ps.damageYaw = angles[YAW]/360.0 * 256;
- }
-
- // play an apropriate pain sound
- if ( (level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) ) {
- player->pain_debounce_time = level.time + 700;
- G_AddEvent( player, EV_PAIN, player->health );
- client->ps.damageEvent++;
- }
-
-
- client->ps.damageCount = count;
-
- //
- // clear totals
- //
- client->damage_blood = 0;
- client->damage_armor = 0;
- client->damage_knockback = 0;
-}
-
-
-
-/*
-=============
-P_WorldEffects
-
-Check for lava / slime contents and drowning
-=============
-*/
-void P_WorldEffects( gentity_t *ent ) {
- qboolean envirosuit;
- int waterlevel;
-
- if ( ent->client->noclip ) {
- ent->client->airOutTime = level.time + 12000; // don't need air
- return;
- }
-
- waterlevel = ent->waterlevel;
-
- envirosuit = ent->client->ps.powerups[PW_BATTLESUIT] > level.time;
-
- //
- // check for drowning
- //
- if ( waterlevel == 3 ) {
- // envirosuit give air
- if ( envirosuit ) {
- ent->client->airOutTime = level.time + 10000;
- }
-
- // if out of air, start drowning
- if ( ent->client->airOutTime < level.time) {
- // drown!
- ent->client->airOutTime += 1000;
- if ( ent->health > 0 ) {
- // take more damage the longer underwater
- ent->damage += 2;
- if (ent->damage > 15)
- ent->damage = 15;
-
- // play a gurp sound instead of a normal pain sound
- if (ent->health <= ent->damage) {
- G_Sound(ent, CHAN_VOICE, G_SoundIndex("*drown.wav"));
- } else if (rand()&1) {
- G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp1.wav"));
- } else {
- G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp2.wav"));
- }
-
- // don't play a normal pain sound
- ent->pain_debounce_time = level.time + 200;
-
- G_Damage (ent, NULL, NULL, NULL, NULL,
- ent->damage, DAMAGE_NO_ARMOR, MOD_WATER);
- }
- }
- } else {
- ent->client->airOutTime = level.time + 12000;
- ent->damage = 2;
- }
-
- //
- // check for sizzle damage (move to pmove?)
- //
- if (waterlevel &&
- (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) {
- if (ent->health > 0
- && ent->pain_debounce_time <= level.time ) {
-
- if ( envirosuit ) {
- G_AddEvent( ent, EV_POWERUP_BATTLESUIT, 0 );
- } else {
- if (ent->watertype & CONTENTS_LAVA) {
- G_Damage (ent, NULL, NULL, NULL, NULL,
- 30*waterlevel, 0, MOD_LAVA);
- }
-
- if (ent->watertype & CONTENTS_SLIME) {
- G_Damage (ent, NULL, NULL, NULL, NULL,
- 10*waterlevel, 0, MOD_SLIME);
- }
- }
- }
- }
-}
-
-
-
-/*
-===============
-G_SetClientSound
-===============
-*/
-void G_SetClientSound( gentity_t *ent ) {
- if( ent->s.eFlags & EF_TICKING ) {
- ent->client->ps.loopSound = G_SoundIndex( "sound/weapons/proxmine/wstbtick.wav");
- }
- else
- if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) {
- ent->client->ps.loopSound = level.snd_fry;
- } else {
- ent->client->ps.loopSound = 0;
- }
-}
-
-
-
-//==============================================================
-
-/*
-==============
-ClientImpacts
-==============
-*/
-void ClientImpacts( gentity_t *ent, pmove_t *pm ) {
- int i, j;
- trace_t trace;
- gentity_t *other;
-
- memset( &trace, 0, sizeof( trace ) );
- for (i=0 ; i<pm->numtouch ; i++) {
- for (j=0 ; j<i ; j++) {
- if (pm->touchents[j] == pm->touchents[i] ) {
- break;
- }
- }
- if (j != i) {
- continue; // duplicated
- }
- other = &g_entities[ pm->touchents[i] ];
-
- if ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) {
- ent->touch( ent, other, &trace );
- }
-
- if ( !other->touch ) {
- continue;
- }
-
- other->touch( other, ent, &trace );
- }
-
-}
-
-/*
-============
-G_TouchTriggers
-
-Find all trigger entities that ent's current position touches.
-Spectators will only interact with teleporters.
-============
-*/
-void G_TouchTriggers( gentity_t *ent ) {
- int i, num;
- int touch[MAX_GENTITIES];
- gentity_t *hit;
- trace_t trace;
- vec3_t mins, maxs;
- static vec3_t range = { 40, 40, 52 };
-
- if ( !ent->client ) {
- return;
- }
-
- //ELIMINATION LMS
- // dead clients don't activate triggers! The reason our pm_spectators can't do anything
- if ( ent->client->ps.stats[STAT_HEALTH] <= 0 && ent->client->ps.pm_type != PM_SPECTATOR) {
- return;
- }
-
- VectorSubtract( ent->client->ps.origin, range, mins );
- VectorAdd( ent->client->ps.origin, range, maxs );
-
- num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
-
- // can't use ent->absmin, because that has a one unit pad
- VectorAdd( ent->client->ps.origin, ent->r.mins, mins );
- VectorAdd( ent->client->ps.origin, ent->r.maxs, maxs );
-
- for ( i=0 ; i<num ; i++ ) {
- hit = &g_entities[touch[i]];
-
- if ( !hit->touch && !ent->touch ) {
- continue;
- }
- if ( !( hit->r.contents & CONTENTS_TRIGGER ) ) {
- continue;
- }
-
- // ignore most entities if a spectator
- if ( (ent->client->sess.sessionTeam == TEAM_SPECTATOR) || ent->client->ps.pm_type == PM_SPECTATOR ) {
- if ( hit->s.eType != ET_TELEPORT_TRIGGER &&
- // this is ugly but adding a new ET_? type will
- // most likely cause network incompatibilities
- //We need to stop eliminated players from opening doors somewhere else /Sago007 20070814
- hit->touch != Touch_DoorTrigger ) {
- continue;
- }
- }
-
- // use seperate code for determining if an item is picked up
- // so you don't have to actually contact its bounding box
- if ( hit->s.eType == ET_ITEM ) {
- if ( !BG_PlayerTouchesItem( &ent->client->ps, &hit->s, level.time ) ) {
- continue;
- }
- } else {
- if ( !trap_EntityContact( mins, maxs, hit ) ) {
- continue;
- }
- }
-
- memset( &trace, 0, sizeof(trace) );
-
- if ( hit->touch ) {
- hit->touch (hit, ent, &trace);
- }
-
- if ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) {
- ent->touch( ent, hit, &trace );
- }
- }
-
- // if we didn't touch a jump pad this pmove frame
- if ( ent->client->ps.jumppad_frame != ent->client->ps.pmove_framecount ) {
- ent->client->ps.jumppad_frame = 0;
- ent->client->ps.jumppad_ent = 0;
- }
-}
-
-/*
-=================
-SpectatorThink
-=================
-*/
-void SpectatorThink( gentity_t *ent, usercmd_t *ucmd ) {
- pmove_t pm;
- gclient_t *client;
-
- client = ent->client;
-
- if ( ( g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) &&
- client->sess.spectatorState != SPECTATOR_FOLLOW &&
- g_elimination_lockspectator.integer>1 &&
- ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- Cmd_FollowCycle_f(ent);
- }
-
- if ( client->sess.spectatorState != SPECTATOR_FOLLOW ) {
- client->ps.pm_type = PM_SPECTATOR;
- client->ps.speed = 400; // faster than normal
-
- // set up for pmove
- memset (&pm, 0, sizeof(pm));
- pm.ps = &client->ps;
- pm.cmd = *ucmd;
- pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; // spectators can fly through bodies
- pm.trace = trap_Trace;
- pm.pointcontents = trap_PointContents;
-
- // perform a pmove
- Pmove (&pm);
- // save results of pmove
- VectorCopy( client->ps.origin, ent->s.origin );
-
- G_TouchTriggers( ent );
- trap_UnlinkEntity( ent );
- }
-
- /* Stopped players from going into follow mode in B5, should be fixed in B9
- if(ent->client->sess.sessionTeam != TEAM_SPECTATOR && g_gametype.integer>=GT_ELIMINATION && g_gametype.integer<=GT_LMS)
- return;
- */
-
- client->oldbuttons = client->buttons;
- client->buttons = ucmd->buttons;
-
- //KK-OAX Changed to keep followcycle functional
- // attack button cycles through spectators
- if ( ( client->buttons & BUTTON_ATTACK ) && ! ( client->oldbuttons & BUTTON_ATTACK ) ) {
- Cmd_FollowCycle_f( ent );
- }
-
- if ( ( client->buttons & BUTTON_USE_HOLDABLE ) && ! ( client->oldbuttons & BUTTON_USE_HOLDABLE ) ) {
- if ( ( g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) &&
- g_elimination_lockspectator.integer>1 &&
- ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- return;
- }
- StopFollowing(ent);
- }
-}
-
-
-
-/*
-=================
-ClientInactivityTimer
-
-Returns qfalse if the client is dropped
-=================
-*/
-qboolean ClientInactivityTimer( gclient_t *client ) {
- if ( ! g_inactivity.integer ) {
- // give everyone some time, so if the operator sets g_inactivity during
- // gameplay, everyone isn't kicked
- client->inactivityTime = level.time + 60 * 1000;
- client->inactivityWarning = qfalse;
- } else if ( client->pers.cmd.forwardmove ||
- client->pers.cmd.rightmove ||
- client->pers.cmd.upmove ||
- (client->pers.cmd.buttons & BUTTON_ATTACK) ) {
- client->inactivityTime = level.time + g_inactivity.integer * 1000;
- client->inactivityWarning = qfalse;
- } else if ( !client->pers.localClient ) {
- if ( level.time > client->inactivityTime ) {
- trap_DropClient( client - level.clients, "Dropped due to inactivity" );
- return qfalse;
- }
- if ( level.time > client->inactivityTime - 10000 && !client->inactivityWarning ) {
- client->inactivityWarning = qtrue;
- trap_SendServerCommand( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" );
- }
- }
- return qtrue;
-}
-
-/*
-==================
-ClientTimerActions
-
-Actions that happen once a second
-==================
-*/
-void ClientTimerActions( gentity_t *ent, int msec ) {
- gclient_t *client;
- int maxHealth;
-
- client = ent->client;
- client->timeResidual += msec;
-
- while ( client->timeResidual >= 1000 ) {
- client->timeResidual -= 1000;
-
- //Stop in elimination!!!
- if (client->ps.pm_flags & PMF_ELIMWARMUP)
- continue;
-
- // regenerate
- if( bg_itemlist[client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
- maxHealth = client->ps.stats[STAT_MAX_HEALTH] / 2;
- }
- else if ( client->ps.powerups[PW_REGEN] ) {
- maxHealth = client->ps.stats[STAT_MAX_HEALTH];
- }
- else {
- maxHealth = 0;
- }
- if( maxHealth ) {
- if ( ent->health < maxHealth ) {
- ent->health += 15;
- if ( ent->health > maxHealth * 1.1 ) {
- ent->health = maxHealth * 1.1;
- }
- G_AddEvent( ent, EV_POWERUP_REGEN, 0 );
- } else if ( ent->health < maxHealth * 2) {
- ent->health += 5;
- if ( ent->health > maxHealth * 2 ) {
- ent->health = maxHealth * 2;
- }
- G_AddEvent( ent, EV_POWERUP_REGEN, 0 );
- }
- } else {
- // count down health when over max
- if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] ) {
- ent->health--;
- }
- //Start killing players in LMS, if we are in overtime
- if(g_gametype.integer==GT_LMS && TeamHealthCount( -1, TEAM_FREE ) != ent->health &&(level.roundNumber==level.roundNumberStarted)&&(level.time>=level.roundStartTime+1000*g_elimination_roundtime.integer)) {
- ent->damage=5;
- G_Damage (ent, NULL, NULL, NULL, NULL,
- ent->damage, DAMAGE_NO_ARMOR, MOD_UNKNOWN);
- }
- else
- if ( ent->health < client->ps.stats[STAT_MAX_HEALTH] ) {
- ent->health+=g_regen.integer;
- if(ent->health>client->ps.stats[STAT_MAX_HEALTH])
- ent->health= client->ps.stats[STAT_MAX_HEALTH];
- }
- }
-
- // count down armor when over max
- if ( client->ps.stats[STAT_ARMOR] > client->ps.stats[STAT_MAX_HEALTH] ) {
- client->ps.stats[STAT_ARMOR]--;
- }
- }
- if( bg_itemlist[client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
- int w, max, inc, t, i;
- int weapList[]={WP_MACHINEGUN,WP_SHOTGUN,WP_GRENADE_LAUNCHER,WP_ROCKET_LAUNCHER,WP_LIGHTNING,WP_RAILGUN,WP_PLASMAGUN,WP_BFG,WP_NAILGUN,WP_PROX_LAUNCHER,WP_CHAINGUN};
- int weapCount = sizeof(weapList) / sizeof(int);
- //
- for (i = 0; i < weapCount; i++) {
- w = weapList[i];
-
- switch(w) {
- case WP_MACHINEGUN: max = 50; inc = 4; t = 1000; break;
- case WP_SHOTGUN: max = 10; inc = 1; t = 1500; break;
- case WP_GRENADE_LAUNCHER: max = 10; inc = 1; t = 2000; break;
- case WP_ROCKET_LAUNCHER: max = 10; inc = 1; t = 1750; break;
- case WP_LIGHTNING: max = 50; inc = 5; t = 1500; break;
- case WP_RAILGUN: max = 10; inc = 1; t = 1750; break;
- case WP_PLASMAGUN: max = 50; inc = 5; t = 1500; break;
- case WP_BFG: max = 10; inc = 1; t = 4000; break;
- case WP_NAILGUN: max = 10; inc = 1; t = 1250; break;
- case WP_PROX_LAUNCHER: max = 5; inc = 1; t = 2000; break;
- case WP_CHAINGUN: max = 100; inc = 5; t = 1000; break;
- default: max = 0; inc = 0; t = 1000; break;
- }
- client->ammoTimes[w] += msec;
- if ( client->ps.ammo[w] >= max ) {
- client->ammoTimes[w] = 0;
- }
- if ( client->ammoTimes[w] >= t ) {
- while ( client->ammoTimes[w] >= t )
- client->ammoTimes[w] -= t;
- client->ps.ammo[w] += inc;
- if ( client->ps.ammo[w] > max ) {
- client->ps.ammo[w] = max;
- }
- }
- }
- }
-}
-
-/*
-====================
-ClientIntermissionThink
-====================
-*/
-void ClientIntermissionThink( gclient_t *client ) {
- client->ps.eFlags &= ~EF_TALK;
- client->ps.eFlags &= ~EF_FIRING;
-
- // the level will exit when everyone wants to or after timeouts
-
- if( g_entities[client->ps.clientNum].r.svFlags & SVF_BOT )
- return; //Bots cannot mark themself as ready
-
- // swap and latch button actions
- client->oldbuttons = client->buttons;
- client->buttons = client->pers.cmd.buttons;
- if ( client->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) & ( client->oldbuttons ^ client->buttons ) ) {
- // this used to be an ^1 but once a player says ready, it should stick
- client->readyToExit = 1;
- }
-}
-
-
-/*
-================
-ClientEvents
-
-Events will be passed on to the clients for presentation,
-but any server game effects are handled here
-================
-*/
-void ClientEvents( gentity_t *ent, int oldEventSequence ) {
- int i, j;
- int event;
- gclient_t *client;
- int damage;
- vec3_t dir;
- vec3_t origin, angles;
-// qboolean fired;
- gitem_t *item;
- gentity_t *drop;
-
- client = ent->client;
-
- if ( oldEventSequence < client->ps.eventSequence - MAX_PS_EVENTS ) {
- oldEventSequence = client->ps.eventSequence - MAX_PS_EVENTS;
- }
- for ( i = oldEventSequence ; i < client->ps.eventSequence ; i++ ) {
- event = client->ps.events[ i & (MAX_PS_EVENTS-1) ];
-
- switch ( event ) {
- case EV_FALL_MEDIUM:
- case EV_FALL_FAR:
- if ( ent->s.eType != ET_PLAYER ) {
- break; // not in the player model
- }
- if ( g_dmflags.integer & DF_NO_FALLING ) {
- break;
- }
- if ( event == EV_FALL_FAR ) {
- damage = 10;
- } else {
- damage = 5;
- }
- VectorSet (dir, 0, 0, 1);
- ent->pain_debounce_time = level.time + 200; // no normal pain sound
- G_Damage (ent, NULL, NULL, NULL, NULL, damage, 0, MOD_FALLING);
- break;
-
- case EV_FIRE_WEAPON:
- FireWeapon( ent );
- break;
-
- case EV_USE_ITEM1: // teleporter
- // drop flags in CTF
- item = NULL;
- j = 0;
-
- if ( ent->client->ps.powerups[ PW_REDFLAG ] ) {
- item = BG_FindItemForPowerup( PW_REDFLAG );
- j = PW_REDFLAG;
- } else if ( ent->client->ps.powerups[ PW_BLUEFLAG ] ) {
- item = BG_FindItemForPowerup( PW_BLUEFLAG );
- j = PW_BLUEFLAG;
- } else if ( ent->client->ps.powerups[ PW_NEUTRALFLAG ] ) {
- item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
- j = PW_NEUTRALFLAG;
- }
-
- if ( item ) {
- drop = Drop_Item( ent, item, 0 );
- // decide how many seconds it has left
- drop->count = ( ent->client->ps.powerups[ j ] - level.time ) / 1000;
- if ( drop->count < 1 ) {
- drop->count = 1;
- }
-
- ent->client->ps.powerups[ j ] = 0;
- }
-
- if ( g_gametype.integer == GT_HARVESTER ) {
- if ( ent->client->ps.generic1 > 0 ) {
- if ( ent->client->sess.sessionTeam == TEAM_RED ) {
- item = BG_FindItem( "Blue Cube" );
- } else {
- item = BG_FindItem( "Red Cube" );
- }
- if ( item ) {
- for ( j = 0; j < ent->client->ps.generic1; j++ ) {
- drop = Drop_Item( ent, item, 0 );
- if ( ent->client->sess.sessionTeam == TEAM_RED ) {
- drop->spawnflags = TEAM_BLUE;
- } else {
- drop->spawnflags = TEAM_RED;
- }
- }
- }
- ent->client->ps.generic1 = 0;
- }
- }
- SelectSpawnPoint( ent->client->ps.origin, origin, angles );
- TeleportPlayer( ent, origin, angles );
- break;
-
- case EV_USE_ITEM2: // medkit
- ent->health = ent->client->ps.stats[STAT_MAX_HEALTH] + 25;
-
- break;
-
- case EV_USE_ITEM3: // kamikaze
- // make sure the invulnerability is off
- ent->client->invulnerabilityTime = 0;
- // start the kamikze
- G_StartKamikaze( ent );
- break;
-
- case EV_USE_ITEM4: // portal
- if( ent->client->portalID ) {
- DropPortalSource( ent );
- }
- else {
- DropPortalDestination( ent );
- }
- break;
- case EV_USE_ITEM5: // invulnerability
- ent->client->invulnerabilityTime = level.time + 10000;
- break;
-
- default:
- break;
- }
- }
-
-}
-
-/*
-==============
-StuckInOtherClient
-==============
-*/
-static int StuckInOtherClient(gentity_t *ent) {
- int i;
- gentity_t *ent2;
-
- ent2 = &g_entities[0];
- for ( i = 0; i < MAX_CLIENTS; i++, ent2++ ) {
- if ( ent2 == ent ) {
- continue;
- }
- if ( !ent2->inuse ) {
- continue;
- }
- if ( !ent2->client ) {
- continue;
- }
- if ( ent2->health <= 0 ) {
- continue;
- }
- //
- if (ent2->r.absmin[0] > ent->r.absmax[0])
- continue;
- if (ent2->r.absmin[1] > ent->r.absmax[1])
- continue;
- if (ent2->r.absmin[2] > ent->r.absmax[2])
- continue;
- if (ent2->r.absmax[0] < ent->r.absmin[0])
- continue;
- if (ent2->r.absmax[1] < ent->r.absmin[1])
- continue;
- if (ent2->r.absmax[2] < ent->r.absmin[2])
- continue;
- return qtrue;
- }
- return qfalse;
-}
-
-void BotTestSolid(vec3_t origin);
-
-/*
-==============
-SendPendingPredictableEvents
-==============
-*/
-void SendPendingPredictableEvents( playerState_t *ps ) {
- gentity_t *t;
- int event, seq;
- int extEvent, number;
-
- // if there are still events pending
- if ( ps->entityEventSequence < ps->eventSequence ) {
- // create a temporary entity for this event which is sent to everyone
- // except the client who generated the event
- seq = ps->entityEventSequence & (MAX_PS_EVENTS-1);
- event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );
- // set external event to zero before calling BG_PlayerStateToEntityState
- extEvent = ps->externalEvent;
- ps->externalEvent = 0;
- // create temporary entity for event
- t = G_TempEntity( ps->origin, event );
- number = t->s.number;
- BG_PlayerStateToEntityState( ps, &t->s, qtrue );
- t->s.number = number;
- t->s.eType = ET_EVENTS + event;
- t->s.eFlags |= EF_PLAYER_EVENT;
- t->s.otherEntityNum = ps->clientNum;
- // send to everyone except the client who generated the event
- t->r.svFlags |= SVF_NOTSINGLECLIENT;
- t->r.singleClient = ps->clientNum;
- // set back external event
- ps->externalEvent = extEvent;
- }
-}
-
-/*
-==============
-ClientThink
-
-This will be called once for each client frame, which will
-usually be a couple times for each server frame on fast clients.
-
-If "g_synchronousClients 1" is set, this will be called exactly
-once for each server frame, which makes for smooth demo recording.
-==============
-*/
-void ClientThink_real( gentity_t *ent ) {
- gclient_t *client;
- pmove_t pm;
- int oldEventSequence;
- int msec;
- usercmd_t *ucmd;
-
- client = ent->client;
-
- // don't think if the client is not yet connected (and thus not yet spawned in)
- if (client->pers.connected != CON_CONNECTED) {
- return;
- }
- // mark the time, so the connection sprite can be removed
- ucmd = &ent->client->pers.cmd;
-
- // sanity check the command time to prevent speedup cheating
- if ( ucmd->serverTime > level.time + 200 ) {
- ucmd->serverTime = level.time + 200;
-// G_Printf("serverTime <<<<<\n" );
- }
- if ( ucmd->serverTime < level.time - 1000 ) {
- ucmd->serverTime = level.time - 1000;
-// G_Printf("serverTime >>>>>\n" );
- }
-
-//Here comes the unlagged bit!
-//unlagged - backward reconciliation #4
- // frameOffset should be about the number of milliseconds into a frame
- // this command packet was received, depending on how fast the server
- // does a G_RunFrame()
- client->frameOffset = trap_Milliseconds() - level.frameStartTime;
-//unlagged - backward reconciliation #4
-
-
-//unlagged - lag simulation #3
- // if the client wants to simulate outgoing packet loss
-/* if ( client->pers.plOut ) {
- // see if a random value is below the threshhold
- float thresh = (float)client->pers.plOut / 100.0f;
- if ( random() < thresh ) {
- // do nothing at all if it is - this is a lost command
- return;
- }
- }*/
-//unlagged - lag simulation #3
-
-
-//unlagged - true ping
- // save the estimated ping in a queue for averaging later
-
- // we use level.previousTime to account for 50ms lag correction
- // besides, this will turn out numbers more like what players are used to
- client->pers.pingsamples[client->pers.samplehead] = level.previousTime + client->frameOffset - ucmd->serverTime;
- client->pers.samplehead++;
- if ( client->pers.samplehead >= NUM_PING_SAMPLES ) {
- client->pers.samplehead -= NUM_PING_SAMPLES;
- }
-
- // initialize the real ping
- if ( g_truePing.integer ) {
- int i, sum = 0;
-
- // get an average of the samples we saved up
- for ( i = 0; i < NUM_PING_SAMPLES; i++ ) {
- sum += client->pers.pingsamples[i];
- }
-
- client->pers.realPing = sum / NUM_PING_SAMPLES;
- }
- else {
- // if g_truePing is off, use the normal ping
- client->pers.realPing = client->ps.ping;
- }
-//unlagged - true ping
-
-
-//unlagged - lag simulation #2
- // keep a queue of past commands
-/* client->pers.cmdqueue[client->pers.cmdhead] = client->pers.cmd;
- client->pers.cmdhead++;
- if ( client->pers.cmdhead >= MAX_LATENT_CMDS ) {
- client->pers.cmdhead -= MAX_LATENT_CMDS;
- }
-
- // if the client wants latency in commands (client-to-server latency)
- if ( client->pers.latentCmds ) {
- // save the actual command time
- int time = ucmd->serverTime;
-
- // find out which index in the queue we want
- int cmdindex = client->pers.cmdhead - client->pers.latentCmds - 1;
- while ( cmdindex < 0 ) {
- cmdindex += MAX_LATENT_CMDS;
- }
-
- // read in the old command
- client->pers.cmd = client->pers.cmdqueue[cmdindex];
-
- // adjust the real ping to reflect the new latency
- client->pers.realPing += time - ucmd->serverTime;
- }*/
-//unlagged - lag simulation #2
-
-
-//unlagged - backward reconciliation #4
- // save the command time *before* pmove_fixed messes with the serverTime,
- // and *after* lag simulation messes with it :)
- // attackTime will be used for backward reconciliation later (time shift)
- client->attackTime = ucmd->serverTime;
-//unlagged - backward reconciliation #4
-
-
-//unlagged - smooth clients #1
- // keep track of this for later - we'll use this to decide whether or not
- // to send extrapolated positions for this client
- client->lastUpdateFrame = level.framenum;
-//unlagged - smooth clients #1
-
-
-//unlagged - lag simulation #1
- // if the client is adding latency to received snapshots (server-to-client latency)
- /*if ( client->pers.latentSnaps ) {
- // adjust the real ping
- client->pers.realPing += client->pers.latentSnaps * (1000 / sv_fps.integer);
- // adjust the attack time so backward reconciliation will work
- client->attackTime -= client->pers.latentSnaps * (1000 / sv_fps.integer);
- }*/
-//unlagged - lag simulation #1
-
-
-//unlagged - true ping
- // make sure the true ping is over 0 - with cl_timenudge it can be less
- if ( client->pers.realPing < 0 ) {
- client->pers.realPing = 0;
- }
-//unlagged - true ping
-
- msec = ucmd->serverTime - client->ps.commandTime;
- // following others may result in bad times, but we still want
- // to check for follow toggles
- if ( msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW ) {
- return;
- }
- if ( msec > 200 ) {
- msec = 200;
- }
-
- if ( pmove_msec.integer < 8 ) {
- trap_Cvar_Set("pmove_msec", "8");
- }
- else if (pmove_msec.integer > 33) {
- trap_Cvar_Set("pmove_msec", "33");
- }
-
- if ( pmove_fixed.integer || client->pers.pmoveFixed ) {
- ucmd->serverTime = ((ucmd->serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;
- //if (ucmd->serverTime - client->ps.commandTime <= 0)
- // return;
- }
-
- //
- // check for exiting intermission
- //
- if ( level.intermissiontime ) {
- ClientIntermissionThink( client );
- return;
- }
-
- // spectators don't do much
- if ( (client->sess.sessionTeam == TEAM_SPECTATOR) || client->isEliminated ) {
- if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
- return;
- }
- SpectatorThink( ent, ucmd );
- return;
- }
-
- // check for inactivity timer, but never drop the local client of a non-dedicated server
- if ( !ClientInactivityTimer( client ) ) {
- return;
- }
-
- // clear the rewards if time
- if ( level.time > client->rewardTime ) {
- client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- }
-
- if ( client->noclip ) {
- client->ps.pm_type = PM_NOCLIP;
- } else if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
- client->ps.pm_type = PM_DEAD;
- } else {
- client->ps.pm_type = PM_NORMAL;
- }
-
- client->ps.gravity = g_gravity.value;
-
- // set speed
- client->ps.speed = g_speed.value;
-
- if( bg_itemlist[client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
- client->ps.speed *= 1.5;
- }
- else
- if ( client->ps.powerups[PW_HASTE] ) {
- client->ps.speed *= 1.3;
- }
-
- // Let go of the hook if we aren't firing
- if ( client->ps.weapon == WP_GRAPPLING_HOOK &&
- client->hook && !( ucmd->buttons & BUTTON_ATTACK ) ) {
- Weapon_HookFree(client->hook);
- }
-
- // set up for pmove
- oldEventSequence = client->ps.eventSequence;
-
- memset (&pm, 0, sizeof(pm));
-
- // check for the hit-scan gauntlet, don't let the action
- // go through as an attack unless it actually hits something
- if ( client->ps.weapon == WP_GAUNTLET && !( ucmd->buttons & BUTTON_TALK ) &&
- ( ucmd->buttons & BUTTON_ATTACK ) && client->ps.weaponTime <= 0 ) {
- pm.gauntletHit = CheckGauntletAttack( ent );
- }
-
- if ( ent->flags & FL_FORCE_GESTURE ) {
- ent->flags &= ~FL_FORCE_GESTURE;
- ent->client->pers.cmd.buttons |= BUTTON_GESTURE;
- }
-
- // check for invulnerability expansion before doing the Pmove
- if (client->ps.powerups[PW_INVULNERABILITY] ) {
- if ( !(client->ps.pm_flags & PMF_INVULEXPAND) ) {
- vec3_t mins = { -42, -42, -42 };
- vec3_t maxs = { 42, 42, 42 };
- vec3_t oldmins, oldmaxs;
-
- VectorCopy (ent->r.mins, oldmins);
- VectorCopy (ent->r.maxs, oldmaxs);
- // expand
- VectorCopy (mins, ent->r.mins);
- VectorCopy (maxs, ent->r.maxs);
- trap_LinkEntity(ent);
- // check if this would get anyone stuck in this player
- if ( !StuckInOtherClient(ent) ) {
- // set flag so the expanded size will be set in PM_CheckDuck
- client->ps.pm_flags |= PMF_INVULEXPAND;
- }
- // set back
- VectorCopy (oldmins, ent->r.mins);
- VectorCopy (oldmaxs, ent->r.maxs);
- trap_LinkEntity(ent);
- }
- }
-
- pm.ps = &client->ps;
- pm.cmd = *ucmd;
- if ( pm.ps->pm_type == PM_DEAD ) {
- pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
- }
- else if ( ent->r.svFlags & SVF_BOT ) {
- pm.tracemask = MASK_PLAYERSOLID | CONTENTS_BOTCLIP;
- }
- else {
- pm.tracemask = MASK_PLAYERSOLID;
- }
- pm.trace = trap_Trace;
- pm.pointcontents = trap_PointContents;
- pm.debugLevel = g_debugMove.integer;
- pm.noFootsteps = ( g_dmflags.integer & DF_NO_FOOTSTEPS ) > 0;
-
- pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed;
- pm.pmove_msec = pmove_msec.integer;
- pm.pmove_float = pmove_float.integer;
-
- VectorCopy( client->ps.origin, client->oldOrigin );
-
- #ifdef MISSIONPACK
- if (level.intermissionQueued != 0 && g_singlePlayer.integer) {
- if ( level.time - level.intermissionQueued >= 1000 ) {
- pm.cmd.buttons = 0;
- pm.cmd.forwardmove = 0;
- pm.cmd.rightmove = 0;
- pm.cmd.upmove = 0;
- if ( level.time - level.intermissionQueued >= 2000 && level.time - level.intermissionQueued <= 2500 ) {
- trap_SendConsoleCommand( EXEC_APPEND, "centerview\n");
- }
- ent->client->ps.pm_type = PM_SPINTERMISSION;
- }
- }
- #endif
- Pmove (&pm);
-
- // save results of pmove
- if ( ent->client->ps.eventSequence != oldEventSequence ) {
- ent->eventTime = level.time;
- }
-//unlagged - smooth clients #2
- // clients no longer do extrapolation if cg_smoothClients is 1, because
- // skip correction is all handled server-side now
- // since that's the case, it makes no sense to store the extra info
- // in the client's snapshot entity, so let's save a little bandwidth
-/*
- if (g_smoothClients.integer) {
- BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
- }
- else {
-*/
- BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
-// }
-//unlagged - smooth clients #2
- SendPendingPredictableEvents( &ent->client->ps );
-
- if ( !( ent->client->ps.eFlags & EF_FIRING ) ) {
- client->fireHeld = qfalse; // for grapple
- }
-
- // use the snapped origin for linking so it matches client predicted versions
- VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );
-
- VectorCopy (pm.mins, ent->r.mins);
- VectorCopy (pm.maxs, ent->r.maxs);
-
- ent->waterlevel = pm.waterlevel;
- ent->watertype = pm.watertype;
-
- // execute client events
- ClientEvents( ent, oldEventSequence );
-
- // link entity now, after any personal teleporters have been used
- trap_LinkEntity (ent);
- if ( !ent->client->noclip ) {
- G_TouchTriggers( ent );
- }
-
- // NOTE: now copy the exact origin over otherwise clients can be snapped into solid
- VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
-
- //test for solid areas in the AAS file
- BotTestAAS(ent->r.currentOrigin);
-
- // touch other objects
- ClientImpacts( ent, &pm );
-
- // save results of triggers and client events
- if (ent->client->ps.eventSequence != oldEventSequence) {
- ent->eventTime = level.time;
- }
-
- // swap and latch button actions
- client->oldbuttons = client->buttons;
- client->buttons = ucmd->buttons;
- client->latched_buttons |= client->buttons & ~client->oldbuttons;
-
- // check for respawning
- if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
- // wait for the attack button to be pressed
- // forcerespawn is to prevent users from waiting out powerups
- // In Last man standing, we force a quick respawn, since
- // the player must be able to loose health
- // pressing attack or use is the normal respawn method
- if ( ( level.time > client->respawnTime ) &&
- ( ( ( g_forcerespawn.integer > 0 ) &&
- ( level.time - client->respawnTime > g_forcerespawn.integer * 1000 ) ) ||
- ( ( ( g_gametype.integer == GT_LMS ) ||
- ( g_gametype.integer == GT_ELIMINATION ) ||
- ( g_gametype.integer == GT_CTF_ELIMINATION ) ) &&
- ( level.time - client->respawnTime > 0 ) ) ||
- ( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) ) ) {
-
- respawn( ent );
- }
- return;
- }
-
- if ( pm.waterlevel <= 1 && pm.ps->groundEntityNum!=ENTITYNUM_NONE && client->lastSentFlyingTime+500>level.time) {
- if ( ! (pm.ps->pm_flags & PMF_TIME_KNOCKBACK) ) {
- client->lastSentFlying = -1;
- }
- }
-
- // perform once-a-second actions
- ClientTimerActions( ent, msec );
-}
-
-/*
-==================
-ClientThink
-
-A new command has arrived from the client
-==================
-*/
-void ClientThink( int clientNum ) {
- gentity_t *ent;
-
- ent = g_entities + clientNum;
- trap_GetUsercmd( clientNum, &ent->client->pers.cmd );
-
- //Unlagged: commented out
- // mark the time we got info, so we can display the
- // phone jack if they don't get any for a while
- //ent->client->lastCmdTime = level.time;
-
- if ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) {
- ClientThink_real( ent );
- }
-}
-
-
-void G_RunClient( gentity_t *ent ) {
- if ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) {
- return;
- }
- ent->client->pers.cmd.serverTime = level.time;
- ClientThink_real( ent );
-}
-
-
-/*
-==================
-SpectatorClientEndFrame
-
-==================
-*/
-void SpectatorClientEndFrame( gentity_t *ent ) {
- gclient_t *cl;
- int i, preservedScore[MAX_PERSISTANT]; //for keeping in elimination
-
- // if we are doing a chase cam or a remote view, grab the latest info
- if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {
- int clientNum, flags;
-
- clientNum = ent->client->sess.spectatorClient;
-
- // team follow1 and team follow2 go to whatever clients are playing
- if ( clientNum == -1 ) {
- clientNum = level.follow1;
- } else if ( clientNum == -2 ) {
- clientNum = level.follow2;
- }
- if ( clientNum >= 0 ) {
- cl = &level.clients[ clientNum ];
- if ( cl->pers.connected == CON_CONNECTED && cl->sess.sessionTeam != TEAM_SPECTATOR ) {
- flags = (cl->ps.eFlags & ~(EF_VOTED | EF_TEAMVOTED)) | (ent->client->ps.eFlags & (EF_VOTED | EF_TEAMVOTED));
- //this is here LMS/Elimination goes wrong with player follow
- if(ent->client->sess.sessionTeam!=TEAM_SPECTATOR){
- for(i = 0; i < MAX_PERSISTANT; i++)
- preservedScore[i] = ent->client->ps.persistant[i];
- ent->client->ps = cl->ps;
- for(i = 0; i < MAX_PERSISTANT; i++)
- ent->client->ps.persistant[i] = preservedScore[i];
- }
- else
- ent->client->ps = cl->ps;
- ent->client->ps.pm_flags |= PMF_FOLLOW;
- ent->client->ps.eFlags = flags;
- return;
- } else {
- // drop them to free spectators unless they are dedicated camera followers
- if ( ent->client->sess.spectatorClient >= 0 ) {
- ent->client->sess.spectatorState = SPECTATOR_FREE;
- ClientBegin( ent->client - level.clients );
- }
- }
- }
-
-
-
- }
-
- if ( ent->client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
- ent->client->ps.pm_flags |= PMF_SCOREBOARD;
- } else {
- ent->client->ps.pm_flags &= ~PMF_SCOREBOARD;
- }
-}
-
-/*
-==============
-ClientEndFrame
-
-Called at the end of each server frame for each connected client
-A fast client will have multiple ClientThink for each ClientEdFrame,
-while a slow client may have multiple ClientEndFrame between ClientThink.
-==============
-*/
-void ClientEndFrame( gentity_t *ent ) {
- int i;
- clientPersistant_t *pers;
-
-//unlagged - smooth clients #1
- int frames;
-//unlagged - smooth clients #1
-
- if ( (ent->client->sess.sessionTeam == TEAM_SPECTATOR) || ent->client->isEliminated ) {
- SpectatorClientEndFrame( ent );
- return;
- }
-
- pers = &ent->client->pers;
-
- // turn off any expired powerups
- for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
- if ( ent->client->ps.powerups[ i ] < level.time ) {
- ent->client->ps.powerups[ i ] = 0;
- }
- }
-
- // set powerup for player animation
- if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
- ent->client->ps.powerups[PW_GUARD] = level.time;
- }
- if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
- ent->client->ps.powerups[PW_SCOUT] = level.time;
- }
- if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_DOUBLER ) {
- ent->client->ps.powerups[PW_DOUBLER] = level.time;
- }
- if( bg_itemlist[ent->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
- ent->client->ps.powerups[PW_AMMOREGEN] = level.time;
- }
- if ( ent->client->invulnerabilityTime > level.time ) {
- ent->client->ps.powerups[PW_INVULNERABILITY] = level.time;
- }
-
- // save network bandwidth
-#if 0
- if ( !g_synchronousClients->integer && ent->client->ps.pm_type == PM_NORMAL ) {
- // FIXME: this must change eventually for non-sync demo recording
- VectorClear( ent->client->ps.viewangles );
- }
-#endif
-
- //
- // If the end of unit layout is displayed, don't give
- // the player any normal movement attributes
- //
- if ( level.intermissiontime ) {
- return;
- }
-
- // burn from lava, etc
- P_WorldEffects (ent);
-
- // apply all the damage taken this frame
- P_DamageFeedback (ent);
-
- //Unlagged: Commented out
- // add the EF_CONNECTION flag if we haven't gotten commands recently
- /*if ( level.time - ent->client->lastCmdTime > 1000 ) {
- ent->s.eFlags |= EF_CONNECTION;
- } else {
- ent->s.eFlags &= ~EF_CONNECTION;
- }*/
-
- ent->client->ps.stats[STAT_HEALTH] = ent->health; // FIXME: get rid of ent->health...
-
- G_SetClientSound (ent);
-
-//Unlagged: Always do the else clause
- // set the latest infor
-/* if (g_smoothClients.integer) {
- BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
- }
- else { */
- BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
-// }
- SendPendingPredictableEvents( &ent->client->ps );
-
-//unlagged - smooth clients #1
- // mark as not missing updates initially
- ent->client->ps.eFlags &= ~EF_CONNECTION;
-
- // see how many frames the client has missed
- frames = level.framenum - ent->client->lastUpdateFrame - 1;
-
- // don't extrapolate more than two frames
- if ( frames > 2 ) {
- frames = 2;
-
- // if they missed more than two in a row, show the phone jack
- ent->client->ps.eFlags |= EF_CONNECTION;
- ent->s.eFlags |= EF_CONNECTION;
- }
-
- // did the client miss any frames?
- if ( frames > 0 && g_smoothClients.integer ) {
- // yep, missed one or more, so extrapolate the player's movement
- G_PredictPlayerMove( ent, (float)frames / sv_fps.integer );
- // save network bandwidth
- SnapVector( ent->s.pos.trBase );
- }
-//unlagged - smooth clients #1
-
-//unlagged - backward reconciliation #1
- // store the client's position for backward reconciliation later
- G_StoreHistory( ent );
-//unlagged - backward reconciliation #1
-
- // set the bit for the reachability area the client is currently in
-// i = trap_AAS_PointReachabilityAreaIndex( ent->client->ps.origin );
-// ent->client->areabits[i >> 3] |= 1 << (i & 7);
-}
-
-
diff --git a/game/code/game/g_admin.c b/game/code/game/g_admin.c
deleted file mode 100644
index 04f8008..0000000
--- a/game/code/game/g_admin.c
+++ /dev/null
@@ -1,3467 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 2004-2006 Tony J. White
-
-This file is part of the Open Arena source code.
-
-Originally copied from Tremulous under GPL version 2 including any later version.
-
-Several modifications, additions, and deletions were made by developers of the
-Open Arena source code.
-
-This shrubbot implementation is the original work of Tony J. White.
-
-Contains contributions from Wesley van Beelen, Chris Bajumpaa, Josh Menke,
-and Travis Maurer.
-
-The functionality of this code mimics the behaviour of the currently
-inactive project shrubet (http://www.etstats.com/shrubet/index.php?ver=2)
-by Ryan Mannion. However, shrubet was a closed-source project and
-none of it's code has been copied, only it's functionality.
-
-Open Arena Source code 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.
-
-Open Arena Source code 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 Open Arena Source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-/* KK-OAX TODO
-1. Clean up the default admin levels to include the commands which I have added
-3. Implement Disorientation in Code
-4. DEBUG, DEBUG, DEBUG
-*/
-
-#include "g_local.h"
-
-// big ugly global buffer for use with buffered printing of long outputs
-static char g_bfb[ 32000 ];
-
-// note: list ordered alphabetically
-g_admin_cmd_t g_admin_cmds[ ] =
- {
- {"adjustban", G_admin_adjustban, "b",
- "change the duration or reason of a ban. duration is specified as "
- "numbers followed by units 'w' (weeks), 'd' (days), 'h' (hours) or "
- "'m' (minutes), or seconds if no units are specified. if the duration is"
- " preceded by a + or -, the ban duration will be extended or shortened by"
- " the specified amount",
- "[^3ban#^7] (^5duration^7) (^5reason^7)"
- },
-
- {"admintest", G_admin_admintest, "a",
- "display your current admin level",
- ""
- },
-
- {"allready", G_admin_allready, "y",
- "makes everyone ready in intermission",
- ""
- },
-
- {"ban", G_admin_ban, "b",
- "ban a player by IP and GUID with an optional expiration time and reason."
- " duration is specified as numbers followed by units 'w' (weeks), 'd' "
- "(days), 'h' (hours) or 'm' (minutes), or seconds if no units are "
- "specified",
- "[^3name|slot#|IP^7] (^5duration^7) (^5reason^7)"
- },
-
- {"cancelvote", G_admin_cancelvote, "c",
- "cancel a vote taking place",
- ""
- },
- //KK-OAX
- {"disorient", G_admin_disorient, "d",
- "disorient a player by flipping player's view and controls",
- "[^3name|slot#^7] (^hreason^7)"
- },
- //{"fling", G_admin_fling, "d",
- // "throws the player specified",
- // "[^3name|slot#^7]"
- //},
-
- {"help", G_admin_help, "h",
- "display commands available to you or help on a specific command",
- "(^5command^7)"
- },
-
- {"kick", G_admin_kick, "k",
- "kick a player with an optional reason",
- "[^3name|slot#^7] (^5reason^7)"
- },
-
- {"listadmins", G_admin_listadmins, "D",
- "display a list of all server admins and their levels",
- "(^5name|start admin#^7)"
- },
-
- {"listplayers", G_admin_listplayers, "i",
- "display a list of players, their client numbers and their levels",
- ""
- },
-
- {"lock", G_admin_lock, "K",
- "lock a team to prevent anyone from joining it",
- "[^3a|h^7]"
- },
- //KK-OAX
- {"map", G_admin_map, "M",
- "load a map",
- "[^3mapname^7]"
- },
-
- {"mute", G_admin_mute, "m",
- "mute a player",
- "[^3name|slot#^7]"
- },
-
- {"namelog", G_admin_namelog, "e",
- "display a list of names used by recently connected players",
- "(^5name^7)"
- },
-
- {"nextmap", G_admin_nextmap, "n",
- "go to the next map in the cycle",
- ""
- },
- //KK-OAX
- {"orient", G_admin_orient, "d",
- "orient a player after a !disorient", "[^3name|slot#^7]"
- },
-
- {"passvote", G_admin_passvote, "V",
- "pass a vote currently taking place",
- ""
- },
-
- {"putteam", G_admin_putteam, "p",
- "move a player to a specified team",
- "[^3name|slot#^7] [^3h|a|s^7]"
- },
-
- {"readconfig", G_admin_readconfig, "G",
- "reloads the admin config file and refreshes permission flags",
- ""
- },
-
- {"rename", G_admin_rename, "N",
- "rename a player",
- "[^3name|slot#^7] [^3new name^7]"
- },
-
- {"restart", G_admin_restart, "r",
- "restart the current map (optionally using named layout)",
- ""
- },
-
- {"setlevel", G_admin_setlevel, "s",
- "sets the admin level of a player",
- "[^3name|slot#|admin#^7] [^3level^7]"
- },
-
- {"showbans", G_admin_showbans, "B",
- "display a (partial) list of active bans",
- "(^5start at ban#^7) (^5name|IP^7)"
- },
- //KK-OAX
- {"shuffle", G_admin_shuffle, "f",
- "Shuffles the teams"
- ""
- },
-
- {"slap", G_admin_slap, "S",
- "Reduces the health of the selected player by the damage specified",
- "[^3name|slot#] [damage] [reason]"
- },
-
- {"spec999", G_admin_spec999, "P",
- "move 999 pingers to the spectator team",
- ""},
-
- {"time", G_admin_time, "C",
- "show the current local server time",
- ""},
-
- {"unban", G_admin_unban, "b",
- "unbans a player specified by the slot as seen in showbans",
- "[^3ban#^7]"
- },
-
- {"unlock", G_admin_unlock, "K",
- "unlock a locked team",
- "[^3a|h^7]"
- },
-
- {"unmute", G_admin_mute, "m",
- "unmute a muted player",
- "[^3name|slot#^7]"
- },
-
-//KK-OAX
- {"warn", G_admin_warn, "w",
- "warn a player",
- "[^3name|slot#^7] [reason]"
- }
-
- };
-
-static int adminNumCmds = sizeof( g_admin_cmds ) / sizeof( g_admin_cmds[ 0 ] );
-
-static int admin_level_maxname = 0;
-g_admin_level_t *g_admin_levels[ MAX_ADMIN_LEVELS ];
-g_admin_admin_t *g_admin_admins[ MAX_ADMIN_ADMINS ];
-g_admin_ban_t *g_admin_bans[ MAX_ADMIN_BANS ];
-g_admin_command_t *g_admin_commands[ MAX_ADMIN_COMMANDS ];
-g_admin_namelog_t *g_admin_namelog[ MAX_ADMIN_NAMELOGS ];
-//KK-OAX Load us up some warnings here....
-g_admin_warning_t *g_admin_warnings[ MAX_ADMIN_WARNINGS ];
-
-qboolean G_admin_permission( gentity_t *ent, char flag )
-{
- int i;
- int l = 0;
- char *flags;
-
- // console always wins
- if( !ent )
- return qtrue;
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( !Q_stricmp( ent->client->pers.guid, g_admin_admins[ i ]->guid ) )
- {
- flags = g_admin_admins[ i ]->flags;
- while( *flags )
- {
- if( *flags == flag )
- return qtrue;
- else if( *flags == '-' )
- {
- while( *flags++ )
- {
- if( *flags == flag )
- return qfalse;
- if( *flags == '+' )
- break;
- }
- }
- else if( *flags == '*' )
- {
- while( *flags++ )
- {
- if( *flags == flag )
- return qfalse;
- }
- // flags with significance only for individuals (
- // like ADMF_INCOGNITO and ADMF_IMMUTABLE are NOT covered
- // by the '*' wildcard. They must be specified manually.
- return ( flag != ADMF_INCOGNITO && flag != ADMF_IMMUTABLE );
- }
- flags++;
- }
- l = g_admin_admins[ i ]->level;
- }
- }
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- if( g_admin_levels[ i ]->level == l )
- {
- flags = g_admin_levels[ i ]->flags;
- while( *flags )
- {
- if( *flags == flag )
- return qtrue;
- if( *flags == '*' )
- {
- while( *flags++ )
- {
- if( *flags == flag )
- return qfalse;
- }
- // flags with significance only for individuals (
- // like ADMF_INCOGNITO and ADMF_IMMUTABLE are NOT covered
- // by the '*' wildcard. They must be specified manually.
- return ( flag != ADMF_INCOGNITO && flag != ADMF_IMMUTABLE );
- }
- flags++;
- }
- }
- }
- return qfalse;
-}
-
-qboolean G_admin_name_check( gentity_t *ent, char *name, char *err, int len )
-{
- int i;
- gclient_t *client;
- char testName[ MAX_NAME_LENGTH ] = {""};
- char name2[ MAX_NAME_LENGTH ] = {""};
-
- G_SanitiseString( name, name2, sizeof( name2 ) );
-
- if( !Q_stricmp( name2, "UnnamedPlayer" ) )
- return qtrue;
-
- for( i = 0; i < level.maxclients; i++ )
- {
- client = &level.clients[ i ];
- if( client->pers.connected == CON_DISCONNECTED )
- continue;
-
- // can rename ones self to the same name using different colors
- if( i == ( ent - g_entities ) )
- continue;
-
- G_SanitiseString( client->pers.netname, testName, sizeof( testName ) );
- if( !Q_stricmp( name2, testName ) )
- {
- Com_sprintf( err, len, "The name '%s^7' is already in use", name );
- return qfalse;
- }
- }
-
- if( !g_adminNameProtect.integer )
- return qtrue;
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( g_admin_admins[ i ]->level < 1 )
- continue;
- G_SanitiseString( g_admin_admins[ i ]->name, testName, sizeof( testName ) );
- if( !Q_stricmp( name2, testName ) &&
- Q_stricmp( ent->client->pers.guid, g_admin_admins[ i ]->guid ) )
- {
- Com_sprintf( err, len, "The name '%s^7' belongs to an admin, "
- "please use another name", name );
- return qfalse;
- }
- }
- return qtrue;
-}
-
-static qboolean admin_higher_guid( char *admin_guid, char *victim_guid )
-{
- int i;
- int alevel = 0;
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( !Q_stricmp( admin_guid, g_admin_admins[ i ]->guid ) )
- {
- alevel = g_admin_admins[ i ]->level;
- break;
- }
- }
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( !Q_stricmp( victim_guid, g_admin_admins[ i ]->guid ) )
- {
- if( alevel < g_admin_admins[ i ]->level )
- return qfalse;
- return !strstr( g_admin_admins[ i ]->flags, va( "%c", ADMF_IMMUTABLE ) );
- }
- }
- return qtrue;
-}
-
-static qboolean admin_higher( gentity_t *admin, gentity_t *victim )
-{
-
- // console always wins
- if( !admin )
- return qtrue;
- // just in case
- if( !victim )
- return qtrue;
-
- return admin_higher_guid( admin->client->pers.guid,
- victim->client->pers.guid );
-}
-
-//KK-OAX Moved the Read/Write int/String functions to g_fileops.c for portability
-//across GAME
-
-//KK-OAX Added Warnings
-static void admin_writeconfig( void )
-{
- fileHandle_t f;
- int len, i, j;
- int t;
- char levels[ MAX_STRING_CHARS ] = {""};
-
- if( !g_admin.string[ 0 ] )
- {
- G_Printf( S_COLOR_YELLOW "WARNING: g_admin is not set. "
- " configuration will not be saved to a file.\n" );
- return;
- }
- t = trap_RealTime( NULL );
- len = trap_FS_FOpenFile( g_admin.string, &f, FS_WRITE );
- if( len < 0 )
- {
- G_Printf( "admin_writeconfig: could not open g_admin file \"%s\"\n",
- g_admin.string );
- return;
- }
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- trap_FS_Write( "[level]\n", 8, f );
- trap_FS_Write( "level = ", 10, f );
- writeFile_int( g_admin_levels[ i ]->level, f );
- trap_FS_Write( "name = ", 10, f );
- writeFile_string( g_admin_levels[ i ]->name, f );
- trap_FS_Write( "flags = ", 10, f );
- writeFile_string( g_admin_levels[ i ]->flags, f );
- trap_FS_Write( "\n", 1, f );
- }
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- // don't write level 0 users
- if( g_admin_admins[ i ]->level == 0 )
- continue;
-
- trap_FS_Write( "[admin]\n", 8, f );
- trap_FS_Write( "name = ", 10, f );
- writeFile_string( g_admin_admins[ i ]->name, f );
- trap_FS_Write( "guid = ", 10, f );
- writeFile_string( g_admin_admins[ i ]->guid, f );
- trap_FS_Write( "level = ", 10, f );
- writeFile_int( g_admin_admins[ i ]->level, f );
- trap_FS_Write( "flags = ", 10, f );
- writeFile_string( g_admin_admins[ i ]->flags, f );
- trap_FS_Write( "\n", 1, f );
- }
- for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
- {
- // don't write expired bans
- // if expires is 0, then it's a perm ban
- if( g_admin_bans[ i ]->expires != 0 &&
- ( g_admin_bans[ i ]->expires - t ) < 1 )
- continue;
-
- trap_FS_Write( "[ban]\n", 6, f );
- trap_FS_Write( "name = ", 10, f );
- writeFile_string( g_admin_bans[ i ]->name, f );
- trap_FS_Write( "guid = ", 10, f );
- writeFile_string( g_admin_bans[ i ]->guid, f );
- trap_FS_Write( "ip = ", 10, f );
- writeFile_string( g_admin_bans[ i ]->ip, f );
- trap_FS_Write( "reason = ", 10, f );
- writeFile_string( g_admin_bans[ i ]->reason, f );
- trap_FS_Write( "made = ", 10, f );
- writeFile_string( g_admin_bans[ i ]->made, f );
- trap_FS_Write( "expires = ", 10, f );
- writeFile_int( g_admin_bans[ i ]->expires, f );
- trap_FS_Write( "banner = ", 10, f );
- writeFile_string( g_admin_bans[ i ]->banner, f );
- trap_FS_Write( "\n", 1, f );
- }
- for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
- {
- levels[ 0 ] = '\0';
- trap_FS_Write( "[command]\n", 10, f );
- trap_FS_Write( "command = ", 10, f );
- writeFile_string( g_admin_commands[ i ]->command, f );
- trap_FS_Write( "exec = ", 10, f );
- writeFile_string( g_admin_commands[ i ]->exec, f );
- trap_FS_Write( "desc = ", 10, f );
- writeFile_string( g_admin_commands[ i ]->desc, f );
- trap_FS_Write( "levels = ", 10, f );
- for( j = 0; g_admin_commands[ i ]->levels[ j ] != -1; j++ )
- {
- Q_strcat( levels, sizeof( levels ),
- va( "%i ", g_admin_commands[ i ]->levels[ j ] ) );
- }
- writeFile_string( levels, f );
- trap_FS_Write( "\n", 1, f );
- }
- for( i = 0; i < MAX_ADMIN_WARNINGS && g_admin_warnings[ i ]; i++ )
- {
- // don't write expired warnings
- // if expires is 0, then it's a perm warning
- // it will get loaded everytime they connect!!!!
- if( g_admin_warnings[ i ]->expires != 0 &&
- ( g_admin_warnings[ i ]->expires - t ) < 1 )
- continue;
-
- trap_FS_Write( "[warning]\n", 10, f );
- trap_FS_Write( "name = ", 10, f );
- writeFile_string( g_admin_warnings[ i ]->name, f );
- trap_FS_Write( "guid = ", 10, f );
- writeFile_string( g_admin_warnings[ i ]->guid, f );
- trap_FS_Write( "ip = ", 10, f );
- writeFile_string( g_admin_warnings[ i ]->ip, f );
- trap_FS_Write( "warning = ", 10, f );
- writeFile_string( g_admin_warnings[ i ]->warning, f );
- trap_FS_Write( "made = ", 10, f );
- writeFile_string( g_admin_warnings[ i ]->made, f );
- trap_FS_Write( "expires = ", 10, f );
- writeFile_int( g_admin_warnings[ i ]->expires, f );
- trap_FS_Write( "warner = ", 10, f );
- writeFile_string( g_admin_warnings[ i ]->warner, f );
- trap_FS_Write( "\n", 1, f );
- }
- trap_FS_FCloseFile( f );
-}
-
-
-// if we can't parse any levels from readconfig, set up default
-// ones to make new installs easier for admins
-//KK-OAX TODO: Add all features to default levels...
-static void admin_default_levels( void )
-{
- g_admin_level_t *l;
- int i;
-
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- BG_Free( g_admin_levels[ i ] );
- g_admin_levels[ i ] = NULL;
- }
- for( i = 0; i <= 5; i++ )
- {
- l = BG_Alloc( sizeof( g_admin_level_t ) );
- l->level = i;
- *l->name = '\0';
- *l->flags = '\0';
- g_admin_levels[ i ] = l;
- }
- Q_strncpyz( g_admin_levels[ 0 ]->name, "^4Unknown Player",
- sizeof( l->name ) );
- Q_strncpyz( g_admin_levels[ 0 ]->flags, "ahC", sizeof( l->flags ) );
-
- Q_strncpyz( g_admin_levels[ 1 ]->name, "^5Server Regular",
- sizeof( l->name ) );
- Q_strncpyz( g_admin_levels[ 1 ]->flags, "iahC", sizeof( l->flags ) );
-
- Q_strncpyz( g_admin_levels[ 2 ]->name, "^6Team Manager",
- sizeof( l->name ) );
- Q_strncpyz( g_admin_levels[ 2 ]->flags, "iahCpPwr", sizeof( l->flags ) );
-
- Q_strncpyz( g_admin_levels[ 3 ]->name, "^2Junior Admin",
- sizeof( l->name ) );
- Q_strncpyz( g_admin_levels[ 3 ]->flags, "iahCpPwrkmfKncN?", sizeof( l->flags ) );
-
- Q_strncpyz( g_admin_levels[ 4 ]->name, "^3Senior Admin",
- sizeof( l->name ) );
- Q_strncpyz( g_admin_levels[ 4 ]->flags, "iahCpPwrkmfKncN?MVdBbeDS51", sizeof( l->flags ) );
-
- Q_strncpyz( g_admin_levels[ 5 ]->name, "^1Server Operator",
- sizeof( l->name ) );
- Q_strncpyz( g_admin_levels[ 5 ]->flags, "*", sizeof( l->flags ) );
- admin_level_maxname = 15;
-}
-
-// return a level for a player entity.
-int G_admin_level( gentity_t *ent )
-{
- int i;
-
- if( !ent )
- {
- return MAX_ADMIN_LEVELS;
- }
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( !Q_stricmp( g_admin_admins[ i ]->guid, ent->client->pers.guid ) )
- return g_admin_admins[ i ]->level;
- }
-
- return 0;
-}
-
-static qboolean admin_command_permission( gentity_t *ent, char *command )
-{
- int i, j;
- int level;
-
- if( !ent )
- return qtrue;
- level = ent->client->pers.adminLevel;
- for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
- {
- if( !Q_stricmp( command, g_admin_commands[ i ]->command ) )
- {
- for( j = 0; g_admin_commands[ i ]->levels[ j ] != -1; j++ )
- {
- if( g_admin_commands[ i ]->levels[ j ] == level )
- {
- return qtrue;
- }
- }
- }
- }
- return qfalse;
-}
-
-static void admin_log( gentity_t *admin, char *cmd, int skiparg )
-{
- fileHandle_t f;
- int len, i, j;
- char string[ MAX_STRING_CHARS ];
- int min, tens, sec;
- g_admin_admin_t *a;
- g_admin_level_t *l;
- char flags[ MAX_ADMIN_FLAGS * 2 ];
- gentity_t *victim = NULL;
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ];
-
- if( !g_adminLog.string[ 0 ] )
- return;
-
-
- len = trap_FS_FOpenFile( g_adminLog.string, &f, FS_APPEND );
- if( len < 0 )
- {
- G_Printf( "admin_log: error could not open %s\n", g_adminLog.string );
- return;
- }
-
- sec = level.time / 1000;
- min = sec / 60;
- sec -= min * 60;
- tens = sec / 10;
- sec -= tens * 10;
-
- *flags = '\0';
- if( admin )
- {
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( !Q_stricmp( g_admin_admins[ i ]->guid , admin->client->pers.guid ) )
- {
-
- a = g_admin_admins[ i ];
- Q_strncpyz( flags, a->flags, sizeof( flags ) );
- for( j = 0; j < MAX_ADMIN_LEVELS && g_admin_levels[ j ]; j++ )
- {
- if( g_admin_levels[ j ]->level == a->level )
- {
- l = g_admin_levels[ j ];
- Q_strcat( flags, sizeof( flags ), l->flags );
- break;
- }
- }
- break;
- }
- }
- }
-
- if( G_SayArgc() > 1 + skiparg )
- {
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) == 1 )
- {
- victim = &g_entities[ pids[ 0 ] ];
- }
- }
-
- if( victim && Q_stricmp( cmd, "attempted" ) )
- {
- Com_sprintf( string, sizeof( string ),
- "%3i:%i%i: %i: %s: %s: %s: %s: %s: %s: \"%s\"\n",
- min,
- tens,
- sec,
- ( admin ) ? admin->s.clientNum : -1,
- ( admin ) ? admin->client->pers.guid
- : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
- ( admin ) ? admin->client->pers.netname : "console",
- flags,
- cmd,
- victim->client->pers.guid,
- victim->client->pers.netname,
- G_SayConcatArgs( 2 + skiparg ) );
- }
- else
- {
- Com_sprintf( string, sizeof( string ),
- "%3i:%i%i: %i: %s: %s: %s: %s: \"%s\"\n",
- min,
- tens,
- sec,
- ( admin ) ? admin->s.clientNum : -1,
- ( admin ) ? admin->client->pers.guid
- : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
- ( admin ) ? admin->client->pers.netname : "console",
- flags,
- cmd,
- G_SayConcatArgs( 1 + skiparg ) );
- }
- trap_FS_Write( string, strlen( string ), f );
- trap_FS_FCloseFile( f );
-}
-
-static int admin_listadmins( gentity_t *ent, int start, char *search )
-{
- int drawn = 0;
- char guid_stub[9];
- char name[ MAX_NAME_LENGTH ] = {""};
- char name2[ MAX_NAME_LENGTH ] = {""};
- char lname[ MAX_NAME_LENGTH ] = {""};
- int i, j;
- gentity_t *vic;
- int l = 0;
- qboolean dup = qfalse;
-
- ADMBP_begin();
-
- // print out all connected players regardless of level if name searching
- for( i = 0; i < level.maxclients && search[ 0 ]; i++ )
- {
- vic = &g_entities[ i ];
-
- if( vic->client && vic->client->pers.connected != CON_CONNECTED )
- continue;
-
- l = vic->client->pers.adminLevel;
-
- G_SanitiseString( vic->client->pers.netname, name, sizeof( name ) );
- if( !strstr( name, search ) )
- continue;
-
- for( j = 0; j < 8; j++ )
- guid_stub[ j ] = vic->client->pers.guid[ j + 24 ];
- guid_stub[ j ] = '\0';
-
- lname[ 0 ] = '\0';
- for( j = 0; j < MAX_ADMIN_LEVELS && g_admin_levels[ j ]; j++ )
- {
- if( g_admin_levels[ j ]->level == l )
- {
- int k, colorlen;
-
- for( colorlen = k = 0; g_admin_levels[ j ]->name[ k ]; k++ )
- if( Q_IsColorString( &g_admin_levels[ j ]->name[ k ] ) )
- colorlen += 2;
- Com_sprintf( lname, sizeof( lname ), "%*s",
- admin_level_maxname + colorlen,
- g_admin_levels[ j ]->name );
- break;
- }
- }
- ADMBP( va( "%4i %4i %s^7 (*%s) %s^7\n",
- i,
- l,
- lname,
- guid_stub,
- vic->client->pers.netname ) );
- drawn++;
- }
-
- for( i = start; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] &&
- drawn < MAX_ADMIN_LISTITEMS; i++ )
- {
- if( search[ 0 ] )
- {
- G_SanitiseString( g_admin_admins[ i ]->name, name, sizeof( name ) );
- if( !strstr( name, search ) )
- continue;
-
- // verify we don't have the same guid/name pair in connected players
- // since we don't want to draw the same player twice
- dup = qfalse;
- for( j = 0; j < level.maxclients; j++ )
- {
- vic = &g_entities[ j ];
- if( !vic->client || vic->client->pers.connected != CON_CONNECTED )
- continue;
- G_SanitiseString( vic->client->pers.netname, name2, sizeof( name2 ) );
- if( !Q_stricmp( vic->client->pers.guid, g_admin_admins[ i ]->guid ) &&
- strstr( name2, search ) )
- {
- dup = qtrue;
- break;
- }
- }
- if( dup )
- continue;
- }
- for( j = 0; j < 8; j++ )
- guid_stub[ j ] = g_admin_admins[ i ]->guid[ j + 24 ];
- guid_stub[ j ] = '\0';
-
- lname[ 0 ] = '\0';
- for( j = 0; j < MAX_ADMIN_LEVELS && g_admin_levels[ j ]; j++ )
- {
- if( g_admin_levels[ j ]->level == g_admin_admins[ i ]->level )
- {
- int k, colorlen;
-
- for( colorlen = k = 0; g_admin_levels[ j ]->name[ k ]; k++ )
- if( Q_IsColorString( &g_admin_levels[ j ]->name[ k ] ) )
- colorlen += 2;
- Com_sprintf( lname, sizeof( lname ), "%*s",
- admin_level_maxname + colorlen,
- g_admin_levels[ j ]->name );
- break;
- }
- }
- ADMBP( va( "%4i %4i %s^7 (*%s) %s^7\n",
- ( i + MAX_CLIENTS ),
- g_admin_admins[ i ]->level,
- lname,
- guid_stub,
- g_admin_admins[ i ]->name ) );
- drawn++;
- }
- ADMBP_end();
- return drawn;
-}
-
-void G_admin_duration( int secs, char *duration, int dursize )
-{
-
- if( secs > ( 60 * 60 * 24 * 365 * 50 ) || secs < 0 )
- Q_strncpyz( duration, "PERMANENT", dursize );
- else if( secs >= ( 60 * 60 * 24 * 365 ) )
- Com_sprintf( duration, dursize, "%1.1f years",
- ( secs / ( 60 * 60 * 24 * 365.0f ) ) );
- else if( secs >= ( 60 * 60 * 24 * 90 ) )
- Com_sprintf( duration, dursize, "%1.1f weeks",
- ( secs / ( 60 * 60 * 24 * 7.0f ) ) );
- else if( secs >= ( 60 * 60 * 24 ) )
- Com_sprintf( duration, dursize, "%1.1f days",
- ( secs / ( 60 * 60 * 24.0f ) ) );
- else if( secs >= ( 60 * 60 ) )
- Com_sprintf( duration, dursize, "%1.1f hours",
- ( secs / ( 60 * 60.0f ) ) );
- else if( secs >= 60 )
- Com_sprintf( duration, dursize, "%1.1f minutes",
- ( secs / 60.0f ) );
- else
- Com_sprintf( duration, dursize, "%i seconds", secs );
-}
-
-qboolean G_admin_ban_check( char *userinfo, char *reason, int rlen )
-{
- char *guid, *ip;
- int i;
- int t;
-
- *reason = '\0';
- t = trap_RealTime( NULL );
- if( !*userinfo )
- return qfalse;
- ip = Info_ValueForKey( userinfo, "ip" );
- if( !*ip )
- return qfalse;
- guid = Info_ValueForKey( userinfo, "cl_guid" );
- for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
- {
- // 0 is for perm ban
- if( g_admin_bans[ i ]->expires != 0 &&
- ( g_admin_bans[ i ]->expires - t ) < 1 )
- continue;
- if( strstr( ip, g_admin_bans[ i ]->ip ) )
- {
- char duration[ 32 ];
- G_admin_duration( ( g_admin_bans[ i ]->expires - t ),
- duration, sizeof( duration ) );
- Com_sprintf(
- reason,
- rlen,
- "You have been banned by %s^7 reason: %s^7 expires: %s",
- g_admin_bans[ i ]->banner,
- g_admin_bans[ i ]->reason,
- duration
- );
- G_Printf( "Banned player tried to connect from IP %s\n", ip );
- return qtrue;
- }
- if( *guid && !Q_stricmp( g_admin_bans[ i ]->guid, guid ) )
- {
- char duration[ 32 ];
- G_admin_duration( ( g_admin_bans[ i ]->expires - t ),
- duration, sizeof( duration ) );
- Com_sprintf(
- reason,
- rlen,
- "You have been banned by %s^7 reason: %s^7 expires: %s",
- g_admin_bans[ i ]->banner,
- g_admin_bans[ i ]->reason,
- duration
- );
- G_Printf( "Banned player tried to connect with GUID %s\n", guid );
- return qtrue;
- }
- }
- return qfalse;
-}
-
-qboolean G_admin_cmd_check( gentity_t *ent, qboolean say )
-{
- int i;
- char command[ MAX_ADMIN_CMD_LEN ];
- char *cmd;
- int skip = 0;
-
- command[ 0 ] = '\0';
- G_SayArgv( 0, command, sizeof( command ) );
- if( !command[ 0 ] )
- return qfalse;
- if( !Q_stricmp( command, "say" ) ||
- ( !Q_stricmp( command, "say_team" ) &&
- G_admin_permission( ent, ADMF_TEAMCHAT_CMD ) ) )
- {
- skip = 1;
- G_SayArgv( 1, command, sizeof( command ) );
- }
-
- if( command[ 0 ] == '!' )
- {
- cmd = &command[ 1 ];
- }
- else
- {
- return qfalse;
- }
-
- for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
- {
- if( Q_stricmp( cmd, g_admin_commands[ i ]->command ) )
- continue;
-
- if( admin_command_permission( ent, cmd ) )
- {
- // flooding say will have already been accounted for in ClientCommand
- if( !say && G_FloodLimited( ent ) )
- return qtrue;
- trap_SendConsoleCommand( EXEC_APPEND, g_admin_commands[ i ]->exec );
- admin_log( ent, cmd, skip );
- }
- else
- {
- ADMP( va( "^3!%s: ^7permission denied\n", g_admin_commands[ i ]->command ) );
- admin_log( ent, "attempted", skip - 1 );
- }
- return qtrue;
- }
-
- for( i = 0; i < adminNumCmds; i++ )
- {
- if( Q_stricmp( cmd, g_admin_cmds[ i ].keyword ) )
- continue;
-
- if( G_admin_permission( ent, g_admin_cmds[ i ].flag[ 0 ] ) )
- {
- // flooding say will have already been accounted for in ClientCommand
- if( !say && G_FloodLimited( ent ) )
- return qtrue;
- g_admin_cmds[ i ].handler( ent, skip );
- admin_log( ent, cmd, skip );
- }
- else
- {
- ADMP( va( "^3!%s: ^7permission denied\n", g_admin_cmds[ i ].keyword ) );
- admin_log( ent, "attempted", skip - 1 );
- }
- return qtrue;
- }
- return qfalse;
-}
-
-void G_admin_namelog_cleanup( )
-{
- int i;
-
- for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
- {
- BG_Free( g_admin_namelog[ i ] );
- g_admin_namelog[ i ] = NULL;
- }
-}
-
-void G_admin_namelog_update( gclient_t *client, qboolean disconnect )
-{
- int i, j;
- g_admin_namelog_t *namelog;
- char n1[ MAX_NAME_LENGTH ];
- char n2[ MAX_NAME_LENGTH ];
- int clientNum = ( client - level.clients );
-
- G_SanitiseString( client->pers.netname, n1, sizeof( n1 ) );
- for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
- {
- if( disconnect && g_admin_namelog[ i ]->slot != clientNum )
- continue;
-
- if( !disconnect && !( g_admin_namelog[ i ]->slot == clientNum ||
- g_admin_namelog[ i ]->slot == -1 ) )
- {
- continue;
- }
-
- if( !Q_stricmp( client->pers.ip, g_admin_namelog[ i ]->ip ) &&
- !Q_stricmp( client->pers.guid, g_admin_namelog[ i ]->guid ) )
- {
- for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES &&
- g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
- {
- G_SanitiseString( g_admin_namelog[ i ]->name[ j ], n2, sizeof( n2 ) );
- if( !Q_stricmp( n1, n2 ) )
- break;
- }
- if( j == MAX_ADMIN_NAMELOG_NAMES )
- j = MAX_ADMIN_NAMELOG_NAMES - 1;
- Q_strncpyz( g_admin_namelog[ i ]->name[ j ], client->pers.netname,
- sizeof( g_admin_namelog[ i ]->name[ j ] ) );
- g_admin_namelog[ i ]->slot = ( disconnect ) ? -1 : clientNum;
-
- // if this player is connecting, they are no longer banned
- if( !disconnect )
- g_admin_namelog[ i ]->banned = qfalse;
-
- return;
- }
- }
- if( i >= MAX_ADMIN_NAMELOGS )
- {
- G_Printf( "G_admin_namelog_update: warning, g_admin_namelogs overflow\n" );
- return;
- }
- namelog = BG_Alloc( sizeof( g_admin_namelog_t ) );
- memset( namelog, 0, sizeof( namelog ) );
- for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES; j++ )
- namelog->name[ j ][ 0 ] = '\0';
- Q_strncpyz( namelog->ip, client->pers.ip, sizeof( namelog->ip ) );
- Q_strncpyz( namelog->guid, client->pers.guid, sizeof( namelog->guid ) );
- Q_strncpyz( namelog->name[ 0 ], client->pers.netname,
- sizeof( namelog->name[ 0 ] ) );
- namelog->slot = ( disconnect ) ? -1 : clientNum;
- g_admin_namelog[ i ] = namelog;
-}
-
-//KK-OAX Added Parsing Warnings
-qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
-{
- g_admin_level_t *l = NULL;
- g_admin_admin_t *a = NULL;
- g_admin_ban_t *b = NULL;
- g_admin_command_t *c = NULL;
- g_admin_warning_t *w = NULL;
- int lc = 0, ac = 0, bc = 0, cc = 0, wc = 0;
- fileHandle_t f;
- int len;
- char *cnf, *cnf2;
- char *t;
- qboolean level_open, admin_open, ban_open, command_open, warning_open;
- int i;
-
- G_admin_cleanup();
-
- if( !g_admin.string[ 0 ] )
- {
- ADMP( "^3!readconfig: g_admin is not set, not loading configuration "
- "from a file\n" );
- admin_default_levels();
- return qfalse;
- }
-
- len = trap_FS_FOpenFile( g_admin.string, &f, FS_READ );
- if( len < 0 )
- {
- G_Printf( "^3!readconfig: ^7could not open admin config file %s\n",
- g_admin.string );
- admin_default_levels();
- return qfalse;
- }
- cnf = BG_Alloc( len + 1 );
- cnf2 = cnf;
- trap_FS_Read( cnf, len, f );
- *( cnf + len ) = '\0';
- trap_FS_FCloseFile( f );
-
- admin_level_maxname = 0;
-
- level_open = admin_open = ban_open = command_open = warning_open = qfalse;
- COM_BeginParseSession( g_admin.string );
- while( 1 )
- {
- t = COM_Parse( &cnf );
- if( !*t )
- break;
-
- if( !Q_stricmp( t, "[level]" ) )
- {
- if( lc >= MAX_ADMIN_LEVELS )
- return qfalse;
- l = BG_Alloc( sizeof( g_admin_level_t ) );
- g_admin_levels[ lc++ ] = l;
- level_open = qtrue;
- admin_open = ban_open = command_open = warning_open = qfalse;
- }
- else if( !Q_stricmp( t, "[admin]" ) )
- {
- if( ac >= MAX_ADMIN_ADMINS )
- return qfalse;
- a = BG_Alloc( sizeof( g_admin_admin_t ) );
- g_admin_admins[ ac++ ] = a;
- admin_open = qtrue;
- level_open = ban_open = command_open = warning_open = qfalse;
- }
- else if( !Q_stricmp( t, "[ban]" ) )
- {
- if( bc >= MAX_ADMIN_BANS )
- return qfalse;
- b = BG_Alloc( sizeof( g_admin_ban_t ) );
- g_admin_bans[ bc++ ] = b;
- ban_open = qtrue;
- level_open = admin_open = command_open = warning_open = qfalse;
- }
- else if( !Q_stricmp( t, "[command]" ) )
- {
- if( cc >= MAX_ADMIN_COMMANDS )
- return qfalse;
- c = BG_Alloc( sizeof( g_admin_command_t ) );
- g_admin_commands[ cc++ ] = c;
- c->levels[ 0 ] = -1;
- command_open = qtrue;
- level_open = admin_open = ban_open = warning_open = qfalse;
- }
- else if( !Q_stricmp( t, "[warning]" ) )
- {
- if( wc >= MAX_ADMIN_WARNINGS )
- return qfalse;
- w = BG_Alloc( sizeof( g_admin_warning_t ) );
- g_admin_warnings[ wc++ ] = w;
- warning_open = qtrue;
- level_open = admin_open = ban_open = command_open = qfalse;
- }
- else if( level_open )
- {
- if( !Q_stricmp( t, "level" ) )
- {
- readFile_int( &cnf, &l->level );
- }
- else if( !Q_stricmp( t, "name" ) )
- {
- readFile_string( &cnf, l->name, sizeof( l->name ) );
- }
- else if( !Q_stricmp( t, "flags" ) )
- {
- readFile_string( &cnf, l->flags, sizeof( l->flags ) );
- }
- else
- {
- COM_ParseError( "[level] unrecognized token \"%s\"", t );
- }
- }
- else if( admin_open )
- {
- if( !Q_stricmp( t, "name" ) )
- {
- readFile_string( &cnf, a->name, sizeof( a->name ) );
- }
- else if( !Q_stricmp( t, "guid" ) )
- {
- readFile_string( &cnf, a->guid, sizeof( a->guid ) );
- }
- else if( !Q_stricmp( t, "level" ) )
- {
- readFile_int( &cnf, &a->level );
- }
- else if( !Q_stricmp( t, "flags" ) )
- {
- readFile_string( &cnf, a->flags, sizeof( a->flags ) );
- }
- else
- {
- COM_ParseError( "[admin] unrecognized token \"%s\"", t );
- }
-
- }
- else if( ban_open )
- {
- if( !Q_stricmp( t, "name" ) )
- {
- readFile_string( &cnf, b->name, sizeof( b->name ) );
- }
- else if( !Q_stricmp( t, "guid" ) )
- {
- readFile_string( &cnf, b->guid, sizeof( b->guid ) );
- }
- else if( !Q_stricmp( t, "ip" ) )
- {
- readFile_string( &cnf, b->ip, sizeof( b->ip ) );
- }
- else if( !Q_stricmp( t, "reason" ) )
- {
- readFile_string( &cnf, b->reason, sizeof( b->reason ) );
- }
- else if( !Q_stricmp( t, "made" ) )
- {
- readFile_string( &cnf, b->made, sizeof( b->made ) );
- }
- else if( !Q_stricmp( t, "expires" ) )
- {
- readFile_int( &cnf, &b->expires );
- }
- else if( !Q_stricmp( t, "banner" ) )
- {
- readFile_string( &cnf, b->banner, sizeof( b->banner ) );
- }
- else
- {
- COM_ParseError( "[ban] unrecognized token \"%s\"", t );
- }
- }
- else if( command_open )
- {
- if( !Q_stricmp( t, "command" ) )
- {
- readFile_string( &cnf, c->command, sizeof( c->command ) );
- }
- else if( !Q_stricmp( t, "exec" ) )
- {
- readFile_string( &cnf, c->exec, sizeof( c->exec ) );
- }
- else if( !Q_stricmp( t, "desc" ) )
- {
- readFile_string( &cnf, c->desc, sizeof( c->desc ) );
- }
- else if( !Q_stricmp( t, "levels" ) )
- {
- char levels[ MAX_STRING_CHARS ] = {""};
- char *level = levels;
- char *lp;
- int cmdlevel = 0;
-
- readFile_string( &cnf, levels, sizeof( levels ) );
- while( cmdlevel < MAX_ADMIN_LEVELS )
- {
- lp = COM_Parse( &level );
- if( !*lp )
- break;
- c->levels[ cmdlevel++ ] = atoi( lp );
- }
- // ensure the list is -1 terminated
- c->levels[ cmdlevel ] = -1;
- }
- else
- {
- COM_ParseError( "[command] unrecognized token \"%s\"", t );
- }
- }
- else if( warning_open )
- {
- if( !Q_stricmp( t, "name" ) )
- {
- readFile_string( &cnf, w->name, sizeof( w->name ) );
- }
- else if( !Q_stricmp( t, "guid" ) )
- {
- readFile_string( &cnf, w->guid, sizeof( w->guid ) );
- }
- else if( !Q_stricmp( t, "ip" ) )
- {
- readFile_string( &cnf, w->ip, sizeof( w->ip ) );
- }
- else if( !Q_stricmp( t, "warning" ) )
- {
- readFile_string( &cnf, w->warning, sizeof( w->warning ) );
- }
- else if( !Q_stricmp( t, "made" ) )
- {
- readFile_string( &cnf, w->made, sizeof( w->made ) );
- }
- else if( !Q_stricmp( t, "expires" ) )
- {
- readFile_int( &cnf, &w->expires );
- }
- else if( !Q_stricmp( t, "warner" ) )
- {
- readFile_string( &cnf, w->warner, sizeof( w->warner ) );
- }
- else
- {
- COM_ParseError( "[warning] unrecognized token \"%s\"", t );
- }
- }
- else
- {
- COM_ParseError( "unexpected token \"%s\"", t );
- }
- }
- BG_Free( cnf2 );
- ADMP( va( "^3!readconfig: ^7loaded %d levels, %d admins, %d bans, %d commands, %d warnings\n",
- lc, ac, bc, cc, wc ) );
- if( lc == 0 )
- admin_default_levels();
- else
- {
- // max printable name length for formatting
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- len = Q_PrintStrlen( g_admin_levels[ i ]->name );
- if( len > admin_level_maxname )
- admin_level_maxname = len;
- }
- }
- // reset adminLevel
- for( i = 0; i < level.maxclients; i++ )
- if( level.clients[ i ].pers.connected != CON_DISCONNECTED )
- level.clients[ i ].pers.adminLevel = G_admin_level( &g_entities[ i ] );
- return qtrue;
-}
-
-qboolean G_admin_time( gentity_t *ent, int skiparg )
-{
- qtime_t qt;
-
- trap_RealTime( &qt );
- ADMP( va( "^3!time: ^7local time is %02i:%02i:%02i\n",
- qt.tm_hour, qt.tm_min, qt.tm_sec ) );
- return qtrue;
-}
-
-qboolean G_admin_setlevel( gentity_t *ent, int skiparg )
-{
- char name[ MAX_NAME_LENGTH ] = {""};
- char lstr[ 11 ]; // 10 is max strlen() for 32-bit int
- char adminname[ MAX_NAME_LENGTH ] = {""};
- char testname[ MAX_NAME_LENGTH ] = {""};
- char guid[ 33 ];
- int l, i;
- gentity_t *vic = NULL;
- qboolean updated = qfalse;
- g_admin_admin_t *a;
- qboolean found = qfalse;
- qboolean numeric = qtrue;
- int matches = 0;
- int id = -1;
-
-
- if( G_SayArgc() < 3 + skiparg )
- {
- ADMP( "^3!setlevel: ^7usage: !setlevel [name|slot#] [level]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, testname, sizeof( testname ) );
- G_SayArgv( 2 + skiparg, lstr, sizeof( lstr ) );
- l = atoi( lstr );
- G_SanitiseString( testname, name, sizeof( name ) );
- for( i = 0; i < sizeof( name ) && name[ i ]; i++ )
- {
- if( !isdigit( name[ i ] ) )
- {
- numeric = qfalse;
- break;
- }
- }
- if( numeric )
- id = atoi( name );
-
- if( ent && l > ent->client->pers.adminLevel )
- {
- ADMP( "^3!setlevel: ^7you may not use !setlevel to set a level higher "
- "than your current level\n" );
- return qfalse;
- }
-
- // if admin is activated for the first time on a running server, we need
- // to ensure at least the default levels get created
- if( !ent && !g_admin_levels[ 0 ] )
- G_admin_readconfig(NULL, 0);
-
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- if( g_admin_levels[ i ]->level == l )
- {
- found = qtrue;
- break;
- }
- }
- if( !found )
- {
- ADMP( "^3!setlevel: ^7level is not defined\n" );
- return qfalse;
- }
-
- if( numeric && id >= 0 && id < level.maxclients )
- vic = &g_entities[ id ];
-
- if( vic && vic->client && vic->client->pers.connected != CON_DISCONNECTED )
- {
- Q_strncpyz( adminname, vic->client->pers.netname, sizeof( adminname ) );
- Q_strncpyz( guid, vic->client->pers.guid, sizeof( guid ) );
- matches = 1;
- }
- else if( numeric && id >= MAX_CLIENTS && id < MAX_CLIENTS + MAX_ADMIN_ADMINS
- && g_admin_admins[ id - MAX_CLIENTS ] )
- {
- Q_strncpyz( adminname, g_admin_admins[ id - MAX_CLIENTS ]->name,
- sizeof( adminname ) );
- Q_strncpyz( guid, g_admin_admins[ id - MAX_CLIENTS ]->guid,
- sizeof( guid ) );
- matches = 1;
- }
- else
- {
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] && matches < 2; i++ )
- {
- G_SanitiseString( g_admin_admins[ i ]->name, testname, sizeof( testname ) );
- if( strstr( testname, name ) )
- {
- Q_strncpyz( adminname, g_admin_admins[ i ]->name, sizeof( adminname ) );
- Q_strncpyz( guid, g_admin_admins[ i ]->guid, sizeof( guid ) );
- matches++;
- }
- }
- for( i = 0; i < level.maxclients && matches < 2; i++ )
- {
- if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
- continue;
- if( matches && !Q_stricmp( level.clients[ i ].pers.guid, guid ) )
- {
- vic = &g_entities[ i ];
- continue;
- }
- G_SanitiseString( level.clients[ i ].pers.netname, testname,
- sizeof( testname ) );
- if( strstr( testname, name ) )
- {
- vic = &g_entities[ i ];
- matches++;
- Q_strncpyz( guid, vic->client->pers.guid, sizeof( guid ) );
- }
- }
- if( vic )
- Q_strncpyz( adminname, vic->client->pers.netname, sizeof( adminname ) );
- }
-
- if( matches == 0 )
- {
- ADMP( "^3!setlevel:^7 no match. use !listplayers or !listadmins to "
- "find an appropriate number to use instead of name.\n" );
- return qfalse;
- }
- if( matches > 1 )
- {
- ADMP( "^3!setlevel:^7 more than one match. Use the admin number "
- "instead:\n" );
- admin_listadmins( ent, 0, name );
- return qfalse;
- }
-
- if( ent && !admin_higher_guid( ent->client->pers.guid, guid ) )
- {
- ADMP( "^3!setlevel: ^7sorry, but your intended victim has a higher"
- " admin level than you\n" );
- return qfalse;
- }
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ];i++ )
- {
- if( !Q_stricmp( g_admin_admins[ i ]->guid, guid ) )
- {
- g_admin_admins[ i ]->level = l;
- Q_strncpyz( g_admin_admins[ i ]->name, adminname,
- sizeof( g_admin_admins[ i ]->name ) );
- updated = qtrue;
- }
- }
- if( !updated )
- {
- if( i == MAX_ADMIN_ADMINS )
- {
- ADMP( "^3!setlevel: ^7too many admins\n" );
- return qfalse;
- }
- a = BG_Alloc( sizeof( g_admin_admin_t ) );
- a->level = l;
- Q_strncpyz( a->name, adminname, sizeof( a->name ) );
- Q_strncpyz( a->guid, guid, sizeof( a->guid ) );
- *a->flags = '\0';
- g_admin_admins[ i ] = a;
- }
-
- AP( va(
- "print \"^3!setlevel: ^7%s^7 was given level %d admin rights by %s\n\"",
- adminname, l, ( ent ) ? ent->client->pers.netname : "console" ) );
- if( vic )
- vic->client->pers.adminLevel = l;
-
- if( !g_admin.string[ 0 ] )
- ADMP( "^3!setlevel: ^7WARNING g_admin not set, not saving admin record "
- "to a file\n" );
- else
- admin_writeconfig();
- return qtrue;
-}
-
-static qboolean admin_create_ban( gentity_t *ent,
- char *netname,
- char *guid,
- char *ip,
- int seconds,
- char *reason )
-{
- g_admin_ban_t *b = NULL;
- qtime_t qt;
- int t;
- int i;
-
- t = trap_RealTime( &qt );
- b = BG_Alloc( sizeof( g_admin_ban_t ) );
-
- if( !b )
- return qfalse;
-
- Q_strncpyz( b->name, netname, sizeof( b->name ) );
- Q_strncpyz( b->guid, guid, sizeof( b->guid ) );
- Q_strncpyz( b->ip, ip, sizeof( b->ip ) );
-
- //strftime( b->made, sizeof( b->made ), "%m/%d/%y %H:%M:%S", lt );
- Com_sprintf( b->made, sizeof( b->made ), "%02i/%02i/%02i %02i:%02i:%02i",
- qt.tm_mon + 1, qt.tm_mday, qt.tm_year % 100,
- qt.tm_hour, qt.tm_min, qt.tm_sec );
-
- if( ent )
- Q_strncpyz( b->banner, ent->client->pers.netname, sizeof( b->banner ) );
- else
- Q_strncpyz( b->banner, "console", sizeof( b->banner ) );
- if( !seconds )
- b->expires = 0;
- else
- b->expires = t + seconds;
- if( !*reason )
- Q_strncpyz( b->reason, "banned by admin", sizeof( b->reason ) );
- else
- Q_strncpyz( b->reason, reason, sizeof( b->reason ) );
- for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
- ;
- if( i == MAX_ADMIN_BANS )
- {
- ADMP( "^3!ban: ^7too many bans\n" );
- BG_Free( b );
- return qfalse;
- }
- g_admin_bans[ i ] = b;
- return qtrue;
-}
-//KK-OAX Copied create_ban to get Time Stuff Right (Didn't feel like writing code to parse it)
-static qboolean admin_create_warning( gentity_t *ent, char *netname, char *guid, char *ip, int seconds, char *warning )
-{
- g_admin_warning_t *w = NULL;
- qtime_t qt;
- int t;
- int i;
-
- t = trap_RealTime( &qt );
- w = BG_Alloc( sizeof( g_admin_warning_t ) );
-
- if( !w )
- return qfalse;
-
- Q_strncpyz( w->name, netname, sizeof( w->name ) );
- Q_strncpyz( w->guid, guid, sizeof( w->guid ) );
- Q_strncpyz( w->ip, ip, sizeof( w->ip ) );
-
- //strftime( b->made, sizeof( b->made ), "%m/%d/%y %H:%M:%S", lt );
- Com_sprintf( w->made, sizeof( w->made ), "%02i/%02i/%02i %02i:%02i:%02i",
- qt.tm_mon + 1, qt.tm_mday, qt.tm_year % 100,
- qt.tm_hour, qt.tm_min, qt.tm_sec );
-
- if( ent )
- Q_strncpyz( w->warner, ent->client->pers.netname, sizeof( w->warner ) );
- else
- Q_strncpyz( w->warner, "console", sizeof( w->warner ) );
- if( !seconds )
- w->expires = 0;
- else
- w->expires = t + seconds;
- if( !*warning )
- Q_strncpyz( w->warning, "warned by admin", sizeof( w->warning ) );
- else
- Q_strncpyz( w->warning, warning, sizeof( w->warning ) );
- for( i = 0; i < MAX_ADMIN_WARNINGS && g_admin_warnings[ i ]; i++ )
- ;
- if( i == MAX_ADMIN_WARNINGS )
- {
- ADMP( "^3!warn: ^7too many warnings\n" );
- BG_Free( w );
- return qfalse;
- }
- g_admin_warnings[ i ] = w;
- return qtrue;
-}
-
-
-int G_admin_parse_time( const char *time )
-{
- int seconds = 0, num = 0;
- while( *time )
- {
- if( !isdigit( *time ) )
- return -1;
- while( isdigit( *time ) )
- num = num * 10 + *time++ - '0';
-
- if( !*time )
- break;
- switch( *time++ )
- {
- case 'w': num *= 7;
- case 'd': num *= 24;
- case 'h': num *= 60;
- case 'm': num *= 60;
- case 's': break;
- default: return -1;
- }
- seconds += num;
- num = 0;
- }
- if( num )
- seconds += num;
- return seconds;
-}
-
-qboolean G_admin_kick( gentity_t *ent, int skiparg )
-{
- int pids[ MAX_CLIENTS ], found;
- char name[ MAX_NAME_LENGTH ], *reason, err[ MAX_STRING_CHARS ];
- int minargc;
- gentity_t *vic;
-
- minargc = 3 + skiparg;
- if( G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
- minargc = 2 + skiparg;
-
- if( G_SayArgc() < minargc )
- {
- ADMP( "^3!kick: ^7usage: !kick [name] [reason]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- reason = G_SayConcatArgs( 2 + skiparg );
- if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
- {
- G_MatchOnePlayer( pids, found, err, sizeof( err ) );
- ADMP( va( "^3!kick: ^7%s\n", err ) );
- return qfalse;
- }
- vic = &g_entities[ pids[ 0 ] ];
- if( !admin_higher( ent, vic ) )
- {
- ADMP( "^3!kick: ^7sorry, but your intended victim has a higher admin"
- " level than you\n" );
- return qfalse;
- }
- if( vic->client->pers.localClient )
- {
- ADMP( "^3!kick: ^7disconnecting the host would end the game\n" );
- return qfalse;
- }
- admin_create_ban( ent,
- vic->client->pers.netname,
- vic->client->pers.guid,
- vic->client->pers.ip,
- G_admin_parse_time( va( "1s%s", g_adminTempBan.string ) ),
- ( *reason ) ? reason : "kicked by admin" );
- if( g_admin.string[ 0 ] )
- admin_writeconfig();
-
- trap_SendServerCommand( pids[ 0 ],
- va( "disconnect \"You have been kicked.\n%s^7\nreason:\n%s\"",
- ( ent ) ? va( "admin:\n%s", ent->client->pers.netname ) : "",
- ( *reason ) ? reason : "kicked by admin" ) );
-
- trap_DropClient( pids[ 0 ], va( "has been kicked%s^7. reason: %s",
- ( ent ) ? va( " by %s", ent->client->pers.netname ) : "",
- ( *reason ) ? reason : "kicked by admin" ) );
-
- return qtrue;
-}
-
-qboolean G_admin_ban( gentity_t *ent, int skiparg )
-{
- int seconds;
- char search[ MAX_NAME_LENGTH ];
- char secs[ MAX_TOKEN_CHARS ];
- char *reason;
- int minargc;
- char duration[ 32 ];
- int logmatch = -1, logmatches = 0;
- int i, j;
- qboolean exactmatch = qfalse;
- char n2[ MAX_NAME_LENGTH ];
- char s2[ MAX_NAME_LENGTH ];
- char guid_stub[ 9 ];
-
- if( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
- G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
- {
- minargc = 2 + skiparg;
- }
- else if( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) ||
- G_admin_permission( ent, ADMF_UNACCOUNTABLE ) ||
- g_adminMaxBan.integer )
- {
- minargc = 3 + skiparg;
- }
- else
- {
- minargc = 4 + skiparg;
- }
- if( G_SayArgc() < minargc )
- {
- ADMP( "^3!ban: ^7usage: !ban [name|slot|ip] [duration] [reason]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, search, sizeof( search ) );
- G_SanitiseString( search, s2, sizeof( s2 ) );
- G_SayArgv( 2 + skiparg, secs, sizeof( secs ) );
-
- seconds = G_admin_parse_time( secs );
- if( seconds <= 0 )
- {
- if( g_adminMaxBan.integer && !G_admin_permission( ent, ADMF_CAN_PERM_BAN) )
- {
- ADMP( va( "^3!ban: ^7using your admin level's maximum ban length of %s\n",
- g_adminMaxBan.string ) );
- seconds = G_admin_parse_time( g_adminMaxBan.string );
- }
- else if( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
- {
- seconds = 0;
- }
- else
- {
- ADMP( "^3!ban: ^7you may not issue permanent bans\n" );
- return qfalse;
- }
- reason = G_SayConcatArgs( 2 + skiparg );
- }
- else
- {
- if( g_adminMaxBan.integer &&
- !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
- seconds > G_admin_parse_time( g_adminMaxBan.string ) )
- {
- ADMP( va( "^3!ban: ^7ban length limited to %s for your admin level\n",
- g_adminMaxBan.string ) );
- seconds = G_admin_parse_time( g_adminMaxBan.string );
- }
- reason = G_SayConcatArgs( 3 + skiparg );
- }
-
- for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
- {
- // skip players in the namelog who have already been banned
- if( g_admin_namelog[ i ]->banned )
- continue;
-
- // skip disconnected players when banning on slot number
- if( g_admin_namelog[ i ]->slot == -1 )
- continue;
-
- if( !Q_stricmp( va( "%d", g_admin_namelog[ i ]->slot ), search ) )
- {
- logmatches = 1;
- logmatch = i;
- exactmatch = qtrue;
- break;
- }
- }
-
- for( i = 0;
- !exactmatch && i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ];
- i++ )
- {
- // skip players in the namelog who have already been banned
- if( g_admin_namelog[ i ]->banned )
- continue;
-
- if( !Q_stricmp( g_admin_namelog[ i ]->ip, search ) )
- {
- logmatches = 1;
- logmatch = i;
- exactmatch = qtrue;
- break;
- }
- for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES &&
- g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
- {
- G_SanitiseString( g_admin_namelog[ i ]->name[ j ], n2, sizeof( n2 ) );
- if( strstr( n2, s2 ) )
- {
- if( logmatch != i )
- logmatches++;
- logmatch = i;
- }
- }
- }
-
- if( !logmatches )
- {
- ADMP( "^3!ban: ^7no player found by that name, IP, or slot number\n" );
- return qfalse;
- }
- if( logmatches > 1 )
- {
- ADMBP_begin();
- ADMBP( "^3!ban: ^7multiple recent clients match name, use IP or slot#:\n" );
- for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
- {
- for( j = 0; j < 8; j++ )
- guid_stub[ j ] = g_admin_namelog[ i ]->guid[ j + 24 ];
- guid_stub[ j ] = '\0';
- for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES &&
- g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
- {
- G_SanitiseString( g_admin_namelog[ i ]->name[ j ], n2, sizeof( n2 ) );
- if( strstr( n2, s2 ) )
- {
- if( g_admin_namelog[ i ]->slot > -1 )
- ADMBP( "^3" );
- ADMBP( va( "%-2s (*%s) %15s ^7'%s^7'\n",
- ( g_admin_namelog[ i ]->slot > -1 ) ?
- va( "%d", g_admin_namelog[ i ]->slot ) : "-",
- guid_stub,
- g_admin_namelog[ i ]->ip,
- g_admin_namelog[ i ]->name[ j ] ) );
- }
- }
- }
- ADMBP_end();
- return qfalse;
- }
-
- if( ent && !admin_higher_guid( ent->client->pers.guid,
- g_admin_namelog[ logmatch ]->guid ) )
- {
-
- ADMP( "^3!ban: ^7sorry, but your intended victim has a higher admin"
- " level than you\n" );
- return qfalse;
- }
- if( !strcmp( g_admin_namelog[ logmatch ]->ip, "localhost" ) )
- {
- ADMP( "^3!ban: ^7disconnecting the host would end the game\n" );
- return qfalse;
- }
-
- G_admin_duration( ( seconds ) ? seconds : -1,
- duration, sizeof( duration ) );
-
- admin_create_ban( ent,
- g_admin_namelog[ logmatch ]->name[ 0 ],
- g_admin_namelog[ logmatch ]->guid,
- g_admin_namelog[ logmatch ]->ip,
- seconds, reason );
-
- g_admin_namelog[ logmatch ]->banned = qtrue;
-
- if( !g_admin.string[ 0 ] )
- ADMP( "^3!ban: ^7WARNING g_admin not set, not saving ban to a file\n" );
- else
- admin_writeconfig();
-
- if( g_admin_namelog[ logmatch ]->slot == -1 )
- {
- // client is already disconnected so stop here
- AP( va( "print \"^3!ban:^7 %s^7 has been banned by %s^7, "
- "duration: %s, reason: %s\n\"",
- g_admin_namelog[ logmatch ]->name[ 0 ],
- ( ent ) ? ent->client->pers.netname : "console",
- duration,
- ( *reason ) ? reason : "banned by admin" ) );
- return qtrue;
- }
-
- trap_SendServerCommand( g_admin_namelog[ logmatch ]->slot,
- va( "disconnect \"You have been banned.\n"
- "admin:\n%s^7\nduration:\n%s\nreason:\n%s\"",
- ( ent ) ? ent->client->pers.netname : "console",
- duration,
- ( *reason ) ? reason : "banned by admin" ) );
-
- trap_DropClient( g_admin_namelog[ logmatch ]->slot,
- va( "has been banned by %s^7, duration: %s, reason: %s",
- ( ent ) ? ent->client->pers.netname : "console",
- duration,
- ( *reason ) ? reason : "banned by admin" ) );
- return qtrue;
-}
-
-qboolean G_admin_unban( gentity_t *ent, int skiparg )
-{
- int bnum;
- int time = trap_RealTime( NULL );
- char bs[ 5 ];
-
- if( G_SayArgc() < 2 + skiparg )
- {
- ADMP( "^3!unban: ^7usage: !unban [ban#]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, bs, sizeof( bs ) );
- bnum = atoi( bs );
- if( bnum < 1 || bnum > MAX_ADMIN_BANS || !g_admin_bans[ bnum - 1 ] )
- {
- ADMP( "^3!unban: ^7invalid ban#\n" );
- return qfalse;
- }
- if( g_admin_bans[ bnum - 1 ]->expires == 0 &&
- !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
- {
- ADMP( "^3!unban: ^7you cannot remove permanent bans\n" );
- return qfalse;
- }
- if( g_adminMaxBan.integer &&
- !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
- g_admin_bans[ bnum - 1 ]->expires - time > G_admin_parse_time( g_adminMaxBan.string ) )
- {
- ADMP( va( "^3!unban: ^7your admin level cannot remove bans longer than %s\n",
- g_adminMaxBan.string ) );
- return qfalse;
- }
- g_admin_bans[ bnum - 1 ]->expires = time;
- AP( va( "print \"^3!unban: ^7ban #%d for %s^7 has been removed by %s\n\"",
- bnum,
- g_admin_bans[ bnum - 1 ]->name,
- ( ent ) ? ent->client->pers.netname : "console" ) );
- if( g_admin.string[ 0 ] )
- admin_writeconfig();
- return qtrue;
-}
-
-qboolean G_admin_adjustban( gentity_t *ent, int skiparg )
-{
- int bnum;
- int length;
- int expires;
- int time = trap_RealTime( NULL );
- char duration[ 32 ] = {""};
- char *reason;
- char bs[ 5 ];
- char secs[ MAX_TOKEN_CHARS ];
- char mode = '\0';
- g_admin_ban_t *ban;
-
- if( G_SayArgc() < 3 + skiparg )
- {
- ADMP( "^3!adjustban: ^7usage: !adjustban [ban#] [duration] [reason]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, bs, sizeof( bs ) );
- bnum = atoi( bs );
- if( bnum < 1 || bnum > MAX_ADMIN_BANS || !g_admin_bans[ bnum - 1 ] )
- {
- ADMP( "^3!adjustban: ^7invalid ban#\n" );
- return qfalse;
- }
- ban = g_admin_bans[ bnum - 1 ];
- if( ban->expires == 0 && !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
- {
- ADMP( "^3!adjustban: ^7you cannot modify permanent bans\n" );
- return qfalse;
- }
- if( g_adminMaxBan.integer &&
- !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
- ban->expires - time > G_admin_parse_time( g_adminMaxBan.string ) )
- {
- ADMP( va( "^3!adjustban: ^7your admin level cannot modify bans longer than %s\n",
- g_adminMaxBan.string ) );
- return qfalse;
- }
- G_SayArgv( 2 + skiparg, secs, sizeof( secs ) );
- if( secs[ 0 ] == '+' || secs[ 0 ] == '-' )
- mode = secs[ 0 ];
- length = G_admin_parse_time( &secs[ mode ? 1 : 0 ] );
- if( length < 0 )
- skiparg--;
- else
- {
- if( length )
- {
- if( ban->expires == 0 && mode )
- {
- ADMP( "^3!adjustban: ^7new duration must be explicit\n" );
- return qfalse;
- }
- if( mode == '+' )
- expires = ban->expires + length;
- else if( mode == '-' )
- expires = ban->expires - length;
- else
- expires = time + length;
- if( expires <= time )
- {
- ADMP( "^3!adjustban: ^7ban duration must be positive\n" );
- return qfalse;
- }
- if( g_adminMaxBan.integer &&
- !G_admin_permission( ent, ADMF_CAN_PERM_BAN ) &&
- expires - time > G_admin_parse_time( g_adminMaxBan.string ) )
- {
- ADMP( va( "^3!adjustban: ^7ban length is limited to %s for your admin level\n",
- g_adminMaxBan.string ) );
- length = G_admin_parse_time( g_adminMaxBan.string );
- expires = time + length;
- }
- }
- else if( G_admin_permission( ent, ADMF_CAN_PERM_BAN ) )
- expires = 0;
- else
- {
- ADMP( "^3!adjustban: ^7ban duration must be positive\n" );
- return qfalse;
- }
-
- ban->expires = expires;
- G_admin_duration( ( expires ) ? expires - time : -1, duration,
- sizeof( duration ) );
- }
- reason = G_SayConcatArgs( 3 + skiparg );
- if( *reason )
- Q_strncpyz( ban->reason, reason, sizeof( ban->reason ) );
- AP( va( "print \"^3!adjustban: ^7ban #%d for %s^7 has been updated by %s^7 "
- "%s%s%s%s%s\n\"",
- bnum,
- ban->name,
- ( ent ) ? ent->client->pers.netname : "console",
- ( length >= 0 ) ? "duration: " : "",
- duration,
- ( length >= 0 && *reason ) ? ", " : "",
- ( *reason ) ? "reason: " : "",
- reason ) );
- if( ent )
- Q_strncpyz( ban->banner, ent->client->pers.netname, sizeof( ban->banner ) );
- if( g_admin.string[ 0 ] )
- admin_writeconfig();
- return qtrue;
-}
-
-qboolean G_admin_putteam( gentity_t *ent, int skiparg )
-{
- int pids[ MAX_CLIENTS ], found;
- //KK-OAPub Changed Team Name Length so "Spectator" doesn't crash Game
- char name[ MAX_NAME_LENGTH ], team[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
- gentity_t *vic;
- team_t teamnum = TEAM_NONE;
-
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- G_SayArgv( 2 + skiparg, team, sizeof( team ) );
- if( G_SayArgc() < 3 + skiparg )
- {
- ADMP( "^3!putteam: ^7usage: !putteam [name] [h|a|s]\n" );
- return qfalse;
- }
-
- if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
- {
- G_MatchOnePlayer( pids, found, err, sizeof( err ) );
- ADMP( va( "^3!putteam: ^7%s\n", err ) );
- return qfalse;
- }
- if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
- {
- ADMP( "^3!putteam: ^7sorry, but your intended victim has a higher "
- " admin level than you\n" );
- return qfalse;
- }
- vic = &g_entities[ pids[ 0 ] ];
- teamnum = G_TeamFromString( team );
- if( teamnum == TEAM_NUM_TEAMS )
- {
- ADMP( va( "^3!putteam: ^7unknown team %s\n", team ) );
- return qfalse;
- }
- if( vic->client->sess.sessionTeam == teamnum )
- return qfalse;
-
- SetTeam( vic, team );
-
- AP( va( "print \"^3!putteam: ^7%s^7 put %s^7 on to the %s team\n\"",
- ( ent ) ? ent->client->pers.netname : "console",
- vic->client->pers.netname, BG_TeamName( teamnum ) ) );
- return qtrue;
-}
-
-//KK-Fixed!!!!
-//KK-Removed Layouts from The command
-qboolean G_admin_map( gentity_t *ent, int skiparg )
-{
- char map[ MAX_QPATH ];
-
- if( G_SayArgc( ) < 2 + skiparg )
- {
- ADMP( "^3!map: ^7usage: !map [map] (layout)\n" );
- return qfalse;
- }
-
- G_SayArgv( skiparg + 1, map, sizeof( map ) );
-
- if( !trap_FS_FOpenFile( va( "maps/%s.bsp", map ), NULL, FS_READ ) )
- {
- ADMP( va( "^3!map: ^7invalid map name '%s'\n", map ) );
- return qfalse;
- }
-
- trap_SendConsoleCommand( EXEC_APPEND, va( "map %s", map ) );
- level.restarted = qtrue;
- AP( va( "print \"^3!map: ^7map '%s' started by %s\n\"", map,
- ( ent ) ? ent->client->pers.netname : "console" ) );
- return qtrue;
-}
-
-qboolean G_admin_mute( gentity_t *ent, int skiparg )
-{
- int pids[ MAX_CLIENTS ], found;
- char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
- char command[ MAX_ADMIN_CMD_LEN ], *cmd;
- gentity_t *vic;
-
- G_SayArgv( skiparg, command, sizeof( command ) );
- cmd = command;
- if( cmd && *cmd == '!' )
- cmd++;
- if( G_SayArgc() < 2 + skiparg )
- {
- ADMP( va( "^3!%s: ^7usage: !%s [name|slot#]\n", cmd, cmd ) );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
- {
- G_MatchOnePlayer( pids, found, err, sizeof( err ) );
- ADMP( va( "^3!%s: ^7%s\n", cmd, err ) );
- return qfalse;
- }
- if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
- {
- ADMP( va( "^3!%s: ^7sorry, but your intended victim has a higher admin"
- " level than you\n", cmd ) );
- return qfalse;
- }
- vic = &g_entities[ pids[ 0 ] ];
- if( vic->client->pers.muted == qtrue )
- {
- if( !Q_stricmp( cmd, "mute" ) )
- {
- ADMP( "^3!mute: ^7player is already muted\n" );
- return qtrue;
- }
- vic->client->pers.muted = qfalse;
- CPx( pids[ 0 ], "cp \"^1You have been unmuted\"" );
- AP( va( "print \"^3!unmute: ^7%s^7 has been unmuted by %s\n\"",
- vic->client->pers.netname,
- ( ent ) ? ent->client->pers.netname : "console" ) );
- }
- else
- {
- if( !Q_stricmp( cmd, "unmute" ) )
- {
- ADMP( "^3!unmute: ^7player is not currently muted\n" );
- return qtrue;
- }
- vic->client->pers.muted = qtrue;
- CPx( pids[ 0 ], "cp \"^1You've been muted\"" );
- AP( va( "print \"^3!mute: ^7%s^7 has been muted by ^7%s\n\"",
- vic->client->pers.netname,
- ( ent ) ? ent->client->pers.netname : "console" ) );
- }
- return qtrue;
-}
-
-
-
-qboolean G_admin_listadmins( gentity_t *ent, int skiparg )
-{
- int i, found = 0;
- char search[ MAX_NAME_LENGTH ] = {""};
- char s[ MAX_NAME_LENGTH ] = {""};
- int start = 0;
- qboolean numeric = qtrue;
- int drawn = 0;
-
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( g_admin_admins[ i ]->level == 0 )
- continue;
- found++;
- }
- if( !found )
- {
- ADMP( "^3!listadmins: ^7no admins defined\n" );
- return qfalse;
- }
-
- if( G_SayArgc() == 2 + skiparg )
- {
- G_SayArgv( 1 + skiparg, s, sizeof( s ) );
- for( i = 0; i < sizeof( s ) && s[ i ]; i++ )
- {
- if( isdigit( s[ i ] ) )
- continue;
- numeric = qfalse;
- }
- if( numeric )
- {
- start = atoi( s );
- if( start > 0 )
- start -= 1;
- else if( start < 0 )
- start = found + start;
- }
- else
- G_SanitiseString( s, search, sizeof( search ) );
- }
-
- if( start >= found || start < 0 )
- start = 0;
-
- if( start >= found )
- {
- ADMP( va( "^3!listadmins: ^7listing %d admins\n", found ) );
- return qfalse;
- }
-
- drawn = admin_listadmins( ent, start, search );
-
- if( search[ 0 ] )
- {
- ADMP( va( "^3!listadmins:^7 found %d admins matching '%s^7'\n",
- drawn, search ) );
- }
- else
- {
- ADMBP_begin();
- ADMBP( va( "^3!listadmins:^7 showing admin %d - %d of %d. ",
- ( found ) ? ( start + 1 ) : 0,
- ( ( start + MAX_ADMIN_LISTITEMS ) > found ) ?
- found : ( start + MAX_ADMIN_LISTITEMS ),
- found ) );
- if( ( start + MAX_ADMIN_LISTITEMS ) < found )
- {
- ADMBP( va( "run '!listadmins %d' to see more",
- ( start + MAX_ADMIN_LISTITEMS + 1 ) ) );
- }
- ADMBP( "\n" );
- ADMBP_end();
- }
- return qtrue;
-}
-
-
-qboolean G_admin_listplayers( gentity_t *ent, int skiparg )
-{
- int i, j;
- gclient_t *p;
- char c[ 3 ], t[ 2 ]; // color and team letter
- char n[ MAX_NAME_LENGTH ] = {""};
- char n2[ MAX_NAME_LENGTH ] = {""};
- char n3[ MAX_NAME_LENGTH ] = {""};
- char lname[ MAX_NAME_LENGTH ];
- char guid_stub[ 9 ];
- char muted[ 2 ];
- int l;
-
- ADMBP_begin();
- ADMBP( va( "^3!listplayers: ^7%d players connected:\n",
- level.numConnectedClients ) );
- for( i = 0; i < level.maxclients; i++ )
- {
- p = &level.clients[ i ];
- Q_strncpyz( t, "S", sizeof( t ) );
- Q_strncpyz( c, S_COLOR_YELLOW, sizeof( c ) );
- if( p->sess.sessionTeam == TEAM_BLUE )
- {
- Q_strncpyz( t, "B", sizeof( t ) );
- Q_strncpyz( c, S_COLOR_BLUE, sizeof( c ) );
- }
- else if( p->sess.sessionTeam == TEAM_RED )
- {
- Q_strncpyz( t, "R", sizeof( t ) );
- Q_strncpyz( c, S_COLOR_RED, sizeof( c ) );
- }
- else if( p->sess.sessionTeam == TEAM_FREE )
- {
- Q_strncpyz( t, "F", sizeof( t ) );
- Q_strncpyz( c, S_COLOR_GREEN, sizeof( c ) );
- }
- else if( p->sess.sessionTeam == TEAM_NONE )
- {
- Q_strncpyz( t, "S", sizeof( t ) );
- Q_strncpyz( c, S_COLOR_WHITE, sizeof( c ) );
- }
- if( p->pers.connected == CON_CONNECTING )
- {
- Q_strncpyz( t, "C", sizeof( t ) );
- Q_strncpyz( c, S_COLOR_CYAN, sizeof( c ) );
- }
- else if( p->pers.connected != CON_CONNECTED )
- {
- continue;
- }
-
- for( j = 0; j < 8; j++ )
- guid_stub[ j ] = p->pers.guid[ j + 24 ];
- guid_stub[ j ] = '\0';
-
- muted[ 0 ] = '\0';
- if( p->pers.muted )
- {
- Q_strncpyz( muted, "M", sizeof( muted ) );
- }
- //Put DisOriented Junk Here!!!
-
- l = 0;
- G_SanitiseString( p->pers.netname, n2, sizeof( n2 ) );
- n[ 0 ] = '\0';
- for( j = 0; j < MAX_ADMIN_ADMINS && g_admin_admins[ j ]; j++ )
- {
- if( !Q_stricmp( g_admin_admins[ j ]->guid, p->pers.guid ) )
- {
- // don't gather aka or level info if the admin is incognito
- if( ent && G_admin_permission( &g_entities[ i ], ADMF_INCOGNITO ) )
- {
- break;
- }
- l = g_admin_admins[ j ]->level;
- G_SanitiseString( g_admin_admins[ j ]->name, n3, sizeof( n3 ) );
- if( Q_stricmp( n2, n3 ) )
- {
- Q_strncpyz( n, g_admin_admins[ j ]->name, sizeof( n ) );
- }
- break;
- }
- }
- lname[ 0 ] = '\0';
- for( j = 0; j < MAX_ADMIN_LEVELS && g_admin_levels[ j ]; j++ )
- {
- if( g_admin_levels[ j ]->level == l )
- {
- int k, colorlen;
-
- for( colorlen = k = 0; g_admin_levels[ j ]->name[ k ]; k++ )
- if( Q_IsColorString( &g_admin_levels[ j ]->name[ k ] ) )
- colorlen += 2;
- Com_sprintf( lname, sizeof( lname ), "%*s",
- admin_level_maxname + colorlen,
- g_admin_levels[ j ]->name );
- break;
- }
- }
-
- ADMBP( va( "%2i %s%s^7 %-2i %s^7 (*%s) ^1%1s^7 %s^7 %s%s^7%s\n",
- i,
- c,
- t,
- l,
- lname,
- guid_stub,
- muted,
- p->pers.netname,
- ( *n ) ? "(a.k.a. " : "",
- n,
- ( *n ) ? ")" : "" ) );
- }
- ADMBP_end();
- return qtrue;
-}
-
-qboolean G_admin_showbans( gentity_t *ent, int skiparg )
-{
- int i, found = 0;
- int max = -1, count;
- int t;
- char duration[ 32 ];
- int max_name = 1, max_banner = 1, colorlen;
- int len;
- int secs;
- int start = 0;
- char filter[ MAX_NAME_LENGTH ] = {""};
- char date[ 11 ];
- char *made;
- int j, k;
- char n1[ MAX_NAME_LENGTH * 2 ] = {""};
- char n2[ MAX_NAME_LENGTH * 2 ] = {""};
- qboolean numeric = qtrue;
- char *ip_match = NULL;
- int ip_match_len = 0;
- char name_match[ MAX_NAME_LENGTH ] = {""};
-
- t = trap_RealTime( NULL );
-
- for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
- {
- if( g_admin_bans[ i ]->expires != 0 &&
- ( g_admin_bans[ i ]->expires - t ) < 1 )
- {
- continue;
- }
- found++;
- max = i;
- }
-
- if( max < 0 )
- {
- ADMP( "^3!showbans: ^7no bans to display\n" );
- return qfalse;
- }
-
- if( G_SayArgc() >= 2 + skiparg )
- {
- G_SayArgv( 1 + skiparg, filter, sizeof( filter ) );
- if( G_SayArgc() >= 3 + skiparg )
- {
- start = atoi( filter );
- G_SayArgv( 2 + skiparg, filter, sizeof( filter ) );
- }
- for( i = 0; i < sizeof( filter ) && filter[ i ] ; i++ )
- {
- if( !isdigit( filter[ i ] ) &&
- filter[ i ] != '.' && filter[ i ] != '-' )
- {
- numeric = qfalse;
- break;
- }
- }
- if( !numeric )
- {
- G_SanitiseString( filter, name_match, sizeof( name_match ) );
- }
- else if( strchr( filter, '.' ) )
- {
- ip_match = filter;
- ip_match_len = strlen(ip_match);
- }
- else
- {
- start = atoi( filter );
- filter[ 0 ] = '\0';
- }
- // showbans 1 means start with ban 0
- if( start > 0 )
- start--;
- else if( start < 0 )
- {
- for( i = max, count = 0; i >= 0 && count < -start; i-- )
- if( g_admin_bans[ i ]->expires == 0 ||
- ( g_admin_bans[ i ]->expires - t ) > 0 )
- count++;
- start = i + 1;
- }
- }
-
- if( start < 0 )
- start = 0;
-
- if( start > max )
- {
- ADMP( va( "^3!showbans: ^7%d is the last valid ban\n", max + 1 ) );
- return qfalse;
- }
-
- for( i = start, count = 0; i <= max && count < MAX_ADMIN_SHOWBANS; i++ )
- {
- if( g_admin_bans[ i ]->expires != 0 &&
- ( g_admin_bans[ i ]->expires - t ) < 1 )
- continue;
-
- if( name_match[ 0 ] )
- {
- G_SanitiseString( g_admin_bans[ i ]->name, n1, sizeof( n1 ) );
- if( !strstr( n1, name_match) )
- continue;
- }
- if( ip_match &&
- Q_strncmp( ip_match, g_admin_bans[ i ]->ip, ip_match_len ) )
- continue;
-
- count++;
-
- len = Q_PrintStrlen( g_admin_bans[ i ]->name );
- if( len > max_name )
- max_name = len;
- len = Q_PrintStrlen( g_admin_bans[ i ]->banner );
- if( len > max_banner )
- max_banner = len;
- }
-
- ADMBP_begin();
- for( i = start, count = 0; i <= max && count < MAX_ADMIN_SHOWBANS; i++ )
- {
- if( g_admin_bans[ i ]->expires != 0 &&
- ( g_admin_bans[ i ]->expires - t ) < 1 )
- continue;
-
- if( name_match[ 0 ] )
- {
- G_SanitiseString( g_admin_bans[ i ]->name, n1, sizeof( n1 ) );
- if( !strstr( n1, name_match) )
- continue;
- }
- if( ip_match &&
- Q_strncmp( ip_match, g_admin_bans[ i ]->ip, ip_match_len ) )
- continue;
-
- count++;
-
- // only print out the the date part of made
- date[ 0 ] = '\0';
- made = g_admin_bans[ i ]->made;
- for( j = 0; made && *made; j++ )
- {
- if( ( j + 1 ) >= sizeof( date ) )
- break;
- if( *made == ' ' )
- break;
- date[ j ] = *made;
- date[ j + 1 ] = '\0';
- made++;
- }
-
- secs = ( g_admin_bans[ i ]->expires - t );
- G_admin_duration( secs, duration, sizeof( duration ) );
-
- for( colorlen = k = 0; g_admin_bans[ i ]->name[ k ]; k++ )
- if( Q_IsColorString( &g_admin_bans[ i ]->name[ k ] ) )
- colorlen += 2;
- Com_sprintf( n1, sizeof( n1 ), "%*s", max_name + colorlen,
- g_admin_bans[ i ]->name );
-
- for( colorlen = k = 0; g_admin_bans[ i ]->banner[ k ]; k++ )
- if( Q_IsColorString( &g_admin_bans[ i ]->banner[ k ] ) )
- colorlen += 2;
- Com_sprintf( n2, sizeof( n2 ), "%*s", max_banner + colorlen,
- g_admin_bans[ i ]->banner );
-
- ADMBP( va( "%4i %s^7 %-15s %-8s %s^7 %-10s\n \\__ %s\n",
- ( i + 1 ),
- n1,
- g_admin_bans[ i ]->ip,
- date,
- n2,
- duration,
- g_admin_bans[ i ]->reason ) );
- }
-
- if( name_match[ 0 ] || ip_match )
- {
- ADMBP( va( "^3!showbans:^7 found %d matching bans by %s. ",
- count,
- ( ip_match ) ? "IP" : "name" ) );
- }
- else
- {
- ADMBP( va( "^3!showbans:^7 showing bans %d - %d of %d (%d total).",
- ( found ) ? ( start + 1 ) : 0,
- i,
- max + 1,
- found ) );
- }
-
- if( i <= max )
- ADMBP( va( " run !showbans %d%s%s to see more",
- i + 1,
- ( filter[ 0 ] ) ? " " : "",
- ( filter[ 0 ] ) ? filter : "" ) );
- ADMBP( "\n" );
- ADMBP_end();
- return qtrue;
-}
-
-qboolean G_admin_help( gentity_t *ent, int skiparg )
-{
- int i;
-
- if( G_SayArgc() < 2 + skiparg )
- {
- int j = 0;
- int count = 0;
-
- ADMBP_begin();
- for( i = 0; i < adminNumCmds; i++ )
- {
- if( G_admin_permission( ent, g_admin_cmds[ i ].flag[ 0 ] ) )
- {
- ADMBP( va( "^3!%-12s", g_admin_cmds[ i ].keyword ) );
- j++;
- count++;
- }
- // show 6 commands per line
- if( j == 6 )
- {
- ADMBP( "\n" );
- j = 0;
- }
- }
- for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
- {
- if( ! admin_command_permission( ent, g_admin_commands[ i ]->command ) )
- continue;
- ADMBP( va( "^3!%-12s", g_admin_commands[ i ]->command ) );
- j++;
- count++;
- // show 6 commands per line
- if( j == 6 )
- {
- ADMBP( "\n" );
- j = 0;
- }
- }
- if( count )
- ADMBP( "\n" );
- ADMBP( va( "^3!help: ^7%i available commands\n", count ) );
- ADMBP( "run !help [^3command^7] for help with a specific command.\n" );
- ADMBP_end();
-
- return qtrue;
- }
- else
- {
- //!help param
- char param[ MAX_ADMIN_CMD_LEN ];
- char *cmd;
-
- G_SayArgv( 1 + skiparg, param, sizeof( param ) );
- cmd = ( param[0] == '!' ) ? ¶m[1] : ¶m[0];
- ADMBP_begin();
- for( i = 0; i < adminNumCmds; i++ )
- {
- if( !Q_stricmp( cmd, g_admin_cmds[ i ].keyword ) )
- {
- if( !G_admin_permission( ent, g_admin_cmds[ i ].flag[ 0 ] ) )
- {
- ADMBP( va( "^3!help: ^7you do not have permission to use '%s'\n",
- g_admin_cmds[ i ].keyword ) );
- ADMBP_end();
- return qfalse;
- }
- ADMBP( va( "^3!help: ^7help for '!%s':\n",
- g_admin_cmds[ i ].keyword ) );
- ADMBP( va( " ^3Function: ^7%s\n", g_admin_cmds[ i ].function ) );
- ADMBP( va( " ^3Syntax: ^7!%s %s\n", g_admin_cmds[ i ].keyword,
- g_admin_cmds[ i ].syntax ) );
- ADMBP( va( " ^3Flag: ^7'%c'\n", g_admin_cmds[ i ].flag[ 0 ] ) );
- ADMBP_end();
- return qtrue;
- }
- }
- for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
- {
- if( !Q_stricmp( cmd, g_admin_commands[ i ]->command ) )
- {
- if( !admin_command_permission( ent, g_admin_commands[ i ]->command ) )
- {
- ADMBP( va( "^3!help: ^7you do not have permission to use '%s'\n",
- g_admin_commands[ i ]->command ) );
- ADMBP_end();
- return qfalse;
- }
- ADMBP( va( "^3!help: ^7help for '%s':\n",
- g_admin_commands[ i ]->command ) );
- ADMBP( va( " ^3Description: ^7%s\n", g_admin_commands[ i ]->desc ) );
- ADMBP( va( " ^3Syntax: ^7!%s\n", g_admin_commands[ i ]->command ) );
- ADMBP_end();
- return qtrue;
- }
- }
- ADMBP( va( "^3!help: ^7no help found for '%s'\n", cmd ) );
- ADMBP_end();
- return qfalse;
- }
-}
-
-qboolean G_admin_admintest( gentity_t *ent, int skiparg )
-{
- int i, l = 0;
- qboolean found = qfalse;
- qboolean lname = qfalse;
-
- if( !ent )
- {
- ADMP( "^3!admintest: ^7you are on the console.\n" );
- return qtrue;
- }
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- if( !Q_stricmp( g_admin_admins[ i ]->guid, ent->client->pers.guid ) )
- {
- found = qtrue;
- break;
- }
- }
-
- if( found )
- {
- l = g_admin_admins[ i ]->level;
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- if( g_admin_levels[ i ]->level != l )
- continue;
- if( *g_admin_levels[ i ]->name )
- {
- lname = qtrue;
- break;
- }
- }
- }
- AP( va( "print \"^3!admintest: ^7%s^7 is a level %d admin %s%s^7%s\n\"",
- ent->client->pers.netname,
- l,
- ( lname ) ? "(" : "",
- ( lname ) ? g_admin_levels[ i ]->name : "",
- ( lname ) ? ")" : "" ) );
- return qtrue;
-}
-
-qboolean G_admin_allready( gentity_t *ent, int skiparg )
-{
- int i = 0;
- gclient_t *cl;
-
- if( !level.intermissiontime )
- {
- ADMP( "^3!allready: ^7this command is only valid during intermission\n" );
- return qfalse;
- }
-
- for( i = 0; i < g_maxclients.integer; i++ )
- {
- cl = level.clients + i;
- if( cl->pers.connected != CON_CONNECTED )
- continue;
-
- if( cl->sess.sessionTeam == TEAM_NONE )
- continue;
-
- cl->readyToExit = 1;
- }
- AP( va( "print \"^3!allready:^7 %s^7 says everyone is READY now\n\"",
- ( ent ) ? ent->client->pers.netname : "console" ) );
- return qtrue;
-}
-
-qboolean G_admin_cancelvote( gentity_t *ent, int skiparg )
-{
-
- if(!level.voteTime && !level.teamVoteTime[ 0 ] && !level.teamVoteTime[ 1 ] )
- {
- ADMP( "^3!cancelvote: ^7no vote in progress\n" );
- return qfalse;
- }
- level.voteNo = level.numConnectedClients;
- level.voteYes = 0;
- CheckVote( );
- level.teamVoteNo[ 0 ] = level.numConnectedClients;
- level.teamVoteYes[ 0 ] = 0;
- CheckTeamVote( TEAM_RED );
- level.teamVoteNo[ 1 ] = level.numConnectedClients;
- level.teamVoteYes[ 1 ] = 0;
- CheckTeamVote( TEAM_BLUE );
- AP( va( "print \"^3!cancelvote: ^7%s^7 decided that everyone voted No\n\"",
- ( ent ) ? ent->client->pers.netname : "console" ) );
- return qtrue;
-}
-
-qboolean G_admin_passvote( gentity_t *ent, int skiparg )
-{
- if(!level.voteTime && !level.teamVoteTime[ 0 ] && !level.teamVoteTime[ 1 ] )
- {
- ADMP( "^3!passvote: ^7no vote in progress\n" );
- return qfalse;
- }
- level.voteYes = level.numConnectedClients;
- level.voteNo = 0;
- CheckVote( );
- level.teamVoteYes[ 0 ] = level.numConnectedClients;
- level.teamVoteNo[ 0 ] = 0;
- CheckTeamVote( TEAM_RED );
- level.teamVoteYes[ 1 ] = level.numConnectedClients;
- level.teamVoteNo[ 1 ] = 0;
- CheckTeamVote( TEAM_BLUE );
- AP( va( "print \"^3!passvote: ^7%s^7 decided that everyone voted Yes\n\"",
- ( ent ) ? ent->client->pers.netname : "console" ) );
- return qtrue;
-}
-
-qboolean G_admin_spec999( gentity_t *ent, int skiparg )
-{
- int i;
- gentity_t *vic;
-
- for( i = 0; i < level.maxclients; i++ )
- {
- vic = &g_entities[ i ];
- if( !vic->client )
- continue;
- if( vic->client->pers.connected != CON_CONNECTED )
- continue;
- if( vic->client->sess.sessionTeam == TEAM_NONE )
- continue;
- if( vic->client->ps.ping == 999 )
- {
- SetTeam( vic, "spectator" );
- AP( va( "print \"^3!spec999: ^7%s^7 moved ^7%s^7 to spectators\n\"",
- ( ent ) ? ent->client->pers.netname : "console",
- vic->client->pers.netname ) );
- }
- }
- return qtrue;
-}
-
-qboolean G_admin_rename( gentity_t *ent, int skiparg )
-{
- int pids[ MAX_CLIENTS ], found;
- char name[ MAX_NAME_LENGTH ];
- char newname[ MAX_NAME_LENGTH ];
- char oldname[ MAX_NAME_LENGTH ];
- char err[ MAX_STRING_CHARS ];
- char userinfo[ MAX_INFO_STRING ];
- char *s;
- gentity_t *victim = NULL;
-
- if( G_SayArgc() < 3 + skiparg )
- {
- ADMP( "^3!rename: ^7usage: !rename [name] [newname]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- s = G_SayConcatArgs( 2 + skiparg );
- Q_strncpyz( newname, s, sizeof( newname ) );
- if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
- {
- G_MatchOnePlayer( pids, found, err, sizeof( err ) );
- ADMP( va( "^3!rename: ^7%s\n", err ) );
- return qfalse;
- }
- victim = &g_entities[ pids[ 0 ] ];
- if( !admin_higher( ent, victim ) )
- {
- ADMP( "^3!rename: ^7sorry, but your intended victim has a higher admin"
- " level than you\n" );
- return qfalse;
- }
- if( !G_admin_name_check( victim, newname, err, sizeof( err ) ) )
- {
- ADMP( va( "^3!rename: ^7%s\n", err ) );
- return qfalse;
- }
-
- //KK-OAX Since NameChanges are not going to be implemented just yet...let's ignore this.
- level.clients[ pids[ 0 ] ].pers.nameChanges--;
- level.clients[ pids[ 0 ] ].pers.nameChangeTime = 0;
-
- trap_GetUserinfo( pids[ 0 ], userinfo, sizeof( userinfo ) );
- s = Info_ValueForKey( userinfo, "name" );
- Q_strncpyz( oldname, s, sizeof( oldname ) );
- Info_SetValueForKey( userinfo, "name", newname );
- trap_SetUserinfo( pids[ 0 ], userinfo );
- ClientUserinfoChanged( pids[ 0 ] );
- AP( va( "print \"^3!rename: ^7%s^7 has been renamed to %s^7 by %s\n\"",
- oldname,
- newname,
- ( ent ) ? ent->client->pers.netname : "console" ) );
- return qtrue;
-}
-
-//KK-Will Fix this For OAPub
-qboolean G_admin_restart( gentity_t *ent, int skiparg )
-{
- char layout[ MAX_CVAR_VALUE_STRING ] = { "" };
-
- if( G_SayArgc( ) > 1 + skiparg )
- {
- char map[ MAX_QPATH ];
-
- trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) );
- G_SayArgv( skiparg + 1, layout, sizeof( layout ) );
-
- }
-
- trap_SendConsoleCommand( EXEC_APPEND, "map_restart" );
- AP( va( "print \"^3!restart: ^7map restarted by %s \n\"",
- ( ent ) ? ent->client->pers.netname : "console" ) );
- return qtrue;
-}
-
-qboolean G_admin_nextmap( gentity_t *ent, int skiparg )
-{
- AP( va( "print \"^3!nextmap: ^7%s^7 decided to load the next map\n\"",
- ( ent ) ? ent->client->pers.netname : "console" ) );
- //level.lastWin = TEAM_NONE;
- //trap_SetConfigstring( CS_WINNER, "NextMap" );
- LogExit( va( "nextmap was run by %s", ( ent ) ? ent->client->pers.netname : "console" ) );
- return qtrue;
-}
-
-qboolean G_admin_namelog( gentity_t *ent, int skiparg )
-{
- int i, j;
- char search[ MAX_NAME_LENGTH ] = {""};
- char s2[ MAX_NAME_LENGTH ] = {""};
- char n2[ MAX_NAME_LENGTH ] = {""};
- char guid_stub[ 9 ];
- qboolean found = qfalse;
- int printed = 0;
-
- if( G_SayArgc() > 1 + skiparg )
- {
- G_SayArgv( 1 + skiparg, search, sizeof( search ) );
- G_SanitiseString( search, s2, sizeof( s2 ) );
- }
- ADMBP_begin();
- for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
- {
- if( search[ 0 ] )
- {
- found = qfalse;
- for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES &&
- g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
- {
- G_SanitiseString( g_admin_namelog[ i ]->name[ j ], n2, sizeof( n2 ) );
- if( strstr( n2, s2 ) )
- {
- found = qtrue;
- break;
- }
- }
- if( !found )
- continue;
- }
- printed++;
- for( j = 0; j < 8; j++ )
- guid_stub[ j ] = g_admin_namelog[ i ]->guid[ j + 24 ];
- guid_stub[ j ] = '\0';
- if( g_admin_namelog[ i ]->slot > -1 )
- ADMBP( "^3" );
- ADMBP( va( "%-2s (*%s) %15s^7",
- ( g_admin_namelog[ i ]->slot > -1 ) ?
- va( "%d", g_admin_namelog[ i ]->slot ) : "-",
- guid_stub, g_admin_namelog[ i ]->ip ) );
- for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES &&
- g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )
- {
- ADMBP( va( " '%s^7'", g_admin_namelog[ i ]->name[ j ] ) );
- }
- ADMBP( "\n" );
- }
- ADMBP( va( "^3!namelog:^7 %d recent clients found\n", printed ) );
- ADMBP_end();
- return qtrue;
-}
-
-qboolean G_admin_lock( gentity_t *ent, int skiparg )
-{
- char teamName[2] = {""};
- team_t team;
-
- if( G_SayArgc() < 2 + skiparg )
- {
- ADMP( "^3!lock: ^7usage: !lock [r|b|f]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, teamName, sizeof( teamName ) );
- team = G_TeamFromString( teamName );
-
- if( team == TEAM_RED )
- {
- if( level.RedTeamLocked )
- {
- ADMP( "^3!lock: ^7the Red team is already locked\n" );
- return qfalse;
- }
- level.RedTeamLocked = qtrue;
- }
- else if( team == TEAM_BLUE ) {
- if( level.BlueTeamLocked )
- {
- ADMP( "^3!lock: ^7the Blue team is already locked\n" );
- return qfalse;
- }
- level.BlueTeamLocked = qtrue;
- }
- else if(team == TEAM_FREE ) {
- if( level.FFALocked )
- {
- ADMP( "^3!lock: ^7DeathMatch is already Locked!!!\n" );
- return qfalse;
- }
- level.FFALocked = qtrue;
- }
- else
- {
- ADMP( va( "^3!lock: ^7invalid team\"%c\"\n", teamName[0] ) );
- return qfalse;
- }
-
- AP( va( "print \"^3!lock: ^7the %s team has been locked by %s\n\"",
- BG_TeamName( team ),
- ( ent ) ? ent->client->pers.netname : "console" ) );
- return qtrue;
-}
-
-qboolean G_admin_unlock( gentity_t *ent, int skiparg )
-{
- char teamName[2] = {""};
- team_t team;
-
- if( G_SayArgc() < 2 + skiparg )
- {
- ADMP( "^3!unlock: ^7usage: !unlock [r|b|f]\n" );
- return qfalse;
- }
- G_SayArgv( 1 + skiparg, teamName, sizeof( teamName ) );
- team = G_TeamFromString( teamName );
-
- if( team == TEAM_RED )
- {
- if( !level.RedTeamLocked )
- {
- ADMP( "^3!unlock: ^7the Red team is not currently locked\n" );
- return qfalse;
- }
- level.RedTeamLocked = qfalse;
- }
- else if( team == TEAM_BLUE ) {
- if( !level.BlueTeamLocked )
- {
- ADMP( "^3!unlock: ^7the Blue team is not currently locked\n" );
- return qfalse;
- }
- level.BlueTeamLocked = qfalse;
- }
- else if( team == TEAM_FREE ) {
- if( !level.FFALocked )
- {
- ADMP( "^!unlock: ^7Deathmatch is not currently Locked!!!\n" );
- return qfalse;
- }
- level.FFALocked = qfalse;
- }
- else
- {
- ADMP( va( "^3!unlock: ^7invalid team\"%c\"\n", teamName[0] ) );
- return qfalse;
- }
- AP( va( "print \"^3!unlock: ^7the %s team has been unlocked by %s\n\"",
- BG_TeamName( team ),
- ( ent ) ? ent->client->pers.netname : "console" ) );
- return qtrue;
-}
-//KK-OAX Begin Addition
-qboolean G_admin_disorient(gentity_t *ent, int skiparg)
-{
- int pids[MAX_CLIENTS], found;
- char name[MAX_NAME_LENGTH], err[MAX_STRING_CHARS];
- char *reason;
- gentity_t *vic;
-
- if(G_SayArgc() < 2+skiparg) {
- ADMP("^/disorient usage: ^7!disorient [name|slot#] [reason]");
- return qfalse;
- }
- G_SayArgv(1+skiparg, name, sizeof(name));
- reason = G_SayConcatArgs(2+skiparg);
-
- if((found = G_ClientNumbersFromString(name, pids, MAX_CLIENTS)) != 1) {
- G_MatchOnePlayer(pids, found, err, sizeof(err));
- ADMP(va("^/disorient: ^7%s", err));
- return qfalse;
- }
- vic = &g_entities[pids[0]];
- if(!admin_higher(ent, vic)) {
- ADMP("^/disorient: ^7sorry, but your intended victim has a higher admin level than you do");
- return qfalse;
- }
-
- if(!(vic->client->sess.sessionTeam == TEAM_RED ||
- vic->client->sess.sessionTeam == TEAM_BLUE ||
- vic->client->sess.sessionTeam == TEAM_FREE )) {
- ADMP("^/disorient: ^7player must be on a team");
- return qfalse;
- }
- if(vic->client->pers.disoriented) {
- ADMP(va("^/disorient: ^7%s^7 is already disoriented",
- vic->client->pers.netname));
- return qfalse;
- }
- vic->client->pers.disoriented = qtrue;
- AP(va("chat \"^/disorient: ^7%s ^7is disoriented\" -1",
- vic->client->pers.netname));
-
- CPx(pids[0], va("cp \"%s ^7disoriented you%s%s\"",
- (ent?ent->client->pers.netname:"^3SERVER CONSOLE"),
- (*reason) ? " because:\n" : "",
- (*reason) ? reason : ""));
- return qtrue;
-}
-qboolean G_admin_orient(gentity_t *ent, int skiparg)
-{
- int pids[MAX_CLIENTS], found;
- char name[MAX_NAME_LENGTH], err[MAX_STRING_CHARS];
- gentity_t *vic;
-
- if(G_SayArgc() < 2+skiparg) {
- ADMP("^/orient usage: ^7!orient [name|slot#]");
- return qfalse;
- }
- G_SayArgv(1+skiparg, name, sizeof(name));
- //Fix
- if((found = G_ClientNumbersFromString(name, pids, MAX_CLIENTS)) != 1) {
- G_MatchOnePlayer(pids, found, err, sizeof(err));
- ADMP(va("^/orient: ^7%s", err));
- return qfalse;
- }
- vic = &g_entities[pids[0]];
-
- if(!vic->client->pers.disoriented) {
- ADMP(va("^/orient: ^7%s^7 is not currently disoriented",
- vic->client->pers.netname));
- return qfalse;
- }
- vic->client->pers.disoriented = qfalse;
- AP(va("chat \"^/orient: ^7%s ^7is no longer disoriented\" -1",
- vic->client->pers.netname));
-
- CPx(pids[0], va("cp \"%s ^7oriented you\"",
- (ent?ent->client->pers.netname:"^3SERVER CONSOLE")));
- return qtrue;
-}
-
-qboolean G_admin_slap( gentity_t *ent, int skiparg )
-{
- int pids[MAX_CLIENTS], found, dmg;
- char name[MAX_NAME_LENGTH], err[MAX_STRING_CHARS];
- char *reason;
- char damage[4];
- gentity_t *vic;
- int soundIndex;
-
- //KK-Too many Parameters Check removed. It'll truncate the reason message.
-
- if(G_SayArgc() < 2+skiparg)
- {
- ADMP("^/slap usage: ^7!slap [name|slot#] [reason] [damage]");
- return qfalse;
- }
-
- G_SayArgv(1+skiparg, name, sizeof(name));
- G_SayArgv(2+skiparg, damage, sizeof(damage));
-
- dmg = atoi(damage);
- if(!dmg)
- {
- dmg = 25;
- reason = G_SayConcatArgs(2+skiparg);
- }
- else
- {
- reason = G_SayConcatArgs(3+skiparg);
- }
-
- if((found = G_ClientNumbersFromString(name, pids, MAX_CLIENTS)) != 1) {
- G_MatchOnePlayer(pids, found, err, sizeof(err));
- ADMP(va("^/slap: ^7%s", err));
- return qfalse;
- }
-
- vic = &g_entities[pids[0]];
- if(!admin_higher(ent, vic)) {
- ADMP("^/slap: ^7sorry, but your intended victim has a higher admin level than you do");
- return qfalse;
- }
-
- if(!(vic->client->sess.sessionTeam == TEAM_RED ||
- vic->client->sess.sessionTeam == TEAM_BLUE ||
- vic->client->sess.sessionTeam == TEAM_FREE )) {
- ADMP("^/slap: ^7player must be in the game!");
- return qfalse;
- }
- //Player Not Alive
- if( vic->health < 1 )
- {
- //Is Their Body Alive?
- if(vic->s.eType != ET_INVISIBLE)
- {
- //Make 'em a Bloody mess
- G_Damage(vic, NULL, NULL, NULL, NULL, 500, 0, MOD_UNKNOWN);
- }
- //Force Their Butt to Respawn
- ClientSpawn( vic );
- }
- // Will the Slap Kill them? (Obviously false if we Respawned 'em)
- if(!(vic->health > dmg ))
- {
- vic->health = 1;
- }
- else //If it won't kill em...Do the full Damage
- {
- vic->health -= dmg;
- }
-
- //KK-OAX Play them the slap sound
- soundIndex = G_SoundIndex("sound/admin/slap.wav");
- G_Sound(vic, CHAN_VOICE, soundIndex );
-
- //Print it to everybody
- AP(va("chat \"^/slap: ^7%s ^7was slapped\" -1", vic->client->pers.netname));
- //CenterPrint it to the Person Being Slapped
- CPx(pids[0], va("cp \"%s ^7slapped you%s%s\"",
- (ent?ent->client->pers.netname:"^3SERVER CONSOLE"),
- (*reason) ? " because:\n" : "",
- (*reason) ? reason : ""));
- return qtrue;
-}
-
-
-//Called Each Time a Warning is Created
-int G_admin_warn_check( gentity_t *ent )
-{
- char *ip, *guid;
- int i;
- int t;
- int numWarnings = 0;
-
- t = trap_RealTime( NULL );
-
- ip = ent->client->pers.ip;
-
- //We Don't Want to Count Warnings for the LocalHost
- if( !*ip )
- return 0;
-
- guid = ent->client->pers.guid;
-
- //Just to make sure...Don't want to crash...Will Figure something better out later
- if( !*guid )
- return 0;
-
- //For Each Warning, up to the max number of warnings
- for( i = 0; i < MAX_ADMIN_WARNINGS && g_admin_warnings[ i ]; i++ )
- {
- // Ignore Expired Warnings
- if( ( g_admin_warnings[ i ]->expires - t ) < 1 )
- continue;
- //If a warning matches their IP or GUID
- if( strstr( ip, g_admin_warnings[ i ]->ip ) || strstr( guid, g_admin_warnings[ i ]->guid ))
- {
- numWarnings++;
- }
- }
- //If we get here, return the number of warnings;
- return numWarnings;
-}
-
-
-qboolean G_admin_warn( gentity_t *ent, int skiparg )
-{
- int pids[MAX_CLIENTS], found;
- int seconds;
- char name[ MAX_NAME_LENGTH ], err[MAX_STRING_CHARS];
- char *reason;
- int minargc;
- char duration[ 32 ];
- char s2[ MAX_NAME_LENGTH ];
- gentity_t *vic;
- int totalWarnings;
- int soundIndex;
-
- if( G_admin_permission( ent, ADMF_UNACCOUNTABLE ) )
- {
- minargc = 1 + skiparg;
- }
- else
- {
- minargc = 2 + skiparg;
- }
-
- if( G_SayArgc() < minargc )
- {
- ADMP( "^3!warn: ^7usage: !warn [name|slot|ip] [reason]\n" );
- return qfalse;
- }
-
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- G_SanitiseString( name, s2, sizeof( s2 ) );
- reason = G_SayConcatArgs(2+skiparg);
-
- seconds = g_warningExpire.integer;
-
- if((found = G_ClientNumbersFromString(name, pids, MAX_CLIENTS)) != 1) {
- G_MatchOnePlayer(pids, found, err, sizeof(err));
- ADMP(va("^/warn: ^7%s", err));
- return qfalse;
- }
-
- vic = &g_entities[pids[0]];
- if(!admin_higher(ent, vic)) {
- ADMP("^/slap: ^7sorry, but your intended victim has a higher admin level than you do");
- return qfalse;
- }
-
- G_admin_duration( ( seconds ) ? seconds : -1,
- duration, sizeof( duration ) );
-
- admin_create_warning( ent,
- vic->client->pers.netname,
- vic->client->pers.guid,
- vic->client->pers.ip,
- seconds, reason );
-
- if( !g_admin.string[ 0 ] )
- ADMP( "^3!warn: ^7WARNING g_admin not set, not saving warning to a file\n" );
- else
- admin_writeconfig();
-
- //KK, Use The Check Warnings Deal Here
- totalWarnings = G_admin_warn_check( vic );
-
- // Play the whistle
- soundIndex = G_SoundIndex("sound/admin/whistle.wav");
- G_GlobalSound( soundIndex );
-
- //First Check to make sure g_maxWarnings isn't a Null Value
- if( g_maxWarnings.integer )
- {
- //If they have gone over the max number of warnings...
- if( totalWarnings >= g_maxWarnings.integer )
- {
- //Give them The Boot till the Warning Expires
- admin_create_ban( ent,
- vic->client->pers.netname,
- vic->client->pers.guid,
- vic->client->pers.ip,
- seconds,
- "Too Many Warnings" );
-
- if( g_admin.string[ 0 ] )
- admin_writeconfig();
-
- trap_SendServerCommand( pids[ 0 ],
- va( "disconnect \"You have been kicked.\n%s^7\nreason:\n%s\"",
- ( ent ) ? va( "admin:\n%s", ent->client->pers.netname ) : "SERVER",
- "Too Many Warnings" ) );
-
- trap_DropClient( pids[ 0 ], va( "has been kicked%s^7. reason: %s",
- "Auto-Admin System",
- "Too Many Warnings" ) );
- return qtrue;
- }
- else
- {
-
- //Print it to everybody
- AP(va("chat \"^/warn: ^7%s ^7was warned\" -1", vic->client->pers.netname));
- //CenterPrint it to the Person Being Slapped
- CPx(pids[0], va("cp \"%s ^7warned you%s%s\"",
- (ent?ent->client->pers.netname:"^3SERVER CONSOLE"),
- (*reason) ? " because:\n" : "",
- (*reason) ? reason : ""));
- return qtrue;
- }
- }
- else //KK-OAX g_maxWarnings is null or 0
- {
- AP(va("chat \"^/warn: ^7%s ^7was warned\" -1", vic->client->pers.netname));
- //CenterPrint it to the Person Being Slapped
- CPx(pids[0], va("cp \"%s ^7warned you%s%s\"",
- (ent?ent->client->pers.netname:"^3SERVER CONSOLE"),
- (*reason) ? " because:\n" : "",
- (*reason) ? reason : ""));
- return qtrue;
- }
-
-}
-
-qboolean G_admin_shuffle( gentity_t *ent, int skipargs )
-{
- trap_SendConsoleCommand( EXEC_APPEND, "shuffle" );
- AP( va( "print \"^3!shuffle: ^7teams shuffled by %s \n\"",
- ( ent ) ? ent->client->pers.netname : "console" ) );
- return qtrue;
-}
-
-//KK-OAX End Additions
-
-/*
-================
- G_admin_print
-
- This function facilitates the ADMP define. ADMP() is similar to CP except
- that it prints the message to the server console if ent is not defined.
-================
-*/
-void G_admin_print( gentity_t *ent, char *m )
-{
- if( ent )
- trap_SendServerCommand( ent - level.gentities, va( "print \"%s\"", m ) );
- else
- {
- char m2[ MAX_STRING_CHARS ];
- if( !trap_Cvar_VariableIntegerValue( "com_ansiColor" ) )
- {
- G_DecolorString( m, m2, sizeof( m2 ) );
- trap_Printf( m2 );
- }
- else
- trap_Printf( m );
- }
-}
-
-void G_admin_buffer_begin()
-{
- g_bfb[ 0 ] = '\0';
-}
-
-void G_admin_buffer_end( gentity_t *ent )
-{
- ADMP( g_bfb );
-}
-
-void G_admin_buffer_print( gentity_t *ent, char *m )
-{
- // 1022 - strlen("print 64 \"\"") - 1
- if( strlen( m ) + strlen( g_bfb ) >= 1009 )
- {
- ADMP( g_bfb );
- g_bfb[ 0 ] = '\0';
- }
- Q_strcat( g_bfb, sizeof( g_bfb ), m );
-}
-
-
-void G_admin_cleanup()
-{
- int i = 0;
-
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- BG_Free( g_admin_levels[ i ] );
- g_admin_levels[ i ] = NULL;
- }
- for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
- {
- BG_Free( g_admin_admins[ i ] );
- g_admin_admins[ i ] = NULL;
- }
- for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
- {
- BG_Free( g_admin_bans[ i ] );
- g_admin_bans[ i ] = NULL;
- }
- for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )
- {
- BG_Free( g_admin_commands[ i ] );
- g_admin_commands[ i ] = NULL;
- }
-}
-
-
-
diff --git a/game/code/game/g_arenas.c b/game/code/game/g_arenas.c
deleted file mode 100644
index 7dcbab9..0000000
--- a/game/code/game/g_arenas.c
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-//
-// g_arenas.c
-//
-
-#include "g_local.h"
-
-
-gentity_t *podium1;
-gentity_t *podium2;
-gentity_t *podium3;
-
-
-/*
-==================
-UpdateTournamentInfo
-==================
-*/
-void UpdateTournamentInfo( void ) {
- int i;
- gentity_t *player;
- int playerClientNum;
- int n, accuracy, perfect, msglen;
- int buflen;
-#ifdef MISSIONPACK // bk001205
- int score1, score2;
- qboolean won;
-#endif
- char buf[32];
- char msg[MAX_STRING_CHARS];
-
- // find the real player
- player = NULL;
- for (i = 0; i < level.maxclients; i++ ) {
- player = &g_entities[i];
- if ( !player->inuse ) {
- continue;
- }
- if ( !( player->r.svFlags & SVF_BOT ) ) {
- break;
- }
- }
- // this should never happen!
- if ( !player || i == level.maxclients ) {
- return;
- }
- playerClientNum = i;
-
- CalculateRanks();
-
- if ( level.clients[playerClientNum].sess.sessionTeam == TEAM_SPECTATOR ) {
-#ifdef MISSIONPACK
- Com_sprintf( msg, sizeof(msg), "postgame %i %i 0 0 0 0 0 0 0 0 0 0 0", level.numNonSpectatorClients, playerClientNum );
-#else
- Com_sprintf( msg, sizeof(msg), "postgame %i %i 0 0 0 0 0 0", level.numNonSpectatorClients, playerClientNum );
-#endif
- }
- else {
- if( player->client->accuracy_shots ) {
- accuracy = player->client->accuracy_hits * 100 / player->client->accuracy_shots;
- }
- else {
- accuracy = 0;
- }
-#ifdef MISSIONPACK
- won = qfalse;
- if (g_gametype.integer >= GT_CTF && g_ffa_gt==0) {
- score1 = level.teamScores[TEAM_RED];
- score2 = level.teamScores[TEAM_BLUE];
- if (level.clients[playerClientNum].sess.sessionTeam == TEAM_RED) {
- won = (level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE]);
- } else {
- won = (level.teamScores[TEAM_BLUE] > level.teamScores[TEAM_RED]);
- }
- } else {
- if (&level.clients[playerClientNum] == &level.clients[ level.sortedClients[0] ]) {
- won = qtrue;
- score1 = level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE];
- score2 = level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE];
- } else {
- score2 = level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE];
- score1 = level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE];
- }
- }
- if (won && player->client->ps.persistant[PERS_KILLED] == 0) {
- perfect = 1;
- } else {
- perfect = 0;
- }
- Com_sprintf( msg, sizeof(msg), "postgame %i %i %i %i %i %i %i %i %i %i %i %i %i %i", level.numNonSpectatorClients, playerClientNum, accuracy,
- player->client->ps.persistant[PERS_IMPRESSIVE_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT],player->client->ps.persistant[PERS_DEFEND_COUNT],
- player->client->ps.persistant[PERS_ASSIST_COUNT], player->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE],
- perfect, score1, score2, level.time, player->client->ps.persistant[PERS_CAPTURES] );
-
-#else
- perfect = ( level.clients[playerClientNum].ps.persistant[PERS_RANK] == 0 && player->client->ps.persistant[PERS_KILLED] == 0 ) ? 1 : 0;
- Com_sprintf( msg, sizeof(msg), "postgame %i %i %i %i %i %i %i %i", level.numNonSpectatorClients, playerClientNum, accuracy,
- player->client->ps.persistant[PERS_IMPRESSIVE_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT],
- player->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE],
- perfect );
-#endif
- }
-
- msglen = strlen( msg );
- for( i = 0; i < level.numNonSpectatorClients; i++ ) {
- n = level.sortedClients[i];
- Com_sprintf( buf, sizeof(buf), " %i %i %i", n, level.clients[n].ps.persistant[PERS_RANK], level.clients[n].ps.persistant[PERS_SCORE] );
- buflen = strlen( buf );
- if( msglen + buflen + 1 >= sizeof(msg) ) {
- break;
- }
- strcat( msg, buf );
- }
- trap_SendConsoleCommand( EXEC_APPEND, msg );
-}
-
-
-static gentity_t *SpawnModelOnVictoryPad( gentity_t *pad, vec3_t offset, gentity_t *ent, int place ) {
- gentity_t *body;
- vec3_t vec;
- vec3_t f, r, u;
-
- body = G_Spawn();
- if ( !body ) {
- G_Printf( S_COLOR_RED "ERROR: out of gentities\n" );
- return NULL;
- }
-
- body->classname = ent->client->pers.netname;
- body->client = ent->client;
- body->s = ent->s;
- body->s.eType = ET_PLAYER; // could be ET_INVISIBLE
- body->s.eFlags = 0; // clear EF_TALK, etc
- body->s.powerups = 0; // clear powerups
- body->s.loopSound = 0; // clear lava burning
- body->s.number = body - g_entities;
- body->timestamp = level.time;
- body->physicsObject = qtrue;
- body->physicsBounce = 0; // don't bounce
- body->s.event = 0;
- body->s.pos.trType = TR_STATIONARY;
- body->s.groundEntityNum = ENTITYNUM_WORLD;
- body->s.legsAnim = LEGS_IDLE;
- body->s.torsoAnim = TORSO_STAND;
- if( body->s.weapon == WP_NONE ) {
- body->s.weapon = WP_MACHINEGUN;
- }
- if( body->s.weapon == WP_GAUNTLET) {
- body->s.torsoAnim = TORSO_STAND2;
- }
- body->s.event = 0;
- body->r.svFlags = ent->r.svFlags;
- VectorCopy (ent->r.mins, body->r.mins);
- VectorCopy (ent->r.maxs, body->r.maxs);
- VectorCopy (ent->r.absmin, body->r.absmin);
- VectorCopy (ent->r.absmax, body->r.absmax);
- body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
- body->r.contents = CONTENTS_BODY;
- body->r.ownerNum = ent->r.ownerNum;
- body->takedamage = qfalse;
-
- VectorSubtract( level.intermission_origin, pad->r.currentOrigin, vec );
- vectoangles( vec, body->s.apos.trBase );
- body->s.apos.trBase[PITCH] = 0;
- body->s.apos.trBase[ROLL] = 0;
-
- AngleVectors( body->s.apos.trBase, f, r, u );
- VectorMA( pad->r.currentOrigin, offset[0], f, vec );
- VectorMA( vec, offset[1], r, vec );
- VectorMA( vec, offset[2], u, vec );
-
- G_SetOrigin( body, vec );
-
- trap_LinkEntity (body);
-
- body->count = place;
-
- return body;
-}
-
-
-static void CelebrateStop( gentity_t *player ) {
- int anim;
-
- if( player->s.weapon == WP_GAUNTLET) {
- anim = TORSO_STAND2;
- }
- else {
- anim = TORSO_STAND;
- }
- player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-}
-
-
-#define TIMER_GESTURE (34*66+50)
-static void CelebrateStart( gentity_t *player ) {
- player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | TORSO_GESTURE;
- player->nextthink = level.time + TIMER_GESTURE;
- player->think = CelebrateStop;
-
- /*
- player->client->ps.events[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = EV_TAUNT;
- player->client->ps.eventParms[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = 0;
- player->client->ps.eventSequence++;
- */
- G_AddEvent(player, EV_TAUNT, 0);
-}
-
-
-static vec3_t offsetFirst = {0, 0, 74};
-static vec3_t offsetSecond = {-10, 60, 54};
-static vec3_t offsetThird = {-19, -60, 45};
-
-static void PodiumPlacementThink( gentity_t *podium ) {
- vec3_t vec;
- vec3_t origin;
- vec3_t f, r, u;
-
- podium->nextthink = level.time + 100;
-
- AngleVectors( level.intermission_angle, vec, NULL, NULL );
- VectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( "g_podiumDist" ), vec, origin );
- origin[2] -= trap_Cvar_VariableIntegerValue( "g_podiumDrop" );
- G_SetOrigin( podium, origin );
-
- if( podium1 ) {
- VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
- vectoangles( vec, podium1->s.apos.trBase );
- podium1->s.apos.trBase[PITCH] = 0;
- podium1->s.apos.trBase[ROLL] = 0;
-
- AngleVectors( podium1->s.apos.trBase, f, r, u );
- VectorMA( podium->r.currentOrigin, offsetFirst[0], f, vec );
- VectorMA( vec, offsetFirst[1], r, vec );
- VectorMA( vec, offsetFirst[2], u, vec );
-
- G_SetOrigin( podium1, vec );
- }
-
- if( podium2 ) {
- VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
- vectoangles( vec, podium2->s.apos.trBase );
- podium2->s.apos.trBase[PITCH] = 0;
- podium2->s.apos.trBase[ROLL] = 0;
-
- AngleVectors( podium2->s.apos.trBase, f, r, u );
- VectorMA( podium->r.currentOrigin, offsetSecond[0], f, vec );
- VectorMA( vec, offsetSecond[1], r, vec );
- VectorMA( vec, offsetSecond[2], u, vec );
-
- G_SetOrigin( podium2, vec );
- }
-
- if( podium3 ) {
- VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
- vectoangles( vec, podium3->s.apos.trBase );
- podium3->s.apos.trBase[PITCH] = 0;
- podium3->s.apos.trBase[ROLL] = 0;
-
- AngleVectors( podium3->s.apos.trBase, f, r, u );
- VectorMA( podium->r.currentOrigin, offsetThird[0], f, vec );
- VectorMA( vec, offsetThird[1], r, vec );
- VectorMA( vec, offsetThird[2], u, vec );
-
- G_SetOrigin( podium3, vec );
- }
-}
-
-
-static gentity_t *SpawnPodium( void ) {
- gentity_t *podium;
- vec3_t vec;
- vec3_t origin;
-
- podium = G_Spawn();
- if ( !podium ) {
- return NULL;
- }
-
- podium->classname = "podium";
- podium->s.eType = ET_GENERAL;
- podium->s.number = podium - g_entities;
- podium->clipmask = CONTENTS_SOLID;
- podium->r.contents = CONTENTS_SOLID;
- podium->s.modelindex = G_ModelIndex( SP_PODIUM_MODEL );
-
- AngleVectors( level.intermission_angle, vec, NULL, NULL );
- VectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( "g_podiumDist" ), vec, origin );
- origin[2] -= trap_Cvar_VariableIntegerValue( "g_podiumDrop" );
- G_SetOrigin( podium, origin );
-
- VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
- podium->s.apos.trBase[YAW] = vectoyaw( vec );
- trap_LinkEntity (podium);
-
- podium->think = PodiumPlacementThink;
- podium->nextthink = level.time + 100;
- return podium;
-}
-
-
-/*
-==================
-SpawnModelsOnVictoryPads
-==================
-*/
-void SpawnModelsOnVictoryPads( void ) {
- gentity_t *player;
- gentity_t *podium;
-
- podium1 = NULL;
- podium2 = NULL;
- podium3 = NULL;
-
- podium = SpawnPodium();
-
- player = SpawnModelOnVictoryPad( podium, offsetFirst, &g_entities[level.sortedClients[0]],
- level.clients[ level.sortedClients[0] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
- if ( player ) {
- player->nextthink = level.time + 2000;
- player->think = CelebrateStart;
- podium1 = player;
- }
-
- player = SpawnModelOnVictoryPad( podium, offsetSecond, &g_entities[level.sortedClients[1]],
- level.clients[ level.sortedClients[1] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
- if ( player ) {
- podium2 = player;
- }
-
- if ( level.numNonSpectatorClients > 2 ) {
- player = SpawnModelOnVictoryPad( podium, offsetThird, &g_entities[level.sortedClients[2]],
- level.clients[ level.sortedClients[2] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
- if ( player ) {
- podium3 = player;
- }
- }
-}
-
-
-/*
-===============
-Svcmd_AbortPodium_f
-===============
-*/
-void Svcmd_AbortPodium_f( void ) {
- if( g_gametype.integer != GT_SINGLE_PLAYER ) {
- return;
- }
-
- if( podium1 ) {
- podium1->nextthink = level.time;
- podium1->think = CelebrateStop;
- }
-}
diff --git a/game/code/game/g_bot.c b/game/code/game/g_bot.c
deleted file mode 100644
index 3fcf082..0000000
--- a/game/code/game/g_bot.c
+++ /dev/null
@@ -1,1026 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// g_bot.c
-
-#include "g_local.h"
-
-
-static int g_numBots;
-static char *g_botInfos[MAX_BOTS];
-
-
-int g_numArenas;
-static char *g_arenaInfos[MAX_ARENAS];
-
-
-#define BOT_BEGIN_DELAY_BASE 2000
-#define BOT_BEGIN_DELAY_INCREMENT 1500
-
-#define BOT_SPAWN_QUEUE_DEPTH 16
-
-typedef struct {
- int clientNum;
- int spawnTime;
-} botSpawnQueue_t;
-
-//static int botBeginDelay = 0; // bk001206 - unused, init
-static botSpawnQueue_t botSpawnQueue[BOT_SPAWN_QUEUE_DEPTH];
-
-vmCvar_t bot_minplayers;
-
-extern gentity_t *podium1;
-extern gentity_t *podium2;
-extern gentity_t *podium3;
-
-float trap_Cvar_VariableValue( const char *var_name ) {
- char buf[128];
-
- trap_Cvar_VariableStringBuffer(var_name, buf, sizeof(buf));
- return atof(buf);
-}
-
-
-
-/*
-===============
-G_ParseInfos
-===============
-*/
-int G_ParseInfos( char *buf, int max, char *infos[] ) {
- char *token;
- int count;
- char key[MAX_TOKEN_CHARS];
- char info[MAX_INFO_STRING];
-
- count = 0;
-
- while ( 1 ) {
- token = COM_Parse( &buf );
- if ( !token[0] ) {
- break;
- }
- if ( strcmp( token, "{" ) ) {
- Com_Printf( "Missing { in info file\n" );
- break;
- }
-
- if ( count == max ) {
- Com_Printf( "Max infos exceeded\n" );
- break;
- }
-
- info[0] = '\0';
- while ( 1 ) {
- token = COM_ParseExt( &buf, qtrue );
- if ( !token[0] ) {
- Com_Printf( "Unexpected end of info file\n" );
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- Q_strncpyz( key, token, sizeof( key ) );
-
- token = COM_ParseExt( &buf, qfalse );
- if ( !token[0] ) {
- strcpy( token, "<NULL>" );
- }
- Info_SetValueForKey( info, key, token );
- }
- if(!BG_CanAlloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1))
- break; //Not enough memory. Don't even try
- //NOTE: extra space for arena number
- //KK-OAX Changed to Tremulous's BG_Alloc
- infos[count] = BG_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
- if (infos[count]) {
- strcpy(infos[count], info);
- count++;
- }
- }
- return count;
-}
-
-/*
-===============
-G_LoadArenasFromFile
-===============
-*/
-static void G_LoadArenasFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_ARENAS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Printf( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_ARENAS_TEXT ) {
- trap_Printf( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_ARENAS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- g_numArenas += G_ParseInfos( buf, MAX_ARENAS - g_numArenas, &g_arenaInfos[g_numArenas] );
-}
-
-/*
-===============
-G_LoadArenas
-===============
-*/
-static void G_LoadArenas( void ) {
- int numdirs;
- vmCvar_t arenasFile;
- char filename[128];
- char dirlist[1024];
- char* dirptr;
- int i, n;
- int dirlen;
-
- g_numArenas = 0;
-
- trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
- if( *arenasFile.string ) {
- G_LoadArenasFromFile(arenasFile.string);
- }
- else {
- G_LoadArenasFromFile("scripts/arenas.txt");
- }
-
- // get all arenas from .arena files
- numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- G_LoadArenasFromFile(filename);
- }
- trap_Printf( va( "%i arenas parsed\n", g_numArenas ) );
-
- for( n = 0; n < g_numArenas; n++ ) {
- Info_SetValueForKey( g_arenaInfos[n], "num", va( "%i", n ) );
- }
-}
-
-
-/*
-===============
-G_GetArenaInfoByNumber
-===============
-*/
-const char *G_GetArenaInfoByMap( const char *map ) {
- int n;
-
- for( n = 0; n < g_numArenas; n++ ) {
- if( Q_stricmp( Info_ValueForKey( g_arenaInfos[n], "map" ), map ) == 0 ) {
- return g_arenaInfos[n];
- }
- }
-
- return NULL;
-}
-
-
-/*
-=================
-PlayerIntroSound
-=================
-*/
-static void PlayerIntroSound( const char *modelAndSkin ) {
- char model[MAX_QPATH];
- char *skin;
-
- Q_strncpyz( model, modelAndSkin, sizeof(model) );
- skin = Q_strrchr( model, '/' );
- if ( skin ) {
- *skin++ = '\0';
- }
- else {
- skin = model;
- }
-
- if( Q_stricmp( skin, "default" ) == 0 ) {
- skin = model;
- }
-
- trap_SendConsoleCommand( EXEC_APPEND, va( "play sound/player/announce/%s.wav\n", skin ) );
-}
-
-/*
-===============
-G_AddRandomBot
-===============
-*/
-void G_AddRandomBot( int team ) {
- int i, n, num;
- float skill;
- char *value, netname[36], *teamstr;
- gclient_t *cl;
-
- if (!trap_AAS_Initialized())
- return; //If no AAS then don't even try
-
- num = 0;
- for ( n = 0; n < g_numBots ; n++ ) {
- value = Info_ValueForKey( g_botInfos[n], "name" );
- //
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
- continue;
- }
- if ( team >= 0 && cl->sess.sessionTeam != team ) {
- continue;
- }
- if ( !Q_stricmp( value, cl->pers.netname ) ) {
- break;
- }
- }
- if (i >= g_maxclients.integer) {
- num++;
- }
- }
- num = random() * num;
- for ( n = 0; n < g_numBots ; n++ ) {
- value = Info_ValueForKey( g_botInfos[n], "name" );
- //
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
- continue;
- }
- if ( team >= 0 && cl->sess.sessionTeam != team ) {
- continue;
- }
- if ( !Q_stricmp( value, cl->pers.netname ) ) {
- break;
- }
- }
- if (i >= g_maxclients.integer) {
- num--;
- if (num <= 0) {
- skill = trap_Cvar_VariableValue( "g_spSkill" );
- if (team == TEAM_RED) teamstr = "red";
- else if (team == TEAM_BLUE) teamstr = "blue";
- else teamstr = "";
- strncpy(netname, value, sizeof(netname)-1);
- netname[sizeof(netname)-1] = '\0';
- Q_CleanStr(netname);
- trap_SendConsoleCommand( EXEC_INSERT, va("addbot %s %f %s %i\n", netname, skill, teamstr, 0) );
- return;
- }
- }
- }
-}
-
-/*
-===============
-G_RemoveRandomBot
-===============
-*/
-int G_RemoveRandomBot( int team ) {
- int i;
- gclient_t *cl;
-
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
- continue;
- }
- if ( team >= 0 && cl->sess.sessionTeam != team ) {
- continue;
- }
- trap_SendConsoleCommand( EXEC_INSERT, va("clientkick %d\n", cl->ps.clientNum) );
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-===============
-G_CountHumanPlayers
-===============
-*/
-int G_CountHumanPlayers( int team ) {
- int i, num;
- gclient_t *cl;
-
- num = 0;
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT ) {
- continue;
- }
- if ( team >= 0 && cl->sess.sessionTeam != team ) {
- continue;
- }
- num++;
- }
- return num;
-}
-
-/*
-===============
-G_CountBotPlayers
-===============
-*/
-int G_CountBotPlayers( int team ) {
- int i, n, num;
- gclient_t *cl;
-
- num = 0;
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
- continue;
- }
- if ( team >= 0 && cl->sess.sessionTeam != team ) {
- continue;
- }
- num++;
- }
- for( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {
- if( !botSpawnQueue[n].spawnTime ) {
- continue;
- }
- if ( botSpawnQueue[n].spawnTime > level.time ) {
- continue;
- }
- num++;
- }
- return num;
-}
-
-/*
-===============
-G_CheckMinimumPlayers
-===============
-*/
-void G_CheckMinimumPlayers( void ) {
- int minplayers;
- int humanplayers, botplayers;
- static int checkminimumplayers_time;
-
- if (level.intermissiontime) return;
- //only check once each 10 seconds
- if (checkminimumplayers_time > level.time - 10000) {
- return;
- }
- checkminimumplayers_time = level.time;
- trap_Cvar_Update(&bot_minplayers);
- minplayers = bot_minplayers.integer;
- if (minplayers <= 0) return;
-
- if (!trap_AAS_Initialized())
- {
- minplayers = 0;
- checkminimumplayers_time = level.time+600*1000;
- return; //If no AAS then don't even try
- }
-
- if (g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
- if (minplayers >= g_maxclients.integer / 2) {
- minplayers = (g_maxclients.integer / 2) -1;
- }
-
- humanplayers = G_CountHumanPlayers( TEAM_RED );
- botplayers = G_CountBotPlayers( TEAM_RED );
- //
- if (humanplayers + botplayers < minplayers) {
- G_AddRandomBot( TEAM_RED );
- } else if (humanplayers + botplayers > minplayers && botplayers) {
- G_RemoveRandomBot( TEAM_RED );
- }
- //
- humanplayers = G_CountHumanPlayers( TEAM_BLUE );
- botplayers = G_CountBotPlayers( TEAM_BLUE );
- //
- if (humanplayers + botplayers < minplayers) {
- G_AddRandomBot( TEAM_BLUE );
- } else if (humanplayers + botplayers > minplayers && botplayers) {
- G_RemoveRandomBot( TEAM_BLUE );
- }
- }
- else if (g_gametype.integer == GT_TOURNAMENT ) {
- if (minplayers >= g_maxclients.integer) {
- minplayers = g_maxclients.integer-1;
- }
- humanplayers = G_CountHumanPlayers( -1 );
- botplayers = G_CountBotPlayers( -1 );
- //
- if (humanplayers + botplayers < minplayers) {
- G_AddRandomBot( TEAM_FREE );
- } else if (humanplayers + botplayers > minplayers && botplayers) {
- // try to remove spectators first
- if (!G_RemoveRandomBot( TEAM_SPECTATOR )) {
- // just remove the bot that is playing
- G_RemoveRandomBot( -1 );
- }
- }
- }
- else if (g_gametype.integer == GT_FFA || g_gametype.integer == GT_LMS) {
- if (minplayers >= g_maxclients.integer) {
- minplayers = g_maxclients.integer-1;
- }
- humanplayers = G_CountHumanPlayers( TEAM_FREE );
- botplayers = G_CountBotPlayers( TEAM_FREE );
- //
- if (humanplayers + botplayers < minplayers) {
- G_AddRandomBot( TEAM_FREE );
- } else if (humanplayers + botplayers > minplayers && botplayers) {
- G_RemoveRandomBot( TEAM_FREE );
- }
- }
-}
-
-/*
-===============
-G_CheckBotSpawn
-===============
-*/
-void G_CheckBotSpawn( void ) {
- int n;
- char userinfo[MAX_INFO_VALUE];
-
- G_CheckMinimumPlayers();
-
- for( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {
- if( !botSpawnQueue[n].spawnTime ) {
- continue;
- }
- if ( botSpawnQueue[n].spawnTime > level.time ) {
- continue;
- }
- ClientBegin( botSpawnQueue[n].clientNum );
- botSpawnQueue[n].spawnTime = 0;
-
- if( g_gametype.integer == GT_SINGLE_PLAYER ) {
- trap_GetUserinfo( botSpawnQueue[n].clientNum, userinfo, sizeof(userinfo) );
- PlayerIntroSound( Info_ValueForKey (userinfo, "model") );
- }
- }
-}
-
-
-/*
-===============
-AddBotToSpawnQueue
-===============
-*/
-static void AddBotToSpawnQueue( int clientNum, int delay ) {
- int n;
-
- for( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {
- if( !botSpawnQueue[n].spawnTime ) {
- botSpawnQueue[n].spawnTime = level.time + delay;
- botSpawnQueue[n].clientNum = clientNum;
- return;
- }
- }
- G_Printf( S_COLOR_YELLOW "Unable to delay spawn\n" );
- ClientBegin( clientNum );
-}
-
-
-/*
-===============
-G_RemoveQueuedBotBegin
-
-Called on client disconnect to make sure the delayed spawn
-doesn't happen on a freed index
-===============
-*/
-void G_RemoveQueuedBotBegin( int clientNum ) {
- int n;
-
- for( n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++ ) {
- if( botSpawnQueue[n].clientNum == clientNum ) {
- botSpawnQueue[n].spawnTime = 0;
- return;
- }
- }
-}
-
-
-/*
-===============
-G_BotConnect
-===============
-*/
-qboolean G_BotConnect( int clientNum, qboolean restart ) {
- bot_settings_t settings;
- char userinfo[MAX_INFO_STRING];
-
- trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
-
- Q_strncpyz( settings.characterfile, Info_ValueForKey( userinfo, "characterfile" ), sizeof(settings.characterfile) );
- settings.skill = atof( Info_ValueForKey( userinfo, "skill" ) );
- Q_strncpyz( settings.team, Info_ValueForKey( userinfo, "team" ), sizeof(settings.team) );
-
- if (!trap_AAS_Initialized() || !BotAISetupClient( clientNum, &settings, restart )) {
- trap_DropClient( clientNum, "BotAISetupClient failed" );
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-===============
-G_AddBot
-===============
-*/
-static void G_AddBot( const char *name, float skill, const char *team, int delay, char *altname) {
- int clientNum;
- char *botinfo;
- gentity_t *bot;
- char *key;
- char *s;
- char *botname;
- char *model;
- char *headmodel;
- char userinfo[MAX_INFO_STRING];
-
- // get the botinfo from bots.txt
- botinfo = G_GetBotInfoByName( name );
- if ( !botinfo ) {
- G_Printf( S_COLOR_RED "Error: Bot '%s' not defined\n", name );
- return;
- }
-
- // create the bot's userinfo
- userinfo[0] = '\0';
-
- botname = Info_ValueForKey( botinfo, "funname" );
- if( !botname[0] ) {
- botname = Info_ValueForKey( botinfo, "name" );
- }
- // check for an alternative name
- if (altname && altname[0]) {
- botname = altname;
- }
- Info_SetValueForKey( userinfo, "name", botname );
- Info_SetValueForKey( userinfo, "rate", "25000" );
- Info_SetValueForKey( userinfo, "snaps", "20" );
- Info_SetValueForKey( userinfo, "skill", va("%1.2f", skill) );
-
- if ( skill >= 1 && skill < 2 ) {
- Info_SetValueForKey( userinfo, "handicap", "50" );
- }
- else if ( skill >= 2 && skill < 3 ) {
- Info_SetValueForKey( userinfo, "handicap", "70" );
- }
- else if ( skill >= 3 && skill < 4 ) {
- Info_SetValueForKey( userinfo, "handicap", "90" );
- }
-
- key = "model";
- model = Info_ValueForKey( botinfo, key );
- if ( !*model ) {
- model = "sarge/default";
- }
- Info_SetValueForKey( userinfo, key, model );
- key = "team_model";
- Info_SetValueForKey( userinfo, key, model );
-
- key = "headmodel";
- headmodel = Info_ValueForKey( botinfo, key );
- if ( !*headmodel ) {
- headmodel = model;
- }
- Info_SetValueForKey( userinfo, key, headmodel );
- key = "team_headmodel";
- Info_SetValueForKey( userinfo, key, headmodel );
-
- key = "gender";
- s = Info_ValueForKey( botinfo, key );
- if ( !*s ) {
- s = "male";
- }
- Info_SetValueForKey( userinfo, "sex", s );
-
- key = "color1";
- s = Info_ValueForKey( botinfo, key );
- if ( !*s ) {
- s = "4";
- }
- Info_SetValueForKey( userinfo, key, s );
-
- key = "color2";
- s = Info_ValueForKey( botinfo, key );
- if ( !*s ) {
- s = "5";
- }
- Info_SetValueForKey( userinfo, key, s );
-
- s = Info_ValueForKey(botinfo, "aifile");
- if (!*s ) {
- trap_Printf( S_COLOR_RED "Error: bot has no aifile specified\n" );
- return;
- }
-
- // have the server allocate a client slot
- clientNum = trap_BotAllocateClient();
- if ( clientNum == -1 ) {
- G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" );
- G_Printf( S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n" );
- return;
- }
-
- // initialize the bot settings
- if( !team || !*team ) {
- if( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
- if( PickTeam(clientNum) == TEAM_RED) {
- team = "red";
- }
- else {
- team = "blue";
- }
- }
- else {
- team = "red";
- }
- }
- Info_SetValueForKey( userinfo, "characterfile", Info_ValueForKey( botinfo, "aifile" ) );
- Info_SetValueForKey( userinfo, "skill", va( "%5.2f", skill ) );
- Info_SetValueForKey( userinfo, "team", team );
-
- bot = &g_entities[ clientNum ];
- bot->r.svFlags |= SVF_BOT;
- bot->inuse = qtrue;
-
- // register the userinfo
- trap_SetUserinfo( clientNum, userinfo );
-
- // have it connect to the game as a normal client
- if ( ClientConnect( clientNum, qtrue, qtrue ) ) {
- return;
- }
-
- if( delay == 0 ) {
- ClientBegin( clientNum );
- return;
- }
-
- AddBotToSpawnQueue( clientNum, delay );
-}
-
-
-/*
-===============
-Svcmd_AddBot_f
-===============
-*/
-void Svcmd_AddBot_f( void ) {
- float skill;
- int delay;
- char name[MAX_TOKEN_CHARS];
- char altname[MAX_TOKEN_CHARS];
- char string[MAX_TOKEN_CHARS];
- char team[MAX_TOKEN_CHARS];
-
- // are bots enabled?
- if ( !trap_Cvar_VariableIntegerValue( "bot_enable" ) || !trap_AAS_Initialized() ) {
- return;
- }
-
- // name
- trap_Argv( 1, name, sizeof( name ) );
- if ( !name[0] ) {
- trap_Printf( "Usage: Addbot <botname> [skill 1-5] [team] [msec delay] [altname]\n" );
- return;
- }
-
- // skill
- trap_Argv( 2, string, sizeof( string ) );
- if ( !string[0] ) {
- skill = 4;
- }
- else {
- skill = atof( string );
- }
-
- // team
- trap_Argv( 3, team, sizeof( team ) );
-
- // delay
- trap_Argv( 4, string, sizeof( string ) );
- if ( !string[0] ) {
- delay = 0;
- }
- else {
- delay = atoi( string );
- }
-
- // alternative name
- trap_Argv( 5, altname, sizeof( altname ) );
-
- G_AddBot( name, skill, team, delay, altname );
-
- // if this was issued during gameplay and we are playing locally,
- // go ahead and load the bot's media immediately
- if ( level.time - level.startTime > 1000 &&
- trap_Cvar_VariableIntegerValue( "cl_running" ) ) {
- trap_SendServerCommand( -1, "loaddefered\n" ); // FIXME: spelled wrong, but not changing for demo
- }
-}
-
-/*
-===============
-Svcmd_BotList_f
-===============
-*/
-void Svcmd_BotList_f( void ) {
- int i;
- char name[MAX_TOKEN_CHARS];
- char funname[MAX_TOKEN_CHARS];
- char model[MAX_TOKEN_CHARS];
- char aifile[MAX_TOKEN_CHARS];
-
- trap_Printf("^1name model aifile funname\n");
- for (i = 0; i < g_numBots; i++) {
- strcpy(name, Info_ValueForKey( g_botInfos[i], "name" ));
- if ( !*name ) {
- strcpy(name, "UnnamedPlayer");
- }
- strcpy(funname, Info_ValueForKey( g_botInfos[i], "funname" ));
- if ( !*funname ) {
- strcpy(funname, "");
- }
- strcpy(model, Info_ValueForKey( g_botInfos[i], "model" ));
- if ( !*model ) {
- strcpy(model, "sarge/default");
- }
- strcpy(aifile, Info_ValueForKey( g_botInfos[i], "aifile"));
- if (!*aifile ) {
- strcpy(aifile, "bots/default_c.c");
- }
- trap_Printf(va("%-16s %-16s %-20s %-20s\n", name, model, aifile, funname));
- }
-}
-
-
-/*
-===============
-G_SpawnBots
-===============
-*/
-static void G_SpawnBots( char *botList, int baseDelay ) {
- char *bot;
- char *p;
- float skill;
- int delay;
- char bots[MAX_INFO_VALUE];
-
- podium1 = NULL;
- podium2 = NULL;
- podium3 = NULL;
-
- skill = trap_Cvar_VariableValue( "g_spSkill" );
- if( skill < 1 ) {
- trap_Cvar_Set( "g_spSkill", "1" );
- skill = 1;
- }
- else if ( skill > 5 ) {
- trap_Cvar_Set( "g_spSkill", "5" );
- skill = 5;
- }
-
- Q_strncpyz( bots, botList, sizeof(bots) );
- p = &bots[0];
- delay = baseDelay;
- while( *p ) {
- //skip spaces
- while( *p && *p == ' ' ) {
- p++;
- }
- if( !p ) {
- break;
- }
-
- // mark start of bot name
- bot = p;
-
- // skip until space of null
- while( *p && *p != ' ' ) {
- p++;
- }
- if( *p ) {
- *p++ = 0;
- }
-
- // we must add the bot this way, calling G_AddBot directly at this stage
- // does "Bad Things"
- trap_SendConsoleCommand( EXEC_INSERT, va("addbot %s %f free %i\n", bot, skill, delay) );
-
- delay += BOT_BEGIN_DELAY_INCREMENT;
- }
-}
-
-
-/*
-===============
-G_LoadBotsFromFile
-===============
-*/
-static void G_LoadBotsFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_BOTS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Printf( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_BOTS_TEXT ) {
- trap_Printf( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- g_numBots += G_ParseInfos( buf, MAX_BOTS - g_numBots, &g_botInfos[g_numBots] );
-}
-
-/*
-===============
-G_LoadBots
-===============
-*/
-static void G_LoadBots( void ) {
- vmCvar_t botsFile;
- int numdirs;
- char filename[128];
- char dirlist[1024];
- char* dirptr;
- int i;
- int dirlen;
-
- if ( !trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
- return;
- }
-
- g_numBots = 0;
-
- trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
- if( *botsFile.string ) {
- G_LoadBotsFromFile(botsFile.string);
- }
- else {
- G_LoadBotsFromFile("scripts/bots.txt");
- }
-
- // get all bots from .bot files
- numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- G_LoadBotsFromFile(filename);
- }
- trap_Printf( va( "%i bots parsed\n", g_numBots ) );
-}
-
-
-
-/*
-===============
-G_GetBotInfoByNumber
-===============
-*/
-char *G_GetBotInfoByNumber( int num ) {
- if( num < 0 || num >= g_numBots ) {
- trap_Printf( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
- return NULL;
- }
- return g_botInfos[num];
-}
-
-
-/*
-===============
-G_GetBotInfoByName
-===============
-*/
-char *G_GetBotInfoByName( const char *name ) {
- int n;
- char *value;
-
- for ( n = 0; n < g_numBots ; n++ ) {
- value = Info_ValueForKey( g_botInfos[n], "name" );
- if ( !Q_stricmp( value, name ) ) {
- return g_botInfos[n];
- }
- }
-
- return NULL;
-}
-
-/*
-===============
-G_InitBots
-===============
-*/
-void G_InitBots( qboolean restart ) {
- int fragLimit;
- int timeLimit;
- const char *arenainfo;
- char *strValue;
- int basedelay;
- char map[MAX_QPATH];
- char serverinfo[MAX_INFO_STRING];
-
- G_LoadBots();
- G_LoadArenas();
-
- trap_Cvar_Register( &bot_minplayers, "bot_minplayers", "0", CVAR_SERVERINFO );
-
- if( g_gametype.integer == GT_SINGLE_PLAYER ) {
- trap_GetServerinfo( serverinfo, sizeof(serverinfo) );
- Q_strncpyz( map, Info_ValueForKey( serverinfo, "mapname" ), sizeof(map) );
- arenainfo = G_GetArenaInfoByMap( map );
- if ( !arenainfo ) {
- return;
- }
-
- strValue = Info_ValueForKey( arenainfo, "fraglimit" );
- fragLimit = atoi( strValue );
- if ( fragLimit ) {
- trap_Cvar_Set( "fraglimit", strValue );
- }
- else {
- trap_Cvar_Set( "fraglimit", "0" );
- }
-
- strValue = Info_ValueForKey( arenainfo, "timelimit" );
- timeLimit = atoi( strValue );
- if ( timeLimit ) {
- trap_Cvar_Set( "timelimit", strValue );
- }
- else {
- trap_Cvar_Set( "timelimit", "0" );
- }
-
- if ( !fragLimit && !timeLimit ) {
- trap_Cvar_Set( "fraglimit", "10" );
- trap_Cvar_Set( "timelimit", "0" );
- }
-
- basedelay = BOT_BEGIN_DELAY_BASE;
- strValue = Info_ValueForKey( arenainfo, "special" );
- if( Q_stricmp( strValue, "training" ) == 0 ) {
- basedelay += 10000;
- }
-
- if( !restart ) {
- G_SpawnBots( Info_ValueForKey( arenainfo, "bots" ), basedelay );
- }
- }
-}
diff --git a/game/code/game/g_client.c b/game/code/game/g_client.c
deleted file mode 100644
index 0804028..0000000
--- a/game/code/game/g_client.c
+++ /dev/null
@@ -1,2173 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-// g_client.c -- client functions that don't happen every frame
-
-static vec3_t playerMins = {-15, -15, -24};
-static vec3_t playerMaxs = {15, 15, 32};
-
-/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32) initial
-potential spawning position for deathmatch games.
-The first time a player enters the game, they will be at an 'initial' spot.
-Targets will be fired when someone spawns in on them.
-"nobots" will prevent bots from using this spot.
-"nohumans" will prevent non-bots from using this spot.
-*/
-void SP_info_player_deathmatch( gentity_t *ent ) {
- int i;
-
- G_SpawnInt( "nobots", "0", &i);
- if ( i ) {
- ent->flags |= FL_NO_BOTS;
- }
- G_SpawnInt( "nohumans", "0", &i );
- if ( i ) {
- ent->flags |= FL_NO_HUMANS;
- }
-}
-
-/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
-equivelant to info_player_deathmatch
-*/
-void SP_info_player_start(gentity_t *ent) {
- ent->classname = "info_player_deathmatch";
- SP_info_player_deathmatch( ent );
-}
-
-//Three for Double_D
-void SP_info_player_dd(gentity_t *ent) {
-}
-void SP_info_player_dd_red(gentity_t *ent) {
-}
-void SP_info_player_dd_blue(gentity_t *ent) {
-}
-
-//One for Standard Domination, not really a player spawn point
-void SP_domination_point(gentity_t *ent) {
-}
-
-/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)
-The intermission will be viewed from this point. Target an info_notnull for the view direction.
-*/
-void SP_info_player_intermission( gentity_t *ent ) {
-
-}
-
-
-
-/*
-=======================================================================
-
- SelectSpawnPoint
-
-=======================================================================
-*/
-
-/*
-================
-SpotWouldTelefrag
-
-================
-*/
-qboolean SpotWouldTelefrag( gentity_t *spot ) {
- int i, num;
- int touch[MAX_GENTITIES];
- gentity_t *hit;
- vec3_t mins, maxs;
-
- VectorAdd( spot->s.origin, playerMins, mins );
- VectorAdd( spot->s.origin, playerMaxs, maxs );
- num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
-
- for (i=0 ; i<num ; i++) {
- hit = &g_entities[touch[i]];
- //if ( hit->client && hit->client->ps.stats[STAT_HEALTH] > 0 ) {
- if ( hit->client) {
- return qtrue;
- }
-
- }
-
- return qfalse;
-}
-
-/*
-================
-SelectNearestDeathmatchSpawnPoint
-
-Find the spot that we DON'T want to use
-================
-*/
-#define MAX_SPAWN_POINTS 128
-gentity_t *SelectNearestDeathmatchSpawnPoint( vec3_t from ) {
- gentity_t *spot;
- vec3_t delta;
- float dist, nearestDist;
- gentity_t *nearestSpot;
-
- nearestDist = 999999;
- nearestSpot = NULL;
- spot = NULL;
-
- while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
-
- VectorSubtract( spot->s.origin, from, delta );
- dist = VectorLength( delta );
- if ( dist < nearestDist ) {
- nearestDist = dist;
- nearestSpot = spot;
- }
- }
-
- return nearestSpot;
-}
-
-
-/*
-================
-SelectRandomDeathmatchSpawnPoint
-
-go to a random point that doesn't telefrag
-================
-*/
-#define MAX_SPAWN_POINTS 128
-gentity_t *SelectRandomDeathmatchSpawnPoint( void ) {
- gentity_t *spot;
- int count;
- int selection;
- gentity_t *spots[MAX_SPAWN_POINTS];
-
- count = 0;
- spot = NULL;
-
- while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
- if ( SpotWouldTelefrag( spot ) ) {
- continue;
- }
- spots[ count ] = spot;
- count++;
- }
-
- if ( !count ) { // no spots that won't telefrag
- return G_Find( NULL, FOFS(classname), "info_player_deathmatch");
- }
-
- selection = rand() % count;
- return spots[ selection ];
-}
-
-/*
-===========
-SelectRandomFurthestSpawnPoint
-
-Chooses a player start, deathmatch start, etc
-============
-*/
-gentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) {
- gentity_t *spot;
- vec3_t delta;
- float dist;
- float list_dist[64];
- gentity_t *list_spot[64];
- int numSpots, rnd, i, j;
-
- numSpots = 0;
- spot = NULL;
-
- while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
- if ( SpotWouldTelefrag( spot ) ) {
- continue;
- }
- VectorSubtract( spot->s.origin, avoidPoint, delta );
- dist = VectorLength( delta );
- for (i = 0; i < numSpots; i++) {
- if ( dist > list_dist[i] ) {
- if ( numSpots >= 64 )
- numSpots = 64-1;
- for (j = numSpots; j > i; j--) {
- list_dist[j] = list_dist[j-1];
- list_spot[j] = list_spot[j-1];
- }
- list_dist[i] = dist;
- list_spot[i] = spot;
- numSpots++;
- if (numSpots > 64)
- numSpots = 64;
- break;
- }
- }
- if (i >= numSpots && numSpots < 64) {
- list_dist[numSpots] = dist;
- list_spot[numSpots] = spot;
- numSpots++;
- }
- }
- if (!numSpots) {
- spot = G_Find( NULL, FOFS(classname), "info_player_deathmatch");
- if (!spot)
- G_Error( "Couldn't find a spawn point" );
- VectorCopy (spot->s.origin, origin);
- origin[2] += 9;
- VectorCopy (spot->s.angles, angles);
- return spot;
- }
-
- // select a random spot from the spawn points furthest away
- rnd = random() * (numSpots / 2);
-
- VectorCopy (list_spot[rnd]->s.origin, origin);
- origin[2] += 9;
- VectorCopy (list_spot[rnd]->s.angles, angles);
-
- return list_spot[rnd];
-}
-
-/*
-===========
-SelectSpawnPoint
-
-Chooses a player start, deathmatch start, etc
-============
-*/
-gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) {
- //return SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles );
-
-
- gentity_t *spot;
- gentity_t *nearestSpot;
-
- nearestSpot = SelectNearestDeathmatchSpawnPoint( avoidPoint );
-
- spot = SelectRandomDeathmatchSpawnPoint ( );
- if ( spot == nearestSpot ) {
- // roll again if it would be real close to point of death
- spot = SelectRandomDeathmatchSpawnPoint ( );
- if ( spot == nearestSpot ) {
- // last try
- spot = SelectRandomDeathmatchSpawnPoint ( );
- }
- }
-
- // find a single player start spot
- if (!spot) {
- G_Error( "Couldn't find a spawn point" );
- }
-
- VectorCopy (spot->s.origin, origin);
- origin[2] += 9;
- VectorCopy (spot->s.angles, angles);
-
- return spot;
-}
-
-/*
-===========
-SelectInitialSpawnPoint
-
-Try to find a spawn point marked 'initial', otherwise
-use normal spawn selection.
-============
-*/
-gentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles ) {
- gentity_t *spot;
-
- spot = NULL;
- while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
- if ( spot->spawnflags & 1 ) {
- break;
- }
- }
-
- if ( !spot || SpotWouldTelefrag( spot ) ) {
- return SelectSpawnPoint( vec3_origin, origin, angles );
- }
-
- VectorCopy (spot->s.origin, origin);
- origin[2] += 9;
- VectorCopy (spot->s.angles, angles);
-
- return spot;
-}
-
-/*
-===========
-SelectSpectatorSpawnPoint
-
-============
-*/
-gentity_t *SelectSpectatorSpawnPoint( vec3_t origin, vec3_t angles ) {
- //gentity_t *spot;
-
- FindIntermissionPoint();
-
- VectorCopy( level.intermission_origin, origin );
- VectorCopy( level.intermission_angle, angles );
-
-
-
- //for some reason we need to return an specific point in elimination (this might not be neccecary anymore but to be sure...)
- //if(g_gametype.integer == GT_ELIMINATION)
- // return SelectSpawnPoint( vec3_origin, origin, angles );
-
- //VectorCopy (origin,spot->s.origin);
- //spot->s.origin[2] += 9;
- //VectorCopy (angles, spot->s.angles);
-
- return NULL; //spot;
-}
-
-/*
-=======================================================================
-
-BODYQUE
-
-=======================================================================
-*/
-
-/*
-===============
-InitBodyQue
-===============
-*/
-void InitBodyQue (void) {
- int i;
- gentity_t *ent;
-
- level.bodyQueIndex = 0;
- for (i=0; i<BODY_QUEUE_SIZE ; i++) {
- ent = G_Spawn();
- ent->classname = "bodyque";
- ent->neverFree = qtrue;
- level.bodyQue[i] = ent;
- }
-}
-
-/*
-=============
-BodySink
-
-After sitting around for five seconds, fall into the ground and dissapear
-=============
-*/
-void BodySink( gentity_t *ent ) {
- if ( level.time - ent->timestamp > 6500 ) {
- // the body ques are never actually freed, they are just unlinked
- trap_UnlinkEntity( ent );
- ent->physicsObject = qfalse;
- return;
- }
- ent->nextthink = level.time + 100;
- ent->s.pos.trBase[2] -= 1;
-}
-
-/*
-=============
-CopyToBodyQue
-
-A player is respawning, so make an entity that looks
-just like the existing corpse to leave behind.
-=============
-*/
-void CopyToBodyQue( gentity_t *ent ) {
- gentity_t *e;
- int i;
- gentity_t *body;
- int contents;
-
- trap_UnlinkEntity (ent);
-
- // if client is in a nodrop area, don't leave the body
- contents = trap_PointContents( ent->s.origin, -1 );
- if ( contents & CONTENTS_NODROP ) {
- return;
- }
-
- // grab a body que and cycle to the next one
- body = level.bodyQue[ level.bodyQueIndex ];
- level.bodyQueIndex = (level.bodyQueIndex + 1) % BODY_QUEUE_SIZE;
-
- trap_UnlinkEntity (body);
-
- body->s = ent->s;
- body->s.eFlags = EF_DEAD; // clear EF_TALK, etc
- if ( ent->s.eFlags & EF_KAMIKAZE ) {
- body->s.eFlags |= EF_KAMIKAZE;
-
- // check if there is a kamikaze timer around for this owner
- for (i = 0; i < MAX_GENTITIES; i++) {
- e = &g_entities[i];
- if (!e->inuse)
- continue;
- if (e->activator != ent)
- continue;
- if (strcmp(e->classname, "kamikaze timer"))
- continue;
- e->activator = body;
- break;
- }
- }
- body->s.powerups = 0; // clear powerups
- body->s.loopSound = 0; // clear lava burning
- body->s.number = body - g_entities;
- body->timestamp = level.time;
- body->physicsObject = qtrue;
- body->physicsBounce = 0; // don't bounce
- if ( body->s.groundEntityNum == ENTITYNUM_NONE ) {
- body->s.pos.trType = TR_GRAVITY;
- body->s.pos.trTime = level.time;
- VectorCopy( ent->client->ps.velocity, body->s.pos.trDelta );
- } else {
- body->s.pos.trType = TR_STATIONARY;
- }
- body->s.event = 0;
-
- // change the animation to the last-frame only, so the sequence
- // doesn't repeat anew for the body
- switch ( body->s.legsAnim & ~ANIM_TOGGLEBIT ) {
- case BOTH_DEATH1:
- case BOTH_DEAD1:
- body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD1;
- break;
- case BOTH_DEATH2:
- case BOTH_DEAD2:
- body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD2;
- break;
- case BOTH_DEATH3:
- case BOTH_DEAD3:
- default:
- body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD3;
- break;
- }
-
- body->r.svFlags = ent->r.svFlags;
- VectorCopy (ent->r.mins, body->r.mins);
- VectorCopy (ent->r.maxs, body->r.maxs);
- VectorCopy (ent->r.absmin, body->r.absmin);
- VectorCopy (ent->r.absmax, body->r.absmax);
-
- body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
- body->r.contents = CONTENTS_CORPSE;
- body->r.ownerNum = ent->s.number;
-
- body->nextthink = level.time + 5000;
- body->think = BodySink;
-
- body->die = body_die;
-
- // don't take more damage if already gibbed
- if ( ent->health <= GIB_HEALTH ) {
- body->takedamage = qfalse;
- } else {
- body->takedamage = qtrue;
- }
-
-
- VectorCopy ( body->s.pos.trBase, body->r.currentOrigin );
- trap_LinkEntity (body);
-}
-
-//======================================================================
-
-
-/*
-==================
-SetClientViewAngle
-
-==================
-*/
-void SetClientViewAngle( gentity_t *ent, vec3_t angle ) {
- int i;
-
- // set the delta angle
- for (i=0 ; i<3 ; i++) {
- int cmdAngle;
-
- cmdAngle = ANGLE2SHORT(angle[i]);
- ent->client->ps.delta_angles[i] = cmdAngle - ent->client->pers.cmd.angles[i];
- }
- VectorCopy( angle, ent->s.angles );
- VectorCopy (ent->s.angles, ent->client->ps.viewangles);
-}
-
-/*
-================
-respawn
-================
-*/
-void respawn( gentity_t *ent ) {
- gentity_t *tent;
-
- if((g_gametype.integer!=GT_ELIMINATION && g_gametype.integer!=GT_CTF_ELIMINATION && g_gametype.integer !=GT_LMS) && !ent->client->isEliminated)
- {
- ent->client->isEliminated = qtrue; //must not be true in warmup
- //Tried moving CopyToBodyQue
- } else {
- //Must always be false in other gametypes
- ent->client->isEliminated = qfalse;
- }
- CopyToBodyQue (ent); //Unlinks ent
-
- if(g_gametype.integer==GT_LMS) {
- if(ent->client->pers.livesLeft>0)
- {
- //ent->client->pers.livesLeft--; Coutned down somewhere else
- ent->client->isEliminated = qfalse;
- }
- else //We have used all our lives
- {
- if( ent->client->isEliminated!=qtrue) {
- ent->client->isEliminated = qtrue;
- if((g_lms_mode.integer == 2 || g_lms_mode.integer == 3) && level.roundNumber == level.roundNumberStarted)
- LMSpoint();
- //Sago: This is really bad
- //TODO: Try not to make people spectators here
- ent->client->sess.spectatorState = PM_SPECTATOR;
- //We have to force spawn imidiantly to prevent lag.
- ClientSpawn(ent);
- }
- return;
- }
- }
-
- if((g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION || g_gametype.integer==GT_LMS)
- && ent->client->ps.pm_type == PM_SPECTATOR && ent->client->ps.stats[STAT_HEALTH] > 0)
- return;
- ClientSpawn(ent);
-
- // add a teleportation effect
- if(g_gametype.integer!=GT_ELIMINATION && g_gametype.integer!=GT_CTF_ELIMINATION && g_gametype.integer!=GT_LMS)
- {
- tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );
- tent->s.clientNum = ent->s.clientNum;
- }
-}
-
-/*
-================
-respawnRound
-================
-*/
-void respawnRound( gentity_t *ent ) {
- gentity_t *tent;
-
- //if(g_gametype.integer!=GT_ELIMINATION || !ent->client->isEliminated)
- //{
- // ent->client->isEliminated = qtrue;
- //CopyToBodyQue (ent);
- //}
-
- //if(g_gametype.integer==GT_ELIMINATION && ent->client->ps.pm_type == PM_SPECTATOR && ent->client->ps.stats[STAT_HEALTH] > 0)
- // return;
- if(ent->client->hook)
- Weapon_HookFree(ent->client->hook);
- ClientSpawn(ent);
-
- // add a teleportation effect
- if(g_gametype.integer!=GT_ELIMINATION && g_gametype.integer!=GT_CTF_ELIMINATION && g_gametype.integer!=GT_LMS)
- {
- tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );
- tent->s.clientNum = ent->s.clientNum;
- }
-}
-
-/*
-================
-TeamCvarSet
-
-Sets the red and blue team client number cvars.
-================
- */
-void TeamCvarSet( void )
-{
- int i;
- qboolean redChanged = qfalse;
- qboolean blueChanged = qfalse;
- qboolean first = qtrue;
- char* temp = NULL;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
- continue;
- }
- if ( level.clients[i].sess.sessionTeam == TEAM_RED ) {
- if(first) {
- temp = va("%i",i);
- first = qfalse;
- }
- else
- temp = va("%s,%i",temp,i);
- }
- }
-
- if(Q_stricmp(g_redTeamClientNumbers.string,temp))
- redChanged = qtrue;
- trap_Cvar_Set("g_redTeamClientNumbers",temp); //Set it right
- first= qtrue;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
- continue;
- }
- if ( level.clients[i].sess.sessionTeam == TEAM_BLUE ) {
- if(first) {
- temp = va("%i",i);
- first = qfalse;
- }
- else
- temp = va("%s,%i",temp,i);
- }
- }
- if(Q_stricmp(g_blueTeamClientNumbers.string,temp))
- blueChanged = qtrue;
- trap_Cvar_Set("g_blueTeamClientNumbers",temp);
-
- //Note: We need to force update of the cvar or SendYourTeamMessage will send the old cvar value!
- if(redChanged) {
- trap_Cvar_Update(&g_redTeamClientNumbers); //Force update of CVAR
- SendYourTeamMessageToTeam(TEAM_RED);
- }
- if(blueChanged) {
- trap_Cvar_Update(&g_blueTeamClientNumbers);
- SendYourTeamMessageToTeam(TEAM_BLUE); //Force update of CVAR
- }
-}
-
-/*
-================
-TeamCount
-
-Returns number of players on a team
-================
-*/
-team_t TeamCount( int ignoreClientNum, int team ) {
- int i;
- int count = 0;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( i == ignoreClientNum ) {
- continue;
- }
- if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
- continue;
- }
-
- if ( level.clients[i].pers.connected == CON_CONNECTING) {
- continue;
- }
-
- if ( level.clients[i].sess.sessionTeam == team ) {
- count++;
- }
- }
-
- return count;
-}
-
-/*
-================
-TeamLivingCount
-
-Returns number of living players on a team
-================
-*/
-team_t TeamLivingCount( int ignoreClientNum, int team ) {
- int i;
- int count = 0;
- qboolean LMS = (g_gametype.integer==GT_LMS);
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( i == ignoreClientNum ) {
- continue;
- }
- if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
- continue;
- }
-
- if ( level.clients[i].pers.connected == CON_CONNECTING) {
- continue;
- }
- //crash if g_gametype.integer is used here, why?
- if ( level.clients[i].sess.sessionTeam == team && (level.clients[i].ps.stats[STAT_HEALTH]>0 || LMS) && !(level.clients[i].isEliminated)) {
- count++;
- }
- }
-
- return count;
-}
-
-/*
-================
-TeamHealthCount
-
-Count total number of healthpoints on teh teams used for draws in Elimination
-================
-*/
-
-team_t TeamHealthCount(int ignoreClientNum, int team ) {
- int i;
- int count = 0;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( i == ignoreClientNum ) {
- continue;
- }
- if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
- continue;
- }
-
- if ( level.clients[i].pers.connected == CON_CONNECTING) {
- continue;
- }
-
- //only count clients with positive health
- if ( level.clients[i].sess.sessionTeam == team && (level.clients[i].ps.stats[STAT_HEALTH]>0)&& !(level.clients[i].isEliminated)) {
- count+=level.clients[i].ps.stats[STAT_HEALTH];
- }
- }
-
- return count;
-}
-
-
-/*
-================
-RespawnAll
-
-Forces all clients to respawn.
-================
-*/
-
-void RespawnAll(void)
-{
- int i;
- gentity_t *client;
- for(i=0;i<level.maxclients;i++)
- {
- if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
- continue;
- }
-
- if ( level.clients[i].pers.connected == CON_CONNECTING) {
- continue;
- }
-
- if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR ) {
- continue;
- }
- client = g_entities + i;
- client->client->ps.pm_type = PM_NORMAL;
- client->client->pers.livesLeft = g_lms_lives.integer;
- respawnRound(client);
- }
- return;
-}
-
-/*
-================
-RespawnDead
-
-Forces all *DEAD* clients to respawn.
-================
-*/
-
-void RespawnDead(void)
-{
- int i;
- gentity_t *client;
- for(i=0;i<level.maxclients;i++)
- {
-
- if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
- continue;
- }
- if ( level.clients[i].pers.connected == CON_CONNECTING) {
- continue;
- }
- client = g_entities + i;
- client->client->pers.livesLeft = g_lms_lives.integer-1;
- if ( level.clients[i].isEliminated == qfalse ){
- continue;
- }
- if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR ) {
- continue;
- }
-
- client->client->pers.livesLeft = g_lms_lives.integer;
-
- respawnRound(client);
- }
- return;
-}
-
-/*
-================
-DisableWeapons
-
-disables all weapons
-================
-*/
-
-void DisableWeapons(void)
-{
- int i;
- gentity_t *client;
- for(i=0;i<level.maxclients;i++)
- {
- if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
- continue;
- }
- if ( level.clients[i].pers.connected == CON_CONNECTING) {
- continue;
- }
-
- if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR ) {
- continue;
- }
- client = g_entities + i;
- client->client->ps.pm_flags |= PMF_ELIMWARMUP;
- }
- ProximityMine_RemoveAll(); //Remove all the prox mines
- return;
-}
-
-/*
-================
-EnableWeapons
-
-enables all weapons
-================
-*/
-
-void EnableWeapons(void)
-{
- int i;
- gentity_t *client;
- for(i=0;i<level.maxclients;i++)
- {
- if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
- continue;
- }
-
- if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR ) {
- continue;
- }
-
- /*if ( level.clients[i].isEliminated == qtrue ){
- continue;
- }*/
-
- client = g_entities + i;
- client->client->ps.pm_flags &= ~PMF_ELIMWARMUP;
- }
- return;
-}
-
-/*
-================
-LMSpoint
-
-Gives a point to the lucky survivor
-================
-*/
-
-void LMSpoint(void)
-{
- int i;
- gentity_t *client;
- for(i=0;i<level.maxclients;i++)
- {
- if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
- continue;
- }
-
- if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR ) {
- continue;
- }
-
- if ( level.clients[i].isEliminated ){
- continue;
- }
-
- client = g_entities + i;
- /*
- Not good in mode 2 & 3
- if ( client->health <= 0 ){
- continue;
- }
- */
-
- client->client->ps.persistant[PERS_SCORE] += 1;
- }
-
- CalculateRanks();
- return;
-}
-
-/*
-================
-TeamLeader
-
-Returns the client number of the team leader
-================
-*/
-int TeamLeader( int team ) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
- continue;
- }
- if ( level.clients[i].sess.sessionTeam == team ) {
- if ( level.clients[i].sess.teamLeader )
- return i;
- }
- }
-
- return -1;
-}
-
-
-/*
-================
-PickTeam
-
-================
-*/
-team_t PickTeam( int ignoreClientNum ) {
- int counts[TEAM_NUM_TEAMS];
-
- counts[TEAM_BLUE] = TeamCount( ignoreClientNum, TEAM_BLUE );
- counts[TEAM_RED] = TeamCount( ignoreClientNum, TEAM_RED );
-
- //KK-OAX Both Teams locked...forget about it, print an error message, keep as spec
- if ( level.RedTeamLocked && level.BlueTeamLocked ) {
- G_Printf( "Both teams have been locked by the Admin! \n" );
- return TEAM_NONE;
- }
- if ( ( counts[TEAM_BLUE] > counts[TEAM_RED] ) && ( !level.RedTeamLocked ) ) {
- return TEAM_RED;
- }
- if ( ( counts[TEAM_RED] > counts[TEAM_BLUE] ) && ( !level.BlueTeamLocked ) ) {
- return TEAM_BLUE;
- }
- // equal team count, so join the team with the lowest score
- if ( ( level.teamScores[TEAM_BLUE] > level.teamScores[TEAM_RED] ) && ( !level.RedTeamLocked ) ) {
- return TEAM_RED;
- }
- if ( ( level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE] ) && ( !level.BlueTeamLocked ) ) {
- return TEAM_BLUE;
- }
- //KK-OAX Force Team Blue?
- return TEAM_BLUE;
-}
-
-/*
-===========
-ForceClientSkin
-
-Forces a client's skin (for teamplay)
-===========
-*/
-/*
-static void ForceClientSkin( gclient_t *client, char *model, const char *skin ) {
- char *p;
-
- if ((p = Q_strrchr(model, '/')) != 0) {
- *p = 0;
- }
-
- Q_strcat(model, MAX_QPATH, "/");
- Q_strcat(model, MAX_QPATH, skin);
-}
-*/
-
-/*
-===========
-ClientCheckName
-============
-*/
-static void ClientCleanName(const char *in, char *out, int outSize)
-{
- int outpos = 0, colorlessLen = 0, spaces = 0;
-
- // discard leading spaces
- for(; *in == ' '; in++);
-
- for(; *in && outpos < outSize - 1; in++)
- {
- out[outpos] = *in;
-
- if(*in == ' ')
- {
- // don't allow too many consecutive spaces
- if(spaces > 2)
- continue;
-
- spaces++;
- }
- else if(outpos > 0 && out[outpos - 1] == Q_COLOR_ESCAPE)
- {
- if(Q_IsColorString(&out[outpos - 1]))
- {
- colorlessLen--;
-
- if(ColorIndex(*in) == 0)
- {
- // Disallow color black in names to prevent players
- // from getting advantage playing in front of black backgrounds
- outpos--;
- continue;
- }
- }
- else
- {
- spaces = 0;
- colorlessLen++;
- }
- }
- else
- {
- spaces = 0;
- colorlessLen++;
- }
-
- outpos++;
- }
-
- out[outpos] = '\0';
-
- // don't allow empty names
- if( *out == '\0' || colorlessLen == 0)
- Q_strncpyz(out, "UnnamedPlayer", outSize );
-}
-
-
-
-/*
-===========
-ClientUserInfoChanged
-
-Called from ClientConnect when the player first connects and
-directly by the server system when the player updates a userinfo variable.
-
-The game can override any of the settings and call trap_SetUserinfo
-if desired.
-============
-*/
-void ClientUserinfoChanged( int clientNum ) {
- gentity_t *ent;
- int teamTask, teamLeader, team, health;
- char *s;
- char model[MAX_QPATH];
- char headModel[MAX_QPATH];
- char oldname[MAX_STRING_CHARS];
- //KK-OAX
- char err[MAX_STRING_CHARS];
- qboolean revertName = qfalse;
-
- gclient_t *client;
- char c1[MAX_INFO_STRING];
- char c2[MAX_INFO_STRING];
- char redTeam[MAX_INFO_STRING];
- char blueTeam[MAX_INFO_STRING];
- char userinfo[MAX_INFO_STRING];
-
- ent = g_entities + clientNum;
- client = ent->client;
-
- trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
-
- // check for malformed or illegal info strings
- if ( !Info_Validate(userinfo) ) {
- strcpy (userinfo, "\\name\\badinfo");
- }
-
- // check for local client
- s = Info_ValueForKey( userinfo, "ip" );
- if ( !strcmp( s, "localhost" ) ) {
- client->pers.localClient = qtrue;
- }
-
- // check the item prediction
- s = Info_ValueForKey( userinfo, "cg_predictItems" );
- if ( !atoi( s ) ) {
- client->pers.predictItemPickup = qfalse;
- } else {
- client->pers.predictItemPickup = qtrue;
- }
-
-//unlagged - client options
- // see if the player has opted out
- s = Info_ValueForKey( userinfo, "cg_delag" );
- if ( !atoi( s ) ) {
- client->pers.delag = 0;
- } else {
- client->pers.delag = atoi( s );
- }
-
- // see if the player is nudging his shots
- s = Info_ValueForKey( userinfo, "cg_cmdTimeNudge" );
- client->pers.cmdTimeNudge = atoi( s );
-
- // see if the player wants to debug the backward reconciliation
- /*s = Info_ValueForKey( userinfo, "cg_debugDelag" );
- if ( !atoi( s ) ) {
- client->pers.debugDelag = qfalse;
- }
- else {
- client->pers.debugDelag = qtrue;
- }*/
-
- // see if the player is simulating incoming latency
- //s = Info_ValueForKey( userinfo, "cg_latentSnaps" );
- //client->pers.latentSnaps = atoi( s );
-
- // see if the player is simulating outgoing latency
- //s = Info_ValueForKey( userinfo, "cg_latentCmds" );
- //client->pers.latentCmds = atoi( s );
-
- // see if the player is simulating outgoing packet loss
- //s = Info_ValueForKey( userinfo, "cg_plOut" );
- //client->pers.plOut = atoi( s );
-//unlagged - client options
-
- // set name
- Q_strncpyz ( oldname, client->pers.netname, sizeof( oldname ) );
- s = Info_ValueForKey (userinfo, "name");
- ClientCleanName( s, client->pers.netname, sizeof(client->pers.netname) );
-
- //KK-OAPub Added From Tremulous-Control Name Changes
- if( strcmp( oldname, client->pers.netname ) )
- {
- if( client->pers.nameChangeTime &&
- ( level.time - client->pers.nameChangeTime )
- <= ( g_minNameChangePeriod.value * 1000 ) )
- {
- trap_SendServerCommand( ent - g_entities, va(
- "print \"Name change spam protection (g_minNameChangePeriod = %d)\n\"",
- g_minNameChangePeriod.integer ) );
- revertName = qtrue;
- }
- else if( g_maxNameChanges.integer > 0
- && client->pers.nameChanges >= g_maxNameChanges.integer )
- {
- trap_SendServerCommand( ent - g_entities, va(
- "print \"Maximum name changes reached (g_maxNameChanges = %d)\n\"",
- g_maxNameChanges.integer ) );
- revertName = qtrue;
- }
- else if( client->pers.muted )
- {
- trap_SendServerCommand( ent - g_entities,
- "print \"You cannot change your name while you are muted\n\"" );
- revertName = qtrue;
- }
- else if( !G_admin_name_check( ent, client->pers.netname, err, sizeof( err ) ) )
- {
- trap_SendServerCommand( ent - g_entities, va( "print \"%s\n\"", err ) );
- revertName = qtrue;
- }
-
- //Never revert a bots name... just to bad if it hapens... but the bot will always be expendeble :-)
- if (ent->r.svFlags & SVF_BOT)
- revertName = qfalse;
-
- if( revertName )
- {
- Q_strncpyz( client->pers.netname, *oldname ? oldname : "UnnamedPlayer",
- sizeof( client->pers.netname ) );
- Info_SetValueForKey( userinfo, "name", oldname );
- trap_SetUserinfo( clientNum, userinfo );
- }
- else
- {
- if( client->pers.connected == CON_CONNECTED )
- {
- client->pers.nameChangeTime = level.time;
- client->pers.nameChanges++;
- }
- }
- }
- // N_G: this condition makes no sense to me and I'm not going to
- // try finding out what it means, I've added parentheses according to
- // evaluation rules of the original code so grab a
- // parentheses pairing highlighting text editor and see for yourself
- // if you got it right
- //Sago: One redundant check and CTF Elim and LMS was missing. Not an important function and I might never have noticed, should properly be ||
- if ( ( ( client->sess.sessionTeam == TEAM_SPECTATOR ) ||
- ( ( ( client->isEliminated ) /*||
- ( client->ps.pm_type == PM_SPECTATOR )*/ ) && //Sago: If this is true client.isEliminated or TEAM_SPECTATOR is true to and this is redundant
- ( g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS) ) ) &&
- ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) ) {
-
- Q_strncpyz( client->pers.netname, "scoreboard", sizeof(client->pers.netname) );
- }
-
- if ( client->pers.connected == CON_CONNECTED ) {
- if ( strcmp( oldname, client->pers.netname ) ) {
- trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname,
- client->pers.netname) );
- }
- }
-
- // set max health
- if (client->ps.powerups[PW_GUARD]) {
- client->pers.maxHealth = 200;
- } else {
- health = atoi( Info_ValueForKey( userinfo, "handicap" ) );
- client->pers.maxHealth = health;
- if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) {
- client->pers.maxHealth = 100;
- }
- }
- client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;
-
- // set model
- if( g_gametype.integer >= GT_TEAM && g_ffa_gt==0) {
- Q_strncpyz( model, Info_ValueForKey (userinfo, "team_model"), sizeof( model ) );
- Q_strncpyz( headModel, Info_ValueForKey (userinfo, "team_headmodel"), sizeof( headModel ) );
- } else {
- Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) );
- Q_strncpyz( headModel, Info_ValueForKey (userinfo, "headmodel"), sizeof( headModel ) );
- }
-
- // bots set their team a few frames later
- if (g_gametype.integer >= GT_TEAM && g_ffa_gt==0 && g_entities[clientNum].r.svFlags & SVF_BOT) {
- s = Info_ValueForKey( userinfo, "team" );
- if ( !Q_stricmp( s, "red" ) || !Q_stricmp( s, "r" ) ) {
- team = TEAM_RED;
- } else if ( !Q_stricmp( s, "blue" ) || !Q_stricmp( s, "b" ) ) {
- team = TEAM_BLUE;
- } else {
- // pick the team with the least number of players
- team = PickTeam( clientNum );
- }
- }
- else {
- team = client->sess.sessionTeam;
- }
-
-/* NOTE: all client side now
-Sago: I am not happy with this exception
-
- // team
- switch( team ) {
- case TEAM_RED:
- ForceClientSkin(client, model, "red");
-// ForceClientSkin(client, headModel, "red");
- break;
- case TEAM_BLUE:
- ForceClientSkin(client, model, "blue");
-// ForceClientSkin(client, headModel, "blue");
- break;
- }
- // don't ever use a default skin in teamplay, it would just waste memory
- // however bots will always join a team but they spawn in as spectator
- if ( g_gametype.integer >= GT_TEAM && team == TEAM_SPECTATOR) {
- ForceClientSkin(client, model, "red");
-// ForceClientSkin(client, headModel, "red");
- }
-*/
-
- if (g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
- client->pers.teamInfo = qtrue;
- } else {
- s = Info_ValueForKey( userinfo, "teamoverlay" );
- if ( ! *s || atoi( s ) != 0 ) {
- client->pers.teamInfo = qtrue;
- } else {
- client->pers.teamInfo = qfalse;
- }
- }
- /*
- s = Info_ValueForKey( userinfo, "cg_pmove_fixed" );
- if ( !*s || atoi( s ) == 0 ) {
- client->pers.pmoveFixed = qfalse;
- }
- else {
- client->pers.pmoveFixed = qtrue;
- }
- */
-
- // team task (0 = none, 1 = offence, 2 = defence)
- teamTask = atoi(Info_ValueForKey(userinfo, "teamtask"));
- // team Leader (1 = leader, 0 is normal player)
- teamLeader = client->sess.teamLeader;
-
- // colors
- if( g_gametype.integer >= GT_TEAM && g_ffa_gt==0 && g_instantgib.integer) {
- switch(team) {
- case TEAM_RED:
- c1[0] = COLOR_BLUE;
- c2[0] = COLOR_BLUE;
- c1[1] = 0;
- c2[1] = 0;
- break;
- case TEAM_BLUE:
- c1[0] = COLOR_RED;
- c2[0] = COLOR_RED;
- c1[1] = 0;
- c2[1] = 0;
- break;
- default:
- break;
- }
- } else {
- strcpy(c1, Info_ValueForKey( userinfo, "color1" ));
- strcpy(c2, Info_ValueForKey( userinfo, "color2" ));
- }
-
- strcpy(redTeam, Info_ValueForKey( userinfo, "g_redteam" ));
- strcpy(blueTeam, Info_ValueForKey( userinfo, "g_blueteam" ));
-
- // send over a subset of the userinfo keys so other clients can
- // print scoreboards, display models, and play custom sounds
- if ( ent->r.svFlags & SVF_BOT ) {
- s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d",
- client->pers.netname, team, model, headModel, c1, c2,
- client->pers.maxHealth, client->sess.wins, client->sess.losses,
- Info_ValueForKey( userinfo, "skill" ), teamTask, teamLeader );
- } else {
- s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\g_redteam\\%s\\g_blueteam\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d",
- client->pers.netname, client->sess.sessionTeam, model, headModel, redTeam, blueTeam, c1, c2,
- client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader);
- }
-
- trap_SetConfigstring( CS_PLAYERS+clientNum, s );
-
- // this is not the userinfo, more like the configstring actually
- G_LogPrintf( "ClientUserinfoChanged: %i %s\\id\\%s\n", clientNum, s, Info_ValueForKey(userinfo, "cl_guid") );
-}
-
-
-/*
-===========
-ClientConnect
-
-Called when a player begins connecting to the server.
-Called again for every map change or tournement restart.
-
-The session information will be valid after exit.
-
-Return NULL if the client should be allowed, otherwise return
-a string with the reason for denial.
-
-Otherwise, the client will be sent the current gamestate
-and will eventually get to ClientBegin.
-
-firstTime will be qtrue the very first time a client connects
-to the server machine, but qfalse on map changes and tournement
-restarts.
-============
-*/
-char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) {
- char *value;
-// char *areabits;
- gclient_t *client;
- char userinfo[MAX_INFO_STRING];
- gentity_t *ent;
- char reason[ MAX_STRING_CHARS ] = {""};
- int i;
-
- //KK-OAX I moved these up so userinfo could be assigned/used.
- ent = &g_entities[ clientNum ];
- client = &level.clients[ clientNum ];
- ent->client = client;
- memset( client, 0, sizeof(*client) );
-
- trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
-
- value = Info_ValueForKey( userinfo, "cl_guid" );
- Q_strncpyz( client->pers.guid, value, sizeof( client->pers.guid ) );
-
-
- // IP filtering //KK-OAX Has this been obsoleted?
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=500
- // recommanding PB based IP / GUID banning, the builtin system is pretty limited
- // check to see if they are on the banned IP list
- value = Info_ValueForKey (userinfo, "ip");
- Q_strncpyz( client->pers.ip, value, sizeof( client->pers.ip ) );
-
- if ( G_FilterPacket( value ) && !Q_stricmp(value,"localhost") ) {
- G_Printf("Player with IP: %s is banned\n",value);
- return "You are banned from this server.";
- }
-
- if( G_admin_ban_check( userinfo, reason, sizeof( reason ) ) ) {
- return va( "%s", reason );
- }
-
- //KK-OAX
- // we don't check GUID or password for bots and local client
- // NOTE: local client <-> "ip" "localhost"
- // this means this client is not running in our current process
- if ( !isBot && (strcmp(value, "localhost") != 0)) {
- // check for a password
- value = Info_ValueForKey (userinfo, "password");
- if ( g_password.string[0] && Q_stricmp( g_password.string, "none" ) &&
- strcmp( g_password.string, value) != 0) {
- return "Invalid password";
- }
- for( i = 0; i < sizeof( client->pers.guid ) - 1 &&
- isxdigit( client->pers.guid[ i ] ); i++ );
- if( i < sizeof( client->pers.guid ) - 1 )
- return "Invalid GUID";
-
- for( i = 0; i < level.maxclients; i++ ) {
-
- if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
- continue;
-
- if( !Q_stricmp( client->pers.guid, level.clients[ i ].pers.guid ) ) {
- if( !G_ClientIsLagging( level.clients + i ) ) {
- trap_SendServerCommand( i, "cp \"Your GUID is not secure\"" );
- return "Duplicate GUID";
- }
- trap_DropClient( i, "Ghost" );
- }
- }
-
- }
-
- //Check for local client
- if( !strcmp( client->pers.ip, "localhost" ) )
- client->pers.localClient = qtrue;
- client->pers.adminLevel = G_admin_level( ent );
-
- client->pers.connected = CON_CONNECTING;
-
- // read or initialize the session data
- if ( firstTime || level.newSession ) {
- G_InitSessionData( client, userinfo );
- }
- G_ReadSessionData( client );
-
- if( isBot ) {
- ent->r.svFlags |= SVF_BOT;
- ent->inuse = qtrue;
- if( !G_BotConnect( clientNum, !firstTime ) ) {
- return "BotConnectfailed";
- }
- }
-
- //KK-OAX Swapped these in order...seemed to help the connection process.
- // get and distribute relevent paramters
- ClientUserinfoChanged( clientNum );
- G_LogPrintf( "ClientConnect: %i\n", clientNum );
-
-
- // don't do the "xxx connected" messages if they were caried over from previous level
- if ( firstTime ) {
- trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname) );
- }
-
- if ( g_gametype.integer >= GT_TEAM &&
- client->sess.sessionTeam != TEAM_SPECTATOR ) {
- BroadcastTeamChange( client, -1 );
- }
-
- // count current clients and rank for scoreboard
- CalculateRanks();
-
- // for statistics
-// client->areabits = areabits;
-// if ( !client->areabits )
-// client->areabits = G_Alloc( (trap_AAS_PointReachabilityAreaIndex( NULL ) + 7) / 8 );
-
-//Sago: Changed the message
-//unlagged - backward reconciliation #5
- // announce it
- if ( g_delagHitscan.integer ) {
- trap_SendServerCommand( clientNum, "print \"Full lag compensation is ON!\n\"" );
- }
- else {
- trap_SendServerCommand( clientNum, "print \"Full lag compensation is OFF!\n\"" );
- }
-
-//unlagged - backward reconciliation #5
- G_admin_namelog_update( client, qfalse );
- return NULL;
-}
-
-void motd (gentity_t *ent)
-{
- char motd[1024];
- fileHandle_t motdFile;
- int motdLen;
- int fileLen;
-
- strcpy (motd, "cp \"");
- fileLen = trap_FS_FOpenFile("motd.cfg", &motdFile, FS_READ);
- if(motdFile)
- {
- char * p;
-
- motdLen = strlen(motd);
- if((motdLen + fileLen) > (sizeof(motd) - 2))
- fileLen = (sizeof(motd) - 2 - motdLen);
- trap_FS_Read(motd + motdLen, fileLen, motdFile);
- motd[motdLen + fileLen] = '"';
- motd[motdLen + fileLen + 1] = 0;
- trap_FS_FCloseFile(motdFile);
-
- while((p = strchr(motd, '\r'))) //Remove carrier return. 0x0D
- memmove(p, p + 1, motdLen + fileLen - (p - motd));
- }
- trap_SendServerCommand(ent - g_entities, motd);
-}
-
-/*
-===========
-ClientBegin
-
-called when a client has finished connecting, and is ready
-to be placed into the level. This will happen every level load,
-and on transition between teams, but doesn't happen on respawns
-============
-*/
-void ClientBegin( int clientNum ) {
- gentity_t *ent;
- gclient_t *client;
- gentity_t *tent;
- int flags;
- int countRed, countBlue, countFree;
- char userinfo[MAX_INFO_STRING];
-
- trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
-
- ent = g_entities + clientNum;
-
- client = level.clients + clientNum;
-
- if ( ent->r.linked ) {
- trap_UnlinkEntity( ent );
- }
- G_InitGentity( ent );
- ent->touch = 0;
- ent->pain = 0;
- ent->client = client;
-
- client->pers.connected = CON_CONNECTED;
- client->pers.enterTime = level.time;
- client->pers.teamState.state = TEAM_BEGIN;
-
- //Elimination:
- client->pers.roundReached = 0; //We will spawn in next round
- if(g_gametype.integer == GT_LMS) {
- client->isEliminated = qtrue; //So player does not give a point in gamemode 2 and 3
- //trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " will start dead\n\"", client->pers.netname) );
- }
-
- //player is a bot:
- if( ent->r.svFlags & SVF_BOT )
- {
- if(!level.hadBots)
- {
- G_LogPrintf( "Info: There has been at least 1 bot now\n" );
- level.hadBots = qtrue;
- }
- }
-
- //Count smallest team
- countFree = TeamCount(-1,TEAM_FREE);
- countRed = TeamCount(-1,TEAM_RED);
- countBlue = TeamCount(-1,TEAM_BLUE);
- if(g_gametype.integer < GT_TEAM || g_ffa_gt)
- {
- if(countFree>level.teamSize)
- level.teamSize=countFree;
- }
- else
- if(countRed>countBlue)
- {
- if(countBlue>level.teamSize)
- level.teamSize=countBlue;
- }
- else
- {
- if(countRed>level.teamSize)
- level.teamSize=countRed;
- }
-
- // save eflags around this, because changing teams will
- // cause this to happen with a valid entity, and we
- // want to make sure the teleport bit is set right
- // so the viewpoint doesn't interpolate through the
- // world to the new position
- flags = client->ps.eFlags;
- memset( &client->ps, 0, sizeof( client->ps ) );
- if( client->sess.sessionTeam != TEAM_SPECTATOR )
- PlayerStore_restore(Info_ValueForKey(userinfo,"cl_guid"),&(client->ps));
- client->ps.eFlags = flags;
-
- // locate ent at a spawn point
- ClientSpawn( ent );
-
- if( ( client->sess.sessionTeam != TEAM_SPECTATOR ) &&
- ( ( !( client->isEliminated ) /*&&
- ( ( !client->ps.pm_type ) == PM_SPECTATOR ) */ ) || //Sago: Yes, it made no sense
- ( ( g_gametype.integer != GT_ELIMINATION || level.intermissiontime) &&
- ( g_gametype.integer != GT_CTF_ELIMINATION || level.intermissiontime) &&
- ( g_gametype.integer != GT_LMS || level.intermissiontime ) ) ) ) {
- // send event
- tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );
- tent->s.clientNum = ent->s.clientNum;
-
- if ( g_gametype.integer != GT_TOURNAMENT ) {
- trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname) );
- }
- }
-
- motd ( ent );
-
- G_LogPrintf( "ClientBegin: %i\n", clientNum );
-
- //Send domination point names:
- if(g_gametype.integer == GT_DOMINATION) {
- DominationPointNamesMessage(ent);
- DominationPointStatusMessage(ent);
- }
-
- TeamCvarSet();
-
- // count current clients and rank for scoreboard
- CalculateRanks();
-
- //Send the list of custom vote options:
- if(strlen(custom_vote_info))
- SendCustomVoteCommands(clientNum);
-}
-
-/*
-===========
-ClientSpawn
-
-Called every time a client is placed fresh in the world:
-after the first ClientBegin, and after each respawn
-Initializes all non-persistant parts of playerState
-============
-*/
-void ClientSpawn(gentity_t *ent) {
- int index;
- vec3_t spawn_origin, spawn_angles;
- gclient_t *client;
- int i;
- clientPersistant_t saved;
- clientSession_t savedSess;
- int persistant[MAX_PERSISTANT];
- gentity_t *spawnPoint;
- int flags;
- int savedPing;
-// char *savedAreaBits;
- int accuracy_hits, accuracy_shots;
- int eventSequence;
- char userinfo[MAX_INFO_STRING];
-
- index = ent - g_entities;
- client = ent->client;
-
- //In Elimination the player should not spawn if he have already spawned in the round (but not for spectators)
- // N_G: You've obviously wanted something ELSE
- //Sago: Yes, the !level.intermissiontime is currently redundant but it might still be the bast place to make the test, CheckElimination in g_main makes sure the next if will fail and the rest of the things this block does might not affect if in Intermission (I'll just test that)
- if(
- (
- (
- g_gametype.integer == GT_ELIMINATION ||
- g_gametype.integer == GT_CTF_ELIMINATION || (g_gametype.integer == GT_LMS && client->isEliminated)) &&
- (!level.intermissiontime || level.warmupTime != 0)
- ) &&
- ( client->sess.sessionTeam != TEAM_SPECTATOR )
- )
- {
- // N_G: Another condition that makes no sense to me, see for
- // yourself if you really meant this
- // Sago: I beleive the TeamCount is to make sure people can join even if the game can't start
- if( ( level.roundNumber == level.roundNumberStarted ) ||
- ( (level.time < level.roundStartTime - g_elimination_activewarmup.integer*1000 ) &&
- TeamCount( -1, TEAM_BLUE ) &&
- TeamCount( -1, TEAM_RED ) ) )
- {
- client->sess.spectatorState = SPECTATOR_FREE;
- client->isEliminated = qtrue;
- client->ps.pm_type = PM_SPECTATOR;
- CalculateRanks();
- return;
- }
- else
- {
- client->pers.roundReached = level.roundNumber+1;
- client->sess.spectatorState = SPECTATOR_NOT;
- client->ps.pm_type = PM_NORMAL;
- client->isEliminated = qfalse;
- CalculateRanks();
- }
- } else {
- //Force false.
- if(client->isEliminated) {
- client->isEliminated = qfalse;
- CalculateRanks();
- }
- }
-
- if(g_gametype.integer == GT_LMS && client->sess.sessionTeam != TEAM_SPECTATOR && (!level.intermissiontime || level.warmupTime != 0))
- {
- if(level.roundNumber==level.roundNumberStarted /*|| level.time<level.roundStartTime-g_elimination_activewarmup.integer*1000*/ && 1>client->pers.livesLeft)
- {
- client->sess.spectatorState = SPECTATOR_FREE;
- if( ent->client->isEliminated!=qtrue) {
- client->isEliminated = qtrue;
- if((g_lms_mode.integer == 2 || g_lms_mode.integer == 3) && level.roundNumber == level.roundNumberStarted)
- LMSpoint();
- }
- client->ps.pm_type = PM_SPECTATOR;
- return;
- }
-
- client->sess.spectatorState = SPECTATOR_NOT;
- client->ps.pm_type = PM_NORMAL;
- client->isEliminated = qfalse;
- if(client->pers.livesLeft>0)
- client->pers.livesLeft--;
- }
-
- // find a spawn point
- // do it before setting health back up, so farthest
- // ranging doesn't count this client
- if ((client->sess.sessionTeam == TEAM_SPECTATOR)
- || ( (client->ps.pm_type == PM_SPECTATOR || client->isEliminated ) && (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) ) ) {
- spawnPoint = SelectSpectatorSpawnPoint ( spawn_origin, spawn_angles);
- } else if (g_gametype.integer == GT_DOUBLE_D) {
- //Double Domination uses special spawn points:
- spawnPoint = SelectDoubleDominationSpawnPoint (client->sess.sessionTeam, spawn_origin, spawn_angles);
- } else if (g_gametype.integer >= GT_CTF && g_ffa_gt==0) {
- // all base oriented team games use the CTF spawn points
- spawnPoint = SelectCTFSpawnPoint (
- client->sess.sessionTeam,
- client->pers.teamState.state,
- spawn_origin, spawn_angles);
- } else {
- do {
- // the first spawn should be at a good looking spot
- if ( !client->pers.initialSpawn && client->pers.localClient ) {
- client->pers.initialSpawn = qtrue;
- spawnPoint = SelectInitialSpawnPoint( spawn_origin, spawn_angles );
- } else {
- // don't spawn near existing origin if possible
- spawnPoint = SelectSpawnPoint (
- client->ps.origin,
- spawn_origin, spawn_angles);
- }
-
- // Tim needs to prevent bots from spawning at the initial point
- // on q3dm0...
- if ( ( spawnPoint->flags & FL_NO_BOTS ) && ( ent->r.svFlags & SVF_BOT ) ) {
- //Sago: The game has a tendency to select the furtest spawn point
- //This is a problem if the fursest spawnpoint keeps being NO_BOTS and it does!
- //This is a hot fix that seeks a spawn point faraway from the the currently found one
- vec3_t old_origin;
- VectorCopy(spawn_origin,old_origin);
- spawnPoint = SelectSpawnPoint (old_origin, spawn_origin, spawn_angles);
- if ( ( spawnPoint->flags & FL_NO_BOTS ) && ( ent->r.svFlags & SVF_BOT ) ) {
- continue; // try again
- }
- }
- // just to be symetric, we have a nohumans option...
- if ( ( spawnPoint->flags & FL_NO_HUMANS ) && !( ent->r.svFlags & SVF_BOT ) ) {
- continue; // try again
- }
-
- break;
-
- } while ( 1 );
- }
- client->pers.teamState.state = TEAM_ACTIVE;
-
- // always clear the kamikaze flag
- ent->s.eFlags &= ~EF_KAMIKAZE;
-
- // toggle the teleport bit so the client knows to not lerp
- // and never clear the voted flag
- flags = ent->client->ps.eFlags & (EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED);
- flags ^= EF_TELEPORT_BIT;
-
-//unlagged - backward reconciliation #3
- // we don't want players being backward-reconciled to the place they died
- G_ResetHistory( ent );
- // and this is as good a time as any to clear the saved state
- ent->client->saved.leveltime = 0;
-//unlagged - backward reconciliation #3
-
- // clear everything but the persistant data
-
- saved = client->pers;
- savedSess = client->sess;
- savedPing = client->ps.ping;
-// savedAreaBits = client->areabits;
- accuracy_hits = client->accuracy_hits;
- accuracy_shots = client->accuracy_shots;
- for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) {
- persistant[i] = client->ps.persistant[i];
- }
- eventSequence = client->ps.eventSequence;
-
- Com_Memset (client, 0, sizeof(*client));
-
- client->pers = saved;
- client->sess = savedSess;
- client->ps.ping = savedPing;
-// client->areabits = savedAreaBits;
- client->accuracy_hits = accuracy_hits;
- client->accuracy_shots = accuracy_shots;
- client->lastkilled_client = -1;
-
- for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) {
- client->ps.persistant[i] = persistant[i];
- }
- client->ps.eventSequence = eventSequence;
- // increment the spawncount so the client will detect the respawn
- client->ps.persistant[PERS_SPAWN_COUNT]++;
- client->ps.persistant[PERS_TEAM] = client->sess.sessionTeam;
-
- client->airOutTime = level.time + 12000;
-
- trap_GetUserinfo( index, userinfo, sizeof(userinfo) );
- // set max health
- client->pers.maxHealth = atoi( Info_ValueForKey( userinfo, "handicap" ) );
- if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) {
- client->pers.maxHealth = 100;
- }
- // clear entity values
- client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;
- client->ps.eFlags = flags;
-
- ent->s.groundEntityNum = ENTITYNUM_NONE;
- ent->client = &level.clients[index];
- ent->takedamage = qtrue;
- ent->inuse = qtrue;
- ent->classname = "player";
- ent->r.contents = CONTENTS_BODY;
- ent->clipmask = MASK_PLAYERSOLID;
- ent->die = player_die;
- ent->waterlevel = 0;
- ent->watertype = 0;
- ent->flags = 0;
-
- //Sago: No one has hit the client yet!
- client->lastSentFlying = -1;
-
- VectorCopy (playerMins, ent->r.mins);
- VectorCopy (playerMaxs, ent->r.maxs);
-
- client->ps.clientNum = index;
-
-if(g_gametype.integer != GT_ELIMINATION && g_gametype.integer != GT_CTF_ELIMINATION && g_gametype.integer != GT_LMS && !g_elimination_allgametypes.integer)
-{
- client->ps.stats[STAT_WEAPONS] = ( 1 << WP_MACHINEGUN );
- if ( g_gametype.integer == GT_TEAM ) {
- client->ps.ammo[WP_MACHINEGUN] = 50;
- } else {
- client->ps.ammo[WP_MACHINEGUN] = 100;
- }
-
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GAUNTLET );
- client->ps.ammo[WP_GAUNTLET] = -1;
- client->ps.ammo[WP_GRAPPLING_HOOK] = -1;
-
- // health will count down towards max_health
- ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] + 25;
-}
-else
-{
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GAUNTLET );
- client->ps.ammo[WP_GAUNTLET] = -1;
- client->ps.ammo[WP_GRAPPLING_HOOK] = -1;
- if (g_elimination_machinegun.integer > 0) {
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_MACHINEGUN );
- client->ps.ammo[WP_MACHINEGUN] = g_elimination_machinegun.integer;
- }
- if (g_elimination_shotgun.integer > 0) {
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_SHOTGUN );
- client->ps.ammo[WP_SHOTGUN] = g_elimination_shotgun.integer;
- }
- if (g_elimination_grenade.integer > 0) {
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GRENADE_LAUNCHER );
- client->ps.ammo[WP_GRENADE_LAUNCHER] = g_elimination_grenade.integer;
- }
- if (g_elimination_rocket.integer > 0) {
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_ROCKET_LAUNCHER );
- client->ps.ammo[WP_ROCKET_LAUNCHER] = g_elimination_rocket.integer;
- }
- if (g_elimination_lightning.integer > 0) {
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_LIGHTNING );
- client->ps.ammo[WP_LIGHTNING] = g_elimination_lightning.integer;
- }
- if (g_elimination_railgun.integer > 0) {
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_RAILGUN );
- client->ps.ammo[WP_RAILGUN] = g_elimination_railgun.integer;
- }
- if (g_elimination_plasmagun.integer > 0) {
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_PLASMAGUN );
- client->ps.ammo[WP_PLASMAGUN] = g_elimination_plasmagun.integer;
- }
- if (g_elimination_bfg.integer > 0) {
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BFG );
- client->ps.ammo[WP_BFG] = g_elimination_bfg.integer;
- }
- if (g_elimination_grapple.integer) {
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GRAPPLING_HOOK );
- }
- if (g_elimination_nail.integer > 0) {
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_NAILGUN );
- client->ps.ammo[WP_NAILGUN] = g_elimination_nail.integer;
- }
- if (g_elimination_mine.integer > 0) {
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_PROX_LAUNCHER );
- client->ps.ammo[WP_PROX_LAUNCHER] = g_elimination_mine.integer;
- }
- if (g_elimination_chain.integer > 0) {
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_CHAINGUN );
- client->ps.ammo[WP_CHAINGUN] = g_elimination_chain.integer;
- }
-
- ent->health = client->ps.stats[STAT_ARMOR] = g_elimination_startArmor.integer; //client->ps.stats[STAT_MAX_HEALTH]*2;
- ent->health = client->ps.stats[STAT_HEALTH] = g_elimination_startHealth.integer; //client->ps.stats[STAT_MAX_HEALTH]*2;
-
-
- // ent->health = client->ps.stats[STAT_HEALTH] = 0;
-}
- //Instantgib mode, replace weapons with rail (and maybe gauntlet)
- if(g_instantgib.integer)
- {
- client->ps.stats[STAT_WEAPONS] = ( 1 << WP_RAILGUN );
- client->ps.ammo[WP_RAILGUN] = 999; //Don't display any ammo
- if(g_instantgib.integer>1)
- {
- client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GAUNTLET );
- client->ps.ammo[WP_GAUNTLET] = -1;
- }
- }
-
- //nexuiz style rocket arena (rocket launcher only)
- if(g_rockets.integer)
- {
- client->ps.stats[STAT_WEAPONS] = ( 1 << WP_ROCKET_LAUNCHER );
- client->ps.ammo[WP_ROCKET_LAUNCHER] = 999;
- }
-
- G_SetOrigin( ent, spawn_origin );
- VectorCopy( spawn_origin, client->ps.origin );
-
- // the respawned flag will be cleared after the attack and jump keys come up
- client->ps.pm_flags |= PMF_RESPAWNED;
- if(g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION || g_gametype.integer==GT_LMS)
- client->ps.pm_flags |= PMF_ELIMWARMUP;
-
- trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd );
- SetClientViewAngle( ent, spawn_angles );
-
- if ( (ent->client->sess.sessionTeam == TEAM_SPECTATOR) || ((client->ps.pm_type == PM_SPECTATOR || client->isEliminated) &&
- (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS) ) ) {
- //Sago: Lets see if this fixes the bots only bug - loose all point on dead bug. (It didn't)
- /*if(g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS) {
- G_KillBox( ent );
- trap_LinkEntity (ent);
- }*/
- } else {
- G_KillBox( ent );
- trap_LinkEntity (ent);
-
- // force the base weapon up
- client->ps.weapon = WP_MACHINEGUN;
- client->ps.weaponstate = WEAPON_READY;
-
- }
-
- // don't allow full run speed for a bit
- client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
- client->ps.pm_time = 100;
-
- client->respawnTime = level.time;
- client->inactivityTime = level.time + g_inactivity.integer * 1000;
- client->latched_buttons = 0;
-
- // set default animations
- client->ps.torsoAnim = TORSO_STAND;
- client->ps.legsAnim = LEGS_IDLE;
-
- if ( level.intermissiontime ) {
- MoveClientToIntermission( ent );
- } else {
- // fire the targets of the spawn point
- G_UseTargets( spawnPoint, ent );
-
- // select the highest weapon number available, after any
- // spawn given items have fired
- client->ps.weapon = 1;
- for ( i = WP_NUM_WEAPONS - 1 ; i > 0 ; i-- ) {
- if ( client->ps.stats[STAT_WEAPONS] & ( 1 << i ) && i !=WP_GRAPPLING_HOOK ) {
- client->ps.weapon = i;
- break;
- }
- }
- }
-
- // run a client frame to drop exactly to the floor,
- // initialize animations and other things
- client->ps.commandTime = level.time - 100;
- ent->client->pers.cmd.serverTime = level.time;
- ClientThink( ent-g_entities );
-
- // positively link the client, even if the command times are weird
- if ( (ent->client->sess.sessionTeam != TEAM_SPECTATOR) || ( (!client->isEliminated || client->ps.pm_type != PM_SPECTATOR)&&
- (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS) ) ) {
- BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
- VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
- trap_LinkEntity( ent );
- }
-
- // run the presend to set anything else
- ClientEndFrame( ent );
-
- // clear entity state values
- BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
-}
-
-
-/*
-===========
-ClientDisconnect
-
-Called when a player drops from the server.
-Will not be called between levels.
-
-This should NOT be called directly by any game logic,
-call trap_DropClient(), which will call this and do
-server system housekeeping.
-============
-*/
-void ClientDisconnect( int clientNum ) {
- gentity_t *ent;
- int i;
- char userinfo[MAX_INFO_STRING];
-
- // cleanup if we are kicking a bot that
- // hasn't spawned yet
- G_RemoveQueuedBotBegin( clientNum );
-
- ent = g_entities + clientNum;
- if ( !ent->client ) {
- return;
- }
- //KK-OAX Admin
- G_admin_namelog_update( ent->client, qtrue );
-
- trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
-
- // stop any following clients
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( (level.clients[i].sess.sessionTeam == TEAM_SPECTATOR || level.clients[i].ps.pm_type == PM_SPECTATOR)
- && level.clients[i].sess.spectatorState == SPECTATOR_FOLLOW
- && level.clients[i].sess.spectatorClient == clientNum ) {
- StopFollowing( &g_entities[i] );
- }
- }
-
- // send effect if they were completely connected
- /*
- *Sago: I have removed this. A little dangerous but I make him suicide in a moment.
- */
- /*if ( ent->client->pers.connected == CON_CONNECTED
- && ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
- tent->s.clientNum = ent->s.clientNum;
-
- // They don't get to take powerups with them!
- // Especially important for stuff like CTF flags
- TossClientItems( ent );
- TossClientPersistantPowerups( ent );
- if( g_gametype.integer == GT_HARVESTER ) {
- TossClientCubes( ent );
- }
-//#endif
-
- }*/
-
- //Is the player alive?
- i = (ent->client->ps.stats[STAT_HEALTH]>0);
- //Commit suicide!
- if ( ent->client->pers.connected == CON_CONNECTED
- && ent->client->sess.sessionTeam != TEAM_SPECTATOR && i ) {
- //Prevent a team from loosing point because of player leaving
- if(g_gametype.integer == GT_TEAM)
- level.teamScores[ ent->client->sess.sessionTeam ]++;
- // Kill him (makes sure he loses flags, etc)
- ent->flags &= ~FL_GODMODE;
- ent->client->ps.stats[STAT_HEALTH] = ent->health = 0;
- player_die (ent, ent, g_entities + ENTITYNUM_WORLD, 100000, MOD_SUICIDE);
- }
-
-
-
- if ( ent->client->pers.connected == CON_CONNECTED && ent->client->sess.sessionTeam != TEAM_SPECTATOR)
- PlayerStore_store(Info_ValueForKey(userinfo,"cl_guid"),ent->client->ps);
-
- G_LogPrintf( "ClientDisconnect: %i\n", clientNum );
-
- // if we are playing in tourney mode and losing, give a win to the other player
- if ( (g_gametype.integer == GT_TOURNAMENT )
- && !level.intermissiontime
- && !level.warmupTime && level.sortedClients[1] == clientNum ) {
- level.clients[ level.sortedClients[0] ].sess.wins++;
- ClientUserinfoChanged( level.sortedClients[0] );
- }
-
- if( g_gametype.integer == GT_TOURNAMENT &&
- ent->client->sess.sessionTeam == TEAM_FREE &&
- level.intermissiontime ) {
-
- trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
- level.restarted = qtrue;
- level.changemap = NULL;
- level.intermissiontime = 0;
- }
-
- trap_UnlinkEntity (ent);
- ent->s.modelindex = 0;
- ent->inuse = qfalse;
- ent->classname = "disconnected";
- ent->client->pers.connected = CON_DISCONNECTED;
- ent->client->ps.persistant[PERS_TEAM] = TEAM_FREE;
- ent->client->sess.sessionTeam = TEAM_FREE;
-
- trap_SetConfigstring( CS_PLAYERS + clientNum, "");
-
- CalculateRanks();
- CountVotes();
-
- if ( ent->r.svFlags & SVF_BOT ) {
- BotAIShutdownClient( clientNum, qfalse );
- }
-}
-
-
diff --git a/game/code/game/g_cmds.c b/game/code/game/g_cmds.c
deleted file mode 100644
index 37a6dcd..0000000
--- a/game/code/game/g_cmds.c
+++ /dev/null
@@ -1,2228 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-#include "../../ui/menudef.h" // for the voice chats
-
-/*
-==================
-DeathmatchScoreboardMessage
-
-==================
-*/
-void DeathmatchScoreboardMessage( gentity_t *ent ) {
- char entry[1024];
- char string[1400];
- int stringlength;
- int i, j;
- gclient_t *cl;
- int numSorted, scoreFlags, accuracy, perfect;
-
- // send the latest information on all clients
- string[0] = 0;
- stringlength = 0;
- scoreFlags = 0;
-
- numSorted = level.numConnectedClients;
-
- for (i=0 ; i < numSorted ; i++) {
- int ping;
-
- cl = &level.clients[level.sortedClients[i]];
-
- if ( cl->pers.connected == CON_CONNECTING ) {
- ping = -1;
- } else {
-//unlagged - true ping
- //ping = cl->ps.ping < 999 ? cl->ps.ping : 999;
- ping = cl->pers.realPing < 999 ? cl->pers.realPing : 999;
-//unlagged - true ping
- }
-
- if( cl->accuracy_shots ) {
- accuracy = cl->accuracy_hits * 100 / cl->accuracy_shots;
- }
- else {
- accuracy = 0;
- }
- perfect = ( cl->ps.persistant[PERS_RANK] == 0 && cl->ps.persistant[PERS_KILLED] == 0 ) ? 1 : 0;
-
- if(g_gametype.integer == GT_LMS) {
- Com_sprintf (entry, sizeof(entry),
- " %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i", level.sortedClients[i],
- cl->ps.persistant[PERS_SCORE], ping, (level.time - cl->pers.enterTime)/60000,
- scoreFlags, g_entities[level.sortedClients[i]].s.powerups, accuracy,
- cl->ps.persistant[PERS_IMPRESSIVE_COUNT],
- cl->ps.persistant[PERS_EXCELLENT_COUNT],
- cl->ps.persistant[PERS_GAUNTLET_FRAG_COUNT],
- cl->ps.persistant[PERS_DEFEND_COUNT],
- cl->ps.persistant[PERS_ASSIST_COUNT],
- perfect,
- cl->ps.persistant[PERS_CAPTURES],
- cl->pers.livesLeft + (cl->isEliminated?0:1));
- }
- else {
- Com_sprintf (entry, sizeof(entry),
- " %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i", level.sortedClients[i],
- cl->ps.persistant[PERS_SCORE], ping, (level.time - cl->pers.enterTime)/60000,
- scoreFlags, g_entities[level.sortedClients[i]].s.powerups, accuracy,
- cl->ps.persistant[PERS_IMPRESSIVE_COUNT],
- cl->ps.persistant[PERS_EXCELLENT_COUNT],
- cl->ps.persistant[PERS_GAUNTLET_FRAG_COUNT],
- cl->ps.persistant[PERS_DEFEND_COUNT],
- cl->ps.persistant[PERS_ASSIST_COUNT],
- perfect,
- cl->ps.persistant[PERS_CAPTURES],
- cl->isEliminated);
- }
- j = strlen(entry);
- if (stringlength + j > 1024)
- break;
- strcpy (string + stringlength, entry);
- stringlength += j;
- }
-
- trap_SendServerCommand( ent-g_entities, va("scores %i %i %i %i%s", i,
- level.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE], level.roundStartTime,
- string ) );
-}
-
-/*
-==================
-DominationPointStatusMessage
-
-==================
-*/
-void DominationPointStatusMessage( gentity_t *ent ) {
- char entry[10]; //Will more likely be 2... in fact cannot be more since we are the server
- char string[10*(MAX_DOMINATION_POINTS+1)];
- int stringlength;
- int i, j;
-
- string[0] = 0;
- stringlength = 0;
-
- for(i = 0;i<MAX_DOMINATION_POINTS && i<level.domination_points_count; i++) {
- Com_sprintf (entry, sizeof(entry)," %i",level.pointStatusDom[i]);
- j = strlen(entry);
- if (stringlength + j > 10*MAX_DOMINATION_POINTS)
- break;
- strcpy (string + stringlength, entry);
- stringlength += j;
- }
-
- trap_SendServerCommand( ent-g_entities, va("domStatus %i%s", level.domination_points_count, string ) );
-}
-
-/*
-==================
-EliminationMessage
-
-==================
-*/
-
-void EliminationMessage(gentity_t *ent) {
- trap_SendServerCommand( ent-g_entities, va("elimination %i %i %i",
- level.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE], level.roundStartTime) );
-}
-
-/*
-==================
-DoubleDominationScoreTime
-
-==================
-*/
-void DoubleDominationScoreTimeMessage( gentity_t *ent ) {
- trap_SendServerCommand( ent-g_entities, va("ddtaken %i", level.timeTaken));
-}
-
-/*
-==================
-DominationPointNames
-==================
-*/
-
-void DominationPointNamesMessage( gentity_t *ent ) {
- char text[MAX_DOMINATION_POINTS_NAMES*MAX_DOMINATION_POINTS];
- int i,j;
- qboolean nullFound;
- for(i=0;i<MAX_DOMINATION_POINTS;i++) {
- Q_strncpyz(text+i*MAX_DOMINATION_POINTS_NAMES,level.domination_points_names[i],MAX_DOMINATION_POINTS_NAMES-1);
- if(i!=MAX_DOMINATION_POINTS-1) {
- //Don't allow "/0"!
- nullFound = qfalse;
- for(j=i*MAX_DOMINATION_POINTS_NAMES; j<(i+1)*MAX_DOMINATION_POINTS_NAMES;j++) {
- if(text[j]==0)
- nullFound = qtrue;
- if(nullFound)
- text[j] = ' ';
- }
- }
- text[MAX_DOMINATION_POINTS_NAMES*MAX_DOMINATION_POINTS-2]=0x19;
- text[MAX_DOMINATION_POINTS_NAMES*MAX_DOMINATION_POINTS-1]=0;
- }
- trap_SendServerCommand( ent-g_entities, va("dompointnames %i \"%s\"", level.domination_points_count, text));
-}
-
-/*
-==================
-YourTeamMessage
-==================
-*/
-
-void YourTeamMessage( gentity_t *ent) {
- int team = level.clients[ent-g_entities].sess.sessionTeam;
-
- switch(team) {
- case TEAM_RED:
- trap_SendServerCommand( ent-g_entities, va("team \"%s\"", g_redTeamClientNumbers.string));
- break;
- case TEAM_BLUE:
- trap_SendServerCommand( ent-g_entities, va("team \"%s\"", g_blueTeamClientNumbers.string));
- break;
- default:
- trap_SendServerCommand( ent-g_entities, "team \"all\"");
- };
-}
-
-/*
-==================
-AttackingTeamMessage
-
-==================
-*/
-void AttackingTeamMessage( gentity_t *ent ) {
- int team;
- if ( (level.eliminationSides+level.roundNumber)%2 == 0 )
- team = TEAM_RED;
- else
- team = TEAM_BLUE;
- trap_SendServerCommand( ent-g_entities, va("attackingteam %i", team));
-}
-
-/*
-==================
-ChallengeMessage
-
-==================
-*/
-
-void ChallengeMessage(gentity_t *ent, int challenge) {
- if ( level.warmupTime != 0)
- return; //We don't send anything doring warmup
- trap_SendServerCommand( ent-g_entities, va("ch %u", challenge) );
-}
-
-/*
-==================
-SendCustomVoteCommands
-
-==================
-*/
-
-void SendCustomVoteCommands(int clientNum) {
- trap_SendServerCommand( clientNum, va("customvotes %s", custom_vote_info) );
-}
-
-/*
-==================
-Cmd_Score_f
-
-Request current scoreboard information
-==================
-*/
-void Cmd_Score_f( gentity_t *ent ) {
- DeathmatchScoreboardMessage( ent );
-}
-
-
-
-/*
-==================
-CheatsOk
-==================
-*/
-qboolean CheatsOk( gentity_t *ent ) {
- if ( !g_cheats.integer ) {
- trap_SendServerCommand( ent-g_entities, va("print \"Cheats are not enabled on this server.\n\""));
- return qfalse;
- }
- if ( ent->health <= 0 ) {
- trap_SendServerCommand( ent-g_entities, va("print \"You must be alive to use this command.\n\""));
- return qfalse;
- }
- return qtrue;
-}
-
-
-/*
-==================
-ConcatArgs
-==================
-*/
-char *ConcatArgs( int start ) {
- int i, c, tlen;
- static char line[MAX_STRING_CHARS];
- int len;
- char arg[MAX_STRING_CHARS];
-
- len = 0;
- c = trap_Argc();
- for ( i = start ; i < c ; i++ ) {
- trap_Argv( i, arg, sizeof( arg ) );
- tlen = strlen( arg );
- if ( len + tlen >= MAX_STRING_CHARS - 1 ) {
- break;
- }
- memcpy( line + len, arg, tlen );
- len += tlen;
- if ( i != c - 1 ) {
- line[len] = ' ';
- len++;
- }
- }
-
- line[len] = 0;
-
- return line;
-}
-
-/*
-==================
-ClientNumberFromString
-
-Returns a player number for either a number or name string
-Returns -1 if invalid
-==================
-*/
-int ClientNumberFromString( gentity_t *to, char *s ) {
- gclient_t *cl;
- int idnum;
- char cleanName[MAX_STRING_CHARS];
-
- // numeric values are just slot numbers
- if (s[0] >= '0' && s[0] <= '9') {
- idnum = atoi( s );
- if ( idnum < 0 || idnum >= level.maxclients ) {
- trap_SendServerCommand( to-g_entities, va("print \"Bad client slot: %i\n\"", idnum));
- return -1;
- }
-
- cl = &level.clients[idnum];
- if ( cl->pers.connected != CON_CONNECTED ) {
- trap_SendServerCommand( to-g_entities, va("print \"Client %i is not active\n\"", idnum));
- return -1;
- }
- return idnum;
- }
-
- // check for a name match
- for ( idnum=0,cl=level.clients ; idnum < level.maxclients ; idnum++,cl++ ) {
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- Q_strncpyz(cleanName, cl->pers.netname, sizeof(cleanName));
- Q_CleanStr(cleanName);
- if ( !Q_stricmp( cleanName, s ) ) {
- return idnum;
- }
- }
-
- trap_SendServerCommand( to-g_entities, va("print \"User %s is not on the server\n\"", s));
- return -1;
-}
-
-/*
-==================
-Cmd_Give_f
-
-Give items to a client
-==================
-*/
-void Cmd_Give_f (gentity_t *ent)
-{
- char *name;
- gitem_t *it;
- int i;
- qboolean give_all;
- gentity_t *it_ent;
- trace_t trace;
-
- if ( !CheatsOk( ent ) ) {
- return;
- }
-
- name = ConcatArgs( 1 );
-
- if (Q_stricmp(name, "all") == 0)
- give_all = qtrue;
- else
- give_all = qfalse;
-
- if (give_all || Q_stricmp( name, "health") == 0)
- {
- ent->health = ent->client->ps.stats[STAT_MAX_HEALTH];
- if (!give_all)
- return;
- }
-
- if (give_all || Q_stricmp(name, "weapons") == 0)
- {
- ent->client->ps.stats[STAT_WEAPONS] = (1 << WP_NUM_WEAPONS) - 1 -
- ( 1 << WP_GRAPPLING_HOOK ) - ( 1 << WP_NONE );
- if (!give_all)
- return;
- }
-
- if (give_all || Q_stricmp(name, "ammo") == 0)
- {
- for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
- ent->client->ps.ammo[i] = 999;
- }
- if (!give_all)
- return;
- }
-
- if (give_all || Q_stricmp(name, "armor") == 0)
- {
- ent->client->ps.stats[STAT_ARMOR] = 200;
-
- if (!give_all)
- return;
- }
-
- if (Q_stricmp(name, "excellent") == 0) {
- ent->client->ps.persistant[PERS_EXCELLENT_COUNT]++;
- return;
- }
- if (Q_stricmp(name, "impressive") == 0) {
- ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
- return;
- }
- if (Q_stricmp(name, "gauntletaward") == 0) {
- ent->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;
- return;
- }
- if (Q_stricmp(name, "defend") == 0) {
- ent->client->ps.persistant[PERS_DEFEND_COUNT]++;
- return;
- }
- if (Q_stricmp(name, "assist") == 0) {
- ent->client->ps.persistant[PERS_ASSIST_COUNT]++;
- return;
- }
-
- // spawn a specific item right on the player
- if ( !give_all ) {
- it = BG_FindItem (name);
- if (!it) {
- return;
- }
-
- it_ent = G_Spawn();
- VectorCopy( ent->r.currentOrigin, it_ent->s.origin );
- it_ent->classname = it->classname;
- G_SpawnItem (it_ent, it);
- FinishSpawningItem(it_ent );
- memset( &trace, 0, sizeof( trace ) );
- Touch_Item (it_ent, ent, &trace);
- if (it_ent->inuse) {
- G_FreeEntity( it_ent );
- }
- }
-}
-
-
-/*
-==================
-Cmd_God_f
-
-Sets client to godmode
-
-argv(0) god
-==================
-*/
-void Cmd_God_f (gentity_t *ent)
-{
- char *msg;
-
- if ( !CheatsOk( ent ) ) {
- return;
- }
-
- ent->flags ^= FL_GODMODE;
- if (!(ent->flags & FL_GODMODE) )
- msg = "godmode OFF\n";
- else
- msg = "godmode ON\n";
-
- trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg));
-}
-
-
-/*
-==================
-Cmd_Notarget_f
-
-Sets client to notarget
-
-argv(0) notarget
-==================
-*/
-void Cmd_Notarget_f( gentity_t *ent ) {
- char *msg;
-
- if ( !CheatsOk( ent ) ) {
- return;
- }
-
- ent->flags ^= FL_NOTARGET;
- if (!(ent->flags & FL_NOTARGET) )
- msg = "notarget OFF\n";
- else
- msg = "notarget ON\n";
-
- trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg));
-}
-
-
-/*
-==================
-Cmd_Noclip_f
-
-argv(0) noclip
-==================
-*/
-void Cmd_Noclip_f( gentity_t *ent ) {
- char *msg;
-
- if ( !CheatsOk( ent ) ) {
- return;
- }
-
- if ( ent->client->noclip ) {
- msg = "noclip OFF\n";
- } else {
- msg = "noclip ON\n";
- }
- ent->client->noclip = !ent->client->noclip;
-
- trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg));
-}
-
-
-/*
-==================
-Cmd_LevelShot_f
-
-This is just to help generate the level pictures
-for the menus. It goes to the intermission immediately
-and sends over a command to the client to resize the view,
-hide the scoreboard, and take a special screenshot
-==================
-*/
-void Cmd_LevelShot_f( gentity_t *ent ) {
- if ( !CheatsOk( ent ) ) {
- return;
- }
-
- // doesn't work in single player
- if ( g_gametype.integer != 0 ) {
- trap_SendServerCommand( ent-g_entities,
- "print \"Must be in g_gametype 0 for levelshot\n\"" );
- return;
- }
-
- BeginIntermission();
- trap_SendServerCommand( ent-g_entities, "clientLevelShot" );
-}
-
-
-/*
-==================
-Cmd_LevelShot_f
-
-This is just to help generate the level pictures
-for the menus. It goes to the intermission immediately
-and sends over a command to the client to resize the view,
-hide the scoreboard, and take a special screenshot
-==================
-*/
-void Cmd_TeamTask_f( gentity_t *ent ) {
- char userinfo[MAX_INFO_STRING];
- char arg[MAX_TOKEN_CHARS];
- int task;
- int client = ent->client - level.clients;
-
- if ( trap_Argc() != 2 ) {
- return;
- }
- trap_Argv( 1, arg, sizeof( arg ) );
- task = atoi( arg );
-
- trap_GetUserinfo(client, userinfo, sizeof(userinfo));
- Info_SetValueForKey(userinfo, "teamtask", va("%d", task));
- trap_SetUserinfo(client, userinfo);
- ClientUserinfoChanged(client);
-}
-
-
-
-/*
-=================
-Cmd_Kill_f
-=================
-*/
-void Cmd_Kill_f( gentity_t *ent ) {
- if ( (ent->client->sess.sessionTeam == TEAM_SPECTATOR) || ent->client->isEliminated ) {
- return;
- }
- if (ent->health <= 0) {
- return;
- }
- ent->flags &= ~FL_GODMODE;
- ent->client->ps.stats[STAT_HEALTH] = ent->health = -999;
- if(ent->client->lastSentFlying>-1)
- //If player is in the air because of knockback we give credit to the person who sent it flying
- player_die (ent, ent, &g_entities[ent->client->lastSentFlying], 100000, MOD_FALLING);
- else
- player_die (ent, ent, ent, 100000, MOD_SUICIDE);
-}
-
-/*
-=================
-BroadCastTeamChange
-
-Let everyone know about a team change
-=================
-*/
-void BroadcastTeamChange( gclient_t *client, int oldTeam )
-{
- if ( client->sess.sessionTeam == TEAM_RED ) {
- trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the red team.\n\"",
- client->pers.netname) );
- } else if ( client->sess.sessionTeam == TEAM_BLUE ) {
- trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the blue team.\n\"",
- client->pers.netname));
- } else if ( client->sess.sessionTeam == TEAM_SPECTATOR && oldTeam != TEAM_SPECTATOR ) {
- trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the spectators.\n\"",
- client->pers.netname));
- } else if ( client->sess.sessionTeam == TEAM_FREE ) {
- trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the battle.\n\"",
- client->pers.netname));
- }
-}
-
-/*
-=================
-SetTeam
-KK-OAX Modded this to accept a forced admin change.
-=================
-*/
-void SetTeam( gentity_t *ent, char *s ) {
- int team, oldTeam;
- gclient_t *client;
- int clientNum;
- spectatorState_t specState;
- int specClient;
- int teamLeader;
- char userinfo[MAX_INFO_STRING];
- qboolean force;
-
- force = G_admin_permission(ent, ADMF_FORCETEAMCHANGE);
-
- //
- // see what change is requested
- //
- client = ent->client;
-
- clientNum = client - level.clients;
- trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
- specClient = 0;
- specState = SPECTATOR_NOT;
- if ( !Q_stricmp( s, "scoreboard" ) || !Q_stricmp( s, "score" ) ) {
- team = TEAM_SPECTATOR;
- specState = SPECTATOR_SCOREBOARD;
- } else if ( !Q_stricmp( s, "follow1" ) ) {
- team = TEAM_SPECTATOR;
- specState = SPECTATOR_FOLLOW;
- specClient = -1;
- } else if ( !Q_stricmp( s, "follow2" ) ) {
- team = TEAM_SPECTATOR;
- specState = SPECTATOR_FOLLOW;
- specClient = -2;
- } else if ( !Q_stricmp( s, "spectator" ) || !Q_stricmp( s, "s" ) ) {
- team = TEAM_SPECTATOR;
- specState = SPECTATOR_FREE;
- } else if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
- // if running a team game, assign player to one of the teams
- specState = SPECTATOR_NOT;
- if ( !Q_stricmp( s, "red" ) || !Q_stricmp( s, "r" ) ) {
- team = TEAM_RED;
- } else if ( !Q_stricmp( s, "blue" ) || !Q_stricmp( s, "b" ) ) {
- team = TEAM_BLUE;
- } else {
- // pick the team with the least number of players
- team = PickTeam( clientNum );
- }
- if ( !force ) {
- if ( g_teamForceBalance.integer ) {
- int counts[TEAM_NUM_TEAMS];
-
- counts[TEAM_BLUE] = TeamCount( ent->client->ps.clientNum, TEAM_BLUE );
- counts[TEAM_RED] = TeamCount( ent->client->ps.clientNum, TEAM_RED );
-
- // We allow a spread of two
- if ( team == TEAM_RED && counts[TEAM_RED] - counts[TEAM_BLUE] > 1 ) {
- trap_SendServerCommand( ent->client->ps.clientNum,
- "cp \"Red team has too many players.\n\"" );
- return; // ignore the request
- }
- if ( team == TEAM_BLUE && counts[TEAM_BLUE] - counts[TEAM_RED] > 1 ) {
- trap_SendServerCommand( ent->client->ps.clientNum,
- "cp \"Blue team has too many players.\n\"" );
- return; // ignore the request
- }
-
- // It's ok, the team we are switching to has less or same number of players
- }
- }
- } else {
- // force them to spectators if there aren't any spots free
- team = TEAM_FREE;
- }
- if ( !force ) {
- // override decision if limiting the players
- if ( (g_gametype.integer == GT_TOURNAMENT)
- && level.numNonSpectatorClients >= 2 ) {
- team = TEAM_SPECTATOR;
- } else if ( g_maxGameClients.integer > 0 &&
- level.numNonSpectatorClients >= g_maxGameClients.integer ) {
- team = TEAM_SPECTATOR;
- }
- }
-
- //
- // decide if we will allow the change
- //
- oldTeam = client->sess.sessionTeam;
- if ( team == oldTeam && team != TEAM_SPECTATOR ) {
- return;
- }
- //KK-OAX Check to make sure the team is not locked from Admin
- if ( !force ) {
- if ( team == TEAM_RED && level.RedTeamLocked ) {
- trap_SendServerCommand( ent->client->ps.clientNum,
- "cp \"The Red Team has been locked by the Admin! \n\"" );
- return;
- }
- if ( team == TEAM_BLUE && level.BlueTeamLocked ) {
- trap_SendServerCommand( ent->client->ps.clientNum,
- "cp \"The Blue Team has been locked by the Admin! \n\"" );
- return;
- }
- if ( team == TEAM_FREE && level.FFALocked ) {
- trap_SendServerCommand( ent->client->ps.clientNum,
- "cp \"This Deathmatch has been locked by the Admin! \n\"" );
- return;
- }
- }
- //
- // execute the team change
- //
-
- // if the player was dead leave the body
- if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
- CopyToBodyQue(ent);
- }
-
- // he starts at 'base'
- client->pers.teamState.state = TEAM_BEGIN;
- if ( oldTeam != TEAM_SPECTATOR ) {
- //Prevent a team from loosing point because of player leaving team
- if(g_gametype.integer == GT_TEAM && ent->client->ps.stats[STAT_HEALTH])
- level.teamScores[ ent->client->sess.sessionTeam ]++;
- // Kill him (makes sure he loses flags, etc)
- ent->flags &= ~FL_GODMODE;
- ent->client->ps.stats[STAT_HEALTH] = ent->health = 0;
- player_die (ent, ent, ent, 100000, MOD_SUICIDE);
-
- }
-
- if(oldTeam!=TEAM_SPECTATOR)
- PlayerStore_store(Info_ValueForKey(userinfo,"cl_guid"),client->ps);
-
- // they go to the end of the line for tournements
- if ( team == TEAM_SPECTATOR ) {
- client->sess.spectatorTime = level.time;
- }
-
- client->sess.sessionTeam = team;
- client->sess.spectatorState = specState;
- client->sess.spectatorClient = specClient;
-
- client->sess.teamLeader = qfalse;
- if ( team == TEAM_RED || team == TEAM_BLUE ) {
- teamLeader = TeamLeader( team );
- // if there is no team leader or the team leader is a bot and this client is not a bot
- if ( teamLeader == -1 || ( !(g_entities[clientNum].r.svFlags & SVF_BOT) && (g_entities[teamLeader].r.svFlags & SVF_BOT) ) ) {
- SetLeader( team, clientNum );
- }
- }
- // make sure there is a team leader on the team the player came from
- if ( oldTeam == TEAM_RED || oldTeam == TEAM_BLUE ) {
- CheckTeamLeader( oldTeam );
- }
-
- BroadcastTeamChange( client, oldTeam );
-
- // get and distribute relevent paramters
- ClientUserinfoChanged( clientNum );
-
- ClientBegin( clientNum );
-}
-
-/*
-=================
-StopFollowing
-
-If the client being followed leaves the game, or you just want to drop
-to free floating spectator mode
-=================
-*/
-void StopFollowing( gentity_t *ent ) {
- if(g_gametype.integer<GT_ELIMINATION || g_gametype.integer>GT_LMS)
- {
- //Shouldn't this already be the case?
- ent->client->ps.persistant[ PERS_TEAM ] = TEAM_SPECTATOR;
- ent->client->sess.sessionTeam = TEAM_SPECTATOR;
- }
- else {
- ent->client->ps.stats[STAT_HEALTH] = 0;
- ent->health = 0;
- }
- ent->client->sess.spectatorState = SPECTATOR_FREE;
- ent->client->ps.pm_flags &= ~PMF_FOLLOW;
- ent->r.svFlags &= ~SVF_BOT;
- ent->client->ps.clientNum = ent - g_entities;
-}
-
-/*
-=================
-Cmd_Team_f
-=================
-*/
-void Cmd_Team_f( gentity_t *ent ) {
- int oldTeam;
- char s[MAX_TOKEN_CHARS];
- qboolean force;
-
- if ( trap_Argc() != 2 ) {
- oldTeam = ent->client->sess.sessionTeam;
- switch ( oldTeam ) {
- case TEAM_BLUE:
- trap_SendServerCommand( ent-g_entities, "print \"Blue team\n\"" );
- break;
- case TEAM_RED:
- trap_SendServerCommand( ent-g_entities, "print \"Red team\n\"" );
- break;
- case TEAM_FREE:
- trap_SendServerCommand( ent-g_entities, "print \"Deathmatch-Playing\n\"" );
- break;
- case TEAM_SPECTATOR:
- trap_SendServerCommand( ent-g_entities, "print \"Spectator team\n\"" );
- break;
- }
- return;
- }
-
- force = G_admin_permission(ent, ADMF_FORCETEAMCHANGE);
-
- if( !force ) {
- if ( ent->client->switchTeamTime > level.time ) {
- trap_SendServerCommand( ent-g_entities, "print \"May not switch teams more than once per 5 seconds.\n\"" );
- return;
- }
- }
-
- // if they are playing a tournement game, count as a loss
- if ( (g_gametype.integer == GT_TOURNAMENT )
- && ent->client->sess.sessionTeam == TEAM_FREE ) {
- ent->client->sess.losses++;
- }
-
- trap_Argv( 1, s, sizeof( s ) );
-
- SetTeam( ent, s );
-
- ent->client->switchTeamTime = level.time + 5000;
-}
-
-
-/*
-=================
-Cmd_Follow_f
-=================
-*/
-void Cmd_Follow_f( gentity_t *ent ) {
- int i;
- char arg[MAX_TOKEN_CHARS];
-
- if ( trap_Argc() != 2 ) {
- if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {
- StopFollowing( ent );
- }
- return;
- }
-
-
- trap_Argv( 1, arg, sizeof( arg ) );
- i = ClientNumberFromString( ent, arg );
- if ( i == -1 ) {
- return;
- }
-
-
-
- // can't follow self
- if ( &level.clients[ i ] == ent->client ) {
- return;
- }
-
- // can't follow another spectator (or an eliminated player)
- if ( (level.clients[ i ].sess.sessionTeam == TEAM_SPECTATOR) || level.clients[ i ].isEliminated) {
- return;
- }
-
- if ( (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) && g_elimination_lockspectator.integer
- && ((ent->client->sess.sessionTeam == TEAM_RED && level.clients[ i ].sess.sessionTeam == TEAM_BLUE) ||
- (ent->client->sess.sessionTeam == TEAM_BLUE && level.clients[ i ].sess.sessionTeam == TEAM_RED) ) ) {
- return;
- }
-
- // if they are playing a tournement game, count as a loss
- if ( (g_gametype.integer == GT_TOURNAMENT )
- && ent->client->sess.sessionTeam == TEAM_FREE ) {
- ent->client->sess.losses++;
- }
-
- // first set them to spectator
- //if ( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
- if ( ent->client->sess.spectatorState == SPECTATOR_NOT ) {
- SetTeam( ent, "spectator" );
- }
-
- ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
- ent->client->sess.spectatorClient = i;
-}
-
-/*
-=================
-Cmd_FollowCycle_f
-KK-OAX Modified to trap arguments.
-=================
-*/
-void Cmd_FollowCycle_f( gentity_t *ent ) {
- int clientnum;
- int original;
- int count;
- char args[11];
- int dir;
-
- if( ent->client->sess.sessionTeam == TEAM_NONE ) {
- dir = 1;
- }
-
- trap_Argv( 0, args, sizeof( args ) );
- if( Q_stricmp( args, "followprev" ) == 0 ) {
- dir = -1;
- } else if( Q_stricmp( args, "follownext" ) == 0 ) {
- dir = 1;
- } else {
- dir = 1;
- }
-
- // if they are playing a tournement game, count as a loss
- if ( (g_gametype.integer == GT_TOURNAMENT )
- && ent->client->sess.sessionTeam == TEAM_FREE ) {
- ent->client->sess.losses++;
- }
- // first set them to spectator
- if ( ent->client->sess.spectatorState == SPECTATOR_NOT ) {
- SetTeam( ent, "spectator" );
- }
-
- if ( dir != 1 && dir != -1 ) {
- G_Error( "Cmd_FollowCycle_f: bad dir %i", dir );
- }
-
- clientnum = ent->client->sess.spectatorClient;
- original = clientnum;
- count = 0;
- do {
- clientnum += dir;
- count++;
- if ( clientnum >= level.maxclients ) {
- clientnum = 0;
- }
- if ( clientnum < 0 ) {
- clientnum = level.maxclients - 1;
- }
-
- if(count>level.maxclients) //We have looked at all clients at least once and found nothing
- return; //We might end up in an infinite loop here. Stop it!
-
- // can only follow connected clients
- if ( level.clients[ clientnum ].pers.connected != CON_CONNECTED ) {
- continue;
- }
-
- // can't follow another spectator
- if ( (level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR) || level.clients[ clientnum ].isEliminated) {
- continue;
- }
-
- //Stop players from spectating players on the enemy team in elimination modes.
- if ( (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) && g_elimination_lockspectator.integer
- && ((ent->client->sess.sessionTeam == TEAM_RED && level.clients[ clientnum ].sess.sessionTeam == TEAM_BLUE) ||
- (ent->client->sess.sessionTeam == TEAM_BLUE && level.clients[ clientnum ].sess.sessionTeam == TEAM_RED) ) ) {
- continue;
- }
-
- // this is good, we can use it
- ent->client->sess.spectatorClient = clientnum;
- ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
- return;
- } while ( clientnum != original );
-
- // leave it where it was
-}
-
-
-/*
-==================
-G_Say
-==================
-*/
-
-static void G_SayTo( gentity_t *ent, gentity_t *other, int mode, int color, const char *name, const char *message ) {
- if (!other) {
- return;
- }
- if (!other->inuse) {
- return;
- }
- if (!other->client) {
- return;
- }
- if ( other->client->pers.connected != CON_CONNECTED ) {
- return;
- }
- if ( mode == SAY_TEAM && !OnSameTeam(ent, other) ) {
- return;
- }
-
- if ((ent->r.svFlags & SVF_BOT) && trap_Cvar_VariableValue( "bot_nochat" )>1) return;
-
- // no chatting to players in tournements
- if ( (g_gametype.integer == GT_TOURNAMENT )
- && other->client->sess.sessionTeam == TEAM_FREE
- && ent->client->sess.sessionTeam != TEAM_FREE ) {
- return;
- }
-
- trap_SendServerCommand( other-g_entities, va("%s \"%s%c%c%s\"",
- mode == SAY_TEAM ? "tchat" : "chat",
- name, Q_COLOR_ESCAPE, color, message));
-}
-
-#define EC "\x19"
-
-void G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText ) {
- int j;
- gentity_t *other;
- int color;
- char name[64];
- // don't let text be too long for malicious reasons
- char text[MAX_SAY_TEXT];
- char location[64];
-
- if ((ent->r.svFlags & SVF_BOT) && trap_Cvar_VariableValue( "bot_nochat" )>1) return;
-
- if ( (g_gametype.integer < GT_TEAM || g_ffa_gt == 1) && mode == SAY_TEAM ) {
- mode = SAY_ALL;
- }
-
- switch ( mode ) {
- default:
- case SAY_ALL:
- G_LogPrintf( "say: %s: %s\n", ent->client->pers.netname, chatText );
- Com_sprintf (name, sizeof(name), "%s%c%c"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_GREEN;
- break;
- case SAY_TEAM:
- G_LogPrintf( "sayteam: %s: %s\n", ent->client->pers.netname, chatText );
- if (Team_GetLocationMsg(ent, location, sizeof(location)))
- Com_sprintf (name, sizeof(name), EC"(%s%c%c"EC") (%s)"EC": ",
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location);
- else
- Com_sprintf (name, sizeof(name), EC"(%s%c%c"EC")"EC": ",
- ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_CYAN;
- break;
- case SAY_TELL:
- if (target && g_gametype.integer >= GT_TEAM && g_ffa_gt != 1 &&
- target->client->sess.sessionTeam == ent->client->sess.sessionTeam &&
- Team_GetLocationMsg(ent, location, sizeof(location)))
- Com_sprintf (name, sizeof(name), EC"[%s%c%c"EC"] (%s)"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location );
- else
- Com_sprintf (name, sizeof(name), EC"[%s%c%c"EC"]"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE );
- color = COLOR_MAGENTA;
- break;
- }
-
- Q_strncpyz( text, chatText, sizeof(text) );
-
- if ( target ) {
- G_SayTo( ent, target, mode, color, name, text );
- return;
- }
-
- // echo the text to the console
- if ( g_dedicated.integer ) {
- G_Printf( "%s%s\n", name, text);
- }
-
- // send it to all the apropriate clients
- for (j = 0; j < level.maxclients; j++) {
- other = &g_entities[j];
- G_SayTo( ent, other, mode, color, name, text );
- }
- //KK-OAX Admin Command Check from Say/SayTeam line
- if( g_adminParseSay.integer )
- {
- G_admin_cmd_check ( ent, qtrue );
- }
-}
-
-
-/*
-==================
-Cmd_Say_f
-KK-OAX Modified this to trap the additional arguments from console.
-==================
-*/
-static void Cmd_Say_f( gentity_t *ent ){
- char *p;
- char arg[MAX_TOKEN_CHARS];
- int mode = SAY_ALL;
-
- trap_Argv( 0, arg, sizeof( arg ) );
- if( Q_stricmp ( arg, "say_team" ) == 0 )
- mode = SAY_TEAM ;
- // KK-OAX Disabled until PM'ing is added
- // support parsing /m out of say text since some people have a hard
- // time figuring out what the console is.
- /*if( !Q_stricmpn( args, "say /m ", 7 ) ||
- !Q_stricmpn( args, "say_team /m ", 12 ) ||
- !Q_stricmpn( args, "say /mt ", 8 ) ||
- !Q_stricmpn( args, "say_team /mt ", 13 ) )
- {
- Cmd_PrivateMessage_f( ent );
- return;
- }
-
- // support parsing /a out of say text for the same reason
- if( !Q_stricmpn( args, "say /a ", 7 ) ||
- !Q_stricmpn( args, "say_team /a ", 12 ) )
- {
- Cmd_AdminMessage_f( ent );
- return;
- }*/
-
- if( trap_Argc( ) < 2 )
- return;
-
- p = ConcatArgs( 1 );
-
- G_Say( ent, NULL, mode, p );
-}
-
-/*
-==================
-Cmd_Tell_f
-==================
-*/
-static void Cmd_Tell_f( gentity_t *ent ) {
- int targetNum;
- gentity_t *target;
- char *p;
- char arg[MAX_TOKEN_CHARS];
-
- if ( trap_Argc () < 2 ) {
- return;
- }
-
- trap_Argv( 1, arg, sizeof( arg ) );
- targetNum = atoi( arg );
- if ( targetNum < 0 || targetNum >= level.maxclients ) {
- return;
- }
-
- target = &g_entities[targetNum];
- if ( !target || !target->inuse || !target->client ) {
- return;
- }
-
- p = ConcatArgs( 2 );
-
- G_LogPrintf( "tell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, p );
- G_Say( ent, target, SAY_TELL, p );
- // don't tell to the player self if it was already directed to this player
- // also don't send the chat back to a bot
- if ( ent != target && !(ent->r.svFlags & SVF_BOT)) {
- G_Say( ent, ent, SAY_TELL, p );
- }
-}
-
-
-static void G_VoiceTo( gentity_t *ent, gentity_t *other, int mode, const char *id, qboolean voiceonly ) {
- int color;
- char *cmd;
-
- if (!other) {
- return;
- }
- if (!other->inuse) {
- return;
- }
- if (!other->client) {
- return;
- }
- if ( mode == SAY_TEAM && !OnSameTeam(ent, other) ) {
- return;
- }
- // no chatting to players in tournements
- if ( (g_gametype.integer == GT_TOURNAMENT )) {
- return;
- }
-
- if (mode == SAY_TEAM) {
- color = COLOR_CYAN;
- cmd = "vtchat";
- }
- else if (mode == SAY_TELL) {
- color = COLOR_MAGENTA;
- cmd = "vtell";
- }
- else {
- color = COLOR_GREEN;
- cmd = "vchat";
- }
-
- trap_SendServerCommand( other-g_entities, va("%s %d %d %d %s", cmd, voiceonly, ent->s.number, color, id));
-}
-
-void G_Voice( gentity_t *ent, gentity_t *target, int mode, const char *id, qboolean voiceonly ) {
- int j;
- gentity_t *other;
-
- if ( (g_gametype.integer < GT_TEAM || g_ffa_gt==1 ) && mode == SAY_TEAM ) {
- mode = SAY_ALL;
- }
-
- if ( target ) {
- G_VoiceTo( ent, target, mode, id, voiceonly );
- return;
- }
-
- // echo the text to the console
- if ( g_dedicated.integer ) {
- G_Printf( "voice: %s %s\n", ent->client->pers.netname, id);
- }
-
- // send it to all the apropriate clients
- for (j = 0; j < level.maxclients; j++) {
- other = &g_entities[j];
- G_VoiceTo( ent, other, mode, id, voiceonly );
- }
-}
-
-/*
-==================
-Cmd_Voice_f
-KK-OAX Modified this to trap args.
-
-In the original, every call to this function would always set "arg0" to false, and it was
-never passed along to other functions, so I removed/commented it out.
-==================
-*/
-static void Cmd_Voice_f( gentity_t *ent ) {
- char *p;
- char arg[MAX_TOKEN_CHARS];
- int mode = SAY_ALL;
- qboolean voiceonly = qfalse;
-
- trap_Argv( 0, arg, sizeof( arg ) );
- if((Q_stricmp ( arg, "vsay_team" ) == 0 ) ||
- Q_stricmp ( arg, "vosay_team" ) == 0 )
- mode = SAY_TEAM;
-
- if((Q_stricmp ( arg, "vosay" ) == 0 ) ||
- Q_stricmp ( arg, "vosay_team" ) == 0 )
- voiceonly = qtrue;
-
- //KK-OAX Removed "arg0" since it will always be set to qfalse.
- if ( trap_Argc () < 2 ) {
- return;
- }
- //KK-OAX This was tricky to figure out, but since none of the original command handlings
- //set it to "qtrue"...
-
- /*if (arg0)
- {
- p = ConcatArgs( 0 );
- }
- else
- {*/
- p = ConcatArgs( 1 );
- //}
-
- G_Voice( ent, NULL, mode, p, voiceonly );
-}
-
-/*
-==================
-Cmd_VoiceTell_f
-KK-OAX Modified this to trap args.
-==================
-*/
-static void Cmd_VoiceTell_f( gentity_t *ent ) {
- int targetNum;
- gentity_t *target;
- char *id;
- char arg[MAX_TOKEN_CHARS];
- qboolean voiceonly = qfalse;
-
- if ( trap_Argc () < 2 ) {
- return;
- }
-
- trap_Argv( 0, arg, sizeof( arg ) );
- if( Q_stricmp ( arg, "votell" ) == 0 )
- voiceonly = qtrue;
-
- trap_Argv( 1, arg, sizeof( arg ) );
- targetNum = atoi( arg );
- if ( targetNum < 0 || targetNum >= level.maxclients ) {
- return;
- }
-
- target = &g_entities[targetNum];
- if ( !target || !target->inuse || !target->client ) {
- return;
- }
-
- id = ConcatArgs( 2 );
-
- G_LogPrintf( "vtell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, id );
- G_Voice( ent, target, SAY_TELL, id, voiceonly );
- // don't tell to the player self if it was already directed to this player
- // also don't send the chat back to a bot
- if ( ent != target && !(ent->r.svFlags & SVF_BOT)) {
- G_Voice( ent, ent, SAY_TELL, id, voiceonly );
- }
-}
-
-
-/*
-==================
-Cmd_VoiceTaunt_f
-==================
-*/
-static void Cmd_VoiceTaunt_f( gentity_t *ent ) {
- gentity_t *who;
- int i;
-
- if (!ent->client) {
- return;
- }
-
- // insult someone who just killed you
- if (ent->enemy && ent->enemy->client && ent->enemy->client->lastkilled_client == ent->s.number) {
- // i am a dead corpse
- if (!(ent->enemy->r.svFlags & SVF_BOT)) {
- G_Voice( ent, ent->enemy, SAY_TELL, VOICECHAT_DEATHINSULT, qfalse );
- }
- if (!(ent->r.svFlags & SVF_BOT)) {
- G_Voice( ent, ent, SAY_TELL, VOICECHAT_DEATHINSULT, qfalse );
- }
- ent->enemy = NULL;
- return;
- }
- // insult someone you just killed
- if (ent->client->lastkilled_client >= 0 && ent->client->lastkilled_client != ent->s.number) {
- who = g_entities + ent->client->lastkilled_client;
- if (who->client) {
- // who is the person I just killed
- if (who->client->lasthurt_mod == MOD_GAUNTLET) {
- if (!(who->r.svFlags & SVF_BOT)) {
- G_Voice( ent, who, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse ); // and I killed them with a gauntlet
- }
- if (!(ent->r.svFlags & SVF_BOT)) {
- G_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse );
- }
- } else {
- if (!(who->r.svFlags & SVF_BOT)) {
- G_Voice( ent, who, SAY_TELL, VOICECHAT_KILLINSULT, qfalse ); // and I killed them with something else
- }
- if (!(ent->r.svFlags & SVF_BOT)) {
- G_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLINSULT, qfalse );
- }
- }
- ent->client->lastkilled_client = -1;
- return;
- }
- }
-
- if (g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
- // praise a team mate who just got a reward
- for(i = 0; i < MAX_CLIENTS; i++) {
- who = g_entities + i;
- if (who->client && who != ent && who->client->sess.sessionTeam == ent->client->sess.sessionTeam) {
- if (who->client->rewardTime > level.time) {
- if (!(who->r.svFlags & SVF_BOT)) {
- G_Voice( ent, who, SAY_TELL, VOICECHAT_PRAISE, qfalse );
- }
- if (!(ent->r.svFlags & SVF_BOT)) {
- G_Voice( ent, ent, SAY_TELL, VOICECHAT_PRAISE, qfalse );
- }
- return;
- }
- }
- }
- }
-
- // just say something
- G_Voice( ent, NULL, SAY_ALL, VOICECHAT_TAUNT, qfalse );
-}
-
-
-
-static char *gc_orders[] = {
- "hold your position",
- "hold this position",
- "come here",
- "cover me",
- "guard location",
- "search and destroy",
- "report"
-};
-
-void Cmd_GameCommand_f( gentity_t *ent ) {
- int player;
- int order;
- char str[MAX_TOKEN_CHARS];
-
- trap_Argv( 1, str, sizeof( str ) );
- player = atoi( str );
- trap_Argv( 2, str, sizeof( str ) );
- order = atoi( str );
-
- if ( player < 0 || player >= MAX_CLIENTS ) {
- return;
- }
- if ( order < 0 || order > sizeof(gc_orders)/sizeof(char *) ) {
- return;
- }
- G_Say( ent, &g_entities[player], SAY_TELL, gc_orders[order] );
- G_Say( ent, ent, SAY_TELL, gc_orders[order] );
-}
-
-/*
-==================
-Cmd_Where_f
-==================
-*/
-void Cmd_Where_f( gentity_t *ent ) {
- trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", vtos( ent->s.origin ) ) );
-}
-
-static const char *gameNames[] = {
- "Free For All",
- "Tournament",
- "Single Player",
- "Team Deathmatch",
- "Capture the Flag",
- "One Flag CTF",
- "Overload",
- "Harvester",
- "Elimination",
- "CTF Elimination",
- "Last Man Standing",
- "Double Domination",
- "Domination"
-};
-
-
-
-/*
-==================
-Cmd_CallVote_f
-==================
-*/
-void Cmd_CallVote_f( gentity_t *ent ) {
- char* c;
- int i;
- char arg1[MAX_STRING_TOKENS];
- char arg2[MAX_STRING_TOKENS];
- char buffer[256];
-
- if ( !g_allowVote.integer ) {
- trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here.\n\"" );
- return;
- }
-
- if ( level.voteTime ) {
- trap_SendServerCommand( ent-g_entities, "print \"A vote is already in progress.\n\"" );
- return;
- }
- if ( ent->client->pers.voteCount >= MAX_VOTE_COUNT ) {
- trap_SendServerCommand( ent-g_entities, "print \"You have called the maximum number of votes.\n\"" );
- return;
- }
- if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
- trap_SendServerCommand( ent-g_entities, "print \"Not allowed to call a vote as spectator.\n\"" );
- return;
- }
-
- // make sure it is a valid command to vote on
- trap_Argv( 1, arg1, sizeof( arg1 ) );
- trap_Argv( 2, arg2, sizeof( arg2 ) );
-
- // check for command separators in arg2
- for( c = arg2; *c; ++c) {
- switch(*c) {
- case '\n':
- case '\r':
- case ';':
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
- return;
- break;
- }
- }
-
-
- if ( !Q_stricmp( arg1, "map_restart" ) ) {
- } else if ( !Q_stricmp( arg1, "nextmap" ) ) {
- } else if ( !Q_stricmp( arg1, "map" ) ) {
- } else if ( !Q_stricmp( arg1, "g_gametype" ) ) {
- } else if ( !Q_stricmp( arg1, "kick" ) ) {
- } else if ( !Q_stricmp( arg1, "clientkick" ) ) {
- } else if ( !Q_stricmp( arg1, "g_doWarmup" ) ) {
- } else if ( !Q_stricmp( arg1, "timelimit" ) ) {
- } else if ( !Q_stricmp( arg1, "fraglimit" ) ) {
- } else if ( !Q_stricmp( arg1, "custom" ) ) {
- } else if ( !Q_stricmp( arg1, "shuffle" ) ) {
- } else {
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
- //trap_SendServerCommand( ent-g_entities, "print \"Vote commands are: map_restart, nextmap, map <mapname>, g_gametype <n>, kick <player>, clientkick <clientnum>, g_doWarmup, timelimit <time>, fraglimit <frags>.\n\"" );
- buffer[0] = 0;
- strcat(buffer,"print \"Vote commands are: ");
- if(allowedVote("map_restart"))
- strcat(buffer, "map_restart, ");
- if(allowedVote("nextmap"))
- strcat(buffer, "nextmap, ");
- if(allowedVote("map"))
- strcat(buffer, "map <mapname>, ");
- if(allowedVote("g_gametype"))
- strcat(buffer, "g_gametype <n>, ");
- if(allowedVote("kick"))
- strcat(buffer, "kick <player>, ");
- if(allowedVote("clientkick"))
- strcat(buffer, "clientkick <clientnum>, ");
- if(allowedVote("g_doWarmup"))
- strcat(buffer, "g_doWarmup, ");
- if(allowedVote("timelimit"))
- strcat(buffer, "timelimit <time>, ");
- if(allowedVote("fraglimit"))
- strcat(buffer, "fraglimit <frags>, ");
- if(allowedVote("shuffle"))
- strcat(buffer, "shuffle, ");
- if(allowedVote("custom"))
- strcat(buffer, "custom <special>, ");
- buffer[strlen(buffer)-2] = 0;
- strcat(buffer, ".\"");
- trap_SendServerCommand( ent-g_entities, buffer);
- return;
- }
-
- if(!allowedVote(arg1)) {
- trap_SendServerCommand( ent-g_entities, "print \"Not allowed here.\n\"" );
- buffer[0] = 0;
- strcat(buffer,"print \"Vote commands are: ");
- if(allowedVote("map_restart"))
- strcat(buffer, "map_restart, ");
- if(allowedVote("nextmap"))
- strcat(buffer, "nextmap, ");
- if(allowedVote("map"))
- strcat(buffer, "map <mapname>, ");
- if(allowedVote("g_gametype"))
- strcat(buffer, "g_gametype <n>, ");
- if(allowedVote("kick"))
- strcat(buffer, "kick <player>, ");
- if(allowedVote("clientkick"))
- strcat(buffer, "clientkick <clientnum>, ");
- if(allowedVote("shuffle"))
- strcat(buffer, "shuffle, ");
- if(allowedVote("g_doWarmup"))
- strcat(buffer, "g_doWarmup, ");
- if(allowedVote("timelimit"))
- strcat(buffer, "timelimit <time>, ");
- if(allowedVote("fraglimit"))
- strcat(buffer, "fraglimit <frags>, ");
- if(allowedVote("custom"))
- strcat(buffer, "custom <special>, ");
- buffer[strlen(buffer)-2] = 0;
- strcat(buffer, ".\"");
- trap_SendServerCommand( ent-g_entities, buffer);
- return;
- }
-
- // if there is still a vote to be executed
- if ( level.voteExecuteTime ) {
- level.voteExecuteTime = 0;
- trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.voteString ) );
- }
-
- // special case for g_gametype, check for bad values
- if ( !Q_stricmp( arg1, "g_gametype" ) ) {
- char s[MAX_STRING_CHARS];
- i = atoi( arg2 );
- if( i == GT_SINGLE_PLAYER || i < GT_FFA || i >= GT_MAX_GAME_TYPE) {
- trap_SendServerCommand( ent-g_entities, "print \"Invalid gametype.\n\"" );
- return;
- }
-
- if( i== g_gametype.integer ) {
- trap_SendServerCommand( ent-g_entities, "print \"This is current gametype\n\"" );
- return;
- }
-
- if(!allowedGametype(arg2)){
- trap_SendServerCommand( ent-g_entities, "print \"Gametype is not available.\n\"" );
- return;
- }
-
- trap_Cvar_VariableStringBuffer( "nextmap", s, sizeof(s) );
- if (*s) {
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %d; map_restart; set nextmap \"%s\"", arg1, i,s );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Change gametype to: %s?", gameNames[i] );
- } else {
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %d; mao_restart", arg1, i );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Change gametype to: %s?", gameNames[i] );
- }
- } else if ( !Q_stricmp( arg1, "map" ) ) {
- // special case for map changes, we want to reset the nextmap setting
- // this allows a player to change maps, but not upset the map rotation
- char s[MAX_STRING_CHARS];
-
- if(!allowedMap(arg2)){
- trap_SendServerCommand( ent-g_entities, "print \"Map is not available.\n\"" );
- return;
- }
-
- trap_Cvar_VariableStringBuffer( "nextmap", s, sizeof(s) );
- if (*s) {
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %s; set nextmap \"%s\"", arg1, arg2, s );
- } else {
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %s", arg1, arg2 );
- }
- //Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Change map to: %s?", arg2 );
- } else if ( !Q_stricmp( arg1, "nextmap" ) ) {
- char s[MAX_STRING_CHARS];
-
- //Sago: Needs to think about this, we miss code to parse if nextmap has arg2
- /*if(!allowedMap(arg2)){
- trap_SendServerCommand( ent-g_entities, "print \"Map is not available.\n\"" );
- return;
- }*/
-
- trap_Cvar_VariableStringBuffer( "nextmap", s, sizeof(s) );
- if (!*s) {
- trap_SendServerCommand( ent-g_entities, "print \"nextmap not set.\n\"" );
- return;
- }
- Com_sprintf( level.voteString, sizeof( level.voteString ), "vstr nextmap");
-
- //Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", "Next map?" );
- } else if ( !Q_stricmp( arg1, "fraglimit" ) ) {
- i = atoi(arg2);
- if(!allowedFraglimit(i)) {
- trap_SendServerCommand( ent-g_entities, "print \"Cannot set fraglimit.\n\"" );
- return;
- }
-
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s \"%d\"", arg1, i );
- if(i)
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Change fraglimit to: %d", i );
- else
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Remove fraglimit?");
- } else if ( !Q_stricmp( arg1, "timelimit" ) ) {
- i = atoi(arg2);
- if(!allowedTimelimit(i)) {
- trap_SendServerCommand( ent-g_entities, "print \"Cannot set timelimit.\n\"" );
- return;
- }
-
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s \"%d\"", arg1, i );
- if(i)
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Change timelimit to: %d", i );
- else
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Remove timelimit?" );
- } else if ( !Q_stricmp( arg1, "map_restart" ) ) {
- Com_sprintf( level.voteString, sizeof( level.voteString ), "map_restart" );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Restart map?" );
- } else if ( !Q_stricmp( arg1, "g_doWarmup" ) ) {
- i = atoi(arg2);
- if(i) {
- Com_sprintf( level.voteString, sizeof( level.voteString ), "g_doWarmup \"1\"" );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Enable warmup?" );
- }
- else {
- Com_sprintf( level.voteString, sizeof( level.voteString ), "g_doWarmup \"0\"" );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Disable warmup?" );
- }
- } else if ( !Q_stricmp( arg1, "clientkick" ) ) {
- i = atoi(arg2);
-
- if(i>=MAX_CLIENTS) { //Only numbers <128 is clients
- trap_SendServerCommand( ent-g_entities, "print \"Cannot kick that number.\n\"" );
- return;
- }
- Com_sprintf( level.voteString, sizeof( level.voteString ), "clientkick_game \"%d\"", i );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Kick %s?" , level.clients[i].pers.netname );
- } else if ( !Q_stricmp( arg1, "shuffle" ) ) {
- if(g_gametype.integer<GT_TEAM || g_ffa_gt==1) { //Not a team game
- trap_SendServerCommand( ent-g_entities, "print \"Can only be used in team games.\n\"" );
- return;
- }
-
- Com_sprintf( level.voteString, sizeof( level.voteString ), "shuffle" );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Shuffle teams?" );
- } else if ( !Q_stricmp( arg1, "kick" ) ) {
- i = 0;
- while(Q_stricmp(arg2,(g_entities+i)->client->pers.netname)) {
- //Not client i, try next
- i++;
- if(i>=MAX_CLIENTS){ //Only numbers <128 is clients
- trap_SendServerCommand( ent-g_entities, "print \"Cannot find the playername. Try clientkick instead.\n\"" );
- return;
- }
- }
-
- Com_sprintf( level.voteString, sizeof( level.voteString ), "clientkick_game \"%d\"", i );
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Kick %s?" , level.clients[i].pers.netname );
- } else if ( !Q_stricmp( arg1, "custom" ) ) {
- t_customvote customvote;
- //Sago: There must always be a test to ensure that length(arg2) is non-zero or the client might be able to execute random commands.
- if(strlen(arg2)<1) {
- trap_SendServerCommand( ent-g_entities, va("print \"Custom vote commands are: %s\n\"",custom_vote_info) );
- return;
- }
- customvote = getCustomVote(arg2);
- if(Q_stricmp(customvote.votename,arg2)) {
- trap_SendServerCommand( ent-g_entities, "print \"Command could not be found\n\"" );
- return;
- }
- Com_sprintf( level.voteString, sizeof( level.voteString ), "%s", customvote.command );
- if(strlen(customvote.displayname))
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", customvote.displayname );
- else
- Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", customvote.command );
- } else {
- //Com_sprintf( level.voteString, sizeof( level.voteString ), "%s \"%s\"", arg1, arg2 );
- //Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString );
- trap_SendServerCommand( ent-g_entities, "print \"Server vality check failed, appears to be my fault. Sorry\n\"" );
- return;
- }
-
- ent->client->pers.voteCount++;
- trap_SendServerCommand( -1, va("print \"%s called a vote.\n\"", ent->client->pers.netname ) );
-
- // start the voting, the caller autoamtically votes yes
- level.voteTime = level.time;
- level.voteYes = 1;
- level.voteNo = 0;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- level.clients[i].ps.eFlags &= ~EF_VOTED;
- level.clients[i].vote = 0;
- }
- ent->client->ps.eFlags |= EF_VOTED;
- ent->client->vote = 1;
- //Do a first count to make sure that numvotingclients is correct!
- CountVotes();
-
- trap_SetConfigstring( CS_VOTE_TIME, va("%i", level.voteTime ) );
- trap_SetConfigstring( CS_VOTE_STRING, level.voteDisplayString );
- trap_SetConfigstring( CS_VOTE_YES, va("%i", level.voteYes ) );
- trap_SetConfigstring( CS_VOTE_NO, va("%i", level.voteNo ) );
-}
-
-/*
-==================
-Cmd_Vote_f
-==================
-*/
-void Cmd_Vote_f( gentity_t *ent ) {
- char msg[64];
-
- if ( !level.voteTime ) {
- trap_SendServerCommand( ent-g_entities, "print \"No vote in progress.\n\"" );
- return;
- }
- /*if ( ent->client->ps.eFlags & EF_VOTED ) {
- trap_SendServerCommand( ent-g_entities, "print \"Vote already cast.\n\"" );
- return;
- }*/
- if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
- trap_SendServerCommand( ent-g_entities, "print \"Not allowed to vote as spectator.\n\"" );
- return;
- }
-
- trap_SendServerCommand( ent-g_entities, "print \"Vote cast.\n\"" );
-
- ent->client->ps.eFlags |= EF_VOTED;
-
- trap_Argv( 1, msg, sizeof( msg ) );
-
- if ( msg[0] == 'y' || msg[1] == 'Y' || msg[1] == '1' ) {
- ent->client->vote = 1;
- } else {
- ent->client->vote = -1;
- }
-
- //Re count the votes
- CountVotes();
-
- // a majority will be determined in CheckVote, which will also account
- // for players entering or leaving
-}
-
-/*
-==================
-Cmd_CallTeamVote_f
-==================
-*/
-void Cmd_CallTeamVote_f( gentity_t *ent ) {
- int i, team, cs_offset;
- char arg1[MAX_STRING_TOKENS];
- char arg2[MAX_STRING_TOKENS];
-
- team = ent->client->sess.sessionTeam;
- if ( team == TEAM_RED )
- cs_offset = 0;
- else if ( team == TEAM_BLUE )
- cs_offset = 1;
- else
- return;
-
- if ( !g_allowVote.integer ) {
- trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here.\n\"" );
- return;
- }
-
- if ( level.teamVoteTime[cs_offset] ) {
- trap_SendServerCommand( ent-g_entities, "print \"A team vote is already in progress.\n\"" );
- return;
- }
- if ( ent->client->pers.teamVoteCount >= MAX_VOTE_COUNT ) {
- trap_SendServerCommand( ent-g_entities, "print \"You have called the maximum number of team votes.\n\"" );
- return;
- }
- if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
- trap_SendServerCommand( ent-g_entities, "print \"Not allowed to call a vote as spectator.\n\"" );
- return;
- }
-
- // make sure it is a valid command to vote on
- trap_Argv( 1, arg1, sizeof( arg1 ) );
- arg2[0] = '\0';
- for ( i = 2; i < trap_Argc(); i++ ) {
- if (i > 2)
- strcat(arg2, " ");
- trap_Argv( i, &arg2[strlen(arg2)], sizeof( arg2 ) - strlen(arg2) );
- }
-
- if( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) {
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
- return;
- }
-
- if ( !Q_stricmp( arg1, "leader" ) ) {
- char netname[MAX_NETNAME], leader[MAX_NETNAME];
-
- if ( !arg2[0] ) {
- i = ent->client->ps.clientNum;
- }
- else {
- // numeric values are just slot numbers
- for (i = 0; i < 3; i++) {
- if ( !arg2[i] || arg2[i] < '0' || arg2[i] > '9' )
- break;
- }
- if ( i >= 3 || !arg2[i]) {
- i = atoi( arg2 );
- if ( i < 0 || i >= level.maxclients ) {
- trap_SendServerCommand( ent-g_entities, va("print \"Bad client slot: %i\n\"", i) );
- return;
- }
-
- if ( !g_entities[i].inuse ) {
- trap_SendServerCommand( ent-g_entities, va("print \"Client %i is not active\n\"", i) );
- return;
- }
- }
- else {
- Q_strncpyz(leader, arg2, sizeof(leader));
- Q_CleanStr(leader);
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].pers.connected == CON_DISCONNECTED )
- continue;
- if (level.clients[i].sess.sessionTeam != team)
- continue;
- Q_strncpyz(netname, level.clients[i].pers.netname, sizeof(netname));
- Q_CleanStr(netname);
- if ( !Q_stricmp(netname, leader) ) {
- break;
- }
- }
- if ( i >= level.maxclients ) {
- trap_SendServerCommand( ent-g_entities, va("print \"%s is not a valid player on your team.\n\"", arg2) );
- return;
- }
- }
- }
- Com_sprintf(arg2, sizeof(arg2), "%d", i);
- } else {
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
- trap_SendServerCommand( ent-g_entities, "print \"Team vote commands are: leader <player>.\n\"" );
- return;
- }
-
- Com_sprintf( level.teamVoteString[cs_offset], sizeof( level.teamVoteString[cs_offset] ), "%s %s", arg1, arg2 );
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].pers.connected == CON_DISCONNECTED )
- continue;
- if (level.clients[i].sess.sessionTeam == team)
- trap_SendServerCommand( i, va("print \"%s called a team vote.\n\"", ent->client->pers.netname ) );
- }
-
- // start the voting, the caller autoamtically votes yes
- level.teamVoteTime[cs_offset] = level.time;
- level.teamVoteYes[cs_offset] = 1;
- level.teamVoteNo[cs_offset] = 0;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if (level.clients[i].sess.sessionTeam == team)
- level.clients[i].ps.eFlags &= ~EF_TEAMVOTED;
- }
- ent->client->ps.eFlags |= EF_TEAMVOTED;
-
- trap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, va("%i", level.teamVoteTime[cs_offset] ) );
- trap_SetConfigstring( CS_TEAMVOTE_STRING + cs_offset, level.teamVoteString[cs_offset] );
- trap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, va("%i", level.teamVoteYes[cs_offset] ) );
- trap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, va("%i", level.teamVoteNo[cs_offset] ) );
-}
-
-/*
-==================
-Cmd_TeamVote_f
-==================
-*/
-void Cmd_TeamVote_f( gentity_t *ent ) {
- int team, cs_offset;
- char msg[64];
-
- team = ent->client->sess.sessionTeam;
- if ( team == TEAM_RED )
- cs_offset = 0;
- else if ( team == TEAM_BLUE )
- cs_offset = 1;
- else
- return;
-
- if ( !level.teamVoteTime[cs_offset] ) {
- trap_SendServerCommand( ent-g_entities, "print \"No team vote in progress.\n\"" );
- return;
- }
- if ( ent->client->ps.eFlags & EF_TEAMVOTED ) {
- trap_SendServerCommand( ent-g_entities, "print \"Team vote already cast.\n\"" );
- return;
- }
- if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
- trap_SendServerCommand( ent-g_entities, "print \"Not allowed to vote as spectator.\n\"" );
- return;
- }
-
- trap_SendServerCommand( ent-g_entities, "print \"Team vote cast.\n\"" );
-
- ent->client->ps.eFlags |= EF_TEAMVOTED;
-
- trap_Argv( 1, msg, sizeof( msg ) );
-
- if ( msg[0] == 'y' || msg[1] == 'Y' || msg[1] == '1' ) {
- level.teamVoteYes[cs_offset]++;
- trap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, va("%i", level.teamVoteYes[cs_offset] ) );
- } else {
- level.teamVoteNo[cs_offset]++;
- trap_SetConfigstring( CS_TEAMVOTE_NO + cs_offset, va("%i", level.teamVoteNo[cs_offset] ) );
- }
-
- // a majority will be determined in TeamCheckVote, which will also account
- // for players entering or leaving
-}
-
-
-/*
-=================
-Cmd_SetViewpos_f
-=================
-*/
-void Cmd_SetViewpos_f( gentity_t *ent ) {
- vec3_t origin, angles;
- char buffer[MAX_TOKEN_CHARS];
- int i;
-
- if ( !g_cheats.integer ) {
- trap_SendServerCommand( ent-g_entities, va("print \"Cheats are not enabled on this server.\n\""));
- return;
- }
- if ( trap_Argc() != 5 ) {
- trap_SendServerCommand( ent-g_entities, va("print \"usage: setviewpos x y z yaw\n\""));
- return;
- }
-
- VectorClear( angles );
- for ( i = 0 ; i < 3 ; i++ ) {
- trap_Argv( i + 1, buffer, sizeof( buffer ) );
- origin[i] = atof( buffer );
- }
-
- trap_Argv( 4, buffer, sizeof( buffer ) );
- angles[YAW] = atof( buffer );
-
- TeleportPlayer( ent, origin, angles );
-}
-
-
-
-/*
-=================
-Cmd_Stats_f
-=================
-*/
-void Cmd_Stats_f( gentity_t *ent ) {
-/*
- int max, n, i;
-
- max = trap_AAS_PointReachabilityAreaIndex( NULL );
-
- n = 0;
- for ( i = 0; i < max; i++ ) {
- if ( ent->client->areabits[i >> 3] & (1 << (i & 7)) )
- n++;
- }
-
- //trap_SendServerCommand( ent-g_entities, va("print \"visited %d of %d areas\n\"", n, max));
- trap_SendServerCommand( ent-g_entities, va("print \"%d%% level coverage\n\"", n * 100 / max));
-*/
-}
-
-void Cmd_GetMappage_f( gentity_t *ent ) {
- t_mappage page;
- char string[(MAX_MAPNAME+1)*MAPS_PER_PAGE+1];
- char arg[MAX_STRING_TOKENS];
- trap_Argv( 1, arg, sizeof( arg ) );
- page = getMappage(atoi(arg));
- Q_strncpyz(string,va("mappage %d %s %s %s %s %s %s %s %s %s %s",page.pagenumber,page.mapname[0],\
- page.mapname[1],page.mapname[2],page.mapname[3],page.mapname[4],page.mapname[5],\
- page.mapname[6],page.mapname[7],page.mapname[8],page.mapname[9]),sizeof(string));
- //G_Printf("Mappage sent: \"%s\"\n", string);
- trap_SendServerCommand( ent-g_entities, string );
-}
-
-//KK-OAX This is the table that ClientCommands runs the console entry against.
-commands_t cmds[ ] =
-{
- // normal commands
- { "team", 0, Cmd_Team_f },
- { "vote", 0, Cmd_Vote_f },
- /*{ "ignore", 0, Cmd_Ignore_f },
- { "unignore", 0, Cmd_Ignore_f },*/
-
- // communication commands
- { "tell", CMD_MESSAGE, Cmd_Tell_f },
- { "callvote", CMD_MESSAGE, Cmd_CallVote_f },
- { "callteamvote", CMD_MESSAGE|CMD_TEAM, Cmd_CallTeamVote_f },
- // can be used even during intermission
- { "say", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
- { "say_team", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
- { "vsay", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Voice_f },
- { "vsay_team", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Voice_f },
- { "vsay_local", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Voice_f },
- { "vtell", CMD_MESSAGE|CMD_INTERMISSION, Cmd_VoiceTell_f },
- { "vosay", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Voice_f },
- { "vosay_team", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Voice_f },
- { "vosay_local", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Voice_f },
- { "votell", CMD_MESSAGE|CMD_INTERMISSION, Cmd_VoiceTell_f },
- { "vtaunt", CMD_MESSAGE|CMD_INTERMISSION, Cmd_VoiceTaunt_f },
- /*{ "m", CMD_MESSAGE|CMD_INTERMISSION, Cmd_PrivateMessage_f },
- { "mt", CMD_MESSAGE|CMD_INTERMISSION, Cmd_PrivateMessage_f },
- { "a", CMD_MESSAGE|CMD_INTERMISSION, Cmd_AdminMessage_f },*/
-
- { "score", CMD_INTERMISSION, Cmd_Score_f },
-
- // cheats
- { "give", CMD_CHEAT|CMD_LIVING, Cmd_Give_f },
- { "god", CMD_CHEAT|CMD_LIVING, Cmd_God_f },
- { "notarget", CMD_CHEAT|CMD_LIVING, Cmd_Notarget_f },
- { "levelshot", CMD_CHEAT, Cmd_LevelShot_f },
- { "setviewpos", CMD_CHEAT, Cmd_SetViewpos_f },
- { "noclip", CMD_CHEAT, Cmd_Noclip_f },
-
- { "kill", CMD_TEAM|CMD_LIVING, Cmd_Kill_f },
- { "where", 0, Cmd_Where_f },
-
- // game commands
-
- { "follow", CMD_NOTEAM, Cmd_Follow_f },
- { "follownext", CMD_NOTEAM, Cmd_FollowCycle_f },
- { "followprev", CMD_NOTEAM, Cmd_FollowCycle_f },
-
- { "teamvote", CMD_TEAM, Cmd_TeamVote_f },
- { "teamtask", CMD_TEAM, Cmd_TeamTask_f },
- //KK-OAX
- { "freespectator", CMD_NOTEAM, StopFollowing },
- { "getmappage", 0, Cmd_GetMappage_f },
- { "gc", 0, Cmd_GameCommand_f }
-
-};
-
-static int numCmds = sizeof( cmds ) / sizeof( cmds[ 0 ] );
-
-/*
-=================
-ClientCommand
-KK-OAX, Takes the client command and runs it through a loop which matches
-it against the table.
-=================
-*/
-void ClientCommand( int clientNum )
-{
- gentity_t *ent;
- char cmd[ MAX_TOKEN_CHARS ];
- int i;
-
- ent = g_entities + clientNum;
- if( !ent->client )
- return; // not fully in game yet
-
- trap_Argv( 0, cmd, sizeof( cmd ) );
-
- for( i = 0; i < numCmds; i++ )
- {
- if( Q_stricmp( cmd, cmds[ i ].cmdName ) == 0 )
- break;
- }
-
- if( i == numCmds )
- { // KK-OAX Admin Command Check
- if( !G_admin_cmd_check( ent, qfalse ) )
- trap_SendServerCommand( clientNum,
- va( "print \"Unknown command %s\n\"", cmd ) );
- return;
- }
-
- // do tests here to reduce the amount of repeated code
- if( !( cmds[ i ].cmdFlags & CMD_INTERMISSION ) && level.intermissiontime )
- return;
-
- if( cmds[ i ].cmdFlags & CMD_CHEAT && !g_cheats.integer )
- {
- trap_SendServerCommand( clientNum,
- "print \"Cheats are not enabled on this server\n\"" );
- return;
- }
- //KK-OAX When the corresponding code is integrated, I will activate these.
- //if( cmds[ i ].cmdFlags & CMD_MESSAGE &&
- // ( ent->client->pers.muted || G_FloodLimited( ent ) ) )
- // return;
-
- //KK-OAX Do I need to change this for FFA gametype?
- if( cmds[ i ].cmdFlags & CMD_TEAM &&
- ent->client->sess.sessionTeam == TEAM_SPECTATOR )
- {
- trap_SendServerCommand( clientNum, "print \"Join a team first\n\"" );
- return;
- }
-
- if( ( cmds[ i ].cmdFlags & CMD_NOTEAM ||
- ( cmds[ i ].cmdFlags & CMD_CHEAT_TEAM && !g_cheats.integer ) ) &&
- ent->client->sess.sessionTeam != TEAM_NONE )
- {
- trap_SendServerCommand( clientNum,
- "print \"Cannot use this command when on a team\n\"" );
- return;
- }
-
- if( cmds[ i ].cmdFlags & CMD_RED &&
- ent->client->sess.sessionTeam != TEAM_RED )
- {
- trap_SendServerCommand( clientNum,
- "print \"Must be on the Red Team to use this command\n\"" );
- return;
- }
-
- if( cmds[ i ].cmdFlags & CMD_BLUE &&
- ent->client->sess.sessionTeam != TEAM_BLUE )
- {
- trap_SendServerCommand( clientNum,
- "print \"Must be on the Blue Team to use this command\n\"" );
- return;
- }
-
- if( ( ent->client->ps.pm_type == PM_DEAD ) && ( cmds[ i ].cmdFlags & CMD_LIVING ) )
- {
- trap_SendServerCommand( clientNum,
- "print \"Must be alive to use this command\n\"" );
- return;
- }
-
- cmds[ i ].cmdHandler( ent );
-}
-
diff --git a/game/code/game/g_combat.c b/game/code/game/g_combat.c
deleted file mode 100644
index f2185e6..0000000
--- a/game/code/game/g_combat.c
+++ /dev/null
@@ -1,1430 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// g_combat.c
-
-#include "g_local.h"
-#include "challenges.h"
-
-/*
-============
-ScorePlum
-============
-*/
-void ScorePlum( gentity_t *ent, vec3_t origin, int score ) {
- gentity_t *plum;
-
- plum = G_TempEntity( origin, EV_SCOREPLUM );
- // only send this temp entity to a single client
- plum->r.svFlags |= SVF_SINGLECLIENT;
- plum->r.singleClient = ent->s.number;
- //
- plum->s.otherEntityNum = ent->s.number;
- plum->s.time = score;
-}
-
-/*
-============
-AddScore
-
-Adds score to both the client and his team
-============
-*/
-void AddScore( gentity_t *ent, vec3_t origin, int score ) {
- int i;
-
- if ( !ent->client ) {
- return;
- }
- // no scoring during pre-match warmup
- if ( level.warmupTime ) {
- return;
- }
- // show score plum
- if( level.numNonSpectatorClients<3 && score < 0 && (g_gametype.integer<GT_TEAM || g_ffa_gt==1)) {
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[ i ].pers.connected != CON_CONNECTED )
- continue; //Client was not connected
-
- if (level.clients[i].sess.sessionTeam == TEAM_SPECTATOR)
- continue; //Don't give anything to spectators
-
- if (g_entities+i == ent)
- continue; //Don't award dead one
-
- level.clients[i].ps.persistant[PERS_SCORE] -= score;
- ScorePlum(ent, origin, -score);
- }
- }
- else {
- ScorePlum(ent, origin, score);
- //
- ent->client->ps.persistant[PERS_SCORE] += score;
- if ( g_gametype.integer == GT_TEAM )
- level.teamScores[ ent->client->ps.persistant[PERS_TEAM] ] += score;
- }
- CalculateRanks();
-}
-
-/*
-=================
-TossClientItems
-
-Toss the weapon and powerups for the killed player
-=================
-*/
-void TossClientItems( gentity_t *self ) {
- gitem_t *item;
- int weapon;
- float angle;
- int i;
- gentity_t *drop;
-
- // drop the weapon if not a gauntlet or machinegun
- weapon = self->s.weapon;
-
- //Never drop in elimination or last man standing mode!
- if( g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_LMS)
- return;
-
- // make a special check to see if they are changing to a new
- // weapon that isn't the mg or gauntlet. Without this, a client
- // can pick up a weapon, be killed, and not drop the weapon because
- // their weapon change hasn't completed yet and they are still holding the MG.
- if ( weapon == WP_MACHINEGUN || weapon == WP_GRAPPLING_HOOK ) {
- if ( self->client->ps.weaponstate == WEAPON_DROPPING ) {
- weapon = self->client->pers.cmd.weapon;
- }
- if ( !( self->client->ps.stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
- weapon = WP_NONE;
- }
- }
-
- if (g_instantgib.integer || g_rockets.integer || g_gametype.integer == GT_CTF_ELIMINATION || g_elimination_allgametypes.integer){
- //Nothing!
- }
- else
- if ( weapon > WP_MACHINEGUN && weapon != WP_GRAPPLING_HOOK &&
- self->client->ps.ammo[ weapon ] ) {
- // find the item type for this weapon
- item = BG_FindItemForWeapon( weapon );
-
- // spawn the item
- Drop_Item( self, item, 0 );
- }
-
- // drop all the powerups if not in teamplay
- if ( g_gametype.integer != GT_TEAM ) {
- angle = 45;
- for ( i = 1 ; i < PW_NUM_POWERUPS ; i++ ) {
- if ( self->client->ps.powerups[ i ] > level.time ) {
- item = BG_FindItemForPowerup( i );
- if ( !item ) {
- continue;
- }
- drop = Drop_Item( self, item, angle );
- // decide how many seconds it has left
- drop->count = ( self->client->ps.powerups[ i ] - level.time ) / 1000;
- if ( drop->count < 1 ) {
- drop->count = 1;
- }
- angle += 45;
- }
- }
- }
-}
-
-/*
-=================
-TossClientCubes
-=================
-*/
-extern gentity_t *neutralObelisk;
-
-void TossClientCubes( gentity_t *self ) {
- gitem_t *item;
- gentity_t *drop;
- vec3_t velocity;
- vec3_t angles;
- vec3_t origin;
-
- self->client->ps.generic1 = 0;
-
- // this should never happen but we should never
- // get the server to crash due to skull being spawned in
- if (!G_EntitiesFree()) {
- return;
- }
-
- if( self->client->sess.sessionTeam == TEAM_RED ) {
- item = BG_FindItem( "Red Cube" );
- }
- else {
- item = BG_FindItem( "Blue Cube" );
- }
-
- angles[YAW] = (float)(level.time % 360);
- angles[PITCH] = 0; // always forward
- angles[ROLL] = 0;
-
- AngleVectors( angles, velocity, NULL, NULL );
- VectorScale( velocity, 150, velocity );
- velocity[2] += 200 + crandom() * 50;
-
- if( neutralObelisk ) {
- VectorCopy( neutralObelisk->s.pos.trBase, origin );
- origin[2] += 44;
- } else {
- VectorClear( origin ) ;
- }
-
- drop = LaunchItem( item, origin, velocity );
-
- drop->nextthink = level.time + g_cubeTimeout.integer * 1000;
- drop->think = G_FreeEntity;
- drop->spawnflags = self->client->sess.sessionTeam;
-}
-
-/*
-=================
-TossClientPersistantPowerups
-=================
-*/
-void TossClientPersistantPowerups( gentity_t *ent ) {
- gentity_t *powerup;
-
- if( !ent->client ) {
- return;
- }
-
- if( !ent->client->persistantPowerup ) {
- return;
- }
-
- powerup = ent->client->persistantPowerup;
-
- powerup->r.svFlags &= ~SVF_NOCLIENT;
- powerup->s.eFlags &= ~EF_NODRAW;
- powerup->r.contents = CONTENTS_TRIGGER;
- trap_LinkEntity( powerup );
-
- ent->client->ps.stats[STAT_PERSISTANT_POWERUP] = 0;
- ent->client->persistantPowerup = NULL;
-}
-
-
-/*
-==================
-LookAtKiller
-==================
-*/
-void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker ) {
- vec3_t dir;
- vec3_t angles;
-
- if ( attacker && attacker != self ) {
- VectorSubtract (attacker->s.pos.trBase, self->s.pos.trBase, dir);
- } else if ( inflictor && inflictor != self ) {
- VectorSubtract (inflictor->s.pos.trBase, self->s.pos.trBase, dir);
- } else {
- self->client->ps.stats[STAT_DEAD_YAW] = self->s.angles[YAW];
- return;
- }
-
- self->client->ps.stats[STAT_DEAD_YAW] = vectoyaw ( dir );
-
- angles[YAW] = vectoyaw ( dir );
- angles[PITCH] = 0;
- angles[ROLL] = 0;
-}
-
-/*
-==================
-GibEntity
-==================
-*/
-void GibEntity( gentity_t *self, int killer ) {
- gentity_t *ent;
- int i;
-
- //if this entity still has kamikaze
- if (self->s.eFlags & EF_KAMIKAZE) {
- // check if there is a kamikaze timer around for this owner
- for (i = 0; i < MAX_GENTITIES; i++) {
- ent = &g_entities[i];
- if (!ent->inuse)
- continue;
- if (ent->activator != self)
- continue;
- if (strcmp(ent->classname, "kamikaze timer"))
- continue;
- G_FreeEntity(ent);
- break;
- }
- }
- G_AddEvent( self, EV_GIB_PLAYER, killer );
- self->takedamage = qfalse;
- self->s.eType = ET_INVISIBLE;
- self->r.contents = 0;
-}
-
-/*
-==================
-body_die
-==================
-*/
-void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
- if ( self->health > GIB_HEALTH ) {
- return;
- }
- if ( !g_blood.integer ) {
- self->health = GIB_HEALTH+1;
- return;
- }
-
- GibEntity( self, 0 );
-}
-
-
-// these are just for logging, the client prints its own messages
-char *modNames[] = {
- "MOD_UNKNOWN",
- "MOD_SHOTGUN",
- "MOD_GAUNTLET",
- "MOD_MACHINEGUN",
- "MOD_GRENADE",
- "MOD_GRENADE_SPLASH",
- "MOD_ROCKET",
- "MOD_ROCKET_SPLASH",
- "MOD_PLASMA",
- "MOD_PLASMA_SPLASH",
- "MOD_RAILGUN",
- "MOD_LIGHTNING",
- "MOD_BFG",
- "MOD_BFG_SPLASH",
- "MOD_WATER",
- "MOD_SLIME",
- "MOD_LAVA",
- "MOD_CRUSH",
- "MOD_TELEFRAG",
- "MOD_FALLING",
- "MOD_SUICIDE",
- "MOD_TARGET_LASER",
- "MOD_TRIGGER_HURT",
- "MOD_NAIL",
- "MOD_CHAINGUN",
- "MOD_PROXIMITY_MINE",
- "MOD_KAMIKAZE",
- "MOD_JUICED",
- "MOD_GRAPPLE"
-};
-
-/*
-==================
-Kamikaze_DeathActivate
-==================
-*/
-void Kamikaze_DeathActivate( gentity_t *ent ) {
- G_StartKamikaze(ent);
- G_FreeEntity(ent);
-}
-
-/*
-==================
-Kamikaze_DeathTimer
-==================
-*/
-void Kamikaze_DeathTimer( gentity_t *self ) {
- gentity_t *ent;
-
- ent = G_Spawn();
- ent->classname = "kamikaze timer";
- VectorCopy(self->s.pos.trBase, ent->s.pos.trBase);
- ent->r.svFlags |= SVF_NOCLIENT;
- ent->think = Kamikaze_DeathActivate;
- ent->nextthink = level.time + 5 * 1000;
-
- ent->activator = self;
-}
-
-
-/*
-==================
-CheckAlmostCapture
-==================
-*/
-void CheckAlmostCapture( gentity_t *self, gentity_t *attacker ) {
- gentity_t *ent;
- vec3_t dir;
- char *classname;
-
- // if this player was carrying a flag
- if ( self->client->ps.powerups[PW_REDFLAG] ||
- self->client->ps.powerups[PW_BLUEFLAG] ||
- self->client->ps.powerups[PW_NEUTRALFLAG] ) {
- // get the goal flag this player should have been going for
- if ( g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTF_ELIMINATION) {
- if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
- classname = "team_CTF_blueflag";
- }
- else {
- classname = "team_CTF_redflag";
- }
- }
- else {
- if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
- classname = "team_CTF_redflag";
- }
- else {
- classname = "team_CTF_blueflag";
- }
- }
- ent = NULL;
- do
- {
- ent = G_Find(ent, FOFS(classname), classname);
- } while (ent && (ent->flags & FL_DROPPED_ITEM));
- // if we found the destination flag and it's not picked up
- if (ent && !(ent->r.svFlags & SVF_NOCLIENT) ) {
- // if the player was *very* close
- VectorSubtract( self->client->ps.origin, ent->s.origin, dir );
- if ( VectorLength(dir) < 200 ) {
- self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
- if ( attacker->client ) {
- attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
- }
- }
- }
- }
-}
-
-/*
-==================
-CheckAlmostScored
-==================
-*/
-void CheckAlmostScored( gentity_t *self, gentity_t *attacker ) {
- gentity_t *ent;
- vec3_t dir;
- char *classname;
-
- // if the player was carrying cubes
- if ( self->client->ps.generic1 ) {
- if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
- classname = "team_redobelisk";
- }
- else {
- classname = "team_blueobelisk";
- }
- ent = G_Find(NULL, FOFS(classname), classname);
- // if we found the destination obelisk
- if ( ent ) {
- // if the player was *very* close
- VectorSubtract( self->client->ps.origin, ent->s.origin, dir );
- if ( VectorLength(dir) < 200 ) {
- self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
- if ( attacker->client ) {
- attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
- }
- }
- }
- }
-}
-
-/*
-==================
-player_die
-==================
-*/
-void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
- gentity_t *ent;
- int anim;
- int contents;
- int killer;
- int i,counter2;
- char *killerName, *obit;
-
- if ( self->client->ps.pm_type == PM_DEAD ) {
- return;
- }
-
- if ( level.intermissiontime ) {
- return;
- }
-
-//unlagged - backward reconciliation #2
- // make sure the body shows up in the client's current position
- G_UnTimeShiftClient( self );
-//unlagged - backward reconciliation #2
- //KK-OAX Here is where we run the streak logic.
- G_RunStreakLogic( attacker, self );
-
- // check for an almost capture
- CheckAlmostCapture( self, attacker );
- // check for a player that almost brought in cubes
- CheckAlmostScored( self, attacker );
-
- if (self->client && self->client->hook) {
- Weapon_HookFree(self->client->hook);
- }
- if ((self->client->ps.eFlags & EF_TICKING) && self->activator) {
- self->client->ps.eFlags &= ~EF_TICKING;
- self->activator->think = G_FreeEntity;
- self->activator->nextthink = level.time;
- }
- self->client->ps.pm_type = PM_DEAD;
-
- if ( attacker ) {
- killer = attacker->s.number;
- if ( attacker->client ) {
- killerName = attacker->client->pers.netname;
- } else {
- killerName = "<non-client>";
- }
- } else {
- killer = ENTITYNUM_WORLD;
- killerName = "<world>";
- }
-
- if ( killer < 0 || killer >= MAX_CLIENTS ) {
- killer = ENTITYNUM_WORLD;
- killerName = "<world>";
- }
-
- if ( meansOfDeath < 0 || meansOfDeath >= sizeof( modNames ) / sizeof( modNames[0] ) ) {
- obit = "<bad obituary>";
- } else {
- obit = modNames[meansOfDeath];
- }
-
- G_LogPrintf("Kill: %i %i %i: %s killed %s by %s\n",
- killer, self->s.number, meansOfDeath, killerName,
- self->client->pers.netname, obit );
-
- // broadcast the death event to everyone
- ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
- ent->s.eventParm = meansOfDeath;
- ent->s.otherEntityNum = self->s.number;
- ent->s.otherEntityNum2 = killer;
- //Sago: Hmmm... generic? Can I transmit anything I like? Like if it is a team kill? Let's try
- ent->s.generic1 = OnSameTeam (self, self->enemy);
- if( !((g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION) && level.time < level.roundStartTime) )
- ent->r.svFlags = SVF_BROADCAST; // send to everyone (if not an elimination gametype during active warmup)
- else
- ent->r.svFlags = SVF_NOCLIENT;
-
- self->enemy = attacker;
-
- self->client->ps.persistant[PERS_KILLED]++;
-
- if (attacker && attacker->client) {
- attacker->client->lastkilled_client = self->s.number;
-
- if ( attacker == self || OnSameTeam (self, attacker ) ) {
- if(g_gametype.integer!=GT_LMS && !((g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION) && level.time < level.roundStartTime))
- if(g_gametype.integer <GT_TEAM && g_ffa_gt!=1 && self->client->ps.persistant[PERS_SCORE]>0 || level.numNonSpectatorClients<3) //Cannot get negative scores by suicide
- AddScore( attacker, self->r.currentOrigin, -1 );
- } else {
- if(g_gametype.integer!=GT_LMS)
- AddScore( attacker, self->r.currentOrigin, 1 );
-
- if( meansOfDeath == MOD_GAUNTLET ) {
-
- // Attack gets a challenge complete:
- if(!(attacker->r.svFlags & SVF_BOT) && !(self->r.svFlags & SVF_BOT))
- ChallengeMessage(attacker,WEAPON_GAUNTLET_KILLS);
-
- // play humiliation on player
- attacker->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 0, attacker->client->pers.netname, "GAUNTLET" );
-
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_GAUNTLET;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- // also play humiliation on target
- self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_GAUNTLETREWARD;
- }
-
- //If neither attacker or taget is bots and not the same
- if(!(attacker->r.svFlags & SVF_BOT) && !(self->r.svFlags & SVF_BOT) && self!=attacker)
- {
- switch(meansOfDeath)
- {
- case MOD_GAUNTLET:
- ChallengeMessage(attacker,WEAPON_GAUNTLET_KILLS);
- break;
- case MOD_MACHINEGUN:
- ChallengeMessage(attacker,WEAPON_MACHINEGUN_KILLS);
- break;
- case MOD_SHOTGUN:
- ChallengeMessage(attacker,WEAPON_SHOTGUN_KILLS);
- break;
- case MOD_GRENADE:
- case MOD_GRENADE_SPLASH:
- ChallengeMessage(attacker,WEAPON_GRANADE_KILLS);
- break;
- case MOD_ROCKET:
- case MOD_ROCKET_SPLASH:
- ChallengeMessage(attacker,WEAPON_ROCKET_KILLS);
- break;
- case MOD_LIGHTNING:
- ChallengeMessage(attacker,WEAPON_LIGHTNING_KILLS);
- break;
- case MOD_PLASMA:
- case MOD_PLASMA_SPLASH:
- ChallengeMessage(attacker,WEAPON_PLASMA_KILLS);
- break;
- case MOD_RAILGUN:
- if(g_instantgib.integer)
- ChallengeMessage(attacker,WEAPON_INSTANT_RAIL_KILLS);
- else
- ChallengeMessage(attacker,WEAPON_RAIL_KILLS);
- break;
- case MOD_BFG:
- case MOD_BFG_SPLASH:
- ChallengeMessage(attacker,WEAPON_BFG_KILLS);
- break;
- case MOD_NAIL:
- ChallengeMessage(attacker,WEAPON_NAILGUN_KILLS);
- break;
- case MOD_CHAINGUN:
- ChallengeMessage(attacker,WEAPON_CHAINGUN_KILLS);
- break;
- case MOD_PROXIMITY_MINE:
- ChallengeMessage(attacker,WEAPON_MINE_KILLS);
- break;
- case MOD_GRAPPLE:
- ChallengeMessage(attacker,WEAPON_GRAPPLE_KILLS);
- break;
- case MOD_LAVA:
- case MOD_SLIME:
- case MOD_TRIGGER_HURT:
- case MOD_FALLING:
- ChallengeMessage(attacker,WEAPON_PUSH_KILLS);
- break;
- case MOD_CRUSH:
- ChallengeMessage(attacker,WEAPON_CRUSH_KILLS);
- break;
- case MOD_TELEFRAG:
- ChallengeMessage(attacker,WEAPON_TELEFRAG_KILLS);
- break;
- };
- ChallengeMessage(attacker,GENERAL_TOTALKILLS);
- ChallengeMessage(self,GENERAL_TOTALDEATHS);
-
- //Lets count number of powerups:
- i = 0;
- counter2 = 0;
-
- if(attacker->client->ps.powerups[PW_QUAD]) {
- ChallengeMessage(attacker,POWERUP_QUAD_KILL);
- counter2++;
- }
- if(self->client->ps.powerups[PW_QUAD]) {
- ChallengeMessage(attacker,POWERUP_COUNTER_QUAD);
- i++;
- }
-
- if(attacker->client->ps.powerups[PW_HASTE]) {
- ChallengeMessage(attacker,POWERUP_SPEED_KILL);
- counter2++;
- }
- if(self->client->ps.powerups[PW_HASTE]) {
- ChallengeMessage(attacker,POWERUP_COUNTER_SPEED);
- i++;
- }
-
- if(attacker->client->ps.powerups[PW_INVIS]) {
- ChallengeMessage(attacker,POWERUP_INVIS_KILL);
- counter2++;
- }
- if(self->client->ps.powerups[PW_INVIS]) {
- ChallengeMessage(attacker,POWERUP_COUNTER_INVIS);
- i++;
- }
-
- if(attacker->client->ps.powerups[PW_FLIGHT]) {
- ChallengeMessage(attacker,POWERUP_FLIGHT_KILL);
- counter2++;
- }
- if(self->client->ps.powerups[PW_FLIGHT]) {
- ChallengeMessage(attacker,POWERUP_COUNTER_FLIGHT);
- i++;
- }
-
- if(self->client->ps.powerups[PW_BATTLESUIT]) {
- ChallengeMessage(attacker,POWERUP_COUNTER_ENVIR);
- i++;
- }
-
- if(self->client->ps.powerups[PW_REGEN]) {
- ChallengeMessage(attacker,POWERUP_COUNTER_REGEN);
- i++;
- }
-
- if(i>1) //The target had more than one powerup
- ChallengeMessage(attacker,POWERUP_COUNTER_MULTI);
- if(counter2>1) //The attacker has more than one powerup
- ChallengeMessage(attacker,POWERUP_MULTI_KILL);
- }
-
- // check for two kills in a short amount of time
- // if this is close enough to the last kill, give a reward sound
- if ( level.time - attacker->client->lastKillTime < CARNAGE_REWARD_TIME ) {
- // KK-OAX
- // Check if Multikills are enabled
- if( g_altExcellent.integer ) {
- attacker->client->pers.multiKillCount++;
- G_checkForMultiKill( attacker );
- } // play excellent on player
- attacker->client->ps.persistant[PERS_EXCELLENT_COUNT]++;
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 1, attacker->client->pers.netname, "EXCELLENT" );
- if(!level.hadBots) //There has not been any bots
- ChallengeMessage(attacker,AWARD_EXCELLENT);
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_EXCELLENT;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
- } else {
- //KK-OAX Clear multikill count
- //Must be 1 so the correct number of kills are displayed to the clients.
- attacker->client->pers.multiKillCount = 1;
- }
- attacker->client->lastKillTime = level.time;
- }
- } else {
- if(g_gametype.integer!=GT_LMS && !((g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION) && level.time < level.roundStartTime))
- if(self->client->ps.persistant[PERS_SCORE]>0 || level.numNonSpectatorClients<3) //Cannot get negative scores by suicide
- AddScore( self, self->r.currentOrigin, -1 );
- }
-
- // Add team bonuses
- Team_FragBonuses(self, inflictor, attacker);
-
- // if I committed suicide, the flag does not fall, it returns.
- if (meansOfDeath == MOD_SUICIDE) {
- if ( self->client->ps.powerups[PW_NEUTRALFLAG] ) { // only happens in One Flag CTF
- Team_ReturnFlag( TEAM_FREE );
- self->client->ps.powerups[PW_NEUTRALFLAG] = 0;
- }
- else if ( self->client->ps.powerups[PW_REDFLAG] ) { // only happens in standard CTF
- Team_ReturnFlag( TEAM_RED );
- self->client->ps.powerups[PW_REDFLAG] = 0;
- }
- else if ( self->client->ps.powerups[PW_BLUEFLAG] ) { // only happens in standard CTF
- Team_ReturnFlag( TEAM_BLUE );
- self->client->ps.powerups[PW_BLUEFLAG] = 0;
- }
- }
-
- // if client is in a nodrop area, don't drop anything (but return CTF flags!)
- contents = trap_PointContents( self->r.currentOrigin, -1 );
- if ( !( contents & CONTENTS_NODROP )) {
- TossClientItems( self );
- }
- else {
- if ( self->client->ps.powerups[PW_NEUTRALFLAG] ) { // only happens in One Flag CTF
- Team_ReturnFlag( TEAM_FREE );
- }
- else if ( self->client->ps.powerups[PW_REDFLAG] ) { // only happens in standard CTF
- Team_ReturnFlag( TEAM_RED );
- }
- else if ( self->client->ps.powerups[PW_BLUEFLAG] ) { // only happens in standard CTF
- Team_ReturnFlag( TEAM_BLUE );
- }
- }
- TossClientPersistantPowerups( self );
- if( g_gametype.integer == GT_HARVESTER ) {
- TossClientCubes( self );
- }
-//#endif
-
- Cmd_Score_f( self ); // show scores
- // send updated scores to any clients that are following this one,
- // or they would get stale scoreboards
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- gclient_t *client;
-
- client = &level.clients[i];
- if ( client->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
- continue;
- }
- if ( client->sess.spectatorClient == self->s.number ) {
- Cmd_Score_f( g_entities + i );
- }
- }
-
- self->takedamage = qtrue; // can still be gibbed
-
- self->s.weapon = WP_NONE;
- self->s.powerups = 0;
- self->r.contents = CONTENTS_CORPSE;
-
- self->s.angles[0] = 0;
- self->s.angles[2] = 0;
- LookAtKiller (self, inflictor, attacker);
-
- VectorCopy( self->s.angles, self->client->ps.viewangles );
-
- self->s.loopSound = 0;
-
- self->r.maxs[2] = -8;
-
- // don't allow respawn until the death anim is done
- // g_forcerespawn may force spawning at some later time
- self->client->respawnTime = level.time + 1700;
- //However during warm up, we should respawn quicker!
- if(g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS)
- if(level.time<=level.roundStartTime && level.time>level.roundStartTime-1000*g_elimination_activewarmup.integer)
- self->client->respawnTime = level.time + rand()%800;
-
-
- // remove powerups
- memset( self->client->ps.powerups, 0, sizeof(self->client->ps.powerups) );
-
- // never gib in a nodrop
- if ( (self->health <= GIB_HEALTH && !(contents & CONTENTS_NODROP) && g_blood.integer) || meansOfDeath == MOD_SUICIDE) {
- // gib death
- GibEntity( self, killer );
- } else {
- // normal death
- static int i;
-
- switch ( i ) {
- case 0:
- anim = BOTH_DEATH1;
- break;
- case 1:
- anim = BOTH_DEATH2;
- break;
- case 2:
- default:
- anim = BOTH_DEATH3;
- break;
- }
-
- // for the no-blood option, we need to prevent the health
- // from going to gib level
- if ( self->health <= GIB_HEALTH ) {
- self->health = GIB_HEALTH+1;
- }
-
- self->client->ps.legsAnim =
- ( ( self->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
- self->client->ps.torsoAnim =
- ( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-
- G_AddEvent( self, EV_DEATH1 + i, killer );
-
- // the body can still be gibbed
- self->die = body_die;
-
- // globally cycle through the different death animations
- i = ( i + 1 ) % 3;
-
- if (self->s.eFlags & EF_KAMIKAZE) {
- Kamikaze_DeathTimer( self );
- }
- }
-
- trap_LinkEntity (self);
-
-}
-
-
-/*
-================
-CheckArmor
-================
-*/
-int CheckArmor (gentity_t *ent, int damage, int dflags)
-{
- gclient_t *client;
- int save;
- int count;
-
- if (!damage)
- return 0;
-
- client = ent->client;
-
- if (!client)
- return 0;
-
- if (dflags & DAMAGE_NO_ARMOR)
- return 0;
-
- // armor
- count = client->ps.stats[STAT_ARMOR];
- save = ceil( damage * ARMOR_PROTECTION );
- if (save >= count)
- save = count;
-
- if (!save)
- return 0;
-
- client->ps.stats[STAT_ARMOR] -= save;
-
- return save;
-}
-
-/*
-================
-RaySphereIntersections
-================
-*/
-int RaySphereIntersections( vec3_t origin, float radius, vec3_t point, vec3_t dir, vec3_t intersections[2] ) {
- float b, c, d, t;
-
- // | origin - (point + t * dir) | = radius
- // a = dir[0]^2 + dir[1]^2 + dir[2]^2;
- // b = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2]));
- // c = (point[0] - origin[0])^2 + (point[1] - origin[1])^2 + (point[2] - origin[2])^2 - radius^2;
-
- // normalize dir so a = 1
- VectorNormalize(dir);
- b = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2]));
- c = (point[0] - origin[0]) * (point[0] - origin[0]) +
- (point[1] - origin[1]) * (point[1] - origin[1]) +
- (point[2] - origin[2]) * (point[2] - origin[2]) -
- radius * radius;
-
- d = b * b - 4 * c;
- if (d > 0) {
- t = (- b + sqrt(d)) / 2;
- VectorMA(point, t, dir, intersections[0]);
- t = (- b - sqrt(d)) / 2;
- VectorMA(point, t, dir, intersections[1]);
- return 2;
- }
- else if (d == 0) {
- t = (- b ) / 2;
- VectorMA(point, t, dir, intersections[0]);
- return 1;
- }
- return 0;
-}
-
-/*
-================
-G_InvulnerabilityEffect
-================
-*/
-int G_InvulnerabilityEffect( gentity_t *targ, vec3_t dir, vec3_t point, vec3_t impactpoint, vec3_t bouncedir ) {
- gentity_t *impact;
- vec3_t intersections[2], vec;
- int n;
-
- if ( !targ->client ) {
- return qfalse;
- }
- VectorCopy(dir, vec);
- VectorInverse(vec);
- // sphere model radius = 42 units
- n = RaySphereIntersections( targ->client->ps.origin, 42, point, vec, intersections);
- if (n > 0) {
- impact = G_TempEntity( targ->client->ps.origin, EV_INVUL_IMPACT );
- VectorSubtract(intersections[0], targ->client->ps.origin, vec);
- vectoangles(vec, impact->s.angles);
- impact->s.angles[0] += 90;
- if (impact->s.angles[0] > 360)
- impact->s.angles[0] -= 360;
- if ( impactpoint ) {
- VectorCopy( intersections[0], impactpoint );
- }
- if ( bouncedir ) {
- VectorCopy( vec, bouncedir );
- VectorNormalize( bouncedir );
- }
- return qtrue;
- }
- else {
- return qfalse;
- }
-}
-
-/*
-catchup_damage
-*/
-static int catchup_damage(int damage, int attacker_points, int target_points) {
- int newdamage;
- if(g_catchup.integer <= 0 )
- return damage;
- //Reduce damage
- if(attacker_points<=target_points+5)
- return damage; //Never reduce damage if only 5 points ahead.
-
- newdamage=damage-((attacker_points-target_points-5) * (g_catchup.integer*damage))/100;
- if(newdamage<damage/2)
- return damage/2;
- return newdamage;
-}
-
-/*
-============
-T_Damage
-
-targ entity that is being damaged
-inflictor entity that is causing the damage
-attacker entity that caused the inflictor to damage targ
- example: targ=monster, inflictor=rocket, attacker=player
-
-dir direction of the attack for knockback
-point point at which the damage is being inflicted, used for headshots
-damage amount of damage being inflicted
-knockback force to be applied against targ as a result of the damage
-
-inflictor, attacker, dir, and point can be NULL for environmental effects
-
-dflags these flags are used to control how T_Damage works
- DAMAGE_RADIUS damage was indirect (from a nearby explosion)
- DAMAGE_NO_ARMOR armor does not protect from this damage
- DAMAGE_NO_KNOCKBACK do not affect velocity, just view angles
- DAMAGE_NO_PROTECTION kills godmode, armor, everything
-============
-*/
-
-void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
- vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {
- gclient_t *client;
- int take;
- int save;
- int asave;
- int knockback;
- int max;
-
- vec3_t bouncedir, impactpoint;
-
- if (!targ->takedamage) {
- return;
- }
-
- // the intermission has allready been qualified for, so don't
- // allow any extra scoring
- if ( level.intermissionQueued ) {
- return;
- }
- if ( targ->client && mod != MOD_JUICED) {
- if ( targ->client->invulnerabilityTime > level.time) {
- if ( dir && point ) {
- G_InvulnerabilityEffect( targ, dir, point, impactpoint, bouncedir );
- }
- return;
- }
- }
- //Sago: This was moved up
- client = targ->client;
-
- //Sago: See if the client was sent flying
- //Check if damage is by somebody who is not a player!
- if( (!attacker || attacker->s.eType != ET_PLAYER) && client->lastSentFlying>-1 && ( mod==MOD_FALLING || mod==MOD_LAVA || mod==MOD_SLIME || mod==MOD_TRIGGER_HURT || mod==MOD_SUICIDE) ) {
- if( client->lastSentFlyingTime+5000<level.time) {
- client->lastSentFlying = -1; //More than 5 seconds, not a kill!
- } else {
- //G_Printf("LastSentFlying %i\n",client->lastSentFlying);
- attacker = &g_entities[client->lastSentFlying];
- }
- }
-
- if ( !inflictor ) {
- inflictor = &g_entities[ENTITYNUM_WORLD];
- }
- if ( !attacker ) {
- attacker = &g_entities[ENTITYNUM_WORLD];
- }
-
- // shootable doors / buttons don't actually have any health
- if ( targ->s.eType == ET_MOVER ) {
- if ( targ->use && targ->moverState == MOVER_POS1 ) {
- targ->use( targ, inflictor, attacker );
- }
- return;
- }
- if( g_gametype.integer == GT_OBELISK && CheckObeliskAttack( targ, attacker ) ) {
- return;
- }
- // reduce damage by the attacker's handicap value
- // unless they are rocket jumping
- if ( attacker->client && attacker != targ ) {
- max = attacker->client->ps.stats[STAT_MAX_HEALTH];
- if( bg_itemlist[attacker->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
- max /= 2;
- }
- damage = damage * max / 100;
- }
-
- //Sago: I have moved this up
- //client = targ->client;
-
- if ( client ) {
- if ( client->noclip ) {
- return;
- }
- }
-
- if ( !dir ) {
- dflags |= DAMAGE_NO_KNOCKBACK;
- } else {
- VectorNormalize(dir);
- }
-
- knockback = damage;
- if ( knockback > 200 ) {
- knockback = 200;
- }
- if ( targ->flags & FL_NO_KNOCKBACK ) {
- knockback = 0;
- }
- if ( dflags & DAMAGE_NO_KNOCKBACK ) {
- knockback = 0;
- }
-
- // figure momentum add, even if the damage won't be taken
- if ( knockback && targ->client ) {
- vec3_t kvel;
- float mass;
-
- mass = 200;
-
- VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
- VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);
-
- // set the timer so that the other client can't cancel
- // out the movement immediately
- if ( !targ->client->ps.pm_time ) {
- int t;
-
- t = knockback * 2;
- if ( t < 50 ) {
- t = 50;
- }
- if ( t > 200 ) {
- t = 200;
- }
- targ->client->ps.pm_time = t;
- targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
- }
- //Remeber the last person to hurt the player
- if( !g_awardpushing.integer || targ==attacker || OnSameTeam (targ, attacker)) {
- targ->client->lastSentFlying = -1;
- } else {
- /*if ( pm->waterlevel <= 1 ) {
- if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) {
- // if getting knocked back, no friction
- if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) {
- control = speed < pm_stopspeed ? pm_stopspeed : speed;
- drop += control*pm_friction*pml.frametime;
- }
- }
- }*/
- targ->client->lastSentFlying = attacker->s.number;
- targ->client->lastSentFlyingTime = level.time;
- }
- }
-
- // check for completely getting out of the damage
- if ( !(dflags & DAMAGE_NO_PROTECTION) ) {
-
- // if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
- // if the attacker was on the same team
- if ( mod != MOD_JUICED && mod != MOD_CRUSH && targ != attacker && !(dflags & DAMAGE_NO_TEAM_PROTECTION) && OnSameTeam (targ, attacker) ) {
- if ( ( !g_friendlyFire.integer && g_gametype.integer != GT_ELIMINATION && g_gametype.integer != GT_CTF_ELIMINATION ) || ( g_elimination_selfdamage.integer<2 && (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) ) ) {
- return;
- }
- }
- if (mod == MOD_PROXIMITY_MINE) {
- if (inflictor && inflictor->parent && OnSameTeam(targ, inflictor->parent)) {
- return;
- }
- if (targ == attacker) {
- return;
- }
- }
-
- // check for godmode
- if ( targ->flags & FL_GODMODE ) {
- return;
- }
- }
-
- // battlesuit protects from all radius damage (but takes knockback)
- // and protects 50% against all damage
- if ( client && client->ps.powerups[PW_BATTLESUIT] ) {
- G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );
- if ( ( dflags & DAMAGE_RADIUS ) || ( mod == MOD_FALLING ) ) {
- return;
- }
- damage *= 0.5;
- }
-
- // add to the attacker's hit counter (if the target isn't a general entity like a prox mine)
- if ( attacker->client && client
- && targ != attacker && targ->health > 0
- && targ->s.eType != ET_MISSILE
- && targ->s.eType != ET_GENERAL) {
- if ( OnSameTeam( targ, attacker ) ) {
- attacker->client->ps.persistant[PERS_HITS]--;
- } else {
- attacker->client->ps.persistant[PERS_HITS]++;
- }
- attacker->client->ps.persistant[PERS_ATTACKEE_ARMOR] = (targ->health<<8)|(client->ps.stats[STAT_ARMOR]);
- }
-
- // always give half damage if hurting self
- // calculated after knockback, so rocket jumping works
- if ( targ == attacker) {
- damage *= 0.5;
- }
-
- if(targ && targ->client && attacker->client )
- damage = catchup_damage(damage, attacker->client->ps.persistant[PERS_SCORE], targ->client->ps.persistant[PERS_SCORE]);
-
- if ( damage < 1 ) {
- damage = 1;
- }
-
- if ((g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS || g_elimination_allgametypes.integer)
- && g_elimination_selfdamage.integer<1 && ( targ == attacker || mod == MOD_FALLING )) {
- damage = 0;
- }
-
-
-//So people can be telefragged!
- if ((g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS) && level.time < level.roundStartTime && ((mod == MOD_LAVA) || (mod == MOD_SLIME)) ) {
- damage = 1000;
- }
-
-
- take = damage;
- save = 0;
-
- // save some from armor
- asave = CheckArmor (targ, take, dflags);
- take -= asave;
-
- if ( g_debugDamage.integer ) {
- G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number,
- targ->health, take, asave );
- }
-
- // add to the damage inflicted on a player this frame
- // the total will be turned into screen blends and view angle kicks
- // at the end of the frame
- if ( client ) {
- if ( attacker ) {
- client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
- } else if(client->lastSentFlying) {
- client->ps.persistant[PERS_ATTACKER] = client->lastSentFlying;
- } else {
- client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
- }
- client->damage_armor += asave;
- client->damage_blood += take;
- client->damage_knockback += knockback;
- if ( dir ) {
- VectorCopy ( dir, client->damage_from );
- client->damage_fromWorld = qfalse;
- } else {
- VectorCopy ( targ->r.currentOrigin, client->damage_from );
- client->damage_fromWorld = qtrue;
- }
- }
-
- // See if it's the player hurting the emeny flag carrier
- if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF || g_gametype.integer == GT_CTF_ELIMINATION) {
- Team_CheckHurtCarrier(targ, attacker);
- }
-
- if (targ->client) {
- // set the last client who damaged the target
- targ->client->lasthurt_client = attacker->s.number;
- targ->client->lasthurt_mod = mod;
- }
-
- //If vampire is enabled, gain health but not from self or teammate, cannot steal more than targ has
- if((targ != attacker) && !(OnSameTeam(targ, attacker)) && g_vampire.value>0.0)
- {
- if(take<targ->health)
- attacker->health += (int)(((float)take)*g_vampire.value);
- else
- attacker->health += (int)(((float)targ->health)*g_vampire.value);
- if(attacker->health>g_vampireMaxHealth.integer)
- attacker->health = g_vampireMaxHealth.integer;
- }
-
- // do the damage
- if (take) {
- targ->health = targ->health - take;
- if ( targ->client ) {
- targ->client->ps.stats[STAT_HEALTH] = targ->health;
- }
-
- if ( targ->health <= 0 ) {
- if ( client )
- targ->flags |= FL_NO_KNOCKBACK;
-
- if (targ->health < -999)
- targ->health = -999;
-
- targ->enemy = attacker;
- targ->die (targ, inflictor, attacker, take, mod);
- return;
- } else if ( targ->pain ) {
- targ->pain (targ, attacker, take);
- }
- }
-
-
-}
-
-
-/*
-============
-CanDamage
-
-Returns qtrue if the inflictor can directly damage the target. Used for
-explosions and melee attacks.
-============
-*/
-qboolean CanDamage (gentity_t *targ, vec3_t origin) {
- vec3_t dest;
- trace_t tr;
- vec3_t midpoint;
-
- // use the midpoint of the bounds instead of the origin, because
- // bmodels may have their origin is 0,0,0
- VectorAdd (targ->r.absmin, targ->r.absmax, midpoint);
- VectorScale (midpoint, 0.5, midpoint);
-
- VectorCopy (midpoint, dest);
- trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
- if (tr.fraction == 1.0 || tr.entityNum == targ->s.number)
- return qtrue;
-
- // this should probably check in the plane of projection,
- // rather than in world coordinate, and also include Z
- VectorCopy (midpoint, dest);
- dest[0] += 15.0;
- dest[1] += 15.0;
- trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
- if (tr.fraction == 1.0)
- return qtrue;
-
- VectorCopy (midpoint, dest);
- dest[0] += 15.0;
- dest[1] -= 15.0;
- trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
- if (tr.fraction == 1.0)
- return qtrue;
-
- VectorCopy (midpoint, dest);
- dest[0] -= 15.0;
- dest[1] += 15.0;
- trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
- if (tr.fraction == 1.0)
- return qtrue;
-
- VectorCopy (midpoint, dest);
- dest[0] -= 15.0;
- dest[1] -= 15.0;
- trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
- if (tr.fraction == 1.0)
- return qtrue;
-
-
- return qfalse;
-}
-
-
-/*
-============
-G_RadiusDamage
-============
-*/
-qboolean G_RadiusDamage ( vec3_t origin, gentity_t *attacker, float damage, float radius,
- gentity_t *ignore, int mod) {
- float points, dist;
- gentity_t *ent;
- int entityList[MAX_GENTITIES];
- int numListedEntities;
- vec3_t mins, maxs;
- vec3_t v;
- vec3_t dir;
- int i, e;
- qboolean hitClient = qfalse;
-
- if ( radius < 1 ) {
- radius = 1;
- }
-
- for ( i = 0 ; i < 3 ; i++ ) {
- mins[i] = origin[i] - radius;
- maxs[i] = origin[i] + radius;
- }
-
- numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
-
- for ( e = 0 ; e < numListedEntities ; e++ ) {
- ent = &g_entities[entityList[ e ]];
-
- if (ent == ignore)
- continue;
- if (!ent->takedamage)
- continue;
-
- // find the distance from the edge of the bounding box
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( origin[i] < ent->r.absmin[i] ) {
- v[i] = ent->r.absmin[i] - origin[i];
- } else if ( origin[i] > ent->r.absmax[i] ) {
- v[i] = origin[i] - ent->r.absmax[i];
- } else {
- v[i] = 0;
- }
- }
-
- dist = VectorLength( v );
- if ( dist >= radius ) {
- continue;
- }
-
- points = damage * ( 1.0 - dist / radius );
-
- if( CanDamage (ent, origin) ) {
- if( LogAccuracyHit( ent, attacker ) ) {
- hitClient = qtrue;
- }
- VectorSubtract (ent->r.currentOrigin, origin, dir);
- // push the center of mass higher than the origin so players
- // get knocked into the air more
- dir[2] += 24;
- G_Damage (ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod);
- }
- }
-
- return hitClient;
-}
diff --git a/game/code/game/g_items.c b/game/code/game/g_items.c
deleted file mode 100644
index cc003bc..0000000
--- a/game/code/game/g_items.c
+++ /dev/null
@@ -1,1090 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-/*
-
- Items are any object that a player can touch to gain some effect.
-
- Pickup will return the number of seconds until they should respawn.
-
- all items should pop when dropped in lava or slime
-
- Respawnable items don't actually go away when picked up, they are
- just made invisible and untouchable. This allows them to ride
- movers and respawn apropriately.
-*/
-
-
-#define RESPAWN_ARMOR 25
-#define RESPAWN_HEALTH 35
-#define RESPAWN_AMMO 40
-#define RESPAWN_HOLDABLE 60
-#define RESPAWN_MEGAHEALTH 35//120
-#define RESPAWN_POWERUP 120
-
-
-//======================================================================
-
-int Pickup_Powerup( gentity_t *ent, gentity_t *other ) {
- int quantity;
- int i;
- gclient_t *client;
-
- if ( !other->client->ps.powerups[ent->item->giTag] ) {
- // round timing to seconds to make multiple powerup timers
- // count in sync
- other->client->ps.powerups[ent->item->giTag] =
- level.time - ( level.time % 1000 );
- }
-
- if ( ent->count ) {
- quantity = ent->count;
- } else {
- quantity = ent->item->quantity;
- }
-
- other->client->ps.powerups[ent->item->giTag] += quantity * 1000;
-
- // give any nearby players a "denied" anti-reward
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- vec3_t delta;
- float len;
- vec3_t forward;
- trace_t tr;
-
- client = &level.clients[i];
- if ( client == other->client ) {
- continue;
- }
- if ( client->pers.connected == CON_DISCONNECTED ) {
- continue;
- }
- if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
- continue;
- }
-
- // if same team in team game, no sound
- // cannot use OnSameTeam as it expects to g_entities, not clients
- if ( g_gametype.integer >= GT_TEAM && g_ffa_gt==0 && other->client->sess.sessionTeam == client->sess.sessionTeam ) {
- continue;
- }
-
- // if too far away, no sound
- VectorSubtract( ent->s.pos.trBase, client->ps.origin, delta );
- len = VectorNormalize( delta );
- if ( len > 192 ) {
- continue;
- }
-
- // if not facing, no sound
- AngleVectors( client->ps.viewangles, forward, NULL, NULL );
- if ( DotProduct( delta, forward ) < 0.4 ) {
- continue;
- }
-
- // if not line of sight, no sound
- trap_Trace( &tr, client->ps.origin, NULL, NULL, ent->s.pos.trBase, ENTITYNUM_NONE, CONTENTS_SOLID );
- if ( tr.fraction != 1.0 ) {
- continue;
- }
-
- // anti-reward
- client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_DENIEDREWARD;
- }
- return RESPAWN_POWERUP;
-}
-
-//======================================================================
-
-int Pickup_PersistantPowerup( gentity_t *ent, gentity_t *other ) {
- int clientNum;
- char userinfo[MAX_INFO_STRING];
- float handicap;
- int max;
-
- other->client->ps.stats[STAT_PERSISTANT_POWERUP] = ent->item - bg_itemlist;
- other->client->persistantPowerup = ent;
-
- switch( ent->item->giTag ) {
- case PW_GUARD:
- clientNum = other->client->ps.clientNum;
- trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
- handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
- if( handicap<=0.0f || handicap>100.0f) {
- handicap = 100.0f;
- }
- max = (int)(2 * handicap);
-
- other->health = max;
- other->client->ps.stats[STAT_HEALTH] = max;
- other->client->ps.stats[STAT_MAX_HEALTH] = max;
- other->client->ps.stats[STAT_ARMOR] = max;
- other->client->pers.maxHealth = max;
-
- break;
-
- case PW_SCOUT:
- clientNum = other->client->ps.clientNum;
- trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
- handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
- if( handicap<=0.0f || handicap>100.0f) {
- handicap = 100.0f;
- }
- other->client->pers.maxHealth = handicap;
- other->client->ps.stats[STAT_ARMOR] = 0;
- break;
-
- case PW_DOUBLER:
- clientNum = other->client->ps.clientNum;
- trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
- handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
- if( handicap<=0.0f || handicap>100.0f) {
- handicap = 100.0f;
- }
- other->client->pers.maxHealth = handicap;
- break;
- case PW_AMMOREGEN:
- clientNum = other->client->ps.clientNum;
- trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
- handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
- if( handicap<=0.0f || handicap>100.0f) {
- handicap = 100.0f;
- }
- other->client->pers.maxHealth = handicap;
- memset(other->client->ammoTimes, 0, sizeof(other->client->ammoTimes));
- break;
- default:
- clientNum = other->client->ps.clientNum;
- trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
- handicap = atof( Info_ValueForKey( userinfo, "handicap" ) );
- if( handicap<=0.0f || handicap>100.0f) {
- handicap = 100.0f;
- }
- other->client->pers.maxHealth = handicap;
- break;
- }
-
- return -1;
-}
-
-//======================================================================
-
-int Pickup_Holdable( gentity_t *ent, gentity_t *other ) {
-
- other->client->ps.stats[STAT_HOLDABLE_ITEM] = ent->item - bg_itemlist;
-
- if( ent->item->giTag == HI_KAMIKAZE ) {
- other->client->ps.eFlags |= EF_KAMIKAZE;
- }
-
- return RESPAWN_HOLDABLE;
-}
-
-
-//======================================================================
-
-void Add_Ammo (gentity_t *ent, int weapon, int count)
-{
- ent->client->ps.ammo[weapon] += count;
- if ( ent->client->ps.ammo[weapon] > 200 ) {
- ent->client->ps.ammo[weapon] = 200;
- }
-}
-
-int Pickup_Ammo (gentity_t *ent, gentity_t *other)
-{
- int quantity;
-
- if ( ent->count ) {
- quantity = ent->count;
- } else {
- quantity = ent->item->quantity;
- }
-
- Add_Ammo (other, ent->item->giTag, quantity);
-
- return RESPAWN_AMMO;
-}
-
-//======================================================================
-
-
-int Pickup_Weapon (gentity_t *ent, gentity_t *other) {
- int quantity;
-
- if ( ent->count < 0 ) {
- quantity = 0; // None for you, sir!
- } else {
- if ( ent->count ) {
- quantity = ent->count;
- } else {
- quantity = ent->item->quantity;
- }
-
- // dropped items and teamplay weapons always have full ammo
- if ( ! (ent->flags & FL_DROPPED_ITEM) && g_gametype.integer != GT_TEAM ) {
- // respawning rules
- // drop the quantity if the already have over the minimum
- if ( other->client->ps.ammo[ ent->item->giTag ] < quantity ) {
- quantity = quantity - other->client->ps.ammo[ ent->item->giTag ];
- } else {
- quantity = 1; // only add a single shot
- }
- }
- }
-
- // add the weapon
- other->client->ps.stats[STAT_WEAPONS] |= ( 1 << ent->item->giTag );
-
- Add_Ammo( other, ent->item->giTag, quantity );
-
- if (ent->item->giTag == WP_GRAPPLING_HOOK)
- other->client->ps.ammo[ent->item->giTag] = -1; // unlimited ammo
-
- // team deathmatch has slow weapon respawns
- if ( g_gametype.integer == GT_TEAM ) {
- return g_weaponTeamRespawn.integer;
- }
-
- return g_weaponRespawn.integer;
-}
-
-
-//======================================================================
-
-int Pickup_Health (gentity_t *ent, gentity_t *other) {
- int max;
- int quantity;
-
- // small and mega healths will go over the max
- if( other->client && bg_itemlist[other->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
- max = other->client->ps.stats[STAT_MAX_HEALTH];
- }
- else
- if ( ent->item->quantity != 5 && ent->item->quantity != 100 ) {
- max = other->client->ps.stats[STAT_MAX_HEALTH];
- } else {
- max = other->client->ps.stats[STAT_MAX_HEALTH] * 2;
- }
-
- if ( ent->count ) {
- quantity = ent->count;
- } else {
- quantity = ent->item->quantity;
- }
-
- other->health += quantity;
-
- if (other->health > max ) {
- other->health = max;
- }
- other->client->ps.stats[STAT_HEALTH] = other->health;
-
- if ( ent->item->quantity == 100 ) { // mega health respawns slow
- return RESPAWN_MEGAHEALTH;
- }
-
- return RESPAWN_HEALTH;
-}
-
-//======================================================================
-
-int Pickup_Armor( gentity_t *ent, gentity_t *other ) {
- int upperBound;
-
- other->client->ps.stats[STAT_ARMOR] += ent->item->quantity;
-
- if( other->client && bg_itemlist[other->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
- upperBound = other->client->ps.stats[STAT_MAX_HEALTH];
- }
- else {
- upperBound = other->client->ps.stats[STAT_MAX_HEALTH] * 2;
- }
-
- if ( other->client->ps.stats[STAT_ARMOR] > upperBound ) {
- other->client->ps.stats[STAT_ARMOR] = upperBound;
- }
-
- return RESPAWN_ARMOR;
-}
-
-//======================================================================
-
-/*
-===============
-RespawnItem
-===============
-*/
-void RespawnItem( gentity_t *ent ) {
- //Don't spawn quad if quadfactor are 1.0 or less
- if(ent->item->giType == IT_POWERUP && ent->item->giTag == PW_QUAD && g_quadfactor.value <= 1.0)
- return;
-
- // randomly select from teamed entities
- if (ent->team) {
- gentity_t *master;
- int count;
- int choice;
-
- if ( !ent->teammaster ) {
- G_Error( "RespawnItem: bad teammaster");
- }
- master = ent->teammaster;
-
- for (count = 0, ent = master; ent; ent = ent->teamchain, count++)
- ;
-
- choice = rand() % count;
-
- for (count = 0, ent = master; count < choice; ent = ent->teamchain, count++)
- ;
- }
-
- ent->r.contents = CONTENTS_TRIGGER;
- ent->s.eFlags &= ~EF_NODRAW;
- ent->r.svFlags &= ~SVF_NOCLIENT;
- trap_LinkEntity (ent);
-
- if ( ent->item->giType == IT_POWERUP ) {
- // play powerup spawn sound to all clients
- gentity_t *te;
-
- // if the powerup respawn sound should Not be global
- if (ent->speed) {
- te = G_TempEntity( ent->s.pos.trBase, EV_GENERAL_SOUND );
- }
- else {
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_SOUND );
- }
- te->s.eventParm = G_SoundIndex( "sound/items/poweruprespawn.wav" );
- te->r.svFlags |= SVF_BROADCAST;
- }
-
- if ( ent->item->giType == IT_HOLDABLE && ent->item->giTag == HI_KAMIKAZE ) {
- // play powerup spawn sound to all clients
- gentity_t *te;
-
- // if the powerup respawn sound should Not be global
- if (ent->speed) {
- te = G_TempEntity( ent->s.pos.trBase, EV_GENERAL_SOUND );
- }
- else {
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_SOUND );
- }
- te->s.eventParm = G_SoundIndex( "sound/items/kamikazerespawn.wav" );
- te->r.svFlags |= SVF_BROADCAST;
- }
-
- // play the normal respawn sound only to nearby clients
- G_AddEvent( ent, EV_ITEM_RESPAWN, 0 );
-
- ent->nextthink = 0;
-}
-
-
-/*
-===============
-Touch_Item
-===============
-*/
-void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) {
- int respawn;
- qboolean predict;
-
- //instant gib
- if ((g_instantgib.integer || g_rockets.integer || g_gametype.integer == GT_CTF_ELIMINATION || g_elimination_allgametypes.integer)
- && ent->item->giType != IT_TEAM)
- return;
-
- //Cannot touch flag before round starts
- if(g_gametype.integer == GT_CTF_ELIMINATION && level.roundNumber != level.roundNumberStarted)
- return;
-
- //Cannot take ctf elimination oneway
- if(g_gametype.integer == GT_CTF_ELIMINATION && g_elimination_ctf_oneway.integer!=0 && (
- (other->client->sess.sessionTeam==TEAM_BLUE && (level.eliminationSides+level.roundNumber)%2 == 0 ) ||
- (other->client->sess.sessionTeam==TEAM_RED && (level.eliminationSides+level.roundNumber)%2 != 0 ) ))
- return;
-
- if (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_LMS)
- return; //nothing to pick up in elimination
-
- if (!other->client)
- return;
- if (other->health < 1)
- return; // dead people can't pickup
-
- // the same pickup rules are used for client side and server side
- if ( !BG_CanItemBeGrabbed( g_gametype.integer, &ent->s, &other->client->ps ) ) {
- return;
- }
-
- //In double DD we cannot "pick up" a flag we already got
- if(g_gametype.integer == GT_DOUBLE_D) {
- if( strcmp(ent->classname, "team_CTF_redflag") == 0 )
- if(other->client->sess.sessionTeam == level.pointStatusA)
- return;
- if( strcmp(ent->classname, "team_CTF_blueflag") == 0 )
- if(other->client->sess.sessionTeam == level.pointStatusB)
- return;
- }
-
- G_LogPrintf( "Item: %i %s\n", other->s.number, ent->item->classname );
-
- predict = other->client->pers.predictItemPickup;
-
- // call the item-specific pickup function
- switch( ent->item->giType ) {
- case IT_WEAPON:
- respawn = Pickup_Weapon(ent, other);
-// predict = qfalse;
- break;
- case IT_AMMO:
- respawn = Pickup_Ammo(ent, other);
-// predict = qfalse;
- break;
- case IT_ARMOR:
- respawn = Pickup_Armor(ent, other);
- break;
- case IT_HEALTH:
- respawn = Pickup_Health(ent, other);
- break;
- case IT_POWERUP:
- respawn = Pickup_Powerup(ent, other);
- predict = qfalse;
- break;
- case IT_PERSISTANT_POWERUP:
- respawn = Pickup_PersistantPowerup(ent, other);
- break;
- case IT_TEAM:
- respawn = Pickup_Team(ent, other);
- break;
- case IT_HOLDABLE:
- respawn = Pickup_Holdable(ent, other);
- break;
- default:
- return;
- }
-
- if ( !respawn ) {
- return;
- }
-
- // play the normal pickup sound
- if (predict) {
- G_AddPredictableEvent( other, EV_ITEM_PICKUP, ent->s.modelindex );
- } else {
- G_AddEvent( other, EV_ITEM_PICKUP, ent->s.modelindex );
- }
-
- // powerup pickups are global broadcasts
- if ( ent->item->giType == IT_POWERUP || ent->item->giType == IT_TEAM) {
- // if we want the global sound to play
- if (!ent->speed) {
- gentity_t *te;
-
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP );
- te->s.eventParm = ent->s.modelindex;
- te->r.svFlags |= SVF_BROADCAST;
- } else {
- gentity_t *te;
-
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP );
- te->s.eventParm = ent->s.modelindex;
- // only send this temp entity to a single client
- te->r.svFlags |= SVF_SINGLECLIENT;
- te->r.singleClient = other->s.number;
- }
- }
-
- // fire item targets
- G_UseTargets (ent, other);
-
- // wait of -1 will not respawn
- if ( ent->wait == -1 ) {
- ent->r.svFlags |= SVF_NOCLIENT;
- ent->s.eFlags |= EF_NODRAW;
- ent->r.contents = 0;
- ent->unlinkAfterEvent = qtrue;
- return;
- }
-
- // non zero wait overrides respawn time
- if ( ent->wait ) {
- respawn = ent->wait;
- }
-
- // random can be used to vary the respawn time
- if ( ent->random ) {
- respawn += crandom() * ent->random;
- if ( respawn < 1 ) {
- respawn = 1;
- }
- }
-
- // dropped items will not respawn
- if ( ent->flags & FL_DROPPED_ITEM ) {
- ent->freeAfterEvent = qtrue;
- }
-
- // picked up items still stay around, they just don't
- // draw anything. This allows respawnable items
- // to be placed on movers.
- ent->r.svFlags |= SVF_NOCLIENT;
- ent->s.eFlags |= EF_NODRAW;
- ent->r.contents = 0;
-
- // ZOID
- // A negative respawn times means to never respawn this item (but don't
- // delete it). This is used by items that are respawned by third party
- // events such as ctf flags
- if ( respawn <= 0 ) {
- ent->nextthink = 0;
- ent->think = 0;
- } else {
- ent->nextthink = level.time + respawn * 1000;
- ent->think = RespawnItem;
- }
- trap_LinkEntity( ent );
-}
-
-
-//======================================================================
-
-/*
-================
-LaunchItem
-
-Spawns an item and tosses it forward
-================
-*/
-gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity ) {
- gentity_t *dropped;
-
- dropped = G_Spawn();
-
- dropped->s.eType = ET_ITEM;
- dropped->s.modelindex = item - bg_itemlist; // store item number in modelindex
- dropped->s.modelindex2 = 1; // This is non-zero is it's a dropped item
-
- dropped->classname = item->classname;
- dropped->item = item;
- VectorSet (dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS);
- VectorSet (dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
- dropped->r.contents = CONTENTS_TRIGGER;
-
- dropped->touch = Touch_Item;
-
- G_SetOrigin( dropped, origin );
- dropped->s.pos.trType = TR_GRAVITY;
- dropped->s.pos.trTime = level.time;
- VectorCopy( velocity, dropped->s.pos.trDelta );
-
- dropped->s.eFlags |= EF_BOUNCE_HALF;
- if ((g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_DOUBLE_D) && item->giType == IT_TEAM) { // Special case for CTF flags
- dropped->think = Team_DroppedFlagThink;
- dropped->nextthink = level.time + 30000;
- Team_CheckDroppedItem( dropped );
- } else { // auto-remove after 30 seconds
- dropped->think = G_FreeEntity;
- dropped->nextthink = level.time + 30000;
- }
-
- dropped->flags = FL_DROPPED_ITEM;
-
- trap_LinkEntity (dropped);
-
- return dropped;
-}
-
-/*
-================
-Drop_Item
-
-Spawns an item and tosses it forward
-================
-*/
-gentity_t *Drop_Item( gentity_t *ent, gitem_t *item, float angle ) {
- vec3_t velocity;
- vec3_t angles;
-
- VectorCopy( ent->s.apos.trBase, angles );
- angles[YAW] += angle;
- angles[PITCH] = 0; // always forward
-
- AngleVectors( angles, velocity, NULL, NULL );
- VectorScale( velocity, 150, velocity );
- velocity[2] += 200 + crandom() * 50;
-
- return LaunchItem( item, ent->s.pos.trBase, velocity );
-}
-
-
-/*
-================
-Use_Item
-
-Respawn the item
-================
-*/
-void Use_Item( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
- RespawnItem( ent );
-}
-
-//======================================================================
-
-/*
-================
-FinishSpawningItem
-
-Traces down to find where an item should rest, instead of letting them
-free fall from their spawn points
-================
-*/
-void FinishSpawningItem( gentity_t *ent ) {
- trace_t tr;
- vec3_t dest;
-
- VectorSet( ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS );
- VectorSet( ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS );
-
- ent->s.eType = ET_ITEM;
- ent->s.modelindex = ent->item - bg_itemlist; // store item number in modelindex
- ent->s.modelindex2 = 0; // zero indicates this isn't a dropped item
-
- ent->r.contents = CONTENTS_TRIGGER;
- ent->touch = Touch_Item;
- // useing an item causes it to respawn
- ent->use = Use_Item;
-
- if ( ent->spawnflags & 1 ) {
- // suspended
- G_SetOrigin( ent, ent->s.origin );
- } else {
- // drop to floor
- VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
- trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
- if ( tr.startsolid ) {
- G_Printf ("FinishSpawningItem: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
- G_FreeEntity( ent );
- return;
- }
-
- // allow to ride movers
- ent->s.groundEntityNum = tr.entityNum;
-
- G_SetOrigin( ent, tr.endpos );
- }
-
- // team slaves and targeted items aren't present at start
- if ( ( ent->flags & FL_TEAMSLAVE ) || ent->targetname ) {
- ent->s.eFlags |= EF_NODRAW;
- ent->r.contents = 0;
- return;
- }
-
-
- // powerups don't spawn in for a while (but not in elimination)
- if(g_gametype.integer != GT_ELIMINATION && g_gametype.integer != GT_CTF_ELIMINATION && g_gametype.integer != GT_LMS
- && !g_instantgib.integer && !g_elimination_allgametypes.integer && !g_rockets.integer )
- if ( ent->item->giType == IT_POWERUP ) {
- float respawn;
-
- respawn = 45 + crandom() * 15;
- ent->s.eFlags |= EF_NODRAW;
- ent->r.contents = 0;
- ent->nextthink = level.time + respawn * 1000;
- ent->think = RespawnItem;
- return;
- }
-
-
- trap_LinkEntity (ent);
-}
-
-
-qboolean itemRegistered[MAX_ITEMS];
-
-/*
-==================
-G_CheckTeamItems
-==================
-*/
-void G_CheckTeamItems( void ) {
-
- // Set up team stuff
- Team_InitGame();
-
- if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_DOUBLE_D) {
- gitem_t *item;
-
- // check for the two flags
- item = BG_FindItem( "Red Flag" );
- if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_redflag in map" );
- }
- item = BG_FindItem( "Blue Flag" );
- if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_blueflag in map" );
- }
- }
- if( g_gametype.integer == GT_1FCTF ) {
- gitem_t *item;
-
- // check for all three flags
- item = BG_FindItem( "Red Flag" );
- if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_redflag in map" );
- }
- item = BG_FindItem( "Blue Flag" );
- if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_blueflag in map" );
- }
- item = BG_FindItem( "Neutral Flag" );
- if ( !item || !itemRegistered[ item - bg_itemlist ] ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_neutralflag in map" );
- }
- }
-
- if( g_gametype.integer == GT_OBELISK ) {
- gentity_t *ent;
-
- // check for the two obelisks
- ent = NULL;
- ent = G_Find( ent, FOFS(classname), "team_redobelisk" );
- if( !ent ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_redobelisk in map" );
- }
-
- ent = NULL;
- ent = G_Find( ent, FOFS(classname), "team_blueobelisk" );
- if( !ent ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_blueobelisk in map" );
- }
- }
-
- if( g_gametype.integer == GT_HARVESTER ) {
- gentity_t *ent;
-
- // check for all three obelisks
- ent = NULL;
- ent = G_Find( ent, FOFS(classname), "team_redobelisk" );
- if( !ent ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_redobelisk in map" );
- }
-
- ent = NULL;
- ent = G_Find( ent, FOFS(classname), "team_blueobelisk" );
- if( !ent ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_blueobelisk in map" );
- }
-
- ent = NULL;
- ent = G_Find( ent, FOFS(classname), "team_neutralobelisk" );
- if( !ent ) {
- G_Printf( S_COLOR_YELLOW "WARNING: No team_neutralobelisk in map" );
- }
- }
-}
-
-/*
-==============
-ClearRegisteredItems
-==============
-*/
-void ClearRegisteredItems( void ) {
- memset( itemRegistered, 0, sizeof( itemRegistered ) );
-
- if(g_instantgib.integer) {
- //Always load Gauntlet and machine gun because g_instantgib might suddenly change
- RegisterItem( BG_FindItemForWeapon( WP_GAUNTLET ) );
- RegisterItem( BG_FindItemForWeapon( WP_MACHINEGUN ) );
- RegisterItem( BG_FindItemForWeapon( WP_RAILGUN ) );
- }
- if(g_rockets.integer) {
- RegisterItem( BG_FindItemForWeapon( WP_GAUNTLET ) );
- RegisterItem( BG_FindItemForWeapon( WP_MACHINEGUN ) );
- RegisterItem( BG_FindItemForWeapon( WP_ROCKET_LAUNCHER ) );
- }
- else
- {
- // players always start with the base weapon
- RegisterItem( BG_FindItemForWeapon( WP_MACHINEGUN ) );
- RegisterItem( BG_FindItemForWeapon( WP_GAUNTLET ) );
- if(g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION
- || g_gametype.integer == GT_LMS || g_elimination_allgametypes.integer)
- {
- RegisterItem( BG_FindItemForWeapon( WP_SHOTGUN ) );
- RegisterItem( BG_FindItemForWeapon( WP_GRENADE_LAUNCHER ) );
- RegisterItem( BG_FindItemForWeapon( WP_ROCKET_LAUNCHER ) );
- RegisterItem( BG_FindItemForWeapon( WP_LIGHTNING ) );
- RegisterItem( BG_FindItemForWeapon( WP_RAILGUN ) );
- RegisterItem( BG_FindItemForWeapon( WP_PLASMAGUN ) );
- RegisterItem( BG_FindItemForWeapon( WP_BFG ) );
- RegisterItem( BG_FindItemForWeapon( WP_NAILGUN ) );
- RegisterItem( BG_FindItemForWeapon( WP_PROX_LAUNCHER ) );
- RegisterItem( BG_FindItemForWeapon( WP_CHAINGUN ) );
- }
- }
- if( g_gametype.integer == GT_HARVESTER ) {
- RegisterItem( BG_FindItem( "Red Cube" ) );
- RegisterItem( BG_FindItem( "Blue Cube" ) );
- }
-
- if(g_gametype.integer == GT_DOUBLE_D ) {
- RegisterItem( BG_FindItem( "Point A (Blue)" ) );
- RegisterItem( BG_FindItem( "Point A (Red)" ) );
- RegisterItem( BG_FindItem( "Point A (White)" ) );
- RegisterItem( BG_FindItem( "Point B (Blue)" ) );
- RegisterItem( BG_FindItem( "Point B (Red)" ) );
- RegisterItem( BG_FindItem( "Point B (White)" ) );
- }
-
- if(g_gametype.integer == GT_DOMINATION ) {
- RegisterItem( BG_FindItem( "Neutral domination point" ) );
- RegisterItem( BG_FindItem( "Red domination point" ) );
- RegisterItem( BG_FindItem( "Blue domination point" ) );
- }
-
-}
-
-/*
-===============
-RegisterItem
-
-The item will be added to the precache list
-===============
-*/
-void RegisterItem( gitem_t *item ) {
- if ( !item ) {
- G_Error( "RegisterItem: NULL" );
- }
- itemRegistered[ item - bg_itemlist ] = qtrue;
-}
-
-
-/*
-===============
-SaveRegisteredItems
-
-Write the needed items to a config string
-so the client will know which ones to precache
-===============
-*/
-void SaveRegisteredItems( void ) {
- char string[MAX_ITEMS+1];
- int i;
- int count;
-
- count = 0;
- for ( i = 0 ; i < bg_numItems ; i++ ) {
- if ( itemRegistered[i] ) {
- count++;
- string[i] = '1';
- } else {
- string[i] = '0';
- }
- }
- string[ bg_numItems ] = 0;
- G_Printf( "%i items registered\n", count );
- trap_SetConfigstring(CS_ITEMS, string);
-}
-
-/*
-============
-G_ItemDisabled
-============
-*/
-int G_ItemDisabled( gitem_t *item ) {
-
- char name[128];
-
- Com_sprintf(name, sizeof(name), "disable_%s", item->classname);
- return trap_Cvar_VariableIntegerValue( name );
-}
-
-/*
-============
-G_SpawnItem
-
-Sets the clipping size and plants the object on the floor.
-
-Items can't be immediately dropped to floor, because they might
-be on an entity that hasn't spawned yet.
-============
-*/
-void G_SpawnItem (gentity_t *ent, gitem_t *item) {
- G_SpawnFloat( "random", "0", &ent->random );
- G_SpawnFloat( "wait", "0", &ent->wait );
-
- //Load all items in instantgib anyway or we will be in trouble if it is suddenly disabled!
- //if((item->giType == IT_TEAM && g_instantgib.integer) || !g_instantgib.integer)
- {
- //Don't load pickups in Elimination (or maybe... gives warnings)
- if (g_gametype.integer != GT_ELIMINATION && g_gametype.integer != GT_CTF_ELIMINATION && g_gametype.integer != GT_LMS)
- RegisterItem( item );
- //Registrer flags anyway in CTF Elimination:
- if (g_gametype.integer == GT_CTF_ELIMINATION && item->giType == IT_TEAM)
- RegisterItem( item );
- if ( G_ItemDisabled(item) )
- return;
- }
- if(!g_persistantpowerups.integer && item->giType == IT_PERSISTANT_POWERUP)
- return;
-
- ent->item = item;
- // some movers spawn on the second frame, so delay item
- // spawns until the third frame so they can ride trains
- ent->nextthink = level.time + FRAMETIME * 2;
- ent->think = FinishSpawningItem;
-
- ent->physicsBounce = 0.50; // items are bouncy
-
- if (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_LMS ||
- ( item->giType != IT_TEAM && (g_instantgib.integer || g_rockets.integer || g_elimination_allgametypes.integer || g_gametype.integer==GT_CTF_ELIMINATION) ) ) {
- ent->s.eFlags |= EF_NODRAW; //Invisible in elimination
- ent->r.svFlags |= SVF_NOCLIENT; //Don't broadcast
- }
-
- if(g_gametype.integer == GT_DOUBLE_D && (strcmp(ent->classname, "team_CTF_redflag")==0 || strcmp(ent->classname, "team_CTF_blueflag")==0 || strcmp(ent->classname, "team_CTF_neutralflag") == 0 || item->giType == IT_PERSISTANT_POWERUP ))
- ent->s.eFlags |= EF_NODRAW; //Don't draw the flag models/persistant powerups
-
- if(g_gametype.integer == GT_CTF_ELIMINATION && strcmp(ent->classname, "team_CTF_neutralflag") == 0)
- ent->s.eFlags |= EF_NODRAW; // Don't draw the flag in CTF_elimination
-
- if(strcmp(ent->classname, "domination_point") == 0)
- ent->s.eFlags |= EF_NODRAW; // Don't draw domination_point. It is just a pointer to where the Domination points should be placed
- if ( item->giType == IT_POWERUP ) {
- G_SoundIndex( "sound/items/poweruprespawn.wav" );
- G_SpawnFloat( "noglobalsound", "0", &ent->speed);
- }
-
- if ( item->giType == IT_PERSISTANT_POWERUP ) {
- ent->s.generic1 = ent->spawnflags;
- }
-}
-
-
-/*
-================
-G_BounceItem
-
-================
-*/
-void G_BounceItem( gentity_t *ent, trace_t *trace ) {
- vec3_t velocity;
- float dot;
- int hitTime;
-
- // reflect the velocity on the trace plane
- hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
- BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
- dot = DotProduct( velocity, trace->plane.normal );
- VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );
-
- // cut the velocity to keep from bouncing forever
- VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta );
-
- // check for stop
- if ( trace->plane.normal[2] > 0 && ent->s.pos.trDelta[2] < 40 ) {
- trace->endpos[2] += 1.0; // make sure it is off ground
- SnapVector( trace->endpos );
- G_SetOrigin( ent, trace->endpos );
- ent->s.groundEntityNum = trace->entityNum;
- return;
- }
-
- VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
- VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
- ent->s.pos.trTime = level.time;
-}
-
-
-/*
-================
-G_RunItem
-
-================
-*/
-void G_RunItem( gentity_t *ent ) {
- vec3_t origin;
- trace_t tr;
- int contents;
- int mask;
-
- // if groundentity has been set to -1, it may have been pushed off an edge
- if ( ent->s.groundEntityNum == -1 ) {
- if ( ent->s.pos.trType != TR_GRAVITY ) {
- ent->s.pos.trType = TR_GRAVITY;
- ent->s.pos.trTime = level.time;
- }
- }
-
- if ( ent->s.pos.trType == TR_STATIONARY ) {
- // check think function
- G_RunThink( ent );
- return;
- }
-
- // get current position
- BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
-
- // trace a line from the previous position to the current position
- if ( ent->clipmask ) {
- mask = ent->clipmask;
- } else {
- mask = MASK_PLAYERSOLID & ~CONTENTS_BODY;//MASK_SOLID;
- }
- trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin,
- ent->r.ownerNum, mask );
-
- VectorCopy( tr.endpos, ent->r.currentOrigin );
-
- if ( tr.startsolid ) {
- tr.fraction = 0;
- }
-
- trap_LinkEntity( ent ); // FIXME: avoid this for stationary?
-
- // check think function
- G_RunThink( ent );
-
- if ( tr.fraction == 1 ) {
- return;
- }
-
- // if it is in a nodrop volume, remove it
- contents = trap_PointContents( ent->r.currentOrigin, -1 );
- if ( contents & CONTENTS_NODROP ) {
- if (ent->item && ent->item->giType == IT_TEAM) {
- Team_FreeEntity(ent);
- } else {
- G_FreeEntity( ent );
- }
- return;
- }
-
- G_BounceItem( ent, &tr );
-}
-
diff --git a/game/code/game/g_killspree.c b/game/code/game/g_killspree.c
deleted file mode 100644
index 339689a..0000000
--- a/game/code/game/g_killspree.c
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 2009 Karl Kuglin
-
-This file is part of the Open Arena source code.
-Parts of this file utilize code originally written for Tremulous by
-Tony J. White.
-Use of that code is governed by GPL version 2 and any later versions.
-
-Open Arena source code 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.
-
-Open Arena source code 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 Open Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// NOTE: This code is by no means complete.
-
-#include "g_local.h"
-
-killspree_t *killSprees[ MAX_KSPREE ];
-deathspree_t *deathSprees[ MAX_DSPREE ];
-multikill_t *multiKills[ MAX_MULTIKILLS ];
-
-/*
-=================
-G_ReadAltKillSettings
-Since this is cvar dependent, it has to be placed in G_InitGame after cvars are registered.
-=================
-*/
-qboolean G_ReadAltKillSettings( gentity_t *ent, int skiparg )
-{
- //Let's Initialize some Spree structs/objects
- killspree_t *k = NULL;
- deathspree_t *d = NULL;
- multikill_t *m = NULL;
- //spree counters
- int ksc = 0, dsc = 0, mc = 0;
- int spreeDivisor;
-
- //Give us an int to use in "for" loops
- int i = 0;
-
- //File Stuff
- fileHandle_t file;
- int length;
- qboolean kspree_read;
- qboolean dspree_read;
- qboolean mkill_read;
- char *cnf, *cnf2;
- char *t;
-
- //Let's clear out any existing killing sprees/death sprees. YAYY BG_FREE!!!!!
- for( i = 0; i < MAX_KSPREE && killSprees[ i ]; i++ ) {
- BG_Free( killSprees[ i ] );
- killSprees[ i ] = NULL;
- }
-
- for( i = 0; i < MAX_KSPREE && deathSprees[ i ]; i++ ) {
- BG_Free( deathSprees[ i ] );
- deathSprees[ i ] = NULL;
- }
-
- for( i = 0; i < MAX_MULTIKILLS && multiKills[ i ]; i++ ) {
- BG_Free( multiKills[ i ] );
- multiKills[ i ] = NULL;
- }
-
- // If the config file is not defined...forget reading/loading
- if( !g_sprees.string[0] ) {
- //Let's disable multikills to keep stock excellent sound
- if( g_altExcellent.integer == 1 )
- {
- trap_Cvar_Set( "g_altExcellent", "0" );
- }
- return qfalse;
- }
- /*
- only set spreeDivisor to cvar g_spreeDiv if g_spreeDiv is >= "2".
- 0 will cause problems and having 1 is just a fool who wants to hear something
- on every kill.
- */
- if( g_spreeDiv.integer >= 2 ) {
- level.spreeDivisor = g_spreeDiv.integer;
- spreeDivisor = level.spreeDivisor;
- } else {
- level.spreeDivisor = 5;
- // We don't want to change the value, keep reminding the server operator.
- //g_spreeDiv.integer = 5;
- spreeDivisor = 5;
- G_Printf( "Error: cvar g_spreeDiv must not be set to 0 or 1, reverting to default settings!\n" );
- G_Printf( "Error: Set g_spreeDiv higher than 1 if 5 is not desired!\n" );
- }
-
- length = trap_FS_FOpenFile( g_sprees.string, &file, FS_READ );
-
- //If the file can't be accessed/opened.
- if( length < 0 ) {
- G_Printf( "Could not open configuration file for Sprees and Multikills %s\n", g_sprees.string );
- trap_Cvar_Set( "g_altExcellent", "0" );
- return qfalse;
- }
- //Allocate some memory.
- cnf = BG_Alloc( length + 1 );
- cnf2 = cnf;
-
- //Load the whole file up.
- trap_FS_Read( cnf, length, file );
- *( cnf + length ) = '\0';
- trap_FS_FCloseFile( file );
-
- kspree_read = dspree_read = mkill_read = qfalse;
-
- //Let's start parsing em.
- COM_BeginParseSession( g_sprees.string );
- while( 1 )
- {
- t = COM_Parse( &cnf );
- if( !*t )
- break;
- if( !Q_stricmp( t, "[kspree]" ) ) {
-
- if( ksc >= MAX_KSPREE )
- return qfalse;
- k = BG_Alloc( sizeof( killspree_t ) );
- killSprees[ ksc++ ] = k;
- kspree_read = qtrue;
- dspree_read = qfalse;
- mkill_read = qfalse;
-
- } else if ( !Q_stricmp( t, "[dspree]" ) ) {
-
- if( dsc >= MAX_DSPREE )
- return qfalse;
- d = BG_Alloc( sizeof( deathspree_t ) );
- deathSprees[ dsc++ ] = d;
- dspree_read = qtrue;
- kspree_read = qfalse;
- mkill_read = qfalse;
- } else if ( !Q_stricmp( t, "[mkill]" ) ) {
-
- if( mc >= MAX_MULTIKILLS )
- return qfalse;
- m = BG_Alloc( sizeof( multikill_t ) );
- multiKills[ mc++ ] = m;
- mkill_read = qtrue;
- kspree_read = qfalse;
- dspree_read = qfalse;
- //Parse a killing spree
- } else if ( kspree_read ) {
- if( !Q_stricmp( t, "level" ) ) {
- readFile_int( &cnf, &k->spreeLevel );
- //Let's take the spreeLevel and multiply it by the spreeDivisor to give us our count
- k->streakCount = ( ( k->spreeLevel ) * ( spreeDivisor ) );
- } else if ( !Q_stricmp( t, "message" ) ) {
- readFile_string( &cnf, k->spreeMsg, sizeof( k->spreeMsg ) );
- } else if ( !Q_stricmp( t, "printpos" ) ) {
- readFile_int( &cnf, &k->position );
- } else if ( !Q_stricmp( t, "sound" ) ) {
- readFile_string( &cnf, k->sound2Play, sizeof( k->sound2Play ) );
- } else {
- COM_ParseError( "Killing Spree unrecognized token \"%s\"", t );
- }
- } else if ( dspree_read ) {
- if( !Q_stricmp( t, "level" ) ) {
- readFile_int( &cnf, &d->spreeLevel );
- //Let's take the spreeLevel and multiply it by the spreeDivisor to give us our count
- d->streakCount = ( ( d->spreeLevel ) * ( spreeDivisor ) );
- } else if ( !Q_stricmp( t, "message" ) ) {
- readFile_string( &cnf, d->spreeMsg, sizeof( d->spreeMsg ) );
- } else if ( !Q_stricmp( t, "printpos" ) ) {
- readFile_int( &cnf, &d->position );
- } else if ( !Q_stricmp( t, "sound" ) ) {
- readFile_string( &cnf, d->sound2Play, sizeof( d->sound2Play ) );
- } else {
- COM_ParseError( "Death Spree unrecognized token \"%s\"", t );
- }
- } else if ( mkill_read ) {
- if ( !Q_stricmp( t, "kills" ) ) {
- readFile_int( &cnf, &m->kills );
- } else if ( !Q_stricmp( t, "message" ) ) {
- readFile_string( &cnf, m->killMsg, sizeof( m->killMsg ) );
- } else if ( !Q_stricmp( t, "sound" ) ) {
- readFile_string( &cnf, m->sound2Play, sizeof( m->sound2Play ) );
- } else {
- COM_ParseError( "Multikill unrecognized token \"%s\"", t );
- }
- } else {
- COM_ParseError( "unexpected token \"%s\"", t );
- }
- }
- //Let's "free" some memory now.
- BG_Free( cnf2 );
- G_Printf("Sprees/Kills: loaded %d killing sprees, %d death sprees, and %d multikills.\n", ksc, dsc, mc );
- //Mark the Upper Bounds of the Arrays (Since they start numbering at 0, We subtract 1 )
- level.kSpreeUBound = ( ksc - 1 );
- level.dSpreeUBound = ( dsc - 1 );
- if( mc > 0 ) {
- level.mKillUBound = ( mc - 1 );
- } else {
- level.mKillUBound = -1;
- //KK-OAX We don't have any kills defined, revert to stock.
- //FIXME: Make sure this change shows up in the console...
- if( g_altExcellent.integer == 1 ) {
- trap_Cvar_Set( "g_altExcellent", "0" );
- }
-
- }
- return qtrue;
-}
-
-
-static char *fillPlaceHolder( char *stringToSearch, char *placeHolder, char *replaceWith )
-{
- static char output[ MAX_SAY_TEXT ];
- char *p;
-
- if( !( p = strstr( stringToSearch, placeHolder ) ) )
- return stringToSearch;
-
- strncpy( output, stringToSearch, p - stringToSearch );
- output[ p - stringToSearch ] = '\0';
-
- Q_snprintf( output + ( p - stringToSearch ), output - stringToSearch, "%s%s", replaceWith, p + strlen( placeHolder ) );
-
- return output;
-}
-
-//This concatenate's the message to broadcast to the clients.
-static char *CreateMessage( gentity_t *ent, char *message, char *spreeNumber )
-{
- static char output[ MAX_SAY_TEXT ] = { "" };
-
- char name[ MAX_NAME_LENGTH ];
- //Do some sanity checks
- if( !ent ) {
- return output;
- } else if ( !*message ) {
- return output;
- } else if ( !spreeNumber ) {
- return output;
- }
- //Get the player name.
- Q_strncpyz( name, ent->client->pers.netname, sizeof( name ) );
- //Do Our Replacements
- Q_strncpyz( output, fillPlaceHolder( message, "[n]", name ), sizeof( output ) );
- Q_strncpyz( output, fillPlaceHolder( output, "[k]", spreeNumber ), sizeof( output ) );
- return output;
-}
-
-
-/*
-================
-G_RunStreakLogic
-KK-OAX This is called from player_die.
-It does all the adding resetting of kill/death streaks
-to be compared against the kill/death spree levels.
-================
-*/
-void G_RunStreakLogic( gentity_t *attacker, gentity_t *victim )
-{
- //We only want to sanity check for the victim at this point.
- if( !victim || !victim->client )
- return;
-
- //We will reset the victim's killstreak counter
- victim->client->pers.killstreak = 0;
- //Add one to the death streak counter
- victim->client->pers.deathstreak++;
-
- //Let's check for a deathspree for the victim
- G_CheckForSpree( victim, victim->client->pers.deathstreak, qfalse );
-
- //Move on to the attacker
- //Make sure they are a client and that the attacker and victim are not the same client
- //We don't want suicide to count towards a killstreak...
- if( ( attacker )
- && ( attacker->client )
- && ( attacker != victim ) ) {
-
- //Check the gametype--If FFA enabled, everybody's on the same team.
- if( g_gametype.integer >= GT_TEAM && g_ffa_gt!= 1 ) {
- //If they are on the same team we don't want to count it towards a killing spree.
- if( OnSameTeam( victim, attacker ) ) {
- return;
- }
- }
- //Add to the killstreak, reset the deathstreak
- attacker->client->pers.deathstreak = 0;
- attacker->client->pers.killstreak++;
-
- //Let's check for a killingspree for the attacker
- G_CheckForSpree( attacker, attacker->client->pers.killstreak, qtrue );
-
- }
-}
-
-
-
-//If the streak / spree divisor is a whole number, we have a spree
-static qboolean TestSpreeWhole( int streak2Test ) {
- float float2Test;
- float spreeFDiv;
- float resultf;
- int spreeDiv;
- int result;
-
- float2Test = streak2Test;
- spreeFDiv = level.spreeDivisor;
- spreeDiv = level.spreeDivisor;
- result = ( streak2Test / spreeDiv );
- resultf = ( float2Test / spreeFDiv );
-
- if( result == resultf ) {
- return qtrue;
- } else {
- return qfalse;
- }
-}
-
-/*
-==================
-G_CheckForSpree
-==================
-*/
-void G_CheckForSpree( gentity_t *ent, int streak2Test, qboolean checkKillSpree )
-{
- int i;
- char *returnedString;
- //If somebody want's to award killing sprees above 99 kills he/she can mod this his/herself!!! :)
- char streakcount[ 3 ];
- char *sound;
- int position;
- int soundIndex;
-
- qboolean isSpree = qfalse;
- int divisionHolder;
-
- //Probably Not Needed, but to protect Server Ops from Crashing their Stuff MidMatch
- if( level.spreeDivisor < 1 ) {
- return;
- }
- divisionHolder = ( streak2Test / level.spreeDivisor );
- //if it's a deathspree
- if( !checkKillSpree ) {
- //Is the streak higher than the largest level defined?
- if( divisionHolder > level.dSpreeUBound ) {
- //Let's make sure it's a whole number to mimic the other sprees
- isSpree = TestSpreeWhole( streak2Test );
- if( !isSpree ) {
- return;
- }
- //We've made it this far...now do the largest spree defined.
- Q_snprintf( streakcount, sizeof( streakcount ), "%i", streak2Test );
- //Check if deathSprees is NULL (actual problem!)
- if(!deathSprees[ level.dSpreeUBound ])
- return;
- returnedString = CreateMessage( ent, deathSprees[ level.dSpreeUBound ]->spreeMsg, streakcount );
- position = deathSprees[ level.dSpreeUBound ]->position;
- sound = deathSprees[ level.dSpreeUBound ]->sound2Play;
- soundIndex = G_SoundIndex( sound );
- G_GlobalSound( soundIndex );
- if( position == CENTER_PRINT ) {
- AP( va("cp \"%s\"", returnedString ) );
- } else {
- AP( va("chat \"%s\"", returnedString ) );
- }
- } else {
- for( i = 0; deathSprees[ i ]; i++ ) {
- //If the deathSpree is equal to the streak to test
- if( deathSprees[ i ]->streakCount == streak2Test ) {
- //Using Q_snprintf to change the int into a char for replacement.
- Q_snprintf( streakcount, sizeof( streakcount ), "%i", deathSprees[ i ]->streakCount );
- //Let's grab the message to show, fill up the placeholders and concatenate it.
- returnedString = CreateMessage ( ent, deathSprees[ i ]->spreeMsg, streakcount );
- //Grab the Print Position ( 1 for Center Printing, 2 for Chat )
- position = deathSprees[ i ]->position;
- //Grab the Sound
- sound = deathSprees[ i ]->sound2Play;
- //Index the Sound
- soundIndex = G_SoundIndex( sound );
- //Play the Sound
- G_GlobalSound( soundIndex );
- //Print the Message
- if( position == CENTER_PRINT ) {
- AP( va("cp \"%s\"", returnedString ) );
- } else {
- AP( va("chat \"%s\"", returnedString ) );
- }
- break;
- }
- }
- }
- } else /*if( checkKillSpree )*/ {
- //Is the streak higher than the largest level defined?
- if( divisionHolder > level.kSpreeUBound ) {
- //Let's make sure it's a whole number to mimic the other sprees
- isSpree = TestSpreeWhole( streak2Test );
- if( !isSpree ) {
- return;
- }
- //We've made it this far...now do the largest spree defined.
- Q_snprintf( streakcount, sizeof( streakcount ), "%i", streak2Test );
- //Check if killSprees is NULL (actual problem!)
- if(!killSprees[ level.kSpreeUBound ])
- return;
- returnedString = CreateMessage( ent, killSprees[ level.kSpreeUBound ]->spreeMsg, streakcount );
- position = killSprees[ level.kSpreeUBound ]->position;
- sound = killSprees[ level.kSpreeUBound ]->sound2Play;
- soundIndex = G_SoundIndex( sound );
- G_GlobalSound( soundIndex );
- if( position == CENTER_PRINT ) {
- AP( va("cp \"%s\"", returnedString ) );
- } else {
- AP( va("chat \"%s\"", returnedString ) );
- }
- } else {
- for( i = 0; killSprees[ i ]; i++ ) {
- if( killSprees[ i ]->streakCount == streak2Test ) {
- Q_snprintf( streakcount, sizeof( streakcount ), "%i", killSprees[ i ]->streakCount );
- returnedString = CreateMessage ( ent, killSprees[ i ]->spreeMsg, streakcount );
- position = killSprees[ i ]->position;
- sound = killSprees[ i ]->sound2Play;
- soundIndex = G_SoundIndex( sound );
- G_GlobalSound( soundIndex );
- if( position == CENTER_PRINT ) {
- AP( va("cp \"%s\"", returnedString ) );
- } else {
- AP( va("chat \"%s\"", returnedString ) );
- }
- break;
- }
- }
- }
- } /*else {
- G_Printf("Killing Spree Error in G_CheckForSpree\n");
- return;
- }*/
-}
-
-
-/*
-===============
-G_checkForMultiKill
-===============
-*/
-void G_checkForMultiKill( gentity_t *ent ) {
-
- int i;
- char *returnedString;
- char *sound;
- int soundIndex;
- int multiKillCount;
- char multiKillString[ 2 ];
- gclient_t *client;
- int clientNum;
-
- client = ent->client;
- clientNum = client - level.clients;
-
- //Let's grab the multikill count for the player first
- multiKillCount = ent->client->pers.multiKillCount;
-
- if( multiKillCount > multiKills[ level.mKillUBound ]->kills ) {
- Q_snprintf( multiKillString, sizeof( multiKillString ), "%i", multiKillCount );
- if(!multiKills[ level.mKillUBound ])
- return; //If null
- returnedString = CreateMessage ( ent, multiKills[ level.mKillUBound ]->killMsg, multiKillString );
- sound = multiKills[ level.mKillUBound ]->sound2Play;
- soundIndex = G_SoundIndex( sound );
- G_GlobalSound( soundIndex );
- AP( va("chat \"%s\"", returnedString ) );
- return;
- } else {
- for( i = 0; multiKills[ i ]; i++ ) {
- //If the multikill count is equal to a killLevel let's do this.
-
- if( multiKills[ i ]->kills == multiKillCount ) {
- Q_snprintf( multiKillString, sizeof( multiKillString ), "%i", multiKills[ i ]->kills );
- //Build the Message
- returnedString = CreateMessage ( ent, multiKills[ i ]->killMsg, multiKillString );
- //Grab the sound
- sound = multiKills[ i ]->sound2Play;
- //Index the sound
- soundIndex = G_SoundIndex( sound );
- //Play the sound
- G_GlobalSound( soundIndex );
- /* Print the String
- Since we don't want to clutter screens (the player is already going to get the excellent icon)
- we won't give them an option to centerprint.
- */
- AP( va("chat \"%s\"", returnedString ) );
- break;
- }
- }
-
- }
-
-}
-
-
-
\ No newline at end of file
diff --git a/game/code/game/g_local.h b/game/code/game/g_local.h
deleted file mode 100644
index 5952af7..0000000
--- a/game/code/game/g_local.h
+++ /dev/null
@@ -1,1364 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 copyPl of the GNU General Public License
-along with Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// g_local.h -- local definitions for game module
-
-#include "../qcommon/q_shared.h"
-#include "bg_public.h"
-#include "g_public.h"
-#include "challenges.h"
-
-//==================================================================
-
-// the "gameversion" client command will print this plus compile date
-#define GAMEVERSION BASEGAME
-
-#define BODY_QUEUE_SIZE 8
-
-#define INFINITE 1000000
-
-#define FRAMETIME 100 // msec
-#define CARNAGE_REWARD_TIME 3000
-#define REWARD_SPRITE_TIME 2000
-
-#define INTERMISSION_DELAY_TIME 1000
-#define SP_INTERMISSION_DELAY_TIME 5000
-
-//Domination how many seconds between awarded a point (multiplied by two if more than 3 points)
-#define DOM_SECSPERPOINT 2000
-
-//limit of the votemaps.cfg file and other custom map files
-#define MAX_MAPS_TEXT 8192
-
-// gentity->flags
-#define FL_GODMODE 0x00000010
-#define FL_NOTARGET 0x00000020
-#define FL_TEAMSLAVE 0x00000400 // not the first on the team
-#define FL_NO_KNOCKBACK 0x00000800
-#define FL_DROPPED_ITEM 0x00001000
-#define FL_NO_BOTS 0x00002000 // spawn point not for bot use
-#define FL_NO_HUMANS 0x00004000 // spawn point just for bots
-#define FL_FORCE_GESTURE 0x00008000 // force gesture on client
-
-// movers are things like doors, plats, buttons, etc
-typedef enum {
- MOVER_POS1,
- MOVER_POS2,
- MOVER_1TO2,
- MOVER_2TO1
-} moverState_t;
-
-#define SP_PODIUM_MODEL "models/mapobjects/podium/podium4.md3"
-
-//============================================================================
-
-typedef struct gentity_s gentity_t;
-typedef struct gclient_s gclient_t;
-
-struct gentity_s {
- entityState_t s; // communicated by server to clients
- entityShared_t r; // shared by both the server system and game
-
- // DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
- // EXPECTS THE FIELDS IN THAT ORDER!
- //================================
-
- struct gclient_s *client; // NULL if not a client
-
- qboolean inuse;
-
- char *classname; // set in QuakeEd
- int spawnflags; // set in QuakeEd
-
- qboolean neverFree; // if true, FreeEntity will only unlink
- // bodyque uses this
-
- int flags; // FL_* variables
-
- char *model;
- char *model2;
- int freetime; // level.time when the object was freed
-
- int eventTime; // events will be cleared EVENT_VALID_MSEC after set
- qboolean freeAfterEvent;
- qboolean unlinkAfterEvent;
-
- qboolean physicsObject; // if true, it can be pushed by movers and fall off edges
- // all game items are physicsObjects,
- float physicsBounce; // 1.0 = continuous bounce, 0.0 = no bounce
- int clipmask; // brushes with this content value will be collided against
- // when moving. items and corpses do not collide against
- // players, for instance
-
- // movers
- moverState_t moverState;
- int soundPos1;
- int sound1to2;
- int sound2to1;
- int soundPos2;
- int soundLoop;
- gentity_t *parent;
- gentity_t *nextTrain;
- gentity_t *prevTrain;
- vec3_t pos1, pos2;
-
- char *message;
-
- int timestamp; // body queue sinking, etc
-
- float angle; // set in editor, -1 = up, -2 = down
- char *target;
- char *targetname;
- char *team;
- char *targetShaderName;
- char *targetShaderNewName;
- gentity_t *target_ent;
-
- float speed;
- vec3_t movedir;
-
- int nextthink;
- void (*think)(gentity_t *self);
- void (*reached)(gentity_t *self); // movers call this when hitting endpoint
- void (*blocked)(gentity_t *self, gentity_t *other);
- void (*touch)(gentity_t *self, gentity_t *other, trace_t *trace);
- void (*use)(gentity_t *self, gentity_t *other, gentity_t *activator);
- void (*pain)(gentity_t *self, gentity_t *attacker, int damage);
- void (*die)(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod);
-
- int pain_debounce_time;
- int fly_sound_debounce_time; // wind tunnel
- int last_move_time;
-
- int health;
-
- qboolean takedamage;
-
- int damage;
- int splashDamage; // quad will increase this without increasing radius
- int splashRadius;
- int methodOfDeath;
- int splashMethodOfDeath;
-
- int count;
-
- gentity_t *chain;
- gentity_t *enemy;
- gentity_t *activator;
- gentity_t *teamchain; // next entity in team
- gentity_t *teammaster; // master of the team
-
- int kamikazeTime;
- int kamikazeShockTime;
-
- int watertype;
- int waterlevel;
-
- int noise_index;
-
- // timing variables
- float wait;
- float random;
-
- gitem_t *item; // for bonus items
-};
-
-
-typedef enum {
- CON_DISCONNECTED,
- CON_CONNECTING,
- CON_CONNECTED
-} clientConnected_t;
-
-typedef enum {
- SPECTATOR_NOT,
- SPECTATOR_FREE,
- SPECTATOR_FOLLOW,
- SPECTATOR_SCOREBOARD
-} spectatorState_t;
-
-typedef enum {
- TEAM_BEGIN, // Beginning a team game, spawn at base
- TEAM_ACTIVE // Now actively playing
-} playerTeamStateState_t;
-
-typedef struct {
- playerTeamStateState_t state;
-
- int location;
-
- int captures;
- int basedefense;
- int carrierdefense;
- int flagrecovery;
- int fragcarrier;
- int assists;
-
- float lasthurtcarrier;
- float lastreturnedflag;
- float flagsince;
- float lastfraggedcarrier;
-} playerTeamState_t;
-
-// the auto following clients don't follow a specific client
-// number, but instead follow the first two active players
-#define FOLLOW_ACTIVE1 -1
-#define FOLLOW_ACTIVE2 -2
-
-// client data that stays across multiple levels or tournament restarts
-// this is achieved by writing all the data to cvar strings at game shutdown
-// time and reading them back at connection time. Anything added here
-// MUST be dealt with in G_InitSessionData() / G_ReadSessionData() / G_WriteSessionData()
-typedef struct {
- team_t sessionTeam;
- int spectatorTime; // for determining next-in-line to play
- spectatorState_t spectatorState;
- int spectatorClient; // for chasecam and follow mode
- int wins, losses; // tournament stats
- qboolean teamLeader; // true when this client is a team leader
-} clientSession_t;
-
-//
-#define MAX_NETNAME 36
-#define MAX_VOTE_COUNT 3
-
-//unlagged - true ping
-#define NUM_PING_SAMPLES 64
-//unlagged - true ping
-
-// client data that stays across multiple respawns, but is cleared
-// on each level change or team change at ClientBegin()
-typedef struct {
- clientConnected_t connected;
- usercmd_t cmd; // we would lose angles if not persistant
- qboolean localClient; // true if "ip" info key is "localhost"
- qboolean initialSpawn; // the first spawn should be at a cool location
- qboolean predictItemPickup; // based on cg_predictItems userinfo
- qboolean pmoveFixed; //
- char netname[MAX_NETNAME];
- int maxHealth; // for handicapping
- int enterTime; // level.time the client entered the game
- playerTeamState_t teamState; // status in teamplay games
- int voteCount; // to prevent people from constantly calling votes
- int teamVoteCount; // to prevent people from constantly calling votes
- qboolean teamInfo; // send team overlay updates?
- //elimination:
- int roundReached; //Only spawn if we are new to this round
- int livesLeft; //lives in LMS
-
-//unlagged - client options
- // these correspond with variables in the userinfo string
- int delag;
-// int debugDelag;
- int cmdTimeNudge;
-//unlagged - client options
-//unlagged - lag simulation #2
-/* int latentSnaps;
- int latentCmds;
- int plOut;
- usercmd_t cmdqueue[MAX_LATENT_CMDS];
- int cmdhead;*/
-//unlagged - lag simulation #2
-//unlagged - true ping
- int realPing;
- int pingsamples[NUM_PING_SAMPLES];
- int samplehead;
-//unlagged - true ping
-//KK-OAX Killing Sprees/Multikills
- int killstreak;
- int deathstreak;
- qboolean onSpree;
- int multiKillCount;
-
-//KK-OAX Admin Stuff
- char guid[ 33 ];
- char ip[ 40 ];
- qboolean muted;
- qboolean disoriented;
- qboolean wasdisoriented;
- int adminLevel;
-
-// flood protection
- int floodDemerits;
- int floodTime;
-
-//Used To Track Name Changes
- int nameChangeTime;
- int nameChanges;
-
-} clientPersistant_t;
-
-//unlagged - backward reconciliation #1
-// the size of history we'll keep
-#define NUM_CLIENT_HISTORY 17
-
-// everything we need to know to backward reconcile
-typedef struct {
- vec3_t mins, maxs;
- vec3_t currentOrigin;
- int leveltime;
-} clientHistory_t;
-//unlagged - backward reconciliation #1
-
-// this structure is cleared on each ClientSpawn(),
-// except for 'client->pers' and 'client->sess'
-struct gclient_s {
- // ps MUST be the first element, because the server expects it
- playerState_t ps; // communicated by server to clients
-
- // the rest of the structure is private to game
- clientPersistant_t pers;
- clientSession_t sess;
-
- qboolean readyToExit; // wishes to leave the intermission
-
- qboolean noclip;
-
- //Unlagged - commented out - handled differently
- //int lastCmdTime; // level.time of last usercmd_t, for EF_CONNECTION
- // we can't just use pers.lastCommand.time, because
- // of the g_sycronousclients case
- int buttons;
- int oldbuttons;
- int latched_buttons;
-
- vec3_t oldOrigin;
-
- // sum up damage over an entire frame, so
- // shotgun blasts give a single big kick
- int damage_armor; // damage absorbed by armor
- int damage_blood; // damage taken out of health
- int damage_knockback; // impact damage
- vec3_t damage_from; // origin for vector calculation
- qboolean damage_fromWorld; // if true, don't use the damage_from vector
-
- int accurateCount; // for "impressive" reward sound
-
- int accuracy_shots; // total number of shots
- int accuracy_hits; // total number of hits
-
- //
- int lastkilled_client; // last client that this client killed
- int lasthurt_client; // last client that damaged this client
- int lasthurt_mod; // type of damage the client did
-
- // timers
- int respawnTime; // can respawn when time > this, force after g_forcerespwan
- int inactivityTime; // kick players when time > this
- qboolean inactivityWarning; // qtrue if the five seoond warning has been given
- int rewardTime; // clear the EF_AWARD_IMPRESSIVE, etc when time > this
-
- int airOutTime;
-
- int lastKillTime; // for multiple kill rewards
-
- qboolean fireHeld; // used for hook
- gentity_t *hook; // grapple hook if out
-
- int switchTeamTime; // time the player switched teams
-
- // timeResidual is used to handle events that happen every second
- // like health / armor countdowns and regeneration
- int timeResidual;
-
- gentity_t *persistantPowerup;
- int portalID;
- int ammoTimes[WP_NUM_WEAPONS];
- int invulnerabilityTime;
-
-
- char *areabits;
-
- qboolean isEliminated; //Has been killed in this round
-
- //New vote system. The votes are saved in the client info, so we know who voted on what and can cancel votes on leave.
- //0=not voted, 1=voted yes, -1=voted no
- int vote;
-
- int lastSentFlying; //The last client that sent the player flying
- int lastSentFlyingTime; //So we can time out
-
-
- //unlagged - backward reconciliation #1
- // the serverTime the button was pressed
- // (stored before pmove_fixed changes serverTime)
- int attackTime;
- // the head of the history queue
- int historyHead;
- // the history queue
- clientHistory_t history[NUM_CLIENT_HISTORY];
- // the client's saved position
- clientHistory_t saved; // used to restore after time shift
- // an approximation of the actual server time we received this
- // command (not in 50ms increments)
- int frameOffset;
-//unlagged - backward reconciliation #1
-
-//unlagged - smooth clients #1
- // the last frame number we got an update from this client
- int lastUpdateFrame;
-//unlagged - smooth clients #1
-};
-
-
-//
-// this structure is cleared as each map is entered
-//
-#define MAX_SPAWN_VARS 64
-#define MAX_SPAWN_VARS_CHARS 4096
-
-typedef struct {
- struct gclient_s *clients; // [maxclients]
-
- struct gentity_s *gentities;
- int gentitySize;
- int num_entities; // current number, <= MAX_GENTITIES
-
- int warmupTime; // restart match at this time
-
- fileHandle_t logFile;
-
- // store latched cvars here that we want to get at often
- int maxclients;
-
- int framenum;
- int time; // in msec
- int previousTime; // so movers can back up when blocked
-
- int startTime; // level.time the map was started
-
- int teamScores[TEAM_NUM_TEAMS];
- int lastTeamLocationTime; // last time of client team location update
-
- qboolean newSession; // don't use any old session data, because
- // we changed gametype
-
- qboolean restarted; // waiting for a map_restart to fire
-
- int numConnectedClients;
- int numNonSpectatorClients; // includes connecting clients
- int numPlayingClients; // connected, non-spectators
- int sortedClients[MAX_CLIENTS]; // sorted by score
- int follow1, follow2; // clientNums for auto-follow spectators
-
- int snd_fry; // sound index for standing in lava
-
- int warmupModificationCount; // for detecting if g_warmup is changed
-
- // voting state
- char voteString[MAX_STRING_CHARS];
- char voteDisplayString[MAX_STRING_CHARS];
- int voteTime; // level.time vote was called
- int voteExecuteTime; // time the vote is executed
- int voteYes;
- int voteNo;
- int numVotingClients; // set by CountVotes
-
- // team voting state
- char teamVoteString[2][MAX_STRING_CHARS];
- int teamVoteTime[2]; // level.time vote was called
- int teamVoteYes[2];
- int teamVoteNo[2];
- int numteamVotingClients[2];// set by CalculateRanks
-
- // spawn variables
- qboolean spawning; // the G_Spawn*() functions are valid
- int numSpawnVars;
- char *spawnVars[MAX_SPAWN_VARS][2]; // key / value pairs
- int numSpawnVarChars;
- char spawnVarChars[MAX_SPAWN_VARS_CHARS];
-
- // intermission state
- int intermissionQueued; // intermission was qualified, but
- // wait INTERMISSION_DELAY_TIME before
- // actually going there so the last
- // frag can be watched. Disable future
- // kills during this delay
- int intermissiontime; // time the intermission was started
- char *changemap;
- qboolean readyToExit; // at least one client wants to exit
- int exitTime;
- vec3_t intermission_origin; // also used for spectator spawns
- vec3_t intermission_angle;
-
- qboolean locationLinked; // target_locations get linked
- gentity_t *locationHead; // head of the location list
- int bodyQueIndex; // dead bodies
- gentity_t *bodyQue[BODY_QUEUE_SIZE];
- int portalSequence;
- //Added for elimination:
- int roundStartTime; //time the current round was started
- int roundNumber; //The round number we have reached
- int roundNumberStarted; //1 less than roundNumber if we are allowed to spawn
- int roundRedPlayers; //How many players was there at start of round
- int roundBluePlayers; //used to find winners in a draw.
- qboolean roundRespawned; //We have respawned for this round!
- int eliminationSides; //Random, change red/blue bases
-
- //Added for Double Domination
- //Points get status: TEAM_FREE for not taking, TEAM_RED/TEAM_BLUE for taken and TEAM_NONE for not spawned yet
- int pointStatusA; //Status of the RED (A) domination point
- int pointStatusB; //Status of the BLUE (B) doimination point
- int timeTaken; //Time team started having both points
- //use roundStartTime for telling, then the points respawn
-
- //Added for standard domination
- int pointStatusDom[MAX_DOMINATION_POINTS]; //Holds the owner of all the points
- int dom_scoreGiven; //Number of times we have provided scores
- int domination_points_count;
- char domination_points_names[MAX_DOMINATION_POINTS][MAX_DOMINATION_POINTS_NAMES];
-
- //Added to keep track of challenges (can only be completed against humanplayers)
- qboolean hadBots; //There was bots in the level
- int teamSize; //The highest number of players on the least populated team when there was most players
-
-//unlagged - backward reconciliation #4
- // actual time this server frame started
- int frameStartTime;
-//unlagged - backward reconciliation #4
-//KK-OAX Storing upper bounds of spree/multikill arrays
- int kSpreeUBound;
- int dSpreeUBound;
- int mKillUBound;
-//KK-OAX Storing g_spreeDiv to avoid dividing by 0.
- int spreeDivisor;
-
- qboolean RedTeamLocked;
- qboolean BlueTeamLocked;
- qboolean FFALocked;
-
-} level_locals_t;
-
-//KK-OAX These are some Print Shortcuts for KillingSprees and Admin
-//KK-Moved to g_admin.h
-//Prints to All when using "va()" in conjunction.
-//#define AP(x) trap_SendServerCommand(-1, x)
-
-//
-// g_spawn.c
-//
-qboolean G_SpawnString( const char *key, const char *defaultString, char **out );
-// spawn string returns a temporary reference, you must CopyString() if you want to keep it
-qboolean G_SpawnFloat( const char *key, const char *defaultString, float *out );
-qboolean G_SpawnInt( const char *key, const char *defaultString, int *out );
-qboolean G_SpawnVector( const char *key, const char *defaultString, float *out );
-void G_SpawnEntitiesFromString( void );
-char *G_NewString( const char *string );
-
-//
-// g_cmds.c
-//
-void Cmd_Score_f (gentity_t *ent);
-void StopFollowing( gentity_t *ent );
-void BroadcastTeamChange( gclient_t *client, int oldTeam );
-void SetTeam( gentity_t *ent, char *s );
-void Cmd_FollowCycle_f( gentity_t *ent ); //KK-OAX Changed to match definition
-char *ConcatArgs( int start ); //KK-OAX This declaration moved from g_svccmds.c
-//KK-OAX Added this to make accessible from g_svcmds_ext.c
-void G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText );
-
-
-// KK-OAX Added these in a seperate file to keep g_cmds.c familiar.
-// g_cmds_ext.c
-//
-
-int G_SayArgc( void );
-qboolean G_SayArgv( int n, char *buffer, int bufferLength );
-char *G_SayConcatArgs( int start );
-void G_DecolorString( char *in, char *out, int len );
-void G_MatchOnePlayer( int *plist, int num, char *err, int len );
-void G_SanitiseString( char *in, char *out, int len );
-int G_ClientNumbersFromString( char *s, int *plist, int max );
-int G_FloodLimited( gentity_t *ent );
-//void QDECL G_AdminMessage( const char *prefix, const char *fmt, ... )
-// ^^ Do Not Need to Declare--Just for Documentation of where it is.
-void Cmd_AdminMessage_f( gentity_t *ent );
-int G_ClientNumberFromString( char *s );
-qboolean G_ClientIsLagging( gclient_t *client );
-void SanitizeString( char *in, char *out );
-
-// KK-OAX Added this for common file stuff between Admin and Sprees.
-// g_fileops.c
-//
-void readFile_int( char **cnf, int *v );
-void readFile_string( char **cnf, char *s, int size );
-void writeFile_int( int v, fileHandle_t f );
-void writeFile_string( char *s, fileHandle_t f );
-
-//
-// g_items.c
-//
-void G_CheckTeamItems( void );
-void G_RunItem( gentity_t *ent );
-void RespawnItem( gentity_t *ent );
-
-void UseHoldableItem( gentity_t *ent );
-void PrecacheItem (gitem_t *it);
-gentity_t *Drop_Item( gentity_t *ent, gitem_t *item, float angle );
-gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity );
-void SetRespawn (gentity_t *ent, float delay);
-void G_SpawnItem (gentity_t *ent, gitem_t *item);
-void FinishSpawningItem( gentity_t *ent );
-void Think_Weapon (gentity_t *ent);
-int ArmorIndex (gentity_t *ent);
-void Add_Ammo (gentity_t *ent, int weapon, int count);
-void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace);
-
-void ClearRegisteredItems( void );
-void RegisterItem( gitem_t *item );
-void SaveRegisteredItems( void );
-
-//
-// g_utils.c
-//
-int G_ModelIndex( char *name );
-int G_SoundIndex( char *name );
-void G_TeamCommand( team_t team, char *cmd );
-void G_KillBox (gentity_t *ent);
-gentity_t *G_Find (gentity_t *from, int fieldofs, const char *match);
-gentity_t *G_PickTarget (char *targetname);
-void G_UseTargets (gentity_t *ent, gentity_t *activator);
-void G_SetMovedir ( vec3_t angles, vec3_t movedir);
-
-void G_InitGentity( gentity_t *e );
-gentity_t *G_Spawn (void);
-gentity_t *G_TempEntity( vec3_t origin, int event );
-void G_Sound( gentity_t *ent, int channel, int soundIndex );
-
-//KK-OAX For Playing Sounds Globally
-void G_GlobalSound( int soundIndex );
-
-void G_FreeEntity( gentity_t *e );
-qboolean G_EntitiesFree( void );
-
-void G_TouchTriggers (gentity_t *ent);
-void G_TouchSolids (gentity_t *ent);
-
-float *tv (float x, float y, float z);
-char *vtos( const vec3_t v );
-
-float vectoyaw( const vec3_t vec );
-
-void G_AddPredictableEvent( gentity_t *ent, int event, int eventParm );
-void G_AddEvent( gentity_t *ent, int event, int eventParm );
-void G_SetOrigin( gentity_t *ent, vec3_t origin );
-void AddRemap(const char *oldShader, const char *newShader, float timeOffset);
-const char *BuildShaderStateConfig( void );
-
-//
-// g_combat.c
-//
-qboolean CanDamage (gentity_t *targ, vec3_t origin);
-void G_Damage (gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_t dir, vec3_t point, int damage, int dflags, int mod);
-qboolean G_RadiusDamage (vec3_t origin, gentity_t *attacker, float damage, float radius, gentity_t *ignore, int mod);
-int G_InvulnerabilityEffect( gentity_t *targ, vec3_t dir, vec3_t point, vec3_t impactpoint, vec3_t bouncedir );
-void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath );
-void TossClientItems( gentity_t *self );
-void TossClientPersistantPowerups( gentity_t *self );
-void TossClientCubes( gentity_t *self );
-
-// damage flags
-#define DAMAGE_RADIUS 0x00000001 // damage was indirect
-#define DAMAGE_NO_ARMOR 0x00000002 // armour does not protect from this damage
-#define DAMAGE_NO_KNOCKBACK 0x00000004 // do not affect velocity, just view angles
-#define DAMAGE_NO_PROTECTION 0x00000008 // armor, shields, invulnerability, and godmode have no effect
-#define DAMAGE_NO_TEAM_PROTECTION 0x00000010 // armor, shields, invulnerability, and godmode have no effect
-
-//
-// g_missile.c
-//
-void G_RunMissile( gentity_t *ent );
-void ProximityMine_RemoveAll( void );
-
-gentity_t *fire_blaster (gentity_t *self, vec3_t start, vec3_t aimdir);
-gentity_t *fire_plasma (gentity_t *self, vec3_t start, vec3_t aimdir);
-gentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t aimdir);
-gentity_t *fire_rocket (gentity_t *self, vec3_t start, vec3_t dir);
-gentity_t *fire_bfg (gentity_t *self, vec3_t start, vec3_t dir);
-gentity_t *fire_grapple (gentity_t *self, vec3_t start, vec3_t dir);
-gentity_t *fire_nail( gentity_t *self, vec3_t start, vec3_t forward, vec3_t right, vec3_t up );
-gentity_t *fire_prox( gentity_t *self, vec3_t start, vec3_t aimdir );
-
-
-//
-// g_mover.c
-//
-void G_RunMover( gentity_t *ent );
-void Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace );
-
-//
-// g_trigger.c
-//
-void trigger_teleporter_touch (gentity_t *self, gentity_t *other, trace_t *trace );
-
-
-//
-// g_misc.c
-//
-void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles );
-void DropPortalSource( gentity_t *ent );
-void DropPortalDestination( gentity_t *ent );
-
-
-//
-// g_weapon.c
-//
-qboolean LogAccuracyHit( gentity_t *target, gentity_t *attacker );
-void CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint );
-//unlagged - attack prediction #3
-// we're making this available to both games
-void SnapVectorTowards( vec3_t v, vec3_t to );
-//unlagged - attack prediction #3
-qboolean CheckGauntletAttack( gentity_t *ent );
-void Weapon_HookFree (gentity_t *ent);
-void Weapon_HookThink (gentity_t *ent);
-
-//unlagged - g_unlagged.c
-void G_ResetHistory( gentity_t *ent );
-void G_StoreHistory( gentity_t *ent );
-void G_TimeShiftAllClients( int time, gentity_t *skip );
-void G_UnTimeShiftAllClients( gentity_t *skip );
-void G_DoTimeShiftFor( gentity_t *ent );
-void G_UndoTimeShiftFor( gentity_t *ent );
-void G_UnTimeShiftClient( gentity_t *client );
-void G_PredictPlayerMove( gentity_t *ent, float frametime );
-//unlagged - g_unlagged.c
-
-//
-// g_client.c
-//
-team_t TeamCount( int ignoreClientNum, int team );
-team_t TeamLivingCount( int ignoreClientNum, int team ); //Elimination
-team_t TeamHealthCount( int ignoreClientNum, int team ); //Elimination
-void RespawnAll(void); //For round elimination
-void RespawnDead(void);
-void EnableWeapons(void);
-void DisableWeapons(void);
-void EndEliminationRound(void);
-void LMSpoint(void);
-//void wins2score(void);
-int TeamLeader( int team );
-team_t PickTeam( int ignoreClientNum );
-void SetClientViewAngle( gentity_t *ent, vec3_t angle );
-gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles );
-void CopyToBodyQue( gentity_t *ent );
-void respawn (gentity_t *ent);
-void BeginIntermission (void);
-void InitClientPersistant (gclient_t *client);
-void InitClientResp (gclient_t *client);
-void InitBodyQue (void);
-void ClientSpawn( gentity_t *ent );
-void player_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod);
-void AddScore( gentity_t *ent, vec3_t origin, int score );
-void CalculateRanks( void );
-qboolean SpotWouldTelefrag( gentity_t *spot );
-
-//
-// g_svcmds.c
-//
-qboolean ConsoleCommand( void );
-void G_ProcessIPBans(void);
-qboolean G_FilterPacket (char *from);
-
-//KK-OAX Added this to make accessible from g_svcmds_ext.c
-gclient_t *ClientForString( const char *s );
-
-//
-// g_weapon.c
-//
-void FireWeapon( gentity_t *ent );
-void G_StartKamikaze( gentity_t *ent );
-
-//
-// p_hud.c
-//
-void MoveClientToIntermission (gentity_t *client);
-void G_SetStats (gentity_t *ent);
-
-//
-// g_cmds.c
-// Also another place /Sago
-
-void DoubleDominationScoreTimeMessage( gentity_t *ent );
-void YourTeamMessage( gentity_t *ent);
-void AttackingTeamMessage( gentity_t *ent );
-void DeathmatchScoreboardMessage (gentity_t *client);
-void EliminationMessage (gentity_t *client);
-void DominationPointNamesMessage (gentity_t *client);
-void DominationPointStatusMessage( gentity_t *ent );
-void ChallengeMessage( gentity_t *ent, int challengeNumber );
-void SendCustomVoteCommands(int clientNum);
-
-//
-// g_pweapon.c
-//
-
-
-//
-// g_main.c
-//
-void FindIntermissionPoint( void );
-void SetLeader(int team, int client);
-void CheckTeamLeader( int team );
-void G_RunThink (gentity_t *ent);
-void QDECL G_LogPrintf( const char *fmt, ... );
-void SendScoreboardMessageToAllClients( void );
-void SendEliminationMessageToAllClients( void );
-void SendDDtimetakenMessageToAllClients( void );
-void SendDominationPointsStatusMessageToAllClients( void );
-void SendYourTeamMessageToTeam( team_t team );
-void QDECL G_Printf( const char *fmt, ... );
-void QDECL G_Error( const char *fmt, ... );
-//KK-OAX Made Accessible for g_admin.c
-void LogExit( const char *string );
-void CheckTeamVote( int team );
-
-//
-// g_client.c
-//
-char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot );
-void ClientUserinfoChanged( int clientNum );
-void ClientDisconnect( int clientNum );
-void ClientBegin( int clientNum );
-void ClientCommand( int clientNum );
-
-//
-// g_active.c
-//
-void ClientThink( int clientNum );
-void ClientEndFrame( gentity_t *ent );
-void G_RunClient( gentity_t *ent );
-
-//
-// g_team.c
-//
-qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 );
-void Team_CheckDroppedItem( gentity_t *dropped );
-qboolean CheckObeliskAttack( gentity_t *obelisk, gentity_t *attacker );
-void ShuffleTeams(void);
-//KK-OAX Added for Command Handling Changes (r24)
-team_t G_TeamFromString( char *str );
-
-//KK-OAX Removed these in Code in favor of bg_alloc.c from Tremulous
-// g_mem.c
-//
-//void *G_Alloc( int size );
-//void G_InitMemory( void );
-
-//KK-OAX This was moved
-// bg_alloc.c
-//
-void Svcmd_GameMem_f( void );
-
-//
-// g_session.c
-//
-void G_ReadSessionData( gclient_t *client );
-void G_InitSessionData( gclient_t *client, char *userinfo );
-
-void G_InitWorldSession( void );
-void G_WriteSessionData( void );
-
-//
-// g_arenas.c
-//
-void UpdateTournamentInfo( void );
-void SpawnModelsOnVictoryPads( void );
-void Svcmd_AbortPodium_f( void );
-
-//
-// g_bot.c
-//
-void G_InitBots( qboolean restart );
-char *G_GetBotInfoByNumber( int num );
-char *G_GetBotInfoByName( const char *name );
-void G_CheckBotSpawn( void );
-void G_RemoveQueuedBotBegin( int clientNum );
-qboolean G_BotConnect( int clientNum, qboolean restart );
-void Svcmd_AddBot_f( void );
-void Svcmd_BotList_f( void );
-void BotInterbreedEndMatch( void );
-
-//
-// g_playerstore.c
-//
-
-void PlayerStoreInit( void );
-void PlayerStore_store(char* guid, playerState_t ps);
-void PlayerStore_restore(char* guid, playerState_t *ps);
-
-//
-// g_vote.c
-//
-int allowedVote(char *commandStr);
-void CheckVote( void );
-void CountVotes( void );
-
-#define MAX_MAPNAME 32
-#define MAPS_PER_PAGE 10
-#define MAX_MAPNAME_BUFFER MAX_MAPNAME*600
-#define MAX_MAPNAME_LENGTH 34
-#define MAX_CUSTOMNAME MAX_MAPNAME
-#define MAX_CUSTOMCOMMAND 100
-#define MAX_CUSTOMDISPLAYNAME 50
-
-typedef struct {
- int pagenumber;
- char mapname[MAPS_PER_PAGE][MAX_MAPNAME];
-} t_mappage;
-
-typedef struct {
- char votename[MAX_CUSTOMNAME]; //Used like "/callvote custom VOTENAME"
- char displayname[MAX_CUSTOMDISPLAYNAME]; //Displayed during voting
- char command[MAX_CUSTOMCOMMAND]; //The command executed
-} t_customvote;
-
-extern char custom_vote_info[1024];
-
-extern t_mappage getMappage(int page);
-extern int allowedMap(char *mapname);
-extern int allowedGametype(char *gametypeStr);
-extern int allowedTimelimit(int limit);
-extern int allowedFraglimit(int limit);
-extern int VoteParseCustomVotes( void );
-extern t_customvote getCustomVote(char* votecommand);
-
-// ai_main.c
-#define MAX_FILEPATH 144
-
-//bot settings
-typedef struct bot_settings_s
-{
- char characterfile[MAX_FILEPATH];
- float skill;
- char team[MAX_FILEPATH];
-} bot_settings_t;
-
-int BotAISetup( int restart );
-int BotAIShutdown( int restart );
-int BotAILoadMap( int restart );
-int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean restart);
-int BotAIShutdownClient( int client, qboolean restart );
-int BotAIStartFrame( int time );
-void BotTestAAS(vec3_t origin);
-
-#include "g_team.h" // teamplay specific stuff
-
-
-extern level_locals_t level;
-extern gentity_t g_entities[MAX_GENTITIES];
-
-#define FOFS(x) ((size_t)&(((gentity_t *)0)->x))
-
-//CVARS
-extern vmCvar_t g_gametype;
-extern vmCvar_t g_dedicated;
-extern vmCvar_t g_cheats;
-extern vmCvar_t g_maxclients; // allow this many total, including spectators
-extern vmCvar_t g_maxGameClients; // allow this many active
-extern vmCvar_t g_restarted;
-
-extern vmCvar_t g_dmflags;
-extern vmCvar_t g_videoflags;
-extern vmCvar_t g_elimflags;
-extern vmCvar_t g_voteflags;
-extern vmCvar_t g_fraglimit;
-extern vmCvar_t g_timelimit;
-extern vmCvar_t g_capturelimit;
-extern vmCvar_t g_friendlyFire;
-extern vmCvar_t g_password;
-extern vmCvar_t g_needpass;
-extern vmCvar_t g_gravity;
-extern vmCvar_t g_speed;
-extern vmCvar_t g_knockback;
-extern vmCvar_t g_quadfactor;
-extern vmCvar_t g_forcerespawn;
-extern vmCvar_t g_inactivity;
-extern vmCvar_t g_debugMove;
-extern vmCvar_t g_debugAlloc;
-extern vmCvar_t g_debugDamage;
-extern vmCvar_t g_weaponRespawn;
-extern vmCvar_t g_weaponTeamRespawn;
-extern vmCvar_t g_synchronousClients;
-extern vmCvar_t g_motd;
-extern vmCvar_t g_warmup;
-extern vmCvar_t g_doWarmup;
-extern vmCvar_t g_blood;
-extern vmCvar_t g_allowVote;
-extern vmCvar_t g_teamAutoJoin;
-extern vmCvar_t g_teamForceBalance;
-extern vmCvar_t g_banIPs;
-extern vmCvar_t g_filterBan;
-extern vmCvar_t g_obeliskHealth;
-extern vmCvar_t g_obeliskRegenPeriod;
-extern vmCvar_t g_obeliskRegenAmount;
-extern vmCvar_t g_obeliskRespawnDelay;
-extern vmCvar_t g_cubeTimeout;
-extern vmCvar_t g_smoothClients;
-extern vmCvar_t pmove_fixed;
-extern vmCvar_t pmove_msec;
-extern vmCvar_t pmove_float;
-extern vmCvar_t g_rankings;
-#ifdef MISSIONPACK
-extern vmCvar_t g_singlePlayer;
-extern vmCvar_t g_redteam;
-extern vmCvar_t g_blueteam;
-#endif
-extern vmCvar_t g_enableDust;
-extern vmCvar_t g_enableBreath;
-extern vmCvar_t g_proxMineTimeout;
-extern vmCvar_t g_music;
-
-//elimination:
-extern vmCvar_t g_elimination_selfdamage;
-extern vmCvar_t g_elimination_startHealth;
-extern vmCvar_t g_elimination_startArmor;
-extern vmCvar_t g_elimination_bfg;
-extern vmCvar_t g_elimination_grapple;
-extern vmCvar_t g_elimination_roundtime;
-extern vmCvar_t g_elimination_warmup;
-extern vmCvar_t g_elimination_activewarmup;
-extern vmCvar_t g_elimination_allgametypes;
-extern vmCvar_t g_elimination_machinegun;
-extern vmCvar_t g_elimination_shotgun;
-extern vmCvar_t g_elimination_grenade;
-extern vmCvar_t g_elimination_rocket;
-extern vmCvar_t g_elimination_railgun;
-extern vmCvar_t g_elimination_lightning;
-extern vmCvar_t g_elimination_plasmagun;
-extern vmCvar_t g_elimination_chain;
-extern vmCvar_t g_elimination_mine;
-extern vmCvar_t g_elimination_nail;
-
-//If lockspectator: 0=no limit, 1 = cannot follow enemy, 2 = must follow friend
-extern vmCvar_t g_elimination_lockspectator;
-
-extern vmCvar_t g_rockets;
-
-//new in elimination Beta2
-extern vmCvar_t g_instantgib;
-extern vmCvar_t g_vampire;
-extern vmCvar_t g_vampireMaxHealth;
-//new in elimination Beta3
-extern vmCvar_t g_regen;
-//Free for all gametype
-extern int g_ffa_gt; //0 = TEAM GAME, 1 = FFA, 2 = TEAM GAME without bases
-
-extern vmCvar_t g_lms_lives;
-
-extern vmCvar_t g_lms_mode; //How do we score: 0 = One Survivor get a point, 1 = same but without overtime, 2 = one point for each player killed (+overtime), 3 = same without overtime
-
-extern vmCvar_t g_elimination_ctf_oneway; //Only attack in one direction (level.eliminationSides+level.roundNumber)%2 == 0 red attacks
-
-extern vmCvar_t g_awardpushing; //The server can decide if players are awarded for pushing people in lave etc.
-
-extern vmCvar_t g_persistantpowerups;
-
-extern vmCvar_t g_catchup; //Favors the week players
-
-extern vmCvar_t g_voteNames;
-extern vmCvar_t g_voteGametypes;
-extern vmCvar_t g_voteMinTimelimit;
-extern vmCvar_t g_voteMaxTimelimit;
-extern vmCvar_t g_voteMinFraglimit;
-extern vmCvar_t g_voteMaxFraglimit;
-
-extern vmCvar_t g_humanplayers;
-
-//used for voIP
-extern vmCvar_t g_redTeamClientNumbers;
-extern vmCvar_t g_blueTeamClientNumbers;
-
-//unlagged - server options
-// some new server-side variables
-extern vmCvar_t g_delagHitscan;
-extern vmCvar_t g_truePing;
-// this is for convenience - using "sv_fps.integer" is nice :)
-extern vmCvar_t sv_fps;
-extern vmCvar_t g_lagLightning;
-//unlagged - server options
-//KK-OAX Killing Sprees
-extern vmCvar_t g_sprees; //Used for specifiying the config file
-extern vmCvar_t g_altExcellent; //Turns on Multikills instead of Excellent
-extern vmCvar_t g_spreeDiv; // Interval of a "streak" that form the spree triggers
-//KK-OAX Command/Chat Flooding/Spamming
-extern vmCvar_t g_floodMaxDemerits;
-extern vmCvar_t g_floodMinTime;
-//KK-OAX Admin
-extern vmCvar_t g_admin;
-extern vmCvar_t g_adminLog;
-extern vmCvar_t g_adminParseSay;
-extern vmCvar_t g_adminNameProtect;
-extern vmCvar_t g_adminTempBan;
-extern vmCvar_t g_adminMaxBan;
-//KK-OAX Admin-Like
-extern vmCvar_t g_specChat;
-extern vmCvar_t g_publicAdminMessages;
-
-extern vmCvar_t g_maxWarnings;
-extern vmCvar_t g_warningExpire;
-
-extern vmCvar_t g_minNameChangePeriod;
-extern vmCvar_t g_maxNameChanges;
-
-
-void trap_Printf( const char *fmt );
-void trap_Error( const char *fmt );
-int trap_Milliseconds( void );
-int trap_RealTime( qtime_t *qtime );
-int trap_Argc( void );
-void trap_Argv( int n, char *buffer, int bufferLength );
-void trap_Args( char *buffer, int bufferLength );
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
-void trap_FS_Read( void *buffer, int len, fileHandle_t f );
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
-void trap_FS_FCloseFile( fileHandle_t f );
-int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
-void trap_SendConsoleCommand( int exec_when, const char *text );
-void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags );
-void trap_Cvar_Update( vmCvar_t *cvar );
-void trap_Cvar_Set( const char *var_name, const char *value );
-int trap_Cvar_VariableIntegerValue( const char *var_name );
-float trap_Cvar_VariableValue( const char *var_name );
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-void trap_LocateGameData( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t, playerState_t *gameClients, int sizeofGameClient );
-void trap_DropClient( int clientNum, const char *reason );
-void trap_SendServerCommand( int clientNum, const char *text );
-void trap_SetConfigstring( int num, const char *string );
-void trap_GetConfigstring( int num, char *buffer, int bufferSize );
-void trap_GetUserinfo( int num, char *buffer, int bufferSize );
-void trap_SetUserinfo( int num, const char *buffer );
-void trap_GetServerinfo( char *buffer, int bufferSize );
-void trap_SetBrushModel( gentity_t *ent, const char *name );
-void trap_Trace( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
-int trap_PointContents( const vec3_t point, int passEntityNum );
-qboolean trap_InPVS( const vec3_t p1, const vec3_t p2 );
-qboolean trap_InPVSIgnorePortals( const vec3_t p1, const vec3_t p2 );
-void trap_AdjustAreaPortalState( gentity_t *ent, qboolean open );
-qboolean trap_AreasConnected( int area1, int area2 );
-void trap_LinkEntity( gentity_t *ent );
-void trap_UnlinkEntity( gentity_t *ent );
-int trap_EntitiesInBox( const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount );
-qboolean trap_EntityContact( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
-int trap_BotAllocateClient( void );
-void trap_BotFreeClient( int clientNum );
-void trap_GetUsercmd( int clientNum, usercmd_t *cmd );
-qboolean trap_GetEntityToken( char *buffer, int bufferSize );
-
-int trap_DebugPolygonCreate(int color, int numPoints, vec3_t *points);
-void trap_DebugPolygonDelete(int id);
-
-int trap_BotLibSetup( void );
-int trap_BotLibShutdown( void );
-int trap_BotLibVarSet(char *var_name, char *value);
-int trap_BotLibVarGet(char *var_name, char *value, int size);
-int trap_BotLibDefine(char *string);
-int trap_BotLibStartFrame(float time);
-int trap_BotLibLoadMap(const char *mapname);
-int trap_BotLibUpdateEntity(int ent, void /* struct bot_updateentity_s */ *bue);
-int trap_BotLibTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3);
-
-int trap_BotGetSnapshotEntity( int clientNum, int sequence );
-int trap_BotGetServerCommand(int clientNum, char *message, int size);
-void trap_BotUserCommand(int client, usercmd_t *ucmd);
-
-int trap_AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas);
-int trap_AAS_AreaInfo( int areanum, void /* struct aas_areainfo_s */ *info );
-void trap_AAS_EntityInfo(int entnum, void /* struct aas_entityinfo_s */ *info);
-
-int trap_AAS_Initialized(void);
-void trap_AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs);
-float trap_AAS_Time(void);
-
-int trap_AAS_PointAreaNum(vec3_t point);
-int trap_AAS_PointReachabilityAreaIndex(vec3_t point);
-int trap_AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas);
-
-int trap_AAS_PointContents(vec3_t point);
-int trap_AAS_NextBSPEntity(int ent);
-int trap_AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size);
-int trap_AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v);
-int trap_AAS_FloatForBSPEpairKey(int ent, char *key, float *value);
-int trap_AAS_IntForBSPEpairKey(int ent, char *key, int *value);
-
-int trap_AAS_AreaReachability(int areanum);
-
-int trap_AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags);
-int trap_AAS_EnableRoutingArea( int areanum, int enable );
-int trap_AAS_PredictRoute(void /*struct aas_predictroute_s*/ *route, int areanum, vec3_t origin,
- int goalareanum, int travelflags, int maxareas, int maxtime,
- int stopevent, int stopcontents, int stoptfl, int stopareanum);
-
-int trap_AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,
- void /*struct aas_altroutegoal_s*/ *altroutegoals, int maxaltroutegoals,
- int type);
-int trap_AAS_Swimming(vec3_t origin);
-int trap_AAS_PredictClientMovement(void /* aas_clientmove_s */ *move, int entnum, vec3_t origin, int presencetype, int onground, vec3_t velocity, vec3_t cmdmove, int cmdframes, int maxframes, float frametime, int stopevent, int stopareanum, int visualize);
-
-
-void trap_EA_Say(int client, char *str);
-void trap_EA_SayTeam(int client, char *str);
-void trap_EA_Command(int client, char *command);
-
-void trap_EA_Action(int client, int action);
-void trap_EA_Gesture(int client);
-void trap_EA_Talk(int client);
-void trap_EA_Attack(int client);
-void trap_EA_Use(int client);
-void trap_EA_Respawn(int client);
-void trap_EA_Crouch(int client);
-void trap_EA_MoveUp(int client);
-void trap_EA_MoveDown(int client);
-void trap_EA_MoveForward(int client);
-void trap_EA_MoveBack(int client);
-void trap_EA_MoveLeft(int client);
-void trap_EA_MoveRight(int client);
-void trap_EA_SelectWeapon(int client, int weapon);
-void trap_EA_Jump(int client);
-void trap_EA_DelayedJump(int client);
-void trap_EA_Move(int client, vec3_t dir, float speed);
-void trap_EA_View(int client, vec3_t viewangles);
-
-void trap_EA_EndRegular(int client, float thinktime);
-void trap_EA_GetInput(int client, float thinktime, void /* struct bot_input_s */ *input);
-void trap_EA_ResetInput(int client);
-
-
-int trap_BotLoadCharacter(char *charfile, float skill);
-void trap_BotFreeCharacter(int character);
-float trap_Characteristic_Float(int character, int index);
-float trap_Characteristic_BFloat(int character, int index, float min, float max);
-int trap_Characteristic_Integer(int character, int index);
-int trap_Characteristic_BInteger(int character, int index, int min, int max);
-void trap_Characteristic_String(int character, int index, char *buf, int size);
-
-int trap_BotAllocChatState(void);
-void trap_BotFreeChatState(int handle);
-void trap_BotQueueConsoleMessage(int chatstate, int type, char *message);
-void trap_BotRemoveConsoleMessage(int chatstate, int handle);
-int trap_BotNextConsoleMessage(int chatstate, void /* struct bot_consolemessage_s */ *cm);
-int trap_BotNumConsoleMessages(int chatstate);
-void trap_BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 );
-int trap_BotNumInitialChats(int chatstate, char *type);
-int trap_BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 );
-int trap_BotChatLength(int chatstate);
-void trap_BotEnterChat(int chatstate, int client, int sendto);
-void trap_BotGetChatMessage(int chatstate, char *buf, int size);
-int trap_StringContains(char *str1, char *str2, int casesensitive);
-int trap_BotFindMatch(char *str, void /* struct bot_match_s */ *match, unsigned long int context);
-void trap_BotMatchVariable(void /* struct bot_match_s */ *match, int variable, char *buf, int size);
-void trap_UnifyWhiteSpaces(char *string);
-void trap_BotReplaceSynonyms(char *string, unsigned long int context);
-int trap_BotLoadChatFile(int chatstate, char *chatfile, char *chatname);
-void trap_BotSetChatGender(int chatstate, int gender);
-void trap_BotSetChatName(int chatstate, char *name, int client);
-void trap_BotResetGoalState(int goalstate);
-void trap_BotRemoveFromAvoidGoals(int goalstate, int number);
-void trap_BotResetAvoidGoals(int goalstate);
-void trap_BotPushGoal(int goalstate, void /* struct bot_goal_s */ *goal);
-void trap_BotPopGoal(int goalstate);
-void trap_BotEmptyGoalStack(int goalstate);
-void trap_BotDumpAvoidGoals(int goalstate);
-void trap_BotDumpGoalStack(int goalstate);
-void trap_BotGoalName(int number, char *name, int size);
-int trap_BotGetTopGoal(int goalstate, void /* struct bot_goal_s */ *goal);
-int trap_BotGetSecondGoal(int goalstate, void /* struct bot_goal_s */ *goal);
-int trap_BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags);
-int trap_BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, void /* struct bot_goal_s */ *ltg, float maxtime);
-int trap_BotTouchingGoal(vec3_t origin, void /* struct bot_goal_s */ *goal);
-int trap_BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, void /* struct bot_goal_s */ *goal);
-int trap_BotGetNextCampSpotGoal(int num, void /* struct bot_goal_s */ *goal);
-int trap_BotGetMapLocationGoal(char *name, void /* struct bot_goal_s */ *goal);
-int trap_BotGetLevelItemGoal(int index, char *classname, void /* struct bot_goal_s */ *goal);
-float trap_BotAvoidGoalTime(int goalstate, int number);
-void trap_BotSetAvoidGoalTime(int goalstate, int number, float avoidtime);
-void trap_BotInitLevelItems(void);
-void trap_BotUpdateEntityItems(void);
-int trap_BotLoadItemWeights(int goalstate, char *filename);
-void trap_BotFreeItemWeights(int goalstate);
-void trap_BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child);
-void trap_BotSaveGoalFuzzyLogic(int goalstate, char *filename);
-void trap_BotMutateGoalFuzzyLogic(int goalstate, float range);
-int trap_BotAllocGoalState(int state);
-void trap_BotFreeGoalState(int handle);
-
-void trap_BotResetMoveState(int movestate);
-void trap_BotMoveToGoal(void /* struct bot_moveresult_s */ *result, int movestate, void /* struct bot_goal_s */ *goal, int travelflags);
-int trap_BotMoveInDirection(int movestate, vec3_t dir, float speed, int type);
-void trap_BotResetAvoidReach(int movestate);
-void trap_BotResetLastAvoidReach(int movestate);
-int trap_BotReachabilityArea(vec3_t origin, int testground);
-int trap_BotMovementViewTarget(int movestate, void /* struct bot_goal_s */ *goal, int travelflags, float lookahead, vec3_t target);
-int trap_BotPredictVisiblePosition(vec3_t origin, int areanum, void /* struct bot_goal_s */ *goal, int travelflags, vec3_t target);
-int trap_BotAllocMoveState(void);
-void trap_BotFreeMoveState(int handle);
-void trap_BotInitMoveState(int handle, void /* struct bot_initmove_s */ *initmove);
-void trap_BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type);
-
-int trap_BotChooseBestFightWeapon(int weaponstate, int *inventory);
-void trap_BotGetWeaponInfo(int weaponstate, int weapon, void /* struct weaponinfo_s */ *weaponinfo);
-int trap_BotLoadWeaponWeights(int weaponstate, char *filename);
-int trap_BotAllocWeaponState(void);
-void trap_BotFreeWeaponState(int weaponstate);
-void trap_BotResetWeaponState(int weaponstate);
-
-int trap_GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child);
-
-void trap_SnapVector( float *v );
-
-//KK-OAX
-//These enable the simplified command handling.
-
-#define CMD_CHEAT 0x0001
-#define CMD_CHEAT_TEAM 0x0002 // is a cheat when used on a team
-#define CMD_MESSAGE 0x0004 // sends message to others (skip when muted)
-#define CMD_TEAM 0x0008 // must be on a team
-#define CMD_NOTEAM 0x0010 // must not be on a team
-#define CMD_RED 0x0020 // must be on the red team (useless right now)
-#define CMD_BLUE 0x0040 // must be on the blue team (useless right now)
-#define CMD_LIVING 0x0080
-#define CMD_INTERMISSION 0x0100 // valid during intermission
-
-
-typedef struct
-{
- char *cmdName;
- int cmdFlags;
- void ( *cmdHandler )( gentity_t *ent );
-} commands_t;
-
-//
-// g_svcmds_ext.c
-// These were added to a seperate file to keep g_svcmds.c navigable.
-void Svcmd_Status_f( void );
-void Svcmd_TeamMessage_f( void );
-void Svcmd_CenterPrint_f( void );
-void Svcmd_BannerPrint_f( void );
-void Svcmd_EjectClient_f( void );
-void Svcmd_DumpUser_f( void );
-void Svcmd_Chat_f( void );
-void Svcmd_ListIP_f( void );
-void Svcmd_MessageWrapper( void );
-
-#include "g_killspree.h"
-#include "g_admin.h"
diff --git a/game/code/game/g_main.c b/game/code/game/g_main.c
deleted file mode 100644
index 7c74289..0000000
--- a/game/code/game/g_main.c
+++ /dev/null
@@ -1,2778 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-#include "g_local.h"
-
-level_locals_t level;
-
-typedef struct {
- vmCvar_t *vmCvar;
- char *cvarName;
- char *defaultString;
- int cvarFlags;
- int modificationCount; // for tracking changes
- qboolean trackChange; // track this variable, and announce if changed
- qboolean teamShader; // track and if changed, update shader state
-} cvarTable_t;
-
-gentity_t g_entities[MAX_GENTITIES];
-gclient_t g_clients[MAX_CLIENTS];
-
-vmCvar_t g_gametype;
-vmCvar_t g_dmflags;
-vmCvar_t g_videoflags;
-vmCvar_t g_elimflags;
-vmCvar_t g_voteflags;
-vmCvar_t g_fraglimit;
-vmCvar_t g_timelimit;
-vmCvar_t g_capturelimit;
-vmCvar_t g_friendlyFire;
-vmCvar_t g_password;
-vmCvar_t g_needpass;
-vmCvar_t g_maxclients;
-vmCvar_t g_maxGameClients;
-vmCvar_t g_dedicated;
-vmCvar_t g_speed;
-vmCvar_t g_gravity;
-vmCvar_t g_cheats;
-vmCvar_t g_knockback;
-vmCvar_t g_quadfactor;
-vmCvar_t g_forcerespawn;
-vmCvar_t g_inactivity;
-vmCvar_t g_debugMove;
-vmCvar_t g_debugDamage;
-vmCvar_t g_debugAlloc;
-vmCvar_t g_weaponRespawn;
-vmCvar_t g_weaponTeamRespawn;
-vmCvar_t g_motd;
-vmCvar_t g_synchronousClients;
-vmCvar_t g_warmup;
-vmCvar_t g_doWarmup;
-vmCvar_t g_restarted;
-vmCvar_t g_logfile;
-vmCvar_t g_logfileSync;
-vmCvar_t g_blood;
-vmCvar_t g_podiumDist;
-vmCvar_t g_podiumDrop;
-vmCvar_t g_allowVote;
-vmCvar_t g_teamAutoJoin;
-vmCvar_t g_teamForceBalance;
-vmCvar_t g_banIPs;
-vmCvar_t g_filterBan;
-vmCvar_t g_smoothClients;
-vmCvar_t pmove_fixed;
-vmCvar_t pmove_msec;
-vmCvar_t pmove_float;
-vmCvar_t g_rankings;
-vmCvar_t g_listEntity;
-vmCvar_t g_obeliskHealth;
-vmCvar_t g_obeliskRegenPeriod;
-vmCvar_t g_obeliskRegenAmount;
-vmCvar_t g_obeliskRespawnDelay;
-vmCvar_t g_cubeTimeout;
-#ifdef MISSIONPACK
-vmCvar_t g_redteam;
-vmCvar_t g_blueteam;
-vmCvar_t g_singlePlayer;
-#endif
-vmCvar_t g_enableDust;
-vmCvar_t g_enableBreath;
-vmCvar_t g_proxMineTimeout;
-vmCvar_t g_music;
-//Following for elimination:
-vmCvar_t g_elimination_selfdamage;
-vmCvar_t g_elimination_startHealth;
-vmCvar_t g_elimination_startArmor;
-vmCvar_t g_elimination_bfg;
-vmCvar_t g_elimination_grapple;
-vmCvar_t g_elimination_roundtime;
-vmCvar_t g_elimination_warmup;
-vmCvar_t g_elimination_activewarmup;
-vmCvar_t g_elimination_allgametypes;
-vmCvar_t g_elimination_machinegun;
-vmCvar_t g_elimination_shotgun;
-vmCvar_t g_elimination_grenade;
-vmCvar_t g_elimination_rocket;
-vmCvar_t g_elimination_railgun;
-vmCvar_t g_elimination_lightning;
-vmCvar_t g_elimination_plasmagun;
-vmCvar_t g_elimination_chain;
-vmCvar_t g_elimination_mine;
-vmCvar_t g_elimination_nail;
-
-vmCvar_t g_elimination_lockspectator;
-
-vmCvar_t g_rockets;
-
-//dmn_clowns suggestions (with my idea of implementing):
-vmCvar_t g_instantgib;
-vmCvar_t g_vampire;
-vmCvar_t g_vampireMaxHealth;
-//Regen
-vmCvar_t g_regen;
-int g_ffa_gt; //Are this a FFA gametype even if gametype is high?
-vmCvar_t g_lms_lives;
-vmCvar_t g_lms_mode;
-vmCvar_t g_elimination_ctf_oneway;
-vmCvar_t g_awardpushing; //The server can decide if players are awarded for pushing people in lave etc.
-vmCvar_t g_persistantpowerups; //Allow missionpack style persistant powerups?
-
-vmCvar_t g_catchup; //Favors the week players
-
-vmCvar_t g_voteNames;
-vmCvar_t g_voteGametypes;
-vmCvar_t g_voteMinTimelimit;
-vmCvar_t g_voteMaxTimelimit;
-vmCvar_t g_voteMinFraglimit;
-vmCvar_t g_voteMaxFraglimit;
-
-vmCvar_t g_humanplayers;
-
-//used for voIP
-vmCvar_t g_redTeamClientNumbers;
-vmCvar_t g_blueTeamClientNumbers;
-
-//unlagged - server options
-vmCvar_t g_delagHitscan;
-vmCvar_t g_truePing;
-vmCvar_t sv_fps;
-vmCvar_t g_lagLightning; //Adds a little lag to the lightninggun to make it less powerfull
-//unlagged - server options
-//KK-OAX
-vmCvar_t g_sprees;
-vmCvar_t g_altExcellent;
-vmCvar_t g_spreeDiv;
-
-//Command/Chat spamming/flooding
-vmCvar_t g_floodMaxDemerits;
-vmCvar_t g_floodMinTime;
-
-//Admin
-vmCvar_t g_admin;
-vmCvar_t g_adminLog;
-vmCvar_t g_adminParseSay;
-vmCvar_t g_adminNameProtect;
-vmCvar_t g_adminTempBan;
-vmCvar_t g_adminMaxBan;
-vmCvar_t g_specChat;
-vmCvar_t g_publicAdminMessages;
-
-vmCvar_t g_maxWarnings;
-vmCvar_t g_warningExpire;
-
-vmCvar_t g_minNameChangePeriod;
-vmCvar_t g_maxNameChanges;
-
-// bk001129 - made static to avoid aliasing
-static cvarTable_t gameCvarTable[] = {
- // don't override the cheat state set by the system
- { &g_cheats, "sv_cheats", "", 0, 0, qfalse },
-
- // noset vars
- { NULL, "gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
- { NULL, "gamedate", __DATE__ , CVAR_ROM, 0, qfalse },
- { &g_restarted, "g_restarted", "0", CVAR_ROM, 0, qfalse },
- { NULL, "sv_mapname", "", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
-
- // latched vars
- { &g_gametype, "g_gametype", "0", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH, 0, qfalse },
-
- { &g_maxclients, "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse },
- { &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse },
-
- // change anytime vars
- { &g_dmflags, "dmflags", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
- { &g_videoflags, "videoflags", "7", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
- { &g_elimflags, "elimflags", "0", CVAR_SERVERINFO, 0, qfalse },
- { &g_voteflags, "voteflags", "0", CVAR_SERVERINFO, 0, qfalse },
- { &g_fraglimit, "fraglimit", "20", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
- { &g_timelimit, "timelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
- { &g_capturelimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
-
- { &g_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO, 0, qfalse },
-
- { &g_friendlyFire, "g_friendlyFire", "0", CVAR_ARCHIVE, 0, qtrue },
-
- { &g_teamAutoJoin, "g_teamAutoJoin", "0", CVAR_ARCHIVE },
- { &g_teamForceBalance, "g_teamForceBalance", "0", CVAR_ARCHIVE },
-
- { &g_warmup, "g_warmup", "20", CVAR_ARCHIVE, 0, qtrue },
- { &g_doWarmup, "g_doWarmup", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
- { &g_logfile, "g_log", "games.log", CVAR_ARCHIVE, 0, qfalse },
- { &g_logfileSync, "g_logsync", "0", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_password, "g_password", "", CVAR_USERINFO, 0, qfalse },
-
- { &g_banIPs, "g_banIPs", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_filterBan, "g_filterBan", "1", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_needpass, "g_needpass", "0", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },
-
- { &g_dedicated, "dedicated", "0", 0, 0, qfalse },
-
- { &g_speed, "g_speed", "320", 0, 0, qtrue },
- { &g_gravity, "g_gravity", "800", 0, 0, qtrue },
- { &g_knockback, "g_knockback", "1000", 0, 0, qtrue },
- { &g_quadfactor, "g_quadfactor", "3", 0, 0, qtrue },
- { &g_weaponRespawn, "g_weaponrespawn", "5", 0, 0, qtrue },
- { &g_weaponTeamRespawn, "g_weaponTeamRespawn", "30", 0, 0, qtrue },
- { &g_forcerespawn, "g_forcerespawn", "20", 0, 0, qtrue },
- { &g_inactivity, "g_inactivity", "0", 0, 0, qtrue },
- { &g_debugMove, "g_debugMove", "0", 0, 0, qfalse },
- { &g_debugDamage, "g_debugDamage", "0", 0, 0, qfalse },
- { &g_debugAlloc, "g_debugAlloc", "0", 0, 0, qfalse },
- { &g_motd, "g_motd", "", 0, 0, qfalse },
- { &g_blood, "com_blood", "1", 0, 0, qfalse },
-
- { &g_podiumDist, "g_podiumDist", "80", 0, 0, qfalse },
- { &g_podiumDrop, "g_podiumDrop", "70", 0, 0, qfalse },
-
- { &g_allowVote, "g_allowVote", "1", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
-
- //new in beta 19
- { &g_voteNames, "g_voteNames", "/map_restart/nextmap/map/g_gametype/kick/clientkick/g_doWarmup/timelimit/fraglimit/shuffle/", CVAR_ARCHIVE, 0, qfalse }, //clientkick g_doWarmup timelimit fraglimit
- { &g_voteGametypes, "g_voteGametypes", "/0/1/3/4/5/6/7/8/9/10/11/12/", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
- { &g_voteMaxTimelimit, "g_voteMaxTimelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
- { &g_voteMinTimelimit, "g_voteMinTimelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
- { &g_voteMaxFraglimit, "g_voteMaxFraglimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
- { &g_voteMinFraglimit, "g_voteMinFraglimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
- //new in beta 19 end
-
- { &g_listEntity, "g_listEntity", "0", 0, 0, qfalse },
-
- { &g_obeliskHealth, "g_obeliskHealth", "2500", 0, 0, qfalse },
- { &g_obeliskRegenPeriod, "g_obeliskRegenPeriod", "1", 0, 0, qfalse },
- { &g_obeliskRegenAmount, "g_obeliskRegenAmount", "15", 0, 0, qfalse },
- { &g_obeliskRespawnDelay, "g_obeliskRespawnDelay", "10", CVAR_SERVERINFO, 0, qfalse },
-
- { &g_cubeTimeout, "g_cubeTimeout", "30", 0, 0, qfalse },
- #ifdef MISSIONPACK
- { &g_redteam, "g_redteam", "Stroggs", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO , 0, qtrue, qtrue },
- { &g_blueteam, "g_blueteam", "Pagans", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO , 0, qtrue, qtrue },
- { &g_singlePlayer, "ui_singlePlayerActive", "", 0, 0, qfalse, qfalse },
- #endif
-
- { &g_enableDust, "g_enableDust", "0", CVAR_SERVERINFO, 0, qtrue, qfalse },
- { &g_enableBreath, "g_enableBreath", "0", CVAR_SERVERINFO, 0, qtrue, qfalse },
- { &g_proxMineTimeout, "g_proxMineTimeout", "20000", 0, 0, qfalse },
-
- { &g_smoothClients, "g_smoothClients", "1", 0, 0, qfalse},
- { &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO | CVAR_ARCHIVE, 0, qfalse},
- { &pmove_msec, "pmove_msec", "11", CVAR_SYSTEMINFO | CVAR_ARCHIVE, 0, qfalse},
-
- { &pmove_float, "pmove_float", "1", CVAR_SYSTEMINFO | CVAR_ARCHIVE, 0, qtrue},
-
-//unlagged - server options
- { &g_delagHitscan, "g_delagHitscan", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qtrue },
- { &g_truePing, "g_truePing", "0", CVAR_ARCHIVE, 0, qtrue },
- // it's CVAR_SYSTEMINFO so the client's sv_fps will be automagically set to its value
- { &sv_fps, "sv_fps", "20", CVAR_SYSTEMINFO | CVAR_ARCHIVE, 0, qfalse },
- { &g_lagLightning, "g_lagLightning", "1", CVAR_ARCHIVE, 0, qtrue },
-//unlagged - server options
-
- { &g_rankings, "g_rankings", "0", 0, 0, qfalse},
- { &g_music, "g_music", "", 0, 0, qfalse},
- //Now for elimination stuff:
- { &g_elimination_selfdamage, "elimination_selfdamage", "0", 0, 0, qtrue },
- { &g_elimination_startHealth, "elimination_startHealth", "200", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
- { &g_elimination_startArmor, "elimination_startArmor", "150", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
- { &g_elimination_bfg, "elimination_bfg", "0", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
- { &g_elimination_grapple, "elimination_grapple", "0", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
- { &g_elimination_roundtime, "elimination_roundtime", "120", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
- { &g_elimination_warmup, "elimination_warmup", "7", CVAR_ARCHIVE | CVAR_NORESTART , 0, qtrue },
- { &g_elimination_activewarmup, "elimination_activewarmup", "5", CVAR_ARCHIVE | CVAR_NORESTART , 0, qtrue },
- { &g_elimination_allgametypes, "g_elimination", "0", CVAR_LATCH | CVAR_NORESTART, 0, qfalse },
-
- { &g_elimination_machinegun, "elimination_machinegun", "500", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
- { &g_elimination_shotgun, "elimination_shotgun", "500", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
- { &g_elimination_grenade, "elimination_grenade", "100", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
- { &g_elimination_rocket, "elimination_rocket", "50", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
- { &g_elimination_railgun, "elimination_railgun", "20", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
- { &g_elimination_lightning, "elimination_lightning", "300", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
- { &g_elimination_plasmagun, "elimination_plasmagun", "200", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
- { &g_elimination_chain, "elimination_chain", "0", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
- { &g_elimination_mine, "elimination_mine", "0", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
- { &g_elimination_nail, "elimination_nail", "0", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
-
- { &g_elimination_ctf_oneway, "elimination_ctf_oneway", "0", CVAR_ARCHIVE| CVAR_NORESTART, 0, qtrue },
-
- { &g_elimination_lockspectator, "elimination_lockspectator", "0", CVAR_NORESTART, 0, qtrue },
-
- { &g_awardpushing, "g_awardpushing", "1", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
-
- //g_persistantpowerups
- #ifdef MISSIONPACK
- { &g_persistantpowerups, "g_runes", "1", CVAR_LATCH, 0, qfalse },
- #else
- { &g_persistantpowerups, "g_runes", "0", CVAR_LATCH|CVAR_ARCHIVE, 0, qfalse },
- #endif
-
-
- //nexuiz style rocket arena
- { &g_rockets, "g_rockets", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_NORESTART, 0, qfalse },
-
- //Instantgib and Vampire thingies
- { &g_instantgib, "g_instantgib", "0", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse },
- { &g_vampire, "g_vampire", "0.0", CVAR_NORESTART, 0, qtrue },
- { &g_regen, "g_regen", "0", CVAR_NORESTART, 0, qtrue },
- { &g_vampireMaxHealth, "g_vampire_max_health", "500", CVAR_NORESTART, 0, qtrue },
- { &g_lms_lives, "g_lms_lives", "1", CVAR_NORESTART, 0, qtrue },
- { &g_lms_mode, "g_lms_mode", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
-
- { &g_catchup, "g_catchup", "0", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue},
-
- { &g_humanplayers, "g_humanplayers", "0", CVAR_ROM | CVAR_NORESTART, 0, qfalse },
-//used for voIP
- { &g_redTeamClientNumbers, "g_redTeamClientNumbers", "0",CVAR_ROM, 0, qfalse },
- { &g_blueTeamClientNumbers, "g_blueTeamClientNumbers", "0",CVAR_ROM, 0, qfalse },
-
- //KK-OAX
- { &g_sprees, "g_sprees", "sprees.dat", 0, 0, qfalse },
- { &g_altExcellent, "g_altExcellent", "0", CVAR_SERVERINFO, 0, qtrue},
- { &g_spreeDiv, "g_spreeDiv", "5", 0, 0, qfalse},
-
- //Used for command/chat flooding
- { &g_floodMaxDemerits, "g_floodMaxDemerits", "5000", CVAR_ARCHIVE, 0, qfalse },
- { &g_floodMinTime, "g_floodMinTime", "2000", CVAR_ARCHIVE, 0, qfalse },
-
- //Admin
- { &g_admin, "g_admin", "admin.dat", CVAR_ARCHIVE, 0, qfalse },
- { &g_adminLog, "g_adminLog", "admin.log", CVAR_ARCHIVE, 0, qfalse },
- { &g_adminParseSay, "g_adminParseSay", "1", CVAR_ARCHIVE, 0, qfalse },
- { &g_adminNameProtect, "g_adminNameProtect", "1", CVAR_ARCHIVE, 0, qfalse },
- { &g_adminTempBan, "g_adminTempBan", "2m", CVAR_ARCHIVE, 0, qfalse },
- { &g_adminMaxBan, "g_adminMaxBan", "2w", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_specChat, "g_specChat", "1", CVAR_ARCHIVE, 0, qfalse },
- { &g_publicAdminMessages, "g_publicAdminMessages", "1", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_maxWarnings, "g_maxWarnings", "3", CVAR_ARCHIVE, 0, qfalse },
- { &g_warningExpire, "g_warningExpire", "3600", CVAR_ARCHIVE, 0, qfalse },
-
- { &g_minNameChangePeriod, "g_minNameChangePeriod", "5", 0, 0, qfalse},
- { &g_maxNameChanges, "g_maxNameChanges", "5", 0, 0, qfalse}
-
-};
-
-// bk001129 - made static to avoid aliasing
-static int gameCvarTableSize = sizeof( gameCvarTable ) / sizeof( gameCvarTable[0] );
-
-
-void G_InitGame( int levelTime, int randomSeed, int restart );
-void G_RunFrame( int levelTime );
-void G_ShutdownGame( int restart );
-void CheckExitRules( void );
-
-
-/*
-================
-vmMain
-
-This is the only way control passes into the module.
-This must be the very first function compiled into the .q3vm file
-================
-*/
-intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
- switch ( command ) {
- case GAME_INIT:
- G_InitGame( arg0, arg1, arg2 );
- return 0;
- case GAME_SHUTDOWN:
- G_ShutdownGame( arg0 );
- return 0;
- case GAME_CLIENT_CONNECT:
- return (intptr_t)ClientConnect( arg0, arg1, arg2 );
- case GAME_CLIENT_THINK:
- ClientThink( arg0 );
- return 0;
- case GAME_CLIENT_USERINFO_CHANGED:
- ClientUserinfoChanged( arg0 );
- return 0;
- case GAME_CLIENT_DISCONNECT:
- ClientDisconnect( arg0 );
- return 0;
- case GAME_CLIENT_BEGIN:
- ClientBegin( arg0 );
- return 0;
- case GAME_CLIENT_COMMAND:
- ClientCommand( arg0 );
- return 0;
- case GAME_RUN_FRAME:
- G_RunFrame( arg0 );
- return 0;
- case GAME_CONSOLE_COMMAND:
- return ConsoleCommand();
- case BOTAI_START_FRAME:
- return BotAIStartFrame( arg0 );
- }
-
- return -1;
-}
-
-
-void QDECL G_Printf( const char *fmt, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, fmt);
- Q_vsnprintf (text, sizeof(text), fmt, argptr);
- va_end (argptr);
-
- trap_Printf( text );
-}
-
-void QDECL G_Error( const char *fmt, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, fmt);
- Q_vsnprintf (text, sizeof(text), fmt, argptr);
- va_end (argptr);
-
- trap_Error( text );
-}
-
-/*
-================
-G_FindTeams
-
-Chain together all entities with a matching team field.
-Entity teams are used for item groups and multi-entity mover groups.
-
-All but the first will have the FL_TEAMSLAVE flag set and teammaster field set
-All but the last will have the teamchain field set to the next one
-================
-*/
-void G_FindTeams( void ) {
- gentity_t *e, *e2;
- int i, j;
- int c, c2;
-
- c = 0;
- c2 = 0;
- for ( i=1, e=g_entities+i ; i < level.num_entities ; i++,e++ ){
- if (!e->inuse)
- continue;
- if (!e->team)
- continue;
- if (e->flags & FL_TEAMSLAVE)
- continue;
- e->teammaster = e;
- c++;
- c2++;
- for (j=i+1, e2=e+1 ; j < level.num_entities ; j++,e2++)
- {
- if (!e2->inuse)
- continue;
- if (!e2->team)
- continue;
- if (e2->flags & FL_TEAMSLAVE)
- continue;
- if (!strcmp(e->team, e2->team))
- {
- c2++;
- e2->teamchain = e->teamchain;
- e->teamchain = e2;
- e2->teammaster = e;
- e2->flags |= FL_TEAMSLAVE;
-
- // make sure that targets only point at the master
- if ( e2->targetname ) {
- e->targetname = e2->targetname;
- e2->targetname = NULL;
- }
- }
- }
- }
- G_Printf ("%i teams with %i entities\n", c, c2);
-}
-
-void G_RemapTeamShaders( void ) {
-#ifdef MISSIONPACK
- char string[1024];
- float f = level.time * 0.001;
- Com_sprintf( string, sizeof(string), "team_icon/%s_red", g_redteam.string );
- AddRemap("textures/ctf2/redteam01", string, f);
- AddRemap("textures/ctf2/redteam02", string, f);
- Com_sprintf( string, sizeof(string), "team_icon/%s_blue", g_blueteam.string );
- AddRemap("textures/ctf2/blueteam01", string, f);
- AddRemap("textures/ctf2/blueteam02", string, f);
- trap_SetConfigstring(CS_SHADERSTATE, BuildShaderStateConfig());
-#endif
-}
-
-
-/*
-=================
-G_RegisterCvars
-=================
-*/
-void G_RegisterCvars( void ) {
- int i;
- cvarTable_t *cv;
- qboolean remapped = qfalse;
-
- for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) {
- trap_Cvar_Register( cv->vmCvar, cv->cvarName,
- cv->defaultString, cv->cvarFlags );
- if ( cv->vmCvar )
- cv->modificationCount = cv->vmCvar->modificationCount;
-
- if (cv->teamShader) {
- remapped = qtrue;
- }
- }
-
- if (remapped) {
- G_RemapTeamShaders();
- }
-
- // check some things
- if ( g_gametype.integer < 0 || g_gametype.integer >= GT_MAX_GAME_TYPE ) {
- G_Printf( "g_gametype %i is out of range, defaulting to 0\n", g_gametype.integer );
- trap_Cvar_Set( "g_gametype", "0" );
- }
-
- //set FFA status for high gametypes:
- if ( g_gametype.integer == GT_LMS ) {
- g_ffa_gt = 1; //Last Man standig is a FFA gametype
- } else {
- g_ffa_gt = 0; //If >GT_CTF use bases
- }
-
- level.warmupModificationCount = g_warmup.modificationCount;
-}
-
-/*
-=================
-G_UpdateCvars
-=================
-*/
-void G_UpdateCvars( void ) {
- int i;
- cvarTable_t *cv;
- qboolean remapped = qfalse;
-
- for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) {
- if ( cv->vmCvar ) {
- trap_Cvar_Update( cv->vmCvar );
-
- if ( cv->modificationCount != cv->vmCvar->modificationCount ) {
- cv->modificationCount = cv->vmCvar->modificationCount;
-
- if ( cv->trackChange ) {
- trap_SendServerCommand( -1, va("print \"Server: %s changed to %s\n\"",
- cv->cvarName, cv->vmCvar->string ) );
- }
-
- if ( cv->vmCvar == &g_voteNames ) {
- //Set vote flags
- int voteflags=0;
- if( allowedVote("map_restart") )
- voteflags|=VF_map_restart;
-
- if( allowedVote("map") )
- voteflags|=VF_map;
-
- if( allowedVote("clientkick") )
- voteflags|=VF_clientkick;
-
- if( allowedVote("shuffle") )
- voteflags|=VF_shuffle;
-
- if( allowedVote("nextmap") )
- voteflags|=VF_nextmap;
-
- if( allowedVote("g_gametype") )
- voteflags|=VF_g_gametype;
-
- if( allowedVote("g_doWarmup") )
- voteflags|=VF_g_doWarmup;
-
- if( allowedVote("timelimit") )
- voteflags|=VF_timelimit;
-
- if( allowedVote("fraglimit") )
- voteflags|=VF_fraglimit;
-
- if( allowedVote("custom") )
- voteflags|=VF_custom;
-
- trap_Cvar_Set("voteflags",va("%i",voteflags));
- }
-
- if (cv->teamShader) {
- remapped = qtrue;
- }
- }
- }
- }
-
- if (remapped) {
- G_RemapTeamShaders();
- }
-}
-
-/*
-============
-G_InitGame
-
-============
-*/
-void G_InitGame( int levelTime, int randomSeed, int restart ) {
- int i;
-
-
- G_Printf ("------- Game Initialization -------\n");
- G_Printf ("gamename: %s\n", GAMEVERSION);
- G_Printf ("gamedate: %s\n", __DATE__);
-
- srand( randomSeed );
-
- G_RegisterCvars();
-
- //disable unwanted cvars
- if( g_gametype.integer == GT_SINGLE_PLAYER )
- {
- g_instantgib.integer = 0;
- g_rockets.integer = 0;
- g_vampire.value = 0.0f;
- }
-
- G_ProcessIPBans();
-
- //KK-OAX Changed to Tremulous's BG_InitMemory
- BG_InitMemory();
-
- // set some level globals
- memset( &level, 0, sizeof( level ) );
-
- level.time = levelTime;
- level.startTime = levelTime;
-
- level.snd_fry = G_SoundIndex("sound/player/fry.wav"); // FIXME standing in lava / slime
-
- if ( g_gametype.integer != GT_SINGLE_PLAYER && g_logfile.string[0] ) {
- if ( g_logfileSync.integer ) {
- trap_FS_FOpenFile( g_logfile.string, &level.logFile, FS_APPEND_SYNC );
- } else {
- trap_FS_FOpenFile( g_logfile.string, &level.logFile, FS_APPEND );
- }
- if ( !level.logFile ) {
- G_Printf( "WARNING: Couldn't open logfile: %s\n", g_logfile.string );
- } else {
- char serverinfo[MAX_INFO_STRING];
-
- trap_GetServerinfo( serverinfo, sizeof( serverinfo ) );
-
- G_LogPrintf("------------------------------------------------------------\n" );
- G_LogPrintf("InitGame: %s\n", serverinfo );
- G_LogPrintf("Info: ServerInfo length: %d of %d\n", strlen(serverinfo), MAX_INFO_STRING );
- }
- } else {
- G_Printf( "Not logging to disk.\n" );
- }
-
- //Parse the custom vote names:
- VoteParseCustomVotes();
-
- G_InitWorldSession();
-
- //KK-OAX Get Admin Configuration
- G_admin_readconfig( NULL, 0 );
- //Let's Load up any killing sprees/multikills
- G_ReadAltKillSettings( NULL, 0 );
-
- // initialize all entities for this game
- memset( g_entities, 0, MAX_GENTITIES * sizeof(g_entities[0]) );
- level.gentities = g_entities;
-
- // initialize all clients for this game
- level.maxclients = g_maxclients.integer;
- memset( g_clients, 0, MAX_CLIENTS * sizeof(g_clients[0]) );
- level.clients = g_clients;
-
- // set client fields on player ents
- for ( i=0 ; i<level.maxclients ; i++ ) {
- g_entities[i].client = level.clients + i;
- }
-
- // always leave room for the max number of clients,
- // even if they aren't all used, so numbers inside that
- // range are NEVER anything but clients
- level.num_entities = MAX_CLIENTS;
-
- // let the server system know where the entites are
- trap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ),
- &level.clients[0].ps, sizeof( level.clients[0] ) );
-
- // reserve some spots for dead player bodies
- InitBodyQue();
-
- ClearRegisteredItems();
-
- // parse the key/value pairs and spawn gentities
- G_SpawnEntitiesFromString();
-
- // general initialization
- G_FindTeams();
-
- // make sure we have flags for CTF, etc
- if( g_gametype.integer >= GT_TEAM && (g_ffa_gt!=1)) {
- G_CheckTeamItems();
- }
-
- SaveRegisteredItems();
-
- G_Printf ("-----------------------------------\n");
-
- if( g_gametype.integer == GT_SINGLE_PLAYER || trap_Cvar_VariableIntegerValue( "com_buildScript" ) ) {
- G_ModelIndex( SP_PODIUM_MODEL );
- G_SoundIndex( "sound/player/gurp1.wav" );
- G_SoundIndex( "sound/player/gurp2.wav" );
- }
-
- if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
- BotAISetup( restart );
- BotAILoadMap( restart );
- G_InitBots( restart );
- }
-
- G_RemapTeamShaders();
-
- //elimination:
- level.roundNumber = 1;
- level.roundNumberStarted = 0;
- level.roundStartTime = level.time+g_elimination_warmup.integer*1000;
- level.roundRespawned = qfalse;
- level.eliminationSides = rand()%2; //0 or 1
-
- //Challenges:
- level.teamSize = 0;
- level.hadBots = qfalse;
-
- if(g_gametype.integer == GT_DOUBLE_D)
- Team_SpawnDoubleDominationPoints();
-
- if(g_gametype.integer == GT_DOMINATION ){
- level.dom_scoreGiven = 0;
- for(i=0;i<MAX_DOMINATION_POINTS;i++)
- level.pointStatusDom[i] = TEAM_NONE;
- level.domination_points_count = 0; //make sure its not too big
- }
-
- PlayerStoreInit();
-
- //Set vote flags
- {
- int voteflags=0;
- if( allowedVote("map_restart") )
- voteflags|=VF_map_restart;
-
- if( allowedVote("map") )
- voteflags|=VF_map;
-
- if( allowedVote("clientkick") )
- voteflags|=VF_clientkick;
-
- if( allowedVote("shuffle") )
- voteflags|=VF_shuffle;
-
- if( allowedVote("nextmap") )
- voteflags|=VF_nextmap;
-
- if( allowedVote("g_gametype") )
- voteflags|=VF_g_gametype;
-
- if( allowedVote("g_doWarmup") )
- voteflags|=VF_g_doWarmup;
-
- if( allowedVote("timelimit") )
- voteflags|=VF_timelimit;
-
- if( allowedVote("fraglimit") )
- voteflags|=VF_fraglimit;
-
- if( allowedVote("custom") )
- voteflags|=VF_custom;
-
- trap_Cvar_Set("voteflags",va("%i",voteflags));
- }
-}
-
-
-
-/*
-=================
-G_ShutdownGame
-=================
-*/
-void G_ShutdownGame( int restart ) {
- G_Printf ("==== ShutdownGame ====\n");
-
- if ( level.logFile ) {
- G_LogPrintf("ShutdownGame:\n" );
- G_LogPrintf("------------------------------------------------------------\n" );
- trap_FS_FCloseFile( level.logFile );
- }
-
- // write all the client session data so we can get it back
- G_WriteSessionData();
-
- //KK-OAX Admin Cleanup
- G_admin_cleanup( );
- G_admin_namelog_cleanup( );
-
- if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
- BotAIShutdown( restart );
- }
-}
-
-
-
-//===================================================================
-
-void QDECL Com_Error ( int level, const char *error, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, error);
- Q_vsnprintf (text, sizeof(text), error, argptr);
- va_end (argptr);
-
- G_Error( "%s", text);
-}
-
-void QDECL Com_Printf( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- Q_vsnprintf (text, sizeof(text), msg, argptr);
- va_end (argptr);
-
- G_Printf ("%s", text);
-}
-
-/*
-========================================================================
-
-PLAYER COUNTING / SCORE SORTING
-
-========================================================================
-*/
-
-/*
-=============
-AddTournamentPlayer
-
-If there are less than two tournament players, put a
-spectator in the game and restart
-=============
-*/
-void AddTournamentPlayer( void ) {
- int i;
- gclient_t *client;
- gclient_t *nextInLine;
-
- if ( level.numPlayingClients >= 2 ) {
- return;
- }
-
- // never change during intermission
- if ( level.intermissiontime ) {
- return;
- }
-
- nextInLine = NULL;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- client = &level.clients[i];
- if ( client->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
- continue;
- }
- // never select the dedicated follow or scoreboard clients
- if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ||
- client->sess.spectatorClient < 0 ) {
- continue;
- }
-
- if ( !nextInLine || client->sess.spectatorTime < nextInLine->sess.spectatorTime ) {
- nextInLine = client;
- }
- }
-
- if ( !nextInLine ) {
- return;
- }
-
- level.warmupTime = -1;
-
- // set them to free-for-all team
- SetTeam( &g_entities[ nextInLine - level.clients ], "f" );
-}
-
-/*
-=======================
-RemoveTournamentLoser
-
-Make the loser a spectator at the back of the line
-=======================
-*/
-void RemoveTournamentLoser( void ) {
- int clientNum;
-
- if ( level.numPlayingClients != 2 ) {
- return;
- }
-
- clientNum = level.sortedClients[1];
-
- if ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) {
- return;
- }
-
- // make them a spectator
- SetTeam( &g_entities[ clientNum ], "s" );
-}
-
-/*
-=======================
-RemoveTournamentWinner
-=======================
-*/
-void RemoveTournamentWinner( void ) {
- int clientNum;
-
- if ( level.numPlayingClients != 2 ) {
- return;
- }
-
- clientNum = level.sortedClients[0];
-
- if ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) {
- return;
- }
-
- // make them a spectator
- SetTeam( &g_entities[ clientNum ], "s" );
-}
-
-/*
-=======================
-AdjustTournamentScores
-=======================
-*/
-void AdjustTournamentScores( void ) {
- int clientNum;
-
- clientNum = level.sortedClients[0];
- if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {
- level.clients[ clientNum ].sess.wins++;
- ClientUserinfoChanged( clientNum );
- }
-
- clientNum = level.sortedClients[1];
- if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {
- level.clients[ clientNum ].sess.losses++;
- ClientUserinfoChanged( clientNum );
- }
-
-}
-
-/*
-=============
-SortRanks
-
-=============
-*/
-int QDECL SortRanks( const void *a, const void *b ) {
- gclient_t *ca, *cb;
-
- ca = &level.clients[*(int *)a];
- cb = &level.clients[*(int *)b];
-
- // sort special clients last
- if ( ca->sess.spectatorState == SPECTATOR_SCOREBOARD || ca->sess.spectatorClient < 0 ) {
- return 1;
- }
- if ( cb->sess.spectatorState == SPECTATOR_SCOREBOARD || cb->sess.spectatorClient < 0 ) {
- return -1;
- }
-
- // then connecting clients
- if ( ca->pers.connected == CON_CONNECTING ) {
- return 1;
- }
- if ( cb->pers.connected == CON_CONNECTING ) {
- return -1;
- }
-
-
- // then spectators
- if ( ca->sess.sessionTeam == TEAM_SPECTATOR && cb->sess.sessionTeam == TEAM_SPECTATOR ) {
- if ( ca->sess.spectatorTime < cb->sess.spectatorTime ) {
- return -1;
- }
- if ( ca->sess.spectatorTime > cb->sess.spectatorTime ) {
- return 1;
- }
- return 0;
- }
- if ( ca->sess.sessionTeam == TEAM_SPECTATOR ) {
- return 1;
- }
- if ( cb->sess.sessionTeam == TEAM_SPECTATOR ) {
- return -1;
- }
-
- //In elimination and CTF elimination, sort dead players last
- if((g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION)
- && level.roundNumber==level.roundNumberStarted && (ca->isEliminated != cb->isEliminated)) {
- if( ca->isEliminated )
- return 1;
- if( cb->isEliminated )
- return -1;
- }
-
- // then sort by score
- if ( ca->ps.persistant[PERS_SCORE]
- > cb->ps.persistant[PERS_SCORE] ) {
- return -1;
- }
- if ( ca->ps.persistant[PERS_SCORE]
- < cb->ps.persistant[PERS_SCORE] ) {
- return 1;
- }
- return 0;
-}
-
-/*
-============
-CalculateRanks
-
-Recalculates the score ranks of all players
-This will be called on every client connect, begin, disconnect, death,
-and team change.
-============
-*/
-void CalculateRanks( void ) {
- int i;
- int rank;
- int score;
- int newScore;
- int humanplayers;
- gclient_t *cl;
-
- level.follow1 = -1;
- level.follow2 = -1;
- level.numConnectedClients = 0;
- level.numNonSpectatorClients = 0;
- level.numPlayingClients = 0;
- humanplayers = 0; // don't count bots
- for ( i = 0; i < TEAM_NUM_TEAMS; i++ ) {
- level.numteamVotingClients[i] = 0;
- }
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].pers.connected != CON_DISCONNECTED ) {
- level.sortedClients[level.numConnectedClients] = i;
- level.numConnectedClients++;
-
- //We just set humanplayers to 0 during intermission
- if ( !level.intermissiontime && level.clients[i].pers.connected == CON_CONNECTED && !(g_entities[i].r.svFlags & SVF_BOT) ) {
- humanplayers++;
- }
-
- if ( level.clients[i].sess.sessionTeam != TEAM_SPECTATOR ) {
- level.numNonSpectatorClients++;
- // decide if this should be auto-followed
- if ( level.clients[i].pers.connected == CON_CONNECTED ) {
- level.numPlayingClients++;
- if ( !(g_entities[i].r.svFlags & SVF_BOT) ) {
- if ( level.clients[i].sess.sessionTeam == TEAM_RED )
- level.numteamVotingClients[0]++;
- else if ( level.clients[i].sess.sessionTeam == TEAM_BLUE )
- level.numteamVotingClients[1]++;
- }
- if ( level.follow1 == -1 ) {
- level.follow1 = i;
- } else if ( level.follow2 == -1 ) {
- level.follow2 = i;
- }
- }
- }
- }
- }
-
- qsort( level.sortedClients, level.numConnectedClients,
- sizeof(level.sortedClients[0]), SortRanks );
-
- // set the rank value for all clients that are connected and not spectators
- if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
- // in team games, rank is just the order of the teams, 0=red, 1=blue, 2=tied
- for ( i = 0; i < level.numConnectedClients; i++ ) {
- cl = &level.clients[ level.sortedClients[i] ];
- if ( level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE] ) {
- cl->ps.persistant[PERS_RANK] = 2;
- } else if ( level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE] ) {
- cl->ps.persistant[PERS_RANK] = 0;
- } else {
- cl->ps.persistant[PERS_RANK] = 1;
- }
- }
- } else {
- rank = -1;
- score = 0;
- for ( i = 0; i < level.numPlayingClients; i++ ) {
- cl = &level.clients[ level.sortedClients[i] ];
- newScore = cl->ps.persistant[PERS_SCORE];
- if ( i == 0 || newScore != score ) {
- rank = i;
- // assume we aren't tied until the next client is checked
- level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank;
- } else {
- // we are tied with the previous client
- level.clients[ level.sortedClients[i-1] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
- level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
- }
- score = newScore;
- if ( g_gametype.integer == GT_SINGLE_PLAYER && level.numPlayingClients == 1 ) {
- level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
- }
- }
- }
-
- // set the CS_SCORES1/2 configstrings, which will be visible to everyone
- if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
- trap_SetConfigstring( CS_SCORES1, va("%i", level.teamScores[TEAM_RED] ) );
- trap_SetConfigstring( CS_SCORES2, va("%i", level.teamScores[TEAM_BLUE] ) );
- } else {
- if ( level.numConnectedClients == 0 ) {
- trap_SetConfigstring( CS_SCORES1, va("%i", SCORE_NOT_PRESENT) );
- trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) );
- } else if ( level.numConnectedClients == 1 ) {
- trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );
- trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) );
- } else {
- trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );
- trap_SetConfigstring( CS_SCORES2, va("%i", level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE] ) );
- }
- }
-
- // see if it is time to end the level
- CheckExitRules();
-
- // if we are at the intermission, send the new info to everyone
- if ( level.intermissiontime ) {
- SendScoreboardMessageToAllClients();
- }
-
- if(g_humanplayers.integer != humanplayers) //Presume all spectators are humans!
- trap_Cvar_Set( "g_humanplayers", va("%i", humanplayers) );
-}
-
-
-/*
-========================================================================
-
-MAP CHANGING
-
-========================================================================
-*/
-
-/*
-========================
-SendScoreboardMessageToAllClients
-
-Do this at BeginIntermission time and whenever ranks are recalculated
-due to enters/exits/forced team changes
-========================
-*/
-void SendScoreboardMessageToAllClients( void ) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
- DeathmatchScoreboardMessage( g_entities + i );
- EliminationMessage( g_entities + i );
- }
- }
-}
-
-/*
-========================
-SendElimiantionMessageToAllClients
-
-Used to send information important to Elimination
-========================
-*/
-void SendEliminationMessageToAllClients( void ) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
- EliminationMessage( g_entities + i );
- }
- }
-}
-
-/*
-========================
-SendDDtimetakenMessageToAllClients
-
-Do this if a team just started dominating.
-========================
-*/
-void SendDDtimetakenMessageToAllClients( void ) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
- DoubleDominationScoreTimeMessage( g_entities + i );
- }
- }
-}
-
-/*
-========================
-SendAttackingTeamMessageToAllClients
-
-Used for CTF Elimination oneway
-========================
-*/
-void SendAttackingTeamMessageToAllClients( void ) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
- AttackingTeamMessage( g_entities + i );
- }
- }
-}
-
-/*
-========================
-SendDominationPointsStatusMessageToAllClients
-
-Used for Standard domination
-========================
-*/
-void SendDominationPointsStatusMessageToAllClients( void ) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
- DominationPointStatusMessage( g_entities + i );
- }
- }
-}
-/*
-========================
-SendYourTeamMessageToTeam
-
-Tell all players on a given team who there allies are. Used for VoIP
-========================
-*/
-void SendYourTeamMessageToTeam( team_t team ) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[ i ].pers.connected == CON_CONNECTED && level.clients[ i ].sess.sessionTeam == team ) {
- YourTeamMessage( g_entities + i );
- }
- }
-}
-
-
-/*
-========================
-MoveClientToIntermission
-
-When the intermission starts, this will be called for all players.
-If a new client connects, this will be called after the spawn function.
-========================
-*/
-void MoveClientToIntermission( gentity_t *ent ) {
- // take out of follow mode if needed
- if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {
- StopFollowing( ent );
- }
-
-
- // move to the spot
- VectorCopy( level.intermission_origin, ent->s.origin );
- VectorCopy( level.intermission_origin, ent->client->ps.origin );
- VectorCopy (level.intermission_angle, ent->client->ps.viewangles);
- ent->client->ps.pm_type = PM_INTERMISSION;
-
- // clean up powerup info
- memset( ent->client->ps.powerups, 0, sizeof(ent->client->ps.powerups) );
-
- ent->client->ps.eFlags = 0;
- ent->s.eFlags = 0;
- ent->s.eType = ET_GENERAL;
- ent->s.modelindex = 0;
- ent->s.loopSound = 0;
- ent->s.event = 0;
- ent->r.contents = 0;
-}
-
-/*
-==================
-FindIntermissionPoint
-
-This is also used for spectator spawns
-==================
-*/
-void FindIntermissionPoint( void ) {
- gentity_t *ent, *target;
- vec3_t dir;
-
- // find the intermission spot
- ent = G_Find (NULL, FOFS(classname), "info_player_intermission");
- if ( !ent ) { // the map creator forgot to put in an intermission point...
- SelectSpawnPoint ( vec3_origin, level.intermission_origin, level.intermission_angle );
- } else {
- VectorCopy (ent->s.origin, level.intermission_origin);
- VectorCopy (ent->s.angles, level.intermission_angle);
- // if it has a target, look towards it
- if ( ent->target ) {
- target = G_PickTarget( ent->target );
- if ( target ) {
- VectorSubtract( target->s.origin, level.intermission_origin, dir );
- vectoangles( dir, level.intermission_angle );
- }
- }
- }
-
-}
-
-/*
-==================
-BeginIntermission
-==================
-*/
-void BeginIntermission( void ) {
- int i;
- gentity_t *client;
-
- if ( level.intermissiontime ) {
- return; // already active
- }
-
- // if in tournement mode, change the wins / losses
- if ( g_gametype.integer == GT_TOURNAMENT ) {
- AdjustTournamentScores();
- }
-
- level.intermissiontime = level.time;
- FindIntermissionPoint();
-
-#ifdef MISSIONPACK
- if (g_singlePlayer.integer) {
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- UpdateTournamentInfo();
- }
-#else
- // if single player game
- if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
- UpdateTournamentInfo();
- SpawnModelsOnVictoryPads();
- }
-#endif
-
- // move all clients to the intermission point
- for (i=0 ; i< level.maxclients ; i++) {
- client = g_entities + i;
- if (!client->inuse)
- continue;
- // respawn if dead
- if (client->health <= 0) {
- respawn(client);
- }
- MoveClientToIntermission( client );
- }
-
- // send the current scoring to all clients
- SendScoreboardMessageToAllClients();
-
-}
-
-
-/*
-=============
-ExitLevel
-
-When the intermission has been exited, the server is either killed
-or moved to a new level based on the "nextmap" cvar
-
-=============
-*/
-void ExitLevel (void) {
- int i;
- gclient_t *cl;
- char nextmap[MAX_STRING_CHARS];
- char d1[MAX_STRING_CHARS];
-
- //bot interbreeding
- BotInterbreedEndMatch();
-
- // if we are running a tournement map, kick the loser to spectator status,
- // which will automatically grab the next spectator and restart
- if ( g_gametype.integer == GT_TOURNAMENT ) {
- if ( !level.restarted ) {
- RemoveTournamentLoser();
- trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
- level.restarted = qtrue;
- level.changemap = NULL;
- level.intermissiontime = 0;
- }
- return;
- }
-
- trap_Cvar_VariableStringBuffer( "nextmap", nextmap, sizeof(nextmap) );
- trap_Cvar_VariableStringBuffer( "d1", d1, sizeof(d1) );
-
- if( !Q_stricmp( nextmap, "map_restart 0" ) && Q_stricmp( d1, "" ) ) {
- trap_Cvar_Set( "nextmap", "vstr d2" );
- trap_SendConsoleCommand( EXEC_APPEND, "vstr d1\n" );
- } else {
- trap_SendConsoleCommand( EXEC_APPEND, "vstr nextmap\n" );
- }
-
- level.changemap = NULL;
- level.intermissiontime = 0;
-
- // reset all the scores so we don't enter the intermission again
- level.teamScores[TEAM_RED] = 0;
- level.teamScores[TEAM_BLUE] = 0;
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- cl->ps.persistant[PERS_SCORE] = 0;
- }
-
- // we need to do this here before chaning to CON_CONNECTING
- G_WriteSessionData();
-
- // change all client states to connecting, so the early players into the
- // next level will know the others aren't done reconnecting
- for (i=0 ; i< g_maxclients.integer ; i++) {
- if ( level.clients[i].pers.connected == CON_CONNECTED ) {
- level.clients[i].pers.connected = CON_CONNECTING;
- }
- }
-
-}
-
-/*
-=================
-G_LogPrintf
-
-Print to the logfile with a time stamp if it is open
-=================
-*/
-void QDECL G_LogPrintf( const char *fmt, ... ) {
- va_list argptr;
- char string[1024];
- int min, tens, sec;
-
- sec = level.time / 1000;
-
- min = sec / 60;
- sec -= min * 60;
- tens = sec / 10;
- sec -= tens * 10;
-
- Com_sprintf( string, sizeof(string), "%3i:%i%i ", min, tens, sec );
-
- va_start( argptr, fmt );
- Q_vsnprintf(string + 7, sizeof(string) - 7, fmt, argptr);
- va_end( argptr );
-
- if ( g_dedicated.integer ) {
- G_Printf( "%s", string + 7 );
- }
-
- if ( !level.logFile ) {
- return;
- }
-
- trap_FS_Write( string, strlen( string ), level.logFile );
-}
-
-/*
-================
-LogExit
-
-Append information about this game to the log file
-================
-*/
-void LogExit( const char *string ) {
- int i, numSorted;
- gclient_t *cl;
- qboolean won = qtrue;
- G_LogPrintf( "Exit: %s\n", string );
-
- level.intermissionQueued = level.time;
-
- // this will keep the clients from playing any voice sounds
- // that will get cut off when the queued intermission starts
- trap_SetConfigstring( CS_INTERMISSION, "1" );
-
- // don't send more than 32 scores (FIXME?)
- numSorted = level.numConnectedClients;
- if ( numSorted > 32 ) {
- numSorted = 32;
- }
-
- if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
- G_LogPrintf( "red:%i blue:%i\n",
- level.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE] );
- }
-
- for (i=0 ; i < numSorted ; i++) {
- int ping;
-
- cl = &level.clients[level.sortedClients[i]];
-
- if ( cl->sess.sessionTeam == TEAM_SPECTATOR ) {
- continue;
- }
- if ( cl->pers.connected == CON_CONNECTING ) {
- continue;
- }
-
- ping = cl->ps.ping < 999 ? cl->ps.ping : 999;
-
- G_LogPrintf( "score: %i ping: %i client: %i %s\n", cl->ps.persistant[PERS_SCORE], ping, level.sortedClients[i], cl->pers.netname );
-#ifdef MISSIONPACK
- if (g_singlePlayer.integer && g_gametype.integer == GT_TOURNAMENT) {
- if (g_entities[cl - level.clients].r.svFlags & SVF_BOT && cl->ps.persistant[PERS_RANK] == 0) {
- won = qfalse;
- }
- }
-#endif
-
- }
-
-#ifdef MISSIONPACK
- if (g_singlePlayer.integer) {
- if (g_gametype.integer >= GT_CTF && g_ffa_gt==0) {
- won = level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE];
- }
- trap_SendConsoleCommand( EXEC_APPEND, (won) ? "spWin\n" : "spLose\n" );
- }
-#endif
-
-
-}
-
-
-/*
-=================
-CheckIntermissionExit
-
-The level will stay at the intermission for a minimum of 5 seconds
-If all players wish to continue, the level will then exit.
-If one or more players have not acknowledged the continue, the game will
-wait 10 seconds before going on.
-=================
-*/
-void CheckIntermissionExit( void ) {
- int ready, notReady, playerCount;
- int i;
- gclient_t *cl;
- int readyMask;
-
- if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
- return;
- }
-
- // see which players are ready
- ready = 0;
- notReady = 0;
- readyMask = 0;
- playerCount = 0;
- for (i=0 ; i< g_maxclients.integer ; i++) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT ) {
- continue;
- }
-
- playerCount++;
- if ( cl->readyToExit ) {
- ready++;
- if ( i < 16 ) {
- readyMask |= 1 << i;
- }
- } else {
- notReady++;
- }
- }
-
- // copy the readyMask to each player's stats so
- // it can be displayed on the scoreboard
- for (i=0 ; i< g_maxclients.integer ; i++) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- cl->ps.stats[STAT_CLIENTS_READY] = readyMask;
- }
-
- // never exit in less than five seconds
- if ( level.time < level.intermissiontime + 5000 ) {
- return;
- }
-
- // only test ready status when there are real players present
- if ( playerCount > 0 ) {
- // if nobody wants to go, clear timer
- if ( !ready ) {
- level.readyToExit = qfalse;
- return;
- }
-
- // if everyone wants to go, go now
- if ( !notReady ) {
- ExitLevel();
- return;
- }
- }
-
- // the first person to ready starts the ten second timeout
- if ( !level.readyToExit ) {
- level.readyToExit = qtrue;
- level.exitTime = level.time;
- }
-
- // if we have waited ten seconds since at least one player
- // wanted to exit, go ahead
- if ( level.time < level.exitTime + 10000 ) {
- return;
- }
-
- ExitLevel();
-}
-
-/*
-=============
-ScoreIsTied
-=============
-*/
-qboolean ScoreIsTied( void ) {
- int a, b;
-
- if ( level.numPlayingClients < 2 ) {
- return qfalse;
- }
-
- //Sago: In Elimination and Oneway Flag Capture teams must win by two points.
- if ( g_gametype.integer == GT_ELIMINATION ||
- (g_gametype.integer == GT_CTF_ELIMINATION && g_elimination_ctf_oneway.integer)) {
- return (level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE] ||
- level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE]+1 ||
- level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE]-1);
- }
-
- if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
- return level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE];
- }
-
- a = level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE];
- b = level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE];
-
- return a == b;
-}
-
-/*
-=================
-CheckExitRules
-
-There will be a delay between the time the exit is qualified for
-and the time everyone is moved to the intermission spot, so you
-can see the last frag.
-=================
-*/
-void CheckExitRules( void ) {
- int i;
- gclient_t *cl;
- // if at the intermission, wait for all non-bots to
- // signal ready, then go to next level
- if ( level.intermissiontime ) {
- CheckIntermissionExit ();
- return;
- } else {
- //sago: Find the reason for this to be neccesary.
- for (i=0 ; i< g_maxclients.integer ; i++) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- cl->ps.stats[STAT_CLIENTS_READY] = 0;
- }
- }
-
- if ( level.intermissionQueued ) {
-#ifdef MISSIONPACK
- int time = (g_singlePlayer.integer) ? SP_INTERMISSION_DELAY_TIME : INTERMISSION_DELAY_TIME;
- if ( level.time - level.intermissionQueued >= time ) {
- level.intermissionQueued = 0;
- BeginIntermission();
- }
-#else
- if ( level.time - level.intermissionQueued >= INTERMISSION_DELAY_TIME ) {
- level.intermissionQueued = 0;
- BeginIntermission();
- }
-#endif
- return;
- }
-
- // check for sudden death
- if ( ScoreIsTied() ) {
- // always wait for sudden death
- return;
- }
-
- if ( g_timelimit.integer && !level.warmupTime ) {
- if ( level.time - level.startTime >= g_timelimit.integer*60000 ) {
- trap_SendServerCommand( -1, "print \"Timelimit hit.\n\"");
- LogExit( "Timelimit hit." );
- return;
- }
- }
-
- if ( level.numPlayingClients < 2 ) {
- return;
- }
-
- if ( (g_gametype.integer < GT_CTF || g_ffa_gt>0 ) && g_fraglimit.integer ) {
- if ( level.teamScores[TEAM_RED] >= g_fraglimit.integer ) {
- trap_SendServerCommand( -1, "print \"Red hit the fraglimit.\n\"" );
- LogExit( "Fraglimit hit." );
- return;
- }
-
- if ( level.teamScores[TEAM_BLUE] >= g_fraglimit.integer ) {
- trap_SendServerCommand( -1, "print \"Blue hit the fraglimit.\n\"" );
- LogExit( "Fraglimit hit." );
- return;
- }
-
- for ( i=0 ; i< g_maxclients.integer ; i++ ) {
- cl = level.clients + i;
- if ( cl->pers.connected != CON_CONNECTED ) {
- continue;
- }
- if ( cl->sess.sessionTeam != TEAM_FREE ) {
- continue;
- }
-
- if ( cl->ps.persistant[PERS_SCORE] >= g_fraglimit.integer ) {
- LogExit( "Fraglimit hit." );
- trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " hit the fraglimit.\n\"",
- cl->pers.netname ) );
- return;
- }
- }
- }
-
- if ( (g_gametype.integer >= GT_CTF && g_ffa_gt<1) && g_capturelimit.integer ) {
-
- if ( level.teamScores[TEAM_RED] >= g_capturelimit.integer ) {
- trap_SendServerCommand( -1, "print \"Red hit the capturelimit.\n\"" );
- LogExit( "Capturelimit hit." );
- return;
- }
-
- if ( level.teamScores[TEAM_BLUE] >= g_capturelimit.integer ) {
- trap_SendServerCommand( -1, "print \"Blue hit the capturelimit.\n\"" );
- LogExit( "Capturelimit hit." );
- return;
- }
- }
-}
-
-//LMS - Last man Stading functions:
-void StartLMSRound(void) {
- int countsLiving;
- countsLiving = TeamLivingCount( -1, TEAM_FREE );
- if(countsLiving<2) {
- trap_SendServerCommand( -1, "print \"Not enough players to start the round\n\"");
- level.roundNumberStarted = level.roundNumber-1;
- level.roundStartTime = level.time+1000*g_elimination_warmup.integer;
- return;
- }
-
- //If we are enough to start a round:
- level.roundNumberStarted = level.roundNumber; //Set numbers
-
-
-
- SendEliminationMessageToAllClients();
- EnableWeapons();
-}
-
-//the elimination start function
-void StartEliminationRound(void) {
-
- int countsLiving[TEAM_NUM_TEAMS];
- countsLiving[TEAM_BLUE] = TeamLivingCount( -1, TEAM_BLUE );
- countsLiving[TEAM_RED] = TeamLivingCount( -1, TEAM_RED );
- if((countsLiving[TEAM_BLUE]==0) || (countsLiving[TEAM_RED]==0))
- {
- trap_SendServerCommand( -1, "print \"Not enough players to start the round\n\"");
- level.roundNumberStarted = level.roundNumber-1;
- level.roundRespawned = qfalse;
- //Remember that one of the teams is empty!
- level.roundRedPlayers = countsLiving[TEAM_RED];
- level.roundBluePlayers = countsLiving[TEAM_BLUE];
- level.roundStartTime = level.time+1000*g_elimination_warmup.integer;
- return;
- }
-
- //If we are enough to start a round:
- level.roundNumberStarted = level.roundNumber; //Set numbers
- level.roundRedPlayers = countsLiving[TEAM_RED];
- level.roundBluePlayers = countsLiving[TEAM_BLUE];
- if(g_gametype.integer == GT_CTF_ELIMINATION) {
- Team_ReturnFlag( TEAM_RED );
- Team_ReturnFlag( TEAM_BLUE );
- }
- if(g_gametype.integer == GT_ELIMINATION) {
- G_LogPrintf( "ELIMINATION: %i %i %i: Round %i has started!\n", level.roundNumber, -1, 0, level.roundNumber );
- } else if(g_gametype.integer == GT_CTF_ELIMINATION) {
- G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: Round %i has started!\n", level.roundNumber, -1, -1, 4, level.roundNumber );
- }
- SendEliminationMessageToAllClients();
- if(g_elimination_ctf_oneway.integer)
- SendAttackingTeamMessageToAllClients(); //Ensure that evaryone know who should attack.
- EnableWeapons();
-}
-
-//things to do at end of round:
-void EndEliminationRound(void)
-{
- DisableWeapons();
- level.roundNumber++;
- level.roundStartTime = level.time+1000*g_elimination_warmup.integer;
- SendEliminationMessageToAllClients();
- CalculateRanks();
- level.roundRespawned = qfalse;
- if(g_elimination_ctf_oneway.integer)
- SendAttackingTeamMessageToAllClients();
-}
-
-//Things to do if we don't want to move the roundNumber
-void RestartEliminationRound(void) {
- DisableWeapons();
- level.roundNumberStarted = level.roundNumber-1;
- level.roundStartTime = level.time+1000*g_elimination_warmup.integer;
- SendEliminationMessageToAllClients();
- level.roundRespawned = qfalse;
- if(g_elimination_ctf_oneway.integer)
- SendAttackingTeamMessageToAllClients();
-}
-
-//Things to do during match warmup
-void WarmupEliminationRound(void) {
- EnableWeapons();
- level.roundNumberStarted = level.roundNumber-1;
- level.roundStartTime = level.time+1000*g_elimination_warmup.integer;
- SendEliminationMessageToAllClients();
- level.roundRespawned = qfalse;
- if(g_elimination_ctf_oneway.integer)
- SendAttackingTeamMessageToAllClients();
-}
-
-/*
-========================================================================
-
-FUNCTIONS CALLED EVERY FRAME
-
-========================================================================
-*/
-
-/*
-CheckDoubleDomination
-*/
-
-void CheckDoubleDomination( void ) {
- if ( level.numPlayingClients < 1 ) {
- return;
- }
-
- if ( level.warmupTime != 0) {
- if( ((level.pointStatusA == TEAM_BLUE && level.pointStatusB == TEAM_BLUE) ||
- (level.pointStatusA == TEAM_RED && level.pointStatusB == TEAM_RED)) &&
- level.timeTaken + 10*1000 <= level.time ) {
- Team_RemoveDoubleDominationPoints();
- level.roundStartTime = level.time + 10*1000;
- SendScoreboardMessageToAllClients();
- }
- return;
- }
-
- if(g_gametype.integer != GT_DOUBLE_D)
- return;
-
- //Don't score if we are in intermission. Both points might have been taken when we went into intermission
- if(level.intermissiontime)
- return;
-
- if(level.pointStatusA == TEAM_RED && level.pointStatusB == TEAM_RED && level.timeTaken + 10*1000 <= level.time) {
- //Red scores
- trap_SendServerCommand( -1, "print \"Red team scores!\n\"");
- AddTeamScore(level.intermission_origin,TEAM_RED,1);
- G_LogPrintf( "DD: %i %i %i: %s scores!\n", -1, TEAM_RED, 2, TeamName(TEAM_RED) );
- Team_ForceGesture(TEAM_RED);
- Team_DD_bonusAtPoints(TEAM_RED);
- Team_RemoveDoubleDominationPoints();
- //We start again in 10 seconds:
- level.roundStartTime = level.time + 10*1000;
- SendScoreboardMessageToAllClients();
- CalculateRanks();
- }
-
- if(level.pointStatusA == TEAM_BLUE && level.pointStatusB == TEAM_BLUE && level.timeTaken + 10*1000 <= level.time) {
- //Blue scores
- trap_SendServerCommand( -1, "print \"Blue team scores!\n\"");
- AddTeamScore(level.intermission_origin,TEAM_BLUE,1);
- G_LogPrintf( "DD: %i %i %i: %s scores!\n", -1, TEAM_BLUE, 2, TeamName(TEAM_BLUE) );
- Team_ForceGesture(TEAM_BLUE);
- Team_DD_bonusAtPoints(TEAM_BLUE);
- Team_RemoveDoubleDominationPoints();
- //We start again in 10 seconds:
- level.roundStartTime = level.time + 10*1000;
- SendScoreboardMessageToAllClients();
- CalculateRanks();
- }
-
- if((level.pointStatusA == TEAM_NONE || level.pointStatusB == TEAM_NONE) && level.time>level.roundStartTime) {
- trap_SendServerCommand( -1, "print \"A new round has started\n\"");
- Team_SpawnDoubleDominationPoints();
- SendScoreboardMessageToAllClients();
- }
-}
-
-/*
-CheckLMS
-*/
-
-void CheckLMS(void) {
- int mode;
- mode = g_lms_mode.integer;
- if ( level.numPlayingClients < 1 ) {
- return;
- }
-
-
-
- //We don't want to do anything in intermission
- if(level.intermissiontime) {
- if(level.roundRespawned) {
- RestartEliminationRound();
- }
- level.roundStartTime = level.time; //so that a player might join at any time to fix the bots+no humans+autojoin bug
- return;
- }
-
- if(g_gametype.integer == GT_LMS)
- {
- int countsLiving[TEAM_NUM_TEAMS];
- //trap_SendServerCommand( -1, "print \"This is LMS!\n\"");
- countsLiving[TEAM_FREE] = TeamLivingCount( -1, TEAM_FREE );
- if(countsLiving[TEAM_FREE]==1 && level.roundNumber==level.roundNumberStarted)
- {
- if(mode <=1 )
- LMSpoint();
- trap_SendServerCommand( -1, "print \"We have a winner!\n\"");
- EndEliminationRound();
- Team_ForceGesture(TEAM_FREE);
- }
-
- if(countsLiving[TEAM_FREE]==0 && level.roundNumber==level.roundNumberStarted)
- {
- trap_SendServerCommand( -1, "print \"All death... how sad\n\"");
- EndEliminationRound();
- }
-
- if((level.roundNumber==level.roundNumberStarted)&&(g_lms_mode.integer == 1 || g_lms_mode.integer==3)&&(level.time>=level.roundStartTime+1000*g_elimination_roundtime.integer))
- {
- trap_SendServerCommand( -1, "print \"Time up - Overtime disabled\n\"");
- if(mode <=1 )
- LMSpoint();
- EndEliminationRound();
- }
-
- //This might be better placed another place:
- if(g_elimination_activewarmup.integer<2)
- g_elimination_activewarmup.integer=2; //We need at least 2 seconds to spawn all players
- if(g_elimination_activewarmup.integer >= g_elimination_warmup.integer) //This must not be true
- g_elimination_warmup.integer = g_elimination_activewarmup.integer+1; //Increase warmup
-
- //Force respawn
- if(level.roundNumber != level.roundNumberStarted && level.time>level.roundStartTime-1000*g_elimination_activewarmup.integer && !level.roundRespawned)
- {
- level.roundRespawned = qtrue;
- RespawnAll();
- DisableWeapons();
- SendEliminationMessageToAllClients();
- }
-
- if(level.time<=level.roundStartTime && level.time>level.roundStartTime-1000*g_elimination_activewarmup.integer)
- {
- RespawnDead();
- //DisableWeapons();
- }
-
- if(level.roundNumber == level.roundNumberStarted)
- {
- EnableWeapons();
- }
-
- if((level.roundNumber>level.roundNumberStarted)&&(level.time>=level.roundStartTime))
- StartLMSRound();
-
- if(level.time+1000*g_elimination_warmup.integer-500>level.roundStartTime && level.numPlayingClients < 2)
- {
- RespawnDead(); //Allow player to run around anyway
- WarmupEliminationRound(); //Start over
- return;
- }
-
- if(level.warmupTime != 0) {
- if(level.time+1000*g_elimination_warmup.integer-500>level.roundStartTime)
- {
- RespawnDead();
- WarmupEliminationRound();
- }
- }
-
- }
-}
-
-/*
-=============
-CheckElimination
-=============
-*/
-void CheckElimination(void) {
- if ( level.numPlayingClients < 1 ) {
- if( (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) &&
- ( level.time+1000*g_elimination_warmup.integer-500>level.roundStartTime ))
- RestartEliminationRound(); //For spectators
- return;
- }
-
- //We don't want to do anything in itnermission
- if(level.intermissiontime) {
- if(level.roundRespawned)
- RestartEliminationRound();
- level.roundStartTime = level.time+1000*g_elimination_warmup.integer;
- return;
- }
-
- if(g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION)
- {
- int counts[TEAM_NUM_TEAMS];
- int countsLiving[TEAM_NUM_TEAMS];
- int countsHealth[TEAM_NUM_TEAMS];
- counts[TEAM_BLUE] = TeamCount( -1, TEAM_BLUE );
- counts[TEAM_RED] = TeamCount( -1, TEAM_RED );
-
- countsLiving[TEAM_BLUE] = TeamLivingCount( -1, TEAM_BLUE );
- countsLiving[TEAM_RED] = TeamLivingCount( -1, TEAM_RED );
-
- countsHealth[TEAM_BLUE] = TeamHealthCount( -1, TEAM_BLUE );
- countsHealth[TEAM_RED] = TeamHealthCount( -1, TEAM_RED );
-
- if(level.roundBluePlayers != 0 && level.roundRedPlayers != 0) { //Cannot score if one of the team never got any living players
- if((countsLiving[TEAM_BLUE]==0)&&(level.roundNumber==level.roundNumberStarted))
- {
- //Blue team has been eliminated!
- trap_SendServerCommand( -1, "print \"Blue Team eliminated!\n\"");
- AddTeamScore(level.intermission_origin,TEAM_RED,1);
- if(g_gametype.integer == GT_ELIMINATION) {
- G_LogPrintf( "ELIMINATION: %i %i %i: %s wins round %i by eleminating the enemy team!\n", level.roundNumber, TEAM_RED, 1, TeamName(TEAM_RED), level.roundNumber );
- } else {
- G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i by eleminating the enemy team!\n", level.roundNumber, -1, TEAM_RED, 6, TeamName(TEAM_RED), level.roundNumber );
- }
- EndEliminationRound();
- Team_ForceGesture(TEAM_RED);
- }
- else if((countsLiving[TEAM_RED]==0)&&(level.roundNumber==level.roundNumberStarted))
- {
- //Red team eliminated!
- trap_SendServerCommand( -1, "print \"Red Team eliminated!\n\"");
- AddTeamScore(level.intermission_origin,TEAM_BLUE,1);
- if(g_gametype.integer == GT_ELIMINATION) {
- G_LogPrintf( "ELIMINATION: %i %i %i: %s wins round %i by eleminating the enemy team!\n", level.roundNumber, TEAM_BLUE, 1, TeamName(TEAM_BLUE), level.roundNumber );
- } else {
- G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i by eleminating the enemy team!\n", level.roundNumber, -1, TEAM_BLUE, 6, TeamName(TEAM_BLUE), level.roundNumber );
- }
- EndEliminationRound();
- Team_ForceGesture(TEAM_BLUE);
- }
- }
-
- //Time up
- if((level.roundNumber==level.roundNumberStarted)&&(level.time>=level.roundStartTime+1000*g_elimination_roundtime.integer))
- {
- trap_SendServerCommand( -1, "print \"No teams eliminated!\n\"");
-
- if(level.roundBluePlayers != 0 && level.roundRedPlayers != 0) {//We don't want to divide by zero. (should not be possible)
- if(g_gametype.integer == GT_CTF_ELIMINATION && g_elimination_ctf_oneway.integer) {
- //One way CTF, make defensice team the winner.
- if ( (level.eliminationSides+level.roundNumber)%2 == 0 ) { //Red was attacking
- trap_SendServerCommand( -1, "print \"Blue team defended the base\n\"");
- AddTeamScore(level.intermission_origin,TEAM_BLUE,1);
- }
- else {
- trap_SendServerCommand( -1, "print \"Red team defended the base\n\"");
- AddTeamScore(level.intermission_origin,TEAM_RED,1);
- }
- }
- else if(((double)countsLiving[TEAM_RED])/((double)level.roundRedPlayers)>((double)countsLiving[TEAM_BLUE])/((double)level.roundBluePlayers))
- {
- //Red team has higher procentage survivors
- trap_SendServerCommand( -1, "print \"Red team has most survivers!\n\"");
- AddTeamScore(level.intermission_origin,TEAM_RED,1);
- if(g_gametype.integer == GT_ELIMINATION) {
- G_LogPrintf( "ELIMINATION: %i %i %i: %s wins round %i due to more survivors!\n", level.roundNumber, TEAM_RED, 2, TeamName(TEAM_RED), level.roundNumber );
- } else {
- G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i due to more survivors!\n", level.roundNumber, -1, TEAM_RED, 7, TeamName(TEAM_RED), level.roundNumber );
- }
- }
- else if(((double)countsLiving[TEAM_RED])/((double)level.roundRedPlayers)<((double)countsLiving[TEAM_BLUE])/((double)level.roundBluePlayers))
- {
- //Blue team has higher procentage survivors
- trap_SendServerCommand( -1, "print \"Blue team has most survivers!\n\"");
- AddTeamScore(level.intermission_origin,TEAM_BLUE,1);
- if(g_gametype.integer == GT_ELIMINATION) {
- G_LogPrintf( "ELIMINATION: %i %i %i: %s wins round %i due to more survivors!\n", level.roundNumber, TEAM_BLUE, 2, TeamName(TEAM_BLUE), level.roundNumber );
- } else {
- G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i due to more survivors!\n", level.roundNumber, -1, TEAM_BLUE, 7, TeamName(TEAM_BLUE), level.roundNumber );
- }
- }
- else if(countsHealth[TEAM_RED]>countsHealth[TEAM_BLUE])
- {
- //Red team has more health
- trap_SendServerCommand( -1, "print \"Red team has more health left!\n\"");
- AddTeamScore(level.intermission_origin,TEAM_RED,1);
- if(g_gametype.integer == GT_ELIMINATION) {
- G_LogPrintf( "ELIMINATION: %i %i %i: %s wins round %i due to more health left!\n", level.roundNumber, TEAM_RED, 3, TeamName(TEAM_RED), level.roundNumber );
- } else {
- G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i due to more health left!\n", level.roundNumber, -1, TEAM_RED, 8, TeamName(TEAM_RED), level.roundNumber );
- }
- }
- else if(countsHealth[TEAM_RED]<countsHealth[TEAM_BLUE])
- {
- //Blue team has more health
- trap_SendServerCommand( -1, "print \"Blue team has more health left!\n\"");
- AddTeamScore(level.intermission_origin,TEAM_BLUE,1);
- if(g_gametype.integer == GT_ELIMINATION) {
- G_LogPrintf( "ELIMINATION: %i %i %i: %s wins round %i due to more health left!\n", level.roundNumber, TEAM_BLUE, 3, TeamName(TEAM_BLUE), level.roundNumber );
- } else {
- G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s wins round %i due to more health left!\n", level.roundNumber, -1, TEAM_BLUE, 8, TeamName(TEAM_BLUE), level.roundNumber );
- }
- }
- }
- //Draw
- if(g_gametype.integer == GT_ELIMINATION) {
- G_LogPrintf( "ELIMINATION: %i %i %i: Round %i ended in a draw!\n", level.roundNumber, -1, 4, level.roundNumber );
- } else {
- G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: Round %i ended in a draw!\n", level.roundNumber, -1, -1, 9, level.roundNumber );
- }
- EndEliminationRound();
- }
-
- //This might be better placed another place:
- if(g_elimination_activewarmup.integer<1)
- g_elimination_activewarmup.integer=1; //We need at least 1 second to spawn all players
- if(g_elimination_activewarmup.integer >= g_elimination_warmup.integer) //This must not be true
- g_elimination_warmup.integer = g_elimination_activewarmup.integer+1; //Increase warmup
-
- //Force respawn
- if(level.roundNumber!=level.roundNumberStarted && level.time>level.roundStartTime-1000*g_elimination_activewarmup.integer && !level.roundRespawned)
- {
- level.roundRespawned = qtrue;
- RespawnAll();
- SendEliminationMessageToAllClients();
- }
-
- if(level.time<=level.roundStartTime && level.time>level.roundStartTime-1000*g_elimination_activewarmup.integer)
- {
- RespawnDead();
- }
-
-
- if((level.roundNumber>level.roundNumberStarted)&&(level.time>=level.roundStartTime))
- StartEliminationRound();
-
- if(level.time+1000*g_elimination_warmup.integer-500>level.roundStartTime)
- if(counts[TEAM_BLUE]<1 || counts[TEAM_RED]<1)
- {
- RespawnDead(); //Allow players to run around anyway
- WarmupEliminationRound(); //Start over
- return;
- }
-
- if(level.warmupTime != 0) {
- if(level.time+1000*g_elimination_warmup.integer-500>level.roundStartTime)
- {
- RespawnDead();
- WarmupEliminationRound();
- }
- }
- }
-}
-
-/*
-=============
-CheckDomination
-=============
-*/
-void CheckDomination(void) {
- int i;
- int scoreFactor = 1;
-
- if ( (level.numPlayingClients < 1) || (g_gametype.integer != GT_DOMINATION) ) {
- return;
- }
-
- //Do nothing if warmup
- if(level.warmupTime != 0)
- return;
-
- //Don't score if we are in intermission. Just plain stupid
- if(level.intermissiontime)
- return;
-
- //Sago: I use if instead of while, since if the server stops for more than 2 seconds people should not be allowed to score anyway
- if(level.domination_points_count>3)
- scoreFactor = 2; //score more slowly if there are many points
- if(level.time>=level.dom_scoreGiven*DOM_SECSPERPOINT*scoreFactor) {
- for(i=0;i<level.domination_points_count;i++) {
- if ( level.pointStatusDom[i] == TEAM_RED )
- AddTeamScore(level.intermission_origin,TEAM_RED,1);
- if ( level.pointStatusDom[i] == TEAM_BLUE )
- AddTeamScore(level.intermission_origin,TEAM_BLUE,1);
- }
- level.dom_scoreGiven++;
- while(level.time>level.dom_scoreGiven*DOM_SECSPERPOINT*scoreFactor)
- level.dom_scoreGiven++;
- CalculateRanks();
- }
-}
-
-/*
-=============
-CheckTournament
-
-Once a frame, check for changes in tournement player state
-=============
-*/
-void CheckTournament( void ) {
- // check because we run 3 game frames before calling Connect and/or ClientBegin
- // for clients on a map_restart
- if ( level.numPlayingClients == 0 ) {
- return;
- }
-
- if ( g_gametype.integer == GT_TOURNAMENT ) {
-
- // pull in a spectator if needed
- if ( level.numPlayingClients < 2 ) {
- AddTournamentPlayer();
- }
-
- // if we don't have two players, go back to "waiting for players"
- if ( level.numPlayingClients != 2 ) {
- if ( level.warmupTime != -1 ) {
- level.warmupTime = -1;
- trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
- G_LogPrintf( "Warmup:\n" );
- }
- return;
- }
-
- if ( level.warmupTime == 0 ) {
- return;
- }
-
- // if the warmup is changed at the console, restart it
- if ( g_warmup.modificationCount != level.warmupModificationCount ) {
- level.warmupModificationCount = g_warmup.modificationCount;
- level.warmupTime = -1;
- }
-
- // if all players have arrived, start the countdown
- if ( level.warmupTime < 0 ) {
- if ( level.numPlayingClients == 2 ) {
- // fudge by -1 to account for extra delays
- if ( g_warmup.integer > 1 ) {
- level.warmupTime = level.time + ( g_warmup.integer - 1 ) * 1000;
- } else {
- level.warmupTime = 0;
- }
-
- trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
- }
- return;
- }
-
- // if the warmup time has counted down, restart
- if ( level.time > level.warmupTime ) {
- level.warmupTime += 10000;
- trap_Cvar_Set( "g_restarted", "1" );
- trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
- level.restarted = qtrue;
- return;
- }
- } else if ( g_gametype.integer != GT_SINGLE_PLAYER && level.warmupTime != 0 ) {
- int counts[TEAM_NUM_TEAMS];
- qboolean notEnough = qfalse;
-
- if ( g_gametype.integer > GT_TEAM && !g_ffa_gt ) {
- counts[TEAM_BLUE] = TeamCount( -1, TEAM_BLUE );
- counts[TEAM_RED] = TeamCount( -1, TEAM_RED );
-
- if (counts[TEAM_RED] < 1 || counts[TEAM_BLUE] < 1) {
- notEnough = qtrue;
- }
- } else if ( level.numPlayingClients < 2 ) {
- notEnough = qtrue;
- }
-
- if ( notEnough ) {
- if ( level.warmupTime != -1 ) {
- level.warmupTime = -1;
- trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
- G_LogPrintf( "Warmup:\n" );
- }
- return; // still waiting for team members
- }
-
- if ( level.warmupTime == 0 ) {
- return;
- }
-
- // if the warmup is changed at the console, restart it
- if ( g_warmup.modificationCount != level.warmupModificationCount ) {
- level.warmupModificationCount = g_warmup.modificationCount;
- level.warmupTime = -1;
- }
-
- // if all players have arrived, start the countdown
- if ( level.warmupTime < 0 ) {
- // fudge by -1 to account for extra delays
- level.warmupTime = level.time + ( g_warmup.integer - 1 ) * 1000;
- trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
- return;
- }
-
- // if the warmup time has counted down, restart
- if ( level.time > level.warmupTime ) {
- level.warmupTime += 10000;
- trap_Cvar_Set( "g_restarted", "1" );
- trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
- level.restarted = qtrue;
- return;
- }
- }
-}
-
-
-
-
-/*
-==================
-PrintTeam
-==================
-*/
-void PrintTeam(int team, char *message) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if (level.clients[i].sess.sessionTeam != team)
- continue;
- trap_SendServerCommand( i, message );
- }
-}
-
-/*
-==================
-SetLeader
-==================
-*/
-void SetLeader(int team, int client) {
- int i;
-
- if ( level.clients[client].pers.connected == CON_DISCONNECTED ) {
- PrintTeam(team, va("print \"%s is not connected\n\"", level.clients[client].pers.netname) );
- return;
- }
- if (level.clients[client].sess.sessionTeam != team) {
- PrintTeam(team, va("print \"%s is not on the team anymore\n\"", level.clients[client].pers.netname) );
- return;
- }
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if (level.clients[i].sess.sessionTeam != team)
- continue;
- if (level.clients[i].sess.teamLeader) {
- level.clients[i].sess.teamLeader = qfalse;
- ClientUserinfoChanged(i);
- }
- }
- level.clients[client].sess.teamLeader = qtrue;
- ClientUserinfoChanged( client );
- PrintTeam(team, va("print \"%s is the new team leader\n\"", level.clients[client].pers.netname) );
-}
-
-/*
-==================
-CheckTeamLeader
-==================
-*/
-void CheckTeamLeader( int team ) {
- int i;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if (level.clients[i].sess.sessionTeam != team)
- continue;
- if (level.clients[i].sess.teamLeader)
- break;
- }
- if (i >= level.maxclients) {
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if (level.clients[i].sess.sessionTeam != team)
- continue;
- if (!(g_entities[i].r.svFlags & SVF_BOT)) {
- level.clients[i].sess.teamLeader = qtrue;
- break;
- }
- }
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if (level.clients[i].sess.sessionTeam != team)
- continue;
- level.clients[i].sess.teamLeader = qtrue;
- break;
- }
- }
-}
-
-/*
-==================
-CheckTeamVote
-==================
-*/
-void CheckTeamVote( int team ) {
- int cs_offset;
-
- if ( team == TEAM_RED )
- cs_offset = 0;
- else if ( team == TEAM_BLUE )
- cs_offset = 1;
- else
- return;
-
- if ( !level.teamVoteTime[cs_offset] ) {
- return;
- }
- if ( level.time - level.teamVoteTime[cs_offset] >= VOTE_TIME ) {
- trap_SendServerCommand( -1, "print \"Team vote failed.\n\"" );
- } else {
- if ( level.teamVoteYes[cs_offset] > level.numteamVotingClients[cs_offset]/2 ) {
- // execute the command, then remove the vote
- trap_SendServerCommand( -1, "print \"Team vote passed.\n\"" );
- //
- if ( !Q_strncmp( "leader", level.teamVoteString[cs_offset], 6) ) {
- //set the team leader
- SetLeader(team, atoi(level.teamVoteString[cs_offset] + 7));
- }
- else {
- trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.teamVoteString[cs_offset] ) );
- }
- } else if ( level.teamVoteNo[cs_offset] >= level.numteamVotingClients[cs_offset]/2 ) {
- // same behavior as a timeout
- trap_SendServerCommand( -1, "print \"Team vote failed.\n\"" );
- } else {
- // still waiting for a majority
- return;
- }
- }
- level.teamVoteTime[cs_offset] = 0;
- trap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, "" );
-
-}
-
-
-/*
-==================
-CheckCvars
-==================
-*/
-void CheckCvars( void ) {
- static int lastMod = -1;
-
- if ( g_password.modificationCount != lastMod ) {
- lastMod = g_password.modificationCount;
- if ( *g_password.string && Q_stricmp( g_password.string, "none" ) ) {
- trap_Cvar_Set( "g_needpass", "1" );
- } else {
- trap_Cvar_Set( "g_needpass", "0" );
- }
- }
-}
-
-/*
-=============
-G_RunThink
-
-Runs thinking code for this frame if necessary
-=============
-*/
-void G_RunThink (gentity_t *ent) {
- float thinktime;
-
- thinktime = ent->nextthink;
- if (thinktime <= 0) {
- return;
- }
- if (thinktime > level.time) {
- return;
- }
-
- ent->nextthink = 0;
- if (!ent->think) {
- G_Error ( "NULL ent->think");
- }
- ent->think (ent);
-}
-
-/*
-================
-G_RunFrame
-
-Advances the non-player objects in the world
-================
-*/
-void G_RunFrame( int levelTime ) {
- int i;
- gentity_t *ent;
- int msec;
-int start, end;
-
- // if we are waiting for the level to restart, do nothing
- if ( level.restarted ) {
- return;
- }
-
- level.framenum++;
- level.previousTime = level.time;
- level.time = levelTime;
- msec = level.time - level.previousTime;
-
- // get any cvar changes
- G_UpdateCvars();
-
- if( (g_gametype.integer==GT_ELIMINATION || g_gametype.integer==GT_CTF_ELIMINATION) && !(g_elimflags.integer & EF_NO_FREESPEC) && g_elimination_lockspectator.integer>1)
- trap_Cvar_Set("elimflags",va("%i",g_elimflags.integer|EF_NO_FREESPEC));
- else
- if( (g_elimflags.integer & EF_NO_FREESPEC) && g_elimination_lockspectator.integer<2)
- trap_Cvar_Set("elimflags",va("%i",g_elimflags.integer&(~EF_NO_FREESPEC) ) );
-
- if( g_elimination_ctf_oneway.integer && !(g_elimflags.integer & EF_ONEWAY) ) {
- trap_Cvar_Set("elimflags",va("%i",g_elimflags.integer|EF_ONEWAY ) );
- //If the server admin has enabled it midgame imidiantly braodcast attacking team
- SendAttackingTeamMessageToAllClients();
- }
- else
- if( !g_elimination_ctf_oneway.integer && (g_elimflags.integer & EF_ONEWAY) ) {
- trap_Cvar_Set("elimflags",va("%i",g_elimflags.integer&(~EF_ONEWAY) ) );
- }
-
- //
- // go through all allocated objects
- //
- start = trap_Milliseconds();
- ent = &g_entities[0];
- for (i=0 ; i<level.num_entities ; i++, ent++) {
- if ( !ent->inuse ) {
- continue;
- }
-
- // clear events that are too old
- if ( level.time - ent->eventTime > EVENT_VALID_MSEC ) {
- if ( ent->s.event ) {
- ent->s.event = 0; // &= EV_EVENT_BITS;
- if ( ent->client ) {
- ent->client->ps.externalEvent = 0;
- // predicted events should never be set to zero
- //ent->client->ps.events[0] = 0;
- //ent->client->ps.events[1] = 0;
- }
- }
- if ( ent->freeAfterEvent ) {
- // tempEntities or dropped items completely go away after their event
- G_FreeEntity( ent );
- continue;
- } else if ( ent->unlinkAfterEvent ) {
- // items that will respawn will hide themselves after their pickup event
- ent->unlinkAfterEvent = qfalse;
- trap_UnlinkEntity( ent );
- }
- }
-
- // temporary entities don't think
- if ( ent->freeAfterEvent ) {
- continue;
- }
-
- if ( !ent->r.linked && ent->neverFree ) {
- continue;
- }
-
-//unlagged - backward reconciliation #2
- // we'll run missiles separately to save CPU in backward reconciliation
-/*
- if ( ent->s.eType == ET_MISSILE ) {
- G_RunMissile( ent );
- continue;
- }
-*/
-//unlagged - backward reconciliation #2
-
- if ( ent->s.eType == ET_ITEM || ent->physicsObject ) {
- G_RunItem( ent );
- continue;
- }
-
- if ( ent->s.eType == ET_MOVER ) {
- G_RunMover( ent );
- continue;
- }
-
- if ( i < MAX_CLIENTS ) {
- G_RunClient( ent );
- continue;
- }
-
- G_RunThink( ent );
- }
-
-//unlagged - backward reconciliation #2
- // NOW run the missiles, with all players backward-reconciled
- // to the positions they were in exactly 50ms ago, at the end
- // of the last server frame
- G_TimeShiftAllClients( level.previousTime, NULL );
-
- ent = &g_entities[0];
- for (i=0 ; i<level.num_entities ; i++, ent++) {
- if ( !ent->inuse ) {
- continue;
- }
-
- // temporary entities don't think
- if ( ent->freeAfterEvent ) {
- continue;
- }
-
- if ( ent->s.eType == ET_MISSILE ) {
- G_RunMissile( ent );
- }
- }
-
- G_UnTimeShiftAllClients( NULL );
-//unlagged - backward reconciliation #2
-
-end = trap_Milliseconds();
-
-start = trap_Milliseconds();
- // perform final fixups on the players
- ent = &g_entities[0];
- for (i=0 ; i < level.maxclients ; i++, ent++ ) {
- if ( ent->inuse ) {
- ClientEndFrame( ent );
- }
- }
-end = trap_Milliseconds();
-
- // see if it is time to do a tournement restart
- CheckTournament();
-
- //Check Elimination state
- CheckElimination();
- CheckLMS();
-
- //Check Double Domination
- CheckDoubleDomination();
-
- CheckDomination();
-
- //Sago: I just need to think why I placed this here... they should only spawn once
- if(g_gametype.integer == GT_DOMINATION)
- Team_Dom_SpawnPoints();
-
- // see if it is time to end the level
- CheckExitRules();
-
- // update to team status?
- CheckTeamStatus();
-
- // cancel vote if timed out
- CheckVote();
-
- // check team votes
- CheckTeamVote( TEAM_RED );
- CheckTeamVote( TEAM_BLUE );
-
- // for tracking changes
- CheckCvars();
-
- if (g_listEntity.integer) {
- for (i = 0; i < MAX_GENTITIES; i++) {
- G_Printf("%4i: %s\n", i, g_entities[i].classname);
- }
- trap_Cvar_Set("g_listEntity", "0");
- }
-
-//unlagged - backward reconciliation #4
- // record the time at the end of this frame - it should be about
- // the time the next frame begins - when the server starts
- // accepting commands from connected clients
- level.frameStartTime = trap_Milliseconds();
-//unlagged - backward reconciliation #4
-}
-
diff --git a/game/code/game/g_misc.c b/game/code/game/g_misc.c
deleted file mode 100644
index 3b32ec4..0000000
--- a/game/code/game/g_misc.c
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// g_misc.c
-
-#include "g_local.h"
-
-
-/*QUAKED func_group (0 0 0) ?
-Used to group brushes together just for editor convenience. They are turned into normal brushes by the utilities.
-*/
-
-
-/*QUAKED info_camp (0 0.5 0) (-4 -4 -4) (4 4 4)
-Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
-*/
-void SP_info_camp( gentity_t *self ) {
- G_SetOrigin( self, self->s.origin );
-}
-
-
-/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
-Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
-*/
-void SP_info_null( gentity_t *self ) {
- G_FreeEntity( self );
-}
-
-
-/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
-Used as a positional target for in-game calculation, like jumppad targets.
-target_position does the same thing
-*/
-void SP_info_notnull( gentity_t *self ){
- G_SetOrigin( self, self->s.origin );
-}
-
-
-/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) linear
-Non-displayed light.
-"light" overrides the default 300 intensity.
-Linear checbox gives linear falloff instead of inverse square
-Lights pointed at a target will be spotlights.
-"radius" overrides the default 64 unit radius of a spotlight at the target point.
-*/
-void SP_light( gentity_t *self ) {
- G_FreeEntity( self );
-}
-
-
-
-/*
-=================================================================================
-
-TELEPORTERS
-
-=================================================================================
-*/
-
-void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles ) {
- gentity_t *tent;
-
- // use temp events at source and destination to prevent the effect
- // from getting dropped by a second player event
- if ( player->client->sess.sessionTeam != TEAM_SPECTATOR && player->client->ps.pm_type != PM_SPECTATOR) {
- tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
- tent->s.clientNum = player->s.clientNum;
-
- tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN );
- tent->s.clientNum = player->s.clientNum;
- }
-
- // unlink to make sure it can't possibly interfere with G_KillBox
- trap_UnlinkEntity (player);
-
- VectorCopy ( origin, player->client->ps.origin );
- player->client->ps.origin[2] += 1;
-
- // spit the player out
- AngleVectors( angles, player->client->ps.velocity, NULL, NULL );
- VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );
- player->client->ps.pm_time = 160; // hold time
- player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
-
- // toggle the teleport bit so the client knows to not lerp
- player->client->ps.eFlags ^= EF_TELEPORT_BIT;
-
-//unlagged - backward reconciliation #3
- // we don't want players being backward-reconciled back through teleporters
- G_ResetHistory( player );
-//unlagged - backward reconciliation #3
-
- // set angles
- SetClientViewAngle( player, angles );
-
- // kill anything at the destination
- if ( player->client->sess.sessionTeam != TEAM_SPECTATOR && player->client->ps.pm_type != PM_SPECTATOR ) {
- G_KillBox (player);
- }
-
- // save results of pmove
- BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );
-
- // use the precise origin for linking
- VectorCopy( player->client->ps.origin, player->r.currentOrigin );
-
- if ( player->client->sess.sessionTeam != TEAM_SPECTATOR && player->client->ps.pm_type != PM_SPECTATOR ) {
- trap_LinkEntity (player);
- }
-}
-
-
-/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
-Point teleporters at these.
-Now that we don't have teleport destination pads, this is just
-an info_notnull
-*/
-void SP_misc_teleporter_dest( gentity_t *ent ) {
-}
-
-
-//===========================================================
-
-/*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16)
-"model" arbitrary .md3 file to display
-*/
-void SP_misc_model( gentity_t *ent ) {
-
-#if 0
- ent->s.modelindex = G_ModelIndex( ent->model );
- VectorSet (ent->mins, -16, -16, -16);
- VectorSet (ent->maxs, 16, 16, 16);
- trap_LinkEntity (ent);
-
- G_SetOrigin( ent, ent->s.origin );
- VectorCopy( ent->s.angles, ent->s.apos.trBase );
-#else
- G_FreeEntity( ent );
-#endif
-}
-
-//===========================================================
-
-void locateCamera( gentity_t *ent ) {
- vec3_t dir;
- gentity_t *target;
- gentity_t *owner;
-
- owner = G_PickTarget( ent->target );
- if ( !owner ) {
- G_Printf( "Couldn't find target for misc_partal_surface\n" );
- G_FreeEntity( ent );
- return;
- }
- ent->r.ownerNum = owner->s.number;
-
- // frame holds the rotate speed
- if ( owner->spawnflags & 1 ) {
- ent->s.frame = 25;
- } else if ( owner->spawnflags & 2 ) {
- ent->s.frame = 75;
- }
-
- // swing camera ?
- if ( owner->spawnflags & 4 ) {
- // set to 0 for no rotation at all
- ent->s.powerups = 0;
- }
- else {
- ent->s.powerups = 1;
- }
-
- // clientNum holds the rotate offset
- ent->s.clientNum = owner->s.clientNum;
-
- VectorCopy( owner->s.origin, ent->s.origin2 );
-
- // see if the portal_camera has a target
- target = G_PickTarget( owner->target );
- if ( target ) {
- VectorSubtract( target->s.origin, owner->s.origin, dir );
- VectorNormalize( dir );
- } else {
- G_SetMovedir( owner->s.angles, dir );
- }
-
- ent->s.eventParm = DirToByte( dir );
-}
-
-/*QUAKED misc_portal_surface (0 0 1) (-8 -8 -8) (8 8 8)
-The portal surface nearest this entity will show a view from the targeted misc_portal_camera, or a mirror view if untargeted.
-This must be within 64 world units of the surface!
-*/
-void SP_misc_portal_surface(gentity_t *ent) {
- VectorClear( ent->r.mins );
- VectorClear( ent->r.maxs );
- trap_LinkEntity (ent);
-
- ent->r.svFlags = SVF_PORTAL;
- ent->s.eType = ET_PORTAL;
-
- if ( !ent->target ) {
- VectorCopy( ent->s.origin, ent->s.origin2 );
- } else {
- ent->think = locateCamera;
- ent->nextthink = level.time + 100;
- }
-}
-
-/*QUAKED misc_portal_camera (0 0 1) (-8 -8 -8) (8 8 8) slowrotate fastrotate noswing
-The target for a misc_portal_director. You can set either angles or target another entity to determine the direction of view.
-"roll" an angle modifier to orient the camera around the target vector;
-*/
-void SP_misc_portal_camera(gentity_t *ent) {
- float roll;
-
- VectorClear( ent->r.mins );
- VectorClear( ent->r.maxs );
- trap_LinkEntity (ent);
-
- G_SpawnFloat( "roll", "0", &roll );
-
- ent->s.clientNum = roll/360.0 * 256;
-}
-
-/*
-======================================================================
-
- SHOOTERS
-
-======================================================================
-*/
-
-void Use_Shooter( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
- vec3_t dir;
- float deg;
- vec3_t up, right;
-
- // see if we have a target
- if ( ent->enemy ) {
- VectorSubtract( ent->enemy->r.currentOrigin, ent->s.origin, dir );
- VectorNormalize( dir );
- } else {
- VectorCopy( ent->movedir, dir );
- }
-
- // randomize a bit
- PerpendicularVector( up, dir );
- CrossProduct( up, dir, right );
-
- deg = crandom() * ent->random;
- VectorMA( dir, deg, up, dir );
-
- deg = crandom() * ent->random;
- VectorMA( dir, deg, right, dir );
-
- VectorNormalize( dir );
-
- switch ( ent->s.weapon ) {
- case WP_GRENADE_LAUNCHER:
- fire_grenade( ent, ent->s.origin, dir );
- break;
- case WP_ROCKET_LAUNCHER:
- fire_rocket( ent, ent->s.origin, dir );
- break;
- case WP_PLASMAGUN:
- fire_plasma( ent, ent->s.origin, dir );
- break;
- }
-
- G_AddEvent( ent, EV_FIRE_WEAPON, 0 );
-}
-
-
-static void InitShooter_Finish( gentity_t *ent ) {
- ent->enemy = G_PickTarget( ent->target );
- ent->think = 0;
- ent->nextthink = 0;
-}
-
-void InitShooter( gentity_t *ent, int weapon ) {
- ent->use = Use_Shooter;
- ent->s.weapon = weapon;
-
- RegisterItem( BG_FindItemForWeapon( weapon ) );
-
- G_SetMovedir( ent->s.angles, ent->movedir );
-
- if ( !ent->random ) {
- ent->random = 1.0;
- }
- ent->random = sin( M_PI * ent->random / 180 );
- // target might be a moving object, so we can't set movedir for it
- if ( ent->target ) {
- ent->think = InitShooter_Finish;
- ent->nextthink = level.time + 500;
- }
- trap_LinkEntity( ent );
-}
-
-/*QUAKED shooter_rocket (1 0 0) (-16 -16 -16) (16 16 16)
-Fires at either the target or the current direction.
-"random" the number of degrees of deviance from the taget. (1.0 default)
-*/
-void SP_shooter_rocket( gentity_t *ent ) {
- InitShooter( ent, WP_ROCKET_LAUNCHER );
-}
-
-/*QUAKED shooter_plasma (1 0 0) (-16 -16 -16) (16 16 16)
-Fires at either the target or the current direction.
-"random" is the number of degrees of deviance from the taget. (1.0 default)
-*/
-void SP_shooter_plasma( gentity_t *ent ) {
- InitShooter( ent, WP_PLASMAGUN);
-}
-
-/*QUAKED shooter_grenade (1 0 0) (-16 -16 -16) (16 16 16)
-Fires at either the target or the current direction.
-"random" is the number of degrees of deviance from the taget. (1.0 default)
-*/
-void SP_shooter_grenade( gentity_t *ent ) {
- InitShooter( ent, WP_GRENADE_LAUNCHER);
-}
-
-static void PortalDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod) {
- G_FreeEntity( self );
- //FIXME do something more interesting
-}
-
-
-void DropPortalDestination( gentity_t *player ) {
- gentity_t *ent;
- vec3_t snapped;
-
- // create the portal destination
- ent = G_Spawn();
- ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_exit.md3" );
-
- VectorCopy( player->s.pos.trBase, snapped );
- SnapVector( snapped );
- G_SetOrigin( ent, snapped );
- VectorCopy( player->r.mins, ent->r.mins );
- VectorCopy( player->r.maxs, ent->r.maxs );
-
- ent->classname = "hi_portal destination";
- ent->s.pos.trType = TR_STATIONARY;
-
- ent->r.contents = CONTENTS_CORPSE;
- ent->takedamage = qtrue;
- ent->health = 200;
- ent->die = PortalDie;
-
- VectorCopy( player->s.apos.trBase, ent->s.angles );
-
- ent->think = G_FreeEntity;
- ent->nextthink = level.time + 2 * 60 * 1000;
-
- trap_LinkEntity( ent );
-
- player->client->portalID = ++level.portalSequence;
- ent->count = player->client->portalID;
-
- // give the item back so they can drop the source now
- player->client->ps.stats[STAT_HOLDABLE_ITEM] = BG_FindItem( "Portal" ) - bg_itemlist;
-}
-
-
-static void PortalTouch( gentity_t *self, gentity_t *other, trace_t *trace) {
- gentity_t *destination;
-
- // see if we will even let other try to use it
- if( other->health <= 0 ) {
- return;
- }
- if( !other->client ) {
- return;
- }
-// if( other->client->ps.persistant[PERS_TEAM] != self->spawnflags ) {
-// return;
-// }
-
- if ( other->client->ps.powerups[PW_NEUTRALFLAG] ) { // only happens in One Flag CTF
- Drop_Item( other, BG_FindItemForPowerup( PW_NEUTRALFLAG ), 0 );
- other->client->ps.powerups[PW_NEUTRALFLAG] = 0;
- }
- else if ( other->client->ps.powerups[PW_REDFLAG] ) { // only happens in standard CTF
- Drop_Item( other, BG_FindItemForPowerup( PW_REDFLAG ), 0 );
- other->client->ps.powerups[PW_REDFLAG] = 0;
- }
- else if ( other->client->ps.powerups[PW_BLUEFLAG] ) { // only happens in standard CTF
- Drop_Item( other, BG_FindItemForPowerup( PW_BLUEFLAG ), 0 );
- other->client->ps.powerups[PW_BLUEFLAG] = 0;
- }
-
- // find the destination
- destination = NULL;
- while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
- if( destination->count == self->count ) {
- break;
- }
- }
-
- // if there is not one, die!
- if( !destination ) {
- if( self->pos1[0] || self->pos1[1] || self->pos1[2] ) {
- TeleportPlayer( other, self->pos1, self->s.angles );
- }
- G_Damage( other, other, other, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG );
- return;
- }
-
- TeleportPlayer( other, destination->s.pos.trBase, destination->s.angles );
-}
-
-
-static void PortalEnable( gentity_t *self ) {
- self->touch = PortalTouch;
- self->think = G_FreeEntity;
- self->nextthink = level.time + 2 * 60 * 1000;
-}
-
-
-void DropPortalSource( gentity_t *player ) {
- gentity_t *ent;
- gentity_t *destination;
- vec3_t snapped;
-
- // create the portal source
- ent = G_Spawn();
- ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_enter.md3" );
-
- VectorCopy( player->s.pos.trBase, snapped );
- SnapVector( snapped );
- G_SetOrigin( ent, snapped );
- VectorCopy( player->r.mins, ent->r.mins );
- VectorCopy( player->r.maxs, ent->r.maxs );
-
- ent->classname = "hi_portal source";
- ent->s.pos.trType = TR_STATIONARY;
-
- ent->r.contents = CONTENTS_CORPSE | CONTENTS_TRIGGER;
- ent->takedamage = qtrue;
- ent->health = 200;
- ent->die = PortalDie;
-
- trap_LinkEntity( ent );
-
- ent->count = player->client->portalID;
- player->client->portalID = 0;
-
-// ent->spawnflags = player->client->ps.persistant[PERS_TEAM];
-
- ent->nextthink = level.time + 1000;
- ent->think = PortalEnable;
-
- // find the destination
- destination = NULL;
- while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
- if( destination->count == ent->count ) {
- VectorCopy( destination->s.pos.trBase, ent->pos1 );
- break;
- }
- }
-
-}
diff --git a/game/code/game/g_missile.c b/game/code/game/g_missile.c
deleted file mode 100644
index 3f8f7f0..0000000
--- a/game/code/game/g_missile.c
+++ /dev/null
@@ -1,889 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-#define MISSILE_PRESTEP_TIME 50
-
-/*
-================
-G_BounceMissile
-
-================
-*/
-void G_BounceMissile( gentity_t *ent, trace_t *trace ) {
- vec3_t velocity;
- float dot;
- int hitTime;
-
- // reflect the velocity on the trace plane
- hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
- BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
- dot = DotProduct( velocity, trace->plane.normal );
- VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );
-
- if ( ent->s.eFlags & EF_BOUNCE_HALF ) {
- VectorScale( ent->s.pos.trDelta, 0.65, ent->s.pos.trDelta );
- // check for stop
- if ( trace->plane.normal[2] > 0.2 && VectorLength( ent->s.pos.trDelta ) < 40 ) {
- G_SetOrigin( ent, trace->endpos );
- return;
- }
- }
-
- VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
- VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
- ent->s.pos.trTime = level.time;
-}
-
-
-/*
-================
-G_ExplodeMissile
-
-Explode a missile without an impact
-================
-*/
-void G_ExplodeMissile( gentity_t *ent ) {
- vec3_t dir;
- vec3_t origin;
-
- BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
- SnapVector( origin );
- G_SetOrigin( ent, origin );
-
- // we don't have a valid direction, so just point straight up
- dir[0] = dir[1] = 0;
- dir[2] = 1;
-
- ent->s.eType = ET_GENERAL;
- G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );
-
- ent->freeAfterEvent = qtrue;
-
- // splash damage
- if ( ent->splashDamage ) {
- if( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent
- , ent->splashMethodOfDeath ) ) {
- g_entities[ent->r.ownerNum].client->accuracy_hits++;
- }
- }
-
- trap_LinkEntity( ent );
-}
-
-/*
-================
-ProximityMine_Explode
-================
-*/
-static void ProximityMine_Explode( gentity_t *mine ) {
- G_ExplodeMissile( mine );
- // if the prox mine has a trigger free it
- if (mine->activator) {
- G_FreeEntity(mine->activator);
- mine->activator = NULL;
- }
-}
-
-/*
-================
-ProximityMine_Die
-================
-*/
-static void ProximityMine_Die( gentity_t *ent, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) {
- ent->think = ProximityMine_Explode;
- ent->nextthink = level.time + 1;
-}
-
-/*
-================
-ProximityMine_Trigger
-================
-*/
-void ProximityMine_Trigger( gentity_t *trigger, gentity_t *other, trace_t *trace ) {
- vec3_t v;
- gentity_t *mine;
-
- if( !other->client ) {
- return;
- }
-
- // trigger is a cube, do a distance test now to act as if it's a sphere
- VectorSubtract( trigger->s.pos.trBase, other->s.pos.trBase, v );
- if( VectorLength( v ) > trigger->parent->splashRadius ) {
- return;
- }
-
-
- if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
- // don't trigger same team mines
- if (trigger->parent->s.generic1 == other->client->sess.sessionTeam) {
- return;
- }
- }
-
- // ok, now check for ability to damage so we don't get triggered thru walls, closed doors, etc...
- if( !CanDamage( other, trigger->s.pos.trBase ) ) {
- return;
- }
-
- // trigger the mine!
- mine = trigger->parent;
- mine->s.loopSound = 0;
- G_AddEvent( mine, EV_PROXIMITY_MINE_TRIGGER, 0 );
- mine->nextthink = level.time + 500;
-
- G_FreeEntity( trigger );
-}
-
-/*
-================
-ProximityMine_Activate
-================
-*/
-static void ProximityMine_Activate( gentity_t *ent ) {
- gentity_t *trigger;
- float r;
- vec3_t v1;
- gentity_t *flag;
- char *c;
- qboolean nearFlag = qfalse;
-
- // find the flag
- switch (ent->s.generic1) {
- case TEAM_RED:
- c = "team_CTF_redflag";
- break;
- case TEAM_BLUE:
- c = "team_CTF_blueflag";
- break;
- default:
- c = NULL;
- }
-
- if(c) {
- flag = NULL;
- while ((flag = G_Find (flag, FOFS(classname), c)) != NULL) {
- if (!(flag->flags & FL_DROPPED_ITEM))
- break;
- }
-
- if(flag) {
- VectorSubtract(ent->r.currentOrigin,flag->r.currentOrigin , v1);
- if(VectorLength(v1) < 500)
- nearFlag = qtrue;
- }
- }
-
- ent->think = ProximityMine_Explode;
- if( nearFlag)
- ent->nextthink = level.time + g_proxMineTimeout.integer/15;
- else
- ent->nextthink = level.time + g_proxMineTimeout.integer;
-
- ent->takedamage = qtrue;
- ent->health = 1;
- ent->die = ProximityMine_Die;
-
- ent->s.loopSound = G_SoundIndex( "sound/weapons/proxmine/wstbtick.wav" );
-
- // build the proximity trigger
- trigger = G_Spawn ();
-
- trigger->classname = "proxmine_trigger";
-
- r = ent->splashRadius;
- VectorSet( trigger->r.mins, -r, -r, -r );
- VectorSet( trigger->r.maxs, r, r, r );
-
- G_SetOrigin( trigger, ent->s.pos.trBase );
-
- trigger->parent = ent;
- trigger->r.contents = CONTENTS_TRIGGER;
- trigger->touch = ProximityMine_Trigger;
-
- trap_LinkEntity (trigger);
-
- // set pointer to trigger so the entity can be freed when the mine explodes
- ent->activator = trigger;
-}
-
-/*
-================
-ProximityMine_ExplodeOnPlayer
-================
-*/
-static void ProximityMine_ExplodeOnPlayer( gentity_t *mine ) {
- gentity_t *player;
-
- player = mine->enemy;
- player->client->ps.eFlags &= ~EF_TICKING;
-
- if ( player->client->invulnerabilityTime > level.time ) {
- G_Damage( player, mine->parent, mine->parent, vec3_origin, mine->s.origin, 1000, DAMAGE_NO_KNOCKBACK, MOD_JUICED );
- player->client->invulnerabilityTime = 0;
- G_TempEntity( player->client->ps.origin, EV_JUICED );
- }
- else {
- G_SetOrigin( mine, player->s.pos.trBase );
- // make sure the explosion gets to the client
- mine->r.svFlags &= ~SVF_NOCLIENT;
- mine->splashMethodOfDeath = MOD_PROXIMITY_MINE;
- G_ExplodeMissile( mine );
- }
-}
-
-/*
-================
-ProximityMine_Player
-================
-*/
-static void ProximityMine_Player( gentity_t *mine, gentity_t *player ) {
- if( mine->s.eFlags & EF_NODRAW ) {
- return;
- }
-
- G_AddEvent( mine, EV_PROXIMITY_MINE_STICK, 0 );
-
- if( player->s.eFlags & EF_TICKING ) {
- player->activator->splashDamage += mine->splashDamage;
- player->activator->splashRadius *= 1.50;
- mine->think = G_FreeEntity;
- mine->nextthink = level.time;
- return;
- }
-
- player->client->ps.eFlags |= EF_TICKING;
- player->activator = mine;
-
- mine->s.eFlags |= EF_NODRAW;
- mine->r.svFlags |= SVF_NOCLIENT;
- mine->s.pos.trType = TR_LINEAR;
- VectorClear( mine->s.pos.trDelta );
-
- mine->enemy = player;
- mine->think = ProximityMine_ExplodeOnPlayer;
- if ( player->client->invulnerabilityTime > level.time ) {
- mine->nextthink = level.time + 2 * 1000;
- }
- else {
- mine->nextthink = level.time + 10 * 1000;
- }
-}
-
-/*
- *=================
- *ProximityMine_RemoveAll
- *=================
- */
-
-void ProximityMine_RemoveAll() {
- gentity_t *mine;
-
- mine = NULL;
-
- while ((mine = G_Find (mine, FOFS(classname), "prox mine")) != NULL) {
- mine->think = ProximityMine_Explode;
- mine->nextthink = level.time + 1;
- }
-}
-
-/*
-================
-G_MissileImpact
-================
-*/
-void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
- gentity_t *other;
- qboolean hitClient = qfalse;
- vec3_t forward, impactpoint, bouncedir;
- int eFlags;
- other = &g_entities[trace->entityNum];
-
- // check for bounce
- if ( !other->takedamage &&
- ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) ) {
- G_BounceMissile( ent, trace );
- G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
- return;
- }
-
- if ( other->takedamage ) {
- if ( ent->s.weapon != WP_PROX_LAUNCHER ) {
- if ( other->client && other->client->invulnerabilityTime > level.time ) {
-
- //
- VectorCopy( ent->s.pos.trDelta, forward );
- VectorNormalize( forward );
- if (G_InvulnerabilityEffect( other, forward, ent->s.pos.trBase, impactpoint, bouncedir )) {
- VectorCopy( bouncedir, trace->plane.normal );
- eFlags = ent->s.eFlags & EF_BOUNCE_HALF;
- ent->s.eFlags &= ~EF_BOUNCE_HALF;
- G_BounceMissile( ent, trace );
- ent->s.eFlags |= eFlags;
- }
- ent->target_ent = other;
- return;
- }
- }
- }
- // impact damage
- if (other->takedamage) {
- // FIXME: wrong damage direction?
- if ( ent->damage ) {
- vec3_t velocity;
-
- if( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) {
- g_entities[ent->r.ownerNum].client->accuracy_hits++;
- hitClient = qtrue;
- }
- BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
- if ( VectorLength( velocity ) == 0 ) {
- velocity[2] = 1; // stepped on a grenade
- }
- G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
- ent->s.origin, ent->damage,
- 0, ent->methodOfDeath);
- }
- }
-
- if( ent->s.weapon == WP_PROX_LAUNCHER ) {
- if( ent->s.pos.trType != TR_GRAVITY ) {
- return;
- }
-
- // if it's a player, stick it on to them (flag them and remove this entity)
- if( other->s.eType == ET_PLAYER && other->health > 0 ) {
- ProximityMine_Player( ent, other );
- return;
- }
-
- SnapVectorTowards( trace->endpos, ent->s.pos.trBase );
- G_SetOrigin( ent, trace->endpos );
- ent->s.pos.trType = TR_STATIONARY;
- VectorClear( ent->s.pos.trDelta );
-
- G_AddEvent( ent, EV_PROXIMITY_MINE_STICK, trace->surfaceFlags );
-
- ent->think = ProximityMine_Activate;
- ent->nextthink = level.time + 2000;
-
- vectoangles( trace->plane.normal, ent->s.angles );
- ent->s.angles[0] += 90;
-
- // link the prox mine to the other entity
- ent->enemy = other;
- ent->die = ProximityMine_Die;
- VectorCopy(trace->plane.normal, ent->movedir);
- VectorSet(ent->r.mins, -4, -4, -4);
- VectorSet(ent->r.maxs, 4, 4, 4);
- trap_LinkEntity(ent);
-
- return;
- }
-
- if (!strcmp(ent->classname, "hook")) {
- gentity_t *nent;
- vec3_t v;
-
- nent = G_Spawn();
- if ( other->takedamage && other->client ) {
-
- G_AddEvent( nent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
- nent->s.otherEntityNum = other->s.number;
-
- ent->enemy = other;
-
- v[0] = other->r.currentOrigin[0] + (other->r.mins[0] + other->r.maxs[0]) * 0.5;
- v[1] = other->r.currentOrigin[1] + (other->r.mins[1] + other->r.maxs[1]) * 0.5;
- v[2] = other->r.currentOrigin[2] + (other->r.mins[2] + other->r.maxs[2]) * 0.5;
-
- SnapVectorTowards( v, ent->s.pos.trBase ); // save net bandwidth
- } else {
- VectorCopy(trace->endpos, v);
- G_AddEvent( nent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
- ent->enemy = NULL;
- }
-
- SnapVectorTowards( v, ent->s.pos.trBase ); // save net bandwidth
-
- nent->freeAfterEvent = qtrue;
- // change over to a normal entity right at the point of impact
- nent->s.eType = ET_GENERAL;
- ent->s.eType = ET_GRAPPLE;
-
- G_SetOrigin( ent, v );
- G_SetOrigin( nent, v );
-
- ent->think = Weapon_HookThink;
- ent->nextthink = level.time + FRAMETIME;
-
- ent->parent->client->ps.pm_flags |= PMF_GRAPPLE_PULL;
- VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);
-
- trap_LinkEntity( ent );
- trap_LinkEntity( nent );
-
- return;
- }
-
- // is it cheaper in bandwidth to just remove this ent and create a new
- // one, rather than changing the missile into the explosion?
-
- if ( other->takedamage && other->client ) {
- G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
- ent->s.otherEntityNum = other->s.number;
- } else if( trace->surfaceFlags & SURF_METALSTEPS ) {
- G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
- } else {
- G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
- }
-
- ent->freeAfterEvent = qtrue;
-
- // change over to a normal entity right at the point of impact
- ent->s.eType = ET_GENERAL;
-
- SnapVectorTowards( trace->endpos, ent->s.pos.trBase ); // save net bandwidth
-
- G_SetOrigin( ent, trace->endpos );
-
- // splash damage (doesn't apply to person directly hit)
- if ( ent->splashDamage ) {
- if( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
- other, ent->splashMethodOfDeath ) ) {
- if( !hitClient ) {
- g_entities[ent->r.ownerNum].client->accuracy_hits++;
- }
- }
- }
-
- trap_LinkEntity( ent );
-}
-
-/*
-================
-G_RunMissile
-================
-*/
-void G_RunMissile( gentity_t *ent ) {
- vec3_t origin;
- trace_t tr;
- int passent;
-
- // get current position
- BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
-
- // if this missile bounced off an invulnerability sphere
- if ( ent->target_ent ) {
- passent = ent->target_ent->s.number;
- }
- // prox mines that left the owner bbox will attach to anything, even the owner
- else if (ent->s.weapon == WP_PROX_LAUNCHER && ent->count) {
- passent = ENTITYNUM_NONE;
- }
- else {
- // ignore interactions with the missile owner
- passent = ent->r.ownerNum;
- }
- // trace a line from the previous position to the current position
- trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );
-
- if ( tr.startsolid || tr.allsolid ) {
- // make sure the tr.entityNum is set to the entity we're stuck in
- trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask );
- tr.fraction = 0;
- }
- else {
- VectorCopy( tr.endpos, ent->r.currentOrigin );
- }
-
- trap_LinkEntity( ent );
-
- if ( tr.fraction != 1 ) {
- // never explode or bounce on sky
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- // If grapple, reset owner
- if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {
- ent->parent->client->hook = NULL;
- }
- G_FreeEntity( ent );
- return;
- }
- G_MissileImpact( ent, &tr );
- if ( ent->s.eType != ET_MISSILE ) {
- return; // exploded
- }
- }
- // if the prox mine wasn't yet outside the player body
- if (ent->s.weapon == WP_PROX_LAUNCHER && !ent->count) {
- // check if the prox mine is outside the owner bbox
- trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, ENTITYNUM_NONE, ent->clipmask );
- if (!tr.startsolid || tr.entityNum != ent->r.ownerNum) {
- ent->count = 1;
- }
- }
- // check think function after bouncing
- G_RunThink( ent );
-}
-
-
-//=============================================================================
-
-/*
-=================
-fire_plasma
-
-=================
-*/
-gentity_t *fire_plasma (gentity_t *self, vec3_t start, vec3_t dir) {
- gentity_t *bolt;
-
- VectorNormalize (dir);
-
- bolt = G_Spawn();
- bolt->classname = "plasma";
- bolt->nextthink = level.time + 10000;
- bolt->think = G_ExplodeMissile;
- bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- bolt->s.weapon = WP_PLASMAGUN;
- bolt->r.ownerNum = self->s.number;
-//unlagged - projectile nudge
- // we'll need this for nudging projectiles later
- bolt->s.otherEntityNum = self->s.number;
-//unlagged - projectile nudge
- bolt->parent = self;
- bolt->damage = 20;
- bolt->splashDamage = 15;
- bolt->splashRadius = 20;
- bolt->methodOfDeath = MOD_PLASMA;
- bolt->splashMethodOfDeath = MOD_PLASMA_SPLASH;
- bolt->clipmask = MASK_SHOT;
- bolt->target_ent = NULL;
-
- bolt->s.pos.trType = TR_LINEAR;
- bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
- VectorCopy( start, bolt->s.pos.trBase );
- VectorScale( dir, 2000, bolt->s.pos.trDelta );
- SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
-
- VectorCopy (start, bolt->r.currentOrigin);
-
- return bolt;
-}
-
-//=============================================================================
-
-
-/*
-=================
-fire_grenade
-=================
-*/
-gentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t dir) {
- gentity_t *bolt;
-
- VectorNormalize (dir);
-
- bolt = G_Spawn();
- bolt->classname = "grenade";
- bolt->nextthink = level.time + 2500;
- bolt->think = G_ExplodeMissile;
- bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- bolt->s.weapon = WP_GRENADE_LAUNCHER;
- bolt->s.eFlags = EF_BOUNCE_HALF;
- bolt->r.ownerNum = self->s.number;
-//unlagged - projectile nudge
- // we'll need this for nudging projectiles later
- bolt->s.otherEntityNum = self->s.number;
-//unlagged - projectile nudge
- bolt->parent = self;
- bolt->damage = 100;
- bolt->splashDamage = 100;
- bolt->splashRadius = 150;
- bolt->methodOfDeath = MOD_GRENADE;
- bolt->splashMethodOfDeath = MOD_GRENADE_SPLASH;
- bolt->clipmask = MASK_SHOT;
- bolt->target_ent = NULL;
-
- bolt->s.pos.trType = TR_GRAVITY;
- bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
- VectorCopy( start, bolt->s.pos.trBase );
- VectorScale( dir, 700, bolt->s.pos.trDelta );
- SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
-
- VectorCopy (start, bolt->r.currentOrigin);
-
- return bolt;
-}
-
-//=============================================================================
-
-
-/*
-=================
-fire_bfg
-=================
-*/
-gentity_t *fire_bfg (gentity_t *self, vec3_t start, vec3_t dir) {
- gentity_t *bolt;
-
- VectorNormalize (dir);
-
- bolt = G_Spawn();
- bolt->classname = "bfg";
- bolt->nextthink = level.time + 10000;
- bolt->think = G_ExplodeMissile;
- bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- bolt->s.weapon = WP_BFG;
- bolt->r.ownerNum = self->s.number;
-//unlagged - projectile nudge
- // we'll need this for nudging projectiles later
- bolt->s.otherEntityNum = self->s.number;
-//unlagged - projectile nudge
- bolt->parent = self;
- bolt->damage = 100;
- bolt->splashDamage = 100;
- bolt->splashRadius = 120;
- bolt->methodOfDeath = MOD_BFG;
- bolt->splashMethodOfDeath = MOD_BFG_SPLASH;
- bolt->clipmask = MASK_SHOT;
- bolt->target_ent = NULL;
-
- bolt->s.pos.trType = TR_LINEAR;
- bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
- VectorCopy( start, bolt->s.pos.trBase );
- VectorScale( dir, 2000, bolt->s.pos.trDelta );
- SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
- VectorCopy (start, bolt->r.currentOrigin);
-
- return bolt;
-}
-
-//=============================================================================
-
-
-/*
-=================
-fire_rocket
-=================
-*/
-gentity_t *fire_rocket (gentity_t *self, vec3_t start, vec3_t dir) {
- gentity_t *bolt;
-
- VectorNormalize (dir);
-
- bolt = G_Spawn();
- bolt->classname = "rocket";
- bolt->nextthink = level.time + 15000;
- bolt->think = G_ExplodeMissile;
- bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- bolt->s.weapon = WP_ROCKET_LAUNCHER;
- bolt->r.ownerNum = self->s.number;
-//unlagged - projectile nudge
- // we'll need this for nudging projectiles later
- bolt->s.otherEntityNum = self->s.number;
-//unlagged - projectile nudge
- bolt->parent = self;
- bolt->damage = 100;
- bolt->splashDamage = 100;
- bolt->splashRadius = 120;
- bolt->methodOfDeath = MOD_ROCKET;
- bolt->splashMethodOfDeath = MOD_ROCKET_SPLASH;
- bolt->clipmask = MASK_SHOT;
- bolt->target_ent = NULL;
-
- bolt->s.pos.trType = TR_LINEAR;
- bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
- VectorCopy( start, bolt->s.pos.trBase );
- VectorScale( dir, 900, bolt->s.pos.trDelta );
- SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
- VectorCopy (start, bolt->r.currentOrigin);
-
- return bolt;
-}
-
-/*
-=================
-fire_grapple
-=================
-*/
-gentity_t *fire_grapple (gentity_t *self, vec3_t start, vec3_t dir) {
- gentity_t *hook;
-//unlagged - grapple
- int hooktime;
-//unlagged - grapple
-
- VectorNormalize (dir);
-
- hook = G_Spawn();
- hook->classname = "hook";
- hook->nextthink = level.time + 10000;
- hook->think = Weapon_HookFree;
- hook->s.eType = ET_MISSILE;
- hook->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- hook->s.weapon = WP_GRAPPLING_HOOK;
- hook->r.ownerNum = self->s.number;
- hook->methodOfDeath = MOD_GRAPPLE;
- hook->clipmask = MASK_SHOT;
- hook->parent = self;
- hook->target_ent = NULL;
-
-//unlagged - grapple
- // we might want this later
- hook->s.otherEntityNum = self->s.number;
-
- // setting the projectile base time back makes the hook's first
- // step larger
-
- if ( self->client ) {
- hooktime = self->client->pers.cmd.serverTime + 50;
- }
- else {
- hooktime = level.time - MISSILE_PRESTEP_TIME;
- }
-
- hook->s.pos.trTime = hooktime;
-//unlagged - grapple
-
- hook->s.pos.trType = TR_LINEAR;
-//unlagged - grapple
- //hook->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
-//unlagged - grapple
- hook->s.otherEntityNum = self->s.number; // use to match beam in client
- VectorCopy( start, hook->s.pos.trBase );
- VectorScale( dir, 800, hook->s.pos.trDelta );
- SnapVector( hook->s.pos.trDelta ); // save net bandwidth
- VectorCopy (start, hook->r.currentOrigin);
-
- self->client->hook = hook;
-
- return hook;
-}
-
-/*
-=================
-fire_nail
-=================
-*/
-#define NAILGUN_SPREAD 500
-
-gentity_t *fire_nail( gentity_t *self, vec3_t start, vec3_t forward, vec3_t right, vec3_t up ) {
- gentity_t *bolt;
- vec3_t dir;
- vec3_t end;
- float r, u, scale;
-
- bolt = G_Spawn();
- bolt->classname = "nail";
- bolt->nextthink = level.time + 10000;
- bolt->think = G_ExplodeMissile;
- bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- bolt->s.weapon = WP_NAILGUN;
- bolt->r.ownerNum = self->s.number;
-//unlagged - projectile nudge
- // we'll need this for nudging projectiles later
- bolt->s.otherEntityNum = self->s.number;
-//unlagged - projectile nudge
- bolt->parent = self;
- bolt->damage = 20;
- bolt->methodOfDeath = MOD_NAIL;
- bolt->clipmask = MASK_SHOT;
- bolt->target_ent = NULL;
-
- bolt->s.pos.trType = TR_LINEAR;
- bolt->s.pos.trTime = level.time;
- VectorCopy( start, bolt->s.pos.trBase );
-
- r = random() * M_PI * 2.0f;
- u = sin(r) * crandom() * NAILGUN_SPREAD * 16;
- r = cos(r) * crandom() * NAILGUN_SPREAD * 16;
- VectorMA( start, 8192 * 16, forward, end);
- VectorMA (end, r, right, end);
- VectorMA (end, u, up, end);
- VectorSubtract( end, start, dir );
- VectorNormalize( dir );
-
- scale = 555 + random() * 1800;
- VectorScale( dir, scale, bolt->s.pos.trDelta );
- SnapVector( bolt->s.pos.trDelta );
-
- VectorCopy( start, bolt->r.currentOrigin );
-
- return bolt;
-}
-
-
-/*
-=================
-fire_prox
-=================
-*/
-gentity_t *fire_prox( gentity_t *self, vec3_t start, vec3_t dir ) {
- gentity_t *bolt;
-
- VectorNormalize (dir);
-
- bolt = G_Spawn();
- bolt->classname = "prox mine";
- bolt->nextthink = level.time + 3000;
- bolt->think = G_ExplodeMissile;
- bolt->s.eType = ET_MISSILE;
- bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- bolt->s.weapon = WP_PROX_LAUNCHER;
- bolt->s.eFlags = 0;
- bolt->r.ownerNum = self->s.number;
-//unlagged - projectile nudge
- // we'll need this for nudging projectiles later
- bolt->s.otherEntityNum = self->s.number;
-//unlagged - projectile nudge
- bolt->parent = self;
- bolt->damage = 0;
- bolt->splashDamage = 100;
- bolt->splashRadius = 150;
- bolt->methodOfDeath = MOD_PROXIMITY_MINE;
- bolt->splashMethodOfDeath = MOD_PROXIMITY_MINE;
- bolt->clipmask = MASK_SHOT;
- bolt->target_ent = NULL;
- // count is used to check if the prox mine left the player bbox
- // if count == 1 then the prox mine left the player bbox and can attack to it
- bolt->count = 0;
-
- //FIXME: we prolly wanna abuse another field
- bolt->s.generic1 = self->client->sess.sessionTeam;
-
- bolt->s.pos.trType = TR_GRAVITY;
- bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
- VectorCopy( start, bolt->s.pos.trBase );
- VectorScale( dir, 700, bolt->s.pos.trDelta );
- SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
-
- VectorCopy (start, bolt->r.currentOrigin);
-
- return bolt;
-}
diff --git a/game/code/game/g_mover.c b/game/code/game/g_mover.c
deleted file mode 100644
index 52183b9..0000000
--- a/game/code/game/g_mover.c
+++ /dev/null
@@ -1,1633 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-#include "g_local.h"
-
-
-
-/*
-===============================================================================
-
-PUSHMOVE
-
-===============================================================================
-*/
-
-void MatchTeam( gentity_t *teamLeader, int moverState, int time );
-
-typedef struct {
- gentity_t *ent;
- vec3_t origin;
- vec3_t angles;
- float deltayaw;
-} pushed_t;
-pushed_t pushed[MAX_GENTITIES], *pushed_p;
-
-
-/*
-============
-G_TestEntityPosition
-
-============
-*/
-gentity_t *G_TestEntityPosition( gentity_t *ent ) {
- trace_t tr;
- int mask;
-
- if ( ent->clipmask ) {
- mask = ent->clipmask;
- } else {
- mask = MASK_SOLID;
- }
- if ( ent->client ) {
- trap_Trace( &tr, ent->client->ps.origin, ent->r.mins, ent->r.maxs, ent->client->ps.origin, ent->s.number, mask );
- } else {
- trap_Trace( &tr, ent->s.pos.trBase, ent->r.mins, ent->r.maxs, ent->s.pos.trBase, ent->s.number, mask );
- }
-
- if (tr.startsolid)
- return &g_entities[ tr.entityNum ];
-
- return NULL;
-}
-
-/*
-================
-G_CreateRotationMatrix
-================
-*/
-void G_CreateRotationMatrix(vec3_t angles, vec3_t matrix[3]) {
- AngleVectors(angles, matrix[0], matrix[1], matrix[2]);
- VectorInverse(matrix[1]);
-}
-
-/*
-================
-G_TransposeMatrix
-================
-*/
-void G_TransposeMatrix(vec3_t matrix[3], vec3_t transpose[3]) {
- int i, j;
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 3; j++) {
- transpose[i][j] = matrix[j][i];
- }
- }
-}
-
-/*
-================
-G_RotatePoint
-================
-*/
-void G_RotatePoint(vec3_t point, vec3_t matrix[3]) {
- vec3_t tvec;
-
- VectorCopy(point, tvec);
- point[0] = DotProduct(matrix[0], tvec);
- point[1] = DotProduct(matrix[1], tvec);
- point[2] = DotProduct(matrix[2], tvec);
-}
-
-/*
-==================
-G_TryPushingEntity
-
-Returns qfalse if the move is blocked
-==================
-*/
-qboolean G_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, vec3_t amove ) {
- vec3_t matrix[3], transpose[3];
- vec3_t org, org2, move2;
- gentity_t *block;
-
- // EF_MOVER_STOP will just stop when contacting another entity
- // instead of pushing it, but entities can still ride on top of it
- if ( ( pusher->s.eFlags & EF_MOVER_STOP ) &&
- check->s.groundEntityNum != pusher->s.number ) {
- return qfalse;
- }
-
- // save off the old position
- if (pushed_p > &pushed[MAX_GENTITIES]) {
- G_Error( "pushed_p > &pushed[MAX_GENTITIES]" );
- }
- pushed_p->ent = check;
- VectorCopy (check->s.pos.trBase, pushed_p->origin);
- VectorCopy (check->s.apos.trBase, pushed_p->angles);
- if ( check->client ) {
- pushed_p->deltayaw = check->client->ps.delta_angles[YAW];
- VectorCopy (check->client->ps.origin, pushed_p->origin);
- }
- pushed_p++;
-
- // try moving the contacted entity
- // figure movement due to the pusher's amove
- G_CreateRotationMatrix( amove, transpose );
- G_TransposeMatrix( transpose, matrix );
- if ( check->client ) {
- VectorSubtract (check->client->ps.origin, pusher->r.currentOrigin, org);
- }
- else {
- VectorSubtract (check->s.pos.trBase, pusher->r.currentOrigin, org);
- }
- VectorCopy( org, org2 );
- G_RotatePoint( org2, matrix );
- VectorSubtract (org2, org, move2);
- // add movement
- VectorAdd (check->s.pos.trBase, move, check->s.pos.trBase);
- VectorAdd (check->s.pos.trBase, move2, check->s.pos.trBase);
- if ( check->client ) {
- VectorAdd (check->client->ps.origin, move, check->client->ps.origin);
- VectorAdd (check->client->ps.origin, move2, check->client->ps.origin);
- // make sure the client's view rotates when on a rotating mover
- check->client->ps.delta_angles[YAW] += ANGLE2SHORT(amove[YAW]);
- }
-
- // may have pushed them off an edge
- if ( check->s.groundEntityNum != pusher->s.number ) {
- check->s.groundEntityNum = -1;
- }
-
- block = G_TestEntityPosition( check );
- if (!block) {
- // pushed ok
- if ( check->client ) {
- VectorCopy( check->client->ps.origin, check->r.currentOrigin );
- } else {
- VectorCopy( check->s.pos.trBase, check->r.currentOrigin );
- }
- trap_LinkEntity (check);
- return qtrue;
- }
-
- // if it is ok to leave in the old position, do it
- // this is only relevent for riding entities, not pushed
- // Sliding trapdoors can cause this.
- VectorCopy( (pushed_p-1)->origin, check->s.pos.trBase);
- if ( check->client ) {
- VectorCopy( (pushed_p-1)->origin, check->client->ps.origin);
- }
- VectorCopy( (pushed_p-1)->angles, check->s.apos.trBase );
- block = G_TestEntityPosition (check);
- if ( !block ) {
- check->s.groundEntityNum = -1;
- pushed_p--;
- return qtrue;
- }
-
- // blocked
- return qfalse;
-}
-
-/*
-==================
-G_CheckProxMinePosition
-==================
-*/
-qboolean G_CheckProxMinePosition( gentity_t *check ) {
- vec3_t start, end;
- trace_t tr;
-
- VectorMA(check->s.pos.trBase, 0.125, check->movedir, start);
- VectorMA(check->s.pos.trBase, 2, check->movedir, end);
- trap_Trace( &tr, start, NULL, NULL, end, check->s.number, MASK_SOLID );
-
- if (tr.startsolid || tr.fraction < 1)
- return qfalse;
-
- return qtrue;
-}
-
-/*
-==================
-G_TryPushingProxMine
-==================
-*/
-qboolean G_TryPushingProxMine( gentity_t *check, gentity_t *pusher, vec3_t move, vec3_t amove ) {
- vec3_t forward, right, up;
- vec3_t org, org2, move2;
- int ret;
-
- // we need this for pushing things later
- VectorSubtract (vec3_origin, amove, org);
- AngleVectors (org, forward, right, up);
-
- // try moving the contacted entity
- VectorAdd (check->s.pos.trBase, move, check->s.pos.trBase);
-
- // figure movement due to the pusher's amove
- VectorSubtract (check->s.pos.trBase, pusher->r.currentOrigin, org);
- org2[0] = DotProduct (org, forward);
- org2[1] = -DotProduct (org, right);
- org2[2] = DotProduct (org, up);
- VectorSubtract (org2, org, move2);
- VectorAdd (check->s.pos.trBase, move2, check->s.pos.trBase);
-
- ret = G_CheckProxMinePosition( check );
- if (ret) {
- VectorCopy( check->s.pos.trBase, check->r.currentOrigin );
- trap_LinkEntity (check);
- }
- return ret;
-}
-
-void G_ExplodeMissile( gentity_t *ent );
-
-/*
-============
-G_MoverPush
-
-Objects need to be moved back on a failed push,
-otherwise riders would continue to slide.
-If qfalse is returned, *obstacle will be the blocking entity
-============
-*/
-qboolean G_MoverPush( gentity_t *pusher, vec3_t move, vec3_t amove, gentity_t **obstacle ) {
- int i, e;
- gentity_t *check;
- vec3_t mins, maxs;
- pushed_t *p;
- int entityList[MAX_GENTITIES];
- int listedEntities;
- vec3_t totalMins, totalMaxs;
-
- *obstacle = NULL;
-
-
- // mins/maxs are the bounds at the destination
- // totalMins / totalMaxs are the bounds for the entire move
- if ( pusher->r.currentAngles[0] || pusher->r.currentAngles[1] || pusher->r.currentAngles[2]
- || amove[0] || amove[1] || amove[2] ) {
- float radius;
-
- radius = RadiusFromBounds( pusher->r.mins, pusher->r.maxs );
- for ( i = 0 ; i < 3 ; i++ ) {
- mins[i] = pusher->r.currentOrigin[i] + move[i] - radius;
- maxs[i] = pusher->r.currentOrigin[i] + move[i] + radius;
- totalMins[i] = mins[i] - move[i];
- totalMaxs[i] = maxs[i] - move[i];
- }
- } else {
- for (i=0 ; i<3 ; i++) {
- mins[i] = pusher->r.absmin[i] + move[i];
- maxs[i] = pusher->r.absmax[i] + move[i];
- }
-
- VectorCopy( pusher->r.absmin, totalMins );
- VectorCopy( pusher->r.absmax, totalMaxs );
- for (i=0 ; i<3 ; i++) {
- if ( move[i] > 0 ) {
- totalMaxs[i] += move[i];
- } else {
- totalMins[i] += move[i];
- }
- }
- }
-
- // unlink the pusher so we don't get it in the entityList
- trap_UnlinkEntity( pusher );
-
- listedEntities = trap_EntitiesInBox( totalMins, totalMaxs, entityList, MAX_GENTITIES );
-
- // move the pusher to it's final position
- VectorAdd( pusher->r.currentOrigin, move, pusher->r.currentOrigin );
- VectorAdd( pusher->r.currentAngles, amove, pusher->r.currentAngles );
- trap_LinkEntity( pusher );
-
- // see if any solid entities are inside the final position
- for ( e = 0 ; e < listedEntities ; e++ ) {
- check = &g_entities[ entityList[ e ] ];
-
- if ( check->s.eType == ET_MISSILE ) {
- // if it is a prox mine
- if ( !strcmp(check->classname, "prox mine") ) {
- // if this prox mine is attached to this mover try to move it with the pusher
- if ( check->enemy == pusher ) {
- if (!G_TryPushingProxMine( check, pusher, move, amove )) {
- //explode
- check->s.loopSound = 0;
- G_AddEvent( check, EV_PROXIMITY_MINE_TRIGGER, 0 );
- G_ExplodeMissile(check);
- if (check->activator) {
- G_FreeEntity(check->activator);
- check->activator = NULL;
- }
- //G_Printf("prox mine explodes\n");
- }
- }
- else {
- //check if the prox mine is crushed by the mover
- if (!G_CheckProxMinePosition( check )) {
- //explode
- check->s.loopSound = 0;
- G_AddEvent( check, EV_PROXIMITY_MINE_TRIGGER, 0 );
- G_ExplodeMissile(check);
- if (check->activator) {
- G_FreeEntity(check->activator);
- check->activator = NULL;
- }
- //G_Printf("prox mine explodes\n");
- }
- }
- continue;
- }
- }
- // only push items and players
- if ( check->s.eType != ET_ITEM && check->s.eType != ET_PLAYER && !check->physicsObject ) {
- continue;
- }
-
- // if the entity is standing on the pusher, it will definitely be moved
- if ( check->s.groundEntityNum != pusher->s.number ) {
- // see if the ent needs to be tested
- if ( check->r.absmin[0] >= maxs[0]
- || check->r.absmin[1] >= maxs[1]
- || check->r.absmin[2] >= maxs[2]
- || check->r.absmax[0] <= mins[0]
- || check->r.absmax[1] <= mins[1]
- || check->r.absmax[2] <= mins[2] ) {
- continue;
- }
- // see if the ent's bbox is inside the pusher's final position
- // this does allow a fast moving object to pass through a thin entity...
- if (!G_TestEntityPosition (check)) {
- continue;
- }
- }
-
- // the entity needs to be pushed
- if ( G_TryPushingEntity( check, pusher, move, amove ) ) {
- continue;
- }
-
- // the move was blocked an entity
-
- // bobbing entities are instant-kill and never get blocked
- if ( pusher->s.pos.trType == TR_SINE || pusher->s.apos.trType == TR_SINE ) {
- G_Damage( check, pusher, pusher, NULL, NULL, 99999, 0, MOD_CRUSH );
- continue;
- }
-
-
- // save off the obstacle so we can call the block function (crush, etc)
- *obstacle = check;
-
- // move back any entities we already moved
- // go backwards, so if the same entity was pushed
- // twice, it goes back to the original position
- for ( p=pushed_p-1 ; p>=pushed ; p-- ) {
- VectorCopy (p->origin, p->ent->s.pos.trBase);
- VectorCopy (p->angles, p->ent->s.apos.trBase);
- if ( p->ent->client ) {
- p->ent->client->ps.delta_angles[YAW] = p->deltayaw;
- VectorCopy (p->origin, p->ent->client->ps.origin);
- }
- trap_LinkEntity (p->ent);
- }
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-=================
-G_MoverTeam
-=================
-*/
-void G_MoverTeam( gentity_t *ent ) {
- vec3_t move, amove;
- gentity_t *part, *obstacle;
- vec3_t origin, angles;
-
- obstacle = NULL;
-
- // make sure all team slaves can move before commiting
- // any moves or calling any think functions
- // if the move is blocked, all moved objects will be backed out
- pushed_p = pushed;
- for (part = ent ; part ; part=part->teamchain) {
- // get current position
- BG_EvaluateTrajectory( &part->s.pos, level.time, origin );
- BG_EvaluateTrajectory( &part->s.apos, level.time, angles );
- VectorSubtract( origin, part->r.currentOrigin, move );
- VectorSubtract( angles, part->r.currentAngles, amove );
- if ( !G_MoverPush( part, move, amove, &obstacle ) ) {
- break; // move was blocked
- }
- }
-
- if (part) {
- // go back to the previous position
- for ( part = ent ; part ; part = part->teamchain ) {
- part->s.pos.trTime += level.time - level.previousTime;
- part->s.apos.trTime += level.time - level.previousTime;
- BG_EvaluateTrajectory( &part->s.pos, level.time, part->r.currentOrigin );
- BG_EvaluateTrajectory( &part->s.apos, level.time, part->r.currentAngles );
- trap_LinkEntity( part );
- }
-
- // if the pusher has a "blocked" function, call it
- if (ent->blocked) {
- ent->blocked( ent, obstacle );
- }
- return;
- }
-
- // the move succeeded
- for ( part = ent ; part ; part = part->teamchain ) {
- // call the reached function if time is at or past end point
- if ( part->s.pos.trType == TR_LINEAR_STOP ) {
- if ( level.time >= part->s.pos.trTime + part->s.pos.trDuration ) {
- if ( part->reached ) {
- part->reached( part );
- }
- }
- }
- }
-}
-
-/*
-================
-G_RunMover
-
-================
-*/
-void G_RunMover( gentity_t *ent ) {
- // if not a team captain, don't do anything, because
- // the captain will handle everything
- if ( ent->flags & FL_TEAMSLAVE ) {
- return;
- }
-
- // if stationary at one of the positions, don't move anything
- if ( ent->s.pos.trType != TR_STATIONARY || ent->s.apos.trType != TR_STATIONARY ) {
- G_MoverTeam( ent );
- }
-
- // check think function
- G_RunThink( ent );
-}
-
-/*
-============================================================================
-
-GENERAL MOVERS
-
-Doors, plats, and buttons are all binary (two position) movers
-Pos1 is "at rest", pos2 is "activated"
-============================================================================
-*/
-
-/*
-===============
-SetMoverState
-===============
-*/
-void SetMoverState( gentity_t *ent, moverState_t moverState, int time ) {
- vec3_t delta;
- float f;
-
- ent->moverState = moverState;
-
- ent->s.pos.trTime = time;
- switch( moverState ) {
- case MOVER_POS1:
- VectorCopy( ent->pos1, ent->s.pos.trBase );
- ent->s.pos.trType = TR_STATIONARY;
- break;
- case MOVER_POS2:
- VectorCopy( ent->pos2, ent->s.pos.trBase );
- ent->s.pos.trType = TR_STATIONARY;
- break;
- case MOVER_1TO2:
- VectorCopy( ent->pos1, ent->s.pos.trBase );
- VectorSubtract( ent->pos2, ent->pos1, delta );
- f = 1000.0 / ent->s.pos.trDuration;
- VectorScale( delta, f, ent->s.pos.trDelta );
- ent->s.pos.trType = TR_LINEAR_STOP;
- break;
- case MOVER_2TO1:
- VectorCopy( ent->pos2, ent->s.pos.trBase );
- VectorSubtract( ent->pos1, ent->pos2, delta );
- f = 1000.0 / ent->s.pos.trDuration;
- VectorScale( delta, f, ent->s.pos.trDelta );
- ent->s.pos.trType = TR_LINEAR_STOP;
- break;
- }
- BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin );
- trap_LinkEntity( ent );
-}
-
-/*
-================
-MatchTeam
-
-All entities in a mover team will move from pos1 to pos2
-in the same amount of time
-================
-*/
-void MatchTeam( gentity_t *teamLeader, int moverState, int time ) {
- gentity_t *slave;
-
- for ( slave = teamLeader ; slave ; slave = slave->teamchain ) {
- SetMoverState( slave, moverState, time );
- }
-}
-
-
-
-/*
-================
-ReturnToPos1
-================
-*/
-void ReturnToPos1( gentity_t *ent ) {
- MatchTeam( ent, MOVER_2TO1, level.time );
-
- // looping sound
- ent->s.loopSound = ent->soundLoop;
-
- // starting sound
- if ( ent->sound2to1 ) {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
- }
-}
-
-
-/*
-================
-Reached_BinaryMover
-================
-*/
-void Reached_BinaryMover( gentity_t *ent ) {
-
- // stop the looping sound
- ent->s.loopSound = ent->soundLoop;
-
- if ( ent->moverState == MOVER_1TO2 ) {
- // reached pos2
- SetMoverState( ent, MOVER_POS2, level.time );
-
- // play sound
- if ( ent->soundPos2 ) {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos2 );
- }
-
- // return to pos1 after a delay
- ent->think = ReturnToPos1;
- ent->nextthink = level.time + ent->wait;
-
- // fire targets
- if ( !ent->activator ) {
- ent->activator = ent;
- }
- G_UseTargets( ent, ent->activator );
- } else if ( ent->moverState == MOVER_2TO1 ) {
- // reached pos1
- SetMoverState( ent, MOVER_POS1, level.time );
-
- // play sound
- if ( ent->soundPos1 ) {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos1 );
- }
-
- // close areaportals
- if ( ent->teammaster == ent || !ent->teammaster ) {
- trap_AdjustAreaPortalState( ent, qfalse );
- }
- } else {
- G_Error( "Reached_BinaryMover: bad moverState" );
- }
-}
-
-
-/*
-================
-Use_BinaryMover
-================
-*/
-void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
- int total;
- int partial;
-
- // only the master should be used
- if ( ent->flags & FL_TEAMSLAVE ) {
- Use_BinaryMover( ent->teammaster, other, activator );
- return;
- }
-
- ent->activator = activator;
-
- if ( ent->moverState == MOVER_POS1 ) {
- // start moving 50 msec later, becase if this was player
- // triggered, level.time hasn't been advanced yet
- MatchTeam( ent, MOVER_1TO2, level.time + 50 );
-
- // starting sound
- if ( ent->sound1to2 ) {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );
- }
-
- // looping sound
- ent->s.loopSound = ent->soundLoop;
-
- // open areaportal
- if ( ent->teammaster == ent || !ent->teammaster ) {
- trap_AdjustAreaPortalState( ent, qtrue );
- }
- return;
- }
-
- // if all the way up, just delay before coming down
- if ( ent->moverState == MOVER_POS2 ) {
- ent->nextthink = level.time + ent->wait;
- return;
- }
-
- // only partway down before reversing
- if ( ent->moverState == MOVER_2TO1 ) {
- total = ent->s.pos.trDuration;
- partial = level.time - ent->s.pos.trTime;
- if ( partial > total ) {
- partial = total;
- }
-
- MatchTeam( ent, MOVER_1TO2, level.time - ( total - partial ) );
-
- if ( ent->sound1to2 ) {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );
- }
- return;
- }
-
- // only partway up before reversing
- if ( ent->moverState == MOVER_1TO2 ) {
- total = ent->s.pos.trDuration;
- partial = level.time - ent->s.pos.trTime;
- if ( partial > total ) {
- partial = total;
- }
-
- MatchTeam( ent, MOVER_2TO1, level.time - ( total - partial ) );
-
- if ( ent->sound2to1 ) {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
- }
- return;
- }
-}
-
-
-
-/*
-================
-InitMover
-
-"pos1", "pos2", and "speed" should be set before calling,
-so the movement delta can be calculated
-================
-*/
-void InitMover( gentity_t *ent ) {
- vec3_t move;
- float distance;
- float light;
- vec3_t color;
- qboolean lightSet, colorSet;
- char *sound;
-
- // if the "model2" key is set, use a seperate model
- // for drawing, but clip against the brushes
- if ( ent->model2 ) {
- ent->s.modelindex2 = G_ModelIndex( ent->model2 );
- }
-
- // if the "loopsound" key is set, use a constant looping sound when moving
- if ( G_SpawnString( "noise", "100", &sound ) ) {
- ent->s.loopSound = G_SoundIndex( sound );
- }
-
- // if the "color" or "light" keys are set, setup constantLight
- lightSet = G_SpawnFloat( "light", "100", &light );
- colorSet = G_SpawnVector( "color", "1 1 1", color );
- if ( lightSet || colorSet ) {
- int r, g, b, i;
-
- r = color[0] * 255;
- if ( r > 255 ) {
- r = 255;
- }
- g = color[1] * 255;
- if ( g > 255 ) {
- g = 255;
- }
- b = color[2] * 255;
- if ( b > 255 ) {
- b = 255;
- }
- i = light / 4;
- if ( i > 255 ) {
- i = 255;
- }
- ent->s.constantLight = r | ( g << 8 ) | ( b << 16 ) | ( i << 24 );
- }
-
-
- ent->use = Use_BinaryMover;
- ent->reached = Reached_BinaryMover;
-
- ent->moverState = MOVER_POS1;
- ent->r.svFlags = SVF_USE_CURRENT_ORIGIN;
- ent->s.eType = ET_MOVER;
- VectorCopy (ent->pos1, ent->r.currentOrigin);
- trap_LinkEntity (ent);
-
- ent->s.pos.trType = TR_STATIONARY;
- VectorCopy( ent->pos1, ent->s.pos.trBase );
-
- // calculate time to reach second position from speed
- VectorSubtract( ent->pos2, ent->pos1, move );
- distance = VectorLength( move );
- if ( ! ent->speed ) {
- ent->speed = 100;
- }
- VectorScale( move, ent->speed, ent->s.pos.trDelta );
- ent->s.pos.trDuration = distance * 1000 / ent->speed;
- if ( ent->s.pos.trDuration <= 0 ) {
- ent->s.pos.trDuration = 1;
- }
-}
-
-
-/*
-===============================================================================
-
-DOOR
-
-A use can be triggered either by a touch function, by being shot, or by being
-targeted by another entity.
-
-===============================================================================
-*/
-
-/*
-================
-Blocked_Door
-================
-*/
-void Blocked_Door( gentity_t *ent, gentity_t *other ) {
- // remove anything other than a client
- if ( !other->client ) {
- // except CTF flags!!!!
- if( other->s.eType == ET_ITEM && other->item->giType == IT_TEAM ) {
- Team_DroppedFlagThink( other );
- return;
- }
- G_TempEntity( other->s.origin, EV_ITEM_POP );
- G_FreeEntity( other );
- return;
- }
-
- if ( ent->damage ) {
- if(g_awardpushing.integer)
- G_Damage( other, ent, ent->activator, NULL, NULL, ent->damage, 0, MOD_CRUSH );
- else
- G_Damage( other, ent, ent, NULL, NULL, ent->damage, 0, MOD_CRUSH );
-
- }
- if ( ent->spawnflags & 4 ) {
- return; // crushers don't reverse
- }
-
- // reverse direction
- Use_BinaryMover( ent, ent, other );
-}
-
-/*
-================
-Touch_DoorTriggerSpectator
-================
-*/
-static void Touch_DoorTriggerSpectator( gentity_t *ent, gentity_t *other, trace_t *trace ) {
- int i, axis;
- vec3_t origin, dir, angles;
-
- axis = ent->count;
- VectorClear(dir);
- if (fabs(other->s.origin[axis] - ent->r.absmax[axis]) <
- fabs(other->s.origin[axis] - ent->r.absmin[axis])) {
- origin[axis] = ent->r.absmin[axis] - 10;
- dir[axis] = -1;
- }
- else {
- origin[axis] = ent->r.absmax[axis] + 10;
- dir[axis] = 1;
- }
- for (i = 0; i < 3; i++) {
- if (i == axis) continue;
- origin[i] = (ent->r.absmin[i] + ent->r.absmax[i]) * 0.5;
- }
- vectoangles(dir, angles);
- TeleportPlayer(other, origin, angles );
-}
-
-/*
-================
-Touch_DoorTrigger
-================
-*/
-void Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace ) {
- if ( other->client && (other->client->sess.sessionTeam == TEAM_SPECTATOR || other->client->ps.pm_type == PM_SPECTATOR)) {
- // if the door is not open and not opening
- if ( ent->parent->moverState != MOVER_1TO2 &&
- ent->parent->moverState != MOVER_POS2) {
- Touch_DoorTriggerSpectator( ent, other, trace );
- }
- }
- else if ( ent->parent->moverState != MOVER_1TO2 ) {
- Use_BinaryMover( ent->parent, ent, other );
- }
-}
-
-
-/*
-======================
-Think_SpawnNewDoorTrigger
-
-All of the parts of a door have been spawned, so create
-a trigger that encloses all of them
-======================
-*/
-void Think_SpawnNewDoorTrigger( gentity_t *ent ) {
- gentity_t *other;
- vec3_t mins, maxs;
- int i, best;
-
- // set all of the slaves as shootable
- for ( other = ent ; other ; other = other->teamchain ) {
- other->takedamage = qtrue;
- }
-
- // find the bounds of everything on the team
- VectorCopy (ent->r.absmin, mins);
- VectorCopy (ent->r.absmax, maxs);
-
- for (other = ent->teamchain ; other ; other=other->teamchain) {
- AddPointToBounds (other->r.absmin, mins, maxs);
- AddPointToBounds (other->r.absmax, mins, maxs);
- }
-
- // find the thinnest axis, which will be the one we expand
- best = 0;
- for ( i = 1 ; i < 3 ; i++ ) {
- if ( maxs[i] - mins[i] < maxs[best] - mins[best] ) {
- best = i;
- }
- }
- maxs[best] += 120;
- mins[best] -= 120;
-
- // create a trigger with this size
- other = G_Spawn ();
- other->classname = "door_trigger";
- VectorCopy (mins, other->r.mins);
- VectorCopy (maxs, other->r.maxs);
- other->parent = ent;
- other->r.contents = CONTENTS_TRIGGER;
- other->touch = Touch_DoorTrigger;
- // remember the thinnest axis
- other->count = best;
- trap_LinkEntity (other);
-
- MatchTeam( ent, ent->moverState, level.time );
-}
-
-void Think_MatchTeam( gentity_t *ent ) {
- MatchTeam( ent, ent->moverState, level.time );
-}
-
-
-/*QUAKED func_door (0 .5 .8) ? START_OPEN x CRUSHER
-TOGGLE wait in both the start and end states for a trigger event.
-START_OPEN the door to moves to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
-NOMONSTER monsters will not trigger this door
-
-"model2" .md3 model to also draw
-"angle" determines the opening direction
-"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
-"speed" movement speed (100 default)
-"wait" wait before returning (3 default, -1 = never return)
-"lip" lip remaining at end of move (8 default)
-"dmg" damage to inflict when blocked (2 default)
-"color" constantLight color
-"light" constantLight radius
-"health" if set, the door must be shot open
-*/
-void SP_func_door (gentity_t *ent) {
- vec3_t abs_movedir;
- float distance;
- vec3_t size;
- float lip;
-
- ent->sound1to2 = ent->sound2to1 = G_SoundIndex("sound/movers/doors/dr1_strt.wav");
- ent->soundPos1 = ent->soundPos2 = G_SoundIndex("sound/movers/doors/dr1_end.wav");
-
- ent->blocked = Blocked_Door;
-
- // default speed of 400
- if (!ent->speed)
- ent->speed = 400;
-
- // default wait of 2 seconds
- if (!ent->wait)
- ent->wait = 2;
- ent->wait *= 1000;
-
- // default lip of 8 units
- G_SpawnFloat( "lip", "8", &lip );
-
- // default damage of 2 points
- G_SpawnInt( "dmg", "2", &ent->damage );
-
- // first position at start
- VectorCopy( ent->s.origin, ent->pos1 );
-
- // calculate second position
- trap_SetBrushModel( ent, ent->model );
- G_SetMovedir (ent->s.angles, ent->movedir);
- abs_movedir[0] = fabs(ent->movedir[0]);
- abs_movedir[1] = fabs(ent->movedir[1]);
- abs_movedir[2] = fabs(ent->movedir[2]);
- VectorSubtract( ent->r.maxs, ent->r.mins, size );
- distance = DotProduct( abs_movedir, size ) - lip;
- VectorMA( ent->pos1, distance, ent->movedir, ent->pos2 );
-
- // if "start_open", reverse position 1 and 2
- if ( ent->spawnflags & 1 ) {
- vec3_t temp;
-
- VectorCopy( ent->pos2, temp );
- VectorCopy( ent->s.origin, ent->pos2 );
- VectorCopy( temp, ent->pos1 );
- }
-
- InitMover( ent );
-
- ent->nextthink = level.time + FRAMETIME;
-
- if ( ! (ent->flags & FL_TEAMSLAVE ) ) {
- int health;
-
- G_SpawnInt( "health", "0", &health );
- if ( health ) {
- ent->takedamage = qtrue;
- }
- if ( ent->targetname || health ) {
- // non touch/shoot doors
- ent->think = Think_MatchTeam;
- } else {
- ent->think = Think_SpawnNewDoorTrigger;
- }
- }
-
-
-}
-
-/*
-===============================================================================
-
-PLAT
-
-===============================================================================
-*/
-
-/*
-==============
-Touch_Plat
-
-Don't allow decent if a living player is on it
-===============
-*/
-void Touch_Plat( gentity_t *ent, gentity_t *other, trace_t *trace ) {
- if ( !other->client || other->client->ps.stats[STAT_HEALTH] <= 0 ) {
- return;
- }
-
- // delay return-to-pos1 by one second
- if ( ent->moverState == MOVER_POS2 ) {
- ent->nextthink = level.time + 1000;
- }
-}
-
-/*
-==============
-Touch_PlatCenterTrigger
-
-If the plat is at the bottom position, start it going up
-===============
-*/
-void Touch_PlatCenterTrigger(gentity_t *ent, gentity_t *other, trace_t *trace ) {
- if ( !other->client ) {
- return;
- }
-
- if ( ent->parent->moverState == MOVER_POS1 ) {
- Use_BinaryMover( ent->parent, ent, other );
- }
-}
-
-
-/*
-================
-SpawnPlatTrigger
-
-Spawn a trigger in the middle of the plat's low position
-Elevator cars require that the trigger extend through the entire low position,
-not just sit on top of it.
-================
-*/
-void SpawnPlatTrigger( gentity_t *ent ) {
- gentity_t *trigger;
- vec3_t tmin, tmax;
-
- // the middle trigger will be a thin trigger just
- // above the starting position
- trigger = G_Spawn();
- trigger->classname = "plat_trigger";
- trigger->touch = Touch_PlatCenterTrigger;
- trigger->r.contents = CONTENTS_TRIGGER;
- trigger->parent = ent;
-
- tmin[0] = ent->pos1[0] + ent->r.mins[0] + 33;
- tmin[1] = ent->pos1[1] + ent->r.mins[1] + 33;
- tmin[2] = ent->pos1[2] + ent->r.mins[2];
-
- tmax[0] = ent->pos1[0] + ent->r.maxs[0] - 33;
- tmax[1] = ent->pos1[1] + ent->r.maxs[1] - 33;
- tmax[2] = ent->pos1[2] + ent->r.maxs[2] + 8;
-
- if ( tmax[0] <= tmin[0] ) {
- tmin[0] = ent->pos1[0] + (ent->r.mins[0] + ent->r.maxs[0]) *0.5;
- tmax[0] = tmin[0] + 1;
- }
- if ( tmax[1] <= tmin[1] ) {
- tmin[1] = ent->pos1[1] + (ent->r.mins[1] + ent->r.maxs[1]) *0.5;
- tmax[1] = tmin[1] + 1;
- }
-
- VectorCopy (tmin, trigger->r.mins);
- VectorCopy (tmax, trigger->r.maxs);
-
- trap_LinkEntity (trigger);
-}
-
-
-/*QUAKED func_plat (0 .5 .8) ?
-Plats are always drawn in the extended position so they will light correctly.
-
-"lip" default 8, protrusion above rest position
-"height" total height of movement, defaults to model height
-"speed" overrides default 200.
-"dmg" overrides default 2
-"model2" .md3 model to also draw
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_plat (gentity_t *ent) {
- float lip, height;
-
- ent->sound1to2 = ent->sound2to1 = G_SoundIndex("sound/movers/plats/pt1_strt.wav");
- ent->soundPos1 = ent->soundPos2 = G_SoundIndex("sound/movers/plats/pt1_end.wav");
-
- VectorClear (ent->s.angles);
-
- G_SpawnFloat( "speed", "200", &ent->speed );
- G_SpawnInt( "dmg", "2", &ent->damage );
- G_SpawnFloat( "wait", "1", &ent->wait );
- G_SpawnFloat( "lip", "8", &lip );
-
- ent->wait = 1000;
-
- // create second position
- trap_SetBrushModel( ent, ent->model );
-
- if ( !G_SpawnFloat( "height", "0", &height ) ) {
- height = (ent->r.maxs[2] - ent->r.mins[2]) - lip;
- }
-
- // pos1 is the rest (bottom) position, pos2 is the top
- VectorCopy( ent->s.origin, ent->pos2 );
- VectorCopy( ent->pos2, ent->pos1 );
- ent->pos1[2] -= height;
-
- InitMover( ent );
-
- // touch function keeps the plat from returning while
- // a live player is standing on it
- ent->touch = Touch_Plat;
-
- ent->blocked = Blocked_Door;
-
- ent->parent = ent; // so it can be treated as a door
-
- // spawn the trigger if one hasn't been custom made
- if ( !ent->targetname ) {
- SpawnPlatTrigger(ent);
- }
-}
-
-
-/*
-===============================================================================
-
-BUTTON
-
-===============================================================================
-*/
-
-/*
-==============
-Touch_Button
-
-===============
-*/
-void Touch_Button(gentity_t *ent, gentity_t *other, trace_t *trace ) {
- if ( !other->client ) {
- return;
- }
-
- if ( ent->moverState == MOVER_POS1 ) {
- Use_BinaryMover( ent, other, other );
- }
-}
-
-
-/*QUAKED func_button (0 .5 .8) ?
-When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
-
-"model2" .md3 model to also draw
-"angle" determines the opening direction
-"target" all entities with a matching targetname will be used
-"speed" override the default 40 speed
-"wait" override the default 1 second wait (-1 = never return)
-"lip" override the default 4 pixel lip remaining at end of move
-"health" if set, the button must be killed instead of touched
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_button( gentity_t *ent ) {
- vec3_t abs_movedir;
- float distance;
- vec3_t size;
- float lip;
-
- ent->sound1to2 = G_SoundIndex("sound/movers/switches/butn2.wav");
-
- if ( !ent->speed ) {
- ent->speed = 40;
- }
-
- if ( !ent->wait ) {
- ent->wait = 1;
- }
- ent->wait *= 1000;
-
- // first position
- VectorCopy( ent->s.origin, ent->pos1 );
-
- // calculate second position
- trap_SetBrushModel( ent, ent->model );
-
- G_SpawnFloat( "lip", "4", &lip );
-
- G_SetMovedir( ent->s.angles, ent->movedir );
- abs_movedir[0] = fabs(ent->movedir[0]);
- abs_movedir[1] = fabs(ent->movedir[1]);
- abs_movedir[2] = fabs(ent->movedir[2]);
- VectorSubtract( ent->r.maxs, ent->r.mins, size );
- distance = abs_movedir[0] * size[0] + abs_movedir[1] * size[1] + abs_movedir[2] * size[2] - lip;
- VectorMA (ent->pos1, distance, ent->movedir, ent->pos2);
-
- if (ent->health) {
- // shootable button
- ent->takedamage = qtrue;
- } else {
- // touchable button
- ent->touch = Touch_Button;
- }
-
- InitMover( ent );
-}
-
-
-
-/*
-===============================================================================
-
-TRAIN
-
-===============================================================================
-*/
-
-
-#define TRAIN_START_ON 1
-#define TRAIN_TOGGLE 2
-#define TRAIN_BLOCK_STOPS 4
-
-/*
-===============
-Think_BeginMoving
-
-The wait time at a corner has completed, so start moving again
-===============
-*/
-void Think_BeginMoving( gentity_t *ent ) {
- ent->s.pos.trTime = level.time;
- ent->s.pos.trType = TR_LINEAR_STOP;
-}
-
-/*
-===============
-Reached_Train
-===============
-*/
-void Reached_Train( gentity_t *ent ) {
- gentity_t *next;
- float speed;
- vec3_t move;
- float length;
-
- // copy the apropriate values
- next = ent->nextTrain;
- if ( !next || !next->nextTrain ) {
- return; // just stop
- }
-
- // fire all other targets
- G_UseTargets( next, NULL );
-
- // set the new trajectory
- ent->nextTrain = next->nextTrain;
- VectorCopy( next->s.origin, ent->pos1 );
- VectorCopy( next->nextTrain->s.origin, ent->pos2 );
-
- // if the path_corner has a speed, use that
- if ( next->speed ) {
- speed = next->speed;
- } else {
- // otherwise use the train's speed
- speed = ent->speed;
- }
- if ( speed < 1 ) {
- speed = 1;
- }
-
- // calculate duration
- VectorSubtract( ent->pos2, ent->pos1, move );
- length = VectorLength( move );
-
- ent->s.pos.trDuration = length * 1000 / speed;
-
- // Tequila comment: Be sure to send to clients after any fast move case
- ent->r.svFlags &= ~SVF_NOCLIENT;
-
- // Tequila comment: Fast move case
- if(ent->s.pos.trDuration<1) {
- // Tequila comment: As trDuration is used later in a division, we need to avoid that case now
- // With null trDuration,
- // the calculated rocks bounding box becomes infinite and the engine think for a short time
- // any entity is riding that mover but not the world entity... In rare case, I found it
- // can also stuck every map entities after func_door are used.
- // The desired effect with very very big speed is to have instant move, so any not null duration
- // lower than a frame duration should be sufficient.
- // Afaik, the negative case don't have to be supported.
- ent->s.pos.trDuration=1;
-
- // Tequila comment: Don't send entity to clients so it becomes really invisible
- ent->r.svFlags |= SVF_NOCLIENT;
- }
-
- // looping sound
- ent->s.loopSound = next->soundLoop;
-
- // start it going
- SetMoverState( ent, MOVER_1TO2, level.time );
-
- // if there is a "wait" value on the target, don't start moving yet
- if ( next->wait ) {
- ent->nextthink = level.time + next->wait * 1000;
- ent->think = Think_BeginMoving;
- ent->s.pos.trType = TR_STATIONARY;
- }
-}
-
-
-/*
-===============
-Think_SetupTrainTargets
-
-Link all the corners together
-===============
-*/
-void Think_SetupTrainTargets( gentity_t *ent ) {
- gentity_t *path, *next, *start;
-
- ent->nextTrain = G_Find( NULL, FOFS(targetname), ent->target );
- if ( !ent->nextTrain ) {
- G_Printf( "func_train at %s with an unfound target\n",
- vtos(ent->r.absmin) );
- return;
- }
-
- start = NULL;
- for ( path = ent->nextTrain ; path != start ; path = next ) {
- if ( !start ) {
- start = path;
- }
-
- if ( !path->target ) {
- G_Printf( "Train corner at %s without a target\n",
- vtos(path->s.origin) );
- return;
- }
-
- // find a path_corner among the targets
- // there may also be other targets that get fired when the corner
- // is reached
- next = NULL;
- do {
- next = G_Find( next, FOFS(targetname), path->target );
- if ( !next ) {
- G_Printf( "Train corner at %s without a target path_corner\n",
- vtos(path->s.origin) );
- return;
- }
- } while ( strcmp( next->classname, "path_corner" ) );
-
- path->nextTrain = next;
- }
-
- // start the train moving from the first corner
- Reached_Train( ent );
-}
-
-
-
-/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8)
-Train path corners.
-Target: next path corner and other targets to fire
-"speed" speed to move to the next corner
-"wait" seconds to wait before behining move to next corner
-*/
-void SP_path_corner( gentity_t *self ) {
- if ( !self->targetname ) {
- G_Printf ("path_corner with no targetname at %s\n", vtos(self->s.origin));
- G_FreeEntity( self );
- return;
- }
- // path corners don't need to be linked in
-}
-
-
-
-/*QUAKED func_train (0 .5 .8) ? START_ON TOGGLE BLOCK_STOPS
-A train is a mover that moves between path_corner target points.
-Trains MUST HAVE AN ORIGIN BRUSH.
-The train spawns at the first target it is pointing at.
-"model2" .md3 model to also draw
-"speed" default 100
-"dmg" default 2
-"noise" looping sound to play when the train is in motion
-"target" next path corner
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_train (gentity_t *self) {
- VectorClear (self->s.angles);
-
- if (self->spawnflags & TRAIN_BLOCK_STOPS) {
- self->damage = 0;
- } else {
- if (!self->damage) {
- self->damage = 2;
- }
- }
-
- if ( !self->speed ) {
- self->speed = 100;
- }
-
- if ( !self->target ) {
- G_Printf ("func_train without a target at %s\n", vtos(self->r.absmin));
- G_FreeEntity( self );
- return;
- }
-
- trap_SetBrushModel( self, self->model );
- InitMover( self );
-
- self->reached = Reached_Train;
-
- // start trains on the second frame, to make sure their targets have had
- // a chance to spawn
- self->nextthink = level.time + FRAMETIME;
- self->think = Think_SetupTrainTargets;
-}
-
-/*
-===============================================================================
-
-STATIC
-
-===============================================================================
-*/
-
-
-/*QUAKED func_static (0 .5 .8) ?
-A bmodel that just sits there, doing nothing. Can be used for conditional walls and models.
-"model2" .md3 model to also draw
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_static( gentity_t *ent ) {
- trap_SetBrushModel( ent, ent->model );
- InitMover( ent );
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.origin, ent->r.currentOrigin );
-}
-
-
-/*
-===============================================================================
-
-ROTATING
-
-===============================================================================
-*/
-
-
-/*QUAKED func_rotating (0 .5 .8) ? START_ON - X_AXIS Y_AXIS
-You need to have an origin brush as part of this entity. The center of that brush will be
-the point around which it is rotated. It will rotate around the Z axis by default. You can
-check either the X_AXIS or Y_AXIS box to change that.
-
-"model2" .md3 model to also draw
-"speed" determines how fast it moves; default value is 100.
-"dmg" damage to inflict when blocked (2 default)
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_rotating (gentity_t *ent) {
- if ( !ent->speed ) {
- ent->speed = 100;
- }
-
- // set the axis of rotation
- ent->s.apos.trType = TR_LINEAR;
- if ( ent->spawnflags & 4 ) {
- ent->s.apos.trDelta[2] = ent->speed;
- } else if ( ent->spawnflags & 8 ) {
- ent->s.apos.trDelta[0] = ent->speed;
- } else {
- ent->s.apos.trDelta[1] = ent->speed;
- }
-
- if (!ent->damage) {
- ent->damage = 2;
- }
-
- trap_SetBrushModel( ent, ent->model );
- InitMover( ent );
-
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );
- VectorCopy( ent->s.apos.trBase, ent->r.currentAngles );
-
- trap_LinkEntity( ent );
-}
-
-
-/*
-===============================================================================
-
-BOBBING
-
-===============================================================================
-*/
-
-
-/*QUAKED func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS
-Normally bobs on the Z axis
-"model2" .md3 model to also draw
-"height" amplitude of bob (32 default)
-"speed" seconds to complete a bob cycle (4 default)
-"phase" the 0.0 to 1.0 offset in the cycle to start at
-"dmg" damage to inflict when blocked (2 default)
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_bobbing (gentity_t *ent) {
- float height;
- float phase;
-
- G_SpawnFloat( "speed", "4", &ent->speed );
- G_SpawnFloat( "height", "32", &height );
- G_SpawnInt( "dmg", "2", &ent->damage );
- G_SpawnFloat( "phase", "0", &phase );
-
- trap_SetBrushModel( ent, ent->model );
- InitMover( ent );
-
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.origin, ent->r.currentOrigin );
-
- ent->s.pos.trDuration = ent->speed * 1000;
- ent->s.pos.trTime = ent->s.pos.trDuration * phase;
- ent->s.pos.trType = TR_SINE;
-
- // set the axis of bobbing
- if ( ent->spawnflags & 1 ) {
- ent->s.pos.trDelta[0] = height;
- } else if ( ent->spawnflags & 2 ) {
- ent->s.pos.trDelta[1] = height;
- } else {
- ent->s.pos.trDelta[2] = height;
- }
-}
-
-/*
-===============================================================================
-
-PENDULUM
-
-===============================================================================
-*/
-
-
-/*QUAKED func_pendulum (0 .5 .8) ?
-You need to have an origin brush as part of this entity.
-Pendulums always swing north / south on unrotated models. Add an angles field to the model to allow rotation in other directions.
-Pendulum frequency is a physical constant based on the length of the beam and gravity.
-"model2" .md3 model to also draw
-"speed" the number of degrees each way the pendulum swings, (30 default)
-"phase" the 0.0 to 1.0 offset in the cycle to start at
-"dmg" damage to inflict when blocked (2 default)
-"color" constantLight color
-"light" constantLight radius
-*/
-void SP_func_pendulum(gentity_t *ent) {
- float freq;
- float length;
- float phase;
- float speed;
-
- G_SpawnFloat( "speed", "30", &speed );
- G_SpawnInt( "dmg", "2", &ent->damage );
- G_SpawnFloat( "phase", "0", &phase );
-
- trap_SetBrushModel( ent, ent->model );
-
- // find pendulum length
- length = fabs( ent->r.mins[2] );
- if ( length < 8 ) {
- length = 8;
- }
-
- freq = 1 / ( M_PI * 2 ) * sqrt( g_gravity.value / ( 3 * length ) );
-
- ent->s.pos.trDuration = ( 1000 / freq );
-
- InitMover( ent );
-
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.origin, ent->r.currentOrigin );
-
- VectorCopy( ent->s.angles, ent->s.apos.trBase );
-
- ent->s.apos.trDuration = 1000 / freq;
- ent->s.apos.trTime = ent->s.apos.trDuration * phase;
- ent->s.apos.trType = TR_SINE;
- ent->s.apos.trDelta[2] = speed;
-}
diff --git a/game/code/game/g_playerstore.c b/game/code/game/g_playerstore.c
deleted file mode 100644
index 6d57561..0000000
--- a/game/code/game/g_playerstore.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 2008-2009 Poul Sander
-
-This file is part of Open Arena source code.
-
-Open Arena source code 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.
-
-Open Arena source code 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 Open Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "g_local.h"
-
-#define MAX_PLAYERS_STORED 32
-
-#define GUID_SIZE 32
-
-typedef struct {
- char guid[GUID_SIZE+1]; //The guid is 32 chars long
- int age; //int that grows each time a new player is stored. The lowest number is always replaced. Reset to 0 then retrieved.
- int persistant[MAX_PERSISTANT]; //This is the only information we need to save
-} playerstore_t;
-
-static playerstore_t playerstore[MAX_PLAYERS_STORED];
-
-static int nextAge;
-
-/*
- *Resets the player store. Should be called everytime game.qvm is loaded.
- */
-void PlayerStoreInit( void ) {
- memset(playerstore,0,sizeof(playerstore));
- nextAge = 1;
-}
-
-void PlayerStore_store(char* guid, playerState_t ps) {
- int place2store = -1;
- int lowestAge = 32000;
- int i;
- if(strlen(guid)<32)
- {
- G_LogPrintf("Playerstore: Failed to store player. Invalid guid: %s\n",guid);
- return;
- }
- for(i=0;i<MAX_PLAYERS_STORED;i++) {
- if(!Q_stricmp(guid,playerstore[i].guid)) {
- place2store=i;
- }
- }
-
- if(place2store<0)
- for(i=0;i<MAX_PLAYERS_STORED;i++) {
- if(playerstore[i].age < lowestAge) {
- place2store = i;
- lowestAge = playerstore[i].age;
- }
- }
-
- //Make sure we don't store in -1
- if(place2store<0)
- place2store = 0;
- //place2store is now the place to store to.
- playerstore[place2store].age = nextAge++;
- Q_strncpyz(playerstore[place2store].guid,guid,GUID_SIZE+1);
- memcpy(playerstore[place2store].persistant,ps.persistant,sizeof(int[MAX_PERSISTANT]));
- G_LogPrintf("Playerstore: Stored player with guid: %s in %u\n", playerstore[place2store].guid,place2store);
-}
-
-void PlayerStore_restore(char* guid, playerState_t *ps) {
- int i;
- if(strlen(guid)<32)
- {
- G_LogPrintf("Playerstore: Failed to restore player. Invalid guid: %s\n",guid);
- return;
- }
- for(i=0;i<MAX_PLAYERS_STORED;i++) {
- if(!Q_stricmpn(guid,playerstore[i].guid,GUID_SIZE) && playerstore[i].age != -1) {
- memcpy(ps->persistant,playerstore[i].persistant,sizeof(int[MAX_PERSISTANT]));
- //Never ever restore a player with negative score
- if(ps->persistant[PERS_SCORE]<0)
- ps->persistant[PERS_SCORE]=0;
- playerstore[i].age = -1;
- G_LogPrintf("Restored player with guid: %s\n",guid);
- return;
- }
- }
- G_LogPrintf("Playerstore: Nothing to restore. Guid: %s\n",guid);
-}
diff --git a/game/code/game/g_public.h b/game/code/game/g_public.h
deleted file mode 100644
index ab0aac3..0000000
--- a/game/code/game/g_public.h
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-// g_public.h -- game module information visible to server
-
-#define GAME_API_VERSION 8
-
-// entity->svFlags
-// the server does not know how to interpret most of the values
-// in entityStates (level eType), so the game must explicitly flag
-// special server behaviors
-#define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects
-
-// TTimo
-// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=551
-#define SVF_CLIENTMASK 0x00000002
-
-#define SVF_BOT 0x00000008 // set if the entity is a bot
-#define SVF_BROADCAST 0x00000020 // send to all connected clients
-#define SVF_PORTAL 0x00000040 // merge a second pvs at origin2 into snapshots
-#define SVF_USE_CURRENT_ORIGIN 0x00000080 // entity->r.currentOrigin instead of entity->s.origin
- // for link position (missiles and movers)
-#define SVF_SINGLECLIENT 0x00000100 // only send to a single client (entityShared_t->singleClient)
-#define SVF_NOSERVERINFO 0x00000200 // don't send CS_SERVERINFO updates to this client
- // so that it can be updated for ping tools without
- // lagging clients
-#define SVF_CAPSULE 0x00000400 // use capsule for collision detection instead of bbox
-#define SVF_NOTSINGLECLIENT 0x00000800 // send entity to everyone but one client
- // (entityShared_t->singleClient)
-
-
-
-//===============================================================
-
-
-typedef struct {
- entityState_t s; // communicated by server to clients
-
- qboolean linked; // qfalse if not in any good cluster
- int linkcount;
-
- int svFlags; // SVF_NOCLIENT, SVF_BROADCAST, etc
-
- // only send to this client when SVF_SINGLECLIENT is set
- // if SVF_CLIENTMASK is set, use bitmask for clients to send to (maxclients must be <= 32, up to the mod to enforce this)
- int singleClient;
-
- qboolean bmodel; // if false, assume an explicit mins / maxs bounding box
- // only set by trap_SetBrushModel
- vec3_t mins, maxs;
- int contents; // CONTENTS_TRIGGER, CONTENTS_SOLID, CONTENTS_BODY, etc
- // a non-solid entity should set to 0
-
- vec3_t absmin, absmax; // derived from mins/maxs and origin + rotation
-
- // currentOrigin will be used for all collision detection and world linking.
- // it will not necessarily be the same as the trajectory evaluation for the current
- // time, because each entity must be moved one at a time after time is advanced
- // to avoid simultanious collision issues
- vec3_t currentOrigin;
- vec3_t currentAngles;
-
- // when a trace call is made and passEntityNum != ENTITYNUM_NONE,
- // an ent will be excluded from testing if:
- // ent->s.number == passEntityNum (don't interact with self)
- // ent->s.ownerNum = passEntityNum (don't interact with your own missiles)
- // entity[ent->s.ownerNum].ownerNum = passEntityNum (don't interact with other missiles from owner)
- int ownerNum;
-} entityShared_t;
-
-
-
-// the server looks at a sharedEntity, which is the start of the game's gentity_t structure
-typedef struct {
- entityState_t s; // communicated by server to clients
- entityShared_t r; // shared by both the server system and game
-} sharedEntity_t;
-
-
-
-//===============================================================
-
-//
-// system traps provided by the main engine
-//
-typedef enum {
- //============== general Quake services ==================
-
- G_PRINT, // ( const char *string );
- // print message on the local console
-
- G_ERROR, // ( const char *string );
- // abort the game
-
- G_MILLISECONDS, // ( void );
- // get current time for profiling reasons
- // this should NOT be used for any game related tasks,
- // because it is not journaled
-
- // console variable interaction
- G_CVAR_REGISTER, // ( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
- G_CVAR_UPDATE, // ( vmCvar_t *vmCvar );
- G_CVAR_SET, // ( const char *var_name, const char *value );
- G_CVAR_VARIABLE_INTEGER_VALUE, // ( const char *var_name );
-
- G_CVAR_VARIABLE_STRING_BUFFER, // ( const char *var_name, char *buffer, int bufsize );
-
- G_ARGC, // ( void );
- // ClientCommand and ServerCommand parameter access
-
- G_ARGV, // ( int n, char *buffer, int bufferLength );
-
- G_FS_FOPEN_FILE, // ( const char *qpath, fileHandle_t *file, fsMode_t mode );
- G_FS_READ, // ( void *buffer, int len, fileHandle_t f );
- G_FS_WRITE, // ( const void *buffer, int len, fileHandle_t f );
- G_FS_FCLOSE_FILE, // ( fileHandle_t f );
-
- G_SEND_CONSOLE_COMMAND, // ( const char *text );
- // add commands to the console as if they were typed in
- // for map changing, etc
-
-
- //=========== server specific functionality =============
-
- G_LOCATE_GAME_DATA, // ( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
- // playerState_t *clients, int sizeofGameClient );
- // the game needs to let the server system know where and how big the gentities
- // are, so it can look at them directly without going through an interface
-
- G_DROP_CLIENT, // ( int clientNum, const char *reason );
- // kick a client off the server with a message
-
- G_SEND_SERVER_COMMAND, // ( int clientNum, const char *fmt, ... );
- // reliably sends a command string to be interpreted by the given
- // client. If clientNum is -1, it will be sent to all clients
-
- G_SET_CONFIGSTRING, // ( int num, const char *string );
- // config strings hold all the index strings, and various other information
- // that is reliably communicated to all clients
- // All of the current configstrings are sent to clients when
- // they connect, and changes are sent to all connected clients.
- // All confgstrings are cleared at each level start.
-
- G_GET_CONFIGSTRING, // ( int num, char *buffer, int bufferSize );
-
- G_GET_USERINFO, // ( int num, char *buffer, int bufferSize );
- // userinfo strings are maintained by the server system, so they
- // are persistant across level loads, while all other game visible
- // data is completely reset
-
- G_SET_USERINFO, // ( int num, const char *buffer );
-
- G_GET_SERVERINFO, // ( char *buffer, int bufferSize );
- // the serverinfo info string has all the cvars visible to server browsers
-
- G_SET_BRUSH_MODEL, // ( gentity_t *ent, const char *name );
- // sets mins and maxs based on the brushmodel name
-
- G_TRACE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
- // collision detection against all linked entities
-
- G_POINT_CONTENTS, // ( const vec3_t point, int passEntityNum );
- // point contents against all linked entities
-
- G_IN_PVS, // ( const vec3_t p1, const vec3_t p2 );
-
- G_IN_PVS_IGNORE_PORTALS, // ( const vec3_t p1, const vec3_t p2 );
-
- G_ADJUST_AREA_PORTAL_STATE, // ( gentity_t *ent, qboolean open );
-
- G_AREAS_CONNECTED, // ( int area1, int area2 );
-
- G_LINKENTITY, // ( gentity_t *ent );
- // an entity will never be sent to a client or used for collision
- // if it is not passed to linkentity. If the size, position, or
- // solidity changes, it must be relinked.
-
- G_UNLINKENTITY, // ( gentity_t *ent );
- // call before removing an interactive entity
-
- G_ENTITIES_IN_BOX, // ( const vec3_t mins, const vec3_t maxs, gentity_t **list, int maxcount );
- // EntitiesInBox will return brush models based on their bounding box,
- // so exact determination must still be done with EntityContact
-
- G_ENTITY_CONTACT, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
- // perform an exact check against inline brush models of non-square shape
-
- // access for bots to get and free a server client (FIXME?)
- G_BOT_ALLOCATE_CLIENT, // ( void );
-
- G_BOT_FREE_CLIENT, // ( int clientNum );
-
- G_GET_USERCMD, // ( int clientNum, usercmd_t *cmd )
-
- G_GET_ENTITY_TOKEN, // qboolean ( char *buffer, int bufferSize )
- // Retrieves the next string token from the entity spawn text, returning
- // false when all tokens have been parsed.
- // This should only be done at GAME_INIT time.
-
- G_FS_GETFILELIST,
- G_DEBUG_POLYGON_CREATE,
- G_DEBUG_POLYGON_DELETE,
- G_REAL_TIME,
- G_SNAPVECTOR,
-
- G_TRACECAPSULE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
- G_ENTITY_CONTACTCAPSULE, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
-
- // 1.32
- G_FS_SEEK,
-
- BOTLIB_SETUP = 200, // ( void );
- BOTLIB_SHUTDOWN, // ( void );
- BOTLIB_LIBVAR_SET,
- BOTLIB_LIBVAR_GET,
- BOTLIB_PC_ADD_GLOBAL_DEFINE,
- BOTLIB_START_FRAME,
- BOTLIB_LOAD_MAP,
- BOTLIB_UPDATENTITY,
- BOTLIB_TEST,
-
- BOTLIB_GET_SNAPSHOT_ENTITY, // ( int client, int ent );
- BOTLIB_GET_CONSOLE_MESSAGE, // ( int client, char *message, int size );
- BOTLIB_USER_COMMAND, // ( int client, usercmd_t *ucmd );
-
- BOTLIB_AAS_ENABLE_ROUTING_AREA = 300,
- BOTLIB_AAS_BBOX_AREAS,
- BOTLIB_AAS_AREA_INFO,
- BOTLIB_AAS_ENTITY_INFO,
-
- BOTLIB_AAS_INITIALIZED,
- BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX,
- BOTLIB_AAS_TIME,
-
- BOTLIB_AAS_POINT_AREA_NUM,
- BOTLIB_AAS_TRACE_AREAS,
-
- BOTLIB_AAS_POINT_CONTENTS,
- BOTLIB_AAS_NEXT_BSP_ENTITY,
- BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY,
- BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY,
- BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY,
- BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY,
-
- BOTLIB_AAS_AREA_REACHABILITY,
-
- BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA,
-
- BOTLIB_AAS_SWIMMING,
- BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT,
-
- BOTLIB_EA_SAY = 400,
- BOTLIB_EA_SAY_TEAM,
- BOTLIB_EA_COMMAND,
-
- BOTLIB_EA_ACTION,
- BOTLIB_EA_GESTURE,
- BOTLIB_EA_TALK,
- BOTLIB_EA_ATTACK,
- BOTLIB_EA_USE,
- BOTLIB_EA_RESPAWN,
- BOTLIB_EA_CROUCH,
- BOTLIB_EA_MOVE_UP,
- BOTLIB_EA_MOVE_DOWN,
- BOTLIB_EA_MOVE_FORWARD,
- BOTLIB_EA_MOVE_BACK,
- BOTLIB_EA_MOVE_LEFT,
- BOTLIB_EA_MOVE_RIGHT,
-
- BOTLIB_EA_SELECT_WEAPON,
- BOTLIB_EA_JUMP,
- BOTLIB_EA_DELAYED_JUMP,
- BOTLIB_EA_MOVE,
- BOTLIB_EA_VIEW,
-
- BOTLIB_EA_END_REGULAR,
- BOTLIB_EA_GET_INPUT,
- BOTLIB_EA_RESET_INPUT,
-
-
- BOTLIB_AI_LOAD_CHARACTER = 500,
- BOTLIB_AI_FREE_CHARACTER,
- BOTLIB_AI_CHARACTERISTIC_FLOAT,
- BOTLIB_AI_CHARACTERISTIC_BFLOAT,
- BOTLIB_AI_CHARACTERISTIC_INTEGER,
- BOTLIB_AI_CHARACTERISTIC_BINTEGER,
- BOTLIB_AI_CHARACTERISTIC_STRING,
-
- BOTLIB_AI_ALLOC_CHAT_STATE,
- BOTLIB_AI_FREE_CHAT_STATE,
- BOTLIB_AI_QUEUE_CONSOLE_MESSAGE,
- BOTLIB_AI_REMOVE_CONSOLE_MESSAGE,
- BOTLIB_AI_NEXT_CONSOLE_MESSAGE,
- BOTLIB_AI_NUM_CONSOLE_MESSAGE,
- BOTLIB_AI_INITIAL_CHAT,
- BOTLIB_AI_REPLY_CHAT,
- BOTLIB_AI_CHAT_LENGTH,
- BOTLIB_AI_ENTER_CHAT,
- BOTLIB_AI_STRING_CONTAINS,
- BOTLIB_AI_FIND_MATCH,
- BOTLIB_AI_MATCH_VARIABLE,
- BOTLIB_AI_UNIFY_WHITE_SPACES,
- BOTLIB_AI_REPLACE_SYNONYMS,
- BOTLIB_AI_LOAD_CHAT_FILE,
- BOTLIB_AI_SET_CHAT_GENDER,
- BOTLIB_AI_SET_CHAT_NAME,
-
- BOTLIB_AI_RESET_GOAL_STATE,
- BOTLIB_AI_RESET_AVOID_GOALS,
- BOTLIB_AI_PUSH_GOAL,
- BOTLIB_AI_POP_GOAL,
- BOTLIB_AI_EMPTY_GOAL_STACK,
- BOTLIB_AI_DUMP_AVOID_GOALS,
- BOTLIB_AI_DUMP_GOAL_STACK,
- BOTLIB_AI_GOAL_NAME,
- BOTLIB_AI_GET_TOP_GOAL,
- BOTLIB_AI_GET_SECOND_GOAL,
- BOTLIB_AI_CHOOSE_LTG_ITEM,
- BOTLIB_AI_CHOOSE_NBG_ITEM,
- BOTLIB_AI_TOUCHING_GOAL,
- BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE,
- BOTLIB_AI_GET_LEVEL_ITEM_GOAL,
- BOTLIB_AI_AVOID_GOAL_TIME,
- BOTLIB_AI_INIT_LEVEL_ITEMS,
- BOTLIB_AI_UPDATE_ENTITY_ITEMS,
- BOTLIB_AI_LOAD_ITEM_WEIGHTS,
- BOTLIB_AI_FREE_ITEM_WEIGHTS,
- BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC,
- BOTLIB_AI_ALLOC_GOAL_STATE,
- BOTLIB_AI_FREE_GOAL_STATE,
-
- BOTLIB_AI_RESET_MOVE_STATE,
- BOTLIB_AI_MOVE_TO_GOAL,
- BOTLIB_AI_MOVE_IN_DIRECTION,
- BOTLIB_AI_RESET_AVOID_REACH,
- BOTLIB_AI_RESET_LAST_AVOID_REACH,
- BOTLIB_AI_REACHABILITY_AREA,
- BOTLIB_AI_MOVEMENT_VIEW_TARGET,
- BOTLIB_AI_ALLOC_MOVE_STATE,
- BOTLIB_AI_FREE_MOVE_STATE,
- BOTLIB_AI_INIT_MOVE_STATE,
-
- BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON,
- BOTLIB_AI_GET_WEAPON_INFO,
- BOTLIB_AI_LOAD_WEAPON_WEIGHTS,
- BOTLIB_AI_ALLOC_WEAPON_STATE,
- BOTLIB_AI_FREE_WEAPON_STATE,
- BOTLIB_AI_RESET_WEAPON_STATE,
-
- BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION,
- BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC,
- BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC,
- BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL,
- BOTLIB_AI_GET_MAP_LOCATION_GOAL,
- BOTLIB_AI_NUM_INITIAL_CHATS,
- BOTLIB_AI_GET_CHAT_MESSAGE,
- BOTLIB_AI_REMOVE_FROM_AVOID_GOALS,
- BOTLIB_AI_PREDICT_VISIBLE_POSITION,
-
- BOTLIB_AI_SET_AVOID_GOAL_TIME,
- BOTLIB_AI_ADD_AVOID_SPOT,
- BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL,
- BOTLIB_AAS_PREDICT_ROUTE,
- BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX,
-
- BOTLIB_PC_LOAD_SOURCE,
- BOTLIB_PC_FREE_SOURCE,
- BOTLIB_PC_READ_TOKEN,
- BOTLIB_PC_SOURCE_FILE_AND_LINE
-
-} gameImport_t;
-
-
-//
-// functions exported by the game subsystem
-//
-typedef enum {
- GAME_INIT, // ( int levelTime, int randomSeed, int restart );
- // init and shutdown will be called every single level
- // The game should call G_GET_ENTITY_TOKEN to parse through all the
- // entity configuration text and spawn gentities.
-
- GAME_SHUTDOWN, // (void);
-
- GAME_CLIENT_CONNECT, // ( int clientNum, qboolean firstTime, qboolean isBot );
- // return NULL if the client is allowed to connect, otherwise return
- // a text string with the reason for denial
-
- GAME_CLIENT_BEGIN, // ( int clientNum );
-
- GAME_CLIENT_USERINFO_CHANGED, // ( int clientNum );
-
- GAME_CLIENT_DISCONNECT, // ( int clientNum );
-
- GAME_CLIENT_COMMAND, // ( int clientNum );
-
- GAME_CLIENT_THINK, // ( int clientNum );
-
- GAME_RUN_FRAME, // ( int levelTime );
-
- GAME_CONSOLE_COMMAND, // ( void );
- // ConsoleCommand will be called when a command has been issued
- // that is not recognized as a builtin function.
- // The game can issue trap_argc() / trap_argv() commands to get the command
- // and parameters. Return qfalse if the game doesn't recognize it as a command.
-
- BOTAI_START_FRAME // ( int time );
-} gameExport_t;
-
diff --git a/game/code/game/g_session.c b/game/code/game/g_session.c
deleted file mode 100644
index 4b03285..0000000
--- a/game/code/game/g_session.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-
-/*
-=======================================================================
-
- SESSION DATA
-
-Session data is the only data that stays persistant across level loads
-and tournament restarts.
-=======================================================================
-*/
-
-/*
-================
-G_WriteClientSessionData
-
-Called on game shutdown
-================
-*/
-void G_WriteClientSessionData( gclient_t *client ) {
- const char *s;
- const char *var;
-
- s = va("%i %i %i %i %i %i %i",
- client->sess.sessionTeam,
- client->sess.spectatorTime,
- client->sess.spectatorState,
- client->sess.spectatorClient,
- client->sess.wins,
- client->sess.losses,
- client->sess.teamLeader
- );
-
- var = va( "session%i", (int)(client - level.clients) );
-
- trap_Cvar_Set( var, s );
-}
-
-/*
-================
-G_ReadSessionData
-
-Called on a reconnect
-================
-*/
-void G_ReadSessionData( gclient_t *client ) {
- char s[MAX_STRING_CHARS];
- const char *var;
-
- // bk001205 - format
- int teamLeader;
- int spectatorState;
- int sessionTeam;
-
- var = va( "session%i", (int)(client - level.clients) );
- trap_Cvar_VariableStringBuffer( var, s, sizeof(s) );
-
- sscanf( s, "%i %i %i %i %i %i %i",
- &sessionTeam, // bk010221 - format
- &client->sess.spectatorTime,
- &spectatorState, // bk010221 - format
- &client->sess.spectatorClient,
- &client->sess.wins,
- &client->sess.losses,
- &teamLeader // bk010221 - format
- );
-
- // bk001205 - format issues
- client->sess.sessionTeam = (team_t)sessionTeam;
- client->sess.spectatorState = (spectatorState_t)spectatorState;
- client->sess.teamLeader = (qboolean)teamLeader;
-}
-
-
-/*
-================
-G_InitSessionData
-
-Called on a first-time connect
-================
-*/
-void G_InitSessionData( gclient_t *client, char *userinfo ) {
- clientSession_t *sess;
- const char *value;
-
- sess = &client->sess;
-
- // initial team determination
- if ( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) {
- if ( g_teamAutoJoin.integer ) {
- sess->sessionTeam = PickTeam( -1 );
- BroadcastTeamChange( client, -1 );
- } else {
- // always spawn as spectator in team games
- sess->sessionTeam = TEAM_SPECTATOR;
- }
- } else {
- value = Info_ValueForKey( userinfo, "team" );
- if ( value[0] == 's' ) {
- // a willing spectator, not a waiting-in-line
- sess->sessionTeam = TEAM_SPECTATOR;
- } else {
- switch ( g_gametype.integer ) {
- default:
- case GT_FFA:
- case GT_LMS:
- case GT_SINGLE_PLAYER:
- if ( g_maxGameClients.integer > 0 &&
- level.numNonSpectatorClients >= g_maxGameClients.integer ) {
- sess->sessionTeam = TEAM_SPECTATOR;
- } else {
- sess->sessionTeam = TEAM_FREE;
- }
- break;
- case GT_TOURNAMENT:
- // if the game is full, go into a waiting mode
- if ( level.numNonSpectatorClients >= 2 ) {
- sess->sessionTeam = TEAM_SPECTATOR;
- } else {
- sess->sessionTeam = TEAM_FREE;
- }
- break;
- }
- }
- }
-
- sess->spectatorState = SPECTATOR_FREE;
- sess->spectatorTime = level.time;
-
- G_WriteClientSessionData( client );
-}
-
-
-/*
-==================
-G_InitWorldSession
-
-==================
-*/
-void G_InitWorldSession( void ) {
- char s[MAX_STRING_CHARS];
- int gt;
-
- trap_Cvar_VariableStringBuffer( "session", s, sizeof(s) );
- gt = atoi( s );
-
- // if the gametype changed since the last session, don't use any
- // client sessions
- if ( g_gametype.integer != gt ) {
- level.newSession = qtrue;
- G_Printf( "Gametype changed, clearing session data.\n" );
- }
-}
-
-/*
-==================
-G_WriteSessionData
-
-==================
-*/
-void G_WriteSessionData( void ) {
- int i;
-
- trap_Cvar_Set( "session", va("%i", g_gametype.integer) );
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[i].pers.connected == CON_CONNECTED ) {
- G_WriteClientSessionData( &level.clients[i] );
- }
- }
-}
diff --git a/game/code/game/g_spawn.c b/game/code/game/g_spawn.c
deleted file mode 100644
index 39de6be..0000000
--- a/game/code/game/g_spawn.c
+++ /dev/null
@@ -1,660 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-#include "g_local.h"
-
-qboolean G_SpawnString( const char *key, const char *defaultString, char **out ) {
- int i;
-
- if ( !level.spawning ) {
- *out = (char *)defaultString;
-// G_Error( "G_SpawnString() called while not spawning" );
- }
-
- for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
- if ( !Q_stricmp( key, level.spawnVars[i][0] ) ) {
- *out = level.spawnVars[i][1];
- return qtrue;
- }
- }
-
- *out = (char *)defaultString;
- return qfalse;
-}
-
-qboolean G_SpawnFloat( const char *key, const char *defaultString, float *out ) {
- char *s;
- qboolean present;
-
- present = G_SpawnString( key, defaultString, &s );
- *out = atof( s );
- return present;
-}
-
-qboolean G_SpawnInt( const char *key, const char *defaultString, int *out ) {
- char *s;
- qboolean present;
-
- present = G_SpawnString( key, defaultString, &s );
- *out = atoi( s );
- return present;
-}
-
-qboolean G_SpawnVector( const char *key, const char *defaultString, float *out ) {
- char *s;
- qboolean present;
-
- present = G_SpawnString( key, defaultString, &s );
- sscanf( s, "%f %f %f", &out[0], &out[1], &out[2] );
- return present;
-}
-
-
-
-//
-// fields are needed for spawning from the entity string
-//
-typedef enum {
- F_INT,
- F_FLOAT,
- F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL
- F_GSTRING, // string on disk, pointer in memory, TAG_GAME
- F_VECTOR,
- F_ANGLEHACK,
- F_ENTITY, // index on disk, pointer in memory
- F_ITEM, // index on disk, pointer in memory
- F_CLIENT, // index on disk, pointer in memory
- F_IGNORE
-} fieldtype_t;
-
-typedef struct
-{
- char *name;
- int ofs;
- fieldtype_t type;
- int flags;
-} field_t;
-
-field_t fields[] = {
- {"classname", FOFS(classname), F_LSTRING},
- {"origin", FOFS(s.origin), F_VECTOR},
- {"model", FOFS(model), F_LSTRING},
- {"model2", FOFS(model2), F_LSTRING},
- {"spawnflags", FOFS(spawnflags), F_INT},
- {"speed", FOFS(speed), F_FLOAT},
- {"target", FOFS(target), F_LSTRING},
- {"targetname", FOFS(targetname), F_LSTRING},
- {"message", FOFS(message), F_LSTRING},
- {"team", FOFS(team), F_LSTRING},
- {"wait", FOFS(wait), F_FLOAT},
- {"random", FOFS(random), F_FLOAT},
- {"count", FOFS(count), F_INT},
- {"health", FOFS(health), F_INT},
- {"light", 0, F_IGNORE},
- {"dmg", FOFS(damage), F_INT},
- {"angles", FOFS(s.angles), F_VECTOR},
- {"angle", FOFS(s.angles), F_ANGLEHACK},
- {"targetShaderName", FOFS(targetShaderName), F_LSTRING},
- {"targetShaderNewName", FOFS(targetShaderNewName), F_LSTRING},
-
- {NULL}
-};
-
-
-typedef struct {
- char *name;
- void (*spawn)(gentity_t *ent);
-} spawn_t;
-
-void SP_info_player_start (gentity_t *ent);
-void SP_info_player_deathmatch (gentity_t *ent);
-void SP_info_player_intermission (gentity_t *ent);
-//For Double Domination:
-void SP_info_player_dd (gentity_t *ent);
-void SP_info_player_dd_red (gentity_t *ent);
-void SP_info_player_dd_blue (gentity_t *ent);
-//standard domination:
-void SP_domination_point ( gentity_t *ent);
-
-void SP_info_firstplace(gentity_t *ent);
-void SP_info_secondplace(gentity_t *ent);
-void SP_info_thirdplace(gentity_t *ent);
-void SP_info_podium(gentity_t *ent);
-
-void SP_func_plat (gentity_t *ent);
-void SP_func_static (gentity_t *ent);
-void SP_func_rotating (gentity_t *ent);
-void SP_func_bobbing (gentity_t *ent);
-void SP_func_pendulum( gentity_t *ent );
-void SP_func_button (gentity_t *ent);
-void SP_func_door (gentity_t *ent);
-void SP_func_train (gentity_t *ent);
-void SP_func_timer (gentity_t *self);
-
-void SP_trigger_always (gentity_t *ent);
-void SP_trigger_multiple (gentity_t *ent);
-void SP_trigger_push (gentity_t *ent);
-void SP_trigger_teleport (gentity_t *ent);
-void SP_trigger_hurt (gentity_t *ent);
-
-void SP_target_remove_powerups( gentity_t *ent );
-void SP_target_give (gentity_t *ent);
-void SP_target_delay (gentity_t *ent);
-void SP_target_speaker (gentity_t *ent);
-void SP_target_print (gentity_t *ent);
-void SP_target_laser (gentity_t *self);
-void SP_target_character (gentity_t *ent);
-void SP_target_score( gentity_t *ent );
-void SP_target_teleporter( gentity_t *ent );
-void SP_target_relay (gentity_t *ent);
-void SP_target_kill (gentity_t *ent);
-void SP_target_position (gentity_t *ent);
-void SP_target_location (gentity_t *ent);
-void SP_target_push (gentity_t *ent);
-
-void SP_light (gentity_t *self);
-void SP_info_null (gentity_t *self);
-void SP_info_notnull (gentity_t *self);
-void SP_info_camp (gentity_t *self);
-void SP_path_corner (gentity_t *self);
-
-void SP_misc_teleporter_dest (gentity_t *self);
-void SP_misc_model(gentity_t *ent);
-void SP_misc_portal_camera(gentity_t *ent);
-void SP_misc_portal_surface(gentity_t *ent);
-
-void SP_shooter_rocket( gentity_t *ent );
-void SP_shooter_plasma( gentity_t *ent );
-void SP_shooter_grenade( gentity_t *ent );
-
-void SP_team_CTF_redplayer( gentity_t *ent );
-void SP_team_CTF_blueplayer( gentity_t *ent );
-
-void SP_team_CTF_redspawn( gentity_t *ent );
-void SP_team_CTF_bluespawn( gentity_t *ent );
-
-void SP_team_blueobelisk( gentity_t *ent );
-void SP_team_redobelisk( gentity_t *ent );
-void SP_team_neutralobelisk( gentity_t *ent );
-
-void SP_item_botroam( gentity_t *ent ) { }
-
-spawn_t spawns[] = {
- // info entities don't do anything at all, but provide positional
- // information for things controlled by other processes
- {"info_player_start", SP_info_player_start},
- {"info_player_deathmatch", SP_info_player_deathmatch},
- {"info_player_intermission", SP_info_player_intermission},
-//Double Domination player spawn:
- {"info_player_dd", SP_info_player_dd},
- {"info_player_dd_red", SP_info_player_dd_red},
- {"info_player_dd_blue", SP_info_player_dd_blue},
-//Standard Domination point spawn:
- {"domination_point", SP_domination_point},
-
-
- {"info_null", SP_info_null},
- {"info_notnull", SP_info_notnull}, // use target_position instead
- {"info_camp", SP_info_camp},
-
- {"func_plat", SP_func_plat},
- {"func_button", SP_func_button},
- {"func_door", SP_func_door},
- {"func_static", SP_func_static},
- {"func_rotating", SP_func_rotating},
- {"func_bobbing", SP_func_bobbing},
- {"func_pendulum", SP_func_pendulum},
- {"func_train", SP_func_train},
- {"func_group", SP_info_null},
- {"func_timer", SP_func_timer}, // rename trigger_timer?
-
- // Triggers are brush objects that cause an effect when contacted
- // by a living player, usually involving firing targets.
- // While almost everything could be done with
- // a single trigger class and different targets, triggered effects
- // could not be client side predicted (push and teleport).
- {"trigger_always", SP_trigger_always},
- {"trigger_multiple", SP_trigger_multiple},
- {"trigger_push", SP_trigger_push},
- {"trigger_teleport", SP_trigger_teleport},
- {"trigger_hurt", SP_trigger_hurt},
-
- // targets perform no action by themselves, but must be triggered
- // by another entity
- {"target_give", SP_target_give},
- {"target_remove_powerups", SP_target_remove_powerups},
- {"target_delay", SP_target_delay},
- {"target_speaker", SP_target_speaker},
- {"target_print", SP_target_print},
- {"target_laser", SP_target_laser},
- {"target_score", SP_target_score},
- {"target_teleporter", SP_target_teleporter},
- {"target_relay", SP_target_relay},
- {"target_kill", SP_target_kill},
- {"target_position", SP_target_position},
- {"target_location", SP_target_location},
- {"target_push", SP_target_push},
-
- {"light", SP_light},
- {"path_corner", SP_path_corner},
-
- {"misc_teleporter_dest", SP_misc_teleporter_dest},
- {"misc_model", SP_misc_model},
- {"misc_portal_surface", SP_misc_portal_surface},
- {"misc_portal_camera", SP_misc_portal_camera},
-
- {"shooter_rocket", SP_shooter_rocket},
- {"shooter_grenade", SP_shooter_grenade},
- {"shooter_plasma", SP_shooter_plasma},
-
- {"team_CTF_redplayer", SP_team_CTF_redplayer},
- {"team_CTF_blueplayer", SP_team_CTF_blueplayer},
-
- {"team_CTF_redspawn", SP_team_CTF_redspawn},
- {"team_CTF_bluespawn", SP_team_CTF_bluespawn},
-
- {"team_redobelisk", SP_team_redobelisk},
- {"team_blueobelisk", SP_team_blueobelisk},
- {"team_neutralobelisk", SP_team_neutralobelisk},
-
- {"item_botroam", SP_item_botroam},
-
- {NULL, 0}
-};
-
-/*
-===============
-G_CallSpawn
-
-Finds the spawn function for the entity and calls it,
-returning qfalse if not found
-===============
-*/
-qboolean G_CallSpawn( gentity_t *ent ) {
- spawn_t *s;
- gitem_t *item;
-
- if ( !ent->classname ) {
- G_Printf ("G_CallSpawn: NULL classname\n");
- return qfalse;
- }
-
- // check item spawn functions
- for ( item=bg_itemlist+1 ; item->classname ; item++ ) {
- if ( !strcmp(item->classname, ent->classname) ) {
- G_SpawnItem( ent, item );
- return qtrue;
- }
- }
-
- // check normal spawn functions
- for ( s=spawns ; s->name ; s++ ) {
- if ( !strcmp(s->name, ent->classname) ) {
- // found it
- s->spawn(ent);
- return qtrue;
- }
- }
- G_Printf ("%s doesn't have a spawn function\n", ent->classname);
- return qfalse;
-}
-
-/*
-=============
-G_NewString
-
-Builds a copy of the string, translating \n to real linefeeds
-so message texts can be multi-line
-=============
-*/
-char *G_NewString( const char *string ) {
- char *newb, *new_p;
- int i,l;
-
- l = strlen(string) + 1;
- //KK-OAX Changed to Tremulous's BG_Alloc
- newb = BG_Alloc( l );
-
- new_p = newb;
-
- // turn \n into a real linefeed
- for ( i=0 ; i< l ; i++ ) {
- if (string[i] == '\\' && i < l-1) {
- i++;
- if (string[i] == 'n') {
- *new_p++ = '\n';
- } else {
- *new_p++ = '\\';
- }
- } else {
- *new_p++ = string[i];
- }
- }
-
- return newb;
-}
-
-
-
-
-/*
-===============
-G_ParseField
-
-Takes a key/value pair and sets the binary values
-in a gentity
-===============
-*/
-void G_ParseField( const char *key, const char *value, gentity_t *ent ) {
- field_t *f;
- byte *b;
- float v;
- vec3_t vec;
-
- for ( f=fields ; f->name ; f++ ) {
- if ( !Q_stricmp(f->name, key) ) {
- // found it
- b = (byte *)ent;
-
- switch( f->type ) {
- case F_LSTRING:
- *(char **)(b+f->ofs) = G_NewString (value);
- break;
- case F_VECTOR:
- sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
- ((float *)(b+f->ofs))[0] = vec[0];
- ((float *)(b+f->ofs))[1] = vec[1];
- ((float *)(b+f->ofs))[2] = vec[2];
- break;
- case F_INT:
- *(int *)(b+f->ofs) = atoi(value);
- break;
- case F_FLOAT:
- *(float *)(b+f->ofs) = atof(value);
- break;
- case F_ANGLEHACK:
- v = atof(value);
- ((float *)(b+f->ofs))[0] = 0;
- ((float *)(b+f->ofs))[1] = v;
- ((float *)(b+f->ofs))[2] = 0;
- break;
- default:
- case F_IGNORE:
- break;
- }
- return;
- }
- }
-}
-
-
-
-
-/*
-===================
-G_SpawnGEntityFromSpawnVars
-
-Spawn an entity and fill in all of the level fields from
-level.spawnVars[], then call the class specfic spawn function
-===================
-*/
-void G_SpawnGEntityFromSpawnVars( void ) {
- int i;
- gentity_t *ent;
- char *s, *value, *gametypeName;
- static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester", "elimination", "ctf", "lms", "dd", "dom"};
-
- // get the next free entity
- ent = G_Spawn();
-
- for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
- G_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], ent );
- }
-
- // check for "notsingle" flag
- if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
- G_SpawnInt( "notsingle", "0", &i );
- if ( i ) {
- G_FreeEntity( ent );
- return;
- }
- }
- // check for "notteam" flag (GT_FFA, GT_TOURNAMENT, GT_SINGLE_PLAYER)
- if ( g_gametype.integer >= GT_TEAM && !g_ffa_gt ) {
- G_SpawnInt( "notteam", "0", &i );
- if ( i ) {
- G_FreeEntity( ent );
- return;
- }
- } else {
- G_SpawnInt( "notfree", "0", &i );
- if ( i ) {
- G_FreeEntity( ent );
- return;
- }
- }
-
-#ifdef MISSIONPACK
- G_SpawnInt( "notta", "0", &i );
- if ( i ) {
- G_FreeEntity( ent );
- return;
- }
-#else
- G_SpawnInt( "notq3a", "0", &i );
- if ( i ) {
- G_FreeEntity( ent );
- return;
- }
-#endif
-
- if( G_SpawnString( "gametype", NULL, &value ) ) {
- if( g_gametype.integer >= GT_FFA && g_gametype.integer < GT_MAX_GAME_TYPE ) {
- gametypeName = gametypeNames[g_gametype.integer];
-
- s = strstr( value, gametypeName );
- if( !s ) {
- G_FreeEntity( ent );
- return;
- }
- }
- }
-
- // move editor origin to pos
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.origin, ent->r.currentOrigin );
-
- // if we didn't get a classname, don't bother spawning anything
- if ( !G_CallSpawn( ent ) ) {
- G_FreeEntity( ent );
- }
-}
-
-
-
-/*
-====================
-G_AddSpawnVarToken
-====================
-*/
-char *G_AddSpawnVarToken( const char *string ) {
- int l;
- char *dest;
-
- l = strlen( string );
- if ( level.numSpawnVarChars + l + 1 > MAX_SPAWN_VARS_CHARS ) {
- G_Error( "G_AddSpawnVarToken: MAX_SPAWN_CHARS" );
- }
-
- dest = level.spawnVarChars + level.numSpawnVarChars;
- memcpy( dest, string, l+1 );
-
- level.numSpawnVarChars += l + 1;
-
- return dest;
-}
-
-/*
-====================
-G_ParseSpawnVars
-
-Parses a brace bounded set of key / value pairs out of the
-level's entity strings into level.spawnVars[]
-
-This does not actually spawn an entity.
-====================
-*/
-qboolean G_ParseSpawnVars( void ) {
- char keyname[MAX_TOKEN_CHARS];
- char com_token[MAX_TOKEN_CHARS];
-
- level.numSpawnVars = 0;
- level.numSpawnVarChars = 0;
-
- // parse the opening brace
- if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
- // end of spawn string
- return qfalse;
- }
- if ( com_token[0] != '{' ) {
- G_Error( "G_ParseSpawnVars: found %s when expecting {",com_token );
- }
-
- // go through all the key / value pairs
- while ( 1 ) {
- // parse key
- if ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) {
- G_Error( "G_ParseSpawnVars: EOF without closing brace" );
- }
-
- if ( keyname[0] == '}' ) {
- break;
- }
-
- // parse value
- if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
- G_Error( "G_ParseSpawnVars: EOF without closing brace" );
- }
-
- if ( com_token[0] == '}' ) {
- G_Error( "G_ParseSpawnVars: closing brace without data" );
- }
- if ( level.numSpawnVars == MAX_SPAWN_VARS ) {
- G_Error( "G_ParseSpawnVars: MAX_SPAWN_VARS" );
- }
- level.spawnVars[ level.numSpawnVars ][0] = G_AddSpawnVarToken( keyname );
- level.spawnVars[ level.numSpawnVars ][1] = G_AddSpawnVarToken( com_token );
- level.numSpawnVars++;
- }
-
- return qtrue;
-}
-
-
-
-/*QUAKED worldspawn (0 0 0) ?
-
-Every map should have exactly one worldspawn.
-"music" music wav file
-"gravity" 800 is default gravity
-"message" Text to print during connection process
-*/
-void SP_worldspawn( void ) {
- char *s;
-
- G_SpawnString( "classname", "", &s );
- if ( Q_stricmp( s, "worldspawn" ) ) {
- G_Error( "SP_worldspawn: The first entity isn't 'worldspawn'" );
- }
-
- // make some data visible to connecting client
- trap_SetConfigstring( CS_GAME_VERSION, GAME_VERSION );
-
- trap_SetConfigstring( CS_LEVEL_START_TIME, va("%i", level.startTime ) );
-
- if ( *g_music.string && Q_stricmp( g_music.string, "none" ) ) {
- trap_SetConfigstring( CS_MUSIC, g_music.string );
- } else {
- G_SpawnString( "music", "", &s );
- trap_SetConfigstring( CS_MUSIC, s );
- }
-
- G_SpawnString( "message", "", &s );
- trap_SetConfigstring( CS_MESSAGE, s ); // map specific message
-
- trap_SetConfigstring( CS_MOTD, g_motd.string ); // message of the day
-
- G_SpawnString( "gravity", "800", &s );
- trap_Cvar_Set( "g_gravity", s );
-
- G_SpawnString( "enableDust", "0", &s );
- trap_Cvar_Set( "g_enableDust", s );
-
- G_SpawnString( "enableBreath", "0", &s );
- trap_Cvar_Set( "g_enableBreath", s );
-
- g_entities[ENTITYNUM_WORLD].s.number = ENTITYNUM_WORLD;
- g_entities[ENTITYNUM_WORLD].classname = "worldspawn";
-
- // see if we want a warmup time
- trap_SetConfigstring( CS_WARMUP, "" );
- if ( g_restarted.integer ) {
- trap_Cvar_Set( "g_restarted", "0" );
- level.warmupTime = 0;
- } else if ( g_doWarmup.integer ) { // Turn it on
- level.warmupTime = -1;
- trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
- G_LogPrintf( "Warmup:\n" );
- }
-
-}
-
-
-/*
-==============
-G_SpawnEntitiesFromString
-
-Parses textual entity definitions out of an entstring and spawns gentities.
-==============
-*/
-void G_SpawnEntitiesFromString( void ) {
- // allow calls to G_Spawn*()
- level.spawning = qtrue;
- level.numSpawnVars = 0;
-
- // the worldspawn is not an actual entity, but it still
- // has a "spawn" function to perform any global setup
- // needed by a level (setting configstrings or cvars, etc)
- if ( !G_ParseSpawnVars() ) {
- G_Error( "SpawnEntities: no entities" );
- }
- SP_worldspawn();
-
- // parse ents
- while( G_ParseSpawnVars() ) {
- G_SpawnGEntityFromSpawnVars();
- }
-
- level.spawning = qfalse; // any future calls to G_Spawn*() will be errors
-}
-
diff --git a/game/code/game/g_svcmds.c b/game/code/game/g_svcmds.c
deleted file mode 100644
index 9d76eb8..0000000
--- a/game/code/game/g_svcmds.c
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-// this file holds commands that can be executed by the server console, but not remote clients
-
-#include "g_local.h"
-
-
-/*
-==============================================================================
-
-PACKET FILTERING
-
-
-You can add or remove addresses from the filter list with:
-
-addip <ip>
-removeip <ip>
-
-The ip address is specified in dot format, and you can use '*' to match any value
-so you can specify an entire class C network with "addip 192.246.40.*"
-
-Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host.
-
-listip
-Prints the current list of filters.
-
-g_filterban <0 or 1>
-
-If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game. This is the default setting.
-
-If 0, then only addresses matching the list will be allowed. This lets you easily set up a private game, or a game that only allows players from your local network.
-
-TTimo NOTE: for persistence, bans are stored in g_banIPs cvar MAX_CVAR_VALUE_STRING
-The size of the cvar string buffer is limiting the banning to around 20 masks
-this could be improved by putting some g_banIPs2 g_banIps3 etc. maybe
-still, you should rely on PB for banning instead
-
-==============================================================================
-*/
-
-typedef struct ipFilter_s
-{
- unsigned mask;
- unsigned compare;
-} ipFilter_t;
-
-#define MAX_IPFILTERS 1024
-
-static ipFilter_t ipFilters[MAX_IPFILTERS];
-static int numIPFilters;
-
-/*
-=================
-StringToFilter
-=================
-*/
-static qboolean StringToFilter (char *s, ipFilter_t *f)
-{
- char num[128];
- int i, j;
- byte b[4];
- byte m[4];
-
- for (i=0 ; i<4 ; i++)
- {
- b[i] = 0;
- m[i] = 0;
- }
-
- for (i=0 ; i<4 ; i++)
- {
- if (*s < '0' || *s > '9')
- {
- if (*s == '*') // 'match any'
- {
- // b[i] and m[i] to 0
- s++;
- if (!*s)
- break;
- s++;
- continue;
- }
- G_Printf( "Bad filter address: %s\n", s );
- return qfalse;
- }
-
- j = 0;
- while (*s >= '0' && *s <= '9')
- {
- num[j++] = *s++;
- }
- num[j] = 0;
- b[i] = atoi(num);
- m[i] = 255;
-
- if (!*s)
- break;
- s++;
- }
-
- f->mask = *(unsigned *)m;
- f->compare = *(unsigned *)b;
-
- return qtrue;
-}
-
-/*
-=================
-UpdateIPBans
-=================
-*/
-static void UpdateIPBans (void)
-{
- byte b[4];
- byte m[4];
- int i,j;
- char iplist_final[MAX_CVAR_VALUE_STRING];
- char ip[64];
-
- *iplist_final = 0;
- for (i = 0 ; i < numIPFilters ; i++)
- {
- if (ipFilters[i].compare == 0xffffffff)
- continue;
-
- *(unsigned *)b = ipFilters[i].compare;
- *(unsigned *)m = ipFilters[i].mask;
- *ip = 0;
- for (j = 0 ; j < 4 ; j++)
- {
- if (m[j]!=255)
- Q_strcat(ip, sizeof(ip), "*");
- else
- Q_strcat(ip, sizeof(ip), va("%i", b[j]));
- Q_strcat(ip, sizeof(ip), (j<3) ? "." : " ");
- }
- if (strlen(iplist_final)+strlen(ip) < MAX_CVAR_VALUE_STRING)
- {
- Q_strcat( iplist_final, sizeof(iplist_final), ip);
- }
- else
- {
- Com_Printf("g_banIPs overflowed at MAX_CVAR_VALUE_STRING\n");
- break;
- }
- }
-
- trap_Cvar_Set( "g_banIPs", iplist_final );
-}
-
-/*
-=================
-G_FilterPacket
-=================
-*/
-qboolean G_FilterPacket (char *from)
-{
- int i;
- unsigned in;
- byte m[4];
- char *p;
-
- i = 0;
- p = from;
- while (*p && i < 4) {
- m[i] = 0;
- while (*p >= '0' && *p <= '9') {
- m[i] = m[i]*10 + (*p - '0');
- p++;
- }
- if (!*p || *p == ':')
- break;
- i++, p++;
- }
-
- in = *(unsigned *)m;
-
- for (i=0 ; i<numIPFilters ; i++)
- if ( (in & ipFilters[i].mask) == ipFilters[i].compare)
- return g_filterBan.integer != 0;
-
- return g_filterBan.integer == 0;
-}
-
-/*
-=================
-AddIP
-=================
-*/
-static void AddIP( char *str )
-{
- int i;
-
- for (i = 0 ; i < numIPFilters ; i++)
- if (ipFilters[i].compare == 0xffffffff)
- break; // free spot
- if (i == numIPFilters)
- {
- if (numIPFilters == MAX_IPFILTERS)
- {
- G_Printf ("IP filter list is full\n");
- return;
- }
- numIPFilters++;
- }
-
- if (!StringToFilter (str, &ipFilters[i]))
- ipFilters[i].compare = 0xffffffffu;
-
- UpdateIPBans();
-}
-
-/*
-=================
-G_ProcessIPBans
-=================
-*/
-void G_ProcessIPBans(void)
-{
- char *s, *t;
- char str[MAX_CVAR_VALUE_STRING];
-
- Q_strncpyz( str, g_banIPs.string, sizeof(str) );
-
- for (t = s = g_banIPs.string; *t; /* */ ) {
- s = strchr(s, ' ');
- if (!s)
- break;
- while (*s == ' ')
- *s++ = 0;
- if (*t)
- AddIP( t );
- t = s;
- }
-}
-
-
-/*
-=================
-Svcmd_AddIP_f
-=================
-*/
-void Svcmd_AddIP_f (void)
-{
- char str[MAX_TOKEN_CHARS];
-
- if ( trap_Argc() < 2 ) {
- G_Printf("Usage: addip <ip-mask>\n");
- return;
- }
-
- trap_Argv( 1, str, sizeof( str ) );
-
- AddIP( str );
-
-}
-
-/*
-=================
-Svcmd_RemoveIP_f
-=================
-*/
-void Svcmd_RemoveIP_f (void)
-{
- ipFilter_t f;
- int i;
- char str[MAX_TOKEN_CHARS];
-
- if ( trap_Argc() < 2 ) {
- G_Printf("Usage: sv removeip <ip-mask>\n");
- return;
- }
-
- trap_Argv( 1, str, sizeof( str ) );
-
- if (!StringToFilter (str, &f))
- return;
-
- for (i=0 ; i<numIPFilters ; i++) {
- if (ipFilters[i].mask == f.mask &&
- ipFilters[i].compare == f.compare) {
- ipFilters[i].compare = 0xffffffffu;
- G_Printf ("Removed.\n");
-
- UpdateIPBans();
- return;
- }
- }
- G_Printf ( "Didn't find %s.\n", str );
-}
-
-/*
-===================
-Svcmd_EntityList_f
-===================
-*/
-void Svcmd_EntityList_f (void) {
- int e;
- gentity_t *check;
-
- check = g_entities+1;
- for (e = 1; e < level.num_entities ; e++, check++) {
- if ( !check->inuse ) {
- continue;
- }
- G_Printf("%3i:", e);
- switch ( check->s.eType ) {
- case ET_GENERAL:
- G_Printf("ET_GENERAL ");
- break;
- case ET_PLAYER:
- G_Printf("ET_PLAYER ");
- break;
- case ET_ITEM:
- G_Printf("ET_ITEM ");
- break;
- case ET_MISSILE:
- G_Printf("ET_MISSILE ");
- break;
- case ET_MOVER:
- G_Printf("ET_MOVER ");
- break;
- case ET_BEAM:
- G_Printf("ET_BEAM ");
- break;
- case ET_PORTAL:
- G_Printf("ET_PORTAL ");
- break;
- case ET_SPEAKER:
- G_Printf("ET_SPEAKER ");
- break;
- case ET_PUSH_TRIGGER:
- G_Printf("ET_PUSH_TRIGGER ");
- break;
- case ET_TELEPORT_TRIGGER:
- G_Printf("ET_TELEPORT_TRIGGER ");
- break;
- case ET_INVISIBLE:
- G_Printf("ET_INVISIBLE ");
- break;
- case ET_GRAPPLE:
- G_Printf("ET_GRAPPLE ");
- break;
- default:
- G_Printf("%3i ", check->s.eType);
- break;
- }
- if ( check->classname ) {
- G_Printf("%s", check->classname);
- }
- G_Printf("\n");
- }
-}
-
-gclient_t *ClientForString( const char *s ) {
- gclient_t *cl;
- int i;
- int idnum;
-
- // numeric values are just slot numbers
- if ( s[0] >= '0' && s[0] <= '9' ) {
- idnum = atoi( s );
- if ( idnum < 0 || idnum >= level.maxclients ) {
- Com_Printf( "Bad client slot: %i\n", idnum );
- return NULL;
- }
-
- cl = &level.clients[idnum];
- if ( cl->pers.connected == CON_DISCONNECTED ) {
- G_Printf( "Client %i is not connected\n", idnum );
- return NULL;
- }
- return cl;
- }
-
- // check for a name match
- for ( i=0 ; i < level.maxclients ; i++ ) {
- cl = &level.clients[i];
- if ( cl->pers.connected == CON_DISCONNECTED ) {
- continue;
- }
- if ( !Q_stricmp( cl->pers.netname, s ) ) {
- return cl;
- }
- }
- G_Printf( "User %s is not on the server\n", s );
-
- return NULL;
-}
-
-/*
-===================
-Svcmd_ForceTeam_f
-
-forceteam <player> <team>
-===================
-*/
-void Svcmd_ForceTeam_f( void ) {
- gclient_t *cl;
- char str[MAX_TOKEN_CHARS];
-
- // find the player
- trap_Argv( 1, str, sizeof( str ) );
- cl = ClientForString( str );
- if ( !cl ) {
- return;
- }
-
- // set the team
- trap_Argv( 2, str, sizeof( str ) );
- SetTeam( &g_entities[cl - level.clients], str );
-}
-
-void ClientKick_f( void ) {
- int idnum, i;
- char str[MAX_TOKEN_CHARS];
-
- trap_Argv( 1, str, sizeof( str ) );
-
- for (i = 0; str[i]; i++) {
- if (str[i] < '0' || str[i] > '9') {
- G_Printf("not a valid client number: \"%s\"\n",str);
- return;
- }
- }
-
- idnum = atoi( str );
-
- //Local client
- if( !strcmp( level.clients[idnum].pers.ip, "localhost" ) ) {
- G_Printf("Kick failed - local player\n");
- return;
- }
-
- //Now clientkick has been moved into game, but we still need to find the idnum the server expects....
- //FIXME: To fix this, we need a relieble way to generate difference between the server's client number and the game's client numbers
- //FIXME: This should not depend on the engine's clientkick at all
- trap_DropClient( idnum, "was kicked" );
- //trap_SendConsoleCommand( EXEC_INSERT, va("clientkick %d\n", level.clients[idnum].ps.clientNum) );
-
-}
-
-//KK-OAX Moved this Declaration to g_local.h
-//char *ConcatArgs( int start );
-
-/*KK-OAX
-===============
-Server Command Table
-Not Worth Listing Elsewhere
-================
-*/
-struct
-{
- char *cmd;
- qboolean dedicated; //if it has to be entered from a dedicated server or RCON
- void ( *function )( void );
-} svcmds[ ] = {
-
- { "entityList", qfalse, Svcmd_EntityList_f },
- { "forceTeam", qfalse, Svcmd_ForceTeam_f },
- { "game_memory", qfalse, Svcmd_GameMem_f },
- { "addbot", qfalse, Svcmd_AddBot_f },
- { "botlist", qfalse, Svcmd_BotList_f },
- { "abort_podium", qfalse, Svcmd_AbortPodium_f },
- { "addip", qfalse, Svcmd_AddIP_f },
- { "removeip", qfalse, Svcmd_RemoveIP_f },
-
- //KK-OAX Uses wrapper in g_svccmds_ext.c
- { "listip", qfalse, Svcmd_ListIP_f },
- //KK-OAX New
- { "status", qfalse, Svcmd_Status_f },
- { "eject", qfalse, Svcmd_EjectClient_f },
- { "dumpuser", qfalse, Svcmd_DumpUser_f },
- // don't handle communication commands unless dedicated
- { "cp", qtrue, Svcmd_CenterPrint_f },
- { "say_team", qtrue, Svcmd_TeamMessage_f },
- { "say", qtrue, Svcmd_MessageWrapper },
- { "chat", qtrue, Svcmd_Chat_f },
- /*{ "m", qtrue, Svcmd_MessageWrapper },
- { "a", qtrue, Svcmd_MessageWrapper },
- { "bp", qtrue, Svcmd_BannerPrint_f }, */
- //Shuffle the teams
- { "shuffle", qfalse, ShuffleTeams },
- //Kicks a player by number in the game logic rather than the server number
- { "clientkick_game", qfalse, ClientKick_f },
-};
-
-/*
-=================
-ConsoleCommand
-
-=================
-*/
-qboolean ConsoleCommand( void )
-{
- char cmd[ MAX_TOKEN_CHARS ];
- int i;
-
- trap_Argv( 0, cmd, sizeof( cmd ) );
-
- for( i = 0; i < sizeof( svcmds ) / sizeof( svcmds[ 0 ] ); i++ )
- {
- if( !Q_stricmp( cmd, svcmds[ i ].cmd ) )
- {
- if( svcmds[ i ].dedicated && !g_dedicated.integer )
- return qfalse;
- svcmds[ i ].function( );
- return qtrue;
- }
- }
- // KK-OAX Will be enabled when admin is added.
- // see if this is an admin command
- if( G_admin_cmd_check( NULL, qfalse ) )
- return qtrue;
-
- if( g_dedicated.integer )
- G_Printf( "unknown command: %s\n", cmd );
-
- return qfalse;
-}
-
diff --git a/game/code/game/g_syscalls.asm b/game/code/game/g_syscalls.asm
deleted file mode 100644
index 19de97d..0000000
--- a/game/code/game/g_syscalls.asm
+++ /dev/null
@@ -1,225 +0,0 @@
-code
-
-equ trap_Printf -1
-equ trap_Error -2
-equ trap_Milliseconds -3
-equ trap_Cvar_Register -4
-equ trap_Cvar_Update -5
-equ trap_Cvar_Set -6
-equ trap_Cvar_VariableIntegerValue -7
-equ trap_Cvar_VariableStringBuffer -8
-equ trap_Argc -9
-equ trap_Argv -10
-equ trap_FS_FOpenFile -11
-equ trap_FS_Read -12
-equ trap_FS_Write -13
-equ trap_FS_FCloseFile -14
-equ trap_SendConsoleCommand -15
-equ trap_LocateGameData -16
-equ trap_DropClient -17
-equ trap_SendServerCommand -18
-equ trap_SetConfigstring -19
-equ trap_GetConfigstring -20
-equ trap_GetUserinfo -21
-equ trap_SetUserinfo -22
-equ trap_GetServerinfo -23
-equ trap_SetBrushModel -24
-equ trap_Trace -25
-equ trap_PointContents -26
-equ trap_InPVS -27
-equ trap_InPVSIgnorePortals -28
-equ trap_AdjustAreaPortalState -29
-equ trap_AreasConnected -30
-equ trap_LinkEntity -31
-equ trap_UnlinkEntity -32
-equ trap_EntitiesInBox -33
-equ trap_EntityContact -34
-equ trap_BotAllocateClient -35
-equ trap_BotFreeClient -36
-equ trap_GetUsercmd -37
-equ trap_GetEntityToken -38
-equ trap_FS_GetFileList -39
-equ trap_DebugPolygonCreate -40
-equ trap_DebugPolygonDelete -41
-equ trap_RealTime -42
-equ trap_SnapVector -43
-equ trap_TraceCapsule -44
-equ trap_EntityContactCapsule -45
-equ trap_FS_Seek -46
-
-equ memset -101
-equ memcpy -102
-equ strncpy -103
-equ sin -104
-equ cos -105
-equ atan2 -106
-equ sqrt -107
-equ floor -111
-equ ceil -112
-equ testPrintInt -113
-equ testPrintFloat -114
-
-
-
-equ trap_BotLibSetup -201
-equ trap_BotLibShutdown -202
-equ trap_BotLibVarSet -203
-equ trap_BotLibVarGet -204
-equ trap_BotLibDefine -205
-equ trap_BotLibStartFrame -206
-equ trap_BotLibLoadMap -207
-equ trap_BotLibUpdateEntity -208
-equ trap_BotLibTest -209
-
-equ trap_BotGetSnapshotEntity -210
-equ trap_BotGetServerCommand -211
-equ trap_BotUserCommand -212
-
-
-
-equ trap_AAS_EnableRoutingArea -301
-equ trap_AAS_BBoxAreas -302
-equ trap_AAS_AreaInfo -303
-equ trap_AAS_EntityInfo -304
-
-equ trap_AAS_Initialized -305
-equ trap_AAS_PresenceTypeBoundingBox -306
-equ trap_AAS_Time -307
-
-equ trap_AAS_PointAreaNum -308
-equ trap_AAS_TraceAreas -309
-
-equ trap_AAS_PointContents -310
-equ trap_AAS_NextBSPEntity -311
-equ trap_AAS_ValueForBSPEpairKey -312
-equ trap_AAS_VectorForBSPEpairKey -313
-equ trap_AAS_FloatForBSPEpairKey -314
-equ trap_AAS_IntForBSPEpairKey -315
-
-equ trap_AAS_AreaReachability -316
-
-equ trap_AAS_AreaTravelTimeToGoalArea -317
-
-equ trap_AAS_Swimming -318
-equ trap_AAS_PredictClientMovement -319
-
-
-
-equ trap_EA_Say -401
-equ trap_EA_SayTeam -402
-equ trap_EA_Command -403
-
-equ trap_EA_Action -404
-equ trap_EA_Gesture -405
-equ trap_EA_Talk -406
-equ trap_EA_Attack -407
-equ trap_EA_Use -408
-equ trap_EA_Respawn -409
-equ trap_EA_Crouch -410
-equ trap_EA_MoveUp -411
-equ trap_EA_MoveDown -412
-equ trap_EA_MoveForward -413
-equ trap_EA_MoveBack -414
-equ trap_EA_MoveLeft -415
-equ trap_EA_MoveRight -416
-
-equ trap_EA_SelectWeapon -417
-equ trap_EA_Jump -418
-equ trap_EA_DelayedJump -419
-equ trap_EA_Move -420
-equ trap_EA_View -421
-
-equ trap_EA_EndRegular -422
-equ trap_EA_GetInput -423
-equ trap_EA_ResetInput -424
-
-
-
-equ trap_BotLoadCharacter -501
-equ trap_BotFreeCharacter -502
-equ trap_Characteristic_Float -503
-equ trap_Characteristic_BFloat -504
-equ trap_Characteristic_Integer -505
-equ trap_Characteristic_BInteger -506
-equ trap_Characteristic_String -507
-
-equ trap_BotAllocChatState -508
-equ trap_BotFreeChatState -509
-equ trap_BotQueueConsoleMessage -510
-equ trap_BotRemoveConsoleMessage -511
-equ trap_BotNextConsoleMessage -512
-equ trap_BotNumConsoleMessages -513
-equ trap_BotInitialChat -514
-equ trap_BotReplyChat -515
-equ trap_BotChatLength -516
-equ trap_BotEnterChat -517
-equ trap_StringContains -518
-equ trap_BotFindMatch -519
-equ trap_BotMatchVariable -520
-equ trap_UnifyWhiteSpaces -521
-equ trap_BotReplaceSynonyms -522
-equ trap_BotLoadChatFile -523
-equ trap_BotSetChatGender -524
-equ trap_BotSetChatName -525
-
-equ trap_BotResetGoalState -526
-equ trap_BotResetAvoidGoals -527
-equ trap_BotPushGoal -528
-equ trap_BotPopGoal -529
-equ trap_BotEmptyGoalStack -530
-equ trap_BotDumpAvoidGoals -531
-equ trap_BotDumpGoalStack -532
-equ trap_BotGoalName -533
-equ trap_BotGetTopGoal -534
-equ trap_BotGetSecondGoal -535
-equ trap_BotChooseLTGItem -536
-equ trap_BotChooseNBGItem -537
-equ trap_BotTouchingGoal -538
-equ trap_BotItemGoalInVisButNotVisible -539
-equ trap_BotGetLevelItemGoal -540
-equ trap_BotAvoidGoalTime -541
-equ trap_BotInitLevelItems -542
-equ trap_BotUpdateEntityItems -543
-equ trap_BotLoadItemWeights -544
-equ trap_BotFreeItemWeights -546
-equ trap_BotSaveGoalFuzzyLogic -546
-equ trap_BotAllocGoalState -547
-equ trap_BotFreeGoalState -548
-
-equ trap_BotResetMoveState -549
-equ trap_BotMoveToGoal -550
-equ trap_BotMoveInDirection -551
-equ trap_BotResetAvoidReach -552
-equ trap_BotResetLastAvoidReach -553
-equ trap_BotReachabilityArea -554
-equ trap_BotMovementViewTarget -555
-equ trap_BotAllocMoveState -556
-equ trap_BotFreeMoveState -557
-equ trap_BotInitMoveState -558
-
-equ trap_BotChooseBestFightWeapon -559
-equ trap_BotGetWeaponInfo -560
-equ trap_BotLoadWeaponWeights -561
-equ trap_BotAllocWeaponState -562
-equ trap_BotFreeWeaponState -563
-equ trap_BotResetWeaponState -564
-equ trap_GeneticParentsAndChildSelection -565
-equ trap_BotInterbreedGoalFuzzyLogic -566
-equ trap_BotMutateGoalFuzzyLogic -567
-equ trap_BotGetNextCampSpotGoal -568
-equ trap_BotGetMapLocationGoal -569
-equ trap_BotNumInitialChats -570
-equ trap_BotGetChatMessage -571
-equ trap_BotRemoveFromAvoidGoals -572
-equ trap_BotPredictVisiblePosition -573
-equ trap_BotSetAvoidGoalTime -574
-equ trap_BotAddAvoidSpot -575
-equ trap_AAS_AlternativeRouteGoals -576
-equ trap_AAS_PredictRoute -577
-equ trap_AAS_PointReachabilityAreaIndex -578
-
-equ trap_BotLibLoadSource -579
-equ trap_BotLibFreeSource -580
-equ trap_BotLibReadToken -581
-equ trap_BotLibSourceFileAndLine -582
-
diff --git a/game/code/game/g_syscalls.c b/game/code/game/g_syscalls.c
deleted file mode 100644
index 1868d0a..0000000
--- a/game/code/game/g_syscalls.c
+++ /dev/null
@@ -1,790 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-// this file is only included when building a dll
-// g_syscalls.asm is included instead when building a qvm
-#ifdef Q3_VM
-#error "Do not use in VM build"
-#endif
-
-static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;
-
-
-Q_EXPORT void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) {
- syscall = syscallptr;
-}
-
-int PASSFLOAT( float x ) {
- floatint_t fi;
- fi.f = x;
- return fi.i;
-}
-
-void trap_Printf( const char *fmt ) {
- syscall( G_PRINT, fmt );
-}
-
-void trap_Error( const char *fmt ) {
- syscall( G_ERROR, fmt );
-}
-
-int trap_Milliseconds( void ) {
- return syscall( G_MILLISECONDS );
-}
-int trap_Argc( void ) {
- return syscall( G_ARGC );
-}
-
-void trap_Argv( int n, char *buffer, int bufferLength ) {
- syscall( G_ARGV, n, buffer, bufferLength );
-}
-
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
- return syscall( G_FS_FOPEN_FILE, qpath, f, mode );
-}
-
-void trap_FS_Read( void *buffer, int len, fileHandle_t f ) {
- syscall( G_FS_READ, buffer, len, f );
-}
-
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f ) {
- syscall( G_FS_WRITE, buffer, len, f );
-}
-
-void trap_FS_FCloseFile( fileHandle_t f ) {
- syscall( G_FS_FCLOSE_FILE, f );
-}
-
-int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ) {
- return syscall( G_FS_GETFILELIST, path, extension, listbuf, bufsize );
-}
-
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ) {
- return syscall( G_FS_SEEK, f, offset, origin );
-}
-
-void trap_SendConsoleCommand( int exec_when, const char *text ) {
- syscall( G_SEND_CONSOLE_COMMAND, exec_when, text );
-}
-
-void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags ) {
- syscall( G_CVAR_REGISTER, cvar, var_name, value, flags );
-}
-
-void trap_Cvar_Update( vmCvar_t *cvar ) {
- syscall( G_CVAR_UPDATE, cvar );
-}
-
-void trap_Cvar_Set( const char *var_name, const char *value ) {
- syscall( G_CVAR_SET, var_name, value );
-}
-
-int trap_Cvar_VariableIntegerValue( const char *var_name ) {
- return syscall( G_CVAR_VARIABLE_INTEGER_VALUE, var_name );
-}
-
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
- syscall( G_CVAR_VARIABLE_STRING_BUFFER, var_name, buffer, bufsize );
-}
-
-
-void trap_LocateGameData( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
- playerState_t *clients, int sizeofGClient ) {
- syscall( G_LOCATE_GAME_DATA, gEnts, numGEntities, sizeofGEntity_t, clients, sizeofGClient );
-}
-
-void trap_DropClient( int clientNum, const char *reason ) {
- syscall( G_DROP_CLIENT, clientNum, reason );
-}
-
-void trap_SendServerCommand( int clientNum, const char *text ) {
- syscall( G_SEND_SERVER_COMMAND, clientNum, text );
-}
-
-void trap_SetConfigstring( int num, const char *string ) {
- syscall( G_SET_CONFIGSTRING, num, string );
-}
-
-void trap_GetConfigstring( int num, char *buffer, int bufferSize ) {
- syscall( G_GET_CONFIGSTRING, num, buffer, bufferSize );
-}
-
-void trap_GetUserinfo( int num, char *buffer, int bufferSize ) {
- syscall( G_GET_USERINFO, num, buffer, bufferSize );
-}
-
-void trap_SetUserinfo( int num, const char *buffer ) {
- syscall( G_SET_USERINFO, num, buffer );
-}
-
-void trap_GetServerinfo( char *buffer, int bufferSize ) {
- syscall( G_GET_SERVERINFO, buffer, bufferSize );
-}
-
-void trap_SetBrushModel( gentity_t *ent, const char *name ) {
- syscall( G_SET_BRUSH_MODEL, ent, name );
-}
-
-void trap_Trace( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask ) {
- syscall( G_TRACE, results, start, mins, maxs, end, passEntityNum, contentmask );
-}
-
-void trap_TraceCapsule( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask ) {
- syscall( G_TRACECAPSULE, results, start, mins, maxs, end, passEntityNum, contentmask );
-}
-
-int trap_PointContents( const vec3_t point, int passEntityNum ) {
- return syscall( G_POINT_CONTENTS, point, passEntityNum );
-}
-
-
-qboolean trap_InPVS( const vec3_t p1, const vec3_t p2 ) {
- return syscall( G_IN_PVS, p1, p2 );
-}
-
-qboolean trap_InPVSIgnorePortals( const vec3_t p1, const vec3_t p2 ) {
- return syscall( G_IN_PVS_IGNORE_PORTALS, p1, p2 );
-}
-
-void trap_AdjustAreaPortalState( gentity_t *ent, qboolean open ) {
- syscall( G_ADJUST_AREA_PORTAL_STATE, ent, open );
-}
-
-qboolean trap_AreasConnected( int area1, int area2 ) {
- return syscall( G_AREAS_CONNECTED, area1, area2 );
-}
-
-void trap_LinkEntity( gentity_t *ent ) {
- syscall( G_LINKENTITY, ent );
-}
-
-void trap_UnlinkEntity( gentity_t *ent ) {
- syscall( G_UNLINKENTITY, ent );
-}
-
-int trap_EntitiesInBox( const vec3_t mins, const vec3_t maxs, int *list, int maxcount ) {
- return syscall( G_ENTITIES_IN_BOX, mins, maxs, list, maxcount );
-}
-
-qboolean trap_EntityContact( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ) {
- return syscall( G_ENTITY_CONTACT, mins, maxs, ent );
-}
-
-qboolean trap_EntityContactCapsule( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ) {
- return syscall( G_ENTITY_CONTACTCAPSULE, mins, maxs, ent );
-}
-
-int trap_BotAllocateClient( void ) {
- return syscall( G_BOT_ALLOCATE_CLIENT );
-}
-
-void trap_BotFreeClient( int clientNum ) {
- syscall( G_BOT_FREE_CLIENT, clientNum );
-}
-
-void trap_GetUsercmd( int clientNum, usercmd_t *cmd ) {
- syscall( G_GET_USERCMD, clientNum, cmd );
-}
-
-qboolean trap_GetEntityToken( char *buffer, int bufferSize ) {
- return syscall( G_GET_ENTITY_TOKEN, buffer, bufferSize );
-}
-
-int trap_DebugPolygonCreate(int color, int numPoints, vec3_t *points) {
- return syscall( G_DEBUG_POLYGON_CREATE, color, numPoints, points );
-}
-
-void trap_DebugPolygonDelete(int id) {
- syscall( G_DEBUG_POLYGON_DELETE, id );
-}
-
-int trap_RealTime( qtime_t *qtime ) {
- return syscall( G_REAL_TIME, qtime );
-}
-
-void trap_SnapVector( float *v ) {
- syscall( G_SNAPVECTOR, v );
- return;
-}
-
-// BotLib traps start here
-int trap_BotLibSetup( void ) {
- return syscall( BOTLIB_SETUP );
-}
-
-int trap_BotLibShutdown( void ) {
- return syscall( BOTLIB_SHUTDOWN );
-}
-
-int trap_BotLibVarSet(char *var_name, char *value) {
- return syscall( BOTLIB_LIBVAR_SET, var_name, value );
-}
-
-int trap_BotLibVarGet(char *var_name, char *value, int size) {
- return syscall( BOTLIB_LIBVAR_GET, var_name, value, size );
-}
-
-int trap_BotLibDefine(char *string) {
- return syscall( BOTLIB_PC_ADD_GLOBAL_DEFINE, string );
-}
-
-int trap_BotLibStartFrame(float time) {
- return syscall( BOTLIB_START_FRAME, PASSFLOAT( time ) );
-}
-
-int trap_BotLibLoadMap(const char *mapname) {
- return syscall( BOTLIB_LOAD_MAP, mapname );
-}
-
-int trap_BotLibUpdateEntity(int ent, void /* struct bot_updateentity_s */ *bue) {
- return syscall( BOTLIB_UPDATENTITY, ent, bue );
-}
-
-int trap_BotLibTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3) {
- return syscall( BOTLIB_TEST, parm0, parm1, parm2, parm3 );
-}
-
-int trap_BotGetSnapshotEntity( int clientNum, int sequence ) {
- return syscall( BOTLIB_GET_SNAPSHOT_ENTITY, clientNum, sequence );
-}
-
-int trap_BotGetServerCommand(int clientNum, char *message, int size) {
- return syscall( BOTLIB_GET_CONSOLE_MESSAGE, clientNum, message, size );
-}
-
-void trap_BotUserCommand(int clientNum, usercmd_t *ucmd) {
- syscall( BOTLIB_USER_COMMAND, clientNum, ucmd );
-}
-
-void trap_AAS_EntityInfo(int entnum, void /* struct aas_entityinfo_s */ *info) {
- syscall( BOTLIB_AAS_ENTITY_INFO, entnum, info );
-}
-
-int trap_AAS_Initialized(void) {
- return syscall( BOTLIB_AAS_INITIALIZED );
-}
-
-void trap_AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs) {
- syscall( BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX, presencetype, mins, maxs );
-}
-
-float trap_AAS_Time(void) {
- floatint_t fi;
- fi.i = syscall( BOTLIB_AAS_TIME );
- return fi.f;
-}
-
-int trap_AAS_PointAreaNum(vec3_t point) {
- return syscall( BOTLIB_AAS_POINT_AREA_NUM, point );
-}
-
-int trap_AAS_PointReachabilityAreaIndex(vec3_t point) {
- return syscall( BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX, point );
-}
-
-int trap_AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas) {
- return syscall( BOTLIB_AAS_TRACE_AREAS, start, end, areas, points, maxareas );
-}
-
-int trap_AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas) {
- return syscall( BOTLIB_AAS_BBOX_AREAS, absmins, absmaxs, areas, maxareas );
-}
-
-int trap_AAS_AreaInfo( int areanum, void /* struct aas_areainfo_s */ *info ) {
- return syscall( BOTLIB_AAS_AREA_INFO, areanum, info );
-}
-
-int trap_AAS_PointContents(vec3_t point) {
- return syscall( BOTLIB_AAS_POINT_CONTENTS, point );
-}
-
-int trap_AAS_NextBSPEntity(int ent) {
- return syscall( BOTLIB_AAS_NEXT_BSP_ENTITY, ent );
-}
-
-int trap_AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size) {
- return syscall( BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY, ent, key, value, size );
-}
-
-int trap_AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v) {
- return syscall( BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY, ent, key, v );
-}
-
-int trap_AAS_FloatForBSPEpairKey(int ent, char *key, float *value) {
- return syscall( BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY, ent, key, value );
-}
-
-int trap_AAS_IntForBSPEpairKey(int ent, char *key, int *value) {
- return syscall( BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY, ent, key, value );
-}
-
-int trap_AAS_AreaReachability(int areanum) {
- return syscall( BOTLIB_AAS_AREA_REACHABILITY, areanum );
-}
-
-int trap_AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags) {
- return syscall( BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA, areanum, origin, goalareanum, travelflags );
-}
-
-int trap_AAS_EnableRoutingArea( int areanum, int enable ) {
- return syscall( BOTLIB_AAS_ENABLE_ROUTING_AREA, areanum, enable );
-}
-
-int trap_AAS_PredictRoute(void /*struct aas_predictroute_s*/ *route, int areanum, vec3_t origin,
- int goalareanum, int travelflags, int maxareas, int maxtime,
- int stopevent, int stopcontents, int stoptfl, int stopareanum) {
- return syscall( BOTLIB_AAS_PREDICT_ROUTE, route, areanum, origin, goalareanum, travelflags, maxareas, maxtime, stopevent, stopcontents, stoptfl, stopareanum );
-}
-
-int trap_AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,
- void /*struct aas_altroutegoal_s*/ *altroutegoals, int maxaltroutegoals,
- int type) {
- return syscall( BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL, start, startareanum, goal, goalareanum, travelflags, altroutegoals, maxaltroutegoals, type );
-}
-
-int trap_AAS_Swimming(vec3_t origin) {
- return syscall( BOTLIB_AAS_SWIMMING, origin );
-}
-
-int trap_AAS_PredictClientMovement(void /* struct aas_clientmove_s */ *move, int entnum, vec3_t origin, int presencetype, int onground, vec3_t velocity, vec3_t cmdmove, int cmdframes, int maxframes, float frametime, int stopevent, int stopareanum, int visualize) {
- return syscall( BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT, move, entnum, origin, presencetype, onground, velocity, cmdmove, cmdframes, maxframes, PASSFLOAT(frametime), stopevent, stopareanum, visualize );
-}
-
-void trap_EA_Say(int client, char *str) {
- syscall( BOTLIB_EA_SAY, client, str );
-}
-
-void trap_EA_SayTeam(int client, char *str) {
- syscall( BOTLIB_EA_SAY_TEAM, client, str );
-}
-
-void trap_EA_Command(int client, char *command) {
- syscall( BOTLIB_EA_COMMAND, client, command );
-}
-
-void trap_EA_Action(int client, int action) {
- syscall( BOTLIB_EA_ACTION, client, action );
-}
-
-void trap_EA_Gesture(int client) {
- syscall( BOTLIB_EA_GESTURE, client );
-}
-
-void trap_EA_Talk(int client) {
- syscall( BOTLIB_EA_TALK, client );
-}
-
-void trap_EA_Attack(int client) {
- syscall( BOTLIB_EA_ATTACK, client );
-}
-
-void trap_EA_Use(int client) {
- syscall( BOTLIB_EA_USE, client );
-}
-
-void trap_EA_Respawn(int client) {
- syscall( BOTLIB_EA_RESPAWN, client );
-}
-
-void trap_EA_Crouch(int client) {
- syscall( BOTLIB_EA_CROUCH, client );
-}
-
-void trap_EA_MoveUp(int client) {
- syscall( BOTLIB_EA_MOVE_UP, client );
-}
-
-void trap_EA_MoveDown(int client) {
- syscall( BOTLIB_EA_MOVE_DOWN, client );
-}
-
-void trap_EA_MoveForward(int client) {
- syscall( BOTLIB_EA_MOVE_FORWARD, client );
-}
-
-void trap_EA_MoveBack(int client) {
- syscall( BOTLIB_EA_MOVE_BACK, client );
-}
-
-void trap_EA_MoveLeft(int client) {
- syscall( BOTLIB_EA_MOVE_LEFT, client );
-}
-
-void trap_EA_MoveRight(int client) {
- syscall( BOTLIB_EA_MOVE_RIGHT, client );
-}
-
-void trap_EA_SelectWeapon(int client, int weapon) {
- syscall( BOTLIB_EA_SELECT_WEAPON, client, weapon );
-}
-
-void trap_EA_Jump(int client) {
- syscall( BOTLIB_EA_JUMP, client );
-}
-
-void trap_EA_DelayedJump(int client) {
- syscall( BOTLIB_EA_DELAYED_JUMP, client );
-}
-
-void trap_EA_Move(int client, vec3_t dir, float speed) {
- syscall( BOTLIB_EA_MOVE, client, dir, PASSFLOAT(speed) );
-}
-
-void trap_EA_View(int client, vec3_t viewangles) {
- syscall( BOTLIB_EA_VIEW, client, viewangles );
-}
-
-void trap_EA_EndRegular(int client, float thinktime) {
- syscall( BOTLIB_EA_END_REGULAR, client, PASSFLOAT(thinktime) );
-}
-
-void trap_EA_GetInput(int client, float thinktime, void /* struct bot_input_s */ *input) {
- syscall( BOTLIB_EA_GET_INPUT, client, PASSFLOAT(thinktime), input );
-}
-
-void trap_EA_ResetInput(int client) {
- syscall( BOTLIB_EA_RESET_INPUT, client );
-}
-
-int trap_BotLoadCharacter(char *charfile, float skill) {
- return syscall( BOTLIB_AI_LOAD_CHARACTER, charfile, PASSFLOAT(skill));
-}
-
-void trap_BotFreeCharacter(int character) {
- syscall( BOTLIB_AI_FREE_CHARACTER, character );
-}
-
-float trap_Characteristic_Float(int character, int index) {
- floatint_t fi;
- fi.i = syscall( BOTLIB_AI_CHARACTERISTIC_FLOAT, character, index );
- return fi.f;
-}
-
-float trap_Characteristic_BFloat(int character, int index, float min, float max) {
- floatint_t fi;
- fi.i = syscall( BOTLIB_AI_CHARACTERISTIC_BFLOAT, character, index, PASSFLOAT(min), PASSFLOAT(max) );
- return fi.f;
-}
-
-int trap_Characteristic_Integer(int character, int index) {
- return syscall( BOTLIB_AI_CHARACTERISTIC_INTEGER, character, index );
-}
-
-int trap_Characteristic_BInteger(int character, int index, int min, int max) {
- return syscall( BOTLIB_AI_CHARACTERISTIC_BINTEGER, character, index, min, max );
-}
-
-void trap_Characteristic_String(int character, int index, char *buf, int size) {
- syscall( BOTLIB_AI_CHARACTERISTIC_STRING, character, index, buf, size );
-}
-
-int trap_BotAllocChatState(void) {
- return syscall( BOTLIB_AI_ALLOC_CHAT_STATE );
-}
-
-void trap_BotFreeChatState(int handle) {
- syscall( BOTLIB_AI_FREE_CHAT_STATE, handle );
-}
-
-void trap_BotQueueConsoleMessage(int chatstate, int type, char *message) {
- syscall( BOTLIB_AI_QUEUE_CONSOLE_MESSAGE, chatstate, type, message );
-}
-
-void trap_BotRemoveConsoleMessage(int chatstate, int handle) {
- syscall( BOTLIB_AI_REMOVE_CONSOLE_MESSAGE, chatstate, handle );
-}
-
-int trap_BotNextConsoleMessage(int chatstate, void /* struct bot_consolemessage_s */ *cm) {
- return syscall( BOTLIB_AI_NEXT_CONSOLE_MESSAGE, chatstate, cm );
-}
-
-int trap_BotNumConsoleMessages(int chatstate) {
- return syscall( BOTLIB_AI_NUM_CONSOLE_MESSAGE, chatstate );
-}
-
-void trap_BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 ) {
- syscall( BOTLIB_AI_INITIAL_CHAT, chatstate, type, mcontext, var0, var1, var2, var3, var4, var5, var6, var7 );
-}
-
-int trap_BotNumInitialChats(int chatstate, char *type) {
- return syscall( BOTLIB_AI_NUM_INITIAL_CHATS, chatstate, type );
-}
-
-int trap_BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 ) {
- return syscall( BOTLIB_AI_REPLY_CHAT, chatstate, message, mcontext, vcontext, var0, var1, var2, var3, var4, var5, var6, var7 );
-}
-
-int trap_BotChatLength(int chatstate) {
- return syscall( BOTLIB_AI_CHAT_LENGTH, chatstate );
-}
-
-void trap_BotEnterChat(int chatstate, int client, int sendto) {
- syscall( BOTLIB_AI_ENTER_CHAT, chatstate, client, sendto );
-}
-
-void trap_BotGetChatMessage(int chatstate, char *buf, int size) {
- syscall( BOTLIB_AI_GET_CHAT_MESSAGE, chatstate, buf, size);
-}
-
-int trap_StringContains(char *str1, char *str2, int casesensitive) {
- return syscall( BOTLIB_AI_STRING_CONTAINS, str1, str2, casesensitive );
-}
-
-int trap_BotFindMatch(char *str, void /* struct bot_match_s */ *match, unsigned long int context) {
- return syscall( BOTLIB_AI_FIND_MATCH, str, match, context );
-}
-
-void trap_BotMatchVariable(void /* struct bot_match_s */ *match, int variable, char *buf, int size) {
- syscall( BOTLIB_AI_MATCH_VARIABLE, match, variable, buf, size );
-}
-
-void trap_UnifyWhiteSpaces(char *string) {
- syscall( BOTLIB_AI_UNIFY_WHITE_SPACES, string );
-}
-
-void trap_BotReplaceSynonyms(char *string, unsigned long int context) {
- syscall( BOTLIB_AI_REPLACE_SYNONYMS, string, context );
-}
-
-int trap_BotLoadChatFile(int chatstate, char *chatfile, char *chatname) {
- return syscall( BOTLIB_AI_LOAD_CHAT_FILE, chatstate, chatfile, chatname );
-}
-
-void trap_BotSetChatGender(int chatstate, int gender) {
- syscall( BOTLIB_AI_SET_CHAT_GENDER, chatstate, gender );
-}
-
-void trap_BotSetChatName(int chatstate, char *name, int client) {
- syscall( BOTLIB_AI_SET_CHAT_NAME, chatstate, name, client );
-}
-
-void trap_BotResetGoalState(int goalstate) {
- syscall( BOTLIB_AI_RESET_GOAL_STATE, goalstate );
-}
-
-void trap_BotResetAvoidGoals(int goalstate) {
- syscall( BOTLIB_AI_RESET_AVOID_GOALS, goalstate );
-}
-
-void trap_BotRemoveFromAvoidGoals(int goalstate, int number) {
- syscall( BOTLIB_AI_REMOVE_FROM_AVOID_GOALS, goalstate, number);
-}
-
-void trap_BotPushGoal(int goalstate, void /* struct bot_goal_s */ *goal) {
- syscall( BOTLIB_AI_PUSH_GOAL, goalstate, goal );
-}
-
-void trap_BotPopGoal(int goalstate) {
- syscall( BOTLIB_AI_POP_GOAL, goalstate );
-}
-
-void trap_BotEmptyGoalStack(int goalstate) {
- syscall( BOTLIB_AI_EMPTY_GOAL_STACK, goalstate );
-}
-
-void trap_BotDumpAvoidGoals(int goalstate) {
- syscall( BOTLIB_AI_DUMP_AVOID_GOALS, goalstate );
-}
-
-void trap_BotDumpGoalStack(int goalstate) {
- syscall( BOTLIB_AI_DUMP_GOAL_STACK, goalstate );
-}
-
-void trap_BotGoalName(int number, char *name, int size) {
- syscall( BOTLIB_AI_GOAL_NAME, number, name, size );
-}
-
-int trap_BotGetTopGoal(int goalstate, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_GET_TOP_GOAL, goalstate, goal );
-}
-
-int trap_BotGetSecondGoal(int goalstate, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_GET_SECOND_GOAL, goalstate, goal );
-}
-
-int trap_BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags) {
- return syscall( BOTLIB_AI_CHOOSE_LTG_ITEM, goalstate, origin, inventory, travelflags );
-}
-
-int trap_BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, void /* struct bot_goal_s */ *ltg, float maxtime) {
- return syscall( BOTLIB_AI_CHOOSE_NBG_ITEM, goalstate, origin, inventory, travelflags, ltg, PASSFLOAT(maxtime) );
-}
-
-int trap_BotTouchingGoal(vec3_t origin, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_TOUCHING_GOAL, origin, goal );
-}
-
-int trap_BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE, viewer, eye, viewangles, goal );
-}
-
-int trap_BotGetLevelItemGoal(int index, char *classname, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_GET_LEVEL_ITEM_GOAL, index, classname, goal );
-}
-
-int trap_BotGetNextCampSpotGoal(int num, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL, num, goal );
-}
-
-int trap_BotGetMapLocationGoal(char *name, void /* struct bot_goal_s */ *goal) {
- return syscall( BOTLIB_AI_GET_MAP_LOCATION_GOAL, name, goal );
-}
-
-float trap_BotAvoidGoalTime(int goalstate, int number) {
- floatint_t fi;
- fi.i = syscall( BOTLIB_AI_AVOID_GOAL_TIME, goalstate, number );
- return fi.f;
-}
-
-void trap_BotSetAvoidGoalTime(int goalstate, int number, float avoidtime) {
- syscall( BOTLIB_AI_SET_AVOID_GOAL_TIME, goalstate, number, PASSFLOAT(avoidtime));
-}
-
-void trap_BotInitLevelItems(void) {
- syscall( BOTLIB_AI_INIT_LEVEL_ITEMS );
-}
-
-void trap_BotUpdateEntityItems(void) {
- syscall( BOTLIB_AI_UPDATE_ENTITY_ITEMS );
-}
-
-int trap_BotLoadItemWeights(int goalstate, char *filename) {
- return syscall( BOTLIB_AI_LOAD_ITEM_WEIGHTS, goalstate, filename );
-}
-
-void trap_BotFreeItemWeights(int goalstate) {
- syscall( BOTLIB_AI_FREE_ITEM_WEIGHTS, goalstate );
-}
-
-void trap_BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child) {
- syscall( BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC, parent1, parent2, child );
-}
-
-void trap_BotSaveGoalFuzzyLogic(int goalstate, char *filename) {
- syscall( BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC, goalstate, filename );
-}
-
-void trap_BotMutateGoalFuzzyLogic(int goalstate, float range) {
- syscall( BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC, goalstate, range );
-}
-
-int trap_BotAllocGoalState(int state) {
- return syscall( BOTLIB_AI_ALLOC_GOAL_STATE, state );
-}
-
-void trap_BotFreeGoalState(int handle) {
- syscall( BOTLIB_AI_FREE_GOAL_STATE, handle );
-}
-
-void trap_BotResetMoveState(int movestate) {
- syscall( BOTLIB_AI_RESET_MOVE_STATE, movestate );
-}
-
-void trap_BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type) {
- syscall( BOTLIB_AI_ADD_AVOID_SPOT, movestate, origin, PASSFLOAT(radius), type);
-}
-
-void trap_BotMoveToGoal(void /* struct bot_moveresult_s */ *result, int movestate, void /* struct bot_goal_s */ *goal, int travelflags) {
- syscall( BOTLIB_AI_MOVE_TO_GOAL, result, movestate, goal, travelflags );
-}
-
-int trap_BotMoveInDirection(int movestate, vec3_t dir, float speed, int type) {
- return syscall( BOTLIB_AI_MOVE_IN_DIRECTION, movestate, dir, PASSFLOAT(speed), type );
-}
-
-void trap_BotResetAvoidReach(int movestate) {
- syscall( BOTLIB_AI_RESET_AVOID_REACH, movestate );
-}
-
-void trap_BotResetLastAvoidReach(int movestate) {
- syscall( BOTLIB_AI_RESET_LAST_AVOID_REACH,movestate );
-}
-
-int trap_BotReachabilityArea(vec3_t origin, int testground) {
- return syscall( BOTLIB_AI_REACHABILITY_AREA, origin, testground );
-}
-
-int trap_BotMovementViewTarget(int movestate, void /* struct bot_goal_s */ *goal, int travelflags, float lookahead, vec3_t target) {
- return syscall( BOTLIB_AI_MOVEMENT_VIEW_TARGET, movestate, goal, travelflags, PASSFLOAT(lookahead), target );
-}
-
-int trap_BotPredictVisiblePosition(vec3_t origin, int areanum, void /* struct bot_goal_s */ *goal, int travelflags, vec3_t target) {
- return syscall( BOTLIB_AI_PREDICT_VISIBLE_POSITION, origin, areanum, goal, travelflags, target );
-}
-
-int trap_BotAllocMoveState(void) {
- return syscall( BOTLIB_AI_ALLOC_MOVE_STATE );
-}
-
-void trap_BotFreeMoveState(int handle) {
- syscall( BOTLIB_AI_FREE_MOVE_STATE, handle );
-}
-
-void trap_BotInitMoveState(int handle, void /* struct bot_initmove_s */ *initmove) {
- syscall( BOTLIB_AI_INIT_MOVE_STATE, handle, initmove );
-}
-
-int trap_BotChooseBestFightWeapon(int weaponstate, int *inventory) {
- return syscall( BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON, weaponstate, inventory );
-}
-
-void trap_BotGetWeaponInfo(int weaponstate, int weapon, void /* struct weaponinfo_s */ *weaponinfo) {
- syscall( BOTLIB_AI_GET_WEAPON_INFO, weaponstate, weapon, weaponinfo );
-}
-
-int trap_BotLoadWeaponWeights(int weaponstate, char *filename) {
- return syscall( BOTLIB_AI_LOAD_WEAPON_WEIGHTS, weaponstate, filename );
-}
-
-int trap_BotAllocWeaponState(void) {
- return syscall( BOTLIB_AI_ALLOC_WEAPON_STATE );
-}
-
-void trap_BotFreeWeaponState(int weaponstate) {
- syscall( BOTLIB_AI_FREE_WEAPON_STATE, weaponstate );
-}
-
-void trap_BotResetWeaponState(int weaponstate) {
- syscall( BOTLIB_AI_RESET_WEAPON_STATE, weaponstate );
-}
-
-int trap_GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child) {
- return syscall( BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION, numranks, ranks, parent1, parent2, child );
-}
-
-int trap_PC_LoadSource( const char *filename ) {
- return syscall( BOTLIB_PC_LOAD_SOURCE, filename );
-}
-
-int trap_PC_FreeSource( int handle ) {
- return syscall( BOTLIB_PC_FREE_SOURCE, handle );
-}
-
-int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) {
- return syscall( BOTLIB_PC_READ_TOKEN, handle, pc_token );
-}
-
-int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) {
- return syscall( BOTLIB_PC_SOURCE_FILE_AND_LINE, handle, filename, line );
-}
diff --git a/game/code/game/g_team.c b/game/code/game/g_team.c
deleted file mode 100644
index 054dccf..0000000
--- a/game/code/game/g_team.c
+++ /dev/null
@@ -1,2162 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Open Arena source code.
-Portions copied from Tremulous under GPL version 2 including any later version.
-
-Open Arena source code 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.
-
-Open Arena source code 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 Open Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-#include "g_local.h"
-
-
-typedef struct teamgame_s {
- float last_flag_capture;
- int last_capture_team;
- flagStatus_t redStatus; // CTF
- flagStatus_t blueStatus; // CTF
- flagStatus_t flagStatus; // One Flag CTF
- int redTakenTime;
- int blueTakenTime;
- int redObeliskAttackedTime;
- int blueObeliskAttackedTime;
-} teamgame_t;
-
-teamgame_t teamgame;
-
-gentity_t *neutralObelisk;
-
-//Some pointers for Double Domination so we don't need GFind (I think it might crash at random times...)
-gentity_t *ddA;
-gentity_t *ddB;
-//Pointers for Standard Domination
-gentity_t *dom_points[MAX_DOMINATION_POINTS];
-
-void Team_SetFlagStatus( int team, flagStatus_t status );
-
-qboolean dominationPointsSpawned;
-
-void Team_InitGame( void ) {
- memset(&teamgame, 0, sizeof teamgame);
-
- switch( g_gametype.integer ) {
- case GT_CTF:
- case GT_CTF_ELIMINATION:
- case GT_DOUBLE_D:
- teamgame.redStatus = -1; // Invalid to force update
- Team_SetFlagStatus( TEAM_RED, FLAG_ATBASE );
- teamgame.blueStatus = -1; // Invalid to force update
- Team_SetFlagStatus( TEAM_BLUE, FLAG_ATBASE );
- ddA = NULL;
- ddB = NULL;
- break;
- case GT_DOMINATION:
- dominationPointsSpawned = qfalse;
- break;
- case GT_1FCTF:
- teamgame.flagStatus = -1; // Invalid to force update
- Team_SetFlagStatus( TEAM_FREE, FLAG_ATBASE );
- break;
- default:
- break;
- }
-}
-
-int OtherTeam(int team) {
- if (team==TEAM_RED)
- return TEAM_BLUE;
- else if (team==TEAM_BLUE)
- return TEAM_RED;
- return team;
-}
-
-const char *TeamName(int team) {
- if (team==TEAM_RED)
- return "RED";
- else if (team==TEAM_BLUE)
- return "BLUE";
- else if (team==TEAM_SPECTATOR)
- return "SPECTATOR";
- return "FREE";
-}
-
-const char *OtherTeamName(int team) {
- if (team==TEAM_RED)
- return "BLUE";
- else if (team==TEAM_BLUE)
- return "RED";
- else if (team==TEAM_SPECTATOR)
- return "SPECTATOR";
- return "FREE";
-}
-
-const char *TeamColorString(int team) {
- if (team==TEAM_RED)
- return S_COLOR_RED;
- else if (team==TEAM_BLUE)
- return S_COLOR_BLUE;
- else if (team==TEAM_SPECTATOR)
- return S_COLOR_YELLOW;
- return S_COLOR_WHITE;
-}
-
-// NULL for everyone
-void QDECL PrintMsg( gentity_t *ent, const char *fmt, ... ) {
- char msg[1024];
- va_list argptr;
- char *p;
-
- va_start (argptr,fmt);
- if (Q_vsnprintf (msg, sizeof(msg), fmt, argptr) > sizeof(msg)) {
- G_Error ( "PrintMsg overrun" );
- }
- va_end (argptr);
-
- // double quotes are bad
- while ((p = strchr(msg, '"')) != NULL)
- *p = '\'';
-
- trap_SendServerCommand ( ( (ent == NULL) ? -1 : ent-g_entities ), va("print \"%s\"", msg ));
-}
-
-/*
-================
-KK-OAX From Tremulous
-G_TeamFromString
-Return the team referenced by a string
-================
-*/
-team_t G_TeamFromString( char *str )
-{
- switch( tolower( *str ) )
- {
- case '0': case 's': return TEAM_NONE;
- case '1': case 'f': return TEAM_FREE;
- case '2': case 'r': return TEAM_RED;
- case '3': case 'b': return TEAM_BLUE;
- default: return TEAM_NUM_TEAMS;
- }
-}
-
-/*
-==============
-AddTeamScore
-
- used for gametype > GT_TEAM
- for gametype GT_TEAM the level.teamScores is updated in AddScore in g_combat.c
-==============
-*/
-void AddTeamScore(vec3_t origin, int team, int score) {
- gentity_t *te;
-
-
- if ( g_gametype.integer != GT_DOMINATION ) {
- te = G_TempEntity(origin, EV_GLOBAL_TEAM_SOUND );
- te->r.svFlags |= SVF_BROADCAST;
-
-
-
- if ( team == TEAM_RED ) {
- if ( level.teamScores[ TEAM_RED ] + score == level.teamScores[ TEAM_BLUE ] ) {
- //teams are tied sound
- te->s.eventParm = GTS_TEAMS_ARE_TIED;
- }
- else if ( level.teamScores[ TEAM_RED ] <= level.teamScores[ TEAM_BLUE ] &&
- level.teamScores[ TEAM_RED ] + score > level.teamScores[ TEAM_BLUE ]) {
- // red took the lead sound
- te->s.eventParm = GTS_REDTEAM_TOOK_LEAD;
- }
- else {
- // red scored sound
- te->s.eventParm = GTS_REDTEAM_SCORED;
- }
- }
- else {
- if ( level.teamScores[ TEAM_BLUE ] + score == level.teamScores[ TEAM_RED ] ) {
- //teams are tied sound
- te->s.eventParm = GTS_TEAMS_ARE_TIED;
- }
- else if ( level.teamScores[ TEAM_BLUE ] <= level.teamScores[ TEAM_RED ] &&
- level.teamScores[ TEAM_BLUE ] + score > level.teamScores[ TEAM_RED ]) {
- // blue took the lead sound
- te->s.eventParm = GTS_BLUETEAM_TOOK_LEAD;
- }
- else {
- // blue scored sound
- te->s.eventParm = GTS_BLUETEAM_SCORED;
- }
- }
- }
- level.teamScores[ team ] += score;
-}
-
-/*
-==============
-OnSameTeam
-==============
-*/
-qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 ) {
- if ( !ent1->client || !ent2->client ) {
- return qfalse;
- }
-
- if ( g_gametype.integer < GT_TEAM || g_ffa_gt==1) {
- return qfalse;
- }
-
- if ( ent1->client->sess.sessionTeam == ent2->client->sess.sessionTeam ) {
- return qtrue;
- }
-
- return qfalse;
-}
-
-
-static char ctfFlagStatusRemap[] = { '0', '1', '*', '*', '2' };
-static char oneFlagStatusRemap[] = { '0', '1', '2', '3', '4' };
-
-void Team_SetFlagStatus( int team, flagStatus_t status ) {
- qboolean modified = qfalse;
-
- switch( team ) {
- case TEAM_RED: // CTF
- if( teamgame.redStatus != status ) {
- teamgame.redStatus = status;
- modified = qtrue;
- }
- break;
-
- case TEAM_BLUE: // CTF
- if( teamgame.blueStatus != status ) {
- teamgame.blueStatus = status;
- modified = qtrue;
- }
- break;
-
- case TEAM_FREE: // One Flag CTF
- if( teamgame.flagStatus != status ) {
- teamgame.flagStatus = status;
- modified = qtrue;
- }
- break;
- }
-
-
- if( modified ) {
- char st[4];
-
- if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTF_ELIMINATION) {
- st[0] = ctfFlagStatusRemap[teamgame.redStatus];
- st[1] = ctfFlagStatusRemap[teamgame.blueStatus];
- st[2] = 0;
- }
- else if (g_gametype.integer == GT_DOUBLE_D) {
- st[0] = oneFlagStatusRemap[teamgame.redStatus];
- st[1] = oneFlagStatusRemap[teamgame.blueStatus];
- st[2] = 0;
- }
- else { // GT_1FCTF
- st[0] = oneFlagStatusRemap[teamgame.flagStatus];
- st[1] = 0;
- }
-
- trap_SetConfigstring( CS_FLAGSTATUS, st );
- }
-}
-
-void Team_CheckDroppedItem( gentity_t *dropped ) {
- if( dropped->item->giTag == PW_REDFLAG ) {
- Team_SetFlagStatus( TEAM_RED, FLAG_DROPPED );
- }
- else if( dropped->item->giTag == PW_BLUEFLAG ) {
- Team_SetFlagStatus( TEAM_BLUE, FLAG_DROPPED );
- }
- else if( dropped->item->giTag == PW_NEUTRALFLAG ) {
- Team_SetFlagStatus( TEAM_FREE, FLAG_DROPPED );
- }
-}
-
-/*
-================
-Team_ForceGesture
-================
-*/
-void Team_ForceGesture(int team) {
- int i;
- gentity_t *ent;
-
- for (i = 0; i < MAX_CLIENTS; i++) {
- ent = &g_entities[i];
- if (!ent->inuse)
- continue;
- if (!ent->client)
- continue;
- if (ent->client->sess.sessionTeam != team)
- continue;
- ent->flags |= FL_FORCE_GESTURE;
- }
-}
-
-/*
-================
-Team_DD_bonusAtPoints
-Adds bonus point to a player if he is close to the point and on the team that scores
-================
-*/
-
-void Team_DD_bonusAtPoints(int team) {
- vec3_t v1, v2;
- int i;
- gentity_t *player;
-
- for (i = 0; i < MAX_CLIENTS; i++) {
- player = &g_entities[i];
- if (!player->inuse)
- continue;
- if (!player->client)
- continue;
-
- if( player->client->sess.sessionTeam != team )
- return; //player was not on scoring team
-
- //See if the player is close to any of the points:
- VectorSubtract(player->r.currentOrigin, ddA->r.currentOrigin, v1);
- VectorSubtract(player->r.currentOrigin, ddB->r.currentOrigin, v2);
- if (!( ( ( VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS &&
- trap_InPVS(ddA->r.currentOrigin, player->r.currentOrigin ) ) ||
- ( VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS &&
- trap_InPVS(ddB->r.currentOrigin, player->r.currentOrigin ) ) )))
- return; //Wasn't close to any of the points
-
- AddScore(player, player->r.currentOrigin, DD_AT_POINT_AT_CAPTURE);
- }
-}
-
-/*
-================
-Team_FragBonuses
-
-Calculate the bonuses for flag defense, flag carrier defense, etc.
-Note that bonuses are not cumulative. You get one, they are in importance
-order.
-================
-*/
-void Team_FragBonuses(gentity_t *targ, gentity_t *inflictor, gentity_t *attacker)
-{
- int i;
- gentity_t *ent;
- int flag_pw, enemy_flag_pw;
- int otherteam;
- int tokens;
- gentity_t *flag, *carrier = NULL;
- char *c;
- vec3_t v1, v2;
- int team;
-
- // no bonus for fragging yourself or team mates
- if (!targ->client || !attacker->client || targ == attacker || OnSameTeam(targ, attacker))
- return;
-
- team = targ->client->sess.sessionTeam;
- otherteam = OtherTeam(targ->client->sess.sessionTeam);
- if (otherteam < 0)
- return; // whoever died isn't on a team
-
- // same team, if the flag at base, check to he has the enemy flag
- if (team == TEAM_RED) {
- flag_pw = PW_REDFLAG;
- enemy_flag_pw = PW_BLUEFLAG;
- } else {
- flag_pw = PW_BLUEFLAG;
- enemy_flag_pw = PW_REDFLAG;
- }
-
- if (g_gametype.integer == GT_1FCTF) {
- enemy_flag_pw = PW_NEUTRALFLAG;
- }
-
- // did the attacker frag the flag carrier?
- tokens = 0;
- if( g_gametype.integer == GT_HARVESTER ) {
- tokens = targ->client->ps.generic1;
- }
- if (targ->client->ps.powerups[enemy_flag_pw]) {
- attacker->client->pers.teamState.lastfraggedcarrier = level.time;
- AddScore(attacker, targ->r.currentOrigin, CTF_FRAG_CARRIER_BONUS);
- attacker->client->pers.teamState.fragcarrier++;
- PrintMsg(NULL, "%s" S_COLOR_WHITE " fragged %s's flag carrier!\n",
- attacker->client->pers.netname, TeamName(team));
- if(g_gametype.integer == GT_CTF) {
- G_LogPrintf( "CTF: %i %i %i: %s fragged %s's flag carrier!\n", attacker->client->ps.clientNum, team, 3, attacker->client->pers.netname, TeamName(team) );
- } else if(g_gametype.integer == GT_CTF_ELIMINATION) {
- G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s fragged %s's flag carrier!\n", level.roundNumber, attacker->client->ps.clientNum, team, 3, attacker->client->pers.netname, TeamName(team) );
- } else if(g_gametype.integer == GT_1FCTF) {
- G_LogPrintf( "1fCTF: %i %i %i: %s fragged %s's flag carrier!\n", attacker->client->ps.clientNum, team, 3, attacker->client->pers.netname, TeamName(team) );
- }
-
-
- // the target had the flag, clear the hurt carrier
- // field on the other team
- for (i = 0; i < g_maxclients.integer; i++) {
- ent = g_entities + i;
- if (ent->inuse && ent->client->sess.sessionTeam == otherteam)
- ent->client->pers.teamState.lasthurtcarrier = 0;
- }
- return;
- }
-
- // did the attacker frag a head carrier? other->client->ps.generic1
- if (tokens) {
- attacker->client->pers.teamState.lastfraggedcarrier = level.time;
- AddScore(attacker, targ->r.currentOrigin, CTF_FRAG_CARRIER_BONUS * tokens * tokens);
- attacker->client->pers.teamState.fragcarrier++;
- PrintMsg(NULL, "%s" S_COLOR_WHITE " fragged %s's skull carrier!\n",
- attacker->client->pers.netname, TeamName(team));
-
- // the target had the flag, clear the hurt carrier
- // field on the other team
- for (i = 0; i < g_maxclients.integer; i++) {
- ent = g_entities + i;
- if (ent->inuse && ent->client->sess.sessionTeam == otherteam)
- ent->client->pers.teamState.lasthurtcarrier = 0;
- }
- return;
- }
-
- if (targ->client->pers.teamState.lasthurtcarrier &&
- level.time - targ->client->pers.teamState.lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT &&
- !attacker->client->ps.powerups[flag_pw]) {
- // attacker is on the same team as the flag carrier and
- // fragged a guy who hurt our flag carrier
- AddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_DANGER_PROTECT_BONUS);
-
- attacker->client->pers.teamState.carrierdefense++;
- targ->client->pers.teamState.lasthurtcarrier = 0;
-
- attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 3, attacker->client->pers.netname, "DEFENCE" );
- if(!level.hadBots)
- ChallengeMessage(attacker,AWARD_DEFENCE);
- team = attacker->client->sess.sessionTeam;
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- return;
- }
-
- if (targ->client->pers.teamState.lasthurtcarrier &&
- level.time - targ->client->pers.teamState.lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT) {
- // attacker is on the same team as the skull carrier and
- AddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_DANGER_PROTECT_BONUS);
-
- attacker->client->pers.teamState.carrierdefense++;
- targ->client->pers.teamState.lasthurtcarrier = 0;
-
- attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
- if(!level.hadBots)
- ChallengeMessage(attacker,AWARD_DEFENCE);
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 3, attacker->client->pers.netname, "DEFENCE" );
- team = attacker->client->sess.sessionTeam;
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- return;
- }
-
-//We place the Double Domination bonus test here! This appears to be the best place to place them.
- if ( g_gametype.integer == GT_DOUBLE_D ) {
- if(attacker->client->sess.sessionTeam == level.pointStatusA ) { //Attack must defend point A
- //See how close attacker and target was to Point A:
- VectorSubtract(targ->r.currentOrigin, ddA->r.currentOrigin, v1);
- VectorSubtract(attacker->r.currentOrigin, ddA->r.currentOrigin, v2);
-
- if ( ( ( VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS &&
- trap_InPVS(ddA->r.currentOrigin, targ->r.currentOrigin ) ) ||
- ( VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS &&
- trap_InPVS(ddA->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&
- attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam) {
-
- //We defended point A
- //Was we dominating and maybe close to score?
- if(attacker->client->sess.sessionTeam == level.pointStatusB && level.time - level.timeTaken > (10-DD_CLOSE)*1000)
- AddScore(attacker, targ->r.currentOrigin, DD_POINT_DEFENCE_CLOSE_BONUS);
- else
- AddScore(attacker, targ->r.currentOrigin, DD_POINT_DEFENCE_BONUS);
- attacker->client->pers.teamState.basedefense++;
-
- attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 3, attacker->client->pers.netname, "DEFENCE" );
- if(!level.hadBots)
- ChallengeMessage(attacker,AWARD_DEFENCE);
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- return; //Return so we don't recieve credits for point B also
-
- } //We denfended point A
-
-
-
- } //Defend point A
-
- if(attacker->client->sess.sessionTeam == level.pointStatusB ) { //Attack must defend point B
- //See how close attacker and target was to Point B:
- VectorSubtract(targ->r.currentOrigin, ddB->r.currentOrigin, v1);
- VectorSubtract(attacker->r.currentOrigin, ddB->r.currentOrigin, v2);
-
- if ( ( ( VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS &&
- trap_InPVS(ddB->r.currentOrigin, targ->r.currentOrigin ) ) ||
- ( VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS &&
- trap_InPVS(ddB->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&
- attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam) {
-
- //We defended point B
- //Was we dominating and maybe close to score?
- if(attacker->client->sess.sessionTeam == level.pointStatusA && level.time - level.timeTaken > (10-DD_CLOSE)*1000)
- AddScore(attacker, targ->r.currentOrigin, DD_POINT_DEFENCE_CLOSE_BONUS);
- else
- AddScore(attacker, targ->r.currentOrigin, DD_POINT_DEFENCE_BONUS);
- attacker->client->pers.teamState.basedefense++;
-
- attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
- if(!level.hadBots)
- ChallengeMessage(attacker,AWARD_DEFENCE);
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 3, attacker->client->pers.netname, "DEFENCE" );
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- return;
-
- } //We denfended point B
-
-
-
- } //Defend point B
- return; //In double Domination we shall not go on, or we would test for team bases that we don't use
- }
-
- // flag and flag carrier area defense bonuses
-
- // we have to find the flag and carrier entities
-
- if( g_gametype.integer == GT_OBELISK ) {
- // find the team obelisk
- switch (attacker->client->sess.sessionTeam) {
- case TEAM_RED:
- c = "team_redobelisk";
- break;
- case TEAM_BLUE:
- c = "team_blueobelisk";
- break;
- default:
- return;
- }
-
- } else if (g_gametype.integer == GT_HARVESTER ) {
- // find the center obelisk
- c = "team_neutralobelisk";
- } else {
- // find the flag
- switch (attacker->client->sess.sessionTeam) {
- case TEAM_RED:
- c = "team_CTF_redflag";
- break;
- case TEAM_BLUE:
- c = "team_CTF_blueflag";
- break;
- default:
- return;
- }
- // find attacker's team's flag carrier
- for (i = 0; i < g_maxclients.integer; i++) {
- carrier = g_entities + i;
- if (carrier->inuse && carrier->client->ps.powerups[flag_pw])
- break;
- carrier = NULL;
- }
- }
- flag = NULL;
- while ((flag = G_Find (flag, FOFS(classname), c)) != NULL) {
- if (!(flag->flags & FL_DROPPED_ITEM))
- break;
- }
-
- if (!flag)
- return; // can't find attacker's flag
-
- // ok we have the attackers flag and a pointer to the carrier
-
- // check to see if we are defending the base's flag
- VectorSubtract(targ->r.currentOrigin, flag->r.currentOrigin, v1);
- VectorSubtract(attacker->r.currentOrigin, flag->r.currentOrigin, v2);
-
- if ( ( ( VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS &&
- trap_InPVS(flag->r.currentOrigin, targ->r.currentOrigin ) ) ||
- ( VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS &&
- trap_InPVS(flag->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&
- attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam && g_gametype.integer != GT_ELIMINATION &&
- (g_gametype.integer != GT_CTF_ELIMINATION || !g_elimination_ctf_oneway.integer ||
- ((level.eliminationSides+level.roundNumber)%2 == 0 && attacker->client->sess.sessionTeam == TEAM_BLUE ) ||
- ((level.eliminationSides+level.roundNumber)%2 == 1 && attacker->client->sess.sessionTeam == TEAM_RED ) ) ) {
-
- // we defended the base flag
- AddScore(attacker, targ->r.currentOrigin, CTF_FLAG_DEFENSE_BONUS);
- attacker->client->pers.teamState.basedefense++;
-
- attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
- if(!level.hadBots)
- ChallengeMessage(attacker,AWARD_DEFENCE);
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 3, attacker->client->pers.netname, "DEFENCE" );
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- return;
- }
-
- if (carrier && carrier != attacker) {
- VectorSubtract(targ->r.currentOrigin, carrier->r.currentOrigin, v1);
- VectorSubtract(attacker->r.currentOrigin, carrier->r.currentOrigin, v1);
-
- if ( ( ( VectorLength(v1) < CTF_ATTACKER_PROTECT_RADIUS &&
- trap_InPVS(carrier->r.currentOrigin, targ->r.currentOrigin ) ) ||
- ( VectorLength(v2) < CTF_ATTACKER_PROTECT_RADIUS &&
- trap_InPVS(carrier->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&
- attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam) {
- AddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_PROTECT_BONUS);
- attacker->client->pers.teamState.carrierdefense++;
-
- attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
- if(!level.hadBots)
- ChallengeMessage(attacker,AWARD_DEFENCE);
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 3, attacker->client->pers.netname, "DEFENCE" );
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- return;
- }
- }
-}
-
-/*
-================
-Team_CheckHurtCarrier
-
-Check to see if attacker hurt the flag carrier. Needed when handing out bonuses for assistance to flag
-carrier defense.
-================
-*/
-void Team_CheckHurtCarrier(gentity_t *targ, gentity_t *attacker)
-{
- int flag_pw;
-
- if (!targ->client || !attacker->client)
- return;
-
- if (targ->client->sess.sessionTeam == TEAM_RED)
- flag_pw = PW_BLUEFLAG;
- else
- flag_pw = PW_REDFLAG;
-
- // flags
- if (targ->client->ps.powerups[flag_pw] &&
- targ->client->sess.sessionTeam != attacker->client->sess.sessionTeam)
- attacker->client->pers.teamState.lasthurtcarrier = level.time;
-
- // skulls
- if (targ->client->ps.generic1 &&
- targ->client->sess.sessionTeam != attacker->client->sess.sessionTeam)
- attacker->client->pers.teamState.lasthurtcarrier = level.time;
-}
-
-
-gentity_t *Team_ResetFlag( int team ) {
- char *c;
- gentity_t *ent, *rent = NULL;
-
- switch (team) {
- case TEAM_RED:
- c = "team_CTF_redflag";
- break;
- case TEAM_BLUE:
- c = "team_CTF_blueflag";
- break;
- case TEAM_FREE:
- c = "team_CTF_neutralflag";
- break;
- default:
- return NULL;
- }
-
- ent = NULL;
- while ((ent = G_Find (ent, FOFS(classname), c)) != NULL) {
- if (ent->flags & FL_DROPPED_ITEM)
- G_FreeEntity(ent);
- else {
- rent = ent;
- RespawnItem(ent);
- }
- }
-
- Team_SetFlagStatus( team, FLAG_ATBASE );
-
- return rent;
-}
-
-//Functions for Domination
-
-void Team_Dom_SpawnPoints( void ) {
- char *c;
- gentity_t *flag;
- int i;
- gitem_t *it;
-
- flag = NULL;
-
- if(dominationPointsSpawned)
- return;
- dominationPointsSpawned = qtrue;
-
- it = NULL;
- it = BG_FindItem ("Neutral domination point");
- if(it == NULL) {
- PrintMsg( NULL, "No domination item\n");
- return;
- } else {
- PrintMsg( NULL, "Domination item found\n");
- }
- i = 0;
- c = "domination_point";
-
- //return; Just to test, the lines below crashes game
-
- while ((flag = G_Find (flag, FOFS(classname), c)) != NULL) {
- if(i>=MAX_DOMINATION_POINTS)
- break;
- //domination_points_names[i] = flag->message;
- if(flag->message) {
- Q_strncpyz(level.domination_points_names[i],flag->message,MAX_DOMINATION_POINTS_NAMES-1);
- PrintMsg( NULL, "Domination point \'%s\' found\n",level.domination_points_names[i]);
- } else {
- Q_strncpyz(level.domination_points_names[i],va("Point %i",i),MAX_DOMINATION_POINTS_NAMES-1);
- PrintMsg( NULL, "Domination point \'%s\' found (autonamed)\n",level.domination_points_names[i]);
- }
- dom_points[i] = G_Spawn();
- VectorCopy( flag->r.currentOrigin, dom_points[i]->s.origin );
- dom_points[i]->classname = it->classname;
- G_SpawnItem(dom_points[i], it);
- FinishSpawningItem(dom_points[i] );
-
- i++;
- }
- level.domination_points_count = i;
-}
-
-int getDomPointNumber( gentity_t *point ) {
- int i;
- for(i=1;i<MAX_DOMINATION_POINTS && i<level.domination_points_count;i++) {
- if(dom_points[i] == NULL)
- return 0; //Not found, just return first, so we don't crash
- if(dom_points[i] == point)
- return i;
- }
- return 0;
-}
-
-void Team_Dom_TakePoint( gentity_t *point, int team ) {
- gitem_t *it;
- vec3_t origin;
- int i;
- i = getDomPointNumber(point);
- if(i<0)
- i = 0;
- if(i>=MAX_DOMINATION_POINTS)
- i = MAX_DOMINATION_POINTS - 1;
-
- it = NULL;
- VectorCopy( point->r.currentOrigin, origin );
-
- if(team == TEAM_RED) {
- it = BG_FindItem ("Red domination point");
- PrintMsg( NULL, "Red took \'%s\'\n",level.domination_points_names[i]);
- } else
- if(team == TEAM_BLUE) {
- it = BG_FindItem ("Blue domination point");
- PrintMsg( NULL, "Blue took \'%s\'\n",level.domination_points_names[i]);
- }
- if (!it || it == NULL) {
- PrintMsg( NULL, "No item\n");
- return;
- }
-
- G_FreeEntity(point);
-
- point = G_Spawn();
-
- VectorCopy( origin, point->s.origin );
- point->classname = it->classname;
- dom_points[i] = point;
- G_SpawnItem(point, it);
- FinishSpawningItem( point );
- level.pointStatusDom[i] = team;
- SendDominationPointsStatusMessageToAllClients();
-}
-
-//Functions for Double Domination
-
-void Team_DD_RemovePointAgfx( void ) {
- if(ddA!=NULL) {
- G_FreeEntity(ddA);
- ddA = NULL;
- }
-}
-
-void Team_DD_RemovePointBgfx( void ) {
- if(ddB!=NULL) {
- G_FreeEntity(ddB);
- ddB = NULL;
- }
-}
-
-void Team_DD_makeA2team( gentity_t *target, int team ) {
- gitem_t *it;
- //gentity_t *it_ent;
- Team_DD_RemovePointAgfx();
- it = NULL;
- if(team == TEAM_NONE)
- return;
- if(team == TEAM_RED)
- it = BG_FindItem ("Point A (Red)");
- if(team == TEAM_BLUE)
- it = BG_FindItem ("Point A (Blue)");
- if(team == TEAM_FREE)
- it = BG_FindItem ("Point A (White)");
- if (!it || it == NULL) {
- PrintMsg( NULL, "No item\n");
- return;
- }
- ddA = G_Spawn();
-
- VectorCopy( target->r.currentOrigin, ddA->s.origin );
- ddA->classname = it->classname;
- G_SpawnItem(ddA, it);
- FinishSpawningItem(ddA );
-}
-
-void Team_DD_makeB2team( gentity_t *target, int team ) {
- gitem_t *it;
- //gentity_t *it_ent;
-
- Team_DD_RemovePointBgfx();
- it = NULL;
- if(team == TEAM_NONE)
- return;
- if(team == TEAM_RED)
- it = BG_FindItem ("Point B (Red)");
- if(team == TEAM_BLUE)
- it = BG_FindItem ("Point B (Blue)");
- if(team == TEAM_FREE)
- it = BG_FindItem ("Point B (White)");
- if (!it || it == NULL) {
- PrintMsg( NULL, "No item\n");
- return;
- }
- ddB = G_Spawn();
-
- VectorCopy( target->r.currentOrigin, ddB->s.origin );
- ddB->classname = it->classname;
- G_SpawnItem(ddB, it);
- FinishSpawningItem(ddB );
-}
-
-void Team_ResetFlags( void ) {
- if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTF_ELIMINATION) {
- Team_ResetFlag( TEAM_RED );
- Team_ResetFlag( TEAM_BLUE );
- }
- else if( g_gametype.integer == GT_1FCTF ) {
- Team_ResetFlag( TEAM_FREE );
- }
-}
-
-void Team_ReturnFlagSound( gentity_t *ent, int team ) {
- gentity_t *te;
-
- if (ent == NULL) {
- G_Printf ("Warning: NULL passed to Team_ReturnFlagSound\n");
- return;
- }
-
- //See if we are during CTF_ELIMINATION warmup
- if((level.time<=level.roundStartTime && level.time>level.roundStartTime-1000*g_elimination_activewarmup.integer)&&g_gametype.integer == GT_CTF_ELIMINATION)
- return;
-
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
- if( team == TEAM_BLUE ) {
- te->s.eventParm = GTS_RED_RETURN;
- }
- else {
- te->s.eventParm = GTS_BLUE_RETURN;
- }
- te->r.svFlags |= SVF_BROADCAST;
-}
-
-void Team_TakeFlagSound( gentity_t *ent, int team ) {
- gentity_t *te;
-
- if (ent == NULL) {
- G_Printf ("Warning: NULL passed to Team_TakeFlagSound\n");
- return;
- }
-
- // only play sound when the flag was at the base
- // or not picked up the last 10 seconds
- switch(team) {
- case TEAM_RED:
- if( teamgame.blueStatus != FLAG_ATBASE ) {
- if (teamgame.blueTakenTime > level.time - 10000 && g_gametype.integer != GT_CTF_ELIMINATION)
- return;
- }
- teamgame.blueTakenTime = level.time;
- break;
-
- case TEAM_BLUE: // CTF
- if( teamgame.redStatus != FLAG_ATBASE ) {
- if (teamgame.redTakenTime > level.time - 10000 && g_gametype.integer != GT_CTF_ELIMINATION)
- return;
- }
- teamgame.redTakenTime = level.time;
- break;
- }
-
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
- if( team == TEAM_BLUE ) {
- te->s.eventParm = GTS_RED_TAKEN;
- }
- else {
- te->s.eventParm = GTS_BLUE_TAKEN;
- }
- te->r.svFlags |= SVF_BROADCAST;
-}
-
-void Team_CaptureFlagSound( gentity_t *ent, int team ) {
- gentity_t *te;
-
- if (ent == NULL) {
- G_Printf ("Warning: NULL passed to Team_CaptureFlagSound\n");
- return;
- }
-
- te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
- if( team == TEAM_BLUE ) {
- te->s.eventParm = GTS_BLUE_CAPTURE;
- }
- else {
- te->s.eventParm = GTS_RED_CAPTURE;
- }
- te->r.svFlags |= SVF_BROADCAST;
-}
-
-void Team_ReturnFlag( int team ) {
- Team_ReturnFlagSound(Team_ResetFlag(team), team);
- if( team == TEAM_FREE ) {
- PrintMsg(NULL, "The flag has returned!\n" );
- if(g_gametype.integer == GT_1FCTF) {
- G_LogPrintf( "1FCTF: %i %i %i: The flag was returned!\n", -1, -1, 2 );
- }
- }
- else {
- PrintMsg(NULL, "The %s flag has returned!\n", TeamName(team));
- if(g_gametype.integer == GT_CTF_ELIMINATION) {
- G_LogPrintf( "CTF: %i %i %i: The %s flag was returned!\n", -1, team, 2, TeamName(team) );
- } else
- if(g_gametype.integer == GT_CTF_ELIMINATION) {
- G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: The %s flag was returned!\n", level.roundNumber, -1, team, 2, TeamName(team) );
- }
- }
-}
-
-void Team_FreeEntity( gentity_t *ent ) {
- if( ent->item->giTag == PW_REDFLAG ) {
- Team_ReturnFlag( TEAM_RED );
- }
- else if( ent->item->giTag == PW_BLUEFLAG ) {
- Team_ReturnFlag( TEAM_BLUE );
- }
- else if( ent->item->giTag == PW_NEUTRALFLAG ) {
- Team_ReturnFlag( TEAM_FREE );
- }
-}
-
-/*
-==============
-Team_DroppedFlagThink
-
-Automatically set in Launch_Item if the item is one of the flags
-
-Flags are unique in that if they are dropped, the base flag must be respawned when they time out
-==============
-*/
-void Team_DroppedFlagThink(gentity_t *ent) {
- int team = TEAM_FREE;
-
- if( ent->item->giTag == PW_REDFLAG ) {
- team = TEAM_RED;
- }
- else if( ent->item->giTag == PW_BLUEFLAG ) {
- team = TEAM_BLUE;
- }
- else if( ent->item->giTag == PW_NEUTRALFLAG ) {
- team = TEAM_FREE;
- }
-
- Team_ReturnFlagSound( Team_ResetFlag( team ), team );
- // Reset Flag will delete this entity
-}
-
-/*
-Update DD points
-*/
-
-void updateDDpoints(void) {
- //teamgame.redStatus = -1; // Invalid to force update
- Team_SetFlagStatus( TEAM_RED, level.pointStatusA );
- //teamgame.blueStatus = -1; // Invalid to force update
- Team_SetFlagStatus( TEAM_BLUE, level.pointStatusB );
-}
-
-/*
-==============
-Team_SpawnDoubleDominationPoints
-==============
-*/
-
-int Team_SpawnDoubleDominationPoints ( void ) {
- gentity_t *ent;
- level.pointStatusA = TEAM_FREE;
- level.pointStatusB = TEAM_FREE;
- updateDDpoints();
- ent = NULL;
- if ((ent = G_Find (ent, FOFS(classname), "team_CTF_redflag")) != NULL) {
- Team_DD_makeA2team( ent, TEAM_FREE );
- }
- ent = NULL;
- if ((ent = G_Find (ent, FOFS(classname), "team_CTF_blueflag")) != NULL) {
- Team_DD_makeB2team( ent, TEAM_FREE );
- }
- return 1;
-}
-
-/*
-==============
-Team_RemoveDoubleDominationPoints
-==============
-*/
-
-int Team_RemoveDoubleDominationPoints ( void ) {
- level.pointStatusA = TEAM_NONE;
- level.pointStatusB = TEAM_NONE;
- updateDDpoints();
- Team_DD_makeA2team( NULL, TEAM_NONE );
- Team_DD_makeB2team( NULL, TEAM_NONE );
- return 1;
-}
-
-/*
-==============
-Team_TouchDoubleDominationPoint
-==============
-*/
-
-//team is the either TEAM_RED(A) or TEAM_BLUE(B)
-int Team_TouchDoubleDominationPoint( gentity_t *ent, gentity_t *other, int team ) {
- gclient_t *cl = other->client;
- qboolean otherDominating, isClose;
- int clientTeam = cl->sess.sessionTeam;
- int otherTeam;
- int score; //Used to add the scores together
-
- if(clientTeam == TEAM_RED)
- otherTeam = TEAM_BLUE;
- else
- otherTeam = TEAM_RED;
-
- otherDominating = qfalse;
- isClose = qfalse;
-
- if(level.pointStatusA == otherTeam && level.pointStatusB == otherTeam) {
- otherDominating = qtrue;
- if(level.time - level.timeTaken > (10-DD_CLOSE)*1000)
- isClose = qtrue;
- }
-
-
- if(team == TEAM_RED) //We have touched point A
- {
- if(TEAM_NONE == level.pointStatusA)
- return 0; //Haven't spawned yet
- if(clientTeam == level.pointStatusA)
- return 0; //If we already have the flag
- //if we didn't have the point, then we have now!
- level.pointStatusA = clientTeam;
- PrintMsg( NULL, "%s" S_COLOR_WHITE " (%s) took control of A!\n", cl->pers.netname, TeamName(clientTeam) );
- Team_DD_makeA2team( ent, clientTeam );
- G_LogPrintf( "DD: %i %i %i: %s took point A for %s!\n", cl->ps.clientNum, clientTeam, 0, cl->pers.netname, TeamName(clientTeam) );
- //Give personal score
- score = DD_POINT_CAPTURE; //Base score for capture
- if(otherDominating){
- score += DD_POINT_CAPTURE_BREAK;
- if(isClose)
- score += DD_POINT_CAPTURE_CLOSE;
- }
- AddScore(other, ent->r.currentOrigin, score);
- //Do we also have point B?
- if(clientTeam == level.pointStatusB)
- {
- //We are dominating!
- level.timeTaken = level.time; //At this time
- PrintMsg( NULL, "%s" S_COLOR_WHITE " is dominating!\n", TeamName(clientTeam) );
- SendDDtimetakenMessageToAllClients();
- }
- }
-
- if(team == TEAM_BLUE) //We have touched point B
- {
- if(TEAM_NONE == level.pointStatusB)
- return 0; //Haven't spawned yet
- if(clientTeam == level.pointStatusB)
- return 0; //If we already have the flag
- //if we didn't have the point, then we have now!
- level.pointStatusB = clientTeam;
- PrintMsg( NULL, "%s" S_COLOR_WHITE " (%s) took control of B!\n", cl->pers.netname, TeamName(clientTeam) );
- Team_DD_makeB2team( ent, clientTeam );
- G_LogPrintf( "DD: %i %i %i: %s took point B for %s!\n", cl->ps.clientNum, clientTeam, 1, cl->pers.netname, TeamName(clientTeam) );
- //Give personal score
- score = DD_POINT_CAPTURE; //Base score for capture
- if(otherDominating){
- score += DD_POINT_CAPTURE_BREAK;
- if(isClose)
- score += DD_POINT_CAPTURE_CLOSE;
- }
- AddScore(other, ent->r.currentOrigin, score);
- //Do we also have point A?
- if(clientTeam == level.pointStatusA)
- {
- //We are dominating!
- level.timeTaken = level.time; //At this time
- PrintMsg( NULL, "%s" S_COLOR_WHITE " is dominating!\n", TeamName(clientTeam) );
- SendDDtimetakenMessageToAllClients();
- }
- }
-
- updateDDpoints();
-
- return 0;
-}
-
-/*
-==============
-Team_TouchOurFlag
-==============
-*/
-int Team_TouchOurFlag( gentity_t *ent, gentity_t *other, int team ) {
- int i;
- gentity_t *player;
- gclient_t *cl = other->client;
- int enemy_flag;
-
- if( g_gametype.integer == GT_1FCTF ) {
- enemy_flag = PW_NEUTRALFLAG;
- }
- else {
- if (cl->sess.sessionTeam == TEAM_RED) {
- enemy_flag = PW_BLUEFLAG;
- } else {
- enemy_flag = PW_REDFLAG;
- }
-
- if ( ent->flags & FL_DROPPED_ITEM ) {
- // hey, its not home. return it by teleporting it back
- PrintMsg( NULL, "%s" S_COLOR_WHITE " returned the %s flag!\n",
- cl->pers.netname, TeamName(team));
- AddScore(other, ent->r.currentOrigin, CTF_RECOVERY_BONUS);
- if(g_gametype.integer == GT_CTF) {
- G_LogPrintf( "CTF: %i %i %i: %s returned the %s flag!\n", cl->ps.clientNum, team, 2, cl->pers.netname, TeamName(team) );
- } else if(g_gametype.integer == GT_CTF_ELIMINATION) {
- G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s returned the %s flag!\n", level.roundNumber, cl->ps.clientNum, team, 2, cl->pers.netname, TeamName(team) );
- }
- other->client->pers.teamState.flagrecovery++;
- other->client->pers.teamState.lastreturnedflag = level.time;
- //ResetFlag will remove this entity! We must return zero
- Team_ReturnFlagSound(Team_ResetFlag(team), team);
- return 0;
- }
- }
-
- // the flag is at home base. if the player has the enemy
- // flag, he's just won!
- if (!cl->ps.powerups[enemy_flag])
- return 0; // We don't have the flag
- if( g_gametype.integer == GT_1FCTF ) {
- PrintMsg( NULL, "%s" S_COLOR_WHITE " captured the flag!\n", cl->pers.netname );
- G_LogPrintf( "1FCTF: %i %i %i: %s captured the flag!\n", cl->ps.clientNum, -1, 1, cl->pers.netname );
- }
- else {
- PrintMsg( NULL, "%s" S_COLOR_WHITE " captured the %s flag!\n", cl->pers.netname, TeamName(OtherTeam(team)));
- if(g_gametype.integer == GT_CTF)
- G_LogPrintf( "CTF: %i %i %i: %s captured the %s flag!\n", cl->ps.clientNum, OtherTeam(team), 1, cl->pers.netname, TeamName(OtherTeam(team)) );
- if(g_gametype.integer == GT_CTF_ELIMINATION)
- G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s captured the %s flag!\n", level.roundNumber, cl->ps.clientNum, OtherTeam(team), 1, cl->pers.netname, TeamName(OtherTeam(team)) );
- }
-
- cl->ps.powerups[enemy_flag] = 0;
-
- teamgame.last_flag_capture = level.time;
- teamgame.last_capture_team = team;
-
- // Increase the team's score
- AddTeamScore(ent->s.pos.trBase, other->client->sess.sessionTeam, 1);
- Team_ForceGesture(other->client->sess.sessionTeam);
- //If CTF Elimination, stop the round:
- if(g_gametype.integer==GT_CTF_ELIMINATION) {
- EndEliminationRound();
- }
-
- other->client->pers.teamState.captures++;
- // add the sprite over the player's head
- other->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- other->client->ps.eFlags |= EF_AWARD_CAP;
- other->client->rewardTime = level.time + REWARD_SPRITE_TIME;
- other->client->ps.persistant[PERS_CAPTURES]++;
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", other->client->ps.clientNum, 4, other->client->pers.netname, "CAPTURE" );
- if(TeamCount(-1,TEAM_RED) && TeamCount(-1,TEAM_BLUE) && !level.hadBots)
- ChallengeMessage(other,AWARD_CAPTURE);
- // other gets another 10 frag bonus
- AddScore(other, ent->r.currentOrigin, CTF_CAPTURE_BONUS);
-
- Team_CaptureFlagSound( ent, team );
-
- // Ok, let's do the player loop, hand out the bonuses
- for (i = 0; i < g_maxclients.integer; i++) {
- player = &g_entities[i];
- if (!player->inuse || player == other)
- continue;
-
- if (player->client->sess.sessionTeam !=
- cl->sess.sessionTeam) {
- player->client->pers.teamState.lasthurtcarrier = -5;
- } else if (player->client->sess.sessionTeam ==
- cl->sess.sessionTeam) {
- if (player != other)
- AddScore(player, ent->r.currentOrigin, CTF_TEAM_BONUS);
- // award extra points for capture assists
- if (player->client->pers.teamState.lastreturnedflag +
- CTF_RETURN_FLAG_ASSIST_TIMEOUT > level.time) {
- AddScore (player, ent->r.currentOrigin, CTF_RETURN_FLAG_ASSIST_BONUS);
- other->client->pers.teamState.assists++;
-
- player->client->ps.persistant[PERS_ASSIST_COUNT]++;
- if(!level.hadBots)
- ChallengeMessage(player,AWARD_ASSIST);
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", player->client->ps.clientNum, 5, player->client->pers.netname, "ASSIST" );
- // add the sprite over the player's head
- player->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- player->client->ps.eFlags |= EF_AWARD_ASSIST;
- player->client->rewardTime = level.time + REWARD_SPRITE_TIME;
-
- } else if (player->client->pers.teamState.lastfraggedcarrier +
- CTF_FRAG_CARRIER_ASSIST_TIMEOUT > level.time) {
- AddScore(player, ent->r.currentOrigin, CTF_FRAG_CARRIER_ASSIST_BONUS);
- other->client->pers.teamState.assists++;
- player->client->ps.persistant[PERS_ASSIST_COUNT]++;
- if(!level.hadBots)
- ChallengeMessage(player,AWARD_ASSIST);
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", player->client->ps.clientNum, 5, player->client->pers.netname, "ASSIST" );
- // add the sprite over the player's head
- player->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- player->client->ps.eFlags |= EF_AWARD_ASSIST;
- player->client->rewardTime = level.time + REWARD_SPRITE_TIME;
- }
- }
- }
- Team_ResetFlags();
-
- CalculateRanks();
-
- return 0; // Do not respawn this automatically
-}
-
-int Team_TouchEnemyFlag( gentity_t *ent, gentity_t *other, int team ) {
- gclient_t *cl = other->client;
-
- if( g_gametype.integer == GT_1FCTF ) {
- PrintMsg (NULL, "%s" S_COLOR_WHITE " got the flag!\n", other->client->pers.netname );
-
- G_LogPrintf( "1FCTF: %i %i %i: %s got the flag!\n", cl->ps.clientNum, team, 0, cl->pers.netname);
-
- cl->ps.powerups[PW_NEUTRALFLAG] = INT_MAX; // flags never expire
-
- if( team == TEAM_RED ) {
- Team_SetFlagStatus( TEAM_FREE, FLAG_TAKEN_RED );
- }
- else {
- Team_SetFlagStatus( TEAM_FREE, FLAG_TAKEN_BLUE );
- }
- }
- else{
- PrintMsg (NULL, "%s" S_COLOR_WHITE " got the %s flag!\n",
- other->client->pers.netname, TeamName(team));
-
- if(g_gametype.integer == GT_CTF) {
- G_LogPrintf( "CTF: %i %i %i: %s got the %s flag!\n", cl->ps.clientNum, team, 0, cl->pers.netname, TeamName(team));
- } else if(g_gametype.integer == GT_CTF_ELIMINATION) {
- G_LogPrintf( "CTF_ELIMINATION: %i %i %i %i: %s got the %s flag!\n", level.roundNumber, cl->ps.clientNum, team, 0, cl->pers.netname, TeamName(team));
- }
-
- if (team == TEAM_RED)
- cl->ps.powerups[PW_REDFLAG] = INT_MAX; // flags never expire
- else
- cl->ps.powerups[PW_BLUEFLAG] = INT_MAX; // flags never expire
-
- Team_SetFlagStatus( team, FLAG_TAKEN );
- }
-
- AddScore(other, ent->r.currentOrigin, CTF_FLAG_BONUS);
- cl->pers.teamState.flagsince = level.time;
- Team_TakeFlagSound( ent, team );
-
- return -1; // Do not respawn this automatically, but do delete it if it was FL_DROPPED
-}
-
-int Pickup_Team( gentity_t *ent, gentity_t *other ) {
- int team;
- gclient_t *cl = other->client;
-
- if( g_gametype.integer == GT_OBELISK ) {
- // there are no team items that can be picked up in obelisk
- G_FreeEntity( ent );
- return 0;
- }
-
- if( g_gametype.integer == GT_HARVESTER ) {
- // the only team items that can be picked up in harvester are the cubes
- if( ent->spawnflags != cl->sess.sessionTeam ) {
- cl->ps.generic1 += 1;
- }
- G_FreeEntity( ent );
- return 0;
- }
- if ( g_gametype.integer == GT_DOMINATION ) {
- Team_Dom_TakePoint(ent, cl->sess.sessionTeam);
- return 0;
- }
- // figure out what team this flag is
- if( strcmp(ent->classname, "team_CTF_redflag") == 0 ) {
- team = TEAM_RED;
- }
- else if( strcmp(ent->classname, "team_CTF_blueflag") == 0 ) {
- team = TEAM_BLUE;
- }
- else if( strcmp(ent->classname, "team_CTF_neutralflag") == 0 ) {
- team = TEAM_FREE;
- }
- else {
- PrintMsg ( other, "Don't know what team the flag is on.\n");
- return 0;
- }
- if( g_gametype.integer == GT_1FCTF ) {
- if( team == TEAM_FREE ) {
- return Team_TouchEnemyFlag( ent, other, cl->sess.sessionTeam );
- }
- if( team != cl->sess.sessionTeam) {
- return Team_TouchOurFlag( ent, other, cl->sess.sessionTeam );
- }
- return 0;
- }
- if( g_gametype.integer == GT_DOUBLE_D) {
- return Team_TouchDoubleDominationPoint( ent, other, team );
- }
- // GT_CTF
- if( team == cl->sess.sessionTeam) {
- return Team_TouchOurFlag( ent, other, team );
- }
- return Team_TouchEnemyFlag( ent, other, team );
-}
-
-/*
-===========
-Team_GetLocation
-
-Report a location for the player. Uses placed nearby target_location entities
-============
-*/
-gentity_t *Team_GetLocation(gentity_t *ent)
-{
- gentity_t *eloc, *best;
- float bestlen, len;
- vec3_t origin;
-
- best = NULL;
- bestlen = 3*8192.0*8192.0;
-
- VectorCopy( ent->r.currentOrigin, origin );
-
- for (eloc = level.locationHead; eloc; eloc = eloc->nextTrain) {
- len = ( origin[0] - eloc->r.currentOrigin[0] ) * ( origin[0] - eloc->r.currentOrigin[0] )
- + ( origin[1] - eloc->r.currentOrigin[1] ) * ( origin[1] - eloc->r.currentOrigin[1] )
- + ( origin[2] - eloc->r.currentOrigin[2] ) * ( origin[2] - eloc->r.currentOrigin[2] );
-
- if ( len > bestlen ) {
- continue;
- }
-
- if ( !trap_InPVS( origin, eloc->r.currentOrigin ) ) {
- continue;
- }
-
- bestlen = len;
- best = eloc;
- }
-
- return best;
-}
-
-
-/*
-===========
-Team_GetLocation
-
-Report a location for the player. Uses placed nearby target_location entities
-============
-*/
-qboolean Team_GetLocationMsg(gentity_t *ent, char *loc, int loclen)
-{
- gentity_t *best;
-
- best = Team_GetLocation( ent );
-
- if (!best)
- return qfalse;
-
- if (best->count) {
- if (best->count < 0)
- best->count = 0;
- if (best->count > 7)
- best->count = 7;
- Com_sprintf(loc, loclen, "%c%c%s" S_COLOR_WHITE, Q_COLOR_ESCAPE, best->count + '0', best->message );
- } else
- Com_sprintf(loc, loclen, "%s", best->message);
-
- return qtrue;
-}
-
-
-/*---------------------------------------------------------------------------*/
-
-/*
-================
-SelectRandomDeathmatchSpawnPoint
-
-go to a random point that doesn't telefrag
-================
-*/
-#define MAX_TEAM_SPAWN_POINTS 32
-gentity_t *SelectRandomTeamSpawnPoint( int teamstate, team_t team ) {
- gentity_t *spot;
- int count;
- int selection;
- gentity_t *spots[MAX_TEAM_SPAWN_POINTS];
- char *classname;
-
- if(g_gametype.integer == GT_ELIMINATION) { //change sides every round
- if((level.roundNumber+level.eliminationSides)%2==1){
- if(team == TEAM_RED)
- team = TEAM_BLUE;
- else if(team == TEAM_BLUE)
- team = TEAM_RED;
- }
- }
-
- if (teamstate == TEAM_BEGIN) {
- if (team == TEAM_RED)
- classname = "team_CTF_redplayer";
- else if (team == TEAM_BLUE)
- classname = "team_CTF_blueplayer";
- else
- return NULL;
- } else {
- if (team == TEAM_RED)
- classname = "team_CTF_redspawn";
- else if (team == TEAM_BLUE)
- classname = "team_CTF_bluespawn";
- else
- return NULL;
- }
- count = 0;
-
- spot = NULL;
-
- while ((spot = G_Find (spot, FOFS(classname), classname)) != NULL) {
- if ( SpotWouldTelefrag( spot ) ) {
- continue;
- }
- spots[ count ] = spot;
- if (++count == MAX_TEAM_SPAWN_POINTS)
- break;
- }
-
- if ( !count ) { // no spots that won't telefrag
- return G_Find( NULL, FOFS(classname), classname);
- }
-
- selection = rand() % count;
- return spots[ selection ];
-}
-
-/*
-================
-SelectRandomDDSpawnPoint
-
-go to a random Double Domination Spawn Point
-================
-*/
-#define MAX_TEAM_SPAWN_POINTS 32
-gentity_t *SelectRandomDDSpawnPoint( void ) {
- gentity_t *spot;
- int count;
- int selection;
- gentity_t *spots[MAX_TEAM_SPAWN_POINTS];
- char *classname;
-
-
- classname = "info_player_dd";
-
- count = 0;
-
- spot = NULL;
-
- while ((spot = G_Find (spot, FOFS(classname), classname)) != NULL) {
- if ( SpotWouldTelefrag( spot ) ) {
- continue;
- }
- spots[ count ] = spot;
- if (++count == MAX_TEAM_SPAWN_POINTS)
- break;
- }
-
- if ( !count ) { // no spots that won't telefrag
- return G_Find( NULL, FOFS(classname), classname);
- }
-
- selection = rand() % count;
- return spots[ selection ];
-}
-
-gentity_t *SelectRandomTeamDDSpawnPoint( team_t team ) {
- gentity_t *spot;
- int count;
- int selection;
- gentity_t *spots[MAX_TEAM_SPAWN_POINTS];
- char *classname;
-
- if(team == TEAM_RED)
- classname = "info_player_dd_red";
- else
- classname = "info_player_dd_blue";
-
- count = 0;
-
- spot = NULL;
-
- while ((spot = G_Find (spot, FOFS(classname), classname)) != NULL) {
- if ( SpotWouldTelefrag( spot ) ) {
- continue;
- }
- spots[ count ] = spot;
- if (++count == MAX_TEAM_SPAWN_POINTS)
- break;
- }
-
- if ( !count ) { // no spots that won't telefrag
- return G_Find( NULL, FOFS(classname), classname);
- }
-
- selection = rand() % count;
- return spots[ selection ];
-}
-
-
-/*
-===========
-SelectCTFSpawnPoint
-
-============
-*/
-gentity_t *SelectCTFSpawnPoint ( team_t team, int teamstate, vec3_t origin, vec3_t angles ) {
- gentity_t *spot;
-
- spot = SelectRandomTeamSpawnPoint ( teamstate, team );
-
- if (!spot) {
- return SelectSpawnPoint( vec3_origin, origin, angles );
- }
-
- VectorCopy (spot->s.origin, origin);
- origin[2] += 9;
- VectorCopy (spot->s.angles, angles);
-
- return spot;
-}
-
-/*
-===========
-SelectDoubleDominationSpawnPoint
-
-============
-*/
-gentity_t *SelectDoubleDominationSpawnPoint ( team_t team, vec3_t origin, vec3_t angles ) {
- gentity_t *spot;
-
- spot = SelectRandomTeamDDSpawnPoint( team );
-
- if(!spot) {
- spot = SelectRandomDDSpawnPoint ( );
- }
-
- if (!spot) {
- return SelectSpawnPoint( vec3_origin, origin, angles );
- }
-
- VectorCopy (spot->s.origin, origin);
- origin[2] += 9;
- VectorCopy (spot->s.angles, angles);
-
- return spot;
-}
-
-/*---------------------------------------------------------------------------*/
-
-static int QDECL SortClients( const void *a, const void *b ) {
- return *(int *)a - *(int *)b;
-}
-
-
-/*
-==================
-TeamplayLocationsMessage
-
-Format:
- clientNum location health armor weapon powerups
-
-==================
-*/
-void TeamplayInfoMessage( gentity_t *ent ) {
- char entry[1024];
- char string[8192];
- int stringlength;
- int i, j;
- gentity_t *player;
- int cnt;
- int h, a, w;
- int clients[TEAM_MAXOVERLAY];
-
- if ( ! ent->client->pers.teamInfo )
- return;
-
- // figure out what client should be on the display
- // we are limited to 8, but we want to use the top eight players
- // but in client order (so they don't keep changing position on the overlay)
- for (i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {
- player = g_entities + level.sortedClients[i];
- if (player->inuse && player->client->sess.sessionTeam ==
- ent->client->sess.sessionTeam ) {
- clients[cnt++] = level.sortedClients[i];
- }
- }
-
- // We have the top eight players, sort them by clientNum
- qsort( clients, cnt, sizeof( clients[0] ), SortClients );
-
- // send the latest information on all clients
- string[0] = 0;
- stringlength = 0;
-
- for (i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {
- player = g_entities + i;
- if (player->inuse && player->client->sess.sessionTeam ==
- ent->client->sess.sessionTeam ) {
-
- h = player->client->ps.stats[STAT_HEALTH];
- a = player->client->ps.stats[STAT_ARMOR];
- w = player->client->ps.weapon;
- if(player->client->isEliminated)
- {
- h = 0;
- a = 0;
- w = 0;
- }
- if (h < 0) h = 0;
- if (a < 0) a = 0;
-
- Com_sprintf (entry, sizeof(entry),
- " %i %i %i %i %i %i",
-// level.sortedClients[i], player->client->pers.teamState.location, h, a,
- i, player->client->pers.teamState.location, h, a,
- w, player->s.powerups);
- j = strlen(entry);
- if (stringlength + j > sizeof(string))
- break;
- strcpy (string + stringlength, entry);
- stringlength += j;
- cnt++;
- }
- }
-
- trap_SendServerCommand( ent-g_entities, va("tinfo %i %s", cnt, string) );
-}
-
-void CheckTeamStatus(void) {
- int i;
- gentity_t *loc, *ent;
-
- if (level.time - level.lastTeamLocationTime > TEAM_LOCATION_UPDATE_TIME) {
-
- level.lastTeamLocationTime = level.time;
-
- for (i = 0; i < g_maxclients.integer; i++) {
- ent = g_entities + i;
-
- if ( ent->client->pers.connected != CON_CONNECTED ) {
- continue;
- }
-
- if (ent->inuse && (ent->client->sess.sessionTeam == TEAM_RED || ent->client->sess.sessionTeam == TEAM_BLUE)) {
- loc = Team_GetLocation( ent );
- if (loc)
- ent->client->pers.teamState.location = loc->health;
- else
- ent->client->pers.teamState.location = 0;
- }
- }
-
- for (i = 0; i < g_maxclients.integer; i++) {
- ent = g_entities + i;
-
- if ( ent->client->pers.connected != CON_CONNECTED ) {
- continue;
- }
-
- if (ent->inuse && (ent->client->sess.sessionTeam == TEAM_RED || ent->client->sess.sessionTeam == TEAM_BLUE)) {
- TeamplayInfoMessage( ent );
- }
- }
- }
-}
-
-/*-----------------------------------------------------------------*/
-
-/*QUAKED team_CTF_redplayer (1 0 0) (-16 -16 -16) (16 16 32)
-Only in CTF games. Red players spawn here at game start.
-*/
-void SP_team_CTF_redplayer( gentity_t *ent ) {
-}
-
-
-/*QUAKED team_CTF_blueplayer (0 0 1) (-16 -16 -16) (16 16 32)
-Only in CTF games. Blue players spawn here at game start.
-*/
-void SP_team_CTF_blueplayer( gentity_t *ent ) {
-}
-
-
-/*QUAKED team_CTF_redspawn (1 0 0) (-16 -16 -24) (16 16 32)
-potential spawning position for red team in CTF games.
-Targets will be fired when someone spawns in on them.
-*/
-void SP_team_CTF_redspawn(gentity_t *ent) {
-}
-
-/*QUAKED team_CTF_bluespawn (0 0 1) (-16 -16 -24) (16 16 32)
-potential spawning position for blue team in CTF games.
-Targets will be fired when someone spawns in on them.
-*/
-void SP_team_CTF_bluespawn(gentity_t *ent) {
-}
-
-/*
-================
-Obelisks
-================
-*/
-
-static void ObeliskRegen( gentity_t *self ) {
- self->nextthink = level.time + g_obeliskRegenPeriod.integer * 1000;
- if( self->health >= g_obeliskHealth.integer ) {
- return;
- }
-
- G_AddEvent( self, EV_POWERUP_REGEN, 0 );
- self->health += g_obeliskRegenAmount.integer;
- if ( self->health > g_obeliskHealth.integer ) {
- self->health = g_obeliskHealth.integer;
- }
-
- self->activator->s.modelindex2 = self->health * 0xff / g_obeliskHealth.integer;
- self->activator->s.frame = 0;
-}
-
-
-static void ObeliskRespawn( gentity_t *self ) {
- self->takedamage = qtrue;
- self->health = g_obeliskHealth.integer;
-
- self->think = ObeliskRegen;
- self->nextthink = level.time + g_obeliskRegenPeriod.integer * 1000;
-
- self->activator->s.frame = 0;
-}
-
-
-static void ObeliskDie( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) {
- int otherTeam;
-
- otherTeam = OtherTeam( self->spawnflags );
- AddTeamScore(self->s.pos.trBase, otherTeam, 1);
- Team_ForceGesture(otherTeam);
-
- CalculateRanks();
-
- self->takedamage = qfalse;
- self->think = ObeliskRespawn;
- self->nextthink = level.time + g_obeliskRespawnDelay.integer * 1000;
-
- self->activator->s.modelindex2 = 0xff;
- self->activator->s.frame = 2;
-
- G_AddEvent( self->activator, EV_OBELISKEXPLODE, 0 );
-
- AddScore(attacker, self->r.currentOrigin, CTF_CAPTURE_BONUS);
-
- // add the sprite over the player's head
- attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- attacker->client->ps.eFlags |= EF_AWARD_CAP;
- attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
- attacker->client->ps.persistant[PERS_CAPTURES]++;
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", attacker->client->ps.clientNum, 4, attacker->client->pers.netname, "CAPTURE" );
- if(TeamCount(-1,TEAM_RED) && TeamCount(-1,TEAM_BLUE) && !level.hadBots)
- ChallengeMessage(attacker,AWARD_CAPTURE);
-
- teamgame.redObeliskAttackedTime = 0;
- teamgame.blueObeliskAttackedTime = 0;
-}
-
-
-static void ObeliskTouch( gentity_t *self, gentity_t *other, trace_t *trace ) {
- int tokens,i;
-
- if ( !other->client ) {
- return;
- }
-
- if ( OtherTeam(other->client->sess.sessionTeam) != self->spawnflags ) {
- return;
- }
-
- tokens = other->client->ps.generic1;
- if( tokens <= 0 ) {
- return;
- }
-
- PrintMsg(NULL, "%s" S_COLOR_WHITE " brought in %i skull%s.\n",
- other->client->pers.netname, tokens, tokens ? "s" : "" );
-
- AddTeamScore(self->s.pos.trBase, other->client->sess.sessionTeam, tokens);
- Team_ForceGesture(other->client->sess.sessionTeam);
-
- AddScore(other, self->r.currentOrigin, CTF_CAPTURE_BONUS*tokens);
-
- // add the sprite over the player's head
- other->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- other->client->ps.eFlags |= EF_AWARD_CAP;
- other->client->rewardTime = level.time + REWARD_SPRITE_TIME;
- other->client->ps.persistant[PERS_CAPTURES] += tokens;
- for(i = 0;i<tokens;i++)
- {
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", other->client->ps.clientNum, 4, other->client->pers.netname, "CAPTURE" );
- if(TeamCount(-1,TEAM_RED) && TeamCount(-1,TEAM_BLUE) && !level.hadBots)
- ChallengeMessage(other,AWARD_CAPTURE);
- }
-
- other->client->ps.generic1 = 0;
- CalculateRanks();
-
- Team_CaptureFlagSound( self, self->spawnflags );
-}
-
-static void ObeliskPain( gentity_t *self, gentity_t *attacker, int damage ) {
- int actualDamage = damage / 10;
- if (actualDamage <= 0) {
- actualDamage = 1;
- }
- self->activator->s.modelindex2 = self->health * 0xff / g_obeliskHealth.integer;
- if (!self->activator->s.frame) {
- G_AddEvent(self, EV_OBELISKPAIN, 0);
- }
- self->activator->s.frame = 1;
- AddScore(attacker, self->r.currentOrigin, actualDamage);
-}
-
-gentity_t *SpawnObelisk( vec3_t origin, int team, int spawnflags) {
- trace_t tr;
- vec3_t dest;
- gentity_t *ent;
-
- ent = G_Spawn();
-
- VectorCopy( origin, ent->s.origin );
- VectorCopy( origin, ent->s.pos.trBase );
- VectorCopy( origin, ent->r.currentOrigin );
-
- VectorSet( ent->r.mins, -15, -15, 0 );
- VectorSet( ent->r.maxs, 15, 15, 87 );
-
- ent->s.eType = ET_GENERAL;
- ent->flags = FL_NO_KNOCKBACK;
-
- if( g_gametype.integer == GT_OBELISK ) {
- ent->r.contents = CONTENTS_SOLID;
- ent->takedamage = qtrue;
- ent->health = g_obeliskHealth.integer;
- ent->die = ObeliskDie;
- ent->pain = ObeliskPain;
- ent->think = ObeliskRegen;
- ent->nextthink = level.time + g_obeliskRegenPeriod.integer * 1000;
- }
- if( g_gametype.integer == GT_HARVESTER ) {
- ent->r.contents = CONTENTS_TRIGGER;
- ent->touch = ObeliskTouch;
- }
-
- if ( spawnflags & 1 ) {
- // suspended
- G_SetOrigin( ent, ent->s.origin );
- } else {
- // mappers like to put them exactly on the floor, but being coplanar
- // will sometimes show up as starting in solid, so lif it up one pixel
- ent->s.origin[2] += 1;
-
- // drop to floor
- VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
- trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
- if ( tr.startsolid ) {
- ent->s.origin[2] -= 1;
- G_Printf( "SpawnObelisk: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin) );
-
- ent->s.groundEntityNum = ENTITYNUM_NONE;
- G_SetOrigin( ent, ent->s.origin );
- }
- else {
- // allow to ride movers
- ent->s.groundEntityNum = tr.entityNum;
- G_SetOrigin( ent, tr.endpos );
- }
- }
-
- ent->spawnflags = team;
-
- trap_LinkEntity( ent );
-
- return ent;
-}
-
-/*QUAKED team_redobelisk (1 0 0) (-16 -16 0) (16 16 8)
-*/
-void SP_team_redobelisk( gentity_t *ent ) {
- gentity_t *obelisk;
-
- if ( g_gametype.integer <= GT_TEAM || g_ffa_gt>0) {
- G_FreeEntity(ent);
- return;
- }
- ent->s.eType = ET_TEAM;
- if ( g_gametype.integer == GT_OBELISK ) {
- obelisk = SpawnObelisk( ent->s.origin, TEAM_RED, ent->spawnflags );
- obelisk->activator = ent;
- // initial obelisk health value
- ent->s.modelindex2 = 0xff;
- ent->s.frame = 0;
- }
- if ( g_gametype.integer == GT_HARVESTER ) {
- obelisk = SpawnObelisk( ent->s.origin, TEAM_RED, ent->spawnflags );
- obelisk->activator = ent;
- }
- ent->s.modelindex = TEAM_RED;
- trap_LinkEntity(ent);
-}
-
-/*QUAKED team_blueobelisk (0 0 1) (-16 -16 0) (16 16 88)
-*/
-void SP_team_blueobelisk( gentity_t *ent ) {
- gentity_t *obelisk;
-
- if ( g_gametype.integer <= GT_TEAM || g_ffa_gt>0) {
- G_FreeEntity(ent);
- return;
- }
- ent->s.eType = ET_TEAM;
- if ( g_gametype.integer == GT_OBELISK ) {
- obelisk = SpawnObelisk( ent->s.origin, TEAM_BLUE, ent->spawnflags );
- obelisk->activator = ent;
- // initial obelisk health value
- ent->s.modelindex2 = 0xff;
- ent->s.frame = 0;
- }
- if ( g_gametype.integer == GT_HARVESTER ) {
- obelisk = SpawnObelisk( ent->s.origin, TEAM_BLUE, ent->spawnflags );
- obelisk->activator = ent;
- }
- ent->s.modelindex = TEAM_BLUE;
- trap_LinkEntity(ent);
-}
-
-/*QUAKED team_neutralobelisk (0 0 1) (-16 -16 0) (16 16 88)
-*/
-void SP_team_neutralobelisk( gentity_t *ent ) {
- if ( g_gametype.integer != GT_1FCTF && g_gametype.integer != GT_HARVESTER ) {
- G_FreeEntity(ent);
- return;
- }
- ent->s.eType = ET_TEAM;
- if ( g_gametype.integer == GT_HARVESTER) {
- neutralObelisk = SpawnObelisk( ent->s.origin, TEAM_FREE, ent->spawnflags);
- neutralObelisk->spawnflags = TEAM_FREE;
- }
- ent->s.modelindex = TEAM_FREE;
- trap_LinkEntity(ent);
-}
-
-
-/*
-================
-CheckObeliskAttack
-================
-*/
-qboolean CheckObeliskAttack( gentity_t *obelisk, gentity_t *attacker ) {
- gentity_t *te;
-
- // if this really is an obelisk
- if( obelisk->die != ObeliskDie ) {
- return qfalse;
- }
-
- // if the attacker is a client
- if( !attacker->client ) {
- return qfalse;
- }
-
- // if the obelisk is on the same team as the attacker then don't hurt it
- if( obelisk->spawnflags == attacker->client->sess.sessionTeam ) {
- return qtrue;
- }
-
- // obelisk may be hurt
-
- // if not played any sounds recently
- if ((obelisk->spawnflags == TEAM_RED &&
- teamgame.redObeliskAttackedTime < level.time - OVERLOAD_ATTACK_BASE_SOUND_TIME) ||
- (obelisk->spawnflags == TEAM_BLUE &&
- teamgame.blueObeliskAttackedTime < level.time - OVERLOAD_ATTACK_BASE_SOUND_TIME) ) {
-
- // tell which obelisk is under attack
- te = G_TempEntity( obelisk->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
- if( obelisk->spawnflags == TEAM_RED ) {
- te->s.eventParm = GTS_REDOBELISK_ATTACKED;
- teamgame.redObeliskAttackedTime = level.time;
- }
- else {
- te->s.eventParm = GTS_BLUEOBELISK_ATTACKED;
- teamgame.blueObeliskAttackedTime = level.time;
- }
- te->r.svFlags |= SVF_BROADCAST;
- }
-
- return qfalse;
-}
-
-/*
-================
-ShuffleTeams
- *Randomizes the teams based on a type of function and then restarts the map
- *Currently there is only one type so type is ignored. You can add total randomizaion or waighted randomization later.
- *
- *The function will split the teams like this:
- *1. Red team
- *2. Blue team
- *3. Blue team
- *4. Red team
- *5. Go to 1
-================
-*/
-void ShuffleTeams(void) {
- int i;
- int assignedClients=1, nextTeam=TEAM_RED;
-
- if ( g_gametype.integer < GT_TEAM || g_ffa_gt==1)
- return; //Can only shuffle team games!
-
- for( i=0;i < level.numConnectedClients; i++ ) {
- if( g_entities[ &level.clients[level.sortedClients[i]] - level.clients].r.svFlags & SVF_BOT)
- continue; //Don't sort bots... they are always equal
-
- if(level.clients[level.sortedClients[i]].sess.sessionTeam==TEAM_RED || level.clients[level.sortedClients[i]].sess.sessionTeam==TEAM_BLUE ) {
- //For every second client we chenge team. But we do it a little of to make it slightly more fair
- if(assignedClients>1) {
- assignedClients=0;
- if(nextTeam == TEAM_RED)
- nextTeam = TEAM_BLUE;
- else
- nextTeam = TEAM_RED;
- }
-
- //Set the team
- //We do not run all the logic because we shall run map_restart in a moment.
- level.clients[level.sortedClients[i]].sess.sessionTeam = nextTeam;
-
- ClientUserinfoChanged( level.sortedClients[i] );
- ClientBegin( level.sortedClients[i] );
-
- assignedClients++;
- }
- }
-
- //Restart!
- trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
-
-}
-
diff --git a/game/code/game/g_trigger.c b/game/code/game/g_trigger.c
deleted file mode 100644
index fdeb0ee..0000000
--- a/game/code/game/g_trigger.c
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "g_local.h"
-
-
-void InitTrigger( gentity_t *self ) {
- if (!VectorCompare (self->s.angles, vec3_origin))
- G_SetMovedir (self->s.angles, self->movedir);
-
- trap_SetBrushModel( self, self->model );
- self->r.contents = CONTENTS_TRIGGER; // replaces the -1 from trap_SetBrushModel
- self->r.svFlags = SVF_NOCLIENT;
-}
-
-
-// the wait time has passed, so set back up for another activation
-void multi_wait( gentity_t *ent ) {
- ent->nextthink = 0;
-}
-
-
-// the trigger was just activated
-// ent->activator should be set to the activator so it can be held through a delay
-// so wait for the delay time before firing
-void multi_trigger( gentity_t *ent, gentity_t *activator ) {
- ent->activator = activator;
- if ( ent->nextthink ) {
- return; // can't retrigger until the wait is over
- }
-
- if ( activator->client ) {
- if ( ( ent->spawnflags & 1 ) &&
- activator->client->sess.sessionTeam != TEAM_RED ) {
- return;
- }
- if ( ( ent->spawnflags & 2 ) &&
- activator->client->sess.sessionTeam != TEAM_BLUE ) {
- return;
- }
- }
-
- G_UseTargets (ent, ent->activator);
-
- if ( ent->wait > 0 ) {
- ent->think = multi_wait;
- ent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;
- } else {
- // we can't just remove (self) here, because this is a touch function
- // called while looping through area links...
- ent->touch = 0;
- ent->nextthink = level.time + FRAMETIME;
- ent->think = G_FreeEntity;
- }
-}
-
-void Use_Multi( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
- multi_trigger( ent, activator );
-}
-
-void Touch_Multi( gentity_t *self, gentity_t *other, trace_t *trace ) {
- if( !other->client ) {
- return;
- }
- multi_trigger( self, other );
-}
-
-/*QUAKED trigger_multiple (.5 .5 .5) ?
-"wait" : Seconds between triggerings, 0.5 default, -1 = one time only.
-"random" wait variance, default is 0
-Variable sized repeatable trigger. Must be targeted at one or more entities.
-so, the basic time between firing is a random time between
-(wait - random) and (wait + random)
-*/
-void SP_trigger_multiple( gentity_t *ent ) {
- G_SpawnFloat( "wait", "0.5", &ent->wait );
- G_SpawnFloat( "random", "0", &ent->random );
-
- if ( ent->random >= ent->wait && ent->wait >= 0 ) {
- ent->random = ent->wait - FRAMETIME;
- G_Printf( "trigger_multiple has random >= wait\n" );
- }
-
- ent->touch = Touch_Multi;
- ent->use = Use_Multi;
-
- InitTrigger( ent );
- trap_LinkEntity (ent);
-}
-
-
-
-/*
-==============================================================================
-
-trigger_always
-
-==============================================================================
-*/
-
-void trigger_always_think( gentity_t *ent ) {
- G_UseTargets(ent, ent);
- G_FreeEntity( ent );
-}
-
-/*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
-This trigger will always fire. It is activated by the world.
-*/
-void SP_trigger_always (gentity_t *ent) {
- // we must have some delay to make sure our use targets are present
- ent->nextthink = level.time + 300;
- ent->think = trigger_always_think;
-}
-
-
-/*
-==============================================================================
-
-trigger_push
-
-==============================================================================
-*/
-
-void trigger_push_touch (gentity_t *self, gentity_t *other, trace_t *trace ) {
-
- if ( !other->client ) {
- return;
- }
-
- BG_TouchJumpPad( &other->client->ps, &self->s );
-}
-
-
-/*
-=================
-AimAtTarget
-
-Calculate origin2 so the target apogee will be hit
-=================
-*/
-void AimAtTarget( gentity_t *self ) {
- gentity_t *ent;
- vec3_t origin;
- float height, gravity, time, forward;
- float dist;
-
- VectorAdd( self->r.absmin, self->r.absmax, origin );
- VectorScale ( origin, 0.5, origin );
-
- ent = G_PickTarget( self->target );
- if ( !ent ) {
- G_FreeEntity( self );
- return;
- }
-
- height = ent->s.origin[2] - origin[2];
- gravity = g_gravity.value;
- time = sqrt( height / ( .5 * gravity ) );
- if ( !time ) {
- G_FreeEntity( self );
- return;
- }
-
- // set s.origin2 to the push velocity
- VectorSubtract ( ent->s.origin, origin, self->s.origin2 );
- self->s.origin2[2] = 0;
- dist = VectorNormalize( self->s.origin2);
-
- forward = dist / time;
- VectorScale( self->s.origin2, forward, self->s.origin2 );
-
- self->s.origin2[2] = time * gravity;
-}
-
-
-/*QUAKED trigger_push (.5 .5 .5) ?
-Must point at a target_position, which will be the apex of the leap.
-This will be client side predicted, unlike target_push
-*/
-void SP_trigger_push( gentity_t *self ) {
- InitTrigger (self);
-
- // unlike other triggers, we need to send this one to the client
- self->r.svFlags &= ~SVF_NOCLIENT;
-
- // make sure the client precaches this sound
- G_SoundIndex("sound/world/jumppad.wav");
-
- self->s.eType = ET_PUSH_TRIGGER;
- self->touch = trigger_push_touch;
- self->think = AimAtTarget;
- self->nextthink = level.time + FRAMETIME;
- trap_LinkEntity (self);
-}
-
-
-void Use_target_push( gentity_t *self, gentity_t *other, gentity_t *activator ) {
- if ( !activator->client ) {
- return;
- }
-
- if ( activator->client->ps.pm_type != PM_NORMAL ) {
- return;
- }
- if ( activator->client->ps.powerups[PW_FLIGHT] ) {
- return;
- }
-
- VectorCopy (self->s.origin2, activator->client->ps.velocity);
-
- // play fly sound every 1.5 seconds
- if ( activator->fly_sound_debounce_time < level.time ) {
- activator->fly_sound_debounce_time = level.time + 1500;
- G_Sound( activator, CHAN_AUTO, self->noise_index );
- }
-}
-
-/*QUAKED target_push (.5 .5 .5) (-8 -8 -8) (8 8 8) bouncepad
-Pushes the activator in the direction.of angle, or towards a target apex.
-"speed" defaults to 1000
-if "bouncepad", play bounce noise instead of windfly
-*/
-void SP_target_push( gentity_t *self ) {
- if (!self->speed) {
- self->speed = 1000;
- }
- G_SetMovedir (self->s.angles, self->s.origin2);
- VectorScale (self->s.origin2, self->speed, self->s.origin2);
-
- if ( self->spawnflags & 1 ) {
- self->noise_index = G_SoundIndex("sound/world/jumppad.wav");
- } else {
- self->noise_index = G_SoundIndex("sound/misc/windfly.wav");
- }
- if ( self->target ) {
- VectorCopy( self->s.origin, self->r.absmin );
- VectorCopy( self->s.origin, self->r.absmax );
- self->think = AimAtTarget;
- self->nextthink = level.time + FRAMETIME;
- }
- self->use = Use_target_push;
-}
-
-/*
-==============================================================================
-
-trigger_teleport
-
-==============================================================================
-*/
-
-void trigger_teleporter_touch (gentity_t *self, gentity_t *other, trace_t *trace ) {
- gentity_t *dest;
-
- if ( !other->client ) {
- return;
- }
-
- if ( other->client->ps.pm_type == PM_DEAD ) {
- return;
- }
- // Spectators only?
- if ( ( self->spawnflags & 1 ) &&
- (other->client->sess.sessionTeam != TEAM_SPECTATOR && other->client->ps.pm_type != PM_SPECTATOR) ) {
- return;
- }
-
-
- dest = G_PickTarget( self->target );
- if (!dest) {
- G_Printf ("Couldn't find teleporter destination\n");
- return;
- }
-
- TeleportPlayer( other, dest->s.origin, dest->s.angles );
-}
-
-
-/*QUAKED trigger_teleport (.5 .5 .5) ? SPECTATOR
-Allows client side prediction of teleportation events.
-Must point at a target_position, which will be the teleport destination.
-
-If spectator is set, only spectators can use this teleport
-Spectator teleporters are not normally placed in the editor, but are created
-automatically near doors to allow spectators to move through them
-*/
-void SP_trigger_teleport( gentity_t *self ) {
- InitTrigger (self);
-
- // unlike other triggers, we need to send this one to the client
- // unless is a spectator trigger
- if ( self->spawnflags & 1 ) {
- self->r.svFlags |= SVF_NOCLIENT;
- } else {
- self->r.svFlags &= ~SVF_NOCLIENT;
- }
-
- // make sure the client precaches this sound
- G_SoundIndex("sound/world/jumppad.wav");
-
- self->s.eType = ET_TELEPORT_TRIGGER;
- self->touch = trigger_teleporter_touch;
-
- trap_LinkEntity (self);
-}
-
-
-/*
-==============================================================================
-
-trigger_hurt
-
-==============================================================================
-*/
-
-/*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF - SILENT NO_PROTECTION SLOW
-Any entity that touches this will be hurt.
-It does dmg points of damage each server frame
-Targeting the trigger will toggle its on / off state.
-
-SILENT supresses playing the sound
-SLOW changes the damage rate to once per second
-NO_PROTECTION *nothing* stops the damage
-
-"dmg" default 5 (whole numbers only)
-
-*/
-void hurt_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
- if ( self->r.linked ) {
- trap_UnlinkEntity( self );
- } else {
- trap_LinkEntity( self );
- }
-}
-
-void hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) {
- int dflags;
-
- if ( !other->takedamage ) {
- return;
- }
-
- if ( self->timestamp > level.time ) {
- return;
- }
-
- if ( self->spawnflags & 16 ) {
- self->timestamp = level.time + 1000;
- } else {
- self->timestamp = level.time + FRAMETIME;
- }
-
- // play sound
- if ( !(self->spawnflags & 4) ) {
- G_Sound( other, CHAN_AUTO, self->noise_index );
- }
-
- if (self->spawnflags & 8)
- dflags = DAMAGE_NO_PROTECTION;
- else
- dflags = 0;
- G_Damage (other, self, self, NULL, NULL, self->damage, dflags, MOD_TRIGGER_HURT);
-}
-
-void SP_trigger_hurt( gentity_t *self ) {
- InitTrigger (self);
-
- self->noise_index = G_SoundIndex( "sound/world/electro.wav" );
- self->touch = hurt_touch;
-
- if ( !self->damage ) {
- self->damage = 5;
- }
-
- self->r.contents = CONTENTS_TRIGGER;
-
- if ( self->spawnflags & 2 ) {
- self->use = hurt_use;
- }
-
- // link in to the world if starting active
- if ( ! (self->spawnflags & 1) ) {
- trap_LinkEntity (self);
- }
-}
-
-
-/*
-==============================================================================
-
-timer
-
-==============================================================================
-*/
-
-
-/*QUAKED func_timer (0.3 0.1 0.6) (-8 -8 -8) (8 8 8) START_ON
-This should be renamed trigger_timer...
-Repeatedly fires its targets.
-Can be turned on or off by using.
-
-"wait" base time between triggering all targets, default is 1
-"random" wait variance, default is 0
-so, the basic time between firing is a random time between
-(wait - random) and (wait + random)
-
-*/
-void func_timer_think( gentity_t *self ) {
- G_UseTargets (self, self->activator);
- // set time before next firing
- self->nextthink = level.time + 1000 * ( self->wait + crandom() * self->random );
-}
-
-void func_timer_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
- self->activator = activator;
-
- // if on, turn it off
- if ( self->nextthink ) {
- self->nextthink = 0;
- return;
- }
-
- // turn it on
- func_timer_think (self);
-}
-
-void SP_func_timer( gentity_t *self ) {
- G_SpawnFloat( "random", "1", &self->random);
- G_SpawnFloat( "wait", "1", &self->wait );
-
- self->use = func_timer_use;
- self->think = func_timer_think;
-
- if ( self->random >= self->wait ) {
- self->random = self->wait - FRAMETIME;
- G_Printf( "func_timer at %s has random >= wait\n", vtos( self->s.origin ) );
- }
-
- if ( self->spawnflags & 1 ) {
- self->nextthink = level.time + FRAMETIME;
- self->activator = self;
- }
-
- self->r.svFlags = SVF_NOCLIENT;
-}
-
-
diff --git a/game/code/game/g_vote.c b/game/code/game/g_vote.c
deleted file mode 100644
index f848678..0000000
--- a/game/code/game/g_vote.c
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 2008-2009 Poul Sander
-
-This file is part of Open Arena source code.
-
-Open Arena source code 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.
-
-Open Arena source code 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 Open Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "g_local.h"
-
-/*
-==================
-allowedVote
- *Note: Keep this in sync with allowedVote in ui_votemenu.c (except for cg_voteNames and g_voteNames)
-==================
- */
-#define MAX_VOTENAME_LENGTH 14 //currently the longest string is "/map_restart/\0" (14 chars)
-int allowedVote(char *commandStr) {
- char tempStr[MAX_VOTENAME_LENGTH];
- int length;
- char voteNames[MAX_CVAR_VALUE_STRING];
- trap_Cvar_VariableStringBuffer( "g_voteNames", voteNames, sizeof( voteNames ) );
- if(!Q_stricmp(voteNames, "*" ))
- return qtrue; //if star, everything is allowed
- length = strlen(commandStr);
- if(length>MAX_VOTENAME_LENGTH-3)
- {
- //Error: too long
- return qfalse;
- }
- //Now constructing a string that starts and ends with '/' like: "/clientkick/"
- tempStr[0] = '/';
- strncpy(&tempStr[1],commandStr,length);
- tempStr[length+1] = '/';
- tempStr[length+2] = '\0';
- if(Q_stristr(voteNames,tempStr) != NULL)
- return qtrue;
- else
- return qfalse;
-}
-
-/*
-==================
-getMappage
-==================
- */
-
-t_mappage getMappage(int page) {
- t_mappage result;
- fileHandle_t file;
- char *token,*pointer;
- char buffer[MAX_MAPNAME_BUFFER];
- int i, nummaps,maplen;
-
- memset(&result,0,sizeof(result));
- memset(&buffer,0,sizeof(buffer));
-
- //Check if there is a votemaps.cfg
- trap_FS_FOpenFile("votemaps.cfg",&file,FS_READ);
- if(file)
- {
- //there is a votemaps.cfg file, take allowed maps from there
- trap_FS_Read(&buffer,sizeof(buffer),file);
- pointer = buffer;
- token = COM_Parse(&pointer);
- if(token[0]==0 && page == 0) {
- //First page empty
- result.pagenumber = -1;
- trap_FS_FCloseFile(file);
- return result;
- }
- //Skip the first pages
- for(i=0;i<MAPS_PER_PAGE*page;i++) {
- token = COM_Parse(&pointer);
- }
- if(!token || token[0]==0) {
- //Page empty, return to first page
- trap_FS_FCloseFile(file);
- return getMappage(0);
- }
- //There is an actual page:
- result.pagenumber = page;
- for(i=0;i<MAPS_PER_PAGE && token;i++) {
- Q_strncpyz(result.mapname[i],token,MAX_MAPNAME);
- token = COM_Parse(&pointer);
- }
- trap_FS_FCloseFile(file);
- return result;
- }
- //There is no votemaps.cfg file, find filelist of maps
- nummaps = trap_FS_GetFileList("maps",".bsp",buffer,sizeof(buffer));
-
- if(nummaps && nummaps<=MAPS_PER_PAGE*page)
- return getMappage(0);
-
- pointer = buffer;
- result.pagenumber = page;
-
- for (i = 0; i < nummaps; i++, pointer += maplen+1) {
- maplen = strlen(pointer);
- if(i>=MAPS_PER_PAGE*page && i<MAPS_PER_PAGE*(page+1)) {
- Q_strncpyz(result.mapname[i-MAPS_PER_PAGE*page],pointer,maplen-3);
- }
- }
- return result;
-
-}
-
-/*
-==================
-allowedMap
-==================
- */
-
-int allowedMap(char *mapname) {
- int length;
- fileHandle_t file; //To check that the map actually exists.
- char buffer[MAX_MAPS_TEXT];
- char *token,*pointer;
- qboolean found;
-
- trap_FS_FOpenFile(va("maps/%s.bsp",mapname),&file,FS_READ);
- if(!file)
- return qfalse; //maps/MAPNAME.bsp does not exist
- trap_FS_FCloseFile(file);
-
- //Now read the file votemaps.cfg to see what maps are allowed
- trap_FS_FOpenFile("votemaps.cfg",&file,FS_READ);
-
- if(!file)
- return qtrue; //if no file, everything is allowed
- length = strlen(mapname);
- if(length>MAX_MAPNAME_LENGTH-3)
- {
- //Error: too long
- trap_FS_FCloseFile(file);
- return qfalse;
- }
-
- //Add file checking here
- trap_FS_Read(&buffer,MAX_MAPS_TEXT,file);
- found = qfalse;
- pointer = buffer;
- token = COM_Parse(&pointer);
- while(token[0]!=0 && !found) {
- if(!Q_stricmp(token,mapname))
- found = qtrue;
- token = COM_Parse(&pointer);
- }
-
- trap_FS_FCloseFile(file);
- //The map was not found
- return found;
-}
-
-/*
-==================
-allowedGametype
-==================
- */
-#define MAX_GAMETYPENAME_LENGTH 5 //currently the longest string is "/12/\0" (5 chars)
-int allowedGametype(char *gametypeStr) {
- char tempStr[MAX_GAMETYPENAME_LENGTH];
- int length;
- char voteGametypes[MAX_CVAR_VALUE_STRING];
- trap_Cvar_VariableStringBuffer( "g_voteGametypes", voteGametypes, sizeof( voteGametypes ) );
- if(!Q_stricmp(voteGametypes, "*" ))
- return qtrue; //if star, everything is allowed
- length = strlen(gametypeStr);
- if(length>MAX_GAMETYPENAME_LENGTH-3)
- {
- //Error: too long
- return qfalse;
- }
- tempStr[0] = '/';
- strncpy(&tempStr[1],gametypeStr,length);
- tempStr[length+1] = '/';
- tempStr[length+2] = '\0';
- if(Q_stristr(voteGametypes,tempStr) != NULL)
- return qtrue;
- else {
- return qfalse;
- }
-}
-
-/*
-==================
-allowedTimelimit
-==================
- */
-int allowedTimelimit(int limit) {
- int min, max;
- min = g_voteMinTimelimit.integer;
- max = g_voteMaxTimelimit.integer;
- if(limit<min && limit != 0)
- return qfalse;
- if(max!=0 && limit>max)
- return qfalse;
- if(limit==0 && max > 0)
- return qfalse;
- return qtrue;
-}
-
-/*
-==================
-allowedFraglimit
-==================
- */
-int allowedFraglimit(int limit) {
- int min, max;
- min = g_voteMinFraglimit.integer;
- max = g_voteMaxFraglimit.integer;
- if(limit<min && limit != 0)
- return qfalse;
- if(max != 0 && limit>max)
- return qfalse;
- if(limit==0 && max > 0)
- return qfalse;
- return qtrue;
-}
-
-#define MAX_CUSTOM_VOTES 12
-
-char custom_vote_info[1024];
-
-/*
-==================
-VoteParseCustomVotes
- *Reads the file votecustom.cfg. Finds all the commands that can be used with
- *"/callvote custom COMMAND" and adds the commands to custom_vote_info
-==================
- */
-int VoteParseCustomVotes( void ) {
- fileHandle_t file;
- char buffer[4*1024];
- int commands;
- char *token,*pointer;
-
- trap_FS_FOpenFile("votecustom.cfg",&file,FS_READ);
-
- if(!file)
- return 0;
-
- memset(&buffer,0,sizeof(buffer));
- memset(&custom_vote_info,0,sizeof(custom_vote_info));
-
- commands = 0;
-
- trap_FS_Read(&buffer,sizeof(buffer),file);
-
- pointer = buffer;
-
- while ( commands < MAX_CUSTOM_VOTES ) {
- token = COM_Parse( &pointer );
- if ( !token[0] ) {
- break;
- }
-
- if ( !strcmp( token, "votecommand" ) ) {
- token = COM_Parse( &pointer );
- Q_strcat(custom_vote_info,sizeof(custom_vote_info),va("%s ",token));
- commands++;
- }
- }
-
- trap_FS_FCloseFile(file);
-
- return commands;
-}
-/*
-==================
-getCustomVote
- *Returns a custom vote. This will go beyond MAX_CUSTOM_VOTES.
-==================
- */
-t_customvote getCustomVote(char* votecommand) {
- t_customvote result;
- fileHandle_t file;
- char buffer[4*1024];
- char *token,*pointer;
- char key[MAX_TOKEN_CHARS];
-
- trap_FS_FOpenFile("votecustom.cfg",&file,FS_READ);
-
- if(!file) {
- memset(&result,0,sizeof(result));
- return result;
- }
-
- memset(&buffer,0,sizeof(buffer));
-
- trap_FS_Read(&buffer,sizeof(buffer),file);
-
- pointer = buffer;
-
- while ( qtrue ) {
- token = COM_Parse( &pointer );
- if ( !token[0] ) {
- break;
- }
-
- if ( strcmp( token, "{" ) ) {
- Com_Printf( "Missing { in votecustom.cfg\n" );
- break;
- }
-
- memset(&result,0,sizeof(result));
-
- while ( 1 ) {
- token = COM_ParseExt( &pointer, qtrue );
- if ( !token[0] ) {
- Com_Printf( "Unexpected end of customvote.cfg\n" );
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- Q_strncpyz( key, token, sizeof( key ) );
-
- token = COM_ParseExt( &pointer, qfalse );
- if ( !token[0] ) {
- Com_Printf("Invalid/missing argument to %s in customvote.cfg\n",key);
- }
- if(!Q_stricmp(key,"votecommand")) {
- Q_strncpyz(result.votename,token,sizeof(result.votename));
- } else if(!Q_stricmp(key,"displayname")) {
- Q_strncpyz(result.displayname,token,sizeof(result.displayname));
- } else if(!Q_stricmp(key,"command")) {
- Q_strncpyz(result.command,token,sizeof(result.command));
- } else {
- Com_Printf("Unknown key in customvote.cfg: %s\n",key);
- }
-
- }
-
- if(!Q_stricmp(result.votename,votecommand)) {
- return result;
- }
- }
-
- //Nothing was found
- memset(&result,0,sizeof(result));
- return result;
-}
-
-/*
-==================
-CheckVote
-==================
-*/
-void CheckVote( void ) {
- if ( level.voteExecuteTime && level.voteExecuteTime < level.time ) {
- level.voteExecuteTime = 0;
- trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.voteString ) );
- }
- if ( !level.voteTime ) {
- return;
- }
- if ( level.time - level.voteTime >= VOTE_TIME ) {
- //Let pass if there was at least twice as many for as against
- if ( level.voteYes > level.voteNo*2 ) {
- trap_SendServerCommand( -1, "print \"Vote passed. At least 2 of 3 voted yes\n\"" );
- level.voteExecuteTime = level.time + 3000;
- } else
- //Let pass if there is more yes than no and at least 2 yes votes and at least 30% yes of all on the server
- if ( level.voteYes > level.voteNo && level.voteYes >= 2 && (level.voteYes*10)>=(level.numVotingClients*3) ) {
- trap_SendServerCommand( -1, "print \"Vote passed.\n\"" );
- level.voteExecuteTime = level.time + 3000;
- } else
- trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
- } else {
- // ATVI Q3 1.32 Patch #9, WNF
- if ( level.voteYes > (level.numVotingClients)/2 ) {
- // execute the command, then remove the vote
- trap_SendServerCommand( -1, "print \"Vote passed.\n\"" );
- level.voteExecuteTime = level.time + 3000;
- } else if ( level.voteNo >= (level.numVotingClients)/2 ) {
- // same behavior as a timeout
- trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
- } else {
- // still waiting for a majority
- return;
- }
- }
- level.voteTime = 0;
- trap_SetConfigstring( CS_VOTE_TIME, "" );
-
-}
-
-/*
-==================
-CountVotes
-
- Iterates through all the clients and counts the votes
-==================
-*/
-void CountVotes( void ) {
- int i;
- int yes=0,no=0;
-
- level.numVotingClients=0;
-
- for ( i = 0 ; i < level.maxclients ; i++ ) {
- if ( level.clients[ i ].pers.connected != CON_CONNECTED )
- continue; //Client was not connected
-
- if (level.clients[i].sess.sessionTeam == TEAM_SPECTATOR)
- continue; //Don't count spectators
-
- if ( g_entities[i].r.svFlags & SVF_BOT )
- continue; //Is a bot
-
- //The client can vote
- level.numVotingClients++;
-
- //Did the client vote yes?
- if(level.clients[i].vote>0)
- yes++;
-
- //Did the client vote no?
- if(level.clients[i].vote<0)
- no++;
- }
-
- //See if anything has changed
- if(level.voteYes != yes) {
- level.voteYes = yes;
- trap_SetConfigstring( CS_VOTE_YES, va("%i", level.voteYes ) );
- }
-
- if(level.voteNo != no) {
- level.voteNo = no;
- trap_SetConfigstring( CS_VOTE_NO, va("%i", level.voteNo ) );
- }
-}
-
diff --git a/game/code/game/g_weapon.c b/game/code/game/g_weapon.c
deleted file mode 100644
index 3dd27be..0000000
--- a/game/code/game/g_weapon.c
+++ /dev/null
@@ -1,1223 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// g_weapon.c
-// perform the server side effects of a weapon firing
-
-#include "g_local.h"
-
-static float s_quadFactor;
-static vec3_t forward, right, up;
-static vec3_t muzzle;
-
-#define NUM_NAILSHOTS 15
-
-/*
-================
-G_BounceProjectile
-================
-*/
-void G_BounceProjectile( vec3_t start, vec3_t impact, vec3_t dir, vec3_t endout ) {
- vec3_t v, newv;
- float dot;
-
- VectorSubtract( impact, start, v );
- dot = DotProduct( v, dir );
- VectorMA( v, -2*dot, dir, newv );
-
- VectorNormalize(newv);
- VectorMA(impact, 8192, newv, endout);
-}
-
-
-/*
-======================================================================
-
-GAUNTLET
-
-======================================================================
-*/
-
-void Weapon_Gauntlet( gentity_t *ent ) {
-
-}
-
-/*
-===============
-CheckGauntletAttack
-===============
-*/
-qboolean CheckGauntletAttack( gentity_t *ent ) {
- trace_t tr;
- vec3_t end;
- gentity_t *tent;
- gentity_t *traceEnt;
- int damage;
-
- // set aiming directions
- AngleVectors (ent->client->ps.viewangles, forward, right, up);
-
- CalcMuzzlePoint ( ent, forward, right, up, muzzle );
-
- VectorMA (muzzle, 32, forward, end);
-
- trap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT);
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- return qfalse;
- }
-
- traceEnt = &g_entities[ tr.entityNum ];
-
- // send blood impact
- if ( traceEnt->takedamage && traceEnt->client ) {
- tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
- tent->s.otherEntityNum = traceEnt->s.number;
- tent->s.eventParm = DirToByte( tr.plane.normal );
- tent->s.weapon = ent->s.weapon;
- }
-
- if ( !traceEnt->takedamage) {
- return qfalse;
- }
-
- if (ent->client->ps.powerups[PW_QUAD] ) {
- G_AddEvent( ent, EV_POWERUP_QUAD, 0 );
- s_quadFactor = g_quadfactor.value;
- } else {
- s_quadFactor = 1;
- }
- if( ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->giTag == PW_DOUBLER ) {
- s_quadFactor *= 2;
- }
-
- if(g_instantgib.integer)
- damage = 500; //High damage in instant gib (normally enough to gib)
- else
- damage = 50 * s_quadFactor;
- G_Damage( traceEnt, ent, ent, forward, tr.endpos,
- damage, 0, MOD_GAUNTLET );
-
- return qtrue;
-}
-
-
-/*
-======================================================================
-
-MACHINEGUN
-
-======================================================================
-*/
-
-/*
-======================
-SnapVectorTowards
-
-Round a vector to integers for more efficient network
-transmission, but make sure that it rounds towards a given point
-rather than blindly truncating. This prevents it from truncating
-into a wall.
-======================
-*/
-//unlagged - attack prediction #3
-// moved to q_shared.c
-/*
-void SnapVectorTowards( vec3_t v, vec3_t to ) {
- int i;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( to[i] <= v[i] ) {
- v[i] = (int)v[i];
- } else {
- v[i] = (int)v[i] + 1;
- }
- }
-}
-*/
-//unlagged - attack prediction #3
-
-//unlagged - attack prediction #3
-// moved from g_weapon.c
-/*
-======================
-SnapVectorTowards
-
-Round a vector to integers for more efficient network
-transmission, but make sure that it rounds towards a given point
-rather than blindly truncating. This prevents it from truncating
-into a wall.
-======================
-*/
-void SnapVectorTowards( vec3_t v, vec3_t to ) {
- int i;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( to[i] <= v[i] ) {
- v[i] = (int)v[i];
- } else {
- v[i] = (int)v[i] + 1;
- }
- }
-}
-//unlagged - attack prediction #3
-
-#define CHAINGUN_SPREAD 600.0
-#define MACHINEGUN_SPREAD 200
-#define MACHINEGUN_DAMAGE 7
-#define MACHINEGUN_TEAM_DAMAGE 5 // wimpier MG in teamplay
-
-void Bullet_Fire (gentity_t *ent, float spread, int damage ) {
- trace_t tr;
- vec3_t end;
- vec3_t impactpoint, bouncedir;
- float r;
- float u;
- gentity_t *tent;
- gentity_t *traceEnt;
- int i, passent;
-
-//unlagged - attack prediction #2
- // we have to use something now that the client knows in advance
- int seed = ent->client->attackTime % 256;
-//unlagged - attack prediction #2
-
- damage *= s_quadFactor;
-
-//unlagged - attack prediction #2
- // this has to match what's on the client
-/*
- r = random() * M_PI * 2.0f;
- u = sin(r) * crandom() * spread * 16;
- r = cos(r) * crandom() * spread * 16;
-*/
- r = Q_random(&seed) * M_PI * 2.0f;
- u = sin(r) * Q_crandom(&seed) * spread * 16;
- r = cos(r) * Q_crandom(&seed) * spread * 16;
-//unlagged - attack prediction #2
-
- VectorMA (muzzle, 8192*16, forward, end);
- VectorMA (end, r, right, end);
- VectorMA (end, u, up, end);
-
- passent = ent->s.number;
- for (i = 0; i < 10; i++) {
-
-//unlagged - backward reconciliation #2
- // backward-reconcile the other clients
- G_DoTimeShiftFor( ent );
-//unlagged - backward reconciliation #2
-
- trap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT);
-
-//unlagged - backward reconciliation #2
- // put them back
- G_UndoTimeShiftFor( ent );
-//unlagged - backward reconciliation #2
-
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- return;
- }
-
- traceEnt = &g_entities[ tr.entityNum ];
-
- // snap the endpos to integers, but nudged towards the line
- SnapVectorTowards( tr.endpos, muzzle );
-
- // send bullet impact
- if ( traceEnt->takedamage && traceEnt->client ) {
- tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
- tent->s.eventParm = traceEnt->s.number;
-//unlagged - attack prediction #2
- // we need the client number to determine whether or not to
- // suppress this event
- tent->s.clientNum = ent->s.clientNum;
-//unlagged - attack prediction #2
- if( LogAccuracyHit( traceEnt, ent ) ) {
- ent->client->accuracy_hits++;
- }
- } else {
- tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL );
- tent->s.eventParm = DirToByte( tr.plane.normal );
-//unlagged - attack prediction #2
- // we need the client number to determine whether or not to
- // suppress this event
- tent->s.clientNum = ent->s.clientNum;
-//unlagged - attack prediction #2
- }
- tent->s.otherEntityNum = ent->s.number;
-
- if ( traceEnt->takedamage) {
- if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
- if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
- G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
- VectorCopy( impactpoint, muzzle );
- // the player can hit him/herself with the bounced rail
- passent = ENTITYNUM_NONE;
- }
- else {
- VectorCopy( tr.endpos, muzzle );
- passent = traceEnt->s.number;
- }
- continue;
- }
- else {
- if(spread == CHAINGUN_SPREAD)
- {
- G_Damage( traceEnt, ent, ent, forward, tr.endpos,
- damage, 0, MOD_CHAINGUN);
- }
- else
- {
- G_Damage( traceEnt, ent, ent, forward, tr.endpos,
- damage, 0, MOD_MACHINEGUN);
- }
- }
- }
- break;
- }
-}
-
-
-/*
-======================================================================
-
-BFG
-
-======================================================================
-*/
-
-void BFG_Fire ( gentity_t *ent ) {
- gentity_t *m;
-
- m = fire_bfg (ent, muzzle, forward);
- m->damage *= s_quadFactor;
- m->splashDamage *= s_quadFactor;
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
-}
-
-
-/*
-======================================================================
-
-SHOTGUN
-
-======================================================================
-*/
-
-// DEFAULT_SHOTGUN_SPREAD and DEFAULT_SHOTGUN_COUNT are in bg_public.h, because
-// client predicts same spreads
-#define DEFAULT_SHOTGUN_DAMAGE 10
-
-qboolean ShotgunPellet( vec3_t start, vec3_t end, gentity_t *ent ) {
- trace_t tr;
- int damage, i, passent;
- gentity_t *traceEnt;
- vec3_t impactpoint, bouncedir;
- vec3_t tr_start, tr_end;
-
- passent = ent->s.number;
- VectorCopy( start, tr_start );
- VectorCopy( end, tr_end );
- for (i = 0; i < 10; i++) {
- trap_Trace (&tr, tr_start, NULL, NULL, tr_end, passent, MASK_SHOT);
- traceEnt = &g_entities[ tr.entityNum ];
-
- // send bullet impact
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- return qfalse;
- }
-
- if ( traceEnt->takedamage) {
- damage = DEFAULT_SHOTGUN_DAMAGE * s_quadFactor;
- if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
- if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
- G_BounceProjectile( tr_start, impactpoint, bouncedir, tr_end );
- VectorCopy( impactpoint, tr_start );
- // the player can hit him/herself with the bounced rail
- passent = ENTITYNUM_NONE;
- }
- else {
- VectorCopy( tr.endpos, tr_start );
- passent = traceEnt->s.number;
- }
- continue;
- }
- else {
- G_Damage( traceEnt, ent, ent, forward, tr.endpos,
- damage, 0, MOD_SHOTGUN);
- if( LogAccuracyHit( traceEnt, ent ) ) {
- return qtrue;
- }
- }
- }
- return qfalse;
- }
- return qfalse;
-}
-
-// this should match CG_ShotgunPattern
-void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {
- int i;
- float r, u;
- vec3_t end;
- vec3_t forward, right, up;
- int oldScore;
- qboolean hitClient = qfalse;
-
-//unlagged - attack prediction #2
- // use this for testing
- //Com_Printf( "Server seed: %d\n", seed );
-//unlagged - attack prediction #2
-
- // derive the right and up vectors from the forward vector, because
- // the client won't have any other information
- VectorNormalize2( origin2, forward );
- PerpendicularVector( right, forward );
- CrossProduct( forward, right, up );
-
- oldScore = ent->client->ps.persistant[PERS_SCORE];
-
-//unlagged - backward reconciliation #2
- // backward-reconcile the other clients
- G_DoTimeShiftFor( ent );
-//unlagged - backward reconciliation #2
-
- // generate the "random" spread pattern
- for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {
- r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
- u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
- VectorMA( origin, 8192 * 16, forward, end);
- VectorMA (end, r, right, end);
- VectorMA (end, u, up, end);
- if( ShotgunPellet( origin, end, ent ) && !hitClient ) {
- hitClient = qtrue;
- ent->client->accuracy_hits++;
- }
- }
-
-//unlagged - backward reconciliation #2
- // put them back
- G_UndoTimeShiftFor( ent );
-//unlagged - backward reconciliation #2
-}
-
-
-void weapon_supershotgun_fire (gentity_t *ent) {
- gentity_t *tent;
-
- // send shotgun blast
- tent = G_TempEntity( muzzle, EV_SHOTGUN );
- VectorScale( forward, 4096, tent->s.origin2 );
- SnapVector( tent->s.origin2 );
-//Sago: This sound like a bad idea...
-//unlagged - attack prediction #2
- // this has to be something the client can predict now
- //tent->s.eventParm = rand() & 255; // seed for spread pattern
- tent->s.eventParm = ent->client->attackTime % 256; // seed for spread pattern
-//unlagged - attack prediction #2
- tent->s.otherEntityNum = ent->s.number;
-
- ShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent );
-}
-
-
-/*
-======================================================================
-
-GRENADE LAUNCHER
-
-======================================================================
-*/
-
-void weapon_grenadelauncher_fire (gentity_t *ent) {
- gentity_t *m;
-
- // extra vertical velocity
- forward[2] += 0.2f;
- VectorNormalize( forward );
-
- m = fire_grenade (ent, muzzle, forward);
- m->damage *= s_quadFactor;
- m->splashDamage *= s_quadFactor;
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
-}
-
-/*
-======================================================================
-
-ROCKET
-
-======================================================================
-*/
-
-void Weapon_RocketLauncher_Fire (gentity_t *ent) {
- gentity_t *m;
-
- m = fire_rocket (ent, muzzle, forward);
- m->damage *= s_quadFactor;
- m->splashDamage *= s_quadFactor;
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
-}
-
-
-/*
-======================================================================
-
-PLASMA GUN
-
-======================================================================
-*/
-
-void Weapon_Plasmagun_Fire (gentity_t *ent) {
- gentity_t *m;
-
- m = fire_plasma (ent, muzzle, forward);
- m->damage *= s_quadFactor;
- m->splashDamage *= s_quadFactor;
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
-}
-
-/*
-======================================================================
-
-RAILGUN
-
-======================================================================
-*/
-
-
-/*
-=================
-weapon_railgun_fire
-=================
-*/
-#define MAX_RAIL_HITS 4
-void weapon_railgun_fire (gentity_t *ent) {
- vec3_t end;
- vec3_t impactpoint, bouncedir;
- trace_t trace;
- gentity_t *tent;
- gentity_t *traceEnt;
- int damage;
- int i;
- int hits;
- int unlinked;
- int passent;
- gentity_t *unlinkedEntities[MAX_RAIL_HITS];
-
- damage = 100 * s_quadFactor;
- if(g_instantgib.integer)
- damage = 800;
-
- VectorMA (muzzle, 8192, forward, end);
-
-//unlagged - backward reconciliation #2
- // backward-reconcile the other clients
- G_DoTimeShiftFor( ent );
-//unlagged - backward reconciliation #2
-
- // trace only against the solids, so the railgun will go through people
- unlinked = 0;
- hits = 0;
- passent = ent->s.number;
- do {
- trap_Trace (&trace, muzzle, NULL, NULL, end, passent, MASK_SHOT );
- if ( trace.entityNum >= ENTITYNUM_MAX_NORMAL ) {
- break;
- }
- traceEnt = &g_entities[ trace.entityNum ];
- if ( traceEnt->takedamage ) {
- if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
- if ( G_InvulnerabilityEffect( traceEnt, forward, trace.endpos, impactpoint, bouncedir ) ) {
- G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
- // snap the endpos to integers to save net bandwidth, but nudged towards the line
- SnapVectorTowards( trace.endpos, muzzle );
- // send railgun beam effect
- tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );
- // set player number for custom colors on the railtrail
- tent->s.clientNum = ent->s.clientNum;
- VectorCopy( muzzle, tent->s.origin2 );
- // move origin a bit to come closer to the drawn gun muzzle
- VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
- VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
- tent->s.eventParm = 255; // don't make the explosion at the end
- //
- VectorCopy( impactpoint, muzzle );
- // the player can hit him/herself with the bounced rail
- passent = ENTITYNUM_NONE;
- }
- }
- else {
- if( LogAccuracyHit( traceEnt, ent ) ) {
- hits++;
- }
- G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
- }
- }
- if ( trace.contents & CONTENTS_SOLID ) {
- break; // we hit something solid enough to stop the beam
- }
- // unlink this entity, so the next trace will go past it
- trap_UnlinkEntity( traceEnt );
- unlinkedEntities[unlinked] = traceEnt;
- unlinked++;
- } while ( unlinked < MAX_RAIL_HITS );
-
-//unlagged - backward reconciliation #2
- // put them back
- G_UndoTimeShiftFor( ent );
-//unlagged - backward reconciliation #2
-
- // link back in any entities we unlinked
- for ( i = 0 ; i < unlinked ; i++ ) {
- trap_LinkEntity( unlinkedEntities[i] );
- }
-
- // the final trace endpos will be the terminal point of the rail trail
-
- // snap the endpos to integers to save net bandwidth, but nudged towards the line
- SnapVectorTowards( trace.endpos, muzzle );
-
- // send railgun beam effect
- tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );
-
- // set player number for custom colors on the railtrail
- tent->s.clientNum = ent->s.clientNum;
-
- VectorCopy( muzzle, tent->s.origin2 );
- // move origin a bit to come closer to the drawn gun muzzle
- VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
- VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
-
- // no explosion at end if SURF_NOIMPACT, but still make the trail
- if ( trace.surfaceFlags & SURF_NOIMPACT ) {
- tent->s.eventParm = 255; // don't make the explosion at the end
- } else {
- tent->s.eventParm = DirToByte( trace.plane.normal );
- }
- tent->s.clientNum = ent->s.clientNum;
-
- // give the shooter a reward sound if they have made two railgun hits in a row
- if ( hits == 0 ) {
- // complete miss
- ent->client->accurateCount = 0;
- } else {
- // check for "impressive" reward sound
- ent->client->accurateCount += hits;
- if ( ent->client->accurateCount >= 2 ) {
- ent->client->accurateCount -= 2;
- ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
- G_LogPrintf( "Award: %i %i: %s gained the %s award!\n", ent->client->ps.clientNum, 2, ent->client->pers.netname, "IMPRESSIVE" );
- if(!level.hadBots) //There has not been any bots
- ChallengeMessage(ent,AWARD_IMPRESSIVE);
- // add the sprite over the player's head
- ent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
- ent->client->ps.eFlags |= EF_AWARD_IMPRESSIVE;
- ent->client->rewardTime = level.time + REWARD_SPRITE_TIME;
- }
- ent->client->accuracy_hits++;
- }
-
-}
-
-
-/*
-======================================================================
-
-GRAPPLING HOOK
-
-======================================================================
-*/
-
-void Weapon_GrapplingHook_Fire (gentity_t *ent)
-{
- if (!ent->client->fireHeld && !ent->client->hook)
- fire_grapple (ent, muzzle, forward);
-
- ent->client->fireHeld = qtrue;
-}
-
-void Weapon_HookFree (gentity_t *ent)
-{
- ent->parent->client->hook = NULL;
- ent->parent->client->ps.pm_flags &= ~PMF_GRAPPLE_PULL;
- G_FreeEntity( ent );
-}
-
-void Weapon_HookThink (gentity_t *ent)
-{
- if (ent->enemy) {
- vec3_t v, oldorigin;
-
- VectorCopy(ent->r.currentOrigin, oldorigin);
- v[0] = ent->enemy->r.currentOrigin[0] + (ent->enemy->r.mins[0] + ent->enemy->r.maxs[0]) * 0.5;
- v[1] = ent->enemy->r.currentOrigin[1] + (ent->enemy->r.mins[1] + ent->enemy->r.maxs[1]) * 0.5;
- v[2] = ent->enemy->r.currentOrigin[2] + (ent->enemy->r.mins[2] + ent->enemy->r.maxs[2]) * 0.5;
- SnapVectorTowards( v, oldorigin ); // save net bandwidth
-
- G_SetOrigin( ent, v );
- }
-
- VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);
-}
-
-/*
-======================================================================
-
-LIGHTNING GUN
-
-======================================================================
-*/
-
-void Weapon_LightningFire( gentity_t *ent ) {
- trace_t tr;
- vec3_t end;
- vec3_t impactpoint, bouncedir;
- gentity_t *traceEnt, *tent;
- int damage, i, passent;
-
- damage = 8 * s_quadFactor;
-
- passent = ent->s.number;
- for (i = 0; i < 10; i++) {
- VectorMA( muzzle, LIGHTNING_RANGE, forward, end );
-
-//Sago: I'm not sure this should recieve backward reconciliation. It is not a real instant hit weapon, it can normally be dogded
-//unlagged - backward reconciliation #2
- // backward-reconcile the other clients
- G_DoTimeShiftFor( ent );
-//unlagged - backward reconciliation #2
-
- trap_Trace( &tr, muzzle, NULL, NULL, end, passent, MASK_SHOT );
-
-//unlagged - backward reconciliation #2
- // put them back
- G_UndoTimeShiftFor( ent );
-//unlagged - backward reconciliation #2
-
- // if not the first trace (the lightning bounced of an invulnerability sphere)
- if (i) {
- // add bounced off lightning bolt temp entity
- // the first lightning bolt is a cgame only visual
- //
- tent = G_TempEntity( muzzle, EV_LIGHTNINGBOLT );
- VectorCopy( tr.endpos, end );
- SnapVector( end );
- VectorCopy( end, tent->s.origin2 );
- }
- if ( tr.entityNum == ENTITYNUM_NONE ) {
- return;
- }
-
- traceEnt = &g_entities[ tr.entityNum ];
-
- if ( traceEnt->takedamage) {
- if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
- if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
- G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
- VectorCopy( impactpoint, muzzle );
- VectorSubtract( end, impactpoint, forward );
- VectorNormalize(forward);
- // the player can hit him/herself with the bounced lightning
- passent = ENTITYNUM_NONE;
- }
- else {
- VectorCopy( tr.endpos, muzzle );
- passent = traceEnt->s.number;
- }
- continue;
- }
- else {
- G_Damage( traceEnt, ent, ent, forward, tr.endpos,
- damage, 0, MOD_LIGHTNING);
- }
- }
-
- if ( traceEnt->takedamage && traceEnt->client ) {
- tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
- tent->s.otherEntityNum = traceEnt->s.number;
- tent->s.eventParm = DirToByte( tr.plane.normal );
- tent->s.weapon = ent->s.weapon;
- if( LogAccuracyHit( traceEnt, ent ) ) {
- ent->client->accuracy_hits++;
- }
- } else if ( !( tr.surfaceFlags & SURF_NOIMPACT ) ) {
- tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS );
- tent->s.eventParm = DirToByte( tr.plane.normal );
- }
-
- break;
- }
-}
-
-/*
-======================================================================
-
-NAILGUN
-
-======================================================================
-*/
-
-void Weapon_Nailgun_Fire (gentity_t *ent) {
- gentity_t *m;
- int count;
-
- for( count = 0; count < NUM_NAILSHOTS; count++ ) {
- m = fire_nail (ent, muzzle, forward, right, up );
- m->damage *= s_quadFactor;
- m->splashDamage *= s_quadFactor;
- }
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
-}
-
-
-/*
-======================================================================
-
-PROXIMITY MINE LAUNCHER
-
-======================================================================
-*/
-
-void weapon_proxlauncher_fire (gentity_t *ent) {
- gentity_t *m;
-
- // extra vertical velocity
- forward[2] += 0.2f;
- VectorNormalize( forward );
-
- m = fire_prox (ent, muzzle, forward);
- m->damage *= s_quadFactor;
- m->splashDamage *= s_quadFactor;
-
-// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
-}
-
-
-//======================================================================
-
-
-/*
-===============
-LogAccuracyHit
-===============
-*/
-qboolean LogAccuracyHit( gentity_t *target, gentity_t *attacker ) {
- if( !target->takedamage ) {
- return qfalse;
- }
-
- if ( target == attacker ) {
- return qfalse;
- }
-
- if( !target->client ) {
- return qfalse;
- }
-
- if( !attacker->client ) {
- return qfalse;
- }
-
- if( target->client->ps.stats[STAT_HEALTH] <= 0 ) {
- return qfalse;
- }
-
- if ( OnSameTeam( target, attacker ) ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-===============
-CalcMuzzlePoint
-
-set muzzle location relative to pivoting eye
-===============
-*/
-void CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {
- VectorCopy( ent->s.pos.trBase, muzzlePoint );
- muzzlePoint[2] += ent->client->ps.viewheight;
- VectorMA( muzzlePoint, 14, forward, muzzlePoint );
- // snap to integer coordinates for more efficient network bandwidth usage
- SnapVector( muzzlePoint );
-}
-
-/*
-===============
-CalcMuzzlePointOrigin
-
-set muzzle location relative to pivoting eye
-===============
-*/
-void CalcMuzzlePointOrigin ( gentity_t *ent, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {
- VectorCopy( ent->s.pos.trBase, muzzlePoint );
- muzzlePoint[2] += ent->client->ps.viewheight;
- VectorMA( muzzlePoint, 14, forward, muzzlePoint );
- // snap to integer coordinates for more efficient network bandwidth usage
- SnapVector( muzzlePoint );
-}
-
-
-
-/*
-===============
-FireWeapon
-===============
-*/
-void FireWeapon( gentity_t *ent ) {
- //Make people drop out of follow mode (this should be moved, so people can change betwean players.)
- if (ent->client->sess.spectatorState == SPECTATOR_FOLLOW) {
- StopFollowing( ent );
- return;
- }
-
- if (ent->client->ps.powerups[PW_QUAD] ) {
- s_quadFactor = g_quadfactor.value;
- } else {
- s_quadFactor = 1;
- }
- if( ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->giTag == PW_DOUBLER ) {
- s_quadFactor *= 2;
- }
-
- // track shots taken for accuracy tracking. Grapple is not a weapon and gauntet is just not tracked
- if( ent->s.weapon != WP_GRAPPLING_HOOK && ent->s.weapon != WP_GAUNTLET ) {
- if( ent->s.weapon == WP_NAILGUN ) {
- ent->client->accuracy_shots += NUM_NAILSHOTS;
- } else {
- ent->client->accuracy_shots++;
- }
- }
-
- // set aiming directions
- AngleVectors (ent->client->ps.viewangles, forward, right, up);
-
- CalcMuzzlePointOrigin ( ent, ent->client->oldOrigin, forward, right, up, muzzle );
-
- // fire the specific weapon
- switch( ent->s.weapon ) {
- case WP_GAUNTLET:
- Weapon_Gauntlet( ent );
- break;
- case WP_LIGHTNING:
- Weapon_LightningFire( ent );
- break;
- case WP_SHOTGUN:
- weapon_supershotgun_fire( ent );
- break;
- case WP_MACHINEGUN:
- if ( g_gametype.integer != GT_TEAM ) {
- Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_DAMAGE );
- } else {
- Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_TEAM_DAMAGE );
- }
- break;
- case WP_GRENADE_LAUNCHER:
- weapon_grenadelauncher_fire( ent );
- break;
- case WP_ROCKET_LAUNCHER:
- Weapon_RocketLauncher_Fire( ent );
- break;
- case WP_PLASMAGUN:
- Weapon_Plasmagun_Fire( ent );
- break;
- case WP_RAILGUN:
- weapon_railgun_fire( ent );
- break;
- case WP_BFG:
- BFG_Fire( ent );
- break;
- case WP_GRAPPLING_HOOK:
- Weapon_GrapplingHook_Fire( ent );
- break;
- case WP_NAILGUN:
- Weapon_Nailgun_Fire( ent );
- break;
- case WP_PROX_LAUNCHER:
- weapon_proxlauncher_fire( ent );
- break;
- case WP_CHAINGUN:
- Bullet_Fire( ent, CHAINGUN_SPREAD, MACHINEGUN_DAMAGE );
- break;
- default:
-// FIXME G_Error( "Bad ent->s.weapon" );
- break;
- }
-}
-
-
-/*
-===============
-KamikazeRadiusDamage
-===============
-*/
-static void KamikazeRadiusDamage( vec3_t origin, gentity_t *attacker, float damage, float radius ) {
- float dist;
- gentity_t *ent;
- int entityList[MAX_GENTITIES];
- int numListedEntities;
- vec3_t mins, maxs;
- vec3_t v;
- vec3_t dir;
- int i, e;
-
- if ( radius < 1 ) {
- radius = 1;
- }
-
- for ( i = 0 ; i < 3 ; i++ ) {
- mins[i] = origin[i] - radius;
- maxs[i] = origin[i] + radius;
- }
-
- numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
-
- for ( e = 0 ; e < numListedEntities ; e++ ) {
- ent = &g_entities[entityList[ e ]];
-
- if (!ent->takedamage) {
- continue;
- }
-
- // dont hit things we have already hit
- if( ent->kamikazeTime > level.time ) {
- continue;
- }
-
- // find the distance from the edge of the bounding box
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( origin[i] < ent->r.absmin[i] ) {
- v[i] = ent->r.absmin[i] - origin[i];
- } else if ( origin[i] > ent->r.absmax[i] ) {
- v[i] = origin[i] - ent->r.absmax[i];
- } else {
- v[i] = 0;
- }
- }
-
- dist = VectorLength( v );
- if ( dist >= radius ) {
- continue;
- }
-
-// if( CanDamage (ent, origin) ) {
- VectorSubtract (ent->r.currentOrigin, origin, dir);
- // push the center of mass higher than the origin so players
- // get knocked into the air more
- dir[2] += 24;
- G_Damage( ent, NULL, attacker, dir, origin, damage, DAMAGE_RADIUS|DAMAGE_NO_TEAM_PROTECTION, MOD_KAMIKAZE );
- ent->kamikazeTime = level.time + 3000;
-// }
- }
-}
-
-/*
-===============
-KamikazeShockWave
-===============
-*/
-static void KamikazeShockWave( vec3_t origin, gentity_t *attacker, float damage, float push, float radius ) {
- float dist;
- gentity_t *ent;
- int entityList[MAX_GENTITIES];
- int numListedEntities;
- vec3_t mins, maxs;
- vec3_t v;
- vec3_t dir;
- int i, e;
-
- if ( radius < 1 )
- radius = 1;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- mins[i] = origin[i] - radius;
- maxs[i] = origin[i] + radius;
- }
-
- numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
-
- for ( e = 0 ; e < numListedEntities ; e++ ) {
- ent = &g_entities[entityList[ e ]];
-
- // dont hit things we have already hit
- if( ent->kamikazeShockTime > level.time ) {
- continue;
- }
-
- // find the distance from the edge of the bounding box
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( origin[i] < ent->r.absmin[i] ) {
- v[i] = ent->r.absmin[i] - origin[i];
- } else if ( origin[i] > ent->r.absmax[i] ) {
- v[i] = origin[i] - ent->r.absmax[i];
- } else {
- v[i] = 0;
- }
- }
-
- dist = VectorLength( v );
- if ( dist >= radius ) {
- continue;
- }
-
-// if( CanDamage (ent, origin) ) {
- VectorSubtract (ent->r.currentOrigin, origin, dir);
- dir[2] += 24;
- G_Damage( ent, NULL, attacker, dir, origin, damage, DAMAGE_RADIUS|DAMAGE_NO_TEAM_PROTECTION, MOD_KAMIKAZE );
- //
- dir[2] = 0;
- VectorNormalize(dir);
- if ( ent->client ) {
- ent->client->ps.velocity[0] = dir[0] * push;
- ent->client->ps.velocity[1] = dir[1] * push;
- ent->client->ps.velocity[2] = 100;
- }
- ent->kamikazeShockTime = level.time + 3000;
-// }
- }
-}
-
-/*
-===============
-KamikazeDamage
-===============
-*/
-static void KamikazeDamage( gentity_t *self ) {
- int i;
- float t;
- gentity_t *ent;
- vec3_t newangles;
-
- self->count += 100;
-
- if (self->count >= KAMI_SHOCKWAVE_STARTTIME) {
- // shockwave push back
- t = self->count - KAMI_SHOCKWAVE_STARTTIME;
- KamikazeShockWave(self->s.pos.trBase, self->activator, 25, 400, (int) (float) t * KAMI_SHOCKWAVE_MAXRADIUS / (KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVE_STARTTIME) );
- }
- //
- if (self->count >= KAMI_EXPLODE_STARTTIME) {
- // do our damage
- t = self->count - KAMI_EXPLODE_STARTTIME;
- KamikazeRadiusDamage( self->s.pos.trBase, self->activator, 400, (int) (float) t * KAMI_BOOMSPHERE_MAXRADIUS / (KAMI_IMPLODE_STARTTIME - KAMI_EXPLODE_STARTTIME) );
- }
-
- // either cycle or kill self
- if( self->count >= KAMI_SHOCKWAVE_ENDTIME ) {
- G_FreeEntity( self );
- return;
- }
- self->nextthink = level.time + 100;
-
- // add earth quake effect
- newangles[0] = crandom() * 2;
- newangles[1] = crandom() * 2;
- newangles[2] = 0;
- for (i = 0; i < MAX_CLIENTS; i++)
- {
- ent = &g_entities[i];
- if (!ent->inuse)
- continue;
- if (!ent->client)
- continue;
-
- if (ent->client->ps.groundEntityNum != ENTITYNUM_NONE) {
- ent->client->ps.velocity[0] += crandom() * 120;
- ent->client->ps.velocity[1] += crandom() * 120;
- ent->client->ps.velocity[2] = 30 + random() * 25;
- }
-
- ent->client->ps.delta_angles[0] += ANGLE2SHORT(newangles[0] - self->movedir[0]);
- ent->client->ps.delta_angles[1] += ANGLE2SHORT(newangles[1] - self->movedir[1]);
- ent->client->ps.delta_angles[2] += ANGLE2SHORT(newangles[2] - self->movedir[2]);
- }
- VectorCopy(newangles, self->movedir);
-}
-
-/*
-===============
-G_StartKamikaze
-===============
-*/
-void G_StartKamikaze( gentity_t *ent ) {
- gentity_t *explosion;
- gentity_t *te;
- vec3_t snapped;
-
- // start up the explosion logic
- explosion = G_Spawn();
-
- explosion->s.eType = ET_EVENTS + EV_KAMIKAZE;
- explosion->eventTime = level.time;
-
- if ( ent->client ) {
- VectorCopy( ent->s.pos.trBase, snapped );
- }
- else {
- VectorCopy( ent->activator->s.pos.trBase, snapped );
- }
- SnapVector( snapped ); // save network bandwidth
- G_SetOrigin( explosion, snapped );
-
- explosion->classname = "kamikaze";
- explosion->s.pos.trType = TR_STATIONARY;
-
- explosion->kamikazeTime = level.time;
-
- explosion->think = KamikazeDamage;
- explosion->nextthink = level.time + 100;
- explosion->count = 0;
- VectorClear(explosion->movedir);
-
- trap_LinkEntity( explosion );
-
- if (ent->client) {
- //
- explosion->activator = ent;
- //
- ent->s.eFlags &= ~EF_KAMIKAZE;
- // nuke the guy that used it
- G_Damage( ent, ent, ent, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_KAMIKAZE );
- }
- else {
- if ( !strcmp(ent->activator->classname, "bodyque") ) {
- explosion->activator = &g_entities[ent->activator->r.ownerNum];
- }
- else {
- explosion->activator = ent->activator;
- }
- }
-
- // play global sound at all clients
- te = G_TempEntity(snapped, EV_GLOBAL_TEAM_SOUND );
- te->r.svFlags |= SVF_BROADCAST;
- te->s.eventParm = GTS_KAMIKAZE;
-}
diff --git a/game/code/game/syn.h b/game/code/game/syn.h
deleted file mode 100644
index d63c576..0000000
--- a/game/code/game/syn.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#define CONTEXT_ALL 0xFFFFFFFF
-#define CONTEXT_NORMAL 1
-#define CONTEXT_NEARBYITEM 2
-#define CONTEXT_CTFREDTEAM 4
-#define CONTEXT_CTFBLUETEAM 8
-#define CONTEXT_REPLY 16
-#define CONTEXT_OBELISKREDTEAM 32
-#define CONTEXT_OBELISKBLUETEAM 64
-#define CONTEXT_HARVESTERREDTEAM 128
-#define CONTEXT_HARVESTERBLUETEAM 256
-
-#define CONTEXT_NAMES 1024
diff --git a/game/code/q3_ui/ui_atoms.c b/game/code/q3_ui/ui_atoms.c
deleted file mode 100644
index 0de6c62..0000000
--- a/game/code/q3_ui/ui_atoms.c
+++ /dev/null
@@ -1,1281 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/**********************************************************************
- UI_ATOMS.C
-
- User interface building blocks and support functions.
-**********************************************************************/
-#include "ui_local.h"
-
-uiStatic_t uis;
-qboolean m_entersound; // after a frame, so caching won't disrupt the sound
-
-void QDECL Com_Error( int level, const char *error, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, error);
- Q_vsnprintf (text, sizeof(text), error, argptr);
- va_end (argptr);
-
- trap_Error( va("%s", text) );
-}
-
-void QDECL Com_Printf( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- Q_vsnprintf (text, sizeof(text), msg, argptr);
- va_end (argptr);
-
- trap_Print( va("%s", text) );
-}
-
-/*
-=================
-UI_ClampCvar
-=================
-*/
-float UI_ClampCvar( float min, float max, float value )
-{
- if ( value < min ) return min;
- if ( value > max ) return max;
- return value;
-}
-
-/*
-=================
-UI_StartDemoLoop
-=================
-*/
-void UI_StartDemoLoop( void ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "d1\n" );
-}
-
-/*
-=================
-UI_PushMenu
-=================
-*/
-void UI_PushMenu( menuframework_s *menu )
-{
- int i;
- menucommon_s* item;
-
- // avoid stacking menus invoked by hotkeys
- for (i=0 ; i<uis.menusp ; i++)
- {
- if (uis.stack[i] == menu)
- {
- uis.menusp = i;
- break;
- }
- }
-
- if (i == uis.menusp)
- {
- if (uis.menusp >= MAX_MENUDEPTH)
- trap_Error("UI_PushMenu: menu stack overflow");
-
- uis.stack[uis.menusp++] = menu;
- }
-
- uis.activemenu = menu;
-
- // default cursor position
- menu->cursor = 0;
- menu->cursor_prev = 0;
-
- m_entersound = qtrue;
-
- trap_Key_SetCatcher( KEYCATCH_UI );
-
- // force first available item to have focus
- for (i=0; i<menu->nitems; i++)
- {
- item = (menucommon_s *)menu->items[i];
- if (!(item->flags & (QMF_GRAYED|QMF_MOUSEONLY|QMF_INACTIVE)))
- {
- menu->cursor_prev = -1;
- Menu_SetCursor( menu, i );
- break;
- }
- }
-
- uis.firstdraw = qtrue;
-}
-
-/*
-=================
-UI_PopMenu
-=================
-*/
-void UI_PopMenu (void)
-{
- trap_S_StartLocalSound( menu_out_sound, CHAN_LOCAL_SOUND );
-
- uis.menusp--;
-
- if (uis.menusp < 0)
- trap_Error ("UI_PopMenu: menu stack underflow");
-
- if (uis.menusp) {
- uis.activemenu = uis.stack[uis.menusp-1];
- uis.firstdraw = qtrue;
- }
- else {
- UI_ForceMenuOff ();
- }
-}
-
-void UI_ForceMenuOff (void)
-{
- uis.menusp = 0;
- uis.activemenu = NULL;
-
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
-}
-
-/*
-=================
-UI_LerpColor
-=================
-*/
-void UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)
-{
- int i;
-
- // lerp and clamp each component
- for (i=0; i<4; i++)
- {
- c[i] = a[i] + t*(b[i]-a[i]);
- if (c[i] < 0)
- c[i] = 0;
- else if (c[i] > 1.0)
- c[i] = 1.0;
- }
-}
-
-/*
-=================
-UI_DrawProportionalString2
-=================
-*/
-static int propMap[128][3] = {
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-
-{0, 0, PROP_SPACE_WIDTH}, // SPACE
-{11, 122, 7}, // !
-{154, 181, 14}, // "
-{55, 122, 17}, // #
-{79, 122, 18}, // $
-{101, 122, 23}, // %
-{153, 122, 18}, // &
-{9, 93, 7}, // '
-{207, 122, 8}, // (
-{230, 122, 9}, // )
-{177, 122, 18}, // *
-{30, 152, 18}, // +
-{85, 181, 7}, // ,
-{34, 93, 11}, // -
-{110, 181, 6}, // .
-{130, 152, 14}, // /
-
-{22, 64, 17}, // 0
-{41, 64, 12}, // 1
-{58, 64, 17}, // 2
-{78, 64, 18}, // 3
-{98, 64, 19}, // 4
-{120, 64, 18}, // 5
-{141, 64, 18}, // 6
-{204, 64, 16}, // 7
-{162, 64, 17}, // 8
-{182, 64, 18}, // 9
-{59, 181, 7}, // :
-{35,181, 7}, // ;
-{203, 152, 14}, // <
-{56, 93, 14}, // =
-{228, 152, 14}, // >
-{177, 181, 18}, // ?
-
-{28, 122, 22}, // @
-{5, 4, 18}, // A
-{27, 4, 18}, // B
-{48, 4, 18}, // C
-{69, 4, 17}, // D
-{90, 4, 13}, // E
-{106, 4, 13}, // F
-{121, 4, 18}, // G
-{143, 4, 17}, // H
-{164, 4, 8}, // I
-{175, 4, 16}, // J
-{195, 4, 18}, // K
-{216, 4, 12}, // L
-{230, 4, 23}, // M
-{6, 34, 18}, // N
-{27, 34, 18}, // O
-
-{48, 34, 18}, // P
-{68, 34, 18}, // Q
-{90, 34, 17}, // R
-{110, 34, 18}, // S
-{130, 34, 14}, // T
-{146, 34, 18}, // U
-{166, 34, 19}, // V
-{185, 34, 29}, // W
-{215, 34, 18}, // X
-{234, 34, 18}, // Y
-{5, 64, 14}, // Z
-{60, 152, 7}, // [
-{106, 151, 13}, // '\'
-{83, 152, 7}, // ]
-{128, 122, 17}, // ^
-{4, 152, 21}, // _
-
-{134, 181, 5}, // '
-{5, 4, 18}, // A
-{27, 4, 18}, // B
-{48, 4, 18}, // C
-{69, 4, 17}, // D
-{90, 4, 13}, // E
-{106, 4, 13}, // F
-{121, 4, 18}, // G
-{143, 4, 17}, // H
-{164, 4, 8}, // I
-{175, 4, 16}, // J
-{195, 4, 18}, // K
-{216, 4, 12}, // L
-{230, 4, 23}, // M
-{6, 34, 18}, // N
-{27, 34, 18}, // O
-
-{48, 34, 18}, // P
-{68, 34, 18}, // Q
-{90, 34, 17}, // R
-{110, 34, 18}, // S
-{130, 34, 14}, // T
-{146, 34, 18}, // U
-{166, 34, 19}, // V
-{185, 34, 29}, // W
-{215, 34, 18}, // X
-{234, 34, 18}, // Y
-{5, 64, 14}, // Z
-{153, 152, 13}, // {
-{11, 181, 5}, // |
-{180, 152, 13}, // }
-{79, 93, 17}, // ~
-{0, 0, -1} // DEL
-};
-
-static int propMapB[26][3] = {
-{11, 12, 33},
-{49, 12, 31},
-{85, 12, 31},
-{120, 12, 30},
-{156, 12, 21},
-{183, 12, 21},
-{207, 12, 32},
-
-{13, 55, 30},
-{49, 55, 13},
-{66, 55, 29},
-{101, 55, 31},
-{135, 55, 21},
-{158, 55, 40},
-{204, 55, 32},
-
-{12, 97, 31},
-{48, 97, 31},
-{82, 97, 30},
-{118, 97, 30},
-{153, 97, 30},
-{185, 97, 25},
-{213, 97, 30},
-
-{11, 139, 32},
-{42, 139, 51},
-{93, 139, 32},
-{126, 139, 31},
-{158, 139, 25},
-};
-
-#define PROPB_GAP_WIDTH 4
-#define PROPB_SPACE_WIDTH 12
-#define PROPB_HEIGHT 36
-
-// bk001205 - code below duplicated in cgame/cg_drawtools.c
-// bk001205 - FIXME: does this belong in ui_shared.c?
-/*
-=================
-UI_DrawBannerString
-=================
-*/
-static void UI_DrawBannerString2( int x, int y, const char* str, vec4_t color )
-{
- const char* s;
- unsigned char ch; // bk001204 - unsigned
- float ax;
- float ay;
- float aw;
- float ah;
- float frow;
- float fcol;
- float fwidth;
- float fheight;
-
- // draw the colored text
- trap_R_SetColor( color );
-
- ax = x * uis.xscale + uis.bias;
- ay = y * uis.yscale;
-
- s = str;
- while ( *s )
- {
- ch = *s & 127;
- if ( ch == ' ' ) {
- ax += ((float)PROPB_SPACE_WIDTH + (float)PROPB_GAP_WIDTH)* uis.xscale;
- }
- else if ( ch >= 'A' && ch <= 'Z' ) {
- ch -= 'A';
- fcol = (float)propMapB[ch][0] / 256.0f;
- frow = (float)propMapB[ch][1] / 256.0f;
- fwidth = (float)propMapB[ch][2] / 256.0f;
- fheight = (float)PROPB_HEIGHT / 256.0f;
- aw = (float)propMapB[ch][2] * uis.xscale;
- ah = (float)PROPB_HEIGHT * uis.yscale;
- trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, uis.charsetPropB );
- ax += (aw + (float)PROPB_GAP_WIDTH * uis.xscale);
- }
- s++;
- }
-
- trap_R_SetColor( NULL );
-}
-
-void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color ) {
- const char * s;
- int ch;
- int width;
- vec4_t drawcolor;
-
- // find the width of the drawn text
- s = str;
- width = 0;
- while ( *s ) {
- ch = *s;
- if ( ch == ' ' ) {
- width += PROPB_SPACE_WIDTH;
- }
- else if ( ch >= 'A' && ch <= 'Z' ) {
- width += propMapB[ch - 'A'][2] + PROPB_GAP_WIDTH;
- }
- s++;
- }
- width -= PROPB_GAP_WIDTH;
-
- switch( style & UI_FORMATMASK ) {
- case UI_CENTER:
- x -= width / 2;
- break;
-
- case UI_RIGHT:
- x -= width;
- break;
-
- case UI_LEFT:
- default:
- break;
- }
-
- if ( style & UI_DROPSHADOW ) {
- drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
- drawcolor[3] = color[3];
- UI_DrawBannerString2( x+2, y+2, str, drawcolor );
- }
-
- UI_DrawBannerString2( x, y, str, color );
-}
-
-
-int UI_ProportionalStringWidth( const char* str ) {
- const char * s;
- int ch;
- int charWidth;
- int width;
-
- s = str;
- width = 0;
- while ( *s ) {
- ch = *s & 127;
- charWidth = propMap[ch][2];
- if ( charWidth != -1 ) {
- width += charWidth;
- width += PROP_GAP_WIDTH;
- }
- s++;
- }
-
- width -= PROP_GAP_WIDTH;
- return width;
-}
-
-static void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t color, float sizeScale, qhandle_t charset )
-{
- const char* s;
- unsigned char ch; // bk001204 - unsigned
- float ax;
- float ay;
- float aw = 0; // bk001204 - init
- float ah;
- float frow;
- float fcol;
- float fwidth;
- float fheight;
-
- // draw the colored text
- trap_R_SetColor( color );
-
- ax = x * uis.xscale + uis.bias;
- ay = y * uis.yscale;
-
- s = str;
- while ( *s )
- {
- ch = *s & 127;
- if ( ch == ' ' ) {
- aw = (float)PROP_SPACE_WIDTH * uis.xscale * sizeScale;
- }
- else if ( propMap[ch][2] != -1 ) {
- fcol = (float)propMap[ch][0] / 256.0f;
- frow = (float)propMap[ch][1] / 256.0f;
- fwidth = (float)propMap[ch][2] / 256.0f;
- fheight = (float)PROP_HEIGHT / 256.0f;
- aw = (float)propMap[ch][2] * uis.xscale * sizeScale;
- ah = (float)PROP_HEIGHT * uis.yscale * sizeScale;
- trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, charset );
- }
-
- ax += (aw + (float)PROP_GAP_WIDTH * uis.xscale * sizeScale);
- s++;
- }
-
- trap_R_SetColor( NULL );
-}
-
-/*
-=================
-UI_ProportionalSizeScale
-=================
-*/
-float UI_ProportionalSizeScale( int style ) {
- if( style & UI_SMALLFONT ) {
- return PROP_SMALL_SIZE_SCALE;
- }
-
- return 1.00;
-}
-
-
-/*
-=================
-UI_DrawProportionalString
-=================
-*/
-void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ) {
- vec4_t drawcolor;
- int width;
- float sizeScale;
-
- sizeScale = UI_ProportionalSizeScale( style );
-
- switch( style & UI_FORMATMASK ) {
- case UI_CENTER:
- width = UI_ProportionalStringWidth( str ) * sizeScale;
- x -= width / 2;
- break;
-
- case UI_RIGHT:
- width = UI_ProportionalStringWidth( str ) * sizeScale;
- x -= width;
- break;
-
- case UI_LEFT:
- default:
- break;
- }
-
- if ( style & UI_DROPSHADOW ) {
- drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
- drawcolor[3] = color[3];
- UI_DrawProportionalString2( x+2, y+2, str, drawcolor, sizeScale, uis.charsetProp );
- }
-
- if ( style & UI_INVERSE ) {
- drawcolor[0] = color[0] * 0.7;
- drawcolor[1] = color[1] * 0.7;
- drawcolor[2] = color[2] * 0.7;
- drawcolor[3] = color[3];
- UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, uis.charsetProp );
- return;
- }
-
- if ( style & UI_PULSE ) {
- drawcolor[0] = color[0] * 0.7;
- drawcolor[1] = color[1] * 0.7;
- drawcolor[2] = color[2] * 0.7;
- drawcolor[3] = color[3];
- UI_DrawProportionalString2( x, y, str, color, sizeScale, uis.charsetProp );
-
- drawcolor[0] = color[0];
- drawcolor[1] = color[1];
- drawcolor[2] = color[2];
- drawcolor[3] = 0.5 + 0.5 * sin( uis.realtime / PULSE_DIVISOR );
- UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, uis.charsetPropGlow );
- return;
- }
-
- UI_DrawProportionalString2( x, y, str, color, sizeScale, uis.charsetProp );
-}
-
-/*
-=================
-UI_DrawProportionalString_Wrapped
-=================
-*/
-void UI_DrawProportionalString_AutoWrapped( int x, int y, int xmax, int ystep, const char* str, int style, vec4_t color ) {
- int width;
- char *s1,*s2,*s3;
- char c_bcp;
- char buf[1024];
- float sizeScale;
-
- if (!str || str[0]=='\0')
- return;
-
- sizeScale = UI_ProportionalSizeScale( style );
-
- Q_strncpyz(buf, str, sizeof(buf));
- s1 = s2 = s3 = buf;
-
- while (1) {
- do {
- s3++;
- } while (*s3!=' ' && *s3!='\0');
- c_bcp = *s3;
- *s3 = '\0';
- width = UI_ProportionalStringWidth(s1) * sizeScale;
- *s3 = c_bcp;
- if (width > xmax) {
- if (s1==s2)
- {
- // fuck, don't have a clean cut, we'll overflow
- s2 = s3;
- }
- *s2 = '\0';
- UI_DrawProportionalString(x, y, s1, style, color);
- y += ystep;
- if (c_bcp == '\0')
- {
- // that was the last word
- // we could start a new loop, but that wouldn't be much use
- // even if the word is too long, we would overflow it (see above)
- // so just print it now if needed
- s2++;
- if (*s2 != '\0') // if we are printing an overflowing line we have s2 == s3
- UI_DrawProportionalString(x, y, s2, style, color);
- break;
- }
- s2++;
- s1 = s2;
- s3 = s2;
- }
- else
- {
- s2 = s3;
- if (c_bcp == '\0') // we reached the end
- {
- UI_DrawProportionalString(x, y, s1, style, color);
- break;
- }
- }
- }
-}
-
-/*
-=================
-UI_DrawString2
-=================
-*/
-static void UI_DrawString2( int x, int y, const char* str, vec4_t color, int charw, int charh )
-{
- const char* s;
- char ch;
- int forceColor = qfalse; //APSFIXME;
- vec4_t tempcolor;
- float ax;
- float ay;
- float aw;
- float ah;
- float frow;
- float fcol;
-
- if (y < -charh)
- // offscreen
- return;
-
- // draw the colored text
- trap_R_SetColor( color );
-
- ax = x * uis.xscale + uis.bias;
- ay = y * uis.yscale;
- aw = charw * uis.xscale;
- ah = charh * uis.yscale;
-
- s = str;
- while ( *s )
- {
- if ( Q_IsColorString( s ) )
- {
- if ( !forceColor )
- {
- memcpy( tempcolor, g_color_table[ColorIndex(s[1])], sizeof( tempcolor ) );
- tempcolor[3] = color[3];
- trap_R_SetColor( tempcolor );
- }
- s += 2;
- continue;
- }
-
- ch = *s & 255;
- if (ch != ' ')
- {
- frow = (ch>>4)*0.0625;
- fcol = (ch&15)*0.0625;
- trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol + 0.0625, frow + 0.0625, uis.charset );
- }
-
- ax += aw;
- s++;
- }
-
- trap_R_SetColor( NULL );
-}
-
-/*
-=================
-UI_DrawString
-=================
-*/
-void UI_DrawString( int x, int y, const char* str, int style, vec4_t color )
-{
- int len;
- int charw;
- int charh;
- vec4_t newcolor;
- vec4_t lowlight;
- float *drawcolor;
- vec4_t dropcolor;
-
- if( !str ) {
- return;
- }
-
- if ((style & UI_BLINK) && ((uis.realtime/BLINK_DIVISOR) & 1))
- return;
-
- if (style & UI_SMALLFONT)
- {
- charw = SMALLCHAR_WIDTH;
- charh = SMALLCHAR_HEIGHT;
- }
- else if (style & UI_GIANTFONT)
- {
- charw = GIANTCHAR_WIDTH;
- charh = GIANTCHAR_HEIGHT;
- }
- else
- {
- charw = BIGCHAR_WIDTH;
- charh = BIGCHAR_HEIGHT;
- }
-
- if (style & UI_PULSE)
- {
- lowlight[0] = 0.8*color[0];
- lowlight[1] = 0.8*color[1];
- lowlight[2] = 0.8*color[2];
- lowlight[3] = 0.8*color[3];
- UI_LerpColor(color,lowlight,newcolor,0.5+0.5*sin(uis.realtime/PULSE_DIVISOR));
- drawcolor = newcolor;
- }
- else
- drawcolor = color;
-
- switch (style & UI_FORMATMASK)
- {
- case UI_CENTER:
- // center justify at x
- len = strlen(str);
- x = x - len*charw/2;
- break;
-
- case UI_RIGHT:
- // right justify at x
- len = strlen(str);
- x = x - len*charw;
- break;
-
- default:
- // left justify at x
- break;
- }
-
- if ( style & UI_DROPSHADOW )
- {
- dropcolor[0] = dropcolor[1] = dropcolor[2] = 0;
- dropcolor[3] = drawcolor[3];
- UI_DrawString2(x+2,y+2,str,dropcolor,charw,charh);
- }
-
- UI_DrawString2(x,y,str,drawcolor,charw,charh);
-}
-
-/*
-=================
-UI_DrawChar
-=================
-*/
-void UI_DrawChar( int x, int y, int ch, int style, vec4_t color )
-{
- char buff[2];
-
- buff[0] = ch;
- buff[1] = '\0';
-
- UI_DrawString( x, y, buff, style, color );
-}
-
-qboolean UI_IsFullscreen( void ) {
- if ( uis.activemenu && ( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
- return uis.activemenu->fullscreen;
- }
-
- return qfalse;
-}
-
-static void NeedCDAction( qboolean result ) {
- if ( !result ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
- }
-}
-
-static void NeedCDKeyAction( qboolean result ) {
- if ( !result ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
- }
-}
-
-void UI_SetActiveMenu( uiMenuCommand_t menu ) {
- // this should be the ONLY way the menu system is brought up
- // enusure minumum menu data is cached
- Menu_Cache();
-
- switch ( menu ) {
- case UIMENU_NONE:
- UI_ForceMenuOff();
- return;
- case UIMENU_MAIN:
- UI_MainMenu();
- return;
- case UIMENU_NEED_CD:
- UI_ConfirmMenu( "Insert the CD", 0, NeedCDAction );
- return;
- case UIMENU_BAD_CD_KEY:
- UI_ConfirmMenu( "Bad CD Key", 0, NeedCDKeyAction );
- return;
- case UIMENU_INGAME:
- /*
- //GRank
- UI_RankingsMenu();
- return;
- */
- trap_Cvar_Set( "cl_paused", "1" );
- UI_InGameMenu();
- return;
-
- // bk001204
- case UIMENU_TEAM:
- case UIMENU_POSTGAME:
- default:
-#ifndef NDEBUG
- Com_Printf("UI_SetActiveMenu: bad enum %d\n", menu );
-#endif
- break;
- }
-}
-
-/*
-=================
-UI_KeyEvent
-=================
-*/
-void UI_KeyEvent( int key, int down ) {
- sfxHandle_t s;
-
- if (!uis.activemenu) {
- return;
- }
-
- if (!down) {
- return;
- }
-
- if (uis.activemenu->key)
- s = uis.activemenu->key( key );
- else
- s = Menu_DefaultKey( uis.activemenu, key );
-
- if ((s > 0) && (s != menu_null_sound))
- trap_S_StartLocalSound( s, CHAN_LOCAL_SOUND );
-}
-
-/*
-=================
-UI_MouseEvent
-=================
-*/
-void UI_MouseEvent( int dx, int dy )
-{
- int i;
- menucommon_s* m;
-
- if (!uis.activemenu)
- return;
-
- // update mouse screen position
- uis.cursorx += dx;
- if (uis.cursorx < 0)
- uis.cursorx = 0;
- else if (uis.cursorx > SCREEN_WIDTH)
- uis.cursorx = SCREEN_WIDTH;
-
- uis.cursory += dy;
- if (uis.cursory < 0)
- uis.cursory = 0;
- else if (uis.cursory > SCREEN_HEIGHT)
- uis.cursory = SCREEN_HEIGHT;
-
- // region test the active menu items
- for (i=0; i<uis.activemenu->nitems; i++)
- {
- m = (menucommon_s*)uis.activemenu->items[i];
-
- if (m->flags & (QMF_GRAYED|QMF_INACTIVE))
- continue;
-
- if ((uis.cursorx < m->left) ||
- (uis.cursorx > m->right) ||
- (uis.cursory < m->top) ||
- (uis.cursory > m->bottom))
- {
- // cursor out of item bounds
- continue;
- }
-
- // set focus to item at cursor
- if (uis.activemenu->cursor != i)
- {
- Menu_SetCursor( uis.activemenu, i );
- ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor_prev]))->flags &= ~QMF_HASMOUSEFOCUS;
-
- if ( !(((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags & QMF_SILENT ) ) {
- trap_S_StartLocalSound( menu_move_sound, CHAN_LOCAL_SOUND );
- }
- }
-
- ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags |= QMF_HASMOUSEFOCUS;
- return;
- }
-
- if (uis.activemenu->nitems > 0) {
- // out of any region
- ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags &= ~QMF_HASMOUSEFOCUS;
- }
-}
-
-char *UI_Argv( int arg ) {
- static char buffer[MAX_STRING_CHARS];
-
- trap_Argv( arg, buffer, sizeof( buffer ) );
-
- return buffer;
-}
-
-
-char *UI_Cvar_VariableString( const char *var_name ) {
- static char buffer[MAX_STRING_CHARS];
-
- trap_Cvar_VariableStringBuffer( var_name, buffer, sizeof( buffer ) );
-
- return buffer;
-}
-
-
-/*
-=================
-UI_Cache
-=================
-*/
-void UI_Cache_f( void ) {
- MainMenu_Cache();
- InGame_Cache();
- ConfirmMenu_Cache();
- PlayerModel_Cache();
- PlayerSettings_Cache();
- Controls_Cache();
- Demos_Cache();
- UI_CinematicsMenu_Cache();
- Preferences_Cache();
- ServerInfo_Cache();
- SpecifyServer_Cache();
- ArenaServers_Cache();
- StartServer_Cache();
- ServerOptions_Cache();
- DriverInfo_Cache();
- GraphicsOptions_Cache();
- UI_DisplayOptionsMenu_Cache();
- UI_SoundOptionsMenu_Cache();
- UI_NetworkOptionsMenu_Cache();
- UI_SPLevelMenu_Cache();
- UI_SPSkillMenu_Cache();
- UI_SPPostgameMenu_Cache();
- TeamMain_Cache();
- UI_AddBots_Cache();
- UI_RemoveBots_Cache();
- UI_SetupMenu_Cache();
-// UI_LoadConfig_Cache();
-// UI_SaveConfigMenu_Cache();
- UI_BotSelectMenu_Cache();
- UI_CDKeyMenu_Cache();
- UI_ModsMenu_Cache();
-
-}
-
-
-/*
-=================
-UI_ConsoleCommand
-=================
-*/
-qboolean UI_ConsoleCommand( int realTime ) {
- char *cmd;
-
- cmd = UI_Argv( 0 );
-
- // ensure minimum menu data is available
- Menu_Cache();
-
- if ( Q_stricmp (cmd, "levelselect") == 0 ) {
- UI_SPLevelMenu_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "postgame") == 0 ) {
- UI_SPPostgameMenu_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "ui_cache") == 0 ) {
- UI_Cache_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "ui_cinematics") == 0 ) {
- UI_CinematicsMenu_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "ui_teamOrders") == 0 ) {
- UI_TeamOrdersMenu_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "iamacheater") == 0 ) {
- UI_SPUnlock_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "iamamonkey") == 0 ) {
- UI_SPUnlockMedals_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "ui_cdkey") == 0 ) {
- UI_CDKeyMenu_f();
- return qtrue;
- }
-
- if ( Q_stricmp (cmd, "ui_mappage") == 0 ) {
- mappage.pagenumber = atoi(UI_Argv( 1 ));
- Q_strncpyz(mappage.mapname[0],UI_Argv(2),32);
- Q_strncpyz(mappage.mapname[1],UI_Argv(3),32);
- Q_strncpyz(mappage.mapname[2],UI_Argv(4),32);
- Q_strncpyz(mappage.mapname[3],UI_Argv(5),32);
- Q_strncpyz(mappage.mapname[4],UI_Argv(6),32);
- Q_strncpyz(mappage.mapname[5],UI_Argv(7),32);
- Q_strncpyz(mappage.mapname[6],UI_Argv(8),32);
- Q_strncpyz(mappage.mapname[7],UI_Argv(9),32);
- Q_strncpyz(mappage.mapname[8],UI_Argv(10),32);
- Q_strncpyz(mappage.mapname[9],UI_Argv(11),32);
-
- UI_VoteMapMenuInternal();
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-=================
-UI_Shutdown
-=================
-*/
-void UI_Shutdown( void ) {
-}
-
-/*
-=================
-UI_Init
-=================
-*/
-void UI_Init( void ) {
- UI_RegisterCvars();
-
- UI_InitGameinfo();
-
- // cache redundant calulations
- trap_GetGlconfig( &uis.glconfig );
-
- // for 640x480 virtualized screen
- uis.xscale = uis.glconfig.vidWidth * (1.0/640.0);
- uis.yscale = uis.glconfig.vidHeight * (1.0/480.0);
- if ( uis.glconfig.vidWidth * 480 > uis.glconfig.vidHeight * 640 ) {
- // wide screen
- uis.bias = 0.5 * ( uis.glconfig.vidWidth - ( uis.glconfig.vidHeight * (640.0/480.0) ) );
- uis.xscale = uis.yscale;
- }
- else {
- // no wide screen
- uis.bias = 0;
- }
-
- // initialize the menu system
- Menu_Cache();
-
- uis.activemenu = NULL;
- uis.menusp = 0;
-}
-
-/*
-================
-UI_AdjustFrom640
-
-Adjusted for resolution and screen aspect ratio
-================
-*/
-void UI_AdjustFrom640( float *x, float *y, float *w, float *h ) {
- // expect valid pointers
- *x = *x * uis.xscale + uis.bias;
- *y *= uis.yscale;
- *w *= uis.xscale;
- *h *= uis.yscale;
-}
-
-void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {
- qhandle_t hShader;
-
- hShader = trap_R_RegisterShaderNoMip( picname );
- UI_AdjustFrom640( &x, &y, &width, &height );
- trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
-}
-
-void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader ) {
- float s0;
- float s1;
- float t0;
- float t1;
-
- if( w < 0 ) { // flip about vertical
- w = -w;
- s0 = 1;
- s1 = 0;
- }
- else {
- s0 = 0;
- s1 = 1;
- }
-
- if( h < 0 ) { // flip about horizontal
- h = -h;
- t0 = 1;
- t1 = 0;
- }
- else {
- t0 = 0;
- t1 = 1;
- }
-
- UI_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, w, h, s0, t0, s1, t1, hShader );
-}
-
-/*
-================
-UI_FillRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void UI_FillRect( float x, float y, float width, float height, const float *color ) {
- trap_R_SetColor( color );
-
- UI_AdjustFrom640( &x, &y, &width, &height );
- trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, uis.whiteShader );
-
- trap_R_SetColor( NULL );
-}
-
-/*
-================
-UI_DrawRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void UI_DrawRect( float x, float y, float width, float height, const float *color ) {
- trap_R_SetColor( color );
-
- UI_AdjustFrom640( &x, &y, &width, &height );
-
- trap_R_DrawStretchPic( x, y, width, 1, 0, 0, 0, 0, uis.whiteShader );
- trap_R_DrawStretchPic( x, y, 1, height, 0, 0, 0, 0, uis.whiteShader );
- trap_R_DrawStretchPic( x, y + height - 1, width, 1, 0, 0, 0, 0, uis.whiteShader );
- trap_R_DrawStretchPic( x + width - 1, y, 1, height, 0, 0, 0, 0, uis.whiteShader );
-
- trap_R_SetColor( NULL );
-}
-
-void UI_SetColor( const float *rgba ) {
- trap_R_SetColor( rgba );
-}
-
-void UI_UpdateScreen( void ) {
- trap_UpdateScreen();
-}
-
-/*
-=================
-UI_Refresh
-=================
-*/
-void UI_Refresh( int realtime )
-{
- uis.frametime = realtime - uis.realtime;
- uis.realtime = realtime;
-
- if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
- return;
- }
-
- UI_UpdateCvars();
-
- if ( uis.activemenu )
- {
- if (uis.activemenu->fullscreen)
- {
- // draw the background
- if( uis.activemenu->showlogo ) {
- UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackShader );
- }
- else {
- UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackNoLogoShader );
- }
- }
-
- if (uis.activemenu->draw)
- uis.activemenu->draw();
- else
- Menu_Draw( uis.activemenu );
-
- if( uis.firstdraw ) {
- UI_MouseEvent( 0, 0 );
- uis.firstdraw = qfalse;
- }
- }
-
- // draw cursor
- UI_SetColor( NULL );
- UI_DrawHandlePic( uis.cursorx-16, uis.cursory-16, 32, 32, uis.cursor);
-
-#ifndef NDEBUG
- if (uis.debug)
- {
- // cursor coordinates
- UI_DrawString( 0, 0, va("(%d,%d)",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed );
- }
-#endif
-
- // delay playing the enter sound until after the
- // menu has been drawn, to avoid delay while
- // caching images
- if (m_entersound)
- {
- trap_S_StartLocalSound( menu_in_sound, CHAN_LOCAL_SOUND );
- m_entersound = qfalse;
- }
-}
-
-void UI_DrawTextBox (int x, int y, int width, int lines)
-{
- UI_FillRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorBlack );
- UI_DrawRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorWhite );
-}
-
-qboolean UI_CursorInRect (int x, int y, int width, int height)
-{
- if (uis.cursorx < x ||
- uis.cursory < y ||
- uis.cursorx > x+width ||
- uis.cursory > y+height)
- return qfalse;
-
- return qtrue;
-}
diff --git a/game/code/q3_ui/ui_cdkey.c b/game/code/q3_ui/ui_cdkey.c
deleted file mode 100644
index ec3029b..0000000
--- a/game/code/q3_ui/ui_cdkey.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-CD KEY MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define ART_FRAME "menu/art/cut_frame"
-#define ART_ACCEPT0 "menu/art/accept_0"
-#define ART_ACCEPT1 "menu/art/accept_1"
-#define ART_BACK0 "menu/art/back_0"
-#define ART_BACK1 "menu/art/back_1"
-
-#define ID_CDKEY 10
-#define ID_ACCEPT 11
-#define ID_BACK 12
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s frame;
-
- menufield_s cdkey;
-
- menubitmap_s accept;
- menubitmap_s back;
-} cdkeyMenuInfo_t;
-
-static cdkeyMenuInfo_t cdkeyMenuInfo;
-
-
-/*
-===============
-UI_CDKeyMenu_Event
-===============
-*/
-static void UI_CDKeyMenu_Event( void *ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_ACCEPT:
- if( cdkeyMenuInfo.cdkey.field.buffer[0] ) {
- trap_SetCDKey( cdkeyMenuInfo.cdkey.field.buffer );
- }
- UI_PopMenu();
- break;
-
- case ID_BACK:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-=================
-UI_CDKeyMenu_PreValidateKey
-=================
-*/
-static int UI_CDKeyMenu_PreValidateKey( const char *key ) {
- char ch;
-
- if( strlen( key ) != 16 ) {
- return 1;
- }
-
- while( ( ch = *key++ ) ) {
- switch( ch ) {
- case '2':
- case '3':
- case '7':
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'g':
- case 'h':
- case 'j':
- case 'l':
- case 'p':
- case 'r':
- case 's':
- case 't':
- case 'w':
- continue;
- default:
- return -1;
- }
- }
-
- return 0;
-}
-
-
-/*
-=================
-UI_CDKeyMenu_DrawKey
-=================
-*/
-static void UI_CDKeyMenu_DrawKey( void *self ) {
- menufield_s *f;
- qboolean focus;
- int style;
- char c;
- float *color;
- int x, y;
- int val;
-
- f = (menufield_s *)self;
-
- focus = (f->generic.parent->cursor == f->generic.menuPosition);
-
- style = UI_LEFT;
- if( focus ) {
- color = color_yellow;
- }
- else {
- color = color_orange;
- }
-
- x = 320 - 8 * BIGCHAR_WIDTH;
- y = 240 - BIGCHAR_HEIGHT / 2;
- UI_FillRect( x, y, 16 * BIGCHAR_WIDTH, BIGCHAR_HEIGHT, listbar_color );
- UI_DrawString( x, y, f->field.buffer, style, color );
-
- // draw cursor if we have focus
- if( focus ) {
- if ( trap_Key_GetOverstrikeMode() ) {
- c = 11;
- } else {
- c = 10;
- }
-
- style &= ~UI_PULSE;
- style |= UI_BLINK;
-
- UI_DrawChar( x + f->field.cursor * BIGCHAR_WIDTH, y, c, style, color_white );
- }
-
- val = UI_CDKeyMenu_PreValidateKey( f->field.buffer );
- if( val == 1 ) {
- UI_DrawProportionalString( 320, 376, "Please enter your CD Key", UI_CENTER|UI_SMALLFONT, color_yellow );
- }
- else if ( val == 0 ) {
- UI_DrawProportionalString( 320, 376, "The CD Key appears to be valid, thank you", UI_CENTER|UI_SMALLFONT, color_white );
- }
- else {
- UI_DrawProportionalString( 320, 376, "The CD Key is not valid", UI_CENTER|UI_SMALLFONT, color_red );
- }
-}
-
-
-/*
-===============
-UI_CDKeyMenu_Init
-===============
-*/
-static void UI_CDKeyMenu_Init( void ) {
- trap_Cvar_Set( "ui_cdkeychecked", "1" );
-
- UI_CDKeyMenu_Cache();
-
- memset( &cdkeyMenuInfo, 0, sizeof(cdkeyMenuInfo) );
- cdkeyMenuInfo.menu.wrapAround = qtrue;
- cdkeyMenuInfo.menu.fullscreen = qtrue;
-
- cdkeyMenuInfo.banner.generic.type = MTYPE_BTEXT;
- cdkeyMenuInfo.banner.generic.x = 320;
- cdkeyMenuInfo.banner.generic.y = 16;
- cdkeyMenuInfo.banner.string = "CD KEY";
- cdkeyMenuInfo.banner.color = color_white;
- cdkeyMenuInfo.banner.style = UI_CENTER;
-
- cdkeyMenuInfo.frame.generic.type = MTYPE_BITMAP;
- cdkeyMenuInfo.frame.generic.name = ART_FRAME;
- cdkeyMenuInfo.frame.generic.flags = QMF_INACTIVE;
- cdkeyMenuInfo.frame.generic.x = 142;
- cdkeyMenuInfo.frame.generic.y = 118;
- cdkeyMenuInfo.frame.width = 359;
- cdkeyMenuInfo.frame.height = 256;
-
- cdkeyMenuInfo.cdkey.generic.type = MTYPE_FIELD;
- cdkeyMenuInfo.cdkey.generic.name = "CD Key:";
- cdkeyMenuInfo.cdkey.generic.flags = QMF_LOWERCASE;
- cdkeyMenuInfo.cdkey.generic.x = 320 - BIGCHAR_WIDTH * 2.5;
- cdkeyMenuInfo.cdkey.generic.y = 240 - BIGCHAR_HEIGHT / 2;
- cdkeyMenuInfo.cdkey.field.widthInChars = 16;
- cdkeyMenuInfo.cdkey.field.maxchars = 16;
- cdkeyMenuInfo.cdkey.generic.ownerdraw = UI_CDKeyMenu_DrawKey;
-
- cdkeyMenuInfo.accept.generic.type = MTYPE_BITMAP;
- cdkeyMenuInfo.accept.generic.name = ART_ACCEPT0;
- cdkeyMenuInfo.accept.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- cdkeyMenuInfo.accept.generic.id = ID_ACCEPT;
- cdkeyMenuInfo.accept.generic.callback = UI_CDKeyMenu_Event;
- cdkeyMenuInfo.accept.generic.x = 640;
- cdkeyMenuInfo.accept.generic.y = 480-64;
- cdkeyMenuInfo.accept.width = 128;
- cdkeyMenuInfo.accept.height = 64;
- cdkeyMenuInfo.accept.focuspic = ART_ACCEPT1;
-
- cdkeyMenuInfo.back.generic.type = MTYPE_BITMAP;
- cdkeyMenuInfo.back.generic.name = ART_BACK0;
- cdkeyMenuInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- cdkeyMenuInfo.back.generic.id = ID_BACK;
- cdkeyMenuInfo.back.generic.callback = UI_CDKeyMenu_Event;
- cdkeyMenuInfo.back.generic.x = 0;
- cdkeyMenuInfo.back.generic.y = 480-64;
- cdkeyMenuInfo.back.width = 128;
- cdkeyMenuInfo.back.height = 64;
- cdkeyMenuInfo.back.focuspic = ART_BACK1;
-
- Menu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.banner );
- Menu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.frame );
- Menu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.cdkey );
- Menu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.accept );
- if( uis.menusp ) {
- Menu_AddItem( &cdkeyMenuInfo.menu, &cdkeyMenuInfo.back );
- }
-
- trap_GetCDKey( cdkeyMenuInfo.cdkey.field.buffer, cdkeyMenuInfo.cdkey.field.maxchars + 1 );
- if( trap_VerifyCDKey( cdkeyMenuInfo.cdkey.field.buffer, NULL ) == qfalse ) {
- cdkeyMenuInfo.cdkey.field.buffer[0] = 0;
- }
-}
-
-
-/*
-=================
-UI_CDKeyMenu_Cache
-=================
-*/
-void UI_CDKeyMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_ACCEPT0 );
- trap_R_RegisterShaderNoMip( ART_ACCEPT1 );
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_FRAME );
-}
-
-
-/*
-===============
-UI_CDKeyMenu
-===============
-*/
-void UI_CDKeyMenu( void ) {
- UI_CDKeyMenu_Init();
- UI_PushMenu( &cdkeyMenuInfo.menu );
-}
-
-
-/*
-===============
-UI_CDKeyMenu_f
-===============
-*/
-void UI_CDKeyMenu_f( void ) {
- UI_CDKeyMenu();
-}
diff --git a/game/code/q3_ui/ui_controls2.c b/game/code/q3_ui/ui_controls2.c
deleted file mode 100644
index 0844e93..0000000
--- a/game/code/q3_ui/ui_controls2.c
+++ /dev/null
@@ -1,1764 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-CONTROLS MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-#define ART_BACK0 "menu/art_blueish/back_0"
-#define ART_BACK1 "menu/art_blueish/back_1"
-#define ART_FRAMEL "menu/art_blueish/frame2_l"
-#define ART_FRAMER "menu/art_blueish/frame1_r"
-
-
-typedef struct {
- char *command;
- char *label;
- int id;
- int anim;
- int defaultbind1;
- int defaultbind2;
- int bind1;
- int bind2;
-} bind_t;
-
-typedef struct
-{
- char* name;
- float defaultvalue;
- float value;
-} configcvar_t;
-
-#define SAVE_NOOP 0
-#define SAVE_YES 1
-#define SAVE_NO 2
-#define SAVE_CANCEL 3
-
-// control sections
-#define C_MOVEMENT 0
-#define C_LOOKING 1
-#define C_WEAPONS 2
-#define C_MISC 3
-#define C_MAX 4
-
-#define ID_MOVEMENT 100
-#define ID_LOOKING 101
-#define ID_WEAPONS 102
-#define ID_MISC 103
-#define ID_DEFAULTS 104
-#define ID_BACK 105
-#define ID_SAVEANDEXIT 106
-#define ID_EXIT 107
-
-// bindable actions
-#define ID_SHOWSCORES 0
-#define ID_USEITEM 1
-#define ID_SPEED 2
-#define ID_FORWARD 3
-#define ID_BACKPEDAL 4
-#define ID_MOVELEFT 5
-#define ID_MOVERIGHT 6
-#define ID_MOVEUP 7
-#define ID_MOVEDOWN 8
-#define ID_LEFT 9
-#define ID_RIGHT 10
-#define ID_STRAFE 11
-#define ID_LOOKUP 12
-#define ID_LOOKDOWN 13
-#define ID_MOUSELOOK 14
-#define ID_CENTERVIEW 15
-#define ID_ZOOMVIEW 16
-#define ID_WEAPON1 17
-#define ID_WEAPON2 18
-#define ID_WEAPON3 19
-#define ID_WEAPON4 20
-#define ID_WEAPON5 21
-#define ID_WEAPON6 22
-#define ID_WEAPON7 23
-#define ID_WEAPON8 24
-#define ID_WEAPON9 25
-#define ID_WEAPON10 26
-#define ID_WEAPON11 27 //Nailgun
-#define ID_WEAPON12 28 //ProxMines
-#define ID_WEAPON13 29 //Chaingun
-#define ID_ATTACK 30
-#define ID_WEAPPREV 31
-#define ID_WEAPNEXT 32
-#define ID_GESTURE 33
-#define ID_CHAT 34
-#define ID_CHAT2 35
-#define ID_CHAT3 36
-#define ID_CHAT4 37
-#define ID_VOIP_TALK 38
-
-// all others
-#define ID_FREELOOK 39
-#define ID_INVERTMOUSE 40
-#define ID_ALWAYSRUN 41
-#define ID_AUTOSWITCH 42
-#define ID_MOUSESPEED 43
-#define ID_JOYENABLE 44
-#define ID_JOYTHRESHOLD 45
-#define ID_SMOOTHMOUSE 46
-#define ID_VOIP_TEAMONLY 47
-
-
-
-#define ANIM_IDLE 0
-#define ANIM_RUN 1
-#define ANIM_WALK 2
-#define ANIM_BACK 3
-#define ANIM_JUMP 4
-#define ANIM_CROUCH 5
-#define ANIM_STEPLEFT 6
-#define ANIM_STEPRIGHT 7
-#define ANIM_TURNLEFT 8
-#define ANIM_TURNRIGHT 9
-#define ANIM_LOOKUP 10
-#define ANIM_LOOKDOWN 11
-#define ANIM_WEAPON1 12
-#define ANIM_WEAPON2 13
-#define ANIM_WEAPON3 14
-#define ANIM_WEAPON4 15
-#define ANIM_WEAPON5 16
-#define ANIM_WEAPON6 17
-#define ANIM_WEAPON7 18
-#define ANIM_WEAPON8 19
-#define ANIM_WEAPON9 20
-#define ANIM_WEAPON10 21
-#define ANIM_ATTACK 22
-#define ANIM_GESTURE 23
-#define ANIM_DIE 24
-#define ANIM_CHAT 25
-
-//New in Beta 23
-#define ANIM_WEAPON11 26 //Nailgun
-#define ANIM_WEAPON12 27 //ProxMines
-#define ANIM_WEAPON13 28 //Chaingun
-
-typedef struct
-{
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
- menubitmap_s player;
-
- menutext_s movement;
- menutext_s looking;
- menutext_s weapons;
- menutext_s misc;
-
- menuaction_s walkforward;
- menuaction_s backpedal;
- menuaction_s stepleft;
- menuaction_s stepright;
- menuaction_s moveup;
- menuaction_s movedown;
- menuaction_s turnleft;
- menuaction_s turnright;
- menuaction_s sidestep;
- menuaction_s run;
- menuaction_s machinegun;
- menuaction_s chainsaw;
- menuaction_s shotgun;
- menuaction_s grenadelauncher;
- menuaction_s rocketlauncher;
- menuaction_s lightning;
- menuaction_s railgun;
- menuaction_s plasma;
- menuaction_s bfg;
- menuaction_s grapple;
- //New in Beta 23
- menuaction_s nailgun;
- menuaction_s proxmine;
- menuaction_s chaingun;
- //New in 23 end
- menuaction_s attack;
- menuaction_s prevweapon;
- menuaction_s nextweapon;
- menuaction_s lookup;
- menuaction_s lookdown;
- menuaction_s mouselook;
- menuradiobutton_s freelook;
- menuaction_s centerview;
- menuaction_s zoomview;
- menuaction_s gesture;
- menuradiobutton_s invertmouse;
- menuslider_s sensitivity;
- menuradiobutton_s smoothmouse;
- menuradiobutton_s alwaysrun;
- menuaction_s showscores;
- menuradiobutton_s autoswitch;
- menuaction_s useitem;
- playerInfo_t playerinfo;
- qboolean changesmade;
- menuaction_s chat;
- menuaction_s chat2;
- menuaction_s chat3;
- menuaction_s chat4;
- menuaction_s voip_talk;
- menuradiobutton_s voip_teamonly;
- menuradiobutton_s joyenable;
- menuslider_s joythreshold;
- int section;
- qboolean waitingforkey;
- char playerModel[64];
- vec3_t playerViewangles;
- vec3_t playerMoveangles;
- int playerLegs;
- int playerTorso;
- int playerWeapon;
- qboolean playerChat;
-
- menubitmap_s back;
- menutext_s name;
-} controls_t;
-
-static controls_t s_controls;
-
-// OLD
-//static vec4_t controls_binding_color = {1.00f, 0.43f, 0.00f, 1.00f}; // bk: Win32 C4305
-
-// New!
-static vec4_t controls_binding_color = {0.58f, 0.70f, 0.81f, 1.00f};
-
-static bind_t g_bindings[] =
-{
- {"+scores", "show scores", ID_SHOWSCORES, ANIM_IDLE, K_TAB, -1, -1, -1},
- {"+button2", "use item", ID_USEITEM, ANIM_IDLE, K_ENTER, -1, -1, -1},
- {"+speed", "run / walk", ID_SPEED, ANIM_RUN, K_SHIFT, -1, -1, -1},
- {"+forward", "walk forward", ID_FORWARD, ANIM_WALK, K_UPARROW, -1, -1, -1},
- {"+back", "backpedal", ID_BACKPEDAL, ANIM_BACK, K_DOWNARROW, -1, -1, -1},
- {"+moveleft", "step left", ID_MOVELEFT, ANIM_STEPLEFT, ',', -1, -1, -1},
- {"+moveright", "step right", ID_MOVERIGHT, ANIM_STEPRIGHT, '.', -1, -1, -1},
- {"+moveup", "up / jump", ID_MOVEUP, ANIM_JUMP, K_SPACE, -1, -1, -1},
- {"+movedown", "down / crouch", ID_MOVEDOWN, ANIM_CROUCH, 'c', -1, -1, -1},
- {"+left", "turn left", ID_LEFT, ANIM_TURNLEFT, K_LEFTARROW, -1, -1, -1},
- {"+right", "turn right", ID_RIGHT, ANIM_TURNRIGHT, K_RIGHTARROW, -1, -1, -1},
- {"+strafe", "sidestep / turn", ID_STRAFE, ANIM_IDLE, K_ALT, -1, -1, -1},
- {"+lookup", "look up", ID_LOOKUP, ANIM_LOOKUP, K_PGDN, -1, -1, -1},
- {"+lookdown", "look down", ID_LOOKDOWN, ANIM_LOOKDOWN, K_DEL, -1, -1, -1},
- {"+mlook", "mouse look", ID_MOUSELOOK, ANIM_IDLE, '/', -1, -1, -1},
- {"centerview", "center view", ID_CENTERVIEW, ANIM_IDLE, K_END, -1, -1, -1},
- {"+zoom", "zoom view", ID_ZOOMVIEW, ANIM_IDLE, -1, -1, -1, -1},
- {"weapon 1", "gauntlet", ID_WEAPON1, ANIM_WEAPON1, '1', -1, -1, -1},
- {"weapon 2", "machinegun", ID_WEAPON2, ANIM_WEAPON2, '2', -1, -1, -1},
- {"weapon 3", "shotgun", ID_WEAPON3, ANIM_WEAPON3, '3', -1, -1, -1},
- {"weapon 4", "grenade launcher", ID_WEAPON4, ANIM_WEAPON4, '4', -1, -1, -1},
- {"weapon 5", "rocket launcher", ID_WEAPON5, ANIM_WEAPON5, '5', -1, -1, -1},
- {"weapon 6", "lightning", ID_WEAPON6, ANIM_WEAPON6, '6', -1, -1, -1},
- {"weapon 7", "railgun", ID_WEAPON7, ANIM_WEAPON7, '7', -1, -1, -1},
- {"weapon 8", "plasma gun", ID_WEAPON8, ANIM_WEAPON8, '8', -1, -1, -1},
- {"weapon 9", "BFG", ID_WEAPON9, ANIM_WEAPON9, '9', -1, -1, -1},
- {"weapon 10", "Grapple", ID_WEAPON10, ANIM_WEAPON10, -1, -1, -1, -1},
- {"weapon 11", "nailgun", ID_WEAPON11, ANIM_WEAPON11, -1, -1, -1, -1},
- {"weapon 12", "mine Launcher", ID_WEAPON12, ANIM_WEAPON12, -1, -1, -1, -1},
- {"weapon 13", "chaingun", ID_WEAPON13, ANIM_WEAPON13, -1, -1, -1, -1},
- {"+attack", "attack", ID_ATTACK, ANIM_ATTACK, K_CTRL, -1, -1, -1},
- {"weapprev", "prev weapon", ID_WEAPPREV, ANIM_IDLE, '[', -1, -1, -1},
- {"weapnext", "next weapon", ID_WEAPNEXT, ANIM_IDLE, ']', -1, -1, -1},
- {"+button3", "gesture", ID_GESTURE, ANIM_GESTURE, K_MOUSE3, -1, -1, -1},
- {"messagemode", "chat", ID_CHAT, ANIM_CHAT, 't', -1, -1, -1},
- {"messagemode2", "chat - team", ID_CHAT2, ANIM_CHAT, -1, -1, -1, -1},
- {"messagemode3", "chat - target", ID_CHAT3, ANIM_CHAT, -1, -1, -1, -1},
- {"messagemode4", "chat - attacker", ID_CHAT4, ANIM_CHAT, -1, -1, -1, -1},
- {"+voiprecord", "voice chat", ID_VOIP_TALK, ANIM_CHAT, 'q', -1, -1, -1},
- {(char*)NULL, (char*)NULL, 0, 0, -1, -1, -1, -1},
-};
-
-static configcvar_t g_configcvars[] =
-{
- {"cl_run", 0, 0},
- {"m_pitch", 0, 0},
- {"cg_autoswitch", 0, 0},
- {"sensitivity", 0, 0},
- {"in_joystick", 0, 0},
- {"joy_threshold", 0, 0},
- {"m_filter", 0, 0},
- {"cl_freelook", 0, 0},
- {"cg_voipTeamOnly", 0, 0},
- {NULL, 0, 0}
-};
-
-static menucommon_s *g_movement_controls[] =
-{
- (menucommon_s *)&s_controls.alwaysrun,
- (menucommon_s *)&s_controls.run,
- (menucommon_s *)&s_controls.walkforward,
- (menucommon_s *)&s_controls.backpedal,
- (menucommon_s *)&s_controls.stepleft,
- (menucommon_s *)&s_controls.stepright,
- (menucommon_s *)&s_controls.moveup,
- (menucommon_s *)&s_controls.movedown,
- (menucommon_s *)&s_controls.turnleft,
- (menucommon_s *)&s_controls.turnright,
- (menucommon_s *)&s_controls.sidestep,
- NULL
-};
-
-static menucommon_s *g_weapons_controls[] = {
- (menucommon_s *)&s_controls.attack,
- (menucommon_s *)&s_controls.nextweapon,
- (menucommon_s *)&s_controls.prevweapon,
- (menucommon_s *)&s_controls.autoswitch,
- (menucommon_s *)&s_controls.chainsaw,
- (menucommon_s *)&s_controls.machinegun,
- (menucommon_s *)&s_controls.shotgun,
- (menucommon_s *)&s_controls.grenadelauncher,
- (menucommon_s *)&s_controls.rocketlauncher,
- (menucommon_s *)&s_controls.lightning,
- (menucommon_s *)&s_controls.railgun,
- (menucommon_s *)&s_controls.plasma,
- (menucommon_s *)&s_controls.bfg,
- (menucommon_s *)&s_controls.grapple,
- (menucommon_s *)&s_controls.nailgun,
- (menucommon_s *)&s_controls.proxmine,
- (menucommon_s *)&s_controls.chaingun,
- NULL,
-};
-
-static menucommon_s *g_looking_controls[] = {
- (menucommon_s *)&s_controls.sensitivity,
- (menucommon_s *)&s_controls.smoothmouse,
- (menucommon_s *)&s_controls.invertmouse,
- (menucommon_s *)&s_controls.lookup,
- (menucommon_s *)&s_controls.lookdown,
- (menucommon_s *)&s_controls.mouselook,
- (menucommon_s *)&s_controls.freelook,
- (menucommon_s *)&s_controls.centerview,
- (menucommon_s *)&s_controls.zoomview,
- (menucommon_s *)&s_controls.joyenable,
- (menucommon_s *)&s_controls.joythreshold,
- NULL,
-};
-
-static menucommon_s *g_misc_controls[] = {
- (menucommon_s *)&s_controls.showscores,
- (menucommon_s *)&s_controls.useitem,
- (menucommon_s *)&s_controls.gesture,
- (menucommon_s *)&s_controls.chat,
- (menucommon_s *)&s_controls.chat2,
- (menucommon_s *)&s_controls.chat3,
- (menucommon_s *)&s_controls.chat4,
- (menucommon_s *)&s_controls.voip_talk,
- (menucommon_s *)&s_controls.voip_teamonly,
- NULL,
-};
-
-static menucommon_s **g_controls[] = {
- g_movement_controls,
- g_looking_controls,
- g_weapons_controls,
- g_misc_controls,
-};
-
-/*
-=================
-Controls_InitCvars
-=================
-*/
-static void Controls_InitCvars( void )
-{
- int i;
- configcvar_t* cvarptr;
-
- cvarptr = g_configcvars;
- for (i=0; ;i++,cvarptr++)
- {
- if (!cvarptr->name)
- break;
-
- // get current value
- cvarptr->value = trap_Cvar_VariableValue( cvarptr->name );
-
- // get default value
- trap_Cvar_Reset( cvarptr->name );
- cvarptr->defaultvalue = trap_Cvar_VariableValue( cvarptr->name );
-
- // restore current value
- trap_Cvar_SetValue( cvarptr->name, cvarptr->value );
- }
-}
-
-/*
-=================
-Controls_GetCvarDefault
-=================
-*/
-static float Controls_GetCvarDefault( char* name )
-{
- configcvar_t* cvarptr;
- int i;
-
- cvarptr = g_configcvars;
- for (i=0; ;i++,cvarptr++)
- {
- if (!cvarptr->name)
- return (0);
-
- if (!strcmp(cvarptr->name,name))
- break;
- }
-
- return (cvarptr->defaultvalue);
-}
-
-/*
-=================
-Controls_GetCvarValue
-=================
-*/
-static float Controls_GetCvarValue( char* name )
-{
- configcvar_t* cvarptr;
- int i;
-
- cvarptr = g_configcvars;
- for (i=0; ;i++,cvarptr++)
- {
- if (!cvarptr->name)
- return (0);
-
- if (!strcmp(cvarptr->name,name))
- break;
- }
-
- return (cvarptr->value);
-}
-
-
-/*
-=================
-Controls_UpdateModel
-=================
-*/
-static void Controls_UpdateModel( int anim ) {
- VectorClear( s_controls.playerViewangles );
- VectorClear( s_controls.playerMoveangles );
- s_controls.playerViewangles[YAW] = 180 - 30;
- s_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW];
- s_controls.playerLegs = LEGS_IDLE;
- s_controls.playerTorso = TORSO_STAND;
- s_controls.playerWeapon = -1;
- s_controls.playerChat = qfalse;
-
- switch( anim ) {
- case ANIM_RUN:
- s_controls.playerLegs = LEGS_RUN;
- break;
-
- case ANIM_WALK:
- s_controls.playerLegs = LEGS_WALK;
- break;
-
- case ANIM_BACK:
- s_controls.playerLegs = LEGS_BACK;
- break;
-
- case ANIM_JUMP:
- s_controls.playerLegs = LEGS_JUMP;
- break;
-
- case ANIM_CROUCH:
- s_controls.playerLegs = LEGS_IDLECR;
- break;
-
- case ANIM_TURNLEFT:
- s_controls.playerViewangles[YAW] += 90;
- break;
-
- case ANIM_TURNRIGHT:
- s_controls.playerViewangles[YAW] -= 90;
- break;
-
- case ANIM_STEPLEFT:
- s_controls.playerLegs = LEGS_WALK;
- s_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW] + 90;
- break;
-
- case ANIM_STEPRIGHT:
- s_controls.playerLegs = LEGS_WALK;
- s_controls.playerMoveangles[YAW] = s_controls.playerViewangles[YAW] - 90;
- break;
-
- case ANIM_LOOKUP:
- s_controls.playerViewangles[PITCH] = -45;
- break;
-
- case ANIM_LOOKDOWN:
- s_controls.playerViewangles[PITCH] = 45;
- break;
-
- case ANIM_WEAPON1:
- s_controls.playerWeapon = WP_GAUNTLET;
- break;
-
- case ANIM_WEAPON2:
- s_controls.playerWeapon = WP_MACHINEGUN;
- break;
-
- case ANIM_WEAPON3:
- s_controls.playerWeapon = WP_SHOTGUN;
- break;
-
- case ANIM_WEAPON4:
- s_controls.playerWeapon = WP_GRENADE_LAUNCHER;
- break;
-
- case ANIM_WEAPON5:
- s_controls.playerWeapon = WP_ROCKET_LAUNCHER;
- break;
-
- case ANIM_WEAPON6:
- s_controls.playerWeapon = WP_LIGHTNING;
- break;
-
- case ANIM_WEAPON7:
- s_controls.playerWeapon = WP_RAILGUN;
- break;
-
- case ANIM_WEAPON8:
- s_controls.playerWeapon = WP_PLASMAGUN;
- break;
-
- case ANIM_WEAPON9:
- s_controls.playerWeapon = WP_BFG;
- break;
-
- case ANIM_WEAPON10:
- s_controls.playerWeapon = WP_GRAPPLING_HOOK;
- break;
-
- case ANIM_WEAPON11:
- s_controls.playerWeapon = WP_NAILGUN;
- break;
-
- case ANIM_WEAPON12:
- s_controls.playerWeapon = WP_PROX_LAUNCHER;
- break;
-
- case ANIM_WEAPON13:
- s_controls.playerWeapon = WP_CHAINGUN;
- break;
-
- case ANIM_ATTACK:
- s_controls.playerTorso = TORSO_ATTACK;
- break;
-
- case ANIM_GESTURE:
- s_controls.playerTorso = TORSO_GESTURE;
- break;
-
- case ANIM_DIE:
- s_controls.playerLegs = BOTH_DEATH1;
- s_controls.playerTorso = BOTH_DEATH1;
- s_controls.playerWeapon = WP_NONE;
- break;
-
- case ANIM_CHAT:
- s_controls.playerChat = qtrue;
- break;
-
- default:
- break;
- }
-
- UI_PlayerInfo_SetInfo( &s_controls.playerinfo, s_controls.playerLegs, s_controls.playerTorso, s_controls.playerViewangles, s_controls.playerMoveangles, s_controls.playerWeapon, s_controls.playerChat );
-}
-
-
-/*
-=================
-Controls_Update
-=================
-*/
-static void Controls_Update( void ) {
- int i;
- int j;
- int y;
- menucommon_s **controls;
- menucommon_s *control;
-
- // disable all controls in all groups
- for( i = 0; i < C_MAX; i++ ) {
- controls = g_controls[i];
- // bk001204 - parentheses
- for( j = 0; (control = controls[j]) ; j++ ) {
- control->flags |= (QMF_HIDDEN|QMF_INACTIVE);
- }
- }
-
- controls = g_controls[s_controls.section];
-
- // enable controls in active group (and count number of items for vertical centering)
- // bk001204 - parentheses
- for( j = 0; (control = controls[j]) ; j++ ) {
- control->flags &= ~(QMF_GRAYED|QMF_HIDDEN|QMF_INACTIVE);
- }
-
- // position controls
- y = ( SCREEN_HEIGHT - j * SMALLCHAR_HEIGHT ) / 2;
- // bk001204 - parentheses
- for( j = 0; (control = controls[j]) ; j++, y += SMALLCHAR_HEIGHT ) {
- control->x = 320;
- control->y = y;
- control->left = 320 - 19*SMALLCHAR_WIDTH;
- control->right = 320 + 21*SMALLCHAR_WIDTH;
- control->top = y;
- control->bottom = y + SMALLCHAR_HEIGHT;
- }
-
- if( s_controls.waitingforkey ) {
- // disable everybody
- for( i = 0; i < s_controls.menu.nitems; i++ ) {
- ((menucommon_s*)(s_controls.menu.items[i]))->flags |= QMF_GRAYED;
- }
-
- // enable action item
- ((menucommon_s*)(s_controls.menu.items[s_controls.menu.cursor]))->flags &= ~QMF_GRAYED;
-
- // don't gray out player's name
- s_controls.name.generic.flags &= ~QMF_GRAYED;
-
- return;
- }
-
- // enable everybody
- for( i = 0; i < s_controls.menu.nitems; i++ ) {
- ((menucommon_s*)(s_controls.menu.items[i]))->flags &= ~QMF_GRAYED;
- }
-
- // makes sure flags are right on the group selection controls
- s_controls.looking.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- s_controls.movement.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- s_controls.weapons.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- s_controls.misc.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
-
- s_controls.looking.generic.flags |= QMF_PULSEIFFOCUS;
- s_controls.movement.generic.flags |= QMF_PULSEIFFOCUS;
- s_controls.weapons.generic.flags |= QMF_PULSEIFFOCUS;
- s_controls.misc.generic.flags |= QMF_PULSEIFFOCUS;
-
- // set buttons
- switch( s_controls.section ) {
- case C_MOVEMENT:
- s_controls.movement.generic.flags &= ~QMF_PULSEIFFOCUS;
- s_controls.movement.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- break;
-
- case C_LOOKING:
- s_controls.looking.generic.flags &= ~QMF_PULSEIFFOCUS;
- s_controls.looking.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- break;
-
- case C_WEAPONS:
- s_controls.weapons.generic.flags &= ~QMF_PULSEIFFOCUS;
- s_controls.weapons.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- break;
-
- case C_MISC:
- s_controls.misc.generic.flags &= ~QMF_PULSEIFFOCUS;
- s_controls.misc.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
- break;
- }
-}
-
-
-/*
-=================
-Controls_DrawKeyBinding
-=================
-*/
-static void Controls_DrawKeyBinding( void *self )
-{
- menuaction_s* a;
- int x;
- int y;
- int b1;
- int b2;
- qboolean c;
- char name[32];
- char name2[32];
-
- a = (menuaction_s*) self;
-
- x = a->generic.x;
- y = a->generic.y;
-
- c = (Menu_ItemAtCursor( a->generic.parent ) == a);
-
- b1 = g_bindings[a->generic.id].bind1;
- if (b1 == -1)
- strcpy(name,"???");
- else
- {
- trap_Key_KeynumToStringBuf( b1, name, 32 );
- Q_strupr(name);
-
- b2 = g_bindings[a->generic.id].bind2;
- if (b2 != -1)
- {
- trap_Key_KeynumToStringBuf( b2, name2, 32 );
- Q_strupr(name2);
-
- strcat( name, " or " );
- strcat( name, name2 );
- }
- }
-
- if (c)
- {
- UI_FillRect( a->generic.left, a->generic.top, a->generic.right-a->generic.left+1, a->generic.bottom-a->generic.top+1, listbar_color );
-
- UI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, text_color_highlight );
- UI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT|UI_PULSE, text_color_highlight );
-
- if (s_controls.waitingforkey)
- {
- UI_DrawChar( x, y, '=', UI_CENTER|UI_BLINK|UI_SMALLFONT, text_color_highlight);
- UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.80, "Waiting for new key ... ESCAPE to cancel", UI_SMALLFONT|UI_CENTER|UI_PULSE, colorWhite );
- }
- else
- {
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, text_color_highlight);
- UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.78, "Press ENTER or CLICK to change", UI_SMALLFONT|UI_CENTER, colorWhite );
- UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.82, "Press BACKSPACE to clear", UI_SMALLFONT|UI_CENTER, colorWhite );
- }
- }
- else
- {
- if (a->generic.flags & QMF_GRAYED)
- {
- UI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, text_color_disabled );
- UI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT, text_color_disabled );
- }
- else
- {
- UI_DrawString( x - SMALLCHAR_WIDTH, y, g_bindings[a->generic.id].label, UI_RIGHT|UI_SMALLFONT, controls_binding_color );
- UI_DrawString( x + SMALLCHAR_WIDTH, y, name, UI_LEFT|UI_SMALLFONT, controls_binding_color );
- }
- }
-}
-
-/*
-=================
-Controls_StatusBar
-=================
-*/
-static void Controls_StatusBar( void *self )
-{
- UI_DrawString(SCREEN_WIDTH * 0.50, SCREEN_HEIGHT * 0.80, "Use Arrow Keys or CLICK to change", UI_SMALLFONT|UI_CENTER, colorWhite );
-}
-
-
-/*
-=================
-Controls_DrawPlayer
-=================
-*/
-static void Controls_DrawPlayer( void *self ) {
- menubitmap_s *b;
- char buf[MAX_QPATH];
-
- trap_Cvar_VariableStringBuffer( "model", buf, sizeof( buf ) );
- if ( strcmp( buf, s_controls.playerModel ) != 0 ) {
- UI_PlayerInfo_SetModel( &s_controls.playerinfo, buf );
- strcpy( s_controls.playerModel, buf );
- Controls_UpdateModel( ANIM_IDLE );
- }
-
- b = (menubitmap_s*) self;
- UI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_controls.playerinfo, uis.realtime/2 );
-}
-
-
-/*
-=================
-Controls_GetKeyAssignment
-=================
-*/
-static void Controls_GetKeyAssignment (char *command, int *twokeys)
-{
- int count;
- int j;
- char b[256];
-
- twokeys[0] = twokeys[1] = -1;
- count = 0;
-
- for ( j = 0; j < 256; j++ )
- {
- trap_Key_GetBindingBuf( j, b, 256 );
- if ( *b == 0 ) {
- continue;
- }
- if ( !Q_stricmp( b, command ) ) {
- twokeys[count] = j;
- count++;
- if (count == 2)
- break;
- }
- }
-}
-
-/*
-=================
-Controls_GetConfig
-=================
-*/
-static void Controls_GetConfig( void )
-{
- int i;
- int twokeys[2];
- bind_t* bindptr;
-
- // put the bindings into a local store
- bindptr = g_bindings;
-
- // iterate each command, get its numeric binding
- for (i=0; ;i++,bindptr++)
- {
- if (!bindptr->label)
- break;
-
- Controls_GetKeyAssignment(bindptr->command, twokeys);
-
- bindptr->bind1 = twokeys[0];
- bindptr->bind2 = twokeys[1];
- }
-
- s_controls.invertmouse.curvalue = Controls_GetCvarValue( "m_pitch" ) < 0;
- s_controls.smoothmouse.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "m_filter" ) );
- s_controls.alwaysrun.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_run" ) );
- s_controls.autoswitch.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_autoswitch" ) );
- s_controls.sensitivity.curvalue = UI_ClampCvar( 2, 30, Controls_GetCvarValue( "sensitivity" ) );
- s_controls.joyenable.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "in_joystick" ) );
- s_controls.joythreshold.curvalue = UI_ClampCvar( 0.05f, 0.75f, Controls_GetCvarValue( "joy_threshold" ) );
- s_controls.freelook.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_freelook" ) );
- s_controls.voip_teamonly.curvalue= UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_voipTeamOnly" ) );
-}
-
-/*
-=================
-Controls_SetConfig
-=================
-*/
-static void Controls_SetConfig( void )
-{
- int i;
- bind_t* bindptr;
-
- // set the bindings from the local store
- bindptr = g_bindings;
-
- // iterate each command, get its numeric binding
- for (i=0; ;i++,bindptr++)
- {
- if (!bindptr->label)
- break;
-
- if (bindptr->bind1 != -1)
- {
- trap_Key_SetBinding( bindptr->bind1, bindptr->command );
-
- if (bindptr->bind2 != -1)
- trap_Key_SetBinding( bindptr->bind2, bindptr->command );
- }
- }
-
- if ( s_controls.invertmouse.curvalue )
- trap_Cvar_SetValue( "m_pitch", -fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
- else
- trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
-
- trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue );
- trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue );
- trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue );
- trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue );
- trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue );
- trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue );
- trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue );
- trap_Cvar_SetValue( "cg_voipTeamOnly", s_controls.voip_teamonly.curvalue);
- trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" );
-}
-
-/*
-=================
-Controls_SetDefaults
-=================
-*/
-static void Controls_SetDefaults( void )
-{
- int i;
- bind_t* bindptr;
-
- // set the bindings from the local store
- bindptr = g_bindings;
-
- // iterate each command, set its default binding
- for (i=0; ;i++,bindptr++)
- {
- if (!bindptr->label)
- break;
-
- bindptr->bind1 = bindptr->defaultbind1;
- bindptr->bind2 = bindptr->defaultbind2;
- }
-
- s_controls.invertmouse.curvalue = Controls_GetCvarDefault( "m_pitch" ) < 0;
- s_controls.smoothmouse.curvalue = Controls_GetCvarDefault( "m_filter" );
- s_controls.alwaysrun.curvalue = Controls_GetCvarDefault( "cl_run" );
- s_controls.autoswitch.curvalue = Controls_GetCvarDefault( "cg_autoswitch" );
- s_controls.sensitivity.curvalue = Controls_GetCvarDefault( "sensitivity" );
- s_controls.joyenable.curvalue = Controls_GetCvarDefault( "in_joystick" );
- s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" );
- s_controls.freelook.curvalue = Controls_GetCvarDefault( "cl_freelook" );
- s_controls.voip_teamonly.curvalue= Controls_GetCvarDefault( "cg_voipTeamOnly");
-}
-
-/*
-=================
-Controls_MenuKey
-=================
-*/
-static sfxHandle_t Controls_MenuKey( int key )
-{
- int id;
- int i;
- qboolean found;
- bind_t* bindptr;
- found = qfalse;
-
- if (!s_controls.waitingforkey)
- {
- switch (key)
- {
- case K_BACKSPACE:
- case K_DEL:
- case K_KP_DEL:
- key = -1;
- break;
-
- case K_MOUSE2:
- case K_ESCAPE:
- if (s_controls.changesmade)
- Controls_SetConfig();
- goto ignorekey;
-
- default:
- goto ignorekey;
- }
- }
- else
- {
- if (key & K_CHAR_FLAG)
- goto ignorekey;
-
- switch (key)
- {
- case K_ESCAPE:
- s_controls.waitingforkey = qfalse;
- Controls_Update();
- return (menu_out_sound);
-
- case '`':
- goto ignorekey;
- }
- }
-
- s_controls.changesmade = qtrue;
-
- if (key != -1)
- {
- // remove from any other bind
- bindptr = g_bindings;
- for (i=0; ;i++,bindptr++)
- {
- if (!bindptr->label)
- break;
-
- if (bindptr->bind2 == key)
- bindptr->bind2 = -1;
-
- if (bindptr->bind1 == key)
- {
- bindptr->bind1 = bindptr->bind2;
- bindptr->bind2 = -1;
- }
- }
- }
-
- // assign key to local store
- id = ((menucommon_s*)(s_controls.menu.items[s_controls.menu.cursor]))->id;
- bindptr = g_bindings;
- for (i=0; ;i++,bindptr++)
- {
- if (!bindptr->label)
- break;
-
- if (bindptr->id == id)
- {
- found = qtrue;
- if (key == -1)
- {
- if( bindptr->bind1 != -1 ) {
- trap_Key_SetBinding( bindptr->bind1, "" );
- bindptr->bind1 = -1;
- }
- if( bindptr->bind2 != -1 ) {
- trap_Key_SetBinding( bindptr->bind2, "" );
- bindptr->bind2 = -1;
- }
- }
- else if (bindptr->bind1 == -1) {
- bindptr->bind1 = key;
- }
- else if (bindptr->bind1 != key && bindptr->bind2 == -1) {
- bindptr->bind2 = key;
- }
- else
- {
- trap_Key_SetBinding( bindptr->bind1, "" );
- trap_Key_SetBinding( bindptr->bind2, "" );
- bindptr->bind1 = key;
- bindptr->bind2 = -1;
- }
- break;
- }
- }
-
- s_controls.waitingforkey = qfalse;
-
- if (found)
- {
- Controls_Update();
- return (menu_out_sound);
- }
-
-ignorekey:
- return Menu_DefaultKey( &s_controls.menu, key );
-}
-
-/*
-=================
-Controls_ResetDefaults_Action
-=================
-*/
-static void Controls_ResetDefaults_Action( qboolean result ) {
- if( !result ) {
- return;
- }
-
- s_controls.changesmade = qtrue;
- Controls_SetDefaults();
- Controls_Update();
-}
-
-/*
-=================
-Controls_ResetDefaults_Draw
-=================
-*/
-static void Controls_ResetDefaults_Draw( void ) {
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, "WARNING: This will reset all", UI_CENTER|UI_SMALLFONT, color_yellow );
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, "controls to their default values.", UI_CENTER|UI_SMALLFONT, color_yellow );
-}
-
-/*
-=================
-Controls_MenuEvent
-=================
-*/
-static void Controls_MenuEvent( void* ptr, int event )
-{
- switch (((menucommon_s*)ptr)->id)
- {
- case ID_MOVEMENT:
- if (event == QM_ACTIVATED)
- {
- s_controls.section = C_MOVEMENT;
- Controls_Update();
- }
- break;
-
- case ID_LOOKING:
- if (event == QM_ACTIVATED)
- {
- s_controls.section = C_LOOKING;
- Controls_Update();
- }
- break;
-
- case ID_WEAPONS:
- if (event == QM_ACTIVATED)
- {
- s_controls.section = C_WEAPONS;
- Controls_Update();
- }
- break;
-
- case ID_MISC:
- if (event == QM_ACTIVATED)
- {
- s_controls.section = C_MISC;
- Controls_Update();
- }
- break;
-
- case ID_DEFAULTS:
- if (event == QM_ACTIVATED)
- {
- UI_ConfirmMenu( "SET TO DEFAULTS?", Controls_ResetDefaults_Draw, Controls_ResetDefaults_Action );
- }
- break;
-
- case ID_BACK:
- if (event == QM_ACTIVATED)
- {
- if (s_controls.changesmade)
- Controls_SetConfig();
- UI_PopMenu();
- }
- break;
-
- case ID_SAVEANDEXIT:
- if (event == QM_ACTIVATED)
- {
- Controls_SetConfig();
- UI_PopMenu();
- }
- break;
-
- case ID_EXIT:
- if (event == QM_ACTIVATED)
- {
- UI_PopMenu();
- }
- break;
-
- case ID_FREELOOK:
- case ID_MOUSESPEED:
- case ID_INVERTMOUSE:
- case ID_SMOOTHMOUSE:
- case ID_ALWAYSRUN:
- case ID_AUTOSWITCH:
- case ID_VOIP_TEAMONLY:
- case ID_JOYENABLE:
- case ID_JOYTHRESHOLD:
- if (event == QM_ACTIVATED)
- {
- s_controls.changesmade = qtrue;
- }
- break;
- }
-}
-
-/*
-=================
-Controls_ActionEvent
-=================
-*/
-static void Controls_ActionEvent( void* ptr, int event )
-{
- if (event == QM_LOSTFOCUS)
- {
- Controls_UpdateModel( ANIM_IDLE );
- }
- else if (event == QM_GOTFOCUS)
- {
- Controls_UpdateModel( g_bindings[((menucommon_s*)ptr)->id].anim );
- }
- else if ((event == QM_ACTIVATED) && !s_controls.waitingforkey)
- {
- s_controls.waitingforkey = 1;
- Controls_Update();
- }
-}
-
-/*
-=================
-Controls_InitModel
-=================
-*/
-static void Controls_InitModel( void )
-{
- memset( &s_controls.playerinfo, 0, sizeof(playerInfo_t) );
-
- UI_PlayerInfo_SetModel( &s_controls.playerinfo, UI_Cvar_VariableString( "model" ) );
-
- Controls_UpdateModel( ANIM_IDLE );
-}
-
-/*
-=================
-Controls_InitWeapons
-=================
-*/
-static void Controls_InitWeapons( void ) {
- gitem_t * item;
-
- for ( item = bg_itemlist + 1 ; item->classname ; item++ ) {
- if ( item->giType != IT_WEAPON ) {
- continue;
- }
- trap_R_RegisterModel( item->world_model[0] );
- }
-}
-
-/*
-=================
-Controls_MenuInit
-=================
-*/
-static void Controls_MenuInit( void )
-{
- static char playername[32];
-
- // zero set all our globals
- memset( &s_controls, 0 ,sizeof(controls_t) );
-
- Controls_Cache();
-
- s_controls.menu.key = Controls_MenuKey;
- s_controls.menu.wrapAround = qtrue;
- s_controls.menu.fullscreen = qtrue;
-
- s_controls.banner.generic.type = MTYPE_BTEXT;
- s_controls.banner.generic.flags = QMF_CENTER_JUSTIFY;
- s_controls.banner.generic.x = 320;
- s_controls.banner.generic.y = 16;
- s_controls.banner.string = "CONTROLS";
- s_controls.banner.color = color_white;
- s_controls.banner.style = UI_CENTER;
-
- s_controls.framel.generic.type = MTYPE_BITMAP;
- s_controls.framel.generic.name = ART_FRAMEL;
- s_controls.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_controls.framel.generic.x = 0;
- s_controls.framel.generic.y = 78;
- s_controls.framel.width = 256;
- s_controls.framel.height = 329;
-
- s_controls.framer.generic.type = MTYPE_BITMAP;
- s_controls.framer.generic.name = ART_FRAMER;
- s_controls.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_controls.framer.generic.x = 376;
- s_controls.framer.generic.y = 76;
- s_controls.framer.width = 256;
- s_controls.framer.height = 334;
-
- s_controls.looking.generic.type = MTYPE_PTEXT;
- s_controls.looking.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_controls.looking.generic.id = ID_LOOKING;
- s_controls.looking.generic.callback = Controls_MenuEvent;
- s_controls.looking.generic.x = 152;
- s_controls.looking.generic.y = 240 - 2 * PROP_HEIGHT;
- s_controls.looking.string = "LOOK";
- s_controls.looking.style = UI_RIGHT;
- s_controls.looking.color = color_red;
-
- s_controls.movement.generic.type = MTYPE_PTEXT;
- s_controls.movement.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_controls.movement.generic.id = ID_MOVEMENT;
- s_controls.movement.generic.callback = Controls_MenuEvent;
- s_controls.movement.generic.x = 152;
- s_controls.movement.generic.y = 240 - PROP_HEIGHT;
- s_controls.movement.string = "MOVE";
- s_controls.movement.style = UI_RIGHT;
- s_controls.movement.color = color_red;
-
- s_controls.weapons.generic.type = MTYPE_PTEXT;
- s_controls.weapons.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_controls.weapons.generic.id = ID_WEAPONS;
- s_controls.weapons.generic.callback = Controls_MenuEvent;
- s_controls.weapons.generic.x = 152;
- s_controls.weapons.generic.y = 240;
- s_controls.weapons.string = "SHOOT";
- s_controls.weapons.style = UI_RIGHT;
- s_controls.weapons.color = color_red;
-
- s_controls.misc.generic.type = MTYPE_PTEXT;
- s_controls.misc.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_controls.misc.generic.id = ID_MISC;
- s_controls.misc.generic.callback = Controls_MenuEvent;
- s_controls.misc.generic.x = 152;
- s_controls.misc.generic.y = 240 + PROP_HEIGHT;
- s_controls.misc.string = "MISC";
- s_controls.misc.style = UI_RIGHT;
- s_controls.misc.color = color_red;
-
- s_controls.back.generic.type = MTYPE_BITMAP;
- s_controls.back.generic.name = ART_BACK0;
- s_controls.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_controls.back.generic.x = 0;
- s_controls.back.generic.y = 480-64;
- s_controls.back.generic.id = ID_BACK;
- s_controls.back.generic.callback = Controls_MenuEvent;
- s_controls.back.width = 128;
- s_controls.back.height = 64;
- s_controls.back.focuspic = ART_BACK1;
-
- s_controls.player.generic.type = MTYPE_BITMAP;
- s_controls.player.generic.flags = QMF_INACTIVE;
- s_controls.player.generic.ownerdraw = Controls_DrawPlayer;
- s_controls.player.generic.x = 400;
- s_controls.player.generic.y = -40;
- s_controls.player.width = 32*10;
- s_controls.player.height = 56*10;
-
- s_controls.walkforward.generic.type = MTYPE_ACTION;
- s_controls.walkforward.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.walkforward.generic.callback = Controls_ActionEvent;
- s_controls.walkforward.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.walkforward.generic.id = ID_FORWARD;
-
- s_controls.backpedal.generic.type = MTYPE_ACTION;
- s_controls.backpedal.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.backpedal.generic.callback = Controls_ActionEvent;
- s_controls.backpedal.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.backpedal.generic.id = ID_BACKPEDAL;
-
- s_controls.stepleft.generic.type = MTYPE_ACTION;
- s_controls.stepleft.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.stepleft.generic.callback = Controls_ActionEvent;
- s_controls.stepleft.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.stepleft.generic.id = ID_MOVELEFT;
-
- s_controls.stepright.generic.type = MTYPE_ACTION;
- s_controls.stepright.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.stepright.generic.callback = Controls_ActionEvent;
- s_controls.stepright.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.stepright.generic.id = ID_MOVERIGHT;
-
- s_controls.moveup.generic.type = MTYPE_ACTION;
- s_controls.moveup.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.moveup.generic.callback = Controls_ActionEvent;
- s_controls.moveup.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.moveup.generic.id = ID_MOVEUP;
-
- s_controls.movedown.generic.type = MTYPE_ACTION;
- s_controls.movedown.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.movedown.generic.callback = Controls_ActionEvent;
- s_controls.movedown.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.movedown.generic.id = ID_MOVEDOWN;
-
- s_controls.turnleft.generic.type = MTYPE_ACTION;
- s_controls.turnleft.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.turnleft.generic.callback = Controls_ActionEvent;
- s_controls.turnleft.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.turnleft.generic.id = ID_LEFT;
-
- s_controls.turnright.generic.type = MTYPE_ACTION;
- s_controls.turnright.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.turnright.generic.callback = Controls_ActionEvent;
- s_controls.turnright.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.turnright.generic.id = ID_RIGHT;
-
- s_controls.sidestep.generic.type = MTYPE_ACTION;
- s_controls.sidestep.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.sidestep.generic.callback = Controls_ActionEvent;
- s_controls.sidestep.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.sidestep.generic.id = ID_STRAFE;
-
- s_controls.run.generic.type = MTYPE_ACTION;
- s_controls.run.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.run.generic.callback = Controls_ActionEvent;
- s_controls.run.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.run.generic.id = ID_SPEED;
-
- s_controls.chainsaw.generic.type = MTYPE_ACTION;
- s_controls.chainsaw.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.chainsaw.generic.callback = Controls_ActionEvent;
- s_controls.chainsaw.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.chainsaw.generic.id = ID_WEAPON1;
-
- s_controls.machinegun.generic.type = MTYPE_ACTION;
- s_controls.machinegun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.machinegun.generic.callback = Controls_ActionEvent;
- s_controls.machinegun.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.machinegun.generic.id = ID_WEAPON2;
-
- s_controls.shotgun.generic.type = MTYPE_ACTION;
- s_controls.shotgun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.shotgun.generic.callback = Controls_ActionEvent;
- s_controls.shotgun.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.shotgun.generic.id = ID_WEAPON3;
-
- s_controls.grenadelauncher.generic.type = MTYPE_ACTION;
- s_controls.grenadelauncher.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.grenadelauncher.generic.callback = Controls_ActionEvent;
- s_controls.grenadelauncher.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.grenadelauncher.generic.id = ID_WEAPON4;
-
- s_controls.rocketlauncher.generic.type = MTYPE_ACTION;
- s_controls.rocketlauncher.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.rocketlauncher.generic.callback = Controls_ActionEvent;
- s_controls.rocketlauncher.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.rocketlauncher.generic.id = ID_WEAPON5;
-
- s_controls.lightning.generic.type = MTYPE_ACTION;
- s_controls.lightning.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.lightning.generic.callback = Controls_ActionEvent;
- s_controls.lightning.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.lightning.generic.id = ID_WEAPON6;
-
- s_controls.railgun.generic.type = MTYPE_ACTION;
- s_controls.railgun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.railgun.generic.callback = Controls_ActionEvent;
- s_controls.railgun.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.railgun.generic.id = ID_WEAPON7;
-
- s_controls.plasma.generic.type = MTYPE_ACTION;
- s_controls.plasma.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.plasma.generic.callback = Controls_ActionEvent;
- s_controls.plasma.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.plasma.generic.id = ID_WEAPON8;
-
- s_controls.bfg.generic.type = MTYPE_ACTION;
- s_controls.bfg.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.bfg.generic.callback = Controls_ActionEvent;
- s_controls.bfg.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.bfg.generic.id = ID_WEAPON9;
-
- s_controls.grapple.generic.type = MTYPE_ACTION;
- s_controls.grapple.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.grapple.generic.callback = Controls_ActionEvent;
- s_controls.grapple.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.grapple.generic.id = ID_WEAPON10;
-
- s_controls.nailgun.generic.type = MTYPE_ACTION;
- s_controls.nailgun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.nailgun.generic.callback = Controls_ActionEvent;
- s_controls.nailgun.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.nailgun.generic.id = ID_WEAPON11;
-
- s_controls.proxmine.generic.type = MTYPE_ACTION;
- s_controls.proxmine.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.proxmine.generic.callback = Controls_ActionEvent;
- s_controls.proxmine.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.proxmine.generic.id = ID_WEAPON12;
-
- s_controls.chaingun.generic.type = MTYPE_ACTION;
- s_controls.chaingun.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.chaingun.generic.callback = Controls_ActionEvent;
- s_controls.chaingun.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.chaingun.generic.id = ID_WEAPON13;
-
- s_controls.attack.generic.type = MTYPE_ACTION;
- s_controls.attack.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.attack.generic.callback = Controls_ActionEvent;
- s_controls.attack.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.attack.generic.id = ID_ATTACK;
-
- s_controls.prevweapon.generic.type = MTYPE_ACTION;
- s_controls.prevweapon.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.prevweapon.generic.callback = Controls_ActionEvent;
- s_controls.prevweapon.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.prevweapon.generic.id = ID_WEAPPREV;
-
- s_controls.nextweapon.generic.type = MTYPE_ACTION;
- s_controls.nextweapon.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.nextweapon.generic.callback = Controls_ActionEvent;
- s_controls.nextweapon.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.nextweapon.generic.id = ID_WEAPNEXT;
-
- s_controls.lookup.generic.type = MTYPE_ACTION;
- s_controls.lookup.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.lookup.generic.callback = Controls_ActionEvent;
- s_controls.lookup.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.lookup.generic.id = ID_LOOKUP;
-
- s_controls.lookdown.generic.type = MTYPE_ACTION;
- s_controls.lookdown.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.lookdown.generic.callback = Controls_ActionEvent;
- s_controls.lookdown.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.lookdown.generic.id = ID_LOOKDOWN;
-
- s_controls.mouselook.generic.type = MTYPE_ACTION;
- s_controls.mouselook.generic.flags = QMF_LEFT_JUSTIFY|QMF_HIGHLIGHT_IF_FOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.mouselook.generic.callback = Controls_ActionEvent;
- s_controls.mouselook.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.mouselook.generic.id = ID_MOUSELOOK;
-
- s_controls.freelook.generic.type = MTYPE_RADIOBUTTON;
- s_controls.freelook.generic.flags = QMF_SMALLFONT;
- s_controls.freelook.generic.x = SCREEN_WIDTH/2;
- s_controls.freelook.generic.name = "free look";
- s_controls.freelook.generic.id = ID_FREELOOK;
- s_controls.freelook.generic.callback = Controls_MenuEvent;
- s_controls.freelook.generic.statusbar = Controls_StatusBar;
-
- s_controls.centerview.generic.type = MTYPE_ACTION;
- s_controls.centerview.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.centerview.generic.callback = Controls_ActionEvent;
- s_controls.centerview.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.centerview.generic.id = ID_CENTERVIEW;
-
- s_controls.zoomview.generic.type = MTYPE_ACTION;
- s_controls.zoomview.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.zoomview.generic.callback = Controls_ActionEvent;
- s_controls.zoomview.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.zoomview.generic.id = ID_ZOOMVIEW;
-
- s_controls.useitem.generic.type = MTYPE_ACTION;
- s_controls.useitem.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.useitem.generic.callback = Controls_ActionEvent;
- s_controls.useitem.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.useitem.generic.id = ID_USEITEM;
-
- s_controls.showscores.generic.type = MTYPE_ACTION;
- s_controls.showscores.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.showscores.generic.callback = Controls_ActionEvent;
- s_controls.showscores.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.showscores.generic.id = ID_SHOWSCORES;
-
- s_controls.invertmouse.generic.type = MTYPE_RADIOBUTTON;
- s_controls.invertmouse.generic.flags = QMF_SMALLFONT;
- s_controls.invertmouse.generic.x = SCREEN_WIDTH/2;
- s_controls.invertmouse.generic.name = "invert mouse";
- s_controls.invertmouse.generic.id = ID_INVERTMOUSE;
- s_controls.invertmouse.generic.callback = Controls_MenuEvent;
- s_controls.invertmouse.generic.statusbar = Controls_StatusBar;
-
- s_controls.smoothmouse.generic.type = MTYPE_RADIOBUTTON;
- s_controls.smoothmouse.generic.flags = QMF_SMALLFONT;
- s_controls.smoothmouse.generic.x = SCREEN_WIDTH/2;
- s_controls.smoothmouse.generic.name = "smooth mouse";
- s_controls.smoothmouse.generic.id = ID_SMOOTHMOUSE;
- s_controls.smoothmouse.generic.callback = Controls_MenuEvent;
- s_controls.smoothmouse.generic.statusbar = Controls_StatusBar;
-
- s_controls.alwaysrun.generic.type = MTYPE_RADIOBUTTON;
- s_controls.alwaysrun.generic.flags = QMF_SMALLFONT;
- s_controls.alwaysrun.generic.x = SCREEN_WIDTH/2;
- s_controls.alwaysrun.generic.name = "always run";
- s_controls.alwaysrun.generic.id = ID_ALWAYSRUN;
- s_controls.alwaysrun.generic.callback = Controls_MenuEvent;
- s_controls.alwaysrun.generic.statusbar = Controls_StatusBar;
-
- s_controls.autoswitch.generic.type = MTYPE_RADIOBUTTON;
- s_controls.autoswitch.generic.flags = QMF_SMALLFONT;
- s_controls.autoswitch.generic.x = SCREEN_WIDTH/2;
- s_controls.autoswitch.generic.name = "autoswitch weapons";
- s_controls.autoswitch.generic.id = ID_AUTOSWITCH;
- s_controls.autoswitch.generic.callback = Controls_MenuEvent;
- s_controls.autoswitch.generic.statusbar = Controls_StatusBar;
-
- s_controls.sensitivity.generic.type = MTYPE_SLIDER;
- s_controls.sensitivity.generic.x = SCREEN_WIDTH/2;
- s_controls.sensitivity.generic.flags = QMF_SMALLFONT;
- s_controls.sensitivity.generic.name = "mouse speed";
- s_controls.sensitivity.generic.id = ID_MOUSESPEED;
- s_controls.sensitivity.generic.callback = Controls_MenuEvent;
- s_controls.sensitivity.minvalue = 2;
- s_controls.sensitivity.maxvalue = 30;
- s_controls.sensitivity.generic.statusbar = Controls_StatusBar;
-
- s_controls.gesture.generic.type = MTYPE_ACTION;
- s_controls.gesture.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.gesture.generic.callback = Controls_ActionEvent;
- s_controls.gesture.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.gesture.generic.id = ID_GESTURE;
-
- s_controls.chat.generic.type = MTYPE_ACTION;
- s_controls.chat.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.chat.generic.callback = Controls_ActionEvent;
- s_controls.chat.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.chat.generic.id = ID_CHAT;
-
- s_controls.chat2.generic.type = MTYPE_ACTION;
- s_controls.chat2.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.chat2.generic.callback = Controls_ActionEvent;
- s_controls.chat2.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.chat2.generic.id = ID_CHAT2;
-
- s_controls.chat3.generic.type = MTYPE_ACTION;
- s_controls.chat3.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.chat3.generic.callback = Controls_ActionEvent;
- s_controls.chat3.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.chat3.generic.id = ID_CHAT3;
-
- s_controls.chat4.generic.type = MTYPE_ACTION;
- s_controls.chat4.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.chat4.generic.callback = Controls_ActionEvent;
- s_controls.chat4.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.chat4.generic.id = ID_CHAT4;
-
- s_controls.voip_talk.generic.type = MTYPE_ACTION;
- s_controls.voip_talk.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
- s_controls.voip_talk.generic.callback = Controls_ActionEvent;
- s_controls.voip_talk.generic.ownerdraw = Controls_DrawKeyBinding;
- s_controls.voip_talk.generic.id = ID_VOIP_TALK;
-
- s_controls.voip_teamonly.generic.type = MTYPE_RADIOBUTTON;
- s_controls.voip_teamonly.generic.flags = QMF_SMALLFONT;
- s_controls.voip_teamonly.generic.x = SCREEN_WIDTH/2;
- s_controls.voip_teamonly.generic.name = "teamonly voicechat";
- s_controls.voip_teamonly.generic.id = ID_VOIP_TEAMONLY;
- s_controls.voip_teamonly.generic.callback = Controls_MenuEvent;
- s_controls.voip_teamonly.generic.statusbar = Controls_StatusBar;
-
- s_controls.joyenable.generic.type = MTYPE_RADIOBUTTON;
- s_controls.joyenable.generic.flags = QMF_SMALLFONT;
- s_controls.joyenable.generic.x = SCREEN_WIDTH/2;
- s_controls.joyenable.generic.name = "joystick";
- s_controls.joyenable.generic.id = ID_JOYENABLE;
- s_controls.joyenable.generic.callback = Controls_MenuEvent;
- s_controls.joyenable.generic.statusbar = Controls_StatusBar;
-
- s_controls.joythreshold.generic.type = MTYPE_SLIDER;
- s_controls.joythreshold.generic.x = SCREEN_WIDTH/2;
- s_controls.joythreshold.generic.flags = QMF_SMALLFONT;
- s_controls.joythreshold.generic.name = "joystick threshold";
- s_controls.joythreshold.generic.id = ID_JOYTHRESHOLD;
- s_controls.joythreshold.generic.callback = Controls_MenuEvent;
- s_controls.joythreshold.minvalue = 0.05f;
- s_controls.joythreshold.maxvalue = 0.75f;
- s_controls.joythreshold.generic.statusbar = Controls_StatusBar;
-
- s_controls.name.generic.type = MTYPE_PTEXT;
- s_controls.name.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
- s_controls.name.generic.x = 320;
- s_controls.name.generic.y = 440;
- s_controls.name.string = playername;
- s_controls.name.style = UI_CENTER;
- s_controls.name.color = text_color_normal;
-
- Menu_AddItem( &s_controls.menu, &s_controls.banner );
- Menu_AddItem( &s_controls.menu, &s_controls.framel );
- Menu_AddItem( &s_controls.menu, &s_controls.framer );
- Menu_AddItem( &s_controls.menu, &s_controls.player );
- Menu_AddItem( &s_controls.menu, &s_controls.name );
-
- Menu_AddItem( &s_controls.menu, &s_controls.looking );
- Menu_AddItem( &s_controls.menu, &s_controls.movement );
- Menu_AddItem( &s_controls.menu, &s_controls.weapons );
- Menu_AddItem( &s_controls.menu, &s_controls.misc );
-
- Menu_AddItem( &s_controls.menu, &s_controls.sensitivity );
- Menu_AddItem( &s_controls.menu, &s_controls.smoothmouse );
- Menu_AddItem( &s_controls.menu, &s_controls.invertmouse );
- Menu_AddItem( &s_controls.menu, &s_controls.lookup );
- Menu_AddItem( &s_controls.menu, &s_controls.lookdown );
- Menu_AddItem( &s_controls.menu, &s_controls.mouselook );
- Menu_AddItem( &s_controls.menu, &s_controls.freelook );
- Menu_AddItem( &s_controls.menu, &s_controls.centerview );
- Menu_AddItem( &s_controls.menu, &s_controls.zoomview );
- Menu_AddItem( &s_controls.menu, &s_controls.joyenable );
- Menu_AddItem( &s_controls.menu, &s_controls.joythreshold );
-
- Menu_AddItem( &s_controls.menu, &s_controls.alwaysrun );
- Menu_AddItem( &s_controls.menu, &s_controls.run );
- Menu_AddItem( &s_controls.menu, &s_controls.walkforward );
- Menu_AddItem( &s_controls.menu, &s_controls.backpedal );
- Menu_AddItem( &s_controls.menu, &s_controls.stepleft );
- Menu_AddItem( &s_controls.menu, &s_controls.stepright );
- Menu_AddItem( &s_controls.menu, &s_controls.moveup );
- Menu_AddItem( &s_controls.menu, &s_controls.movedown );
- Menu_AddItem( &s_controls.menu, &s_controls.turnleft );
- Menu_AddItem( &s_controls.menu, &s_controls.turnright );
- Menu_AddItem( &s_controls.menu, &s_controls.sidestep );
-
- Menu_AddItem( &s_controls.menu, &s_controls.attack );
- Menu_AddItem( &s_controls.menu, &s_controls.nextweapon );
- Menu_AddItem( &s_controls.menu, &s_controls.prevweapon );
- Menu_AddItem( &s_controls.menu, &s_controls.autoswitch );
- Menu_AddItem( &s_controls.menu, &s_controls.chainsaw );
- Menu_AddItem( &s_controls.menu, &s_controls.machinegun );
- Menu_AddItem( &s_controls.menu, &s_controls.shotgun );
- Menu_AddItem( &s_controls.menu, &s_controls.grenadelauncher );
- Menu_AddItem( &s_controls.menu, &s_controls.rocketlauncher );
- Menu_AddItem( &s_controls.menu, &s_controls.lightning );
- Menu_AddItem( &s_controls.menu, &s_controls.railgun );
- Menu_AddItem( &s_controls.menu, &s_controls.plasma );
- Menu_AddItem( &s_controls.menu, &s_controls.bfg );
- Menu_AddItem( &s_controls.menu, &s_controls.grapple );
- Menu_AddItem( &s_controls.menu, &s_controls.nailgun );
- Menu_AddItem( &s_controls.menu, &s_controls.proxmine );
- Menu_AddItem( &s_controls.menu, &s_controls.chaingun );
-
- Menu_AddItem( &s_controls.menu, &s_controls.showscores );
- Menu_AddItem( &s_controls.menu, &s_controls.useitem );
- Menu_AddItem( &s_controls.menu, &s_controls.gesture );
- Menu_AddItem( &s_controls.menu, &s_controls.chat );
- Menu_AddItem( &s_controls.menu, &s_controls.chat2 );
- Menu_AddItem( &s_controls.menu, &s_controls.chat3 );
- Menu_AddItem( &s_controls.menu, &s_controls.chat4 );
- Menu_AddItem( &s_controls.menu, &s_controls.voip_talk );
- Menu_AddItem( &s_controls.menu, &s_controls.voip_teamonly );
-
- Menu_AddItem( &s_controls.menu, &s_controls.back );
-
- trap_Cvar_VariableStringBuffer( "name", s_controls.name.string, 16 );
- Q_CleanStr( s_controls.name.string );
-
- // initialize the configurable cvars
- Controls_InitCvars();
-
- // initialize the current config
- Controls_GetConfig();
-
- // intialize the model
- Controls_InitModel();
-
- // intialize the weapons
- Controls_InitWeapons ();
-
- // initial default section
- s_controls.section = C_LOOKING;
-
- // update the ui
- Controls_Update();
-}
-
-
-/*
-=================
-Controls_Cache
-=================
-*/
-void Controls_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
-}
-
-
-/*
-=================
-UI_ControlsMenu
-=================
-*/
-void UI_ControlsMenu( void ) {
- Controls_MenuInit();
- UI_PushMenu( &s_controls.menu );
-}
diff --git a/game/code/q3_ui/ui_credits.c b/game/code/q3_ui/ui_credits.c
deleted file mode 100644
index e6c0501..0000000
--- a/game/code/q3_ui/ui_credits.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-CREDITS
-
-=======================================================================
-*/
-
-/*
- *Sago 2008-06-29: This is kinda annoying and does not really give usefull information anyway
- */
-
-
-#include "ui_local.h"
-
-
-typedef struct {
- menuframework_s menu;
-} creditsmenu_t;
-
-static creditsmenu_t s_credits;
-
-
-/*
-=================
-UI_CreditMenu_Key
-=================
-*/
-static sfxHandle_t UI_CreditMenu_Key( int key ) {
- if( key & K_CHAR_FLAG ) {
- return 0;
- }
-
- //Sago: I no longer show credits on close. Consider something else if ingame credits are to be made
- //trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
- return 0;
-}
-
-
-/*
-===============
-UI_CreditMenu_Draw
-===============
-*/
-static void UI_CreditMenu_Draw( void ) {
- int y;
-
- y = 12;
- UI_DrawProportionalString( 320, y, "Thank you for playing", UI_CENTER|UI_SMALLFONT, color_white );
- y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "Open Arena", UI_CENTER|UI_SMALLFONT, color_white );
-
- //y += 28;
- //UI_DrawString( 320, y, "Click or press any key to quit", UI_CENTER|UI_SMALLFONT, color_red );
-
- y = 480 - PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
- UI_DrawProportionalString( 320, y, "www.openarena.ws", UI_CENTER|UI_SMALLFONT, color_white );
-}
-
-
-/*
-===============
-UI_CreditMenu
-===============
-*/
-void UI_CreditMenu( void ) {
- memset( &s_credits, 0 ,sizeof(s_credits) );
-
- s_credits.menu.draw = UI_CreditMenu_Draw;
- s_credits.menu.key = UI_CreditMenu_Key;
- s_credits.menu.fullscreen = qtrue;
- UI_PushMenu ( &s_credits.menu );
-}
diff --git a/game/code/q3_ui/ui_gameinfo.c b/game/code/q3_ui/ui_gameinfo.c
deleted file mode 100644
index fe2228e..0000000
--- a/game/code/q3_ui/ui_gameinfo.c
+++ /dev/null
@@ -1,815 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-//
-// gameinfo.c
-//
-
-#include "ui_local.h"
-
-
-//
-// arena and bot info
-//
-
-#define POOLSIZE 128 * 1024
-
-int ui_numBots;
-static char *ui_botInfos[MAX_BOTS];
-
-static int ui_numArenas;
-static char *ui_arenaInfos[MAX_ARENAS];
-
-static int ui_numSinglePlayerArenas;
-static int ui_numSpecialSinglePlayerArenas;
-
-static char memoryPool[POOLSIZE];
-static int allocPoint, outOfMemory;
-
-
-/*
-===============
-UI_Alloc
-===============
-*/
-void *UI_Alloc( int size ) {
- char *p;
-
- if ( allocPoint + size > POOLSIZE ) {
- outOfMemory = qtrue;
- return NULL;
- }
-
- p = &memoryPool[allocPoint];
-
- allocPoint += ( size + 31 ) & ~31;
-
- return p;
-}
-
-/*
-===============
-UI_InitMemory
-===============
-*/
-void UI_InitMemory( void ) {
- allocPoint = 0;
- outOfMemory = qfalse;
-}
-
-/*
-===============
-UI_ParseInfos
-===============
-*/
-int UI_ParseInfos( char *buf, int max, char *infos[] ) {
- char *token;
- int count;
- char key[MAX_TOKEN_CHARS];
- char info[MAX_INFO_STRING];
-
- count = 0;
-
- while ( 1 ) {
- token = COM_Parse( &buf );
- if ( !token[0] ) {
- break;
- }
- if ( strcmp( token, "{" ) ) {
- Com_Printf( "Missing { in info file\n" );
- break;
- }
-
- if ( count == max ) {
- Com_Printf( "Max infos exceeded\n" );
- break;
- }
-
- info[0] = '\0';
- while ( 1 ) {
- token = COM_ParseExt( &buf, qtrue );
- if ( !token[0] ) {
- Com_Printf( "Unexpected end of info file\n" );
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- Q_strncpyz( key, token, sizeof( key ) );
-
- token = COM_ParseExt( &buf, qfalse );
- if ( !token[0] ) {
- strcpy( token, "<NULL>" );
- }
- Info_SetValueForKey( info, key, token );
- }
- //NOTE: extra space for arena number
- infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
- if (infos[count]) {
- strcpy(infos[count], info);
- count++;
- }
- }
- return count;
-}
-
-/*
-===============
-UI_LoadArenasFromFile
-===============
-*/
-static void UI_LoadArenasFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_ARENAS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_ARENAS_TEXT ) {
- trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_ARENAS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] );
-}
-
-/*
-===============
-UI_LoadArenas
-===============
-*/
-static void UI_LoadArenas( void ) {
- int numdirs;
- vmCvar_t arenasFile;
- char filename[128];
- char dirlist[20*1024];
- char* dirptr;
- int i, n;
- int dirlen;
- char *type;
- char *tag;
- int singlePlayerNum, specialNum, otherNum;
-
- ui_numArenas = 0;
-
- trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
- if( *arenasFile.string ) {
- UI_LoadArenasFromFile(arenasFile.string);
- }
- else {
- UI_LoadArenasFromFile("scripts/arenas.txt");
- }
-
- // get all arenas from .arena files
- numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, sizeof(dirlist) );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- UI_LoadArenasFromFile(filename);
- }
- trap_Print( va( "%i arenas parsed\n", ui_numArenas ) );
- if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all arenas\n");
-
- // set initial numbers
- for( n = 0; n < ui_numArenas; n++ ) {
- Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", n ) );
- }
-
- // go through and count single players levels
- ui_numSinglePlayerArenas = 0;
- ui_numSpecialSinglePlayerArenas = 0;
- for( n = 0; n < ui_numArenas; n++ ) {
- // determine type
- type = Info_ValueForKey( ui_arenaInfos[n], "type" );
-
- // if no type specified, it will be treated as "ffa"
- if( !*type ) {
- continue;
- }
-
- if( strstr( type, "single" ) ) {
- // check for special single player arenas (training, final)
- tag = Info_ValueForKey( ui_arenaInfos[n], "special" );
- if( *tag ) {
- ui_numSpecialSinglePlayerArenas++;
- continue;
- }
-
- ui_numSinglePlayerArenas++;
- }
- }
-
- n = ui_numSinglePlayerArenas % ARENAS_PER_TIER;
- if( n != 0 ) {
- ui_numSinglePlayerArenas -= n;
- trap_Print( va( "%i arenas ignored to make count divisible by %i\n", n, ARENAS_PER_TIER ) );
- }
-
- // go through once more and assign number to the levels
- singlePlayerNum = 0;
- specialNum = singlePlayerNum + ui_numSinglePlayerArenas;
- otherNum = specialNum + ui_numSpecialSinglePlayerArenas + n;
- for( n = 0; n < ui_numArenas; n++ ) {
- // determine type
- type = Info_ValueForKey( ui_arenaInfos[n], "type" );
-
- // if no type specified, it will be treated as "ffa"
- if( *type ) {
- if( strstr( type, "single" ) ) {
- // check for special single player arenas (training, final)
- tag = Info_ValueForKey( ui_arenaInfos[n], "special" );
- if( *tag ) {
- Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", specialNum++ ) );
- continue;
- }
-
- Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", singlePlayerNum++ ) );
- continue;
- }
- }
-
- Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", otherNum++ ) );
- }
-}
-
-/*
-===============
-UI_GetArenaInfoByNumber
-===============
-*/
-const char *UI_GetArenaInfoByNumber( int num ) {
- int n;
- char *value;
-
- if( num < 0 || num >= ui_numArenas ) {
- trap_Print( va( S_COLOR_RED "Invalid arena number: %i\n", num ) );
- return NULL;
- }
-
- for( n = 0; n < ui_numArenas; n++ ) {
- value = Info_ValueForKey( ui_arenaInfos[n], "num" );
- if( *value && atoi(value) == num ) {
- return ui_arenaInfos[n];
- }
- }
-
- return NULL;
-}
-
-
-/*
-===============
-UI_GetArenaInfoByNumber
-===============
-*/
-const char *UI_GetArenaInfoByMap( const char *map ) {
- int n;
-
- for( n = 0; n < ui_numArenas; n++ ) {
- if( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], "map" ), map ) == 0 ) {
- return ui_arenaInfos[n];
- }
- }
-
- return NULL;
-}
-
-
-/*
-===============
-UI_GetSpecialArenaInfo
-===============
-*/
-const char *UI_GetSpecialArenaInfo( const char *tag ) {
- int n;
-
- for( n = 0; n < ui_numArenas; n++ ) {
- if( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], "special" ), tag ) == 0 ) {
- return ui_arenaInfos[n];
- }
- }
-
- return NULL;
-}
-
-/*
-===============
-UI_LoadBotsFromFile
-===============
-*/
-static void UI_LoadBotsFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_BOTS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_BOTS_TEXT ) {
- trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- ui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] );
- if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all bots\n");
-}
-
-/*
-===============
-UI_LoadBots
-===============
-*/
-static void UI_LoadBots( void ) {
- vmCvar_t botsFile;
- int numdirs;
- char filename[128];
- char dirlist[1024];
- char* dirptr;
- int i;
- int dirlen;
-
- ui_numBots = 0;
-
- trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
- if( *botsFile.string ) {
- UI_LoadBotsFromFile(botsFile.string);
- }
- else {
- UI_LoadBotsFromFile("scripts/bots.txt");
- }
-
- // get all bots from .bot files
- numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- UI_LoadBotsFromFile(filename);
- }
- trap_Print( va( "%i bots parsed\n", ui_numBots ) );
-}
-
-
-/*
-===============
-UI_GetBotInfoByNumber
-===============
-*/
-char *UI_GetBotInfoByNumber( int num ) {
- if( num < 0 || num >= ui_numBots ) {
- trap_Print( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
- return NULL;
- }
- return ui_botInfos[num];
-}
-
-
-/*
-===============
-UI_GetBotInfoByName
-===============
-*/
-char *UI_GetBotInfoByName( const char *name ) {
- int n;
- char *value;
-
- for ( n = 0; n < ui_numBots ; n++ ) {
- value = Info_ValueForKey( ui_botInfos[n], "name" );
- if ( !Q_stricmp( value, name ) ) {
- return ui_botInfos[n];
- }
- }
-
- return NULL;
-}
-
-
-//
-// single player game info
-//
-
-/*
-===============
-UI_GetBestScore
-
-Returns the player's best finish on a given level, 0 if the have not played the level
-===============
-*/
-void UI_GetBestScore( int level, int *score, int *skill ) {
- int n;
- int skillScore;
- int bestScore;
- int bestScoreSkill;
- char arenaKey[16];
- char scores[MAX_INFO_VALUE];
-
- if( !score || !skill ) {
- return;
- }
-
- if( level < 0 || level > ui_numArenas ) {
- return;
- }
-
- bestScore = 0;
- bestScoreSkill = 0;
-
- for( n = 1; n <= 5; n++ ) {
- trap_Cvar_VariableStringBuffer( va( "g_spScores%i", n ), scores, MAX_INFO_VALUE );
-
- Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
- skillScore = atoi( Info_ValueForKey( scores, arenaKey ) );
-
- if( skillScore < 1 || skillScore > 8 ) {
- continue;
- }
-
- if( !bestScore || skillScore <= bestScore ) {
- bestScore = skillScore;
- bestScoreSkill = n;
- }
- }
-
- *score = bestScore;
- *skill = bestScoreSkill;
-}
-
-
-/*
-===============
-UI_SetBestScore
-
-Set the player's best finish for a level
-===============
-*/
-void UI_SetBestScore( int level, int score ) {
- int skill;
- int oldScore;
- char arenaKey[16];
- char scores[MAX_INFO_VALUE];
-
- // validate score
- if( score < 1 || score > 8 ) {
- return;
- }
-
- // validate skill
- skill = (int)trap_Cvar_VariableValue( "g_spSkill" );
- if( skill < 1 || skill > 5 ) {
- return;
- }
-
- // get scores
- trap_Cvar_VariableStringBuffer( va( "g_spScores%i", skill ), scores, MAX_INFO_VALUE );
-
- // see if this is better
- Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
- oldScore = atoi( Info_ValueForKey( scores, arenaKey ) );
- if( oldScore && oldScore <= score ) {
- return;
- }
-
- // update scores
- Info_SetValueForKey( scores, arenaKey, va( "%i", score ) );
- trap_Cvar_Set( va( "g_spScores%i", skill ), scores );
-}
-
-
-/*
-===============
-UI_LogAwardData
-===============
-*/
-void UI_LogAwardData( int award, int data ) {
- char key[16];
- char awardData[MAX_INFO_VALUE];
- int oldValue;
-
- if( data == 0 ) {
- return;
- }
-
- if( award > AWARD_PERFECT ) {
- trap_Print( va( S_COLOR_RED "Bad award %i in UI_LogAwardData\n", award ) );
- return;
- }
-
- trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, sizeof(awardData) );
-
- Com_sprintf( key, sizeof(key), "a%i", award );
- oldValue = atoi( Info_ValueForKey( awardData, key ) );
-
- Info_SetValueForKey( awardData, key, va( "%i", oldValue + data ) );
- trap_Cvar_Set( "g_spAwards", awardData );
-}
-
-
-/*
-===============
-UI_GetAwardLevel
-===============
-*/
-int UI_GetAwardLevel( int award ) {
- char key[16];
- char awardData[MAX_INFO_VALUE];
-
- trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, sizeof(awardData) );
-
- Com_sprintf( key, sizeof(key), "a%i", award );
- return atoi( Info_ValueForKey( awardData, key ) );
-}
-
-
-/*
-===============
-UI_TierCompleted
-===============
-*/
-int UI_TierCompleted( int levelWon ) {
- int level;
- int n;
- int tier;
- int score;
- int skill;
- const char *info;
-
- tier = levelWon / ARENAS_PER_TIER;
- level = tier * ARENAS_PER_TIER;
-
- if( tier == UI_GetNumSPTiers() ) {
- info = UI_GetSpecialArenaInfo( "training" );
- if( levelWon == atoi( Info_ValueForKey( info, "num" ) ) ) {
- return 0;
- }
- info = UI_GetSpecialArenaInfo( "final" );
- if( !info || levelWon == atoi( Info_ValueForKey( info, "num" ) ) ) {
- return tier + 1;
- }
- return -1;
- }
-
- for( n = 0; n < ARENAS_PER_TIER; n++, level++ ) {
- UI_GetBestScore( level, &score, &skill );
- if ( score != 1 ) {
- return -1;
- }
- }
- return tier + 1;
-}
-
-
-/*
-===============
-UI_ShowTierVideo
-===============
-*/
-qboolean UI_ShowTierVideo( int tier ) {
- char key[16];
- char videos[MAX_INFO_VALUE];
-
- if( tier <= 0 ) {
- return qfalse;
- }
-
- trap_Cvar_VariableStringBuffer( "g_spVideos", videos, sizeof(videos) );
-
- Com_sprintf( key, sizeof(key), "tier%i", tier );
- if( atoi( Info_ValueForKey( videos, key ) ) ) {
- return qfalse;
- }
-
- Info_SetValueForKey( videos, key, va( "%i", 1 ) );
- trap_Cvar_Set( "g_spVideos", videos );
-
- return qtrue;
-}
-
-
-/*
-===============
-UI_CanShowTierVideo
-===============
-*/
-qboolean UI_CanShowTierVideo( int tier ) {
- char key[16];
- char videos[MAX_INFO_VALUE];
-
- if( !tier ) {
- return qfalse;
- }
-
- if( uis.demoversion && tier != 8 ) {
- return qfalse;
- }
-
- trap_Cvar_VariableStringBuffer( "g_spVideos", videos, sizeof(videos) );
-
- Com_sprintf( key, sizeof(key), "tier%i", tier );
- if( atoi( Info_ValueForKey( videos, key ) ) ) {
- return qtrue;
- }
-
- return qfalse;
-}
-
-
-/*
-===============
-UI_GetCurrentGame
-
-Returns the next level the player has not won
-===============
-*/
-int UI_GetCurrentGame( void ) {
- int level;
- int rank;
- int skill;
- const char *info;
-
- info = UI_GetSpecialArenaInfo( "training" );
- if( info ) {
- level = atoi( Info_ValueForKey( info, "num" ) );
- UI_GetBestScore( level, &rank, &skill );
- if ( !rank || rank > 1 ) {
- return level;
- }
- }
-
- for( level = 0; level < ui_numSinglePlayerArenas; level++ ) {
- UI_GetBestScore( level, &rank, &skill );
- if ( !rank || rank > 1 ) {
- return level;
- }
- }
-
- info = UI_GetSpecialArenaInfo( "final" );
- if( !info ) {
- return -1;
- }
- return atoi( Info_ValueForKey( info, "num" ) );
-}
-
-
-/*
-===============
-UI_NewGame
-
-Clears the scores and sets the difficutly level
-===============
-*/
-void UI_NewGame( void ) {
- trap_Cvar_Set( "g_spScores1", "" );
- trap_Cvar_Set( "g_spScores2", "" );
- trap_Cvar_Set( "g_spScores3", "" );
- trap_Cvar_Set( "g_spScores4", "" );
- trap_Cvar_Set( "g_spScores5", "" );
- trap_Cvar_Set( "g_spAwards", "" );
- trap_Cvar_Set( "g_spVideos", "" );
-}
-
-
-/*
-===============
-UI_GetNumArenas
-===============
-*/
-int UI_GetNumArenas( void ) {
- return ui_numArenas;
-}
-
-
-/*
-===============
-UI_GetNumSPArenas
-===============
-*/
-int UI_GetNumSPArenas( void ) {
- return ui_numSinglePlayerArenas;
-}
-
-
-/*
-===============
-UI_GetNumSPTiers
-===============
-*/
-int UI_GetNumSPTiers( void ) {
- return ui_numSinglePlayerArenas / ARENAS_PER_TIER;
-}
-
-
-/*
-===============
-UI_GetNumBots
-===============
-*/
-int UI_GetNumBots( void ) {
- return ui_numBots;
-}
-
-
-/*
-===============
-UI_SPUnlock_f
-===============
-*/
-void UI_SPUnlock_f( void ) {
- char arenaKey[16];
- char scores[MAX_INFO_VALUE];
- int level;
- int tier;
-
- // get scores for skill 1
- trap_Cvar_VariableStringBuffer( "g_spScores1", scores, MAX_INFO_VALUE );
-
- // update scores
- for( level = 0; level < ui_numSinglePlayerArenas + ui_numSpecialSinglePlayerArenas; level++ ) {
- Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
- Info_SetValueForKey( scores, arenaKey, "1" );
- }
- trap_Cvar_Set( "g_spScores1", scores );
-
- // unlock cinematics
- for( tier = 1; tier <= 8; tier++ ) {
- UI_ShowTierVideo( tier );
- }
-
- trap_Print( "All levels unlocked at skill level 1\n" );
-
- UI_SPLevelMenu_ReInit();
-}
-
-
-/*
-===============
-UI_SPUnlockMedals_f
-===============
-*/
-void UI_SPUnlockMedals_f( void ) {
- int n;
- char key[16];
- char awardData[MAX_INFO_VALUE];
-
- trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, MAX_INFO_VALUE );
-
- for( n = 0; n < 6; n++ ) {
- Com_sprintf( key, sizeof(key), "a%i", n );
- Info_SetValueForKey( awardData, key, "100" );
- }
-
- trap_Cvar_Set( "g_spAwards", awardData );
-
- trap_Print( "All levels unlocked at 100\n" );
-}
-
-
-/*
-===============
-UI_InitGameinfo
-===============
-*/
-void UI_InitGameinfo( void ) {
-
- UI_InitMemory();
- UI_LoadArenas();
- UI_LoadBots();
-
- uis.demoversion = qfalse;
-}
diff --git a/game/code/q3_ui/ui_local.h b/game/code/q3_ui/ui_local.h
deleted file mode 100644
index 40c0fac..0000000
--- a/game/code/q3_ui/ui_local.h
+++ /dev/null
@@ -1,899 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#ifndef __UI_LOCAL_H__
-#define __UI_LOCAL_H__
-
-#include "../qcommon/q_shared.h"
-#include "../renderer/tr_types.h"
-//NOTE: include the ui_public.h from the new UI
-#include "../ui/ui_public.h" // bk001205 - yes, do have to use this
-//redefine to old API version
-#undef UI_API_VERSION
-#define UI_API_VERSION 4
-#include "../client/keycodes.h"
-#include "../game/bg_public.h"
-
-typedef void (*voidfunc_f)(void);
-
-extern vmCvar_t ui_ffa_fraglimit;
-extern vmCvar_t ui_ffa_timelimit;
-
-extern vmCvar_t ui_tourney_fraglimit;
-extern vmCvar_t ui_tourney_timelimit;
-
-extern vmCvar_t ui_team_fraglimit;
-extern vmCvar_t ui_team_timelimit;
-extern vmCvar_t ui_team_friendly;
-
-extern vmCvar_t ui_ctf_capturelimit;
-extern vmCvar_t ui_ctf_timelimit;
-extern vmCvar_t ui_ctf_friendly;
-
-extern vmCvar_t ui_1fctf_capturelimit;
-extern vmCvar_t ui_1fctf_timelimit;
-extern vmCvar_t ui_1fctf_friendly;
-
-extern vmCvar_t ui_overload_capturelimit;
-extern vmCvar_t ui_overload_timelimit;
-extern vmCvar_t ui_overload_friendly;
-
-extern vmCvar_t ui_harvester_capturelimit;
-extern vmCvar_t ui_harvester_timelimit;
-extern vmCvar_t ui_harvester_friendly;
-
-extern vmCvar_t ui_elimination_capturelimit;
-extern vmCvar_t ui_elimination_timelimit;
-
-extern vmCvar_t ui_ctf_elimination_capturelimit;
-extern vmCvar_t ui_ctf_elimination_timelimit;
-
-extern vmCvar_t ui_lms_fraglimit;
-extern vmCvar_t ui_lms_timelimit;
-
-extern vmCvar_t ui_dd_capturelimit;
-extern vmCvar_t ui_dd_timelimit;
-extern vmCvar_t ui_dd_friendly;
-
-extern vmCvar_t ui_dom_capturelimit;
-extern vmCvar_t ui_dom_timelimit;
-extern vmCvar_t ui_dom_friendly;
-
-extern vmCvar_t ui_arenasFile;
-extern vmCvar_t ui_botsFile;
-extern vmCvar_t ui_spScores1;
-extern vmCvar_t ui_spScores2;
-extern vmCvar_t ui_spScores3;
-extern vmCvar_t ui_spScores4;
-extern vmCvar_t ui_spScores5;
-extern vmCvar_t ui_spAwards;
-extern vmCvar_t ui_spVideos;
-extern vmCvar_t ui_spSkill;
-
-extern vmCvar_t ui_spSelection;
-
-extern vmCvar_t ui_browserMaster;
-extern vmCvar_t ui_browserGameType;
-extern vmCvar_t ui_browserSortKey;
-extern vmCvar_t ui_browserShowFull;
-extern vmCvar_t ui_browserShowEmpty;
-
-extern vmCvar_t ui_brassTime;
-extern vmCvar_t ui_drawCrosshair;
-extern vmCvar_t ui_drawCrosshairNames;
-extern vmCvar_t ui_marks;
-
-extern vmCvar_t ui_server1;
-extern vmCvar_t ui_server2;
-extern vmCvar_t ui_server3;
-extern vmCvar_t ui_server4;
-extern vmCvar_t ui_server5;
-extern vmCvar_t ui_server6;
-extern vmCvar_t ui_server7;
-extern vmCvar_t ui_server8;
-extern vmCvar_t ui_server9;
-extern vmCvar_t ui_server10;
-extern vmCvar_t ui_server11;
-extern vmCvar_t ui_server12;
-extern vmCvar_t ui_server13;
-extern vmCvar_t ui_server14;
-extern vmCvar_t ui_server15;
-extern vmCvar_t ui_server16;
-
-//extern vmCvar_t ui_cdkey;
-//extern vmCvar_t ui_cdkeychecked;
-extern vmCvar_t ui_setupchecked;
-
-//new in beta 23:
-extern vmCvar_t ui_browserOnlyHumans;
-
-//
-// ui_qmenu.c
-//
-
-#define RCOLUMN_OFFSET ( BIGCHAR_WIDTH )
-#define LCOLUMN_OFFSET (-BIGCHAR_WIDTH )
-
-#define SLIDER_RANGE 10
-#define MAX_EDIT_LINE 256
-
-#define MAX_MENUDEPTH 8
-#define MAX_MENUITEMS 64
-
-#define MTYPE_NULL 0
-#define MTYPE_SLIDER 1
-#define MTYPE_ACTION 2
-#define MTYPE_SPINCONTROL 3
-#define MTYPE_FIELD 4
-#define MTYPE_RADIOBUTTON 5
-#define MTYPE_BITMAP 6
-#define MTYPE_TEXT 7
-#define MTYPE_SCROLLLIST 8
-#define MTYPE_PTEXT 9
-#define MTYPE_BTEXT 10
-
-#define QMF_BLINK 0x00000001
-#define QMF_SMALLFONT 0x00000002
-#define QMF_LEFT_JUSTIFY 0x00000004
-#define QMF_CENTER_JUSTIFY 0x00000008
-#define QMF_RIGHT_JUSTIFY 0x00000010
-#define QMF_NUMBERSONLY 0x00000020 // edit field is only numbers
-#define QMF_HIGHLIGHT 0x00000040
-#define QMF_HIGHLIGHT_IF_FOCUS 0x00000080 // steady focus
-#define QMF_PULSEIFFOCUS 0x00000100 // pulse if focus
-#define QMF_HASMOUSEFOCUS 0x00000200
-#define QMF_NOONOFFTEXT 0x00000400
-#define QMF_MOUSEONLY 0x00000800 // only mouse input allowed
-#define QMF_HIDDEN (unsigned int)0x00001000 // skips drawing
-#define QMF_GRAYED (unsigned int)0x00002000 // grays and disables
-#define QMF_INACTIVE (unsigned int)0x00004000 // disables any input
-#define QMF_NODEFAULTINIT 0x00008000 // skip default initialization
-#define QMF_OWNERDRAW 0x00010000
-#define QMF_PULSE 0x00020000
-#define QMF_LOWERCASE 0x00040000 // edit field is all lower case
-#define QMF_UPPERCASE 0x00080000 // edit field is all upper case
-#define QMF_SILENT 0x00100000
-
-//for cgs.ffa_gt and g_ffa kinda leary about this...
-//#define FREEFORALL (s_serveroptions.gametype==GT_LMS)
-//#define TRAP_FREEFORALL (trap_Cvar_VariableValue( "g_gametype" ) == GT_LMS)
-
-// callback notifications
-#define QM_GOTFOCUS 1
-#define QM_LOSTFOCUS 2
-#define QM_ACTIVATED 3
-
-typedef struct _tag_menuframework
-{
- int cursor;
- int cursor_prev;
-
- int nitems;
- void *items[MAX_MENUITEMS];
-
- void (*draw) (void);
- sfxHandle_t (*key) (int key);
-
- qboolean wrapAround;
- qboolean fullscreen;
- qboolean showlogo;
-} menuframework_s;
-
-typedef struct
-{
- int type;
- const char *name;
- int id;
- int x, y;
- int left;
- int top;
- int right;
- int bottom;
- menuframework_s *parent;
- int menuPosition;
- unsigned flags;
-
- void (*callback)( void *self, int event );
- void (*statusbar)( void *self );
- void (*ownerdraw)( void *self );
-} menucommon_s;
-
-typedef struct {
- int cursor;
- int scroll;
- int widthInChars;
- char buffer[MAX_EDIT_LINE];
- int maxchars;
-} mfield_t;
-
-typedef struct
-{
- menucommon_s generic;
- mfield_t field;
-} menufield_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- float minvalue;
- float maxvalue;
- float curvalue;
-
- float range;
-} menuslider_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- int oldvalue;
- int curvalue;
- int numitems;
- int top;
-
- const char **itemnames;
-
- int width;
- int height;
- int columns;
- int seperation;
-} menulist_s;
-
-typedef struct
-{
- menucommon_s generic;
-} menuaction_s;
-
-typedef struct
-{
- menucommon_s generic;
- int curvalue;
-} menuradiobutton_s;
-
-typedef struct
-{
- menucommon_s generic;
- char* focuspic;
- char* errorpic;
- qhandle_t shader;
- qhandle_t focusshader;
- int width;
- int height;
- float* focuscolor;
-} menubitmap_s;
-
-typedef struct
-{
- menucommon_s generic;
- char* string;
- int style;
- float* color;
-} menutext_s;
-
-#define MAX_MAPNAME_LENGTH 32
-
-typedef struct {
- int pagenumber;
- char mapname[10][MAX_MAPNAME_LENGTH];
-} t_mappage;
-
-extern t_mappage mappage;
-
-extern void Menu_Cache( void );
-extern void Menu_Focus( menucommon_s *m );
-extern void Menu_AddItem( menuframework_s *menu, void *item );
-extern void Menu_AdjustCursor( menuframework_s *menu, int dir );
-extern void Menu_Draw( menuframework_s *menu );
-extern void *Menu_ItemAtCursor( menuframework_s *m );
-extern sfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item );
-extern void Menu_SetCursor( menuframework_s *s, int cursor );
-extern void Menu_SetCursorToItem( menuframework_s *m, void* ptr );
-extern sfxHandle_t Menu_DefaultKey( menuframework_s *s, int key );
-extern void Bitmap_Init( menubitmap_s *b );
-extern void Bitmap_Draw( menubitmap_s *b );
-extern void ScrollList_Draw( menulist_s *l );
-extern sfxHandle_t ScrollList_Key( menulist_s *l, int key );
-extern sfxHandle_t menu_in_sound;
-extern sfxHandle_t menu_move_sound;
-extern sfxHandle_t menu_out_sound;
-extern sfxHandle_t menu_buzz_sound;
-extern sfxHandle_t menu_null_sound;
-extern sfxHandle_t weaponChangeSound;
-extern vec4_t menu_text_color;
-extern vec4_t menu_grayed_color;
-extern vec4_t menu_dark_color;
-extern vec4_t menu_highlight_color;
-extern vec4_t menu_red_color;
-extern vec4_t menu_black_color;
-extern vec4_t menu_dim_color;
-extern vec4_t color_black;
-extern vec4_t color_white;
-extern vec4_t color_yellow;
-extern vec4_t color_blue;
-extern vec4_t color_orange;
-extern vec4_t color_red;
-extern vec4_t color_dim;
-extern vec4_t name_color;
-extern vec4_t list_color;
-extern vec4_t listbar_color;
-extern vec4_t text_color_disabled;
-extern vec4_t text_color_normal;
-extern vec4_t text_color_highlight;
-
-extern char *ui_medalNames[];
-extern char *ui_medalPicNames[];
-extern char *ui_medalSounds[];
-
-//
-// ui_mfield.c
-//
-extern void MField_Clear( mfield_t *edit );
-extern void MField_KeyDownEvent( mfield_t *edit, int key );
-extern void MField_CharEvent( mfield_t *edit, int ch );
-extern void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color );
-extern void MenuField_Init( menufield_s* m );
-extern void MenuField_Draw( menufield_s *f );
-extern sfxHandle_t MenuField_Key( menufield_s* m, int* key );
-
-//
-// ui_menu.c
-//
-extern void MainMenu_Cache( void );
-extern void UI_MainMenu(void);
-extern void UI_RegisterCvars( void );
-extern void UI_UpdateCvars( void );
-
-//
-// ui_credits.c
-//
-extern void UI_CreditMenu( void );
-
-//
-// ui_ingame.c
-//
-extern void InGame_Cache( void );
-extern void UI_InGameMenu(void);
-
-//
-// ui_confirm.c
-//
-extern void ConfirmMenu_Cache( void );
-extern void UI_ConfirmMenu( const char *question, void (*draw)( void ), void (*action)( qboolean result ) );
-extern void UI_ConfirmMenu_Style( const char *question, int style, void (*draw)( void ), void (*action)( qboolean result ) );
-extern void UI_Message( const char **lines );
-
-//
-// ui_setup.c
-//
-extern void UI_SetupMenu_Cache( void );
-extern void UI_SetupMenu(void);
-
-//
-// ui_team.c
-//
-extern void UI_TeamMainMenu( void );
-extern void TeamMain_Cache( void );
-
-//
-// ui_connect.c
-//
-extern void UI_DrawConnectScreen( qboolean overlay );
-
-//
-// ui_controls2.c
-//
-extern void UI_ControlsMenu( void );
-extern void Controls_Cache( void );
-
-//
-// ui_demo2.c
-//
-extern void UI_DemosMenu( void );
-extern void Demos_Cache( void );
-
-//
-// ui_challenges.c
-//
-extern void UI_Challenges( void );
-
-//
-// ui_cinematics.c
-//
-extern void UI_CinematicsMenu( void );
-extern void UI_CinematicsMenu_f( void );
-extern void UI_CinematicsMenu_Cache( void );
-
-//
-// ui_mods.c
-//
-extern void UI_ModsMenu( void );
-extern void UI_ModsMenu_Cache( void );
-
-//
-// ui_cdkey.c
-//
-extern void UI_CDKeyMenu( void );
-extern void UI_CDKeyMenu_Cache( void );
-extern void UI_CDKeyMenu_f( void );
-
-//
-// ui_playermodel.c
-//
-extern void UI_PlayerModelMenu( void );
-extern void PlayerModel_Cache( void );
-
-//
-// ui_playersettings.c
-//
-extern void UI_PlayerSettingsMenu( void );
-extern void PlayerSettings_Cache( void );
-
-//
-// ui_preferences.c
-//
-extern void UI_PreferencesMenu( void );
-extern void Preferences_Cache( void );
-
-//
-// ui_specifyleague.c
-//
-extern void UI_SpecifyLeagueMenu( void );
-extern void SpecifyLeague_Cache( void );
-
-//
-// ui_specifyserver.c
-//
-extern void UI_SpecifyServerMenu( void );
-extern void SpecifyServer_Cache( void );
-
-//
-// ui_servers2.c
-//
-#define MAX_FAVORITESERVERS 16
-
-extern void UI_ArenaServersMenu( void );
-extern void ArenaServers_Cache( void );
-
-//
-// ui_startserver.c
-//
-extern void UI_StartServerMenu( qboolean multiplayer );
-extern void StartServer_Cache( void );
-extern void ServerOptions_Cache( void );
-extern void UI_BotSelectMenu( char *bot );
-extern void UI_BotSelectMenu_Cache( void );
-
-//
-// ui_serverinfo.c
-//
-extern void UI_ServerInfoMenu( void );
-extern void ServerInfo_Cache( void );
-
-//
-// ui_video.c
-//
-extern void UI_GraphicsOptionsMenu( void );
-extern void GraphicsOptions_Cache( void );
-extern void DriverInfo_Cache( void );
-
-//
-// ui_votemenu.c
-//
-extern void UI_VoteMenuMenu( void );
-
-//
-// ui_votemenu_fraglimit.c
-//
-extern void UI_VoteFraglimitMenu( void );
-
-//
-// ui_votemenu_timelimit.c
-//
-extern void UI_VoteTimelimitMenu( void );
-
-//
-// ui_votemenu_gametype.c
-//
-extern void UI_VoteGametypeMenu( void );
-
-//
-// ui_votemenu_kick.c
-//
-extern void UI_VoteKickMenu( void );
-
-//
-// ui_votemenu_map.c
-//
-extern void UI_VoteMapMenu( void );
-extern void UI_VoteMapMenuInternal( void );
-
-//
-// ui_password.c
-//
-extern void SpecifyPassword_Cache( void );
-extern void UI_SpecifyPasswordMenu( char* string, char *name );
-
-//
-// ui_firstconnect.c
-//
-extern void FirstConnect_Cache( void );
-extern void UI_FirstConnectMenu( void );
-
-//
-// ui_votemenu_custom.c
-
-extern void UI_VoteCustomMenu( void );
-
-//
-// ui_players.c
-//
-
-//FIXME ripped from cg_local.h
-typedef struct {
- int oldFrame;
- int oldFrameTime; // time when ->oldFrame was exactly on
-
- int frame;
- int frameTime; // time when ->frame will be exactly on
-
- float backlerp;
-
- float yawAngle;
- qboolean yawing;
- float pitchAngle;
- qboolean pitching;
-
- int animationNumber; // may include ANIM_TOGGLEBIT
- animation_t *animation;
- int animationTime; // time when the first frame of the animation will be exact
-} lerpFrame_t;
-
-typedef struct {
- // model info
- qhandle_t legsModel;
- qhandle_t legsSkin;
- lerpFrame_t legs;
-
- qhandle_t torsoModel;
- qhandle_t torsoSkin;
- lerpFrame_t torso;
-
- qhandle_t headModel;
- qhandle_t headSkin;
-
- animation_t animations[MAX_ANIMATIONS];
-
- qhandle_t weaponModel;
- qhandle_t barrelModel;
- qhandle_t flashModel;
- vec3_t flashDlightColor;
- int muzzleFlashTime;
-
- // currently in use drawing parms
- vec3_t viewAngles;
- vec3_t moveAngles;
- weapon_t currentWeapon;
- int legsAnim;
- int torsoAnim;
-
- // animation vars
- weapon_t weapon;
- weapon_t lastWeapon;
- weapon_t pendingWeapon;
- int weaponTimer;
- int pendingLegsAnim;
- int torsoAnimationTimer;
-
- int pendingTorsoAnim;
- int legsAnimationTimer;
-
- qboolean chat;
- qboolean newModel;
-
- qboolean barrelSpinning;
- float barrelAngle;
- int barrelTime;
-
- int realWeapon;
-} playerInfo_t;
-
-void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time );
-void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model );
-void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNum, qboolean chat );
-qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName );
-
-//
-// ui_atoms.c
-//
-typedef struct {
- int frametime;
- int realtime;
- int cursorx;
- int cursory;
- int menusp;
- menuframework_s* activemenu;
- menuframework_s* stack[MAX_MENUDEPTH];
- glconfig_t glconfig;
- qboolean debug;
- qhandle_t whiteShader;
- qhandle_t menuBackShader;
- qhandle_t menuBackNoLogoShader;
- qhandle_t charset;
- qhandle_t charsetProp;
- qhandle_t charsetPropGlow;
- qhandle_t charsetPropB;
- qhandle_t cursor;
- qhandle_t rb_on;
- qhandle_t rb_off;
- float xscale;
- float yscale;
- float bias;
- qboolean demoversion;
- qboolean firstdraw;
-} uiStatic_t;
-
-extern void UI_Init( void );
-extern void UI_Shutdown( void );
-extern void UI_KeyEvent( int key, int down );
-extern void UI_MouseEvent( int dx, int dy );
-extern void UI_Refresh( int realtime );
-extern qboolean UI_ConsoleCommand( int realTime );
-extern float UI_ClampCvar( float min, float max, float value );
-extern void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname );
-extern void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader );
-extern void UI_FillRect( float x, float y, float width, float height, const float *color );
-extern void UI_DrawRect( float x, float y, float width, float height, const float *color );
-extern void UI_UpdateScreen( void );
-extern void UI_SetColor( const float *rgba );
-extern void UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t);
-extern void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color );
-extern float UI_ProportionalSizeScale( int style );
-extern void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );
-extern void UI_DrawProportionalString_AutoWrapped( int x, int ystart, int xmax, int ystep, const char* str, int style, vec4_t color );
-extern int UI_ProportionalStringWidth( const char* str );
-extern void UI_DrawString( int x, int y, const char* str, int style, vec4_t color );
-extern void UI_DrawChar( int x, int y, int ch, int style, vec4_t color );
-extern qboolean UI_CursorInRect (int x, int y, int width, int height);
-extern void UI_AdjustFrom640( float *x, float *y, float *w, float *h );
-extern void UI_DrawTextBox (int x, int y, int width, int lines);
-extern qboolean UI_IsFullscreen( void );
-extern void UI_SetActiveMenu( uiMenuCommand_t menu );
-extern void UI_PushMenu ( menuframework_s *menu );
-extern void UI_PopMenu (void);
-extern void UI_ForceMenuOff (void);
-extern char *UI_Argv( int arg );
-extern char *UI_Cvar_VariableString( const char *var_name );
-extern void UI_Refresh( int time );
-extern void UI_StartDemoLoop( void );
-extern qboolean m_entersound;
-extern uiStatic_t uis;
-
-//
-// ui_spLevel.c
-//
-void UI_SPLevelMenu_Cache( void );
-void UI_SPLevelMenu( void );
-void UI_SPLevelMenu_f( void );
-void UI_SPLevelMenu_ReInit( void );
-
-//
-// ui_spArena.c
-//
-void UI_SPArena_Start( const char *arenaInfo );
-
-//
-// ui_spPostgame.c
-//
-void UI_SPPostgameMenu_Cache( void );
-void UI_SPPostgameMenu_f( void );
-
-//
-// ui_spSkill.c
-//
-void UI_SPSkillMenu( const char *arenaInfo );
-void UI_SPSkillMenu_Cache( void );
-
-//
-// ui_syscalls.c
-//
-void trap_Print( const char *string );
-void trap_Error( const char *string );
-int trap_Milliseconds( void );
-void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
-void trap_Cvar_Update( vmCvar_t *vmCvar );
-void trap_Cvar_Set( const char *var_name, const char *value );
-float trap_Cvar_VariableValue( const char *var_name );
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-void trap_Cvar_SetValue( const char *var_name, float value );
-void trap_Cvar_Reset( const char *name );
-void trap_Cvar_Create( const char *var_name, const char *var_value, int flags );
-void trap_Cvar_InfoStringBuffer( int bit, char *buffer, int bufsize );
-int trap_Argc( void );
-void trap_Argv( int n, char *buffer, int bufferLength );
-void trap_Cmd_ExecuteText( int exec_when, const char *text ); // don't use EXEC_NOW!
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
-void trap_FS_Read( void *buffer, int len, fileHandle_t f );
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
-void trap_FS_FCloseFile( fileHandle_t f );
-int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
-qhandle_t trap_R_RegisterModel( const char *name );
-qhandle_t trap_R_RegisterSkin( const char *name );
-qhandle_t trap_R_RegisterShaderNoMip( const char *name );
-void trap_R_ClearScene( void );
-void trap_R_AddRefEntityToScene( const refEntity_t *re );
-void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );
-void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
-void trap_R_RenderScene( const refdef_t *fd );
-void trap_R_SetColor( const float *rgba );
-void trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
-void trap_UpdateScreen( void );
-int trap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName );
-void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );
-sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed );
-void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen );
-void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen );
-void trap_Key_SetBinding( int keynum, const char *binding );
-qboolean trap_Key_IsDown( int keynum );
-qboolean trap_Key_GetOverstrikeMode( void );
-void trap_Key_SetOverstrikeMode( qboolean state );
-void trap_Key_ClearStates( void );
-int trap_Key_GetCatcher( void );
-void trap_Key_SetCatcher( int catcher );
-void trap_GetClipboardData( char *buf, int bufsize );
-void trap_GetClientState( uiClientState_t *state );
-void trap_GetGlconfig( glconfig_t *glconfig );
-int trap_GetConfigString( int index, char* buff, int buffsize );
-int trap_LAN_GetServerCount( int source );
-void trap_LAN_GetServerAddressString( int source, int n, char *buf, int buflen );
-void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen );
-int trap_LAN_GetPingQueueCount( void );
-int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen );
-void trap_LAN_ClearPing( int n );
-void trap_LAN_GetPing( int n, char *buf, int buflen, int *pingtime );
-void trap_LAN_GetPingInfo( int n, char *buf, int buflen );
-int trap_MemoryRemaining( void );
-void trap_GetCDKey( char *buf, int buflen );
-void trap_SetCDKey( char *buf );
-
-qboolean trap_VerifyCDKey( const char *key, const char *chksum); // bk001208 - RC4
-
-void trap_SetPbClStatus( int status );
-
-//
-// ui_addbots.c
-//
-void UI_AddBots_Cache( void );
-void UI_AddBotsMenu( void );
-
-//
-// ui_removebots.c
-//
-void UI_RemoveBots_Cache( void );
-void UI_RemoveBotsMenu( void );
-
-//
-// ui_teamorders.c
-//
-extern void UI_TeamOrdersMenu( void );
-extern void UI_TeamOrdersMenu_f( void );
-extern void UI_TeamOrdersMenu_Cache( void );
-
-//
-// ui_loadconfig.c
-//
-void UI_LoadConfig_Cache( void );
-void UI_LoadConfigMenu( void );
-
-//
-// ui_saveconfig.c
-//
-void UI_SaveConfigMenu_Cache( void );
-void UI_SaveConfigMenu( void );
-
-//
-// ui_display.c
-//
-void UI_DisplayOptionsMenu_Cache( void );
-void UI_DisplayOptionsMenu( void );
-
-//
-// ui_sound.c
-//
-void UI_SoundOptionsMenu_Cache( void );
-void UI_SoundOptionsMenu( void );
-
-//
-// ui_network.c
-//
-void UI_NetworkOptionsMenu_Cache( void );
-void UI_NetworkOptionsMenu( void );
-
-//
-// ui_gameinfo.c
-//
-typedef enum {
- AWARD_ACCURACY,
- AWARD_IMPRESSIVE,
- AWARD_EXCELLENT,
- AWARD_GAUNTLET,
- AWARD_FRAGS,
- AWARD_PERFECT
-} awardType_t;
-
-const char *UI_GetArenaInfoByNumber( int num );
-const char *UI_GetArenaInfoByMap( const char *map );
-const char *UI_GetSpecialArenaInfo( const char *tag );
-int UI_GetNumArenas( void );
-int UI_GetNumSPArenas( void );
-int UI_GetNumSPTiers( void );
-
-char *UI_GetBotInfoByNumber( int num );
-char *UI_GetBotInfoByName( const char *name );
-int UI_GetNumBots( void );
-
-void UI_GetBestScore( int level, int *score, int *skill );
-void UI_SetBestScore( int level, int score );
-int UI_TierCompleted( int levelWon );
-qboolean UI_ShowTierVideo( int tier );
-qboolean UI_CanShowTierVideo( int tier );
-int UI_GetCurrentGame( void );
-void UI_NewGame( void );
-void UI_LogAwardData( int award, int data );
-int UI_GetAwardLevel( int award );
-
-void UI_SPUnlock_f( void );
-void UI_SPUnlockMedals_f( void );
-
-void UI_InitGameinfo( void );
-
-//GRank
-
-//
-// ui_rankings.c
-//
-void Rankings_DrawText( void* self );
-void Rankings_DrawName( void* self );
-void Rankings_DrawPassword( void* self );
-void Rankings_Cache( void );
-void UI_RankingsMenu( void );
-
-//
-// ui_login.c
-//
-void Login_Cache( void );
-void UI_LoginMenu( void );
-
-//
-// ui_signup.c
-//
-void Signup_Cache( void );
-void UI_SignupMenu( void );
-
-//
-// ui_rankstatus.c
-//
-void RankStatus_Cache( void );
-void UI_RankStatusMenu( void );
-
-#endif
diff --git a/game/code/q3_ui/ui_main.c b/game/code/q3_ui/ui_main.c
deleted file mode 100644
index d24dd7f..0000000
--- a/game/code/q3_ui/ui_main.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-USER INTERFACE MAIN
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-/*
-================
-vmMain
-
-This is the only way control passes into the module.
-This must be the very first function compiled into the .qvm file
-================
-*/
-intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
- switch ( command ) {
- case UI_GETAPIVERSION:
- return UI_API_VERSION;
-
- case UI_INIT:
- UI_Init();
- return 0;
-
- case UI_SHUTDOWN:
- UI_Shutdown();
- return 0;
-
- case UI_KEY_EVENT:
- UI_KeyEvent( arg0, arg1 );
- return 0;
-
- case UI_MOUSE_EVENT:
- UI_MouseEvent( arg0, arg1 );
- return 0;
-
- case UI_REFRESH:
- UI_Refresh( arg0 );
- return 0;
-
- case UI_IS_FULLSCREEN:
- return UI_IsFullscreen();
-
- case UI_SET_ACTIVE_MENU:
- UI_SetActiveMenu( arg0 );
- return 0;
-
- case UI_CONSOLE_COMMAND:
- return UI_ConsoleCommand(arg0);
-
- case UI_DRAW_CONNECT_SCREEN:
- UI_DrawConnectScreen( arg0 );
- return 0;
- case UI_HASUNIQUECDKEY: // mod authors need to observe this
- return qtrue; // bk010117 - change this to qfalse for mods!
- }
-
- return -1;
-}
-
-
-/*
-================
-cvars
-================
-*/
-
-typedef struct {
- vmCvar_t *vmCvar;
- char *cvarName;
- char *defaultString;
- int cvarFlags;
-} cvarTable_t;
-
-vmCvar_t ui_ffa_fraglimit;
-vmCvar_t ui_ffa_timelimit;
-
-vmCvar_t ui_tourney_fraglimit;
-vmCvar_t ui_tourney_timelimit;
-
-vmCvar_t ui_team_fraglimit;
-vmCvar_t ui_team_timelimit;
-vmCvar_t ui_team_friendly;
-
-vmCvar_t ui_ctf_capturelimit;
-vmCvar_t ui_ctf_timelimit;
-vmCvar_t ui_ctf_friendly;
-
-vmCvar_t ui_1fctf_capturelimit;
-vmCvar_t ui_1fctf_timelimit;
-vmCvar_t ui_1fctf_friendly;
-
-vmCvar_t ui_overload_capturelimit;
-vmCvar_t ui_overload_timelimit;
-vmCvar_t ui_overload_friendly;
-
-vmCvar_t ui_harvester_capturelimit;
-vmCvar_t ui_harvester_timelimit;
-vmCvar_t ui_harvester_friendly;
-
-vmCvar_t ui_elimination_capturelimit;
-vmCvar_t ui_elimination_timelimit;
-
-vmCvar_t ui_ctf_elimination_capturelimit;
-vmCvar_t ui_ctf_elimination_timelimit;
-
-vmCvar_t ui_lms_fraglimit;
-vmCvar_t ui_lms_timelimit;
-
-vmCvar_t ui_dd_capturelimit;
-vmCvar_t ui_dd_timelimit;
-vmCvar_t ui_dd_friendly;
-
-vmCvar_t ui_dom_capturelimit;
-vmCvar_t ui_dom_timelimit;
-vmCvar_t ui_dom_friendly;
-
-vmCvar_t ui_arenasFile;
-vmCvar_t ui_botsFile;
-vmCvar_t ui_spScores1;
-vmCvar_t ui_spScores2;
-vmCvar_t ui_spScores3;
-vmCvar_t ui_spScores4;
-vmCvar_t ui_spScores5;
-vmCvar_t ui_spAwards;
-vmCvar_t ui_spVideos;
-vmCvar_t ui_spSkill;
-
-vmCvar_t ui_spSelection;
-
-vmCvar_t ui_browserMaster;
-vmCvar_t ui_browserGameType;
-vmCvar_t ui_browserSortKey;
-vmCvar_t ui_browserShowFull;
-vmCvar_t ui_browserShowEmpty;
-
-vmCvar_t ui_brassTime;
-vmCvar_t ui_drawCrosshair;
-vmCvar_t ui_drawCrosshairNames;
-vmCvar_t ui_marks;
-
-vmCvar_t ui_server1;
-vmCvar_t ui_server2;
-vmCvar_t ui_server3;
-vmCvar_t ui_server4;
-vmCvar_t ui_server5;
-vmCvar_t ui_server6;
-vmCvar_t ui_server7;
-vmCvar_t ui_server8;
-vmCvar_t ui_server9;
-vmCvar_t ui_server10;
-vmCvar_t ui_server11;
-vmCvar_t ui_server12;
-vmCvar_t ui_server13;
-vmCvar_t ui_server14;
-vmCvar_t ui_server15;
-vmCvar_t ui_server16;
-
-//vmCvar_t ui_cdkeychecked;
-
-//new in beta 23:
-vmCvar_t ui_browserOnlyHumans;
-
-//new in beta 37:
-vmCvar_t ui_setupchecked;
-
-// bk001129 - made static to avoid aliasing.
-static cvarTable_t cvarTable[] = {
- { &ui_ffa_fraglimit, "ui_ffa_fraglimit", "20", CVAR_ARCHIVE },
- { &ui_ffa_timelimit, "ui_ffa_timelimit", "0", CVAR_ARCHIVE },
-
- { &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE },
- { &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE },
-
- { &ui_team_fraglimit, "ui_team_fraglimit", "0", CVAR_ARCHIVE },
- { &ui_team_timelimit, "ui_team_timelimit", "20", CVAR_ARCHIVE },
- { &ui_team_friendly, "ui_team_friendly", "1", CVAR_ARCHIVE },
-
- { &ui_ctf_capturelimit, "ui_ctf_capturelimit", "8", CVAR_ARCHIVE },
- { &ui_ctf_timelimit, "ui_ctf_timelimit", "30", CVAR_ARCHIVE },
- { &ui_ctf_friendly, "ui_ctf_friendly", "0", CVAR_ARCHIVE },
-
- { &ui_1fctf_capturelimit, "ui_1fctf_capturelimit", "8", CVAR_ARCHIVE },
- { &ui_1fctf_timelimit, "ui_1fctf_timelimit", "30", CVAR_ARCHIVE },
- { &ui_1fctf_friendly, "ui_1fctf_friendly", "0", CVAR_ARCHIVE },
-
- { &ui_overload_capturelimit, "ui_overload_capturelimit", "8", CVAR_ARCHIVE },
- { &ui_overload_timelimit, "ui_overload_timelimit", "30", CVAR_ARCHIVE },
- { &ui_overload_friendly, "ui_overload_friendly", "0", CVAR_ARCHIVE },
-
- { &ui_harvester_capturelimit, "ui_harvester_capturelimit", "20", CVAR_ARCHIVE },
- { &ui_harvester_timelimit, "ui_harvester_timelimit", "30", CVAR_ARCHIVE },
- { &ui_harvester_friendly, "ui_harvester_friendly", "0", CVAR_ARCHIVE },
-
- { &ui_elimination_capturelimit, "ui_elimination_capturelimit", "8", CVAR_ARCHIVE },
- { &ui_elimination_timelimit, "ui_elimination_timelimit", "20", CVAR_ARCHIVE },
-
- { &ui_ctf_elimination_capturelimit, "ui_ctf_elimination_capturelimit", "8", CVAR_ARCHIVE },
- { &ui_ctf_elimination_timelimit, "ui_ctf_elimination_timelimit", "30", CVAR_ARCHIVE },
-
- { &ui_lms_fraglimit, "ui_lms_fraglimit", "20", CVAR_ARCHIVE },
- { &ui_lms_timelimit, "ui_lms_timelimit", "0", CVAR_ARCHIVE },
-
- { &ui_dd_capturelimit, "ui_dd_capturelimit", "8", CVAR_ARCHIVE },
- { &ui_dd_timelimit, "ui_dd_timelimit", "30", CVAR_ARCHIVE },
- { &ui_dd_friendly, "ui_dd_friendly", "0", CVAR_ARCHIVE },
-
- { &ui_dom_capturelimit, "ui_dom_capturelimit", "500", CVAR_ARCHIVE },
- { &ui_dom_timelimit, "ui_dom_timelimit", "30", CVAR_ARCHIVE },
- { &ui_dom_friendly, "ui_dom_friendly", "0", CVAR_ARCHIVE },
-
- { &ui_arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM },
- { &ui_botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM },
- { &ui_spScores1, "g_spScores1", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores2, "g_spScores2", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores3, "g_spScores3", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores4, "g_spScores4", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores5, "g_spScores5", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spAwards, "g_spAwards", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spVideos, "g_spVideos", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spSkill, "g_spSkill", "2", CVAR_ARCHIVE | CVAR_LATCH },
-
- { &ui_spSelection, "ui_spSelection", "", CVAR_ROM },
-
- { &ui_browserMaster, "ui_browserMaster", "0", CVAR_ARCHIVE },
- { &ui_browserGameType, "ui_browserGameType", "0", CVAR_ARCHIVE },
- { &ui_browserSortKey, "ui_browserSortKey", "4", CVAR_ARCHIVE },
- { &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE },
- { &ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE },
-
- { &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
- { &ui_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
- { &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
- { &ui_marks, "cg_marks", "1", CVAR_ARCHIVE },
-
- { &ui_server1, "server1", "", CVAR_ARCHIVE },
- { &ui_server2, "server2", "", CVAR_ARCHIVE },
- { &ui_server3, "server3", "", CVAR_ARCHIVE },
- { &ui_server4, "server4", "", CVAR_ARCHIVE },
- { &ui_server5, "server5", "", CVAR_ARCHIVE },
- { &ui_server6, "server6", "", CVAR_ARCHIVE },
- { &ui_server7, "server7", "", CVAR_ARCHIVE },
- { &ui_server8, "server8", "", CVAR_ARCHIVE },
- { &ui_server9, "server9", "", CVAR_ARCHIVE },
- { &ui_server10, "server10", "", CVAR_ARCHIVE },
- { &ui_server11, "server11", "", CVAR_ARCHIVE },
- { &ui_server12, "server12", "", CVAR_ARCHIVE },
- { &ui_server13, "server13", "", CVAR_ARCHIVE },
- { &ui_server14, "server14", "", CVAR_ARCHIVE },
- { &ui_server15, "server15", "", CVAR_ARCHIVE },
- { &ui_server16, "server16", "", CVAR_ARCHIVE },
-
- //{ &ui_cdkeychecked, "ui_cdkeychecked", "0", CVAR_ROM },
-
- //new in beta 23:
- { &ui_browserOnlyHumans, "ui_browserOnlyHumans", "0", CVAR_ARCHIVE },
-
- //new in beta 37:
- { &ui_setupchecked, "ui_setupchecked", "0", CVAR_ARCHIVE },
-};
-
-// bk001129 - made static to avoid aliasing
-static int cvarTableSize = sizeof(cvarTable) / sizeof(cvarTable[0]);
-
-/*
-=================
-UI_RegisterCvars
-=================
-*/
-void UI_RegisterCvars( void ) {
- int i;
- cvarTable_t *cv;
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );
- }
-}
-
-/*
-=================
-UI_UpdateCvars
-=================
-*/
-void UI_UpdateCvars( void ) {
- int i;
- cvarTable_t *cv;
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Update( cv->vmCvar );
- }
-}
diff --git a/game/code/q3_ui/ui_menu.c b/game/code/q3_ui/ui_menu.c
deleted file mode 100644
index 06a5fd1..0000000
--- a/game/code/q3_ui/ui_menu.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-MAIN MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define ID_SINGLEPLAYER 10
-#define ID_MULTIPLAYER 11
-#define ID_SETUP 12
-#define ID_DEMOS 13
-//#define ID_CINEMATICS 14
-#define ID_CHALLENGES 14
-#define ID_TEAMARENA 15
-#define ID_MODS 16
-#define ID_EXIT 17
-
-#define MAIN_BANNER_MODEL "models/mapobjects/banner/banner5.md3"
-#define MAIN_MENU_VERTICAL_SPACING 34
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s singleplayer;
- menutext_s multiplayer;
- menutext_s setup;
- menutext_s demos;
- //menutext_s cinematics;
- menutext_s challenges;
- menutext_s teamArena;
- menutext_s mods;
- menutext_s exit;
-
- qhandle_t bannerModel;
-} mainmenu_t;
-
-
-static mainmenu_t s_main;
-
-typedef struct {
- menuframework_s menu;
- char errorMessage[4096];
-} errorMessage_t;
-
-static errorMessage_t s_errorMessage;
-
-/*
-=================
-MainMenu_ExitAction
-=================
-*/
-static void MainMenu_ExitAction( qboolean result ) {
- if( !result ) {
- return;
- }
- UI_PopMenu();
- //UI_CreditMenu();
- trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" );
-}
-
-
-
-/*
-=================
-Main_MenuEvent
-=================
-*/
-void Main_MenuEvent (void* ptr, int event) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_SINGLEPLAYER:
- UI_SPLevelMenu();
- break;
-
- case ID_MULTIPLAYER:
- if(ui_setupchecked.integer)
- UI_ArenaServersMenu();
- else
- UI_FirstConnectMenu();
- break;
-
- case ID_SETUP:
- UI_SetupMenu();
- break;
-
- case ID_DEMOS:
- UI_DemosMenu();
- break;
-
- /*case ID_CINEMATICS:
- UI_CinematicsMenu();
- break;*/
-
- case ID_CHALLENGES:
- UI_Challenges();
- break;
-
- case ID_MODS:
- UI_ModsMenu();
- break;
-
- case ID_TEAMARENA:
- trap_Cvar_Set( "fs_game", "missionpack");
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
- break;
-
- case ID_EXIT:
- UI_ConfirmMenu( "EXIT GAME?", 0, MainMenu_ExitAction );
- break;
- }
-}
-
-
-/*
-===============
-MainMenu_Cache
-===============
-*/
-void MainMenu_Cache( void ) {
- s_main.bannerModel = trap_R_RegisterModel( MAIN_BANNER_MODEL );
-}
-
-sfxHandle_t ErrorMessage_Key(int key)
-{
- trap_Cvar_Set( "com_errorMessage", "" );
- UI_MainMenu();
- return (menu_null_sound);
-}
-
-/*
-===============
-Main_MenuDraw
-TTimo: this function is common to the main menu and errorMessage menu
-===============
-*/
-
-static void Main_MenuDraw( void ) {
- refdef_t refdef;
- refEntity_t ent;
- vec3_t origin;
- vec3_t angles;
- float adjust;
- float x, y, w, h;
- vec4_t color = {0.2, 0.2, 1.0, 1};
-
- // setup the refdef
-
- memset( &refdef, 0, sizeof( refdef ) );
-
- refdef.rdflags = RDF_NOWORLDMODEL;
-
- AxisClear( refdef.viewaxis );
-
- x = 0;
- y = 0;
- w = 640;
- h = 120;
- UI_AdjustFrom640( &x, &y, &w, &h );
- refdef.x = x;
- refdef.y = y;
- refdef.width = w;
- refdef.height = h;
-
- adjust = 0; // JDC: Kenneth asked me to stop this 1.0 * sin( (float)uis.realtime / 1000 );
- refdef.fov_x = 60 + adjust;
- refdef.fov_y = 19.6875 + adjust;
-
- refdef.time = uis.realtime;
-
- origin[0] = 300;
- origin[1] = 0;
- origin[2] = -32;
-
- trap_R_ClearScene();
-
- // add the model
-
- memset( &ent, 0, sizeof(ent) );
-
- adjust = 5.0 * sin( (float)uis.realtime / 5000 );
- VectorSet( angles, 0, 180 + adjust, 0 );
- AnglesToAxis( angles, ent.axis );
- ent.hModel = s_main.bannerModel;
- VectorCopy( origin, ent.origin );
- VectorCopy( origin, ent.lightingOrigin );
- ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
- VectorCopy( ent.origin, ent.oldorigin );
-
- trap_R_AddRefEntityToScene( &ent );
-
- trap_R_RenderScene( &refdef );
-
- if (strlen(s_errorMessage.errorMessage))
- {
- UI_DrawProportionalString_AutoWrapped( 320, 192, 600, 20, s_errorMessage.errorMessage, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
- }
- else
- {
- // standard menu drawing
- Menu_Draw( &s_main.menu );
- }
-
- UI_DrawProportionalString( 320, 372, "", UI_CENTER|UI_SMALLFONT, color );
- UI_DrawString( 320, 400, "OpenArena(c) 2005-2009 OpenArena Team", UI_CENTER|UI_SMALLFONT, color );
- UI_DrawString( 320, 414, "OpenArena comes with ABSOLUTELY NO WARRANTY; this is free software", UI_CENTER|UI_SMALLFONT, color );
- UI_DrawString( 320, 428, "and you are welcome to redistribute it under certain conditions;", UI_CENTER|UI_SMALLFONT, color );
- UI_DrawString( 320, 444, "read COPYING for details.", UI_CENTER|UI_SMALLFONT, color );
-
- //Draw version.
- UI_DrawString( 640-40, 480-14, "^7OAX", UI_SMALLFONT, color );
- if((int)trap_Cvar_VariableValue("protocol")!=71)
- UI_DrawString( 0, 480-14, va("^7Protocol: %i",(int)trap_Cvar_VariableValue("protocol")), UI_SMALLFONT, color);
-}
-
-
-/*
-===============
-UI_TeamArenaExists
-===============
-*/
-static qboolean UI_TeamArenaExists( void ) {
- int numdirs;
- char dirlist[2048];
- char *dirptr;
- char *descptr;
- int i;
- int dirlen;
-
- numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) );
- dirptr = dirlist;
- for( i = 0; i < numdirs; i++ ) {
- dirlen = strlen( dirptr ) + 1;
- descptr = dirptr + dirlen;
- if (Q_stricmp(dirptr, "missionpack") == 0) {
- return qtrue;
- }
- dirptr += dirlen + strlen(descptr) + 1;
- }
- return qfalse;
-}
-
-
-/*
-===============
-UI_MainMenu
-
-The main menu only comes up when not in a game,
-so make sure that the attract loop server is down
-and that local cinematics are killed
-===============
-*/
-void UI_MainMenu( void ) {
- int y;
- qboolean teamArena = qfalse;
- int style = UI_CENTER | UI_DROPSHADOW;
-
- trap_Cvar_Set( "sv_killserver", "1" );
-
- memset( &s_main, 0 ,sizeof(mainmenu_t) );
- memset( &s_errorMessage, 0 ,sizeof(errorMessage_t) );
-
- // com_errorMessage would need that too
- MainMenu_Cache();
-
- trap_Cvar_VariableStringBuffer( "com_errorMessage", s_errorMessage.errorMessage, sizeof(s_errorMessage.errorMessage) );
- if (strlen(s_errorMessage.errorMessage))
- {
- s_errorMessage.menu.draw = Main_MenuDraw;
- s_errorMessage.menu.key = ErrorMessage_Key;
- s_errorMessage.menu.fullscreen = qtrue;
- s_errorMessage.menu.wrapAround = qtrue;
- s_errorMessage.menu.showlogo = qtrue;
-
- trap_Key_SetCatcher( KEYCATCH_UI );
- uis.menusp = 0;
- UI_PushMenu ( &s_errorMessage.menu );
-
- return;
- }
-
- s_main.menu.draw = Main_MenuDraw;
- s_main.menu.fullscreen = qtrue;
- s_main.menu.wrapAround = qtrue;
- s_main.menu.showlogo = qtrue;
-
- y = 134;
- s_main.singleplayer.generic.type = MTYPE_PTEXT;
- s_main.singleplayer.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.singleplayer.generic.x = 320;
- s_main.singleplayer.generic.y = y;
- s_main.singleplayer.generic.id = ID_SINGLEPLAYER;
- s_main.singleplayer.generic.callback = Main_MenuEvent;
- s_main.singleplayer.string = "SINGLE PLAYER";
- s_main.singleplayer.color = color_red;
- s_main.singleplayer.style = style;
-
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.multiplayer.generic.type = MTYPE_PTEXT;
- s_main.multiplayer.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.multiplayer.generic.x = 320;
- s_main.multiplayer.generic.y = y;
- s_main.multiplayer.generic.id = ID_MULTIPLAYER;
- s_main.multiplayer.generic.callback = Main_MenuEvent;
- s_main.multiplayer.string = "MULTIPLAYER";
- s_main.multiplayer.color = color_red;
- s_main.multiplayer.style = style;
-
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.setup.generic.type = MTYPE_PTEXT;
- s_main.setup.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.setup.generic.x = 320;
- s_main.setup.generic.y = y;
- s_main.setup.generic.id = ID_SETUP;
- s_main.setup.generic.callback = Main_MenuEvent;
- s_main.setup.string = "SETUP";
- s_main.setup.color = color_red;
- s_main.setup.style = style;
-
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.demos.generic.type = MTYPE_PTEXT;
- s_main.demos.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.demos.generic.x = 320;
- s_main.demos.generic.y = y;
- s_main.demos.generic.id = ID_DEMOS;
- s_main.demos.generic.callback = Main_MenuEvent;
- s_main.demos.string = "DEMOS";
- s_main.demos.color = color_red;
- s_main.demos.style = style;
-
- /*y += MAIN_MENU_VERTICAL_SPACING;
- s_main.cinematics.generic.type = MTYPE_PTEXT;
- s_main.cinematics.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.cinematics.generic.x = 320;
- s_main.cinematics.generic.y = y;
- s_main.cinematics.generic.id = ID_CINEMATICS;
- s_main.cinematics.generic.callback = Main_MenuEvent;
- s_main.cinematics.string = "CINEMATICS";
- s_main.cinematics.color = color_red;
- s_main.cinematics.style = style;*/
-
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.challenges.generic.type = MTYPE_PTEXT;
- s_main.challenges.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.challenges.generic.x = 320;
- s_main.challenges.generic.y = y;
- s_main.challenges.generic.id = ID_CHALLENGES;
- s_main.challenges.generic.callback = Main_MenuEvent;
- s_main.challenges.string = "STATISTICS";
- s_main.challenges.color = color_red;
- s_main.challenges.style = style;
-
- if (UI_TeamArenaExists()) {
- teamArena = qtrue;
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.teamArena.generic.type = MTYPE_PTEXT;
- s_main.teamArena.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.teamArena.generic.x = 320;
- s_main.teamArena.generic.y = y;
- s_main.teamArena.generic.id = ID_TEAMARENA;
- s_main.teamArena.generic.callback = Main_MenuEvent;
- s_main.teamArena.string = "MISSION PACK";
- s_main.teamArena.color = color_red;
- s_main.teamArena.style = style;
- }
-
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.mods.generic.type = MTYPE_PTEXT;
- s_main.mods.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.mods.generic.x = 320;
- s_main.mods.generic.y = y;
- s_main.mods.generic.id = ID_MODS;
- s_main.mods.generic.callback = Main_MenuEvent;
- s_main.mods.string = "MODS";
- s_main.mods.color = color_red;
- s_main.mods.style = style;
-
- y += MAIN_MENU_VERTICAL_SPACING;
- s_main.exit.generic.type = MTYPE_PTEXT;
- s_main.exit.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_main.exit.generic.x = 320;
- s_main.exit.generic.y = y;
- s_main.exit.generic.id = ID_EXIT;
- s_main.exit.generic.callback = Main_MenuEvent;
- s_main.exit.string = "EXIT";
- s_main.exit.color = color_red;
- s_main.exit.style = style;
-
- Menu_AddItem( &s_main.menu, &s_main.singleplayer );
- Menu_AddItem( &s_main.menu, &s_main.multiplayer );
- Menu_AddItem( &s_main.menu, &s_main.setup );
- Menu_AddItem( &s_main.menu, &s_main.demos );
- //Menu_AddItem( &s_main.menu, &s_main.cinematics );
- Menu_AddItem( &s_main.menu, &s_main.challenges );
- if (teamArena) {
- Menu_AddItem( &s_main.menu, &s_main.teamArena );
- }
- Menu_AddItem( &s_main.menu, &s_main.mods );
- Menu_AddItem( &s_main.menu, &s_main.exit );
-
- trap_Key_SetCatcher( KEYCATCH_UI );
- uis.menusp = 0;
- UI_PushMenu ( &s_main.menu );
-
-}
diff --git a/game/code/q3_ui/ui_playermodel.c b/game/code/q3_ui/ui_playermodel.c
deleted file mode 100644
index 99d5a7c..0000000
--- a/game/code/q3_ui/ui_playermodel.c
+++ /dev/null
@@ -1,731 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-#define MODEL_BACK0 "menu/art_blueish/back_0"
-#define MODEL_BACK1 "menu/art_blueish/back_1"
-#define MODEL_SELECT "menu/art/opponents_select"
-#define MODEL_SELECTED "menu/art/opponents_selected"
-#define MODEL_FRAMEL "menu/art_blueish/frame1_l"
-#define MODEL_FRAMER "menu/art_blueish/frame1_r"
-#define MODEL_PORTS "menu/art_blueish/player_models_ports"
-#define MODEL_ARROWS "menu/art_blueish/gs_arrows_0"
-#define MODEL_ARROWSL "menu/art_blueish/gs_arrows_l"
-#define MODEL_ARROWSR "menu/art_blueish/gs_arrows_r"
-
-#define LOW_MEMORY (5 * 1024 * 1024)
-
-static char* playermodel_artlist[] =
-{
- MODEL_BACK0,
- MODEL_BACK1,
- MODEL_SELECT,
- MODEL_SELECTED,
- MODEL_FRAMEL,
- MODEL_FRAMER,
- MODEL_PORTS,
- MODEL_ARROWS,
- MODEL_ARROWSL,
- MODEL_ARROWSR,
- NULL
-};
-
-#define PLAYERGRID_COLS 4
-#define PLAYERGRID_ROWS 4
-#define MAX_MODELSPERPAGE (PLAYERGRID_ROWS*PLAYERGRID_COLS)
-
-#define MAX_PLAYERMODELS 256
-
-#define ID_PLAYERPIC0 0
-#define ID_PLAYERPIC1 1
-#define ID_PLAYERPIC2 2
-#define ID_PLAYERPIC3 3
-#define ID_PLAYERPIC4 4
-#define ID_PLAYERPIC5 5
-#define ID_PLAYERPIC6 6
-#define ID_PLAYERPIC7 7
-#define ID_PLAYERPIC8 8
-#define ID_PLAYERPIC9 9
-#define ID_PLAYERPIC10 10
-#define ID_PLAYERPIC11 11
-#define ID_PLAYERPIC12 12
-#define ID_PLAYERPIC13 13
-#define ID_PLAYERPIC14 14
-#define ID_PLAYERPIC15 15
-#define ID_PREVPAGE 100
-#define ID_NEXTPAGE 101
-#define ID_BACK 102
-
-typedef struct
-{
- menuframework_s menu;
- menubitmap_s pics[MAX_MODELSPERPAGE];
- menubitmap_s picbuttons[MAX_MODELSPERPAGE];
- menubitmap_s framel;
- menubitmap_s framer;
- menubitmap_s ports;
- menutext_s banner;
- menubitmap_s back;
- menubitmap_s player;
- menubitmap_s arrows;
- menubitmap_s left;
- menubitmap_s right;
- menutext_s modelname;
- menutext_s skinname;
- menutext_s playername;
- playerInfo_t playerinfo;
- int nummodels;
- char modelnames[MAX_PLAYERMODELS][128];
- int modelpage;
- int numpages;
- char modelskin[64];
- int selectedmodel;
-} playermodel_t;
-
-static playermodel_t s_playermodel;
-
-/*
-=================
-PlayerModel_UpdateGrid
-=================
-*/
-static void PlayerModel_UpdateGrid( void )
-{
- int i;
- int j;
-
- j = s_playermodel.modelpage * MAX_MODELSPERPAGE;
- for (i=0; i<PLAYERGRID_ROWS*PLAYERGRID_COLS; i++,j++)
- {
- if (j < s_playermodel.nummodels)
- {
- // model/skin portrait
- s_playermodel.pics[i].generic.name = s_playermodel.modelnames[j];
- s_playermodel.picbuttons[i].generic.flags &= ~QMF_INACTIVE;
- }
- else
- {
- // dead slot
- s_playermodel.pics[i].generic.name = NULL;
- s_playermodel.picbuttons[i].generic.flags |= QMF_INACTIVE;
- }
-
- s_playermodel.pics[i].generic.flags &= ~QMF_HIGHLIGHT;
- s_playermodel.pics[i].shader = 0;
- s_playermodel.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
- }
-
- if (s_playermodel.selectedmodel/MAX_MODELSPERPAGE == s_playermodel.modelpage)
- {
- // set selected model
- i = s_playermodel.selectedmodel % MAX_MODELSPERPAGE;
-
- s_playermodel.pics[i].generic.flags |= QMF_HIGHLIGHT;
- s_playermodel.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
- }
-
- if (s_playermodel.numpages > 1)
- {
- if (s_playermodel.modelpage > 0)
- s_playermodel.left.generic.flags &= ~QMF_INACTIVE;
- else
- s_playermodel.left.generic.flags |= QMF_INACTIVE;
-
- if (s_playermodel.modelpage < s_playermodel.numpages-1)
- s_playermodel.right.generic.flags &= ~QMF_INACTIVE;
- else
- s_playermodel.right.generic.flags |= QMF_INACTIVE;
- }
- else
- {
- // hide left/right markers
- s_playermodel.left.generic.flags |= QMF_INACTIVE;
- s_playermodel.right.generic.flags |= QMF_INACTIVE;
- }
-}
-
-/*
-=================
-PlayerModel_UpdateModel
-=================
-*/
-static void PlayerModel_UpdateModel( void )
-{
- vec3_t viewangles;
- vec3_t moveangles;
-
- memset( &s_playermodel.playerinfo, 0, sizeof(playerInfo_t) );
-
- viewangles[YAW] = 180 - 30;
- viewangles[PITCH] = 0;
- viewangles[ROLL] = 0;
- VectorClear( moveangles );
-
- UI_PlayerInfo_SetModel( &s_playermodel.playerinfo, s_playermodel.modelskin );
- UI_PlayerInfo_SetInfo( &s_playermodel.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, moveangles, WP_MACHINEGUN, qfalse );
-}
-
-/*
-=================
-PlayerModel_SaveChanges
-=================
-*/
-static void PlayerModel_SaveChanges( void )
-{
- trap_Cvar_Set( "model", s_playermodel.modelskin );
- trap_Cvar_Set( "headmodel", s_playermodel.modelskin );
- trap_Cvar_Set( "team_model", s_playermodel.modelskin );
- trap_Cvar_Set( "team_headmodel", s_playermodel.modelskin );
-}
-
-/*
-=================
-PlayerModel_MenuEvent
-=================
-*/
-static void PlayerModel_MenuEvent( void* ptr, int event )
-{
- if (event != QM_ACTIVATED)
- return;
-
- switch (((menucommon_s*)ptr)->id)
- {
- case ID_PREVPAGE:
- if (s_playermodel.modelpage > 0)
- {
- s_playermodel.modelpage--;
- PlayerModel_UpdateGrid();
- }
- break;
-
- case ID_NEXTPAGE:
- if (s_playermodel.modelpage < s_playermodel.numpages-1)
- {
- s_playermodel.modelpage++;
- PlayerModel_UpdateGrid();
- }
- break;
-
- case ID_BACK:
- PlayerModel_SaveChanges();
- UI_PopMenu();
- break;
- }
-}
-
-/*
-=================
-PlayerModel_MenuKey
-=================
-*/
-static sfxHandle_t PlayerModel_MenuKey( int key )
-{
- menucommon_s* m;
- int picnum;
-
- switch (key)
- {
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- m = Menu_ItemAtCursor(&s_playermodel.menu);
- picnum = m->id - ID_PLAYERPIC0;
- if (picnum >= 0 && picnum <= 15)
- {
- if (picnum > 0)
- {
- Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor-1);
- return (menu_move_sound);
-
- }
- else if (s_playermodel.modelpage > 0)
- {
- s_playermodel.modelpage--;
- Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor+15);
- PlayerModel_UpdateGrid();
- return (menu_move_sound);
- }
- else
- return (menu_buzz_sound);
- }
- break;
-
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- m = Menu_ItemAtCursor(&s_playermodel.menu);
- picnum = m->id - ID_PLAYERPIC0;
- if (picnum >= 0 && picnum <= 15)
- {
- if ((picnum < 15) && (s_playermodel.modelpage*MAX_MODELSPERPAGE + picnum+1 < s_playermodel.nummodels))
- {
- Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor+1);
- return (menu_move_sound);
- }
- else if ((picnum == 15) && (s_playermodel.modelpage < s_playermodel.numpages-1))
- {
- s_playermodel.modelpage++;
- Menu_SetCursor(&s_playermodel.menu,s_playermodel.menu.cursor-15);
- PlayerModel_UpdateGrid();
- return (menu_move_sound);
- }
- else
- return (menu_buzz_sound);
- }
- break;
-
- case K_MOUSE2:
- case K_ESCAPE:
- PlayerModel_SaveChanges();
- break;
- }
-
- return ( Menu_DefaultKey( &s_playermodel.menu, key ) );
-}
-
-/*
-=================
-PlayerModel_PicEvent
-=================
-*/
-static void PlayerModel_PicEvent( void* ptr, int event )
-{
- int modelnum;
- int maxlen;
- char* buffptr;
- char* pdest;
- int i;
-
- if (event != QM_ACTIVATED)
- return;
-
- for (i=0; i<PLAYERGRID_ROWS*PLAYERGRID_COLS; i++)
- {
- // reset
- s_playermodel.pics[i].generic.flags &= ~QMF_HIGHLIGHT;
- s_playermodel.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
- }
-
- // set selected
- i = ((menucommon_s*)ptr)->id - ID_PLAYERPIC0;
- s_playermodel.pics[i].generic.flags |= QMF_HIGHLIGHT;
- s_playermodel.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
-
- // get model and strip icon_
- modelnum = s_playermodel.modelpage*MAX_MODELSPERPAGE + i;
- buffptr = s_playermodel.modelnames[modelnum] + strlen("models/players/");
- pdest = strstr(buffptr,"icon_");
- if (pdest)
- {
- // track the whole model/skin name
- Q_strncpyz(s_playermodel.modelskin,buffptr,pdest-buffptr+1);
- strcat(s_playermodel.modelskin,pdest + 5);
-
- // seperate the model name
- maxlen = pdest-buffptr;
- if (maxlen > 16)
- maxlen = 16;
- Q_strncpyz( s_playermodel.modelname.string, buffptr, maxlen );
- Q_strupr( s_playermodel.modelname.string );
-
- // seperate the skin name
- maxlen = strlen(pdest+5)+1;
- if (maxlen > 16)
- maxlen = 16;
- Q_strncpyz( s_playermodel.skinname.string, pdest+5, maxlen );
- Q_strupr( s_playermodel.skinname.string );
-
- s_playermodel.selectedmodel = modelnum;
-
- if( trap_MemoryRemaining() > LOW_MEMORY ) {
- PlayerModel_UpdateModel();
- }
- }
-}
-
-/*
-=================
-PlayerModel_DrawPlayer
-=================
-*/
-static void PlayerModel_DrawPlayer( void *self )
-{
- menubitmap_s* b;
-
- b = (menubitmap_s*) self;
-
- if( trap_MemoryRemaining() <= LOW_MEMORY ) {
- UI_DrawProportionalString( b->generic.x, b->generic.y + b->height / 2, "LOW MEMORY", UI_LEFT, color_red );
- return;
- }
-
- UI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_playermodel.playerinfo, uis.realtime/2 );
-}
-
-/*
-=================
-PlayerModel_BuildList
-=================
-*/
-static void PlayerModel_BuildList( void )
-{
- int numdirs;
- int numfiles;
- char dirlist[2048];
- char filelist[2048];
- char skinname[MAX_QPATH];
- char* dirptr;
- char* fileptr;
- int i;
- int j;
- int dirlen;
- int filelen;
- qboolean precache;
-
- precache = trap_Cvar_VariableValue("com_buildscript");
-
- s_playermodel.modelpage = 0;
- s_playermodel.nummodels = 0;
-
- // iterate directory of all player models
- numdirs = trap_FS_GetFileList("models/players", "/", dirlist, 2048 );
- dirptr = dirlist;
- for (i=0; i<numdirs && s_playermodel.nummodels < MAX_PLAYERMODELS; i++,dirptr+=dirlen+1)
- {
- dirlen = strlen(dirptr);
-
- if (dirlen && dirptr[dirlen-1]=='/') dirptr[dirlen-1]='\0';
-
- if (!strcmp(dirptr,".") || !strcmp(dirptr,".."))
- continue;
-
- // iterate all skin files in directory
- numfiles = trap_FS_GetFileList( va("models/players/%s",dirptr), "tga", filelist, 2048 );
- fileptr = filelist;
- for (j=0; j<numfiles && s_playermodel.nummodels < MAX_PLAYERMODELS;j++,fileptr+=filelen+1)
- {
- filelen = strlen(fileptr);
-
- COM_StripExtension(fileptr,skinname, sizeof(skinname));
-
- // look for icon_????
- if (!Q_stricmpn(skinname,"icon_",5))
- {
- Com_sprintf( s_playermodel.modelnames[s_playermodel.nummodels++],
- sizeof( s_playermodel.modelnames[s_playermodel.nummodels] ),
- "models/players/%s/%s", dirptr, skinname );
- //if (s_playermodel.nummodels >= MAX_PLAYERMODELS)
- // return;
- }
-
- if( precache ) {
- trap_S_RegisterSound( va( "sound/player/announce/%s_wins.wav", skinname), qfalse );
- }
- }
- }
-
- //APSFIXME - Degenerate no models case
-
- s_playermodel.numpages = s_playermodel.nummodels/MAX_MODELSPERPAGE;
- if (s_playermodel.nummodels % MAX_MODELSPERPAGE)
- s_playermodel.numpages++;
-}
-
-/*
-=================
-PlayerModel_SetMenuItems
-=================
-*/
-static void PlayerModel_SetMenuItems( void )
-{
- int i;
- int maxlen;
- char modelskin[64];
- char* buffptr;
- char* pdest;
-
- // name
- trap_Cvar_VariableStringBuffer( "name", s_playermodel.playername.string, 16 );
- Q_CleanStr( s_playermodel.playername.string );
-
- // model
- trap_Cvar_VariableStringBuffer( "model", s_playermodel.modelskin, 64 );
-
- // find model in our list
- for (i=0; i<s_playermodel.nummodels; i++)
- {
- // strip icon_
- buffptr = s_playermodel.modelnames[i] + strlen("models/players/");
- pdest = strstr(buffptr,"icon_");
- if (pdest)
- {
- Q_strncpyz(modelskin,buffptr,pdest-buffptr+1);
- strcat(modelskin,pdest + 5);
- }
- else
- continue;
-
- if (!Q_stricmp( s_playermodel.modelskin, modelskin ))
- {
- // found pic, set selection here
- s_playermodel.selectedmodel = i;
- s_playermodel.modelpage = i/MAX_MODELSPERPAGE;
-
- // seperate the model name
- maxlen = pdest-buffptr;
- if (maxlen > 16)
- maxlen = 16;
- Q_strncpyz( s_playermodel.modelname.string, buffptr, maxlen );
- Q_strupr( s_playermodel.modelname.string );
-
- // seperate the skin name
- maxlen = strlen(pdest+5)+1;
- if (maxlen > 16)
- maxlen = 16;
- Q_strncpyz( s_playermodel.skinname.string, pdest+5, maxlen );
- Q_strupr( s_playermodel.skinname.string );
- break;
- }
- }
-}
-
-/*
-=================
-PlayerModel_MenuInit
-=================
-*/
-static void PlayerModel_MenuInit( void )
-{
- int i;
- int j;
- int k;
- int x;
- int y;
- static char playername[32];
- static char modelname[32];
- static char skinname[32];
-
- // zero set all our globals
- memset( &s_playermodel, 0 ,sizeof(playermodel_t) );
-
- PlayerModel_Cache();
-
- s_playermodel.menu.key = PlayerModel_MenuKey;
- s_playermodel.menu.wrapAround = qtrue;
- s_playermodel.menu.fullscreen = qtrue;
-
- s_playermodel.banner.generic.type = MTYPE_BTEXT;
- s_playermodel.banner.generic.x = 320;
- s_playermodel.banner.generic.y = 16;
- s_playermodel.banner.string = "PLAYER MODEL";
- s_playermodel.banner.color = color_white;
- s_playermodel.banner.style = UI_CENTER;
-
- s_playermodel.framel.generic.type = MTYPE_BITMAP;
- s_playermodel.framel.generic.name = MODEL_FRAMEL;
- s_playermodel.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_playermodel.framel.generic.x = 0;
- s_playermodel.framel.generic.y = 78;
- s_playermodel.framel.width = 256;
- s_playermodel.framel.height = 329;
-
- s_playermodel.framer.generic.type = MTYPE_BITMAP;
- s_playermodel.framer.generic.name = MODEL_FRAMER;
- s_playermodel.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_playermodel.framer.generic.x = 376;
- s_playermodel.framer.generic.y = 76;
- s_playermodel.framer.width = 256;
- s_playermodel.framer.height = 334;
-
- s_playermodel.ports.generic.type = MTYPE_BITMAP;
- s_playermodel.ports.generic.name = MODEL_PORTS;
- s_playermodel.ports.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_playermodel.ports.generic.x = 50;
- s_playermodel.ports.generic.y = 59;
- s_playermodel.ports.width = 274;
- s_playermodel.ports.height = 274;
-
- y = 59;
- for (i=0,k=0; i<PLAYERGRID_ROWS; i++)
- {
- x = 50;
- for (j=0; j<PLAYERGRID_COLS; j++,k++)
- {
- s_playermodel.pics[k].generic.type = MTYPE_BITMAP;
- s_playermodel.pics[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_playermodel.pics[k].generic.x = x;
- s_playermodel.pics[k].generic.y = y;
- s_playermodel.pics[k].width = 64;
- s_playermodel.pics[k].height = 64;
- s_playermodel.pics[k].focuspic = MODEL_SELECTED;
- s_playermodel.pics[k].focuscolor = colorRed;
-
- s_playermodel.picbuttons[k].generic.type = MTYPE_BITMAP;
- s_playermodel.picbuttons[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS;
- s_playermodel.picbuttons[k].generic.id = ID_PLAYERPIC0+k;
- s_playermodel.picbuttons[k].generic.callback = PlayerModel_PicEvent;
- s_playermodel.picbuttons[k].generic.x = x - 16;
- s_playermodel.picbuttons[k].generic.y = y - 16;
- s_playermodel.picbuttons[k].generic.left = x;
- s_playermodel.picbuttons[k].generic.top = y;
- s_playermodel.picbuttons[k].generic.right = x + 64;
- s_playermodel.picbuttons[k].generic.bottom = y + 64;
- s_playermodel.picbuttons[k].width = 128;
- s_playermodel.picbuttons[k].height = 128;
- s_playermodel.picbuttons[k].focuspic = MODEL_SELECT;
- s_playermodel.picbuttons[k].focuscolor = colorRed;
-
- x += 64+6;
- }
- y += 64+6;
- }
-
- s_playermodel.playername.generic.type = MTYPE_PTEXT;
- s_playermodel.playername.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
- s_playermodel.playername.generic.x = 320;
- s_playermodel.playername.generic.y = 440;
- s_playermodel.playername.string = playername;
- s_playermodel.playername.style = UI_CENTER;
- s_playermodel.playername.color = text_color_normal;
-
- s_playermodel.modelname.generic.type = MTYPE_PTEXT;
- s_playermodel.modelname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
- s_playermodel.modelname.generic.x = 497;
- s_playermodel.modelname.generic.y = 54;
- s_playermodel.modelname.string = modelname;
- s_playermodel.modelname.style = UI_CENTER;
- s_playermodel.modelname.color = text_color_normal;
-
- s_playermodel.skinname.generic.type = MTYPE_PTEXT;
- s_playermodel.skinname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
- s_playermodel.skinname.generic.x = 497;
- s_playermodel.skinname.generic.y = 394;
- s_playermodel.skinname.string = skinname;
- s_playermodel.skinname.style = UI_CENTER;
- s_playermodel.skinname.color = text_color_normal;
-
- s_playermodel.player.generic.type = MTYPE_BITMAP;
- s_playermodel.player.generic.flags = QMF_INACTIVE;
- s_playermodel.player.generic.ownerdraw = PlayerModel_DrawPlayer;
- s_playermodel.player.generic.x = 400;
- s_playermodel.player.generic.y = -40;
- s_playermodel.player.width = 32*10;
- s_playermodel.player.height = 56*10;
-
- s_playermodel.arrows.generic.type = MTYPE_BITMAP;
- s_playermodel.arrows.generic.name = MODEL_ARROWS;
- s_playermodel.arrows.generic.flags = QMF_INACTIVE;
- s_playermodel.arrows.generic.x = 125;
- s_playermodel.arrows.generic.y = 340;
- s_playermodel.arrows.width = 128;
- s_playermodel.arrows.height = 32;
-
- s_playermodel.left.generic.type = MTYPE_BITMAP;
- s_playermodel.left.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_playermodel.left.generic.callback = PlayerModel_MenuEvent;
- s_playermodel.left.generic.id = ID_PREVPAGE;
- s_playermodel.left.generic.x = 125;
- s_playermodel.left.generic.y = 340;
- s_playermodel.left.width = 64;
- s_playermodel.left.height = 32;
- s_playermodel.left.focuspic = MODEL_ARROWSL;
-
- s_playermodel.right.generic.type = MTYPE_BITMAP;
- s_playermodel.right.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_playermodel.right.generic.callback = PlayerModel_MenuEvent;
- s_playermodel.right.generic.id = ID_NEXTPAGE;
- s_playermodel.right.generic.x = 125+61;
- s_playermodel.right.generic.y = 340;
- s_playermodel.right.width = 64;
- s_playermodel.right.height = 32;
- s_playermodel.right.focuspic = MODEL_ARROWSR;
-
- s_playermodel.back.generic.type = MTYPE_BITMAP;
- s_playermodel.back.generic.name = MODEL_BACK0;
- s_playermodel.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_playermodel.back.generic.callback = PlayerModel_MenuEvent;
- s_playermodel.back.generic.id = ID_BACK;
- s_playermodel.back.generic.x = 0;
- s_playermodel.back.generic.y = 480-64;
- s_playermodel.back.width = 128;
- s_playermodel.back.height = 64;
- s_playermodel.back.focuspic = MODEL_BACK1;
-
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.banner );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.framel );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.framer );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.ports );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.playername );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.modelname );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.skinname );
-
- for (i=0; i<MAX_MODELSPERPAGE; i++)
- {
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.pics[i] );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.picbuttons[i] );
- }
-
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.player );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.arrows );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.left );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.right );
- Menu_AddItem( &s_playermodel.menu, &s_playermodel.back );
-
- // find all available models
-// PlayerModel_BuildList();
-
- // set initial states
- PlayerModel_SetMenuItems();
-
- // update user interface
- PlayerModel_UpdateGrid();
- PlayerModel_UpdateModel();
-}
-
-/*
-=================
-PlayerModel_Cache
-=================
-*/
-void PlayerModel_Cache( void )
-{
- int i;
-
- for( i = 0; playermodel_artlist[i]; i++ ) {
- trap_R_RegisterShaderNoMip( playermodel_artlist[i] );
- }
-
- PlayerModel_BuildList();
- for( i = 0; i < s_playermodel.nummodels; i++ ) {
- trap_R_RegisterShaderNoMip( s_playermodel.modelnames[i] );
- }
-}
-
-void UI_PlayerModelMenu(void)
-{
- PlayerModel_MenuInit();
-
- UI_PushMenu( &s_playermodel.menu );
-
- Menu_SetCursorToItem( &s_playermodel.menu, &s_playermodel.pics[s_playermodel.selectedmodel % MAX_MODELSPERPAGE] );
-}
-
-
diff --git a/game/code/q3_ui/ui_players.c b/game/code/q3_ui/ui_players.c
deleted file mode 100644
index 182b5f0..0000000
--- a/game/code/q3_ui/ui_players.c
+++ /dev/null
@@ -1,1249 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// ui_players.c
-
-#include "ui_local.h"
-
-
-#define UI_TIMER_GESTURE 2300
-#define UI_TIMER_JUMP 1000
-#define UI_TIMER_LAND 130
-#define UI_TIMER_WEAPON_SWITCH 300
-#define UI_TIMER_ATTACK 500
-#define UI_TIMER_MUZZLE_FLASH 20
-#define UI_TIMER_WEAPON_DELAY 250
-
-#define JUMP_HEIGHT 56
-
-#define SWINGSPEED 0.3f
-
-#define SPIN_SPEED 0.9f
-#define COAST_TIME 1000
-
-
-static int dp_realtime;
-static float jumpHeight;
-
-
-/*
-===============
-UI_PlayerInfo_SetWeapon
-===============
-*/
-static void UI_PlayerInfo_SetWeapon( playerInfo_t *pi, weapon_t weaponNum ) {
- gitem_t * item;
- char path[MAX_QPATH];
-
- pi->currentWeapon = weaponNum;
-tryagain:
- pi->realWeapon = weaponNum;
- pi->weaponModel = 0;
- pi->barrelModel = 0;
- pi->flashModel = 0;
-
- if ( weaponNum == WP_NONE ) {
- return;
- }
-
- for ( item = bg_itemlist + 1; item->classname ; item++ ) {
- if ( item->giType != IT_WEAPON ) {
- continue;
- }
- if ( item->giTag == weaponNum ) {
- break;
- }
- }
-
- if ( item->classname ) {
- pi->weaponModel = trap_R_RegisterModel( item->world_model[0] );
- }
-
- if( pi->weaponModel == 0 ) {
- if( weaponNum == WP_MACHINEGUN ) {
- weaponNum = WP_NONE;
- goto tryagain;
- }
- weaponNum = WP_MACHINEGUN;
- goto tryagain;
- }
-
- if ( weaponNum == WP_MACHINEGUN || weaponNum == WP_GAUNTLET || weaponNum == WP_BFG ) {
- strcpy( path, item->world_model[0] );
- COM_StripExtension( path, path, sizeof(path) );
- strcat( path, "_barrel.md3" );
- pi->barrelModel = trap_R_RegisterModel( path );
- }
-
- strcpy( path, item->world_model[0] );
- COM_StripExtension( path, path, sizeof(path) );
- strcat( path, "_flash.md3" );
- pi->flashModel = trap_R_RegisterModel( path );
-
- switch( weaponNum ) {
- case WP_GAUNTLET:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_MACHINEGUN:
- MAKERGB( pi->flashDlightColor, 1, 1, 0 );
- break;
-
- case WP_SHOTGUN:
- MAKERGB( pi->flashDlightColor, 1, 1, 0 );
- break;
-
- case WP_GRENADE_LAUNCHER:
- MAKERGB( pi->flashDlightColor, 1, 0.7f, 0.5f );
- break;
-
- case WP_ROCKET_LAUNCHER:
- MAKERGB( pi->flashDlightColor, 1, 0.75f, 0 );
- break;
-
- case WP_LIGHTNING:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_RAILGUN:
- MAKERGB( pi->flashDlightColor, 1, 0.5f, 0 );
- break;
-
- case WP_PLASMAGUN:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_BFG:
- MAKERGB( pi->flashDlightColor, 1, 0.7f, 1 );
- break;
-
- case WP_GRAPPLING_HOOK:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- default:
- MAKERGB( pi->flashDlightColor, 1, 1, 1 );
- break;
- }
-}
-
-
-/*
-===============
-UI_ForceLegsAnim
-===============
-*/
-static void UI_ForceLegsAnim( playerInfo_t *pi, int anim ) {
- pi->legsAnim = ( ( pi->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-
- if ( anim == LEGS_JUMP ) {
- pi->legsAnimationTimer = UI_TIMER_JUMP;
- }
-}
-
-
-/*
-===============
-UI_SetLegsAnim
-===============
-*/
-static void UI_SetLegsAnim( playerInfo_t *pi, int anim ) {
- if ( pi->pendingLegsAnim ) {
- anim = pi->pendingLegsAnim;
- pi->pendingLegsAnim = 0;
- }
- UI_ForceLegsAnim( pi, anim );
-}
-
-
-/*
-===============
-UI_ForceTorsoAnim
-===============
-*/
-static void UI_ForceTorsoAnim( playerInfo_t *pi, int anim ) {
- pi->torsoAnim = ( ( pi->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-
- if ( anim == TORSO_GESTURE ) {
- pi->torsoAnimationTimer = UI_TIMER_GESTURE;
- }
-
- if ( anim == TORSO_ATTACK || anim == TORSO_ATTACK2 ) {
- pi->torsoAnimationTimer = UI_TIMER_ATTACK;
- }
-}
-
-
-/*
-===============
-UI_SetTorsoAnim
-===============
-*/
-static void UI_SetTorsoAnim( playerInfo_t *pi, int anim ) {
- if ( pi->pendingTorsoAnim ) {
- anim = pi->pendingTorsoAnim;
- pi->pendingTorsoAnim = 0;
- }
-
- UI_ForceTorsoAnim( pi, anim );
-}
-
-
-/*
-===============
-UI_TorsoSequencing
-===============
-*/
-static void UI_TorsoSequencing( playerInfo_t *pi ) {
- int currentAnim;
-
- currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
-
- if ( pi->weapon != pi->currentWeapon ) {
- if ( currentAnim != TORSO_DROP ) {
- pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
- UI_ForceTorsoAnim( pi, TORSO_DROP );
- }
- }
-
- if ( pi->torsoAnimationTimer > 0 ) {
- return;
- }
-
- if( currentAnim == TORSO_GESTURE ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-
- if( currentAnim == TORSO_ATTACK || currentAnim == TORSO_ATTACK2 ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-
- if ( currentAnim == TORSO_DROP ) {
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
- pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
- UI_ForceTorsoAnim( pi, TORSO_RAISE );
- return;
- }
-
- if ( currentAnim == TORSO_RAISE ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-}
-
-
-/*
-===============
-UI_LegsSequencing
-===============
-*/
-static void UI_LegsSequencing( playerInfo_t *pi ) {
- int currentAnim;
-
- currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
-
- if ( pi->legsAnimationTimer > 0 ) {
- if ( currentAnim == LEGS_JUMP ) {
- jumpHeight = JUMP_HEIGHT * sin( M_PI * ( UI_TIMER_JUMP - pi->legsAnimationTimer ) / UI_TIMER_JUMP );
- }
- return;
- }
-
- if ( currentAnim == LEGS_JUMP ) {
- UI_ForceLegsAnim( pi, LEGS_LAND );
- pi->legsAnimationTimer = UI_TIMER_LAND;
- jumpHeight = 0;
- return;
- }
-
- if ( currentAnim == LEGS_LAND ) {
- UI_SetLegsAnim( pi, LEGS_IDLE );
- return;
- }
-}
-
-
-/*
-======================
-UI_PositionEntityOnTag
-======================
-*/
-static void UI_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- clipHandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
-
- // lerp the tag
- trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // cast away const because of compiler problems
- MatrixMultiply( lerped.axis, ((refEntity_t*)parent)->axis, entity->axis );
- entity->backlerp = parent->backlerp;
-}
-
-
-/*
-======================
-UI_PositionRotatedEntityOnTag
-======================
-*/
-static void UI_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- clipHandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
- vec3_t tempAxis[3];
-
- // lerp the tag
- trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // cast away const because of compiler problems
- MatrixMultiply( entity->axis, ((refEntity_t *)parent)->axis, tempAxis );
- MatrixMultiply( lerped.axis, tempAxis, entity->axis );
-}
-
-
-/*
-===============
-UI_SetLerpFrameAnimation
-===============
-*/
-static void UI_SetLerpFrameAnimation( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
- animation_t *anim;
-
- lf->animationNumber = newAnimation;
- newAnimation &= ~ANIM_TOGGLEBIT;
-
- if ( newAnimation < 0 || newAnimation >= MAX_ANIMATIONS ) {
- trap_Error( va("Bad animation number: %i", newAnimation) );
- }
-
- anim = &ci->animations[ newAnimation ];
-
- lf->animation = anim;
- lf->animationTime = lf->frameTime + anim->initialLerp;
-}
-
-
-/*
-===============
-UI_RunLerpFrame
-===============
-*/
-static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
- int f;
- animation_t *anim;
-
- // see if the animation sequence is switching
- if ( newAnimation != lf->animationNumber || !lf->animation ) {
- UI_SetLerpFrameAnimation( ci, lf, newAnimation );
- }
-
- // if we have passed the current frame, move it to
- // oldFrame and calculate a new frame
- if ( dp_realtime >= lf->frameTime ) {
- lf->oldFrame = lf->frame;
- lf->oldFrameTime = lf->frameTime;
-
- // get the next frame based on the animation
- anim = lf->animation;
- if ( dp_realtime < lf->animationTime ) {
- lf->frameTime = lf->animationTime; // initial lerp
- } else {
- lf->frameTime = lf->oldFrameTime + anim->frameLerp;
- }
- f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
- if ( f >= anim->numFrames ) {
- f -= anim->numFrames;
- if ( anim->loopFrames ) {
- f %= anim->loopFrames;
- f += anim->numFrames - anim->loopFrames;
- } else {
- f = anim->numFrames - 1;
- // the animation is stuck at the end, so it
- // can immediately transition to another sequence
- lf->frameTime = dp_realtime;
- }
- }
- lf->frame = anim->firstFrame + f;
- if ( dp_realtime > lf->frameTime ) {
- lf->frameTime = dp_realtime;
- }
- }
-
- if ( lf->frameTime > dp_realtime + 200 ) {
- lf->frameTime = dp_realtime;
- }
-
- if ( lf->oldFrameTime > dp_realtime ) {
- lf->oldFrameTime = dp_realtime;
- }
- // calculate current lerp value
- if ( lf->frameTime == lf->oldFrameTime ) {
- lf->backlerp = 0;
- } else {
- lf->backlerp = 1.0 - (float)( dp_realtime - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
- }
-}
-
-
-/*
-===============
-UI_PlayerAnimation
-===============
-*/
-static void UI_PlayerAnimation( playerInfo_t *pi, int *legsOld, int *legs, float *legsBackLerp,
- int *torsoOld, int *torso, float *torsoBackLerp ) {
-
- // legs animation
- pi->legsAnimationTimer -= uis.frametime;
- if ( pi->legsAnimationTimer < 0 ) {
- pi->legsAnimationTimer = 0;
- }
-
- UI_LegsSequencing( pi );
-
- if ( pi->legs.yawing && ( pi->legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {
- UI_RunLerpFrame( pi, &pi->legs, LEGS_TURN );
- } else {
- UI_RunLerpFrame( pi, &pi->legs, pi->legsAnim );
- }
- *legsOld = pi->legs.oldFrame;
- *legs = pi->legs.frame;
- *legsBackLerp = pi->legs.backlerp;
-
- // torso animation
- pi->torsoAnimationTimer -= uis.frametime;
- if ( pi->torsoAnimationTimer < 0 ) {
- pi->torsoAnimationTimer = 0;
- }
-
- UI_TorsoSequencing( pi );
-
- UI_RunLerpFrame( pi, &pi->torso, pi->torsoAnim );
- *torsoOld = pi->torso.oldFrame;
- *torso = pi->torso.frame;
- *torsoBackLerp = pi->torso.backlerp;
-}
-
-
-/*
-==================
-UI_SwingAngles
-==================
-*/
-static void UI_SwingAngles( float destination, float swingTolerance, float clampTolerance,
- float speed, float *angle, qboolean *swinging ) {
- float swing;
- float move;
- float scale;
-
- if ( !*swinging ) {
- // see if a swing should be started
- swing = AngleSubtract( *angle, destination );
- if ( swing > swingTolerance || swing < -swingTolerance ) {
- *swinging = qtrue;
- }
- }
-
- if ( !*swinging ) {
- return;
- }
-
- // modify the speed depending on the delta
- // so it doesn't seem so linear
- swing = AngleSubtract( destination, *angle );
- scale = fabs( swing );
- if ( scale < swingTolerance * 0.5 ) {
- scale = 0.5;
- } else if ( scale < swingTolerance ) {
- scale = 1.0;
- } else {
- scale = 2.0;
- }
-
- // swing towards the destination angle
- if ( swing >= 0 ) {
- move = uis.frametime * scale * speed;
- if ( move >= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- } else if ( swing < 0 ) {
- move = uis.frametime * scale * -speed;
- if ( move <= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- }
-
- // clamp to no more than tolerance
- swing = AngleSubtract( destination, *angle );
- if ( swing > clampTolerance ) {
- *angle = AngleMod( destination - (clampTolerance - 1) );
- } else if ( swing < -clampTolerance ) {
- *angle = AngleMod( destination + (clampTolerance - 1) );
- }
-}
-
-
-/*
-======================
-UI_MovedirAdjustment
-======================
-*/
-static float UI_MovedirAdjustment( playerInfo_t *pi ) {
- vec3_t relativeAngles;
- vec3_t moveVector;
-
- VectorSubtract( pi->viewAngles, pi->moveAngles, relativeAngles );
- AngleVectors( relativeAngles, moveVector, NULL, NULL );
- if ( Q_fabs( moveVector[0] ) < 0.01 ) {
- moveVector[0] = 0.0;
- }
- if ( Q_fabs( moveVector[1] ) < 0.01 ) {
- moveVector[1] = 0.0;
- }
-
- if ( moveVector[1] == 0 && moveVector[0] > 0 ) {
- return 0;
- }
- if ( moveVector[1] < 0 && moveVector[0] > 0 ) {
- return 22;
- }
- if ( moveVector[1] < 0 && moveVector[0] == 0 ) {
- return 45;
- }
- if ( moveVector[1] < 0 && moveVector[0] < 0 ) {
- return -22;
- }
- if ( moveVector[1] == 0 && moveVector[0] < 0 ) {
- return 0;
- }
- if ( moveVector[1] > 0 && moveVector[0] < 0 ) {
- return 22;
- }
- if ( moveVector[1] > 0 && moveVector[0] == 0 ) {
- return -45;
- }
-
- return -22;
-}
-
-
-/*
-===============
-UI_PlayerAngles
-===============
-*/
-static void UI_PlayerAngles( playerInfo_t *pi, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {
- vec3_t legsAngles, torsoAngles, headAngles;
- float dest;
- float adjust;
-
- VectorCopy( pi->viewAngles, headAngles );
- headAngles[YAW] = AngleMod( headAngles[YAW] );
- VectorClear( legsAngles );
- VectorClear( torsoAngles );
-
- // --------- yaw -------------
-
- // allow yaw to drift a bit
- if ( ( pi->legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE
- || ( pi->torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) {
- // if not standing still, always point all in the same direction
- pi->torso.yawing = qtrue; // always center
- pi->torso.pitching = qtrue; // always center
- pi->legs.yawing = qtrue; // always center
- }
-
- // adjust legs for movement dir
- adjust = UI_MovedirAdjustment( pi );
- legsAngles[YAW] = headAngles[YAW] + adjust;
- torsoAngles[YAW] = headAngles[YAW] + 0.25 * adjust;
-
-
- // torso
- UI_SwingAngles( torsoAngles[YAW], 25, 90, SWINGSPEED, &pi->torso.yawAngle, &pi->torso.yawing );
- UI_SwingAngles( legsAngles[YAW], 40, 90, SWINGSPEED, &pi->legs.yawAngle, &pi->legs.yawing );
-
- torsoAngles[YAW] = pi->torso.yawAngle;
- legsAngles[YAW] = pi->legs.yawAngle;
-
- // --------- pitch -------------
-
- // only show a fraction of the pitch angle in the torso
- if ( headAngles[PITCH] > 180 ) {
- dest = (-360 + headAngles[PITCH]) * 0.75;
- } else {
- dest = headAngles[PITCH] * 0.75;
- }
- UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching );
- torsoAngles[PITCH] = pi->torso.pitchAngle;
-
- // pull the angles back out of the hierarchial chain
- AnglesSubtract( headAngles, torsoAngles, headAngles );
- AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
- AnglesToAxis( legsAngles, legs );
- AnglesToAxis( torsoAngles, torso );
- AnglesToAxis( headAngles, head );
-}
-
-
-/*
-===============
-UI_PlayerFloatSprite
-===============
-*/
-static void UI_PlayerFloatSprite( playerInfo_t *pi, vec3_t origin, qhandle_t shader ) {
- refEntity_t ent;
-
- memset( &ent, 0, sizeof( ent ) );
- VectorCopy( origin, ent.origin );
- ent.origin[2] += 48;
- ent.reType = RT_SPRITE;
- ent.customShader = shader;
- ent.radius = 10;
- ent.renderfx = 0;
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-/*
-======================
-UI_MachinegunSpinAngle
-======================
-*/
-float UI_MachinegunSpinAngle( playerInfo_t *pi ) {
- int delta;
- float angle;
- float speed;
- int torsoAnim;
-
- delta = dp_realtime - pi->barrelTime;
- if ( pi->barrelSpinning ) {
- angle = pi->barrelAngle + delta * SPIN_SPEED;
- } else {
- if ( delta > COAST_TIME ) {
- delta = COAST_TIME;
- }
-
- speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
- angle = pi->barrelAngle + delta * speed;
- }
-
- torsoAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
- if( torsoAnim == TORSO_ATTACK2 ) {
- torsoAnim = TORSO_ATTACK;
- }
- if ( pi->barrelSpinning == !(torsoAnim == TORSO_ATTACK) ) {
- pi->barrelTime = dp_realtime;
- pi->barrelAngle = AngleMod( angle );
- pi->barrelSpinning = !!(torsoAnim == TORSO_ATTACK);
- }
-
- return angle;
-}
-
-
-/*
-===============
-UI_DrawPlayer
-===============
-*/
-void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ) {
- refdef_t refdef;
- refEntity_t legs;
- refEntity_t torso;
- refEntity_t head;
- refEntity_t gun;
- refEntity_t barrel;
- refEntity_t flash;
- vec3_t origin;
- int renderfx;
- vec3_t mins = {-16, -16, -24};
- vec3_t maxs = {16, 16, 32};
- float len;
- float xx;
-
- if ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) {
- return;
- }
-
- dp_realtime = time;
-
- if ( pi->pendingWeapon != -1 && dp_realtime > pi->weaponTimer ) {
- pi->weapon = pi->pendingWeapon;
- pi->lastWeapon = pi->pendingWeapon;
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- if( pi->currentWeapon != pi->weapon ) {
- trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL );
- }
- }
-
- UI_AdjustFrom640( &x, &y, &w, &h );
-
- y -= jumpHeight;
-
- memset( &refdef, 0, sizeof( refdef ) );
- memset( &legs, 0, sizeof(legs) );
- memset( &torso, 0, sizeof(torso) );
- memset( &head, 0, sizeof(head) );
-
- refdef.rdflags = RDF_NOWORLDMODEL;
-
- AxisClear( refdef.viewaxis );
-
- refdef.x = x;
- refdef.y = y;
- refdef.width = w;
- refdef.height = h;
-
- refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
- xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
- refdef.fov_y = atan2( refdef.height, xx );
- refdef.fov_y *= ( 360 / M_PI );
-
- // calculate distance so the player nearly fills the box
- len = 0.7 * ( maxs[2] - mins[2] );
- origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
-
- refdef.time = dp_realtime;
-
- trap_R_ClearScene();
-
- // get the rotation information
- UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis );
-
- // get the animation state (after rotation, to allow feet shuffle)
- UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp,
- &torso.oldframe, &torso.frame, &torso.backlerp );
-
- renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
-
- //
- // add the legs
- //
- legs.hModel = pi->legsModel;
- legs.customSkin = pi->legsSkin;
-
- VectorCopy( origin, legs.origin );
-
- VectorCopy( origin, legs.lightingOrigin );
- legs.renderfx = renderfx;
- VectorCopy (legs.origin, legs.oldorigin);
-
- trap_R_AddRefEntityToScene( &legs );
-
- if (!legs.hModel) {
- return;
- }
-
- //
- // add the torso
- //
- torso.hModel = pi->torsoModel;
- if (!torso.hModel) {
- return;
- }
-
- torso.customSkin = pi->torsoSkin;
-
- VectorCopy( origin, torso.lightingOrigin );
-
- UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, "tag_torso");
-
- torso.renderfx = renderfx;
-
- trap_R_AddRefEntityToScene( &torso );
-
- //
- // add the head
- //
- head.hModel = pi->headModel;
- if (!head.hModel) {
- return;
- }
- head.customSkin = pi->headSkin;
-
- VectorCopy( origin, head.lightingOrigin );
-
- UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, "tag_head");
-
- head.renderfx = renderfx;
-
- trap_R_AddRefEntityToScene( &head );
-
- //
- // add the gun
- //
- if ( pi->currentWeapon != WP_NONE ) {
- memset( &gun, 0, sizeof(gun) );
- gun.hModel = pi->weaponModel;
- VectorCopy( origin, gun.lightingOrigin );
- UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, "tag_weapon");
- gun.renderfx = renderfx;
- trap_R_AddRefEntityToScene( &gun );
- }
-
- //
- // add the spinning barrel
- //
- if ( pi->realWeapon == WP_MACHINEGUN || pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
- vec3_t angles;
-
- memset( &barrel, 0, sizeof(barrel) );
- VectorCopy( origin, barrel.lightingOrigin );
- barrel.renderfx = renderfx;
-
- barrel.hModel = pi->barrelModel;
- angles[YAW] = 0;
- angles[PITCH] = 0;
- angles[ROLL] = UI_MachinegunSpinAngle( pi );
- if( pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
- angles[PITCH] = angles[ROLL];
- angles[ROLL] = 0;
- }
- AnglesToAxis( angles, barrel.axis );
-
- UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel");
-
- trap_R_AddRefEntityToScene( &barrel );
- }
-
- //
- // add muzzle flash
- //
- if ( dp_realtime <= pi->muzzleFlashTime ) {
- if ( pi->flashModel ) {
- memset( &flash, 0, sizeof(flash) );
- flash.hModel = pi->flashModel;
- VectorCopy( origin, flash.lightingOrigin );
- UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash");
- flash.renderfx = renderfx;
- trap_R_AddRefEntityToScene( &flash );
- }
-
- // make a dlight for the flash
- if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) {
- trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), pi->flashDlightColor[0],
- pi->flashDlightColor[1], pi->flashDlightColor[2] );
- }
- }
-
- //
- // add the chat icon
- //
- if ( pi->chat ) {
- UI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) );
- }
-
- //
- // add an accent light
- //
- origin[0] -= 100; // + = behind, - = in front
- origin[1] += 100; // + = left, - = right
- origin[2] += 100; // + = above, - = below
- trap_R_AddLightToScene( origin, 500, 1.0, 1.0, 1.0 );
-
- origin[0] -= 100;
- origin[1] -= 100;
- origin[2] -= 100;
- trap_R_AddLightToScene( origin, 500, 1.0, 0.0, 0.0 );
-
- trap_R_RenderScene( &refdef );
-}
-
-
-/*
-==========================
-UI_RegisterClientSkin
-==========================
-*/
-static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, const char *skinName ) {
- char filename[MAX_QPATH];
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName );
- pi->legsSkin = trap_R_RegisterSkin( filename );
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName );
- pi->torsoSkin = trap_R_RegisterSkin( filename );
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/head_%s.skin", modelName, skinName );
- pi->headSkin = trap_R_RegisterSkin( filename );
-
- if ( !pi->legsSkin || !pi->torsoSkin || !pi->headSkin ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-======================
-UI_ParseAnimationFile
-======================
-*/
-static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) {
- char *text_p, *prev;
- int len;
- int i;
- char *token;
- float fps;
- int skip;
- char text[20000];
- fileHandle_t f;
-
- memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS );
-
- // load the file
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( len <= 0 ) {
- return qfalse;
- }
- if ( len >= ( sizeof( text ) - 1 ) ) {
- Com_Printf( "File %s too long\n", filename );
- trap_FS_FCloseFile( f );
- return qfalse;
- }
- trap_FS_Read( text, len, f );
- text[len] = 0;
- trap_FS_FCloseFile( f );
-
- // parse the text
- text_p = text;
- skip = 0; // quite the compiler warning
-
- // read optional parameters
- while ( 1 ) {
- prev = text_p; // so we can unget
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( !Q_stricmp( token, "footsteps" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- continue;
- } else if ( !Q_stricmp( token, "headoffset" ) ) {
- for ( i = 0 ; i < 3 ; i++ ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- }
- continue;
- } else if ( !Q_stricmp( token, "sex" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- continue;
- }
-
- // if it is a number, start parsing animations
- if ( token[0] >= '0' && token[0] <= '9' ) {
- text_p = prev; // unget the token
- break;
- }
-
- Com_Printf( "unknown token '%s' is %s\n", token, filename );
- }
-
- // read information for each frame
- for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].firstFrame = atoi( token );
- // leg only frames are adjusted to not count the upper body only frames
- if ( i == LEGS_WALKCR ) {
- skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
- }
- if ( i >= LEGS_WALKCR ) {
- animations[i].firstFrame -= skip;
- }
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].numFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].loopFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- fps = atof( token );
- if ( fps == 0 ) {
- fps = 1;
- }
- animations[i].frameLerp = 1000 / fps;
- animations[i].initialLerp = 1000 / fps;
- }
-
- if ( i != MAX_ANIMATIONS ) {
- Com_Printf( "Error parsing animation file: %s", filename );
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-==========================
-UI_RegisterClientModelname
-==========================
-*/
-qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName ) {
- char modelName[MAX_QPATH];
- char skinName[MAX_QPATH];
- char filename[MAX_QPATH];
- char *slash;
-
- pi->torsoModel = 0;
- pi->headModel = 0;
-
- if ( !modelSkinName[0] ) {
- return qfalse;
- }
-
- Q_strncpyz( modelName, modelSkinName, sizeof( modelName ) );
-
- slash = strchr( modelName, '/' );
- if ( !slash ) {
- // modelName did not include a skin name
- Q_strncpyz( skinName, "default", sizeof( skinName ) );
- } else {
- Q_strncpyz( skinName, slash + 1, sizeof( skinName ) );
- // truncate modelName
- *slash = 0;
- }
-
- // load cmodels before models so filecache works
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
- pi->legsModel = trap_R_RegisterModel( filename );
- if ( !pi->legsModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
- pi->torsoModel = trap_R_RegisterModel( filename );
- if ( !pi->torsoModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", modelName );
- pi->headModel = trap_R_RegisterModel( filename );
- if ( !pi->headModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
-
- // if any skins failed to load, fall back to default
- if ( !UI_RegisterClientSkin( pi, modelName, skinName ) ) {
- if ( !UI_RegisterClientSkin( pi, modelName, "default" ) ) {
- Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName );
- return qfalse;
- }
- }
-
- // load the animations
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
- if ( !UI_ParseAnimationFile( filename, pi->animations ) ) {
- Com_Printf( "Failed to load animation file %s\n", filename );
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-===============
-UI_PlayerInfo_SetModel
-===============
-*/
-void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model ) {
- memset( pi, 0, sizeof(*pi) );
- UI_RegisterClientModelname( pi, model );
- pi->weapon = WP_MACHINEGUN;
- pi->currentWeapon = pi->weapon;
- pi->lastWeapon = pi->weapon;
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- pi->chat = qfalse;
- pi->newModel = qtrue;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
-}
-
-
-/*
-===============
-UI_PlayerInfo_SetInfo
-===============
-*/
-void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) {
- int currentAnim;
- weapon_t weaponNum;
-
- pi->chat = chat;
-
- // view angles
- VectorCopy( viewAngles, pi->viewAngles );
-
- // move angles
- VectorCopy( moveAngles, pi->moveAngles );
-
- if ( pi->newModel ) {
- pi->newModel = qfalse;
-
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
- pi->legs.yawAngle = viewAngles[YAW];
- pi->legs.yawing = qfalse;
-
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
- pi->torso.yawAngle = viewAngles[YAW];
- pi->torso.yawing = qfalse;
-
- if ( weaponNumber != -1 ) {
- pi->weapon = weaponNumber;
- pi->currentWeapon = weaponNumber;
- pi->lastWeapon = weaponNumber;
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
- }
-
- return;
- }
-
- // weapon
- if ( weaponNumber == -1 ) {
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- }
- else if ( weaponNumber != WP_NONE ) {
- pi->pendingWeapon = weaponNumber;
- pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY;
- }
- weaponNum = pi->lastWeapon;
- pi->weapon = weaponNum;
-
- if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) {
- torsoAnim = legsAnim = BOTH_DEATH1;
- pi->weapon = pi->currentWeapon = WP_NONE;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
-
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
-
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
-
- return;
- }
-
- // leg animation
- currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
- if ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) {
- pi->pendingLegsAnim = legsAnim;
- }
- else if ( legsAnim != currentAnim ) {
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
- }
-
- // torso animation
- if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) {
- if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
- torsoAnim = TORSO_STAND2;
- }
- else {
- torsoAnim = TORSO_STAND;
- }
- }
-
- if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) {
- if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
- torsoAnim = TORSO_ATTACK2;
- }
- else {
- torsoAnim = TORSO_ATTACK;
- }
- pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH;
- //FIXME play firing sound here
- }
-
- currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
-
- if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) {
- pi->pendingTorsoAnim = torsoAnim;
- }
- else if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) {
- pi->pendingTorsoAnim = torsoAnim;
- }
- else if ( torsoAnim != currentAnim ) {
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
- }
-}
diff --git a/game/code/q3_ui/ui_playersettings.c b/game/code/q3_ui/ui_playersettings.c
deleted file mode 100644
index f138b07..0000000
--- a/game/code/q3_ui/ui_playersettings.c
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-#define ART_FRAMEL "menu/art_blueish/frame2_l"
-#define ART_FRAMER "menu/art_blueish/frame1_r"
-#define ART_MODEL0 "menu/art_blueish/model_0"
-#define ART_MODEL1 "menu/art_blueish/model_1"
-#define ART_BACK0 "menu/art_blueish/back_0"
-#define ART_BACK1 "menu/art_blueish/back_1"
-#define ART_FX_BASE "menu/art/fx_base"
-#define ART_FX_BLUE "menu/art/fx_blue"
-#define ART_FX_CYAN "menu/art/fx_cyan"
-#define ART_FX_GREEN "menu/art/fx_grn"
-#define ART_FX_RED "menu/art/fx_red"
-#define ART_FX_TEAL "menu/art/fx_teal"
-#define ART_FX_WHITE "menu/art/fx_white"
-#define ART_FX_YELLOW "menu/art/fx_yel"
-
-#define ID_NAME 10
-#define ID_HANDICAP 11
-#define ID_EFFECTS 12
-#define ID_EFFECTS2 13
-#define ID_BACK 14
-#define ID_MODEL 15
-
-#define MAX_NAMELENGTH 20
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
- menubitmap_s player;
-
- menufield_s name;
- menulist_s handicap;
- menulist_s effects;
-
- //Added in beta 29
- menulist_s effects2;
-
- menubitmap_s back;
- menubitmap_s model;
- menubitmap_s item_null;
-
- qhandle_t fxBasePic;
- qhandle_t fxPic[7];
- playerInfo_t playerinfo;
- int current_fx;
- char playerModel[MAX_QPATH];
-} playersettings_t;
-
-static playersettings_t s_playersettings;
-
-static int gamecodetoui[] = {4,2,3,0,5,1,6};
-static int uitogamecode[] = {4,6,2,3,1,5,7};
-
-static const char *handicap_items[] = {
- "None",
- "95",
- "90",
- "85",
- "80",
- "75",
- "70",
- "65",
- "60",
- "55",
- "50",
- "45",
- "40",
- "35",
- "30",
- "25",
- "20",
- "15",
- "10",
- "5",
- NULL
-};
-
-
-/*
-=================
-PlayerSettings_DrawName
-=================
-*/
-static void PlayerSettings_DrawName( void *self ) {
- menufield_s *f;
- qboolean focus;
- int style;
- char *txt;
- char c;
- float *color;
- int n;
- int basex, x, y;
- char name[32];
-
- f = (menufield_s*)self;
- basex = f->generic.x;
- y = f->generic.y;
- focus = (f->generic.parent->cursor == f->generic.menuPosition);
-
- style = UI_LEFT|UI_SMALLFONT;
- color = text_color_normal;
- if( focus ) {
- style |= UI_PULSE;
- color = text_color_highlight;
- }
-
- UI_DrawProportionalString( basex, y, "Name", style, color );
-
- // draw the actual name
- basex += 64;
- y += PROP_HEIGHT;
- txt = f->field.buffer;
- color = g_color_table[ColorIndex(COLOR_WHITE)];
- x = basex;
- while ( (c = *txt) != 0 ) {
- if ( !focus && Q_IsColorString( txt ) ) {
- n = ColorIndex( *(txt+1) );
- if( n == 0 ) {
- n = 7;
- }
- color = g_color_table[n];
- txt += 2;
- continue;
- }
- UI_DrawChar( x, y, c, style, color );
- txt++;
- x += SMALLCHAR_WIDTH;
- }
-
- // draw cursor if we have focus
- if( focus ) {
- if ( trap_Key_GetOverstrikeMode() ) {
- c = 11;
- } else {
- c = 10;
- }
-
- style &= ~UI_PULSE;
- style |= UI_BLINK;
-
- UI_DrawChar( basex + f->field.cursor * SMALLCHAR_WIDTH, y, c, style, color_white );
- }
-
- // draw at bottom also using proportional font
- Q_strncpyz( name, f->field.buffer, sizeof(name) );
- Q_CleanStr( name );
- UI_DrawProportionalString( 320, 440, name, UI_CENTER|UI_BIGFONT, text_color_normal );
-}
-
-
-/*
-=================
-PlayerSettings_DrawHandicap
-=================
-*/
-static void PlayerSettings_DrawHandicap( void *self ) {
- menulist_s *item;
- qboolean focus;
- int style;
- float *color;
-
- item = (menulist_s *)self;
- focus = (item->generic.parent->cursor == item->generic.menuPosition);
-
- style = UI_LEFT|UI_SMALLFONT;
- color = text_color_normal;
- if( focus ) {
- style |= UI_PULSE;
- color = text_color_highlight;
- }
-
- UI_DrawProportionalString( item->generic.x, item->generic.y, "Handicap", style, color );
- UI_DrawProportionalString( item->generic.x + 64, item->generic.y + PROP_HEIGHT, handicap_items[item->curvalue], style, color );
-}
-
-
-/*
-=================
-PlayerSettings_DrawEffects
-=================
-*/
-static void PlayerSettings_DrawEffects( void *self ) {
- menulist_s *item;
- qboolean focus;
- int style;
- float *color;
-
- item = (menulist_s *)self;
- focus = (item->generic.parent->cursor == item->generic.menuPosition);
-
- style = UI_LEFT|UI_SMALLFONT;
- color = text_color_normal;
- if( focus ) {
- style |= UI_PULSE;
- color = text_color_highlight;
- }
-
- UI_DrawProportionalString( item->generic.x, item->generic.y, "Effects", style, color );
-
- UI_DrawHandlePic( item->generic.x + 64, item->generic.y + PROP_HEIGHT + 8, 128, 8, s_playersettings.fxBasePic );
- UI_DrawHandlePic( item->generic.x + 64 + item->curvalue * 16 + 8, item->generic.y + PROP_HEIGHT + 6, 16, 12, s_playersettings.fxPic[item->curvalue] );
-}
-
-/*
-=================
-PlayerSettings_DrawEffects
-=================
-*/
-static void PlayerSettings_DrawEffects2( void *self ) {
- menulist_s *item;
- qboolean focus;
-
- item = (menulist_s *)self;
- focus = (item->generic.parent->cursor == item->generic.menuPosition);
-
- UI_DrawHandlePic( item->generic.x + 64, item->generic.y + 8, 128, 8, s_playersettings.fxBasePic );
- UI_DrawHandlePic( item->generic.x + 64 + item->curvalue * 16 + 8, item->generic.y + 6, 16, 12, s_playersettings.fxPic[item->curvalue] );
-}
-
-
-/*
-=================
-PlayerSettings_DrawPlayer
-=================
-*/
-static void PlayerSettings_DrawPlayer( void *self ) {
- menubitmap_s *b;
- vec3_t viewangles;
- char buf[MAX_QPATH];
-
- trap_Cvar_VariableStringBuffer( "model", buf, sizeof( buf ) );
- if ( strcmp( buf, s_playersettings.playerModel ) != 0 ) {
- UI_PlayerInfo_SetModel( &s_playersettings.playerinfo, buf );
- strcpy( s_playersettings.playerModel, buf );
-
- viewangles[YAW] = 180 - 30;
- viewangles[PITCH] = 0;
- viewangles[ROLL] = 0;
- UI_PlayerInfo_SetInfo( &s_playersettings.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
- }
-
- b = (menubitmap_s*) self;
- UI_DrawPlayer( b->generic.x, b->generic.y, b->width, b->height, &s_playersettings.playerinfo, uis.realtime/2 );
-}
-
-
-/*
-=================
-PlayerSettings_SaveChanges
-=================
-*/
-static void PlayerSettings_SaveChanges( void ) {
- // name
- trap_Cvar_Set( "name", s_playersettings.name.field.buffer );
-
- // handicap
- trap_Cvar_SetValue( "handicap", 100 - s_playersettings.handicap.curvalue * 5 );
-
- // effects color
- trap_Cvar_SetValue( "color1", uitogamecode[s_playersettings.effects.curvalue] );
-
- // effects2 color
- trap_Cvar_SetValue( "color2", uitogamecode[s_playersettings.effects2.curvalue] );
-}
-
-
-/*
-=================
-PlayerSettings_MenuKey
-=================
-*/
-static sfxHandle_t PlayerSettings_MenuKey( int key ) {
- if( key == K_MOUSE2 || key == K_ESCAPE ) {
- PlayerSettings_SaveChanges();
- }
- return Menu_DefaultKey( &s_playersettings.menu, key );
-}
-
-
-/*
-=================
-PlayerSettings_SetMenuItems
-=================
-*/
-static void PlayerSettings_SetMenuItems( void ) {
- vec3_t viewangles;
- int c;
- int h;
-
- // name
- Q_strncpyz( s_playersettings.name.field.buffer, UI_Cvar_VariableString("name"), sizeof(s_playersettings.name.field.buffer) );
-
- // effects color
- c = trap_Cvar_VariableValue( "color1" ) - 1;
- if( c < 0 || c > 6 ) {
- c = 6;
- }
- s_playersettings.effects.curvalue = gamecodetoui[c];
-
- // effects2 color
- c = trap_Cvar_VariableValue( "color2" ) - 1;
- if( c < 0 || c > 6 ) {
- c = 6;
- }
- s_playersettings.effects2.curvalue = gamecodetoui[c];
-
- // model/skin
- memset( &s_playersettings.playerinfo, 0, sizeof(playerInfo_t) );
-
- viewangles[YAW] = 180 - 30;
- viewangles[PITCH] = 0;
- viewangles[ROLL] = 0;
-
- UI_PlayerInfo_SetModel( &s_playersettings.playerinfo, UI_Cvar_VariableString( "model" ) );
- UI_PlayerInfo_SetInfo( &s_playersettings.playerinfo, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
-
- // handicap
- h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
- s_playersettings.handicap.curvalue = 20 - h / 5;
-}
-
-
-/*
-=================
-PlayerSettings_MenuEvent
-=================
-*/
-static void PlayerSettings_MenuEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_HANDICAP:
- trap_Cvar_Set( "handicap", va( "%i", 100 - 25 * s_playersettings.handicap.curvalue ) );
- break;
-
- case ID_MODEL:
- PlayerSettings_SaveChanges();
- UI_PlayerModelMenu();
- break;
-
- case ID_BACK:
- PlayerSettings_SaveChanges();
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-=================
-PlayerSettings_MenuInit
-=================
-*/
-static void PlayerSettings_MenuInit( void ) {
- int y;
-
- memset(&s_playersettings,0,sizeof(playersettings_t));
-
- PlayerSettings_Cache();
-
- s_playersettings.menu.key = PlayerSettings_MenuKey;
- s_playersettings.menu.wrapAround = qtrue;
- s_playersettings.menu.fullscreen = qtrue;
-
- s_playersettings.banner.generic.type = MTYPE_BTEXT;
- s_playersettings.banner.generic.x = 320;
- s_playersettings.banner.generic.y = 16;
- s_playersettings.banner.string = "PLAYER SETTINGS";
- s_playersettings.banner.color = color_white;
- s_playersettings.banner.style = UI_CENTER;
-
- s_playersettings.framel.generic.type = MTYPE_BITMAP;
- s_playersettings.framel.generic.name = ART_FRAMEL;
- s_playersettings.framel.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_playersettings.framel.generic.x = 0;
- s_playersettings.framel.generic.y = 78;
- s_playersettings.framel.width = 256;
- s_playersettings.framel.height = 329;
-
- s_playersettings.framer.generic.type = MTYPE_BITMAP;
- s_playersettings.framer.generic.name = ART_FRAMER;
- s_playersettings.framer.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_playersettings.framer.generic.x = 376;
- s_playersettings.framer.generic.y = 76;
- s_playersettings.framer.width = 256;
- s_playersettings.framer.height = 334;
-
- y = 144;
- s_playersettings.name.generic.type = MTYPE_FIELD;
- s_playersettings.name.generic.flags = QMF_NODEFAULTINIT;
- s_playersettings.name.generic.ownerdraw = PlayerSettings_DrawName;
- s_playersettings.name.field.widthInChars = MAX_NAMELENGTH;
- s_playersettings.name.field.maxchars = MAX_NAMELENGTH;
- s_playersettings.name.generic.x = 192;
- s_playersettings.name.generic.y = y;
- s_playersettings.name.generic.left = 192 - 8;
- s_playersettings.name.generic.top = y - 8;
- s_playersettings.name.generic.right = 192 + 200;
- s_playersettings.name.generic.bottom = y + 2 * PROP_HEIGHT;
-
- y += 3 * PROP_HEIGHT;
- s_playersettings.handicap.generic.type = MTYPE_SPINCONTROL;
- s_playersettings.handicap.generic.flags = QMF_NODEFAULTINIT;
- s_playersettings.handicap.generic.id = ID_HANDICAP;
- s_playersettings.handicap.generic.ownerdraw = PlayerSettings_DrawHandicap;
- s_playersettings.handicap.generic.x = 192;
- s_playersettings.handicap.generic.y = y;
- s_playersettings.handicap.generic.left = 192 - 8;
- s_playersettings.handicap.generic.top = y - 8;
- s_playersettings.handicap.generic.right = 192 + 200;
- s_playersettings.handicap.generic.bottom = y + 2 * PROP_HEIGHT;
- s_playersettings.handicap.numitems = 20;
-
- y += 3 * PROP_HEIGHT;
- s_playersettings.effects.generic.type = MTYPE_SPINCONTROL;
- s_playersettings.effects.generic.flags = QMF_NODEFAULTINIT;
- s_playersettings.effects.generic.id = ID_EFFECTS;
- s_playersettings.effects.generic.ownerdraw = PlayerSettings_DrawEffects;
- s_playersettings.effects.generic.x = 192;
- s_playersettings.effects.generic.y = y;
- s_playersettings.effects.generic.left = 192 - 8;
- s_playersettings.effects.generic.top = y - 8;
- s_playersettings.effects.generic.right = 192 + 200;
- s_playersettings.effects.generic.bottom = y + 2* PROP_HEIGHT;
- s_playersettings.effects.numitems = 7;
-
- y += 2*PROP_HEIGHT;
- s_playersettings.effects2.generic.type = MTYPE_SPINCONTROL;
- s_playersettings.effects2.generic.flags = QMF_NODEFAULTINIT;
- s_playersettings.effects2.generic.id = ID_EFFECTS2;
- s_playersettings.effects2.generic.ownerdraw = PlayerSettings_DrawEffects2;
- s_playersettings.effects2.generic.x = 192;
- s_playersettings.effects2.generic.y = y;
- s_playersettings.effects2.generic.left = 192 - 8;
- s_playersettings.effects2.generic.top = y - 8;
- s_playersettings.effects2.generic.right = 192 + 200;
- s_playersettings.effects2.generic.bottom = y + 2* PROP_HEIGHT;
- s_playersettings.effects2.numitems = 7;
-
- s_playersettings.model.generic.type = MTYPE_BITMAP;
- s_playersettings.model.generic.name = ART_MODEL0;
- s_playersettings.model.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_playersettings.model.generic.id = ID_MODEL;
- s_playersettings.model.generic.callback = PlayerSettings_MenuEvent;
- s_playersettings.model.generic.x = 640;
- s_playersettings.model.generic.y = 480-64;
- s_playersettings.model.width = 128;
- s_playersettings.model.height = 64;
- s_playersettings.model.focuspic = ART_MODEL1;
-
- s_playersettings.player.generic.type = MTYPE_BITMAP;
- s_playersettings.player.generic.flags = QMF_INACTIVE;
- s_playersettings.player.generic.ownerdraw = PlayerSettings_DrawPlayer;
- s_playersettings.player.generic.x = 400;
- s_playersettings.player.generic.y = -40;
- s_playersettings.player.width = 32*10;
- s_playersettings.player.height = 56*10;
-
- s_playersettings.back.generic.type = MTYPE_BITMAP;
- s_playersettings.back.generic.name = ART_BACK0;
- s_playersettings.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_playersettings.back.generic.id = ID_BACK;
- s_playersettings.back.generic.callback = PlayerSettings_MenuEvent;
- s_playersettings.back.generic.x = 0;
- s_playersettings.back.generic.y = 480-64;
- s_playersettings.back.width = 128;
- s_playersettings.back.height = 64;
- s_playersettings.back.focuspic = ART_BACK1;
-
- s_playersettings.item_null.generic.type = MTYPE_BITMAP;
- s_playersettings.item_null.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;
- s_playersettings.item_null.generic.x = 0;
- s_playersettings.item_null.generic.y = 0;
- s_playersettings.item_null.width = 640;
- s_playersettings.item_null.height = 480;
-
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.banner );
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.framel );
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.framer );
-
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.name );
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.handicap );
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.effects );
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.effects2 );
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.model );
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.back );
-
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.player );
-
- Menu_AddItem( &s_playersettings.menu, &s_playersettings.item_null );
-
- PlayerSettings_SetMenuItems();
-}
-
-
-/*
-=================
-PlayerSettings_Cache
-=================
-*/
-void PlayerSettings_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
- trap_R_RegisterShaderNoMip( ART_MODEL0 );
- trap_R_RegisterShaderNoMip( ART_MODEL1 );
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
-
- s_playersettings.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
- s_playersettings.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
- s_playersettings.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
- s_playersettings.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
- s_playersettings.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
- s_playersettings.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
- s_playersettings.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
- s_playersettings.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
-}
-
-
-/*
-=================
-UI_PlayerSettingsMenu
-=================
-*/
-void UI_PlayerSettingsMenu( void ) {
- PlayerSettings_MenuInit();
- UI_PushMenu( &s_playersettings.menu );
-}
diff --git a/game/code/q3_ui/ui_preferences.c b/game/code/q3_ui/ui_preferences.c
deleted file mode 100644
index 41f1e32..0000000
--- a/game/code/q3_ui/ui_preferences.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-GAME OPTIONS MENU
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define ART_FRAMEL "menu/art_blueish/frame2_l"
-#define ART_FRAMER "menu/art_blueish/frame1_r"
-#define ART_BACK0 "menu/art_blueish/back_0"
-#define ART_BACK1 "menu/art_blueish/back_1"
-
-#define PREFERENCES_X_POS 360
-
-#define ID_CROSSHAIR 127
-#define ID_SIMPLEITEMS 128
-#define ID_HIGHQUALITYSKY 129
-#define ID_EJECTINGBRASS 130
-#define ID_WALLMARKS 131
-#define ID_DYNAMICLIGHTS 132
-#define ID_IDENTIFYTARGET 133
-#define ID_SYNCEVERYFRAME 134
-#define ID_FORCEMODEL 135
-#define ID_DRAWTEAMOVERLAY 136
-#define ID_ALLOWDOWNLOAD 137
-#define ID_BACK 138
-//Elimination
-#define ID_WEAPONBAR 139
-#define ID_DELAGHITSCAN 140
-#define ID_COLORRED 141
-#define ID_COLORGREEN 142
-#define ID_COLORBLUE 143
-#define ID_CROSSHAIRHEALTH 144
-
-#define NUM_CROSSHAIRS 99
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menulist_s crosshair;
- menuradiobutton_s crosshairHealth;
-
- //Crosshair colors:
- menuslider_s crosshairColorRed;
- menuslider_s crosshairColorGreen;
- menuslider_s crosshairColorBlue;
-
- menuradiobutton_s simpleitems;
- menuradiobutton_s alwaysweaponbar;
- menuradiobutton_s brass;
- menuradiobutton_s wallmarks;
- menuradiobutton_s dynamiclights;
- menuradiobutton_s identifytarget;
- menuradiobutton_s highqualitysky;
- menuradiobutton_s synceveryframe;
- menuradiobutton_s forcemodel;
- menulist_s drawteamoverlay;
- menuradiobutton_s delaghitscan;
- menuradiobutton_s allowdownload;
- menubitmap_s back;
-
- qhandle_t crosshairShader[NUM_CROSSHAIRS];
-} preferences_t;
-
-static preferences_t s_preferences;
-
-static const char *teamoverlay_names[] =
-{
- "off",
- "upper right",
- "lower right",
- "lower left",
- NULL
-};
-
-static void Preferences_SetMenuItems( void ) {
- s_preferences.crosshair.curvalue = (int)trap_Cvar_VariableValue( "cg_drawCrosshair" ) % NUM_CROSSHAIRS;
- s_preferences.crosshairHealth.curvalue = trap_Cvar_VariableValue( "cg_crosshairHealth") != 0;
- s_preferences.crosshairColorRed.curvalue = trap_Cvar_VariableValue( "cg_crosshairColorRed")*255.0f;
- s_preferences.crosshairColorGreen.curvalue = trap_Cvar_VariableValue( "cg_crosshairColorGreen")*255.0f;
- s_preferences.crosshairColorBlue.curvalue = trap_Cvar_VariableValue( "cg_crosshairColorBlue")*255.0f;
- s_preferences.simpleitems.curvalue = trap_Cvar_VariableValue( "cg_simpleItems" ) != 0;
- s_preferences.alwaysweaponbar.curvalue = trap_Cvar_VariableValue( "cg_alwaysWeaponBar" ) != 0;
- s_preferences.brass.curvalue = trap_Cvar_VariableValue( "cg_brassTime" ) != 0;
- s_preferences.wallmarks.curvalue = trap_Cvar_VariableValue( "cg_marks" ) != 0;
- s_preferences.identifytarget.curvalue = trap_Cvar_VariableValue( "cg_drawCrosshairNames" ) != 0;
- s_preferences.dynamiclights.curvalue = trap_Cvar_VariableValue( "r_dynamiclight" ) != 0;
- s_preferences.highqualitysky.curvalue = trap_Cvar_VariableValue ( "r_fastsky" ) == 0;
- s_preferences.synceveryframe.curvalue = trap_Cvar_VariableValue( "r_finish" ) != 0;
- s_preferences.forcemodel.curvalue = trap_Cvar_VariableValue( "cg_forcemodel" ) != 0;
- s_preferences.drawteamoverlay.curvalue = Com_Clamp( 0, 3, trap_Cvar_VariableValue( "cg_drawTeamOverlay" ) );
- s_preferences.allowdownload.curvalue = trap_Cvar_VariableValue( "cl_allowDownload" ) != 0;
- s_preferences.delaghitscan.curvalue = trap_Cvar_VariableValue( "cg_delag" ) != 0;
-}
-
-static void Preferences_Event( void* ptr, int notification ) {
- if( notification != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_CROSSHAIR:
- s_preferences.crosshair.curvalue++;
- if( s_preferences.crosshair.curvalue == NUM_CROSSHAIRS || s_preferences.crosshairShader[s_preferences.crosshair.curvalue]==0 ) {
- s_preferences.crosshair.curvalue = 0;
- }
- trap_Cvar_SetValue( "cg_drawCrosshair", s_preferences.crosshair.curvalue );
- break;
-
- case ID_CROSSHAIRHEALTH:
- trap_Cvar_SetValue( "cg_crosshairHealth", s_preferences.crosshairHealth.curvalue );
- if(s_preferences.crosshairHealth.curvalue) {
- //If crosshairHealth is on: Don't allow color selection
- s_preferences.crosshairColorRed.generic.flags |= QMF_INACTIVE;
- s_preferences.crosshairColorGreen.generic.flags |= QMF_INACTIVE;
- s_preferences.crosshairColorBlue.generic.flags |= QMF_INACTIVE;
- } else {
- //If crosshairHealth is off: Allow color selection
- s_preferences.crosshairColorRed.generic.flags &= ~QMF_INACTIVE;
- s_preferences.crosshairColorGreen.generic.flags &= ~QMF_INACTIVE;
- s_preferences.crosshairColorBlue.generic.flags &= ~QMF_INACTIVE;
- }
- break;
-
- case ID_COLORRED:
- trap_Cvar_SetValue( "cg_crosshairColorRed", ((float)s_preferences.crosshairColorRed.curvalue)/255.f );
- break;
-
- case ID_COLORGREEN:
- trap_Cvar_SetValue( "cg_crosshairColorGreen", ((float)s_preferences.crosshairColorGreen.curvalue)/255.f );
- break;
-
- case ID_COLORBLUE:
- trap_Cvar_SetValue( "cg_crosshairColorBlue", ((float)s_preferences.crosshairColorBlue.curvalue)/255.f );
- break;
-
- case ID_SIMPLEITEMS:
- trap_Cvar_SetValue( "cg_simpleItems", s_preferences.simpleitems.curvalue );
- break;
-
- case ID_WEAPONBAR:
- trap_Cvar_SetValue( "cg_alwaysWeaponBar", s_preferences.alwaysweaponbar.curvalue );
- break;
-
- case ID_HIGHQUALITYSKY:
- trap_Cvar_SetValue( "r_fastsky", !s_preferences.highqualitysky.curvalue );
- break;
-
- case ID_EJECTINGBRASS:
- if ( s_preferences.brass.curvalue )
- trap_Cvar_Reset( "cg_brassTime" );
- else
- trap_Cvar_SetValue( "cg_brassTime", 0 );
- break;
-
- case ID_WALLMARKS:
- trap_Cvar_SetValue( "cg_marks", s_preferences.wallmarks.curvalue );
- break;
-
- case ID_DYNAMICLIGHTS:
- trap_Cvar_SetValue( "r_dynamiclight", s_preferences.dynamiclights.curvalue );
- break;
-
- case ID_IDENTIFYTARGET:
- trap_Cvar_SetValue( "cg_drawCrosshairNames", s_preferences.identifytarget.curvalue );
- break;
-
- case ID_SYNCEVERYFRAME:
- trap_Cvar_SetValue( "r_finish", s_preferences.synceveryframe.curvalue );
- break;
-
- case ID_FORCEMODEL:
- trap_Cvar_SetValue( "cg_forcemodel", s_preferences.forcemodel.curvalue );
- break;
-
- case ID_DRAWTEAMOVERLAY:
- trap_Cvar_SetValue( "cg_drawTeamOverlay", s_preferences.drawteamoverlay.curvalue );
- break;
-
- case ID_ALLOWDOWNLOAD:
- trap_Cvar_SetValue( "cl_allowDownload", s_preferences.allowdownload.curvalue );
- trap_Cvar_SetValue( "sv_allowDownload", s_preferences.allowdownload.curvalue );
- break;
-
- case ID_DELAGHITSCAN:
- trap_Cvar_SetValue( "g_delagHitscan", s_preferences.delaghitscan.curvalue );
- trap_Cvar_SetValue( "cg_delag", s_preferences.delaghitscan.curvalue );
- break;
-
- case ID_BACK:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-=================
-Crosshair_Draw
-=================
-*/
-static void Crosshair_Draw( void *self ) {
- menulist_s *s;
- float *color;
- int x, y;
- int style;
- qboolean focus;
- vec4_t color4;
-
- s = (menulist_s *)self;
- x = s->generic.x;
- y = s->generic.y;
-
- style = UI_SMALLFONT;
- focus = (s->generic.parent->cursor == s->generic.menuPosition);
-
- if ( s->generic.flags & QMF_GRAYED )
- color = text_color_disabled;
- else if ( focus )
- {
- color = text_color_highlight;
- style |= UI_PULSE;
- }
- else if ( s->generic.flags & QMF_BLINK )
- {
- color = text_color_highlight;
- style |= UI_BLINK;
- }
- else
- color = text_color_normal;
-
- if ( focus )
- {
- // draw cursor
- UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
- }
-
- UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );
- if( !s->curvalue ) {
- return;
- }
- color4[0]=((float)s_preferences.crosshairColorRed.curvalue)/255.f;
- color4[1]=((float)s_preferences.crosshairColorGreen.curvalue)/255.f;
- color4[2]=((float)s_preferences.crosshairColorBlue.curvalue)/255.f;
- color4[3]=1.0f;
- trap_R_SetColor( color4 );
- UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y - 4, 24, 24, s_preferences.crosshairShader[s->curvalue] );
-}
-
-
-static void Preferences_MenuInit( void ) {
- int y;
-
- memset( &s_preferences, 0 ,sizeof(preferences_t) );
-
- Preferences_Cache();
-
- s_preferences.menu.wrapAround = qtrue;
- s_preferences.menu.fullscreen = qtrue;
-
- s_preferences.banner.generic.type = MTYPE_BTEXT;
- s_preferences.banner.generic.x = 320;
- s_preferences.banner.generic.y = 16;
- s_preferences.banner.string = "GAME OPTIONS";
- s_preferences.banner.color = color_white;
- s_preferences.banner.style = UI_CENTER;
-
- s_preferences.framel.generic.type = MTYPE_BITMAP;
- s_preferences.framel.generic.name = ART_FRAMEL;
- s_preferences.framel.generic.flags = QMF_INACTIVE;
- s_preferences.framel.generic.x = 0;
- s_preferences.framel.generic.y = 78;
- s_preferences.framel.width = 256;
- s_preferences.framel.height = 329;
-
- s_preferences.framer.generic.type = MTYPE_BITMAP;
- s_preferences.framer.generic.name = ART_FRAMER;
- s_preferences.framer.generic.flags = QMF_INACTIVE;
- s_preferences.framer.generic.x = 376;
- s_preferences.framer.generic.y = 76;
- s_preferences.framer.width = 256;
- s_preferences.framer.height = 334;
-
- y = 104;
- s_preferences.crosshair.generic.type = MTYPE_TEXT;
- s_preferences.crosshair.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT|QMF_NODEFAULTINIT|QMF_OWNERDRAW;
- s_preferences.crosshair.generic.x = PREFERENCES_X_POS;
- s_preferences.crosshair.generic.y = y;
- s_preferences.crosshair.generic.name = "Crosshair:";
- s_preferences.crosshair.generic.callback = Preferences_Event;
- s_preferences.crosshair.generic.ownerdraw = Crosshair_Draw;
- s_preferences.crosshair.generic.id = ID_CROSSHAIR;
- s_preferences.crosshair.generic.top = y - 4;
- s_preferences.crosshair.generic.bottom = y + 20;
- s_preferences.crosshair.generic.left = PREFERENCES_X_POS - ( ( strlen(s_preferences.crosshair.generic.name) + 1 ) * SMALLCHAR_WIDTH );
- s_preferences.crosshair.generic.right = PREFERENCES_X_POS + 48;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.crosshairHealth.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.crosshairHealth.generic.name = "Crosshair shows health:";
- s_preferences.crosshairHealth.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.crosshairHealth.generic.callback = Preferences_Event;
- s_preferences.crosshairHealth.generic.id = ID_CROSSHAIRHEALTH;
- s_preferences.crosshairHealth.generic.x = PREFERENCES_X_POS;
- s_preferences.crosshairHealth.generic.y = y;
-
- y += BIGCHAR_HEIGHT;
- s_preferences.crosshairColorRed.generic.type = MTYPE_SLIDER;
- s_preferences.crosshairColorRed.generic.name = "Crosshair red:";
- s_preferences.crosshairColorRed.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.crosshairColorRed.generic.callback = Preferences_Event;
- s_preferences.crosshairColorRed.generic.id = ID_COLORRED;
- s_preferences.crosshairColorRed.generic.x = PREFERENCES_X_POS;
- s_preferences.crosshairColorRed.generic.y = y;
- s_preferences.crosshairColorRed.minvalue = 0.0f;
- s_preferences.crosshairColorRed.maxvalue = 255.0f;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.crosshairColorGreen.generic.type = MTYPE_SLIDER;
- s_preferences.crosshairColorGreen.generic.name = "Crosshair green:";
- s_preferences.crosshairColorGreen.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.crosshairColorGreen.generic.callback = Preferences_Event;
- s_preferences.crosshairColorGreen.generic.id = ID_COLORGREEN;
- s_preferences.crosshairColorGreen.generic.x = PREFERENCES_X_POS;
- s_preferences.crosshairColorGreen.generic.y = y;
- s_preferences.crosshairColorGreen.minvalue = 0.0f;
- s_preferences.crosshairColorGreen.maxvalue = 255.0f;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.crosshairColorBlue.generic.type = MTYPE_SLIDER;
- s_preferences.crosshairColorBlue.generic.name = "Crosshair blue:";
- s_preferences.crosshairColorBlue.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.crosshairColorBlue.generic.callback = Preferences_Event;
- s_preferences.crosshairColorBlue.generic.id = ID_COLORBLUE;
- s_preferences.crosshairColorBlue.generic.x = PREFERENCES_X_POS;
- s_preferences.crosshairColorBlue.generic.y = y;
- s_preferences.crosshairColorBlue.minvalue = 0.0f;
- s_preferences.crosshairColorBlue.maxvalue = 255.0f;
-
-
- if(s_preferences.crosshairHealth.curvalue) {
- s_preferences.crosshairColorRed.generic.flags |= QMF_INACTIVE;
- s_preferences.crosshairColorGreen.generic.flags |= QMF_INACTIVE;
- s_preferences.crosshairColorBlue.generic.flags |= QMF_INACTIVE;
- }
-
- y += BIGCHAR_HEIGHT+2+4;
- s_preferences.simpleitems.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.simpleitems.generic.name = "Simple Items:";
- s_preferences.simpleitems.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.simpleitems.generic.callback = Preferences_Event;
- s_preferences.simpleitems.generic.id = ID_SIMPLEITEMS;
- s_preferences.simpleitems.generic.x = PREFERENCES_X_POS;
- s_preferences.simpleitems.generic.y = y;
-
- //Elimination
- y += BIGCHAR_HEIGHT;
- s_preferences.alwaysweaponbar.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.alwaysweaponbar.generic.name = "Always show weapons:";
- s_preferences.alwaysweaponbar.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.alwaysweaponbar.generic.callback = Preferences_Event;
- s_preferences.alwaysweaponbar.generic.id = ID_WEAPONBAR;
- s_preferences.alwaysweaponbar.generic.x = PREFERENCES_X_POS;
- s_preferences.alwaysweaponbar.generic.y = y;
-
- y += BIGCHAR_HEIGHT;
- s_preferences.wallmarks.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.wallmarks.generic.name = "Marks on Walls:";
- s_preferences.wallmarks.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.wallmarks.generic.callback = Preferences_Event;
- s_preferences.wallmarks.generic.id = ID_WALLMARKS;
- s_preferences.wallmarks.generic.x = PREFERENCES_X_POS;
- s_preferences.wallmarks.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.brass.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.brass.generic.name = "Ejecting Brass:";
- s_preferences.brass.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.brass.generic.callback = Preferences_Event;
- s_preferences.brass.generic.id = ID_EJECTINGBRASS;
- s_preferences.brass.generic.x = PREFERENCES_X_POS;
- s_preferences.brass.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.dynamiclights.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.dynamiclights.generic.name = "Dynamic Lights:";
- s_preferences.dynamiclights.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.dynamiclights.generic.callback = Preferences_Event;
- s_preferences.dynamiclights.generic.id = ID_DYNAMICLIGHTS;
- s_preferences.dynamiclights.generic.x = PREFERENCES_X_POS;
- s_preferences.dynamiclights.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.identifytarget.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.identifytarget.generic.name = "Identify Target:";
- s_preferences.identifytarget.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.identifytarget.generic.callback = Preferences_Event;
- s_preferences.identifytarget.generic.id = ID_IDENTIFYTARGET;
- s_preferences.identifytarget.generic.x = PREFERENCES_X_POS;
- s_preferences.identifytarget.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.highqualitysky.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.highqualitysky.generic.name = "High Quality Sky:";
- s_preferences.highqualitysky.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.highqualitysky.generic.callback = Preferences_Event;
- s_preferences.highqualitysky.generic.id = ID_HIGHQUALITYSKY;
- s_preferences.highqualitysky.generic.x = PREFERENCES_X_POS;
- s_preferences.highqualitysky.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.synceveryframe.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.synceveryframe.generic.name = "Sync Every Frame:";
- s_preferences.synceveryframe.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.synceveryframe.generic.callback = Preferences_Event;
- s_preferences.synceveryframe.generic.id = ID_SYNCEVERYFRAME;
- s_preferences.synceveryframe.generic.x = PREFERENCES_X_POS;
- s_preferences.synceveryframe.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.forcemodel.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.forcemodel.generic.name = "Force Player Models:";
- s_preferences.forcemodel.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.forcemodel.generic.callback = Preferences_Event;
- s_preferences.forcemodel.generic.id = ID_FORCEMODEL;
- s_preferences.forcemodel.generic.x = PREFERENCES_X_POS;
- s_preferences.forcemodel.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.drawteamoverlay.generic.type = MTYPE_SPINCONTROL;
- s_preferences.drawteamoverlay.generic.name = "Draw Team Overlay:";
- s_preferences.drawteamoverlay.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.drawteamoverlay.generic.callback = Preferences_Event;
- s_preferences.drawteamoverlay.generic.id = ID_DRAWTEAMOVERLAY;
- s_preferences.drawteamoverlay.generic.x = PREFERENCES_X_POS;
- s_preferences.drawteamoverlay.generic.y = y;
- s_preferences.drawteamoverlay.itemnames = teamoverlay_names;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.delaghitscan.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.delaghitscan.generic.name = "Unlag hitscan:";
- s_preferences.delaghitscan.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.delaghitscan.generic.callback = Preferences_Event;
- s_preferences.delaghitscan.generic.id = ID_DELAGHITSCAN;
- s_preferences.delaghitscan.generic.x = PREFERENCES_X_POS;
- s_preferences.delaghitscan.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.allowdownload.generic.type = MTYPE_RADIOBUTTON;
- s_preferences.allowdownload.generic.name = "Automatic Downloading:";
- s_preferences.allowdownload.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_preferences.allowdownload.generic.callback = Preferences_Event;
- s_preferences.allowdownload.generic.id = ID_ALLOWDOWNLOAD;
- s_preferences.allowdownload.generic.x = PREFERENCES_X_POS;
- s_preferences.allowdownload.generic.y = y;
-
- y += BIGCHAR_HEIGHT+2;
- s_preferences.back.generic.type = MTYPE_BITMAP;
- s_preferences.back.generic.name = ART_BACK0;
- s_preferences.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_preferences.back.generic.callback = Preferences_Event;
- s_preferences.back.generic.id = ID_BACK;
- s_preferences.back.generic.x = 0;
- s_preferences.back.generic.y = 480-64;
- s_preferences.back.width = 128;
- s_preferences.back.height = 64;
- s_preferences.back.focuspic = ART_BACK1;
-
- Menu_AddItem( &s_preferences.menu, &s_preferences.banner );
- Menu_AddItem( &s_preferences.menu, &s_preferences.framel );
- Menu_AddItem( &s_preferences.menu, &s_preferences.framer );
-
- Menu_AddItem( &s_preferences.menu, &s_preferences.crosshair );
- Menu_AddItem( &s_preferences.menu, &s_preferences.crosshairHealth );
- Menu_AddItem( &s_preferences.menu, &s_preferences.crosshairColorRed );
- Menu_AddItem( &s_preferences.menu, &s_preferences.crosshairColorGreen );
- Menu_AddItem( &s_preferences.menu, &s_preferences.crosshairColorBlue );
- Menu_AddItem( &s_preferences.menu, &s_preferences.simpleitems );
- Menu_AddItem( &s_preferences.menu, &s_preferences.alwaysweaponbar );
- Menu_AddItem( &s_preferences.menu, &s_preferences.wallmarks );
- Menu_AddItem( &s_preferences.menu, &s_preferences.brass );
- Menu_AddItem( &s_preferences.menu, &s_preferences.dynamiclights );
- Menu_AddItem( &s_preferences.menu, &s_preferences.identifytarget );
- Menu_AddItem( &s_preferences.menu, &s_preferences.highqualitysky );
- Menu_AddItem( &s_preferences.menu, &s_preferences.synceveryframe );
- Menu_AddItem( &s_preferences.menu, &s_preferences.forcemodel );
- Menu_AddItem( &s_preferences.menu, &s_preferences.drawteamoverlay );
- Menu_AddItem( &s_preferences.menu, &s_preferences.delaghitscan );
- Menu_AddItem( &s_preferences.menu, &s_preferences.allowdownload );
-
- Menu_AddItem( &s_preferences.menu, &s_preferences.back );
-
- Preferences_SetMenuItems();
-}
-
-
-/*
-===============
-Preferences_Cache
-===============
-*/
-void Preferences_Cache( void ) {
- int n;
-
- trap_R_RegisterShaderNoMip( ART_FRAMEL );
- trap_R_RegisterShaderNoMip( ART_FRAMER );
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- for( n = 0; n < NUM_CROSSHAIRS; n++ ) {
- if (n < 10)
- s_preferences.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a' + n ) );
- else
- s_preferences.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%02d", n - 10) );
-
- }
-}
-
-
-/*
-===============
-UI_PreferencesMenu
-===============
-*/
-void UI_PreferencesMenu( void ) {
- Preferences_MenuInit();
- UI_PushMenu( &s_preferences.menu );
-}
diff --git a/game/code/q3_ui/ui_servers2.c b/game/code/q3_ui/ui_servers2.c
deleted file mode 100644
index c781713..0000000
--- a/game/code/q3_ui/ui_servers2.c
+++ /dev/null
@@ -1,1850 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-MULTIPLAYER MENU (SERVER BROWSER)
-
-=======================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define MAX_GLOBALSERVERS 256
-#define MAX_PINGREQUESTS 32
-#define MAX_ADDRESSLENGTH 64
-#define MAX_HOSTNAMELENGTH 31
-#define MAX_MAPNAMELENGTH 20
-#define MAX_LISTBOXITEMS 256
-#define MAX_LOCALSERVERS 124
-#define MAX_STATUSLENGTH 64
-#define MAX_LEAGUELENGTH 28
-#define MAX_LISTBOXWIDTH 70
-
-#define ART_BACK0 "menu/art_blueish/back_0"
-#define ART_BACK1 "menu/art_blueish/back_1"
-#define ART_CREATE0 "menu/art_blueish/create_0"
-#define ART_CREATE1 "menu/art_blueish/create_1"
-#define ART_SPECIFY0 "menu/art_blueish/specify_0"
-#define ART_SPECIFY1 "menu/art_blueish/specify_1"
-#define ART_REFRESH0 "menu/art_blueish/refresh_0"
-#define ART_REFRESH1 "menu/art_blueish/refresh_1"
-#define ART_CONNECT0 "menu/art_blueish/fight_0"
-#define ART_CONNECT1 "menu/art_blueish/fight_1"
-#define ART_ARROWS0 "menu/art_blueish/arrows_vert_0"
-#define ART_ARROWS_UP "menu/art_blueish/arrows_vert_top"
-#define ART_ARROWS_DOWN "menu/art_blueish/arrows_vert_bot"
-#define ART_UNKNOWNMAP "menu/art_blueish/unknownmap"
-#define ART_REMOVE0 "menu/art_blueish/delete_0"
-#define ART_REMOVE1 "menu/art_blueish/delete_1"
-
-#define ID_MASTER 10
-#define ID_GAMETYPE 11
-#define ID_SORTKEY 12
-#define ID_SHOW_FULL 13
-#define ID_SHOW_EMPTY 14
-
-#define ID_LIST 15
-#define ID_SCROLL_UP 16
-#define ID_SCROLL_DOWN 17
-#define ID_BACK 18
-#define ID_REFRESH 19
-#define ID_SPECIFY 20
-#define ID_CREATE 21
-#define ID_CONNECT 22
-#define ID_REMOVE 23
-
-//Beta 23
-#define ID_ONLY_HUMANS 24
-#define ID_HIDE_PRIVATE 25
-
-#define GR_LOGO 30
-#define GR_LETTERS 31
-
-#define UIAS_LOCAL 0
-#define UIAS_GLOBAL1 1
-#define UIAS_GLOBAL2 2
-#define UIAS_GLOBAL3 3
-#define UIAS_GLOBAL4 4
-#define UIAS_GLOBAL5 5
-#define UIAS_FAVORITES 6
-
-#define SORT_HOST 0
-#define SORT_MAP 1
-#define SORT_CLIENTS 2
-#define SORT_GAME 3
-#define SORT_PING 4
-#define SORT_HUMANS 5
-
-#define GAMES_ALL 0
-#define GAMES_FFA 1
-#define GAMES_TEAMPLAY 2
-#define GAMES_TOURNEY 3
-#define GAMES_CTF 4
-#define GAMES_1FCTF 5
-#define GAMES_OBELISK 6
-#define GAMES_HARVESTER 7
-#define GAMES_ELIMINATION 8
-#define GAMES_CTF_ELIMINATION 9
-#define GAMES_LMS 10
-#define GAMES_DOUBLE_D 11
-#define GAMES_DOM 12
-
-
-static const char *master_items[] = {
- "Local",
- "Internet",
- "Internet(2)",
- "Internet(3)",
- "Internet(4)",
- "Internet(5)",
- "Favorites",
- NULL
-};
-
-static const char *servertype_items[] = {
- "All",
- "Free For All",
- "Team Deathmatch",
- "Tournament",
- "Capture the Flag",
- "One Flag Capture",
- "Overload",
- "Harvester",
- "Elimination",
- "CTF Elimination",
- "Last Man Standing",
- "Double Domination",
- "Domination",
- NULL
-};
-
-static const char *sortkey_items[] = {
- "Server Name",
- "Map Name",
- "Open Player Spots",
- "Game Type",
- "Ping Time",
- "Human Players",
- NULL
-};
-
-static char* gamenames[] = {
- "DM ", // deathmatch
- "1v1", // tournament
- "SP ", // single player
- "Team DM", // team deathmatch
- "CTF", // capture the flag
- "One Flag CTF", // one flag ctf
- "OverLoad", // Overload
- "Harvester", // Harvester
- "Elimination",
- "CTF Elimination",
- "Last Man Standing",
- "Double Domination",
- "Domination", // Dom replaces Rocket Arena 3
- "Q3F", // Q3F
- "Urban Terror", // Urban Terror
- "OSP", // Orange Smoothie Productions
- "???", // unknown
- NULL
-};
-
-static char* netnames[] = {
- "???",
- "IP4",
- "IP6",
- NULL
-};
-
-static char quake3worldMessage[] = "Visit www.openarena.ws - News, Community, Events, Files";
-
-
-typedef struct {
- char adrstr[MAX_ADDRESSLENGTH];
- int start;
-} pinglist_t;
-
-typedef struct servernode_s {
- char adrstr[MAX_ADDRESSLENGTH];
- char hostname[MAX_HOSTNAMELENGTH+3];
- char mapname[MAX_MAPNAMELENGTH];
- int numclients;
- int humanclients;
- qboolean needPass;
- int maxclients;
- int pingtime;
- int gametype;
- char gamename[16];
- int nettype;
- int minPing;
- int maxPing;
- //qboolean bPB;
-
-} servernode_t;
-
-typedef struct {
- char buff[MAX_LISTBOXWIDTH+64]; // +60 gives room for color codes... Sago: I need four more
- servernode_t* servernode;
-} table_t;
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
-
- menulist_s master;
- menulist_s gametype;
- menulist_s sortkey;
- menuradiobutton_s showfull;
- menuradiobutton_s showempty;
-
- menuradiobutton_s onlyhumans;
- menuradiobutton_s hideprivate;
-
- menulist_s list;
- menubitmap_s mappic;
- menubitmap_s arrows;
- menubitmap_s up;
- menubitmap_s down;
- menutext_s status;
- menutext_s statusbar;
-
- menubitmap_s remove;
- menubitmap_s back;
- menubitmap_s refresh;
- menubitmap_s specify;
- menubitmap_s create;
- menubitmap_s go;
-
- pinglist_t pinglist[MAX_PINGREQUESTS];
- table_t table[MAX_LISTBOXITEMS];
- char* items[MAX_LISTBOXITEMS];
- int numqueriedservers;
- int *numservers;
- servernode_t *serverlist;
- int currentping;
- qboolean refreshservers;
- int nextpingtime;
- int maxservers;
- int refreshtime;
- char favoriteaddresses[MAX_FAVORITESERVERS][MAX_ADDRESSLENGTH];
- int numfavoriteaddresses;
-} arenaservers_t;
-
-static arenaservers_t g_arenaservers;
-
-
-static servernode_t g_globalserverlist[MAX_GLOBALSERVERS];
-static int g_numglobalservers;
-static servernode_t g_localserverlist[MAX_LOCALSERVERS];
-static int g_numlocalservers;
-static servernode_t g_favoriteserverlist[MAX_FAVORITESERVERS];
-static int g_numfavoriteservers;
-static int g_servertype;
-static int g_gametype;
-static int g_sortkey;
-static int g_emptyservers;
-static int g_fullservers;
-
-static int g_onlyhumans;
-static int g_hideprivate;
-
-/*
- *Removes illigal chars but keeps colors
- */
-char *Q_CleanStrWithColor( char *string ) {
- char* d;
- char* s;
- int c;
-
- s = string;
- d = string;
- while ((c = *s) != 0 ) {
- if ( Q_IsColorString( s ) ) {
- *d++ = c;
- }
- else if ( c >= 0x20 && c <= 0x7E ) {
- *d++ = c;
- }
- s++;
- }
- *d = '\0';
-
- return string;
-}
-
-
-/*
-=================
-ArenaServers_MaxPing
-=================
-*/
-static int ArenaServers_MaxPing( void ) {
- int maxPing;
-
- maxPing = (int)trap_Cvar_VariableValue( "cl_maxPing" );
- if( maxPing < 100 ) {
- maxPing = 100;
- }
- return maxPing;
-}
-
-
-/*
-=================
-ArenaServers_Compare
-=================
-*/
-static int QDECL ArenaServers_Compare( const void *arg1, const void *arg2 ) {
- float f1;
- float f2;
- servernode_t* t1;
- servernode_t* t2;
-
- t1 = (servernode_t *)arg1;
- t2 = (servernode_t *)arg2;
-
- switch( g_sortkey ) {
- case SORT_HOST:
- return Q_stricmp( t1->hostname, t2->hostname );
-
- case SORT_MAP:
- return Q_stricmp( t1->mapname, t2->mapname );
-
- case SORT_CLIENTS:
- f1 = t1->maxclients - t1->numclients;
- if( f1 < 0 ) {
- f1 = 0;
- }
-
- f2 = t2->maxclients - t2->numclients;
- if( f2 < 0 ) {
- f2 = 0;
- }
-
- if( f1 < f2 ) {
- return 1;
- }
- if( f1 == f2 ) {
- return 0;
- }
- return -1;
-
- case SORT_HUMANS:
- f1 = t1->humanclients;
- f2 = t2->humanclients;
-
- if( f1 < f2 ) {
- return 1;
- }
- if( f1 == f2 ) {
- return 0;
- }
- return -1;
-
- case SORT_GAME:
- if( t1->gametype < t2->gametype ) {
- return -1;
- }
- if( t1->gametype == t2->gametype ) {
- return 0;
- }
- return 1;
-
- case SORT_PING:
- if( t1->pingtime < t2->pingtime ) {
- return -1;
- }
- if( t1->pingtime > t2->pingtime ) {
- return 1;
- }
- return Q_stricmp( t1->hostname, t2->hostname );
- }
-
- return 0;
-}
-
-
-/*
-=================
-ArenaServers_Go
-=================
-*/
-static void ArenaServers_Go( void ) {
- servernode_t* servernode;
-
- servernode = g_arenaservers.table[g_arenaservers.list.curvalue].servernode;
- if( servernode ) {
- if(servernode->needPass) {
- UI_SpecifyPasswordMenu( va( "connect %s\n", servernode->adrstr ), servernode->hostname );
- }
- else
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", servernode->adrstr ) );
- }
-}
-
-
-/*
-=================
-ArenaServers_UpdatePicture
-=================
-*/
-static void ArenaServers_UpdatePicture( void ) {
- static char picname[64];
- servernode_t* servernodeptr;
-
- if( !g_arenaservers.list.numitems ) {
- g_arenaservers.mappic.generic.name = NULL;
- }
- else {
- servernodeptr = g_arenaservers.table[g_arenaservers.list.curvalue].servernode;
- Com_sprintf( picname, sizeof(picname), "levelshots/%s.tga", servernodeptr->mapname );
- g_arenaservers.mappic.generic.name = picname;
-
- }
-
- // force shader update during draw
- g_arenaservers.mappic.shader = 0;
-}
-
-/*
-=================
- Q_strcpyColor - This function will return the real length of the string if numChars
- len of character data is desired. It looks for color codes and adds 2 to the length
- for each combo found. This is used to make color strings show up correctly in column
- formatted environments. Otherwise, the columns will be off 2 * num of color codes.
-=================
-*/
-int Q_strcpyColor( const char *src, char *dest, int numChars )
-{
-int count, len;
-char *d;
-const char *s;
-
- if( !src || !dest )
- {
- return 0;
- }
-
- count = len = 0;
- s = src;
- d = dest;
-
- while( *s && count < numChars )
- {
- if( Q_IsColorString( s ))
- {
- *d++ = *s++;
- *d++ = *s++;
- len += 2;
- continue;
- }
- *d = *s;
- s++;
- d++;
- count++;
- len++;
- }
-
- // Now fill up the end of the string with space characters if needed...
- while( count < numChars )
- {
- *d = ' ';
- //d[len] = ' ';
- d++;
- len++;
- count++;
- }
- return len;
-}
-
-
-/*
-=================
-ArenaServers_UpdateMenu
-=================
-*/
-static void ArenaServers_UpdateMenu( void ) {
- int i;
- int j;
- int count, bufAddr;
- char* buff;
- servernode_t* servernodeptr;
- table_t* tableptr;
- char *b, *pingColor;
-
- if( g_arenaservers.numqueriedservers > 0 ) {
- // servers found
- if( g_arenaservers.refreshservers && ( g_arenaservers.currentping <= g_arenaservers.numqueriedservers ) ) {
- // show progress
- Com_sprintf( g_arenaservers.status.string, MAX_STATUSLENGTH, "%d of %d Arena Servers.", g_arenaservers.currentping, g_arenaservers.numqueriedservers);
- g_arenaservers.statusbar.string = "Press SPACE to stop";
- qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);
- }
- else {
- // all servers pinged - enable controls
- g_arenaservers.master.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.gametype.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.sortkey.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.showempty.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.onlyhumans.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.hideprivate.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.showfull.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.list.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.refresh.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.go.generic.flags &= ~QMF_GRAYED;
-
- // update status bar
- if( g_servertype >= UIAS_GLOBAL1 && g_servertype <= UIAS_GLOBAL5 ) {
- g_arenaservers.statusbar.string = quake3worldMessage;
- }
- else {
- g_arenaservers.statusbar.string = "";
- }
-
- }
- }
- else {
- // no servers found
- if( g_arenaservers.refreshservers ) {
- strcpy( g_arenaservers.status.string,"Scanning For Servers." );
- g_arenaservers.statusbar.string = "Press SPACE to stop";
-
- // disable controls during refresh
- g_arenaservers.master.generic.flags |= QMF_GRAYED;
- g_arenaservers.gametype.generic.flags |= QMF_GRAYED;
- g_arenaservers.sortkey.generic.flags |= QMF_GRAYED;
- g_arenaservers.showempty.generic.flags |= QMF_GRAYED;
- g_arenaservers.onlyhumans.generic.flags |= QMF_GRAYED;
- g_arenaservers.hideprivate.generic.flags |= QMF_GRAYED;
- g_arenaservers.showfull.generic.flags |= QMF_GRAYED;
- g_arenaservers.list.generic.flags |= QMF_GRAYED;
- g_arenaservers.refresh.generic.flags |= QMF_GRAYED;
- g_arenaservers.go.generic.flags |= QMF_GRAYED;
- }
- else {
- if( g_arenaservers.numqueriedservers < 0 ) {
- strcpy(g_arenaservers.status.string,"No Response From Master Server." );
- }
- else {
- strcpy(g_arenaservers.status.string,"No Servers Found." );
- }
-
- // update status bar
- if( g_servertype >= UIAS_GLOBAL1 && g_servertype <= UIAS_GLOBAL5 ) {
- g_arenaservers.statusbar.string = quake3worldMessage;
- }
- else {
- g_arenaservers.statusbar.string = "";
- }
-
- // end of refresh - set control state
- g_arenaservers.master.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.gametype.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.sortkey.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.showempty.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.onlyhumans.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.hideprivate.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.showfull.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.list.generic.flags |= QMF_GRAYED;
- g_arenaservers.refresh.generic.flags &= ~QMF_GRAYED;
- g_arenaservers.go.generic.flags |= QMF_GRAYED;
- }
-
- // zero out list box
- g_arenaservers.list.numitems = 0;
- g_arenaservers.list.curvalue = 0;
- g_arenaservers.list.top = 0;
-
- // update picture
- ArenaServers_UpdatePicture();
- return;
- }
-
- // build list box strings - apply culling filters
- servernodeptr = g_arenaservers.serverlist;
- count = *g_arenaservers.numservers;
- for( i = 0, j = 0; i < count; i++, servernodeptr++ ) {
- tableptr = &g_arenaservers.table[j];
- tableptr->servernode = servernodeptr;
- buff = tableptr->buff;
-
- // can only cull valid results
- if( !g_emptyservers && !servernodeptr->numclients ) {
- continue;
- }
-
- //If "Show only humans" and "Hide empty server" are enabled hide servers that only have bots
- if( !g_emptyservers && g_onlyhumans && !servernodeptr->humanclients ) {
- continue;
- }
-
- if( !g_fullservers && ( servernodeptr->numclients == servernodeptr->maxclients ) ) {
- continue;
- }
-
- switch( g_gametype ) {
- case GAMES_ALL:
- break;
-
- case GAMES_FFA:
- if( servernodeptr->gametype != GT_FFA ) {
- continue;
- }
- break;
-
- case GAMES_TEAMPLAY:
- if( servernodeptr->gametype != GT_TEAM ) {
- continue;
- }
- break;
-
- case GAMES_TOURNEY:
- if( servernodeptr->gametype != GT_TOURNAMENT ) {
- continue;
- }
- break;
-
- case GAMES_CTF:
- if( servernodeptr->gametype != GT_CTF ) {
- continue;
- }
- break;
-
- case GAMES_1FCTF:
- if( servernodeptr->gametype != GT_1FCTF ) {
- continue;
- }
- break;
-
- case GAMES_OBELISK:
- if( servernodeptr->gametype != GT_OBELISK ) {
- continue;
- }
- break;
-
- case GAMES_HARVESTER:
- if( servernodeptr->gametype != GT_HARVESTER ) {
- continue;
- }
- break;
-
- case GAMES_ELIMINATION:
- if( servernodeptr->gametype != GT_ELIMINATION ) {
- continue;
- }
- break;
-
- case GAMES_CTF_ELIMINATION:
- if( servernodeptr->gametype != GT_CTF_ELIMINATION ) {
- continue;
- }
- break;
-
- case GAMES_LMS:
- if( servernodeptr->gametype != GT_LMS ) {
- continue;
- }
- break;
-
- case GAMES_DOUBLE_D:
- if( servernodeptr->gametype != GT_DOUBLE_D ) {
- continue;
- }
- break;
-
- case GAMES_DOM:
- if( servernodeptr->gametype != GT_DOMINATION ) {
- continue;
- }
- break;
- }
-
- if(g_hideprivate && servernodeptr->needPass)
- continue;
-
- if( servernodeptr->pingtime < servernodeptr->minPing ) {
- pingColor = S_COLOR_BLUE;
- }
- else if( servernodeptr->maxPing && servernodeptr->pingtime > servernodeptr->maxPing ) {
- pingColor = S_COLOR_BLUE;
- }
- else if( servernodeptr->pingtime < 200 ) {
- pingColor = S_COLOR_GREEN;
- }
- else if( servernodeptr->pingtime < 400 ) {
- pingColor = S_COLOR_YELLOW;
- }
- else {
- pingColor = S_COLOR_RED;
- }
-
- /*
- Com_sprintf( buff, MAX_LISTBOXWIDTH, "%-20.20s %-12.12s %2d/%2d %-8.8s %3s %s%3d ",
- servernodeptr->hostname, servernodeptr->mapname, servernodeptr->numclients,
- servernodeptr->maxclients, servernodeptr->gamename,
- netnames[servernodeptr->nettype], pingColor, servernodeptr->pingtime ); //, servernodeptr->bPB ? "Yes" : "No"
- */
- b = buff;
- *b++ = '^';
- *b++ = '7';
- bufAddr = Q_strcpyColor( servernodeptr->hostname, b, 30 );
- b += bufAddr;
- *b++ = ' ';
- *b++ = '^';
- *b++ = '7';
-
- bufAddr = Q_strcpyColor( servernodeptr->mapname, b, 16 );
- b += bufAddr;
- *b++ = ' ';
-
- if(g_onlyhumans == 0)
- Com_sprintf( b, 7, "%2d/%2d ", servernodeptr->numclients, servernodeptr->maxclients );
- else
- Com_sprintf( b, 7, "%2d/%2d ", servernodeptr->humanclients, servernodeptr->maxclients );
- b += 6;
-
- bufAddr = Q_strcpyColor( servernodeptr->gamename, b, 8 );
- b += bufAddr;
- *b++ = ' ';
-
- bufAddr = Q_strcpyColor( netnames[servernodeptr->nettype], b, 3 );
- b += bufAddr;
- *b++ = ' ';
-
- Com_sprintf( b, 12, "%s%3d ", pingColor, servernodeptr->pingtime );
- j++;
- }
-
- g_arenaservers.list.numitems = j;
- g_arenaservers.list.curvalue = 0;
- g_arenaservers.list.top = 0;
-
- // update picture
- ArenaServers_UpdatePicture();
-}
-
-
-/*
-=================
-ArenaServers_Remove
-=================
-*/
-static void ArenaServers_Remove( void )
-{
- int i;
- servernode_t* servernodeptr;
- table_t* tableptr;
-
- if (!g_arenaservers.list.numitems)
- return;
-
- // remove selected item from display list
- // items are in scattered order due to sort and cull
- // perform delete on list box contents, resync all lists
-
- tableptr = &g_arenaservers.table[g_arenaservers.list.curvalue];
- servernodeptr = tableptr->servernode;
-
- // find address in master list
- for (i=0; i<g_arenaservers.numfavoriteaddresses; i++)
- {
- if (!Q_stricmp(g_arenaservers.favoriteaddresses[i],servernodeptr->adrstr))
- {
- // delete address from master list
- if (i < g_arenaservers.numfavoriteaddresses-1)
- {
- // shift items up
- memcpy( &g_arenaservers.favoriteaddresses[i], &g_arenaservers.favoriteaddresses[i+1], (g_arenaservers.numfavoriteaddresses - i - 1)* MAX_ADDRESSLENGTH );
- }
- g_arenaservers.numfavoriteaddresses--;
- memset( &g_arenaservers.favoriteaddresses[g_arenaservers.numfavoriteaddresses], 0, MAX_ADDRESSLENGTH );
- break;
- }
- }
-
- // find address in server list
- for (i=0; i<g_numfavoriteservers; i++)
- {
- if (&g_favoriteserverlist[i] == servernodeptr)
- {
- // delete address from server list
- if (i < g_numfavoriteservers-1)
- {
- // shift items up
- memcpy( &g_favoriteserverlist[i], &g_favoriteserverlist[i+1], (g_numfavoriteservers - i - 1)*sizeof(servernode_t));
- }
- g_numfavoriteservers--;
- memset( &g_favoriteserverlist[ g_numfavoriteservers ], 0, sizeof(servernode_t));
- break;
- }
- }
-
- g_arenaservers.numqueriedservers = g_arenaservers.numfavoriteaddresses;
- g_arenaservers.currentping = g_arenaservers.numfavoriteaddresses;
-}
-
-
-/*
-=================
-ArenaServers_Insert
-=================
-*/
-static void ArenaServers_Insert( char* adrstr, char* info, int pingtime )
-{
- servernode_t* servernodeptr;
- char* s;
- int i;
-
-
- if ((pingtime >= ArenaServers_MaxPing()) && (g_servertype != UIAS_FAVORITES))
- {
- // slow global or local servers do not get entered
- return;
- }
-
- if (*g_arenaservers.numservers >= g_arenaservers.maxservers) {
- // list full;
- servernodeptr = g_arenaservers.serverlist+(*g_arenaservers.numservers)-1;
- } else {
- // next slot
- servernodeptr = g_arenaservers.serverlist+(*g_arenaservers.numservers);
- (*g_arenaservers.numservers)++;
- }
-
- Q_strncpyz( servernodeptr->adrstr, adrstr, MAX_ADDRESSLENGTH );
-
- Q_strncpyz( servernodeptr->hostname, Info_ValueForKey( info, "hostname"), MAX_HOSTNAMELENGTH );
- Q_CleanStrWithColor( servernodeptr->hostname );
- Q_strupr( servernodeptr->hostname );
-
- Q_strncpyz( servernodeptr->mapname, Info_ValueForKey( info, "mapname"), MAX_MAPNAMELENGTH );
- Q_CleanStr( servernodeptr->mapname );
- Q_strupr( servernodeptr->mapname );
-
- servernodeptr->numclients = atoi( Info_ValueForKey( info, "clients") );
- servernodeptr->humanclients = atoi( Info_ValueForKey( info, "g_humanplayers") );
- servernodeptr->needPass = atoi( Info_ValueForKey( info, "g_needpass") );
- servernodeptr->maxclients = atoi( Info_ValueForKey( info, "sv_maxclients") );
- servernodeptr->pingtime = pingtime;
- servernodeptr->minPing = atoi( Info_ValueForKey( info, "minPing") );
- servernodeptr->maxPing = atoi( Info_ValueForKey( info, "maxPing") );
-
-
- s = Info_ValueForKey( info, "nettype" );
- for (i=0; ;i++)
- {
- if (!netnames[i])
- {
- servernodeptr->nettype = 0;
- break;
- }
- else if (!Q_stricmp( netnames[i], s ))
- {
- servernodeptr->nettype = i;
- break;
- }
- }
-
- servernodeptr->nettype = atoi(Info_ValueForKey(info, "nettype"));
-
- s = Info_ValueForKey( info, "game");
- i = atoi( Info_ValueForKey( info, "gametype") );
- if( i < 0 ) {
- i = 0;
- }
- else if( i > 11 ) {
- i = 12;
- }
- if( *s ) {
- servernodeptr->gametype = i;//-1;
- Q_strncpyz( servernodeptr->gamename, s, sizeof(servernodeptr->gamename) );
- }
- else {
- servernodeptr->gametype = i;
- Q_strncpyz( servernodeptr->gamename, gamenames[i], sizeof(servernodeptr->gamename) );
- }
-}
-
-
-/*
-=================
-ArenaServers_InsertFavorites
-
-Insert nonresponsive address book entries into display lists.
-=================
-*/
-void ArenaServers_InsertFavorites( void )
-{
- int i;
- int j;
- char info[MAX_INFO_STRING];
-
- // resync existing results with new or deleted cvars
- info[0] = '\0';
- Info_SetValueForKey( info, "hostname", "No Response" );
- for (i=0; i<g_arenaservers.numfavoriteaddresses; i++)
- {
- // find favorite address in refresh list
- for (j=0; j<g_numfavoriteservers; j++)
- if (!Q_stricmp(g_arenaservers.favoriteaddresses[i],g_favoriteserverlist[j].adrstr))
- break;
-
- if ( j >= g_numfavoriteservers)
- {
- // not in list, add it
- ArenaServers_Insert( g_arenaservers.favoriteaddresses[i], info, ArenaServers_MaxPing() );
- }
- }
-}
-
-
-/*
-=================
-ArenaServers_LoadFavorites
-
-Load cvar address book entries into local lists.
-=================
-*/
-void ArenaServers_LoadFavorites( void )
-{
- int i;
- int j;
- int numtempitems;
- char emptyinfo[MAX_INFO_STRING];
- char adrstr[MAX_ADDRESSLENGTH];
- servernode_t templist[MAX_FAVORITESERVERS];
- qboolean found;
-
- found = qfalse;
- emptyinfo[0] = '\0';
-
- // copy the old
- memcpy( templist, g_favoriteserverlist, sizeof(servernode_t)*MAX_FAVORITESERVERS );
- numtempitems = g_numfavoriteservers;
-
- // clear the current for sync
- memset( g_favoriteserverlist, 0, sizeof(servernode_t)*MAX_FAVORITESERVERS );
- g_numfavoriteservers = 0;
-
- // resync existing results with new or deleted cvars
- for (i=0; i<MAX_FAVORITESERVERS; i++)
- {
- trap_Cvar_VariableStringBuffer( va("server%d",i+1), adrstr, MAX_ADDRESSLENGTH );
- if (!adrstr[0])
- continue;
-
- // quick sanity check to avoid slow domain name resolving
- // first character must be numeric
- if (adrstr[0] < '0' || adrstr[0] > '9')
- continue;
-
- // favorite server addresses must be maintained outside refresh list
- // this mimics local and global netadr's stored in client
- // these can be fetched to fill ping list
- strcpy( g_arenaservers.favoriteaddresses[g_numfavoriteservers], adrstr );
-
- // find this server in the old list
- for (j=0; j<numtempitems; j++)
- if (!Q_stricmp( templist[j].adrstr, adrstr ))
- break;
-
- if (j < numtempitems)
- {
- // found server - add exisiting results
- memcpy( &g_favoriteserverlist[g_numfavoriteservers], &templist[j], sizeof(servernode_t) );
- found = qtrue;
- }
- else
- {
- // add new server
- Q_strncpyz( g_favoriteserverlist[g_numfavoriteservers].adrstr, adrstr, MAX_ADDRESSLENGTH );
- g_favoriteserverlist[g_numfavoriteservers].pingtime = ArenaServers_MaxPing();
- }
-
- g_numfavoriteservers++;
- }
-
- g_arenaservers.numfavoriteaddresses = g_numfavoriteservers;
-
- if (!found)
- {
- // no results were found, reset server list
- // list will be automatically refreshed when selected
- g_numfavoriteservers = 0;
- }
-}
-
-
-/*
-=================
-ArenaServers_StopRefresh
-=================
-*/
-static void ArenaServers_StopRefresh( void )
-{
- if (!g_arenaservers.refreshservers)
- // not currently refreshing
- return;
-
- g_arenaservers.refreshservers = qfalse;
-
- if (g_servertype == UIAS_FAVORITES)
- {
- // nonresponsive favorites must be shown
- ArenaServers_InsertFavorites();
- }
-
- // final tally
- if (g_arenaservers.numqueriedservers >= 0)
- {
- g_arenaservers.currentping = *g_arenaservers.numservers;
- g_arenaservers.numqueriedservers = *g_arenaservers.numservers;
- }
-
- // sort
- qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);
-
- ArenaServers_UpdateMenu();
-}
-
-
-/*
-=================
-ArenaServers_DoRefresh
-=================
-*/
-static void ArenaServers_DoRefresh( void )
-{
- int i;
- int j;
- int time;
- int maxPing;
- char adrstr[MAX_ADDRESSLENGTH];
- char info[MAX_INFO_STRING];
-
- if (uis.realtime < g_arenaservers.refreshtime)
- {
- if (g_servertype != UIAS_FAVORITES) {
- if (g_servertype == UIAS_LOCAL) {
- if (!trap_LAN_GetServerCount(g_servertype)) {
- return;
- }
- }
- if (trap_LAN_GetServerCount(g_servertype) < 0) {
- // still waiting for response
- return;
- }
- }
- }
-
- if (uis.realtime < g_arenaservers.nextpingtime)
- {
- // wait for time trigger
- return;
- }
-
- // trigger at 10Hz intervals
- g_arenaservers.nextpingtime = uis.realtime + 10;
-
- // process ping results
- maxPing = ArenaServers_MaxPing();
- for (i=0; i<MAX_PINGREQUESTS; i++)
- {
- trap_LAN_GetPing( i, adrstr, MAX_ADDRESSLENGTH, &time );
- if (!adrstr[0])
- {
- // ignore empty or pending pings
- continue;
- }
-
- // find ping result in our local list
- for (j=0; j<MAX_PINGREQUESTS; j++)
- if (!Q_stricmp( adrstr, g_arenaservers.pinglist[j].adrstr ))
- break;
-
- if (j < MAX_PINGREQUESTS)
- {
- // found it
- if (!time)
- {
- time = uis.realtime - g_arenaservers.pinglist[j].start;
- if (time < maxPing)
- {
- // still waiting
- continue;
- }
- }
-
- if (time > maxPing)
- {
- // stale it out
- info[0] = '\0';
- time = maxPing;
- }
- else
- {
- trap_LAN_GetPingInfo( i, info, MAX_INFO_STRING );
- }
-
- // insert ping results
- ArenaServers_Insert( adrstr, info, time );
-
- // clear this query from internal list
- g_arenaservers.pinglist[j].adrstr[0] = '\0';
- }
-
- // clear this query from external list
- trap_LAN_ClearPing( i );
- }
-
- // get results of servers query
- // counts can increase as servers respond
- if (g_servertype == UIAS_FAVORITES) {
- g_arenaservers.numqueriedservers = g_arenaservers.numfavoriteaddresses;
- } else {
- g_arenaservers.numqueriedservers = trap_LAN_GetServerCount(g_servertype);
- }
-
-// if (g_arenaservers.numqueriedservers > g_arenaservers.maxservers)
-// g_arenaservers.numqueriedservers = g_arenaservers.maxservers;
-
- // send ping requests in reasonable bursts
- // iterate ping through all found servers
- for (i=0; i<MAX_PINGREQUESTS && g_arenaservers.currentping < g_arenaservers.numqueriedservers; i++)
- {
- if (trap_LAN_GetPingQueueCount() >= MAX_PINGREQUESTS)
- {
- // ping queue is full
- break;
- }
-
- // find empty slot
- for (j=0; j<MAX_PINGREQUESTS; j++)
- if (!g_arenaservers.pinglist[j].adrstr[0])
- break;
-
- if (j >= MAX_PINGREQUESTS)
- // no empty slots available yet - wait for timeout
- break;
-
- // get an address to ping
-
- if (g_servertype == UIAS_FAVORITES) {
- strcpy( adrstr, g_arenaservers.favoriteaddresses[g_arenaservers.currentping] );
- } else {
- trap_LAN_GetServerAddressString(g_servertype, g_arenaservers.currentping, adrstr, MAX_ADDRESSLENGTH );
- }
-
- strcpy( g_arenaservers.pinglist[j].adrstr, adrstr );
- g_arenaservers.pinglist[j].start = uis.realtime;
-
- trap_Cmd_ExecuteText( EXEC_NOW, va( "ping %s\n", adrstr ) );
-
- // advance to next server
- g_arenaservers.currentping++;
- }
-
- if (!trap_LAN_GetPingQueueCount())
- {
- // all pings completed
- ArenaServers_StopRefresh();
- return;
- }
-
- // update the user interface with ping status
- ArenaServers_UpdateMenu();
-}
-
-
-/*
-=================
-ArenaServers_StartRefresh
-=================
-*/
-static void ArenaServers_StartRefresh( void )
-{
- int i;
- char myargs[32], protocol[32];
-
- memset( g_arenaservers.serverlist, 0, g_arenaservers.maxservers*sizeof(table_t) );
-
- for (i=0; i<MAX_PINGREQUESTS; i++)
- {
- g_arenaservers.pinglist[i].adrstr[0] = '\0';
- trap_LAN_ClearPing( i );
- }
-
- g_arenaservers.refreshservers = qtrue;
- g_arenaservers.currentping = 0;
- g_arenaservers.nextpingtime = 0;
- *g_arenaservers.numservers = 0;
- g_arenaservers.numqueriedservers = 0;
-
- // allow max 5 seconds for responses
- g_arenaservers.refreshtime = uis.realtime + 5000;
-
- // place menu in zeroed state
- ArenaServers_UpdateMenu();
-
- if( g_servertype == UIAS_LOCAL ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "localservers\n" );
- return;
- }
-
- if( g_servertype >= UIAS_GLOBAL1 && g_servertype <= UIAS_GLOBAL5 ) {
- switch( g_arenaservers.gametype.curvalue ) {
- default:
- case GAMES_ALL:
- myargs[0] = 0;
- break;
-
- case GAMES_FFA:
- strcpy( myargs, " ffa" );
- break;
-
- case GAMES_TEAMPLAY:
- strcpy( myargs, " team" );
- break;
-
- case GAMES_TOURNEY:
- strcpy( myargs, " tourney" );
- break;
-
- case GAMES_CTF:
- strcpy( myargs, " ctf" );
- break;
-
- case GAMES_ELIMINATION:
- strcpy( myargs, " elimination" );
- break;
-
- case GAMES_CTF_ELIMINATION:
- strcpy( myargs, " ctfelimination" );
- break;
-
- case GAMES_LMS:
- strcpy( myargs, " lms" );
- break;
-
- case GAMES_DOUBLE_D:
- strcpy( myargs, " dd" );
- break;
-
- case GAMES_DOM:
- strcpy( myargs, " dom" );
- break;
- }
-
-
- if (g_emptyservers) {
- strcat(myargs, " empty");
- }
-
- if (g_fullservers) {
- strcat(myargs, " full");
- }
-
- protocol[0] = '\0';
- trap_Cvar_VariableStringBuffer( "debug_protocol", protocol, sizeof(protocol) );
- if (strlen(protocol)) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "globalservers %d %s%s\n", g_servertype - 1, protocol, myargs ));
- }
- else {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "globalservers %d %d%s\n", g_servertype - 1, (int)trap_Cvar_VariableValue( "protocol" ), myargs ) );
- }
- }
-}
-
-
-/*
-=================
-ArenaServers_SaveChanges
-=================
-*/
-void ArenaServers_SaveChanges( void )
-{
- int i;
-
- for (i=0; i<g_arenaservers.numfavoriteaddresses; i++)
- trap_Cvar_Set( va("server%d",i+1), g_arenaservers.favoriteaddresses[i] );
-
- for (; i<MAX_FAVORITESERVERS; i++)
- trap_Cvar_Set( va("server%d",i+1), "" );
-}
-
-
-/*
-=================
-ArenaServers_Sort
-=================
-*/
-void ArenaServers_Sort( int type ) {
- if( g_sortkey == type ) {
- return;
- }
-
- g_sortkey = type;
- qsort( g_arenaservers.serverlist, *g_arenaservers.numservers, sizeof( servernode_t ), ArenaServers_Compare);
-}
-
-
-/*
-=================
-ArenaServers_SetType
-=================
-*/
-int ArenaServers_SetType( int type )
-{
- if(type >= UIAS_GLOBAL1 && type <= UIAS_GLOBAL5)
- {
- char masterstr[2], cvarname[sizeof("sv_master1")];
-
- while(type <= UIAS_GLOBAL5)
- {
- Com_sprintf(cvarname, sizeof(cvarname), "sv_master%d", type);
- trap_Cvar_VariableStringBuffer(cvarname, masterstr, sizeof(masterstr));
- if(*masterstr)
- break;
-
- type++;
- }
- }
-
- g_servertype = type;
-
- switch( type ) {
- default:
- case UIAS_LOCAL:
- g_arenaservers.remove.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- g_arenaservers.serverlist = g_localserverlist;
- g_arenaservers.numservers = &g_numlocalservers;
- g_arenaservers.maxservers = MAX_LOCALSERVERS;
- break;
-
- case UIAS_GLOBAL1:
- case UIAS_GLOBAL2:
- case UIAS_GLOBAL3:
- case UIAS_GLOBAL4:
- case UIAS_GLOBAL5:
- g_arenaservers.remove.generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- g_arenaservers.serverlist = g_globalserverlist;
- g_arenaservers.numservers = &g_numglobalservers;
- g_arenaservers.maxservers = MAX_GLOBALSERVERS;
- break;
-
- case UIAS_FAVORITES:
- g_arenaservers.remove.generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);
- g_arenaservers.serverlist = g_favoriteserverlist;
- g_arenaservers.numservers = &g_numfavoriteservers;
- g_arenaservers.maxservers = MAX_FAVORITESERVERS;
- break;
-
- }
-
- if( !*g_arenaservers.numservers ) {
- ArenaServers_StartRefresh();
- }
- else {
- // avoid slow operation, use existing results
- g_arenaservers.currentping = *g_arenaservers.numservers;
- g_arenaservers.numqueriedservers = *g_arenaservers.numservers;
- ArenaServers_UpdateMenu();
- }
- strcpy(g_arenaservers.status.string,"hit refresh to update");
-
- return type;
-}
-
-/*
-=================
-ArenaServers_Event
-=================
-*/
-static void ArenaServers_Event( void* ptr, int event ) {
- int id;
-
- id = ((menucommon_s*)ptr)->id;
-
- if( event != QM_ACTIVATED && id != ID_LIST ) {
- return;
- }
-
- switch( id ) {
- case ID_MASTER:
- g_arenaservers.master.curvalue = ArenaServers_SetType(g_arenaservers.master.curvalue);
- trap_Cvar_SetValue( "ui_browserMaster", g_arenaservers.master.curvalue);
- break;
-
- case ID_GAMETYPE:
- trap_Cvar_SetValue( "ui_browserGameType", g_arenaservers.gametype.curvalue );
- g_gametype = g_arenaservers.gametype.curvalue;
- ArenaServers_UpdateMenu();
- break;
-
- case ID_SORTKEY:
- trap_Cvar_SetValue( "ui_browserSortKey", g_arenaservers.sortkey.curvalue );
- ArenaServers_Sort( g_arenaservers.sortkey.curvalue );
- ArenaServers_UpdateMenu();
- break;
-
- case ID_SHOW_FULL:
- trap_Cvar_SetValue( "ui_browserShowFull", g_arenaservers.showfull.curvalue );
- g_fullservers = g_arenaservers.showfull.curvalue;
- ArenaServers_UpdateMenu();
- break;
-
- case ID_SHOW_EMPTY:
- trap_Cvar_SetValue( "ui_browserShowEmpty", g_arenaservers.showempty.curvalue );
- g_emptyservers = g_arenaservers.showempty.curvalue;
- ArenaServers_UpdateMenu();
- break;
-
- case ID_ONLY_HUMANS:
- trap_Cvar_SetValue( "ui_browserOnlyHumans", g_arenaservers.onlyhumans.curvalue );
- g_onlyhumans = g_arenaservers.onlyhumans.curvalue;
- ArenaServers_UpdateMenu();
- break;
-
- case ID_HIDE_PRIVATE:
- //trap_Cvar_SetValue( "ui_browserHidePrivate", g_arenaservers.hideprivate.curvalue );
- g_hideprivate = g_arenaservers.hideprivate.curvalue;
- ArenaServers_UpdateMenu();
- break;
-
- case ID_LIST:
- if( event == QM_GOTFOCUS ) {
- ArenaServers_UpdatePicture();
- }
- break;
-
- case ID_SCROLL_UP:
- ScrollList_Key( &g_arenaservers.list, K_UPARROW );
- break;
-
- case ID_SCROLL_DOWN:
- ScrollList_Key( &g_arenaservers.list, K_DOWNARROW );
- break;
-
- case ID_BACK:
- ArenaServers_StopRefresh();
- ArenaServers_SaveChanges();
- UI_PopMenu();
- break;
-
- case ID_REFRESH:
- ArenaServers_StartRefresh();
- break;
-
- case ID_SPECIFY:
- UI_SpecifyServerMenu();
- break;
-
- case ID_CREATE:
- UI_StartServerMenu( qtrue );
- break;
-
- case ID_CONNECT:
- ArenaServers_Go();
- break;
-
- case ID_REMOVE:
- ArenaServers_Remove();
- ArenaServers_UpdateMenu();
- break;
- }
-}
-
-
-/*
-=================
-ArenaServers_MenuDraw
-=================
-*/
-static void ArenaServers_MenuDraw( void )
-{
- if (g_arenaservers.refreshservers)
- ArenaServers_DoRefresh();
-
- Menu_Draw( &g_arenaservers.menu );
-}
-
-
-/*
-=================
-ArenaServers_MenuKey
-=================
-*/
-static sfxHandle_t ArenaServers_MenuKey( int key ) {
- if( key == K_SPACE && g_arenaservers.refreshservers ) {
- ArenaServers_StopRefresh();
- return menu_move_sound;
- }
-
- if( ( key == K_DEL || key == K_KP_DEL ) && ( g_servertype == UIAS_FAVORITES ) &&
- ( Menu_ItemAtCursor( &g_arenaservers.menu) == &g_arenaservers.list ) ) {
- ArenaServers_Remove();
- ArenaServers_UpdateMenu();
- return menu_move_sound;
- }
-
- if( key == K_MOUSE2 || key == K_ESCAPE ) {
- ArenaServers_StopRefresh();
- ArenaServers_SaveChanges();
- }
-
- if( key == K_MWHEELUP ) {
- ScrollList_Key( &g_arenaservers.list, K_UPARROW );
- }
-
- if( key == K_MWHEELDOWN ) {
- ScrollList_Key( &g_arenaservers.list, K_DOWNARROW );
- }
-
-
- return Menu_DefaultKey( &g_arenaservers.menu, key );
-}
-
-
-/*
-=================
-ArenaServers_MenuInit
-=================
-*/
-static void ArenaServers_MenuInit( void ) {
- int i;
- int y;
- int value;
- static char statusbuffer[MAX_STATUSLENGTH];
-
- // zero set all our globals
- memset( &g_arenaservers, 0 ,sizeof(arenaservers_t) );
-
- ArenaServers_Cache();
-
- g_arenaservers.menu.fullscreen = qtrue;
- g_arenaservers.menu.wrapAround = qtrue;
- g_arenaservers.menu.draw = ArenaServers_MenuDraw;
- g_arenaservers.menu.key = ArenaServers_MenuKey;
-
- g_arenaservers.banner.generic.type = MTYPE_BTEXT;
- g_arenaservers.banner.generic.flags = QMF_CENTER_JUSTIFY;
- g_arenaservers.banner.generic.x = 320;
- g_arenaservers.banner.generic.y = 16;
- g_arenaservers.banner.string = "ARENA SERVERS";
- g_arenaservers.banner.style = UI_CENTER;
- g_arenaservers.banner.color = color_white;
-
- y = 80-SMALLCHAR_HEIGHT;
- g_arenaservers.master.generic.type = MTYPE_SPINCONTROL;
- g_arenaservers.master.generic.name = "Servers:";
- g_arenaservers.master.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- g_arenaservers.master.generic.callback = ArenaServers_Event;
- g_arenaservers.master.generic.id = ID_MASTER;
- g_arenaservers.master.generic.x = 320;
- g_arenaservers.master.generic.y = y;
- g_arenaservers.master.itemnames = master_items;
-
- y += SMALLCHAR_HEIGHT;
- g_arenaservers.gametype.generic.type = MTYPE_SPINCONTROL;
- g_arenaservers.gametype.generic.name = "Game Type:";
- g_arenaservers.gametype.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- g_arenaservers.gametype.generic.callback = ArenaServers_Event;
- g_arenaservers.gametype.generic.id = ID_GAMETYPE;
- g_arenaservers.gametype.generic.x = 320;
- g_arenaservers.gametype.generic.y = y;
- g_arenaservers.gametype.itemnames = servertype_items;
-
- y += SMALLCHAR_HEIGHT;
- g_arenaservers.sortkey.generic.type = MTYPE_SPINCONTROL;
- g_arenaservers.sortkey.generic.name = "Sort By:";
- g_arenaservers.sortkey.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- g_arenaservers.sortkey.generic.callback = ArenaServers_Event;
- g_arenaservers.sortkey.generic.id = ID_SORTKEY;
- g_arenaservers.sortkey.generic.x = 320;
- g_arenaservers.sortkey.generic.y = y;
- g_arenaservers.sortkey.itemnames = sortkey_items;
-
- y += SMALLCHAR_HEIGHT;
- g_arenaservers.showfull.generic.type = MTYPE_RADIOBUTTON;
- g_arenaservers.showfull.generic.name = "Show Full:";
- g_arenaservers.showfull.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- g_arenaservers.showfull.generic.callback = ArenaServers_Event;
- g_arenaservers.showfull.generic.id = ID_SHOW_FULL;
- g_arenaservers.showfull.generic.x = 320;
- g_arenaservers.showfull.generic.y = y;
-
- y += SMALLCHAR_HEIGHT;
- g_arenaservers.showempty.generic.type = MTYPE_RADIOBUTTON;
- g_arenaservers.showempty.generic.name = "Show Empty:";
- g_arenaservers.showempty.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- g_arenaservers.showempty.generic.callback = ArenaServers_Event;
- g_arenaservers.showempty.generic.id = ID_SHOW_EMPTY;
- g_arenaservers.showempty.generic.x = 320;
- g_arenaservers.showempty.generic.y = y;
-
- y += SMALLCHAR_HEIGHT;
- g_arenaservers.onlyhumans.generic.type = MTYPE_RADIOBUTTON;
- g_arenaservers.onlyhumans.generic.name = "Only humans:";
- g_arenaservers.onlyhumans.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- g_arenaservers.onlyhumans.generic.callback = ArenaServers_Event;
- g_arenaservers.onlyhumans.generic.id = ID_ONLY_HUMANS;
- g_arenaservers.onlyhumans.generic.x = 320;
- g_arenaservers.onlyhumans.generic.y = y;
-
- y += SMALLCHAR_HEIGHT;
- g_arenaservers.hideprivate.generic.type = MTYPE_RADIOBUTTON;
- g_arenaservers.hideprivate.generic.name = "Hide private:";
- g_arenaservers.hideprivate.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- g_arenaservers.hideprivate.generic.callback = ArenaServers_Event;
- g_arenaservers.hideprivate.generic.id = ID_HIDE_PRIVATE;
- g_arenaservers.hideprivate.generic.x = 320;
- g_arenaservers.hideprivate.generic.y = y;
-
- y += 2 * SMALLCHAR_HEIGHT;
- g_arenaservers.list.generic.type = MTYPE_SCROLLLIST;
- g_arenaservers.list.generic.flags = QMF_HIGHLIGHT_IF_FOCUS;
- g_arenaservers.list.generic.id = ID_LIST;
- g_arenaservers.list.generic.callback = ArenaServers_Event;
- g_arenaservers.list.generic.x = 22;
- g_arenaservers.list.generic.y = y;
- g_arenaservers.list.width = MAX_LISTBOXWIDTH;
- g_arenaservers.list.height = 11;
- g_arenaservers.list.itemnames = (const char **)g_arenaservers.items;
- for( i = 0; i < MAX_LISTBOXITEMS; i++ ) {
- g_arenaservers.items[i] = g_arenaservers.table[i].buff;
- }
-
- g_arenaservers.mappic.generic.type = MTYPE_BITMAP;
- g_arenaservers.mappic.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- g_arenaservers.mappic.generic.x = 72;
- g_arenaservers.mappic.generic.y = 80;
- g_arenaservers.mappic.width = 128;
- g_arenaservers.mappic.height = 96;
- g_arenaservers.mappic.errorpic = ART_UNKNOWNMAP;
-
- g_arenaservers.arrows.generic.type = MTYPE_BITMAP;
- g_arenaservers.arrows.generic.name = ART_ARROWS0;
- g_arenaservers.arrows.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- g_arenaservers.arrows.generic.callback = ArenaServers_Event;
- g_arenaservers.arrows.generic.x = 512+48+12;
- g_arenaservers.arrows.generic.y = 240-64+48;
- g_arenaservers.arrows.width = 64;
- g_arenaservers.arrows.height = 128;
-
- g_arenaservers.up.generic.type = MTYPE_BITMAP;
- g_arenaservers.up.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
- g_arenaservers.up.generic.callback = ArenaServers_Event;
- g_arenaservers.up.generic.id = ID_SCROLL_UP;
- g_arenaservers.up.generic.x = 512+48+12;
- g_arenaservers.up.generic.y = 240-64+48;
- g_arenaservers.up.width = 64;
- g_arenaservers.up.height = 64;
- g_arenaservers.up.focuspic = ART_ARROWS_UP;
-
- g_arenaservers.down.generic.type = MTYPE_BITMAP;
- g_arenaservers.down.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_MOUSEONLY;
- g_arenaservers.down.generic.callback = ArenaServers_Event;
- g_arenaservers.down.generic.id = ID_SCROLL_DOWN;
- g_arenaservers.down.generic.x = 512+48+12;
- g_arenaservers.down.generic.y = 240+48;
- g_arenaservers.down.width = 64;
- g_arenaservers.down.height = 64;
- g_arenaservers.down.focuspic = ART_ARROWS_DOWN;
-
- y = 376;
- g_arenaservers.status.generic.type = MTYPE_TEXT;
- g_arenaservers.status.generic.x = 320;
- g_arenaservers.status.generic.y = y;
- g_arenaservers.status.string = statusbuffer;
- g_arenaservers.status.style = UI_CENTER|UI_SMALLFONT;
- g_arenaservers.status.color = menu_text_color;
-
- y += SMALLCHAR_HEIGHT;
- g_arenaservers.statusbar.generic.type = MTYPE_TEXT;
- g_arenaservers.statusbar.generic.x = 320;
- g_arenaservers.statusbar.generic.y = y;
- g_arenaservers.statusbar.string = "";
- g_arenaservers.statusbar.style = UI_CENTER|UI_SMALLFONT;
- g_arenaservers.statusbar.color = text_color_normal;
-
- g_arenaservers.remove.generic.type = MTYPE_BITMAP;
- g_arenaservers.remove.generic.name = ART_REMOVE0;
- g_arenaservers.remove.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- g_arenaservers.remove.generic.callback = ArenaServers_Event;
- g_arenaservers.remove.generic.id = ID_REMOVE;
- g_arenaservers.remove.generic.x = 450;
- g_arenaservers.remove.generic.y = 86;
- g_arenaservers.remove.width = 96;
- g_arenaservers.remove.height = 48;
- g_arenaservers.remove.focuspic = ART_REMOVE1;
-
- g_arenaservers.back.generic.type = MTYPE_BITMAP;
- g_arenaservers.back.generic.name = ART_BACK0;
- g_arenaservers.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- g_arenaservers.back.generic.callback = ArenaServers_Event;
- g_arenaservers.back.generic.id = ID_BACK;
- g_arenaservers.back.generic.x = 0;
- g_arenaservers.back.generic.y = 480-64;
- g_arenaservers.back.width = 128;
- g_arenaservers.back.height = 64;
- g_arenaservers.back.focuspic = ART_BACK1;
-
- g_arenaservers.specify.generic.type = MTYPE_BITMAP;
- g_arenaservers.specify.generic.name = ART_SPECIFY0;
- g_arenaservers.specify.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- g_arenaservers.specify.generic.callback = ArenaServers_Event;
- g_arenaservers.specify.generic.id = ID_SPECIFY;
- g_arenaservers.specify.generic.x = 128;
- g_arenaservers.specify.generic.y = 480-64;
- g_arenaservers.specify.width = 128;
- g_arenaservers.specify.height = 64;
- g_arenaservers.specify.focuspic = ART_SPECIFY1;
-
- g_arenaservers.refresh.generic.type = MTYPE_BITMAP;
- g_arenaservers.refresh.generic.name = ART_REFRESH0;
- g_arenaservers.refresh.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- g_arenaservers.refresh.generic.callback = ArenaServers_Event;
- g_arenaservers.refresh.generic.id = ID_REFRESH;
- g_arenaservers.refresh.generic.x = 256;
- g_arenaservers.refresh.generic.y = 480-64;
- g_arenaservers.refresh.width = 128;
- g_arenaservers.refresh.height = 64;
- g_arenaservers.refresh.focuspic = ART_REFRESH1;
-
- g_arenaservers.create.generic.type = MTYPE_BITMAP;
- g_arenaservers.create.generic.name = ART_CREATE0;
- g_arenaservers.create.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- g_arenaservers.create.generic.callback = ArenaServers_Event;
- g_arenaservers.create.generic.id = ID_CREATE;
- g_arenaservers.create.generic.x = 384;
- g_arenaservers.create.generic.y = 480-64;
- g_arenaservers.create.width = 128;
- g_arenaservers.create.height = 64;
- g_arenaservers.create.focuspic = ART_CREATE1;
-
- g_arenaservers.go.generic.type = MTYPE_BITMAP;
- g_arenaservers.go.generic.name = ART_CONNECT0;
- g_arenaservers.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- g_arenaservers.go.generic.callback = ArenaServers_Event;
- g_arenaservers.go.generic.id = ID_CONNECT;
- g_arenaservers.go.generic.x = 640;
- g_arenaservers.go.generic.y = 480-64;
- g_arenaservers.go.width = 128;
- g_arenaservers.go.height = 64;
- g_arenaservers.go.focuspic = ART_CONNECT1;
-
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.banner );
-
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.master );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.gametype );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.sortkey );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.showfull);
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.showempty );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.onlyhumans );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.hideprivate );
-
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.mappic );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.list );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.status );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.statusbar );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.arrows );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.up );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.down );
-
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.remove );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.back );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.specify );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.refresh );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.create );
- Menu_AddItem( &g_arenaservers.menu, (void*) &g_arenaservers.go );
-
- ArenaServers_LoadFavorites();
-
- g_servertype = Com_Clamp( 0, 3, ui_browserMaster.integer );
- // hack to get rid of MPlayer stuff
- value = g_servertype;
- if (value >= 1)
- value--;
- g_arenaservers.master.curvalue = value;
-
- g_gametype = Com_Clamp( 0, 12, ui_browserGameType.integer );
- g_arenaservers.gametype.curvalue = g_gametype;
-
- g_sortkey = Com_Clamp( 0, 4, ui_browserSortKey.integer );
- g_arenaservers.sortkey.curvalue = g_sortkey;
-
- g_fullservers = Com_Clamp( 0, 1, ui_browserShowFull.integer );
- g_arenaservers.showfull.curvalue = g_fullservers;
-
- g_emptyservers = Com_Clamp( 0, 1, ui_browserShowEmpty.integer );
- g_arenaservers.showempty.curvalue = g_emptyservers;
-
- g_arenaservers.onlyhumans.curvalue = Com_Clamp( 0, 1, ui_browserOnlyHumans.integer );
- g_onlyhumans = ui_browserOnlyHumans.integer;
-
- g_arenaservers.hideprivate.curvalue = 1; //Com_Clamp( 0, 1, ui_browserOnlyHumans.integer );
- g_hideprivate = 1; //ui_browserOnlyHumans.integer;
-
- // force to initial state and refresh
- g_arenaservers.master.curvalue = g_servertype = ArenaServers_SetType(g_servertype);
-
- trap_Cvar_Register(NULL, "debug_protocol", "", 0 );
-}
-
-
-/*
-=================
-ArenaServers_Cache
-=================
-*/
-void ArenaServers_Cache( void ) {
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_CREATE0 );
- trap_R_RegisterShaderNoMip( ART_CREATE1 );
- trap_R_RegisterShaderNoMip( ART_SPECIFY0 );
- trap_R_RegisterShaderNoMip( ART_SPECIFY1 );
- trap_R_RegisterShaderNoMip( ART_REFRESH0 );
- trap_R_RegisterShaderNoMip( ART_REFRESH1 );
- trap_R_RegisterShaderNoMip( ART_CONNECT0 );
- trap_R_RegisterShaderNoMip( ART_CONNECT1 );
- trap_R_RegisterShaderNoMip( ART_ARROWS0 );
- trap_R_RegisterShaderNoMip( ART_ARROWS_UP );
- trap_R_RegisterShaderNoMip( ART_ARROWS_DOWN );
- trap_R_RegisterShaderNoMip( ART_UNKNOWNMAP );
-}
-
-
-/*
-=================
-UI_ArenaServersMenu
-=================
-*/
-void UI_ArenaServersMenu( void ) {
- ArenaServers_MenuInit();
- UI_PushMenu( &g_arenaservers.menu );
-}
diff --git a/game/code/q3_ui/ui_sparena.c b/game/code/q3_ui/ui_sparena.c
deleted file mode 100644
index 157670e..0000000
--- a/game/code/q3_ui/ui_sparena.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-void UI_SPArena_Start( const char *arenaInfo ) {
- char *map;
- int level;
- int n;
- char *txt;
-
- n = (int)trap_Cvar_VariableValue( "sv_maxclients" );
- if ( n < 8 ) {
- trap_Cvar_SetValue( "sv_maxclients", 8 );
- }
-
- level = atoi( Info_ValueForKey( arenaInfo, "num" ) );
- txt = Info_ValueForKey( arenaInfo, "special" );
- if( txt[0] ) {
- if( Q_stricmp( txt, "training" ) == 0 ) {
- level = -4;
- }
- else if( Q_stricmp( txt, "final" ) == 0 ) {
- level = UI_GetNumSPTiers() * ARENAS_PER_TIER;
- }
- }
- trap_Cvar_SetValue( "ui_spSelection", level );
-
- map = Info_ValueForKey( arenaInfo, "map" );
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "spmap %s\n", map ) );
-}
diff --git a/game/code/q3_ui/ui_splevel.c b/game/code/q3_ui/ui_splevel.c
deleted file mode 100644
index ce06b9d..0000000
--- a/game/code/q3_ui/ui_splevel.c
+++ /dev/null
@@ -1,1011 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=============================================================================
-
-SINGLE PLAYER LEVEL SELECT MENU
-
-=============================================================================
-*/
-
-#include "ui_local.h"
-
-
-#define ART_LEVELFRAME_FOCUS "menu/art_blueish/maps_select"
-#define ART_LEVELFRAME_SELECTED "menu/art_blueish/maps_selected"
-#define ART_ARROW "menu/art_blueish/narrow_0"
-#define ART_ARROW_FOCUS "menu/art_blueish/narrow_1"
-#define ART_MAP_UNKNOWN "menu/art/unknownmap"
-#define ART_MAP_COMPLETE1 "menu/art/level_complete1"
-#define ART_MAP_COMPLETE2 "menu/art/level_complete2"
-#define ART_MAP_COMPLETE3 "menu/art/level_complete3"
-#define ART_MAP_COMPLETE4 "menu/art/level_complete4"
-#define ART_MAP_COMPLETE5 "menu/art/level_complete5"
-#define ART_BACK0 "menu/art_blueish/back_0"
-#define ART_BACK1 "menu/art_blueish/back_1"
-#define ART_FIGHT0 "menu/art_blueish/fight_0"
-#define ART_FIGHT1 "menu/art_blueish/fight_1"
-#define ART_RESET0 "menu/art_blueish/reset_0"
-#define ART_RESET1 "menu/art_blueish/reset_1"
-#define ART_CUSTOM0 "menu/art_blueish/skirmish_0"
-#define ART_CUSTOM1 "menu/art_blueish/skirmish_1"
-
-#define ID_LEFTARROW 10
-#define ID_PICTURE0 11
-#define ID_PICTURE1 12
-#define ID_PICTURE2 13
-#define ID_PICTURE3 14
-#define ID_RIGHTARROW 15
-#define ID_PLAYERPIC 16
-#define ID_AWARD1 17
-#define ID_AWARD2 18
-#define ID_AWARD3 19
-#define ID_AWARD4 20
-#define ID_AWARD5 21
-#define ID_AWARD6 22
-#define ID_BACK 23
-#define ID_RESET 24
-#define ID_CUSTOM 25
-#define ID_NEXT 26
-
-#define PLAYER_Y 314
-#define AWARDS_Y (PLAYER_Y + 26)
-
-
-typedef struct {
- menuframework_s menu;
- menutext_s item_banner;
- menubitmap_s item_leftarrow;
- menubitmap_s item_maps[4];
- menubitmap_s item_rightarrow;
- menubitmap_s item_player;
- menubitmap_s item_awards[6];
- menubitmap_s item_back;
- menubitmap_s item_reset;
- menubitmap_s item_custom;
- menubitmap_s item_next;
- menubitmap_s item_null;
-
- qboolean reinit;
-
- const char * selectedArenaInfo;
- int numMaps;
- char levelPicNames[4][MAX_QPATH];
- char levelNames[4][16];
- int levelScores[4];
- int levelScoresSkill[4];
- qhandle_t levelSelectedPic;
- qhandle_t levelFocusPic;
- qhandle_t levelCompletePic[5];
-
- char playerModel[MAX_QPATH];
- char playerPicName[MAX_QPATH];
- int awardLevels[6];
- sfxHandle_t awardSounds[6];
-
- int numBots;
- qhandle_t botPics[7];
- char botNames[7][10];
-} levelMenuInfo_t;
-
-static levelMenuInfo_t levelMenuInfo;
-
-static int selectedArenaSet;
-static int selectedArena;
-static int currentSet;
-static int currentGame;
-static int trainingTier;
-static int finalTier;
-static int minTier;
-static int maxTier;
-
-
-/*
-=================
-PlayerIcon
-=================
-*/
-static void PlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize ) {
- char *skin;
- char model[MAX_QPATH];
-
- Q_strncpyz( model, modelAndSkin, sizeof(model));
- skin = Q_strrchr( model, '/' );
- if ( skin ) {
- *skin++ = '\0';
- }
- else {
- skin = "default";
- }
-
- Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_%s.tga", model, skin );
-
- if( !trap_R_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, "default" ) != 0 ) {
- Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_default.tga", model );
- }
-}
-
-
-/*
-=================
-PlayerIconhandle
-=================
-*/
-static qhandle_t PlayerIconHandle( const char *modelAndSkin ) {
- char iconName[MAX_QPATH];
-
- PlayerIcon( modelAndSkin, iconName, sizeof(iconName) );
- return trap_R_RegisterShaderNoMip( iconName );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_SetBots
-=================
-*/
-static void UI_SPLevelMenu_SetBots( void ) {
- char *p;
- char *bot;
- char *botInfo;
- char bots[MAX_INFO_STRING];
-
- levelMenuInfo.numBots = 0;
- if ( selectedArenaSet > currentSet ) {
- return;
- }
-
- Q_strncpyz( bots, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "bots" ), sizeof(bots) );
-
- p = &bots[0];
- while( *p && levelMenuInfo.numBots < 7 ) {
- //skip spaces
- while( *p && *p == ' ' ) {
- p++;
- }
- if( !p ) {
- break;
- }
-
- // mark start of bot name
- bot = p;
-
- // skip until space of null
- while( *p && *p != ' ' ) {
- p++;
- }
- if( *p ) {
- *p++ = 0;
- }
-
- botInfo = UI_GetBotInfoByName( bot );
- if( !botInfo ) {
- botInfo = UI_GetBotInfoByNumber( levelMenuInfo.numBots );
- }
- if( botInfo ) {
- levelMenuInfo.botPics[levelMenuInfo.numBots] = PlayerIconHandle( Info_ValueForKey( botInfo, "model" ) );
- Q_strncpyz( levelMenuInfo.botNames[levelMenuInfo.numBots], Info_ValueForKey( botInfo, "name" ), 10 );
- }
- else {
- levelMenuInfo.botPics[levelMenuInfo.numBots] = 0;
- Q_strncpyz( levelMenuInfo.botNames[levelMenuInfo.numBots], bot, 10 );
- }
- Q_CleanStr( levelMenuInfo.botNames[levelMenuInfo.numBots] );
- levelMenuInfo.numBots++;
- }
-}
-
-
-/*
-=================
-UI_SPLevelMenu_SetMenuItems
-=================
-*/
-static void UI_SPLevelMenu_SetMenuArena( int n, int level, const char *arenaInfo ) {
- char map[MAX_QPATH];
-
- Q_strncpyz( map, Info_ValueForKey( arenaInfo, "map" ), sizeof(map) );
-
- Q_strncpyz( levelMenuInfo.levelNames[n], map, sizeof(levelMenuInfo.levelNames[n]) );
- Q_strupr( levelMenuInfo.levelNames[n] );
-
- UI_GetBestScore( level, &levelMenuInfo.levelScores[n], &levelMenuInfo.levelScoresSkill[n] );
- if( levelMenuInfo.levelScores[n] > 8 ) {
- levelMenuInfo.levelScores[n] = 8;
- }
-
- strcpy( levelMenuInfo.levelPicNames[n], va( "levelshots/%s.tga", map ) );
- if( !trap_R_RegisterShaderNoMip( levelMenuInfo.levelPicNames[n] ) ) {
- strcpy( levelMenuInfo.levelPicNames[n], ART_MAP_UNKNOWN );
- }
- levelMenuInfo.item_maps[n].shader = 0;
- if ( selectedArenaSet > currentSet ) {
- levelMenuInfo.item_maps[n].generic.flags |= QMF_GRAYED;
- }
- else {
- levelMenuInfo.item_maps[n].generic.flags &= ~QMF_GRAYED;
- }
-
- levelMenuInfo.item_maps[n].generic.flags &= ~QMF_INACTIVE;
-}
-
-static void UI_SPLevelMenu_SetMenuItems( void ) {
- int n;
- int level;
- const char *arenaInfo;
-
- if ( selectedArenaSet > currentSet ) {
- selectedArena = -1;
- }
- else if ( selectedArena == -1 ) {
- selectedArena = 0;
- }
-
- if( selectedArenaSet == trainingTier || selectedArenaSet == finalTier ) {
- selectedArena = 0;
- }
-
- if( selectedArena != -1 ) {
- trap_Cvar_SetValue( "ui_spSelection", selectedArenaSet * ARENAS_PER_TIER + selectedArena );
- }
-
- if( selectedArenaSet == trainingTier ) {
- arenaInfo = UI_GetSpecialArenaInfo( "training" );
- level = atoi( Info_ValueForKey( arenaInfo, "num" ) );
- UI_SPLevelMenu_SetMenuArena( 0, level, arenaInfo );
- levelMenuInfo.selectedArenaInfo = arenaInfo;
-
- levelMenuInfo.item_maps[0].generic.x = 256;
- Bitmap_Init( &levelMenuInfo.item_maps[0] );
- levelMenuInfo.item_maps[0].generic.bottom += 32;
- levelMenuInfo.numMaps = 1;
-
- levelMenuInfo.item_maps[1].generic.flags |= QMF_INACTIVE;
- levelMenuInfo.item_maps[2].generic.flags |= QMF_INACTIVE;
- levelMenuInfo.item_maps[3].generic.flags |= QMF_INACTIVE;
- levelMenuInfo.levelPicNames[1][0] = 0;
- levelMenuInfo.levelPicNames[2][0] = 0;
- levelMenuInfo.levelPicNames[3][0] = 0;
- levelMenuInfo.item_maps[1].shader = 0;
- levelMenuInfo.item_maps[2].shader = 0;
- levelMenuInfo.item_maps[3].shader = 0;
- }
- else if( selectedArenaSet == finalTier ) {
- arenaInfo = UI_GetSpecialArenaInfo( "final" );
- level = atoi( Info_ValueForKey( arenaInfo, "num" ) );
- UI_SPLevelMenu_SetMenuArena( 0, level, arenaInfo );
- levelMenuInfo.selectedArenaInfo = arenaInfo;
-
- levelMenuInfo.item_maps[0].generic.x = 256;
- Bitmap_Init( &levelMenuInfo.item_maps[0] );
- levelMenuInfo.item_maps[0].generic.bottom += 32;
- levelMenuInfo.numMaps = 1;
-
- levelMenuInfo.item_maps[1].generic.flags |= QMF_INACTIVE;
- levelMenuInfo.item_maps[2].generic.flags |= QMF_INACTIVE;
- levelMenuInfo.item_maps[3].generic.flags |= QMF_INACTIVE;
- levelMenuInfo.levelPicNames[1][0] = 0;
- levelMenuInfo.levelPicNames[2][0] = 0;
- levelMenuInfo.levelPicNames[3][0] = 0;
- levelMenuInfo.item_maps[1].shader = 0;
- levelMenuInfo.item_maps[2].shader = 0;
- levelMenuInfo.item_maps[3].shader = 0;
- }
- else {
- levelMenuInfo.item_maps[0].generic.x = 46;
- Bitmap_Init( &levelMenuInfo.item_maps[0] );
- levelMenuInfo.item_maps[0].generic.bottom += 18;
- levelMenuInfo.numMaps = 4;
-
- for ( n = 0; n < 4; n++ ) {
- level = selectedArenaSet * ARENAS_PER_TIER + n;
- arenaInfo = UI_GetArenaInfoByNumber( level );
- UI_SPLevelMenu_SetMenuArena( n, level, arenaInfo );
- }
-
- if( selectedArena != -1 ) {
- levelMenuInfo.selectedArenaInfo = UI_GetArenaInfoByNumber( selectedArenaSet * ARENAS_PER_TIER + selectedArena );
- }
- }
-
- // enable/disable arrows when they are valid/invalid
- if ( selectedArenaSet == minTier ) {
- levelMenuInfo.item_leftarrow.generic.flags |= ( QMF_INACTIVE | QMF_HIDDEN );
- }
- else {
- levelMenuInfo.item_leftarrow.generic.flags &= ~( QMF_INACTIVE | QMF_HIDDEN );
- }
-
- if ( selectedArenaSet == maxTier ) {
- levelMenuInfo.item_rightarrow.generic.flags |= ( QMF_INACTIVE | QMF_HIDDEN );
- }
- else {
- levelMenuInfo.item_rightarrow.generic.flags &= ~( QMF_INACTIVE | QMF_HIDDEN );
- }
-
- UI_SPLevelMenu_SetBots();
-}
-
-
-/*
-=================
-UI_SPLevelMenu_ResetEvent
-=================
-*/
-static void UI_SPLevelMenu_ResetDraw( void ) {
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 0, "WARNING: This resets all of the", UI_CENTER|UI_SMALLFONT, color_yellow );
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 1, "single player game variables.", UI_CENTER|UI_SMALLFONT, color_yellow );
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 2, "Do this only if you want to", UI_CENTER|UI_SMALLFONT, color_yellow );
- UI_DrawProportionalString( SCREEN_WIDTH/2, 356 + PROP_HEIGHT * 3, "start over from the beginning.", UI_CENTER|UI_SMALLFONT, color_yellow );
-}
-
-static void UI_SPLevelMenu_ResetAction( qboolean result ) {
- if( !result ) {
- return;
- }
-
- // clear game variables
- UI_NewGame();
- trap_Cvar_SetValue( "ui_spSelection", -4 );
-
- // make the level select menu re-initialize
- UI_PopMenu();
- UI_SPLevelMenu();
-}
-
-static void UI_SPLevelMenu_ResetEvent( void* ptr, int event )
-{
- if (event != QM_ACTIVATED) {
- return;
- }
-
- UI_ConfirmMenu( "RESET GAME?", UI_SPLevelMenu_ResetDraw, UI_SPLevelMenu_ResetAction );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_LevelEvent
-=================
-*/
-static void UI_SPLevelMenu_LevelEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- if ( selectedArenaSet == trainingTier || selectedArenaSet == finalTier ) {
- return;
- }
-
- selectedArena = ((menucommon_s*)ptr)->id - ID_PICTURE0;
- levelMenuInfo.selectedArenaInfo = UI_GetArenaInfoByNumber( selectedArenaSet * ARENAS_PER_TIER + selectedArena );
- UI_SPLevelMenu_SetBots();
-
- trap_Cvar_SetValue( "ui_spSelection", selectedArenaSet * ARENAS_PER_TIER + selectedArena );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_LeftArrowEvent
-=================
-*/
-static void UI_SPLevelMenu_LeftArrowEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- if ( selectedArenaSet == minTier ) {
- return;
- }
-
- selectedArenaSet--;
- UI_SPLevelMenu_SetMenuItems();
-}
-
-
-/*
-=================
-UI_SPLevelMenu_RightArrowEvent
-=================
-*/
-static void UI_SPLevelMenu_RightArrowEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- if ( selectedArenaSet == maxTier ) {
- return;
- }
-
- selectedArenaSet++;
- UI_SPLevelMenu_SetMenuItems();
-}
-
-
-/*
-=================
-UI_SPLevelMenu_PlayerEvent
-=================
-*/
-static void UI_SPLevelMenu_PlayerEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- UI_PlayerSettingsMenu();
-}
-
-
-/*
-=================
-UI_SPLevelMenu_AwardEvent
-=================
-*/
-static void UI_SPLevelMenu_AwardEvent( void* ptr, int notification ) {
- int n;
-
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- n = ((menucommon_s*)ptr)->id - ID_AWARD1;
- trap_S_StartLocalSound( levelMenuInfo.awardSounds[n], CHAN_ANNOUNCER );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_NextEvent
-=================
-*/
-static void UI_SPLevelMenu_NextEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- if ( selectedArenaSet > currentSet ) {
- return;
- }
-
- if ( selectedArena == -1 ) {
- selectedArena = 0;
- }
-
- UI_SPSkillMenu( levelMenuInfo.selectedArenaInfo );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_BackEvent
-=================
-*/
-static void UI_SPLevelMenu_BackEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- if ( selectedArena == -1 ) {
- selectedArena = 0;
- }
-
- UI_PopMenu();
-}
-
-
-/*
-=================
-UI_SPLevelMenu_CustomEvent
-=================
-*/
-static void UI_SPLevelMenu_CustomEvent( void* ptr, int notification ) {
- if (notification != QM_ACTIVATED) {
- return;
- }
-
- UI_StartServerMenu( qfalse );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_MenuDraw
-=================
-*/
-#define LEVEL_DESC_LEFT_MARGIN 332
-
-static void UI_SPLevelMenu_MenuDraw( void ) {
- int n, i;
- int x, y;
- vec4_t color;
- int level;
-// int fraglimit;
- int pad;
- char buf[MAX_INFO_VALUE];
- char string[64];
-
- if( levelMenuInfo.reinit ) {
- UI_PopMenu();
- UI_SPLevelMenu();
- return;
- }
-
- // draw player name
- trap_Cvar_VariableStringBuffer( "name", string, 32 );
- Q_CleanStr( string );
- UI_DrawProportionalString( 320, PLAYER_Y, string, UI_CENTER|UI_SMALLFONT, color_orange );
-
- // check for model changes
- trap_Cvar_VariableStringBuffer( "model", buf, sizeof(buf) );
- if( Q_stricmp( buf, levelMenuInfo.playerModel ) != 0 ) {
- Q_strncpyz( levelMenuInfo.playerModel, buf, sizeof(levelMenuInfo.playerModel) );
- PlayerIcon( levelMenuInfo.playerModel, levelMenuInfo.playerPicName, sizeof(levelMenuInfo.playerPicName) );
- levelMenuInfo.item_player.shader = 0;
- }
-
- // standard menu drawing
- Menu_Draw( &levelMenuInfo.menu );
-
- // draw player award levels
- y = AWARDS_Y;
- i = 0;
- for( n = 0; n < 6; n++ ) {
- level = levelMenuInfo.awardLevels[n];
- if( level > 0 ) {
- if( i & 1 ) {
- x = 224 - (i - 1 ) / 2 * (48 + 16);
- }
- else {
- x = 368 + i / 2 * (48 + 16);
- }
- i++;
-
- if( level == 1 ) {
- continue;
- }
-
- if( level >= 1000000 ) {
- Com_sprintf( string, sizeof(string), "%im", level / 1000000 );
- }
- else if( level >= 1000 ) {
- Com_sprintf( string, sizeof(string), "%ik", level / 1000 );
- }
- else {
- Com_sprintf( string, sizeof(string), "%i", level );
- }
-
- UI_DrawString( x + 24, y + 48, string, UI_CENTER, color_yellow );
- }
- }
-
- UI_DrawProportionalString( 18, 38, va( "Tier %i", selectedArenaSet + 1 ), UI_LEFT|UI_SMALLFONT, color_orange );
-
- for ( n = 0; n < levelMenuInfo.numMaps; n++ ) {
- x = levelMenuInfo.item_maps[n].generic.x;
- y = levelMenuInfo.item_maps[n].generic.y;
- UI_FillRect( x, y + 96, 128, 18, color_black );
- }
-
- if ( selectedArenaSet > currentSet ) {
- UI_DrawProportionalString( 320, 216, "ACCESS DENIED", UI_CENTER|UI_BIGFONT, color_red );
- return;
- }
-
- // show levelshots for levels of current tier
- Vector4Copy( color_white, color );
- color[3] = 0.5+0.5*sin(uis.realtime/PULSE_DIVISOR);
- for ( n = 0; n < levelMenuInfo.numMaps; n++ ) {
- x = levelMenuInfo.item_maps[n].generic.x;
- y = levelMenuInfo.item_maps[n].generic.y;
-
- UI_DrawString( x + 64, y + 96, levelMenuInfo.levelNames[n], UI_CENTER|UI_SMALLFONT, color_orange );
-
- if( levelMenuInfo.levelScores[n] == 1 ) {
- UI_DrawHandlePic( x, y, 128, 96, levelMenuInfo.levelCompletePic[levelMenuInfo.levelScoresSkill[n] - 1] );
- }
-
- if ( n == selectedArena ) {
- if( Menu_ItemAtCursor( &levelMenuInfo.menu ) == &levelMenuInfo.item_maps[n] ) {
- trap_R_SetColor( color );
- }
- UI_DrawHandlePic( x-1, y-1, 130, 130 - 14, levelMenuInfo.levelSelectedPic );
- trap_R_SetColor( NULL );
- }
- else if( Menu_ItemAtCursor( &levelMenuInfo.menu ) == &levelMenuInfo.item_maps[n] ) {
- trap_R_SetColor( color );
- UI_DrawHandlePic( x-31, y-30, 256, 256-27, levelMenuInfo.levelFocusPic);
- trap_R_SetColor( NULL );
- }
- }
-
- // show map name and long name of selected level
- y = 192;
- Q_strncpyz( buf, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "map" ), 20 );
- Q_strupr( buf );
- Com_sprintf( string, sizeof(string), "%s: %s", buf, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "longname" ) );
- UI_DrawProportionalString( 320, y, string, UI_CENTER|UI_SMALLFONT, color_orange );
-
-// fraglimit = atoi( Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "fraglimit" ) );
-// UI_DrawString( 18, 212, va("Frags %i", fraglimit) , UI_LEFT|UI_SMALLFONT, color_orange );
-
- // draw bot opponents
- y += 24;
- pad = (7 - levelMenuInfo.numBots) * (64 + 26) / 2;
- for( n = 0; n < levelMenuInfo.numBots; n++ ) {
- x = 18 + pad + (64 + 26) * n;
- if( levelMenuInfo.botPics[n] ) {
- UI_DrawHandlePic( x, y, 64, 64, levelMenuInfo.botPics[n]);
- }
- else {
- UI_FillRect( x, y, 64, 64, color_black );
- UI_DrawProportionalString( x+22, y+18, "?", UI_BIGFONT, color_orange );
- }
- UI_DrawString( x, y + 64, levelMenuInfo.botNames[n], UI_SMALLFONT|UI_LEFT, color_orange );
- }
-}
-
-
-/*
-=================
-UI_SPLevelMenu_Cache
-=================
-*/
-void UI_SPLevelMenu_Cache( void ) {
- int n;
-
- trap_R_RegisterShaderNoMip( ART_LEVELFRAME_FOCUS );
- trap_R_RegisterShaderNoMip( ART_LEVELFRAME_SELECTED );
- trap_R_RegisterShaderNoMip( ART_ARROW );
- trap_R_RegisterShaderNoMip( ART_ARROW_FOCUS );
- trap_R_RegisterShaderNoMip( ART_MAP_UNKNOWN );
- trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE1 );
- trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE2 );
- trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE3 );
- trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE4 );
- trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE5 );
- trap_R_RegisterShaderNoMip( ART_BACK0 );
- trap_R_RegisterShaderNoMip( ART_BACK1 );
- trap_R_RegisterShaderNoMip( ART_FIGHT0 );
- trap_R_RegisterShaderNoMip( ART_FIGHT1 );
- trap_R_RegisterShaderNoMip( ART_RESET0 );
- trap_R_RegisterShaderNoMip( ART_RESET1 );
- trap_R_RegisterShaderNoMip( ART_CUSTOM0 );
- trap_R_RegisterShaderNoMip( ART_CUSTOM1 );
-
- for( n = 0; n < 6; n++ ) {
- trap_R_RegisterShaderNoMip( ui_medalPicNames[n] );
- levelMenuInfo.awardSounds[n] = trap_S_RegisterSound( ui_medalSounds[n], qfalse );
- }
-
- levelMenuInfo.levelSelectedPic = trap_R_RegisterShaderNoMip( ART_LEVELFRAME_SELECTED );
- levelMenuInfo.levelFocusPic = trap_R_RegisterShaderNoMip( ART_LEVELFRAME_FOCUS );
- levelMenuInfo.levelCompletePic[0] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE1 );
- levelMenuInfo.levelCompletePic[1] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE2 );
- levelMenuInfo.levelCompletePic[2] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE3 );
- levelMenuInfo.levelCompletePic[3] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE4 );
- levelMenuInfo.levelCompletePic[4] = trap_R_RegisterShaderNoMip( ART_MAP_COMPLETE5 );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_Init
-=================
-*/
-static void UI_SPLevelMenu_Init( void ) {
- int skill;
- int n;
- int x, y;
- int count;
- char buf[MAX_QPATH];
-
- skill = (int)trap_Cvar_VariableValue( "g_spSkill" );
- if( skill < 1 || skill > 5 ) {
- trap_Cvar_Set( "g_spSkill", "2" );
- skill = 2;
- }
-
- memset( &levelMenuInfo, 0, sizeof(levelMenuInfo) );
- levelMenuInfo.menu.fullscreen = qtrue;
- levelMenuInfo.menu.wrapAround = qtrue;
- levelMenuInfo.menu.draw = UI_SPLevelMenu_MenuDraw;
-
- UI_SPLevelMenu_Cache();
-
- levelMenuInfo.item_banner.generic.type = MTYPE_BTEXT;
- levelMenuInfo.item_banner.generic.x = 320;
- levelMenuInfo.item_banner.generic.y = 16;
- levelMenuInfo.item_banner.string = "CHOOSE LEVEL";
- levelMenuInfo.item_banner.color = color_red;
- levelMenuInfo.item_banner.style = UI_CENTER;
-
- levelMenuInfo.item_leftarrow.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_leftarrow.generic.name = ART_ARROW;
- levelMenuInfo.item_leftarrow.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- levelMenuInfo.item_leftarrow.generic.x = 18;
- levelMenuInfo.item_leftarrow.generic.y = 64;
- levelMenuInfo.item_leftarrow.generic.callback = UI_SPLevelMenu_LeftArrowEvent;
- levelMenuInfo.item_leftarrow.generic.id = ID_LEFTARROW;
- levelMenuInfo.item_leftarrow.width = 16;
- levelMenuInfo.item_leftarrow.height = 114;
- levelMenuInfo.item_leftarrow.focuspic = ART_ARROW_FOCUS;
-
- levelMenuInfo.item_maps[0].generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_maps[0].generic.name = levelMenuInfo.levelPicNames[0];
- levelMenuInfo.item_maps[0].generic.flags = QMF_LEFT_JUSTIFY;
- levelMenuInfo.item_maps[0].generic.x = 46;
- levelMenuInfo.item_maps[0].generic.y = 64;
- levelMenuInfo.item_maps[0].generic.id = ID_PICTURE0;
- levelMenuInfo.item_maps[0].generic.callback = UI_SPLevelMenu_LevelEvent;
- levelMenuInfo.item_maps[0].width = 128;
- levelMenuInfo.item_maps[0].height = 96;
-
- levelMenuInfo.item_maps[1].generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_maps[1].generic.name = levelMenuInfo.levelPicNames[1];
- levelMenuInfo.item_maps[1].generic.flags = QMF_LEFT_JUSTIFY;
- levelMenuInfo.item_maps[1].generic.x = 186;
- levelMenuInfo.item_maps[1].generic.y = 64;
- levelMenuInfo.item_maps[1].generic.id = ID_PICTURE1;
- levelMenuInfo.item_maps[1].generic.callback = UI_SPLevelMenu_LevelEvent;
- levelMenuInfo.item_maps[1].width = 128;
- levelMenuInfo.item_maps[1].height = 96;
-
- levelMenuInfo.item_maps[2].generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_maps[2].generic.name = levelMenuInfo.levelPicNames[2];
- levelMenuInfo.item_maps[2].generic.flags = QMF_LEFT_JUSTIFY;
- levelMenuInfo.item_maps[2].generic.x = 326;
- levelMenuInfo.item_maps[2].generic.y = 64;
- levelMenuInfo.item_maps[2].generic.id = ID_PICTURE2;
- levelMenuInfo.item_maps[2].generic.callback = UI_SPLevelMenu_LevelEvent;
- levelMenuInfo.item_maps[2].width = 128;
- levelMenuInfo.item_maps[2].height = 96;
-
- levelMenuInfo.item_maps[3].generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_maps[3].generic.name = levelMenuInfo.levelPicNames[3];
- levelMenuInfo.item_maps[3].generic.flags = QMF_LEFT_JUSTIFY;
- levelMenuInfo.item_maps[3].generic.x = 466;
- levelMenuInfo.item_maps[3].generic.y = 64;
- levelMenuInfo.item_maps[3].generic.id = ID_PICTURE3;
- levelMenuInfo.item_maps[3].generic.callback = UI_SPLevelMenu_LevelEvent;
- levelMenuInfo.item_maps[3].width = 128;
- levelMenuInfo.item_maps[3].height = 96;
-
- levelMenuInfo.item_rightarrow.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_rightarrow.generic.name = ART_ARROW;
- levelMenuInfo.item_rightarrow.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- levelMenuInfo.item_rightarrow.generic.x = 606;
- levelMenuInfo.item_rightarrow.generic.y = 64;
- levelMenuInfo.item_rightarrow.generic.callback = UI_SPLevelMenu_RightArrowEvent;
- levelMenuInfo.item_rightarrow.generic.id = ID_RIGHTARROW;
- levelMenuInfo.item_rightarrow.width = -16;
- levelMenuInfo.item_rightarrow.height = 114;
- levelMenuInfo.item_rightarrow.focuspic = ART_ARROW_FOCUS;
-
- trap_Cvar_VariableStringBuffer( "model", levelMenuInfo.playerModel, sizeof(levelMenuInfo.playerModel) );
- PlayerIcon( levelMenuInfo.playerModel, levelMenuInfo.playerPicName, sizeof(levelMenuInfo.playerPicName) );
- levelMenuInfo.item_player.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_player.generic.name = levelMenuInfo.playerPicName;
- levelMenuInfo.item_player.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY;
- levelMenuInfo.item_player.generic.x = 288;
- levelMenuInfo.item_player.generic.y = AWARDS_Y;
- levelMenuInfo.item_player.generic.id = ID_PLAYERPIC;
- levelMenuInfo.item_player.generic.callback = UI_SPLevelMenu_PlayerEvent;
- levelMenuInfo.item_player.width = 64;
- levelMenuInfo.item_player.height = 64;
-
- for( n = 0; n < 6; n++ ) {
- levelMenuInfo.awardLevels[n] = UI_GetAwardLevel( n );
- }
- levelMenuInfo.awardLevels[AWARD_FRAGS] = 100 * (levelMenuInfo.awardLevels[AWARD_FRAGS] / 100);
-
- y = AWARDS_Y;
- count = 0;
- for( n = 0; n < 6; n++ ) {
- if( levelMenuInfo.awardLevels[n] ) {
- if( count & 1 ) {
- x = 224 - (count - 1 ) / 2 * (48 + 16);
- }
- else {
- x = 368 + count / 2 * (48 + 16);
- }
-
- levelMenuInfo.item_awards[count].generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_awards[count].generic.name = ui_medalPicNames[n];
- levelMenuInfo.item_awards[count].generic.flags = QMF_LEFT_JUSTIFY|QMF_SILENT|QMF_MOUSEONLY;
- levelMenuInfo.item_awards[count].generic.x = x;
- levelMenuInfo.item_awards[count].generic.y = y;
- levelMenuInfo.item_awards[count].generic.id = ID_AWARD1 + n;
- levelMenuInfo.item_awards[count].generic.callback = UI_SPLevelMenu_AwardEvent;
- levelMenuInfo.item_awards[count].width = 48;
- levelMenuInfo.item_awards[count].height = 48;
- count++;
- }
- }
-
- levelMenuInfo.item_back.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_back.generic.name = ART_BACK0;
- levelMenuInfo.item_back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- levelMenuInfo.item_back.generic.x = 0;
- levelMenuInfo.item_back.generic.y = 480-64;
- levelMenuInfo.item_back.generic.callback = UI_SPLevelMenu_BackEvent;
- levelMenuInfo.item_back.generic.id = ID_BACK;
- levelMenuInfo.item_back.width = 128;
- levelMenuInfo.item_back.height = 64;
- levelMenuInfo.item_back.focuspic = ART_BACK1;
-
- levelMenuInfo.item_reset.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_reset.generic.name = ART_RESET0;
- levelMenuInfo.item_reset.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- levelMenuInfo.item_reset.generic.x = 170;
- levelMenuInfo.item_reset.generic.y = 480-64;
- levelMenuInfo.item_reset.generic.callback = UI_SPLevelMenu_ResetEvent;
- levelMenuInfo.item_reset.generic.id = ID_RESET;
- levelMenuInfo.item_reset.width = 128;
- levelMenuInfo.item_reset.height = 64;
- levelMenuInfo.item_reset.focuspic = ART_RESET1;
-
- levelMenuInfo.item_custom.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_custom.generic.name = ART_CUSTOM0;
- levelMenuInfo.item_custom.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- levelMenuInfo.item_custom.generic.x = 342;
- levelMenuInfo.item_custom.generic.y = 480-64;
- levelMenuInfo.item_custom.generic.callback = UI_SPLevelMenu_CustomEvent;
- levelMenuInfo.item_custom.generic.id = ID_CUSTOM;
- levelMenuInfo.item_custom.width = 128;
- levelMenuInfo.item_custom.height = 64;
- levelMenuInfo.item_custom.focuspic = ART_CUSTOM1;
-
- levelMenuInfo.item_next.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_next.generic.name = ART_FIGHT0;
- levelMenuInfo.item_next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- levelMenuInfo.item_next.generic.x = 640;
- levelMenuInfo.item_next.generic.y = 480-64;
- levelMenuInfo.item_next.generic.callback = UI_SPLevelMenu_NextEvent;
- levelMenuInfo.item_next.generic.id = ID_NEXT;
- levelMenuInfo.item_next.width = 128;
- levelMenuInfo.item_next.height = 64;
- levelMenuInfo.item_next.focuspic = ART_FIGHT1;
-
- levelMenuInfo.item_null.generic.type = MTYPE_BITMAP;
- levelMenuInfo.item_null.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;
- levelMenuInfo.item_null.generic.x = 0;
- levelMenuInfo.item_null.generic.y = 0;
- levelMenuInfo.item_null.width = 640;
- levelMenuInfo.item_null.height = 480;
-
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_banner );
-
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_leftarrow );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[0] );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[1] );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[2] );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_maps[3] );
- levelMenuInfo.item_maps[0].generic.bottom += 18;
- levelMenuInfo.item_maps[1].generic.bottom += 18;
- levelMenuInfo.item_maps[2].generic.bottom += 18;
- levelMenuInfo.item_maps[3].generic.bottom += 18;
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_rightarrow );
-
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_player );
-
- for( n = 0; n < count; n++ ) {
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_awards[n] );
- }
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_back );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_reset );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_custom );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_next );
- Menu_AddItem( &levelMenuInfo.menu, &levelMenuInfo.item_null );
-
- trap_Cvar_VariableStringBuffer( "ui_spSelection", buf, sizeof(buf) );
- if( *buf ) {
- n = atoi( buf );
- selectedArenaSet = n / ARENAS_PER_TIER;
- selectedArena = n % ARENAS_PER_TIER;
- }
- else {
- selectedArenaSet = currentSet;
- selectedArena = currentGame;
- }
-
- UI_SPLevelMenu_SetMenuItems();
-}
-
-
-/*
-=================
-UI_SPLevelMenu
-=================
-*/
-void UI_SPLevelMenu( void ) {
- int level;
- int trainingLevel;
- const char *arenaInfo;
-
- trainingTier = -1;
- arenaInfo = UI_GetSpecialArenaInfo( "training" );
- if( arenaInfo ) {
- minTier = trainingTier;
- trainingLevel = atoi( Info_ValueForKey( arenaInfo, "num" ) );
- }
- else {
- minTier = 0;
- trainingLevel = -2;
- }
-
- finalTier = UI_GetNumSPTiers();
- arenaInfo = UI_GetSpecialArenaInfo( "final" );
- if( arenaInfo ) {
- maxTier = finalTier;
- }
- else {
- maxTier = finalTier - 1;
- if( maxTier < minTier ) {
- maxTier = minTier;
- }
- }
-
- level = UI_GetCurrentGame();
- if ( level == -1 ) {
- level = UI_GetNumSPArenas() - 1;
- if( maxTier == finalTier ) {
- level++;
- }
- }
-
- if( level == trainingLevel ) {
- currentSet = -1;
- currentGame = 0;
- }
- else {
- currentSet = level / ARENAS_PER_TIER;
- currentGame = level % ARENAS_PER_TIER;
- }
-
- UI_SPLevelMenu_Init();
- UI_PushMenu( &levelMenuInfo.menu );
- Menu_SetCursorToItem( &levelMenuInfo.menu, &levelMenuInfo.item_next );
-}
-
-
-/*
-=================
-UI_SPLevelMenu_f
-=================
-*/
-void UI_SPLevelMenu_f( void ) {
- trap_Key_SetCatcher( KEYCATCH_UI );
- uis.menusp = 0;
- UI_SPLevelMenu();
-}
-
-
-/*
-=================
-UI_SPLevelMenu_ReInit
-=================
-*/
-void UI_SPLevelMenu_ReInit( void ) {
- levelMenuInfo.reinit = qtrue;
-}
diff --git a/game/code/q3_ui/ui_startserver.c b/game/code/q3_ui/ui_startserver.c
deleted file mode 100644
index 52ddf5f..0000000
--- a/game/code/q3_ui/ui_startserver.c
+++ /dev/null
@@ -1,2329 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=============================================================================
-
-START SERVER MENU *****
-
-=============================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define GAMESERVER_BACK0 "menu/art_blueish/back_0"
-#define GAMESERVER_BACK1 "menu/art_blueish/back_1"
-#define GAMESERVER_NEXT0 "menu/art_blueish/next_0"
-#define GAMESERVER_NEXT1 "menu/art_blueish/next_1"
-#define GAMESERVER_FRAMEL "menu/art_blueish/frame2_l"
-#define GAMESERVER_FRAMER "menu/art_blueish/frame1_r"
-#define GAMESERVER_SELECT "menu/art_blueish/maps_select"
-#define GAMESERVER_SELECTED "menu/art_blueish/maps_selected"
-#define GAMESERVER_FIGHT0 "menu/art_blueish/fight_0"
-#define GAMESERVER_FIGHT1 "menu/art_blueish/fight_1"
-#define GAMESERVER_UNKNOWNMAP "menu/art/unknownmap"
-#define GAMESERVER_ARROWS "menu/art_blueish/gs_arrows_0"
-#define GAMESERVER_ARROWSL "menu/art_blueish/gs_arrows_l"
-#define GAMESERVER_ARROWSR "menu/art_blueish/gs_arrows_r"
-
-#define MAX_MAPROWS 4
-#define MAX_MAPCOLS 2
-#define MAX_MAPSPERPAGE (MAX_MAPROWS * MAX_MAPCOLS)
-
-//#define MAX_SERVERSTEXT 8192
-
-#define MAX_SERVERMAPS MAX_ARENAS
-#define MAX_NAMELENGTH 16
-
-#define ID_GAMETYPE 10
-#define ID_PICTURES 11 // 12, 13, 14, 15, 16, 17, 18
-#define ID_PREVPAGE 19
-#define ID_NEXTPAGE 20
-#define ID_STARTSERVERBACK 21
-#define ID_STARTSERVERNEXT 22
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menulist_s gametype;
- menubitmap_s mappics[MAX_MAPSPERPAGE];
- menubitmap_s mapbuttons[MAX_MAPSPERPAGE];
- menubitmap_s arrows;
- menubitmap_s prevpage;
- menubitmap_s nextpage;
- menubitmap_s back;
- menubitmap_s next;
-
- menutext_s mapname;
- menubitmap_s item_null;
-
- qboolean multiplayer;
- int currentmap;
- int nummaps;
- int page;
- int maxpages;
- int maplist[MAX_SERVERMAPS];
-} startserver_t;
-
-static startserver_t s_startserver;
-
-static const char *gametype_items[] = {
- "Free For All",
- "Team Deathmatch",
- "Tournament",
- "Capture the Flag",
- "One Flag Capture",
- "Overload",
- "Harvester",
- "Elimination",
- "CTF Elimination",
- "Last Man Standing",
- "Double Domination",
- "Domination",
- NULL
-};
-
-static int gametype_remap[] = {
- GT_FFA,
- GT_TEAM,
- GT_TOURNAMENT,
- GT_CTF,
- GT_1FCTF,
- GT_OBELISK,
- GT_HARVESTER,
- GT_ELIMINATION,
- GT_CTF_ELIMINATION,
- GT_LMS,
- GT_DOUBLE_D,
- GT_DOMINATION };
-
-static int gametype_remap2[] = {
- 0,
- 2,
- 0,
- 1,
- 3,
- 4,
- 5,
- 6,
- 7,
- 8,
- 9,
- 10,
- 11 }; //this works and should increment for more gametypes
-
-static void UI_ServerOptionsMenu( qboolean multiplayer );
-
-
-/*
-=================
-GametypeBits from arenas.txt + .arena files
-=================
-*/
-static int GametypeBits( char *string ) {
- int bits;
- char *p;
- char *token;
-
- bits = 0;
- p = string;
- while( 1 ) {
- token = COM_ParseExt( &p, qfalse );
- if( token[0] == 0 ) {
- break;
- }
-
- if( Q_stricmp( token, "ffa" ) == 0 ) {
- bits |= 1 << GT_FFA;
- continue;
- }
-
- if( Q_stricmp( token, "tourney" ) == 0 ) {
- bits |= 1 << GT_TOURNAMENT;
- continue;
- }
-
- if( Q_stricmp( token, "single" ) == 0 ) {
- bits |= 1 << GT_SINGLE_PLAYER;
- continue;
- }
-
- if( Q_stricmp( token, "team" ) == 0 ) {
- bits |= 1 << GT_TEAM;
- continue;
- }
-
- if( Q_stricmp( token, "ctf" ) == 0 ) {
- bits |= 1 << GT_CTF;
- continue;
- }
-
- if( Q_stricmp( token, "oneflag" ) == 0 ) {
- bits |= 1 << GT_1FCTF;
- continue;
- }
-
- if( Q_stricmp( token, "overload" ) == 0 ) {
- bits |= 1 << GT_OBELISK;
- continue;
- }
-
- if( Q_stricmp( token, "harvester" ) == 0 ) {
- bits |= 1 << GT_HARVESTER;
- continue;
- }
-
- if( Q_stricmp( token, "elimination" ) == 0 ) {
- bits |= 1 << GT_ELIMINATION;
- continue;
- }
-
- if( Q_stricmp( token, "ctfelimination" ) == 0 ) {
- bits |= 1 << GT_CTF_ELIMINATION;
- continue;
- }
-
- if( Q_stricmp( token, "lms" ) == 0 ) {
- bits |= 1 << GT_LMS;
- continue;
- }
- if( Q_stricmp( token, "dd" ) == 0 ) {
- bits |= 1 << GT_DOUBLE_D;
- continue;
- }
-
- if( Q_stricmp( token, "dom" ) == 0 ) {
- bits |= 1 << GT_DOMINATION;
- continue;
- }
-}
- return bits;
-}
-
-
-/*
-=================
-StartServer_Update
-=================
-*/
-static void StartServer_Update( void ) {
- int i;
- int top;
- static char picname[MAX_MAPSPERPAGE][64];
- const char *info;
- char mapname[MAX_NAMELENGTH];
-
- top = s_startserver.page*MAX_MAPSPERPAGE;
-
- for (i=0; i<MAX_MAPSPERPAGE; i++)
- {
- if (top+i >= s_startserver.nummaps)
- break;
-
- info = UI_GetArenaInfoByNumber( s_startserver.maplist[ top + i ]);
- Q_strncpyz( mapname, Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
- Q_strupr( mapname );
-
- Com_sprintf( picname[i], sizeof(picname[i]), "levelshots/%s", mapname );
-
- s_startserver.mappics[i].generic.flags &= ~((unsigned int)QMF_HIGHLIGHT);
- s_startserver.mappics[i].generic.name = picname[i];
- s_startserver.mappics[i].shader = 0;
-
- // reset
- s_startserver.mapbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
- s_startserver.mapbuttons[i].generic.flags &= ~((unsigned int)QMF_INACTIVE);
- }
-
- for (; i<MAX_MAPSPERPAGE; i++)
- {
- s_startserver.mappics[i].generic.flags &= ~((unsigned int)QMF_HIGHLIGHT);
- s_startserver.mappics[i].generic.name = NULL;
- s_startserver.mappics[i].shader = 0;
-
- // disable
- s_startserver.mapbuttons[i].generic.flags &= ~((unsigned int)QMF_PULSEIFFOCUS);
- s_startserver.mapbuttons[i].generic.flags |= QMF_INACTIVE;
- }
-
-
- // no servers to start
- if( !s_startserver.nummaps ) {
- s_startserver.next.generic.flags |= QMF_INACTIVE;
-
- // set the map name
- strcpy( s_startserver.mapname.string, "NO MAPS FOUND" );
- }
- else {
- // set the highlight
- s_startserver.next.generic.flags &= ~((unsigned int)QMF_INACTIVE);
- i = s_startserver.currentmap - top;
- if ( i >=0 && i < MAX_MAPSPERPAGE )
- {
- s_startserver.mappics[i].generic.flags |= QMF_HIGHLIGHT;
- s_startserver.mapbuttons[i].generic.flags &= ~((unsigned int)QMF_PULSEIFFOCUS);
- }
-
- // set the map name
- info = UI_GetArenaInfoByNumber( s_startserver.maplist[ s_startserver.currentmap ]);
- Q_strncpyz( s_startserver.mapname.string, Info_ValueForKey( info, "map" ), MAX_NAMELENGTH);
- }
-
- Q_strupr( s_startserver.mapname.string );
-}
-
-
-/*
-=================
-StartServer_MapEvent
-=================
-*/
-static void StartServer_MapEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED) {
- return;
- }
-
- s_startserver.currentmap = (s_startserver.page*MAX_MAPSPERPAGE) + (((menucommon_s*)ptr)->id - ID_PICTURES);
- StartServer_Update();
-}
-
-
-/*
-=================
-StartServer_GametypeEvent
-=================
-*/
-static void StartServer_GametypeEvent( void* ptr, int event ) {
- int i;
- int count;
- int gamebits;
- int matchbits;
- const char *info;
-
- if( event != QM_ACTIVATED) {
- return;
- }
-
- count = UI_GetNumArenas();
- s_startserver.nummaps = 0;
- matchbits = 1 << gametype_remap[s_startserver.gametype.curvalue];
- if( gametype_remap[s_startserver.gametype.curvalue] == GT_FFA ) {
- matchbits |= ( 1 << GT_SINGLE_PLAYER );
- }
- for( i = 0; i < count; i++ ) {
- info = UI_GetArenaInfoByNumber( i );
-
- gamebits = GametypeBits( Info_ValueForKey( info, "type") );
- if( !( gamebits & matchbits ) ) {
- continue;
- }
-
- s_startserver.maplist[s_startserver.nummaps] = i;
- s_startserver.nummaps++;
- }
- s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE;
- s_startserver.page = 0;
- s_startserver.currentmap = 0;
-
- StartServer_Update();
-}
-
-
-/*
-=================
-StartServer_MenuEvent
-=================
-*/
-static void StartServer_MenuEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_PREVPAGE:
- if( s_startserver.page > 0 ) {
- s_startserver.page--;
- StartServer_Update();
- }
- break;
-
- case ID_NEXTPAGE:
- if( s_startserver.page < s_startserver.maxpages - 1 ) {
- s_startserver.page++;
- StartServer_Update();
- }
- break;
-
- case ID_STARTSERVERNEXT:
- trap_Cvar_SetValue( "g_gameType", gametype_remap[s_startserver.gametype.curvalue] );
- UI_ServerOptionsMenu( s_startserver.multiplayer );
- break;
-
- case ID_STARTSERVERBACK:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-===============
-StartServer_LevelshotDraw
-===============
-*/
-static void StartServer_LevelshotDraw( void *self ) {
- menubitmap_s *b;
- int x;
- int y;
- int w;
- int h;
- int n;
- const char *info;
-
- b = (menubitmap_s *)self;
-
- if( !b->generic.name ) {
- return;
- }
-
- if( b->generic.name && !b->shader ) {
- b->shader = trap_R_RegisterShaderNoMip( b->generic.name );
- if( !b->shader && b->errorpic ) {
- b->shader = trap_R_RegisterShaderNoMip( b->errorpic );
- }
- }
-
- if( b->focuspic && !b->focusshader ) {
- b->focusshader = trap_R_RegisterShaderNoMip( b->focuspic );
- }
-
- x = b->generic.x;
- y = b->generic.y;
- w = b->width;
- h = b->height;
- if( b->shader ) {
- UI_DrawHandlePic( x, y, w, h, b->shader );
- }
-
- x = b->generic.x;
- y = b->generic.y + b->height;
- UI_FillRect( x, y, b->width, 28, colorBlack );
-
- x += b->width / 2;
- y += 4;
- n = s_startserver.page * MAX_MAPSPERPAGE + b->generic.id - ID_PICTURES;
-
- info = UI_GetArenaInfoByNumber( s_startserver.maplist[ n ]);
- UI_DrawString( x, y, Info_ValueForKey( info, "map" ), UI_CENTER|UI_SMALLFONT, color_orange );
-
- x = b->generic.x;
- y = b->generic.y;
- w = b->width;
- h = b->height + 28;
- if( b->generic.flags & QMF_HIGHLIGHT ) {
- UI_DrawHandlePic( x, y, w, h, b->focusshader );
- }
-}
-
-
-/*
-=================
-StartServer_MenuInit
-=================
-*/
-static void StartServer_MenuInit( void ) {
- int i;
- int x;
- int y;
- static char mapnamebuffer[64];
-
- // zero set all our globals
- memset( &s_startserver, 0 ,sizeof(startserver_t) );
-
- StartServer_Cache();
-
- s_startserver.menu.wrapAround = qtrue;
- s_startserver.menu.fullscreen = qtrue;
-
- s_startserver.banner.generic.type = MTYPE_BTEXT;
- s_startserver.banner.generic.x = 320;
- s_startserver.banner.generic.y = 16;
- s_startserver.banner.string = "GAME SERVER";
- s_startserver.banner.color = color_white;
- s_startserver.banner.style = UI_CENTER;
-
- s_startserver.framel.generic.type = MTYPE_BITMAP;
- s_startserver.framel.generic.name = GAMESERVER_FRAMEL;
- s_startserver.framel.generic.flags = QMF_INACTIVE;
- s_startserver.framel.generic.x = 0;
- s_startserver.framel.generic.y = 78;
- s_startserver.framel.width = 256;
- s_startserver.framel.height = 329;
-
- s_startserver.framer.generic.type = MTYPE_BITMAP;
- s_startserver.framer.generic.name = GAMESERVER_FRAMER;
- s_startserver.framer.generic.flags = QMF_INACTIVE;
- s_startserver.framer.generic.x = 376;
- s_startserver.framer.generic.y = 76;
- s_startserver.framer.width = 256;
- s_startserver.framer.height = 334;
-
- s_startserver.gametype.generic.type = MTYPE_SPINCONTROL;
- s_startserver.gametype.generic.name = "Game Type:";
- s_startserver.gametype.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_startserver.gametype.generic.callback = StartServer_GametypeEvent;
- s_startserver.gametype.generic.id = ID_GAMETYPE;
- s_startserver.gametype.generic.x = 320 - 24;
- s_startserver.gametype.generic.y = 368;
- s_startserver.gametype.itemnames = gametype_items;
-
- for (i=0; i<MAX_MAPSPERPAGE; i++)
- {
- //x = (i % MAX_MAPCOLS) * (128+8) + 188;
- //y = (i / MAX_MAPROWS) * (128+8) + 96;
- x = (640-MAX_MAPROWS*140)/2 + ( (i % MAX_MAPROWS) * 140 );
- y = 96 + ( (i / MAX_MAPROWS) * 140 );
-
- s_startserver.mappics[i].generic.type = MTYPE_BITMAP;
- s_startserver.mappics[i].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_startserver.mappics[i].generic.x = x;
- s_startserver.mappics[i].generic.y = y;
- s_startserver.mappics[i].generic.id = ID_PICTURES+i;
- s_startserver.mappics[i].width = 128;
- s_startserver.mappics[i].height = 96;
- s_startserver.mappics[i].focuspic = GAMESERVER_SELECTED;
- s_startserver.mappics[i].errorpic = GAMESERVER_UNKNOWNMAP;
- s_startserver.mappics[i].generic.ownerdraw = StartServer_LevelshotDraw;
-
- s_startserver.mapbuttons[i].generic.type = MTYPE_BITMAP;
- s_startserver.mapbuttons[i].generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_NODEFAULTINIT;
- s_startserver.mapbuttons[i].generic.id = ID_PICTURES+i;
- s_startserver.mapbuttons[i].generic.callback = StartServer_MapEvent;
- s_startserver.mapbuttons[i].generic.x = x - 30;
- s_startserver.mapbuttons[i].generic.y = y - 32;
- s_startserver.mapbuttons[i].width = 256;
- s_startserver.mapbuttons[i].height = 248;
- s_startserver.mapbuttons[i].generic.left = x;
- s_startserver.mapbuttons[i].generic.top = y;
- s_startserver.mapbuttons[i].generic.right = x + 128;
- s_startserver.mapbuttons[i].generic.bottom = y + 128;
- s_startserver.mapbuttons[i].focuspic = GAMESERVER_SELECT;
- }
-
- s_startserver.arrows.generic.type = MTYPE_BITMAP;
- s_startserver.arrows.generic.name = GAMESERVER_ARROWS;
- s_startserver.arrows.generic.flags = QMF_INACTIVE;
- s_startserver.arrows.generic.x = 260;
- s_startserver.arrows.generic.y = 400;
- s_startserver.arrows.width = 128;
- s_startserver.arrows.height = 32;
-
- s_startserver.prevpage.generic.type = MTYPE_BITMAP;
- s_startserver.prevpage.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_startserver.prevpage.generic.callback = StartServer_MenuEvent;
- s_startserver.prevpage.generic.id = ID_PREVPAGE;
- s_startserver.prevpage.generic.x = 260;
- s_startserver.prevpage.generic.y = 400;
- s_startserver.prevpage.width = 64;
- s_startserver.prevpage.height = 32;
- s_startserver.prevpage.focuspic = GAMESERVER_ARROWSL;
-
- s_startserver.nextpage.generic.type = MTYPE_BITMAP;
- s_startserver.nextpage.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_startserver.nextpage.generic.callback = StartServer_MenuEvent;
- s_startserver.nextpage.generic.id = ID_NEXTPAGE;
- s_startserver.nextpage.generic.x = 321;
- s_startserver.nextpage.generic.y = 400;
- s_startserver.nextpage.width = 64;
- s_startserver.nextpage.height = 32;
- s_startserver.nextpage.focuspic = GAMESERVER_ARROWSR;
-
- s_startserver.mapname.generic.type = MTYPE_PTEXT;
- s_startserver.mapname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
- s_startserver.mapname.generic.x = 320;
- s_startserver.mapname.generic.y = 440;
- s_startserver.mapname.string = mapnamebuffer;
- s_startserver.mapname.style = UI_CENTER|UI_BIGFONT;
- s_startserver.mapname.color = text_color_normal;
-
- s_startserver.back.generic.type = MTYPE_BITMAP;
- s_startserver.back.generic.name = GAMESERVER_BACK0;
- s_startserver.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_startserver.back.generic.callback = StartServer_MenuEvent;
- s_startserver.back.generic.id = ID_STARTSERVERBACK;
- s_startserver.back.generic.x = 0;
- s_startserver.back.generic.y = 480-64;
- s_startserver.back.width = 128;
- s_startserver.back.height = 64;
- s_startserver.back.focuspic = GAMESERVER_BACK1;
-
- s_startserver.next.generic.type = MTYPE_BITMAP;
- s_startserver.next.generic.name = GAMESERVER_NEXT0;
- s_startserver.next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_startserver.next.generic.callback = StartServer_MenuEvent;
- s_startserver.next.generic.id = ID_STARTSERVERNEXT;
- s_startserver.next.generic.x = 640;
- s_startserver.next.generic.y = 480-64;
- s_startserver.next.width = 128;
- s_startserver.next.height = 64;
- s_startserver.next.focuspic = GAMESERVER_NEXT1;
-
- s_startserver.item_null.generic.type = MTYPE_BITMAP;
- s_startserver.item_null.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;
- s_startserver.item_null.generic.x = 0;
- s_startserver.item_null.generic.y = 0;
- s_startserver.item_null.width = 640;
- s_startserver.item_null.height = 480;
-
- Menu_AddItem( &s_startserver.menu, &s_startserver.banner );
- Menu_AddItem( &s_startserver.menu, &s_startserver.framel );
- Menu_AddItem( &s_startserver.menu, &s_startserver.framer );
-
- Menu_AddItem( &s_startserver.menu, &s_startserver.gametype );
- for (i=0; i<MAX_MAPSPERPAGE; i++)
- {
- Menu_AddItem( &s_startserver.menu, &s_startserver.mappics[i] );
- Menu_AddItem( &s_startserver.menu, &s_startserver.mapbuttons[i] );
- }
-
- Menu_AddItem( &s_startserver.menu, &s_startserver.arrows );
- Menu_AddItem( &s_startserver.menu, &s_startserver.prevpage );
- Menu_AddItem( &s_startserver.menu, &s_startserver.nextpage );
- Menu_AddItem( &s_startserver.menu, &s_startserver.back );
- Menu_AddItem( &s_startserver.menu, &s_startserver.next );
- Menu_AddItem( &s_startserver.menu, &s_startserver.mapname );
- Menu_AddItem( &s_startserver.menu, &s_startserver.item_null );
-
- StartServer_GametypeEvent( NULL, QM_ACTIVATED );
-}
-
-
-/*
-=================
-StartServer_Cache
-=================
-*/
-void StartServer_Cache( void )
-{
- int i;
- const char *info;
- qboolean precache;
- char picname[64];
- char mapname[ MAX_NAMELENGTH ];
-
- trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 );
- trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 );
- trap_R_RegisterShaderNoMip( GAMESERVER_NEXT0 );
- trap_R_RegisterShaderNoMip( GAMESERVER_NEXT1 );
- trap_R_RegisterShaderNoMip( GAMESERVER_FRAMEL );
- trap_R_RegisterShaderNoMip( GAMESERVER_FRAMER );
- trap_R_RegisterShaderNoMip( GAMESERVER_SELECT );
- trap_R_RegisterShaderNoMip( GAMESERVER_SELECTED );
- trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );
- trap_R_RegisterShaderNoMip( GAMESERVER_ARROWS );
- trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSL );
- trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSR );
-
- precache = trap_Cvar_VariableValue("com_buildscript");
-
- if( precache )
- {
- for( i = 0; i < UI_GetNumArenas(); i++ )
- {
- info = UI_GetArenaInfoByNumber( i );
- Q_strncpyz( mapname, Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
- Q_strupr( mapname );
-
- Com_sprintf( picname, sizeof(picname), "levelshots/%s", mapname );
- trap_R_RegisterShaderNoMip(picname);
- }
- }
-}
-
-
-/*
-=================
-UI_StartServerMenu
-=================
-*/
-void UI_StartServerMenu( qboolean multiplayer ) {
- StartServer_MenuInit();
- s_startserver.multiplayer = multiplayer;
- UI_PushMenu( &s_startserver.menu );
-}
-
-
-
-/*
-=============================================================================
-
-SERVER OPTIONS MENU *****
-
-=============================================================================
-*/
-
-#define ID_PLAYER_TYPE 25
-#define ID_MAXCLIENTS 26
-//#define ID_DEDICATED 27
-#define ID_GO 28
-#define ID_BACK 29
-
-#define PLAYER_SLOTS 12
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
-
- menubitmap_s mappic;
- menubitmap_s picframe;
-
-// menulist_s dedicated;
- menufield_s timelimit;
- menufield_s fraglimit;
- menufield_s flaglimit;
- menuradiobutton_s friendlyfire;
- menufield_s hostname;
- menuradiobutton_s pure;
- menuradiobutton_s lan;
- menulist_s pmove;
- //Here are the elimination stuff
- menuradiobutton_s oneway;
- menuradiobutton_s instantgib;
- menuradiobutton_s rockets;
- menulist_s lmsMode;
- menulist_s botSkill;
-
- menutext_s player0;
- menulist_s playerType[PLAYER_SLOTS];
- menutext_s playerName[PLAYER_SLOTS];
- menulist_s playerTeam[PLAYER_SLOTS];
-
- menubitmap_s go;
- menubitmap_s next;
- menubitmap_s back;
-
- qboolean multiplayer;
- int gametype;
- char mapnamebuffer[32];
- char playerNameBuffers[PLAYER_SLOTS][16];
-
- qboolean newBot;
- int newBotIndex;
- char newBotName[16];
-
- //menulist_s punkbuster;
-} serveroptions_t;
-
-static serveroptions_t s_serveroptions;
-
-/*static const char *dedicated_list[] = {
- "No",
- "LAN",
- "Internet",
- NULL
-};*/
-
-static const char *playerType_list[] = {
- "Open",
- "Bot",
- "----",
- NULL
-};
-
-static const char *playerTeam_list[] = {
- "Blue",
- "Red",
- NULL
-};
-
-static const char *botSkill_list[] = {
- "I Can Win",
- "Bring It On",
- "Hurt Me Plenty",
- "Hardcore",
- "Nightmare!",
- NULL
-};
-
-//Elimiantion - LMS mode
-static const char *lmsMode_list[] = {
- "Round+OT",
- "Round-OT",
- "Kill+OT",
- "Kill-OT",
- NULL
-};
-
-static const char *pmove_list[] = {
- "Framerate dependent",
- "Fixed framerate 125Hz",
- "Fixed framerate 91Hz",
- "Accurate",
- NULL
-};
-
-/*
-=================
-BotAlreadySelected
-=================
-*/
-static qboolean BotAlreadySelected( const char *checkName ) {
- int n;
-
- for( n = 1; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue != 1 ) {
- continue;
- }
- if( (s_serveroptions.gametype >= GT_TEAM) && s_serveroptions.gametype != GT_LMS &&
- (s_serveroptions.playerTeam[n].curvalue != s_serveroptions.playerTeam[s_serveroptions.newBotIndex].curvalue ) ) {
- continue;
- }
- if( Q_stricmp( checkName, s_serveroptions.playerNameBuffers[n] ) == 0 ) {
- return qtrue;
- }
- }
-
- return qfalse;
-}
-
-
-/*
-=================
-ServerOptions_Start
-=================
-*/
-static void ServerOptions_Start( void ) {
- int timelimit;
- int fraglimit;
- int maxclients;
-// int dedicated;
- int friendlyfire;
- int flaglimit;
- int pure;
- int pmove;
- int lan;
- int instantgib;
- int rockets;
- int oneway;
- int lmsMode;
- int skill;
- int n;
- const char *info;
- char buf[64];
-
-
- timelimit = atoi( s_serveroptions.timelimit.field.buffer );
- fraglimit = atoi( s_serveroptions.fraglimit.field.buffer );
- flaglimit = atoi( s_serveroptions.flaglimit.field.buffer );
-// dedicated = s_serveroptions.dedicated.curvalue;
- friendlyfire = s_serveroptions.friendlyfire.curvalue;
- pure = s_serveroptions.pure.curvalue;
- lan = s_serveroptions.lan.curvalue;
- pmove = s_serveroptions.pmove.curvalue;
- instantgib = s_serveroptions.instantgib.curvalue;
- rockets = s_serveroptions.rockets.curvalue;
- oneway = s_serveroptions.oneway.curvalue;
- //Sago: For some reason you need to add 1 to curvalue to get the UI to show the right thing (fixed?)
- lmsMode = s_serveroptions.lmsMode.curvalue; //+1;
- skill = s_serveroptions.botSkill.curvalue + 1;
-
- //set maxclients
- for( n = 0, maxclients = 0; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue == 2 ) {
- continue;
- }
- if( (s_serveroptions.playerType[n].curvalue == 1) && (s_serveroptions.playerNameBuffers[n][0] == 0) ) {
- continue;
- }
- maxclients++;
- }
-
- switch( s_serveroptions.gametype ) {
- case GT_FFA:
- default:
- trap_Cvar_SetValue( "ui_ffa_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_ffa_timelimit", timelimit );
- break;
-
- case GT_TOURNAMENT:
- trap_Cvar_SetValue( "ui_tourney_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_tourney_timelimit", timelimit );
- break;
-
- case GT_TEAM:
- trap_Cvar_SetValue( "ui_team_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_team_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_team_friendlt", friendlyfire );
- break;
-
- case GT_CTF:
- trap_Cvar_SetValue( "ui_ctf_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_ctf_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_ctf_friendlt", friendlyfire );
- break;
-
- case GT_1FCTF:
- trap_Cvar_SetValue( "ui_1fctf_capturelimit", fraglimit );
- trap_Cvar_SetValue( "ui_1fctf_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_1fctf_friendlt", friendlyfire );
- break;
-
- case GT_OBELISK:
- trap_Cvar_SetValue( "ui_overload_capturelimit", fraglimit );
- trap_Cvar_SetValue( "ui_overload_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_overload_friendlt", friendlyfire );
- break;
-
- case GT_HARVESTER:
- trap_Cvar_SetValue( "ui_harvester_capturelimit", fraglimit );
- trap_Cvar_SetValue( "ui_harvester_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_harvester_friendlt", friendlyfire );
- break;
-
- case GT_ELIMINATION:
- trap_Cvar_SetValue( "ui_elimination_capturelimit", fraglimit );
- trap_Cvar_SetValue( "ui_elimination_timelimit", timelimit );
- //trap_Cvar_SetValue( "ui_elimination_friendlt", friendlyfire );
- break;
-
- case GT_CTF_ELIMINATION:
- trap_Cvar_SetValue( "ui_ctf_elimination_capturelimit", fraglimit );
- trap_Cvar_SetValue( "ui_ctf_elimination_timelimit", timelimit );
- //trap_Cvar_SetValue( "ui_ctf_elimination_friendlt", friendlyfire );
- break;
-
- case GT_LMS:
- trap_Cvar_SetValue( "ui_lms_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_lms_timelimit", timelimit );
- break;
-
- case GT_DOUBLE_D:
- trap_Cvar_SetValue( "ui_dd_capturelimit", fraglimit );
- trap_Cvar_SetValue( "ui_dd_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_dd_friendlt", friendlyfire );
- break;
- }
-
- trap_Cvar_SetValue( "sv_maxclients", Com_Clamp( 0, 12, maxclients ) );
-// trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, dedicated ) );
- trap_Cvar_SetValue ("timelimit", Com_Clamp( 0, timelimit, timelimit ) );
- trap_Cvar_SetValue ("fraglimit", Com_Clamp( 0, fraglimit, fraglimit ) );
- trap_Cvar_SetValue ("capturelimit", Com_Clamp( 0, flaglimit, flaglimit ) );
- trap_Cvar_SetValue( "g_friendlyfire", friendlyfire );
- trap_Cvar_SetValue( "sv_pure", pure );
- trap_Cvar_SetValue( "sv_lanForceRate", lan );
- trap_Cvar_SetValue( "g_instantgib", instantgib );
- trap_Cvar_SetValue( "g_rockets", rockets );
- trap_Cvar_SetValue( "g_lms_mode", lmsMode);
- trap_Cvar_SetValue( "elimination_ctf_oneway", oneway );
- switch(pmove) {
- case 1:
- //Fixed framerate 125 Hz
- trap_Cvar_SetValue( "pmove_fixed", 1);
- trap_Cvar_SetValue( "pmove_msec", 8);
- trap_Cvar_SetValue( "pmove_float", 0);
- break;
- case 2:
- //Fixed framerate 91 Hz
- trap_Cvar_SetValue( "pmove_fixed", 1);
- trap_Cvar_SetValue( "pmove_msec", 11);
- trap_Cvar_SetValue( "pmove_float", 0);
- break;
- case 3:
- //Accurate physics
- trap_Cvar_SetValue( "pmove_fixed", 0);
- trap_Cvar_SetValue( "pmove_float", 1);
- break;
- default:
- //Framerate dependent
- trap_Cvar_SetValue( "pmove_fixed", 0);
- trap_Cvar_SetValue( "pmove_float", 0);
- break;
- };
- trap_Cvar_Set("sv_hostname", s_serveroptions.hostname.field.buffer );
-
- // the wait commands will allow the dedicated to take effect
- info = UI_GetArenaInfoByNumber( s_startserver.maplist[ s_startserver.currentmap ]);
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", Info_ValueForKey( info, "map" )));
-
- // add bots
- trap_Cmd_ExecuteText( EXEC_APPEND, "wait 3\n" );
- for( n = 1; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue != 1 ) {
- continue;
- }
- if( s_serveroptions.playerNameBuffers[n][0] == 0 ) {
- continue;
- }
- if( s_serveroptions.playerNameBuffers[n][0] == '-' ) {
- continue;
- }
- if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
- Com_sprintf( buf, sizeof(buf), "addbot %s %i %s\n", s_serveroptions.playerNameBuffers[n], skill,
- playerTeam_list[s_serveroptions.playerTeam[n].curvalue] );
- }
- else {
- Com_sprintf( buf, sizeof(buf), "addbot %s %i\n", s_serveroptions.playerNameBuffers[n], skill );
- }
- trap_Cmd_ExecuteText( EXEC_APPEND, buf );
- }
-
- // set player's team
- if( /*dedicated == 0 &&*/ s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait 5; team %s\n", playerTeam_list[s_serveroptions.playerTeam[0].curvalue] ) );
- }
-}
-
-
-/*
-=================
-ServerOptions_InitPlayerItems
-=================
-*/
-static void ServerOptions_InitPlayerItems( void ) {
- int n;
- int v;
-
- // init types
- if( s_serveroptions.multiplayer ) {
- v = 0; // open
- }
- else {
- v = 1; // bot
- }
-
- for( n = 0; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerType[n].curvalue = v;
- }
-
- if( s_serveroptions.multiplayer && (s_serveroptions.gametype < GT_TEAM || s_serveroptions.gametype == GT_LMS ) ) {
- for( n = 8; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerType[n].curvalue = 2;
- }
- }
-
- // if not a dedicated server, first slot is reserved for the human on the server
-// if( s_serveroptions.dedicated.curvalue == 0 ) {
- // human
- s_serveroptions.playerType[0].generic.flags |= QMF_INACTIVE;
- s_serveroptions.playerType[0].curvalue = 0;
- trap_Cvar_VariableStringBuffer( "name", s_serveroptions.playerNameBuffers[0], sizeof(s_serveroptions.playerNameBuffers[0]) );
- Q_CleanStr( s_serveroptions.playerNameBuffers[0] );
-// }
-
- // init teams
- if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
- for( n = 0; n < (PLAYER_SLOTS / 2); n++ ) {
- s_serveroptions.playerTeam[n].curvalue = 0;
- }
- for( ; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerTeam[n].curvalue = 1;
- }
- }
- else {
- for( n = 0; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- }
- }
-}
-
-
-/*
-=================
-ServerOptions_SetPlayerItems
-=================
-*/
-static void ServerOptions_SetPlayerItems( void ) {
- int start;
- int n;
-
- // types
-// for( n = 0; n < PLAYER_SLOTS; n++ ) {
-// if( (!s_serveroptions.multiplayer) && (n > 0) && (s_serveroptions.playerType[n].curvalue == 0) ) {
-// s_serveroptions.playerType[n].curvalue = 1;
-// }
-// }
-
- // names
-// if( s_serveroptions.dedicated.curvalue == 0 ) {
- s_serveroptions.player0.string = "Human";
- s_serveroptions.playerName[0].generic.flags &= ~((unsigned int)QMF_HIDDEN);
-
- start = 1;
-/* }
- else {
- s_serveroptions.player0.string = "Open";
- start = 0;
- }*/
- for( n = start; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue == 1 ) {
- s_serveroptions.playerName[n].generic.flags &= ~( (unsigned int)(QMF_INACTIVE|QMF_HIDDEN));
- }
- else {
- s_serveroptions.playerName[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- }
- }
-
- // teams
- if( s_serveroptions.gametype < GT_TEAM || s_serveroptions.gametype == GT_LMS ) {
- return;
- }
- for( n = start; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue == 2 ) {
- s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- }
- else {
- s_serveroptions.playerTeam[n].generic.flags &= ~((unsigned int) (QMF_INACTIVE|QMF_HIDDEN));
- }
- }
-}
-
-
-/*
-=================
-ServerOptions_Event
-=================
-*/
-static void ServerOptions_Event( void* ptr, int event ) {
- switch( ((menucommon_s*)ptr)->id ) {
-
- //if( event != QM_ACTIVATED && event != QM_LOSTFOCUS) {
- // return;
- //}
- case ID_PLAYER_TYPE:
- if( event != QM_ACTIVATED ) {
- break;
- }
- ServerOptions_SetPlayerItems();
- break;
-
- case ID_MAXCLIENTS:
-// case ID_DEDICATED:
- ServerOptions_SetPlayerItems();
- break;
- case ID_GO:
- if( event != QM_ACTIVATED ) {
- break;
- }
- ServerOptions_Start();
- break;
-
- case ID_STARTSERVERNEXT:
- if( event != QM_ACTIVATED ) {
- break;
- }
- break;
- case ID_BACK:
- if( event != QM_ACTIVATED ) {
- break;
- }
- UI_PopMenu();
- break;
- }
-}
-
-
-static void ServerOptions_PlayerNameEvent( void* ptr, int event ) {
- int n;
-
- if( event != QM_ACTIVATED ) {
- return;
- }
- n = ((menutext_s*)ptr)->generic.id;
- s_serveroptions.newBotIndex = n;
- UI_BotSelectMenu( s_serveroptions.playerNameBuffers[n] );
-}
-
-
-/*
-=================
-ServerOptions_StatusBar
-=================
-*/
-static void ServerOptions_StatusBar( void* ptr ) {
- UI_DrawString( 320, 440, "0 = NO LIMIT", UI_CENTER|UI_SMALLFONT, colorWhite );
-}
-
-/*
-=================
-ServerOptions_StatusBar_Instantgib
-=================
-*/
-static void ServerOptions_StatusBar_Instantgib( void* ptr ) {
- UI_DrawString( 320, 440, "Only railgun and instant kill", UI_CENTER|UI_SMALLFONT, colorWhite );
-}
-
-/*
-=================
-ServerOptions_StatusBar_Allrockets
-=================
-*/
-static void ServerOptions_StatusBar_Allrockets( void* ptr ) {
- UI_DrawString( 320, 440, "Only Rocket launcher with Inf. ammo", UI_CENTER|UI_SMALLFONT, colorWhite );
-}
-
-/*
-=================
-ServerOptions_StatusBar_Pure
-=================
-*/
-static void ServerOptions_StatusBar_Pure( void* ptr ) {
- UI_DrawString( 320, 440, "Require identical pk3 files", UI_CENTER|UI_SMALLFONT, colorWhite );
-}
-
-/*
-=================
-ServerOptions_StatusBar_Oneway
-=================
-*/
-static void ServerOptions_StatusBar_Oneway( void* ptr ) {
- UI_DrawString( 320, 440, "Only one team can capture in a round", UI_CENTER|UI_SMALLFONT, colorWhite );
-}
-
-/*
-=================
-ServerOptions_StatusBar_Pmove
-=================
-*/
-static void ServerOptions_StatusBar_Pmove( void* ptr ) {
- switch( ((menulist_s*)ptr)->curvalue ) {
- case 0:
- UI_DrawString( 320, 440, "Physics depends on players framerates", UI_CENTER|UI_SMALLFONT, colorWhite );
- UI_DrawString( 320, 460, "Not all players are equal", UI_CENTER|UI_SMALLFONT, colorWhite );
- break;
- case 1:
- case 2:
- UI_DrawString( 320, 440, "Physics are calculated at fixed intervals", UI_CENTER|UI_SMALLFONT, colorWhite );
- UI_DrawString( 320, 460, "All players are equal", UI_CENTER|UI_SMALLFONT, colorWhite );
- break;
- case 3:
- UI_DrawString( 320, 440, "Physics are calculated exactly", UI_CENTER|UI_SMALLFONT, colorWhite );
- UI_DrawString( 320, 460, "All players are equal", UI_CENTER|UI_SMALLFONT, colorWhite );
- break;
- default:
- UI_DrawString( 320, 440, "Framerate dependent or not", UI_CENTER|UI_SMALLFONT, colorWhite );
- break;
- }
-
-}
-
-
-/*
-===============
-ServerOptions_LevelshotDraw
-===============
-*/
-static void ServerOptions_LevelshotDraw( void *self ) {
- menubitmap_s *b;
- int x;
- int y;
-
- // strange place for this, but it works
- if( s_serveroptions.newBot ) {
- Q_strncpyz( s_serveroptions.playerNameBuffers[s_serveroptions.newBotIndex], s_serveroptions.newBotName, 16 );
- s_serveroptions.newBot = qfalse;
- }
-
- b = (menubitmap_s *)self;
-
- Bitmap_Draw( b );
-
- x = b->generic.x;
- y = b->generic.y + b->height;
- UI_FillRect( x, y, b->width, 40, colorBlack );
-
- x += b->width / 2;
- y += 4;
- UI_DrawString( x, y, s_serveroptions.mapnamebuffer, UI_CENTER|UI_SMALLFONT, color_orange );
-
- y += SMALLCHAR_HEIGHT;
- UI_DrawString( x, y, gametype_items[gametype_remap2[s_serveroptions.gametype]], UI_CENTER|UI_SMALLFONT, color_orange );
-}
-
-
-static void ServerOptions_InitBotNames( void ) {
- int count;
- int n;
- const char *arenaInfo;
- const char *botInfo;
- char *p;
- char *bot;
- char bots[MAX_INFO_STRING];
-
- //this SHOULD work
- if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
- Q_strncpyz( s_serveroptions.playerNameBuffers[1], "gargoyle", 16 );
- Q_strncpyz( s_serveroptions.playerNameBuffers[2], "kyonshi", 16 );
- Q_strncpyz( s_serveroptions.playerNameBuffers[3], "grism", 16 );
- if( s_serveroptions.gametype != GT_TEAM ) {
- s_serveroptions.playerType[3].curvalue = 2;
- }
- Q_strncpyz( s_serveroptions.playerNameBuffers[4], "merman", 16 );
- s_serveroptions.playerType[4].curvalue = 2;
- Q_strncpyz( s_serveroptions.playerNameBuffers[5], "skelebot", 16 );
- s_serveroptions.playerType[5].curvalue = 2;
-
- Q_strncpyz( s_serveroptions.playerNameBuffers[6], "sergei", 16 );
- Q_strncpyz( s_serveroptions.playerNameBuffers[7], "assassin", 16 );
- Q_strncpyz( s_serveroptions.playerNameBuffers[8], "grunt", 16 );
- Q_strncpyz( s_serveroptions.playerNameBuffers[9], "skelebot", 16 );
- if( s_serveroptions.gametype != GT_TEAM ) {
- s_serveroptions.playerType[9].curvalue = 2;
- }
- Q_strncpyz( s_serveroptions.playerNameBuffers[10], "merman", 16 );
- s_serveroptions.playerType[10].curvalue = 2;
- Q_strncpyz( s_serveroptions.playerNameBuffers[11], "skelebot", 16 );
- s_serveroptions.playerType[11].curvalue = 2;
-
- return;
- }
-
- count = 1; // skip the first slot, reserved for a human
-
- // get info for this map
- arenaInfo = UI_GetArenaInfoByMap( s_serveroptions.mapnamebuffer );
-
- // get the bot info - we'll seed with them if any are listed
- Q_strncpyz( bots, Info_ValueForKey( arenaInfo, "bots" ), sizeof(bots) );
- p = &bots[0];
- while( *p && count < PLAYER_SLOTS ) {
- //skip spaces
- while( *p && *p == ' ' ) {
- p++;
- }
- if( !p ) {
- break;
- }
-
- // mark start of bot name
- bot = p;
-
- // skip until space of null
- while( *p && *p != ' ' ) {
- p++;
- }
- if( *p ) {
- *p++ = 0;
- }
-
- botInfo = UI_GetBotInfoByName( bot );
- bot = Info_ValueForKey( botInfo, "name" );
-
- if(!Q_stricmp(bot,""))
- bot = "Sarge";
-
- Q_strncpyz( s_serveroptions.playerNameBuffers[count], bot, sizeof(s_serveroptions.playerNameBuffers[count]) );
- count++;
- }
-
- // set the rest of the bot slots to to other bots
- for( n = count; n < PLAYER_SLOTS; n++ ) {
- switch(n%4){
- case 0:
- strcpy( s_serveroptions.playerNameBuffers[n], "Grunt" );
- break;
- case 1:
- strcpy( s_serveroptions.playerNameBuffers[n], "Merman" );
- break;
- case 2:
- strcpy( s_serveroptions.playerNameBuffers[n], "Kyonshi" );
- break;
- default:
- strcpy( s_serveroptions.playerNameBuffers[n], "Skelebot" );
- }
- }
-
- // pad up to #8 as open slots
- for( ;count < 8; count++ ) {
- s_serveroptions.playerType[count].curvalue = 0;
- }
-
- // close off the rest by default
- for( ;count < PLAYER_SLOTS; count++ ) {
- if( s_serveroptions.playerType[count].curvalue == 1 ) {
- s_serveroptions.playerType[count].curvalue = 2;
- }
- }
-}
-
-
-/*
-=================
-ServerOptions_SetMenuItems
-=================
-*/
-static void ServerOptions_SetMenuItems( void ) {
- static char picname[64];
- const char *info;
-
- switch( s_serveroptions.gametype ) {
- case GT_FFA:
- default:
- Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_fraglimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_timelimit" ) ) );
- break;
-
- case GT_TOURNAMENT:
- Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_fraglimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_timelimit" ) ) );
- break;
-
- case GT_TEAM:
- Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_fraglimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_team_friendly" ) );
- break;
-
- case GT_CTF:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_ctf_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_ctf_friendly" ) );
- break;
-
- case GT_1FCTF:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_1fctf_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_1fctf_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_1fctf_friendly" ) );
- break;
-
- case GT_OBELISK:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_overload_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_overload_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_overload_friendly" ) );
- break;
-
- case GT_HARVESTER:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_harvester_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_harvester_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_harvester_friendly" ) );
- break;
-
- case GT_ELIMINATION:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_elimination_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_elimination_timelimit" ) ) );
- //s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_elimination_friendly" ) );
- break;
-
- case GT_CTF_ELIMINATION:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_elimination_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_elimination_timelimit" ) ) );
- //s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_ctf_elimination_friendly" ) );
- break;
-
- case GT_LMS:
- Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_lms_fraglimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_lms_timelimit" ) ) );
- break;
-
- case GT_DOUBLE_D:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_dd_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_dd_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_dd_friendly" ) );
- break;
-
- case GT_DOMINATION:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_dom_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_dom_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_dom_friendly" ) );
- break;
-
- }
-
- Q_strncpyz( s_serveroptions.hostname.field.buffer, UI_Cvar_VariableString( "sv_hostname" ), sizeof( s_serveroptions.hostname.field.buffer ) );
- s_serveroptions.pure.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_pure" ) );
- s_serveroptions.lan.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_lanforcerate" ) );
- s_serveroptions.instantgib.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "g_instantgib" ) );
- s_serveroptions.rockets.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "g_rockets" ) );
- s_serveroptions.lmsMode.curvalue = Com_Clamp( 0, 3, trap_Cvar_VariableValue("g_lms_mode") );
- s_serveroptions.oneway.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "elimination_ctf_oneway" ) );
- s_serveroptions.pmove.curvalue = 0;
- if(trap_Cvar_VariableValue( "pmove_fixed" ))
- s_serveroptions.pmove.curvalue = 1;
- if(trap_Cvar_VariableValue( "pmove_fixed" ) && trap_Cvar_VariableValue( "pmove_msec" )==11)
- s_serveroptions.pmove.curvalue = 2;
- if(trap_Cvar_VariableValue( "pmove_float" ))
- s_serveroptions.pmove.curvalue = 3;
-
- // set the map pic
- info = UI_GetArenaInfoByNumber(s_startserver.maplist[s_startserver.currentmap]);
- Com_sprintf( picname, 64, "levelshots/%s", Info_ValueForKey( info, "map") );
- s_serveroptions.mappic.generic.name = picname;
-
- // set the map name
- strcpy( s_serveroptions.mapnamebuffer, s_startserver.mapname.string );
- Q_strupr( s_serveroptions.mapnamebuffer );
-
- // get the player selections initialized
- ServerOptions_InitPlayerItems();
- ServerOptions_SetPlayerItems();
-
- // seed bot names
- ServerOptions_InitBotNames();
- ServerOptions_SetPlayerItems();
-}
-
-/*
-=================
-PlayerName_Draw
-=================
-*/
-static void PlayerName_Draw( void *item ) {
- menutext_s *s;
- float *color;
- int x, y;
- int style;
- qboolean focus;
-
- s = (menutext_s *)item;
-
- x = s->generic.x;
- y = s->generic.y;
-
- style = UI_SMALLFONT;
- focus = (s->generic.parent->cursor == s->generic.menuPosition);
-
- if ( s->generic.flags & QMF_GRAYED )
- color = text_color_disabled;
- else if ( focus )
- {
- color = text_color_highlight;
- style |= UI_PULSE;
- }
- else if ( s->generic.flags & QMF_BLINK )
- {
- color = text_color_highlight;
- style |= UI_BLINK;
- }
- else
- color = text_color_normal;
-
- if ( focus )
- {
- // draw cursor
- UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
- }
-
- UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );
- UI_DrawString( x + SMALLCHAR_WIDTH, y, s->string, style|UI_LEFT, color );
-}
-
-
-/*
-=================
-ServerOptions_MenuInit
-=================
-*/
-#define OPTIONS_X 456
-
-static void ServerOptions_MenuInit( qboolean multiplayer ) {
- int y;
- int n;
-
- memset( &s_serveroptions, 0 ,sizeof(serveroptions_t) );
- s_serveroptions.multiplayer = multiplayer;
- // so the new gametypes work
- s_serveroptions.gametype = (int)Com_Clamp( 0, GT_MAX_GAME_TYPE - 1, trap_Cvar_VariableValue( "g_gameType" ) );
-
- ServerOptions_Cache();
-
- s_serveroptions.menu.wrapAround = qtrue;
- s_serveroptions.menu.fullscreen = qtrue;
-
- s_serveroptions.banner.generic.type = MTYPE_BTEXT;
- s_serveroptions.banner.generic.x = 320;
- s_serveroptions.banner.generic.y = 16;
- s_serveroptions.banner.string = "GAME SERVER";
- s_serveroptions.banner.color = color_white;
- s_serveroptions.banner.style = UI_CENTER;
-
- s_serveroptions.mappic.generic.type = MTYPE_BITMAP;
- s_serveroptions.mappic.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_serveroptions.mappic.generic.x = 352;
- s_serveroptions.mappic.generic.y = 80;
- s_serveroptions.mappic.width = 160;
- s_serveroptions.mappic.height = 120;
- s_serveroptions.mappic.errorpic = GAMESERVER_UNKNOWNMAP;
- s_serveroptions.mappic.generic.ownerdraw = ServerOptions_LevelshotDraw;
-
- s_serveroptions.picframe.generic.type = MTYPE_BITMAP;
- s_serveroptions.picframe.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE|QMF_HIGHLIGHT;
- s_serveroptions.picframe.generic.x = 352 - 38;
- s_serveroptions.picframe.generic.y = 80 - 40;
- s_serveroptions.picframe.width = 320;
- s_serveroptions.picframe.height = 320;
- s_serveroptions.picframe.focuspic = GAMESERVER_SELECT;
-
- y = 268;
- if( s_serveroptions.gametype < GT_CTF || s_serveroptions.gametype== GT_LMS) {
- s_serveroptions.fraglimit.generic.type = MTYPE_FIELD;
- s_serveroptions.fraglimit.generic.name = "Frag Limit:";
- s_serveroptions.fraglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.fraglimit.generic.x = OPTIONS_X;
- s_serveroptions.fraglimit.generic.y = y;
- s_serveroptions.fraglimit.generic.statusbar = ServerOptions_StatusBar;
- s_serveroptions.fraglimit.field.widthInChars = 3;
- s_serveroptions.fraglimit.field.maxchars = 3;
- }
- else {
- s_serveroptions.flaglimit.generic.type = MTYPE_FIELD;
- s_serveroptions.flaglimit.generic.name = "Capture Limit:";
- s_serveroptions.flaglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.flaglimit.generic.x = OPTIONS_X;
- s_serveroptions.flaglimit.generic.y = y;
- s_serveroptions.flaglimit.generic.statusbar = ServerOptions_StatusBar;
- s_serveroptions.flaglimit.field.widthInChars = 3;
- s_serveroptions.flaglimit.field.maxchars = 3;
- }
-
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.timelimit.generic.type = MTYPE_FIELD;
- s_serveroptions.timelimit.generic.name = "Time Limit:";
- s_serveroptions.timelimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.timelimit.generic.x = OPTIONS_X;
- s_serveroptions.timelimit.generic.y = y;
- s_serveroptions.timelimit.generic.statusbar = ServerOptions_StatusBar;
- s_serveroptions.timelimit.field.widthInChars = 3;
- s_serveroptions.timelimit.field.maxchars = 3;
-
- if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS && s_serveroptions.gametype != GT_ELIMINATION && s_serveroptions.gametype != GT_CTF_ELIMINATION) {
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.friendlyfire.generic.type = MTYPE_RADIOBUTTON;
- s_serveroptions.friendlyfire.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.friendlyfire.generic.x = OPTIONS_X;
- s_serveroptions.friendlyfire.generic.y = y;
- s_serveroptions.friendlyfire.generic.name = "Friendly Fire:";
- }
-
- if( s_serveroptions.gametype == GT_CTF_ELIMINATION) {
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.oneway.generic.type = MTYPE_RADIOBUTTON;
- s_serveroptions.oneway.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.oneway.generic.x = OPTIONS_X;
- s_serveroptions.oneway.generic.y = y;
- s_serveroptions.oneway.generic.name = "Oneway attack:";
- s_serveroptions.oneway.generic.statusbar = ServerOptions_StatusBar_Oneway;
- }
-
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.pure.generic.type = MTYPE_RADIOBUTTON;
- s_serveroptions.pure.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.pure.generic.x = OPTIONS_X;
- s_serveroptions.pure.generic.y = y;
- s_serveroptions.pure.generic.name = "Pure Server:";
- s_serveroptions.pure.generic.statusbar = ServerOptions_StatusBar_Pure;
-
- if( s_serveroptions.multiplayer ) {
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.lan.generic.type = MTYPE_RADIOBUTTON;
- s_serveroptions.lan.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.lan.generic.x = OPTIONS_X;
- s_serveroptions.lan.generic.y = y;
- s_serveroptions.lan.generic.name = "Optimize for LAN:";
- }
-
- //Insantgib option
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.instantgib.generic.type = MTYPE_RADIOBUTTON;
- s_serveroptions.instantgib.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.instantgib.generic.x = OPTIONS_X;
- s_serveroptions.instantgib.generic.y = y;
- s_serveroptions.instantgib.generic.name = "Instantgib:";
- s_serveroptions.instantgib.generic.statusbar = ServerOptions_StatusBar_Instantgib;
-
- //Rockets option
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.rockets.generic.type = MTYPE_RADIOBUTTON;
- s_serveroptions.rockets.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.rockets.generic.x = OPTIONS_X;
- s_serveroptions.rockets.generic.y = y;
- s_serveroptions.rockets.generic.name = "All rockets:";
- s_serveroptions.rockets.generic.statusbar = ServerOptions_StatusBar_Allrockets;
-
- if( s_serveroptions.gametype == GT_LMS ) {
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.lmsMode.generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.lmsMode.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.lmsMode.generic.name = "Score mode:";
- s_serveroptions.lmsMode.generic.x = OPTIONS_X; //32 + (strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH;
- s_serveroptions.lmsMode.generic.y = y;
- s_serveroptions.lmsMode.itemnames = lmsMode_list;
- //s_serveroptions.lmsMode.curvalue = 0;
-
- }
-
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.pmove.generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.pmove.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.pmove.generic.name = "Physics:";
- s_serveroptions.pmove.generic.x = OPTIONS_X; //32 + (strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH;
- s_serveroptions.pmove.generic.y = y;
- s_serveroptions.pmove.itemnames = pmove_list;
- s_serveroptions.pmove.generic.statusbar = ServerOptions_StatusBar_Pmove;
-
- if( s_serveroptions.multiplayer ) {
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.hostname.generic.type = MTYPE_FIELD;
- s_serveroptions.hostname.generic.name = "Hostname:";
- s_serveroptions.hostname.generic.flags = QMF_SMALLFONT;
- s_serveroptions.hostname.generic.x = OPTIONS_X;
- s_serveroptions.hostname.generic.y = y;
- s_serveroptions.hostname.field.widthInChars = 18;
- s_serveroptions.hostname.field.maxchars = 64;
- }
-
- y = 80;
- s_serveroptions.botSkill.generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.botSkill.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.botSkill.generic.name = "Bot Skill: ";
- s_serveroptions.botSkill.generic.x = 32 + (strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH;
- s_serveroptions.botSkill.generic.y = y;
- s_serveroptions.botSkill.itemnames = botSkill_list;
- s_serveroptions.botSkill.curvalue = 1;
-
- y += ( 2 * SMALLCHAR_HEIGHT );
- s_serveroptions.player0.generic.type = MTYPE_TEXT;
- s_serveroptions.player0.generic.flags = QMF_SMALLFONT;
- s_serveroptions.player0.generic.x = 32 + SMALLCHAR_WIDTH;
- s_serveroptions.player0.generic.y = y;
- s_serveroptions.player0.color = color_orange;
- s_serveroptions.player0.style = UI_LEFT|UI_SMALLFONT;
-
- for( n = 0; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerType[n].generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.playerType[n].generic.flags = QMF_SMALLFONT;
- s_serveroptions.playerType[n].generic.id = ID_PLAYER_TYPE;
- s_serveroptions.playerType[n].generic.callback = ServerOptions_Event;
- s_serveroptions.playerType[n].generic.x = 32;
- s_serveroptions.playerType[n].generic.y = y;
- s_serveroptions.playerType[n].itemnames = playerType_list;
-
- s_serveroptions.playerName[n].generic.type = MTYPE_TEXT;
- s_serveroptions.playerName[n].generic.flags = QMF_SMALLFONT;
- s_serveroptions.playerName[n].generic.x = 96;
- s_serveroptions.playerName[n].generic.y = y;
- s_serveroptions.playerName[n].generic.callback = ServerOptions_PlayerNameEvent;
- s_serveroptions.playerName[n].generic.id = n;
- s_serveroptions.playerName[n].generic.ownerdraw = PlayerName_Draw;
- s_serveroptions.playerName[n].color = color_orange;
- s_serveroptions.playerName[n].style = UI_SMALLFONT;
- s_serveroptions.playerName[n].string = s_serveroptions.playerNameBuffers[n];
- s_serveroptions.playerName[n].generic.top = s_serveroptions.playerName[n].generic.y;
- s_serveroptions.playerName[n].generic.bottom = s_serveroptions.playerName[n].generic.y + SMALLCHAR_HEIGHT;
- s_serveroptions.playerName[n].generic.left = s_serveroptions.playerName[n].generic.x - SMALLCHAR_HEIGHT/ 2;
- s_serveroptions.playerName[n].generic.right = s_serveroptions.playerName[n].generic.x + 16 * SMALLCHAR_WIDTH;
-
- s_serveroptions.playerTeam[n].generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.playerTeam[n].generic.flags = QMF_SMALLFONT;
- s_serveroptions.playerTeam[n].generic.x = 240;
- s_serveroptions.playerTeam[n].generic.y = y;
- s_serveroptions.playerTeam[n].itemnames = playerTeam_list;
-
- y += ( SMALLCHAR_HEIGHT + 4 );
- }
-
- s_serveroptions.back.generic.type = MTYPE_BITMAP;
- s_serveroptions.back.generic.name = GAMESERVER_BACK0;
- s_serveroptions.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_serveroptions.back.generic.callback = ServerOptions_Event;
- s_serveroptions.back.generic.id = ID_BACK;
- s_serveroptions.back.generic.x = 0;
- s_serveroptions.back.generic.y = 480-64;
- s_serveroptions.back.width = 128;
- s_serveroptions.back.height = 64;
- s_serveroptions.back.focuspic = GAMESERVER_BACK1;
-
- s_serveroptions.next.generic.type = MTYPE_BITMAP;
- s_serveroptions.next.generic.name = GAMESERVER_NEXT0;
- s_serveroptions.next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE|QMF_GRAYED|QMF_HIDDEN;
- s_serveroptions.next.generic.callback = ServerOptions_Event;
- s_serveroptions.next.generic.id = ID_STARTSERVERNEXT;
- s_serveroptions.next.generic.x = 640;
- s_serveroptions.next.generic.y = 480-64-72;
- s_serveroptions.next.generic.statusbar = ServerOptions_StatusBar;
- s_serveroptions.next.width = 128;
- s_serveroptions.next.height = 64;
- s_serveroptions.next.focuspic = GAMESERVER_NEXT1;
-
- s_serveroptions.go.generic.type = MTYPE_BITMAP;
- s_serveroptions.go.generic.name = GAMESERVER_FIGHT0;
- s_serveroptions.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_serveroptions.go.generic.callback = ServerOptions_Event;
- s_serveroptions.go.generic.id = ID_GO;
- s_serveroptions.go.generic.x = 640;
- s_serveroptions.go.generic.y = 480-64;
- s_serveroptions.go.width = 128;
- s_serveroptions.go.height = 64;
- s_serveroptions.go.focuspic = GAMESERVER_FIGHT1;
-
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.banner );
-
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.mappic );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.picframe );
-
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.botSkill );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.player0 );
- for( n = 0; n < PLAYER_SLOTS; n++ ) {
- if( n != 0 ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerType[n] );
- }
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerName[n] );
- if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerTeam[n] );
- }
- }
-
- if( s_serveroptions.gametype < GT_CTF || s_serveroptions.gametype == GT_LMS ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.fraglimit );
- }
- else {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.flaglimit );
- }
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.timelimit );
- if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS && s_serveroptions.gametype != GT_ELIMINATION && s_serveroptions.gametype != GT_CTF_ELIMINATION) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.friendlyfire );
- }
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.pure );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.instantgib );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.rockets );
- if( s_serveroptions.gametype == GT_LMS) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.lmsMode );
- }
- if( s_serveroptions.gametype == GT_CTF_ELIMINATION) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.oneway );
- }
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.pmove );
- if( s_serveroptions.multiplayer ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.lan );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.hostname );
- }
-
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.back );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.next );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.go );
-
- ServerOptions_SetMenuItems();
-}
-
-/*
-=================
-ServerOptions_Cache
-=================
-*/
-void ServerOptions_Cache( void ) {
- trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 );
- trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 );
- trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT0 );
- trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT1 );
- trap_R_RegisterShaderNoMip( GAMESERVER_SELECT );
- trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );
-}
-
-
-/*
-=================
-UI_ServerOptionsMenu
-=================
-*/
-static void UI_ServerOptionsMenu( qboolean multiplayer ) {
- ServerOptions_MenuInit( multiplayer );
- UI_PushMenu( &s_serveroptions.menu );
-}
-
-
-
-/*
-=============================================================================
-
-BOT SELECT MENU *****
-
-=============================================================================
-*/
-
-
-#define BOTSELECT_BACK0 "menu/art_blueish/back_0"
-#define BOTSELECT_BACK1 "menu/art_blueish/back_1"
-#define BOTSELECT_ACCEPT0 "menu/art_blueish/accept_0"
-#define BOTSELECT_ACCEPT1 "menu/art_blueish/accept_1"
-#define BOTSELECT_SELECT "menu/art/opponents_select"
-#define BOTSELECT_SELECTED "menu/art/opponents_selected"
-#define BOTSELECT_ARROWS "menu/art_blueish/gs_arrows_0"
-#define BOTSELECT_ARROWSL "menu/art_blueish/gs_arrows_l"
-#define BOTSELECT_ARROWSR "menu/art_blueish/gs_arrows_r"
-
-#define PLAYERGRID_COLS 4
-#define PLAYERGRID_ROWS 4
-#define MAX_MODELSPERPAGE (PLAYERGRID_ROWS * PLAYERGRID_COLS)
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
-
- menubitmap_s pics[MAX_MODELSPERPAGE];
- menubitmap_s picbuttons[MAX_MODELSPERPAGE];
- menutext_s picnames[MAX_MODELSPERPAGE];
-
- menubitmap_s arrows;
- menubitmap_s left;
- menubitmap_s right;
-
- menubitmap_s go;
- menubitmap_s back;
-
- int numBots;
- int modelpage;
- int numpages;
- int selectedmodel;
- int sortedBotNums[MAX_BOTS];
- char boticons[MAX_MODELSPERPAGE][MAX_QPATH];
- char botnames[MAX_MODELSPERPAGE][16];
-} botSelectInfo_t;
-
-static botSelectInfo_t botSelectInfo;
-
-
-/*
-=================
-UI_BotSelectMenu_SortCompare
-=================
-*/
-static int QDECL UI_BotSelectMenu_SortCompare( const void *arg1, const void *arg2 ) {
- int num1, num2;
- const char *info1, *info2;
- const char *name1, *name2;
-
- num1 = *(int *)arg1;
- num2 = *(int *)arg2;
-
- info1 = UI_GetBotInfoByNumber( num1 );
- info2 = UI_GetBotInfoByNumber( num2 );
-
- name1 = Info_ValueForKey( info1, "name" );
- name2 = Info_ValueForKey( info2, "name" );
-
- return Q_stricmp( name1, name2 );
-}
-
-
-/*
-=================
-UI_BotSelectMenu_BuildList
-=================
-*/
-static void UI_BotSelectMenu_BuildList( void ) {
- int n;
-
- botSelectInfo.modelpage = 0;
- botSelectInfo.numBots = UI_GetNumBots();
- botSelectInfo.numpages = botSelectInfo.numBots / MAX_MODELSPERPAGE;
- if( botSelectInfo.numBots % MAX_MODELSPERPAGE ) {
- botSelectInfo.numpages++;
- }
-
- // initialize the array
- for( n = 0; n < botSelectInfo.numBots; n++ ) {
- botSelectInfo.sortedBotNums[n] = n;
- }
-
- // now sort it
- qsort( botSelectInfo.sortedBotNums, botSelectInfo.numBots, sizeof(botSelectInfo.sortedBotNums[0]), UI_BotSelectMenu_SortCompare );
-}
-
-
-/*
-=================
-ServerPlayerIcon
-=================
-*/
-static void ServerPlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize ) {
- char *skin;
- char model[MAX_QPATH];
-
- Q_strncpyz( model, modelAndSkin, sizeof(model));
- skin = Q_strrchr( model, '/' );
- if ( skin ) {
- *skin++ = '\0';
- }
- else {
- skin = "default";
- }
-
- Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_%s.tga", model, skin );
-
- if( !trap_R_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, "default" ) != 0 ) {
- Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_default.tga", model );
- }
-}
-
-
-/*
-=================
-UI_BotSelectMenu_UpdateGrid
-=================
-*/
-static void UI_BotSelectMenu_UpdateGrid( void ) {
- const char *info;
- int i;
- int j;
-
- j = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
- for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++, j++) {
- if( j < botSelectInfo.numBots ) {
- info = UI_GetBotInfoByNumber( botSelectInfo.sortedBotNums[j] );
- ServerPlayerIcon( Info_ValueForKey( info, "model" ), botSelectInfo.boticons[i], MAX_QPATH );
- Q_strncpyz( botSelectInfo.botnames[i], Info_ValueForKey( info, "name" ), 16 );
- Q_CleanStr( botSelectInfo.botnames[i] );
- botSelectInfo.pics[i].generic.name = botSelectInfo.boticons[i];
- if( BotAlreadySelected( botSelectInfo.botnames[i] ) ) {
- botSelectInfo.picnames[i].color = color_red;
- }
- else {
- botSelectInfo.picnames[i].color = color_orange;
- }
- botSelectInfo.picbuttons[i].generic.flags &= ~((unsigned int)QMF_INACTIVE);
- }
- else {
- // dead slot
- botSelectInfo.pics[i].generic.name = NULL;
- botSelectInfo.picbuttons[i].generic.flags |= QMF_INACTIVE;
- botSelectInfo.botnames[i][0] = 0;
- }
-
- botSelectInfo.pics[i].generic.flags &= ~((unsigned int)QMF_HIGHLIGHT);
- botSelectInfo.pics[i].shader = 0;
- botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
- }
-
- // set selected model
- i = botSelectInfo.selectedmodel % MAX_MODELSPERPAGE;
- botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;
- botSelectInfo.picbuttons[i].generic.flags &= ~((unsigned int)QMF_PULSEIFFOCUS);
-
- if( botSelectInfo.numpages > 1 ) {
- if( botSelectInfo.modelpage > 0 ) {
- botSelectInfo.left.generic.flags &= ~((unsigned int)QMF_INACTIVE);
- }
- else {
- botSelectInfo.left.generic.flags |= QMF_INACTIVE;
- }
-
- if( botSelectInfo.modelpage < (botSelectInfo.numpages - 1) ) {
- botSelectInfo.right.generic.flags &= ~((unsigned int)QMF_INACTIVE);
- }
- else {
- botSelectInfo.right.generic.flags |= QMF_INACTIVE;
- }
- }
- else {
- // hide left/right markers
- botSelectInfo.left.generic.flags |= QMF_INACTIVE;
- botSelectInfo.right.generic.flags |= QMF_INACTIVE;
- }
-}
-
-
-/*
-=================
-UI_BotSelectMenu_Default
-=================
-*/
-static void UI_BotSelectMenu_Default( char *bot ) {
- const char *botInfo;
- const char *test;
- int n;
- int i;
-
- for( n = 0; n < botSelectInfo.numBots; n++ ) {
- botInfo = UI_GetBotInfoByNumber( n );
- test = Info_ValueForKey( botInfo, "name" );
- if( Q_stricmp( bot, test ) == 0 ) {
- break;
- }
- }
- if( n == botSelectInfo.numBots ) {
- botSelectInfo.selectedmodel = 0;
- return;
- }
-
- for( i = 0; i < botSelectInfo.numBots; i++ ) {
- if( botSelectInfo.sortedBotNums[i] == n ) {
- break;
- }
- }
- if( i == botSelectInfo.numBots ) {
- botSelectInfo.selectedmodel = 0;
- return;
- }
-
- botSelectInfo.selectedmodel = i;
-}
-
-
-/*
-=================
-UI_BotSelectMenu_LeftEvent
-=================
-*/
-static void UI_BotSelectMenu_LeftEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- if( botSelectInfo.modelpage > 0 ) {
- botSelectInfo.modelpage--;
- botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
- UI_BotSelectMenu_UpdateGrid();
- }
-}
-
-
-/*
-=================
-UI_BotSelectMenu_RightEvent
-=================
-*/
-static void UI_BotSelectMenu_RightEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- if( botSelectInfo.modelpage < botSelectInfo.numpages - 1 ) {
- botSelectInfo.modelpage++;
- botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
- UI_BotSelectMenu_UpdateGrid();
- }
-}
-
-
-/*
-=================
-UI_BotSelectMenu_BotEvent
-=================
-*/
-static void UI_BotSelectMenu_BotEvent( void* ptr, int event ) {
- int i;
-
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++ ) {
- botSelectInfo.pics[i].generic.flags &= ~((unsigned int)QMF_HIGHLIGHT);
- botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
- }
-
- // set selected
- i = ((menucommon_s*)ptr)->id;
- botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;
- botSelectInfo.picbuttons[i].generic.flags &= ~((unsigned int)QMF_PULSEIFFOCUS);
- botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE + i;
-}
-
-
-/*
-=================
-UI_BotSelectMenu_BackEvent
-=================
-*/
-static void UI_BotSelectMenu_BackEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- UI_PopMenu();
-}
-
-
-/*
-=================
-UI_BotSelectMenu_SelectEvent
-=================
-*/
-static void UI_BotSelectMenu_SelectEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- UI_PopMenu();
-
- s_serveroptions.newBot = qtrue;
- Q_strncpyz( s_serveroptions.newBotName, botSelectInfo.botnames[botSelectInfo.selectedmodel % MAX_MODELSPERPAGE], 16 );
-}
-
-
-/*
-=================
-UI_BotSelectMenu_Cache
-=================
-*/
-void UI_BotSelectMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( BOTSELECT_BACK0 );
- trap_R_RegisterShaderNoMip( BOTSELECT_BACK1 );
- trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT0 );
- trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT1 );
- trap_R_RegisterShaderNoMip( BOTSELECT_SELECT );
- trap_R_RegisterShaderNoMip( BOTSELECT_SELECTED );
- trap_R_RegisterShaderNoMip( BOTSELECT_ARROWS );
- trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSL );
- trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSR );
-}
-
-
-static void UI_BotSelectMenu_Init( char *bot ) {
- int i, j, k;
- int x, y;
-
- memset( &botSelectInfo, 0 ,sizeof(botSelectInfo) );
- botSelectInfo.menu.wrapAround = qtrue;
- botSelectInfo.menu.fullscreen = qtrue;
-
- UI_BotSelectMenu_Cache();
-
- botSelectInfo.banner.generic.type = MTYPE_BTEXT;
- botSelectInfo.banner.generic.x = 320;
- botSelectInfo.banner.generic.y = 16;
- botSelectInfo.banner.string = "SELECT BOT";
- botSelectInfo.banner.color = color_white;
- botSelectInfo.banner.style = UI_CENTER;
-
- y = 80;
- for( i = 0, k = 0; i < PLAYERGRID_ROWS; i++) {
- x = 180;
- for( j = 0; j < PLAYERGRID_COLS; j++, k++ ) {
- botSelectInfo.pics[k].generic.type = MTYPE_BITMAP;
- botSelectInfo.pics[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- botSelectInfo.pics[k].generic.x = x;
- botSelectInfo.pics[k].generic.y = y;
- botSelectInfo.pics[k].generic.name = botSelectInfo.boticons[k];
- botSelectInfo.pics[k].width = 64;
- botSelectInfo.pics[k].height = 64;
- botSelectInfo.pics[k].focuspic = BOTSELECT_SELECTED;
- botSelectInfo.pics[k].focuscolor = colorRed;
-
- botSelectInfo.picbuttons[k].generic.type = MTYPE_BITMAP;
- botSelectInfo.picbuttons[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS;
- botSelectInfo.picbuttons[k].generic.callback = UI_BotSelectMenu_BotEvent;
- botSelectInfo.picbuttons[k].generic.id = k;
- botSelectInfo.picbuttons[k].generic.x = x - 16;
- botSelectInfo.picbuttons[k].generic.y = y - 16;
- botSelectInfo.picbuttons[k].generic.left = x;
- botSelectInfo.picbuttons[k].generic.top = y;
- botSelectInfo.picbuttons[k].generic.right = x + 64;
- botSelectInfo.picbuttons[k].generic.bottom = y + 64;
- botSelectInfo.picbuttons[k].width = 128;
- botSelectInfo.picbuttons[k].height = 128;
- botSelectInfo.picbuttons[k].focuspic = BOTSELECT_SELECT;
- botSelectInfo.picbuttons[k].focuscolor = colorRed;
-
- botSelectInfo.picnames[k].generic.type = MTYPE_TEXT;
- botSelectInfo.picnames[k].generic.flags = QMF_SMALLFONT;
- botSelectInfo.picnames[k].generic.x = x + 32;
- botSelectInfo.picnames[k].generic.y = y + 64;
- botSelectInfo.picnames[k].string = botSelectInfo.botnames[k];
- botSelectInfo.picnames[k].color = color_orange;
- botSelectInfo.picnames[k].style = UI_CENTER|UI_SMALLFONT;
-
- x += (64 + 6);
- }
- y += (64 + SMALLCHAR_HEIGHT + 6);
- }
-
- botSelectInfo.arrows.generic.type = MTYPE_BITMAP;
- botSelectInfo.arrows.generic.name = BOTSELECT_ARROWS;
- botSelectInfo.arrows.generic.flags = QMF_INACTIVE;
- botSelectInfo.arrows.generic.x = 260;
- botSelectInfo.arrows.generic.y = 440;
- botSelectInfo.arrows.width = 128;
- botSelectInfo.arrows.height = 32;
-
- botSelectInfo.left.generic.type = MTYPE_BITMAP;
- botSelectInfo.left.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- botSelectInfo.left.generic.callback = UI_BotSelectMenu_LeftEvent;
- botSelectInfo.left.generic.x = 260;
- botSelectInfo.left.generic.y = 440;
- botSelectInfo.left.width = 64;
- botSelectInfo.left.height = 32;
- botSelectInfo.left.focuspic = BOTSELECT_ARROWSL;
-
- botSelectInfo.right.generic.type = MTYPE_BITMAP;
- botSelectInfo.right.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- botSelectInfo.right.generic.callback = UI_BotSelectMenu_RightEvent;
- botSelectInfo.right.generic.x = 321;
- botSelectInfo.right.generic.y = 440;
- botSelectInfo.right.width = 64;
- botSelectInfo.right.height = 32;
- botSelectInfo.right.focuspic = BOTSELECT_ARROWSR;
-
- botSelectInfo.back.generic.type = MTYPE_BITMAP;
- botSelectInfo.back.generic.name = BOTSELECT_BACK0;
- botSelectInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- botSelectInfo.back.generic.callback = UI_BotSelectMenu_BackEvent;
- botSelectInfo.back.generic.x = 0;
- botSelectInfo.back.generic.y = 480-64;
- botSelectInfo.back.width = 128;
- botSelectInfo.back.height = 64;
- botSelectInfo.back.focuspic = BOTSELECT_BACK1;
-
- botSelectInfo.go.generic.type = MTYPE_BITMAP;
- botSelectInfo.go.generic.name = BOTSELECT_ACCEPT0;
- botSelectInfo.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- botSelectInfo.go.generic.callback = UI_BotSelectMenu_SelectEvent;
- botSelectInfo.go.generic.x = 640;
- botSelectInfo.go.generic.y = 480-64;
- botSelectInfo.go.width = 128;
- botSelectInfo.go.height = 64;
- botSelectInfo.go.focuspic = BOTSELECT_ACCEPT1;
-
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.banner );
- for( i = 0; i < MAX_MODELSPERPAGE; i++ ) {
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.pics[i] );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.picbuttons[i] );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.picnames[i] );
- }
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.arrows );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.left );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.right );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.back );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.go );
-
- UI_BotSelectMenu_BuildList();
- UI_BotSelectMenu_Default( bot );
- botSelectInfo.modelpage = botSelectInfo.selectedmodel / MAX_MODELSPERPAGE;
- UI_BotSelectMenu_UpdateGrid();
-}
-
-
-/*
-=================
-UI_BotSelectMenu
-=================
-*/
-void UI_BotSelectMenu( char *bot ) {
- UI_BotSelectMenu_Init( bot );
- UI_PushMenu( &botSelectInfo.menu );
-}
diff --git a/game/code/q3_ui/ui_startserver.c.org b/game/code/q3_ui/ui_startserver.c.org
deleted file mode 100644
index e0af3e4..0000000
--- a/game/code/q3_ui/ui_startserver.c.org
+++ /dev/null
@@ -1,2209 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=============================================================================
-
-START SERVER MENU *****
-
-=============================================================================
-*/
-
-
-#include "ui_local.h"
-
-
-#define GAMESERVER_BACK0 "menu/art/back_0"
-#define GAMESERVER_BACK1 "menu/art/back_1"
-#define GAMESERVER_NEXT0 "menu/art/next_0"
-#define GAMESERVER_NEXT1 "menu/art/next_1"
-#define GAMESERVER_FRAMEL "menu/art/frame2_l"
-#define GAMESERVER_FRAMER "menu/art/frame1_r"
-#define GAMESERVER_SELECT "menu/art/maps_select"
-#define GAMESERVER_SELECTED "menu/art/maps_selected"
-#define GAMESERVER_FIGHT0 "menu/art/fight_0"
-#define GAMESERVER_FIGHT1 "menu/art/fight_1"
-#define GAMESERVER_UNKNOWNMAP "menu/art/unknownmap"
-#define GAMESERVER_ARROWS "menu/art/gs_arrows_0"
-#define GAMESERVER_ARROWSL "menu/art/gs_arrows_l"
-#define GAMESERVER_ARROWSR "menu/art/gs_arrows_r"
-
-#define MAX_MAPROWS 4
-#define MAX_MAPCOLS 2
-#define MAX_MAPSPERPAGE (MAX_MAPROWS * MAX_MAPCOLS)
-
-//#define MAX_SERVERSTEXT 8192
-
-#define MAX_SERVERMAPS MAX_ARENAS
-#define MAX_NAMELENGTH 16
-
-#define ID_GAMETYPE 10
-#define ID_PICTURES 11 // 12, 13, 14, 15, 16, 17, 18
-#define ID_PREVPAGE 19
-#define ID_NEXTPAGE 20
-#define ID_STARTSERVERBACK 21
-#define ID_STARTSERVERNEXT 22
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menulist_s gametype;
- menubitmap_s mappics[MAX_MAPSPERPAGE];
- menubitmap_s mapbuttons[MAX_MAPSPERPAGE];
- menubitmap_s arrows;
- menubitmap_s prevpage;
- menubitmap_s nextpage;
- menubitmap_s back;
- menubitmap_s next;
-
- menutext_s mapname;
- menubitmap_s item_null;
-
- qboolean multiplayer;
- int currentmap;
- int nummaps;
- int page;
- int maxpages;
- char maplist[MAX_SERVERMAPS][MAX_NAMELENGTH];
- int mapGamebits[MAX_SERVERMAPS];
-} startserver_t;
-
-static startserver_t s_startserver;
-
-static const char *gametype_items[] = {
- "Free For All",
- "Team Deathmatch",
- "Tournament",
- "Capture the Flag",
- "One Flag Capture",
- "Overload",
- "Harvester",
- "Elimination",
- "CTF Elimination",
- "Last Man Standing",
- "Double Domination",
- "Domination",
- NULL
-};
-
-static int gametype_remap[] = {
- GT_FFA,
- GT_TEAM,
- GT_TOURNAMENT,
- GT_CTF,
- GT_1FCTF,
- GT_OBELISK,
- GT_HARVESTER,
- GT_ELIMINATION,
- GT_CTF_ELIMINATION,
- GT_LMS,
- GT_DOUBLE_D,
- GT_DOMINATION };
-
-static int gametype_remap2[] = {
- 0,
- 2,
- 0,
- 1,
- 3,
- 4,
- 5,
- 6,
- 7,
- 8,
- 9,
- 10,
- 11 }; //this works and should increment for more gametypes
-
-// use ui_servers2.c definition
-//extern const char* punkbuster_items[];
-
-static void UI_ServerOptionsMenu( qboolean multiplayer );
-
-
-/*
-=================
-GametypeBits from arenas.txt + .arena files
-=================
-*/
-static int GametypeBits( char *string ) {
- int bits;
- char *p;
- char *token;
-
- bits = 0;
- p = string;
- while( 1 ) {
- token = COM_ParseExt( &p, qfalse );
- if( token[0] == 0 ) {
- break;
- }
-
- if( Q_stricmp( token, "ffa" ) == 0 ) {
- bits |= 1 << GT_FFA;
- continue;
- }
-
- if( Q_stricmp( token, "tourney" ) == 0 ) {
- bits |= 1 << GT_TOURNAMENT;
- continue;
- }
-
- if( Q_stricmp( token, "single" ) == 0 ) {
- bits |= 1 << GT_SINGLE_PLAYER;
- continue;
- }
-
- if( Q_stricmp( token, "team" ) == 0 ) {
- bits |= 1 << GT_TEAM;
- continue;
- }
-
- if( Q_stricmp( token, "ctf" ) == 0 ) {
- bits |= 1 << GT_CTF;
- continue;
- }
-
- if( Q_stricmp( token, "oneflag" ) == 0 ) {
- bits |= 1 << GT_1FCTF;
- continue;
- }
-
- if( Q_stricmp( token, "overload" ) == 0 ) {
- bits |= 1 << GT_OBELISK;
- continue;
- }
-
- if( Q_stricmp( token, "harvester" ) == 0 ) {
- bits |= 1 << GT_HARVESTER;
- continue;
- }
-
- if( Q_stricmp( token, "elimination" ) == 0 ) {
- bits |= 1 << GT_ELIMINATION;
- continue;
- }
-
- if( Q_stricmp( token, "ctfelimination" ) == 0 ) {
- bits |= 1 << GT_CTF_ELIMINATION;
- continue;
- }
-
- if( Q_stricmp( token, "lms" ) == 0 ) {
- bits |= 1 << GT_LMS;
- continue;
- }
- if( Q_stricmp( token, "dd" ) == 0 ) {
- bits |= 1 << GT_DOUBLE_D;
- continue;
- }
-
- if( Q_stricmp( token, "dom" ) == 0 ) {
- bits |= 1 << GT_DOMINATION;
- continue;
- }
-}
- return bits;
-}
-
-
-/*
-=================
-StartServer_Update
-=================
-*/
-static void StartServer_Update( void ) {
- int i;
- int top;
- static char picname[MAX_MAPSPERPAGE][64];
-
- top = s_startserver.page*MAX_MAPSPERPAGE;
-
- for (i=0; i<MAX_MAPSPERPAGE; i++)
- {
- if (top+i >= s_startserver.nummaps)
- break;
-
- Com_sprintf( picname[i], sizeof(picname[i]), "levelshots/%s", s_startserver.maplist[top+i] );
-
- s_startserver.mappics[i].generic.flags &= ~((unsigned int)QMF_HIGHLIGHT);
- s_startserver.mappics[i].generic.name = picname[i];
- s_startserver.mappics[i].shader = 0;
-
- // reset
- s_startserver.mapbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
- s_startserver.mapbuttons[i].generic.flags &= ~((unsigned int)QMF_INACTIVE);
- }
-
- for (; i<MAX_MAPSPERPAGE; i++)
- {
- s_startserver.mappics[i].generic.flags &= ~((unsigned int)QMF_HIGHLIGHT);
- s_startserver.mappics[i].generic.name = NULL;
- s_startserver.mappics[i].shader = 0;
-
- // disable
- s_startserver.mapbuttons[i].generic.flags &= ~((unsigned int)QMF_PULSEIFFOCUS);
- s_startserver.mapbuttons[i].generic.flags |= QMF_INACTIVE;
- }
-
-
- // no servers to start
- if( !s_startserver.nummaps ) {
- s_startserver.next.generic.flags |= QMF_INACTIVE;
-
- // set the map name
- strcpy( s_startserver.mapname.string, "NO MAPS FOUND" );
- }
- else {
- // set the highlight
- s_startserver.next.generic.flags &= ~((unsigned int)QMF_INACTIVE);
- i = s_startserver.currentmap - top;
- if ( i >=0 && i < MAX_MAPSPERPAGE )
- {
- s_startserver.mappics[i].generic.flags |= QMF_HIGHLIGHT;
- s_startserver.mapbuttons[i].generic.flags &= ~((unsigned int)QMF_PULSEIFFOCUS);
- }
-
- // set the map name
- strcpy( s_startserver.mapname.string, s_startserver.maplist[s_startserver.currentmap] );
- }
-
- Q_strupr( s_startserver.mapname.string );
-}
-
-
-/*
-=================
-StartServer_MapEvent
-=================
-*/
-static void StartServer_MapEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED) {
- return;
- }
-
- s_startserver.currentmap = (s_startserver.page*MAX_MAPSPERPAGE) + (((menucommon_s*)ptr)->id - ID_PICTURES);
- StartServer_Update();
-}
-
-
-/*
-=================
-StartServer_GametypeEvent
-=================
-*/
-static void StartServer_GametypeEvent( void* ptr, int event ) {
- int i;
- int count;
- int gamebits;
- int matchbits;
- const char *info;
-
- if( event != QM_ACTIVATED) {
- return;
- }
-
- count = UI_GetNumArenas();
- s_startserver.nummaps = 0;
- matchbits = 1 << gametype_remap[s_startserver.gametype.curvalue];
- if( gametype_remap[s_startserver.gametype.curvalue] == GT_FFA || gametype_remap[s_startserver.gametype.curvalue] == GT_LMS ) {
- matchbits |= ( 1 << GT_SINGLE_PLAYER );
- }
- for( i = 0; i < count; i++ ) {
- info = UI_GetArenaInfoByNumber( i );
-
- gamebits = GametypeBits( Info_ValueForKey( info, "type") );
- if( !( gamebits & matchbits ) ) {
- continue;
- }
-
- Q_strncpyz( s_startserver.maplist[s_startserver.nummaps], Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
- Q_strupr( s_startserver.maplist[s_startserver.nummaps] );
- s_startserver.mapGamebits[s_startserver.nummaps] = gamebits;
- s_startserver.nummaps++;
- }
- s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE;
- s_startserver.page = 0;
- s_startserver.currentmap = 0;
-
- StartServer_Update();
-}
-
-
-/*
-=================
-StartServer_MenuEvent
-=================
-*/
-static void StartServer_MenuEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_PREVPAGE:
- if( s_startserver.page > 0 ) {
- s_startserver.page--;
- StartServer_Update();
- }
- break;
-
- case ID_NEXTPAGE:
- if( s_startserver.page < s_startserver.maxpages - 1 ) {
- s_startserver.page++;
- StartServer_Update();
- }
- break;
-
- case ID_STARTSERVERNEXT:
- trap_Cvar_SetValue( "g_gameType", gametype_remap[s_startserver.gametype.curvalue] );
- UI_ServerOptionsMenu( s_startserver.multiplayer );
- break;
-
- case ID_STARTSERVERBACK:
- UI_PopMenu();
- break;
- }
-}
-
-
-/*
-===============
-StartServer_LevelshotDraw
-===============
-*/
-static void StartServer_LevelshotDraw( void *self ) {
- menubitmap_s *b;
- int x;
- int y;
- int w;
- int h;
- int n;
-
- b = (menubitmap_s *)self;
-
- if( !b->generic.name ) {
- return;
- }
-
- if( b->generic.name && !b->shader ) {
- b->shader = trap_R_RegisterShaderNoMip( b->generic.name );
- if( !b->shader && b->errorpic ) {
- b->shader = trap_R_RegisterShaderNoMip( b->errorpic );
- }
- }
-
- if( b->focuspic && !b->focusshader ) {
- b->focusshader = trap_R_RegisterShaderNoMip( b->focuspic );
- }
-
- x = b->generic.x;
- y = b->generic.y;
- w = b->width;
- h = b->height;
- if( b->shader ) {
- UI_DrawHandlePic( x, y, w, h, b->shader );
- }
-
- x = b->generic.x;
- y = b->generic.y + b->height;
- UI_FillRect( x, y, b->width, 28, colorBlack );
-
- x += b->width / 2;
- y += 4;
- n = s_startserver.page * MAX_MAPSPERPAGE + b->generic.id - ID_PICTURES;
- UI_DrawString( x, y, s_startserver.maplist[n], UI_CENTER|UI_SMALLFONT, color_orange );
-
- x = b->generic.x;
- y = b->generic.y;
- w = b->width;
- h = b->height + 28;
- if( b->generic.flags & QMF_HIGHLIGHT ) {
- UI_DrawHandlePic( x, y, w, h, b->focusshader );
- }
-}
-
-
-/*
-=================
-StartServer_MenuInit
-=================
-*/
-static void StartServer_MenuInit( void ) {
- int i;
- int x;
- int y;
- static char mapnamebuffer[64];
-
- // zero set all our globals
- memset( &s_startserver, 0 ,sizeof(startserver_t) );
-
- StartServer_Cache();
-
- s_startserver.menu.wrapAround = qtrue;
- s_startserver.menu.fullscreen = qtrue;
-
- s_startserver.banner.generic.type = MTYPE_BTEXT;
- s_startserver.banner.generic.x = 320;
- s_startserver.banner.generic.y = 16;
- s_startserver.banner.string = "GAME SERVER";
- s_startserver.banner.color = color_white;
- s_startserver.banner.style = UI_CENTER;
-
- s_startserver.framel.generic.type = MTYPE_BITMAP;
- s_startserver.framel.generic.name = GAMESERVER_FRAMEL;
- s_startserver.framel.generic.flags = QMF_INACTIVE;
- s_startserver.framel.generic.x = 0;
- s_startserver.framel.generic.y = 78;
- s_startserver.framel.width = 256;
- s_startserver.framel.height = 329;
-
- s_startserver.framer.generic.type = MTYPE_BITMAP;
- s_startserver.framer.generic.name = GAMESERVER_FRAMER;
- s_startserver.framer.generic.flags = QMF_INACTIVE;
- s_startserver.framer.generic.x = 376;
- s_startserver.framer.generic.y = 76;
- s_startserver.framer.width = 256;
- s_startserver.framer.height = 334;
-
- s_startserver.gametype.generic.type = MTYPE_SPINCONTROL;
- s_startserver.gametype.generic.name = "Game Type:";
- s_startserver.gametype.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_startserver.gametype.generic.callback = StartServer_GametypeEvent;
- s_startserver.gametype.generic.id = ID_GAMETYPE;
- s_startserver.gametype.generic.x = 320 - 24;
- s_startserver.gametype.generic.y = 368;
- s_startserver.gametype.itemnames = gametype_items;
-
- for (i=0; i<MAX_MAPSPERPAGE; i++)
- {
- //x = (i % MAX_MAPCOLS) * (128+8) + 188;
- //y = (i / MAX_MAPROWS) * (128+8) + 96;
- x = (640-MAX_MAPROWS*140)/2 + ( (i % MAX_MAPROWS) * 140 );
- y = 96 + ( (i / MAX_MAPROWS) * 140 );
-
- s_startserver.mappics[i].generic.type = MTYPE_BITMAP;
- s_startserver.mappics[i].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_startserver.mappics[i].generic.x = x;
- s_startserver.mappics[i].generic.y = y;
- s_startserver.mappics[i].generic.id = ID_PICTURES+i;
- s_startserver.mappics[i].width = 128;
- s_startserver.mappics[i].height = 96;
- s_startserver.mappics[i].focuspic = GAMESERVER_SELECTED;
- s_startserver.mappics[i].errorpic = GAMESERVER_UNKNOWNMAP;
- s_startserver.mappics[i].generic.ownerdraw = StartServer_LevelshotDraw;
-
- s_startserver.mapbuttons[i].generic.type = MTYPE_BITMAP;
- s_startserver.mapbuttons[i].generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_NODEFAULTINIT;
- s_startserver.mapbuttons[i].generic.id = ID_PICTURES+i;
- s_startserver.mapbuttons[i].generic.callback = StartServer_MapEvent;
- s_startserver.mapbuttons[i].generic.x = x - 30;
- s_startserver.mapbuttons[i].generic.y = y - 32;
- s_startserver.mapbuttons[i].width = 256;
- s_startserver.mapbuttons[i].height = 248;
- s_startserver.mapbuttons[i].generic.left = x;
- s_startserver.mapbuttons[i].generic.top = y;
- s_startserver.mapbuttons[i].generic.right = x + 128;
- s_startserver.mapbuttons[i].generic.bottom = y + 128;
- s_startserver.mapbuttons[i].focuspic = GAMESERVER_SELECT;
- }
-
- s_startserver.arrows.generic.type = MTYPE_BITMAP;
- s_startserver.arrows.generic.name = GAMESERVER_ARROWS;
- s_startserver.arrows.generic.flags = QMF_INACTIVE;
- s_startserver.arrows.generic.x = 260;
- s_startserver.arrows.generic.y = 400;
- s_startserver.arrows.width = 128;
- s_startserver.arrows.height = 32;
-
- s_startserver.prevpage.generic.type = MTYPE_BITMAP;
- s_startserver.prevpage.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_startserver.prevpage.generic.callback = StartServer_MenuEvent;
- s_startserver.prevpage.generic.id = ID_PREVPAGE;
- s_startserver.prevpage.generic.x = 260;
- s_startserver.prevpage.generic.y = 400;
- s_startserver.prevpage.width = 64;
- s_startserver.prevpage.height = 32;
- s_startserver.prevpage.focuspic = GAMESERVER_ARROWSL;
-
- s_startserver.nextpage.generic.type = MTYPE_BITMAP;
- s_startserver.nextpage.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_startserver.nextpage.generic.callback = StartServer_MenuEvent;
- s_startserver.nextpage.generic.id = ID_NEXTPAGE;
- s_startserver.nextpage.generic.x = 321;
- s_startserver.nextpage.generic.y = 400;
- s_startserver.nextpage.width = 64;
- s_startserver.nextpage.height = 32;
- s_startserver.nextpage.focuspic = GAMESERVER_ARROWSR;
-
- s_startserver.mapname.generic.type = MTYPE_PTEXT;
- s_startserver.mapname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
- s_startserver.mapname.generic.x = 320;
- s_startserver.mapname.generic.y = 440;
- s_startserver.mapname.string = mapnamebuffer;
- s_startserver.mapname.style = UI_CENTER|UI_BIGFONT;
- s_startserver.mapname.color = text_color_normal;
-
- s_startserver.back.generic.type = MTYPE_BITMAP;
- s_startserver.back.generic.name = GAMESERVER_BACK0;
- s_startserver.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_startserver.back.generic.callback = StartServer_MenuEvent;
- s_startserver.back.generic.id = ID_STARTSERVERBACK;
- s_startserver.back.generic.x = 0;
- s_startserver.back.generic.y = 480-64;
- s_startserver.back.width = 128;
- s_startserver.back.height = 64;
- s_startserver.back.focuspic = GAMESERVER_BACK1;
-
- s_startserver.next.generic.type = MTYPE_BITMAP;
- s_startserver.next.generic.name = GAMESERVER_NEXT0;
- s_startserver.next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_startserver.next.generic.callback = StartServer_MenuEvent;
- s_startserver.next.generic.id = ID_STARTSERVERNEXT;
- s_startserver.next.generic.x = 640;
- s_startserver.next.generic.y = 480-64;
- s_startserver.next.width = 128;
- s_startserver.next.height = 64;
- s_startserver.next.focuspic = GAMESERVER_NEXT1;
-
- s_startserver.item_null.generic.type = MTYPE_BITMAP;
- s_startserver.item_null.generic.flags = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;
- s_startserver.item_null.generic.x = 0;
- s_startserver.item_null.generic.y = 0;
- s_startserver.item_null.width = 640;
- s_startserver.item_null.height = 480;
-
- Menu_AddItem( &s_startserver.menu, &s_startserver.banner );
- Menu_AddItem( &s_startserver.menu, &s_startserver.framel );
- Menu_AddItem( &s_startserver.menu, &s_startserver.framer );
-
- Menu_AddItem( &s_startserver.menu, &s_startserver.gametype );
- for (i=0; i<MAX_MAPSPERPAGE; i++)
- {
- Menu_AddItem( &s_startserver.menu, &s_startserver.mappics[i] );
- Menu_AddItem( &s_startserver.menu, &s_startserver.mapbuttons[i] );
- }
-
- Menu_AddItem( &s_startserver.menu, &s_startserver.arrows );
- Menu_AddItem( &s_startserver.menu, &s_startserver.prevpage );
- Menu_AddItem( &s_startserver.menu, &s_startserver.nextpage );
- Menu_AddItem( &s_startserver.menu, &s_startserver.back );
- Menu_AddItem( &s_startserver.menu, &s_startserver.next );
- Menu_AddItem( &s_startserver.menu, &s_startserver.mapname );
- Menu_AddItem( &s_startserver.menu, &s_startserver.item_null );
-
- StartServer_GametypeEvent( NULL, QM_ACTIVATED );
-}
-
-
-/*
-=================
-StartServer_Cache
-=================
-*/
-void StartServer_Cache( void )
-{
- int i;
- const char *info;
- qboolean precache;
- char picname[64];
-
- trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 );
- trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 );
- trap_R_RegisterShaderNoMip( GAMESERVER_NEXT0 );
- trap_R_RegisterShaderNoMip( GAMESERVER_NEXT1 );
- trap_R_RegisterShaderNoMip( GAMESERVER_FRAMEL );
- trap_R_RegisterShaderNoMip( GAMESERVER_FRAMER );
- trap_R_RegisterShaderNoMip( GAMESERVER_SELECT );
- trap_R_RegisterShaderNoMip( GAMESERVER_SELECTED );
- trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );
- trap_R_RegisterShaderNoMip( GAMESERVER_ARROWS );
- trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSL );
- trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSR );
-
- precache = trap_Cvar_VariableValue("com_buildscript");
-
- s_startserver.nummaps = UI_GetNumArenas();
-
- for( i = 0; i < s_startserver.nummaps; i++ ) {
- info = UI_GetArenaInfoByNumber( i );
-
- Q_strncpyz( s_startserver.maplist[i], Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
- Q_strupr( s_startserver.maplist[i] );
- s_startserver.mapGamebits[i] = GametypeBits( Info_ValueForKey( info, "type") );
-
- if( precache ) {
- Com_sprintf( picname, sizeof(picname), "levelshots/%s", s_startserver.maplist[i] );
- trap_R_RegisterShaderNoMip(picname);
- }
- }
-
- s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE;
-}
-
-
-/*
-=================
-UI_StartServerMenu
-=================
-*/
-void UI_StartServerMenu( qboolean multiplayer ) {
- StartServer_MenuInit();
- s_startserver.multiplayer = multiplayer;
- UI_PushMenu( &s_startserver.menu );
-}
-
-
-
-/*
-=============================================================================
-
-SERVER OPTIONS MENU *****
-
-=============================================================================
-*/
-
-#define ID_PLAYER_TYPE 25
-#define ID_MAXCLIENTS 26
-//#define ID_DEDICATED 27
-#define ID_GO 28
-#define ID_BACK 29
-
-#define PLAYER_SLOTS 12
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
-
- menubitmap_s mappic;
- menubitmap_s picframe;
-
-// menulist_s dedicated;
- menufield_s timelimit;
- menufield_s fraglimit;
- menufield_s flaglimit;
- menuradiobutton_s friendlyfire;
- menufield_s hostname;
- menuradiobutton_s pure;
- //Here are the elimination stuff
- menuradiobutton_s instantgib;
- menuradiobutton_s rockets;
- menulist_s lmsMode;
- menulist_s botSkill;
-
- menutext_s player0;
- menulist_s playerType[PLAYER_SLOTS];
- menutext_s playerName[PLAYER_SLOTS];
- menulist_s playerTeam[PLAYER_SLOTS];
-
- menubitmap_s go;
- menubitmap_s next;
- menubitmap_s back;
-
- qboolean multiplayer;
- int gametype;
- char mapnamebuffer[32];
- char playerNameBuffers[PLAYER_SLOTS][16];
-
- qboolean newBot;
- int newBotIndex;
- char newBotName[16];
-
- //menulist_s punkbuster;
-} serveroptions_t;
-
-static serveroptions_t s_serveroptions;
-
-/*static const char *dedicated_list[] = {
- "No",
- "LAN",
- "Internet",
- NULL
-};*/
-
-static const char *playerType_list[] = {
- "Open",
- "Bot",
- "----",
- NULL
-};
-
-static const char *playerTeam_list[] = {
- "Blue",
- "Red",
- NULL
-};
-
-static const char *botSkill_list[] = {
- "I Can Win",
- "Bring It On",
- "Hurt Me Plenty",
- "Hardcore",
- "Nightmare!",
- NULL
-};
-
-//Elimiantion - LMS mode
-static const char *lmsMode_list[] = {
- "Round+OT",
- "Round-OT",
- "Kill+OT",
- "Kill-OT",
- NULL
-};
-
-/*
-=================
-BotAlreadySelected
-=================
-*/
-static qboolean BotAlreadySelected( const char *checkName ) {
- int n;
-
- for( n = 1; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue != 1 ) {
- continue;
- }
- if( (s_serveroptions.gametype >= GT_TEAM) && s_serveroptions.gametype != GT_LMS &&
- (s_serveroptions.playerTeam[n].curvalue != s_serveroptions.playerTeam[s_serveroptions.newBotIndex].curvalue ) ) {
- continue;
- }
- if( Q_stricmp( checkName, s_serveroptions.playerNameBuffers[n] ) == 0 ) {
- return qtrue;
- }
- }
-
- return qfalse;
-}
-
-
-/*
-=================
-ServerOptions_Start
-=================
-*/
-static void ServerOptions_Start( void ) {
- int timelimit;
- int fraglimit;
- int maxclients;
-// int dedicated;
- int friendlyfire;
- int flaglimit;
- int pure;
- int instantgib;
- int rockets;
- int lmsMode;
- int skill;
- int n;
- char buf[64];
-
-
- timelimit = atoi( s_serveroptions.timelimit.field.buffer );
- fraglimit = atoi( s_serveroptions.fraglimit.field.buffer );
- flaglimit = atoi( s_serveroptions.flaglimit.field.buffer );
-// dedicated = s_serveroptions.dedicated.curvalue;
- friendlyfire = s_serveroptions.friendlyfire.curvalue;
- pure = s_serveroptions.pure.curvalue;
- instantgib = s_serveroptions.instantgib.curvalue;
- rockets = s_serveroptions.rockets.curvalue;
- //Sago: For some reason you need to add 1 to curvalue to get the UI to show the right thing
- lmsMode = s_serveroptions.lmsMode.curvalue + 1;
- skill = s_serveroptions.botSkill.curvalue + 1;
-
- //set maxclients
- for( n = 0, maxclients = 0; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue == 2 ) {
- continue;
- }
- if( (s_serveroptions.playerType[n].curvalue == 1) && (s_serveroptions.playerNameBuffers[n][0] == 0) ) {
- continue;
- }
- maxclients++;
- }
-
- switch( s_serveroptions.gametype ) {
- case GT_FFA:
- default:
- trap_Cvar_SetValue( "ui_ffa_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_ffa_timelimit", timelimit );
- break;
-
- case GT_TOURNAMENT:
- trap_Cvar_SetValue( "ui_tourney_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_tourney_timelimit", timelimit );
- break;
-
- case GT_TEAM:
- trap_Cvar_SetValue( "ui_team_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_team_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_team_friendlt", friendlyfire );
- break;
-
- case GT_CTF:
- trap_Cvar_SetValue( "ui_ctf_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_ctf_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_ctf_friendlt", friendlyfire );
- break;
-
- case GT_1FCTF:
- trap_Cvar_SetValue( "ui_1fctf_capturelimit", fraglimit );
- trap_Cvar_SetValue( "ui_1fctf_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_1fctf_friendlt", friendlyfire );
- break;
-
- case GT_OBELISK:
- trap_Cvar_SetValue( "ui_overload_capturelimit", fraglimit );
- trap_Cvar_SetValue( "ui_overload_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_overload_friendlt", friendlyfire );
- break;
-
- case GT_HARVESTER:
- trap_Cvar_SetValue( "ui_harvester_capturelimit", fraglimit );
- trap_Cvar_SetValue( "ui_harvester_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_harvester_friendlt", friendlyfire );
- break;
-
- case GT_ELIMINATION:
- trap_Cvar_SetValue( "ui_elimination_capturelimit", fraglimit );
- trap_Cvar_SetValue( "ui_elimination_timelimit", timelimit );
- //trap_Cvar_SetValue( "ui_elimination_friendlt", friendlyfire );
- break;
-
- case GT_CTF_ELIMINATION:
- trap_Cvar_SetValue( "ui_ctf_elimination_capturelimit", fraglimit );
- trap_Cvar_SetValue( "ui_ctf_elimination_timelimit", timelimit );
- //trap_Cvar_SetValue( "ui_ctf_elimination_friendlt", friendlyfire );
- break;
-
- case GT_LMS:
- trap_Cvar_SetValue( "ui_lms_fraglimit", fraglimit );
- trap_Cvar_SetValue( "ui_lms_timelimit", timelimit );
- break;
-
- case GT_DOUBLE_D:
- trap_Cvar_SetValue( "ui_dd_capturelimit", fraglimit );
- trap_Cvar_SetValue( "ui_dd_timelimit", timelimit );
- trap_Cvar_SetValue( "ui_dd_friendlt", friendlyfire );
- break;
- }
-
- trap_Cvar_SetValue( "sv_maxclients", Com_Clamp( 0, 12, maxclients ) );
-// trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, dedicated ) );
- trap_Cvar_SetValue ("timelimit", Com_Clamp( 0, timelimit, timelimit ) );
- trap_Cvar_SetValue ("fraglimit", Com_Clamp( 0, fraglimit, fraglimit ) );
- trap_Cvar_SetValue ("capturelimit", Com_Clamp( 0, flaglimit, flaglimit ) );
- trap_Cvar_SetValue( "g_friendlyfire", friendlyfire );
- trap_Cvar_SetValue( "sv_pure", pure );
- trap_Cvar_SetValue( "g_instantgib", instantgib );
- trap_Cvar_SetValue( "g_rockets", rockets );
- trap_Cvar_SetValue( "g_lms_mode", lmsMode-1);
- trap_Cvar_Set("sv_hostname", s_serveroptions.hostname.field.buffer );
-
- //trap_Cvar_SetValue( "sv_punkbuster", s_serveroptions.punkbuster.curvalue );
-
- // the wait commands will allow the dedicated to take effect
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", s_startserver.maplist[s_startserver.currentmap] ) );
-
- // add bots
- trap_Cmd_ExecuteText( EXEC_APPEND, "wait 3\n" );
- for( n = 1; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue != 1 ) {
- continue;
- }
- if( s_serveroptions.playerNameBuffers[n][0] == 0 ) {
- continue;
- }
- if( s_serveroptions.playerNameBuffers[n][0] == '-' ) {
- continue;
- }
- if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
- Com_sprintf( buf, sizeof(buf), "addbot %s %i %s\n", s_serveroptions.playerNameBuffers[n], skill,
- playerTeam_list[s_serveroptions.playerTeam[n].curvalue] );
- }
- else {
- Com_sprintf( buf, sizeof(buf), "addbot %s %i\n", s_serveroptions.playerNameBuffers[n], skill );
- }
- trap_Cmd_ExecuteText( EXEC_APPEND, buf );
- }
-
- // set player's team
- if( /*dedicated == 0 &&*/ s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait 5; team %s\n", playerTeam_list[s_serveroptions.playerTeam[0].curvalue] ) );
- }
-}
-
-
-/*
-=================
-ServerOptions_InitPlayerItems
-=================
-*/
-static void ServerOptions_InitPlayerItems( void ) {
- int n;
- int v;
-
- // init types
- if( s_serveroptions.multiplayer ) {
- v = 0; // open
- }
- else {
- v = 1; // bot
- }
-
- for( n = 0; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerType[n].curvalue = v;
- }
-
- if( s_serveroptions.multiplayer && (s_serveroptions.gametype < GT_TEAM || s_serveroptions.gametype == GT_LMS ) ) {
- for( n = 8; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerType[n].curvalue = 2;
- }
- }
-
- // if not a dedicated server, first slot is reserved for the human on the server
-// if( s_serveroptions.dedicated.curvalue == 0 ) {
- // human
- s_serveroptions.playerType[0].generic.flags |= QMF_INACTIVE;
- s_serveroptions.playerType[0].curvalue = 0;
- trap_Cvar_VariableStringBuffer( "name", s_serveroptions.playerNameBuffers[0], sizeof(s_serveroptions.playerNameBuffers[0]) );
- Q_CleanStr( s_serveroptions.playerNameBuffers[0] );
-// }
-
- // init teams
- if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
- for( n = 0; n < (PLAYER_SLOTS / 2); n++ ) {
- s_serveroptions.playerTeam[n].curvalue = 0;
- }
- for( ; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerTeam[n].curvalue = 1;
- }
- }
- else {
- for( n = 0; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- }
- }
-}
-
-
-/*
-=================
-ServerOptions_SetPlayerItems
-=================
-*/
-static void ServerOptions_SetPlayerItems( void ) {
- int start;
- int n;
-
- // types
-// for( n = 0; n < PLAYER_SLOTS; n++ ) {
-// if( (!s_serveroptions.multiplayer) && (n > 0) && (s_serveroptions.playerType[n].curvalue == 0) ) {
-// s_serveroptions.playerType[n].curvalue = 1;
-// }
-// }
-
- // names
-// if( s_serveroptions.dedicated.curvalue == 0 ) {
- s_serveroptions.player0.string = "Human";
- s_serveroptions.playerName[0].generic.flags &= ~((unsigned int)QMF_HIDDEN);
-
- start = 1;
-/* }
- else {
- s_serveroptions.player0.string = "Open";
- start = 0;
- }*/
- for( n = start; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue == 1 ) {
- s_serveroptions.playerName[n].generic.flags &= ~( (unsigned int)(QMF_INACTIVE|QMF_HIDDEN));
- }
- else {
- s_serveroptions.playerName[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- }
- }
-
- // teams
- if( s_serveroptions.gametype < GT_TEAM || s_serveroptions.gametype == GT_LMS ) {
- return;
- }
- for( n = start; n < PLAYER_SLOTS; n++ ) {
- if( s_serveroptions.playerType[n].curvalue == 2 ) {
- s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
- }
- else {
- s_serveroptions.playerTeam[n].generic.flags &= ~((unsigned int) (QMF_INACTIVE|QMF_HIDDEN));
- }
- }
-}
-
-
-/*
-=================
-ServerOptions_Event
-=================
-*/
-static void ServerOptions_Event( void* ptr, int event ) {
- switch( ((menucommon_s*)ptr)->id ) {
-
- //if( event != QM_ACTIVATED && event != QM_LOSTFOCUS) {
- // return;
- //}
- case ID_PLAYER_TYPE:
- if( event != QM_ACTIVATED ) {
- break;
- }
- ServerOptions_SetPlayerItems();
- break;
-
- case ID_MAXCLIENTS:
-// case ID_DEDICATED:
- ServerOptions_SetPlayerItems();
- break;
- case ID_GO:
- if( event != QM_ACTIVATED ) {
- break;
- }
- ServerOptions_Start();
- break;
-
- case ID_STARTSERVERNEXT:
- if( event != QM_ACTIVATED ) {
- break;
- }
- break;
- case ID_BACK:
- if( event != QM_ACTIVATED ) {
- break;
- }
- UI_PopMenu();
- break;
- }
-}
-
-
-static void ServerOptions_PlayerNameEvent( void* ptr, int event ) {
- int n;
-
- if( event != QM_ACTIVATED ) {
- return;
- }
- n = ((menutext_s*)ptr)->generic.id;
- s_serveroptions.newBotIndex = n;
- UI_BotSelectMenu( s_serveroptions.playerNameBuffers[n] );
-}
-
-
-/*
-=================
-ServerOptions_StatusBar
-=================
-*/
-static void ServerOptions_StatusBar( void* ptr ) {
- switch( ((menucommon_s*)ptr)->id ) {
- default:
- UI_DrawString( 320, 440, "0 = NO LIMIT", UI_CENTER|UI_SMALLFONT, colorWhite );
- break;
- }
-}
-
-/*
-=================
-ServerOptions_StatusBar_Instantgib
-=================
-*/
-static void ServerOptions_StatusBar_Instantgib( void* ptr ) {
- switch( ((menucommon_s*)ptr)->id ) {
- default:
- UI_DrawString( 320, 440, "Only railgun and instant kill", UI_CENTER|UI_SMALLFONT, colorWhite );
- break;
- }
-}
-
-
-/*
-===============
-ServerOptions_LevelshotDraw
-===============
-*/
-static void ServerOptions_LevelshotDraw( void *self ) {
- menubitmap_s *b;
- int x;
- int y;
-
- // strange place for this, but it works
- if( s_serveroptions.newBot ) {
- Q_strncpyz( s_serveroptions.playerNameBuffers[s_serveroptions.newBotIndex], s_serveroptions.newBotName, 16 );
- s_serveroptions.newBot = qfalse;
- }
-
- b = (menubitmap_s *)self;
-
- Bitmap_Draw( b );
-
- x = b->generic.x;
- y = b->generic.y + b->height;
- UI_FillRect( x, y, b->width, 40, colorBlack );
-
- x += b->width / 2;
- y += 4;
- UI_DrawString( x, y, s_serveroptions.mapnamebuffer, UI_CENTER|UI_SMALLFONT, color_orange );
-
- y += SMALLCHAR_HEIGHT;
- UI_DrawString( x, y, gametype_items[gametype_remap2[s_serveroptions.gametype]], UI_CENTER|UI_SMALLFONT, color_orange );
-}
-
-
-static void ServerOptions_InitBotNames( void ) {
- int count;
- int n;
- const char *arenaInfo;
- const char *botInfo;
- char *p;
- char *bot;
- char bots[MAX_INFO_STRING];
-
- //this SHOULD work
- if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
- Q_strncpyz( s_serveroptions.playerNameBuffers[1], "gargoyle", 16 );
- Q_strncpyz( s_serveroptions.playerNameBuffers[2], "kyonshi", 16 );
- Q_strncpyz( s_serveroptions.playerNameBuffers[3], "grism", 16 );
- if( s_serveroptions.gametype != GT_TEAM ) {
- s_serveroptions.playerType[3].curvalue = 2;
- }
- Q_strncpyz( s_serveroptions.playerNameBuffers[4], "merman", 16 );
- s_serveroptions.playerType[4].curvalue = 2;
- Q_strncpyz( s_serveroptions.playerNameBuffers[5], "skelebot", 16 );
- s_serveroptions.playerType[5].curvalue = 2;
-
- Q_strncpyz( s_serveroptions.playerNameBuffers[6], "sergei", 16 );
- Q_strncpyz( s_serveroptions.playerNameBuffers[7], "assassin", 16 );
- Q_strncpyz( s_serveroptions.playerNameBuffers[8], "grunt", 16 );
- Q_strncpyz( s_serveroptions.playerNameBuffers[9], "skelebot", 16 );
- if( s_serveroptions.gametype != GT_TEAM ) {
- s_serveroptions.playerType[9].curvalue = 2;
- }
- Q_strncpyz( s_serveroptions.playerNameBuffers[10], "merman", 16 );
- s_serveroptions.playerType[10].curvalue = 2;
- Q_strncpyz( s_serveroptions.playerNameBuffers[11], "skelebot", 16 );
- s_serveroptions.playerType[11].curvalue = 2;
-
- return;
- }
-
- count = 1; // skip the first slot, reserved for a human
-
- // get info for this map
- arenaInfo = UI_GetArenaInfoByMap( s_serveroptions.mapnamebuffer );
-
- // get the bot info - we'll seed with them if any are listed
- Q_strncpyz( bots, Info_ValueForKey( arenaInfo, "bots" ), sizeof(bots) );
- p = &bots[0];
- while( *p && count < PLAYER_SLOTS ) {
- //skip spaces
- while( *p && *p == ' ' ) {
- p++;
- }
- if( !p ) {
- break;
- }
-
- // mark start of bot name
- bot = p;
-
- // skip until space of null
- while( *p && *p != ' ' ) {
- p++;
- }
- if( *p ) {
- *p++ = 0;
- }
-
- botInfo = UI_GetBotInfoByName( bot );
- bot = Info_ValueForKey( botInfo, "name" );
-
- if(!Q_stricmp(bot,""))
- bot = "Sarge";
-
- Q_strncpyz( s_serveroptions.playerNameBuffers[count], bot, sizeof(s_serveroptions.playerNameBuffers[count]) );
- count++;
- }
-
- // set the rest of the bot slots to to other bots
- for( n = count; n < PLAYER_SLOTS; n++ ) {
- switch(n%4){
- case 0:
- strcpy( s_serveroptions.playerNameBuffers[n], "Grunt" );
- break;
- case 1:
- strcpy( s_serveroptions.playerNameBuffers[n], "Merman" );
- break;
- case 2:
- strcpy( s_serveroptions.playerNameBuffers[n], "Kyonshi" );
- break;
- default:
- strcpy( s_serveroptions.playerNameBuffers[n], "Skelebot" );
- }
- }
-
- // pad up to #8 as open slots
- for( ;count < 8; count++ ) {
- s_serveroptions.playerType[count].curvalue = 0;
- }
-
- // close off the rest by default
- for( ;count < PLAYER_SLOTS; count++ ) {
- if( s_serveroptions.playerType[count].curvalue == 1 ) {
- s_serveroptions.playerType[count].curvalue = 2;
- }
- }
-}
-
-
-/*
-=================
-ServerOptions_SetMenuItems
-=================
-*/
-static void ServerOptions_SetMenuItems( void ) {
- static char picname[64];
-
- switch( s_serveroptions.gametype ) {
- case GT_FFA:
- default:
- Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_fraglimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_timelimit" ) ) );
- break;
-
- case GT_TOURNAMENT:
- Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_fraglimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_timelimit" ) ) );
- break;
-
- case GT_TEAM:
- Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_fraglimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_team_friendly" ) );
- break;
-
- case GT_CTF:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_ctf_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_ctf_friendly" ) );
- break;
-
- case GT_1FCTF:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_1fctf_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_1fctf_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_1fctf_friendly" ) );
- break;
-
- case GT_OBELISK:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_overload_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_overload_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_overload_friendly" ) );
- break;
-
- case GT_HARVESTER:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_harvester_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_harvester_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_harvester_friendly" ) );
- break;
-
- case GT_ELIMINATION:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_elimination_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_elimination_timelimit" ) ) );
- //s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_elimination_friendly" ) );
- break;
-
- case GT_CTF_ELIMINATION:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_elimination_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_elimination_timelimit" ) ) );
- //s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_ctf_elimination_friendly" ) );
- break;
-
- case GT_LMS:
- Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_lms_fraglimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_lms_timelimit" ) ) );
- break;
-
- case GT_DOUBLE_D:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_dd_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_dd_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_dd_friendly" ) );
- break;
-
- case GT_DOMINATION:
- Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_dom_capturelimit" ) ) );
- Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_dom_timelimit" ) ) );
- s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_dom_friendly" ) );
- break;
-
- }
-
- Q_strncpyz( s_serveroptions.hostname.field.buffer, UI_Cvar_VariableString( "sv_hostname" ), sizeof( s_serveroptions.hostname.field.buffer ) );
- s_serveroptions.pure.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_pure" ) );
- s_serveroptions.instantgib.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "g_instantgib" ) );
- s_serveroptions.rockets.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "g_rockets" ) );
- s_serveroptions.lmsMode.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue("g_lms_mode") )+1;
-
- // set the map pic
- Com_sprintf( picname, 64, "levelshots/%s", s_startserver.maplist[s_startserver.currentmap] );
- s_serveroptions.mappic.generic.name = picname;
-
- // set the map name
- strcpy( s_serveroptions.mapnamebuffer, s_startserver.mapname.string );
- Q_strupr( s_serveroptions.mapnamebuffer );
-
- // get the player selections initialized
- ServerOptions_InitPlayerItems();
- ServerOptions_SetPlayerItems();
-
- // seed bot names
- ServerOptions_InitBotNames();
- ServerOptions_SetPlayerItems();
-}
-
-/*
-=================
-PlayerName_Draw
-=================
-*/
-static void PlayerName_Draw( void *item ) {
- menutext_s *s;
- float *color;
- int x, y;
- int style;
- qboolean focus;
-
- s = (menutext_s *)item;
-
- x = s->generic.x;
- y = s->generic.y;
-
- style = UI_SMALLFONT;
- focus = (s->generic.parent->cursor == s->generic.menuPosition);
-
- if ( s->generic.flags & QMF_GRAYED )
- color = text_color_disabled;
- else if ( focus )
- {
- color = text_color_highlight;
- style |= UI_PULSE;
- }
- else if ( s->generic.flags & QMF_BLINK )
- {
- color = text_color_highlight;
- style |= UI_BLINK;
- }
- else
- color = text_color_normal;
-
- if ( focus )
- {
- // draw cursor
- UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
- }
-
- UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );
- UI_DrawString( x + SMALLCHAR_WIDTH, y, s->string, style|UI_LEFT, color );
-}
-
-
-/*
-=================
-ServerOptions_MenuInit
-=================
-*/
-#define OPTIONS_X 456
-
-static void ServerOptions_MenuInit( qboolean multiplayer ) {
- int y;
- int n;
-
- memset( &s_serveroptions, 0 ,sizeof(serveroptions_t) );
- s_serveroptions.multiplayer = multiplayer;
- // so the new gametypes work
- s_serveroptions.gametype = (int)Com_Clamp( 0, GT_MAX_GAME_TYPE - 1, trap_Cvar_VariableValue( "g_gameType" ) );
- //s_serveroptions.punkbuster.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_punkbuster" ) );
-
- ServerOptions_Cache();
-
- s_serveroptions.menu.wrapAround = qtrue;
- s_serveroptions.menu.fullscreen = qtrue;
-
- s_serveroptions.banner.generic.type = MTYPE_BTEXT;
- s_serveroptions.banner.generic.x = 320;
- s_serveroptions.banner.generic.y = 16;
- s_serveroptions.banner.string = "GAME SERVER";
- s_serveroptions.banner.color = color_white;
- s_serveroptions.banner.style = UI_CENTER;
-
- s_serveroptions.mappic.generic.type = MTYPE_BITMAP;
- s_serveroptions.mappic.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- s_serveroptions.mappic.generic.x = 352;
- s_serveroptions.mappic.generic.y = 80;
- s_serveroptions.mappic.width = 160;
- s_serveroptions.mappic.height = 120;
- s_serveroptions.mappic.errorpic = GAMESERVER_UNKNOWNMAP;
- s_serveroptions.mappic.generic.ownerdraw = ServerOptions_LevelshotDraw;
-
- s_serveroptions.picframe.generic.type = MTYPE_BITMAP;
- s_serveroptions.picframe.generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE|QMF_HIGHLIGHT;
- s_serveroptions.picframe.generic.x = 352 - 38;
- s_serveroptions.picframe.generic.y = 80 - 40;
- s_serveroptions.picframe.width = 320;
- s_serveroptions.picframe.height = 320;
- s_serveroptions.picframe.focuspic = GAMESERVER_SELECT;
-
- y = 272;
- if( s_serveroptions.gametype < GT_CTF || s_serveroptions.gametype== GT_LMS) {
- s_serveroptions.fraglimit.generic.type = MTYPE_FIELD;
- s_serveroptions.fraglimit.generic.name = "Frag Limit:";
- s_serveroptions.fraglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.fraglimit.generic.x = OPTIONS_X;
- s_serveroptions.fraglimit.generic.y = y;
- s_serveroptions.fraglimit.generic.statusbar = ServerOptions_StatusBar;
- s_serveroptions.fraglimit.field.widthInChars = 3;
- s_serveroptions.fraglimit.field.maxchars = 3;
- }
- else {
- s_serveroptions.flaglimit.generic.type = MTYPE_FIELD;
- s_serveroptions.flaglimit.generic.name = "Capture Limit:";
- s_serveroptions.flaglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.flaglimit.generic.x = OPTIONS_X;
- s_serveroptions.flaglimit.generic.y = y;
- s_serveroptions.flaglimit.generic.statusbar = ServerOptions_StatusBar;
- s_serveroptions.flaglimit.field.widthInChars = 3;
- s_serveroptions.flaglimit.field.maxchars = 3;
- }
-
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.timelimit.generic.type = MTYPE_FIELD;
- s_serveroptions.timelimit.generic.name = "Time Limit:";
- s_serveroptions.timelimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.timelimit.generic.x = OPTIONS_X;
- s_serveroptions.timelimit.generic.y = y;
- s_serveroptions.timelimit.generic.statusbar = ServerOptions_StatusBar;
- s_serveroptions.timelimit.field.widthInChars = 3;
- s_serveroptions.timelimit.field.maxchars = 3;
-
- if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS && s_serveroptions.gametype != GT_ELIMINATION && s_serveroptions.gametype != GT_CTF_ELIMINATION) {
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.friendlyfire.generic.type = MTYPE_RADIOBUTTON;
- s_serveroptions.friendlyfire.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.friendlyfire.generic.x = OPTIONS_X;
- s_serveroptions.friendlyfire.generic.y = y;
- s_serveroptions.friendlyfire.generic.name = "Friendly Fire:";
- }
-
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.pure.generic.type = MTYPE_RADIOBUTTON;
- s_serveroptions.pure.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.pure.generic.x = OPTIONS_X;
- s_serveroptions.pure.generic.y = y;
- s_serveroptions.pure.generic.name = "Pure Server:";
-
- //Insantgib option
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.instantgib.generic.type = MTYPE_RADIOBUTTON;
- s_serveroptions.instantgib.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.instantgib.generic.x = OPTIONS_X;
- s_serveroptions.instantgib.generic.y = y;
- s_serveroptions.instantgib.generic.name = "Instantgib:";
- s_serveroptions.instantgib.generic.statusbar = ServerOptions_StatusBar_Instantgib;
-
- //Rockets option
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.rockets.generic.type = MTYPE_RADIOBUTTON;
- s_serveroptions.rockets.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.rockets.generic.x = OPTIONS_X;
- s_serveroptions.rockets.generic.y = y;
- s_serveroptions.rockets.generic.name = "All rockets:";
-
- if( s_serveroptions.gametype == GT_LMS ) {
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.lmsMode.generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.lmsMode.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.lmsMode.generic.name = "Score mode:";
- s_serveroptions.lmsMode.generic.x = OPTIONS_X; //32 + (strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH;
- s_serveroptions.lmsMode.generic.y = y;
- s_serveroptions.lmsMode.itemnames = lmsMode_list;
- //s_serveroptions.lmsMode.curvalue = 0;
-
- }
-
-/* if( s_serveroptions.multiplayer ) {
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.dedicated.generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.dedicated.generic.id = ID_DEDICATED;
- s_serveroptions.dedicated.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.dedicated.generic.callback = ServerOptions_Event;
- s_serveroptions.dedicated.generic.x = OPTIONS_X;
- s_serveroptions.dedicated.generic.y = y;
- s_serveroptions.dedicated.generic.name = "Dedicated:";
- s_serveroptions.dedicated.itemnames = dedicated_list;
- }*/
-
- if( s_serveroptions.multiplayer ) {
- y += BIGCHAR_HEIGHT+2;
- s_serveroptions.hostname.generic.type = MTYPE_FIELD;
- s_serveroptions.hostname.generic.name = "Hostname:";
- s_serveroptions.hostname.generic.flags = QMF_SMALLFONT;
- s_serveroptions.hostname.generic.x = OPTIONS_X;
- s_serveroptions.hostname.generic.y = y;
- s_serveroptions.hostname.field.widthInChars = 18;
- s_serveroptions.hostname.field.maxchars = 64;
- }
-
- y = 80;
- s_serveroptions.botSkill.generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.botSkill.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_serveroptions.botSkill.generic.name = "Bot Skill: ";
- s_serveroptions.botSkill.generic.x = 32 + (strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH;
- s_serveroptions.botSkill.generic.y = y;
- s_serveroptions.botSkill.itemnames = botSkill_list;
- s_serveroptions.botSkill.curvalue = 1;
-
- y += ( 2 * SMALLCHAR_HEIGHT );
- s_serveroptions.player0.generic.type = MTYPE_TEXT;
- s_serveroptions.player0.generic.flags = QMF_SMALLFONT;
- s_serveroptions.player0.generic.x = 32 + SMALLCHAR_WIDTH;
- s_serveroptions.player0.generic.y = y;
- s_serveroptions.player0.color = color_orange;
- s_serveroptions.player0.style = UI_LEFT|UI_SMALLFONT;
-
- for( n = 0; n < PLAYER_SLOTS; n++ ) {
- s_serveroptions.playerType[n].generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.playerType[n].generic.flags = QMF_SMALLFONT;
- s_serveroptions.playerType[n].generic.id = ID_PLAYER_TYPE;
- s_serveroptions.playerType[n].generic.callback = ServerOptions_Event;
- s_serveroptions.playerType[n].generic.x = 32;
- s_serveroptions.playerType[n].generic.y = y;
- s_serveroptions.playerType[n].itemnames = playerType_list;
-
- s_serveroptions.playerName[n].generic.type = MTYPE_TEXT;
- s_serveroptions.playerName[n].generic.flags = QMF_SMALLFONT;
- s_serveroptions.playerName[n].generic.x = 96;
- s_serveroptions.playerName[n].generic.y = y;
- s_serveroptions.playerName[n].generic.callback = ServerOptions_PlayerNameEvent;
- s_serveroptions.playerName[n].generic.id = n;
- s_serveroptions.playerName[n].generic.ownerdraw = PlayerName_Draw;
- s_serveroptions.playerName[n].color = color_orange;
- s_serveroptions.playerName[n].style = UI_SMALLFONT;
- s_serveroptions.playerName[n].string = s_serveroptions.playerNameBuffers[n];
- s_serveroptions.playerName[n].generic.top = s_serveroptions.playerName[n].generic.y;
- s_serveroptions.playerName[n].generic.bottom = s_serveroptions.playerName[n].generic.y + SMALLCHAR_HEIGHT;
- s_serveroptions.playerName[n].generic.left = s_serveroptions.playerName[n].generic.x - SMALLCHAR_HEIGHT/ 2;
- s_serveroptions.playerName[n].generic.right = s_serveroptions.playerName[n].generic.x + 16 * SMALLCHAR_WIDTH;
-
- s_serveroptions.playerTeam[n].generic.type = MTYPE_SPINCONTROL;
- s_serveroptions.playerTeam[n].generic.flags = QMF_SMALLFONT;
- s_serveroptions.playerTeam[n].generic.x = 240;
- s_serveroptions.playerTeam[n].generic.y = y;
- s_serveroptions.playerTeam[n].itemnames = playerTeam_list;
-
- y += ( SMALLCHAR_HEIGHT + 4 );
- }
-
- s_serveroptions.back.generic.type = MTYPE_BITMAP;
- s_serveroptions.back.generic.name = GAMESERVER_BACK0;
- s_serveroptions.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_serveroptions.back.generic.callback = ServerOptions_Event;
- s_serveroptions.back.generic.id = ID_BACK;
- s_serveroptions.back.generic.x = 0;
- s_serveroptions.back.generic.y = 480-64;
- s_serveroptions.back.width = 128;
- s_serveroptions.back.height = 64;
- s_serveroptions.back.focuspic = GAMESERVER_BACK1;
-
- s_serveroptions.next.generic.type = MTYPE_BITMAP;
- s_serveroptions.next.generic.name = GAMESERVER_NEXT0;
- s_serveroptions.next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE|QMF_GRAYED|QMF_HIDDEN;
- s_serveroptions.next.generic.callback = ServerOptions_Event;
- s_serveroptions.next.generic.id = ID_STARTSERVERNEXT;
- s_serveroptions.next.generic.x = 640;
- s_serveroptions.next.generic.y = 480-64-72;
- s_serveroptions.next.generic.statusbar = ServerOptions_StatusBar;
- s_serveroptions.next.width = 128;
- s_serveroptions.next.height = 64;
- s_serveroptions.next.focuspic = GAMESERVER_NEXT1;
-
- s_serveroptions.go.generic.type = MTYPE_BITMAP;
- s_serveroptions.go.generic.name = GAMESERVER_FIGHT0;
- s_serveroptions.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_serveroptions.go.generic.callback = ServerOptions_Event;
- s_serveroptions.go.generic.id = ID_GO;
- s_serveroptions.go.generic.x = 640;
- s_serveroptions.go.generic.y = 480-64;
- s_serveroptions.go.width = 128;
- s_serveroptions.go.height = 64;
- s_serveroptions.go.focuspic = GAMESERVER_FIGHT1;
-
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.banner );
-
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.mappic );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.picframe );
-
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.botSkill );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.player0 );
- for( n = 0; n < PLAYER_SLOTS; n++ ) {
- if( n != 0 ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerType[n] );
- }
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerName[n] );
- if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerTeam[n] );
- }
- }
-
- if( s_serveroptions.gametype < GT_CTF || s_serveroptions.gametype == GT_LMS ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.fraglimit );
- }
- else {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.flaglimit );
- }
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.timelimit );
- if( s_serveroptions.gametype >= GT_TEAM && s_serveroptions.gametype != GT_LMS && s_serveroptions.gametype != GT_ELIMINATION && s_serveroptions.gametype != GT_CTF_ELIMINATION) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.friendlyfire );
- }
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.pure );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.instantgib );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.rockets );
- if( s_serveroptions.gametype == GT_LMS) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.lmsMode );
- }
-/* if( s_serveroptions.multiplayer ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.dedicated );
- }*/
- if( s_serveroptions.multiplayer ) {
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.hostname );
- }
-
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.back );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.next );
- Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.go );
-
- ServerOptions_SetMenuItems();
-}
-
-/*
-=================
-ServerOptions_Cache
-=================
-*/
-void ServerOptions_Cache( void ) {
- trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 );
- trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 );
- trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT0 );
- trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT1 );
- trap_R_RegisterShaderNoMip( GAMESERVER_SELECT );
- trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );
-}
-
-
-/*
-=================
-UI_ServerOptionsMenu
-=================
-*/
-static void UI_ServerOptionsMenu( qboolean multiplayer ) {
- ServerOptions_MenuInit( multiplayer );
- UI_PushMenu( &s_serveroptions.menu );
-}
-
-
-
-/*
-=============================================================================
-
-BOT SELECT MENU *****
-
-=============================================================================
-*/
-
-
-#define BOTSELECT_BACK0 "menu/art/back_0"
-#define BOTSELECT_BACK1 "menu/art/back_1"
-#define BOTSELECT_ACCEPT0 "menu/art/accept_0"
-#define BOTSELECT_ACCEPT1 "menu/art/accept_1"
-#define BOTSELECT_SELECT "menu/art/opponents_select"
-#define BOTSELECT_SELECTED "menu/art/opponents_selected"
-#define BOTSELECT_ARROWS "menu/art/gs_arrows_0"
-#define BOTSELECT_ARROWSL "menu/art/gs_arrows_l"
-#define BOTSELECT_ARROWSR "menu/art/gs_arrows_r"
-
-#define PLAYERGRID_COLS 4
-#define PLAYERGRID_ROWS 4
-#define MAX_MODELSPERPAGE (PLAYERGRID_ROWS * PLAYERGRID_COLS)
-
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
-
- menubitmap_s pics[MAX_MODELSPERPAGE];
- menubitmap_s picbuttons[MAX_MODELSPERPAGE];
- menutext_s picnames[MAX_MODELSPERPAGE];
-
- menubitmap_s arrows;
- menubitmap_s left;
- menubitmap_s right;
-
- menubitmap_s go;
- menubitmap_s back;
-
- int numBots;
- int modelpage;
- int numpages;
- int selectedmodel;
- int sortedBotNums[MAX_BOTS];
- char boticons[MAX_MODELSPERPAGE][MAX_QPATH];
- char botnames[MAX_MODELSPERPAGE][16];
-} botSelectInfo_t;
-
-static botSelectInfo_t botSelectInfo;
-
-
-/*
-=================
-UI_BotSelectMenu_SortCompare
-=================
-*/
-static int QDECL UI_BotSelectMenu_SortCompare( const void *arg1, const void *arg2 ) {
- int num1, num2;
- const char *info1, *info2;
- const char *name1, *name2;
-
- num1 = *(int *)arg1;
- num2 = *(int *)arg2;
-
- info1 = UI_GetBotInfoByNumber( num1 );
- info2 = UI_GetBotInfoByNumber( num2 );
-
- name1 = Info_ValueForKey( info1, "name" );
- name2 = Info_ValueForKey( info2, "name" );
-
- return Q_stricmp( name1, name2 );
-}
-
-
-/*
-=================
-UI_BotSelectMenu_BuildList
-=================
-*/
-static void UI_BotSelectMenu_BuildList( void ) {
- int n;
-
- botSelectInfo.modelpage = 0;
- botSelectInfo.numBots = UI_GetNumBots();
- botSelectInfo.numpages = botSelectInfo.numBots / MAX_MODELSPERPAGE;
- if( botSelectInfo.numBots % MAX_MODELSPERPAGE ) {
- botSelectInfo.numpages++;
- }
-
- // initialize the array
- for( n = 0; n < botSelectInfo.numBots; n++ ) {
- botSelectInfo.sortedBotNums[n] = n;
- }
-
- // now sort it
- qsort( botSelectInfo.sortedBotNums, botSelectInfo.numBots, sizeof(botSelectInfo.sortedBotNums[0]), UI_BotSelectMenu_SortCompare );
-}
-
-
-/*
-=================
-ServerPlayerIcon
-=================
-*/
-static void ServerPlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize ) {
- char *skin;
- char model[MAX_QPATH];
-
- Q_strncpyz( model, modelAndSkin, sizeof(model));
- skin = Q_strrchr( model, '/' );
- if ( skin ) {
- *skin++ = '\0';
- }
- else {
- skin = "default";
- }
-
- Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_%s.tga", model, skin );
-
- if( !trap_R_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, "default" ) != 0 ) {
- Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_default.tga", model );
- }
-}
-
-
-/*
-=================
-UI_BotSelectMenu_UpdateGrid
-=================
-*/
-static void UI_BotSelectMenu_UpdateGrid( void ) {
- const char *info;
- int i;
- int j;
-
- j = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
- for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++, j++) {
- if( j < botSelectInfo.numBots ) {
- info = UI_GetBotInfoByNumber( botSelectInfo.sortedBotNums[j] );
- ServerPlayerIcon( Info_ValueForKey( info, "model" ), botSelectInfo.boticons[i], MAX_QPATH );
- Q_strncpyz( botSelectInfo.botnames[i], Info_ValueForKey( info, "name" ), 16 );
- Q_CleanStr( botSelectInfo.botnames[i] );
- botSelectInfo.pics[i].generic.name = botSelectInfo.boticons[i];
- if( BotAlreadySelected( botSelectInfo.botnames[i] ) ) {
- botSelectInfo.picnames[i].color = color_red;
- }
- else {
- botSelectInfo.picnames[i].color = color_orange;
- }
- botSelectInfo.picbuttons[i].generic.flags &= ~((unsigned int)QMF_INACTIVE);
- }
- else {
- // dead slot
- botSelectInfo.pics[i].generic.name = NULL;
- botSelectInfo.picbuttons[i].generic.flags |= QMF_INACTIVE;
- botSelectInfo.botnames[i][0] = 0;
- }
-
- botSelectInfo.pics[i].generic.flags &= ~((unsigned int)QMF_HIGHLIGHT);
- botSelectInfo.pics[i].shader = 0;
- botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
- }
-
- // set selected model
- i = botSelectInfo.selectedmodel % MAX_MODELSPERPAGE;
- botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;
- botSelectInfo.picbuttons[i].generic.flags &= ~((unsigned int)QMF_PULSEIFFOCUS);
-
- if( botSelectInfo.numpages > 1 ) {
- if( botSelectInfo.modelpage > 0 ) {
- botSelectInfo.left.generic.flags &= ~((unsigned int)QMF_INACTIVE);
- }
- else {
- botSelectInfo.left.generic.flags |= QMF_INACTIVE;
- }
-
- if( botSelectInfo.modelpage < (botSelectInfo.numpages - 1) ) {
- botSelectInfo.right.generic.flags &= ~((unsigned int)QMF_INACTIVE);
- }
- else {
- botSelectInfo.right.generic.flags |= QMF_INACTIVE;
- }
- }
- else {
- // hide left/right markers
- botSelectInfo.left.generic.flags |= QMF_INACTIVE;
- botSelectInfo.right.generic.flags |= QMF_INACTIVE;
- }
-}
-
-
-/*
-=================
-UI_BotSelectMenu_Default
-=================
-*/
-static void UI_BotSelectMenu_Default( char *bot ) {
- const char *botInfo;
- const char *test;
- int n;
- int i;
-
- for( n = 0; n < botSelectInfo.numBots; n++ ) {
- botInfo = UI_GetBotInfoByNumber( n );
- test = Info_ValueForKey( botInfo, "name" );
- if( Q_stricmp( bot, test ) == 0 ) {
- break;
- }
- }
- if( n == botSelectInfo.numBots ) {
- botSelectInfo.selectedmodel = 0;
- return;
- }
-
- for( i = 0; i < botSelectInfo.numBots; i++ ) {
- if( botSelectInfo.sortedBotNums[i] == n ) {
- break;
- }
- }
- if( i == botSelectInfo.numBots ) {
- botSelectInfo.selectedmodel = 0;
- return;
- }
-
- botSelectInfo.selectedmodel = i;
-}
-
-
-/*
-=================
-UI_BotSelectMenu_LeftEvent
-=================
-*/
-static void UI_BotSelectMenu_LeftEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- if( botSelectInfo.modelpage > 0 ) {
- botSelectInfo.modelpage--;
- botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
- UI_BotSelectMenu_UpdateGrid();
- }
-}
-
-
-/*
-=================
-UI_BotSelectMenu_RightEvent
-=================
-*/
-static void UI_BotSelectMenu_RightEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- if( botSelectInfo.modelpage < botSelectInfo.numpages - 1 ) {
- botSelectInfo.modelpage++;
- botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
- UI_BotSelectMenu_UpdateGrid();
- }
-}
-
-
-/*
-=================
-UI_BotSelectMenu_BotEvent
-=================
-*/
-static void UI_BotSelectMenu_BotEvent( void* ptr, int event ) {
- int i;
-
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++ ) {
- botSelectInfo.pics[i].generic.flags &= ~((unsigned int)QMF_HIGHLIGHT);
- botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
- }
-
- // set selected
- i = ((menucommon_s*)ptr)->id;
- botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;
- botSelectInfo.picbuttons[i].generic.flags &= ~((unsigned int)QMF_PULSEIFFOCUS);
- botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE + i;
-}
-
-
-/*
-=================
-UI_BotSelectMenu_BackEvent
-=================
-*/
-static void UI_BotSelectMenu_BackEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- UI_PopMenu();
-}
-
-
-/*
-=================
-UI_BotSelectMenu_SelectEvent
-=================
-*/
-static void UI_BotSelectMenu_SelectEvent( void* ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- UI_PopMenu();
-
- s_serveroptions.newBot = qtrue;
- Q_strncpyz( s_serveroptions.newBotName, botSelectInfo.botnames[botSelectInfo.selectedmodel % MAX_MODELSPERPAGE], 16 );
-}
-
-
-/*
-=================
-UI_BotSelectMenu_Cache
-=================
-*/
-void UI_BotSelectMenu_Cache( void ) {
- trap_R_RegisterShaderNoMip( BOTSELECT_BACK0 );
- trap_R_RegisterShaderNoMip( BOTSELECT_BACK1 );
- trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT0 );
- trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT1 );
- trap_R_RegisterShaderNoMip( BOTSELECT_SELECT );
- trap_R_RegisterShaderNoMip( BOTSELECT_SELECTED );
- trap_R_RegisterShaderNoMip( BOTSELECT_ARROWS );
- trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSL );
- trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSR );
-}
-
-
-static void UI_BotSelectMenu_Init( char *bot ) {
- int i, j, k;
- int x, y;
-
- memset( &botSelectInfo, 0 ,sizeof(botSelectInfo) );
- botSelectInfo.menu.wrapAround = qtrue;
- botSelectInfo.menu.fullscreen = qtrue;
-
- UI_BotSelectMenu_Cache();
-
- botSelectInfo.banner.generic.type = MTYPE_BTEXT;
- botSelectInfo.banner.generic.x = 320;
- botSelectInfo.banner.generic.y = 16;
- botSelectInfo.banner.string = "SELECT BOT";
- botSelectInfo.banner.color = color_white;
- botSelectInfo.banner.style = UI_CENTER;
-
- y = 80;
- for( i = 0, k = 0; i < PLAYERGRID_ROWS; i++) {
- x = 180;
- for( j = 0; j < PLAYERGRID_COLS; j++, k++ ) {
- botSelectInfo.pics[k].generic.type = MTYPE_BITMAP;
- botSelectInfo.pics[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
- botSelectInfo.pics[k].generic.x = x;
- botSelectInfo.pics[k].generic.y = y;
- botSelectInfo.pics[k].generic.name = botSelectInfo.boticons[k];
- botSelectInfo.pics[k].width = 64;
- botSelectInfo.pics[k].height = 64;
- botSelectInfo.pics[k].focuspic = BOTSELECT_SELECTED;
- botSelectInfo.pics[k].focuscolor = colorRed;
-
- botSelectInfo.picbuttons[k].generic.type = MTYPE_BITMAP;
- botSelectInfo.picbuttons[k].generic.flags = QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS;
- botSelectInfo.picbuttons[k].generic.callback = UI_BotSelectMenu_BotEvent;
- botSelectInfo.picbuttons[k].generic.id = k;
- botSelectInfo.picbuttons[k].generic.x = x - 16;
- botSelectInfo.picbuttons[k].generic.y = y - 16;
- botSelectInfo.picbuttons[k].generic.left = x;
- botSelectInfo.picbuttons[k].generic.top = y;
- botSelectInfo.picbuttons[k].generic.right = x + 64;
- botSelectInfo.picbuttons[k].generic.bottom = y + 64;
- botSelectInfo.picbuttons[k].width = 128;
- botSelectInfo.picbuttons[k].height = 128;
- botSelectInfo.picbuttons[k].focuspic = BOTSELECT_SELECT;
- botSelectInfo.picbuttons[k].focuscolor = colorRed;
-
- botSelectInfo.picnames[k].generic.type = MTYPE_TEXT;
- botSelectInfo.picnames[k].generic.flags = QMF_SMALLFONT;
- botSelectInfo.picnames[k].generic.x = x + 32;
- botSelectInfo.picnames[k].generic.y = y + 64;
- botSelectInfo.picnames[k].string = botSelectInfo.botnames[k];
- botSelectInfo.picnames[k].color = color_orange;
- botSelectInfo.picnames[k].style = UI_CENTER|UI_SMALLFONT;
-
- x += (64 + 6);
- }
- y += (64 + SMALLCHAR_HEIGHT + 6);
- }
-
- botSelectInfo.arrows.generic.type = MTYPE_BITMAP;
- botSelectInfo.arrows.generic.name = BOTSELECT_ARROWS;
- botSelectInfo.arrows.generic.flags = QMF_INACTIVE;
- botSelectInfo.arrows.generic.x = 260;
- botSelectInfo.arrows.generic.y = 440;
- botSelectInfo.arrows.width = 128;
- botSelectInfo.arrows.height = 32;
-
- botSelectInfo.left.generic.type = MTYPE_BITMAP;
- botSelectInfo.left.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- botSelectInfo.left.generic.callback = UI_BotSelectMenu_LeftEvent;
- botSelectInfo.left.generic.x = 260;
- botSelectInfo.left.generic.y = 440;
- botSelectInfo.left.width = 64;
- botSelectInfo.left.height = 32;
- botSelectInfo.left.focuspic = BOTSELECT_ARROWSL;
-
- botSelectInfo.right.generic.type = MTYPE_BITMAP;
- botSelectInfo.right.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- botSelectInfo.right.generic.callback = UI_BotSelectMenu_RightEvent;
- botSelectInfo.right.generic.x = 321;
- botSelectInfo.right.generic.y = 440;
- botSelectInfo.right.width = 64;
- botSelectInfo.right.height = 32;
- botSelectInfo.right.focuspic = BOTSELECT_ARROWSR;
-
- botSelectInfo.back.generic.type = MTYPE_BITMAP;
- botSelectInfo.back.generic.name = BOTSELECT_BACK0;
- botSelectInfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- botSelectInfo.back.generic.callback = UI_BotSelectMenu_BackEvent;
- botSelectInfo.back.generic.x = 0;
- botSelectInfo.back.generic.y = 480-64;
- botSelectInfo.back.width = 128;
- botSelectInfo.back.height = 64;
- botSelectInfo.back.focuspic = BOTSELECT_BACK1;
-
- botSelectInfo.go.generic.type = MTYPE_BITMAP;
- botSelectInfo.go.generic.name = BOTSELECT_ACCEPT0;
- botSelectInfo.go.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- botSelectInfo.go.generic.callback = UI_BotSelectMenu_SelectEvent;
- botSelectInfo.go.generic.x = 640;
- botSelectInfo.go.generic.y = 480-64;
- botSelectInfo.go.width = 128;
- botSelectInfo.go.height = 64;
- botSelectInfo.go.focuspic = BOTSELECT_ACCEPT1;
-
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.banner );
- for( i = 0; i < MAX_MODELSPERPAGE; i++ ) {
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.pics[i] );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.picbuttons[i] );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.picnames[i] );
- }
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.arrows );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.left );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.right );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.back );
- Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.go );
-
- UI_BotSelectMenu_BuildList();
- UI_BotSelectMenu_Default( bot );
- botSelectInfo.modelpage = botSelectInfo.selectedmodel / MAX_MODELSPERPAGE;
- UI_BotSelectMenu_UpdateGrid();
-}
-
-
-/*
-=================
-UI_BotSelectMenu
-=================
-*/
-void UI_BotSelectMenu( char *bot ) {
- UI_BotSelectMenu_Init( bot );
- UI_PushMenu( &botSelectInfo.menu );
-}
diff --git a/game/code/q3_ui/ui_video.c b/game/code/q3_ui/ui_video.c
deleted file mode 100644
index a136d16..0000000
--- a/game/code/q3_ui/ui_video.c
+++ /dev/null
@@ -1,1373 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "ui_local.h"
-
-void GraphicsOptions_MenuInit( void );
-
-/*
-=======================================================================
-
-DRIVER INFORMATION MENU
-
-=======================================================================
-*/
-
-
-#define DRIVERINFO_FRAMEL "menu/art_blueish/frame2_l"
-#define DRIVERINFO_FRAMER "menu/art_blueish/frame1_r"
-#define DRIVERINFO_BACK0 "menu/art_blueish/back_0"
-#define DRIVERINFO_BACK1 "menu/art_blueish/back_1"
-
-static char* driverinfo_artlist[] =
-{
- DRIVERINFO_FRAMEL,
- DRIVERINFO_FRAMER,
- DRIVERINFO_BACK0,
- DRIVERINFO_BACK1,
- NULL,
-};
-
-#define ID_DRIVERINFOBACK 100
-
-typedef struct
-{
- menuframework_s menu;
- menutext_s banner;
- menubitmap_s back;
- menubitmap_s framel;
- menubitmap_s framer;
- char stringbuff[1024];
- char* strings[64];
- int numstrings;
-} driverinfo_t;
-
-static driverinfo_t s_driverinfo;
-
-/*
-=================
-DriverInfo_Event
-=================
-*/
-static void DriverInfo_Event( void* ptr, int event )
-{
- if (event != QM_ACTIVATED)
- return;
-
- switch (((menucommon_s*)ptr)->id)
- {
- case ID_DRIVERINFOBACK:
- UI_PopMenu();
- break;
- }
-}
-
-/*
-=================
-DriverInfo_MenuDraw
-=================
-*/
-static void DriverInfo_MenuDraw( void )
-{
- int i;
- int y;
-
- Menu_Draw( &s_driverinfo.menu );
-
- UI_DrawString( 320, 80, "VENDOR", UI_CENTER|UI_SMALLFONT, color_red );
- UI_DrawString( 320, 152, "PIXELFORMAT", UI_CENTER|UI_SMALLFONT, color_red );
- UI_DrawString( 320, 192, "EXTENSIONS", UI_CENTER|UI_SMALLFONT, color_red );
-
- UI_DrawString( 320, 80+16, uis.glconfig.vendor_string, UI_CENTER|UI_SMALLFONT, text_color_normal );
- UI_DrawString( 320, 96+16, uis.glconfig.version_string, UI_CENTER|UI_SMALLFONT, text_color_normal );
- UI_DrawString( 320, 112+16, uis.glconfig.renderer_string, UI_CENTER|UI_SMALLFONT, text_color_normal );
- UI_DrawString( 320, 152+16, va ("color(%d-bits) Z(%d-bits) stencil(%d-bits)", uis.glconfig.colorBits, uis.glconfig.depthBits, uis.glconfig.stencilBits), UI_CENTER|UI_SMALLFONT, text_color_normal );
-
- // double column
- y = 192+16;
- for (i=0; i<s_driverinfo.numstrings/2; i++) {
- UI_DrawString( 320-4, y, s_driverinfo.strings[i*2], UI_RIGHT|UI_SMALLFONT, text_color_normal );
- UI_DrawString( 320+4, y, s_driverinfo.strings[i*2+1], UI_LEFT|UI_SMALLFONT, text_color_normal );
- y += SMALLCHAR_HEIGHT;
- }
-
- if (s_driverinfo.numstrings & 1)
- UI_DrawString( 320, y, s_driverinfo.strings[s_driverinfo.numstrings-1], UI_CENTER|UI_SMALLFONT, text_color_normal );
-}
-
-/*
-=================
-DriverInfo_Cache
-=================
-*/
-void DriverInfo_Cache( void )
-{
- int i;
-
- // touch all our pics
- for (i=0; ;i++)
- {
- if (!driverinfo_artlist[i])
- break;
- trap_R_RegisterShaderNoMip(driverinfo_artlist[i]);
- }
-}
-
-/*
-=================
-UI_DriverInfo_Menu
-=================
-*/
-static void UI_DriverInfo_Menu( void )
-{
- char* eptr;
- int i;
- int len;
-
- // zero set all our globals
- memset( &s_driverinfo, 0 ,sizeof(driverinfo_t) );
-
- DriverInfo_Cache();
-
- s_driverinfo.menu.fullscreen = qtrue;
- s_driverinfo.menu.draw = DriverInfo_MenuDraw;
-
- s_driverinfo.banner.generic.type = MTYPE_BTEXT;
- s_driverinfo.banner.generic.x = 320;
- s_driverinfo.banner.generic.y = 16;
- s_driverinfo.banner.string = "DRIVER INFO";
- s_driverinfo.banner.color = color_white;
- s_driverinfo.banner.style = UI_CENTER;
-
- s_driverinfo.framel.generic.type = MTYPE_BITMAP;
- s_driverinfo.framel.generic.name = DRIVERINFO_FRAMEL;
- s_driverinfo.framel.generic.flags = QMF_INACTIVE;
- s_driverinfo.framel.generic.x = 0;
- s_driverinfo.framel.generic.y = 78;
- s_driverinfo.framel.width = 256;
- s_driverinfo.framel.height = 329;
-
- s_driverinfo.framer.generic.type = MTYPE_BITMAP;
- s_driverinfo.framer.generic.name = DRIVERINFO_FRAMER;
- s_driverinfo.framer.generic.flags = QMF_INACTIVE;
- s_driverinfo.framer.generic.x = 376;
- s_driverinfo.framer.generic.y = 76;
- s_driverinfo.framer.width = 256;
- s_driverinfo.framer.height = 334;
-
- s_driverinfo.back.generic.type = MTYPE_BITMAP;
- s_driverinfo.back.generic.name = DRIVERINFO_BACK0;
- s_driverinfo.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_driverinfo.back.generic.callback = DriverInfo_Event;
- s_driverinfo.back.generic.id = ID_DRIVERINFOBACK;
- s_driverinfo.back.generic.x = 0;
- s_driverinfo.back.generic.y = 480-64;
- s_driverinfo.back.width = 128;
- s_driverinfo.back.height = 64;
- s_driverinfo.back.focuspic = DRIVERINFO_BACK1;
-
- // TTimo: overflow with particularly long GL extensions (such as the gf3)
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=399
- // NOTE: could have pushed the size of stringbuff, but the list is already out of the screen
- // (no matter what your resolution)
- Q_strncpyz(s_driverinfo.stringbuff, uis.glconfig.extensions_string, 1024);
-
- // build null terminated extension strings
- eptr = s_driverinfo.stringbuff;
- while ( s_driverinfo.numstrings<40 && *eptr )
- {
- while ( *eptr && *eptr == ' ' )
- *eptr++ = '\0';
-
- // track start of valid string
- if (*eptr && *eptr != ' ')
- s_driverinfo.strings[s_driverinfo.numstrings++] = eptr;
-
- while ( *eptr && *eptr != ' ' )
- eptr++;
- }
-
- // safety length strings for display
- for (i=0; i<s_driverinfo.numstrings; i++) {
- len = strlen(s_driverinfo.strings[i]);
- if (len > 32) {
- s_driverinfo.strings[i][len-1] = '>';
- s_driverinfo.strings[i][len] = '\0';
- }
- }
-
- Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.banner );
- Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.framel );
- Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.framer );
- Menu_AddItem( &s_driverinfo.menu, &s_driverinfo.back );
-
- UI_PushMenu( &s_driverinfo.menu );
-}
-
-/*
-=======================================================================
-
-GRAPHICS OPTIONS MENU
-
-=======================================================================
-*/
-
-#define GRAPHICSOPTIONS_FRAMEL "menu/art_blueish/frame2_l"
-#define GRAPHICSOPTIONS_FRAMER "menu/art_blueish/frame1_r"
-#define GRAPHICSOPTIONS_BACK0 "menu/art_blueish/back_0"
-#define GRAPHICSOPTIONS_BACK1 "menu/art_blueish/back_1"
-#define GRAPHICSOPTIONS_ACCEPT0 "menu/art_blueish/accept_0"
-#define GRAPHICSOPTIONS_ACCEPT1 "menu/art_blueish/accept_1"
-
-#define ID_BACK2 101
-#define ID_FULLSCREEN 102
-#define ID_LIST 103
-#define ID_MODE 104
-#define ID_DRIVERINFO 105
-#define ID_GRAPHICS 106
-#define ID_DISPLAY 107
-#define ID_SOUND 108
-#define ID_NETWORK 109
-#define ID_RATIO 110
-
-typedef struct {
- menuframework_s menu;
-
- menutext_s banner;
- menubitmap_s framel;
- menubitmap_s framer;
-
- menutext_s graphics;
- menutext_s display;
- menutext_s sound;
- menutext_s network;
-
- menulist_s list;
- menulist_s ratio;
- menulist_s mode;
- menulist_s driver;
- menuslider_s tq;
- menulist_s fs;
- menulist_s lighting;
- menulist_s flares;
- menulist_s bloom;
- menulist_s allow_extensions;
- menulist_s texturebits;
- menulist_s colordepth;
- menulist_s geometry;
- menulist_s filter;
- menulist_s aniso;
- menutext_s driverinfo;
-
- menubitmap_s apply;
- menubitmap_s back;
-} graphicsoptions_t;
-
-typedef struct
-{
- int mode;
- qboolean fullscreen;
- int tq;
- int lighting;
- qboolean flares;
- qboolean bloom;
- int colordepth;
- int texturebits;
- int geometry;
- int filter;
- int aniso;
- int driver;
- qboolean extensions;
-} InitialVideoOptions_s;
-
-static InitialVideoOptions_s s_ivo;
-static graphicsoptions_t s_graphicsoptions;
-
-static InitialVideoOptions_s s_ivo_templates[] =
-{
- {
- 6, qtrue, 3, 0, qfalse,qfalse, 2, 2, 2, 1, 0, 0, qtrue
- },
- {
- 4, qtrue, 2, 0, qfalse,qfalse, 2, 2, 1, 1, 0, 0, qtrue // JDC: this was tq 3
- },
- {
- 3, qtrue, 2, 0, qfalse,qfalse, 0, 0, 1, 0, 0, 0, qtrue
- },
- {
- 2, qtrue, 1, 0, qfalse,qfalse, 1, 0, 0, 0, 0, 0, qtrue
- },
- {
- 2, qtrue, 1, 1, qfalse,qfalse, 1, 0, 0, 0, 0, 0, qtrue
- },
- {
- 3, qtrue, 1, 0, qfalse,qfalse, 0, 0, 1, 0, 0, 0, qtrue
- }
-};
-
-#define NUM_IVO_TEMPLATES ( sizeof( s_ivo_templates ) / sizeof( s_ivo_templates[0] ) )
-
-static const char *builtinResolutions[ ] =
-{
- "320x240",
- "400x300",
- "512x384",
- "640x480",
- "800x600",
- "960x720",
- "1024x768",
- "1152x864",
- "1280x1024",
- "1600x1200",
- "2048x1536",
- "856x480",
- NULL
-};
-
-static const char *knownRatios[ ][2] =
-{
- { "1.25:1", "5:4" },
- { "1.33:1", "4:3" },
- { "1.50:1", "3:2" },
- { "1.56:1", "14:9" },
- { "1.60:1", "16:10" },
- { "1.67:1", "5:3" },
- { "1.78:1", "16:9" },
- { NULL , NULL }
-};
-
-#define MAX_RESOLUTIONS 32
-
-static const char* ratios[ MAX_RESOLUTIONS ];
-static char ratioBuf[ MAX_RESOLUTIONS ][ 8 ];
-static int ratioToRes[ MAX_RESOLUTIONS ];
-static int resToRatio[ MAX_RESOLUTIONS ];
-
-static char resbuf[ MAX_STRING_CHARS ];
-static const char* detectedResolutions[ MAX_RESOLUTIONS ];
-
-static const char** resolutions = builtinResolutions;
-static qboolean resolutionsDetected = qfalse;
-
-/*
-=================
-GraphicsOptions_FindBuiltinResolution
-=================
-*/
-static int GraphicsOptions_FindBuiltinResolution( int mode )
-{
- int i;
-
- if( !resolutionsDetected )
- return mode;
-
- if( mode < 0 )
- return -1;
-
- for( i = 0; builtinResolutions[ i ]; i++ )
- {
- if( !Q_stricmp( builtinResolutions[ i ], detectedResolutions[ mode ] ) )
- return i;
- }
-
- return -1;
-}
-
-/*
-=================
-GraphicsOptions_FindDetectedResolution
-=================
-*/
-static int GraphicsOptions_FindDetectedResolution( int mode )
-{
- int i;
-
- if( !resolutionsDetected )
- return mode;
-
- if( mode < 0 )
- return -1;
-
- for( i = 0; detectedResolutions[ i ]; i++ )
- {
- if( !Q_stricmp( builtinResolutions[ mode ], detectedResolutions[ i ] ) )
- return i;
- }
-
- return -1;
-}
-
-/*
-=================
-GraphicsOptions_GetAspectRatios
-=================
-*/
-static void GraphicsOptions_GetAspectRatios( void )
-{
- int i, r;
-
- // build ratio list from resolutions
- for( r = 0; resolutions[r]; r++ )
- {
- int w, h;
- char *x;
- char str[ sizeof(ratioBuf[0]) ];
-
- // calculate resolution's aspect ratio
- x = strchr( resolutions[r], 'x' ) + 1;
- Q_strncpyz( str, resolutions[r], x-resolutions[r] );
- w = atoi( str );
- h = atoi( x );
- Com_sprintf( str, sizeof(str), "%.2f:1", (float)w / (float)h );
-
- // add ratio to list if it is new
- // establish res/ratio relationship
- for( i = 0; ratioBuf[i][0]; i++ )
- {
- if( !Q_stricmp( str, ratioBuf[i] ) )
- break;
- }
- if( !ratioBuf[i][0] )
- {
- Q_strncpyz( ratioBuf[i], str, sizeof(ratioBuf[i]) );
- ratioToRes[i] = r;
- }
- resToRatio[r] = i;
- }
-
- // prepare itemlist pointer array
- // rename common ratios ("1.33:1" -> "4:3")
- for( r = 0; ratioBuf[r][0]; r++ )
- {
- for( i = 0; knownRatios[i][0]; i++ )
- {
- if( !Q_stricmp( ratioBuf[r], knownRatios[i][0] ) )
- {
- Q_strncpyz( ratioBuf[r], knownRatios[i][1], sizeof(ratioBuf[r]) );
- break;
- }
- }
- ratios[r] = ratioBuf[r];
- }
- ratios[r] = NULL;
-}
-
-/*
-=================
-GraphicsOptions_GetInitialVideo
-=================
-*/
-static void GraphicsOptions_GetInitialVideo( void )
-{
- s_ivo.colordepth = s_graphicsoptions.colordepth.curvalue;
- s_ivo.driver = s_graphicsoptions.driver.curvalue;
- s_ivo.mode = s_graphicsoptions.mode.curvalue;
- s_ivo.fullscreen = s_graphicsoptions.fs.curvalue;
- s_ivo.extensions = s_graphicsoptions.allow_extensions.curvalue;
- s_ivo.tq = s_graphicsoptions.tq.curvalue;
- s_ivo.lighting = s_graphicsoptions.lighting.curvalue;
- s_ivo.flares = s_graphicsoptions.flares.curvalue;
- s_ivo.bloom = s_graphicsoptions.bloom.curvalue;
- s_ivo.geometry = s_graphicsoptions.geometry.curvalue;
- s_ivo.filter = s_graphicsoptions.filter.curvalue;
- s_ivo.aniso = s_graphicsoptions.aniso.curvalue;
- s_ivo.texturebits = s_graphicsoptions.texturebits.curvalue;
-}
-
-/*
-=================
-GraphicsOptions_GetResolutions
-=================
-*/
-static void GraphicsOptions_GetResolutions( void )
-{
- Q_strncpyz(resbuf, UI_Cvar_VariableString("r_availableModes"), sizeof(resbuf));
- if(*resbuf)
- {
- char* s = resbuf;
- unsigned int i = 0;
- while( s && i < sizeof(detectedResolutions)/sizeof(detectedResolutions[0])-1)
- {
- detectedResolutions[i++] = s;
- s = strchr(s, ' ');
- if( s )
- *s++ = '\0';
- }
- detectedResolutions[ i ] = NULL;
-
- if( i > 0 )
- {
- resolutions = detectedResolutions;
- resolutionsDetected = qtrue;
- }
- }
-}
-
-/*
-=================
-GraphicsOptions_CheckConfig
-=================
-*/
-static void GraphicsOptions_CheckConfig( void )
-{
- int i;
-
- for ( i = 0; i < NUM_IVO_TEMPLATES-1; i++ )
- {
- if ( s_ivo_templates[i].colordepth != s_graphicsoptions.colordepth.curvalue )
- continue;
- if ( s_ivo_templates[i].driver != s_graphicsoptions.driver.curvalue )
- continue;
- if ( GraphicsOptions_FindDetectedResolution(s_ivo_templates[i].mode) != s_graphicsoptions.mode.curvalue )
- continue;
- if ( s_ivo_templates[i].fullscreen != s_graphicsoptions.fs.curvalue )
- continue;
- if ( s_ivo_templates[i].tq != s_graphicsoptions.tq.curvalue )
- continue;
- if ( s_ivo_templates[i].lighting != s_graphicsoptions.lighting.curvalue )
- continue;
- if ( s_ivo_templates[i].flares != s_graphicsoptions.flares.curvalue )
- continue;
- if ( s_ivo_templates[i].bloom != s_graphicsoptions.bloom.curvalue )
- continue;
- if ( s_ivo_templates[i].geometry != s_graphicsoptions.geometry.curvalue )
- continue;
- if ( s_ivo_templates[i].filter != s_graphicsoptions.filter.curvalue )
- continue;
- if ( s_ivo_templates[i].aniso != s_graphicsoptions.aniso.curvalue )
- continue;
-// if ( s_ivo_templates[i].texturebits != s_graphicsoptions.texturebits.curvalue )
-// continue;
- s_graphicsoptions.list.curvalue = i;
- return;
- }
-
- // return 'Custom' ivo template
- s_graphicsoptions.list.curvalue = NUM_IVO_TEMPLATES - 1;
-}
-
-/*
-=================
-GraphicsOptions_UpdateMenuItems
-=================
-*/
-static void GraphicsOptions_UpdateMenuItems( void )
-{
- if ( s_graphicsoptions.driver.curvalue == 1 )
- {
- s_graphicsoptions.fs.curvalue = 1;
- s_graphicsoptions.fs.generic.flags |= QMF_GRAYED;
- s_graphicsoptions.colordepth.curvalue = 1;
- }
- else
- {
- s_graphicsoptions.fs.generic.flags &= ~QMF_GRAYED;
- }
-
- if ( s_graphicsoptions.fs.curvalue == 0 || s_graphicsoptions.driver.curvalue == 1 )
- {
- s_graphicsoptions.colordepth.curvalue = 0;
- s_graphicsoptions.colordepth.generic.flags |= QMF_GRAYED;
- }
- else
- {
- s_graphicsoptions.colordepth.generic.flags &= ~QMF_GRAYED;
- }
-
- if ( s_graphicsoptions.allow_extensions.curvalue == 0 )
- {
- if ( s_graphicsoptions.texturebits.curvalue == 0 )
- {
- s_graphicsoptions.texturebits.curvalue = 1;
- }
- }
-
- s_graphicsoptions.apply.generic.flags |= QMF_HIDDEN|QMF_INACTIVE;
-
- if ( s_ivo.mode != s_graphicsoptions.mode.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.fullscreen != s_graphicsoptions.fs.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.extensions != s_graphicsoptions.allow_extensions.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.tq != s_graphicsoptions.tq.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.lighting != s_graphicsoptions.lighting.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.flares != s_graphicsoptions.flares.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.bloom != s_graphicsoptions.bloom.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.colordepth != s_graphicsoptions.colordepth.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.driver != s_graphicsoptions.driver.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.texturebits != s_graphicsoptions.texturebits.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.geometry != s_graphicsoptions.geometry.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.filter != s_graphicsoptions.filter.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
- if ( s_ivo.aniso != s_graphicsoptions.aniso.curvalue )
- {
- s_graphicsoptions.apply.generic.flags &= ~(QMF_HIDDEN|QMF_INACTIVE);
- }
-
- GraphicsOptions_CheckConfig();
-}
-
-/*
-=================
-GraphicsOptions_ApplyChanges
-=================
-*/
-static void GraphicsOptions_ApplyChanges( void *unused, int notification )
-{
- if (notification != QM_ACTIVATED)
- return;
-
- switch ( s_graphicsoptions.texturebits.curvalue )
- {
- case 0:
- trap_Cvar_SetValue( "r_texturebits", 0 );
- break;
- case 1:
- trap_Cvar_SetValue( "r_texturebits", 16 );
- break;
- case 2:
- trap_Cvar_SetValue( "r_texturebits", 32 );
- break;
- }
- trap_Cvar_SetValue( "r_picmip", 3 - s_graphicsoptions.tq.curvalue );
- trap_Cvar_SetValue( "r_allowExtensions", s_graphicsoptions.allow_extensions.curvalue );
-
- if( resolutionsDetected )
- {
- // search for builtin mode that matches the detected mode
- int mode;
- if ( s_graphicsoptions.mode.curvalue == -1
- || s_graphicsoptions.mode.curvalue >= sizeof(detectedResolutions)/sizeof(detectedResolutions[0]) )
- s_graphicsoptions.mode.curvalue = 0;
-
- mode = GraphicsOptions_FindBuiltinResolution( s_graphicsoptions.mode.curvalue );
- if( mode == -1 )
- {
- char w[ 16 ], h[ 16 ];
- Q_strncpyz( w, detectedResolutions[ s_graphicsoptions.mode.curvalue ], sizeof( w ) );
- *strchr( w, 'x' ) = 0;
- Q_strncpyz( h,
- strchr( detectedResolutions[ s_graphicsoptions.mode.curvalue ], 'x' ) + 1, sizeof( h ) );
- trap_Cvar_Set( "r_customwidth", w );
- trap_Cvar_Set( "r_customheight", h );
- }
-
- trap_Cvar_SetValue( "r_mode", mode );
- }
- else
- trap_Cvar_SetValue( "r_mode", s_graphicsoptions.mode.curvalue );
-
- trap_Cvar_SetValue( "r_fullscreen", s_graphicsoptions.fs.curvalue );
- trap_Cvar_SetValue( "r_colorbits", 0 );
- trap_Cvar_SetValue( "r_depthbits", 0 );
- trap_Cvar_SetValue( "r_stencilbits", 0 );
- trap_Cvar_SetValue( "r_vertexLight", s_graphicsoptions.lighting.curvalue );
- trap_Cvar_SetValue( "cg_autovertex", s_graphicsoptions.lighting.curvalue );
- trap_Cvar_SetValue( "r_flares", s_graphicsoptions.flares.curvalue );
- trap_Cvar_SetValue( "r_bloom", s_graphicsoptions.bloom.curvalue );
-
- //r_ext_texture_filter_anisotropic is special
- if(s_graphicsoptions.aniso.curvalue) {
- trap_Cvar_SetValue( "r_ext_max_anisotropy", s_graphicsoptions.aniso.curvalue*2 );
- trap_Cvar_SetValue( "r_ext_texture_filter_anisotropic", qtrue );
- }
- else
- trap_Cvar_SetValue( "r_ext_texture_filter_anisotropic", qfalse );
-
- trap_Cvar_SetValue( "com_hunkmegs", 128 );
-
-
- if ( s_graphicsoptions.geometry.curvalue == 2 )
- {
- trap_Cvar_SetValue( "r_lodBias", 0 );
- trap_Cvar_SetValue( "r_subdivisions", 4 );
- }
- else if ( s_graphicsoptions.geometry.curvalue == 1 )
- {
- trap_Cvar_SetValue( "r_lodBias", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 12 );
- }
- else
- {
- trap_Cvar_SetValue( "r_lodBias", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 20 );
- }
-
- if ( s_graphicsoptions.filter.curvalue )
- {
- trap_Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR" );
- }
- else
- {
- trap_Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" );
- }
-
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" );
-}
-
-/*
-=================
-GraphicsOptions_Event
-=================
-*/
-static void GraphicsOptions_Event( void* ptr, int event ) {
- InitialVideoOptions_s *ivo;
-
- if( event != QM_ACTIVATED ) {
- return;
- }
-
- switch( ((menucommon_s*)ptr)->id ) {
- case ID_RATIO:
- s_graphicsoptions.mode.curvalue = ratioToRes[ s_graphicsoptions.ratio.curvalue ];
- // fall through to apply mode constraints
- case ID_MODE:
- // clamp 3dfx video modes
- if ( s_graphicsoptions.driver.curvalue == 1 )
- {
- if ( s_graphicsoptions.mode.curvalue < 2 )
- s_graphicsoptions.mode.curvalue = 2;
- else if ( s_graphicsoptions.mode.curvalue > 6 )
- s_graphicsoptions.mode.curvalue = 6;
- }
- s_graphicsoptions.ratio.curvalue = resToRatio[ s_graphicsoptions.mode.curvalue ];
- break;
-
- case ID_LIST:
- ivo = &s_ivo_templates[s_graphicsoptions.list.curvalue];
-
- s_graphicsoptions.mode.curvalue = GraphicsOptions_FindDetectedResolution(ivo->mode);
- s_graphicsoptions.ratio.curvalue = resToRatio[ s_graphicsoptions.mode.curvalue ];
- s_graphicsoptions.tq.curvalue = ivo->tq;
- s_graphicsoptions.lighting.curvalue = ivo->lighting;
- s_graphicsoptions.colordepth.curvalue = ivo->colordepth;
- s_graphicsoptions.texturebits.curvalue = ivo->texturebits;
- s_graphicsoptions.geometry.curvalue = ivo->geometry;
- s_graphicsoptions.filter.curvalue = ivo->filter;
- s_graphicsoptions.aniso.curvalue = ivo->aniso;
- s_graphicsoptions.fs.curvalue = ivo->fullscreen;
- s_graphicsoptions.flares.curvalue = ivo->flares;
- s_graphicsoptions.bloom.curvalue = ivo->bloom;
- break;
-
- case ID_DRIVERINFO:
- UI_DriverInfo_Menu();
- break;
-
- case ID_BACK2:
- UI_PopMenu();
- break;
-
- case ID_GRAPHICS:
- break;
-
- case ID_DISPLAY:
- UI_PopMenu();
- UI_DisplayOptionsMenu();
- break;
-
- case ID_SOUND:
- UI_PopMenu();
- UI_SoundOptionsMenu();
- break;
-
- case ID_NETWORK:
- UI_PopMenu();
- UI_NetworkOptionsMenu();
- break;
- }
-}
-
-
-/*
-================
-GraphicsOptions_TQEvent
-================
-*/
-static void GraphicsOptions_TQEvent( void *ptr, int event ) {
- if( event != QM_ACTIVATED ) {
- return;
- }
- s_graphicsoptions.tq.curvalue = (int)(s_graphicsoptions.tq.curvalue + 0.5);
-}
-
-
-/*
-================
-GraphicsOptions_MenuDraw
-================
-*/
-void GraphicsOptions_MenuDraw (void)
-{
-//APSFIX - rework this
- GraphicsOptions_UpdateMenuItems();
-
- Menu_Draw( &s_graphicsoptions.menu );
-}
-
-/*
-=================
-GraphicsOptions_SetMenuItems
-=================
-*/
-static void GraphicsOptions_SetMenuItems( void )
-{
- s_graphicsoptions.mode.curvalue =
- GraphicsOptions_FindDetectedResolution( trap_Cvar_VariableValue( "r_mode" ) );
-
- if ( s_graphicsoptions.mode.curvalue < 0 )
- {
- if( resolutionsDetected )
- {
- int i;
- char buf[MAX_STRING_CHARS];
- trap_Cvar_VariableStringBuffer("r_customwidth", buf, sizeof(buf)-2);
- buf[strlen(buf)+1] = 0;
- buf[strlen(buf)] = 'x';
- trap_Cvar_VariableStringBuffer("r_customheight", buf+strlen(buf), sizeof(buf)-strlen(buf));
-
- for(i = 0; detectedResolutions[i]; ++i)
- {
- if(!Q_stricmp(buf, detectedResolutions[i]))
- {
- s_graphicsoptions.mode.curvalue = i;
- break;
- }
- }
- if ( s_graphicsoptions.mode.curvalue < 0 )
- s_graphicsoptions.mode.curvalue = 0;
- }
- else
- {
- s_graphicsoptions.mode.curvalue = 3;
- }
- }
- s_graphicsoptions.fs.curvalue = trap_Cvar_VariableValue("r_fullscreen");
- s_graphicsoptions.allow_extensions.curvalue = trap_Cvar_VariableValue("r_allowExtensions");
- s_graphicsoptions.flares.curvalue = trap_Cvar_VariableValue("r_flares");
- s_graphicsoptions.bloom.curvalue = trap_Cvar_VariableValue("r_bloom");
- if(trap_Cvar_VariableValue("r_ext_texture_filter_anisotropic")) {
- s_graphicsoptions.aniso.curvalue = trap_Cvar_VariableValue("r_ext_max_anisotropy")/2;
- }
- s_graphicsoptions.tq.curvalue = 3-trap_Cvar_VariableValue( "r_picmip");
- if ( s_graphicsoptions.tq.curvalue < 0 )
- {
- s_graphicsoptions.tq.curvalue = 0;
- }
- else if ( s_graphicsoptions.tq.curvalue > 3 )
- {
- s_graphicsoptions.tq.curvalue = 3;
- }
-
- s_graphicsoptions.lighting.curvalue = trap_Cvar_VariableValue( "r_vertexLight" ) != 0;
- switch ( ( int ) trap_Cvar_VariableValue( "r_texturebits" ) )
- {
- default:
- case 0:
- s_graphicsoptions.texturebits.curvalue = 0;
- break;
- case 16:
- s_graphicsoptions.texturebits.curvalue = 1;
- break;
- case 32:
- s_graphicsoptions.texturebits.curvalue = 2;
- break;
- }
-
- if ( !Q_stricmp( UI_Cvar_VariableString( "r_textureMode" ), "GL_LINEAR_MIPMAP_NEAREST" ) )
- {
- s_graphicsoptions.filter.curvalue = 0;
- }
- else
- {
- s_graphicsoptions.filter.curvalue = 1;
- }
-
- if ( trap_Cvar_VariableValue( "r_lodBias" ) > 0 )
- {
- if ( trap_Cvar_VariableValue( "r_subdivisions" ) >= 20 )
- {
- s_graphicsoptions.geometry.curvalue = 0;
- }
- else
- {
- s_graphicsoptions.geometry.curvalue = 1;
- }
- }
- else
- {
- s_graphicsoptions.geometry.curvalue = 2;
- }
-
- switch ( ( int ) trap_Cvar_VariableValue( "r_colorbits" ) )
- {
- default:
- case 0:
- s_graphicsoptions.colordepth.curvalue = 0;
- break;
- case 16:
- s_graphicsoptions.colordepth.curvalue = 1;
- break;
- case 32:
- s_graphicsoptions.colordepth.curvalue = 2;
- break;
- }
-
- if ( s_graphicsoptions.fs.curvalue == 0 )
- {
- s_graphicsoptions.colordepth.curvalue = 0;
- }
- if ( s_graphicsoptions.driver.curvalue == 1 )
- {
- s_graphicsoptions.colordepth.curvalue = 1;
- }
-}
-
-/*
-================
-GraphicsOptions_MenuInit
-================
-*/
-void GraphicsOptions_MenuInit( void )
-{
- static const char *s_driver_names[] =
- {
- "Default",
- "Voodoo",
- NULL
- };
-
- static const char *tq_names[] =
- {
- "Default",
- "16 bit",
- "32 bit",
- NULL
- };
-
- static const char *s_graphics_options_names[] =
- {
- "Very High Quality",
- "High Quality",
- "Normal",
- "Fast",
- "Fastest",
- "Custom",
- NULL
- };
-
- static const char *lighting_names[] =
- {
- "Lightmap (Normal)",
- "Vertex (Low)",
- NULL
- };
-
- static const char *colordepth_names[] =
- {
- "Default",
- "16 bit",
- "32 bit",
- NULL
- };
-
- static const char *filter_names[] =
- {
- "Bilinear",
- "Trilinear",
- NULL
- };
-
- static const char *aniso_names[] =
- {
- "Off",
- "2x",
- "4x",
- "6x",
- "8x",
- NULL
- };
-
- static const char *quality_names[] =
- {
- "Low",
- "Medium",
- "High",
- NULL
- };
- static const char *enabled_names[] =
- {
- "Off",
- "On",
- NULL
- };
-
- int y;
-
- // zero set all our globals
- memset( &s_graphicsoptions, 0 ,sizeof(graphicsoptions_t) );
-
-
- GraphicsOptions_GetResolutions();
- GraphicsOptions_GetAspectRatios();
-
- GraphicsOptions_Cache();
-
- s_graphicsoptions.menu.wrapAround = qtrue;
- s_graphicsoptions.menu.fullscreen = qtrue;
- s_graphicsoptions.menu.draw = GraphicsOptions_MenuDraw;
-
- s_graphicsoptions.banner.generic.type = MTYPE_BTEXT;
- s_graphicsoptions.banner.generic.x = 320;
- s_graphicsoptions.banner.generic.y = 16;
- s_graphicsoptions.banner.string = "SYSTEM SETUP";
- s_graphicsoptions.banner.color = color_white;
- s_graphicsoptions.banner.style = UI_CENTER;
-
- s_graphicsoptions.framel.generic.type = MTYPE_BITMAP;
- s_graphicsoptions.framel.generic.name = GRAPHICSOPTIONS_FRAMEL;
- s_graphicsoptions.framel.generic.flags = QMF_INACTIVE;
- s_graphicsoptions.framel.generic.x = 0;
- s_graphicsoptions.framel.generic.y = 78;
- s_graphicsoptions.framel.width = 256;
- s_graphicsoptions.framel.height = 329;
-
- s_graphicsoptions.framer.generic.type = MTYPE_BITMAP;
- s_graphicsoptions.framer.generic.name = GRAPHICSOPTIONS_FRAMER;
- s_graphicsoptions.framer.generic.flags = QMF_INACTIVE;
- s_graphicsoptions.framer.generic.x = 376;
- s_graphicsoptions.framer.generic.y = 76;
- s_graphicsoptions.framer.width = 256;
- s_graphicsoptions.framer.height = 334;
-
- s_graphicsoptions.graphics.generic.type = MTYPE_PTEXT;
- s_graphicsoptions.graphics.generic.flags = QMF_RIGHT_JUSTIFY;
- s_graphicsoptions.graphics.generic.id = ID_GRAPHICS;
- s_graphicsoptions.graphics.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.graphics.generic.x = 216;
- s_graphicsoptions.graphics.generic.y = 240 - 2 * PROP_HEIGHT;
- s_graphicsoptions.graphics.string = "GRAPHICS";
- s_graphicsoptions.graphics.style = UI_RIGHT;
- s_graphicsoptions.graphics.color = color_red;
-
- s_graphicsoptions.display.generic.type = MTYPE_PTEXT;
- s_graphicsoptions.display.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_graphicsoptions.display.generic.id = ID_DISPLAY;
- s_graphicsoptions.display.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.display.generic.x = 216;
- s_graphicsoptions.display.generic.y = 240 - PROP_HEIGHT;
- s_graphicsoptions.display.string = "DISPLAY";
- s_graphicsoptions.display.style = UI_RIGHT;
- s_graphicsoptions.display.color = color_red;
-
- s_graphicsoptions.sound.generic.type = MTYPE_PTEXT;
- s_graphicsoptions.sound.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_graphicsoptions.sound.generic.id = ID_SOUND;
- s_graphicsoptions.sound.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.sound.generic.x = 216;
- s_graphicsoptions.sound.generic.y = 240;
- s_graphicsoptions.sound.string = "SOUND";
- s_graphicsoptions.sound.style = UI_RIGHT;
- s_graphicsoptions.sound.color = color_red;
-
- s_graphicsoptions.network.generic.type = MTYPE_PTEXT;
- s_graphicsoptions.network.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_graphicsoptions.network.generic.id = ID_NETWORK;
- s_graphicsoptions.network.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.network.generic.x = 216;
- s_graphicsoptions.network.generic.y = 240 + PROP_HEIGHT;
- s_graphicsoptions.network.string = "NETWORK";
- s_graphicsoptions.network.style = UI_RIGHT;
- s_graphicsoptions.network.color = color_red;
-
- y = 240 - 7 * (BIGCHAR_HEIGHT + 2);
- s_graphicsoptions.list.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.list.generic.name = "Graphics Settings:";
- s_graphicsoptions.list.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.list.generic.x = 400;
- s_graphicsoptions.list.generic.y = y;
- s_graphicsoptions.list.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.list.generic.id = ID_LIST;
- s_graphicsoptions.list.itemnames = s_graphics_options_names;
- y += 2 * ( BIGCHAR_HEIGHT + 2 );
-
- s_graphicsoptions.driver.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.driver.generic.name = "GL Driver:";
- s_graphicsoptions.driver.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.driver.generic.x = 400;
- s_graphicsoptions.driver.generic.y = y;
- s_graphicsoptions.driver.itemnames = s_driver_names;
- s_graphicsoptions.driver.curvalue = (uis.glconfig.driverType == GLDRV_VOODOO);
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_allowExtensions"
- s_graphicsoptions.allow_extensions.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.allow_extensions.generic.name = "GL Extensions:";
- s_graphicsoptions.allow_extensions.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.allow_extensions.generic.x = 400;
- s_graphicsoptions.allow_extensions.generic.y = y;
- s_graphicsoptions.allow_extensions.itemnames = enabled_names;
- y += BIGCHAR_HEIGHT+2;
-
- s_graphicsoptions.ratio.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.ratio.generic.name = "Aspect Ratio:";
- s_graphicsoptions.ratio.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.ratio.generic.x = 400;
- s_graphicsoptions.ratio.generic.y = y;
- s_graphicsoptions.ratio.itemnames = ratios;
- s_graphicsoptions.ratio.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.ratio.generic.id = ID_RATIO;
- y += BIGCHAR_HEIGHT+2;
-
-
- // references/modifies "r_mode"
- s_graphicsoptions.mode.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.mode.generic.name = "Resolution:";
- s_graphicsoptions.mode.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.mode.generic.x = 400;
- s_graphicsoptions.mode.generic.y = y;
- s_graphicsoptions.mode.itemnames = resolutions;
- s_graphicsoptions.mode.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.mode.generic.id = ID_MODE;
- y += BIGCHAR_HEIGHT+2;
-
- // references "r_colorbits"
- s_graphicsoptions.colordepth.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.colordepth.generic.name = "Color Depth:";
- s_graphicsoptions.colordepth.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.colordepth.generic.x = 400;
- s_graphicsoptions.colordepth.generic.y = y;
- s_graphicsoptions.colordepth.itemnames = colordepth_names;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_fullscreen"
- s_graphicsoptions.fs.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.fs.generic.name = "Fullscreen:";
- s_graphicsoptions.fs.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.fs.generic.x = 400;
- s_graphicsoptions.fs.generic.y = y;
- s_graphicsoptions.fs.itemnames = enabled_names;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_vertexLight"
- s_graphicsoptions.lighting.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.lighting.generic.name = "Lighting:";
- s_graphicsoptions.lighting.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.lighting.generic.x = 400;
- s_graphicsoptions.lighting.generic.y = y;
- s_graphicsoptions.lighting.itemnames = lighting_names;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_flares"
- s_graphicsoptions.flares.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.flares.generic.name = "Flares:";
- s_graphicsoptions.flares.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.flares.generic.x = 400;
- s_graphicsoptions.flares.generic.y = y;
- s_graphicsoptions.flares.itemnames = enabled_names;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_bloom"
- s_graphicsoptions.bloom.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.bloom.generic.name = "Bloom:";
- s_graphicsoptions.bloom.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.bloom.generic.x = 400;
- s_graphicsoptions.bloom.generic.y = y;
- s_graphicsoptions.bloom.itemnames = enabled_names;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_lodBias" & "subdivisions"
- s_graphicsoptions.geometry.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.geometry.generic.name = "Geometric Detail:";
- s_graphicsoptions.geometry.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.geometry.generic.x = 400;
- s_graphicsoptions.geometry.generic.y = y;
- s_graphicsoptions.geometry.itemnames = quality_names;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_picmip"
- s_graphicsoptions.tq.generic.type = MTYPE_SLIDER;
- s_graphicsoptions.tq.generic.name = "Texture Detail:";
- s_graphicsoptions.tq.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.tq.generic.x = 400;
- s_graphicsoptions.tq.generic.y = y;
- s_graphicsoptions.tq.minvalue = 0;
- s_graphicsoptions.tq.maxvalue = 3;
- s_graphicsoptions.tq.generic.callback = GraphicsOptions_TQEvent;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_textureBits"
- s_graphicsoptions.texturebits.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.texturebits.generic.name = "Texture Quality:";
- s_graphicsoptions.texturebits.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.texturebits.generic.x = 400;
- s_graphicsoptions.texturebits.generic.y = y;
- s_graphicsoptions.texturebits.itemnames = tq_names;
- y += BIGCHAR_HEIGHT+2;
-
- // references/modifies "r_textureMode"
- s_graphicsoptions.filter.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.filter.generic.name = "Texture Filter:";
- s_graphicsoptions.filter.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.filter.generic.x = 400;
- s_graphicsoptions.filter.generic.y = y;
- s_graphicsoptions.filter.itemnames = filter_names;
- y += 2+BIGCHAR_HEIGHT;
-
- s_graphicsoptions.aniso.generic.type = MTYPE_SPINCONTROL;
- s_graphicsoptions.aniso.generic.name = "Anisotropy:";
- s_graphicsoptions.aniso.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
- s_graphicsoptions.aniso.generic.x = 400;
- s_graphicsoptions.aniso.generic.y = y;
- s_graphicsoptions.aniso.itemnames = aniso_names;
- y += 2*BIGCHAR_HEIGHT;
-
- s_graphicsoptions.driverinfo.generic.type = MTYPE_PTEXT;
- s_graphicsoptions.driverinfo.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
- s_graphicsoptions.driverinfo.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.driverinfo.generic.id = ID_DRIVERINFO;
- s_graphicsoptions.driverinfo.generic.x = 320;
- s_graphicsoptions.driverinfo.generic.y = y;
- s_graphicsoptions.driverinfo.string = "Driver Info";
- s_graphicsoptions.driverinfo.style = UI_CENTER|UI_SMALLFONT;
- s_graphicsoptions.driverinfo.color = color_red;
- y += BIGCHAR_HEIGHT+2;
-
- s_graphicsoptions.back.generic.type = MTYPE_BITMAP;
- s_graphicsoptions.back.generic.name = GRAPHICSOPTIONS_BACK0;
- s_graphicsoptions.back.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
- s_graphicsoptions.back.generic.callback = GraphicsOptions_Event;
- s_graphicsoptions.back.generic.id = ID_BACK2;
- s_graphicsoptions.back.generic.x = 0;
- s_graphicsoptions.back.generic.y = 480-64;
- s_graphicsoptions.back.width = 128;
- s_graphicsoptions.back.height = 64;
- s_graphicsoptions.back.focuspic = GRAPHICSOPTIONS_BACK1;
-
- s_graphicsoptions.apply.generic.type = MTYPE_BITMAP;
- s_graphicsoptions.apply.generic.name = GRAPHICSOPTIONS_ACCEPT0;
- s_graphicsoptions.apply.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_HIDDEN|QMF_INACTIVE;
- s_graphicsoptions.apply.generic.callback = GraphicsOptions_ApplyChanges;
- s_graphicsoptions.apply.generic.x = 640;
- s_graphicsoptions.apply.generic.y = 480-64;
- s_graphicsoptions.apply.width = 128;
- s_graphicsoptions.apply.height = 64;
- s_graphicsoptions.apply.focuspic = GRAPHICSOPTIONS_ACCEPT1;
-
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.banner );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.framel );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.framer );
-
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.graphics );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.display );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.sound );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.network );
-
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.list );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.driver );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.allow_extensions );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.ratio );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.mode );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.colordepth );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.fs );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.lighting );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.flares );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.bloom );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.geometry );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.tq );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.texturebits );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.filter );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.aniso );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.driverinfo );
-
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.back );
- Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.apply );
-
- GraphicsOptions_SetMenuItems();
- GraphicsOptions_GetInitialVideo();
-
- if ( uis.glconfig.driverType == GLDRV_ICD &&
- uis.glconfig.hardwareType == GLHW_3DFX_2D3D )
- {
- s_graphicsoptions.driver.generic.flags |= QMF_HIDDEN|QMF_INACTIVE;
- }
-}
-
-
-/*
-=================
-GraphicsOptions_Cache
-=================
-*/
-void GraphicsOptions_Cache( void ) {
- trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_FRAMEL );
- trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_FRAMER );
- trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_BACK0 );
- trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_BACK1 );
- trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_ACCEPT0 );
- trap_R_RegisterShaderNoMip( GRAPHICSOPTIONS_ACCEPT1 );
-}
-
-
-/*
-=================
-UI_GraphicsOptionsMenu
-=================
-*/
-void UI_GraphicsOptionsMenu( void ) {
- GraphicsOptions_MenuInit();
- UI_PushMenu( &s_graphicsoptions.menu );
- Menu_SetCursorToItem( &s_graphicsoptions.menu, &s_graphicsoptions.graphics );
-}
diff --git a/game/code/qcommon/q_shared.c b/game/code/qcommon/q_shared.c
deleted file mode 100644
index 275f628..0000000
--- a/game/code/qcommon/q_shared.c
+++ /dev/null
@@ -1,1397 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// q_shared.c -- stateless support routines that are included in each code dll
-#include "q_shared.h"
-
-float Com_Clamp( float min, float max, float value ) {
- if ( value < min ) {
- return min;
- }
- if ( value > max ) {
- return max;
- }
- return value;
-}
-
-
-/*
-============
-COM_SkipPath
-============
-*/
-char *COM_SkipPath (char *pathname)
-{
- char *last;
-
- last = pathname;
- while (*pathname)
- {
- if (*pathname=='/')
- last = pathname+1;
- pathname++;
- }
- return last;
-}
-
-/*
-============
-COM_GetExtension
-============
-*/
-const char *COM_GetExtension( const char *name ) {
- int length, i;
-
- length = strlen(name)-1;
- i = length;
-
- while (name[i] != '.')
- {
- i--;
- if (name[i] == '/' || i == 0)
- return ""; // no extension
- }
-
- return &name[i+1];
-}
-
-
-/*
-============
-COM_StripExtension
-============
-*/
-void COM_StripExtension( const char *in, char *out, int destsize ) {
- int length;
-
- Q_strncpyz(out, in, destsize);
-
- length = strlen(out)-1;
- while (length > 0 && out[length] != '.')
- {
- length--;
- if (out[length] == '/')
- return; // no extension
- }
- if (length)
- out[length] = 0;
-}
-
-
-/*
-==================
-COM_DefaultExtension
-==================
-*/
-void COM_DefaultExtension (char *path, int maxSize, const char *extension ) {
- char oldPath[MAX_QPATH];
- char *src;
-
-//
-// if path doesn't have a .EXT, append extension
-// (extension should include the .)
-//
- src = path + strlen(path) - 1;
-
- while (*src != '/' && src != path) {
- if ( *src == '.' ) {
- return; // it has an extension
- }
- src--;
- }
-
- Q_strncpyz( oldPath, path, sizeof( oldPath ) );
- Com_sprintf( path, maxSize, "%s%s", oldPath, extension );
-}
-
-/*
-============================================================================
-
- BYTE ORDER FUNCTIONS
-
-============================================================================
-*/
-/*
-// can't just use function pointers, or dll linkage can
-// mess up when qcommon is included in multiple places
-static short (*_BigShort) (short l);
-static short (*_LittleShort) (short l);
-static int (*_BigLong) (int l);
-static int (*_LittleLong) (int l);
-static qint64 (*_BigLong64) (qint64 l);
-static qint64 (*_LittleLong64) (qint64 l);
-static float (*_BigFloat) (const float *l);
-static float (*_LittleFloat) (const float *l);
-
-short BigShort(short l){return _BigShort(l);}
-short LittleShort(short l) {return _LittleShort(l);}
-int BigLong (int l) {return _BigLong(l);}
-int LittleLong (int l) {return _LittleLong(l);}
-qint64 BigLong64 (qint64 l) {return _BigLong64(l);}
-qint64 LittleLong64 (qint64 l) {return _LittleLong64(l);}
-float BigFloat (const float *l) {return _BigFloat(l);}
-float LittleFloat (const float *l) {return _LittleFloat(l);}
-*/
-
-short ShortSwap (short l)
-{
- byte b1,b2;
-
- b1 = l&255;
- b2 = (l>>8)&255;
-
- return (b1<<8) + b2;
-}
-
-short ShortNoSwap (short l)
-{
- return l;
-}
-
-int LongSwap (int l)
-{
- byte b1,b2,b3,b4;
-
- b1 = l&255;
- b2 = (l>>8)&255;
- b3 = (l>>16)&255;
- b4 = (l>>24)&255;
-
- return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
-}
-
-int LongNoSwap (int l)
-{
- return l;
-}
-
-qint64 Long64Swap (qint64 ll)
-{
- qint64 result;
-
- result.b0 = ll.b7;
- result.b1 = ll.b6;
- result.b2 = ll.b5;
- result.b3 = ll.b4;
- result.b4 = ll.b3;
- result.b5 = ll.b2;
- result.b6 = ll.b1;
- result.b7 = ll.b0;
-
- return result;
-}
-
-qint64 Long64NoSwap (qint64 ll)
-{
- return ll;
-}
-
-typedef union {
- float f;
- unsigned int i;
-} _FloatByteUnion;
-
-float FloatSwap (const float *f) {
- _FloatByteUnion out;
-
- out.f = *f;
- out.i = LongSwap(out.i);
-
- return out.f;
-}
-
-float FloatNoSwap (const float *f)
-{
- return *f;
-}
-
-/*
-================
-Swap_Init
-================
-*/
-/*
-void Swap_Init (void)
-{
- byte swaptest[2] = {1,0};
-
-// set the byte swapping variables in a portable manner
- if ( *(short *)swaptest == 1)
- {
- _BigShort = ShortSwap;
- _LittleShort = ShortNoSwap;
- _BigLong = LongSwap;
- _LittleLong = LongNoSwap;
- _BigLong64 = Long64Swap;
- _LittleLong64 = Long64NoSwap;
- _BigFloat = FloatSwap;
- _LittleFloat = FloatNoSwap;
- }
- else
- {
- _BigShort = ShortNoSwap;
- _LittleShort = ShortSwap;
- _BigLong = LongNoSwap;
- _LittleLong = LongSwap;
- _BigLong64 = Long64NoSwap;
- _LittleLong64 = Long64Swap;
- _BigFloat = FloatNoSwap;
- _LittleFloat = FloatSwap;
- }
-
-}
-*/
-
-/*
-============================================================================
-
-PARSING
-
-============================================================================
-*/
-
-static char com_token[MAX_TOKEN_CHARS];
-static char com_parsename[MAX_TOKEN_CHARS];
-static int com_lines;
-
-void COM_BeginParseSession( const char *name )
-{
- com_lines = 0;
- Com_sprintf(com_parsename, sizeof(com_parsename), "%s", name);
-}
-
-int COM_GetCurrentParseLine( void )
-{
- return com_lines;
-}
-
-char *COM_Parse( char **data_p )
-{
- return COM_ParseExt( data_p, qtrue );
-}
-
-void COM_ParseError( char *format, ... )
-{
- va_list argptr;
- static char string[4096];
-
- va_start (argptr, format);
- Q_vsnprintf (string, sizeof(string), format, argptr);
- va_end (argptr);
-
- Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, com_lines, string);
-}
-
-void COM_ParseWarning( char *format, ... )
-{
- va_list argptr;
- static char string[4096];
-
- va_start (argptr, format);
- Q_vsnprintf (string, sizeof(string), format, argptr);
- va_end (argptr);
-
- Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, com_lines, string);
-}
-
-/*
-==============
-COM_Parse
-
-Parse a token out of a string
-Will never return NULL, just empty strings
-
-If "allowLineBreaks" is qtrue then an empty
-string will be returned if the next token is
-a newline.
-==============
-*/
-static char *SkipWhitespace( char *data, qboolean *hasNewLines ) {
- int c;
-
- while( (c = *data) <= ' ') {
- if( !c ) {
- return NULL;
- }
- if( c == '\n' ) {
- com_lines++;
- *hasNewLines = qtrue;
- }
- data++;
- }
-
- return data;
-}
-
-int COM_Compress( char *data_p ) {
- char *in, *out;
- int c;
- qboolean newline = qfalse, whitespace = qfalse;
-
- in = out = data_p;
- if (in) {
- while ((c = *in) != 0) {
- // skip double slash comments
- if ( c == '/' && in[1] == '/' ) {
- while (*in && *in != '\n') {
- in++;
- }
- // skip /* */ comments
- } else if ( c == '/' && in[1] == '*' ) {
- while ( *in && ( *in != '*' || in[1] != '/' ) )
- in++;
- if ( *in )
- in += 2;
- // record when we hit a newline
- } else if ( c == '\n' || c == '\r' ) {
- newline = qtrue;
- in++;
- // record when we hit whitespace
- } else if ( c == ' ' || c == '\t') {
- whitespace = qtrue;
- in++;
- // an actual token
- } else {
- // if we have a pending newline, emit it (and it counts as whitespace)
- if (newline) {
- *out++ = '\n';
- newline = qfalse;
- whitespace = qfalse;
- } if (whitespace) {
- *out++ = ' ';
- whitespace = qfalse;
- }
-
- // copy quoted strings unmolested
- if (c == '"') {
- *out++ = c;
- in++;
- while (1) {
- c = *in;
- if (c && c != '"') {
- *out++ = c;
- in++;
- } else {
- break;
- }
- }
- if (c == '"') {
- *out++ = c;
- in++;
- }
- } else {
- *out = c;
- out++;
- in++;
- }
- }
- }
- }
- *out = 0;
- return out - data_p;
-}
-
-char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
-{
- int c = 0, len;
- qboolean hasNewLines = qfalse;
- char *data;
-
- data = *data_p;
- len = 0;
- com_token[0] = 0;
-
- // make sure incoming data is valid
- if ( !data )
- {
- *data_p = NULL;
- return com_token;
- }
-
- while ( 1 )
- {
- // skip whitespace
- data = SkipWhitespace( data, &hasNewLines );
- if ( !data )
- {
- *data_p = NULL;
- return com_token;
- }
- if ( hasNewLines && !allowLineBreaks )
- {
- *data_p = data;
- return com_token;
- }
-
- c = *data;
-
- // skip double slash comments
- if ( c == '/' && data[1] == '/' )
- {
- data += 2;
- while (*data && *data != '\n') {
- data++;
- }
- }
- // skip /* */ comments
- else if ( c=='/' && data[1] == '*' )
- {
- data += 2;
- while ( *data && ( *data != '*' || data[1] != '/' ) )
- {
- data++;
- }
- if ( *data )
- {
- data += 2;
- }
- }
- else
- {
- break;
- }
- }
-
- // handle quoted strings
- if (c == '\"')
- {
- data++;
- while (1)
- {
- c = *data++;
- if (c=='\"' || !c)
- {
- com_token[len] = 0;
- *data_p = ( char * ) data;
- return com_token;
- }
- if (len < MAX_TOKEN_CHARS - 1)
- {
- com_token[len] = c;
- len++;
- }
- }
- }
-
- // parse a regular word
- do
- {
- if (len < MAX_TOKEN_CHARS - 1)
- {
- com_token[len] = c;
- len++;
- }
- data++;
- c = *data;
- if ( c == '\n' )
- com_lines++;
- } while (c>32);
-
- com_token[len] = 0;
-
- *data_p = ( char * ) data;
- return com_token;
-}
-
-
-#if 0
-// no longer used
-/*
-===============
-COM_ParseInfos
-===============
-*/
-int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ) {
- char *token;
- int count;
- char key[MAX_TOKEN_CHARS];
-
- count = 0;
-
- while ( 1 ) {
- token = COM_Parse( &buf );
- if ( !token[0] ) {
- break;
- }
- if ( strcmp( token, "{" ) ) {
- Com_Printf( "Missing { in info file\n" );
- break;
- }
-
- if ( count == max ) {
- Com_Printf( "Max infos exceeded\n" );
- break;
- }
-
- infos[count][0] = 0;
- while ( 1 ) {
- token = COM_ParseExt( &buf, qtrue );
- if ( !token[0] ) {
- Com_Printf( "Unexpected end of info file\n" );
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- Q_strncpyz( key, token, sizeof( key ) );
-
- token = COM_ParseExt( &buf, qfalse );
- if ( !token[0] ) {
- strcpy( token, "<NULL>" );
- }
- Info_SetValueForKey( infos[count], key, token );
- }
- count++;
- }
-
- return count;
-}
-#endif
-
-
-/*
-==================
-COM_MatchToken
-==================
-*/
-void COM_MatchToken( char **buf_p, char *match ) {
- char *token;
-
- token = COM_Parse( buf_p );
- if ( strcmp( token, match ) ) {
- Com_Error( ERR_DROP, "MatchToken: %s != %s", token, match );
- }
-}
-
-
-/*
-=================
-SkipBracedSection
-
-The next token should be an open brace.
-Skips until a matching close brace is found.
-Internal brace depths are properly skipped.
-=================
-*/
-void SkipBracedSection (char **program) {
- char *token;
- int depth;
-
- depth = 0;
- do {
- token = COM_ParseExt( program, qtrue );
- if( token[1] == 0 ) {
- if( token[0] == '{' ) {
- depth++;
- }
- else if( token[0] == '}' ) {
- depth--;
- }
- }
- } while( depth && *program );
-}
-
-/*
-=================
-SkipRestOfLine
-=================
-*/
-void SkipRestOfLine ( char **data ) {
- char *p;
- int c;
-
- p = *data;
- while ( (c = *p++) != 0 ) {
- if ( c == '\n' ) {
- com_lines++;
- break;
- }
- }
-
- *data = p;
-}
-
-
-void Parse1DMatrix (char **buf_p, int x, float *m) {
- char *token;
- int i;
-
- COM_MatchToken( buf_p, "(" );
-
- for (i = 0 ; i < x ; i++) {
- token = COM_Parse(buf_p);
- m[i] = atof(token);
- }
-
- COM_MatchToken( buf_p, ")" );
-}
-
-void Parse2DMatrix (char **buf_p, int y, int x, float *m) {
- int i;
-
- COM_MatchToken( buf_p, "(" );
-
- for (i = 0 ; i < y ; i++) {
- Parse1DMatrix (buf_p, x, m + i * x);
- }
-
- COM_MatchToken( buf_p, ")" );
-}
-
-void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m) {
- int i;
-
- COM_MatchToken( buf_p, "(" );
-
- for (i = 0 ; i < z ; i++) {
- Parse2DMatrix (buf_p, y, x, m + i * x*y);
- }
-
- COM_MatchToken( buf_p, ")" );
-}
-
-
-/*
-============================================================================
-
- LIBRARY REPLACEMENT FUNCTIONS
-
-============================================================================
-*/
-
-int Q_isprint( int c )
-{
- if ( c >= 0x20 && c <= 0x7E )
- return ( 1 );
- return ( 0 );
-}
-
-int Q_islower( int c )
-{
- if (c >= 'a' && c <= 'z')
- return ( 1 );
- return ( 0 );
-}
-
-int Q_isupper( int c )
-{
- if (c >= 'A' && c <= 'Z')
- return ( 1 );
- return ( 0 );
-}
-
-int Q_isalpha( int c )
-{
- if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
- return ( 1 );
- return ( 0 );
-}
-
-char* Q_strrchr( const char* string, int c )
-{
- char cc = c;
- char *s;
- char *sp=(char *)0;
-
- s = (char*)string;
-
- while (*s)
- {
- if (*s == cc)
- sp = s;
- s++;
- }
- if (cc == 0)
- sp = s;
-
- return sp;
-}
-
-/*
-=============
-Q_strncpyz
-
-Safe strncpy that ensures a trailing zero
-=============
-*/
-void Q_strncpyz( char *dest, const char *src, int destsize ) {
- if ( !dest ) {
- Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" );
- }
- if ( !src ) {
- Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
- }
- if ( destsize < 1 ) {
- Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
- }
-
- strncpy( dest, src, destsize-1 );
- dest[destsize-1] = 0;
-}
-
-int Q_stricmpn (const char *s1, const char *s2, int n) {
- int c1, c2;
-
- if ( s1 == NULL ) {
- if ( s2 == NULL )
- return 0;
- else
- return -1;
- }
- else if ( s2==NULL )
- return 1;
-
-
-
- do {
- c1 = *s1++;
- c2 = *s2++;
-
- if (!n--) {
- return 0; // strings are equal until end point
- }
-
- if (c1 != c2) {
- if (c1 >= 'a' && c1 <= 'z') {
- c1 -= ('a' - 'A');
- }
- if (c2 >= 'a' && c2 <= 'z') {
- c2 -= ('a' - 'A');
- }
- if (c1 != c2) {
- return c1 < c2 ? -1 : 1;
- }
- }
- } while (c1);
-
- return 0; // strings are equal
-}
-
-int Q_strncmp (const char *s1, const char *s2, int n) {
- int c1, c2;
-
- do {
- c1 = *s1++;
- c2 = *s2++;
-
- if (!n--) {
- return 0; // strings are equal until end point
- }
-
- if (c1 != c2) {
- return c1 < c2 ? -1 : 1;
- }
- } while (c1);
-
- return 0; // strings are equal
-}
-
-int Q_stricmp (const char *s1, const char *s2) {
- return (s1 && s2) ? Q_stricmpn (s1, s2, 99999) : -1;
-}
-
-
-char *Q_strlwr( char *s1 ) {
- char *s;
-
- s = s1;
- while ( *s ) {
- *s = tolower(*s);
- s++;
- }
- return s1;
-}
-
-char *Q_strupr( char *s1 ) {
- char *s;
-
- s = s1;
- while ( *s ) {
- *s = toupper(*s);
- s++;
- }
- return s1;
-}
-
-
-// never goes past bounds or leaves without a terminating 0
-void Q_strcat( char *dest, int size, const char *src ) {
- int l1;
-
- l1 = strlen( dest );
- if ( l1 >= size ) {
- Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
- }
- Q_strncpyz( dest + l1, src, size - l1 );
-}
-
-/*
-* Find the first occurrence of find in s.
-*/
-const char *Q_stristr( const char *s, const char *find)
-{
- char c, sc;
- size_t len;
-
- if ((c = *find++) != 0)
- {
- if (c >= 'a' && c <= 'z')
- {
- c -= ('a' - 'A');
- }
- len = strlen(find);
- do
- {
- do
- {
- if ((sc = *s++) == 0)
- return NULL;
- if (sc >= 'a' && sc <= 'z')
- {
- sc -= ('a' - 'A');
- }
- } while (sc != c);
- } while (Q_stricmpn(s, find, len) != 0);
- s--;
- }
- return s;
-}
-
-
-int Q_PrintStrlen( const char *string ) {
- int len;
- const char *p;
-
- if( !string ) {
- return 0;
- }
-
- len = 0;
- p = string;
- while( *p ) {
- if( Q_IsColorString( p ) ) {
- p += 2;
- continue;
- }
- p++;
- len++;
- }
-
- return len;
-}
-
-
-char *Q_CleanStr( char *string ) {
- char* d;
- char* s;
- int c;
- qboolean hadColor = qfalse;
-
- s = string;
- d = string;
- while ((c = *s) != 0 ) {
- if ( Q_IsColorString( s ) ) {
- s++;
- hadColor = qtrue;
- }
- else if ( c >= 0x20 && c <= 0x7E ) {
- *d++ = c;
- }
- s++;
- }
- *d = '\0';
- if(hadColor)
- return Q_CleanStr( string );
- else
- return string;
-}
-
-int Q_CountChar(const char *string, char tocount)
-{
- int count;
-
- for(count = 0; *string; string++)
- {
- if(*string == tocount)
- count++;
- }
-
- return count;
-}
-
-void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {
- int len;
- va_list argptr;
- char bigbuffer[32000]; // big, but small enough to fit in PPC stack
-
- va_start (argptr,fmt);
- len = Q_vsnprintf (bigbuffer, sizeof(bigbuffer), fmt,argptr);
- va_end (argptr);
- if ( len >= sizeof( bigbuffer ) ) {
- Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
- }
- if (len >= size) {
- Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
-#ifdef _DEBUG
- __asm {
- int 3;
- }
-#endif
- }
- Q_strncpyz (dest, bigbuffer, size );
-}
-
-
-/*
-============
-va
-
-does a varargs printf into a temp buffer, so I don't need to have
-varargs versions of all text functions.
-============
-*/
-char * QDECL va( char *format, ... ) {
- va_list argptr;
- static char string[2][32000]; // in case va is called by nested functions
- static int index = 0;
- char *buf;
-
- buf = string[index & 1];
- index++;
-
- va_start (argptr, format);
- Q_vsnprintf (buf, sizeof(*string), format, argptr);
- va_end (argptr);
-
- return buf;
-}
-
-/*
-============
-Com_TruncateLongString
-
-Assumes buffer is atleast TRUNCATE_LENGTH big
-============
-*/
-void Com_TruncateLongString( char *buffer, const char *s )
-{
- int length = strlen( s );
-
- if( length <= TRUNCATE_LENGTH )
- Q_strncpyz( buffer, s, TRUNCATE_LENGTH );
- else
- {
- Q_strncpyz( buffer, s, ( TRUNCATE_LENGTH / 2 ) - 3 );
- Q_strcat( buffer, TRUNCATE_LENGTH, " ... " );
- Q_strcat( buffer, TRUNCATE_LENGTH, s + length - ( TRUNCATE_LENGTH / 2 ) + 3 );
- }
-}
-
-/*
-=====================================================================
-
- INFO STRINGS
-
-=====================================================================
-*/
-
-/*
-===============
-Info_ValueForKey
-
-Searches the string for the given
-key and returns the associated value, or an empty string.
-FIXME: overflow check?
-===============
-*/
-char *Info_ValueForKey( const char *s, const char *key ) {
- char pkey[BIG_INFO_KEY];
- static char value[2][BIG_INFO_VALUE]; // use two buffers so compares
- // work without stomping on each other
- static int valueindex = 0;
- char *o;
-
- if ( !s || !key ) {
- return "";
- }
-
- if ( strlen( s ) >= BIG_INFO_STRING ) {
- Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
- }
-
- valueindex ^= 1;
- if (*s == '\\')
- s++;
- while (1)
- {
- o = pkey;
- while (*s != '\\')
- {
- if (!*s)
- return "";
- *o++ = *s++;
- }
- *o = 0;
- s++;
-
- o = value[valueindex];
-
- while (*s != '\\' && *s)
- {
- *o++ = *s++;
- }
- *o = 0;
-
- if (!Q_stricmp (key, pkey) )
- return value[valueindex];
-
- if (!*s)
- break;
- s++;
- }
-
- return "";
-}
-
-
-/*
-===================
-Info_NextPair
-
-Used to itterate through all the key/value pairs in an info string
-===================
-*/
-void Info_NextPair( const char **head, char *key, char *value ) {
- char *o;
- const char *s;
-
- s = *head;
-
- if ( *s == '\\' ) {
- s++;
- }
- key[0] = 0;
- value[0] = 0;
-
- o = key;
- while ( *s != '\\' ) {
- if ( !*s ) {
- *o = 0;
- *head = s;
- return;
- }
- *o++ = *s++;
- }
- *o = 0;
- s++;
-
- o = value;
- while ( *s != '\\' && *s ) {
- *o++ = *s++;
- }
- *o = 0;
-
- *head = s;
-}
-
-
-/*
-===================
-Info_RemoveKey
-===================
-*/
-void Info_RemoveKey( char *s, const char *key ) {
- char *start;
- char pkey[MAX_INFO_KEY];
- char value[MAX_INFO_VALUE];
- char *o;
-
- if ( strlen( s ) >= MAX_INFO_STRING ) {
- Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
- }
-
- if (strchr (key, '\\')) {
- return;
- }
-
- while (1)
- {
- start = s;
- if (*s == '\\')
- s++;
- o = pkey;
- while (*s != '\\')
- {
- if (!*s)
- return;
- *o++ = *s++;
- }
- *o = 0;
- s++;
-
- o = value;
- while (*s != '\\' && *s)
- {
- if (!*s)
- return;
- *o++ = *s++;
- }
- *o = 0;
-
- if (!strcmp (key, pkey) )
- {
- memmove(start, s, strlen(s) + 1); // remove this part
-
- return;
- }
-
- if (!*s)
- return;
- }
-
-}
-
-/*
-===================
-Info_RemoveKey_Big
-===================
-*/
-void Info_RemoveKey_Big( char *s, const char *key ) {
- char *start;
- char pkey[BIG_INFO_KEY];
- char value[BIG_INFO_VALUE];
- char *o;
-
- if ( strlen( s ) >= BIG_INFO_STRING ) {
- Com_Error( ERR_DROP, "Info_RemoveKey_Big: oversize infostring" );
- }
-
- if (strchr (key, '\\')) {
- return;
- }
-
- while (1)
- {
- start = s;
- if (*s == '\\')
- s++;
- o = pkey;
- while (*s != '\\')
- {
- if (!*s)
- return;
- *o++ = *s++;
- }
- *o = 0;
- s++;
-
- o = value;
- while (*s != '\\' && *s)
- {
- if (!*s)
- return;
- *o++ = *s++;
- }
- *o = 0;
-
- if (!strcmp (key, pkey) )
- {
- strcpy (start, s); // remove this part
- return;
- }
-
- if (!*s)
- return;
- }
-
-}
-
-
-
-
-/*
-==================
-Info_Validate
-
-Some characters are illegal in info strings because they
-can mess up the server's parsing
-==================
-*/
-qboolean Info_Validate( const char *s ) {
- if ( strchr( s, '\"' ) ) {
- return qfalse;
- }
- if ( strchr( s, ';' ) ) {
- return qfalse;
- }
- return qtrue;
-}
-
-/*
-==================
-Info_SetValueForKey
-
-Changes or adds a key/value pair
-==================
-*/
-void Info_SetValueForKey( char *s, const char *key, const char *value ) {
- char newi[MAX_INFO_STRING];
- const char* blacklist = "\\;\"";
-
- if ( strlen( s ) >= MAX_INFO_STRING ) {
- Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
- }
-
- for(; *blacklist; ++blacklist)
- {
- if (strchr (key, *blacklist) || strchr (value, *blacklist))
- {
- Com_Printf (S_COLOR_YELLOW "Can't use keys or values with a '%c': %s = %s\n", *blacklist, key, value);
- return;
- }
- }
-
- Info_RemoveKey (s, key);
- if (!value || !strlen(value))
- return;
-
- Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
-
- if (strlen(newi) + strlen(s) >= MAX_INFO_STRING)
- {
- Com_Printf ("Info string length exceeded\n");
- return;
- }
-
- strcat (newi, s);
- strcpy (s, newi);
-}
-
-/*
-==================
-Info_SetValueForKey_Big
-
-Changes or adds a key/value pair
-==================
-*/
-void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
- char newi[BIG_INFO_STRING];
- const char* blacklist = "\\;\"";
-
- if ( strlen( s ) >= BIG_INFO_STRING ) {
- Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
- }
-
- for(; *blacklist; ++blacklist)
- {
- if (strchr (key, *blacklist) || strchr (value, *blacklist))
- {
- Com_Printf (S_COLOR_YELLOW "Can't use keys or values with a '%c': %s = %s\n", *blacklist, key, value);
- return;
- }
- }
-
- Info_RemoveKey_Big (s, key);
- if (!value || !strlen(value))
- return;
-
- Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
-
- if (strlen(newi) + strlen(s) >= BIG_INFO_STRING)
- {
- Com_Printf ("BIG Info string length exceeded\n");
- return;
- }
-
- strcat (s, newi);
-}
-
-
-
-
-//====================================================================
-
-/*
-==================
-Com_CharIsOneOfCharset
-==================
-*/
-static qboolean Com_CharIsOneOfCharset( char c, char *set )
-{
- int i;
-
- for( i = 0; i < strlen( set ); i++ )
- {
- if( set[ i ] == c )
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-==================
-Com_SkipCharset
-==================
-*/
-char *Com_SkipCharset( char *s, char *sep )
-{
- char *p = s;
-
- while( p )
- {
- if( Com_CharIsOneOfCharset( *p, sep ) )
- p++;
- else
- break;
- }
-
- return p;
-}
-
-/*
-==================
-Com_SkipTokens
-==================
-*/
-char *Com_SkipTokens( char *s, int numTokens, char *sep )
-{
- int sepCount = 0;
- char *p = s;
-
- while( sepCount < numTokens )
- {
- if( Com_CharIsOneOfCharset( *p++, sep ) )
- {
- sepCount++;
- while( Com_CharIsOneOfCharset( *p, sep ) )
- p++;
- }
- else if( *p == '\0' )
- break;
- }
-
- if( sepCount == numTokens )
- return p;
- else
- return s;
-}
diff --git a/game/code/qcommon/q_shared.h b/game/code/qcommon/q_shared.h
deleted file mode 100644
index df7797d..0000000
--- a/game/code/qcommon/q_shared.h
+++ /dev/null
@@ -1,1284 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#ifndef __Q_SHARED_H
-#define __Q_SHARED_H
-
-// q_shared.h -- included first by ALL program modules.
-// A user mod should never modify this file
-
-//#ifdef STANDALONE
- #define PRODUCT_NAME "ioq3+oa"
- #define BASEGAME "baseoa"
- #define CLIENT_WINDOW_TITLE "OpenArena"
- #define CLIENT_WINDOW_MIN_TITLE "OA"
-/*#else
- #define PRODUCT_NAME "ioq3"
- #define BASEGAME "baseq3"
- #define CLIENT_WINDOW_TITLE "ioquake3"
- #define CLIENT_WINDOW_MIN_TITLE "ioq3"
-#endif*/
-
-#ifdef _MSC_VER
- #define PRODUCT_VERSION "1.35"
-#endif
-
-#define Q3_VERSION PRODUCT_NAME " " PRODUCT_VERSION
-
-#define MAX_TEAMNAME 32
-
-#ifdef _MSC_VER
-
-#pragma warning(disable : 4018) // signed/unsigned mismatch
-#pragma warning(disable : 4032)
-#pragma warning(disable : 4051)
-#pragma warning(disable : 4057) // slightly different base types
-#pragma warning(disable : 4100) // unreferenced formal parameter
-#pragma warning(disable : 4115)
-#pragma warning(disable : 4125) // decimal digit terminates octal escape sequence
-#pragma warning(disable : 4127) // conditional expression is constant
-#pragma warning(disable : 4136)
-#pragma warning(disable : 4152) // nonstandard extension, function/data pointer conversion in expression
-//#pragma warning(disable : 4201)
-//#pragma warning(disable : 4214)
-#pragma warning(disable : 4244)
-#pragma warning(disable : 4142) // benign redefinition
-//#pragma warning(disable : 4305) // truncation from const double to float
-//#pragma warning(disable : 4310) // cast truncates constant value
-//#pragma warning(disable: 4505) // unreferenced local function has been removed
-#pragma warning(disable : 4514)
-#pragma warning(disable : 4702) // unreachable code
-#pragma warning(disable : 4711) // selected for automatic inline expansion
-#pragma warning(disable : 4220) // varargs matches remaining parameters
-//#pragma intrinsic( memset, memcpy )
-#endif
-
-//Ignore __attribute__ on non-gcc platforms
-#ifndef __GNUC__
-#ifndef __attribute__
-#define __attribute__(x)
-#endif
-#endif
-
-#if (defined _MSC_VER)
-#define Q_EXPORT __declspec(dllexport)
-#elif (defined __SUNPRO_C)
-#define Q_EXPORT __global
-#elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun))
-#define Q_EXPORT __attribute__((visibility("default")))
-#else
-#define Q_EXPORT
-#endif
-
-
-/**********************************************************************
- VM Considerations
-
- The VM can not use the standard system headers because we aren't really
- using the compiler they were meant for. We use bg_lib.h which contains
- prototypes for the functions we define for our own use in bg_lib.c.
-
- When writing mods, please add needed headers HERE, do not start including
- stuff like <stdio.h> in the various .c files that make up each of the VMs
- since you will be including system headers files can will have issues.
-
- Remember, if you use a C library function that is not defined in bg_lib.c,
- you will have to add your own version for support in the VM.
-
- **********************************************************************/
-
-#ifdef Q3_VM
-
-#include "../game/bg_lib.h"
-
-typedef int intptr_t;
-
-#else
-
-#include <assert.h>
-#include <math.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
-#include <ctype.h>
-#include <limits.h>
-
-// vsnprintf is ISO/IEC 9899:1999
-// abstracting this to make it portable
-#ifdef _WIN32
- #define Q_vsnprintf _vsnprintf
- #define Q_snprintf _snprintf
-#else
- #define Q_vsnprintf vsnprintf
- #define Q_snprintf snprintf
-#endif
-
-#ifdef _MSC_VER
- #include <io.h>
-
- typedef __int64 int64_t;
- typedef __int32 int32_t;
- typedef __int16 int16_t;
- typedef __int8 int8_t;
- typedef unsigned __int64 uint64_t;
- typedef unsigned __int32 uint32_t;
- typedef unsigned __int16 uint16_t;
- typedef unsigned __int8 uint8_t;
-#else
- #include <stdint.h>
-#endif
-
-#endif
-
-
-#include "q_platform.h"
-
-//=============================================================
-
-typedef unsigned char byte;
-
-typedef enum {qfalse, qtrue} qboolean;
-
-typedef union {
- float f;
- int i;
- unsigned int ui;
-} floatint_t;
-
-typedef int qhandle_t;
-typedef int sfxHandle_t;
-typedef int fileHandle_t;
-typedef int clipHandle_t;
-
-#define PAD(x,y) (((x)+(y)-1) & ~((y)-1))
-
-#ifdef __GNUC__
-#define ALIGN(x) __attribute__((aligned(x)))
-#else
-#define ALIGN(x)
-#endif
-
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
-#define MAX_QINT 0x7fffffff
-#define MIN_QINT (-MAX_QINT-1)
-
-
-// angle indexes
-#define PITCH 0 // up / down
-#define YAW 1 // left / right
-#define ROLL 2 // fall over
-
-// the game guarantees that no string from the network will ever
-// exceed MAX_STRING_CHARS
-#define MAX_STRING_CHARS 1024 // max length of a string passed to Cmd_TokenizeString
-#define MAX_STRING_TOKENS 1024 // max tokens resulting from Cmd_TokenizeString
-#define MAX_TOKEN_CHARS 1024 // max length of an individual token
-
-#define MAX_INFO_STRING 1024
-#define MAX_INFO_KEY 1024
-#define MAX_INFO_VALUE 1024
-
-#define BIG_INFO_STRING 8192 // used for system info key only
-#define BIG_INFO_KEY 8192
-#define BIG_INFO_VALUE 8192
-
-
-#define MAX_QPATH 64 // max length of a quake game pathname
-#ifdef PATH_MAX
-#define MAX_OSPATH PATH_MAX
-#else
-#define MAX_OSPATH 256 // max length of a filesystem pathname
-#endif
-
-#define MAX_NAME_LENGTH 32 // max length of a client name
-
-#define MAX_SAY_TEXT 150
-
-// paramters for command buffer stuffing
-typedef enum {
- EXEC_NOW, // don't return until completed, a VM should NEVER use this,
- // because some commands might cause the VM to be unloaded...
- EXEC_INSERT, // insert at current position, but don't run yet
- EXEC_APPEND // add to end of the command buffer (normal case)
-} cbufExec_t;
-
-
-//
-// these aren't needed by any of the VMs. put in another header?
-//
-#define MAX_MAP_AREA_BYTES 32 // bit vector of area visibility
-
-
-// print levels from renderer (FIXME: set up for game / cgame?)
-typedef enum {
- PRINT_ALL,
- PRINT_DEVELOPER, // only print when "developer 1"
- PRINT_WARNING,
- PRINT_ERROR
-} printParm_t;
-
-
-#ifdef ERR_FATAL
-#undef ERR_FATAL // this is be defined in malloc.h
-#endif
-
-// parameters to the main Error routine
-typedef enum {
- ERR_FATAL, // exit the entire game with a popup window
- ERR_DROP, // print to console and disconnect from game
- ERR_SERVERDISCONNECT, // don't kill server
- ERR_DISCONNECT, // client disconnected from the server
- ERR_NEED_CD // pop up the need-cd dialog
-} errorParm_t;
-
-
-// font rendering values used by ui and cgame
-
-#define PROP_GAP_WIDTH 3
-#define PROP_SPACE_WIDTH 8
-#define PROP_HEIGHT 27
-#define PROP_SMALL_SIZE_SCALE 0.75
-
-#define BLINK_DIVISOR 200
-#define PULSE_DIVISOR 75
-
-#define UI_LEFT 0x00000000 // default
-#define UI_CENTER 0x00000001
-#define UI_RIGHT 0x00000002
-#define UI_FORMATMASK 0x00000007
-#define UI_SMALLFONT 0x00000010
-#define UI_BIGFONT 0x00000020 // default
-#define UI_GIANTFONT 0x00000040
-#define UI_DROPSHADOW 0x00000800
-#define UI_BLINK 0x00001000
-#define UI_INVERSE 0x00002000
-#define UI_PULSE 0x00004000
-
-#if defined(_DEBUG) && !defined(BSPC)
- #define HUNK_DEBUG
-#endif
-
-typedef enum {
- h_high,
- h_low,
- h_dontcare
-} ha_pref;
-
-#ifdef HUNK_DEBUG
-#define Hunk_Alloc( size, preference ) Hunk_AllocDebug(size, preference, #size, __FILE__, __LINE__)
-void *Hunk_AllocDebug( int size, ha_pref preference, char *label, char *file, int line );
-#else
-void *Hunk_Alloc( int size, ha_pref preference );
-#endif
-
-#define Com_Memset memset
-#define Com_Memcpy memcpy
-
-#define CIN_system 1
-#define CIN_loop 2
-#define CIN_hold 4
-#define CIN_silent 8
-#define CIN_shader 16
-
-/*
-==============================================================
-
-MATHLIB
-
-==============================================================
-*/
-
-
-typedef float vec_t;
-typedef vec_t vec2_t[2];
-typedef vec_t vec3_t[3];
-typedef vec_t vec4_t[4];
-typedef vec_t vec5_t[5];
-
-typedef int fixed4_t;
-typedef int fixed8_t;
-typedef int fixed16_t;
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846f // matches value in gcc v2 math.h
-#endif
-
-#define NUMVERTEXNORMALS 162
-extern vec3_t bytedirs[NUMVERTEXNORMALS];
-
-// all drawing is done to a 640*480 virtual screen size
-// and will be automatically scaled to the real resolution
-#define SCREEN_WIDTH 640
-#define SCREEN_HEIGHT 480
-
-#define TINYCHAR_WIDTH (SMALLCHAR_WIDTH)
-#define TINYCHAR_HEIGHT (SMALLCHAR_HEIGHT/2)
-
-#define SMALLCHAR_WIDTH 8
-#define SMALLCHAR_HEIGHT 16
-
-#define BIGCHAR_WIDTH 16
-#define BIGCHAR_HEIGHT 16
-
-#define GIANTCHAR_WIDTH 32
-#define GIANTCHAR_HEIGHT 48
-
-extern vec4_t colorBlack;
-extern vec4_t colorRed;
-extern vec4_t colorGreen;
-extern vec4_t colorBlue;
-extern vec4_t colorYellow;
-extern vec4_t colorMagenta;
-extern vec4_t colorCyan;
-extern vec4_t colorWhite;
-extern vec4_t colorLtGrey;
-extern vec4_t colorMdGrey;
-extern vec4_t colorDkGrey;
-
-#define Q_COLOR_ESCAPE '^'
-#define Q_IsColorString(p) ((p) && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) >= '0' && *((p)+1) <= '8') // ^[0-8]
-#define COLOR_BLACK '0'
-#define COLOR_RED '1'
-#define COLOR_GREEN '2'
-#define COLOR_YELLOW '3'
-#define COLOR_BLUE '4'
-#define COLOR_CYAN '5'
-#define COLOR_MAGENTA '6'
-#define COLOR_WHITE '7'
-#define COLOR_MENU '8'
-#define ColorIndex(c) ((c) - '0')
-
-#define S_COLOR_BLACK "^0"
-#define S_COLOR_RED "^1"
-#define S_COLOR_GREEN "^2"
-#define S_COLOR_YELLOW "^3"
-#define S_COLOR_BLUE "^4"
-#define S_COLOR_CYAN "^5"
-#define S_COLOR_MAGENTA "^6"
-#define S_COLOR_WHITE "^7"
-#define S_COLOR_MENU "^8"
-
-extern vec4_t g_color_table[9];
-
-#define MAKERGB( v, r, g, b ) v[0]=r;v[1]=g;v[2]=b
-#define MAKERGBA( v, r, g, b, a ) v[0]=r;v[1]=g;v[2]=b;v[3]=a
-
-#define DEG2RAD( a ) ( ( (a) * M_PI ) / 180.0F )
-#define RAD2DEG( a ) ( ( (a) * 180.0f ) / M_PI )
-
-struct cplane_s;
-
-extern vec3_t vec3_origin;
-extern vec3_t axisDefault[3];
-
-#define nanmask (255<<23)
-
-#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
-
-#if idppc
-
-static ID_INLINE float Q_rsqrt( float number ) {
- float x = 0.5f * number;
- float y;
-#ifdef __GNUC__
- asm("frsqrte %0,%1" : "=f" (y) : "f" (number));
-#else
- y = __frsqrte( number );
-#endif
- return y * (1.5f - (x * y * y));
- }
-
-#ifdef __GNUC__
-static ID_INLINE float Q_fabs(float x) {
- float abs_x;
-
- asm("fabs %0,%1" : "=f" (abs_x) : "f" (x));
- return abs_x;
-}
-#else
-#define Q_fabs __fabsf
-#endif
-
-#else
-float Q_fabs( float f );
-float Q_rsqrt( float f ); // reciprocal square root
-#endif
-
-#define SQRTFAST( x ) ( (x) * Q_rsqrt( x ) )
-
-signed char ClampChar( int i );
-signed short ClampShort( int i );
-
-// this isn't a real cheap function to call!
-int DirToByte( vec3_t dir );
-void ByteToDir( int b, vec3_t dir );
-
-#if 1
-
-#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
-#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2])
-#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2])
-#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2])
-#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s))
-#define VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s))
-
-#else
-
-#define DotProduct(x,y) _DotProduct(x,y)
-#define VectorSubtract(a,b,c) _VectorSubtract(a,b,c)
-#define VectorAdd(a,b,c) _VectorAdd(a,b,c)
-#define VectorCopy(a,b) _VectorCopy(a,b)
-#define VectorScale(v, s, o) _VectorScale(v,s,o)
-#define VectorMA(v, s, b, o) _VectorMA(v,s,b,o)
-
-#endif
-
-#ifdef Q3_VM
-#ifdef VectorCopy
-#undef VectorCopy
-// this is a little hack to get more efficient copies in our interpreter
-typedef struct {
- float v[3];
-} vec3struct_t;
-#define VectorCopy(a,b) (*(vec3struct_t *)b=*(vec3struct_t *)a)
-#endif
-#endif
-
-#define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0)
-#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2])
-#define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z))
-#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
-
-#define SnapVector(v) {v[0]=((int)(v[0]));v[1]=((int)(v[1]));v[2]=((int)(v[2]));}
-// just in case you do't want to use the macros
-vec_t _DotProduct( const vec3_t v1, const vec3_t v2 );
-void _VectorSubtract( const vec3_t veca, const vec3_t vecb, vec3_t out );
-void _VectorAdd( const vec3_t veca, const vec3_t vecb, vec3_t out );
-void _VectorCopy( const vec3_t in, vec3_t out );
-void _VectorScale( const vec3_t in, float scale, vec3_t out );
-void _VectorMA( const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc );
-
-unsigned ColorBytes3 (float r, float g, float b);
-unsigned ColorBytes4 (float r, float g, float b, float a);
-
-float NormalizeColor( const vec3_t in, vec3_t out );
-
-float RadiusFromBounds( const vec3_t mins, const vec3_t maxs );
-void ClearBounds( vec3_t mins, vec3_t maxs );
-void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs );
-
-#if !defined( Q3_VM ) || ( defined( Q3_VM ) && defined( __Q3_VM_MATH ) )
-static ID_INLINE int VectorCompare( const vec3_t v1, const vec3_t v2 ) {
- if (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2]) {
- return 0;
- }
- return 1;
-}
-
-static ID_INLINE vec_t VectorLength( const vec3_t v ) {
- return (vec_t)sqrt (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
-}
-
-static ID_INLINE vec_t VectorLengthSquared( const vec3_t v ) {
- return (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
-}
-
-static ID_INLINE vec_t Distance( const vec3_t p1, const vec3_t p2 ) {
- vec3_t v;
-
- VectorSubtract (p2, p1, v);
- return VectorLength( v );
-}
-
-static ID_INLINE vec_t DistanceSquared( const vec3_t p1, const vec3_t p2 ) {
- vec3_t v;
-
- VectorSubtract (p2, p1, v);
- return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
-}
-
-// fast vector normalize routine that does not check to make sure
-// that length != 0, nor does it return length, uses rsqrt approximation
-static ID_INLINE void VectorNormalizeFast( vec3_t v )
-{
- float ilength;
-
- ilength = Q_rsqrt( DotProduct( v, v ) );
-
- v[0] *= ilength;
- v[1] *= ilength;
- v[2] *= ilength;
-}
-
-static ID_INLINE void VectorInverse( vec3_t v ){
- v[0] = -v[0];
- v[1] = -v[1];
- v[2] = -v[2];
-}
-
-static ID_INLINE void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross ) {
- cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
- cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
- cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
-}
-
-#else
-int VectorCompare( const vec3_t v1, const vec3_t v2 );
-
-vec_t VectorLength( const vec3_t v );
-
-vec_t VectorLengthSquared( const vec3_t v );
-
-vec_t Distance( const vec3_t p1, const vec3_t p2 );
-
-vec_t DistanceSquared( const vec3_t p1, const vec3_t p2 );
-
-void VectorNormalizeFast( vec3_t v );
-
-void VectorInverse( vec3_t v );
-
-void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross );
-
-#endif
-
-vec_t VectorNormalize (vec3_t v); // returns vector length
-vec_t VectorNormalize2( const vec3_t v, vec3_t out );
-void Vector4Scale( const vec4_t in, vec_t scale, vec4_t out );
-void VectorRotate( vec3_t in, vec3_t matrix[3], vec3_t out );
-int Q_log2(int val);
-
-float Q_acos(float c);
-
-int Q_rand( int *seed );
-float Q_random( int *seed );
-float Q_crandom( int *seed );
-
-#define random() ((rand () & 0x7fff) / ((float)0x7fff))
-#define crandom() (2.0 * (random() - 0.5))
-
-void vectoangles( const vec3_t value1, vec3_t angles);
-void AnglesToAxis( const vec3_t angles, vec3_t axis[3] );
-
-void AxisClear( vec3_t axis[3] );
-void AxisCopy( vec3_t in[3], vec3_t out[3] );
-
-void SetPlaneSignbits( struct cplane_s *out );
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *plane);
-
-qboolean BoundsIntersect(const vec3_t mins, const vec3_t maxs,
- const vec3_t mins2, const vec3_t maxs2);
-qboolean BoundsIntersectSphere(const vec3_t mins, const vec3_t maxs,
- const vec3_t origin, vec_t radius);
-qboolean BoundsIntersectPoint(const vec3_t mins, const vec3_t maxs,
- const vec3_t origin);
-
-float AngleMod(float a);
-float LerpAngle (float from, float to, float frac);
-float AngleSubtract( float a1, float a2 );
-void AnglesSubtract( vec3_t v1, vec3_t v2, vec3_t v3 );
-
-float AngleNormalize360 ( float angle );
-float AngleNormalize180 ( float angle );
-float AngleDelta ( float angle1, float angle2 );
-
-qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c );
-void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal );
-void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
-void RotateAroundDirection( vec3_t axis[3], float yaw );
-void MakeNormalVectors( const vec3_t forward, vec3_t right, vec3_t up );
-// perpendicular vector could be replaced by this
-
-//int PlaneTypeForNormal (vec3_t normal);
-
-void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]);
-void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
-void PerpendicularVector( vec3_t dst, const vec3_t src );
-int Q_isnan( float x );
-
-
-//=============================================
-
-float Com_Clamp( float min, float max, float value );
-
-char *COM_SkipPath( char *pathname );
-const char *COM_GetExtension( const char *name );
-void COM_StripExtension(const char *in, char *out, int destsize);
-void COM_DefaultExtension( char *path, int maxSize, const char *extension );
-
-void COM_BeginParseSession( const char *name );
-int COM_GetCurrentParseLine( void );
-char *COM_Parse( char **data_p );
-char *COM_ParseExt( char **data_p, qboolean allowLineBreak );
-int COM_Compress( char *data_p );
-void COM_ParseError( char *format, ... ) __attribute__ ((format (printf, 1, 2)));
-void COM_ParseWarning( char *format, ... ) __attribute__ ((format (printf, 1, 2)));
-//int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] );
-
-#define MAX_TOKENLENGTH 1024
-
-#ifndef TT_STRING
-//token types
-#define TT_STRING 1 // string
-#define TT_LITERAL 2 // literal
-#define TT_NUMBER 3 // number
-#define TT_NAME 4 // name
-#define TT_PUNCTUATION 5 // punctuation
-#endif
-
-typedef struct pc_token_s
-{
- int type;
- int subtype;
- int intvalue;
- float floatvalue;
- char string[MAX_TOKENLENGTH];
-} pc_token_t;
-
-// data is an in/out parm, returns a parsed out token
-
-void COM_MatchToken( char**buf_p, char *match );
-
-void SkipBracedSection (char **program);
-void SkipRestOfLine ( char **data );
-
-void Parse1DMatrix (char **buf_p, int x, float *m);
-void Parse2DMatrix (char **buf_p, int y, int x, float *m);
-void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m);
-
-void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
-
-char *Com_SkipTokens( char *s, int numTokens, char *sep );
-char *Com_SkipCharset( char *s, char *sep );
-
-void Com_RandomBytes( byte *string, int len );
-
-// mode parm for FS_FOpenFile
-typedef enum {
- FS_READ,
- FS_WRITE,
- FS_APPEND,
- FS_APPEND_SYNC
-} fsMode_t;
-
-typedef enum {
- FS_SEEK_CUR,
- FS_SEEK_END,
- FS_SEEK_SET
-} fsOrigin_t;
-
-//=============================================
-
-int Q_isprint( int c );
-int Q_islower( int c );
-int Q_isupper( int c );
-int Q_isalpha( int c );
-
-// portable case insensitive compare
-int Q_stricmp (const char *s1, const char *s2);
-int Q_strncmp (const char *s1, const char *s2, int n);
-int Q_stricmpn (const char *s1, const char *s2, int n);
-char *Q_strlwr( char *s1 );
-char *Q_strupr( char *s1 );
-char *Q_strrchr( const char* string, int c );
-const char *Q_stristr( const char *s, const char *find);
-
-// buffer size safe library replacements
-void Q_strncpyz( char *dest, const char *src, int destsize );
-void Q_strcat( char *dest, int size, const char *src );
-
-// strlen that discounts Quake color sequences
-int Q_PrintStrlen( const char *string );
-// removes color sequences from string
-char *Q_CleanStr( char *string );
-// Count the number of char tocount encountered in string
-int Q_CountChar(const char *string, char tocount);
-
-//=============================================
-
-// 64-bit integers for global rankings interface
-// implemented as a struct for qvm compatibility
-typedef struct
-{
- byte b0;
- byte b1;
- byte b2;
- byte b3;
- byte b4;
- byte b5;
- byte b6;
- byte b7;
-} qint64;
-
-//=============================================
-/*
-short BigShort(short l);
-short LittleShort(short l);
-int BigLong (int l);
-int LittleLong (int l);
-qint64 BigLong64 (qint64 l);
-qint64 LittleLong64 (qint64 l);
-float BigFloat (const float *l);
-float LittleFloat (const float *l);
-
-void Swap_Init (void);
-*/
-char * QDECL va(char *format, ...) __attribute__ ((format (printf, 1, 2)));
-
-#define TRUNCATE_LENGTH 64
-void Com_TruncateLongString( char *buffer, const char *s );
-
-//=============================================
-
-//
-// key / value info strings
-//
-char *Info_ValueForKey( const char *s, const char *key );
-void Info_RemoveKey( char *s, const char *key );
-void Info_RemoveKey_big( char *s, const char *key );
-void Info_SetValueForKey( char *s, const char *key, const char *value );
-void Info_SetValueForKey_Big( char *s, const char *key, const char *value );
-qboolean Info_Validate( const char *s );
-void Info_NextPair( const char **s, char *key, char *value );
-
-// this is only here so the functions in q_shared.c and bg_*.c can link
-void QDECL Com_Error( int level, const char *error, ... ) __attribute__ ((format (printf, 2, 3)));
-void QDECL Com_Printf( const char *msg, ... ) __attribute__ ((format (printf, 1, 2)));
-
-
-/*
-==========================================================
-
-CVARS (console variables)
-
-Many variables can be used for cheating purposes, so when
-cheats is zero, force all unspecified variables to their
-default values.
-==========================================================
-*/
-
-#define CVAR_ARCHIVE 1 // set to cause it to be saved to vars.rc
- // used for system variables, not for player
- // specific configurations
-#define CVAR_USERINFO 2 // sent to server on connect or change
-#define CVAR_SERVERINFO 4 // sent in response to front end requests
-#define CVAR_SYSTEMINFO 8 // these cvars will be duplicated on all clients
-#define CVAR_INIT 16 // don't allow change from console at all,
- // but can be set from the command line
-#define CVAR_LATCH 32 // will only change when C code next does
- // a Cvar_Get(), so it can't be changed
- // without proper initialization. modified
- // will be set, even though the value hasn't
- // changed yet
-#define CVAR_ROM 64 // display only, cannot be set by user at all
-#define CVAR_USER_CREATED 128 // created by a set command
-#define CVAR_TEMP 256 // can be set even when cheats are disabled, but is not archived
-#define CVAR_CHEAT 512 // can not be changed if cheats are disabled
-#define CVAR_NORESTART 1024 // do not clear when a cvar_restart is issued
-
-#define CVAR_SERVER_CREATED 2048 // cvar was created by a server the client connected to.
-#define CVAR_NONEXISTENT 0xFFFFFFFF // Cvar doesn't exist.
-
-// nothing outside the Cvar_*() functions should modify these fields!
-typedef struct cvar_s {
- char *name;
- char *string;
- char *resetString; // cvar_restart will reset to this value
- char *latchedString; // for CVAR_LATCH vars
- int flags;
- qboolean modified; // set each time the cvar is changed
- int modificationCount; // incremented each time the cvar is changed
- float value; // atof( string )
- int integer; // atoi( string )
- struct cvar_s *next;
- struct cvar_s *hashNext;
-} cvar_t;
-
-#define MAX_CVAR_VALUE_STRING 256
-
-typedef int cvarHandle_t;
-
-// the modules that run in the virtual machine can't access the cvar_t directly,
-// so they must ask for structured updates
-typedef struct {
- cvarHandle_t handle;
- int modificationCount;
- float value;
- int integer;
- char string[MAX_CVAR_VALUE_STRING];
-} vmCvar_t;
-
-/*
-==============================================================
-
-COLLISION DETECTION
-
-==============================================================
-*/
-
-#include "surfaceflags.h" // shared with the q3map utility
-
-// plane types are used to speed some tests
-// 0-2 are axial planes
-#define PLANE_X 0
-#define PLANE_Y 1
-#define PLANE_Z 2
-#define PLANE_NON_AXIAL 3
-
-
-/*
-=================
-PlaneTypeForNormal
-=================
-*/
-
-#define PlaneTypeForNormal(x) (x[0] == 1.0 ? PLANE_X : (x[1] == 1.0 ? PLANE_Y : (x[2] == 1.0 ? PLANE_Z : PLANE_NON_AXIAL) ) )
-
-// plane_t structure
-// !!! if this is changed, it must be changed in asm code too !!!
-typedef struct cplane_s {
- vec3_t normal;
- float dist;
- byte type; // for fast side tests: 0,1,2 = axial, 3 = nonaxial
- byte signbits; // signx + (signy<<1) + (signz<<2), used as lookup during collision
- byte pad[2];
-} cplane_t;
-
-
-// a trace is returned when a box is swept through the world
-typedef struct {
- qboolean allsolid; // if true, plane is not valid
- qboolean startsolid; // if true, the initial point was in a solid area
- float fraction; // time completed, 1.0 = didn't hit anything
- vec3_t endpos; // final position
- cplane_t plane; // surface normal at impact, transformed to world space
- int surfaceFlags; // surface hit
- int contents; // contents on other side of surface hit
- int entityNum; // entity the contacted sirface is a part of
-} trace_t;
-
-// trace->entityNum can also be 0 to (MAX_GENTITIES-1)
-// or ENTITYNUM_NONE, ENTITYNUM_WORLD
-
-
-// markfragments are returned by CM_MarkFragments()
-typedef struct {
- int firstPoint;
- int numPoints;
-} markFragment_t;
-
-
-
-typedef struct {
- vec3_t origin;
- vec3_t axis[3];
-} orientation_t;
-
-//=====================================================================
-
-
-// in order from highest priority to lowest
-// if none of the catchers are active, bound key strings will be executed
-#define KEYCATCH_CONSOLE 0x0001
-#define KEYCATCH_UI 0x0002
-#define KEYCATCH_MESSAGE 0x0004
-#define KEYCATCH_CGAME 0x0008
-
-
-// sound channels
-// channel 0 never willingly overrides
-// other channels will allways override a playing sound on that channel
-typedef enum {
- CHAN_AUTO,
- CHAN_LOCAL, // menu sounds, etc
- CHAN_WEAPON,
- CHAN_VOICE,
- CHAN_ITEM,
- CHAN_BODY,
- CHAN_LOCAL_SOUND, // chat messages, etc
- CHAN_ANNOUNCER // announcer voices, etc
-} soundChannel_t;
-
-
-/*
-========================================================================
-
- ELEMENTS COMMUNICATED ACROSS THE NET
-
-========================================================================
-*/
-
-#define ANGLE2SHORT(x) ((int)((x)*65536/360) & 65535)
-#define SHORT2ANGLE(x) ((x)*(360.0/65536))
-
-#define SNAPFLAG_RATE_DELAYED 1
-#define SNAPFLAG_NOT_ACTIVE 2 // snapshot used during connection and for zombies
-#define SNAPFLAG_SERVERCOUNT 4 // toggled every map_restart so transitions can be detected
-
-//
-// per-level limits
-//
-#define MAX_CLIENTS 64 // absolute limit
-#define MAX_LOCATIONS 64
-
-#define GENTITYNUM_BITS 10 // don't need to send any more
-#define MAX_GENTITIES (1<<GENTITYNUM_BITS)
-
-// entitynums are communicated with GENTITY_BITS, so any reserved
-// values that are going to be communcated over the net need to
-// also be in this range
-#define ENTITYNUM_NONE (MAX_GENTITIES-1)
-#define ENTITYNUM_WORLD (MAX_GENTITIES-2)
-#define ENTITYNUM_MAX_NORMAL (MAX_GENTITIES-2)
-
-
-#define MAX_MODELS 256 // these are sent over the net as 8 bits
-#define MAX_SOUNDS 256 // so they cannot be blindly increased
-
-
-#define MAX_CONFIGSTRINGS 1024
-
-// these are the only configstrings that the system reserves, all the
-// other ones are strictly for servergame to clientgame communication
-#define CS_SERVERINFO 0 // an info string with all the serverinfo cvars
-#define CS_SYSTEMINFO 1 // an info string for server system to client system configuration (timescale, etc)
-
-#define RESERVED_CONFIGSTRINGS 2 // game can't modify below this, only the system can
-
-#define MAX_GAMESTATE_CHARS 16000
-typedef struct {
- int stringOffsets[MAX_CONFIGSTRINGS];
- char stringData[MAX_GAMESTATE_CHARS];
- int dataCount;
-} gameState_t;
-
-//=========================================================
-
-// bit field limits
-#define MAX_STATS 16
-#define MAX_PERSISTANT 16
-#define MAX_POWERUPS 16
-#define MAX_WEAPONS 16
-
-#define MAX_PS_EVENTS 2
-
-#define PS_PMOVEFRAMECOUNTBITS 6
-
-// playerState_t is the information needed by both the client and server
-// to predict player motion and actions
-// nothing outside of pmove should modify these, or some degree of prediction error
-// will occur
-
-// you can't add anything to this without modifying the code in msg.c
-
-// playerState_t is a full superset of entityState_t as it is used by players,
-// so if a playerState_t is transmitted, the entityState_t can be fully derived
-// from it.
-typedef struct playerState_s {
- int commandTime; // cmd->serverTime of last executed command
- int pm_type;
- int bobCycle; // for view bobbing and footstep generation
- int pm_flags; // ducked, jump_held, etc
- int pm_time;
-
- vec3_t origin;
- vec3_t velocity;
- int weaponTime;
- int gravity;
- int speed;
- int delta_angles[3]; // add to command angles to get view direction
- // changed by spawns, rotating objects, and teleporters
-
- int groundEntityNum;// ENTITYNUM_NONE = in air
-
- int legsTimer; // don't change low priority animations until this runs out
- int legsAnim; // mask off ANIM_TOGGLEBIT
-
- int torsoTimer; // don't change low priority animations until this runs out
- int torsoAnim; // mask off ANIM_TOGGLEBIT
-
- int movementDir; // a number 0 to 7 that represents the reletive angle
- // of movement to the view angle (axial and diagonals)
- // when at rest, the value will remain unchanged
- // used to twist the legs during strafing
-
- vec3_t grapplePoint; // location of grapple to pull towards if PMF_GRAPPLE_PULL
-
- int eFlags; // copied to entityState_t->eFlags
-
- int eventSequence; // pmove generated events
- int events[MAX_PS_EVENTS];
- int eventParms[MAX_PS_EVENTS];
-
- int externalEvent; // events set on player from another source
- int externalEventParm;
- int externalEventTime;
-
- int clientNum; // ranges from 0 to MAX_CLIENTS-1
- int weapon; // copied to entityState_t->weapon
- int weaponstate;
-
- vec3_t viewangles; // for fixed views
- int viewheight;
-
- // damage feedback
- int damageEvent; // when it changes, latch the other parms
- int damageYaw;
- int damagePitch;
- int damageCount;
-
- int stats[MAX_STATS];
- int persistant[MAX_PERSISTANT]; // stats that aren't cleared on death
- int powerups[MAX_POWERUPS]; // level.time that the powerup runs out
- int ammo[MAX_WEAPONS];
-
- int generic1;
- int loopSound;
- int jumppad_ent; // jumppad entity hit this frame
-
- // not communicated over the net at all
- int ping; // server to game info for scoreboard
- int pmove_framecount; // FIXME: don't transmit over the network
- int jumppad_frame;
- int entityEventSequence;
-} playerState_t;
-
-
-//====================================================================
-
-
-//
-// usercmd_t->button bits, many of which are generated by the client system,
-// so they aren't game/cgame only definitions
-//
-#define BUTTON_ATTACK 1
-#define BUTTON_TALK 2 // displays talk balloon and disables actions
-#define BUTTON_USE_HOLDABLE 4
-#define BUTTON_GESTURE 8
-#define BUTTON_WALKING 16 // walking can't just be infered from MOVE_RUN
- // because a key pressed late in the frame will
- // only generate a small move value for that frame
- // walking will use different animations and
- // won't generate footsteps
-#define BUTTON_AFFIRMATIVE 32
-#define BUTTON_NEGATIVE 64
-
-#define BUTTON_GETFLAG 128
-#define BUTTON_GUARDBASE 256
-#define BUTTON_PATROL 512
-#define BUTTON_FOLLOWME 1024
-
-#define BUTTON_ANY 2048 // any key whatsoever
-
-#define MOVE_RUN 120 // if forwardmove or rightmove are >= MOVE_RUN,
- // then BUTTON_WALKING should be set
-
-// usercmd_t is sent to the server each client frame
-typedef struct usercmd_s {
- int serverTime;
- int angles[3];
- int buttons;
- byte weapon; // weapon
- signed char forwardmove, rightmove, upmove;
-} usercmd_t;
-
-//===================================================================
-
-// if entityState->solid == SOLID_BMODEL, modelindex is an inline model number
-#define SOLID_BMODEL 0xffffff
-
-typedef enum {
- TR_STATIONARY,
- TR_INTERPOLATE, // non-parametric, but interpolate between snapshots
- TR_LINEAR,
- TR_LINEAR_STOP,
- TR_SINE, // value = base + sin( time / duration ) * delta
- TR_GRAVITY
-} trType_t;
-
-typedef struct {
- trType_t trType;
- int trTime;
- int trDuration; // if non 0, trTime + trDuration = stop time
- vec3_t trBase;
- vec3_t trDelta; // velocity, etc
-} trajectory_t;
-
-// entityState_t is the information conveyed from the server
-// in an update message about entities that the client will
-// need to render in some way
-// Different eTypes may use the information in different ways
-// The messages are delta compressed, so it doesn't really matter if
-// the structure size is fairly large
-
-typedef struct entityState_s {
- int number; // entity index
- int eType; // entityType_t
- int eFlags;
-
- trajectory_t pos; // for calculating position
- trajectory_t apos; // for calculating angles
-
- int time;
- int time2;
-
- vec3_t origin;
- vec3_t origin2;
-
- vec3_t angles;
- vec3_t angles2;
-
- int otherEntityNum; // shotgun sources, etc
- int otherEntityNum2;
-
- int groundEntityNum; // -1 = in air
-
- int constantLight; // r + (g<<8) + (b<<16) + (intensity<<24)
- int loopSound; // constantly loop this sound
-
- int modelindex;
- int modelindex2;
- int clientNum; // 0 to (MAX_CLIENTS - 1), for players and corpses
- int frame;
-
- int solid; // for client side prediction, trap_linkentity sets this properly
-
- int event; // impulse events -- muzzle flashes, footsteps, etc
- int eventParm;
-
- // for players
- int powerups; // bit flags
- int weapon; // determines weapon and flash model, etc
- int legsAnim; // mask off ANIM_TOGGLEBIT
- int torsoAnim; // mask off ANIM_TOGGLEBIT
-
- int generic1;
-} entityState_t;
-
-typedef enum {
- CA_UNINITIALIZED,
- CA_DISCONNECTED, // not talking to a server
- CA_AUTHORIZING, // not used any more, was checking cd key
- CA_CONNECTING, // sending request packets to the server
- CA_CHALLENGING, // sending challenge packets to the server
- CA_CONNECTED, // netchan_t established, getting gamestate
- CA_LOADING, // only during cgame initialization, never during main loop
- CA_PRIMED, // got gamestate, waiting for first frame
- CA_ACTIVE, // game views should be displayed
- CA_CINEMATIC // playing a cinematic or a static pic, not connected to a server
-} connstate_t;
-
-// font support
-
-#define GLYPH_START 0
-#define GLYPH_END 255
-#define GLYPH_CHARSTART 32
-#define GLYPH_CHAREND 127
-#define GLYPHS_PER_FONT GLYPH_END - GLYPH_START + 1
-typedef struct {
- int height; // number of scan lines
- int top; // top of glyph in buffer
- int bottom; // bottom of glyph in buffer
- int pitch; // width for copying
- int xSkip; // x adjustment
- int imageWidth; // width of actual image
- int imageHeight; // height of actual image
- float s; // x offset in image where glyph starts
- float t; // y offset in image where glyph starts
- float s2;
- float t2;
- qhandle_t glyph; // handle to the shader with the glyph
- char shaderName[32];
-} glyphInfo_t;
-
-typedef struct {
- glyphInfo_t glyphs [GLYPHS_PER_FONT];
- float glyphScale;
- char name[MAX_QPATH];
-} fontInfo_t;
-
-#define Square(x) ((x)*(x))
-
-// real time
-//=============================================
-
-
-typedef struct qtime_s {
- int tm_sec; /* seconds after the minute - [0,59] */
- int tm_min; /* minutes after the hour - [0,59] */
- int tm_hour; /* hours since midnight - [0,23] */
- int tm_mday; /* day of the month - [1,31] */
- int tm_mon; /* months since January - [0,11] */
- int tm_year; /* years since 1900 */
- int tm_wday; /* days since Sunday - [0,6] */
- int tm_yday; /* days since January 1 - [0,365] */
- int tm_isdst; /* daylight savings time flag */
-} qtime_t;
-
-
-// server browser sources
-// TTimo: AS_MPLAYER is no longer used
-#define AS_LOCAL 0
-#define AS_MPLAYER 1
-#define AS_GLOBAL 2
-#define AS_FAVORITES 3
-
-
-// cinematic states
-typedef enum {
- FMV_IDLE,
- FMV_PLAY, // play
- FMV_EOF, // all other conditions, i.e. stop/EOF/abort
- FMV_ID_BLT,
- FMV_ID_IDLE,
- FMV_LOOPED,
- FMV_ID_WAIT
-} e_status;
-
-typedef enum _flag_status {
- FLAG_ATBASE = 0,
- FLAG_TAKEN, // CTF
- FLAG_TAKEN_RED, // One Flag CTF
- FLAG_TAKEN_BLUE, // One Flag CTF
- FLAG_DROPPED
-} flagStatus_t;
-
-
-
-#define MAX_GLOBAL_SERVERS 4096
-#define MAX_OTHER_SERVERS 128
-#define MAX_PINGREQUESTS 32
-#define MAX_SERVERSTATUSREQUESTS 16
-
-#define SAY_ALL 0
-#define SAY_TEAM 1
-#define SAY_TELL 2
-
-#define CDKEY_LEN 16
-#define CDCHKSUM_LEN 2
-
-
-#endif // __Q_SHARED_H
diff --git a/game/code/qcommon/qfiles.h b/game/code/qcommon/qfiles.h
deleted file mode 100644
index 7f1ef96..0000000
--- a/game/code/qcommon/qfiles.h
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#ifndef __QFILES_H__
-#define __QFILES_H__
-
-//
-// qfiles.h: quake file formats
-// This file must be identical in the quake and utils directories
-//
-
-//Ignore __attribute__ on non-gcc platforms
-#ifndef __GNUC__
-#ifndef __attribute__
-#define __attribute__(x)
-#endif
-#endif
-
-// surface geometry should not exceed these limits
-#define SHADER_MAX_VERTEXES 1000
-#define SHADER_MAX_INDEXES (6*SHADER_MAX_VERTEXES)
-
-
-// the maximum size of game relative pathnames
-#define MAX_QPATH 64
-
-/*
-========================================================================
-
-QVM files
-
-========================================================================
-*/
-
-#define VM_MAGIC 0x12721444
-#define VM_MAGIC_VER2 0x12721445
-typedef struct {
- int vmMagic;
-
- int instructionCount;
-
- int codeOffset;
- int codeLength;
-
- int dataOffset;
- int dataLength;
- int litLength; // ( dataLength - litLength ) should be byteswapped on load
- int bssLength; // zero filled memory appended to datalength
-
- //!!! below here is VM_MAGIC_VER2 !!!
- int jtrgLength; // number of jump table targets
-} vmHeader_t;
-
-/*
-========================================================================
-
-.MD3 triangle model file format
-
-========================================================================
-*/
-
-#define MD3_IDENT (('3'<<24)+('P'<<16)+('D'<<8)+'I')
-#define MD3_VERSION 15
-
-// limits
-#define MD3_MAX_LODS 3
-#define MD3_MAX_TRIANGLES 8192 // per surface
-#define MD3_MAX_VERTS 4096 // per surface
-#define MD3_MAX_SHADERS 256 // per surface
-#define MD3_MAX_FRAMES 1024 // per model
-#define MD3_MAX_SURFACES 32 // per model
-#define MD3_MAX_TAGS 16 // per frame
-
-// vertex scales
-#define MD3_XYZ_SCALE (1.0/64)
-
-typedef struct md3Frame_s {
- vec3_t bounds[2];
- vec3_t localOrigin;
- float radius;
- char name[16];
-} md3Frame_t;
-
-typedef struct md3Tag_s {
- char name[MAX_QPATH]; // tag name
- vec3_t origin;
- vec3_t axis[3];
-} md3Tag_t;
-
-/*
-** md3Surface_t
-**
-** CHUNK SIZE
-** header sizeof( md3Surface_t )
-** shaders sizeof( md3Shader_t ) * numShaders
-** triangles[0] sizeof( md3Triangle_t ) * numTriangles
-** st sizeof( md3St_t ) * numVerts
-** XyzNormals sizeof( md3XyzNormal_t ) * numVerts * numFrames
-*/
-typedef struct {
- int ident; //
-
- char name[MAX_QPATH]; // polyset name
-
- int flags;
- int numFrames; // all surfaces in a model should have the same
-
- int numShaders; // all surfaces in a model should have the same
- int numVerts;
-
- int numTriangles;
- int ofsTriangles;
-
- int ofsShaders; // offset from start of md3Surface_t
- int ofsSt; // texture coords are common for all frames
- int ofsXyzNormals; // numVerts * numFrames
-
- int ofsEnd; // next surface follows
-} md3Surface_t;
-
-typedef struct {
- char name[MAX_QPATH];
- int shaderIndex; // for in-game use
-} md3Shader_t;
-
-typedef struct {
- int indexes[3];
-} md3Triangle_t;
-
-typedef struct {
- float st[2];
-} md3St_t;
-
-typedef struct {
- short xyz[3];
- short normal;
-} md3XyzNormal_t;
-
-typedef struct {
- int ident;
- int version;
-
- char name[MAX_QPATH]; // model name
-
- int flags;
-
- int numFrames;
- int numTags;
- int numSurfaces;
-
- int numSkins;
-
- int ofsFrames; // offset for first frame
- int ofsTags; // numFrames * numTags
- int ofsSurfaces; // first surface, others follow
-
- int ofsEnd; // end of file
-} md3Header_t;
-
-/*
-==============================================================================
-
-MD4 file format
-
-==============================================================================
-*/
-
-#define MD4_IDENT (('4'<<24)+('P'<<16)+('D'<<8)+'I')
-#define MD4_VERSION 1
-#define MD4_MAX_BONES 128
-
-typedef struct {
- int boneIndex; // these are indexes into the boneReferences,
- float boneWeight; // not the global per-frame bone list
- vec3_t offset;
-} md4Weight_t;
-
-typedef struct {
- vec3_t normal;
- vec2_t texCoords;
- int numWeights;
- md4Weight_t weights[1]; // variable sized
-} md4Vertex_t;
-
-typedef struct {
- int indexes[3];
-} md4Triangle_t;
-
-typedef struct {
- int ident;
-
- char name[MAX_QPATH]; // polyset name
- char shader[MAX_QPATH];
- int shaderIndex; // for in-game use
-
- int ofsHeader; // this will be a negative number
-
- int numVerts;
- int ofsVerts;
-
- int numTriangles;
- int ofsTriangles;
-
- // Bone references are a set of ints representing all the bones
- // present in any vertex weights for this surface. This is
- // needed because a model may have surfaces that need to be
- // drawn at different sort times, and we don't want to have
- // to re-interpolate all the bones for each surface.
- int numBoneReferences;
- int ofsBoneReferences;
-
- int ofsEnd; // next surface follows
-} md4Surface_t;
-
-typedef struct {
- float matrix[3][4];
-} md4Bone_t;
-
-typedef struct {
- vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame
- vec3_t localOrigin; // midpoint of bounds, used for sphere cull
- float radius; // dist from localOrigin to corner
- md4Bone_t bones[1]; // [numBones]
-} md4Frame_t;
-
-typedef struct {
- int numSurfaces;
- int ofsSurfaces; // first surface, others follow
- int ofsEnd; // next lod follows
-} md4LOD_t;
-
-typedef struct {
- int ident;
- int version;
-
- char name[MAX_QPATH]; // model name
-
- // frames and bones are shared by all levels of detail
- int numFrames;
- int numBones;
- int ofsBoneNames; // char name[ MAX_QPATH ]
- int ofsFrames; // md4Frame_t[numFrames]
-
- // each level of detail has completely separate sets of surfaces
- int numLODs;
- int ofsLODs;
-
- int ofsEnd; // end of file
-} md4Header_t;
-
-/*
- * Here are the definitions for Ravensoft's model format of md4. Raven stores their
- * playermodels in .mdr files, in some games, which are pretty much like the md4
- * format implemented by ID soft. It seems like ID's original md4 stuff is not used at all.
- * MDR is being used in EliteForce, JediKnight2 and Soldiers of Fortune2 (I think).
- * So this comes in handy for anyone who wants to make it possible to load player
- * models from these games.
- * This format has bone tags, which is similar to the thing you have in md3 I suppose.
- * Raven has released their version of md3view under GPL enabling me to add support
- * to this codebase. Thanks to Steven Howes aka Skinner for helping with example
- * source code.
- *
- * - Thilo Schulz (arny at ats.s.bawue.de)
- */
-
-// If you want to enable support for Raven's .mdr / md4 format, uncomment the next
-// line.
-//#define RAVENMD4
-
-#ifdef RAVENMD4
-
-#define MDR_IDENT (('5'<<24)+('M'<<16)+('D'<<8)+'R')
-#define MDR_VERSION 2
-#define MDR_MAX_BONES 128
-
-typedef struct {
- int boneIndex; // these are indexes into the boneReferences,
- float boneWeight; // not the global per-frame bone list
- vec3_t offset;
-} mdrWeight_t;
-
-typedef struct {
- vec3_t normal;
- vec2_t texCoords;
- int numWeights;
- mdrWeight_t weights[1]; // variable sized
-} mdrVertex_t;
-
-typedef struct {
- int indexes[3];
-} mdrTriangle_t;
-
-typedef struct {
- int ident;
-
- char name[MAX_QPATH]; // polyset name
- char shader[MAX_QPATH];
- int shaderIndex; // for in-game use
-
- int ofsHeader; // this will be a negative number
-
- int numVerts;
- int ofsVerts;
-
- int numTriangles;
- int ofsTriangles;
-
- // Bone references are a set of ints representing all the bones
- // present in any vertex weights for this surface. This is
- // needed because a model may have surfaces that need to be
- // drawn at different sort times, and we don't want to have
- // to re-interpolate all the bones for each surface.
- int numBoneReferences;
- int ofsBoneReferences;
-
- int ofsEnd; // next surface follows
-} mdrSurface_t;
-
-typedef struct {
- float matrix[3][4];
-} mdrBone_t;
-
-typedef struct {
- vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame
- vec3_t localOrigin; // midpoint of bounds, used for sphere cull
- float radius; // dist from localOrigin to corner
- char name[16];
- mdrBone_t bones[1]; // [numBones]
-} mdrFrame_t;
-
-typedef struct {
- unsigned char Comp[24]; // MC_COMP_BYTES is in MatComp.h, but don't want to couple
-} mdrCompBone_t;
-
-typedef struct {
- vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame
- vec3_t localOrigin; // midpoint of bounds, used for sphere cull
- float radius; // dist from localOrigin to corner
- mdrCompBone_t bones[1]; // [numBones]
-} mdrCompFrame_t;
-
-typedef struct {
- int numSurfaces;
- int ofsSurfaces; // first surface, others follow
- int ofsEnd; // next lod follows
-} mdrLOD_t;
-
-typedef struct {
- int boneIndex;
- char name[32];
-} mdrTag_t;
-
-typedef struct {
- int ident;
- int version;
-
- char name[MAX_QPATH]; // model name
-
- // frames and bones are shared by all levels of detail
- int numFrames;
- int numBones;
- int ofsFrames; // mdrFrame_t[numFrames]
-
- // each level of detail has completely separate sets of surfaces
- int numLODs;
- int ofsLODs;
-
- int numTags;
- int ofsTags;
-
- int ofsEnd; // end of file
-} mdrHeader_t;
-
-#endif
-
-/*
-==============================================================================
-
- .BSP file format
-
-==============================================================================
-*/
-
-
-#define BSP_IDENT (('P'<<24)+('S'<<16)+('B'<<8)+'I')
- // little-endian "IBSP"
-
-#define BSP_VERSION 46
-
-
-// there shouldn't be any problem with increasing these values at the
-// expense of more memory allocation in the utilities
-#define MAX_MAP_MODELS 0x400
-#define MAX_MAP_BRUSHES 0x8000
-#define MAX_MAP_ENTITIES 0x800
-#define MAX_MAP_ENTSTRING 0x40000
-#define MAX_MAP_SHADERS 0x400
-
-#define MAX_MAP_AREAS 0x100 // MAX_MAP_AREA_BYTES in q_shared must match!
-#define MAX_MAP_FOGS 0x100
-#define MAX_MAP_PLANES 0x20000
-#define MAX_MAP_NODES 0x20000
-#define MAX_MAP_BRUSHSIDES 0x20000
-#define MAX_MAP_LEAFS 0x20000
-#define MAX_MAP_LEAFFACES 0x20000
-#define MAX_MAP_LEAFBRUSHES 0x40000
-#define MAX_MAP_PORTALS 0x20000
-#define MAX_MAP_LIGHTING 0x800000
-#define MAX_MAP_LIGHTGRID 0x800000
-#define MAX_MAP_VISIBILITY 0x200000
-
-#define MAX_MAP_DRAW_SURFS 0x20000
-#define MAX_MAP_DRAW_VERTS 0x80000
-#define MAX_MAP_DRAW_INDEXES 0x80000
-
-
-// key / value pair sizes in the entities lump
-#define MAX_KEY 32
-#define MAX_VALUE 1024
-
-// the editor uses these predefined yaw angles to orient entities up or down
-#define ANGLE_UP -1
-#define ANGLE_DOWN -2
-
-#define LIGHTMAP_WIDTH 128
-#define LIGHTMAP_HEIGHT 128
-
-#define MAX_WORLD_COORD ( 128*1024 )
-#define MIN_WORLD_COORD ( -128*1024 )
-#define WORLD_SIZE ( MAX_WORLD_COORD - MIN_WORLD_COORD )
-
-//=============================================================================
-
-
-typedef struct {
- int fileofs, filelen;
-} lump_t;
-
-#define LUMP_ENTITIES 0
-#define LUMP_SHADERS 1
-#define LUMP_PLANES 2
-#define LUMP_NODES 3
-#define LUMP_LEAFS 4
-#define LUMP_LEAFSURFACES 5
-#define LUMP_LEAFBRUSHES 6
-#define LUMP_MODELS 7
-#define LUMP_BRUSHES 8
-#define LUMP_BRUSHSIDES 9
-#define LUMP_DRAWVERTS 10
-#define LUMP_DRAWINDEXES 11
-#define LUMP_FOGS 12
-#define LUMP_SURFACES 13
-#define LUMP_LIGHTMAPS 14
-#define LUMP_LIGHTGRID 15
-#define LUMP_VISIBILITY 16
-#define HEADER_LUMPS 17
-
-typedef struct {
- int ident;
- int version;
-
- lump_t lumps[HEADER_LUMPS];
-} dheader_t;
-
-typedef struct {
- float mins[3], maxs[3];
- int firstSurface, numSurfaces;
- int firstBrush, numBrushes;
-} dmodel_t;
-
-typedef struct {
- char shader[MAX_QPATH];
- int surfaceFlags;
- int contentFlags;
-} dshader_t;
-
-// planes x^1 is allways the opposite of plane x
-
-typedef struct {
- float normal[3];
- float dist;
-} dplane_t;
-
-typedef struct {
- int planeNum;
- int children[2]; // negative numbers are -(leafs+1), not nodes
- int mins[3]; // for frustom culling
- int maxs[3];
-} dnode_t;
-
-typedef struct {
- int cluster; // -1 = opaque cluster (do I still store these?)
- int area;
-
- int mins[3]; // for frustum culling
- int maxs[3];
-
- int firstLeafSurface;
- int numLeafSurfaces;
-
- int firstLeafBrush;
- int numLeafBrushes;
-} dleaf_t;
-
-typedef struct {
- int planeNum; // positive plane side faces out of the leaf
- int shaderNum;
-} dbrushside_t;
-
-typedef struct {
- int firstSide;
- int numSides;
- int shaderNum; // the shader that determines the contents flags
-} dbrush_t;
-
-typedef struct {
- char shader[MAX_QPATH];
- int brushNum;
- int visibleSide; // the brush side that ray tests need to clip against (-1 == none)
-} dfog_t;
-
-typedef struct {
- vec3_t xyz;
- float st[2];
- float lightmap[2];
- vec3_t normal;
- byte color[4];
-} drawVert_t;
-
-#define drawVert_t_cleared(x) drawVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0, 0}}
-
-typedef enum {
- MST_BAD,
- MST_PLANAR,
- MST_PATCH,
- MST_TRIANGLE_SOUP,
- MST_FLARE
-} mapSurfaceType_t;
-
-typedef struct {
- int shaderNum;
- int fogNum;
- int surfaceType;
-
- int firstVert;
- int numVerts;
-
- int firstIndex;
- int numIndexes;
-
- int lightmapNum;
- int lightmapX, lightmapY;
- int lightmapWidth, lightmapHeight;
-
- vec3_t lightmapOrigin;
- vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds
-
- int patchWidth;
- int patchHeight;
-} dsurface_t;
-
-
-#endif
diff --git a/game/code/qcommon/surfaceflags.h b/game/code/qcommon/surfaceflags.h
deleted file mode 100644
index b7c10a1..0000000
--- a/game/code/qcommon/surfaceflags.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// This file must be identical in the quake and utils directories
-
-// contents flags are seperate bits
-// a given brush can contribute multiple content bits
-
-// these definitions also need to be in q_shared.h!
-
-#define CONTENTS_SOLID 1 // an eye is never valid in a solid
-#define CONTENTS_LAVA 8
-#define CONTENTS_SLIME 16
-#define CONTENTS_WATER 32
-#define CONTENTS_FOG 64
-
-#define CONTENTS_NOTTEAM1 0x0080
-#define CONTENTS_NOTTEAM2 0x0100
-#define CONTENTS_NOBOTCLIP 0x0200
-
-#define CONTENTS_AREAPORTAL 0x8000
-
-#define CONTENTS_PLAYERCLIP 0x10000
-#define CONTENTS_MONSTERCLIP 0x20000
-//bot specific contents types
-#define CONTENTS_TELEPORTER 0x40000
-#define CONTENTS_JUMPPAD 0x80000
-#define CONTENTS_CLUSTERPORTAL 0x100000
-#define CONTENTS_DONOTENTER 0x200000
-#define CONTENTS_BOTCLIP 0x400000
-#define CONTENTS_MOVER 0x800000
-
-#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
-
-#define CONTENTS_BODY 0x2000000 // should never be on a brush, only in game
-#define CONTENTS_CORPSE 0x4000000
-#define CONTENTS_DETAIL 0x8000000 // brushes not used for the bsp
-#define CONTENTS_STRUCTURAL 0x10000000 // brushes used for the bsp
-#define CONTENTS_TRANSLUCENT 0x20000000 // don't consume surface fragments inside
-#define CONTENTS_TRIGGER 0x40000000
-#define CONTENTS_NODROP 0x80000000 // don't leave bodies or items (death fog, lava)
-
-#define SURF_NODAMAGE 0x1 // never give falling damage
-#define SURF_SLICK 0x2 // effects game physics
-#define SURF_SKY 0x4 // lighting from environment map
-#define SURF_LADDER 0x8
-#define SURF_NOIMPACT 0x10 // don't make missile explosions
-#define SURF_NOMARKS 0x20 // don't leave missile marks
-#define SURF_FLESH 0x40 // make flesh sounds and effects
-#define SURF_NODRAW 0x80 // don't generate a drawsurface at all
-#define SURF_HINT 0x100 // make a primary bsp splitter
-#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
-#define SURF_NOLIGHTMAP 0x400 // surface doesn't need a lightmap
-#define SURF_POINTLIGHT 0x800 // generate lighting info at vertexes
-#define SURF_METALSTEPS 0x1000 // clanking footsteps
-#define SURF_NOSTEPS 0x2000 // no footstep sounds
-#define SURF_NONSOLID 0x4000 // don't collide against curves with this set
-#define SURF_LIGHTFILTER 0x8000 // act as a light filter during q3map -light
-#define SURF_ALPHASHADOW 0x10000 // do per-pixel light shadow casting in q3map
-#define SURF_NODLIGHT 0x20000 // don't dlight even if solid (solid lava, skies)
-#define SURF_DUST 0x40000 // leave a dust trail when walking on this surface
diff --git a/game/code/renderer/tr_types.h b/game/code/renderer/tr_types.h
deleted file mode 100644
index 50f9759..0000000
--- a/game/code/renderer/tr_types.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#ifndef __TR_TYPES_H
-#define __TR_TYPES_H
-
-
-#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces
-#define MAX_ENTITIES 1023 // can't be increased without changing drawsurf bit packing
-
-// renderfx flags
-#define RF_MINLIGHT 0x0001 // allways have some light (viewmodel, some items)
-#define RF_THIRD_PERSON 0x0002 // don't draw through eyes, only mirrors (player bodies, chat sprites)
-#define RF_FIRST_PERSON 0x0004 // only draw through eyes (view weapon, damage blood blob)
-#define RF_DEPTHHACK 0x0008 // for view weapon Z crunching
-
-#define RF_CROSSHAIR 0x0010 // This item is a cross hair and will draw over everything similar to
- // DEPTHHACK in stereo rendering mode, with the difference that the
- // projection matrix won't be hacked to reduce the stereo separation as
- // is done for the gun.
-
-#define RF_NOSHADOW 0x0040 // don't add stencil shadows
-
-#define RF_LIGHTING_ORIGIN 0x0080 // use refEntity->lightingOrigin instead of refEntity->origin
- // for lighting. This allows entities to sink into the floor
- // with their origin going solid, and allows all parts of a
- // player to get the same lighting
-
-#define RF_SHADOW_PLANE 0x0100 // use refEntity->shadowPlane
-#define RF_WRAP_FRAMES 0x0200 // mod the model frames by the maxframes to allow continuous
-
-// refdef flags
-#define RDF_NOWORLDMODEL 0x0001 // used for player configuration screen
-#define RDF_HYPERSPACE 0x0004 // teleportation effect
-
-typedef struct {
- vec3_t xyz;
- float st[2];
- byte modulate[4];
-} polyVert_t;
-
-typedef struct poly_s {
- qhandle_t hShader;
- int numVerts;
- polyVert_t *verts;
-} poly_t;
-
-typedef enum {
- RT_MODEL,
- RT_POLY,
- RT_SPRITE,
- RT_BEAM,
- RT_RAIL_CORE,
- RT_RAIL_RINGS,
- RT_LIGHTNING,
- RT_PORTALSURFACE, // doesn't draw anything, just info for portals
-
- RT_MAX_REF_ENTITY_TYPE
-} refEntityType_t;
-
-typedef struct {
- refEntityType_t reType;
- int renderfx;
-
- qhandle_t hModel; // opaque type outside refresh
-
- // most recent data
- vec3_t lightingOrigin; // so multi-part models can be lit identically (RF_LIGHTING_ORIGIN)
- float shadowPlane; // projection shadows go here, stencils go slightly lower
-
- vec3_t axis[3]; // rotation vectors
- qboolean nonNormalizedAxes; // axis are not normalized, i.e. they have scale
- float origin[3]; // also used as MODEL_BEAM's "from"
- int frame; // also used as MODEL_BEAM's diameter
-
- // previous data for frame interpolation
- float oldorigin[3]; // also used as MODEL_BEAM's "to"
- int oldframe;
- float backlerp; // 0.0 = current, 1.0 = old
-
- // texturing
- int skinNum; // inline skin index
- qhandle_t customSkin; // NULL for default skin
- qhandle_t customShader; // use one image for the entire thing
-
- // misc
- byte shaderRGBA[4]; // colors used by rgbgen entity shaders
- float shaderTexCoord[2]; // texture coordinates used by tcMod entity modifiers
- float shaderTime; // subtracted from refdef time to control effect start times
-
- // extra sprite information
- float radius;
- float rotation;
-} refEntity_t;
-
-
-#define MAX_RENDER_STRINGS 8
-#define MAX_RENDER_STRING_LENGTH 32
-
-typedef struct {
- int x, y, width, height;
- float fov_x, fov_y;
- vec3_t vieworg;
- vec3_t viewaxis[3]; // transformation matrix
-
- // time in milliseconds for shader effects and other time dependent rendering issues
- int time;
-
- int rdflags; // RDF_NOWORLDMODEL, etc
-
- // 1 bits will prevent the associated area from rendering at all
- byte areamask[MAX_MAP_AREA_BYTES];
-
- // text messages for deform text shaders
- char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH];
-} refdef_t;
-
-
-typedef enum {
- STEREO_CENTER,
- STEREO_LEFT,
- STEREO_RIGHT
-} stereoFrame_t;
-
-
-/*
-** glconfig_t
-**
-** Contains variables specific to the OpenGL configuration
-** being run right now. These are constant once the OpenGL
-** subsystem is initialized.
-*/
-typedef enum {
- TC_NONE,
- TC_S3TC, // this is for the GL_S3_s3tc extension.
- TC_S3TC_ARB // this is for the GL_EXT_texture_compression_s3tc extension.
-} textureCompression_t;
-
-typedef enum {
- GLDRV_ICD, // driver is integrated with window system
- // WARNING: there are tests that check for
- // > GLDRV_ICD for minidriverness, so this
- // should always be the lowest value in this
- // enum set
- GLDRV_STANDALONE, // driver is a non-3Dfx standalone driver
- GLDRV_VOODOO // driver is a 3Dfx standalone driver
-} glDriverType_t;
-
-typedef enum {
- GLHW_GENERIC, // where everthing works the way it should
- GLHW_3DFX_2D3D, // Voodoo Banshee or Voodoo3, relevant since if this is
- // the hardware type then there can NOT exist a secondary
- // display adapter
- GLHW_RIVA128, // where you can't interpolate alpha
- GLHW_RAGEPRO, // where you can't modulate alpha on alpha textures
- GLHW_PERMEDIA2 // where you don't have src*dst
-} glHardwareType_t;
-
-typedef struct {
- char renderer_string[MAX_STRING_CHARS];
- char vendor_string[MAX_STRING_CHARS];
- char version_string[MAX_STRING_CHARS];
- char extensions_string[BIG_INFO_STRING];
-
- int maxTextureSize; // queried from GL
- int numTextureUnits; // multitexture ability
-
- int colorBits, depthBits, stencilBits;
-
- glDriverType_t driverType;
- glHardwareType_t hardwareType;
-
- qboolean deviceSupportsGamma;
- textureCompression_t textureCompression;
- qboolean textureEnvAddAvailable;
-
- int vidWidth, vidHeight;
- // aspect is the screen's physical width / height, which may be different
- // than scrWidth / scrHeight if the pixels are non-square
- // normal screens should be 4/3, but wide aspect monitors may be 16/9
- float windowAspect;
-
- int displayFrequency;
-
- // synonymous with "does rendering consume the entire screen?", therefore
- // a Voodoo or Voodoo2 will have this set to TRUE, as will a Win32 ICD that
- // used CDS.
- qboolean isFullscreen;
- qboolean stereoEnabled;
- qboolean smpActive; // dual processor
-} glconfig_t;
-
-#endif // __TR_TYPES_H
diff --git a/game/code/ui/ui_gameinfo.c b/game/code/ui/ui_gameinfo.c
deleted file mode 100644
index e445910..0000000
--- a/game/code/ui/ui_gameinfo.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-//
-// gameinfo.c
-//
-
-#include "ui_local.h"
-
-
-//
-// arena and bot info
-//
-
-
-int ui_numBots;
-static char *ui_botInfos[MAX_BOTS];
-
-static int ui_numArenas;
-static char *ui_arenaInfos[MAX_ARENAS];
-
-#ifndef MISSIONPACK // bk001206
-static int ui_numSinglePlayerArenas;
-static int ui_numSpecialSinglePlayerArenas;
-#endif
-
-/*
-===============
-UI_ParseInfos
-===============
-*/
-int UI_ParseInfos( char *buf, int max, char *infos[] ) {
- char *token;
- int count;
- char key[MAX_TOKEN_CHARS];
- char info[MAX_INFO_STRING];
-
- count = 0;
-
- while ( 1 ) {
- token = COM_Parse( &buf );
- if ( !token[0] ) {
- break;
- }
- if ( strcmp( token, "{" ) ) {
- Com_Printf( "Missing { in info file\n" );
- break;
- }
-
- if ( count == max ) {
- Com_Printf( "Max infos exceeded\n" );
- break;
- }
-
- info[0] = '\0';
- while ( 1 ) {
- token = COM_ParseExt( &buf, qtrue );
- if ( !token[0] ) {
- Com_Printf( "Unexpected end of info file\n" );
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- Q_strncpyz( key, token, sizeof( key ) );
-
- token = COM_ParseExt( &buf, qfalse );
- if ( !token[0] ) {
- strcpy( token, "<NULL>" );
- }
- Info_SetValueForKey( info, key, token );
- }
- //NOTE: extra space for arena number
- infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
- if (infos[count]) {
- strcpy(infos[count], info);
- count++;
- }
- }
- return count;
-}
-
-/*
-===============
-UI_LoadArenasFromFile
-===============
-*/
-static void UI_LoadArenasFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_ARENAS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_ARENAS_TEXT ) {
- trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_ARENAS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] );
-}
-
-/*
-===============
-UI_LoadArenas
-===============
-*/
-void UI_LoadArenas( void ) {
- int numdirs;
- vmCvar_t arenasFile;
- char filename[128];
- char dirlist[1024];
- char* dirptr;
- int i, n;
- int dirlen;
- char *type;
-
- ui_numArenas = 0;
- uiInfo.mapCount = 0;
-
- trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
- if( *arenasFile.string ) {
- UI_LoadArenasFromFile(arenasFile.string);
- }
- else {
- UI_LoadArenasFromFile("scripts/arenas.txt");
- }
-
- // get all arenas from .arena files
- numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- UI_LoadArenasFromFile(filename);
- }
- trap_Print( va( "%i arenas parsed\n", ui_numArenas ) );
- if (UI_OutOfMemory()) {
- trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all arenas\n");
- }
-
- for( n = 0; n < ui_numArenas; n++ ) {
- // determine type
-
- uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
- uiInfo.mapList[uiInfo.mapCount].mapLoadName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "map"));
- uiInfo.mapList[uiInfo.mapCount].mapName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "longname"));
- uiInfo.mapList[uiInfo.mapCount].levelShot = -1;
- uiInfo.mapList[uiInfo.mapCount].imageName = String_Alloc(va("levelshots/%s", uiInfo.mapList[uiInfo.mapCount].mapLoadName));
- uiInfo.mapList[uiInfo.mapCount].typeBits = 0;
-
- type = Info_ValueForKey( ui_arenaInfos[n], "type" );
- // if no type specified, it will be treated as "ffa"
- if( *type ) {
- if( strstr( type, "ffa" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_FFA);
- }
- if( strstr( type, "tourney" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_TOURNAMENT);
- }
- if( strstr( type, "ctf" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_CTF);
- }
- if( strstr( type, "oneflag" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_1FCTF);
- }
- if( strstr( type, "overload" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_OBELISK);
- }
- if( strstr( type, "harvester" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_HARVESTER);
- }
- if( strstr( type, "elimination" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_ELIMINATION);
- }
- if( strstr( type, "ctfelimination" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_CTF_ELIMINATION);
- }
- if( strstr( type, "lms" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_LMS);
- }
- if( strstr( type, "dd" ) ) {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_DOUBLE_D);
- }
- } else {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_FFA);
- }
-
- uiInfo.mapCount++;
- if (uiInfo.mapCount >= MAX_MAPS) {
- break;
- }
- }
-}
-
-
-/*
-===============
-UI_LoadBotsFromFile
-===============
-*/
-static void UI_LoadBotsFromFile( char *filename ) {
- int len;
- fileHandle_t f;
- char buf[MAX_BOTS_TEXT];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
- return;
- }
- if ( len >= MAX_BOTS_TEXT ) {
- trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- COM_Compress(buf);
-
- ui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] );
-}
-
-/*
-===============
-UI_LoadBots
-===============
-*/
-void UI_LoadBots( void ) {
- vmCvar_t botsFile;
- int numdirs;
- char filename[128];
- char dirlist[1024];
- char* dirptr;
- int i;
- int dirlen;
-
- ui_numBots = 0;
-
- trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
- if( *botsFile.string ) {
- UI_LoadBotsFromFile(botsFile.string);
- }
- else {
- UI_LoadBotsFromFile("scripts/bots.txt");
- }
-
- // get all bots from .bot files
- numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
- dirptr = dirlist;
- for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
- dirlen = strlen(dirptr);
- strcpy(filename, "scripts/");
- strcat(filename, dirptr);
- UI_LoadBotsFromFile(filename);
- }
- trap_Print( va( "%i bots parsed\n", ui_numBots ) );
-}
-
-
-/*
-===============
-UI_GetBotInfoByNumber
-===============
-*/
-char *UI_GetBotInfoByNumber( int num ) {
- if( num < 0 || num >= ui_numBots ) {
- trap_Print( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
- return NULL;
- }
- return ui_botInfos[num];
-}
-
-
-/*
-===============
-UI_GetBotInfoByName
-===============
-*/
-char *UI_GetBotInfoByName( const char *name ) {
- int n;
- char *value;
-
- for ( n = 0; n < ui_numBots ; n++ ) {
- value = Info_ValueForKey( ui_botInfos[n], "name" );
- if ( !Q_stricmp( value, name ) ) {
- return ui_botInfos[n];
- }
- }
-
- return NULL;
-}
-
-int UI_GetNumBots( void ) {
- return ui_numBots;
-}
-
-
-char *UI_GetBotNameByNumber( int num ) {
- char *info = UI_GetBotInfoByNumber(num);
- if (info) {
- return Info_ValueForKey( info, "name" );
- }
- return "Sarge";
-}
diff --git a/game/code/ui/ui_local.h b/game/code/ui/ui_local.h
deleted file mode 100644
index 281673a..0000000
--- a/game/code/ui/ui_local.h
+++ /dev/null
@@ -1,1138 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#ifndef __UI_LOCAL_H__
-#define __UI_LOCAL_H__
-
-#include "../qcommon/q_shared.h"
-#include "../renderer/tr_types.h"
-#include "ui_public.h"
-#include "../client/keycodes.h"
-#include "../game/bg_public.h"
-#include "ui_shared.h"
-
-// global display context
-
-extern vmCvar_t ui_ffa_fraglimit;
-extern vmCvar_t ui_ffa_timelimit;
-
-extern vmCvar_t ui_tourney_fraglimit;
-extern vmCvar_t ui_tourney_timelimit;
-
-extern vmCvar_t ui_team_fraglimit;
-extern vmCvar_t ui_team_timelimit;
-extern vmCvar_t ui_team_friendly;
-
-extern vmCvar_t ui_ctf_capturelimit;
-extern vmCvar_t ui_ctf_timelimit;
-extern vmCvar_t ui_ctf_friendly;
-
-extern vmCvar_t ui_arenasFile;
-extern vmCvar_t ui_botsFile;
-extern vmCvar_t ui_spScores1;
-extern vmCvar_t ui_spScores2;
-extern vmCvar_t ui_spScores3;
-extern vmCvar_t ui_spScores4;
-extern vmCvar_t ui_spScores5;
-extern vmCvar_t ui_spAwards;
-extern vmCvar_t ui_spVideos;
-extern vmCvar_t ui_spSkill;
-
-extern vmCvar_t ui_spSelection;
-
-extern vmCvar_t ui_browserMaster;
-extern vmCvar_t ui_browserGameType;
-extern vmCvar_t ui_browserSortKey;
-extern vmCvar_t ui_browserShowFull;
-extern vmCvar_t ui_browserShowEmpty;
-
-extern vmCvar_t ui_brassTime;
-extern vmCvar_t ui_drawCrosshair;
-extern vmCvar_t ui_drawCrosshairNames;
-extern vmCvar_t ui_marks;
-
-extern vmCvar_t ui_server1;
-extern vmCvar_t ui_server2;
-extern vmCvar_t ui_server3;
-extern vmCvar_t ui_server4;
-extern vmCvar_t ui_server5;
-extern vmCvar_t ui_server6;
-extern vmCvar_t ui_server7;
-extern vmCvar_t ui_server8;
-extern vmCvar_t ui_server9;
-extern vmCvar_t ui_server10;
-extern vmCvar_t ui_server11;
-extern vmCvar_t ui_server12;
-extern vmCvar_t ui_server13;
-extern vmCvar_t ui_server14;
-extern vmCvar_t ui_server15;
-extern vmCvar_t ui_server16;
-
-extern vmCvar_t ui_cdkey;
-extern vmCvar_t ui_cdkeychecked;
-
-extern vmCvar_t ui_captureLimit;
-extern vmCvar_t ui_fragLimit;
-extern vmCvar_t ui_gameType;
-extern vmCvar_t ui_netGameType;
-extern vmCvar_t ui_actualNetGameType;
-extern vmCvar_t ui_joinGameType;
-extern vmCvar_t ui_netSource;
-extern vmCvar_t ui_serverFilterType;
-extern vmCvar_t ui_dedicated;
-extern vmCvar_t ui_opponentName;
-extern vmCvar_t ui_menuFiles;
-extern vmCvar_t ui_currentTier;
-extern vmCvar_t ui_currentMap;
-extern vmCvar_t ui_currentNetMap;
-extern vmCvar_t ui_mapIndex;
-extern vmCvar_t ui_currentOpponent;
-extern vmCvar_t ui_selectedPlayer;
-extern vmCvar_t ui_selectedPlayerName;
-extern vmCvar_t ui_lastServerRefresh_0;
-extern vmCvar_t ui_lastServerRefresh_1;
-extern vmCvar_t ui_lastServerRefresh_2;
-extern vmCvar_t ui_lastServerRefresh_3;
-extern vmCvar_t ui_singlePlayerActive;
-extern vmCvar_t ui_scoreAccuracy;
-extern vmCvar_t ui_scoreImpressives;
-extern vmCvar_t ui_scoreExcellents;
-extern vmCvar_t ui_scoreDefends;
-extern vmCvar_t ui_scoreAssists;
-extern vmCvar_t ui_scoreGauntlets;
-extern vmCvar_t ui_scoreScore;
-extern vmCvar_t ui_scorePerfect;
-extern vmCvar_t ui_scoreTeam;
-extern vmCvar_t ui_scoreBase;
-extern vmCvar_t ui_scoreTimeBonus;
-extern vmCvar_t ui_scoreSkillBonus;
-extern vmCvar_t ui_scoreShutoutBonus;
-extern vmCvar_t ui_scoreTime;
-extern vmCvar_t ui_smallFont;
-extern vmCvar_t ui_bigFont;
-extern vmCvar_t ui_serverStatusTimeOut;
-
-extern vmCvar_t ui_humansonly;
-
-
-
-//
-// ui_qmenu.c
-//
-
-#define RCOLUMN_OFFSET ( BIGCHAR_WIDTH )
-#define LCOLUMN_OFFSET (-BIGCHAR_WIDTH )
-
-#define SLIDER_RANGE 10
-#define MAX_EDIT_LINE 256
-
-#define MAX_MENUDEPTH 8
-#define MAX_MENUITEMS 96
-
-#define MTYPE_NULL 0
-#define MTYPE_SLIDER 1
-#define MTYPE_ACTION 2
-#define MTYPE_SPINCONTROL 3
-#define MTYPE_FIELD 4
-#define MTYPE_RADIOBUTTON 5
-#define MTYPE_BITMAP 6
-#define MTYPE_TEXT 7
-#define MTYPE_SCROLLLIST 8
-#define MTYPE_PTEXT 9
-#define MTYPE_BTEXT 10
-
-#define QMF_BLINK 0x00000001
-#define QMF_SMALLFONT 0x00000002
-#define QMF_LEFT_JUSTIFY 0x00000004
-#define QMF_CENTER_JUSTIFY 0x00000008
-#define QMF_RIGHT_JUSTIFY 0x00000010
-#define QMF_NUMBERSONLY 0x00000020 // edit field is only numbers
-#define QMF_HIGHLIGHT 0x00000040
-#define QMF_HIGHLIGHT_IF_FOCUS 0x00000080 // steady focus
-#define QMF_PULSEIFFOCUS 0x00000100 // pulse if focus
-#define QMF_HASMOUSEFOCUS 0x00000200
-#define QMF_NOONOFFTEXT 0x00000400
-#define QMF_MOUSEONLY 0x00000800 // only mouse input allowed
-#define QMF_HIDDEN 0x00001000 // skips drawing
-#define QMF_GRAYED 0x00002000 // grays and disables
-#define QMF_INACTIVE 0x00004000 // disables any input
-#define QMF_NODEFAULTINIT 0x00008000 // skip default initialization
-#define QMF_OWNERDRAW 0x00010000
-#define QMF_PULSE 0x00020000
-#define QMF_LOWERCASE 0x00040000 // edit field is all lower case
-#define QMF_UPPERCASE 0x00080000 // edit field is all upper case
-#define QMF_SILENT 0x00100000
-
-// callback notifications
-#define QM_GOTFOCUS 1
-#define QM_LOSTFOCUS 2
-#define QM_ACTIVATED 3
-
-typedef struct _tag_menuframework
-{
- int cursor;
- int cursor_prev;
-
- int nitems;
- void *items[MAX_MENUITEMS];
-
- void (*draw) (void);
- sfxHandle_t (*key) (int key);
-
- qboolean wrapAround;
- qboolean fullscreen;
- qboolean showlogo;
-} menuframework_s;
-
-typedef struct
-{
- int type;
- const char *name;
- int id;
- int x, y;
- int left;
- int top;
- int right;
- int bottom;
- menuframework_s *parent;
- int menuPosition;
- unsigned flags;
-
- void (*callback)( void *self, int event );
- void (*statusbar)( void *self );
- void (*ownerdraw)( void *self );
-} menucommon_s;
-
-typedef struct {
- int cursor;
- int scroll;
- int widthInChars;
- char buffer[MAX_EDIT_LINE];
- int maxchars;
-} mfield_t;
-
-typedef struct
-{
- menucommon_s generic;
- mfield_t field;
-} menufield_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- float minvalue;
- float maxvalue;
- float curvalue;
-
- float range;
-} menuslider_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- int oldvalue;
- int curvalue;
- int numitems;
- int top;
-
- const char **itemnames;
-
- int width;
- int height;
- int columns;
- int seperation;
-} menulist_s;
-
-typedef struct
-{
- menucommon_s generic;
-} menuaction_s;
-
-typedef struct
-{
- menucommon_s generic;
- int curvalue;
-} menuradiobutton_s;
-
-typedef struct
-{
- menucommon_s generic;
- char* focuspic;
- char* errorpic;
- qhandle_t shader;
- qhandle_t focusshader;
- int width;
- int height;
- float* focuscolor;
-} menubitmap_s;
-
-typedef struct
-{
- menucommon_s generic;
- char* string;
- int style;
- float* color;
-} menutext_s;
-
-extern void Menu_Cache( void );
-extern void Menu_Focus( menucommon_s *m );
-extern void Menu_AddItem( menuframework_s *menu, void *item );
-extern void Menu_AdjustCursor( menuframework_s *menu, int dir );
-extern void Menu_Draw( menuframework_s *menu );
-extern void *Menu_ItemAtCursor( menuframework_s *m );
-extern sfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item );
-extern void Menu_SetCursor( menuframework_s *s, int cursor );
-extern void Menu_SetCursorToItem( menuframework_s *m, void* ptr );
-extern sfxHandle_t Menu_DefaultKey( menuframework_s *s, int key );
-extern void Bitmap_Init( menubitmap_s *b );
-extern void Bitmap_Draw( menubitmap_s *b );
-extern void ScrollList_Draw( menulist_s *l );
-extern sfxHandle_t ScrollList_Key( menulist_s *l, int key );
-extern sfxHandle_t menu_in_sound;
-extern sfxHandle_t menu_move_sound;
-extern sfxHandle_t menu_out_sound;
-extern sfxHandle_t menu_buzz_sound;
-extern sfxHandle_t menu_null_sound;
-extern sfxHandle_t weaponChangeSound;
-extern vec4_t menu_text_color;
-extern vec4_t menu_grayed_color;
-extern vec4_t menu_dark_color;
-extern vec4_t menu_highlight_color;
-extern vec4_t menu_red_color;
-extern vec4_t menu_black_color;
-extern vec4_t menu_dim_color;
-extern vec4_t color_black;
-extern vec4_t color_white;
-extern vec4_t color_yellow;
-extern vec4_t color_blue;
-extern vec4_t color_orange;
-extern vec4_t color_red;
-extern vec4_t color_dim;
-extern vec4_t name_color;
-extern vec4_t list_color;
-extern vec4_t listbar_color;
-extern vec4_t text_color_disabled;
-extern vec4_t text_color_normal;
-extern vec4_t text_color_highlight;
-
-extern char *ui_medalNames[];
-extern char *ui_medalPicNames[];
-extern char *ui_medalSounds[];
-
-//
-// ui_mfield.c
-//
-extern void MField_Clear( mfield_t *edit );
-extern void MField_KeyDownEvent( mfield_t *edit, int key );
-extern void MField_CharEvent( mfield_t *edit, int ch );
-extern void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color );
-extern void MenuField_Init( menufield_s* m );
-extern void MenuField_Draw( menufield_s *f );
-extern sfxHandle_t MenuField_Key( menufield_s* m, int* key );
-
-//
-// ui_main.c
-//
-void UI_Report( void );
-void UI_Load( void );
-void UI_LoadMenus(const char *menuFile, qboolean reset);
-void _UI_SetActiveMenu( uiMenuCommand_t menu );
-int UI_AdjustTimeByGame(int time);
-void UI_ShowPostGame(qboolean newHigh);
-void UI_ClearScores( void );
-void UI_LoadArenas(void);
-
-//
-// ui_menu.c
-//
-extern void MainMenu_Cache( void );
-extern void UI_MainMenu(void);
-extern void UI_RegisterCvars( void );
-extern void UI_UpdateCvars( void );
-
-//
-// ui_credits.c
-//
-extern void UI_CreditMenu( void );
-
-//
-// ui_ingame.c
-//
-extern void InGame_Cache( void );
-extern void UI_InGameMenu(void);
-
-//
-// ui_confirm.c
-//
-extern void ConfirmMenu_Cache( void );
-extern void UI_ConfirmMenu( const char *question, void (*draw)( void ), void (*action)( qboolean result ) );
-
-//
-// ui_setup.c
-//
-extern void UI_SetupMenu_Cache( void );
-extern void UI_SetupMenu(void);
-
-//
-// ui_team.c
-//
-extern void UI_TeamMainMenu( void );
-extern void TeamMain_Cache( void );
-
-//
-// ui_connect.c
-//
-extern void UI_DrawConnectScreen( qboolean overlay );
-
-//
-// ui_controls2.c
-//
-extern void UI_ControlsMenu( void );
-extern void Controls_Cache( void );
-
-//
-// ui_demo2.c
-//
-extern void UI_DemosMenu( void );
-extern void Demos_Cache( void );
-
-//
-// ui_cinematics.c
-//
-extern void UI_CinematicsMenu( void );
-extern void UI_CinematicsMenu_f( void );
-extern void UI_CinematicsMenu_Cache( void );
-
-//
-// ui_mods.c
-//
-extern void UI_ModsMenu( void );
-extern void UI_ModsMenu_Cache( void );
-
-//
-// ui_cdkey.c
-//
-extern void UI_CDKeyMenu( void );
-extern void UI_CDKeyMenu_Cache( void );
-extern void UI_CDKeyMenu_f( void );
-
-//
-// ui_playermodel.c
-//
-extern void UI_PlayerModelMenu( void );
-extern void PlayerModel_Cache( void );
-
-//
-// ui_playersettings.c
-//
-extern void UI_PlayerSettingsMenu( void );
-extern void PlayerSettings_Cache( void );
-
-//
-// ui_preferences.c
-//
-extern void UI_PreferencesMenu( void );
-extern void Preferences_Cache( void );
-
-//
-// ui_specifyleague.c
-//
-extern void UI_SpecifyLeagueMenu( void );
-extern void SpecifyLeague_Cache( void );
-
-//
-// ui_specifyserver.c
-//
-extern void UI_SpecifyServerMenu( void );
-extern void SpecifyServer_Cache( void );
-
-//
-// ui_servers2.c
-//
-#define MAX_FAVORITESERVERS 16
-
-extern void UI_ArenaServersMenu( void );
-extern void ArenaServers_Cache( void );
-
-//
-// ui_startserver.c
-//
-extern void UI_StartServerMenu( qboolean multiplayer );
-extern void StartServer_Cache( void );
-extern void ServerOptions_Cache( void );
-extern void UI_BotSelectMenu( char *bot );
-extern void UI_BotSelectMenu_Cache( void );
-
-//
-// ui_serverinfo.c
-//
-extern void UI_ServerInfoMenu( void );
-extern void ServerInfo_Cache( void );
-
-//
-// ui_video.c
-//
-extern void UI_GraphicsOptionsMenu( void );
-extern void GraphicsOptions_Cache( void );
-extern void DriverInfo_Cache( void );
-
-//
-// ui_players.c
-//
-
-//FIXME ripped from cg_local.h
-typedef struct {
- int oldFrame;
- int oldFrameTime; // time when ->oldFrame was exactly on
-
- int frame;
- int frameTime; // time when ->frame will be exactly on
-
- float backlerp;
-
- float yawAngle;
- qboolean yawing;
- float pitchAngle;
- qboolean pitching;
-
- int animationNumber; // may include ANIM_TOGGLEBIT
- animation_t *animation;
- int animationTime; // time when the first frame of the animation will be exact
-} lerpFrame_t;
-
-typedef struct {
- // model info
- qhandle_t legsModel;
- qhandle_t legsSkin;
- lerpFrame_t legs;
-
- qhandle_t torsoModel;
- qhandle_t torsoSkin;
- lerpFrame_t torso;
-
- qhandle_t headModel;
- qhandle_t headSkin;
-
- animation_t animations[MAX_TOTALANIMATIONS];
-
- qhandle_t weaponModel;
- qhandle_t barrelModel;
- qhandle_t flashModel;
- vec3_t flashDlightColor;
- int muzzleFlashTime;
-
- // currently in use drawing parms
- vec3_t viewAngles;
- vec3_t moveAngles;
- weapon_t currentWeapon;
- int legsAnim;
- int torsoAnim;
-
- // animation vars
- weapon_t weapon;
- weapon_t lastWeapon;
- weapon_t pendingWeapon;
- int weaponTimer;
- int pendingLegsAnim;
- int torsoAnimationTimer;
-
- int pendingTorsoAnim;
- int legsAnimationTimer;
-
- qboolean chat;
- qboolean newModel;
-
- qboolean barrelSpinning;
- float barrelAngle;
- int barrelTime;
-
- int realWeapon;
-} playerInfo_t;
-
-void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time );
-void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model, const char *headmodel, char *teamName );
-void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNum, qboolean chat );
-qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName , const char *headName, const char *teamName);
-
-//
-// ui_atoms.c
-//
-// this is only used in the old ui, the new ui has it's own version
-typedef struct {
- int frametime;
- int realtime;
- int cursorx;
- int cursory;
- glconfig_t glconfig;
- qboolean debug;
- qhandle_t whiteShader;
- qhandle_t menuBackShader;
- qhandle_t menuBackShader2;
- qhandle_t menuBackNoLogoShader;
- qhandle_t charset;
- qhandle_t charsetProp;
- qhandle_t charsetPropGlow;
- qhandle_t charsetPropB;
- qhandle_t cursor;
- qhandle_t rb_on;
- qhandle_t rb_off;
- float scale;
- float bias;
- qboolean demoversion;
- qboolean firstdraw;
-} uiStatic_t;
-
-
-// new ui stuff
-#define UI_NUMFX 7
-#define MAX_HEADS 64
-#define MAX_ALIASES 64
-#define MAX_HEADNAME 32
-#define MAX_TEAMS 64
-#define MAX_GAMETYPES 16
-#define MAX_MAPS 128
-#define MAX_SPMAPS 16
-#define PLAYERS_PER_TEAM 5
-#define MAX_PINGREQUESTS 32
-#define MAX_ADDRESSLENGTH 64
-#define MAX_HOSTNAMELENGTH 22
-#define MAX_MAPNAMELENGTH 16
-#define MAX_STATUSLENGTH 64
-#define MAX_LISTBOXWIDTH 59
-#define UI_FONT_THRESHOLD 0.1
-#define MAX_DISPLAY_SERVERS 2048
-#define MAX_SERVERSTATUS_LINES 128
-#define MAX_SERVERSTATUS_TEXT 1024
-#define MAX_FOUNDPLAYER_SERVERS 16
-#define TEAM_MEMBERS 5
-#define GAMES_ALL 0
-#define GAMES_FFA 1
-#define GAMES_TEAMPLAY 2
-#define GAMES_TOURNEY 3
-#define GAMES_CTF 4
-#define MAPS_PER_TIER 3
-#define MAX_TIERS 16
-#define MAX_MODS 64
-#define MAX_DEMOS 256
-#define MAX_MOVIES 256
-#define MAX_PLAYERMODELS 256
-
-
-typedef struct {
- const char *name;
- const char *imageName;
- qhandle_t headImage;
- const char *base;
- qboolean active;
- int reference;
-} characterInfo;
-
-typedef struct {
- const char *name;
- const char *ai;
- const char *action;
-} aliasInfo;
-
-typedef struct {
- const char *teamName;
- const char *imageName;
- const char *teamMembers[TEAM_MEMBERS];
- qhandle_t teamIcon;
- qhandle_t teamIcon_Metal;
- qhandle_t teamIcon_Name;
- int cinematic;
-} teamInfo;
-
-typedef struct {
- const char *gameType;
- int gtEnum;
-} gameTypeInfo;
-
-typedef struct {
- const char *mapName;
- const char *mapLoadName;
- const char *imageName;
- const char *opponentName;
- int teamMembers;
- int typeBits;
- int cinematic;
- int timeToBeat[MAX_GAMETYPES];
- qhandle_t levelShot;
- qboolean active;
-} mapInfo;
-
-typedef struct {
- const char *tierName;
- const char *maps[MAPS_PER_TIER];
- int gameTypes[MAPS_PER_TIER];
- qhandle_t mapHandles[MAPS_PER_TIER];
-} tierInfo;
-
-typedef struct serverFilter_s {
- const char *description;
- const char *basedir;
-} serverFilter_t;
-
-typedef struct {
- char adrstr[MAX_ADDRESSLENGTH];
- int start;
-} pinglist_t;
-
-
-typedef struct serverStatus_s {
- pinglist_t pingList[MAX_PINGREQUESTS];
- int numqueriedservers;
- int currentping;
- int nextpingtime;
- int maxservers;
- int refreshtime;
- int numServers;
- int sortKey;
- int sortDir;
- int lastCount;
- qboolean refreshActive;
- int currentServer;
- int displayServers[MAX_DISPLAY_SERVERS];
- int numDisplayServers;
- int numPlayersOnServers;
- int nextDisplayRefresh;
- int nextSortTime;
- qhandle_t currentServerPreview;
- int currentServerCinematic;
- int motdLen;
- int motdWidth;
- int motdPaintX;
- int motdPaintX2;
- int motdOffset;
- int motdTime;
- char motd[MAX_STRING_CHARS];
-} serverStatus_t;
-
-
-typedef struct {
- char adrstr[MAX_ADDRESSLENGTH];
- char name[MAX_ADDRESSLENGTH];
- int startTime;
- int serverNum;
- qboolean valid;
-} pendingServer_t;
-
-typedef struct {
- int num;
- pendingServer_t server[MAX_SERVERSTATUSREQUESTS];
-} pendingServerStatus_t;
-
-typedef struct {
- char address[MAX_ADDRESSLENGTH];
- char *lines[MAX_SERVERSTATUS_LINES][4];
- char text[MAX_SERVERSTATUS_TEXT];
- char pings[MAX_CLIENTS * 3];
- int numLines;
-} serverStatusInfo_t;
-
-typedef struct {
- const char *modName;
- const char *modDescr;
-} modInfo_t;
-
-
-typedef struct {
- displayContextDef_t uiDC;
- int newHighScoreTime;
- int newBestTime;
- int showPostGameTime;
- qboolean newHighScore;
- qboolean demoAvailable;
- qboolean soundHighScore;
-
- int characterCount;
- int botIndex;
- characterInfo characterList[MAX_HEADS];
-
- int aliasCount;
- aliasInfo aliasList[MAX_ALIASES];
-
- int teamCount;
- teamInfo teamList[MAX_TEAMS];
-
- int numGameTypes;
- gameTypeInfo gameTypes[MAX_GAMETYPES];
-
- int numJoinGameTypes;
- gameTypeInfo joinGameTypes[MAX_GAMETYPES];
-
- int redBlue;
- int playerCount;
- int myTeamCount;
- int teamIndex;
- int playerRefresh;
- int playerIndex;
- int playerNumber;
- qboolean teamLeader;
- char playerNames[MAX_CLIENTS][MAX_NAME_LENGTH];
- char teamNames[MAX_CLIENTS][MAX_NAME_LENGTH];
- int teamClientNums[MAX_CLIENTS];
-
- int mapCount;
- mapInfo mapList[MAX_MAPS];
-
-
- int tierCount;
- tierInfo tierList[MAX_TIERS];
-
- int skillIndex;
-
- modInfo_t modList[MAX_MODS];
- int modCount;
- int modIndex;
-
- const char *demoList[MAX_DEMOS];
- int demoCount;
- int demoIndex;
-
- const char *movieList[MAX_MOVIES];
- int movieCount;
- int movieIndex;
- int previewMovie;
-
- serverStatus_t serverStatus;
-
- // for the showing the status of a server
- char serverStatusAddress[MAX_ADDRESSLENGTH];
- serverStatusInfo_t serverStatusInfo;
- int nextServerStatusRefresh;
-
- // to retrieve the status of server to find a player
- pendingServerStatus_t pendingServerStatus;
- char findPlayerName[MAX_STRING_CHARS];
- char foundPlayerServerAddresses[MAX_FOUNDPLAYER_SERVERS][MAX_ADDRESSLENGTH];
- char foundPlayerServerNames[MAX_FOUNDPLAYER_SERVERS][MAX_ADDRESSLENGTH];
- int currentFoundPlayerServer;
- int numFoundPlayerServers;
- int nextFindPlayerRefresh;
-
- int currentCrosshair;
- int startPostGameTime;
- sfxHandle_t newHighScoreSound;
-
- int q3HeadCount;
- char q3HeadNames[MAX_PLAYERMODELS][64];
- qhandle_t q3HeadIcons[MAX_PLAYERMODELS];
- int q3SelectedHead;
-
- int effectsColor;
-
- qboolean inGameLoad;
-
-} uiInfo_t;
-
-extern uiInfo_t uiInfo;
-
-
-extern void UI_Init( void );
-extern void UI_Shutdown( void );
-extern void UI_KeyEvent( int key );
-extern void UI_MouseEvent( int dx, int dy );
-extern void UI_Refresh( int realtime );
-extern qboolean UI_ConsoleCommand( int realTime );
-extern float UI_ClampCvar( float min, float max, float value );
-extern void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname );
-extern void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader );
-extern void UI_FillRect( float x, float y, float width, float height, const float *color );
-extern void UI_DrawRect( float x, float y, float width, float height, const float *color );
-extern void UI_DrawTopBottom(float x, float y, float w, float h);
-extern void UI_DrawSides(float x, float y, float w, float h);
-extern void UI_UpdateScreen( void );
-extern void UI_SetColor( const float *rgba );
-extern void UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t);
-extern void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color );
-extern float UI_ProportionalSizeScale( int style );
-extern void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );
-extern int UI_ProportionalStringWidth( const char* str );
-extern void UI_DrawString( int x, int y, const char* str, int style, vec4_t color );
-extern void UI_DrawChar( int x, int y, int ch, int style, vec4_t color );
-extern qboolean UI_CursorInRect (int x, int y, int width, int height);
-extern void UI_AdjustFrom640( float *x, float *y, float *w, float *h );
-extern void UI_DrawTextBox (int x, int y, int width, int lines);
-extern qboolean UI_IsFullscreen( void );
-extern void UI_SetActiveMenu( uiMenuCommand_t menu );
-extern void UI_PushMenu ( menuframework_s *menu );
-extern void UI_PopMenu (void);
-extern void UI_ForceMenuOff (void);
-extern char *UI_Argv( int arg );
-extern char *UI_Cvar_VariableString( const char *var_name );
-extern void UI_Refresh( int time );
-extern void UI_KeyEvent( int key );
-extern void UI_StartDemoLoop( void );
-extern qboolean m_entersound;
-void UI_LoadBestScores(const char *map, int game);
-extern uiStatic_t uis;
-
-//
-// ui_spLevel.c
-//
-void UI_SPLevelMenu_Cache( void );
-void UI_SPLevelMenu( void );
-void UI_SPLevelMenu_f( void );
-void UI_SPLevelMenu_ReInit( void );
-
-//
-// ui_spArena.c
-//
-void UI_SPArena_Start( const char *arenaInfo );
-
-//
-// ui_spPostgame.c
-//
-void UI_SPPostgameMenu_Cache( void );
-void UI_SPPostgameMenu_f( void );
-
-//
-// ui_spSkill.c
-//
-void UI_SPSkillMenu( const char *arenaInfo );
-void UI_SPSkillMenu_Cache( void );
-
-//
-// ui_syscalls.c
-//
-void trap_Print( const char *string );
-void trap_Error( const char *string );
-int trap_Milliseconds( void );
-void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
-void trap_Cvar_Update( vmCvar_t *vmCvar );
-void trap_Cvar_Set( const char *var_name, const char *value );
-float trap_Cvar_VariableValue( const char *var_name );
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-void trap_Cvar_SetValue( const char *var_name, float value );
-void trap_Cvar_Reset( const char *name );
-void trap_Cvar_Create( const char *var_name, const char *var_value, int flags );
-void trap_Cvar_InfoStringBuffer( int bit, char *buffer, int bufsize );
-int trap_Argc( void );
-void trap_Argv( int n, char *buffer, int bufferLength );
-void trap_Cmd_ExecuteText( int exec_when, const char *text ); // don't use EXEC_NOW!
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
-void trap_FS_Read( void *buffer, int len, fileHandle_t f );
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
-void trap_FS_FCloseFile( fileHandle_t f );
-int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
-qhandle_t trap_R_RegisterModel( const char *name );
-qhandle_t trap_R_RegisterSkin( const char *name );
-qhandle_t trap_R_RegisterShaderNoMip( const char *name );
-void trap_R_ClearScene( void );
-void trap_R_AddRefEntityToScene( const refEntity_t *re );
-void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );
-void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
-void trap_R_RenderScene( const refdef_t *fd );
-void trap_R_SetColor( const float *rgba );
-void trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
-void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );
-void trap_UpdateScreen( void );
-int trap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName );
-void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );
-sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed );
-void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen );
-void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen );
-void trap_Key_SetBinding( int keynum, const char *binding );
-qboolean trap_Key_IsDown( int keynum );
-qboolean trap_Key_GetOverstrikeMode( void );
-void trap_Key_SetOverstrikeMode( qboolean state );
-void trap_Key_ClearStates( void );
-int trap_Key_GetCatcher( void );
-void trap_Key_SetCatcher( int catcher );
-void trap_GetClipboardData( char *buf, int bufsize );
-void trap_GetClientState( uiClientState_t *state );
-void trap_GetGlconfig( glconfig_t *glconfig );
-int trap_GetConfigString( int index, char* buff, int buffsize );
-int trap_LAN_GetServerCount( int source );
-void trap_LAN_GetServerAddressString( int source, int n, char *buf, int buflen );
-void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen );
-int trap_LAN_GetServerPing( int source, int n );
-int trap_LAN_GetPingQueueCount( void );
-void trap_LAN_ClearPing( int n );
-void trap_LAN_GetPing( int n, char *buf, int buflen, int *pingtime );
-void trap_LAN_GetPingInfo( int n, char *buf, int buflen );
-void trap_LAN_LoadCachedServers( void );
-void trap_LAN_SaveCachedServers( void );
-void trap_LAN_MarkServerVisible(int source, int n, qboolean visible);
-int trap_LAN_ServerIsVisible( int source, int n);
-qboolean trap_LAN_UpdateVisiblePings( int source );
-int trap_LAN_AddServer(int source, const char *name, const char *addr);
-void trap_LAN_RemoveServer(int source, const char *addr);
-void trap_LAN_ResetPings(int n);
-int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen );
-int trap_LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 );
-int trap_MemoryRemaining( void );
-void trap_GetCDKey( char *buf, int buflen );
-void trap_SetCDKey( char *buf );
-void trap_R_RegisterFont(const char *pFontname, int pointSize, fontInfo_t *font);
-void trap_S_StopBackgroundTrack( void );
-void trap_S_StartBackgroundTrack( const char *intro, const char *loop);
-int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits);
-e_status trap_CIN_StopCinematic(int handle);
-e_status trap_CIN_RunCinematic (int handle);
-void trap_CIN_DrawCinematic (int handle);
-void trap_CIN_SetExtents (int handle, int x, int y, int w, int h);
-int trap_RealTime(qtime_t *qtime);
-void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset );
-qboolean trap_VerifyCDKey( const char *key, const char *chksum);
-
-void trap_SetPbClStatus( int status );
-
-//
-// ui_addbots.c
-//
-void UI_AddBots_Cache( void );
-void UI_AddBotsMenu( void );
-
-//
-// ui_removebots.c
-//
-void UI_RemoveBots_Cache( void );
-void UI_RemoveBotsMenu( void );
-
-//
-// ui_teamorders.c
-//
-extern void UI_TeamOrdersMenu( void );
-extern void UI_TeamOrdersMenu_f( void );
-extern void UI_TeamOrdersMenu_Cache( void );
-
-//
-// ui_loadconfig.c
-//
-void UI_LoadConfig_Cache( void );
-void UI_LoadConfigMenu( void );
-
-//
-// ui_saveconfig.c
-//
-void UI_SaveConfigMenu_Cache( void );
-void UI_SaveConfigMenu( void );
-
-//
-// ui_display.c
-//
-void UI_DisplayOptionsMenu_Cache( void );
-void UI_DisplayOptionsMenu( void );
-
-//
-// ui_sound.c
-//
-void UI_SoundOptionsMenu_Cache( void );
-void UI_SoundOptionsMenu( void );
-
-//
-// ui_network.c
-//
-void UI_NetworkOptionsMenu_Cache( void );
-void UI_NetworkOptionsMenu( void );
-
-//
-// ui_gameinfo.c
-//
-typedef enum {
- AWARD_ACCURACY,
- AWARD_IMPRESSIVE,
- AWARD_EXCELLENT,
- AWARD_GAUNTLET,
- AWARD_FRAGS,
- AWARD_PERFECT
-} awardType_t;
-
-const char *UI_GetArenaInfoByNumber( int num );
-const char *UI_GetArenaInfoByMap( const char *map );
-const char *UI_GetSpecialArenaInfo( const char *tag );
-int UI_GetNumArenas( void );
-int UI_GetNumSPArenas( void );
-int UI_GetNumSPTiers( void );
-
-char *UI_GetBotInfoByNumber( int num );
-char *UI_GetBotInfoByName( const char *name );
-int UI_GetNumBots( void );
-void UI_LoadBots( void );
-char *UI_GetBotNameByNumber( int num );
-
-void UI_GetBestScore( int level, int *score, int *skill );
-void UI_SetBestScore( int level, int score );
-int UI_TierCompleted( int levelWon );
-qboolean UI_ShowTierVideo( int tier );
-qboolean UI_CanShowTierVideo( int tier );
-int UI_GetCurrentGame( void );
-void UI_NewGame( void );
-void UI_LogAwardData( int award, int data );
-int UI_GetAwardLevel( int award );
-
-void UI_SPUnlock_f( void );
-void UI_SPUnlockMedals_f( void );
-
-void UI_InitGameinfo( void );
-
-//
-// ui_login.c
-//
-void Login_Cache( void );
-void UI_LoginMenu( void );
-
-//
-// ui_signup.c
-//
-void Signup_Cache( void );
-void UI_SignupMenu( void );
-
-//
-// ui_rankstatus.c
-//
-void RankStatus_Cache( void );
-void UI_RankStatusMenu( void );
-
-
-// new ui
-
-#define ASSET_BACKGROUND "uiBackground"
-
-// for tracking sp game info in Team Arena
-typedef struct postGameInfo_s {
- int score;
- int redScore;
- int blueScore;
- int perfects;
- int accuracy;
- int impressives;
- int excellents;
- int defends;
- int assists;
- int gauntlets;
- int captures;
- int time;
- int timeBonus;
- int shutoutBonus;
- int skillBonus;
- int baseScore;
-} postGameInfo_t;
-
-
-
-#endif
diff --git a/game/code/ui/ui_main.c b/game/code/ui/ui_main.c
deleted file mode 100644
index 9ebc80f..0000000
--- a/game/code/ui/ui_main.c
+++ /dev/null
@@ -1,5999 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/*
-=======================================================================
-
-USER INTERFACE MAIN
-
-=======================================================================
-*/
-
-// use this to get a demo build without an explicit demo build, i.e. to get the demo ui files to build
-//#define PRE_RELEASE_TADEMO
-
-#include "ui_local.h"
-
-uiInfo_t uiInfo;
-
-static const char *MonthAbbrev[] = {
- "Jan","Feb","Mar",
- "Apr","May","Jun",
- "Jul","Aug","Sep",
- "Oct","Nov","Dec"
-};
-
-
-static const char *skillLevels[] = {
- "I Can Win",
- "Bring It On",
- "Hurt Me Plenty",
- "Hardcore",
- "Nightmare"
-};
-
-static const int numSkillLevels = sizeof(skillLevels) / sizeof(const char*);
-
-/*
- *These sources are currently hardcoded in the engine.
- *
- *Empty options will not be displayed or circled to.
- */
-static const char *netSources[] = {
- "Local",
- "",
- "Internet",
- "Favorites"
-};
-static const int numNetSources = sizeof(netSources) / sizeof(const char*);
-
-static const serverFilter_t serverFilters[] = {
- {"All", "" },
- {"OpenArena", "" },
- {"Missionpack", "missionpack" },
- {"Rocket Arena", "arena" },
- {"Alliance", "alliance20" },
- {"Weapons Factory Arena", "wfa" },
- {"OSP", "osp" },
-};
-
-static const char *teamArenaGameTypes[] = {
- "FFA",
- "TOURNAMENT",
- "SP",
- "TEAM DM",
- "CTF",
- "1FCTF",
- "OVERLOAD",
- "HARVESTER",
- "ELIMINATION",
- "CTFELIMINATION",
- "LMS",
- "DOUBLE D",
- "DOMINATION"
-};
-
-static int const numTeamArenaGameTypes = sizeof(teamArenaGameTypes) / sizeof(const char*);
-
-
-static const char *teamArenaGameNames[] = {
- "Free For All",
- "Tournament",
- "Single Player",
- "Team Deathmatch",
- "Capture the Flag",
- "One Flag CTF",
- "Overload",
- "Harvester",
- "Elimination",
- "CTF Elimination",
- "Last Man Standing",
- "Double Domination",
- "Domination"
-};
-
-static int const numTeamArenaGameNames = sizeof(teamArenaGameNames) / sizeof(const char*);
-
-
-static const int numServerFilters = sizeof(serverFilters) / sizeof(serverFilter_t);
-
-static const char *sortKeys[] = {
- "Server Name",
- "Map Name",
- "Open Player Spots",
- "Game Type",
- "Ping Time"
-};
-static const int numSortKeys = sizeof(sortKeys) / sizeof(const char*);
-
-static char* netnames[] = {
- "???",
- "UDP",
- NULL
-};
-
-#ifndef MISSIONPACK // bk001206
-static char quake3worldMessage[] = "Visit www.openarena.ws - News, Community, Events, Files";
-#endif
-
-static int gamecodetoui[] = {4,2,3,0,5,1,6};
-static int uitogamecode[] = {4,6,2,3,1,5,7};
-
-
-static void UI_StartServerRefresh(qboolean full);
-static void UI_StopServerRefresh( void );
-static void UI_DoServerRefresh( void );
-static void UI_FeederSelection(float feederID, int index);
-static void UI_BuildServerDisplayList(qboolean force);
-static void UI_BuildServerStatus(qboolean force);
-static void UI_BuildFindPlayerList(qboolean force);
-static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 );
-static int UI_MapCountByGameType(qboolean singlePlayer);
-static int UI_HeadCountByTeam( void );
-static void UI_ParseGameInfo(const char *teamFile);
-static void UI_ParseTeamInfo(const char *teamFile);
-static const char *UI_SelectedMap(int index, int *actual);
-static const char *UI_SelectedHead(int index, int *actual);
-static int UI_GetIndexFromSelection(int actual);
-
-int ProcessNewUI( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 );
-
-/*
-================
-vmMain
-
-This is the only way control passes into the module.
-This must be the very first function compiled into the .qvm file
-================
-*/
-vmCvar_t ui_new;
-vmCvar_t ui_debug;
-vmCvar_t ui_initialized;
-vmCvar_t ui_teamArenaFirstRun;
-
-void _UI_Init( qboolean );
-void _UI_Shutdown( void );
-void _UI_KeyEvent( int key, qboolean down );
-void _UI_MouseEvent( int dx, int dy );
-void _UI_Refresh( int realtime );
-qboolean _UI_IsFullscreen( void );
-intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
- switch ( command ) {
- case UI_GETAPIVERSION:
- return UI_API_VERSION;
-
- case UI_INIT:
- _UI_Init(arg0);
- return 0;
-
- case UI_SHUTDOWN:
- _UI_Shutdown();
- return 0;
-
- case UI_KEY_EVENT:
- _UI_KeyEvent( arg0, arg1 );
- return 0;
-
- case UI_MOUSE_EVENT:
- _UI_MouseEvent( arg0, arg1 );
- return 0;
-
- case UI_REFRESH:
- _UI_Refresh( arg0 );
- return 0;
-
- case UI_IS_FULLSCREEN:
- return _UI_IsFullscreen();
-
- case UI_SET_ACTIVE_MENU:
- _UI_SetActiveMenu( arg0 );
- return 0;
-
- case UI_CONSOLE_COMMAND:
- return UI_ConsoleCommand(arg0);
-
- case UI_DRAW_CONNECT_SCREEN:
- UI_DrawConnectScreen( arg0 );
- return 0;
- case UI_HASUNIQUECDKEY: // mod authors need to observe this
- return qtrue; // bk010117 - change this to qfalse for mods!
-
- }
-
- return -1;
-}
-
-
-
-void AssetCache( void ) {
- int n;
- //if (Assets.textFont == NULL) {
- //}
- //Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND );
- //Com_Printf("Menu Size: %i bytes\n", sizeof(Menus));
- uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
- uiInfo.uiDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
- uiInfo.uiDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
- uiInfo.uiDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
- uiInfo.uiDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
- uiInfo.uiDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
- uiInfo.uiDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
- uiInfo.uiDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
- uiInfo.uiDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
- uiInfo.uiDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
- uiInfo.uiDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
- uiInfo.uiDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
- uiInfo.uiDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
- uiInfo.uiDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
- uiInfo.uiDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
- uiInfo.uiDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
- uiInfo.uiDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
-
- for( n = 0; n < NUM_CROSSHAIRS; n++ ) {
- uiInfo.uiDC.Assets.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a' + n ) );
- }
-
- uiInfo.newHighScoreSound = trap_S_RegisterSound("sound/feedback/voc_newhighscore.wav", qfalse);
-}
-
-void _UI_DrawSides(float x, float y, float w, float h, float size) {
- UI_AdjustFrom640( &x, &y, &w, &h );
- size *= uiInfo.uiDC.xscale;
- trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
- trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
-}
-
-void _UI_DrawTopBottom(float x, float y, float w, float h, float size) {
- UI_AdjustFrom640( &x, &y, &w, &h );
- size *= uiInfo.uiDC.yscale;
- trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
- trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
-}
-/*
-================
-UI_DrawRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void _UI_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
- trap_R_SetColor( color );
-
- _UI_DrawTopBottom(x, y, width, height, size);
- _UI_DrawSides(x, y, width, height, size);
-
- trap_R_SetColor( NULL );
-}
-
-int Text_Width(const char *text, float scale, int limit) {
- int count,len;
- float out;
- glyphInfo_t *glyph;
- float useScale;
- const char *s = text;
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale >= ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- out = 0;
- if (text) {
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- if ( Q_IsColorString(s) ) {
- s += 2;
- continue;
- } else {
- glyph = &font->glyphs[(int)*s];
- out += glyph->xSkip;
- s++;
- count++;
- }
- }
- }
- return out * useScale;
-}
-
-int Text_Height(const char *text, float scale, int limit) {
- int len, count;
- float max;
- glyphInfo_t *glyph;
- float useScale;
- const char *s = text; // bk001206 - unsigned
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale >= ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- max = 0;
- if (text) {
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- if ( Q_IsColorString(s) ) {
- s += 2;
- continue;
- } else {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- if (max < glyph->height) {
- max = glyph->height;
- }
- s++;
- count++;
- }
- }
- }
- return max * useScale;
-}
-
-void Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
- float w, h;
- w = width * scale;
- h = height * scale;
- UI_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
-}
-
-void Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph;
- float useScale;
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale >= ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- if (text) {
- const char *s = text; // bk001206 - unsigned
- trap_R_SetColor( color );
- memcpy(&newColor[0], &color[0], sizeof(vec4_t));
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
- //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- float yadj = useScale * glyph->top;
- if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
- int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
- colorBlack[3] = newColor[3];
- trap_R_SetColor( colorBlack );
- Text_PaintChar(x + ofs, y - yadj + ofs,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- trap_R_SetColor( newColor );
- colorBlack[3] = 1.0;
- }
- Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
-
- x += (glyph->xSkip * useScale) + adjust;
- s++;
- count++;
- }
- }
- trap_R_SetColor( NULL );
- }
-}
-
-void Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph, *glyph2;
- float yadj;
- float useScale;
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale >= ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- if (text) {
- const char *s = text; // bk001206 - unsigned
- trap_R_SetColor( color );
- memcpy(&newColor[0], &color[0], sizeof(vec4_t));
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- glyph2 = &font->glyphs[ (int) cursor]; // bk001206 - possible signed char
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
- //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- yadj = useScale * glyph->top;
- if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
- int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
- colorBlack[3] = newColor[3];
- trap_R_SetColor( colorBlack );
- Text_PaintChar(x + ofs, y - yadj + ofs,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- colorBlack[3] = 1.0;
- trap_R_SetColor( newColor );
- }
- Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
-
- yadj = useScale * glyph2->top;
- if (count == cursorPos && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
- Text_PaintChar(x, y - yadj,
- glyph2->imageWidth,
- glyph2->imageHeight,
- useScale,
- glyph2->s,
- glyph2->t,
- glyph2->s2,
- glyph2->t2,
- glyph2->glyph);
- }
-
- x += (glyph->xSkip * useScale);
- s++;
- count++;
- }
- }
- // need to paint cursor at end of text
- if (cursorPos == len && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
- yadj = useScale * glyph2->top;
- Text_PaintChar(x, y - yadj,
- glyph2->imageWidth,
- glyph2->imageHeight,
- useScale,
- glyph2->s,
- glyph2->t,
- glyph2->s2,
- glyph2->t2,
- glyph2->glyph);
-
- }
-
- trap_R_SetColor( NULL );
- }
-}
-
-
-static void Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph;
- if (text) {
- const char *s = text; // bk001206 - unsigned
- float max = *maxX;
- float useScale;
- fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
- if (scale <= ui_smallFont.value) {
- font = &uiInfo.uiDC.Assets.smallFont;
- } else if (scale > ui_bigFont.value) {
- font = &uiInfo.uiDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- trap_R_SetColor( color );
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- float yadj = useScale * glyph->top;
- if (Text_Width(s, useScale, 1) + x > max) {
- *maxX = 0;
- break;
- }
- Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- x += (glyph->xSkip * useScale) + adjust;
- *maxX = x;
- count++;
- s++;
- }
- }
- trap_R_SetColor( NULL );
- }
-
-}
-
-
-void UI_ShowPostGame(qboolean newHigh) {
- trap_Cvar_Set ("cg_cameraOrbit", "0");
- trap_Cvar_Set("cg_thirdPerson", "0");
- uiInfo.soundHighScore = newHigh;
- _UI_SetActiveMenu(UIMENU_POSTGAME);
-}
-/*
-=================
-_UI_Refresh
-=================
-*/
-
-void UI_DrawCenteredPic(qhandle_t image, int w, int h) {
- int x, y;
- x = (SCREEN_WIDTH - w) / 2;
- y = (SCREEN_HEIGHT - h) / 2;
- UI_DrawHandlePic(x, y, w, h, image);
-}
-
-int frameCount = 0;
-int startTime;
-
-#define UI_FPS_FRAMES 4
-void _UI_Refresh( int realtime )
-{
- static int index;
- static int previousTimes[UI_FPS_FRAMES];
-
- //if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
- // return;
- //}
-
- uiInfo.uiDC.frameTime = realtime - uiInfo.uiDC.realTime;
- uiInfo.uiDC.realTime = realtime;
-
- previousTimes[index % UI_FPS_FRAMES] = uiInfo.uiDC.frameTime;
- index++;
- if ( index > UI_FPS_FRAMES ) {
- int i, total;
- // average multiple frames together to smooth changes out a bit
- total = 0;
- for ( i = 0 ; i < UI_FPS_FRAMES ; i++ ) {
- total += previousTimes[i];
- }
- if ( !total ) {
- total = 1;
- }
- uiInfo.uiDC.FPS = 1000 * UI_FPS_FRAMES / total;
- }
-
-
-
- UI_UpdateCvars();
-
- if (Menu_Count() > 0) {
- // paint all the menus
- Menu_PaintAll();
- // refresh server browser list
- UI_DoServerRefresh();
- // refresh server status
- UI_BuildServerStatus(qfalse);
- // refresh find player list
- UI_BuildFindPlayerList(qfalse);
- }
-
- // draw cursor
- UI_SetColor( NULL );
- if (Menu_Count() > 0) {
- UI_DrawHandlePic( uiInfo.uiDC.cursorx-16, uiInfo.uiDC.cursory-16, 32, 32, uiInfo.uiDC.Assets.cursor);
- }
-
-#ifndef NDEBUG
- if (uiInfo.uiDC.debug)
- {
- // cursor coordinates
- //FIXME
- //UI_DrawString( 0, 0, va("(%d,%d)",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed );
- }
-#endif
-
-}
-
-/*
-=================
-_UI_Shutdown
-=================
-*/
-void _UI_Shutdown( void ) {
- trap_LAN_SaveCachedServers();
-}
-
-char *defaultMenu = NULL;
-
-char *GetMenuBuffer(const char *filename) {
- int len;
- fileHandle_t f;
- static char buf[MAX_MENUFILE];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
- return defaultMenu;
- }
- if ( len >= MAX_MENUFILE ) {
- trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", filename, len, MAX_MENUFILE ) );
- trap_FS_FCloseFile( f );
- return defaultMenu;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
- //COM_Compress(buf);
- return buf;
-
-}
-
-qboolean Asset_Parse(int handle) {
- pc_token_t token;
- const char *tempStr;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (Q_stricmp(token.string, "{") != 0) {
- return qfalse;
- }
-
- while ( 1 ) {
-
- memset(&token, 0, sizeof(pc_token_t));
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
-
- if (Q_stricmp(token.string, "}") == 0) {
- return qtrue;
- }
-
- // font
- if (Q_stricmp(token.string, "font") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
- return qfalse;
- }
- trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.textFont);
- uiInfo.uiDC.Assets.fontRegistered = qtrue;
- continue;
- }
-
- if (Q_stricmp(token.string, "smallFont") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
- return qfalse;
- }
- trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.smallFont);
- continue;
- }
-
- if (Q_stricmp(token.string, "bigFont") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
- return qfalse;
- }
- trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.bigFont);
- continue;
- }
-
-
- // gradientbar
- if (Q_stricmp(token.string, "gradientbar") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
- continue;
- }
-
- // enterMenuSound
- if (Q_stricmp(token.string, "menuEnterSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // exitMenuSound
- if (Q_stricmp(token.string, "menuExitSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // itemFocusSound
- if (Q_stricmp(token.string, "itemFocusSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // menuBuzzSound
- if (Q_stricmp(token.string, "menuBuzzSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- if (Q_stricmp(token.string, "cursor") == 0) {
- if (!PC_String_Parse(handle, &uiInfo.uiDC.Assets.cursorStr)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.cursor = trap_R_RegisterShaderNoMip( uiInfo.uiDC.Assets.cursorStr);
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeClamp") == 0) {
- if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeClamp)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeCycle") == 0) {
- if (!PC_Int_Parse(handle, &uiInfo.uiDC.Assets.fadeCycle)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeAmount") == 0) {
- if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeAmount)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowX") == 0) {
- if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowX)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowY") == 0) {
- if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowY)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowColor") == 0) {
- if (!PC_Color_Parse(handle, &uiInfo.uiDC.Assets.shadowColor)) {
- return qfalse;
- }
- uiInfo.uiDC.Assets.shadowFadeClamp = uiInfo.uiDC.Assets.shadowColor[3];
- continue;
- }
-
- }
- return qfalse;
-}
-
-void Font_Report( void ) {
- int i;
- Com_Printf("Font Info\n");
- Com_Printf("=========\n");
- for ( i = 32; i < 96; i++) {
- Com_Printf("Glyph handle %i: %i\n", i, uiInfo.uiDC.Assets.textFont.glyphs[i].glyph);
- }
-}
-
-void UI_Report( void ) {
- String_Report();
- //Font_Report();
-
-}
-
-void UI_ParseMenu(const char *menuFile) {
- int handle;
- pc_token_t token;
-
- Com_Printf("Parsing menu file:%s\n", menuFile);
-
- handle = trap_PC_LoadSource(menuFile);
- if (!handle) {
- return;
- }
-
- while ( 1 ) {
- memset(&token, 0, sizeof(pc_token_t));
- if (!trap_PC_ReadToken( handle, &token )) {
- break;
- }
-
- //if ( Q_stricmp( token, "{" ) ) {
- // Com_Printf( "Missing { in menu file\n" );
- // break;
- //}
-
- //if ( menuCount == MAX_MENUS ) {
- // Com_Printf( "Too many menus!\n" );
- // break;
- //}
-
- if ( token.string[0] == '}' ) {
- break;
- }
-
- if (Q_stricmp(token.string, "assetGlobalDef") == 0) {
- if (Asset_Parse(handle)) {
- continue;
- } else {
- break;
- }
- }
-
- if (Q_stricmp(token.string, "menudef") == 0) {
- // start a new menu
- Menu_New(handle);
- }
- }
- trap_PC_FreeSource(handle);
-}
-
-qboolean Load_Menu(int handle) {
- pc_token_t token;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (token.string[0] != '{') {
- return qfalse;
- }
-
- while ( 1 ) {
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
-
- if ( token.string[0] == 0 ) {
- return qfalse;
- }
-
- if ( token.string[0] == '}' ) {
- return qtrue;
- }
-
- UI_ParseMenu(token.string);
- }
- return qfalse;
-}
-
-void UI_LoadMenus(const char *menuFile, qboolean reset) {
- pc_token_t token;
- int handle;
- int start;
-
- start = trap_Milliseconds();
-
- handle = trap_PC_LoadSource( menuFile );
- if (!handle) {
- trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );
- handle = trap_PC_LoadSource( "ui/menus.txt" );
- if (!handle) {
- trap_Error( va( S_COLOR_RED "default menu file not found: ui/menus.txt, unable to continue!\n") );
- }
- }
-
- ui_new.integer = 1;
-
- if (reset) {
- Menu_Reset();
- }
-
- while ( 1 ) {
- if (!trap_PC_ReadToken(handle, &token))
- break;
- if( token.string[0] == 0 || token.string[0] == '}') {
- break;
- }
-
- if ( token.string[0] == '}' ) {
- break;
- }
-
- if (Q_stricmp(token.string, "loadmenu") == 0) {
- if (Load_Menu(handle)) {
- continue;
- } else {
- break;
- }
- }
- }
-
- Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start);
-
- trap_PC_FreeSource( handle );
-}
-
-void UI_Load(void) {
- char lastName[1024];
- menuDef_t *menu = Menu_GetFocused();
- char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
- if (menu && menu->window.name) {
- strcpy(lastName, menu->window.name);
- }
- if (menuSet == NULL || menuSet[0] == '\0') {
- menuSet = "ui/menus.txt";
- }
-
- String_Init();
-
-#ifdef PRE_RELEASE_TADEMO
- UI_ParseGameInfo("demogameinfo.txt");
-#else
- UI_ParseGameInfo("gameinfo.txt");
- UI_LoadArenas();
-#endif
-
- UI_LoadMenus(menuSet, qtrue);
- Menus_CloseAll();
- Menus_ActivateByName(lastName);
-
-}
-
-static const char *handicapValues[] = {"None","95","90","85","80","75","70","65","60","55","50","45","40","35","30","25","20","15","10","5",NULL};
-#ifndef MISSIONPACK // bk001206
-static int numHandicaps = sizeof(handicapValues) / sizeof(const char*);
-#endif
-
-static void UI_DrawHandicap(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i, h;
-
- h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
- i = 20 - h / 5;
-
- Text_Paint(rect->x, rect->y, scale, color, handicapValues[i], 0, 0, textStyle);
-}
-
-static void UI_DrawClanName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_teamName"), 0, 0, textStyle);
-}
-
-
-static void UI_SetCapFragLimits(qboolean uiVars) {
- int cap = 5;
- int frag = 10;
- if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_OBELISK) {
- cap = 4;
- } else if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_HARVESTER) {
- cap = 15;
- }
- if (uiVars) {
- trap_Cvar_Set("ui_captureLimit", va("%d", cap));
- trap_Cvar_Set("ui_fragLimit", va("%d", frag));
- } else {
- trap_Cvar_Set("capturelimit", va("%d", cap));
- trap_Cvar_Set("fraglimit", va("%d", frag));
- }
-}
-// ui_gameType assumes gametype 0 is -1 ALL and will not show
-static void UI_DrawGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_gameType.integer].gameType, 0, 0, textStyle);
-}
-
-static void UI_DrawNetGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (ui_netGameType.integer < 0 || ui_netGameType.integer > uiInfo.numGameTypes) {
- trap_Cvar_Set("ui_netGameType", "0");
- trap_Cvar_Set("ui_actualNetGameType", "0");
- }
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_netGameType.integer].gameType , 0, 0, textStyle);
-}
-
-static void UI_DrawJoinGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (ui_joinGameType.integer < 0 || ui_joinGameType.integer > uiInfo.numJoinGameTypes) {
- trap_Cvar_Set("ui_joinGameType", "0");
- }
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.joinGameTypes[ui_joinGameType.integer].gameType , 0, 0, textStyle);
-}
-
-
-
-static int UI_TeamIndexFromName(const char *name) {
- int i;
-
- if (name && *name) {
- for (i = 0; i < uiInfo.teamCount; i++) {
- if (Q_stricmp(name, uiInfo.teamList[i].teamName) == 0) {
- return i;
- }
- }
- }
-
- return 0;
-
-}
-
-static void UI_DrawClanLogo(rectDef_t *rect, float scale, vec4_t color) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (i >= 0 && i < uiInfo.teamCount) {
- trap_R_SetColor( color );
-
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
- trap_R_SetColor(NULL);
- }
-}
-
-static void UI_DrawClanCinematic(rectDef_t *rect, float scale, vec4_t color) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (i >= 0 && i < uiInfo.teamCount) {
-
- if (uiInfo.teamList[i].cinematic >= -2) {
- if (uiInfo.teamList[i].cinematic == -1) {
- uiInfo.teamList[i].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.teamList[i].imageName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- }
- if (uiInfo.teamList[i].cinematic >= 0) {
- trap_CIN_RunCinematic(uiInfo.teamList[i].cinematic);
- trap_CIN_SetExtents(uiInfo.teamList[i].cinematic, rect->x, rect->y, rect->w, rect->h);
- trap_CIN_DrawCinematic(uiInfo.teamList[i].cinematic);
- } else {
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal);
- trap_R_SetColor(NULL);
- uiInfo.teamList[i].cinematic = -2;
- }
- } else {
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
- trap_R_SetColor(NULL);
- }
- }
-
-}
-
-static void UI_DrawPreviewCinematic(rectDef_t *rect, float scale, vec4_t color) {
- if (uiInfo.previewMovie > -2) {
- uiInfo.previewMovie = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.movieList[uiInfo.movieIndex]), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- if (uiInfo.previewMovie >= 0) {
- trap_CIN_RunCinematic(uiInfo.previewMovie);
- trap_CIN_SetExtents(uiInfo.previewMovie, rect->x, rect->y, rect->w, rect->h);
- trap_CIN_DrawCinematic(uiInfo.previewMovie);
- } else {
- uiInfo.previewMovie = -2;
- }
- }
-
-}
-
-
-
-static void UI_DrawSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i;
- i = trap_Cvar_VariableValue( "g_spSkill" );
- if (i < 1 || i > numSkillLevels) {
- i = 1;
- }
- Text_Paint(rect->x, rect->y, scale, color, skillLevels[i-1],0, 0, textStyle);
-}
-
-
-static void UI_DrawTeamName(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int textStyle) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
- if (i >= 0 && i < uiInfo.teamCount) {
- Text_Paint(rect->x, rect->y, scale, color, va("%s: %s", (blue) ? "Blue" : "Red", uiInfo.teamList[i].teamName),0, 0, textStyle);
- }
-}
-
-static void UI_DrawTeamMember(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int num, int textStyle) {
- // 0 - None
- // 1 - Human
- // 2..NumCharacters - Bot
- int value = trap_Cvar_VariableValue(va(blue ? "ui_blueteam%i" : "ui_redteam%i", num));
- const char *text;
- if (value <= 0) {
- text = "Closed";
- } else if (value == 1) {
- text = "Human";
- } else {
- value -= 2;
-
- if (ui_actualNetGameType.integer >= GT_TEAM) {
- if (value >= uiInfo.characterCount) {
- value = 0;
- }
- text = uiInfo.characterList[value].name;
- } else {
- if (value >= UI_GetNumBots()) {
- value = 0;
- }
- text = UI_GetBotNameByNumber(value);
- }
- }
- Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
-}
-
-static void UI_DrawEffects(rectDef_t *rect, float scale, vec4_t color) {
- UI_DrawHandlePic( rect->x, rect->y - 14, 128, 8, uiInfo.uiDC.Assets.fxBasePic );
- UI_DrawHandlePic( rect->x + uiInfo.effectsColor * 16 + 8, rect->y - 16, 16, 12, uiInfo.uiDC.Assets.fxPic[uiInfo.effectsColor] );
-}
-
-static void UI_DrawMapPreview(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
- int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
- if (map < 0 || map > uiInfo.mapCount) {
- if (net) {
- ui_currentNetMap.integer = 0;
- trap_Cvar_Set("ui_currentNetMap", "0");
- } else {
- ui_currentMap.integer = 0;
- trap_Cvar_Set("ui_currentMap", "0");
- }
- map = 0;
- }
-
- if (uiInfo.mapList[map].levelShot == -1) {
- uiInfo.mapList[map].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[map].imageName);
- }
-
- if (uiInfo.mapList[map].levelShot > 0) {
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.mapList[map].levelShot);
- } else {
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("menu/art/unknownmap"));
- }
-}
-
-
-static void UI_DrawMapTimeToBeat(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int minutes, seconds, time;
- if (ui_currentMap.integer < 0 || ui_currentMap.integer > uiInfo.mapCount) {
- ui_currentMap.integer = 0;
- trap_Cvar_Set("ui_currentMap", "0");
- }
-
- time = uiInfo.mapList[ui_currentMap.integer].timeToBeat[uiInfo.gameTypes[ui_gameType.integer].gtEnum];
-
- minutes = time / 60;
- seconds = time % 60;
-
- Text_Paint(rect->x, rect->y, scale, color, va("%02i:%02i", minutes, seconds), 0, 0, textStyle);
-}
-
-
-
-static void UI_DrawMapCinematic(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
-
- int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
- if (map < 0 || map > uiInfo.mapCount) {
- if (net) {
- ui_currentNetMap.integer = 0;
- trap_Cvar_Set("ui_currentNetMap", "0");
- } else {
- ui_currentMap.integer = 0;
- trap_Cvar_Set("ui_currentMap", "0");
- }
- map = 0;
- }
-
- if (uiInfo.mapList[map].cinematic >= -1) {
- if (uiInfo.mapList[map].cinematic == -1) {
- uiInfo.mapList[map].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[map].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- }
- if (uiInfo.mapList[map].cinematic >= 0) {
- trap_CIN_RunCinematic(uiInfo.mapList[map].cinematic);
- trap_CIN_SetExtents(uiInfo.mapList[map].cinematic, rect->x, rect->y, rect->w, rect->h);
- trap_CIN_DrawCinematic(uiInfo.mapList[map].cinematic);
- } else {
- uiInfo.mapList[map].cinematic = -2;
- }
- } else {
- UI_DrawMapPreview(rect, scale, color, net);
- }
-}
-
-
-
-static qboolean updateModel = qtrue;
-static qboolean q3Model = qfalse;
-
-static void UI_DrawPlayerModel(rectDef_t *rect) {
- static playerInfo_t info;
- char model[MAX_QPATH];
- char team[256];
- char head[256];
- vec3_t viewangles;
- vec3_t moveangles;
-
- if (trap_Cvar_VariableValue("ui_Q3Model")) {
- strcpy(model, UI_Cvar_VariableString("model"));
- strcpy(head, UI_Cvar_VariableString("headmodel"));
- if (!q3Model) {
- q3Model = qtrue;
- updateModel = qtrue;
- }
- team[0] = '\0';
- } else {
-
- strcpy(team, UI_Cvar_VariableString("ui_teamName"));
- strcpy(model, UI_Cvar_VariableString("team_model"));
- strcpy(head, UI_Cvar_VariableString("team_headmodel"));
- if (q3Model) {
- q3Model = qfalse;
- updateModel = qtrue;
- }
- }
- if (updateModel) {
- memset( &info, 0, sizeof(playerInfo_t) );
- viewangles[YAW] = 180 - 10;
- viewangles[PITCH] = 0;
- viewangles[ROLL] = 0;
- VectorClear( moveangles );
- UI_PlayerInfo_SetModel( &info, model, head, team);
- UI_PlayerInfo_SetInfo( &info, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
-// UI_RegisterClientModelname( &info, model, head, team);
- updateModel = qfalse;
- }
-
- UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info, uiInfo.uiDC.realTime / 2);
-
-}
-
-static void UI_DrawNetSource(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (ui_netSource.integer < 0 || ui_netSource.integer > numNetSources) {
- ui_netSource.integer = 0;
- }
- Text_Paint(rect->x, rect->y, scale, color, va("Source: %s", netSources[ui_netSource.integer]), 0, 0, textStyle);
-}
-
-static void UI_DrawNetMapPreview(rectDef_t *rect, float scale, vec4_t color) {
-
- if (uiInfo.serverStatus.currentServerPreview > 0) {
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.serverStatus.currentServerPreview);
- } else {
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("menu/art/unknownmap"));
- }
-}
-
-static void UI_DrawNetMapCinematic(rectDef_t *rect, float scale, vec4_t color) {
- if (ui_currentNetMap.integer < 0 || ui_currentNetMap.integer > uiInfo.mapCount) {
- ui_currentNetMap.integer = 0;
- trap_Cvar_Set("ui_currentNetMap", "0");
- }
-
- if (uiInfo.serverStatus.currentServerCinematic >= 0) {
- trap_CIN_RunCinematic(uiInfo.serverStatus.currentServerCinematic);
- trap_CIN_SetExtents(uiInfo.serverStatus.currentServerCinematic, rect->x, rect->y, rect->w, rect->h);
- trap_CIN_DrawCinematic(uiInfo.serverStatus.currentServerCinematic);
- } else {
- UI_DrawNetMapPreview(rect, scale, color);
- }
-}
-
-
-
-static void UI_DrawNetFilter(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
- ui_serverFilterType.integer = 0;
- }
- Text_Paint(rect->x, rect->y, scale, color, va("Filter: %s", serverFilters[ui_serverFilterType.integer].description), 0, 0, textStyle);
-}
-
-
-static void UI_DrawTier(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i;
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= uiInfo.tierCount) {
- i = 0;
- }
- Text_Paint(rect->x, rect->y, scale, color, va("Tier: %s", uiInfo.tierList[i].tierName),0, 0, textStyle);
-}
-
-static void UI_DrawTierMap(rectDef_t *rect, int index) {
- int i;
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= uiInfo.tierCount) {
- i = 0;
- }
-
- if (uiInfo.tierList[i].mapHandles[index] == -1) {
- uiInfo.tierList[i].mapHandles[index] = trap_R_RegisterShaderNoMip(va("levelshots/%s", uiInfo.tierList[i].maps[index]));
- }
-
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.tierList[i].mapHandles[index]);
-}
-
-static const char *UI_EnglishMapName(const char *map) {
- int i;
- for (i = 0; i < uiInfo.mapCount; i++) {
- if (Q_stricmp(map, uiInfo.mapList[i].mapLoadName) == 0) {
- return uiInfo.mapList[i].mapName;
- }
- }
- return "";
-}
-
-static void UI_DrawTierMapName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i, j;
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= uiInfo.tierCount) {
- i = 0;
- }
- j = trap_Cvar_VariableValue("ui_currentMap");
- if (j < 0 || j > MAPS_PER_TIER) {
- j = 0;
- }
-
- Text_Paint(rect->x, rect->y, scale, color, UI_EnglishMapName(uiInfo.tierList[i].maps[j]), 0, 0, textStyle);
-}
-
-static void UI_DrawTierGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int i, j;
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= uiInfo.tierCount) {
- i = 0;
- }
- j = trap_Cvar_VariableValue("ui_currentMap");
- if (j < 0 || j > MAPS_PER_TIER) {
- j = 0;
- }
-
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[uiInfo.tierList[i].gameTypes[j]].gameType , 0, 0, textStyle);
-}
-
-
-#ifndef MISSIONPACK // bk001206
-static const char *UI_OpponentLeaderName(void) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- return uiInfo.teamList[i].teamMembers[0];
-}
-#endif
-
-static const char *UI_AIFromName(const char *name) {
- int j;
- for (j = 0; j < uiInfo.aliasCount; j++) {
- if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
- return uiInfo.aliasList[j].ai;
- }
- }
- return "sergei";
-}
-
-#ifndef MISSIONPACK // bk001206
-static const int UI_AIIndex(const char *name) {
- int j;
- for (j = 0; j < uiInfo.characterCount; j++) {
- if (Q_stricmp(name, uiInfo.characterList[j].name) == 0) {
- return j;
- }
- }
- return 0;
-}
-#endif
-
-#ifndef MISSIONPACK // bk001206
-static const int UI_AIIndexFromName(const char *name) {
- int j;
- for (j = 0; j < uiInfo.aliasCount; j++) {
- if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
- return UI_AIIndex(uiInfo.aliasList[j].ai);
- }
- }
- return 0;
-}
-#endif
-
-
-#ifndef MISSIONPACK // bk001206
-static const char *UI_OpponentLeaderHead(void) {
- const char *leader = UI_OpponentLeaderName();
- return UI_AIFromName(leader);
-}
-#endif
-
-#ifndef MISSIONPACK // bk001206
-static const char *UI_OpponentLeaderModel(void) {
- int i;
- const char *head = UI_OpponentLeaderHead();
- for (i = 0; i < uiInfo.characterCount; i++) {
- if (Q_stricmp(head, uiInfo.characterList[i].name) == 0) {
- return uiInfo.characterList[i].base;
- }
- }
- return "sergei";
-}
-#endif
-
-
-static qboolean updateOpponentModel = qtrue;
-static void UI_DrawOpponent(rectDef_t *rect) {
- static playerInfo_t info2;
- char model[MAX_QPATH];
- char headmodel[MAX_QPATH];
- char team[256];
- vec3_t viewangles;
- vec3_t moveangles;
-
- if (updateOpponentModel) {
-
- strcpy(model, UI_Cvar_VariableString("ui_opponentModel"));
- strcpy(headmodel, UI_Cvar_VariableString("ui_opponentModel"));
- team[0] = '\0';
-
- memset( &info2, 0, sizeof(playerInfo_t) );
- viewangles[YAW] = 180 - 10;
- viewangles[PITCH] = 0;
- viewangles[ROLL] = 0;
- VectorClear( moveangles );
- UI_PlayerInfo_SetModel( &info2, model, headmodel, "");
- UI_PlayerInfo_SetInfo( &info2, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
- UI_RegisterClientModelname( &info2, model, headmodel, team);
- updateOpponentModel = qfalse;
- }
-
- UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info2, uiInfo.uiDC.realTime / 2);
-
-}
-
-static void UI_NextOpponent( void ) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- i++;
- if (i >= uiInfo.teamCount) {
- i = 0;
- }
- if (i == j) {
- i++;
- if ( i >= uiInfo.teamCount) {
- i = 0;
- }
- }
- trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
-}
-
-static void UI_PriorOpponent( void ) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- i--;
- if (i < 0) {
- i = uiInfo.teamCount - 1;
- }
- if (i == j) {
- i--;
- if ( i < 0) {
- i = uiInfo.teamCount - 1;
- }
- }
- trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
-}
-
-static void UI_DrawPlayerLogo(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
-
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
- trap_R_SetColor( NULL );
-}
-
-static void UI_DrawPlayerLogoMetal(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
- trap_R_SetColor( NULL );
-}
-
-static void UI_DrawPlayerLogoName(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
- trap_R_SetColor( NULL );
-}
-
-static void UI_DrawOpponentLogo(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
- trap_R_SetColor( NULL );
-}
-
-static void UI_DrawOpponentLogoMetal(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
- trap_R_SetColor( NULL );
-}
-
-static void UI_DrawOpponentLogoName(rectDef_t *rect, vec3_t color) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- if (uiInfo.teamList[i].teamIcon == -1) {
- uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
- uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
- uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
- }
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
- trap_R_SetColor( NULL );
-}
-
-static void UI_DrawAllMapsSelection(rectDef_t *rect, float scale, vec4_t color, int textStyle, qboolean net) {
- int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
- if (map >= 0 && map < uiInfo.mapCount) {
- Text_Paint(rect->x, rect->y, scale, color, uiInfo.mapList[map].mapName, 0, 0, textStyle);
- }
-}
-
-static void UI_DrawOpponentName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_opponentName"), 0, 0, textStyle);
-}
-
-
-static int UI_OwnerDrawWidth(int ownerDraw, float scale) {
- int i, h, value;
- const char *text;
- const char *s = NULL;
-
- switch (ownerDraw) {
- case UI_HANDICAP:
- h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
- i = 20 - h / 5;
- s = handicapValues[i];
- break;
- case UI_CLANNAME:
- s = UI_Cvar_VariableString("ui_teamName");
- break;
- case UI_GAMETYPE:
- s = uiInfo.gameTypes[ui_gameType.integer].gameType;
- break;
- case UI_SKILL:
- i = trap_Cvar_VariableValue( "g_spSkill" );
- if (i < 1 || i > numSkillLevels) {
- i = 1;
- }
- s = skillLevels[i-1];
- break;
- case UI_BLUETEAMNAME:
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_blueTeam"));
- if (i >= 0 && i < uiInfo.teamCount) {
- s = va("%s: %s", "Blue", uiInfo.teamList[i].teamName);
- }
- break;
- case UI_REDTEAMNAME:
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_redTeam"));
- if (i >= 0 && i < uiInfo.teamCount) {
- s = va("%s: %s", "Red", uiInfo.teamList[i].teamName);
- }
- break;
- case UI_BLUETEAM1:
- case UI_BLUETEAM2:
- case UI_BLUETEAM3:
- case UI_BLUETEAM4:
- case UI_BLUETEAM5:
- value = trap_Cvar_VariableValue(va("ui_blueteam%i", ownerDraw-UI_BLUETEAM1 + 1));
- if (value <= 0) {
- text = "Closed";
- } else if (value == 1) {
- text = "Human";
- } else {
- value -= 2;
- if (value >= uiInfo.aliasCount) {
- value = 0;
- }
- text = uiInfo.aliasList[value].name;
- }
- s = va("%i. %s", ownerDraw-UI_BLUETEAM1 + 1, text);
- break;
- case UI_REDTEAM1:
- case UI_REDTEAM2:
- case UI_REDTEAM3:
- case UI_REDTEAM4:
- case UI_REDTEAM5:
- value = trap_Cvar_VariableValue(va("ui_redteam%i", ownerDraw-UI_REDTEAM1 + 1));
- if (value <= 0) {
- text = "Closed";
- } else if (value == 1) {
- text = "Human";
- } else {
- value -= 2;
- if (value >= uiInfo.aliasCount) {
- value = 0;
- }
- text = uiInfo.aliasList[value].name;
- }
- s = va("%i. %s", ownerDraw-UI_REDTEAM1 + 1, text);
- break;
- case UI_NETSOURCE:
- if (ui_netSource.integer < 0 || ui_netSource.integer > uiInfo.numJoinGameTypes) {
- ui_netSource.integer = 0;
- }
- s = va("Source: %s", netSources[ui_netSource.integer]);
- break;
- case UI_NETFILTER:
- if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
- ui_serverFilterType.integer = 0;
- }
- s = va("Filter: %s", serverFilters[ui_serverFilterType.integer].description );
- break;
- case UI_TIER:
- break;
- case UI_TIER_MAPNAME:
- break;
- case UI_TIER_GAMETYPE:
- break;
- case UI_ALLMAPS_SELECTION:
- break;
- case UI_OPPONENT_NAME:
- break;
- case UI_KEYBINDSTATUS:
- if (Display_KeyBindPending()) {
- s = "Waiting for new key... Press ESCAPE to cancel";
- } else {
- s = "Press ENTER or CLICK to change, Press BACKSPACE to clear";
- }
- break;
- case UI_SERVERREFRESHDATE:
- s = UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer));
- break;
- default:
- break;
- }
-
- if (s) {
- return Text_Width(s, scale, 0);
- }
- return 0;
-}
-
-static void UI_DrawBotName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- int value = uiInfo.botIndex;
- int game = trap_Cvar_VariableValue("g_gametype");
- const char *text = "";
- if (game >= GT_TEAM && !GT_LMS ) {
- if (value >= uiInfo.characterCount) {
- value = 0;
- }
- text = uiInfo.characterList[value].name;
- } else {
- if (value >= UI_GetNumBots()) {
- value = 0;
- }
- text = UI_GetBotNameByNumber(value);
- }
- Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
-}
-
-static void UI_DrawBotSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (uiInfo.skillIndex >= 0 && uiInfo.skillIndex < numSkillLevels) {
- Text_Paint(rect->x, rect->y, scale, color, skillLevels[uiInfo.skillIndex], 0, 0, textStyle);
- }
-}
-
-static void UI_DrawRedBlue(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- Text_Paint(rect->x, rect->y, scale, color, (uiInfo.redBlue == 0) ? "Red" : "Blue", 0, 0, textStyle);
-}
-
-static void UI_DrawCrosshair(rectDef_t *rect, float scale, vec4_t color) {
- trap_R_SetColor( color );
- if (uiInfo.currentCrosshair < 0 || uiInfo.currentCrosshair >= NUM_CROSSHAIRS) {
- uiInfo.currentCrosshair = 0;
- }
- UI_DrawHandlePic( rect->x, rect->y - rect->h, rect->w, rect->h, uiInfo.uiDC.Assets.crosshairShader[uiInfo.currentCrosshair]);
- trap_R_SetColor( NULL );
-}
-
-/*
-===============
-UI_BuildPlayerList
-===============
-*/
-static void UI_BuildPlayerList( void ) {
- uiClientState_t cs;
- int n, count, team, team2, playerTeamNumber;
- char info[MAX_INFO_STRING];
-
- trap_GetClientState( &cs );
- trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );
- uiInfo.playerNumber = cs.clientNum;
- uiInfo.teamLeader = atoi(Info_ValueForKey(info, "tl"));
- team = atoi(Info_ValueForKey(info, "t"));
- trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
- count = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
- uiInfo.playerCount = 0;
- uiInfo.myTeamCount = 0;
- playerTeamNumber = 0;
- for( n = 0; n < count; n++ ) {
- trap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING );
-
- if (info[0]) {
- Q_strncpyz( uiInfo.playerNames[uiInfo.playerCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
- Q_CleanStr( uiInfo.playerNames[uiInfo.playerCount] );
- uiInfo.playerCount++;
- team2 = atoi(Info_ValueForKey(info, "t"));
- if (team2 == team) {
- Q_strncpyz( uiInfo.teamNames[uiInfo.myTeamCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
- Q_CleanStr( uiInfo.teamNames[uiInfo.myTeamCount] );
- uiInfo.teamClientNums[uiInfo.myTeamCount] = n;
- if (uiInfo.playerNumber == n) {
- playerTeamNumber = uiInfo.myTeamCount;
- }
- uiInfo.myTeamCount++;
- }
- }
- }
-
- if (!uiInfo.teamLeader) {
- trap_Cvar_Set("cg_selectedPlayer", va("%d", playerTeamNumber));
- }
-
- n = trap_Cvar_VariableValue("cg_selectedPlayer");
- if (n < 0 || n > uiInfo.myTeamCount) {
- n = 0;
- }
- if (n < uiInfo.myTeamCount) {
- trap_Cvar_Set("cg_selectedPlayerName", uiInfo.teamNames[n]);
- }
-}
-
-
-static void UI_DrawSelectedPlayer(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
- uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
- UI_BuildPlayerList();
- }
- Text_Paint(rect->x, rect->y, scale, color, (uiInfo.teamLeader) ? UI_Cvar_VariableString("cg_selectedPlayerName") : UI_Cvar_VariableString("name") , 0, 0, textStyle);
-}
-
-static void UI_DrawServerRefreshDate(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- if (uiInfo.serverStatus.refreshActive) {
- vec4_t lowLight, newColor;
- lowLight[0] = 0.8 * color[0];
- lowLight[1] = 0.8 * color[1];
- lowLight[2] = 0.8 * color[2];
- lowLight[3] = 0.8 * color[3];
- LerpColor(color,lowLight,newColor,0.5+0.5*sin(uiInfo.uiDC.realTime / PULSE_DIVISOR));
- Text_Paint(rect->x, rect->y, scale, newColor, va("Getting info for %d servers (ESC to cancel)", trap_LAN_GetServerCount(ui_netSource.integer)), 0, 0, textStyle);
- } else {
- char buff[64];
- Q_strncpyz(buff, UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer)), 64);
- Text_Paint(rect->x, rect->y, scale, color, va("Refresh Time: %s", buff), 0, 0, textStyle);
- }
-}
-
-static void UI_DrawServerMOTD(rectDef_t *rect, float scale, vec4_t color) {
- if (uiInfo.serverStatus.motdLen) {
- float maxX;
-
- if (uiInfo.serverStatus.motdWidth == -1) {
- uiInfo.serverStatus.motdWidth = 0;
- uiInfo.serverStatus.motdPaintX = rect->x + 1;
- uiInfo.serverStatus.motdPaintX2 = -1;
- }
-
- if (uiInfo.serverStatus.motdOffset > uiInfo.serverStatus.motdLen) {
- uiInfo.serverStatus.motdOffset = 0;
- uiInfo.serverStatus.motdPaintX = rect->x + 1;
- uiInfo.serverStatus.motdPaintX2 = -1;
- }
-
- if (uiInfo.uiDC.realTime > uiInfo.serverStatus.motdTime) {
- uiInfo.serverStatus.motdTime = uiInfo.uiDC.realTime + 10;
- if (uiInfo.serverStatus.motdPaintX <= rect->x + 2) {
- if (uiInfo.serverStatus.motdOffset < uiInfo.serverStatus.motdLen) {
- uiInfo.serverStatus.motdPaintX += Text_Width(&uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], scale, 1) - 1;
- uiInfo.serverStatus.motdOffset++;
- } else {
- uiInfo.serverStatus.motdOffset = 0;
- if (uiInfo.serverStatus.motdPaintX2 >= 0) {
- uiInfo.serverStatus.motdPaintX = uiInfo.serverStatus.motdPaintX2;
- } else {
- uiInfo.serverStatus.motdPaintX = rect->x + rect->w - 2;
- }
- uiInfo.serverStatus.motdPaintX2 = -1;
- }
- } else {
- //serverStatus.motdPaintX--;
- uiInfo.serverStatus.motdPaintX -= 2;
- if (uiInfo.serverStatus.motdPaintX2 >= 0) {
- //serverStatus.motdPaintX2--;
- uiInfo.serverStatus.motdPaintX2 -= 2;
- }
- }
- }
-
- maxX = rect->x + rect->w - 2;
- Text_Paint_Limit(&maxX, uiInfo.serverStatus.motdPaintX, rect->y + rect->h - 3, scale, color, &uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], 0, 0);
- if (uiInfo.serverStatus.motdPaintX2 >= 0) {
- float maxX2 = rect->x + rect->w - 2;
- Text_Paint_Limit(&maxX2, uiInfo.serverStatus.motdPaintX2, rect->y + rect->h - 3, scale, color, uiInfo.serverStatus.motd, 0, uiInfo.serverStatus.motdOffset);
- }
- if (uiInfo.serverStatus.motdOffset && maxX > 0) {
- // if we have an offset ( we are skipping the first part of the string ) and we fit the string
- if (uiInfo.serverStatus.motdPaintX2 == -1) {
- uiInfo.serverStatus.motdPaintX2 = rect->x + rect->w - 2;
- }
- } else {
- uiInfo.serverStatus.motdPaintX2 = -1;
- }
-
- }
-}
-
-static void UI_DrawKeyBindStatus(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
-// int ofs = 0; TTimo: unused
- if (Display_KeyBindPending()) {
- Text_Paint(rect->x, rect->y, scale, color, "Waiting for new key... Press ESCAPE to cancel", 0, 0, textStyle);
- } else {
- Text_Paint(rect->x, rect->y, scale, color, "Press ENTER or CLICK to change, Press BACKSPACE to clear", 0, 0, textStyle);
- }
-}
-
-static void UI_DrawGLInfo(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
- char * eptr;
- char buff[1024];
- const char *lines[64];
- int y, numLines, i;
-
- Text_Paint(rect->x + 2, rect->y, scale, color, va("VENDOR: %s", uiInfo.uiDC.glconfig.vendor_string), 0, 30, textStyle);
- Text_Paint(rect->x + 2, rect->y + 15, scale, color, va("VERSION: %s: %s", uiInfo.uiDC.glconfig.version_string,uiInfo.uiDC.glconfig.renderer_string), 0, 30, textStyle);
- Text_Paint(rect->x + 2, rect->y + 30, scale, color, va ("PIXELFORMAT: color(%d-bits) Z(%d-bits) stencil(%d-bits)", uiInfo.uiDC.glconfig.colorBits, uiInfo.uiDC.glconfig.depthBits, uiInfo.uiDC.glconfig.stencilBits), 0, 30, textStyle);
-
- // build null terminated extension strings
- // TTimo: https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=399
- // in TA this was not directly crashing, but displaying a nasty broken shader right in the middle
- // brought down the string size to 1024, there's not much that can be shown on the screen anyway
- Q_strncpyz(buff, uiInfo.uiDC.glconfig.extensions_string, 1024);
- eptr = buff;
- y = rect->y + 45;
- numLines = 0;
- while ( y < rect->y + rect->h && *eptr )
- {
- while ( *eptr && *eptr == ' ' )
- *eptr++ = '\0';
-
- // track start of valid string
- if (*eptr && *eptr != ' ') {
- lines[numLines++] = eptr;
- }
-
- while ( *eptr && *eptr != ' ' )
- eptr++;
- }
-
- i = 0;
- while (i < numLines) {
- Text_Paint(rect->x + 2, y, scale, color, lines[i++], 0, 20, textStyle);
- if (i < numLines) {
- Text_Paint(rect->x + rect->w / 2, y, scale, color, lines[i++], 0, 20, textStyle);
- }
- y += 10;
- if (y > rect->y + rect->h - 11) {
- break;
- }
- }
-
-
-}
-
-// FIXME: table drive
-//
-static void UI_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- rectDef_t rect;
-
- rect.x = x + text_x;
- rect.y = y + text_y;
- rect.w = w;
- rect.h = h;
-
- switch (ownerDraw) {
- case UI_HANDICAP:
- UI_DrawHandicap(&rect, scale, color, textStyle);
- break;
- case UI_EFFECTS:
- UI_DrawEffects(&rect, scale, color);
- break;
- case UI_PLAYERMODEL:
- UI_DrawPlayerModel(&rect);
- break;
- case UI_CLANNAME:
- UI_DrawClanName(&rect, scale, color, textStyle);
- break;
- case UI_CLANLOGO:
- UI_DrawClanLogo(&rect, scale, color);
- break;
- case UI_CLANCINEMATIC:
- UI_DrawClanCinematic(&rect, scale, color);
- break;
- case UI_PREVIEWCINEMATIC:
- UI_DrawPreviewCinematic(&rect, scale, color);
- break;
- case UI_GAMETYPE:
- UI_DrawGameType(&rect, scale, color, textStyle);
- break;
- case UI_NETGAMETYPE:
- UI_DrawNetGameType(&rect, scale, color, textStyle);
- break;
- case UI_JOINGAMETYPE:
- UI_DrawJoinGameType(&rect, scale, color, textStyle);
- break;
- case UI_MAPPREVIEW:
- UI_DrawMapPreview(&rect, scale, color, qtrue);
- break;
- case UI_MAP_TIMETOBEAT:
- UI_DrawMapTimeToBeat(&rect, scale, color, textStyle);
- break;
- case UI_MAPCINEMATIC:
- UI_DrawMapCinematic(&rect, scale, color, qfalse);
- break;
- case UI_STARTMAPCINEMATIC:
- UI_DrawMapCinematic(&rect, scale, color, qtrue);
- break;
- case UI_SKILL:
- UI_DrawSkill(&rect, scale, color, textStyle);
- break;
- case UI_BLUETEAMNAME:
- UI_DrawTeamName(&rect, scale, color, qtrue, textStyle);
- break;
- case UI_REDTEAMNAME:
- UI_DrawTeamName(&rect, scale, color, qfalse, textStyle);
- break;
- case UI_BLUETEAM1:
- case UI_BLUETEAM2:
- case UI_BLUETEAM3:
- case UI_BLUETEAM4:
- case UI_BLUETEAM5:
- UI_DrawTeamMember(&rect, scale, color, qtrue, ownerDraw - UI_BLUETEAM1 + 1, textStyle);
- break;
- case UI_REDTEAM1:
- case UI_REDTEAM2:
- case UI_REDTEAM3:
- case UI_REDTEAM4:
- case UI_REDTEAM5:
- UI_DrawTeamMember(&rect, scale, color, qfalse, ownerDraw - UI_REDTEAM1 + 1, textStyle);
- break;
- case UI_NETSOURCE:
- UI_DrawNetSource(&rect, scale, color, textStyle);
- break;
- case UI_NETMAPPREVIEW:
- UI_DrawNetMapPreview(&rect, scale, color);
- break;
- case UI_NETMAPCINEMATIC:
- UI_DrawNetMapCinematic(&rect, scale, color);
- break;
- case UI_NETFILTER:
- UI_DrawNetFilter(&rect, scale, color, textStyle);
- break;
- case UI_TIER:
- UI_DrawTier(&rect, scale, color, textStyle);
- break;
- case UI_OPPONENTMODEL:
- UI_DrawOpponent(&rect);
- break;
- case UI_TIERMAP1:
- UI_DrawTierMap(&rect, 0);
- break;
- case UI_TIERMAP2:
- UI_DrawTierMap(&rect, 1);
- break;
- case UI_TIERMAP3:
- UI_DrawTierMap(&rect, 2);
- break;
- case UI_PLAYERLOGO:
- UI_DrawPlayerLogo(&rect, color);
- break;
- case UI_PLAYERLOGO_METAL:
- UI_DrawPlayerLogoMetal(&rect, color);
- break;
- case UI_PLAYERLOGO_NAME:
- UI_DrawPlayerLogoName(&rect, color);
- break;
- case UI_OPPONENTLOGO:
- UI_DrawOpponentLogo(&rect, color);
- break;
- case UI_OPPONENTLOGO_METAL:
- UI_DrawOpponentLogoMetal(&rect, color);
- break;
- case UI_OPPONENTLOGO_NAME:
- UI_DrawOpponentLogoName(&rect, color);
- break;
- case UI_TIER_MAPNAME:
- UI_DrawTierMapName(&rect, scale, color, textStyle);
- break;
- case UI_TIER_GAMETYPE:
- UI_DrawTierGameType(&rect, scale, color, textStyle);
- break;
- case UI_ALLMAPS_SELECTION:
- UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qtrue);
- break;
- case UI_MAPS_SELECTION:
- UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qfalse);
- break;
- case UI_OPPONENT_NAME:
- UI_DrawOpponentName(&rect, scale, color, textStyle);
- break;
- case UI_BOTNAME:
- UI_DrawBotName(&rect, scale, color, textStyle);
- break;
- case UI_BOTSKILL:
- UI_DrawBotSkill(&rect, scale, color, textStyle);
- break;
- case UI_REDBLUE:
- UI_DrawRedBlue(&rect, scale, color, textStyle);
- break;
- case UI_CROSSHAIR:
- UI_DrawCrosshair(&rect, scale, color);
- break;
- case UI_SELECTEDPLAYER:
- UI_DrawSelectedPlayer(&rect, scale, color, textStyle);
- break;
- case UI_SERVERREFRESHDATE:
- UI_DrawServerRefreshDate(&rect, scale, color, textStyle);
- break;
- case UI_SERVERMOTD:
- UI_DrawServerMOTD(&rect, scale, color);
- break;
- case UI_GLINFO:
- UI_DrawGLInfo(&rect,scale, color, textStyle);
- break;
- case UI_KEYBINDSTATUS:
- UI_DrawKeyBindStatus(&rect,scale, color, textStyle);
- break;
- default:
- break;
- }
-
-}
-
-static qboolean UI_OwnerDrawVisible(int flags) {
- qboolean vis = qtrue;
-
- while (flags) {
-
- if (flags & UI_SHOW_FFA) {
- if (trap_Cvar_VariableValue("g_gametype") != GT_FFA || trap_Cvar_VariableValue("g_gametype") != GT_LMS ) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_FFA;
- }
-
- if (flags & UI_SHOW_NOTFFA) {
- if (trap_Cvar_VariableValue("g_gametype") == GT_FFA || trap_Cvar_VariableValue("g_gametype") == GT_LMS ) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_NOTFFA;
- }
-
- if (flags & UI_SHOW_LEADER) {
- // these need to show when this client can give orders to a player or a group
- if (!uiInfo.teamLeader) {
- vis = qfalse;
- } else {
- // if showing yourself
- if (ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber) {
- vis = qfalse;
- }
- }
- flags &= ~UI_SHOW_LEADER;
- }
- if (flags & UI_SHOW_NOTLEADER) {
- // these need to show when this client is assigning their own status or they are NOT the leader
- if (uiInfo.teamLeader) {
- // if not showing yourself
- if (!(ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber)) {
- vis = qfalse;
- }
- // these need to show when this client can give orders to a player or a group
- }
- flags &= ~UI_SHOW_NOTLEADER;
- }
- if (flags & UI_SHOW_FAVORITESERVERS) {
- // this assumes you only put this type of display flag on something showing in the proper context
- if (ui_netSource.integer != AS_FAVORITES) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_FAVORITESERVERS;
- }
- if (flags & UI_SHOW_NOTFAVORITESERVERS) {
- // this assumes you only put this type of display flag on something showing in the proper context
- if (ui_netSource.integer == AS_FAVORITES) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_NOTFAVORITESERVERS;
- }
- if (flags & UI_SHOW_ANYTEAMGAME) {
- if (uiInfo.gameTypes[ui_gameType.integer].gtEnum <= GT_TEAM && uiInfo.gameTypes[ui_gameType.integer].gtEnum != GT_LMS ) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_ANYTEAMGAME;
- }
- if (flags & UI_SHOW_ANYNONTEAMGAME) {
- if (uiInfo.gameTypes[ui_gameType.integer].gtEnum > GT_TEAM || uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_LMS ) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_ANYNONTEAMGAME;
- }
- if (flags & UI_SHOW_NETANYTEAMGAME) {
- if (uiInfo.gameTypes[ui_netGameType.integer].gtEnum <= GT_TEAM && uiInfo.gameTypes[ui_gameType.integer].gtEnum != GT_LMS ) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_NETANYTEAMGAME;
- }
- if (flags & UI_SHOW_NETANYNONTEAMGAME) {
- if (uiInfo.gameTypes[ui_netGameType.integer].gtEnum > GT_TEAM || uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_LMS ) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_NETANYNONTEAMGAME;
- }
- if (flags & UI_SHOW_NEWHIGHSCORE) {
- if (uiInfo.newHighScoreTime < uiInfo.uiDC.realTime) {
- vis = qfalse;
- } else {
- if (uiInfo.soundHighScore) {
- if (trap_Cvar_VariableValue("sv_killserver") == 0) {
- // wait on server to go down before playing sound
- trap_S_StartLocalSound(uiInfo.newHighScoreSound, CHAN_ANNOUNCER);
- uiInfo.soundHighScore = qfalse;
- }
- }
- }
- flags &= ~UI_SHOW_NEWHIGHSCORE;
- }
- if (flags & UI_SHOW_NEWBESTTIME) {
- if (uiInfo.newBestTime < uiInfo.uiDC.realTime) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_NEWBESTTIME;
- }
- if (flags & UI_SHOW_DEMOAVAILABLE) {
- if (!uiInfo.demoAvailable) {
- vis = qfalse;
- }
- flags &= ~UI_SHOW_DEMOAVAILABLE;
- } else {
- flags = 0;
- }
- }
- return vis;
-}
-
-static qboolean UI_Handicap_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int h;
- h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
- if (key == K_MOUSE2) {
- h -= 5;
- } else {
- h += 5;
- }
- if (h > 100) {
- h = 5;
- } else if (h < 0) {
- h = 100;
- }
- trap_Cvar_Set( "handicap", va( "%i", h) );
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_Effects_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
-
- if (key == K_MOUSE2) {
- uiInfo.effectsColor--;
- } else {
- uiInfo.effectsColor++;
- }
-
- if( uiInfo.effectsColor > 6 ) {
- uiInfo.effectsColor = 0;
- } else if (uiInfo.effectsColor < 0) {
- uiInfo.effectsColor = 6;
- }
-
- trap_Cvar_SetValue( "color1", uitogamecode[uiInfo.effectsColor] );
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_ClanName_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (uiInfo.teamList[i].cinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
- uiInfo.teamList[i].cinematic = -1;
- }
- if (key == K_MOUSE2) {
- i--;
- } else {
- i++;
- }
- if (i >= uiInfo.teamCount) {
- i = 0;
- } else if (i < 0) {
- i = uiInfo.teamCount - 1;
- }
- trap_Cvar_Set( "ui_teamName", uiInfo.teamList[i].teamName);
- UI_HeadCountByTeam();
- UI_FeederSelection(FEEDER_HEADS, 0);
- updateModel = qtrue;
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_GameType_HandleKey(int flags, float *special, int key, qboolean resetMap) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int oldCount = UI_MapCountByGameType(qtrue);
-
- // hard coded mess here
- if (key == K_MOUSE2) {
- ui_gameType.integer--;
- if (ui_gameType.integer == 2) {
- ui_gameType.integer = 1;
- } else if (ui_gameType.integer < 2) {
- ui_gameType.integer = uiInfo.numGameTypes - 1;
- }
- } else {
- ui_gameType.integer++;
- if (ui_gameType.integer >= uiInfo.numGameTypes) {
- ui_gameType.integer = 1;
- } else if (ui_gameType.integer == 2) {
- ui_gameType.integer = 3;
- }
- }
-
- if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_TOURNAMENT) {
- trap_Cvar_Set("ui_Q3Model", "1");
- } else {
- trap_Cvar_Set("ui_Q3Model", "0");
- }
-
- trap_Cvar_Set("ui_gameType", va("%d", ui_gameType.integer));
- UI_SetCapFragLimits(qtrue);
- UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
- if (resetMap && oldCount != UI_MapCountByGameType(qtrue)) {
- trap_Cvar_Set( "ui_currentMap", "0");
- Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, NULL);
- }
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_NetGameType_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
-
- if (key == K_MOUSE2) {
- ui_netGameType.integer--;
- } else {
- ui_netGameType.integer++;
- }
-
- if (ui_netGameType.integer < 0) {
- ui_netGameType.integer = uiInfo.numGameTypes - 1;
- } else if (ui_netGameType.integer >= uiInfo.numGameTypes) {
- ui_netGameType.integer = 0;
- }
-
- trap_Cvar_Set( "ui_netGameType", va("%d", ui_netGameType.integer));
- trap_Cvar_Set( "ui_actualnetGameType", va("%d", uiInfo.gameTypes[ui_netGameType.integer].gtEnum));
- trap_Cvar_Set( "ui_currentNetMap", "0");
- UI_MapCountByGameType(qfalse);
- Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, NULL);
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_JoinGameType_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
-
- if (key == K_MOUSE2) {
- ui_joinGameType.integer--;
- } else {
- ui_joinGameType.integer++;
- }
-
- if (ui_joinGameType.integer < 0) {
- ui_joinGameType.integer = uiInfo.numJoinGameTypes - 1;
- } else if (ui_joinGameType.integer >= uiInfo.numJoinGameTypes) {
- ui_joinGameType.integer = 0;
- }
-
- trap_Cvar_Set( "ui_joinGameType", va("%d", ui_joinGameType.integer));
- UI_BuildServerDisplayList(qtrue);
- return qtrue;
- }
- return qfalse;
-}
-
-
-
-static qboolean UI_Skill_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int i = trap_Cvar_VariableValue( "g_spSkill" );
-
- if (key == K_MOUSE2) {
- i--;
- } else {
- i++;
- }
-
- if (i < 1) {
- i = numSkillLevels;
- } else if (i > numSkillLevels) {
- i = 1;
- }
-
- trap_Cvar_Set("g_spSkill", va("%i", i));
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_TeamName_HandleKey(int flags, float *special, int key, qboolean blue) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int i;
- i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
-
- if (key == K_MOUSE2) {
- i--;
- } else {
- i++;
- }
-
- if (i >= uiInfo.teamCount) {
- i = 0;
- } else if (i < 0) {
- i = uiInfo.teamCount - 1;
- }
-
- trap_Cvar_Set( (blue) ? "ui_blueTeam" : "ui_redTeam", uiInfo.teamList[i].teamName);
-
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_TeamMember_HandleKey(int flags, float *special, int key, qboolean blue, int num) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- // 0 - None
- // 1 - Human
- // 2..NumCharacters - Bot
- char *cvar = va(blue ? "ui_blueteam%i" : "ui_redteam%i", num);
- int value = trap_Cvar_VariableValue(cvar);
-
- if (key == K_MOUSE2) {
- value--;
- } else {
- value++;
- }
-
- if (ui_actualNetGameType.integer >= GT_TEAM) {
- if (value >= uiInfo.characterCount + 2) {
- value = 0;
- } else if (value < 0) {
- value = uiInfo.characterCount + 2 - 1;
- }
- } else {
- if (value >= UI_GetNumBots() + 2) {
- value = 0;
- } else if (value < 0) {
- value = UI_GetNumBots() + 2 - 1;
- }
- }
-
- trap_Cvar_Set(cvar, va("%i", value));
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_NetSource_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
-
- if (key == K_MOUSE2) {
- ui_netSource.integer--;
- if(strlen(netSources[ui_netSource.integer])<1)
- ui_netSource.integer--;
- } else {
- ui_netSource.integer++;
- if(strlen(netSources[ui_netSource.integer])<1)
- ui_netSource.integer++;
- }
-
- if (ui_netSource.integer >= numNetSources) {
- ui_netSource.integer = 0;
- } else if (ui_netSource.integer < 0) {
- ui_netSource.integer = numNetSources - 1;
- }
-
- UI_BuildServerDisplayList(qtrue);
- if (ui_netSource.integer != AS_GLOBAL) {
- UI_StartServerRefresh(qtrue);
- }
- trap_Cvar_Set( "ui_netSource", va("%d", ui_netSource.integer));
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_NetFilter_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
-
- if (key == K_MOUSE2) {
- ui_serverFilterType.integer--;
- } else {
- ui_serverFilterType.integer++;
- }
-
- if (ui_serverFilterType.integer >= numServerFilters) {
- ui_serverFilterType.integer = 0;
- } else if (ui_serverFilterType.integer < 0) {
- ui_serverFilterType.integer = numServerFilters - 1;
- }
- UI_BuildServerDisplayList(qtrue);
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_OpponentName_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- if (key == K_MOUSE2) {
- UI_PriorOpponent();
- } else {
- UI_NextOpponent();
- }
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_BotName_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int game = trap_Cvar_VariableValue("g_gametype");
- int value = uiInfo.botIndex;
-
- if (key == K_MOUSE2) {
- value--;
- } else {
- value++;
- }
-
- if (game >= GT_TEAM && !GT_LMS) {
- if (value >= uiInfo.characterCount + 2) {
- value = 0;
- } else if (value < 0) {
- value = uiInfo.characterCount + 2 - 1;
- }
- } else {
- if (value >= UI_GetNumBots() + 2) {
- value = 0;
- } else if (value < 0) {
- value = UI_GetNumBots() + 2 - 1;
- }
- }
- uiInfo.botIndex = value;
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_BotSkill_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- if (key == K_MOUSE2) {
- uiInfo.skillIndex--;
- } else {
- uiInfo.skillIndex++;
- }
- if (uiInfo.skillIndex >= numSkillLevels) {
- uiInfo.skillIndex = 0;
- } else if (uiInfo.skillIndex < 0) {
- uiInfo.skillIndex = numSkillLevels-1;
- }
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_RedBlue_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- uiInfo.redBlue ^= 1;
- return qtrue;
- }
- return qfalse;
-}
-
-static qboolean UI_Crosshair_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- if (key == K_MOUSE2) {
- uiInfo.currentCrosshair--;
- } else {
- uiInfo.currentCrosshair++;
- }
-
- if (uiInfo.currentCrosshair >= NUM_CROSSHAIRS) {
- uiInfo.currentCrosshair = 0;
- } else if (uiInfo.currentCrosshair < 0) {
- uiInfo.currentCrosshair = NUM_CROSSHAIRS - 1;
- }
- trap_Cvar_Set("cg_drawCrosshair", va("%d", uiInfo.currentCrosshair));
- return qtrue;
- }
- return qfalse;
-}
-
-
-
-static qboolean UI_SelectedPlayer_HandleKey(int flags, float *special, int key) {
- if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
- int selected;
-
- UI_BuildPlayerList();
- if (!uiInfo.teamLeader) {
- return qfalse;
- }
- selected = trap_Cvar_VariableValue("cg_selectedPlayer");
-
- if (key == K_MOUSE2) {
- selected--;
- } else {
- selected++;
- }
-
- if (selected > uiInfo.myTeamCount) {
- selected = 0;
- } else if (selected < 0) {
- selected = uiInfo.myTeamCount;
- }
-
- if (selected == uiInfo.myTeamCount) {
- trap_Cvar_Set( "cg_selectedPlayerName", "Everyone");
- } else {
- trap_Cvar_Set( "cg_selectedPlayerName", uiInfo.teamNames[selected]);
- }
- trap_Cvar_Set( "cg_selectedPlayer", va("%d", selected));
- }
- return qfalse;
-}
-
-
-static qboolean UI_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) {
- switch (ownerDraw) {
- case UI_HANDICAP:
- return UI_Handicap_HandleKey(flags, special, key);
- break;
- case UI_EFFECTS:
- return UI_Effects_HandleKey(flags, special, key);
- break;
- case UI_CLANNAME:
- return UI_ClanName_HandleKey(flags, special, key);
- break;
- case UI_GAMETYPE:
- return UI_GameType_HandleKey(flags, special, key, qtrue);
- break;
- case UI_NETGAMETYPE:
- return UI_NetGameType_HandleKey(flags, special, key);
- break;
- case UI_JOINGAMETYPE:
- return UI_JoinGameType_HandleKey(flags, special, key);
- break;
- case UI_SKILL:
- return UI_Skill_HandleKey(flags, special, key);
- break;
- case UI_BLUETEAMNAME:
- return UI_TeamName_HandleKey(flags, special, key, qtrue);
- break;
- case UI_REDTEAMNAME:
- return UI_TeamName_HandleKey(flags, special, key, qfalse);
- break;
- case UI_BLUETEAM1:
- case UI_BLUETEAM2:
- case UI_BLUETEAM3:
- case UI_BLUETEAM4:
- case UI_BLUETEAM5:
- UI_TeamMember_HandleKey(flags, special, key, qtrue, ownerDraw - UI_BLUETEAM1 + 1);
- break;
- case UI_REDTEAM1:
- case UI_REDTEAM2:
- case UI_REDTEAM3:
- case UI_REDTEAM4:
- case UI_REDTEAM5:
- UI_TeamMember_HandleKey(flags, special, key, qfalse, ownerDraw - UI_REDTEAM1 + 1);
- break;
- case UI_NETSOURCE:
- UI_NetSource_HandleKey(flags, special, key);
- break;
- case UI_NETFILTER:
- UI_NetFilter_HandleKey(flags, special, key);
- break;
- case UI_OPPONENT_NAME:
- UI_OpponentName_HandleKey(flags, special, key);
- break;
- case UI_BOTNAME:
- return UI_BotName_HandleKey(flags, special, key);
- break;
- case UI_BOTSKILL:
- return UI_BotSkill_HandleKey(flags, special, key);
- break;
- case UI_REDBLUE:
- UI_RedBlue_HandleKey(flags, special, key);
- break;
- case UI_CROSSHAIR:
- UI_Crosshair_HandleKey(flags, special, key);
- break;
- case UI_SELECTEDPLAYER:
- UI_SelectedPlayer_HandleKey(flags, special, key);
- break;
- default:
- break;
- }
-
- return qfalse;
-}
-
-
-static float UI_GetValue(int ownerDraw) {
- return 0;
-}
-
-/*
-=================
-UI_ServersQsortCompare
-=================
-*/
-static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 ) {
- return trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey, uiInfo.serverStatus.sortDir, *(int*)arg1, *(int*)arg2);
-}
-
-
-/*
-=================
-UI_ServersSort
-=================
-*/
-void UI_ServersSort(int column, qboolean force) {
-
- if ( !force ) {
- if ( uiInfo.serverStatus.sortKey == column ) {
- return;
- }
- }
-
- uiInfo.serverStatus.sortKey = column;
- qsort( &uiInfo.serverStatus.displayServers[0], uiInfo.serverStatus.numDisplayServers, sizeof(int), UI_ServersQsortCompare);
-}
-
-/*
-static void UI_StartSinglePlayer(void) {
- int i,j, k, skill;
- char buff[1024];
- i = trap_Cvar_VariableValue( "ui_currentTier" );
- if (i < 0 || i >= tierCount) {
- i = 0;
- }
- j = trap_Cvar_VariableValue("ui_currentMap");
- if (j < 0 || j > MAPS_PER_TIER) {
- j = 0;
- }
-
- trap_Cvar_SetValue( "singleplayer", 1 );
- trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, 7, tierList[i].gameTypes[j] ) );
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", tierList[i].maps[j] ) );
- skill = trap_Cvar_VariableValue( "g_spSkill" );
-
- if (j == MAPS_PER_TIER-1) {
- k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[0]), skill, "", teamList[k].teamMembers[0]);
- } else {
- k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
- for (i = 0; i < PLAYERS_PER_TEAM; i++) {
- Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[i]), skill, "Blue", teamList[k].teamMembers[i]);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- }
-
- k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- for (i = 1; i < PLAYERS_PER_TEAM; i++) {
- Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[i]), skill, "Red", teamList[k].teamMembers[i]);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- }
- trap_Cmd_ExecuteText( EXEC_APPEND, "wait 5; team Red\n" );
- }
-
-
-}
-*/
-
-/*
-===============
-UI_LoadMods
-===============
-*/
-static void UI_LoadMods( void ) {
- int numdirs;
- char dirlist[2048];
- char *dirptr;
- char *descptr;
- int i;
- int dirlen;
-
- uiInfo.modCount = 0;
- numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) );
- dirptr = dirlist;
- for( i = 0; i < numdirs; i++ ) {
- dirlen = strlen( dirptr ) + 1;
- descptr = dirptr + dirlen;
- uiInfo.modList[uiInfo.modCount].modName = String_Alloc(dirptr);
- uiInfo.modList[uiInfo.modCount].modDescr = String_Alloc(descptr);
- dirptr += dirlen + strlen(descptr) + 1;
- uiInfo.modCount++;
- if (uiInfo.modCount >= MAX_MODS) {
- break;
- }
- }
-
-}
-
-
-/*
-===============
-UI_LoadTeams
-===============
-*/
-static void UI_LoadTeams( void ) {
- char teamList[4096];
- char *teamName;
- int i, len, count;
-
- count = trap_FS_GetFileList( "", "team", teamList, 4096 );
-
- if (count) {
- teamName = teamList;
- for ( i = 0; i < count; i++ ) {
- len = strlen( teamName );
- UI_ParseTeamInfo(teamName);
- teamName += len + 1;
- }
- }
-
-}
-
-
-/*
-===============
-UI_LoadMovies
-===============
-*/
-static void UI_LoadMovies( void ) {
- char movielist[4096];
- char *moviename;
- int i, len;
-
- uiInfo.movieCount = trap_FS_GetFileList( "video", "roq", movielist, 4096 );
-
- if (uiInfo.movieCount) {
- if (uiInfo.movieCount > MAX_MOVIES) {
- uiInfo.movieCount = MAX_MOVIES;
- }
- moviename = movielist;
- for ( i = 0; i < uiInfo.movieCount; i++ ) {
- len = strlen( moviename );
- if (!Q_stricmp(moviename + len - 4,".roq")) {
- moviename[len-4] = '\0';
- }
- Q_strupr(moviename);
- uiInfo.movieList[i] = String_Alloc(moviename);
- moviename += len + 1;
- }
- }
-
-}
-
-
-
-/*
-===============
-UI_LoadDemos
-===============
-*/
-static void UI_LoadDemos( void ) {
- char demolist[4096];
- char demoExt[32];
- char *demoname;
- int i, len;
-
- Com_sprintf(demoExt, sizeof(demoExt), "dm_%d", (int)trap_Cvar_VariableValue("protocol"));
-
- uiInfo.demoCount = trap_FS_GetFileList( "demos", demoExt, demolist, 4096 );
-
- Com_sprintf(demoExt, sizeof(demoExt), ".dm_%d", (int)trap_Cvar_VariableValue("protocol"));
-
- if (uiInfo.demoCount) {
- if (uiInfo.demoCount > MAX_DEMOS) {
- uiInfo.demoCount = MAX_DEMOS;
- }
- demoname = demolist;
- for ( i = 0; i < uiInfo.demoCount; i++ ) {
- len = strlen( demoname );
- if (!Q_stricmp(demoname + len - strlen(demoExt), demoExt)) {
- demoname[len-strlen(demoExt)] = '\0';
- }
- Q_strupr(demoname);
- uiInfo.demoList[i] = String_Alloc(demoname);
- demoname += len + 1;
- }
- }
-
-}
-
-
-static qboolean UI_SetNextMap(int actual, int index) {
- int i;
- for (i = actual + 1; i < uiInfo.mapCount; i++) {
- if (uiInfo.mapList[i].active) {
- Menu_SetFeederSelection(NULL, FEEDER_MAPS, index + 1, "skirmish");
- return qtrue;
- }
- }
- return qfalse;
-}
-
-
-static void UI_StartSkirmish(qboolean next) {
- int i, k, g, delay, temp;
- float skill;
- char buff[MAX_STRING_CHARS];
-
- if (next) {
- int actual;
- int index = trap_Cvar_VariableValue("ui_mapIndex");
- UI_MapCountByGameType(qtrue);
- UI_SelectedMap(index, &actual);
- if (UI_SetNextMap(actual, index)) {
- } else {
- UI_GameType_HandleKey(0, NULL, K_MOUSE1, qfalse);
- UI_MapCountByGameType(qtrue);
- Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, "skirmish");
- }
- }
-
- g = uiInfo.gameTypes[ui_gameType.integer].gtEnum;
- trap_Cvar_SetValue( "g_gametype", g );
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName) );
- skill = trap_Cvar_VariableValue( "g_spSkill" );
- trap_Cvar_Set("ui_scoreMap", uiInfo.mapList[ui_currentMap.integer].mapName);
-
- k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
-
- trap_Cvar_Set("ui_singlePlayerActive", "1");
-
- // set up sp overrides, will be replaced on postgame
- temp = trap_Cvar_VariableValue( "capturelimit" );
- trap_Cvar_Set("ui_saveCaptureLimit", va("%i", temp));
- temp = trap_Cvar_VariableValue( "fraglimit" );
- trap_Cvar_Set("ui_saveFragLimit", va("%i", temp));
-
- UI_SetCapFragLimits(qfalse);
-
- temp = trap_Cvar_VariableValue( "cg_drawTimer" );
- trap_Cvar_Set("ui_drawTimer", va("%i", temp));
- temp = trap_Cvar_VariableValue( "g_doWarmup" );
- trap_Cvar_Set("ui_doWarmup", va("%i", temp));
- temp = trap_Cvar_VariableValue( "g_friendlyFire" );
- trap_Cvar_Set("ui_friendlyFire", va("%i", temp));
- temp = trap_Cvar_VariableValue( "sv_maxClients" );
- trap_Cvar_Set("ui_maxClients", va("%i", temp));
- temp = trap_Cvar_VariableValue( "g_warmup" );
- trap_Cvar_Set("ui_Warmup", va("%i", temp));
- temp = trap_Cvar_VariableValue( "sv_pure" );
- trap_Cvar_Set("ui_pure", va("%i", temp));
-
- trap_Cvar_Set("cg_cameraOrbit", "0");
- trap_Cvar_Set("cg_thirdPerson", "0");
- trap_Cvar_Set("cg_drawTimer", "1");
- trap_Cvar_Set("g_doWarmup", "1");
- trap_Cvar_Set("g_warmup", "15");
- trap_Cvar_Set("sv_pure", "0");
- trap_Cvar_Set("g_friendlyFire", "0");
- trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
- trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
-
- if (trap_Cvar_VariableValue("ui_recordSPDemo")) {
- Com_sprintf(buff, MAX_STRING_CHARS, "%s_%i", uiInfo.mapList[ui_currentMap.integer].mapLoadName, g);
- trap_Cvar_Set("ui_recordSPDemoName", buff);
- }
-
- delay = 500;
-
- if (g == GT_TOURNAMENT) {
- trap_Cvar_Set("sv_maxClients", "2");
- Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %f "", %i \n", uiInfo.mapList[ui_currentMap.integer].opponentName, skill, delay);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- } else {
- temp = uiInfo.mapList[ui_currentMap.integer].teamMembers * 2;
- trap_Cvar_Set("sv_maxClients", va("%d", temp));
- for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers; i++) {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f %s %i %s\n", UI_AIFromName(uiInfo.teamList[k].teamMembers[i]), skill, (g == GT_FFA) ? "" : "Blue", delay, uiInfo.teamList[k].teamMembers[i]);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- delay += 500;
- }
- k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers-1; i++) {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f %s %i %s\n", UI_AIFromName(uiInfo.teamList[k].teamMembers[i]), skill, (g == GT_FFA) ? "" : "Red", delay, uiInfo.teamList[k].teamMembers[i]);
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- delay += 500;
- }
- }
- if (g >= GT_TEAM ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "wait 5; team Red\n" );
- }
-}
-
-static void UI_Update(const char *name) {
- int val = trap_Cvar_VariableValue(name);
-
- if (Q_stricmp(name, "ui_SetName") == 0) {
- trap_Cvar_Set( "name", UI_Cvar_VariableString("ui_Name"));
- } else if (Q_stricmp(name, "ui_setRate") == 0) {
- float rate = trap_Cvar_VariableValue("rate");
- if (rate >= 5000) {
- trap_Cvar_Set("cl_maxpackets", "30");
- trap_Cvar_Set("cl_packetdup", "1");
- } else if (rate >= 4000) {
- trap_Cvar_Set("cl_maxpackets", "15");
- trap_Cvar_Set("cl_packetdup", "2"); // favor less prediction errors when there's packet loss
- } else {
- trap_Cvar_Set("cl_maxpackets", "15");
- trap_Cvar_Set("cl_packetdup", "1"); // favor lower bandwidth
- }
- } else if (Q_stricmp(name, "ui_GetName") == 0) {
- trap_Cvar_Set( "ui_Name", UI_Cvar_VariableString("name"));
- } else if (Q_stricmp(name, "r_colorbits") == 0) {
- switch (val) {
- case 0:
- trap_Cvar_SetValue( "r_depthbits", 0 );
- trap_Cvar_SetValue( "r_stencilbits", 0 );
- break;
- case 16:
- trap_Cvar_SetValue( "r_depthbits", 16 );
- trap_Cvar_SetValue( "r_stencilbits", 0 );
- break;
- case 32:
- trap_Cvar_SetValue( "r_depthbits", 24 );
- break;
- }
- } else if (Q_stricmp(name, "r_lodbias") == 0) {
- switch (val) {
- case 0:
- trap_Cvar_SetValue( "r_subdivisions", 4 );
- break;
- case 1:
- trap_Cvar_SetValue( "r_subdivisions", 12 );
- break;
- case 2:
- trap_Cvar_SetValue( "r_subdivisions", 20 );
- break;
- }
- } else if (Q_stricmp(name, "ui_glCustom") == 0) {
- switch (val) {
- case 0: // high quality
- trap_Cvar_SetValue( "r_fullScreen", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 4 );
- trap_Cvar_SetValue( "r_vertexlight", 0 );
- trap_Cvar_SetValue( "r_lodbias", 0 );
- trap_Cvar_SetValue( "r_colorbits", 32 );
- trap_Cvar_SetValue( "r_depthbits", 24 );
- trap_Cvar_SetValue( "r_picmip", 0 );
- trap_Cvar_SetValue( "r_mode", 4 );
- trap_Cvar_SetValue( "r_texturebits", 32 );
- trap_Cvar_SetValue( "r_fastSky", 0 );
- trap_Cvar_SetValue( "r_inGameVideo", 1 );
- trap_Cvar_SetValue( "cg_shadows", 1 );
- trap_Cvar_SetValue( "cg_brassTime", 2500 );
- trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
- break;
- case 1: // normal
- trap_Cvar_SetValue( "r_fullScreen", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 12 );
- trap_Cvar_SetValue( "r_vertexlight", 0 );
- trap_Cvar_SetValue( "r_lodbias", 0 );
- trap_Cvar_SetValue( "r_colorbits", 0 );
- trap_Cvar_SetValue( "r_depthbits", 24 );
- trap_Cvar_SetValue( "r_picmip", 1 );
- trap_Cvar_SetValue( "r_mode", 3 );
- trap_Cvar_SetValue( "r_texturebits", 0 );
- trap_Cvar_SetValue( "r_fastSky", 0 );
- trap_Cvar_SetValue( "r_inGameVideo", 1 );
- trap_Cvar_SetValue( "cg_brassTime", 2500 );
- trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
- trap_Cvar_SetValue( "cg_shadows", 0 );
- break;
- case 2: // fast
- trap_Cvar_SetValue( "r_fullScreen", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 8 );
- trap_Cvar_SetValue( "r_vertexlight", 0 );
- trap_Cvar_SetValue( "r_lodbias", 1 );
- trap_Cvar_SetValue( "r_colorbits", 0 );
- trap_Cvar_SetValue( "r_depthbits", 0 );
- trap_Cvar_SetValue( "r_picmip", 1 );
- trap_Cvar_SetValue( "r_mode", 3 );
- trap_Cvar_SetValue( "r_texturebits", 0 );
- trap_Cvar_SetValue( "cg_shadows", 0 );
- trap_Cvar_SetValue( "r_fastSky", 1 );
- trap_Cvar_SetValue( "r_inGameVideo", 0 );
- trap_Cvar_SetValue( "cg_brassTime", 0 );
- trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
- break;
- case 3: // fastest
- trap_Cvar_SetValue( "r_fullScreen", 1 );
- trap_Cvar_SetValue( "r_subdivisions", 20 );
- trap_Cvar_SetValue( "r_vertexlight", 1 );
- trap_Cvar_SetValue( "r_lodbias", 2 );
- trap_Cvar_SetValue( "r_colorbits", 16 );
- trap_Cvar_SetValue( "r_depthbits", 16 );
- trap_Cvar_SetValue( "r_mode", 3 );
- trap_Cvar_SetValue( "r_picmip", 2 );
- trap_Cvar_SetValue( "r_texturebits", 16 );
- trap_Cvar_SetValue( "cg_shadows", 0 );
- trap_Cvar_SetValue( "cg_brassTime", 0 );
- trap_Cvar_SetValue( "r_fastSky", 1 );
- trap_Cvar_SetValue( "r_inGameVideo", 0 );
- trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
- break;
- }
- } else if (Q_stricmp(name, "ui_mousePitch") == 0) {
- if (val == 0) {
- trap_Cvar_SetValue( "m_pitch", 0.022f );
- } else {
- trap_Cvar_SetValue( "m_pitch", -0.022f );
- }
- }
-}
-
-static void UI_RunMenuScript(char **args) {
- const char *name, *name2;
- char buff[1024];
-
- if (String_Parse(args, &name)) {
- if (Q_stricmp(name, "StartServer") == 0) {
- int i, clients, oldclients;
- float skill;
- trap_Cvar_Set("cg_thirdPerson", "0");
- trap_Cvar_Set("cg_cameraOrbit", "0");
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, ui_dedicated.integer ) );
- trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, 13, uiInfo.gameTypes[ui_netGameType.integer].gtEnum ) );
- trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
- trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName ) );
- skill = trap_Cvar_VariableValue( "g_spSkill" );
- // set max clients based on spots
- oldclients = trap_Cvar_VariableValue( "sv_maxClients" );
- clients = 0;
- for (i = 0; i < PLAYERS_PER_TEAM; i++) {
- int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
- if (bot >= 0) {
- clients++;
- }
- bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
- if (bot >= 0) {
- clients++;
- }
- }
- if (clients == 0) {
- clients = 8;
- }
-
- if (oldclients > clients) {
- clients = oldclients;
- }
-
- trap_Cvar_Set("sv_maxClients", va("%d",clients));
-
- for (i = 0; i < PLAYERS_PER_TEAM; i++) {
- int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
- if (bot > 1) {
- if (ui_actualNetGameType.integer >= GT_TEAM) {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Blue");
- } else {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
- }
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- }
- bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
- if (bot > 1) {
- if (ui_actualNetGameType.integer >= GT_TEAM) {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Red");
- } else {
- Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
- }
- trap_Cmd_ExecuteText( EXEC_APPEND, buff );
- }
- }
- } else if (Q_stricmp(name, "updateSPMenu") == 0) {
- UI_SetCapFragLimits(qtrue);
- UI_MapCountByGameType(qtrue);
- ui_mapIndex.integer = UI_GetIndexFromSelection(ui_currentMap.integer);
- trap_Cvar_Set("ui_mapIndex", va("%d", ui_mapIndex.integer));
- Menu_SetFeederSelection(NULL, FEEDER_MAPS, ui_mapIndex.integer, "skirmish");
- UI_GameType_HandleKey(0, NULL, K_MOUSE1, qfalse);
- UI_GameType_HandleKey(0, NULL, K_MOUSE2, qfalse);
- } else if (Q_stricmp(name, "resetDefaults") == 0) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n");
- trap_Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n");
- Controls_SetDefaults();
- trap_Cvar_Set("com_introPlayed", "1" );
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" );
- } else if (Q_stricmp(name, "getCDKey") == 0) {
- char out[17];
- trap_GetCDKey(buff, 17);
- trap_Cvar_Set("cdkey1", "");
- trap_Cvar_Set("cdkey2", "");
- trap_Cvar_Set("cdkey3", "");
- trap_Cvar_Set("cdkey4", "");
- if (strlen(buff) == CDKEY_LEN) {
- Q_strncpyz(out, buff, 5);
- trap_Cvar_Set("cdkey1", out);
- Q_strncpyz(out, buff + 4, 5);
- trap_Cvar_Set("cdkey2", out);
- Q_strncpyz(out, buff + 8, 5);
- trap_Cvar_Set("cdkey3", out);
- Q_strncpyz(out, buff + 12, 5);
- trap_Cvar_Set("cdkey4", out);
- }
-
- } else if (Q_stricmp(name, "verifyCDKey") == 0) {
- buff[0] = '\0';
- Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey1"));
- Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey2"));
- Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey3"));
- Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey4"));
- trap_Cvar_Set("cdkey", buff);
- if (trap_VerifyCDKey(buff, UI_Cvar_VariableString("cdkeychecksum"))) {
- trap_Cvar_Set("ui_cdkeyvalid", "CD Key Appears to be valid.");
- trap_SetCDKey(buff);
- } else {
- trap_Cvar_Set("ui_cdkeyvalid", "CD Key does not appear to be valid.");
- }
- } else if (Q_stricmp(name, "loadArenas") == 0) {
- UI_LoadArenas();
- UI_MapCountByGameType(qfalse);
- Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, "createserver");
- } else if (Q_stricmp(name, "saveControls") == 0) {
- Controls_SetConfig(qtrue);
- } else if (Q_stricmp(name, "loadControls") == 0) {
- Controls_GetConfig();
- } else if (Q_stricmp(name, "clearError") == 0) {
- trap_Cvar_Set("com_errorMessage", "");
- } else if (Q_stricmp(name, "loadGameInfo") == 0) {
-#ifdef PRE_RELEASE_TADEMO
- UI_ParseGameInfo("demogameinfo.txt");
-#else
- UI_ParseGameInfo("gameinfo.txt");
-#endif
- UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
- } else if (Q_stricmp(name, "resetScores") == 0) {
- UI_ClearScores();
- } else if (Q_stricmp(name, "RefreshServers") == 0) {
- UI_StartServerRefresh(qtrue);
- UI_BuildServerDisplayList(qtrue);
- } else if (Q_stricmp(name, "RefreshFilter") == 0) {
- UI_StartServerRefresh(qfalse);
- UI_BuildServerDisplayList(qtrue);
- } else if (Q_stricmp(name, "RunSPDemo") == 0) {
- if (uiInfo.demoAvailable) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s_%i\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum));
- }
- } else if (Q_stricmp(name, "LoadDemos") == 0) {
- UI_LoadDemos();
- } else if (Q_stricmp(name, "LoadMovies") == 0) {
- UI_LoadMovies();
- } else if (Q_stricmp(name, "LoadMods") == 0) {
- UI_LoadMods();
- } else if (Q_stricmp(name, "playMovie") == 0) {
- if (uiInfo.previewMovie >= 0) {
- trap_CIN_StopCinematic(uiInfo.previewMovie);
- }
- trap_Cmd_ExecuteText( EXEC_APPEND, va("cinematic %s.roq 2\n", uiInfo.movieList[uiInfo.movieIndex]));
- } else if (Q_stricmp(name, "RunMod") == 0) {
- trap_Cvar_Set( "fs_game", uiInfo.modList[uiInfo.modIndex].modName);
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
- } else if (Q_stricmp(name, "RunDemo") == 0) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s\n", uiInfo.demoList[uiInfo.demoIndex]));
- } else if (Q_stricmp(name, "Quake3") == 0) {
- trap_Cvar_Set( "fs_game", "");
- trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
- } else if (Q_stricmp(name, "closeJoin") == 0) {
- if (uiInfo.serverStatus.refreshActive) {
- UI_StopServerRefresh();
- uiInfo.serverStatus.nextDisplayRefresh = 0;
- uiInfo.nextServerStatusRefresh = 0;
- uiInfo.nextFindPlayerRefresh = 0;
- UI_BuildServerDisplayList(qtrue);
- } else {
- Menus_CloseByName("joinserver");
- Menus_OpenByName("main");
- }
- } else if (Q_stricmp(name, "StopRefresh") == 0) {
- UI_StopServerRefresh();
- uiInfo.serverStatus.nextDisplayRefresh = 0;
- uiInfo.nextServerStatusRefresh = 0;
- uiInfo.nextFindPlayerRefresh = 0;
- } else if (Q_stricmp(name, "UpdateFilter") == 0) {
- if (ui_netSource.integer == AS_LOCAL) {
- UI_StartServerRefresh(qtrue);
- }
- UI_BuildServerDisplayList(qtrue);
- UI_FeederSelection(FEEDER_SERVERS, 0);
- } else if (Q_stricmp(name, "ServerStatus") == 0) {
- trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], uiInfo.serverStatusAddress, sizeof(uiInfo.serverStatusAddress));
- UI_BuildServerStatus(qtrue);
- } else if (Q_stricmp(name, "FoundPlayerServerStatus") == 0) {
- Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
- UI_BuildServerStatus(qtrue);
- Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
- } else if (Q_stricmp(name, "FindPlayer") == 0) {
- UI_BuildFindPlayerList(qtrue);
- // clear the displayed server status info
- uiInfo.serverStatusInfo.numLines = 0;
- Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
- } else if (Q_stricmp(name, "JoinServer") == 0) {
- trap_Cvar_Set("cg_thirdPerson", "0");
- trap_Cvar_Set("cg_cameraOrbit", "0");
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- if (uiInfo.serverStatus.currentServer >= 0 && uiInfo.serverStatus.currentServer < uiInfo.serverStatus.numDisplayServers) {
- trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, 1024);
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", buff ) );
- }
- } else if (Q_stricmp(name, "FoundPlayerJoinServer") == 0) {
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- if (uiInfo.currentFoundPlayerServer >= 0 && uiInfo.currentFoundPlayerServer < uiInfo.numFoundPlayerServers) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer] ) );
- }
- } else if (Q_stricmp(name, "Quit") == 0) {
- trap_Cvar_Set("ui_singlePlayerActive", "0");
- trap_Cmd_ExecuteText( EXEC_NOW, "quit");
- } else if (Q_stricmp(name, "Controls") == 0) {
- trap_Cvar_Set( "cl_paused", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- Menus_CloseAll();
- Menus_ActivateByName("setup_menu2");
- } else if (Q_stricmp(name, "Leave") == 0) {
- trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- Menus_CloseAll();
- Menus_ActivateByName("main");
- } else if (Q_stricmp(name, "ServerSort") == 0) {
- int sortColumn;
- if (Int_Parse(args, &sortColumn)) {
- // if same column we're already sorting on then flip the direction
- if (sortColumn == uiInfo.serverStatus.sortKey) {
- uiInfo.serverStatus.sortDir = !uiInfo.serverStatus.sortDir;
- }
- // make sure we sort again
- UI_ServersSort(sortColumn, qtrue);
- }
- } else if (Q_stricmp(name, "nextSkirmish") == 0) {
- UI_StartSkirmish(qtrue);
- } else if (Q_stricmp(name, "SkirmishStart") == 0) {
- UI_StartSkirmish(qfalse);
- } else if (Q_stricmp(name, "closeingame") == 0) {
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
- } else if (Q_stricmp(name, "voteMap") == 0) {
- if (ui_currentNetMap.integer >=0 && ui_currentNetMap.integer < uiInfo.mapCount) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote map %s\n",uiInfo.mapList[ui_currentNetMap.integer].mapLoadName) );
- }
- } else if (Q_stricmp(name, "voteKick") == 0) {
- if (uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote kick %s\n",uiInfo.playerNames[uiInfo.playerIndex]) );
- }
- } else if (Q_stricmp(name, "voteGame") == 0) {
- if (ui_netGameType.integer >= 0 && ui_netGameType.integer < uiInfo.numGameTypes) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote g_gametype %i\n",uiInfo.gameTypes[ui_netGameType.integer].gtEnum) );
- }
- } else if (Q_stricmp(name, "voteLeader") == 0) {
- if (uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("callteamvote leader %s\n",uiInfo.teamNames[uiInfo.teamIndex]) );
- }
- } else if (Q_stricmp(name, "addBot") == 0) {
- if (trap_Cvar_VariableValue("g_gametype") >= GT_TEAM && !GT_LMS ) {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", uiInfo.characterList[uiInfo.botIndex].name, uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") );
- } else {
- trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", UI_GetBotNameByNumber(uiInfo.botIndex), uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") );
- }
- } else if (Q_stricmp(name, "addFavorite") == 0) {
- if (ui_netSource.integer != AS_FAVORITES) {
- char name[MAX_NAME_LENGTH];
- char addr[MAX_NAME_LENGTH];
- int res;
-
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
- name[0] = addr[0] = '\0';
- Q_strncpyz(name, Info_ValueForKey(buff, "hostname"), MAX_NAME_LENGTH);
- Q_strncpyz(addr, Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
- if (strlen(name) > 0 && strlen(addr) > 0) {
- res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
- if (res == 0) {
- // server already in the list
- Com_Printf("Favorite already in list\n");
- }
- else if (res == -1) {
- // list full
- Com_Printf("Favorite list full\n");
- }
- else {
- // successfully added
- Com_Printf("Added favorite server %s\n", addr);
- }
- }
- }
- } else if (Q_stricmp(name, "deleteFavorite") == 0) {
- if (ui_netSource.integer == AS_FAVORITES) {
- char addr[MAX_NAME_LENGTH];
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
- addr[0] = '\0';
- Q_strncpyz(addr, Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
- if (strlen(addr) > 0) {
- trap_LAN_RemoveServer(AS_FAVORITES, addr);
- }
- }
- } else if (Q_stricmp(name, "createFavorite") == 0) {
- if (ui_netSource.integer == AS_FAVORITES) {
- char name[MAX_NAME_LENGTH];
- char addr[MAX_NAME_LENGTH];
- int res;
-
- name[0] = addr[0] = '\0';
- Q_strncpyz(name, UI_Cvar_VariableString("ui_favoriteName"), MAX_NAME_LENGTH);
- Q_strncpyz(addr, UI_Cvar_VariableString("ui_favoriteAddress"), MAX_NAME_LENGTH);
- if (strlen(name) > 0 && strlen(addr) > 0) {
- res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
- if (res == 0) {
- // server already in the list
- Com_Printf("Favorite already in list\n");
- }
- else if (res == -1) {
- // list full
- Com_Printf("Favorite list full\n");
- }
- else {
- // successfully added
- Com_Printf("Added favorite server %s\n", addr);
- }
- }
- }
- } else if (Q_stricmp(name, "orders") == 0) {
- const char *orders;
- if (String_Parse(args, &orders)) {
- int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
- if (selectedPlayer < uiInfo.myTeamCount) {
- strcpy(buff, orders);
- trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
- trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
- } else {
- int i;
- for (i = 0; i < uiInfo.myTeamCount; i++) {
- if (Q_stricmp(UI_Cvar_VariableString("name"), uiInfo.teamNames[i]) == 0) {
- continue;
- }
- strcpy(buff, orders);
- trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamNames[i]) );
- trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
- }
- }
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
- }
- } else if (Q_stricmp(name, "voiceOrdersTeam") == 0) {
- const char *orders;
- if (String_Parse(args, &orders)) {
- int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
- if (selectedPlayer == uiInfo.myTeamCount) {
- trap_Cmd_ExecuteText( EXEC_APPEND, orders );
- trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
- }
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
- }
- } else if (Q_stricmp(name, "voiceOrders") == 0) {
- const char *orders;
- if (String_Parse(args, &orders)) {
- int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
- if (selectedPlayer < uiInfo.myTeamCount) {
- strcpy(buff, orders);
- trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
- trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
- }
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
- }
- } else if (Q_stricmp(name, "glCustom") == 0) {
- trap_Cvar_Set("ui_glCustom", "4");
- } else if (Q_stricmp(name, "update") == 0) {
- if (String_Parse(args, &name2)) {
- UI_Update(name2);
- }
- } else if (Q_stricmp(name, "setPbClStatus") == 0) {
- int stat;
- if ( Int_Parse( args, &stat ) )
- trap_SetPbClStatus( stat );
- }
- else {
- Com_Printf("unknown UI script %s\n", name);
- }
- }
-}
-
-static void UI_GetTeamColor(vec4_t *color) {
-}
-
-/*
-==================
-UI_MapCountByGameType
-==================
-*/
-static int UI_MapCountByGameType(qboolean singlePlayer) {
- int i, c, game;
- c = 0;
- game = singlePlayer ? uiInfo.gameTypes[ui_gameType.integer].gtEnum : uiInfo.gameTypes[ui_netGameType.integer].gtEnum;
- if (game == GT_SINGLE_PLAYER) {
- game++;
- }
- if (game == GT_TEAM) {
- game = GT_FFA;
- }
-
- for (i = 0; i < uiInfo.mapCount; i++) {
- uiInfo.mapList[i].active = qfalse;
- if ( uiInfo.mapList[i].typeBits & (1 << game)) {
- if (singlePlayer) {
- if (!(uiInfo.mapList[i].typeBits & (1 << GT_SINGLE_PLAYER))) {
- continue;
- }
- }
- c++;
- uiInfo.mapList[i].active = qtrue;
- }
- }
- return c;
-}
-
-qboolean UI_hasSkinForBase(const char *base, const char *team) {
- char test[1024];
-
- Com_sprintf( test, sizeof( test ), "models/players/%s/%s/lower_default.skin", base, team );
-
- if (trap_FS_FOpenFile(test, NULL, FS_READ)) {
- return qtrue;
- }
- Com_sprintf( test, sizeof( test ), "models/players/characters/%s/%s/lower_default.skin", base, team );
-
- if (trap_FS_FOpenFile(test, NULL, FS_READ)) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-UI_MapCountByTeam
-==================
-*/
-static int UI_HeadCountByTeam(void) {
- static int init = 0;
- int i, j, k, c, tIndex;
-
- c = 0;
- if (!init) {
- for (i = 0; i < uiInfo.characterCount; i++) {
- uiInfo.characterList[i].reference = 0;
- for (j = 0; j < uiInfo.teamCount; j++) {
- if (UI_hasSkinForBase(uiInfo.characterList[i].base, uiInfo.teamList[j].teamName)) {
- uiInfo.characterList[i].reference |= (1<<j);
- }
- }
- }
- init = 1;
- }
-
- tIndex = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
-
- // do names
- for (i = 0; i < uiInfo.characterCount; i++) {
- uiInfo.characterList[i].active = qfalse;
- for(j = 0; j < TEAM_MEMBERS; j++) {
- if (uiInfo.teamList[tIndex].teamMembers[j] != NULL) {
- if (uiInfo.characterList[i].reference&(1<<tIndex)) {// && Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.characterList[i].name)==0) {
- uiInfo.characterList[i].active = qtrue;
- c++;
- break;
- }
- }
- }
- }
-
- // and then aliases
- for(j = 0; j < TEAM_MEMBERS; j++) {
- for(k = 0; k < uiInfo.aliasCount; k++) {
- if (uiInfo.aliasList[k].name != NULL) {
- if (Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.aliasList[k].name)==0) {
- for (i = 0; i < uiInfo.characterCount; i++) {
- if (uiInfo.characterList[i].headImage != -1 && uiInfo.characterList[i].reference&(1<<tIndex) && Q_stricmp(uiInfo.aliasList[k].ai, uiInfo.characterList[i].name)==0) {
- if (uiInfo.characterList[i].active == qfalse) {
- uiInfo.characterList[i].active = qtrue;
- c++;
- }
- break;
- }
- }
- }
- }
- }
- }
- return c;
-}
-
-/*
-==================
-UI_InsertServerIntoDisplayList
-==================
-*/
-static void UI_InsertServerIntoDisplayList(int num, int position) {
- int i;
-
- if (position < 0 || position > uiInfo.serverStatus.numDisplayServers ) {
- return;
- }
- //
- uiInfo.serverStatus.numDisplayServers++;
- for (i = uiInfo.serverStatus.numDisplayServers; i > position; i--) {
- uiInfo.serverStatus.displayServers[i] = uiInfo.serverStatus.displayServers[i-1];
- }
- uiInfo.serverStatus.displayServers[position] = num;
-}
-
-/*
-==================
-UI_RemoveServerFromDisplayList
-==================
-*/
-static void UI_RemoveServerFromDisplayList(int num) {
- int i, j;
-
- for (i = 0; i < uiInfo.serverStatus.numDisplayServers; i++) {
- if (uiInfo.serverStatus.displayServers[i] == num) {
- uiInfo.serverStatus.numDisplayServers--;
- for (j = i; j < uiInfo.serverStatus.numDisplayServers; j++) {
- uiInfo.serverStatus.displayServers[j] = uiInfo.serverStatus.displayServers[j+1];
- }
- return;
- }
- }
-}
-
-/*
-==================
-UI_BinaryServerInsertion
-==================
-*/
-static void UI_BinaryServerInsertion(int num) {
- int mid, offset, res, len;
-
- // use binary search to insert server
- len = uiInfo.serverStatus.numDisplayServers;
- mid = len;
- offset = 0;
- res = 0;
- while(mid > 0) {
- mid = len >> 1;
- //
- res = trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey,
- uiInfo.serverStatus.sortDir, num, uiInfo.serverStatus.displayServers[offset+mid]);
- // if equal
- if (res == 0) {
- UI_InsertServerIntoDisplayList(num, offset+mid);
- return;
- }
- // if larger
- else if (res == 1) {
- offset += mid;
- len -= mid;
- }
- // if smaller
- else {
- len -= mid;
- }
- }
- if (res == 1) {
- offset++;
- }
- UI_InsertServerIntoDisplayList(num, offset);
-}
-
-/*
-==================
-UI_BuildServerDisplayList
-==================
-*/
-static void UI_BuildServerDisplayList(qboolean force) {
- int i, count, clients, maxClients, ping, game, len, visible;
- char info[MAX_STRING_CHARS];
-// qboolean startRefresh = qtrue; TTimo: unused
- static int numinvisible;
-
- if (!(force || uiInfo.uiDC.realTime > uiInfo.serverStatus.nextDisplayRefresh)) {
- return;
- }
- // if we shouldn't reset
- if ( force == 2 ) {
- force = 0;
- }
-
- // do motd updates here too
- trap_Cvar_VariableStringBuffer( "cl_motdString", uiInfo.serverStatus.motd, sizeof(uiInfo.serverStatus.motd) );
- len = strlen(uiInfo.serverStatus.motd);
- if (len == 0) {
- strcpy(uiInfo.serverStatus.motd, "Welcome to Team Arena!");
- len = strlen(uiInfo.serverStatus.motd);
- }
- if (len != uiInfo.serverStatus.motdLen) {
- uiInfo.serverStatus.motdLen = len;
- uiInfo.serverStatus.motdWidth = -1;
- }
-
- if (force) {
- numinvisible = 0;
- // clear number of displayed servers
- uiInfo.serverStatus.numDisplayServers = 0;
- uiInfo.serverStatus.numPlayersOnServers = 0;
- // set list box index to zero
- Menu_SetFeederSelection(NULL, FEEDER_SERVERS, 0, NULL);
- // mark all servers as visible so we store ping updates for them
- trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
- }
-
- // get the server count (comes from the master)
- count = trap_LAN_GetServerCount(ui_netSource.integer);
- if (count == -1 || (ui_netSource.integer == AS_LOCAL && count == 0) ) {
- // still waiting on a response from the master
- uiInfo.serverStatus.numDisplayServers = 0;
- uiInfo.serverStatus.numPlayersOnServers = 0;
- uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 500;
- return;
- }
-
- visible = qfalse;
- for (i = 0; i < count; i++) {
- // if we already got info for this server
- if (!trap_LAN_ServerIsVisible(ui_netSource.integer, i)) {
- continue;
- }
- visible = qtrue;
- // get the ping for this server
- ping = trap_LAN_GetServerPing(ui_netSource.integer, i);
- if (ping > 0 || ui_netSource.integer == AS_FAVORITES) {
-
- trap_LAN_GetServerInfo(ui_netSource.integer, i, info, MAX_STRING_CHARS);
-
- if(trap_Cvar_VariableValue("ui_humansonly"))
- clients = atoi(Info_ValueForKey(info, "g_humanplayers"));
- else
- clients = atoi(Info_ValueForKey(info, "clients"));
- uiInfo.serverStatus.numPlayersOnServers += clients;
-
- if (ui_browserShowEmpty.integer == 0) {
- if (clients == 0) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- continue;
- }
- }
-
- if (ui_browserShowFull.integer == 0) {
- maxClients = atoi(Info_ValueForKey(info, "sv_maxclients"));
- if (clients == maxClients) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- continue;
- }
- }
-
- if (uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum != -1) {
- game = atoi(Info_ValueForKey(info, "gametype"));
- if (game != uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- continue;
- }
- }
-
- if (ui_serverFilterType.integer > 0) {
- if (Q_stricmp(Info_ValueForKey(info, "game"), serverFilters[ui_serverFilterType.integer].basedir) != 0) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- continue;
- }
- }
- // make sure we never add a favorite server twice
- if (ui_netSource.integer == AS_FAVORITES) {
- UI_RemoveServerFromDisplayList(i);
- }
- // insert the server into the list
- UI_BinaryServerInsertion(i);
- // done with this server
- if (ping > 0) {
- trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
- numinvisible++;
- }
- }
- }
-
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime;
-
- // if there were no servers visible for ping updates
- if (!visible) {
-// UI_StopServerRefresh();
-// uiInfo.serverStatus.nextDisplayRefresh = 0;
- }
-}
-
-typedef struct
-{
- char *name, *altName;
-} serverStatusCvar_t;
-
-serverStatusCvar_t serverStatusCvars[] = {
- {"sv_hostname", "Name"},
- {"Address", ""},
- {"gamename", "Game name"},
- {"g_gametype", "Game type"},
- {"mapname", "Map"},
- {"version", ""},
- {"protocol", ""},
- {"timelimit", ""},
- {"fraglimit", ""},
- {NULL, NULL}
-};
-
-/*
-==================
-UI_SortServerStatusInfo
-==================
-*/
-static void UI_SortServerStatusInfo( serverStatusInfo_t *info ) {
- int i, j, index;
- char *tmp1, *tmp2;
-
- // FIXME: if "gamename" == "baseq3" or "missionpack" then
- // replace the gametype number by FFA, CTF etc.
- //
- index = 0;
- for (i = 0; serverStatusCvars[i].name; i++) {
- for (j = 0; j < info->numLines; j++) {
- if ( !info->lines[j][1] || info->lines[j][1][0] ) {
- continue;
- }
- if ( !Q_stricmp(serverStatusCvars[i].name, info->lines[j][0]) ) {
- // swap lines
- tmp1 = info->lines[index][0];
- tmp2 = info->lines[index][3];
- info->lines[index][0] = info->lines[j][0];
- info->lines[index][3] = info->lines[j][3];
- info->lines[j][0] = tmp1;
- info->lines[j][3] = tmp2;
- //
- if ( strlen(serverStatusCvars[i].altName) ) {
- info->lines[index][0] = serverStatusCvars[i].altName;
- }
- index++;
- }
- }
- }
-}
-
-/*
-==================
-UI_GetServerStatusInfo
-==================
-*/
-static int UI_GetServerStatusInfo( const char *serverAddress, serverStatusInfo_t *info ) {
- char *p, *score, *ping, *name;
- int i, len;
-
- if (!info) {
- trap_LAN_ServerStatus( serverAddress, NULL, 0);
- return qfalse;
- }
- memset(info, 0, sizeof(*info));
- if ( trap_LAN_ServerStatus( serverAddress, info->text, sizeof(info->text)) ) {
- Q_strncpyz(info->address, serverAddress, sizeof(info->address));
- p = info->text;
- info->numLines = 0;
- info->lines[info->numLines][0] = "Address";
- info->lines[info->numLines][1] = "";
- info->lines[info->numLines][2] = "";
- info->lines[info->numLines][3] = info->address;
- info->numLines++;
- // get the cvars
- while (p && *p) {
- p = strchr(p, '\\');
- if (!p) break;
- *p++ = '\0';
- if (*p == '\\')
- break;
- info->lines[info->numLines][0] = p;
- info->lines[info->numLines][1] = "";
- info->lines[info->numLines][2] = "";
- p = strchr(p, '\\');
- if (!p) break;
- *p++ = '\0';
- info->lines[info->numLines][3] = p;
-
- info->numLines++;
- if (info->numLines >= MAX_SERVERSTATUS_LINES)
- break;
- }
- // get the player list
- if (info->numLines < MAX_SERVERSTATUS_LINES-3) {
- // empty line
- info->lines[info->numLines][0] = "";
- info->lines[info->numLines][1] = "";
- info->lines[info->numLines][2] = "";
- info->lines[info->numLines][3] = "";
- info->numLines++;
- // header
- info->lines[info->numLines][0] = "num";
- info->lines[info->numLines][1] = "score";
- info->lines[info->numLines][2] = "ping";
- info->lines[info->numLines][3] = "name";
- info->numLines++;
- // parse players
- i = 0;
- len = 0;
- while (p && *p) {
- if (*p == '\\')
- *p++ = '\0';
- if (!p)
- break;
- score = p;
- p = strchr(p, ' ');
- if (!p)
- break;
- *p++ = '\0';
- ping = p;
- p = strchr(p, ' ');
- if (!p)
- break;
- *p++ = '\0';
- name = p;
- Com_sprintf(&info->pings[len], sizeof(info->pings)-len, "%d", i);
- info->lines[info->numLines][0] = &info->pings[len];
- len += strlen(&info->pings[len]) + 1;
- info->lines[info->numLines][1] = score;
- info->lines[info->numLines][2] = ping;
- info->lines[info->numLines][3] = name;
- info->numLines++;
- if (info->numLines >= MAX_SERVERSTATUS_LINES)
- break;
- p = strchr(p, '\\');
- if (!p)
- break;
- *p++ = '\0';
- //
- i++;
- }
- }
- UI_SortServerStatusInfo( info );
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==================
-stristr
-==================
-*/
-static char *stristr(char *str, char *charset) {
- int i;
-
- while(*str) {
- for (i = 0; charset[i] && str[i]; i++) {
- if (toupper(charset[i]) != toupper(str[i])) break;
- }
- if (!charset[i]) return str;
- str++;
- }
- return NULL;
-}
-
-/*
-==================
-UI_BuildFindPlayerList
-==================
-*/
-static void UI_BuildFindPlayerList(qboolean force) {
- static int numFound, numTimeOuts;
- int i, j, resend;
- serverStatusInfo_t info;
- char name[MAX_NAME_LENGTH+2];
- char infoString[MAX_STRING_CHARS];
-
- if (!force) {
- if (!uiInfo.nextFindPlayerRefresh || uiInfo.nextFindPlayerRefresh > uiInfo.uiDC.realTime) {
- return;
- }
- }
- else {
- memset(&uiInfo.pendingServerStatus, 0, sizeof(uiInfo.pendingServerStatus));
- uiInfo.numFoundPlayerServers = 0;
- uiInfo.currentFoundPlayerServer = 0;
- trap_Cvar_VariableStringBuffer( "ui_findPlayer", uiInfo.findPlayerName, sizeof(uiInfo.findPlayerName));
- Q_CleanStr(uiInfo.findPlayerName);
- // should have a string of some length
- if (!strlen(uiInfo.findPlayerName)) {
- uiInfo.nextFindPlayerRefresh = 0;
- return;
- }
- // set resend time
- resend = ui_serverStatusTimeOut.integer / 2 - 10;
- if (resend < 50) {
- resend = 50;
- }
- trap_Cvar_Set("cl_serverStatusResendTime", va("%d", resend));
- // reset all server status requests
- trap_LAN_ServerStatus( NULL, NULL, 0);
- //
- uiInfo.numFoundPlayerServers = 1;
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
- sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
- "searching %d...", uiInfo.pendingServerStatus.num);
- numFound = 0;
- numTimeOuts++;
- }
- for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
- // if this pending server is valid
- if (uiInfo.pendingServerStatus.server[i].valid) {
- // try to get the server status for this server
- if (UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, &info ) ) {
- //
- numFound++;
- // parse through the server status lines
- for (j = 0; j < info.numLines; j++) {
- // should have ping info
- if ( !info.lines[j][2] || !info.lines[j][2][0] ) {
- continue;
- }
- // clean string first
- Q_strncpyz(name, info.lines[j][3], sizeof(name));
- Q_CleanStr(name);
- // if the player name is a substring
- if (stristr(name, uiInfo.findPlayerName)) {
- // add to found server list if we have space (always leave space for a line with the number found)
- if (uiInfo.numFoundPlayerServers < MAX_FOUNDPLAYER_SERVERS-1) {
- //
- Q_strncpyz(uiInfo.foundPlayerServerAddresses[uiInfo.numFoundPlayerServers-1],
- uiInfo.pendingServerStatus.server[i].adrstr,
- sizeof(uiInfo.foundPlayerServerAddresses[0]));
- Q_strncpyz(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
- uiInfo.pendingServerStatus.server[i].name,
- sizeof(uiInfo.foundPlayerServerNames[0]));
- uiInfo.numFoundPlayerServers++;
- }
- else {
- // can't add any more so we're done
- uiInfo.pendingServerStatus.num = uiInfo.serverStatus.numDisplayServers;
- }
- }
- }
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
- sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
- "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
- // retrieved the server status so reuse this spot
- uiInfo.pendingServerStatus.server[i].valid = qfalse;
- }
- }
- // if empty pending slot or timed out
- if (!uiInfo.pendingServerStatus.server[i].valid ||
- uiInfo.pendingServerStatus.server[i].startTime < uiInfo.uiDC.realTime - ui_serverStatusTimeOut.integer) {
- if (uiInfo.pendingServerStatus.server[i].valid) {
- numTimeOuts++;
- }
- // reset server status request for this address
- UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, NULL );
- // reuse pending slot
- uiInfo.pendingServerStatus.server[i].valid = qfalse;
- // if we didn't try to get the status of all servers in the main browser yet
- if (uiInfo.pendingServerStatus.num < uiInfo.serverStatus.numDisplayServers) {
- uiInfo.pendingServerStatus.server[i].startTime = uiInfo.uiDC.realTime;
- trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num],
- uiInfo.pendingServerStatus.server[i].adrstr, sizeof(uiInfo.pendingServerStatus.server[i].adrstr));
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num], infoString, sizeof(infoString));
- Q_strncpyz(uiInfo.pendingServerStatus.server[i].name, Info_ValueForKey(infoString, "hostname"), sizeof(uiInfo.pendingServerStatus.server[0].name));
- uiInfo.pendingServerStatus.server[i].valid = qtrue;
- uiInfo.pendingServerStatus.num++;
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
- sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
- "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
- }
- }
- }
- for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
- if (uiInfo.pendingServerStatus.server[i].valid) {
- break;
- }
- }
- // if still trying to retrieve server status info
- if (i < MAX_SERVERSTATUSREQUESTS) {
- uiInfo.nextFindPlayerRefresh = uiInfo.uiDC.realTime + 25;
- }
- else {
- // add a line that shows the number of servers found
- if (!uiInfo.numFoundPlayerServers) {
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]), "no servers found");
- }
- else {
- Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]),
- "%d server%s found with player %s", uiInfo.numFoundPlayerServers-1,
- uiInfo.numFoundPlayerServers == 2 ? "":"s", uiInfo.findPlayerName);
- }
- uiInfo.nextFindPlayerRefresh = 0;
- // show the server status info for the selected server
- UI_FeederSelection(FEEDER_FINDPLAYER, uiInfo.currentFoundPlayerServer);
- }
-}
-
-/*
-==================
-UI_BuildServerStatus
-==================
-*/
-static void UI_BuildServerStatus(qboolean force) {
-
- if (uiInfo.nextFindPlayerRefresh) {
- return;
- }
- if (!force) {
- if (!uiInfo.nextServerStatusRefresh || uiInfo.nextServerStatusRefresh > uiInfo.uiDC.realTime) {
- return;
- }
- }
- else {
- Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
- uiInfo.serverStatusInfo.numLines = 0;
- // reset all server status requests
- trap_LAN_ServerStatus( NULL, NULL, 0);
- }
- if (uiInfo.serverStatus.currentServer < 0 || uiInfo.serverStatus.currentServer > uiInfo.serverStatus.numDisplayServers || uiInfo.serverStatus.numDisplayServers == 0) {
- return;
- }
- if (UI_GetServerStatusInfo( uiInfo.serverStatusAddress, &uiInfo.serverStatusInfo ) ) {
- uiInfo.nextServerStatusRefresh = 0;
- UI_GetServerStatusInfo( uiInfo.serverStatusAddress, NULL );
- }
- else {
- uiInfo.nextServerStatusRefresh = uiInfo.uiDC.realTime + 500;
- }
-}
-
-/*
-==================
-UI_FeederCount
-==================
-*/
-static int UI_FeederCount(float feederID) {
- if (feederID == FEEDER_HEADS) {
- return UI_HeadCountByTeam();
- } else if (feederID == FEEDER_Q3HEADS) {
- return uiInfo.q3HeadCount;
- } else if (feederID == FEEDER_CINEMATICS) {
- return uiInfo.movieCount;
- } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
- return UI_MapCountByGameType(feederID == FEEDER_MAPS ? qtrue : qfalse);
- } else if (feederID == FEEDER_SERVERS) {
- return uiInfo.serverStatus.numDisplayServers;
- } else if (feederID == FEEDER_SERVERSTATUS) {
- return uiInfo.serverStatusInfo.numLines;
- } else if (feederID == FEEDER_FINDPLAYER) {
- return uiInfo.numFoundPlayerServers;
- } else if (feederID == FEEDER_PLAYER_LIST) {
- if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
- uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
- UI_BuildPlayerList();
- }
- return uiInfo.playerCount;
- } else if (feederID == FEEDER_TEAM_LIST) {
- if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
- uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
- UI_BuildPlayerList();
- }
- return uiInfo.myTeamCount;
- } else if (feederID == FEEDER_MODS) {
- return uiInfo.modCount;
- } else if (feederID == FEEDER_DEMOS) {
- return uiInfo.demoCount;
- }
- return 0;
-}
-
-static const char *UI_SelectedMap(int index, int *actual) {
- int i, c;
- c = 0;
- *actual = 0;
- for (i = 0; i < uiInfo.mapCount; i++) {
- if (uiInfo.mapList[i].active) {
- if (c == index) {
- *actual = i;
- return uiInfo.mapList[i].mapName;
- } else {
- c++;
- }
- }
- }
- return "";
-}
-
-static const char *UI_SelectedHead(int index, int *actual) {
- int i, c;
- c = 0;
- *actual = 0;
- for (i = 0; i < uiInfo.characterCount; i++) {
- if (uiInfo.characterList[i].active) {
- if (c == index) {
- *actual = i;
- return uiInfo.characterList[i].name;
- } else {
- c++;
- }
- }
- }
- return "";
-}
-
-static int UI_GetIndexFromSelection(int actual) {
- int i, c;
- c = 0;
- for (i = 0; i < uiInfo.mapCount; i++) {
- if (uiInfo.mapList[i].active) {
- if (i == actual) {
- return c;
- }
- c++;
- }
- }
- return 0;
-}
-
-static void UI_UpdatePendingPings( void ) {
- trap_LAN_ResetPings(ui_netSource.integer);
- uiInfo.serverStatus.refreshActive = qtrue;
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
-
-}
-
-static const char *UI_FeederItemText(float feederID, int index, int column, qhandle_t *handle) {
- static char info[MAX_STRING_CHARS];
- static char hostname[1024];
- static char clientBuff[32];
- static int lastColumn = -1;
- static int lastTime = 0;
- *handle = -1;
- if (feederID == FEEDER_HEADS) {
- int actual;
- return UI_SelectedHead(index, &actual);
- } else if (feederID == FEEDER_Q3HEADS) {
- if (index >= 0 && index < uiInfo.q3HeadCount) {
- return uiInfo.q3HeadNames[index];
- }
- } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
- int actual;
- return UI_SelectedMap(index, &actual);
- } else if (feederID == FEEDER_SERVERS) {
- if (index >= 0 && index < uiInfo.serverStatus.numDisplayServers) {
- int ping, game;
- if (lastColumn != column || lastTime > uiInfo.uiDC.realTime + 5000) {
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
- lastColumn = column;
- lastTime = uiInfo.uiDC.realTime;
- }
- ping = atoi(Info_ValueForKey(info, "ping"));
- if (ping == -1) {
- // if we ever see a ping that is out of date, do a server refresh
- // UI_UpdatePendingPings();
- }
- switch (column) {
- case SORT_HOST :
- if (ping <= 0) {
- return Info_ValueForKey(info, "addr");
- } else {
- if ( ui_netSource.integer == AS_LOCAL ) {
- Com_sprintf( hostname, sizeof(hostname), "%s [%s]",
- Info_ValueForKey(info, "hostname"),
- netnames[atoi(Info_ValueForKey(info, "nettype"))] );
- return hostname;
- }
- else {
- Com_sprintf( hostname, sizeof(hostname), "%s", Info_ValueForKey(info, "hostname"));
- return hostname;
- }
- }
- case SORT_MAP : return Info_ValueForKey(info, "mapname");
- case SORT_CLIENTS :
- Com_sprintf( clientBuff, sizeof(clientBuff), "%s (%s)", trap_Cvar_VariableValue("ui_humansonly")? Info_ValueForKey(info, "g_humanplayers") : Info_ValueForKey(info, "clients"), Info_ValueForKey(info, "sv_maxclients"));
- return clientBuff;
- case SORT_GAME :
- game = atoi(Info_ValueForKey(info, "gametype"));
- if (game >= 0 && game < numTeamArenaGameTypes) {
- return teamArenaGameTypes[game];
- } else {
- return "Unknown";
- }
- case SORT_PING :
- if (ping <= 0) {
- return "...";
- } else {
- return Info_ValueForKey(info, "ping");
- }
- }
- }
- } else if (feederID == FEEDER_SERVERSTATUS) {
- if ( index >= 0 && index < uiInfo.serverStatusInfo.numLines ) {
- if ( column >= 0 && column < 4 ) {
- return uiInfo.serverStatusInfo.lines[index][column];
- }
- }
- } else if (feederID == FEEDER_FINDPLAYER) {
- if ( index >= 0 && index < uiInfo.numFoundPlayerServers ) {
- //return uiInfo.foundPlayerServerAddresses[index];
- return uiInfo.foundPlayerServerNames[index];
- }
- } else if (feederID == FEEDER_PLAYER_LIST) {
- if (index >= 0 && index < uiInfo.playerCount) {
- return uiInfo.playerNames[index];
- }
- } else if (feederID == FEEDER_TEAM_LIST) {
- if (index >= 0 && index < uiInfo.myTeamCount) {
- return uiInfo.teamNames[index];
- }
- } else if (feederID == FEEDER_MODS) {
- if (index >= 0 && index < uiInfo.modCount) {
- if (uiInfo.modList[index].modDescr && *uiInfo.modList[index].modDescr) {
- return uiInfo.modList[index].modDescr;
- } else {
- return uiInfo.modList[index].modName;
- }
- }
- } else if (feederID == FEEDER_CINEMATICS) {
- if (index >= 0 && index < uiInfo.movieCount) {
- return uiInfo.movieList[index];
- }
- } else if (feederID == FEEDER_DEMOS) {
- if (index >= 0 && index < uiInfo.demoCount) {
- return uiInfo.demoList[index];
- }
- }
- return "";
-}
-
-
-static qhandle_t UI_FeederItemImage(float feederID, int index) {
- if (feederID == FEEDER_HEADS) {
- int actual;
- UI_SelectedHead(index, &actual);
- index = actual;
- if (index >= 0 && index < uiInfo.characterCount) {
- if (uiInfo.characterList[index].headImage == -1) {
- uiInfo.characterList[index].headImage = trap_R_RegisterShaderNoMip(uiInfo.characterList[index].imageName);
- }
- return uiInfo.characterList[index].headImage;
- }
- } else if (feederID == FEEDER_Q3HEADS) {
- if (index >= 0 && index < uiInfo.q3HeadCount) {
- return uiInfo.q3HeadIcons[index];
- }
- } else if (feederID == FEEDER_ALLMAPS || feederID == FEEDER_MAPS) {
- int actual;
- UI_SelectedMap(index, &actual);
- index = actual;
- if (index >= 0 && index < uiInfo.mapCount) {
- if (uiInfo.mapList[index].levelShot == -1) {
- uiInfo.mapList[index].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[index].imageName);
- }
- return uiInfo.mapList[index].levelShot;
- }
- }
- return 0;
-}
-
-static void UI_FeederSelection(float feederID, int index) {
- static char info[MAX_STRING_CHARS];
- if (feederID == FEEDER_HEADS) {
- int actual;
- UI_SelectedHead(index, &actual);
- index = actual;
- if (index >= 0 && index < uiInfo.characterCount) {
- trap_Cvar_Set( "team_model", va("%s", uiInfo.characterList[index].base));
- trap_Cvar_Set( "team_headmodel", va("*%s", uiInfo.characterList[index].name));
- updateModel = qtrue;
- }
- } else if (feederID == FEEDER_Q3HEADS) {
- if (index >= 0 && index < uiInfo.q3HeadCount) {
- trap_Cvar_Set( "model", uiInfo.q3HeadNames[index]);
- trap_Cvar_Set( "headmodel", uiInfo.q3HeadNames[index]);
- updateModel = qtrue;
- }
- } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
- int actual, map;
- map = (feederID == FEEDER_ALLMAPS) ? ui_currentNetMap.integer : ui_currentMap.integer;
- if (uiInfo.mapList[map].cinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.mapList[map].cinematic);
- uiInfo.mapList[map].cinematic = -1;
- }
- UI_SelectedMap(index, &actual);
- trap_Cvar_Set("ui_mapIndex", va("%d", index));
- ui_mapIndex.integer = index;
-
- if (feederID == FEEDER_MAPS) {
- ui_currentMap.integer = actual;
- trap_Cvar_Set("ui_currentMap", va("%d", actual));
- uiInfo.mapList[ui_currentMap.integer].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[ui_currentMap.integer].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
- trap_Cvar_Set("ui_opponentModel", uiInfo.mapList[ui_currentMap.integer].opponentName);
- updateOpponentModel = qtrue;
- } else {
- ui_currentNetMap.integer = actual;
- trap_Cvar_Set("ui_currentNetMap", va("%d", actual));
- uiInfo.mapList[ui_currentNetMap.integer].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- }
-
- } else if (feederID == FEEDER_SERVERS) {
- const char *mapName = NULL;
- uiInfo.serverStatus.currentServer = index;
- trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
- uiInfo.serverStatus.currentServerPreview = trap_R_RegisterShaderNoMip(va("levelshots/%s", Info_ValueForKey(info, "mapname")));
- if (uiInfo.serverStatus.currentServerCinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
- uiInfo.serverStatus.currentServerCinematic = -1;
- }
- mapName = Info_ValueForKey(info, "mapname");
- if (mapName && *mapName) {
- uiInfo.serverStatus.currentServerCinematic = trap_CIN_PlayCinematic(va("%s.roq", mapName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
- }
- } else if (feederID == FEEDER_SERVERSTATUS) {
- //
- } else if (feederID == FEEDER_FINDPLAYER) {
- uiInfo.currentFoundPlayerServer = index;
- //
- if ( index < uiInfo.numFoundPlayerServers-1) {
- // build a new server status for this server
- Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
- Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
- UI_BuildServerStatus(qtrue);
- }
- } else if (feederID == FEEDER_PLAYER_LIST) {
- uiInfo.playerIndex = index;
- } else if (feederID == FEEDER_TEAM_LIST) {
- uiInfo.teamIndex = index;
- } else if (feederID == FEEDER_MODS) {
- uiInfo.modIndex = index;
- } else if (feederID == FEEDER_CINEMATICS) {
- uiInfo.movieIndex = index;
- if (uiInfo.previewMovie >= 0) {
- trap_CIN_StopCinematic(uiInfo.previewMovie);
- }
- uiInfo.previewMovie = -1;
- } else if (feederID == FEEDER_DEMOS) {
- uiInfo.demoIndex = index;
- }
-}
-
-static qboolean Team_Parse(char **p) {
- char *token;
- const char *tempStr;
- int i;
-
- token = COM_ParseExt(p, qtrue);
-
- if (token[0] != '{') {
- return qfalse;
- }
-
- while ( 1 ) {
-
- token = COM_ParseExt(p, qtrue);
-
- if (Q_stricmp(token, "}") == 0) {
- return qtrue;
- }
-
- if ( !token || token[0] == 0 ) {
- return qfalse;
- }
-
- if (token[0] == '{') {
- // seven tokens per line, team name and icon, and 5 team member names
- if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamName) || !String_Parse(p, &tempStr)) {
- return qfalse;
- }
-
-
- uiInfo.teamList[uiInfo.teamCount].imageName = tempStr;
- uiInfo.teamList[uiInfo.teamCount].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[uiInfo.teamCount].imageName);
- uiInfo.teamList[uiInfo.teamCount].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[uiInfo.teamCount].imageName));
- uiInfo.teamList[uiInfo.teamCount].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[uiInfo.teamCount].imageName));
-
- uiInfo.teamList[uiInfo.teamCount].cinematic = -1;
-
- for (i = 0; i < TEAM_MEMBERS; i++) {
- uiInfo.teamList[uiInfo.teamCount].teamMembers[i] = NULL;
- if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamMembers[i])) {
- return qfalse;
- }
- }
-
- Com_Printf("Loaded team %s with team icon %s.\n", uiInfo.teamList[uiInfo.teamCount].teamName, tempStr);
- if (uiInfo.teamCount < MAX_TEAMS) {
- uiInfo.teamCount++;
- } else {
- Com_Printf("Too many teams, last team replaced!\n");
- }
- token = COM_ParseExt(p, qtrue);
- if (token[0] != '}') {
- return qfalse;
- }
- }
- }
-
- return qfalse;
-}
-
-static qboolean Character_Parse(char **p) {
- char *token;
- const char *tempStr;
-
- token = COM_ParseExt(p, qtrue);
-
- if (token[0] != '{') {
- return qfalse;
- }
-
-
- while ( 1 ) {
- token = COM_ParseExt(p, qtrue);
-
- if (Q_stricmp(token, "}") == 0) {
- return qtrue;
- }
-
- if ( !token || token[0] == 0 ) {
- return qfalse;
- }
-
- if (token[0] == '{') {
- // two tokens per line, character name and sex
- if (!String_Parse(p, &uiInfo.characterList[uiInfo.characterCount].name) || !String_Parse(p, &tempStr)) {
- return qfalse;
- }
-
- uiInfo.characterList[uiInfo.characterCount].headImage = -1;
- uiInfo.characterList[uiInfo.characterCount].imageName = String_Alloc(va("models/players/heads/%s/icon_default.tga", uiInfo.characterList[uiInfo.characterCount].name));
-
- if (tempStr && (!Q_stricmp(tempStr, "female"))) {
- uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("kyonshi"));
- } else if (tempStr && (!Q_stricmp(tempStr, "male"))) {
- uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("sergei"));
- } else {
- uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("%s",tempStr));
- }
-
- Com_Printf("Loaded %s character %s.\n", uiInfo.characterList[uiInfo.characterCount].base, uiInfo.characterList[uiInfo.characterCount].name);
- if (uiInfo.characterCount < MAX_HEADS) {
- uiInfo.characterCount++;
- } else {
- Com_Printf("Too many characters, last character replaced!\n");
- }
-
- token = COM_ParseExt(p, qtrue);
- if (token[0] != '}') {
- return qfalse;
- }
- }
- }
-
- return qfalse;
-}
-
-
-static qboolean Alias_Parse(char **p) {
- char *token;
-
- token = COM_ParseExt(p, qtrue);
-
- if (token[0] != '{') {
- return qfalse;
- }
-
- while ( 1 ) {
- token = COM_ParseExt(p, qtrue);
-
- if (Q_stricmp(token, "}") == 0) {
- return qtrue;
- }
-
- if ( !token || token[0] == 0 ) {
- return qfalse;
- }
-
- if (token[0] == '{') {
- // three tokens per line, character name, bot alias, and preferred action a - all purpose, d - defense, o - offense
- if (!String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].name) || !String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].ai) || !String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].action)) {
- return qfalse;
- }
-
- Com_Printf("Loaded character alias %s using character ai %s.\n", uiInfo.aliasList[uiInfo.aliasCount].name, uiInfo.aliasList[uiInfo.aliasCount].ai);
- if (uiInfo.aliasCount < MAX_ALIASES) {
- uiInfo.aliasCount++;
- } else {
- Com_Printf("Too many aliases, last alias replaced!\n");
- }
-
- token = COM_ParseExt(p, qtrue);
- if (token[0] != '}') {
- return qfalse;
- }
- }
- }
-
- return qfalse;
-}
-
-
-
-// mode
-// 0 - high level parsing
-// 1 - team parsing
-// 2 - character parsing
-static void UI_ParseTeamInfo(const char *teamFile) {
- char *token;
- char *p;
- char *buff = NULL;
- //static int mode = 0; TTimo: unused
-
- buff = GetMenuBuffer(teamFile);
- if (!buff) {
- return;
- }
-
- p = buff;
-
- while ( 1 ) {
- token = COM_ParseExt( &p, qtrue );
- if( !token || token[0] == 0 || token[0] == '}') {
- break;
- }
-
- if ( Q_stricmp( token, "}" ) == 0 ) {
- break;
- }
-
- if (Q_stricmp(token, "teams") == 0) {
-
- if (Team_Parse(&p)) {
- continue;
- } else {
- break;
- }
- }
-
- if (Q_stricmp(token, "characters") == 0) {
- Character_Parse(&p);
- }
-
- if (Q_stricmp(token, "aliases") == 0) {
- Alias_Parse(&p);
- }
-
- }
-
-}
-
-
-static qboolean GameType_Parse(char **p, qboolean join) {
- char *token;
-
- token = COM_ParseExt(p, qtrue);
-
- if (token[0] != '{') {
- return qfalse;
- }
-
- if (join) {
- uiInfo.numJoinGameTypes = 0;
- } else {
- uiInfo.numGameTypes = 0;
- }
-
- while ( 1 ) {
- token = COM_ParseExt(p, qtrue);
-
- if (Q_stricmp(token, "}") == 0) {
- return qtrue;
- }
-
- if ( !token || token[0] == 0 ) {
- return qfalse;
- }
-
- if (token[0] == '{') {
- // two tokens per line, character name and sex
- if (join) {
- if (!String_Parse(p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gameType) || !Int_Parse(p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gtEnum)) {
- return qfalse;
- }
- } else {
- if (!String_Parse(p, &uiInfo.gameTypes[uiInfo.numGameTypes].gameType) || !Int_Parse(p, &uiInfo.gameTypes[uiInfo.numGameTypes].gtEnum)) {
- return qfalse;
- }
- }
-
- if (join) {
- if (uiInfo.numJoinGameTypes < MAX_GAMETYPES) {
- uiInfo.numJoinGameTypes++;
- } else {
- Com_Printf("Too many net game types, last one replace!\n");
- }
- } else {
- if (uiInfo.numGameTypes < MAX_GAMETYPES) {
- uiInfo.numGameTypes++;
- } else {
- Com_Printf("Too many game types, last one replace!\n");
- }
- }
-
- token = COM_ParseExt(p, qtrue);
- if (token[0] != '}') {
- return qfalse;
- }
- }
- }
- return qfalse;
-}
-
-static qboolean MapList_Parse(char **p) {
- char *token;
-
- token = COM_ParseExt(p, qtrue);
-
- if (token[0] != '{') {
- return qfalse;
- }
-
- uiInfo.mapCount = 0;
-
- while ( 1 ) {
- token = COM_ParseExt(p, qtrue);
-
- if (Q_stricmp(token, "}") == 0) {
- return qtrue;
- }
-
- if ( !token || token[0] == 0 ) {
- return qfalse;
- }
-
- if (token[0] == '{') {
- if (!String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].mapName) || !String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].mapLoadName)
- ||!Int_Parse(p, &uiInfo.mapList[uiInfo.mapCount].teamMembers) ) {
- return qfalse;
- }
-
- if (!String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].opponentName)) {
- return qfalse;
- }
-
- uiInfo.mapList[uiInfo.mapCount].typeBits = 0;
-
- while (1) {
- token = COM_ParseExt(p, qtrue);
- if (token[0] >= '0' && token[0] <= '9') {
- uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << (token[0] - 0x030));
- if (!Int_Parse(p, &uiInfo.mapList[uiInfo.mapCount].timeToBeat[token[0] - 0x30])) {
- return qfalse;
- }
- } else {
- break;
- }
- }
-
- //mapList[mapCount].imageName = String_Alloc(va("levelshots/%s", mapList[mapCount].mapLoadName));
- //if (uiInfo.mapCount == 0) {
- // only load the first cinematic, selection loads the others
- // uiInfo.mapList[uiInfo.mapCount].cinematic = trap_CIN_PlayCinematic(va("%s.roq",uiInfo.mapList[uiInfo.mapCount].mapLoadName), qfalse, qfalse, qtrue, 0, 0, 0, 0);
- //}
- uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
- uiInfo.mapList[uiInfo.mapCount].levelShot = trap_R_RegisterShaderNoMip(va("levelshots/%s_small", uiInfo.mapList[uiInfo.mapCount].mapLoadName));
-
- if (uiInfo.mapCount < MAX_MAPS) {
- uiInfo.mapCount++;
- } else {
- Com_Printf("Too many maps, last one replaced!\n");
- }
- }
- }
- return qfalse;
-}
-
-static void UI_ParseGameInfo(const char *teamFile) {
- char *token;
- char *p;
- char *buff = NULL;
- //int mode = 0; TTimo: unused
-
- buff = GetMenuBuffer(teamFile);
- if (!buff) {
- return;
- }
-
- p = buff;
-
- while ( 1 ) {
- token = COM_ParseExt( &p, qtrue );
- if( !token || token[0] == 0 || token[0] == '}') {
- break;
- }
-
- if ( Q_stricmp( token, "}" ) == 0 ) {
- break;
- }
-
- if (Q_stricmp(token, "gametypes") == 0) {
-
- if (GameType_Parse(&p, qfalse)) {
- continue;
- } else {
- break;
- }
- }
-
- if (Q_stricmp(token, "joingametypes") == 0) {
-
- if (GameType_Parse(&p, qtrue)) {
- continue;
- } else {
- break;
- }
- }
-
- if (Q_stricmp(token, "maps") == 0) {
- // start a new menu
- MapList_Parse(&p);
- }
-
- }
-}
-
-static void UI_Pause(qboolean b) {
- if (b) {
- // pause the game and set the ui keycatcher
- trap_Cvar_Set( "cl_paused", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- } else {
- // unpause the game and clear the ui keycatcher
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- }
-}
-
-#ifndef MISSIONPACK // bk001206
-static int UI_OwnerDraw_Width(int ownerDraw) {
- // bk001205 - LCC missing return value
- return 0;
-}
-#endif
-
-static int UI_PlayCinematic(const char *name, float x, float y, float w, float h) {
- return trap_CIN_PlayCinematic(name, x, y, w, h, (CIN_loop | CIN_silent));
-}
-
-static void UI_StopCinematic(int handle) {
- if (handle >= 0) {
- trap_CIN_StopCinematic(handle);
- } else {
- handle = abs(handle);
- if (handle == UI_MAPCINEMATIC) {
- if (uiInfo.mapList[ui_currentMap.integer].cinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.mapList[ui_currentMap.integer].cinematic);
- uiInfo.mapList[ui_currentMap.integer].cinematic = -1;
- }
- } else if (handle == UI_NETMAPCINEMATIC) {
- if (uiInfo.serverStatus.currentServerCinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
- uiInfo.serverStatus.currentServerCinematic = -1;
- }
- } else if (handle == UI_CLANCINEMATIC) {
- int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
- if (i >= 0 && i < uiInfo.teamCount) {
- if (uiInfo.teamList[i].cinematic >= 0) {
- trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
- uiInfo.teamList[i].cinematic = -1;
- }
- }
- }
- }
-}
-
-static void UI_DrawCinematic(int handle, float x, float y, float w, float h) {
- trap_CIN_SetExtents(handle, x, y, w, h);
- trap_CIN_DrawCinematic(handle);
-}
-
-static void UI_RunCinematicFrame(int handle) {
- trap_CIN_RunCinematic(handle);
-}
-
-
-
-/*
-=================
-PlayerModel_BuildList
-=================
-*/
-static void UI_BuildQ3Model_List( void )
-{
- int numdirs;
- int numfiles;
- char dirlist[2048];
- char filelist[2048];
- char skinname[MAX_QPATH];
- char scratch[256];
- char* dirptr;
- char* fileptr;
- int i;
- int j, k, dirty;
- int dirlen;
- int filelen;
-
- uiInfo.q3HeadCount = 0;
-
- // iterate directory of all player models
- numdirs = trap_FS_GetFileList("models/players", "/", dirlist, 2048 );
- dirptr = dirlist;
- for (i=0; i<numdirs && uiInfo.q3HeadCount < MAX_PLAYERMODELS; i++,dirptr+=dirlen+1)
- {
- dirlen = strlen(dirptr);
-
- if (dirlen && dirptr[dirlen-1]=='/') dirptr[dirlen-1]='\0';
-
- if (!strcmp(dirptr,".") || !strcmp(dirptr,".."))
- continue;
-
- // iterate all skin files in directory
- numfiles = trap_FS_GetFileList( va("models/players/%s",dirptr), "tga", filelist, 2048 );
- fileptr = filelist;
- for (j=0; j<numfiles && uiInfo.q3HeadCount < MAX_PLAYERMODELS;j++,fileptr+=filelen+1)
- {
- filelen = strlen(fileptr);
-
- COM_StripExtension(fileptr, skinname, sizeof(skinname));
-
- // look for icon_????
- if (Q_stricmpn(skinname, "icon_", 5) == 0 && !(Q_stricmp(skinname,"icon_blue") == 0 || Q_stricmp(skinname,"icon_red") == 0))
- {
- if (Q_stricmp(skinname, "icon_default") == 0) {
- Com_sprintf( scratch, sizeof(scratch), "%s", dirptr);
- } else {
- Com_sprintf( scratch, sizeof(scratch), "%s/%s",dirptr, skinname + 5);
- }
- dirty = 0;
- for(k=0;k<uiInfo.q3HeadCount;k++) {
- if (!Q_stricmp(scratch, uiInfo.q3HeadNames[uiInfo.q3HeadCount])) {
- dirty = 1;
- break;
- }
- }
- if (!dirty) {
- Com_sprintf( uiInfo.q3HeadNames[uiInfo.q3HeadCount], sizeof(uiInfo.q3HeadNames[uiInfo.q3HeadCount]), "%s", scratch);
- uiInfo.q3HeadIcons[uiInfo.q3HeadCount++] = trap_R_RegisterShaderNoMip(va("models/players/%s/%s",dirptr,skinname));
- }
- }
-
- }
- }
-
-}
-
-
-
-/*
-=================
-UI_Init
-=================
-*/
-void _UI_Init( qboolean inGameLoad ) {
- const char *menuSet;
- int start;
-
- //uiInfo.inGameLoad = inGameLoad;
-
- UI_RegisterCvars();
- UI_InitMemory();
-
- // cache redundant calulations
- trap_GetGlconfig( &uiInfo.uiDC.glconfig );
-
- // for 640x480 virtualized screen
- uiInfo.uiDC.yscale = uiInfo.uiDC.glconfig.vidHeight * (1.0/480.0);
- uiInfo.uiDC.xscale = uiInfo.uiDC.glconfig.vidWidth * (1.0/640.0);
- if ( uiInfo.uiDC.glconfig.vidWidth * 480 > uiInfo.uiDC.glconfig.vidHeight * 640 ) {
- // wide screen
- uiInfo.uiDC.bias = 0.5 * ( uiInfo.uiDC.glconfig.vidWidth - ( uiInfo.uiDC.glconfig.vidHeight * (640.0/480.0) ) );
- }
- else {
- // no wide screen
- uiInfo.uiDC.bias = 0;
- }
-
-
- //UI_Load();
- uiInfo.uiDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
- uiInfo.uiDC.setColor = &UI_SetColor;
- uiInfo.uiDC.drawHandlePic = &UI_DrawHandlePic;
- uiInfo.uiDC.drawStretchPic = &trap_R_DrawStretchPic;
- uiInfo.uiDC.drawText = &Text_Paint;
- uiInfo.uiDC.textWidth = &Text_Width;
- uiInfo.uiDC.textHeight = &Text_Height;
- uiInfo.uiDC.registerModel = &trap_R_RegisterModel;
- uiInfo.uiDC.modelBounds = &trap_R_ModelBounds;
- uiInfo.uiDC.fillRect = &UI_FillRect;
- uiInfo.uiDC.drawRect = &_UI_DrawRect;
- uiInfo.uiDC.drawSides = &_UI_DrawSides;
- uiInfo.uiDC.drawTopBottom = &_UI_DrawTopBottom;
- uiInfo.uiDC.clearScene = &trap_R_ClearScene;
- uiInfo.uiDC.drawSides = &_UI_DrawSides;
- uiInfo.uiDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
- uiInfo.uiDC.renderScene = &trap_R_RenderScene;
- uiInfo.uiDC.registerFont = &trap_R_RegisterFont;
- uiInfo.uiDC.ownerDrawItem = &UI_OwnerDraw;
- uiInfo.uiDC.getValue = &UI_GetValue;
- uiInfo.uiDC.ownerDrawVisible = &UI_OwnerDrawVisible;
- uiInfo.uiDC.runScript = &UI_RunMenuScript;
- uiInfo.uiDC.getTeamColor = &UI_GetTeamColor;
- uiInfo.uiDC.setCVar = trap_Cvar_Set;
- uiInfo.uiDC.getCVarString = trap_Cvar_VariableStringBuffer;
- uiInfo.uiDC.getCVarValue = trap_Cvar_VariableValue;
- uiInfo.uiDC.drawTextWithCursor = &Text_PaintWithCursor;
- uiInfo.uiDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
- uiInfo.uiDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
- uiInfo.uiDC.startLocalSound = &trap_S_StartLocalSound;
- uiInfo.uiDC.ownerDrawHandleKey = &UI_OwnerDrawHandleKey;
- uiInfo.uiDC.feederCount = &UI_FeederCount;
- uiInfo.uiDC.feederItemImage = &UI_FeederItemImage;
- uiInfo.uiDC.feederItemText = &UI_FeederItemText;
- uiInfo.uiDC.feederSelection = &UI_FeederSelection;
- uiInfo.uiDC.setBinding = &trap_Key_SetBinding;
- uiInfo.uiDC.getBindingBuf = &trap_Key_GetBindingBuf;
- uiInfo.uiDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
- uiInfo.uiDC.executeText = &trap_Cmd_ExecuteText;
- uiInfo.uiDC.Error = &Com_Error;
- uiInfo.uiDC.Print = &Com_Printf;
- uiInfo.uiDC.Pause = &UI_Pause;
- uiInfo.uiDC.ownerDrawWidth = &UI_OwnerDrawWidth;
- uiInfo.uiDC.registerSound = &trap_S_RegisterSound;
- uiInfo.uiDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
- uiInfo.uiDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
- uiInfo.uiDC.playCinematic = &UI_PlayCinematic;
- uiInfo.uiDC.stopCinematic = &UI_StopCinematic;
- uiInfo.uiDC.drawCinematic = &UI_DrawCinematic;
- uiInfo.uiDC.runCinematicFrame = &UI_RunCinematicFrame;
-
- Init_Display(&uiInfo.uiDC);
-
- String_Init();
-
- uiInfo.uiDC.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
- uiInfo.uiDC.whiteShader = trap_R_RegisterShaderNoMip( "white" );
-
- AssetCache();
-
- start = trap_Milliseconds();
-
- uiInfo.teamCount = 0;
- uiInfo.characterCount = 0;
- uiInfo.aliasCount = 0;
-
-#ifdef PRE_RELEASE_TADEMO
- UI_ParseTeamInfo("demoteaminfo.txt");
- UI_ParseGameInfo("demogameinfo.txt");
-#else
- UI_ParseTeamInfo("teaminfo.txt");
- UI_LoadTeams();
- UI_ParseGameInfo("gameinfo.txt");
-#endif
-
- menuSet = UI_Cvar_VariableString("ui_menuFiles");
- if (menuSet == NULL || menuSet[0] == '\0') {
- menuSet = "ui/menus.txt";
- }
-
-#if 0
- if (uiInfo.inGameLoad) {
- UI_LoadMenus("ui/ingame.txt", qtrue);
- } else { // bk010222: left this: UI_LoadMenus(menuSet, qtrue);
- }
-#else
- UI_LoadMenus(menuSet, qtrue);
- UI_LoadMenus("ui/ingame.txt", qfalse);
-#endif
-
- Menus_CloseAll();
-
- trap_LAN_LoadCachedServers();
- UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
-
- UI_BuildQ3Model_List();
- UI_LoadBots();
-
- // sets defaults for ui temp cvars
- uiInfo.effectsColor = gamecodetoui[(int)trap_Cvar_VariableValue("color1")-1];
- uiInfo.currentCrosshair = (int)trap_Cvar_VariableValue("cg_drawCrosshair");
- trap_Cvar_Set("ui_mousePitch", (trap_Cvar_VariableValue("m_pitch") >= 0) ? "0" : "1");
-
- uiInfo.serverStatus.currentServerCinematic = -1;
- uiInfo.previewMovie = -1;
-
- if (trap_Cvar_VariableValue("ui_TeamArenaFirstRun") == 0) {
- trap_Cvar_Set("s_volume", "0.8");
- trap_Cvar_Set("s_musicvolume", "0.5");
- trap_Cvar_Set("ui_TeamArenaFirstRun", "1");
- }
-
- trap_Cvar_Register(NULL, "debug_protocol", "", 0 );
-
- trap_Cvar_Set("ui_actualNetGameType", va("%d", ui_netGameType.integer));
-}
-
-
-/*
-=================
-UI_KeyEvent
-=================
-*/
-void _UI_KeyEvent( int key, qboolean down ) {
-
- if (Menu_Count() > 0) {
- menuDef_t *menu = Menu_GetFocused();
- if (menu) {
- if (key == K_ESCAPE && down && !Menus_AnyFullScreenVisible()) {
- Menus_CloseAll();
- } else {
- Menu_HandleKey(menu, key, down );
- }
- } else {
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- }
- }
-
- //if ((s > 0) && (s != menu_null_sound)) {
- // trap_S_StartLocalSound( s, CHAN_LOCAL_SOUND );
- //}
-}
-
-/*
-=================
-UI_MouseEvent
-=================
-*/
-void _UI_MouseEvent( int dx, int dy )
-{
- // update mouse screen position
- uiInfo.uiDC.cursorx += dx;
- if (uiInfo.uiDC.cursorx < 0)
- uiInfo.uiDC.cursorx = 0;
- else if (uiInfo.uiDC.cursorx > SCREEN_WIDTH)
- uiInfo.uiDC.cursorx = SCREEN_WIDTH;
-
- uiInfo.uiDC.cursory += dy;
- if (uiInfo.uiDC.cursory < 0)
- uiInfo.uiDC.cursory = 0;
- else if (uiInfo.uiDC.cursory > SCREEN_HEIGHT)
- uiInfo.uiDC.cursory = SCREEN_HEIGHT;
-
- if (Menu_Count() > 0) {
- //menuDef_t *menu = Menu_GetFocused();
- //Menu_HandleMouseMove(menu, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
- Display_MouseMove(NULL, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
- }
-
-}
-
-void UI_LoadNonIngame( void ) {
- const char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
- if (menuSet == NULL || menuSet[0] == '\0') {
- menuSet = "ui/menus.txt";
- }
- UI_LoadMenus(menuSet, qfalse);
- uiInfo.inGameLoad = qfalse;
-}
-
-void _UI_SetActiveMenu( uiMenuCommand_t menu ) {
- char buf[256];
-
- // this should be the ONLY way the menu system is brought up
- // enusure minumum menu data is cached
- if (Menu_Count() > 0) {
- vec3_t v;
- v[0] = v[1] = v[2] = 0;
- switch ( menu ) {
- case UIMENU_NONE:
- trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
- trap_Key_ClearStates();
- trap_Cvar_Set( "cl_paused", "0" );
- Menus_CloseAll();
-
- return;
- case UIMENU_MAIN:
- trap_Cvar_Set( "sv_killserver", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- //trap_S_StartLocalSound( trap_S_RegisterSound("sound/misc/menu_background.wav", qfalse) , CHAN_LOCAL_SOUND );
- //trap_S_StartBackgroundTrack("sound/misc/menu_background.wav", NULL);
- if (uiInfo.inGameLoad) {
- UI_LoadNonIngame();
- }
- Menus_CloseAll();
- Menus_ActivateByName("main");
- trap_Cvar_VariableStringBuffer("com_errorMessage", buf, sizeof(buf));
- if (strlen(buf)) {
- if (!ui_singlePlayerActive.integer) {
- Menus_ActivateByName("error_popmenu");
- } else {
- trap_Cvar_Set("com_errorMessage", "");
- }
- }
- return;
- case UIMENU_TEAM:
- trap_Key_SetCatcher( KEYCATCH_UI );
- Menus_ActivateByName("team");
- return;
- case UIMENU_NEED_CD:
- // no cd check in TA
- //trap_Key_SetCatcher( KEYCATCH_UI );
- //Menus_ActivateByName("needcd");
- //UI_ConfirmMenu( "Insert the CD", NULL, NeedCDAction );
- return;
- case UIMENU_BAD_CD_KEY:
- // no cd check in TA
- //trap_Key_SetCatcher( KEYCATCH_UI );
- //Menus_ActivateByName("badcd");
- //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
- return;
- case UIMENU_POSTGAME:
- trap_Cvar_Set( "sv_killserver", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- if (uiInfo.inGameLoad) {
- UI_LoadNonIngame();
- }
- Menus_CloseAll();
- Menus_ActivateByName("endofgame");
- //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
- return;
- case UIMENU_INGAME:
- trap_Cvar_Set( "cl_paused", "1" );
- trap_Key_SetCatcher( KEYCATCH_UI );
- UI_BuildPlayerList();
- Menus_CloseAll();
- Menus_ActivateByName("ingame");
- return;
- }
- }
-}
-
-qboolean _UI_IsFullscreen( void ) {
- return Menus_AnyFullScreenVisible();
-}
-
-
-
-static connstate_t lastConnState;
-static char lastLoadingText[MAX_INFO_VALUE];
-
-static void UI_ReadableSize ( char *buf, int bufsize, int value )
-{
- if (value > 1024*1024*1024 ) { // gigs
- Com_sprintf( buf, bufsize, "%d", value / (1024*1024*1024) );
- Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d GB",
- (value % (1024*1024*1024))*100 / (1024*1024*1024) );
- } else if (value > 1024*1024 ) { // megs
- Com_sprintf( buf, bufsize, "%d", value / (1024*1024) );
- Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d MB",
- (value % (1024*1024))*100 / (1024*1024) );
- } else if (value > 1024 ) { // kilos
- Com_sprintf( buf, bufsize, "%d KB", value / 1024 );
- } else { // bytes
- Com_sprintf( buf, bufsize, "%d bytes", value );
- }
-}
-
-// Assumes time is in msec
-static void UI_PrintTime ( char *buf, int bufsize, int time ) {
- time /= 1000; // change to seconds
-
- if (time > 3600) { // in the hours range
- Com_sprintf( buf, bufsize, "%d hr %d min", time / 3600, (time % 3600) / 60 );
- } else if (time > 60) { // mins
- Com_sprintf( buf, bufsize, "%d min %d sec", time / 60, time % 60 );
- } else { // secs
- Com_sprintf( buf, bufsize, "%d sec", time );
- }
-}
-
-void Text_PaintCenter(float x, float y, float scale, vec4_t color, const char *text, float adjust) {
- int len = Text_Width(text, scale, 0);
- Text_Paint(x - len / 2, y, scale, color, text, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
-}
-
-void Text_PaintCenter_AutoWrapped(float x, float y, float xmax, float ystep, float scale, vec4_t color, const char *str, float adjust) {
- int width;
- char *s1,*s2,*s3;
- char c_bcp;
- char buf[1024];
-
- if (!str || str[0]=='\0')
- return;
-
- Q_strncpyz(buf, str, sizeof(buf));
- s1 = s2 = s3 = buf;
-
- while (1) {
- do {
- s3++;
- } while (*s3!=' ' && *s3!='\0');
- c_bcp = *s3;
- *s3 = '\0';
- width = Text_Width(s1, scale, 0);
- *s3 = c_bcp;
- if (width > xmax) {
- if (s1==s2)
- {
- // fuck, don't have a clean cut, we'll overflow
- s2 = s3;
- }
- *s2 = '\0';
- Text_PaintCenter(x, y, scale, color, s1, adjust);
- y += ystep;
- if (c_bcp == '\0')
- {
- // that was the last word
- // we could start a new loop, but that wouldn't be much use
- // even if the word is too long, we would overflow it (see above)
- // so just print it now if needed
- s2++;
- if (*s2 != '\0') // if we are printing an overflowing line we have s2 == s3
- Text_PaintCenter(x, y, scale, color, s2, adjust);
- break;
- }
- s2++;
- s1 = s2;
- s3 = s2;
- }
- else
- {
- s2 = s3;
- if (c_bcp == '\0') // we reached the end
- {
- Text_PaintCenter(x, y, scale, color, s1, adjust);
- break;
- }
- }
- }
-}
-
-static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, float yStart, float scale ) {
- static char dlText[] = "Downloading:";
- static char etaText[] = "Estimated time left:";
- static char xferText[] = "Transfer rate:";
-
- int downloadSize, downloadCount, downloadTime;
- char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64];
- int xferRate;
- int leftWidth;
- const char *s;
-
- downloadSize = trap_Cvar_VariableValue( "cl_downloadSize" );
- downloadCount = trap_Cvar_VariableValue( "cl_downloadCount" );
- downloadTime = trap_Cvar_VariableValue( "cl_downloadTime" );
-
- leftWidth = 320;
-
- UI_SetColor(colorWhite);
- Text_PaintCenter(centerPoint, yStart + 112, scale, colorWhite, dlText, 0);
- Text_PaintCenter(centerPoint, yStart + 192, scale, colorWhite, etaText, 0);
- Text_PaintCenter(centerPoint, yStart + 248, scale, colorWhite, xferText, 0);
-
- if (downloadSize > 0) {
- s = va( "%s (%d%%)", downloadName,
- (int)( (float)downloadCount * 100.0f / downloadSize ) );
- } else {
- s = downloadName;
- }
-
- Text_PaintCenter(centerPoint, yStart+136, scale, colorWhite, s, 0);
-
- UI_ReadableSize( dlSizeBuf, sizeof dlSizeBuf, downloadCount );
- UI_ReadableSize( totalSizeBuf, sizeof totalSizeBuf, downloadSize );
-
- if (downloadCount < 4096 || !downloadTime) {
- Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
- Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
- } else {
- if ((uiInfo.uiDC.realTime - downloadTime) / 1000) {
- xferRate = downloadCount / ((uiInfo.uiDC.realTime - downloadTime) / 1000);
- } else {
- xferRate = 0;
- }
- UI_ReadableSize( xferRateBuf, sizeof xferRateBuf, xferRate );
-
- // Extrapolate estimated completion time
- if (downloadSize && xferRate) {
- int n = downloadSize / xferRate; // estimated time for entire d/l in secs
-
- // We do it in K (/1024) because we'd overflow around 4MB
- UI_PrintTime ( dlTimeBuf, sizeof dlTimeBuf,
- (n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000);
-
- Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, dlTimeBuf, 0);
- Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
- } else {
- Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
- if (downloadSize) {
- Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
- } else {
- Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s copied)", dlSizeBuf), 0);
- }
- }
-
- if (xferRate) {
- Text_PaintCenter(leftWidth, yStart+272, scale, colorWhite, va("%s/Sec", xferRateBuf), 0);
- }
- }
-}
-
-/*
-========================
-UI_DrawConnectScreen
-
-This will also be overlaid on the cgame info screen during loading
-to prevent it from blinking away too rapidly on local or lan games.
-========================
-*/
-void UI_DrawConnectScreen( qboolean overlay ) {
- char *s;
- uiClientState_t cstate;
- char info[MAX_INFO_VALUE];
- char text[256];
- float centerPoint, yStart, scale;
-
- menuDef_t *menu = Menus_FindByName("Connect");
-
-
- if ( !overlay && menu ) {
- Menu_Paint(menu, qtrue);
- }
-
- if (!overlay) {
- centerPoint = 320;
- yStart = 130;
- scale = 0.5f;
- } else {
- centerPoint = 320;
- yStart = 32;
- scale = 0.6f;
- return;
- }
-
- // see what information we should display
- trap_GetClientState( &cstate );
-
- info[0] = '\0';
- if( trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ) ) {
- Text_PaintCenter(centerPoint, yStart, scale, colorWhite, va( "Loading %s", Info_ValueForKey( info, "mapname" )), 0);
- }
-
- if (!Q_stricmp(cstate.servername,"localhost")) {
- Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite, va("Starting up..."), ITEM_TEXTSTYLE_SHADOWEDMORE);
- } else {
- strcpy(text, va("Connecting to %s", cstate.servername));
- Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite,text , ITEM_TEXTSTYLE_SHADOWEDMORE);
- }
-
- // display global MOTD at bottom
- Text_PaintCenter(centerPoint, 600, scale, colorWhite, Info_ValueForKey( cstate.updateInfoString, "motd" ), 0);
- // print any server info (server full, bad version, etc)
- if ( cstate.connState < CA_CONNECTED ) {
- Text_PaintCenter_AutoWrapped(centerPoint, yStart + 176, 630, 20, scale, colorWhite, cstate.messageString, 0);
- }
-
- if ( lastConnState > cstate.connState ) {
- lastLoadingText[0] = '\0';
- }
- lastConnState = cstate.connState;
-
- switch ( cstate.connState ) {
- case CA_CONNECTING:
- s = va("Awaiting connection...%i", cstate.connectPacketCount);
- break;
- case CA_CHALLENGING:
- s = va("Awaiting challenge...%i", cstate.connectPacketCount);
- break;
- case CA_CONNECTED: {
- char downloadName[MAX_INFO_VALUE];
-
- trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof(downloadName) );
- if (*downloadName) {
- UI_DisplayDownloadInfo( downloadName, centerPoint, yStart, scale );
- return;
- }
- }
- s = "Awaiting gamestate...";
- break;
- case CA_LOADING:
- return;
- case CA_PRIMED:
- return;
- default:
- return;
- }
-
-
- if (Q_stricmp(cstate.servername,"localhost")) {
- Text_PaintCenter(centerPoint, yStart + 80, scale, colorWhite, s, 0);
- }
-
- // password required / connection rejected information goes here
-}
-
-
-/*
-================
-cvars
-================
-*/
-
-typedef struct {
- vmCvar_t *vmCvar;
- char *cvarName;
- char *defaultString;
- int cvarFlags;
-} cvarTable_t;
-
-vmCvar_t ui_ffa_fraglimit;
-vmCvar_t ui_ffa_timelimit;
-
-vmCvar_t ui_tourney_fraglimit;
-vmCvar_t ui_tourney_timelimit;
-
-vmCvar_t ui_team_fraglimit;
-vmCvar_t ui_team_timelimit;
-vmCvar_t ui_team_friendly;
-
-vmCvar_t ui_ctf_capturelimit;
-vmCvar_t ui_ctf_timelimit;
-vmCvar_t ui_ctf_friendly;
-
-vmCvar_t ui_arenasFile;
-vmCvar_t ui_botsFile;
-vmCvar_t ui_spScores1;
-vmCvar_t ui_spScores2;
-vmCvar_t ui_spScores3;
-vmCvar_t ui_spScores4;
-vmCvar_t ui_spScores5;
-vmCvar_t ui_spAwards;
-vmCvar_t ui_spVideos;
-vmCvar_t ui_spSkill;
-
-vmCvar_t ui_spSelection;
-
-vmCvar_t ui_browserMaster;
-vmCvar_t ui_browserGameType;
-vmCvar_t ui_browserSortKey;
-vmCvar_t ui_browserShowFull;
-vmCvar_t ui_browserShowEmpty;
-
-vmCvar_t ui_brassTime;
-vmCvar_t ui_drawCrosshair;
-vmCvar_t ui_drawCrosshairNames;
-vmCvar_t ui_marks;
-
-vmCvar_t ui_server1;
-vmCvar_t ui_server2;
-vmCvar_t ui_server3;
-vmCvar_t ui_server4;
-vmCvar_t ui_server5;
-vmCvar_t ui_server6;
-vmCvar_t ui_server7;
-vmCvar_t ui_server8;
-vmCvar_t ui_server9;
-vmCvar_t ui_server10;
-vmCvar_t ui_server11;
-vmCvar_t ui_server12;
-vmCvar_t ui_server13;
-vmCvar_t ui_server14;
-vmCvar_t ui_server15;
-vmCvar_t ui_server16;
-
-vmCvar_t ui_cdkeychecked;
-
-vmCvar_t ui_redteam;
-vmCvar_t ui_redteam1;
-vmCvar_t ui_redteam2;
-vmCvar_t ui_redteam3;
-vmCvar_t ui_redteam4;
-vmCvar_t ui_redteam5;
-vmCvar_t ui_blueteam;
-vmCvar_t ui_blueteam1;
-vmCvar_t ui_blueteam2;
-vmCvar_t ui_blueteam3;
-vmCvar_t ui_blueteam4;
-vmCvar_t ui_blueteam5;
-vmCvar_t ui_teamName;
-vmCvar_t ui_dedicated;
-vmCvar_t ui_gameType;
-vmCvar_t ui_netGameType;
-vmCvar_t ui_actualNetGameType;
-vmCvar_t ui_joinGameType;
-vmCvar_t ui_netSource;
-vmCvar_t ui_serverFilterType;
-vmCvar_t ui_opponentName;
-vmCvar_t ui_menuFiles;
-vmCvar_t ui_currentTier;
-vmCvar_t ui_currentMap;
-vmCvar_t ui_currentNetMap;
-vmCvar_t ui_mapIndex;
-vmCvar_t ui_currentOpponent;
-vmCvar_t ui_selectedPlayer;
-vmCvar_t ui_selectedPlayerName;
-vmCvar_t ui_lastServerRefresh_0;
-vmCvar_t ui_lastServerRefresh_1;
-vmCvar_t ui_lastServerRefresh_2;
-vmCvar_t ui_lastServerRefresh_3;
-vmCvar_t ui_singlePlayerActive;
-vmCvar_t ui_scoreAccuracy;
-vmCvar_t ui_scoreImpressives;
-vmCvar_t ui_scoreExcellents;
-vmCvar_t ui_scoreCaptures;
-vmCvar_t ui_scoreDefends;
-vmCvar_t ui_scoreAssists;
-vmCvar_t ui_scoreGauntlets;
-vmCvar_t ui_scoreScore;
-vmCvar_t ui_scorePerfect;
-vmCvar_t ui_scoreTeam;
-vmCvar_t ui_scoreBase;
-vmCvar_t ui_scoreTimeBonus;
-vmCvar_t ui_scoreSkillBonus;
-vmCvar_t ui_scoreShutoutBonus;
-vmCvar_t ui_scoreTime;
-vmCvar_t ui_captureLimit;
-vmCvar_t ui_fragLimit;
-vmCvar_t ui_smallFont;
-vmCvar_t ui_bigFont;
-vmCvar_t ui_findPlayer;
-vmCvar_t ui_Q3Model;
-vmCvar_t ui_hudFiles;
-vmCvar_t ui_recordSPDemo;
-vmCvar_t ui_realCaptureLimit;
-vmCvar_t ui_realWarmUp;
-vmCvar_t ui_serverStatusTimeOut;
-
-vmCvar_t ui_humansonly;
-
-
-// bk001129 - made static to avoid aliasing
-static cvarTable_t cvarTable[] = {
- { &ui_ffa_fraglimit, "ui_ffa_fraglimit", "20", CVAR_ARCHIVE },
- { &ui_ffa_timelimit, "ui_ffa_timelimit", "0", CVAR_ARCHIVE },
-
- { &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE },
- { &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE },
-
- { &ui_team_fraglimit, "ui_team_fraglimit", "0", CVAR_ARCHIVE },
- { &ui_team_timelimit, "ui_team_timelimit", "20", CVAR_ARCHIVE },
- { &ui_team_friendly, "ui_team_friendly", "1", CVAR_ARCHIVE },
-
- { &ui_ctf_capturelimit, "ui_ctf_capturelimit", "8", CVAR_ARCHIVE },
- { &ui_ctf_timelimit, "ui_ctf_timelimit", "30", CVAR_ARCHIVE },
- { &ui_ctf_friendly, "ui_ctf_friendly", "0", CVAR_ARCHIVE },
-
- { &ui_arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM },
- { &ui_botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM },
- { &ui_spScores1, "g_spScores1", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores2, "g_spScores2", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores3, "g_spScores3", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores4, "g_spScores4", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spScores5, "g_spScores5", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spAwards, "g_spAwards", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spVideos, "g_spVideos", "", CVAR_ARCHIVE | CVAR_ROM },
- { &ui_spSkill, "g_spSkill", "2", CVAR_ARCHIVE },
-
- { &ui_spSelection, "ui_spSelection", "", CVAR_ROM },
-
- { &ui_browserMaster, "ui_browserMaster", "0", CVAR_ARCHIVE },
- { &ui_browserGameType, "ui_browserGameType", "0", CVAR_ARCHIVE },
- { &ui_browserSortKey, "ui_browserSortKey", "4", CVAR_ARCHIVE },
- { &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE },
- { &ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE },
-
- { &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
- { &ui_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
- { &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
- { &ui_marks, "cg_marks", "1", CVAR_ARCHIVE },
-
- { &ui_server1, "server1", "", CVAR_ARCHIVE },
- { &ui_server2, "server2", "", CVAR_ARCHIVE },
- { &ui_server3, "server3", "", CVAR_ARCHIVE },
- { &ui_server4, "server4", "", CVAR_ARCHIVE },
- { &ui_server5, "server5", "", CVAR_ARCHIVE },
- { &ui_server6, "server6", "", CVAR_ARCHIVE },
- { &ui_server7, "server7", "", CVAR_ARCHIVE },
- { &ui_server8, "server8", "", CVAR_ARCHIVE },
- { &ui_server9, "server9", "", CVAR_ARCHIVE },
- { &ui_server10, "server10", "", CVAR_ARCHIVE },
- { &ui_server11, "server11", "", CVAR_ARCHIVE },
- { &ui_server12, "server12", "", CVAR_ARCHIVE },
- { &ui_server13, "server13", "", CVAR_ARCHIVE },
- { &ui_server14, "server14", "", CVAR_ARCHIVE },
- { &ui_server15, "server15", "", CVAR_ARCHIVE },
- { &ui_server16, "server16", "", CVAR_ARCHIVE },
- { &ui_cdkeychecked, "ui_cdkeychecked", "0", CVAR_ROM },
- { &ui_new, "ui_new", "0", CVAR_TEMP },
- { &ui_debug, "ui_debug", "0", CVAR_TEMP },
- { &ui_initialized, "ui_initialized", "0", CVAR_TEMP },
- { &ui_teamName, "ui_teamName", "Pagans", CVAR_ARCHIVE },
- { &ui_opponentName, "ui_opponentName", "Stroggs", CVAR_ARCHIVE },
- { &ui_redteam, "ui_redteam", "Pagans", CVAR_ARCHIVE },
- { &ui_blueteam, "ui_blueteam", "Stroggs", CVAR_ARCHIVE },
- { &ui_dedicated, "ui_dedicated", "0", CVAR_ARCHIVE },
- { &ui_gameType, "ui_gametype", "3", CVAR_ARCHIVE },
- { &ui_joinGameType, "ui_joinGametype", "0", CVAR_ARCHIVE },
- { &ui_netGameType, "ui_netGametype", "3", CVAR_ARCHIVE },
- { &ui_actualNetGameType, "ui_actualNetGametype", "3", CVAR_ARCHIVE },
- { &ui_redteam1, "ui_redteam1", "0", CVAR_ARCHIVE },
- { &ui_redteam2, "ui_redteam2", "0", CVAR_ARCHIVE },
- { &ui_redteam3, "ui_redteam3", "0", CVAR_ARCHIVE },
- { &ui_redteam4, "ui_redteam4", "0", CVAR_ARCHIVE },
- { &ui_redteam5, "ui_redteam5", "0", CVAR_ARCHIVE },
- { &ui_blueteam1, "ui_blueteam1", "0", CVAR_ARCHIVE },
- { &ui_blueteam2, "ui_blueteam2", "0", CVAR_ARCHIVE },
- { &ui_blueteam3, "ui_blueteam3", "0", CVAR_ARCHIVE },
- { &ui_blueteam4, "ui_blueteam4", "0", CVAR_ARCHIVE },
- { &ui_blueteam5, "ui_blueteam5", "0", CVAR_ARCHIVE },
- { &ui_netSource, "ui_netSource", "0", CVAR_ARCHIVE },
- { &ui_menuFiles, "ui_menuFiles", "ui/menus.txt", CVAR_ARCHIVE },
- { &ui_currentTier, "ui_currentTier", "0", CVAR_ARCHIVE },
- { &ui_currentMap, "ui_currentMap", "0", CVAR_ARCHIVE },
- { &ui_currentNetMap, "ui_currentNetMap", "0", CVAR_ARCHIVE },
- { &ui_mapIndex, "ui_mapIndex", "0", CVAR_ARCHIVE },
- { &ui_currentOpponent, "ui_currentOpponent", "0", CVAR_ARCHIVE },
- { &ui_selectedPlayer, "cg_selectedPlayer", "0", CVAR_ARCHIVE},
- { &ui_selectedPlayerName, "cg_selectedPlayerName", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_0, "ui_lastServerRefresh_0", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_1, "ui_lastServerRefresh_1", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_2, "ui_lastServerRefresh_2", "", CVAR_ARCHIVE},
- { &ui_lastServerRefresh_3, "ui_lastServerRefresh_3", "", CVAR_ARCHIVE},
- { &ui_singlePlayerActive, "ui_singlePlayerActive", "0", 0},
- { &ui_scoreAccuracy, "ui_scoreAccuracy", "0", CVAR_ARCHIVE},
- { &ui_scoreImpressives, "ui_scoreImpressives", "0", CVAR_ARCHIVE},
- { &ui_scoreExcellents, "ui_scoreExcellents", "0", CVAR_ARCHIVE},
- { &ui_scoreCaptures, "ui_scoreCaptures", "0", CVAR_ARCHIVE},
- { &ui_scoreDefends, "ui_scoreDefends", "0", CVAR_ARCHIVE},
- { &ui_scoreAssists, "ui_scoreAssists", "0", CVAR_ARCHIVE},
- { &ui_scoreGauntlets, "ui_scoreGauntlets", "0",CVAR_ARCHIVE},
- { &ui_scoreScore, "ui_scoreScore", "0", CVAR_ARCHIVE},
- { &ui_scorePerfect, "ui_scorePerfect", "0", CVAR_ARCHIVE},
- { &ui_scoreTeam, "ui_scoreTeam", "0 to 0", CVAR_ARCHIVE},
- { &ui_scoreBase, "ui_scoreBase", "0", CVAR_ARCHIVE},
- { &ui_scoreTime, "ui_scoreTime", "00:00", CVAR_ARCHIVE},
- { &ui_scoreTimeBonus, "ui_scoreTimeBonus", "0", CVAR_ARCHIVE},
- { &ui_scoreSkillBonus, "ui_scoreSkillBonus", "0", CVAR_ARCHIVE},
- { &ui_scoreShutoutBonus, "ui_scoreShutoutBonus", "0", CVAR_ARCHIVE},
- { &ui_fragLimit, "ui_fragLimit", "10", 0},
- { &ui_captureLimit, "ui_captureLimit", "5", 0},
- { &ui_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE},
- { &ui_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE},
- { &ui_findPlayer, "ui_findPlayer", "Sarge", CVAR_ARCHIVE},
- { &ui_Q3Model, "ui_q3model", "0", CVAR_ARCHIVE},
- { &ui_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
- { &ui_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE},
- { &ui_teamArenaFirstRun, "ui_teamArenaFirstRun", "0", CVAR_ARCHIVE},
- { &ui_realWarmUp, "g_warmup", "20", CVAR_ARCHIVE},
- { &ui_realCaptureLimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART},
- { &ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE},
- { &ui_humansonly, "ui_humansonly", "0", CVAR_ARCHIVE},
-};
-
-// bk001129 - made static to avoid aliasing
-static int cvarTableSize = sizeof(cvarTable) / sizeof(cvarTable[0]);
-
-
-/*
-=================
-UI_RegisterCvars
-=================
-*/
-void UI_RegisterCvars( void ) {
- int i;
- cvarTable_t *cv;
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );
- }
-}
-
-/*
-=================
-UI_UpdateCvars
-=================
-*/
-void UI_UpdateCvars( void ) {
- int i;
- cvarTable_t *cv;
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Update( cv->vmCvar );
- }
-}
-
-
-/*
-=================
-ArenaServers_StopRefresh
-=================
-*/
-static void UI_StopServerRefresh( void )
-{
- int count;
-
- if (!uiInfo.serverStatus.refreshActive) {
- // not currently refreshing
- return;
- }
- uiInfo.serverStatus.refreshActive = qfalse;
- Com_Printf("%d servers listed in browser with %d players.\n",
- uiInfo.serverStatus.numDisplayServers,
- uiInfo.serverStatus.numPlayersOnServers);
- count = trap_LAN_GetServerCount(ui_netSource.integer);
- if (count - uiInfo.serverStatus.numDisplayServers > 0) {
- Com_Printf("%d servers not listed due to packet loss or pings higher than %d\n",
- count - uiInfo.serverStatus.numDisplayServers,
- (int) trap_Cvar_VariableValue("cl_maxPing"));
- }
-
-}
-
-/*
-=================
-ArenaServers_MaxPing
-=================
-*/
-#ifndef MISSIONPACK // bk001206
-static int ArenaServers_MaxPing( void ) {
- int maxPing;
-
- maxPing = (int)trap_Cvar_VariableValue( "cl_maxPing" );
- if( maxPing < 100 ) {
- maxPing = 100;
- }
- return maxPing;
-}
-#endif
-
-/*
-=================
-UI_DoServerRefresh
-=================
-*/
-static void UI_DoServerRefresh( void )
-{
- qboolean wait = qfalse;
-
- if (!uiInfo.serverStatus.refreshActive) {
- return;
- }
- if (ui_netSource.integer != AS_FAVORITES) {
- if (ui_netSource.integer == AS_LOCAL) {
- if (!trap_LAN_GetServerCount(ui_netSource.integer)) {
- wait = qtrue;
- }
- } else {
- if (trap_LAN_GetServerCount(ui_netSource.integer) < 0) {
- wait = qtrue;
- }
- }
- }
-
- if (uiInfo.uiDC.realTime < uiInfo.serverStatus.refreshtime) {
- if (wait) {
- return;
- }
- }
-
- // if still trying to retrieve pings
- if (trap_LAN_UpdateVisiblePings(ui_netSource.integer)) {
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
- } else if (!wait) {
- // get the last servers in the list
- UI_BuildServerDisplayList(2);
- // stop the refresh
- UI_StopServerRefresh();
- }
- //
- UI_BuildServerDisplayList(qfalse);
-}
-
-/*
-=================
-UI_StartServerRefresh
-=================
-*/
-static void UI_StartServerRefresh(qboolean full)
-{
- char *ptr;
-
- qtime_t q;
- trap_RealTime(&q);
- trap_Cvar_Set( va("ui_lastServerRefresh_%i", ui_netSource.integer), va("%s-%i, %i at %i:%i", MonthAbbrev[q.tm_mon],q.tm_mday, 1900+q.tm_year,q.tm_hour,q.tm_min));
-
- if (!full) {
- UI_UpdatePendingPings();
- return;
- }
-
- uiInfo.serverStatus.refreshActive = qtrue;
- uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 1000;
- // clear number of displayed servers
- uiInfo.serverStatus.numDisplayServers = 0;
- uiInfo.serverStatus.numPlayersOnServers = 0;
- // mark all servers as visible so we store ping updates for them
- trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
- // reset all the pings
- trap_LAN_ResetPings(ui_netSource.integer);
- //
- if( ui_netSource.integer == AS_LOCAL ) {
- trap_Cmd_ExecuteText( EXEC_NOW, "localservers\n" );
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
- return;
- }
-
- uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 5000;
- if( ui_netSource.integer == AS_GLOBAL ) {
-
- ptr = UI_Cvar_VariableString("debug_protocol");
- if (strlen(ptr)) {
- trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers 0 %s full empty\n", ptr));
- }
- else {
- trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers 0 %d full empty\n", (int)trap_Cvar_VariableValue( "protocol" ) ) );
- }
- }
-}
-
diff --git a/game/code/ui/ui_players.c b/game/code/ui/ui_players.c
deleted file mode 100644
index 59a339c..0000000
--- a/game/code/ui/ui_players.c
+++ /dev/null
@@ -1,1379 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// ui_players.c
-
-#include "ui_local.h"
-
-
-#define UI_TIMER_GESTURE 2300
-#define UI_TIMER_JUMP 1000
-#define UI_TIMER_LAND 130
-#define UI_TIMER_WEAPON_SWITCH 300
-#define UI_TIMER_ATTACK 500
-#define UI_TIMER_MUZZLE_FLASH 20
-#define UI_TIMER_WEAPON_DELAY 250
-
-#define JUMP_HEIGHT 56
-
-#define SWINGSPEED 0.3f
-
-#define SPIN_SPEED 0.9f
-#define COAST_TIME 1000
-
-
-static int dp_realtime;
-static float jumpHeight;
-sfxHandle_t weaponChangeSound;
-
-
-/*
-===============
-UI_PlayerInfo_SetWeapon
-===============
-*/
-static void UI_PlayerInfo_SetWeapon( playerInfo_t *pi, weapon_t weaponNum ) {
- gitem_t * item;
- char path[MAX_QPATH];
-
- pi->currentWeapon = weaponNum;
-tryagain:
- pi->realWeapon = weaponNum;
- pi->weaponModel = 0;
- pi->barrelModel = 0;
- pi->flashModel = 0;
-
- if ( weaponNum == WP_NONE ) {
- return;
- }
-
- for ( item = bg_itemlist + 1; item->classname ; item++ ) {
- if ( item->giType != IT_WEAPON ) {
- continue;
- }
- if ( item->giTag == weaponNum ) {
- break;
- }
- }
-
- if ( item->classname ) {
- pi->weaponModel = trap_R_RegisterModel( item->world_model[0] );
- }
-
- if( pi->weaponModel == 0 ) {
- if( weaponNum == WP_MACHINEGUN ) {
- weaponNum = WP_NONE;
- goto tryagain;
- }
- weaponNum = WP_MACHINEGUN;
- goto tryagain;
- }
-
- if ( weaponNum == WP_MACHINEGUN || weaponNum == WP_GAUNTLET || weaponNum == WP_BFG ) {
- strcpy( path, item->world_model[0] );
- COM_StripExtension(path, path, sizeof(path));
- strcat( path, "_barrel.md3" );
- pi->barrelModel = trap_R_RegisterModel( path );
- }
-
- strcpy( path, item->world_model[0] );
- COM_StripExtension(path, path, sizeof(path));
- strcat( path, "_flash.md3" );
- pi->flashModel = trap_R_RegisterModel( path );
-
- switch( weaponNum ) {
- case WP_GAUNTLET:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_MACHINEGUN:
- MAKERGB( pi->flashDlightColor, 1, 1, 0 );
- break;
-
- case WP_SHOTGUN:
- MAKERGB( pi->flashDlightColor, 1, 1, 0 );
- break;
-
- case WP_GRENADE_LAUNCHER:
- MAKERGB( pi->flashDlightColor, 1, 0.7f, 0.5f );
- break;
-
- case WP_ROCKET_LAUNCHER:
- MAKERGB( pi->flashDlightColor, 1, 0.75f, 0 );
- break;
-
- case WP_LIGHTNING:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_RAILGUN:
- MAKERGB( pi->flashDlightColor, 1, 0.5f, 0 );
- break;
-
- case WP_PLASMAGUN:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- case WP_BFG:
- MAKERGB( pi->flashDlightColor, 1, 0.7f, 1 );
- break;
-
- case WP_GRAPPLING_HOOK:
- MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
- break;
-
- default:
- MAKERGB( pi->flashDlightColor, 1, 1, 1 );
- break;
- }
-}
-
-
-/*
-===============
-UI_ForceLegsAnim
-===============
-*/
-static void UI_ForceLegsAnim( playerInfo_t *pi, int anim ) {
- pi->legsAnim = ( ( pi->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-
- if ( anim == LEGS_JUMP ) {
- pi->legsAnimationTimer = UI_TIMER_JUMP;
- }
-}
-
-
-/*
-===============
-UI_SetLegsAnim
-===============
-*/
-static void UI_SetLegsAnim( playerInfo_t *pi, int anim ) {
- if ( pi->pendingLegsAnim ) {
- anim = pi->pendingLegsAnim;
- pi->pendingLegsAnim = 0;
- }
- UI_ForceLegsAnim( pi, anim );
-}
-
-
-/*
-===============
-UI_ForceTorsoAnim
-===============
-*/
-static void UI_ForceTorsoAnim( playerInfo_t *pi, int anim ) {
- pi->torsoAnim = ( ( pi->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
-
- if ( anim == TORSO_GESTURE ) {
- pi->torsoAnimationTimer = UI_TIMER_GESTURE;
- }
-
- if ( anim == TORSO_ATTACK || anim == TORSO_ATTACK2 ) {
- pi->torsoAnimationTimer = UI_TIMER_ATTACK;
- }
-}
-
-
-/*
-===============
-UI_SetTorsoAnim
-===============
-*/
-static void UI_SetTorsoAnim( playerInfo_t *pi, int anim ) {
- if ( pi->pendingTorsoAnim ) {
- anim = pi->pendingTorsoAnim;
- pi->pendingTorsoAnim = 0;
- }
-
- UI_ForceTorsoAnim( pi, anim );
-}
-
-
-/*
-===============
-UI_TorsoSequencing
-===============
-*/
-static void UI_TorsoSequencing( playerInfo_t *pi ) {
- int currentAnim;
-
- currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
-
- if ( pi->weapon != pi->currentWeapon ) {
- if ( currentAnim != TORSO_DROP ) {
- pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
- UI_ForceTorsoAnim( pi, TORSO_DROP );
- }
- }
-
- if ( pi->torsoAnimationTimer > 0 ) {
- return;
- }
-
- if( currentAnim == TORSO_GESTURE ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-
- if( currentAnim == TORSO_ATTACK || currentAnim == TORSO_ATTACK2 ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-
- if ( currentAnim == TORSO_DROP ) {
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
- pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
- UI_ForceTorsoAnim( pi, TORSO_RAISE );
- return;
- }
-
- if ( currentAnim == TORSO_RAISE ) {
- UI_SetTorsoAnim( pi, TORSO_STAND );
- return;
- }
-}
-
-
-/*
-===============
-UI_LegsSequencing
-===============
-*/
-static void UI_LegsSequencing( playerInfo_t *pi ) {
- int currentAnim;
-
- currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
-
- if ( pi->legsAnimationTimer > 0 ) {
- if ( currentAnim == LEGS_JUMP ) {
- jumpHeight = JUMP_HEIGHT * sin( M_PI * ( UI_TIMER_JUMP - pi->legsAnimationTimer ) / UI_TIMER_JUMP );
- }
- return;
- }
-
- if ( currentAnim == LEGS_JUMP ) {
- UI_ForceLegsAnim( pi, LEGS_LAND );
- pi->legsAnimationTimer = UI_TIMER_LAND;
- jumpHeight = 0;
- return;
- }
-
- if ( currentAnim == LEGS_LAND ) {
- UI_SetLegsAnim( pi, LEGS_IDLE );
- return;
- }
-}
-
-
-/*
-======================
-UI_PositionEntityOnTag
-======================
-*/
-static void UI_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- clipHandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
-
- // lerp the tag
- trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // cast away const because of compiler problems
- MatrixMultiply( lerped.axis, ((refEntity_t*)parent)->axis, entity->axis );
- entity->backlerp = parent->backlerp;
-}
-
-
-/*
-======================
-UI_PositionRotatedEntityOnTag
-======================
-*/
-static void UI_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- clipHandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
- vec3_t tempAxis[3];
-
- // lerp the tag
- trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // cast away const because of compiler problems
- MatrixMultiply( entity->axis, ((refEntity_t *)parent)->axis, tempAxis );
- MatrixMultiply( lerped.axis, tempAxis, entity->axis );
-}
-
-
-/*
-===============
-UI_SetLerpFrameAnimation
-===============
-*/
-static void UI_SetLerpFrameAnimation( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
- animation_t *anim;
-
- lf->animationNumber = newAnimation;
- newAnimation &= ~ANIM_TOGGLEBIT;
-
- if ( newAnimation < 0 || newAnimation >= MAX_ANIMATIONS ) {
- trap_Error( va("Bad animation number: %i", newAnimation) );
- }
-
- anim = &ci->animations[ newAnimation ];
-
- lf->animation = anim;
- lf->animationTime = lf->frameTime + anim->initialLerp;
-}
-
-
-/*
-===============
-UI_RunLerpFrame
-===============
-*/
-static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
- int f;
- animation_t *anim;
-
- // see if the animation sequence is switching
- if ( newAnimation != lf->animationNumber || !lf->animation ) {
- UI_SetLerpFrameAnimation( ci, lf, newAnimation );
- }
-
- // if we have passed the current frame, move it to
- // oldFrame and calculate a new frame
- if ( dp_realtime >= lf->frameTime ) {
- lf->oldFrame = lf->frame;
- lf->oldFrameTime = lf->frameTime;
-
- // get the next frame based on the animation
- anim = lf->animation;
- if ( dp_realtime < lf->animationTime ) {
- lf->frameTime = lf->animationTime; // initial lerp
- } else {
- lf->frameTime = lf->oldFrameTime + anim->frameLerp;
- }
- f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
- if ( f >= anim->numFrames ) {
- f -= anim->numFrames;
- if ( anim->loopFrames ) {
- f %= anim->loopFrames;
- f += anim->numFrames - anim->loopFrames;
- } else {
- f = anim->numFrames - 1;
- // the animation is stuck at the end, so it
- // can immediately transition to another sequence
- lf->frameTime = dp_realtime;
- }
- }
- lf->frame = anim->firstFrame + f;
- if ( dp_realtime > lf->frameTime ) {
- lf->frameTime = dp_realtime;
- }
- }
-
- if ( lf->frameTime > dp_realtime + 200 ) {
- lf->frameTime = dp_realtime;
- }
-
- if ( lf->oldFrameTime > dp_realtime ) {
- lf->oldFrameTime = dp_realtime;
- }
- // calculate current lerp value
- if ( lf->frameTime == lf->oldFrameTime ) {
- lf->backlerp = 0;
- } else {
- lf->backlerp = 1.0 - (float)( dp_realtime - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
- }
-}
-
-
-/*
-===============
-UI_PlayerAnimation
-===============
-*/
-static void UI_PlayerAnimation( playerInfo_t *pi, int *legsOld, int *legs, float *legsBackLerp,
- int *torsoOld, int *torso, float *torsoBackLerp ) {
-
- // legs animation
- pi->legsAnimationTimer -= uiInfo.uiDC.frameTime;
- if ( pi->legsAnimationTimer < 0 ) {
- pi->legsAnimationTimer = 0;
- }
-
- UI_LegsSequencing( pi );
-
- if ( pi->legs.yawing && ( pi->legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {
- UI_RunLerpFrame( pi, &pi->legs, LEGS_TURN );
- } else {
- UI_RunLerpFrame( pi, &pi->legs, pi->legsAnim );
- }
- *legsOld = pi->legs.oldFrame;
- *legs = pi->legs.frame;
- *legsBackLerp = pi->legs.backlerp;
-
- // torso animation
- pi->torsoAnimationTimer -= uiInfo.uiDC.frameTime;
- if ( pi->torsoAnimationTimer < 0 ) {
- pi->torsoAnimationTimer = 0;
- }
-
- UI_TorsoSequencing( pi );
-
- UI_RunLerpFrame( pi, &pi->torso, pi->torsoAnim );
- *torsoOld = pi->torso.oldFrame;
- *torso = pi->torso.frame;
- *torsoBackLerp = pi->torso.backlerp;
-}
-
-
-/*
-==================
-UI_SwingAngles
-==================
-*/
-static void UI_SwingAngles( float destination, float swingTolerance, float clampTolerance,
- float speed, float *angle, qboolean *swinging ) {
- float swing;
- float move;
- float scale;
-
- if ( !*swinging ) {
- // see if a swing should be started
- swing = AngleSubtract( *angle, destination );
- if ( swing > swingTolerance || swing < -swingTolerance ) {
- *swinging = qtrue;
- }
- }
-
- if ( !*swinging ) {
- return;
- }
-
- // modify the speed depending on the delta
- // so it doesn't seem so linear
- swing = AngleSubtract( destination, *angle );
- scale = fabs( swing );
- if ( scale < swingTolerance * 0.5 ) {
- scale = 0.5;
- } else if ( scale < swingTolerance ) {
- scale = 1.0;
- } else {
- scale = 2.0;
- }
-
- // swing towards the destination angle
- if ( swing >= 0 ) {
- move = uiInfo.uiDC.frameTime * scale * speed;
- if ( move >= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- } else if ( swing < 0 ) {
- move = uiInfo.uiDC.frameTime * scale * -speed;
- if ( move <= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- }
-
- // clamp to no more than tolerance
- swing = AngleSubtract( destination, *angle );
- if ( swing > clampTolerance ) {
- *angle = AngleMod( destination - (clampTolerance - 1) );
- } else if ( swing < -clampTolerance ) {
- *angle = AngleMod( destination + (clampTolerance - 1) );
- }
-}
-
-
-/*
-======================
-UI_MovedirAdjustment
-======================
-*/
-static float UI_MovedirAdjustment( playerInfo_t *pi ) {
- vec3_t relativeAngles;
- vec3_t moveVector;
-
- VectorSubtract( pi->viewAngles, pi->moveAngles, relativeAngles );
- AngleVectors( relativeAngles, moveVector, NULL, NULL );
- if ( Q_fabs( moveVector[0] ) < 0.01 ) {
- moveVector[0] = 0.0;
- }
- if ( Q_fabs( moveVector[1] ) < 0.01 ) {
- moveVector[1] = 0.0;
- }
-
- if ( moveVector[1] == 0 && moveVector[0] > 0 ) {
- return 0;
- }
- if ( moveVector[1] < 0 && moveVector[0] > 0 ) {
- return 22;
- }
- if ( moveVector[1] < 0 && moveVector[0] == 0 ) {
- return 45;
- }
- if ( moveVector[1] < 0 && moveVector[0] < 0 ) {
- return -22;
- }
- if ( moveVector[1] == 0 && moveVector[0] < 0 ) {
- return 0;
- }
- if ( moveVector[1] > 0 && moveVector[0] < 0 ) {
- return 22;
- }
- if ( moveVector[1] > 0 && moveVector[0] == 0 ) {
- return -45;
- }
-
- return -22;
-}
-
-
-/*
-===============
-UI_PlayerAngles
-===============
-*/
-static void UI_PlayerAngles( playerInfo_t *pi, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {
- vec3_t legsAngles, torsoAngles, headAngles;
- float dest;
- float adjust;
-
- VectorCopy( pi->viewAngles, headAngles );
- headAngles[YAW] = AngleMod( headAngles[YAW] );
- VectorClear( legsAngles );
- VectorClear( torsoAngles );
-
- // --------- yaw -------------
-
- // allow yaw to drift a bit
- if ( ( pi->legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE
- || ( pi->torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) {
- // if not standing still, always point all in the same direction
- pi->torso.yawing = qtrue; // always center
- pi->torso.pitching = qtrue; // always center
- pi->legs.yawing = qtrue; // always center
- }
-
- // adjust legs for movement dir
- adjust = UI_MovedirAdjustment( pi );
- legsAngles[YAW] = headAngles[YAW] + adjust;
- torsoAngles[YAW] = headAngles[YAW] + 0.25 * adjust;
-
-
- // torso
- UI_SwingAngles( torsoAngles[YAW], 25, 90, SWINGSPEED, &pi->torso.yawAngle, &pi->torso.yawing );
- UI_SwingAngles( legsAngles[YAW], 40, 90, SWINGSPEED, &pi->legs.yawAngle, &pi->legs.yawing );
-
- torsoAngles[YAW] = pi->torso.yawAngle;
- legsAngles[YAW] = pi->legs.yawAngle;
-
- // --------- pitch -------------
-
- // only show a fraction of the pitch angle in the torso
- if ( headAngles[PITCH] > 180 ) {
- dest = (-360 + headAngles[PITCH]) * 0.75;
- } else {
- dest = headAngles[PITCH] * 0.75;
- }
- UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching );
- torsoAngles[PITCH] = pi->torso.pitchAngle;
-
- // pull the angles back out of the hierarchial chain
- AnglesSubtract( headAngles, torsoAngles, headAngles );
- AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
- AnglesToAxis( legsAngles, legs );
- AnglesToAxis( torsoAngles, torso );
- AnglesToAxis( headAngles, head );
-}
-
-
-/*
-===============
-UI_PlayerFloatSprite
-===============
-*/
-static void UI_PlayerFloatSprite( playerInfo_t *pi, vec3_t origin, qhandle_t shader ) {
- refEntity_t ent;
-
- memset( &ent, 0, sizeof( ent ) );
- VectorCopy( origin, ent.origin );
- ent.origin[2] += 48;
- ent.reType = RT_SPRITE;
- ent.customShader = shader;
- ent.radius = 10;
- ent.renderfx = 0;
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-/*
-======================
-UI_MachinegunSpinAngle
-======================
-*/
-float UI_MachinegunSpinAngle( playerInfo_t *pi ) {
- int delta;
- float angle;
- float speed;
- int torsoAnim;
-
- delta = dp_realtime - pi->barrelTime;
- if ( pi->barrelSpinning ) {
- angle = pi->barrelAngle + delta * SPIN_SPEED;
- } else {
- if ( delta > COAST_TIME ) {
- delta = COAST_TIME;
- }
-
- speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
- angle = pi->barrelAngle + delta * speed;
- }
-
- torsoAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
- if( torsoAnim == TORSO_ATTACK2 ) {
- torsoAnim = TORSO_ATTACK;
- }
- if ( pi->barrelSpinning == !(torsoAnim == TORSO_ATTACK) ) {
- pi->barrelTime = dp_realtime;
- pi->barrelAngle = AngleMod( angle );
- pi->barrelSpinning = !!(torsoAnim == TORSO_ATTACK);
- }
-
- return angle;
-}
-
-
-/*
-===============
-UI_DrawPlayer
-===============
-*/
-void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ) {
- refdef_t refdef;
- refEntity_t legs;
- refEntity_t torso;
- refEntity_t head;
- refEntity_t gun;
- refEntity_t barrel;
- refEntity_t flash;
- vec3_t origin;
- int renderfx;
- vec3_t mins = {-16, -16, -24};
- vec3_t maxs = {16, 16, 32};
- float len;
- float xx;
-
- if ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) {
- return;
- }
-
- // this allows the ui to cache the player model on the main menu
- if (w == 0 || h == 0) {
- return;
- }
-
- dp_realtime = time;
-
- if ( pi->pendingWeapon != -1 && dp_realtime > pi->weaponTimer ) {
- pi->weapon = pi->pendingWeapon;
- pi->lastWeapon = pi->pendingWeapon;
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- if( pi->currentWeapon != pi->weapon ) {
- trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL );
- }
- }
-
- UI_AdjustFrom640( &x, &y, &w, &h );
-
- y -= jumpHeight;
-
- memset( &refdef, 0, sizeof( refdef ) );
- memset( &legs, 0, sizeof(legs) );
- memset( &torso, 0, sizeof(torso) );
- memset( &head, 0, sizeof(head) );
-
- refdef.rdflags = RDF_NOWORLDMODEL;
-
- AxisClear( refdef.viewaxis );
-
- refdef.x = x;
- refdef.y = y;
- refdef.width = w;
- refdef.height = h;
-
- refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
- xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
- refdef.fov_y = atan2( refdef.height, xx );
- refdef.fov_y *= ( 360 / (float)M_PI );
-
- // calculate distance so the player nearly fills the box
- len = 0.7 * ( maxs[2] - mins[2] );
- origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
-
- refdef.time = dp_realtime;
-
- trap_R_ClearScene();
-
- // get the rotation information
- UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis );
-
- // get the animation state (after rotation, to allow feet shuffle)
- UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp,
- &torso.oldframe, &torso.frame, &torso.backlerp );
-
- renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
-
- //
- // add the legs
- //
- legs.hModel = pi->legsModel;
- legs.customSkin = pi->legsSkin;
-
- VectorCopy( origin, legs.origin );
-
- VectorCopy( origin, legs.lightingOrigin );
- legs.renderfx = renderfx;
- VectorCopy (legs.origin, legs.oldorigin);
-
- trap_R_AddRefEntityToScene( &legs );
-
- if (!legs.hModel) {
- return;
- }
-
- //
- // add the torso
- //
- torso.hModel = pi->torsoModel;
- if (!torso.hModel) {
- return;
- }
-
- torso.customSkin = pi->torsoSkin;
-
- VectorCopy( origin, torso.lightingOrigin );
-
- UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, "tag_torso");
-
- torso.renderfx = renderfx;
-
- trap_R_AddRefEntityToScene( &torso );
-
- //
- // add the head
- //
- head.hModel = pi->headModel;
- if (!head.hModel) {
- return;
- }
- head.customSkin = pi->headSkin;
-
- VectorCopy( origin, head.lightingOrigin );
-
- UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, "tag_head");
-
- head.renderfx = renderfx;
-
- trap_R_AddRefEntityToScene( &head );
-
- //
- // add the gun
- //
- if ( pi->currentWeapon != WP_NONE ) {
- memset( &gun, 0, sizeof(gun) );
- gun.hModel = pi->weaponModel;
- VectorCopy( origin, gun.lightingOrigin );
- UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, "tag_weapon");
- gun.renderfx = renderfx;
- trap_R_AddRefEntityToScene( &gun );
- }
-
- //
- // add the spinning barrel
- //
- if ( pi->realWeapon == WP_MACHINEGUN || pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
- vec3_t angles;
-
- memset( &barrel, 0, sizeof(barrel) );
- VectorCopy( origin, barrel.lightingOrigin );
- barrel.renderfx = renderfx;
-
- barrel.hModel = pi->barrelModel;
- angles[YAW] = 0;
- angles[PITCH] = 0;
- angles[ROLL] = UI_MachinegunSpinAngle( pi );
- if( pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
- angles[PITCH] = angles[ROLL];
- angles[ROLL] = 0;
- }
- AnglesToAxis( angles, barrel.axis );
-
- UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel");
-
- trap_R_AddRefEntityToScene( &barrel );
- }
-
- //
- // add muzzle flash
- //
- if ( dp_realtime <= pi->muzzleFlashTime ) {
- if ( pi->flashModel ) {
- memset( &flash, 0, sizeof(flash) );
- flash.hModel = pi->flashModel;
- VectorCopy( origin, flash.lightingOrigin );
- UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash");
- flash.renderfx = renderfx;
- trap_R_AddRefEntityToScene( &flash );
- }
-
- // make a dlight for the flash
- if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) {
- trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), pi->flashDlightColor[0],
- pi->flashDlightColor[1], pi->flashDlightColor[2] );
- }
- }
-
- //
- // add the chat icon
- //
- if ( pi->chat ) {
- UI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) );
- }
-
- //
- // add an accent light
- //
- origin[0] -= 100; // + = behind, - = in front
- origin[1] += 100; // + = left, - = right
- origin[2] += 100; // + = above, - = below
- trap_R_AddLightToScene( origin, 500, 1.0, 1.0, 1.0 );
-
- origin[0] -= 100;
- origin[1] -= 100;
- origin[2] -= 100;
- trap_R_AddLightToScene( origin, 500, 1.0, 0.0, 0.0 );
-
- trap_R_RenderScene( &refdef );
-}
-
-/*
-==========================
-UI_FileExists
-==========================
-*/
-static qboolean UI_FileExists(const char *filename) {
- int len;
-
- len = trap_FS_FOpenFile( filename, NULL, FS_READ );
- if (len>0) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==========================
-UI_FindClientHeadFile
-==========================
-*/
-static qboolean UI_FindClientHeadFile( char *filename, int length, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) {
- char *team, *headsFolder;
- int i;
-
- team = "default";
-
- if ( headModelName[0] == '*' ) {
- headsFolder = "heads/";
- headModelName++;
- }
- else {
- headsFolder = "";
- }
- while(1) {
- for ( i = 0; i < 2; i++ ) {
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s/%s%s_%s.%s", headsFolder, headModelName, headSkinName, teamName, base, team, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s/%s_%s.%s", headsFolder, headModelName, headSkinName, base, team, ext );
- }
- if ( UI_FileExists( filename ) ) {
- return qtrue;
- }
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, headSkinName, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, headSkinName, ext );
- }
- if ( UI_FileExists( filename ) ) {
- return qtrue;
- }
- if ( !teamName || !*teamName ) {
- break;
- }
- }
- // if tried the heads folder first
- if ( headsFolder[0] ) {
- break;
- }
- headsFolder = "heads/";
- }
-
- return qfalse;
-}
-
-/*
-==========================
-UI_RegisterClientSkin
-==========================
-*/
-static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName , const char *teamName) {
- char filename[MAX_QPATH*2];
-
- if (teamName && *teamName) {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/%s/lower_%s.skin", modelName, teamName, skinName );
- } else {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName );
- }
- pi->legsSkin = trap_R_RegisterSkin( filename );
- if (!pi->legsSkin) {
- if (teamName && *teamName) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%s/lower_%s.skin", modelName, teamName, skinName );
- } else {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower_%s.skin", modelName, skinName );
- }
- pi->legsSkin = trap_R_RegisterSkin( filename );
- }
-
- if (teamName && *teamName) {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/%s/upper_%s.skin", modelName, teamName, skinName );
- } else {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName );
- }
- pi->torsoSkin = trap_R_RegisterSkin( filename );
- if (!pi->torsoSkin) {
- if (teamName && *teamName) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%s/upper_%s.skin", modelName, teamName, skinName );
- } else {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper_%s.skin", modelName, skinName );
- }
- pi->torsoSkin = trap_R_RegisterSkin( filename );
- }
-
- if ( UI_FindClientHeadFile( filename, sizeof(filename), teamName, headModelName, headSkinName, "head", "skin" ) ) {
- pi->headSkin = trap_R_RegisterSkin( filename );
- }
-
- if ( !pi->legsSkin || !pi->torsoSkin || !pi->headSkin ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-======================
-UI_ParseAnimationFile
-======================
-*/
-static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) {
- char *text_p, *prev;
- int len;
- int i;
- char *token;
- float fps;
- int skip;
- char text[20000];
- fileHandle_t f;
-
- memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS );
-
- // load the file
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( len <= 0 ) {
- return qfalse;
- }
- if ( len >= ( sizeof( text ) - 1 ) ) {
- Com_Printf( "File %s too long\n", filename );
- trap_FS_FCloseFile( f );
- return qfalse;
- }
- trap_FS_Read( text, len, f );
- text[len] = 0;
- trap_FS_FCloseFile( f );
-
- COM_Compress(text);
-
- // parse the text
- text_p = text;
- skip = 0; // quite the compiler warning
-
- // read optional parameters
- while ( 1 ) {
- prev = text_p; // so we can unget
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( !Q_stricmp( token, "footsteps" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- continue;
- } else if ( !Q_stricmp( token, "headoffset" ) ) {
- for ( i = 0 ; i < 3 ; i++ ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- }
- continue;
- } else if ( !Q_stricmp( token, "sex" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- continue;
- }
-
- // if it is a number, start parsing animations
- if ( token[0] >= '0' && token[0] <= '9' ) {
- text_p = prev; // unget the token
- break;
- }
-
- Com_Printf( "unknown token '%s' is %s\n", token, filename );
- }
-
- // read information for each frame
- for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].firstFrame = atoi( token );
- // leg only frames are adjusted to not count the upper body only frames
- if ( i == LEGS_WALKCR ) {
- skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
- }
- if ( i >= LEGS_WALKCR ) {
- animations[i].firstFrame -= skip;
- }
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].numFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- animations[i].loopFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- fps = atof( token );
- if ( fps == 0 ) {
- fps = 1;
- }
- animations[i].frameLerp = 1000 / fps;
- animations[i].initialLerp = 1000 / fps;
- }
-
- if ( i != MAX_ANIMATIONS ) {
- Com_Printf( "Error parsing animation file: %s", filename );
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-==========================
-UI_RegisterClientModelname
-==========================
-*/
-qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName, const char *headModelSkinName, const char *teamName ) {
- char modelName[MAX_QPATH];
- char skinName[MAX_QPATH];
- char headModelName[MAX_QPATH];
- char headSkinName[MAX_QPATH];
- char filename[MAX_QPATH];
- char *slash;
-
- pi->torsoModel = 0;
- pi->headModel = 0;
-
- if ( !modelSkinName[0] ) {
- return qfalse;
- }
-
- Q_strncpyz( modelName, modelSkinName, sizeof( modelName ) );
-
- slash = strchr( modelName, '/' );
- if ( !slash ) {
- // modelName did not include a skin name
- Q_strncpyz( skinName, "default", sizeof( skinName ) );
- } else {
- Q_strncpyz( skinName, slash + 1, sizeof( skinName ) );
- *slash = '\0';
- }
-
- Q_strncpyz( headModelName, headModelSkinName, sizeof( headModelName ) );
- slash = strchr( headModelName, '/' );
- if ( !slash ) {
- // modelName did not include a skin name
- Q_strncpyz( headSkinName, "default", sizeof( skinName ) );
- } else {
- Q_strncpyz( headSkinName, slash + 1, sizeof( skinName ) );
- *slash = '\0';
- }
-
- // load cmodels before models so filecache works
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
- pi->legsModel = trap_R_RegisterModel( filename );
- if ( !pi->legsModel ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower.md3", modelName );
- pi->legsModel = trap_R_RegisterModel( filename );
- if ( !pi->legsModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
- }
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
- pi->torsoModel = trap_R_RegisterModel( filename );
- if ( !pi->torsoModel ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper.md3", modelName );
- pi->torsoModel = trap_R_RegisterModel( filename );
- if ( !pi->torsoModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
- }
-
- if (headModelName[0] == '*' ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", &headModelName[1], &headModelName[1] );
- }
- else {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headModelName );
- }
- pi->headModel = trap_R_RegisterModel( filename );
- if ( !pi->headModel && headModelName[0] != '*') {
- Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", headModelName, headModelName );
- pi->headModel = trap_R_RegisterModel( filename );
- }
-
- if (!pi->headModel) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
-
- // if any skins failed to load, fall back to default
- if ( !UI_RegisterClientSkin( pi, modelName, skinName, headModelName, headSkinName, teamName) ) {
- if ( !UI_RegisterClientSkin( pi, modelName, "default", headModelName, "default", teamName ) ) {
- Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName );
- return qfalse;
- }
- }
-
- // load the animations
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
- if ( !UI_ParseAnimationFile( filename, pi->animations ) ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName );
- if ( !UI_ParseAnimationFile( filename, pi->animations ) ) {
- Com_Printf( "Failed to load animation file %s\n", filename );
- return qfalse;
- }
- }
-
- return qtrue;
-}
-
-
-/*
-===============
-UI_PlayerInfo_SetModel
-===============
-*/
-void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model, const char *headmodel, char *teamName ) {
- memset( pi, 0, sizeof(*pi) );
- UI_RegisterClientModelname( pi, model, headmodel, teamName );
- pi->weapon = WP_MACHINEGUN;
- pi->currentWeapon = pi->weapon;
- pi->lastWeapon = pi->weapon;
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- pi->chat = qfalse;
- pi->newModel = qtrue;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
-}
-
-
-/*
-===============
-UI_PlayerInfo_SetInfo
-===============
-*/
-void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) {
- int currentAnim;
- weapon_t weaponNum;
-
- pi->chat = chat;
-
- // view angles
- VectorCopy( viewAngles, pi->viewAngles );
-
- // move angles
- VectorCopy( moveAngles, pi->moveAngles );
-
- if ( pi->newModel ) {
- pi->newModel = qfalse;
-
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
- pi->legs.yawAngle = viewAngles[YAW];
- pi->legs.yawing = qfalse;
-
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
- pi->torso.yawAngle = viewAngles[YAW];
- pi->torso.yawing = qfalse;
-
- if ( weaponNumber != -1 ) {
- pi->weapon = weaponNumber;
- pi->currentWeapon = weaponNumber;
- pi->lastWeapon = weaponNumber;
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
- }
-
- return;
- }
-
- // weapon
- if ( weaponNumber == -1 ) {
- pi->pendingWeapon = -1;
- pi->weaponTimer = 0;
- }
- else if ( weaponNumber != WP_NONE ) {
- pi->pendingWeapon = weaponNumber;
- pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY;
- }
- weaponNum = pi->lastWeapon;
- pi->weapon = weaponNum;
-
- if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) {
- torsoAnim = legsAnim = BOTH_DEATH1;
- pi->weapon = pi->currentWeapon = WP_NONE;
- UI_PlayerInfo_SetWeapon( pi, pi->weapon );
-
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
-
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
-
- return;
- }
-
- // leg animation
- currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
- if ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) {
- pi->pendingLegsAnim = legsAnim;
- }
- else if ( legsAnim != currentAnim ) {
- jumpHeight = 0;
- pi->pendingLegsAnim = 0;
- UI_ForceLegsAnim( pi, legsAnim );
- }
-
- // torso animation
- if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) {
- if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
- torsoAnim = TORSO_STAND2;
- }
- else {
- torsoAnim = TORSO_STAND;
- }
- }
-
- if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) {
- if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
- torsoAnim = TORSO_ATTACK2;
- }
- else {
- torsoAnim = TORSO_ATTACK;
- }
- pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH;
- //FIXME play firing sound here
- }
-
- currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
-
- if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) {
- pi->pendingTorsoAnim = torsoAnim;
- }
- else if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) {
- pi->pendingTorsoAnim = torsoAnim;
- }
- else if ( torsoAnim != currentAnim ) {
- pi->pendingTorsoAnim = 0;
- UI_ForceTorsoAnim( pi, torsoAnim );
- }
-}
diff --git a/game/code/ui/ui_shared.c b/game/code/ui/ui_shared.c
deleted file mode 100644
index f632096..0000000
--- a/game/code/ui/ui_shared.c
+++ /dev/null
@@ -1,5783 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// string allocation/managment
-
-#include "ui_shared.h"
-
-#define SCROLL_TIME_START 500
-#define SCROLL_TIME_ADJUST 150
-#define SCROLL_TIME_ADJUSTOFFSET 40
-#define SCROLL_TIME_FLOOR 20
-
-typedef struct scrollInfo_s {
- int nextScrollTime;
- int nextAdjustTime;
- int adjustValue;
- int scrollKey;
- float xStart;
- float yStart;
- itemDef_t *item;
- qboolean scrollDir;
-} scrollInfo_t;
-
-static scrollInfo_t scrollInfo;
-
-static void (*captureFunc) (void *p) = 0;
-static void *captureData = NULL;
-static itemDef_t *itemCapture = NULL; // item that has the mouse captured ( if any )
-
-displayContextDef_t *DC = NULL;
-
-static qboolean g_waitingForKey = qfalse;
-static qboolean g_editingField = qfalse;
-
-static itemDef_t *g_bindItem = NULL;
-static itemDef_t *g_editItem = NULL;
-
-menuDef_t Menus[MAX_MENUS]; // defined menus
-int menuCount = 0; // how many
-
-menuDef_t *menuStack[MAX_OPEN_MENUS];
-int openMenuCount = 0;
-
-static qboolean debugMode = qfalse;
-
-#define DOUBLE_CLICK_DELAY 300
-static int lastListBoxClickTime = 0;
-
-void Item_RunScript(itemDef_t *item, const char *s);
-void Item_SetupKeywordHash(void);
-void Menu_SetupKeywordHash(void);
-int BindingIDFromName(const char *name);
-qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down);
-itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu);
-itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu);
-static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y);
-
-#ifdef CGAME
-#define MEM_POOL_SIZE 128 * 1024
-#else
-#define MEM_POOL_SIZE 1024 * 1024
-#endif
-
-static char memoryPool[MEM_POOL_SIZE];
-static int allocPoint, outOfMemory;
-
-
-/*
-===============
-UI_Alloc
-===============
-*/
-void *UI_Alloc( int size ) {
- char *p;
-
- if ( allocPoint + size > MEM_POOL_SIZE ) {
- outOfMemory = qtrue;
- if (DC->Print) {
- DC->Print("UI_Alloc: Failure. Out of memory!\n");
- }
- //DC->trap_Print(S_COLOR_YELLOW"WARNING: UI Out of Memory!\n");
- return NULL;
- }
-
- p = &memoryPool[allocPoint];
-
- allocPoint += ( size + 15 ) & ~15;
-
- return p;
-}
-
-/*
-===============
-UI_InitMemory
-===============
-*/
-void UI_InitMemory( void ) {
- allocPoint = 0;
- outOfMemory = qfalse;
-}
-
-qboolean UI_OutOfMemory( void ) {
- return outOfMemory;
-}
-
-
-
-
-
-#define HASH_TABLE_SIZE 2048
-/*
-================
-return a hash value for the string
-================
-*/
-static unsigned hashForString(const char *str) {
- int i;
- unsigned hash;
- char letter;
-
- hash = 0;
- i = 0;
- while (str[i] != '\0') {
- letter = tolower(str[i]);
- hash+=(unsigned)(letter)*(i+119);
- i++;
- }
- hash &= (HASH_TABLE_SIZE-1);
- return hash;
-}
-
-typedef struct stringDef_s {
- struct stringDef_s *next;
- const char *str;
-} stringDef_t;
-
-static int strPoolIndex = 0;
-static char strPool[STRING_POOL_SIZE];
-
-static int strHandleCount = 0;
-static stringDef_t *strHandle[HASH_TABLE_SIZE];
-
-
-const char *String_Alloc(const char *p) {
- int len;
- unsigned hash;
- stringDef_t *str, *last;
- static const char *staticNULL = "";
-
- if (p == NULL) {
- return NULL;
- }
-
- if (*p == 0) {
- return staticNULL;
- }
-
- hash = hashForString(p);
-
- str = strHandle[hash];
- while (str) {
- if (strcmp(p, str->str) == 0) {
- return str->str;
- }
- str = str->next;
- }
-
- len = strlen(p);
- if (len + strPoolIndex + 1 < STRING_POOL_SIZE) {
- int ph = strPoolIndex;
- strcpy(&strPool[strPoolIndex], p);
- strPoolIndex += len + 1;
-
- str = strHandle[hash];
- last = str;
- while (str && str->next) {
- last = str;
- str = str->next;
- }
-
- str = UI_Alloc(sizeof(stringDef_t));
- str->next = NULL;
- str->str = &strPool[ph];
- if (last) {
- last->next = str;
- } else {
- strHandle[hash] = str;
- }
- return &strPool[ph];
- }
- return NULL;
-}
-
-void String_Report(void) {
- float f;
- Com_Printf("Memory/String Pool Info\n");
- Com_Printf("----------------\n");
- f = strPoolIndex;
- f /= STRING_POOL_SIZE;
- f *= 100;
- Com_Printf("String Pool is %.1f%% full, %i bytes out of %i used.\n", f, strPoolIndex, STRING_POOL_SIZE);
- f = allocPoint;
- f /= MEM_POOL_SIZE;
- f *= 100;
- Com_Printf("Memory Pool is %.1f%% full, %i bytes out of %i used.\n", f, allocPoint, MEM_POOL_SIZE);
-}
-
-/*
-=================
-String_Init
-=================
-*/
-void String_Init(void) {
- int i;
- for (i = 0; i < HASH_TABLE_SIZE; i++) {
- strHandle[i] = NULL;
- }
- strHandleCount = 0;
- strPoolIndex = 0;
- menuCount = 0;
- openMenuCount = 0;
- UI_InitMemory();
- Item_SetupKeywordHash();
- Menu_SetupKeywordHash();
- if (DC && DC->getBindingBuf) {
- Controls_GetConfig();
- }
-}
-
-/*
-=================
-PC_SourceWarning
-=================
-*/
-void PC_SourceWarning(int handle, char *format, ...) {
- int line;
- char filename[128];
- va_list argptr;
- static char string[4096];
-
- va_start (argptr, format);
- Q_vsnprintf (string, sizeof(string), format, argptr);
- va_end (argptr);
-
- filename[0] = '\0';
- line = 0;
- trap_PC_SourceFileAndLine(handle, filename, &line);
-
- Com_Printf(S_COLOR_YELLOW "WARNING: %s, line %d: %s\n", filename, line, string);
-}
-
-/*
-=================
-PC_SourceError
-=================
-*/
-void PC_SourceError(int handle, char *format, ...) {
- int line;
- char filename[128];
- va_list argptr;
- static char string[4096];
-
- va_start (argptr, format);
- Q_vsnprintf (string, sizeof(string), format, argptr);
- va_end (argptr);
-
- filename[0] = '\0';
- line = 0;
- trap_PC_SourceFileAndLine(handle, filename, &line);
-
- Com_Printf(S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string);
-}
-
-/*
-=================
-LerpColor
-=================
-*/
-void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)
-{
- int i;
-
- // lerp and clamp each component
- for (i=0; i<4; i++)
- {
- c[i] = a[i] + t*(b[i]-a[i]);
- if (c[i] < 0)
- c[i] = 0;
- else if (c[i] > 1.0)
- c[i] = 1.0;
- }
-}
-
-/*
-=================
-Float_Parse
-=================
-*/
-qboolean Float_Parse(char **p, float *f) {
- char *token;
- token = COM_ParseExt(p, qfalse);
- if (token && token[0] != 0) {
- *f = atof(token);
- return qtrue;
- } else {
- return qfalse;
- }
-}
-
-/*
-=================
-PC_Float_Parse
-=================
-*/
-qboolean PC_Float_Parse(int handle, float *f) {
- pc_token_t token;
- int negative = qfalse;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (token.string[0] == '-') {
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- negative = qtrue;
- }
- if (token.type != TT_NUMBER) {
- PC_SourceError(handle, "expected float but found %s\n", token.string);
- return qfalse;
- }
- if (negative)
- *f = -token.floatvalue;
- else
- *f = token.floatvalue;
- return qtrue;
-}
-
-/*
-=================
-Color_Parse
-=================
-*/
-qboolean Color_Parse(char **p, vec4_t *c) {
- int i;
- float f;
-
- for (i = 0; i < 4; i++) {
- if (!Float_Parse(p, &f)) {
- return qfalse;
- }
- (*c)[i] = f;
- }
- return qtrue;
-}
-
-/*
-=================
-PC_Color_Parse
-=================
-*/
-qboolean PC_Color_Parse(int handle, vec4_t *c) {
- int i;
- float f;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- (*c)[i] = f;
- }
- return qtrue;
-}
-
-/*
-=================
-Int_Parse
-=================
-*/
-qboolean Int_Parse(char **p, int *i) {
- char *token;
- token = COM_ParseExt(p, qfalse);
-
- if (token && token[0] != 0) {
- *i = atoi(token);
- return qtrue;
- } else {
- return qfalse;
- }
-}
-
-/*
-=================
-PC_Int_Parse
-=================
-*/
-qboolean PC_Int_Parse(int handle, int *i) {
- pc_token_t token;
- int negative = qfalse;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (token.string[0] == '-') {
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- negative = qtrue;
- }
- if (token.type != TT_NUMBER) {
- PC_SourceError(handle, "expected integer but found %s\n", token.string);
- return qfalse;
- }
- *i = token.intvalue;
- if (negative)
- *i = - *i;
- return qtrue;
-}
-
-/*
-=================
-Rect_Parse
-=================
-*/
-qboolean Rect_Parse(char **p, rectDef_t *r) {
- if (Float_Parse(p, &r->x)) {
- if (Float_Parse(p, &r->y)) {
- if (Float_Parse(p, &r->w)) {
- if (Float_Parse(p, &r->h)) {
- return qtrue;
- }
- }
- }
- }
- return qfalse;
-}
-
-/*
-=================
-PC_Rect_Parse
-=================
-*/
-qboolean PC_Rect_Parse(int handle, rectDef_t *r) {
- if (PC_Float_Parse(handle, &r->x)) {
- if (PC_Float_Parse(handle, &r->y)) {
- if (PC_Float_Parse(handle, &r->w)) {
- if (PC_Float_Parse(handle, &r->h)) {
- return qtrue;
- }
- }
- }
- }
- return qfalse;
-}
-
-/*
-=================
-String_Parse
-=================
-*/
-qboolean String_Parse(char **p, const char **out) {
- char *token;
-
- token = COM_ParseExt(p, qfalse);
- if (token && token[0] != 0) {
- *(out) = String_Alloc(token);
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-=================
-PC_String_Parse
-=================
-*/
-qboolean PC_String_Parse(int handle, const char **out) {
- pc_token_t token;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
-
- *(out) = String_Alloc(token.string);
- return qtrue;
-}
-
-/*
-=================
-PC_Script_Parse
-=================
-*/
-qboolean PC_Script_Parse(int handle, const char **out) {
- char script[1024];
- pc_token_t token;
-
- memset(script, 0, sizeof(script));
- // scripts start with { and have ; separated command lists.. commands are command, arg..
- // basically we want everything between the { } as it will be interpreted at run time
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (Q_stricmp(token.string, "{") != 0) {
- return qfalse;
- }
-
- while ( 1 ) {
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
-
- if (Q_stricmp(token.string, "}") == 0) {
- *out = String_Alloc(script);
- return qtrue;
- }
-
- if (token.string[1] != '\0') {
- Q_strcat(script, 1024, va("\"%s\"", token.string));
- } else {
- Q_strcat(script, 1024, token.string);
- }
- Q_strcat(script, 1024, " ");
- }
- return qfalse; // bk001105 - LCC missing return value
-}
-
-// display, window, menu, item code
-//
-
-/*
-==================
-Init_Display
-
-Initializes the display with a structure to all the drawing routines
- ==================
-*/
-void Init_Display(displayContextDef_t *dc) {
- DC = dc;
-}
-
-
-
-// type and style painting
-
-void GradientBar_Paint(rectDef_t *rect, vec4_t color) {
- // gradient bar takes two paints
- DC->setColor( color );
- DC->drawHandlePic(rect->x, rect->y, rect->w, rect->h, DC->Assets.gradientBar);
- DC->setColor( NULL );
-}
-
-
-/*
-==================
-Window_Init
-
-Initializes a window structure ( windowDef_t ) with defaults
-
-==================
-*/
-void Window_Init(Window *w) {
- memset(w, 0, sizeof(windowDef_t));
- w->borderSize = 1;
- w->foreColor[0] = w->foreColor[1] = w->foreColor[2] = w->foreColor[3] = 1.0;
- w->cinematic = -1;
-}
-
-void Fade(int *flags, float *f, float clamp, int *nextTime, int offsetTime, qboolean bFlags, float fadeAmount) {
- if (*flags & (WINDOW_FADINGOUT | WINDOW_FADINGIN)) {
- if (DC->realTime > *nextTime) {
- *nextTime = DC->realTime + offsetTime;
- if (*flags & WINDOW_FADINGOUT) {
- *f -= fadeAmount;
- if (bFlags && *f <= 0.0) {
- *flags &= ~(WINDOW_FADINGOUT | WINDOW_VISIBLE);
- }
- } else {
- *f += fadeAmount;
- if (*f >= clamp) {
- *f = clamp;
- if (bFlags) {
- *flags &= ~WINDOW_FADINGIN;
- }
- }
- }
- }
- }
-}
-
-
-
-void Window_Paint(Window *w, float fadeAmount, float fadeClamp, float fadeCycle) {
- //float bordersize = 0;
- vec4_t color;
- rectDef_t fillRect = w->rect;
-
-
- if (debugMode) {
- color[0] = color[1] = color[2] = color[3] = 1;
- DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, 1, color);
- }
-
- if (w == NULL || (w->style == 0 && w->border == 0)) {
- return;
- }
-
- if (w->border != 0) {
- fillRect.x += w->borderSize;
- fillRect.y += w->borderSize;
- fillRect.w -= w->borderSize + 1;
- fillRect.h -= w->borderSize + 1;
- }
-
- if (w->style == WINDOW_STYLE_FILLED) {
- // box, but possible a shader that needs filled
- if (w->background) {
- Fade(&w->flags, &w->backColor[3], fadeClamp, &w->nextTime, fadeCycle, qtrue, fadeAmount);
- DC->setColor(w->backColor);
- DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
- DC->setColor(NULL);
- } else {
- DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->backColor);
- }
- } else if (w->style == WINDOW_STYLE_GRADIENT) {
- GradientBar_Paint(&fillRect, w->backColor);
- // gradient bar
- } else if (w->style == WINDOW_STYLE_SHADER) {
- if (w->flags & WINDOW_FORECOLORSET) {
- DC->setColor(w->foreColor);
- }
- DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
- DC->setColor(NULL);
- } else if (w->style == WINDOW_STYLE_TEAMCOLOR) {
- if (DC->getTeamColor) {
- DC->getTeamColor(&color);
- DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, color);
- }
- } else if (w->style == WINDOW_STYLE_CINEMATIC) {
- if (w->cinematic == -1) {
- w->cinematic = DC->playCinematic(w->cinematicName, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
- if (w->cinematic == -1) {
- w->cinematic = -2;
- }
- }
- if (w->cinematic >= 0) {
- DC->runCinematicFrame(w->cinematic);
- DC->drawCinematic(w->cinematic, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
- }
- }
-
- if (w->border == WINDOW_BORDER_FULL) {
- // full
- // HACK HACK HACK
- if (w->style == WINDOW_STYLE_TEAMCOLOR) {
- if (color[0] > 0) {
- // red
- color[0] = 1;
- color[1] = color[2] = .5;
-
- } else {
- color[2] = 1;
- color[0] = color[1] = .5;
- }
- color[3] = 1;
- DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, color);
- } else {
- DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, w->borderColor);
- }
- } else if (w->border == WINDOW_BORDER_HORZ) {
- // top/bottom
- DC->setColor(w->borderColor);
- DC->drawTopBottom(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
- DC->setColor( NULL );
- } else if (w->border == WINDOW_BORDER_VERT) {
- // left right
- DC->setColor(w->borderColor);
- DC->drawSides(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
- DC->setColor( NULL );
- } else if (w->border == WINDOW_BORDER_KCGRADIENT) {
- // this is just two gradient bars along each horz edge
- rectDef_t r = w->rect;
- r.h = w->borderSize;
- GradientBar_Paint(&r, w->borderColor);
- r.y = w->rect.y + w->rect.h - 1;
- GradientBar_Paint(&r, w->borderColor);
- }
-
-}
-
-
-void Item_SetScreenCoords(itemDef_t *item, float x, float y) {
-
- if (item == NULL) {
- return;
- }
-
- if (item->window.border != 0) {
- x += item->window.borderSize;
- y += item->window.borderSize;
- }
-
- item->window.rect.x = x + item->window.rectClient.x;
- item->window.rect.y = y + item->window.rectClient.y;
- item->window.rect.w = item->window.rectClient.w;
- item->window.rect.h = item->window.rectClient.h;
-
- // force the text rects to recompute
- item->textRect.w = 0;
- item->textRect.h = 0;
-}
-
-// FIXME: consolidate this with nearby stuff
-void Item_UpdatePosition(itemDef_t *item) {
- float x, y;
- menuDef_t *menu;
-
- if (item == NULL || item->parent == NULL) {
- return;
- }
-
- menu = item->parent;
-
- x = menu->window.rect.x;
- y = menu->window.rect.y;
-
- if (menu->window.border != 0) {
- x += menu->window.borderSize;
- y += menu->window.borderSize;
- }
-
- Item_SetScreenCoords(item, x, y);
-
-}
-
-// menus
-void Menu_UpdatePosition(menuDef_t *menu) {
- int i;
- float x, y;
-
- if (menu == NULL) {
- return;
- }
-
- x = menu->window.rect.x;
- y = menu->window.rect.y;
- if (menu->window.border != 0) {
- x += menu->window.borderSize;
- y += menu->window.borderSize;
- }
-
- for (i = 0; i < menu->itemCount; i++) {
- Item_SetScreenCoords(menu->items[i], x, y);
- }
-}
-
-void Menu_PostParse(menuDef_t *menu) {
- if (menu == NULL) {
- return;
- }
- if (menu->fullScreen) {
- menu->window.rect.x = 0;
- menu->window.rect.y = 0;
- menu->window.rect.w = 640;
- menu->window.rect.h = 480;
- }
- Menu_UpdatePosition(menu);
-}
-
-itemDef_t *Menu_ClearFocus(menuDef_t *menu) {
- int i;
- itemDef_t *ret = NULL;
-
- if (menu == NULL) {
- return NULL;
- }
-
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
- ret = menu->items[i];
- }
- menu->items[i]->window.flags &= ~WINDOW_HASFOCUS;
- if (menu->items[i]->leaveFocus) {
- Item_RunScript(menu->items[i], menu->items[i]->leaveFocus);
- }
- }
-
- return ret;
-}
-
-qboolean IsVisible(int flags) {
- return (flags & WINDOW_VISIBLE && !(flags & WINDOW_FADINGOUT));
-}
-
-qboolean Rect_ContainsPoint(rectDef_t *rect, float x, float y) {
- if (rect) {
- if (x > rect->x && x < rect->x + rect->w && y > rect->y && y < rect->y + rect->h) {
- return qtrue;
- }
- }
- return qfalse;
-}
-
-int Menu_ItemsMatchingGroup(menuDef_t *menu, const char *name) {
- int i;
- int count = 0;
- for (i = 0; i < menu->itemCount; i++) {
- if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
- count++;
- }
- }
- return count;
-}
-
-itemDef_t *Menu_GetMatchingItemByNumber(menuDef_t *menu, int index, const char *name) {
- int i;
- int count = 0;
- for (i = 0; i < menu->itemCount; i++) {
- if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
- if (count == index) {
- return menu->items[i];
- }
- count++;
- }
- }
- return NULL;
-}
-
-
-
-void Script_SetColor(itemDef_t *item, char **args) {
- const char *name;
- int i;
- float f;
- vec4_t *out;
- // expecting type of color to set and 4 args for the color
- if (String_Parse(args, &name)) {
- out = NULL;
- if (Q_stricmp(name, "backcolor") == 0) {
- out = &item->window.backColor;
- item->window.flags |= WINDOW_BACKCOLORSET;
- } else if (Q_stricmp(name, "forecolor") == 0) {
- out = &item->window.foreColor;
- item->window.flags |= WINDOW_FORECOLORSET;
- } else if (Q_stricmp(name, "bordercolor") == 0) {
- out = &item->window.borderColor;
- }
-
- if (out) {
- for (i = 0; i < 4; i++) {
- if (!Float_Parse(args, &f)) {
- return;
- }
- (*out)[i] = f;
- }
- }
- }
-}
-
-void Script_SetAsset(itemDef_t *item, char **args) {
- const char *name;
- // expecting name to set asset to
- if (String_Parse(args, &name)) {
- // check for a model
- if (item->type == ITEM_TYPE_MODEL) {
- }
- }
-}
-
-void Script_SetBackground(itemDef_t *item, char **args) {
- const char *name;
- // expecting name to set asset to
- if (String_Parse(args, &name)) {
- item->window.background = DC->registerShaderNoMip(name);
- }
-}
-
-
-
-
-itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p) {
- int i;
- if (menu == NULL || p == NULL) {
- return NULL;
- }
-
- for (i = 0; i < menu->itemCount; i++) {
- if (Q_stricmp(p, menu->items[i]->window.name) == 0) {
- return menu->items[i];
- }
- }
-
- return NULL;
-}
-
-void Script_SetTeamColor(itemDef_t *item, char **args) {
- if (DC->getTeamColor) {
- int i;
- vec4_t color;
- DC->getTeamColor(&color);
- for (i = 0; i < 4; i++) {
- item->window.backColor[i] = color[i];
- }
- }
-}
-
-void Script_SetItemColor(itemDef_t *item, char **args) {
- const char *itemname;
- const char *name;
- vec4_t color;
- int i;
- vec4_t *out;
- // expecting type of color to set and 4 args for the color
- if (String_Parse(args, &itemname) && String_Parse(args, &name)) {
- itemDef_t *item2;
- int j;
- int count = Menu_ItemsMatchingGroup(item->parent, itemname);
-
- if (!Color_Parse(args, &color)) {
- return;
- }
-
- for (j = 0; j < count; j++) {
- item2 = Menu_GetMatchingItemByNumber(item->parent, j, itemname);
- if (item2 != NULL) {
- out = NULL;
- if (Q_stricmp(name, "backcolor") == 0) {
- out = &item2->window.backColor;
- } else if (Q_stricmp(name, "forecolor") == 0) {
- out = &item2->window.foreColor;
- item2->window.flags |= WINDOW_FORECOLORSET;
- } else if (Q_stricmp(name, "bordercolor") == 0) {
- out = &item2->window.borderColor;
- }
-
- if (out) {
- for (i = 0; i < 4; i++) {
- (*out)[i] = color[i];
- }
- }
- }
- }
- }
-}
-
-
-void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow) {
- itemDef_t *item;
- int i;
- int count = Menu_ItemsMatchingGroup(menu, p);
- for (i = 0; i < count; i++) {
- item = Menu_GetMatchingItemByNumber(menu, i, p);
- if (item != NULL) {
- if (bShow) {
- item->window.flags |= WINDOW_VISIBLE;
- } else {
- item->window.flags &= ~WINDOW_VISIBLE;
- // stop cinematics playing in the window
- if (item->window.cinematic >= 0) {
- DC->stopCinematic(item->window.cinematic);
- item->window.cinematic = -1;
- }
- }
- }
- }
-}
-
-void Menu_FadeItemByName(menuDef_t *menu, const char *p, qboolean fadeOut) {
- itemDef_t *item;
- int i;
- int count = Menu_ItemsMatchingGroup(menu, p);
- for (i = 0; i < count; i++) {
- item = Menu_GetMatchingItemByNumber(menu, i, p);
- if (item != NULL) {
- if (fadeOut) {
- item->window.flags |= (WINDOW_FADINGOUT | WINDOW_VISIBLE);
- item->window.flags &= ~WINDOW_FADINGIN;
- } else {
- item->window.flags |= (WINDOW_VISIBLE | WINDOW_FADINGIN);
- item->window.flags &= ~WINDOW_FADINGOUT;
- }
- }
- }
-}
-
-menuDef_t *Menus_FindByName(const char *p) {
- int i;
- for (i = 0; i < menuCount; i++) {
- if (Q_stricmp(Menus[i].window.name, p) == 0) {
- return &Menus[i];
- }
- }
- return NULL;
-}
-
-void Menus_ShowByName(const char *p) {
- menuDef_t *menu = Menus_FindByName(p);
- if (menu) {
- Menus_Activate(menu);
- }
-}
-
-void Menus_OpenByName(const char *p) {
- Menus_ActivateByName(p);
-}
-
-static void Menu_RunCloseScript(menuDef_t *menu) {
- if (menu && menu->window.flags & WINDOW_VISIBLE && menu->onClose) {
- itemDef_t item;
- item.parent = menu;
- Item_RunScript(&item, menu->onClose);
- }
-}
-
-void Menus_CloseByName(const char *p) {
- menuDef_t *menu = Menus_FindByName(p);
- if (menu != NULL) {
- Menu_RunCloseScript(menu);
- menu->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS);
- }
-}
-
-void Menus_CloseAll(void) {
- int i;
- for (i = 0; i < menuCount; i++) {
- Menu_RunCloseScript(&Menus[i]);
- Menus[i].window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
- }
-}
-
-
-void Script_Show(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menu_ShowItemByName(item->parent, name, qtrue);
- }
-}
-
-void Script_Hide(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menu_ShowItemByName(item->parent, name, qfalse);
- }
-}
-
-void Script_FadeIn(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menu_FadeItemByName(item->parent, name, qfalse);
- }
-}
-
-void Script_FadeOut(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menu_FadeItemByName(item->parent, name, qtrue);
- }
-}
-
-
-
-void Script_Open(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menus_OpenByName(name);
- }
-}
-
-void Script_ConditionalOpen(itemDef_t *item, char **args) {
- const char *cvar;
- const char *name1;
- const char *name2;
- float val;
-
- if ( String_Parse(args, &cvar) && String_Parse(args, &name1) && String_Parse(args, &name2) ) {
- val = DC->getCVarValue( cvar );
- if ( val == 0.f ) {
- Menus_OpenByName(name2);
- } else {
- Menus_OpenByName(name1);
- }
- }
-}
-
-void Script_Close(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- Menus_CloseByName(name);
- }
-}
-
-void Menu_TransitionItemByName(menuDef_t *menu, const char *p, rectDef_t rectFrom, rectDef_t rectTo, int time, float amt) {
- itemDef_t *item;
- int i;
- int count = Menu_ItemsMatchingGroup(menu, p);
- for (i = 0; i < count; i++) {
- item = Menu_GetMatchingItemByNumber(menu, i, p);
- if (item != NULL) {
- item->window.flags |= (WINDOW_INTRANSITION | WINDOW_VISIBLE);
- item->window.offsetTime = time;
- memcpy(&item->window.rectClient, &rectFrom, sizeof(rectDef_t));
- memcpy(&item->window.rectEffects, &rectTo, sizeof(rectDef_t));
- item->window.rectEffects2.x = abs(rectTo.x - rectFrom.x) / amt;
- item->window.rectEffects2.y = abs(rectTo.y - rectFrom.y) / amt;
- item->window.rectEffects2.w = abs(rectTo.w - rectFrom.w) / amt;
- item->window.rectEffects2.h = abs(rectTo.h - rectFrom.h) / amt;
- Item_UpdatePosition(item);
- }
- }
-}
-
-
-void Script_Transition(itemDef_t *item, char **args) {
- const char *name;
- rectDef_t rectFrom, rectTo;
- int time;
- float amt;
-
- if (String_Parse(args, &name)) {
- if ( Rect_Parse(args, &rectFrom) && Rect_Parse(args, &rectTo) && Int_Parse(args, &time) && Float_Parse(args, &amt)) {
- Menu_TransitionItemByName(item->parent, name, rectFrom, rectTo, time, amt);
- }
- }
-}
-
-
-void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, float cx, float cy, int time) {
- itemDef_t *item;
- int i;
- int count = Menu_ItemsMatchingGroup(menu, p);
- for (i = 0; i < count; i++) {
- item = Menu_GetMatchingItemByNumber(menu, i, p);
- if (item != NULL) {
- item->window.flags |= (WINDOW_ORBITING | WINDOW_VISIBLE);
- item->window.offsetTime = time;
- item->window.rectEffects.x = cx;
- item->window.rectEffects.y = cy;
- item->window.rectClient.x = x;
- item->window.rectClient.y = y;
- Item_UpdatePosition(item);
- }
- }
-}
-
-
-void Script_Orbit(itemDef_t *item, char **args) {
- const char *name;
- float cx, cy, x, y;
- int time;
-
- if (String_Parse(args, &name)) {
- if ( Float_Parse(args, &x) && Float_Parse(args, &y) && Float_Parse(args, &cx) && Float_Parse(args, &cy) && Int_Parse(args, &time) ) {
- Menu_OrbitItemByName(item->parent, name, x, y, cx, cy, time);
- }
- }
-}
-
-
-
-void Script_SetFocus(itemDef_t *item, char **args) {
- const char *name;
- itemDef_t *focusItem;
-
- if (String_Parse(args, &name)) {
- focusItem = Menu_FindItemByName(item->parent, name);
- if (focusItem && !(focusItem->window.flags & WINDOW_DECORATION) && !(focusItem->window.flags & WINDOW_HASFOCUS)) {
- Menu_ClearFocus(item->parent);
- focusItem->window.flags |= WINDOW_HASFOCUS;
- if (focusItem->onFocus) {
- Item_RunScript(focusItem, focusItem->onFocus);
- }
- if (DC->Assets.itemFocusSound) {
- DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND );
- }
- }
- }
-}
-
-void Script_SetPlayerModel(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- DC->setCVar("team_model", name);
- }
-}
-
-void Script_SetPlayerHead(itemDef_t *item, char **args) {
- const char *name;
- if (String_Parse(args, &name)) {
- DC->setCVar("team_headmodel", name);
- }
-}
-
-void Script_SetCvar(itemDef_t *item, char **args) {
- const char *cvar, *val;
- if (String_Parse(args, &cvar) && String_Parse(args, &val)) {
- DC->setCVar(cvar, val);
- }
-
-}
-
-void Script_Exec(itemDef_t *item, char **args) {
- const char *val;
- if (String_Parse(args, &val)) {
- DC->executeText(EXEC_APPEND, va("%s ; ", val));
- }
-}
-
-void Script_Play(itemDef_t *item, char **args) {
- const char *val;
- if (String_Parse(args, &val)) {
- DC->startLocalSound(DC->registerSound(val, qfalse), CHAN_LOCAL_SOUND);
- }
-}
-
-void Script_playLooped(itemDef_t *item, char **args) {
- const char *val;
- if (String_Parse(args, &val)) {
- DC->stopBackgroundTrack();
- DC->startBackgroundTrack(val, val);
- }
-}
-
-
-commandDef_t commandList[] =
-{
- {"fadein", &Script_FadeIn}, // group/name
- {"fadeout", &Script_FadeOut}, // group/name
- {"show", &Script_Show}, // group/name
- {"hide", &Script_Hide}, // group/name
- {"setcolor", &Script_SetColor}, // works on this
- {"open", &Script_Open}, // menu
- {"conditionalopen", &Script_ConditionalOpen}, // menu
- {"close", &Script_Close}, // menu
- {"setasset", &Script_SetAsset}, // works on this
- {"setbackground", &Script_SetBackground}, // works on this
- {"setitemcolor", &Script_SetItemColor}, // group/name
- {"setteamcolor", &Script_SetTeamColor}, // sets this background color to team color
- {"setfocus", &Script_SetFocus}, // sets this background color to team color
- {"setplayermodel", &Script_SetPlayerModel}, // sets this background color to team color
- {"setplayerhead", &Script_SetPlayerHead}, // sets this background color to team color
- {"transition", &Script_Transition}, // group/name
- {"setcvar", &Script_SetCvar}, // group/name
- {"exec", &Script_Exec}, // group/name
- {"play", &Script_Play}, // group/name
- {"playlooped", &Script_playLooped}, // group/name
- {"orbit", &Script_Orbit} // group/name
-};
-
-int scriptCommandCount = sizeof(commandList) / sizeof(commandDef_t);
-
-
-void Item_RunScript(itemDef_t *item, const char *s) {
- char script[1024], *p;
- int i;
- qboolean bRan;
- memset(script, 0, sizeof(script));
- if (item && s && s[0]) {
- Q_strcat(script, 1024, s);
- p = script;
- while (1) {
- const char *command;
- // expect command then arguments, ; ends command, NULL ends script
- if (!String_Parse(&p, &command)) {
- return;
- }
-
- if (command[0] == ';' && command[1] == '\0') {
- continue;
- }
-
- bRan = qfalse;
- for (i = 0; i < scriptCommandCount; i++) {
- if (Q_stricmp(command, commandList[i].name) == 0) {
- (commandList[i].handler(item, &p));
- bRan = qtrue;
- break;
- }
- }
- // not in our auto list, pass to handler
- if (!bRan) {
- DC->runScript(&p);
- }
- }
- }
-}
-
-
-qboolean Item_EnableShowViaCvar(itemDef_t *item, int flag) {
- char script[1024], *p;
- memset(script, 0, sizeof(script));
- if (item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
- char buff[1024];
- DC->getCVarString(item->cvarTest, buff, sizeof(buff));
-
- Q_strcat(script, 1024, item->enableCvar);
- p = script;
- while (1) {
- const char *val;
- // expect value then ; or NULL, NULL ends list
- if (!String_Parse(&p, &val)) {
- return (item->cvarFlags & flag) ? qfalse : qtrue;
- }
-
- if (val[0] == ';' && val[1] == '\0') {
- continue;
- }
-
- // enable it if any of the values are true
- if (item->cvarFlags & flag) {
- if (Q_stricmp(buff, val) == 0) {
- return qtrue;
- }
- } else {
- // disable it if any of the values are true
- if (Q_stricmp(buff, val) == 0) {
- return qfalse;
- }
- }
-
- }
- return (item->cvarFlags & flag) ? qfalse : qtrue;
- }
- return qtrue;
-}
-
-
-// will optionaly set focus to this item
-qboolean Item_SetFocus(itemDef_t *item, float x, float y) {
- int i;
- itemDef_t *oldFocus;
- sfxHandle_t *sfx = &DC->Assets.itemFocusSound;
- qboolean playSound = qfalse;
- menuDef_t *parent; // bk001206: = (menuDef_t*)item->parent;
- // sanity check, non-null, not a decoration and does not already have the focus
- if (item == NULL || item->window.flags & WINDOW_DECORATION || item->window.flags & WINDOW_HASFOCUS || !(item->window.flags & WINDOW_VISIBLE)) {
- return qfalse;
- }
-
- // bk001206 - this can be NULL.
- parent = (menuDef_t*)item->parent;
-
- // items can be enabled and disabled based on cvars
- if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
- return qfalse;
- }
-
- if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
- return qfalse;
- }
-
- oldFocus = Menu_ClearFocus(item->parent);
-
- if (item->type == ITEM_TYPE_TEXT) {
- rectDef_t r;
- r = item->textRect;
- r.y -= r.h;
- if (Rect_ContainsPoint(&r, x, y)) {
- item->window.flags |= WINDOW_HASFOCUS;
- if (item->focusSound) {
- sfx = &item->focusSound;
- }
- playSound = qtrue;
- } else {
- if (oldFocus) {
- oldFocus->window.flags |= WINDOW_HASFOCUS;
- if (oldFocus->onFocus) {
- Item_RunScript(oldFocus, oldFocus->onFocus);
- }
- }
- }
- } else {
- item->window.flags |= WINDOW_HASFOCUS;
- if (item->onFocus) {
- Item_RunScript(item, item->onFocus);
- }
- if (item->focusSound) {
- sfx = &item->focusSound;
- }
- playSound = qtrue;
- }
-
- if (playSound && sfx) {
- DC->startLocalSound( *sfx, CHAN_LOCAL_SOUND );
- }
-
- for (i = 0; i < parent->itemCount; i++) {
- if (parent->items[i] == item) {
- parent->cursorItem = i;
- break;
- }
- }
-
- return qtrue;
-}
-
-int Item_ListBox_MaxScroll(itemDef_t *item) {
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
- int count = DC->feederCount(item->special);
- int max;
-
- if (item->window.flags & WINDOW_HORIZONTAL) {
- max = count - (item->window.rect.w / listPtr->elementWidth) + 1;
- }
- else {
- max = count - (item->window.rect.h / listPtr->elementHeight) + 1;
- }
- if (max < 0) {
- return 0;
- }
- return max;
-}
-
-int Item_ListBox_ThumbPosition(itemDef_t *item) {
- float max, pos, size;
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
-
- max = Item_ListBox_MaxScroll(item);
- if (item->window.flags & WINDOW_HORIZONTAL) {
- size = item->window.rect.w - (SCROLLBAR_SIZE * 2) - 2;
- if (max > 0) {
- pos = (size-SCROLLBAR_SIZE) / (float) max;
- } else {
- pos = 0;
- }
- pos *= listPtr->startPos;
- return item->window.rect.x + 1 + SCROLLBAR_SIZE + pos;
- }
- else {
- size = item->window.rect.h - (SCROLLBAR_SIZE * 2) - 2;
- if (max > 0) {
- pos = (size-SCROLLBAR_SIZE) / (float) max;
- } else {
- pos = 0;
- }
- pos *= listPtr->startPos;
- return item->window.rect.y + 1 + SCROLLBAR_SIZE + pos;
- }
-}
-
-int Item_ListBox_ThumbDrawPosition(itemDef_t *item) {
- int min, max;
-
- if (itemCapture == item) {
- if (item->window.flags & WINDOW_HORIZONTAL) {
- min = item->window.rect.x + SCROLLBAR_SIZE + 1;
- max = item->window.rect.x + item->window.rect.w - 2*SCROLLBAR_SIZE - 1;
- if (DC->cursorx >= min + SCROLLBAR_SIZE/2 && DC->cursorx <= max + SCROLLBAR_SIZE/2) {
- return DC->cursorx - SCROLLBAR_SIZE/2;
- }
- else {
- return Item_ListBox_ThumbPosition(item);
- }
- }
- else {
- min = item->window.rect.y + SCROLLBAR_SIZE + 1;
- max = item->window.rect.y + item->window.rect.h - 2*SCROLLBAR_SIZE - 1;
- if (DC->cursory >= min + SCROLLBAR_SIZE/2 && DC->cursory <= max + SCROLLBAR_SIZE/2) {
- return DC->cursory - SCROLLBAR_SIZE/2;
- }
- else {
- return Item_ListBox_ThumbPosition(item);
- }
- }
- }
- else {
- return Item_ListBox_ThumbPosition(item);
- }
-}
-
-float Item_Slider_ThumbPosition(itemDef_t *item) {
- float value, range, x;
- editFieldDef_t *editDef = item->typeData;
-
- if (item->text) {
- x = item->textRect.x + item->textRect.w + 8;
- } else {
- x = item->window.rect.x;
- }
-
- if (editDef == NULL && item->cvar) {
- return x;
- }
-
- value = DC->getCVarValue(item->cvar);
-
- if (value < editDef->minVal) {
- value = editDef->minVal;
- } else if (value > editDef->maxVal) {
- value = editDef->maxVal;
- }
-
- range = editDef->maxVal - editDef->minVal;
- value -= editDef->minVal;
- value /= range;
- //value /= (editDef->maxVal - editDef->minVal);
- value *= SLIDER_WIDTH;
- x += value;
- // vm fuckage
- //x = x + (((float)value / editDef->maxVal) * SLIDER_WIDTH);
- return x;
-}
-
-int Item_Slider_OverSlider(itemDef_t *item, float x, float y) {
- rectDef_t r;
-
- r.x = Item_Slider_ThumbPosition(item) - (SLIDER_THUMB_WIDTH / 2);
- r.y = item->window.rect.y - 2;
- r.w = SLIDER_THUMB_WIDTH;
- r.h = SLIDER_THUMB_HEIGHT;
-
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_THUMB;
- }
- return 0;
-}
-
-int Item_ListBox_OverLB(itemDef_t *item, float x, float y) {
- rectDef_t r;
- listBoxDef_t *listPtr;
- int thumbstart;
- int count;
-
- count = DC->feederCount(item->special);
- listPtr = (listBoxDef_t*)item->typeData;
- if (item->window.flags & WINDOW_HORIZONTAL) {
- // check if on left arrow
- r.x = item->window.rect.x;
- r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
- r.h = r.w = SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_LEFTARROW;
- }
- // check if on right arrow
- r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_RIGHTARROW;
- }
- // check if on thumb
- thumbstart = Item_ListBox_ThumbPosition(item);
- r.x = thumbstart;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_THUMB;
- }
- r.x = item->window.rect.x + SCROLLBAR_SIZE;
- r.w = thumbstart - r.x;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_PGUP;
- }
- r.x = thumbstart + SCROLLBAR_SIZE;
- r.w = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_PGDN;
- }
- } else {
- r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
- r.y = item->window.rect.y;
- r.h = r.w = SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_LEFTARROW;
- }
- r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_RIGHTARROW;
- }
- thumbstart = Item_ListBox_ThumbPosition(item);
- r.y = thumbstart;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_THUMB;
- }
- r.y = item->window.rect.y + SCROLLBAR_SIZE;
- r.h = thumbstart - r.y;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_PGUP;
- }
- r.y = thumbstart + SCROLLBAR_SIZE;
- r.h = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
- if (Rect_ContainsPoint(&r, x, y)) {
- return WINDOW_LB_PGDN;
- }
- }
- return 0;
-}
-
-
-void Item_ListBox_MouseEnter(itemDef_t *item, float x, float y)
-{
- rectDef_t r;
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
-
- item->window.flags &= ~(WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN);
- item->window.flags |= Item_ListBox_OverLB(item, x, y);
-
- if (item->window.flags & WINDOW_HORIZONTAL) {
- if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
- // check for selection hit as we have exausted buttons and thumb
- if (listPtr->elementStyle == LISTBOX_IMAGE) {
- r.x = item->window.rect.x;
- r.y = item->window.rect.y;
- r.h = item->window.rect.h - SCROLLBAR_SIZE;
- r.w = item->window.rect.w - listPtr->drawPadding;
- if (Rect_ContainsPoint(&r, x, y)) {
- listPtr->cursorPos = (int)((x - r.x) / listPtr->elementWidth) + listPtr->startPos;
- if (listPtr->cursorPos >= listPtr->endPos) {
- listPtr->cursorPos = listPtr->endPos;
- }
- }
- } else {
- // text hit..
- }
- }
- } else if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
- r.x = item->window.rect.x;
- r.y = item->window.rect.y;
- r.w = item->window.rect.w - SCROLLBAR_SIZE;
- r.h = item->window.rect.h - listPtr->drawPadding;
- if (Rect_ContainsPoint(&r, x, y)) {
- listPtr->cursorPos = (int)((y - 2 - r.y) / listPtr->elementHeight) + listPtr->startPos;
- if (listPtr->cursorPos > listPtr->endPos) {
- listPtr->cursorPos = listPtr->endPos;
- }
- }
- }
-}
-
-void Item_MouseEnter(itemDef_t *item, float x, float y) {
- rectDef_t r;
- if (item) {
- r = item->textRect;
- r.y -= r.h;
- // in the text rect?
-
- // items can be enabled and disabled based on cvars
- if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
- return;
- }
-
- if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
- return;
- }
-
- if (Rect_ContainsPoint(&r, x, y)) {
- if (!(item->window.flags & WINDOW_MOUSEOVERTEXT)) {
- Item_RunScript(item, item->mouseEnterText);
- item->window.flags |= WINDOW_MOUSEOVERTEXT;
- }
- if (!(item->window.flags & WINDOW_MOUSEOVER)) {
- Item_RunScript(item, item->mouseEnter);
- item->window.flags |= WINDOW_MOUSEOVER;
- }
-
- } else {
- // not in the text rect
- if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
- // if we were
- Item_RunScript(item, item->mouseExitText);
- item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
- }
- if (!(item->window.flags & WINDOW_MOUSEOVER)) {
- Item_RunScript(item, item->mouseEnter);
- item->window.flags |= WINDOW_MOUSEOVER;
- }
-
- if (item->type == ITEM_TYPE_LISTBOX) {
- Item_ListBox_MouseEnter(item, x, y);
- }
- }
- }
-}
-
-void Item_MouseLeave(itemDef_t *item) {
- if (item) {
- if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
- Item_RunScript(item, item->mouseExitText);
- item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
- }
- Item_RunScript(item, item->mouseExit);
- item->window.flags &= ~(WINDOW_LB_RIGHTARROW | WINDOW_LB_LEFTARROW);
- }
-}
-
-itemDef_t *Menu_HitTest(menuDef_t *menu, float x, float y) {
- int i;
- for (i = 0; i < menu->itemCount; i++) {
- if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
- return menu->items[i];
- }
- }
- return NULL;
-}
-
-void Item_SetMouseOver(itemDef_t *item, qboolean focus) {
- if (item) {
- if (focus) {
- item->window.flags |= WINDOW_MOUSEOVER;
- } else {
- item->window.flags &= ~WINDOW_MOUSEOVER;
- }
- }
-}
-
-
-qboolean Item_OwnerDraw_HandleKey(itemDef_t *item, int key) {
- if (item && DC->ownerDrawHandleKey) {
- return DC->ownerDrawHandleKey(item->window.ownerDraw, item->window.ownerDrawFlags, &item->special, key);
- }
- return qfalse;
-}
-
-qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolean force) {
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
- int count = DC->feederCount(item->special);
- int max, viewmax;
-
- if (force || (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS)) {
- max = Item_ListBox_MaxScroll(item);
- if (item->window.flags & WINDOW_HORIZONTAL) {
- viewmax = (item->window.rect.w / listPtr->elementWidth);
- if ( key == K_LEFTARROW )
- {
- if (!listPtr->notselectable) {
- listPtr->cursorPos--;
- if (listPtr->cursorPos < 0) {
- listPtr->cursorPos = 0;
- }
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos--;
- if (listPtr->startPos < 0)
- listPtr->startPos = 0;
- }
- return qtrue;
- }
- if ( key == K_RIGHTARROW )
- {
- if (!listPtr->notselectable) {
- listPtr->cursorPos++;
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= count) {
- listPtr->cursorPos = count-1;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos++;
- if (listPtr->startPos >= count)
- listPtr->startPos = count-1;
- }
- return qtrue;
- }
- }
- else {
- viewmax = (item->window.rect.h / listPtr->elementHeight);
- if ( key == K_UPARROW )
- {
- if (!listPtr->notselectable) {
- listPtr->cursorPos--;
- if (listPtr->cursorPos < 0) {
- listPtr->cursorPos = 0;
- }
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos--;
- if (listPtr->startPos < 0)
- listPtr->startPos = 0;
- }
- return qtrue;
- }
- if ( key == K_DOWNARROW )
- {
- if (!listPtr->notselectable) {
- listPtr->cursorPos++;
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= count) {
- listPtr->cursorPos = count-1;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos++;
- if (listPtr->startPos > max)
- listPtr->startPos = max;
- }
- return qtrue;
- }
- }
- // mouse hit
- if (key == K_MOUSE1 || key == K_MOUSE2) {
- if (item->window.flags & WINDOW_LB_LEFTARROW) {
- listPtr->startPos--;
- if (listPtr->startPos < 0) {
- listPtr->startPos = 0;
- }
- } else if (item->window.flags & WINDOW_LB_RIGHTARROW) {
- // one down
- listPtr->startPos++;
- if (listPtr->startPos > max) {
- listPtr->startPos = max;
- }
- } else if (item->window.flags & WINDOW_LB_PGUP) {
- // page up
- listPtr->startPos -= viewmax;
- if (listPtr->startPos < 0) {
- listPtr->startPos = 0;
- }
- } else if (item->window.flags & WINDOW_LB_PGDN) {
- // page down
- listPtr->startPos += viewmax;
- if (listPtr->startPos > max) {
- listPtr->startPos = max;
- }
- } else if (item->window.flags & WINDOW_LB_THUMB) {
- // Display_SetCaptureItem(item);
- } else {
- // select an item
- if (DC->realTime < lastListBoxClickTime && listPtr->doubleClick) {
- Item_RunScript(item, listPtr->doubleClick);
- }
- lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY;
- if (item->cursorPos != listPtr->cursorPos) {
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- }
- return qtrue;
- }
- if ( key == K_HOME ) {
- // home
- listPtr->startPos = 0;
- return qtrue;
- }
- if ( key == K_END ) {
- // end
- listPtr->startPos = max;
- return qtrue;
- }
- if (key == K_PGUP ) {
- // page up
- if (!listPtr->notselectable) {
- listPtr->cursorPos -= viewmax;
- if (listPtr->cursorPos < 0) {
- listPtr->cursorPos = 0;
- }
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos -= viewmax;
- if (listPtr->startPos < 0) {
- listPtr->startPos = 0;
- }
- }
- return qtrue;
- }
- if ( key == K_PGDN ) {
- // page down
- if (!listPtr->notselectable) {
- listPtr->cursorPos += viewmax;
- if (listPtr->cursorPos < listPtr->startPos) {
- listPtr->startPos = listPtr->cursorPos;
- }
- if (listPtr->cursorPos >= count) {
- listPtr->cursorPos = count-1;
- }
- if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
- listPtr->startPos = listPtr->cursorPos - viewmax + 1;
- }
- item->cursorPos = listPtr->cursorPos;
- DC->feederSelection(item->special, item->cursorPos);
- }
- else {
- listPtr->startPos += viewmax;
- if (listPtr->startPos > max) {
- listPtr->startPos = max;
- }
- }
- return qtrue;
- }
- }
- return qfalse;
-}
-
-qboolean Item_YesNo_HandleKey(itemDef_t *item, int key) {
-
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
- if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
- DC->setCVar(item->cvar, va("%i", !DC->getCVarValue(item->cvar)));
- return qtrue;
- }
- }
-
- return qfalse;
-
-}
-
-int Item_Multi_CountSettings(itemDef_t *item) {
- multiDef_t *multiPtr = (multiDef_t*)item->typeData;
- if (multiPtr == NULL) {
- return 0;
- }
- return multiPtr->count;
-}
-
-int Item_Multi_FindCvarByValue(itemDef_t *item) {
- char buff[1024];
- float value = 0;
- int i;
- multiDef_t *multiPtr = (multiDef_t*)item->typeData;
- if (multiPtr) {
- if (multiPtr->strDef) {
- DC->getCVarString(item->cvar, buff, sizeof(buff));
- } else {
- value = DC->getCVarValue(item->cvar);
- }
- for (i = 0; i < multiPtr->count; i++) {
- if (multiPtr->strDef) {
- if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
- return i;
- }
- } else {
- if (multiPtr->cvarValue[i] == value) {
- return i;
- }
- }
- }
- }
- return 0;
-}
-
-const char *Item_Multi_Setting(itemDef_t *item) {
- char buff[1024];
- float value = 0;
- int i;
- multiDef_t *multiPtr = (multiDef_t*)item->typeData;
- if (multiPtr) {
- if (multiPtr->strDef) {
- DC->getCVarString(item->cvar, buff, sizeof(buff));
- } else {
- value = DC->getCVarValue(item->cvar);
- }
- for (i = 0; i < multiPtr->count; i++) {
- if (multiPtr->strDef) {
- if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
- return multiPtr->cvarList[i];
- }
- } else {
- if (multiPtr->cvarValue[i] == value) {
- return multiPtr->cvarList[i];
- }
- }
- }
- }
- return "";
-}
-
-qboolean Item_Multi_HandleKey(itemDef_t *item, int key) {
- multiDef_t *multiPtr = (multiDef_t*)item->typeData;
- if (multiPtr) {
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
- if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
- int current = Item_Multi_FindCvarByValue(item) + 1;
- int max = Item_Multi_CountSettings(item);
- if ( current < 0 || current >= max ) {
- current = 0;
- }
- if (multiPtr->strDef) {
- DC->setCVar(item->cvar, multiPtr->cvarStr[current]);
- } else {
- float value = multiPtr->cvarValue[current];
- if (((float)((int) value)) == value) {
- DC->setCVar(item->cvar, va("%i", (int) value ));
- }
- else {
- DC->setCVar(item->cvar, va("%f", value ));
- }
- }
- return qtrue;
- }
- }
- }
- return qfalse;
-}
-
-qboolean Item_TextField_HandleKey(itemDef_t *item, int key) {
- char buff[1024];
- int len;
- itemDef_t *newItem = NULL;
- editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
-
- if (item->cvar) {
-
- memset(buff, 0, sizeof(buff));
- DC->getCVarString(item->cvar, buff, sizeof(buff));
- len = strlen(buff);
- if (editPtr->maxChars && len > editPtr->maxChars) {
- len = editPtr->maxChars;
- }
- if ( key & K_CHAR_FLAG ) {
- key &= ~K_CHAR_FLAG;
-
-
- if (key == 'h' - 'a' + 1 ) { // ctrl-h is backspace
- if ( item->cursorPos > 0 ) {
- memmove( &buff[item->cursorPos - 1], &buff[item->cursorPos], len + 1 - item->cursorPos);
- item->cursorPos--;
- if (item->cursorPos < editPtr->paintOffset) {
- editPtr->paintOffset--;
- }
- }
- DC->setCVar(item->cvar, buff);
- return qtrue;
- }
-
-
- //
- // ignore any non printable chars
- //
- if ( key < 32 || !item->cvar) {
- return qtrue;
- }
-
- if (item->type == ITEM_TYPE_NUMERICFIELD) {
- if (key < '0' || key > '9') {
- return qfalse;
- }
- }
-
- if (!DC->getOverstrikeMode()) {
- if (( len == MAX_EDITFIELD - 1 ) || (editPtr->maxChars && len >= editPtr->maxChars)) {
- return qtrue;
- }
- memmove( &buff[item->cursorPos + 1], &buff[item->cursorPos], len + 1 - item->cursorPos );
- } else {
- if (editPtr->maxChars && item->cursorPos >= editPtr->maxChars) {
- return qtrue;
- }
- }
-
- buff[item->cursorPos] = key;
-
- DC->setCVar(item->cvar, buff);
-
- if (item->cursorPos < len + 1) {
- item->cursorPos++;
- if (editPtr->maxPaintChars && item->cursorPos > editPtr->maxPaintChars) {
- editPtr->paintOffset++;
- }
- }
-
- } else {
-
- if ( key == K_DEL ) {
- if ( item->cursorPos < len ) {
- memmove( buff + item->cursorPos, buff + item->cursorPos + 1, len - item->cursorPos);
- DC->setCVar(item->cvar, buff);
- }
- return qtrue;
- }
-
- if ( key == K_RIGHTARROW )
- {
- if (editPtr->maxPaintChars && item->cursorPos >= editPtr->maxPaintChars && item->cursorPos < len) {
- item->cursorPos++;
- editPtr->paintOffset++;
- return qtrue;
- }
- if (item->cursorPos < len) {
- item->cursorPos++;
- }
- return qtrue;
- }
-
- if ( key == K_LEFTARROW )
- {
- if ( item->cursorPos > 0 ) {
- item->cursorPos--;
- }
- if (item->cursorPos < editPtr->paintOffset) {
- editPtr->paintOffset--;
- }
- return qtrue;
- }
-
- if ( key == K_HOME ) {// || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {
- item->cursorPos = 0;
- editPtr->paintOffset = 0;
- return qtrue;
- }
-
- if ( key == K_END ) {// ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {
- item->cursorPos = len;
- if(item->cursorPos > editPtr->maxPaintChars) {
- editPtr->paintOffset = len - editPtr->maxPaintChars;
- }
- return qtrue;
- }
-
- if ( key == K_INS ) {
- DC->setOverstrikeMode(!DC->getOverstrikeMode());
- return qtrue;
- }
- }
-
- if (key == K_TAB || key == K_DOWNARROW ) {
- newItem = Menu_SetNextCursorItem(item->parent);
- if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
- g_editItem = newItem;
- }
- }
-
- if (key == K_UPARROW ) {
- newItem = Menu_SetPrevCursorItem(item->parent);
- if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
- g_editItem = newItem;
- }
- }
-
- if ( key == K_ENTER || key == K_KP_ENTER || key == K_ESCAPE) {
- return qfalse;
- }
-
- return qtrue;
- }
- return qfalse;
-
-}
-
-static void Scroll_ListBox_AutoFunc(void *p) {
- scrollInfo_t *si = (scrollInfo_t*)p;
- if (DC->realTime > si->nextScrollTime) {
- // need to scroll which is done by simulating a click to the item
- // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
- // so it calls it directly
- Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
- si->nextScrollTime = DC->realTime + si->adjustValue;
- }
-
- if (DC->realTime > si->nextAdjustTime) {
- si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
- if (si->adjustValue > SCROLL_TIME_FLOOR) {
- si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
- }
- }
-}
-
-static void Scroll_ListBox_ThumbFunc(void *p) {
- scrollInfo_t *si = (scrollInfo_t*)p;
- rectDef_t r;
- int pos, max;
-
- listBoxDef_t *listPtr = (listBoxDef_t*)si->item->typeData;
- if (si->item->window.flags & WINDOW_HORIZONTAL) {
- if (DC->cursorx == si->xStart) {
- return;
- }
- r.x = si->item->window.rect.x + SCROLLBAR_SIZE + 1;
- r.y = si->item->window.rect.y + si->item->window.rect.h - SCROLLBAR_SIZE - 1;
- r.h = SCROLLBAR_SIZE;
- r.w = si->item->window.rect.w - (SCROLLBAR_SIZE*2) - 2;
- max = Item_ListBox_MaxScroll(si->item);
- //
- pos = (DC->cursorx - r.x - SCROLLBAR_SIZE/2) * max / (r.w - SCROLLBAR_SIZE);
- if (pos < 0) {
- pos = 0;
- }
- else if (pos > max) {
- pos = max;
- }
- listPtr->startPos = pos;
- si->xStart = DC->cursorx;
- }
- else if (DC->cursory != si->yStart) {
-
- r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_SIZE - 1;
- r.y = si->item->window.rect.y + SCROLLBAR_SIZE + 1;
- r.h = si->item->window.rect.h - (SCROLLBAR_SIZE*2) - 2;
- r.w = SCROLLBAR_SIZE;
- max = Item_ListBox_MaxScroll(si->item);
- //
- pos = (DC->cursory - r.y - SCROLLBAR_SIZE/2) * max / (r.h - SCROLLBAR_SIZE);
- if (pos < 0) {
- pos = 0;
- }
- else if (pos > max) {
- pos = max;
- }
- listPtr->startPos = pos;
- si->yStart = DC->cursory;
- }
-
- if (DC->realTime > si->nextScrollTime) {
- // need to scroll which is done by simulating a click to the item
- // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
- // so it calls it directly
- Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
- si->nextScrollTime = DC->realTime + si->adjustValue;
- }
-
- if (DC->realTime > si->nextAdjustTime) {
- si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
- if (si->adjustValue > SCROLL_TIME_FLOOR) {
- si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
- }
- }
-}
-
-static void Scroll_Slider_ThumbFunc(void *p) {
- float x, value, cursorx;
- scrollInfo_t *si = (scrollInfo_t*)p;
- editFieldDef_t *editDef = si->item->typeData;
-
- if (si->item->text) {
- x = si->item->textRect.x + si->item->textRect.w + 8;
- } else {
- x = si->item->window.rect.x;
- }
-
- cursorx = DC->cursorx;
-
- if (cursorx < x) {
- cursorx = x;
- } else if (cursorx > x + SLIDER_WIDTH) {
- cursorx = x + SLIDER_WIDTH;
- }
- value = cursorx - x;
- value /= SLIDER_WIDTH;
- value *= (editDef->maxVal - editDef->minVal);
- value += editDef->minVal;
- DC->setCVar(si->item->cvar, va("%f", value));
-}
-
-void Item_StartCapture(itemDef_t *item, int key) {
- int flags;
- switch (item->type) {
- case ITEM_TYPE_EDITFIELD:
- case ITEM_TYPE_NUMERICFIELD:
-
- case ITEM_TYPE_LISTBOX:
- {
- flags = Item_ListBox_OverLB(item, DC->cursorx, DC->cursory);
- if (flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW)) {
- scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START;
- scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
- scrollInfo.adjustValue = SCROLL_TIME_START;
- scrollInfo.scrollKey = key;
- scrollInfo.scrollDir = (flags & WINDOW_LB_LEFTARROW) ? qtrue : qfalse;
- scrollInfo.item = item;
- captureData = &scrollInfo;
- captureFunc = &Scroll_ListBox_AutoFunc;
- itemCapture = item;
- } else if (flags & WINDOW_LB_THUMB) {
- scrollInfo.scrollKey = key;
- scrollInfo.item = item;
- scrollInfo.xStart = DC->cursorx;
- scrollInfo.yStart = DC->cursory;
- captureData = &scrollInfo;
- captureFunc = &Scroll_ListBox_ThumbFunc;
- itemCapture = item;
- }
- break;
- }
- case ITEM_TYPE_SLIDER:
- {
- flags = Item_Slider_OverSlider(item, DC->cursorx, DC->cursory);
- if (flags & WINDOW_LB_THUMB) {
- scrollInfo.scrollKey = key;
- scrollInfo.item = item;
- scrollInfo.xStart = DC->cursorx;
- scrollInfo.yStart = DC->cursory;
- captureData = &scrollInfo;
- captureFunc = &Scroll_Slider_ThumbFunc;
- itemCapture = item;
- }
- break;
- }
- }
-}
-
-void Item_StopCapture(itemDef_t *item) {
-
-}
-
-qboolean Item_Slider_HandleKey(itemDef_t *item, int key, qboolean down) {
- float x, value, width, work;
-
- //DC->Print("slider handle key\n");
- if (item->window.flags & WINDOW_HASFOCUS && item->cvar && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
- if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
- editFieldDef_t *editDef = item->typeData;
- if (editDef) {
- rectDef_t testRect;
- width = SLIDER_WIDTH;
- if (item->text) {
- x = item->textRect.x + item->textRect.w + 8;
- } else {
- x = item->window.rect.x;
- }
-
- testRect = item->window.rect;
- testRect.x = x;
- value = (float)SLIDER_THUMB_WIDTH / 2;
- testRect.x -= value;
- //DC->Print("slider x: %f\n", testRect.x);
- testRect.w = (SLIDER_WIDTH + (float)SLIDER_THUMB_WIDTH / 2);
- //DC->Print("slider w: %f\n", testRect.w);
- if (Rect_ContainsPoint(&testRect, DC->cursorx, DC->cursory)) {
- work = DC->cursorx - x;
- value = work / width;
- value *= (editDef->maxVal - editDef->minVal);
- // vm fuckage
- // value = (((float)(DC->cursorx - x)/ SLIDER_WIDTH) * (editDef->maxVal - editDef->minVal));
- value += editDef->minVal;
- DC->setCVar(item->cvar, va("%f", value));
- return qtrue;
- }
- }
- }
- }
- DC->Print("slider handle key exit\n");
- return qfalse;
-}
-
-
-qboolean Item_HandleKey(itemDef_t *item, int key, qboolean down) {
-
- if (itemCapture) {
- Item_StopCapture(itemCapture);
- itemCapture = NULL;
- captureFunc = 0;
- captureData = NULL;
- } else {
- // bk001206 - parentheses
- if ( down && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
- Item_StartCapture(item, key);
- }
- }
-
- if (!down) {
- return qfalse;
- }
-
- switch (item->type) {
- case ITEM_TYPE_BUTTON:
- return qfalse;
- break;
- case ITEM_TYPE_RADIOBUTTON:
- return qfalse;
- break;
- case ITEM_TYPE_CHECKBOX:
- return qfalse;
- break;
- case ITEM_TYPE_EDITFIELD:
- case ITEM_TYPE_NUMERICFIELD:
- //return Item_TextField_HandleKey(item, key);
- return qfalse;
- break;
- case ITEM_TYPE_COMBO:
- return qfalse;
- break;
- case ITEM_TYPE_LISTBOX:
- return Item_ListBox_HandleKey(item, key, down, qfalse);
- break;
- case ITEM_TYPE_YESNO:
- return Item_YesNo_HandleKey(item, key);
- break;
- case ITEM_TYPE_MULTI:
- return Item_Multi_HandleKey(item, key);
- break;
- case ITEM_TYPE_OWNERDRAW:
- return Item_OwnerDraw_HandleKey(item, key);
- break;
- case ITEM_TYPE_BIND:
- return Item_Bind_HandleKey(item, key, down);
- break;
- case ITEM_TYPE_SLIDER:
- return Item_Slider_HandleKey(item, key, down);
- break;
- //case ITEM_TYPE_IMAGE:
- // Item_Image_Paint(item);
- // break;
- default:
- return qfalse;
- break;
- }
-
- //return qfalse;
-}
-
-void Item_Action(itemDef_t *item) {
- if (item) {
- Item_RunScript(item, item->action);
- }
-}
-
-itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu) {
- qboolean wrapped = qfalse;
- int oldCursor = menu->cursorItem;
-
- if (menu->cursorItem < 0) {
- menu->cursorItem = menu->itemCount-1;
- wrapped = qtrue;
- }
-
- while (menu->cursorItem > -1) {
-
- menu->cursorItem--;
- if (menu->cursorItem < 0 && !wrapped) {
- wrapped = qtrue;
- menu->cursorItem = menu->itemCount -1;
- }
-
- if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
- Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
- return menu->items[menu->cursorItem];
- }
- }
- menu->cursorItem = oldCursor;
- return NULL;
-
-}
-
-itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu) {
-
- qboolean wrapped = qfalse;
- int oldCursor = menu->cursorItem;
-
-
- if (menu->cursorItem == -1) {
- menu->cursorItem = 0;
- wrapped = qtrue;
- }
-
- while (menu->cursorItem < menu->itemCount) {
-
- menu->cursorItem++;
- if (menu->cursorItem >= menu->itemCount && !wrapped) {
- wrapped = qtrue;
- menu->cursorItem = 0;
- }
- if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
- Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
- return menu->items[menu->cursorItem];
- }
-
- }
-
- menu->cursorItem = oldCursor;
- return NULL;
-}
-
-static void Window_CloseCinematic(windowDef_t *window) {
- if (window->style == WINDOW_STYLE_CINEMATIC && window->cinematic >= 0) {
- DC->stopCinematic(window->cinematic);
- window->cinematic = -1;
- }
-}
-
-static void Menu_CloseCinematics(menuDef_t *menu) {
- if (menu) {
- int i;
- Window_CloseCinematic(&menu->window);
- for (i = 0; i < menu->itemCount; i++) {
- Window_CloseCinematic(&menu->items[i]->window);
- if (menu->items[i]->type == ITEM_TYPE_OWNERDRAW) {
- DC->stopCinematic(0-menu->items[i]->window.ownerDraw);
- }
- }
- }
-}
-
-static void Display_CloseCinematics( void ) {
- int i;
- for (i = 0; i < menuCount; i++) {
- Menu_CloseCinematics(&Menus[i]);
- }
-}
-
-void Menus_Activate(menuDef_t *menu) {
- menu->window.flags |= (WINDOW_HASFOCUS | WINDOW_VISIBLE);
- if (menu->onOpen) {
- itemDef_t item;
- item.parent = menu;
- Item_RunScript(&item, menu->onOpen);
- }
-
- if (menu->soundName && *menu->soundName) {
-// DC->stopBackgroundTrack(); // you don't want to do this since it will reset s_rawend
- DC->startBackgroundTrack(menu->soundName, menu->soundName);
- }
-
- Display_CloseCinematics();
-
-}
-
-int Display_VisibleMenuCount( void ) {
- int i, count;
- count = 0;
- for (i = 0; i < menuCount; i++) {
- if (Menus[i].window.flags & (WINDOW_FORCED | WINDOW_VISIBLE)) {
- count++;
- }
- }
- return count;
-}
-
-void Menus_HandleOOBClick(menuDef_t *menu, int key, qboolean down) {
- if (menu) {
- int i;
- // basically the behaviour we are looking for is if there are windows in the stack.. see if
- // the cursor is within any of them.. if not close them otherwise activate them and pass the
- // key on.. force a mouse move to activate focus and script stuff
- if (down && menu->window.flags & WINDOW_OOB_CLICK) {
- Menu_RunCloseScript(menu);
- menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
- }
-
- for (i = 0; i < menuCount; i++) {
- if (Menu_OverActiveItem(&Menus[i], DC->cursorx, DC->cursory)) {
- Menu_RunCloseScript(menu);
- menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
- Menus_Activate(&Menus[i]);
- Menu_HandleMouseMove(&Menus[i], DC->cursorx, DC->cursory);
- Menu_HandleKey(&Menus[i], key, down);
- }
- }
-
- if (Display_VisibleMenuCount() == 0) {
- if (DC->Pause) {
- DC->Pause(qfalse);
- }
- }
- Display_CloseCinematics();
- }
-}
-
-static rectDef_t *Item_CorrectedTextRect(itemDef_t *item) {
- static rectDef_t rect;
- memset(&rect, 0, sizeof(rectDef_t));
- if (item) {
- rect = item->textRect;
- if (rect.w) {
- rect.y -= rect.h;
- }
- }
- return ▭
-}
-
-void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) {
- int i;
- itemDef_t *item = NULL;
- qboolean inHandler = qfalse;
-
- if (inHandler) {
- return;
- }
-
- inHandler = qtrue;
- if (g_waitingForKey && down) {
- Item_Bind_HandleKey(g_bindItem, key, down);
- inHandler = qfalse;
- return;
- }
-
- if (g_editingField && down) {
- if (!Item_TextField_HandleKey(g_editItem, key)) {
- g_editingField = qfalse;
- g_editItem = NULL;
- inHandler = qfalse;
- return;
- } else if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) {
- g_editingField = qfalse;
- g_editItem = NULL;
- Display_MouseMove(NULL, DC->cursorx, DC->cursory);
- } else if (key == K_TAB || key == K_UPARROW || key == K_DOWNARROW) {
- return;
- }
- }
-
- if (menu == NULL) {
- inHandler = qfalse;
- return;
- }
-
- // see if the mouse is within the window bounds and if so is this a mouse click
- if (down && !(menu->window.flags & WINDOW_POPUP) && !Rect_ContainsPoint(&menu->window.rect, DC->cursorx, DC->cursory)) {
- static qboolean inHandleKey = qfalse;
- // bk001206 - parentheses
- if (!inHandleKey && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
- inHandleKey = qtrue;
- Menus_HandleOOBClick(menu, key, down);
- inHandleKey = qfalse;
- inHandler = qfalse;
- return;
- }
- }
-
- // get the item with focus
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
- item = menu->items[i];
- }
- }
-
- if (item != NULL) {
- if (Item_HandleKey(item, key, down)) {
- Item_Action(item);
- inHandler = qfalse;
- return;
- }
- }
-
- if (!down) {
- inHandler = qfalse;
- return;
- }
-
- // default handling
- switch ( key ) {
-
- case K_F11:
- if (DC->getCVarValue("developer")) {
- debugMode ^= 1;
- }
- break;
-
- case K_F12:
- if (DC->getCVarValue("developer")) {
- DC->executeText(EXEC_APPEND, "screenshot\n");
- }
- break;
- case K_UPARROW:
- Menu_SetPrevCursorItem(menu);
- break;
-
- case K_ESCAPE:
- if (!g_waitingForKey && menu->onESC) {
- itemDef_t it;
- it.parent = menu;
- Item_RunScript(&it, menu->onESC);
- }
- break;
- case K_TAB:
- case K_DOWNARROW:
- Menu_SetNextCursorItem(menu);
- break;
-
- case K_MOUSE1:
- case K_MOUSE2:
- if (item) {
- if (item->type == ITEM_TYPE_TEXT) {
- if (Rect_ContainsPoint(Item_CorrectedTextRect(item), DC->cursorx, DC->cursory)) {
- Item_Action(item);
- }
- } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
- item->cursorPos = 0;
- g_editingField = qtrue;
- g_editItem = item;
- DC->setOverstrikeMode(qtrue);
- }
- } else {
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
- Item_Action(item);
- }
- }
- }
- break;
-
- case K_JOY1:
- case K_JOY2:
- case K_JOY3:
- case K_JOY4:
- case K_AUX1:
- case K_AUX2:
- case K_AUX3:
- case K_AUX4:
- case K_AUX5:
- case K_AUX6:
- case K_AUX7:
- case K_AUX8:
- case K_AUX9:
- case K_AUX10:
- case K_AUX11:
- case K_AUX12:
- case K_AUX13:
- case K_AUX14:
- case K_AUX15:
- case K_AUX16:
- break;
- case K_KP_ENTER:
- case K_ENTER:
- if (item) {
- if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
- item->cursorPos = 0;
- g_editingField = qtrue;
- g_editItem = item;
- DC->setOverstrikeMode(qtrue);
- } else {
- Item_Action(item);
- }
- }
- break;
- }
- inHandler = qfalse;
-}
-
-void ToWindowCoords(float *x, float *y, windowDef_t *window) {
- if (window->border != 0) {
- *x += window->borderSize;
- *y += window->borderSize;
- }
- *x += window->rect.x;
- *y += window->rect.y;
-}
-
-void Rect_ToWindowCoords(rectDef_t *rect, windowDef_t *window) {
- ToWindowCoords(&rect->x, &rect->y, window);
-}
-
-void Item_SetTextExtents(itemDef_t *item, int *width, int *height, const char *text) {
- const char *textPtr = (text) ? text : item->text;
-
- if (textPtr == NULL ) {
- return;
- }
-
- *width = item->textRect.w;
- *height = item->textRect.h;
-
- // keeps us from computing the widths and heights more than once
- if (*width == 0 || (item->type == ITEM_TYPE_OWNERDRAW && item->textalignment == ITEM_ALIGN_CENTER)) {
- int originalWidth = DC->textWidth(item->text, item->textscale, 0);
-
- if (item->type == ITEM_TYPE_OWNERDRAW && (item->textalignment == ITEM_ALIGN_CENTER || item->textalignment == ITEM_ALIGN_RIGHT)) {
- originalWidth += DC->ownerDrawWidth(item->window.ownerDraw, item->textscale);
- } else if (item->type == ITEM_TYPE_EDITFIELD && item->textalignment == ITEM_ALIGN_CENTER && item->cvar) {
- char buff[256];
- DC->getCVarString(item->cvar, buff, 256);
- originalWidth += DC->textWidth(buff, item->textscale, 0);
- }
-
- *width = DC->textWidth(textPtr, item->textscale, 0);
- *height = DC->textHeight(textPtr, item->textscale, 0);
- item->textRect.w = *width;
- item->textRect.h = *height;
- item->textRect.x = item->textalignx;
- item->textRect.y = item->textaligny;
- if (item->textalignment == ITEM_ALIGN_RIGHT) {
- item->textRect.x = item->textalignx - originalWidth;
- } else if (item->textalignment == ITEM_ALIGN_CENTER) {
- item->textRect.x = item->textalignx - originalWidth / 2;
- }
-
- ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
- }
-}
-
-void Item_TextColor(itemDef_t *item, vec4_t *newColor) {
- vec4_t lowLight;
- menuDef_t *parent = (menuDef_t*)item->parent;
-
- Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
- lowLight[0] = 0.8 * item->window.foreColor[0];
- lowLight[1] = 0.8 * item->window.foreColor[1];
- lowLight[2] = 0.8 * item->window.foreColor[2];
- lowLight[3] = 0.8 * item->window.foreColor[3];
- LerpColor(item->window.foreColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else {
- memcpy(newColor, &item->window.foreColor, sizeof(vec4_t));
- // items can be enabled and disabled based on cvars
- }
-
- if (item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
- if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
- memcpy(newColor, &parent->disableColor, sizeof(vec4_t));
- }
- }
-}
-
-void Item_Text_AutoWrapped_Paint(itemDef_t *item) {
- char text[1024];
- const char *p, *textPtr, *newLinePtr;
- char buff[1024];
- int width, height, len, textWidth, newLine, newLineWidth;
- float y;
- vec4_t color;
-
- textWidth = 0;
- newLinePtr = NULL;
-
- if (item->text == NULL) {
- if (item->cvar == NULL) {
- return;
- }
- else {
- DC->getCVarString(item->cvar, text, sizeof(text));
- textPtr = text;
- }
- }
- else {
- textPtr = item->text;
- }
- if (*textPtr == '\0') {
- return;
- }
- Item_TextColor(item, &color);
- Item_SetTextExtents(item, &width, &height, textPtr);
-
- y = item->textaligny;
- len = 0;
- buff[0] = '\0';
- newLine = 0;
- newLineWidth = 0;
- p = textPtr;
- while (p) {
- if (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\0') {
- newLine = len;
- newLinePtr = p+1;
- newLineWidth = textWidth;
- }
- textWidth = DC->textWidth(buff, item->textscale, 0);
- if ( (newLine && textWidth > item->window.rect.w) || *p == '\n' || *p == '\0') {
- if (len) {
- if (item->textalignment == ITEM_ALIGN_LEFT) {
- item->textRect.x = item->textalignx;
- } else if (item->textalignment == ITEM_ALIGN_RIGHT) {
- item->textRect.x = item->textalignx - newLineWidth;
- } else if (item->textalignment == ITEM_ALIGN_CENTER) {
- item->textRect.x = item->textalignx - newLineWidth / 2;
- }
- item->textRect.y = y;
- ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
- //
- buff[newLine] = '\0';
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, buff, 0, 0, item->textStyle);
- }
- if (*p == '\0') {
- break;
- }
- //
- y += height + 5;
- p = newLinePtr;
- len = 0;
- newLine = 0;
- newLineWidth = 0;
- continue;
- }
- buff[len++] = *p++;
- buff[len] = '\0';
- }
-}
-
-void Item_Text_Wrapped_Paint(itemDef_t *item) {
- char text[1024];
- const char *p, *start, *textPtr;
- char buff[1024];
- int width, height;
- float x, y;
- vec4_t color;
-
- // now paint the text and/or any optional images
- // default to left
-
- if (item->text == NULL) {
- if (item->cvar == NULL) {
- return;
- }
- else {
- DC->getCVarString(item->cvar, text, sizeof(text));
- textPtr = text;
- }
- }
- else {
- textPtr = item->text;
- }
- if (*textPtr == '\0') {
- return;
- }
-
- Item_TextColor(item, &color);
- Item_SetTextExtents(item, &width, &height, textPtr);
-
- x = item->textRect.x;
- y = item->textRect.y;
- start = textPtr;
- p = strchr(textPtr, '\r');
- while (p && *p) {
- strncpy(buff, start, p-start+1);
- buff[p-start] = '\0';
- DC->drawText(x, y, item->textscale, color, buff, 0, 0, item->textStyle);
- y += height + 5;
- start += p - start + 1;
- p = strchr(p+1, '\r');
- }
- DC->drawText(x, y, item->textscale, color, start, 0, 0, item->textStyle);
-}
-
-void Item_Text_Paint(itemDef_t *item) {
- char text[1024];
- const char *textPtr;
- int height, width;
- vec4_t color;
-
- if (item->window.flags & WINDOW_WRAPPED) {
- Item_Text_Wrapped_Paint(item);
- return;
- }
- if (item->window.flags & WINDOW_AUTOWRAPPED) {
- Item_Text_AutoWrapped_Paint(item);
- return;
- }
-
- if (item->text == NULL) {
- if (item->cvar == NULL) {
- return;
- }
- else {
- DC->getCVarString(item->cvar, text, sizeof(text));
- textPtr = text;
- }
- }
- else {
- textPtr = item->text;
- }
-
- // this needs to go here as it sets extents for cvar types as well
- Item_SetTextExtents(item, &width, &height, textPtr);
-
- if (*textPtr == '\0') {
- return;
- }
-
-
- Item_TextColor(item, &color);
-
- //FIXME: this is a fucking mess
-/*
- adjust = 0;
- if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
- adjust = 0.5;
- }
-
- if (item->textStyle == ITEM_TEXTSTYLE_SHADOWED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
- Fade(&item->window.flags, &DC->Assets.shadowColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
- DC->drawText(item->textRect.x + DC->Assets.shadowX, item->textRect.y + DC->Assets.shadowY, item->textscale, DC->Assets.shadowColor, textPtr, adjust);
- }
-*/
-
-
-// if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
-// Fade(&item->window.flags, &item->window.outlineColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
-// /*
-// Text_Paint(item->textRect.x-1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x+1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x-1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x+1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x-1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
-// Text_Paint(item->textRect.x+1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
-// */
-// DC->drawText(item->textRect.x - 1, item->textRect.y + 1, item->textscale * 1.02, item->window.outlineColor, textPtr, adjust);
-// }
-
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, textPtr, 0, 0, item->textStyle);
-}
-
-
-
-//float trap_Cvar_VariableValue( const char *var_name );
-//void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-
-void Item_TextField_Paint(itemDef_t *item) {
- char buff[1024];
- vec4_t newColor, lowLight;
- int offset;
- menuDef_t *parent = (menuDef_t*)item->parent;
- editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
-
- Item_Text_Paint(item);
-
- buff[0] = '\0';
-
- if (item->cvar) {
- DC->getCVarString(item->cvar, buff, sizeof(buff));
- }
-
- parent = (menuDef_t*)item->parent;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- offset = (item->text && *item->text) ? 8 : 0;
- if (item->window.flags & WINDOW_HASFOCUS && g_editingField) {
- char cursor = DC->getOverstrikeMode() ? '_' : '|';
- DC->drawTextWithCursor(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, item->cursorPos - editPtr->paintOffset , cursor, editPtr->maxPaintChars, item->textStyle);
- } else {
- DC->drawText(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, 0, editPtr->maxPaintChars, item->textStyle);
- }
-
-}
-
-void Item_YesNo_Paint(itemDef_t *item) {
- vec4_t newColor, lowLight;
- float value;
- menuDef_t *parent = (menuDef_t*)item->parent;
-
- value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- if (item->text) {
- Item_Text_Paint(item);
- DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
- } else {
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
- }
-}
-
-void Item_Multi_Paint(itemDef_t *item) {
- vec4_t newColor, lowLight;
- const char *text = "";
- menuDef_t *parent = (menuDef_t*)item->parent;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- text = Item_Multi_Setting(item);
-
- if (item->text) {
- Item_Text_Paint(item);
- DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
- } else {
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
- }
-}
-
-
-typedef struct {
- char *command;
- int id;
- int defaultbind1;
- int defaultbind2;
- int bind1;
- int bind2;
-} bind_t;
-
-typedef struct
-{
- char* name;
- float defaultvalue;
- float value;
-} configcvar_t;
-
-
-static bind_t g_bindings[] =
-{
- {"+scores", K_TAB, -1, -1, -1},
- {"+button2", K_ENTER, -1, -1, -1},
- {"+speed", K_SHIFT, -1, -1, -1},
- {"+forward", K_UPARROW, -1, -1, -1},
- {"+back", K_DOWNARROW, -1, -1, -1},
- {"+moveleft", ',', -1, -1, -1},
- {"+moveright", '.', -1, -1, -1},
- {"+moveup", K_SPACE, -1, -1, -1},
- {"+movedown", 'c', -1, -1, -1},
- {"+left", K_LEFTARROW, -1, -1, -1},
- {"+right", K_RIGHTARROW, -1, -1, -1},
- {"+strafe", K_ALT, -1, -1, -1},
- {"+lookup", K_PGDN, -1, -1, -1},
- {"+lookdown", K_DEL, -1, -1, -1},
- {"+mlook", '/', -1, -1, -1},
- {"centerview", K_END, -1, -1, -1},
- {"+zoom", -1, -1, -1, -1},
- {"weapon 1", '1', -1, -1, -1},
- {"weapon 2", '2', -1, -1, -1},
- {"weapon 3", '3', -1, -1, -1},
- {"weapon 4", '4', -1, -1, -1},
- {"weapon 5", '5', -1, -1, -1},
- {"weapon 6", '6', -1, -1, -1},
- {"weapon 7", '7', -1, -1, -1},
- {"weapon 8", '8', -1, -1, -1},
- {"weapon 9", '9', -1, -1, -1},
- {"weapon 10", '0', -1, -1, -1},
- {"weapon 11", -1, -1, -1, -1},
- {"weapon 12", -1, -1, -1, -1},
- {"weapon 13", -1, -1, -1, -1},
- {"+attack", K_CTRL, -1, -1, -1},
- {"weapprev", '[', -1, -1, -1},
- {"weapnext", ']', -1, -1, -1},
- {"+button3", K_MOUSE3, -1, -1, -1},
- {"+button4", K_MOUSE4, -1, -1, -1},
- {"prevTeamMember", 'w', -1, -1, -1},
- {"nextTeamMember", 'r', -1, -1, -1},
- {"nextOrder", 't', -1, -1, -1},
- {"confirmOrder", 'y', -1, -1, -1},
- {"denyOrder", 'n', -1, -1, -1},
- {"taskOffense", 'o', -1, -1, -1},
- {"taskDefense", 'd', -1, -1, -1},
- {"taskPatrol", 'p', -1, -1, -1},
- {"taskCamp", 'c', -1, -1, -1},
- {"taskFollow", 'f', -1, -1, -1},
- {"taskRetrieve", 'v', -1, -1, -1},
- {"taskEscort", 'e', -1, -1, -1},
- {"taskOwnFlag", 'i', -1, -1, -1},
- {"taskSuicide", 'k', -1, -1, -1},
- {"tauntKillInsult", K_F1, -1, -1, -1},
- {"tauntPraise", K_F2, -1, -1, -1},
- {"tauntTaunt", K_F3, -1, -1, -1},
- {"tauntDeathInsult", K_F4, -1, -1, -1},
- {"tauntGauntlet", K_F5, -1, -1, -1},
- {"scoresUp", K_KP_PGUP, -1, -1, -1},
- {"scoresDown", K_KP_PGDN, -1, -1, -1},
- // bk001205 - this one below was: '-1'
- {"messagemode", -1, -1, -1, -1},
- {"messagemode2", -1, -1, -1, -1},
- {"messagemode3", -1, -1, -1, -1},
- {"messagemode4", -1, -1, -1, -1}
-};
-
-
-static const int g_bindCount = sizeof(g_bindings) / sizeof(bind_t);
-
-#ifndef MISSIONPACK // bk001206
-static configcvar_t g_configcvars[] =
-{
- {"cl_run", 0, 0},
- {"m_pitch", 0, 0},
- {"cg_autoswitch", 0, 0},
- {"sensitivity", 0, 0},
- {"in_joystick", 0, 0},
- {"joy_threshold", 0, 0},
- {"m_filter", 0, 0},
- {"cl_freelook", 0, 0},
- {NULL, 0, 0}
-};
-#endif
-
-/*
-=================
-Controls_GetKeyAssignment
-=================
-*/
-static void Controls_GetKeyAssignment (char *command, int *twokeys)
-{
- int count;
- int j;
- char b[256];
-
- twokeys[0] = twokeys[1] = -1;
- count = 0;
-
- for ( j = 0; j < 256; j++ )
- {
- DC->getBindingBuf( j, b, 256 );
- if ( *b == 0 ) {
- continue;
- }
- if ( !Q_stricmp( b, command ) ) {
- twokeys[count] = j;
- count++;
- if (count == 2) {
- break;
- }
- }
- }
-}
-
-/*
-=================
-Controls_GetConfig
-=================
-*/
-void Controls_GetConfig( void )
-{
- int i;
- int twokeys[2];
-
- // iterate each command, get its numeric binding
- for (i=0; i < g_bindCount; i++)
- {
-
- Controls_GetKeyAssignment(g_bindings[i].command, twokeys);
-
- g_bindings[i].bind1 = twokeys[0];
- g_bindings[i].bind2 = twokeys[1];
- }
-
- //s_controls.invertmouse.curvalue = DC->getCVarValue( "m_pitch" ) < 0;
- //s_controls.smoothmouse.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "m_filter" ) );
- //s_controls.alwaysrun.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_run" ) );
- //s_controls.autoswitch.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_autoswitch" ) );
- //s_controls.sensitivity.curvalue = UI_ClampCvar( 2, 30, Controls_GetCvarValue( "sensitivity" ) );
- //s_controls.joyenable.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "in_joystick" ) );
- //s_controls.joythreshold.curvalue = UI_ClampCvar( 0.05, 0.75, Controls_GetCvarValue( "joy_threshold" ) );
- //s_controls.freelook.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_freelook" ) );
-}
-
-/*
-=================
-Controls_SetConfig
-=================
-*/
-void Controls_SetConfig(qboolean restart)
-{
- int i;
-
- // iterate each command, get its numeric binding
- for (i=0; i < g_bindCount; i++)
- {
-
- if (g_bindings[i].bind1 != -1)
- {
- DC->setBinding( g_bindings[i].bind1, g_bindings[i].command );
-
- if (g_bindings[i].bind2 != -1)
- DC->setBinding( g_bindings[i].bind2, g_bindings[i].command );
- }
- }
-
- //if ( s_controls.invertmouse.curvalue )
- // DC->setCVar("m_pitch", va("%f),-fabs( DC->getCVarValue( "m_pitch" ) ) );
- //else
- // trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
-
- //trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue );
- //trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue );
- //trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue );
- //trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue );
- //trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue );
- //trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue );
- //trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue );
- DC->executeText(EXEC_APPEND, "in_restart\n");
- //trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" );
-}
-
-/*
-=================
-Controls_SetDefaults
-=================
-*/
-void Controls_SetDefaults( void )
-{
- int i;
-
- // iterate each command, set its default binding
- for (i=0; i < g_bindCount; i++)
- {
- g_bindings[i].bind1 = g_bindings[i].defaultbind1;
- g_bindings[i].bind2 = g_bindings[i].defaultbind2;
- }
-
- //s_controls.invertmouse.curvalue = Controls_GetCvarDefault( "m_pitch" ) < 0;
- //s_controls.smoothmouse.curvalue = Controls_GetCvarDefault( "m_filter" );
- //s_controls.alwaysrun.curvalue = Controls_GetCvarDefault( "cl_run" );
- //s_controls.autoswitch.curvalue = Controls_GetCvarDefault( "cg_autoswitch" );
- //s_controls.sensitivity.curvalue = Controls_GetCvarDefault( "sensitivity" );
- //s_controls.joyenable.curvalue = Controls_GetCvarDefault( "in_joystick" );
- //s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" );
- //s_controls.freelook.curvalue = Controls_GetCvarDefault( "cl_freelook" );
-}
-
-int BindingIDFromName(const char *name) {
- int i;
- for (i=0; i < g_bindCount; i++)
- {
- if (Q_stricmp(name, g_bindings[i].command) == 0) {
- return i;
- }
- }
- return -1;
-}
-
-char g_nameBind1[32];
-char g_nameBind2[32];
-
-void BindingFromName(const char *cvar) {
- int i, b1, b2;
-
- // iterate each command, set its default binding
- for (i=0; i < g_bindCount; i++)
- {
- if (Q_stricmp(cvar, g_bindings[i].command) == 0) {
- b1 = g_bindings[i].bind1;
- if (b1 == -1) {
- break;
- }
- DC->keynumToStringBuf( b1, g_nameBind1, 32 );
- Q_strupr(g_nameBind1);
-
- b2 = g_bindings[i].bind2;
- if (b2 != -1)
- {
- DC->keynumToStringBuf( b2, g_nameBind2, 32 );
- Q_strupr(g_nameBind2);
- strcat( g_nameBind1, " or " );
- strcat( g_nameBind1, g_nameBind2 );
- }
- return;
- }
- }
- strcpy(g_nameBind1, "???");
-}
-
-void Item_Slider_Paint(itemDef_t *item) {
- vec4_t newColor, lowLight;
- float x, y, value;
- menuDef_t *parent = (menuDef_t*)item->parent;
-
- value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- y = item->window.rect.y;
- if (item->text) {
- Item_Text_Paint(item);
- x = item->textRect.x + item->textRect.w + 8;
- } else {
- x = item->window.rect.x;
- }
- DC->setColor(newColor);
- DC->drawHandlePic( x, y, SLIDER_WIDTH, SLIDER_HEIGHT, DC->Assets.sliderBar );
-
- x = Item_Slider_ThumbPosition(item);
- DC->drawHandlePic( x - (SLIDER_THUMB_WIDTH / 2), y - 2, SLIDER_THUMB_WIDTH, SLIDER_THUMB_HEIGHT, DC->Assets.sliderThumb );
-
-}
-
-void Item_Bind_Paint(itemDef_t *item) {
- vec4_t newColor, lowLight;
- float value;
- int maxChars = 0;
- menuDef_t *parent = (menuDef_t*)item->parent;
- editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
- if (editPtr) {
- maxChars = editPtr->maxPaintChars;
- }
-
- value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- if (g_bindItem == item) {
- lowLight[0] = 0.8f * 1.0f;
- lowLight[1] = 0.8f * 0.0f;
- lowLight[2] = 0.8f * 0.0f;
- lowLight[3] = 0.8f * 1.0f;
- } else {
- lowLight[0] = 0.8f * parent->focusColor[0];
- lowLight[1] = 0.8f * parent->focusColor[1];
- lowLight[2] = 0.8f * parent->focusColor[2];
- lowLight[3] = 0.8f * parent->focusColor[3];
- }
- LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else {
- memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
- }
-
- if (item->text) {
- Item_Text_Paint(item);
- BindingFromName(item->cvar);
- DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, g_nameBind1, 0, maxChars, item->textStyle);
- } else {
- DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "FIXME" : "FIXME", 0, maxChars, item->textStyle);
- }
-}
-
-qboolean Display_KeyBindPending(void) {
- return g_waitingForKey;
-}
-
-qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) {
- int id;
- int i;
-
- if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey)
- {
- if (down && (key == K_MOUSE1 || key == K_ENTER)) {
- g_waitingForKey = qtrue;
- g_bindItem = item;
- }
- return qtrue;
- }
- else
- {
- if (!g_waitingForKey || g_bindItem == NULL) {
- return qtrue;
- }
-
- if (key & K_CHAR_FLAG) {
- return qtrue;
- }
-
- switch (key)
- {
- case K_ESCAPE:
- g_waitingForKey = qfalse;
- return qtrue;
-
- case K_BACKSPACE:
- id = BindingIDFromName(item->cvar);
- if (id != -1) {
- g_bindings[id].bind1 = -1;
- g_bindings[id].bind2 = -1;
- }
- Controls_SetConfig(qtrue);
- g_waitingForKey = qfalse;
- g_bindItem = NULL;
- return qtrue;
-
- case '`':
- return qtrue;
- }
- }
-
- if (key != -1)
- {
-
- for (i=0; i < g_bindCount; i++)
- {
-
- if (g_bindings[i].bind2 == key) {
- g_bindings[i].bind2 = -1;
- }
-
- if (g_bindings[i].bind1 == key)
- {
- g_bindings[i].bind1 = g_bindings[i].bind2;
- g_bindings[i].bind2 = -1;
- }
- }
- }
-
-
- id = BindingIDFromName(item->cvar);
-
- if (id != -1) {
- if (key == -1) {
- if( g_bindings[id].bind1 != -1 ) {
- DC->setBinding( g_bindings[id].bind1, "" );
- g_bindings[id].bind1 = -1;
- }
- if( g_bindings[id].bind2 != -1 ) {
- DC->setBinding( g_bindings[id].bind2, "" );
- g_bindings[id].bind2 = -1;
- }
- }
- else if (g_bindings[id].bind1 == -1) {
- g_bindings[id].bind1 = key;
- }
- else if (g_bindings[id].bind1 != key && g_bindings[id].bind2 == -1) {
- g_bindings[id].bind2 = key;
- }
- else {
- DC->setBinding( g_bindings[id].bind1, "" );
- DC->setBinding( g_bindings[id].bind2, "" );
- g_bindings[id].bind1 = key;
- g_bindings[id].bind2 = -1;
- }
- }
-
- Controls_SetConfig(qtrue);
- g_waitingForKey = qfalse;
-
- return qtrue;
-}
-
-
-
-void AdjustFrom640(float *x, float *y, float *w, float *h) {
- //*x = *x * DC->scale + DC->bias;
- *x *= DC->xscale;
- *y *= DC->yscale;
- *w *= DC->xscale;
- *h *= DC->yscale;
-}
-
-void Item_Model_Paint(itemDef_t *item) {
- float x, y, w, h;
- refdef_t refdef;
- refEntity_t ent;
- vec3_t mins, maxs, origin;
- vec3_t angles;
- modelDef_t *modelPtr = (modelDef_t*)item->typeData;
-
- if (modelPtr == NULL) {
- return;
- }
-
- // setup the refdef
- memset( &refdef, 0, sizeof( refdef ) );
- refdef.rdflags = RDF_NOWORLDMODEL;
- AxisClear( refdef.viewaxis );
- x = item->window.rect.x+1;
- y = item->window.rect.y+1;
- w = item->window.rect.w-2;
- h = item->window.rect.h-2;
-
- AdjustFrom640( &x, &y, &w, &h );
-
- refdef.x = x;
- refdef.y = y;
- refdef.width = w;
- refdef.height = h;
-
- DC->modelBounds( item->asset, mins, maxs );
-
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
-
- // calculate distance so the model nearly fills the box
- if (qtrue) {
- float len = 0.5 * ( maxs[2] - mins[2] );
- origin[0] = len / 0.268; // len / tan( fov/2 )
- //origin[0] = len / tan(w/2);
- } else {
- origin[0] = item->textscale;
- }
- refdef.fov_x = (modelPtr->fov_x) ? modelPtr->fov_x : w;
- refdef.fov_y = (modelPtr->fov_y) ? modelPtr->fov_y : h;
-
- //refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
- //xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
- //refdef.fov_y = atan2( refdef.height, xx );
- //refdef.fov_y *= ( 360 / M_PI );
-
- DC->clearScene();
-
- refdef.time = DC->realTime;
-
- // add the model
-
- memset( &ent, 0, sizeof(ent) );
-
- //adjust = 5.0 * sin( (float)uis.realtime / 500 );
- //adjust = 360 % (int)((float)uis.realtime / 1000);
- //VectorSet( angles, 0, 0, 1 );
-
- // use item storage to track
- if (modelPtr->rotationSpeed) {
- if (DC->realTime > item->window.nextTime) {
- item->window.nextTime = DC->realTime + modelPtr->rotationSpeed;
- modelPtr->angle = (int)(modelPtr->angle + 1) % 360;
- }
- }
- VectorSet( angles, 0, modelPtr->angle, 0 );
- AnglesToAxis( angles, ent.axis );
-
- ent.hModel = item->asset;
- VectorCopy( origin, ent.origin );
- VectorCopy( origin, ent.lightingOrigin );
- ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
- VectorCopy( ent.origin, ent.oldorigin );
-
- DC->addRefEntityToScene( &ent );
- DC->renderScene( &refdef );
-
-}
-
-
-void Item_Image_Paint(itemDef_t *item) {
- if (item == NULL) {
- return;
- }
- DC->drawHandlePic(item->window.rect.x+1, item->window.rect.y+1, item->window.rect.w-2, item->window.rect.h-2, item->asset);
-}
-
-void Item_ListBox_Paint(itemDef_t *item) {
- float x, y, size, count, i, thumb;
- qhandle_t image;
- qhandle_t optionalImage;
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
-
- // the listbox is horizontal or vertical and has a fixed size scroll bar going either direction
- // elements are enumerated from the DC and either text or image handles are acquired from the DC as well
- // textscale is used to size the text, textalignx and textaligny are used to size image elements
- // there is no clipping available so only the last completely visible item is painted
- count = DC->feederCount(item->special);
- // default is vertical if horizontal flag is not here
- if (item->window.flags & WINDOW_HORIZONTAL) {
- // draw scrollbar in bottom of the window
- // bar
- x = item->window.rect.x + 1;
- y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE - 1;
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowLeft);
- x += SCROLLBAR_SIZE - 1;
- size = item->window.rect.w - (SCROLLBAR_SIZE * 2);
- DC->drawHandlePic(x, y, size+1, SCROLLBAR_SIZE, DC->Assets.scrollBar);
- x += size - 1;
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowRight);
- // thumb
- thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
- if (thumb > x - SCROLLBAR_SIZE - 1) {
- thumb = x - SCROLLBAR_SIZE - 1;
- }
- DC->drawHandlePic(thumb, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
- //
- listPtr->endPos = listPtr->startPos;
- size = item->window.rect.w - 2;
- // items
- // size contains max available space
- if (listPtr->elementStyle == LISTBOX_IMAGE) {
- // fit = 0;
- x = item->window.rect.x + 1;
- y = item->window.rect.y + 1;
- for (i = listPtr->startPos; i < count; i++) {
- // always draw at least one
- // which may overdraw the box if it is too small for the element
- image = DC->feederItemImage(item->special, i);
- if (image) {
- DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
- }
-
- if (i == item->cursorPos) {
- DC->drawRect(x, y, listPtr->elementWidth-1, listPtr->elementHeight-1, item->window.borderSize, item->window.borderColor);
- }
-
- size -= listPtr->elementWidth;
- if (size < listPtr->elementWidth) {
- listPtr->drawPadding = size; //listPtr->elementWidth - size;
- break;
- }
- x += listPtr->elementWidth;
- listPtr->endPos++;
- // fit++;
- }
- } else {
- //
- }
- } else {
- // draw scrollbar to right side of the window
- x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE - 1;
- y = item->window.rect.y + 1;
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowUp);
- y += SCROLLBAR_SIZE - 1;
-
- listPtr->endPos = listPtr->startPos;
- size = item->window.rect.h - (SCROLLBAR_SIZE * 2);
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, size+1, DC->Assets.scrollBar);
- y += size - 1;
- DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowDown);
- // thumb
- thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
- if (thumb > y - SCROLLBAR_SIZE - 1) {
- thumb = y - SCROLLBAR_SIZE - 1;
- }
- DC->drawHandlePic(x, thumb, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
-
- // adjust size for item painting
- size = item->window.rect.h - 2;
- if (listPtr->elementStyle == LISTBOX_IMAGE) {
- // fit = 0;
- x = item->window.rect.x + 1;
- y = item->window.rect.y + 1;
- for (i = listPtr->startPos; i < count; i++) {
- // always draw at least one
- // which may overdraw the box if it is too small for the element
- image = DC->feederItemImage(item->special, i);
- if (image) {
- DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
- }
-
- if (i == item->cursorPos) {
- DC->drawRect(x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, item->window.borderSize, item->window.borderColor);
- }
-
- listPtr->endPos++;
- size -= listPtr->elementWidth;
- if (size < listPtr->elementHeight) {
- listPtr->drawPadding = listPtr->elementHeight - size;
- break;
- }
- y += listPtr->elementHeight;
- // fit++;
- }
- } else {
- x = item->window.rect.x + 1;
- y = item->window.rect.y + 1;
- for (i = listPtr->startPos; i < count; i++) {
- const char *text;
- // always draw at least one
- // which may overdraw the box if it is too small for the element
-
- if (listPtr->numColumns > 0) {
- int j;
- for (j = 0; j < listPtr->numColumns; j++) {
- text = DC->feederItemText(item->special, i, j, &optionalImage);
- if (optionalImage >= 0) {
- DC->drawHandlePic(x + 4 + listPtr->columnInfo[j].pos, y - 1 + listPtr->elementHeight / 2, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
- } else if (text) {
- DC->drawText(x + 4 + listPtr->columnInfo[j].pos, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, listPtr->columnInfo[j].maxChars, item->textStyle);
- }
- }
- } else {
- text = DC->feederItemText(item->special, i, 0, &optionalImage);
- if (optionalImage >= 0) {
- //DC->drawHandlePic(x + 4 + listPtr->elementHeight, y, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
- } else if (text) {
- DC->drawText(x + 4, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, 0, item->textStyle);
- }
- }
-
- if (i == item->cursorPos) {
- DC->fillRect(x + 2, y + 2, item->window.rect.w - SCROLLBAR_SIZE - 4, listPtr->elementHeight, item->window.outlineColor);
- }
-
- size -= listPtr->elementHeight;
- if (size < listPtr->elementHeight) {
- listPtr->drawPadding = listPtr->elementHeight - size;
- break;
- }
- listPtr->endPos++;
- y += listPtr->elementHeight;
- // fit++;
- }
- }
- }
-}
-
-
-void Item_OwnerDraw_Paint(itemDef_t *item) {
- menuDef_t *parent;
-
- if (item == NULL) {
- return;
- }
- parent = (menuDef_t*)item->parent;
-
- if (DC->ownerDrawItem) {
- vec4_t color, lowLight;
- menuDef_t *parent = (menuDef_t*)item->parent;
- Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
- memcpy(&color, &item->window.foreColor, sizeof(color));
- if (item->numColors > 0 && DC->getValue) {
- // if the value is within one of the ranges then set color to that, otherwise leave at default
- int i;
- float f = DC->getValue(item->window.ownerDraw);
- for (i = 0; i < item->numColors; i++) {
- if (f >= item->colorRanges[i].low && f <= item->colorRanges[i].high) {
- memcpy(&color, &item->colorRanges[i].color, sizeof(color));
- break;
- }
- }
- }
-
- if (item->window.flags & WINDOW_HASFOCUS) {
- lowLight[0] = 0.8 * parent->focusColor[0];
- lowLight[1] = 0.8 * parent->focusColor[1];
- lowLight[2] = 0.8 * parent->focusColor[2];
- lowLight[3] = 0.8 * parent->focusColor[3];
- LerpColor(parent->focusColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
- lowLight[0] = 0.8 * item->window.foreColor[0];
- lowLight[1] = 0.8 * item->window.foreColor[1];
- lowLight[2] = 0.8 * item->window.foreColor[2];
- lowLight[3] = 0.8 * item->window.foreColor[3];
- LerpColor(item->window.foreColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
- }
-
- if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
- Com_Memcpy(color, parent->disableColor, sizeof(vec4_t));
- }
-
- if (item->text) {
- Item_Text_Paint(item);
- if (item->text[0]) {
- // +8 is an offset kludge to properly align owner draw items that have text combined with them
- DC->ownerDrawItem(item->textRect.x + item->textRect.w + 8, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
- } else {
- DC->ownerDrawItem(item->textRect.x + item->textRect.w, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
- }
- } else {
- DC->ownerDrawItem(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, item->textalignx, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
- }
- }
-}
-
-
-void Item_Paint(itemDef_t *item) {
- vec4_t red;
- menuDef_t *parent = (menuDef_t*)item->parent;
- red[0] = red[3] = 1;
- red[1] = red[2] = 0;
-
- if (item == NULL) {
- return;
- }
-
- if (item->window.flags & WINDOW_ORBITING) {
- if (DC->realTime > item->window.nextTime) {
- float rx, ry, a, c, s, w, h;
-
- item->window.nextTime = DC->realTime + item->window.offsetTime;
- // translate
- w = item->window.rectClient.w / 2;
- h = item->window.rectClient.h / 2;
- rx = item->window.rectClient.x + w - item->window.rectEffects.x;
- ry = item->window.rectClient.y + h - item->window.rectEffects.y;
- a = 3 * M_PI / 180;
- c = cos(a);
- s = sin(a);
- item->window.rectClient.x = (rx * c - ry * s) + item->window.rectEffects.x - w;
- item->window.rectClient.y = (rx * s + ry * c) + item->window.rectEffects.y - h;
- Item_UpdatePosition(item);
-
- }
- }
-
-
- if (item->window.flags & WINDOW_INTRANSITION) {
- if (DC->realTime > item->window.nextTime) {
- int done = 0;
- item->window.nextTime = DC->realTime + item->window.offsetTime;
- // transition the x,y
- if (item->window.rectClient.x == item->window.rectEffects.x) {
- done++;
- } else {
- if (item->window.rectClient.x < item->window.rectEffects.x) {
- item->window.rectClient.x += item->window.rectEffects2.x;
- if (item->window.rectClient.x > item->window.rectEffects.x) {
- item->window.rectClient.x = item->window.rectEffects.x;
- done++;
- }
- } else {
- item->window.rectClient.x -= item->window.rectEffects2.x;
- if (item->window.rectClient.x < item->window.rectEffects.x) {
- item->window.rectClient.x = item->window.rectEffects.x;
- done++;
- }
- }
- }
- if (item->window.rectClient.y == item->window.rectEffects.y) {
- done++;
- } else {
- if (item->window.rectClient.y < item->window.rectEffects.y) {
- item->window.rectClient.y += item->window.rectEffects2.y;
- if (item->window.rectClient.y > item->window.rectEffects.y) {
- item->window.rectClient.y = item->window.rectEffects.y;
- done++;
- }
- } else {
- item->window.rectClient.y -= item->window.rectEffects2.y;
- if (item->window.rectClient.y < item->window.rectEffects.y) {
- item->window.rectClient.y = item->window.rectEffects.y;
- done++;
- }
- }
- }
- if (item->window.rectClient.w == item->window.rectEffects.w) {
- done++;
- } else {
- if (item->window.rectClient.w < item->window.rectEffects.w) {
- item->window.rectClient.w += item->window.rectEffects2.w;
- if (item->window.rectClient.w > item->window.rectEffects.w) {
- item->window.rectClient.w = item->window.rectEffects.w;
- done++;
- }
- } else {
- item->window.rectClient.w -= item->window.rectEffects2.w;
- if (item->window.rectClient.w < item->window.rectEffects.w) {
- item->window.rectClient.w = item->window.rectEffects.w;
- done++;
- }
- }
- }
- if (item->window.rectClient.h == item->window.rectEffects.h) {
- done++;
- } else {
- if (item->window.rectClient.h < item->window.rectEffects.h) {
- item->window.rectClient.h += item->window.rectEffects2.h;
- if (item->window.rectClient.h > item->window.rectEffects.h) {
- item->window.rectClient.h = item->window.rectEffects.h;
- done++;
- }
- } else {
- item->window.rectClient.h -= item->window.rectEffects2.h;
- if (item->window.rectClient.h < item->window.rectEffects.h) {
- item->window.rectClient.h = item->window.rectEffects.h;
- done++;
- }
- }
- }
-
- Item_UpdatePosition(item);
-
- if (done == 4) {
- item->window.flags &= ~WINDOW_INTRANSITION;
- }
-
- }
- }
-
- if (item->window.ownerDrawFlags && DC->ownerDrawVisible) {
- if (!DC->ownerDrawVisible(item->window.ownerDrawFlags)) {
- item->window.flags &= ~WINDOW_VISIBLE;
- } else {
- item->window.flags |= WINDOW_VISIBLE;
- }
- }
-
- if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE)) {
- if (!Item_EnableShowViaCvar(item, CVAR_SHOW)) {
- return;
- }
- }
-
- if (item->window.flags & WINDOW_TIMEDVISIBLE) {
-
- }
-
- if (!(item->window.flags & WINDOW_VISIBLE)) {
- return;
- }
-
- // paint the rect first..
- Window_Paint(&item->window, parent->fadeAmount , parent->fadeClamp, parent->fadeCycle);
-
- if (debugMode) {
- vec4_t color;
- rectDef_t *r = Item_CorrectedTextRect(item);
- color[1] = color[3] = 1;
- color[0] = color[2] = 0;
- DC->drawRect(r->x, r->y, r->w, r->h, 1, color);
- }
-
- //DC->drawRect(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, 1, red);
-
- switch (item->type) {
- case ITEM_TYPE_OWNERDRAW:
- Item_OwnerDraw_Paint(item);
- break;
- case ITEM_TYPE_TEXT:
- case ITEM_TYPE_BUTTON:
- Item_Text_Paint(item);
- break;
- case ITEM_TYPE_RADIOBUTTON:
- break;
- case ITEM_TYPE_CHECKBOX:
- break;
- case ITEM_TYPE_EDITFIELD:
- case ITEM_TYPE_NUMERICFIELD:
- Item_TextField_Paint(item);
- break;
- case ITEM_TYPE_COMBO:
- break;
- case ITEM_TYPE_LISTBOX:
- Item_ListBox_Paint(item);
- break;
- //case ITEM_TYPE_IMAGE:
- // Item_Image_Paint(item);
- // break;
- case ITEM_TYPE_MODEL:
- Item_Model_Paint(item);
- break;
- case ITEM_TYPE_YESNO:
- Item_YesNo_Paint(item);
- break;
- case ITEM_TYPE_MULTI:
- Item_Multi_Paint(item);
- break;
- case ITEM_TYPE_BIND:
- Item_Bind_Paint(item);
- break;
- case ITEM_TYPE_SLIDER:
- Item_Slider_Paint(item);
- break;
- default:
- break;
- }
-
-}
-
-void Menu_Init(menuDef_t *menu) {
- memset(menu, 0, sizeof(menuDef_t));
- menu->cursorItem = -1;
- menu->fadeAmount = DC->Assets.fadeAmount;
- menu->fadeClamp = DC->Assets.fadeClamp;
- menu->fadeCycle = DC->Assets.fadeCycle;
- Window_Init(&menu->window);
-}
-
-itemDef_t *Menu_GetFocusedItem(menuDef_t *menu) {
- int i;
- if (menu) {
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
- return menu->items[i];
- }
- }
- }
- return NULL;
-}
-
-menuDef_t *Menu_GetFocused(void) {
- int i;
- for (i = 0; i < menuCount; i++) {
- if (Menus[i].window.flags & WINDOW_HASFOCUS && Menus[i].window.flags & WINDOW_VISIBLE) {
- return &Menus[i];
- }
- }
- return NULL;
-}
-
-void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down) {
- if (menu) {
- int i;
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->special == feeder) {
- Item_ListBox_HandleKey(menu->items[i], (down) ? K_DOWNARROW : K_UPARROW, qtrue, qtrue);
- return;
- }
- }
- }
-}
-
-
-
-void Menu_SetFeederSelection(menuDef_t *menu, int feeder, int index, const char *name) {
- if (menu == NULL) {
- if (name == NULL) {
- menu = Menu_GetFocused();
- } else {
- menu = Menus_FindByName(name);
- }
- }
-
- if (menu) {
- int i;
- for (i = 0; i < menu->itemCount; i++) {
- if (menu->items[i]->special == feeder) {
- if (index == 0) {
- listBoxDef_t *listPtr = (listBoxDef_t*)menu->items[i]->typeData;
- listPtr->cursorPos = 0;
- listPtr->startPos = 0;
- }
- menu->items[i]->cursorPos = index;
- DC->feederSelection(menu->items[i]->special, menu->items[i]->cursorPos);
- return;
- }
- }
- }
-}
-
-qboolean Menus_AnyFullScreenVisible(void) {
- int i;
- for (i = 0; i < menuCount; i++) {
- if (Menus[i].window.flags & WINDOW_VISIBLE && Menus[i].fullScreen) {
- return qtrue;
- }
- }
- return qfalse;
-}
-
-menuDef_t *Menus_ActivateByName(const char *p) {
- int i;
- menuDef_t *m = NULL;
- menuDef_t *focus = Menu_GetFocused();
- for (i = 0; i < menuCount; i++) {
- if (Q_stricmp(Menus[i].window.name, p) == 0) {
- m = &Menus[i];
- Menus_Activate(m);
- if (openMenuCount < MAX_OPEN_MENUS && focus != NULL) {
- menuStack[openMenuCount++] = focus;
- }
- } else {
- Menus[i].window.flags &= ~WINDOW_HASFOCUS;
- }
- }
- Display_CloseCinematics();
- return m;
-}
-
-
-void Item_Init(itemDef_t *item) {
- memset(item, 0, sizeof(itemDef_t));
- item->textscale = 0.55f;
- Window_Init(&item->window);
-}
-
-void Menu_HandleMouseMove(menuDef_t *menu, float x, float y) {
- int i, pass;
- qboolean focusSet = qfalse;
-
- itemDef_t *overItem;
- if (menu == NULL) {
- return;
- }
-
- if (!(menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
- return;
- }
-
- if (itemCapture) {
- //Item_MouseMove(itemCapture, x, y);
- return;
- }
-
- if (g_waitingForKey || g_editingField) {
- return;
- }
-
- // FIXME: this is the whole issue of focus vs. mouse over..
- // need a better overall solution as i don't like going through everything twice
- for (pass = 0; pass < 2; pass++) {
- for (i = 0; i < menu->itemCount; i++) {
- // turn off focus each item
- // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
-
- if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
- continue;
- }
-
- // items can be enabled and disabled based on cvars
- if (menu->items[i]->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_ENABLE)) {
- continue;
- }
-
- if (menu->items[i]->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_SHOW)) {
- continue;
- }
-
-
-
- if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
- if (pass == 1) {
- overItem = menu->items[i];
- if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
- if (!Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
- continue;
- }
- }
- // if we are over an item
- if (IsVisible(overItem->window.flags)) {
- // different one
- Item_MouseEnter(overItem, x, y);
- // Item_SetMouseOver(overItem, qtrue);
-
- // if item is not a decoration see if it can take focus
- if (!focusSet) {
- focusSet = Item_SetFocus(overItem, x, y);
- }
- }
- }
- } else if (menu->items[i]->window.flags & WINDOW_MOUSEOVER) {
- Item_MouseLeave(menu->items[i]);
- Item_SetMouseOver(menu->items[i], qfalse);
- }
- }
- }
-
-}
-
-void Menu_Paint(menuDef_t *menu, qboolean forcePaint) {
- int i;
-
- if (menu == NULL) {
- return;
- }
-
- if (!(menu->window.flags & WINDOW_VISIBLE) && !forcePaint) {
- return;
- }
-
- if (menu->window.ownerDrawFlags && DC->ownerDrawVisible && !DC->ownerDrawVisible(menu->window.ownerDrawFlags)) {
- return;
- }
-
- if (forcePaint) {
- menu->window.flags |= WINDOW_FORCED;
- }
-
- // draw the background if necessary
- if (menu->fullScreen) {
- // implies a background shader
- // FIXME: make sure we have a default shader if fullscreen is set with no background
- DC->drawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, menu->window.background );
- } else if (menu->window.background) {
- // this allows a background shader without being full screen
- //UI_DrawHandlePic(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, menu->backgroundShader);
- }
-
- // paint the background and or border
- Window_Paint(&menu->window, menu->fadeAmount, menu->fadeClamp, menu->fadeCycle );
-
- for (i = 0; i < menu->itemCount; i++) {
- Item_Paint(menu->items[i]);
- }
-
- if (debugMode) {
- vec4_t color;
- color[0] = color[2] = color[3] = 1;
- color[1] = 0;
- DC->drawRect(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, 1, color);
- }
-}
-
-/*
-===============
-Item_ValidateTypeData
-===============
-*/
-void Item_ValidateTypeData(itemDef_t *item) {
- if (item->typeData) {
- return;
- }
-
- if (item->type == ITEM_TYPE_LISTBOX) {
- item->typeData = UI_Alloc(sizeof(listBoxDef_t));
- memset(item->typeData, 0, sizeof(listBoxDef_t));
- } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD || item->type == ITEM_TYPE_YESNO || item->type == ITEM_TYPE_BIND || item->type == ITEM_TYPE_SLIDER || item->type == ITEM_TYPE_TEXT) {
- item->typeData = UI_Alloc(sizeof(editFieldDef_t));
- memset(item->typeData, 0, sizeof(editFieldDef_t));
- if (item->type == ITEM_TYPE_EDITFIELD) {
- if (!((editFieldDef_t *) item->typeData)->maxPaintChars) {
- ((editFieldDef_t *) item->typeData)->maxPaintChars = MAX_EDITFIELD;
- }
- }
- } else if (item->type == ITEM_TYPE_MULTI) {
- item->typeData = UI_Alloc(sizeof(multiDef_t));
- } else if (item->type == ITEM_TYPE_MODEL) {
- item->typeData = UI_Alloc(sizeof(modelDef_t));
- }
-}
-
-/*
-===============
-Keyword Hash
-===============
-*/
-
-#define KEYWORDHASH_SIZE 512
-
-typedef struct keywordHash_s
-{
- char *keyword;
- qboolean (*func)(itemDef_t *item, int handle);
- struct keywordHash_s *next;
-} keywordHash_t;
-
-int KeywordHash_Key(char *keyword) {
- int register hash, i;
-
- hash = 0;
- for (i = 0; keyword[i] != '\0'; i++) {
- if (keyword[i] >= 'A' && keyword[i] <= 'Z')
- hash += (keyword[i] + ('a' - 'A')) * (119 + i);
- else
- hash += keyword[i] * (119 + i);
- }
- hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (KEYWORDHASH_SIZE-1);
- return hash;
-}
-
-void KeywordHash_Add(keywordHash_t *table[], keywordHash_t *key) {
- int hash;
-
- hash = KeywordHash_Key(key->keyword);
-/*
- if (table[hash]) {
- int collision = qtrue;
- }
-*/
- key->next = table[hash];
- table[hash] = key;
-}
-
-keywordHash_t *KeywordHash_Find(keywordHash_t *table[], char *keyword)
-{
- keywordHash_t *key;
- int hash;
-
- hash = KeywordHash_Key(keyword);
- for (key = table[hash]; key; key = key->next) {
- if (!Q_stricmp(key->keyword, keyword))
- return key;
- }
- return NULL;
-}
-
-/*
-===============
-Item Keyword Parse functions
-===============
-*/
-
-// name <string>
-qboolean ItemParse_name( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->window.name)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// name <string>
-qboolean ItemParse_focusSound( itemDef_t *item, int handle ) {
- const char *temp;
- if (!PC_String_Parse(handle, &temp)) {
- return qfalse;
- }
- item->focusSound = DC->registerSound(temp, qfalse);
- return qtrue;
-}
-
-
-// text <string>
-qboolean ItemParse_text( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->text)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// group <string>
-qboolean ItemParse_group( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->window.group)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// asset_model <string>
-qboolean ItemParse_asset_model( itemDef_t *item, int handle ) {
- const char *temp;
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_String_Parse(handle, &temp)) {
- return qfalse;
- }
- item->asset = DC->registerModel(temp);
- modelPtr->angle = rand() % 360;
- return qtrue;
-}
-
-// asset_shader <string>
-qboolean ItemParse_asset_shader( itemDef_t *item, int handle ) {
- const char *temp;
-
- if (!PC_String_Parse(handle, &temp)) {
- return qfalse;
- }
- item->asset = DC->registerShaderNoMip(temp);
- return qtrue;
-}
-
-// model_origin <number> <number> <number>
-qboolean ItemParse_model_origin( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (PC_Float_Parse(handle, &modelPtr->origin[0])) {
- if (PC_Float_Parse(handle, &modelPtr->origin[1])) {
- if (PC_Float_Parse(handle, &modelPtr->origin[2])) {
- return qtrue;
- }
- }
- }
- return qfalse;
-}
-
-// model_fovx <number>
-qboolean ItemParse_model_fovx( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_Float_Parse(handle, &modelPtr->fov_x)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// model_fovy <number>
-qboolean ItemParse_model_fovy( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_Float_Parse(handle, &modelPtr->fov_y)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// model_rotation <integer>
-qboolean ItemParse_model_rotation( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_Int_Parse(handle, &modelPtr->rotationSpeed)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// model_angle <integer>
-qboolean ItemParse_model_angle( itemDef_t *item, int handle ) {
- modelDef_t *modelPtr;
- Item_ValidateTypeData(item);
- modelPtr = (modelDef_t*)item->typeData;
-
- if (!PC_Int_Parse(handle, &modelPtr->angle)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// rect <rectangle>
-qboolean ItemParse_rect( itemDef_t *item, int handle ) {
- if (!PC_Rect_Parse(handle, &item->window.rectClient)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// style <integer>
-qboolean ItemParse_style( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->window.style)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// decoration
-qboolean ItemParse_decoration( itemDef_t *item, int handle ) {
- item->window.flags |= WINDOW_DECORATION;
- return qtrue;
-}
-
-// notselectable
-qboolean ItemParse_notselectable( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
- Item_ValidateTypeData(item);
- listPtr = (listBoxDef_t*)item->typeData;
- if (item->type == ITEM_TYPE_LISTBOX && listPtr) {
- listPtr->notselectable = qtrue;
- }
- return qtrue;
-}
-
-// manually wrapped
-qboolean ItemParse_wrapped( itemDef_t *item, int handle ) {
- item->window.flags |= WINDOW_WRAPPED;
- return qtrue;
-}
-
-// auto wrapped
-qboolean ItemParse_autowrapped( itemDef_t *item, int handle ) {
- item->window.flags |= WINDOW_AUTOWRAPPED;
- return qtrue;
-}
-
-
-// horizontalscroll
-qboolean ItemParse_horizontalscroll( itemDef_t *item, int handle ) {
- item->window.flags |= WINDOW_HORIZONTAL;
- return qtrue;
-}
-
-// type <integer>
-qboolean ItemParse_type( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->type)) {
- return qfalse;
- }
- Item_ValidateTypeData(item);
- return qtrue;
-}
-
-// elementwidth, used for listbox image elements
-// uses textalignx for storage
-qboolean ItemParse_elementwidth( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
-
- Item_ValidateTypeData(item);
- listPtr = (listBoxDef_t*)item->typeData;
- if (!PC_Float_Parse(handle, &listPtr->elementWidth)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// elementheight, used for listbox image elements
-// uses textaligny for storage
-qboolean ItemParse_elementheight( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
-
- Item_ValidateTypeData(item);
- listPtr = (listBoxDef_t*)item->typeData;
- if (!PC_Float_Parse(handle, &listPtr->elementHeight)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// feeder <float>
-qboolean ItemParse_feeder( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->special)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// elementtype, used to specify what type of elements a listbox contains
-// uses textstyle for storage
-qboolean ItemParse_elementtype( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- listPtr = (listBoxDef_t*)item->typeData;
- if (!PC_Int_Parse(handle, &listPtr->elementStyle)) {
- return qfalse;
- }
- return qtrue;
-}
-
-// columns sets a number of columns and an x pos and width per..
-qboolean ItemParse_columns( itemDef_t *item, int handle ) {
- int num, i;
- listBoxDef_t *listPtr;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- listPtr = (listBoxDef_t*)item->typeData;
- if (PC_Int_Parse(handle, &num)) {
- if (num > MAX_LB_COLUMNS) {
- num = MAX_LB_COLUMNS;
- }
- listPtr->numColumns = num;
- for (i = 0; i < num; i++) {
- int pos, width, maxChars;
-
- if (PC_Int_Parse(handle, &pos) && PC_Int_Parse(handle, &width) && PC_Int_Parse(handle, &maxChars)) {
- listPtr->columnInfo[i].pos = pos;
- listPtr->columnInfo[i].width = width;
- listPtr->columnInfo[i].maxChars = maxChars;
- } else {
- return qfalse;
- }
- }
- } else {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_border( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->window.border)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_bordersize( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->window.borderSize)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_visible( itemDef_t *item, int handle ) {
- int i;
-
- if (!PC_Int_Parse(handle, &i)) {
- return qfalse;
- }
- if (i) {
- item->window.flags |= WINDOW_VISIBLE;
- }
- return qtrue;
-}
-
-qboolean ItemParse_ownerdraw( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->window.ownerDraw)) {
- return qfalse;
- }
- item->type = ITEM_TYPE_OWNERDRAW;
- return qtrue;
-}
-
-qboolean ItemParse_align( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->alignment)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_textalign( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->textalignment)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_textalignx( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->textalignx)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_textaligny( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->textaligny)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_textscale( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->textscale)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_textstyle( itemDef_t *item, int handle ) {
- if (!PC_Int_Parse(handle, &item->textStyle)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_backcolor( itemDef_t *item, int handle ) {
- int i;
- float f;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- item->window.backColor[i] = f;
- }
- return qtrue;
-}
-
-qboolean ItemParse_forecolor( itemDef_t *item, int handle ) {
- int i;
- float f;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- item->window.foreColor[i] = f;
- item->window.flags |= WINDOW_FORECOLORSET;
- }
- return qtrue;
-}
-
-qboolean ItemParse_bordercolor( itemDef_t *item, int handle ) {
- int i;
- float f;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- item->window.borderColor[i] = f;
- }
- return qtrue;
-}
-
-qboolean ItemParse_outlinecolor( itemDef_t *item, int handle ) {
- if (!PC_Color_Parse(handle, &item->window.outlineColor)){
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_background( itemDef_t *item, int handle ) {
- const char *temp;
-
- if (!PC_String_Parse(handle, &temp)) {
- return qfalse;
- }
- item->window.background = DC->registerShaderNoMip(temp);
- return qtrue;
-}
-
-qboolean ItemParse_cinematic( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->window.cinematicName)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_doubleClick( itemDef_t *item, int handle ) {
- listBoxDef_t *listPtr;
-
- Item_ValidateTypeData(item);
- if (!item->typeData) {
- return qfalse;
- }
-
- listPtr = (listBoxDef_t*)item->typeData;
-
- if (!PC_Script_Parse(handle, &listPtr->doubleClick)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_onFocus( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->onFocus)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_leaveFocus( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->leaveFocus)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_mouseEnter( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->mouseEnter)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_mouseExit( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->mouseExit)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_mouseEnterText( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->mouseEnterText)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_mouseExitText( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->mouseExitText)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_action( itemDef_t *item, int handle ) {
- if (!PC_Script_Parse(handle, &item->action)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_special( itemDef_t *item, int handle ) {
- if (!PC_Float_Parse(handle, &item->special)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_cvarTest( itemDef_t *item, int handle ) {
- if (!PC_String_Parse(handle, &item->cvarTest)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean ItemParse_cvar( itemDef_t *item, int handle ) {
- editFieldDef_t *editPtr;
-
- Item_ValidateTypeData(item);
- if (!PC_String_Parse(handle, &item->cvar)) {
- return qfalse;
- }
- if (item->typeData) {
- editPtr = (editFieldDef_t*)item->typeData;
- editPtr->minVal = -1;
- editPtr->maxVal = -1;
- editPtr->defVal = -1;
- }
- return qtrue;
-}
-
-qboolean ItemParse_maxChars( itemDef_t *item, int handle ) {
- editFieldDef_t *editPtr;
- int maxChars;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
-
- if (!PC_Int_Parse(handle, &maxChars)) {
- return qfalse;
- }
- editPtr = (editFieldDef_t*)item->typeData;
- editPtr->maxChars = maxChars;
- return qtrue;
-}
-
-qboolean ItemParse_maxPaintChars( itemDef_t *item, int handle ) {
- editFieldDef_t *editPtr;
- int maxChars;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
-
- if (!PC_Int_Parse(handle, &maxChars)) {
- return qfalse;
- }
- editPtr = (editFieldDef_t*)item->typeData;
- editPtr->maxPaintChars = maxChars;
- return qtrue;
-}
-
-
-
-qboolean ItemParse_cvarFloat( itemDef_t *item, int handle ) {
- editFieldDef_t *editPtr;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- editPtr = (editFieldDef_t*)item->typeData;
- if (PC_String_Parse(handle, &item->cvar) &&
- PC_Float_Parse(handle, &editPtr->defVal) &&
- PC_Float_Parse(handle, &editPtr->minVal) &&
- PC_Float_Parse(handle, &editPtr->maxVal)) {
- return qtrue;
- }
- return qfalse;
-}
-
-qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) {
- pc_token_t token;
- multiDef_t *multiPtr;
- int pass;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- multiPtr = (multiDef_t*)item->typeData;
- multiPtr->count = 0;
- multiPtr->strDef = qtrue;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (*token.string != '{') {
- return qfalse;
- }
-
- pass = 0;
- while ( 1 ) {
- if (!trap_PC_ReadToken(handle, &token)) {
- PC_SourceError(handle, "end of file inside menu item\n");
- return qfalse;
- }
-
- if (*token.string == '}') {
- return qtrue;
- }
-
- if (*token.string == ',' || *token.string == ';') {
- continue;
- }
-
- if (pass == 0) {
- multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
- pass = 1;
- } else {
- multiPtr->cvarStr[multiPtr->count] = String_Alloc(token.string);
- pass = 0;
- multiPtr->count++;
- if (multiPtr->count >= MAX_MULTI_CVARS) {
- return qfalse;
- }
- }
-
- }
- return qfalse; // bk001205 - LCC missing return value
-}
-
-qboolean ItemParse_cvarFloatList( itemDef_t *item, int handle ) {
- pc_token_t token;
- multiDef_t *multiPtr;
-
- Item_ValidateTypeData(item);
- if (!item->typeData)
- return qfalse;
- multiPtr = (multiDef_t*)item->typeData;
- multiPtr->count = 0;
- multiPtr->strDef = qfalse;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (*token.string != '{') {
- return qfalse;
- }
-
- while ( 1 ) {
- if (!trap_PC_ReadToken(handle, &token)) {
- PC_SourceError(handle, "end of file inside menu item\n");
- return qfalse;
- }
-
- if (*token.string == '}') {
- return qtrue;
- }
-
- if (*token.string == ',' || *token.string == ';') {
- continue;
- }
-
- multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
- if (!PC_Float_Parse(handle, &multiPtr->cvarValue[multiPtr->count])) {
- return qfalse;
- }
-
- multiPtr->count++;
- if (multiPtr->count >= MAX_MULTI_CVARS) {
- return qfalse;
- }
-
- }
- return qfalse; // bk001205 - LCC missing return value
-}
-
-
-
-qboolean ItemParse_addColorRange( itemDef_t *item, int handle ) {
- colorRangeDef_t color;
-
- if (PC_Float_Parse(handle, &color.low) &&
- PC_Float_Parse(handle, &color.high) &&
- PC_Color_Parse(handle, &color.color) ) {
- if (item->numColors < MAX_COLOR_RANGES) {
- memcpy(&item->colorRanges[item->numColors], &color, sizeof(color));
- item->numColors++;
- }
- return qtrue;
- }
- return qfalse;
-}
-
-qboolean ItemParse_ownerdrawFlag( itemDef_t *item, int handle ) {
- int i;
- if (!PC_Int_Parse(handle, &i)) {
- return qfalse;
- }
- item->window.ownerDrawFlags |= i;
- return qtrue;
-}
-
-qboolean ItemParse_enableCvar( itemDef_t *item, int handle ) {
- if (PC_Script_Parse(handle, &item->enableCvar)) {
- item->cvarFlags = CVAR_ENABLE;
- return qtrue;
- }
- return qfalse;
-}
-
-qboolean ItemParse_disableCvar( itemDef_t *item, int handle ) {
- if (PC_Script_Parse(handle, &item->enableCvar)) {
- item->cvarFlags = CVAR_DISABLE;
- return qtrue;
- }
- return qfalse;
-}
-
-qboolean ItemParse_showCvar( itemDef_t *item, int handle ) {
- if (PC_Script_Parse(handle, &item->enableCvar)) {
- item->cvarFlags = CVAR_SHOW;
- return qtrue;
- }
- return qfalse;
-}
-
-qboolean ItemParse_hideCvar( itemDef_t *item, int handle ) {
- if (PC_Script_Parse(handle, &item->enableCvar)) {
- item->cvarFlags = CVAR_HIDE;
- return qtrue;
- }
- return qfalse;
-}
-
-
-keywordHash_t itemParseKeywords[] = {
- {"name", ItemParse_name, NULL},
- {"text", ItemParse_text, NULL},
- {"group", ItemParse_group, NULL},
- {"asset_model", ItemParse_asset_model, NULL},
- {"asset_shader", ItemParse_asset_shader, NULL},
- {"model_origin", ItemParse_model_origin, NULL},
- {"model_fovx", ItemParse_model_fovx, NULL},
- {"model_fovy", ItemParse_model_fovy, NULL},
- {"model_rotation", ItemParse_model_rotation, NULL},
- {"model_angle", ItemParse_model_angle, NULL},
- {"rect", ItemParse_rect, NULL},
- {"style", ItemParse_style, NULL},
- {"decoration", ItemParse_decoration, NULL},
- {"notselectable", ItemParse_notselectable, NULL},
- {"wrapped", ItemParse_wrapped, NULL},
- {"autowrapped", ItemParse_autowrapped, NULL},
- {"horizontalscroll", ItemParse_horizontalscroll, NULL},
- {"type", ItemParse_type, NULL},
- {"elementwidth", ItemParse_elementwidth, NULL},
- {"elementheight", ItemParse_elementheight, NULL},
- {"feeder", ItemParse_feeder, NULL},
- {"elementtype", ItemParse_elementtype, NULL},
- {"columns", ItemParse_columns, NULL},
- {"border", ItemParse_border, NULL},
- {"bordersize", ItemParse_bordersize, NULL},
- {"visible", ItemParse_visible, NULL},
- {"ownerdraw", ItemParse_ownerdraw, NULL},
- {"align", ItemParse_align, NULL},
- {"textalign", ItemParse_textalign, NULL},
- {"textalignx", ItemParse_textalignx, NULL},
- {"textaligny", ItemParse_textaligny, NULL},
- {"textscale", ItemParse_textscale, NULL},
- {"textstyle", ItemParse_textstyle, NULL},
- {"backcolor", ItemParse_backcolor, NULL},
- {"forecolor", ItemParse_forecolor, NULL},
- {"bordercolor", ItemParse_bordercolor, NULL},
- {"outlinecolor", ItemParse_outlinecolor, NULL},
- {"background", ItemParse_background, NULL},
- {"onFocus", ItemParse_onFocus, NULL},
- {"leaveFocus", ItemParse_leaveFocus, NULL},
- {"mouseEnter", ItemParse_mouseEnter, NULL},
- {"mouseExit", ItemParse_mouseExit, NULL},
- {"mouseEnterText", ItemParse_mouseEnterText, NULL},
- {"mouseExitText", ItemParse_mouseExitText, NULL},
- {"action", ItemParse_action, NULL},
- {"special", ItemParse_special, NULL},
- {"cvar", ItemParse_cvar, NULL},
- {"maxChars", ItemParse_maxChars, NULL},
- {"maxPaintChars", ItemParse_maxPaintChars, NULL},
- {"focusSound", ItemParse_focusSound, NULL},
- {"cvarFloat", ItemParse_cvarFloat, NULL},
- {"cvarStrList", ItemParse_cvarStrList, NULL},
- {"cvarFloatList", ItemParse_cvarFloatList, NULL},
- {"addColorRange", ItemParse_addColorRange, NULL},
- {"ownerdrawFlag", ItemParse_ownerdrawFlag, NULL},
- {"enableCvar", ItemParse_enableCvar, NULL},
- {"cvarTest", ItemParse_cvarTest, NULL},
- {"disableCvar", ItemParse_disableCvar, NULL},
- {"showCvar", ItemParse_showCvar, NULL},
- {"hideCvar", ItemParse_hideCvar, NULL},
- {"cinematic", ItemParse_cinematic, NULL},
- {"doubleclick", ItemParse_doubleClick, NULL},
- {NULL, 0, NULL}
-};
-
-keywordHash_t *itemParseKeywordHash[KEYWORDHASH_SIZE];
-
-/*
-===============
-Item_SetupKeywordHash
-===============
-*/
-void Item_SetupKeywordHash(void) {
- int i;
-
- memset(itemParseKeywordHash, 0, sizeof(itemParseKeywordHash));
- for (i = 0; itemParseKeywords[i].keyword; i++) {
- KeywordHash_Add(itemParseKeywordHash, &itemParseKeywords[i]);
- }
-}
-
-/*
-===============
-Item_Parse
-===============
-*/
-qboolean Item_Parse(int handle, itemDef_t *item) {
- pc_token_t token;
- keywordHash_t *key;
-
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (*token.string != '{') {
- return qfalse;
- }
- while ( 1 ) {
- if (!trap_PC_ReadToken(handle, &token)) {
- PC_SourceError(handle, "end of file inside menu item\n");
- return qfalse;
- }
-
- if (*token.string == '}') {
- return qtrue;
- }
-
- key = KeywordHash_Find(itemParseKeywordHash, token.string);
- if (!key) {
- PC_SourceError(handle, "unknown menu item keyword %s", token.string);
- continue;
- }
- if ( !key->func(item, handle) ) {
- PC_SourceError(handle, "couldn't parse menu item keyword %s", token.string);
- return qfalse;
- }
- }
- return qfalse; // bk001205 - LCC missing return value
-}
-
-
-// Item_InitControls
-// init's special control types
-void Item_InitControls(itemDef_t *item) {
- if (item == NULL) {
- return;
- }
- if (item->type == ITEM_TYPE_LISTBOX) {
- listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
- item->cursorPos = 0;
- if (listPtr) {
- listPtr->cursorPos = 0;
- listPtr->startPos = 0;
- listPtr->endPos = 0;
- listPtr->cursorPos = 0;
- }
- }
-}
-
-/*
-===============
-Menu Keyword Parse functions
-===============
-*/
-
-qboolean MenuParse_font( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_String_Parse(handle, &menu->font)) {
- return qfalse;
- }
- if (!DC->Assets.fontRegistered) {
- DC->registerFont(menu->font, 48, &DC->Assets.textFont);
- DC->Assets.fontRegistered = qtrue;
- }
- return qtrue;
-}
-
-qboolean MenuParse_name( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_String_Parse(handle, &menu->window.name)) {
- return qfalse;
- }
- if (Q_stricmp(menu->window.name, "main") == 0) {
- // default main as having focus
- //menu->window.flags |= WINDOW_HASFOCUS;
- }
- return qtrue;
-}
-
-qboolean MenuParse_fullscreen( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Int_Parse(handle, (int*) &menu->fullScreen)) { // bk001206 - cast qboolean
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_rect( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Rect_Parse(handle, &menu->window.rect)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_style( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Int_Parse(handle, &menu->window.style)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_visible( itemDef_t *item, int handle ) {
- int i;
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_Int_Parse(handle, &i)) {
- return qfalse;
- }
- if (i) {
- menu->window.flags |= WINDOW_VISIBLE;
- }
- return qtrue;
-}
-
-qboolean MenuParse_onOpen( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Script_Parse(handle, &menu->onOpen)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_onClose( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Script_Parse(handle, &menu->onClose)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_onESC( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Script_Parse(handle, &menu->onESC)) {
- return qfalse;
- }
- return qtrue;
-}
-
-
-
-qboolean MenuParse_border( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Int_Parse(handle, &menu->window.border)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_borderSize( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Float_Parse(handle, &menu->window.borderSize)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_backcolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- menu->window.backColor[i] = f;
- }
- return qtrue;
-}
-
-qboolean MenuParse_forecolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- menu->window.foreColor[i] = f;
- menu->window.flags |= WINDOW_FORECOLORSET;
- }
- return qtrue;
-}
-
-qboolean MenuParse_bordercolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- menu->window.borderColor[i] = f;
- }
- return qtrue;
-}
-
-qboolean MenuParse_focuscolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
-
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- menu->focusColor[i] = f;
- }
- return qtrue;
-}
-
-qboolean MenuParse_disablecolor( itemDef_t *item, int handle ) {
- int i;
- float f;
- menuDef_t *menu = (menuDef_t*)item;
- for (i = 0; i < 4; i++) {
- if (!PC_Float_Parse(handle, &f)) {
- return qfalse;
- }
- menu->disableColor[i] = f;
- }
- return qtrue;
-}
-
-
-qboolean MenuParse_outlinecolor( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (!PC_Color_Parse(handle, &menu->window.outlineColor)){
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_background( itemDef_t *item, int handle ) {
- const char *buff;
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_String_Parse(handle, &buff)) {
- return qfalse;
- }
- menu->window.background = DC->registerShaderNoMip(buff);
- return qtrue;
-}
-
-qboolean MenuParse_cinematic( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_String_Parse(handle, &menu->window.cinematicName)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_ownerdrawFlag( itemDef_t *item, int handle ) {
- int i;
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_Int_Parse(handle, &i)) {
- return qfalse;
- }
- menu->window.ownerDrawFlags |= i;
- return qtrue;
-}
-
-qboolean MenuParse_ownerdraw( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_Int_Parse(handle, &menu->window.ownerDraw)) {
- return qfalse;
- }
- return qtrue;
-}
-
-
-// decoration
-qboolean MenuParse_popup( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- menu->window.flags |= WINDOW_POPUP;
- return qtrue;
-}
-
-
-qboolean MenuParse_outOfBounds( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- menu->window.flags |= WINDOW_OOB_CLICK;
- return qtrue;
-}
-
-qboolean MenuParse_soundLoop( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_String_Parse(handle, &menu->soundName)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_fadeClamp( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_Float_Parse(handle, &menu->fadeClamp)) {
- return qfalse;
- }
- return qtrue;
-}
-
-qboolean MenuParse_fadeAmount( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_Float_Parse(handle, &menu->fadeAmount)) {
- return qfalse;
- }
- return qtrue;
-}
-
-
-qboolean MenuParse_fadeCycle( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
-
- if (!PC_Int_Parse(handle, &menu->fadeCycle)) {
- return qfalse;
- }
- return qtrue;
-}
-
-
-qboolean MenuParse_itemDef( itemDef_t *item, int handle ) {
- menuDef_t *menu = (menuDef_t*)item;
- if (menu->itemCount < MAX_MENUITEMS) {
- menu->items[menu->itemCount] = UI_Alloc(sizeof(itemDef_t));
- Item_Init(menu->items[menu->itemCount]);
- if (!Item_Parse(handle, menu->items[menu->itemCount])) {
- return qfalse;
- }
- Item_InitControls(menu->items[menu->itemCount]);
- menu->items[menu->itemCount++]->parent = menu;
- }
- return qtrue;
-}
-
-keywordHash_t menuParseKeywords[] = {
- {"font", MenuParse_font, NULL},
- {"name", MenuParse_name, NULL},
- {"fullscreen", MenuParse_fullscreen, NULL},
- {"rect", MenuParse_rect, NULL},
- {"style", MenuParse_style, NULL},
- {"visible", MenuParse_visible, NULL},
- {"onOpen", MenuParse_onOpen, NULL},
- {"onClose", MenuParse_onClose, NULL},
- {"onESC", MenuParse_onESC, NULL},
- {"border", MenuParse_border, NULL},
- {"borderSize", MenuParse_borderSize, NULL},
- {"backcolor", MenuParse_backcolor, NULL},
- {"forecolor", MenuParse_forecolor, NULL},
- {"bordercolor", MenuParse_bordercolor, NULL},
- {"focuscolor", MenuParse_focuscolor, NULL},
- {"disablecolor", MenuParse_disablecolor, NULL},
- {"outlinecolor", MenuParse_outlinecolor, NULL},
- {"background", MenuParse_background, NULL},
- {"ownerdraw", MenuParse_ownerdraw, NULL},
- {"ownerdrawFlag", MenuParse_ownerdrawFlag, NULL},
- {"outOfBoundsClick", MenuParse_outOfBounds, NULL},
- {"soundLoop", MenuParse_soundLoop, NULL},
- {"itemDef", MenuParse_itemDef, NULL},
- {"cinematic", MenuParse_cinematic, NULL},
- {"popup", MenuParse_popup, NULL},
- {"fadeClamp", MenuParse_fadeClamp, NULL},
- {"fadeCycle", MenuParse_fadeCycle, NULL},
- {"fadeAmount", MenuParse_fadeAmount, NULL},
- {NULL, 0, NULL}
-};
-
-keywordHash_t *menuParseKeywordHash[KEYWORDHASH_SIZE];
-
-/*
-===============
-Menu_SetupKeywordHash
-===============
-*/
-void Menu_SetupKeywordHash(void) {
- int i;
-
- memset(menuParseKeywordHash, 0, sizeof(menuParseKeywordHash));
- for (i = 0; menuParseKeywords[i].keyword; i++) {
- KeywordHash_Add(menuParseKeywordHash, &menuParseKeywords[i]);
- }
-}
-
-/*
-===============
-Menu_Parse
-===============
-*/
-qboolean Menu_Parse(int handle, menuDef_t *menu) {
- pc_token_t token;
- keywordHash_t *key;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (*token.string != '{') {
- return qfalse;
- }
-
- while ( 1 ) {
-
- memset(&token, 0, sizeof(pc_token_t));
- if (!trap_PC_ReadToken(handle, &token)) {
- PC_SourceError(handle, "end of file inside menu\n");
- return qfalse;
- }
-
- if (*token.string == '}') {
- return qtrue;
- }
-
- key = KeywordHash_Find(menuParseKeywordHash, token.string);
- if (!key) {
- PC_SourceError(handle, "unknown menu keyword %s", token.string);
- continue;
- }
- if ( !key->func((itemDef_t*)menu, handle) ) {
- PC_SourceError(handle, "couldn't parse menu keyword %s", token.string);
- return qfalse;
- }
- }
- return qfalse; // bk001205 - LCC missing return value
-}
-
-/*
-===============
-Menu_New
-===============
-*/
-void Menu_New(int handle) {
- menuDef_t *menu = &Menus[menuCount];
-
- if (menuCount < MAX_MENUS) {
- Menu_Init(menu);
- if (Menu_Parse(handle, menu)) {
- Menu_PostParse(menu);
- menuCount++;
- }
- }
-}
-
-int Menu_Count(void) {
- return menuCount;
-}
-
-void Menu_PaintAll(void) {
- int i;
- if (captureFunc) {
- captureFunc(captureData);
- }
-
- for (i = 0; i < Menu_Count(); i++) {
- Menu_Paint(&Menus[i], qfalse);
- }
-
- if (debugMode) {
- vec4_t v = {1, 1, 1, 1};
- DC->drawText(5, 25, .5, v, va("fps: %f", DC->FPS), 0, 0, 0);
- }
-}
-
-void Menu_Reset(void) {
- menuCount = 0;
-}
-
-displayContextDef_t *Display_GetContext(void) {
- return DC;
-}
-
-#ifndef MISSIONPACK // bk001206
-static float captureX;
-static float captureY;
-#endif
-
-void *Display_CaptureItem(int x, int y) {
- int i;
-
- for (i = 0; i < menuCount; i++) {
- // turn off focus each item
- // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
- if (Rect_ContainsPoint(&Menus[i].window.rect, x, y)) {
- return &Menus[i];
- }
- }
- return NULL;
-}
-
-
-// FIXME:
-qboolean Display_MouseMove(void *p, int x, int y) {
- int i;
- menuDef_t *menu = p;
-
- if (menu == NULL) {
- menu = Menu_GetFocused();
- if (menu) {
- if (menu->window.flags & WINDOW_POPUP) {
- Menu_HandleMouseMove(menu, x, y);
- return qtrue;
- }
- }
- for (i = 0; i < menuCount; i++) {
- Menu_HandleMouseMove(&Menus[i], x, y);
- }
- } else {
- menu->window.rect.x += x;
- menu->window.rect.y += y;
- Menu_UpdatePosition(menu);
- }
- return qtrue;
-
-}
-
-int Display_CursorType(int x, int y) {
- int i;
- for (i = 0; i < menuCount; i++) {
- rectDef_t r2;
- r2.x = Menus[i].window.rect.x - 3;
- r2.y = Menus[i].window.rect.y - 3;
- r2.w = r2.h = 7;
- if (Rect_ContainsPoint(&r2, x, y)) {
- return CURSOR_SIZER;
- }
- }
- return CURSOR_ARROW;
-}
-
-
-void Display_HandleKey(int key, qboolean down, int x, int y) {
- menuDef_t *menu = Display_CaptureItem(x, y);
- if (menu == NULL) {
- menu = Menu_GetFocused();
- }
- if (menu) {
- Menu_HandleKey(menu, key, down );
- }
-}
-
-static void Window_CacheContents(windowDef_t *window) {
- if (window) {
- if (window->cinematicName) {
- int cin = DC->playCinematic(window->cinematicName, 0, 0, 0, 0);
- DC->stopCinematic(cin);
- }
- }
-}
-
-
-static void Item_CacheContents(itemDef_t *item) {
- if (item) {
- Window_CacheContents(&item->window);
- }
-
-}
-
-static void Menu_CacheContents(menuDef_t *menu) {
- if (menu) {
- int i;
- Window_CacheContents(&menu->window);
- for (i = 0; i < menu->itemCount; i++) {
- Item_CacheContents(menu->items[i]);
- }
-
- if (menu->soundName && *menu->soundName) {
- DC->registerSound(menu->soundName, qfalse);
- }
- }
-
-}
-
-void Display_CacheAll(void) {
- int i;
- for (i = 0; i < menuCount; i++) {
- Menu_CacheContents(&Menus[i]);
- }
-}
-
-
-static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y) {
- if (menu && menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED)) {
- if (Rect_ContainsPoint(&menu->window.rect, x, y)) {
- int i;
- for (i = 0; i < menu->itemCount; i++) {
- // turn off focus each item
- // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
-
- if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
- continue;
- }
-
- if (menu->items[i]->window.flags & WINDOW_DECORATION) {
- continue;
- }
-
- if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
- itemDef_t *overItem = menu->items[i];
- if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
- if (Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
- return qtrue;
- } else {
- continue;
- }
- } else {
- return qtrue;
- }
- }
- }
-
- }
- }
- return qfalse;
-}
-
diff --git a/game/code/ui/ui_shared.h b/game/code/ui/ui_shared.h
deleted file mode 100644
index 6d772d8..0000000
--- a/game/code/ui/ui_shared.h
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#ifndef __UI_SHARED_H
-#define __UI_SHARED_H
-
-
-#include "../qcommon/q_shared.h"
-#include "../renderer/tr_types.h"
-#include "../client/keycodes.h"
-
-#include "../../ui/menudef.h"
-
-#define MAX_MENUNAME 32
-#define MAX_ITEMTEXT 64
-#define MAX_ITEMACTION 64
-#define MAX_MENUDEFFILE 4096
-#define MAX_MENUFILE 32768
-#define MAX_MENUS 64
-#define MAX_MENUITEMS 96
-#define MAX_COLOR_RANGES 10
-#define MAX_OPEN_MENUS 16
-
-#define WINDOW_MOUSEOVER 0x00000001 // mouse is over it, non exclusive
-#define WINDOW_HASFOCUS 0x00000002 // has cursor focus, exclusive
-#define WINDOW_VISIBLE 0x00000004 // is visible
-#define WINDOW_GREY 0x00000008 // is visible but grey ( non-active )
-#define WINDOW_DECORATION 0x00000010 // for decoration only, no mouse, keyboard, etc..
-#define WINDOW_FADINGOUT 0x00000020 // fading out, non-active
-#define WINDOW_FADINGIN 0x00000040 // fading in
-#define WINDOW_MOUSEOVERTEXT 0x00000080 // mouse is over it, non exclusive
-#define WINDOW_INTRANSITION 0x00000100 // window is in transition
-#define WINDOW_FORECOLORSET 0x00000200 // forecolor was explicitly set ( used to color alpha images or not )
-#define WINDOW_HORIZONTAL 0x00000400 // for list boxes and sliders, vertical is default this is set of horizontal
-#define WINDOW_LB_LEFTARROW 0x00000800 // mouse is over left/up arrow
-#define WINDOW_LB_RIGHTARROW 0x00001000 // mouse is over right/down arrow
-#define WINDOW_LB_THUMB 0x00002000 // mouse is over thumb
-#define WINDOW_LB_PGUP 0x00004000 // mouse is over page up
-#define WINDOW_LB_PGDN 0x00008000 // mouse is over page down
-#define WINDOW_ORBITING 0x00010000 // item is in orbit
-#define WINDOW_OOB_CLICK 0x00020000 // close on out of bounds click
-#define WINDOW_WRAPPED 0x00040000 // manually wrap text
-#define WINDOW_AUTOWRAPPED 0x00080000 // auto wrap text
-#define WINDOW_FORCED 0x00100000 // forced open
-#define WINDOW_POPUP 0x00200000 // popup
-#define WINDOW_BACKCOLORSET 0x00400000 // backcolor was explicitly set
-#define WINDOW_TIMEDVISIBLE 0x00800000 // visibility timing ( NOT implemented )
-
-
-// CGAME cursor type bits
-#define CURSOR_NONE 0x00000001
-#define CURSOR_ARROW 0x00000002
-#define CURSOR_SIZER 0x00000004
-
-#ifdef CGAME
-#define STRING_POOL_SIZE 128*1024
-#else
-#define STRING_POOL_SIZE 384*1024
-#endif
-#define MAX_STRING_HANDLES 4096
-
-#define MAX_SCRIPT_ARGS 12
-#define MAX_EDITFIELD 256
-
-#define ART_FX_BASE "menu/art/fx_base"
-#define ART_FX_BLUE "menu/art/fx_blue"
-#define ART_FX_CYAN "menu/art/fx_cyan"
-#define ART_FX_GREEN "menu/art/fx_grn"
-#define ART_FX_RED "menu/art/fx_red"
-#define ART_FX_TEAL "menu/art/fx_teal"
-#define ART_FX_WHITE "menu/art/fx_white"
-#define ART_FX_YELLOW "menu/art/fx_yel"
-
-#define ASSET_GRADIENTBAR "ui/assets/gradientbar2.tga"
-#define ASSET_SCROLLBAR "ui/assets/scrollbar.tga"
-#define ASSET_SCROLLBAR_ARROWDOWN "ui/assets/scrollbar_arrow_dwn_a.tga"
-#define ASSET_SCROLLBAR_ARROWUP "ui/assets/scrollbar_arrow_up_a.tga"
-#define ASSET_SCROLLBAR_ARROWLEFT "ui/assets/scrollbar_arrow_left.tga"
-#define ASSET_SCROLLBAR_ARROWRIGHT "ui/assets/scrollbar_arrow_right.tga"
-#define ASSET_SCROLL_THUMB "ui/assets/scrollbar_thumb.tga"
-#define ASSET_SLIDER_BAR "ui/assets/slider2.tga"
-#define ASSET_SLIDER_THUMB "ui/assets/sliderbutt_1.tga"
-#define SCROLLBAR_SIZE 16.0
-#define SLIDER_WIDTH 96.0
-#define SLIDER_HEIGHT 16.0
-#define SLIDER_THUMB_WIDTH 12.0
-#define SLIDER_THUMB_HEIGHT 20.0
-#define NUM_CROSSHAIRS 99
-
-typedef struct {
- const char *command;
- const char *args[MAX_SCRIPT_ARGS];
-} scriptDef_t;
-
-
-typedef struct {
- float x; // horiz position
- float y; // vert position
- float w; // width
- float h; // height;
-} rectDef_t;
-
-typedef rectDef_t Rectangle;
-
-// FIXME: do something to separate text vs window stuff
-typedef struct {
- Rectangle rect; // client coord rectangle
- Rectangle rectClient; // screen coord rectangle
- const char *name; //
- const char *group; // if it belongs to a group
- const char *cinematicName; // cinematic name
- int cinematic; // cinematic handle
- int style; //
- int border; //
- int ownerDraw; // ownerDraw style
- int ownerDrawFlags; // show flags for ownerdraw items
- float borderSize; //
- int flags; // visible, focus, mouseover, cursor
- Rectangle rectEffects; // for various effects
- Rectangle rectEffects2; // for various effects
- int offsetTime; // time based value for various effects
- int nextTime; // time next effect should cycle
- vec4_t foreColor; // text color
- vec4_t backColor; // border color
- vec4_t borderColor; // border color
- vec4_t outlineColor; // border color
- qhandle_t background; // background asset
-} windowDef_t;
-
-typedef windowDef_t Window;
-
-typedef struct {
- vec4_t color;
- float low;
- float high;
-} colorRangeDef_t;
-
-// FIXME: combine flags into bitfields to save space
-// FIXME: consolidate all of the common stuff in one structure for menus and items
-// THINKABOUTME: is there any compelling reason not to have items contain items
-// and do away with a menu per say.. major issue is not being able to dynamically allocate
-// and destroy stuff.. Another point to consider is adding an alloc free call for vm's and have
-// the engine just allocate the pool for it based on a cvar
-// many of the vars are re-used for different item types, as such they are not always named appropriately
-// the benefits of c++ in DOOM will greatly help crap like this
-// FIXME: need to put a type ptr that points to specific type info per type
-//
-#define MAX_LB_COLUMNS 16
-
-typedef struct columnInfo_s {
- int pos;
- int width;
- int maxChars;
-} columnInfo_t;
-
-typedef struct listBoxDef_s {
- int startPos;
- int endPos;
- int drawPadding;
- int cursorPos;
- float elementWidth;
- float elementHeight;
- int elementStyle;
- int numColumns;
- columnInfo_t columnInfo[MAX_LB_COLUMNS];
- const char *doubleClick;
- qboolean notselectable;
-} listBoxDef_t;
-
-typedef struct editFieldDef_s {
- float minVal; // edit field limits
- float maxVal; //
- float defVal; //
- float range; //
- int maxChars; // for edit fields
- int maxPaintChars; // for edit fields
- int paintOffset; //
-} editFieldDef_t;
-
-#define MAX_MULTI_CVARS 32
-
-typedef struct multiDef_s {
- const char *cvarList[MAX_MULTI_CVARS];
- const char *cvarStr[MAX_MULTI_CVARS];
- float cvarValue[MAX_MULTI_CVARS];
- int count;
- qboolean strDef;
-} multiDef_t;
-
-typedef struct modelDef_s {
- int angle;
- vec3_t origin;
- float fov_x;
- float fov_y;
- int rotationSpeed;
-} modelDef_t;
-
-#define CVAR_ENABLE 0x00000001
-#define CVAR_DISABLE 0x00000002
-#define CVAR_SHOW 0x00000004
-#define CVAR_HIDE 0x00000008
-
-typedef struct itemDef_s {
- Window window; // common positional, border, style, layout info
- Rectangle textRect; // rectangle the text ( if any ) consumes
- int type; // text, button, radiobutton, checkbox, textfield, listbox, combo
- int alignment; // left center right
- int textalignment; // ( optional ) alignment for text within rect based on text width
- float textalignx; // ( optional ) text alignment x coord
- float textaligny; // ( optional ) text alignment x coord
- float textscale; // scale percentage from 72pts
- int textStyle; // ( optional ) style, normal and shadowed are it for now
- const char *text; // display text
- void *parent; // menu owner
- qhandle_t asset; // handle to asset
- const char *mouseEnterText; // mouse enter script
- const char *mouseExitText; // mouse exit script
- const char *mouseEnter; // mouse enter script
- const char *mouseExit; // mouse exit script
- const char *action; // select script
- const char *onFocus; // select script
- const char *leaveFocus; // select script
- const char *cvar; // associated cvar
- const char *cvarTest; // associated cvar for enable actions
- const char *enableCvar; // enable, disable, show, or hide based on value, this can contain a list
- int cvarFlags; // what type of action to take on cvarenables
- sfxHandle_t focusSound;
- int numColors; // number of color ranges
- colorRangeDef_t colorRanges[MAX_COLOR_RANGES];
- float special; // used for feeder id's etc.. diff per type
- int cursorPos; // cursor position in characters
- void *typeData; // type specific data ptr's
-} itemDef_t;
-
-typedef struct {
- Window window;
- const char *font; // font
- qboolean fullScreen; // covers entire screen
- int itemCount; // number of items;
- int fontIndex; //
- int cursorItem; // which item as the cursor
- int fadeCycle; //
- float fadeClamp; //
- float fadeAmount; //
- const char *onOpen; // run when the menu is first opened
- const char *onClose; // run when the menu is closed
- const char *onESC; // run when the menu is closed
- const char *soundName; // background loop sound for menu
-
- vec4_t focusColor; // focus color for items
- vec4_t disableColor; // focus color for items
- itemDef_t *items[MAX_MENUITEMS]; // items this menu contains
-} menuDef_t;
-
-typedef struct {
- const char *fontStr;
- const char *cursorStr;
- const char *gradientStr;
- fontInfo_t textFont;
- fontInfo_t smallFont;
- fontInfo_t bigFont;
- qhandle_t cursor;
- qhandle_t gradientBar;
- qhandle_t scrollBarArrowUp;
- qhandle_t scrollBarArrowDown;
- qhandle_t scrollBarArrowLeft;
- qhandle_t scrollBarArrowRight;
- qhandle_t scrollBar;
- qhandle_t scrollBarThumb;
- qhandle_t buttonMiddle;
- qhandle_t buttonInside;
- qhandle_t solidBox;
- qhandle_t sliderBar;
- qhandle_t sliderThumb;
- sfxHandle_t menuEnterSound;
- sfxHandle_t menuExitSound;
- sfxHandle_t menuBuzzSound;
- sfxHandle_t itemFocusSound;
- float fadeClamp;
- int fadeCycle;
- float fadeAmount;
- float shadowX;
- float shadowY;
- vec4_t shadowColor;
- float shadowFadeClamp;
- qboolean fontRegistered;
-
- // player settings
- qhandle_t fxBasePic;
- qhandle_t fxPic[7];
- qhandle_t crosshairShader[NUM_CROSSHAIRS];
-
-} cachedAssets_t;
-
-typedef struct {
- const char *name;
- void (*handler) (itemDef_t *item, char** args);
-} commandDef_t;
-
-typedef struct {
- qhandle_t (*registerShaderNoMip) (const char *p);
- void (*setColor) (const vec4_t v);
- void (*drawHandlePic) (float x, float y, float w, float h, qhandle_t asset);
- void (*drawStretchPic) (float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
- void (*drawText) (float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style );
- int (*textWidth) (const char *text, float scale, int limit);
- int (*textHeight) (const char *text, float scale, int limit);
- qhandle_t (*registerModel) (const char *p);
- void (*modelBounds) (qhandle_t model, vec3_t min, vec3_t max);
- void (*fillRect) ( float x, float y, float w, float h, const vec4_t color);
- void (*drawRect) ( float x, float y, float w, float h, float size, const vec4_t color);
- void (*drawSides) (float x, float y, float w, float h, float size);
- void (*drawTopBottom) (float x, float y, float w, float h, float size);
- void (*clearScene) ( void );
- void (*addRefEntityToScene) (const refEntity_t *re );
- void (*renderScene) ( const refdef_t *fd );
- void (*registerFont) (const char *pFontname, int pointSize, fontInfo_t *font);
- void (*ownerDrawItem) (float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle);
- float (*getValue) (int ownerDraw);
- qboolean (*ownerDrawVisible) (int flags);
- void (*runScript)(char **p);
- void (*getTeamColor)(vec4_t *color);
- void (*getCVarString)(const char *cvar, char *buffer, int bufsize);
- float (*getCVarValue)(const char *cvar);
- void (*setCVar)(const char *cvar, const char *value);
- void (*drawTextWithCursor)(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style);
- void (*setOverstrikeMode)(qboolean b);
- qboolean (*getOverstrikeMode)( void );
- void (*startLocalSound)( sfxHandle_t sfx, int channelNum );
- qboolean (*ownerDrawHandleKey)(int ownerDraw, int flags, float *special, int key);
- int (*feederCount)(float feederID);
- const char *(*feederItemText)(float feederID, int index, int column, qhandle_t *handle);
- qhandle_t (*feederItemImage)(float feederID, int index);
- void (*feederSelection)(float feederID, int index);
- void (*keynumToStringBuf)( int keynum, char *buf, int buflen );
- void (*getBindingBuf)( int keynum, char *buf, int buflen );
- void (*setBinding)( int keynum, const char *binding );
- void (*executeText)(int exec_when, const char *text );
- void (*Error)(int level, const char *error, ...);
- void (*Print)(const char *msg, ...);
- void (*Pause)(qboolean b);
- int (*ownerDrawWidth)(int ownerDraw, float scale);
- sfxHandle_t (*registerSound)(const char *name, qboolean compressed);
- void (*startBackgroundTrack)( const char *intro, const char *loop);
- void (*stopBackgroundTrack)( void );
- int (*playCinematic)(const char *name, float x, float y, float w, float h);
- void (*stopCinematic)(int handle);
- void (*drawCinematic)(int handle, float x, float y, float w, float h);
- void (*runCinematicFrame)(int handle);
-
- float yscale;
- float xscale;
- float bias;
- int realTime;
- int frameTime;
- int cursorx;
- int cursory;
- qboolean debug;
-
- cachedAssets_t Assets;
-
- glconfig_t glconfig;
- qhandle_t whiteShader;
- qhandle_t gradientImage;
- qhandle_t cursor;
- float FPS;
-
-} displayContextDef_t;
-
-const char *String_Alloc(const char *p);
-void String_Init( void );
-void String_Report( void );
-void Init_Display(displayContextDef_t *dc);
-void Display_ExpandMacros(char * buff);
-void Menu_Init(menuDef_t *menu);
-void Item_Init(itemDef_t *item);
-void Menu_PostParse(menuDef_t *menu);
-menuDef_t *Menu_GetFocused( void );
-void Menu_HandleKey(menuDef_t *menu, int key, qboolean down);
-void Menu_HandleMouseMove(menuDef_t *menu, float x, float y);
-void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down);
-qboolean Float_Parse(char **p, float *f);
-qboolean Color_Parse(char **p, vec4_t *c);
-qboolean Int_Parse(char **p, int *i);
-qboolean Rect_Parse(char **p, rectDef_t *r);
-qboolean String_Parse(char **p, const char **out);
-qboolean Script_Parse(char **p, const char **out);
-qboolean PC_Float_Parse(int handle, float *f);
-qboolean PC_Color_Parse(int handle, vec4_t *c);
-qboolean PC_Int_Parse(int handle, int *i);
-qboolean PC_Rect_Parse(int handle, rectDef_t *r);
-qboolean PC_String_Parse(int handle, const char **out);
-qboolean PC_Script_Parse(int handle, const char **out);
-int Menu_Count( void );
-void Menu_New(int handle);
-void Menu_PaintAll( void );
-menuDef_t *Menus_ActivateByName(const char *p);
-void Menu_Reset( void );
-qboolean Menus_AnyFullScreenVisible( void );
-void Menus_Activate(menuDef_t *menu);
-
-displayContextDef_t *Display_GetContext( void );
-void *Display_CaptureItem(int x, int y);
-qboolean Display_MouseMove(void *p, int x, int y);
-int Display_CursorType(int x, int y);
-qboolean Display_KeyBindPending( void );
-void Menus_OpenByName(const char *p);
-menuDef_t *Menus_FindByName(const char *p);
-void Menus_ShowByName(const char *p);
-void Menus_CloseByName(const char *p);
-void Display_HandleKey(int key, qboolean down, int x, int y);
-void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t);
-void Menus_CloseAll( void );
-void Menu_Paint(menuDef_t *menu, qboolean forcePaint);
-void Menu_SetFeederSelection(menuDef_t *menu, int feeder, int index, const char *name);
-void Display_CacheAll( void );
-
-void *UI_Alloc( int size );
-void UI_InitMemory( void );
-qboolean UI_OutOfMemory( void );
-
-void Controls_GetConfig( void );
-void Controls_SetConfig(qboolean restart);
-void Controls_SetDefaults( void );
-
-int trap_PC_AddGlobalDefine( char *define );
-int trap_PC_LoadSource( const char *filename );
-int trap_PC_FreeSource( int handle );
-int trap_PC_ReadToken( int handle, pc_token_t *pc_token );
-int trap_PC_SourceFileAndLine( int handle, char *filename, int *line );
-
-#endif
diff --git a/game/code/ui/ui_syscalls.asm b/game/code/ui/ui_syscalls.asm
deleted file mode 100644
index 6dc352e..0000000
--- a/game/code/ui/ui_syscalls.asm
+++ /dev/null
@@ -1,101 +0,0 @@
-code
-
-equ trap_Error -1
-equ trap_Print -2
-equ trap_Milliseconds -3
-equ trap_Cvar_Set -4
-equ trap_Cvar_VariableValue -5
-equ trap_Cvar_VariableStringBuffer -6
-equ trap_Cvar_SetValue -7
-equ trap_Cvar_Reset -8
-equ trap_Cvar_Create -9
-equ trap_Cvar_InfoStringBuffer -10
-equ trap_Argc -11
-equ trap_Argv -12
-equ trap_Cmd_ExecuteText -13
-equ trap_FS_FOpenFile -14
-equ trap_FS_Read -15
-equ trap_FS_Write -16
-equ trap_FS_FCloseFile -17
-equ trap_FS_GetFileList -18
-equ trap_R_RegisterModel -19
-equ trap_R_RegisterSkin -20
-equ trap_R_RegisterShaderNoMip -21
-equ trap_R_ClearScene -22
-equ trap_R_AddRefEntityToScene -23
-equ trap_R_AddPolyToScene -24
-equ trap_R_AddLightToScene -25
-equ trap_R_RenderScene -26
-equ trap_R_SetColor -27
-equ trap_R_DrawStretchPic -28
-equ trap_UpdateScreen -29
-equ trap_CM_LerpTag -30
-equ trap_CM_LoadModel -31
-equ trap_S_RegisterSound -32
-equ trap_S_StartLocalSound -33
-equ trap_Key_KeynumToStringBuf -34
-equ trap_Key_GetBindingBuf -35
-equ trap_Key_SetBinding -36
-equ trap_Key_IsDown -37
-equ trap_Key_GetOverstrikeMode -38
-equ trap_Key_SetOverstrikeMode -39
-equ trap_Key_ClearStates -40
-equ trap_Key_GetCatcher -41
-equ trap_Key_SetCatcher -42
-equ trap_GetClipboardData -43
-equ trap_GetGlconfig -44
-equ trap_GetClientState -45
-equ trap_GetConfigString -46
-equ trap_LAN_GetPingQueueCount -47
-equ trap_LAN_ClearPing -48
-equ trap_LAN_GetPing -49
-equ trap_LAN_GetPingInfo -50
-equ trap_Cvar_Register -51
-equ trap_Cvar_Update -52
-equ trap_MemoryRemaining -53
-equ trap_GetCDKey -54
-equ trap_SetCDKey -55
-equ trap_R_RegisterFont -56
-equ trap_R_ModelBounds -57
-equ trap_PC_AddGlobalDefine -58
-equ trap_PC_LoadSource -59
-equ trap_PC_FreeSource -60
-equ trap_PC_ReadToken -61
-equ trap_PC_SourceFileAndLine -62
-equ trap_S_StopBackgroundTrack -63
-equ trap_S_StartBackgroundTrack -64
-equ trap_RealTime -65
-equ trap_LAN_GetServerCount -66
-equ trap_LAN_GetServerAddressString -67
-equ trap_LAN_GetServerInfo -68
-equ trap_LAN_MarkServerVisible -69
-equ trap_LAN_UpdateVisiblePings -70
-equ trap_LAN_ResetPings -71
-equ trap_LAN_LoadCachedServers -72
-equ trap_LAN_SaveCachedServers -73
-equ trap_LAN_AddServer -74
-equ trap_LAN_RemoveServer -75
-equ trap_CIN_PlayCinematic -76
-equ trap_CIN_StopCinematic -77
-equ trap_CIN_RunCinematic -78
-equ trap_CIN_DrawCinematic -79
-equ trap_CIN_SetExtents -80
-equ trap_R_RemapShader -81
-equ trap_VerifyCDKey -82
-equ trap_LAN_ServerStatus -83
-equ trap_LAN_GetServerPing -84
-equ trap_LAN_ServerIsVisible -85
-equ trap_LAN_CompareServers -86
-equ trap_FS_Seek -87
-equ trap_SetPbClStatus -88
-
-equ memset -101
-equ memcpy -102
-equ strncpy -103
-equ sin -104
-equ cos -105
-equ atan2 -106
-equ sqrt -107
-equ floor -108
-equ ceil -109
-
diff --git a/game/linux_scripts/supermake b/game/linux_scripts/supermake
deleted file mode 100755
index 3f2982d..0000000
--- a/game/linux_scripts/supermake
+++ /dev/null
@@ -1,25 +0,0 @@
-
-#Tip: You can create a supermake.local file and this script will get the variable from there!
-BINNAME=openarena
-MODNAME=oax
-
-if [ -r ./supermake.local ] ; then
-source ./supermake.local
-fi
-
-if [ -r $BINNAME ] ; then
- echo $BINNAME found
-else
- echo $BINNAME not found! Check the variables in the script
- exit 1
-fi
-
-#Create the mod dir
-mkdir -p ~/.openarena/$MODNAME
-
-
-pushd ..
-#Build, pak it and start
-make && cd build/release-linux-x86_64/baseq3 && zip -r ~/.openarena/$MODNAME/$MODNAME.pk3 vm && $BINNAME +set fs_game $MODNAME +set debug 1 +set sv_pure 0 +vm_ui 2 +vm_game 2 +vm_cgame 2
-popd
-
diff --git a/game/linux_scripts/supermake_native b/game/linux_scripts/supermake_native
deleted file mode 100755
index 5fdd25e..0000000
--- a/game/linux_scripts/supermake_native
+++ /dev/null
@@ -1,24 +0,0 @@
-
-#Tip: You can create a supermake.local file and this script will get the variable from there!
-BINNAME=openarena
-MODNAME=oax
-
-if [ -r ./supermake.local ] ; then
-source ./supermake.local
-fi
-
-if [ -r $BINNAME ] ; then
- echo $BINNAME found
-else
- echo $BINNAME not found! Check the variables in the script
- exit 1
-fi
-
-#Create the mod dir
-mkdir -p ~/.openarena/$MODNAME
-
-pushd ..
-#Build, pak it and start
-make && cd build/release-linux-x86_64/baseq3 && cp *.so ~/.openarena/$MODNAME/ && $BINNAME +set fs_game $MODNAME +set debug 1 +set sv_pure 0 +vm_ui 0 +vm_game 0 +vm_cgame 0
-popd
-
diff --git a/game/text/COPYING.txt b/game/text/COPYING.txt
deleted file mode 100644
index 98443f3..0000000
--- a/game/text/COPYING.txt
+++ /dev/null
@@ -1,281 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/game/text/id-readme.txt b/game/text/id-readme.txt
deleted file mode 100644
index 55b00f3..0000000
--- a/game/text/id-readme.txt
+++ /dev/null
@@ -1,145 +0,0 @@
-Quake III Arena GPL source release
-==================================
-
-This file contains the following sections:
-
-LICENSE
-GENERAL NOTES
-
-LICENSE
-=======
-
-See COPYING.txt for the GNU GENERAL PUBLIC LICENSE
-
-Some source code in this release is not covered by the GPL:
-
-IO on .zip files using portions of zlib
------------------------------------------------------------------------------
-lines file(s)
-4299 code/qcommon/unzip.c
-4546 libs/pak/unzip.cpp
-Copyright (C) 1998 Gilles Vollant
-zlib is Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-
-standard C library replacement routines
------------------------------------------------------------------------------
-lines file(s)
-1324 code/game/bg_lib.c
-Copyright (c) 1992, 1993
-The Regents of the University of California. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
-ADPCM coder/decoder
------------------------------------------------------------------------------
-lines file(s)
-330 code/client/snd_adpcm.c
-Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
-Netherlands.
-
- All Rights Reserved
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in
-supporting documentation, and that the names of Stichting Mathematisch
-Centrum or CWI not be used in advertising or publicity pertaining to
-distribution of the software without specific, written prior permission.
-
-STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
-THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
-FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-JPEG library
------------------------------------------------------------------------------
-code/jpeg-6
-libs/jpeg6
-Copyright (C) 1991-1995, Thomas G. Lane
-
-Permission is hereby granted to use, copy, modify, and distribute this
-software (or portions thereof) for any purpose, without fee, subject to these
-conditions:
-(1) If any part of the source code for this software is distributed, then this
-README file must be included, with this copyright and no-warranty notice
-unaltered; and any additions, deletions, or changes to the original files
-must be clearly indicated in accompanying documentation.
-(2) If only executable code is distributed, then the accompanying
-documentation must state that "this software is based in part on the work of
-the Independent JPEG Group".
-(3) Permission for use of this software is granted only if the user accepts
-full responsibility for any undesirable consequences; the authors accept
-NO LIABILITY for damages of any kind.
-
-These conditions apply to any software derived from or based on the IJG code,
-not just to the unmodified library. If you use our work, you ought to
-acknowledge us.
-
-NOTE: unfortunately the README that came with our copy of the library has
-been lost, so the one from release 6b is included instead. There are a few
-'glue type' modifications to the library to make it easier to use from
-the engine, but otherwise the dependency can be easily cleaned up to a
-better release of the library.
-
-
-GENERAL NOTES
-=============
-
-A short summary of the file layout:
-
-code/ Quake III Arena source code ( renderer, game code, OS layer etc. )
-code/bspc bot routes compiler source code
-lcc/ the retargetable C compiler ( produces assembly to be turned into qvm bytecode by q3asm )
-q3asm/ assembly to qvm bytecode compiler
-q3map/ map compiler ( .map -> .bsp ) - this is the version that comes with Q3Radiant 200f
-q3radiant/ Q3Radiant map editor build 200f ( common/ and libs/ are support dirs for radiant )
-
-While we made sure we were still able to compile the game on Windows, GNU/Linux
-and Mac, this build didn't get any kind of extensive testing so it may not work
-completely right. Whenever an id game is released under GPL, several projects
-start making the source code more friendly to nowaday's compilers and
-environements. If you are picking up this release weeks/months/years after we
-uploaded it, you probably want to look around on the net for cleaned up
-versions of this codebase as well.
diff --git a/game/ui/hud.txt b/game/ui/hud.txt
deleted file mode 100644
index ab99a10..0000000
--- a/game/ui/hud.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-// hud menu defs
-//
-{
- loadMenu { "ui/hud.menu" }
- loadMenu { "ui/score.menu" }
- loadMenu { "ui/teamscore.menu" }
-}
diff --git a/game/ui/hud2.txt b/game/ui/hud2.txt
deleted file mode 100644
index c0a2da4..0000000
--- a/game/ui/hud2.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-// hud menu defs
-//
-{
- loadMenu { "ui/min_hud.menu" }
- loadMenu { "ui/score.menu" }
- loadMenu { "ui/teamscore.menu" }
-}
diff --git a/game/ui/ingame.txt b/game/ui/ingame.txt
deleted file mode 100644
index fb523ba..0000000
--- a/game/ui/ingame.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-// menu defs
-//
-{
- loadMenu { "ui/ingame.menu" }
- loadMenu { "ui/ingame_vote.menu" }
- loadMenu { "ui/ingame_about.menu" }
- loadMenu { "ui/ingame_controls.menu" }
- loadMenu { "ui/ingame_join.menu" }
- loadMenu { "ui/ingame_options.menu" }
- loadMenu { "ui/ingame_system.menu" }
- loadMenu { "ui/ingame_leave.menu" }
- loadMenu { "ui/ingame_player.menu" }
- loadMenu { "ui/ingame_addbot.menu" }
- loadMenu { "ui/ingame_callvote.menu" }
- loadMenu { "ui/ingame_orders.menu" }
-}
diff --git a/game/ui/menudef.h b/game/ui/menudef.h
deleted file mode 100644
index 7bb7b0a..0000000
--- a/game/ui/menudef.h
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#define ITEM_TYPE_TEXT 0 // simple text
-#define ITEM_TYPE_BUTTON 1 // button, basically text with a border
-#define ITEM_TYPE_RADIOBUTTON 2 // toggle button, may be grouped
-#define ITEM_TYPE_CHECKBOX 3 // check box
-#define ITEM_TYPE_EDITFIELD 4 // editable text, associated with a cvar
-#define ITEM_TYPE_COMBO 5 // drop down list
-#define ITEM_TYPE_LISTBOX 6 // scrollable list
-#define ITEM_TYPE_MODEL 7 // model
-#define ITEM_TYPE_OWNERDRAW 8 // owner draw, name specs what it is
-#define ITEM_TYPE_NUMERICFIELD 9 // editable text, associated with a cvar
-#define ITEM_TYPE_SLIDER 10 // mouse speed, volume, etc.
-#define ITEM_TYPE_YESNO 11 // yes no cvar setting
-#define ITEM_TYPE_MULTI 12 // multiple list setting, enumerated
-#define ITEM_TYPE_BIND 13 // multiple list setting, enumerated
-
-#define ITEM_ALIGN_LEFT 0 // left alignment
-#define ITEM_ALIGN_CENTER 1 // center alignment
-#define ITEM_ALIGN_RIGHT 2 // right alignment
-
-#define ITEM_TEXTSTYLE_NORMAL 0 // normal text
-#define ITEM_TEXTSTYLE_BLINK 1 // fast blinking
-#define ITEM_TEXTSTYLE_PULSE 2 // slow pulsing
-#define ITEM_TEXTSTYLE_SHADOWED 3 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_OUTLINED 4 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_OUTLINESHADOWED 5 // drop shadow ( need a color for this )
-#define ITEM_TEXTSTYLE_SHADOWEDMORE 6 // drop shadow ( need a color for this )
-
-#define WINDOW_BORDER_NONE 0 // no border
-#define WINDOW_BORDER_FULL 1 // full border based on border color ( single pixel )
-#define WINDOW_BORDER_HORZ 2 // horizontal borders only
-#define WINDOW_BORDER_VERT 3 // vertical borders only
-#define WINDOW_BORDER_KCGRADIENT 4 // horizontal border using the gradient bars
-
-#define WINDOW_STYLE_EMPTY 0 // no background
-#define WINDOW_STYLE_FILLED 1 // filled with background color
-#define WINDOW_STYLE_GRADIENT 2 // gradient bar based on background color
-#define WINDOW_STYLE_SHADER 3 // gradient bar based on background color
-#define WINDOW_STYLE_TEAMCOLOR 4 // team color
-#define WINDOW_STYLE_CINEMATIC 5 // cinematic
-
-#define MENU_TRUE 1 // uh.. true
-#define MENU_FALSE 0 // and false
-
-#define HUD_VERTICAL 0x00
-#define HUD_HORIZONTAL 0x01
-
-// list box element types
-#define LISTBOX_TEXT 0x00
-#define LISTBOX_IMAGE 0x01
-
-// list feeders
-#define FEEDER_HEADS 0x00 // model heads
-#define FEEDER_MAPS 0x01 // text maps based on game type
-#define FEEDER_SERVERS 0x02 // servers
-#define FEEDER_CLANS 0x03 // clan names
-#define FEEDER_ALLMAPS 0x04 // all maps available, in graphic format
-#define FEEDER_REDTEAM_LIST 0x05 // red team members
-#define FEEDER_BLUETEAM_LIST 0x06 // blue team members
-#define FEEDER_PLAYER_LIST 0x07 // players
-#define FEEDER_TEAM_LIST 0x08 // team members for team voting
-#define FEEDER_MODS 0x09 // team members for team voting
-#define FEEDER_DEMOS 0x0a // team members for team voting
-#define FEEDER_SCOREBOARD 0x0b // team members for team voting
-#define FEEDER_Q3HEADS 0x0c // model heads
-#define FEEDER_SERVERSTATUS 0x0d // server status
-#define FEEDER_FINDPLAYER 0x0e // find player
-#define FEEDER_CINEMATICS 0x0f // cinematics
-
-// display flags
-#define CG_SHOW_BLUE_TEAM_HAS_REDFLAG 0x00000001
-#define CG_SHOW_RED_TEAM_HAS_BLUEFLAG 0x00000002
-#define CG_SHOW_ANYTEAMGAME 0x00000004
-#define CG_SHOW_HARVESTER 0x00000008
-#define CG_SHOW_ONEFLAG 0x00000010
-#define CG_SHOW_CTF 0x00000020
-#define CG_SHOW_OBELISK 0x00000040
-#define CG_SHOW_HEALTHCRITICAL 0x00000080
-#define CG_SHOW_SINGLEPLAYER 0x00000100
-#define CG_SHOW_TOURNAMENT 0x00000200
-#define CG_SHOW_DURINGINCOMINGVOICE 0x00000400
-#define CG_SHOW_IF_PLAYER_HAS_FLAG 0x00000800
-#define CG_SHOW_LANPLAYONLY 0x00001000
-#define CG_SHOW_MINED 0x00002000
-#define CG_SHOW_HEALTHOK 0x00004000
-#define CG_SHOW_TEAMINFO 0x00008000
-#define CG_SHOW_NOTEAMINFO 0x00010000
-#define CG_SHOW_OTHERTEAMHASFLAG 0x00020000
-#define CG_SHOW_YOURTEAMHASENEMYFLAG 0x00040000
-#define CG_SHOW_ANYNONTEAMGAME 0x00080000
-#define CG_SHOW_2DONLY 0x10000000
-
-
-#define UI_SHOW_LEADER 0x00000001
-#define UI_SHOW_NOTLEADER 0x00000002
-#define UI_SHOW_FAVORITESERVERS 0x00000004
-#define UI_SHOW_ANYNONTEAMGAME 0x00000008
-#define UI_SHOW_ANYTEAMGAME 0x00000010
-#define UI_SHOW_NEWHIGHSCORE 0x00000020
-#define UI_SHOW_DEMOAVAILABLE 0x00000040
-#define UI_SHOW_NEWBESTTIME 0x00000080
-#define UI_SHOW_FFA 0x00000100
-#define UI_SHOW_NOTFFA 0x00000200
-#define UI_SHOW_NETANYNONTEAMGAME 0x00000400
-#define UI_SHOW_NETANYTEAMGAME 0x00000800
-#define UI_SHOW_NOTFAVORITESERVERS 0x00001000
-
-
-
-
-// owner draw types
-// ideally these should be done outside of this file but
-// this makes it much easier for the macro expansion to
-// convert them for the designers ( from the .menu files )
-#define CG_OWNERDRAW_BASE 1
-#define CG_PLAYER_ARMOR_ICON 1
-#define CG_PLAYER_ARMOR_VALUE 2
-#define CG_PLAYER_HEAD 3
-#define CG_PLAYER_HEALTH 4
-#define CG_PLAYER_AMMO_ICON 5
-#define CG_PLAYER_AMMO_VALUE 6
-#define CG_SELECTEDPLAYER_HEAD 7
-#define CG_SELECTEDPLAYER_NAME 8
-#define CG_SELECTEDPLAYER_LOCATION 9
-#define CG_SELECTEDPLAYER_STATUS 10
-#define CG_SELECTEDPLAYER_WEAPON 11
-#define CG_SELECTEDPLAYER_POWERUP 12
-
-#define CG_FLAGCARRIER_HEAD 13
-#define CG_FLAGCARRIER_NAME 14
-#define CG_FLAGCARRIER_LOCATION 15
-#define CG_FLAGCARRIER_STATUS 16
-#define CG_FLAGCARRIER_WEAPON 17
-#define CG_FLAGCARRIER_POWERUP 18
-
-#define CG_PLAYER_ITEM 19
-#define CG_PLAYER_SCORE 20
-
-#define CG_BLUE_FLAGHEAD 21
-#define CG_BLUE_FLAGSTATUS 22
-#define CG_BLUE_FLAGNAME 23
-#define CG_RED_FLAGHEAD 24
-#define CG_RED_FLAGSTATUS 25
-#define CG_RED_FLAGNAME 26
-
-#define CG_BLUE_SCORE 27
-#define CG_RED_SCORE 28
-#define CG_RED_NAME 29
-#define CG_BLUE_NAME 30
-#define CG_HARVESTER_SKULLS 31 // only shows in harvester
-#define CG_ONEFLAG_STATUS 32 // only shows in one flag
-#define CG_PLAYER_LOCATION 33
-#define CG_TEAM_COLOR 34
-#define CG_CTF_POWERUP 35
-
-#define CG_AREA_POWERUP 36
-#define CG_AREA_LAGOMETER 37 // painted with old system
-#define CG_PLAYER_HASFLAG 38
-#define CG_GAME_TYPE 39 // not done
-
-#define CG_SELECTEDPLAYER_ARMOR 40
-#define CG_SELECTEDPLAYER_HEALTH 41
-#define CG_PLAYER_STATUS 42
-#define CG_FRAGGED_MSG 43 // painted with old system
-#define CG_PROXMINED_MSG 44 // painted with old system
-#define CG_AREA_FPSINFO 45 // painted with old system
-#define CG_AREA_SYSTEMCHAT 46 // painted with old system
-#define CG_AREA_TEAMCHAT 47 // painted with old system
-#define CG_AREA_CHAT 48 // painted with old system
-#define CG_GAME_STATUS 49
-#define CG_KILLER 50
-#define CG_PLAYER_ARMOR_ICON2D 51
-#define CG_PLAYER_AMMO_ICON2D 52
-#define CG_ACCURACY 53
-#define CG_ASSISTS 54
-#define CG_DEFEND 55
-#define CG_EXCELLENT 56
-#define CG_IMPRESSIVE 57
-#define CG_PERFECT 58
-#define CG_GAUNTLET 59
-#define CG_SPECTATORS 60
-#define CG_TEAMINFO 61
-#define CG_VOICE_HEAD 62
-#define CG_VOICE_NAME 63
-#define CG_PLAYER_HASFLAG2D 64
-#define CG_HARVESTER_SKULLS2D 65 // only shows in harvester
-#define CG_CAPFRAGLIMIT 66
-#define CG_1STPLACE 67
-#define CG_2NDPLACE 68
-#define CG_CAPTURES 69
-
-
-
-
-#define UI_OWNERDRAW_BASE 200
-#define UI_HANDICAP 200
-#define UI_EFFECTS 201
-#define UI_PLAYERMODEL 202
-#define UI_CLANNAME 203
-#define UI_CLANLOGO 204
-#define UI_GAMETYPE 205
-#define UI_MAPPREVIEW 206
-#define UI_SKILL 207
-#define UI_BLUETEAMNAME 208
-#define UI_REDTEAMNAME 209
-#define UI_BLUETEAM1 210
-#define UI_BLUETEAM2 211
-#define UI_BLUETEAM3 212
-#define UI_BLUETEAM4 213
-#define UI_BLUETEAM5 214
-#define UI_REDTEAM1 215
-#define UI_REDTEAM2 216
-#define UI_REDTEAM3 217
-#define UI_REDTEAM4 218
-#define UI_REDTEAM5 219
-#define UI_NETSOURCE 220
-#define UI_NETMAPPREVIEW 221
-#define UI_NETFILTER 222
-#define UI_TIER 223
-#define UI_OPPONENTMODEL 224
-#define UI_TIERMAP1 225
-#define UI_TIERMAP2 226
-#define UI_TIERMAP3 227
-#define UI_PLAYERLOGO 228
-#define UI_OPPONENTLOGO 229
-#define UI_PLAYERLOGO_METAL 230
-#define UI_OPPONENTLOGO_METAL 231
-#define UI_PLAYERLOGO_NAME 232
-#define UI_OPPONENTLOGO_NAME 233
-#define UI_TIER_MAPNAME 234
-#define UI_TIER_GAMETYPE 235
-#define UI_ALLMAPS_SELECTION 236
-#define UI_OPPONENT_NAME 237
-#define UI_VOTE_KICK 238
-#define UI_BOTNAME 239
-#define UI_BOTSKILL 240
-#define UI_REDBLUE 241
-#define UI_CROSSHAIR 242
-#define UI_SELECTEDPLAYER 243
-#define UI_MAPCINEMATIC 244
-#define UI_NETGAMETYPE 245
-#define UI_NETMAPCINEMATIC 246
-#define UI_SERVERREFRESHDATE 247
-#define UI_SERVERMOTD 248
-#define UI_GLINFO 249
-#define UI_KEYBINDSTATUS 250
-#define UI_CLANCINEMATIC 251
-#define UI_MAP_TIMETOBEAT 252
-#define UI_JOINGAMETYPE 253
-#define UI_PREVIEWCINEMATIC 254
-#define UI_STARTMAPCINEMATIC 255
-#define UI_MAPS_SELECTION 256
-
-#define VOICECHAT_GETFLAG "getflag" // command someone to get the flag
-#define VOICECHAT_OFFENSE "offense" // command someone to go on offense
-#define VOICECHAT_DEFEND "defend" // command someone to go on defense
-#define VOICECHAT_DEFENDFLAG "defendflag" // command someone to defend the flag
-#define VOICECHAT_PATROL "patrol" // command someone to go on patrol (roam)
-#define VOICECHAT_CAMP "camp" // command someone to camp (we don't have sounds for this one)
-#define VOICECHAT_FOLLOWME "followme" // command someone to follow you
-#define VOICECHAT_RETURNFLAG "returnflag" // command someone to return our flag
-#define VOICECHAT_FOLLOWFLAGCARRIER "followflagcarrier" // command someone to follow the flag carrier
-#define VOICECHAT_YES "yes" // yes, affirmative, etc.
-#define VOICECHAT_NO "no" // no, negative, etc.
-#define VOICECHAT_ONGETFLAG "ongetflag" // I'm getting the flag
-#define VOICECHAT_ONOFFENSE "onoffense" // I'm on offense
-#define VOICECHAT_ONDEFENSE "ondefense" // I'm on defense
-#define VOICECHAT_ONPATROL "onpatrol" // I'm on patrol (roaming)
-#define VOICECHAT_ONCAMPING "oncamp" // I'm camping somewhere
-#define VOICECHAT_ONFOLLOW "onfollow" // I'm following
-#define VOICECHAT_ONFOLLOWCARRIER "onfollowcarrier" // I'm following the flag carrier
-#define VOICECHAT_ONRETURNFLAG "onreturnflag" // I'm returning our flag
-#define VOICECHAT_INPOSITION "inposition" // I'm in position
-#define VOICECHAT_IHAVEFLAG "ihaveflag" // I have the flag
-#define VOICECHAT_BASEATTACK "baseattack" // the base is under attack
-#define VOICECHAT_ENEMYHASFLAG "enemyhasflag" // the enemy has our flag (CTF)
-#define VOICECHAT_STARTLEADER "startleader" // I'm the leader
-#define VOICECHAT_STOPLEADER "stopleader" // I resign leadership
-#define VOICECHAT_TRASH "trash" // lots of trash talk
-#define VOICECHAT_WHOISLEADER "whoisleader" // who is the team leader
-#define VOICECHAT_WANTONDEFENSE "wantondefense" // I want to be on defense
-#define VOICECHAT_WANTONOFFENSE "wantonoffense" // I want to be on offense
-#define VOICECHAT_KILLINSULT "kill_insult" // I just killed you
-#define VOICECHAT_TAUNT "taunt" // I want to taunt you
-#define VOICECHAT_DEATHINSULT "death_insult" // you just killed me
-#define VOICECHAT_KILLGAUNTLET "kill_gauntlet" // I just killed you with the gauntlet
-#define VOICECHAT_PRAISE "praise" // you did something good
diff --git a/game/ui/menus.txt b/game/ui/menus.txt
deleted file mode 100644
index 8d14c3d..0000000
--- a/game/ui/menus.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-// menu defs
-//
-{
- loadMenu { "ui/main.menu" }
- loadMenu { "ui/joinserver.menu" }
- loadMenu { "ui/filter.menu" }
- loadMenu { "ui/punkbuster.menu" }
- loadMenu { "ui/player.menu" }
- loadMenu { "ui/setup.menu" }
- loadMenu { "ui/fight.menu" }
- loadMenu { "ui/skirmish.menu" }
- loadMenu { "ui/createserver.menu" }
- loadMenu { "ui/controls.menu" }
- loadMenu { "ui/cdkey.menu" }
- loadMenu { "ui/system.menu" }
- loadMenu { "ui/options.menu" }
- loadMenu { "ui/help.menu" }
- loadMenu { "ui/ordershelp.menu" }
- loadMenu { "ui/mod.menu" }
- loadMenu { "ui/demo.menu" }
- loadMenu { "ui/cinematicmenu.menu" }
- loadMenu { "ui/credit.menu" }
- loadMenu { "ui/demo_quit.menu" }
- loadMenu { "ui/connect.menu" }
- loadMenu { "ui/powerup.menu" }
- loadMenu { "ui/password.menu" }
- loadMenu { "ui/quake3.menu" }
- loadMenu { "ui/quit.menu" }
- loadMenu { "ui/vid_restart.menu" }
- loadMenu { "ui/default.menu" }
- loadMenu { "ui/addfilter.menu" }
- loadMenu { "ui/error.menu" }
- loadMenu { "ui/serverinfo.menu" }
- loadMenu { "ui/findplayer.menu" }
- loadMenu { "ui/endofgame.menu" }
- loadMenu { "ui/quitcredit.menu" }
- loadMenu { "ui/resetscore.menu" }
- loadMenu { "ui/createfavorite.menu" }
-}
diff --git a/linux_scripts/supermake b/linux_scripts/supermake
new file mode 100755
index 0000000..abe3f07
--- /dev/null
+++ b/linux_scripts/supermake
@@ -0,0 +1,27 @@
+
+#Tip: You can create a supermake.local file and this script will get the variable from there!
+BINNAME=openarena
+MODNAME=oax
+#ARCH should be either i386 (32 bit) or x86_64 (64 bit)
+ARCH=i386
+
+if [ -r ./supermake.local ] ; then
+source ./supermake.local
+fi
+
+if [ -r $BINNAME ] ; then
+ echo $BINNAME found
+else
+ echo $BINNAME not found! Check the variables in the script
+ exit 1
+fi
+
+#Create the mod dir
+mkdir -p ~/.openarena/$MODNAME
+
+
+pushd ..
+#Build, pak it and start
+make && cd build/release-linux-$ARCH/baseq3 && zip -r ~/.openarena/$MODNAME/$MODNAME.pk3 vm && $BINNAME +set fs_game $MODNAME +set debug 1 +set sv_pure 0 +vm_ui 2 +vm_game 2 +vm_cgame 2
+popd
+
diff --git a/linux_scripts/supermake.local b/linux_scripts/supermake.local
new file mode 100644
index 0000000..876370e
--- /dev/null
+++ b/linux_scripts/supermake.local
@@ -0,0 +1,2 @@
+BINNAME=/media/winG/games/openarena-0.8.1/openarena.x86_64
+ARCH=x86_64
diff --git a/linux_scripts/supermake_native b/linux_scripts/supermake_native
new file mode 100755
index 0000000..3502d17
--- /dev/null
+++ b/linux_scripts/supermake_native
@@ -0,0 +1,26 @@
+
+#Tip: You can create a supermake.local file and this script will get the variable from there!
+BINNAME=openarena
+MODNAME=oax
+#ARCH should be either i386 (32 bit) or x86_64 (64 bit)
+ARCH=i386
+
+if [ -r ./supermake.local ] ; then
+source ./supermake.local
+fi
+
+if [ -r $BINNAME ] ; then
+ echo $BINNAME found
+else
+ echo $BINNAME not found! Check the variables in the script
+ exit 1
+fi
+
+#Create the mod dir
+mkdir -p ~/.openarena/$MODNAME
+
+pushd ..
+#Build, pak it and start
+make && cd build/release-linux-$ARCH/baseq3 && cp *.so ~/.openarena/$MODNAME/ && $BINNAME +set fs_game $MODNAME +set debug 1 +set sv_pure 0 +vm_ui 0 +vm_game 0 +vm_cgame 0
+popd
+
diff --git a/game/sprees.dat b/sprees.dat
similarity index 100%
rename from game/sprees.dat
rename to sprees.dat
diff --git a/engine/COPYING.txt b/text/COPYING.txt
similarity index 100%
rename from engine/COPYING.txt
rename to text/COPYING.txt
diff --git a/game/text/README b/text/README
similarity index 100%
rename from game/text/README
rename to text/README
diff --git a/engine/id-readme.txt b/text/id-readme.txt
similarity index 100%
rename from engine/id-readme.txt
rename to text/id-readme.txt
diff --git a/engine/ui/hud.txt b/ui/hud.txt
similarity index 100%
rename from engine/ui/hud.txt
rename to ui/hud.txt
diff --git a/engine/ui/hud2.txt b/ui/hud2.txt
similarity index 100%
rename from engine/ui/hud2.txt
rename to ui/hud2.txt
diff --git a/engine/ui/ingame.txt b/ui/ingame.txt
similarity index 100%
rename from engine/ui/ingame.txt
rename to ui/ingame.txt
diff --git a/ui/menudef.h b/ui/menudef.h
new file mode 100644
index 0000000..414ae9a
--- /dev/null
+++ b/ui/menudef.h
@@ -0,0 +1,310 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#define ITEM_TYPE_TEXT 0 // simple text
+#define ITEM_TYPE_BUTTON 1 // button, basically text with a border
+#define ITEM_TYPE_RADIOBUTTON 2 // toggle button, may be grouped
+#define ITEM_TYPE_CHECKBOX 3 // check box
+#define ITEM_TYPE_EDITFIELD 4 // editable text, associated with a cvar
+#define ITEM_TYPE_COMBO 5 // drop down list
+#define ITEM_TYPE_LISTBOX 6 // scrollable list
+#define ITEM_TYPE_MODEL 7 // model
+#define ITEM_TYPE_OWNERDRAW 8 // owner draw, name specs what it is
+#define ITEM_TYPE_NUMERICFIELD 9 // editable text, associated with a cvar
+#define ITEM_TYPE_SLIDER 10 // mouse speed, volume, etc.
+#define ITEM_TYPE_YESNO 11 // yes no cvar setting
+#define ITEM_TYPE_MULTI 12 // multiple list setting, enumerated
+#define ITEM_TYPE_BIND 13 // multiple list setting, enumerated
+
+#define ITEM_ALIGN_LEFT 0 // left alignment
+#define ITEM_ALIGN_CENTER 1 // center alignment
+#define ITEM_ALIGN_RIGHT 2 // right alignment
+
+#define ITEM_TEXTSTYLE_NORMAL 0 // normal text
+#define ITEM_TEXTSTYLE_BLINK 1 // fast blinking
+#define ITEM_TEXTSTYLE_PULSE 2 // slow pulsing
+#define ITEM_TEXTSTYLE_SHADOWED 3 // drop shadow ( need a color for this )
+#define ITEM_TEXTSTYLE_OUTLINED 4 // drop shadow ( need a color for this )
+#define ITEM_TEXTSTYLE_OUTLINESHADOWED 5 // drop shadow ( need a color for this )
+#define ITEM_TEXTSTYLE_SHADOWEDMORE 6 // drop shadow ( need a color for this )
+
+#define WINDOW_BORDER_NONE 0 // no border
+#define WINDOW_BORDER_FULL 1 // full border based on border color ( single pixel )
+#define WINDOW_BORDER_HORZ 2 // horizontal borders only
+#define WINDOW_BORDER_VERT 3 // vertical borders only
+#define WINDOW_BORDER_KCGRADIENT 4 // horizontal border using the gradient bars
+
+#define WINDOW_STYLE_EMPTY 0 // no background
+#define WINDOW_STYLE_FILLED 1 // filled with background color
+#define WINDOW_STYLE_GRADIENT 2 // gradient bar based on background color
+#define WINDOW_STYLE_SHADER 3 // gradient bar based on background color
+#define WINDOW_STYLE_TEAMCOLOR 4 // team color
+#define WINDOW_STYLE_CINEMATIC 5 // cinematic
+
+#define MENU_TRUE 1 // uh.. true
+#define MENU_FALSE 0 // and false
+
+#define HUD_VERTICAL 0x00
+#define HUD_HORIZONTAL 0x01
+
+// list box element types
+#define LISTBOX_TEXT 0x00
+#define LISTBOX_IMAGE 0x01
+
+// list feeders
+#define FEEDER_HEADS 0x00 // model heads
+#define FEEDER_MAPS 0x01 // text maps based on game type
+#define FEEDER_SERVERS 0x02 // servers
+#define FEEDER_CLANS 0x03 // clan names
+#define FEEDER_ALLMAPS 0x04 // all maps available, in graphic format
+#define FEEDER_REDTEAM_LIST 0x05 // red team members
+#define FEEDER_BLUETEAM_LIST 0x06 // blue team members
+#define FEEDER_PLAYER_LIST 0x07 // players
+#define FEEDER_TEAM_LIST 0x08 // team members for team voting
+#define FEEDER_MODS 0x09 // team members for team voting
+#define FEEDER_DEMOS 0x0a // team members for team voting
+#define FEEDER_SCOREBOARD 0x0b // team members for team voting
+#define FEEDER_Q3HEADS 0x0c // model heads
+#define FEEDER_SERVERSTATUS 0x0d // server status
+#define FEEDER_FINDPLAYER 0x0e // find player
+#define FEEDER_CINEMATICS 0x0f // cinematics
+
+// display flags
+#define CG_SHOW_BLUE_TEAM_HAS_REDFLAG 0x00000001
+#define CG_SHOW_RED_TEAM_HAS_BLUEFLAG 0x00000002
+#define CG_SHOW_ANYTEAMGAME 0x00000004
+#define CG_SHOW_HARVESTER 0x00000008
+#define CG_SHOW_ONEFLAG 0x00000010
+#define CG_SHOW_CTF 0x00000020
+#define CG_SHOW_OBELISK 0x00000040
+#define CG_SHOW_HEALTHCRITICAL 0x00000080
+#define CG_SHOW_SINGLEPLAYER 0x00000100
+#define CG_SHOW_TOURNAMENT 0x00000200
+#define CG_SHOW_DURINGINCOMINGVOICE 0x00000400
+#define CG_SHOW_IF_PLAYER_HAS_FLAG 0x00000800
+#define CG_SHOW_LANPLAYONLY 0x00001000
+#define CG_SHOW_MINED 0x00002000
+#define CG_SHOW_HEALTHOK 0x00004000
+#define CG_SHOW_TEAMINFO 0x00008000
+#define CG_SHOW_NOTEAMINFO 0x00010000
+#define CG_SHOW_OTHERTEAMHASFLAG 0x00020000
+#define CG_SHOW_YOURTEAMHASENEMYFLAG 0x00040000
+#define CG_SHOW_ANYNONTEAMGAME 0x00080000
+#define CG_SHOW_2DONLY 0x10000000
+
+
+#define UI_SHOW_LEADER 0x00000001
+#define UI_SHOW_NOTLEADER 0x00000002
+#define UI_SHOW_FAVORITESERVERS 0x00000004
+#define UI_SHOW_ANYNONTEAMGAME 0x00000008
+#define UI_SHOW_ANYTEAMGAME 0x00000010
+#define UI_SHOW_NEWHIGHSCORE 0x00000020
+#define UI_SHOW_DEMOAVAILABLE 0x00000040
+#define UI_SHOW_NEWBESTTIME 0x00000080
+#define UI_SHOW_FFA 0x00000100
+#define UI_SHOW_NOTFFA 0x00000200
+#define UI_SHOW_NETANYNONTEAMGAME 0x00000400
+#define UI_SHOW_NETANYTEAMGAME 0x00000800
+#define UI_SHOW_NOTFAVORITESERVERS 0x00001000
+
+
+
+
+// owner draw types
+// ideally these should be done outside of this file but
+// this makes it much easier for the macro expansion to
+// convert them for the designers ( from the .menu files )
+#define CG_OWNERDRAW_BASE 1
+#define CG_PLAYER_ARMOR_ICON 1
+#define CG_PLAYER_ARMOR_VALUE 2
+#define CG_PLAYER_HEAD 3
+#define CG_PLAYER_HEALTH 4
+#define CG_PLAYER_AMMO_ICON 5
+#define CG_PLAYER_AMMO_VALUE 6
+#define CG_SELECTEDPLAYER_HEAD 7
+#define CG_SELECTEDPLAYER_NAME 8
+#define CG_SELECTEDPLAYER_LOCATION 9
+#define CG_SELECTEDPLAYER_STATUS 10
+#define CG_SELECTEDPLAYER_WEAPON 11
+#define CG_SELECTEDPLAYER_POWERUP 12
+
+#define CG_FLAGCARRIER_HEAD 13
+#define CG_FLAGCARRIER_NAME 14
+#define CG_FLAGCARRIER_LOCATION 15
+#define CG_FLAGCARRIER_STATUS 16
+#define CG_FLAGCARRIER_WEAPON 17
+#define CG_FLAGCARRIER_POWERUP 18
+
+#define CG_PLAYER_ITEM 19
+#define CG_PLAYER_SCORE 20
+
+#define CG_BLUE_FLAGHEAD 21
+#define CG_BLUE_FLAGSTATUS 22
+#define CG_BLUE_FLAGNAME 23
+#define CG_RED_FLAGHEAD 24
+#define CG_RED_FLAGSTATUS 25
+#define CG_RED_FLAGNAME 26
+
+#define CG_BLUE_SCORE 27
+#define CG_RED_SCORE 28
+#define CG_RED_NAME 29
+#define CG_BLUE_NAME 30
+#define CG_HARVESTER_SKULLS 31 // only shows in harvester
+#define CG_ONEFLAG_STATUS 32 // only shows in one flag
+#define CG_PLAYER_LOCATION 33
+#define CG_TEAM_COLOR 34
+#define CG_CTF_POWERUP 35
+
+#define CG_AREA_POWERUP 36
+#define CG_AREA_LAGOMETER 37 // painted with old system
+#define CG_PLAYER_HASFLAG 38
+#define CG_GAME_TYPE 39 // not done
+
+#define CG_SELECTEDPLAYER_ARMOR 40
+#define CG_SELECTEDPLAYER_HEALTH 41
+#define CG_PLAYER_STATUS 42
+#define CG_FRAGGED_MSG 43 // painted with old system
+#define CG_PROXMINED_MSG 44 // painted with old system
+#define CG_AREA_FPSINFO 45 // painted with old system
+#define CG_AREA_SYSTEMCHAT 46 // painted with old system
+#define CG_AREA_TEAMCHAT 47 // painted with old system
+#define CG_AREA_CHAT 48 // painted with old system
+#define CG_GAME_STATUS 49
+#define CG_KILLER 50
+#define CG_PLAYER_ARMOR_ICON2D 51
+#define CG_PLAYER_AMMO_ICON2D 52
+#define CG_ACCURACY 53
+#define CG_ASSISTS 54
+#define CG_DEFEND 55
+#define CG_EXCELLENT 56
+#define CG_IMPRESSIVE 57
+#define CG_PERFECT 58
+#define CG_GAUNTLET 59
+#define CG_SPECTATORS 60
+#define CG_TEAMINFO 61
+#define CG_VOICE_HEAD 62
+#define CG_VOICE_NAME 63
+#define CG_PLAYER_HASFLAG2D 64
+#define CG_HARVESTER_SKULLS2D 65 // only shows in harvester
+#define CG_CAPFRAGLIMIT 66
+#define CG_1STPLACE 67
+#define CG_2NDPLACE 68
+#define CG_CAPTURES 69
+
+
+
+
+#define UI_OWNERDRAW_BASE 200
+#define UI_HANDICAP 200
+#define UI_EFFECTS 201
+#define UI_PLAYERMODEL 202
+#define UI_CLANNAME 203
+#define UI_CLANLOGO 204
+#define UI_GAMETYPE 205
+#define UI_MAPPREVIEW 206
+#define UI_SKILL 207
+#define UI_BLUETEAMNAME 208
+#define UI_REDTEAMNAME 209
+#define UI_BLUETEAM1 210
+#define UI_BLUETEAM2 211
+#define UI_BLUETEAM3 212
+#define UI_BLUETEAM4 213
+#define UI_BLUETEAM5 214
+#define UI_REDTEAM1 215
+#define UI_REDTEAM2 216
+#define UI_REDTEAM3 217
+#define UI_REDTEAM4 218
+#define UI_REDTEAM5 219
+#define UI_NETSOURCE 220
+#define UI_NETMAPPREVIEW 221
+#define UI_NETFILTER 222
+#define UI_TIER 223
+#define UI_OPPONENTMODEL 224
+#define UI_TIERMAP1 225
+#define UI_TIERMAP2 226
+#define UI_TIERMAP3 227
+#define UI_PLAYERLOGO 228
+#define UI_OPPONENTLOGO 229
+#define UI_PLAYERLOGO_METAL 230
+#define UI_OPPONENTLOGO_METAL 231
+#define UI_PLAYERLOGO_NAME 232
+#define UI_OPPONENTLOGO_NAME 233
+#define UI_TIER_MAPNAME 234
+#define UI_TIER_GAMETYPE 235
+#define UI_ALLMAPS_SELECTION 236
+#define UI_OPPONENT_NAME 237
+#define UI_VOTE_KICK 238
+#define UI_BOTNAME 239
+#define UI_BOTSKILL 240
+#define UI_REDBLUE 241
+#define UI_CROSSHAIR 242
+#define UI_SELECTEDPLAYER 243
+#define UI_MAPCINEMATIC 244
+#define UI_NETGAMETYPE 245
+#define UI_NETMAPCINEMATIC 246
+#define UI_SERVERREFRESHDATE 247
+#define UI_SERVERMOTD 248
+#define UI_GLINFO 249
+#define UI_KEYBINDSTATUS 250
+#define UI_CLANCINEMATIC 251
+#define UI_MAP_TIMETOBEAT 252
+#define UI_JOINGAMETYPE 253
+#define UI_PREVIEWCINEMATIC 254
+#define UI_STARTMAPCINEMATIC 255
+#define UI_MAPS_SELECTION 256
+#define UI_PLAYERMODEL2 257
+#define UI_OPPONENTMODEL2 258
+
+#define VOICECHAT_GETFLAG "getflag" // command someone to get the flag
+#define VOICECHAT_OFFENSE "offense" // command someone to go on offense
+#define VOICECHAT_DEFEND "defend" // command someone to go on defense
+#define VOICECHAT_DEFENDFLAG "defendflag" // command someone to defend the flag
+#define VOICECHAT_PATROL "patrol" // command someone to go on patrol (roam)
+#define VOICECHAT_CAMP "camp" // command someone to camp (we don't have sounds for this one)
+#define VOICECHAT_FOLLOWME "followme" // command someone to follow you
+#define VOICECHAT_RETURNFLAG "returnflag" // command someone to return our flag
+#define VOICECHAT_FOLLOWFLAGCARRIER "followflagcarrier" // command someone to follow the flag carrier
+#define VOICECHAT_YES "yes" // yes, affirmative, etc.
+#define VOICECHAT_NO "no" // no, negative, etc.
+#define VOICECHAT_ONGETFLAG "ongetflag" // I'm getting the flag
+#define VOICECHAT_ONOFFENSE "onoffense" // I'm on offense
+#define VOICECHAT_ONDEFENSE "ondefense" // I'm on defense
+#define VOICECHAT_ONPATROL "onpatrol" // I'm on patrol (roaming)
+#define VOICECHAT_ONCAMPING "oncamp" // I'm camping somewhere
+#define VOICECHAT_ONFOLLOW "onfollow" // I'm following
+#define VOICECHAT_ONFOLLOWCARRIER "onfollowcarrier" // I'm following the flag carrier
+#define VOICECHAT_ONRETURNFLAG "onreturnflag" // I'm returning our flag
+#define VOICECHAT_INPOSITION "inposition" // I'm in position
+#define VOICECHAT_IHAVEFLAG "ihaveflag" // I have the flag
+#define VOICECHAT_BASEATTACK "baseattack" // the base is under attack
+#define VOICECHAT_ENEMYHASFLAG "enemyhasflag" // the enemy has our flag (CTF)
+#define VOICECHAT_STARTLEADER "startleader" // I'm the leader
+#define VOICECHAT_STOPLEADER "stopleader" // I resign leadership
+#define VOICECHAT_TRASH "trash" // lots of trash talk
+#define VOICECHAT_WHOISLEADER "whoisleader" // who is the team leader
+#define VOICECHAT_WANTONDEFENSE "wantondefense" // I want to be on defense
+#define VOICECHAT_WANTONOFFENSE "wantonoffense" // I want to be on offense
+#define VOICECHAT_KILLINSULT "kill_insult" // I just killed you
+#define VOICECHAT_TAUNT "taunt" // I want to taunt you
+#define VOICECHAT_DEATHINSULT "death_insult" // you just killed me
+#define VOICECHAT_KILLGAUNTLET "kill_gauntlet" // I just killed you with the gauntlet
+#define VOICECHAT_PRAISE "praise" // you did something good
diff --git a/engine/ui/menus.txt b/ui/menus.txt
similarity index 100%
rename from engine/ui/menus.txt
rename to ui/menus.txt
diff --git a/game/windows_scripts/cgame.q3asm b/windows_scripts/cgame.q3asm
similarity index 100%
rename from game/windows_scripts/cgame.q3asm
rename to windows_scripts/cgame.q3asm
diff --git a/game/windows_scripts/cgame_mp.q3asm b/windows_scripts/cgame_mp.q3asm
similarity index 100%
rename from game/windows_scripts/cgame_mp.q3asm
rename to windows_scripts/cgame_mp.q3asm
diff --git a/game/windows_scripts/game.q3asm b/windows_scripts/game.q3asm
similarity index 100%
rename from game/windows_scripts/game.q3asm
rename to windows_scripts/game.q3asm
diff --git a/game/windows_scripts/game_mp.q3asm b/windows_scripts/game_mp.q3asm
similarity index 100%
rename from game/windows_scripts/game_mp.q3asm
rename to windows_scripts/game_mp.q3asm
diff --git a/game/windows_scripts/q3_ui.q3asm b/windows_scripts/q3_ui.q3asm
similarity index 100%
rename from game/windows_scripts/q3_ui.q3asm
rename to windows_scripts/q3_ui.q3asm
diff --git a/game/windows_scripts/ui.q3asm b/windows_scripts/ui.q3asm
similarity index 100%
rename from game/windows_scripts/ui.q3asm
rename to windows_scripts/ui.q3asm
diff --git a/game/windows_scripts/windows_compile_cgame.bat b/windows_scripts/windows_compile_cgame.bat
similarity index 100%
rename from game/windows_scripts/windows_compile_cgame.bat
rename to windows_scripts/windows_compile_cgame.bat
diff --git a/game/windows_scripts/windows_compile_cgame_missionpack.bat b/windows_scripts/windows_compile_cgame_missionpack.bat
similarity index 100%
rename from game/windows_scripts/windows_compile_cgame_missionpack.bat
rename to windows_scripts/windows_compile_cgame_missionpack.bat
diff --git a/game/windows_scripts/windows_compile_game.bat b/windows_scripts/windows_compile_game.bat
similarity index 100%
rename from game/windows_scripts/windows_compile_game.bat
rename to windows_scripts/windows_compile_game.bat
diff --git a/game/windows_scripts/windows_compile_game_missionpack.bat b/windows_scripts/windows_compile_game_missionpack.bat
similarity index 100%
rename from game/windows_scripts/windows_compile_game_missionpack.bat
rename to windows_scripts/windows_compile_game_missionpack.bat
diff --git a/game/windows_scripts/windows_compile_q3_ui.bat b/windows_scripts/windows_compile_q3_ui.bat
similarity index 100%
rename from game/windows_scripts/windows_compile_q3_ui.bat
rename to windows_scripts/windows_compile_q3_ui.bat
diff --git a/game/windows_scripts/windows_compile_readme.txt b/windows_scripts/windows_compile_readme.txt
similarity index 100%
rename from game/windows_scripts/windows_compile_readme.txt
rename to windows_scripts/windows_compile_readme.txt
diff --git a/game/windows_scripts/windows_compile_ui_missionpack.bat b/windows_scripts/windows_compile_ui_missionpack.bat
similarity index 100%
rename from game/windows_scripts/windows_compile_ui_missionpack.bat
rename to windows_scripts/windows_compile_ui_missionpack.bat
--
Packaging for the OpenArena engine
More information about the Pkg-games-commits
mailing list